From 2d5d6999541add350fb396ef02dc42ca3215049e Mon Sep 17 00:00:00 2001
From: Chris O'Hara <cohara87@gmail.com>
Date: Thu, 31 Oct 2013 11:41:57 +1100
Subject: [PATCH] Remove the XSS filter.

The xss() function was originally a port of the XSS filter from
CodeIgniter. I added it to the library because there wasn't an
alternative at the time. Unfortunately I don't have the time or
expertise to maintain the XSS filter or keep merging upstream
changes.

If you need one for your app, I suggest looking at Caja sanitisation
engine maintained by Google. (https://code.google.com/p/google-caja/
source/browse/trunk/src/com/google/caja/plugin/html-sanitizer.js)

Closes #123, #138, #181, #206, #210, #221, #223, #226, #227, #231, #232
---
 README.md           |   5 -
 lib/filter.js       |   6 --
 lib/xss.js          | 228 --------------------------------------------
 package.json        |   2 +-
 test/filter.test.js |  33 -------
 validator-min.js    |   2 +-
 validator.js        | 209 +---------------------------------------
 7 files changed, 3 insertions(+), 482 deletions(-)
 delete mode 100755 lib/xss.js

diff --git a/README.md b/README.md
index 528e01139..36d36f544 100755
--- a/README.md
+++ b/README.md
@@ -34,7 +34,6 @@ var int = sanitize('0123').toInt();                  //123
 var bool = sanitize('true').toBoolean();             //true
 var str = sanitize(' \t\r hello \n').trim();         //'hello'
 var str = sanitize('aaaaaaaaab').ltrim('a');         //'b'
-var str = sanitize(large_input_str).xss();
 var str = sanitize('&lt;a&gt;').entityDecode();      //'<a>'
 ```
 
@@ -58,7 +57,6 @@ get('/', function (req, res) {
     req.checkHeader('referer').contains('localhost');
 
     //Sanitize user input
-    req.sanitize('textarea').xss();
     req.sanitize('foo').toBoolean();
 
     //etc.
@@ -130,8 +128,6 @@ toBooleanStrict()               //False unless str = '1' or 'true'
 entityDecode()                  //Decode HTML entities
 entityEncode()
 escape()                        //Escape &, <, >, and "
-xss()                           //Remove common XSS attack vectors from user-supplied HTML
-xss(true)                       //Remove common XSS attack vectors from images
 ```
 
 ## Extending the library
