<?php

namespace App\Utils;

/**
 * Anti XSS library
 *
 * ported from "CodeIgniter"
 *
 * @author      EllisLab Dev Team
 * @author      Lars Moelleken
 * @copyright   Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
 * @copyright   Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
 * @license     http://opensource.org/licenses/MIT	MIT License
 */
class AntiXSS
{

  /**
   * @var array
   */
  protected static $entitiesFallback = array(
      "\t" => '&Tab;',
      "\n" => '&NewLine;',
      '!'  => '&excl;',
      '"'  => '&quot;',
      '#'  => '&num;',
      '$'  => '&dollar;',
      '%'  => '&percnt;',
      '&'  => '&amp;',
      "'"  => '&apos;',
      '('  => '&lpar;',
      ')'  => '&rpar;',
      '*'  => '&ast;',
      '+'  => '&plus;',
      ','  => '&comma;',
      '.'  => '&period;',
      '/'  => '&sol;',
      ':'  => '&colon;',
      ';'  => '&semi;',
      '<'  => '&lt;',
      '<⃒' => '&nvlt;',
      '='  => '&equals;',
      '=⃥' => '&bne;',
      '>'  => '&gt;',
      '>⃒' => '&nvgt',
      '?'  => '&quest;',
      '@'  => '&commat;',
      '['  => '&lbrack;',
      ']'  => '&rsqb;',
      '^'  => '&Hat;',
      '_'  => '&lowbar;',
      '`'  => '&grave;',
      'fj' => '&fjlig;',
      '{'  => '&lbrace;',
      '|'  => '&vert;',
      '}'  => '&rcub;',
      ' '  => '&nbsp;',
      '¡'  => '&iexcl;',
      '¢'  => '&cent;',
      '£'  => '&pound;',
      '¤'  => '&curren;',
      '¥'  => '&yen;',
      '¦'  => '&brvbar;',
      '§'  => '&sect;',
      '¨'  => '&DoubleDot;',
      '©'  => '&copy;',
      'ª'  => '&ordf;',
      '«'  => '&laquo;',
      '¬'  => '&not;',
      '­'  => '&shy;',
      '®'  => '&reg;',
      '¯'  => '&macr;',
      '°'  => '&deg;',
      '±'  => '&plusmn;',
      '²'  => '&sup2;',
      '³'  => '&sup3;',
      '´'  => '&DiacriticalAcute;',
      'µ'  => '&micro;',
      '¶'  => '&para;',
      '·'  => '&CenterDot;',
      '¸'  => '&Cedilla;',
      '¹'  => '&sup1;',
      'º'  => '&ordm;',
      '»'  => '&raquo;',
      '¼'  => '&frac14;',
      '½'  => '&half;',
      '¾'  => '&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;',
      'Ā'  => '&Amacr;',
      'ā'  => '&amacr;',
      'Ă'  => '&Abreve;',
      'ă'  => '&abreve;',
      'Ą'  => '&Aogon;',
      'ą'  => '&aogon;',
      'Ć'  => '&Cacute;',
      'ć'  => '&cacute;',
      'Ĉ'  => '&Ccirc;',
      'ĉ'  => '&ccirc;',
      'Ċ'  => '&Cdot;',
      'ċ'  => '&cdot;',
      'Č'  => '&Ccaron;',
      'č'  => '&ccaron;',
      'Ď'  => '&Dcaron;',
      'ď'  => '&dcaron;',
      'Đ'  => '&Dstrok;',
      'đ'  => '&dstrok;',
      'Ē'  => '&Emacr;',
      'ē'  => '&emacr;',
      'Ė'  => '&Edot;',
      'ė'  => '&edot;',
      'Ę'  => '&Eogon;',
      'ę'  => '&eogon;',
      'Ě'  => '&Ecaron;',
      'ě'  => '&ecaron;',
      'Ĝ'  => '&Gcirc;',
      'ĝ'  => '&gcirc;',
      'Ğ'  => '&Gbreve;',
      'ğ'  => '&gbreve;',
      'Ġ'  => '&Gdot;',
      'ġ'  => '&gdot;',
      'Ģ'  => '&Gcedil;',
      'Ĥ'  => '&Hcirc;',
      'ĥ'  => '&hcirc;',
      'Ħ'  => '&Hstrok;',
      'ħ'  => '&hstrok;',
      'Ĩ'  => '&Itilde;',
      'ĩ'  => '&itilde;',
      'Ī'  => '&Imacr;',
      'ī'  => '&imacr;',
      'Į'  => '&Iogon;',
      'į'  => '&iogon;',
      'İ'  => '&Idot;',
      'ı'  => '&inodot;',
      'Ĳ'  => '&IJlig;',
      'ĳ'  => '&ijlig;',
      'Ĵ'  => '&Jcirc;',
      'ĵ'  => '&jcirc;',
      'Ķ'  => '&Kcedil;',
      'ķ'  => '&kcedil;',
      'ĸ'  => '&kgreen;',
      'Ĺ'  => '&Lacute;',
      'ĺ'  => '&lacute;',
      'Ļ'  => '&Lcedil;',
      'ļ'  => '&lcedil;',
      'Ľ'  => '&Lcaron;',
      'ľ'  => '&lcaron;',
      'Ŀ'  => '&Lmidot;',
      'ŀ'  => '&lmidot;',
      'Ł'  => '&Lstrok;',
      'ł'  => '&lstrok;',
      'Ń'  => '&Nacute;',
      'ń'  => '&nacute;',
      'Ņ'  => '&Ncedil;',
      'ņ'  => '&ncedil;',
      'Ň'  => '&Ncaron;',
      'ň'  => '&ncaron;',
      'ŉ'  => '&napos;',
      'Ŋ'  => '&ENG;',
      'ŋ'  => '&eng;',
      'Ō'  => '&Omacr;',
      'ō'  => '&omacr;',
      'Ő'  => '&Odblac;',
      'ő'  => '&odblac;',
      'Œ'  => '&OElig;',
      'œ'  => '&oelig;',
      'Ŕ'  => '&Racute;',
      'ŕ'  => '&racute;',
      'Ŗ'  => '&Rcedil;',
      'ŗ'  => '&rcedil;',
      'Ř'  => '&Rcaron;',
      'ř'  => '&rcaron;',
      'Ś'  => '&Sacute;',
      'ś'  => '&sacute;',
      'Ŝ'  => '&Scirc;',
      'ŝ'  => '&scirc;',
      'Ş'  => '&Scedil;',
      'ş'  => '&scedil;',
      'Š'  => '&Scaron;',
      'š'  => '&scaron;',
      'Ţ'  => '&Tcedil;',
      'ţ'  => '&tcedil;',
      'Ť'  => '&Tcaron;',
      'ť'  => '&tcaron;',
      'Ŧ'  => '&Tstrok;',
      'ŧ'  => '&tstrok;',
      'Ũ'  => '&Utilde;',
      'ũ'  => '&utilde;',
      'Ū'  => '&Umacr;',
      'ū'  => '&umacr;',
      'Ŭ'  => '&Ubreve;',
      'ŭ'  => '&ubreve;',
      'Ů'  => '&Uring;',
      'ů'  => '&uring;',
      'Ű'  => '&Udblac;',
      'ű'  => '&udblac;',
      'Ų'  => '&Uogon;',
      'ų'  => '&uogon;',
      'Ŵ'  => '&Wcirc;',
      'ŵ'  => '&wcirc;',
      'Ŷ'  => '&Ycirc;',
      'ŷ'  => '&ycirc;',
      'Ÿ'  => '&Yuml;',
      'Ź'  => '&Zacute;',
      'ź'  => '&zacute;',
      'Ż'  => '&Zdot;',
      'ż'  => '&zdot;',
      'Ž'  => '&Zcaron;',
      'ž'  => '&zcaron;',
      'ƒ'  => '&fnof;',
      'Ƶ'  => '&imped;',
      'ǵ'  => '&gacute;',
      'ȷ'  => '&jmath;',
      'ˆ'  => '&circ;',
      'ˇ'  => '&Hacek;',
      '˘'  => '&Breve;',
      '˙'  => '&dot;',
      '˚'  => '&ring;',
      '˛'  => '&ogon;',
      '˜'  => '&DiacriticalTilde;',
      '˝'  => '&DiacriticalDoubleAcute;',
      '̑'  => '&DownBreve;',
      'Α'  => '&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;',
      'ε'  => '&epsi;',
      'ζ'  => '&zeta;',
      'η'  => '&eta;',
      'θ'  => '&theta;',
      'ι'  => '&iota;',
      'κ'  => '&kappa;',
      'λ'  => '&lambda;',
      'μ'  => '&mu;',
      'ν'  => '&nu;',
      'ξ'  => '&xi;',
      'ο'  => '&omicron;',
      'π'  => '&pi;',
      'ρ'  => '&rho;',
      'ς'  => '&sigmav;',
      'σ'  => '&sigma;',
      'τ'  => '&tau;',
      'υ'  => '&upsi;',
      'φ'  => '&phi;',
      'χ'  => '&chi;',
      'ψ'  => '&psi;',
      'ω'  => '&omega;',
      'ϑ'  => '&thetasym;',
      'ϒ'  => '&upsih;',
      'ϕ'  => '&straightphi;',
      'ϖ'  => '&piv;',
      'Ϝ'  => '&Gammad;',
      'ϝ'  => '&gammad;',
      'ϰ'  => '&varkappa;',
      'ϱ'  => '&rhov;',
      'ϵ'  => '&straightepsilon;',
      '϶'  => '&backepsilon;',
      'Ё'  => '&IOcy;',
      'Ђ'  => '&DJcy;',
      'Ѓ'  => '&GJcy;',
      'Є'  => '&Jukcy;',
      'Ѕ'  => '&DScy;',
      'І'  => '&Iukcy;',
      'Ї'  => '&YIcy;',
      'Ј'  => '&Jsercy;',
      'Љ'  => '&LJcy;',
      'Њ'  => '&NJcy;',
      'Ћ'  => '&TSHcy;',
      'Ќ'  => '&KJcy;',
      'Ў'  => '&Ubrcy;',
      'Џ'  => '&DZcy;',
      'А'  => '&Acy;',
      'Б'  => '&Bcy;',
      'В'  => '&Vcy;',
      'Г'  => '&Gcy;',
      'Д'  => '&Dcy;',
      'Е'  => '&IEcy;',
      'Ж'  => '&ZHcy;',
      'З'  => '&Zcy;',
      'И'  => '&Icy;',
      'Й'  => '&Jcy;',
      'К'  => '&Kcy;',
      'Л'  => '&Lcy;',
      'М'  => '&Mcy;',
      'Н'  => '&Ncy;',
      'О'  => '&Ocy;',
      'П'  => '&Pcy;',
      'Р'  => '&Rcy;',
      'С'  => '&Scy;',
      'Т'  => '&Tcy;',
      'У'  => '&Ucy;',
      'Ф'  => '&Fcy;',
      'Х'  => '&KHcy;',
      'Ц'  => '&TScy;',
      'Ч'  => '&CHcy;',
      'Ш'  => '&SHcy;',
      'Щ'  => '&SHCHcy;',
      'Ъ'  => '&HARDcy;',
      'Ы'  => '&Ycy;',
      'Ь'  => '&SOFTcy;',
      'Э'  => '&Ecy;',
      'Ю'  => '&YUcy;',
      'Я'  => '&YAcy;',
      'а'  => '&acy;',
      'б'  => '&bcy;',
      'в'  => '&vcy;',
      'г'  => '&gcy;',
      'д'  => '&dcy;',
      'е'  => '&iecy;',
      'ж'  => '&zhcy;',
      'з'  => '&zcy;',
      'и'  => '&icy;',
      'й'  => '&jcy;',
      'к'  => '&kcy;',
      'л'  => '&lcy;',
      'м'  => '&mcy;',
      'н'  => '&ncy;',
      'о'  => '&ocy;',
      'п'  => '&pcy;',
      'р'  => '&rcy;',
      'с'  => '&scy;',
      'т'  => '&tcy;',
      'у'  => '&ucy;',
      'ф'  => '&fcy;',
      'х'  => '&khcy;',
      'ц'  => '&tscy;',
      'ч'  => '&chcy;',
      'ш'  => '&shcy;',
      'щ'  => '&shchcy;',
      'ъ'  => '&hardcy;',
      'ы'  => '&ycy;',
      'ь'  => '&softcy;',
      'э'  => '&ecy;',
      'ю'  => '&yucy;',
      'я'  => '&yacy;',
      'ё'  => '&iocy;',
      'ђ'  => '&djcy;',
      'ѓ'  => '&gjcy;',
      'є'  => '&jukcy;',
      'ѕ'  => '&dscy;',
      'і'  => '&iukcy;',
      'ї'  => '&yicy;',
      'ј'  => '&jsercy;',
      'љ'  => '&ljcy;',
      'њ'  => '&njcy;',
      'ћ'  => '&tshcy;',
      'ќ'  => '&kjcy;',
      'ў'  => '&ubrcy;',
      'џ'  => '&dzcy;',
      ' '  => '&ensp;',
      ' '  => '&emsp;',
      ' '  => '&emsp13;',
      ' '  => '&emsp14;',
      ' '  => '&numsp;',
      ' '  => '&puncsp;',
      ' '  => '&ThinSpace;',
      ' '  => '&hairsp;',
      '​'  => '&ZeroWidthSpace;',
      '‌'  => '&zwnj;',
      '‍'  => '&zwj;',
      '‎'  => '&lrm;',
      '‏'  => '&rlm;',
      '‐'  => '&hyphen;',
      '–'  => '&ndash;',
      '—'  => '&mdash;',
      '―'  => '&horbar;',
      '‖'  => '&Verbar;',
      '‘'  => '&OpenCurlyQuote;',
      '’'  => '&rsquo;',
      '‚'  => '&sbquo;',
      '“'  => '&OpenCurlyDoubleQuote;',
      '”'  => '&rdquo;',
      '„'  => '&bdquo;',
      '†'  => '&dagger;',
      '‡'  => '&Dagger;',
      '•'  => '&bull;',
      '‥'  => '&nldr;',
      '…'  => '&hellip;',
      '‰'  => '&permil;',
      '‱'  => '&pertenk;',
      '′'  => '&prime;',
      '″'  => '&Prime;',
      '‴'  => '&tprime;',
      '‵'  => '&backprime;',
      '‹'  => '&lsaquo;',
      '›'  => '&rsaquo;',
      '‾'  => '&oline;',
      '⁁'  => '&caret;',
      '⁃'  => '&hybull;',
      '⁄'  => '&frasl;',
      '⁏'  => '&bsemi;',
      '⁗'  => '&qprime;',
      ' '  => '&MediumSpace;',
      '  ' => '&ThickSpace;',
      '⁠'  => '&NoBreak;',
      '⁡'  => '&af;',
      '⁢'  => '&InvisibleTimes;',
      '⁣'  => '&ic;',
      '€'  => '&euro;',
      '⃛'  => '&TripleDot;',
      '⃜'  => '&DotDot;',
      'ℂ'  => '&complexes;',
      '℅'  => '&incare;',
      'ℊ'  => '&gscr;',
      'ℋ'  => '&HilbertSpace;',
      'ℌ'  => '&Hfr;',
      'ℍ'  => '&Hopf;',
      'ℎ'  => '&planckh;',
      'ℏ'  => '&planck;',
      'ℐ'  => '&imagline;',
      'ℑ'  => '&Ifr;',
      'ℒ'  => '&lagran;',
      'ℓ'  => '&ell;',
      'ℕ'  => '&naturals;',
      '№'  => '&numero;',
      '℗'  => '&copysr;',
      '℘'  => '&wp;',
      'ℙ'  => '&primes;',
      'ℚ'  => '&rationals;',
      'ℛ'  => '&realine;',
      'ℜ'  => '&Rfr;',
      'ℝ'  => '&Ropf;',
      '℞'  => '&rx;',
      '™'  => '&trade;',
      'ℤ'  => '&Zopf;',
      '℧'  => '&mho;',
      'ℨ'  => '&Zfr;',
      '℩'  => '&iiota;',
      'ℬ'  => '&Bscr;',
      'ℭ'  => '&Cfr;',
      'ℯ'  => '&escr;',
      'ℰ'  => '&expectation;',
      'ℱ'  => '&Fouriertrf;',
      'ℳ'  => '&Mellintrf;',
      'ℴ'  => '&orderof;',
      'ℵ'  => '&aleph;',
      'ℶ'  => '&beth;',
      'ℷ'  => '&gimel;',
      'ℸ'  => '&daleth;',
      'ⅅ'  => '&CapitalDifferentialD;',
      'ⅆ'  => '&DifferentialD;',
      'ⅇ'  => '&exponentiale;',
      'ⅈ'  => '&ImaginaryI;',
      '⅓'  => '&frac13;',
      '⅔'  => '&frac23;',
      '⅕'  => '&frac15;',
      '⅖'  => '&frac25;',
      '⅗'  => '&frac35;',
      '⅘'  => '&frac45;',
      '⅙'  => '&frac16;',
      '⅚'  => '&frac56;',
      '⅛'  => '&frac18;',
      '⅜'  => '&frac38;',
      '⅝'  => '&frac58;',
      '⅞'  => '&frac78;',
      '←'  => '&larr;',
      '↑'  => '&uarr;',
      '→'  => '&srarr;',
      '↓'  => '&darr;',
      '↔'  => '&harr;',
      '↕'  => '&UpDownArrow;',
      '↖'  => '&nwarrow;',
      '↗'  => '&UpperRightArrow;',
      '↘'  => '&LowerRightArrow;',
      '↙'  => '&swarr;',
      '↚'  => '&nleftarrow;',
      '↛'  => '&nrarr;',
      '↝'  => '&rarrw;',
      '↝̸' => '&nrarrw;',
      '↞'  => '&Larr;',
      '↟'  => '&Uarr;',
      '↠'  => '&twoheadrightarrow;',
      '↡'  => '&Darr;',
      '↢'  => '&larrtl;',
      '↣'  => '&rarrtl;',
      '↤'  => '&LeftTeeArrow;',
      '↥'  => '&UpTeeArrow;',
      '↦'  => '&map;',
      '↧'  => '&DownTeeArrow;',
      '↩'  => '&larrhk;',
      '↪'  => '&rarrhk;',
      '↫'  => '&larrlp;',
      '↬'  => '&looparrowright;',
      '↭'  => '&harrw;',
      '↮'  => '&nleftrightarrow;',
      '↰'  => '&Lsh;',
      '↱'  => '&rsh;',
      '↲'  => '&ldsh;',
      '↳'  => '&rdsh;',
      '↵'  => '&crarr;',
      '↶'  => '&curvearrowleft;',
      '↷'  => '&curarr;',
      '↺'  => '&olarr;',
      '↻'  => '&orarr;',
      '↼'  => '&leftharpoonup;',
      '↽'  => '&leftharpoondown;',
      '↾'  => '&RightUpVector;',
      '↿'  => '&uharl;',
      '⇀'  => '&rharu;',
      '⇁'  => '&rhard;',
      '⇂'  => '&RightDownVector;',
      '⇃'  => '&dharl;',
      '⇄'  => '&rightleftarrows;',
      '⇅'  => '&udarr;',
      '⇆'  => '&lrarr;',
      '⇇'  => '&llarr;',
      '⇈'  => '&upuparrows;',
      '⇉'  => '&rrarr;',
      '⇊'  => '&downdownarrows;',
      '⇋'  => '&leftrightharpoons;',
      '⇌'  => '&rightleftharpoons;',
      '⇍'  => '&nLeftarrow;',
      '⇎'  => '&nhArr;',
      '⇏'  => '&nrArr;',
      '⇐'  => '&DoubleLeftArrow;',
      '⇑'  => '&DoubleUpArrow;',
      '⇒'  => '&Implies;',
      '⇓'  => '&Downarrow;',
      '⇔'  => '&hArr;',
      '⇕'  => '&Updownarrow;',
      '⇖'  => '&nwArr;',
      '⇗'  => '&neArr;',
      '⇘'  => '&seArr;',
      '⇙'  => '&swArr;',
      '⇚'  => '&lAarr;',
      '⇛'  => '&rAarr;',
      '⇝'  => '&zigrarr;',
      '⇤'  => '&LeftArrowBar;',
      '⇥'  => '&RightArrowBar;',
      '⇵'  => '&DownArrowUpArrow;',
      '⇽'  => '&loarr;',
      '⇾'  => '&roarr;',
      '⇿'  => '&hoarr;',
      '∀'  => '&forall;',
      '∁'  => '&comp;',
      '∂'  => '&part;',
      '∂̸' => '&npart;',
      '∃'  => '&Exists;',
      '∄'  => '&nexist;',
      '∅'  => '&empty;',
      '∇'  => '&nabla;',
      '∈'  => '&isinv;',
      '∉'  => '&notin;',
      '∋'  => '&ReverseElement;',
      '∌'  => '&notniva;',
      '∏'  => '&prod;',
      '∐'  => '&Coproduct;',
      '∑'  => '&sum;',
      '−'  => '&minus;',
      '∓'  => '&MinusPlus;',
      '∔'  => '&plusdo;',
      '∖'  => '&ssetmn;',
      '∗'  => '&lowast;',
      '∘'  => '&compfn;',
      '√'  => '&Sqrt;',
      '∝'  => '&prop;',
      '∞'  => '&infin;',
      '∟'  => '&angrt;',
      '∠'  => '&angle;',
      '∠⃒' => '&nang;',
      '∡'  => '&angmsd;',
      '∢'  => '&angsph;',
      '∣'  => '&mid;',
      '∤'  => '&nshortmid;',
      '∥'  => '&shortparallel;',
      '∦'  => '&nparallel;',
      '∧'  => '&and;',
      '∨'  => '&or;',
      '∩'  => '&cap;',
      '∩︀' => '&caps;',
      '∪'  => '&cup;',
      '∪︀' => '&cups',
      '∫'  => '&Integral;',
      '∬'  => '&Int;',
      '∭'  => '&tint;',
      '∮'  => '&ContourIntegral;',
      '∯'  => '&DoubleContourIntegral;',
      '∰'  => '&Cconint;',
      '∱'  => '&cwint;',
      '∲'  => '&cwconint;',
      '∳'  => '&awconint;',
      '∴'  => '&there4;',
      '∵'  => '&Because;',
      '∶'  => '&ratio;',
      '∷'  => '&Colon;',
      '∸'  => '&minusd;',
      '∺'  => '&mDDot;',
      '∻'  => '&homtht;',
      '∼'  => '&sim;',
      '∼⃒' => '&nvsim;',
      '∽'  => '&bsim;',
      '∽̱' => '&race;',
      '∾'  => '&ac;',
      '∾̳' => '&acE;',
      '∿'  => '&acd;',
      '≀'  => '&wr;',
      '≁'  => '&NotTilde;',
      '≂'  => '&esim;',
      '≂̸' => '&nesim;',
      '≃'  => '&simeq;',
      '≄'  => '&nsime;',
      '≅'  => '&TildeFullEqual;',
      '≆'  => '&simne;',
      '≇'  => '&ncong;',
      '≈'  => '&approx;',
      '≉'  => '&napprox;',
      '≊'  => '&ape;',
      '≋'  => '&apid;',
      '≋̸' => '&napid;',
      '≌'  => '&bcong;',
      '≍'  => '&CupCap;',
      '≍⃒' => '&nvap;',
      '≎'  => '&bump;',
      '≎̸' => '&nbump;',
      '≏'  => '&HumpEqual;',
      '≏̸' => '&nbumpe;',
      '≐'  => '&esdot;',
      '≐̸' => '&nedot;',
      '≑'  => '&doteqdot;',
      '≒'  => '&fallingdotseq;',
      '≓'  => '&risingdotseq;',
      '≔'  => '&coloneq;',
      '≕'  => '&eqcolon;',
      '≖'  => '&ecir;',
      '≗'  => '&circeq;',
      '≙'  => '&wedgeq;',
      '≚'  => '&veeeq;',
      '≜'  => '&triangleq;',
      '≟'  => '&equest;',
      '≠'  => '&NotEqual;',
      '≡'  => '&Congruent;',
      '≡⃥' => '&bnequiv;',
      '≢'  => '&NotCongruent;',
      '≤'  => '&leq;',
      '≤⃒' => '&nvle;',
      '≥'  => '&ge;',
      '≥⃒' => '&nvge;',
      '≦'  => '&lE;',
      '≦̸' => '&nlE;',
      '≧'  => '&geqq;',
      '≧̸' => '&NotGreaterFullEqual;',
      '≨'  => '&lneqq;',
      '≨︀' => '&lvertneqq;',
      '≩'  => '&gneqq;',
      '≩︀' => '&gvertneqq;',
      '≪'  => '&ll;',
      '≪̸' => '&nLtv;',
      '≪⃒' => '&nLt;',
      '≫'  => '&gg;',
      '≫̸' => '&NotGreaterGreater;',
      '≫⃒' => '&nGt;',
      '≬'  => '&between;',
      '≭'  => '&NotCupCap;',
      '≮'  => '&NotLess;',
      '≯'  => '&ngtr;',
      '≰'  => '&NotLessEqual;',
      '≱'  => '&ngeq;',
      '≲'  => '&LessTilde;',
      '≳'  => '&GreaterTilde;',
      '≴'  => '&nlsim;',
      '≵'  => '&ngsim;',
      '≶'  => '&lessgtr;',
      '≷'  => '&gl;',
      '≸'  => '&ntlg;',
      '≹'  => '&NotGreaterLess;',
      '≺'  => '&prec;',
      '≻'  => '&succ;',
      '≼'  => '&PrecedesSlantEqual;',
      '≽'  => '&succcurlyeq;',
      '≾'  => '&precsim;',
      '≿'  => '&SucceedsTilde;',
      '≿̸' => '&NotSucceedsTilde;',
      '⊀'  => '&npr;',
      '⊁'  => '&NotSucceeds;',
      '⊂'  => '&sub;',
      '⊂⃒' => '&vnsub;',
      '⊃'  => '&sup;',
      '⊃⃒' => '&nsupset;',
      '⊄'  => '&nsub;',
      '⊅'  => '&nsup;',
      '⊆'  => '&SubsetEqual;',
      '⊇'  => '&supe;',
      '⊈'  => '&NotSubsetEqual;',
      '⊉'  => '&NotSupersetEqual;',
      '⊊'  => '&subsetneq;',
      '⊊︀' => '&vsubne;',
      '⊋'  => '&supsetneq;',
      '⊋︀' => '&vsupne;',
      '⊍'  => '&cupdot;',
      '⊎'  => '&UnionPlus;',
      '⊏'  => '&sqsub;',
      '⊏̸' => '&NotSquareSubset;',
      '⊐'  => '&sqsupset;',
      '⊐̸' => '&NotSquareSuperset;',
      '⊑'  => '&SquareSubsetEqual;',
      '⊒'  => '&SquareSupersetEqual;',
      '⊓'  => '&sqcap;',
      '⊓︀' => '&sqcaps;',
      '⊔'  => '&sqcup;',
      '⊔︀' => '&sqcups;',
      '⊕'  => '&CirclePlus;',
      '⊖'  => '&ominus;',
      '⊗'  => '&CircleTimes;',
      '⊘'  => '&osol;',
      '⊙'  => '&CircleDot;',
      '⊚'  => '&ocir;',
      '⊛'  => '&oast;',
      '⊝'  => '&odash;',
      '⊞'  => '&boxplus;',
      '⊟'  => '&boxminus;',
      '⊠'  => '&timesb;',
      '⊡'  => '&sdotb;',
      '⊢'  => '&vdash;',
      '⊣'  => '&dashv;',
      '⊤'  => '&DownTee;',
      '⊥'  => '&perp;',
      '⊧'  => '&models;',
      '⊨'  => '&DoubleRightTee;',
      '⊩'  => '&Vdash;',
      '⊪'  => '&Vvdash;',
      '⊫'  => '&VDash;',
      '⊬'  => '&nvdash;',
      '⊭'  => '&nvDash;',
      '⊮'  => '&nVdash;',
      '⊯'  => '&nVDash;',
      '⊰'  => '&prurel;',
      '⊲'  => '&vartriangleleft;',
      '⊳'  => '&vrtri;',
      '⊴'  => '&LeftTriangleEqual;',
      '⊴⃒' => '&nvltrie;',
      '⊵'  => '&RightTriangleEqual;',
      '⊵⃒' => '&nvrtrie;',
      '⊶'  => '&origof;',
      '⊷'  => '&imof;',
      '⊸'  => '&mumap;',
      '⊹'  => '&hercon;',
      '⊺'  => '&intcal;',
      '⊻'  => '&veebar;',
      '⊽'  => '&barvee;',
      '⊾'  => '&angrtvb;',
      '⊿'  => '&lrtri;',
      '⋀'  => '&xwedge;',
      '⋁'  => '&xvee;',
      '⋂'  => '&bigcap;',
      '⋃'  => '&bigcup;',
      '⋄'  => '&diamond;',
      '⋅'  => '&sdot;',
      '⋆'  => '&Star;',
      '⋇'  => '&divonx;',
      '⋈'  => '&bowtie;',
      '⋉'  => '&ltimes;',
      '⋊'  => '&rtimes;',
      '⋋'  => '&lthree;',
      '⋌'  => '&rthree;',
      '⋍'  => '&backsimeq;',
      '⋎'  => '&curlyvee;',
      '⋏'  => '&curlywedge;',
      '⋐'  => '&Sub;',
      '⋑'  => '&Supset;',
      '⋒'  => '&Cap;',
      '⋓'  => '&Cup;',
      '⋔'  => '&pitchfork;',
      '⋕'  => '&epar;',
      '⋖'  => '&lessdot;',
      '⋗'  => '&gtrdot;',
      '⋘'  => '&Ll;',
      '⋘̸' => '&nLl;',
      '⋙'  => '&Gg;',
      '⋙̸' => '&nGg;',
      '⋚'  => '&lesseqgtr;',
      '⋚︀' => '&lesg;',
      '⋛'  => '&gtreqless;',
      '⋛︀' => '&gesl;',
      '⋞'  => '&curlyeqprec;',
      '⋟'  => '&cuesc;',
      '⋠'  => '&NotPrecedesSlantEqual;',
      '⋡'  => '&NotSucceedsSlantEqual;',
      '⋢'  => '&NotSquareSubsetEqual;',
      '⋣'  => '&NotSquareSupersetEqual;',
      '⋦'  => '&lnsim;',
      '⋧'  => '&gnsim;',
      '⋨'  => '&precnsim;',
      '⋩'  => '&scnsim;',
      '⋪'  => '&nltri;',
      '⋫'  => '&ntriangleright;',
      '⋬'  => '&nltrie;',
      '⋭'  => '&NotRightTriangleEqual;',
      '⋮'  => '&vellip;',
      '⋯'  => '&ctdot;',
      '⋰'  => '&utdot;',
      '⋱'  => '&dtdot;',
      '⋲'  => '&disin;',
      '⋳'  => '&isinsv;',
      '⋴'  => '&isins;',
      '⋵'  => '&isindot;',
      '⋵̸' => '&notindot;',
      '⋶'  => '&notinvc;',
      '⋷'  => '&notinvb;',
      '⋹'  => '&isinE;',
      '⋹̸' => '&notinE;',
      '⋺'  => '&nisd;',
      '⋻'  => '&xnis;',
      '⋼'  => '&nis;',
      '⋽'  => '&notnivc;',
      '⋾'  => '&notnivb;',
      '⌅'  => '&barwed;',
      '⌆'  => '&doublebarwedge;',
      '⌈'  => '&lceil;',
      '⌉'  => '&RightCeiling;',
      '⌊'  => '&LeftFloor;',
      '⌋'  => '&RightFloor;',
      '⌌'  => '&drcrop;',
      '⌍'  => '&dlcrop;',
      '⌎'  => '&urcrop;',
      '⌏'  => '&ulcrop;',
      '⌐'  => '&bnot;',
      '⌒'  => '&profline;',
      '⌓'  => '&profsurf;',
      '⌕'  => '&telrec;',
      '⌖'  => '&target;',
      '⌜'  => '&ulcorner;',
      '⌝'  => '&urcorner;',
      '⌞'  => '&llcorner;',
      '⌟'  => '&drcorn;',
      '⌢'  => '&frown;',
      '⌣'  => '&smile;',
      '⌭'  => '&cylcty;',
      '⌮'  => '&profalar;',
      '⌶'  => '&topbot;',
      '⌽'  => '&ovbar;',
      '⌿'  => '&solbar;',
      '⍼'  => '&angzarr;',
      '⎰'  => '&lmoust;',
      '⎱'  => '&rmoust;',
      '⎴'  => '&OverBracket;',
      '⎵'  => '&bbrk;',
      '⎶'  => '&bbrktbrk;',
      '⏜'  => '&OverParenthesis;',
      '⏝'  => '&UnderParenthesis;',
      '⏞'  => '&OverBrace;',
      '⏟'  => '&UnderBrace;',
      '⏢'  => '&trpezium;',
      '⏧'  => '&elinters;',
      '␣'  => '&blank;',
      'Ⓢ'  => '&oS;',
      '─'  => '&HorizontalLine;',
      '│'  => '&boxv;',
      '┌'  => '&boxdr;',
      '┐'  => '&boxdl;',
      '└'  => '&boxur;',
      '┘'  => '&boxul;',
      '├'  => '&boxvr;',
      '┤'  => '&boxvl;',
      '┬'  => '&boxhd;',
      '┴'  => '&boxhu;',
      '┼'  => '&boxvh;',
      '═'  => '&boxH;',
      '║'  => '&boxV;',
      '╒'  => '&boxdR;',
      '╓'  => '&boxDr;',
      '╔'  => '&boxDR;',
      '╕'  => '&boxdL;',
      '╖'  => '&boxDl;',
      '╗'  => '&boxDL;',
      '╘'  => '&boxuR;',
      '╙'  => '&boxUr;',
      '╚'  => '&boxUR;',
      '╛'  => '&boxuL;',
      '╜'  => '&boxUl;',
      '╝'  => '&boxUL;',
      '╞'  => '&boxvR;',
      '╟'  => '&boxVr;',
      '╠'  => '&boxVR;',
      '╡'  => '&boxvL;',
      '╢'  => '&boxVl;',
      '╣'  => '&boxVL;',
      '╤'  => '&boxHd;',
      '╥'  => '&boxhD;',
      '╦'  => '&boxHD;',
      '╧'  => '&boxHu;',
      '╨'  => '&boxhU;',
      '╩'  => '&boxHU;',
      '╪'  => '&boxvH;',
      '╫'  => '&boxVh;',
      '╬'  => '&boxVH;',
      '▀'  => '&uhblk;',
      '▄'  => '&lhblk;',
      '█'  => '&block;',
      '░'  => '&blk14;',
      '▒'  => '&blk12;',
      '▓'  => '&blk34;',
      '□'  => '&Square;',
      '▪'  => '&squarf;',
      '▫'  => '&EmptyVerySmallSquare;',
      '▭'  => '&rect;',
      '▮'  => '&marker;',
      '▱'  => '&fltns;',
      '△'  => '&bigtriangleup;',
      '▴'  => '&blacktriangle;',
      '▵'  => '&triangle;',
      '▸'  => '&blacktriangleright;',
      '▹'  => '&rtri;',
      '▽'  => '&bigtriangledown;',
      '▾'  => '&blacktriangledown;',
      '▿'  => '&triangledown;',
      '◂'  => '&blacktriangleleft;',
      '◃'  => '&ltri;',
      '◊'  => '&lozenge;',
      '○'  => '&cir;',
      '◬'  => '&tridot;',
      '◯'  => '&bigcirc;',
      '◸'  => '&ultri;',
      '◹'  => '&urtri;',
      '◺'  => '&lltri;',
      '◻'  => '&EmptySmallSquare;',
      '◼'  => '&FilledSmallSquare;',
      '★'  => '&starf;',
      '☆'  => '&star;',
      '☎'  => '&phone;',
      '♀'  => '&female;',
      '♂'  => '&male;',
      '♠'  => '&spadesuit;',
      '♣'  => '&clubs;',
      '♥'  => '&hearts;',
      '♦'  => '&diamondsuit;',
      '♪'  => '&sung;',
      '♭'  => '&flat;',
      '♮'  => '&natur;',
      '♯'  => '&sharp;',
      '✓'  => '&check;',
      '✗'  => '&cross;',
      '✠'  => '&maltese;',
      '✶'  => '&sext;',
      '❘'  => '&VerticalSeparator;',
      '❲'  => '&lbbrk;',
      '❳'  => '&rbbrk;',
      '⟈'  => '&bsolhsub;',
      '⟉'  => '&suphsol;',
      '⟦'  => '&LeftDoubleBracket;',
      '⟧'  => '&RightDoubleBracket;',
      '⟨'  => '&langle;',
      '⟩'  => '&RightAngleBracket;',
      '⟪'  => '&Lang;',
      '⟫'  => '&Rang;',
      '⟬'  => '&loang;',
      '⟭'  => '&roang;',
      '⟵'  => '&longleftarrow;',
      '⟶'  => '&LongRightArrow;',
      '⟷'  => '&LongLeftRightArrow;',
      '⟸'  => '&xlArr;',
      '⟹'  => '&DoubleLongRightArrow;',
      '⟺'  => '&xhArr;',
      '⟼'  => '&xmap;',
      '⟿'  => '&dzigrarr;',
      '⤂'  => '&nvlArr;',
      '⤃'  => '&nvrArr;',
      '⤄'  => '&nvHarr;',
      '⤅'  => '&Map;',
      '⤌'  => '&lbarr;',
      '⤍'  => '&bkarow;',
      '⤎'  => '&lBarr;',
      '⤏'  => '&dbkarow;',
      '⤐'  => '&drbkarow;',
      '⤑'  => '&DDotrahd;',
      '⤒'  => '&UpArrowBar;',
      '⤓'  => '&DownArrowBar;',
      '⤖'  => '&Rarrtl;',
      '⤙'  => '&latail;',
      '⤚'  => '&ratail;',
      '⤛'  => '&lAtail;',
      '⤜'  => '&rAtail;',
      '⤝'  => '&larrfs;',
      '⤞'  => '&rarrfs;',
      '⤟'  => '&larrbfs;',
      '⤠'  => '&rarrbfs;',
      '⤣'  => '&nwarhk;',
      '⤤'  => '&nearhk;',
      '⤥'  => '&searhk;',
      '⤦'  => '&swarhk;',
      '⤧'  => '&nwnear;',
      '⤨'  => '&toea;',
      '⤩'  => '&seswar;',
      '⤪'  => '&swnwar;',
      '⤳'  => '&rarrc;',
      '⤳̸' => '&nrarrc;',
      '⤵'  => '&cudarrr;',
      '⤶'  => '&ldca;',
      '⤷'  => '&rdca;',
      '⤸'  => '&cudarrl;',
      '⤹'  => '&larrpl;',
      '⤼'  => '&curarrm;',
      '⤽'  => '&cularrp;',
      '⥅'  => '&rarrpl;',
      '⥈'  => '&harrcir;',
      '⥉'  => '&Uarrocir;',
      '⥊'  => '&lurdshar;',
      '⥋'  => '&ldrushar;',
      '⥎'  => '&LeftRightVector;',
      '⥏'  => '&RightUpDownVector;',
      '⥐'  => '&DownLeftRightVector;',
      '⥑'  => '&LeftUpDownVector;',
      '⥒'  => '&LeftVectorBar;',
      '⥓'  => '&RightVectorBar;',
      '⥔'  => '&RightUpVectorBar;',
      '⥕'  => '&RightDownVectorBar;',
      '⥖'  => '&DownLeftVectorBar;',
      '⥗'  => '&DownRightVectorBar;',
      '⥘'  => '&LeftUpVectorBar;',
      '⥙'  => '&LeftDownVectorBar;',
      '⥚'  => '&LeftTeeVector;',
      '⥛'  => '&RightTeeVector;',
      '⥜'  => '&RightUpTeeVector;',
      '⥝'  => '&RightDownTeeVector;',
      '⥞'  => '&DownLeftTeeVector;',
      '⥟'  => '&DownRightTeeVector;',
      '⥠'  => '&LeftUpTeeVector;',
      '⥡'  => '&LeftDownTeeVector;',
      '⥢'  => '&lHar;',
      '⥣'  => '&uHar;',
      '⥤'  => '&rHar;',
      '⥥'  => '&dHar;',
      '⥦'  => '&luruhar;',
      '⥧'  => '&ldrdhar;',
      '⥨'  => '&ruluhar;',
      '⥩'  => '&rdldhar;',
      '⥪'  => '&lharul;',
      '⥫'  => '&llhard;',
      '⥬'  => '&rharul;',
      '⥭'  => '&lrhard;',
      '⥮'  => '&udhar;',
      '⥯'  => '&ReverseUpEquilibrium;',
      '⥰'  => '&RoundImplies;',
      '⥱'  => '&erarr;',
      '⥲'  => '&simrarr;',
      '⥳'  => '&larrsim;',
      '⥴'  => '&rarrsim;',
      '⥵'  => '&rarrap;',
      '⥶'  => '&ltlarr;',
      '⥸'  => '&gtrarr;',
      '⥹'  => '&subrarr;',
      '⥻'  => '&suplarr;',
      '⥼'  => '&lfisht;',
      '⥽'  => '&rfisht;',
      '⥾'  => '&ufisht;',
      '⥿'  => '&dfisht;',
      '⦅'  => '&lopar;',
      '⦆'  => '&ropar;',
      '⦋'  => '&lbrke;',
      '⦌'  => '&rbrke;',
      '⦍'  => '&lbrkslu;',
      '⦎'  => '&rbrksld;',
      '⦏'  => '&lbrksld;',
      '⦐'  => '&rbrkslu;',
      '⦑'  => '&langd;',
      '⦒'  => '&rangd;',
      '⦓'  => '&lparlt;',
      '⦔'  => '&rpargt;',
      '⦕'  => '&gtlPar;',
      '⦖'  => '&ltrPar;',
      '⦚'  => '&vzigzag;',
      '⦜'  => '&vangrt;',
      '⦝'  => '&angrtvbd;',
      '⦤'  => '&ange;',
      '⦥'  => '&range;',
      '⦦'  => '&dwangle;',
      '⦧'  => '&uwangle;',
      '⦨'  => '&angmsdaa;',
      '⦩'  => '&angmsdab;',
      '⦪'  => '&angmsdac;',
      '⦫'  => '&angmsdad;',
      '⦬'  => '&angmsdae;',
      '⦭'  => '&angmsdaf;',
      '⦮'  => '&angmsdag;',
      '⦯'  => '&angmsdah;',
      '⦰'  => '&bemptyv;',
      '⦱'  => '&demptyv;',
      '⦲'  => '&cemptyv;',
      '⦳'  => '&raemptyv;',
      '⦴'  => '&laemptyv;',
      '⦵'  => '&ohbar;',
      '⦶'  => '&omid;',
      '⦷'  => '&opar;',
      '⦹'  => '&operp;',
      '⦻'  => '&olcross;',
      '⦼'  => '&odsold;',
      '⦾'  => '&olcir;',
      '⦿'  => '&ofcir;',
      '⧀'  => '&olt;',
      '⧁'  => '&ogt;',
      '⧂'  => '&cirscir;',
      '⧃'  => '&cirE;',
      '⧄'  => '&solb;',
      '⧅'  => '&bsolb;',
      '⧉'  => '&boxbox;',
      '⧍'  => '&trisb;',
      '⧎'  => '&rtriltri;',
      '⧏'  => '&LeftTriangleBar;',
      '⧏̸' => '&NotLeftTriangleBar;',
      '⧐'  => '&RightTriangleBar;',
      '⧐̸' => '&NotRightTriangleBar;',
      '⧜'  => '&iinfin;',
      '⧝'  => '&infintie;',
      '⧞'  => '&nvinfin;',
      '⧣'  => '&eparsl;',
      '⧤'  => '&smeparsl;',
      '⧥'  => '&eqvparsl;',
      '⧫'  => '&lozf;',
      '⧴'  => '&RuleDelayed;',
      '⧶'  => '&dsol;',
      '⨀'  => '&xodot;',
      '⨁'  => '&bigoplus;',
      '⨂'  => '&bigotimes;',
      '⨄'  => '&biguplus;',
      '⨆'  => '&bigsqcup;',
      '⨌'  => '&iiiint;',
      '⨍'  => '&fpartint;',
      '⨐'  => '&cirfnint;',
      '⨑'  => '&awint;',
      '⨒'  => '&rppolint;',
      '⨓'  => '&scpolint;',
      '⨔'  => '&npolint;',
      '⨕'  => '&pointint;',
      '⨖'  => '&quatint;',
      '⨗'  => '&intlarhk;',
      '⨢'  => '&pluscir;',
      '⨣'  => '&plusacir;',
      '⨤'  => '&simplus;',
      '⨥'  => '&plusdu;',
      '⨦'  => '&plussim;',
      '⨧'  => '&plustwo;',
      '⨩'  => '&mcomma;',
      '⨪'  => '&minusdu;',
      '⨭'  => '&loplus;',
      '⨮'  => '&roplus;',
      '⨯'  => '&Cross;',
      '⨰'  => '&timesd;',
      '⨱'  => '&timesbar;',
      '⨳'  => '&smashp;',
      '⨴'  => '&lotimes;',
      '⨵'  => '&rotimes;',
      '⨶'  => '&otimesas;',
      '⨷'  => '&Otimes;',
      '⨸'  => '&odiv;',
      '⨹'  => '&triplus;',
      '⨺'  => '&triminus;',
      '⨻'  => '&tritime;',
      '⨼'  => '&iprod;',
      '⨿'  => '&amalg;',
      '⩀'  => '&capdot;',
      '⩂'  => '&ncup;',
      '⩃'  => '&ncap;',
      '⩄'  => '&capand;',
      '⩅'  => '&cupor;',
      '⩆'  => '&cupcap;',
      '⩇'  => '&capcup;',
      '⩈'  => '&cupbrcap;',
      '⩉'  => '&capbrcup;',
      '⩊'  => '&cupcup;',
      '⩋'  => '&capcap;',
      '⩌'  => '&ccups;',
      '⩍'  => '&ccaps;',
      '⩐'  => '&ccupssm;',
      '⩓'  => '&And;',
      '⩔'  => '&Or;',
      '⩕'  => '&andand;',
      '⩖'  => '&oror;',
      '⩗'  => '&orslope;',
      '⩘'  => '&andslope;',
      '⩚'  => '&andv;',
      '⩛'  => '&orv;',
      '⩜'  => '&andd;',
      '⩝'  => '&ord;',
      '⩟'  => '&wedbar;',
      '⩦'  => '&sdote;',
      '⩪'  => '&simdot;',
      '⩭'  => '&congdot;',
      '⩭̸' => '&ncongdot;',
      '⩮'  => '&easter;',
      '⩯'  => '&apacir;',
      '⩰'  => '&apE;',
      '⩰̸' => '&napE;',
      '⩱'  => '&eplus;',
      '⩲'  => '&pluse;',
      '⩳'  => '&Esim;',
      '⩴'  => '&Colone;',
      '⩵'  => '&Equal;',
      '⩷'  => '&ddotseq;',
      '⩸'  => '&equivDD;',
      '⩹'  => '&ltcir;',
      '⩺'  => '&gtcir;',
      '⩻'  => '&ltquest;',
      '⩼'  => '&gtquest;',
      '⩽'  => '&les;',
      '⩽̸' => '&nles;',
      '⩾'  => '&ges;',
      '⩾̸' => '&nges;',
      '⩿'  => '&lesdot;',
      '⪀'  => '&gesdot;',
      '⪁'  => '&lesdoto;',
      '⪂'  => '&gesdoto;',
      '⪃'  => '&lesdotor;',
      '⪄'  => '&gesdotol;',
      '⪅'  => '&lap;',
      '⪆'  => '&gap;',
      '⪇'  => '&lne;',
      '⪈'  => '&gne;',
      '⪉'  => '&lnap;',
      '⪊'  => '&gnap;',
      '⪋'  => '&lesseqqgtr;',
      '⪌'  => '&gEl;',
      '⪍'  => '&lsime;',
      '⪎'  => '&gsime;',
      '⪏'  => '&lsimg;',
      '⪐'  => '&gsiml;',
      '⪑'  => '&lgE;',
      '⪒'  => '&glE;',
      '⪓'  => '&lesges;',
      '⪔'  => '&gesles;',
      '⪕'  => '&els;',
      '⪖'  => '&egs;',
      '⪗'  => '&elsdot;',
      '⪘'  => '&egsdot;',
      '⪙'  => '&el;',
      '⪚'  => '&eg;',
      '⪝'  => '&siml;',
      '⪞'  => '&simg;',
      '⪟'  => '&simlE;',
      '⪠'  => '&simgE;',
      '⪡'  => '&LessLess;',
      '⪡̸' => '&NotNestedLessLess;',
      '⪢'  => '&GreaterGreater;',
      '⪢̸' => '&NotNestedGreaterGreater;',
      '⪤'  => '&glj;',
      '⪥'  => '&gla;',
      '⪦'  => '&ltcc;',
      '⪧'  => '&gtcc;',
      '⪨'  => '&lescc;',
      '⪩'  => '&gescc;',
      '⪪'  => '&smt;',
      '⪫'  => '&lat;',
      '⪬'  => '&smte;',
      '⪬︀' => '&smtes;',
      '⪭'  => '&late;',
      '⪭︀' => '&lates;',
      '⪮'  => '&bumpE;',
      '⪯'  => '&preceq;',
      '⪯̸' => '&NotPrecedesEqual;',
      '⪰'  => '&SucceedsEqual;',
      '⪰̸' => '&NotSucceedsEqual;',
      '⪳'  => '&prE;',
      '⪴'  => '&scE;',
      '⪵'  => '&precneqq;',
      '⪶'  => '&scnE;',
      '⪷'  => '&precapprox;',
      '⪸'  => '&succapprox;',
      '⪹'  => '&precnapprox;',
      '⪺'  => '&succnapprox;',
      '⪻'  => '&Pr;',
      '⪼'  => '&Sc;',
      '⪽'  => '&subdot;',
      '⪾'  => '&supdot;',
      '⪿'  => '&subplus;',
      '⫀'  => '&supplus;',
      '⫁'  => '&submult;',
      '⫂'  => '&supmult;',
      '⫃'  => '&subedot;',
      '⫄'  => '&supedot;',
      '⫅'  => '&subE;',
      '⫅̸' => '&nsubE;',
      '⫆'  => '&supseteqq;',
      '⫆̸' => '&nsupseteqq;',
      '⫇'  => '&subsim;',
      '⫈'  => '&supsim;',
      '⫋'  => '&subsetneqq;',
      '⫋︀' => '&vsubnE;',
      '⫌'  => '&supnE;',
      '⫌︀' => '&varsupsetneqq;',
      '⫏'  => '&csub;',
      '⫐'  => '&csup;',
      '⫑'  => '&csube;',
      '⫒'  => '&csupe;',
      '⫓'  => '&subsup;',
      '⫔'  => '&supsub;',
      '⫕'  => '&subsub;',
      '⫖'  => '&supsup;',
      '⫗'  => '&suphsub;',
      '⫘'  => '&supdsub;',
      '⫙'  => '&forkv;',
      '⫚'  => '&topfork;',
      '⫛'  => '&mlcp;',
      '⫤'  => '&Dashv;',
      '⫦'  => '&Vdashl;',
      '⫧'  => '&Barv;',
      '⫨'  => '&vBar;',
      '⫩'  => '&vBarv;',
      '⫫'  => '&Vbar;',
      '⫬'  => '&Not;',
      '⫭'  => '&bNot;',
      '⫮'  => '&rnmid;',
      '⫯'  => '&cirmid;',
      '⫰'  => '&midcir;',
      '⫱'  => '&topcir;',
      '⫲'  => '&nhpar;',
      '⫳'  => '&parsim;',
      '⫽'  => '&parsl;',
      '⫽⃥' => '&nparsl;',
      'ﬀ'  => '&fflig;',
      'ﬁ'  => '&filig;',
      'ﬂ'  => '&fllig;',
      'ﬃ'  => '&ffilig;',
      'ﬄ'  => '&ffllig;',
      '𝒜' => '&Ascr;',
      '𝒞' => '&Cscr;',
      '𝒟' => '&Dscr;',
      '𝒢' => '&Gscr;',
      '𝒥' => '&Jscr;',
      '𝒦' => '&Kscr;',
      '𝒩' => '&Nscr;',
      '𝒪' => '&Oscr;',
      '𝒫' => '&Pscr;',
      '𝒬' => '&Qscr;',
      '𝒮' => '&Sscr;',
      '𝒯' => '&Tscr;',
      '𝒰' => '&Uscr;',
      '𝒱' => '&Vscr;',
      '𝒲' => '&Wscr;',
      '𝒳' => '&Xscr;',
      '𝒴' => '&Yscr;',
      '𝒵' => '&Zscr;',
      '𝒶' => '&ascr;',
      '𝒷' => '&bscr;',
      '𝒸' => '&cscr;',
      '𝒹' => '&dscr;',
      '𝒻' => '&fscr;',
      '𝒽' => '&hscr;',
      '𝒾' => '&iscr;',
      '𝒿' => '&jscr;',
      '𝓀' => '&kscr;',
      '𝓁' => '&lscr;',
      '𝓂' => '&mscr;',
      '𝓃' => '&nscr;',
      '𝓅' => '&pscr;',
      '𝓆' => '&qscr;',
      '𝓇' => '&rscr;',
      '𝓈' => '&sscr;',
      '𝓉' => '&tscr;',
      '𝓊' => '&uscr;',
      '𝓋' => '&vscr;',
      '𝓌' => '&wscr;',
      '𝓍' => '&xscr;',
      '𝓎' => '&yscr;',
      '𝓏' => '&zscr;',
      '𝔄' => '&Afr;',
      '𝔅' => '&Bfr;',
      '𝔇' => '&Dfr;',
      '𝔈' => '&Efr;',
      '𝔉' => '&Ffr;',
      '𝔊' => '&Gfr;',
      '𝔍' => '&Jfr;',
      '𝔎' => '&Kfr;',
      '𝔏' => '&Lfr;',
      '𝔐' => '&Mfr;',
      '𝔑' => '&Nfr;',
      '𝔒' => '&Ofr;',
      '𝔓' => '&Pfr;',
      '𝔔' => '&Qfr;',
      '𝔖' => '&Sfr;',
      '𝔗' => '&Tfr;',
      '𝔘' => '&Ufr;',
      '𝔙' => '&Vfr;',
      '𝔚' => '&Wfr;',
      '𝔛' => '&Xfr;',
      '𝔜' => '&Yfr;',
      '𝔞' => '&afr;',
      '𝔟' => '&bfr;',
      '𝔠' => '&cfr;',
      '𝔡' => '&dfr;',
      '𝔢' => '&efr;',
      '𝔣' => '&ffr;',
      '𝔤' => '&gfr;',
      '𝔥' => '&hfr;',
      '𝔦' => '&ifr;',
      '𝔧' => '&jfr;',
      '𝔨' => '&kfr;',
      '𝔩' => '&lfr;',
      '𝔪' => '&mfr;',
      '𝔫' => '&nfr;',
      '𝔬' => '&ofr;',
      '𝔭' => '&pfr;',
      '𝔮' => '&qfr;',
      '𝔯' => '&rfr;',
      '𝔰' => '&sfr;',
      '𝔱' => '&tfr;',
      '𝔲' => '&ufr;',
      '𝔳' => '&vfr;',
      '𝔴' => '&wfr;',
      '𝔵' => '&xfr;',
      '𝔶' => '&yfr;',
      '𝔷' => '&zfr;',
      '𝔸' => '&Aopf;',
      '𝔹' => '&Bopf;',
      '𝔻' => '&Dopf;',
      '𝔼' => '&Eopf;',
      '𝔽' => '&Fopf;',
      '𝔾' => '&Gopf;',
      '𝕀' => '&Iopf;',
      '𝕁' => '&Jopf;',
      '𝕂' => '&Kopf;',
      '𝕃' => '&Lopf;',
      '𝕄' => '&Mopf;',
      '𝕆' => '&Oopf;',
      '𝕊' => '&Sopf;',
      '𝕋' => '&Topf;',
      '𝕌' => '&Uopf;',
      '𝕍' => '&Vopf;',
      '𝕎' => '&Wopf;',
      '𝕏' => '&Xopf;',
      '𝕐' => '&Yopf;',
      '𝕒' => '&aopf;',
      '𝕓' => '&bopf;',
      '𝕔' => '&copf;',
      '𝕕' => '&dopf;',
      '𝕖' => '&eopf;',
      '𝕗' => '&fopf;',
      '𝕘' => '&gopf;',
      '𝕙' => '&hopf;',
      '𝕚' => '&iopf;',
      '𝕛' => '&jopf;',
      '𝕜' => '&kopf;',
      '𝕝' => '&lopf;',
      '𝕞' => '&mopf;',
      '𝕟' => '&nopf;',
      '𝕠' => '&oopf;',
      '𝕡' => '&popf;',
      '𝕢' => '&qopf;',
      '𝕣' => '&ropf;',
      '𝕤' => '&sopf;',
      '𝕥' => '&topf;',
      '𝕦' => '&uopf;',
      '𝕧' => '&vopf;',
      '𝕨' => '&wopf;',
      '𝕩' => '&xopf;',
      '𝕪' => '&yopf;',
      '𝕫' => '&zopf;',
  );

