//file:noinspection unused
package com.intellisrc.crypt.encode

import com.intellisrc.core.Log
import com.intellisrc.core.SysInfo
import groovy.transform.CompileStatic

import java.lang.reflect.Modifier
import java.nio.CharBuffer
import java.nio.charset.StandardCharsets
import java.util.regex.Pattern

/*
 * @author: A.Lepe
 * @since: Sep 10,2010 (Originally created in PHP for Yayahuic Framework)
 *
 * This class provides 2-way string encoding as a way of obfuscation.
 * While it doesn't really provide security, it could be used to
 * create confusion or to reduce the storage size of a string (see notes).
 * Or... you can use it just for fun! :)
 *
 * Features:
 * - Use of uncommon methods to encode/decode strings
 * - a salt key can be used to change output
 * - 2 Planes of UTF-8 can be used (128k+ chars) (see notes).
 * - Depending on the settings, the encoded string may
 *   result smaller than the length of the original string.
 * - Many possible combinations (input, output).
 * - Translation from one charset to another.
 * - Get a numeric representation of a string
 *
 * NOTES:
 *  1. If you encode, for example, from HASH (16 chars) to ALPHA (52 chars) the resulting
 *     string length will be smaller than the original string. The opposite is also true:
 *     If you encode an alphanumeric string (ALPHA) to NUMBERS (10 chars), the resulting
 *     string length will be longer than the original string.
 *  2. If you store data and you use any of the characters inside the SMP (Plane 2), which
 *     are composed of 4 bytes, you may need prepare your code to handle such strings. For
 *     example:
 *     "æ—¥æœ¬èª�".toCharArray().length == 3  // Any character inside the BMP (Basic Multilingual Plane) can be stored inside a `char`
 *     "ğŸ•™ğŸ«›ğŸ�¸ğŸ›¡".toCharArray().length == 8 // Instead of iterating over those characters you will need to use getCodePoints() method.
 *
 * In order to decode/decode a string 2 settings are required:
 *
 * 1) INPUT: Is the expected format of the string to encode (Default: BASIC).
 *
 * Closest the charset to the input, the smaller is the resulted encoded string.
 * For example, if only numbers are to being encoded, use NUM.
 * If the string to be encoded contains one or more characters not presented
 *      in the selected charset, the result will be garbage.
 * If the input string is a hash (MD5, SHA*, etc), use "HASH".
 * If a string is the result of an encoding method such as base64, unpack('H*',...) ]
 *      it is recommended to use "BASE64".
 * Crypt hashes (created by an standard Unix DES-based algorithm) may contain any ascii
 *      character when using salt strings, as those are stored within the hash itself.
 *      For that reason, use BASIC or LATIN as input.
 * Even for the same string, different "INPUT" methods may result in different
 * encoded strings.
 *
 * 2) OUTPUT: Is the expected format AFTER being encoded (Default: ANUM).
 *
 * Wider the charset used, the smaller is the resulted encoded string.
 * Using the full UTF8 range (65k+) results in the highest entropy, but
 *      it may present some problems handling the resulted string.
 * Some visually interesting outputs are BRAILLE and LINES.
 * After UTF8, KANJI or KOR provides the wider ranges, giving a higher entropy.
 * INVISIBLE may provide an extra difficulty to read as are not visual characters.
 * ALPHA,ANUM,HASH,LCASE,UCASE,NUM are safe to store (as in a DB) without worrying about
 * escaping chars or having problems with language encoding.
 *
 * 3) KEY: used to randomize output. It is optional.
 *
 * NOTE: There is no font that will display all characters in this list.
 *       Some fonts of the most complete are:
 *
 * Recommended fonts:
 *  - Noto - Google (77,000 characters)
 *  - Unifont (65,000 characters)
 *  - Dejavu (6,000 characters)
 *
 * Fonts marked with [**] may require specific font to display
 *
 * https://www.ssec.wisc.edu/~tomw/java/unicode.html
 * https://en.wikipedia.org/wiki/Unicode_block
 * http://www.unicode.org/charts/
 */

@CompileStatic
class LpCode {
    //NOTE: The smaller the chunkSize, the larger the output, higher the CPU usage and lower the Memory usage.
    int chunkSize = 100      //For large size texts, it is better to use chunks (for very large texts, 1024 might be better)
    int glueChar = 0x1E      //Which character to use to glue a chunk (it can be part of the OUTPUT charset)
    static boolean warn = false  //if true, will warn when input includes characters not included in INPUT charset
    int blockSize = 16      // When using blocks
    String blockPadding = ""    // Character used to pad block
    /* ************ PARTS ***************** */
    //Binary-like (2 chars: 0,1) : 10111010111011111010100111000011111101000101000100
    static public final List<Integer> BIT = 0x30..0x31
    //Space character (used only to complement any other)
    static public final List<Integer> SPACE = [0x20]
    //New line characters. Use it when your text might contain new line characters (return character and line feed)
    static public final List<Integer> NEWLINES = [0x0A,0x0D]
    // = and + symbols (2 chars) : Used to complement others : +===+=+=++=++=+=+=++=
    static public final List<Integer> EQUALPLUS = [0x3D, 0x2B]
    // a to f (6 chars) : ebacedaebfccedafcfaeeeefbacaef
    static public final List<Integer> aTof = 0x61..0x66
    // A to F (6 chars) : CCEEFEBEFEFCCAACFCFEBACEDAEBFCCEDA
    static public final List<Integer> AtoF = 0x41..0x46
    //0-9 (10 digits) : 058507141981398903957820054
    static public final List<Integer> NUMBERS = 0x30..0x39
    //a-z (26 chars) : iofwbwhqvtjdtglpsuxvpjomkrinrzkfgb
    static public final List<Integer> LOWERCASE = 0x61..0x7A
    //A-Z (26 chars) : YRXAFMKZCIOFWBWHQVTJDTGLPSU
    static public final List<Integer> UPPERCASE = 0x41..0x5A

    /* ************ BLOCKS **************** */
    //Any English ascii char (96 chars) : r~<s>3,o2F$%]<|5tu^9bmfN>R^
    static public final List<Integer> BASIC = 0x20..0x7F
    //Extended Ascii (without BASIC) (719 chars) : Ã‚Å…ÊšÆµÈ²É­ÊµË¿É È Æ¸Ì¹Å”Ì´Ç…Æ›Ê¸È•È´Â³É­Å Ì©Í§
    static public final List<Integer> EXTENDED = 0xA1..0x036F
    // Latin (inc. COMBINING) ( 91 chars) : áµ�ê�¾â±¯á»¡ê¬¶á¹­â±¨á¹¥á·ƒá»«á¸­áº­á·½ê�šá¶”á´‡áº®ê�‘á¹Šá·ƒâ±°ê¬¹ê��á»¿
    static public final List<Integer> LATIN = (0x1D00..0x1D65) + (0x1D6B..0x1EFF) + (0x1AB0..0x1AC0) + (0x2C60..0x2C7F) -
        [0x1DFA, 0xA7C0, 0xA7C1] + (0xA722..0xA7CA) + (0xA7F2..0xA7FF) + (0xAB30..0xAB64)
    // Greek (344 chars) : Í¼á¾§á½ƒÎ¼Î á½›Î•á¿·á¼›á¼¸á½±á¿¾á¿ªÎ—Ï€á¼§á¿�á¼«á¼˜á¼¶á¾¾
    static public final List<Integer> GREEK = (0x0370..0x03E1) + (0x1D66..0x1D6A) + (0x1F00..0x1FFE) -
        [0x0378, 0x0379, 0x0380, 0x0381, 0x0382, 0x0383, 0x038B, 0x038D, 0x03A2, 0x1F16, 0x1F17,
         0x1F1E, 0x1F1F, 0x1F46, 0x1F47, 0x1F4E, 0x1F4F, 0x1F58, 0x1F5A, 0x1F5C, 0x1F5E, 0x1F7E,
         0x1F7F, 0x1FB5, 0x1FC5, 0x1FD4, 0x1FD5, 0x1FDC, 0x1FF0, 0x1FF1, 0x1FF5] + [0xAB65]
    // Cyrillic (265 chars) : ê™Ÿê™­Ğ¯ê™�êšŒÑ˜êš—ÑŒÑ­ê™¯â·¼Ñ‡ĞƒÑ‡â·»Ğ¤êšŸĞ³Ğ®
    static public final List<Integer> CYRILLIC = (0x0400..0x047F) + (0x1C80..0x1C88) + (0x2DE0..0x2DFF) + (0xA640..0xA69F)
    // Armenian (93 chars) : ÖˆÕ³Õ¯Õ¾Õ¸Õ�Õ�Õ�ÕŸÕ¿Ö€Õ‚Õ™Õ²Õ‰Ö„Õ‡Ö„Ô±Õ†ÕŸÕ�ÕºÕ‹
    static public final List<Integer> ARMENIAN = (0x0531..0x058A) - [0x0557, 0x0558] + (0xFB13..0xFB17)
    // Hebrew (133 chars) : ×²×œï¬¸Ö°×œï¬¡Ö¼×†Ö«ï¬Ÿï¬¨Ö±ï¬±×—ï­ŠÖ ï¬ºï¬�Ö¬Ö˜Ö²×˜ï­†Ö­ï¬°Öœ
    static public final List<Integer> HEBREW = (0x0591..0x05F4) - (0x05C8..0x05CF) - (0x05EB..0x05EF) + (0xFB1D..0xFB4F) -
        [0xFB37, 0xFB3D, 0xFB3F, 0xFB42, 0xFB45]
    // Arabic (1109 chars) : à£µïº«ï®½Û£Ø¬ïº¤Ù„ï»¼ï±‚ï·ºïµ�ï»�ï¹¿Û™ï²¤ï°¾ï±¿ïµ¸
    static public final List<Integer> ARABIC = (0x0600..0x06FF) + (0x08A0..0x08FF) - [0x061D, 0x08B5] - (0x08C8..0x08D2) +
        (0xFB50..0xFBC1) + (0xFBD3..0xFDC7) - [0xFD90, 0xFD91] + [0xFDCF] + (0xFDF0..0xFDFF) +
        (0xFE70..0xFEFC) - [0xFE76]
    // Syriac (108 chars) : Ü¸Ü‚İ‡Üˆİ‘Ü°İªÜ¬ÜšÜ¼İ‚İ¢Ü�Üˆİ¯Ü¶Ü¥Ü®Üˆİ£İ�Ü³ÜšÜ¤Ü®Ü·İ©Ü—İ…Ü¯İ�İšÜ�İ’
    static public final List<Integer> SYRIAC = (0x0700..0x076F) - [0x070E, 0x070F, 0x074B, 0x074C]

    // Thaana - Maldivas (50 chars) : Ş”ŞŸŞ¢Ş–Ş§Ş�Ş™Ş¯Ş�Ş¤ŞªŞ€ŞŸŞ€Ş…Ş°Ş’Ş©ŞŸŞ�Ş¬Ş”Ş›Ş•Ş­Ş§Ş§Ş®Ş£ŞšŞ…Ş•Ş«Ş«Ş£Ş£Ş‹Ş¤Ş•Ş¨ŞªŞ±Ş’Ş�Ş€
    static public final List<Integer> THAANA = 0x0780..0x07B1
    // NKO - West Africa (62 chars) : ß…ß•ß›ßŒß³ß¢ß­ß¥ß‡ß”ßŸß¾ß�ß‰ß£ß¨ß­ßƒß¹ßˆß“ß€ß™
    static public final List<Integer> NKO = (0x07C0..0x07FF) - [0x07FB, 0x07FC]
    // Samaritan - Aramaic (ancient Greek, Arabic and Hebrew) (62 chars) : à µà ˜à „à ¬à “à ­à °à »à …à •à ›à Œà µà ¢à ­à ¥à ‡à ”à Ÿà ¾à �à ‰à £à ¨à ­à ƒà »à ˆà “à €à ™à ¨à ¨à ³à ·à ˆà §à „à ”à „
    static public final List<Integer> SAMARITAN = (0x0800..0x083F) - [0x082E, 0x082F]
    // Mandaic - Southeastern Aramaic (Iraq, Iran) (29 chars) : Not available in some fonts
    static public final List<Integer> MANDAIC = (0x0840..0x085B) + [0x085E]
    // Devanagari - India (160 chars) : à¤©à¤‰à¤¼à¥�à¤ºà¥©à¤«à¤¬à¤…à¤ à¥¹ê£»à¥“à¤�à¤½ê£®à¤›à¥–à¤�à¥€à¤Œà¥¿à¤�à¤¡ê£ªà¥¿à¤�à¤€ê£©à¥©à¥œ
    static public final List<Integer> DEVANAGARI = (0x0900..0x097F) + (0xA8E0..0xA8FF)
    // Bengali - India (92 chars) : à¦¢à¦™à¦ à§„à§½à¦·à¦—à¦ à§¨à§£à¦ à§§à¦�à¦›à§‡à§·à¦Ÿà§¸à§�à¦˜à§±à§¸à¦£à¦“à¦¤à¦¾à¦“à§‡à§ªà§£à¦†
    static public final List<Integer> BENGALI = (0x0985..0x09FE) - [0x0984, 0x098D, 0x098E, 0x0991, 0x0992, 0x09A9, 0x09B1, 0x09B3,
                                                                    0x09B4, 0x09B5, 0x09BA, 0x09BB, 0x09C5, 0x09C6,
                                                                    0x09C9, 0x09CA, 0x09DE, 0x09E4, 0x09E5] -
        (0x09CF..0x09D6) - (0x09D8..0x09DB)
    // Gutmukhi - India (92 chars) : à¦¬à¦¢à¦™à¦ à§„à§½à¦·à¦—à¦ à§¨à§£à¦ à§§à¦�à¦›à§‡à§·à¦Ÿà§¸à§�à¦˜à§±à§¸
    static public final List<Integer> GUTMUKHI = (0x0985..0x09FE) - [0x0984, 0x098D, 0x098E, 0x0991, 0x0992, 0x09A9, 0x09B1,
                                                                     0x09B3, 0x09B4, 0x09B5, 0x09BA, 0x09BB, 0x09C5, 0x09C6,
                                                                     0x09C9, 0x09CA, 0x09DE, 0x09E4, 0x09E5] - (0x09CF..0x09D6) - (0x09D8..0x09DB)
    // Gujarati - India (91 chars) : à«�àª—à«¹à«ˆà«®àª�à«Œàª—à«‰àª¡à«­à«¡àª¬à« à«ªà«°àª¬àª¾à«£àª—àª�àª¾à«©àª¢à«¢à«€à«€à«§àª¤àª¿àª�
    static public final List<Integer> GUJARATI = (0x0A81..0x0AFF) - [0x0A84, 0x0A8E, 0x0A92, 0x0AA9, 0x0AB1, 0x0AB4, 0x0ABA, 0x0ABB,
                                                                     0x0AC6, 0x0ACA, 0x0ACE, 0x0ACF, 0x0AE4, 0x0AE5] -
        (0x0AD1..0x0ADF) - (0x0AF2..0x0AF8)
    // Oriya - India (91 chars) : à¬›à­�à¬™à­±à­�à­­à¬Ÿà­—à¬™à­•à¬£à­¬à­ à¬®à­Ÿà­©à­¯à¬®à­€à­¢à¬™à¬�
    static public final List<Integer> ORIYA = (0x0B01..0x0B77) - [0x0B04, 0x0B0D, 0x0B0E, 0x0B11, 0x0B12, 0x0B29, 0x0B31, 0x0B34,
                                                                  0x0B3A, 0x0B3B, 0x0B45, 0x0B46, 0x0B49, 0x0B4A, 0x0B5E, 0x0B64, 0x0B65] -
        (0x0B4E..0x0B54) - (0x0B58..0x0B5B)
    // Tamil - India (76 chars) : à¯¶à¯ˆà¯µà¯�à®™à¯‹à¯�à¯®à®�à¯�à¯§à®�à¯°à®³à®Ÿ
    static public final List<Integer> TAMIL = (0x0B82..0x0BFA) - [0x0B84, 0x0B91, 0x0B9B, 0x0B9D, 0x0BC9, 0x0BCE, 0x0BCF] -
        (0x0B8B..0x0B8D) - (0x0B96..0x0B98) - (0x0BA0..0x0BA2) -
        (0x0BA5..0x0BA7) - (0x0BAB..0x0BAD) - (0x0BC3..0x0BC5) -
        (0x0BD1..0x0BD6) - (0x0BD8..0x0BE5)
    // Telegu - India (99 chars) : à°¤à°�à±¹à°¡à±­à±·à°†à±‡à±¾à±ºà°§à°–à±¦à±½à±„à±¨à±·à±Šà±¨à°™à±‡à±„à±«à±ºà±‹à°‹à±ºà±‡à°°à°¸à±¸à°‚à°¦
    static public final List<Integer> TELEGU = (0x0C00..0x0C7F) - [0x0C0D, 0x0C11, 0x0C29, 0x0C3A, 0x0C3B, 0x0C3C, 0x0C45, 0x0C49,
                                                                   0x0C57, 0x0C64, 0x0C65, 0x0C70] -
        (0x0C4E..0x0C54) - (0x0C5B..0x0C5F) - (0x0C72..0x0C76)
    // Kannada - India (96 chars) : à²µà³–à³«à³€à²”à³�à²¥à²³à²’à³¢à³±à²�à³£à² à²•à²Œà³�à²”à²¨à²„à²…à³ƒà²�à³®à²—à³¦à³§à³„à²›à³Šà³•à³�à²±à² à²¶
    static public final List<Integer> KANNADA = (0x0C80..0x0CF2) - [0x0C8D, 0x0C91, 0x0CA9, 0x0CB4, 0x0CBA, 0x0CBB, 0x0CC5, 0x0CC9,
                                                                    0x0CDF, 0x0CE4, 0x0CE5, 0x0CF0] - (0x0CD7..0x0CDD)
    // Malayam (118 chars) : àµ™àµ²à´¥à´ªàµ¯à´‚à´¢à´ƒà´‰àµ§à´Œà´¦àµ¬àµ�à´´àµ�à´«àµ à´†à´¾àµ±àµ®àµ�à´¡àµ‡àµ­àµ§à´�à´˜à´«à´¡àµ�
    static public final List<Integer> MALAYAM = (0x0D00..0x0D7F) - [0x0D0D, 0x0D11, 0x0D45, 0x0D49, 0x0D64, 0x0D65] - (0x0D50..0x0D53)
    // Sinhala (94 chars) : à¶±à·˜à¶­à·†à¶¦à¶ºà¶±à·Šà·²à¶¹à·›à¶…à¶•à¶®à¶�à·«à·¬à¶£à¶¤à¶µà¶ªà·©à¶µà·Ÿà·¯
    static public final List<Integer> SINHALA = (0x0D81..0x0DF4) - [0x0D84, 0x0DB2, 0x0DBC, 0x0DBE, 0x0DBF, 0x0DD5, 0x0DD7, 0x0DF0, 0x0DF1] -
        (0x0D97..0x0D99) - (0x0DCB..0x0DCE) - (0x0DE0..0x0DE5)
    // Thai (87 chars) : à¸�à¸�à¸¶à¹“à¸¿à¹‘à¹‹à¸™à¸¯à¸˜à¸³à¸“à¹€à¸�à¸�à¸�à¸–à¹šà¹—à¸’à¸‰à¹Œà¸Šà¸©
    static public final List<Integer> THAI = (0x0E01..0x0E5B) - (0x0E3B..0x0E3E)
    // Tai Viet (72 chars) : êªˆêª�êª—êª¤êªŠêªºêª¹êª“êª�êªªêªºêª§êªºêª¢êªµêª©êªœêª¥êª§êªºê«›êª¹êª§ê«œêª“êª¬ê«€
    static public final List<Integer> TAI_VIET = (0xAA80..0xAAC2) + (0xAADB..0xAADF)
    // Lao (79 chars) : àº”àº”à»‘à»œàºšàººàº¥àº¶àºˆàº�à»ˆàº¯à»�àº¼àº‰àº†àºµà»Ÿàºœàº³
    static public final List<Integer> LAO = (0x0E81..0x0EDF) - [0x0E83, 0x0E85, 0x0E8B, 0x0EA4, 0x0EA6, 0x0EA8, 0x0EA9, 0x0EAC, 0x0EBE, 0x0EBF,
                                                                0x0EC5, 0x0EC6, 0x0ECE, 0x0ECF, 0x0EDA, 0x0EDB]

