]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/Net/IDNA2.php
[ROUTES] Allow accept-header specification during router creation
[quix0rs-gnu-social.git] / extlib / Net / IDNA2.php
1 <?php
2
3 // {{{ license{{{{{{
4
5 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
6 //
7 // +----------------------------------------------------------------------+
8 // | This library is free software; you can redistribute it and/or modify |
9 // | it under the terms of the GNU Lesser General Public License as       |
10 // | published by the Free Software Foundation; either version 2.1 of the |
11 // | License, or (at your option) any later version.                      |
12 // |                                                                      |
13 // | This library is distributed in the hope that it will be useful, but  |
14 // | WITHOUT ANY WARRANTY; without even the implied warranty of           |
15 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
16 // | Lesser General Public License for more details.                      |
17 // |                                                                      |
18 // | You should have received a copy of the GNU Lesser General Public     |
19 // | License along with this library; if not, write to the Free Software  |
20 // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 |
21 // | USA.                                                                 |
22 // +----------------------------------------------------------------------+
23 //
24
25 // }}}}}}}}}
26 require_once 'Net/IDNA2/Exception.php';
27 require_once 'Net/IDNA2/Exception/Nameprep.php';
28
29 /**
30  * Encode/decode Internationalized Domain Names.
31  *
32  * The class allows one to convert internationalized domain names
33  * (see RFC 3490 for details) as they can be used with various registries worldwide
34  * to be translated between their original (localized) form and their encoded form
35  * as it will be used in the DNS (Domain Name System).
36  *
37  * The class provides two public methods, encode() and decode(), which do exactly
38  * what you would expect them to do. You are allowed to use complete domain names,
39  * simple strings and complete email addresses as well. That means, that you might
40  * use any of the following notations:
41  *
42  * - www.n�rgler.com
43  * - xn--nrgler-wxa
44  * - xn--brse-5qa.xn--knrz-1ra.info
45  *
46  * Unicode input might be given as either UTF-8 string, UCS-4 string or UCS-4
47  * array. Unicode output is available in the same formats.
48  * You can select your preferred format via {@link set_paramter()}.
49  *
50  * ACE input and output is always expected to be ASCII.
51  *
52  * @package Net
53  * @author  Markus Nix <mnix@docuverse.de>
54  * @author  Matthias Sommerfeld <mso@phlylabs.de>
55  * @author  Stefan Neufeind <pear.neufeind@speedpartner.de>
56  * @version $Id$
57  */
58 class Net_IDNA2
59 {
60     // {{{ npdata
61     /**
62      * These Unicode codepoints are
63      * mapped to nothing, See RFC3454 for details
64      *
65      * @static
66      * @var array
67      * @access private
68      */
69     private static $_np_map_nothing = [
70         0xAD,
71         0x34F,
72         0x1806,
73         0x180B,
74         0x180C,
75         0x180D,
76         0x200B,
77         0x200C,
78         0x200D,
79         0x2060,
80         0xFE00,
81         0xFE01,
82         0xFE02,
83         0xFE03,
84         0xFE04,
85         0xFE05,
86         0xFE06,
87         0xFE07,
88         0xFE08,
89         0xFE09,
90         0xFE0A,
91         0xFE0B,
92         0xFE0C,
93         0xFE0D,
94         0xFE0E,
95         0xFE0F,
96         0xFEFF
97     ];
98
99     /**
100      * Prohibited codepints
101      *
102      * @static
103      * @var array
104      * @access private
105      */
106     private static $_general_prohibited = [
107         0,
108         1,
109         2,
110         3,
111         4,
112         5,
113         6,
114         7,
115         8,
116         9,
117         0xA,
118         0xB,
119         0xC,
120         0xD,
121         0xE,
122         0xF,
123         0x10,
124         0x11,
125         0x12,
126         0x13,
127         0x14,
128         0x15,
129         0x16,
130         0x17,
131         0x18,
132         0x19,
133         0x1A,
134         0x1B,
135         0x1C,
136         0x1D,
137         0x1E,
138         0x1F,
139         0x20,
140         0x21,
141         0x22,
142         0x23,
143         0x24,
144         0x25,
145         0x26,
146         0x27,
147         0x28,
148         0x29,
149         0x2A,
150         0x2B,
151         0x2C,
152         0x2F,
153         0x3B,
154         0x3C,
155         0x3D,
156         0x3E,
157         0x3F,
158         0x40,
159         0x5B,
160         0x5C,
161         0x5D,
162         0x5E,
163         0x5F,
164         0x60,
165         0x7B,
166         0x7C,
167         0x7D,
168         0x7E,
169         0x7F,
170         0x3002
171     ];
172
173     /**
174      * Codepints prohibited by Nameprep
175      * @static
176      * @var array
177      * @access private
178      */
179     private static $_np_prohibit = [
180         0xA0,
181         0x1680,
182         0x2000,
183         0x2001,
184         0x2002,
185         0x2003,
186         0x2004,
187         0x2005,
188         0x2006,
189         0x2007,
190         0x2008,
191         0x2009,
192         0x200A,
193         0x200B,
194         0x202F,
195         0x205F,
196         0x3000,
197         0x6DD,
198         0x70F,
199         0x180E,
200         0x200C,
201         0x200D,
202         0x2028,
203         0x2029,
204         0xFEFF,
205         0xFFF9,
206         0xFFFA,
207         0xFFFB,
208         0xFFFC,
209         0xFFFE,
210         0xFFFF,
211         0x1FFFE,
212         0x1FFFF,
213         0x2FFFE,
214         0x2FFFF,
215         0x3FFFE,
216         0x3FFFF,
217         0x4FFFE,
218         0x4FFFF,
219         0x5FFFE,
220         0x5FFFF,
221         0x6FFFE,
222         0x6FFFF,
223         0x7FFFE,
224         0x7FFFF,
225         0x8FFFE,
226         0x8FFFF,
227         0x9FFFE,
228         0x9FFFF,
229         0xAFFFE,
230         0xAFFFF,
231         0xBFFFE,
232         0xBFFFF,
233         0xCFFFE,
234         0xCFFFF,
235         0xDFFFE,
236         0xDFFFF,
237         0xEFFFE,
238         0xEFFFF,
239         0xFFFFE,
240         0xFFFFF,
241         0x10FFFE,
242         0x10FFFF,
243         0xFFF9,
244         0xFFFA,
245         0xFFFB,
246         0xFFFC,
247         0xFFFD,
248         0x340,
249         0x341,
250         0x200E,
251         0x200F,
252         0x202A,
253         0x202B,
254         0x202C,
255         0x202D,
256         0x202E,
257         0x206A,
258         0x206B,
259         0x206C,
260         0x206D,
261         0x206E,
262         0x206F,
263         0xE0001
264     ];
265
266     /**
267      * Codepoint ranges prohibited by nameprep
268      *
269      * @static
270      * @var array
271      * @access private
272      */
273     private static $_np_prohibit_ranges = [
274         [0x80, 0x9F],
275         [0x2060, 0x206F],
276         [0x1D173, 0x1D17A],
277         [0xE000, 0xF8FF],
278         [0xF0000, 0xFFFFD],
279         [0x100000, 0x10FFFD],
280         [0xFDD0, 0xFDEF],
281         [0xD800, 0xDFFF],
282         [0x2FF0, 0x2FFB],
283         [0xE0020, 0xE007F]
284     ];
285
286     /**
287      * Replacement mappings (casemapping, replacement sequences, ...)
288      *
289      * @static
290      * @var array
291      * @access private
292      */
293     private static $_np_replacemaps = [
294         0x41 => [0x61],
295         0x42 => [0x62],
296         0x43 => [0x63],
297         0x44 => [0x64],
298         0x45 => [0x65],
299         0x46 => [0x66],
300         0x47 => [0x67],
301         0x48 => [0x68],
302         0x49 => [0x69],
303         0x4A => [0x6A],
304         0x4B => [0x6B],
305         0x4C => [0x6C],
306         0x4D => [0x6D],
307         0x4E => [0x6E],
308         0x4F => [0x6F],
309         0x50 => [0x70],
310         0x51 => [0x71],
311         0x52 => [0x72],
312         0x53 => [0x73],
313         0x54 => [0x74],
314         0x55 => [0x75],
315         0x56 => [0x76],
316         0x57 => [0x77],
317         0x58 => [0x78],
318         0x59 => [0x79],
319         0x5A => [0x7A],
320         0xB5 => [0x3BC],
321         0xC0 => [0xE0],
322         0xC1 => [0xE1],
323         0xC2 => [0xE2],
324         0xC3 => [0xE3],
325         0xC4 => [0xE4],
326         0xC5 => [0xE5],
327         0xC6 => [0xE6],
328         0xC7 => [0xE7],
329         0xC8 => [0xE8],
330         0xC9 => [0xE9],
331         0xCA => [0xEA],
332         0xCB => [0xEB],
333         0xCC => [0xEC],
334         0xCD => [0xED],
335         0xCE => [0xEE],
336         0xCF => [0xEF],
337         0xD0 => [0xF0],
338         0xD1 => [0xF1],
339         0xD2 => [0xF2],
340         0xD3 => [0xF3],
341         0xD4 => [0xF4],
342         0xD5 => [0xF5],
343         0xD6 => [0xF6],
344         0xD8 => [0xF8],
345         0xD9 => [0xF9],
346         0xDA => [0xFA],
347         0xDB => [0xFB],
348         0xDC => [0xFC],
349         0xDD => [0xFD],
350         0xDE => [0xFE],
351         0xDF => [0x73, 0x73],
352         0x100 => [0x101],
353         0x102 => [0x103],
354         0x104 => [0x105],
355         0x106 => [0x107],
356         0x108 => [0x109],
357         0x10A => [0x10B],
358         0x10C => [0x10D],
359         0x10E => [0x10F],
360         0x110 => [0x111],
361         0x112 => [0x113],
362         0x114 => [0x115],
363         0x116 => [0x117],
364         0x118 => [0x119],
365         0x11A => [0x11B],
366         0x11C => [0x11D],
367         0x11E => [0x11F],
368         0x120 => [0x121],
369         0x122 => [0x123],
370         0x124 => [0x125],
371         0x126 => [0x127],
372         0x128 => [0x129],
373         0x12A => [0x12B],
374         0x12C => [0x12D],
375         0x12E => [0x12F],
376         0x130 => [0x69, 0x307],
377         0x132 => [0x133],
378         0x134 => [0x135],
379         0x136 => [0x137],
380         0x139 => [0x13A],
381         0x13B => [0x13C],
382         0x13D => [0x13E],
383         0x13F => [0x140],
384         0x141 => [0x142],
385         0x143 => [0x144],
386         0x145 => [0x146],
387         0x147 => [0x148],
388         0x149 => [0x2BC, 0x6E],
389         0x14A => [0x14B],
390         0x14C => [0x14D],
391         0x14E => [0x14F],
392         0x150 => [0x151],
393         0x152 => [0x153],
394         0x154 => [0x155],
395         0x156 => [0x157],
396         0x158 => [0x159],
397         0x15A => [0x15B],
398         0x15C => [0x15D],
399         0x15E => [0x15F],
400         0x160 => [0x161],
401         0x162 => [0x163],
402         0x164 => [0x165],
403         0x166 => [0x167],
404         0x168 => [0x169],
405         0x16A => [0x16B],
406         0x16C => [0x16D],
407         0x16E => [0x16F],
408         0x170 => [0x171],
409         0x172 => [0x173],
410         0x174 => [0x175],
411         0x176 => [0x177],
412         0x178 => [0xFF],
413         0x179 => [0x17A],
414         0x17B => [0x17C],
415         0x17D => [0x17E],
416         0x17F => [0x73],
417         0x181 => [0x253],
418         0x182 => [0x183],
419         0x184 => [0x185],
420         0x186 => [0x254],
421         0x187 => [0x188],
422         0x189 => [0x256],
423         0x18A => [0x257],
424         0x18B => [0x18C],
425         0x18E => [0x1DD],
426         0x18F => [0x259],
427         0x190 => [0x25B],
428         0x191 => [0x192],
429         0x193 => [0x260],
430         0x194 => [0x263],
431         0x196 => [0x269],
432         0x197 => [0x268],
433         0x198 => [0x199],
434         0x19C => [0x26F],
435         0x19D => [0x272],
436         0x19F => [0x275],
437         0x1A0 => [0x1A1],
438         0x1A2 => [0x1A3],
439         0x1A4 => [0x1A5],
440         0x1A6 => [0x280],
441         0x1A7 => [0x1A8],
442         0x1A9 => [0x283],
443         0x1AC => [0x1AD],
444         0x1AE => [0x288],
445         0x1AF => [0x1B0],
446         0x1B1 => [0x28A],
447         0x1B2 => [0x28B],
448         0x1B3 => [0x1B4],
449         0x1B5 => [0x1B6],
450         0x1B7 => [0x292],
451         0x1B8 => [0x1B9],
452         0x1BC => [0x1BD],
453         0x1C4 => [0x1C6],
454         0x1C5 => [0x1C6],
455         0x1C7 => [0x1C9],
456         0x1C8 => [0x1C9],
457         0x1CA => [0x1CC],
458         0x1CB => [0x1CC],
459         0x1CD => [0x1CE],
460         0x1CF => [0x1D0],
461         0x1D1 => [0x1D2],
462         0x1D3 => [0x1D4],
463         0x1D5 => [0x1D6],
464         0x1D7 => [0x1D8],
465         0x1D9 => [0x1DA],
466         0x1DB => [0x1DC],
467         0x1DE => [0x1DF],
468         0x1E0 => [0x1E1],
469         0x1E2 => [0x1E3],
470         0x1E4 => [0x1E5],
471         0x1E6 => [0x1E7],
472         0x1E8 => [0x1E9],
473         0x1EA => [0x1EB],
474         0x1EC => [0x1ED],
475         0x1EE => [0x1EF],
476         0x1F0 => [0x6A, 0x30C],
477         0x1F1 => [0x1F3],
478         0x1F2 => [0x1F3],
479         0x1F4 => [0x1F5],
480         0x1F6 => [0x195],
481         0x1F7 => [0x1BF],
482         0x1F8 => [0x1F9],
483         0x1FA => [0x1FB],
484         0x1FC => [0x1FD],
485         0x1FE => [0x1FF],
486         0x200 => [0x201],
487         0x202 => [0x203],
488         0x204 => [0x205],
489         0x206 => [0x207],
490         0x208 => [0x209],
491         0x20A => [0x20B],
492         0x20C => [0x20D],
493         0x20E => [0x20F],
494         0x210 => [0x211],
495         0x212 => [0x213],
496         0x214 => [0x215],
497         0x216 => [0x217],
498         0x218 => [0x219],
499         0x21A => [0x21B],
500         0x21C => [0x21D],
501         0x21E => [0x21F],
502         0x220 => [0x19E],
503         0x222 => [0x223],
504         0x224 => [0x225],
505         0x226 => [0x227],
506         0x228 => [0x229],
507         0x22A => [0x22B],
508         0x22C => [0x22D],
509         0x22E => [0x22F],
510         0x230 => [0x231],
511         0x232 => [0x233],
512         0x345 => [0x3B9],
513         0x37A => [0x20, 0x3B9],
514         0x386 => [0x3AC],
515         0x388 => [0x3AD],
516         0x389 => [0x3AE],
517         0x38A => [0x3AF],
518         0x38C => [0x3CC],
519         0x38E => [0x3CD],
520         0x38F => [0x3CE],
521         0x390 => [0x3B9, 0x308, 0x301],
522         0x391 => [0x3B1],
523         0x392 => [0x3B2],
524         0x393 => [0x3B3],
525         0x394 => [0x3B4],
526         0x395 => [0x3B5],
527         0x396 => [0x3B6],
528         0x397 => [0x3B7],
529         0x398 => [0x3B8],
530         0x399 => [0x3B9],
531         0x39A => [0x3BA],
532         0x39B => [0x3BB],
533         0x39C => [0x3BC],
534         0x39D => [0x3BD],
535         0x39E => [0x3BE],
536         0x39F => [0x3BF],
537         0x3A0 => [0x3C0],
538         0x3A1 => [0x3C1],
539         0x3A3 => [0x3C3],
540         0x3A4 => [0x3C4],
541         0x3A5 => [0x3C5],
542         0x3A6 => [0x3C6],
543         0x3A7 => [0x3C7],
544         0x3A8 => [0x3C8],
545         0x3A9 => [0x3C9],
546         0x3AA => [0x3CA],
547         0x3AB => [0x3CB],
548         0x3B0 => [0x3C5, 0x308, 0x301],
549         0x3C2 => [0x3C3],
550         0x3D0 => [0x3B2],
551         0x3D1 => [0x3B8],
552         0x3D2 => [0x3C5],
553         0x3D3 => [0x3CD],
554         0x3D4 => [0x3CB],
555         0x3D5 => [0x3C6],
556         0x3D6 => [0x3C0],
557         0x3D8 => [0x3D9],
558         0x3DA => [0x3DB],
559         0x3DC => [0x3DD],
560         0x3DE => [0x3DF],
561         0x3E0 => [0x3E1],
562         0x3E2 => [0x3E3],
563         0x3E4 => [0x3E5],
564         0x3E6 => [0x3E7],
565         0x3E8 => [0x3E9],
566         0x3EA => [0x3EB],
567         0x3EC => [0x3ED],
568         0x3EE => [0x3EF],
569         0x3F0 => [0x3BA],
570         0x3F1 => [0x3C1],
571         0x3F2 => [0x3C3],
572         0x3F4 => [0x3B8],
573         0x3F5 => [0x3B5],
574         0x400 => [0x450],
575         0x401 => [0x451],
576         0x402 => [0x452],
577         0x403 => [0x453],
578         0x404 => [0x454],
579         0x405 => [0x455],
580         0x406 => [0x456],
581         0x407 => [0x457],
582         0x408 => [0x458],
583         0x409 => [0x459],
584         0x40A => [0x45A],
585         0x40B => [0x45B],
586         0x40C => [0x45C],
587         0x40D => [0x45D],
588         0x40E => [0x45E],
589         0x40F => [0x45F],
590         0x410 => [0x430],
591         0x411 => [0x431],
592         0x412 => [0x432],
593         0x413 => [0x433],
594         0x414 => [0x434],
595         0x415 => [0x435],
596         0x416 => [0x436],
597         0x417 => [0x437],
598         0x418 => [0x438],
599         0x419 => [0x439],
600         0x41A => [0x43A],
601         0x41B => [0x43B],
602         0x41C => [0x43C],
603         0x41D => [0x43D],
604         0x41E => [0x43E],
605         0x41F => [0x43F],
606         0x420 => [0x440],
607         0x421 => [0x441],
608         0x422 => [0x442],
609         0x423 => [0x443],
610         0x424 => [0x444],
611         0x425 => [0x445],
612         0x426 => [0x446],
613         0x427 => [0x447],
614         0x428 => [0x448],
615         0x429 => [0x449],
616         0x42A => [0x44A],
617         0x42B => [0x44B],
618         0x42C => [0x44C],
619         0x42D => [0x44D],
620         0x42E => [0x44E],
621         0x42F => [0x44F],
622         0x460 => [0x461],
623         0x462 => [0x463],
624         0x464 => [0x465],
625         0x466 => [0x467],
626         0x468 => [0x469],
627         0x46A => [0x46B],
628         0x46C => [0x46D],
629         0x46E => [0x46F],
630         0x470 => [0x471],
631         0x472 => [0x473],
632         0x474 => [0x475],
633         0x476 => [0x477],
634         0x478 => [0x479],
635         0x47A => [0x47B],
636         0x47C => [0x47D],
637         0x47E => [0x47F],
638         0x480 => [0x481],
639         0x48A => [0x48B],
640         0x48C => [0x48D],
641         0x48E => [0x48F],
642         0x490 => [0x491],
643         0x492 => [0x493],
644         0x494 => [0x495],
645         0x496 => [0x497],
646         0x498 => [0x499],
647         0x49A => [0x49B],
648         0x49C => [0x49D],
649         0x49E => [0x49F],
650         0x4A0 => [0x4A1],
651         0x4A2 => [0x4A3],
652         0x4A4 => [0x4A5],
653         0x4A6 => [0x4A7],
654         0x4A8 => [0x4A9],
655         0x4AA => [0x4AB],
656         0x4AC => [0x4AD],
657         0x4AE => [0x4AF],
658         0x4B0 => [0x4B1],
659         0x4B2 => [0x4B3],
660         0x4B4 => [0x4B5],
661         0x4B6 => [0x4B7],
662         0x4B8 => [0x4B9],
663         0x4BA => [0x4BB],
664         0x4BC => [0x4BD],
665         0x4BE => [0x4BF],
666         0x4C1 => [0x4C2],
667         0x4C3 => [0x4C4],
668         0x4C5 => [0x4C6],
669         0x4C7 => [0x4C8],
670         0x4C9 => [0x4CA],
671         0x4CB => [0x4CC],
672         0x4CD => [0x4CE],
673         0x4D0 => [0x4D1],
674         0x4D2 => [0x4D3],
675         0x4D4 => [0x4D5],
676         0x4D6 => [0x4D7],
677         0x4D8 => [0x4D9],
678         0x4DA => [0x4DB],
679         0x4DC => [0x4DD],
680         0x4DE => [0x4DF],
681         0x4E0 => [0x4E1],
682         0x4E2 => [0x4E3],
683         0x4E4 => [0x4E5],
684         0x4E6 => [0x4E7],
685         0x4E8 => [0x4E9],
686         0x4EA => [0x4EB],
687         0x4EC => [0x4ED],
688         0x4EE => [0x4EF],
689         0x4F0 => [0x4F1],
690         0x4F2 => [0x4F3],
691         0x4F4 => [0x4F5],
692         0x4F8 => [0x4F9],
693         0x500 => [0x501],
694         0x502 => [0x503],
695         0x504 => [0x505],
696         0x506 => [0x507],
697         0x508 => [0x509],
698         0x50A => [0x50B],
699         0x50C => [0x50D],
700         0x50E => [0x50F],
701         0x531 => [0x561],
702         0x532 => [0x562],
703         0x533 => [0x563],
704         0x534 => [0x564],
705         0x535 => [0x565],
706         0x536 => [0x566],
707         0x537 => [0x567],
708         0x538 => [0x568],
709         0x539 => [0x569],
710         0x53A => [0x56A],
711         0x53B => [0x56B],
712         0x53C => [0x56C],
713         0x53D => [0x56D],
714         0x53E => [0x56E],
715         0x53F => [0x56F],
716         0x540 => [0x570],
717         0x541 => [0x571],
718         0x542 => [0x572],
719         0x543 => [0x573],
720         0x544 => [0x574],
721         0x545 => [0x575],
722         0x546 => [0x576],
723         0x547 => [0x577],
724         0x548 => [0x578],
725         0x549 => [0x579],
726         0x54A => [0x57A],
727         0x54B => [0x57B],
728         0x54C => [0x57C],
729         0x54D => [0x57D],
730         0x54E => [0x57E],
731         0x54F => [0x57F],
732         0x550 => [0x580],
733         0x551 => [0x581],
734         0x552 => [0x582],
735         0x553 => [0x583],
736         0x554 => [0x584],
737         0x555 => [0x585],
738         0x556 => [0x586],
739         0x587 => [0x565, 0x582],
740         0x1E00 => [0x1E01],
741         0x1E02 => [0x1E03],
742         0x1E04 => [0x1E05],
743         0x1E06 => [0x1E07],
744         0x1E08 => [0x1E09],
745         0x1E0A => [0x1E0B],
746         0x1E0C => [0x1E0D],
747         0x1E0E => [0x1E0F],
748         0x1E10 => [0x1E11],
749         0x1E12 => [0x1E13],
750         0x1E14 => [0x1E15],
751         0x1E16 => [0x1E17],
752         0x1E18 => [0x1E19],
753         0x1E1A => [0x1E1B],
754         0x1E1C => [0x1E1D],
755         0x1E1E => [0x1E1F],
756         0x1E20 => [0x1E21],
757         0x1E22 => [0x1E23],
758         0x1E24 => [0x1E25],
759         0x1E26 => [0x1E27],
760         0x1E28 => [0x1E29],
761         0x1E2A => [0x1E2B],
762         0x1E2C => [0x1E2D],
763         0x1E2E => [0x1E2F],
764         0x1E30 => [0x1E31],
765         0x1E32 => [0x1E33],
766         0x1E34 => [0x1E35],
767         0x1E36 => [0x1E37],
768         0x1E38 => [0x1E39],
769         0x1E3A => [0x1E3B],
770         0x1E3C => [0x1E3D],
771         0x1E3E => [0x1E3F],
772         0x1E40 => [0x1E41],
773         0x1E42 => [0x1E43],
774         0x1E44 => [0x1E45],
775         0x1E46 => [0x1E47],
776         0x1E48 => [0x1E49],
777         0x1E4A => [0x1E4B],
778         0x1E4C => [0x1E4D],
779         0x1E4E => [0x1E4F],
780         0x1E50 => [0x1E51],
781         0x1E52 => [0x1E53],
782         0x1E54 => [0x1E55],
783         0x1E56 => [0x1E57],
784         0x1E58 => [0x1E59],
785         0x1E5A => [0x1E5B],
786         0x1E5C => [0x1E5D],
787         0x1E5E => [0x1E5F],
788         0x1E60 => [0x1E61],
789         0x1E62 => [0x1E63],
790         0x1E64 => [0x1E65],
791         0x1E66 => [0x1E67],
792         0x1E68 => [0x1E69],
793         0x1E6A => [0x1E6B],
794         0x1E6C => [0x1E6D],
795         0x1E6E => [0x1E6F],
796         0x1E70 => [0x1E71],
797         0x1E72 => [0x1E73],
798         0x1E74 => [0x1E75],
799         0x1E76 => [0x1E77],
800         0x1E78 => [0x1E79],
801         0x1E7A => [0x1E7B],
802         0x1E7C => [0x1E7D],
803         0x1E7E => [0x1E7F],
804         0x1E80 => [0x1E81],
805         0x1E82 => [0x1E83],
806         0x1E84 => [0x1E85],
807         0x1E86 => [0x1E87],
808         0x1E88 => [0x1E89],
809         0x1E8A => [0x1E8B],
810         0x1E8C => [0x1E8D],
811         0x1E8E => [0x1E8F],
812         0x1E90 => [0x1E91],
813         0x1E92 => [0x1E93],
814         0x1E94 => [0x1E95],
815         0x1E96 => [0x68, 0x331],
816         0x1E97 => [0x74, 0x308],
817         0x1E98 => [0x77, 0x30A],
818         0x1E99 => [0x79, 0x30A],
819         0x1E9A => [0x61, 0x2BE],
820         0x1E9B => [0x1E61],
821         0x1EA0 => [0x1EA1],
822         0x1EA2 => [0x1EA3],
823         0x1EA4 => [0x1EA5],
824         0x1EA6 => [0x1EA7],
825         0x1EA8 => [0x1EA9],
826         0x1EAA => [0x1EAB],
827         0x1EAC => [0x1EAD],
828         0x1EAE => [0x1EAF],
829         0x1EB0 => [0x1EB1],
830         0x1EB2 => [0x1EB3],
831         0x1EB4 => [0x1EB5],
832         0x1EB6 => [0x1EB7],
833         0x1EB8 => [0x1EB9],
834         0x1EBA => [0x1EBB],
835         0x1EBC => [0x1EBD],
836         0x1EBE => [0x1EBF],
837         0x1EC0 => [0x1EC1],
838         0x1EC2 => [0x1EC3],
839         0x1EC4 => [0x1EC5],
840         0x1EC6 => [0x1EC7],
841         0x1EC8 => [0x1EC9],
842         0x1ECA => [0x1ECB],
843         0x1ECC => [0x1ECD],
844         0x1ECE => [0x1ECF],
845         0x1ED0 => [0x1ED1],
846         0x1ED2 => [0x1ED3],
847         0x1ED4 => [0x1ED5],
848         0x1ED6 => [0x1ED7],
849         0x1ED8 => [0x1ED9],
850         0x1EDA => [0x1EDB],
851         0x1EDC => [0x1EDD],
852         0x1EDE => [0x1EDF],
853         0x1EE0 => [0x1EE1],
854         0x1EE2 => [0x1EE3],
855         0x1EE4 => [0x1EE5],
856         0x1EE6 => [0x1EE7],
857         0x1EE8 => [0x1EE9],
858         0x1EEA => [0x1EEB],
859         0x1EEC => [0x1EED],
860         0x1EEE => [0x1EEF],
861         0x1EF0 => [0x1EF1],
862         0x1EF2 => [0x1EF3],
863         0x1EF4 => [0x1EF5],
864         0x1EF6 => [0x1EF7],
865         0x1EF8 => [0x1EF9],
866         0x1F08 => [0x1F00],
867         0x1F09 => [0x1F01],
868         0x1F0A => [0x1F02],
869         0x1F0B => [0x1F03],
870         0x1F0C => [0x1F04],
871         0x1F0D => [0x1F05],
872         0x1F0E => [0x1F06],
873         0x1F0F => [0x1F07],
874         0x1F18 => [0x1F10],
875         0x1F19 => [0x1F11],
876         0x1F1A => [0x1F12],
877         0x1F1B => [0x1F13],
878         0x1F1C => [0x1F14],
879         0x1F1D => [0x1F15],
880         0x1F28 => [0x1F20],
881         0x1F29 => [0x1F21],
882         0x1F2A => [0x1F22],
883         0x1F2B => [0x1F23],
884         0x1F2C => [0x1F24],
885         0x1F2D => [0x1F25],
886         0x1F2E => [0x1F26],
887         0x1F2F => [0x1F27],
888         0x1F38 => [0x1F30],
889         0x1F39 => [0x1F31],
890         0x1F3A => [0x1F32],
891         0x1F3B => [0x1F33],
892         0x1F3C => [0x1F34],
893         0x1F3D => [0x1F35],
894         0x1F3E => [0x1F36],
895         0x1F3F => [0x1F37],
896         0x1F48 => [0x1F40],
897         0x1F49 => [0x1F41],
898         0x1F4A => [0x1F42],
899         0x1F4B => [0x1F43],
900         0x1F4C => [0x1F44],
901         0x1F4D => [0x1F45],
902         0x1F50 => [0x3C5, 0x313],
903         0x1F52 => [0x3C5, 0x313, 0x300],
904         0x1F54 => [0x3C5, 0x313, 0x301],
905         0x1F56 => [0x3C5, 0x313, 0x342],
906         0x1F59 => [0x1F51],
907         0x1F5B => [0x1F53],
908         0x1F5D => [0x1F55],
909         0x1F5F => [0x1F57],
910         0x1F68 => [0x1F60],
911         0x1F69 => [0x1F61],
912         0x1F6A => [0x1F62],
913         0x1F6B => [0x1F63],
914         0x1F6C => [0x1F64],
915         0x1F6D => [0x1F65],
916         0x1F6E => [0x1F66],
917         0x1F6F => [0x1F67],
918         0x1F80 => [0x1F00, 0x3B9],
919         0x1F81 => [0x1F01, 0x3B9],
920         0x1F82 => [0x1F02, 0x3B9],
921         0x1F83 => [0x1F03, 0x3B9],
922         0x1F84 => [0x1F04, 0x3B9],
923         0x1F85 => [0x1F05, 0x3B9],
924         0x1F86 => [0x1F06, 0x3B9],
925         0x1F87 => [0x1F07, 0x3B9],
926         0x1F88 => [0x1F00, 0x3B9],
927         0x1F89 => [0x1F01, 0x3B9],
928         0x1F8A => [0x1F02, 0x3B9],
929         0x1F8B => [0x1F03, 0x3B9],
930         0x1F8C => [0x1F04, 0x3B9],
931         0x1F8D => [0x1F05, 0x3B9],
932         0x1F8E => [0x1F06, 0x3B9],
933         0x1F8F => [0x1F07, 0x3B9],
934         0x1F90 => [0x1F20, 0x3B9],
935         0x1F91 => [0x1F21, 0x3B9],
936         0x1F92 => [0x1F22, 0x3B9],
937         0x1F93 => [0x1F23, 0x3B9],
938         0x1F94 => [0x1F24, 0x3B9],
939         0x1F95 => [0x1F25, 0x3B9],
940         0x1F96 => [0x1F26, 0x3B9],
941         0x1F97 => [0x1F27, 0x3B9],
942         0x1F98 => [0x1F20, 0x3B9],
943         0x1F99 => [0x1F21, 0x3B9],
944         0x1F9A => [0x1F22, 0x3B9],
945         0x1F9B => [0x1F23, 0x3B9],
946         0x1F9C => [0x1F24, 0x3B9],
947         0x1F9D => [0x1F25, 0x3B9],
948         0x1F9E => [0x1F26, 0x3B9],
949         0x1F9F => [0x1F27, 0x3B9],
950         0x1FA0 => [0x1F60, 0x3B9],
951         0x1FA1 => [0x1F61, 0x3B9],
952         0x1FA2 => [0x1F62, 0x3B9],
953         0x1FA3 => [0x1F63, 0x3B9],
954         0x1FA4 => [0x1F64, 0x3B9],
955         0x1FA5 => [0x1F65, 0x3B9],
956         0x1FA6 => [0x1F66, 0x3B9],
957         0x1FA7 => [0x1F67, 0x3B9],
958         0x1FA8 => [0x1F60, 0x3B9],
959         0x1FA9 => [0x1F61, 0x3B9],
960         0x1FAA => [0x1F62, 0x3B9],
961         0x1FAB => [0x1F63, 0x3B9],
962         0x1FAC => [0x1F64, 0x3B9],
963         0x1FAD => [0x1F65, 0x3B9],
964         0x1FAE => [0x1F66, 0x3B9],
965         0x1FAF => [0x1F67, 0x3B9],
966         0x1FB2 => [0x1F70, 0x3B9],
967         0x1FB3 => [0x3B1, 0x3B9],
968         0x1FB4 => [0x3AC, 0x3B9],
969         0x1FB6 => [0x3B1, 0x342],
970         0x1FB7 => [0x3B1, 0x342, 0x3B9],
971         0x1FB8 => [0x1FB0],
972         0x1FB9 => [0x1FB1],
973         0x1FBA => [0x1F70],
974         0x1FBB => [0x1F71],
975         0x1FBC => [0x3B1, 0x3B9],
976         0x1FBE => [0x3B9],
977         0x1FC2 => [0x1F74, 0x3B9],
978         0x1FC3 => [0x3B7, 0x3B9],
979         0x1FC4 => [0x3AE, 0x3B9],
980         0x1FC6 => [0x3B7, 0x342],
981         0x1FC7 => [0x3B7, 0x342, 0x3B9],
982         0x1FC8 => [0x1F72],
983         0x1FC9 => [0x1F73],
984         0x1FCA => [0x1F74],
985         0x1FCB => [0x1F75],
986         0x1FCC => [0x3B7, 0x3B9],
987         0x1FD2 => [0x3B9, 0x308, 0x300],
988         0x1FD3 => [0x3B9, 0x308, 0x301],
989         0x1FD6 => [0x3B9, 0x342],
990         0x1FD7 => [0x3B9, 0x308, 0x342],
991         0x1FD8 => [0x1FD0],
992         0x1FD9 => [0x1FD1],
993         0x1FDA => [0x1F76],
994         0x1FDB => [0x1F77],
995         0x1FE2 => [0x3C5, 0x308, 0x300],
996         0x1FE3 => [0x3C5, 0x308, 0x301],
997         0x1FE4 => [0x3C1, 0x313],
998         0x1FE6 => [0x3C5, 0x342],
999         0x1FE7 => [0x3C5, 0x308, 0x342],
1000         0x1FE8 => [0x1FE0],
1001         0x1FE9 => [0x1FE1],
1002         0x1FEA => [0x1F7A],
1003         0x1FEB => [0x1F7B],
1004         0x1FEC => [0x1FE5],
1005         0x1FF2 => [0x1F7C, 0x3B9],
1006         0x1FF3 => [0x3C9, 0x3B9],
1007         0x1FF4 => [0x3CE, 0x3B9],
1008         0x1FF6 => [0x3C9, 0x342],
1009         0x1FF7 => [0x3C9, 0x342, 0x3B9],
1010         0x1FF8 => [0x1F78],
1011         0x1FF9 => [0x1F79],
1012         0x1FFA => [0x1F7C],
1013         0x1FFB => [0x1F7D],
1014         0x1FFC => [0x3C9, 0x3B9],
1015         0x20A8 => [0x72, 0x73],
1016         0x2102 => [0x63],
1017         0x2103 => [0xB0, 0x63],
1018         0x2107 => [0x25B],
1019         0x2109 => [0xB0, 0x66],
1020         0x210B => [0x68],
1021         0x210C => [0x68],
1022         0x210D => [0x68],
1023         0x2110 => [0x69],
1024         0x2111 => [0x69],
1025         0x2112 => [0x6C],
1026         0x2115 => [0x6E],
1027         0x2116 => [0x6E, 0x6F],
1028         0x2119 => [0x70],
1029         0x211A => [0x71],
1030         0x211B => [0x72],
1031         0x211C => [0x72],
1032         0x211D => [0x72],
1033         0x2120 => [0x73, 0x6D],
1034         0x2121 => [0x74, 0x65, 0x6C],
1035         0x2122 => [0x74, 0x6D],
1036         0x2124 => [0x7A],
1037         0x2126 => [0x3C9],
1038         0x2128 => [0x7A],
1039         0x212A => [0x6B],
1040         0x212B => [0xE5],
1041         0x212C => [0x62],
1042         0x212D => [0x63],
1043         0x2130 => [0x65],
1044         0x2131 => [0x66],
1045         0x2133 => [0x6D],
1046         0x213E => [0x3B3],
1047         0x213F => [0x3C0],
1048         0x2145 => [0x64],
1049         0x2160 => [0x2170],
1050         0x2161 => [0x2171],
1051         0x2162 => [0x2172],
1052         0x2163 => [0x2173],
1053         0x2164 => [0x2174],
1054         0x2165 => [0x2175],
1055         0x2166 => [0x2176],
1056         0x2167 => [0x2177],
1057         0x2168 => [0x2178],
1058         0x2169 => [0x2179],
1059         0x216A => [0x217A],
1060         0x216B => [0x217B],
1061         0x216C => [0x217C],
1062         0x216D => [0x217D],
1063         0x216E => [0x217E],
1064         0x216F => [0x217F],
1065         0x24B6 => [0x24D0],
1066         0x24B7 => [0x24D1],
1067         0x24B8 => [0x24D2],
1068         0x24B9 => [0x24D3],
1069         0x24BA => [0x24D4],
1070         0x24BB => [0x24D5],
1071         0x24BC => [0x24D6],
1072         0x24BD => [0x24D7],
1073         0x24BE => [0x24D8],
1074         0x24BF => [0x24D9],
1075         0x24C0 => [0x24DA],
1076         0x24C1 => [0x24DB],
1077         0x24C2 => [0x24DC],
1078         0x24C3 => [0x24DD],
1079         0x24C4 => [0x24DE],
1080         0x24C5 => [0x24DF],
1081         0x24C6 => [0x24E0],
1082         0x24C7 => [0x24E1],
1083         0x24C8 => [0x24E2],
1084         0x24C9 => [0x24E3],
1085         0x24CA => [0x24E4],
1086         0x24CB => [0x24E5],
1087         0x24CC => [0x24E6],
1088         0x24CD => [0x24E7],
1089         0x24CE => [0x24E8],
1090         0x24CF => [0x24E9],
1091         0x3371 => [0x68, 0x70, 0x61],
1092         0x3373 => [0x61, 0x75],
1093         0x3375 => [0x6F, 0x76],
1094         0x3380 => [0x70, 0x61],
1095         0x3381 => [0x6E, 0x61],
1096         0x3382 => [0x3BC, 0x61],
1097         0x3383 => [0x6D, 0x61],
1098         0x3384 => [0x6B, 0x61],
1099         0x3385 => [0x6B, 0x62],
1100         0x3386 => [0x6D, 0x62],
1101         0x3387 => [0x67, 0x62],
1102         0x338A => [0x70, 0x66],
1103         0x338B => [0x6E, 0x66],
1104         0x338C => [0x3BC, 0x66],
1105         0x3390 => [0x68, 0x7A],
1106         0x3391 => [0x6B, 0x68, 0x7A],
1107         0x3392 => [0x6D, 0x68, 0x7A],
1108         0x3393 => [0x67, 0x68, 0x7A],
1109         0x3394 => [0x74, 0x68, 0x7A],
1110         0x33A9 => [0x70, 0x61],
1111         0x33AA => [0x6B, 0x70, 0x61],
1112         0x33AB => [0x6D, 0x70, 0x61],
1113         0x33AC => [0x67, 0x70, 0x61],
1114         0x33B4 => [0x70, 0x76],
1115         0x33B5 => [0x6E, 0x76],
1116         0x33B6 => [0x3BC, 0x76],
1117         0x33B7 => [0x6D, 0x76],
1118         0x33B8 => [0x6B, 0x76],
1119         0x33B9 => [0x6D, 0x76],
1120         0x33BA => [0x70, 0x77],
1121         0x33BB => [0x6E, 0x77],
1122         0x33BC => [0x3BC, 0x77],
1123         0x33BD => [0x6D, 0x77],
1124         0x33BE => [0x6B, 0x77],
1125         0x33BF => [0x6D, 0x77],
1126         0x33C0 => [0x6B, 0x3C9],
1127         0x33C1 => [0x6D, 0x3C9],
1128         /* 0x33C2  => [0x61, 0x2E, 0x6D, 0x2E], */
1129         0x33C3 => [0x62, 0x71],
1130         0x33C6 => [0x63, 0x2215, 0x6B, 0x67],
1131         0x33C7 => [0x63, 0x6F, 0x2E],
1132         0x33C8 => [0x64, 0x62],
1133         0x33C9 => [0x67, 0x79],
1134         0x33CB => [0x68, 0x70],
1135         0x33CD => [0x6B, 0x6B],
1136         0x33CE => [0x6B, 0x6D],
1137         0x33D7 => [0x70, 0x68],
1138         0x33D9 => [0x70, 0x70, 0x6D],
1139         0x33DA => [0x70, 0x72],
1140         0x33DC => [0x73, 0x76],
1141         0x33DD => [0x77, 0x62],
1142         0xFB00 => [0x66, 0x66],
1143         0xFB01 => [0x66, 0x69],
1144         0xFB02 => [0x66, 0x6C],
1145         0xFB03 => [0x66, 0x66, 0x69],
1146         0xFB04 => [0x66, 0x66, 0x6C],
1147         0xFB05 => [0x73, 0x74],
1148         0xFB06 => [0x73, 0x74],
1149         0xFB13 => [0x574, 0x576],
1150         0xFB14 => [0x574, 0x565],
1151         0xFB15 => [0x574, 0x56B],
1152         0xFB16 => [0x57E, 0x576],
1153         0xFB17 => [0x574, 0x56D],
1154         0xFF21 => [0xFF41],
1155         0xFF22 => [0xFF42],
1156         0xFF23 => [0xFF43],
1157         0xFF24 => [0xFF44],
1158         0xFF25 => [0xFF45],
1159         0xFF26 => [0xFF46],
1160         0xFF27 => [0xFF47],
1161         0xFF28 => [0xFF48],
1162         0xFF29 => [0xFF49],
1163         0xFF2A => [0xFF4A],
1164         0xFF2B => [0xFF4B],
1165         0xFF2C => [0xFF4C],
1166         0xFF2D => [0xFF4D],
1167         0xFF2E => [0xFF4E],
1168         0xFF2F => [0xFF4F],
1169         0xFF30 => [0xFF50],
1170         0xFF31 => [0xFF51],
1171         0xFF32 => [0xFF52],
1172         0xFF33 => [0xFF53],
1173         0xFF34 => [0xFF54],
1174         0xFF35 => [0xFF55],
1175         0xFF36 => [0xFF56],
1176         0xFF37 => [0xFF57],
1177         0xFF38 => [0xFF58],
1178         0xFF39 => [0xFF59],
1179         0xFF3A => [0xFF5A],
1180         0x10400 => [0x10428],
1181         0x10401 => [0x10429],
1182         0x10402 => [0x1042A],
1183         0x10403 => [0x1042B],
1184         0x10404 => [0x1042C],
1185         0x10405 => [0x1042D],
1186         0x10406 => [0x1042E],
1187         0x10407 => [0x1042F],
1188         0x10408 => [0x10430],
1189         0x10409 => [0x10431],
1190         0x1040A => [0x10432],
1191         0x1040B => [0x10433],
1192         0x1040C => [0x10434],
1193         0x1040D => [0x10435],
1194         0x1040E => [0x10436],
1195         0x1040F => [0x10437],
1196         0x10410 => [0x10438],
1197         0x10411 => [0x10439],
1198         0x10412 => [0x1043A],
1199         0x10413 => [0x1043B],
1200         0x10414 => [0x1043C],
1201         0x10415 => [0x1043D],
1202         0x10416 => [0x1043E],
1203         0x10417 => [0x1043F],
1204         0x10418 => [0x10440],
1205         0x10419 => [0x10441],
1206         0x1041A => [0x10442],
1207         0x1041B => [0x10443],
1208         0x1041C => [0x10444],
1209         0x1041D => [0x10445],
1210         0x1041E => [0x10446],
1211         0x1041F => [0x10447],
1212         0x10420 => [0x10448],
1213         0x10421 => [0x10449],
1214         0x10422 => [0x1044A],
1215         0x10423 => [0x1044B],
1216         0x10424 => [0x1044C],
1217         0x10425 => [0x1044D],
1218         0x1D400 => [0x61],
1219         0x1D401 => [0x62],
1220         0x1D402 => [0x63],
1221         0x1D403 => [0x64],
1222         0x1D404 => [0x65],
1223         0x1D405 => [0x66],
1224         0x1D406 => [0x67],
1225         0x1D407 => [0x68],
1226         0x1D408 => [0x69],
1227         0x1D409 => [0x6A],
1228         0x1D40A => [0x6B],
1229         0x1D40B => [0x6C],
1230         0x1D40C => [0x6D],
1231         0x1D40D => [0x6E],
1232         0x1D40E => [0x6F],
1233         0x1D40F => [0x70],
1234         0x1D410 => [0x71],
1235         0x1D411 => [0x72],
1236         0x1D412 => [0x73],
1237         0x1D413 => [0x74],
1238         0x1D414 => [0x75],
1239         0x1D415 => [0x76],
1240         0x1D416 => [0x77],
1241         0x1D417 => [0x78],
1242         0x1D418 => [0x79],
1243         0x1D419 => [0x7A],
1244         0x1D434 => [0x61],
1245         0x1D435 => [0x62],
1246         0x1D436 => [0x63],
1247         0x1D437 => [0x64],
1248         0x1D438 => [0x65],
1249         0x1D439 => [0x66],
1250         0x1D43A => [0x67],
1251         0x1D43B => [0x68],
1252         0x1D43C => [0x69],
1253         0x1D43D => [0x6A],
1254         0x1D43E => [0x6B],
1255         0x1D43F => [0x6C],
1256         0x1D440 => [0x6D],
1257         0x1D441 => [0x6E],
1258         0x1D442 => [0x6F],
1259         0x1D443 => [0x70],
1260         0x1D444 => [0x71],
1261         0x1D445 => [0x72],
1262         0x1D446 => [0x73],
1263         0x1D447 => [0x74],
1264         0x1D448 => [0x75],
1265         0x1D449 => [0x76],
1266         0x1D44A => [0x77],
1267         0x1D44B => [0x78],
1268         0x1D44C => [0x79],
1269         0x1D44D => [0x7A],
1270         0x1D468 => [0x61],
1271         0x1D469 => [0x62],
1272         0x1D46A => [0x63],
1273         0x1D46B => [0x64],
1274         0x1D46C => [0x65],
1275         0x1D46D => [0x66],
1276         0x1D46E => [0x67],
1277         0x1D46F => [0x68],
1278         0x1D470 => [0x69],
1279         0x1D471 => [0x6A],
1280         0x1D472 => [0x6B],
1281         0x1D473 => [0x6C],
1282         0x1D474 => [0x6D],
1283         0x1D475 => [0x6E],
1284         0x1D476 => [0x6F],
1285         0x1D477 => [0x70],
1286         0x1D478 => [0x71],
1287         0x1D479 => [0x72],
1288         0x1D47A => [0x73],
1289         0x1D47B => [0x74],
1290         0x1D47C => [0x75],
1291         0x1D47D => [0x76],
1292         0x1D47E => [0x77],
1293         0x1D47F => [0x78],
1294         0x1D480 => [0x79],
1295         0x1D481 => [0x7A],
1296         0x1D49C => [0x61],
1297         0x1D49E => [0x63],
1298         0x1D49F => [0x64],
1299         0x1D4A2 => [0x67],
1300         0x1D4A5 => [0x6A],
1301         0x1D4A6 => [0x6B],
1302         0x1D4A9 => [0x6E],
1303         0x1D4AA => [0x6F],
1304         0x1D4AB => [0x70],
1305         0x1D4AC => [0x71],
1306         0x1D4AE => [0x73],
1307         0x1D4AF => [0x74],
1308         0x1D4B0 => [0x75],
1309         0x1D4B1 => [0x76],
1310         0x1D4B2 => [0x77],
1311         0x1D4B3 => [0x78],
1312         0x1D4B4 => [0x79],
1313         0x1D4B5 => [0x7A],
1314         0x1D4D0 => [0x61],
1315         0x1D4D1 => [0x62],
1316         0x1D4D2 => [0x63],
1317         0x1D4D3 => [0x64],
1318         0x1D4D4 => [0x65],
1319         0x1D4D5 => [0x66],
1320         0x1D4D6 => [0x67],
1321         0x1D4D7 => [0x68],
1322         0x1D4D8 => [0x69],
1323         0x1D4D9 => [0x6A],
1324         0x1D4DA => [0x6B],
1325         0x1D4DB => [0x6C],
1326         0x1D4DC => [0x6D],
1327         0x1D4DD => [0x6E],
1328         0x1D4DE => [0x6F],
1329         0x1D4DF => [0x70],
1330         0x1D4E0 => [0x71],
1331         0x1D4E1 => [0x72],
1332         0x1D4E2 => [0x73],
1333         0x1D4E3 => [0x74],
1334         0x1D4E4 => [0x75],
1335         0x1D4E5 => [0x76],
1336         0x1D4E6 => [0x77],
1337         0x1D4E7 => [0x78],
1338         0x1D4E8 => [0x79],
1339         0x1D4E9 => [0x7A],
1340         0x1D504 => [0x61],
1341         0x1D505 => [0x62],
1342         0x1D507 => [0x64],
1343         0x1D508 => [0x65],
1344         0x1D509 => [0x66],
1345         0x1D50A => [0x67],
1346         0x1D50D => [0x6A],
1347         0x1D50E => [0x6B],
1348         0x1D50F => [0x6C],
1349         0x1D510 => [0x6D],
1350         0x1D511 => [0x6E],
1351         0x1D512 => [0x6F],
1352         0x1D513 => [0x70],
1353         0x1D514 => [0x71],
1354         0x1D516 => [0x73],
1355         0x1D517 => [0x74],
1356         0x1D518 => [0x75],
1357         0x1D519 => [0x76],
1358         0x1D51A => [0x77],
1359         0x1D51B => [0x78],
1360         0x1D51C => [0x79],
1361         0x1D538 => [0x61],
1362         0x1D539 => [0x62],
1363         0x1D53B => [0x64],
1364         0x1D53C => [0x65],
1365         0x1D53D => [0x66],
1366         0x1D53E => [0x67],
1367         0x1D540 => [0x69],
1368         0x1D541 => [0x6A],
1369         0x1D542 => [0x6B],
1370         0x1D543 => [0x6C],
1371         0x1D544 => [0x6D],
1372         0x1D546 => [0x6F],
1373         0x1D54A => [0x73],
1374         0x1D54B => [0x74],
1375         0x1D54C => [0x75],
1376         0x1D54D => [0x76],
1377         0x1D54E => [0x77],
1378         0x1D54F => [0x78],
1379         0x1D550 => [0x79],
1380         0x1D56C => [0x61],
1381         0x1D56D => [0x62],
1382         0x1D56E => [0x63],
1383         0x1D56F => [0x64],
1384         0x1D570 => [0x65],
1385         0x1D571 => [0x66],
1386         0x1D572 => [0x67],
1387         0x1D573 => [0x68],
1388         0x1D574 => [0x69],
1389         0x1D575 => [0x6A],
1390         0x1D576 => [0x6B],
1391         0x1D577 => [0x6C],
1392         0x1D578 => [0x6D],
1393         0x1D579 => [0x6E],
1394         0x1D57A => [0x6F],
1395         0x1D57B => [0x70],
1396         0x1D57C => [0x71],
1397         0x1D57D => [0x72],
1398         0x1D57E => [0x73],
1399         0x1D57F => [0x74],
1400         0x1D580 => [0x75],
1401         0x1D581 => [0x76],
1402         0x1D582 => [0x77],
1403         0x1D583 => [0x78],
1404         0x1D584 => [0x79],
1405         0x1D585 => [0x7A],
1406         0x1D5A0 => [0x61],
1407         0x1D5A1 => [0x62],
1408         0x1D5A2 => [0x63],
1409         0x1D5A3 => [0x64],
1410         0x1D5A4 => [0x65],
1411         0x1D5A5 => [0x66],
1412         0x1D5A6 => [0x67],
1413         0x1D5A7 => [0x68],
1414         0x1D5A8 => [0x69],
1415         0x1D5A9 => [0x6A],
1416         0x1D5AA => [0x6B],
1417         0x1D5AB => [0x6C],
1418         0x1D5AC => [0x6D],
1419         0x1D5AD => [0x6E],
1420         0x1D5AE => [0x6F],
1421         0x1D5AF => [0x70],
1422         0x1D5B0 => [0x71],
1423         0x1D5B1 => [0x72],
1424         0x1D5B2 => [0x73],
1425         0x1D5B3 => [0x74],
1426         0x1D5B4 => [0x75],
1427         0x1D5B5 => [0x76],
1428         0x1D5B6 => [0x77],
1429         0x1D5B7 => [0x78],
1430         0x1D5B8 => [0x79],
1431         0x1D5B9 => [0x7A],
1432         0x1D5D4 => [0x61],
1433         0x1D5D5 => [0x62],
1434         0x1D5D6 => [0x63],
1435         0x1D5D7 => [0x64],
1436         0x1D5D8 => [0x65],
1437         0x1D5D9 => [0x66],
1438         0x1D5DA => [0x67],
1439         0x1D5DB => [0x68],
1440         0x1D5DC => [0x69],
1441         0x1D5DD => [0x6A],
1442         0x1D5DE => [0x6B],
1443         0x1D5DF => [0x6C],
1444         0x1D5E0 => [0x6D],
1445         0x1D5E1 => [0x6E],
1446         0x1D5E2 => [0x6F],
1447         0x1D5E3 => [0x70],
1448         0x1D5E4 => [0x71],
1449         0x1D5E5 => [0x72],
1450         0x1D5E6 => [0x73],
1451         0x1D5E7 => [0x74],
1452         0x1D5E8 => [0x75],
1453         0x1D5E9 => [0x76],
1454         0x1D5EA => [0x77],
1455         0x1D5EB => [0x78],
1456         0x1D5EC => [0x79],
1457         0x1D5ED => [0x7A],
1458         0x1D608 => [0x61],
1459         0x1D609 => [0x62],
1460         0x1D60A => [0x63],
1461         0x1D60B => [0x64],
1462         0x1D60C => [0x65],
1463         0x1D60D => [0x66],
1464         0x1D60E => [0x67],
1465         0x1D60F => [0x68],
1466         0x1D610 => [0x69],
1467         0x1D611 => [0x6A],
1468         0x1D612 => [0x6B],
1469         0x1D613 => [0x6C],
1470         0x1D614 => [0x6D],
1471         0x1D615 => [0x6E],
1472         0x1D616 => [0x6F],
1473         0x1D617 => [0x70],
1474         0x1D618 => [0x71],
1475         0x1D619 => [0x72],
1476         0x1D61A => [0x73],
1477         0x1D61B => [0x74],
1478         0x1D61C => [0x75],
1479         0x1D61D => [0x76],
1480         0x1D61E => [0x77],
1481         0x1D61F => [0x78],
1482         0x1D620 => [0x79],
1483         0x1D621 => [0x7A],
1484         0x1D63C => [0x61],
1485         0x1D63D => [0x62],
1486         0x1D63E => [0x63],
1487         0x1D63F => [0x64],
1488         0x1D640 => [0x65],
1489         0x1D641 => [0x66],
1490         0x1D642 => [0x67],
1491         0x1D643 => [0x68],
1492         0x1D644 => [0x69],
1493         0x1D645 => [0x6A],
1494         0x1D646 => [0x6B],
1495         0x1D647 => [0x6C],
1496         0x1D648 => [0x6D],
1497         0x1D649 => [0x6E],
1498         0x1D64A => [0x6F],
1499         0x1D64B => [0x70],
1500         0x1D64C => [0x71],
1501         0x1D64D => [0x72],
1502         0x1D64E => [0x73],
1503         0x1D64F => [0x74],
1504         0x1D650 => [0x75],
1505         0x1D651 => [0x76],
1506         0x1D652 => [0x77],
1507         0x1D653 => [0x78],
1508         0x1D654 => [0x79],
1509         0x1D655 => [0x7A],
1510         0x1D670 => [0x61],
1511         0x1D671 => [0x62],
1512         0x1D672 => [0x63],
1513         0x1D673 => [0x64],
1514         0x1D674 => [0x65],
1515         0x1D675 => [0x66],
1516         0x1D676 => [0x67],
1517         0x1D677 => [0x68],
1518         0x1D678 => [0x69],
1519         0x1D679 => [0x6A],
1520         0x1D67A => [0x6B],
1521         0x1D67B => [0x6C],
1522         0x1D67C => [0x6D],
1523         0x1D67D => [0x6E],
1524         0x1D67E => [0x6F],
1525         0x1D67F => [0x70],
1526         0x1D680 => [0x71],
1527         0x1D681 => [0x72],
1528         0x1D682 => [0x73],
1529         0x1D683 => [0x74],
1530         0x1D684 => [0x75],
1531         0x1D685 => [0x76],
1532         0x1D686 => [0x77],
1533         0x1D687 => [0x78],
1534         0x1D688 => [0x79],
1535         0x1D689 => [0x7A],
1536         0x1D6A8 => [0x3B1],
1537         0x1D6A9 => [0x3B2],
1538         0x1D6AA => [0x3B3],
1539         0x1D6AB => [0x3B4],
1540         0x1D6AC => [0x3B5],
1541         0x1D6AD => [0x3B6],
1542         0x1D6AE => [0x3B7],
1543         0x1D6AF => [0x3B8],
1544         0x1D6B0 => [0x3B9],
1545         0x1D6B1 => [0x3BA],
1546         0x1D6B2 => [0x3BB],
1547         0x1D6B3 => [0x3BC],
1548         0x1D6B4 => [0x3BD],
1549         0x1D6B5 => [0x3BE],
1550         0x1D6B6 => [0x3BF],
1551         0x1D6B7 => [0x3C0],
1552         0x1D6B8 => [0x3C1],
1553         0x1D6B9 => [0x3B8],
1554         0x1D6BA => [0x3C3],
1555         0x1D6BB => [0x3C4],
1556         0x1D6BC => [0x3C5],
1557         0x1D6BD => [0x3C6],
1558         0x1D6BE => [0x3C7],
1559         0x1D6BF => [0x3C8],
1560         0x1D6C0 => [0x3C9],
1561         0x1D6D3 => [0x3C3],
1562         0x1D6E2 => [0x3B1],
1563         0x1D6E3 => [0x3B2],
1564         0x1D6E4 => [0x3B3],
1565         0x1D6E5 => [0x3B4],
1566         0x1D6E6 => [0x3B5],
1567         0x1D6E7 => [0x3B6],
1568         0x1D6E8 => [0x3B7],
1569         0x1D6E9 => [0x3B8],
1570         0x1D6EA => [0x3B9],
1571         0x1D6EB => [0x3BA],
1572         0x1D6EC => [0x3BB],
1573         0x1D6ED => [0x3BC],
1574         0x1D6EE => [0x3BD],
1575         0x1D6EF => [0x3BE],
1576         0x1D6F0 => [0x3BF],
1577         0x1D6F1 => [0x3C0],
1578         0x1D6F2 => [0x3C1],
1579         0x1D6F3 => [0x3B8],
1580         0x1D6F4 => [0x3C3],
1581         0x1D6F5 => [0x3C4],
1582         0x1D6F6 => [0x3C5],
1583         0x1D6F7 => [0x3C6],
1584         0x1D6F8 => [0x3C7],
1585         0x1D6F9 => [0x3C8],
1586         0x1D6FA => [0x3C9],
1587         0x1D70D => [0x3C3],
1588         0x1D71C => [0x3B1],
1589         0x1D71D => [0x3B2],
1590         0x1D71E => [0x3B3],
1591         0x1D71F => [0x3B4],
1592         0x1D720 => [0x3B5],
1593         0x1D721 => [0x3B6],
1594         0x1D722 => [0x3B7],
1595         0x1D723 => [0x3B8],
1596         0x1D724 => [0x3B9],
1597         0x1D725 => [0x3BA],
1598         0x1D726 => [0x3BB],
1599         0x1D727 => [0x3BC],
1600         0x1D728 => [0x3BD],
1601         0x1D729 => [0x3BE],
1602         0x1D72A => [0x3BF],
1603         0x1D72B => [0x3C0],
1604         0x1D72C => [0x3C1],
1605         0x1D72D => [0x3B8],
1606         0x1D72E => [0x3C3],
1607         0x1D72F => [0x3C4],
1608         0x1D730 => [0x3C5],
1609         0x1D731 => [0x3C6],
1610         0x1D732 => [0x3C7],
1611         0x1D733 => [0x3C8],
1612         0x1D734 => [0x3C9],
1613         0x1D747 => [0x3C3],
1614         0x1D756 => [0x3B1],
1615         0x1D757 => [0x3B2],
1616         0x1D758 => [0x3B3],
1617         0x1D759 => [0x3B4],
1618         0x1D75A => [0x3B5],
1619         0x1D75B => [0x3B6],
1620         0x1D75C => [0x3B7],
1621         0x1D75D => [0x3B8],
1622         0x1D75E => [0x3B9],
1623         0x1D75F => [0x3BA],
1624         0x1D760 => [0x3BB],
1625         0x1D761 => [0x3BC],
1626         0x1D762 => [0x3BD],
1627         0x1D763 => [0x3BE],
1628         0x1D764 => [0x3BF],
1629         0x1D765 => [0x3C0],
1630         0x1D766 => [0x3C1],
1631         0x1D767 => [0x3B8],
1632         0x1D768 => [0x3C3],
1633         0x1D769 => [0x3C4],
1634         0x1D76A => [0x3C5],
1635         0x1D76B => [0x3C6],
1636         0x1D76C => [0x3C7],
1637         0x1D76D => [0x3C8],
1638         0x1D76E => [0x3C9],
1639         0x1D781 => [0x3C3],
1640         0x1D790 => [0x3B1],
1641         0x1D791 => [0x3B2],
1642         0x1D792 => [0x3B3],
1643         0x1D793 => [0x3B4],
1644         0x1D794 => [0x3B5],
1645         0x1D795 => [0x3B6],
1646         0x1D796 => [0x3B7],
1647         0x1D797 => [0x3B8],
1648         0x1D798 => [0x3B9],
1649         0x1D799 => [0x3BA],
1650         0x1D79A => [0x3BB],
1651         0x1D79B => [0x3BC],
1652         0x1D79C => [0x3BD],
1653         0x1D79D => [0x3BE],
1654         0x1D79E => [0x3BF],
1655         0x1D79F => [0x3C0],
1656         0x1D7A0 => [0x3C1],
1657         0x1D7A1 => [0x3B8],
1658         0x1D7A2 => [0x3C3],
1659         0x1D7A3 => [0x3C4],
1660         0x1D7A4 => [0x3C5],
1661         0x1D7A5 => [0x3C6],
1662         0x1D7A6 => [0x3C7],
1663         0x1D7A7 => [0x3C8],
1664         0x1D7A8 => [0x3C9],
1665         0x1D7BB => [0x3C3],
1666         0x3F9 => [0x3C3],
1667         0x1D2C => [0x61],
1668         0x1D2D => [0xE6],
1669         0x1D2E => [0x62],
1670         0x1D30 => [0x64],
1671         0x1D31 => [0x65],
1672         0x1D32 => [0x1DD],
1673         0x1D33 => [0x67],
1674         0x1D34 => [0x68],
1675         0x1D35 => [0x69],
1676         0x1D36 => [0x6A],
1677         0x1D37 => [0x6B],
1678         0x1D38 => [0x6C],
1679         0x1D39 => [0x6D],
1680         0x1D3A => [0x6E],
1681         0x1D3C => [0x6F],
1682         0x1D3D => [0x223],
1683         0x1D3E => [0x70],
1684         0x1D3F => [0x72],
1685         0x1D40 => [0x74],
1686         0x1D41 => [0x75],
1687         0x1D42 => [0x77],
1688         0x213B => [0x66, 0x61, 0x78],
1689         0x3250 => [0x70, 0x74, 0x65],
1690         0x32CC => [0x68, 0x67],
1691         0x32CE => [0x65, 0x76],
1692         0x32CF => [0x6C, 0x74, 0x64],
1693         0x337A => [0x69, 0x75],
1694         0x33DE => [0x76, 0x2215, 0x6D],
1695         0x33DF => [0x61, 0x2215, 0x6D]
1696     ];
1697
1698     /**
1699      * Normalization Combining Classes; Code Points not listed
1700      * got Combining Class 0.
1701      *
1702      * @static
1703      * @var array
1704      * @access private
1705      */
1706     private static $_np_norm_combcls = [
1707         0x334 => 1,
1708         0x335 => 1,
1709         0x336 => 1,
1710         0x337 => 1,
1711         0x338 => 1,
1712         0x93C => 7,
1713         0x9BC => 7,
1714         0xA3C => 7,
1715         0xABC => 7,
1716         0xB3C => 7,
1717         0xCBC => 7,
1718         0x1037 => 7,
1719         0x3099 => 8,
1720         0x309A => 8,
1721         0x94D => 9,
1722         0x9CD => 9,
1723         0xA4D => 9,
1724         0xACD => 9,
1725         0xB4D => 9,
1726         0xBCD => 9,
1727         0xC4D => 9,
1728         0xCCD => 9,
1729         0xD4D => 9,
1730         0xDCA => 9,
1731         0xE3A => 9,
1732         0xF84 => 9,
1733         0x1039 => 9,
1734         0x1714 => 9,
1735         0x1734 => 9,
1736         0x17D2 => 9,
1737         0x5B0 => 10,
1738         0x5B1 => 11,
1739         0x5B2 => 12,
1740         0x5B3 => 13,
1741         0x5B4 => 14,
1742         0x5B5 => 15,
1743         0x5B6 => 16,
1744         0x5B7 => 17,
1745         0x5B8 => 18,
1746         0x5B9 => 19,
1747         0x5BB => 20,
1748         0x5Bc => 21,
1749         0x5BD => 22,
1750         0x5BF => 23,
1751         0x5C1 => 24,
1752         0x5C2 => 25,
1753         0xFB1E => 26,
1754         0x64B => 27,
1755         0x64C => 28,
1756         0x64D => 29,
1757         0x64E => 30,
1758         0x64F => 31,
1759         0x650 => 32,
1760         0x651 => 33,
1761         0x652 => 34,
1762         0x670 => 35,
1763         0x711 => 36,
1764         0xC55 => 84,
1765         0xC56 => 91,
1766         0xE38 => 103,
1767         0xE39 => 103,
1768         0xE48 => 107,
1769         0xE49 => 107,
1770         0xE4A => 107,
1771         0xE4B => 107,
1772         0xEB8 => 118,
1773         0xEB9 => 118,
1774         0xEC8 => 122,
1775         0xEC9 => 122,
1776         0xECA => 122,
1777         0xECB => 122,
1778         0xF71 => 129,
1779         0xF72 => 130,
1780         0xF7A => 130,
1781         0xF7B => 130,
1782         0xF7C => 130,
1783         0xF7D => 130,
1784         0xF80 => 130,
1785         0xF74 => 132,
1786         0x321 => 202,
1787         0x322 => 202,
1788         0x327 => 202,
1789         0x328 => 202,
1790         0x31B => 216,
1791         0xF39 => 216,
1792         0x1D165 => 216,
1793         0x1D166 => 216,
1794         0x1D16E => 216,
1795         0x1D16F => 216,
1796         0x1D170 => 216,
1797         0x1D171 => 216,
1798         0x1D172 => 216,
1799         0x302A => 218,
1800         0x316 => 220,
1801         0x317 => 220,
1802         0x318 => 220,
1803         0x319 => 220,
1804         0x31C => 220,
1805         0x31D => 220,
1806         0x31E => 220,
1807         0x31F => 220,
1808         0x320 => 220,
1809         0x323 => 220,
1810         0x324 => 220,
1811         0x325 => 220,
1812         0x326 => 220,
1813         0x329 => 220,
1814         0x32A => 220,
1815         0x32B => 220,
1816         0x32C => 220,
1817         0x32D => 220,
1818         0x32E => 220,
1819         0x32F => 220,
1820         0x330 => 220,
1821         0x331 => 220,
1822         0x332 => 220,
1823         0x333 => 220,
1824         0x339 => 220,
1825         0x33A => 220,
1826         0x33B => 220,
1827         0x33C => 220,
1828         0x347 => 220,
1829         0x348 => 220,
1830         0x349 => 220,
1831         0x34D => 220,
1832         0x34E => 220,
1833         0x353 => 220,
1834         0x354 => 220,
1835         0x355 => 220,
1836         0x356 => 220,
1837         0x591 => 220,
1838         0x596 => 220,
1839         0x59B => 220,
1840         0x5A3 => 220,
1841         0x5A4 => 220,
1842         0x5A5 => 220,
1843         0x5A6 => 220,
1844         0x5A7 => 220,
1845         0x5AA => 220,
1846         0x655 => 220,
1847         0x656 => 220,
1848         0x6E3 => 220,
1849         0x6EA => 220,
1850         0x6ED => 220,
1851         0x731 => 220,
1852         0x734 => 220,
1853         0x737 => 220,
1854         0x738 => 220,
1855         0x739 => 220,
1856         0x73B => 220,
1857         0x73C => 220,
1858         0x73E => 220,
1859         0x742 => 220,
1860         0x744 => 220,
1861         0x746 => 220,
1862         0x748 => 220,
1863         0x952 => 220,
1864         0xF18 => 220,
1865         0xF19 => 220,
1866         0xF35 => 220,
1867         0xF37 => 220,
1868         0xFC6 => 220,
1869         0x193B => 220,
1870         0x20E8 => 220,
1871         0x1D17B => 220,
1872         0x1D17C => 220,
1873         0x1D17D => 220,
1874         0x1D17E => 220,
1875         0x1D17F => 220,
1876         0x1D180 => 220,
1877         0x1D181 => 220,
1878         0x1D182 => 220,
1879         0x1D18A => 220,
1880         0x1D18B => 220,
1881         0x59A => 222,
1882         0x5AD => 222,
1883         0x1929 => 222,
1884         0x302D => 222,
1885         0x302E => 224,
1886         0x302F => 224,
1887         0x1D16D => 226,
1888         0x5AE => 228,
1889         0x18A9 => 228,
1890         0x302B => 228,
1891         0x300 => 230,
1892         0x301 => 230,
1893         0x302 => 230,
1894         0x303 => 230,
1895         0x304 => 230,
1896         0x305 => 230,
1897         0x306 => 230,
1898         0x307 => 230,
1899         0x308 => 230,
1900         0x309 => 230,
1901         0x30A => 230,
1902         0x30B => 230,
1903         0x30C => 230,
1904         0x30D => 230,
1905         0x30E => 230,
1906         0x30F => 230,
1907         0x310 => 230,
1908         0x311 => 230,
1909         0x312 => 230,
1910         0x313 => 230,
1911         0x314 => 230,
1912         0x33D => 230,
1913         0x33E => 230,
1914         0x33F => 230,
1915         0x340 => 230,
1916         0x341 => 230,
1917         0x342 => 230,
1918         0x343 => 230,
1919         0x344 => 230,
1920         0x346 => 230,
1921         0x34A => 230,
1922         0x34B => 230,
1923         0x34C => 230,
1924         0x350 => 230,
1925         0x351 => 230,
1926         0x352 => 230,
1927         0x357 => 230,
1928         0x363 => 230,
1929         0x364 => 230,
1930         0x365 => 230,
1931         0x366 => 230,
1932         0x367 => 230,
1933         0x368 => 230,
1934         0x369 => 230,
1935         0x36A => 230,
1936         0x36B => 230,
1937         0x36C => 230,
1938         0x36D => 230,
1939         0x36E => 230,
1940         0x36F => 230,
1941         0x483 => 230,
1942         0x484 => 230,
1943         0x485 => 230,
1944         0x486 => 230,
1945         0x592 => 230,
1946         0x593 => 230,
1947         0x594 => 230,
1948         0x595 => 230,
1949         0x597 => 230,
1950         0x598 => 230,
1951         0x599 => 230,
1952         0x59C => 230,
1953         0x59D => 230,
1954         0x59E => 230,
1955         0x59F => 230,
1956         0x5A0 => 230,
1957         0x5A1 => 230,
1958         0x5A8 => 230,
1959         0x5A9 => 230,
1960         0x5AB => 230,
1961         0x5AC => 230,
1962         0x5AF => 230,
1963         0x5C4 => 230,
1964         0x610 => 230,
1965         0x611 => 230,
1966         0x612 => 230,
1967         0x613 => 230,
1968         0x614 => 230,
1969         0x615 => 230,
1970         0x653 => 230,
1971         0x654 => 230,
1972         0x657 => 230,
1973         0x658 => 230,
1974         0x6D6 => 230,
1975         0x6D7 => 230,
1976         0x6D8 => 230,
1977         0x6D9 => 230,
1978         0x6DA => 230,
1979         0x6DB => 230,
1980         0x6DC => 230,
1981         0x6DF => 230,
1982         0x6E0 => 230,
1983         0x6E1 => 230,
1984         0x6E2 => 230,
1985         0x6E4 => 230,
1986         0x6E7 => 230,
1987         0x6E8 => 230,
1988         0x6EB => 230,
1989         0x6EC => 230,
1990         0x730 => 230,
1991         0x732 => 230,
1992         0x733 => 230,
1993         0x735 => 230,
1994         0x736 => 230,
1995         0x73A => 230,
1996         0x73D => 230,
1997         0x73F => 230,
1998         0x740 => 230,
1999         0x741 => 230,
2000         0x743 => 230,
2001         0x745 => 230,
2002         0x747 => 230,
2003         0x749 => 230,
2004         0x74A => 230,
2005         0x951 => 230,
2006         0x953 => 230,
2007         0x954 => 230,
2008         0xF82 => 230,
2009         0xF83 => 230,
2010         0xF86 => 230,
2011         0xF87 => 230,
2012         0x170D => 230,
2013         0x193A => 230,
2014         0x20D0 => 230,
2015         0x20D1 => 230,
2016         0x20D4 => 230,
2017         0x20D5 => 230,
2018         0x20D6 => 230,
2019         0x20D7 => 230,
2020         0x20DB => 230,
2021         0x20DC => 230,
2022         0x20E1 => 230,
2023         0x20E7 => 230,
2024         0x20E9 => 230,
2025         0xFE20 => 230,
2026         0xFE21 => 230,
2027         0xFE22 => 230,
2028         0xFE23 => 230,
2029         0x1D185 => 230,
2030         0x1D186 => 230,
2031         0x1D187 => 230,
2032         0x1D189 => 230,
2033         0x1D188 => 230,
2034         0x1D1AA => 230,
2035         0x1D1AB => 230,
2036         0x1D1AC => 230,
2037         0x1D1AD => 230,
2038         0x315 => 232,
2039         0x31A => 232,
2040         0x302C => 232,
2041         0x35F => 233,
2042         0x362 => 233,
2043         0x35D => 234,
2044         0x35E => 234,
2045         0x360 => 234,
2046         0x361 => 234,
2047         0x345 => 240
2048     ];
2049     // }}}
2050
2051     // {{{ properties
2052     /**
2053      * @var string
2054      * @access private
2055      */
2056     private $_punycode_prefix = 'xn--';
2057
2058     /**
2059      * @access private
2060      */
2061     private $_invalid_ucs = 0x80000000;
2062
2063     /**
2064      * @access private
2065      */
2066     private $_max_ucs = 0x10FFFF;
2067
2068     /**
2069      * @var int
2070      * @access private
2071      */
2072     private $_base = 36;
2073
2074     /**
2075      * @var int
2076      * @access private
2077      */
2078     private $_tmin = 1;
2079
2080     /**
2081      * @var int
2082      * @access private
2083      */
2084     private $_tmax = 26;
2085
2086     /**
2087      * @var int
2088      * @access private
2089      */
2090     private $_skew = 38;
2091
2092     /**
2093      * @var int
2094      * @access private
2095      */
2096     private $_damp = 700;
2097
2098     /**
2099      * @var int
2100      * @access private
2101      */
2102     private $_initial_bias = 72;
2103
2104     /**
2105      * @var int
2106      * @access private
2107      */
2108     private $_initial_n = 0x80;
2109
2110     /**
2111      * @var int
2112      * @access private
2113      */
2114     private $_slast;
2115
2116     /**
2117      * @access private
2118      */
2119     private $_sbase = 0xAC00;
2120
2121     /**
2122      * @access private
2123      */
2124     private $_lbase = 0x1100;
2125
2126     /**
2127      * @access private
2128      */
2129     private $_vbase = 0x1161;
2130
2131     /**
2132      * @access private
2133      */
2134     private $_tbase = 0x11a7;
2135
2136     /**
2137      * @var int
2138      * @access private
2139      */
2140     private $_lcount = 19;
2141
2142     /**
2143      * @var int
2144      * @access private
2145      */
2146     private $_vcount = 21;
2147
2148     /**
2149      * @var int
2150      * @access private
2151      */
2152     private $_tcount = 28;
2153
2154     /**
2155      * vcount * tcount
2156      *
2157      * @var int
2158      * @access private
2159      */
2160     private $_ncount = 588;
2161
2162     /**
2163      * lcount * tcount * vcount
2164      *
2165      * @var int
2166      * @access private
2167      */
2168     private $_scount = 11172;
2169
2170     /**
2171      * Default encoding for encode()'s input and decode()'s output is UTF-8;
2172      * Other possible encodings are ucs4_string and ucs4_array
2173      * See {@link setParams()} for how to select these
2174      *
2175      * @var bool
2176      * @access private
2177      */
2178     private $_api_encoding = 'utf8';
2179
2180     /**
2181      * Overlong UTF-8 encodings are forbidden
2182      *
2183      * @var bool
2184      * @access private
2185      */
2186     private $_allow_overlong = false;
2187
2188     /**
2189      * Behave strict or not
2190      *
2191      * @var bool
2192      * @access private
2193      */
2194     private $_strict_mode = false;
2195
2196     /**
2197      * IDNA-version to use
2198      *
2199      * Values are "2003" and "2008".
2200      * Defaults to "2003", since that was the original version and for
2201      * compatibility with previous versions of this library.
2202      * If you need to encode "new" characters like the German "Eszett",
2203      * please switch to 2008 first before encoding.
2204      *
2205      * @var bool
2206      * @access private
2207      */
2208     private $_version = '2003';
2209
2210     /**
2211      * Cached value indicating whether or not mbstring function overloading is
2212      * on for strlen
2213      *
2214      * This is cached for optimal performance.
2215      *
2216      * @var boolean
2217      * @see Net_IDNA2::_byteLength()
2218      */
2219     private static $_mb_string_overload = null;
2220     // }}}
2221
2222
2223     // {{{ constructor
2224     /**
2225      * Constructor
2226      *
2227      * @param array|null $options Options to initialise the object with
2228      *
2229      * @access public
2230      * @see    setParams()
2231      */
2232     public function __construct($options = null)
2233     {
2234         $this->_slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount;
2235
2236         if (is_array($options)) {
2237             $this->setParams($options);
2238         }
2239
2240         // populate mbstring overloading cache if not set
2241         if (self::$_mb_string_overload === null) {
2242             self::$_mb_string_overload = (extension_loaded('mbstring')
2243                 && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
2244         }
2245     }
2246     // }}}
2247
2248
2249     /**
2250      * Sets a new option value. Available options and values:
2251      *
2252      * [utf8 -     Use either UTF-8 or ISO-8859-1 as input (true for UTF-8, false
2253      *             otherwise); The output is always UTF-8]
2254      * [overlong - Unicode does not allow unnecessarily long encodings of chars,
2255      *             to allow this, set this parameter to true, else to false;
2256      *             default is false.]
2257      * [strict -   true: strict mode, good for registration purposes - Causes errors
2258      *             on failures; false: loose mode, ideal for "wildlife" applications
2259      *             by silently ignoring errors and returning the original input instead]
2260      *
2261      * @param mixed $option Parameter to set (string: single parameter; array of Parameter => Value pairs)
2262      * @param string|false $value Value to use (if parameter 1 is a string)
2263      *
2264      * @return bool       true on success, false otherwise
2265      * @access public
2266      */
2267     public function setParams($option, $value = false): bool
2268     {
2269         if (!is_array($option)) {
2270             $option = [$option => $value];
2271         }
2272
2273         foreach ($option as $k => $v) {
2274             switch ($k) {
2275                 case 'encoding':
2276                     switch ($v) {
2277                         case 'utf8':
2278                         case 'ucs4_string':
2279                         case 'ucs4_array':
2280                             $this->_api_encoding = $v;
2281                             break;
2282
2283                         default:
2284                             throw new InvalidArgumentException('Set Parameter: Unknown parameter ' . $v . ' for option ' . $k);
2285                     }
2286
2287                     break;
2288
2289                 case 'overlong':
2290                     $this->_allow_overlong = ($v) ? true : false;
2291                     break;
2292
2293                 case 'strict':
2294                     $this->_strict_mode = ($v) ? true : false;
2295                     break;
2296
2297                 case 'version':
2298                     if (in_array($v, ['2003', '2008'])) {
2299                         $this->_version = $v;
2300                     } else {
2301                         throw new InvalidArgumentException('Set Parameter: Invalid parameter ' . $v . ' for option ' . $k);
2302                     }
2303                     break;
2304
2305                 default:
2306                     return false;
2307             }
2308         }
2309
2310         return true;
2311     }
2312
2313     /**
2314      * Encode a given UTF-8 domain name.
2315      *
2316      * @param string $decoded Domain name (UTF-8 or UCS-4)
2317      * @param string|false $one_time_encoding Desired input encoding, see {@link set_parameter}
2318      *                                  If not given will use default-encoding
2319      *
2320      * @return mixed Encoded Domain name (ACE string) / processed string
2321      * @throws Exception
2322      * @access public
2323      */
2324     public function encode(string $decoded, $one_time_encoding = false)
2325     {
2326         // Forcing conversion of input to UCS4 array
2327         // If one time encoding is given, use this, else the objects property
2328         switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
2329             case 'utf8':
2330                 $decoded = $this->_utf8_to_ucs4($decoded);
2331                 break;
2332             case 'ucs4_string':
2333                 $decoded = $this->_ucs4_string_to_ucs4($decoded);
2334             // no break
2335             case 'ucs4_array':
2336                 break;
2337             default:
2338                 throw new InvalidArgumentException('Unsupported input format');
2339         }
2340
2341         // No input, no output, what else did you expect?
2342         if (empty($decoded)) {
2343             return '';
2344         }
2345
2346         // Anchors for iteration
2347         $last_begin = 0;
2348         // Output string
2349         $output = '';
2350
2351         foreach ($decoded as $k => $v) {
2352             // Make sure to use just the plain dot
2353             switch ($v) {
2354                 case 0x3002:
2355                 case 0xFF0E:
2356                 case 0xFF61:
2357                     $decoded[$k] = 0x2E;
2358                 // It's right, no break here
2359                 // The codepoints above have to be converted to dots anyway
2360
2361                 // Stumbling across an anchoring character
2362                 // no break
2363                 case 0x2E:
2364                 case 0x2F:
2365                 case 0x3A:
2366                 case 0x3F:
2367                 case 0x40:
2368                     // Neither email addresses nor URLs allowed in strict mode
2369                     if ($this->_strict_mode) {
2370                         throw new InvalidArgumentException('Neither email addresses nor URLs are allowed in strict mode.');
2371                     }
2372                     // Skip first char
2373                     if ($k) {
2374                         $encoded = '';
2375                         $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k) - $last_begin)));
2376                         if ($encoded) {
2377                             $output .= $encoded;
2378                         } else {
2379                             $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k) - $last_begin)));
2380                         }
2381                         $output .= chr($decoded[$k]);
2382                     }
2383                     $last_begin = $k + 1;
2384             }
2385         }
2386         // Catch the rest of the string
2387         if ($last_begin) {
2388             $inp_len = sizeof($decoded);
2389             $encoded = '';
2390             $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len) - $last_begin)));
2391             if ($encoded) {
2392                 $output .= $encoded;
2393             } else {
2394                 $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len) - $last_begin)));
2395             }
2396             return $output;
2397         }
2398
2399         if ($output = $this->_encode($decoded)) {
2400             return $output;
2401         }
2402
2403         return $this->_ucs4_to_utf8($decoded);
2404     }
2405
2406     /**
2407      * Decode a given ACE domain name.
2408      *
2409      * @param string $input Domain name (ACE string)
2410      * @param string|false $one_time_encoding Desired output encoding, see {@link set_parameter}
2411      *
2412      * @return mixed                   Decoded Domain name (UTF-8 or UCS-4) / processed string
2413      * @throws Exception
2414      * @access public
2415      */
2416     public function decode(string $input, $one_time_encoding = false)
2417     {
2418         // Optionally set
2419         if ($one_time_encoding) {
2420             switch ($one_time_encoding) {
2421                 case 'utf8':
2422                 case 'ucs4_string':
2423                 case 'ucs4_array':
2424                     break;
2425                 default:
2426                     throw new InvalidArgumentException('Unknown encoding ' . $one_time_encoding);
2427             }
2428         }
2429         // Make sure to drop any newline characters around
2430         $input = trim($input);
2431
2432         // Negotiate input and try to determine, whether it is a plain string,
2433         // an email address or something like a complete URL
2434         if (strpos($input, '@')) { // Maybe it is an email address
2435             // No no in strict mode
2436             if ($this->_strict_mode) {
2437                 throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
2438             }
2439             list($email_pref, $input) = explode('@', $input, 2);
2440             $arr = explode('.', $input);
2441             foreach ($arr as $k => $v) {
2442                 $conv = $this->_decode($v);
2443                 if ($conv) {
2444                     $arr[$k] = $conv;
2445                 }
2446             }
2447             $return = $email_pref . '@' . join('.', $arr);
2448         } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters)
2449             // No no in strict mode
2450             if ($this->_strict_mode) {
2451                 throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
2452             }
2453
2454             $parsed = parse_url($input);
2455             if (isset($parsed['host'])) {
2456                 $arr = explode('.', $parsed['host']);
2457                 foreach ($arr as $k => $v) {
2458                     $conv = $this->_decode($v);
2459                     if ($conv) {
2460                         $arr[$k] = $conv;
2461                     }
2462                 }
2463                 $parsed['host'] = join('.', $arr);
2464                 if (isset($parsed['scheme'])) {
2465                     $parsed['scheme'] .= (strtolower($parsed['scheme']) == 'mailto') ? ':' : '://';
2466                 }
2467                 $return = $this->_unparse_url($parsed);
2468             } else { // parse_url seems to have failed, try without it
2469                 $arr = explode('.', $input);
2470                 foreach ($arr as $k => $v) {
2471                     $conv = $this->_decode($v);
2472                     if ($conv) {
2473                         $arr[$k] = $conv;
2474                     }
2475                 }
2476                 $return = join('.', $arr);
2477             }
2478         } else { // Otherwise we consider it being a pure domain name string
2479             $return = $this->_decode($input);
2480         }
2481         // The output is UTF-8 by default, other output formats need conversion here
2482         // If one time encoding is given, use this, else the objects property
2483         switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
2484             case 'utf8':
2485                 return $return;
2486                 break;
2487             case 'ucs4_string':
2488                 return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return));
2489                 break;
2490             case 'ucs4_array':
2491                 return $this->_utf8_to_ucs4($return);
2492                 break;
2493             default:
2494                 throw new InvalidArgumentException('Unsupported output format');
2495         }
2496     }
2497
2498
2499     // {{{ private
2500
2501     /**
2502      * Opposite function to parse_url()
2503      *
2504      * Inspired by code from comments of php.net-documentation for parse_url()
2505      *
2506      * @param array $parts_arr parts (strings) as returned by parse_url()
2507      *
2508      * @return string
2509      * @access private
2510      */
2511     private function _unparse_url(array $parts_arr): string
2512     {
2513         if (!empty($parts_arr['scheme'])) {
2514             $ret_url = $parts_arr['scheme'];
2515         }
2516         if (!empty($parts_arr['user'])) {
2517             $ret_url .= $parts_arr['user'];
2518             if (!empty($parts_arr['pass'])) {
2519                 $ret_url .= ':' . $parts_arr['pass'];
2520             }
2521             $ret_url .= '@';
2522         }
2523         $ret_url .= $parts_arr['host'];
2524         if (!empty($parts_arr['port'])) {
2525             $ret_url .= ':' . $parts_arr['port'];
2526         }
2527         $ret_url .= $parts_arr['path'];
2528         if (!empty($parts_arr['query'])) {
2529             $ret_url .= '?' . $parts_arr['query'];
2530         }
2531         if (!empty($parts_arr['fragment'])) {
2532             $ret_url .= '#' . $parts_arr['fragment'];
2533         }
2534         return $ret_url;
2535     }
2536
2537     /**
2538      * The actual encoding algorithm.
2539      *
2540      * @param array of strings $decoded Decoded string which should be encoded
2541      *
2542      * @return string         Encoded string
2543      * @throws Exception
2544      * @access private
2545      */
2546     private function _encode($decoded): string
2547     {
2548         // We cannot encode a domain name containing the Punycode prefix
2549         $extract = self::_byteLength($this->_punycode_prefix);
2550         $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix);
2551         $check_deco = array_slice($decoded, 0, $extract);
2552
2553         if ($check_pref == $check_deco) {
2554             throw new InvalidArgumentException('This is already a punycode string');
2555         }
2556
2557         // We will not try to encode strings consisting of basic code points only
2558         $encodable = false;
2559         foreach ($decoded as $k => $v) {
2560             if ($v > 0x7a) {
2561                 $encodable = true;
2562                 break;
2563             }
2564         }
2565         if (!$encodable) {
2566             if ($this->_strict_mode) {
2567                 throw new InvalidArgumentException('The given string does not contain encodable chars');
2568             }
2569
2570             return false;
2571         }
2572
2573         // Do NAMEPREP
2574         $decoded = $this->_nameprep($decoded);
2575
2576         $deco_len = count($decoded);
2577
2578         // Empty array
2579         if (!$deco_len) {
2580             return false;
2581         }
2582
2583         // How many chars have been consumed
2584         $codecount = 0;
2585
2586         // Start with the prefix; copy it to output
2587         $encoded = $this->_punycode_prefix;
2588
2589         $encoded = '';
2590         // Copy all basic code points to output
2591         for ($i = 0; $i < $deco_len; ++$i) {
2592             $test = $decoded[$i];
2593             // Will match [0-9a-zA-Z-]
2594             if ((0x2F < $test && $test < 0x40)
2595                 || (0x40 < $test && $test < 0x5B)
2596                 || (0x60 < $test && $test <= 0x7B)
2597                 || (0x2D == $test)
2598             ) {
2599                 $encoded .= chr($decoded[$i]);
2600                 $codecount++;
2601             }
2602         }
2603
2604         // All codepoints were basic ones
2605         if ($codecount == $deco_len) {
2606             return $encoded;
2607         }
2608
2609         // Start with the prefix; copy it to output
2610         $encoded = $this->_punycode_prefix . $encoded;
2611
2612         // If we have basic code points in output, add an hyphen to the end
2613         if ($codecount) {
2614             $encoded .= '-';
2615         }
2616
2617         // Now find and encode all non-basic code points
2618         $is_first = true;
2619         $cur_code = $this->_initial_n;
2620         $bias = $this->_initial_bias;
2621         $delta = 0;
2622
2623         while ($codecount < $deco_len) {
2624             // Find the smallest code point >= the current code point and
2625             // remember the last ouccrence of it in the input
2626             for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) {
2627                 if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) {
2628                     $next_code = $decoded[$i];
2629                 }
2630             }
2631
2632             $delta += ($next_code - $cur_code) * ($codecount + 1);
2633             $cur_code = $next_code;
2634
2635             // Scan input again and encode all characters whose code point is $cur_code
2636             for ($i = 0; $i < $deco_len; $i++) {
2637                 if ($decoded[$i] < $cur_code) {
2638                     $delta++;
2639                 } elseif ($decoded[$i] == $cur_code) {
2640                     for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) {
2641                         $t = ($k <= $bias) ?
2642                             $this->_tmin :
2643                             (($k >= $bias + $this->_tmax) ? $this->_tmax : $k - $bias);
2644
2645                         if ($q < $t) {
2646                             break;
2647                         }
2648
2649                         $encoded .= $this->_encodeDigit(ceil($t + (($q - $t) % ($this->_base - $t))));
2650                         $q = ($q - $t) / ($this->_base - $t);
2651                     }
2652
2653                     $encoded .= $this->_encodeDigit($q);
2654                     $bias = $this->_adapt($delta, $codecount + 1, $is_first);
2655                     $codecount++;
2656                     $delta = 0;
2657                     $is_first = false;
2658                 }
2659             }
2660
2661             $delta++;
2662             $cur_code++;
2663         }
2664
2665         return $encoded;
2666     }
2667
2668     /**
2669      * The actual decoding algorithm.
2670      *
2671      * @param string $encoded Encoded string which should be decoded
2672      *
2673      * @return string         Decoded string
2674      * @throws Exception
2675      * @access private
2676      */
2677     private function _decode($encoded): string
2678     {
2679         // We do need to find the Punycode prefix
2680         if (!preg_match('!^' . preg_quote($this->_punycode_prefix, '!') . '!', $encoded)) {
2681             return false;
2682         }
2683
2684         $encode_test = preg_replace('!^' . preg_quote($this->_punycode_prefix, '!') . '!', '', $encoded);
2685
2686         // If nothing left after removing the prefix, it is hopeless
2687         if (!$encode_test) {
2688             return false;
2689         }
2690
2691         // Find last occurrence of the delimiter
2692         $delim_pos = strrpos($encoded, '-');
2693
2694         if ($delim_pos > self::_byteLength($this->_punycode_prefix)) {
2695             for ($k = self::_byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
2696                 $decoded[] = ord($encoded{$k});
2697             }
2698         } else {
2699             $decoded = [];
2700         }
2701
2702         $deco_len = count($decoded);
2703         $enco_len = self::_byteLength($encoded);
2704
2705         // Wandering through the strings; init
2706         $is_first = true;
2707         $bias = $this->_initial_bias;
2708         $idx = 0;
2709         $char = $this->_initial_n;
2710
2711         for ($enco_idx = ($delim_pos) ? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
2712             for ($old_idx = $idx, $w = 1, $k = $this->_base; 1; $k += $this->_base) {
2713                 $digit = $this->_decodeDigit($encoded{$enco_idx++});
2714                 $idx += $digit * $w;
2715
2716                 $t = ($k <= $bias) ?
2717                     $this->_tmin :
2718                     (($k >= $bias + $this->_tmax) ? $this->_tmax : ($k - $bias));
2719
2720                 if ($digit < $t) {
2721                     break;
2722                 }
2723
2724                 $w = (int)($w * ($this->_base - $t));
2725             }
2726
2727             $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first);
2728             $is_first = false;
2729             $char += (int)($idx / ($deco_len + 1));
2730             $idx %= ($deco_len + 1);
2731
2732             if ($deco_len > 0) {
2733                 // Make room for the decoded char
2734                 for ($i = $deco_len; $i > $idx; $i--) {
2735                     $decoded[$i] = $decoded[($i - 1)];
2736                 }
2737             }
2738
2739             $decoded[$idx++] = $char;
2740         }
2741
2742         return $this->_ucs4_to_utf8($decoded);
2743     }
2744
2745     /**
2746      * Adapt the bias according to the current code point and position.
2747      *
2748      * @param int $delta ...
2749      * @param int $npoints ...
2750      * @param bool $is_first ...
2751      *
2752      * @return int
2753      * @access private
2754      */
2755     private function _adapt(int $delta, int $npoints, bool $is_first): int
2756     {
2757         $delta = (int)($is_first ? ($delta / $this->_damp) : ($delta / 2));
2758         $delta += (int)($delta / $npoints);
2759
2760         for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) {
2761             $delta = (int)($delta / ($this->_base - $this->_tmin));
2762         }
2763
2764         return (int)($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew));
2765     }
2766
2767     /**
2768      * Encoding a certain digit.
2769      *
2770      * @param int $d One digit to encode
2771      *
2772      * @return string (char)  Encoded digit
2773      * @access private
2774      */
2775     private function _encodeDigit(int $d): string
2776     {
2777         return chr($d + 22 + 75 * ($d < 26));
2778     }
2779
2780     /**
2781      * Decode a certain digit.
2782      *
2783      * @param string (char) $cp One digit (character) to decode
2784      *
2785      * @return int     Decoded digit
2786      * @access private
2787      */
2788     private function _decodeDigit(string $cp): int
2789     {
2790         $cp = ord($cp);
2791         return ($cp - 48 < 10) ? $cp - 22 : (($cp - 65 < 26) ? $cp - 65 : (($cp - 97 < 26) ? $cp - 97 : $this->_base));
2792     }
2793
2794     /**
2795      * Do Nameprep according to RFC3491 and RFC3454.
2796      *
2797      * @param array $input Unicode Characters
2798      *
2799      * @return array of strings      Unicode Characters, Nameprep'd
2800      * @throws Exception
2801      * @access private
2802      */
2803     private function _nameprep(array $input): array
2804     {
2805         $output = [];
2806
2807         // Walking through the input array, performing the required steps on each of
2808         // the input chars and putting the result into the output array
2809         // While mapping required chars we apply the canonical ordering
2810
2811         foreach ($input as $v) {
2812             // Map to nothing == skip that code point
2813             if (in_array($v, self::$_np_map_nothing)) {
2814                 continue;
2815             }
2816
2817             // Try to find prohibited input
2818             if (in_array($v, self::$_np_prohibit) || in_array($v, self::$_general_prohibited)) {
2819                 throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
2820             }
2821
2822             foreach (self::$_np_prohibit_ranges as $range) {
2823                 if ($range[0] <= $v && $v <= $range[1]) {
2824                     throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
2825                 }
2826             }
2827
2828             // Hangul syllable decomposition
2829             if (0xAC00 <= $v && $v <= 0xD7AF) {
2830                 foreach ($this->_hangulDecompose($v) as $out) {
2831                     $output[] = $out;
2832                 }
2833             } elseif (($this->_version == '2003') && isset(self::$_np_replacemaps[$v])) {
2834                 // There's a decomposition mapping for that code point
2835                 // Decompositions only in version 2003 (original) of IDNA
2836                 foreach ($this->_applyCannonicalOrdering(self::$_np_replacemaps[$v]) as $out) {
2837                     $output[] = $out;
2838                 }
2839             } else {
2840                 $output[] = $v;
2841             }
2842         }
2843
2844         // Combine code points
2845
2846         $last_class = 0;
2847         $last_starter = 0;
2848         $out_len = count($output);
2849
2850         for ($i = 0; $i < $out_len; ++$i) {
2851             $class = $this->_getCombiningClass($output[$i]);
2852
2853             if ((!$last_class || $last_class != $class) && $class) {
2854                 // Try to match
2855                 $seq_len = $i - $last_starter;
2856                 $out = $this->_combine(array_slice($output, $last_starter, $seq_len));
2857
2858                 // On match: Replace the last starter with the composed character and remove
2859                 // the now redundant non-starter(s)
2860                 if ($out) {
2861                     $output[$last_starter] = $out;
2862
2863                     if (count($out) != $seq_len) {
2864                         for ($j = $i + 1; $j < $out_len; ++$j) {
2865                             $output[$j - 1] = $output[$j];
2866                         }
2867
2868                         unset($output[$out_len]);
2869                     }
2870
2871                     // Rewind the for loop by one, since there can be more possible compositions
2872                     $i--;
2873                     $out_len--;
2874                     $last_class = ($i == $last_starter) ? 0 : $this->_getCombiningClass($output[$i - 1]);
2875
2876                     continue;
2877                 }
2878             }
2879
2880             // The current class is 0
2881             if (!$class) {
2882                 $last_starter = $i;
2883             }
2884
2885             $last_class = $class;
2886         }
2887
2888         return $output;
2889     }
2890
2891     /**
2892      * Decomposes a Hangul syllable
2893      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
2894      *
2895      * @param int $char 32bit UCS4 code point
2896      *
2897      * @return array        Either Hangul Syllable decomposed or original 32bit
2898      *                      value as one value array
2899      * @access private
2900      */
2901     private function _hangulDecompose(int $char): array
2902     {
2903         $sindex = $char - $this->_sbase;
2904
2905         if ($sindex < 0 || $sindex >= $this->_scount) {
2906             return [$char];
2907         }
2908
2909         $result = [];
2910         $T = $this->_tbase + $sindex % $this->_tcount;
2911         $result[] = (int)($this->_lbase + $sindex / $this->_ncount);
2912         $result[] = (int)($this->_vbase + ($sindex % $this->_ncount) / $this->_tcount);
2913
2914         if ($T != $this->_tbase) {
2915             $result[] = $T;
2916         }
2917
2918         return $result;
2919     }
2920
2921     /**
2922      * Ccomposes a Hangul syllable
2923      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
2924      *
2925      * @param array $input Decomposed UCS4 sequence
2926      *
2927      * @return array       UCS4 sequence with syllables composed
2928      * @access private
2929      */
2930     private function _hangulCompose(array $input): array
2931     {
2932         $inp_len = count($input);
2933
2934         if (!$inp_len) {
2935             return [];
2936         }
2937
2938         $result = [];
2939         $last = $input[0];
2940         $result[] = $last; // copy first char from input to output
2941
2942         for ($i = 1; $i < $inp_len; ++$i) {
2943             $char = $input[$i];
2944
2945             // Find out, wether two current characters from L and V
2946             $lindex = $last - $this->_lbase;
2947
2948             if (0 <= $lindex && $lindex < $this->_lcount) {
2949                 $vindex = $char - $this->_vbase;
2950
2951                 if (0 <= $vindex && $vindex < $this->_vcount) {
2952                     // create syllable of form LV
2953                     $last = ($this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount);
2954                     $out_off = count($result) - 1;
2955                     $result[$out_off] = $last; // reset last
2956
2957                     // discard char
2958                     continue;
2959                 }
2960             }
2961
2962             // Find out, wether two current characters are LV and T
2963             $sindex = $last - $this->_sbase;
2964
2965             if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount) == 0) {
2966                 $tindex = $char - $this->_tbase;
2967
2968                 if (0 <= $tindex && $tindex <= $this->_tcount) {
2969                     // create syllable of form LVT
2970                     $last += $tindex;
2971                     $out_off = count($result) - 1;
2972                     $result[$out_off] = $last; // reset last
2973
2974                     // discard char
2975                     continue;
2976                 }
2977             }
2978
2979             // if neither case was true, just add the character
2980             $last = $char;
2981             $result[] = $char;
2982         }
2983
2984         return $result;
2985     }
2986
2987     /**
2988      * Returns the combining class of a certain wide char.
2989      *
2990      * @param integer $char Wide char to check (32bit integer)
2991      *
2992      * @return int      Combining class if found, else 0
2993      * @access private
2994      */
2995     private function _getCombiningClass(int $char): int
2996     {
2997         return isset(self::$_np_norm_combcls[$char]) ? self::$_np_norm_combcls[$char] : 0;
2998     }
2999
3000     /**
3001      * Apllies the canonical ordering of a decomposed UCS4 sequence.
3002      *
3003      * @param array $input Decomposed UCS4 sequence
3004      *
3005      * @return array       Ordered USC4 sequence
3006      * @access private
3007      */
3008     private function _applyCannonicalOrdering(array $input): array
3009     {
3010         $swap = true;
3011         $size = count($input);
3012
3013         while ($swap) {
3014             $swap = false;
3015             $last = $this->_getCombiningClass($input[0]);
3016
3017             for ($i = 0; $i < $size - 1; ++$i) {
3018                 $next = $this->_getCombiningClass($input[$i + 1]);
3019
3020                 if ($next != 0 && $last > $next) {
3021                     // Move item leftward until it fits
3022                     for ($j = $i + 1; $j > 0; --$j) {
3023                         if ($this->_getCombiningClass($input[$j - 1]) <= $next) {
3024                             break;
3025                         }
3026
3027                         $t = $input[$j];
3028                         $input[$j] = $input[$j - 1];
3029                         $input[$j - 1] = $t;
3030                         $swap = 1;
3031                     }
3032
3033                     // Reentering the loop looking at the old character again
3034                     $next = $last;
3035                 }
3036
3037                 $last = $next;
3038             }
3039         }
3040
3041         return $input;
3042     }
3043
3044     /**
3045      * Do composition of a sequence of starter and non-starter.
3046      *
3047      * @param array $input UCS4 Decomposed sequence
3048      *
3049      * @return array|false       Ordered USC4 sequence
3050      * @access private
3051      */
3052     private function _combine($input)
3053     {
3054         $inp_len = count($input);
3055
3056         // Is it a Hangul syllable?
3057         if (1 != $inp_len) {
3058             $hangul = $this->_hangulCompose($input);
3059
3060             // This place is probably wrong
3061             if (count($hangul) != $inp_len) {
3062                 return $hangul;
3063             }
3064         }
3065
3066         foreach (self::$_np_replacemaps as $np_src => $np_target) {
3067             if ($np_target[0] != $input[0]) {
3068                 continue;
3069             }
3070
3071             if (count($np_target) != $inp_len) {
3072                 continue;
3073             }
3074
3075             $hit = false;
3076
3077             foreach ($input as $k2 => $v2) {
3078                 if ($v2 == $np_target[$k2]) {
3079                     $hit = true;
3080                 } else {
3081                     $hit = false;
3082                     break;
3083                 }
3084             }
3085
3086             if ($hit) {
3087                 return $np_src;
3088             }
3089         }
3090
3091         return false;
3092     }
3093
3094     /**
3095      * This converts an UTF-8 encoded string to its UCS-4 (array) representation
3096      * By talking about UCS-4 we mean arrays of 32bit integers representing
3097      * each of the "chars". This is due to PHP not being able to handle strings with
3098      * bit depth different from 8. This applies to the reverse method _ucs4_to_utf8(), too.
3099      * The following UTF-8 encodings are supported:
3100      *
3101      * bytes bits  representation
3102      * 1        7  0xxxxxxx
3103      * 2       11  110xxxxx 10xxxxxx
3104      * 3       16  1110xxxx 10xxxxxx 10xxxxxx
3105      * 4       21  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3106      * 5       26  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3107      * 6       31  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3108      *
3109      * Each x represents a bit that can be used to store character data.
3110      *
3111      * @param string $input utf8-encoded string
3112      *
3113      * @return array        ucs4-encoded array
3114      * @throws Exception
3115      * @access private
3116      */
3117     private function _utf8_to_ucs4(string $input): array
3118     {
3119         $output = [];
3120         $out_len = 0;
3121         $inp_len = self::_byteLength($input, '8bit');
3122         $mode = 'next';
3123         $test = 'none';
3124         for ($k = 0; $k < $inp_len; ++$k) {
3125             $v = ord($input{$k}); // Extract byte from input string
3126
3127             if ($v < 128) { // We found an ASCII char - put into string as is
3128                 $output[$out_len] = $v;
3129                 ++$out_len;
3130                 if ('add' == $mode) {
3131                     throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte ' . $k);
3132                 }
3133                 continue;
3134             }
3135             if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char
3136                 $start_byte = $v;
3137                 $mode = 'add';
3138                 $test = 'range';
3139                 if ($v >> 5 == 6) { // &110xxxxx 10xxxxx
3140                     $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left
3141                     $v = ($v - 192) << 6;
3142                 } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx
3143                     $next_byte = 1;
3144                     $v = ($v - 224) << 12;
3145                 } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3146                     $next_byte = 2;
3147                     $v = ($v - 240) << 18;
3148                 } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3149                     $next_byte = 3;
3150                     $v = ($v - 248) << 24;
3151                 } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3152                     $next_byte = 4;
3153                     $v = ($v - 252) << 30;
3154                 } else {
3155                     throw new UnexpectedValueException('This might be UTF-8, but I don\'t understand it at byte ' . $k);
3156                 }
3157                 if ('add' == $mode) {
3158                     $output[$out_len] = (int)$v;
3159                     ++$out_len;
3160                     continue;
3161                 }
3162             }
3163             if ('add' == $mode) {
3164                 if (!$this->_allow_overlong && $test == 'range') {
3165                     $test = 'none';
3166                     if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) {
3167                         throw new OutOfRangeException('Bogus UTF-8 character detected (out of legal range) at byte ' . $k);
3168                     }
3169                 }
3170                 if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx
3171                     $v = ($v - 128) << ($next_byte * 6);
3172                     $output[($out_len - 1)] += $v;
3173                     --$next_byte;
3174                 } else {
3175                     throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte ' . $k);
3176                 }
3177                 if ($next_byte < 0) {
3178                     $mode = 'next';
3179                 }
3180             }
3181         } // for
3182         return $output;
3183     }
3184
3185     /**
3186      * Convert UCS-4 array into UTF-8 string
3187      *
3188      * @param array $input ucs4-encoded array
3189      *
3190      * @return string      utf8-encoded string
3191      * @throws Exception
3192      * @access private
3193      */
3194     private function _ucs4_to_utf8(array $input): string
3195     {
3196         $output = '';
3197
3198         foreach ($input as $v) {
3199             // $v = ord($v);
3200
3201             if ($v < 128) {
3202                 // 7bit are transferred literally
3203                 $output .= chr($v);
3204             } elseif ($v < 1 << 11) {
3205                 // 2 bytes
3206                 $output .= chr(192 + ($v >> 6))
3207                     . chr(128 + ($v & 63));
3208             } elseif ($v < 1 << 16) {
3209                 // 3 bytes
3210                 $output .= chr(224 + ($v >> 12))
3211                     . chr(128 + (($v >> 6) & 63))
3212                     . chr(128 + ($v & 63));
3213             } elseif ($v < 1 << 21) {
3214                 // 4 bytes
3215                 $output .= chr(240 + ($v >> 18))
3216                     . chr(128 + (($v >> 12) & 63))
3217                     . chr(128 + (($v >> 6) & 63))
3218                     . chr(128 + ($v & 63));
3219             } elseif ($v < 1 << 26) {
3220                 // 5 bytes
3221                 $output .= chr(248 + ($v >> 24))
3222                     . chr(128 + (($v >> 18) & 63))
3223                     . chr(128 + (($v >> 12) & 63))
3224                     . chr(128 + (($v >> 6) & 63))
3225                     . chr(128 + ($v & 63));
3226             } elseif ($v < 1 << 31) {
3227                 // 6 bytes
3228                 $output .= chr(252 + ($v >> 30))
3229                     . chr(128 + (($v >> 24) & 63))
3230                     . chr(128 + (($v >> 18) & 63))
3231                     . chr(128 + (($v >> 12) & 63))
3232                     . chr(128 + (($v >> 6) & 63))
3233                     . chr(128 + ($v & 63));
3234             } else {
3235                 throw new UnexpectedValueException('Conversion from UCS-4 to UTF-8 failed: malformed input');
3236             }
3237         }
3238
3239         return $output;
3240     }
3241
3242     /**
3243      * Convert UCS-4 array into UCS-4 string
3244      *
3245      * @param array $input ucs4-encoded array
3246      *
3247      * @return string      ucs4-encoded string
3248      * @throws Exception
3249      * @access private
3250      */
3251     private function _ucs4_to_ucs4_string(array $input): string
3252     {
3253         $output = '';
3254         // Take array values and split output to 4 bytes per value
3255         // The bit mask is 255, which reads &11111111
3256         foreach ($input as $v) {
3257             $output .= ($v & (255 << 24) >> 24) . ($v & (255 << 16) >> 16) . ($v & (255 << 8) >> 8) . ($v & 255);
3258         }
3259         return $output;
3260     }
3261
3262     /**
3263      * Convert UCS-4 string into UCS-4 array
3264      *
3265      * @param string $input ucs4-encoded string
3266      *
3267      * @return array        ucs4-encoded array
3268      * @throws InvalidArgumentException
3269      * @access private
3270      */
3271     private function _ucs4_string_to_ucs4(string $input): array
3272     {
3273         $output = [];
3274
3275         $inp_len = self::_byteLength($input);
3276         // Input length must be dividable by 4
3277         if ($inp_len % 4) {
3278             throw new InvalidArgumentException('Input UCS4 string is broken');
3279         }
3280
3281         // Empty input - return empty output
3282         if (!$inp_len) {
3283             return $output;
3284         }
3285
3286         for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) {
3287             // Increment output position every 4 input bytes
3288             if (!$i % 4) {
3289                 $out_len++;
3290                 $output[$out_len] = 0;
3291             }
3292             $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4)));
3293         }
3294         return $output;
3295     }
3296
3297     /**
3298      * Echo hex representation of UCS4 sequence.
3299      *
3300      * @param array $input UCS4 sequence
3301      * @param bool $include_bit Include bitmask in output
3302      *
3303      * @return void
3304      * @static
3305      * @access private
3306      */
3307     private static function _showHex(array $input, bool $include_bit = false) //: void  XXX PHP: Upgrade to PHP 7.1
3308     {
3309         foreach ($input as $k => $v) {
3310             echo '[', $k, '] => ', sprintf('%X', $v);
3311
3312             if ($include_bit) {
3313                 echo ' (', Net_IDNA2::_showBitmask($v), ')';
3314             }
3315
3316             echo "\n";
3317         }
3318     }
3319
3320     /**
3321      * Gives you a bit representation of given Byte (8 bits), Word (16 bits) or DWord (32 bits)
3322      * Output width is automagically determined
3323      *
3324      * @param int $octet ...
3325      *
3326      * @return string    Bitmask-representation
3327      * @static
3328      * @access private
3329      */
3330     private static function _showBitmask(int $octet): string
3331     {
3332         if ($octet >= (1 << 16)) {
3333             $w = 31;
3334         } elseif ($octet >= (1 << 8)) {
3335             $w = 15;
3336         } else {
3337             $w = 7;
3338         }
3339
3340         $return = '';
3341
3342         for ($i = $w; $i > -1; $i--) {
3343             $return .= ($octet & (1 << $i)) ? '1' : '0';
3344         }
3345
3346         return $return;
3347     }
3348
3349     /**
3350      * Gets the length of a string in bytes even if mbstring function
3351      * overloading is turned on
3352      *
3353      * @param string $string the string for which to get the length.
3354      * @param string $encoding [optional] &mbstring.encoding.parameter;
3355      *
3356      * @return int the length of the string in bytes.
3357      *
3358      * @see Net_IDNA2::$_mb_string_overload
3359      */
3360     private static function _byteLength(string $string, string $encoding = '8bit'): int
3361     {
3362         if (self::$_mb_string_overload) {
3363             return mb_strlen($string, $encoding);
3364         }
3365         return strlen((binary)$string);
3366     }
3367
3368     // }}}}
3369
3370     // {{{ factory
3371     /**
3372      * Attempts to return a concrete IDNA instance for either php4 or php5.
3373      *
3374      * @param array $params Set of paramaters
3375      *
3376      * @return Net_IDNA2
3377      * @access public
3378      */
3379     public static function getInstance(array $params = []): Net_IDNA2
3380     {
3381         return new Net_IDNA2($params);
3382     }
3383     // }}}
3384
3385     // {{{ singleton
3386     /**
3387      * Attempts to return a concrete IDNA instance for either php4 or php5,
3388      * only creating a new instance if no IDNA instance with the same
3389      * parameters currently exists.
3390      *
3391      * @param array $params Set of parameters
3392      *
3393      * @return Net_IDNA2
3394      * @access public
3395      */
3396     public static function singleton(array $params = []): Net_IDNA2
3397     {
3398         static $instances;
3399         if (!isset($instances)) {
3400             $instances = [];
3401         }
3402
3403         $signature = serialize($params);
3404         if (!isset($instances[$signature])) {
3405             $instances[$signature] = Net_IDNA2::getInstance($params);
3406         }
3407
3408         return $instances[$signature];
3409     }
3410     // }}}
3411 }