@@ -221,7 +217,6 @@ var errors = validator.getErrors(); // ['Invalid email', 'String is too small']
 - [oris](https://github.com/orls) - Added in()
 - [mren](https://github.com/mren) - Decoupled rules
 - [Thorsten Basse](https://github.com/tbasse) - Cleanup and refinement of existing validators
-- [Neal Poole](https://github.com/nealpoole) - Port the latest xss() updates from CodeIgniter
 
 ## LICENSE
 
diff --git a/lib/filter.js b/lib/filter.js
index f828c33ee..c739d8498 100755
--- a/lib/filter.js
+++ b/lib/filter.js
@@ -1,5 +1,4 @@
 var entities = require('./entities');
-var xss = require('./xss');
 
 var Filter = exports.Filter = function() {}
 
@@ -28,11 +27,6 @@ Filter.prototype.convert = Filter.prototype.sanitize = function(str) {
     return this;
 }
 
-Filter.prototype.xss = function(is_image) {
-    this.modify(xss.clean(this.str, is_image));
-    return this.wrap(this.str);
-}
-
 Filter.prototype.entityDecode = function() {
     this.modify(entities.decode(this.str));
     return this.wrap(this.str);
diff --git a/lib/xss.js b/lib/xss.js
deleted file mode 100755
index 4a2ed9e66..000000000
--- a/lib/xss.js
+++ /dev/null
@@ -1,228 +0,0 @@
-//This module is adapted from the CodeIgniter framework
-//The license is available at http://codeigniter.com/
-
-var html_entity_decode = require('./entities').decode;
-
-var never_allowed_str = {
-    'document.cookie':              '[removed]',
-    'document.write':               '[removed]',
-    '.parentNode':                  '[removed]',
-    '.innerHTML':                   '[removed]',
-    'window.location':              '[removed]',
-    '-moz-binding':                 '[removed]',
-    '<!--':                         '&lt;!--',
-    '-->':                          '--&gt;',
-    '(<!\\[CDATA\\[)':              '&lt;![CDATA[',
-    '<comment>':                    '&lt;comment&gt;'
-};
-
-var never_allowed_regex = {
-    'javascript\\s*:':                                       '[removed]',
-    'expression\\s*(\\(|&#40;)':                             '[removed]',
-    'vbscript\\s*:':                                         '[removed]',
-    'Redirect\\s+302':                                       '[removed]',
-    "([\"'])?data\\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?":  '[removed]'
-};
-
-var non_displayables = [
-    /%0[0-8bcef]/g,           // url encoded 00-08, 11, 12, 14, 15
-    /%1[0-9a-f]/g,            // url encoded 16-31
-    /[\x00-\x08]/g,           // 00-08
-    /\x0b/g, /\x0c/g,         // 11,12
-    /[\x0e-\x1f]/g            // 14-31
-];
-
-var compact_words = [
-    'javascript', 'expression', 'vbscript',
-    'script', 'base64', 'applet', 'alert',
-    'document', 'write', 'cookie', 'window'
-];
-
-exports.clean = function(str, is_image) {
-
-    //Remove invisible characters
-    str = remove_invisible_characters(str);
-
-    //Protect query string variables in URLs => 901119URL5918AMP18930PROTECT8198
-    var hash;
-    do {
-      // ensure str does not contain hash before inserting it
-      hash = xss_hash();
-    } while(str.indexOf(hash) >= 0)
-    str = str.replace(/\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)/ig, hash + '$1=$2');
-
-    //Validate standard character entities. Add a semicolon if missing.  We do this to enable
-    //the conversion of entities to ASCII later.
-    str = str.replace(/(&#?[0-9a-z]{2,})([\x00-\x20])*;?/ig, '$1;$2');
-
-    //Validate UTF16 two byte encoding (x00) - just as above, adds a semicolon if missing.
-    str = str.replace(/(&#x?)([0-9A-F]+);?/ig, '$1$2;');
-
-    //Un-protect query string variables
-    str = str.replace(new RegExp(hash, 'g'), '&');
-
-    //Decode just in case stuff like this is submitted:
-    //<a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
-    try{  
-      str = decodeURIComponent(str);
-    }
-    catch(error){
-      // str was not actually URI-encoded
-    }
-
-    //Convert character entities to ASCII - this permits our tests below to work reliably.
-    //We only convert entities that are within tags since these are the ones that will pose security problems.
-    str = str.replace(/[a-z]+=([\'\"]).*?\1/gi, function(m, match) {
-        return m.replace(match, convert_attribute(match));
-    });
-    str = str.replace(/<\w+.*/gi, function(m) {
-        return m.replace(m, html_entity_decode(m));
-    });
-
-    //Remove invisible characters again
-    str = remove_invisible_characters(str);
-
-    //Convert tabs to spaces
-    str = str.replace('\t', ' ');
-
-    //Captured the converted string for later comparison
-    var converted_string = str;
-
-    //Remove strings that are never allowed
-    for (var i in never_allowed_str) {
-        str = str.replace(new RegExp(i, "gi"), never_allowed_str[i]);
-    }
-
-    //Remove regex patterns that are never allowed
-    for (var i in never_allowed_regex) {
-        str = str.replace(new RegExp(i, 'gi'), never_allowed_regex[i]);
-    }
-
-    //Compact any exploded words like:  j a v a s c r i p t
-    // We only want to do this when it is followed by a non-word character
-    for (var i = 0, l = compact_words.length; i < l; i++) {
-        var spacified = compact_words[i].split('').join('\\s*')+'\\s*';
-
-        str = str.replace(new RegExp('('+spacified+')(\\W)', 'ig'), function(m, compat, after) {
-            return compat.replace(/\s+/g, '') + after;
-        });
-    }
-
-    //Remove disallowed Javascript in links or img tags
-    do {
-        var original = str;
-
-        if (str.match(/<a/i)) {
-            str = str.replace(/<a\s+([^>]*?)(>|$)/gi, function(m, attributes, end_tag) {
-                var filtered_attributes = filter_attributes(attributes.replace('<','').replace('>',''));
-                filtered_attributes = filtered_attributes.replace(/href=.*?(?:alert\(|alert&#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)/gi, '');
-                return m.replace(attributes, filtered_attributes);
-            });
-        }
-
-        if (str.match(/<img/i)) {
-            str = str.replace(/<img\s+([^>]*?)(\s?\/?>|$)/gi, function(m, attributes, end_tag) {
-                var filtered_attributes = filter_attributes(attributes.replace('<','').replace('>',''));
-                filtered_attributes = filtered_attributes.replace(/src=.*?(?:alert\(|alert&#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, '');
-                return m.replace(attributes, filtered_attributes);
-            });
-        }
-
-        if (str.match(/script/i) || str.match(/xss/i)) {
-            str = str.replace(/<(\/*)(script|xss)(.*?)\>/gi, '[removed]');
-        }
-
-    } while(original !== str);
-
-    // Remove Evil HTML Attributes (like event handlers and style)
-    var event_handlers = ['\\bon\\w*', '\\bstyle', '\\bformaction'];
-
-    //Adobe Photoshop puts XML metadata into JFIF images, including namespacing,
-    //so we have to allow this for images
-    if (!is_image) {
-        event_handlers.push('xmlns');
-    }
-
-    do {
-        var attribs = [];
-        var count = 0;
-
-        attribs = attribs.concat(str.match(new RegExp("("+event_handlers.join('|')+")\\s*=\\s*(\\x22|\\x27)([^\\2]*?)(\\2)", 'ig')));
-        attribs = attribs.concat(str.match(new RegExp("("+event_handlers.join('|')+")\\s*=\\s*([^\\s>]*)", 'ig')));
-        attribs = attribs.filter(function(element) { return element !== null; });
-
-        if (attribs.length > 0) {
-            for (var i = 0; i < attribs.length; ++i) {
-                attribs[i] = attribs[i].replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'), '\\$&')
-            }
-
-            str = str.replace(new RegExp("(<?)(\/?[^><]+?)([^A-Za-z<>\\-])(.*?)("+attribs.join('|')+")(.*?)([\\s><]?)([><]*)", 'i'), function(m, a, b, c, d, e, f, g, h) {
-                ++count;
-                return a + b + ' ' + d + f + g + h;
-            });
-        }
-    } while (count > 0);
-
-    //Sanitize naughty HTML elements
-    //If a tag containing any of the words in the list
-    //below is found, the tag gets converted to entities.
-    //So this: <blink>
-    //Becomes: &lt;blink&gt;
-    var naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
-    str = str.replace(new RegExp('<(/*\\s*)('+naughty+')([^><]*)([><]*)', 'gi'), function(m, a, b, c, d) {
-        return '&lt;' + a + b + c + d.replace('>','&gt;').replace('<','&lt;');
-    });
-
-    //Sanitize naughty scripting elements Similar to above, only instead of looking for
-    //tags it looks for PHP and JavaScript commands that are disallowed.  Rather than removing the
-    //code, it simply converts the parenthesis to entities rendering the code un-executable.
-    //For example:    eval('some code')
-    //Becomes:        eval&#40;'some code'&#41;
-    str = str.replace(/(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)/gi, '$1$2&#40;$3&#41;');
-
-    //This adds a bit of extra precaution in case something got through the above filters
-    for (var i in never_allowed_str) {
-        str = str.replace(new RegExp(i, "gi"), never_allowed_str[i]);
-    }
-    for (var i in never_allowed_regex) {
-        str = str.replace(new RegExp(i, 'gi'), never_allowed_regex[i]);
-    }
-
-    //Images are handled in a special way
-    if (is_image && str !== converted_string) {
-        throw new Error('Image may contain XSS');
-    }
-
-    return str;
-}
-
-function remove_invisible_characters(str) {
-    for (var i = 0, l = non_displayables.length; i < l; i++) {
-        str = str.replace(non_displayables[i], '');
-    }
-    return str;
-}
-
-function xss_hash() {
-    var str = '', num = 10;
-    while (num--) str += String.fromCharCode(Math.random() * 25 | 97);
-    return str;
-}
-
-function convert_attribute(str) {
-    return str.replace('>','&gt;').replace('<','&lt;').replace('\\','\\\\');
-}
-
-function filter_attributes(str) {
-    var result = "";
-
-    var match = str.match(/\s*[a-z-]+\s*=\s*(\x22|\x27)([^\1]*?)\1/ig);
-    if (match) {
-        for (var i = 0; i < match.length; ++i) {
-            result += match[i].replace(/\*.*?\*/g, '');
-        }
-    }
-
-    return result;
-}
-
diff --git a/package.json b/package.json
index f2b7bcd57..bf5f62f02 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "description"   : "Data validation, filtering and sanitization for node.js",
   "version"       : "1.5.1",
   "homepage"      : "http://github.com/chriso/node-validator",
-  "keywords"      : ["validator", "validation", "assert", "params", "sanitization", "xss", "entities", "sanitize", "sanitisation", "input"],
+  "keywords"      : ["validator", "validation", "assert", "params", "sanitization", "entities", "sanitize", "sanitisation", "input"],
   "author"        : "Chris O'Hara <cohara87@gmail.com>",
   "main"          : "./lib",
   "directories"   : { "lib" : "./lib" },
diff --git a/test/filter.test.js b/test/filter.test.js
index 65f3b68c4..99e288b17 100755
--- a/test/filter.test.js
+++ b/test/filter.test.js
@@ -132,39 +132,6 @@ module.exports = {
         assert.equal('&frac12;', Filter.sanitize('½').entityEncode());
     },
 
-    'test #xss()': function () {
-        //Need more tests!
-        assert.equal('[removed] foobar', Filter.sanitize('javascript  : foobar').xss());
-        assert.equal('[removed] foobar', Filter.sanitize('j a vasc ri pt: foobar').xss());
-        assert.equal('<a >some text</a>', Filter.sanitize('<a href="javascript:alert(\'xss\')">some text</a>').xss());
-
-        assert.equal('<s <> <s >This is a test</s>', Filter.sanitize('<s <onmouseover="alert(1)"> <s onmouseover="alert(1)">This is a test</s>').xss());
-        assert.equal('<a >">test</a>', Filter.sanitize('<a href="javascriptJ a V a S c R iPt::alert(1)" "<s>">test</a>').xss());
-        assert.equal('<div ><h1>You have won</h1>Please click the link and enter your login details: <a href="http://example.com/">http://good.com</a></div>', Filter.sanitize('<div style="z-index: 9999999; background-color: green; width: 100%; height: 100%"><h1>You have won</h1>Please click the link and enter your login details: <a href="http://example.com/">http://good.com</a></div>').xss());
-        assert.equal('<scrRedirec[removed]t 302ipt type="text/javascript">prompt(1);</scrRedirec[removed]t 302ipt>', Filter.sanitize('<scrRedirecRedirect 302t 302ipt type="text/javascript">prompt(1);</scrRedirecRedirect 302t 302ipt>').xss());
-        assert.equal('<img src="a" ', Filter.sanitize('<img src="a" onerror=\'eval(atob("cHJvbXB0KDEpOw=="))\'').xss());
-
-
-        // Source: http://blog.kotowicz.net/2012/07/codeigniter-210-xssclean-cross-site.html
-        assert.equal('<img src=">" >', Filter.sanitize('<img/src=">" onerror=alert(1)>').xss());
-        assert.equal('<button a=">" autofocus ></button>', Filter.sanitize('<button/a=">" autofocus onfocus=alert&#40;1&#40;></button>').xss());
-        assert.equal('<button a=">" autofocus >', Filter.sanitize('<button a=">" autofocus onfocus=alert&#40;1&#40;>').xss());
-        assert.equal('<a target="_blank">clickme in firefox</a>', Filter.sanitize('<a target="_blank" href="data:text/html;BASE64youdummy,PHNjcmlwdD5hbGVydCh3aW5kb3cub3BlbmVyLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5pbm5lckhUTUwpPC9zY3JpcHQ+">clickme in firefox</a>').xss());
-        assert.equal('<a/\'\'\' target="_blank" href=[removed]PHNjcmlwdD5hbGVydChvcGVuZXIuZG9jdW1lbnQuYm9keS5pbm5lckhUTUwpPC9zY3JpcHQ+>firefox11</a>', Filter.sanitize('<a/\'\'\' target="_blank" href=data:text/html;;base64,PHNjcmlwdD5hbGVydChvcGVuZXIuZG9jdW1lbnQuYm9keS5pbm5lckhUTUwpPC9zY3JpcHQ+>firefox11</a>').xss());
-
-        var url = 'http://www.example.com/test.php?a=b&b=c&c=d';
-        assert.equal(url, Filter.sanitize(url).xss());
-    },
-
-    'test chaining': function () {
-        assert.equal('&amp;amp;amp;', Filter.sanitize('&').chain().entityEncode().entityEncode().entityEncode().value());
-
-        //Return the default behaviour
-        Filter.wrap = function (str) {
-            return str;
-        }
-    },
-
     'test #escape': function () {
         assert.equal('&amp;&lt;&quot;&gt;', Filter.sanitize('&<">').escape());
     }
diff --git a/validator-min.js b/validator-min.js
index 9b39281cc..5cf9befdc 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(root,factory){if(typeof define === 'function' && define.amd){define(['exports'],factory);}else if(typeof exports === 'object'){factory(exports);}else{factory(root);}}(this,function(t){var r={"&nbsp;":" ","&iexcl;":"¡","&cent;":"¢","&pound;":"£","&curren;":"€","&yen;":"¥","&brvbar;":"Š","&sect;":"§","&uml;":"š","&copy;":"©","&ordf;":"ª","&laquo;":"«","&not;":"¬","&shy;":"­","&reg;":"®","&macr;":"¯","&deg;":"°","&plusmn;":"±","&sup2;":"²","&sup3;":"³","&acute;":"Ž","&micro;":"µ","&para;":"¶","&middot;":"·","&cedil;":"ž","&sup1;":"¹","&ordm;":"º","&raquo;":"»","&frac14;":"Œ","&frac12;":"œ","&frac34;":"Ÿ","&iquest;":"¿","&Agrave;":"À","&Aacute;":"Á","&Acirc;":"Â","&Atilde;":"Ã","&Auml;":"Ä","&Aring;":"Å","&AElig;":"Æ","&Ccedil;":"Ç","&Egrave;":"È","&Eacute;":"É","&Ecirc;":"Ê","&Euml;":"Ë","&Igrave;":"Ì","&Iacute;":"Í","&Icirc;":"Î","&Iuml;":"Ï","&ETH;":"Ð","&Ntilde;":"Ñ","&Ograve;":"Ò","&Oacute;":"Ó","&Ocirc;":"Ô","&Otilde;":"Õ","&Ouml;":"Ö","&times;":"×","&Oslash;":"Ø","&Ugrave;":"Ù","&Uacute;":"Ú","&Ucirc;":"Û","&Uuml;":"Ü","&Yacute;":"Ý","&THORN;":"Þ","&szlig;":"ß","&agrave;":"à","&aacute;":"á","&acirc;":"â","&atilde;":"ã","&auml;":"ä","&aring;":"å","&aelig;":"æ","&ccedil;":"ç","&egrave;":"è","&eacute;":"é","&ecirc;":"ê","&euml;":"ë","&igrave;":"ì","&iacute;":"í","&icirc;":"î","&iuml;":"ï","&eth;":"ð","&ntilde;":"ñ","&ograve;":"ò","&oacute;":"ó","&ocirc;":"ô","&otilde;":"õ","&ouml;":"ö","&divide;":"÷","&oslash;":"ø","&ugrave;":"ù","&uacute;":"ú","&ucirc;":"û","&uuml;":"ü","&yacute;":"ý","&thorn;":"þ","&yuml;":"ÿ","&quot;":'"',"&lt;":"<","&gt;":">","&apos;":"'","&minus;":"−","&circ;":"ˆ","&tilde;":"˜","&Scaron;":"Š","&lsaquo;":"‹","&OElig;":"Œ","&lsquo;":"‘","&rsquo;":"’","&ldquo;":"“","&rdquo;":"”","&bull;":"•","&ndash;":"–","&mdash;":"—","&trade;":"™","&scaron;":"š","&rsaquo;":"›","&oelig;":"œ","&Yuml;":"Ÿ","&fnof;":"ƒ","&Alpha;":"Α","&Beta;":"Β","&Gamma;":"Γ","&Delta;":"Δ","&Epsilon;":"Ε","&Zeta;":"Ζ","&Eta;":"Η","&Theta;":"Θ","&Iota;":"Ι","&Kappa;":"Κ","&Lambda;":"Λ","&Mu;":"Μ","&Nu;":"Ν","&Xi;":"Ξ","&Omicron;":"Ο","&Pi;":"Π","&Rho;":"Ρ","&Sigma;":"Σ","&Tau;":"Τ","&Upsilon;":"Υ","&Phi;":"Φ","&Chi;":"Χ","&Psi;":"Ψ","&Omega;":"Ω","&alpha;":"α","&beta;":"β","&gamma;":"γ","&delta;":"δ","&epsilon;":"ε","&zeta;":"ζ","&eta;":"η","&theta;":"θ","&iota;":"ι","&kappa;":"κ","&lambda;":"λ","&mu;":"μ","&nu;":"ν","&xi;":"ξ","&omicron;":"ο","&pi;":"π","&rho;":"ρ","&sigmaf;":"ς","&sigma;":"σ","&tau;":"τ","&upsilon;":"υ","&phi;":"φ","&chi;":"χ","&psi;":"ψ","&omega;":"ω","&thetasym;":"ϑ","&upsih;":"ϒ","&piv;":"ϖ","&ensp;":" ","&emsp;":" ","&thinsp;":" ","&zwnj;":"‌","&zwj;":"‍","&lrm;":"‎","&rlm;":"‏","&sbquo;":"‚","&bdquo;":"„","&dagger;":"†","&Dagger;":"‡","&hellip;":"…","&permil;":"‰","&prime;":"′","&Prime;":"″","&oline;":"‾","&frasl;":"⁄","&euro;":"€","&image;":"ℑ","&weierp;":"℘","&real;":"ℜ","&alefsym;":"ℵ","&larr;":"←","&uarr;":"↑","&rarr;":"→","&darr;":"↓","&harr;":"↔","&crarr;":"↵","&lArr;":"⇐","&uArr;":"⇑","&rArr;":"⇒","&dArr;":"⇓","&hArr;":"⇔","&forall;":"∀","&part;":"∂","&exist;":"∃","&empty;":"∅","&nabla;":"∇","&isin;":"∈","&notin;":"∉","&ni;":"∋","&prod;":"∏","&sum;":"∑","&lowast;":"∗","&radic;":"√","&prop;":"∝","&infin;":"∞","&ang;":"∠","&and;":"∧","&or;":"∨","&cap;":"∩","&cup;":"∪","&int;":"∫","&there4;":"∴","&sim;":"∼","&cong;":"≅","&asymp;":"≈","&ne;":"≠","&equiv;":"≡","&le;":"≤","&ge;":"≥","&sub;":"⊂","&sup;":"⊃","&nsub;":"⊄","&sube;":"⊆","&supe;":"⊇","&oplus;":"⊕","&otimes;":"⊗","&perp;":"⊥","&sdot;":"⋅","&lceil;":"⌈","&rceil;":"⌉","&lfloor;":"⌊","&rfloor;":"⌋","&lang;":"〈","&rang;":"〉","&loz;":"◊","&spades;":"♠","&clubs;":"♣","&hearts;":"♥","&diams;":"♦"};var e=function(t){if(!~t.indexOf("&"))return t;for(var e in r){t=t.replace(new RegExp(e,"g"),r[e])}t=t.replace(/&#x(0*[0-9a-f]{2,5});?/gi,function(t,r){return String.fromCharCode(parseInt(+r,16))});t=t.replace(/&#([0-9]{2,4});?/gi,function(t,r){return String.fromCharCode(+r)});t=t.replace(/&amp;/g,"&");return t};var i=function(t){t=t.replace(/&/g,"&amp;");t=t.replace(/'/g,"&#39;");for(var e in r){t=t.replace(new RegExp(r[e],"g"),e)}return t};t.entities={encode:i,decode:e};var s={"document.cookie":"","document.write":"",".parentNode":"",".innerHTML":"","window.location":"","-moz-binding":"","<!--":"&lt;!--","-->":"--&gt;","<![CDATA[":"&lt;![CDATA["};var n={"javascript\\s*:":"","expression\\s*(\\(|&\\#40;)":"","vbscript\\s*:":"","Redirect\\s+302":""};var a=[/%0[0-8bcef]/g,/%1[0-9a-f]/g,/[\x00-\x08]/g,/\x0b/g,/\x0c/g,/[\x0e-\x1f]/g];var o=["javascript","expression","vbscript","script","applet","alert","document","write","cookie","window"];t.xssClean=function(r,e){if(typeof r==="object"){for(var i in r){r[i]=t.xssClean(r[i])}return r}r=c(r);r=r.replace(/\&([a-z\_0-9]+)\=([a-z\_0-9]+)/i,u()+"$1=$2");r=r.replace(/(&\#?[0-9a-z]{2,})([\x00-\x20])*;?/i,"$1;$2");r=r.replace(/(&\#x?)([0-9A-F]+);?/i,"$1;$2");r=r.replace(u(),"&");try{r=decodeURIComponent(r)}catch(a){}r=r.replace(/[a-z]+=([\'\"]).*?\1/gi,function(t,r){return t.replace(r,p(r))});r=c(r);r=r.replace("	"," ");var l=r;for(var i in s){r=r.replace(i,s[i])}for(var i in n){r=r.replace(new RegExp(i,"i"),n[i])}for(var i in o){var f=o[i].split("").join("\\s*")+"\\s*";r=r.replace(new RegExp("("+f+")(\\W)","ig"),function(t,r,e){return r.replace(/\s+/g,"")+e})}do{var m=r;if(r.match(/<a/i)){r=r.replace(/<a\s+([^>]*?)(>|$)/gi,function(t,r,e){r=h(r.replace("<","").replace(">",""));return t.replace(r,r.replace(/href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi,""))})}if(r.match(/<img/i)){r=r.replace(/<img\s+([^>]*?)(\s?\/?>|$)/gi,function(t,r,e){r=h(r.replace("<","").replace(">",""));return t.replace(r,r.replace(/src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi,""))})}if(r.match(/script/i)||r.match(/xss/i)){r=r.replace(/<(\/*)(script|xss)(.*?)\>/gi,"")}}while(m!=r);event_handlers=["[^a-z_-]on\\w*"];if(!e){event_handlers.push("xmlns")}r=r.replace(new RegExp("<([^><]+?)("+event_handlers.join("|")+")(\\s*=\\s*[^><]*)([><]*)","i"),"<$1$4");naughty="alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss";r=r.replace(new RegExp("<(/*\\s*)("+naughty+")([^><]*)([><]*)","gi"),function(t,r,e,i,s){return"&lt;"+r+e+i+s.replace(">","&gt;").replace("<","&lt;")});r=r.replace(/(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)/gi,"$1$2&#40;$3&#41;");for(var i in s){r=r.replace(i,s[i])}for(var i in n){r=r.replace(new RegExp(i,"i"),n[i])}if(e&&r!==l){throw new Error("Image may contain XSS")}return r};function c(t){for(var r in a){t=t.replace(a[r],"")}return t}function u(){return"!*$^#(@*#&"}function p(t){return t.replace(">","&gt;").replace("<","&lt;").replace("\\","\\\\")}function h(t){var r=/\/\*.*?\*\//g;return t.replace(/\s*[a-z-]+\s*=\s*'[^']*'/gi,function(t){return t.replace(r,"")}).replace(/\s*[a-z-]+\s*=\s*"[^"]*"/gi,function(t){return t.replace(r,"")}).replace(/\s*[a-z-]+\s*=\s*[^\s]+/gi,function(t){return t.replace(r,"")})}var l=t.Validator=function(){};l.prototype.check=function(t,r){this.str=typeof t==="undefined"||t===null||isNaN(t)&&t.length===undefined?"":t+"";this.msg=r;this._errors=this._errors||[];return this};l.prototype.validate=l.prototype.check;l.prototype.assert=l.prototype.check;l.prototype.error=function(t){throw new Error(t)};function f(t){if(t instanceof Date){return t}var r=Date.parse(t);if(isNaN(r)){return null}return new Date(r)}l.prototype.isAfter=function(t){t=t||new Date;var r=f(this.str),e=f(t);if(!(r&&e&&r>=e)){return this.error(this.msg||"Invalid date")}return this};l.prototype.isBefore=function(t){t=t||new Date;var r=f(this.str),e=f(t);if(!(r&&e&&r<=e)){return this.error(this.msg||"Invalid date")}return this};l.prototype.isEmail=function(){if(!this.str.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/)){return this.error(this.msg||"Invalid email")}return this};l.prototype.isCreditCard=function(){this.str=this.str.replace(/[^0-9]+/g,"");if(!this.str.match(/^(?: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})$/)){return this.error(this.msg||"Invalid credit card")}var t=0;var r;var e;var i=false;for(var s=this.length-1;s>=0;s--){r=this.substring(s,s+1);e=parseInt(r,10);if(i){e*=2;if(e>=10){t+=e%10+1}else{t+=e}}else{t+=e}if(i){i=false}else{i=true}}if(t%10!==0){return this.error(this.msg||"Invalid credit card")}return this};l.prototype.isUrl=function(){if(!this.str.match(/^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i)||this.str.length>2083){return this.error(this.msg||"Invalid URL")}return this};l.prototype.isIP=function(){if(!this.str.match(/^(?:(?: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]?)$/)){return this.error(this.msg||"Invalid IP")}return this};l.prototype.isAlpha=function(){if(!this.str.match(/^[a-zA-Z]+$/)){return this.error(this.msg||"Invalid characters")}return this};l.prototype.isAlphanumeric=function(){if(!this.str.match(/^[a-zA-Z0-9]+$/)){return this.error(this.msg||"Invalid characters")}return this};l.prototype.isNumeric=function(){if(!this.str.match(/^-?[0-9]+$/)){return this.error(this.msg||"Invalid number")}return this};l.prototype.isLowercase=function(){if(!this.str.match(/^[a-z0-9]+$/)){return this.error(this.msg||"Invalid characters")}return this};l.prototype.isUppercase=function(){if(!this.str.match(/^[A-Z0-9]+$/)){return this.error(this.msg||"Invalid characters")}return this};l.prototype.isInt=function(){if(!this.str.match(/^(?:-?(?:0|[1-9][0-9]*))$/)){return this.error(this.msg||"Invalid integer")}return this};l.prototype.isDecimal=function(){if(!this.str.match(/^(?:-?(?:0|[1-9][0-9]*))?(?:\.[0-9]*)?$/)){return this.error(this.msg||"Invalid decimal")}return this};l.prototype.isFloat=function(){return this.isDecimal()};l.prototype.notNull=function(){if(this.str===""){return this.error(this.msg||"Invalid characters")}return this};l.prototype.isNull=function(){if(this.str!==""){return this.error(this.msg||"Invalid characters")}return this};l.prototype.notEmpty=function(){if(this.str.match(/^[\s\t\r\n]*$/)){return this.error(this.msg||"String is whitespace")}return this};l.prototype.equals=function(t){if(this.str!=t){return this.error(this.msg||"Not equal")}return this};l.prototype.contains=function(t){if(this.str.indexOf(t)===-1){return this.error(this.msg||"Invalid characters")}return this};l.prototype.notContains=function(t){if(this.str.indexOf(t)>=0){return this.error(this.msg||"Invalid characters")}return this};l.prototype.regex=l.prototype.is=function(t,r){if(Object.prototype.toString.call(t).slice(8,-1)!=="RegExp"){t=new RegExp(t,r)}if(!this.str.match(t)){return this.error(this.msg||"Invalid characters")}return this};l.prototype.notRegex=l.prototype.not=function(t,r){if(Object.prototype.toString.call(t).slice(8,-1)!=="RegExp"){t=new RegExp(t,r)}if(this.str.match(t)){this.error(this.msg||"Invalid characters")}return this};l.prototype.len=function(t,r){if(this.str.length<t){return this.error(this.msg||"String is too small")}if(typeof r!==undefined&&this.str.length>r){return this.error(this.msg||"String is too large")}return this};l.prototype.isUUID=function(t){var r;if(t==3||t=="v3"){r=/[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i}else if(t==4||t=="v4"){r=/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i}else{r=/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i}if(!this.str.match(r)){return this.error(this.msg||"Not a UUID")}return this};l.prototype.isDate=function(){var t=Date.parse(this.str);if(isNaN(t)){return this.error(this.msg||"Not a date")}return this};l.prototype.isIn=function(t){if(t&&typeof t.indexOf==="function"){if(!~t.indexOf(this.str)){return this.error(this.msg||"Unexpected value")}return this}else{return this.error(this.msg||"Invalid in() argument")}};l.prototype.notIn=function(t){if(t&&typeof t.indexOf==="function"){if(t.indexOf(this.str)!==-1){return this.error(this.msg||"Unexpected value")}return this}else{return this.error(this.msg||"Invalid notIn() argument")}};l.prototype.min=function(t){var r=parseFloat(this.str);if(!isNaN(r)&&r<t){return this.error(this.msg||"Invalid number")}return this};l.prototype.max=function(t){var r=parseFloat(this.str);if(!isNaN(r)&&r>t){return this.error(this.msg||"Invalid number")}return this};l.prototype.isArray=function(){if(!Array.isArray(this.str)){return this.error(this.msg||"Not an array")}return this};var m=t.Filter=function(){};var d="\\r\\n\\t\\s";m.prototype.modify=function(t){this.str=t};m.prototype.convert=m.prototype.sanitize=function(t){this.str=t==null?"":t+"";return this};m.prototype.xss=function(r){this.modify(t.xssClean(this.str,r));return this.str};m.prototype.entityDecode=function(){this.modify(e(this.str));return this.str};m.prototype.entityEncode=function(){this.modify(i(this.str));return this.str};m.prototype.escape=function(){this.modify(this.str.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;"));return this.str};m.prototype.ltrim=function(t){t=t||d;this.modify(this.str.replace(new RegExp("^["+t+"]+","g"),""));return this.str};m.prototype.rtrim=function(t){t=t||d;this.modify(this.str.replace(new RegExp("["+t+"]+$","g"),""));return this.str};m.prototype.trim=function(t){t=t||d;this.modify(this.str.replace(new RegExp("^["+t+"]+|["+t+"]+$","g"),""));return this.str};m.prototype.ifNull=function(t){if(!this.str||this.str===""){this.modify(t)}return this.str};m.prototype.toFloat=function(){this.modify(parseFloat(this.str));return this.str};m.prototype.toInt=function(t){t=t||10;this.modify(parseInt(this.str,t));return this.str};m.prototype.toBoolean=function(){if(!this.str||this.str=="0"||this.str=="false"||this.str==""){this.modify(false)}else{this.modify(true)}return this.str};m.prototype.toBooleanStrict=function(){if(this.str=="1"||this.str=="true"){this.modify(true)}else{this.modify(false)}return this.str};t.sanitize=t.convert=function(r){var e=new t.Filter;return e.sanitize(r)};t.check=t.validate=t.assert=function(r,e){var i=new t.Validator;return i.check(r,e)};return t;}));
+(function(e,t){typeof define=="function"&&define.amd?define(["exports"],t):typeof exports=="object"?t(exports):t(e)})(this,function(e){function s(e){if(/^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/.test(e)){var t=e.split(".").sort();return t[3]>255?!1:!0}return!1}function o(e){return/^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$/.test(e)?!0:!1}function u(e){if(e instanceof Date)return e;var t=Date.parse(e);return isNaN(t)?null:new Date(t)}var t={"&nbsp;":"\u00a0","&iexcl;":"\u00a1","&cent;":"\u00a2","&pound;":"\u00a3","&curren;":"\u20ac","&yen;":"\u00a5","&brvbar;":"\u0160","&sect;":"\u00a7","&uml;":"\u0161","&copy;":"\u00a9","&ordf;":"\u00aa","&laquo;":"\u00ab","&not;":"\u00ac","&shy;":"\u00ad","&reg;":"\u00ae","&macr;":"\u00af","&deg;":"\u00b0","&plusmn;":"\u00b1","&sup2;":"\u00b2","&sup3;":"\u00b3","&acute;":"\u017d","&micro;":"\u00b5","&para;":"\u00b6","&middot;":"\u00b7","&cedil;":"\u017e","&sup1;":"\u00b9","&ordm;":"\u00ba","&raquo;":"\u00bb","&frac14;":"\u0152","&frac12;":"\u0153","&frac34;":"\u0178","&iquest;":"\u00bf","&Agrave;":"\u00c0","&Aacute;":"\u00c1","&Acirc;":"\u00c2","&Atilde;":"\u00c3","&Auml;":"\u00c4","&Aring;":"\u00c5","&AElig;":"\u00c6","&Ccedil;":"\u00c7","&Egrave;":"\u00c8","&Eacute;":"\u00c9","&Ecirc;":"\u00ca","&Euml;":"\u00cb","&Igrave;":"\u00cc","&Iacute;":"\u00cd","&Icirc;":"\u00ce","&Iuml;":"\u00cf","&ETH;":"\u00d0","&Ntilde;":"\u00d1","&Ograve;":"\u00d2","&Oacute;":"\u00d3","&Ocirc;":"\u00d4","&Otilde;":"\u00d5","&Ouml;":"\u00d6","&times;":"\u00d7","&Oslash;":"\u00d8","&Ugrave;":"\u00d9","&Uacute;":"\u00da","&Ucirc;":"\u00db","&Uuml;":"\u00dc","&Yacute;":"\u00dd","&THORN;":"\u00de","&szlig;":"\u00df","&agrave;":"\u00e0","&aacute;":"\u00e1","&acirc;":"\u00e2","&atilde;":"\u00e3","&auml;":"\u00e4","&aring;":"\u00e5","&aelig;":"\u00e6","&ccedil;":"\u00e7","&egrave;":"\u00e8","&eacute;":"\u00e9","&ecirc;":"\u00ea","&euml;":"\u00eb","&igrave;":"\u00ec","&iacute;":"\u00ed","&icirc;":"\u00ee","&iuml;":"\u00ef","&eth;":"\u00f0","&ntilde;":"\u00f1","&ograve;":"\u00f2","&oacute;":"\u00f3","&ocirc;":"\u00f4","&otilde;":"\u00f5","&ouml;":"\u00f6","&divide;":"\u00f7","&oslash;":"\u00f8","&ugrave;":"\u00f9","&uacute;":"\u00fa","&ucirc;":"\u00fb","&uuml;":"\u00fc","&yacute;":"\u00fd","&thorn;":"\u00fe","&yuml;":"\u00ff","&quot;":'"',"&lt;":"<","&gt;":">","&apos;":"'","&minus;":"\u2212","&circ;":"\u02c6","&tilde;":"\u02dc","&Scaron;":"\u0160","&lsaquo;":"\u2039","&OElig;":"\u0152","&lsquo;":"\u2018","&rsquo;":"\u2019","&ldquo;":"\u201c","&rdquo;":"\u201d","&bull;":"\u2022","&ndash;":"\u2013","&mdash;":"\u2014","&trade;":"\u2122","&scaron;":"\u0161","&rsaquo;":"\u203a","&oelig;":"\u0153","&Yuml;":"\u0178","&fnof;":"\u0192","&Alpha;":"\u0391","&Beta;":"\u0392","&Gamma;":"\u0393","&Delta;":"\u0394","&Epsilon;":"\u0395","&Zeta;":"\u0396","&Eta;":"\u0397","&Theta;":"\u0398","&Iota;":"\u0399","&Kappa;":"\u039a","&Lambda;":"\u039b","&Mu;":"\u039c","&Nu;":"\u039d","&Xi;":"\u039e","&Omicron;":"\u039f","&Pi;":"\u03a0","&Rho;":"\u03a1","&Sigma;":"\u03a3","&Tau;":"\u03a4","&Upsilon;":"\u03a5","&Phi;":"\u03a6","&Chi;":"\u03a7","&Psi;":"\u03a8","&Omega;":"\u03a9","&alpha;":"\u03b1","&beta;":"\u03b2","&gamma;":"\u03b3","&delta;":"\u03b4","&epsilon;":"\u03b5","&zeta;":"\u03b6","&eta;":"\u03b7","&theta;":"\u03b8","&iota;":"\u03b9","&kappa;":"\u03ba","&lambda;":"\u03bb","&mu;":"\u03bc","&nu;":"\u03bd","&xi;":"\u03be","&omicron;":"\u03bf","&pi;":"\u03c0","&rho;":"\u03c1","&sigmaf;":"\u03c2","&sigma;":"\u03c3","&tau;":"\u03c4","&upsilon;":"\u03c5","&phi;":"\u03c6","&chi;":"\u03c7","&psi;":"\u03c8","&omega;":"\u03c9","&thetasym;":"\u03d1","&upsih;":"\u03d2","&piv;":"\u03d6","&ensp;":"\u2002","&emsp;":"\u2003","&thinsp;":"\u2009","&zwnj;":"\u200c","&zwj;":"\u200d","&lrm;":"\u200e","&rlm;":"\u200f","&sbquo;":"\u201a","&bdquo;":"\u201e","&dagger;":"\u2020","&Dagger;":"\u2021","&hellip;":"\u2026","&permil;":"\u2030","&prime;":"\u2032","&Prime;":"\u2033","&oline;":"\u203e","&frasl;":"\u2044","&euro;":"\u20ac","&image;":"\u2111","&weierp;":"\u2118","&real;":"\u211c","&alefsym;":"\u2135","&larr;":"\u2190","&uarr;":"\u2191","&rarr;":"\u2192","&darr;":"\u2193","&harr;":"\u2194","&crarr;":"\u21b5","&lArr;":"\u21d0","&uArr;":"\u21d1","&rArr;":"\u21d2","&dArr;":"\u21d3","&hArr;":"\u21d4","&forall;":"\u2200","&part;":"\u2202","&exist;":"\u2203","&empty;":"\u2205","&nabla;":"\u2207","&isin;":"\u2208","&notin;":"\u2209","&ni;":"\u220b","&prod;":"\u220f","&sum;":"\u2211","&lowast;":"\u2217","&radic;":"\u221a","&prop;":"\u221d","&infin;":"\u221e","&ang;":"\u2220","&and;":"\u2227","&or;":"\u2228","&cap;":"\u2229","&cup;":"\u222a","&int;":"\u222b","&there4;":"\u2234","&sim;":"\u223c","&cong;":"\u2245","&asymp;":"\u2248","&ne;":"\u2260","&equiv;":"\u2261","&le;":"\u2264","&ge;":"\u2265","&sub;":"\u2282","&sup;":"\u2283","&nsub;":"\u2284","&sube;":"\u2286","&supe;":"\u2287","&oplus;":"\u2295","&otimes;":"\u2297","&perp;":"\u22a5","&sdot;":"\u22c5","&lceil;":"\u2308","&rceil;":"\u2309","&lfloor;":"\u230a","&rfloor;":"\u230b","&lang;":"\u2329","&rang;":"\u232a","&loz;":"\u25ca","&spades;":"\u2660","&clubs;":"\u2663","&hearts;":"\u2665","&diams;":"\u2666"},n=function(e){if(!~e.indexOf("&"))return e;for(var n in t)e=e.replace(new RegExp(n,"g"),t[n]);return e=e.replace(/&#x(0*[0-9a-f]{2,5});?/gi,function(e,t){return String.fromCharCode(parseInt(+t,16))}),e=e.replace(/&#([0-9]{2,4});?/gi,function(e,t){return String.fromCharCode(+t)}),e=e.replace(/&amp;/g,"&"),e},r=function(e){e=e.replace(/&/g,"&amp;"),e=e.replace(/'/g,"&#39;");for(var n in t)e=e.replace(new RegExp(t[n],"g"),n);return e};e.entities={encode:r,decode:n};var i=e.Validator=function(){};i.prototype.check=function(e,t){return this.str=typeof e=="undefined"||e===null||isNaN(e)&&e.length===undefined?"":e+"",this.msg=t,this._errors=this._errors||[],this},i.prototype.validate=i.prototype.check,i.prototype.assert=i.prototype.check,i.prototype.error=function(e){throw new Error(e)},i.prototype.isAfter=function(e){e=e||new Date;var t=u(this.str),n=u(e);return t&&n&&t>=n?this:this.error(this.msg||"Invalid date")},i.prototype.isBefore=function(e){e=e||new Date;var t=u(this.str),n=u(e);return t&&n&&t<=n?this:this.error(this.msg||"Invalid date")},i.prototype.isEmail=function(){return this.str.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/)?this:this.error(this.msg||"Invalid email")},i.prototype.isCreditCard=function(){this.str=this.str.replace(/[^0-9]+/g,"");if(!this.str.match(/^(?: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})$/))return this.error(this.msg||"Invalid credit card");var e=0,t,n,r=!1;for(var i=this.length-1;i>=0;i--)t=this.substring(i,i+1),n=parseInt(t,10),r?(n*=2,n>=10?e+=n%10+1:e+=n):e+=n,r?r=!1:r=!0;return e%10!==0?this.error(this.msg||"Invalid credit card"):this},i.prototype.isUrl=function(){return!this.str.match(/^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i)||this.str.length>2083?this.error(this.msg||"Invalid URL"):this},i.prototype.isIPv4=function(){return s(this.str)?this:this.error(this.msg||"Invalid IP")},i.prototype.isIPv6=function(){return o(this.str)?this:this.error(this.msg||"Invalid IP")},i.prototype.isIP=function(){return s(this.str)||o(this.str)?this:this.error(this.msg||"Invalid IP")},i.prototype.isAlpha=function(){return this.str.match(/^[a-zA-Z]+$/)?this:this.error(this.msg||"Invalid characters")},i.prototype.isAlphanumeric=function(){return this.str.match(/^[a-zA-Z0-9]+$/)?this:this.error(this.msg||"Invalid characters")},i.prototype.isNumeric=function(){return this.str.match(/^-?[0-9]+$/)?this:this.error(this.msg||"Invalid number")},i.prototype.isHexadecimal=function(){return this.str.match(/^[0-9a-fA-F]+$/)?this:this.error(this.msg||"Invalid hexadecimal")},i.prototype.isHexColor=function(){return this.str.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)?this:this.error(this.msg||"Invalid hexcolor")},i.prototype.isLowercase=function(){return this.str!==this.str.toLowerCase()?this.error(this.msg||"Invalid characters"):this},i.prototype.isUppercase=function(){return this.str!==this.str.toUpperCase()?this.error(this.msg||"Invalid characters"):this},i.prototype.isInt=function(){return this.str.match(/^(?:-?(?:0|[1-9][0-9]*))$/)?this:this.error(this.msg||"Invalid integer")},i.prototype.isDecimal=function(){return this.str.match(/^(?:-?(?:0|[1-9][0-9]*))?(?:\.[0-9]*)?$/)?this:this.error(this.msg||"Invalid decimal")},i.prototype.isDivisibleBy=function(e){return parseFloat(this.str)%parseInt(e,10)===0},i.prototype.isFloat=function(){return this.isDecimal()},i.prototype.notNull=function(){return this.str===""?this.error(this.msg||"String is empty"):this},i.prototype.isNull=function(){return this.str!==""?this.error(this.msg||"String is not empty"):this},i.prototype.notEmpty=function(){return this.str.match(/^[\s\t\r\n]*$/)?this.error(this.msg||"String is whitespace"):this},i.prototype.equals=function(e){return this.str!=e?this.error(this.msg||"Not equal"):this},i.prototype.contains=function(e){return this.str.indexOf(e)===-1||!e?this.error(this.msg||"Invalid characters"):this},i.prototype.notContains=function(e){return this.str.indexOf(e)>=0?this.error(this.msg||"Invalid characters"):this},i.prototype.regex=i.prototype.is=function(e,t){return Object.prototype.toString.call(e).slice(8,-1)!=="RegExp"&&(e=new RegExp(e,t)),this.str.match(e)?this:this.error(this.msg||"Invalid characters")},i.prototype.notRegex=i.prototype.not=function(e,t){return Object.prototype.toString.call(e).slice(8,-1)!=="RegExp"&&(e=new RegExp(e,t)),this.str.match(e)&&this.error(this.msg||"Invalid characters"),this},i.prototype.len=function(e,t){return this.str.length<e?this.error(this.msg||"String is too small"):typeof t!==undefined&&this.str.length>t?this.error(this.msg||"String is too large"):this},i.prototype.isUUID=function(e){var t;return e==3||e=="v3"?t=/[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i:e==4||e=="v4"?t=/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i:e==5||e=="v5"?t=/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i:t=/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,this.str.match(t)?this:this.error(this.msg||"Not a UUID")},i.prototype.isUUIDv3=function(){return this.isUUID(3)},i.prototype.isUUIDv4=function(){return this.isUUID(4)},i.prototype.isUUIDv5=function(){return this.isUUID(5)},i.prototype.isDate=function(){var e=Date.parse(this.str);return isNaN(e)?this.error(this.msg||"Not a date"):this},i.prototype.isIn=function(e){return e&&typeof e.indexOf=="function"?~e.indexOf(this.str)?this:this.error(this.msg||"Unexpected value"):this.error(this.msg||"Invalid in() argument")},i.prototype.notIn=function(e){return e&&typeof e.indexOf=="function"?e.indexOf(this.str)!==-1?this.error(this.msg||"Unexpected value"):this:this.error(this.msg||"Invalid notIn() argument")},i.prototype.min=function(e){var t=parseFloat(this.str);return!isNaN(t)&&t<e?this.error(this.msg||"Invalid number"):this},i.prototype.max=function(e){var t=parseFloat(this.str);return!isNaN(t)&&t>e?this.error(this.msg||"Invalid number"):this};var a=e.Filter=function(){},f="\\r\\n\\t\\s";return a.prototype.modify=function(e){this.str=e},a.prototype.convert=a.prototype.sanitize=function(e){return this.str=e==null?"":e+"",this},a.prototype.entityDecode=function(){return this.modify(n(this.str)),this.str},a.prototype.entityEncode=function(){return this.modify(r(this.str)),this.str},a.prototype.escape=function(){return this.modify(this.str.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")),this.str},a.prototype.ltrim=function(e){return e=e||f,this.modify(this.str.replace(new RegExp("^["+e+"]+","g"),"")),this.str},a.prototype.rtrim=function(e){return e=e||f,this.modify(this.str.replace(new RegExp("["+e+"]+$","g"),"")),this.str},a.prototype.trim=function(e){return e=e||f,this.modify(this.str.replace(new RegExp("^["+e+"]+|["+e+"]+$","g"),"")),this.str},a.prototype.ifNull=function(e){return(!this.str||this.str==="")&&this.modify(e),this.str},a.prototype.toFloat=function(){return this.modify(parseFloat(this.str)),this.str},a.prototype.toInt=function(e){return e=e||10,this.modify(parseInt(this.str,e)),this.str},a.prototype.toBoolean=function(){return!this.str||this.str=="0"||this.str=="false"||this.str==""?this.modify(!1):this.modify(!0),this.str},a.prototype.toBooleanStrict=function(){return this.str=="1"||this.str=="true"?this.modify(!0):this.modify(!1),this.str},e.sanitize=e.convert=function(t){var n=new e.Filter;return n.sanitize(t)},e.check=e.validate=e.assert=function(t,n){var r=new e.Validator;return r.check(t,n)},e});
diff --git a/validator.js b/validator.js
index acf7c4229..62eee2a9e 100644
--- a/validator.js
+++ b/validator.js
@@ -335,208 +335,6 @@
         decode: decode
     }
 
-    //This module is adapted from the CodeIgniter framework
-    //The license is available at http://codeigniter.com/
-
-    var never_allowed_str = {
-        'document.cookie':              '',
-        'document.write':               '',
-        '.parentNode':                  '',
-        '.innerHTML':                   '',
-        'window.location':              '',
-        '-moz-binding':                 '',
-        '<!--':                         '&lt;!--',
-        '-->':                          '--&gt;',
-        '<![CDATA[':                    '&lt;![CDATA['
-    };
-
-    var never_allowed_regex = {
-        'javascript\\s*:':              '',
-        'expression\\s*(\\(|&\\#40;)':  '',
-        'vbscript\\s*:':                '',
-        'Redirect\\s+302':              ''
-    };
-
-    var non_displayables = [
-        /%0[0-8bcef]/g,           // url encoded 00-08, 11, 12, 14, 15
-        /%1[0-9a-f]/g,            // url encoded 16-31
-        /[\x00-\x08]/g,           // 00-08
-        /\x0b/g, /\x0c/g,         // 11,12
-        /[\x0e-\x1f]/g            // 14-31
-    ];
-
-    var compact_words = [
-        'javascript', 'expression', 'vbscript',
-        'script', 'applet', 'alert', 'document',
-        'write', 'cookie', 'window'
-    ];
-
-    exports.xssClean = function(str, is_image) {
-
-        //Recursively clean objects and arrays
-        if (typeof str === 'object') {
-            for (var i in str) {
-                str[i] = exports.xssClean(str[i]);
-            }
-            return str;
-        }
-
-        //Remove invisible characters
-        str = remove_invisible_characters(str);
-
-        //Protect query string variables in URLs => 901119URL5918AMP18930PROTECT8198
-        str = str.replace(/\&([a-z\_0-9]+)\=([a-z\_0-9]+)/i, xss_hash() + '$1=$2');
-
-        //Validate standard character entities - add a semicolon if missing.  We do this to enable
-        //the conversion of entities to ASCII later.
-        str = str.replace(/(&\#?[0-9a-z]{2,})([\x00-\x20])*;?/i, '$1;$2');
-
-        //Validate UTF16 two byte encoding (x00) - just as above, adds a semicolon if missing.
-        str = str.replace(/(&\#x?)([0-9A-F]+);?/i, '$1;$2');
-
-        //Un-protect query string variables
-        str = str.replace(xss_hash(), '&');
-
-        //Decode just in case stuff like this is submitted:
-        //<a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
-        try {
-          str = decodeURIComponent(str);
-        } catch (e) {
-          // str was not actually URI-encoded
-        }
-
-        //Convert character entities to ASCII - this permits our tests below to work reliably.
-        //We only convert entities that are within tags since these are the ones that will pose security problems.
-        str = str.replace(/[a-z]+=([\'\"]).*?\1/gi, function(m, match) {
-            return m.replace(match, convert_attribute(match));
-        });
-
-        //Remove invisible characters again
-        str = remove_invisible_characters(str);
-
-        //Convert tabs to spaces
-        str = str.replace('\t', ' ');
-
-        //Captured the converted string for later comparison
-        var converted_string = str;
-
-        //Remove strings that are never allowed
-        for (var i in never_allowed_str) {
-            str = str.replace(i, never_allowed_str[i]);
-        }
-
-        //Remove regex patterns that are never allowed
-        for (var i in never_allowed_regex) {
-            str = str.replace(new RegExp(i, 'i'), never_allowed_regex[i]);
-        }
-
-        //Compact any exploded words like:  j a v a s c r i p t
-        // We only want to do this when it is followed by a non-word character
-        for (var i in compact_words) {
-            var spacified = compact_words[i].split('').join('\\s*')+'\\s*';
-
-            str = str.replace(new RegExp('('+spacified+')(\\W)', 'ig'), function(m, compat, after) {
-                return compat.replace(/\s+/g, '') + after;
-            });
-        }
-
-        //Remove disallowed Javascript in links or img tags
-        do {
-            var original = str;
-
-            if (str.match(/<a/i)) {
-                str = str.replace(/<a\s+([^>]*?)(>|$)/gi, function(m, attributes, end_tag) {
-                    attributes = filter_attributes(attributes.replace('<','').replace('>',''));
-                    return m.replace(attributes, attributes.replace(/href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, ''));
-                });
-            }
-
-            if (str.match(/<img/i)) {
-                str = str.replace(/<img\s+([^>]*?)(\s?\/?>|$)/gi, function(m, attributes, end_tag) {
-                    attributes = filter_attributes(attributes.replace('<','').replace('>',''));
-                    return m.replace(attributes, attributes.replace(/src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, ''));
-                });
-            }
-
-            if (str.match(/script/i) || str.match(/xss/i)) {
-                str = str.replace(/<(\/*)(script|xss)(.*?)\>/gi, '');
-            }
-
-        } while(original != str);
-
-        //Remove JavaScript Event Handlers - Note: This code is a little blunt.  It removes the event
-        //handler and anything up to the closing >, but it's unlikely to be a problem.
-        event_handlers = ['[^a-z_\-]on\\w*'];
-
-        //Adobe Photoshop puts XML metadata into JFIF images, including namespacing,
-        //so we have to allow this for images
-        if (!is_image) {
-            event_handlers.push('xmlns');
-        }
-
-        str = str.replace(new RegExp("<([^><]+?)("+event_handlers.join('|')+")(\\s*=\\s*[^><]*)([><]*)", 'i'), '<$1$4');
-
-        //Sanitize naughty HTML elements
-        //If a tag containing any of the words in the list
-        //below is found, the tag gets converted to entities.
-        //So this: <blink>
-        //Becomes: &lt;blink&gt;
-        naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
-        str = str.replace(new RegExp('<(/*\\s*)('+naughty+')([^><]*)([><]*)', 'gi'), function(m, a, b, c, d) {
-            return '&lt;' + a + b + c + d.replace('>','&gt;').replace('<','&lt;');
-        });
-
-        //Sanitize naughty scripting elements Similar to above, only instead of looking for
-        //tags it looks for PHP and JavaScript commands that are disallowed.  Rather than removing the
-        //code, it simply converts the parenthesis to entities rendering the code un-executable.
-        //For example:    eval('some code')
-        //Becomes:        eval&#40;'some code'&#41;
-        str = str.replace(/(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)/gi, '$1$2&#40;$3&#41;');
-
-        //This adds a bit of extra precaution in case something got through the above filters
-        for (var i in never_allowed_str) {
-            str = str.replace(i, never_allowed_str[i]);
-        }
-        for (var i in never_allowed_regex) {
-            str = str.replace(new RegExp(i, 'i'), never_allowed_regex[i]);
-        }
-
-        //Images are handled in a special way
-        if (is_image && str !== converted_string) {
-            throw new Error('Image may contain XSS');
-        }
-
-        return str;
-    }
-
-    function remove_invisible_characters(str) {
-        for (var i in non_displayables) {
-            str = str.replace(non_displayables[i], '');
-        }
-        return str;
-    }
-
-    function xss_hash() {
-        //TODO: Create a random hash
-        return '!*$^#(@*#&';
-    }
-
-    function convert_attribute(str) {
-        return str.replace('>','&gt;').replace('<','&lt;').replace('\\','\\\\');
-    }
-
-    //Filter Attributes - filters tag attributes for consistency and safety
-    function filter_attributes(str) {
-        var comments = /\/\*.*?\*\//g;
-        return str.replace(/\s*[a-z-]+\s*=\s*'[^']*'/gi, function (m) {
-            return m.replace(comments, '');
-        }).replace(/\s*[a-z-]+\s*=\s*"[^"]*"/gi, function (m) {
-            return m.replace(comments, '');
-        }).replace(/\s*[a-z-]+\s*=\s*[^\s]+/gi, function (m) {
-            return m.replace(comments, '');
-        });
-    }
-
     var Validator = exports.Validator = function() {}
 
     Validator.prototype.check = function(str, fail_msg) {
@@ -913,11 +711,6 @@
         return this;
     }
 
-    Filter.prototype.xss = function(is_image) {
-        this.modify(exports.xssClean(this.str, is_image));
-        return this.str;
-    }
-
     Filter.prototype.entityDecode = function() {
         this.modify(decode(this.str));
         return this.str;
@@ -1007,4 +800,4 @@
 
     return exports;
 
-}));
\ No newline at end of file
+}));