  /**
   * List of never allowed regex replacements
   *
   * @var  array
   */
  protected static $_never_allowed_regex = array(
    // default javascript
    'javascript\s*:',
    // default javascript
    '(document|(document\.)?window)\.(location|on\w*)',
    // Java: jar-protocol is an XSS hazard
    'jar\s*:',
    // Mac (will not run the script, but open it in AppleScript Editor)
    'applescript\s*:',
    // IE: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#VBscript_in_an_image
    'vbscript\s*:',
    // IE, surprise!
    'wscript\s*:',
    // IE
    'jscript\s*:',
    // IE: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#VBscript_in_an_image
    'vbs\s*:',
    // https://html5sec.org/#behavior
    'behavior\s:',
    // ?
    'Redirect\s+30\d',
    // data-attribute + base64
    "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?",
    // remove Netscape 4 JS entities
    '&\s*\{[^}]*(\}\s*;?|$)',
    // old IE, old Netscape
    'expression\s*(\(|&\#40;)',
    // old Netscape
    'mocha\s*:',
    // old Netscape
    'livescript\s*:',
  );

  /**
   * XSS Hash - random Hash for protecting URLs.
   *
   * @var  string
   */
  protected $_xss_hash;

  /**
   * the replacement-string for not allowed strings
   *
   * @var string
   */
  protected $_replacement = '';