    // Tibetan (213 chars) : à¼­à¾¯à¼…à¿ˆà¿‡à½¸à½©à¾±à¼ƒà½¿à½…à¾£à¾‡à¼‘à½¸à½’
    static public final List<Integer> TIBETAN = (0x0F00..0x0FDA) - (0x0F6D..0x0F70) - [0x0F98, 0x0FBD]
    // Myanmar (223 chars) : á‚œê§«á�½ê©¦ê§­á�…á�‰á€’á‚Šê©ªê©³á�¶ê§»á�°á�Šá�¢á‚ˆê§·á‚’á‚‰á�‡
    static public final List<Integer> MYANMAR = (0x1000..0x109F) + (0xA9E0..0xA9FE) + (0xAA60..0xAA7F)
    // Georgian (174 chars) : á²´á²“áƒ—áƒ•â´�áƒ¢á‚©á² á‚¤á²˜áƒ»áƒœá²¹â´’á‚©áƒ’á²ºâ´�â´’á²¡á‚ºá²«á²ªáƒ±
    static public final List<Integer> GEORGIAN = (0x10A0..0x10FF) + (0x1C90..0x1CBF) - [0x10C6, 0x10CE, 0x10CF, 0x1CBB, 0x1CBC] -
        (0x10C8..0x10CC) + (0x2D00..0x2D25) + [0x2D27, 0x2D2D]
    // Ethiopic (496 chars) : á‰”á�‹á‰˜á‹¹â·‰áˆ©áŒ»â¶�áŒ¡á‹ áŠ áŒ�á�°á‰�á�µ
    static public final List<Integer> ETHIOPIC = (0x1200..0x1399) - [0x1249, 0x124E, 0x124F, 0x1257, 0x1259, 0x125E, 0x125F,
                                                                     0x1289, 0x128E, 0x128F, 0x12B1, 0x12B6, 0x12B7, 0x12BF,
                                                                     0x12C1, 0x12C6, 0x12C7, 0x12D7, 0x1311, 0x1316, 0x1317,
                                                                     0x135B, 0x135C] - (0x137D..0x137F) +
        (0x2D80..0x2D96) + (0x2DA0..0x2DDE) - [0x2DA7, 0x2DAF, 0x2DB7, 0x2DBF,
                                               0x2DC7, 0x2DCF, 0x2DD7] +
        (0xAB01..0xAB16) - [0xAB07, 0xAB08, 0xAB0F, 0xAB10, 0xAB27] + (0xAB20..0xAB2E)
    // Cherokee (172 chars) : á�ƒê®¼á��ê®¡ê­½á�Šê®…ê®‚ê®®á�‚ê®�á�»á�¹ê®€ê­½ê®”ê®•á�˜ê®“á�ƒê®›á�¡ê®¾á�¦ê®‡
    static public final List<Integer> CHEROKEE = (0x13A0..0x13FD) - [0x13F6, 0x13F7] + (0xAB70..0xABBF)
    // Unified Canadian Aborigine Syllabics (710 chars) : á–ºá“½á”´á•ªá˜�á‘Ÿá–¹á–·á“§á�¼á‘¸á–­á–�á¢µá�Ÿá£‚á‘¶á�¾á™†á”²á”£á¢µá—§á˜«á��
    static public final List<Integer> UCAS = (0x1400..0x167F) + (0x18B0..0x18F5)
    // OGHAM (29 chars) : áš™áš“áš‹áš’áš˜ášœáš—áš—áš“áš”áš”áš�áš›áš‹áš•áš‘áš‚áš’
    static public final List<Integer> OGHAM = (0x1680..0x169C)
    // Runic (89 chars) : ášµá›�á›¶á›¯á›±áš§áš´á›¦áš¹á›‚á›�á››á›«á›¯áš®áš¼áš¤áš¶á›…á›ªá›ˆáš¹áš®á›˜áš¡áš°áš á›šá›„á›˜áš á›”á›©
    static public final List<Integer> RUNIC = (0x16A0..0x16F8)
    // Tagalog - Philippines (22 chars) [**] : áœ€áœ‹áœˆáœ‹áœ…áœ�áœ�áœ�áœ�áœ�áœ”áœ¶áœ‹áœŒáœ‘áœµáœˆáœ„áœ“áœ‘áœ�áœ‹áœ¶áœ„áœ’áœ�áœ…áœ“áœ�áœ‰áœ‹
    static public final List<Integer> TAGALOG = (0x1700..0x1714) + [0x1735, 0x1736] - [0x170D]
    // (23 chars) : áœ¦áœ¬áœªáœ¨áœ¦áœ¤áœ áœ­áœ¦áœ áœ§áœ®áœ¬áœ¦áœ¶áœ£áœ²áœ¥áœ³áœ¯áœ§áœ´
    static public final List<Integer> HANUNOO = (0x1720..0x1736)
    // (20 chars) : á�‘á�„á��á�Œá��á�…á�„á�ˆá�’á��á��á�Šá��á�‹á�“á��á�…á�†á�‡á�ˆ
    static public final List<Integer> BUHID = (0x1740..0x1753)
    // (18 chars) : [**] á�ªá�©á�­á�°á�£á�¦á�¥á�¦á�²á�©á�§á�²á� á�ªá�°á�°á�¯á�¢á�¥á�©á�¦á�¨á�¬á�¨á�°á�­á�¥á�§á� á�­á�¯á�ªá�²á�¤á� á�£á�¤á�¢á�¬á�­á�£á�£á�©á� á�®
    static public final List<Integer> TAGBANWA = (0x1760..0x1773) - [0x1773, 0x1771]
    // (144 chars) : á��á�‰á�½á§±á§¡á§§á�¤á§½áŸ²á�‘á�¨á�»á�¬áŸ¢á§¬á�…áŸ¤
    static public final List<Integer> KHMER = (0x1780..0x17F9) + (0x19E0..0x19FF) - [0x17B4, 0x17B5, 0x17DE, 0x17DF] - (0x17EA..0x17EF)
    // (153 chars) : á …á ®á¢‘á¡‰á¢ á »á¢‰á¢¦á¢™á¡�á¡¸á¡€á¢‹á ©á¡­á ˆá¡„á¢ªá ¢á ²á¡€á¡™á¢‰á¢—á¢€á ±á¡šá¢�á¢¦á¢’
    static public final List<Integer> MONGOLIAN = (0x1800..0x18AA) - (0x180B..0x180F) - (0x181A..0x181F) - (0x1879..0x187F)
    // SMP: + (0x11660..0x1166C)
    // (68 chars) : á¥‰á¥€á¤‹á¤‰á¤šá¤›á¤’á¤€á¤’á¤¨á¤›á¤‚á¤‚á¤›á¤°á¥€á¤‡á¤©á¤�á¤¸á¥�á¤´á¤ˆá¤‹á¤´á¤–á¥Š
    static public final List<Integer> LIMBU = (0x1900..0x194F) - [0x191F] - (0x192C..0x192F) - (0x193C..0x193F) - (0x1941..0x1943)
    // Taile / new Taile (118 chars) : á¥œá¦�á§ƒá¦¨á¦�á¦¶á¦†á¦¹á¥–á¦™á§ˆá§…á¦·á¥±á¦¡á§„á¦¾á¥¬á¥¦á¦†á¥±
    static public final List<Integer> TAILE = (0x1950..0x19DF) - [0x196E, 0x196F] - (0x1975..0x197F) -
        (0x19AC..0x19AF) - (0x19CA..0x19CF) - (0x19DB..0x19DD)
    // (30 chars) : á¨‹á¨‡á¨ƒá¨€á¨”á¨”á¨�á¨�á¨‚á¨�á¨�á¨”á¨�á¨ˆá¨†á¨Ÿá¨™á¨‡á¨�á¨˜
    static public final List<Integer> BUGINESE = (0x1A00..0x1A1F) - [0x1A1C, 0x1A1D]
    // Tai Tham (127 chars) : áª�á©‘á©�á©¥á©‡á©²áª‰á©²á¨¡á©§á©¥áª áª‡á©‘á¨¹á¨ºá©€á©–á©˜á©ˆá©£áªƒá©�á©•
    static public final List<Integer> TAI_THAM = (0x1A20..0x1AAD) - [0x1A5F, 0x1A7D, 0x1A7E] - (0x1A8A..0x1A8F) - (0x1A9A..0x1A9F)
    // (121 chars) : á­¥á¬™á¬�á­™á¬™á­–á¬ºá­›á¬‚á­·á¬¤á¬¡á­¹á¬¢á¬€
    static public final List<Integer> BALINESE = (0x1B00..0x1B7C) - (0x1B4C..0x1B4F)
    // (72 chars) : á®ºá®¹á®“á®�á®ªá®ºá®§á®ºá®¢á®µá®©á®œá®¥á®§á®ºá³ƒá®¹á®§á³„á®“á®¬á³€á®…á®™á®»á®…
    static public final List<Integer> SUNDANESE = (0x1B80..0x1BBF) + (0x1CC0..0x1CC7)
    // (56 chars) : á¯�á¯˜á¯¥á¯Ÿá¯‘á¯›á¯¤á¯�á¯§á¯�á¯�á¯—á¯ á¯¦á¯©á¯�á¯«á¯‰á¯«á¯�á¯‡á¯¢á¯«á¯¼á¯…
    static public final List<Integer> BATAK = (0x1BC0..0x1BFF) - (0x1BF4..0x1BFB)
    // (74 chars) : á°˜á°¿á°›á°¢á±„á°Ÿá°Œá°ˆá°ƒá°“á°¬á°¿á°�á±ƒá°�á±…á°¾á°‘á±ˆá°ªá°¿á°¶á°¾á°£á°›á°‹á±�á°¨á°¬
    static public final List<Integer> LEPCHA = (0x1C00..0x1C4F) - (0x1C38..0x1C3A) - (0x1C4A..0x1C4C)
    // OL CHIKI (48 chars) : á±™á±�á±¦á±¤á±«á±¹á±‘á±Ÿá± á±™á±¸á±’á±©á±›á± á±³á±¼á±–á±”á±¯á±¢á±²á±½á±¡á±¢á±œá±¦á±³á±¢á±¼á±˜á±´á±�
    static public final List<Integer> OL_CHIKI = (0x1C50..0x1C7F)
    // (42 chars) : á³µá³¤á³±á³²á³£á³�á³©á³²á³—á³—á³•á³šá³¥á³²á³­á³�á³”á³�á³©á³ á³�á³œá³©á³¬á³œá³¡á³«á³±á³�á³¢á³›á³³á³¹á³�á³©á³·á³¨á³±á³¶
    static public final List<Integer> VEDIC = (0x1CD0..0x1CF9)
    // (94 chars) : â°¡â°µâ°¬â±‚â±œâ°´â±�â°ƒâ°“â°©â°�â±—â±˜â°�â°Ÿâ°°â°¥â±•â°°â±‘â±›â°‹â°›â°«â°ºâ°§
    static public final List<Integer> GLAGOLITIC = (0x2C00..0x2C5E) - [0x2C2F]
    // (123 chars) : â²„â²™â²£â²•â²¼â³³â³‹â²„â²œâ³ºâ³­â²¨â²¨â²¶â³�â³�â²„â²¶â³‹â²€â³‰â³‘â²ƒâ³°â³”â³½â²»â²™
    static public final List<Integer> COPTIC = (0x2C80..0x2CF3) + (0x2CF9..0x2CFF) //SMP: + (0x102E0..0x102FB)
    // (59 chars) : âµ›âµ˜â´ºâµ¿âµ�â´¾âµ˜âµ âµ˜âµƒâµ¢âµ‘â´½âµ¿â´ºâ´»âµ‰â´·âµœâ´´âµ�âµ˜âµ�âµ˜âµœâµŸâ´°â´³âµ£âµ†â´·
    static public final List<Integer> TIFINAGH = (0x2D30..0x2D67) + [0x2D6F, 0x2D70, 0x2D7F]
    // (329 chars) : â¼šâ¼¨â¾©â¾�âº²â¿ˆâ»†âº»â¼­âº¬â¾�â»–â¼•âº„â¿€â¼¨
    static public final List<Integer> RADICALS = (0x2E80..0x2EF3) - [0x2E9A] + (0x2F00..0x2FD5)
    // (71 chars) : ã„¨ã†±ã†´ã„�ã„¢ã„¦ã†¹ã†¡ã„ˆã†°ã„¡ã†ºã„�ã†£ã„“ã„®
    static public final List<Integer> BOPOMOFO = (0x3105..0x312F) + (0x31A0..0x31BB)
    // Hangul (666 chars) : í�ºíŸ“á…¹ã‰†íŸ„ã‰¿ê¥µá†ˆá†‘ã‰­ãŠ�ãŠ¯ã‰·ãˆ„ã‰¾á‡©ãˆ›
    static public final List<Integer> HANGUL = (0x1100..0x11FF) + (0x3131..0x318E) - [0x3164, 0x321F] + (0x3200..0x3250) +
        (0x3260..0x32B0) + (0xA960..0xA97C) + (0xD7B0..0xD7C6) + (0xD7CB..0xD7FB) +
        (0xFFA1..0xFFDC) - [0xFFBF, 0xFFC0, 0xFFC0, 0xFFC8, 0xFFC9, 0xFFD8, 0xFFD9] //Half witdh
    // Chinese (inc. Japanese Kanji, 27,558 chars) : ç­¥è²´ç±™ã—§ç†’é®¼äˆ¥é§Šè™¹è’¤å†½ã¬¬
    static public final List<Integer> HANZU = (0x3400..0x4DB5) + (0x4E00..0x9FEF)
    // (879 chars) : ï¦‰ã�¹ï§¹ï¥‡ï¥­ï§¥ãŒ’ïª�ã�¤ã‹‚ã‹†ï¤Œã‹”
    static public final List<Integer> IDEOGRAPHIC = (0x3190..0x319F) + (0x31C0..0x31E3) + (0x32C0..0x33FF) + (0xA700..0xA721) +
        (0xE801..0xE805) + (0xF900..0xFACE) + (0xFAD2..0xFAD4) + [0xFAD8, 0xFAD9]
    // Full Width Numbers (10 chars) : ï¼–ï¼˜ï¼‘ï¼—ï¼“ï¼•ï¼•ï¼’ï¼�ï¼•ï¼˜ï¼•ï¼�ï¼—ï¼‘
    static public final List<Integer> FW_NUM = (0xFF10..0xFF19)
    // (26 chars) : ï½†ï½�ï½‹ï½šï½ƒï½‰ï½�ï½†ï½—ï½‚ï½—ï½ˆ
    static public final List<Integer> FW_LOW = (0xFF41..0xFF5A)
    // (26 chars) : ï¼²ï¼¸ï¼¡ï¼¦ï¼­ï¼«ï¼ºï¼£ï¼©ï¼¯ï¼¦ï¼·
    static public final List<Integer> FW_UP = (0xFF21..0xFF3A)
    // (103 chars) : ï¼–ï½�ï¼µï¼®ï¼‘ï¼©ï¼…ï½�ï¼¢ï½�ï¼�ï¿¥ï¼¬ï¼�ï¼·ï¼´
    static public final List<Integer> FULL_WIDTH = (0xFF01..0xFF60) + (0xFFE0..0xFFE6)
    // Korean (11,172 chars) : ê¹€ë„¾ë”“ë¬¡ìŒ·í”‘ì½�ì‰Ÿë€¶ì›�íˆ™ì“­ë†­ë� ì‚š
    static public final List<Integer> KOREAN = (0xAC00..0xD7A3)
    // Hiragana (102 chars) : ã‚�ã�Œã�©ã�¨ã‚„ã‚�ã�“ã�·ã‚Šã��ã�©ã�±ã�«ã‡¹
    static public final List<Integer> HIRAGANA = (0x31F0..0x31FF) + (0x3041..0x3096)
    // Katakana (84 chars) : ãƒšã‚¾ã‚¡ã‚¯ãƒ“ãƒ´ãƒ†ã‚´ã‚ªãƒ®ãƒ›ãƒ‡ã‚±ã‚°
    static public final List<Integer> KATAKANA = (0x30A1..0x30F4)
    // (63 chars) : ï¾Šï¾ƒï½¨ï¾”ï½¹ï¾›ï¾�ï¾�ï½£ï¾›ï½¿ï½¥ï¾†ï¾�ï¾ˆï¾Œï¾‡ï½§ï¾‹ï½½ï¾’ï¾�
    static public final List<Integer> HW_KATAKANA = (0xFF61..0xFF9F)
    // (1223 chars) : ê‡•ê�§ê‚¾êˆ³ê�¨ê†µê€˜êˆ†ê�¨ê€‡ê‘�ê�¡ê�¥ê€§ê†§ê�¬ê�’
    static public final List<Integer> YI_SYLLABLE = (0xA000..0xA4C6)
    // (48 chars) : ê“ºê“´ê“«ê“ªê“·ê“œê“™ê“�ê“¦ê“¤ê“«ê“¹ê“‘ê“Ÿê“ ê“™ê“¸ê“’ê“©ê“›ê“ 
    static public final List<Integer> LISU = (0xA4D0..0xA4FF)
    // (300 chars) : ê—”ê–¤ê”‚ê”®ê˜¤ê˜‹ê•¡ê—²ê• ê”˜ê•®ê”´ê–¾ê—˜ê”Œê”‘
    static public final List<Integer> VAI = (0xA500..0xA62B)
    // (88 chars) : êš¿ê››ê›„ê›·ê›§ê›‹ê›šê›«ê›¡ê›‡ê›ƒêš°ê›˜ê›¶ê›ˆê›¬êš§ê›°êšªê›±êš´
    static public final List<Integer> BAMUM = (0xA6A0..0xA6F7)
    // (45 chars) [**] : ê �ê •ê Šê “ê †ê ˆê ¦ê —ê �ê ¥ê ‹ê ¨ê �ê ‡ê ™ê §ê –ê ¡ê ¢ê Šê Ÿê ƒê ’ê ’ê ‘ê ˆê •ê ¡ê ˜ê —ê ¥ê ‰ê ”
    static public final List<Integer> SYLOTI = (0xA800..0xA82C)
    // (56 chars) : ê¡Ÿê¡‘ê¡›ê¡¤ê¡�ê¡§ê¡�ê¡�ê¡—ê¡ ê¡¦ê¡©ê¡�ê¡«ê¡‰ê¡«ê¡�ê¡‡ê¡¢ê¡«ê¡´ê¡…ê¡¥ê¡�ê¡”ê¡‹ê¡¢ê¡±
    static public final List<Integer> PHAGS_PA = (0xA840..0xA877)
    // (82 chars) : ê¢©ê¢¦ê¢—ê¢„ê¢¾ê¢°ê¢¿ê¢�ê¢�ê¢�ê¢‘ê¢·ê¢œê¢˜ê¢½ê¢¦ê¢´ê¢�ê¢ª
    static public final List<Integer> SAURASHTRA = (0xA880..0xA8C5) + (0xA8CE..0xA8D9)
    // (48 chars) : ê¤�ê¤�ê¤�ê¤¬ê¤ªê¤¤ê¤›ê¤šê¤§ê¤Œê¤‰ê¤€ê¤–ê¤”ê¤›ê¤©ê¤�ê¤�ê¤�ê¤‰ê¤¨ê¤‚ê¤™ê¤‹ê¤�ê¤£ê¤¬ê¤†ê¤„ê¤Ÿê¤’
    static public final List<Integer> KAYAH = (0xA900..0xA92F)
    // (37 chars) : ê¤µê¥‡ê¥ˆê¤¸ê¥‘ê¥„ê¤¿ê¥�ê¥�ê¤·ê¤¾ê¥…ê¥Šê¤¸ê¥’ê¤¼ê¥“ê¥Œê¤³ê¥�ê¤·ê¥�ê¤°ê¥€
    static public final List<Integer> REJANG = (0xA930..0xA953) + [0xA95F]
    // (91 chars) : ê¦˜ê§„ê§”ê¦•ê¦¾ê¦ˆê§…ê¦•ê§ƒê¦“ê§•ê¦¾ê§‘ê¦™
    static public final List<Integer> JAVA = (0xA980..0xA9DF) - [0xA9CE] - (0xA9DA..0xA9DD)
    // (83 chars) : ê¨†ê©�ê¨ƒê¨¥ê¨�ê¨‡ê©‰ê©“ê¨«ê¨™ê©™ê©�ê¨©ê©–ê¨­ê¨Œê¨²
    static public final List<Integer> CHAM = (0xAA00..0xAA36) + (0xAA40..0xAA5F) - [0xAA4E, 0xAA4F, 0xAA5A, 0xAA5B]
    // (79 chars) : ê¯€ê«¨ê¯œê«­ê¯¸ê¯‚ê««ê¯§ê«­ê¯¸ê¯£ê¯¤ê«¦ê¯�ê¯�ê«²ê¯¶ê¯–ê¯¨ê« ê¯¦ê¯…ê¯šê¯­ê«£ê««ê¯©ê¯†ê¯ƒê«¦
    static public final List<Integer> MEETEI = (0xAAE0..0xAAF6) + (0xABC0..0xABF9) - [0xABEE, 0xABEF]
    // Braille (255 chars) : â¡Ÿâ¡‚â£³â¢›â¢–â£—â ¿â£¿â¢�â¢µâ¢†â£´â ‚â¢Šâ¡™â¡œâ¡�â¢¾â£“â£™â£›â¡®â¢ºâ¡¨
    static public final List<Integer> BRAILLE = (0x2801..0x28FF)
    // Superscript (14 chars) : â�¸â�¾â�¸â�ºâ�¿â�¸â�¸â�¼â�·â�½â�¸â�·â�¾â�°â�¹â�ºâ�·
    static public final List<Integer> SUPERSCRIPT = [0x2070, 0x2071] + (0x2074..0x207F)
    // (28 chars) : â‚‹â‚•â‚‘â‚‚â‚’â‚‡â‚™â‚�â‚�â‚‚â‚…â‚�â‚˜â‚�
    static public final List<Integer> SUBSCRIPT = (0x2080..0x209C) - [0x208F]
    // (32 chars) : â‚¤â‚¹â‚¹â‚¤â‚¬â‚´â‚¬â‚´â‚¹â‚¼â‚½â‚³â‚»â‚¦â‚¼â‚¡â‚°â‚£â‚§
    static public final List<Integer> CURRENCY = (0x20A0..0x20BF)
    // (2552 chars) : âŠ°â®«âš’â—˜â‹“âª²â›±â�Šâœ�â…µâŸ„
    static public final List<Integer> SYMBOLS = (0x2010..0x2027) + [0x203E, 0x2043, 0x20DB, 0x20DC, 0x20E6, 0x20E8] + (0x2030..0x205E) +
        (0x20D0..0x20F0) + (0x2100..0x218B) + (0x2190..0x2426) + (0x2440..0x244A) +
        (0x25A1..0x2775) + (0x2794..0x27FF) + (0x2900..0x2BFF) - [0x2B74, 0x2B75, 0x2B96] +
        (0x2E00..0x2E52) + (0x2FF0..0x2FFB) + (0x3001..0x303F) + (0x3099..0x30A0) +
        (0xA830..0xA839) + (0xAB66..0xAB6B) + [0xE83A] + (0xFB00..0xFB08) + (0xFB10..0xFB12) +
        (0xFE10..0xFE19) + (0xFE20..0xFE6B) - [0xFE53, 0xFE67] + (0xFFE8..0xFFEF) +
        (0xFFF9..0xFFFD)
    // Circled numbers (71 chars) : ãŠ±ãŠ³â‘­ãŠºâ�ˆãŠ²ã‰—â�‡â‘¦â“¾â‘²ã‰—â‘¥â‘£â‘³â“·
    //                                                  0         1-20
    static public final List<Integer> CIRCLE_NUMS = [0x24EA] + (0x2460..0x2473) +
    //       21-35              36-50         1-10 (single line) 1-10 (double line)
        (0x3251..0x325F) + (0x32B1..0x32BF) + (0x2780..0x2789) + (0x24F5..0x24FE)
    // Negative circled numbers (31 chars) : â�ºâ�“â“±â�»â“¿â�‹â�·â�¾â“«â�»â“®â�’â��â“±â“´
    //                                                      0           1-10              11-20              1-10 colored
    static public final List<Integer> CIRCLE_NEG_NUMS =  [0x24FF] + (0x2776..0x277F) + (0x24EB..0x24F4) + (0x278A..0x2793)
    // Numbers with parenthesis (20 chars) : â‘´â‘¸â‘¾â‘´â’�â’‚â‘¶â’†â‘ºâ‘ºâ’„â‘µâ’ƒâ’€â‘½â‘½
    static public final List<Integer> PAREN_NUMS = (0x2474..0x2487) // 1-20
    // Lowercase letters with parenthesis (26 chars) : â’¯â’²â’©â’°â’®â’œâ’�â’´â’­â’³â’œâ’¡â’¨
    static public final List<Integer> PAREN_LOW = (0x249c..0x24B5)
    // Circled uppercase letters (26 chars) : â’¹â’¼â“�â’ºâ’¸â“€â“‚â’¾â’·â’½â“€â“…â“Œâ“Š
    static public final List<Integer> CIRCLE_UP = (0x24B6..0x24CF)
    // Circled lowercase letters (26 chars) : â“£â“¦â“�â“¤â“¢â“�â“’â“¨â“¡â“§â“�â“•â“œâ“šâ“©
    static public final List<Integer> CIRCLE_LOW = (0x24D0..0x24E9)
    // Box drawing (128 chars) : â”ƒâ•¾â”‚â•»â•œâ”³â”ªâ”´â”µâ•œâ”ºâ•´â”›â”�â•�â”¡â”¡â”�â”µâ•œâ”½â•˜â”²â”¶â”ˆâ”‰â”«â•—
    static public final List<Integer> BOX = (0x2500..0x257F)
    // Block drawing (33 chars) : â–‡â––â–‘â–—â–”â–…â–€â–˜â–�â–‹â–�â–‹â–”â–”â–™â–�â–‚â–„â–›â–�â–…â–”â–�â–�â–•â–�â–�â–”â–Œâ–„â–„â–�â–†â–›â–’â–’
    static public final List<Integer> BLOCK = (0x2580..0x25A0)
    // Hexagram (64 chars) : ä·€ä·�ä··ä·�ä·¸ä·œä·™ä·‰ä·µä·ªä·™ä·¹ä·ºä·¹ä·¦ä·‚ä·¼ä·„ä·ƒä·¡
    static public final List<Integer> HEXAGRAM = (0x4DC0..0x4DFF)
    // Non-displayable (use with caution) (2,048 chars)
    //static public final List<Integer> SURROGATES = (0xD800..0xDFFF) === DOESN'T ENCODE/DECODE CORRECTLY
    //Random characters which can or not display
    static public final List<Integer> PRIVATE = (0xE000..0xF8FF)
    //Any UTF8 char (65,536 chars) use with caution as many characters can not be rendered
    static public final List<Integer> UTF8 = 0x0..0xFFFF

