diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 167acc1583..311e9f85b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,6 +45,10 @@ See [Debugging](./docs/debugging.md). If you want to develop on the web assembly side you can run `yarn serve` and then go to . +### boa-unicode + +Boa uses the library `boa-unicode` to query Unicode character properties and classes in lexer and parser. See [boa_unicode/README.md](./boa_unicode/README.md) for development and more information. + ### Setup #### VSCode Plugins diff --git a/Cargo.lock b/Cargo.lock index 53821b6842..2877daf5c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ name = "Boa" version = "0.10.0" dependencies = [ "bitflags", + "boa_unicode", "chrono", "criterion", "float-cmp", @@ -108,6 +109,13 @@ dependencies = [ "structopt", ] +[[package]] +name = "boa_unicode" +version = "0.10.0" +dependencies = [ + "unicode-general-category", +] + [[package]] name = "boa_wasm" version = "0.10.0" @@ -1263,6 +1271,12 @@ dependencies = [ "matches", ] +[[package]] +name = "unicode-general-category" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1e2c61f9441613aca1a1c88803bb36df292990aada6abb5133b9b532e07ec" + [[package]] name = "unicode-normalization" version = "0.1.16" diff --git a/Cargo.toml b/Cargo.toml index fc0a914b72..6dbd3e939c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "boa_cli", "boa_wasm", "boa_tester", + "boa_unicode", ] # The release profile, used for `cargo build --release`. diff --git a/boa/Cargo.toml b/boa/Cargo.toml index 6c75cad5c3..2fa7d0bc8c 100644 --- a/boa/Cargo.toml +++ b/boa/Cargo.toml @@ -21,6 +21,7 @@ vm = [] console = [] [dependencies] +boa_unicode = { path = "../boa_unicode" } gc = { version = "0.3.6", features = ["derive"] } serde = { version = "1.0.118", features = ["derive"] } serde_json = "1.0.61" diff --git a/boa/src/syntax/lexer/identifier.rs b/boa/src/syntax/lexer/identifier.rs index b8d35eecee..937bafa5a6 100644 --- a/boa/src/syntax/lexer/identifier.rs +++ b/boa/src/syntax/lexer/identifier.rs @@ -8,6 +8,7 @@ use crate::{ lexer::{Token, TokenKind}, }, }; +use boa_unicode::UnicodeProperties; use core::convert::TryFrom; use std::io::Read; use std::str; @@ -44,6 +45,38 @@ impl Identifier { pub(super) fn new(init: char) -> Self { Self { init } } + + /// Checks if a character is IdentifierStart as per ECMAScript standards. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-names-and-keywords + pub(super) fn is_identifier_start(ch: u32) -> bool { + matches!(ch, 0x0024 /* $ */ | 0x005F /* _ */) + || if let Ok(ch) = char::try_from(ch) { + ch.is_id_start() + } else { + false + } + } + + /// Checks if a character is IdentifierPart as per ECMAScript standards. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-names-and-keywords + fn is_identifier_part(ch: u32) -> bool { + matches!( + ch, + 0x0024 /* $ */ | 0x005F /* _ */ | 0x200C /* */ | 0x200D /* */ + ) || if let Ok(ch) = char::try_from(ch) { + ch.is_id_continue() + } else { + false + } + } } impl Tokenizer for Identifier { @@ -58,13 +91,7 @@ impl Tokenizer for Identifier { self.init.encode_utf8(&mut init_buf); buf.extend(init_buf.iter().take(self.init.len_utf8())); - cursor.take_while_char_pred(&mut buf, &|c: u32| { - if let Ok(c) = char::try_from(c) { - c.is_alphabetic() || c.is_digit(10) || c == '_' - } else { - false - } - })?; + cursor.take_while_char_pred(&mut buf, &Self::is_identifier_part)?; let token_str = unsafe { str::from_utf8_unchecked(buf.as_slice()) }; let tk = match token_str { diff --git a/boa/src/syntax/lexer/mod.rs b/boa/src/syntax/lexer/mod.rs index cff616fe4b..cb7b6366d4 100644 --- a/boa/src/syntax/lexer/mod.rs +++ b/boa/src/syntax/lexer/mod.rs @@ -199,12 +199,6 @@ impl Lexer { )), '"' | '\'' => StringLiteral::new(c).lex(&mut self.cursor, start), '`' => TemplateLiteral.lex(&mut self.cursor, start), - _ if c.is_digit(10) => { - NumberLiteral::new(next_ch as u8).lex(&mut self.cursor, start) - } - _ if c.is_alphabetic() || c == '$' || c == '_' => { - Identifier::new(c).lex(&mut self.cursor, start) - } ';' => Ok(Token::new( Punctuator::Semicolon.into(), Span::new(start, self.cursor.pos()), @@ -252,6 +246,12 @@ impl Lexer { '=' | '*' | '+' | '-' | '%' | '|' | '&' | '^' | '<' | '>' | '!' | '~' | '?' => { Operator::new(next_ch as u8).lex(&mut self.cursor, start) } + _ if c.is_digit(10) => { + NumberLiteral::new(next_ch as u8).lex(&mut self.cursor, start) + } + _ if Identifier::is_identifier_start(c as u32) => { + Identifier::new(c).lex(&mut self.cursor, start) + } _ => { let details = format!( "unexpected '{}' at line {}, column {}", diff --git a/boa/src/syntax/lexer/tests.rs b/boa/src/syntax/lexer/tests.rs index d392621db1..230ab1847f 100644 --- a/boa/src/syntax/lexer/tests.rs +++ b/boa/src/syntax/lexer/tests.rs @@ -70,6 +70,52 @@ fn check_multi_line_comment() { expect_tokens(&mut lexer, &expected); } +#[test] +fn check_identifier() { + let s = "x x1 _x $x __ $$ Ѐ ЀЀ x\u{200C}\u{200D}"; + let mut lexer = Lexer::new(s.as_bytes()); + + let expected = [ + TokenKind::identifier("x"), + TokenKind::identifier("x1"), + TokenKind::identifier("_x"), + TokenKind::identifier("$x"), + TokenKind::identifier("__"), + TokenKind::identifier("$$"), + TokenKind::identifier("Ѐ"), + TokenKind::identifier("ЀЀ"), + TokenKind::identifier("x\u{200C}\u{200D}"), + ]; + + expect_tokens(&mut lexer, &expected); +} + +#[test] +fn check_invalid_identifier_start() { + let invalid_identifier_starts = ["\u{200C}", "\u{200D}", "😀"]; + + for s in invalid_identifier_starts.iter() { + let mut lexer = Lexer::new(s.as_bytes()); + lexer + .next() + .expect_err("Invalid identifier start not rejected as expected"); + } +} + +#[test] +fn check_invalid_identifier_part() { + let invalid_identifier_parts = [" ", "\n", ".", "*", "😀", "\u{007F}"]; + + for part in invalid_identifier_parts.iter() { + let s = String::from("x") + part; + let mut lexer = Lexer::new(s.as_bytes()); + assert_eq!( + lexer.next().unwrap().unwrap().kind(), + &TokenKind::identifier("x") + ); + } +} + #[test] fn check_string() { let s = "'aaa' \"bbb\""; diff --git a/boa_unicode/Cargo.toml b/boa_unicode/Cargo.toml new file mode 100644 index 0000000000..73d48516ed --- /dev/null +++ b/boa_unicode/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "boa_unicode" +version = "0.10.0" +authors = ["boa-dev"] +description = "Boa is a Javascript lexer, parser and Just-in-Time compiler written in Rust. Currently, it has support for some of the language." +repository = "https://github.com/boa-dev/boa" +keywords = ["javascript", "compiler", "lexer", "parser", "unicode"] +categories = ["parsing"] +license = "Unlicense/MIT" +exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"] +edition = "2018" + +[dependencies] +unicode-general-category = "0.3.0" diff --git a/boa_unicode/README.md b/boa_unicode/README.md new file mode 100644 index 0000000000..62b5e8d5b5 --- /dev/null +++ b/boa_unicode/README.md @@ -0,0 +1,26 @@ +# boa-unicode + +`boa-unicode` defines the trait to provide methods for querying properties or classes for Unicode identifiers. These properties are used to determine if a code point (char) is valid for being the start/part of an identifier in lexer and parser. + +Current version: Unicode 13.0.0 + +## Development + +The Unicode character tables used to query properties are generated by `build_tables.js`. This script depends on [Node.js](https://nodejs.org/en/) and [rustfmt](https://github.com/rust-lang/rustfmt). You can run the script with: + +``` +$ node build_tables.js +``` + +or with [npm](https://www.npmjs.com/): + +``` +$ npm run build-tables +``` + +The configurations are defined as constants in the script. Please check the comments in `build_tables.js` for more information. + +## More Info + +- [Unicode® Standard Annex #31 - UNICODE IDENTIFIER AND PATTERN SYNTAX](https://unicode.org/reports/tr31/) +- [Unicode® Standard Annex #44 - UNICODE CHARACTER DATABASE](https://unicode.org/reports/tr44/) diff --git a/boa_unicode/build_tables.js b/boa_unicode/build_tables.js new file mode 100644 index 0000000000..629c01028e --- /dev/null +++ b/boa_unicode/build_tables.js @@ -0,0 +1,132 @@ +#!/usr/bin/env node +/** + * This file is used to generate the Rust source code with tables for Unicode properties and classes. + * + * This script downloads the content of `PropList.txt` from the remote server, parses the file, extracts + * the target properties, prepares the char tables, and then writes to the output Rust file. It also + * formats the output file with the command `rustfmt`. Please make sure `rustfmt` is available in the environment. + * + * Update and run this script when {@link https://unicode.org/reports/tr44/|Unicode® Standard Annex #44} is updated, and + * always check the latest standard meets the {@link https://tc39.es/ecma262/#sec-names-and-keywords|spec of ECMAScript}. + * + * Run this script with command `node ./build_tables.js` or `npm run build-tables`. + * + * Version: Unicode 13.0.0 + */ + +const fs = require("fs"); +const path = require("path"); +const https = require("https"); +const child_process = require("child_process"); + +/** + * The URL to download the content of `PropList.txt` through HTTP Get. + * + * Please make sure the content follows the UCD file format defined in + * {@link http://unicode.org/reports/tr44/#UCD_Files|UAX#44}. + * + * @constant {string} + */ +const PROPLIST_TXT_URL = + "https://www.unicode.org/Public/13.0.0/ucd/PropList.txt"; + +/** + * The target properties to process given in tuples. The first element is the property to search for. + * The second element is the table variable name in the output Rust file. + * + * @constant {[string, string][]} + */ +const TARGET_PROPERTIES = [ + ["Pattern_Syntax", "PATTERN_SYNTAX"], + ["Other_ID_Continue", "OTHER_ID_CONTINUE"], + ["Other_ID_Start", "OTHER_ID_START"], + ["Pattern_White_Space", "PATTERN_WHITE_SPACE"], +]; + +/** + * The path of output Rust file. + * + * @constant {string} + */ +const OUTPUT_FILE = path.join(__dirname, "./src/tables.rs"); + +/** + * The doc comment to add to the beginning of output Rust file. + * + * @constant {string} + */ +const OUTPUT_FILE_DOC_COMMENT = ` +//! This module implements the unicode lookup tables for identifier and pattern syntax. +//! Version: Unicode 13.0.0 +//! +//! This file is generated by \`boa_unicode/build_tables.js\`. Please do not modify it directly. +//! +//! More information: +//! - [Unicode® Standard Annex #44][uax44] +//! +//! [uax44]: http://unicode.org/reports/tr44 +`.trim(); + +https + .get(PROPLIST_TXT_URL, (res) => { + let text = ""; + + res.on("data", (chunk) => { + text += chunk; + }); + + res.on("end", () => { + buildRustFile(text); + }); + }) + .on("error", (err) => { + console.log(`Failed to get 'PropList.txt': ${err.message}`); + }) + .end(); + +function buildRustFile(propListText) { + const dataRegex = /(^|\n)(?[0-9A-F]+)(\.\.(?[0-9A-F]+))?\s*;\s*(?[^\s]+)/gi; + const data = [...propListText.matchAll(dataRegex)].map( + (match) => match.groups + ); + + const rustVariables = TARGET_PROPERTIES.map( + ([propertyName, rustTableName]) => { + const codePoints = data + .filter(({ property }) => property === propertyName) + .map(({ codePointStart, codePointEnd }) => [ + codePointStart, + codePointEnd ?? codePointStart, + ]) + .map(([codePointStart, codePointEnd]) => [ + parseInt(codePointStart, 16), + parseInt(codePointEnd, 16), + ]) + .reduce((codePoints, [codePointStart, codePointEnd]) => { + for (let cp = codePointStart; cp <= codePointEnd; cp++) { + codePoints.push(cp); + } + return codePoints; + }, []); + + codePoints.sort((a, b) => a - b); + const rustTable = `&[${codePoints + .map((cp) => `'\\u{${cp.toString(16).padStart(4, "0").toUpperCase()}}'`) + .join(",")}]`; + const rustVariable = `pub static ${rustTableName}: &[char] = ${rustTable};`; + + console.log(`${propertyName}: ${codePoints.length} code points`); + return rustVariable; + } + ); + + const rustFile = `${OUTPUT_FILE_DOC_COMMENT}\n\n${rustVariables.join( + "\n\n" + )}`; + + console.log("Writing output file..."); + fs.writeFileSync(OUTPUT_FILE, rustFile); + + console.log("Running rustfmt..."); + child_process.execSync(`rustfmt ${OUTPUT_FILE}`); +} diff --git a/boa_unicode/package.json b/boa_unicode/package.json new file mode 100644 index 0000000000..1b0d8859ed --- /dev/null +++ b/boa_unicode/package.json @@ -0,0 +1,5 @@ +{ + "scripts": { + "build-tables": "node ./build_tables.js" + } +} diff --git a/boa_unicode/src/lib.rs b/boa_unicode/src/lib.rs new file mode 100644 index 0000000000..340ac855de --- /dev/null +++ b/boa_unicode/src/lib.rs @@ -0,0 +1,100 @@ +//! This library implements the extension to query if a char belongs to a particular unicode identifier property. +//! Version: Unicode 13.0.0 +//! +//! More information: +//! - [Unicode® Standard Annex #31][uax31] +//! +//! [uax31]: http://unicode.org/reports/tr31 + +mod tables; +#[cfg(test)] +mod tests; + +use unicode_general_category::{get_general_category, GeneralCategory}; + +/// The version of Unicode. +pub const UNICODE_VERSION: (u64, u64, u64) = (13, 0, 0); + +/// Extend a type of code point to query if a value belongs to a particular Unicode property. +/// +/// This trait defines methods for querying properties and classes mentioned or defined in Unicode® Standard Annex #31. +/// These properties are used to determine if a code point (char) is valid for being the start/part of an identifier and assist in +/// the standard treatment of Unicode identifiers in parsers and lexers. +/// +/// More information: +/// - [Unicode® Standard Annex #31][uax31] +/// +/// [uax31]: http://unicode.org/reports/tr31 +pub trait UnicodeProperties: Sized + Copy { + /// Returns `true` if this value is a member of "ID_Start". + fn is_id_start(self) -> bool; + + /// Returns `true` if this value is a member of "ID_Continue". + fn is_id_continue(self) -> bool; + + /// Returns `true` if this value is a member of "Other_ID_Start". + fn is_other_id_start(self) -> bool; + + /// Returns `true` if this value is a member of "Other_ID_Continue". + fn is_other_id_continue(self) -> bool; + + /// Returns `true` if this value is a member of "Pattern_Syntax". + fn is_pattern_syntax(self) -> bool; + + /// Returns `true` if this value is a member of "Pattern_White_Space". + fn is_pattern_whitespace(self) -> bool; +} + +fn table_binary_search(target: char, table: &'static [char]) -> bool { + table.binary_search(&target).is_ok() +} + +impl UnicodeProperties for char { + #[inline] + fn is_id_start(self) -> bool { + !self.is_pattern_syntax() + && !self.is_pattern_whitespace() + && (self.is_other_id_start() + || matches!( + get_general_category(self), + GeneralCategory::LowercaseLetter + | GeneralCategory::ModifierLetter + | GeneralCategory::OtherLetter + | GeneralCategory::TitlecaseLetter + | GeneralCategory::UppercaseLetter + | GeneralCategory::LetterNumber + )) + } + + #[inline] + fn is_id_continue(self) -> bool { + !self.is_pattern_syntax() + && !self.is_pattern_whitespace() + && (self.is_id_start() + || self.is_other_id_continue() + || matches!( + get_general_category(self), + GeneralCategory::NonspacingMark + | GeneralCategory::SpacingMark + | GeneralCategory::DecimalNumber + | GeneralCategory::ConnectorPunctuation + )) + } + + #[inline] + fn is_other_id_start(self) -> bool { + table_binary_search(self, tables::OTHER_ID_START) + } + #[inline] + fn is_other_id_continue(self) -> bool { + table_binary_search(self, tables::OTHER_ID_CONTINUE) + } + #[inline] + fn is_pattern_syntax(self) -> bool { + table_binary_search(self, tables::PATTERN_SYNTAX) + } + #[inline] + fn is_pattern_whitespace(self) -> bool { + table_binary_search(self, tables::PATTERN_WHITE_SPACE) + } +} diff --git a/boa_unicode/src/tables.rs b/boa_unicode/src/tables.rs new file mode 100644 index 0000000000..0ec6ae0747 --- /dev/null +++ b/boa_unicode/src/tables.rs @@ -0,0 +1,371 @@ +//! This module implements the unicode lookup tables for identifier and pattern syntax. +//! Version: Unicode 13.0.0 +//! +//! This file is generated by `boa_unicode/build_tables.js`. Please do not modify it directly. +//! +//! More information: +//! - [Unicode® Standard Annex #44][uax44] +//! +//! [uax44]: http://unicode.org/reports/tr44 + +pub static PATTERN_SYNTAX: &[char] = &[ + '\u{0021}', '\u{0022}', '\u{0023}', '\u{0024}', '\u{0025}', '\u{0026}', '\u{0027}', '\u{0028}', + '\u{0029}', '\u{002A}', '\u{002B}', '\u{002C}', '\u{002D}', '\u{002E}', '\u{002F}', '\u{003A}', + '\u{003B}', '\u{003C}', '\u{003D}', '\u{003E}', '\u{003F}', '\u{0040}', '\u{005B}', '\u{005C}', + '\u{005D}', '\u{005E}', '\u{0060}', '\u{007B}', '\u{007C}', '\u{007D}', '\u{007E}', '\u{00A1}', + '\u{00A2}', '\u{00A3}', '\u{00A4}', '\u{00A5}', '\u{00A6}', '\u{00A7}', '\u{00A9}', '\u{00AB}', + '\u{00AC}', '\u{00AE}', '\u{00B0}', '\u{00B1}', '\u{00B6}', '\u{00BB}', '\u{00BF}', '\u{00D7}', + '\u{00F7}', '\u{2010}', '\u{2011}', '\u{2012}', '\u{2013}', '\u{2014}', '\u{2015}', '\u{2016}', + '\u{2017}', '\u{2018}', '\u{2019}', '\u{201A}', '\u{201B}', '\u{201C}', '\u{201D}', '\u{201E}', + '\u{201F}', '\u{2020}', '\u{2021}', '\u{2022}', '\u{2023}', '\u{2024}', '\u{2025}', '\u{2026}', + '\u{2027}', '\u{2030}', '\u{2031}', '\u{2032}', '\u{2033}', '\u{2034}', '\u{2035}', '\u{2036}', + '\u{2037}', '\u{2038}', '\u{2039}', '\u{203A}', '\u{203B}', '\u{203C}', '\u{203D}', '\u{203E}', + '\u{2041}', '\u{2042}', '\u{2043}', '\u{2044}', '\u{2045}', '\u{2046}', '\u{2047}', '\u{2048}', + '\u{2049}', '\u{204A}', '\u{204B}', '\u{204C}', '\u{204D}', '\u{204E}', '\u{204F}', '\u{2050}', + '\u{2051}', '\u{2052}', '\u{2053}', '\u{2055}', '\u{2056}', '\u{2057}', '\u{2058}', '\u{2059}', + '\u{205A}', '\u{205B}', '\u{205C}', '\u{205D}', '\u{205E}', '\u{2190}', '\u{2191}', '\u{2192}', + '\u{2193}', '\u{2194}', '\u{2195}', '\u{2196}', '\u{2197}', '\u{2198}', '\u{2199}', '\u{219A}', + '\u{219B}', '\u{219C}', '\u{219D}', '\u{219E}', '\u{219F}', '\u{21A0}', '\u{21A1}', '\u{21A2}', + '\u{21A3}', '\u{21A4}', '\u{21A5}', '\u{21A6}', '\u{21A7}', '\u{21A8}', '\u{21A9}', '\u{21AA}', + '\u{21AB}', '\u{21AC}', '\u{21AD}', '\u{21AE}', '\u{21AF}', '\u{21B0}', '\u{21B1}', '\u{21B2}', + '\u{21B3}', '\u{21B4}', '\u{21B5}', '\u{21B6}', '\u{21B7}', '\u{21B8}', '\u{21B9}', '\u{21BA}', + '\u{21BB}', '\u{21BC}', '\u{21BD}', '\u{21BE}', '\u{21BF}', '\u{21C0}', '\u{21C1}', '\u{21C2}', + '\u{21C3}', '\u{21C4}', '\u{21C5}', '\u{21C6}', '\u{21C7}', '\u{21C8}', '\u{21C9}', '\u{21CA}', + '\u{21CB}', '\u{21CC}', '\u{21CD}', '\u{21CE}', '\u{21CF}', '\u{21D0}', '\u{21D1}', '\u{21D2}', + '\u{21D3}', '\u{21D4}', '\u{21D5}', '\u{21D6}', '\u{21D7}', '\u{21D8}', '\u{21D9}', '\u{21DA}', + '\u{21DB}', '\u{21DC}', '\u{21DD}', '\u{21DE}', '\u{21DF}', '\u{21E0}', '\u{21E1}', '\u{21E2}', + '\u{21E3}', '\u{21E4}', '\u{21E5}', '\u{21E6}', '\u{21E7}', '\u{21E8}', '\u{21E9}', '\u{21EA}', + '\u{21EB}', '\u{21EC}', '\u{21ED}', '\u{21EE}', '\u{21EF}', '\u{21F0}', '\u{21F1}', '\u{21F2}', + '\u{21F3}', '\u{21F4}', '\u{21F5}', '\u{21F6}', '\u{21F7}', '\u{21F8}', '\u{21F9}', '\u{21FA}', + '\u{21FB}', '\u{21FC}', '\u{21FD}', '\u{21FE}', '\u{21FF}', '\u{2200}', '\u{2201}', '\u{2202}', + '\u{2203}', '\u{2204}', '\u{2205}', '\u{2206}', '\u{2207}', '\u{2208}', '\u{2209}', '\u{220A}', + '\u{220B}', '\u{220C}', '\u{220D}', '\u{220E}', '\u{220F}', '\u{2210}', '\u{2211}', '\u{2212}', + '\u{2213}', '\u{2214}', '\u{2215}', '\u{2216}', '\u{2217}', '\u{2218}', '\u{2219}', '\u{221A}', + '\u{221B}', '\u{221C}', '\u{221D}', '\u{221E}', '\u{221F}', '\u{2220}', '\u{2221}', '\u{2222}', + '\u{2223}', '\u{2224}', '\u{2225}', '\u{2226}', '\u{2227}', '\u{2228}', '\u{2229}', '\u{222A}', + '\u{222B}', '\u{222C}', '\u{222D}', '\u{222E}', '\u{222F}', '\u{2230}', '\u{2231}', '\u{2232}', + '\u{2233}', '\u{2234}', '\u{2235}', '\u{2236}', '\u{2237}', '\u{2238}', '\u{2239}', '\u{223A}', + '\u{223B}', '\u{223C}', '\u{223D}', '\u{223E}', '\u{223F}', '\u{2240}', '\u{2241}', '\u{2242}', + '\u{2243}', '\u{2244}', '\u{2245}', '\u{2246}', '\u{2247}', '\u{2248}', '\u{2249}', '\u{224A}', + '\u{224B}', '\u{224C}', '\u{224D}', '\u{224E}', '\u{224F}', '\u{2250}', '\u{2251}', '\u{2252}', + '\u{2253}', '\u{2254}', '\u{2255}', '\u{2256}', '\u{2257}', '\u{2258}', '\u{2259}', '\u{225A}', + '\u{225B}', '\u{225C}', '\u{225D}', '\u{225E}', '\u{225F}', '\u{2260}', '\u{2261}', '\u{2262}', + '\u{2263}', '\u{2264}', '\u{2265}', '\u{2266}', '\u{2267}', '\u{2268}', '\u{2269}', '\u{226A}', + '\u{226B}', '\u{226C}', '\u{226D}', '\u{226E}', '\u{226F}', '\u{2270}', '\u{2271}', '\u{2272}', + '\u{2273}', '\u{2274}', '\u{2275}', '\u{2276}', '\u{2277}', '\u{2278}', '\u{2279}', '\u{227A}', + '\u{227B}', '\u{227C}', '\u{227D}', '\u{227E}', '\u{227F}', '\u{2280}', '\u{2281}', '\u{2282}', + '\u{2283}', '\u{2284}', '\u{2285}', '\u{2286}', '\u{2287}', '\u{2288}', '\u{2289}', '\u{228A}', + '\u{228B}', '\u{228C}', '\u{228D}', '\u{228E}', '\u{228F}', '\u{2290}', '\u{2291}', '\u{2292}', + '\u{2293}', '\u{2294}', '\u{2295}', '\u{2296}', '\u{2297}', '\u{2298}', '\u{2299}', '\u{229A}', + '\u{229B}', '\u{229C}', '\u{229D}', '\u{229E}', '\u{229F}', '\u{22A0}', '\u{22A1}', '\u{22A2}', + '\u{22A3}', '\u{22A4}', '\u{22A5}', '\u{22A6}', '\u{22A7}', '\u{22A8}', '\u{22A9}', '\u{22AA}', + '\u{22AB}', '\u{22AC}', '\u{22AD}', '\u{22AE}', '\u{22AF}', '\u{22B0}', '\u{22B1}', '\u{22B2}', + '\u{22B3}', '\u{22B4}', '\u{22B5}', '\u{22B6}', '\u{22B7}', '\u{22B8}', '\u{22B9}', '\u{22BA}', + '\u{22BB}', '\u{22BC}', '\u{22BD}', '\u{22BE}', '\u{22BF}', '\u{22C0}', '\u{22C1}', '\u{22C2}', + '\u{22C3}', '\u{22C4}', '\u{22C5}', '\u{22C6}', '\u{22C7}', '\u{22C8}', '\u{22C9}', '\u{22CA}', + '\u{22CB}', '\u{22CC}', '\u{22CD}', '\u{22CE}', '\u{22CF}', '\u{22D0}', '\u{22D1}', '\u{22D2}', + '\u{22D3}', '\u{22D4}', '\u{22D5}', '\u{22D6}', '\u{22D7}', '\u{22D8}', '\u{22D9}', '\u{22DA}', + '\u{22DB}', '\u{22DC}', '\u{22DD}', '\u{22DE}', '\u{22DF}', '\u{22E0}', '\u{22E1}', '\u{22E2}', + '\u{22E3}', '\u{22E4}', '\u{22E5}', '\u{22E6}', '\u{22E7}', '\u{22E8}', '\u{22E9}', '\u{22EA}', + '\u{22EB}', '\u{22EC}', '\u{22ED}', '\u{22EE}', '\u{22EF}', '\u{22F0}', '\u{22F1}', '\u{22F2}', + '\u{22F3}', '\u{22F4}', '\u{22F5}', '\u{22F6}', '\u{22F7}', '\u{22F8}', '\u{22F9}', '\u{22FA}', + '\u{22FB}', '\u{22FC}', '\u{22FD}', '\u{22FE}', '\u{22FF}', '\u{2300}', '\u{2301}', '\u{2302}', + '\u{2303}', '\u{2304}', '\u{2305}', '\u{2306}', '\u{2307}', '\u{2308}', '\u{2309}', '\u{230A}', + '\u{230B}', '\u{230C}', '\u{230D}', '\u{230E}', '\u{230F}', '\u{2310}', '\u{2311}', '\u{2312}', + '\u{2313}', '\u{2314}', '\u{2315}', '\u{2316}', '\u{2317}', '\u{2318}', '\u{2319}', '\u{231A}', + '\u{231B}', '\u{231C}', '\u{231D}', '\u{231E}', '\u{231F}', '\u{2320}', '\u{2321}', '\u{2322}', + '\u{2323}', '\u{2324}', '\u{2325}', '\u{2326}', '\u{2327}', '\u{2328}', '\u{2329}', '\u{232A}', + '\u{232B}', '\u{232C}', '\u{232D}', '\u{232E}', '\u{232F}', '\u{2330}', '\u{2331}', '\u{2332}', + '\u{2333}', '\u{2334}', '\u{2335}', '\u{2336}', '\u{2337}', '\u{2338}', '\u{2339}', '\u{233A}', + '\u{233B}', '\u{233C}', '\u{233D}', '\u{233E}', '\u{233F}', '\u{2340}', '\u{2341}', '\u{2342}', + '\u{2343}', '\u{2344}', '\u{2345}', '\u{2346}', '\u{2347}', '\u{2348}', '\u{2349}', '\u{234A}', + '\u{234B}', '\u{234C}', '\u{234D}', '\u{234E}', '\u{234F}', '\u{2350}', '\u{2351}', '\u{2352}', + '\u{2353}', '\u{2354}', '\u{2355}', '\u{2356}', '\u{2357}', '\u{2358}', '\u{2359}', '\u{235A}', + '\u{235B}', '\u{235C}', '\u{235D}', '\u{235E}', '\u{235F}', '\u{2360}', '\u{2361}', '\u{2362}', + '\u{2363}', '\u{2364}', '\u{2365}', '\u{2366}', '\u{2367}', '\u{2368}', '\u{2369}', '\u{236A}', + '\u{236B}', '\u{236C}', '\u{236D}', '\u{236E}', '\u{236F}', '\u{2370}', '\u{2371}', '\u{2372}', + '\u{2373}', '\u{2374}', '\u{2375}', '\u{2376}', '\u{2377}', '\u{2378}', '\u{2379}', '\u{237A}', + '\u{237B}', '\u{237C}', '\u{237D}', '\u{237E}', '\u{237F}', '\u{2380}', '\u{2381}', '\u{2382}', + '\u{2383}', '\u{2384}', '\u{2385}', '\u{2386}', '\u{2387}', '\u{2388}', '\u{2389}', '\u{238A}', + '\u{238B}', '\u{238C}', '\u{238D}', '\u{238E}', '\u{238F}', '\u{2390}', '\u{2391}', '\u{2392}', + '\u{2393}', '\u{2394}', '\u{2395}', '\u{2396}', '\u{2397}', '\u{2398}', '\u{2399}', '\u{239A}', + '\u{239B}', '\u{239C}', '\u{239D}', '\u{239E}', '\u{239F}', '\u{23A0}', '\u{23A1}', '\u{23A2}', + '\u{23A3}', '\u{23A4}', '\u{23A5}', '\u{23A6}', '\u{23A7}', '\u{23A8}', '\u{23A9}', '\u{23AA}', + '\u{23AB}', '\u{23AC}', '\u{23AD}', '\u{23AE}', '\u{23AF}', '\u{23B0}', '\u{23B1}', '\u{23B2}', + '\u{23B3}', '\u{23B4}', '\u{23B5}', '\u{23B6}', '\u{23B7}', '\u{23B8}', '\u{23B9}', '\u{23BA}', + '\u{23BB}', '\u{23BC}', '\u{23BD}', '\u{23BE}', '\u{23BF}', '\u{23C0}', '\u{23C1}', '\u{23C2}', + '\u{23C3}', '\u{23C4}', '\u{23C5}', '\u{23C6}', '\u{23C7}', '\u{23C8}', '\u{23C9}', '\u{23CA}', + '\u{23CB}', '\u{23CC}', '\u{23CD}', '\u{23CE}', '\u{23CF}', '\u{23D0}', '\u{23D1}', '\u{23D2}', + '\u{23D3}', '\u{23D4}', '\u{23D5}', '\u{23D6}', '\u{23D7}', '\u{23D8}', '\u{23D9}', '\u{23DA}', + '\u{23DB}', '\u{23DC}', '\u{23DD}', '\u{23DE}', '\u{23DF}', '\u{23E0}', '\u{23E1}', '\u{23E2}', + '\u{23E3}', '\u{23E4}', '\u{23E5}', '\u{23E6}', '\u{23E7}', '\u{23E8}', '\u{23E9}', '\u{23EA}', + '\u{23EB}', '\u{23EC}', '\u{23ED}', '\u{23EE}', '\u{23EF}', '\u{23F0}', '\u{23F1}', '\u{23F2}', + '\u{23F3}', '\u{23F4}', '\u{23F5}', '\u{23F6}', '\u{23F7}', '\u{23F8}', '\u{23F9}', '\u{23FA}', + '\u{23FB}', '\u{23FC}', '\u{23FD}', '\u{23FE}', '\u{23FF}', '\u{2400}', '\u{2401}', '\u{2402}', + '\u{2403}', '\u{2404}', '\u{2405}', '\u{2406}', '\u{2407}', '\u{2408}', '\u{2409}', '\u{240A}', + '\u{240B}', '\u{240C}', '\u{240D}', '\u{240E}', '\u{240F}', '\u{2410}', '\u{2411}', '\u{2412}', + '\u{2413}', '\u{2414}', '\u{2415}', '\u{2416}', '\u{2417}', '\u{2418}', '\u{2419}', '\u{241A}', + '\u{241B}', '\u{241C}', '\u{241D}', '\u{241E}', '\u{241F}', '\u{2420}', '\u{2421}', '\u{2422}', + '\u{2423}', '\u{2424}', '\u{2425}', '\u{2426}', '\u{2427}', '\u{2428}', '\u{2429}', '\u{242A}', + '\u{242B}', '\u{242C}', '\u{242D}', '\u{242E}', '\u{242F}', '\u{2430}', '\u{2431}', '\u{2432}', + '\u{2433}', '\u{2434}', '\u{2435}', '\u{2436}', '\u{2437}', '\u{2438}', '\u{2439}', '\u{243A}', + '\u{243B}', '\u{243C}', '\u{243D}', '\u{243E}', '\u{243F}', '\u{2440}', '\u{2441}', '\u{2442}', + '\u{2443}', '\u{2444}', '\u{2445}', '\u{2446}', '\u{2447}', '\u{2448}', '\u{2449}', '\u{244A}', + '\u{244B}', '\u{244C}', '\u{244D}', '\u{244E}', '\u{244F}', '\u{2450}', '\u{2451}', '\u{2452}', + '\u{2453}', '\u{2454}', '\u{2455}', '\u{2456}', '\u{2457}', '\u{2458}', '\u{2459}', '\u{245A}', + '\u{245B}', '\u{245C}', '\u{245D}', '\u{245E}', '\u{245F}', '\u{2500}', '\u{2501}', '\u{2502}', + '\u{2503}', '\u{2504}', '\u{2505}', '\u{2506}', '\u{2507}', '\u{2508}', '\u{2509}', '\u{250A}', + '\u{250B}', '\u{250C}', '\u{250D}', '\u{250E}', '\u{250F}', '\u{2510}', '\u{2511}', '\u{2512}', + '\u{2513}', '\u{2514}', '\u{2515}', '\u{2516}', '\u{2517}', '\u{2518}', '\u{2519}', '\u{251A}', + '\u{251B}', '\u{251C}', '\u{251D}', '\u{251E}', '\u{251F}', '\u{2520}', '\u{2521}', '\u{2522}', + '\u{2523}', '\u{2524}', '\u{2525}', '\u{2526}', '\u{2527}', '\u{2528}', '\u{2529}', '\u{252A}', + '\u{252B}', '\u{252C}', '\u{252D}', '\u{252E}', '\u{252F}', '\u{2530}', '\u{2531}', '\u{2532}', + '\u{2533}', '\u{2534}', '\u{2535}', '\u{2536}', '\u{2537}', '\u{2538}', '\u{2539}', '\u{253A}', + '\u{253B}', '\u{253C}', '\u{253D}', '\u{253E}', '\u{253F}', '\u{2540}', '\u{2541}', '\u{2542}', + '\u{2543}', '\u{2544}', '\u{2545}', '\u{2546}', '\u{2547}', '\u{2548}', '\u{2549}', '\u{254A}', + '\u{254B}', '\u{254C}', '\u{254D}', '\u{254E}', '\u{254F}', '\u{2550}', '\u{2551}', '\u{2552}', + '\u{2553}', '\u{2554}', '\u{2555}', '\u{2556}', '\u{2557}', '\u{2558}', '\u{2559}', '\u{255A}', + '\u{255B}', '\u{255C}', '\u{255D}', '\u{255E}', '\u{255F}', '\u{2560}', '\u{2561}', '\u{2562}', + '\u{2563}', '\u{2564}', '\u{2565}', '\u{2566}', '\u{2567}', '\u{2568}', '\u{2569}', '\u{256A}', + '\u{256B}', '\u{256C}', '\u{256D}', '\u{256E}', '\u{256F}', '\u{2570}', '\u{2571}', '\u{2572}', + '\u{2573}', '\u{2574}', '\u{2575}', '\u{2576}', '\u{2577}', '\u{2578}', '\u{2579}', '\u{257A}', + '\u{257B}', '\u{257C}', '\u{257D}', '\u{257E}', '\u{257F}', '\u{2580}', '\u{2581}', '\u{2582}', + '\u{2583}', '\u{2584}', '\u{2585}', '\u{2586}', '\u{2587}', '\u{2588}', '\u{2589}', '\u{258A}', + '\u{258B}', '\u{258C}', '\u{258D}', '\u{258E}', '\u{258F}', '\u{2590}', '\u{2591}', '\u{2592}', + '\u{2593}', '\u{2594}', '\u{2595}', '\u{2596}', '\u{2597}', '\u{2598}', '\u{2599}', '\u{259A}', + '\u{259B}', '\u{259C}', '\u{259D}', '\u{259E}', '\u{259F}', '\u{25A0}', '\u{25A1}', '\u{25A2}', + '\u{25A3}', '\u{25A4}', '\u{25A5}', '\u{25A6}', '\u{25A7}', '\u{25A8}', '\u{25A9}', '\u{25AA}', + '\u{25AB}', '\u{25AC}', '\u{25AD}', '\u{25AE}', '\u{25AF}', '\u{25B0}', '\u{25B1}', '\u{25B2}', + '\u{25B3}', '\u{25B4}', '\u{25B5}', '\u{25B6}', '\u{25B7}', '\u{25B8}', '\u{25B9}', '\u{25BA}', + '\u{25BB}', '\u{25BC}', '\u{25BD}', '\u{25BE}', '\u{25BF}', '\u{25C0}', '\u{25C1}', '\u{25C2}', + '\u{25C3}', '\u{25C4}', '\u{25C5}', '\u{25C6}', '\u{25C7}', '\u{25C8}', '\u{25C9}', '\u{25CA}', + '\u{25CB}', '\u{25CC}', '\u{25CD}', '\u{25CE}', '\u{25CF}', '\u{25D0}', '\u{25D1}', '\u{25D2}', + '\u{25D3}', '\u{25D4}', '\u{25D5}', '\u{25D6}', '\u{25D7}', '\u{25D8}', '\u{25D9}', '\u{25DA}', + '\u{25DB}', '\u{25DC}', '\u{25DD}', '\u{25DE}', '\u{25DF}', '\u{25E0}', '\u{25E1}', '\u{25E2}', + '\u{25E3}', '\u{25E4}', '\u{25E5}', '\u{25E6}', '\u{25E7}', '\u{25E8}', '\u{25E9}', '\u{25EA}', + '\u{25EB}', '\u{25EC}', '\u{25ED}', '\u{25EE}', '\u{25EF}', '\u{25F0}', '\u{25F1}', '\u{25F2}', + '\u{25F3}', '\u{25F4}', '\u{25F5}', '\u{25F6}', '\u{25F7}', '\u{25F8}', '\u{25F9}', '\u{25FA}', + '\u{25FB}', '\u{25FC}', '\u{25FD}', '\u{25FE}', '\u{25FF}', '\u{2600}', '\u{2601}', '\u{2602}', + '\u{2603}', '\u{2604}', '\u{2605}', '\u{2606}', '\u{2607}', '\u{2608}', '\u{2609}', '\u{260A}', + '\u{260B}', '\u{260C}', '\u{260D}', '\u{260E}', '\u{260F}', '\u{2610}', '\u{2611}', '\u{2612}', + '\u{2613}', '\u{2614}', '\u{2615}', '\u{2616}', '\u{2617}', '\u{2618}', '\u{2619}', '\u{261A}', + '\u{261B}', '\u{261C}', '\u{261D}', '\u{261E}', '\u{261F}', '\u{2620}', '\u{2621}', '\u{2622}', + '\u{2623}', '\u{2624}', '\u{2625}', '\u{2626}', '\u{2627}', '\u{2628}', '\u{2629}', '\u{262A}', + '\u{262B}', '\u{262C}', '\u{262D}', '\u{262E}', '\u{262F}', '\u{2630}', '\u{2631}', '\u{2632}', + '\u{2633}', '\u{2634}', '\u{2635}', '\u{2636}', '\u{2637}', '\u{2638}', '\u{2639}', '\u{263A}', + '\u{263B}', '\u{263C}', '\u{263D}', '\u{263E}', '\u{263F}', '\u{2640}', '\u{2641}', '\u{2642}', + '\u{2643}', '\u{2644}', '\u{2645}', '\u{2646}', '\u{2647}', '\u{2648}', '\u{2649}', '\u{264A}', + '\u{264B}', '\u{264C}', '\u{264D}', '\u{264E}', '\u{264F}', '\u{2650}', '\u{2651}', '\u{2652}', + '\u{2653}', '\u{2654}', '\u{2655}', '\u{2656}', '\u{2657}', '\u{2658}', '\u{2659}', '\u{265A}', + '\u{265B}', '\u{265C}', '\u{265D}', '\u{265E}', '\u{265F}', '\u{2660}', '\u{2661}', '\u{2662}', + '\u{2663}', '\u{2664}', '\u{2665}', '\u{2666}', '\u{2667}', '\u{2668}', '\u{2669}', '\u{266A}', + '\u{266B}', '\u{266C}', '\u{266D}', '\u{266E}', '\u{266F}', '\u{2670}', '\u{2671}', '\u{2672}', + '\u{2673}', '\u{2674}', '\u{2675}', '\u{2676}', '\u{2677}', '\u{2678}', '\u{2679}', '\u{267A}', + '\u{267B}', '\u{267C}', '\u{267D}', '\u{267E}', '\u{267F}', '\u{2680}', '\u{2681}', '\u{2682}', + '\u{2683}', '\u{2684}', '\u{2685}', '\u{2686}', '\u{2687}', '\u{2688}', '\u{2689}', '\u{268A}', + '\u{268B}', '\u{268C}', '\u{268D}', '\u{268E}', '\u{268F}', '\u{2690}', '\u{2691}', '\u{2692}', + '\u{2693}', '\u{2694}', '\u{2695}', '\u{2696}', '\u{2697}', '\u{2698}', '\u{2699}', '\u{269A}', + '\u{269B}', '\u{269C}', '\u{269D}', '\u{269E}', '\u{269F}', '\u{26A0}', '\u{26A1}', '\u{26A2}', + '\u{26A3}', '\u{26A4}', '\u{26A5}', '\u{26A6}', '\u{26A7}', '\u{26A8}', '\u{26A9}', '\u{26AA}', + '\u{26AB}', '\u{26AC}', '\u{26AD}', '\u{26AE}', '\u{26AF}', '\u{26B0}', '\u{26B1}', '\u{26B2}', + '\u{26B3}', '\u{26B4}', '\u{26B5}', '\u{26B6}', '\u{26B7}', '\u{26B8}', '\u{26B9}', '\u{26BA}', + '\u{26BB}', '\u{26BC}', '\u{26BD}', '\u{26BE}', '\u{26BF}', '\u{26C0}', '\u{26C1}', '\u{26C2}', + '\u{26C3}', '\u{26C4}', '\u{26C5}', '\u{26C6}', '\u{26C7}', '\u{26C8}', '\u{26C9}', '\u{26CA}', + '\u{26CB}', '\u{26CC}', '\u{26CD}', '\u{26CE}', '\u{26CF}', '\u{26D0}', '\u{26D1}', '\u{26D2}', + '\u{26D3}', '\u{26D4}', '\u{26D5}', '\u{26D6}', '\u{26D7}', '\u{26D8}', '\u{26D9}', '\u{26DA}', + '\u{26DB}', '\u{26DC}', '\u{26DD}', '\u{26DE}', '\u{26DF}', '\u{26E0}', '\u{26E1}', '\u{26E2}', + '\u{26E3}', '\u{26E4}', '\u{26E5}', '\u{26E6}', '\u{26E7}', '\u{26E8}', '\u{26E9}', '\u{26EA}', + '\u{26EB}', '\u{26EC}', '\u{26ED}', '\u{26EE}', '\u{26EF}', '\u{26F0}', '\u{26F1}', '\u{26F2}', + '\u{26F3}', '\u{26F4}', '\u{26F5}', '\u{26F6}', '\u{26F7}', '\u{26F8}', '\u{26F9}', '\u{26FA}', + '\u{26FB}', '\u{26FC}', '\u{26FD}', '\u{26FE}', '\u{26FF}', '\u{2700}', '\u{2701}', '\u{2702}', + '\u{2703}', '\u{2704}', '\u{2705}', '\u{2706}', '\u{2707}', '\u{2708}', '\u{2709}', '\u{270A}', + '\u{270B}', '\u{270C}', '\u{270D}', '\u{270E}', '\u{270F}', '\u{2710}', '\u{2711}', '\u{2712}', + '\u{2713}', '\u{2714}', '\u{2715}', '\u{2716}', '\u{2717}', '\u{2718}', '\u{2719}', '\u{271A}', + '\u{271B}', '\u{271C}', '\u{271D}', '\u{271E}', '\u{271F}', '\u{2720}', '\u{2721}', '\u{2722}', + '\u{2723}', '\u{2724}', '\u{2725}', '\u{2726}', '\u{2727}', '\u{2728}', '\u{2729}', '\u{272A}', + '\u{272B}', '\u{272C}', '\u{272D}', '\u{272E}', '\u{272F}', '\u{2730}', '\u{2731}', '\u{2732}', + '\u{2733}', '\u{2734}', '\u{2735}', '\u{2736}', '\u{2737}', '\u{2738}', '\u{2739}', '\u{273A}', + '\u{273B}', '\u{273C}', '\u{273D}', '\u{273E}', '\u{273F}', '\u{2740}', '\u{2741}', '\u{2742}', + '\u{2743}', '\u{2744}', '\u{2745}', '\u{2746}', '\u{2747}', '\u{2748}', '\u{2749}', '\u{274A}', + '\u{274B}', '\u{274C}', '\u{274D}', '\u{274E}', '\u{274F}', '\u{2750}', '\u{2751}', '\u{2752}', + '\u{2753}', '\u{2754}', '\u{2755}', '\u{2756}', '\u{2757}', '\u{2758}', '\u{2759}', '\u{275A}', + '\u{275B}', '\u{275C}', '\u{275D}', '\u{275E}', '\u{275F}', '\u{2760}', '\u{2761}', '\u{2762}', + '\u{2763}', '\u{2764}', '\u{2765}', '\u{2766}', '\u{2767}', '\u{2768}', '\u{2769}', '\u{276A}', + '\u{276B}', '\u{276C}', '\u{276D}', '\u{276E}', '\u{276F}', '\u{2770}', '\u{2771}', '\u{2772}', + '\u{2773}', '\u{2774}', '\u{2775}', '\u{2794}', '\u{2795}', '\u{2796}', '\u{2797}', '\u{2798}', + '\u{2799}', '\u{279A}', '\u{279B}', '\u{279C}', '\u{279D}', '\u{279E}', '\u{279F}', '\u{27A0}', + '\u{27A1}', '\u{27A2}', '\u{27A3}', '\u{27A4}', '\u{27A5}', '\u{27A6}', '\u{27A7}', '\u{27A8}', + '\u{27A9}', '\u{27AA}', '\u{27AB}', '\u{27AC}', '\u{27AD}', '\u{27AE}', '\u{27AF}', '\u{27B0}', + '\u{27B1}', '\u{27B2}', '\u{27B3}', '\u{27B4}', '\u{27B5}', '\u{27B6}', '\u{27B7}', '\u{27B8}', + '\u{27B9}', '\u{27BA}', '\u{27BB}', '\u{27BC}', '\u{27BD}', '\u{27BE}', '\u{27BF}', '\u{27C0}', + '\u{27C1}', '\u{27C2}', '\u{27C3}', '\u{27C4}', '\u{27C5}', '\u{27C6}', '\u{27C7}', '\u{27C8}', + '\u{27C9}', '\u{27CA}', '\u{27CB}', '\u{27CC}', '\u{27CD}', '\u{27CE}', '\u{27CF}', '\u{27D0}', + '\u{27D1}', '\u{27D2}', '\u{27D3}', '\u{27D4}', '\u{27D5}', '\u{27D6}', '\u{27D7}', '\u{27D8}', + '\u{27D9}', '\u{27DA}', '\u{27DB}', '\u{27DC}', '\u{27DD}', '\u{27DE}', '\u{27DF}', '\u{27E0}', + '\u{27E1}', '\u{27E2}', '\u{27E3}', '\u{27E4}', '\u{27E5}', '\u{27E6}', '\u{27E7}', '\u{27E8}', + '\u{27E9}', '\u{27EA}', '\u{27EB}', '\u{27EC}', '\u{27ED}', '\u{27EE}', '\u{27EF}', '\u{27F0}', + '\u{27F1}', '\u{27F2}', '\u{27F3}', '\u{27F4}', '\u{27F5}', '\u{27F6}', '\u{27F7}', '\u{27F8}', + '\u{27F9}', '\u{27FA}', '\u{27FB}', '\u{27FC}', '\u{27FD}', '\u{27FE}', '\u{27FF}', '\u{2800}', + '\u{2801}', '\u{2802}', '\u{2803}', '\u{2804}', '\u{2805}', '\u{2806}', '\u{2807}', '\u{2808}', + '\u{2809}', '\u{280A}', '\u{280B}', '\u{280C}', '\u{280D}', '\u{280E}', '\u{280F}', '\u{2810}', + '\u{2811}', '\u{2812}', '\u{2813}', '\u{2814}', '\u{2815}', '\u{2816}', '\u{2817}', '\u{2818}', + '\u{2819}', '\u{281A}', '\u{281B}', '\u{281C}', '\u{281D}', '\u{281E}', '\u{281F}', '\u{2820}', + '\u{2821}', '\u{2822}', '\u{2823}', '\u{2824}', '\u{2825}', '\u{2826}', '\u{2827}', '\u{2828}', + '\u{2829}', '\u{282A}', '\u{282B}', '\u{282C}', '\u{282D}', '\u{282E}', '\u{282F}', '\u{2830}', + '\u{2831}', '\u{2832}', '\u{2833}', '\u{2834}', '\u{2835}', '\u{2836}', '\u{2837}', '\u{2838}', + '\u{2839}', '\u{283A}', '\u{283B}', '\u{283C}', '\u{283D}', '\u{283E}', '\u{283F}', '\u{2840}', + '\u{2841}', '\u{2842}', '\u{2843}', '\u{2844}', '\u{2845}', '\u{2846}', '\u{2847}', '\u{2848}', + '\u{2849}', '\u{284A}', '\u{284B}', '\u{284C}', '\u{284D}', '\u{284E}', '\u{284F}', '\u{2850}', + '\u{2851}', '\u{2852}', '\u{2853}', '\u{2854}', '\u{2855}', '\u{2856}', '\u{2857}', '\u{2858}', + '\u{2859}', '\u{285A}', '\u{285B}', '\u{285C}', '\u{285D}', '\u{285E}', '\u{285F}', '\u{2860}', + '\u{2861}', '\u{2862}', '\u{2863}', '\u{2864}', '\u{2865}', '\u{2866}', '\u{2867}', '\u{2868}', + '\u{2869}', '\u{286A}', '\u{286B}', '\u{286C}', '\u{286D}', '\u{286E}', '\u{286F}', '\u{2870}', + '\u{2871}', '\u{2872}', '\u{2873}', '\u{2874}', '\u{2875}', '\u{2876}', '\u{2877}', '\u{2878}', + '\u{2879}', '\u{287A}', '\u{287B}', '\u{287C}', '\u{287D}', '\u{287E}', '\u{287F}', '\u{2880}', + '\u{2881}', '\u{2882}', '\u{2883}', '\u{2884}', '\u{2885}', '\u{2886}', '\u{2887}', '\u{2888}', + '\u{2889}', '\u{288A}', '\u{288B}', '\u{288C}', '\u{288D}', '\u{288E}', '\u{288F}', '\u{2890}', + '\u{2891}', '\u{2892}', '\u{2893}', '\u{2894}', '\u{2895}', '\u{2896}', '\u{2897}', '\u{2898}', + '\u{2899}', '\u{289A}', '\u{289B}', '\u{289C}', '\u{289D}', '\u{289E}', '\u{289F}', '\u{28A0}', + '\u{28A1}', '\u{28A2}', '\u{28A3}', '\u{28A4}', '\u{28A5}', '\u{28A6}', '\u{28A7}', '\u{28A8}', + '\u{28A9}', '\u{28AA}', '\u{28AB}', '\u{28AC}', '\u{28AD}', '\u{28AE}', '\u{28AF}', '\u{28B0}', + '\u{28B1}', '\u{28B2}', '\u{28B3}', '\u{28B4}', '\u{28B5}', '\u{28B6}', '\u{28B7}', '\u{28B8}', + '\u{28B9}', '\u{28BA}', '\u{28BB}', '\u{28BC}', '\u{28BD}', '\u{28BE}', '\u{28BF}', '\u{28C0}', + '\u{28C1}', '\u{28C2}', '\u{28C3}', '\u{28C4}', '\u{28C5}', '\u{28C6}', '\u{28C7}', '\u{28C8}', + '\u{28C9}', '\u{28CA}', '\u{28CB}', '\u{28CC}', '\u{28CD}', '\u{28CE}', '\u{28CF}', '\u{28D0}', + '\u{28D1}', '\u{28D2}', '\u{28D3}', '\u{28D4}', '\u{28D5}', '\u{28D6}', '\u{28D7}', '\u{28D8}', + '\u{28D9}', '\u{28DA}', '\u{28DB}', '\u{28DC}', '\u{28DD}', '\u{28DE}', '\u{28DF}', '\u{28E0}', + '\u{28E1}', '\u{28E2}', '\u{28E3}', '\u{28E4}', '\u{28E5}', '\u{28E6}', '\u{28E7}', '\u{28E8}', + '\u{28E9}', '\u{28EA}', '\u{28EB}', '\u{28EC}', '\u{28ED}', '\u{28EE}', '\u{28EF}', '\u{28F0}', + '\u{28F1}', '\u{28F2}', '\u{28F3}', '\u{28F4}', '\u{28F5}', '\u{28F6}', '\u{28F7}', '\u{28F8}', + '\u{28F9}', '\u{28FA}', '\u{28FB}', '\u{28FC}', '\u{28FD}', '\u{28FE}', '\u{28FF}', '\u{2900}', + '\u{2901}', '\u{2902}', '\u{2903}', '\u{2904}', '\u{2905}', '\u{2906}', '\u{2907}', '\u{2908}', + '\u{2909}', '\u{290A}', '\u{290B}', '\u{290C}', '\u{290D}', '\u{290E}', '\u{290F}', '\u{2910}', + '\u{2911}', '\u{2912}', '\u{2913}', '\u{2914}', '\u{2915}', '\u{2916}', '\u{2917}', '\u{2918}', + '\u{2919}', '\u{291A}', '\u{291B}', '\u{291C}', '\u{291D}', '\u{291E}', '\u{291F}', '\u{2920}', + '\u{2921}', '\u{2922}', '\u{2923}', '\u{2924}', '\u{2925}', '\u{2926}', '\u{2927}', '\u{2928}', + '\u{2929}', '\u{292A}', '\u{292B}', '\u{292C}', '\u{292D}', '\u{292E}', '\u{292F}', '\u{2930}', + '\u{2931}', '\u{2932}', '\u{2933}', '\u{2934}', '\u{2935}', '\u{2936}', '\u{2937}', '\u{2938}', + '\u{2939}', '\u{293A}', '\u{293B}', '\u{293C}', '\u{293D}', '\u{293E}', '\u{293F}', '\u{2940}', + '\u{2941}', '\u{2942}', '\u{2943}', '\u{2944}', '\u{2945}', '\u{2946}', '\u{2947}', '\u{2948}', + '\u{2949}', '\u{294A}', '\u{294B}', '\u{294C}', '\u{294D}', '\u{294E}', '\u{294F}', '\u{2950}', + '\u{2951}', '\u{2952}', '\u{2953}', '\u{2954}', '\u{2955}', '\u{2956}', '\u{2957}', '\u{2958}', + '\u{2959}', '\u{295A}', '\u{295B}', '\u{295C}', '\u{295D}', '\u{295E}', '\u{295F}', '\u{2960}', + '\u{2961}', '\u{2962}', '\u{2963}', '\u{2964}', '\u{2965}', '\u{2966}', '\u{2967}', '\u{2968}', + '\u{2969}', '\u{296A}', '\u{296B}', '\u{296C}', '\u{296D}', '\u{296E}', '\u{296F}', '\u{2970}', + '\u{2971}', '\u{2972}', '\u{2973}', '\u{2974}', '\u{2975}', '\u{2976}', '\u{2977}', '\u{2978}', + '\u{2979}', '\u{297A}', '\u{297B}', '\u{297C}', '\u{297D}', '\u{297E}', '\u{297F}', '\u{2980}', + '\u{2981}', '\u{2982}', '\u{2983}', '\u{2984}', '\u{2985}', '\u{2986}', '\u{2987}', '\u{2988}', + '\u{2989}', '\u{298A}', '\u{298B}', '\u{298C}', '\u{298D}', '\u{298E}', '\u{298F}', '\u{2990}', + '\u{2991}', '\u{2992}', '\u{2993}', '\u{2994}', '\u{2995}', '\u{2996}', '\u{2997}', '\u{2998}', + '\u{2999}', '\u{299A}', '\u{299B}', '\u{299C}', '\u{299D}', '\u{299E}', '\u{299F}', '\u{29A0}', + '\u{29A1}', '\u{29A2}', '\u{29A3}', '\u{29A4}', '\u{29A5}', '\u{29A6}', '\u{29A7}', '\u{29A8}', + '\u{29A9}', '\u{29AA}', '\u{29AB}', '\u{29AC}', '\u{29AD}', '\u{29AE}', '\u{29AF}', '\u{29B0}', + '\u{29B1}', '\u{29B2}', '\u{29B3}', '\u{29B4}', '\u{29B5}', '\u{29B6}', '\u{29B7}', '\u{29B8}', + '\u{29B9}', '\u{29BA}', '\u{29BB}', '\u{29BC}', '\u{29BD}', '\u{29BE}', '\u{29BF}', '\u{29C0}', + '\u{29C1}', '\u{29C2}', '\u{29C3}', '\u{29C4}', '\u{29C5}', '\u{29C6}', '\u{29C7}', '\u{29C8}', + '\u{29C9}', '\u{29CA}', '\u{29CB}', '\u{29CC}', '\u{29CD}', '\u{29CE}', '\u{29CF}', '\u{29D0}', + '\u{29D1}', '\u{29D2}', '\u{29D3}', '\u{29D4}', '\u{29D5}', '\u{29D6}', '\u{29D7}', '\u{29D8}', + '\u{29D9}', '\u{29DA}', '\u{29DB}', '\u{29DC}', '\u{29DD}', '\u{29DE}', '\u{29DF}', '\u{29E0}', + '\u{29E1}', '\u{29E2}', '\u{29E3}', '\u{29E4}', '\u{29E5}', '\u{29E6}', '\u{29E7}', '\u{29E8}', + '\u{29E9}', '\u{29EA}', '\u{29EB}', '\u{29EC}', '\u{29ED}', '\u{29EE}', '\u{29EF}', '\u{29F0}', + '\u{29F1}', '\u{29F2}', '\u{29F3}', '\u{29F4}', '\u{29F5}', '\u{29F6}', '\u{29F7}', '\u{29F8}', + '\u{29F9}', '\u{29FA}', '\u{29FB}', '\u{29FC}', '\u{29FD}', '\u{29FE}', '\u{29FF}', '\u{2A00}', + '\u{2A01}', '\u{2A02}', '\u{2A03}', '\u{2A04}', '\u{2A05}', '\u{2A06}', '\u{2A07}', '\u{2A08}', + '\u{2A09}', '\u{2A0A}', '\u{2A0B}', '\u{2A0C}', '\u{2A0D}', '\u{2A0E}', '\u{2A0F}', '\u{2A10}', + '\u{2A11}', '\u{2A12}', '\u{2A13}', '\u{2A14}', '\u{2A15}', '\u{2A16}', '\u{2A17}', '\u{2A18}', + '\u{2A19}', '\u{2A1A}', '\u{2A1B}', '\u{2A1C}', '\u{2A1D}', '\u{2A1E}', '\u{2A1F}', '\u{2A20}', + '\u{2A21}', '\u{2A22}', '\u{2A23}', '\u{2A24}', '\u{2A25}', '\u{2A26}', '\u{2A27}', '\u{2A28}', + '\u{2A29}', '\u{2A2A}', '\u{2A2B}', '\u{2A2C}', '\u{2A2D}', '\u{2A2E}', '\u{2A2F}', '\u{2A30}', + '\u{2A31}', '\u{2A32}', '\u{2A33}', '\u{2A34}', '\u{2A35}', '\u{2A36}', '\u{2A37}', '\u{2A38}', + '\u{2A39}', '\u{2A3A}', '\u{2A3B}', '\u{2A3C}', '\u{2A3D}', '\u{2A3E}', '\u{2A3F}', '\u{2A40}', + '\u{2A41}', '\u{2A42}', '\u{2A43}', '\u{2A44}', '\u{2A45}', '\u{2A46}', '\u{2A47}', '\u{2A48}', + '\u{2A49}', '\u{2A4A}', '\u{2A4B}', '\u{2A4C}', '\u{2A4D}', '\u{2A4E}', '\u{2A4F}', '\u{2A50}', + '\u{2A51}', '\u{2A52}', '\u{2A53}', '\u{2A54}', '\u{2A55}', '\u{2A56}', '\u{2A57}', '\u{2A58}', + '\u{2A59}', '\u{2A5A}', '\u{2A5B}', '\u{2A5C}', '\u{2A5D}', '\u{2A5E}', '\u{2A5F}', '\u{2A60}', + '\u{2A61}', '\u{2A62}', '\u{2A63}', '\u{2A64}', '\u{2A65}', '\u{2A66}', '\u{2A67}', '\u{2A68}', + '\u{2A69}', '\u{2A6A}', '\u{2A6B}', '\u{2A6C}', '\u{2A6D}', '\u{2A6E}', '\u{2A6F}', '\u{2A70}', + '\u{2A71}', '\u{2A72}', '\u{2A73}', '\u{2A74}', '\u{2A75}', '\u{2A76}', '\u{2A77}', '\u{2A78}', + '\u{2A79}', '\u{2A7A}', '\u{2A7B}', '\u{2A7C}', '\u{2A7D}', '\u{2A7E}', '\u{2A7F}', '\u{2A80}', + '\u{2A81}', '\u{2A82}', '\u{2A83}', '\u{2A84}', '\u{2A85}', '\u{2A86}', '\u{2A87}', '\u{2A88}', + '\u{2A89}', '\u{2A8A}', '\u{2A8B}', '\u{2A8C}', '\u{2A8D}', '\u{2A8E}', '\u{2A8F}', '\u{2A90}', + '\u{2A91}', '\u{2A92}', '\u{2A93}', '\u{2A94}', '\u{2A95}', '\u{2A96}', '\u{2A97}', '\u{2A98}', + '\u{2A99}', '\u{2A9A}', '\u{2A9B}', '\u{2A9C}', '\u{2A9D}', '\u{2A9E}', '\u{2A9F}', '\u{2AA0}', + '\u{2AA1}', '\u{2AA2}', '\u{2AA3}', '\u{2AA4}', '\u{2AA5}', '\u{2AA6}', '\u{2AA7}', '\u{2AA8}', + '\u{2AA9}', '\u{2AAA}', '\u{2AAB}', '\u{2AAC}', '\u{2AAD}', '\u{2AAE}', '\u{2AAF}', '\u{2AB0}', + '\u{2AB1}', '\u{2AB2}', '\u{2AB3}', '\u{2AB4}', '\u{2AB5}', '\u{2AB6}', '\u{2AB7}', '\u{2AB8}', + '\u{2AB9}', '\u{2ABA}', '\u{2ABB}', '\u{2ABC}', '\u{2ABD}', '\u{2ABE}', '\u{2ABF}', '\u{2AC0}', + '\u{2AC1}', '\u{2AC2}', '\u{2AC3}', '\u{2AC4}', '\u{2AC5}', '\u{2AC6}', '\u{2AC7}', '\u{2AC8}', + '\u{2AC9}', '\u{2ACA}', '\u{2ACB}', '\u{2ACC}', '\u{2ACD}', '\u{2ACE}', '\u{2ACF}', '\u{2AD0}', + '\u{2AD1}', '\u{2AD2}', '\u{2AD3}', '\u{2AD4}', '\u{2AD5}', '\u{2AD6}', '\u{2AD7}', '\u{2AD8}', + '\u{2AD9}', '\u{2ADA}', '\u{2ADB}', '\u{2ADC}', '\u{2ADD}', '\u{2ADE}', '\u{2ADF}', '\u{2AE0}', + '\u{2AE1}', '\u{2AE2}', '\u{2AE3}', '\u{2AE4}', '\u{2AE5}', '\u{2AE6}', '\u{2AE7}', '\u{2AE8}', + '\u{2AE9}', '\u{2AEA}', '\u{2AEB}', '\u{2AEC}', '\u{2AED}', '\u{2AEE}', '\u{2AEF}', '\u{2AF0}', + '\u{2AF1}', '\u{2AF2}', '\u{2AF3}', '\u{2AF4}', '\u{2AF5}', '\u{2AF6}', '\u{2AF7}', '\u{2AF8}', + '\u{2AF9}', '\u{2AFA}', '\u{2AFB}', '\u{2AFC}', '\u{2AFD}', '\u{2AFE}', '\u{2AFF}', '\u{2B00}', + '\u{2B01}', '\u{2B02}', '\u{2B03}', '\u{2B04}', '\u{2B05}', '\u{2B06}', '\u{2B07}', '\u{2B08}', + '\u{2B09}', '\u{2B0A}', '\u{2B0B}', '\u{2B0C}', '\u{2B0D}', '\u{2B0E}', '\u{2B0F}', '\u{2B10}', + '\u{2B11}', '\u{2B12}', '\u{2B13}', '\u{2B14}', '\u{2B15}', '\u{2B16}', '\u{2B17}', '\u{2B18}', + '\u{2B19}', '\u{2B1A}', '\u{2B1B}', '\u{2B1C}', '\u{2B1D}', '\u{2B1E}', '\u{2B1F}', '\u{2B20}', + '\u{2B21}', '\u{2B22}', '\u{2B23}', '\u{2B24}', '\u{2B25}', '\u{2B26}', '\u{2B27}', '\u{2B28}', + '\u{2B29}', '\u{2B2A}', '\u{2B2B}', '\u{2B2C}', '\u{2B2D}', '\u{2B2E}', '\u{2B2F}', '\u{2B30}', + '\u{2B31}', '\u{2B32}', '\u{2B33}', '\u{2B34}', '\u{2B35}', '\u{2B36}', '\u{2B37}', '\u{2B38}', + '\u{2B39}', '\u{2B3A}', '\u{2B3B}', '\u{2B3C}', '\u{2B3D}', '\u{2B3E}', '\u{2B3F}', '\u{2B40}', + '\u{2B41}', '\u{2B42}', '\u{2B43}', '\u{2B44}', '\u{2B45}', '\u{2B46}', '\u{2B47}', '\u{2B48}', + '\u{2B49}', '\u{2B4A}', '\u{2B4B}', '\u{2B4C}', '\u{2B4D}', '\u{2B4E}', '\u{2B4F}', '\u{2B50}', + '\u{2B51}', '\u{2B52}', '\u{2B53}', '\u{2B54}', '\u{2B55}', '\u{2B56}', '\u{2B57}', '\u{2B58}', + '\u{2B59}', '\u{2B5A}', '\u{2B5B}', '\u{2B5C}', '\u{2B5D}', '\u{2B5E}', '\u{2B5F}', '\u{2B60}', + '\u{2B61}', '\u{2B62}', '\u{2B63}', '\u{2B64}', '\u{2B65}', '\u{2B66}', '\u{2B67}', '\u{2B68}', + '\u{2B69}', '\u{2B6A}', '\u{2B6B}', '\u{2B6C}', '\u{2B6D}', '\u{2B6E}', '\u{2B6F}', '\u{2B70}', + '\u{2B71}', '\u{2B72}', '\u{2B73}', '\u{2B74}', '\u{2B75}', '\u{2B76}', '\u{2B77}', '\u{2B78}', + '\u{2B79}', '\u{2B7A}', '\u{2B7B}', '\u{2B7C}', '\u{2B7D}', '\u{2B7E}', '\u{2B7F}', '\u{2B80}', + '\u{2B81}', '\u{2B82}', '\u{2B83}', '\u{2B84}', '\u{2B85}', '\u{2B86}', '\u{2B87}', '\u{2B88}', + '\u{2B89}', '\u{2B8A}', '\u{2B8B}', '\u{2B8C}', '\u{2B8D}', '\u{2B8E}', '\u{2B8F}', '\u{2B90}', + '\u{2B91}', '\u{2B92}', '\u{2B93}', '\u{2B94}', '\u{2B95}', '\u{2B96}', '\u{2B97}', '\u{2B98}', + '\u{2B99}', '\u{2B9A}', '\u{2B9B}', '\u{2B9C}', '\u{2B9D}', '\u{2B9E}', '\u{2B9F}', '\u{2BA0}', + '\u{2BA1}', '\u{2BA2}', '\u{2BA3}', '\u{2BA4}', '\u{2BA5}', '\u{2BA6}', '\u{2BA7}', '\u{2BA8}', + '\u{2BA9}', '\u{2BAA}', '\u{2BAB}', '\u{2BAC}', '\u{2BAD}', '\u{2BAE}', '\u{2BAF}', '\u{2BB0}', + '\u{2BB1}', '\u{2BB2}', '\u{2BB3}', '\u{2BB4}', '\u{2BB5}', '\u{2BB6}', '\u{2BB7}', '\u{2BB8}', + '\u{2BB9}', '\u{2BBA}', '\u{2BBB}', '\u{2BBC}', '\u{2BBD}', '\u{2BBE}', '\u{2BBF}', '\u{2BC0}', + '\u{2BC1}', '\u{2BC2}', '\u{2BC3}', '\u{2BC4}', '\u{2BC5}', '\u{2BC6}', '\u{2BC7}', '\u{2BC8}', + '\u{2BC9}', '\u{2BCA}', '\u{2BCB}', '\u{2BCC}', '\u{2BCD}', '\u{2BCE}', '\u{2BCF}', '\u{2BD0}', + '\u{2BD1}', '\u{2BD2}', '\u{2BD3}', '\u{2BD4}', '\u{2BD5}', '\u{2BD6}', '\u{2BD7}', '\u{2BD8}', + '\u{2BD9}', '\u{2BDA}', '\u{2BDB}', '\u{2BDC}', '\u{2BDD}', '\u{2BDE}', '\u{2BDF}', '\u{2BE0}', + '\u{2BE1}', '\u{2BE2}', '\u{2BE3}', '\u{2BE4}', '\u{2BE5}', '\u{2BE6}', '\u{2BE7}', '\u{2BE8}', + '\u{2BE9}', '\u{2BEA}', '\u{2BEB}', '\u{2BEC}', '\u{2BED}', '\u{2BEE}', '\u{2BEF}', '\u{2BF0}', + '\u{2BF1}', '\u{2BF2}', '\u{2BF3}', '\u{2BF4}', '\u{2BF5}', '\u{2BF6}', '\u{2BF7}', '\u{2BF8}', + '\u{2BF9}', '\u{2BFA}', '\u{2BFB}', '\u{2BFC}', '\u{2BFD}', '\u{2BFE}', '\u{2BFF}', '\u{2E00}', + '\u{2E01}', '\u{2E02}', '\u{2E03}', '\u{2E04}', '\u{2E05}', '\u{2E06}', '\u{2E07}', '\u{2E08}', + '\u{2E09}', '\u{2E0A}', '\u{2E0B}', '\u{2E0C}', '\u{2E0D}', '\u{2E0E}', '\u{2E0F}', '\u{2E10}', + '\u{2E11}', '\u{2E12}', '\u{2E13}', '\u{2E14}', '\u{2E15}', '\u{2E16}', '\u{2E17}', '\u{2E18}', + '\u{2E19}', '\u{2E1A}', '\u{2E1B}', '\u{2E1C}', '\u{2E1D}', '\u{2E1E}', '\u{2E1F}', '\u{2E20}', + '\u{2E21}', '\u{2E22}', '\u{2E23}', '\u{2E24}', '\u{2E25}', '\u{2E26}', '\u{2E27}', '\u{2E28}', + '\u{2E29}', '\u{2E2A}', '\u{2E2B}', '\u{2E2C}', '\u{2E2D}', '\u{2E2E}', '\u{2E2F}', '\u{2E30}', + '\u{2E31}', '\u{2E32}', '\u{2E33}', '\u{2E34}', '\u{2E35}', '\u{2E36}', '\u{2E37}', '\u{2E38}', + '\u{2E39}', '\u{2E3A}', '\u{2E3B}', '\u{2E3C}', '\u{2E3D}', '\u{2E3E}', '\u{2E3F}', '\u{2E40}', + '\u{2E41}', '\u{2E42}', '\u{2E43}', '\u{2E44}', '\u{2E45}', '\u{2E46}', '\u{2E47}', '\u{2E48}', + '\u{2E49}', '\u{2E4A}', '\u{2E4B}', '\u{2E4C}', '\u{2E4D}', '\u{2E4E}', '\u{2E4F}', '\u{2E50}', + '\u{2E51}', '\u{2E52}', '\u{2E53}', '\u{2E54}', '\u{2E55}', '\u{2E56}', '\u{2E57}', '\u{2E58}', + '\u{2E59}', '\u{2E5A}', '\u{2E5B}', '\u{2E5C}', '\u{2E5D}', '\u{2E5E}', '\u{2E5F}', '\u{2E60}', + '\u{2E61}', '\u{2E62}', '\u{2E63}', '\u{2E64}', '\u{2E65}', '\u{2E66}', '\u{2E67}', '\u{2E68}', + '\u{2E69}', '\u{2E6A}', '\u{2E6B}', '\u{2E6C}', '\u{2E6D}', '\u{2E6E}', '\u{2E6F}', '\u{2E70}', + '\u{2E71}', '\u{2E72}', '\u{2E73}', '\u{2E74}', '\u{2E75}', '\u{2E76}', '\u{2E77}', '\u{2E78}', + '\u{2E79}', '\u{2E7A}', '\u{2E7B}', '\u{2E7C}', '\u{2E7D}', '\u{2E7E}', '\u{2E7F}', '\u{3001}', + '\u{3002}', '\u{3003}', '\u{3008}', '\u{3009}', '\u{300A}', '\u{300B}', '\u{300C}', '\u{300D}', + '\u{300E}', '\u{300F}', '\u{3010}', '\u{3011}', '\u{3012}', '\u{3013}', '\u{3014}', '\u{3015}', + '\u{3016}', '\u{3017}', '\u{3018}', '\u{3019}', '\u{301A}', '\u{301B}', '\u{301C}', '\u{301D}', + '\u{301E}', '\u{301F}', '\u{3020}', '\u{3030}', '\u{FD3E}', '\u{FD3F}', '\u{FE45}', '\u{FE46}', +]; + +pub static OTHER_ID_CONTINUE: &[char] = &[ + '\u{00B7}', '\u{0387}', '\u{1369}', '\u{136A}', '\u{136B}', '\u{136C}', '\u{136D}', '\u{136E}', + '\u{136F}', '\u{1370}', '\u{1371}', '\u{19DA}', +]; + +pub static OTHER_ID_START: &[char] = &[ + '\u{1885}', '\u{1886}', '\u{2118}', '\u{212E}', '\u{309B}', '\u{309C}', +]; + +pub static PATTERN_WHITE_SPACE: &[char] = &[ + '\u{0009}', '\u{000A}', '\u{000B}', '\u{000C}', '\u{000D}', '\u{0020}', '\u{0085}', '\u{200E}', + '\u{200F}', '\u{2028}', '\u{2029}', +]; diff --git a/boa_unicode/src/tests.rs b/boa_unicode/src/tests.rs new file mode 100644 index 0000000000..316b310609 --- /dev/null +++ b/boa_unicode/src/tests.rs @@ -0,0 +1,8 @@ +use unicode_general_category; +#[test] +fn check_unicode_version() { + assert_eq!( + super::UNICODE_VERSION, + unicode_general_category::UNICODE_VERSION + ); +}