PageSourceSearch

https://www.archify.com/assets/third-party/validator/bootstrapValidator.js

js archify.com collected 2026-09-24 10:22:47 UTC 249,767 bytes, 6,478 lines download raw bytes

1/*!
2 * BootstrapValidator (http://bootstrapvalidator.com)
3 * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
4 *
5 * @version     v0.5.0, built on 2014-07-14 4:31:02 PM
6 * @author      https://twitter.com/nghuuphuoc
7 * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
8 * @license     MIT
9 */
10(function($) {
11    var BootstrapValidator = function(form, options) {
12        this.$form   = $(form);
13        this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options);
14
15        this.$invalidFields = $([]);    // Array of invalid fields
16        this.$submitButton  = null;     // The submit button which is clicked to submit form
17
18        // Validating status
19        this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
20        this.STATUS_VALIDATING    = 'VALIDATING';
21        this.STATUS_INVALID       = 'INVALID';
22        this.STATUS_VALID         = 'VALID';
23
24        // Determine the event that is fired when user change the field value
25        // Most modern browsers supports input event except IE 7, 8.
26        // IE 9 supports input event but the event is still not fired if I press the backspace key.
27        // Get IE version
28        // https://gist.github.com/padolsey/527683/#comment-7595
29        var ieVersion = (function() {
30            var v = 3, div = document.createElement('div'), a = div.all || [];
31            while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]) {}
32            return v > 4 ? v : !v;
33        }());
34
35        var el = document.createElement('div');
36        this._changeEvent = (ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input';
37
38        // The flag to indicate that the form is ready to submit when a remote/callback validator returns
39        this._submitIfValid = null;
40
41        // Field elements
42        this._cacheFields = {};
43
44        this._init();
45    };
46
47    BootstrapValidator.prototype = {
48        constructor: BootstrapValidator,
49
50        /**
51         * Init form
52         */
53        _init: function() {
54            var that    = this,
55                options = {
56                    excluded:       this.$form.attr('data-bv-excluded'),
57                    trigger:        this.$form.attr('data-bv-trigger'),
58                    message:        this.$form.attr('data-bv-message'),
59                    container:      this.$form.attr('data-bv-container'),
60                    group:          this.$form.attr('data-bv-group'),
61                    submitButtons:  this.$form.attr('data-bv-submitbuttons'),
62                    threshold:      this.$form.attr('data-bv-threshold'),
63                    live:           this.$form.attr('data-bv-live'),
64                    onSuccess:      this.$form.attr('data-bv-onsuccess'),
65                    onError:        this.$form.attr('data-bv-onerror'),
66                    fields:         {},
67                    feedbackIcons: {
68                        valid:      this.$form.attr('data-bv-feedbackicons-valid'),
69                        invalid:    this.$form.attr('data-bv-feedbackicons-invalid'),
70                        validating: this.$form.attr('data-bv-feedbackicons-validating')
71                    }
72                };
73
74            this.$form
75                // Disable client side validation in HTML 5
76                .attr('novalidate', 'novalidate')
77                .addClass(this.options.elementClass)
78                // Disable the default submission first
79                .on('submit.bv', function(e) {
80                    e.preventDefault();
81                    that.validate();
82                })
83                .on('click.bv', this.options.submitButtons, function() {
84                    that.$submitButton  = $(this);
85					// The user just click the submit button
86					that._submitIfValid = true;
87                })
88                // Find all fields which have either "name" or "data-bv-field" attribute
89                .find('[name], [data-bv-field]')
90                    .each(function() {
91                        var $field = $(this),
92                            field  = $field.attr('name') || $field.attr('data-bv-field'),
93                            opts   = that._parseOptions($field);
94                        if (opts) {
95                            $field.attr('data-bv-field', field);
96                            options.fields[field] = $.extend({}, opts, options.fields[field]);
97                        }
98                    });
99
100            this.options = $.extend(true, this.options, options);
101            for (var field in this.options.fields) {
102                this._initField(field);
103            }
104
105            this.$form.trigger($.Event('init.form.bv'), {
106                bv: this,
107                options: this.options
108            });
109
110            // Prepare the events
111            if (this.options.onSuccess) {
112                this.$form.on('success.form.bv', function(e) {
113                    $.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]);
114                });
115            }
116            if (this.options.onError) {
117                this.$form.on('error.form.bv', function(e) {
118                    $.fn.bootstrapValidator.helpers.call(that.options.onError, [e]);
119                });
120            }
121        },
122
123        /**
124         * Parse the validator options from HTML attributes
125         *
126         * @param {jQuery} $field The field element
127         * @returns {Object}
128         */
129        _parseOptions: function($field) {
130            var field      = $field.attr('name') || $field.attr('data-bv-field'),
131                validators = {},
132                validator,
133                v,          // Validator name
134                enabled,
135                optionName,
136                optionValue,
137                html5AttrName,
138                html5AttrMap;
139
140            for (v in $.fn.bootstrapValidator.validators) {
141                validator    = $.fn.bootstrapValidator.validators[v];
142                enabled      = $field.attr('data-bv-' + v.toLowerCase()) + '';
143                html5AttrMap = ('function' === typeof validator.enableByHtml5) ? validator.enableByHtml5($field) : null;
144
145                if ((html5AttrMap && enabled !== 'false')
146                    || (html5AttrMap !== true && ('' === enabled || 'true' === enabled)))
147                {
148                    // Try to parse the options via attributes
149                    validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes);
150                    validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]);
151
152                    for (html5AttrName in validator.html5Attributes) {
153                        optionName  = validator.html5Attributes[html5AttrName];
154                        optionValue = $field.attr('data-bv-' + v.toLowerCase() + '-' + html5AttrName);
155                        if (optionValue) {
156                            if ('true' === optionValue) {
157                                optionValue = true;
158                            } else if ('false' === optionValue) {
159                                optionValue = false;
160                            }
161                            validators[v][optionName] = optionValue;
162                        }
163                    }
164                }
165            }
166
167            var opts = {
168                    excluded:      $field.attr('data-bv-excluded'),
169                    feedbackIcons: $field.attr('data-bv-feedbackicons'),
170                    trigger:       $field.attr('data-bv-trigger'),
171                    message:       $field.attr('data-bv-message'),
172                    container:     $field.attr('data-bv-container'),
173                    group:         $field.attr('data-bv-group'),
174                    selector:      $field.attr('data-bv-selector'),
175                    threshold:     $field.attr('data-bv-threshold'),
176                    onStatus:      $field.attr('data-bv-onstatus'),
177                    onSuccess:     $field.attr('data-bv-onsuccess'),
178                    onError:       $field.attr('data-bv-onerror'),
179                    validators:    validators
180                },
181                emptyOptions    = $.isEmptyObject(opts),        // Check if the field options are set using HTML attributes
182                emptyValidators = $.isEmptyObject(validators);  // Check if the field validators are set using HTML attributes
183
184            if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) {
185                opts.validators = validators;
186                return opts;
187            } else {
188                return null;
189            }
190        },
191
192        /**
193         * Init field
194         *
195         * @param {String|jQuery} field The field name or field element
196         */
197        _initField: function(field) {
198            var fields = $([]);
199            switch (typeof field) {
200                case 'object':
201                    fields = field;
202                    field  = field.attr('data-bv-field');
203                    break;
204                case 'string':
205                    fields = this.getFieldElements(field);
206                    fields.attr('data-bv-field', field);
207                    break;
208                default:
209                    break;
210            }
211
212            if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
213                return;
214            }
215
216            // We don't need to validate non-existing fields
217            if (fields.length === 0) {
218                delete this.options.fields[field];
219                return;
220            }
221            var validatorName;
222            for (validatorName in this.options.fields[field].validators) {
223                if (!$.fn.bootstrapValidator.validators[validatorName]) {
224                    delete this.options.fields[field].validators[validatorName];
225                }
226            }
227            if (this.options.fields[field].enabled === null) {
228                this.options.fields[field].enabled = true;
229            }
230
231            var that      = this,
232                total     = fields.length,
233                type      = fields.attr('type'),
234                updateAll = (total === 1) || ('radio' === type) || ('checkbox' === type),
235                event     = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName) ? 'change' : this._changeEvent,
236                trigger   = (this.options.fields[field].trigger || this.options.trigger || event).split(' '),
237                events    = $.map(trigger, function(item) {
238                    return item + '.update.bv';
239                }).join(' ');
240
241            for (var i = 0; i < total; i++) {
242                var $field    = fields.eq(i),
243                    group     = this.options.fields[field].group || this.options.group,
244                    $parent   = $field.parents(group),
245                    // Allow user to indicate where the error messages are shown
246                    container = this.options.fields[field].container || this.options.container,
247                    $message  = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group);
248
249                if (container && container !== 'tooltip' && container !== 'popover') {
250                    $message.addClass('has-danger');
251                }
252
253                // Remove all error messages and feedback icons
254                $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove();
255                $parent.find('i[data-bv-icon-for="' + field + '"]').remove();
256
257                // Whenever the user change the field value, mark it as not val
257idated yet
258                $field.off(events).on(events, function() {
259                    that.updateStatus($(this), that.STATUS_NOT_VALIDATED);
260                });
261
262                // Create help block elements for showing the error messages
263                $field.data('bv.messages', $message);
264                for (validatorName in this.options.fields[field].validators) {
265                    $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
266
267                    if (!updateAll || i === total - 1) {
268                        $('<small/>')
269                            .css('display', 'none')
270                            .addClass('help-block')
271                            .attr('data-bv-validator', validatorName)
272                            .attr('data-bv-for', field)
273                            .attr('data-bv-result', this.STATUS_NOT_VALIDATED)
274                            .html(this._getMessage(field, validatorName))
275                            .appendTo($message);
276                    }
277
278                    // Prepare the validator events
279                    if (this.options.fields[field].validators[validatorName].onSuccess) {
280                        $field.on('success.validator.bv', function(e, data) {
281                             $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onSuccess, [e, data]);
282                        });
283                    }
284                    if (this.options.fields[field].validators[validatorName].onError) {
285                        $field.on('error.validator.bv', function(e, data) {
286                             $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onError, [e, data]);
287                        });
288                    }
289                }
290
291                // Prepare the feedback icons
292                // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
293                if (this.options.fields[field].feedbackIcons !== false && this.options.fields[field].feedbackIcons !== 'false'
294                    && this.options.feedbackIcons
295                    && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
296                    && (!updateAll || i === total - 1))
297                {
298                    $parent.removeClass('has-success').removeClass('has-danger').addClass('has-feedback');
299                    var $icon = $('<i/>')
300                                    .css('display', 'none')
301                                    .addClass('form-control-feedback')
302                                    .attr('data-bv-icon-for', field)
303                                    // Place it after the label containing the checkbox/radio
304                                    // so when clicking the icon, it doesn't effect to the checkbox/radio element
305                                    .insertAfter(('checkbox' === type || 'radio' === type) ? $field.parent() : $field);
306
307                    // The feedback icon does not render correctly if there is no label
308                    // https://github.com/twbs/bootstrap/issues/12873
309                    if ($parent.find('label').length === 0) {
310                        $icon.css('top', 0);
311                    }
312                    // Fix feedback icons in input-group
313                    if ($parent.find('.input-group').length !== 0) {
314                        $icon.css({
315                            'top': 0,
316                            'z-index': 100
317                        }).insertAfter($parent.find('.input-group').eq(0));
318                    }
319                }
320            }
321
322            // Prepare the events
323            if (this.options.fields[field].onSuccess) {
324                fields.on('success.field.bv', function(e, data) {
325                    $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onSuccess, [e, data]);
326                });
327            }
328            if (this.options.fields[field].onError) {
329                fields.on('error.field.bv', function(e, data) {
330                    $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onError, [e, data]);
331                });
332            }
333            if (this.options.fields[field].onStatus) {
334                fields.on('status.field.bv', function(e, data) {
335                    $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onStatus, [e, data]);
336                });
337            }
338
339            // Set live mode
340            events = $.map(trigger, function(item) {
341                return item + '.live.bv';
342            }).join(' ');
343            switch (this.options.live) {
344                case 'submitted':
345                    break;
346                case 'disabled':
347                    fields.off(events);
348                    break;
349                case 'enabled':
350                /* falls through */
351                default:
352                    fields.off(events).on(events, function() {
353                        if (that._exceedThreshold($(this))) {
354                            that.validateField($(this));
355                        }
356                    });
357                    break;
358            }
359
360            fields.trigger($.Event('init.field.bv'), {
361                bv: this,
362                field: field,
363                element: fields
364            });
365        },
366
367        /**
368         * Get the error message for given field and validator
369         *
370         * @param {String} field The field name
371         * @param {String} validatorName The validator name
372         * @returns {String}
373         */
374        _getMessage: function(field, validatorName) {
375            if (!this.options.fields[field] || !$.fn.bootstrapValidator.validators[validatorName]
376                || !this.options.fields[field].validators || !this.options.fields[field].validators[validatorName])
377            {
378                return '';
379            }
380
381            var options = this.options.fields[field].validators[validatorName];
382            switch (true) {
383                case (!!options.message):
384                    return options.message;
385                case (!!this.options.fields[field].message):
386                    return this.options.fields[field].message;
387                case (!!$.fn.bootstrapValidator.i18n[validatorName]):
388                    return $.fn.bootstrapValidator.i18n[validatorName]['default'];
389                default:
390                    return this.options.message;
391            }
392        },
393
394        /**
395         * Get the element to place the error messages
396         *
397         * @param {jQuery} $field The field element
398         * @param {String} group
399         * @returns {jQuery}
400         */
401        _getMessageContainer: function($field, group) {
402            var $parent = $field.parent();
403            if ($parent.is(group)) {
404                return $parent;
405            }
406
407            var cssClasses = $parent.attr('class');
408            if (!cssClasses) {
409                return this._getMessageContainer($parent, group);
410            }
411
412            cssClasses = cssClasses.split(' ');
413            var n = cssClasses.length;
414            for (var i = 0; i < n; i++) {
415                if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) {
416                    return $parent;
417                }
418            }
419
420            return this._getMessageContainer($parent, group);
421        },
422
423        /**
424         * Called when all validations are completed
425         */
426        _submit: function() {
427            var isValid   = this.isValid(),
428                eventType = isValid ? 'success.form.bv' : 'error.form.bv',
429                e         = $.Event(eventType);
430
431            this.$form.trigger(e);
432
433            // Call default handler
434            // Check if whether the submit button is clicked
435            if (this.$submitButton) {
436                isValid ? this._onSuccess(e) : this._onError(e);
437            }
438        },
439
440        /**
441         * Check if the field is excluded.
442         * Returning true means that the field will not be validated
443         *
444         * @param {jQuery} $field The field element
445         * @returns {Boolean}
446         */
447        _isExcluded: function($field) {
448            var excludedAttr = $field.attr('data-bv-excluded'),
449                // I still need to check the 'name' attribute while initializing the field
450                field        = $field.attr('data-bv-field') || $field.attr('name');
451
452            switch (true) {
453                case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true)):
454                case (excludedAttr === 'true'):
455                case (excludedAttr === ''):
456                    return true;
457
458                case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false)):
459                case (excludedAttr === 'false'):
460                    return false;
461
462                default:
463                    if (this.options.excluded) {
464                        // Convert to array first
465                        if ('string' === typeof this.options.excluded) {
466                            this.options.excluded = $.map(this.options.excluded.split(','), function(item) {
467                                // Trim the spaces
468                                return $.trim(item);
469                            });
470                        }
471
472                        var length = this.options.excluded.length;
473                        for (var i = 0; i < length; i++) {
474                            if (('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i]))
475                                || ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true))
476                            {
477                                return true;
478                            }
479                        }
480                    }
481                    return false;
482            }
483        },
484
485        /**
486         * Check if the number of characters of field value exceed the threshold or not
487         *
488         * @param {jQuery} $field The field element
489         * @returns {Boolean}
490         */
491        _exceedThreshold: function($field) {
492            var field     = $field.attr('data-bv-field'),
493                threshold = this.options.fields[field].threshold || this.options.threshold;
494            if (!threshold) {
495                return true;
496            }
497            var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1;
498            return (cannotType || $field.val().length >= threshold);
499        },
500        
501        // ---
502        // Events
503        // ---
504
505        /**
506         * The default handler of error.form.bv event.
507         * It will be called when there is a invalid field
508         *
509         * @param {jQuery.Event} e The jQuery event object
510         */
511        _onError: function(e) {
512            if (e.isDefaultPrevented()) {
513                return;
514            }
515
516            if ('submitted' === this.options.live) {
517                // Enable live mode
518                this.options.live = 'enabled';
519                var that = this;
520                for (var field in this.options.fields) {
521                    (function(f) {
522                        var fields  = that.getFieldElements(f);
523                        if (fields.length) {
524                            var type    = $(fields[0]).attr('type'),
525                                event   = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName) ? 'change' : that._changeEvent,
526                                trigger = that.options.fields[field].trigger || that.options.trigger || event,
527                                events  = $.map(trigger.split(' '), function(item) {
528                                    return item + '.live.bv';
529                                }).join(' ');
530
531                            fields.off(events).on(events, function() {
532                                if (that._exceedThreshold($(this))) {
533                                    that.validateField($(this));
534                                }
535                            });
536                        }
537                    })(field);
538                }
539            }
540
541            var $invalidField = this.$invalidFields.eq(0);
542            if ($invalidField) {
543                // Activate the tab containing the invalid field if exists
544                var $tabPane = $invalidField.parents('.tab-pane'), tabId;
545                if ($tabPane && (tabId = $tabPane.attr('id'))) {
546                    $('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show');
547                }
548
549                // Focus to the first invalid field
550                $invalidField.focus();
551            }
552        },
553
554        /**
555         * The default handler of success.form.bv event.
556         * It will be called when all the fields are valid
557         *
558         * @param {jQuery.Event} e The jQuery event object
559         */
560        _onSuccess: function(e) {
561            if (e.isDefaultPrevented()) {
562                return;
563            }
564
565            // Submit the form
566            this.disableSubmitButtons(true).defaultSubmit();
567        },
568
569        /**
570         * Called after validating a field element
571         *
572         * @param {jQuery} $field The field element
573         * @param {String} [validatorName] The validator name
574         */
575        _onFieldValidated: function($field, validatorName) {
576            var field         = $field.attr('data-bv-field'),
577                validators    = this.options.fields[field].validators,
578                counter       = {},
579                numValidators = 0,
580                data          = {
581                    bv: this,
582                    field: field,
583                    element: $field,
584                    validator: validatorName
585                };
586
587            // Trigger an event after given validator completes
588            if (validatorName) {
589                switch ($field.data('bv.result.' + validatorName)) {
590                    case this.STATUS_INVALID:
591                        $field.trigger($.Event('error.validator.bv'), data);
592                        break;
593                    case this.STATUS_VALID:
594                        $field.trigger($.Event('success.validator.bv'), data);
595                        break;
596                    default:
597                        break;
598                }
599            }
600
601            counter[this.STATUS_NOT_VALIDATED] = 0;
602            counter[this.STATUS_VALIDATING]    = 0;
603            counter[this.STATUS_INVALID]       = 0;
604            counter[this.STATUS_VALID]         = 0;
605
606            for (var v in validators) {
607                if (validators[v].enabled === false) {
608                    continue;
609                }
610
611                numValidators++;
612                var result = $field.data('bv.result.' + v);
613                if (result) {
614                    counter[result]++;
615                }
616            }
617
618            if (counter[this.STATUS_VALID] === numValidators) {
619                // Remove from the list of invalid fields
620                this.$invalidFields = this.$invalidFields.not($field);
621
622                $field.trigger($.Event('success.field.bv'), data);
623            }
624            // If all validators are completed and there is at least one validator which doesn't pass
625            else if (counter[this.STATUS_NOT_VALIDATED] === 0 && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) {
626                // Add to the list of invalid fields
627                this.$invalidFields = this.$invalidFields.add($field);
628
629                $field.trigger($.Event('error.field.bv'), data);
630            }
631        },
632
633        // ---
634        // Public methods
635        // ---
636
637        /**
638         * Retrieve the field elements by given name
639         *
640         * @param {String} field The field name
641         * @returns {null|jQuery[]}
642         */
643        getFieldElements: function(field) {
644            if (!this._cacheFields[field]) {
645                this._cacheFields[field] = (this.options.fields[field] && this.options.fields[field].selector)
646                                         ? $(this.options.fields[field].selector)
647                                         : this.$form.find('[name="' + field + '"]');
648            }
649
650            return this._cacheFields[field];
651        },
652
653        /**
654         * Disable/enable submit buttons
655         *
656         * @param {Boolean} disabled Can be true or false
657         * @returns {BootstrapValidator}
658         */
659        disableSubmitButtons: function(disabled) {
660            if (!disabled) {
661                this.$form.find(this.options.submitButtons).removeAttr('disabled');
662            } else if (this.options.live !== 'disabled') {
663                // Don't disable if the live validating mode is disabled
664                this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
665            }
666
667            return this;
668        },
669
670        /**
671         * Validate the form
672         *
673         * @returns {BootstrapValidator}
674         */
675        validate: function() {
676            if (!this.options.fields) {
677                return this;
678            }
679            this.disableSubmitButtons(true);
680
681            for (var field in this.options.fields) {
682                this.validateField(field);
683            }
684
685            this._submit();
686
687            return this;
688        },
689
690        /**
691         * Validate given field
692         *
693         * @param {String|jQuery} field The field name or field element
694         * @returns {BootstrapValidator}
695         */
696        validateField: function(field) {
697            var fields = $([]);
698            switch (typeof field) {
699                case 'object':
700                    fields = field;
701                    field  = field.attr('data-bv-field');
702                    break;
703                case 'string':
704                    fields = this.getFieldElements(field);
705                    break;
706                default:
707                    break;
708            }
709
710            if (this.options.fields[field] && this.options.fields[field].enabled === false) {
711                return this;
712            }
713
714            var that       = this,
715                type       = fields.attr('type'),
716                total      = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
717                updateAll  = ('radio' === type || 'checkbox' === type),
718                validators = this.options.fields[field].validators,
719                validatorName,
720                validateResult;
721
722            for (var i = 0; i < total; i++) {
723                var $field = fields.eq(i);
724                if (this._isExcluded($field)) {
725                    continue;
726                }
727
728                for (validatorName in validators) {
729                    if ($field.data('bv.dfs.' + validatorName)) {
730                        $field.data('bv.dfs.' + validatorName).reject();
731                    }
732
733                    // Don't validate field if it is already done
734                    var result = $field.data('bv.result.' + validatorName);
735                    if (result === this.STATUS_VALID || result === this.STATUS_INVALID || validators[validatorName].enabled === false) {
736                        this._onFieldValidated($field, validatorName);
737                        continue;
738                    }
739
740                    $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
741                    validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
742
743                    // validateResult can be a $.Deferred object ...
744                    if ('object' === typeof validateResult && validateResult.resolve) {
745                        this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName);
746                        $field.data('bv.dfs.' + validatorName, validateResult);
747
748                        validateResult.done(function($f, v, isValid, message) {
749                            // v is validator name
750                            $f.removeData('bv.dfs.' + v);
751                            if (message) {
752                                that.updateMessage($f, v, message);
753                            }
754
755                            that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
756
757                            if (isValid && that._submitIfValid === true) {
758                                // If a remote validator returns true and the form is ready to submit, then do it
759                                that._submit();
760                            }
761                        });
762                    }
763                    // ... or object { valid: true/false, message: 'dynamic message' }
764                    else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) {
765                        this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message);
766                        this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
767                    }
768                    // ... or a boolean value
769                    else if ('boolean' === typeof validateResult) {
770                        this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
771                    }
772                }
773            }
774
775            return this;
776        },
777
778        /**
779         * Update the error message
780         *
781         * @param {String|jQuery} field The field name or field element
782         * @param {String} validator The validator name
783         * @param {String} message The message
784         * @returns {BootstrapValidator}
785         */
786        updateMessage: function(field, validator, message) {
787            var $fields = $([]);
788            switch (typeof field) {
789                case 'object':
790                    $fields = field;
791                    field   = field.attr('data-bv-field');
792                    break;
793                case 'string':
794                    $fields = this.getFieldElements(field);
795                    break;
796                default:
797                    break;
798            }
799
800            $fields.each(function() {
801                $(this).data('bv.messages').find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]').html(message);
802            });
803        },
804        
805        /**
806         * Update all validating results of field
807         *
808         * @param {String|jQuery} field The field name or field element
809         * @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
810         * @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators
811         * @returns {BootstrapValidator}
812         */
813        updateStatus: function(field, status, validatorName) {
814            var fields = $([]);
815            switch (typeof field) {
816                case 'object':
817                    fields = field;
818                    field  = field.attr('data-bv-field');
819                    break;
820                case 'string':
821                    fields = this.getFieldElements(field);
822                    break;
823                default:
824                    break;
825            }
826
827            if (status === this.STATUS_NOT_VALIDATED) {
828                // Reset the flag
829                this._submitIfValid = false;
830            }
831
832            var that  = this,
833                type  = fields.attr('type'),
834                group = this.options.fields[field].group || this.options.group,
835                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
836
837            for (var i = 0; i < total; i++) {
838                var $field       = fields.eq(i);
839                if (this._isExcluded($field)) {
840                    continue;
841                }
842
843                var $parent      = $field.parents(group),
844                    $message     = $field.data('bv.messages'),
845                    $allErrors   = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'),
846                    $errors      = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors,
847                    $icon        = $parent.find('.form-control-feedback[data-bv-icon-for="' + field + '"]'),
848                    container    = this.options.fields[field].container || this.options.container,
849                    isValidField = null;
850
851                // Update status
852                if (validatorName) {
853                    $field.data('bv.result.' + validatorName, status);
854                } else {
855                    for (var v in this.options.fields[field].validators) {
856                        $field.data('bv.result.' + v, status);
857                    }
858                }
859
860                // Show/hide error elements and feedback icons
861                $errors.attr('data-bv-result', status);
862
863                // Determine the tab containing the element
864                var $tabPane = $field.parents('.tab-pane'),
865                    tabId, $tab;
866                if ($tabPane && (tabId = $tabPane.attr('id'))) {
867                    $tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent();
868                }
869
870                switch (status) {
871                    case this.STATUS_VALIDATING:
872                        isValidField = null;
873                        this.disableSubmitButtons(true);
874                        $parent.removeClass('has-success').removeClass('has-danger');
875                        if ($icon) {
876                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show();
877                        }
878                        if ($tab) {
879                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
880                        }
881                        break;
882
883                    case this.STATUS_INVALID:
884                        isValidField = false;
885                        this.disableSubmitButtons(true);
886                        $parent.removeClass('has-success').addClass('has-danger');
887                        if ($icon) {
888                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
889                        }
890                        if ($tab) {
891                            $tab.removeClass('bv-tab-success').addClass('bv-tab-error');
892                        }
893                        break;
894
895                    case this.STATUS_VALID:
896                        // If the field is valid (passes all validators)
897                        isValidField = ($allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED +'"]').length === 0)
898                                     ? ($allErrors.filter('[data-bv-result="' + this.STATUS_VALID +'"]').length === $allErrors.length)  // All validators are completed
899                                     : null;                                                                                            // There are some validators that have not done
900                        if (isValidField !== null) {
901                            this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField);
902                            if ($icon) {
903                                $icon
904                                    .removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).removeClass(this.options.feedbackIcons.valid)
905                                    .addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid)
906                                    .show();
907                            }
908                        }
909
910                        $parent.removeClass('has-danger has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-danger');
911                        if ($tab) {
912                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error').addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error');
913                        }
914                        break;
915
916                    case this.STATUS_NOT_VALIDATED:
917                    /* falls through */
918                    default:
919                        isValidField = null;
920                        this.disableSubmitButtons(false);
921                        $parent.removeClass('has-success').removeClass('has-danger');
922                        if ($icon) {
923                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide();
924                        }
925                        if ($tab) {
926                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
927                        }
928                        break;
929                }
930
931                switch (true) {
932                    // Only show the first error message if it is placed inside a tooltip ...
933                    case ($icon && 'tooltip' === container):
934                        (isValidField === false)
935                                ? $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({
936                                    html: true,
937                                    placement: 'top',
938                                    title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html()
939                                })
940                                : $icon.css('cursor', '').tooltip('destroy');
941                        break;
942                    // ... or popover
943                    case ($icon && 'popover' === container):
944                        (isValidField === false)
945                                ? $icon.css('cursor', 'pointer').popover('destroy').popover({
946                                    content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(),
947                                    html: true,
948                                    placement: 'top',
949                                    trigger: 'hover click'
950                                })
951                                : $icon.css('cursor', '').popover('destroy');
952                        break;
953                    default:
954                        (status === this.STATUS_INVALID) ? $errors.show() : $errors.hide();
955                        break;
956                }
957
958                // Trigger an event
959                $field.trigger($.Event('status.field.bv'), {
960                    bv: this,
961                    field: field,
962                    element: $field,
963                    status: status
964                });
965                this._onFieldValidated($field, validatorName);
966            }
967
968            return this;
969        },
970
971        /**
972         * Check the form validity
973         *
974         * @returns {Boolean}
975         */
976        isValid: function() {
977            for (var field in this.options.fields) {
978                if (!this.isValidField(field)) {
979                    return false;
980                }
981            }
982
983            return true;
984        },
985
986        /**
987         * Check if the field is valid or not
988         *
989         * @param {String|jQuery} field The field name or field element
990         * @returns {Boolean}
991         */
992        isValidField: function(field) {
993            var fields = $([]);
994            switch (typeof field) {
995                case 'object':
996                    fields = field;
997                    field  = field.attr('data-bv-field');
998                    break;
999                case 'string':
1000                    fields = this.getFieldElements(field);
1001                    break;
1002                default:
1003                    break;
1004            }
1005            if (fields.length === 0 || this.options.fields[field] === null || this.options.fields[field].enabled === false) {
1006                return true;
1007            }
1008
1009            var type  = fields.attr('type'),
1010                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
1011                $field, validatorName, status;
1012            for (var i = 0; i < total; i++) {
1013                $field = fields.eq(i);
1014                if (this._isExcluded($field)) {
1015                    continue;
1016                }
1017
1018                for (validatorName in this.options.fields[field].validators) {
1019                    if (this.options.fields[field].validators[validatorName].enabled === false) {
1020                        continue;
1021                    }
1022
1023                    status = $field.data('bv.result.' + validatorName);
1024                    if (status !== this.STATUS_VALID) {
1025                        return false;
1026                    }
1027                }
1028            }
1029
1030            return true;
1031        },
1032
1033        /**
1034         * Check if all fields inside a given container are valid.
1035         * It's useful when working with a wizard-like such as tab, collapse
1036         *
1037         * @param {String|jQuery} container The container selector or element
1038         * @returns {Boolean}
1039         */
1040        isValidContainer: function(container) {
1041            var that       = this,
1042                map        = {},
1043                $container = ('string' === typeof container) ? $(container) : container;
1044            if ($container.length === 0) {
1045                return true;
1046            }
1047
1048            $container.find('[data-bv-field]').each(function() {
1049                var $field = $(this),
1050                    field  = $field.attr('data-bv-field');
1051                if (!that._isExcluded($field) && !map[field]) {
1052                    map[field] = $field;
1053                }
1054            });
1055
1056            for (var field in map) {
1057                var $f = map[field];
1058                if ($f.data('bv.messages')
1059                      .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]')
1060                      .filter(function() {
1061                          var v = $(this).attr('data-bv-validator'),
1062                              f = $(this).attr('data-bv-for');
1063                          return (that.options.fields[f].validators[v].enabled !== false
1064                                && $f.data('bv.result.' + v) && $f.data('bv.result.' + v) !== that.STATUS_VALID);
1065                      })
1066                      .length !== 0)
1067                {
1068                    // The field is not valid
1069                    return false;
1070                }
1071            }
1072
1073            return true;
1074        },
1075
1076        /**
1077         * Submit the form using default submission.
1078         * It also does not perform any validations when submitting the form
1079         */
1080        defaultSubmit: function() {
1081            if (this.$submitButton) {
1082                // Create hidden input to send the submit buttons
1083                $('<input/>')
1084                    .attr('type', 'hidden')
1085                    .attr('data-bv-submit-hidden', '')
1086                    .attr('name', this.$submitButton.attr('name'))
1087                    .val(this.$submitButton.val())
1088                    .appendTo(this.$form);
1089            }
1090
1091            // Submit form
1092            this.$form.off('submit.bv').submit();
1093        },
1094
1095        // ---
1096        // Useful APIs which aren't used internally
1097        // ---
1098
1099        /**
1100         * Get the list of invalid fields
1101         *
1102         * @returns {jQuery[]}
1103         */
1104        getInvalidFields: function() {
1105            return this.$invalidFields;
1106        },
1107
1108        /**
1109         * Returns the clicked submit button
1110         *
1111         * @returns {jQuery}
1112         */
1113        getSubmitButton: function() {
1114            return this.$submitButton;
1115        },
1116
1117        /**
1118         * Get the error messages
1119         *
1120         * @param {String|jQuery} [field] The field name or field element
1121         * If the field is not defined, the method returns all error messages of all fields
1122         * @param {String} [validator] The name of validator
1123         * If the validator is not defined, the method returns error messages of all validators
1124         * @returns {String[]}
1125         */
1126        getMessages: function(field, validator) {
1127            var that     = this,
1128                messages = [],
1129                $fields  = $([]);
1130
1131            switch (true) {
1132                case (field && 'object' === typeof field):
1133                    $fields = field;
1134                    break;
1135                case (field && 'string' === typeof field):
1136                    var f = this.getFieldElements(field);
1137                    if (f.length > 0) {
1138                        var type = f.attr('type');
1139                        $fields = ('radio' === type || 'checkbox' === type) ? f.eq(0) : f;
1140                    }
1141                    break;
1142                default:
1143                    $fields = this.$invalidFields;
1144                    break;
1145            }
1146
1147            var filter = validator ? '[data-bv-validator="' + validator + '"]' : '';
1148            $fields.each(function() {
1149                messages = messages.concat(
1150                    $(this)
1151                        .data('bv.messages')
1152                        .find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter)
1153                        .map(function() {
1154                            var v = $(this).attr('data-bv-validator'),
1155                                f = $(this).attr('data-bv-for');
1156                            return (that.options.fields[f].validators[v].enabled === false) ? '' : $(this).html();
1157                        })
1158                        .get()
1159                );
1160            });
1161
1162            return messages;
1163        },
1164
1165        /**
1166         * Get the field options
1167         *
1168         * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
1169         * @param {String} [validator] The name of validator. It null, the method returns form options
1170         * @param {String} [option] The option name
1171         * @return {String|Object}
1172         */
1173        getOptions: function(field, validator, option) {
1174            if (!field) {
1175                return this.options;
1176            }
1177            if ('object' === typeof field) {
1178                field = field.attr('data-bv-field');
1179            }
1180            if (!this.options.fields[field]) {
1181                return null;
1182            }
1183
1184            var options = this.options.fields[field];
1185            if (!validator) {
1186                return options;
1187            }
1188            if (!options.validators || !options.validators[validator]) {
1189                return null;
1190            }
1191
1192            return option ? options.validators[validator][option] : options.validators[validator];
1193        },
1194
1195        /**
1196         * Update the option of a specific validator
1197         *
1198         * @param {String|jQuery} field The field name or field element
1199         * @param {String} validator The validator name
1200         * @param {String} option The option name
1201         * @param {String} value The value to set
1202         * @returns {BootstrapValidator}
1203         */
1204        updateOption: function(field, validator, option, value) {
1205            if ('object' === typeof field) {
1206                field = field.attr('data-bv-field');
1207            }
1208            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
1209                this.options.fields[field].validators[validator][option] = value;
1210                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
1211            }
1212
1213            return this;
1214        },
1215
1216        /**
1217         * Add a new field
1218         *
1219         * @param {String|jQuery} field The field name or field element
1220         * @param {Object} [options] The validator rules
1221         * @returns {BootstrapValidator}
1222         */
1223        addField: function(field, options) {
1224            var fields = $([]);
1225            switch (typeof field) {
1226                case 'object':
1227                    fields = field;
1228                    field  = field.attr('data-bv-field') || field.attr('name');
1229                    break;
1230                case 'string':
1231                    delete this._cacheFields[field];
1232                    fields = this.getFieldElements(field);
1233                    break;
1234                default:
1235                    break;
1236            }
1237
1238            fields.attr('data-bv-field', field);
1239
1240            var type  = fields.attr('type'),
1241                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
1242
1243            for (var i = 0; i < total; i++) {
1244                var $field = fields.eq(i);
1245
1246                // Try to parse the options from HTML attributes
1247                var opts = this._parseOptions($field);
1248                opts = (opts === null) ? options : $.extend(true, options, opts);
1249
1250                this.options.fields[field] = $.extend(true, this.options.fields[field], opts);
1251
1252                // Update the cache
1253                this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field;
1254
1255                // Init the element
1256                this._initField(('checkbox' === type || 'radio' === type) ? field : $field);
1257            }
1258
1259            this.disableSubmitButtons(false);
1260            // Trigger an event
1261            this.$form.trigger($.Event('added.field.bv'), {
1262                field: field,
1263                element: fields,
1264                options: this.options.fields[field]
1265            });
1266
1267            return this;
1268        },
1269
1270        /**
1271         * Remove a given field
1272         *
1273         * @param {String|jQuery} field The field name or field element
1274         * @returns {BootstrapValidator}
1275         */
1276        removeField: function(field) {
1277            var fields = $([]);
1278            switch (typeof field) {
1279                case 'object':
1280                    fields = field;
1281                    field  = field.attr('data-bv-field') || field.attr('name');
1282                    fields.attr('data-bv-field', field);
1283                    break;
1284                case 'string':
1285                    fields = this.getFieldElements(field);
1286                    break;
1287                default:
1288                    break;
1289            }
1290
1291            if (fields.length === 0) {
1292                return this;
1293            }
1294
1295            var type  = fields.attr('type'),
1296                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
1297
1298            for (var i = 0; i < total; i++) {
1299                var $field = fields.eq(i);
1300
1301                // Remove from the list of invalid fields
1302                this.$invalidFields = this.$invalidFields.not($field);
1303
1304                // Update the cache
1305                this._cacheFields[field] = this._cacheFields[field].not($field);
1306            }
1307
1308            if (!this._cacheFields[field] || this._cacheFields[field].length === 0) {
1309                delete this.options.fields[field];
1310            }
1311            if ('checkbox' === type || 'radio' === type) {
1312                this._initField(field);
1313            }
1314
1315            this.disableSubmitButtons(false);
1316            // Trigger an event
1317            this.$form.trigger($.Event('removed.field.bv'), {
1318                field: field,
1319                element: fields
1320            });
1321
1322            return this;
1323        },
1324
1325        /**
1326         * Reset given field
1327         *
1328         * @param {String|jQuery} field The field name or field element
1329         * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
1330         * @returns {BootstrapValidator}
1331         */
1332        resetField: function(field, resetValue) {
1333            var $fields = $([]);
1334            switch (typeof field) {
1335                case 'object':
1336                    $fields = field;
1337                    field   = field.attr('data-bv-field');
1338                    break;
1339                case 'string':
1340                    $fields = this.getFieldElements(field);
1341                    break;
1342                default:
1343                    break;
1344            }
1345
1346            var total = $fields.length;
1347            if (this.options.fields[field]) {
1348                for (var i = 0; i < total; i++) {
1349                    for (var validator in this.options.fields[field].validators) {
1350                        $fields.eq(i).removeData('bv.dfs.' + validator);
1351                    }
1352                }
1353            }
1354
1355            // Mark field as not validated yet
1356            this.updateStatus(field, this.STATUS_NOT_VALIDATED);
1357
1358            if (resetValue) {
1359                var type = $fields.attr('type');
1360                ('radio' === type || 'checkbox' === type) ? $fields.removeAttr('checked').removeAttr('selected') : $fields.val('');
1361            }
1362
1363            return this;
1364        },
1365
1366        /**
1367         * Reset the form
1368         *
1369         * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
1370         * @returns {BootstrapValidator}
1371         */
1372        resetForm: function(resetValue) {
1373            for (var field in this.options.fields) {
1374                this.resetField(field, resetValue);
1375            }
1376
1377            this.$invalidFields = $([]);
1378            this.$submitButton  = null;
1379
1380            // Enable submit buttons
1381            this.disableSubmitButtons(false);
1382
1383            return this;
1384        },
1385
1386        /**
1387         * Revalidate given field
1388         * It's used when you need to revalidate the field which its value is updated by other plugin
1389         *
1390         * @param {String|jQuery} field The field name of field element
1391         * @returns {BootstrapValidator}
1392         */
1393        revalidateField: function(field) {
1394            this.updateStatus(field, this.STATUS_NOT_VALIDATED)
1395                .validateField(field);
1396
1397            return this;
1398        },
1399
1400        /**
1401         * Enable/Disable all validators to given field
1402         *
1403         * @param {String} field The field name
1404         * @param {Boolean} enabled Enable/Disable field validators
1405         * @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled
1406         * @returns {BootstrapValidator}
1407         */
1408        enableFieldValidators: function(field, enabled, validatorName) {
1409            var validators = this.options.fields[field].validators;
1410
1411            // Enable/disable particular validator
1412            if (validatorName
1413                && validators
1414                && validators[validatorName] && validators[validatorName].enabled !== enabled)
1415            {
1416                this.options.fields[field].validators[validatorName].enabled = enabled;
1417                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName);
1418            }
1419            // Enable/disable all validators
1420            else if (!validatorName && this.options.fields[field].enabled !== enabled) {
1421                this.options.fields[field].enabled = enabled;
1422                for (var v in validators) {
1423                    this.enableFieldValidators(field, enabled, v);
1424                }
1425            }
1426
1427            return this;
1428        },
1429
1430        /**
1431         * Some validators have option which its value is dynamic.
1432         * For example, the zipCode validator has the country option which might be changed dynamically by a select element.
1433         *
1434         * @param {jQuery|String} field The field name or element
1435         * @param {String|Function} option The option which can be determined by:
1436         * - a string
1437         * - name of field which defines the value
1438         * - name of function which returns the value
1439         * - a function returns the value
1440         *
1441         * The callback function has the format of
1442         *      callback: function(value, validator, $field) {
1443         *          // value is the value of field
1444         *          // validator is the BootstrapValidator instance
1445         *          // $field is the field element
1446         *      }
1447         *
1448         * @returns {String}
1449         */
1450        getDynamicOption: function(field, option) {
1451            var $field = ('string' === typeof field) ? this.getFieldElements(field) : field,
1452                value  = $field.val();
1453
1454            // Option can be determined by
1455            // ... a function
1456            if ('function' === typeof option) {
1457                return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
1458            }
1459            // ... value of other field
1460            else if ('string' === typeof option) {
1461                var $f = this.getFieldElements(option);
1462                if ($f.length) {
1463                    return $f.val();
1464                }
1465                // ... return value of callback
1466                else {
1467                    return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
1468                }
1469            }
1470
1471            return null;
1472        },
1473
1474        /**
1475         * Destroy the plugin
1476         * It will remove all error messages, feedback icons and turn off the events
1477         */
1478        destroy: function() {
1479            var field, fields, $field, validator, $icon, container, group;
1480            for (field in this.options.fields) {
1481                fields    = this.getFieldElements(field);
1482                container = this.options.fields[field].container || this.options.container,
1483                group     = this.options.fields[field].group || this.options.group;
1484                for (var i = 0; i < fields.length; i++) {
1485                    $field = fields.eq(i);
1486                    $field
1487                        // Remove all error messages
1488                        .data('bv.messages')
1489                            .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove().end()
1490                            .end()
1491                        .removeData('bv.messages')
1492                        // Remove feedback classes
1493                        .parents(group)
1494                            .removeClass('has-feedback has-danger has-success')
1495                            .end()
1496                        // Turn off events
1497                        .off('.bv')
1498                        .removeAttr('data-bv-field');
1499
1500                    // Remove feedback icons, tooltip/popover container
1501                    $icon = $field.parents(group).find('i[data-bv-icon-for="' + field + '"]');
1502                    if ($icon) {
1503                        switch (container) {
1504                            case 'tooltip':
1505                                $icon.tooltip('destroy').remove();
1506                                break;
1507                            case 'popover':
1508                                $icon.popover('destroy').remove();
1509                                break;
1510                            default:
1511                                $icon.remove();
1512                                break;
1513                        }
1514                    }
1515
1516                    for (validator in this.options.fields[field].validators) {
1517                        if ($field.data('bv.dfs.' + validator)) {
1518                            $field.data('bv.dfs.' + validator).reject();
1519                        }
1520                        $field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator);
1521                    }
1522                }
1523            }
1524
1525            // Enable submit buttons
1526            this.disableSubmitButtons(false);
1527
1528            this.$form
1529                .removeClass(this.options.elementClass)
1530                .off('.bv')
1531                .removeData('bootstrapValidator')
1532                // Remove generated hidden elements
1533                .find('[data-bv-submit-hidden]').remove();
1534        }
1535    };
1536
1537    // Plugin definition
1538    $.fn.bootstrapValidator = function(option) {
1539        var params = arguments;
1540        return this.each(function() {
1541            var $this   = $(this),
1542                data    = $this.data('bootstrapValidator'),
1543                options = 'object' === typeof option && option;
1544            if (!data) {
1545                data = new BootstrapValidator(this, options);
1546                $this.data('bootstrapValidator', data);
1547            }
1548
1549            // Allow to call plugin method
1550            if ('string' === typeof option) {
1551                data[option].apply(data, Array.prototype.slice.call(params, 1));
1552            }
1553        });
1554    };
1555
1556    // The default options
1557    $.fn.bootstrapValidator.DEFAULT_OPTIONS = {
1558        // The form CSS class
1559        elementClass: 'bv-form',
1560
1561        // Default invalid message
1562        message: 'This value is not valid',
1563
1564        // The CSS selector for indicating the element consists the field
1565        // By default, each field is placed inside the <div class="form-group"></div>
1566        // You should adjust this option if your form group consists of many fields which not all of them need to be validated
1567        group: '.form-group',
1568
1569        //The error messages container. It can be:
1570        // - 'tooltip' if you want to use Bootstrap tooltip to show error messages
1571        // - 'popover' if you want to use Bootstrap popover to show error messages
1572        // - a CSS selector indicating the container
1573        // In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message
1574        // You also can define the message container for particular field
1575        container: null,
1576
1577        // The field will not be live validated if its length is less than this number of characters
1578        threshold: null,
1579
1580        // Indicate fields which won't be validated
1581        // By default, the plugin will not validate the following kind of fields:
1582        // - disabled
1583        // - hidden
1584        // - invisible
1585        //
1586        // The setting consists of jQuery filters. Accept 3 formats:
1587        // - A string. Use a comma to separate filter
1588        // - An array. Each element is a filter
1589        // - An array. Each element can be a callback function
1590        //      function($field, validator) {
1591        //          $field is jQuery object representing the field element
1592        //          validator is the BootstrapValidator instance
1593        //          return true or false;
1594        //      }
1595        //
1596        // The 3 following settings are equivalent:
1597        //
1598        // 1) ':disabled, :hidden, :not(:visible)'
1599        // 2) [':disabled', ':hidden', ':not(:visible)']
1600        // 3) [':disabled', ':hidden', function($field) {
1601        //        return !$field.is(':visible');
1602        //    }]
1603        excluded: [':disabled', ':hidden', ':not(:visible)'],
1604
1605        // Shows ok/error/loading icons based on the field validity.
1606        // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation).
1607        // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically.
1608        // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later.
1609        //
1610        // Examples:
1611        // - Use Glyphicons icons:
1612        //  feedbackIcons: {
1613        //      valid: 'glyphicon glyphicon-ok',
1614        //      invalid: 'glyphicon glyphicon-remove',
1615        //      validating: 'glyphicon glyphicon-refresh'
1616        //  }
1617        // - Use FontAwesome icons:
1618        //  feedbackIcons: {
1619        //      valid: 'fa fa-check',
1620        //      invalid: 'fa fa-times',
1621        //      validating: 'fa fa-refresh'
1622        //  }
1623        feedbackIcons: {
1624            valid:      null,
1625            invalid:    null,
1626            validating: null
1627        },
1628
1629        // The submit buttons selector
1630        // These buttons will be disabled to prevent the valid form from multiple submissions
1631        submitButtons: '[type="submit"]',
1632
1633        // Live validating option
1634        // Can be one of 3 values:
1635        // - enabled: The plugin validates fields as soon as they are changed
1636        // - disabled: Disable the live validating. The error messages are only shown after the form is submitted
1637        // - submitted: The live validating is enabled after the form is submitted
1638        live: 'enabled',
1639
1640        // Map the field name with validator rules
1641        fields: null
1642    };
1643
1644    // Available validators
1645    $.fn.bootstrapValidator.validators  = {};
1646
1647    // i18n
1648    $.fn.bootstrapValidator.i18n        = {};
1649
1650    $.fn.bootstrapValidator.Constructor = BootstrapValidator;
1651
1652    // Helper methods, which can be used in validator class
1653    $.fn.bootstrapValidator.helpers = {
1654        /**
1655         * Execute a callback function
1656         *
1657         * @param {String|Function} functionName Can be
1658         * - name of global function
1659         * - name of namespace function (such as A.B.C)
1660         * - a function
1661         * @param {Array} args The callback arguments
1662         */
1663        call: function(functionName, args) {
1664            if ('function' === typeof functionName) {
1665                return functionName.apply(this, args);
1666            } else if ('string' === typeof functionName) {
1667                if ('()' === functionName.substring(functionName.length - 2)) {
1668                    functionName = functionName.substring(0, functionName.length - 2);
1669                }
1670                var ns      = functionName.split('.'),
1671                    func    = ns.pop(),
1672                    context = window;
1673                for (var i = 0; i < ns.length; i++) {
1674                    context = context[ns[i]];
1675                }
1676                return context[func].apply(this, args);
1677            }
1678        },
1679
1680        /**
1681         * Format a string
1682         * It's used to format the error message
1683         * format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20'
1684         *
1685         * @param {String} message
1686         * @param {Array} parameters
1687         * @returns {String}
1688         */
1689        format: function(message, parameters) {
1690            if (!$.isArray(parameters)) {
1691                parameters = [parameters];
1692            }
1693
1694            for (var i in parameters) {
1695                message = message.replace('%s', parameters[i]);
1696            }
1697
1698            return message;
1699        },
1700
1701        /**
1702         * Validate a date
1703         *
1704         * @param {Number} year The full year in 4 digits
1705         * @param {Number} month The month number
1706         * @param {Number} day The day number
1707         * @param {Boolean} [notInFuture] If true, the date must not be in the future
1708         * @returns {Boolean}
1709         */
1710        date: function(year, month, day, notInFuture) {
1711            if (isNaN(year) || isNaN(month) || isNaN(day)) {
1712                return false;
1713            }
1714
1715            day   = parseInt(day, 10);
1716            month = parseInt(month, 10);
1717            year  = parseInt(year, 10);
1718
1719            if (year < 1000 || year > 9999 || month <= 0 || month > 12) {
1720                return false;
1721            }
1722            var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1723            // Update the number of days in Feb of leap year
1724            if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
1725                numDays[1] = 29;
1726            }
1727
1728            // Check the day
1729            if (day <= 0 || day > numDays[month - 1]) {
1730                return false;
1731            }
1732
1733            if (notInFuture === true) {
1734                var currentDate  = new Date(),
1735                    currentYear  = currentDate.getFullYear(),
1736                    currentMonth = currentDate.getMonth(),
1737                    currentDay   = currentDate.getDate();
1738                return (year < currentYear
1739                        || (year === currentYear && month - 1 < currentMonth)
1740                        || (year === currentYear && month - 1 === currentMonth && day < currentDay));
1741            }
1742
1743            return true;
1744        },
1745
1746        /**
1747         * Implement Luhn validation algorithm
1748         * Credit to https://gist.github.com/ShirtlessKirk/2134376
1749         *
1750         * @see http://en.wikipedia.org/wiki/Luhn
1751         * @param {String} value
1752         * @returns {Boolean}
1753         */
1754        luhn: function(value) {
1755            var length  = value.length,
1756                mul     = 0,
1757                prodArr = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]],
1758                sum     = 0;
1759
1760            while (length--) {
1761                sum += prodArr[mul][parseInt(value.charAt(length), 10)];
1762                mul ^= 1;
1763            }
1764
1765            return (sum % 10 === 0 && sum > 0);
1766        },
1767
1768        /**
1769         * Implement modulus 11, 10 (ISO 7064) algorithm
1770         *
1771         * @param {String} value
1772         * @returns {Boolean}
1773         */
1774        mod11And10: function(value) {
1775            var check  = 5,
1776                length = value.length;
1777            for (var i = 0; i < length; i++) {
1778                check = (((check || 10) * 2) % 11 + parseInt(value.charAt(i), 10)) % 10;
1779            }
1780            return (check === 1);
1781        },
1782
1783        /**
1784         * Implements Mod 37, 36 (ISO 7064) algorithm
1785         * Usages:
1786         * mod37And36('A12425GABC1234002M')
1787         * mod37And36('002006673085', '0123456789')
1788         *
1789         * @param {String} value
1790         * @param {String} [alphabet]
1791         * @returns {Boolean}
1792         */
1793        mod37And36: function(value, alphabet) {
1794            alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
1795            var modulus = alphabet.length,
1796                length  = value.length,
1797                check   = Math.floor(modulus / 2);
1798            for (var i = 0; i < length; i++) {
1799                check = (((check || modulus) * 2) % (modulus + 1) + alphabet.indexOf(value.charAt(i))) % modulus;
1800            }
1801            return (check === 1);
1802        }
1803    };
1804}(window.jQuery));
1805;(function($) {
1806    $.fn.bootstrapValidator.i18n.base64 = $.extend($.fn.bootstrapValidator.i18n.base64 || {}, {
1807        'default': 'Please enter a valid base 64 encoded'
1808    });
1809
1810    $.fn.bootstrapValidator.validators.base64 = {
1811        /**
1812         * Return true if the input value is a base 64 encoded string.
1813         *
1814         * @param {BootstrapValidator} validator The validator plugin instance
1815         * @param {jQuery} $field Field element
1816         * @param {Object} options Can consist of the following keys:
1817         * - message: The invalid message
1818         * @returns {Boolean}
1819         */
1820        validate: function(validator, $field, options) {
1821            var value = $field.val();
1822            if (value === '') {
1823                return true;
1824            }
1825
1826            return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(value);
1827        }
1828    };
1829}(window.jQuery));
1830;(function($) {
1831    $.fn.bootstrapValidator.i18n.between = $.extend($.fn.bootstrapValidator.i18n.between || {}, {
1832        'default': 'Please enter a value between %s and %s',
1833        notInclusive: 'Please enter a value between %s and %s strictly'
1834    });
1835
1836    $.fn.bootstrapValidator.validators.between = {
1837        html5Attributes: {
1838            message: 'message',
1839            min: 'min',
1840            max: 'max',
1841            inclusive: 'inclusive'
1842        },
1843
1844        enableByHtml5: function($field) {
1845            if ('range' === $field.attr('type')) {
1846                return {
1847                    min: $field.attr('min'),
1848                    max: $field.attr('max')
1849                };
1850            }
1851
1852            return false;
1853        },
1854
1855        /**
1856         * Return true if the input value is between (strictly or not) two given numbers
1857         *
1858         * @param {BootstrapValidator} validator The validator plugin instance
1859         * @param {jQuery} $field Field element
1860         * @param {Object} options Can consist of the following keys:
1861         * - min
1862         * - max
1863         *
1864         * The min, max keys define the number which the field value compares to. min, max can be
1865         *      - A number
1866         *      - Name of field which its value defines the number
1867         *      - Name of callback function that returns the number
1868         *      - A callback function that returns the number
1869         *
1870         * - inclusive [optional]: Can be true or false. Default is true
1871         * - message: The invalid message
1872         * @returns {Boolean|Object}
1873         */
1874        validate: function(validator, $field, options) {
1875            var value = $field.val();
1876            if (value === '') {
1877                return true;
1878            }
1879
1880            var min = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min),
1881                max = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max);
1882
1883            value = parseFloat(value);
1884			return (options.inclusive === true || options.inclusive === undefined)
1885                    ? {
1886                        valid: value >= min && value <= max,
1887                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between['default'], [min, max])
1888                    }
1889                    : {
1890                        valid: value > min  && value <  max,
1891                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between.notInclusive, [min, max])
1892                    };
1893        }
1894    };
1895}(window.jQuery));
1896;(function($) {
1897    $.fn.bootstrapValidator.i18n.callback = $.extend($.fn.bootstrapValidator.i18n.callback || {}, {
1898        'default': 'Please enter a valid value'
1899    });
1900
1901    $.fn.bootstrapValidator.validators.callback = {
1902        html5Attributes: {
1903            message: 'message',
1904            callback: 'callback'
1905        },
1906
1907        /**
1908         * Return result from the callback method
1909         *
1910         * @param {BootstrapValidator} validator The validator plugin instance
1911         * @param {jQuery} $field Field element
1912         * @param {Object} options Can consist of the following keys:
1913         * - callback: The callback method that passes 2 parameters:
1914         *      callback: function(fieldValue, validator, $field) {
1915         *          // fieldValue is the value of field
1916         *          // validator is instance of BootstrapValidator
1917         *          // $field is the field element
1918         *      }
1919         * - message: The invalid message
1920         * @returns {Boolean|Deferred}
1921         */
1922        validate: function(validator, $field, options) {
1923            var value = $field.val();
1924
1925            if (options.callback) {
1926                var dfd      = new $.Deferred(),
1927                    response = $.fn.bootstrapValidator.helpers.call(options.callback, [value, validator, $field]);
1928                dfd.resolve($field, 'callback', 'boolean' === typeof response ? response : response.valid, 'object' === typeof response && response.message ? response.message : null);
1929                return dfd;
1930            }
1931
1932            return true;
1933        }
1934    };
1935}(window.jQuery));
1936;(function($) {
1937    $.fn.bootstrapValidator.i18n.choice = $.extend($.fn.bootstrapValidator.i18n.choice || {}, {
1938        'default': 'Please enter a valid value',
1939        less: 'Please choose %s options at minimum',
1940        more: 'Please choose %s options at maximum',
1941        between: 'Please choose %s - %s options'
1942    });
1943
1944    $.fn.bootstrapValidator.validators.choice = {
1945        html5Attributes: {
1946            message: 'message',
1947            min: 'min',
1948            max: 'max'
1949        },
1950
1951        /**
1952         * Check if the number of checked boxes are less or more than a given number
1953         *
1954         * @param {BootstrapValidator} validator The validator plugin instance
1955         * @param {jQuery} $field Field element
1956         * @param {Object} options Consists of following keys:
1957         * - min
1958         * - max
1959         *
1960         * At least one of two keys is required
1961         * The min, max keys define the number which the field value compares to. min, max can be
1962         *      - A number
1963         *      - Name of field which its value defines the number
1964         *      - Name of callback function that returns the number
1965         *      - A callback function that returns the number
1966         *
1967         * - message: The invalid message
1968         * @returns {Object}
1969         */
1970        validate: function(validator, $field, options) {
1971            var numChoices = $field.is('select')
1972                            ? validator.getFieldElements($field.attr('data-bv-field')).find('option').filter(':selected').length
1973                            : validator.getFieldElements($field.attr('data-bv-field')).filter(':checked').length,
1974                min        = options.min ? ($.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min)) : null,
1975                max        = options.max ? ($.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max)) : null,
1976                isValid    = true,
1977                message    = options.message || $.fn.bootstrapValidator.i18n.choice['default'];
1978
1979            if ((min && numChoices < parseInt(min, 10)) || (max && numChoices > parseInt(max, 10))) {
1980                isValid = false;
1981            }
1982
1983            switch (true) {
1984                case (!!min && !!max):
1985                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.between, [parseInt(min, 10), parseInt(max, 10)]);
1986                    break;
1987
1988                case (!!min):
1989                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.less, parseInt(min, 10));
1990                    break;
1991
1992                case (!!max):
1993                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.more, parseInt(max, 10));
1994                    break;
1995
1996                default:
1997                    break;
1998            }
1999
2000            return { valid: isValid, message: message };
2001        }
2002    };
2003}(window.jQuery));
2004;(function($) {
2005    $.fn.bootstrapValidator.i18n.creditCard = $.extend($.fn.bootstrapValidator.i18n.creditCard || {}, {
2006        'default': 'Please enter a valid credit card number'
2007    });
2008
2009    $.fn.bootstrapValidator.validators.creditCard = {
2010        /**
2011         * Return true if the input value is valid credit card number
2012         * Based on https://gist.github.com/DiegoSalazar/4075533
2013         *
2014         * @param {BootstrapValidator} validator The validator plugin instance
2015         * @param {jQuery} $field Field element
2016         * @param {Object} [options] Can consist of the following key:
2017         * - message: The invalid message
2018         * @returns {Boolean}
2019         */
2020        validate: function(validator, $field, options) {
2021            var value = $field.val();
2022            if (value === '') {
2023                return true;
2024            }
2025
2026            // Accept only digits, dashes or spaces
2027            if (/[^0-9-\s]+/.test(value)) {
2028                return false;
2029            }
2030            value = value.replace(/\D/g, '');
2031
2032            if (!$.fn.bootstrapValidator.helpers.luhn(value)) {
2033                return false;
2034            }
2035
2036            // Validate the card number based on prefix (IIN ranges) and length
2037            var cards = {
2038                AMERICAN_EXPRESS: {
2039                    length: [15],
2040                    prefix: ['34', '37']
2041                },
2042                DINERS_CLUB: {
2043                    length: [14],
2044                    prefix: ['300', '301', '302', '303', '304', '305', '36']
2045                },
2046                DINERS_CLUB_US: {
2047                    length: [16],
2048                    prefix: ['54', '55']
2049                },
2050                DISCOVER: {
2051                    length: [16],
2052                    prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
2053                             '62214', '62215', '62216', '62217', '62218', '62219',
2054                             '6222', '6223', '6224', '6225', '6226', '6227', '6228',
2055                             '62290', '62291', '622920', '622921', '622922', '622923',
2056                             '622924', '622925', '644', '645', '646', '647', '648',
2057                             '649', '65']
2058                },
2059                JCB: {
2060                    length: [16],
2061                    prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
2062                },
2063                LASER: {
2064                    length: [16, 17, 18, 19],
2065                    prefix: ['6304', '6706', '6771', '6709']
2066                },
2067                MAESTRO: {
2068                    length: [12, 13, 14, 15, 16, 17, 18, 19],
2069                    prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
2070                },
2071                MASTERCARD: {
2072                    length: [16],
2073                    prefix: ['51', '52', '53', '54', '55']
2074                },
2075                SOLO: {
2076                    length: [16, 18, 19],
2077                    prefix: ['6334', '6767']
2078                },
2079                UNIONPAY: {
2080                    length: [16, 17, 18, 19],
2081                    prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
2082                             '62215', '62216', '62217', '62218', '62219', '6222', '6223',
2083                             '6224', '6225', '6226', '6227', '6228', '62290', '62291',
2084                             '622920', '622921', '622922', '622923', '622924', '622925']
2085                },
2086                VISA: {
2087                    length: [16],
2088                    prefix: ['4']
2089                }
2090            };
2091
2092            var type, i;
2093            for (type in cards) {
2094                for (i in cards[type].prefix) {
2095                    if (value.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i]     // Check the prefix
2096                        && $.inArray(value.length, cards[type].length) !== -1)                      // and length
2097                    {
2098                        return true;
2099                    }
2100                }
2101            }
2102
2103            return false;
2104        }
2105    };
2106}(window.jQuery));
2107;(function($) {
2108    $.fn.bootstrapValidator.i18n.cusip = $.extend($.fn.bootstrapValidator.i18n.cusip || {}, {
2109        'default': 'Please enter a valid CUSIP number'
2110    });
2111
2112    $.fn.bootstrapValidator.validators.cusip = {
2113        /**
2114         * Validate a CUSIP
2115         * Examples:
2116         * - Valid: 037833100, 931142103, 14149YAR8, 126650BG6
2117         * - Invalid: 31430F200, 022615AC2
2118         *
2119         * @see http://en.wikipedia.org/wiki/CUSIP
2120         * @param {BootstrapValidator} validator The validator plugin instance
2121         * @param {jQuery} $field Field element
2122         * @param {Object} [options] Can consist of the following keys:
2123         * - message: The invalid message
2124         * @returns {Boolean}
2125         */
2126        validate: function(validator, $field, options) {
2127            var value = $field.val();
2128            if (value === '') {
2129                return true;
2130            }
2131
2132            value = value.toUpperCase();
2133            if (!/^[0-9A-Z]{9}$/.test(value)) {
2134                return false;
2135            }
2136
2137            var converted = $.map(value.split(''), function(item) {
2138                                var code = item.charCodeAt(0);
2139                                return (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0))
2140                                            // Replace A, B, C, ..., Z with 10, 11, ..., 35
2141                                            ? (code - 'A'.charCodeAt(0) + 10)
2142                                            : item;
2143                            }),
2144                length    = converted.length,
2145                sum       = 0;
2146            for (var i = 0; i < length - 1; i++) {
2147                var num = parseInt(converted[i], 10);
2148                if (i % 2 !== 0) {
2149                    num *= 2;
2150                }
2151                if (num > 9) {
2152                    num -= 9;
2153                }
2154                sum += num;
2155            }
2156
2157            sum = (10 - (sum % 10)) % 10;
2158            return sum === converted[length - 1];
2159        }
2160    };
2161}(window.jQuery));
2162;(function($) {
2163    $.fn.bootstrapValidator.i18n.cvv = $.extend($.fn.bootstrapValidator.i18n.cvv || {}, {
2164        'default': 'Please enter a valid CVV number'
2165    });
2166
2167    $.fn.bootstrapValidator.validators.cvv = {
2168        html5Attributes: {
2169            message: 'message',
2170            ccfield: 'creditCardField'
2171        },
2172
2173        /**
2174         * Return true if the input value is a valid CVV number.
2175         *
2176         * @param {BootstrapValidator} validator The validator plugin instance
2177         * @param {jQuery} $field Field element
2178         * @param {Object} options Can consist of the following keys:
2179         * - creditCardField: The credit card number field. It can be null
2180         * - message: The invalid message
2181         * @returns {Boolean}
2182         */
2183        validate: function(validator, $field, options) {
2184            var value = $field.val();
2185            if (value === '') {
2186                return true;
2187            }
2188
2189            if (!/^[0-9]{3,4}$/.test(value)) {
2190                return false;
2191            }
2192
2193            if (!options.creditCardField) {
2194                return true;
2195            }
2196
2197            // Get the credit card number
2198            var creditCard = validator.getFieldElements(options.creditCardField).val();
2199            if (creditCard === '') {
2200                return true;
2201            }
2202            
2203            creditCard = creditCard.replace(/\D/g, '');
2204
2205            // Supported credit card types
2206            var cards = {
2207                AMERICAN_EXPRESS: {
2208                    length: [15],
2209                    prefix: ['34', '37']
2210                },
2211                DINERS_CLUB: {
2212                    length: [14],
2213                    prefix: ['300', '301', '302', '303', '304', '305', '36']
2214                },
2215                DINERS_CLUB_US: {
2216                    length: [16],
2217                    prefix: ['54', '55']
2218                },
2219                DISCOVER: {
2220                    length: [16],
2221                    prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
2222                             '62214', '62215', '62216', '62217', '62218', '62219',
2223                             '6222', '6223', '6224', '6225', '6226', '6227', '6228',
2224                             '62290', '62291', '622920', '622921', '622922', '622923',
2225                             '622924', '622925', '644', '645', '646', '647', '648',
2226                             '649', '65']
2227                },
2228                JCB: {
2229                    length: [16],
2230                    prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
2231                },
2232                LASER: {
2233                    length: [16, 17, 18, 19],
2234                    prefix: ['6304', '6706', '6771', '6709']
2235                },
2236                MAESTRO: {
2237                    length: [12, 13, 14, 15, 16, 17, 18, 19],
2238                    prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
2239                },
2240                MASTERCARD: {
2241                    length: [16],
2242                    prefix: ['51', '52', '53', '54', '55']
2243                },
2244                SOLO: {
2245                    length: [16, 18, 19],
2246                    prefix: ['6334', '6767']
2247                },
2248                UNIONPAY: {
2249                    length: [16, 17, 18, 19],
2250                    prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
2251                             '62215', '62216', '62217', '62218', '62219', '6222', '6223',
2252                             '6224', '6225', '6226', '6227', '6228', '62290', '62291',
2253                             '622920', '622921', '622922', '622923', '622924', '622925']
2254                },
2255                VISA: {
2256                    length: [16],
2257                    prefix: ['4']
2258                }
2259            };
2260            var type, i, creditCardType = null;
2261            for (type in cards) {
2262                for (i in cards[type].prefix) {
2263                    if (creditCard.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i]    // Check the prefix
2264                        && $.inArray(creditCard.length, cards[type].length) !== -1)                     // and length
2265                    {
2266                        creditCardType = type;
2267                        break;
2268                    }
2269                }
2270            }
2271
2272            return (creditCardType === null)
2273                        ? false
2274                        : (('AMERICAN_EXPRESS' === creditCardType) ? (value.length === 4) : (value.length === 3));
2275        }
2276    };
2277}(window.jQuery));
2278;(function($) {
2279    $.fn.bootstrapValidator.i18n.date = $.extend($.fn.bootstrapValidator.i18n.date || {}, {
2280        'default': 'Please enter a valid date'
2281    });
2282
2283    $.fn.bootstrapValidator.validators.date = {
2284        html5Attributes: {
2285            message: 'message',
2286            format: 'format',
2287            separator: 'separator'
2288        },
2289
2290        /**
2291         * Return true if the input value is valid date
2292         *
2293         * @param {BootstrapValidator} validator The validator plugin instance
2294         * @param {jQuery} $field Field element
2295         * @param {Object} options Can consist of the following keys:
2296         * - message: The invalid message
2297         * - separator: Use to separate the date, month, and year.
2298         * By default, it is /
2299         * - format: The date format. Default is MM/DD/YYYY
2300         * The format can be:
2301         *
2302         * i) date: Consist of DD, MM, YYYY parts which are separated by the separator option
2303         * ii) date and time:
2304         * The time can consist of h, m, s parts which are separated by :
2305         * ii) date, time and A (indicating AM or PM)
2306         * @returns {Boolean}
2307         */
2308        validate: function(validator, $field, options) {
2309            var value = $field.val();
2310            if (value === '') {
2311                return true;
2312            }
2313
2314            options.format = options.format || 'MM/DD/YYYY';
2315
2316            var formats    = options.format.split(' '),
2317                dateFormat = formats[0],
2318                timeFormat = (formats.length > 1) ? formats[1] : null,
2319                amOrPm     = (formats.length > 2) ? formats[2] : null,
2320                sections   = value.split(' '),
2321                date       = sections[0],
2322                time       = (sections.length > 1) ? sections[1] : null;
2323
2324            if (formats.length !== sections.length) {
2325                return false;
2326            }
2327
2328            // Determine the separator
2329            var separator = options.separator;
2330            if (!separator) {
2331                separator = (date.indexOf('/') !== -1) ? '/' : ((date.indexOf('-') !== -1) ? '-' : null);
2332            }
2333            if (separator === null || date.indexOf(separator) === -1) {
2334                return false;
2335            }
2336
2337            // Determine the date
2338            date       = date.split(separator);
2339            dateFormat = dateFormat.split(separator);
2340            if (date.length !== dateFormat.length) {
2341                return false;
2342            }
2343
2344            var year  = date[$.inArray('YYYY', dateFormat)],
2345                month = date[$.inArray('MM', dateFormat)],
2346                day   = date[$.inArray('DD', dateFormat)];
2347
2348            if (!year || !month || !day) {
2349                return false;
2350            }
2351
2352            // Determine the time
2353            var minutes = null, hours = null, seconds = null;
2354            if (timeFormat) {
2355                timeFormat = timeFormat.split(':');
2356                time       = time.split(':');
2357
2358                if (timeFormat.length !== time.length) {
2359                    return false;
2360                }
2361
2362                hours   = time.length > 0 ? time[0] : null;
2363                minutes = time.length > 1 ? time[1] : null;
2364                seconds = time.length > 2 ? time[2] : null;
2365
2366                // Validate seconds
2367                if (seconds) {
2368                    seconds = parseInt(seconds, 10);
2369                    if (isNaN(seconds) || seconds < 0 || seconds > 60) {
2370                        return false;
2371                    }
2372                }
2373
2374                // Validate hours
2375                if (hours) {
2376                    hours = parseInt(hours, 10);
2377                    if (isNaN(hours) || hours < 0 || hours >= 24 || (amOrPm && hours > 12)) {
2378                        return false;
2379                    }
2380                }
2381
2382                // Validate minutes
2383                if (minutes) {
2384                    minutes = parseInt(minutes, 10);
2385                    if (isNaN(minutes) || minutes < 0 || minutes > 59) {
2386                        return false;
2387                    }
2388                }
2389            }
2390
2391            // Validate day, month, and year
2392            return $.fn.bootstrapValidator.helpers.date(year, month, day);
2393        }
2394    };
2395}(window.jQuery));
2396;(function($) {
2397    $.fn.bootstrapValidator.i18n.different = $.extend($.fn.bootstrapValidator.i18n.different || {}, {
2398        'default': 'Please enter a different value'
2399    });
2400
2401    $.fn.bootstrapValidator.validators.different = {
2402        html5Attributes: {
2403            message: 'message',
2404            field: 'field'
2405        },
2406
2407        /**
2408         * Return true if the input value is different with given field's value
2409         *
2410         * @param {BootstrapValidator} validator The validator plugin instance
2411         * @param {jQuery} $field Field element
2412         * @param {Object} options Consists of the following key:
2413         * - field: The name of field that will be used to compare with current one
2414         * - message: The invalid message
2415         * @returns {Boolean}
2416         */
2417        validate: function(validator, $field, options) {
2418            var value = $field.val();
2419            if (value === '') {
2420                return true;
2421            }
2422
2423            var compareWith = validator.getFieldElements(options.field);
2424            if (compareWith === null) {
2425                return true;
2426            }
2427
2428            if (value !== compareWith.val()) {
2429                validator.updateStatus(options.field, validator.STATUS_VALID, 'different');
2430                return true;
2431            } else {
2432                return false;
2433            }
2434        }
2435    };
2436}(window.jQuery));
2437;(function($) {
2438    $.fn.bootstrapValidator.i18n.digits = $.extend($.fn.bootstrapValidator.i18n.digits || {}, {
2439        'default': 'Please enter only digits'
2440    });
2441
2442    $.fn.bootstrapValidator.validators.digits = {
2443        /**
2444         * Return true if the input value contains digits only
2445         *
2446         * @param {BootstrapValidator} validator Validate plugin instance
2447         * @param {jQuery} $field Field element
2448         * @param {Object} [options]
2449         * @returns {Boolean}
2450         */
2451        validate: function(validator, $field, options) {
2452            var value = $field.val();
2453            if (value === '') {
2454                return true;
2455            }
2456
2457            return /^\d+$/.test(value);
2458        }
2459    };
2460}(window.jQuery));
2461;(function($) {
2462    $.fn.bootstrapValidator.i18n.ean = $.extend($.fn.bootstrapValidator.i18n.ean || {}, {
2463        'default': 'Please enter a valid EAN number'
2464    });
2465
2466    $.fn.bootstrapValidator.validators.ean = {
2467        /**
2468         * Validate EAN (International Article Number)
2469         * Examples:
2470         * - Valid: 73513537, 9780471117094, 4006381333931
2471         * - Invalid: 73513536
2472         *
2473         * @see http://en.wikipedia.org/wiki/European_Article_Number
2474         * @param {BootstrapValidator} validator The validator plugin instance
2475         * @param {jQuery} $field Field element
2476         * @param {Object} options Can consist of the following keys:
2477         * - message: The invalid message
2478         * @returns {Boolean}
2479         */
2480        validate: function(validator, $field, options) {
2481            var value = $field.val();
2482            if (value === '') {
2483                return true;
2484            }
2485
2486            if (!/^(\d{8}|\d{12}|\d{13})$/.test(value)) {
2487                return false;
2488            }
2489
2490            var length = value.length,
2491                sum    = 0,
2492                weight = (length === 8) ? [3, 1] : [1, 3];
2493            for (var i = 0; i < length - 1; i++) {
2494                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
2495            }
2496            sum = (10 - sum % 10) % 10;
2497            return (sum + '' === value.charAt(length - 1));
2498        }
2499    };
2500}(window.jQuery));
2501;(function($) {
2502    $.fn.bootstrapValidator.i18n.emailAddress = $.extend($.fn.bootstrapValidator.i18n.emailAddress || {}, {
2503        'default': 'Please enter a valid email address'
2504    });
2505
2506    $.fn.bootstrapValidator.validators.emailAddress = {
2507        enableByHtml5: function($field) {
2508            return ('email' === $field.attr('type'));
2509        },
2510
2511        /**
2512         * Return true if and only if the input value is a valid email address
2513         *
2514         * @param {BootstrapValidator} validator Validate plugin instance
2515         * @param {jQuery} $field Field element
2516         * @param {Object} [options]
2517         * @returns {Boolean}
2518         */
2519        validate: function(validator, $field, options) {
2520            var value = $field.val();
2521            if (value === '') {
2522                return true;
2523            }
2524
2525            // Email address regular expression
2526            // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
2527            var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2528            return emailRegExp.test(value);
2529        }
2530    };
2531}(window.jQuery));
2532;(function($) {
2533    $.fn.bootstrapValidator.i18n.file = $.extend($.fn.bootstrapValidator.i18n.file || {}, {
2534        'default': 'Please choose a valid file'
2535    });
2536
2537    $.fn.bootstrapValidator.validators.file = {
2538        html5Attributes: {
2539            extension: 'extension',
2540            maxsize: 'maxSize',
2541            message: 'message',
2542            type: 'type'
2543        },
2544
2545        /**
2546         * Validate upload file. Use HTML 5 API if the browser supports
2547         *
2548         * @param {BootstrapValidator} validator The validator plugin instance
2549         * @param {jQuery} $field Field element
2550         * @param {Object} options Can consist of the following keys:
2551         * - extension: The allowed extensions, separated by a comma
2552         * - maxSize: The maximum size in bytes
2553         * - message: The invalid message
2554         * - type: The allowed MIME type, separated by a comma
2555         * @returns {Boolean}
2556         */
2557        validate: function(validator, $field, options) {
2558            var value = $field.val();
2559            if (value === '') {
2560                return true;
2561            }
2562
2563            var ext,
2564                extensions = options.extension ? options.extension.toLowerCase().split(',') : null,
2565                types      = options.type      ? options.type.toLowerCase().split(',')      : null,
2566                html5      = (window.File && window.FileList && window.FileReader);
2567
2568            if (html5) {
2569                // Get FileList instance
2570                var files = $field.get(0).files,
2571                    total = files.length;
2572                for (var i = 0; i < total; i++) {
2573                    // Check file size
2574                    if (options.maxSize && files[i].size > parseInt(options.maxSize, 10)) {
2575                        return false;
2576                    }
2577
2578                    // Check file extension
2579                    ext = files[i].name.substr(files[i].name.lastIndexOf('.') + 1);
2580                    if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) {
2581                        return false;
2582                    }
2583
2584                    // Check file type
2585                    if (types && $.inArray(files[i].type.toLowerCase(), types) === -1) {
2586                        return false;
2587                    }
2588                }
2589            } else {
2590                // Check file extension
2591                ext = value.substr(value.lastIndexOf('.') + 1);
2592                if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) {
2593                    return false;
2594                }
2595            }
2596
2597            return true;
2598        }
2599    };
2600}(window.jQuery));
2601;(function($) {
2602    $.fn.bootstrapValidator.i18n.greaterThan = $.extend($.fn.bootstrapValidator.i18n.greaterThan || {}, {
2603        'default': 'Please enter a value greater than or equal to %s',
2604        notInclusive: 'Please enter a value greater than %s'
2605    });
2606
2607    $.fn.bootstrapValidator.validators.greaterThan = {
2608        html5Attributes: {
2609            message: 'message',
2610            value: 'value',
2611            inclusive: 'inclusive'
2612        },
2613
2614        enableByHtml5: function($field) {
2615            var min = $field.attr('min');
2616            if (min) {
2617                return {
2618                    value: min
2619                };
2620            }
2621
2622            return false;
2623        },
2624
2625        /**
2626         * Return true if the input value is greater than or equals to given number
2627         *
2628         * @param {BootstrapValidator} validator Validate plugin instance
2629         * @param {jQuery} $field Field element
2630         * @param {Object} options Can consist of the following keys:
2631         * - value: Define the number to compare with. It can be
2632         *      - A number
2633         *      - Name of field which its value defines the number
2634         *      - Name of callback function that returns the number
2635         *      - A callback function that returns the number
2636         *
2637         * - inclusive [optional]: Can be true or false. Default is true
2638         * - message: The invalid message
2639         * @returns {Boolean|Object}
2640         */
2641        validate: function(validator, $field, options) {
2642            var value = $field.val();
2643            if (value === '') {
2644                return true;
2645            }
2646
2647            var compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value);
2648
2649            value = parseFloat(value);
2650			return (options.inclusive === true || options.inclusive === undefined)
2651                    ? {
2652                        valid: value >= compareTo,
2653                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan['default'], compareTo)
2654                    }
2655                    : {
2656                        valid: value > compareTo,
2657                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan.notInclusive, compareTo)
2658                    };
2659        }
2660    };
2661}(window.jQuery));
2662;(function($) {
2663    $.fn.bootstrapValidator.i18n.grid = $.extend($.fn.bootstrapValidator.i18n.grid || {}, {
2664        'default': 'Please enter a valid GRId number'
2665    });
2666
2667    $.fn.bootstrapValidator.validators.grid = {
2668        /**
2669         * Validate GRId (Global Release Identifier)
2670         * Examples:
2671         * - Valid: A12425GABC1234002M, A1-2425G-ABC1234002-M, A1 2425G ABC1234002 M, Grid:A1-2425G-ABC1234002-M
2672         * - Invalid: A1-2425G-ABC1234002-Q
2673         *
2674         * @see http://en.wikipedia.org/wiki/Global_Release_Identifier
2675         * @param {BootstrapValidator} validator The validator plugin instance
2676         * @param {jQuery} $field Field element
2677         * @param {Object} options Can consist of the following keys:
2678         * - message: The invalid message
2679         * @returns {Boolean}
2680         */
2681        validate: function(validator, $field, options) {
2682            var value = $field.val();
2683            if (value === '') {
2684                return true;
2685            }
2686
2687            value = value.toUpperCase();
2688            if (!/^[GRID:]*([0-9A-Z]{2})[-\s]*([0-9A-Z]{5})[-\s]*([0-9A-Z]{10})[-\s]*([0-9A-Z]{1})$/g.test(value)) {
2689                return false;
2690            }
2691            value = value.replace(/\s/g, '').replace(/-/g, '');
2692            if ('GRID:' === value.substr(0, 5)) {
2693                value = value.substr(5);
2694            }
2695            return $.fn.bootstrapValidator.helpers.mod37And36(value);
2696        }
2697    };
2698}(window.jQuery));
2699;(function($) {
2700    $.fn.bootstrapValidator.i18n.hex = $.extend($.fn.bootstrapValidator.i18n.hex || {}, {
2701        'default': 'Please enter a valid hexadecimal number'
2702    });
2703
2704    $.fn.bootstrapValidator.validators.hex = {
2705        /**
2706         * Return true if and only if the input value is a valid hexadecimal number
2707         *
2708         * @param {BootstrapValidator} validator The validator plugin instance
2709         * @param {jQuery} $field Field element
2710         * @param {Object} options Consist of key:
2711         * - message: The invalid message
2712         * @returns {Boolean}
2713         */
2714        validate: function(validator, $field, options) {
2715            var value = $field.val();
2716            if (value === '') {
2717                return true;
2718            }
2719
2720            return /^[0-9a-fA-F]+$/.test(value);
2721        }
2722    };
2723}(window.jQuery));
2724;(function($) {
2725    $.fn.bootstrapValidator.i18n.hexColor = $.extend($.fn.bootstrapValidator.i18n.hexColor || {}, {
2726        'default': 'Please enter a valid hex color'
2727    });
2728
2729    $.fn.bootstrapValidator.validators.hexColor = {
2730        enableByHtml5: function($field) {
2731            return ('color' === $field.attr('type'));
2732        },
2733
2734        /**
2735         * Return true if the input value is a valid hex color
2736         *
2737         * @param {BootstrapValidator} validator The validator plugin instance
2738         * @param {jQuery} $field Field element
2739         * @param {Object} options Can consist of the following keys:
2740         * - message: The invalid message
2741         * @returns {Boolean}
2742         */
2743        validate: function(validator, $field, options) {
2744            var value = $field.val();
2745            if (value === '') {
2746                return true;
2747            }
2748            return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value);
2749        }
2750    };
2751}(window.jQuery));
2752;(function($) {
2753    $.fn.bootstrapValidator.i18n.iban = $.extend($.fn.bootstrapValidator.i18n.iban || {}, {
2754        'default': 'Please enter a valid IBAN number',
2755        countryNotSupported: 'The country code %s is not supported',
2756        country: 'Please enter a valid IBAN number in %s',
2757        countries: {
2758            AD: 'Andorra',
2759            AE: 'United Arab Emirates',
2760            AL: 'Albania',
2761            AO: 'Angola',
2762            AT: 'Austria',
2763            AZ: 'Azerbaijan',
2764            BA: 'Bosnia and Herzegovina',
2765            BE: 'Belgium',
2766            BF: 'Burkina Faso',
2767            BG: 'Bulgaria',
2768            BH: 'Bahrain',
2769            BI: 'Burundi',
2770            BJ: 'Benin',
2771            BR: 'Brazil',
2772            CH: 'Switzerland',
2773            CI: 'Ivory Coast',
2774            CM: 'Cameroon',
2775            CR: 'Costa Rica',
2776            CV: 'Cape Verde',
2777            CY: 'Cyprus',
2778            CZ: 'Czech Republic',
2779            DE: 'Germany',
2780            DK: 'Denmark',
2781            DO: 'Dominican Republic',
2782            DZ: 'Algeria',
2783            EE: 'Estonia',
2784            ES: 'Spain',
2785            FI: 'Finland',
2786            FO: 'Faroe Islands',
2787            FR: 'France',
2788            GB: 'United Kingdom',
2789            GE: 'Georgia',
2790            GI: 'Gibraltar',
2791            GL: 'Greenland',
2792            GR: 'Greece',
2793            GT: 'Guatemala',
2794            HR: 'Croatia',
2795            HU: 'Hungary',
2796            IE: 'Ireland',
2797            IL: 'Israel',
2798            IR: 'Iran',
2799            IS: 'Iceland',
2800            IT: 'Italy',
2801            JO: 'Jordan',
2802            KW: 'Kuwait',
2803            KZ: 'Kazakhstan',
2804            LB: 'Lebanon',
2805            LI: 'Liechtenstein',
2806            LT: 'Lithuania',
2807            LU: 'Luxembourg',
2808            LV: 'Latvia',
2809            MC: 'Monaco',
2810            MD: 'Moldova',
2811            ME: 'Montenegro',
2812            MG: 'Madagascar',
2813            MK: 'Macedonia',
2814            ML: 'Mali',
2815            MR: 'Mauritania',
2816            MT: 'Malta',
2817            MU: 'Mauritius',
2818            MZ: 'Mozambique',
2819            NL: 'Netherlands',
2820            NO: 'Norway',
2821            PK: 'Pakistan',
2822            PL: 'Poland',
2823            PS: 'Palestinian',
2824            PT: 'Portugal',
2825            QA: 'Qatar',
2826            RO: 'Romania',
2827            RS: 'Serbia',
2828            SA: 'Saudi Arabia',
2829            SE: 'Sweden',
2830            SI: 'Slovenia',
2831            SK: 'Slovakia',
2832            SM: 'San Marino',
2833            SN: 'Senegal',
2834            TN: 'Tunisia',
2835            TR: 'Turkey',
2836            VG: 'Virgin Islands, British'
2837        }
2838    });
2839
2840    $.fn.bootstrapValidator.validators.iban = {
2841        html5Attributes: {
2842            message: 'message',
2843            country: 'country'
2844        },
2845
2846        // http://www.swift.com/dsp/resources/documents/IBAN_Registry.pdf
2847        // http://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country
2848        REGEX: {
2849            'AD': 'AD[0-9]{2}[0-9]{4}[0-9]{4}[A-Z0-9]{12}',                     // Andorra
2850            'AE': 'AE[0-9]{2}[0-9]{3}[0-9]{16}',                                // United Arab Emirates
2851            'AL': 'AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}',                             // Albania
2852            'AO': 'AO[0-9]{2}[0-9]{21}',                                        // Angola
2853            'AT': 'AT[0-9]{2}[0-9]{5}[0-9]{11}',                                // Austria
2854            'AZ': 'AZ[0-9]{2}[A-Z]{4}[A-Z0-9]{20}',                             // Azerbaijan
2855            'BA': 'BA[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{8}[0-9]{2}',                 // Bosnia and Herzegovina
2856            'BE': 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}',                         // Belgium
2857            'BF': 'BF[0-9]{2}[0-9]{23}',                                        // Burkina Faso
2858            'BG': 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}',              // Bulgaria
2859            'BH': 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}',                             // Bahrain
2860            'BI': 'BI[0-9]{2}[0-9]{12}',                                        // Burundi
2861            'BJ': 'BJ[0-9]{2}[A-Z]{1}[0-9]{23}',                                // Benin
2862            'BR': 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]',           // Brazil
2863            'CH': 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}',                             // Switzerland
2864            'CI': 'CI[0-9]{2}[A-Z]{1}[0-9]{23}',                                // Ivory Coast
2865            'CM': 'CM[0-9]{2}[0-9]{23}',                                        // Cameroon
2866            'CR': 'CR[0-9]{2}[0-9]{3}[0-9]{14}',                                // Costa Rica
2867            'CV': 'CV[0-9]{2}[0-9]{21}',                                        // Cape Verde
2868            'CY': 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}',                     // Cyprus
2869            'CZ': 'CZ[0-9]{2}[0-9]{20}',                                        // Czech Republic
2870            'DE': 'DE[0-9]{2}[0-9]{8}[0-9]{10}',                                // Germany
2871            'DK': 'DK[0-9]{2}[0-9]{14}',                                        // Denmark
2872            'DO': 'DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}',                             // Dominican Republic
2873            'DZ': 'DZ[0-9]{2}[0-9]{20}',                                        // Algeria
2874            'EE': 'EE[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{11}[0-9]{1}',                // Estonia
2875            'ES': 'ES[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{1}[0-9]{1}[0-9]{10}',        // Spain
2876            'FI': 'FI[0-9]{2}[0-9]{6}[0-9]{7}[0-9]{1}',                         // Finland
2877            'FO': 'FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',                         // Faroe Islands
2878            'FR': 'FR[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',             // France
2879            'GB': 'GB[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',                         // United Kingdom
2880            'GE': 'GE[0-9]{2}[A-Z]{2}[0-9]{16}',                                // Georgia
2881            'GI': 'GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}',                             // Gibraltar
2882            'GL': 'GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',                         // Greenland
2883            'GR': 'GR[0-9]{2}[0-9]{3}[0-9]{4}[A-Z0-9]{16}',                     // Greece
2884            'GT': 'GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}',                          // Guatemala
2885            'HR': 'HR[0-9]{2}[0-9]{7}
2885[0-9]{10}',                                // Croatia
2886            'HU': 'HU[0-9]{2}[0-9]{3}[0-9]{4}[0-9]{1}[0-9]{15}[0-9]{1}',        // Hungary
2887            'IE': 'IE[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',                         // Ireland
2888            'IL': 'IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}',                        // Israel
2889            'IR': 'IR[0-9]{2}[0-9]{22}',                                        // Iran
2890            'IS': 'IS[0-9]{2}[0-9]{4}[0-9]{2}[0-9]{6}[0-9]{10}',                // Iceland
2891            'IT': 'IT[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',             // Italy
2892            'JO': 'JO[0-9]{2}[A-Z]{4}[0-9]{4}[0]{8}[A-Z0-9]{10}',               // Jordan
2893            'KW': 'KW[0-9]{2}[A-Z]{4}[0-9]{22}',                                // Kuwait
2894            'KZ': 'KZ[0-9]{2}[0-9]{3}[A-Z0-9]{13}',                             // Kazakhstan
2895            'LB': 'LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}',                             // Lebanon
2896            'LI': 'LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}',                             // Liechtenstein
2897            'LT': 'LT[0-9]{2}[0-9]{5}[0-9]{11}',                                // Lithuania
2898            'LU': 'LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}',                             // Luxembourg
2899            'LV': 'LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}',                             // Latvia
2900            'MC': 'MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',             // Monaco
2901            'MD': 'MD[0-9]{2}[A-Z0-9]{20}',                                     // Moldova
2902            'ME': 'ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                        // Montenegro
2903            'MG': 'MG[0-9]{2}[0-9]{23}',                                        // Madagascar
2904            'MK': 'MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}',                     // Macedonia
2905            'ML': 'ML[0-9]{2}[A-Z]{1}[0-9]{23}',                                // Mali
2906            'MR': 'MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}',                      // Mauritania
2907            'MT': 'MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}',                     // Malta
2908            'MU': 'MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{3}',// Mauritius
2909            'MZ': 'MZ[0-9]{2}[0-9]{21}',                                        // Mozambique
2910            'NL': 'NL[0-9]{2}[A-Z]{4}[0-9]{10}',                                // Netherlands
2911            'NO': 'NO[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{1}',                         // Norway
2912            'PK': 'PK[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',                             // Pakistan
2913            'PL': 'PL[0-9]{2}[0-9]{8}[0-9]{16}',                                // Poland
2914            'PS': 'PS[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',                             // Palestinian
2915            'PT': 'PT[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{11}[0-9]{2}',                // Portugal
2916            'QA': 'QA[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',                             // Qatar
2917            'RO': 'RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',                             // Romania
2918            'RS': 'RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                        // Serbia
2919            'SA': 'SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}',                             // Saudi Arabia
2920            'SE': 'SE[0-9]{2}[0-9]{3}[0-9]{16}[0-9]{1}',                        // Sweden
2921            'SI': 'SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}',                         // Slovenia
2922            'SK': 'SK[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{10}',                        // Slovakia
2923            'SM': 'SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',             // San Marino
2924            'SN': 'SN[0-9]{2}[A-Z]{1}[0-9]{23}',                                // Senegal
2925            'TN': 'TN59[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                      // Tunisia
2926            'TR': 'TR[0-9]{2}[0-9]{5}[A-Z0-9]{1}[A-Z0-9]{16}',                  // Turkey
2927            'VG': 'VG[0-9]{2}[A-Z]{4}[0-9]{16}'                                 // Virgin Islands, British
2928        },
2929
2930        /**
2931         * Validate an International Bank Account Number (IBAN)
2932         * To test it, take the sample IBAN from
2933         * http://www.nordea.com/Our+services/International+products+and+services/Cash+Management/IBAN+countries/908462.html
2934         *
2935         * @param {BootstrapValidator} validator The validator plugin instance
2936         * @param {jQuery} $field Field element
2937         * @param {Object} options Can consist of the following keys:
2938         * - message: The invalid message
2939         * - country: The ISO 3166-1 country code. It can be
2940         *      - A country code
2941         *      - Name of field which its value defines the country code
2942         *      - Name of callback function that returns the country code
2943         *      - A callback function that returns the country code
2944         * @returns {Boolean|Object}
2945         */
2946        validate: function(validator, $field, options) {
2947            var value = $field.val();
2948            if (value === '') {
2949                return true;
2950            }
2951
2952            value = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
2953            var country = options.country;
2954            if (!country) {
2955                country = value.substr(0, 2);
2956            } else if (typeof country !== 'string' || !this.REGEX[country]) {
2957                // Determine the country code
2958                country = validator.getDynamicOption($field, country);
2959            }
2960
2961            if (!this.REGEX[country]) {
2962                return {
2963                    valid: false,
2964                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.iban.countryNotSupported, country)
2965                };
2966            }
2967
2968            if (!(new RegExp('^' + this.REGEX[country] + '$')).test(value)) {
2969                return {
2970                    valid: false,
2971                    message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.iban.country, $.fn.bootstrapValidator.i18n.iban.countries[country])
2972                };
2973            }
2974
2975            value = value.substr(4) + value.substr(0, 4);
2976            value = $.map(value.split(''), function(n) {
2977                var code = n.charCodeAt(0);
2978                return (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0))
2979                        // Replace A, B, C, ..., Z with 10, 11, ..., 35
2980                        ? (code - 'A'.charCodeAt(0) + 10)
2981                        : n;
2982            });
2983            value = value.join('');
2984
2985            var temp   = parseInt(value.substr(0, 1), 10),
2986                length = value.length;
2987            for (var i = 1; i < length; ++i) {
2988                temp = (temp * 10 + parseInt(value.substr(i, 1), 10)) % 97;
2989            }
2990
2991            return {
2992                valid: (temp === 1),
2993                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.iban.country, $.fn.bootstrapValidator.i18n.iban.countries[country])
2994            };
2995        }
2996    };
2997}(window.jQuery));
2998;(function($) {
2999    $.fn.bootstrapValidator.i18n.id = $.extend($.fn.bootstrapValidator.i18n.id || {}, {
3000        'default': 'Please enter a valid identification number',
3001        countryNotSupported: 'The country code %s is not supported',
3002        country: 'Please enter a valid %s identification number',
3003        countries: {
3004            BA: 'Bosnia and Herzegovina',
3005            BG: 'Bulgarian',
3006            BR: 'Brazilian',
3007            CH: 'Swiss',
3008            CL: 'Chilean',
3009            CZ: 'Czech',
3010            DK: 'Danish',
3011            EE: 'Estonian',
3012            ES: 'Spanish',
3013            FI: 'Finnish',
3014            HR: 'Croatian',
3015            IE: 'Irish',
3016            IS: 'Iceland',
3017            LT: 'Lithuanian',
3018            LV: 'Latvian',
3019            ME: 'Montenegro',
3020            MK: 'Macedonian',
3021            NL: 'Dutch',
3022            RO: 'Romanian',
3023            RS: 'Serbian',
3024            SE: 'Swedish',
3025            SI: 'Slovenian',
3026            SK: 'Slovak',
3027            SM: 'San Marino',
3028            ZA: 'South African'
3029        }
3030    });
3031
3032    $.fn.bootstrapValidator.validators.id = {
3033        html5Attributes: {
3034            message: 'message',
3035            country: 'country'
3036        },
3037
3038        // Supported country codes
3039        COUNTRY_CODES: [
3040            'BA', 'BG', 'BR', 'CH', 'CL', 'CZ', 'DK', 'EE', 'ES', 'FI', 'HR', 'IE', 'IS', 'LT', 'LV', 'ME', 'MK', 'NL',
3041            'RO', 'RS', 'SE', 'SI', 'SK', 'SM', 'ZA'
3042        ],
3043
3044        /**
3045         * Validate identification number in different countries
3046         *
3047         * @see http://en.wikipedia.org/wiki/National_identification_number
3048         * @param {BootstrapValidator} validator The validator plugin instance
3049         * @param {jQuery} $field Field element
3050         * @param {Object} options Consist of key:
3051         * - message: The invalid message
3052         * - country: The ISO 3166-1 country code. It can be
3053         *      - One of country code defined in COUNTRY_CODES
3054         *      - Name of field which its value defines the country code
3055         *      - Name of callback function that returns the country code
3056         *      - A callback function that returns the country code
3057         * @returns {Boolean|Object}
3058         */
3059        validate: function(validator, $field, options) {
3060            var value = $field.val();
3061            if (value === '') {
3062                return true;
3063            }
3064
3065            var country = options.country;
3066            if (!country) {
3067                country = value.substr(0, 2);
3068            } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
3069                // Determine the country code
3070                country = validator.getDynamicOption($field, country);
3071            }
3072
3073            if ($.inArray(country, this.COUNTRY_CODES) === -1) {
3074                return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.id.countryNotSupported, country) };
3075            }
3076
3077            var method  = ['_', country.toLowerCase()].join('');
3078            return this[method](value)
3079                    ? true
3080                    : {
3081                        valid: false,
3082                        message: $.fn.bootstrapValidator.helpers.format(
3082options.message || $.fn.bootstrapValidator.i18n.id.country, $.fn.bootstrapValidator.i18n.id.countries[country.toUpperCase()])
3083                    };
3084        },
3085
3086        /**
3087         * Validate Unique Master Citizen Number which uses in
3088         * - Bosnia and Herzegovina (country code: BA)
3089         * - Macedonia (MK)
3090         * - Montenegro (ME)
3091         * - Serbia (RS)
3092         * - Slovenia (SI)
3093         *
3094         * @see http://en.wikipedia.org/wiki/Unique_Master_Citizen_Number
3095         * @param {String} value The ID
3096         * @param {String} countryCode The ISO country code, can be BA, MK, ME, RS, SI
3097         * @returns {Boolean}
3098         */
3099        _validateJMBG: function(value, countryCode) {
3100            if (!/^\d{13}$/.test(value)) {
3101                return false;
3102            }
3103            var day   = parseInt(value.substr(0, 2), 10),
3104                month = parseInt(value.substr(2, 2), 10),
3105                year  = parseInt(value.substr(4, 3), 10),
3106                rr    = parseInt(value.substr(7, 2), 10),
3107                k     = parseInt(value.substr(12, 1), 10);
3108
3109            // Validate date of birth
3110            // FIXME: Validate the year of birth
3111            if (day > 31 || month > 12) {
3112                return false;
3113            }
3114
3115            // Validate checksum
3116            var sum = 0;
3117            for (var i = 0; i < 6; i++) {
3118                sum += (7 - i) * (parseInt(value.charAt(i), 10) + parseInt(value.charAt(i + 6), 10));
3119            }
3120            sum = 11 - sum % 11;
3121            if (sum === 10 || sum === 11) {
3122                sum = 0;
3123            }
3124            if (sum !== k) {
3125                return false;
3126            }
3127
3128            // Validate political region
3129            // rr is the political region of birth, which can be in ranges:
3130            // 10-19: Bosnia and Herzegovina
3131            // 20-29: Montenegro
3132            // 30-39: Croatia (not used anymore)
3133            // 41-49: Macedonia
3134            // 50-59: Slovenia (only 50 is used)
3135            // 70-79: Central Serbia
3136            // 80-89: Serbian province of Vojvodina
3137            // 90-99: Kosovo
3138            switch (countryCode.toUpperCase()) {
3139                case 'BA':
3140                    return (10 <= rr && rr <= 19);
3141                case 'MK':
3142                    return (41 <= rr && rr <= 49);
3143                case 'ME':
3144                    return (20 <= rr && rr <= 29);
3145                case 'RS':
3146                    return (70 <= rr && rr <= 99);
3147                case 'SI':
3148                    return (50 <= rr && rr <= 59);
3149                default:
3150                    return true;
3151            }
3152        },
3153
3154        _ba: function(value) {
3155            return this._validateJMBG(value, 'BA');
3156        },
3157        _mk: function(value) {
3158            return this._validateJMBG(value, 'MK');
3159        },
3160        _me: function(value) {
3161            return this._validateJMBG(value, 'ME');
3162        },
3163        _rs: function(value) {
3164            return this._validateJMBG(value, 'RS');
3165        },
3166
3167        /**
3168         * Examples: 0101006500006
3169         */
3170        _si: function(value) {
3171            return this._validateJMBG(value, 'SI');
3172        },
3173
3174        /**
3175         * Validate Bulgarian national identification number (EGN)
3176         * Examples:
3177         * - Valid: 7523169263, 8032056031, 803205 603 1, 8001010008, 7501020018, 7552010005, 7542011030
3178         * - Invalid: 8019010008
3179         *
3180         * @see http://en.wikipedia.org/wiki/Uniform_civil_number
3181         * @param {String} value The ID
3182         * @returns {Boolean}
3183         */
3184        _bg: function(value) {
3185            if (!/^\d{10}$/.test(value) && !/^\d{6}\s\d{3}\s\d{1}$/.test(value)) {
3186                return false;
3187            }
3188            value = value.replace(/\s/g, '');
3189            // Check the birth date
3190            var year  = parseInt(value.substr(0, 2), 10) + 1900,
3191                month = parseInt(value.substr(2, 2), 10),
3192                day   = parseInt(value.substr(4, 2), 10);
3193            if (month > 40) {
3194                year += 100;
3195                month -= 40;
3196            } else if (month > 20) {
3197                year -= 100;
3198                month -= 20;
3199            }
3200
3201            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3202                return false;
3203            }
3204
3205            var sum    = 0,
3206                weight = [2, 4, 8, 5, 10, 9, 7, 3, 6];
3207            for (var i = 0; i < 9; i++) {
3208                sum += parseInt(value.charAt(i), 10) * weight[i];
3209            }
3210            sum = (sum % 11) % 10;
3211            return (sum + '' === value.substr(9, 1));
3212        },
3213
3214        /**
3215         * Validate Brazilian national identification number (CPF)
3216         * Examples:
3217         * - Valid: 39053344705, 390.533.447-05, 111.444.777-35
3218         * - Invalid: 231.002.999-00
3219         *
3220         * @see http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
3221         * @param {String} value The ID
3222         * @returns {Boolean}
3223         */
3224        _br: function(value) {
3225            if (/^1{11}|2{11}|3{11}|4{11}|5{11}|6{11}|7{11}|8{11}|9{11}|0{11}$/.test(value)) {
3226                return false;
3227            }
3228            if (!/^\d{11}$/.test(value) && !/^\d{3}\.\d{3}\.\d{3}-\d{2}$/.test(value)) {
3229                return false;
3230            }
3231            value = value.replace(/\./g, '').replace(/-/g, '');
3232
3233            var d1 = 0;
3234            for (var i = 0; i < 9; i++) {
3235                d1 += (10 - i) * parseInt(value.charAt(i), 10);
3236            }
3237            d1 = 11 - d1 % 11;
3238            if (d1 === 10 || d1 === 11) {
3239                d1 = 0;
3240            }
3241            if (d1 + '' !== value.charAt(9)) {
3242                return false;
3243            }
3244
3245            var d2 = 0;
3246            for (i = 0; i < 10; i++) {
3247                d2 += (11 - i) * parseInt(value.charAt(i), 10);
3248            }
3249            d2 = 11 - d2 % 11;
3250            if (d2 === 10 || d2 === 11) {
3251                d2 = 0;
3252            }
3253
3254            return (d2 + '' === value.charAt(10));
3255        },
3256
3257        /**
3258         * Validate Swiss Social Security Number (AHV-Nr/No AVS)
3259         * Examples:
3260         * - Valid: 756.1234.5678.95, 7561234567895
3261         *
3262         * @see http://en.wikipedia.org/wiki/National_identification_number#Switzerland
3263         * @see http://www.bsv.admin.ch/themen/ahv/00011/02185/index.html?lang=de
3264         * @param {String} value The ID
3265         * @returns {Boolean}
3266         */
3267        _ch: function(value) {
3268            if (!/^756[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{2}$/.test(value)) {
3269                return false;
3270            }
3271            value = value.replace(/\D/g, '').substr(3);
3272            var length = value.length,
3273                sum    = 0,
3274                weight = (length === 8) ? [3, 1] : [1, 3];
3275            for (var i = 0; i < length - 1; i++) {
3276                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
3277            }
3278            sum = 10 - sum % 10;
3279            return (sum + '' === value.charAt(length - 1));
3280        },
3281
3282        /**
3283         * Validate Chilean national identification number (RUN/RUT)
3284         * Examples:
3285         * - Valid: 76086428-5, 22060449-7, 12531909-2
3286         *
3287         * @see http://en.wikipedia.org/wiki/National_identification_number#Chile
3288         * @see https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html for samples
3289         * @param {String} value The ID
3290         * @returns {Boolean}
3291         */
3292        _cl: function(value) {
3293            if (!/^\d{7,8}[-]{0,1}[0-9K]$/i.test(value)) {
3294                return false;
3295            }
3296            value = value.replace(/\-/g, '');
3297            while (value.length < 9) {
3298                value = '0' + value;
3299            }
3300            var sum    = 0,
3301                weight = [3, 2, 7, 6, 5, 4, 3, 2];
3302            for (var i = 0; i < 8; i++) {
3303                sum += parseInt(value.charAt(i), 10) * weight[i];
3304            }
3305            sum = 11 - sum % 11;
3306            if (sum === 11) {
3307                sum = 0;
3308            } else if (sum === 10) {
3309                sum = 'K';
3310            }
3311            return sum + '' === value.charAt(8).toUpperCase();
3312        },
3313
3314        /**
3315         * Validate Czech national identification number (RC)
3316         * Examples:
3317         * - Valid: 7103192745, 991231123
3318         * - Invalid: 1103492745, 590312123
3319         *
3320         * @param {String} value The ID
3321         * @returns {Boolean}
3322         */
3323        _cz: function(value) {
3324            if (!/^\d{9,10}$/.test(value)) {
3325                return false;
3326            }
3327            var year  = 1900 + parseInt(value.substr(0, 2), 10),
3328                month = parseInt(value.substr(2, 2), 10) % 50 % 20,
3329                day   = parseInt(value.substr(4, 2), 10);
3330            if (value.length === 9) {
3331                if (year >= 1980) {
3332                    year -= 100;
3333                }
3334                if (year > 1953) {
3335                    return false;
3336                }
3337            } else if (year < 1954) {
3338                year += 100;
3339            }
3340
3341            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3342                return false;
3343            }
3344
3345            // Check that the birth date is not in the future
3346            if (value.length === 10) {
3347                var check = parseInt(value.substr(0, 9), 10) % 11;
3348                if (year < 1985) {
3349                    check = check % 10;
3350                }
3351                return (check + '' === value.substr(9, 1));
3352            }
3353
3354            return true;
3355        },
3356
3357        /**
3358         * Validate Danish Personal Identification number (CPR)
3359         * Examples:
3360         * - Valid: 2110625629, 211062-5629
3361         * - Invalid: 511062-5629
3362         *
3363         * @see https://en.wikipedia.org/wiki/Personal_identification_number_(Denmark)
3364         * @param {String} value The ID
3365         * @returns {Boolean}
3366         */
3367        _dk: function(value) {
3368            if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) {
3369                return false;
3370            }
3371            value = value.replace(/-/g, '');
3372            var day   = parseInt(value.substr(0, 2), 10),
3373                month = parseInt(value.substr(2, 2), 10),
3374                year  = parseInt(value.substr(4, 2), 10);
3375
3376            switch (true) {
3377                case ('5678'.indexOf(value.charAt(6)) !== -1 && year >= 58):
3378                    year += 1800;
3379                    break;
3380                case ('0123'.indexOf(value.charAt(6)) !== -1):
3381                case ('49'.indexOf(value.charAt(6)) !== -1 && year >= 37):
3382                    year += 1900;
3383                    break;
3384                default:
3385                    year += 2000;
3386                    break;
3387            }
3388
3389            return $.fn.bootstrapValidator.helpers.date(year, month, day);
3390        },
3391
3392        /**
3393         * Validate Estonian Personal Identification Code (isikukood)
3394         * Examples:
3395         * - Valid: 37605030299
3396         *
3397         * @see http://et.wikipedia.org/wiki/Isikukood
3398         * @param {String} value The ID
3399         * @returns {Boolean}
3400         */
3401        _ee: function(value) {
3402            // Use the same format as Lithuanian Personal Code
3403            return this._lt(value);
3404        },
3405
3406        /**
3407         * Validate Spanish personal identity code (DNI)
3408         * Support i) DNI (for Spanish citizens) and ii) NIE (for foreign people)
3409         *
3410         * Examples:
3411         * - Valid: i) 54362315K, 54362315-K; ii) X2482300W, X-2482300W, X-2482300-W
3412         * - Invalid: i) 54362315Z; ii) X-2482300A
3413         *
3414         * @see https://en.wikipedia.org/wiki/National_identification_number#Spain
3415         * @param {String} value The ID
3416         * @returns {Boolean}
3417         */
3418        _es: function(value) {
3419            if (!/^[0-9A-Z]{8}[-]{0,1}[0-9A-Z]$/.test(value)                    // DNI
3420                && !/^[XYZ][-]{0,1}[0-9]{7}[-]{0,1}[0-9A-Z]$/.test(value)) {    // NIE
3421                return false;
3422            }
3423
3424            value = value.replace(/-/g, '');
3425            var index = 'XYZ'.indexOf(value.charAt(0));
3426            if (index !== -1) {
3427                // It is NIE number
3428                value = index + value.substr(1) + '';
3429            }
3430
3431            var check = parseInt(value.substr(0, 8), 10);
3432            check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
3433            return (check === value.substr(8, 1));
3434        },
3435
3436        /**
3437         * Validate Finnish Personal Identity Code (HETU)
3438         * Examples:
3439         * - Valid: 311280-888Y, 131052-308T
3440         * - Invalid: 131052-308U, 310252-308Y
3441         *
3442         * @param {String} value The ID
3443         * @returns {Boolean}
3444         */
3445        _fi: function(value) {
3446            if (!/^[0-9]{6}[-+A][0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/.test(value)) {
3447                return false;
3448            }
3449            var day       = parseInt(value.substr(0, 2), 10),
3450                month     = parseInt(value.substr(2, 2), 10),
3451                year      = parseInt(value.substr(4, 2), 10),
3452                centuries = {
3453                    '+': 1800,
3454                    '-': 1900,
3455                    'A': 2000
3456                };
3457            year = centuries[value.charAt(6)] + year;
3458
3459            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3460                return false;
3461            }
3462
3463            var individual = parseInt(value.substr(7, 3), 10);
3464            if (individual < 2) {
3465                return false;
3466            }
3467            var n = value.substr(0, 6) + value.substr(7, 3) + '';
3468            n = parseInt(n, 10);
3469            return '0123456789ABCDEFHJKLMNPRSTUVWXY'.charAt(n % 31) === value.charAt(10);
3470        },
3471
3472        /**
3473         * Validate Croatian personal identification number (OIB)
3474         * Examples:
3475         * - Valid: 33392005961
3476         * - Invalid: 33392005962
3477         *
3478         * @param {String} value The ID
3479         * @returns {Boolean}
3480         */
3481        _hr: function(value) {
3482            if (!/^[0-9]{11}$/.test(value)) {
3483                return false;
3484            }
3485            return $.fn.bootstrapValidator.helpers.mod11And10(value);
3486        },
3487
3488        /**
3489         * Validate Irish Personal Public Service Number (PPS)
3490         * Examples:
3491         * - Valid: 6433435F, 6433435FT, 6433435FW, 6433435OA, 6433435IH, 1234567TW, 1234567FA
3492         * - Invalid: 6433435E, 6433435VH
3493         *
3494         * @see https://en.wikipedia.org/wiki/Personal_Public_Service_Number
3495         * @param {String} value The ID
3496         * @returns {Boolean}
3497         */
3498        _ie: function(value) {
3499            if (!/^\d{7}[A-W][AHWTX]?$/.test(value)) {
3500                return false;
3501            }
3502
3503            var getCheckDigit = function(value) {
3504                while (value.length < 7) {
3505                    value = '0' + value;
3506                }
3507                var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV',
3508                    sum      = 0;
3509                for (var i = 0; i < 7; i++) {
3510                    sum += parseInt(value.charAt(i), 10) * (8 - i);
3511                }
3512                sum += 9 * alphabet.indexOf(value.substr(7));
3513                return alphabet[sum % 23];
3514            };
3515
3516            // 2013 format
3517            if (value.length === 9 && ('A' === value.charAt(8) || 'H' === value.charAt(8))) {
3518                return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + '');
3519            }
3520            // The old format
3521            else {
3522                return value.charAt(7) === getCheckDigit(value.substr(0, 7));
3523            }
3524        },
3525
3526        /**
3527         * Validate Iceland national identification number (Kennitala)
3528         * Examples:
3529         * - Valid: 120174-3399, 1201743399, 0902862349
3530         *
3531         * @see http://en.wikipedia.org/wiki/Kennitala
3532         * @param {String} value The ID
3533         * @returns {Boolean}
3534         */
3535        _is: function(value) {
3536            if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) {
3537                return false;
3538            }
3539            value = value.replace(/-/g, '');
3540            var day     = parseInt(value.substr(0, 2), 10),
3541                month   = parseInt(value.substr(2, 2), 10),
3542                year    = parseInt(value.substr(4, 2), 10),
3543                century = parseInt(value.charAt(9), 10);
3544
3545            year = (century === 9) ? (1900 + year) : ((20 + century) * 100 + year);
3546            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
3547                return false;
3548            }
3549            // Validate the check digit
3550            var sum    = 0,
3551                weight = [3, 2, 7, 6, 5, 4, 3, 2];
3552            for (var i = 0; i < 8; i++) {
3553                sum += parseInt(value.charAt(i), 10) * weight[i];
3554            }
3555            sum = 11 - sum % 11;
3556            return (sum + '' === value.charAt(8));
3557        },
3558
3559        /**
3560         * Validate Lithuanian Personal Code (Asmens kodas)
3561         * Examples:
3562         * - Valid: 38703181745
3563         * - Invalid: 38703181746, 78703181745, 38703421745
3564         *
3565         * @see http://en.wikipedia.org/wiki/National_identification_number#Lithuania
3566         * @see http://www.adomas.org/midi2007/pcode.html
3567         * @param {String} value The ID
3568         * @returns {Boolean}
3569         */
3570        _lt: function(value) {
3571            if (!/^[0-9]{11}$/.test(value)) {
3572                return false;
3573            }
3574            var gender  = parseInt(value.charAt(0), 10),
3575                year    = parseInt(value.substr(1, 2), 10),
3576                month   = parseInt(value.substr(3, 2), 10),
3577                day     = parseInt(value.substr(5, 2), 10),
3578                century = (gender % 2 === 0) ? (17 + gender / 2) : (17 + (gender + 1) / 2);
3579            year = century * 100 + year;
3580            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
3581                return false;
3582            }
3583
3584            // Validate the check digit
3585            var sum    = 0,
3586                weight = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1];
3587            for (var i = 0; i < 10; i++) {
3588                sum += parseInt(value.charAt(i), 10) * weight[i];
3589            }
3590            sum = sum % 11;
3591            if (sum !== 10) {
3592                return sum + '' === value.charAt(10);
3593            }
3594
3595            // Re-calculate the check digit
3596            sum    = 0;
3597            weight = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3];
3598            for (i = 0; i < 10; i++) {
3599                sum += parseInt(value.charAt(i), 10) * weight[i];
3600            }
3601            sum = sum % 11;
3602            if (sum === 10) {
3603                sum = 0;
3604            }
3605            return (sum + '' === value.charAt(10));
3606        },
3607
3608        /**
3609         * Validate Latvian Personal Code (Personas kods)
3610         * Examples:
3611         * - Valid: 161175-19997, 16117519997
3612         * - Invalid: 161375-19997
3613         *
3614         * @see http://laacz.lv/2006/11/25/pk-parbaudes-algoritms/
3615         * @param {String} value The ID
3616         * @returns {Boolean}
3617         */
3618        _lv: function(value) {
3619            if (!/^[0-9]{6}[-]{0,1}[0-9]{5}$/.test(value)) {
3620                return false;
3621            }
3622            value = value.replace(/\D/g, '');
3623            // Check birth date
3624            var day   = parseInt(value.substr(0, 2), 10),
3625                month = parseInt(value.substr(2, 2), 10),
3626                year  = parseInt(value.substr(4, 2), 10);
3627            year = year + 1800 + parseInt(value.charAt(6), 10) * 100;
3628
3629            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
3630                return false;
3631            }
3632
3633            // Check personal code
3634            var sum    = 0,
3635                weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9];
3636            for (var i = 0; i < 10; i++) {
3637                sum += parseInt(value.charAt(i), 10) * weight[i];
3638            }
3639            sum = (sum + 1) % 11 % 10;
3640            return (sum + '' === value.charAt(10));
3641        },
3642
3643        /**
3644         * Validate Dutch national identification number (BSN)
3645         * Examples:
3646         * - Valid: 111222333, 941331490, 9413.31.490
3647         * - Invalid: 111252333
3648         *
3649         * @see https://nl.wikipedia.org/wiki/Burgerservicenummer
3650         * @param {String} value The ID
3651         * @returns {Boolean}
3652         */
3653        _nl: function(value) {
3654            while (value.length < 9) {
3655                value = '0' + value;
3656            }
3657            if (!/^[0-9]{4}[.]{0,1}[0-9]{2}[.]{0,1}[0-9]{3}$/.test(value)) {
3658                return false;
3659            }
3660            value = value.replace(/\./g, '');
3661            if (parseInt(value, 10) === 0) {
3662                return false;
3663            }
3664            var sum    = 0,
3665                length = value.length;
3666            for (var i = 0; i < length - 1; i++) {
3667                sum += (9 - i) * parseInt(value.charAt(i), 10);
3668            }
3669            sum = sum % 11;
3670            if (sum === 10) {
3671                sum = 0;
3672            }
3673            return (sum + '' === value.charAt(length - 1));
3674        },
3675
3676        /**
3677         * Validate Romanian numerical personal code (CNP)
3678         * Examples:
3679         * - Valid: 1630615123457, 1800101221144
3680         * - Invalid: 8800101221144, 1632215123457, 1630615123458
3681         *
3682         * @see http://en.wikipedia.org/wiki/National_identification_number#Romania
3683         * @param {String} value The ID
3684         * @returns {Boolean}
3685         */
3686        _ro: function(value) {
3687            if (!/^[0-9]{13}$/.test(value)) {
3688                return false;
3689            }
3690            var gender = parseInt(value.charAt(0), 10);
3691            if (gender === 0 || gender === 7 || gender === 8) {
3692                return false;
3693            }
3694
3695            // Determine the date of birth
3696            var year      = parseInt(value.substr(1, 2), 10),
3697                month     = parseInt(value.substr(3, 2), 10),
3698                day       = parseInt(value.substr(5, 2), 10),
3699                // The year of date is determined base on the gender
3700                centuries = {
3701                    '1': 1900,  // Male born between 1900 and 1999
3702                    '2': 1900,  // Female born between 1900 and 1999
3703                    '3': 1800,  // Male born between 1800 and 1899
3704                    '4': 1800,  // Female born between 1800 and 1899
3705                    '5': 2000,  // Male born after 2000
3706                    '6': 2000   // Female born after 2000
3707                };
3708            if (day > 31 && month > 12) {
3709                return false;
3710            }
3711            if (gender !== 9) {
3712                year = centuries[gender + ''] + year;
3713                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3714                    return false;
3715                }
3716            }
3717
3718            // Validate the check digit
3719            var sum    = 0,
3720                weight = [2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9],
3721                length = value.length;
3722            for (var i = 0; i < length - 1; i++) {
3723                sum += parseInt(value.charAt(i), 10) * weight[i];
3724            }
3725            sum = sum % 11;
3726            if (sum === 10) {
3727                sum = 1;
3728            }
3729            return (sum + '' === value.charAt(length - 1));
3730        },
3731
3732        /**
3733         * Validate Swedish personal identity number (personnummer)
3734         * Examples:
3735         * - Valid: 8112289874, 811228-9874, 811228+9874
3736         * - Invalid: 811228-9873
3737         *
3738         * @see http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)
3739         * @param {String} value The ID
3740         * @returns {Boolean}
3741         */
3742        _se: function(value) {
3743            if (!/^[0-9]{10}$/.test(value) && !/^[0-9]{6}[-|+][0-9]{4}$/.test(value)) {
3744                return false;
3745            }
3746            value = value.replace(/[^0-9]/g, '');
3747
3748            var year  = parseInt(value.substr(0, 2), 10) + 1900,
3749                month = parseInt(value.substr(2, 2), 10),
3750                day   = parseInt(value.substr(4, 2), 10);
3751            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3752                return false;
3753            }
3754
3755            // Validate the last check digit
3756            return $.fn.bootstrapValidator.helpers.luhn(value);
3757        },
3758
3759        /**
3760         * Validate Slovak national identifier number (RC)
3761         * Examples:
3762         * - Valid: 7103192745, 991231123
3763         * - Invalid: 7103192746, 1103492745
3764         *
3765         * @param {String} value The ID
3766         * @returns {Boolean}
3767         */
3768        _sk: function(value) {
3769            // Slovakia uses the same format as Czech Republic
3770            return this._cz(value);
3771        },
3772
3773        /**
3774         * Validate San Marino citizen number
3775         *
3776         * @see http://en.wikipedia.org/wiki/National_identification_number#San_Marino
3777         * @param {String} value The ID
3778         * @returns {Boolean}
3779         */
3780        _sm: function(value) {
3781            return /^\d{5}$/.test(value);
3782        },
3783
3784        /**
3785         * Validate South African ID
3786         * Example:
3787         * - Valid: 8001015009087
3788         * - Invalid: 8001015009287, 8001015009086
3789         *
3790         * @see http://en.wikipedia.org/wiki/National_identification_number#South_Africa
3791         * @param {String} value The ID
3792         * @returns {Boolean}
3793         */
3794        _za: function(value) {
3795            if (!/^[0-9]{10}[0|1][8|9][0-9]$/.test(value)) {
3796                return false;
3797            }
3798            var year        = parseInt(value.substr(0, 2), 10),
3799                currentYear = new Date().getFullYear() % 100,
3800                month       = parseInt(value.substr(2, 2), 10),
3801                day         = parseInt(value.substr(4, 2), 10);
3802            year = (year >= currentYear) ? (year + 1900) : (year + 2000);
3803
3804            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3805                return false;
3806            }
3807
3808            // Validate the last check digit
3809            return $.fn.bootstrapValidator.helpers.luhn(value);
3810        }
3811    };
3812}(window.jQuery));
3813;(function($) {
3814    $.fn.bootstrapValidator.i18n.identical = $.extend($.fn.bootstrapValidator.i18n.identical || {}, {
3815        'default': 'Please enter the same value'
3816    });
3817
3818    $.fn.bootstrapValidator.validators.identical = {
3819        html5Attributes: {
3820            message: 'message',
3821            field: 'field'
3822        },
3823
3824        /**
3825         * Check if input value equals to value of particular one
3826         *
3827         * @param {BootstrapValidator} validator The validator plugin instance
3828         * @param {jQuery} $field Field element
3829         * @param {Object} options Consists of the following key:
3830         * - field: The name of field that will be used to compare with current one
3831         * @returns {Boolean}
3832         */
3833        validate: function(validator, $field, options) {
3834            var value = $field.val();
3835            if (value === '') {
3836                return true;
3837            }
3838
3839            var compareWith = validator.getFieldElements(options.field);
3840            if (compareWith === null) {
3841                return true;
3842            }
3843
3844            if (value === compareWith.val()) {
3845                validator.updateStatus(options.field, validator.STATUS_VALID, 'identical');
3846                return true;
3847            } else {
3848                return false;
3849            }
3850        }
3851    };
3852}(window.jQuery));
3853;(function($) {
3854    $.fn.bootstrapValidator.i18n.imei = $.extend($.fn.bootstrapValidator.i18n.imei || {}, {
3855        'default': 'Please enter a valid IMEI number'
3856    });
3857
3858    $.fn.bootstrapValidator.validators.imei = {
3859        /**
3860         * Validate IMEI (International Mobile Station Equipment Identity)
3861         * Examples:
3862         * - Valid: 35-209900-176148-1, 35-209900-176148-23, 3568680000414120, 490154203237518
3863         * - Invalid: 490154203237517
3864         *
3865         * @see http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity
3866         * @param {BootstrapValidator} validator The validator plugin instance
3867         * @param {jQuery} $field Field element
3868         * @param {Object} options Can consist of the following keys:
3869         * - message: The invalid message
3870         * @returns {Boolean}
3871         */
3872        validate: function(validator, $field, options) {
3873            var value = $field.val();
3874            if (value === '') {
3875                return true;
3876            }
3877
3878            switch (true) {
3879                case /^\d{15}$/.test(value):
3880                case /^\d{2}-\d{6}-\d{6}-\d{1}$/.test(value):
3881                case /^\d{2}\s\d{6}\s\d{6}\s\d{1}$/.test(value):
3882                    value = value.replace(/[^0-9]/g, '');
3883                    return $.fn.bootstrapValidator.helpers.luhn(value);
3884
3885                case /^\d{14}$/.test(value):
3886                case /^\d{16}$/.test(value):
3887                case /^\d{2}-\d{6}-\d{6}(|-\d{2})$/.test(value):
3888                case /^\d{2}\s\d{6}\s\d{6}(|\s\d{2})$/.test(value):
3889                    return true;
3890
3891                default:
3892                    return false;
3893            }
3894        }
3895    };
3896}(window.jQuery));
3897;(function($) {
3898    $.fn.bootstrapValidator.i18n.integer = $.extend($.fn.bootstrapValidator.i18n.integer || {}, {
3899        'default': 'Please enter a valid number'
3900    });
3901
3902    $.fn.bootstrapValidator.validators.integer = {
3903        enableByHtml5: function($field) {
3904            return ('number' === $field.attr('type')) && ($field.attr('step') === undefined || $field.attr('step') % 1 === 0);
3905        },
3906
3907        /**
3908         * Return true if the input value is an integer
3909         *
3910         * @param {BootstrapValidator} validator The validator plugin instance
3911         * @param {jQuery} $field Field element
3912         * @param {Object} options Can consist of the following key:
3913         * - message: The invalid message
3914         * @returns {Boolean}
3915         */
3916        validate: function(validator, $field, options) {
3917            var value = $field.val();
3918            if (value === '') {
3919                return true;
3920            }
3921            return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value);
3922        }
3923    };
3924}(window.jQuery));
3925;(function($) {
3926    $.fn.bootstrapValidator.i18n.ip = $.extend($.fn.bootstrapValidator.i18n.ip || {}, {
3927        'default': 'Please enter a valid IP address',
3928        ipv4: 'Please enter a valid IPv4 address',
3929        ipv6: 'Please enter a valid IPv6 address'
3930    });
3931
3932    $.fn.bootstrapValidator.validators.ip = {
3933        html5Attributes: {
3934            message: 'message',
3935            ipv4: 'ipv4',
3936            ipv6: 'ipv6'
3937        },
3938
3939        /**
3940         * Return true if the input value is a IP address.
3941         *
3942         * @param {BootstrapValidator} validator The validator plugin instance
3943         * @param {jQuery} $field Field element
3944         * @param {Object} options Can consist of the following keys:
3945         * - ipv4: Enable IPv4 validator, default to true
3946         * - ipv6: Enable IPv6 validator, default to true
3947         * - message: The invalid message
3948         * @returns {Boolean|Object}
3949         */
3950        validate: function(validator, $field, options) {
3951            var value = $field.val();
3952            if (value === '') {
3953                return true;
3954            }
3955            options = $.extend({}, { ipv4: true, ipv6: true }, options);
3956
3957            if (options.ipv4) {
3958                return {
3959                    valid: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value),
3960                    message: options.message || $.fn.bootstrapValidator.i18n.ip.ipv4
3961                };
3962            } else if (options.ipv6) {
3963                return {
3964                    valid: /^\s*((([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}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(value),
3965                    message: options.message || $.fn.bootstrapValidator.i18n.ip.ipv6
3966                };
3967            }
3968
3969            return false;
3970        }
3971    };
3972}(window.jQuery));
3973;(function($) {
3974    $.fn.bootstrapValidator.i18n.isbn = $.extend($.fn.bootstrapValidator.i18n.isbn || {}, {
3975        'default': 'Please enter a valid ISBN number'
3976    });
3977
3978    $.fn.bootstrapValidator.validators.isbn = {
3979        /**
3980         * Return true if the input value is a valid ISBN 10 or ISBN 13 number
3981         * Examples:
3982         * - Valid:
3983         * ISBN 10: 99921-58-10-7, 9971-5-0210-0, 960-425-059-0, 80-902734-1-6, 85-359-0277-5, 1-84356-028-3, 0-684-84328-5, 0-8044-2957-X, 0-85131-041-9, 0-943396-04-2, 0-9752298-0-X
3984         * ISBN 13: 978-0-306-40615-7
3985         * - Invalid:
3986         * ISBN 10: 99921-58-10-6
3987         * ISBN 13: 978-0-306-40615-6
3988         *
3989         * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
3990         * @param {BootstrapValidator} validator The validator plugin instance
3991         * @param {jQuery} $field Field element
3992         * @param {Object} [options] Can consist of the following keys:
3993         * - message: The invalid message
3994         * @returns {Boolean}
3995         */
3996        validate: function(validator, $field, options) {
3997            var value = $field.val();
3998            if (value === '') {
3999                return true;
4000            }
4001
4002            // http://en.wikipedia.org/wiki/International_Standard_Book_Number#Overview
4003            // Groups are separated by a hyphen or a space
4004            var type;
4005            switch (true) {
4006                case /^\d{9}[\dX]$/.test(value):
4007                case (value.length === 13 && /^(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)):
4008                case (value.length === 13 && /^(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)):
4009                    type = 'ISBN10';
4010                    break;
4011                case /^(978|979)\d{9}[\dX]$/.test(value):
4012                case (value.length === 17 && /^(978|979)-(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)):
4013                case (value.length === 17 && /^(978|979)\s(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)):
4014                    type = 'ISBN13';
4015                    break;
4016                default:
4017                    return false;
4018            }
4019
4020            // Replace all special characters except digits and X
4021            value = value.replace(/[^0-9X]/gi, '');
4022            var chars  = value.split(''),
4023                length = chars.length,
4024                sum    = 0,
4025                i,
4026                checksum;
4027
4028            switch (type) {
4029                case 'ISBN10':
4030                    sum = 0;
4031                    for (i = 0; i < length - 1; i++) {
4032                        sum += parseInt(chars[i], 10) * (10 - i);
4033                    }
4034                    checksum = 11 - (sum % 11);
4035                    if (checksum === 11) {
4036                        checksum = 0;
4037                    } else if (checksum === 10) {
4038                        checksum = 'X';
4039                    }
4040                    return (checksum + '' === chars[length - 1]);
4041
4042                case 'ISBN13':
4043                    sum = 0;
4044                    for (i = 0; i < length - 1; i++) {
4045                        sum += ((i % 2 === 0) ? parseInt(chars[i], 10) : (parseInt(chars[i], 10) * 3));
4046                    }
4047                    checksum = 10 - (sum % 10);
4048                    if (checksum === 10) {
4049                        checksum = '0';
4050                    }
4051                    return (checksum + '' === chars[length - 1]);
4052
4053                default:
4054                    return false;
4055            }
4056        }
4057    };
4058}(window.jQuery));
4059;(function($) {
4060    $.fn.bootstrapValidator.i18n.isin = $.extend($.fn.bootstrapValidator.i18n.isin || {}, {
4061        'default': 'Please enter a valid ISIN number'
4062    });
4063
4064    $.fn.bootstrapValidator.validators.isin = {
4065        // Available country codes
4066        // See http://isin.net/country-codes/
4067        COUNTRY_CODES: 'AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW',
4068
4069        /**
4070         * Validate an ISIN (International Securities Identification Number)
4071         * Examples:
4072         * - Valid: US0378331005, AU0000XVGZA3, GB0002634946
4073         * - Invalid: US0378331004, AA0000XVGZA3
4074         *
4075         * @see http://en.wikipedia.org/wiki/International_Securities_Identifying_Number
4076         * @param {BootstrapValidator} validator The validator plugin instance
4077         * @param {jQuery} $field Field element
4078         * @param {Object} options Can consist of the following keys:
4079         * - message: The invalid message
4080         * @returns {Boolean}
4081         */
4082        validate: function(validator, $field, options) {
4083            var value = $field.val();
4084            if (value === '') {
4085                return true;
4086            }
4087
4088            value = value.toUpperCase();
4089            var regex = new RegExp('^(' + this.COUNTRY_CODES + ')[0-9A-Z]{10}$');
4090            if (!regex.test(value)) {
4091                return false;
4092            }
4093
4094            var converted = '',
4095                length    = value.length;
4096            // Convert letters to number
4097            for (var i = 0; i < length - 1; i++) {
4098                var c = value.charCodeAt(i);
4099                converted += ((c > 57) ? (c - 55).toString() : value.charAt(i));
4100            }
4101
4102            var digits = '',
4103                n      = converted.length,
4104                group  = (n % 2 !== 0) ? 0 : 1;
4105            for (i = 0; i < n; i++) {
4106                digits += (parseInt(converted[i], 10) * ((i % 2) === group ? 2 : 1) + '');
4107            }
4108
4109            var sum = 0;
4110            for (i = 0; i < digits.length; i++) {
4111                sum += parseInt(digits.charAt(i), 10);
4112            }
4113            sum = (10 - (sum % 10)) % 10;
4114            return sum + '' === value.charAt(length - 1);
4115        }
4116    };
4117}(window.jQuery));
4118;(function($) {
4119    $.fn.bootstrapValidator.i18n.ismn = $.extend($.fn.bootstrapValidator.i18n.ismn || {}, {
4120        'default': 'Please enter a valid ISMN number'
4121    });
4122
4123    $.fn.bootstrapValidator.validators.ismn = {
4124        /**
4125         * Validate ISMN (International Standard Music Number)
4126         * Examples:
4127         * - Valid: M230671187, 979-0-0601-1561-5, 979 0 3452 4680 5, 9790060115615
4128         * - Invalid: 9790060115614
4129         *
4130         * @see http://en.wikipedia.org/wiki/International_Standard_Music_Number
4131         * @param {BootstrapValidator} validator The validator plugin instance
4132         * @param {jQuery} $field Field element
4133         * @param {Object} options Can consist of the following keys:
4134         * - message: The invalid message
4135         * @returns {Boolean}
4136         */
4137        validate: function(validator, $field, options) {
4138            var value = $field.val();
4139            if (value === '') {
4140                return true;
4141            }
4142
4143            // Groups are separated by a hyphen or a space
4144            var type;
4145            switch (true) {
4146                case /^M\d{9}$/.test(value):
4147                case /^M-\d{4}-\d{4}-\d{1}$/.test(value):
4148                case /^M\s\d{4}\s\d{4}\s\d{1}$/.test(value):
4149                    type = 'ISMN10';
4150                    break;
4151                case /^9790\d{9}$/.test(value):
4152                case /^979-0-\d{4}-\d{4}-\d{1}$/.test(value):
4153                case /^979\s0\s\d{4}\s\d{4}\s\d{1}$/.test(value):
4154                    type = 'ISMN13';
4155                    break;
4156                default:
4157                    return false;
4158            }
4159
4160            if ('ISMN10' === type) {
4161                value = '9790' + value.substr(1);
4162            }
4163
4164            // Replace all special characters except digits
4165            value = value.replace(/[^0-9]/gi, '');
4166            var length = value.length,
4167                sum    = 0,
4168                weight = [1, 3];
4169            for (var i = 0; i < length - 1; i++) {
4170                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
4171            }
4172            sum = 10 - sum % 10;
4173            return (sum + '' === value.charAt(length - 1));
4174        }
4175    };
4176}(window.jQuery));
4177;(function($) {
4178    $.fn.bootstrapValidator.i18n.issn = $.extend($.fn.bootstrapValidator.i18n.issn || {}, {
4179        'default': 'Please enter a valid ISSN number'
4180    });
4181
4182    $.fn.bootstrapValidator.validators.issn = {
4183        /**
4184         * Validate ISSN (International Standard Serial Number)
4185         * Examples:
4186         * - Valid: 0378-5955, 0024-9319, 0032-1478
4187         * - Invalid: 0032-147X
4188         *
4189         * @see http://en.wikipedia.org/wiki/International_Standard_Serial_Number
4190         * @param {BootstrapValidator} validator The validator plugin instance
4191         * @param {jQuery} $field Field element
4192         * @param {Object} options Can consist of the following keys:
4193         * - message: The invalid message
4194         * @returns {Boolean}
4195         */
4196        validate: function(validator, $field, options) {
4197            var value = $field.val();
4198            if (value === '') {
4199                return true;
4200            }
4201
4202            // Groups are separated by a hyphen or a space
4203            if (!/^\d{4}\-\d{3}[\dX]$/.test(value)) {
4204                return false;
4205            }
4206
4207            // Replace all special characters except digits and X
4208            value = value.replace(/[^0-9X]/gi, '');
4209            var chars  = value.split(''),
4210                length = chars.length,
4211                sum    = 0;
4212
4213            if (chars[7] === 'X') {
4214                chars[7] = 10;
4215            }
4216            for (var i = 0; i < length; i++) {
4217                sum += parseInt(chars[i], 10) * (8 - i);
4218            }
4219            return (sum % 11 === 0);
4220        }
4221    };
4222}(window.jQuery));
4223;(function($) {
4224    $.fn.bootstrapValidator.i18n.lessThan = $.extend($.fn.bootstrapValidator.i18n.lessThan || {}, {
4225        'default': 'Please enter a value less than or equal to %s',
4226        notInclusive: 'Please enter a value less than %s'
4227    });
4228
4229    $.fn.bootstrapValidator.validators.lessThan = {
4230        html5Attributes: {
4231            message: 'message',
4232            value: 'value',
4233            inclusive: 'inclusive'
4234        },
4235
4236        enableByHtml5: function($field) {
4237            var max = $field.attr('max');
4238            if (max) {
4239                return {
4240                    value: max
4241                };
4242            }
4243
4244            return false;
4245        },
4246
4247        /**
4248         * Return true if the input value is less than or equal to given number
4249         *
4250         * @param {BootstrapValidator} validator The validator plugin instance
4251         * @param {jQuery} $field Field element
4252         * @param {Object} options Can consist of the following keys:
4253         * - value: The number used to compare to. It can be
4254         *      - A number
4255         *      - Name of field which its value defines the number
4256         *      - Name of callback function that returns the number
4257         *      - A callback function that returns the number
4258         *
4259         * - inclusive [optional]: Can be true or false. Default is true
4260         * - message: The invalid message
4261         * @returns {Boolean|Object}
4262         */
4263        validate: function(validator, $field, options) {
4264            var value = $field.val();
4265            if (value === '') {
4266                return true;
4267            }
4268
4269            var compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value);
4270
4271            value = parseFloat(value);
4272            return (options.inclusive === true || options.inclusive === undefined)
4273                    ? {
4274                        valid: value <= compareTo,
4275                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan['default'], compareTo)
4276                    }
4277                    : {
4278                        valid: value < compareTo,
4279                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan.notInclusive, compareTo)
4280                    };
4281        }
4282    };
4283}(window.jQuery));
4284;(function($) {
4285    $.fn.bootstrapValidator.i18n.mac = $.extend($.fn.bootstrapValidator.i18n.mac || {}, {
4286        'default': 'Please enter a valid MAC address'
4287    });
4288
4289    $.fn.bootstrapValidator.validators.mac = {
4290        /**
4291         * Return true if the input value is a MAC address.
4292         *
4293         * @param {BootstrapValidator} validator The validator plugin instance
4294         * @param {jQuery} $field Field element
4295         * @param {Object} options Can consist of the following keys:
4296         * - message: The invalid message
4297         * @returns {Boolean}
4298         */
4299        validate: function(validator, $field, options) {
4300            var value = $field.val();
4301            if (value === '') {
4302                return true;
4303            }
4304
4305            return /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value);
4306        }
4307    };
4308}(window.jQuery));
4309;(function($) {
4310    $.fn.bootstrapValidator.i18n.notEmpty = $.extend($.fn.bootstrapValidator.i18n.notEmpty || {}, {
4311        'default': 'Please enter a value'
4312    });
4313
4314    $.fn.bootstrapValidator.validators.notEmpty = {
4315        enableByHtml5: function($field) {
4316            var required = $field.attr('required') + '';
4317            return ('required' === required || 'true' === required);
4318        },
4319
4320        /**
4321         * Check if input value is empty or not
4322         *
4323         * @param {BootstrapValidator} validator The validator plugin instance
4324         * @param {jQuery} $field Field element
4325         * @param {Object} options
4326         * @returns {Boolean}
4327         */
4328        validate: function(validator, $field, options) {
4329            var type = $field.attr('type');
4330            if ('radio' === type || 'checkbox' === type) {
4331                return validator
4332                            .getFieldElements($field.attr('data-bv-field'))
4333                            .filter(':checked')
4334                            .length > 0;
4335            }
4336
4337            return $.trim($field.val()) !== '';
4338        }
4339    };
4340}(window.jQuery));
4341;(function($) {
4342    $.fn.bootstrapValidator.i18n.numeric = $.extend($.fn.bootstrapValidator.i18n.numeric || {}, {
4343        'default': 'Please enter a valid float number'
4344    });
4345
4346    $.fn.bootstrapValidator.validators.numeric = {
4347        html5Attributes: {
4348            message: 'message',
4349            separator: 'separator'
4350        },
4351
4352        enableByHtml5: function($field) {
4353            return ('number' === $field.attr('type')) && ($field.attr('step') !== undefined) && ($field.attr('step') % 1 !== 0);
4354        },
4355
4356        /**
4357         * Validate decimal number
4358         *
4359         * @param {BootstrapValidator} validator The validator plugin instance
4360         * @param {jQuery} $field Field element
4361         * @param {Object} options Consist of key:
4362         * - message: The invalid message
4363         * - separator: The decimal separator. Can be "." (default), ","
4364         * @returns {Boolean}
4365         */
4366        validate: function(validator, $field, options) {
4367            var value = $field.val();
4368            if (value === '') {
4369                return true;
4370            }
4371            var separator = options.separator || '.';
4372            if (separator !== '.') {
4373                value = value.replace(separator, '.');
4374            }
4375
4376            return !isNaN(parseFloat(value)) && isFinite(value);
4377        }
4378    };
4379}(window.jQuery));
4380;(function($) {
4381    $.fn.bootstrapValidator.i18n.phone = $.extend($.fn.bootstrapValidator.i18n.phone || {}, {
4382        'default': 'Please enter a valid phone number',
4383        countryNotSupported: 'The country code %s is not supported',
4384        country: 'Please enter a valid phone number in %s',
4385        countries: {
4386            GB: 'United Kingdom',
4387            US: 'USA'
4388        }
4389    });
4390
4391    $.fn.bootstrapValidator.validators.phone = {
4392        html5Attributes: {
4393            message: 'message',
4394            country: 'country'
4395        },
4396
4397        // The supported countries
4398        COUNTRY_CODES: ['GB', 'US'],
4399
4400        /**
4401         * Return true if the input value contains a valid phone number for the country
4402         * selected in the options
4403         *
4404         * @param {BootstrapValidator} validator Validate plugin instance
4405         * @param {jQuery} $field Field element
4406         * @param {Object} options Consist of key:
4407         * - message: The invalid message
4408         * - country: The ISO-3166 country code. It can be
4409         *      - A country code
4410         *      - Name of field which its value defines the country code
4411         *      - Name of callback function that returns the country code
4412         *      - A callback function that returns the country code
4413         *
4414         * Currently it only supports United State (US) or United Kingdom (GB) countries
4415         * @returns {Boolean|Object}
4416         */
4417        validate: function(validator, $field, options) {
4418            var value = $field.val();
4419            if (value === '') {
4420                return true;
4421            }
4422
4423            var country = options.country;
4424            if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) {
4425                // Try to determine the country
4426                country = validator.getDynamicOption($field, country);
4427            }
4428
4429            if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
4430                return {
4431                    valid: false,
4432                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.phone.countryNotSupported, country)
4433                };
4434            }
4435
4436            var isValid = true;
4437            switch (country.toUpperCase()) {
4438            	case 'GB':
4439            		// http://aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers#Match_GB_telephone_number_in_any_format
4440            		// Test: http://regexr.com/38uhv
4441            		value   = $.trim(value);
4442            		isValid = (/^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\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}|8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d))(?:(?:[\s-]?(?:x|ext\.?\s?|\#)\d+)?)$/).test(value);
4443                    break;
4444
4445                case 'US':
4446                /* falls through */
4447                default:
4448                    // Make sure US phone numbers have 10 digits
4449                    // May start with 1, +1, or 1-; should discard
4450                    // Area code may be delimited with (), & sections may be delimited with . or -
4451                    // Test: http://regexr.com/38mqi
4452                    value   = value.replace(/\D/g, '');
4453                    isValid = (/^(?:(1\-?)|(\+1 ?))?\(?(\d{3})[\)\-\.]?(\d{3})[\-\.]?(\d{4})$/).test(value) && (value.length === 10);
4454                    break;
4455            }
4456
4457            return {
4458                valid: isValid,
4459                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.phone.country, $.fn.bootstrapValidator.i18n.phone.countries[country])
4460            };
4461        }
4462    };
4463}(window.jQuery));
4464;(function($) {
4465    $.fn.bootstrapValidator.i18n.regexp = $.extend($.fn.bootstrapValidator.i18n.regexp || {}, {
4466        'default': 'Please enter a value matching the pattern'
4467    });
4468
4469    $.fn.bootstrapValidator.validators.regexp = {
4470        html5Attributes: {
4471            message: 'message',
4472            regexp: 'regexp'
4473        },
4474
4475        enableByHtml5: function($field) {
4476            var pattern = $field.attr('pattern');
4477            if (pattern) {
4478                return {
4479                    regexp: pattern
4480                };
4481            }
4482
4483            return false;
4484        },
4485
4486        /**
4487         * Check if the element value matches given regular expression
4488         *
4489         * @param {BootstrapValidator} validator The validator plugin instance
4490         * @param {jQuery} $field Field element
4491         * @param {Object} options Consists of the following key:
4492         * - regexp: The regular expression you need to check
4493         * @returns {Boolean}
4494         */
4495        validate: function(validator, $field, options) {
4496            var value = $field.val();
4497            if (value === '') {
4498                return true;
4499            }
4500
4501            var regexp = ('string' === typeof options.regexp) ? new RegExp(options.regexp) : options.regexp;
4502            return regexp.test(value);
4503        }
4504    };
4505}(window.jQuery));
4506;(function($) {
4507    $.fn.bootstrapValidator.i18n.remote = $.extend($.fn.bootstrapValidator.i18n.remote || {}, {
4508        'default': 'Please enter a valid value'
4509    });
4510
4511    $.fn.bootstrapValidator.validators.remote = {
4512        html5Attributes: {
4513            message: 'message',
4514            url: 'url',
4515            name: 'name'
4516        },
4517
4518        /**
4519         * Request a remote server to check the input value
4520         *
4521         * @param {BootstrapValidator} validator Plugin instance
4522         * @param {jQuery} $field Field element
4523         * @param {Object} options Can consist of the following keys:
4524         * - url {String|Function}
4525         * - type {String} [optional] Can be GET or POST (default)
4526         * - data {Object|Function} [optional]: By default, it will take the value
4527         *  {
4528         *      <fieldName>: <fieldValue>
4529         *  }
4530         * - name {String} [optional]: Override the field name for the request.
4531         * - message: The invalid message
4532         * @returns {Boolean|Deferred}
4533         */
4534        validate: function(validator, $field, options) {
4535            var value = $field.val();
4536            if (value === '') {
4537                return true;
4538            }
4539
4540            var name = $field.attr('data-bv-field'),
4541                data = options.data || {},
4542                url  = options.url,
4543                type = options.type || 'POST';
4544
4545            // Support dynamic data
4546            if ('function' === typeof data) {
4547                data = data.call(this, validator);
4548            }
4549
4550            // Support dynamic url
4551            if ('function' === typeof url) {
4552                url = url.call(this, validator);
4553            }
4554
4555            data[options.name || name] = value;
4556
4557            var dfd = new $.Deferred();
4558            var xhr = $.ajax({
4559                type: type,
4560                url: url,
4561                dataType: 'json',
4562                data: data
4563            });
4564            xhr.then(function(response) {
4565                dfd.resolve($field, 'remote', response.valid === true || response.valid === 'true', response.message ? response.message : null);
4566            });
4567
4568            dfd.fail(function() {
4569                xhr.abort();
4570            });
4571
4572            return dfd;
4573        }
4574    };
4575}(window.jQuery));
4576;(function($) {
4577    $.fn.bootstrapValidator.i18n.rtn = $.extend($.fn.bootstrapValidator.i18n.rtn || {}, {
4578        'default': 'Please enter a valid RTN number'
4579    });
4580
4581    $.fn.bootstrapValidator.validators.rtn = {
4582        /**
4583         * Validate a RTN (Routing transit number)
4584         * Examples:
4585         * - Valid: 021200025, 789456124
4586         *
4587         * @see http://en.wikipedia.org/wiki/Routing_transit_number
4588         * @param {BootstrapValidator} validator The validator plugin instance
4589         * @param {jQuery} $field Field element
4590         * @param {Object} options Can consist of the following keys:
4591         * - message: The invalid message
4592         * @returns {Boolean}
4593         */
4594        validate: function(validator, $field, options) {
4595            var value = $field.val();
4596            if (value === '') {
4597                return true;
4598            }
4599
4600            if (!/^\d{9}$/.test(value)) {
4601                return false;
4602            }
4603
4604            var sum = 0;
4605            for (var i = 0; i < value.length; i += 3) {
4606                sum += parseInt(value.charAt(i),     10) * 3
4607                    +  parseInt(value.charAt(i + 1), 10) * 7
4608                    +  parseInt(value.charAt(i + 2), 10);
4609            }
4610            return (sum !== 0 && sum % 10 === 0);
4611        }
4612    };
4613}(window.jQuery));
4614;(function($) {
4615    $.fn.bootstrapValidator.i18n.sedol = $.extend($.fn.bootstrapValidator.i18n.sedol || {}, {
4616        'default': 'Please enter a valid SEDOL number'
4617    });
4618
4619    $.fn.bootstrapValidator.validators.sedol = {
4620        /**
4621         * Validate a SEDOL (Stock Exchange Daily Official List)
4622         * Examples:
4623         * - Valid: 0263494, B0WNLY7
4624         *
4625         * @see http://en.wikipedia.org/wiki/SEDOL
4626         * @param {BootstrapValidator} validator The validator plugin instance
4627         * @param {jQuery} $field Field element
4628         * @param {Object} options Can consist of the following keys:
4629         * - message: The invalid message
4630         * @returns {Boolean}
4631         */
4632        validate: function(validator, $field, options) {
4633            var value = $field.val();
4634            if (value === '') {
4635                return true;
4636            }
4637
4638            value = value.toUpperCase();
4639            if (!/^[0-9A-Z]{7}$/.test(value)) {
4640                return false;
4641            }
4642
4643            var sum    = 0,
4644                weight = [1, 3, 1, 7, 3, 9, 1],
4645                length = value.length;
4646            for (var i = 0; i < length - 1; i++) {
4647	            sum += weight[i] * parseInt(value.charAt(i), 36);
4648	        }
4649	        sum = (10 - sum % 10) % 10;
4650            return sum + '' === value.charAt(length - 1);
4651        }
4652    };
4653}(window.jQuery));
4654;(function($) {
4655    $.fn.bootstrapValidator.i18n.siren = $.extend($.fn.bootstrapValidator.i18n.siren || {}, {
4656        'default': 'Please enter a valid SIREN number'
4657    });
4658
4659	$.fn.bootstrapValidator.validators.siren = {
4660		/**
4661		 * Check if a string is a siren number
4662		 *
4663		 * @param {BootstrapValidator} validator The validator plugin instance
4664		 * @param {jQuery} $field Field element
4665		 * @param {Object} options Consist of key:
4666         * - message: The invalid message
4667		 * @returns {Boolean}
4668		 */
4669		validate: function(validator, $field, options) {
4670			var value = $field.val();
4671			if (value === '') {
4672				return true;
4673			}
4674
4675            if (!/^\d{9}$/.test(value)) {
4676                return false;
4677            }
4678            return $.fn.bootstrapValidator.helpers.luhn(value);
4679		}
4680	};
4681}(window.jQuery));
4682;(function($) {
4683    $.fn.bootstrapValidator.i18n.siret = $.extend($.fn.bootstrapValidator.i18n.siret || {}, {
4684        'default': 'Please enter a valid SIRET number'
4685    });
4686
4687	$.fn.bootstrapValidator.validators.siret = {
4688        /**
4689         * Check if a string is a siret number
4690         *
4691         * @param {BootstrapValidator} validator The validator plugin instance
4692         * @param {jQuery} $field Field element
4693         * @param {Object} options Consist of key:
4694         * - message: The invalid message
4695         * @returns {Boolean}
4696         */
4697		validate: function(validator, $field, options) {
4698			var value = $field.val();
4699			if (value === '') {
4700				return true;
4701			}
4702
4703			var sum    = 0,
4704                length = value.length,
4705                tmp;
4706			for (var i = 0; i < length; i++) {
4707                tmp = parseInt(value.charAt(i), 10);
4708				if ((i % 2) === 0) {
4709					tmp = tmp * 2;
4710					if (tmp > 9) {
4711						tmp -= 9;
4712					}
4713				}
4714				sum += tmp;
4715			}
4716			return (sum % 10 === 0);
4717		}
4718	};
4719}(window.jQuery));
4720;(function($) {
4721    $.fn.bootstrapValidator.i18n.step = $.extend($.fn.bootstrapValidator.i18n.step || {}, {
4722        'default': 'Please enter a valid step of %s'
4723    });
4724
4725    $.fn.bootstrapValidator.validators.step = {
4726        html5Attributes: {
4727            message: 'message',
4728            base: 'baseValue',
4729            step: 'step'
4730        },
4731
4732        /**
4733         * Return true if the input value is valid step one
4734         *
4735         * @param {BootstrapValidator} validator The validator plugin instance
4736         * @param {jQuery} $field Field element
4737         * @param {Object} options Can consist of the following keys:
4738         * - baseValue: The base value
4739         * - step: The step
4740         * - message: The invalid message
4741         * @returns {Boolean|Object}
4742         */
4743        validate: function(validator, $field, options) {
4744            var value = $field.val();
4745            if (value === '') {
4746                return true;
4747            }
4748
4749            options = $.extend({}, { baseValue: 0, step: 1 }, options);
4750            value   = parseFloat(value);
4751            if (!$.isNumeric(value)) {
4752                return false;
4753            }
4754
4755            var round = function(x, precision) {
4756                    var m = Math.pow(10, precision);
4757                    x = x * m;
4758                    var sign   = (x > 0) | -(x < 0),
4759                        isHalf = (x % 1 === 0.5 * sign);
4760                    if (isHalf) {
4761                        return (Math.floor(x) + (sign > 0)) / m;
4762                    } else {
4763                        return Math.round(x) / m;
4764                    }
4765                },
4766                floatMod = function(x, y) {
4767                    if (y === 0.0) {
4768                        return 1.0;
4769                    }
4770                    var dotX      = (x + '').split('.'),
4771                        dotY      = (y + '').split('.'),
4772                        precision = ((dotX.length === 1) ? 0 : dotX[1].length) + ((dotY.length === 1) ? 0 : dotY[1].length);
4773                    return round(x - y * Math.floor(x / y), precision);
4774                };
4775
4776            var mod = floatMod(value - options.baseValue, options.step);
4777            return {
4778                valid: mod === 0.0 || mod === options.step,
4779                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.step['default'], [options.step])
4780            };
4781        }
4782    };
4783}(window.jQuery));
4784;(function($) {
4785    $.fn.bootstrapValidator.i18n.stringCase = $.extend($.fn.bootstrapValidator.i18n.stringCase || {}, {
4786        'default': 'Please enter only lowercase characters',
4787        upper: 'Please enter only uppercase characters'
4788    });
4789
4790    $.fn.bootstrapValidator.validators.stringCase = {
4791        html5Attributes: {
4792            message: 'message',
4793            'case': 'case'
4794        },
4795
4796        /**
4797         * Check if a string is a lower or upper case one
4798         *
4799         * @param {BootstrapValidator} validator The validator plugin instance
4800         * @param {jQuery} $field Field element
4801         * @param {Object} options Consist of key:
4802         * - message: The invalid message
4803         * - case: Can be 'lower' (default) or 'upper'
4804         * @returns {Object}
4805         */
4806        validate: function(validator, $field, options) {
4807            var value = $field.val();
4808            if (value === '') {
4809                return true;
4810            }
4811
4812            var stringCase = (options['case'] || 'lower').toLowerCase();
4813            return {
4814                valid: ('upper' === stringCase) ? value === value.toUpperCase() : value === value.toLowerCase(),
4815                message: options.message || (('upper' === stringCase) ? $.fn.bootstrapValidator.i18n.stringCase.upper : $.fn.bootstrapValidator.i18n.stringCase['default'])
4816            };
4817        }
4818    };
4819}(window.jQuery));
4820;(function($) {
4821    $.fn.bootstrapValidator.i18n.stringLength = $.extend($.fn.bootstrapValidator.i18n.stringLength || {}, {
4822        'default': 'Please enter a value with valid length',
4823        less: 'Please enter less than %s characters',
4824        more: 'Please enter more than %s characters',
4825        between: 'Please enter value between %s and %s characters long'
4826    });
4827
4828    $.fn.bootstrapValidator.validators.stringLength = {
4829        html5Attributes: {
4830            message: 'message',
4831            min: 'min',
4832            max: 'max'
4833        },
4834
4835        enableByHtml5: function($field) {
4836            var maxLength = $field.attr('maxlength');
4837            if (maxLength) {
4838                return {
4839                    max: parseInt(maxLength, 10)
4840                };
4841            }
4842
4843            return false;
4844        },
4845
4846        /**
4847         * Check if the length of element value is less or more than given number
4848         *
4849         * @param {BootstrapValidator} validator The validator plugin instance
4850         * @param {jQuery} $field Field element
4851         * @param {Object} options Consists of following keys:
4852         * - min
4853         * - max
4854         * At least one of two keys is required
4855         * The min, max keys define the number which the field value compares to. min, max can be
4856         *      - A number
4857         *      - Name of field which its value defines the number
4858         *      - Name of callback function that returns the number
4859         *      - A callback function that returns the number
4860         *
4861         * - message: The invalid message
4862         * @returns {Object}
4863         */
4864        validate: function(validator, $field, options) {
4865            var value = $field.val();
4866            if (value === '') {
4867                return true;
4868            }
4869
4870            var min     = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min),
4871                max     = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max),
4872                length  = value.length,
4873                isValid = true,
4874                message = options.message || $.fn.bootstrapValidator.i18n.stringLength['default'];
4875
4876            if ((min && length < parseInt(min, 10)) || (max && length > parseInt(max, 10))) {
4877                isValid = false;
4878            }
4879
4880            switch (true) {
4881                case (!!min && !!max):
4882                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.between, [parseInt(min, 10), parseInt(max, 10)]);
4883                    break;
4884
4885                case (!!min):
4886                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.more, parseInt(min, 10));
4887                    break;
4888
4889                case (!!max):
4890                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.less, parseInt(max, 10));
4891                    break;
4892
4893                default:
4894                    break;
4895            }
4896
4897            return { valid: isValid, message: message };
4898        }
4899    };
4900}(window.jQuery));
4901;(function($) {
4902    $.fn.bootstrapValidator.i18n.uri = $.extend($.fn.bootstrapValidator.i18n.uri || {}, {
4903        'default': 'Please enter a valid URI'
4904    });
4905
4906    $.fn.bootstrapValidator.validators.uri = {
4907        html5Attributes: {
4908            message: 'message',
4909            allowlocal: 'allowLocal'
4910        },
4911
4912        enableByHtml5: function($field) {
4913            return ('url' === $field.attr('type'));
4914        },
4915
4916        /**
4917         * Return true if the input value is a valid URL
4918         *
4919         * @param {BootstrapValidator} validator The validator plugin instance
4920         * @param {jQuery} $field Field element
4921         * @param {Object} options
4922         * - message: The error message
4923         * - allowLocal: Allow the private and local network IP. Default to false
4924         * @returns {Boolean}
4925         */
4926        validate: function(validator, $field, options) {
4927            var value = $field.val();
4928            if (value === '') {
4929                return true;
4930            }
4931
4932            // Credit to https://gist.github.com/dperini/729294
4933            //
4934            // Regular Expression for URL validation
4935            //
4936            // Author: Diego Perini
4937            // Updated: 2010/12/05
4938            //
4939            // the regular expression composed & commented
4940            // could be easily tweaked for RFC compliance,
4941            // it was expressly modified to fit & satisfy
4942            // these test for an URL shortener:
4943            //
4944            //   http://mathiasbynens.be/demo/url-regex
4945            //
4946            // Notes on possible differences from a standard/generic validation:
4947            //
4948            // - utf-8 char class take in consideration the full Unicode range
4949            // - TLDs have been made mandatory so single names like "localhost" fails
4950            // - protocols have been restricted to ftp, http and https only as requested
4951            //
4952            // Changes:
4953            //
4954            // - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255
4955            //   first and last IP address of each class is considered invali
4955d
4956            //   (since they are broadcast/network addresses)
4957            //
4958            // - Added exclusion of private, reserved and/or local networks ranges
4959            //
4960            var allowLocal = options.allowLocal === true || options.allowLocal === 'true',
4961                urlExp     = new RegExp(
4962                    "^" +
4963                    // protocol identifier
4964                    "(?:(?:https?|ftp)://)" +
4965                    // user:pass authentication
4966                    "(?:\\S+(?::\\S*)?@)?" +
4967                    "(?:" +
4968                    // IP address exclusion
4969                    // private & local networks
4970                    (allowLocal
4971                        ? ''
4972                        : ("(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
4973                           "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
4974                           "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})")) +
4975                    // IP address dotted notation octets
4976                    // excludes loopback network 0.0.0.0
4977                    // excludes reserved space >= 224.0.0.0
4978                    // excludes network & broadcast addresses
4979                    // (first & last IP address of each class)
4980                    "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
4981                    "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
4982                    "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
4983                    "|" +
4984                    // host name
4985                    "(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)" +
4986                    // domain name
4987                    "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
4988                    // TLD identifier
4989                    "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
4990                    ")" +
4991                    // port number
4992                    "(?::\\d{2,5})?" +
4993                    // resource path
4994                    "(?:/[^\\s]*)?" +
4995                    "$", "i"
4996                );
4997
4998            return urlExp.test(value);
4999        }
5000    };
5001}(window.jQuery));
5002;(function($) {
5003    $.fn.bootstrapValidator.i18n.uuid = $.extend($.fn.bootstrapValidator.i18n.uuid || {}, {
5004        'default': 'Please enter a valid UUID number',
5005        version: 'Please enter a valid UUID version %s number'
5006    });
5007
5008    $.fn.bootstrapValidator.validators.uuid = {
5009        html5Attributes: {
5010            message: 'message',
5011            version: 'version'
5012        },
5013
5014        /**
5015         * Return true if and only if the input value is a valid UUID string
5016         *
5017         * @see http://en.wikipedia.org/wiki/Universally_unique_identifier
5018         * @param {BootstrapValidator} validator The validator plugin instance
5019         * @param {jQuery} $field Field element
5020         * @param {Object} options Consist of key:
5021         * - message: The invalid message
5022         * - version: Can be 3, 4, 5, null
5023         * @returns {Boolean|Object}
5024         */
5025        validate: function(validator, $field, options) {
5026            var value = $field.val();
5027            if (value === '') {
5028                return true;
5029            }
5030
5031            // See the format at http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions
5032            var patterns = {
5033                    '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
5034                    '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
5035                    '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
5036                    all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
5037                },
5038                version = options.version ? (options.version + '') : 'all';
5039            return {
5040                valid: (null === patterns[version]) ? true : patterns[version].test(value),
5041                message: options.version
5042                            ? $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.uuid.version, options.version)
5043                            : (options.message || $.fn.bootstrapValidator.i18n.uuid['default'])
5044            };
5045        }
5046    };
5047}(window.jQuery));
5048;(function($) {
5049    $.fn.bootstrapValidator.i18n.vat = $.extend($.fn.bootstrapValidator.i18n.vat || {}, {
5050        'default': 'Please enter a valid VAT number',
5051        countryNotSupported: 'The country code %s is not supported',
5052        country: 'Please enter a valid %s VAT number',
5053        countries: {
5054            AT: 'Austrian',
5055            BE: 'Belgian',
5056            BG: 'Bulgarian',
5057            CH: 'Swiss',
5058            CY: 'Cypriot',
5059            CZ: 'Czech',
5060            DE: 'German',
5061            DK: 'Danish',
5062            EE: 'Estonian',
5063            ES: 'Spanish',
5064            FI: 'Finnish',
5065            FR: 'French',
5066            GB: 'United Kingdom',
5067            GR: 'Greek',
5068            EL: 'Greek',
5069            HU: 'Hungarian',
5070            HR: 'Croatian',
5071            IE: 'Irish',
5072            IT: 'Italian',
5073            LT: 'Lithuanian',
5074            LU: 'Luxembourg',
5075            LV: 'Latvian',
5076            MT: 'Maltese',
5077            NL: 'Dutch',
5078            NO: 'Norwegian',
5079            PL: 'Polish',
5080            PT: 'Portuguese',
5081            RO: 'Romanian',
5082            RU: 'Russian',
5083            RS: 'Serbian',
5084            SE: 'Swedish',
5085            SI: 'Slovenian',
5086            SK: 'Slovak'
5087        }
5088    });
5089
5090    $.fn.bootstrapValidator.validators.vat = {
5091        html5Attributes: {
5092            message: 'message',
5093            country: 'country'
5094        },
5095
5096        // Supported country codes
5097        COUNTRY_CODES: [
5098            'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'EL', 'HU', 'IE', 'IT',
5099            'LV', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB'
5100        ],
5101
5102        /**
5103         * Validate an European VAT number
5104         *
5105         * @param {BootstrapValidator} validator The validator plugin instance
5106         * @param {jQuery} $field Field element
5107         * @param {Object} options Consist of key:
5108         * - message: The invalid message
5109         * - country: The ISO 3166-1 country code. It can be
5110         *      - One of country code defined in COUNTRY_CODES
5111         *      - Name of field which its value defines the country code
5112         *      - Name of callback function that returns the country code
5113         *      - A callback function that returns the country code
5114         * @returns {Boolean|Object}
5115         */
5116        validate: function(validator, $field, options) {
5117            var value = $field.val();
5118            if (value === '') {
5119                return true;
5120            }
5121
5122            var country = options.country;
5123            if (!country) {
5124                country = value.substr(0, 2);
5125            } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
5126                // Determine the country code
5127                country = validator.getDynamicOption($field, country);
5128            }
5129
5130            if ($.inArray(country, this.COUNTRY_CODES) === -1) {
5131                return {
5132                    valid: false,
5133                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.vat.countryNotSupported, country)
5134                };
5135            }
5136
5137            var method  = ['_', country.toLowerCase()].join('');
5138            return this[method](value)
5139                ? true
5140                : {
5141                    valid: false,
5142                    message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.vat.country, $.fn.bootstrapValidator.i18n.vat.countries[country.toUpperCase()])
5143                };
5144        },
5145
5146        // VAT validators
5147
5148        /**
5149         * Validate Austrian VAT number
5150         * Example:
5151         * - Valid: ATU13585627
5152         * - Invalid: ATU13585626
5153         *
5154         * @param {String} value VAT number
5155         * @returns {Boolean}
5156         */
5157        _at: function(value) {
5158            if (!/^ATU[0-9]{8}$/.test(value)) {
5159                return false;
5160            }
5161
5162            value = value.substr(3);
5163            var sum    = 0,
5164                weight = [1, 2, 1, 2, 1, 2, 1],
5165                temp   = 0;
5166
5167            for (var i = 0; i < 7; i++) {
5168                temp = parseInt(value.charAt(i), 10) * weight[i];
5169                if (temp > 9) {
5170                    temp = Math.floor(temp / 10) + temp % 10;
5171                }
5172                sum += temp;
5173            }
5174
5175            sum = 10 - (sum + 4) % 10;
5176            if (sum === 10) {
5177                sum = 0;
5178            }
5179
5180            return (sum + '' === value.substr(7, 1));
5181        },
5182
5183        /**
5184         * Validate Belgian VAT number
5185         * Example:
5186         * - Valid: BE0428759497
5187         * - Invalid: BE431150351
5188         *
5189         * @param {String} value VAT number
5190         * @returns {Boolean}
5191         */
5192        _be: function(value) {
5193            if (!/^BE[0]{0,1}[0-9]{9}$/.test(value)) {
5194                return false;
5195            }
5196
5197            value = value.substr(2);
5198            if (value.length === 9) {
5199                value = '0' + value;
5200            }
5201
5202            if (value.substr(1, 1) === '0') {
5203                return false;
5204            }
5205
5206            var sum = parseInt(value.substr(0, 8), 10) + parseInt(value.substr(8, 2), 10);
5207            return (sum % 97 === 0);
5208        },
5209
5210        /**
5211         * Validate Bulgarian VAT number
5212         * Example:
5213         * - Valid: BG175074752,
5214         * BG7523169263, BG8032056031,
5215         * BG7542011030,
5216         * BG7111042925
5217         * - Invalid: BG175074753, BG7552A10004, BG7111042922
5218         *
5219         * @param {String} value VAT number
5220         * @returns {Boolean}
5221         */
5222        _bg: function(value) {
5223            if (!/^BG[0-9]{9,10}$/.test(value)) {
5224                return false;
5225            }
5226
5227            value = value.substr(2);
5228            var sum = 0, i = 0;
5229
5230            // Legal entities
5231            if (value.length === 9) {
5232                for (i = 0; i < 8; i++) {
5233                    sum += parseInt(value.charAt(i), 10) * (i + 1);
5234                }
5235                sum = sum % 11;
5236                if (sum === 10) {
5237                    sum = 0;
5238                    for (i = 0; i < 8; i++) {
5239                        sum += parseInt(value.charAt(i), 10) * (i + 3);
5240                    }
5241                }
5242                sum = sum % 10;
5243                return (sum + '' === value.substr(8));
5244            }
5245            // Physical persons, foreigners and others
5246            else if (value.length === 10) {
5247                // Validate Bulgarian national identification numbers
5248                var egn = function(value) {
5249                        // Check the birth date
5250                        var year  = parseInt(value.substr(0, 2), 10) + 1900,
5251                            month = parseInt(value.substr(2, 2), 10),
5252                            day   = parseInt(value.substr(4, 2), 10);
5253                        if (month > 40) {
5254                            year += 100;
5255                            month -= 40;
5256                        } else if (month > 20) {
5257                            year -= 100;
5258                            month -= 20;
5259                        }
5260
5261                        if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
5262                            return false;
5263                        }
5264
5265                        var sum    = 0,
5266                            weight = [2, 4, 8, 5, 10, 9, 7, 3, 6];
5267                        for (var i = 0; i < 9; i++) {
5268                            sum += parseInt(value.charAt(i), 10) * weight[i];
5269                        }
5270                        sum = (sum % 11) % 10;
5271                        return (sum + '' === value.substr(9, 1));
5272                    },
5273                    // Validate Bulgarian personal number of a foreigner
5274                    pnf = function(value) {
5275                        var sum    = 0,
5276                            weight = [21, 19, 17, 13, 11, 9, 7, 3, 1];
5277                        for (var i = 0; i < 9; i++) {
5278                            sum += parseInt(value.charAt(i), 10) * weight[i];
5279                        }
5280                        sum = sum % 10;
5281                        return (sum + '' === value.substr(9, 1));
5282                    },
5283                    // Finally, consider it as a VAT number
5284                    vat = function(value) {
5285                        var sum    = 0,
5286                            weight = [4, 3, 2, 7, 6, 5, 4, 3, 2];
5287                        for (var i = 0; i < 9; i++) {
5288                            sum += parseInt(value.charAt(i), 10) * weight[i];
5289                        }
5290                        sum = 11 - sum % 11;
5291                        if (sum === 10) {
5292                            return false;
5293                        }
5294                        if (sum === 11) {
5295                            sum = 0;
5296                        }
5297                        return (sum + '' === value.substr(9, 1));
5298                    };
5299                return (egn(value) || pnf(value) || vat(value));
5300            }
5301
5302            return false;
5303        },
5304
5305        /**
5306         * Validate Swiss VAT number
5307         *
5308         * @param {String} value VAT number
5309         * @returns {Boolean}
5310         */
5311        _ch: function(value) {
5312            if (!/^CHE[0-9]{9}(MWST)?$/.test(value)) {
5313                return false;
5314            }
5315
5316            value = value.substr(3);
5317            var sum    = 0,
5318                weight = [5, 4, 3, 2, 7, 6, 5, 4];
5319            for (var i = 0; i < 8; i++) {
5320                sum += parseInt(value.charAt(i), 10) * weight[i];
5321            }
5322
5323            sum = 11 - sum % 11;
5324            if (sum === 10) {
5325                return false;
5326            }
5327            if (sum === 11) {
5328                sum = 0;
5329            }
5330
5331            return (sum + '' === value.substr(8, 1));
5332        },
5333
5334        /**
5335         * Validate Cypriot VAT number
5336         * Examples:
5337         * - Valid: CY10259033P
5338         * - Invalid: CY10259033Z
5339         *
5340         * @param {String} value VAT number
5341         * @returns {Boolean}
5342         */
5343        _cy: function(value) {
5344            if (!/^CY[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
5345                return false;
5346            }
5347
5348            value = value.substr(2);
5349
5350            // Do not allow to start with "12"
5351            if (value.substr(0, 2) === '12') {
5352                return false;
5353            }
5354
5355            // Extract the next digit and multiply by the counter.
5356            var sum         = 0,
5357                translation = {
5358                    '0': 1,  '1': 0,  '2': 5,  '3': 7,  '4': 9,
5359                    '5': 13, '6': 15, '7': 17, '8': 19, '9': 21
5360                };
5361            for (var i = 0; i < 8; i++) {
5362                var temp = parseInt(value.charAt(i), 10);
5363                if (i % 2 === 0) {
5364                    temp = translation[temp + ''];
5365                }
5366                sum += temp;
5367            }
5368
5369            sum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[sum % 26];
5370            return (sum + '' === value.substr(8, 1));
5371        },
5372
5373        /**
5374         * Validate Czech Republic VAT number
5375         * Can be:
5376         * i) Legal entities (8 digit numbers)
5377         * ii) Individuals with a RC (the 9 or 10 digit Czech birth number)
5378         * iii) Individuals without a RC (9 digit numbers beginning with 6)
5379         *
5380         * Examples:
5381         * - Valid: i) CZ25123891; ii) CZ7103192745, CZ991231123; iii) CZ640903926
5382         * - Invalid: i) CZ25123890; ii) CZ1103492745, CZ590312123
5383         *
5384         * @param {String} value VAT number
5385         * @returns {Boolean}
5386         */
5387        _cz: function(value) {
5388            if (!/^CZ[0-9]{8,10}$/.test(value)) {
5389                return false;
5390            }
5391
5392            value = value.substr(2);
5393
5394            var sum = 0,
5395                i   = 0;
5396            if (value.length === 8) {
5397                // Do not allow to start with '9'
5398                if (value.charAt(0) + '' === '9') {
5399                    return false;
5400                }
5401
5402                sum = 0;
5403                for (i = 0; i < 7; i++) {
5404                    sum += parseInt(value.charAt(i), 10) * (8 - i);
5405                }
5406                sum = 11 - sum % 11;
5407                if (sum === 10) {
5408                    sum = 0;
5409                }
5410                if (sum === 11) {
5411                    sum = 1;
5412                }
5413
5414                return (sum + '' === value.substr(7, 1));
5415            } else if (value.length === 9 && (value.charAt(0) + '' === '6')) {
5416                sum = 0;
5417                // Skip the first (which is 6)
5418                for (i = 0; i < 7; i++) {
5419                    sum += parseInt(value.charAt(i + 1), 10) * (8 - i);
5420                }
5421                sum = 11 - sum % 11;
5422                if (sum === 10) {
5423                    sum = 0;
5424                }
5425                if (sum === 11) {
5426                    sum = 1;
5427                }
5428                sum = [8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 10][sum - 1];
5429                return (sum + '' === value.substr(8, 1));
5430            } else if (value.length === 9 || value.length === 10) {
5431                // Validate Czech birth number (Rodné číslo), which is also national identifier
5432                var year  = 1900 + parseInt(value.substr(0, 2), 10),
5433                    month = parseInt(value.substr(2, 2), 10) % 50 % 20,
5434                    day   = parseInt(value.substr(4, 2), 10);
5435                if (value.length === 9) {
5436                    if (year >= 1980) {
5437                        year -= 100;
5438                    }
5439                    if (year > 1953) {
5440                        return false;
5441                    }
5442                } else if (year < 1954) {
5443                    year += 100;
5444                }
5445
5446                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
5447                    return false;
5448                }
5449
5450                // Check that the birth date is not in the future
5451                if (value.length === 10) {
5452                    var check = parseInt(value.substr(0, 9), 10) % 11;
5453                    if (year < 1985) {
5454                        check = check % 10;
5455                    }
5456                    return (check + '' === value.substr(9, 1));
5457                }
5458
5459                return true;
5460            }
5461
5462            return false;
5463        },
5464
5465        /**
5466         * Validate German VAT number
5467         * Examples:
5468         * - Valid: DE136695976
5469         * - Invalid: DE136695978
5470         *
5471         * @param {String} value VAT number
5472         * @returns {Boolean}
5473         */
5474        _de: function(value) {
5475            if (!/^DE[0-9]{9}$/.test(value)) {
5476                return false;
5477            }
5478
5479            value = value.substr(2);
5480            return $.fn.bootstrapValidator.helpers.mod11And10(value);
5481        },
5482
5483        /**
5484         * Validate Danish VAT number
5485         * Example:
5486         * - Valid: DK13585628
5487         * - Invalid: DK13585627
5488         *
5489         * @param {String} value VAT number
5490         * @returns {Boolean}
5491         */
5492        _dk: function(value) {
5493            if (!/^DK[0-9]{8}$/.test(value)) {
5494                return false;
5495            }
5496
5497            value = value.substr(2);
5498            var sum    = 0,
5499                weight = [2, 7, 6, 5, 4, 3, 2, 1];
5500            for (var i = 0; i < 8; i++) {
5501                sum += parseInt(value.charAt(i), 10) * weight[i];
5502            }
5503
5504            return (sum % 11 === 0);
5505        },
5506
5507        /**
5508         * Validate Estonian VAT number
5509         * Examples:
5510         * - Valid: EE100931558, EE100594102
5511         * - Invalid: EE100594103
5512         *
5513         * @param {String} value VAT number
5514         * @returns {Boolean}
5515         */
5516        _ee: function(value) {
5517            if (!/^EE[0-9]{9}$/.test(value)) {
5518                return false;
5519            }
5520
5521            value = value.substr(2);
5522            var sum    = 0,
5523                weight = [3, 7, 1, 3, 7, 1, 3, 7, 1];
5524
5525            for (var i = 0; i < 9; i++) {
5526                sum += parseInt(value.charAt(i), 10) * weight[i];
5527            }
5528
5529            return (sum % 10 === 0);
5530        },
5531
5532        /**
5533         * Validate Spanish VAT number (NIF - Número de Identificación Fiscal)
5534         * Can be:
5535         * i) DNI (Documento nacional de identidad), for Spaniards
5536         * ii) NIE (Número de Identificación de Extranjeros), for foreigners
5537         * iii) CIF (Certificado de Identificación Fiscal), for legal entities and others
5538         *
5539         * Examples:
5540         * - Valid: i) ES54362315K; ii) ESX2482300W, ESX5253868R; iii) ESM1234567L, ESJ99216582, ESB58378431, ESB64717838
5541         * - Invalid: i) ES54362315Z; ii) ESX2482300A; iii) ESJ99216583
5542         *
5543         * @param {String} value VAT number
5544         * @returns {Boolean}
5545         */
5546        _es: function(value) {
5547            if (!/^ES[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
5548                return false;
5549            }
5550
5551            value = value.substr(2);
5552            var dni = function(value) {
5553                    var check = parseInt(value.substr(0, 8), 10);
5554                    check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
5555                    return (check + '' === value.substr(8, 1));
5556                },
5557                nie = function(value) {
5558                    var check = ['XYZ'.indexOf(value.charAt(0)), value.substr(1)].join('');
5559                    check = parseInt(check, 10);
5560                    check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
5561                    return (check + '' === value.substr(8, 1));
5562                },
5563                cif = function(value) {
5564                    var first = value.charAt(0), check;
5565                    if ('KLM'.indexOf(first) !== -1) {
5566                        // K: Spanish younger than 14 year old
5567                        // L: Spanish living outside Spain without DNI
5568                        // M: Granted the tax to foreigners who have no NIE
5569                        check = parseInt(value.substr(1, 8), 10);
5570                        check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
5571                        return (check + '' === value.substr(8, 1));
5572                    } else if ('ABCDEFGHJNPQRSUVW'.indexOf(first) !== -1) {
5573                        var sum    = 0,
5574                            weight = [2, 1, 2, 1, 2, 1, 2],
5575                            temp   = 0;
5576
5577                        for (var i = 0; i < 7; i++) {
5578                            temp = parseInt(value.charAt(i + 1), 10) * weight[i];
5579                            if (temp > 9) {
5580                                temp = Math.floor(temp / 10) + temp % 10;
5581                            }
5582                            sum += temp;
5583                        }
5584                        sum = 10 - sum % 10;
5585                        return (sum + '' === value.substr(8, 1) || 'JABCDEFGHI'[sum] === value.substr(8, 1));
5586                    }
5587
5588                    return false;
5589                };
5590
5591            var first = value.charAt(0);
5592            if (/^[0-9]$/.test(first)) {
5593                return dni(value);
5594            } else if (/^[XYZ]$/.test(first)) {
5595                return nie(value);
5596            } else {
5597                return cif(value);
5598            }
5599        },
5600
5601        /**
5602         * Validate Finnish VAT number
5603         * Examples:
5604         * - Valid: FI20774740
5605         * - Invalid: FI20774741
5606         *
5607         * @param {String} value VAT number
5608         * @returns {Boolean}
5609         */
5610        _fi: function(value) {
5611            if (!/^FI[0-9]{8}$/.test(value)) {
5612                return false;
5613            }
5614
5615            value = value.substr(2);
5616            var sum    = 0,
5617                weight = [7, 9, 10, 5, 8, 4, 2, 1];
5618
5619            for (var i = 0; i < 8; i++) {
5620                sum += parseInt(value.charAt(i), 10) * weight[i];
5621            }
5622
5623            return (sum % 11 === 0);
5624        },
5625
5626        /**
5627         * Validate French VAT number (TVA - taxe sur la valeur ajoutée)
5628         * It's constructed by a SIREN number, prefixed by two characters.
5629         *
5630         * Examples:
5631         * - Valid: FR40303265045, FR23334175221, FRK7399859412, FR4Z123456782
5632         * - Invalid: FR84323140391
5633         *
5634         * @param {String} value VAT number
5635         * @returns {Boolean}
5636         */
5637        _fr: function(value) {
5638            if (!/^FR[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
5639                return false;
5640            }
5641
5642            value = value.substr(2);
5643
5644			if (!$.fn.bootstrapValidator.helpers.luhn(value.substr(2))) {
5645                return false;
5646            }
5647
5648            if (/^[0-9]{2}$/.test(value.substr(0, 2))) {
5649                // First two characters are digits
5650                return value.substr(0, 2) === (parseInt(value.substr(2) + '12', 10) % 97 + '');
5651            } else {
5652                // The first characters cann't be O and I
5653                var alphabet = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ',
5654                    check;
5655                // First one is digit
5656                if (/^[0-9]{1}$/.test(value.charAt(0))) {
5657                    check = alphabet.indexOf(value.charAt(0)) * 24 + alphabet.indexOf(value.charAt(1)) - 10;
5658                } else {
5659                    check = alphabet.indexOf(value.charAt(0)) * 34 + alphabet.indexOf(value.charAt(1)) - 100;
5660                }
5661                return ((parseInt(value.substr(2), 10) + 1 + Math.floor(check / 11)) % 11) === (check % 11);
5662            }
5663        },
5664
5665        /**
5666         * Validate United Kingdom VAT number
5667         * Example:
5668         * - Valid: GB980780684
5669         * - Invalid: GB802311781
5670         *
5671         * @param {String} value VAT number
5672         * @returns {Boolean}
5673         */
5674        _gb: function(value) {
5675            if (!/^GB[0-9]{9}$/.test(value)             /* Standard */
5676                && !/^GB[0-9]{12}$/.test(value)         /* Branches */
5677                && !/^GBGD[0-9]{3}$/.test(value)        /* Government department */
5678                && !/^GBHA[0-9]{3}$/.test(value)        /* Health authority */
5679                && !/^GB(GD|HA)8888[0-9]{5}$/.test(value))
5680            {
5681                return false;
5682            }
5683
5684            value = value.substr(2);
5685            var length = value.length;
5686            if (length === 5) {
5687                var firstTwo  = value.substr(0, 2),
5688                    lastThree = parseInt(value.substr(2), 10);
5689                return ('GD' === firstTwo && lastThree < 500) || ('HA' === firstTwo && lastThree >= 500);
5690            } else if (length === 11 && ('GD8888' === value.substr(0, 6) || 'HA8888' === value.substr(0, 6))) {
5691                if (('GD' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) >= 500)
5692                    || ('HA' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) < 500))
5693                {
5694                    return false;
5695                }
5696                return (parseInt(value.substr(6, 3), 10) % 97 === parseInt(value.substr(9, 2), 10));
5697            } else if (length === 9 || length === 12) {
5698                var sum    = 0,
5699                    weight = [8, 7, 6, 5, 4, 3, 2, 10, 1];
5700                for (var i = 0; i < 9; i++) {
5701                    sum += parseInt(value.charAt(i), 10) * weight[i];
5702                }
5703                sum = sum % 97;
5704
5705                if (parseInt(value.substr(0, 3), 10) >= 100) {
5706                    return (sum === 0 || sum === 42 || sum === 55);
5707                } else {
5708                    return (sum === 0);
5709                }
5710            }
5711
5712            return true;
5713        },
5714
5715        /**
5716         * Validate Greek VAT number
5717         * Examples:
5718         * - Valid: GR023456780, EL094259216
5719         * - Invalid: EL123456781
5720         *
5721         * @param {String} value VAT number
5722         * @returns {Boolean}
5723         */
5724        _gr: function(value) {
5725            if (!/^GR[0-9]{9}$/.test(value)) {
5726                return false;
5727            }
5728
5729            value = value.substr(2);
5730            if (value.length === 8) {
5731                value = '0' + value;
5732            }
5733
5734            var sum    = 0,
5735                weight = [256, 128, 64, 32, 16, 8, 4, 2];
5736            for (var i = 0; i < 8; i++) {
5737                sum += parseInt(value.charAt(i), 10) * weight[i];
5738            }
5739            sum = (sum % 11) % 10;
5740
5741            return (sum + '' === value.substr(8, 1));
5742        },
5743
5744        // EL is traditionally prefix of Greek VAT numbers
5745        _el: function(value) {
5746            if (!/^EL[0-9]{9}$/.test(value)) {
5747                return false;
5748            }
5749
5750            value = 'GR' + value.substr(2);
5751            return this._gr(value);
5752        },
5753
5754        /**
5755         * Validate Hungarian VAT number
5756         * Examples:
5757         * - Valid: HU12892312
5758         * - Invalid: HU12892313
5759         *
5760         * @param {String} value VAT number
5761         * @returns {Boolean}
5762         */
5763        _hu: function(value) {
5764            if (!/^HU[0-9]{8}$/.test(value)) {
5765                return false;
5766            }
5767
5768            value = value.substr(2);
5769            var sum    = 0,
5770                weight = [9, 7, 3, 1, 9, 7, 3, 1];
5771
5772            for (var i = 0; i < 8; i++) {
5773                sum += parseInt(value.charAt(i), 10) * weight[i];
5774            }
5775
5776            return (sum % 10 === 0);
5777        },
5778
5779        /**
5780         * Validate Croatian VAT number
5781         * Examples:
5782         * - Valid: HR33392005961
5783         * - Invalid: HR33392005962
5784         *
5785         * @param {String} value VAT number
5786         * @returns {Boolean}
5787         */
5788        _hr: function(value) {
5789            if (!/^HR[0-9]{11}$/.test(value)) {
5790                return false;
5791            }
5792
5793            value = value.substr(2);
5794            return $.fn.bootstrapValidator.helpers.mod11And10(value);
5795        },
5796
5797        /**
5798         * Validate Irish VAT number
5799         * Examples:
5800         * - Valid: IE6433435F, IE6433435OA, IE8D79739I
5801         * - Invalid: IE8D79738J
5802         *
5803         * @param {String} value VAT number
5804         * @returns {Boolean}
5805         */
5806        _ie: function(value) {
5807            if (!/^IE[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
5808                return false;
5809            }
5810
5811            value = value.substr(2);
5812            var getCheckDigit = function(value) {
5813                while (value.length < 7) {
5814                    value = '0' + value;
5815                }
5816                var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV',
5817                    sum      = 0;
5818                for (var i = 0; i < 7; i++) {
5819                    sum += parseInt(value.charAt(i), 10) * (8 - i);
5820                }
5821                sum += 9 * alphabet.indexOf(value.substr(7));
5822                return alphabet[sum % 23];
5823            };
5824
5825            // The first 7 characters are digits
5826            if (/^[0-9]+$/.test(value.substr(0, 7))) {
5827                // New system
5828                return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + '');
5829            } else if ('ABCDEFGHIJKLMNOPQRSTUVWXYZ+*'.indexOf(value.charAt(1)) !== -1) {
5830                // Old system
5831                return value.charAt(7) === getCheckDigit(value.substr(2, 5) + value.substr(0, 1) + '');
5832            }
5833
5834            return true;
5835        },
5836
5837        /**
5838         * Validate Italian VAT number, which consists of 11 digits.
5839         * - First 7 digits are a company identifier
5840         * - Next 3 are the province of residence
5841         * - The last one is a check digit
5842         *
5843         * Examples:
5844         * - Valid: IT00743110157
5845         * - Invalid: IT00743110158
5846         *
5847         * @param {String} value VAT number
5848         * @returns {Boolean}
5849         */
5850        _it: function(value) {
5851            if (!/^IT[0-9]{11}$/.test(value)) {
5852                return false;
5853            }
5854
5855            value = value.substr(2);
5856            if (parseInt(value.substr(0, 7), 10) === 0) {
5857                return false;
5858            }
5859
5860            var lastThree = parseInt(value.substr(7, 3), 10);
5861            if ((lastThree < 1) || (lastThree > 201) && lastThree !== 999 && lastThree !== 888) {
5862                return false;
5863            }
5864
5865            return $.fn.bootstrapValidator.helpers.luhn(value);
5866        },
5867
5868        /**
5869         * Validate Lithuanian VAT number
5870         * It can be:
5871         * - 9 digits, for legal entities
5872         * - 12 digits, for temporarily registered taxpayers
5873         *
5874         * Examples:
5875         * - Valid: LT119511515, LT100001919017, LT100004801610
5876         * - Invalid: LT100001919018
5877         *
5878         * @param {String} value VAT number
5879         * @returns {Boolean}
5880         */
5881        _lt: function(value) {
5882            if (!/^LT([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
5883                return false;
5884            }
5885
5886            value = value.substr(2);
5887            var length = value.length,
5888                sum    = 0,
5889                i;
5890            for (i = 0; i < length - 1; i++) {
5891                sum += parseInt(value.charAt(i), 10) * (1 + i % 9);
5892            }
5893            var check = sum % 11;
5894            if (check === 10) {
5895                sum = 0;
5896                for (i = 0; i < length - 1; i++) {
5897                    sum += parseInt(value.charAt(i), 10) * (1 + (i + 2) % 9);
5898                }
5899            }
5900            check = check % 11 % 10;
5901            return (check + '' === value.charAt(length - 1));
5902        },
5903
5904        /**
5905         * Validate Luxembourg VAT number
5906         * Examples:
5907         * - Valid: LU15027442
5908         * - Invalid: LU15027443
5909         *
5910         * @param {String} value VAT number
5911         * @returns {Boolean}
5912         */
5913        _lu: function(value) {
5914            if (!/^LU[0-9]{8}$/.test(value)) {
5915                return false;
5916            }
5917
5918            value = value.substr(2);
5919            return ((parseInt(value.substr(0, 6), 10) % 89) + '' === value.substr(6, 2));
5920        },
5921
5922        /**
5923         * Validate Latvian VAT number
5924         * Examples:
5925         * - Valid: LV40003521600, LV16117519997
5926         * - Invalid: LV40003521601, LV16137519997
5927         *
5928         * @param {String} value VAT number
5929         * @returns {Boolean}
5930         */
5931        _lv: function(value) {
5932            if (!/^LV[0-9]{11}$/.test(value)) {
5933                return false;
5934            }
5935
5936            value = value.substr(2);
5937            var first  = parseInt(value.charAt(0), 10),
5938                sum    = 0,
5939                weight = [],
5940                i,
5941                length = value.length;
5942            if (first > 3) {
5943                // Legal entity
5944                sum    = 0;
5945                weight = [9, 1, 4, 8, 3, 10, 2, 5, 7, 6, 1];
5946                for (i = 0; i < length; i++) {
5947                    sum += parseInt(value.charAt(i), 10) * weight[i];
5948                }
5949                sum = sum % 11;
5950                return (sum === 3);
5951            } else {
5952                // Check birth date
5953                var day   = parseInt(value.substr(0, 2), 10),
5954                    month = parseInt(value.substr(2, 2), 10),
5955                    year  = parseInt(value.substr(4, 2), 10);
5956                year = year + 1800 + parseInt(value.charAt(6), 10) * 100;
5957
5958                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
5959                    return false;
5960                }
5961
5962                // Check personal code
5963                sum    = 0;
5964                weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9];
5965                for (i = 0; i < length - 1; i++) {
5966                    sum += parseInt(value.charAt(i), 10) * weight[i];
5967                }
5968                sum = (sum + 1) % 11 % 10;
5969                return (sum + '' === value.charAt(length - 1));
5970            }
5971        },
5972
5973        /**
5974         * Validate Maltese VAT number
5975         * Examples:
5976         * - Valid: MT11679112
5977         * - Invalid: MT11679113
5978         *
5979         * @param {String} value VAT number
5980         * @returns {Boolean}
5981         */
5982        _mt: function(value) {
5983            if (!/^MT[0-9]{8}$/.test(value)) {
5984                return false;
5985            }
5986
5987            value = value.substr(2);
5988            var sum    = 0,
5989                weight = [3, 4, 6, 7, 8, 9, 10, 1];
5990
5991            for (var i = 0; i < 8; i++) {
5992                sum += parseInt(value.charAt(i), 10) * weight[i];
5993            }
5994
5995            return (sum % 37 === 0);
5996        },
5997
5998        /**
5999         * Validate Dutch VAT number
6000         * Examples:
6001         * - Valid: NL004495445B01
6002         * - Invalid: NL123456789B90
6003         *
6004         * @param {String} value VAT number
6005         * @returns {Boolean}
6006         */
6007        _nl: function(value) {
6008            if (!/^NL[0-9]{9}B[0-9]{2}$/.test(value)) {
6009               return false;
6010            }
6011            value = value.substr(2);
6012            var sum    = 0,
6013                weight = [9, 8, 7, 6, 5, 4, 3, 2];
6014            for (var i = 0; i < 8; i++) {
6015                sum += parseInt(value.charAt(i), 10) * weight[i];
6016            }
6017
6018            sum = sum % 11;
6019            if (sum > 9) {
6020                sum = 0;
6021            }
6022            return (sum + '' === value.substr(8, 1));
6023        },
6024
6025        /**
6026         * Validate Norwegian VAT number
6027         *
6028         * @see http://www.brreg.no/english/coordination/number.html
6029         * @param {String} value VAT number
6030         * @returns {Boolean}
6031         */
6032        _no: function(value) {
6033            if (!/^NO[0-9]{9}$/.test(value)) {
6034               return false;
6035            }
6036            value = value.substr(2);
6037            var sum    = 0,
6038                weight = [3, 2, 7, 6, 5, 4, 3, 2];
6039            for (var i = 0; i < 8; i++) {
6040                sum += parseInt(value.charAt(i), 10) * weight[i];
6041            }
6042
6043            sum = 11 - sum % 11;
6044            if (sum === 11) {
6045                sum = 0;
6046            }
6047            return (sum + '' === value.substr(8, 1));
6048        },
6049
6050        /**
6051         * Validate Polish VAT number
6052         * Examples:
6053         * - Valid: PL8567346215
6054         * - Invalid: PL8567346216
6055         *
6056         * @param {String} value VAT number
6057         * @returns {Boolean}
6058         */
6059        _pl: function(value) {
6060            if (!/^PL[0-9]{10}$/.test(value)) {
6061                return false;
6062            }
6063
6064            value = value.substr(2);
6065            var sum    = 0,
6066                weight = [6, 5, 7, 2, 3, 4, 5, 6, 7, -1];
6067
6068            for (var i = 0; i < 10; i++) {
6069                sum += parseInt(value.charAt(i), 10) * weight[i];
6070            }
6071
6072            return (sum % 11 === 0);
6073        },
6074
6075        /**
6076         * Validate Portuguese VAT number
6077         * Examples:
6078         * - Valid: PT501964843
6079         * - Invalid: PT501964842
6080         *
6081         * @param {String} value VAT number
6082         * @returns {Boolean}
6083         */
6084        _pt: function(value) {
6085            if (!/^PT[0-9]{9}$/.test(value)) {
6086                return false;
6087            }
6088
6089            value = value.substr(2);
6090            var sum    = 0,
6091                weight = [9, 8, 7, 6, 5, 4, 3, 2];
6092
6093            for (var i = 0; i < 8; i++) {
6094                sum += parseInt(value.charAt(i), 10) * weight[i];
6095            }
6096            sum = 11 - sum % 11;
6097            if (sum > 9) {
6098                sum = 0;
6099            }
6100            return (sum + '' === value.substr(8, 1));
6101        },
6102
6103        /**
6104         * Validate Romanian VAT number
6105         * Examples:
6106         * - Valid: RO18547290
6107         * - Invalid: RO18547291
6108         *
6109         * @param {String} value VAT number
6110         * @returns {Boolean}
6111         */
6112        _ro: function(value) {
6113            if (!/^RO[1-9][0-9]{1,9}$/.test(value)) {
6114                return false;
6115            }
6116            value = value.substr(2);
6117
6118            var length = value.length,
6119                weight = [7, 5, 3, 2, 1, 7, 5, 3, 2].slice(10 - length),
6120                sum    = 0;
6121            for (var i = 0; i < length - 1; i++) {
6122                sum += parseInt(value.charAt(i), 10) * weight[i];
6123            }
6124
6125            sum = (10 * sum) % 11 % 10;
6126            return (sum + '' === value.substr(length - 1, 1));
6127        },
6128
6129        /**
6130         * Validate Russian VAT number (Taxpayer Identification Number - INN)
6131         *
6132         * @param {String} value VAT number
6133         * @returns {Boolean}
6134         */
6135        _ru: function(value) {
6136            if (!/^RU([0-9]{9}|[0-9]{12})$/.test(value)) {
6137                return false;
6138            }
6139
6140            value = value.substr(2);
6141            var i = 0;
6142            if (value.length === 10) {
6143                var sum    = 0,
6144                    weight = [2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
6145                for (i = 0; i < 10; i++) {
6146                    sum += parseInt(value.charAt(i), 10) * weight[i];
6147                }
6148                sum = sum % 11;
6149                if (sum > 9) {
6150                    sum = sum % 10;
6151                }
6152
6153                return (sum + '' === value.substr(9, 1));
6154            } else if (value.length === 12) {
6155                var sum1    = 0,
6156                    weight1 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0],
6157                    sum2    = 0,
6158                    weight2 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
6159
6160                for (i = 0; i < 11; i++) {
6161                    sum1 += parseInt(value.charAt(i), 10) * weight1[i];
6162                    sum2 += parseInt(value.charAt(i), 10) * weight2[i];
6163                }
6164                sum1 = sum1 % 11;
6165                if (sum1 > 9) {
6166                    sum1 = sum1 % 10;
6167                }
6168                sum2 = sum2 % 11;
6169                if (sum2 > 9) {
6170                    sum2 = sum2 % 10;
6171                }
6172
6173                return (sum1 + '' === value.substr(10, 1) && sum2 + '' === value.substr(11, 1));
6174            }
6175
6176            return false;
6177        },
6178
6179        /**
6180         * Validate Serbian VAT number
6181         *
6182         * @param {String} value VAT number
6183         * @returns {Boolean}
6184         */
6185        _rs: function(value) {
6186            if (!/^RS[0-9]{9}$/.test(value)) {
6187                return false;
6188            }
6189
6190            value = value.substr(2);
6191            var sum  = 10,
6192                temp = 0;
6193            for (var i = 0; i < 8; i++) {
6194                temp = (parseInt(value.charAt(i), 10) + sum) % 10;
6195                if (temp === 0) {
6196                    temp = 10;
6197                }
6198                sum = (2 * temp) % 11;
6199            }
6200
6201            return ((sum + parseInt(value.substr(8, 1), 10)) % 10 === 1);
6202        },
6203
6204        /**
6205         * Validate Swedish VAT number
6206         * Examples:
6207         * - Valid: SE123456789701
6208         * - Invalid: SE123456789101
6209         *
6210         * @param {String} value VAT number
6211         * @returns {Boolean}
6212         */
6213        _se: function(value) {
6214            if (!/^SE[0-9]{10}01$/.test(value)) {
6215                return false;
6216            }
6217
6218            value = value.substr(2, 10);
6219            return $.fn.bootstrapValidator.helpers.luhn(value);
6220        },
6221
6222        /**
6223         * Validate Slovenian VAT number
6224         * Examples:
6225         * - Valid: SI50223054
6226         * - Invalid: SI50223055
6227         *
6228         * @param {String} value VAT number
6229         * @returns {Boolean}
6230         */
6231        _si: function(value) {
6232            if (!/^SI[0-9]{8}$/.test(value)) {
6233                return false;
6234            }
6235
6236            value = value.substr(2);
6237            var sum    = 0,
6238                weight = [8, 7, 6, 5, 4, 3, 2];
6239
6240            for (var i = 0; i < 7; i++) {
6241                sum += parseInt(value.charAt(i), 10) * weight[i];
6242            }
6243            sum = 11 - sum % 11;
6244            if (sum === 10) {
6245                sum = 0;
6246            }
6247            return (sum + '' === value.substr(7, 1));
6248        },
6249
6250        /**
6251         * Validate Slovak VAT number
6252         * Examples:
6253         * - Valid: SK2022749619
6254         * - Invalid: SK2022749618
6255         *
6256         * @param {String} value VAT number
6257         * @returns {Boolean}
6258         */
6259        _sk: function(value) {
6260            if (!/^SK[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
6261                return false;
6262            }
6263
6264            return (parseInt(value.substr(2), 10) % 11 === 0);
6265        }
6266    };
6267}(window.jQuery));
6268;(function($) {
6269    $.fn.bootstrapValidator.i18n.vin = $.extend($.fn.bootstrapValidator.i18n.vin || {}, {
6270        'default': 'Please enter a valid VIN number'
6271    });
6272
6273    $.fn.bootstrapValidator.validators.vin = {
6274        /**
6275         * Validate an US VIN (Vehicle Identification Number)
6276         *
6277         * @param {BootstrapValidator} validator The validator plugin instance
6278         * @param {jQuery} $field Field element
6279         * @param {Object} options Consist of key:
6280         * - message: The invalid message
6281         * @returns {Boolean}
6282         */
6283        validate: function(validator, $field, options) {
6284            var value = $field.val();
6285            if (value === '') {
6286                return true;
6287            }
6288
6289            // Don't accept I, O, Q characters
6290            if (!/^[a-hj-npr-z0-9]{8}[0-9xX][a-hj-npr-z0-9]{8}$/i.test(value)) {
6291                return false;
6292            }
6293
6294            value = value.toUpperCase();
6295            var chars   = {
6296                    A: 1,   B: 2,   C: 3,   D: 4,   E: 5,   F: 6,   G: 7,   H: 8,
6297                    J: 1,   K: 2,   L: 3,   M: 4,   N: 5,           P: 7,           R: 9,
6298                            S: 2,   T: 3,   U: 4,   V: 5,   W: 6,   X: 7,   Y: 8,   Z: 9,
6299                    '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '0': 0
6300                },
6301                weights = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2],
6302                sum     = 0,
6303                length  = value.length;
6304            for (var i = 0; i < length; i++) {
6305                sum += chars[value.charAt(i) + ''] * weights[i];
6306            }
6307
6308            var reminder = sum % 11;
6309            if (reminder === 10) {
6310                reminder = 'X';
6311            }
6312
6313            return (reminder + '') === value.charAt(8);
6314        }
6315    };
6316}(window.jQuery));
6317;(function($) {
6318    $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, {
6319        'default': 'Please enter a valid zip code',
6320        countryNotSupported: 'The country code %s is not supported',
6321        country: 'Please enter a valid %s',
6322        countries: {
6323            'CA': 'Canadian postal code',
6324            'DK': 'Danish postal code',
6325            'GB': 'United Kingdom postal code',
6326            'IT': 'Italian postal code',
6327            'NL': 'Dutch postal code',
6328            'SE': 'Swiss postal code',
6329            'SG': 'Singapore postal code',
6330            'US': 'US zip code'
6331        }
6332    });
6333
6334    $.fn.bootstrapValidator.validators.zipCode = {
6335        html5Attributes: {
6336            message: 'message',
6337            country: 'country'
6338        },
6339
6340        COUNTRY_CODES: ['CA', 'DK', 'GB', 'IT', 'NL', 'SE', 'SG', 'US'],
6341
6342        /**
6343         * Return true if and only if the input value is a valid country zip code
6344         *
6345         * @param {BootstrapValidator} validator The validator plugin instance
6346         * @param {jQuery} $field Field element
6347         * @param {Object} options Consist of key:
6348         * - message: The invalid message
6349         * - country: The country
6350         *
6351         * The country can be defined by:
6352         * - An ISO 3166 country code
6353         * Currently it supports the following countries:
6354         *      - US (United States)
6355         *      - CA (Canada)
6356         *      - DK (Denmark)
6357         *      - GB (United Kingdom)
6358         *      - IT (Italy)
6359         *      - NL (Netherlands)
6360         *      - SE (Sweden)
6361         *      - SG (Singapore)
6362         *
6363         * - Name of field which its value defines the country code
6364         * - Name of callback function that returns the country code
6365         * - A callback function that returns the country code
6366         *
6367         * callback: function(value, validator, $field) {
6368         *      // value is the value of field
6369         *      // validator is the BootstrapValidator instance
6370         *      // $field is jQuery element representing the field
6371         * }
6372         *
6373         * @returns {Boolean|Object}
6374         */
6375        validate: function(validator, $field, options) {
6376            var value = $field.val();
6377            if (value === '' || !options.country) {
6378                return true;
6379            }
6380
6381            var country = options.country;
6382            if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) {
6383                // Try to determine the country
6384                country = validator.getDynamicOption($field, country);
6385            }
6386
6387            if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
6388                return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.zipCode.countryNotSupported, country) };
6389            }
6390
6391            var isValid = false;
6392            country = country.toUpperCase();
6393            switch (country) {
6394                case 'CA':
6395                    isValid = /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}[0-9]{1}$/i.test(value);
6396                    break;
6397
6398                case 'DK':
6399                    isValid = /^(DK(-|\s)?)?\d{4}$/i.test(value);
6400                    break;
6401
6402                case 'GB':
6403                    isValid = this._gb(value);
6404                    break;
6405
6406                // http://en.wikipedia.org/wiki/List_of_postal_codes_in_Italy
6407                case 'IT':
6408                    isValid = /^(I-|IT-)?\d{5}$/i.test(value);
6409                    break;
6410
6411                // http://en.wikipedia.org/wiki/Postal_codes_in_the_Netherlands
6412                case 'NL':
6413                    isValid = /^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i.test(value);
6414                    break;
6415
6416                case 'SE':
6417                    isValid = /^(S-)?\d{3}\s?\d{2}$/i.test(value);
6418                    break;
6419
6420                case 'SG':
6421                    isValid = /^([0][1-9]|[1-6][0-9]|[7]([0-3]|[5-9])|[8][0-2])(\d{4})$/i.test(value);
6422                    break;
6423
6424                case 'US':
6425                /* falls through */
6426                default:
6427                    isValid = /^\d{4,5}([\-]?\d{4})?$/.test(value);
6428                    break;
6429            }
6430
6431            return {
6432                valid: isValid,
6433                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.zipCode.country, $.fn.bootstrapValidator.i18n.zipCode.countries[country])
6434            };
6435        },
6436
6437        /**
6438         * Validate United Kingdom postcode
6439         * Examples:
6440         * - Standard: EC1A 1BB, W1A 1HQ, M1 1AA, B33 8TH, CR2 6XH, DN55 1PT
6441         * - Special cases:
6442         * AI-2640, ASCN 1ZZ, GIR 0AA
6443         *
6444         * @see http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom
6445         * @param {String} value The postcode
6446         * @returns {Boolean}
6447         */
6448        _gb: function(value) {
6449            var firstChar  = '[ABCDEFGHIJKLMNOPRSTUWYZ]',     // Does not accept QVX
6450                secondChar = '[ABCDEFGHKLMNOPQRSTUVWXY]',     // Does not accept IJZ
6451                thirdChar  = '[ABCDEFGHJKPMNRSTUVWXY]',
6452                fourthChar = '[ABEHMNPRVWXY]',
6453                fifthChar  = '[ABDEFGHJLNPQRSTUWXYZ]',
6454                regexps    = [
6455                    // AN NAA, ANN NAA, AAN NAA, AANN NAA format
6456                    new RegExp('^(' + firstChar + '{1}' + secondChar + '?[0-9]{1,2})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
6457                    // ANA NAA
6458                    new RegExp('^(' + firstChar + '{1}[0-9]{1}' + thirdChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
6459                    // AANA NAA
6460                    new RegExp('^(' + firstChar + '{1}' + secondChar + '{1}?[0-9]{1}' + fourthChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
6461
6462                    new RegExp('^(BF1)(\\s*)([0-6]{1}[ABDEFGHJLNPQRST]{1}[ABDEFGHJLNPQRSTUWZYZ]{1})$', 'i'),        // BFPO postcodes
6463                    /^(GIR)(\s*)(0AA)$/i,                       // Special postcode GIR 0AA
6464                    /^(BFPO)(\s*)([0-9]{1,4})$/i,               // Standard BFPO numbers
6465                    /^(BFPO)(\s*)(c\/o\s*[0-9]{1,3})$/i,        // c/o BFPO numbers
6466                    /^([A-Z]{4})(\s*)(1ZZ)$/i,                  // Overseas Territories
6467                    /^(AI-2640)$/i                              // Anguilla
6468                ];
6469            for (var i = 0; i < regexps.length; i++) {
6470                if (regexps[i].test(value)) {
6471                    return true;
6472                }
6473            }
6474
6475            return false;
6476        }
6477    };
6478}(window.jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.