    /* ************ COMBOS **************** */
    //0-9a-f //similar to md5, sh,a etc (but with variable length) (16 chars)
    // Sample: d86987e6f13634f4378325c8deabba
    static public final List<Integer> HASH = NUMBERS + aTof
    //0-9A-F //same as 'HASH' but uppercase (16 chars)
    // Sample: 56412AD4B5D66855E8779CE9F83AB8
    static public final List<Integer> HASH_UP = NUMBERS + AtoF
    //a-zA-Z (52 chars)
    // Sample: qzzndkvqmITTiQYYONLnOsY
    static public final List<Integer> ALPHA = LOWERCASE + UPPERCASE
    //0-9a-zA-Z (62 chars)
    // Sample: u3ngV1s3IpO4iJjkv5LRCpYjb7KV
    static public final List<Integer> ANUM = NUMBERS + LOWERCASE + UPPERCASE
    //0-9a-zA-Z=+/ (as result of Base64, etc) (64 chars)
    // Sample: +CrCsQN8peNtuta1w32V5gee=
    static public final List<Integer> BASE64 = ANUM + EQUALPLUS
    //Ascii Extended (support for accents and other common symbols) (815 chars)
    // Sample: Ê›Ã²Ã ÆƒÍ�Ä”Ê¥Ä»Ì Å†Ä¡Ä¥Ì«É•È´Ç�È«Ì¹Í€È¸GÅ‘Ê•Ë©Â«aÄ�ÃšÇ˜Ì�Ì³Ê Å”
    static public final List<Integer> ASCII = BASIC + EXTENDED
    // Alphanumeric in a circle (154 chars)
    // Sample: â’»â’»â“®â“”â“™ãŠ½â““â“¶ã‰Ÿâ’¸ãŠ·â“‹ãŠ¼â“‡ã‰›â��â“�
    static public final List<Integer> CIRCLES = CIRCLE_LOW + CIRCLE_UP + CIRCLE_NUMS + CIRCLE_NEG_NUMS
    // Japanese, Korean, Chinese (40861 chars)
    // Sample: ëˆ¹ã�”é¹¼ì…£æ€£ì­®ç¸‘ì“‚æ¸•ç·£ä¸šë™šæ¹ŠçŸŠæ�Ÿ
    static public final List<Integer> CJK = RADICALS + BOPOMOFO + HANGUL + IDEOGRAPHIC + HANZU + KOREAN + HIRAGANA + KATAKANA
    // Languages from India (705 chars)
    // Sample: à°�à­§à­Ÿê£¾à¥«à¯‚à¬Œà²œà±¬à§µà¤�àª¥à¤”àª¾à¯°à²¶
    static public final List<Integer> INDIAN = DEVANAGARI + BENGALI + GUTMUKHI + GUJARATI + ORIYA + TAMIL + TELEGU + KANNADA
    // South-East Asia (1673 chars)
    // Sample: á²”à­±à¸�áƒ�á²£à¸…à°Šà¶±â´�à´�à³‘à±™à¤µà¯ºà²¯
    static public final List<Integer> SE_ASIA = MALAYAM + SINHALA + THAI + LAO + MYANMAR + TAI_VIET + INDIAN + GEORGIAN + BALINESE
    // Visible characters : safe option instead of UTF8 (48392 chars)
    // Sample: è�¼ê§½ä…›à·‘æ¡»é«‚á‚…ç‚™â£¾å‚€ã­§ç�‰ä·„ì«¢ë¢°ä¶‚ã£¨
    static public final List<Integer> VISIBLE = ASCII + GREEK + CYRILLIC + ARMENIAN + HEBREW + ARABIC + SYRIAC + THAANA +
        NKO + SAMARITAN + MANDAIC + INDIAN + SE_ASIA + TIBETAN + CJK + BRAILLE + SYMBOLS + HEXAGRAM - SPACE