  /**
   * list of never allowed strings
   *
   * @var  array
   */
  protected $_never_allowed_str = array();

  /**
   * list of never allowed strings, afterwards
   *
   * @var array
   */
  protected $_never_allowed_str_afterwards = array();

  /**
   * __construct()
   */
  public function __construct()
  {
      $this->_never_allowed_str = array(
        'document.cookie' => $this->_replacement,
        'document.write'  => $this->_replacement,
        '.parentNode'     => $this->_replacement,
        '.innerHTML'      => $this->_replacement,
        '-moz-binding'    => $this->_replacement,
        '<!--'            => '&lt;!--',
        '-->'             => '--&gt;',
        '<![CDATA['       => '&lt;![CDATA[',
        '<!ENTITY'        => '&lt;!ENTITY',
        '<!DOCTYPE'       => '&lt;!DOCTYPE',
        '<!ATTLIST'       => '&lt;!ATTLIST',
        '<comment>'       => '&lt;comment&gt;',
    );

      $this->_never_allowed_str_afterwards = array(
        'FSCommand',
        'onAbort',
        'onActivate',
        'onAttribute',
        'onAfterPrint',
        'onAfterScriptExecute',
        'onAfterUpdate',
        'onAnimationEnd',
        'onAnimationIteration',
        'onAnimationStart',
        'onAriaRequest',
        'onAutoComplete',
        'onAutoCompleteError',
        'onBeforeActivate',
        'onBeforeCopy',
        'onBeforeCut',
        'onBeforeDeactivate',
        'onBeforeEditFocus',
        'onBeforePaste',
        'onBeforePrint',
        'onBeforeScriptExecute',
        'onBeforeUnload',
        'onBeforeUpdate',
        'onBegin',
        'onBlur',
        'onBounce',
        'onCancel',
        'onCanPlay',
        'onCanPlayThrough',
        'onCellChange',
        'onChange',
        'onClick',
        'onClose',
        'onCommand',
        'onCompassNeedsCalibration',
        'onContextMenu',
        'onControlSelect',
        'onCopy',
        'onCueChange',
        'onCut',
        'onDataAvailable',
        'onDataSetChanged',
        'onDataSetComplete',
        'onDblClick',
        'onDeactivate',
        'onDeviceLight',
        'onDeviceMotion',
        'onDeviceOrientation',
        'onDeviceProximity',
        'onDrag',
        'onDragDrop',
        'onDragEnd',
        'onDragEnter',
        'onDragLeave',
        'onDragOver',
        'onDragStart',
        'onDrop',
        'onDurationChange',
        'onEmptied',
        'onEnd',
        'onEnded',
        'onError',
        'onErrorUpdate',
        'onExit',
        'onFilterChange',
        'onFinish',
        'onFocus',
        'onFocusIn',
        'onFocusOut',
        'onFormChange',
        'onFormInput',
        'onFullScreenChange',
        'onFullScreenError',
        'onGotPointerCapture',
        'onHashChange',
        'onHelp',
        'onInput',
        'onInvalid',
        'onKeyDown',
        'onKeyPress',
        'onKeyUp',
        'onLanguageChange',
        'onLayoutComplete',
        'onLoad',
        'onLoadedData',
        'onLoadedMetaData',
        'onLoadStart',
        'onLoseCapture',
        'onLostPointerCapture',
        'onMediaComplete',
        'onMediaError',
        'onMessage',
        'onMouseDown',
        'onMouseEnter',
        'onMouseLeave',
        'onMouseMove',
        'onMouseOut',
        'onMouseOver',
        'onMouseUp',
        'onMouseWheel',
        'onMove',
        'onMoveEnd',
        'onMoveStart',
        'onMozFullScreenChange',
        'onMozFullScreenError',
        'onMozPointerLockChange',
        'onMozPointerLockError',
        'onMsContentZoom',
        'onMsFullScreenChange',
        'onMsFullScreenError',
        'onMsGestureChange',
        'onMsGestureDoubleTap',
        'onMsGestureEnd',
        'onMsGestureHold',
        'onMsGestureStart',
        'onMsGestureTap',
        'onMsGotPointerCapture',
        'onMsInertiaStart',
        'onMsLostPointerCapture',
        'onMsManipulationStateChanged',
        'onMsPointerCancel',
        'onMsPointerDown',
        'onMsPointerEnter',
        'onMsPointerLeave',
        'onMsPointerMove',
        'onMsPointerOut',
        'onMsPointerOver',
        'onMsPointerUp',
        'onMsSiteModeJumpListItemRemoved',
        'onMsThumbnailClick',
        'onOffline',
        'onOnline',
        'onOutOfSync',
        'onPage',
        'onPageHide',
        'onPageShow',
        'onPaste',
        'onPause',
        'onPlay',
        'onPlaying',
        'onPointerCancel',
        'onPointerDown',
        'onPointerEnter',
        'onPointerLeave',
        'onPointerLockChange',
        'onPointerLockError',
        'onPointerMove',
        'onPointerOut',
        'onPointerOver',
        'onPointerUp',
        'onPopState',
        'onProgress',
        'onPropertyChange',
        'onRateChange',
        'onReadyStateChange',
        'onReceived',
        'onRepeat',
        'onReset',
        'onResize',
        'onResizeEnd',
        'onResizeStart',
        'onResume',
        'onReverse',
        'onRowDelete',
        'onRowEnter',
        'onRowExit',
        'onRowInserted',
        'onRowsDelete',
        'onRowsEnter',
        'onRowsExit',
        'onRowsInserted',
        'onScroll',
        'onSearch',
        'onSeek',
        'onSeeked',
        'onSeeking',
        'onSelect',
        'onSelectionChange',
        'onSelectStart',
        'onStalled',
        'onStorage',
        'onStorageCommit',
        'onStart',
        'onStop',
        'onShow',
        'onSyncRestored',
        'onSubmit',
        'onSuspend',
        'onSynchRestored',
        'onTimeError',
        'onTimeUpdate',
        'onTrackChange',
        'onTransitionEnd',
        'onToggle',
        'onUnload',
        'onURLFlip',
        'onUserProximity',
        'onVolumeChange',
        'onWaiting',
        'onWebKitAnimationEnd',
        'onWebKitAnimationIteration',
        'onWebKitAnimationStart',
        'onWebKitFullScreenChange',
        'onWebKitFullScreenError',
        'onWebKitTransitionEnd',
        'onWheel',
        'seekSegmentTime',
        'userid',
        'datasrc',
        'datafld',
        'dataformatas',
        'ev:handler',
        'ev:event',
        '0;url',
    );
  }

