Source for file idna_convert.class.php

Documentation is available at idna_convert.class.php

  1. <?php
  2. // {{{ license
  3.  
  4. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  5. //
  6. // +----------------------------------------------------------------------+
  7. // | This library is free software; you can redistribute it and/or modify |
  8. // | it under the terms of the GNU Lesser General Public License as       |
  9. // | published by the Free Software Foundation; either version 2.1 of the |
  10. // | License, or (at your option) any later version.                      |
  11. // |                                                                      |
  12. // | This library is distributed in the hope that it will be useful, but  |
  13. // | WITHOUT ANY WARRANTY; without even the implied warranty of           |
  14. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
  15. // | Lesser General Public License for more details.                      |
  16. // |                                                                      |
  17. // | You should have received a copy of the GNU Lesser General Public     |
  18. // | License along with this library; if not, write to the Free Software  |
  19. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 |
  20. // | USA.                                                                 |
  21. // +----------------------------------------------------------------------+
  22. //
  23.  
  24. // }}}
  25.  
  26. /**
  27.  * Encode/decode Internationalized Domain Names.
  28.  *
  29.  * The class allows to convert internationalized domain names
  30.  * (see RFC 3490 for details) as they can be used with various registries worldwide
  31.  * to be translated between their original (localized) form and their encoded form
  32.  * as it will be used in the DNS (Domain Name System).
  33.  *
  34.  * The class provides two public methods, encode() and decode(), which do exactly
  35.  * what you would expect them to do. You are allowed to use complete domain names,
  36.  * simple strings and complete email addresses as well. That means, that you might
  37.  * use any of the following notations:
  38.  *
  39.  * - www.nörgler.com
  40.  * - xn--nrgler-wxa
  41.  * - xn--brse-5qa.xn--knrz-1ra.info
  42.  *
  43.  * Unicode input might be given as either UTF-8 string, UCS-4 string or UCS-4 array.
  44.  * Unicode output is available in the same formats.
  45.  * You can select your preferred format via {@link set_paramter()}.
  46.  *
  47.  * ACE input and output is always expected to be ASCII.
  48.  *
  49.  * @package IDNA Convert
  50.  * @author  Matthias Sommerfeld <mso@phlylabs.de>
  51.  * @copyright 2004-2011 phlyLabs Berlin, http://phlylabs.de
  52.  * @version 0.8.0 2011-03-11
  53.  */
  54. {
  55.     // NP See below
  56.  
  57.     // Internal settings, do not mess with them
  58.     protected $_punycode_prefix = 'xn--';
  59.     protected $_invalid_ucs = 0x80000000;
  60.     protected $_max_ucs = 0x10FFFF;
  61.     protected $_base = 36;
  62.     protected $_tmin = 1;
  63.     protected $_tmax = 26;
  64.     protected $_skew = 38;
  65.     protected $_damp = 700;
  66.     protected $_initial_bias = 72;
  67.     protected $_initial_n = 0x80;
  68.     protected $_sbase = 0xAC00;
  69.     protected $_lbase = 0x1100;
  70.     protected $_vbase = 0x1161;
  71.     protected $_tbase = 0x11A7;
  72.     protected $_lcount = 19;
  73.     protected $_vcount = 21;
  74.     protected $_tcount = 28;
  75.     protected $_ncount = 588;   // _vcount * _tcount
  76.     protected $_scount = 11172; // _lcount * _tcount * _vcount
  77.     protected $_error = false;
  78.  
  79.     protected static $_mb_string_overload = null;
  80.  
  81.     // See {@link set_paramter()} for details of how to change the following
  82.     // settings from within your script / application
  83.     protected $_api_encoding = 'utf8';   // Default input charset is UTF-8
  84.     protected $_allow_overlong = false;  // Overlong UTF-8 encodings are forbidden
  85.     protected $_strict_mode = false;     // Behave strict or not
  86.     protected $_idn_version = 2003;      // Can be either 2003 (old, default) or 2008
  87.  
  88.     /**
  89.      * the constructor
  90.      *
  91.      * @param array $options 
  92.      * @return boolean 
  93.      * @since 0.5.2
  94.      */
  95.     public function __construct($options = false)
  96.     {
  97.         $this->slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount;
  98.         // If parameters are given, pass these to the respective method
  99.         if (is_array($options)) {
  100.             $this->set_parameter($options);
  101.         }
  102.  
  103.         // populate mbstring overloading cache if not set
  104.         if (self::$_mb_string_overload === null) {
  105.             self::$_mb_string_overload = (extension_loaded('mbstring')
  106.                 && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
  107.         }
  108.     }
  109.  
  110.     /**
  111.      * Sets a new option value. Available options and values:
  112.      * [encoding - Use either UTF-8, UCS4 as array or UCS4 as string as input ('utf8' for UTF-8,
  113.      *         'ucs4_string' and 'ucs4_array' respectively for UCS4); The output is always UTF-8]
  114.      * [overlong - Unicode does not allow unnecessarily long encodings of chars,
  115.      *             to allow this, set this parameter to true, else to false;
  116.      *             default is false.]
  117.      * [strict - true: strict mode, good for registration purposes - Causes errors
  118.      *           on failures; false: loose mode, ideal for "wildlife" applications
  119.      *           by silently ignoring errors and returning the original input instead
  120.      *
  121.      * @param    mixed     Parameter to set (string: single parameter; array of Parameter => Value pairs)
  122.      * @param    string    Value to use (if parameter 1 is a string)
  123.      * @return   boolean   true on success, false otherwise
  124.      */
  125.     public function set_parameter($option, $value = false)
  126.     {
  127.         if (!is_array($option)) {
  128.             $option = array($option => $value);
  129.         }
  130.         foreach ($option as $k => $v) {
  131.             switch ($k) {
  132.             case 'encoding':
  133.                 switch ($v) {
  134.                 case 'utf8':
  135.                 case 'ucs4_string':
  136.                 case 'ucs4_array':
  137.                     $this->_api_encoding = $v;
  138.                     break;
  139.                 default:
  140.                     $this->_error('Set Parameter: Unknown parameter '.$v.' for option '.$k);
  141.                     return false;
  142.                 }
  143.                 break;
  144.             case 'overlong':
  145.                 $this->_allow_overlong = ($v) ? true : false;
  146.                 break;
  147.             case 'strict':
  148.                 $this->_strict_mode = ($v) ? true : false;
  149.                 break;
  150.             case 'idn_version':
  151.                 if (in_array($v, array('2003', '2008'))) {
  152.                     $this->_idn_version = $v;
  153.                 } else {
  154.                     $this->_error('Set Parameter: Unknown parameter '.$v.' for option '.$k);
  155.                 }
  156.                 break;
  157.             case 'encode_german_sz': // Deprecated
  158.                 if (!$v) {
  159.                     self::$NP['replacemaps'][0xDF] = array(0x73, 0x73);
  160.                 } else {
  161.                     unset(self::$NP['replacemaps'][0xDF]);
  162.                 }
  163.                 break;
  164.             default:
  165.                 $this->_error('Set Parameter: Unknown option '.$k);
  166.                 return false;
  167.             }
  168.         }
  169.         return true;
  170.     }
  171.  
  172.     /**
  173.      * Decode a given ACE domain name
  174.      * @param    string   Domain name (ACE string)
  175.      *  [@param    string   Desired output encoding, see {@link set_parameter}]
  176.      * @return   string   Decoded Domain name (UTF-8 or UCS-4)
  177.      */
  178.     public function decode($input, $one_time_encoding = false)
  179.     {
  180.         // Optionally set
  181.         if ($one_time_encoding) {
  182.             switch ($one_time_encoding) {
  183.             case 'utf8':
  184.             case 'ucs4_string':
  185.             case 'ucs4_array':
  186.                 break;
  187.             default:
  188.                 $this->_error('Unknown encoding '.$one_time_encoding);
  189.                 return false;
  190.             }
  191.         }
  192.         // Make sure to drop any newline characters around
  193.         $input = trim($input);
  194.  
  195.         // Negotiate input and try to determine, whether it is a plain string,
  196.         // an email address or something like a complete URL
  197.         if (strpos($input, '@')) { // Maybe it is an email address
  198.             // No no in strict mode
  199.             if ($this->_strict_mode) {
  200.                 $this->_error('Only simple domain name parts can be handled in strict mode');
  201.                 return false;
  202.             }
  203.             list ($email_pref, $input) = explode('@', $input, 2);
  204.             $arr = explode('.', $input);
  205.             foreach ($arr as $k => $v) {
  206.                 if (preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $v)) {
  207.                     $conv = $this->_decode($v);
  208.                     if ($conv) $arr[$k] = $conv;
  209.                 }
  210.             }
  211.             $input = join('.', $arr);
  212.             $arr = explode('.', $email_pref);
  213.             foreach ($arr as $k => $v) {
  214.                 if (preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $v)) {
  215.                     $conv = $this->_decode($v);
  216.                     if ($conv) $arr[$k] = $conv;
  217.                 }
  218.             }
  219.             $email_pref = join('.', $arr);
  220.             $return = $email_pref . '@' . $input;
  221.         } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters)
  222.             // No no in strict mode
  223.             if ($this->_strict_mode) {
  224.                 $this->_error('Only simple domain name parts can be handled in strict mode');
  225.                 return false;
  226.             }
  227.             $parsed = parse_url($input);
  228.             if (isset($parsed['host'])) {
  229.                 $arr = explode('.', $parsed['host']);
  230.                 foreach ($arr as $k => $v) {
  231.                     $conv = $this->_decode($v);
  232.                     if ($conv) $arr[$k] = $conv;
  233.                 }
  234.                 $parsed['host'] = join('.', $arr);
  235.                 $return =
  236.                         (empty($parsed['scheme']) ? '' : $parsed['scheme'].(strtolower($parsed['scheme']) == 'mailto' ? ':' : '://'))
  237.                         .(empty($parsed['user']) ? '' : $parsed['user'].(empty($parsed['pass']) ? '' : ':'.$parsed['pass']).'@')
  238.                         .$parsed['host']
  239.                         .(empty($parsed['port']) ? '' : ':'.$parsed['port'])
  240.                         .(empty($parsed['path']) ? '' : $parsed['path'])
  241.                         .(empty($parsed['query']) ? '' : '?'.$parsed['query'])
  242.                         .(empty($parsed['fragment']) ? '' : '#'.$parsed['fragment']);
  243.             } else { // parse_url seems to have failed, try without it
  244.                 $arr = explode('.', $input);
  245.                 foreach ($arr as $k => $v) {
  246.                     $conv = $this->_decode($v);
  247.                     $arr[$k] = ($conv) ? $conv : $v;
  248.                 }
  249.                 $return = join('.', $arr);
  250.             }
  251.         } else { // Otherwise we consider it being a pure domain name string
  252.             $return = $this->_decode($input);
  253.             if (!$return) $return = $input;
  254.         }
  255.         // The output is UTF-8 by default, other output formats need conversion here
  256.         // If one time encoding is given, use this, else the objects property
  257.         switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
  258.         case 'utf8':
  259.             return $return;
  260.             break;
  261.         case 'ucs4_string':
  262.            return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return));
  263.            break;
  264.         case 'ucs4_array':
  265.             return $this->_utf8_to_ucs4($return);
  266.             break;
  267.         default:
  268.             $this->_error('Unsupported output format');
  269.             return false;
  270.         }
  271.     }
  272.  
  273.     /**
  274.      * Encode a given UTF-8 domain name
  275.      * @param    string   Domain name (UTF-8 or UCS-4)
  276.      *  [@param    string   Desired input encoding, see {@link set_parameter}]
  277.      * @return   string   Encoded Domain name (ACE string)
  278.      */
  279.     public function encode($decoded, $one_time_encoding = false)
  280.     {
  281.         // Forcing conversion of input to UCS4 array
  282.         // If one time encoding is given, use this, else the objects property
  283.         switch ($one_time_encoding ? $one_time_encoding : $this->_api_encoding) {
  284.         case 'utf8':
  285.             $decoded = $this->_utf8_to_ucs4($decoded);
  286.             break;
  287.         case 'ucs4_string':
  288.            $decoded = $this->_ucs4_string_to_ucs4($decoded);
  289.         case 'ucs4_array':
  290.            break;
  291.         default:
  292.             $this->_error('Unsupported input format: '.($one_time_encoding ? $one_time_encoding : $this->_api_encoding));
  293.             return false;
  294.         }
  295.  
  296.         // No input, no output, what else did you expect?
  297.         if (empty($decoded)) return '';
  298.  
  299.         // Anchors for iteration
  300.         $last_begin = 0;
  301.         // Output string
  302.         $output = '';
  303.         foreach ($decoded as $k => $v) {
  304.             // Make sure to use just the plain dot
  305.             switch($v) {
  306.             case 0x3002:
  307.             case 0xFF0E:
  308.             case 0xFF61:
  309.                 $decoded[$k] = 0x2E;
  310.                 // Right, no break here, the above are converted to dots anyway
  311.             // Stumbling across an anchoring character
  312.             case 0x2E:
  313.             case 0x2F:
  314.             case 0x3A:
  315.             case 0x3F:
  316.             case 0x40:
  317.                 // Neither email addresses nor URLs allowed in strict mode
  318.                 if ($this->_strict_mode) {
  319.                    $this->_error('Neither email addresses nor URLs are allowed in strict mode.');
  320.                    return false;
  321.                 } else {
  322.                     // Skip first char
  323.                     if ($k) {
  324.                         $encoded = '';
  325.                         $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin)));
  326.                         if ($encoded) {
  327.                             $output .= $encoded;
  328.                         } else {
  329.                             $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin)));
  330.                         }
  331.                         $output .= chr($decoded[$k]);
  332.                     }
  333.                     $last_begin = $k + 1;
  334.                 }
  335.             }
  336.         }
  337.         // Catch the rest of the string
  338.         if ($last_begin) {
  339.             $inp_len = sizeof($decoded);
  340.             $encoded = '';
  341.             $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
  342.             if ($encoded) {
  343.                 $output .= $encoded;
  344.             } else {
  345.                 $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
  346.             }
  347.             return $output;
  348.         } else {
  349.             if ($output = $this->_encode($decoded)) {
  350.                 return $output;
  351.             } else {
  352.                 return $this->_ucs4_to_utf8($decoded);
  353.             }
  354.         }
  355.     }
  356.  
  357.     /**
  358.      * Removes a weakness of encode(), which cannot properly handle URIs but instead encodes their
  359.      * path or query components, too.
  360.      * @param string  $uri  Expects the URI as a UTF-8 (or ASCII) string
  361.      * @return  string  The URI encoded to Punycode, everything but the host component is left alone
  362.      * @since 0.6.4
  363.      */
  364.     public function encode_uri($uri)
  365.     {
  366.         $parsed = parse_url($uri);
  367.         if (!isset($parsed['host'])) {
  368.             $this->_error('The given string does not look like a URI');
  369.             return false;
  370.         }
  371.         $arr = explode('.', $parsed['host']);
  372.         foreach ($arr as $k => $v) {
  373.             $conv = $this->encode($v, 'utf8');
  374.             if ($conv) $arr[$k] = $conv;
  375.         }
  376.         $parsed['host'] = join('.', $arr);
  377.         $return =
  378.                 (empty($parsed['scheme']) ? '' : $parsed['scheme'].(strtolower($parsed['scheme']) == 'mailto' ? ':' : '://'))
  379.                 .(empty($parsed['user']) ? '' : $parsed['user'].(empty($parsed['pass']) ? '' : ':'.$parsed['pass']).'@')
  380.                 .$parsed['host']
  381.                 .(empty($parsed['port']) ? '' : ':'.$parsed['port'])
  382.                 .(empty($parsed['path']) ? '' : $parsed['path'])
  383.                 .(empty($parsed['query']) ? '' : '?'.$parsed['query'])
  384.                 .(empty($parsed['fragment']) ? '' : '#'.$parsed['fragment']);
  385.         return $return;
  386.     }
  387.  
  388.     /**
  389.      * Use this method to get the last error ocurred
  390.      * @param    void 
  391.      * @return   string   The last error, that occured
  392.      */
  393.     public function get_last_error()
  394.     {
  395.         return $this->_error;
  396.     }
  397.  
  398.     /**
  399.      * The actual decoding algorithm
  400.      * @param string 
  401.      * @return mixed 
  402.      */
  403.     protected function _decode($encoded)
  404.     {
  405.         $decoded = array();
  406.         // find the Punycode prefix
  407.         if (!preg_match('!^'.preg_quote($this->_punycode_prefix, '!').'!', $encoded)) {
  408.             $this->_error('This is not a punycode string');
  409.             return false;
  410.         }
  411.         $encode_test = preg_replace('!^'.preg_quote($this->_punycode_prefix, '!').'!', '', $encoded);
  412.         // If nothing left after removing the prefix, it is hopeless
  413.         if (!$encode_test) {
  414.             $this->_error('The given encoded string was empty');
  415.             return false;
  416.         }
  417.         // Find last occurence of the delimiter
  418.         $delim_pos = strrpos($encoded, '-');
  419.         if ($delim_pos > self::byteLength($this->_punycode_prefix)) {
  420.             for ($k = self::byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
  421.                 $decoded[] = ord($encoded{$k});
  422.             }
  423.         }
  424.         $deco_len = count($decoded);
  425.         $enco_len = self::byteLength($encoded);
  426.  
  427.         // Wandering through the strings; init
  428.         $is_first = true;
  429.         $bias = $this->_initial_bias;
  430.         $idx = 0;
  431.         $char = $this->_initial_n;
  432.  
  433.         for ($enco_idx = ($delim_pos) ? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
  434.             for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) {
  435.                 $digit = $this->_decode_digit($encoded{$enco_idx++});
  436.                 $idx += $digit * $w;
  437.                 $t = ($k <= $bias) ? $this->_tmin :
  438.                         (($k >= $bias + $this->_tmax) ? $this->_tmax : ($k - $bias));
  439.                 if ($digit < $t) break;
  440.                 $w = (int) ($w * ($this->_base - $t));
  441.             }
  442.             $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first);
  443.             $is_first = false;
  444.             $char += (int) ($idx / ($deco_len + 1));
  445.             $idx %= ($deco_len + 1);
  446.             if ($deco_len > 0) {
  447.                 // Make room for the decoded char
  448.                 for ($i = $deco_len; $i > $idx; $i--) $decoded[$i] = $decoded[($i - 1)];
  449.             }
  450.             $decoded[$idx++] = $char;
  451.         }
  452.         return $this->_ucs4_to_utf8($decoded);
  453.     }
  454.  
  455.     /**
  456.      * The actual encoding algorithm
  457.      * @param  string 
  458.      * @return mixed 
  459.      */
  460.     protected function _encode($decoded)
  461.     {
  462.         // We cannot encode a domain name containing the Punycode prefix
  463.         $extract = self::byteLength($this->_punycode_prefix);
  464.         $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix);
  465.         $check_deco = array_slice($decoded, 0, $extract);
  466.  
  467.         if ($check_pref == $check_deco) {
  468.             $this->_error('This is already a punycode string');
  469.             return false;
  470.         }
  471.         // We will not try to encode strings consisting of basic code points only
  472.         $encodable = false;
  473.         foreach ($decoded as $k => $v) {
  474.             if ($v > 0x7a) {
  475.                 $encodable = true;
  476.                 break;
  477.             }
  478.         }
  479.         if (!$encodable) {
  480.             $this->_error('The given string does not contain encodable chars');
  481.             return false;
  482.         }
  483.         // Do NAMEPREP
  484.         $decoded = $this->_nameprep($decoded);
  485.         if (!$decoded || !is_array($decoded)) return false; // NAMEPREP failed
  486.         $deco_len  = count($decoded);
  487.         if (!$deco_len) return false; // Empty array
  488.         $codecount = 0; // How many chars have been consumed
  489.         $encoded = '';
  490.         // Copy all basic code points to output
  491.         for ($i = 0; $i < $deco_len; ++$i) {
  492.             $test = $decoded[$i];
  493.             // Will match [-0-9a-zA-Z]
  494.             if ((0x2F < $test && $test < 0x40) || (0x40 < $test && $test < 0x5B)
  495.                     || (0x60 < $test && $test <= 0x7B) || (0x2D == $test)) {
  496.                 $encoded .= chr($decoded[$i]);
  497.                 $codecount++;
  498.             }
  499.         }
  500.         if ($codecount == $deco_len) return $encoded; // All codepoints were basic ones
  501.  
  502.         // Start with the prefix; copy it to output
  503.         $encoded = $this->_punycode_prefix.$encoded;
  504.         // If we have basic code points in output, add an hyphen to the end
  505.         if ($codecount) $encoded .= '-';
  506.         // Now find and encode all non-basic code points
  507.         $is_first = true;
  508.         $cur_code = $this->_initial_n;
  509.         $bias = $this->_initial_bias;
  510.         $delta = 0;
  511.         while ($codecount < $deco_len) {
  512.             // Find the smallest code point >= the current code point and
  513.             // remember the last ouccrence of it in the input
  514.             for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) {
  515.                 if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) {
  516.                     $next_code = $decoded[$i];
  517.                 }
  518.             }
  519.             $delta += ($next_code - $cur_code) * ($codecount + 1);
  520.             $cur_code = $next_code;
  521.  
  522.             // Scan input again and encode all characters whose code point is $cur_code
  523.             for ($i = 0; $i < $deco_len; $i++) {
  524.                 if ($decoded[$i] < $cur_code) {
  525.                     $delta++;
  526.                 } elseif ($decoded[$i] == $cur_code) {
  527.                     for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) {
  528.                         $t = ($k <= $bias) ? $this->_tmin :
  529.                                 (($k >= $bias + $this->_tmax) ? $this->_tmax : $k - $bias);
  530.                         if ($q < $t) break;
  531.                         $encoded .= $this->_encode_digit(intval($t + (($q - $t) % ($this->_base - $t)))); //v0.4.5 Changed from ceil() to intval()
  532.                         $q = (int) (($q - $t) / ($this->_base - $t));
  533.                     }
  534.                     $encoded .= $this->_encode_digit($q);
  535.                     $bias = $this->_adapt($delta, $codecount+1, $is_first);
  536.                     $codecount++;
  537.                     $delta = 0;
  538.                     $is_first = false;
  539.                 }
  540.             }
  541.             $delta++;
  542.             $cur_code++;
  543.         }
  544.         return $encoded;
  545.     }
  546.  
  547.     /**
  548.      * Adapt the bias according to the current code point and position
  549.      * @param int $delta 
  550.      * @param int $npoints 
  551.      * @param int $is_first 
  552.      * @return int 
  553.      */
  554.     protected function _adapt($delta, $npoints, $is_first)
  555.     {
  556.         $delta = intval($is_first ? ($delta / $this->_damp) : ($delta / 2));
  557.         $delta += intval($delta / $npoints);
  558.         for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) {
  559.             $delta = intval($delta / ($this->_base - $this->_tmin));
  560.         }
  561.         return intval($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew));
  562.     }
  563.  
  564.     /**
  565.      * Encoding a certain digit
  566.      * @param    int $d 
  567.      * @return string 
  568.      */
  569.     protected function _encode_digit($d)
  570.     {
  571.         return chr($d + 22 + 75 * ($d < 26));
  572.     }
  573.  
  574.     /**
  575.      * Decode a certain digit
  576.      * @param    int $cp 
  577.      * @return int 
  578.      */
  579.     protected function _decode_digit($cp)
  580.     {
  581.         $cp = ord($cp);
  582.         return ($cp - 48 < 10) ? $cp - 22 : (($cp - 65 < 26) ? $cp - 65 : (($cp - 97 < 26) ? $cp - 97 : $this->_base));
  583.     }
  584.  
  585.     /**
  586.      * Internal error handling method
  587.      * @param  string $error 
  588.      */
  589.     protected function _error($error = '')
  590.     {
  591.         $this->_error = $error;
  592.     }
  593.  
  594.     /**
  595.      * Do Nameprep according to RFC3491 and RFC3454
  596.      * @param    array    Unicode Characters
  597.      * @return   string   Unicode Characters, Nameprep'd
  598.      */
  599.     protected function _nameprep($input)
  600.     {
  601.         $output = array();
  602.         $error = false;
  603.         //
  604.         // Mapping
  605.         // Walking through the input array, performing the required steps on each of
  606.         // the input chars and putting the result into the output array
  607.         // While mapping required chars we apply the cannonical ordering
  608.         foreach ($input as $v) {
  609.             // Map to nothing == skip that code point
  610.             if (in_array($v, self::$NP['map_nothing'])) continue;
  611.             // Try to find prohibited input
  612.             if (in_array($v, self::$NP['prohibit']) || in_array($v, self::$NP['general_prohibited'])) {
  613.                 $this->_error('NAMEPREP: Prohibited input U+'.sprintf('%08X', $v));
  614.                 return false;
  615.             }
  616.             foreach (self::$NP['prohibit_ranges'] as $range) {
  617.                 if ($range[0] <= $v && $v <= $range[1]) {
  618.                     $this->_error('NAMEPREP: Prohibited input U+'.sprintf('%08X', $v));
  619.                     return false;
  620.                 }
  621.             }
  622.  
  623.             if (0xAC00 <= $v && $v <= 0xD7AF) {
  624.                 // Hangul syllable decomposition
  625.                 foreach ($this->_hangul_decompose($v) as $out) {
  626.                     $output[] = (int) $out;
  627.                 }
  628.             } elseif (($this->_idn_version == '2003') && isset(self::$NP['replacemaps'][$v])) {
  629.                 // There's a decomposition mapping for that code point
  630.                 // Decompositions only in version 2003 (original) of IDNA
  631.                 foreach ($this->_apply_cannonical_ordering(self::$NP['replacemaps'][$v]) as $out) {
  632.                     $output[] = (int) $out;
  633.                 }
  634.             } else {
  635.                 $output[] = (int) $v;
  636.             }
  637.         }
  638.         // Before applying any Combining, try to rearrange any Hangul syllables
  639.         $output = $this->_hangul_compose($output);
  640.         //
  641.         // Combine code points
  642.         //
  643.         $last_class = 0;
  644.         $last_starter = 0;
  645.         $out_len = count($output);
  646.         for ($i = 0; $i < $out_len; ++$i) {
  647.             $class = $this->_get_combining_class($output[$i]);
  648.             if ((!$last_class || $last_class > $class) && $class) {
  649.                 // Try to match
  650.                 $seq_len = $i - $last_starter;
  651.                 $out = $this->_combine(array_slice($output, $last_starter, $seq_len));
  652.                 // On match: Replace the last starter with the composed character and remove
  653.                 // the now redundant non-starter(s)
  654.                 if ($out) {
  655.                     $output[$last_starter] = $out;
  656.                     if (count($out) != $seq_len) {
  657.                         for ($j = $i+1; $j < $out_len; ++$j) $output[$j-1] = $output[$j];
  658.                         unset($output[$out_len]);
  659.                     }
  660.                     // Rewind the for loop by one, since there can be more possible compositions
  661.                     $i--;
  662.                     $out_len--;
  663.                     $last_class = ($i == $last_starter) ? 0 : $this->_get_combining_class($output[$i-1]);
  664.                     continue;
  665.                 }
  666.             }
  667.             // The current class is 0
  668.             if (!$class) $last_starter = $i;
  669.             $last_class = $class;
  670.         }
  671.         return $output;
  672.     }
  673.  
  674.     /**
  675.      * Decomposes a Hangul syllable
  676.      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul
  677.      * @param    integer  32bit UCS4 code point
  678.      * @return   array    Either Hangul Syllable decomposed or original 32bit value as one value array
  679.      */
  680.     protected function _hangul_decompose($char)
  681.     {
  682.         $sindex = (int) $char - $this->_sbase;
  683.         if ($sindex < 0 || $sindex >= $this->_scount) return array($char);
  684.         $result = array();
  685.         $result[] = (int) $this->_lbase + $sindex / $this->_ncount;
  686.         $result[] = (int) $this->_vbase + ($sindex % $this->_ncount) / $this->_tcount;
  687.         $T = intval($this->_tbase + $sindex % $this->_tcount);
  688.         if ($T != $this->_tbase) $result[] = $T;
  689.         return $result;
  690.     }
  691.     /**
  692.      * Ccomposes a Hangul syllable
  693.      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul
  694.      * @param    array    Decomposed UCS4 sequence
  695.      * @return   array    UCS4 sequence with syllables composed
  696.      */
  697.     protected function _hangul_compose($input)
  698.     {
  699.         $inp_len = count($input);
  700.         if (!$inp_len) return array();
  701.         $result = array();
  702.         $last = (int) $input[0];
  703.         $result[] = $last; // copy first char from input to output
  704.  
  705.         for ($i = 1; $i < $inp_len; ++$i) {
  706.             $char = (int) $input[$i];
  707.             $sindex = $last - $this->_sbase;
  708.             $lindex = $last - $this->_lbase;
  709.             $vindex = $char - $this->_vbase;
  710.             $tindex = $char - $this->_tbase;
  711.             // Find out, whether two current characters are LV and T
  712.             if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount == 0)
  713.                     && 0 <= $tindex && $tindex <= $this->_tcount) {
  714.                 // create syllable of form LVT
  715.                 $last += $tindex;
  716.                 $result[(count($result) - 1)] = $last; // reset last
  717.                 continue; // discard char
  718.             }
  719.             // Find out, whether two current characters form L and V
  720.             if (0 <= $lindex && $lindex < $this->_lcount && 0 <= $vindex && $vindex < $this->_vcount) {
  721.                 // create syllable of form LV
  722.                 $last = (int) $this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount;
  723.                 $result[(count($result) - 1)] = $last; // reset last
  724.                 continue; // discard char
  725.             }
  726.             // if neither case was true, just add the character
  727.             $last = $char;
  728.             $result[] = $char;
  729.         }
  730.         return $result;
  731.     }
  732.  
  733.     /**
  734.      * Returns the combining class of a certain wide char
  735.      * @param    integer    Wide char to check (32bit integer)
  736.      * @return   integer    Combining class if found, else 0
  737.      */
  738.     protected function _get_combining_class($char)
  739.     {
  740.         return isset(self::$NP['norm_combcls'][$char]) ? self::$NP['norm_combcls'][$char] : 0;
  741.     }
  742.  
  743.     /**
  744.      * Applies the cannonical ordering of a decomposed UCS4 sequence
  745.      * @param    array      Decomposed UCS4 sequence
  746.      * @return   array      Ordered USC4 sequence
  747.      */
  748.     protected function _apply_cannonical_ordering($input)
  749.     {
  750.         $swap = true;
  751.         $size = count($input);
  752.         while ($swap) {
  753.             $swap = false;
  754.             $last = $this->_get_combining_class(intval($input[0]));
  755.             for ($i = 0; $i < $size-1; ++$i) {
  756.                 $next = $this->_get_combining_class(intval($input[$i+1]));
  757.                 if ($next != 0 && $last > $next) {
  758.                     // Move item leftward until it fits
  759.                     for ($j = $i + 1; $j > 0; --$j) {
  760.                         if ($this->_get_combining_class(intval($input[$j-1])) <= $next) break;
  761.                         $t = intval($input[$j]);
  762.                         $input[$j] = intval($input[$j-1]);
  763.                         $input[$j-1] = $t;
  764.                         $swap = true;
  765.                     }
  766.                     // Reentering the loop looking at the old character again
  767.                     $next = $last;
  768.                 }
  769.                 $last = $next;
  770.             }
  771.         }
  772.         return $input;
  773.     }
  774.  
  775.     /**
  776.      * Do composition of a sequence of starter and non-starter
  777.      * @param    array      UCS4 Decomposed sequence
  778.      * @return   array      Ordered USC4 sequence
  779.      */
  780.     protected function _combine($input)
  781.     {
  782.         $inp_len = count($input);
  783.         foreach (self::$NP['replacemaps'] as $np_src => $np_target) {
  784.             if ($np_target[0] != $input[0]) continue;
  785.             if (count($np_target) != $inp_len) continue;
  786.             $hit = false;
  787.             foreach ($input as $k2 => $v2) {
  788.                 if ($v2 == $np_target[$k2]) {
  789.                     $hit = true;
  790.                 } else {
  791.                     $hit = false;
  792.                     break;
  793.                 }
  794.             }
  795.             if ($hit) return $np_src;
  796.         }
  797.         return false;
  798.     }
  799.  
  800.     /**
  801.      * This converts an UTF-8 encoded string to its UCS-4 representation
  802.      * By talking about UCS-4 "strings" we mean arrays of 32bit integers representing
  803.      * each of the "chars". This is due to PHP not being able to handle strings with
  804.      * bit depth different from 8. This apllies to the reverse method _ucs4_to_utf8(), too.
  805.      * The following UTF-8 encodings are supported:
  806.      * bytes bits  representation
  807.      * 1        7  0xxxxxxx
  808.      * 2       11  110xxxxx 10xxxxxx
  809.      * 3       16  1110xxxx 10xxxxxx 10xxxxxx
  810.      * 4       21  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  811.      * 5       26  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  812.      * 6       31  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  813.      * Each x represents a bit that can be used to store character data.
  814.      * The five and six byte sequences are part of Annex D of ISO/IEC 10646-1:2000
  815.      * @param string $input 
  816.      * @return string 
  817.      */
  818.     protected function _utf8_to_ucs4($input)
  819.     {
  820.         $output = array();
  821.         $out_len = 0;
  822.         $inp_len = self::byteLength($input);
  823.         $mode = 'next';
  824.         $test = 'none';
  825.         for ($k = 0; $k < $inp_len; ++$k) {
  826.             $v = ord($input{$k}); // Extract byte from input string
  827.             if ($v < 128) { // We found an ASCII char - put into stirng as is
  828.                 $output[$out_len] = $v;
  829.                 ++$out_len;
  830.                 if ('add' == $mode) {
  831.                     $this->_error('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
  832.                     return false;
  833.                 }
  834.                 continue;
  835.             }
  836.             if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char
  837.                 $start_byte = $v;
  838.                 $mode = 'add';
  839.                 $test = 'range';
  840.                 if ($v >> 5 == 6) { // &110xxxxx 10xxxxx
  841.                     $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left
  842.                     $v = ($v - 192) << 6;
  843.                 } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx
  844.                     $next_byte = 1;
  845.                     $v = ($v - 224) << 12;
  846.                 } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  847.                     $next_byte = 2;
  848.                     $v = ($v - 240) << 18;
  849.                 } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  850.                     $next_byte = 3;
  851.                     $v = ($v - 248) << 24;
  852.                 } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  853.                     $next_byte = 4;
  854.                     $v = ($v - 252) << 30;
  855.                 } else {
  856.                     $this->_error('This might be UTF-8, but I don\'t understand it at byte '.$k);
  857.                     return false;
  858.                 }
  859.                 if ('add' == $mode) {
  860.                     $output[$out_len] = (int) $v;
  861.                     ++$out_len;
  862.                     continue;
  863.                 }
  864.             }
  865.             if ('add' == $mode) {
  866.                 if (!$this->_allow_overlong && $test == 'range') {
  867.                     $test = 'none';
  868.                     if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) {
  869.                         $this->_error('Bogus UTF-8 character detected (out of legal range) at byte '.$k);
  870.                         return false;
  871.                     }
  872.                 }
  873.                 if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx
  874.                     $v = ($v - 128) << ($next_byte * 6);
  875.                     $output[($out_len - 1)] += $v;
  876.                     --$next_byte;
  877.                 } else {
  878.                     $this->_error('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
  879.                     return false;
  880.                 }
  881.                 if ($next_byte < 0) {
  882.                     $mode = 'next';
  883.                 }
  884.             }
  885.         } // for
  886.         return $output;
  887.     }
  888.  
  889.     /**
  890.      * Convert UCS-4 string into UTF-8 string
  891.      * See _utf8_to_ucs4() for details
  892.      * @param string  $input 
  893.      * @return string 
  894.      */
  895.     protected function _ucs4_to_utf8($input)
  896.     {
  897.         $output = '';
  898.         foreach ($input as $k => $v) {
  899.             if ($v < 128) { // 7bit are transferred literally
  900.                 $output .= chr($v);
  901.             } elseif ($v < (1 << 11)) { // 2 bytes
  902.                 $output .= chr(192+($v >> 6)).chr(128+($v & 63));
  903.             } elseif ($v < (1 << 16)) { // 3 bytes
  904.                 $output .= chr(224+($v >> 12)).chr(128+(($v >> 6) & 63)).chr(128+($v & 63));
  905.             } elseif ($v < (1 << 21)) { // 4 bytes
  906.                 $output .= chr(240+($v >> 18)).chr(128+(($v >> 12) & 63)).chr(128+(($v >> 6) & 63)).chr(128+($v & 63));
  907.             } elseif (self::$safe_mode) {
  908.                 $output .= self::$safe_char;
  909.             } else {
  910.                 $this->_error('Conversion from UCS-4 to UTF-8 failed: malformed input at byte '.$k);
  911.                 return false;
  912.             }
  913.         }
  914.         return $output;
  915.     }
  916.  
  917.     /**
  918.      * Convert UCS-4 array into UCS-4 string
  919.      *
  920.      * @param array $input 
  921.      * @return string 
  922.      */
  923.     protected function _ucs4_to_ucs4_string($input)
  924.     {
  925.         $output = '';
  926.         // Take array values and split output to 4 bytes per value
  927.         // The bit mask is 255, which reads &11111111
  928.         foreach ($input as $v) {
  929.             $output .= chr(($v >> 24) & 255).chr(($v >> 16) & 255).chr(($v >> 8) & 255).chr($v & 255);
  930.         }
  931.         return $output;
  932.     }
  933.  
  934.     /**
  935.      * Convert UCS-4 strin into UCS-4 garray
  936.      *
  937.      * @param  string $input 
  938.      * @return array 
  939.      */
  940.     protected function _ucs4_string_to_ucs4($input)
  941.     {
  942.         $output = array();
  943.         $inp_len = self::byteLength($input);
  944.         // Input length must be dividable by 4
  945.         if ($inp_len % 4) {
  946.             $this->_error('Input UCS4 string is broken');
  947.             return false;
  948.         }
  949.         // Empty input - return empty output
  950.         if (!$inp_len) return $output;
  951.         for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) {
  952.             // Increment output position every 4 input bytes
  953.             if (!($i % 4)) {
  954.                 $out_len++;
  955.                 $output[$out_len] = 0;
  956.             }
  957.             $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) );
  958.         }
  959.         return $output;
  960.     }
  961.  
  962.     /**
  963.      * Gets the length of a string in bytes even if mbstring function
  964.      * overloading is turned on
  965.      *
  966.      * @param string $string the string for which to get the length.
  967.      * @return integer the length of the string in bytes.
  968.      */
  969.     protected static function byteLength($string)
  970.     {
  971.         if (self::$_mb_string_overload) {
  972.             return mb_strlen($string, '8bit');
  973.         }
  974.         return strlen((binary) $string);
  975.     }
  976.  
  977.     /**
  978.      * Attempts to return a concrete IDNA instance.
  979.      *
  980.      * @param array $params Set of paramaters
  981.      * @return idna_convert 
  982.      * @access public
  983.      */
  984.     public function getInstance($params = array())
  985.     {
  986.         return new idna_convert($params);
  987.     }
  988.  
  989.     /**
  990.      * Attempts to return a concrete IDNA instance for either php4 or php5,
  991.      * only creating a new instance if no IDNA instance with the same
  992.      * parameters currently exists.
  993.      *
  994.      * @param array $params Set of paramaters
  995.      *
  996.      * @return object idna_convert 
  997.      * @access public
  998.      */
  999.     public function singleton($params = array())
  1000.     {
  1001.         static $instances;
  1002.         if (!isset($instances)) {
  1003.             $instances = array();
  1004.         }
  1005.         $signature = serialize($params);
  1006.         if (!isset($instances[$signature])) {
  1007.             $instances[$signature] = idna_convert::getInstance($params);
  1008.         }
  1009.         return $instances[$signature];
  1010.     }
  1011.  
  1012.     /**
  1013.      * Holds all relevant mapping tables
  1014.      * See RFC3454 for details
  1015.      *
  1016.      * @private array
  1017.      * @since 0.5.2
  1018.      */
  1019.     protected static $NP = array
  1020.             ('map_nothing' => array(0xAD, 0x34F, 0x1806, 0x180B, 0x180C, 0x180D, 0x200B, 0x200C
  1021.                     ,0x200D, 0x2060, 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07
  1022.                     ,0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, 0xFEFF
  1023.                     )
  1024.             ,'general_prohibited' => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
  1025.                     ,20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ,33, 34, 35, 36, 37, 38, 39, 40, 41, 42
  1026.                     ,43, 44, 47, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126, 127, 0x3002
  1027.                     )
  1028.             ,'prohibit' => array(0xA0, 0x340, 0x341, 0x6DD, 0x70F, 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003
  1029.                     ,0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x200C, 0x200D, 0x200E, 0x200F
  1030.                     ,0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 0x202F, 0x205F, 0x206A, 0x206B, 0x206C
  1031.                     ,0x206D, 0x206E, 0x206F, 0x3000, 0xFEFF, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF
  1032.                     ,0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE
  1033.                     ,0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE, 0xBFFFF
  1034.                     ,0xCFFFE, 0xCFFFF, 0xDFFFE, 0xDFFFF, 0xE0001, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE, 0x10FFFF
  1035.                     )
  1036.             ,'prohibit_ranges' => array(array(0x80, 0x9F), array(0x2060, 0x206F), array(0x1D173, 0x1D17A)
  1037.                     ,array(0xE000, 0xF8FF) ,array(0xF0000, 0xFFFFD), array(0x100000, 0x10FFFD)
  1038.                     ,array(0xFDD0, 0xFDEF), array(0xD800, 0xDFFF), array(0x2FF0, 0x2FFB), array(0xE0020, 0xE007F)
  1039.                     )
  1040.             ,'replacemaps' => array(0x41 => array(0x61), 0x42 => array(0x62), 0x43 => array(0x63)
  1041.                     ,0x44 => array(0x64), 0x45 => array(0x65), 0x46 => array(0x66), 0x47 => array(0x67)
  1042.                     ,0x48 => array(0x68), 0x49 => array(0x69), 0x4A => array(0x6A), 0x4B => array(0x6B)
  1043.                     ,0x4C => array(0x6C), 0x4D => array(0x6D), 0x4E => array(0x6E), 0x4F => array(0x6F)
  1044.                     ,0x50 => array(0x70), 0x51 => array(0x71), 0x52 => array(0x72), 0x53 => array(0x73)
  1045.                     ,0x54 => array(0x74), 0x55 => array(0x75), 0x56 => array(0x76), 0x57 => array(0x77)
  1046.                     ,0x58 => array(0x78), 0x59 => array(0x79), 0x5A => array(0x7A), 0xB5 => array(0x3BC)
  1047.                     ,0xC0 => array(0xE0), 0xC1 => array(0xE1), 0xC2 => array(0xE2), 0xC3 => array(0xE3)
  1048.                     ,0xC4 => array(0xE4), 0xC5 => array(0xE5), 0xC6 => array(0xE6), 0xC7 => array(0xE7)
  1049.                     ,0xC8 => array(0xE8), 0xC9 => array(0xE9), 0xCA => array(0xEA), 0xCB => array(0xEB)
  1050.                     ,0xCC => array(0xEC), 0xCD => array(0xED), 0xCE => array(0xEE), 0xCF => array(0xEF)
  1051.                     ,0xD0 => array(0xF0), 0xD1 => array(0xF1), 0xD2 => array(0xF2), 0xD3 => array(0xF3)
  1052.                     ,0xD4 => array(0xF4), 0xD5 => array(0xF5), 0xD6 => array(0xF6), 0xD8 => array(0xF8)
  1053.                     ,0xD9 => array(0xF9), 0xDA => array(0xFA), 0xDB => array(0xFB), 0xDC => array(0xFC)
  1054.                     ,0xDD => array(0xFD), 0xDE => array(0xFE), 0xDF => array(0x73, 0x73)
  1055.                     ,0x100 => array(0x101), 0x102 => array(0x103), 0x104 => array(0x105)
  1056.                     ,0x106 => array(0x107), 0x108 => array(0x109), 0x10A => array(0x10B)
  1057.                     ,0x10C => array(0x10D), 0x10E => array(0x10F), 0x110 => array(0x111)
  1058.                     ,0x112 => array(0x113), 0x114 => array(0x115), 0x116 => array(0x117)
  1059.                     ,0x118 => array(0x119), 0x11A => array(0x11B), 0x11C => array(0x11D)
  1060.                     ,0x11E => array(0x11F), 0x120 => array(0x121), 0x122 => array(0x123)
  1061.                     ,0x124 => array(0x125), 0x126 => array(0x127), 0x128 => array(0x129)
  1062.                     ,0x12A => array(0x12B), 0x12C => array(0x12D), 0x12E => array(0x12F)
  1063.                     ,0x130 => array(0x69, 0x307), 0x132 => array(0x133), 0x134 => array(0x135)
  1064.                     ,0x136 => array(0x137), 0x139 => array(0x13A), 0x13B => array(0x13C)
  1065.                     ,0x13D => array(0x13E), 0x13F => array(0x140), 0x141 => array(0x142)
  1066.                     ,0x143 => array(0x144), 0x145 => array(0x146), 0x147 => array(0x148)
  1067.                     ,0x149 => array(0x2BC, 0x6E), 0x14A => array(0x14B), 0x14C => array(0x14D)
  1068.                     ,0x14E => array(0x14F), 0x150 => array(0x151), 0x152 => array(0x153)
  1069.                     ,0x154 => array(0x155), 0x156 => array(0x157), 0x158 => array(0x159)
  1070.                     ,0x15A => array(0x15B), 0x15C => array(0x15D), 0x15E => array(0x15F)
  1071.                     ,0x160 => array(0x161), 0x162 => array(0x163), 0x164 => array(0x165)
  1072.                     ,0x166 => array(0x167), 0x168 => array(0x169), 0x16A => array(0x16B)
  1073.                     ,0x16C => array(0x16D), 0x16E => array(0x16F), 0x170 => array(0x171)
  1074.                     ,0x172 => array(0x173), 0x174 => array(0x175), 0x176 => array(0x177)
  1075.                     ,0x178 => array(0xFF), 0x179 => array(0x17A), 0x17B => array(0x17C)
  1076.                     ,0x17D => array(0x17E), 0x17F => array(0x73), 0x181 => array(0x253)
  1077.                     ,0x182 => array(0x183), 0x184 => array(0x185), 0x186 => array(0x254)
  1078.                     ,0x187 => array(0x188), 0x189 => array(0x256), 0x18A => array(0x257)
  1079.                     ,0x18B => array(0x18C), 0x18E => array(0x1DD), 0x18F => array(0x259)
  1080.                     ,0x190 => array(0x25B), 0x191 => array(0x192), 0x193 => array(0x260)
  1081.                     ,0x194 => array(0x263), 0x196 => array(0x269), 0x197 => array(0x268)
  1082.                     ,0x198 => array(0x199), 0x19C => array(0x26F), 0x19D => array(0x272)
  1083.                     ,0x19F => array(0x275), 0x1A0 => array(0x1A1), 0x1A2 => array(0x1A3)
  1084.                     ,0x1A4 => array(0x1A5), 0x1A6 => array(0x280), 0x1A7 => array(0x1A8)
  1085.                     ,0x1A9 => array(0x283), 0x1AC => array(0x1AD), 0x1AE => array(0x288)
  1086.                     ,0x1AF => array(0x1B0), 0x1B1 => array(0x28A), 0x1B2 => array(0x28B)
  1087.                     ,0x1B3 => array(0x1B4), 0x1B5 => array(0x1B6), 0x1B7 => array(0x292)
  1088.                     ,0x1B8 => array(0x1B9), 0x1BC => array(0x1BD), 0x1C4 => array(0x1C6)
  1089.                     ,0x1C5 => array(0x1C6), 0x1C7 => array(0x1C9), 0x1C8 => array(0x1C9)
  1090.                     ,0x1CA => array(0x1CC), 0x1CB => array(0x1CC), 0x1CD => array(0x1CE)
  1091.                     ,0x1CF => array(0x1D0), 0x1D1   => array(0x1D2), 0x1D3   => array(0x1D4)
  1092.                     ,0x1D5   => array(0x1D6), 0x1D7   => array(0x1D8), 0x1D9   => array(0x1DA)
  1093.                     ,0x1DB   => array(0x1DC), 0x1DE   => array(0x1DF), 0x1E0   => array(0x1E1)
  1094.                     ,0x1E2   => array(0x1E3), 0x1E4   => array(0x1E5), 0x1E6   => array(0x1E7)
  1095.                     ,0x1E8   => array(0x1E9), 0x1EA   => array(0x1EB), 0x1EC   => array(0x1ED)
  1096.                     ,0x1EE   => array(0x1EF), 0x1F0   => array(0x6A, 0x30C), 0x1F1   => array(0x1F3)
  1097.                     ,0x1F2   => array(0x1F3), 0x1F4   => array(0x1F5), 0x1F6   => array(0x195)
  1098.                     ,0x1F7   => array(0x1BF), 0x1F8   => array(0x1F9), 0x1FA   => array(0x1FB)
  1099.                     ,0x1FC   => array(0x1FD), 0x1FE   => array(0x1FF), 0x200   => array(0x201)
  1100.                     ,0x202   => array(0x203), 0x204   => array(0x205), 0x206   => array(0x207)
  1101.                     ,0x208   => array(0x209), 0x20A   => array(0x20B), 0x20C   => array(0x20D)
  1102.                     ,0x20E   => array(0x20F), 0x210   => array(0x211), 0x212   => array(0x213)
  1103.                     ,0x214   => array(0x215), 0x216   => array(0x217), 0x218   => array(0x219)
  1104.                     ,0x21A   => array(0x21B), 0x21C   => array(0x21D), 0x21E   => array(0x21F)
  1105.                     ,0x220   => array(0x19E), 0x222   => array(0x223), 0x224   => array(0x225)
  1106.                     ,0x226   => array(0x227), 0x228   => array(0x229), 0x22A   => array(0x22B)
  1107.                     ,0x22C   => array(0x22D), 0x22E   => array(0x22F), 0x230   => array(0x231)
  1108.                     ,0x232   => array(0x233), 0x345   => array(0x3B9), 0x37A   => array(0x20, 0x3B9)
  1109.                     ,0x386   => array(0x3AC), 0x388   => array(0x3AD), 0x389   => array(0x3AE)
  1110.                     ,0x38A   => array(0x3AF), 0x38C   => array(0x3CC), 0x38E   => array(0x3CD)
  1111.                     ,0x38F   => array(0x3CE), 0x390   => array(0x3B9, 0x308, 0x301)
  1112.                     ,0x391   => array(0x3B1), 0x392   => array(0x3B2), 0x393   => array(0x3B3)
  1113.                     ,0x394   => array(0x3B4), 0x395   => array(0x3B5), 0x396   => array(0x3B6)
  1114.                     ,0x397   => array(0x3B7), 0x398   => array(0x3B8), 0x399   => array(0x3B9)
  1115.                     ,0x39A   => array(0x3BA), 0x39B   => array(0x3BB), 0x39C   => array(0x3BC)
  1116.                     ,0x39D   => array(0x3BD), 0x39E   => array(0x3BE), 0x39F   => array(0x3BF)
  1117.                     ,0x3A0   => array(0x3C0), 0x3A1   => array(0x3C1), 0x3A3   => array(0x3C3)
  1118.                     ,0x3A4   => array(0x3C4), 0x3A5   => array(0x3C5), 0x3A6   => array(0x3C6)
  1119.                     ,0x3A7   => array(0x3C7), 0x3A8   => array(0x3C8), 0x3A9   => array(0x3C9)
  1120.                     ,0x3AA   => array(0x3CA), 0x3AB   => array(0x3CB), 0x3B0   => array(0x3C5, 0x308, 0x301)
  1121.                     ,0x3C2   => array(0x3C3), 0x3D0   => array(0x3B2), 0x3D1   => array(0x3B8)
  1122.                     ,0x3D2   => array(0x3C5), 0x3D3   => array(0x3CD), 0x3D4   => array(0x3CB)
  1123.                     ,0x3D5   => array(0x3C6), 0x3D6   => array(0x3C0), 0x3D8   => array(0x3D9)
  1124.                     ,0x3DA   => array(0x3DB), 0x3DC   => array(0x3DD), 0x3DE   => array(0x3DF)
  1125.                     ,0x3E0   => array(0x3E1), 0x3E2   => array(0x3E3), 0x3E4   => array(0x3E5)
  1126.                     ,0x3E6   => array(0x3E7), 0x3E8   => array(0x3E9), 0x3EA   => array(0x3EB)
  1127.                     ,0x3EC   => array(0x3ED), 0x3EE   => array(0x3EF), 0x3F0   => array(0x3BA)
  1128.                     ,0x3F1   => array(0x3C1), 0x3F2   => array(0x3C3), 0x3F4   => array(0x3B8)
  1129.                     ,0x3F5   => array(0x3B5), 0x400   => array(0x450), 0x401   => array(0x451)
  1130.                     ,0x402   => array(0x452), 0x403   => array(0x453), 0x404   => array(0x454)
  1131.                     ,0x405   => array(0x455), 0x406   => array(0x456), 0x407   => array(0x457)
  1132.                     ,0x408   => array(0x458), 0x409   => array(0x459), 0x40A   => array(0x45A)
  1133.                     ,0x40B   => array(0x45B), 0x40C   => array(0x45C), 0x40D   => array(0x45D)
  1134.                     ,0x40E   => array(0x45E), 0x40F   => array(0x45F), 0x410   => array(0x430)
  1135.                     ,0x411   => array(0x431), 0x412   => array(0x432), 0x413   => array(0x433)
  1136.                     ,0x414   => array(0x434), 0x415   => array(0x435), 0x416   => array(0x436)
  1137.                     ,0x417   => array(0x437), 0x418   => array(0x438), 0x419   => array(0x439)
  1138.                     ,0x41A   => array(0x43A), 0x41B   => array(0x43B), 0x41C   => array(0x43C)
  1139.                     ,0x41D   => array(0x43D), 0x41E   => array(0x43E), 0x41F   => array(0x43F)
  1140.                     ,0x420   => array(0x440), 0x421   => array(0x441), 0x422   => array(0x442)
  1141.                     ,0x423   => array(0x443), 0x424   => array(0x444), 0x425   => array(0x445)
  1142.                     ,0x426   => array(0x446), 0x427   => array(0x447), 0x428   => array(0x448)
  1143.                     ,0x429   => array(0x449), 0x42A   => array(0x44A), 0x42B   => array(0x44B)
  1144.                     ,0x42C   => array(0x44C), 0x42D   => array(0x44D), 0x42E   => array(0x44E)
  1145.                     ,0x42F   => array(0x44F), 0x460   => array(0x461), 0x462   => array(0x463)
  1146.                     ,0x464   => array(0x465), 0x466   => array(0x467), 0x468   => array(0x469)
  1147.                     ,0x46A   => array(0x46B), 0x46C   => array(0x46D), 0x46E   => array(0x46F)
  1148.                     ,0x470   => array(0x471), 0x472   => array(0x473), 0x474   => array(0x475)
  1149.                     ,0x476   => array(0x477), 0x478   => array(0x479), 0x47A   => array(0x47B)
  1150.                     ,0x47C   => array(0x47D), 0x47E   => array(0x47F), 0x480   => array(0x481)
  1151.                     ,0x48A   => array(0x48B), 0x48C   => array(0x48D), 0x48E   => array(0x48F)
  1152.                     ,0x490   => array(0x491), 0x492   => array(0x493), 0x494   => array(0x495)
  1153.                     ,0x496   => array(0x497), 0x498   => array(0x499), 0x49A   => array(0x49B)
  1154.                     ,0x49C   => array(0x49D), 0x49E   => array(0x49F), 0x4A0   => array(0x4A1)
  1155.                     ,0x4A2   => array(0x4A3), 0x4A4   => array(0x4A5), 0x4A6   => array(0x4A7)
  1156.                     ,0x4A8   => array(0x4A9), 0x4AA   => array(0x4AB), 0x4AC   => array(0x4AD)
  1157.                     ,0x4AE   => array(0x4AF), 0x4B0   => array(0x4B1), 0x4B2   => array(0x4B3)
  1158.                     ,0x4B4   => array(0x4B5), 0x4B6   => array(0x4B7), 0x4B8   => array(0x4B9)
  1159.                     ,0x4BA   => array(0x4BB), 0x4BC   => array(0x4BD), 0x4BE   => array(0x4BF)
  1160.                     ,0x4C1   => array(0x4C2), 0x4C3   => array(0x4C4), 0x4C5   => array(0x4C6)
  1161.                     ,0x4C7   => array(0x4C8), 0x4C9   => array(0x4CA), 0x4CB   => array(0x4CC)
  1162.                     ,0x4CD   => array(0x4CE), 0x4D0   => array(0x4D1), 0x4D2   => array(0x4D3)
  1163.                     ,0x4D4   => array(0x4D5), 0x4D6   => array(0x4D7), 0x4D8   => array(0x4D9)
  1164.                     ,0x4DA   => array(0x4DB), 0x4DC   => array(0x4DD), 0x4DE   => array(0x4DF)
  1165.                     ,0x4E0   => array(0x4E1), 0x4E2   => array(0x4E3), 0x4E4   => array(0x4E5)
  1166.                     ,0x4E6   => array(0x4E7), 0x4E8   => array(0x4E9), 0x4EA   => array(0x4EB)
  1167.                     ,0x4EC   => array(0x4ED), 0x4EE   => array(0x4EF), 0x4F0   => array(0x4F1)
  1168.                     ,0x4F2   => array(0x4F3), 0x4F4   => array(0x4F5), 0x4F8   => array(0x4F9)
  1169.                     ,0x500   => array(0x501), 0x502   => array(0x503), 0x504   => array(0x505)
  1170.                     ,0x506   => array(0x507), 0x508   => array(0x509), 0x50A   => array(0x50B)
  1171.                     ,0x50C   => array(0x50D), 0x50E   => array(0x50F), 0x531   => array(0x561)
  1172.                     ,0x532   => array(0x562), 0x533   => array(0x563), 0x534   => array(0x564)
  1173.                     ,0x535   => array(0x565), 0x536   => array(0x566), 0x537   => array(0x567)
  1174.                     ,0x538   => array(0x568), 0x539   => array(0x569), 0x53A   => array(0x56A)
  1175.                     ,0x53B   => array(0x56B), 0x53C   => array(0x56C), 0x53D   => array(0x56D)
  1176.                     ,0x53E   => array(0x56E), 0x53F   => array(0x56F), 0x540   => array(0x570)
  1177.                     ,0x541   => array(0x571), 0x542   => array(0x572), 0x543   => array(0x573)
  1178.                     ,0x544   => array(0x574), 0x545   => array(0x575), 0x546   => array(0x576)
  1179.                     ,0x547   => array(0x577), 0x548   => array(0x578), 0x549   => array(0x579)
  1180.                     ,0x54A   => array(0x57A), 0x54B   => array(0x57B), 0x54C   => array(0x57C)
  1181.                     ,0x54D   => array(0x57D), 0x54E   => array(0x57E), 0x54F   => array(0x57F)
  1182.                     ,0x550   => array(0x580), 0x551   => array(0x581), 0x552   => array(0x582)
  1183.                     ,0x553   => array(0x583), 0x554   => array(0x584), 0x555   => array(0x585)
  1184.                     ,0x556 => array(0x586), 0x587 => array(0x565, 0x582), 0xE33 => array(0xE4D, 0xE32)
  1185.                     ,0x1E00  => array(0x1E01), 0x1E02  => array(0x1E03), 0x1E04  => array(0x1E05)
  1186.                     ,0x1E06  => array(0x1E07), 0x1E08  => array(0x1E09), 0x1E0A  => array(0x1E0B)
  1187.                     ,0x1E0C  => array(0x1E0D), 0x1E0E  => array(0x1E0F), 0x1E10  => array(0x1E11)
  1188.                     ,0x1E12  => array(0x1E13), 0x1E14  => array(0x1E15), 0x1E16  => array(0x1E17)
  1189.                     ,0x1E18  => array(0x1E19), 0x1E1A  => array(0x1E1B), 0x1E1C  => array(0x1E1D)
  1190.                     ,0x1E1E  => array(0x1E1F), 0x1E20  => array(0x1E21), 0x1E22  => array(0x1E23)
  1191.                     ,0x1E24  => array(0x1E25), 0x1E26  => array(0x1E27), 0x1E28  => array(0x1E29)
  1192.                     ,0x1E2A  => array(0x1E2B), 0x1E2C  => array(0x1E2D), 0x1E2E  => array(0x1E2F)
  1193.                     ,0x1E30  => array(0x1E31), 0x1E32  => array(0x1E33), 0x1E34  => array(0x1E35)
  1194.                     ,0x1E36  => array(0x1E37), 0x1E38  => array(0x1E39), 0x1E3A  => array(0x1E3B)
  1195.                     ,0x1E3C  => array(0x1E3D), 0x1E3E  => array(0x1E3F), 0x1E40  => array(0x1E41)
  1196.                     ,0x1E42  => array(0x1E43), 0x1E44  => array(0x1E45), 0x1E46  => array(0x1E47)
  1197.                     ,0x1E48  => array(0x1E49), 0x1E4A  => array(0x1E4B), 0x1E4C  => array(0x1E4D)
  1198.                     ,0x1E4E  => array(0x1E4F), 0x1E50  => array(0x1E51), 0x1E52  => array(0x1E53)
  1199.                     ,0x1E54  => array(0x1E55), 0x1E56  => array(0x1E57), 0x1E58  => array(0x1E59)
  1200.                     ,0x1E5A  => array(0x1E5B), 0x1E5C  => array(0x1E5D), 0x1E5E  => array(0x1E5F)
  1201.                     ,0x1E60  => array(0x1E61), 0x1E62  => array(0x1E63), 0x1E64  => array(0x1E65)
  1202.                     ,0x1E66  => array(0x1E67), 0x1E68  => array(0x1E69), 0x1E6A  => array(0x1E6B)
  1203.                     ,0x1E6C  => array(0x1E6D), 0x1E6E  => array(0x1E6F), 0x1E70  => array(0x1E71)
  1204.                     ,0x1E72  => array(0x1E73), 0x1E74  => array(0x1E75), 0x1E76  => array(0x1E77)
  1205.                     ,0x1E78  => array(0x1E79), 0x1E7A  => array(0x1E7B), 0x1E7C  => array(0x1E7D)
  1206.                     ,0x1E7E  => array(0x1E7F), 0x1E80  => array(0x1E81), 0x1E82  => array(0x1E83)
  1207.                     ,0x1E84  => array(0x1E85), 0x1E86  => array(0x1E87), 0x1E88  => array(0x1E89)
  1208.                     ,0x1E8A  => array(0x1E8B), 0x1E8C  => array(0x1E8D), 0x1E8E  => array(0x1E8F)
  1209.                     ,0x1E90  => array(0x1E91), 0x1E92  => array(0x1E93), 0x1E94  => array(0x1E95)
  1210.                     ,0x1E96  => array(0x68, 0x331), 0x1E97  => array(0x74, 0x308), 0x1E98  => array(0x77, 0x30A)
  1211.                     ,0x1E99  => array(0x79, 0x30A), 0x1E9A  => array(0x61, 0x2BE), 0x1E9B  => array(0x1E61)
  1212.                     ,0x1EA0  => array(0x1EA1), 0x1EA2  => array(0x1EA3), 0x1EA4  => array(0x1EA5)
  1213.                     ,0x1EA6  => array(0x1EA7), 0x1EA8  => array(0x1EA9), 0x1EAA  => array(0x1EAB)
  1214.                     ,0x1EAC  => array(0x1EAD), 0x1EAE  => array(0x1EAF), 0x1EB0  => array(0x1EB1)
  1215.                     ,0x1EB2  => array(0x1EB3), 0x1EB4  => array(0x1EB5), 0x1EB6  => array(0x1EB7)
  1216.                     ,0x1EB8  => array(0x1EB9), 0x1EBA  => array(0x1EBB), 0x1EBC  => array(0x1EBD)
  1217.                     ,0x1EBE  => array(0x1EBF), 0x1EC0  => array(0x1EC1), 0x1EC2  => array(0x1EC3)
  1218.                     ,0x1EC4  => array(0x1EC5), 0x1EC6  => array(0x1EC7), 0x1EC8  => array(0x1EC9)
  1219.                     ,0x1ECA  => array(0x1ECB), 0x1ECC  => array(0x1ECD), 0x1ECE  => array(0x1ECF)
  1220.                     ,0x1ED0  => array(0x1ED1), 0x1ED2  => array(0x1ED3), 0x1ED4  => array(0x1ED5)
  1221.                     ,0x1ED6  => array(0x1ED7), 0x1ED8  => array(0x1ED9), 0x1EDA  => array(0x1EDB)
  1222.                     ,0x1EDC  => array(0x1EDD), 0x1EDE  => array(0x1EDF), 0x1EE0  => array(0x1EE1)
  1223.                     ,0x1EE2  => array(0x1EE3), 0x1EE4  => array(0x1EE5), 0x1EE6  => array(0x1EE7)
  1224.                     ,0x1EE8  => array(0x1EE9), 0x1EEA  => array(0x1EEB), 0x1EEC  => array(0x1EED)
  1225.                     ,0x1EEE  => array(0x1EEF), 0x1EF0  => array(0x1EF1), 0x1EF2  => array(0x1EF3)
  1226.                     ,0x1EF4  => array(0x1EF5), 0x1EF6  => array(0x1EF7), 0x1EF8  => array(0x1EF9)
  1227.                     ,0x1F08  => array(0x1F00), 0x1F09  => array(0x1F01), 0x1F0A  => array(0x1F02)
  1228.                     ,0x1F0B  => array(0x1F03), 0x1F0C  => array(0x1F04), 0x1F0D  => array(0x1F05)
  1229.                     ,0x1F0E  => array(0x1F06), 0x1F0F  => array(0x1F07), 0x1F18  => array(0x1F10)
  1230.                     ,0x1F19  => array(0x1F11), 0x1F1A  => array(0x1F12), 0x1F1B  => array(0x1F13)
  1231.                     ,0x1F1C  => array(0x1F14), 0x1F1D  => array(0x1F15), 0x1F28  => array(0x1F20)
  1232.                     ,0x1F29  => array(0x1F21), 0x1F2A  => array(0x1F22), 0x1F2B  => array(0x1F23)
  1233.                     ,0x1F2C  => array(0x1F24), 0x1F2D  => array(0x1F25), 0x1F2E  => array(0x1F26)
  1234.                     ,0x1F2F  => array(0x1F27), 0x1F38  => array(0x1F30), 0x1F39  => array(0x1F31)
  1235.                     ,0x1F3A  => array(0x1F32), 0x1F3B  => array(0x1F33), 0x1F3C  => array(0x1F34)
  1236.                     ,0x1F3D  => array(0x1F35), 0x1F3E  => array(0x1F36), 0x1F3F  => array(0x1F37)
  1237.                     ,0x1F48  => array(0x1F40), 0x1F49  => array(0x1F41), 0x1F4A  => array(0x1F42)
  1238.                     ,0x1F4B  => array(0x1F43), 0x1F4C  => array(0x1F44), 0x1F4D  => array(0x1F45)
  1239.                     ,0x1F50  => array(0x3C5, 0x313), 0x1F52  => array(0x3C5, 0x313, 0x300)
  1240.                     ,0x1F54  => array(0x3C5, 0x313, 0x301), 0x1F56  => array(0x3C5, 0x313, 0x342)
  1241.                     ,0x1F59  => array(0x1F51), 0x1F5B  => array(0x1F53), 0x1F5D  => array(0x1F55)
  1242.                     ,0x1F5F  => array(0x1F57), 0x1F68  => array(0x1F60), 0x1F69  => array(0x1F61)
  1243.                     ,0x1F6A  => array(0x1F62), 0x1F6B  => array(0x1F63), 0x1F6C  => array(0x1F64)
  1244.                     ,0x1F6D  => array(0x1F65), 0x1F6E  => array(0x1F66), 0x1F6F  => array(0x1F67)
  1245.                     ,0x1F80  => array(0x1F00, 0x3B9), 0x1F81  => array(0x1F01, 0x3B9)
  1246.                     ,0x1F82  => array(0x1F02, 0x3B9), 0x1F83  => array(0x1F03, 0x3B9)
  1247.                     ,0x1F84  => array(0x1F04, 0x3B9), 0x1F85  => array(0x1F05, 0x3B9)
  1248.                     ,0x1F86  => array(0x1F06, 0x3B9), 0x1F87  => array(0x1F07, 0x3B9)
  1249.                     ,0x1F88  => array(0x1F00, 0x3B9), 0x1F89  => array(0x1F01, 0x3B9)
  1250.                     ,0x1F8A  => array(0x1F02, 0x3B9), 0x1F8B  => array(0x1F03, 0x3B9)
  1251.                     ,0x1F8C  => array(0x1F04, 0x3B9), 0x1F8D  => array(0x1F05, 0x3B9)
  1252.                     ,0x1F8E  => array(0x1F06, 0x3B9), 0x1F8F  => array(0x1F07, 0x3B9)
  1253.                     ,0x1F90  => array(0x1F20, 0x3B9), 0x1F91  => array(0x1F21, 0x3B9)
  1254.                     ,0x1F92  => array(0x1F22, 0x3B9), 0x1F93  => array(0x1F23, 0x3B9)
  1255.                     ,0x1F94  => array(0x1F24, 0x3B9), 0x1F95  => array(0x1F25, 0x3B9)
  1256.                     ,0x1F96  => array(0x1F26, 0x3B9), 0x1F97  => array(0x1F27, 0x3B9)
  1257.                     ,0x1F98  => array(0x1F20, 0x3B9), 0x1F99  => array(0x1F21, 0x3B9)
  1258.                     ,0x1F9A  => array(0x1F22, 0x3B9), 0x1F9B  => array(0x1F23, 0x3B9)
  1259.                     ,0x1F9C  => array(0x1F24, 0x3B9), 0x1F9D  => array(0x1F25, 0x3B9)
  1260.                     ,0x1F9E  => array(0x1F26, 0x3B9), 0x1F9F  => array(0x1F27, 0x3B9)
  1261.                     ,0x1FA0  => array(0x1F60, 0x3B9), 0x1FA1  => array(0x1F61, 0x3B9)
  1262.                     ,0x1FA2  => array(0x1F62, 0x3B9), 0x1FA3  => array(0x1F63, 0x3B9)
  1263.                     ,0x1FA4  => array(0x1F64, 0x3B9), 0x1FA5  => array(0x1F65, 0x3B9)
  1264.                     ,0x1FA6  => array(0x1F66, 0x3B9), 0x1FA7  => array(0x1F67, 0x3B9)
  1265.                     ,0x1FA8  => array(0x1F60, 0x3B9), 0x1FA9  => array(0x1F61, 0x3B9)
  1266.                     ,0x1FAA  => array(0x1F62, 0x3B9), 0x1FAB  => array(0x1F63, 0x3B9)
  1267.                     ,0x1FAC  => array(0x1F64, 0x3B9), 0x1FAD  => array(0x1F65, 0x3B9)
  1268.                     ,0x1FAE  => array(0x1F66, 0x3B9), 0x1FAF  => array(0x1F67, 0x3B9)
  1269.                     ,0x1FB2  => array(0x1F70, 0x3B9), 0x1FB3  => array(0x3B1, 0x3B9)
  1270.                     ,0x1FB4  => array(0x3AC, 0x3B9), 0x1FB6  => array(0x3B1, 0x342)
  1271.                     ,0x1FB7  => array(0x3B1, 0x342, 0x3B9), 0x1FB8  => array(0x1FB0)
  1272.                     ,0x1FB9  => array(0x1FB1), 0x1FBA  => array(0x1F70), 0x1FBB  => array(0x1F71)
  1273.                     ,0x1FBC  => array(0x3B1, 0x3B9), 0x1FBE  => array(0x3B9)
  1274.                     ,0x1FC2  => array(0x1F74, 0x3B9), 0x1FC3  => array(0x3B7, 0x3B9)
  1275.                     ,0x1FC4  => array(0x3AE, 0x3B9), 0x1FC6  => array(0x3B7, 0x342)
  1276.                     ,0x1FC7  => array(0x3B7, 0x342, 0x3B9), 0x1FC8  => array(0x1F72)
  1277.                     ,0x1FC9  => array(0x1F73), 0x1FCA  => array(0x1F74), 0x1FCB  => array(0x1F75)
  1278.                     ,0x1FCC  => array(0x3B7, 0x3B9), 0x1FD2  => array(0x3B9, 0x308, 0x300)
  1279.                     ,0x1FD3  => array(0x3B9, 0x308, 0x301), 0x1FD6  => array(0x3B9, 0x342)
  1280.                     ,0x1FD7  => array(0x3B9, 0x308, 0x342), 0x1FD8  => array(0x1FD0)
  1281.                     ,0x1FD9  => array(0x1FD1), 0x1FDA  => array(0x1F76)
  1282.                     ,0x1FDB  => array(0x1F77), 0x1FE2  => array(0x3C5, 0x308, 0x300)
  1283.                     ,0x1FE3  => array(0x3C5, 0x308, 0x301), 0x1FE4  => array(0x3C1, 0x313)
  1284.                     ,0x1FE6  => array(0x3C5, 0x342), 0x1FE7  => array(0x3C5, 0x308, 0x342)
  1285.                     ,0x1FE8  => array(0x1FE0), 0x1FE9  => array(0x1FE1)
  1286.                     ,0x1FEA  => array(0x1F7A), 0x1FEB  => array(0x1F7B)
  1287.                     ,0x1FEC  => array(0x1FE5), 0x1FF2  => array(0x1F7C, 0x3B9)
  1288.                     ,0x1FF3  => array(0x3C9, 0x3B9), 0x1FF4  => array(0x3CE, 0x3B9)
  1289.                     ,0x1FF6  => array(0x3C9, 0x342), 0x1FF7  => array(0x3C9, 0x342, 0x3B9)
  1290.                     ,0x1FF8  => array(0x1F78), 0x1FF9  => array(0x1F79), 0x1FFA  => array(0x1F7C)
  1291.                     ,0x1FFB  => array(0x1F7D), 0x1FFC  => array(0x3C9, 0x3B9)
  1292.                     ,0x20A8  => array(0x72, 0x73), 0x2102  => array(0x63), 0x2103  => array(0xB0, 0x63)
  1293.                     ,0x2107  => array(0x25B), 0x2109  => array(0xB0, 0x66), 0x210B  => array(0x68)
  1294.                     ,0x210C  => array(0x68), 0x210D  => array(0x68), 0x2110  => array(0x69)
  1295.                     ,0x2111  => array(0x69), 0x2112  => array(0x6C), 0x2115  => array(0x6E)
  1296.                     ,0x2116  => array(0x6E, 0x6F), 0x2119  => array(0x70), 0x211A  => array(0x71)
  1297.                     ,0x211B  => array(0x72), 0x211C  => array(0x72), 0x211D  => array(0x72)
  1298.                     ,0x2120  => array(0x73, 0x6D), 0x2121  => array(0x74, 0x65, 0x6C)
  1299.                     ,0x2122  => array(0x74, 0x6D), 0x2124  => array(0x7A), 0x2126  => array(0x3C9)
  1300.                     ,0x2128  => array(0x7A), 0x212A  => array(0x6B), 0x212B  => array(0xE5)
  1301.                     ,0x212C  => array(0x62), 0x212D  => array(0x63), 0x2130  => array(0x65)
  1302.                     ,0x2131  => array(0x66), 0x2133  => array(0x6D), 0x213E  => array(0x3B3)
  1303.                     ,0x213F  => array(0x3C0), 0x2145  => array(0x64) ,0x2160  => array(0x2170)
  1304.                     ,0x2161  => array(0x2171), 0x2162  => array(0x2172), 0x2163  => array(0x2173)
  1305.                     ,0x2164  => array(0x2174), 0x2165  => array(0x2175), 0x2166  => array(0x2176)
  1306.                     ,0x2167  => array(0x2177), 0x2168  => array(0x2178), 0x2169  => array(0x2179)
  1307.                     ,0x216A  => array(0x217A), 0x216B  => array(0x217B), 0x216C  => array(0x217C)
  1308.                     ,0x216D  => array(0x217D), 0x216E  => array(0x217E), 0x216F  => array(0x217F)
  1309.                     ,0x24B6  => array(0x24D0), 0x24B7  => array(0x24D1), 0x24B8  => array(0x24D2)
  1310.                     ,0x24B9  => array(0x24D3), 0x24BA  => array(0x24D4), 0x24BB  => array(0x24D5)
  1311.                     ,0x24BC  => array(0x24D6), 0x24BD  => array(0x24D7), 0x24BE  => array(0x24D8)
  1312.                     ,0x24BF  => array(0x24D9), 0x24C0  => array(0x24DA), 0x24C1  => array(0x24DB)
  1313.                     ,0x24C2  => array(0x24DC), 0x24C3  => array(0x24DD), 0x24C4  => array(0x24DE)
  1314.                     ,0x24C5  => array(0x24DF), 0x24C6  => array(0x24E0), 0x24C7  => array(0x24E1)
  1315.                     ,0x24C8  => array(0x24E2), 0x24C9  => array(0x24E3), 0x24CA  => array(0x24E4)
  1316.                     ,0x24CB  => array(0x24E5), 0x24CC  => array(0x24E6), 0x24CD  => array(0x24E7)
  1317.                     ,0x24CE  => array(0x24E8), 0x24CF  => array(0x24E9), 0x3371  => array(0x68, 0x70, 0x61)
  1318.                     ,0x3373  => array(0x61, 0x75), 0x3375  => array(0x6F, 0x76)
  1319.                     ,0x3380  => array(0x70, 0x61), 0x3381  => array(0x6E, 0x61)
  1320.                     ,0x3382  => array(0x3BC, 0x61), 0x3383  => array(0x6D, 0x61)
  1321.                     ,0x3384  => array(0x6B, 0x61), 0x3385  => array(0x6B, 0x62)
  1322.                     ,0x3386  => array(0x6D, 0x62), 0x3387  => array(0x67, 0x62)
  1323.                     ,0x338A  => array(0x70, 0x66), 0x338B  => array(0x6E, 0x66)
  1324.                     ,0x338C  => array(0x3BC, 0x66), 0x3390  => array(0x68, 0x7A)
  1325.                     ,0x3391  => array(0x6B, 0x68, 0x7A), 0x3392  => array(0x6D, 0x68, 0x7A)
  1326.                     ,0x3393  => array(0x67, 0x68, 0x7A), 0x3394  => array(0x74, 0x68, 0x7A)
  1327.                     ,0x33A9  => array(0x70, 0x61), 0x33AA  => array(0x6B, 0x70, 0x61)
  1328.                     ,0x33AB  => array(0x6D, 0x70, 0x61), 0x33AC  => array(0x67, 0x70, 0x61)
  1329.                     ,0x33B4  => array(0x70, 0x76), 0x33B5  => array(0x6E, 0x76)
  1330.                     ,0x33B6  => array(0x3BC, 0x76), 0x33B7  => array(0x6D, 0x76)
  1331.                     ,0x33B8  => array(0x6B, 0x76), 0x33B9  => array(0x6D, 0x76)
  1332.                     ,0x33BA  => array(0x70, 0x77), 0x33BB  => array(0x6E, 0x77)
  1333.                     ,0x33BC  => array(0x3BC, 0x77), 0x33BD  => array(0x6D, 0x77)
  1334.                     ,0x33BE  => array(0x6B, 0x77), 0x33BF  => array(0x6D, 0x77)
  1335.                     ,0x33C0  => array(0x6B, 0x3C9), 0x33C1  => array(0x6D, 0x3C9) /*
  1336.                     ,0x33C2  => array(0x61, 0x2E, 0x6D, 0x2E) */
  1337.                     ,0x33C3  => array(0x62, 0x71), 0x33C6  => array(0x63, 0x2215, 0x6B, 0x67)
  1338.                     ,0x33C7  => array(0x63, 0x6F, 0x2E), 0x33C8  => array(0x64, 0x62)
  1339.                     ,0x33C9  => array(0x67, 0x79), 0x33CB  => array(0x68, 0x70)
  1340.                     ,0x33CD  => array(0x6B, 0x6B), 0x33CE  => array(0x6B, 0x6D)
  1341.                     ,0x33D7  => array(0x70, 0x68), 0x33D9  => array(0x70, 0x70, 0x6D)
  1342.                     ,0x33DA  => array(0x70, 0x72), 0x33DC  => array(0x73, 0x76)
  1343.                     ,0x33DD  => array(0x77, 0x62), 0xFB00  => array(0x66, 0x66)
  1344.                     ,0xFB01  => array(0x66, 0x69), 0xFB02  => array(0x66, 0x6C)
  1345.                     ,0xFB03  => array(0x66, 0x66, 0x69), 0xFB04  => array(0x66, 0x66, 0x6C)
  1346.                     ,0xFB05  => array(0x73, 0x74), 0xFB06  => array(0x73, 0x74)
  1347.                     ,0xFB13  => array(0x574, 0x576), 0xFB14  => array(0x574, 0x565)
  1348.                     ,0xFB15  => array(0x574, 0x56B), 0xFB16  => array(0x57E, 0x576)
  1349.                     ,0xFB17  => array(0x574, 0x56D), 0xFF21  => array(0xFF41)
  1350.                     ,0xFF22  => array(0xFF42), 0xFF23  => array(0xFF43), 0xFF24  => array(0xFF44)
  1351.                     ,0xFF25  => array(0xFF45), 0xFF26  => array(0xFF46), 0xFF27  => array(0xFF47)
  1352.                     ,0xFF28  => array(0xFF48), 0xFF29  => array(0xFF49), 0xFF2A  => array(0xFF4A)
  1353.                     ,0xFF2B  => array(0xFF4B), 0xFF2C  => array(0xFF4C), 0xFF2D  => array(0xFF4D)
  1354.                     ,0xFF2E  => array(0xFF4E), 0xFF2F  => array(0xFF4F), 0xFF30  => array(0xFF50)
  1355.                     ,0xFF31  => array(0xFF51), 0xFF32  => array(0xFF52), 0xFF33  => array(0xFF53)
  1356.                     ,0xFF34  => array(0xFF54), 0xFF35  => array(0xFF55), 0xFF36  => array(0xFF56)
  1357.                     ,0xFF37  => array(0xFF57), 0xFF38  => array(0xFF58), 0xFF39  => array(0xFF59)
  1358.                     ,0xFF3A  => array(0xFF5A), 0x10400 => array(0x10428), 0x10401 => array(0x10429)
  1359.                     ,0x10402 => array(0x1042A), 0x10403 => array(0x1042B), 0x10404 => array(0x1042C)
  1360.                     ,0x10405 => array(0x1042D), 0x10406 => array(0x1042E), 0x10407 => array(0x1042F)
  1361.                     ,0x10408 => array(0x10430), 0x10409 => array(0x10431), 0x1040A => array(0x10432)
  1362.                     ,0x1040B => array(0x10433), 0x1040C => array(0x10434), 0x1040D => array(0x10435)
  1363.                     ,0x1040E => array(0x10436), 0x1040F => array(0x10437), 0x10410 => array(0x10438)
  1364.                     ,0x10411 => array(0x10439), 0x10412 => array(0x1043A), 0x10413 => array(0x1043B)
  1365.                     ,0x10414 => array(0x1043C), 0x10415 => array(0x1043D), 0x10416 => array(0x1043E)
  1366.                     ,0x10417 => array(0x1043F), 0x10418 => array(0x10440), 0x10419 => array(0x10441)
  1367.                     ,0x1041A => array(0x10442), 0x1041B => array(0x10443), 0x1041C => array(0x10444)
  1368.                     ,0x1041D => array(0x10445), 0x1041E => array(0x10446), 0x1041F => array(0x10447)
  1369.                     ,0x10420 => array(0x10448), 0x10421 => array(0x10449), 0x10422 => array(0x1044A)
  1370.                     ,0x10423 => array(0x1044B), 0x10424 => array(0x1044C), 0x10425 => array(0x1044D)
  1371.                     ,0x1D400 => array(0x61), 0x1D401 => array(0x62), 0x1D402 => array(0x63)
  1372.                     ,0x1D403 => array(0x64), 0x1D404 => array(0x65), 0x1D405 => array(0x66)
  1373.                     ,0x1D406 => array(0x67), 0x1D407 => array(0x68), 0x1D408 => array(0x69)
  1374.                     ,0x1D409 => array(0x6A), 0x1D40A => array(0x6B), 0x1D40B => array(0x6C)
  1375.                     ,0x1D40C => array(0x6D), 0x1D40D => array(0x6E), 0x1D40E => array(0x6F)
  1376.                     ,0x1D40F => array(0x70), 0x1D410 => array(0x71), 0x1D411 => array(0x72)
  1377.                     ,0x1D412 => array(0x73), 0x1D413 => array(0x74), 0x1D414 => array(0x75)
  1378.                     ,0x1D415 => array(0x76), 0x1D416 => array(0x77), 0x1D417 => array(0x78)
  1379.                     ,0x1D418 => array(0x79), 0x1D419 => array(0x7A), 0x1D434 => array(0x61)
  1380.                     ,0x1D435 => array(0x62), 0x1D436 => array(0x63), 0x1D437 => array(0x64)
  1381.                     ,0x1D438 => array(0x65), 0x1D439 => array(0x66), 0x1D43A => array(0x67)
  1382.                     ,0x1D43B => array(0x68), 0x1D43C => array(0x69), 0x1D43D => array(0x6A)
  1383.                     ,0x1D43E => array(0x6B), 0x1D43F => array(0x6C), 0x1D440 => array(0x6D)
  1384.                     ,0x1D441 => array(0x6E), 0x1D442 => array(0x6F), 0x1D443 => array(0x70)
  1385.                     ,0x1D444 => array(0x71), 0x1D445 => array(0x72), 0x1D446 => array(0x73)
  1386.                     ,0x1D447 => array(0x74), 0x1D448 => array(0x75), 0x1D449 => array(0x76)
  1387.                     ,0x1D44A => array(0x77), 0x1D44B => array(0x78), 0x1D44C => array(0x79)
  1388.                     ,0x1D44D => array(0x7A), 0x1D468 => array(0x61), 0x1D469 => array(0x62)
  1389.                     ,0x1D46A => array(0x63), 0x1D46B => array(0x64), 0x1D46C => array(0x65)
  1390.                     ,0x1D46D => array(0x66), 0x1D46E => array(0x67), 0x1D46F => array(0x68)
  1391.                     ,0x1D470 => array(0x69), 0x1D471 => array(0x6A), 0x1D472 => array(0x6B)
  1392.                     ,0x1D473 => array(0x6C), 0x1D474 => array(0x6D), 0x1D475 => array(0x6E)
  1393.                     ,0x1D476 => array(0x6F), 0x1D477 => array(0x70), 0x1D478 => array(0x71)
  1394.                     ,0x1D479 => array(0x72), 0x1D47A => array(0x73), 0x1D47B => array(0x74)
  1395.                     ,0x1D47C => array(0x75), 0x1D47D => array(0x76), 0x1D47E => array(0x77)
  1396.                     ,0x1D47F => array(0x78), 0x1D480 => array(0x79), 0x1D481 => array(0x7A)
  1397.                     ,0x1D49C => array(0x61), 0x1D49E => array(0x63), 0x1D49F => array(0x64)
  1398.                     ,0x1D4A2 => array(0x67), 0x1D4A5 => array(0x6A), 0x1D4A6 => array(0x6B)
  1399.                     ,0x1D4A9 => array(0x6E), 0x1D4AA => array(0x6F), 0x1D4AB => array(0x70)
  1400.                     ,0x1D4AC => array(0x71), 0x1D4AE => array(0x73), 0x1D4AF => array(0x74)
  1401.                     ,0x1D4B0 => array(0x75), 0x1D4B1 => array(0x76), 0x1D4B2 => array(0x77)
  1402.                     ,0x1D4B3 => array(0x78), 0x1D4B4 => array(0x79), 0x1D4B5 => array(0x7A)
  1403.                     ,0x1D4D0 => array(0x61), 0x1D4D1 => array(0x62), 0x1D4D2 => array(0x63)
  1404.                     ,0x1D4D3 => array(0x64), 0x1D4D4 => array(0x65), 0x1D4D5 => array(0x66)
  1405.                     ,0x1D4D6 => array(0x67), 0x1D4D7 => array(0x68), 0x1D4D8 => array(0x69)
  1406.                     ,0x1D4D9 => array(0x6A), 0x1D4DA => array(0x6B), 0x1D4DB => array(0x6C)
  1407.                     ,0x1D4DC => array(0x6D), 0x1D4DD => array(0x6E), 0x1D4DE => array(0x6F)
  1408.                     ,0x1D4DF => array(0x70), 0x1D4E0 => array(0x71), 0x1D4E1 => array(0x72)
  1409.                     ,0x1D4E2 => array(0x73), 0x1D4E3 => array(0x74), 0x1D4E4 => array(0x75)
  1410.                     ,0x1D4E5 => array(0x76), 0x1D4E6 => array(0x77), 0x1D4E7 => array(0x78)
  1411.                     ,0x1D4E8 => array(0x79), 0x1D4E9 => array(0x7A), 0x1D504 => array(0x61)
  1412.                     ,0x1D505 => array(0x62), 0x1D507 => array(0x64), 0x1D508 => array(0x65)
  1413.                     ,0x1D509 => array(0x66), 0x1D50A => array(0x67), 0x1D50D => array(0x6A)
  1414.                     ,0x1D50E => array(0x6B), 0x1D50F => array(0x6C), 0x1D510 => array(0x6D)
  1415.                     ,0x1D511 => array(0x6E), 0x1D512 => array(0x6F), 0x1D513 => array(0x70)
  1416.                     ,0x1D514 => array(0x71), 0x1D516 => array(0x73), 0x1D517 => array(0x74)
  1417.                     ,0x1D518 => array(0x75), 0x1D519 => array(0x76), 0x1D51A => array(0x77)
  1418.                     ,0x1D51B => array(0x78), 0x1D51C => array(0x79), 0x1D538 => array(0x61)
  1419.                     ,0x1D539 => array(0x62), 0x1D53B => array(0x64), 0x1D53C => array(0x65)
  1420.                     ,0x1D53D => array(0x66), 0x1D53E => array(0x67), 0x1D540 => array(0x69)
  1421.                     ,0x1D541 => array(0x6A), 0x1D542 => array(0x6B), 0x1D543 => array(0x6C)
  1422.                     ,0x1D544 => array(0x6D), 0x1D546 => array(0x6F), 0x1D54A => array(0x73)
  1423.                     ,0x1D54B => array(0x74), 0x1D54C => array(0x75), 0x1D54D => array(0x76)
  1424.                     ,0x1D54E => array(0x77), 0x1D54F => array(0x78), 0x1D550 => array(0x79)
  1425.                     ,0x1D56C => array(0x61), 0x1D56D => array(0x62), 0x1D56E => array(0x63)
  1426.                     ,0x1D56F => array(0x64), 0x1D570 => array(0x65), 0x1D571 => array(0x66)
  1427.                     ,0x1D572 => array(0x67), 0x1D573 => array(0x68), 0x1D574 => array(0x69)
  1428.                     ,0x1D575 => array(0x6A), 0x1D576 => array(0x6B), 0x1D577 => array(0x6C)
  1429.                     ,0x1D578 => array(0x6D), 0x1D579 => array(0x6E), 0x1D57A => array(0x6F)
  1430.                     ,0x1D57B => array(0x70), 0x1D57C => array(0x71), 0x1D57D => array(0x72)
  1431.                     ,0x1D57E => array(0x73), 0x1D57F => array(0x74), 0x1D580 => array(0x75)
  1432.                     ,0x1D581 => array(0x76), 0x1D582 => array(0x77), 0x1D583 => array(0x78)
  1433.                     ,0x1D584 => array(0x79), 0x1D585 => array(0x7A), 0x1D5A0 => array(0x61)
  1434.                     ,0x1D5A1 => array(0x62), 0x1D5A2 => array(0x63), 0x1D5A3 => array(0x64)
  1435.                     ,0x1D5A4 => array(0x65), 0x1D5A5 => array(0x66), 0x1D5A6 => array(0x67)
  1436.                     ,0x1D5A7 => array(0x68), 0x1D5A8 => array(0x69), 0x1D5A9 => array(0x6A)
  1437.                     ,0x1D5AA => array(0x6B), 0x1D5AB => array(0x6C), 0x1D5AC => array(0x6D)
  1438.                     ,0x1D5AD => array(0x6E), 0x1D5AE => array(0x6F), 0x1D5AF => array(0x70)
  1439.                     ,0x1D5B0 => array(0x71), 0x1D5B1 => array(0x72), 0x1D5B2 => array(0x73)
  1440.                     ,0x1D5B3 => array(0x74), 0x1D5B4 => array(0x75), 0x1D5B5 => array(0x76)
  1441.                     ,0x1D5B6 => array(0x77), 0x1D5B7 => array(0x78), 0x1D5B8 => array(0x79)
  1442.                     ,0x1D5B9 => array(0x7A), 0x1D5D4 => array(0x61), 0x1D5D5 => array(0x62)
  1443.                     ,0x1D5D6 => array(0x63), 0x1D5D7 => array(0x64), 0x1D5D8 => array(0x65)
  1444.                     ,0x1D5D9 => array(0x66), 0x1D5DA => array(0x67), 0x1D5DB => array(0x68)
  1445.                     ,0x1D5DC => array(0x69), 0x1D5DD => array(0x6A), 0x1D5DE => array(0x6B)
  1446.                     ,0x1D5DF => array(0x6C), 0x1D5E0 => array(0x6D), 0x1D5E1 => array(0x6E)
  1447.                     ,0x1D5E2 => array(0x6F), 0x1D5E3 => array(0x70), 0x1D5E4 => array(0x71)
  1448.                     ,0x1D5E5 => array(0x72), 0x1D5E6 => array(0x73), 0x1D5E7 => array(0x74)
  1449.                     ,0x1D5E8 => array(0x75), 0x1D5E9 => array(0x76), 0x1D5EA => array(0x77)
  1450.                     ,0x1D5EB => array(0x78), 0x1D5EC => array(0x79), 0x1D5ED => array(0x7A)
  1451.                     ,0x1D608 => array(0x61), 0x1D609 => array(0x62) ,0x1D60A => array(0x63)
  1452.                     ,0x1D60B => array(0x64), 0x1D60C => array(0x65), 0x1D60D => array(0x66)
  1453.                     ,0x1D60E => array(0x67), 0x1D60F => array(0x68), 0x1D610 => array(0x69)
  1454.                     ,0x1D611 => array(0x6A), 0x1D612 => array(0x6B), 0x1D613 => array(0x6C)
  1455.                     ,0x1D614 => array(0x6D), 0x1D615 => array(0x6E), 0x1D616 => array(0x6F)
  1456.                     ,0x1D617 => array(0x70), 0x1D618 => array(0x71), 0x1D619 => array(0x72)
  1457.                     ,0x1D61A => array(0x73), 0x1D61B => array(0x74), 0x1D61C => array(0x75)
  1458.                     ,0x1D61D => array(0x76), 0x1D61E => array(0x77), 0x1D61F => array(0x78)
  1459.                     ,0x1D620 => array(0x79), 0x1D621 => array(0x7A), 0x1D63C => array(0x61)
  1460.                     ,0x1D63D => array(0x62), 0x1D63E => array(0x63), 0x1D63F => array(0x64)
  1461.                     ,0x1D640 => array(0x65), 0x1D641 => array(0x66), 0x1D642 => array(0x67)
  1462.                     ,0x1D643 => array(0x68), 0x1D644 => array(0x69), 0x1D645 => array(0x6A)
  1463.                     ,0x1D646 => array(0x6B), 0x1D647 => array(0x6C), 0x1D648 => array(0x6D)
  1464.                     ,0x1D649 => array(0x6E), 0x1D64A => array(0x6F), 0x1D64B => array(0x70)
  1465.                     ,0x1D64C => array(0x71), 0x1D64D => array(0x72), 0x1D64E => array(0x73)
  1466.                     ,0x1D64F => array(0x74), 0x1D650 => array(0x75), 0x1D651 => array(0x76)
  1467.                     ,0x1D652 => array(0x77), 0x1D653 => array(0x78), 0x1D654 => array(0x79)
  1468.                     ,0x1D655 => array(0x7A), 0x1D670 => array(0x61), 0x1D671 => array(0x62)
  1469.                     ,0x1D672 => array(0x63), 0x1D673 => array(0x64), 0x1D674 => array(0x65)
  1470.                     ,0x1D675 => array(0x66), 0x1D676 => array(0x67), 0x1D677 => array(0x68)
  1471.                     ,0x1D678 => array(0x69), 0x1D679 => array(0x6A), 0x1D67A => array(0x6B)
  1472.                     ,0x1D67B => array(0x6C), 0x1D67C => array(0x6D), 0x1D67D => array(0x6E)
  1473.                     ,0x1D67E => array(0x6F), 0x1D67F => array(0x70), 0x1D680 => array(0x71)
  1474.                     ,0x1D681 => array(0x72), 0x1D682 => array(0x73), 0x1D683 => array(0x74)
  1475.                     ,0x1D684 => array(0x75), 0x1D685 => array(0x76), 0x1D686 => array(0x77)
  1476.                     ,0x1D687 => array(0x78), 0x1D688 => array(0x79), 0x1D689 => array(0x7A)
  1477.                     ,0x1D6A8 => array(0x3B1), 0x1D6A9 => array(0x3B2), 0x1D6AA => array(0x3B3)
  1478.                     ,0x1D6AB => array(0x3B4), 0x1D6AC => array(0x3B5), 0x1D6AD => array(0x3B6)
  1479.                     ,0x1D6AE => array(0x3B7), 0x1D6AF => array(0x3B8), 0x1D6B0 => array(0x3B9)
  1480.                     ,0x1D6B1 => array(0x3BA), 0x1D6B2 => array(0x3BB), 0x1D6B3 => array(0x3BC)
  1481.                     ,0x1D6B4 => array(0x3BD), 0x1D6B5 => array(0x3BE), 0x1D6B6 => array(0x3BF)
  1482.                     ,0x1D6B7 => array(0x3C0), 0x1D6B8 => array(0x3C1), 0x1D6B9 => array(0x3B8)
  1483.                     ,0x1D6BA => array(0x3C3), 0x1D6BB => array(0x3C4), 0x1D6BC => array(0x3C5)
  1484.                     ,0x1D6BD => array(0x3C6), 0x1D6BE => array(0x3C7), 0x1D6BF => array(0x3C8)
  1485.                     ,0x1D6C0 => array(0x3C9), 0x1D6D3 => array(0x3C3), 0x1D6E2 => array(0x3B1)
  1486.                     ,0x1D6E3 => array(0x3B2), 0x1D6E4 => array(0x3B3), 0x1D6E5 => array(0x3B4)
  1487.                     ,0x1D6E6 => array(0x3B5), 0x1D6E7 => array(0x3B6), 0x1D6E8 => array(0x3B7)
  1488.                     ,0x1D6E9 => array(0x3B8), 0x1D6EA => array(0x3B9), 0x1D6EB => array(0x3BA)
  1489.                     ,0x1D6EC => array(0x3BB), 0x1D6ED => array(0x3BC), 0x1D6EE => array(0x3BD)
  1490.                     ,0x1D6EF => array(0x3BE), 0x1D6F0 => array(0x3BF), 0x1D6F1 => array(0x3C0)
  1491.                     ,0x1D6F2 => array(0x3C1), 0x1D6F3 => array(0x3B8) ,0x1D6F4 => array(0x3C3)
  1492.                     ,0x1D6F5 => array(0x3C4), 0x1D6F6 => array(0x3C5), 0x1D6F7 => array(0x3C6)
  1493.                     ,0x1D6F8 => array(0x3C7), 0x1D6F9 => array(0x3C8) ,0x1D6FA => array(0x3C9)
  1494.                     ,0x1D70D => array(0x3C3), 0x1D71C => array(0x3B1), 0x1D71D => array(0x3B2)
  1495.                     ,0x1D71E => array(0x3B3), 0x1D71F => array(0x3B4), 0x1D720 => array(0x3B5)
  1496.                     ,0x1D721 => array(0x3B6), 0x1D722 => array(0x3B7), 0x1D723 => array(0x3B8)
  1497.                     ,0x1D724 => array(0x3B9), 0x1D725 => array(0x3BA), 0x1D726 => array(0x3BB)
  1498.                     ,0x1D727 => array(0x3BC), 0x1D728 => array(0x3BD), 0x1D729 => array(0x3BE)
  1499.                     ,0x1D72A => array(0x3BF), 0x1D72B => array(0x3C0), 0x1D72C => array(0x3C1)
  1500.                     ,0x1D72D => array(0x3B8), 0x1D72E => array(0x3C3), 0x1D72F => array(0x3C4)
  1501.                     ,0x1D730 => array(0x3C5), 0x1D731 => array(0x3C6), 0x1D732 => array(0x3C7)
  1502.                     ,0x1D733 => array(0x3C8), 0x1D734 => array(0x3C9), 0x1D747 => array(0x3C3)
  1503.                     ,0x1D756 => array(0x3B1), 0x1D757 => array(0x3B2), 0x1D758 => array(0x3B3)
  1504.                     ,0x1D759 => array(0x3B4), 0x1D75A => array(0x3B5), 0x1D75B => array(0x3B6)
  1505.                     ,0x1D75C => array(0x3B7), 0x1D75D => array(0x3B8), 0x1D75E => array(0x3B9)
  1506.                     ,0x1D75F => array(0x3BA), 0x1D760 => array(0x3BB), 0x1D761 => array(0x3BC)
  1507.                     ,0x1D762 => array(0x3BD), 0x1D763 => array(0x3BE), 0x1D764 => array(0x3BF)
  1508.                     ,0x1D765 => array(0x3C0), 0x1D766 => array(0x3C1), 0x1D767 => array(0x3B8)
  1509.                     ,0x1D768 => array(0x3C3), 0x1D769 => array(0x3C4), 0x1D76A => array(0x3C5)
  1510.                     ,0x1D76B => array(0x3C6), 0x1D76C => array(0x3C7), 0x1D76D => array(0x3C8)
  1511.                     ,0x1D76E => array(0x3C9), 0x1D781 => array(0x3C3), 0x1D790 => array(0x3B1)
  1512.                     ,0x1D791 => array(0x3B2), 0x1D792 => array(0x3B3), 0x1D793 => array(0x3B4)
  1513.                     ,0x1D794 => array(0x3B5), 0x1D795 => array(0x3B6), 0x1D796 => array(0x3B7)
  1514.                     ,0x1D797 => array(0x3B8), 0x1D798 => array(0x3B9), 0x1D799 => array(0x3BA)
  1515.                     ,0x1D79A => array(0x3BB), 0x1D79B => array(0x3BC), 0x1D79C => array(0x3BD)
  1516.                     ,0x1D79D => array(0x3BE), 0x1D79E => array(0x3BF), 0x1D79F => array(0x3C0)
  1517.                     ,0x1D7A0 => array(0x3C1), 0x1D7A1 => array(0x3B8), 0x1D7A2 => array(0x3C3)
  1518.                     ,0x1D7A3 => array(0x3C4), 0x1D7A4 => array(0x3C5), 0x1D7A5 => array(0x3C6)
  1519.                     ,0x1D7A6 => array(0x3C7), 0x1D7A7 => array(0x3C8), 0x1D7A8 => array(0x3C9)
  1520.                     ,0x1D7BB => array(0x3C3), 0x3F9   => array(0x3C3), 0x1D2C  => array(0x61)
  1521.                     ,0x1D2D  => array(0xE6), 0x1D2E  => array(0x62), 0x1D30  => array(0x64)
  1522.                     ,0x1D31  => array(0x65), 0x1D32  => array(0x1DD), 0x1D33  => array(0x67)
  1523.                     ,0x1D34  => array(0x68), 0x1D35  => array(0x69), 0x1D36  => array(0x6A)
  1524.                     ,0x1D37  => array(0x6B), 0x1D38  => array(0x6C), 0x1D39  => array(0x6D)
  1525.                     ,0x1D3A  => array(0x6E), 0x1D3C  => array(0x6F), 0x1D3D  => array(0x223)
  1526.                     ,0x1D3E  => array(0x70), 0x1D3F  => array(0x72), 0x1D40  => array(0x74)
  1527.                     ,0x1D41  => array(0x75), 0x1D42  => array(0x77), 0x213B  => array(0x66, 0x61, 0x78)
  1528.                     ,0x3250  => array(0x70, 0x74, 0x65), 0x32CC  => array(0x68, 0x67)
  1529.                     ,0x32CE  => array(0x65, 0x76), 0x32CF  => array(0x6C, 0x74, 0x64)
  1530.                     ,0x337A  => array(0x69, 0x75), 0x33DE  => array(0x76, 0x2215, 0x6D)
  1531.                     ,0x33DF  => array(0x61, 0x2215, 0x6D)
  1532.                     )
  1533.             ,'norm_combcls' => array(0x334   => 1,   0x335   => 1,   0x336   => 1,   0x337   => 1
  1534.                     ,0x338   => 1,   0x93C   => 7,   0x9BC   => 7,   0xA3C   => 7,   0xABC   => 7
  1535.                     ,0xB3C   => 7,   0xCBC   => 7,   0x1037  => 7,   0x3099  => 8,   0x309A  => 8
  1536.                     ,0x94D   => 9,   0x9CD   => 9,   0xA4D   => 9,   0xACD   => 9,   0xB4D   => 9
  1537.                     ,0xBCD   => 9,   0xC4D   => 9,   0xCCD   => 9,   0xD4D   => 9,   0xDCA   => 9
  1538.                     ,0xE3A   => 9,   0xF84   => 9,   0x1039  => 9,   0x1714  => 9,   0x1734  => 9
  1539.                     ,0x17D2  => 9,   0x5B0   => 10,  0x5B1   => 11,  0x5B2   => 12,  0x5B3   => 13
  1540.                     ,0x5B4   => 14,  0x5B5   => 15,  0x5B6   => 16,  0x5B7   => 17,  0x5B8   => 18
  1541.                     ,0x5B9   => 19,  0x5BB   => 20,  0x5Bc   => 21,  0x5BD   => 22,  0x5BF   => 23
  1542.                     ,0x5C1   => 24,  0x5C2   => 25,  0xFB1E  => 26,  0x64B   => 27,  0x64C   => 28
  1543.                     ,0x64D   => 29,  0x64E   => 30,  0x64F   => 31,  0x650   => 32,  0x651   => 33
  1544.                     ,0x652   => 34,  0x670   => 35,  0x711   => 36,  0xC55   => 84,  0xC56   => 91
  1545.                     ,0xE38   => 103, 0xE39   => 103, 0xE48   => 107, 0xE49   => 107, 0xE4A   => 107
  1546.                     ,0xE4B   => 107, 0xEB8   => 118, 0xEB9   => 118, 0xEC8   => 122, 0xEC9   => 122
  1547.                     ,0xECA   => 122, 0xECB   => 122, 0xF71   => 129, 0xF72   => 130, 0xF7A   => 130
  1548.                     ,0xF7B   => 130, 0xF7C   => 130, 0xF7D   => 130, 0xF80   => 130, 0xF74   => 132
  1549.                     ,0x321   => 202, 0x322   => 202, 0x327   => 202, 0x328   => 202, 0x31B   => 216
  1550.                     ,0xF39   => 216, 0x1D165 => 216, 0x1D166 => 216, 0x1D16E => 216, 0x1D16F => 216
  1551.                     ,0x1D170 => 216, 0x1D171 => 216, 0x1D172 => 216, 0x302A  => 218, 0x316   => 220
  1552.                     ,0x317   => 220, 0x318   => 220, 0x319   => 220, 0x31C   => 220, 0x31D   => 220
  1553.                     ,0x31E   => 220, 0x31F   => 220, 0x320   => 220, 0x323   => 220, 0x324   => 220
  1554.                     ,0x325   => 220, 0x326   => 220, 0x329   => 220, 0x32A   => 220, 0x32B   => 220
  1555.                     ,0x32C   => 220, 0x32D   => 220, 0x32E   => 220, 0x32F   => 220, 0x330   => 220
  1556.                     ,0x331   => 220, 0x332   => 220, 0x333   => 220, 0x339   => 220, 0x33A   => 220
  1557.                     ,0x33B   => 220, 0x33C   => 220, 0x347   => 220, 0x348   => 220, 0x349   => 220
  1558.                     ,0x34D   => 220, 0x34E   => 220, 0x353   => 220, 0x354   => 220, 0x355   => 220
  1559.                     ,0x356   => 220, 0x591   => 220, 0x596   => 220, 0x59B   => 220, 0x5A3   => 220
  1560.                     ,0x5A4   => 220, 0x5A5   => 220, 0x5A6   => 220, 0x5A7   => 220, 0x5AA   => 220
  1561.                     ,0x655   => 220, 0x656   => 220, 0x6E3   => 220, 0x6EA   => 220, 0x6ED   => 220
  1562.                     ,0x731   => 220, 0x734   => 220, 0x737   => 220, 0x738   => 220, 0x739   => 220
  1563.                     ,0x73B   => 220, 0x73C   => 220, 0x73E   => 220, 0x742   => 220, 0x744   => 220
  1564.                     ,0x746   => 220, 0x748   => 220, 0x952   => 220, 0xF18   => 220, 0xF19   => 220
  1565.                     ,0xF35   => 220, 0xF37   => 220, 0xFC6   => 220, 0x193B  => 220, 0x20E8  => 220
  1566.                     ,0x1D17B => 220, 0x1D17C => 220, 0x1D17D => 220, 0x1D17E => 220, 0x1D17F => 220
  1567.                     ,0x1D180 => 220, 0x1D181 => 220, 0x1D182 => 220, 0x1D18A => 220, 0x1D18B => 220
  1568.                     ,0x59A   => 222, 0x5AD   => 222, 0x1929  => 222, 0x302D  => 222, 0x302E  => 224
  1569.                     ,0x302F  => 224, 0x1D16D => 226, 0x5AE   => 228, 0x18A9  => 228, 0x302B  => 228
  1570.                     ,0x300   => 230, 0x301   => 230, 0x302   => 230, 0x303   => 230, 0x304   => 230
  1571.                     ,0x305   => 230, 0x306   => 230, 0x307   => 230, 0x308   => 230, 0x309   => 230
  1572.                     ,0x30A   => 230, 0x30B   => 230, 0x30C   => 230, 0x30D   => 230, 0x30E   => 230
  1573.                     ,0x30F   => 230, 0x310   => 230, 0x311   => 230, 0x312   => 230, 0x313   => 230
  1574.                     ,0x314   => 230, 0x33D   => 230, 0x33E   => 230, 0x33F   => 230, 0x340   => 230
  1575.                     ,0x341   => 230, 0x342   => 230, 0x343   => 230, 0x344   => 230, 0x346   => 230
  1576.                     ,0x34A   => 230, 0x34B   => 230, 0x34C   => 230, 0x350   => 230, 0x351   => 230
  1577.                     ,0x352   => 230, 0x357   => 230, 0x363   => 230, 0x364   => 230, 0x365   => 230
  1578.                     ,0x366   => 230, 0x367   => 230, 0x368   => 230, 0x369   => 230, 0x36A   => 230
  1579.                     ,0x36B   => 230, 0x36C   => 230, 0x36D   => 230, 0x36E   => 230, 0x36F   => 230
  1580.                     ,0x483   => 230, 0x484   => 230, 0x485   => 230, 0x486   => 230, 0x592   => 230
  1581.                     ,0x593   => 230, 0x594   => 230, 0x595   => 230, 0x597   => 230, 0x598   => 230
  1582.                     ,0x599   => 230, 0x59C   => 230, 0x59D   => 230, 0x59E   => 230, 0x59F   => 230
  1583.                     ,0x5A0   => 230, 0x5A1   => 230, 0x5A8   => 230, 0x5A9   => 230, 0x5AB   => 230
  1584.                     ,0x5AC   => 230, 0x5AF   => 230, 0x5C4   => 230, 0x610   => 230, 0x611   => 230
  1585.                     ,0x612   => 230, 0x613   => 230, 0x614   => 230, 0x615   => 230, 0x653   => 230
  1586.                     ,0x654   => 230, 0x657   => 230, 0x658   => 230, 0x6D6   => 230, 0x6D7   => 230
  1587.                     ,0x6D8   => 230, 0x6D9   => 230, 0x6DA   => 230, 0x6DB   => 230, 0x6DC   => 230
  1588.                     ,0x6DF   => 230, 0x6E0   => 230, 0x6E1   => 230, 0x6E2   => 230, 0x6E4   => 230
  1589.                     ,0x6E7   => 230, 0x6E8   => 230, 0x6EB   => 230, 0x6EC   => 230, 0x730   => 230
  1590.                     ,0x732   => 230, 0x733   => 230, 0x735   => 230, 0x736   => 230, 0x73A   => 230
  1591.                     ,0x73D   => 230, 0x73F   => 230, 0x740   => 230, 0x741   => 230, 0x743   => 230
  1592.                     ,0x745   => 230, 0x747   => 230, 0x749   => 230, 0x74A   => 230, 0x951   => 230
  1593.                     ,0x953   => 230, 0x954   => 230, 0xF82   => 230, 0xF83   => 230, 0xF86   => 230
  1594.                     ,0xF87   => 230, 0x170D  => 230, 0x193A  => 230, 0x20D0  => 230, 0x20D1  => 230
  1595.                     ,0x20D4  => 230, 0x20D5  => 230, 0x20D6  => 230, 0x20D7  => 230, 0x20DB  => 230
  1596.                     ,0x20DC  => 230, 0x20E1  => 230, 0x20E7  => 230, 0x20E9  => 230, 0xFE20  => 230
  1597.                     ,0xFE21  => 230, 0xFE22  => 230, 0xFE23  => 230, 0x1D185 => 230, 0x1D186 => 230
  1598.                     ,0x1D187 => 230, 0x1D189 => 230, 0x1D188 => 230, 0x1D1AA => 230, 0x1D1AB => 230
  1599.                     ,0x1D1AC => 230, 0x1D1AD => 230, 0x315   => 232, 0x31A   => 232, 0x302C  => 232
  1600.                     ,0x35F   => 233, 0x362   => 233, 0x35D   => 234, 0x35E   => 234, 0x360   => 234
  1601.                     ,0x361   => 234, 0x345   => 240
  1602.                     )
  1603.             );
  1604. }
  1605. ?>

Documentation generated on Tue, 19 Nov 2013 15:05:10 +0100 by phpDocumentor 1.4.3