    /*
        SMP: Supplementary Multilingual Plane
        NOTE: Be aware that the following blocks are formed with more bytes and it might require special handling
     */
    // (80 chars) : ğ�…¬ğ�…¤ğ�†„ğ�…‡ğ�…‰ğ�…´ğ�†Œğ�†‡ğ�…�ğ�†„ğ�†‡ğ�…»ğ�…ƒğ�…—ğ�…”ğ�…¸ğ�…—ğ�…Šğ�…Ÿğ�…�ğ�…»ğ�…œğ�…§ğ�…¥ğ�…�ğ�†…ğ�†�ğ�…œğ�…£
    static public final List<Integer> GREEK_SMP = (0x10140..0x1018E) + (0x101A0)
    // (13 chars) : ğ�†šğ�†™ğ�†˜ğ�†œğ�†‘ğ�†’ğ�†›ğ�†›ğ�†‘ğ�†“ğ�†–ğ�†�ğ�†’ğ�†–ğ�†•ğ�†”ğ�†˜ğ�†œğ�†–ğ�†”ğ�†�ğ�†˜ğ�†šğ�†�ğ�†�ğ�†›ğ�†“
    static public final List<Integer> ROMAN = (0x10190..0x1019C)
    // (57 chars) : ğ�„�ğ�„–ğ�„±ğ�„ ğ�„¼ğ�„²ğ�„Šğ�„¯ğ�„Šğ�„�ğ�„‰ğ�„”ğ�„”ğ�„¢ğ�„•ğ�„œğ�„Ÿğ�„¤ğ�„€ğ�„¸ğ�„�ğ�„šğ�„–
    static public final List<Integer> AEGEAN = (0x10100..0x10102) + (0x10107..0x10133) + (0x10137..0x1013F)
    // (46 chars) : ğ�‡§ğ�‡™ğ�‡�ğ�‡©ğ�‡¬ğ�‡±ğ�‡¼ğ�‡—ğ�‡¯ğ�‡�ğ�‡˜ğ�‡�ğ�‡­ğ�‡•ğ�‡ ğ�‡”ğ�‡”ğ�‡®ğ�‡­ğ�‡¡ğ�‡�ğ�‡¥ğ�‡©ğ�‡ ğ�‡·ğ�‡§ğ�‡±ğ�‡ ğ�‡¬ğ�‡½ğ�‡”ğ�‡´ğ�‡³ğ�‡®ğ�‡¡ğ�‡š
    static public final List<Integer> PHAISTOS = (0x101D0..0x101FD)
    // (29 chars) : ğ�Š–ğ�Š–ğ�Š’ğ�Š•ğ�Š•ğ�ŠŒğ�Ššğ�ŠŠğ�Š”ğ�Š�ğ�Šƒğ�Š“ğ�Š†ğ�Š˜ğ�Š�ğ�Š�ğ�Šƒğ�Š„ğ�Š�ğ�Š™ğ�Š�ğ�Š…ğ�Šƒğ�Š•ğ�Šƒğ�ŠŠğ�Š�ğ�Š˜ğ�Š™
    static public final List<Integer> LYCIAN = (0x10280..0x1029C)
    // (49 chars) : ğ�Šªğ�Š§ğ�‹…ğ�Š¼ğ�‹…ğ�Š¸ğ�‹‹ğ�‹ƒğ�Š¿ğ�Š®ğ�Š´ğ�‹‚ğ�‹�ğ�Š¡ğ�‹�ğ�Š ğ�‹�ğ�Š«ğ�Š¢ğ�Š®ğ�Š¾
    static public final List<Integer> CARIAN = (0x102A0..0x102D0)
    // (36 chars) : ğ�Œ�ğ�Œ“ğ�Œƒğ�Œ†ğ�Œ„ğ�Œ˜ğ�Œ†ğ�Œ‘ğ�Œ‰ğ�Œ”ğ�Œ›ğ�Œ•ğ�Œ¢ğ�Œ…ğ�Œ�ğ�Œ„ğ�Œƒğ�Œ“ğ�Œˆğ�Œ‚ğ�Œ…ğ�Œ�ğ�Œ—ğ�Œ™ğ�Œ¡
    static public final List<Integer> OLD_ITALIC = (0x10300..0x10323)
    // (30 chars) : ğ�Œ³ğ�Œ½ğ��ƒğ�Œ²ğ��‡ğ��‡ğ�Œ½ğ�Œ²ğ�Œ¿ğ��…ğ��‰ğ�Œ¿ğ�Œ»ğ�Œ¼ğ�Œ¾ğ��ˆ
    static public final List<Integer> GOTHIC = (0x1032D..0x1034A)
    // (43 chars) [**] : ğ��¢ğ��°ğ���ğ��­ğ��²ğ��”ğ��¦ğ��°ğ��¯ğ��Ÿğ��«ğ��ºğ��Ÿğ�� ğ��šğ��°ğ�� ğ��ªğ��¨ğ��¨ğ���ğ��·ğ���ğ��˜ğ��¥ğ��•ğ��¢ğ��°ğ��¶ğ��›ğ��¡ğ��˜ğ��Ÿğ��š
    static public final List<Integer> OLD_PERMIC = (0x10350..0x1037A)
    // (31 chars) : ğ��™ğ��ˆğ��‘ğ��˜ğ��œğ��€ğ��”ğ���ğ��‹ğ��˜ğ��Œğ��‰ğ��‚ğ��‘ğ��’ğ��Ÿğ��›ğ��ƒğ���ğ���ğ��›ğ��šğ��‘ğ���ğ��›ğ��…ğ��‹ğ��‹ğ���ğ��‹ğ��–ğ���ğ��‡ğ��šğ��ˆğ��™ğ��”
    static public final List<Integer> UGARTIC = (0x10380..0x1039D) + [0x1039F]
    // (51 chars) : ğ��“ğ��«ğ���ğ��•ğ���ğ��¢ğ��¹ğ��·ğ��®ğ��ªğ��¿ğ��‘ğ��¼ğ��¼ğ��¹ğ��¹ğ��’ğ���ğ��”ğ��³
    static public final List<Integer> OLD_PERSIAN = (0x1039F..0x103D5) - (0x103C4..0x103C7)
    // (80 chars) : ğ��„ğ��—ğ��™ğ�‘„ğ��Œğ��‡ğ��Ÿğ��„ğ��‡ğ�‘‹ğ��“ğ��§ğ��¤ğ�‘ˆğ��§ğ��šğ��¯ğ���ğ�‘‹ğ��¬ğ��·ğ��µğ��­ğ��…ğ���ğ��¬ğ��³ğ��‚
    static public final List<Integer> DESERET = (0x10400..0x1044F)
    // (48 chars) : ğ�‘»ğ�‘µğ�‘ªğ�‘«ğ�‘¶ğ�‘�ğ�‘˜ğ�‘‘ğ�‘§ğ�‘¥ğ�‘ªğ�‘¸ğ�‘�ğ�‘�ğ�‘¡ğ�‘˜ğ�‘¹ğ�‘“ğ�‘¨ğ�‘šğ�‘¡ğ�‘²ğ�‘½ğ�‘—ğ�‘•ğ�‘®
    static public final List<Integer> SHAVIAN = (0x10450..0x1047F)
    // (40 chars) : ğ�’Šğ�’†ğ�’©ğ�’‹ğ�’¥ğ�’‚ğ�’Šğ�’˜ğ�’•ğ�’•ğ�’–ğ�’ ğ�’�ğ�’£ğ�’…ğ�’™ğ�’™ğ�’„ğ�’‹ğ�’˜ğ�’•ğ�’—ğ�’�ğ�’‘ğ�’�ğ�’‹ğ�’�ğ�’šğ�’¨
    static public final List<Integer> OSMANYA = (0x10480..0x104A9) - [0x1049E,0x1049F]
    // (72 chars) : ğ�’»ğ�“¯ğ�“¬ğ�“‚ğ�’¿ğ�“Ÿğ�“¯ğ�“šğ�“¯ğ�““ğ�“¨ğ�“œğ�“�ğ�“˜ğ�“šğ�“¯ğ�“¶ğ�“¬ğ�“šğ�“¹ğ�“‚ğ�“¡ğ�“µğ�’´
    static public final List<Integer> OSAGE = (0x104B0..0x104D3) + (0x104D8..0x104FB)
    // (40 chars) [**] : ğ�”†ğ�”§ğ�”‹ğ�”£ğ�”‚ğ�”Šğ�”˜ğ�”•ğ�”•ğ�”–ğ�”�ğ�”�ğ�”¡ğ�”…ğ�”™ğ�”™ğ�”„ğ�”‹ğ�”˜ğ�”•ğ�”—ğ�”�ğ�”‘ğ�”�ğ�”‹ğ�”�ğ�”šğ�”¦ğ�”‰ğ�”¦ğ�”�ğ�”Ÿğ�”•ğ�”šğ�”œğ�”˜
    static public final List<Integer> ELBASAN = (0x10500..0x10527)
    // Caucasian Albanian (53 chars) : ğ�•šğ�”°ğ�”·ğ�”¾ğ�”¶ğ�•¢ğ�•¡ğ�•�ğ�”¼ğ�•„ğ�•�ğ�•ˆğ�•’ğ�•–ğ�•�ğ�•�ğ�• ğ�”ºğ�•‡ğ�•‘ğ�•€ğ�•…ğ�•˜ğ�•“ğ�”¶ğ�”¿ğ�•�ğ�•¯ğ�•œğ�•�ğ�•�ğ�•Ÿğ�”»ğ�•˜ğ�”¸ğ�•¡
    static public final List<Integer> ALBANIAN = (0x10530..0x10563) + [0x1056F]
    // (55 chars) : ğ� ¯ğ� ƒğ� ®ğ� ƒğ� ®ğ� •ğ� „ğ� �ğ� ‘ğ� ¥ğ� ¿ğ� �ğ� ˜ğ� –ğ� ‚ğ� ©ğ� ¯ğ� ±ğ� �ğ� Ÿğ� ¨ğ� ‘ğ� °ğ� Ÿğ� ¤ğ� ¿ğ� Ÿ
    static public final List<Integer> CYPRIOT = (0x10800..0x10838) - [0x10806,0x10807,0x10809,0x10836] + [0x1083C, 0x1083F]
    // Imperial Aramaic (31 chars) : ğ�¡”ğ�¡œğ�¡‹ğ�¡›ğ�¡Œğ�¡‰ğ�¡‚ğ�¡‘ğ�¡’ğ�¡�ğ�¡šğ�¡ƒğ�¡œğ�¡�ğ�¡šğ�¡�ğ�¡‘ğ�¡�ğ�¡šğ�¡…ğ�¡‹ğ�¡‹ğ�¡�ğ�¡‹ğ�¡™ğ�¡�ğ�¡‡ğ�¡�ğ�¡ˆğ�¡˜ğ�¡”
    static public final List<Integer> ARAMAIC = (0x10840..0x1085F) - [0x10856]
    // (32 chars) [**] : ğ�¡¸ğ�¡¥ğ�¡­ğ�¡µğ�¡­ğ�¡µğ�¡¸ğ�¡½ğ�¡¼ğ�¡²ğ�¡ºğ�¡§ğ�¡½ğ�¡ ğ�¡±ğ�¡¢ğ�¡¦ğ�¡¯ğ�¡­ğ�¡µğ�¡¸ğ�¡¿ğ�¡«ğ�¡¥ğ�¡³ğ�¡­ğ�¡¶ğ�¡°ğ�¡¥ğ�¡¥ğ�¡°ğ�¡¶ğ�¡³ğ�¡¬ğ�¡¿ğ�¡¹ğ�¡±
    static public final List<Integer> PALMYRENE = (0x10860..0x1087F)
    // (40 chars) [**] : ğ�¢šğ�¢Šğ�¢†ğ�¢¯ğ�¢‹ğ�¢«ğ�¢‚ğ�¢Šğ�¢˜ğ�¢•ğ�¢•ğ�¢–ğ�¢§ğ�¢�ğ�¢©ğ�¢…ğ�¢™ğ�¢™ğ�¢„ğ�¢‹ğ�¢˜ğ�¢•ğ�¢—ğ�¢�ğ�¢‘ğ�¢�ğ�¢‹ğ�¢�ğ�¢šğ�¢®ğ�¢‰
    static public final List<Integer> NABATAEAN = (0x10880..0x1089E) + (0x108A7..0x108AF)
    // (26 chars) [**] : ğ�£«ğ�£¾ğ�££ğ�£©ğ�£¯ğ�£¤ğ�£½ğ�£ ğ�£½ğ�£¦ğ�£±ğ�£»ğ�£µğ�£¨ğ�£¢ğ�£µğ�£§ğ�£ªğ�£®ğ�£²ğ�£´ğ�£¼ğ�£»ğ�£®ğ�£¨ğ�£¯ğ�£­ğ�£«ğ�£°ğ�£©ğ�£¬
    static public final List<Integer> HATRAN = (0x108E0..0x108F5) - [0x108F3] + (0x108FB..0x108FF)
    // (29 chars) : ğ�¤†ğ�¤˜ğ�¤�ğ�¤�ğ�¤ƒğ�¤„ğ�¤�ğ�¤™ğ�¤�ğ�¤…ğ�¤ƒğ�¤•ğ�¤ƒğ�¤Šğ�¤�ğ�¤˜ğ�¤™ğ�¤†ğ�¤�ğ�¤™ğ�¤Ÿğ�¤ƒğ�¤�ğ�¤“ğ�¤‹ğ�¤Šğ�¤•ğ�¤ˆğ�¤Šğ�¤…ğ�¤€ğ�¤‰ğ�¤‡ğ�¤�ğ�¤€ğ�¤”ğ�¤‰ğ�¤‹ğ�¤ˆğ�¤–
    static public final List<Integer> PHOENICIAN = (0x10900..0x1091B) + [0x1091F]
    // (27 chars) : ğ�¤µğ�¤ ğ�¤©ğ�¤·ğ�¤©ğ�¤ªğ�¤¦ğ�¤·ğ�¤¯ğ�¤°ğ�¤±ğ�¤¢ğ�¤¿ğ�¤ªğ�¤°ğ�¤¶ğ�¤µğ�¤±ğ�¤µğ�¤¤ğ�¤§ğ�¤¿ğ�¤±ğ�¤©ğ�¤µğ�¤´ğ�¤¿ğ�¤³ğ�¤¡ğ�¤ ğ�¤¦ğ�¤¯ğ�¤§ğ�¤±ğ�¤µğ�¤ªğ�¤«ğ�¤¬ğ�¤¹
    static public final List<Integer> LYDIAN = (0x10920..0x10939) + [0x1093F]
    // (242 chars) Hieroglyphic : ğ�¥¦ğ�§®ğ�¥´ğ�¤¬ğ�¤¦ğ�§µğ�§�ğ�§¿ğ�¥¯ğ�¦¡ğ�¤¬ğ�¦ªğ�§‰ğ�¦¦ğ�¦œğ�¥ƒğ�§ ğ�¦«ğ�§“ğ�§‰
    static public final List<Integer> MEROITIC = (0x10908..0x109B7) + (0x109BC..0x109FF) - [0x109D0,0x109D1]
    // (68 chars) : ğ�¨…ğ�©“ğ�©„ğ�¨�ğ�¨�ğ�¨£ğ�¨¢ğ�¨›ğ�¨�ğ�¨›ğ�¨®ğ�¨¢ğ�¨ƒğ�¨ƒğ�¨¢ğ�¨²ğ�©„ğ�¨Œğ�¨±ğ�¨¤ğ�©€ğ�©—ğ�¨¸ğ�¨�ğ�¨�ğ�¨¸ğ�¨Ÿğ�©’ğ�¨�ğ�©„ğ�¨­ğ�¨‘ğ�©”ğ�¨Œğ�¨¥ğ�©ˆ
    static public final List<Integer> KHAROSHTHI = (0x10A00..0x10A03) + [0x10A05,0x10A06] + (0x10A0C..0x10A13) +
                                                   (0x10A15..0x10A17) + (0x10A19..0x10A35) + (0x10A38..0x10A3A) +
                                                   (0x10A3F..0x10A48) + (0x10A50..0x10A58)
    // (64 chars) : ğ�ª�ğ�ª�ğ�©¶ğ�ª�ğ�©¹ğ�ª�ğ�ª˜ğ�ªˆğ�©´ğ�©«ğ�ª˜ğ�©¸ğ�©»ğ�©¸ğ�©§ğ�ªƒğ�©½ğ�ª…ğ�ª‚ğ�© ğ�ª‡
    static public final List<Integer> OLD_ARABIAN = (0x10A60..0x10A9F)
    // (51 chars) : ğ�«�ğ�«‘ğ�«³ğ�«´ğ�«�ğ�«„ğ�«›ğ�«˜ğ�«®ğ�«œğ�«¦ğ�«‡ğ�«£ğ�«¬ğ�«µğ�«‘ğ�«�ğ�«‰ğ�«�ğ�« ğ�«�ğ�«¢
    static public final List<Integer> MANICHEAN = (0x10AC0..0x10AE6) + (0x10AEB..0x10AF6)
    // (61 chars) : ğ�¬¼ğ�¬’ğ�¬›ğ�¬�ğ�¬�ğ�¬‡ğ�¬°ğ�¬�ğ�¬‘ğ�¬µğ�¬˜ğ�¬ªğ�¬›ğ�¬�ğ�¬¼ğ�¬¡ğ�¬ªğ�¬¡ğ�¬®
    static public final List<Integer> AVESTAN = (0x10B00..0x10B35) + (0x10B39..0x10B3F)
    // (30 chars) [**] : ğ�­�ğ�­�ğ�­Ÿğ�­…ğ�­‰ğ�­Ÿğ�­›ğ�­œğ�­�ğ�­ˆğ�­Šğ�­†ğ�­‚ğ�­�ğ�­•ğ�­•ğ�­Ÿğ�­�ğ�­ƒğ�­€ğ�­�ğ�­•ğ�­�ğ�­‰ğ�­‡ğ�­�ğ�­šğ�­†ğ�­‘ğ�­›ğ�­Ÿğ�­�ğ�­‰ğ�­“ğ�­˜ğ�­�ğ�­�ğ�­‘ğ�­Ÿğ�­Š
    static public final List<Integer> PARTHIAN = (0x10B40..0x10B55) + (0x10B58..0x10B5F)
    // (56 chars) [**] : ğ�­²ğ�®�ğ�®ªğ�­©ğ�­£ğ�®�ğ�®¯ğ�­¦ğ�®Œğ�­«ğ�®‘ğ�®‘ğ�®«ğ�­¢ğ�­¨ğ�­­ğ�®€ğ�­¯ğ�®ˆğ�­¯ğ�®‘ğ�®†ğ�­¤ğ�­¯ğ�­½ğ�®„ğ�­©ğ�®Œğ�®šğ�®Šğ�­¤ğ�­¸ğ�®™ğ�­®ğ�­¹ğ�®�ğ�­¡ğ�®‹ğ�­¥
    static public final List<Integer> PAHLAVI = (0x10B60..0x10B72) + (0x10B78..0x10B91) + (0x10B99..0x10B9C) + (0x10BA9..0x10BAF)
    // (73 chars) : ğ�°‰ğ�±ƒğ�°…ğ�°¶ğ�°ƒğ�°°ğ�°¬ğ�°´ğ�°¯ğ�°‘ğ�°°ğ�°‹ğ�°©ğ�°�ğ�°™ğ�±†ğ�° ğ�°·ğ�°Ÿğ�°±ğ�°¤ğ�°¤ğ�±‚ğ�°•ğ�°¢ğ�°¨ğ�°¸ğ�°”ğ�°¤ğ�°»ğ�°·ğ�°�ğ�°»ğ�°¾ğ�°¹
    static public final List<Integer> OLD_TURKIC = (0x10C00..0x10C48)
    // (158 chars) : ğ�²Šğ�³¥ğ�³šğ�´³ğ�²™ğ�´¸ğ�²šğ�³¡ğ�³»ğ�²„ğ�²„ğ�´±ğ�²ƒğ�³�ğ�´…ğ�³•ğ�³±ğ�³¨ğ�³•ğ�³“ğ�²‡ğ�³�ğ�²‡
    static public final List<Integer> OLD_HUNGARIAN = (0x10C80..0x10CB2) + (0x10CC0..0x10CF2) + (0x10CFA..0x10D27) + (0x10D30..0x10D39)
    // (31 chars) : ğ�¹ºğ�¹±ğ�¹®ğ�¹»ğ�¹¥ğ�¹«ğ�¹«ğ�¹­ğ�¹«ğ�¹¶ğ�¹°ğ�¹§ğ�¹ºğ�¹¨ğ�¹¹ğ�¹´ğ�¹¨ğ�¹³ğ�¹©ğ�¹¶ğ�¹¦ğ�¹¹ğ�¹ºğ�¹«ğ�¹¢ğ�¹­ğ�¹·
    static public final List<Integer> RUMI = (0x10E60..0x10E7E)
    // (82 chars) [**] : ğ�¼Œğ�¼�ğ�¼�ğ�¼�ğ�¼¾ğ�¼�ğ�¼™ğ�½„ğ�¼§ğ�¼½ğ�¼�ğ�¼³ğ�¼˜ğ�¼›ğ�½�ğ�¼ ğ�½†ğ�½�ğ�¼¡ğ�¼�ğ�¼ƒğ�¼½ğ�¼µğ�¼–ğ�½ˆğ�½–ğ�¼‡ğ�¼¦ğ�¼šğ�½‘ğ�¼¥ğ�¼³ğ�¼“ğ�¼“ğ�¼£
    static public final List<Integer> SOGDIAN = (0x10F00..0x10F27) + (0x10F30..0x10F59)
    // (109 chars) : ğ‘�©ğ‘€¿ğ‘�–ğ‘�„ğ‘€œğ‘€¯ğ‘�ƒğ‘�–ğ‘� ğ‘€«ğ‘�‰ğ‘€«ğ‘�¯ğ‘€²ğ‘€ºğ‘€�ğ‘€Šğ‘€µğ‘�‰ğ‘€”ğ‘�šğ‘€¡ğ‘�…ğ‘�§ğ‘€Ÿğ‘€¬ğ‘�§ğ‘€¯ğ‘€…
    static public final List<Integer> BRAHMI = (0x11000..0x1104D) + (0x11052..0x1106F) + [0x1107F]
    // (66 chars) : ğ‘‚©ğ‘‚¥ğ‘‚‰ğ‘‚µğ‘‚§ğ‘‚¿ğ‘‚›ğ‘‚¸ğ‘‚„ğ‘‚¤ğ‘‚�ğ‘‚³ğ‘‚‹ğ‘‚„ğ‘‚‰ğ‘‚£ğ‘‚†ğ‘‚™ğ‘‚œğ‘‚”ğ‘‚•ğ‘‚³ğ‘‚±ğ‘‚›ğ‘‚«ğ‘‚¸ğ‘‚´ğ‘‚�ğ‘‚´ğ‘‚¿
    static public final List<Integer> KAITHI = (0x11080..0x110C1)
    // (36 chars) [**] : ğ‘ƒ•ğ‘ƒ¨ğ‘ƒ—ğ‘ƒ�ğ‘ƒ–ğ‘ƒ¥ğ‘ƒ±ğ‘ƒ¢ğ‘ƒ¸ğ‘ƒ’ğ‘ƒ¡ğ‘ƒ•ğ‘ƒ�ğ‘ƒ ğ‘ƒ™ğ‘ƒ“ğ‘ƒ’ğ‘ƒšğ‘ƒ¤ğ‘ƒ¦ğ‘ƒ·ğ‘ƒ�ğ‘ƒ¤ğ‘ƒ¨ğ‘ƒ“ğ‘ƒ�ğ‘ƒ¹
    static public final List<Integer> SORA_SOMPENG = [0x110CD] + (0x110D0..0x110E8) + (0x110F0..0x110F9)
    // (70 chars) : ğ‘„©ğ‘„—ğ‘„Šğ‘…†ğ‘„¯ğ‘„ˆğ‘„‰ğ‘„¹ğ‘„¸ğ‘„”ğ‘„±ğ‘……ğ‘„‰ğ‘„›ğ‘„»ğ‘„šğ‘„¼ğ‘„²ğ‘„¡ğ‘„¼ğ‘„’ğ‘…‚ğ‘…�ğ‘„»ğ‘„Šğ‘„’ğ‘„Šğ‘„Šğ‘„½ğ‘„�ğ‘„·ğ‘„–ğ‘„¿ğ‘„±ğ‘„•ğ‘…„ğ‘„´ğ‘„¦
    static public final List<Integer> CHAKMA = (0x11100..0x11134) + (0x11136..0x11146)
    // (39 chars) [**] : ğ‘…©ğ‘…¤ğ‘…¡ğ‘…¤ğ‘…©ğ‘…¬ğ‘…´ğ‘… ğ‘…‘ğ‘…¥ğ‘…¶ğ‘…�ğ‘…±ğ‘…¨ğ‘…�ğ‘…³ğ‘…®ğ‘…£ğ‘…˜ğ‘…–ğ‘…—ğ‘…©ğ‘…©ğ‘…£ğ‘…Ÿ
    static public final List<Integer> MAHAJANI = (0x11150..0x11176)
    // (96 chars) : ğ‘‡ƒğ‘†²ğ‘‡�ğ‘†�ğ‘‡™ğ‘†°ğ‘‡�ğ‘‡˜ğ‘†»ğ‘†“ğ‘†ºğ‘†¢ğ‘†±ğ‘†‘ğ‘‡“ğ‘‡Ÿğ‘†�ğ‘‡’ğ‘†Ÿğ‘†’ğ‘†�ğ‘‡�ğ‘†“ğ‘†§ğ‘†…ğ‘†„ğ‘†¼ğ‘†�ğ‘‡�ğ‘†”ğ‘‡•ğ‘‡”ğ‘†¿
    static public final List<Integer> SHARADA = (0x11180..0x111DF)
    // (38 chars) : ğ‘‡³ğ‘‡³ğ‘‡¤ğ‘‡¯ğ‘‡¬ğ‘‡¯ğ‘‡§ğ‘‡¤ğ‘‡¨ğ‘‡²ğ‘‡±ğ‘‡®ğ‘‡ªğ‘‡®ğ‘‡­ğ‘‡´ğ‘‡®ğ‘‡§ğ‘‡¦ğ‘‡©ğ‘‡¨
    static public final List<Integer> SHINHALA = (0x111E1..0x111F4)
    // (62 chars) : ğ‘ˆ¢ğ‘ˆ¯ğ‘ˆ§ğ‘ˆ†ğ‘ˆ”ğ‘ˆ¡ğ‘ˆ¼ğ‘ˆ�ğ‘ˆˆğ‘ˆ¥ğ‘ˆ¨ğ‘ˆ¯ğ‘ˆ‚ğ‘ˆ»ğ‘ˆ‰ğ‘ˆ•ğ‘ˆ�ğ‘ˆ›ğ‘ˆ¨ğ‘ˆ¨ğ‘ˆ³ğ‘ˆ·ğ‘ˆ‰ğ‘ˆ©
    static public final List<Integer> KHOJKI = (0x11200..0x1123E) - [0x11212]
    // (38 chars) [**] : ğ‘ŠŠğ‘Š£ğ‘Š¡ğ‘Š›ğ‘Š§ğ‘ŠŠğ‘Š˜ğ‘Š�ğ‘Š�ğ‘Š™ğ‘Š�ğ‘Š‘ğ‘ŠŠğ‘Š§ğ‘Š¨ğ‘ŠŸğ‘Š¦ğ‘Š€ğ‘Š�ğ‘Š–ğ‘Š�ğ‘Š‹ğ‘Š–ğ‘Š¡ğ‘Š¥ğ‘Š†ğ‘Š�ğ‘Š„ğ‘Š¢ğ‘Š¡
    static public final List<Integer> MULTANI = (0x11280..0x112A9) - [0x11287,0x11289,0x1128E,0x1129E]
    // (69 chars) : ğ‘Š¶ğ‘‹¥ğ‘Š¼ğ‘‹€ğ‘‹–ğ‘‹”ğ‘‹–ğ‘Š¶ğ‘‹˜ğ‘‹·ğ‘‹„ğ‘Š¸ğ‘Š³ğ‘‹“ğ‘‹„ğ‘‹‘ğ‘Šºğ‘‹°ğ‘‹³ğ‘‹°ğ‘‹¦ğ‘‹�ğ‘‹ˆğ‘‹¸ğ‘‹ªğ‘‹‘ğ‘‹¥ğ‘‹¸
    static public final List<Integer> KHUDAWADI = (0x112B0..0x112EA) + (0x112F0..0x112F9)
    // (85 chars) : ğ‘Œ–ğ‘Œ‚ğ‘Œ½ğ‘�°ğ‘Œ–ğ‘ŒŒğ‘Œ†ğ‘�Ÿğ‘��ğ‘�°ğ‘Œšğ‘Œ²ğ‘�¢ğ‘Œ¿ğ‘Œ“ğ‘��ğ‘Œ¢ğ‘�ƒğ‘ŒŒğ‘�´ğ‘��ğ‘Œ�ğ‘�¡ğ‘Œ®ğ‘�§ğ‘�¦ğ‘Œ“ğ‘Œ§ğ‘Œ�ğ‘Œˆ
    static public final List<Integer> GRANTHA = (0x11300..0x11303) + (0x11305..0x1130C) + (0x1130F..0x11310) + (0x11313..0x11328) +
                                                (0x1132A..0x11330) + [0x11332,0x11333] + (0x11335..0x11339) + (0x1133C..0x11344) +
                                                [0x11347,0x11348,0x1134B,0x1134C,0x1134D,0x11350,0x11357] + (0x1135D..0x11363) +
                                                (0x11366..0x1136C) + (0x11370..0x11374)
    // (97 chars) : ğ‘�ˆğ‘‘™ğ‘�¿ğ‘�‘ğ‘�“ğ‘‘—ğ‘��ğ‘�³ğ‘�­ğ‘��ğ‘�©ğ‘‘�ğ‘�»ğ‘�šğ‘�¬ğ‘�¼ğ‘�¨ğ‘‘˜ğ‘‘‰ğ‘��ğ‘‘�ğ‘‘…ğ‘�®ğ‘�¢ğ‘�‡ğ‘‘€ğ‘��ğ‘�˜
    static public final List<Integer> NEWA = (0x11400..0x11461) - [0x1145C]
    // (82 chars) : ğ‘’¨ğ‘’§ğ‘’–ğ‘’…ğ‘’¿ğ‘’±ğ‘’¾ğ‘’Œğ‘’�ğ‘’�ğ‘’�ğ‘’¶ğ‘’�ğ‘’™ğ‘’¼ğ‘’§ğ‘’µğ‘’�ğ‘’«ğ‘’˜ğ‘’›ğ‘“�ğ‘’ ğ‘’¾ğ‘“‡ğ‘’¡ğ‘’�ğ‘’ƒ
    static public final List<Integer> TIRHUTA = (0x11480..0x114C7) + (0x114D0..0x114D9)
    // (92 chars) : ğ‘—�ğ‘—…ğ‘—“ğ‘–‰ğ‘–±ğ‘–£ğ‘–˜ğ‘–‘ğ‘––ğ‘–µğ‘—�ğ‘–¨ğ‘–�ğ‘––ğ‘—†ğ‘—…ğ‘––ğ‘—‡ğ‘–•ğ‘–“ğ‘–´ğ‘——ğ‘–—ğ‘—–ğ‘–¾ğ‘–�ğ‘—‘ğ‘—–ğ‘–›
    static public final List<Integer> SIDDHAM = (0x11580..0x115B5) + (0x115B8..0x115DD)
    // (79 chars) : ğ‘˜­ğ‘˜‘ğ‘˜‘ğ‘™ƒğ‘™—ğ‘˜—ğ‘˜°ğ‘˜¡ğ‘˜¬ğ‘˜„ğ‘˜›ğ‘˜ºğ‘˜§ğ‘˜·ğ‘˜²ğ‘˜‡ğ‘˜‚ğ‘˜­ğ‘™˜ğ‘˜™ğ‘˜«ğ‘˜¿ğ‘™’ğ‘™“ğ‘˜�ğ‘˜¤ğ‘˜•ğ‘˜¢ğ‘™’ğ‘™�ğ‘™€ğ‘˜�
    static public final List<Integer> MODI = (0x11600..0x11644) + (0x11650..0x11659)
    // (67 chars) : ğ‘šŒğ‘šŒğ‘š¢ğ‘š¤ğ‘š©ğ‘›†ğ‘›…ğ‘š�ğ‘š…ğ‘šµğ‘šˆğ‘š�ğ‘šƒğ‘›‚ğ‘š…ğ‘š²ğ‘š“ğ‘š²ğ‘š·ğ‘š”ğ‘ššğ‘š‹ğ‘š¨ğ‘š•ğ‘š¸ğ‘š§ğ‘š°
    static public final List<Integer> TAKRI = (0x11680..0x116B8) + (0x116C0..0x116C9)
    // (58 chars) : ğ‘œ—ğ‘œ�ğ‘œ°ğ‘œ¡ğ‘œ�ğ‘œ¶ğ‘œ“ğ‘œ�ğ‘œ„ğ‘œƒğ‘œ¢ğ‘œ�ğ‘œŒğ‘œ•ğ‘œŒğ‘œŒğ‘œºğ‘œ˜ğ‘œˆğ‘œ³ğ‘œ‚ğ‘œ‚ğ‘œ¼ğ‘œ ğ‘œ�ğ‘œ°ğ‘œ‹ğ‘œ²
    static public final List<Integer> AHOM = (0x11700..0x1171A) + (0x1171D..0x1172B) + (0x11730..0x1173F)
    // (84 chars) : ğ‘£“ğ‘£¿ğ‘£„ğ‘¢²ğ‘¢¨ğ‘£¬ğ‘£›ğ‘£‡ğ‘¢±ğ‘¢®ğ‘¢²ğ‘¢®ğ‘£²ğ‘£‘ğ‘¢ªğ‘¢§ğ‘£”ğ‘£�ğ‘¢½ğ‘¢¢ğ‘¢¶ğ‘¢£ğ‘£¨ğ‘£ˆğ‘¢¬ğ‘¢«ğ‘£œğ‘£­ğ‘¢ 
    static public final List<Integer> WARANG_CITI = (0x118A0..0x118F2) + [0x118FF]
    // (72 chars) : ğ‘¨€ğ‘¨–ğ‘¨¥ğ‘¨‹ğ‘¨»ğ‘¨¸ğ‘¨’ğ‘¨�ğ‘¨«ğ‘¨»ğ‘¨¦ğ‘¨»ğ‘¨£ğ‘¨´ğ‘¨¨ğ‘¨�ğ‘¨¤ğ‘¨¦ğ‘¨»ğ‘©‚ğ‘¨¸ğ‘¨¦ğ‘©…ğ‘¨’ğ‘¨­
    static public final List<Integer> ZANABAZAR = (0x11A00..0x11A47)
    // (83 chars) : ğ‘©—ğ‘©¹ğ‘©›ğ‘ª�ğ‘©�ğ‘©²ğ‘ª–ğ‘ª�ğ‘©�ğ‘ªƒğ‘©§ğ‘©¢ğ‘©¯ğ‘©´ğ‘©£ğ‘ª€ğ‘©·ğ‘©�ğ‘©�ğ‘ª›ğ‘©�ğ‘©œğ‘ª•ğ‘©¦ğ‘ª�ğ‘©¦ğ‘©’
    static public final List<Integer> SOYOMBO = (0x11A50..0x11AA2)
    // (57 chars) : ğ‘«­ğ‘«œğ‘«·ğ‘«®ğ‘«†ğ‘««ğ‘«†ğ‘«™ğ‘«…ğ‘«�ğ‘«�ğ‘«�ğ‘«‘ğ‘«˜ğ‘«›ğ‘« ğ‘«€ğ‘«³ğ‘«‰ğ‘«–ğ‘«’ğ‘«¢ğ‘«�ğ‘«�ğ‘«®ğ‘«‘
    static public final List<Integer> PAU_CIN_HAU = (0x11AC0..0x11AF8)
    // (97 chars) : ğ‘±¡ğ‘±™ğ‘°�ğ‘±�ğ‘°‹ğ‘±¥ğ‘±�ğ‘°�ğ‘°’ğ‘±£ğ‘°‘ğ‘°²ğ‘°¬ğ‘°�ğ‘°¨ğ‘±›ğ‘°½ğ‘°�ğ‘°¯ğ‘°¾ğ‘°«ğ‘±¤
    static public final List<Integer> BHAIKSUKI = (0x11C00..0x11C45) - [0x11C09,0x11C37] + (0x11C50..0x11C6C)
    // (68 chars) : ğ‘²ƒğ‘±´ğ‘²ˆğ‘±²ğ‘²¦ğ‘±»ğ‘²­ğ‘±ºğ‘²…ğ‘²�ğ‘²–ğ‘²œğ‘±¿ğ‘²¦ğ‘±¼ğ‘±²ğ‘²…ğ‘±¸ğ‘±²ğ‘²Š
    static public final List<Integer> MARCHEN = (0x11C70..0x11C8F) + (0x11C92..0x11CB6) - [0x11CA8]
    // (1235 chars) : ğ’€©ğ’“²ğ’�œğ’„…ğ’Š ğ’…³ğ’‚�ğ’ƒ½ğ’Œ®ğ’�£ğ’�‚ğ’�¾
    static public final List<Integer> CUNEIFORM = (0x12000..0x12399) + (0x12400..0x12474) + (0x12480..0x12543)
    // (1071 chars) Hieroglyphic : ğ“‚·ğ“��ğ“‹¤ğ“‰—ğ“�¾ğ“‚�ğ“‹®ğ“�¢ğ“†³ğ“‡ˆğ“‹¶ğ“��ğ“Š™ğ“ƒ¨ğ“Š‡ğ“€¿ğ“�Œ
    static public final List<Integer> EGYPTIAN = (0x13000..0x1342E)
    // (583 chars) Hieroglyphic : ğ”’¶ğ”’‹ğ””£ğ”•’ğ”“Ÿğ””„ğ”�©ğ”�­ğ”’¥ğ”�–ğ”–¥ğ”“¿ğ”’—ğ”˜µğ”•¢ğ”‘›ğ”–‚ğ”�—ğ”˜�ğ”‘·ğ”™�
    static public final List<Integer> ANATOLIAN = (0x14400..0x14646)
    // (570 chars) : ğ–¦·ğ–¦·ğ–¢�ğ–¢’ğ– �ğ–¤…ğ–¦•ğ– ¥ğ–¨©ğ–¡–ğ–§ƒğ–¦�ğ–¢¯ğ–¤™ğ–§«ğ–¦˜ğ–¨­ğ–¡·ğ–§†ğ–£½ğ–¢�ğ–£¨
    static public final List<Integer> BAMUM_SMP = (0x16800..0x16A39)
    // (136 chars) [**] : ğ–©–ğ–©£ğ–©�ğ–©�ğ–©›ğ–©®ğ–©�ğ–©�ğ–©Šğ–©£ğ–©�ğ–©šğ–©˜ğ–©˜ğ–©�ğ–©¦ğ–©€ğ–©ˆğ–©•ğ–©…ğ–©’ğ–©£ğ–©©ğ–©‹ğ–©‘ğ–©ˆğ–©�ğ–©Šğ–©•ğ–©¨ğ–©š
    static public final List<Integer> MRO = (0x16A40..0x16A69) - [0x16A5F] + [0x16A6E,0x16A6F]
    // (142 chars) [**] : ğ–«¨ğ–«–ğ–«¡ğ–«™ğ–«¤ğ–««ğ–«¥ğ–«´ğ–«•ğ–« ğ–«”ğ–«“ğ–«£ğ–«˜ğ–«’ğ–«•ğ–«�ğ–«§ğ–«©ğ–«³ğ–«“ğ–«§ğ–«¨ğ–«’ğ–«‘ğ–«µğ–«´ğ–«�ğ–«™ğ–«šğ–«“ğ–«¨ğ–«œğ–«–
    static public final List<Integer> BASSA_VAH = (0x16AD0..0x16AED) + (0x16AF0..0x16AF5)
    // (127 chars) : ğ–¬”ğ–®‹ğ–¬¢ğ–¬½ğ–¬˜ğ–­¿ğ–­ ğ–­œğ–­«ğ–¬°ğ–¬ ğ–­…ğ–¬¦ğ–­�ğ–­³ğ–­�ğ–¬€ğ–­‘ğ–­…ğ–®ƒğ–­±ğ–¬°ğ–¬˜ğ–¬›ğ–¬¡ğ–¬·ğ–¬¹ğ–¬©ğ–­ƒğ–­­ğ–¬¼ğ–¬´
    static public final List<Integer> PAHAWH_HMONG = (0x16B00..0x16B45) + (0x16B50..0x16B77) - [0x16B5A,0x16B62] + (0x16B7D..0x16B8F)
    // (149 chars) : ğ–¼‡ğ–¼œğ–½²ğ–½²ğ–¾œğ–½‘ğ–¼·ğ–¼¹ğ–½­ğ–½†ğ–¼±ğ–¼©ğ–¾�ğ–¼·ğ–½†ğ–¾‚ğ–¼¦ğ–¼œğ–½­ğ–¾™ğ–½©ğ–½”ğ–¼±ğ–¼›ğ–½ˆğ–½•ğ–½°
    static public final List<Integer> MIAO = (0x16F00..0x16F4A) + (0x16F4F..0x16F87) + (0x16F8F..0x16F9F)
    // (6892 chars) : ğ—¸“ğ˜�¶ğ—œ›ğ—¤­ğ—·•ğ—›‹ğ—�†ğ˜‹‘ğ˜��ğ—‹©ğ˜ª‰ğ—•¤ğ—¾¤ğ˜——
    static public final List<Integer> TANGUT = [0x16FE0] + (0x17000..0x187F7) + (0x18800..0x18AF2)
    // (396 chars) [**] : ğ›‰­ğ›ˆ�ğ›†¤ğ›Š€ğ›…·ğ›ˆ ğ›‹ºğ›Šªğ›‰¸ğ›‰’ğ›†�ğ›†¹ğ›‰Šğ›ˆ™ğ›…¼ğ›ˆ�ğ›ˆ–ğ›‰¢ğ›‡¯
    static public final List<Integer> NUSHU = (0x1B170..0x1B2FB)
    // (144 chars) : ğ›±Ÿğ›±¼ğ›°•ğ›±—ğ›²’ğ›±¨ğ›°´ğ›±‹ğ›°Ÿğ›°ˆğ›°ºğ›²€ğ›±�ğ›±±ğ›°¥ğ›²œğ›²ƒğ›°�ğ›°©ğ›°¸ğ›°­ğ›±¡ğ›±¶ğ›°„ğ›±¥
    static public final List<Integer> DUPLOYAN = (0x1BC00..0x1BC6A) + (0x1BC70..0x1BC7C) + (0x1BC80..0x1BC88) + (0x1BC90..0x1BC9F) - [0x1BCAA,0x1BCAB,0x1BC9D]
    // (549 chars) : ğ�ˆ¨ğ�‚¬ğ�†´ğ��´ğ�‚¯ğ�€§ğ�…¬ğ�ƒ�ğ�ˆ¹ğ��…ğ�‡–ğ�ˆ¾ğ�ˆ‹ğ�ˆ½ğ�†—ğ�…£ğ�‡Œğ��¢ğ�‡†ğ�…¤ğ�…�ğ�…˜ğ�€œğ�ƒ¤ğ��ºğ�…ˆğ�„»ğ�€¯ğ�…­ğ�…†ğ�†¢
    static public final List<Integer> MUSICAL = (0x1D000..0x1D0F5) + //Byzantine
                                                (0x1D100..0x1D1EA) - [0x1D127,0x1D128] + //General
                                                (0x1D200..0x1D245) //Greek
    // (20 chars) : ğ�‹®ğ�‹¯ğ�‹«ğ�‹¯ğ�‹ªğ�‹²ğ�‹¯ğ�‹¤ğ�‹§ğ�‹¦ğ�‹©ğ�‹ ğ�‹¥ğ�‹²ğ�‹¯ğ�‹¤ğ�‹°
    static public final List<Integer> MAYAN = (0x1D2E0..0x1D2F3)
    // (87 chars) * Similar to HEXAGRAMS : ğ�Œ´ğ���ğ�Œ»ğ���ğ��‡ğ�Œ™ğ�Œ¯ğ�Œ–ğ�Œ³ğ�Œ“ğ�Œºğ�Œ�ğ�ŒŒğ�Œ�ğ�Œ”ğ��”ğ��“ğ�Œ�
    static public final List<Integer> TAIXUANJING = (0x1D300..0x1D356)
    // (25 chars) : ğ��«ğ��µğ��¢ğ��ªğ��¬ğ��´ğ��·ğ��§ğ��¨ğ��©ğ��°ğ��®ğ��¢ğ��¤ğ��´ğ��¢ğ��¸ğ��¦ğ��§ğ��¢
    static public final List<Integer> COUNTING = (0x1D360..0x1D378)
    // (1020 chars) : ğ�Ÿ‰ğ�›¸ğ�›�ğ�›‘ğ�‘ƒğ��²ğ�›¾ğ�™Ÿğ�”¶ğ�›™ğ�—�ğ���ğ�”ƒğ�”‰ğ�œ­ğ�—�ğ�—–
    static public final List<Integer> MATH = (0x1D400..0x1D7FF) - [0x1D6A6,0x1D6A7,0x1D7CD,0x1D7CE]
    // (38 chars) [**] : ğ�€“ğ�€•ğ�€—ğ�€¨ğ�€§ğ�€�ğ�€ˆğ�€ ğ�€›ğ�€¡ğ�€„ğ�€‹ğ�€ ğ�€�ğ�€˜ğ�€¦ğ�€‹ğ�€–ğ�€�ğ�€Šğ�€—ğ�€�ğ�€�ğ�€‹ğ�€¦ğ�€ªğ�€Ÿğ�€©ğ�€€ğ�€Œğ�€”ğ�€Šğ�€ˆğ�€”ğ�€�ğ�€¤ğ�€†ğ�€�ğ�€„ğ�€£ğ�€�ğ�€£ğ�€Œğ�€–ğ�€¦ğ�€£ğ�€¤ğ�€Œğ�€Ÿğ�€”ğ�€…ğ�€ƒğ�€‰ğ�€‰ğ�€�ğ�€›ğ�€ƒğ�€‹ğ�€£ğ�€„ğ�€�ğ�€©ğ�€€ğ�€‰ğ�€˜ğ�€¦ğ�€�ğ�€§ğ�€›ğ�€�
    static public final List<Integer> GLAGOLITIC_SMP = (0x1E000..0x1E02A) - [0x1E007,0x1E019,0x1E01A,0x1E022,0x1E025]
    // (71 chars) [**] : ğ�„Ÿğ�„‚ğ�…�ğ�„œğ�…�ğ�„‰ğ�„£ğ�„�ğ�„»ğ�„œğ�„„ğ�„…ğ�…�ğ�„Ÿğ�…†ğ�„¨ğ�„¡ğ�„”ğ�„–ğ�„…ğ�……ğ�„½ğ�…€ğ�„•ğ�„”
    static public final List<Integer> NYIAKENG = (0x1E100..0x1E12C) + (0x1E130..0x1E13D) + (0x1E140..0x1E149) + [0x1E14E,0x1E14F]
    // (59 chars) : ğ�‹ªğ�‹©ğ�‹‹ğ�‹¿ğ�‹¯ğ�‹�ğ�‹©ğ�‹±ğ�‹©ğ�‹’ğ�‹³ğ�‹ ğ�‹Œğ�‹¿ğ�‹‹ğ�‹Šğ�‹˜ğ�‹†ğ�‹­ğ�‹…ğ�‹œğ�‹©ğ�‹Ÿğ�‹©ğ�‹­ğ�‹®ğ�‹�ğ�‹‚ğ�‹²
    static public final List<Integer> WANCHO = (0x1E2C0..0x1E2F9) + [0x1E2FF]
    // (213 chars) : ğ�£€ğ�¡µğ�¡¨ğ�¢­ğ� ‚ğ�¡ºğ�¡„ğ�¢Ÿğ�¢‚ğ� �ğ�¡µğ�¡“ğ�¡©ğ� ¨ğ�¡¹ğ�¡»ğ� ‘ğ� ªğ�¢ƒğ�¡¥ğ�¢šğ� ‰
    static public final List<Integer> MENDE_KIKAKUI = (0x1E800..0x1E8D6) - [0x1E8C5,0x1E8C6]
    // (88 chars) : ğ�¥Ÿğ�¤©ğ�¥‘ğ�¤†ğ�¥•ğ�¤‹ğ�¥”ğ�¤•ğ�¤¢ğ�¥”ğ�¤±ğ�¤“ğ�¤²ğ�¤„ğ�¤†ğ�¤˜ğ�¤§ğ�¤©ğ�¤£ğ�¥‘ğ�¤´ğ�¥“ğ�¤³ğ�¤²ğ�¤šğ�¤ªğ�¤€ğ�¥„ğ�¤ºğ�¤±ğ�¤�ğ�¤¢ğ�¥Ÿ
    static public final List<Integer> ADLAM = (0x1E900..0x1E94B) + (0x1E950..0x1E959) + [0x1E95E,0x1E95F]
    // (68 chars) :           ğ�²®ğ�²—ğ�±»ğ�²�ğ�±²
    static public final List<Integer> SIYAQ = (0x1EC71..0x1ECB4)
    // (143 chars) : ğ�¸›ğ�¹¶ğ�º˜ğ�º¥ğ�º’ğ�º¯ğ�º¦ğ�º¬ğ�º´ğ�ºŒğ�¹¡ğ�¸®ğ�¹‡ğ�º·ğ�º–ğ�¹¹ğ�¹µ
    static public final List<Integer> ARABIC_SMP = (0x1EE00..0x1EEBB) + [0x1EEF0,0x1EEF1] - [0x1EE04,0x1EE20,0x1EE23,0x1EE25,0x1EE26,
                                                                                             0x1EE28,0x1EE33,0x1EE38,0x1EE3A,0x1EE48,
                                                                                             0x1EE4A,0x1EE4C,0x1EE50,0x1EE53,0x1EE55,
                                                                                             0x1EE56,0x1EE58,0x1EE5A,0x1EE5C,0x1EE5E,
                                                                                             0x1EE60,0x1EE63,0x1EE65,0x1EE66,0x1EE6B,
                                                                                             0x1EE73,0x1EE78,0x1EE7D,0x1EE7F,0x1EE8A,
                                                                                             0x1EEA4,0x1EEAA] -
                                                    (0x1EE3C..0x1EE41) - (0x1EE43..0x1EE46) - (0x1EE9C..0x1EEA0)
    // (44 chars) : ğŸ€”ğŸ€�ğŸ€›ğŸ€�ğŸ€ªğŸ€–ğŸ€ƒğŸ€”ğŸ€�ğŸ€�ğŸ€šğŸ€ªğŸ€ˆğŸ€…ğŸ€™ğŸ€‡
    static public final List<Integer> MAHJONG = (0x1F000..0x1F02B)
    // (100 chars) : ğŸ‚‚ğŸ�°ğŸ��ğŸ�µğŸ�­ğŸ‚€ğŸ�¥ğŸ€¹ğŸ�‰ğŸ€¸ğŸ€±ğŸ� ğŸ�²ğŸ‚�ğŸ€»ğŸ�±ğŸ‚’ğŸ�ŒğŸ€»ğŸ€´ğŸ€´ğŸ�¼ğŸ€±ğŸ�©ğŸ€¸ğŸ��ğŸ�¨ğŸ�ŒğŸ€·
    static public final List<Integer> DOMINO = (0x1F030..0x1F093)
    // (82 chars) : ğŸ‚¿ğŸƒ…ğŸƒ“ğŸ‚¹ğŸƒ ğŸƒ�ğŸƒˆğŸ‚¸ğŸ‚¥ğŸƒ£ğŸƒ•ğŸƒ¢ğŸ‚¬ğŸ‚®ğŸ‚®ğŸ‚²ğŸƒš
    static public final List<Integer> CARDS = (0x1F0A0..0x1F0F5) - [0x1F0AF,0x1F0B0,0x1F0C0,0x1F0D0]
    // (84 chars) : ğŸ¨ŠğŸ¨‡ğŸ¨´ğŸ¨°ğŸ¨�ğŸ¨‚ğŸ¨–ğŸ¨ƒğŸ©ˆğŸ¨¨ğŸ¨ŒğŸ¨‹ğŸ¨¼ğŸ©�ğŸ¨€ğŸ¨¿ğŸ¨�ğŸ¨©ğŸ¨¦
    static public final List<Integer> CHESS = (0x1FA00..0x1FA53)
    // (14 chars) : ğŸ©§ğŸ©­ğŸ©§ğŸ©©ğŸ©¬ğŸ©§ğŸ©§ğŸ©«ğŸ©¤ğŸ©ªğŸ©§ğŸ©¤ğŸ©­
    static public final List<Integer> CHESS_CH = (0x1FA60..0x1FA6D)
    // (10 chars) : ğŸ„…ğŸ„…ğŸ„†ğŸ„ˆğŸ„ƒğŸ„‰ğŸ„…ğŸ„‡ğŸ„‡ğŸ„‚ğŸ„�ğŸ„‡ğŸ„ˆğŸ„‡ğŸ„�ğŸ„‰ğŸ„ƒğŸ„„ğŸ„ƒğŸ„ŠğŸ„ˆğŸ„ƒğŸ„…
    static public final List<Integer> COMMA_NUM = (0x1F101..0x1F10A)
    // (26 chars) : ğŸ„–ğŸ„¡ğŸ„¤ğŸ„¢ğŸ„˜ğŸ„’ğŸ„¢ğŸ„—ğŸ„šğŸ„�ğŸ„£ğŸ„¥ğŸ„¦ğŸ„¤
    static public final List<Integer> PAREN_UP = (0x1F110..0x1F129)
    // (26 chars) : ğŸ„ºğŸ„¸ğŸ…ˆğŸ…‚ğŸ„¸ğŸ…‡ğŸ„°ğŸ„´ğŸ„¹ğŸ„»ğŸ„¼ğŸ„ºğŸ„´ğŸ…ˆğŸ„µğŸ„³ğŸ„±ğŸ„¶ğŸ…‰ğŸ„²
    static public final List<Integer> SQUARE_UP = (0x1F130..0x1F149)
    // (26 chars) : ğŸ…§ğŸ…�ğŸ…§ğŸ…–ğŸ…¡ğŸ…¤ğŸ…¢ğŸ…˜ğŸ…’ğŸ…¢ğŸ…—ğŸ…šğŸ…�ğŸ…£ğŸ…¥ğŸ…¦ğŸ…¤ğŸ…�ğŸ…˜ğŸ…Ÿ
    static public final List<Integer> CIRCLE_UP_NEG = (0x1F150..0x1F169)
    // (26 chars) : ğŸ…¸ğŸ†‡ğŸ…°ğŸ…´ğŸ…¹ğŸ…»ğŸ…¼ğŸ…ºğŸ…´ğŸ†ˆğŸ…µğŸ…³ğŸ…±ğŸ…¶ğŸ†‰ğŸ…²ğŸ…¶ğŸ…¾ğŸ…±ğŸ†„ğŸ†‡ğŸ†€ğŸ†ƒğŸ††ğŸ†€
    static public final List<Integer> SQUARE_UP_NEG = (0x1F170..0x1F189)
    // (150 chars) : ğŸ ˜ğŸ ŠğŸ �ğŸ¡™ğŸ �ğŸ¢«ğŸ ‡ğŸ ´ğŸ¡«ğŸ ¼ğŸ ¤ğŸ §ğŸ —ğŸ¢—ğŸ ©ğŸ¢€ğŸ¡–ğŸ ½ğŸ ‹ğŸ¢ŸğŸ¡´ğŸ ¿ğŸ¢�ğŸ¢”ğŸ “ğŸ¢‘ğŸ¡¡ğŸ¡¿ğŸ¢…ğŸ ¶
    static public final List<Integer> ARROWS = (0x1F800..0x1F847) - (0x1F80C..0x1F80F) + (0x1F850..0x1F859) + (0x1F860..0x1F887) + (0x1F890..0x1F8AD) + [0x1F8B0,0x1F8B1]
    // (654 chars) : ğ�š“ğŸ„‹ğŸ™”ğ�™µğŸœ¶ğŸœ©ğŸ�¤ğŸœ�ğŸ™¶ğ�›–ğŸ„‹ğŸŸ�ğŸ™´ğ�œ¢ğŸ™ªğ�š¼ğŸ†�ğŸ��ğ�œœğŸ™·ğŸ…­ğŸŸ•ğŸ†”ğŸœ¾ğŸœ‡
    static public final List<Integer> SYMBOLS_SMP = (0x10600..0x10736) + (0x10740..0x10755) + (0x10760..0x10767) +
                                                    (0x1F650..0x1F67F) + // Dingbats
                                                    (0x1F700..0x1F773) + // Alchemical
                                                    (0x1F780..0x1F7D8) + // Geometric
                                                    [0x1F100] + (0x1F10B..0x1F10F) + (0x1F12A..0x1F12F) + (0x1F14A..0x1F14F) + (0x1F16A..0x1F16F) + (0x1F18A..0x1F1AD) // Assorted
    // (1325 chars) : ğŸ¥¿ğŸ©²ğŸ‘™ğŸª�ğŸ§„ğŸ›¡ğŸ—¦ğŸ•™ğŸ«›ğŸ—�ğŸªµğŸŸ¨ğŸ“�ğŸ”�ğŸ–˜ğŸ�¸ğŸ�”ğŸ¥•ğŸ”¬ğŸ�¾ğŸ«µğŸ›£
    static public final List<Integer> EMOJI = (0x1F300..0x1F64F) + (0x1F680..0x1F6D7) + (0x1F6E0..0x1F6EC) + (0x1F6F0..0x1F6FC) +
                                              (0x1F90C..0x1F9FF) + (0x1FA70..0x1FA7C) + (0x1FA80..0x1FA88) + (0x1FA90..0x1FABD) +
                                              (0x1FABF..0x1FAC5) + (0x1FACE..0x1FADB) + (0x1FAE0..0x1FAE8) + (0x1FAF0..0x1FAF8) +
                                              (0x1F7E0..0x1F7EB) // Geometric
    // (269 chars) : ğ�€¨ğ�€¤ğ�ƒ‚ğ�€²ğ�‚‡ğ�ƒšğŸˆ˜ğ�ƒ�ğ�‚¬ğ�€…ğŸˆ–ğ�‚½ğ�€ˆğ�ƒ¥ğ�‚ ğ�‚­ğ�‚®ğ�ƒ ğŸˆ–ğ�‚»ğ�‚‹ğ�ƒ›ğ�ƒ¥ğ��Œğ�€šğ�ƒ„
    static public final List<Integer> IDEOGRAMS = (0x10000..0x1005D) - [0x1000C,0x10027,0x1003B,0x1003E,0x1004E,0x1004F] +
                                                  (0x10080..0x100FA) + (0x1F200..0x1F202) + (0x1F210..0x1F23B) + (0x1F240..0x1F248) +
                                                  [0x1F250,0x1F251]
    // (203 chars) : ğŸ­–ğŸ¬¡ğŸ¯ˆğŸ¬ŒğŸ®¿ğŸ®µğŸ®�ğŸ­¡ğŸ¬—ğŸ­€ğŸ®Ÿ
    static public final List<Integer> BLOCK_SMP = (0x1FB00..0x1FBCA)
    // (10 chars) : ğŸ¯´ğŸ¯±ğŸ¯¶ğŸ¯°ğŸ¯µğŸ¯°ğŸ¯¸ğŸ¯¹ğŸ¯°ğŸ¯²ğŸ¯¸ğŸ¯¹ğŸ¯¸ğŸ¯±ğŸ¯²
    static public final List<Integer> DIGITS = (0x1FBF0..0x1FBF9)