  /**
   * XSS Clean
   *
   * Sanitizes data so that Cross Site Scripting Hacks can be
   * prevented.  This method does a fair amount of work but
   * it is extremely thorough, designed to prevent even the
   * most obscure XSS attempts.  Nothing is ever 100% foolproof,
   * of course, but I haven't been able to get anything passed
   * the filter.
   *
   * Note: Should only be used to deal with data upon submission.
   *   It's not something that should be used for general
   *   runtime processing.
   *
   * @link  http://channel.bitflux.ch/wiki/XSS_Prevention
   *    Based in part on some code and ideas from Bitflux.
   *
   * @link  http://ha.ckers.org/xss.html
   *    To help develop this script I used this great list of
   *    vulnerabilities along with a few other hacks I've
   *    harvested from examining vulnerabilities in other programs.
   *
   * @param  mixed $str      input data e.g. string or array
   * @param  bool  $is_image whether the input is an image
   *
   * @return  string|array|boolean  boolean: will return a boolean, if the "is_image"-parameter is true
   *                                string: will return a string, if the input is a string
   *                                array: will return a array, if the input is a array
   */
  public function xss_clean($str, $is_image = false)
  {
      if (is_array($str)) {
          foreach ($str as &$value) {
              $value = $this->xss_clean($value);
          }

          return $str;
      }

      $str = (string)$str;
      $strInt = (int)$str;
      $strFloat = (float)$str;
    /** @noinspection TypeUnsafeComparisonInspection */
    if (
        !$str
        ||
        $str === null
        ||
        is_bool($str)
        ||
        "$strInt" == $str || is_int($str)
        ||
        "$strFloat" == $str || is_float($str)
    ) {
        return $str;
    }

    // removes all non-UTF-8 characters
    // &&
    // remove NULL characters (ignored by some browsers)
    $str = UTF8::clean($str, true, true, false);

    // decode the string
    $str = $this->decode_string($str);

    // and again... removes all non-UTF-8 characters
    $str = UTF8::clean($str, true, true, false);

    // capture converted string for later comparison
    if ($is_image === true) {
        $converted_string = $str;
    }

      do {
          $old_str = $str;
          $str = $this->_do($str, $is_image);
      } while ($old_str !== $str);

    /*
     * images are Handled in a special way
     *
     * Essentially, we want to know that after all of the character
     * conversion is done whether any unwanted, likely XSS, code was found.
     *
     * If not, we return TRUE, as the image is clean.
     *
     * However, if the string post-conversion does not matched the
     * string post-removal of XSS, then it fails, as there was unwanted XSS
     * code found and removed/changed during processing.
     */
    if ($is_image === true) {
        /** @noinspection PhpUndefinedVariableInspection */
      return ($str === $converted_string);
    }

      return $str;
  }

