diff --git a/CHANGELOG.md b/CHANGELOG.md index 01475ad7d..c1f36980e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,58 @@ #### HEAD +- Added a German locale to `isMobilePhone()`, `isAlpha()` and `isAlphanumeric()` + ([#477](https://github.com/chriso/validator.js/pull/477)) +- Print a deprecation warning if validator input is not a string + ([1f67e1e](https://github.com/chriso/validator.js/commit/1f67e1e15198c0ae735151290dc8dc2bf14da254)) + +#### 4.6.1 + +- Fix coercion of objects: `Object.toString()` is `[object Object]` not `""` + ([a57f3c8](https://github.com/chriso/validator.js/commit/a57f3c843c715fba2664ee22ec80e9e28e88e0a6)) + +#### 4.6.0 + +- Added a Spanish locale to `isMobilePhone()` + ([#481](https://github.com/chriso/validator.js/pull/481)) +- Fix string coercion of objects created with `Object.create(null)` + ([#484](https://github.com/chriso/validator.js/issues/484)) + +#### 4.5.2 + +- Fix a timezone issue with short-form ISO 8601 dates, e.g. + `validator.isDate('2011-12-21')` + ([#480](https://github.com/chriso/validator.js/issues/480)) + +#### 4.5.1 + +- Make `isLength()` / `isByteLength()` accept `{min, max}` as options object. + ([#474](https://github.com/chriso/validator.js/issues/474)) + +#### 4.5.0 + +- Add validation for Indian mobile phone numbers + ([#471](https://github.com/chriso/validator.js/pull/471)) +- Tweak Greek and Chinese mobile phone validation + ([#467](https://github.com/chriso/validator.js/pull/467), + [#468](https://github.com/chriso/validator.js/pull/468)) +- Fixed a bug in `isDate()` when validating ISO 8601 dates without a timezone + ([#472](https://github.com/chriso/validator.js/issues/472)) + +#### 4.4.1 + +- Allow triple hyphens in IDNA hostnames + ([#466](https://github.com/chriso/validator.js/issues/466)) + +#### 4.4.0 + +- Added `isMACAddress()` validator + ([#458](https://github.com/chriso/validator.js/pull/458)) +- Added `isWhitelisted()` validator + ([#462](https://github.com/chriso/validator.js/pull/462)) - Added a New Zealand locale to `isMobilePhone()` ([#452](https://github.com/chriso/validator.js/pull/452)) +- Added options to control GMail address normalization + ([#460](https://github.com/chriso/validator.js/pull/460)) #### 4.3.0 diff --git a/LICENSE b/LICENSE index e8710cf49..37a807cbc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 Chris O'Hara +Copyright (c) 2016 Chris O'Hara Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 820068bc2..4e618ee79 100644 --- a/README.md +++ b/README.md @@ -31,18 +31,28 @@ The library can also be installed through [bower][bower] $ bower install validator-js ``` +### Strings only + +**This library validates and sanitizes strings only**. + +All input is coerced to a string using the following rules: + +- Call the `toString` property if available. +- Replace `null`, `undefined`, `NaN` or items with `.length === 0` with an empty string. +- Everything else is coerced with `'' + input`. + ### Validators - **contains(str, seed)** - check if the string contains the seed. - **equals(str, comparison)** - check if the string matches the comparison. - **isAfter(str [, date])** - check if the string is a date that's after the specified date (defaults to now). -- **isAlpha(str)** - check if the string contains only letters (a-zA-Z). -- **isAlphanumeric(str)** - check if the string contains only letters and numbers. +- **isAlpha(str [, locale])** - check if the string contains only letters (a-zA-Z). Locale is one of `['en-US', 'de-DE']`) and defaults to `en-US`. +- **isAlphanumeric(str [, locale])** - check if the string contains only letters and numbers. Locale is one of `['en-US', 'de-DE']`) and defaults to `en-US`. - **isAscii(str)** - check if the string contains ASCII chars only. - **isBase64(str)** - check if a string is base64 encoded. - **isBefore(str [, date])** - check if the string is a date that's before the specified date. - **isBoolean(str)** - check if a string is a boolean. -- **isByteLength(str, min [, max])** - check if the string's length (in bytes) falls in a range. +- **isByteLength(str, options)** - check if the string's length (in bytes) falls in a range.`options` is an object which defaults to `{min:0, max: undefined}`. - **isCreditCard(str)** - check if the string is a credit card. - **isCurrency(str, options)** - check if the string is a valid currency amount. `options` is an object which defaults to `{symbol: '$', require_symbol: false, allow_space_after_symbol: false, symbol_after_digits: false, allow_negatives: true, parens_for_negatives: false, negative_sign_before_digits: false, negative_sign_after_digits: false, allow_negative_sign_placeholder: false, thousands_separator: ',', decimal_separator: '.', allow_space_after_digits: false }`. - **isDate(str)** - check if the string is a date. @@ -62,9 +72,10 @@ $ bower install validator-js - **isIn(str, values)** - check if the string is in a array of allowed values. - **isInt(str [, options])** - check if the string is an integer. `options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). - **isJSON(str)** - check if the string is valid JSON (note: uses JSON.parse). -- **isLength(str, min [, max])** - check if the string's length falls in a range. Note: this function takes into account surrogate pairs. +- **isLength(str, options)** - check if the string's length falls in a range. `options` is an object which defaults to `{min:0, max: undefined}`. Note: this function takes into account surrogate pairs. - **isLowercase(str)** - check if the string is lowercase. -- **isMobilePhone(str, locale)** - check if the string is a mobile phone number, (locale is one of `['zh-CN', 'zh-TW', 'en-ZA', 'en-AU', 'en-HK', 'pt-PT', 'fr-FR', 'el-GR', 'en-GB', 'en-US', 'en-ZM', 'ru-RU', 'nb-NO', 'nn-NO', 'vi-VN', 'en-NZ', 'fi-FI']`). +- **isMACAddress(str)** - check if the string is a MAC address. +- **isMobilePhone(str, locale)** - check if the string is a mobile phone number, (locale is one of `['zh-CN', 'zh-TW', 'en-ZA', 'en-AU', 'en-HK', 'pt-PT', 'fr-FR', 'el-GR', 'en-GB', 'en-US', 'en-ZM', 'ru-RU', 'nb-NO', 'nn-NO', 'vi-VN', 'en-NZ', 'en-IN', 'es-ES', 'de-DE', 'fi-FI']`). - **isMongoId(str)** - check if the string is a valid hex-encoded representation of a [MongoDB ObjectId][mongoid]. - **isMultibyte(str)** - check if the string contains one or more multibyte chars. - **isNull(str)** - check if the string is null. @@ -74,6 +85,7 @@ $ bower install validator-js - **isUUID(str [, version])** - check if the string is a UUID (version 3, 4 or 5). - **isUppercase(str)** - check if the string is uppercase. - **isVariableWidth(str)** - check if the string contains a mixture of full and half-width chars. +- **isWhitelisted(str, chars)** - checks characters if they appear in the whitelist. - **matches(str, pattern [, modifiers])** - check if string matches the pattern. Either `matches('foo', /foo/i)` or `matches('foo', 'foo', 'i')`. ### Sanitizers @@ -81,7 +93,7 @@ $ bower install validator-js - **blacklist(input, chars)** - remove characters that appear in the blacklist. The characters are used in a RegExp and so you will need to escape some chars, e.g. `blacklist(input, '\\[\\]')`. - **escape(input)** - replace `<`, `>`, `&`, `'`, `"` and `/` with HTML entities. - **ltrim(input [, chars])** - trim characters from the left-side of the input. -- **normalizeEmail(email [, options])** - canonicalize an email address. `options` is an object which defaults to `{ lowercase: true }`. With `lowercase` set to `true`, the local part of the email address is lowercased for all domains; the hostname is always lowercased and the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail). Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and are stripped of tags (e.g. `some.one+tag@gmail.com` becomes `someone@gmail.com`) and all `@googlemail.com` addresses are normalized to `@gmail.com`. +- **normalizeEmail(email [, options])** - canonicalize an email address. `options` is an object which defaults to `{ lowercase: true, remove_dots: true, remove_extension: true }`. With `lowercase` set to `true`, the local part of the email address is lowercased for all domains; the hostname is always lowercased and the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail). Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and are stripped of extensions (e.g. `some.one+extension@gmail.com` becomes `someone@gmail.com`) and all `@googlemail.com` addresses are normalized to `@gmail.com`. - **rtrim(input [, chars])** - trim characters from the right-side of the input. - **stripLow(input [, keep_new_lines])** - remove characters with a numerical value < 32 and 127, mostly control characters. If `keep_new_lines` is `true`, newline characters are preserved (`\n` and `\r`, hex `0xA` and `0xD`). Unicode-safe in JavaScript. - **toBoolean(input [, strict])** - convert the input to a boolean. Everything except for `'0'`, `'false'` and `''` returns `true`. In strict mode only `'1'` and `'true'` return `true`. @@ -98,14 +110,6 @@ XSS sanitization was removed from the library in [2d5d6999](https://github.com/c For an alternative, look at Yahoo's [xss-filters library](https://github.com/yahoo/xss-filters). -### Strings only - -This library validates and sanitizes **strings** only. All input will be coerced to a string using the following rules - -- Call the `toString` property if available. -- Replace `null`, `undefined` or `NaN` with an empty string. -- Everything else is coerced with `input + ''`. - ### Extensions You can add your own validators using `validator.extend(name, fn)` @@ -139,7 +143,7 @@ Tests require node v4.0+. ### License (MIT) ``` -Copyright (c) 2015 Chris O'Hara +Copyright (c) 2016 Chris O'Hara Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/package.json b/package.json index 52a4b401e..a1b62716e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "validator", "description": "String validation and sanitization", - "version": "4.3.0", + "version": "4.6.1", "homepage": "http://github.com/chriso/validator.js", "keywords": [ "validator", "validation", "validate", "sanitization", diff --git a/test/sanitizers.js b/test/sanitizers.js index e24c9f815..04d7020d2 100644 --- a/test/sanitizers.js +++ b/test/sanitizers.js @@ -198,7 +198,9 @@ describe('Sanitizers', function () { , 'an invalid email address': false , '': false , '+extension@gmail.com': false - // some.name.midd..leNa...me...+extension@GoogleMail.com was removed from test cases because of a bug with validator.isEmail. See issue #258 + , '...@gmail.com': false + , '.+extension@googlemail.com': false + , 'some.name.midd..leNa...me...+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' } }); test({ @@ -211,13 +213,27 @@ describe('Sanitizers', function () { , 'TEST@me.com': 'TEST@me.com' , 'TEST@ME.COM': 'TEST@me.com' , 'blAH@x.com': 'blAH@x.com' - + // Domains that are known for being case-insensitive are always lowercased , 'SOME.name@GMAIL.com': 'somename@gmail.com' , 'SOME.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' , 'SOME.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com' } }); + test({ + sanitizer: 'normalizeEmail' + , args: [{remove_dots: false}] + , expect: { + 'SOME.name@GMAIL.com': 'some.name@gmail.com' + } + }); + test({ + sanitizer: 'normalizeEmail' + , args: [{remove_extension: false}] + , expect: { + 'foo+bar@gmail.com': 'foo+bar@gmail.com' + } + }); }); }); diff --git a/test/validators.js b/test/validators.js index edd9784af..dccc33ca3 100644 --- a/test/validators.js +++ b/test/validators.js @@ -183,6 +183,7 @@ describe('Validators', function () { , 'http://foo--bar.com' , 'http://høyfjellet.no' , 'http://xn--j1aac5a4g.xn--j1amh' + , 'http://xn------eddceddeftq7bvv7c4ke4c.xn--p1ai' , 'http://кулік.укр' ] , invalid: [ @@ -397,6 +398,25 @@ describe('Validators', function () { }); }); + it('should validate MAC addresses', function () { + test({ + validator: 'isMACAddress', + valid: [ + 'ab:ab:ab:ab:ab:ab', + 'FF:FF:FF:FF:FF:FF', + '01:02:03:04:05:ab', + '01:AB:03:04:05:06' + ], + invalid: [ + 'abc', + '01:02:03:04:05', + '01:02:03:04::ab', + '1:2:3:4:5:6', + 'AB:CD:EF:GH:01:02' + ] + }); + }); + it('should validate IP addresses', function () { test({ validator: 'isIP' @@ -531,6 +551,28 @@ describe('Validators', function () { 'abc1' , ' foo ' , '' + , 'ÄBC' + , 'FÜübar' + , 'Jön' + , 'Heiß' + ] + }); + }); + + it('should validate german alpha strings', function () { + test({ + validator: 'isAlpha' + , args: ['de-DE'] + , valid: [ + 'äbc' + , 'ÄBC' + , 'FöÖbär' + , 'Heiß' + ] + , invalid: [ + 'äbc1' + , ' föö ' + , '' ] }); }); @@ -545,6 +587,24 @@ describe('Validators', function () { , invalid: [ 'abc ' , 'foo!!' + , 'ÄBC' + , 'FÜübar' + , 'Jön' + ] + }); + }); + + it('should validate german alphanumeric strings', function () { + test({ + validator: 'isAlphanumeric' + , args: ['de-DE'] + , valid: [ + 'äbc123' + , 'ÄBC11' + ] + , invalid: [ + 'äca ' + , 'föö!!' ] }); }); @@ -652,9 +712,43 @@ describe('Validators', function () { , '' ] }); - - test({ validator: 'isInt', args: [{ min: 10 }], valid: [15, 80, 99], invalid: [9, 6, 3.2, 'a'] } ); - test({ validator: 'isInt', args: [{ min: 10, max: 15 }], valid: [15, 11, 13], invalid: [9, 2, 17, 3.2, 33, 'a'] } ); + test({ + validator: 'isInt' + , args: [{ + min: 10 + }] + , valid: [ + '15' + , '80' + , '99' + ] + , invalid: [ + '9' + , '6' + , '3.2' + , 'a' + ] + }); + test({ + validator: 'isInt' + , args: [{ + min: 10 + , max: 15 + }] + , valid: [ + '15' + , '11' + , '13' + ] + , invalid: [ + '9' + , '2' + , '17' + , '3.2' + , '33' + , 'a' + ] + }); }); it('should validate floats', function () { @@ -680,9 +774,50 @@ describe('Validators', function () { , 'foo' ] }); - - test({ validator: 'isFloat', args: [{ min: 3.7 }], valid: [3.888, 3.92, 4.5, 50, 3.7, 3.71], invalid: [3.6, 3.69, 3, 1.5, 'a'] } ); - test({ validator: 'isFloat', args: [{ min: 0.1, max: 1.0 }], valid: [0.1, 1.0, 0.15, 0.33, 0.57, 0.7], invalid: [0, 0.0, 'a', 1.3, 0.05, 5] } ); + test({ + validator: 'isFloat' + , args: [{ + min: 3.7 + }] + , valid: [ + '3.888' + , '3.92' + , '4.5' + , '50' + , '3.7' + , '3.71' + ] + , invalid: [ + '3.6' + , '3.69' + , '3' + , '1.5' + , 'a' + ] + }); + test({ + validator: 'isFloat' + , args: [{ + min: 0.1 + , max: 1.0 + }] + , valid: [ + '0.1' + , '1.0' + , '0.15' + , '0.33' + , '0.57' + , '0.7' + ] + , invalid: [ + '0' + , '0.0' + , 'a' + , '1.3' + , '0.05' + , '5' + ] + }); }); it('should validate hexadecimal strings', function () { @@ -722,14 +857,11 @@ describe('Validators', function () { validator: 'isNull' , valid: [ '' - , NaN - , [] - , undefined - , null ] , invalid: [ ' ' , 'foo' + , '3' ] }); }); @@ -752,15 +884,32 @@ describe('Validators', function () { invalid: ['acb'] }); }); - it('should validate strings by length', function () { + it('should validate strings by length (deprecated api)', function () { test({ validator: 'isLength', args: [2], valid: ['abc', 'de', 'abcd'], invalid: [ '', 'a' ] }); test({ validator: 'isLength', args: [2, 3], valid: ['abc', 'de'], invalid: [ '', 'a', 'abcd' ] }); test({ validator: 'isLength', args: [2, 3], valid: ['干𩸽', '𠮷野家'], invalid: [ '', '𠀋', '千竈通り' ] }); + test({ validator: 'isLength', args: [0, 0], valid: [''], invalid: ['a', 'ab'] }); }); - it('should validate strings by byte length', function () { + it('should validate strings by byte length (deprecated api)', function () { test({ validator: 'isByteLength', args: [2], valid: ['abc', 'de', 'abcd', 'gmail'], invalid: [ '', 'a' ] }); test({ validator: 'isByteLength', args: [2, 3], valid: ['abc', 'de', 'g'], invalid: [ '', 'a', 'abcd', 'gm' ] }); + test({ validator: 'isByteLength', args: [0, 0], valid: [''], invalid: ['g', 'a'] }); + }); + + it('should validate strings by length', function () { + test({ validator: 'isLength', args: [{min: 2}], valid: ['abc', 'de', 'abcd'], invalid: ['', 'a'] }); + test({ validator: 'isLength', args: [{min: 2, max: 3}], valid: ['abc', 'de'], invalid: ['', 'a', 'abcd'] }); + test({ validator: 'isLength', args: [{min: 2, max: 3}], valid: ['干𩸽', '𠮷野家'], invalid: [ '', '𠀋', '千竈通り' ] }); + test({ validator: 'isLength', args: [{max: 3}], valid: ['abc', 'de', 'a', ''], invalid: ['abcd'] }); + test({ validator: 'isLength', args: [{max: 0}], valid: [''], invalid: ['a', 'ab'] }); + }); + + it('should validate strings by byte length', function () { + test({ validator: 'isByteLength', args: [{min: 2}], valid: ['abc', 'de', 'abcd', 'gmail'], invalid: ['', 'a'] }); + test({ validator: 'isByteLength', args: [{min: 2, max: 3}], valid: ['abc', 'de', 'g'], invalid: ['', 'a', 'abcd', 'gm'] }); + test({ validator: 'isByteLength', args: [{max: 3}], valid: ['abc', 'de', 'g', 'a', ''], invalid: ['abcd', 'gm'] }); + test({ validator: 'isByteLength', args: [{max: 0}], valid: [''], invalid: ['g', 'a'] }); }); it('should validate UUIDs', function () { @@ -839,7 +988,7 @@ describe('Validators', function () { invalid: ['foobarbaz', 'barfoo'] }); test({ validator: 'isIn', args: [['foo', 'bar']], valid: ['foo', 'bar'], invalid: ['foobar', 'barfoo', ''] }); - test({ validator: 'isIn', args: [[1, 2, 3]], valid: ['1', '2', '3'], + test({ validator: 'isIn', args: [['1', '2', '3']], valid: ['1', '2', '3'], invalid: ['4', ''] }); test({ validator: 'isIn', invalid: ['foo', ''] }); }); @@ -871,7 +1020,7 @@ describe('Validators', function () { , '2-23-22' , '12' , '11/2/23 12:24' - , new Date() + , new Date().toString() , 'Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)' , '2/22/23 23:24:26' // valid ISO 8601 dates below @@ -924,6 +1073,7 @@ describe('Validators', function () { , 'Wed, 9 Apr 2014 10:21:03 +0200' , 'Wed, 9 Apr 2014 06:21:03 -0200' , 'Wed, 9 Apr 2014 08:21:03 +0000' + , '2016-01-20 07:11' ] , invalid: [ 'foo' @@ -965,11 +1115,11 @@ describe('Validators', function () { it('should validate dates against a start date', function () { test({ validator: 'isAfter', args: ['2011-08-03'], - valid: [ '2011-08-04', new Date(2011, 8, 10) ], - invalid: [ '2010-07-02', '2011-08-03', new Date(0), 'foo'] }); + valid: [ '2011-08-04', new Date(2011, 8, 10).toString() ], + invalid: [ '2010-07-02', '2011-08-03', new Date(0).toString(), 'foo'] }); test({ validator: 'isAfter', - valid: [ '2100-08-04', new Date(Date.now() + 86400000) ], - invalid: [ '2010-07-02', new Date(0) ] }); + valid: [ '2100-08-04', new Date(Date.now() + 86400000).toString() ], + invalid: [ '2010-07-02', new Date(0).toString() ] }); test({ validator: 'isAfter', args: ['2011-08-03'], valid: [ '2015-09-17' ], invalid: [ 'invalid date' ] }); @@ -979,14 +1129,14 @@ describe('Validators', function () { it('should validate dates against an end date', function () { test({ validator: 'isBefore', args: ['08/04/2011'], - valid: [ '2010-07-02', '2010-08-04', new Date(0) ], - invalid: [ '08/04/2011', new Date(2011, 9, 10) ] }); - test({ validator: 'isBefore', args: [ new Date(2011, 7, 4) ], - valid: [ '2010-07-02', '2010-08-04', new Date(0) ], - invalid: [ '08/04/2011', new Date(2011, 9, 10) ] }); + valid: [ '2010-07-02', '2010-08-04', new Date(0).toString() ], + invalid: [ '08/04/2011', new Date(2011, 9, 10).toString() ] }); + test({ validator: 'isBefore', args: [ new Date(2011, 7, 4).toString() ], + valid: [ '2010-07-02', '2010-08-04', new Date(0).toString() ], + invalid: [ '08/04/2011', new Date(2011, 9, 10).toString() ] }); test({ validator: 'isBefore', - valid: [ '2000-08-04', new Date(0), new Date(Date.now() - 86400000) ], - invalid: [ '2100-07-02', new Date(2017, 10, 10) ] }); + valid: [ '2000-08-04', new Date(0).toString(), new Date(Date.now() - 86400000).toString() ], + invalid: [ '2100-07-02', new Date(2017, 10, 10).toString() ] }); test({ validator: 'isBefore', args: ['2011-08-03'], valid: [ '1999-12-31' ], invalid: [ 'invalid date' ] }); @@ -1110,8 +1260,6 @@ describe('Validators', function () { ] , invalid: [ '{ key: "value" }' - , { "key": "value" } - , { key: 'value' } , '{ \'key\': \'value\' }' , 'null' , '1234' @@ -1295,6 +1443,22 @@ describe('Validators', function () { }); it('should validate mobile phone number', function () { + test({ + validator: 'isMobilePhone' + , valid: [ + '+49 (0) 123 456 789' + , '+49 (0) 123 456789' + , '0123/4567890' + , '+49 01234567890' + , '01234567890' + ] + , invalid: [ + '' + , 'Vml2YW11cyBmZXJtZtesting123' + ], + args: ['de-DE'] + }); + test({ validator: 'isMobilePhone' , valid: [ @@ -1433,13 +1597,14 @@ describe('Validators', function () { test({ validator: 'isMobilePhone' , valid: [ - '2102323234' - , '+302646041461' - , '+306944848966' + '+306944848966' , '6944848966' + , '306944848966' ] , invalid: [ - '120000000' + '2102323234' + , '+302646041461' + , '120000000' , '20000000000' , '68129485729' , '6589394827' @@ -1606,6 +1771,32 @@ describe('Validators', function () { ], args: ['vi-VN'] }); + + test({ + validator: 'isMobilePhone' + , valid: [ + '+34654789321' + , '654789321' + , '+34714789321' + , '714789321' + , '+34744789321' + , '744789321' + ] + , invalid: [ + '12345' + , '' + , 'Vml2YW11cyBmZXJtZtesting123' + , '+3465478932' + , '65478932' + , '+346547893210' + , '6547893210' + , '+34704789321' + , '704789321' + , '+34754789321' + , '754789321' + ], + args: ['es-ES'] + }); }); test({ @@ -2413,4 +2604,41 @@ describe('Validators', function () { ] }); }); + + it('should validate whitelisted characters', function () { + test({ validator: 'isWhitelisted', args: ['abcdefghijklmnopqrstuvwxyz-'], valid: ['foo', 'foobar', 'baz-foo'], + invalid: ['foo bar', 'fo.bar', 'türkçe'] }); + }); + + it('should convert non-string input', function () { + var empty = [undefined, null, [], NaN]; + empty.forEach(function (item) { + assert.equal(validator.toString(item), ''); + assert(validator.isNull(item)); + }); + + var objects = [{}, Object.create(null)]; + objects.forEach(function (item) { + assert.equal(validator.toString(item), '[object Object]'); + }); + }); + + it('should error on non-string input when the coerce flag is false', function () { + validator.coerce = false; + + try { + validator.toString({}); + assert(false); + } catch (err) { + } + + validator.coerce = true; + + try { + validator.toString({}); + } catch (err) { + assert(false); + } + }); + }); diff --git a/validator.js b/validator.js index 73b84934a..cb92d5ac9 100644 --- a/validator.js +++ b/validator.js @@ -35,7 +35,7 @@ 'use strict'; - validator = { version: '4.3.0' }; + validator = { version: '4.6.1', coerce: true }; var emailUserPart = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i; var quotedEmailUser = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i; @@ -52,6 +52,8 @@ var isbn10Maybe = /^(?:[0-9]{9}X|[0-9]{10})$/ , isbn13Maybe = /^(?:[0-9]{13})$/; + var macAddress = /^([0-9a-fA-F][0-9a-fA-F]:){5}([0-9a-fA-F][0-9a-fA-F])$/; + var ipv4Maybe = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ , ipv6Block = /^[0-9A-F]{1,4}$/i; @@ -62,8 +64,14 @@ , all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i }; - var alpha = /^[A-Z]+$/i - , alphanumeric = /^[0-9A-Z]+$/i + var alpha = { + 'en-US': /^[A-Z]+$/i, + 'de-DE': /^[A-ZÄÖÜß]+$/i, + } + , alphanumeric = { + 'en-US': /^[0-9A-Z]+$/i, + 'de-DE': /^[0-9A-ZÄÖÜß]+$/i + } , numeric = /^[-+]?[0-9]+$/ , int = /^(?:[-+]?(?:0|[1-9][0-9]*))$/ , float = /^(?:[-+]?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/ @@ -81,14 +89,14 @@ var base64 = /^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i; var phones = { - 'zh-CN': /^(\+?0?86\-?)?1[345789]\d{9}$/, + 'zh-CN': /^(\+?0?86\-?)?((13\d|14[57]|15[^4,\D]|17[678]|18\d)\d{8}|170[059]\d{7})$/, 'zh-TW': /^(\+?886\-?|0)?9\d{8}$/, 'en-ZA': /^(\+?27|0)\d{9}$/, 'en-AU': /^(\+?61|0)4\d{8}$/, 'en-HK': /^(\+?852\-?)?[569]\d{3}\-?\d{4}$/, 'fr-FR': /^(\+?33|0)[67]\d{8}$/, 'pt-PT': /^(\+351)?9[1236]\d{7}$/, - 'el-GR': /^(\+30)?((2\d{9})|(69\d{8}))$/, + 'el-GR': /^(\+?30)?(69\d{8})$/, 'en-GB': /^(\+?44|0)7\d{9}$/, 'en-US': /^(\+?1)?[2-9]\d{2}[2-9](?!11)\d{6}$/, 'en-ZM': /^(\+26)?09[567]\d{7}$/, @@ -97,7 +105,13 @@ 'nn-NO': /^(\+?47)?[49]\d{7}$/, 'vi-VN': /^(0|\+?84)?((1(2([0-9])|6([2-9])|88|99))|(9((?!5)[0-9])))([0-9]{7})$/, 'en-NZ': /^(\+?64|0)2\d{7,9}$/, +<<<<<<< HEAD 'fi-FI': /^(00358|\+358|0)\s?(4|40|41|42|44|45|50)\s?(\d\s?){4,8}\d$/ +======= + 'en-IN': /^(\+?91|0)?[789]\d{9}$/, + 'es-ES': /^(\+34)?(6\d{1}|7[1234])\d{7}$/, + 'de-DE': /^(\+?49[ \.\-])?([\(]{1}[0-9]{1,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/ +>>>>>>> b6fc33af4c36b35e0769c4afafb0d4a2d1b6c3e3 }; // from http://goo.gl/0ejHHW @@ -124,8 +138,24 @@ }; validator.toString = function (input) { - if (typeof input === 'object' && input !== null && input.toString) { - input = input.toString(); + // The library validates strings only. Currently it coerces all input to a string, but this + // will go away in an upcoming major version change. Print a deprecation notice for now + if (typeof input !== 'string') { + if (!validator.coerce) { + throw new Error('this library validates strings only'); + } + if (typeof console === 'object' && console && typeof console.warn === 'function') { + console.warn('warning: you tried to validate a ' + typeof input + ' but this library ' + + '(github.com/chriso/validator.js) validates strings only. Please update your code ' + + 'as this will be an error soon.'); + } + } + if (typeof input === 'object' && input !== null) { + if (typeof input.toString === 'function') { + input = input.toString(); + } else { + input = '[object Object]'; + } } else if (input === null || typeof input === 'undefined' || (isNaN(input) && !input.length)) { input = ''; } @@ -195,8 +225,8 @@ user = user.replace(/\./g, '').toLowerCase(); } - if (!validator.isByteLength(user, 0, 64) || - !validator.isByteLength(domain, 0, 256)) { + if (!validator.isByteLength(user, {max: 64}) || + !validator.isByteLength(domain, {max: 256})) { return false; } @@ -296,8 +326,12 @@ return true; }; + validator.isMACAddress = function (str) { + return macAddress.test(str); + }; + validator.isIP = function (str, version) { - version = validator.toString(version); + version = version ? version + '' : ''; if (!version) { return validator.isIP(str, 4) || validator.isIP(str, 6); } else if (version === '4') { @@ -394,8 +428,10 @@ // disallow full-width chars return false; } - if (part[0] === '-' || part[part.length - 1] === '-' || - part.indexOf('---') >= 0) { + if (part[0] === '-' || part[part.length - 1] === '-') { + return false; + } + if (part.indexOf('---') >= 0 && part.slice(0, 4) !== 'xn--') { return false; } } @@ -406,12 +442,14 @@ return (['true', 'false', '1', '0'].indexOf(str) >= 0); }; - validator.isAlpha = function (str) { - return alpha.test(str); + validator.isAlpha = function (str, locale) { + locale = locale || 'en-US'; + return alpha[locale].test(str); }; - validator.isAlphanumeric = function (str) { - return alphanumeric.test(str); + validator.isAlphanumeric = function (str, locale) { + locale = locale || 'en-US'; + return alphanumeric[locale].test(str); }; validator.isNumeric = function (str) { @@ -452,20 +490,35 @@ }; validator.isDivisibleBy = function (str, num) { - return validator.toFloat(str) % validator.toInt(num) === 0; + return validator.toFloat(str) % parseInt(num, 10) === 0; }; validator.isNull = function (str) { return str.length === 0; }; - validator.isLength = function (str, min, max) { + validator.isLength = function (str, options) { + var min, max; + if (typeof(options) === 'object') { + min = options.min || 0; + max = options.max; + } else { // backwards compatibility: isLength(str, min [, max]) + min = arguments[1]; + max = arguments[2]; + } var surrogatePairs = str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g) || []; var len = str.length - surrogatePairs.length; return len >= min && (typeof max === 'undefined' || len <= max); }; - - validator.isByteLength = function (str, min, max) { + validator.isByteLength = function (str, options) { + var min, max; + if (typeof(options) === 'object') { + min = options.min || 0; + max = options.max; + } else { // backwards compatibility: isByteLength(str, min [, max]) + min = arguments[1]; + max = arguments[2]; + } var len = encodeURI(str).split(/%..|./).length - 1; return len >= min && (typeof max === 'undefined' || len <= max); }; @@ -498,7 +551,11 @@ } } else { timezone = iso8601Parts[21]; - if (!timezone || timezone === 'z' || timezone === 'Z') { + if (!timezone) { + // if no hour/minute was provided, the date is GMT + return !iso8601Parts[12] ? 0 : null; + } + if (timezone === 'z' || timezone === 'Z') { return 0; } sign = iso8601Parts[22]; @@ -518,6 +575,7 @@ if (isNaN(normalizedDate)) { return false; } + // normalizedDate is in the user's timezone. Apply the input // timezone offset to the date so that the year and day match // the input @@ -528,6 +586,7 @@ normalizedDate = new Date(normalizedDate.getTime() + 60000 * timezoneDifference); } + var day = String(normalizedDate.getDate()); var dayOrYear, dayOrYearMatches, year; //check for valid double digits that could be late days @@ -540,6 +599,7 @@ dayOrYear = dayOrYearMatches.map(function(digitString) { return digitString.match(/\d+/g)[0]; }).join('/'); + year = String(normalizedDate.getFullYear()).slice(-2); if (dayOrYear === day || dayOrYear === year) { return true; @@ -577,6 +637,16 @@ return false; }; + validator.isWhitelisted = function (str, chars) { + for (var i = str.length - 1; i >= 0; i--) { + if (chars.indexOf(str[i]) === -1) { + return false; + } + } + + return true; + }; + validator.isCreditCard = function (str) { var sanitized = str.replace(/[^0-9]+/g, ''); if (!creditCard.test(sanitized)) { @@ -631,7 +701,7 @@ }; validator.isISBN = function (str, version) { - version = validator.toString(version); + version = version ? version + '' : ''; if (!version) { return validator.isISBN(str, 10) || validator.isISBN(str, 13); } @@ -778,7 +848,9 @@ }; var default_normalize_email_options = { - lowercase: true + lowercase: true, + remove_dots: true, + remove_extension: true }; validator.normalizeEmail = function (email, options) { @@ -789,11 +861,16 @@ var parts = email.split('@', 2); parts[1] = parts[1].toLowerCase(); if (parts[1] === 'gmail.com' || parts[1] === 'googlemail.com') { - parts[0] = parts[0].toLowerCase().replace(/\./g, ''); - if (parts[0][0] === '+') { + if (options.remove_extension) { + parts[0] = parts[0].split('+')[0]; + } + if (options.remove_dots) { + parts[0] = parts[0].replace(/\./g, ''); + } + if (!parts[0].length) { return false; } - parts[0] = parts[0].split('+')[0]; + parts[0] = parts[0].toLowerCase(); parts[1] = 'gmail.com'; } else if (options.lowercase) { parts[0] = parts[0].toLowerCase(); diff --git a/validator.min.js b/validator.min.js index 1e76b5bbf..667ba2b10 100644 --- a/validator.min.js +++ b/validator.min.js @@ -20,4 +20,4 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -!function(t,e){"undefined"!=typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&"object"==typeof define.amd?define(e):"function"==typeof define&&"object"==typeof define.petal?define(t,[],e):this[t]=e()}("validator",function(t){"use strict";function e(t){var e,r,n,i,o=t.match(C);if(o){if(e=o[21],!e||"z"===e||"Z"===e)return 0;r=o[22],-1!==e.indexOf(":")?(n=parseInt(o[23]),i=parseInt(o[24])):(n=0,i=parseInt(o[23]))}else{if(t=t.toLowerCase(),e=t.match(/(?:\s|gmt\s*)(-|\+)(\d{1,4})(\s|$)/),!e)return-1!==t.indexOf("gmt")?0:null;r=e[1];var u=e[2];3===u.length&&(u="0"+u),u.length<=2?(n=0,i=parseInt(u)):(n=parseInt(u.slice(0,2)),i=parseInt(u.slice(2,4)))}return(60*n+i)*("-"===r?1:-1)}function r(t,e){t=t||{};for(var r in e)"undefined"==typeof t[r]&&(t[r]=e[r]);return t}function n(t){var e="(\\"+t.symbol.replace(/\./g,"\\.")+")"+(t.require_symbol?"":"?"),r="-?",n="[1-9]\\d*",i="[1-9]\\d{0,2}(\\"+t.thousands_separator+"\\d{3})*",o=["0",n,i],u="("+o.join("|")+")?",a="(\\"+t.decimal_separator+"\\d{2})?",s=u+a;return t.allow_negatives&&!t.parens_for_negatives&&(t.negative_sign_after_digits?s+=r:t.negative_sign_before_digits&&(s=r+s)),t.allow_negative_sign_placeholder?s="( (?!\\-))?"+s:t.allow_space_after_symbol?s=" ?"+s:t.allow_space_after_digits&&(s+="( (?!$))?"),t.symbol_after_digits?s+=e:s=e+s,t.allow_negatives&&(t.parens_for_negatives?s="(\\("+s+"\\)|"+s+")":t.negative_sign_before_digits||t.negative_sign_after_digits||(s=r+s)),new RegExp("^(?!-? )(?=.*\\d)"+s+"$")}t={version:"4.3.0"};var i=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i,o=/^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i,u=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+$/i,a=/^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*$/i,s=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\s]*<(.+)>$/i,l=/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,f=/^[A-Z]{2}[0-9A-Z]{9}[0-9]$/,c=/^(?:[0-9]{9}X|[0-9]{10})$/,p=/^(?:[0-9]{13})$/,g=/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/,d=/^[0-9A-F]{1,4}$/i,F={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i},_=/^[A-Z]+$/i,x=/^[0-9A-Z]+$/i,h=/^[-+]?[0-9]+$/,v=/^(?:[-+]?(?:0|[1-9][0-9]*))$/,m=/^(?:[-+]?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/,$=/^[0-9A-F]+$/i,A=/^[-+]?([0-9]+|\.[0-9]+|[0-9]+\.[0-9]+)$/,w=/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i,D=/^[\x00-\x7F]+$/,b=/[^\x00-\x7F]/,y=/[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/,I=/[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/,O=/[\uD800-\uDBFF][\uDC00-\uDFFF]/,E=/^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i,S={"zh-CN":/^(\+?0?86\-?)?1[345789]\d{9}$/,"zh-TW":/^(\+?886\-?|0)?9\d{8}$/,"en-ZA":/^(\+?27|0)\d{9}$/,"en-AU":/^(\+?61|0)4\d{8}$/,"en-HK":/^(\+?852\-?)?[569]\d{3}\-?\d{4}$/,"fr-FR":/^(\+?33|0)[67]\d{8}$/,"pt-PT":/^(\+351)?9[1236]\d{7}$/,"el-GR":/^(\+30)?((2\d{9})|(69\d{8}))$/,"en-GB":/^(\+?44|0)7\d{9}$/,"en-US":/^(\+?1)?[2-9]\d{2}[2-9](?!11)\d{6}$/,"en-ZM":/^(\+26)?09[567]\d{7}$/,"ru-RU":/^(\+?7|8)?9\d{9}$/,"nb-NO":/^(\+?47)?[49]\d{7}$/,"nn-NO":/^(\+?47)?[49]\d{7}$/,"vi-VN":/^(0|\+?84)?((1(2([0-9])|6([2-9])|88|99))|(9((?!5)[0-9])))([0-9]{7})$/,"en-NZ":/^(\+?64|0)2\d{7,9}$/},C=/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;t.extend=function(e,r){t[e]=function(){var e=Array.prototype.slice.call(arguments);return e[0]=t.toString(e[0]),r.apply(t,e)}},t.init=function(){for(var e in t)"function"==typeof t[e]&&"toString"!==e&&"toDate"!==e&&"extend"!==e&&"init"!==e&&t.extend(e,t[e])},t.toString=function(t){return"object"==typeof t&&null!==t&&t.toString?t=t.toString():(null===t||"undefined"==typeof t||isNaN(t)&&!t.length)&&(t=""),""+t},t.toDate=function(t){return"[object Date]"===Object.prototype.toString.call(t)?t:(t=Date.parse(t),isNaN(t)?null:new Date(t))},t.toFloat=function(t){return parseFloat(t)},t.toInt=function(t,e){return parseInt(t,e||10)},t.toBoolean=function(t,e){return e?"1"===t||"true"===t:"0"!==t&&"false"!==t&&""!==t},t.equals=function(e,r){return e===t.toString(r)},t.contains=function(e,r){return e.indexOf(t.toString(r))>=0},t.matches=function(t,e,r){return"[object RegExp]"!==Object.prototype.toString.call(e)&&(e=new RegExp(e,r)),e.test(t)};var N={allow_display_name:!1,allow_utf8_local_part:!0,require_tld:!0};t.isEmail=function(e,n){if(n=r(n,N),n.allow_display_name){var l=e.match(s);l&&(e=l[1])}var f=e.split("@"),c=f.pop(),p=f.join("@"),g=c.toLowerCase();if(("gmail.com"===g||"googlemail.com"===g)&&(p=p.replace(/\./g,"").toLowerCase()),!t.isByteLength(p,0,64)||!t.isByteLength(c,0,256))return!1;if(!t.isFQDN(c,{require_tld:n.require_tld}))return!1;if('"'===p[0])return p=p.slice(1,p.length-1),n.allow_utf8_local_part?a.test(p):o.test(p);for(var d=n.allow_utf8_local_part?u:i,F=p.split("."),_=0;_=2083||/\s/.test(e))return!1;if(0===e.indexOf("mailto:"))return!1;n=r(n,j);var i,o,u,a,s,l,f;if(f=e.split("://"),f.length>1){if(i=f.shift(),n.require_valid_protocol&&-1===n.protocols.indexOf(i))return!1}else{if(n.require_protocol)return!1;n.allow_protocol_relative_urls&&"//"===e.substr(0,2)&&(f[0]=e.substr(2))}return e=f.join("://"),f=e.split("#"),e=f.shift(),f=e.split("?"),e=f.shift(),f=e.split("/"),e=f.shift(),f=e.split("@"),f.length>1&&(o=f.shift(),o.indexOf(":")>=0&&o.split(":").length>2)?!1:(a=f.join("@"),f=a.split(":"),u=f.shift(),f.length&&(l=f.join(":"),s=parseInt(l,10),!/^[0-9]+$/.test(l)||0>=s||s>65535)?!1:t.isIP(u)||t.isFQDN(u,n)||"localhost"===u?n.host_whitelist&&-1===n.host_whitelist.indexOf(u)?!1:n.host_blacklist&&-1!==n.host_blacklist.indexOf(u)?!1:!0:!1)},t.isIP=function(e,r){if(r=t.toString(r),!r)return t.isIP(e,4)||t.isIP(e,6);if("4"===r){if(!g.test(e))return!1;var n=e.split(".").sort(function(t,e){return t-e});return n[3]<=255}if("6"===r){var i=e.split(":"),o=!1,u=t.isIP(i[i.length-1],4),a=u?7:8;if(i.length>a)return!1;if("::"===e)return!0;"::"===e.substr(0,2)?(i.shift(),i.shift(),o=!0):"::"===e.substr(e.length-2)&&(i.pop(),i.pop(),o=!0);for(var s=0;s0&&s=1:i.length===a}return!1};var B={require_tld:!0,allow_underscores:!1,allow_trailing_dot:!1};t.isFQDN=function(t,e){e=r(e,B),e.allow_trailing_dot&&"."===t[t.length-1]&&(t=t.substring(0,t.length-1));var n=t.split(".");if(e.require_tld){var i=n.pop();if(!n.length||!/^([a-z\u00a1-\uffff]{2,}|xn[a-z0-9-]{2,})$/i.test(i))return!1}for(var o,u=0;u=0)return!1;o=o.replace(/_/g,"")}if(!/^[a-z\u00a1-\uffff0-9-]+$/i.test(o))return!1;if(/[\uff01-\uff5e]/.test(o))return!1;if("-"===o[0]||"-"===o[o.length-1]||o.indexOf("---")>=0)return!1}return!0},t.isBoolean=function(t){return["true","false","1","0"].indexOf(t)>=0},t.isAlpha=function(t){return _.test(t)},t.isAlphanumeric=function(t){return x.test(t)},t.isNumeric=function(t){return h.test(t)},t.isDecimal=function(t){return""!==t&&A.test(t)},t.isHexadecimal=function(t){return $.test(t)},t.isHexColor=function(t){return w.test(t)},t.isLowercase=function(t){return t===t.toLowerCase()},t.isUppercase=function(t){return t===t.toUpperCase()},t.isInt=function(t,e){return e=e||{},v.test(t)&&(!e.hasOwnProperty("min")||t>=e.min)&&(!e.hasOwnProperty("max")||t<=e.max)},t.isFloat=function(t,e){return e=e||{},""===t||"."===t?!1:m.test(t)&&(!e.hasOwnProperty("min")||t>=e.min)&&(!e.hasOwnProperty("max")||t<=e.max)},t.isDivisibleBy=function(e,r){return t.toFloat(e)%t.toInt(r)===0},t.isNull=function(t){return 0===t.length},t.isLength=function(t,e,r){var n=t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g)||[],i=t.length-n.length;return i>=e&&("undefined"==typeof r||r>=i)},t.isByteLength=function(t,e,r){var n=encodeURI(t).split(/%..|./).length-1;return n>=e&&("undefined"==typeof r||r>=n)},t.isUUID=function(t,e){var r=F[e?e:"all"];return r&&r.test(t)},t.isDate=function(t){var r=new Date(Date.parse(t));if(isNaN(r))return!1;var n=e(t);if(null!==n){var i=r.getTimezoneOffset()-n;r=new Date(r.getTime()+6e4*i)}var o,u,a,s=String(r.getDate());return(u=t.match(/(^|[^:\d])[23]\d([^:\d]|$)/g))?(o=u.map(function(t){return t.match(/\d+/g)[0]}).join("/"),a=String(r.getFullYear()).slice(-2),o===s||o===a?!0:o===s+"/"+a||o===a+"/"+s?!0:!1):!0},t.isAfter=function(e,r){var n=t.toDate(r||new Date),i=t.toDate(e);return!!(i&&n&&i>n)},t.isBefore=function(e,r){var n=t.toDate(r||new Date),i=t.toDate(e);return!!(i&&n&&n>i)},t.isIn=function(e,r){var n;if("[object Array]"===Object.prototype.toString.call(r)){var i=[];for(n in r)i[n]=t.toString(r[n]);return i.indexOf(e)>=0}return"object"==typeof r?r.hasOwnProperty(e):r&&"function"==typeof r.indexOf?r.indexOf(e)>=0:!1},t.isCreditCard=function(t){var e=t.replace(/[^0-9]+/g,"");if(!l.test(e))return!1;for(var r,n,i,o=0,u=e.length-1;u>=0;u--)r=e.substring(u,u+1),n=parseInt(r,10),i?(n*=2,o+=n>=10?n%10+1:n):o+=n,i=!i;return!!(o%10===0?e:!1)},t.isISIN=function(t){if(!f.test(t))return!1;for(var e,r,n=t.replace(/[A-Z]/g,function(t){return parseInt(t,36)}),i=0,o=!0,u=n.length-2;u>=0;u--)e=n.substring(u,u+1),r=parseInt(e,10),o?(r*=2,i+=r>=10?r+1:r):i+=r,o=!o;return parseInt(t.substr(t.length-1),10)===(1e4-i)%10},t.isISBN=function(e,r){if(r=t.toString(r),!r)return t.isISBN(e,10)||t.isISBN(e,13);var n,i=e.replace(/[\s-]+/g,""),o=0;if("10"===r){if(!c.test(i))return!1;for(n=0;9>n;n++)o+=(n+1)*i.charAt(n);if(o+="X"===i.charAt(9)?100:10*i.charAt(9),o%11===0)return!!i}else if("13"===r){if(!p.test(i))return!1;var u=[1,3];for(n=0;12>n;n++)o+=u[n%2]*i.charAt(n);if(i.charAt(12)-(10-o%10)%10===0)return!!i}return!1},t.isMobilePhone=function(t,e){return e in S?S[e].test(t):!1};var Z={symbol:"$",require_symbol:!1,allow_space_after_symbol:!1,symbol_after_digits:!1,allow_negatives:!0,parens_for_negatives:!1,negative_sign_before_digits:!1,negative_sign_after_digits:!1,allow_negative_sign_placeholder:!1,thousands_separator:",",decimal_separator:".",allow_space_after_digits:!1};t.isCurrency=function(t,e){return e=r(e,Z),n(e).test(t)},t.isJSON=function(t){try{var e=JSON.parse(t);return!!e&&"object"==typeof e}catch(r){}return!1},t.isMultibyte=function(t){return b.test(t)},t.isAscii=function(t){return D.test(t)},t.isFullWidth=function(t){return y.test(t)},t.isHalfWidth=function(t){return I.test(t)},t.isVariableWidth=function(t){return y.test(t)&&I.test(t)},t.isSurrogatePair=function(t){return O.test(t)},t.isBase64=function(t){return E.test(t)},t.isMongoId=function(e){return t.isHexadecimal(e)&&24===e.length},t.isISO8601=function(t){return C.test(t)},t.ltrim=function(t,e){var r=e?new RegExp("^["+e+"]+","g"):/^\s+/g;return t.replace(r,"")},t.rtrim=function(t,e){var r=e?new RegExp("["+e+"]+$","g"):/\s+$/g;return t.replace(r,"")},t.trim=function(t,e){var r=e?new RegExp("^["+e+"]+|["+e+"]+$","g"):/^\s+|\s+$/g;return t.replace(r,"")},t.escape=function(t){return t.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/\//g,"/").replace(/\`/g,"`")},t.stripLow=function(e,r){var n=r?"\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F":"\\x00-\\x1F\\x7F";return t.blacklist(e,n)},t.whitelist=function(t,e){return t.replace(new RegExp("[^"+e+"]+","g"),"")},t.blacklist=function(t,e){return t.replace(new RegExp("["+e+"]+","g"),"")};var z={lowercase:!0};return t.normalizeEmail=function(e,n){if(n=r(n,z),!t.isEmail(e))return!1;var i=e.split("@",2);if(i[1]=i[1].toLowerCase(),"gmail.com"===i[1]||"googlemail.com"===i[1]){if(i[0]=i[0].toLowerCase().replace(/\./g,""),"+"===i[0][0])return!1;i[0]=i[0].split("+")[0],i[1]="gmail.com"}else n.lowercase&&(i[0]=i[0].toLowerCase());return i.join("@")},t.init(),t}); +!function(t,e){"undefined"!=typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&"object"==typeof define.amd?define(e):"function"==typeof define&&"object"==typeof define.petal?define(t,[],e):this[t]=e()}("validator",function(t){"use strict";function e(t){var e,r,n,i,o=t.match(C);if(o){if(e=o[21],!e)return o[12]?null:0;if("z"===e||"Z"===e)return 0;r=o[22],-1!==e.indexOf(":")?(n=parseInt(o[23]),i=parseInt(o[24])):(n=0,i=parseInt(o[23]))}else{if(t=t.toLowerCase(),e=t.match(/(?:\s|gmt\s*)(-|\+)(\d{1,4})(\s|$)/),!e)return-1!==t.indexOf("gmt")?0:null;r=e[1];var a=e[2];3===a.length&&(a="0"+a),a.length<=2?(n=0,i=parseInt(a)):(n=parseInt(a.slice(0,2)),i=parseInt(a.slice(2,4)))}return(60*n+i)*("-"===r?1:-1)}function r(t,e){t=t||{};for(var r in e)"undefined"==typeof t[r]&&(t[r]=e[r]);return t}function n(t){var e="(\\"+t.symbol.replace(/\./g,"\\.")+")"+(t.require_symbol?"":"?"),r="-?",n="[1-9]\\d*",i="[1-9]\\d{0,2}(\\"+t.thousands_separator+"\\d{3})*",o=["0",n,i],a="("+o.join("|")+")?",s="(\\"+t.decimal_separator+"\\d{2})?",u=a+s;return t.allow_negatives&&!t.parens_for_negatives&&(t.negative_sign_after_digits?u+=r:t.negative_sign_before_digits&&(u=r+u)),t.allow_negative_sign_placeholder?u="( (?!\\-))?"+u:t.allow_space_after_symbol?u=" ?"+u:t.allow_space_after_digits&&(u+="( (?!$))?"),t.symbol_after_digits?u+=e:u=e+u,t.allow_negatives&&(t.parens_for_negatives?u="(\\("+u+"\\)|"+u+")":t.negative_sign_before_digits||t.negative_sign_after_digits||(u=r+u)),new RegExp("^(?!-? )(?=.*\\d)"+u+"$")}t={version:"4.6.1",coerce:!0};var i=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i,o=/^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i,a=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+$/i,s=/^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*$/i,u=/^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\s]*<(.+)>$/i,l=/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,f=/^[A-Z]{2}[0-9A-Z]{9}[0-9]$/,c=/^(?:[0-9]{9}X|[0-9]{10})$/,d=/^(?:[0-9]{13})$/,g=/^([0-9a-fA-F][0-9a-fA-F]:){5}([0-9a-fA-F][0-9a-fA-F])$/,p=/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/,F=/^[0-9A-F]{1,4}$/i,_={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i},x={"en-US":/^[A-Z]+$/i,"de-DE":/^[A-ZÄÖÜß]+$/i},h={"en-US":/^[0-9A-Z]+$/i,"de-DE":/^[0-9A-ZÄÖÜß]+$/i},v=/^[-+]?[0-9]+$/,m=/^(?:[-+]?(?:0|[1-9][0-9]*))$/,A=/^(?:[-+]?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/,$=/^[0-9A-F]+$/i,w=/^[-+]?([0-9]+|\.[0-9]+|[0-9]+\.[0-9]+)$/,y=/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i,b=/^[\x00-\x7F]+$/,D=/[^\x00-\x7F]/,E=/[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/,I=/[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/,O=/[\uD800-\uDBFF][\uDC00-\uDFFF]/,S=/^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i,j={"zh-CN":/^(\+?0?86\-?)?((13\d|14[57]|15[^4,\D]|17[678]|18\d)\d{8}|170[059]\d{7})$/,"zh-TW":/^(\+?886\-?|0)?9\d{8}$/,"en-ZA":/^(\+?27|0)\d{9}$/,"en-AU":/^(\+?61|0)4\d{8}$/,"en-HK":/^(\+?852\-?)?[569]\d{3}\-?\d{4}$/,"fr-FR":/^(\+?33|0)[67]\d{8}$/,"pt-PT":/^(\+351)?9[1236]\d{7}$/,"el-GR":/^(\+?30)?(69\d{8})$/,"en-GB":/^(\+?44|0)7\d{9}$/,"en-US":/^(\+?1)?[2-9]\d{2}[2-9](?!11)\d{6}$/,"en-ZM":/^(\+26)?09[567]\d{7}$/,"ru-RU":/^(\+?7|8)?9\d{9}$/,"nb-NO":/^(\+?47)?[49]\d{7}$/,"nn-NO":/^(\+?47)?[49]\d{7}$/,"vi-VN":/^(0|\+?84)?((1(2([0-9])|6([2-9])|88|99))|(9((?!5)[0-9])))([0-9]{7})$/,"en-NZ":/^(\+?64|0)2\d{7,9}$/,"en-IN":/^(\+?91|0)?[789]\d{9}$/,"es-ES":/^(\+34)?(6\d{1}|7[1234])\d{7}$/,"de-DE":/^(\+?49[ \.\-])?([\(]{1}[0-9]{1,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/},C=/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;t.extend=function(e,r){t[e]=function(){var e=Array.prototype.slice.call(arguments);return e[0]=t.toString(e[0]),r.apply(t,e)}},t.init=function(){for(var e in t)"function"==typeof t[e]&&"toString"!==e&&"toDate"!==e&&"extend"!==e&&"init"!==e&&t.extend(e,t[e])},t.toString=function(e){if("string"!=typeof e){if(!t.coerce)throw new Error("this library validates strings only");"object"==typeof console&&console&&"function"==typeof console.warn&&console.warn("warning: you tried to validate a "+typeof e+" but this library (github.com/chriso/validator.js) validates strings only. Please update your code as this will be an error soon.")}return"object"==typeof e&&null!==e?e="function"==typeof e.toString?e.toString():"[object Object]":(null===e||"undefined"==typeof e||isNaN(e)&&!e.length)&&(e=""),""+e},t.toDate=function(t){return"[object Date]"===Object.prototype.toString.call(t)?t:(t=Date.parse(t),isNaN(t)?null:new Date(t))},t.toFloat=function(t){return parseFloat(t)},t.toInt=function(t,e){return parseInt(t,e||10)},t.toBoolean=function(t,e){return e?"1"===t||"true"===t:"0"!==t&&"false"!==t&&""!==t},t.equals=function(e,r){return e===t.toString(r)},t.contains=function(e,r){return e.indexOf(t.toString(r))>=0},t.matches=function(t,e,r){return"[object RegExp]"!==Object.prototype.toString.call(e)&&(e=new RegExp(e,r)),e.test(t)};var N={allow_display_name:!1,allow_utf8_local_part:!0,require_tld:!0};t.isEmail=function(e,n){if(n=r(n,N),n.allow_display_name){var l=e.match(u);l&&(e=l[1])}var f=e.split("@"),c=f.pop(),d=f.join("@"),g=c.toLowerCase();if(("gmail.com"===g||"googlemail.com"===g)&&(d=d.replace(/\./g,"").toLowerCase()),!t.isByteLength(d,{max:64})||!t.isByteLength(c,{max:256}))return!1;if(!t.isFQDN(c,{require_tld:n.require_tld}))return!1;if('"'===d[0])return d=d.slice(1,d.length-1),n.allow_utf8_local_part?s.test(d):o.test(d);for(var p=n.allow_utf8_local_part?a:i,F=d.split("."),_=0;_=2083||/\s/.test(e))return!1;if(0===e.indexOf("mailto:"))return!1;n=r(n,Z);var i,o,a,s,u,l,f;if(f=e.split("://"),f.length>1){if(i=f.shift(),n.require_valid_protocol&&-1===n.protocols.indexOf(i))return!1}else{if(n.require_protocol)return!1;n.allow_protocol_relative_urls&&"//"===e.substr(0,2)&&(f[0]=e.substr(2))}return e=f.join("://"),f=e.split("#"),e=f.shift(),f=e.split("?"),e=f.shift(),f=e.split("/"),e=f.shift(),f=e.split("@"),f.length>1&&(o=f.shift(),o.indexOf(":")>=0&&o.split(":").length>2)?!1:(s=f.join("@"),f=s.split(":"),a=f.shift(),f.length&&(l=f.join(":"),u=parseInt(l,10),!/^[0-9]+$/.test(l)||0>=u||u>65535)?!1:t.isIP(a)||t.isFQDN(a,n)||"localhost"===a?n.host_whitelist&&-1===n.host_whitelist.indexOf(a)?!1:n.host_blacklist&&-1!==n.host_blacklist.indexOf(a)?!1:!0:!1)},t.isMACAddress=function(t){return g.test(t)},t.isIP=function(e,r){if(r=t.toString(r),!r)return t.isIP(e,4)||t.isIP(e,6);if("4"===r){if(!p.test(e))return!1;var n=e.split(".").sort(function(t,e){return t-e});return n[3]<=255}if("6"===r){var i=e.split(":"),o=!1,a=t.isIP(i[i.length-1],4),s=a?7:8;if(i.length>s)return!1;if("::"===e)return!0;"::"===e.substr(0,2)?(i.shift(),i.shift(),o=!0):"::"===e.substr(e.length-2)&&(i.pop(),i.pop(),o=!0);for(var u=0;u0&&u=1:i.length===s}return!1};var B={require_tld:!0,allow_underscores:!1,allow_trailing_dot:!1};t.isFQDN=function(t,e){e=r(e,B),e.allow_trailing_dot&&"."===t[t.length-1]&&(t=t.substring(0,t.length-1));var n=t.split(".");if(e.require_tld){var i=n.pop();if(!n.length||!/^([a-z\u00a1-\uffff]{2,}|xn[a-z0-9-]{2,})$/i.test(i))return!1}for(var o,a=0;a=0)return!1;o=o.replace(/_/g,"")}if(!/^[a-z\u00a1-\uffff0-9-]+$/i.test(o))return!1;if(/[\uff01-\uff5e]/.test(o))return!1;if("-"===o[0]||"-"===o[o.length-1])return!1;if(o.indexOf("---")>=0&&"xn--"!==o.slice(0,4))return!1}return!0},t.isBoolean=function(t){return["true","false","1","0"].indexOf(t)>=0},t.isAlpha=function(t,e){return e=e||"en-US",x[e].test(t)},t.isAlphanumeric=function(t,e){return e=e||"en-US",h[e].test(t)},t.isNumeric=function(t){return v.test(t)},t.isDecimal=function(t){return""!==t&&w.test(t)},t.isHexadecimal=function(t){return $.test(t)},t.isHexColor=function(t){return y.test(t)},t.isLowercase=function(t){return t===t.toLowerCase()},t.isUppercase=function(t){return t===t.toUpperCase()},t.isInt=function(t,e){return e=e||{},m.test(t)&&(!e.hasOwnProperty("min")||t>=e.min)&&(!e.hasOwnProperty("max")||t<=e.max)},t.isFloat=function(t,e){return e=e||{},""===t||"."===t?!1:A.test(t)&&(!e.hasOwnProperty("min")||t>=e.min)&&(!e.hasOwnProperty("max")||t<=e.max)},t.isDivisibleBy=function(e,r){return t.toFloat(e)%t.toInt(r)===0},t.isNull=function(t){return 0===t.length},t.isLength=function(t,e){var r,n;"object"==typeof e?(r=e.min||0,n=e.max):(r=arguments[1],n=arguments[2]);var i=t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g)||[],o=t.length-i.length;return o>=r&&("undefined"==typeof n||n>=o)},t.isByteLength=function(t,e){var r,n;"object"==typeof e?(r=e.min||0,n=e.max):(r=arguments[1],n=arguments[2]);var i=encodeURI(t).split(/%..|./).length-1;return i>=r&&("undefined"==typeof n||n>=i)},t.isUUID=function(t,e){var r=_[e?e:"all"];return r&&r.test(t)},t.isDate=function(t){var r=new Date(Date.parse(t));if(isNaN(r))return!1;var n=e(t);if(null!==n){var i=r.getTimezoneOffset()-n;r=new Date(r.getTime()+6e4*i)}var o,a,s,u=String(r.getDate());return(a=t.match(/(^|[^:\d])[23]\d([^:\d]|$)/g))?(o=a.map(function(t){return t.match(/\d+/g)[0]}).join("/"),s=String(r.getFullYear()).slice(-2),o===u||o===s?!0:o===u+"/"+s||o===s+"/"+u?!0:!1):!0},t.isAfter=function(e,r){var n=t.toDate(r||new Date),i=t.toDate(e);return!!(i&&n&&i>n)},t.isBefore=function(e,r){var n=t.toDate(r||new Date),i=t.toDate(e);return!!(i&&n&&n>i)},t.isIn=function(e,r){var n;if("[object Array]"===Object.prototype.toString.call(r)){var i=[];for(n in r)i[n]=t.toString(r[n]);return i.indexOf(e)>=0}return"object"==typeof r?r.hasOwnProperty(e):r&&"function"==typeof r.indexOf?r.indexOf(e)>=0:!1},t.isWhitelisted=function(t,e){for(var r=t.length-1;r>=0;r--)if(-1===e.indexOf(t[r]))return!1;return!0},t.isCreditCard=function(t){var e=t.replace(/[^0-9]+/g,"");if(!l.test(e))return!1;for(var r,n,i,o=0,a=e.length-1;a>=0;a--)r=e.substring(a,a+1),n=parseInt(r,10),i?(n*=2,o+=n>=10?n%10+1:n):o+=n,i=!i;return!!(o%10===0?e:!1)},t.isISIN=function(t){if(!f.test(t))return!1;for(var e,r,n=t.replace(/[A-Z]/g,function(t){return parseInt(t,36)}),i=0,o=!0,a=n.length-2;a>=0;a--)e=n.substring(a,a+1),r=parseInt(e,10),o?(r*=2,i+=r>=10?r+1:r):i+=r,o=!o;return parseInt(t.substr(t.length-1),10)===(1e4-i)%10},t.isISBN=function(e,r){if(r=t.toString(r),!r)return t.isISBN(e,10)||t.isISBN(e,13);var n,i=e.replace(/[\s-]+/g,""),o=0;if("10"===r){if(!c.test(i))return!1;for(n=0;9>n;n++)o+=(n+1)*i.charAt(n);if(o+="X"===i.charAt(9)?100:10*i.charAt(9),o%11===0)return!!i}else if("13"===r){if(!d.test(i))return!1;var a=[1,3];for(n=0;12>n;n++)o+=a[n%2]*i.charAt(n);if(i.charAt(12)-(10-o%10)%10===0)return!!i}return!1},t.isMobilePhone=function(t,e){return e in j?j[e].test(t):!1};var z={symbol:"$",require_symbol:!1,allow_space_after_symbol:!1,symbol_after_digits:!1,allow_negatives:!0,parens_for_negatives:!1,negative_sign_before_digits:!1,negative_sign_after_digits:!1,allow_negative_sign_placeholder:!1,thousands_separator:",",decimal_separator:".",allow_space_after_digits:!1};t.isCurrency=function(t,e){return e=r(e,z),n(e).test(t)},t.isJSON=function(t){try{var e=JSON.parse(t);return!!e&&"object"==typeof e}catch(r){}return!1},t.isMultibyte=function(t){return D.test(t)},t.isAscii=function(t){return b.test(t)},t.isFullWidth=function(t){return E.test(t)},t.isHalfWidth=function(t){return I.test(t)},t.isVariableWidth=function(t){return E.test(t)&&I.test(t)},t.isSurrogatePair=function(t){return O.test(t)},t.isBase64=function(t){return S.test(t)},t.isMongoId=function(e){return t.isHexadecimal(e)&&24===e.length},t.isISO8601=function(t){return C.test(t)},t.ltrim=function(t,e){var r=e?new RegExp("^["+e+"]+","g"):/^\s+/g;return t.replace(r,"")},t.rtrim=function(t,e){var r=e?new RegExp("["+e+"]+$","g"):/\s+$/g;return t.replace(r,"")},t.trim=function(t,e){var r=e?new RegExp("^["+e+"]+|["+e+"]+$","g"):/^\s+|\s+$/g;return t.replace(r,"")},t.escape=function(t){return t.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/\//g,"/").replace(/\`/g,"`")},t.stripLow=function(e,r){var n=r?"\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F":"\\x00-\\x1F\\x7F";return t.blacklist(e,n)},t.whitelist=function(t,e){return t.replace(new RegExp("[^"+e+"]+","g"),"")},t.blacklist=function(t,e){return t.replace(new RegExp("["+e+"]+","g"),"")};var q={lowercase:!0,remove_dots:!0,remove_extension:!0};return t.normalizeEmail=function(e,n){if(n=r(n,q),!t.isEmail(e))return!1;var i=e.split("@",2);if(i[1]=i[1].toLowerCase(),"gmail.com"===i[1]||"googlemail.com"===i[1]){if(n.remove_extension&&(i[0]=i[0].split("+")[0]),n.remove_dots&&(i[0]=i[0].replace(/\./g,"")),!i[0].length)return!1;i[0]=i[0].toLowerCase(),i[1]="gmail.com"}else n.lowercase&&(i[0]=i[0].toLowerCase());return i.join("@")},t.init(),t});