    /* ************ SMP COMBOS **************** */
    // Hieroglyphics (1896 chars) : ğ“‹¢ğ“�¯ğ“‚±ğ“��ğ“Œ´ğ”–¥ğ”’º
    static public final List<Integer> HIEROGLYPHIC = EGYPTIAN + MEROITIC + ANATOLIAN
    // Lines (151 chars) : ğ�Œ­ğ���ğ�Œ´ä·�ä·‹ğ�Œ…ğ�Œ°ğ�Œ›ğ�Œ€ğ�Œˆä·«ğ��–ğ�Œ�ğ�Œ‚ä·›ä·–
    static public final List<Integer> LINES_SMP = HEXAGRAM + TAIXUANJING
    // (1317 chars) : ğ’€Šğ’‹«ğ’�­ğ’”«ğ’Œ»ğ’ŠŠğ’‰²ğ’‘™ğ’€‚ğ’‰¹
    static public final List<Integer> WEDGE = UGARTIC + OLD_PERSIAN + CUNEIFORM
    // (68,498 chars) : ã‹Ÿè®�ğŸ¬µí„‡ğ�Šˆíœ¹ğŸ¯ˆâ›·æ“¶
    static public final List<Integer> VISIBLE_SMP = VISIBLE + GREEK_SMP + ROMAN + AEGEAN + PHAISTOS + LYCIAN + CARIAN + OLD_ITALIC +
        GOTHIC + OLD_PERMIC + UGARTIC + OLD_PERSIAN + DESERET + SHAVIAN + OSMANYA + OSAGE + ELBASAN + ALBANIAN + CYPRIOT + ARAMAIC +
        PALMYRENE + NABATAEAN + HATRAN + PHOENICIAN + LYDIAN + MEROITIC + KHAROSHTHI + OLD_ARABIAN + MANICHEAN + AVESTAN + PARTHIAN +
        PAHLAVI + OLD_TURKIC + OLD_HUNGARIAN + RUMI + SOGDIAN + BRAHMI + KAITHI + SORA_SOMPENG + CHAKMA + MAHAJANI + SHARADA + SHINHALA +
        KHOJKI + MULTANI + KHUDAWADI + GRANTHA + NEWA + TIRHUTA + SIDDHAM + MODI + TAKRI + AHOM + WARANG_CITI + ZANABAZAR + SOYOMBO +
        PAU_CIN_HAU + BHAIKSUKI + MARCHEN + CUNEIFORM + EGYPTIAN + ANATOLIAN + BAMUM_SMP + MRO + BASSA_VAH + PAHAWH_HMONG + MIAO +
        TANGUT + DUPLOYAN + MUSICAL + MAYAN + TAIXUANJING + COUNTING + MATH + GLAGOLITIC_SMP + NYIAKENG + WANCHO + MENDE_KIKAKUI +
        ADLAM + SIYAQ + ARABIC_SMP + MAHJONG + DOMINO + CARDS + COMMA_NUM + PAREN_UP + SQUARE_UP + CIRCLE_UP_NEG + SQUARE_UP_NEG +
        ARROWS + SYMBOLS_SMP + EMOJI + CHESS + CHESS_CH + IDEOGRAMS + BLOCK_SMP + DIGITS

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Wrapper around a list of characters with special properties
     */
    static class CharSet {
        final private List<Integer> chars

