PageSourceSearch

https://www.milifestylemarketing.com/js/validate.js

js milifestylemarketing.com collected 2026-10-04 01:22:37 UTC 45,550 bytes, 1,217 lines download raw bytes

vendor: 45,550 bytes, lines 1-1217
1(function(exports, module, define) {
2    "use strict";
3
4
5    var validate = function(attributes, constraints, options) {
6        options = v.extend({}, v.options, options);
7
8        var results = v.runValidations(attributes, constraints, options),
9            attr, validator;
10
11        if (results.some(function(r) { return v.isPromise(r.error); })) {
12            throw new Error("Use validate.async if you want support for promises");
13        }
14        return validate.processValidationResults(results, options);
15    };
16
17    var v = validate;
18
19    // Copies over attributes from one or more sources to a single destination.
20    // Very much similar to underscore's extend.
21    // The first argument is the target object and the remaining arguments will be
22    // used as sources.
23    v.extend = function(obj) {
24        [].slice.call(arguments, 1).forEach(function(source) {
25            for (var attr in source) {
26                obj[attr] = source[attr];
27            }
28        });
29        return obj;
30    };
31
32    v.extend(validate, {
33        // This is the version of the library as a semver.
34        // The toString function will allow it to be coerced into a string
35        version: {
36            major: 0,
37            minor: 13,
38            patch: 1,
39            metadata: "development",
40            toString: function() {
41                var version = v.format("%{major}.%{minor}.%{patch}", v.version);
42                if (!v.isEmpty(v.version.metadata)) {
43                    version += "+" + v.version.metadata;
44                }
45                return version;
46            }
47        },
48
49        // Below is the dependencies that are used in validate.js
50
51        // The constructor of the Promise implementation.
52        // If you are using Q.js, RSVP or any other A+ compatible implementation
53        // override this attribute to be the constructor of that promise.
54        // Since jQuery promises aren't A+ compatible they won't work.
55        Promise: typeof Promise !== "undefined" ? Promise : /* istanbul ignore next */ null,
56
57        EMPTY_STRING_REGEXP: /^\s*$/,
58
59        // Runs the validators specified by the constraints object.
60        // Will return an array of the format:
61        //     [{attribute: "<attribute name>", error: "<validation result>"}, ...]
62        runValidations: function(attributes, constraints, options) {
63            var results = [],
64                attr, validatorName, value, validators, validator, validatorOptions, error;
65
66            if (v.isDomElement(attributes) || v.isJqueryElement(attributes)) {
67                attributes = v.collectFormValues(attributes);
68            }
69
70            // Loops through each constraints, finds the correct validator and run it.
71            for (attr in constraints) {
72                value = v.getDeepObjectValue(attributes, attr);
73                // This allows the constraints for an attribute to be a function.
74                // The function will be called with the value, attribute name, the complete dict of
75                // attributes as well as the options and constraints passed in.
76                // This is useful when you want to have different
77                // validations depending on the attribute value.
78                validators = v.result(constraints[attr], value, attributes, attr, options, constraints);
79
80                for (validatorName in validators) {
81                    validator = v.validators[validatorName];
82
83                    if (!validator) {
84                        error = v.format("Unknown validator %{name}", { name: validatorName });
85                        throw new Error(error);
86                    }
87
88                    validatorOptions = validators[validatorName];
89                    // This allows the options to be a function. The function will be
90                    // called with the value, attribute name, the complete dict of
91                    // attributes as well as the options and constraints passed in.
92                    // This is useful when you want to have different
93                    // validations depending on the attribute value.
94                    validatorOptions = v.result(validatorOptions, value, attributes, attr, options, constraints);
95                    if (!validatorOptions) {
96                        continue;
97                    }
98                    results.push({
99                        attribute: attr,
100                        value: value,
101                        validator: validatorName,
102                        globalOptions: options,
103                        attributes: attributes,
104                        options: validatorOptions,
105                        error: validator.call(validator,
106                            value,
107                            validatorOptions,
108                            attr,
109                            attributes,
110                            options)
111                    });
112                }
113            }
114
115            return results;
116        },
117
118        // Takes the output from runValidations and converts it to the correct
119        // output format.
120        processValidationResults: function(errors, options) {
121            errors = v.pruneEmptyErrors(errors, options);
122            errors = v.expandMultipleErrors(errors, options);
123            errors = v.convertErrorMessages(errors, options);
124
125            var format = options.format || "grouped";
126
127            if (typeof v.formatters[format] === 'function') {
128                errors = v.formatters[format](errors);
129            } else {
130                throw new Error(v.format("Unknown format %{format}", options));
131            }
132
133            return v.isEmpty(errors) ? undefined : errors;
134        },
135
136        // Runs the validations with support for promises.
137        // This function will return a promise that is settled when all the
138        // validation promises have been completed.
139        // It can be called even if no validations returned a promise.
140        async: function(attributes, constraints, options) {
141            options = v.extend({}, v.async.options, options);
142
143            var WrapErrors = options.wrapErrors || function(errors) {
144                return errors;
145            };
146
147            // Removes unknown attributes
148            if (options.cleanAttributes !== false) {
149                attributes = v.cleanAttributes(attributes, constraints);
150            }
151
152            var results = v.runValidations(attributes, constraints, options);
153
154            return new v.Promise(function(resolve, reject) {
155                v.waitForResults(results).then(function() {
156                    var errors = v.processValidationResults(results, options);
157                    if (errors) {
158                        reject(new WrapErrors(errors, options, attributes, constraints));
159                    } else {
160                        resolve(attributes);
161                    }
162                }, function(err) {
163                    reject(err);
164                });
165            });
166        },
167
168        single: function(value, constraints, options) {
169            options = v.extend({}, v.single.options, options, {
170                format: "flat",
171                fullMessages: false
172            });
173            return v({ single: value }, { single: constraints }, options);
174        },
175
176        // Returns a promise that is resolved when all promises in the results array
177        // are settled. The promise returned from this function is always resolved,
178        // never rejected.
179        // This function modifies the input argument, it replaces the promises
180        // with the value returned from the promise.
181        waitForResults: function(results) {
182            // Create a sequence of all the results starting with a resolved promise.
183            return results.reduce(function(memo, result) {
184                // If this result isn't a promise skip it in the sequence.
185                if (!v.isPromise(result.error)) {
186                    return memo;
187                }
188
189                return memo.then(function() {
190                    return result.error.then(function(error) {
191                        result.error = error || null;
192                    });
193                });
194            }, new v.Promise(function(r) { r(); })); // A resolved promise
195        },
196
197        // If the given argument is a call: function the and: function return the value
198        // otherwise just return the value. Additional arguments will be passed as
199        // arguments to the function.
200        // Example:
201        // ```
202        // result('foo') // 'foo'
203        // result(Math.max, 1, 2) // 2
204        // ```
205        result: function(value) {
206            var args = [].slice.call(arguments, 1);
207            if (typeof value === 'function') {
208                value = value.apply(null, args);
209            }
210            return value;
211        },
212
213        // Checks if the value is a number. This function does not consider NaN a
214        // number like many other `isNumber` functions do.
215        isNumber: function(value) {
216            return typeof value === 'number' && !isNaN(value);
217        },
218
219        // Returns false if the object is not a function
220        isFunction: function(value) {
221            return typeof value === 'function';
222        },
223
224        // A simple check to verify that the value is an integer. Uses `isNumber`
225        // and a simple modulo check.
226        isInteger: function(value) {
227            return v.isNumber(value) && value % 1 === 0;
228        },
229
230        // Checks if the value is a boolean
231        isBoolean: function(value) {
232            return typeof value === 'boolean';
233        },
234
235        // Uses the `Object` function to check if the given argument is an object.
236        isObject: function(obj) {
237            return obj === Object(obj);
238        },
239
240        // Simply checks if the object is an instance of a date
241        isDate: function(obj) {
242            return obj instanceof Date;
243        },
244
245        // Returns false if the object is `null` of `undefined`
246        isDefined: function(obj) {
247            return obj !== null && obj !== undefined;
248        },
249
250        // Checks if the given argument is a promise. Anything with a `then`
251        // function is considered a promise.
252        isPromise: function(p) {
253            return !!p && v.isFunction(p.then);
254        },
255
256        isJqueryElement: function(o) {
257            return o && v.isString(o.jquery);
258        },
259
260        isDomElement: function(o) {
261            if (!o) {
262                return false;
263            }
264
265            if (!o.querySelectorAll || !o.querySelector) {
266                return false;
267            }
268
269            if (v.isObject(document) && o === document) {
270                return true;
271            }
272
273
274            /* istanbul ignore else */
275            if (typeof HTMLElement === "object") {
276                return o instanceof HTMLElement;
277            } else {
278                return o &&
279                    typeof o === "object" &&
280                    o !== null &&
281                    o.nodeType === 1 &&
282                    typeof o.nodeName === "string";
283            }
284        },
285
286        isEmpty: function(value) {
287            var attr;
288
289            // Null and undefined are empty
290            if (!v.isDefined(value)) {
291                return true;
292            }
293
294            // functions are non empty
295            if (v.isFunction(value)) {
296                return false;
297            }
298
299            // Whitespace only strings are empty
300            if (v.isString(value)) {
301                return v.EMPTY_STRING_REGEXP.test(value);
302            }
303
304            // For arrays we use the length property
305            if (v.isArray(value)) {
306                return value.length === 0;
307            }
308
309            // Dates have no attributes but aren't empty
310            if (v.isDate(value)) {
311                return false;
312            }
313
314            // If we find at least one property we consider it non empty
315            if (v.isObject(value)) {
316                for (attr in value) {
317                    return false;
318                }
319                return true;
320            }
321
322            return false;
323        },
324
325        // Formats the specified strings with the given values like so:
326        // ```
327        // format("Foo: %{foo}", {foo: "bar"}) // "Foo bar"
328        // ```
329        // If you want to write %{...} without having it replaced simply
330        // prefix it with % like this `Foo: %%{foo}` and it will be returned
331        // as `"Foo: %{foo}"`
332        format: v.extend(function(str, vals) {
333            if (!v.isString(str)) {
334                return str;
335            }
336            return str.replace(v.format.FORMAT_REGEXP, function(m0, m1, m2) {
337                if (m1 === '%') {
338                    return "%{" + m2 + "}";
339                } else {
340                    return String(vals[m2]);
341                }
342            });
343        }, {
344            // Finds %{key} style patterns in the given string
345            FORMAT_REGEXP: /(%?)%\{([^\}]+)\}/g
346        }),
347
348        // "Prettifies" the given string.
349        // Prettifying means replacing [.\_-] with spaces as well as splitting
350        // camel case words.
351        prettify: function(str) {
352            if (v.isNumber(str)) {
353                // If there are more than 2 decimals round it to two
354                if ((str * 100) % 1 === 0) {
355                    return "" + str;
356                } else {
357                    return parseFloat(Math.round(str * 100) / 100).toFixed(2);
358                }
359            }
360
361            if (v.isArray(str)) {
362                return str.map(function(s) { return v.prettify(s); }).join(", ");
363            }
364
365            if (v.isObject(str)) {
366                if (!v.isDefined(str.toString)) {
367                    return JSON.stringify(str);
368                }
369
370                return str.toString();
371            }
372
373            // Ensure the string is actually a string
374            str = "" + str;
375
376            return str
377                // Splits keys separated by periods
378                .replace(/([^\s])\.([^\s])/g, '$1 $2')
379                // Removes backslashes
380                .replace(/\\+/g, '')
381                // Replaces - and - with space
382                .replace(/[_-]/g, ' ')
383                // Splits camel cased words
384                .replace(/([a-z])([A-Z])/g, function(m0, m1, m2) {
385                    return "" + m1 + " " + m2.toLowerCase();
386                })
387                .toLowerCase();
388        },
389
390        stringifyValue: function(value, options) {
391            var prettify = options && options.prettify || v.prettify;
392            return prettify(value);
393        },
394
395        isString: function(value) {
396            return typeof value === 'string';
397        },
398
399        isArray: function(value) {
400            return {}.toString.call(value) === '[object Array]';
401        },
402
403        // Checks if the object is a hash, which is equivalent to an object that
404        // is neither an array nor a function.
405        isHash: function(value) {
406            return v.isObject(value) && !v.isArray(value) && !v.isFunction(value);
407        },
408
409        contains: function(obj, value) {
410            if (!v.isDefined(obj)) {
411                return false;
412            }
413            if (v.isArray(obj)) {
414                return obj.indexOf(value) !== -1;
415            }
416            return value in obj;
417        },
418
419        unique: function(array) {
420            if (!v.isArray(array)) {
421                return array;
422            }
423            return array.filter(function(el, index, array) {
424                return array.indexOf(el) == index;
425            });
426        },
427
428        forEachKeyInKeypath: function(object, keypath, callback) {
429            if (!v.isString(keypath)) {
430                return undefined;
431            }
432
433            var key = "",
434                i, escape = false;
435
436            for (i = 0; i < keypath.length; ++i) {
437                switch (keypath[i]) {
438                    case '.':
439                        if (escape) {
440                            escape = false;
441                            key += '.';
442                        } else {
443                            object = callback(object, key, false);
444                            key = "";
445                        }
446                        break;
447
448                    case '\\':
449                        if (escape) {
450                            escape = false;
451                            key += '\\';
452                        } else {
453                            escape = true;
454                        }
455                        break;
456
457                    default:
458                        escape = false;
459                        key += keypath[i];
460                        break;
461                }
462            }
463
464            return callback(object, key, true);
465        },
466
467        getDeepObjectValue: function(obj, keypath) {
468            if (!v.isObject(obj)) {
469                return undefined;
470            }
471
472            return v.forEachKeyInKeypath(obj, keypath, function(obj, key) {
473                if (v.isObject(obj)) {
474                    return obj[key];
475                }
476            });
477        },
478
479        // This returns an object with all the values of the form.
480        // It uses the input name as key and the value as value
481        // So for example this:
482        // <input type="text" name="email" value="[email protected]" />
483        // would return:
484        // {email: "[email protected]"}
485        collectFormValues: function(form, options) {
486            var values = {},
487                i, j, input, inputs, option, value;
488
489            if (v.isJqueryElement(form)) {
490                form = form[0];
491            }
492
493            if (!form) {
494                return values;
495            }
496
497            options = options || {};
498
499            inputs = form.querySelectorAll("input[name], textarea[name]");
500            for (i = 0; i < inputs.length; ++i) {
501                input = inputs.item(i);
502
503                if (v.isDefined(input.getAttribute("data-ignored"))) {
504                    continue;
505                }
506
507                var name = input.name.replace(/\./g, "\\\\.");
508                value = v.sanitizeFormValue(input.value, options);
509                if (input.type === "number") {
510                    value = value ? +value : null;
511                } else if (input.type === "checkbox") {
512                    if (input.attributes.value) {
513                        if (!input.checked) {
514                            value = values[name] || null;
515                        }
516                    } else {
517                        value = input.checked;
518                    }
519                } else if (input.type === "radio") {
520                    if (!input.checked) {
521                        value = values[name] || null;
522                    }
523                }
524                values[name] = value;
525            }
526
527            inputs = form.querySelectorAll("select[name]");
528            for (i = 0; i < inputs.length; ++i) {
529                input = inputs.item(i);
530                if (v.isDefined(input.getAttribute("data-ignored"))) {
531                    continue;
532                }
533
534                if (input.multiple) {
535                    value = [];
536                    for (j in input.options) {
537                        option = input.options[j];
538                        if (option && option.selected) {
539                            value.push(v.sanitizeFormValue(option.value, options));
540                        }
541                    }
542                } else {
543                    var _val = typeof input.options[input.selectedIndex] !== 'undefined' ? input.options[input.selectedIndex].value : /* istanbul ignore next */ '';
544                    value = v.sanitizeFormValue(_val, options);
545                }
546                values[input.name] = value;
547            }
548
549            return values;
550        },
551
552        sanitizeFormValue: function(value, options) {
553            if (options.trim && v.isString(value)) {
554                value = value.trim();
555            }
556
557            if (options.nullify !== false && value === "") {
558                return null;
559            }
560            return value;
561        },
562
563        capitalize: function(str) {
564            if (!v.isString(str)) {
565                return str;
566            }
567            return str[0].toUpperCase() + str.slice(1);
568        },
569
570        // Remove all errors who's error attribute is empty (null or undefined)
571        pruneEmptyErrors: function(errors) {
572            return errors.filter(function(error) {
573                return !v.isEmpty(error.error);
574            });
575        },
576
577        // In
578        // [{error: ["err1", "err2"], ...}]
579        // Out
580        // [{error: "err1", ...}, {error: "err2", ...}]
581        //
582        // All attributes in an error with multiple messages are duplicated
583        // when expanding the errors.
584        expandMultipleErrors: function(errors) {
585            var ret = [];
586            errors.forEach(function(error) {
587                // Removes errors without a message
588                if (v.isArray(error.error)) {
589                    error.error.forEach(function(msg) {
590                        ret.push(v.extend({}, error, { error: msg }));
591                    });
592                } else {
593                    ret.push(error);
594                }
595            });
596            return ret;
597        },
598
599        // Converts the error mesages by prepending the attribute name unless the
600        // message is prefixed by ^
601        convertErrorMessages: function(errors, options) {
602            options = options || {};
603
604            var ret = [],
605                prettify = options.prettify || v.prettify;
606            errors.forEach(function(errorInfo) {
607                var error = v.result(errorInfo.error,
608                    errorInfo.value,
609                    errorInfo.attribute,
610                    errorInfo.options,
611                    errorInfo.attributes,
612                    errorInfo.globalOptions);
613
614                if (!v.isString(error)) {
615                    ret.push(errorInfo);
616                    return;
617                }
618
619                if (error[0] === '^') {
620                    error = error.slice(1);
621                } else if (options.fullMessages !== false) {
622                    error = v.capitalize(prettify(errorInfo.attribute)) + " " + error;
623                }
624                error = error.replace(/\\\^/g, "^");
625                error = v.format(error, {
626                    value: v.stringifyValue(errorInfo.value, options)
627                });
628                ret.push(v.extend({}, errorInfo, { error: error }));
629            });
630            return ret;
631        },
632
633        // In:
634        // [{attribute: "<attributeName>", ...}]
635        // Out:
636        // {"<attributeName>": [{attribute: "<attributeName>", ...}]}
637        groupErrorsByAttribute: function(errors) {
638            var ret = {};
639            errors.forEach(function(error) {
640                var list = ret[error.attribute];
641                if (list) {
642                    list.push(error);
643                } else {
644                    ret[error.attribute] = [error];
645                }
646            });
647            return ret;
648        },
649
650        // In:
651        // [{error: "<message 1>", ...}, {error: "<message 2>", ...}]
652        // Out:
653        // ["<message 1>", "<message 2>"]
654        flattenErrorsToArray: function(errors) {
655            return errors
656                .map(function(error) { return error.error; })
657                .filter(function(value, index, self) {
658                    return self.indexOf(value) === index;
659                });
660        },
661
662        cleanAttributes: function(attributes, whitelist) {
663            function whitelistCreator(obj, key, last) {
664                if (v.isObject(obj[key])) {
665                    return obj[key];
666                }
667                return (obj[key] = last ? true : {});
668            }
669
670            function buildObjectWhitelist(whitelist) {
671                var ow = {},
672                    lastObject, attr;
673                for (attr in whitelist) {
674                    if (!whitelist[attr]) {
675                        continue;
676                    }
677                    v.forEachKeyInKeypath(ow, attr, whitelistCreator);
678                }
679                return ow;
680            }
681
682            function cleanRecursive(attributes, whitelist) {
683                if (!v.isObject(attributes)) {
684                    return attributes;
685                }
686
687                var ret = v.extend({}, attributes),
688                    w, attribute;
689
690                for (attribute in attributes) {
691                    w = whitelist[attribute];
692
693                    if (v.isObject(w)) {
694                        ret[attribute] = cleanRecursive(ret[attribute], w);
695                    } else if (!w) {
696                        delete ret[attribute];
697                    }
698                }
699                return ret;
700            }
701
702            if (!v.isObject(whitelist) || !v.isObject(attributes)) {
703                return {};
704            }
705
706            whitelist = buildObjectWhitelist(whitelist);
707            return cleanRecursive(attributes, whitelist);
708        },
709
710        exposeModule: function(validate, root, exports, module, define) {
711            if (exports) {
712                if (module && module.exports) {
713                    exports = module.exports = validate;
714                }
715                exports.validate = validate;
716            } else {
717                root.validate = validate;
718                if (validate.isFunction(define) && define.amd) {
719                    define([], function() { return validate; });
720                }
721            }
722        },
723
724        warn: function(msg) {
725            if (typeof console !== "undefined" && console.warn) {
726                console.warn("[validate.js] " + msg);
727            }
728        },
729
730        error: function(msg) {
731            if (typeof console !== "undefined" && console.error) {
732                console.error("[validate.js] " + msg);
733            }
734        }
735    });
736
737    validate.validators = {
738        // Presence validates that the value isn't empty
739        presence: function(value, options) {
740            options = v.extend({}, this.options, options);
741            if (options.allowEmpty !== false ? !v.isDefined(value) : v.isEmpty(value)) {
742                return options.message || this.message || "can't be blank";
743            }
744        },
745        length: function(value, options, attribute) {
746            // Empty values are allowed
747            if (!v.isDefined(value)) {
748                return;
749            }
750
751            options = v.extend({}, this.options, options);
752
753            var is = options.is,
754                maximum = options.maximum,
755                minimum = options.minimum,
756                tokenizer = options.tokenizer || function(val) { return val; },
757                err, errors = [];
758
759            value = tokenizer(value);
760            var length = value.length;
761            if (!v.isNumber(length)) {
762                return options.message || this.notValid || "has an incorrect length";
763            }
764
765            // Is checks
766            if (v.isNumber(is) && length !== is) {
767                err = options.wrongLength ||
768                    this.wrongLength ||
769                    "is the wrong length (should be %{count} characters)";
770                errors.push(v.format(err, { count: is }));
771            }
772
773            if (v.isNumber(minimum) && length < minimum) {
774                err = options.tooShort ||
775                    this.tooShort ||
776                    "is too short (minimum is %{count} characters)";
777                errors.push(v.format(err, { count: minimum }));
778            }
779
780            if (v.isNumber(maximum) && length > maximum) {
781                err = options.tooLong ||
782                    this.tooLong ||
783                    "is too long (maximum is %{count} characters)";
784                errors.push(v.format(err, { count: maximum }));
785            }
786
787            if (errors.length > 0) {
788                return options.message || errors;
789            }
790        },
791        numericality: function(value, options, attribute, attributes, globalOptions) {
792            // Empty values are fine
793            if (!v.isDefined(value)) {
794                return;
795            }
796
797            options = v.extend({}, this.options, options);
798
799            var errors = [],
800                name, count, checks = {
801                    greaterThan: function(v, c) { return v > c; },
802                    greaterThanOrEqualTo: function(v, c) { return v >= c; },
803                    equalTo: function(v, c) { return v === c; },
804                    lessThan: function(v, c) { return v < c; },
805                    lessThanOrEqualTo: function(v, c) { return v <= c; },
806                    divisibleBy: function(v, c) { return v % c === 0; }
807                },
808                prettify = options.prettify ||
809                (globalOptions && globalOptions.prettify) ||
810                v.prettify;
811
812            // Strict will check that it is a valid looking number
813            if (v.isString(value) && options.strict) {
814                var pattern = "^-?(0|[1-9]\\d*)";
815                if (!options.onlyInteger) {
816                    pattern += "(\\.\\d+)?";
817                }
818                pattern += "$";
819
820                if (!(new RegExp(pattern).test(value))) {
821                    return options.message ||
822                        options.notValid ||
823                        this.notValid ||
824                        this.message ||
825                        "must be a valid number";
826                }
827            }
828
829            // Coerce the value to a number unless we're being strict.
830            if (options.noStrings !== true && v.isString(value) && !v.isEmpty(value)) {
831                value = +value;
832            }
833
834            // If it's not a number we shouldn't continue since it will compare it.
835            if (!v.isNumber(value)) {
836                return options.message ||
837                    options.notValid ||
838                    this.notValid ||
839                    this.message ||
840                    "is not a number";
841            }
842
843            // Same logic as above, sort of. Don't bother with comparisons if this
844            // doesn't pass.
845            if (options.onlyInteger && !v.isInteger(value)) {
846                return options.message ||
847                    options.notInteger ||
848                    this.notInteger ||
849                    this.message ||
850                    "must be an integer";
851            }
852
853            for (name in checks) {
854                count = options[name];
855                if (v.isNumber(count) && !checks[name](value, count)) {
856                    // This picks the default message if specified
857                    // For example the greaterThan check uses the message from
858                    // this.notGreaterThan so we capitalize the name and prepend "not"
859                    var key = "not" + v.capitalize(name);
860                    var msg = options[key] ||
861                        this[key] ||
862                        this.message ||
863                        "must be %{type} %{count}";
864
865                    errors.push(v.format(msg, {
866                        count: count,
867                        type: prettify(name)
868                    }));
869                }
870            }
871
872            if (options.odd && value % 2 !== 1) {
873                errors.push(options.notOdd ||
874                    this.notOdd ||
875                    this.message ||
876                    "must be odd");
877            }
878            if (options.even && value % 2 !== 0) {
879                errors.push(options.notEven ||
880                    this.notEven ||
881                    this.message ||
882                    "must be even");
883            }
884
885            if (errors.length) {
886                return options.message || errors;
887            }
888        },
889        datetime: v.extend(function(value, options) {
890            if (!v.isFunction(this.parse) || !v.isFunction(this.format)) {
891                throw new Error("Both the parse and format functions needs to be set to use the datetime/date validator");
892            }
893
894            // Empty values are fine
895            if (!v.isDefined(value)) {
896                return;
897            }
898
899            options = v.extend({}, this.options, options);
900
901            var err, errors = [],
902                earliest = options.earliest ? this.parse(options.earliest, options) : NaN,
903                latest = options.latest ? this.parse(options.latest, options) : NaN;
904
905            value = this.parse(value, options);
906
907            // 86400000 is the number of milliseconds in a day, this is used to remove
908            // the time from the date
909            if (isNaN(value) || options.dateOnly && value % 86400000 !== 0) {
910                err = options.notValid ||
911                    options.message ||
912                    this.notValid ||
913                    "must be a valid date";
914                return v.format(err, { value: arguments[0] });
915            }
916
917            if (!isNaN(earliest) && value < earliest) {
918                err = options.tooEarly ||
919                    options.message ||
920                    this.tooEarly ||
921                    "must be no earlier than %{date}";
922                err = v.format(err, {
923                    value: this.format(value, options),
924                    date: this.format(earliest, options)
925                });
926                errors.push(err);
927            }
928
929            if (!isNaN(latest) && value > latest) {
930                err = options.tooLate ||
931                    options.message ||
932                    this.tooLate ||
933                    "must be no later than %{date}";
934                err = v.format(err, {
935                    date: this.format(latest, options),
936                    value: this.format(value, options)
937                });
938                errors.push(err);
939            }
940
941            if (errors.length) {
942                return v.unique(errors);
943            }
944        }, {
945            parse: null,
946            format: null
947        }),
948        date: function(value, options) {
949            options = v.extend({}, options, { dateOnly: true });
950            return v.validators.datetime.call(v.validators.datetime, value, options);
951        },
952        format: function(value, options) {
953            if (v.isString(options) || (options instanceof RegExp)) {
954                options = { pattern: options };
955            }
956
957            options = v.extend({}, this.options, options);
958
959            var message = options.message || this.message || "is invalid",
960                pattern = options.pattern,
961                match;
962
963            // Empty values are allowed
964            if (!v.isDefined(value)) {
965                return;
966            }
967            if (!v.isString(value)) {
968                return message;
969            }
970
971            if (v.isString(pattern)) {
972                pattern = new RegExp(options.pattern, options.flags);
973            }
974            match = pattern.exec(value);
975            if (!match || match[0].length != value.length) {
976                return message;
977            }
978        },
979        inclusion: function(value, options) {
980            // Empty values are fine
981            if (!v.isDefined(value)) {
982                return;
983            }
984            if (v.isArray(options)) {
985                options = { within: options };
986            }
987            options = v.extend({}, this.options, options);
988            if (v.contains(options.within, value)) {
989                return;
990            }
991            var message = options.message ||
992                this.message ||
993                "^%{value} is not included in the list";
994            return v.format(message, { value: value });
995        },
996        exclusion: function(value, options) {
997            // Empty values are fine
998            if (!v.isDefined(value)) {
999                return;
1000            }
1001            if (v.isArray(options)) {
1002                options = { within: options };
1003            }
1004            options = v.extend({}, this.options, options);
1005            if (!v.contains(options.within, value)) {
1006                return;
1007            }
1008            var message = options.message || this.message || "^%{value} is restricted";
1009            if (v.isString(options.within[value])) {
1010                value = options.within[value];
1011            }
1012            return v.format(message, { value: value });
1013        },
1014        email: v.extend(function(value, options) {
1015            options = v.extend({}, this.options, options);
1016            var message = options.message || this.message || "is not a valid email";
1017            // Empty values are fine
1018            if (!v.isDefined(value)) {
1019                return;
1020            }
1021            if (!v.isString(value)) {
1022                return message;
1023            }
1024            if (!this.PATTERN.exec(value)) {
1025                return message;
1026            }
1027        }, {
1028            PATTERN: /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?: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]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i
1029        }),
1030        equality: function(value, options, attribute, attributes, globalOptions) {
1031            if (!v.isDefined(value)) {
1032                return;
1033            }
1034
1035            if (v.isString(options)) {
1036                options = { attribute: options };
1037            }
1038            options = v.extend({}, this.options, options);
1039            var message = options.message ||
1040                this.message ||
1041                "is not equal to %{attribute}";
1042
1043            if (v.isEmpty(options.attribute) || !v.isString(options.attribute)) {
1044                throw new Error("The attribute must be a non empty string");
1045            }
1046
1047            var otherValue = v.getDeepObjectValue(attributes, options.attribute),
1048                comparator = options.comparator || function(v1, v2) {
1049                    return v1 === v2;
1050                },
1051                prettify = options.prettify ||
1052                (globalOptions && globalOptions.prettify) ||
1053                v.prettify;
1054
1055            if (!comparator(value, otherValue, options, attribute, attributes)) {
1056                return v.format(message, { attribute: prettify(options.attribute) });
1057            }
1058        },
1059        // A URL validator that is used to validate URLs with the ability to
1060        // restrict schemes and some domains.
1061        url: function(value, options) {
1062            if (!v.isDefined(value)) {
1063                return;
1064            }
1065
1066            options = v.extend({}, this.options, options);
1067
1068            var message = options.message || this.message || "is not a valid url",
1069                schemes = options.schemes || this.schemes || ['http', 'https'],
1070                allowLocal = options.allowLocal || this.allowLocal || false,
1071                allowDataUrl = options.allowDataUrl || this.allowDataUrl || false;
1072            if (!v.isString(value)) {
1073                return message;
1074            }
1075
1076
1077            var regex =
1078                "^" +
1079                // protocol identifier
1080                "(?:(?:" + schemes.join("|") + ")://)" +
1081                // user:pass authentication
1082                "(?:\\S+(?::\\S*)?@)?" +
1083                "(?:";
1084
1085            var tld = "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))";
1086
1087            if (allowLocal) {
1088                tld += "?";
1089            } else {
1090                regex +=
1091                    // IP address exclusion
1092                    // private & local networks
1093                    "(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
1094                    "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
1095                    "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})";
1096            }
1097
1098            regex +=
1099                // IP address dotted notation octets
1100                // excludes loopback network 0.0.0.0
1101                // excludes reserved space >= 224.0.0.0
1102                // excludes network & broacast addresses
1103                // (first & last IP address of each class)
1104                "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
1105                "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
1106                "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
1107                "|" +
1108                // host name
1109                "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
1110                // domain name
1111                "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
1112                tld +
1113                ")" +
1114                // port number
1115                "(?::\\d{2,5})?" +
1116                // resource path
1117                "(?:[/?#]\\S*)?" +
1118                "$";
1119
1120            if (allowDataUrl) {
1121                // RFC 2397
1122                var mediaType = "\\w+\\/[-+.\\w]+(?:;[\\w=]+)*";
1123                var urlchar = "[A-Za-z0-9-_.!~\\*'();\\/?:@&=+$,%]*";
1124                var dataurl = "data:(?:" + mediaType + ")?(?:;base64)?," + urlchar;
1125                regex = "(?:" + regex + ")|(?:^" + dataurl + "$)";
1126            }
1127
1128            var PATTERN = new RegExp(regex, 'i');
1129            if (!PATTERN.exec(value)) {
1130                return message;
1131            }
1132        },
1133        type: v.extend(function(value, originalOptions, attribute, attributes, globalOptions) {
1134            if (v.isString(originalOptions)) {
1135                originalOptions = { type: originalOptions };
1136            }
1137
1138            if (!v.isDefined(value)) {
1139                return;
1140            }
1141
1142            var options = v.extend({}, this.options, originalOptions);
1143
1144            var type = options.type;
1145            if (!v.isDefined(type)) {
1146                throw new Error("No type was specified");
1147            }
1148
1149            var check;
1150            if (v.isFunction(type)) {
1151                check = type;
1152            } else {
1153                check = this.types[type];
1154            }
1155
1156            if (!v.isFunction(check)) {
1157                throw new Error("validate.validators.type.types." + type + " must be a function.");
1158            }
1159
1160            if (!check(value, options, attribute, attributes, globalOptions)) {
1161                var message = originalOptions.message ||
1162                    this.messages[type] ||
1163                    this.message ||
1164                    options.message ||
1165                    (v.isFunction(type) ? "must be of the correct type" : "must be of type %{type}");
1166
1167                if (v.isFunction(message)) {
1168                    message = message(value, originalOptions, attribute, attributes, globalOptions);
1169                }
1170
1171                return v.format(message, { attribute: v.prettify(attribute), type: type });
1172            }
1173        }, {
1174            types: {
1175                object: function(value) {
1176                    return v.isObject(value) && !v.isArray(value);
1177                },
1178                array: v.isArray,
1179                integer: v.isInteger,
1180                number: v.isNumber,
1181                string: v.isString,
1182                date: v.isDate,
1183                boolean: v.isBoolean
1184            },
1185            messages: {}
1186        })
1187    };
1188
1189    validate.formatters = {
1190        detailed: function(errors) { return errors; },
1191        flat: v.flattenErrorsToArray,
1192        grouped: function(errors) {
1193            var attr;
1194
1195            errors = v.groupErrorsByAttribute(errors);
1196            for (attr in errors) {
1197                errors[attr] = v.flattenErrorsToArray(errors[attr]);
1198            }
1199            return errors;
1200        },
1201        constraint: function(errors) {
1202            var attr;
1203            errors = v.groupErrorsByAttribute(errors);
1204            for (attr in errors) {
1205                errors[attr] = errors[attr].map(function(result) {
1206                    return result.validator;
1207                }).sort();
1208            }
1209            return errors;
1210        }
1211    };
1212
1213    validate.exposeModule(validate, this, exports, module, define);
1214}).call(this,
1215    typeof exports !== 'undefined' ? /* istanbul ignore next */ exports : null,
1216    typeof module !== 'undefined' ? /* istanbul ignore next */ module : null,
1217    typeof define !== 'undefined' ? /* istanbul ignore next */ define : null);

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.