  /**
   * @param $str
   * @param $is_image
   *
   * @return mixed
   */
  protected function _do($str, $is_image)
  {
      // remove strings that are never allowed
    $str = $this->_do_never_allowed($str);

    // make php tags safe for displaying
    $str = $this->make_php_tags_safe($str, $is_image);

    // corrects words before the browser will do it
    $str = $this->compact_exploded_javascript($str);

    // remove disallowed javascript calls in links, images etc.
    $str = $this->remove_disallowed_javascript($str);

    // remove evil attributes such as style, onclick and xmlns
    $str = $this->remove_evil_attributes($str, $is_image);

    // sanitize naughty HTML elements
    $str = $this->sanitize_naughty_html($str);

    // sanitize naughty JavaScript elements
    $str = $this->sanitize_naughty_javascript($str);

    // final clean up

    // This adds a bit of extra precaution in case
    // something got through the above filters.
    $str = $this->_do_never_allowed($str);
      $str = $this->_do_never_allowed_afterwards($str);

      return $str;
  }

  /**
   * decode the html-tags via "UTF8::html_entity_decode()" or the string via "UTF8::urldecode()"
   *
   * @param string $str
   *
   * @return string
   */
  protected function decode_string($str)
  {
      if (preg_match('/<\w+.*/si', $str, $matches) === 1) {
          $str = preg_replace_callback(
          '/<\w+.*/si',
          array(
              $this,
              '_decode_entity',
          ),
          $str
      );
      } else {
          $str = UTF8::urldecode($str);
      }

      return $str;
  }