        CharSet(Collection<Integer> chars) {
            this.chars = chars.toList().unique()
            assert length > 1 : "Charset must be at least 1 character"
        }

        int getLength() {
            return chars.size()
        }

        int getPosition(int chr) {
            return chars.toList().indexOf(chr)
        }

        int getAt(int index) {
            return chars[index]
        }

        List<Integer> getChars() {
            return chars.collect() // Create a clone of the List so we don't modify it
        }
    }

    private CharSet input
    private CharSet output
    private long seed
    /**
     * Constructor using a CharSet as input and a list as output
     * @param input
     * @param output
     * @param seed
     */
    LpCode(CharSet input, Collection<Integer> output, long seed = 0) {
        this.input = input
        this.output = new CharSet(output)
        this.seed = seed
    }
    /**
     * Constructor using a list of characters and a CharSet
     * @param input
     * @param output
     * @param seed
     */
    LpCode(Collection<Integer> input, CharSet output, long seed = 0) {
        this.input = new CharSet(input)
        this.output = output
        this.seed = seed
    }
    /**
     * Constructor using input and output as CharSet
     * @param input
     * @param output
     * @param seed
     */
    LpCode(CharSet input, CharSet output, long seed = 0) {
        this.input = input
        this.output = output
        this.seed = seed
    }
    /**
     * Constructor using two lists of characters
     * @param input
     * @param output
     * @param seed
     */
    LpCode(Collection<Integer> input = BASIC, Collection<Integer> output = ANUM, long seed = 0) {
        this.input = new CharSet(input)
        this.output = new CharSet(output)
        this.seed = seed
    }
    /**
     * Get the BigInteger from an array of characters for a specific CharSet
     * @param chars
     * @param charSet
     * @param seed
     * @return
     */
    static BigInteger toNumber(char[] chars, CharSet charSet, long seed = 0) {
        LpCode lpCode = new LpCode(charSet, charSet, seed)
        if(seed) { chars = lpCode.randomize(chars) }
        return toNum(chars, charSet)
    }
    /**
     * Get the BigInteger from an array of characters for a specific list of characters
     * @param chars
     * @param charSet
     * @param seed
     * @return
     */
    static BigInteger toNumber(char[] chars, Collection<Integer> charSet, long seed = 0) {
        return toNumber(chars, new CharSet(charSet), seed)
    }
    /**
     * Convert number to char array
     * @param number
     * @param charSet
     * @param seed
     * @return
     */
    static char[] toCharArray(BigInteger number, CharSet charSet, long seed = 0) {
        LpCode lpCode = new LpCode(charSet, charSet, seed)
        char[] chars = toStr(number, charSet)
        if(seed) { chars = lpCode.randomize(chars, true) }
        return chars
    }
    /**
     * Convert number to char array using a list of characters
     * @param number
     * @param charSet
     * @param seed
     * @return
     */
    static char[] toCharArray(BigInteger number, Collection<Integer> charSet, long seed = 0) {
        return toCharArray(number, new CharSet(charSet), seed)
    }
    /**
     * Convert number to string
     * @param number
     * @param charSet
     * @param seed
     * @return
     */
    static String toString(BigInteger number, CharSet charSet, long seed = 0) {
        LpCode lpCode = new LpCode(charSet, charSet, seed)
        char[] chars = toStr(number, charSet)
        return (seed ? lpCode.randomize(chars, true) : chars).toString()
    }
    /**
     * Convert number to string
     * @param number
     * @param charSet
     * @param seed
     * @return
     */
    static String toString(BigInteger number, Collection<Integer> charSet, long seed = 0) {
        return toString(number, new CharSet(charSet), seed)
    }

