re2js 2.1.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  * re2js
3
3
  * RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching
4
4
  *
5
- * @version v2.1.1
5
+ * @version v2.2.1
6
6
  * @author Alexey Vasiliev
7
7
  * @homepage https://github.com/le0pard/re2js#readme
8
8
  * @repository github:le0pard/re2js
@@ -40,6 +40,8 @@ class RE2Flags {
40
40
  static UNICODE_GROUPS = 0x80;
41
41
  // Regexp END_TEXT was $, not \z. Internal use only.
42
42
  static WAS_DOLLAR = 0x100;
43
+ // Allow captureless Lookbehinds (?<=) and (?<!)
44
+ static LOOKBEHIND = 0x200;
43
45
  static MATCH_NL = RE2Flags.CLASS_NL | RE2Flags.DOT_NL;
44
46
  // As close to Perl as possible.
45
47
  static PERL = RE2Flags.CLASS_NL | RE2Flags.ONE_LINE | RE2Flags.PERL_X | RE2Flags.UNICODE_GROUPS;
@@ -51,12 +53,31 @@ class RE2Flags {
51
53
  static ANCHOR_BOTH = 2;
52
54
  }
53
55
 
56
+ /**
57
+ * Public flags for RE2JS and RE2Set compilation.
58
+ */
59
+ const PublicFlags = {
60
+ CASE_INSENSITIVE: 1,
61
+ // case insensitive matching
62
+ DOTALL: 2,
63
+ // dot matches all characters, including newline
64
+ MULTILINE: 4,
65
+ // multiline matching
66
+ DISABLE_UNICODE_GROUPS: 8,
67
+ // unicode groups will be syntax errors
68
+ LONGEST_MATCH: 16,
69
+ // matches longest possible string
70
+ LOOKBEHINDS: 512 // enable linear-time captureless lookbehinds
71
+ };
72
+
54
73
  /**
55
74
  * Various constants and helper for unicode codepoints.
56
75
  */
57
76
  const ASCII_SIZE = 128;
58
77
  const ASCII_TO_UPPER = new Int32Array(ASCII_SIZE);
59
78
  const ASCII_TO_LOWER = new Int32Array(ASCII_SIZE);
79
+ // The highest legal Basic Multilingual Plane (BMP) value.
80
+ const MAX_BMP = 0xffff;
60
81
  for (let i = 0; i < ASCII_SIZE; i++) {
61
82
  if (i >= 97 && i <= 122) {
62
83
  // a-z
@@ -80,11 +101,13 @@ class Codepoint {
80
101
  static toUpperCase(codepoint) {
81
102
  if (codepoint < ASCII_SIZE) return ASCII_TO_UPPER[codepoint];
82
103
  const s = String.fromCodePoint(codepoint).toUpperCase();
83
- if (s.length > 1) {
104
+ const expectedLen = s.codePointAt(0) > MAX_BMP ? 2 : 1;
105
+ if (s.length > expectedLen) {
84
106
  return codepoint;
85
107
  }
86
108
  const sOrigin = String.fromCodePoint(s.codePointAt(0)).toLowerCase();
87
- if (sOrigin.length > 1 || sOrigin.codePointAt(0) !== codepoint) {
109
+ const originExpectedLen = sOrigin.codePointAt(0) > MAX_BMP ? 2 : 1;
110
+ if (sOrigin.length > originExpectedLen || sOrigin.codePointAt(0) !== codepoint) {
88
111
  return codepoint;
89
112
  }
90
113
  return s.codePointAt(0);
@@ -95,11 +118,13 @@ class Codepoint {
95
118
  static toLowerCase(codepoint) {
96
119
  if (codepoint < ASCII_SIZE) return ASCII_TO_LOWER[codepoint];
97
120
  const s = String.fromCodePoint(codepoint).toLowerCase();
98
- if (s.length > 1) {
121
+ const expectedLen = s.codePointAt(0) > MAX_BMP ? 2 : 1;
122
+ if (s.length > expectedLen) {
99
123
  return codepoint;
100
124
  }
101
125
  const sOrigin = String.fromCodePoint(s.codePointAt(0)).toUpperCase();
102
- if (sOrigin.length > 1 || sOrigin.codePointAt(0) !== codepoint) {
126
+ const originExpectedLen = sOrigin.codePointAt(0) > MAX_BMP ? 2 : 1;
127
+ if (sOrigin.length > originExpectedLen || sOrigin.codePointAt(0) !== codepoint) {
103
128
  return codepoint;
104
129
  }
105
130
  return s.codePointAt(0);
@@ -201,52 +226,52 @@ class UnicodeTables {
201
226
  static _CASE_ORBIT = null;
202
227
  static get CASE_ORBIT() {
203
228
  if (!this._CASE_ORBIT) {
204
- this._CASE_ORBIT = decodeOrbit('rCrDIzDYqpII-LiC8cQlHa+0HGrpI6EzClClOBmOBkOBoOBpOBnOBrOBsOBqOlByPBzPBxPyK5crCz+HCydD1dD4dB5dB6dC8dEgeBheCieDmeDpeHj-HCweD1fDxeB+9HBwfC1FE2eBxfBjeBjdD1eDmpIHycB0fEmdBgda6cBhdD4cB1cdyhBC0hBK+hBDhiBBiiBIqiBIgkHChkHKikHDjkHBkkHImkHYjjBBnkH9gGygBB0gBB+gBBhhBBlkHBihBBqhBBijBBqypB4OhzHB70H6BgzHD-GiHo8HBp8HBq8HBr8HBs8HBt8HBu8HBv8HBg8HBh8HBi8HBj8HBk8HBl8HBm8HBn8HB48HB58HB68HB78HB88HB98HB+8HB-8HBw8HBx8HBy8HBz8HB08HB18HB28HB38HBo9HBp9HBq9HBr9HBs9HBt9HBu9HBv9HBg9HBh9HBi9HBj9HBk9HBl9HBm9HBn9HE89HJz9HClaFs+HJj+HHwcQwdQ8-HJz-HqJpdErCBlG-ohBrypBBokH6lVm4+BBl4+B6nCohhCBphhCBqhhCBrhhCBshhCBthhCBuhhCBvhhCBwhhCBxhhCByhhCBzhhCB0hhCB1hhCB2hhCB3hhCB4hhCB5hhCB6hhCB7hhCB8hhCB9hhCB+hhCB-hhCBgihCBhihCBiihCBjihCBkihCBlihCBmihCBnihCBoihCBpihCBqihCBrihCBsihCBtihCBuihCBvihCBgghCBhghCBighCBjghCBkghCBlghCBmghCBnghCBoghCBpghCBqghCBrghCBsghCBtghCBughCBvghCBwghCBxghCByghCBzghCB0ghCB1ghCB2ghCB3ghCB4ghCB5ghCB6ghCB7ghCB8ghCB9ghCB+ghCB-ghCBghhCBhhhCBihhCBjhhCBkhhCBlhhCBmhhCBnhhChD4mhCB5mhCB6mhCB7mhCB8mhCB9mhCB+mhCB-mhCBgnhCBhnhCBinhCBjnhCBknhCBlnhCBmnhCBnnhCBonhCBpnhCBqnhCBrnhCBsnhCBtnhCBunhCBvnhCBwnhCBxnhCBynhCBznhCB0nhCB1nhCB2nhCB3nhCB4nhCB5nhCB6nhCB7nhCFwlhCBxlhCBylhCBzlhCB0lhCB1lhCB2lhCB3lhCB4lhCB5lhCB6lhCB7lhCB8lhCB9lhCB+lhCB-lhCBgmhCBhmhCBimhCBjmhCBkmhCBlmhCBmmhCBnmhCBomhCBpmhCBqmhCBrmhCBsmhCBtmhCBumhCBvmhCBwmhCBxmhCBymhCBzmhC1D3shCB4shCB5shCB6shCB7shCB8shCB9shCB+shCB-shCBgthCBhthCCjthCBkthCBlthCBmthCBnthCBothCBpthCBqthCBrthCBsthCBtthCButhCBvthCBwthCBxthCCzthCB0thCB1thCB2thCB3thCB4thCB5thCC7thCB8thCCwrhCBxrhCByrhCBzrhCB0rhCB1rhCB2rhCB3rhCB4rhCB5rhCB6rhCC8rhCB9rhCB+rhCB-rhCBgshCBhshCBishCBjshCBkshCBlshCBmshCBnshCBoshCBpshCBqshCCsshCBtshCBushCBvshCBwshCBxshCByshCC0shCB1shCk2BgmjCBhmjCBimjCBjmjCBkmjCBlmjCBmmjCBnmjCBomjCBpmjCBqmjCBrmjCBsmjCBtmjCBumjCBvmjCBwmjCBxmjCBymjCBzmjCB0mjCB1mjCB2mjCB3mjCB4mjCB5mjCB6mjCB7mjCB8mjCB9mjCB+mjCB-mjCBgnjCBhnjCBinjCBjnjCBknjCBlnjCBmnjCBnnjCBonjCBpnjCBqnjCBrnjCBsnjCBtnjCBunjCBvnjCBwnjCBxnjCBynjCOgkjCBhkjCBikjCBjkjCBkkjCBlkjCBmkjCBnkjCBokjCBpkjCBqkjCBrkjCBskjCBtkjCBukjCBvkjCBwkjCBxkjCBykjCBzkjCB0kjCB1kjCB2kjCB3kjCB4kjCB5kjCB6kjCB7kjCB8kjCB9kjCB+kjCB-kjCBgljCBhljCBiljCBjljCBkljCBlljCBmljCBnljCBoljCBpljCBqljCBrljCBsljCBtljCBuljCBvljCBwljCBxljCByljC+CwrjCBxrjCByrjCBzrjCB0rjCB1rjCB2rjCB3rjCB4rjCB5rjCB6rjCB7rjCB8rjCB9rjCB+rjCB-rjCBgsjCBhsjCBisjCBjsjCBksjCBlsjCLwqjCBxqjCByqjCBzqjCB0qjCB1qjCB2qjCB3qjCB4qjCB5qjCB6qjCB7qjCB8qjCB9qjCB+qjCB-qjCBgrjCBhrjCBirjCBjrjCBkrjCBlrjC74CgmmCBhmmCBimmCBjmmCBkmmCBlmmCBmmmCBnmmCBommCBpmmCBqmmCBrmmCBsmmCBtmmCBummCBvmmCBwmmCBxmmCBymmCBzmmCB0mmCB1mmCB2mmCB3mmCB4mmCB5mmCB6mmCB7mmCB8mmCB9mmCB+mmCB-mmCBglmCBhlmCBilmCBjlmCBklmCBllmCBmlmCBnlmCBolmCBplmCBqlmCBrlmCBslmCBtlmCBulmCBvlmCBwlmCBxlmCBylmCBzlmCB0lmCB1lmCB2lmCB3lmCB4lmCB5lmCB6lmCB7lmCB8lmCB9lmCB+lmCB-lmChrVgz7CBhz7CBiz7CBjz7CBkz7CBlz7CBmz7CBnz7CBoz7CBpz7CBqz7CBrz7CBsz7CBtz7CBuz7CBvz7CBwz7CBxz7CByz7CBzz7CB0z7CB1z7CB2z7CB3z7CB4z7CB5z7CB6z7CB7z7CB8z7CB9z7CB+z7CB-z7CBgy7CBhy7CBiy7CBjy7CBky7CBly7CBmy7CBny7CBoy7CBpy7CBqy7CBry7CBsy7CBty7CBuy7CBvy7CBwy7CBxy7CByy7CBzy7CB0y7CB1y7CB2y7CB3y7CB4y7CB5y7CB6y7CB7y7CB8y7CB9y7CB+y7CB-y7Ch0eip6DBjp6DBkp6DBlp6DBmp6DBnp6DBop6DBpp6DBqp6DBrp6DBsp6DBtp6DBup6DBvp6DBwp6DBxp6DByp6DBzp6DB0p6DB1p6DB2p6DB3p6DB4p6DB5p6DB6p6DB7p6DB8p6DB9p6DB+p6DB-p6DBgq6DBhq6DBiq6DBjq6DBgo6DBho6DBio6DBjo6DBko6DBlo6DBmo6DBno6DBoo6DBpo6DBqo6DBro6DBso6DBto6DBuo6DBvo6DBwo6DBxo6DByo6DBzo6DB0o6DB1o6DB2o6DB3o6DB4o6DB5o6DB6o6DB7o6DB8o6DB9o6DB+o6DB-o6DBgp6DBhp6D');
229
+ this._CASE_ORBIT = decodeOrbit('rCrDIzDYqpII-LiC8cQlHa+0HGrpI6EzClClOBmOBkOBoOBpOBnOBrOBsOBqOlByPBzPBxPyK5crCz+HCydD1dD4dB5dB6dC8dEgeBheCieDmeDpeHj-HCweD1fDxeB+9HBwfC1FE2eBxfBjeBjdD1eDmpIHycB0fEmdBgda6cBhdD4cB1cdyhBC0hBK+hBDhiBBiiBIqiBIgkHChkHKikHDjkHBkkHImkHYjjBBnkH9gGygBB0gBB+gBBhhBBlkHBihBBqhBBijBBqypB4OhzHB70H6BgzHD-GiHo8HBp8HBq8HBr8HBs8HBt8HBu8HBv8HBg8HBh8HBi8HBj8HBk8HBl8HBm8HBn8HB48HB58HB68HB78HB88HB98HB+8HB-8HBw8HBx8HBy8HBz8HB08HB18HB28HB38HBo9HBp9HBq9HBr9HBs9HBt9HBu9HBv9HBg9HBh9HBi9HBj9HBk9HBl9HBm9HBn9HE89HJz9HClaFs+HJj+HHwcQwdQ8-HJz-HqJpdErCBlG-ohBrypBBokH6lVm4+BBl4+B');
205
230
  }
206
231
  return this._CASE_ORBIT;
207
232
  }
208
233
  static _Print = null;
209
234
  static get Print() {
210
235
  if (!this._Print) {
211
- this._Print = new UnicodeRangeTable(decodeRanges('hB9CBjBLBCpWBDFBFGBCCCBSBCsMBClBBDxBBDCBC2BBJaBFFBSVBC-FBCvBBD6BBDkDBP6BBDwBBDOBCbBDCCBJBGeBJqCBCgFBCHBDBBDVBCGBCEEBCBDIBDBBDDBJFFBCCBDBDYBDCBCFBFBBDVBCGBCBBCBBCBBDCCBDBFBBDCBEIIBCBCIIBPBLCBCIBCCBCVBCGBCBBCEBDJBCCBCCBDQQBCBDLBIGBCCBCHBDBBDVBCGBCBBCEBDIBDBBDCBICBFBBCEBDRBLBBCFBECBCDBEBBCCCBEEBEEBBBELBFEBECBCDBDHHPUBGMBCCBCWBCPBDIBCCBCDBIBBCCBDDDBCBDJBIVBCCBCWBCJBCEBDIBCCBCDBIBBHBBCDBDJBCCBNMBCCBCyBBCCBCFBFPBDZBCCBCRBEXBCIBCDDBFBEFFBEBCCCBGBHJBDCBN5BBFcBmBBBCCCBDBCXBCCCBVBDEBCCCBFBCJBDDBhBnCBCjBBFmBBCjBBCOBCMBmBlGBCGGD4LBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBDfBEZBH1CBDFBD-TBCbBE4CBIVBKXBKTBNMBCCBCBBN9CBDJBHJBHNBCKBH4CBIqBBGlCBLeBCLBFLBFEEBoBBDEBMrBBFZBHKBE9BBDgCBCcBDKBHJBHNBDeByBsCBClFBJ7BBEOBE9BBGqBBDKBJqBBG1QBDFBDlBBDFBDHBCGCBdBD0BBCOBCNBDFBCSBDCBCIBSXBJuBBSBBDaBCMBEgBBQgBBQrEBF5UBXKBWz4BBDfBC8KBGsBBCGGD3BBIBBPXBKGBCGBCGBCGBCGBCGBCGBCGBC9DBjBZBC4CBN1GBbPBC+BBC1CBDmDBGqBBC9CBC1CBKvBBCszcBE2BBK7KBV3FBJtGBDBBCCCBGBW6BBEJBH3BBJlCBJLBHzDBMdBEtCBCKBFgBBC2BBKNBDJBDmDBZbBLFBDFBDFBKGBCGBC7BBF9DBDJBHj9KBNWBFwBBloItLBDpDBnBGBNEBGZBCEBCCCBCCBCCB7DBR8NBD1BBIhBhBBoBBHyBBCSBCDBFEBCmEBF9FBEFBDFBDFBDCBEGBCGBOBBDLBCZBCSBCBBCOBDNBjB6DBGCBFsBBE3CBCMBEwBwBBsBBjEcBEwBBQbBFjBBKdBGqBBGdBCkBBFNBrB9EBDJBHjBBFjBBFnBBJzBBMLBCOBCGBCBBCKBCOBCGBCBBEzBBN2JBKVBLHBZFBCpBBCIBmCFBDCCBqBBCBBEDDBVBCnCBJIBxBSBCBBGgBBEaBGhChCB2BBFTBDxBBCBBGHBCCBCcBDCBFJBIIBI-BBhBmBBFLBK1BBEcBDaBGZBIDBNGBxCoCB4ByBBOyBBItBBJJBHlBBEcBJBBxGeBCpBBCCBDBBRCB4BrBBJpBBXZBnBbBVWBKtCBFjBBK9BBCEBOYBIJBH0BBCRBJmBBK-CBCTBMRBCuBB-BGBCCCBCBCOBCKBH6BBGJBHDBCHBDBBDVBCGBCBBCEBCJBDBBDCBDHHGGBDGBEEBMJBCDDClBBCJBCDDCDBCJBCBBJBBe7CBCEBfnCBJJBnF1BBDlBBjBkCBMJBHMBU5BBHJBHTBdaBDOBFWB6F7BBlDyCBNHBDDDBGBCBBCdBCBBDLBKJBnCHBDtBBDKBcnCBJyCBOoCBIJB3FhBBPJBHIBCsBBCNBLcBEfBDVBCNBqCGBCBBCrBBECCBCCBHBJJBHFBCBBCkBBCBBCFBIJB3JYBIQBCoBBEcB2CQQBwBBO6cBnDuDBCEBMjGBtyCiDBOvhBBRVBL68DBGmSB61G5BBn2B4RBIeBCJBFwCBCJBHdBDFBLlCBLJBCGBCUBGSBxN5BBnG6CBmDqCBF4BBIQBhCEBMBBP3-FBJ1mBBqBJBo3IDBCGBCBBCiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBDDBh7D5HBHzNBtCtBBDWBKzDB9B1HBLmBBDpCBJvDBWlCB7DTBNTBN2CBKYBoE0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDjJBD9VBQEBCOBxiBeBHFB2GGBCQBDGBCBBCEBG9BBiBxDxDBrBBENBDJBFBBhKeBS5BBGxOxOBoBB3GqBBFhPhPBFBCDBCBBCOBCkGBDPBqBrCBFJBFBByYjCBtC8BBjGDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQB1BBBvIrBBFjDBNOBDOBCOBCkBBLtFB5BcBOrBBFIBIBBPFB7E3eBFQBEMBE2DBF+CBHLBFQQBKBF3BBJJBHnBBJdBDLBFBB-BzKBNNBDMBEJBG3BBIOBDKBHIBIyEBClDBngB-2pBBhB5hEBH9GBDh0FBPwpHBQtTBjtC9QBjvBq6EBG-iEBxq3VvHB', false));
236
+ this._Print = new UnicodeRangeTable(decodeRanges('hB9CBjBLBCpWBDFBFGBCCCBSBCsMBClBBDxBBDCBC2BBJaBFFBSVBC-FBCvBBD6BBDkDBP6BBDwBBDOBCbBDCCBJBGfBIqCBCgFBCHBDBBDVBCGBCEEBCBDIBDBBDDBJFFBCCBDBDYBDCBCFBFBBDVBCGBCBBCBBCBBDCCBDBFBBDCBEIIBCBCIIBPBLCBCIBCCBCVBCGBCBBCEBDJBCCBCCBDQQBCBDLBIGBCCBCHBDBBDVBCGBCBBCEBDIBDBBDCBICBFBBCEBDRBLBBCFBECBCDBEBBCCCBEEBEEBBBELBFEBECBCDBDHHPUBGMBCCBCWBCPBDIBCCBCDBIBBCCBCBBDDBDJBIVBCCBCWBCJBCEBDIBCCBCDBIBBGCBCDBDJBCCBNMBCCBCyBBCCBCFBFPBDZBCCBCRBEXBCIBCDDBFBEFFBEBCCCBGBHJBDCBN5BBFcBmBBBCCCBDBCXBCCCBVBDEBCCCBFBCJBDDBhBnCBCjBBFmBBCjBBCOBCMBmBlGBCGGD4LBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBDfBEZBH1CBDFBD-TBCbBE4CBIVBKXBKTBNMBCCBCBBN9CBDJBHJBHNBCKBH4CBIqBBGlCBLeBCLBFLBFEEBoBBDEBMrBBFZBHKBE9BBDgCBCcBDKBHJBHNBDtBBDLBVsCBClFBJ7BBEOBE9BBGqBBDKBJqBBG1QBDFBDlBBDFBDHBCGCBdBD0BBCOBCNBDFBCSBDCBCIBSXBJuBBSBBDaBCMBEhBBPgBBQrEBF5UBXKBWz4BBD9LBGsBBCGGD3BBIBBPXBKGBCGBCGBCGBCGBCGBCGBCGBC9DBjBZBC4CBN1GBbPBC+BBC1CBDmDBGqBBC9CBC1CBKvBBCszcBE2BBK7KBV3FBJ8GBV7BBEJBH3BBJlCBJLBHzDBMdBEtCBCKBFgBBC2BBKNBDJBDmDBZbBLFBDFBDFBKGBCGBC7BBF9DBDJBHj9KBNWBFwBBloItLBDpDBnBGBNEBGZBCEBCCCBCCBCCBoUBhBpBBHyBBCSBCDBFEBCmEBF9FBEFBDFBDFBDCBEGBCGBOBBDLBCZBCSBCBBCOBDNBjB6DBGCBFsBBE3CBCMBEwBwBBsBBjEcBEwBBQbBFjBBKdBGqBBGdBCkBBFNBrB9EBDJBHjBBFjBBFnBBJzBBMLBCOBCGBCBBCKBCOBCGBCBBEzBBN2JBKVBLHBZFBCpBBCIBmCFBDCCBqBBCBBEDDBVBCnCBJIBxBSBCBBGgBBEaBGaBnB3BBFTBDxBBCBBGHBCCBCcBDCBFJBIIBI-BBhBmBBFLBK1BBEcBDaBGZBIDBNGBxCoCB4ByBBOyBBItBBJJBHlBBEcBJBBxGeBCpBBCCBDBBRFBJIBiBtBBJpBBXZBnBbBVWBKtCBFjBBK9BBCEBOYBIJBH0BBCRBJmBBK-CBCTBMRBCuBB-BGBCCCBCBCOBCKBH6BBGJBHDBCHBDBBDVBCGBCBBCEBCJBDBBDCBDHHGGBDGBEEBMJBCDDClBBCJBCDDCDBCJBCBBJBBe7CBCEBfnCBJJBnF1BBDlBBjBkCBMJBHMBU5BBHJBHTBdaBDOBFWB6F7BBlDyCBNHBDDDBGBCBBCdBCBBDLBKJBnCHBDtBBDKBcnCBJyCBOoCBIJB3CHB5ChBBPJBHIBCsBBCNBLcBEfBDVBCNBqCGBCBBCrBBECCBCCBHBJJBHFBCBBCkBBCBBCFBIJBHrBBFJB3HYBIQBCoBBEcB2CQQBwBBO6cBnDuDBCEBMjGBtyCiDBOvhBBRVBL68DBGmSB61G5BBn2B4RBIeBCJBFwCBCJBHdBDFBLlCBLJBCGBCUBGSBxN5BBnG6CBGYBDYBtBqCBF4BBIQBhCEBMGBK1mHBqBfBiDyDB+vIDBCGBCBBCiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBDDBh7D8HBEzNBHWBQQBQtBBDWBKzDB9B1HBLmBBDpCBJvDBWlCB7DTBNTBN2CBKYBoE0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDjJBD9VBQEBCOBxiBeBHFB2GGBCQBDGBCBBCEBG9BBiBxDxDBrBBENBDJBFBBhKeBS5BBGxOxOBoBB3GqBBFhGhGBdBCVBJBBhHGBCDBCBBCOBCkGBDPBqBrCBFJBFBByYjCBtC8BBjGDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQB1BBBvIrBBFjDBNOBDOBCOBCkBBLtFB5BcBOrBBFIBIBBPFB7E4eBEQBEMBE5GBHLBFQQBKBF3BBJJBHnBBJdBDLBFBBPIBoB3KBJNBDMBEKBE4BBCFFBOBDLBFJBIyEBCmDBmgB-2pBBhB9oEBDt0FBDwpHBQtTBjtC9QBjvBq6EBGppIBnkzVvHB', false));
212
237
  }
213
238
  return this._Print;
214
239
  }
215
240
  static CATEGORIES = new LazyMap({
216
- C: () => new UnicodeRangeTable(decodeRanges('AfBgDgBBOrWrWBHHBCBICCVuMuMnBBBzBBBE4B4BBGBcDBHQBXhGhGxBBB8BBBmDNB8BBByBBBQddBCCMEBgBHBsCiFiFJBBDBBXIICCBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEBCCBFFBLLBFBXEEYLLGBBKEEFGBDFBDFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBPMMBEB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBgBwBBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKMMBDBbEByBPBDBBcOOBBBiBOBiBOBtEDB7UVBMUB14BBBhB+K+KBDBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHBvGBBDCCJUB8BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBjoIBvLBBrDlBBILBGEBbGGCGD+DPB+NBB3BGBCfBrBFB0BUUFDBGoEoEBCB-FCBHBBHBBHBBECBIIIBLBDBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBC-BB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBE2BBtBHBrBVBblBBdTBYIBvCDBlBIB-BGGBLBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1FBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBL1JBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMBxhBPBXJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CkDBsCDB6BGBS-BBGKBDNB5-FHB3mBoBBLm3IBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBF-6DB7HFB1NrCBvBBBYIB1D7BB3HJBoBBBrCHBxDUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-OBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB5eDBSCBOCB4DDBgDFBNDBCOBNDB5BHBLFBpBHBfBBNDBD9BB1KLBPBBOCBLEB5BGBQBBMFBKGB0EnDnDBkgBBh3pBfB7hEFB-GBBj0FNBypHOBvThtCB-QhvBBs6EEBhjEvq3VBxHvw-FB', false)),
241
+ C: () => new UnicodeRangeTable(decodeRanges('AfBgDgBBOrWrWBHHBCBICCVuMuMnBBBzBBBE4B4BBGBcDBHQBXhGhGxBBB8BBBmDNB8BBByBBBQddBCCMEBhBGBsCiFiFJBBDBBXIICCBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEDBBFBBLGBXEEYLLGBBKEEFGBDEBEFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBPMMBEB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBvBBBNTBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKMMBDBbEByBPBDBBcOOBBBjBNBiBOBtEDB7UVBMUB14BBB-LEBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHB+GTB9BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBjoIBvLBBrDlBBILBGEBbGGCGDrUfBrBFB0BUUFDBGoEoEBCB-FCBHBBHBBHBBECBIIIBLBDBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBclBB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBHHBKgBBvBHBrBVBblBBdTBYIBvCDBlBIB-BGGBLBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1CBJ3CBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBLFBtBDBL1HBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMBxhBPBXJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CEBaBBarBBsCDB6BGBS-BBGKBIIB3mHoBBhBgDB0D8vIBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBF-6DB+HCB1NFBYOBSOBvBBBYIB1D7BB3HJBoBBBrCHBxDUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-FBgBXXBGBD-GBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB6eCBSCBOCB7GFBNDBCOBNDB5BHBLFBpBHBfBBNDBDNBKmBB5KHBPBBOCBMCB6BCCBCBRBBNDBLGB0EoDoDBjgBBh3pBfB-oEBBv0FBBypHOBvThtCB-QhvBBs6EEBrpIlkzVBxHvw-FB', false)),
217
242
  Cc: () => new UnicodeRangeTable(decodeRanges('AfgDgB', true)),
218
243
  Cf: () => new UnicodeRangeTable(decodeRanges('tFzqBzqBBEBXhGhGyBhMhMBxCxCs5D9-B9-BBDBbEByBEBCJBw03B6H6HBBBimEQQj7IPBhjiBDBwmFHBn0rYffB+CB', false)),
219
- Cn: () => new UnicodeRangeTable(decodeRanges('4bBBHDBICCVuMuMnBBBzBBBE4B4BBGBcDBHKBvI9B9BBmDmDBMB8BBByBBBQddBCCMEBgBDDBDBuHJJBDDBXXICCBBBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEBCCBFFBLLBFBXEEYLLGBBKEEFGBDFBDFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBbFB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBgBwBBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKmDmDNBBcOOBBBiBOBiBOBtEDB7UVBMUB14BBBhB+K+KBDBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHBvGBBDCCJUB8BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBDBvzIBBrDlBBILBGEBbGGCGD+DPB+NBB3BGBCfBrBFB0BUUFDBGoEoEBCC-FCBHBBHBBHBBECBIIIBIBGBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBC-BB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBE2BBtBHBrBVBblBBdTBYIBvCDBlBIBlCJBCBBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1FBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBL1JBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMB3iBJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CkDBsCDB6BGBS-BBGKBDNB5-FHB3mBoBBLm3IBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBJ76DB7HFB1NrCBvBBBYIB1D7BB3HJBoBBBjGUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-OBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB5eDBSCBOCB4DDBgDFBNDBCOBNDB5BHBLFBpBHBfBBNDBD9BB1KLBPBBOCBLEB5BGBQBBMFBKGB0EnDnDBkgBBh3pBfB7hEFB-GBBj0FNBypHOBvThtCB-QhvBBs6EEBhjEwi3VBCdBhD-DBxHvw-BB---BBB---BBB', false)),
244
+ Cn: () => new UnicodeRangeTable(decodeRanges('4bBBHDBICCVuMuMnBBBzBBBE4B4BBGBcDBHKBvI9B9BBmDmDBMB8BBByBBBQddBCCMEBjBEBuHJJBDDBXXICCBBBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEDBBFBBLGBXEEYLLGBBKEEFGBDEBEFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBbFB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBvBBBNTBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKmDmDNBBcOOBBBjBNBiBOBtEDB7UVBMUB14BBB-LEBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHB+GTB9BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBDBvzIBBrDlBBILBGEBbGGCGDrUfBrBFB0BUUFDBGoEoEBCC-FCBHBBHBBHBBECBIIIBIBGBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBclBB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBHHBKgBBvBHBrBVBblBBdTBYIBvCDBlBIBlCJBCBBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1CBJ3CBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBLFBtBDBL1HBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMB3iBJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CEBaBBarBBsCDB6BGBS-BBGKBIIB3mHoBBhBgDB0D8vIBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBJ76DB+HCB1NFBYOBSOBvBBBYIB1D7BB3HJBoBBBjGUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-FBgBXXBGBD-GBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB6eCBSCBOCB7GFBNDBCOBNDB5BHBLFBpBHBfBBNDBDNBKmBB5KHBPBBOCBMCB6BCCBCBRBBNDBLGB0EoDoDBjgBBh3pBfB-oEBBv0FBBypHOBvThtCB-QhvBBs6EEBrpIm8yVBCdBhD-DBxHvw-BB---BBB---BBB', false)),
220
245
  Co: () => new UnicodeRangeTable(decodeRanges('gg4B-nGh4hc9--BD9--B', true)),
221
246
  Cs: () => new UnicodeRangeTable(decodeRanges('gg2B--B', true)),
222
- L: () => new UnicodeRangeTable(decodeRanges('hCZBHZBwBLLFGGBVBCeBCpOBFLBPEBICCiEEBCBBDDBCHHCCBCCCBSBCyCBCqEBJlFBClBBDHHBnBBoCaBFDBuBqBBkBBBCiDBCQQBIIBLLBBBDRRCdBe4CBMZZBfBKBBFGGBUBFKKEYYBXBIKBGXBCFBSpBB7B1BBETTIJBQPBFHBDBBDVBCGBCEEBCBERROBBCCBPBBLJJBEBFBBDVBCGBCBBCBBCBBgBDBCUUBBBRIBCCBCVBCGBCBBCEBETTQBBYMMBGBDBBDVBCGBCBBCEBEffBCCBBBQSSCFBECBCDBEBBCCCBEEBEEBBBELBX1B1BBGBCCBCWBCPBEbbBBBDDDBffFHBCCBCWBCJBCEBEgBgBBCCBQQBSSBHBCCBCoBBDRRGCBJCBZFBGRBEXBCIBCDDBFB7BvBBCBBNGB7BBBCCCBDBCXBCCCBIBCBBKDDBDBCWWBCBhBgCgCBGBCjBBcEB0DqBBVRRBEBFDBEEEBIIBBBFMBNSSBkBBCGGDqBBCsKBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBmBPBR1CBDFBErTBDQBCZBGqCBHHBIRBOSBPRBPMBCCBQzBBkBFFkC4CBIEBDhBBCGGBkCBLeByBdBDEBMrBBFZB3BWBK0BBzC+C+CBtBBSHB3BdBOBBLrBBbjBBqBCBLjBBDKBGqBBDCBqBDBCFBCBBEGGB+FBhC1IBDFBDlBBDFBDHBCGCBdBD0BBCGBCEEBBBCGBEDBDFBFMBGCBCGB1DOORMBmDFFDJBCEEBDBHGCBCBCKBDDBGEBF1B1BB8zC8zCBjHBHDBEBBNlBBCGGD3BBIRRBVBKGBCGBCGBCGBCGBCGBCGBCGBxC2O2OBrBrBBDBGBBF1CBHCBC5CBCDBGqBBC9CBSfBxBPBhQ-tGBhCs0VBkCtBBDsIBEPBLBBVuBBReBDlCByBIBDmDBDiCBDBBCCCBGBWPBCCBCDBCWBezBBPxBB-BFBECCBMMBaBLWBacBIuBBdRRBDBCJBLEBCoBBYCBCHBVWBEEEBwBBCEEBDDBDBDCCZCBDKBICBNFBDFBDFBKGBCGBCqBBCNBHyDBej9KBNWBFwBBloItLBDpDBnBGBNEBGCCBIBCMBCEBCCCBCCBCCBqDBiBqLBT-BBD1BBpBLB1DEBCmEBlBZBHZBM4CBEFBDFBDFBDCBkBLBCZBCSBCBBCOBDNBjB6DBmMcBEwBBwBfBOTBCHBHlBBLdBDjBBFHBxB9EBTjBBFjBBFnBBJzBBNKBCOBCGBCBBCKBCOBCGBCBBEzBBN2JBKVBLHBZFBCpBBCIBmCFBDCCBqBBCBBEDDBVBLWBKeBiCSBCBBLVBLZBnC3BBHBBhCQQBCBCCBCcBrBcBEcBkBHBCbBc1BBLVBLSBORBvDoCB4ByBBOyBBOjBBnBbBKWB7HpBBHBBRCB8BcBLJJBUBrBRBvBUBcWBN0BB6BBBDOOBrBBhBYBbjBBeDDJiBBENNBuBBPDBWCCkBRBCYBUBBgCGBCCCBCBCOBCJBIuBBnBHBDBBDVBCGBCBBCEBETTNEBfJBCDDClBBCaaCtBtBBzBBTDBVCBfvBBVBBC5F5FBtBBqBDBlBvBBV8B8BBpBBOoCoCBZBmBGB6FrBB1D-BBgBHBDDDBGBCBBCXBQCC-CHBDmBBRCCdLLBmBBIWWMtBBUTTBnCBoGgBBgBIBCkBBSyByBBcBxDGBCBBClBBWaaBEBCBBCfBPoKoKBRBQCCBLBChBB9DwCwCB4cBnHjGBtyCgDBQvhBBSFBa68DBGmSB61GdBj3B4RBIeBSuCBSdBTvBBRDBgBUBGSBxNsBB0G-BBhEqCBGjCjCBLBhCBBCddB2-FBJ1mBBqBJBo3IDBCGBCBBCiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBn7F0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDYBCYBCeBCYBCeBCYBCeBCYBCeBCYBCHB15BeBHFBmI9BBzEsBBLGBRiKiKBcBTrBBlPbBlHdBDwPwPBFBCDBCBBCOBCkGB8BjCBI1lB1lBBCBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQBlqE-2pBBhB5hEBH9GBDh0FBPwpHBQtTBjtC9QBjvBq6EBG-iEB', false)),
223
- LC: () => new UnicodeRangeTable(decodeRanges('hCZBHZB7BLLBVBCeBCiGBCDBFvGBCaBhGDBDBBECBCHHCCBCCCBSBCyCBCqEBJlFBClBBKoBB44ClBBCGGDqBBDCBhV1CBDFBjkCKBGqBBDCBhCrBBgCMBChBBmD1IBDFBDlBBDFBDHBCGCBdBD0BBCGBCEEBBBCGBEDBDFBFMBGCBCGBmIFFDJBCEEBDBHGCBCBCFBFDDBCBGEBF1B1BB8zC8zCB6DBDmDBHDBEBBNlBBCGGzoetBBTbBnEtCBCWBEDBC9BBDBBCCCBGBZBBE2Z2ZBpBBGIBIvCBh6TGBNEBqgBZBHZBmlBvCBhDjBBFjBB1DKBCOBCGBCBBCKBCOBCGBCBBk2ByBBOyBB+CVBLVB74C-BBhrV-BBhsZ0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDYBCYBCeBCYBCeBCYBCeBCYBCeBCYBCHB15BJBCTBHFB2uCjCB', false)),
224
- Ll: () => new UnicodeRangeTable(decodeRanges('hDZB7BqBqBBWBCHBC2BCBQCBuBCDECBBBDCCDEEBFFDEEBBBDDDCCCDCCBCCDEECDDBDDBBBHGDCOCBSCBDDCEEC4BCBFBDDDBCCFICBjCBCaBiGCCEEEBBBTccBhBBCBBECBCWCBDBCGDB0B0BBuBBCgBCK0BCDMCBgDCxBoBBo6CqBBDCB5XFBjkCIBC2D2DBqBBgCMBChBBnD0ECBHBCgDCBHBJFBLHBJHBJFBLHBJHBJNBDHBJHBJHBJEBCBBHEEBBBCBBJDBDBBJHBLCBCBBzIEEBEEcKFDBBJDBF2B2Bs1CvBBCEEBGCFCCBCCBEBGiDCBIICFFNlBBCGG0oesBCUaCoEMCBBBC+BCBGBCCCDICFCCDCCBBBCSCGGGCMCFCCDEECICbEE2ZqBBGIBIvCBh6TGBNEBqhBZBumBnBBpEjBB8EKBCOBCGBCBBk4ByBB+DVB75CfBhsVfB7sZZBbGBCRBbZBbDBCCCBFBCKBbZBbZBbZBbZBbZBbZBbZBbZBbbBdYBCFBbYBCFBbYBCFBbYBCFBbYBCFBC15B15BBIBCTBHFB4vChBB', false)),
225
- Lm: () => new UnicodeRangeTable(decodeRanges('wVRBFLBPEBICCmEGG-OnHnHlFBBuIBBFgBgBKEEhFoFoF1mBgEgE2R72B72BsDkTkTxOFBvF+BBOjBjBBjBByVOORMBg-CBByHgGgG2OsBsBBDBGiDiDB+C+CBBB34bjnBjnBBEBvIzDzDdBB6DIBxCYYqDCBEBB2OXXqEtDtDWBBoDDBKngVngVuBBBh-BFBCpBBCIB0sBhBhBxuXDB9PCBpBBBnRMBhCBBCtgQtgQBCBCGBCBByhM9BBqGGBudgjBgjB', false)),
226
- Lo: () => new UnicodeRangeTable(decodeRanges('qFQQhIFFBCBxG8Z8ZBZBFDBuBfBCJBkBBBCiDBCZZBLLBBBDRRCdBe4CBMZZBfBWVBrBYBIKBGXBCFBSoBB8B1BBETTIJBROBFHBDBBDVBCGBCEEBCBERROBBCCBPBBLJJBEBFBBDVBCGBCBBCBBCBBgBDBCUUBBBRIBCCBCVBCGBCBBCEBETTQBBYMMBGBDBBDVBCGBCBBCEBEffBCCBBBQSSCFBECBCDBEBBCCCBEEBEEBBBELBX1B1BBGBCCBCWBCPBEbbBBBDDDBffFHBCCBCWBCJBCEBEgBgBBCCBQQBSSBHBCCBCoBBDRRGCBJCBZFBGRBEXBCIBCDDBFB7BvBBCBBNFB8BBBCCCBDBCXBCCCBIBCBBKDDBDBYDBhBgCgCBGBCjBBcEB0DqBBVRRBEBFDBEEEBIIBBBFMBNyDyDBnKBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBmBPByDrTBDQBCZBGqCBHHBIRBOSBPRBPMBCCBQzBBpBkCkCBhBBC0BBIEBDhBBCGGBkCBLeByBdBDEBMrBBFZB3BWBK0BBxFuBBSHB3BdBOBBLrBBbjBBqBCBLdByDDBCFBCBBE7hB7hBBCB4-C3BBZWBKGBCGBCGBCGBCGBCGBCGBCGBoR2B2BF1CBJCCB4CBFGGBpBBC9CBSfBxBPBhQ-tGBhC0wUBC2jBBkCnBBJrIBFPBLBBjCyByBBkCBqFoDoDEGBCCBCDBCWBezBBPxBB-BFBECCBMMBaBLWBacBIuBBuBEBDIBLEBCoBBYCBCHBVPBCFBEEEBwBBCEEBDDBDBDCCZBBEKBIPPBEBDFBDFBKGBCGByEiBBej9KBNWBFwBBloItLBDpDBkCCCBIBCMBCEBCCCBCCBCCBqDBiBqLBT-BBD1BBpBLB1DEBCmEBqDJBCsBBDeBEFBDFBDFBDCBkBLBCZBCSBCBBCOBDNBjB6DBmMcBEwBBwBfBOTBCHBHlBBLdBDjBBFHBhEtCBjDnBBJzBB9CzBBN2JBKVBLHB5EFBDCCBqBBCBBEDDBVBLWBKeBiCSBCBBLVBLZBnC3BBHBBhCQQBCBCCBCcBrBcBEcBkBHBCbBc1BBLVBLSBORBvDoCB4FjBBnBDBCxJxJBoBBHBBRCB8BcBLJJBUBrBRBvBUBcWBN0BB6BBBDOOBrBBhBYBbjBBeDDJiBBENNBuBBPDBWCCkBRBCYBUBBgCGBCCCBCBCOBCJBIuBBnBHBDBBDVBCGBCBBCEBETTNEBfJBCDDClBBCaaCtBtBBzBBTDBVCBfvBBVBBC5F5FBtBBqBDBlBvBBV8B8BBpBBOoCoCBZBmBGB6FrBB0GHBDDDBGBCBBCXBQCC-CHBDmBBRCCdLLBmBBIWWMtBBUTTBnCBoGgBBgBIBCkBBSyByBBcBxDGBCBBClBBWaaBEBCBBCfBPoKoKBRBQCCBLBChBB9DwCwCB4cBnHjGBtyCgDBQvhBBSFBa68DBGmSB61GdBj3B4RBIeBSuCBSdBTvBB0BUBGSB0NnBB2MqCBGwFwFB2-FBJ1mBBqBJB43IiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBxzI2P2PBrBBiBiKiKBcBTrBBlPaBmHdBDwPwPBFBCDBCBBCOBCkGB8pBDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQBlqE-2pBBhB5hEBH9GBDh0FBPwpHBQtTBjtC9QBjvBq6EBG-iEB', false)),
247
+ L: () => new UnicodeRangeTable(decodeRanges('hCZBHZBwBLLFGGBVBCeBCpOBFLBPEBICCiEEBCBBDDBCHHCCBCCCBSBCyCBCqEBJlFBClBBDHHBnBBoCaBFDBuBqBBkBBBCiDBCQQBIIBLLBBBDRRCdBe4CBMZZBfBKBBFGGBUBFKKEYYBXBIKBGXBCGBRpBB7B1BBETTIJBQPBFHBDBBDVBCGBCEEBCBERROBBCCBPBBLJJBEBFBBDVBCGBCBBCBBCBBgBDBCUUBBBRIBCCBCVBCGBCBBCEBETTQBBYMMBGBDBBDVBCGBCBBCEBEffBCCBBBQSSCFBECBCDBEBBCCCBEEBEEBBBELBX1B1BBGBCCBCWBCPBEbbBBBCBBDBBfFFBGBCCBCWBCJBCEBEffBBBCBBQBBSIBCCBCoBBDRRGCBJCBZFBGRBEXBCIBCDDBFB7BvBBCBBNGB7BBBCCCBDBCXBCCCBIBCBBKDDBDBCWWBCBhBgCgCBGBCjBBcEB0DqBBVRRBEBFDBEEEBIIBBBFMBNSSBkBBCGGDqBBCsKBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBmBPBR1CBDFBErTBDQBCZBGqCBHHBIRBOSBPRBPMBCCBQzBBkBFFkC4CBIEBDhBBCGGBkCBLeByBdBDEBMrBBFZB3BWBK0BBzC+C+CBtBBSHB3BdBOBBLrBBbjBBqBCBLjBBDKBGqBBDCBqBDBCFBCBBEGGB+FBhC1IBDFBDlBBDFBDHBCGCBdBD0BBCGBCEEBBBCGBEDBDFBFMBGCBCGB1DOORMBmDFFDJBCEEBDBHGCBCBCKBDDBGEBF1B1BB8zC8zCBjHBHDBEBBNlBBCGGD3BBIRRBVBKGBCGBCGBCGBCGBCGBCGBCGBxC2O2OBrBrBBDBGBBF1CBHCBC5CBCDBGqBBC9CBSfBxBPBhQ-tGBhCs0VBkCtBBDsIBEPBLBBVuBBReBDlCByBIBDmDBDxCBVQBCCBCDBCWBezBBPxBB-BFBECCBMMBaBLWBacBIuBBdRRBDBCJBLEBCoBBYCBCHBVWBEEEBwBBCEEBDDBDBDCCZCBDKBICBNFBDFBDFBKGBCGBCqBBCNBHyDBej9KBNWBFwBBloItLBDpDBnBGBNEBGCCBIBCMBCEBCCCBCCBCCBqDBiBqLBT-BBD1BBpBLB1DEBCmEBlBZBHZBM4CBEFBDFBDFBDCBkBLBCZBCSBCBBCOBDNBjB6DBmMcBEwBBwBfBOTBCHBHlBBLdBDjBBFHBxB9EBTjBBFjBBFnBBJzBBNKBCOBCGBCBBCKBCOBCGBCBBEzBBN2JBKVBLHBZFBCpBBCIBmCFBDCCBqBBCBBEDDBVBLWBKeBiCSBCBBLVBLZBHZBnB3BBHBBhCQQBCBCCBCcBrBcBEcBkBHBCbBc1BBLVBLSBORBvDoCB4ByBBOyBBOjBBnBbBKWB7HpBBHBBRFB5BcBLJJBUBrBRBvBUBcWBN0BB6BBBDOOBrBBhBYBbjBBeDDJiBBENNBuBBPDBWCCkBRBCYBUBBgCGBCCCBCBCOBCJBIuBBnBHBDBBDVBCGBCBBCEBETTNEBfJBCDDClBBCaaCtBtBBzBBTDBVCBfvBBVBBC5F5FBtBBqBDBlBvBBV8B8BBpBBOoCoCBZBmBGB6FrBB1D-BBgBHBDDDBGBCBBCXBQCC-CHBDmBBRCCdLLBmBBIWWMtBBUTTBnCBoGgBBgBIBCkBBSyByBBcBxDGBCBBClBBWaaBEBCBBCfBPYYBqBBlISBQCCBLBChBB9DwCwCB4cBnHjGBtyCgDBQvhBBSFBa68DBGmSB61GdBj3B4RBIeBSuCBSdBTvBBRDBgBUBGSBxNsBB0G-BBhBYBDYBtBqCBGjCjCBLBhCBBCPPBNNB0mHBqBfBiDyDB+vIDBCGBCBBCiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBn7F0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDYBCYBCeBCYBCeBCYBCeBCYBCeBCYBCHB15BeBHFBmI9BBzEsBBLGBRiKiKBcBTrBBlPbBlHdBDwGwGBdBCCBCBBCGBDEBKBBhHGBCDBCBBCOBCkGB8BjCBI1lB1lBBCBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQBlqE-2pBBhB9oEBDt0FBDwpHBQtTBjtC9QBjvBq6EBGppIB', false)),
248
+ LC: () => new UnicodeRangeTable(decodeRanges('hCZBHZB7BLLBVBCeBCiGBCDBFvGBDZBhGDBDBBECBCHHCCBCCCBSBCyCBCqEBJlFBClBBKoBB44ClBBCGGDqBBDCBhV1CBDFBjkCKBGqBBDCBhCrBBgCMBChBBmD1IBDFBDlBBDFBDHBCGCBdBD0BBCGBCEEBBBCGBEDBDFBFMBGCBCGBmIFFDJBCEEBDBHGCBCBCFBFDDBCBGEBF1B1BB8zC8zCB6DBDmDBHDBEBBNlBBCGGzoetBBTbBnEtCBCWBEDBCsCBZBBE2Z2ZBpBBGIBIvCBh6TGBNEBqgBZBHZBmlBvCBhDjBBFjBB1DKBCOBCGBCBBCKBCOBCGBCBBk2ByBBOyBB+CVBLVB74C-BBhrV-BBhBYBDYBtpZ0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDYBCYBCeBCYBCeBCYBCeBCYBCeBCYBCHB15BJBCTBHFB2uCjCB', false)),
249
+ Ll: () => new UnicodeRangeTable(decodeRanges('hDZB7BqBqBBWBCHBC2BCBQCBuBCDECBBBDCCDEEBFFDEEBBBDDDCCCDCCBCCDEECDDBDDBBBHGDCOCBSCBDDCEEC4BCBFBDDDBCCFICBjCBDZBiGCCEEEBBBTccBhBBCBBECBCWCBDBCGDB0B0BBuBBCgBCK0BCDMCBgDCxBoBBo6CqBBDCB5XFBjkCIBC2D2DBqBBgCMBChBBnD0ECBHBCgDCBHBJFBLHBJHBJFBLHBJHBJNBDHBJHBJHBJEBCBBHEEBBBCBBJDBDBBJHBLCBCBBzIEEBEEcKFDBBJDBF2B2Bs1CvBBCEEBGCFCCBCCBEBGiDCBIICFFNlBBCGG0oesBCUaCoEMCBBBC+BCBGBCCCDICFCCDCCBBBCSCGGGCMCFCCDOCbEE2ZqBBGIBIvCBh6TGBNEBqhBZBumBnBBpEjBB8EKBCOBCGBCBBk4ByBB+DVB75CfBhsVfB8BYBnqZZBbGBCRBbZBbDBCCCBFBCKBbZBbZBbZBbZBbZBbZBbZBbZBbbBdYBCFBbYBCFBbYBCFBbYBCFBbYBCFBC15B15BBIBCTBHFB4vChBB', false)),
250
+ Lm: () => new UnicodeRangeTable(decodeRanges('wVRBFLBPEBICCmEGG-OnHnHlFBBuIBBFgBgBKEEhFoFoF1mBgEgE2R72B72BsDkTkTxOFBvF+BBOjBjBBjBByVOORMBg-CBByHgGgG2OsBsBBDBGiDiDB+C+CBBB34bjnBjnBBEBvIzDzDdBB6DIBxCYYpDDBEBB2OXXqEtDtDWBBoDDBKngVngVuBBBh-BFBCpBBCIB0sBhBhB2K04D04DnrTDB9PCBpBBBnRMBhCBBCPPB9-P9-PBCBCGBCBByhM9BBqGGBud0Q0QsSAB', false)),
251
+ Lo: () => new UnicodeRangeTable(decodeRanges('qFQQhIFFBCBxGBB7ZaBFDBuBfBCJBkBBBCiDBCZZBLLBBBDRRCdBe4CBMZZBfBWVBrBYBIKBGXBCGBRoBB8B1BBETTIJBROBFHBDBBDVBCGBCEEBCBERROBBCCBPBBLJJBEBFBBDVBCGBCBBCBBCBBgBDBCUUBBBRIBCCBCVBCGBCBBCEBETTQBBYMMBGBDBBDVBCGBCBBCEBEffBCCBBBQSSCFBECBCDBEBBCCCBEEBEEBBBELBX1B1BBGBCCBCWBCPBEbbBBBCBBDBBfFFBGBCCBCWBCJBCEBEffBBBCBBQBBSIBCCBCoBBDRRGCBJCBZFBGRBEXBCIBCDDBFB7BvBBCBBNFB8BBBCCCBDBCXBCCCBIBCBBKDDBDBYDBhBgCgCBGBCjBBcEB0DqBBVRRBEBFDBEEEBIIBBBFMBNyDyDBnKBCDBDGBCCCBCBDoBBCDBDgBBCDBDGBCCCBCBDOBC4BBCDBDiCBmBPByDrTBDQBCZBGqCBHHBIRBOSBPRBPMBCCBQzBBpBkCkCBhBBC0BBIEBDhBBCGGBkCBLeByBdBDEBMrBBFZB3BWBK0BBxFuBBSHB3BdBOBBLrBBbjBBqBCBLdByDDBCFBCBBE7hB7hBBCB4-C3BBZWBKGBCGBCGBCGBCGBCGBCGBCGBoR2B2BF1CBJCCB4CBFGGBpBBC9CBSfBxBPBhQ-tGBhC0wUBC2jBBkCnBBJrIBFPBLBBjCyByBBkCBqFoDoDEGBCCBCDBCWBezBBPxBB-BFBECCBMMBaBLWBacBIuBBuBEBDIBLEBCoBBYCBCHBVPBCFBEEEBwBBCEEBDDBDBDCCZBBEKBIPPBEBDFBDFBKGBCGByEiBBej9KBNWBFwBBloItLBDpDBkCCCBIBCMBCEBCCCBCCBCCBqDBiBqLBT-BBD1BBpBLB1DEBCmEBqDJBCsBBDeBEFBDFBDFBDCBkBLBCZBCSBCBBCOBDNBjB6DBmMcBEwBBwBfBOTBCHBHlBBLdBDjBBFHBhEtCBjDnBBJzBB9CzBBN2JBKVBLHB5EFBDCCBqBBCBBEDDBVBLWBKeBiCSBCBBLVBLZBHZBnB3BBHBBhCQQBCBCCBCcBrBcBEcBkBHBCbBc1BBLVBLSBORBvDoCB4FjBBnBDBCxJxJBoBBHBBRCBCBB5BcBLJJBUBrBRBvBUBcWBN0BB6BBBDOOBrBBhBYBbjBBeDDJiBBENNBuBBPDBWCCkBRBCYBUBBgCGBCCCBCBCOBCJBIuBBnBHBDBBDVBCGBCBBCEBETTNEBfJBCDDClBBCaaCtBtBBzBBTDBVCBfvBBVBBC5F5FBtBBqBDBlBvBBV8B8BBpBBOoCoCBZBmBGB6FrBB0GHBDDDBGBCBBCXBQCC-CHBDmBBRCCdLLBmBBIWWMtBBUTTBnCBoGgBBgBIBCkBBSyByBBcBxDGBCBBClBBWaaBEBCBBCfBPYYBnBBCBBlISBQCCBLBChBB9DwCwCB4cBnHjGBtyCgDBQvhBBSFBa68DBGmSB61GdBj3B4RBIeBSuCBSdBTvBB0BUBGSB0NnBB2MqCBGwFwFB0mHBqBfBiDyDBuwIiJBQeeBBBDPPBCBJrMBloCqDBGMBEIBIJBxzI2P2PBrBBiBiKiKBcBTrBBlPaBmHdBDwGwGBdBCCBCBBCGBDEBKiHiHBFBCDBCBBCOBCkGB8pBDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQBlqE-2pBBhB9oEBDt0FBDwpHBQtTBjtC9QBjvBq6EBGppIB', false)),
227
252
  Lt: () => new UnicodeRangeTable(decodeRanges('lOGDnB2sH2sHBGBJHBJHBNQQwBAB', false)),
228
- Lu: () => new UnicodeRangeTable(decodeRanges('hCZBmDWBCGBiB2BCDOCDuBCBECEBBCCCBCCBBBDDBCBBCCBEBBCBBCECBCCDCCBCCBBBCCCBEEIJDCMCDQCDDDCCBC4BCIBBCBBDCCBCBCGCiJCCEJJHCCBBBCCCBCCBPBCIBkBDDBBBEWCGDDCBBDyBBxBgBCK2BCBMCD+CCDlBBq6ClBBCGGzW1CB0kCHHBpBBDCBhK0ECKgDCKHBJFBLHBJHBJFBMGCJHBpCDBNDBNDBNEBMDBnIFFECBDCBDEEBDBHGCBCBDDBLBBG+B+B9zCvBBxBCCBBBDGCBCBCDDJCBCgDCJCCFuqeuqeCqBCUaCoEMCE8BCLECBICFCCDCCEUCBDBCEBCOCBCBCCCBEEGGCZs5Vs5VBYBmmBnBBpEjBB9EKBCOBCGBCBBr3ByBB+EVB75CfBhsVfBhtZZBbZBbZBbCCBGDBDDBCBCHBbZBbBBCDBDHBCGBcBBCDBCEBCEEBFBcZBbZBbZBbZBbZBbZBfYBiBYBiBYBiBYBiBYBiB2pE2pEBgBB', false)),
229
- M: () => new UnicodeRangeTable(decodeRanges('gYvDB0IGBoIsBBCCCBCCBCCpCKBxBUBRmDmDBFBDFBDBBCDBkBffBZB8CKB7BIBKZZBCBCIBCCBCEBsBCB8BIBrBXBCgBB3BCBCRBCGBLBBeCB5BCCBFBDBBDCBKLLBbbDCB5BCCBDBFBBDCBEffBEEMCB5BCCBGBCCBCCBVBBXFBCCB5BCCBFBDBBDCBICBLBBf8B8BBDBECBCDBKpBpBBDB4BCCBFBCCBCDBIBBMBBeCB5BCCBFBCCBCDBIBBMBBQNNBCB4BBBCGBCCBCDBKLLBeeBBBnCFFBEBCCCBGBTBB+BDDBFBNHBjDDDBHBMGBqCBBcECFBByBTBCBBGKBCjBBKlDlDBSBYDBFCBCCBDGBEDBOLBCLLBCBgWCBzdDBdCBeBBfBBhCfBKuBuBBBBC2D2DBjBjB3DLBFLB8GEB6BJBCcBDxBxBBdByBEBwBQBnBIBNCBfMB5BNBxBTB5ECBCUBFHHDCBnG-BBxWgBB--CCBuEhDhDBeBrRFBqDBB1udDBCJBhBBBxCBBxIEEFYYBDBF0C0CBzBzBBQBbRBOnBnBBGBaMBtBDBwBNBlBkCkCBMBNJJBuBuBBBBzBCCBBBDBBGBBCqBqBBDBGBBtHHBCBBx5TiXiXBOBRPBuejHjH2EEBn0BCBCBBGDBpBCBFmFmFB+R+RBCBiCEB+JBBwCDBnCKByBDB7DCB2BOBqBDDBLLBCBuBKBI+B+BBBBlBNBRBBtBNNBBBxBNBJDBCBB9CLBHDD+ELBWDB4BBBCGBDBBDCBKLLBDDBFBEEBkCIBCDDCDBCEBCPPBzCzCBQBYyCyCBSBsHGBDIBcBBzCQBrDMBmDOBhIOB2HFBCBBDDBCCCBuEuEBFBDGBEddBIBpBGBCDBJKKBJBvBPB2MHBCHBzCVBCNB7DFBECCBCCBFBCjCjCBDBCBBCEB8KDBKBBCxBxBBFBEEBYmnFmnFHOBpmLRBhuCEB8BGB5gBCCB1BBIDByCMMBslTslTBizEizEBsBBDWB-QEBEFBJHBDGBfDB1ECB89B2BBFxBBJPPXEBCOBxqBGBCQBDGBCBBCEBlDhFhFBFB4L+B+BBCB9PDB-HBBhXGBuDGB29lYvHB', false)),
230
- Mc: () => new UnicodeRangeTable(decodeRanges('joC4B4BDCBJDBCBBzBBB7BCBHBBDBBLsBsB7BCBjC7B7BBBBJCCB2B2BB7B7BCHHBDDBLLnDBBCBBECBCCBLqBqBBBB+BDB+BBB7BCCBDBDBBCBBKBBdPPB7B7BBBBGCBCCBLrBrBBsCsCBBBHHBTBBrKBBgCsFsFBFFHDDBaaBLLBBBDGBWBBDFBDLLBBB5zBffiEIIBGBCBB7KDBDCBFBBCFBhHBB7BCCKCCBJJBEByExBxBGCCBDBCBB+BffFBBD9B9BDCBCEEBxBxBBGBJBBsFWW35EBB0-dBBD5C5CBzBzBBOBvEBBwBxBxBBFFBDDBBBvDBBDBBZuBuBCuDuDDBBGuHuHBCCBCCBCC0gZCCgEuBuBBBBFBB0DZZB8B8BxBCBKBBO+C+CBBBEBBCrFrFBBBgBBB7BBBCDBDBBDCBKLLB1C1CBBBIDDCDBCBBCmDmDBBBJBBErDrDBBBHCCBCBDuHuHBBBHDBDyDyDBBBJBBCuDuDCBBHoDoDCBBFmImIBBBK4H4HBEBCBBFDDCvEvEBBBJDBF1C1CeBB-B4M4MPrDrDIDD2GEBFBBC-K-KBNNxBBBJBBCpvQpvQBBBlxD2BBpDBB0rYBBHFB', false)),
253
+ Lu: () => new UnicodeRangeTable(decodeRanges('hCZBmDWBCGBiB2BCDOCDuBCBECEBBCCCBCCBBBDDBCBBCCBEBBCBBCECBCCDCCBCCBBBCCCBEEIJDCMCDQCDDDCCBC4BCIBBCBBDCCBCBCGCiJCCEJJHCCBBBCCCBCCBPBCIBkBDDBBBEWCGDDCBBDyBBxBgBCK2BCBMCD+CCDlBBq6ClBBCGGzW1CB0kCHHBpBBDCBhK0ECKgDCKHBJFBLHBJHBJFBMGCJHBpCDBNDBNDBNEBMDBnIFFECBDCBDEEBDBHGCBCBDDBLBBG+B+B9zCvBBxBCCBBBDGCBCBCDDJCBCgDCJCCFuqeuqeCqBCUaCoEMCE8BCLECBICFCCDCCEUCBDBCEBCOCBCBCCCBQCZs5Vs5VBYBmmBnBBpEjBB9EKBCOBCGBCBBr3ByBB+EVB75CfBhsVfBhCYBoqZZBbZBbZBbCCBGDBDDBCBCHBbZBbBBCDBDHBCGBcBBCDBCEBCEEBFBcZBbZBbZBbZBbZBbZBfYBiBYBiBYBiBYBiBYBiB2pE2pEBgBB', false)),
254
+ M: () => new UnicodeRangeTable(decodeRanges('gYvDB0IGBoIsBBCCCBCCBCCpCKBxBUBRmDmDBFBDFBDBBCDBkBffBZB8CKB7BIBKZZBCBCIBCCBCEBsBCB8BIBrBXBCgBB3BCBCRBCGBLBBeCB5BCCBFBDBBDCBKLLBbbDCB5BCCBDBFBBDCBEffBEEMCB5BCCBGBCCBCCBVBBXFBCCB5BCCBFBDBBDCBICBLBBf8B8BBDBECBCDBKpBpBBDB4BCCBFBCCBCDBIBBMBBeCB5BCCBFBCCBCDBIBBMBBQNNBCB4BBBCGBCCBCDBKLLBeeBBBnCFFBEBCCCBGBTBB+BDDBFBNHBjDDDBHBMGBqCBBcECFBByBTBCBBGKBCjBBKlDlDBSBYDBFCBCCBDGBEDBOLBCLLBCBgWCBzdDBdCBeBBfBBhCfBKuBuBBBBC2D2DBjBjB3DLBFLB8GEB6BJBCcBDxBxBBsBBDLBVEBwBQBnBIBNCBfMB5BNBxBTB5ECBCUBFHHDCBnG-BBxWgBB--CCBuEhDhDBeBrRFBqDBB1udDBCJBhBBBxCBBxIEEFYYBDBF0C0CBzBzBBQBbRBOnBnBBGBaMBtBDBwBNBlBkCkCBMBNJJBuBuBBBBzBCCBBBDBBGBBCqBqBBDBGBBtHHBCBBx5TiXiXBOBRPBuejHjH2EEBn0BCBCBBGDBpBCBFmFmFB+R+RBCBiCEB+JBBuCFBnCKByBDB7DCB2BOBqBDDBLLBCBuBKBI+B+BBBBlBNBRBBtBNNBBBxBNBJDBCBB9CLBHDD+ELBWDB4BBBCGBDBBDCBKLLBDDBFBEEBkCIBCDDCDBCEBCPPBzCzCBQBYyCyCBSBsHGBDIBcBBzCQBrDMBmDOBhIOB2HFBCBBDDBCCCBuEuEBFBDGBEddBIBpBGBCDBJKKBJBvBPBnGHBoGHBCHBzCVBCNB7DFBECCBCCBFBCjCjCBDBCBBCEB8KDBKBBCxBxBBFBEEBYmnFmnFHOBpmLRBhuCEB8BGB5gBCCB1BBIDByCMMBslTslTBizEizEBsBBDWB-QEBEFBJHBDGBfDB1ECB89B2BBFxBBJPPXEBCOBxqBGBCQBDGBCBBCEBlDhFhFBFB4L+B+BBCB9PDB-HBB0HDDIBBG7O7OBFBuDGB29lYvHB', false)),
255
+ Mc: () => new UnicodeRangeTable(decodeRanges('joC4B4BDCBJDBCBBzBBB7BCBHBBDBBLsBsB7BCBjC7B7BBBBJCCB2B2BB7B7BCHHBDDBLLnDBBCBBECBCCBLqBqBBBB+BDB+BBB7BCCBDBDBBCBBKBBdPPB7B7BBBBGCBCCBLrBrBBsCsCBBBHHBTBBrKBBgCsFsFBFFHDDBaaBLLBBBDGBWBBDFBDLLBBB5zBffiEIIBGBCBB7KDBDCBFBBCFBhHBB7BCCKCCBJJBEByExBxBGCCBDBCBB+BffFBBD9B9BDCBCEEBxBxBBGBJBBsFWW35EBB0-dBBD5C5CBzBzBBOBvEBBwBxBxBBFFBDDBBBvDBBDBBZuBuBCuDuDDBBGuHuHBCCBCCBCC0gZCCgEuBuBBBBFBB0DZZB8B8BxBCBKBBO+C+CBBBEBBCrFrFBBBgBBB7BBBCDBDBBDCBKLLB1C1CBBBIDDCDBCBBCmDmDBBBJBBErDrDBBBHCCBCBDuHuHBBBHDBDyDyDBBBJBBCuDuDCBBHoDoDCBBFmImIBBBK4H4HBEBCBBFDDCvEvEBBBJDBF1C1CeBB-BqGqGECCoGPPrDIID2G2GBDBFBBC-K-KBNNxBBBJBBCpvQpvQBBBlxD2BBpDBB0rYBBHFB', false)),
231
256
  Me: () => new UnicodeRangeTable(decodeRanges('okBBB1xF-wB-wBBCBCCBsshBCB', false)),
232
- Mn: () => new UnicodeRangeTable(decodeRanges('gYvDB0IEBqIsBBCCCBCCBCCpCKBxBUBRmDmDBFBDFBDBBCDBkBffBZB8CKB7BIBKZZBCBCIBCCBCEBsBCB8BIBrBXBCfB4BCCFHBFEEBFBLBBe7B7BFDBJVVBbbDBB6BFFBFFBDDBBBEffBEEMBB6BFFBDBCBBFVVBXXBEBC7B7BDCCBCBJIIBMMBff+BNNzBEE4BCCBBBGCBCDBIBBMBBe7B7BDHHGBBVBBdBB6BBBFDBJVVBeepCIIBBBC7C7CDGBNHBjDDDBHBMGBqCBBcEC4BNBCEBCBBGKBCjBBKnDnDBCBCFBCBBDBBaBBFCBRDBODDBHHQgWgWBBBzdCBeBBfBBfBBhCBBCGBJDDBJBKuBuBBBBC2D2DBjBjB3DCBFBBKHHBBB8GBBD7B7BCGBCCCDHBHJBDxBxBBMBCPByBDBxBCCBDBCGGpBIBNBBhBDBDBBCCB5BCCBEECCB7BHBDBB5ECBCMBCGBFHHEBBnG-BBxWMBFEEBKB--CCBuEhDhDBeBrRDBsDBB1udFFBIBhBBBxCBBxIEEFaaBGG4EBBbRBOnBnBBGBaKBvBCBxBDDBCBDBBoBkCkCBEBDBBDBBNJJwB0B0BCCBDBBGBBCrBrBBJJvHDDFx5Tx5TiXPBRPBuejHjH2EEBn0BCBCBBGDBpBCBFmFmFB+R+RBCBiCEB+JBBwCDBnCKByBDB8D3B3BBNBqBDDBLLBBByBDBDBBI+B+BBBBlBEBCHB-BNNB1B1BBHBLDBDgDgDBBBDCCBHHD+E+EEHBWBB6BBBEmBmBBFBEEBnCFBOECPBB2CHBDCBCYY1CFBCFFBCCBvHvHBCBHBBCBBcBB2CHBDCCBrDrDCDDBEBCmDmDCDDBCBCEBkIIBCBBhIBBCFFxEDBDBBFhBhBBIBpBFBDDBJKKBEBDCBvBMBCBB3MGBCFBCzCzCBUBDGBCBBCBB7DFBECCBCCBFBCpCpCBEEC8K8KBMMB1B1BBDBGCCYmnFmnFHOBpmLLBECBhuCEB8BGB5gBgCgCBCByC5lT5lTBizEizEBsBBDWBhRCBSHBDGBfDB1ECB89B2BBFxBBJPPXEBCOBxqBGBCQBDGBCBBCEBlDhFhFBFB4L+B+BBCB9PDB-HBBhXGBuDGB29lYvHB', false)),
233
- N: () => new UnicodeRangeTable(decodeRanges('wBJB5DBBGDDBBBitBJBnEJBnGJB9MJB3DJBFFBtDJB3DJB3DJBDFBvDMB0DJBJGBoDJBpDGBISBuDJBhDJB3DJBnCTBtIJBnCJBwWTBybCBwHJBHJBXJBtJJBhEKBmFJBHJB3FJB3CJBnEJBHJB3gBEEBEBHJBnGyBBDEB3W7BBvCVB3TdBqrBqYqYaIBPCB4KDBrEJBfHBCOBhBJBoBOBh7cJB9FJBhKFB7EJBnBJBnGJBXJB3CJB3MJB34UJBuPsBBN4BBSBB2KaBlBDBeJJnEEBrGJBvdHBaGBoBIBsCEBXFBhFBBDPBDtBBhCIB1BBBfCBsCEBpDHBZHBqBGBrKFBxBJBHJB3IeB-EJBrBDBxDGBnEdBhEJB9BJBxEJBITB8HJB3KJB3DJB3LJBnDJBHTBtCLBlNSB+CJB3UJB3CcBkHJBnCJBnNJBnDUBshBuDBimPJBnpCJB3CJBnEJBCGBvQJBnIWB6yXJBnuBTBNTBtDYB2iBxBBhqCJBnNJB3PJB4HJBtWIBhEJB4Y6BBCCBCDBtCsBBCOBjeMBk3CJB', false)),
234
- Nd: () => new UnicodeRangeTable(decodeRanges('wBJnxBJnEJnGJ9MJ3DJ3DJ3DJ3DJ3DJ3DJ3DJ3DJ3DJhDJ3DJnCJ3IJnCJn6BJnBJtJJhEJnFJHJ3FJ3CJnEJHJnuiBJnVJnBJnGJXJ3CJ3MJ34UJnsBJnkCJHJ9YJhEJ9BJxEJ3IJ3KJ3DJ3LJnDJHTtCJnNJnDJ3UJ3CJ3HJnCJnNJ3uQJnpCJ3CJnEJ3QJ37XJ12CxBhqCJnNJ3PJ4HJ2aJ30EJ', true)),
235
- Nl: () => new UnicodeRangeTable(decodeRanges('u3FCBwzCiBBDDB-zDaaBHBPCBs1dJBxyW0BBtOJJnEEBrhIuDB', false)),
257
+ Mn: () => new UnicodeRangeTable(decodeRanges('gYvDB0IEBqIsBBCCCBCCBCCpCKBxBUBRmDmDBFBDFBDBBCDBkBffBZB8CKB7BIBKZZBCBCIBCCBCEBsBCB8BIBrBXBCfB4BCCFHBFEEBFBLBBe7B7BFDBJVVBbbDBB6BFFBFFBDDBBBEffBEEMBB6BFFBDBCBBFVVBXXBEBC7B7BDCCBCBJIIBMMBff+BNNzBEE4BCCBBBGCBCDBIBBMBBe7B7BDHHGBBVBBdBB6BBBFDBJVVBeepCIIBBBC7C7CDGBNHBjDDDBHBMGBqCBBcEC4BNBCEBCBBGKBCjBBKnDnDBCBCFBCBBDBBaBBFCBRDBODDBHHQgWgWBBBzdCBeBBfBBfBBhCBBCGBJDDBJBKuBuBBBBC2D2DBjBjB3DCBFBBKHHBBB8GBBD7B7BCGBCCCDHBHJBDxBxBBMBCeBDLBVDBxBCCBDBCGGpBIBNBBhBDBDBBCCB5BCCBEECCB7BHBDBB5ECBCMBCGBFHHEBBnG-BBxWMBFEEBKB--CCBuEhDhDBeBrRDBsDBB1udFFBIBhBBBxCBBxIEEFaaBGG4EBBbRBOnBnBBGBaKBvBCBxBDDBCBDBBoBkCkCBEBDBBDBBNJJwB0B0BCCBDBBGBBCrBrBBJJvHDDFx5Tx5TiXPBRPBuejHjH2EEBn0BCBCBBGDBpBCBFmFmFB+R+RBCBiCEB+JBBuCFBnCKByBDB8D3B3BBNBqBDDBLLBBByBDBDBBI+B+BBBBlBEBCHB-BNNB1B1BBHBLDBDgDgDBBBDCCBHHD+E+EEHBWBB6BBBEmBmBBFBEEBnCFBOECPBB2CHBDCBCYY1CFBCFFBCCBvHvHBCBHBBCBBcBB2CHBDCCBrDrDCDDBEBCmDmDCDDBCBCEBkIIBCBBhIBBCFFxEDBDBBFhBhBBIBpBFBDDBJKKBEBDCBvBMBCBBnGCCBBBCqGqGBFBCFBCzCzCBUBDGBCBBCBB7DFBECCBCCBFBCpCpCBEEC8K8KBMMB1B1BBDBGCCYmnFmnFHOBpmLLBECBhuCEB8BGB5gBgCgCBCByC5lT5lTBizEizEBsBBDWBhRCBSHBDGBfDB1ECB89B2BBFxBBJPPXEBCOBxqBGBCQBDGBCBBCEBlDhFhFBFB4L+B+BBCB9PDB-HBB0HDDIBBG7O7OBFBuDGB29lYvHB', false)),
258
+ N: () => new UnicodeRangeTable(decodeRanges('wBJB5DBBGDDBBBitBJBnEJBnGJB9MJB3DJBFFBtDJB3DJB3DJBDFBvDMB0DJBJGBoDJBpDGBISBuDJBhDJB3DJBnCTBtIJBnCJBwWTBybCBwHJBHJBXJBtJJBhEKBmFJBHJB3FJB3CJBnEJBHJB3gBEEBEBHJBnGyBBDEB3W7BBvCVB3TdBqrBqYqYaIBPCB4KDBrEJBfHBCOBhBJBoBOBh7cJB9FJBhKFB7EJBnBJBnGJBXJB3CJB3MJB34UJBuPsBBN4BBSBB2KaBlBDBeJJnEEBrGJBvdHBaGBoBIBsCEBXFBhFBBDPBDtBBhCIB1BBBfCBsCEBpDHBZHBqBGBrKFBxBJBHJB3IeB-EJBrBDBxDGBnEdBhEJB9BJBxEJBITB8HJB3KJB3DJB3LJBnDJBHTBtCLBlNSB+CJB3UJB3CcBkHJBnCJB3BJBnLJBnDUBshBuDBimPJBnpCJB3CJBnEJBCGBvQJBnIWB+KCB6nXJBnuBTBNTBtDYB2iBxBBhqCJBnNJB3PJB4HJBtWIBhEJB4Y6BBCCBCDBtCsBBCOBjeMBk3CJB', false)),
259
+ Nd: () => new UnicodeRangeTable(decodeRanges('wBJnxBJnEJnGJ9MJ3DJ3DJ3DJ3DJ3DJ3DJ3DJ3DJ3DJhDJ3DJnCJ3IJnCJn6BJnBJtJJhEJnFJHJ3FJ3CJnEJHJnuiBJnVJnBJnGJXJ3CJ3MJ34UJnsBJnkCJHJ9YJhEJ9BJxEJ3IJ3KJ3DJ3LJnDJHTtCJnNJnDJ3UJ3CJ3HJnCJ3BJnLJ3uQJnpCJ3CJnEJ3QJ37XJ12CxBhqCJnNJ3PJ4HJ2aJ30EJ', true)),
260
+ Nl: () => new UnicodeRangeTable(decodeRanges('u3FCBwzCiBBDDB-zDaaBHBPCBs1dJBxyW0BBtOJJnEEBrhIuDBm8SCB', false)),
236
261
  No: () => new UnicodeRangeTable(decodeRanges('yFBBGDDBBB2pCFB5LFB5DCBmEGB6GGBSIByNJB2hBTB0jBJBhP20B20BEFBHJBnGPBqB3W3WB6BBvCVB3TdBqrB1kB1kBBCBrEJBfHBCOBhBJBoBOBxrdFBymWsBBiCDBSBB2KaBlBDB1pBHBaGBoBIBsCEBXFBhFBBDPBDtBBhCIB1BBBfCBsCEBpDHBZHBqBGBrKFBhLeB-EJBrBDBxDGBnETB8LTBmqBBBvNIBobSB0aUBn8SGB-YWBqhZTBNTBtDYBvqFIBid6BBCCBCDBtCsBBCOBjeMB', false)),
237
- P: () => new UnicodeRangeTable(decodeRanges('hBCBCFBCDBLBBEBBbCBCccCkBkBGEELBBEEE-VJJzOFBqBBB0BCCDDDtBBBVBBCBBOCCBBBrCDBnDsBsBBMBqHCB3BOBgBmImIBLLtE5D5D6DnMnMNwLwL7CLLBpFpFBNBCmBmBBCBoCrCrCBDBFBBwDFBsFlTlTBHB4EuTuTtBBBvCCBoCBB+ECBCCBmBKB6JBB5GBBhEGBCFBhFBBLGBdCB9DDB8BEB-BBBhCHBM9Z9ZBWBJTBCMBCLBfBBPBB6TDBeBB+hBNBwCBBgBJB0MVBgCDBhBBB8XDBCBBxDwEwEBtBBCfBDLBkNCBFJBDLBRNNjD7C7CjgdBBuICBkDLL0DFB9LDB3CBBpBCBCyByBBwBwBiDMBRBB9DDB-DBBRBB6HzqUzqUBxGxGBIBXiBBCNBCFFCBB2ECBCFBCDBLBBEBBbCBCccCCCBFB7MCB9UxBxB-MoXoXoGgBgBxIIBnBxDxDBFBjCGB6CDByO-J-JoFEBtBDB+FGBuDBBCDB-DDBxBBBwCDBFOOCCB5CFBsDrJrJBCCBzDzDBDBLBBCpDpD7HWBqDCBdMBtCjEjEBBB9HpIpIBBB8E9C9CBGB0CCBCEB+CJB4GgDgDBDBrBBBmUBBrCMBwFxjBxjBBDB97CBB8zOBBmEiCiCBDBJpRpRBBBoJDBoK9lT9lTovHEB07C-a-aBAB', false)),
262
+ P: () => new UnicodeRangeTable(decodeRanges('hBCBCFBCDBLBBEBBbCBCccCkBkBGEELBBEEE-VJJzOFBqBBB0BCCDDDtBBBVBBCBBOCCBBBrCDBnDsBsBBMBqHCB3BOBgBmImIBLLtE5D5D6DnMnMNwLwL7CLLBpFpFBNBCmBmBBCBoCrCrCBDBFBBwDFBsFlTlTBHB4EuTuTtBBBvCCBoCBB+ECBCCBmBKB6JBB5GBBhEGBCFBhFBBLGBdCB9DDB8BEB-BBBhCHBM9Z9ZBWBJTBCMBCLBfBBPBB6TDBeBB+hBNBwCBBgBJB0MVBgCDBhBBB8XDBCBBxDwEwEBtBBCfBDLBkNCBFJBDLBRNNjD7C7CjgdBBuICBkDLL0DFB9LDB3CBBpBCBCyByBBwBwBiDMBRBB9DDB-DBBRBB6HzqUzqUBxGxGBIBXiBBCNBCFFCBB2ECBCFBCDBLBBEBBbCBCccCCCBFB7MCB9UxBxB-MoXoXoGgBgBxIIBnBxDxDBFBjCGB6CDByO-J-JjBlElEBDBtBDB+FGBuDBBCDB-DDBxBBBwCDBFOOCCB5CFBsDrJrJBCCBzDzDBDBLBBCpDpD7HWBqDCBdMBtCjEjEBBB9HpIpIBBB8E9C9CBGB0CCBCEB+CJB4GgDgDBDBrBBBmUBBrCMBwFxjBxjBBDB97CBB8zOBBmEiCiCBDBJpRpRBBBoJDBoK9lT9lTovHEB07C-a-aBAB', false)),
238
263
  Pc: () => new UnicodeRangeTable(decodeRanges('-Cg-Hg-HBUU-u3BBBZCBwHAB', false)),
239
264
  Pd: () => new UnicodeRangeTable(decodeRanges('tB9qB9qB0BiyDiyDmgBqgCqgCBEBiwDDDgBBBFdd-NUUwDxszBxszBBmBmBLqFqFhzD-J-J', false)),
240
265
  Pe: () => new UnicodeRangeTable(decodeRanges('pB0B0BgB+1D+1DC-6B-6BqtC4B4BQ7T7TCff-hBMCxChBhBCGC1MUChCCCiBmhBmhBCECtBGCtNICEGCDBB-ozB6G6GeOCESSCCCrF0B0BgBGD', false)),
241
266
  Pf: () => new UnicodeRangeTable(decodeRanges('7F+6H+6HEddpuDCCFDDQEE', false)),
242
267
  Pi: () => new UnicodeRangeTable(decodeRanges('rFt7Ht7HDBBDaapuDCCFDDQEE', false)),
243
- Po: () => new UnicodeRangeTable(decodeRanges('hBCBCCBDECBLLBEEBcclCGGPBBI-V-VJzOzOBEBqB3B3BDDDtBBBVBBCBBOCCBBBrCDBnDsBsBBMBqHCB3BOBgBmImIBLLtE5D5D6DnMnMNwLwL7CLLBpFpFBNBCxDxDrCEBFBBwDFBsFlTlTBHBmY9D9DBBBoCBB+ECBCCBmBFBCDB6JBB5GBBhEGBCFBhFBBLGBdCB9DDB8BEB-BBBhCHBMjajaBJJBGBJIBDDBDCBEKBCCCBIB7kDDBCBBxDwEwEBFFBBBDDDBHBCBBCDDBLLBDBCJBDDBCCCBLBDCBtNCB6B+F+FjgdBBuICBkDLL0DFB9LDB3CBBpBCBCyByBBwBwBiDMBRBB9DDB-DBBRBB6HlxUlxUBFBDXXVBBDDBECBCDBICBHCCB2E2EBBBCCBDECBLLBEEBcclBDDB7M7MBBB9UxBxB-MoXoXoGgBgBxIIBnBxDxDBFBjCGB6CDB5dEBtBDB+FGBuDBBCDB-DDBxBBBwCDBFOOCCB5CFBsDrJrJBCCBzDzDBDBLBBCpDpD7HWBqDCBdMBtCjEjEBBB9HpIpIBBB8E9C9CBGB0CCBCEB+CJB4GgDgDBDBrBBBmUBBrCMBwFxjBxjBBDB97CBB8zOBBmEiCiCBDBJpRpRBBBoJDBoK9lT9lTovHEB07C-a-aBAB', false)),
268
+ Po: () => new UnicodeRangeTable(decodeRanges('hBCBCCBDECBLLBEEBcclCGGPBBI-V-VJzOzOBEBqB3B3BDDDtBBBVBBCBBOCCBBBrCDBnDsBsBBMBqHCB3BOBgBmImIBLLtE5D5D6DnMnMNwLwL7CLLBpFpFBNBCxDxDrCEBFBBwDFBsFlTlTBHBmY9D9DBBBoCBB+ECBCCBmBFBCDB6JBB5GBBhEGBCFBhFBBLGBdCB9DDB8BEB-BBBhCHBMjajaBJJBGBJIBDDBDCBEKBCCCBIB7kDDBCBBxDwEwEBFFBBBDDDBHBCBBCDDBLLBDBCJBDDBCCCBLBDCBtNCB6B+F+FjgdBBuICBkDLL0DFB9LDB3CBBpBCBCyByBBwBwBiDMBRBB9DDB-DBBRBB6HlxUlxUBFBDXXVBBDDBECBCDBICBHCCB2E2EBBBCCBDECBLLBEEBcclBDDB7M7MBBB9UxBxB-MoXoXoGgBgBxIIBnBxDxDBFBjCGB6CDB0ZlElEBDBtBDB+FGBuDBBCDB-DDBxBBBwCDBFOOCCB5CFBsDrJrJBCCBzDzDBDBLBBCpDpD7HWBqDCBdMBtCjEjEBBB9HpIpIBBB8E9C9CBGB0CCBCEB+CJB4GgDgDBDBrBBBmUBBrCMBwFxjBxjBBDB97CBB8zOBBmEiCiCBDBJpRpRBBBoJDBoK9lT9lTovHEB07C-a-aBAB', false)),
244
269
  Ps: () => new UnicodeRangeTable(decodeRanges('oBzBzBgB-1D-1DC-6B-6B-rCEEnB4B4BQ7T7TCff-hBMCxChBhBCGC1MUChCCCiBmhBmhBCECaTTCECtNICEGCDipzBipzB4GeeCMCESSCCCrFzBzBgBEEDAB', false)),
245
- S: () => new UnicodeRangeTable(decodeRanges('kBHHRCBgBCCcCCkBEBCBBDCCBCBDEEfgBgBrODBNNBGGBCCCBPB2DPPBxDxDsErIrIBBB3DCBDDDBvGvGLUUB4H4HIBBpEqLqLBHHB2H2H-DjEjEBGBlEwGwGqBmGmGiGCBQCCBBBDFBVECmEHBCFBCBBGDBmGBBxXJB0WuLuLlL+E+EBgBBiLJBKIBhiBCCBBBMCBOCBOCBOBBmCOOoBCBOCBUgBBgCBBCDBCBBLCCBBBGFBCECFMMBFFBDBGDBC7B7BBFFB2LBFcBD+HBXKByCtCBXnTBtBwBBDeBLyMBX+BBFfBD1LBDfBCoDBmHFBmLBBvBZBC4CBN1GBbPBFOOBNNWBBHBB8CBB0HBBFJBhBlBBKRRBdBMdBJQQBeBLmBBQ-JBhuG-BBx0V2BB6RWBKBBoDBB+EDBLDB+RCBiHPPB+9T+9TpEQB+LPBgEtBtBBCBjDCCBBBD7E7EHRRBBBgBCCcCCiEGBCGBOBB6JIB6BQBDCBCMBEwBwBBrBB7zBBBwSmWmWBwtCwtC2kCcBr6SDBG3qU3qUk7DvHBRzNB9EzDB9B1HBLmBBD7BBGCBXBBIdBF8BBWhCBE7F7FB1CBrbaagBaagBaagBaagBaa9B-PB4BDBzBHBCNBCBBp2BwNwNttCEE+DiOiOBvIvIBqBBFjDBNOBDOBCOBCkBBYgFB5BcBOrBBFIBIBBPFB7E3eBFQBEMBE2DBF+CBHLBFQQBKBF3BBJJBHnBBJdBDLBFBB-BzKBNNBDMBEJBG3BBIOBDKBHIBIyEBC7CB', false)),
246
- Sc: () => new UnicodeRangeTable(decodeRanges('kB+D+DBCBqnB8D8DzPBBzPBBI2H2HoImSmS8sClmClmCBfB47hBkuVkuVtD7E7E8GBBEBB3-HDB-4wBxtCxtC', false)),
270
+ S: () => new UnicodeRangeTable(decodeRanges('kBHHRCBgBCCcCCkBEBCBBDCCBCBDEEfgBgBrODBNNBGGBCCCBPB2DPPBxDxDsErIrIBBB3DCBDDDBvGvGLUUB4H4HIBBpEqLqLBHHB2H2H-DjEjEBGBlEwGwGqBmGmGiGCBQCCBBBDFBVECmEHBCFBCBBGDBmGBBxXJB0WuLuLlL+E+EBgBBiLJBKIBhiBCCBBBMCBOCBOCBOBBmCOOoBCBOCBUhBB-BBBCDBCBBLCCBBBGFBCECFMMBFFBDBGDBC7B7BBFFB2LBFcBD+HBXKByCtCBXnTBtBwBBDeBLyMBX+BBFfBD1LBDpEBmHFBmLBBvBZBC4CBN1GBbPBFOOBNNWBBHBB8CBB0HBBFJBhBlBBKRRBdBMdBJQQBeBLmBBQ-JBhuG-BBx0V2BB6RWBKBBoDBB+EDBLDB+RCBiHPPB+9T+9TpEgBBuLPBhCBB3BHBtBDBjDCCBBBD7E7EHRRBBBgBCCcCCiEGBCGBOBB6JIB6BQBDCBCMBEwBwBBrBB7zBBBwSmWmWBiKiKBGBnjC2kC2kCBbBr6SDBG3qU3qUk7DvHBLCBEzNBHWBQQBgDzDB9B1HBLmBBD7BBGCBXBBIdBF8BBWhCBE7F7FB1CBrbaagBaagBaagBaagBaa9B-PB4BDBzBHBCNBCBBp2BwNwNttCEE+DiOiOBvIvIBqBBFjDBNOBDOBCOBCkBBYgFB5BcBOrBBFIBIBBPFB7E4eBEQBEMBE5GBHLBFQQBKBF3BBJJBHnBBJdBDLBFBBPIBoB3KBJNBDMBEKBE4BBCFFBOBDLBFJBIyEBC7CBLAB', false)),
271
+ Sc: () => new UnicodeRangeTable(decodeRanges('kB+D+DBCBqnB8D8DzPBBzPBBI2H2HoImSmS8sClmClmCBgBB37hBkuVkuVtD7E7E8GBBEBB3-HDB-4wBxtCxtC', false)),
247
272
  Sk: () => new UnicodeRangeTable(decodeRanges('+CCCoCHHFEEqQDBNNBGGBCCCBPB2DPPBjoBjoB15FCCBBBMCBOCBOCBOBB9kEBBkzdWBKBBoDBBxePPBniUniUBPB8bCCjF4g9B4g9BBDB', false)),
248
- Sm: () => new UnicodeRangeTable(decodeRanges('rBRRBBB+BCCuBFFmBgBgB-XwQwQBBB8xGOOoBCBOCBsEoBoBBDBHlClCBDBGBBFGDIgBgBBDDCgBgBBqIBhBBB7CffBXBpBFB2OKK3BHBwDxKxKBDBDeBLPBhIiEBX+BBFfBDhIBxBUBDFB9+zB5Z5ZCCBlFRRBBB+BCCkEHHBCBitDBBypyBaagBaagBaagBaagBaat5FBB', false)),
249
- So: () => new UnicodeRangeTable(decodeRanges('mFDDFCCyerIrIBgEgEBvGvGLUUB4H4HkQ2L2LjEFBClElEwGqBqBoMCBQCCBBBDFBVECmEHBCFBCBBGDBmGBBxXJB0WzWzW+EhBBiLJBKIBksBBBCDBCBBLCCBHHBEBCECFMMBPPCBBC7B7BBKKBDBDDBCBBCBBCGBCeBDBBCCCBdBtIHBFTBDGBDwCBCdBanBBHnCBXKByCtCBX2FBCIBC1BBJuDBC3HBtBrBBhC-HBhQvBBWBBHmBBDfBCoDBmHFBmLBBvBZBC4CBN1GBbPBFOOBNNWBBHBBxKBBFJBhBlBBKRRBdBMdBJQQBeBLmBBQ-JBhuG-BBx0V2BBibDBLBBC+R+RBBBn2UPBgEuBuBBBBlPEEFBBOBB6JIB6BQBDCBCMBEwBwBBrBB7zBBBwS3jD3jD2kCHBFQBr6SDBG3qU3qUk7DvHBRzNB9EzDB9B1HBLmBBD7BBGCBXBBIdBF8BBWhCBE7F7FB1CBqlB-PB4BDBzBHBCNBCBBp2B96C96CiEyWyWBqBBFjDBNOBDOBCOBCkBBYgFB5BcBOrBBFIBIBBPFB7E6HBG3WBFQBEMBE2DBF+CBHLBFQQBKBF3BBJJBHnBBJdBDLBFBB-BzKBNNBDMBEJBG3BBIOBDKBHIBIyEBC7CB', false)),
273
+ Sm: () => new UnicodeRangeTable(decodeRanges('rBRRBBB+BCCuBFFmBgBgB-XwQwQBBB8xGOOoBCBOCBsEoBoBBDBHlClCBDBGBBFGDIgBgBBDDCgBgBBqIBhBBB7CffBXBpBFB2OKK3BHBwDxKxKBDBDeBLPBhIiEBX+BBFfBDhIBxBUBDFB9+zB5Z5ZCCBlFRRBBB+BCCkEHHBCBitDBBhrwBx+Bx+BagBgBagBgBagBgBagBgBat5Ft5FB-uC-uCBHB', false)),
274
+ So: () => new UnicodeRangeTable(decodeRanges('mFDDFCCyerIrIBgEgEBvGvGLUUB4H4HkQ2L2LjEFBClElEwGqBqBoMCBQCCBBBDFBVECmEHBCFBCBBGDBmGBBxXJB0WzWzW+EhBBiLJBKIBksBBBCDBCBBLCCBHHBEBCECFMMBPPCBBC7B7BBKKBDBDDBCBBCBBCGBCeBDBBCCCBdBtIHBFTBDGBDwCBCdBanBBHnCBXKByCtCBX2FBCIBC1BBJuDBC3HBtBrBBhC-HBhQvBBWBBHmBBDpEBmHFBmLBBvBZBC4CBN1GBbPBFOOBNNWBBHBBxKBBFJBhBlBBKRRBdBMdBJQQBeBLmBBQ-JBhuG-BBx0V2BBibDBLBBC+R+RBBBqqUPBuLPBhCBB3BHBuBCBlPEEFBBOBB6JIB6BQBDCBCMBEwBwBBrBB7zBBBwSpgBpgBBGBnjC2kC2kCBGBFQBr6SDBG3qU3qUk7DvHBLCBEzNBHWBQPBhDzDB9B1HBLmBBD7BBGCBXBBIdBF8BBWhCBE7F7FB1CBqlB-PB4BDBzBHBCNBCBBp2B96C96CiEyWyWBqBBFjDBNOBDOBCOBCkBBYgFB5BcBOrBBFIBIBBPFB7E6HBG4WBEQBEMBE5GBHLBFQQBKBF3BBJJBHnBBJdBDLBFBB-B3KBJNBDMBEKBE4BBCFFBOBDLBFJBIyEBC7CBLAB', false)),
250
275
  Z: () => new UnicodeRangeTable(decodeRanges('gBgEgEgvFgsCgsCBJBeBBGwBwBh9DAB', false)),
251
276
  Zl: () => new UnicodeRangeTable(decodeRanges('ohIA', true)),
252
277
  Zp: () => new UnicodeRangeTable(decodeRanges('phIA', true)),
@@ -259,7 +284,7 @@ class UnicodeTables {
259
284
  Adlam: () => new UnicodeRangeTable(decodeRanges('go6DrCFJFB', true)),
260
285
  Ahom: () => new UnicodeRangeTable(decodeRanges('g4lCaDOFW', true)),
261
286
  Anatolian_Hieroglyphs: () => new UnicodeRangeTable(decodeRanges('ggxCmS', true)),
262
- Arabic: () => new UnicodeRangeTable(decodeRanges('gwBEBCFBCNBCCBCfBCJBMZBCrDBChBBxCvBBxHeBCBBGqCBCcBxy8ByDBRqLBDvCBD1BBIhBhBBOBxDEBCmEBk7DeBkCCB4BDBh43BDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQB1BBB', false)),
287
+ Arabic: () => new UnicodeRangeTable(decodeRanges('gwBEBCFBCNBCCBCfBCJBMZBCrDBChBBxCvBBxHhBBGqCBCcBxy8BtPBDvEBhBPBxDEBCmEBk7DeBkCFBJIBiBFBh43BDBCaBCBBCDDCJBCDBCCCHFFCECBBBCBBCDDCICBCCDDBCGBCDBCDBCCCBIBCQBGCBCEBCQB1BBB', false)),
263
288
  Armenian: () => new UnicodeRangeTable(decodeRanges('xpBlBDxBDCks9BE', true)),
264
289
  Avestan: () => new UnicodeRangeTable(decodeRanges('g4iC1BEG', true)),
265
290
  Balinese: () => new UnicodeRangeTable(decodeRanges('g4GsCCxB', true)),
@@ -267,6 +292,7 @@ class UnicodeTables {
267
292
  Bassa_Vah: () => new UnicodeRangeTable(decodeRanges('w26CdDF', true)),
268
293
  Batak: () => new UnicodeRangeTable(decodeRanges('g+GzBJD', true)),
269
294
  Bengali: () => new UnicodeRangeTable(decodeRanges('gsCDBCHBDBBDVBCGBCEEBCBDIBDBBDDBJFFBCCBDBDYB', false)),
295
+ Beria_Erfe: () => new UnicodeRangeTable(decodeRanges('g17CYDY', true)),
270
296
  Bhaiksuki: () => new UnicodeRangeTable(decodeRanges('ggnCICsBCNLc', true)),
271
297
  Bopomofo: () => new UnicodeRangeTable(decodeRanges('qXB6wLqBxDf', true)),
272
298
  Brahmi: () => new UnicodeRangeTable(decodeRanges('ggkCtCFjBKA', true)),
@@ -280,7 +306,7 @@ class UnicodeTables {
280
306
  Cham: () => new UnicodeRangeTable(decodeRanges('gwqB2BKNDJDD', true)),
281
307
  Cherokee: () => new UnicodeRangeTable(decodeRanges('g9E1CDFz7lBvC', true)),
282
308
  Chorasmian: () => new UnicodeRangeTable(decodeRanges('w9jCb', true)),
283
- Common: () => new UnicodeRangeTable(decodeRanges('AgCBbFBbuBBCOBCEBYgBgBiOmBBGEBDTB1DKKHCC+THHPEEhB9E9ElQiEiEB6mB6mB2MDBjJwvBwvBBBBoCBBsGBBCumBumBOIIBCBCFBCCBDmYmYBKBD2CBCKBEKBCOBSgBBgClBBCCBDFBCaBCQBqBCBF5UBXKBW-cBhIzTBDfBCoDBhQ9CBzMUBCCCBXBQHBFDB8CBBE7C7CB0E0EBOBhBlBBKxBxBB+BBgBwCBwB5C5CBmFBhuG-BBhoWhBBnDCBmFJB1HhFhFsMPPBzuUzuUBxGxGBIBXiBBCSBCDB0ECCBeBbFBbKBLuBuBBhChCBFBCGBLEBjICBFsBBEIBxCMB0BsBBlHaBltuBDB96D5HBHzNB9EzDB9B1HBLmBBD9BBEQBJBBIdBF8BB2GTBNTBN2CBKYBoE0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDjJBDxBByjFjCBtC8BBjWrBBFjDBNOBDOBCOBCkBBLtFB5BZBCBBOrBBFIBIBBPFB7E3eBFQBEMBE2DBF+CBHLBFQQBKBF3BBJJBHnBBJdBDLBFBB-BzKBNNBDMBEJBG3BBIOBDKBHIBIyEBClDBoghYffB+CB', false)),
309
+ Common: () => new UnicodeRangeTable(decodeRanges('AgCBbFBbuBBCOBCEBYgBgBiOmBBGEBDTB1DKKHCC+THHPEEhB9E9ElQiEiEB6mB6mB2MDBjJwvBwvBBBBoCBBsGBBCumBumBOIIBCBCFBCCBDmYmYBKBD2CBCKBEKBCOBShBB-BlBBCCBDFBCaBCQBqBCBF5UBXKBW-cBhIzTBDpEBhQ9CBzMUBCCCBXBQHBFDB8CBBE7C7CB0E0EBOBhBlBBKxBxBB+BBgBwCBwB5C5CBmFBhuG-BBhoWhBBnDCBmFJB1HhFhFsMPPBzuUzuUBxGxGBIBXiBBCSBCDB0ECCBeBbFBbKBLuBuBBhChCBFBCGBLEBjICBFsBBEIBxCMB0BsBBlHaBltuBDB96D8HBEzNBHWBQQBgDzDB9B1HBLmBBD9BBEQBJBBIdBF8BB2GTBNTBN2CBKYBoE0CBCmCBCBBDDDBDDBCBCLBCCCBFBCgCBCDBDHBCGBCbBCDBCEBCEEBFBCzKBDjJBDxBByjFjCBtC8BBjWrBBFjDBNOBDOBCOBCkBBLtFB5BZBCBBOrBBFIBIBBPFB7E4eBEQBEMBE5GBHLBFQQBKBF3BBJJBHnBBJdBDLBFBBPIBoB3KBJNBDMBEKBE4BBCFFBOBDLBFJBIyEBCmDBnghYffB+CB', false)),
284
310
  Coptic: () => new UnicodeRangeTable(decodeRanges('ifNxkKzDGG', true)),
285
311
  Cuneiform: () => new UnicodeRangeTable(decodeRanges('ggoC5cnDuDCEMjG', true)),
286
312
  Cypriot: () => new UnicodeRangeTable(decodeRanges('ggiCFBDCCBqBBCBBEDD', false)),
@@ -305,7 +331,7 @@ class UnicodeTables {
305
331
  Gunjala_Gondi: () => new UnicodeRangeTable(decodeRanges('grnCFCBCkBCBCFIJ', true)),
306
332
  Gurmukhi: () => new UnicodeRangeTable(decodeRanges('hwCCBCFBFBBDVBCGBCBBCBBCBBDCCBDBFBBDCBEIIBCBCIIBPB', false)),
307
333
  Gurung_Khema: () => new UnicodeRangeTable(decodeRanges('go4C5B', true)),
308
- Han: () => new UnicodeRangeTable(decodeRanges('g0LZBC4CBN1GBwBCCaIBPDBle-tGBhC-vUBhoWtLBDpDBpodBBNBBvgkB-2pBBhB5hEBH9GBDh0FBPwpHBQtTBjtC9QBjvBq6EBG-iEB', false)),
334
+ Han: () => new UnicodeRangeTable(decodeRanges('g0LZBC4CBN1GBwBCCaIBPDBle-tGBhC-vUBhoWtLBDpDBpodBBNGBqgkB-2pBBhB9oEBDt0FBDwpHBQtTBjtC9QBjvBq6EBGppIB', false)),
309
335
  Hangul: () => new UnicodeRangeTable(decodeRanges('goE-HvxHBiI9CyDeiCei3dckUj9KNWFwBl9JeEFDFDFDC', true)),
310
336
  Hanifi_Rohingya: () => new UnicodeRangeTable(decodeRanges('gojCnBJJ', true)),
311
337
  Hanunoo: () => new UnicodeRangeTable(decodeRanges('g5FU', true)),
@@ -313,12 +339,12 @@ class UnicodeTables {
313
339
  Hebrew: () => new UnicodeRangeTable(decodeRanges('xsB2BBJaBFFBpp9BZBCEBCCCBCCBCCBIB', false)),
314
340
  Hiragana: () => new UnicodeRangeTable(decodeRanges('hiM1CBHCBi7-C+IBTeeBBBulQAB', false)),
315
341
  Imperial_Aramaic: () => new UnicodeRangeTable(decodeRanges('giiCVCI', true)),
316
- Inherited: () => new UnicodeRangeTable(decodeRanges('gYvDB2IBBlOKBbhXhXBCB8qEeBiQCBCMBCGBFHHEBBnG-BBtQBBjGgBB65DDBsDBBmrzBPBRNBwejHjH7iEl+uBl+uBBsBBDWBhRCBSHBDGBfDBz6rYvHB', false)),
342
+ Inherited: () => new UnicodeRangeTable(decodeRanges('gYvDB2IBBlOKBbhXhXBCB8qEtBBDLBlPCBCMBCGBFHHEBBnG-BBtQBBjGgBB65DDBsDBBmrzBPBRNBwejHjH7iEl+uBl+uBBsBBDWBhRCBSHBDGBfDBz6rYvHB', false)),
317
343
  Inscriptional_Pahlavi: () => new UnicodeRangeTable(decodeRanges('g7iCSGH', true)),
318
344
  Inscriptional_Parthian: () => new UnicodeRangeTable(decodeRanges('g6iCVDH', true)),
319
345
  Javanese: () => new UnicodeRangeTable(decodeRanges('gsqBtCDJFB', true)),
320
346
  Kaithi: () => new UnicodeRangeTable(decodeRanges('gkkCiCLA', true)),
321
- Kannada: () => new UnicodeRangeTable(decodeRanges('gkDMCCCWCJCEDICCCDIBHBCDDJCC', true)),
347
+ Kannada: () => new UnicodeRangeTable(decodeRanges('gkDMCCCWCJCEDICCCDIBGCCDDJCC', true)),
322
348
  Katakana: () => new UnicodeRangeTable(decodeRanges('hlM5CBDCBxHPBxGuBBC3CBvgzBJBCsBBzisBDBCGBCBBCgJgJBBBzBPPBCB', false)),
323
349
  Kawi: () => new UnicodeRangeTable(decodeRanges('g4nCQCoBEc', true)),
324
350
  Kayah_Li: () => new UnicodeRangeTable(decodeRanges('goqBtBCA', true)),
@@ -329,7 +355,7 @@ class UnicodeTables {
329
355
  Khudawadi: () => new UnicodeRangeTable(decodeRanges('w1kC6BGJ', true)),
330
356
  Kirat_Rai: () => new UnicodeRangeTable(decodeRanges('gq7C5B', true)),
331
357
  Lao: () => new UnicodeRangeTable(decodeRanges('h0DBBCCCBDBCXBCCCBVBDEBCCCBFBCJBDDB', false)),
332
- Latin: () => new UnicodeRangeTable(decodeRanges('hCZBHZBwBQQGWBCeBCgOBoBEB8wGlBBHwBBGDBGMBClCBiC-HByLOORMBuEBBHccSoBB42CfBj1elDBEiCBDBBCCCBGBWNBxZqBBCIBCDB38TGB7gBZBHZBmhCFBCpBBCIBm61BeBHFB', false)),
358
+ Latin: () => new UnicodeRangeTable(decodeRanges('hCZBHZBwBQQGWBCeBCgOBoBEB8wGlBBHwBBGDBGMBClCBiC-HByLOORMBuEBBHccSoBB42CfBj1elDBExCBVOBxZqBBCIBCDB38TGB7gBZBHZBmhCFBCpBBCIBm61BeBHFB', false)),
333
359
  Lepcha: () => new UnicodeRangeTable(decodeRanges('ggH3BEOEC', true)),
334
360
  Limbu: () => new UnicodeRangeTable(decodeRanges('goGeBCLBFLBFEEBKB', false)),
335
361
  Linear_A: () => new UnicodeRangeTable(decodeRanges('gwhC2JKVLH', true)),
@@ -388,9 +414,10 @@ class UnicodeTables {
388
414
  Runic: () => new UnicodeRangeTable(decodeRanges('g1FqCEK', true)),
389
415
  Samaritan: () => new UnicodeRangeTable(decodeRanges('ggCtBDO', true)),
390
416
  Saurashtra: () => new UnicodeRangeTable(decodeRanges('gkqBlCJL', true)),
391
- Sharada: () => new UnicodeRangeTable(decodeRanges('gskC-C', true)),
417
+ Sharada: () => new UnicodeRangeTable(decodeRanges('gskC-ChsCH', true)),
392
418
  Shavian: () => new UnicodeRangeTable(decodeRanges('wihCvB', true)),
393
419
  Siddham: () => new UnicodeRangeTable(decodeRanges('gslC1BDlB', true)),
420
+ Sidetic: () => new UnicodeRangeTable(decodeRanges('gqiCZ', true)),
394
421
  SignWriting: () => new UnicodeRangeTable(decodeRanges('gg2DrUQECO', true)),
395
422
  Sinhala: () => new UnicodeRangeTable(decodeRanges('hsDCBCRBEXBCIBCDDBFBEFFBEBCCCBGBHJBDCBt-gCTB', false)),
396
423
  Sogdian: () => new UnicodeRangeTable(decodeRanges('w5jCpB', true)),
@@ -405,21 +432,23 @@ class UnicodeTables {
405
432
  Tai_Le: () => new UnicodeRangeTable(decodeRanges('wqGdDE', true)),
406
433
  Tai_Tham: () => new UnicodeRangeTable(decodeRanges('gxG+BCcDKHJHN', true)),
407
434
  Tai_Viet: () => new UnicodeRangeTable(decodeRanges('g0qBiCZE', true)),
435
+ Tai_Yo: () => new UnicodeRangeTable(decodeRanges('g25DeCVJB', true)),
408
436
  Takri: () => new UnicodeRangeTable(decodeRanges('g0lC5BHJ', true)),
409
437
  Tamil: () => new UnicodeRangeTable(decodeRanges('i8CBBCFBECBCDBEBBCCCBEEBEEBBBELBFEBECBCDBDHHPUBm+kCxBBOAB', false)),
410
438
  Tangsa: () => new UnicodeRangeTable(decodeRanges('wz6CuCCJ', true)),
411
- Tangut: () => new UnicodeRangeTable(decodeRanges('g-7CgBgBB2-FBJ-XBhQIB', false)),
412
- Telugu: () => new UnicodeRangeTable(decodeRanges('ggDMBCCBCWBCPBDIBCCBCDBIBBCCBDDDBCBDJBIIB', false)),
439
+ Tangut: () => new UnicodeRangeTable(decodeRanges('g-7CgBgBB+3GBhQeBiDyDB', false)),
440
+ Telugu: () => new UnicodeRangeTable(decodeRanges('ggDMCCCWCPDICCCDIBCCCBDDDJII', true)),
413
441
  Thaana: () => new UnicodeRangeTable(decodeRanges('g8BxB', true)),
414
442
  Thai: () => new UnicodeRangeTable(decodeRanges('hwD5BGb', true)),
415
443
  Tibetan: () => new UnicodeRangeTable(decodeRanges('g4DnCCjBFmBCjBCOCGFB', true)),
416
444
  Tifinagh: () => new UnicodeRangeTable(decodeRanges('wpL3BIBPA', true)),
417
445
  Tirhuta: () => new UnicodeRangeTable(decodeRanges('gklCnCJJ', true)),
418
446
  Todhri: () => new UnicodeRangeTable(decodeRanges('guhCzB', true)),
447
+ Tolong_Siki: () => new UnicodeRangeTable(decodeRanges('wtnCrBFJ', true)),
419
448
  Toto: () => new UnicodeRangeTable(decodeRanges('w04De', true)),
420
449
  Tulu_Tigalari: () => new UnicodeRangeTable(decodeRanges('g8kCJBCDDClBBCJBCDDCDBCJBCBBJBB', false)),
421
450
  Ugaritic: () => new UnicodeRangeTable(decodeRanges('g8gCdCA', true)),
422
- Unknown: () => new UnicodeRangeTable(decodeRanges('4bBBHDBICCVuMuMnBBBzBBBE4B4BBGBcDBHKBvI9B9BBmDmDBMB8BBByBBBQddBCCMEBgBDDBDBuHJJBDDBXXICCBBBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEBCCBFFBLLBFBXEEYLLGBBKEEFGBDFBDFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBbFB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBgBwBBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKmDmDNBBcOOBBBiBOBiBOBtEDB7UVBMUB14BBBhB+K+KBDBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHBvGBBDCCJUB8BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBjoIBvLBBrDlBBILBGEBbGGCGD+DPB+NBB3BGBCfBrBFB0BUUFDBGoEoEBCC-FCBHBBHBBHBBECBIIIBIBGBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBC-BB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBE2BBtBHBrBVBblBBdTBYIBvCDBlBIBlCJBCBBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1FBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBL1JBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMB3iBJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CkDBsCDB6BGBS-BBGKBDNB5-FHB3mBoBBLm3IBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBJ76DB7HFB1NrCBvBBBYIB1D7BB3HJBoBBBjGUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-OBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB5eDBSCBOCB4DDBgDFBNDBCOBNDB5BHBLFBpBHBfBBNDBD9BB1KLBPBBOCBLEB5BGBQBBMFBKGB0EnDnDBkgBBh3pBfB7hEFB-GBBj0FNBypHOBvThtCB-QhvBBs6EEBhjEwi3VBCdBhD-DBxHvw-FB', false)),
451
+ Unknown: () => new UnicodeRangeTable(decodeRanges('4bBBHDBICCVuMuMnBBBzBBBE4B4BBGBcDBHKBvI9B9BBmDmDBMB8BBByBBBQddBCCMEBjBEBuHJJBDDBXXICCBBBFBBKBBDBBFHBCDBDGGBaaBEEHDBDBBXIIDGDBCCGDBDBBECBCGBFCCBFBSJBEKKEXXIDDGBBLIEBCCBNBFBBNGBIEEJBBDBBXIIDGGBKKBDDBEEBFBEDBDGGBTTBIBDHHBBBEFFBBBDCCDCBDCBECBNDBGCBEFFBCCBEBCNBWEBOEEYRRBKKEFFBFBDEEDBBFBBLGBXEEYLLGBBKEEFGBDEBEFFBLLELBOEE0BEEHDBRBBbEETCBZKKCBBICBCDBHCCJFBLBBELB7BDBekBBDCCGZZCYYBGGCIILBBFfBpClBlBBCBoBlBlBQOOBjBBnGCCBDBCBB6LFFBIICFFBqBqBFBBiBFFBIICFFBQQ6BFFBkCkCBhBhBBBBbFB3CBBHBB+UCB6CGBXIBZIBVLBOEEDLB-CBBLFBLFBbFB6CGBsBEBnCJBgBNNBCBNDBCCBrBBBGKBtBDBbFBMCB-BBBiCeeBMMBEBLFBPBBvBBBNTBuCnFnFBGB9BCBQCB-BEBsBBBMHBsBEB3QBBHBBnBBBHBBJGCgBBB2BQQPBBHUUBEEKmDmDNBBcOOBBBjBNBiBOBtEDB7UVBMUB14BBB-LEBuBCCBDBCBB5BGBDNBZIBI4BI-DhBBb6C6CBKB3GZBxC3C3CBoDoDBDBsB-C-C3CIBxBuzcuzcBBB4BIB9KTB5FHB+GTB9BCBLFB5BHBnCHBNFB1DKBfCBvCMMBCBiB4B4BBHBPBBLBBoDXBdJBHBBHBBHIBIII9BDB-DBBLFBl9KLBYDByBjoIBvLBBrDlBBILBGEBbGGCGDrUfBrBFB0BUUFDBGoEoEBCC-FCBHBBHBBHBBECBIIIBIBGBBNbbUDDQBBPhBB8DEBEDBuBCB5COOBBBCuBBvBhEBeCByBOBdDBlBIBfEBsBEBfmBmBBCBPpBB-EBBLFBlBDBlBDBpBHB1BKBNQQIDDMQQIDDBBB1BLB4JIBXJBJXBHrBrBKkCBHBBCtBtBDCBCBBYpCpCBGBKvBBUDDBDBiBCBcEBclBB5BDBVBBzBDDBDBJEEeBBEDBLGBKGBhCfBoBDBNIB3BCBeBBcEBbGBFLBIvCBqC2BB0BMB0BGBvBHBLFBnBCBeHBDvGBgBrBrBEBBDPBHHBKgBBvBHBrBVBblBBdTBYIBvCDBlBIBlCJBCBBaGBLFB2BTTBGBoBIBhDVVBJBTwBwBB8BBICCFQQMFB8BEBLFBFJJBDDBXXIDDGLLBDDBEEBCCBEBCEBIBBICBGKBLCCBCCnBLLCBBCFFLDDBGBDcB9CGGBcBpCHBLlFB3BBBnBhBBmCKBLFBOSB7BFBLFBVbBcBBQDBY4FB9BjDB0CLBJBBCBBJDDfDDBNNBHBLlCBJBBvBBBMaBpCHB0CMBqCGBL1CBJ3CBjBNBLFBKuBuBPJBeCBhBBBXPPBnCBIDDtBCBCDDKHBLFBHDDmBDDHGBLFBtBDBL1HBaGBSqBqBBBBe0CBCOBzBMB8clDBwDGGBJBlGryCBkDMB3iBJB88DEBoS41GB7Bl2BB6RGBgBLLBCByCLLBEBfBBHJBnCJBLIIWEBUvNB7BlGB8CEBaBBarBBsCDB6BGBS-BBGKBIIB3mHoBBhBgDB0D8vIBFIIDkJkJBNBCcBEBBCNBFHBtMjoCBsDEBOCBKGBLBBJ76DB+HCB1NFBYOBSOBvBBBYIB1D7BB3HJBoBBBjGUBnC5DBVLBVLB4CIBamEB2CoCoCDBBCBBDBBFNNCIIiCFFBJJIddFGGCCBI1K1KBlJlJB-V-VBNBGQQBuiBBgBFBH0GBISSBIIDGGBDB-BgBBCvDBuBCBPBBLDBD-JBgBQB7BEBCvOBrB1GBsBDBC-FBgBXXBGBD-GBIFFDQQmGBBRoBBtCDBLDBDwYBlCrCB+BhGBFccDCCBCCLFFCCCBEBCDBCECEDDCBBCICDCCBFFIKFCLLSEBEGGSzBBDtIBtBDBlDLBQBBQQQmBJBvF3BBeMBtBDBKGBDNBH5EB6eCBSCBOCB7GFBNDBCOBNDB5BHBLFBpBHBfBBNDBDNBKmBB5KHBPBBOCBMCB6BCCBCBRBBNDBLGB0EoDoDBjgBBh3pBfB-oEBBv0FBBypHOBvThtCB-QhvBBs6EEBrpIm8yVBCdBhD-DBxHvw-FB', false)),
423
452
  Vai: () => new UnicodeRangeTable(decodeRanges('gopBrJ', true)),
424
453
  Vithkuqi: () => new UnicodeRangeTable(decodeRanges('wrhCKCOCGCBCKCOCGCB', true)),
425
454
  Wancho: () => new UnicodeRangeTable(decodeRanges('g24D5BGA', true)),
@@ -429,22 +458,18 @@ class UnicodeTables {
429
458
  Zanabazar_Square: () => new UnicodeRangeTable(decodeRanges('gwmCnC', true))
430
459
  });
431
460
  static FOLD_CATEGORIES = new LazyMap({
432
- C: () => new UnicodeRangeTable(decodeRanges('z+pBCC', false)),
433
- Cn: () => new UnicodeRangeTable(decodeRanges('z+pBCC', false)),
434
- L: () => new UnicodeRangeTable(decodeRanges('latkpBtkpBCAB', false)),
435
- LC: () => new UnicodeRangeTable(decodeRanges('latkpBtkpBCAB', false)),
436
- Ll: () => new UnicodeRangeTable(decodeRanges('hCZBmDWBCGBiBuBCEECDOCDuBCBECEBBCCCBCCBBBDDBCBBCCBEBBCBBCECBCCDCCBCCBBBCCCBEEIBBCBBCBBCOCDQCDBBCCCBBBC4BCIBBCBBDCCBCBCGC3HrBrBCEEJHHCCBCCCBCCBPBCIBkBJJCUCGDDCBBDyBBxBgBCK2BCBMCD+CCDlBBq6ClBBCGGzW1CB0kCHHBpBBDCBhK0ECKgDCKHBJFBLHBJHBJFBMGCJHBZHBJHBJHBJEBMEBMDBNEBMEBqJEEBHHxC9zC9zCBuBBxBCCBBBDGCBCBCDDJCBCgDCJCCFuqeuqeCqBCUaCoEMCE8BCLECBICFCCDCCEUCBDBCEBCOCBCBCCCBEECKCZs5Vs5VBYBmmBnBBpEjBB9EKBCOBCGBCBBr3ByBB+EVB75CfBhsVfBh1ehBB', false)),
461
+ L: () => new UnicodeRangeTable(decodeRanges('laA', true)),
462
+ LC: () => new UnicodeRangeTable(decodeRanges('laA', true)),
463
+ Ll: () => new UnicodeRangeTable(decodeRanges('hCZBmDWBCGBiBuBCEECDOCDuBCBECEBBCCCBCCBBBDDBCBBCCBEBBCBBCECBCCDCCBCCBBBCCCBEEIBBCBBCBBCOCDQCDBBCCCBBBC4BCIBBCBBDCCBCBCGC3HrBrBCEEJHHCCBCCCBCCBPBCIBkBJJCUCGDDCBBDyBBxBgBCK2BCBMCD+CCDlBBq6ClBBCGGzW1CB0kCHHBpBBDCBhK0ECKgDCKHBJFBLHBJHBJFBMGCJHBZHBJHBJHBJEBMEBMDBNEBMEBqJEEBHHxC9zC9zCBuBBxBCCBBBDGCBCBCDDJCBCgDCJCCFuqeuqeCqBCUaCoEMCE8BCLECBICFCCDCCEUCBDBCEBCOCBCBCCCBQCZs5Vs5VBYBmmBnBBpEjBB9EKBCOBCGBCBBr3ByBB+EVB75CfBhsVfBhCYBoyehBB', false)),
437
464
  Lt: () => new UnicodeRangeTable(decodeRanges('kOCCBCCBCClBCCtsHHBJHBJHBMQQwBAB', false)),
438
- Lu: () => new UnicodeRangeTable(decodeRanges('hDZB7BqBqBBWBCHBCuBCEECDOCDsBCDECBBBDCCDEEGDDECBDDDCCCDFFDEECDDECCGBBCBBCBBCOCBSCDBBCEECkBCEQCJDDBCCFICBEBCBBCCCBEEBCCBCBCEBDCCBDDIDDCBBEFBGLLBnFnFsBCCEEEBBBvBDBCdBCBBECBCWCBDBCGD1BvBBCgBCK0BCDMCBgDCyBlBBq6CqBBDCB5XFBjkCIBCvHvHERRzD0ECGGGC8CCBHBJFBLHBJHBJFBMGCJHBJNBzBBBNSSBPPBEEpL2B2Bs1CvBBCEEBGCHDDLiDCJCCFNNBkBBCGG0oesBCUaCoEMCE8BCLCCDICFFFCBBDSCMOCFCCDEEGECb9a9advCBi8UZBumBnBBpEjBB8EKBCOBCGBCBBk4ByBB+DVB75CfBhsVfBj1ehBB', false)),
465
+ Lu: () => new UnicodeRangeTable(decodeRanges('hDZB7BqBqBBWBCHBCuBCEECDOCDsBCDECBBBDCCDEEGDDECBDDDCCCDFFDEECDDECCGBBCBBCBBCOCBSCDBBCEECkBCEQCJDDBCCFICBEBCBBCCCBEEBCCBCBCEBDCCBDDIDDCBBEFBGLLBnFnFsBCCEEEBBBvBDBCdBCBBECBCWCBDBCGD1BvBBCgBCK0BCDMCBgDCyBlBBq6CqBBDCB5XFBjkCIBCvHvHERRzD0ECGGGC8CCBHBJFBLHBJHBJFBMGCJHBJNBzBBBNSSBPPBEEpL2B2Bs1CvBBCEEBGCHDDLiDCJCCFNNBkBBCGG0oesBCUaCoEMCE8BCLCCDICFFFCBBDSCMOCFCCDOCb9a9advCBi8UZBumBnBBpEjBB8EKBCOBCGBCBBk4ByBB+DVB75CfBhsVfB8BYBvyehBB', false)),
439
466
  M: () => new UnicodeRangeTable(decodeRanges('5cgBgBlgHAB', false)),
440
467
  Mn: () => new UnicodeRangeTable(decodeRanges('5cgBgBlgHAB', false))
441
468
  });
442
469
  static FOLD_SCRIPT = new LazyMap({
443
470
  Common: () => new UnicodeRangeTable(decodeRanges('8cgBgB', false)),
444
471
  Greek: () => new UnicodeRangeTable(decodeRanges('1FwUwU', false)),
445
- Inherited: () => new UnicodeRangeTable(decodeRanges('5cgBgBlgHAB', false)),
446
- Latin: () => new UnicodeRangeTable(decodeRanges('y+pBCC', false)),
447
- Unknown: () => new UnicodeRangeTable(decodeRanges('z+pBCC', false))
472
+ Inherited: () => new UnicodeRangeTable(decodeRanges('5cgBgBlgHAB', false))
448
473
  });
449
474
  }
450
475
 
@@ -573,11 +598,16 @@ class Unicode {
573
598
  // to compare it to |r2|.
574
599
  // -1 is interpreted as the end-of-file mark.
575
600
  static equalsIgnoreCase(r1, r2) {
576
- // Runes already match, or one of them is EOF
577
- if (r1 < 0 || r2 < 0 || r1 === r2) {
601
+ // Runes already match
602
+ if (r1 === r2) {
578
603
  return true;
579
604
  }
580
605
 
606
+ // Safely fail if either is EOF (and they didn't explicitly match above)
607
+ if (r1 < 0 || r2 < 0) {
608
+ return false;
609
+ }
610
+
581
611
  // Fast path for the common case where both runes are ASCII characters.
582
612
  // Coerces both runes to lowercase if applicable.
583
613
  if (r1 <= this.MAX_ASCII && r2 <= this.MAX_ASCII) {
@@ -830,7 +860,7 @@ class Utils {
830
860
  // Encoding[(Encoding['UTF_16'] = 0)] = 'UTF_16'
831
861
  // Encoding[(Encoding['UTF_8'] = 1)] = 'UTF_8'
832
862
  const createEnum = (values = [], initNum = 0) => {
833
- const enumObject = {};
863
+ const enumObject = Object.create(null);
834
864
  for (let i = 0; i < values.length; i++) {
835
865
  const val = values[i];
836
866
  const keyVal = initNum + i;
@@ -972,6 +1002,9 @@ class MachineInputBase {
972
1002
  hasString() {
973
1003
  return false;
974
1004
  }
1005
+ hasAnyString() {
1006
+ return false;
1007
+ }
975
1008
 
976
1009
  // Helper for the exact-literal fast-path execution router
977
1010
  prefixLength() {
@@ -997,6 +1030,13 @@ class MachineUTF8Input extends MachineInputBase {
997
1030
  return idx !== -1 && idx <= this.end - target.length;
998
1031
  }
999
1032
 
1033
+ // Executes a high-speed, single - pass search for multiple literal strings
1034
+ // simultaneously using an Aho-Corasick automaton.
1035
+ hasAnyString(prefilter, pos) {
1036
+ if (!prefilter.ac8) return false;
1037
+ return prefilter.ac8.searchUTF8(this.bytes, this.start + pos, this.end);
1038
+ }
1039
+
1000
1040
  // Returns the rune at the specified index; the units are
1001
1041
  // unspecified, but could be UTF-8 byte, UTF-16 char, or rune
1002
1042
  // indices. Returns the width (in the same units) of the rune in
@@ -1015,17 +1055,23 @@ class MachineUTF8Input extends MachineInputBase {
1015
1055
  return c << 3 | 1;
1016
1056
  } else if (c >= 0xc2 && c <= 0xdf && pos + 1 < this.end) {
1017
1057
  const c1 = this.bytes[pos + 1] & 0xff;
1058
+ if ((c1 & 0xc0) !== 0x80) return c << 3 | 1;
1018
1059
  const rune = (c & 0x1f) << 6 | c1 & 0x3f;
1019
1060
  return rune << 3 | 2;
1020
1061
  } else if (c >= 0xe0 && c <= 0xef && pos + 2 < this.end) {
1021
1062
  const c1 = this.bytes[pos + 1] & 0xff;
1063
+ if ((c1 & 0xc0) !== 0x80) return c << 3 | 1;
1022
1064
  const c2 = this.bytes[pos + 2] & 0xff;
1065
+ if ((c2 & 0xc0) !== 0x80) return c << 3 | 1;
1023
1066
  const rune = (c & 0x0f) << 12 | (c1 & 0x3f) << 6 | c2 & 0x3f;
1024
1067
  return rune << 3 | 3;
1025
1068
  } else if (c >= 0xf0 && c <= 0xf4 && pos + 3 < this.end) {
1026
1069
  const c1 = this.bytes[pos + 1] & 0xff;
1070
+ if ((c1 & 0xc0) !== 0x80) return c << 3 | 1;
1027
1071
  const c2 = this.bytes[pos + 2] & 0xff;
1072
+ if ((c2 & 0xc0) !== 0x80) return c << 3 | 1;
1028
1073
  const c3 = this.bytes[pos + 3] & 0xff;
1074
+ if ((c3 & 0xc0) !== 0x80) return c << 3 | 1;
1029
1075
  const rune = (c & 0x07) << 18 | (c1 & 0x3f) << 12 | (c2 & 0x3f) << 6 | c3 & 0x3f;
1030
1076
  return rune << 3 | 4;
1031
1077
  } else {
@@ -1104,6 +1150,13 @@ class MachineUTF16Input extends MachineInputBase {
1104
1150
  return idx !== -1 && idx <= this.end - prefilter.str.length;
1105
1151
  }
1106
1152
 
1153
+ // Executes a high-speed, single - pass search for multiple literal strings
1154
+ // simultaneously using an Aho-Corasick automaton.
1155
+ hasAnyString(prefilter, pos) {
1156
+ if (!prefilter.ac16) return false;
1157
+ return prefilter.ac16.searchUTF16(this.charSequence, this.start + pos, this.end);
1158
+ }
1159
+
1107
1160
  // Returns the rune at the specified index; the units are
1108
1161
  // unspecified, but could be UTF-8 byte, UTF-16 char, or rune
1109
1162
  // indices. Returns the width (in the same units) of the rune in
@@ -1549,7 +1602,15 @@ class Matcher {
1549
1602
  if (this.hasMatch) {
1550
1603
  start = this.groups[1];
1551
1604
  if (this.groups[0] === this.groups[1]) {
1552
- start++;
1605
+ // Safely calculate structural encoding width to avoid sequence corruption
1606
+ const machineInput = this.matcherInput.isUTF16Encoding() ? MachineInput.fromUTF16(this.matcherInput.asCharSequence(), 0, this.matcherInputLength) : MachineInput.fromUTF8(this.matcherInput.asBytes(), 0, this.matcherInputLength);
1607
+ const r = machineInput.step(start);
1608
+ if (r < 0) {
1609
+ // EOF
1610
+ start++; // Advance past length to force loop exit
1611
+ } else {
1612
+ start += r & 7; // Advance by safely decoded width
1613
+ }
1553
1614
  }
1554
1615
  }
1555
1616
  return this.genMatch(start, RE2Flags.UNANCHORED);
@@ -1563,14 +1624,16 @@ class Matcher {
1563
1624
  * @private
1564
1625
  */
1565
1626
  genMatch(startByte, anchor) {
1566
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
1627
+ const hasLookbehinds = this.patternInput.re2().prog.numLb > 0;
1628
+ const ngroup = hasLookbehinds ? 1 + this.patternGroupCount : 1;
1629
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, ngroup);
1567
1630
  const ok = res[0];
1568
1631
  if (!ok) {
1569
1632
  return false;
1570
1633
  }
1571
1634
  this.groups = res[1];
1572
1635
  this.hasMatch = true;
1573
- this.hasGroups = false;
1636
+ this.hasGroups = hasLookbehinds || this.patternGroupCount === 0;
1574
1637
  this.anchorFlag = anchor;
1575
1638
  return true;
1576
1639
  }
@@ -1686,6 +1749,8 @@ class Matcher {
1686
1749
  const groupName = replacement.substring(i + 1, j);
1687
1750
  res += this.group(groupName);
1688
1751
  last = j + 1;
1752
+ i = j;
1753
+ continue;
1689
1754
  }
1690
1755
  }
1691
1756
  }
@@ -1765,6 +1830,7 @@ class Matcher {
1765
1830
  if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get('>')) {
1766
1831
  res += replacement.substring(i - 1, j + 1);
1767
1832
  last = j + 1;
1833
+ i = j;
1768
1834
  continue;
1769
1835
  }
1770
1836
  const groupName = replacement.substring(i + 1, j);
@@ -1774,6 +1840,8 @@ class Matcher {
1774
1840
  res += `$<${groupName}>`;
1775
1841
  }
1776
1842
  last = j + 1;
1843
+ i = j;
1844
+ continue;
1777
1845
  }
1778
1846
  }
1779
1847
  }
@@ -1857,6 +1925,8 @@ class Inst {
1857
1925
  static RUNE1 = 9;
1858
1926
  static RUNE_ANY = 10;
1859
1927
  static RUNE_ANY_NOT_NL = 11;
1928
+ static LB_WRITE = 12;
1929
+ static LB_CHECK = 13;
1860
1930
  static isRuneOp(op) {
1861
1931
  return Inst.RUNE <= op && op <= Inst.RUNE_ANY_NOT_NL;
1862
1932
  }
@@ -1896,6 +1966,8 @@ class Inst {
1896
1966
  return r === r0;
1897
1967
  }
1898
1968
  const len = this.runes.length;
1969
+ if (len === 0) return false;
1970
+
1899
1971
  // If the array is exactly 2, 4, 6, or 8 items, DO NOT fall through to binary search
1900
1972
  if (len === 2 || len === 4 || len === 6 || len === 8) {
1901
1973
  for (let j = 0; j < len; j += 2) {
@@ -1909,22 +1981,19 @@ class Inst {
1909
1981
  return false; // Stop here
1910
1982
  }
1911
1983
 
1912
- // Otherwise binary search.
1913
- let lo = 0;
1914
- let hi = this.runes.length / 2 | 0;
1915
- while (lo < hi) {
1916
- const m = lo + hi >> 1; // native cpu instruction for "lo + (((hi - lo) / 2) | 0)"
1917
- const c = this.runes[2 * m];
1918
- if (c <= r) {
1919
- if (r <= this.runes[2 * m + 1]) {
1920
- return true;
1921
- }
1922
- lo = m + 1;
1923
- } else {
1924
- hi = m;
1925
- }
1984
+ // Branchless Binary Search (Lower Bound)
1985
+ // Compiles to optimal conditional move (cmov) machine code, preventing
1986
+ // branch mispredictions on large, chaotic Unicode arrays
1987
+ let base = 0;
1988
+ let n = len >> 1;
1989
+ while (n > 1) {
1990
+ const half = n >> 1;
1991
+ base += this.runes[base + half << 1] <= r ? half : 0;
1992
+ n -= half;
1926
1993
  }
1927
- return false;
1994
+ base += this.runes[base << 1] <= r ? 1 : 0;
1995
+ const m = base - 1;
1996
+ return m >= 0 && r <= this.runes[m << 1 | 1];
1928
1997
  }
1929
1998
 
1930
1999
  // matchRunePos checks whether the instruction matches (and consumes) r.
@@ -1939,6 +2008,7 @@ class Inst {
1939
2008
  return r === r0 ? 0 : -1;
1940
2009
  }
1941
2010
  const len = this.runes.length;
2011
+ if (len === 0) return -1;
1942
2012
  if (len === 2 || len === 4 || len === 6 || len === 8) {
1943
2013
  for (let j = 0; j < len; j += 2) {
1944
2014
  if (r < this.runes[j]) return -1;
@@ -1946,19 +2016,18 @@ class Inst {
1946
2016
  }
1947
2017
  return -1;
1948
2018
  }
1949
- let lo = 0;
1950
- let hi = Math.floor(len / 2);
1951
- while (lo < hi) {
1952
- const m = lo + hi >> 1;
1953
- const c = this.runes[2 * m];
1954
- if (c <= r) {
1955
- if (r <= this.runes[2 * m + 1]) return m;
1956
- lo = m + 1;
1957
- } else {
1958
- hi = m;
1959
- }
2019
+
2020
+ // Branchless Binary Search (Lower Bound)
2021
+ let base = 0;
2022
+ let n = len >> 1;
2023
+ while (n > 1) {
2024
+ const half = n >> 1;
2025
+ base += this.runes[base + half << 1] <= r ? half : 0;
2026
+ n -= half;
1960
2027
  }
1961
- return -1;
2028
+ base += this.runes[base << 1] <= r ? 1 : 0;
2029
+ const m = base - 1;
2030
+ return m >= 0 && r <= this.runes[m << 1 | 1] ? m : -1;
1962
2031
  }
1963
2032
  /**
1964
2033
  *
@@ -1980,6 +2049,10 @@ class Inst {
1980
2049
  return 'fail';
1981
2050
  case Inst.NOP:
1982
2051
  return `nop -> ${this.out}`;
2052
+ case Inst.LB_WRITE:
2053
+ return `lbwrite ${this.lb} -> ${this.out}`;
2054
+ case Inst.LB_CHECK:
2055
+ return `lbcheck ${this.lb} -> ${this.out}, ${this.arg}`;
1983
2056
  case Inst.RUNE:
1984
2057
  if (this.runes === null) {
1985
2058
  return 'rune <null>';
@@ -2053,6 +2126,7 @@ class Queue {
2053
2126
  //
2054
2127
  // Called by RE2.doExecute.
2055
2128
  class Machine {
2129
+ static THREADS_CHUNK_SIZE = 128;
2056
2130
  static fromRE2(re2) {
2057
2131
  const m = new Machine();
2058
2132
  m.prog = re2.prog;
@@ -2079,21 +2153,29 @@ class Machine {
2079
2153
  } else {
2080
2154
  this.resetCap();
2081
2155
  }
2156
+
2157
+ // Initialize the Lookbehind tracking table
2158
+ if (this.prog.numLb > 0) {
2159
+ if (!this.lbTable || this.lbTable.length < this.prog.numLb + 1) {
2160
+ this.lbTable = new Int32Array(this.prog.numLb + 1);
2161
+ }
2162
+ this.lbTable.fill(-1);
2163
+ }
2082
2164
  }
2083
2165
 
2084
2166
  // Wipes existing typed array memory without reallocating
2085
2167
  resetCap() {
2086
2168
  for (let i = 0; i < this.poolSize; i++) {
2087
2169
  const t = this.pool[i];
2088
- t.cap.fill(0);
2170
+ t.cap.fill(-1);
2089
2171
  }
2090
2172
  }
2091
2173
  initNewCap(ncap) {
2092
2174
  for (let i = 0; i < this.poolSize; i++) {
2093
2175
  const t = this.pool[i];
2094
- t.cap = new Int32Array(ncap);
2176
+ t.cap = new Int32Array(ncap).fill(-1);
2095
2177
  }
2096
- this.matchcap = new Int32Array(ncap);
2178
+ this.matchcap = new Int32Array(ncap).fill(-1);
2097
2179
  }
2098
2180
  submatches() {
2099
2181
  if (this.ncap === 0) {
@@ -2106,14 +2188,21 @@ class Machine {
2106
2188
  // alloc() allocates a new thread with the given instruction.
2107
2189
  // It uses the free pool if possible.
2108
2190
  alloc(inst) {
2109
- let t;
2110
- if (this.poolSize > 0) {
2111
- this.poolSize--;
2112
- t = this.pool[this.poolSize];
2113
- } else {
2114
- t = new Thread();
2115
- t.cap = new Int32Array(this.matchcap.length);
2191
+ if (this.poolSize === 0) {
2192
+ const capLen = this.matchcap.length;
2193
+
2194
+ // Bulk allocate threads in a tight loop so the V8 engine
2195
+ // places them adjacently in the young generation heap
2196
+ for (let i = 0; i < Machine.THREADS_CHUNK_SIZE; i++) {
2197
+ const t = new Thread();
2198
+ t.cap = new Int32Array(capLen);
2199
+ this.pool[this.poolSize++] = t;
2200
+ }
2116
2201
  }
2202
+
2203
+ // Pop a thread from the top of the pool stack
2204
+ this.poolSize--;
2205
+ const t = this.pool[this.poolSize];
2117
2206
  t.inst = inst;
2118
2207
  return t;
2119
2208
  }
@@ -2166,10 +2255,16 @@ class Machine {
2166
2255
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && pos !== 0) {
2167
2256
  break;
2168
2257
  }
2258
+ if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) {
2259
+ break;
2260
+ }
2169
2261
  if (this.matched) {
2170
2262
  break;
2171
2263
  }
2172
- if (!(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
2264
+ // Disable Prefix Acceleration if the regex contains lookbehinds
2265
+ // Fast-forwarding the string pointer will skip over the positions where
2266
+ // the parallel lookbehind automata need to be spawned.
2267
+ if (this.prog.numLb === 0 && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
2173
2268
  const advance = input.index(this.re2, pos);
2174
2269
  if (advance < 0) {
2175
2270
  break;
@@ -2187,6 +2282,10 @@ class Machine {
2187
2282
  if (this.ncap > 0) {
2188
2283
  this.matchcap[0] = pos;
2189
2284
  }
2285
+ // Spawn Lookbehind threads BEFORE the main pattern
2286
+ for (let i = 0; i < this.prog.lbStarts.length; i++) {
2287
+ this.add(runq, this.prog.lbStarts[i], pos, this.matchcap, flag, null);
2288
+ }
2190
2289
  this.add(runq, this.prog.start, pos, this.matchcap, flag, null);
2191
2290
  }
2192
2291
  const nextPos = pos + width;
@@ -2236,8 +2335,15 @@ class Machine {
2236
2335
  while (true) {
2237
2336
  if (runq.isEmpty()) {
2238
2337
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && pos !== 0) break;
2338
+ if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) {
2339
+ break;
2340
+ }
2239
2341
  }
2240
2342
  if (pos === 0 || anchor === RE2Flags.UNANCHORED) {
2343
+ // Spawn Lookbehind threads BEFORE the main pattern
2344
+ for (let i = 0; i < this.prog.lbStarts.length; i++) {
2345
+ this.add(runq, this.prog.lbStarts[i], pos, this.matchcap, flag, null);
2346
+ }
2241
2347
  this.add(runq, this.prog.start, pos, this.matchcap, flag, null);
2242
2348
  }
2243
2349
  const nextPos = pos + width;
@@ -2347,63 +2453,83 @@ class Machine {
2347
2453
  runq.clear();
2348
2454
  }
2349
2455
  add(q, pc, pos, cap, cond, t) {
2350
- if (pc === 0) {
2351
- return t;
2352
- }
2353
- if (q.contains(pc)) {
2354
- return t;
2355
- }
2356
- const d = q.add(pc);
2357
- const inst = this.prog.inst[pc];
2358
- switch (inst.op) {
2359
- case Inst.FAIL:
2360
- break;
2361
- case Inst.ALT:
2362
- case Inst.ALT_MATCH:
2363
- t = this.add(q, inst.out, pos, cap, cond, t);
2364
- t = this.add(q, inst.arg, pos, cap, cond, t);
2365
- break;
2366
- case Inst.EMPTY_WIDTH:
2367
- if ((inst.arg & ~cond) === 0) {
2368
- t = this.add(q, inst.out, pos, cap, cond, t);
2369
- }
2370
- break;
2371
- case Inst.NOP:
2372
- t = this.add(q, inst.out, pos, cap, cond, t);
2373
- break;
2374
- case Inst.CAPTURE:
2375
- if (inst.arg < this.ncap) {
2376
- const opos = cap[inst.arg];
2377
- cap[inst.arg] = pos;
2378
- this.add(q, inst.out, pos, cap, cond, null);
2379
- cap[inst.arg] = opos;
2380
- } else {
2456
+ while (true) {
2457
+ if (pc === 0) {
2458
+ return t;
2459
+ }
2460
+ if (q.contains(pc)) {
2461
+ return t;
2462
+ }
2463
+ const d = q.add(pc);
2464
+ const inst = this.prog.inst[pc];
2465
+ switch (inst.op) {
2466
+ case Inst.FAIL:
2467
+ return t;
2468
+ case Inst.ALT:
2469
+ case Inst.ALT_MATCH:
2381
2470
  t = this.add(q, inst.out, pos, cap, cond, t);
2382
- }
2383
- break;
2384
- case Inst.MATCH:
2385
- case Inst.RUNE:
2386
- case Inst.RUNE1:
2387
- case Inst.RUNE_ANY:
2388
- case Inst.RUNE_ANY_NOT_NL:
2389
- if (t === null) {
2390
- t = this.alloc(inst);
2391
- } else {
2392
- t.inst = inst;
2393
- }
2394
- if (this.ncap > 0 && t.cap !== cap) {
2395
- // Direct assignment utilizing Typed Array performance
2396
- for (let c = 0; c < this.ncap; c++) {
2397
- t.cap[c] = cap[c];
2471
+ pc = inst.arg; // Flattened tail recursion
2472
+ continue;
2473
+ case Inst.EMPTY_WIDTH:
2474
+ if ((inst.arg & ~cond) === 0) {
2475
+ pc = inst.out; // Flattened tail recursion
2476
+ continue;
2398
2477
  }
2399
- }
2400
- q.denseThreads[d] = t;
2401
- t = null;
2402
- break;
2403
- default:
2404
- throw new Error('unhandled');
2478
+ return t;
2479
+ case Inst.NOP:
2480
+ pc = inst.out; // Flattened tail recursion
2481
+ continue;
2482
+ case Inst.CAPTURE:
2483
+ if (inst.arg < this.ncap) {
2484
+ const opos = cap[inst.arg];
2485
+ cap[inst.arg] = pos;
2486
+ this.add(q, inst.out, pos, cap, cond, null);
2487
+ cap[inst.arg] = opos;
2488
+ return t;
2489
+ } else {
2490
+ pc = inst.out; // Flattened tail recursion
2491
+ continue;
2492
+ }
2493
+ case Inst.LB_WRITE:
2494
+ this.lbTable[Math.abs(inst.lb)] = pos;
2495
+ pc = inst.out;
2496
+ continue;
2497
+ case Inst.LB_CHECK:
2498
+ if (inst.lb > 0) {
2499
+ // Positive Lookbehind
2500
+ if (this.lbTable[inst.lb] === pos) {
2501
+ pc = inst.out; // Flattened tail recursion
2502
+ continue;
2503
+ }
2504
+ } else if (this.lbTable[-inst.lb] !== pos) {
2505
+ // Negative Lookbehind
2506
+ pc = inst.out; // Flattened tail recursion
2507
+ continue;
2508
+ }
2509
+ return t;
2510
+ case Inst.MATCH:
2511
+ case Inst.RUNE:
2512
+ case Inst.RUNE1:
2513
+ case Inst.RUNE_ANY:
2514
+ case Inst.RUNE_ANY_NOT_NL:
2515
+ if (t === null) {
2516
+ t = this.alloc(inst);
2517
+ } else {
2518
+ t.inst = inst;
2519
+ }
2520
+ if (this.ncap > 0 && t.cap !== cap) {
2521
+ // Direct assignment utilizing Typed Array performance
2522
+ for (let c = 0; c < this.ncap; c++) {
2523
+ t.cap[c] = cap[c];
2524
+ }
2525
+ }
2526
+ q.denseThreads[d] = t;
2527
+ t = null;
2528
+ return t;
2529
+ default:
2530
+ throw new Error('unhandled');
2531
+ }
2405
2532
  }
2406
- return t;
2407
2533
  }
2408
2534
  }
2409
2535
 
@@ -2431,8 +2557,15 @@ class DFAState {
2431
2557
  this.nfaStates = nfaStates; // Int32Array of Instruction PCs
2432
2558
  this.isMatch = isMatch; // Boolean
2433
2559
  this.matchIDs = matchIDs; // Array of integers indicating which Set patterns matched
2434
- this.nextAscii = new Array(Unicode.MAX_ASCII + 1).fill(null); // Flat array for blisteringly fast ASCII lookups
2435
- this.nextMap = new Map(); // Cache of Char -> DFAState
2560
+
2561
+ // Latin-1 (Unicode.MAX_LATIN1 + 1) flat arrays for blisteringly fast O(1) lookups
2562
+ // completely covering standard English, European languages, and 1-byte encodings.
2563
+ this.nextLatin1 = new Array(Unicode.MAX_LATIN1 + 1).fill(null); // Flat array for blisteringly fast ASCII lookups
2564
+ this.nextLatin1Anchored = new Array(Unicode.MAX_LATIN1 + 1).fill(null); // Flat array for blisteringly fast ASCII lookups
2565
+ // 2 arrays used as hash map for V8 optimization (N is small number, so O(n) faster than Map O(1))
2566
+ this.transKeys = [];
2567
+ this.transVals = [];
2568
+ this.lastSeen = 0; // Track when this state was last used for LRU eviction
2436
2569
  }
2437
2570
  }
2438
2571
  class DFA {
@@ -2445,6 +2578,7 @@ class DFA {
2445
2578
  this.stateLimit = 10000; // Prevent memory explosion (ReDoS protection)
2446
2579
  this.cacheClears = 0; // Track thrashing
2447
2580
  this.failed = false; // mark if DFA cannot work with provided prog
2581
+ this.clock = 0; // Global clock for LRU eviction
2448
2582
  }
2449
2583
 
2450
2584
  // Follows epsilon (empty) transitions to find all reachable states without consuming a char
@@ -2475,6 +2609,8 @@ class DFA {
2475
2609
  // Bailing out on complex empty-width assertions to keep DFA fast.
2476
2610
  // Engine will seamlessly fall back to the NFA.
2477
2611
  case Inst.EMPTY_WIDTH:
2612
+ case Inst.LB_WRITE:
2613
+ case Inst.LB_CHECK:
2478
2614
  return null;
2479
2615
  }
2480
2616
  }
@@ -2502,6 +2638,7 @@ class DFA {
2502
2638
  for (let i = 0; i < bucket.length; i++) {
2503
2639
  const state = bucket[i];
2504
2640
  if (arraysEqual(state.nfaStates, sortedPCs)) {
2641
+ state.lastSeen = ++this.clock;
2505
2642
  return state;
2506
2643
  }
2507
2644
  }
@@ -2514,40 +2651,99 @@ class DFA {
2514
2651
  if (this.failed) return null;
2515
2652
 
2516
2653
  // Safety: prevent memory exhaustion from state explosion
2517
- // We flush the cache and return null, which seamlessly routes execution to the NFA
2654
+ // We prune the cache to keep the newest 50%
2518
2655
  if (this.stateCount >= this.stateLimit) {
2519
- this.stateCache.clear();
2520
- this.stateCount = 0;
2521
- this.startState = null;
2522
2656
  this.cacheClears++;
2523
2657
 
2524
2658
  // If this regex causes continuous cache thrashing, permanently fall back to NFA
2525
2659
  // to avoid spending CPU cycles constantly rebuilding the DFA tree.
2526
2660
  if (this.cacheClears >= DFA.MAX_CACHE_CLEARS) {
2527
2661
  this.failed = true;
2662
+ this.stateCache.clear();
2663
+ this.stateCount = 0;
2664
+ this.startState = null;
2665
+ return null;
2666
+ }
2667
+ this.evictCache();
2668
+
2669
+ // After eviction, the bucket reference might be stale or empty.
2670
+ // We must re-fetch or re-create the bucket.
2671
+ bucket = this.stateCache.get(hash);
2672
+ if (!bucket) {
2673
+ bucket = [];
2674
+ this.stateCache.set(hash, bucket);
2528
2675
  }
2529
- return null;
2530
2676
  }
2531
2677
 
2532
2678
  // State not found, create it and add to bucket
2533
2679
  const state = new DFAState(sortedPCs, closureResult.isMatch, closureResult.matchIDs);
2680
+ state.lastSeen = ++this.clock;
2534
2681
  bucket.push(state);
2535
2682
  this.stateCount++;
2536
2683
  return state;
2537
2684
  }
2685
+ evictCache() {
2686
+ const allStates = [];
2687
+ for (const bucket of this.stateCache.values()) {
2688
+ for (let i = 0; i < bucket.length; i++) {
2689
+ allStates.push(bucket[i]);
2690
+ }
2691
+ }
2692
+
2693
+ // Sort ascending by lastSeen (oldest first)
2694
+ allStates.sort((a, b) => a.lastSeen - b.lastSeen);
2695
+
2696
+ // Keep the newest 50%
2697
+ const keepCount = Math.max(1, Math.floor(this.stateLimit / 2));
2698
+ const startIndex = allStates.length - keepCount;
2699
+ const survivorsArray = allStates.slice(startIndex);
2700
+ const survivors = new Set(survivorsArray);
2701
+ this.stateCache.clear();
2702
+ this.stateCount = 0;
2703
+ for (let i = 0; i < survivorsArray.length; i++) {
2704
+ const state = survivorsArray[i];
2705
+
2706
+ // Sever ties to all states to prevent memory leaks and dangling pointers
2707
+ state.nextLatin1.fill(null);
2708
+ state.nextLatin1Anchored.fill(null);
2709
+ // zero-allocation cleanup
2710
+ state.transKeys.length = 0;
2711
+ state.transVals.length = 0;
2712
+ const hash = hashPCs(state.nfaStates);
2713
+ let bucket = this.stateCache.get(hash);
2714
+ if (!bucket) {
2715
+ bucket = [];
2716
+ this.stateCache.set(hash, bucket);
2717
+ }
2718
+ bucket.push(state);
2719
+ this.stateCount++;
2720
+ }
2721
+
2722
+ // Start state must either be preserved or nullified so it gets re-created
2723
+ if (this.startState && !survivors.has(this.startState)) {
2724
+ this.startState = null;
2725
+ }
2726
+ }
2538
2727
 
2539
2728
  // Compute the next DFA state given a current state and a character
2540
2729
  step(state, charCode, anchor) {
2541
- // OPTIMIZATION: ASCII Fast-Path
2542
- if (anchor === RE2Flags.UNANCHORED && charCode <= Unicode.MAX_ASCII) {
2543
- const next = state.nextAscii[charCode];
2544
- if (next !== null) {
2545
- return next;
2730
+ // OPTIMIZATION: Latin-1 Array Fast-Path
2731
+ if (charCode <= Unicode.MAX_LATIN1) {
2732
+ if (anchor === RE2Flags.UNANCHORED) {
2733
+ const next = state.nextLatin1[charCode];
2734
+ if (next !== null) return next;
2735
+ } else {
2736
+ const next = state.nextLatin1Anchored[charCode];
2737
+ if (next !== null) return next;
2546
2738
  }
2547
2739
  } else {
2740
+ // Dense Array Linear Search fallback for Runes > 255
2548
2741
  const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
2549
- if (state.nextMap.has(key)) {
2550
- return state.nextMap.get(key);
2742
+ // get [key] -> nextState
2743
+ const keys = state.transKeys;
2744
+ const len = keys.length;
2745
+ for (let i = 0; i < len; i++) {
2746
+ if (keys[i] === key) return state.transVals[i];
2551
2747
  }
2552
2748
  }
2553
2749
  const nextPCs = [];
@@ -2564,11 +2760,17 @@ class DFA {
2564
2760
  const nextState = this.getState(nextPCs);
2565
2761
 
2566
2762
  // Cache the result
2567
- if (anchor === RE2Flags.UNANCHORED && charCode <= Unicode.MAX_ASCII) {
2568
- state.nextAscii[charCode] = nextState;
2763
+ if (charCode <= Unicode.MAX_LATIN1) {
2764
+ if (anchor === RE2Flags.UNANCHORED) {
2765
+ state.nextLatin1[charCode] = nextState;
2766
+ } else {
2767
+ state.nextLatin1Anchored[charCode] = nextState;
2768
+ }
2569
2769
  } else {
2570
2770
  const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
2571
- state.nextMap.set(key, nextState);
2771
+ // store key -> nextState
2772
+ state.transKeys.push(key);
2773
+ state.transVals.push(nextState);
2572
2774
  }
2573
2775
  return nextState;
2574
2776
  }
@@ -2601,10 +2803,11 @@ class DFA {
2601
2803
  if (width === 0) {
2602
2804
  break;
2603
2805
  }
2604
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_ASCII && currentState.nextAscii[rune] || this.step(currentState, rune, anchor);
2806
+ currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
2605
2807
 
2606
2808
  // If we hit an unrecoverable DFA error or bailout, signal fallback
2607
2809
  if (currentState === null) return null;
2810
+ currentState.lastSeen = ++this.clock;
2608
2811
  if (currentState.isMatch) {
2609
2812
  if (anchor === RE2Flags.ANCHOR_BOTH) {
2610
2813
  if (i + width === endPos) return true;
@@ -2652,9 +2855,10 @@ class DFA {
2652
2855
  const rune = r >> 3;
2653
2856
  const width = r & 7;
2654
2857
  if (width === 0) break;
2655
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_ASCII && currentState.nextAscii[rune] || this.step(currentState, rune, anchor);
2858
+ currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
2656
2859
  if (currentState === null) return null; // Bailout to NFA
2657
2860
 
2861
+ currentState.lastSeen = ++this.clock;
2658
2862
  i += width;
2659
2863
  checkMatch(currentState, i);
2660
2864
  if (currentState.nfaStates.length === 0) {
@@ -2692,7 +2896,7 @@ class BitState {
2692
2896
  // Bitwise shift (>>> 5) instead of Math.floor( / 32)
2693
2897
  const visitedSize = prog.numInst() * (end + 1) + VISITED_BITS - 1 >>> 5;
2694
2898
  if (this.visited.length < visitedSize) {
2695
- this.visited = new Uint32Array(Math.floor(MAX_BACKTRACK_VECTOR / VISITED_BITS));
2899
+ this.visited = new Uint32Array(visitedSize);
2696
2900
  } else {
2697
2901
  this.visited.fill(0, 0, visitedSize);
2698
2902
  }
@@ -2778,11 +2982,12 @@ class BitState {
2778
2982
  const outInst = re2.prog.getInst(inst.out);
2779
2983
  if (Inst.isRuneOp(outInst.op)) {
2780
2984
  this.push(re2, inst.arg, currentPos, false);
2781
- currentPc = inst.out;
2985
+ currentPc = inst.arg;
2986
+ currentPos = this.end;
2782
2987
  continue;
2783
2988
  }
2784
2989
  this.push(re2, inst.out, this.end, false);
2785
- currentPc = inst.arg;
2990
+ currentPc = inst.out;
2786
2991
  continue;
2787
2992
  }
2788
2993
  case Inst.RUNE:
@@ -2863,6 +3068,11 @@ class BitState {
2863
3068
  if (currentPos === this.end) return true;
2864
3069
  break;
2865
3070
  }
3071
+ case Inst.LB_WRITE:
3072
+ case Inst.LB_CHECK:
3073
+ {
3074
+ throw new RE2JSInternalException('Backtracker cannot evaluate Lookbehind instructions');
3075
+ }
2866
3076
  default:
2867
3077
  {
2868
3078
  throw new RE2JSInternalException('bad inst');
@@ -3220,6 +3430,8 @@ const cleanupOnePass = (p, original) => {
3220
3430
  class OnePass {
3221
3431
  static compile(prog) {
3222
3432
  if (prog.start === 0) return null;
3433
+ // OnePass cannot evaluate Lookbehinds
3434
+ if (prog.numLb > 0) return null;
3223
3435
  const startInst = prog.inst[prog.start];
3224
3436
  // onepass regexps must be strictly anchored
3225
3437
  if (startInst.op !== Inst.EMPTY_WIDTH || (startInst.arg & Utils.EMPTY_BEGIN_TEXT) === 0) {
@@ -3297,6 +3509,10 @@ class OnePass {
3297
3509
  switch (inst.op) {
3298
3510
  case Inst.MATCH:
3299
3511
  {
3512
+ // Verify ANCHOR_BOTH constraint before accepting the match
3513
+ if (anchor === RE2Flags.ANCHOR_BOTH && pos !== input.endPos()) {
3514
+ return null;
3515
+ }
3300
3516
  matched = true;
3301
3517
  if (matchcap.length > 0) {
3302
3518
  matchcap[0] = 0;
@@ -3399,6 +3615,10 @@ class Regexp {
3399
3615
  // Matches concatenation of subs[]
3400
3616
  'ALTERNATE',
3401
3617
  // Matches union of subs[]
3618
+ 'PLB',
3619
+ // Positive LookBehind
3620
+ 'NLB',
3621
+ // Negative LookBehind
3402
3622
  // Pseudo ops, used internally by Parser for parsing stack:
3403
3623
  'LEFT_PAREN', 'VERTICAL_BAR']);
3404
3624
  static isPseudoOp(op) {
@@ -3423,6 +3643,7 @@ class Regexp {
3423
3643
  regex.max = re.max;
3424
3644
  regex.name = re.name;
3425
3645
  regex.namedGroups = re.namedGroups;
3646
+ regex.lb = re.lb; // Track lookbehind index
3426
3647
  return regex;
3427
3648
  }
3428
3649
  constructor(op) {
@@ -3437,6 +3658,7 @@ class Regexp {
3437
3658
  this.cap = 0; // capturing index, for CAPTURE
3438
3659
  this.name = null; // capturing name, for CAPTURE
3439
3660
  this.namedGroups = Object.create(null); // map of group name -> capturing index
3661
+ this.lb = 0; // Lookbehind index tracking
3440
3662
  }
3441
3663
  reinit() {
3442
3664
  this.flags = 0;
@@ -3447,6 +3669,7 @@ class Regexp {
3447
3669
  this.max = 0;
3448
3670
  this.name = null;
3449
3671
  this.namedGroups = Object.create(null);
3672
+ this.lb = 0;
3450
3673
  }
3451
3674
  toString() {
3452
3675
  return this.appendTo();
@@ -3537,6 +3760,12 @@ class Regexp {
3537
3760
  case Regexp.Op.ANY_CHAR:
3538
3761
  out += '(?s:.)';
3539
3762
  break;
3763
+ case Regexp.Op.PLB:
3764
+ out += `(?<=${this.subs[0].appendTo()})`;
3765
+ break;
3766
+ case Regexp.Op.NLB:
3767
+ out += `(?<!${this.subs[0].appendTo()})`;
3768
+ break;
3540
3769
  case Regexp.Op.CAPTURE:
3541
3770
  if (this.name === null || this.name.length === 0) {
3542
3771
  out += '(';
@@ -3701,11 +3930,101 @@ class Regexp {
3701
3930
  }
3702
3931
  break;
3703
3932
  }
3933
+ case Regexp.Op.PLB:
3934
+ case Regexp.Op.NLB:
3935
+ {
3936
+ if (this.lb !== that.lb || !this.subs[0].equals(that.subs[0])) {
3937
+ return false;
3938
+ }
3939
+ break;
3940
+ }
3704
3941
  }
3705
3942
  return true;
3706
3943
  }
3707
3944
  }
3708
3945
 
3946
+ // High-speed, single-pass Aho-Corasick string matcher optimized for V8.
3947
+ // Builds a trie with failure links to search for multiple prefixes simultaneously.
3948
+ class AhoCorasick {
3949
+ constructor(wordArrays) {
3950
+ this.next = [Object.create(null)];
3951
+ this.fail = [0];
3952
+ this.match = [false];
3953
+
3954
+ // Build Trie
3955
+ for (const word of wordArrays) {
3956
+ let node = 0;
3957
+ for (let i = 0; i < word.length; i++) {
3958
+ const val = word[i];
3959
+ if (!(val in this.next[node])) {
3960
+ this.next.push(Object.create(null));
3961
+ this.fail.push(0);
3962
+ this.match.push(false);
3963
+ this.next[node][val] = this.next.length - 1;
3964
+ }
3965
+ node = this.next[node][val];
3966
+ }
3967
+ this.match[node] = true;
3968
+ }
3969
+
3970
+ // Build Failure Links (BFS)
3971
+ const queue = [];
3972
+ for (const val in this.next[0]) {
3973
+ if (Object.prototype.hasOwnProperty.call(this.next[0], val)) {
3974
+ const child = this.next[0][val];
3975
+ this.fail[child] = 0;
3976
+ queue.push(child);
3977
+ }
3978
+ }
3979
+ while (queue.length > 0) {
3980
+ const curr = queue.shift();
3981
+ for (const val in this.next[curr]) {
3982
+ if (Object.prototype.hasOwnProperty.call(this.next[curr], val)) {
3983
+ const child = this.next[curr][val];
3984
+ let failNode = this.fail[curr];
3985
+ while (failNode !== 0 && !(val in this.next[failNode])) {
3986
+ failNode = this.fail[failNode];
3987
+ }
3988
+ if (val in this.next[failNode]) {
3989
+ this.fail[child] = this.next[failNode][val];
3990
+ } else {
3991
+ this.fail[child] = 0;
3992
+ }
3993
+ this.match[child] = this.match[child] || this.match[this.fail[child]];
3994
+ queue.push(child);
3995
+ }
3996
+ }
3997
+ }
3998
+ }
3999
+ searchUTF16(charSeq, start, end) {
4000
+ let node = 0;
4001
+ for (let i = start; i < end; i++) {
4002
+ const val = charSeq.charCodeAt(i);
4003
+ while (node !== 0 && !(val in this.next[node])) {
4004
+ node = this.fail[node];
4005
+ }
4006
+ if (val in this.next[node]) {
4007
+ node = this.next[node][val];
4008
+ }
4009
+ if (this.match[node]) return true;
4010
+ }
4011
+ return false;
4012
+ }
4013
+ searchUTF8(bytes, start, end) {
4014
+ let node = 0;
4015
+ for (let i = start; i < end; i++) {
4016
+ const val = bytes[i];
4017
+ while (node !== 0 && !(val in this.next[node])) {
4018
+ node = this.fail[node];
4019
+ }
4020
+ if (val in this.next[node]) {
4021
+ node = this.next[node][val];
4022
+ }
4023
+ if (this.match[node]) return true;
4024
+ }
4025
+ return false;
4026
+ }
4027
+ }
3709
4028
  class Prefilter {
3710
4029
  static Type = {
3711
4030
  NONE: 0,
@@ -3718,6 +4037,8 @@ class Prefilter {
3718
4037
  this.subs = [];
3719
4038
  this.str = '';
3720
4039
  this.bytes = null;
4040
+ this.ac16 = null;
4041
+ this.ac8 = null;
3721
4042
  }
3722
4043
  eval(input, pos) {
3723
4044
  switch (this.type) {
@@ -3731,6 +4052,10 @@ class Prefilter {
3731
4052
  }
3732
4053
  return true;
3733
4054
  case Prefilter.Type.OR:
4055
+ // Exploit Aho-Corasick if it was successfully built
4056
+ if (this.ac16 && this.ac8) {
4057
+ return input.hasAnyString(this, pos);
4058
+ }
3734
4059
  for (let i = 0; i < this.subs.length; i++) {
3735
4060
  if (this.subs[i].eval(input, pos)) return true;
3736
4061
  }
@@ -3748,6 +4073,8 @@ class PrefilterTree {
3748
4073
  static fromRegexp(re) {
3749
4074
  if (!re) return new Prefilter(Prefilter.Type.NONE);
3750
4075
  switch (re.op) {
4076
+ case Regexp.Op.PLB:
4077
+ case Regexp.Op.NLB:
3751
4078
  case Regexp.Op.NO_MATCH:
3752
4079
  case Regexp.Op.EMPTY_MATCH:
3753
4080
  case Regexp.Op.BEGIN_LINE:
@@ -3819,7 +4146,9 @@ class PrefilterTree {
3819
4146
  const s = PrefilterTree.simplify(sub);
3820
4147
  if (s.type !== Prefilter.Type.NONE) {
3821
4148
  if (s.type === Prefilter.Type.AND) {
3822
- newSubs.push(...s.subs);
4149
+ for (let j = 0; j < s.subs.length; j++) {
4150
+ newSubs.push(s.subs[j]);
4151
+ }
3823
4152
  } else {
3824
4153
  newSubs.push(s);
3825
4154
  }
@@ -3861,6 +4190,27 @@ class PrefilterTree {
3861
4190
  }
3862
4191
  }
3863
4192
  pf.subs = uniqueSubs;
4193
+
4194
+ // Build an Aho-Corasick automaton if all children are exact matches
4195
+ let allExact = true;
4196
+ for (const sub of uniqueSubs) {
4197
+ if (sub.type !== Prefilter.Type.EXACT) {
4198
+ allExact = false;
4199
+ break;
4200
+ }
4201
+ }
4202
+ if (allExact && uniqueSubs.length > 1) {
4203
+ const words16 = uniqueSubs.map(s => {
4204
+ const arr = [];
4205
+ for (let i = 0; i < s.str.length; i++) {
4206
+ arr.push(s.str.charCodeAt(i));
4207
+ }
4208
+ return arr;
4209
+ });
4210
+ pf.ac16 = new AhoCorasick(words16);
4211
+ const words8 = uniqueSubs.map(s => s.bytes);
4212
+ pf.ac8 = new AhoCorasick(words8);
4213
+ }
3864
4214
  return pf;
3865
4215
  }
3866
4216
  return pf;
@@ -3898,6 +4248,8 @@ class Prog {
3898
4248
  // number of CAPTURE insts in re
3899
4249
  // 2 => implicit ( and ) for whole match $0
3900
4250
  this.numCap = 2;
4251
+ this.lbStarts = []; // Track starting PCs of lookbehind automata
4252
+ this.numLb = 0; // Total number of lookbehinds
3901
4253
  }
3902
4254
 
3903
4255
  // Returns the instruction at the specified pc.
@@ -4230,6 +4582,26 @@ class Compiler {
4230
4582
  }
4231
4583
  return f;
4232
4584
  }
4585
+ lookBehind(a, lb) {
4586
+ const id = this.newInst(Inst.LB_WRITE);
4587
+ this.prog.getInst(id.i).lb = lb;
4588
+
4589
+ // Create the prefix wildcard `.*` for the lookbehind automaton
4590
+ const any = this.rune(Compiler.ANY_RUNE(), 0);
4591
+ const dotStar = this.star(any, true); // nongreedy = true
4592
+ const lbAutomaton = this.cat(dotStar, a);
4593
+ this.prog.patch(lbAutomaton.out, id.i);
4594
+ const checkId = this.newInst(Inst.LB_CHECK);
4595
+ this.prog.getInst(checkId.i).lb = lb;
4596
+
4597
+ // Save the starting point of this lookbehind automaton
4598
+ this.prog.lbStarts.push(lbAutomaton.i);
4599
+ if (Math.abs(lb) > this.prog.numLb) {
4600
+ this.prog.numLb = Math.abs(lb);
4601
+ }
4602
+ checkId.out = new PatchList(checkId.i << 1, checkId.i << 1);
4603
+ return checkId;
4604
+ }
4233
4605
  compile(re) {
4234
4606
  switch (re.op) {
4235
4607
  case Regexp.Op.NO_MATCH:
@@ -4265,6 +4637,9 @@ class Compiler {
4265
4637
  return this.empty(Utils.EMPTY_WORD_BOUNDARY);
4266
4638
  case Regexp.Op.NO_WORD_BOUNDARY:
4267
4639
  return this.empty(Utils.EMPTY_NO_WORD_BOUNDARY);
4640
+ case Regexp.Op.PLB:
4641
+ case Regexp.Op.NLB:
4642
+ return this.lookBehind(this.compile(re.subs[0]), re.lb);
4268
4643
  case Regexp.Op.CAPTURE:
4269
4644
  {
4270
4645
  const bra = this.cap(re.cap << 1);
@@ -4324,6 +4699,8 @@ class Simplify {
4324
4699
  return null;
4325
4700
  }
4326
4701
  switch (re.op) {
4702
+ case Regexp.Op.PLB:
4703
+ case Regexp.Op.NLB:
4327
4704
  case Regexp.Op.CAPTURE:
4328
4705
  {
4329
4706
  const sub = Simplify.simplify(re.subs[0]);
@@ -4360,7 +4737,9 @@ class Simplify {
4360
4737
  // Flatten nested concatenations
4361
4738
  if (nsub.op === Regexp.Op.CONCAT) {
4362
4739
  changed = true;
4363
- newSubs.push(...nsub.subs);
4740
+ for (let j = 0; j < nsub.subs.length; j++) {
4741
+ newSubs.push(nsub.subs[j]);
4742
+ }
4364
4743
  continue;
4365
4744
  }
4366
4745
  } else if (re.op === Regexp.Op.ALTERNATE) {
@@ -4372,7 +4751,9 @@ class Simplify {
4372
4751
  // Flatten nested alternations
4373
4752
  if (nsub.op === Regexp.Op.ALTERNATE) {
4374
4753
  changed = true;
4375
- newSubs.push(...nsub.subs);
4754
+ for (let j = 0; j < nsub.subs.length; j++) {
4755
+ newSubs.push(nsub.subs[j]);
4756
+ }
4376
4757
  continue;
4377
4758
  }
4378
4759
  }
@@ -5382,7 +5763,10 @@ class Parser {
5382
5763
  return t.pop();
5383
5764
  }
5384
5765
  static concatRunes(x, y) {
5385
- return [...x, ...y];
5766
+ for (let i = 0; i < y.length; i++) {
5767
+ x.push(y[i]);
5768
+ }
5769
+ return x;
5386
5770
  }
5387
5771
  constructor(wholeRegexp, flags = 0) {
5388
5772
  this.wholeRegexp = wholeRegexp;
@@ -5401,6 +5785,7 @@ class Parser {
5401
5785
  this.repeats = 0; // product of all repetitions seen
5402
5786
  this.height = null; // regexp height, for height limit check
5403
5787
  this.size = null; // regexp compiled size, for size limit check
5788
+ this.nlb = 0; // Number of lookbehinds seen
5404
5789
  }
5405
5790
 
5406
5791
  // Allocate a Regexp, from the free list if possible.
@@ -5417,8 +5802,8 @@ class Parser {
5417
5802
  return re;
5418
5803
  }
5419
5804
  reuse(re) {
5420
- if (this.height !== null && Object.prototype.hasOwnProperty.call(this.height, re)) {
5421
- delete this.height[re];
5805
+ if (this.height !== null && this.height.has(re)) {
5806
+ this.height.delete(re);
5422
5807
  }
5423
5808
  if (re.subs !== null && re.subs.length > 0) {
5424
5809
  re.subs[0] = this.free;
@@ -5450,20 +5835,20 @@ class Parser {
5450
5835
  if (n <= 0) {
5451
5836
  n = 1;
5452
5837
  }
5453
- if (n > Parser.MAX_SIZE / this.repeats) {
5838
+ if (n > Math.floor(Parser.MAX_SIZE / this.repeats)) {
5454
5839
  this.repeats = Parser.MAX_SIZE;
5455
5840
  } else {
5456
5841
  this.repeats *= n;
5457
5842
  }
5458
5843
  }
5459
- if (this.numRegexp < Parser.MAX_SIZE / this.repeats) {
5844
+ if (this.numRegexp < Math.floor(Parser.MAX_SIZE / this.repeats)) {
5460
5845
  return;
5461
5846
  }
5462
5847
 
5463
5848
  // We need to start tracking size.
5464
5849
  // Make the map and belatedly populate it
5465
5850
  // with info about everything we've constructed so far.
5466
- this.size = {};
5851
+ this.size = new Map();
5467
5852
  for (let reEx of this.stack) {
5468
5853
  this.checkSize(reEx);
5469
5854
  }
@@ -5473,9 +5858,9 @@ class Parser {
5473
5858
  }
5474
5859
  }
5475
5860
  calcSize(re, force = false) {
5476
- if (!force) {
5477
- if (Object.prototype.hasOwnProperty.call(this.size, re)) {
5478
- return this.size[re];
5861
+ if (!force && this.size !== null) {
5862
+ if (this.size.has(re)) {
5863
+ return this.size.get(re);
5479
5864
  }
5480
5865
  }
5481
5866
  let size = 0;
@@ -5485,6 +5870,8 @@ class Parser {
5485
5870
  size = re.runes.length;
5486
5871
  break;
5487
5872
  }
5873
+ case Regexp.Op.PLB:
5874
+ case Regexp.Op.NLB:
5488
5875
  case Regexp.Op.CAPTURE:
5489
5876
  case Regexp.Op.STAR:
5490
5877
  {
@@ -5532,7 +5919,10 @@ class Parser {
5532
5919
  }
5533
5920
  }
5534
5921
  size = Math.max(1, size);
5535
- this.size[re] = size;
5922
+ if (this.size === null) {
5923
+ this.size = new Map();
5924
+ }
5925
+ this.size.set(re, size);
5536
5926
  return size;
5537
5927
  }
5538
5928
  checkHeight(re) {
@@ -5540,7 +5930,7 @@ class Parser {
5540
5930
  return;
5541
5931
  }
5542
5932
  if (this.height === null) {
5543
- this.height = {};
5933
+ this.height = new Map();
5544
5934
  for (let reEx of this.stack) {
5545
5935
  this.checkHeight(reEx);
5546
5936
  }
@@ -5550,9 +5940,9 @@ class Parser {
5550
5940
  }
5551
5941
  }
5552
5942
  calcHeight(re, force = false) {
5553
- if (!force) {
5554
- if (Object.prototype.hasOwnProperty.call(this.height, re)) {
5555
- return this.height[re];
5943
+ if (!force && this.height !== null) {
5944
+ if (this.height.has(re)) {
5945
+ return this.height.get(re);
5556
5946
  }
5557
5947
  }
5558
5948
  let h = 1;
@@ -5562,7 +5952,10 @@ class Parser {
5562
5952
  h = 1 + hsub;
5563
5953
  }
5564
5954
  }
5565
- this.height[re] = h;
5955
+ if (this.height === null) {
5956
+ this.height = new Map();
5957
+ }
5958
+ this.height.set(re, h);
5566
5959
  return h;
5567
5960
  }
5568
5961
 
@@ -6130,6 +6523,19 @@ class Parser {
6130
6523
  let repeatPos = -1;
6131
6524
  bigswitch: switch (t.peek()) {
6132
6525
  case Codepoint.CODES.get('('):
6526
+ // Intercept Lookbehinds if the flag is enabled
6527
+ if ((this.flags & RE2Flags.LOOKBEHIND) !== 0) {
6528
+ if (t.lookingAt('(?<=')) {
6529
+ this.parsePosLookBehind();
6530
+ t.skip(4); // Skip over '(?<='
6531
+ break;
6532
+ }
6533
+ if (t.lookingAt('(?<!')) {
6534
+ this.parseNegLookBehind();
6535
+ t.skip(4); // Skip over '(?<!'
6536
+ break;
6537
+ }
6538
+ }
6133
6539
  if ((this.flags & RE2Flags.PERL_X) !== 0 && t.lookingAt('(?')) {
6134
6540
  // Flag changes and non-capturing groups.
6135
6541
  this.parsePerlFlags(t);
@@ -6410,6 +6816,20 @@ class Parser {
6410
6816
  throw new RE2JSSyntaxException(Parser.ERR_INVALID_PERL_OP, t.from(startPos));
6411
6817
  }
6412
6818
 
6819
+ // Lookbehinds parsing
6820
+ parsePosLookBehind() {
6821
+ const re = this.newRegexp(Regexp.Op.LEFT_PAREN);
6822
+ re.flags = this.flags;
6823
+ re.lb = ++this.nlb;
6824
+ return this.push(re);
6825
+ }
6826
+ parseNegLookBehind() {
6827
+ const re = this.newRegexp(Regexp.Op.LEFT_PAREN);
6828
+ re.flags = this.flags;
6829
+ re.lb = -++this.nlb;
6830
+ return this.push(re);
6831
+ }
6832
+
6413
6833
  // parseVerticalBar handles a | in the input.
6414
6834
  parseVerticalBar() {
6415
6835
  this.concat();
@@ -6479,6 +6899,18 @@ class Parser {
6479
6899
  }
6480
6900
  // Restore flags at time of paren.
6481
6901
  this.flags = re2.flags;
6902
+
6903
+ // Handle lookbehinds
6904
+ if (re2.lb !== 0) {
6905
+ if (re2.lb > 0) {
6906
+ re2.op = Regexp.Op.PLB;
6907
+ } else {
6908
+ re2.op = Regexp.Op.NLB;
6909
+ }
6910
+ re2.subs = [re1];
6911
+ this.push(re2);
6912
+ return;
6913
+ }
6482
6914
  if (re2.cap === 0) {
6483
6915
  // Just for grouping.
6484
6916
  this.push(re1);
@@ -6877,21 +7309,25 @@ class RE2 {
6877
7309
  // We must use the NFA.
6878
7310
  if (ncap > 0) {
6879
7311
  // Backtracker bit-state execution bounds check
6880
- if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) {
7312
+ if (this.prog.numLb === 0 && input.endPos() <= Backtracker.maxBitStateLen(this.prog)) {
6881
7313
  return Backtracker.execute(this, input, pos, anchor, ncap);
6882
7314
  }
6883
7315
  // NFA execution
6884
7316
  return this.doExecuteNFA(input, pos, anchor, ncap);
6885
7317
  }
6886
- const dfaResult = this.dfa.match(input, pos, anchor);
6887
- if (dfaResult !== null) {
6888
- // DFA succeeded (returned true or false)
6889
- return dfaResult ? [] : null; // Return empty array to signify "matched but no captures"
6890
- }
6891
7318
 
6892
- // Backtracker bit-state execution bounds check
6893
- if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) {
6894
- return Backtracker.execute(this, input, pos, anchor, ncap);
7319
+ // The DFA will safely return null (bailout) if it encounters a lookbehind
7320
+ if (this.prog.numLb === 0) {
7321
+ const dfaResult = this.dfa.match(input, pos, anchor);
7322
+ if (dfaResult !== null) {
7323
+ // DFA succeeded (returned true or false)
7324
+ return dfaResult ? [] : null; // Return empty array to signify "matched but no captures"
7325
+ }
7326
+
7327
+ // Backtracker bit-state execution bounds check
7328
+ if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) {
7329
+ return Backtracker.execute(this, input, pos, anchor, ncap);
7330
+ }
6895
7331
  }
6896
7332
 
6897
7333
  // Fallback to NFA
@@ -7475,9 +7911,20 @@ class RE2 {
7475
7911
  }
7476
7912
 
7477
7913
  class RE2Set {
7478
- constructor(anchor = RE2Flags.UNANCHORED, flags = RE2Flags.PERL) {
7914
+ static UNANCHORED = RE2Flags.UNANCHORED;
7915
+ static ANCHOR_START = RE2Flags.ANCHOR_START;
7916
+ static ANCHOR_BOTH = RE2Flags.ANCHOR_BOTH;
7917
+ constructor(anchor = RE2Set.UNANCHORED, flags = 0) {
7479
7918
  this.anchor = anchor;
7480
- this.flags = flags;
7919
+ this.jsFlags = flags;
7920
+ let re2Flags = RE2Flags.PERL;
7921
+ if ((flags & PublicFlags.DISABLE_UNICODE_GROUPS) !== 0) {
7922
+ re2Flags &= -129;
7923
+ }
7924
+ if ((flags & PublicFlags.LOOKBEHINDS) !== 0) {
7925
+ re2Flags |= RE2Flags.LOOKBEHIND;
7926
+ }
7927
+ this.re2Flags = re2Flags;
7481
7928
  this.regexps = [];
7482
7929
  this.prog = null;
7483
7930
  this.dfa = null;
@@ -7487,7 +7934,17 @@ class RE2Set {
7487
7934
  if (this.prog) {
7488
7935
  throw new RE2JSCompileException('Cannot add patterns after compile');
7489
7936
  }
7490
- const re = Parser.parse(pattern, this.flags);
7937
+ let fregex = pattern;
7938
+ if ((this.jsFlags & PublicFlags.CASE_INSENSITIVE) !== 0) {
7939
+ fregex = `(?i)${fregex}`;
7940
+ }
7941
+ if ((this.jsFlags & PublicFlags.DOTALL) !== 0) {
7942
+ fregex = `(?s)${fregex}`;
7943
+ }
7944
+ if ((this.jsFlags & PublicFlags.MULTILINE) !== 0) {
7945
+ fregex = `(?m)${fregex}`;
7946
+ }
7947
+ const re = Parser.parse(fregex, this.re2Flags);
7491
7948
  this.regexps.push(Simplify.simplify(re));
7492
7949
  return this.regexps.length - 1;
7493
7950
  }
@@ -7506,15 +7963,21 @@ class RE2Set {
7506
7963
  match(input) {
7507
7964
  if (!this.prog) this.compile();
7508
7965
  const machineInput = Array.isArray(input) ? MachineInput.fromUTF8(input) : MachineInput.fromUTF16(input);
7966
+ let internalAnchor = RE2Flags.UNANCHORED;
7967
+ if (this.anchor === RE2Set.ANCHOR_START) {
7968
+ internalAnchor = RE2Flags.ANCHOR_START;
7969
+ } else if (this.anchor === RE2Set.ANCHOR_BOTH) {
7970
+ internalAnchor = RE2Flags.ANCHOR_BOTH;
7971
+ }
7509
7972
 
7510
7973
  // Fast path: Try the blistering fast DFA
7511
- const dfaResult = this.dfa.matchSet(machineInput, 0, this.anchor);
7974
+ const dfaResult = this.dfa.matchSet(machineInput, 0, internalAnchor);
7512
7975
  if (dfaResult !== null) return dfaResult;
7513
7976
 
7514
7977
  // Safe Fallback: Handle boundaries (\b) or massive state explosions via NFA
7515
7978
  const machine = Machine.fromRE2(this.dummyRe2);
7516
7979
  machine.init(0);
7517
- return machine.matchSet(machineInput, 0, this.anchor);
7980
+ return machine.matchSet(machineInput, 0, internalAnchor);
7518
7981
  }
7519
7982
  }
7520
7983
 
@@ -7614,7 +8077,7 @@ class TranslateRegExpString {
7614
8077
  changed = true;
7615
8078
  continue;
7616
8079
  } else if (ch === '(' && i + 2 < size && data[i + 1] === '?' && data[i + 2] === '<') {
7617
- if (i + 3 >= size || data[i + 3] !== '=' && data[i + 3] !== '!') {
8080
+ if (i + 3 < size && !'=!>)'.includes(data[i + 3])) {
7618
8081
  result += '(?P<';
7619
8082
  i += 3;
7620
8083
  changed = true;
@@ -7644,24 +8107,28 @@ class RE2JS {
7644
8107
  /**
7645
8108
  * Flag: case insensitive matching.
7646
8109
  */
7647
- static CASE_INSENSITIVE = 1;
8110
+ static CASE_INSENSITIVE = PublicFlags.CASE_INSENSITIVE;
7648
8111
  /**
7649
8112
  * Flag: dot ({@code .}) matches all characters, including newline.
7650
8113
  */
7651
- static DOTALL = 2;
8114
+ static DOTALL = PublicFlags.DOTALL;
7652
8115
  /**
7653
8116
  * Flag: multiline matching: {@code ^} and {@code $} match at beginning and end of line, not just
7654
8117
  * beginning and end of input.
7655
8118
  */
7656
- static MULTILINE = 4;
8119
+ static MULTILINE = PublicFlags.MULTILINE;
7657
8120
  /**
7658
8121
  * Flag: Unicode groups (e.g. {@code \p\ Greek\} ) will be syntax errors.
7659
8122
  */
7660
- static DISABLE_UNICODE_GROUPS = 8;
8123
+ static DISABLE_UNICODE_GROUPS = PublicFlags.DISABLE_UNICODE_GROUPS;
7661
8124
  /**
7662
8125
  * Flag: matches longest possible string.
7663
8126
  */
7664
- static LONGEST_MATCH = 16;
8127
+ static LONGEST_MATCH = PublicFlags.LONGEST_MATCH;
8128
+ /**
8129
+ * Flag: enable linear-time captureless lookbehinds.
8130
+ */
8131
+ static LOOKBEHINDS = PublicFlags.LOOKBEHINDS;
7665
8132
 
7666
8133
  /**
7667
8134
  * Returns a literal pattern string for the specified string.
@@ -7724,13 +8191,16 @@ class RE2JS {
7724
8191
  if ((flags & RE2JS.MULTILINE) !== 0) {
7725
8192
  fregex = `(?m)${fregex}`;
7726
8193
  }
7727
- if ((flags & ~(RE2JS.MULTILINE | RE2JS.DOTALL | RE2JS.CASE_INSENSITIVE | RE2JS.DISABLE_UNICODE_GROUPS | RE2JS.LONGEST_MATCH)) !== 0) {
7728
- throw new RE2JSFlagsException('Flags should only be a combination of MULTILINE, DOTALL, CASE_INSENSITIVE, DISABLE_UNICODE_GROUPS, LONGEST_MATCH');
8194
+ if ((flags & ~(RE2JS.MULTILINE | RE2JS.DOTALL | RE2JS.CASE_INSENSITIVE | RE2JS.DISABLE_UNICODE_GROUPS | RE2JS.LONGEST_MATCH | RE2JS.LOOKBEHINDS)) !== 0) {
8195
+ throw new RE2JSFlagsException('Flags should only be a combination of MULTILINE, DOTALL, CASE_INSENSITIVE, DISABLE_UNICODE_GROUPS, LONGEST_MATCH, LOOKBEHINDS');
7729
8196
  }
7730
8197
  let re2Flags = RE2Flags.PERL;
7731
8198
  if ((flags & RE2JS.DISABLE_UNICODE_GROUPS) !== 0) {
7732
8199
  re2Flags &= -129;
7733
8200
  }
8201
+ if ((flags & RE2JS.LOOKBEHINDS) !== 0) {
8202
+ re2Flags |= RE2Flags.LOOKBEHIND;
8203
+ }
7734
8204
  const p = new RE2JS(regex, flags);
7735
8205
  // The compiled RE2 regexp.
7736
8206
  p.re2Input = RE2.compileImpl(fregex, re2Flags, (flags & RE2JS.LONGEST_MATCH) !== 0);