  /**
   * Do Never Allowed
   *
   * @param string $str
   *
   * @return  string
   */
  protected function _do_never_allowed($str)
  {
      static $neverAllowedRegex;

      if (null === $neverAllowedRegex) {
          $neverAllowedRegex = implode('|', self::$_never_allowed_regex);
      }

      $str = str_ireplace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str);

      $str = preg_replace('#' . $neverAllowedRegex . '#is', $this->_replacement, $str);

      return (string)$str;
  }

  /*
   * Makes PHP tags safe
   *
   * Note: XML tags are inadvertently replaced too:
   *
   * <?xml
   *
   * But it doesn't seem to pose a problem.
   *
   * @param string $str
   * @param boolean $is_image
   *
   * @return string
   */
  public function make_php_tags_safe($str, $is_image)
  {
      if ($is_image === true) {
          // Images have a tendency to have the PHP short opening and
      // closing tags every so often so we skip those and only
      // do the long opening tags.
      $str = preg_replace('/<\?(php)/i', '&lt;?\\1', $str);
      } else {
          $str = str_replace(
          array(
              '<?',
              '?>',
          ),
          array(
              '&lt;?',
              '?&gt;',
          ),
          $str
      );
      }

      return (string)$str;
  }

  /**
   * Compact any exploded words
   *
   * This corrects words like:  j a v a s c r i p t
   * These words are compacted back to their correct state.
   *
   * @param string $str
   *
   * @return string
   */
  public function compact_exploded_javascript($str)
  {
      static $wordsCache;

      $words = array(
        'javascript',
        'expression',
        'vbscript',
        'jscript',
        'wscript',
        'vbs',
        'script',
        'base64',
        'applet',
        'alert',
        'document',
        'write',
        'cookie',
        'window',
        'confirm',
        'prompt',
        'eval',
    );

      foreach ($words as $word) {
          if (!isset($wordsCache[$word])) {
              $word = $wordsCache[$word] = chunk_split($word, 1, '\s*');
          } else {
              $word = $wordsCache[$word];
          }

      // We only want to do this when it is followed by a non-word character
      // That way valid stuff like "dealer to" does not become "dealerto".
      $str = preg_replace_callback(
          '#(' . substr($word, 0, -3) . ')(\W)#is',
          array(
              $this,
              '_compact_exploded_words',
          ),
          $str
      );
      }

      return (string)$str;
  }

  /**
   * Remove disallowed Javascript in links or img tags
   * We used to do some version comparisons and use of stripos(),
   * but it is dog slow compared to these simplified non-capturing
   * preg_match(), especially if the pattern exists in the string
   *
   * Note: It was reported that not only space characters, but all in
   * the following pattern can be parsed as separators between a tag name
   * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C]
   * ... however, remove_invisible_characters() above already strips the
   * hex-encoded ones, so we'll skip them below.
   *
   * @param string $str
   *
   * @return string
   */
  public function remove_disallowed_javascript($str)
  {
      do {
          $original = $str;

          if (preg_match('/<a/i', $str)) {
              $str = preg_replace_callback(
            '#<a[^a-z0-9>]+([^>]*?)(?:>|$)#i',
            array(
                $this,
                '_js_link_removal',
            ),
            $str
        );
          }

          if (preg_match('/<img/i', $str)) {
              $str = preg_replace_callback(
            '#<img[^a-z0-9]+([^>]*?)(?:\s?/?>|$)#i',
            array(
                $this,
                '_js_img_removal',
            ),
            $str
        );
          }

          if (preg_match('/script|xss/i', $str)) {
              $str = preg_replace('#</*(?:script|xss).*?>#si', $this->_replacement, $str);
          }
      } while ($original !== $str);

      return (string)$str;
  }

  /**
   * Remove Evil HTML Attributes (like event handlers and style)
   *
   * It removes the evil attribute and either:
   *
   *  - Everything up until a space. For example, everything between the pipes:
   *
   *  <code>
   *    <a |style=document.write('hello');alert('world');| class=link>
   *  </code>
   *
   *  - Everything inside the quotes. For example, everything between the pipes:
   *
   *  <code>
   *    <a |style="document.write('hello'); alert('world');"| class="link">
   *  </code>
   *
   * @param  string $str      The string to check
   * @param  bool   $is_image Whether the input is an image
   *
   * @return  string  The string with the evil attributes removed
   */
  public function remove_evil_attributes($str, $is_image)
  {
      // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Event_Handlers

    $evil_attributes = array(
        'on\w*',
        'style',
        'xmlns',
        'formaction',
        'form',
        'xlink:href',
        'seekSegmentTime',
        'FSCommand',
        'eval',
    );

      if ($is_image === true) {
          /*
       * Adobe Photoshop puts XML metadata into JFIF images,
       * including namespacing, so we have to allow this for images.
       */
      unset($evil_attributes[array_search('xmlns', $evil_attributes, true)]);
      }

      $evil_attributes_string = implode('|', $evil_attributes);

      do {
          $count = $temp_count = 0;

      // replace occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
      $str = preg_replace('/(<[^>]+)(?<!\w)(' . $evil_attributes_string . ')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is', '$1' . $this->_replacement, $str, -1, $temp_count);
          $count += $temp_count;

      // find occurrences of illegal attribute strings without quotes
      $str = preg_replace('/(<[^>]+)(?<!\w)(' . $evil_attributes_string . ')\s*=\s*([^\s>]*)/is', '$1' . $this->_replacement, $str, -1, $temp_count);
          $count += $temp_count;
      } while ($count);

      return (string)$str;
  }

  /**
   * 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;
   *
   * @param string $str
   *
   * @return string
   */
  public function sanitize_naughty_html($str)
  {
      $naughty = 'alert|prompt|confirm|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|button|select|isindex|layer|link|meta|keygen|object|plaintext|style|script|textarea|title|math|video|svg|xml|xss|eval';
      $str = preg_replace_callback(
        '#<(/*\s*)(' . $naughty . ')([^><]*)([><]*)#is',
        array(
            $this,
            '_sanitize_naughty_html',
        ),
        $str
    );

      return (string)$str;
  }

  /**
   * 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;
   *
   * @param string $str
   *
   * @return string
   */
  public function sanitize_naughty_javascript($str)
  {
      $str = preg_replace(
        '#(alert|eval|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si',
        '\\1\\2&#40;\\3&#41;',
        $str
    );

      return (string)$str;
  }

  /**
   * Do Never Allowed Afterwards
   *
   * clean-up also some string, also if there is no html-tag
   *
   * @param string $str
   *
   * @return  string
   */
  protected function _do_never_allowed_afterwards($str)
  {
      static $neverAllowedStrAfterwardsRegex;

      if (null === $neverAllowedStrAfterwardsRegex) {
          foreach ($this->_never_allowed_str_afterwards as &$neverAllowedStr) {
              $neverAllowedStr .= '.*=';
          }
          unset($neverAllowedStr);

          $neverAllowedStrAfterwardsRegex = implode('|', $this->_never_allowed_str_afterwards);
      }

      $str = preg_replace('#' . $neverAllowedStrAfterwardsRegex . '#isU', $this->_replacement, $str);

      return (string)$str;
  }

  /**
   * set the replacement-string for not allowed strings
   *
   * @param string $string
   */
  public function setReplacement($string)
  {
      $this->_replacement = (string)$string;
  }

  /**
   * Compact Exploded Words
   *
   * Callback method for xss_clean() to remove whitespace from
   * things like 'j a v a s c r i p t'.
   *
   * @param  array $matches
   *
   * @return  string
   */
  protected function _compact_exploded_words($matches)
  {
      return preg_replace('/\s+/', '', $matches[1]) . $matches[2];
  }

  /**
   * Sanitize Naughty HTML
   *
   * Callback method for AntiXSS->sanitize_naughty_html() to remove naughty HTML elements.
   *
   * @param  array $matches
   *
   * @return  string
   */
  protected function _sanitize_naughty_html($matches)
  {
      return '&lt;' . $matches[1] . $matches[2] . $matches[3] // encode opening brace
           // encode captured opening or closing brace to prevent recursive vectors:
           . str_replace(
               array(
                   '>',
                   '<',
               ),
               array(
                   '&gt;',
                   '&lt;',
               ),
               $matches[4]
           );
  }

  /**
   * JS Image Removal
   *
   * Callback method for xss_clean() to sanitize image tags.
   *
   * This limits the PCRE backtracks, making it more performance friendly
   * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
   * PHP 5.2+ on image tag heavy strings.
   *
   * @param  array $match
   *
   * @return  string
   */
  protected function _js_img_removal($match)
  {
      return $this->_js_removal($match, 'src');
  }

  /**
   * JS Removal
   *
   * Callback method for xss_clean() to sanitize tags.
   *
   * This limits the PCRE backtracks, making it more performance friendly
   * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
   * PHP 5.2+ on image tag heavy strings.
   *
   * @param  array $match
   * @param string $search
   *
   * @return  string
   */
  protected function _js_removal($match, $search)
  {
      if (!$match[0]) {
          return '';
      }

      $replacer = preg_replace(
        '#' . $search . '=.*?(?:(?:alert|prompt|confirm)(?:\((\')*|&\#40;)|javascript:|livescript:|wscript:|vbscript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
        '',
        $this->_filter_attributes(str_replace(array('<', '>',), '', $match[1]))
    );

      return str_ireplace($match[1], $replacer, $match[0]);
  }

  /**
   * Filter Attributes
   *
   * Filters tag attributes for consistency and safety.
   *
   * @param  string $str
   *
   * @return  string
   */
  protected function _filter_attributes($str)
  {
      if ($str === '') {
          return '';
      }

      $out = '';
      if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#i', $str, $matches)) {
          foreach ($matches[0] as $match) {
              $out .= preg_replace('#/\*.*?\*/#s', '', $match);
          }
      }

      return $out;
  }

  /**
   * JS Link Removal
   *
   * Callback method for xss_clean() to sanitize links.
   *
   * This limits the PCRE backtracks, making it more performance friendly
   * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
   * PHP 5.2+ on link-heavy strings.
   *
   * @param  array $match
   *
   * @return  string
   */
  protected function _js_link_removal($match)
  {
      return $this->_js_removal($match, 'href');
  }

  /**
   * HTML Entity Decode Callback
   *
   * @param  array $match
   *
   * @return  string
   */
  protected function _decode_entity($match)
  {
      $hash = $this->xss_hash();

    // protect GET variables in URLs
    // 901119URL5918AMP18930PROTECT8198
    $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', $hash . '\\1=\\2', $match[0]);

    // un-protect URL GET vars
    return str_replace($this->xss_hash(), '&', $this->_entity_decode($match));
  }

  /**
   * XSS Hash
   *
   * Generates the XSS hash if needed and returns it.
   *
   * @return  string  XSS hash
   */
  public function xss_hash()
  {
      if ($this->_xss_hash === null) {
          $rand = Bootup::get_random_bytes(16);

          if (!$rand) {
              $this->_xss_hash = md5(uniqid(mt_rand(), true));
          } else {
              $this->_xss_hash = bin2hex($rand);
          }
      }

      return $this->_xss_hash;
  }

  /**
   * @param $str
   *
   * @return string
   */
  protected function _entity_decode($str)
  {
      static $entities;

      $flags = Bootup::is_php('5.4') ? ENT_QUOTES | ENT_HTML5 : ENT_QUOTES;

    // decode
    if (strpos($str, $this->xss_hash()) !== false) {
        $str = UTF8::html_entity_decode($str, $flags);
    } else {
        $str = UTF8::urldecode($str);
    }

    // decode-again, for e.g. HHVM, PHP 5.3, miss configured applications ...
    if (preg_match_all('/&[a-z]{2,}[;]{0}/i', $str, $matches)) {
        if (null === $entities) {

        // links:
        // - http://dev.w3.org/html5/html-author/charref
        // - http://www.w3schools.com/charsets/ref_html_entities_n.asp
        $entitiesSecurity = array(
            '&#x00000;'          => '',
            '&#0;'               => '',
            '&#x00001;'          => '',
            '&#1;'               => '',
            '&nvgt;'             => '',
            '&#61253;'           => '',
            '&#x0EF45;'          => '',
            '&shy;'              => '',
            '&#x000AD;'          => '',
            '&#173;'             => '',
            '&colon;'            => ':',
            '&#x0003A;'          => ':',
            '&#58;'              => ':',
            '&lpar;'             => '(',
            '&#x00028;'          => '(',
            '&#40;'              => '(',
            '&rpar;'             => ')',
            '&#x00029;'          => ')',
            '&#41;'              => ')',
            '&quest;'            => '?',
            '&#x0003F;'          => '?',
            '&#63;'              => '?',
            '&sol;'              => '/',
            '&#x0002F;'          => '/',
            '&#47;'              => '/',
            '&apos;'             => '\'',
            '&#x00027;'          => '\'',
            '&#39;'              => '\'',
            '&bsol;'             => '\\',
            '&#x0005C;'          => '\\',
            '&#92;'              => '\\',
            '&comma;'            => ',',
            '&#x0002C;'          => ',',
            '&#44;'              => ',',
            '&period;'           => '.',
            '&#x0002E;'          => '.',
            '&quot;'             => '"',
            '&QUOT;'             => '"',
            '&#x00022;'          => '"',
            '&#34;'              => '"',
            '&grave;'            => '`',
            '&DiacriticalGrave;' => '`',
            '&#x00060;'          => '`',
            '&#96;'              => '`',
            '&#46;'              => '.',
            '&equals;'           => '=',
            '&#x0003D;'          => '=',
            '&#61;'              => '=',
            '&newline;'          => "\n",
            '&#x0000A;'          => "\n",
            '&#10;'              => "\n",
            '&tab;'              => "\t",
            '&#x00009;'          => "\n",
            '&#9;'               => "\n",
        );

            $entitiesTmp = get_html_translation_table(HTML_ENTITIES, $flags);
            $entitiesTmp = array_merge(self::$entitiesFallback, $entitiesTmp);

            $entities = array_merge(
            $entitiesSecurity,
            array_map('strtolower', array_flip($entitiesTmp))
        );
        }

        $replace = array();
        $matches = array_unique(array_map('strtolower', $matches[0]));
        foreach ($matches as $match) {
            $match .= ';';
            if (array_key_exists($match, $entities) === true) {
                $replace[$match] = $entities[$match];
            }
        }

        if (count($replace) > 0) {
            $str = str_ireplace(array_keys($replace), array_values($replace), $str);
        }
    }

      return $str;
  }
}