    /**
     * The following methods are static wrappers for `translate`
     * @param chars : char array or String
     * @param from  : CharSet or List<Integer>
     * @param to    : CharSet or List<Integer>
     * @return char array or String
     */
    static char[] translate(char[] chars, CharSet from, CharSet to) {
        return new LpCode(from, to).translate(chars)
    }
    static char[] translate(char[] chars, Collection<Integer> from, CharSet to) {
        return new LpCode(from, to).translate(chars)
    }
    static char[] translate(char[] chars, CharSet from, Collection<Integer> to) {
        return new LpCode(from, to).translate(chars)
    }
    static char[] translate(char[] chars, Collection<Integer> from, Collection<Integer> to) {
        return new LpCode(from, to).translate(chars)
    }
    static String translate(String str, CharSet from, CharSet to) {
        return new LpCode(from, to).translate(str.toCharArray()).toString()
    }
    static String translate(String str, Collection<Integer> from, CharSet to) {
        return new LpCode(from, to).translate(str.toCharArray()).toString()
    }
    static String translate(String str, CharSet from, Collection<Integer> to) {
        return new LpCode(from, to).translate(str.toCharArray()).toString()
    }
    static String translate(String str, Collection<Integer> from, Collection<Integer> to) {
        return new LpCode(from, to).translate(str.toCharArray()).toString()
    }
    /**
     * Translates from one charset to another
     * `Translate` won't encode, it is just a 1 to 1 conversion.
     * For example:  A -> ğŸ…° -> ğŸ…� -> ğŸ„° -> a -> 1
     *
     * NOTE: In the case the target charset uses a out-of-bounds character,
     * it will not translate
     *
     * @param str
     * @return
     */
    char[] translate(char[] str) {
        String res = ""
        List<Integer> cps = getCodePoints(str.toString())
        cps.each {
            int idx = input.getPosition(it)
            if(idx >= 0) {
                if(idx <= output.length) {
                    res += Character.toString(output[idx])
                } else {
                    res += Character.toString(it)
                }
            } else {
                res += Character.toString(it)
            }
        }
        return res.toCharArray()
    }
    /**
     * Encode an array of characters
     * @param str
     * @return
     */
    char[] encode(char[] str) {
        if (seed) {
            str = randomize(str)
        }
        BigInteger num = toNum(str, input)
        return toStr(num, output)
    }
    /**
     * Encode and return block of text instead of single line
     */
    char[] encodeBlock(char[] str) {
        return getBlock(encode(str), blockSize, blockPadding)
    }
    /**
     * Encode an input stream and write it into an output stream
     * @param inputStream : string to encode
     * @param outputStream
     */
    void encode(InputStream inputStream, OutputStream outputStream, Collection<Integer> glue, int chunkCharSize = chunkSize) {
        InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)
        BufferedReader br = new BufferedReader(reader)
        OutputStreamWriter writer = new OutputStreamWriter(outputStream)
        CharBuffer buff = CharBuffer.allocate(chunkSize)
        boolean init = false // flag to know if we already started
        while(br.read(buff) > 0) {
            buff.flip()
            String encoded = encode(buff.chars).toString()
            String sep = init ? glue.collect { Character.toString(it) }.join("") : ""
            writer.write(sep + encoded)
            writer.flush()
            buff.clear()
            init = true
        }
    }
    void encode(InputStream inputStream, OutputStream outputStream, int glue = glueChar, int chunkCharSize = chunkSize) {
        encode(inputStream, outputStream, [glue], chunkCharSize)
    }
    void encode(InputStream inputStream, OutputStream outputStream, String glue, int chunkCharSize = chunkSize) {
        encode(inputStream, outputStream, getCodePoints(glue), chunkCharSize)
    }
    /**
     * Encode splitting the input string in chunks and glue them with some separator
     * This method helps to reduce the memory consumption by trading cpu usage
     * @param str
     * @param glue
     * @param chunkSize
     * @return
     */
    String encodeByChunks(char[] str, Collection<Integer> glue, int chunkCharSize = chunkSize) {
        List<String> buff = []
        glue.each {
            output.chars.removeElement(it) // Remove it from charset if it is included
        }
        (0..str.length - 1).step(chunkCharSize).each {
            int next = it + chunkCharSize
            if(next > str.length - 1) { next = str.length }
            buff << encode(str.toList().subList(it, next).toArray() as char[]).toString()
        }
        return buff.join(codePointsToString(glue))
    }
    String encodeByChunks(char[] str, int glue = glueChar, int chunkCharSize = chunkSize) {
        return encodeByChunks(str, [glue], chunkCharSize)
    }
    String encodeByChunks(char[] str, String glue, int chunkCharSize = chunkSize) {
        return encodeByChunks(str, getCodePoints(glue), chunkCharSize)
    }
    /**
     * Decode an array of characters
     * @param str
     * @return
     */
    char[] decode(char[] str) {
        BigInteger num = toNum(str, output)
        str = toStr(num, input)
        if (seed) {
            str = randomize(str, true)
        }
        return str
    }
    /**
     * Decode a block of text created by encodeBlock()
     */
    char[] decodeBlock(char[] str) {
        return decode(unblock(str, blockPadding))
    }
    /**
     * Decode an input stream and write it into an output stream
     * @param inputStream : encoded string
     * @param outputStream
     */
    void decode(InputStream inputStream, OutputStream outputStream, Collection<Integer> glue) {
        OutputStreamWriter writer = new OutputStreamWriter(outputStream)
        Scanner scanner = new Scanner(inputStream)
        String div = codePointsToString(glue)
        scanner.useDelimiter(Pattern.quote(div))
        while(scanner.hasNext()) {
            String part = scanner.next().replaceAll(div, "")
            String decoded = decode(part.toCharArray()).toString()
            writer.write(decoded)
            writer.flush()
        }
    }
    void decode(InputStream inputStream, OutputStream outputStream, int glue = glueChar) {
        decode(inputStream, outputStream, [glue])
    }
    void decode(InputStream inputStream, OutputStream outputStream, String glue) {
        decode(inputStream, outputStream, getCodePoints(glue))
    }
    /**
     * Decode a string which was previously encoded by "encodeByChunks"
     * @param str
     * @param glue
     * @return
     */
    String decodeByChunks(char[] str, Collection<Integer> glue) {
        List<String> buff = []
        glue.each {
            output.chars.removeElement(it) // Remove it from charset if it is included
        }
        String div = codePointsToString(glue)
        str.toString().tokenize(div).each {
            buff << decode(it.toCharArray()).toString()
        }
        return buff.join("")
    }
    String decodeByChunks(char[] str, int glue = glueChar) {
        return decodeByChunks(str, [glue])
    }
    String decodeByChunks(char[] str, String glue) {
        return decodeByChunks(str, getCodePoints(glue))
    }
    /**
     * Converts an array of characters to a number
     * @param chars
     * @param charset
     * @return
     */
    static protected BigInteger toNum(char[] chars, CharSet charset) {
        String str = chars.toString()
        List<Integer> codePoints = getCodePoints(str)
        int len = codePoints.size()
        BigInteger n = 0
        codePoints.eachWithIndex {
            int cp, int s ->
                int r = charset.getPosition(cp)
                if(r == -1) { // Not found in charset
                    if(warn) {
                        Log.w("Character: [%s](0x%d) not found in charset: [%s ~ %s]", Character.toString(cp), cp, Character.toString(charset.chars.min()), Character.toString(charset.chars.max()))
                    }
                    r = Random.range(0, charset.length - 1) //Replace by a random character
                }
                //noinspection GrReassignedInClosureLocalVar
                n = (s == len - 1) ? n + (r + 1) : (n + (r + 1)) * (charset.length)
        }
        return n
    }

    /**
     * Get all codePoints in String
     * @param str
     * @return
     */
    static List<Integer> getCodePoints(String str) {
        List<Integer> list = []
        for (int offset = 0, s = 0; offset < str.length(); s++) {
            int cp = str.codePointAt(offset)
            list << cp
            offset += Character.charCount(cp)
        }
        return list
    }
    /**
     * Get the codePoint of a single character
     * @param str
     * @return
     */
    static Integer getCodePoint(String str) {
        return getCodePoints(str).first()
    }
    /**
     * Converts a number into an array of characters
     * @param num
     * @param charset
     * @return
     */
    static protected char[] toStr(BigInteger num, CharSet charset) {
        LinkedList<Character> anum = new LinkedList<>()
        while (num-- >= 1) {
            int c = charset.chars[(num % (charset.length)) as int]
            Character.toChars(c).toList().reverse().each {
                anum.addFirst(it)
            }
            num = num.divide((charset.length) as BigInteger)
        }
        return anum.toArray() as char[]
    }
    /**
     * Randomize a char array (keeping each character)
     * @param str
     * @param reverse
     * @return
     */
    char[] randomize(char[] chars, boolean reverse = false) {
        String str = chars.toString()
        Random random = new Random(seed)
        List<Integer> cps = getCodePoints(str)
        List<Integer> pos = (0..(cps.size() - 1)).toList()
        pos.shuffle(random)
        List<String> out = []
        pos.withIndex().each {
            int p, int i ->
                if(reverse) {
                    out[p] = Character.toString(cps[i])
                } else {
                    out[i] = Character.toString(cps[p])
                }
        }
        return out.join("").toCharArray()
    }
    /**
     * Get the list of all defined charsets
     * @return
     */
    static Map<String, CharSet> getCharsets() {
        Map charsets = [:] as Map<String, CharSet>
        try {
            LpCode.declaredFields.each {
                if (Modifier.isStatic(it.modifiers) && Modifier.isPublic(it.modifiers)) {
                    List<Integer> list = it.get(null) as List<Integer>
                    if (list.size() > 2 || it.name == "BIN") {
                        charsets[it.name] = new CharSet(list)
                    }
                }
            }
        } catch (Exception ignore) {
        }
        return charsets
    }
    /**
     * Convert codePoints to String
     * @param codes
     * @return
     */
    static String codePointsToString(Collection<Integer> codes) {
        return codes.collect { Character.toString(it) }.join("")
    }

    /**
     * Convert a string into a lines
     * @param input
     * @param blockSize
     * @param padding
     * @return
     */
    static List<String> split(char[] input, int blockSize, String padding) {
        //noinspection RegExpSimplifiable
        return input.toString().split("(?<=\\G.{${blockSize}})").collect { it.padRight(blockSize, padding)}
    }

    /**
     * Split a string (usually the output of 'encode') and return it as block of text
     * @param input
     * @param blockSize
     * @param padding
     * @return
     */
    static char[] getBlock(char[] input, int blockSize, String padding = "") {
        return split(input, blockSize, padding).join(SysInfo.newLine).toCharArray()
    }

    /**
     * Return a block of text as a single line, removing any padding
     * @param input
     * @param padding
     * @return
     */
    static char[] unblock(char[] input, String padding = "") {
        return input.toString().replaceAll(padding, "").replaceAll(SysInfo.newLine, "").toCharArray()
    }
}
