diff --git a/CMakeLists.txt b/CMakeLists.txt index f823141..1fd79d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ add_link_options(${FLAGS}) add_executable(${PROJECT_NAME} main.cpp misc.cpp config.cpp servehelper.cpp numberhelper.cpp pixivclient.cpp pixivmodels.cpp hiredis_wrapper.cpp routes/home.cpp routes/css.cpp routes/artworks.cpp routes/tags.cpp routes/guess_extension.cpp routes/users/common.cpp routes/users/illustrations.cpp - blankie/serializer.cpp blankie/escape.cpp blankie/murl.cpp) + blankie/serializer.cpp blankie/escape.cpp blankie/unescape.cpp blankie/murl.cpp) set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 diff --git a/blankie/murl.cpp b/blankie/murl.cpp index a17dfe8..6023339 100644 --- a/blankie/murl.cpp +++ b/blankie/murl.cpp @@ -26,11 +26,6 @@ // Looser than RFC 3986, but fragments might as well own everything #define FRAGMENT "([^ ]*)" -#define FULL_HTTP_HTTPS_REGEX \ - "(?:(https?)?:)?//" AUTHORITY \ - PATH_ABEMPTY \ - "(?:\\?" QUERY ")?" \ - "(?:#" FRAGMENT ")?" #define HTTP_HTTPS_REGEX \ "(?:(https?)?:)?(?://" AUTHORITY ")?" \ PATH_ABEMPTY \ @@ -45,8 +40,7 @@ static std::string tolower(std::string str); namespace blankie { namespace murl { -std::regex full_url_regex(FULL_HTTP_HTTPS_REGEX, std::regex::icase); -std::regex url_regex(HTTP_HTTPS_REGEX, std::regex::icase); +const std::regex url_regex(HTTP_HTTPS_REGEX, std::regex::icase); Url::Url(const std::string& str) { std::smatch sm; diff --git a/blankie/murl.h b/blankie/murl.h index b675c6f..d73796f 100644 --- a/blankie/murl.h +++ b/blankie/murl.h @@ -6,8 +6,6 @@ namespace blankie { namespace murl { -extern std::regex full_url_regex; - struct Url { std::string scheme; std::string userinfo; diff --git a/blankie/serializer.cpp b/blankie/serializer.cpp index 9ae211b..5a3d43d 100644 --- a/blankie/serializer.cpp +++ b/blankie/serializer.cpp @@ -36,6 +36,8 @@ std::string Element::serialize() const { out += escape(*text); } else if (const std::string* str = std::get_if(&node)) { out += escape(*str); + } else if (const HTMLString* html_str = std::get_if(&node)) { + out += html_str->str; } else { throw std::runtime_error("Encountered unknown node"); } diff --git a/blankie/serializer.h b/blankie/serializer.h index e23bbe6..6e580ad 100644 --- a/blankie/serializer.h +++ b/blankie/serializer.h @@ -9,9 +9,15 @@ namespace blankie { namespace html { struct Element; +struct HTMLString { + HTMLString() = default; + explicit HTMLString(std::string str_) : str(std::move(str_)) {} + + std::string str; +}; typedef std::pair Attribute; -typedef std::variant Node; +typedef std::variant Node; struct Element { const char* tag; diff --git a/blankie/unescape.cpp b/blankie/unescape.cpp new file mode 100644 index 0000000..d2f4260 --- /dev/null +++ b/blankie/unescape.cpp @@ -0,0 +1,125 @@ +#include +#include +#include + +#include "unescape.h" +#include "unescape_data.h" + +// https://stackoverflow.com/a/42013433 +static inline size_t codepoint_to_utf8(char* buf, const unsigned long code) { + // you see, i don't care + // https://t.me/NightShadowsHangout/670534 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wconversion" + if (code <= 0x7F) { + buf[0] = static_cast(code); + return 1; + } else if (code <= 0x7FF) { + buf[0] = 0xC0 | static_cast(code >> 6); /* 110xxxxx */ + buf[1] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 2; + } else if (code <= 0xFFFF) { + buf[0] = 0xE0 | static_cast(code >> 12); /* 1110xxxx */ + buf[1] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ + buf[2] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 3; + } else if (code <= 0x10FFFF) { + buf[0] = 0xF0 | static_cast(code >> 18); /* 11110xxx */ + buf[1] = 0x80 | ((code >> 12) & 0x3F); /* 10xxxxxx */ + buf[2] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ + buf[3] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 4; + #pragma GCC diagnostic pop + } else { + throw std::invalid_argument("codepoint passed is bigger than 0x10FFFF"); + } +} + +static inline bool isdigit(char ch) { + return ch >= '0' && ch <= '9'; +} + +static inline bool ishex(char ch) { + return isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} + +static inline unsigned long decode_numeric_entity(const std::string& entity) { + unsigned long codepoint; + char* last_converted_char; + + errno = 0; + if (entity[1] == 'x' || entity[1] == 'X') { + if (entity.size() <= 2 || !ishex(entity[2])) { + return 0; + } + codepoint = strtoul(&entity.c_str()[2], &last_converted_char, 16); + } else { + if (entity.size() <= 1 || !isdigit(entity[1])) { + return 0; + } + codepoint = strtoul(&entity.c_str()[1], &last_converted_char, 10); + } + + if ((codepoint == ULONG_MAX && errno == ERANGE) || last_converted_char[0] != '\0') { + return 0; + } + + if (codepoint >= 0x80 && codepoint <= 0x9F) { + codepoint = windows1252_repl[codepoint - 0x80]; + } + if (!codepoint || codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) { + codepoint = 0xFFFD; + } + + return codepoint; +} + +static inline unsigned long decode_string_entity(const std::string& entity) { + for (const Entity& i : string_entities) { + if (entity == i.string) { + return i.codepoint; + } + } + + return 0; +} + +static inline unsigned long decode_entity(std::string entity) { + return !entity.empty() && entity[0] == '#' + ? decode_numeric_entity(entity) + : decode_string_entity(entity); +} + +namespace blankie { +namespace html { + +[[nodiscard]] std::string unescape(const std::string& str) { + std::string output; + unsigned long codepoint; + char codepoint_buf[4]; + size_t offset = 0, old_offset = 0, offset_end, codepoint_buf_size; + + output.reserve(str.size()); + while ((offset = str.find('&', offset)) != std::string::npos) { + offset_end = str.find(';', ++offset); + if (offset_end == std::string::npos) { + break; + } + + codepoint = decode_entity(str.substr(offset, offset_end - offset)); + if (codepoint) { + codepoint_buf_size = codepoint_to_utf8(codepoint_buf, codepoint); + output.append(str, old_offset, offset - old_offset - 1); + output.append(codepoint_buf, codepoint_buf_size); + old_offset = offset = offset_end + 1; + } + } + + if (str.size() > old_offset) { + output.append(str, old_offset, std::string::npos); + } + return output; +} + +} // namespace html +} // namespace blankie diff --git a/blankie/unescape.h b/blankie/unescape.h new file mode 100644 index 0000000..5213dca --- /dev/null +++ b/blankie/unescape.h @@ -0,0 +1,9 @@ +#pragma once + +namespace blankie { +namespace html { + +[[nodiscard]] std::string unescape(const std::string& str); + +} // namespace html +} // namespace blankie diff --git a/blankie/unescape_data.h b/blankie/unescape_data.h new file mode 100644 index 0000000..78edfec --- /dev/null +++ b/blankie/unescape_data.h @@ -0,0 +1,2073 @@ +static const unsigned long windows1252_repl[32] = { + /* 0x80: */ 0x20AC, + /* 0x81: */ 0x0081, + /* 0x82: */ 0x201A, + /* 0x83: */ 0x0192, + /* 0x84: */ 0x201E, + /* 0x85: */ 0x2026, + /* 0x86: */ 0x2020, + /* 0x87: */ 0x2021, + /* 0x88: */ 0x02C6, + /* 0x89: */ 0x2030, + /* 0x8A: */ 0x0160, + /* 0x8B: */ 0x2039, + /* 0x8C: */ 0x0152, + /* 0x8D: */ 0x008D, + /* 0x8E: */ 0x017D, + /* 0x8F: */ 0x008F, + /* 0x90: */ 0x0090, + /* 0x91: */ 0x2018, + /* 0x92: */ 0x2019, + /* 0x93: */ 0x201C, + /* 0x94: */ 0x201D, + /* 0x95: */ 0x2022, + /* 0x96: */ 0x2013, + /* 0x97: */ 0x2014, + /* 0x98: */ 0x02DC, + /* 0x99: */ 0x2122, + /* 0x9A: */ 0x0161, + /* 0x9B: */ 0x203A, + /* 0x9C: */ 0x0153, + /* 0x9D: */ 0x009D, + /* 0x9E: */ 0x017E, + /* 0x9F: */ 0x0178, +}; + +struct Entity { + const char* string; + unsigned long codepoint; +}; + +static const Entity string_entities[] = { + {"Tab", 0x9}, + {"NewLine", 0xA}, + {"excl", 0x21}, + {"quot", 0x22}, + {"QUOT", 0x22}, + {"num", 0x23}, + {"dollar", 0x24}, + {"percnt", 0x25}, + {"amp", 0x26}, + {"AMP", 0x26}, + {"apos", 0x27}, + {"lpar", 0x28}, + {"rpar", 0x29}, + {"ast", 0x2A}, + {"midast", 0x2A}, + {"plus", 0x2B}, + {"comma", 0x2C}, + {"period", 0x2E}, + {"sol", 0x2F}, + {"colon", 0x3A}, + {"semi", 0x3B}, + {"lt", 0x3C}, + {"LT", 0x3C}, + {"equals", 0x3D}, + {"gt", 0x3E}, + {"GT", 0x3E}, + {"quest", 0x3F}, + {"commat", 0x40}, + {"lsqb", 0x5B}, + {"lbrack", 0x5B}, + {"bsol", 0x5C}, + {"rsqb", 0x5D}, + {"rbrack", 0x5D}, + {"Hat", 0x5E}, + {"lowbar", 0x5F}, + {"grave", 0x60}, + {"DiacriticalGrave", 0x60}, + {"lcub", 0x7B}, + {"lbrace", 0x7B}, + {"verbar", 0x7C}, + {"vert", 0x7C}, + {"VerticalLine", 0x7C}, + {"rcub", 0x7D}, + {"rbrace", 0x7D}, + {"nbsp", 0xA0}, + {"NonBreakingSpace", 0xA0}, + {"iexcl", 0xA1}, + {"cent", 0xA2}, + {"pound", 0xA3}, + {"curren", 0xA4}, + {"yen", 0xA5}, + {"brvbar", 0xA6}, + {"sect", 0xA7}, + {"Dot", 0xA8}, + {"die", 0xA8}, + {"DoubleDot", 0xA8}, + {"uml", 0xA8}, + {"copy", 0xA9}, + {"COPY", 0xA9}, + {"ordf", 0xAA}, + {"laquo", 0xAB}, + {"not", 0xAC}, + {"shy", 0xAD}, + {"reg", 0xAE}, + {"circledR", 0xAE}, + {"REG", 0xAE}, + {"macr", 0xAF}, + {"OverBar", 0xAF}, + {"strns", 0xAF}, + {"deg", 0xB0}, + {"plusmn", 0xB1}, + {"pm", 0xB1}, + {"PlusMinus", 0xB1}, + {"sup2", 0xB2}, + {"sup3", 0xB3}, + {"acute", 0xB4}, + {"DiacriticalAcute", 0xB4}, + {"micro", 0xB5}, + {"para", 0xB6}, + {"middot", 0xB7}, + {"centerdot", 0xB7}, + {"CenterDot", 0xB7}, + {"cedil", 0xB8}, + {"Cedilla", 0xB8}, + {"sup1", 0xB9}, + {"ordm", 0xBA}, + {"raquo", 0xBB}, + {"frac14", 0xBC}, + {"frac12", 0xBD}, + {"half", 0xBD}, + {"frac34", 0xBE}, + {"iquest", 0xBF}, + {"Agrave", 0xC0}, + {"Aacute", 0xC1}, + {"Acirc", 0xC2}, + {"Atilde", 0xC3}, + {"Auml", 0xC4}, + {"Aring", 0xC5}, + {"AElig", 0xC6}, + {"Ccedil", 0xC7}, + {"Egrave", 0xC8}, + {"Eacute", 0xC9}, + {"Ecirc", 0xCA}, + {"Euml", 0xCB}, + {"Igrave", 0xCC}, + {"Iacute", 0xCD}, + {"Icirc", 0xCE}, + {"Iuml", 0xCF}, + {"ETH", 0xD0}, + {"Ntilde", 0xD1}, + {"Ograve", 0xD2}, + {"Oacute", 0xD3}, + {"Ocirc", 0xD4}, + {"Otilde", 0xD5}, + {"Ouml", 0xD6}, + {"times", 0xD7}, + {"Oslash", 0xD8}, + {"Ugrave", 0xD9}, + {"Uacute", 0xDA}, + {"Ucirc", 0xDB}, + {"Uuml", 0xDC}, + {"Yacute", 0xDD}, + {"THORN", 0xDE}, + {"szlig", 0xDF}, + {"agrave", 0xE0}, + {"aacute", 0xE1}, + {"acirc", 0xE2}, + {"atilde", 0xE3}, + {"auml", 0xE4}, + {"aring", 0xE5}, + {"aelig", 0xE6}, + {"ccedil", 0xE7}, + {"egrave", 0xE8}, + {"eacute", 0xE9}, + {"ecirc", 0xEA}, + {"euml", 0xEB}, + {"igrave", 0xEC}, + {"iacute", 0xED}, + {"icirc", 0xEE}, + {"iuml", 0xEF}, + {"eth", 0xF0}, + {"ntilde", 0xF1}, + {"ograve", 0xF2}, + {"oacute", 0xF3}, + {"ocirc", 0xF4}, + {"otilde", 0xF5}, + {"ouml", 0xF6}, + {"divide", 0xF7}, + {"div", 0xF7}, + {"oslash", 0xF8}, + {"ugrave", 0xF9}, + {"uacute", 0xFA}, + {"ucirc", 0xFB}, + {"uuml", 0xFC}, + {"yacute", 0xFD}, + {"thorn", 0xFE}, + {"yuml", 0xFF}, + {"Amacr", 0x100}, + {"amacr", 0x101}, + {"Abreve", 0x102}, + {"abreve", 0x103}, + {"Aogon", 0x104}, + {"aogon", 0x105}, + {"Cacute", 0x106}, + {"cacute", 0x107}, + {"Ccirc", 0x108}, + {"ccirc", 0x109}, + {"Cdot", 0x10A}, + {"cdot", 0x10B}, + {"Ccaron", 0x10C}, + {"ccaron", 0x10D}, + {"Dcaron", 0x10E}, + {"dcaron", 0x10F}, + {"Dstrok", 0x110}, + {"dstrok", 0x111}, + {"Emacr", 0x112}, + {"emacr", 0x113}, + {"Edot", 0x116}, + {"edot", 0x117}, + {"Eogon", 0x118}, + {"eogon", 0x119}, + {"Ecaron", 0x11A}, + {"ecaron", 0x11B}, + {"Gcirc", 0x11C}, + {"gcirc", 0x11D}, + {"Gbreve", 0x11E}, + {"gbreve", 0x11F}, + {"Gdot", 0x120}, + {"gdot", 0x121}, + {"Gcedil", 0x122}, + {"Hcirc", 0x124}, + {"hcirc", 0x125}, + {"Hstrok", 0x126}, + {"hstrok", 0x127}, + {"Itilde", 0x128}, + {"itilde", 0x129}, + {"Imacr", 0x12A}, + {"imacr", 0x12B}, + {"Iogon", 0x12E}, + {"iogon", 0x12F}, + {"Idot", 0x130}, + {"imath", 0x131}, + {"inodot", 0x131}, + {"IJlig", 0x132}, + {"ijlig", 0x133}, + {"Jcirc", 0x134}, + {"jcirc", 0x135}, + {"Kcedil", 0x136}, + {"kcedil", 0x137}, + {"kgreen", 0x138}, + {"Lacute", 0x139}, + {"lacute", 0x13A}, + {"Lcedil", 0x13B}, + {"lcedil", 0x13C}, + {"Lcaron", 0x13D}, + {"lcaron", 0x13E}, + {"Lmidot", 0x13F}, + {"lmidot", 0x140}, + {"Lstrok", 0x141}, + {"lstrok", 0x142}, + {"Nacute", 0x143}, + {"nacute", 0x144}, + {"Ncedil", 0x145}, + {"ncedil", 0x146}, + {"Ncaron", 0x147}, + {"ncaron", 0x148}, + {"napos", 0x149}, + {"ENG", 0x14A}, + {"eng", 0x14B}, + {"Omacr", 0x14C}, + {"omacr", 0x14D}, + {"Odblac", 0x150}, + {"odblac", 0x151}, + {"OElig", 0x152}, + {"oelig", 0x153}, + {"Racute", 0x154}, + {"racute", 0x155}, + {"Rcedil", 0x156}, + {"rcedil", 0x157}, + {"Rcaron", 0x158}, + {"rcaron", 0x159}, + {"Sacute", 0x15A}, + {"sacute", 0x15B}, + {"Scirc", 0x15C}, + {"scirc", 0x15D}, + {"Scedil", 0x15E}, + {"scedil", 0x15F}, + {"Scaron", 0x160}, + {"scaron", 0x161}, + {"Tcedil", 0x162}, + {"tcedil", 0x163}, + {"Tcaron", 0x164}, + {"tcaron", 0x165}, + {"Tstrok", 0x166}, + {"tstrok", 0x167}, + {"Utilde", 0x168}, + {"utilde", 0x169}, + {"Umacr", 0x16A}, + {"umacr", 0x16B}, + {"Ubreve", 0x16C}, + {"ubreve", 0x16D}, + {"Uring", 0x16E}, + {"uring", 0x16F}, + {"Udblac", 0x170}, + {"udblac", 0x171}, + {"Uogon", 0x172}, + {"uogon", 0x173}, + {"Wcirc", 0x174}, + {"wcirc", 0x175}, + {"Ycirc", 0x176}, + {"ycirc", 0x177}, + {"Yuml", 0x178}, + {"Zacute", 0x179}, + {"zacute", 0x17A}, + {"Zdot", 0x17B}, + {"zdot", 0x17C}, + {"Zcaron", 0x17D}, + {"zcaron", 0x17E}, + {"fnof", 0x192}, + {"imped", 0x1B5}, + {"gacute", 0x1F5}, + {"jmath", 0x237}, + {"circ", 0x2C6}, + {"caron", 0x2C7}, + {"Hacek", 0x2C7}, + {"breve", 0x2D8}, + {"Breve", 0x2D8}, + {"dot", 0x2D9}, + {"DiacriticalDot", 0x2D9}, + {"ring", 0x2DA}, + {"ogon", 0x2DB}, + {"tilde", 0x2DC}, + {"DiacriticalTilde", 0x2DC}, + {"dblac", 0x2DD}, + {"DiacriticalDoubleAcute", 0x2DD}, + {"DownBreve", 0x311}, + {"UnderBar", 0x332}, + {"Alpha", 0x391}, + {"Beta", 0x392}, + {"Gamma", 0x393}, + {"Delta", 0x394}, + {"Epsilon", 0x395}, + {"Zeta", 0x396}, + {"Eta", 0x397}, + {"Theta", 0x398}, + {"Iota", 0x399}, + {"Kappa", 0x39A}, + {"Lambda", 0x39B}, + {"Mu", 0x39C}, + {"Nu", 0x39D}, + {"Xi", 0x39E}, + {"Omicron", 0x39F}, + {"Pi", 0x3A0}, + {"Rho", 0x3A1}, + {"Sigma", 0x3A3}, + {"Tau", 0x3A4}, + {"Upsilon", 0x3A5}, + {"Phi", 0x3A6}, + {"Chi", 0x3A7}, + {"Psi", 0x3A8}, + {"Omega", 0x3A9}, + {"alpha", 0x3B1}, + {"beta", 0x3B2}, + {"gamma", 0x3B3}, + {"delta", 0x3B4}, + {"epsiv", 0x3B5}, + {"varepsilon", 0x3B5}, + {"epsilon", 0x3B5}, + {"zeta", 0x3B6}, + {"eta", 0x3B7}, + {"theta", 0x3B8}, + {"iota", 0x3B9}, + {"kappa", 0x3BA}, + {"lambda", 0x3BB}, + {"mu", 0x3BC}, + {"nu", 0x3BD}, + {"xi", 0x3BE}, + {"omicron", 0x3BF}, + {"pi", 0x3C0}, + {"rho", 0x3C1}, + {"sigmav", 0x3C2}, + {"varsigma", 0x3C2}, + {"sigmaf", 0x3C2}, + {"sigma", 0x3C3}, + {"tau", 0x3C4}, + {"upsi", 0x3C5}, + {"upsilon", 0x3C5}, + {"phi", 0x3C6}, + {"phiv", 0x3C6}, + {"varphi", 0x3C6}, + {"chi", 0x3C7}, + {"psi", 0x3C8}, + {"omega", 0x3C9}, + {"thetav", 0x3D1}, + {"vartheta", 0x3D1}, + {"thetasym", 0x3D1}, + {"Upsi", 0x3D2}, + {"upsih", 0x3D2}, + {"straightphi", 0x3D5}, + {"piv", 0x3D6}, + {"varpi", 0x3D6}, + {"Gammad", 0x3DC}, + {"gammad", 0x3DD}, + {"digamma", 0x3DD}, + {"kappav", 0x3F0}, + {"varkappa", 0x3F0}, + {"rhov", 0x3F1}, + {"varrho", 0x3F1}, + {"epsi", 0x3F5}, + {"straightepsilon", 0x3F5}, + {"bepsi", 0x3F6}, + {"backepsilon", 0x3F6}, + {"IOcy", 0x401}, + {"DJcy", 0x402}, + {"GJcy", 0x403}, + {"Jukcy", 0x404}, + {"DScy", 0x405}, + {"Iukcy", 0x406}, + {"YIcy", 0x407}, + {"Jsercy", 0x408}, + {"LJcy", 0x409}, + {"NJcy", 0x40A}, + {"TSHcy", 0x40B}, + {"KJcy", 0x40C}, + {"Ubrcy", 0x40E}, + {"DZcy", 0x40F}, + {"Acy", 0x410}, + {"Bcy", 0x411}, + {"Vcy", 0x412}, + {"Gcy", 0x413}, + {"Dcy", 0x414}, + {"IEcy", 0x415}, + {"ZHcy", 0x416}, + {"Zcy", 0x417}, + {"Icy", 0x418}, + {"Jcy", 0x419}, + {"Kcy", 0x41A}, + {"Lcy", 0x41B}, + {"Mcy", 0x41C}, + {"Ncy", 0x41D}, + {"Ocy", 0x41E}, + {"Pcy", 0x41F}, + {"Rcy", 0x420}, + {"Scy", 0x421}, + {"Tcy", 0x422}, + {"Ucy", 0x423}, + {"Fcy", 0x424}, + {"KHcy", 0x425}, + {"TScy", 0x426}, + {"CHcy", 0x427}, + {"SHcy", 0x428}, + {"SHCHcy", 0x429}, + {"HARDcy", 0x42A}, + {"Ycy", 0x42B}, + {"SOFTcy", 0x42C}, + {"Ecy", 0x42D}, + {"YUcy", 0x42E}, + {"YAcy", 0x42F}, + {"acy", 0x430}, + {"bcy", 0x431}, + {"vcy", 0x432}, + {"gcy", 0x433}, + {"dcy", 0x434}, + {"iecy", 0x435}, + {"zhcy", 0x436}, + {"zcy", 0x437}, + {"icy", 0x438}, + {"jcy", 0x439}, + {"kcy", 0x43A}, + {"lcy", 0x43B}, + {"mcy", 0x43C}, + {"ncy", 0x43D}, + {"ocy", 0x43E}, + {"pcy", 0x43F}, + {"rcy", 0x440}, + {"scy", 0x441}, + {"tcy", 0x442}, + {"ucy", 0x443}, + {"fcy", 0x444}, + {"khcy", 0x445}, + {"tscy", 0x446}, + {"chcy", 0x447}, + {"shcy", 0x448}, + {"shchcy", 0x449}, + {"hardcy", 0x44A}, + {"ycy", 0x44B}, + {"softcy", 0x44C}, + {"ecy", 0x44D}, + {"yucy", 0x44E}, + {"yacy", 0x44F}, + {"iocy", 0x451}, + {"djcy", 0x452}, + {"gjcy", 0x453}, + {"jukcy", 0x454}, + {"dscy", 0x455}, + {"iukcy", 0x456}, + {"yicy", 0x457}, + {"jsercy", 0x458}, + {"ljcy", 0x459}, + {"njcy", 0x45A}, + {"tshcy", 0x45B}, + {"kjcy", 0x45C}, + {"ubrcy", 0x45E}, + {"dzcy", 0x45F}, + {"ensp", 0x2002}, + {"emsp", 0x2003}, + {"emsp13", 0x2004}, + {"emsp14", 0x2005}, + {"numsp", 0x2007}, + {"puncsp", 0x2008}, + {"thinsp", 0x2009}, + {"ThinSpace", 0x2009}, + {"hairsp", 0x200A}, + {"VeryThinSpace", 0x200A}, + {"ZeroWidthSpace", 0x200B}, + {"NegativeVeryThinSpace", 0x200B}, + {"NegativeThinSpace", 0x200B}, + {"NegativeMediumSpace", 0x200B}, + {"NegativeThickSpace", 0x200B}, + {"zwnj", 0x200C}, + {"zwj", 0x200D}, + {"lrm", 0x200E}, + {"rlm", 0x200F}, + {"hyphen", 0x2010}, + {"dash", 0x2010}, + {"ndash", 0x2013}, + {"mdash", 0x2014}, + {"horbar", 0x2015}, + {"Verbar", 0x2016}, + {"Vert", 0x2016}, + {"lsquo", 0x2018}, + {"OpenCurlyQuote", 0x2018}, + {"rsquo", 0x2019}, + {"rsquor", 0x2019}, + {"CloseCurlyQuote", 0x2019}, + {"lsquor", 0x201A}, + {"sbquo", 0x201A}, + {"ldquo", 0x201C}, + {"OpenCurlyDoubleQuote", 0x201C}, + {"rdquo", 0x201D}, + {"rdquor", 0x201D}, + {"CloseCurlyDoubleQuote", 0x201D}, + {"ldquor", 0x201E}, + {"bdquo", 0x201E}, + {"dagger", 0x2020}, + {"Dagger", 0x2021}, + {"ddagger", 0x2021}, + {"bull", 0x2022}, + {"bullet", 0x2022}, + {"nldr", 0x2025}, + {"hellip", 0x2026}, + {"mldr", 0x2026}, + {"permil", 0x2030}, + {"pertenk", 0x2031}, + {"prime", 0x2032}, + {"Prime", 0x2033}, + {"tprime", 0x2034}, + {"bprime", 0x2035}, + {"backprime", 0x2035}, + {"lsaquo", 0x2039}, + {"rsaquo", 0x203A}, + {"oline", 0x203E}, + {"caret", 0x2041}, + {"hybull", 0x2043}, + {"frasl", 0x2044}, + {"bsemi", 0x204F}, + {"qprime", 0x2057}, + {"MediumSpace", 0x205F}, + {"NoBreak", 0x2060}, + {"ApplyFunction", 0x2061}, + {"af", 0x2061}, + {"InvisibleTimes", 0x2062}, + {"it", 0x2062}, + {"InvisibleComma", 0x2063}, + {"ic", 0x2063}, + {"euro", 0x20AC}, + {"tdot", 0x20DB}, + {"TripleDot", 0x20DB}, + {"DotDot", 0x20DC}, + {"Copf", 0x2102}, + {"complexes", 0x2102}, + {"incare", 0x2105}, + {"gscr", 0x210A}, + {"hamilt", 0x210B}, + {"HilbertSpace", 0x210B}, + {"Hscr", 0x210B}, + {"Hfr", 0x210C}, + {"Poincareplane", 0x210C}, + {"quaternions", 0x210D}, + {"Hopf", 0x210D}, + {"planckh", 0x210E}, + {"planck", 0x210F}, + {"hbar", 0x210F}, + {"plankv", 0x210F}, + {"hslash", 0x210F}, + {"Iscr", 0x2110}, + {"imagline", 0x2110}, + {"image", 0x2111}, + {"Im", 0x2111}, + {"imagpart", 0x2111}, + {"Ifr", 0x2111}, + {"Lscr", 0x2112}, + {"lagran", 0x2112}, + {"Laplacetrf", 0x2112}, + {"ell", 0x2113}, + {"Nopf", 0x2115}, + {"naturals", 0x2115}, + {"numero", 0x2116}, + {"copysr", 0x2117}, + {"weierp", 0x2118}, + {"wp", 0x2118}, + {"Popf", 0x2119}, + {"primes", 0x2119}, + {"rationals", 0x211A}, + {"Qopf", 0x211A}, + {"Rscr", 0x211B}, + {"realine", 0x211B}, + {"real", 0x211C}, + {"Re", 0x211C}, + {"realpart", 0x211C}, + {"Rfr", 0x211C}, + {"reals", 0x211D}, + {"Ropf", 0x211D}, + {"rx", 0x211E}, + {"trade", 0x2122}, + {"TRADE", 0x2122}, + {"integers", 0x2124}, + {"Zopf", 0x2124}, + {"ohm", 0x2126}, + {"mho", 0x2127}, + {"Zfr", 0x2128}, + {"zeetrf", 0x2128}, + {"iiota", 0x2129}, + {"angst", 0x212B}, + {"bernou", 0x212C}, + {"Bernoullis", 0x212C}, + {"Bscr", 0x212C}, + {"Cfr", 0x212D}, + {"Cayleys", 0x212D}, + {"escr", 0x212F}, + {"Escr", 0x2130}, + {"expectation", 0x2130}, + {"Fscr", 0x2131}, + {"Fouriertrf", 0x2131}, + {"phmmat", 0x2133}, + {"Mellintrf", 0x2133}, + {"Mscr", 0x2133}, + {"order", 0x2134}, + {"orderof", 0x2134}, + {"oscr", 0x2134}, + {"alefsym", 0x2135}, + {"aleph", 0x2135}, + {"beth", 0x2136}, + {"gimel", 0x2137}, + {"daleth", 0x2138}, + {"CapitalDifferentialD", 0x2145}, + {"DD", 0x2145}, + {"DifferentialD", 0x2146}, + {"dd", 0x2146}, + {"ExponentialE", 0x2147}, + {"exponentiale", 0x2147}, + {"ee", 0x2147}, + {"ImaginaryI", 0x2148}, + {"ii", 0x2148}, + {"frac13", 0x2153}, + {"frac23", 0x2154}, + {"frac15", 0x2155}, + {"frac25", 0x2156}, + {"frac35", 0x2157}, + {"frac45", 0x2158}, + {"frac16", 0x2159}, + {"frac56", 0x215A}, + {"frac18", 0x215B}, + {"frac38", 0x215C}, + {"frac58", 0x215D}, + {"frac78", 0x215E}, + {"larr", 0x2190}, + {"leftarrow", 0x2190}, + {"LeftArrow", 0x2190}, + {"slarr", 0x2190}, + {"ShortLeftArrow", 0x2190}, + {"uarr", 0x2191}, + {"uparrow", 0x2191}, + {"UpArrow", 0x2191}, + {"ShortUpArrow", 0x2191}, + {"rarr", 0x2192}, + {"rightarrow", 0x2192}, + {"RightArrow", 0x2192}, + {"srarr", 0x2192}, + {"ShortRightArrow", 0x2192}, + {"darr", 0x2193}, + {"downarrow", 0x2193}, + {"DownArrow", 0x2193}, + {"ShortDownArrow", 0x2193}, + {"harr", 0x2194}, + {"leftrightarrow", 0x2194}, + {"LeftRightArrow", 0x2194}, + {"varr", 0x2195}, + {"updownarrow", 0x2195}, + {"UpDownArrow", 0x2195}, + {"nwarr", 0x2196}, + {"UpperLeftArrow", 0x2196}, + {"nwarrow", 0x2196}, + {"nearr", 0x2197}, + {"UpperRightArrow", 0x2197}, + {"nearrow", 0x2197}, + {"searr", 0x2198}, + {"searrow", 0x2198}, + {"LowerRightArrow", 0x2198}, + {"swarr", 0x2199}, + {"swarrow", 0x2199}, + {"LowerLeftArrow", 0x2199}, + {"nlarr", 0x219A}, + {"nleftarrow", 0x219A}, + {"nrarr", 0x219B}, + {"nrightarrow", 0x219B}, + {"rarrw", 0x219D}, + {"rightsquigarrow", 0x219D}, + {"Larr", 0x219E}, + {"twoheadleftarrow", 0x219E}, + {"Uarr", 0x219F}, + {"Rarr", 0x21A0}, + {"twoheadrightarrow", 0x21A0}, + {"Darr", 0x21A1}, + {"larrtl", 0x21A2}, + {"leftarrowtail", 0x21A2}, + {"rarrtl", 0x21A3}, + {"rightarrowtail", 0x21A3}, + {"LeftTeeArrow", 0x21A4}, + {"mapstoleft", 0x21A4}, + {"UpTeeArrow", 0x21A5}, + {"mapstoup", 0x21A5}, + {"map", 0x21A6}, + {"RightTeeArrow", 0x21A6}, + {"mapsto", 0x21A6}, + {"DownTeeArrow", 0x21A7}, + {"mapstodown", 0x21A7}, + {"larrhk", 0x21A9}, + {"hookleftarrow", 0x21A9}, + {"rarrhk", 0x21AA}, + {"hookrightarrow", 0x21AA}, + {"larrlp", 0x21AB}, + {"looparrowleft", 0x21AB}, + {"rarrlp", 0x21AC}, + {"looparrowright", 0x21AC}, + {"harrw", 0x21AD}, + {"leftrightsquigarrow", 0x21AD}, + {"nharr", 0x21AE}, + {"nleftrightarrow", 0x21AE}, + {"lsh", 0x21B0}, + {"Lsh", 0x21B0}, + {"rsh", 0x21B1}, + {"Rsh", 0x21B1}, + {"ldsh", 0x21B2}, + {"rdsh", 0x21B3}, + {"crarr", 0x21B5}, + {"cularr", 0x21B6}, + {"curvearrowleft", 0x21B6}, + {"curarr", 0x21B7}, + {"curvearrowright", 0x21B7}, + {"olarr", 0x21BA}, + {"circlearrowleft", 0x21BA}, + {"orarr", 0x21BB}, + {"circlearrowright", 0x21BB}, + {"lharu", 0x21BC}, + {"LeftVector", 0x21BC}, + {"leftharpoonup", 0x21BC}, + {"lhard", 0x21BD}, + {"leftharpoondown", 0x21BD}, + {"DownLeftVector", 0x21BD}, + {"uharr", 0x21BE}, + {"upharpoonright", 0x21BE}, + {"RightUpVector", 0x21BE}, + {"uharl", 0x21BF}, + {"upharpoonleft", 0x21BF}, + {"LeftUpVector", 0x21BF}, + {"rharu", 0x21C0}, + {"RightVector", 0x21C0}, + {"rightharpoonup", 0x21C0}, + {"rhard", 0x21C1}, + {"rightharpoondown", 0x21C1}, + {"DownRightVector", 0x21C1}, + {"dharr", 0x21C2}, + {"RightDownVector", 0x21C2}, + {"downharpoonright", 0x21C2}, + {"dharl", 0x21C3}, + {"LeftDownVector", 0x21C3}, + {"downharpoonleft", 0x21C3}, + {"rlarr", 0x21C4}, + {"rightleftarrows", 0x21C4}, + {"RightArrowLeftArrow", 0x21C4}, + {"udarr", 0x21C5}, + {"UpArrowDownArrow", 0x21C5}, + {"lrarr", 0x21C6}, + {"leftrightarrows", 0x21C6}, + {"LeftArrowRightArrow", 0x21C6}, + {"llarr", 0x21C7}, + {"leftleftarrows", 0x21C7}, + {"uuarr", 0x21C8}, + {"upuparrows", 0x21C8}, + {"rrarr", 0x21C9}, + {"rightrightarrows", 0x21C9}, + {"ddarr", 0x21CA}, + {"downdownarrows", 0x21CA}, + {"lrhar", 0x21CB}, + {"ReverseEquilibrium", 0x21CB}, + {"leftrightharpoons", 0x21CB}, + {"rlhar", 0x21CC}, + {"rightleftharpoons", 0x21CC}, + {"Equilibrium", 0x21CC}, + {"nlArr", 0x21CD}, + {"nLeftarrow", 0x21CD}, + {"nhArr", 0x21CE}, + {"nLeftrightarrow", 0x21CE}, + {"nrArr", 0x21CF}, + {"nRightarrow", 0x21CF}, + {"lArr", 0x21D0}, + {"Leftarrow", 0x21D0}, + {"DoubleLeftArrow", 0x21D0}, + {"uArr", 0x21D1}, + {"Uparrow", 0x21D1}, + {"DoubleUpArrow", 0x21D1}, + {"rArr", 0x21D2}, + {"Rightarrow", 0x21D2}, + {"Implies", 0x21D2}, + {"DoubleRightArrow", 0x21D2}, + {"dArr", 0x21D3}, + {"Downarrow", 0x21D3}, + {"DoubleDownArrow", 0x21D3}, + {"hArr", 0x21D4}, + {"Leftrightarrow", 0x21D4}, + {"DoubleLeftRightArrow", 0x21D4}, + {"iff", 0x21D4}, + {"vArr", 0x21D5}, + {"Updownarrow", 0x21D5}, + {"DoubleUpDownArrow", 0x21D5}, + {"nwArr", 0x21D6}, + {"neArr", 0x21D7}, + {"seArr", 0x21D8}, + {"swArr", 0x21D9}, + {"lAarr", 0x21DA}, + {"Lleftarrow", 0x21DA}, + {"rAarr", 0x21DB}, + {"Rrightarrow", 0x21DB}, + {"zigrarr", 0x21DD}, + {"larrb", 0x21E4}, + {"LeftArrowBar", 0x21E4}, + {"rarrb", 0x21E5}, + {"RightArrowBar", 0x21E5}, + {"duarr", 0x21F5}, + {"DownArrowUpArrow", 0x21F5}, + {"loarr", 0x21FD}, + {"roarr", 0x21FE}, + {"hoarr", 0x21FF}, + {"forall", 0x2200}, + {"ForAll", 0x2200}, + {"comp", 0x2201}, + {"complement", 0x2201}, + {"part", 0x2202}, + {"PartialD", 0x2202}, + {"exist", 0x2203}, + {"Exists", 0x2203}, + {"nexist", 0x2204}, + {"NotExists", 0x2204}, + {"nexists", 0x2204}, + {"empty", 0x2205}, + {"emptyset", 0x2205}, + {"emptyv", 0x2205}, + {"varnothing", 0x2205}, + {"nabla", 0x2207}, + {"Del", 0x2207}, + {"isin", 0x2208}, + {"isinv", 0x2208}, + {"Element", 0x2208}, + {"in", 0x2208}, + {"notin", 0x2209}, + {"NotElement", 0x2209}, + {"notinva", 0x2209}, + {"niv", 0x220B}, + {"ReverseElement", 0x220B}, + {"ni", 0x220B}, + {"SuchThat", 0x220B}, + {"notni", 0x220C}, + {"notniva", 0x220C}, + {"NotReverseElement", 0x220C}, + {"prod", 0x220F}, + {"Product", 0x220F}, + {"coprod", 0x2210}, + {"Coproduct", 0x2210}, + {"sum", 0x2211}, + {"Sum", 0x2211}, + {"minus", 0x2212}, + {"mnplus", 0x2213}, + {"mp", 0x2213}, + {"MinusPlus", 0x2213}, + {"plusdo", 0x2214}, + {"dotplus", 0x2214}, + {"setmn", 0x2216}, + {"setminus", 0x2216}, + {"Backslash", 0x2216}, + {"ssetmn", 0x2216}, + {"smallsetminus", 0x2216}, + {"lowast", 0x2217}, + {"compfn", 0x2218}, + {"SmallCircle", 0x2218}, + {"radic", 0x221A}, + {"Sqrt", 0x221A}, + {"prop", 0x221D}, + {"propto", 0x221D}, + {"Proportional", 0x221D}, + {"vprop", 0x221D}, + {"varpropto", 0x221D}, + {"infin", 0x221E}, + {"angrt", 0x221F}, + {"ang", 0x2220}, + {"angle", 0x2220}, + {"angmsd", 0x2221}, + {"measuredangle", 0x2221}, + {"angsph", 0x2222}, + {"mid", 0x2223}, + {"VerticalBar", 0x2223}, + {"smid", 0x2223}, + {"shortmid", 0x2223}, + {"nmid", 0x2224}, + {"NotVerticalBar", 0x2224}, + {"nsmid", 0x2224}, + {"nshortmid", 0x2224}, + {"par", 0x2225}, + {"parallel", 0x2225}, + {"DoubleVerticalBar", 0x2225}, + {"spar", 0x2225}, + {"shortparallel", 0x2225}, + {"npar", 0x2226}, + {"nparallel", 0x2226}, + {"NotDoubleVerticalBar", 0x2226}, + {"nspar", 0x2226}, + {"nshortparallel", 0x2226}, + {"and", 0x2227}, + {"wedge", 0x2227}, + {"or", 0x2228}, + {"vee", 0x2228}, + {"cap", 0x2229}, + {"cup", 0x222A}, + {"int", 0x222B}, + {"Integral", 0x222B}, + {"Int", 0x222C}, + {"tint", 0x222D}, + {"iiint", 0x222D}, + {"conint", 0x222E}, + {"oint", 0x222E}, + {"ContourIntegral", 0x222E}, + {"Conint", 0x222F}, + {"DoubleContourIntegral", 0x222F}, + {"Cconint", 0x2230}, + {"cwint", 0x2231}, + {"cwconint", 0x2232}, + {"ClockwiseContourIntegral", 0x2232}, + {"awconint", 0x2233}, + {"CounterClockwiseContourIntegral", 0x2233}, + {"there4", 0x2234}, + {"therefore", 0x2234}, + {"Therefore", 0x2234}, + {"becaus", 0x2235}, + {"because", 0x2235}, + {"Because", 0x2235}, + {"ratio", 0x2236}, + {"Colon", 0x2237}, + {"Proportion", 0x2237}, + {"minusd", 0x2238}, + {"dotminus", 0x2238}, + {"mDDot", 0x223A}, + {"homtht", 0x223B}, + {"sim", 0x223C}, + {"Tilde", 0x223C}, + {"thksim", 0x223C}, + {"thicksim", 0x223C}, + {"bsim", 0x223D}, + {"backsim", 0x223D}, + {"ac", 0x223E}, + {"mstpos", 0x223E}, + {"acd", 0x223F}, + {"wreath", 0x2240}, + {"VerticalTilde", 0x2240}, + {"wr", 0x2240}, + {"nsim", 0x2241}, + {"NotTilde", 0x2241}, + {"esim", 0x2242}, + {"EqualTilde", 0x2242}, + {"eqsim", 0x2242}, + {"sime", 0x2243}, + {"TildeEqual", 0x2243}, + {"simeq", 0x2243}, + {"nsime", 0x2244}, + {"nsimeq", 0x2244}, + {"NotTildeEqual", 0x2244}, + {"cong", 0x2245}, + {"TildeFullEqual", 0x2245}, + {"simne", 0x2246}, + {"ncong", 0x2247}, + {"NotTildeFullEqual", 0x2247}, + {"asymp", 0x2248}, + {"ap", 0x2248}, + {"TildeTilde", 0x2248}, + {"approx", 0x2248}, + {"thkap", 0x2248}, + {"thickapprox", 0x2248}, + {"nap", 0x2249}, + {"NotTildeTilde", 0x2249}, + {"napprox", 0x2249}, + {"ape", 0x224A}, + {"approxeq", 0x224A}, + {"apid", 0x224B}, + {"bcong", 0x224C}, + {"backcong", 0x224C}, + {"asympeq", 0x224D}, + {"CupCap", 0x224D}, + {"bump", 0x224E}, + {"HumpDownHump", 0x224E}, + {"Bumpeq", 0x224E}, + {"bumpe", 0x224F}, + {"HumpEqual", 0x224F}, + {"bumpeq", 0x224F}, + {"esdot", 0x2250}, + {"DotEqual", 0x2250}, + {"doteq", 0x2250}, + {"eDot", 0x2251}, + {"doteqdot", 0x2251}, + {"efDot", 0x2252}, + {"fallingdotseq", 0x2252}, + {"erDot", 0x2253}, + {"risingdotseq", 0x2253}, + {"colone", 0x2254}, + {"coloneq", 0x2254}, + {"Assign", 0x2254}, + {"ecolon", 0x2255}, + {"eqcolon", 0x2255}, + {"ecir", 0x2256}, + {"eqcirc", 0x2256}, + {"cire", 0x2257}, + {"circeq", 0x2257}, + {"wedgeq", 0x2259}, + {"veeeq", 0x225A}, + {"trie", 0x225C}, + {"triangleq", 0x225C}, + {"equest", 0x225F}, + {"questeq", 0x225F}, + {"ne", 0x2260}, + {"NotEqual", 0x2260}, + {"equiv", 0x2261}, + {"Congruent", 0x2261}, + {"nequiv", 0x2262}, + {"NotCongruent", 0x2262}, + {"le", 0x2264}, + {"leq", 0x2264}, + {"ge", 0x2265}, + {"GreaterEqual", 0x2265}, + {"geq", 0x2265}, + {"lE", 0x2266}, + {"LessFullEqual", 0x2266}, + {"leqq", 0x2266}, + {"gE", 0x2267}, + {"GreaterFullEqual", 0x2267}, + {"geqq", 0x2267}, + {"lnE", 0x2268}, + {"lneqq", 0x2268}, + {"gnE", 0x2269}, + {"gneqq", 0x2269}, + {"Lt", 0x226A}, + {"NestedLessLess", 0x226A}, + {"ll", 0x226A}, + {"Gt", 0x226B}, + {"NestedGreaterGreater", 0x226B}, + {"gg", 0x226B}, + {"twixt", 0x226C}, + {"between", 0x226C}, + {"NotCupCap", 0x226D}, + {"nlt", 0x226E}, + {"NotLess", 0x226E}, + {"nless", 0x226E}, + {"ngt", 0x226F}, + {"NotGreater", 0x226F}, + {"ngtr", 0x226F}, + {"nle", 0x2270}, + {"NotLessEqual", 0x2270}, + {"nleq", 0x2270}, + {"nge", 0x2271}, + {"NotGreaterEqual", 0x2271}, + {"ngeq", 0x2271}, + {"lsim", 0x2272}, + {"LessTilde", 0x2272}, + {"lesssim", 0x2272}, + {"gsim", 0x2273}, + {"gtrsim", 0x2273}, + {"GreaterTilde", 0x2273}, + {"nlsim", 0x2274}, + {"NotLessTilde", 0x2274}, + {"ngsim", 0x2275}, + {"NotGreaterTilde", 0x2275}, + {"lg", 0x2276}, + {"lessgtr", 0x2276}, + {"LessGreater", 0x2276}, + {"gl", 0x2277}, + {"gtrless", 0x2277}, + {"GreaterLess", 0x2277}, + {"ntlg", 0x2278}, + {"NotLessGreater", 0x2278}, + {"ntgl", 0x2279}, + {"NotGreaterLess", 0x2279}, + {"pr", 0x227A}, + {"Precedes", 0x227A}, + {"prec", 0x227A}, + {"sc", 0x227B}, + {"Succeeds", 0x227B}, + {"succ", 0x227B}, + {"prcue", 0x227C}, + {"PrecedesSlantEqual", 0x227C}, + {"preccurlyeq", 0x227C}, + {"sccue", 0x227D}, + {"SucceedsSlantEqual", 0x227D}, + {"succcurlyeq", 0x227D}, + {"prsim", 0x227E}, + {"precsim", 0x227E}, + {"PrecedesTilde", 0x227E}, + {"scsim", 0x227F}, + {"succsim", 0x227F}, + {"SucceedsTilde", 0x227F}, + {"npr", 0x2280}, + {"nprec", 0x2280}, + {"NotPrecedes", 0x2280}, + {"nsc", 0x2281}, + {"nsucc", 0x2281}, + {"NotSucceeds", 0x2281}, + {"sub", 0x2282}, + {"subset", 0x2282}, + {"sup", 0x2283}, + {"supset", 0x2283}, + {"Superset", 0x2283}, + {"nsub", 0x2284}, + {"nsup", 0x2285}, + {"sube", 0x2286}, + {"SubsetEqual", 0x2286}, + {"subseteq", 0x2286}, + {"supe", 0x2287}, + {"supseteq", 0x2287}, + {"SupersetEqual", 0x2287}, + {"nsube", 0x2288}, + {"nsubseteq", 0x2288}, + {"NotSubsetEqual", 0x2288}, + {"nsupe", 0x2289}, + {"nsupseteq", 0x2289}, + {"NotSupersetEqual", 0x2289}, + {"subne", 0x228A}, + {"subsetneq", 0x228A}, + {"supne", 0x228B}, + {"supsetneq", 0x228B}, + {"cupdot", 0x228D}, + {"uplus", 0x228E}, + {"UnionPlus", 0x228E}, + {"sqsub", 0x228F}, + {"SquareSubset", 0x228F}, + {"sqsubset", 0x228F}, + {"sqsup", 0x2290}, + {"SquareSuperset", 0x2290}, + {"sqsupset", 0x2290}, + {"sqsube", 0x2291}, + {"SquareSubsetEqual", 0x2291}, + {"sqsubseteq", 0x2291}, + {"sqsupe", 0x2292}, + {"SquareSupersetEqual", 0x2292}, + {"sqsupseteq", 0x2292}, + {"sqcap", 0x2293}, + {"SquareIntersection", 0x2293}, + {"sqcup", 0x2294}, + {"SquareUnion", 0x2294}, + {"oplus", 0x2295}, + {"CirclePlus", 0x2295}, + {"ominus", 0x2296}, + {"CircleMinus", 0x2296}, + {"otimes", 0x2297}, + {"CircleTimes", 0x2297}, + {"osol", 0x2298}, + {"odot", 0x2299}, + {"CircleDot", 0x2299}, + {"ocir", 0x229A}, + {"circledcirc", 0x229A}, + {"oast", 0x229B}, + {"circledast", 0x229B}, + {"odash", 0x229D}, + {"circleddash", 0x229D}, + {"plusb", 0x229E}, + {"boxplus", 0x229E}, + {"minusb", 0x229F}, + {"boxminus", 0x229F}, + {"timesb", 0x22A0}, + {"boxtimes", 0x22A0}, + {"sdotb", 0x22A1}, + {"dotsquare", 0x22A1}, + {"vdash", 0x22A2}, + {"RightTee", 0x22A2}, + {"dashv", 0x22A3}, + {"LeftTee", 0x22A3}, + {"top", 0x22A4}, + {"DownTee", 0x22A4}, + {"bottom", 0x22A5}, + {"bot", 0x22A5}, + {"perp", 0x22A5}, + {"UpTee", 0x22A5}, + {"models", 0x22A7}, + {"vDash", 0x22A8}, + {"DoubleRightTee", 0x22A8}, + {"Vdash", 0x22A9}, + {"Vvdash", 0x22AA}, + {"VDash", 0x22AB}, + {"nvdash", 0x22AC}, + {"nvDash", 0x22AD}, + {"nVdash", 0x22AE}, + {"nVDash", 0x22AF}, + {"prurel", 0x22B0}, + {"vltri", 0x22B2}, + {"vartriangleleft", 0x22B2}, + {"LeftTriangle", 0x22B2}, + {"vrtri", 0x22B3}, + {"vartriangleright", 0x22B3}, + {"RightTriangle", 0x22B3}, + {"ltrie", 0x22B4}, + {"trianglelefteq", 0x22B4}, + {"LeftTriangleEqual", 0x22B4}, + {"rtrie", 0x22B5}, + {"trianglerighteq", 0x22B5}, + {"RightTriangleEqual", 0x22B5}, + {"origof", 0x22B6}, + {"imof", 0x22B7}, + {"mumap", 0x22B8}, + {"multimap", 0x22B8}, + {"hercon", 0x22B9}, + {"intcal", 0x22BA}, + {"intercal", 0x22BA}, + {"veebar", 0x22BB}, + {"barvee", 0x22BD}, + {"angrtvb", 0x22BE}, + {"lrtri", 0x22BF}, + {"xwedge", 0x22C0}, + {"Wedge", 0x22C0}, + {"bigwedge", 0x22C0}, + {"xvee", 0x22C1}, + {"Vee", 0x22C1}, + {"bigvee", 0x22C1}, + {"xcap", 0x22C2}, + {"Intersection", 0x22C2}, + {"bigcap", 0x22C2}, + {"xcup", 0x22C3}, + {"Union", 0x22C3}, + {"bigcup", 0x22C3}, + {"diam", 0x22C4}, + {"diamond", 0x22C4}, + {"Diamond", 0x22C4}, + {"sdot", 0x22C5}, + {"sstarf", 0x22C6}, + {"Star", 0x22C6}, + {"divonx", 0x22C7}, + {"divideontimes", 0x22C7}, + {"bowtie", 0x22C8}, + {"ltimes", 0x22C9}, + {"rtimes", 0x22CA}, + {"lthree", 0x22CB}, + {"leftthreetimes", 0x22CB}, + {"rthree", 0x22CC}, + {"rightthreetimes", 0x22CC}, + {"bsime", 0x22CD}, + {"backsimeq", 0x22CD}, + {"cuvee", 0x22CE}, + {"curlyvee", 0x22CE}, + {"cuwed", 0x22CF}, + {"curlywedge", 0x22CF}, + {"Sub", 0x22D0}, + {"Subset", 0x22D0}, + {"Sup", 0x22D1}, + {"Supset", 0x22D1}, + {"Cap", 0x22D2}, + {"Cup", 0x22D3}, + {"fork", 0x22D4}, + {"pitchfork", 0x22D4}, + {"epar", 0x22D5}, + {"ltdot", 0x22D6}, + {"lessdot", 0x22D6}, + {"gtdot", 0x22D7}, + {"gtrdot", 0x22D7}, + {"Ll", 0x22D8}, + {"Gg", 0x22D9}, + {"ggg", 0x22D9}, + {"leg", 0x22DA}, + {"LessEqualGreater", 0x22DA}, + {"lesseqgtr", 0x22DA}, + {"gel", 0x22DB}, + {"gtreqless", 0x22DB}, + {"GreaterEqualLess", 0x22DB}, + {"cuepr", 0x22DE}, + {"curlyeqprec", 0x22DE}, + {"cuesc", 0x22DF}, + {"curlyeqsucc", 0x22DF}, + {"nprcue", 0x22E0}, + {"NotPrecedesSlantEqual", 0x22E0}, + {"nsccue", 0x22E1}, + {"NotSucceedsSlantEqual", 0x22E1}, + {"nsqsube", 0x22E2}, + {"NotSquareSubsetEqual", 0x22E2}, + {"nsqsupe", 0x22E3}, + {"NotSquareSupersetEqual", 0x22E3}, + {"lnsim", 0x22E6}, + {"gnsim", 0x22E7}, + {"prnsim", 0x22E8}, + {"precnsim", 0x22E8}, + {"scnsim", 0x22E9}, + {"succnsim", 0x22E9}, + {"nltri", 0x22EA}, + {"ntriangleleft", 0x22EA}, + {"NotLeftTriangle", 0x22EA}, + {"nrtri", 0x22EB}, + {"ntriangleright", 0x22EB}, + {"NotRightTriangle", 0x22EB}, + {"nltrie", 0x22EC}, + {"ntrianglelefteq", 0x22EC}, + {"NotLeftTriangleEqual", 0x22EC}, + {"nrtrie", 0x22ED}, + {"ntrianglerighteq", 0x22ED}, + {"NotRightTriangleEqual", 0x22ED}, + {"vellip", 0x22EE}, + {"ctdot", 0x22EF}, + {"utdot", 0x22F0}, + {"dtdot", 0x22F1}, + {"disin", 0x22F2}, + {"isinsv", 0x22F3}, + {"isins", 0x22F4}, + {"isindot", 0x22F5}, + {"notinvc", 0x22F6}, + {"notinvb", 0x22F7}, + {"isinE", 0x22F9}, + {"nisd", 0x22FA}, + {"xnis", 0x22FB}, + {"nis", 0x22FC}, + {"notnivc", 0x22FD}, + {"notnivb", 0x22FE}, + {"barwed", 0x2305}, + {"barwedge", 0x2305}, + {"Barwed", 0x2306}, + {"doublebarwedge", 0x2306}, + {"lceil", 0x2308}, + {"LeftCeiling", 0x2308}, + {"rceil", 0x2309}, + {"RightCeiling", 0x2309}, + {"lfloor", 0x230A}, + {"LeftFloor", 0x230A}, + {"rfloor", 0x230B}, + {"RightFloor", 0x230B}, + {"drcrop", 0x230C}, + {"dlcrop", 0x230D}, + {"urcrop", 0x230E}, + {"ulcrop", 0x230F}, + {"bnot", 0x2310}, + {"profline", 0x2312}, + {"profsurf", 0x2313}, + {"telrec", 0x2315}, + {"target", 0x2316}, + {"ulcorn", 0x231C}, + {"ulcorner", 0x231C}, + {"urcorn", 0x231D}, + {"urcorner", 0x231D}, + {"dlcorn", 0x231E}, + {"llcorner", 0x231E}, + {"drcorn", 0x231F}, + {"lrcorner", 0x231F}, + {"frown", 0x2322}, + {"sfrown", 0x2322}, + {"smile", 0x2323}, + {"ssmile", 0x2323}, + {"cylcty", 0x232D}, + {"profalar", 0x232E}, + {"topbot", 0x2336}, + {"ovbar", 0x233D}, + {"solbar", 0x233F}, + {"angzarr", 0x237C}, + {"lmoust", 0x23B0}, + {"lmoustache", 0x23B0}, + {"rmoust", 0x23B1}, + {"rmoustache", 0x23B1}, + {"tbrk", 0x23B4}, + {"OverBracket", 0x23B4}, + {"bbrk", 0x23B5}, + {"UnderBracket", 0x23B5}, + {"bbrktbrk", 0x23B6}, + {"OverParenthesis", 0x23DC}, + {"UnderParenthesis", 0x23DD}, + {"OverBrace", 0x23DE}, + {"UnderBrace", 0x23DF}, + {"trpezium", 0x23E2}, + {"elinters", 0x23E7}, + {"blank", 0x2423}, + {"oS", 0x24C8}, + {"circledS", 0x24C8}, + {"boxh", 0x2500}, + {"HorizontalLine", 0x2500}, + {"boxv", 0x2502}, + {"boxdr", 0x250C}, + {"boxdl", 0x2510}, + {"boxur", 0x2514}, + {"boxul", 0x2518}, + {"boxvr", 0x251C}, + {"boxvl", 0x2524}, + {"boxhd", 0x252C}, + {"boxhu", 0x2534}, + {"boxvh", 0x253C}, + {"boxH", 0x2550}, + {"boxV", 0x2551}, + {"boxdR", 0x2552}, + {"boxDr", 0x2553}, + {"boxDR", 0x2554}, + {"boxdL", 0x2555}, + {"boxDl", 0x2556}, + {"boxDL", 0x2557}, + {"boxuR", 0x2558}, + {"boxUr", 0x2559}, + {"boxUR", 0x255A}, + {"boxuL", 0x255B}, + {"boxUl", 0x255C}, + {"boxUL", 0x255D}, + {"boxvR", 0x255E}, + {"boxVr", 0x255F}, + {"boxVR", 0x2560}, + {"boxvL", 0x2561}, + {"boxVl", 0x2562}, + {"boxVL", 0x2563}, + {"boxHd", 0x2564}, + {"boxhD", 0x2565}, + {"boxHD", 0x2566}, + {"boxHu", 0x2567}, + {"boxhU", 0x2568}, + {"boxHU", 0x2569}, + {"boxvH", 0x256A}, + {"boxVh", 0x256B}, + {"boxVH", 0x256C}, + {"uhblk", 0x2580}, + {"lhblk", 0x2584}, + {"block", 0x2588}, + {"blk14", 0x2591}, + {"blk12", 0x2592}, + {"blk34", 0x2593}, + {"squ", 0x25A1}, + {"square", 0x25A1}, + {"Square", 0x25A1}, + {"squf", 0x25AA}, + {"squarf", 0x25AA}, + {"blacksquare", 0x25AA}, + {"FilledVerySmallSquare", 0x25AA}, + {"EmptyVerySmallSquare", 0x25AB}, + {"rect", 0x25AD}, + {"marker", 0x25AE}, + {"fltns", 0x25B1}, + {"xutri", 0x25B3}, + {"bigtriangleup", 0x25B3}, + {"utrif", 0x25B4}, + {"blacktriangle", 0x25B4}, + {"utri", 0x25B5}, + {"triangle", 0x25B5}, + {"rtrif", 0x25B8}, + {"blacktriangleright", 0x25B8}, + {"rtri", 0x25B9}, + {"triangleright", 0x25B9}, + {"xdtri", 0x25BD}, + {"bigtriangledown", 0x25BD}, + {"dtrif", 0x25BE}, + {"blacktriangledown", 0x25BE}, + {"dtri", 0x25BF}, + {"triangledown", 0x25BF}, + {"ltrif", 0x25C2}, + {"blacktriangleleft", 0x25C2}, + {"ltri", 0x25C3}, + {"triangleleft", 0x25C3}, + {"loz", 0x25CA}, + {"lozenge", 0x25CA}, + {"cir", 0x25CB}, + {"tridot", 0x25EC}, + {"xcirc", 0x25EF}, + {"bigcirc", 0x25EF}, + {"ultri", 0x25F8}, + {"urtri", 0x25F9}, + {"lltri", 0x25FA}, + {"EmptySmallSquare", 0x25FB}, + {"FilledSmallSquare", 0x25FC}, + {"starf", 0x2605}, + {"bigstar", 0x2605}, + {"star", 0x2606}, + {"phone", 0x260E}, + {"female", 0x2640}, + {"male", 0x2642}, + {"spades", 0x2660}, + {"spadesuit", 0x2660}, + {"clubs", 0x2663}, + {"clubsuit", 0x2663}, + {"hearts", 0x2665}, + {"heartsuit", 0x2665}, + {"diams", 0x2666}, + {"diamondsuit", 0x2666}, + {"sung", 0x266A}, + {"flat", 0x266D}, + {"natur", 0x266E}, + {"natural", 0x266E}, + {"sharp", 0x266F}, + {"check", 0x2713}, + {"checkmark", 0x2713}, + {"cross", 0x2717}, + {"malt", 0x2720}, + {"maltese", 0x2720}, + {"sext", 0x2736}, + {"VerticalSeparator", 0x2758}, + {"lbbrk", 0x2772}, + {"rbbrk", 0x2773}, + {"lobrk", 0x27E6}, + {"LeftDoubleBracket", 0x27E6}, + {"robrk", 0x27E7}, + {"RightDoubleBracket", 0x27E7}, + {"lang", 0x27E8}, + {"LeftAngleBracket", 0x27E8}, + {"langle", 0x27E8}, + {"rang", 0x27E9}, + {"RightAngleBracket", 0x27E9}, + {"rangle", 0x27E9}, + {"Lang", 0x27EA}, + {"Rang", 0x27EB}, + {"loang", 0x27EC}, + {"roang", 0x27ED}, + {"xlarr", 0x27F5}, + {"longleftarrow", 0x27F5}, + {"LongLeftArrow", 0x27F5}, + {"xrarr", 0x27F6}, + {"longrightarrow", 0x27F6}, + {"LongRightArrow", 0x27F6}, + {"xharr", 0x27F7}, + {"longleftrightarrow", 0x27F7}, + {"LongLeftRightArrow", 0x27F7}, + {"xlArr", 0x27F8}, + {"Longleftarrow", 0x27F8}, + {"DoubleLongLeftArrow", 0x27F8}, + {"xrArr", 0x27F9}, + {"Longrightarrow", 0x27F9}, + {"DoubleLongRightArrow", 0x27F9}, + {"xhArr", 0x27FA}, + {"Longleftrightarrow", 0x27FA}, + {"DoubleLongLeftRightArrow", 0x27FA}, + {"xmap", 0x27FC}, + {"longmapsto", 0x27FC}, + {"dzigrarr", 0x27FF}, + {"nvlArr", 0x2902}, + {"nvrArr", 0x2903}, + {"nvHarr", 0x2904}, + {"Map", 0x2905}, + {"lbarr", 0x290C}, + {"rbarr", 0x290D}, + {"bkarow", 0x290D}, + {"lBarr", 0x290E}, + {"rBarr", 0x290F}, + {"dbkarow", 0x290F}, + {"RBarr", 0x2910}, + {"drbkarow", 0x2910}, + {"DDotrahd", 0x2911}, + {"UpArrowBar", 0x2912}, + {"DownArrowBar", 0x2913}, + {"Rarrtl", 0x2916}, + {"latail", 0x2919}, + {"ratail", 0x291A}, + {"lAtail", 0x291B}, + {"rAtail", 0x291C}, + {"larrfs", 0x291D}, + {"rarrfs", 0x291E}, + {"larrbfs", 0x291F}, + {"rarrbfs", 0x2920}, + {"nwarhk", 0x2923}, + {"nearhk", 0x2924}, + {"searhk", 0x2925}, + {"hksearow", 0x2925}, + {"swarhk", 0x2926}, + {"hkswarow", 0x2926}, + {"nwnear", 0x2927}, + {"nesear", 0x2928}, + {"toea", 0x2928}, + {"seswar", 0x2929}, + {"tosa", 0x2929}, + {"swnwar", 0x292A}, + {"rarrc", 0x2933}, + {"cudarrr", 0x2935}, + {"ldca", 0x2936}, + {"rdca", 0x2937}, + {"cudarrl", 0x2938}, + {"larrpl", 0x2939}, + {"curarrm", 0x293C}, + {"cularrp", 0x293D}, + {"rarrpl", 0x2945}, + {"harrcir", 0x2948}, + {"Uarrocir", 0x2949}, + {"lurdshar", 0x294A}, + {"ldrushar", 0x294B}, + {"LeftRightVector", 0x294E}, + {"RightUpDownVector", 0x294F}, + {"DownLeftRightVector", 0x2950}, + {"LeftUpDownVector", 0x2951}, + {"LeftVectorBar", 0x2952}, + {"RightVectorBar", 0x2953}, + {"RightUpVectorBar", 0x2954}, + {"RightDownVectorBar", 0x2955}, + {"DownLeftVectorBar", 0x2956}, + {"DownRightVectorBar", 0x2957}, + {"LeftUpVectorBar", 0x2958}, + {"LeftDownVectorBar", 0x2959}, + {"LeftTeeVector", 0x295A}, + {"RightTeeVector", 0x295B}, + {"RightUpTeeVector", 0x295C}, + {"RightDownTeeVector", 0x295D}, + {"DownLeftTeeVector", 0x295E}, + {"DownRightTeeVector", 0x295F}, + {"LeftUpTeeVector", 0x2960}, + {"LeftDownTeeVector", 0x2961}, + {"lHar", 0x2962}, + {"uHar", 0x2963}, + {"rHar", 0x2964}, + {"dHar", 0x2965}, + {"luruhar", 0x2966}, + {"ldrdhar", 0x2967}, + {"ruluhar", 0x2968}, + {"rdldhar", 0x2969}, + {"lharul", 0x296A}, + {"llhard", 0x296B}, + {"rharul", 0x296C}, + {"lrhard", 0x296D}, + {"udhar", 0x296E}, + {"UpEquilibrium", 0x296E}, + {"duhar", 0x296F}, + {"ReverseUpEquilibrium", 0x296F}, + {"RoundImplies", 0x2970}, + {"erarr", 0x2971}, + {"simrarr", 0x2972}, + {"larrsim", 0x2973}, + {"rarrsim", 0x2974}, + {"rarrap", 0x2975}, + {"ltlarr", 0x2976}, + {"gtrarr", 0x2978}, + {"subrarr", 0x2979}, + {"suplarr", 0x297B}, + {"lfisht", 0x297C}, + {"rfisht", 0x297D}, + {"ufisht", 0x297E}, + {"dfisht", 0x297F}, + {"lopar", 0x2985}, + {"ropar", 0x2986}, + {"lbrke", 0x298B}, + {"rbrke", 0x298C}, + {"lbrkslu", 0x298D}, + {"rbrksld", 0x298E}, + {"lbrksld", 0x298F}, + {"rbrkslu", 0x2990}, + {"langd", 0x2991}, + {"rangd", 0x2992}, + {"lparlt", 0x2993}, + {"rpargt", 0x2994}, + {"gtlPar", 0x2995}, + {"ltrPar", 0x2996}, + {"vzigzag", 0x299A}, + {"vangrt", 0x299C}, + {"angrtvbd", 0x299D}, + {"ange", 0x29A4}, + {"range", 0x29A5}, + {"dwangle", 0x29A6}, + {"uwangle", 0x29A7}, + {"angmsdaa", 0x29A8}, + {"angmsdab", 0x29A9}, + {"angmsdac", 0x29AA}, + {"angmsdad", 0x29AB}, + {"angmsdae", 0x29AC}, + {"angmsdaf", 0x29AD}, + {"angmsdag", 0x29AE}, + {"angmsdah", 0x29AF}, + {"bemptyv", 0x29B0}, + {"demptyv", 0x29B1}, + {"cemptyv", 0x29B2}, + {"raemptyv", 0x29B3}, + {"laemptyv", 0x29B4}, + {"ohbar", 0x29B5}, + {"omid", 0x29B6}, + {"opar", 0x29B7}, + {"operp", 0x29B9}, + {"olcross", 0x29BB}, + {"odsold", 0x29BC}, + {"olcir", 0x29BE}, + {"ofcir", 0x29BF}, + {"olt", 0x29C0}, + {"ogt", 0x29C1}, + {"cirscir", 0x29C2}, + {"cirE", 0x29C3}, + {"solb", 0x29C4}, + {"bsolb", 0x29C5}, + {"boxbox", 0x29C9}, + {"trisb", 0x29CD}, + {"rtriltri", 0x29CE}, + {"LeftTriangleBar", 0x29CF}, + {"RightTriangleBar", 0x29D0}, + {"race", 0x29DA}, + {"iinfin", 0x29DC}, + {"infintie", 0x29DD}, + {"nvinfin", 0x29DE}, + {"eparsl", 0x29E3}, + {"smeparsl", 0x29E4}, + {"eqvparsl", 0x29E5}, + {"lozf", 0x29EB}, + {"blacklozenge", 0x29EB}, + {"RuleDelayed", 0x29F4}, + {"dsol", 0x29F6}, + {"xodot", 0x2A00}, + {"bigodot", 0x2A00}, + {"xoplus", 0x2A01}, + {"bigoplus", 0x2A01}, + {"xotime", 0x2A02}, + {"bigotimes", 0x2A02}, + {"xuplus", 0x2A04}, + {"biguplus", 0x2A04}, + {"xsqcup", 0x2A06}, + {"bigsqcup", 0x2A06}, + {"qint", 0x2A0C}, + {"iiiint", 0x2A0C}, + {"fpartint", 0x2A0D}, + {"cirfnint", 0x2A10}, + {"awint", 0x2A11}, + {"rppolint", 0x2A12}, + {"scpolint", 0x2A13}, + {"npolint", 0x2A14}, + {"pointint", 0x2A15}, + {"quatint", 0x2A16}, + {"intlarhk", 0x2A17}, + {"pluscir", 0x2A22}, + {"plusacir", 0x2A23}, + {"simplus", 0x2A24}, + {"plusdu", 0x2A25}, + {"plussim", 0x2A26}, + {"plustwo", 0x2A27}, + {"mcomma", 0x2A29}, + {"minusdu", 0x2A2A}, + {"loplus", 0x2A2D}, + {"roplus", 0x2A2E}, + {"Cross", 0x2A2F}, + {"timesd", 0x2A30}, + {"timesbar", 0x2A31}, + {"smashp", 0x2A33}, + {"lotimes", 0x2A34}, + {"rotimes", 0x2A35}, + {"otimesas", 0x2A36}, + {"Otimes", 0x2A37}, + {"odiv", 0x2A38}, + {"triplus", 0x2A39}, + {"triminus", 0x2A3A}, + {"tritime", 0x2A3B}, + {"iprod", 0x2A3C}, + {"intprod", 0x2A3C}, + {"amalg", 0x2A3F}, + {"capdot", 0x2A40}, + {"ncup", 0x2A42}, + {"ncap", 0x2A43}, + {"capand", 0x2A44}, + {"cupor", 0x2A45}, + {"cupcap", 0x2A46}, + {"capcup", 0x2A47}, + {"cupbrcap", 0x2A48}, + {"capbrcup", 0x2A49}, + {"cupcup", 0x2A4A}, + {"capcap", 0x2A4B}, + {"ccups", 0x2A4C}, + {"ccaps", 0x2A4D}, + {"ccupssm", 0x2A50}, + {"And", 0x2A53}, + {"Or", 0x2A54}, + {"andand", 0x2A55}, + {"oror", 0x2A56}, + {"orslope", 0x2A57}, + {"andslope", 0x2A58}, + {"andv", 0x2A5A}, + {"orv", 0x2A5B}, + {"andd", 0x2A5C}, + {"ord", 0x2A5D}, + {"wedbar", 0x2A5F}, + {"sdote", 0x2A66}, + {"simdot", 0x2A6A}, + {"congdot", 0x2A6D}, + {"easter", 0x2A6E}, + {"apacir", 0x2A6F}, + {"apE", 0x2A70}, + {"eplus", 0x2A71}, + {"pluse", 0x2A72}, + {"Esim", 0x2A73}, + {"Colone", 0x2A74}, + {"Equal", 0x2A75}, + {"eDDot", 0x2A77}, + {"ddotseq", 0x2A77}, + {"equivDD", 0x2A78}, + {"ltcir", 0x2A79}, + {"gtcir", 0x2A7A}, + {"ltquest", 0x2A7B}, + {"gtquest", 0x2A7C}, + {"les", 0x2A7D}, + {"LessSlantEqual", 0x2A7D}, + {"leqslant", 0x2A7D}, + {"ges", 0x2A7E}, + {"GreaterSlantEqual", 0x2A7E}, + {"geqslant", 0x2A7E}, + {"lesdot", 0x2A7F}, + {"gesdot", 0x2A80}, + {"lesdoto", 0x2A81}, + {"gesdoto", 0x2A82}, + {"lesdotor", 0x2A83}, + {"gesdotol", 0x2A84}, + {"lap", 0x2A85}, + {"lessapprox", 0x2A85}, + {"gap", 0x2A86}, + {"gtrapprox", 0x2A86}, + {"lne", 0x2A87}, + {"lneq", 0x2A87}, + {"gne", 0x2A88}, + {"gneq", 0x2A88}, + {"lnap", 0x2A89}, + {"lnapprox", 0x2A89}, + {"gnap", 0x2A8A}, + {"gnapprox", 0x2A8A}, + {"lEg", 0x2A8B}, + {"lesseqqgtr", 0x2A8B}, + {"gEl", 0x2A8C}, + {"gtreqqless", 0x2A8C}, + {"lsime", 0x2A8D}, + {"gsime", 0x2A8E}, + {"lsimg", 0x2A8F}, + {"gsiml", 0x2A90}, + {"lgE", 0x2A91}, + {"glE", 0x2A92}, + {"lesges", 0x2A93}, + {"gesles", 0x2A94}, + {"els", 0x2A95}, + {"eqslantless", 0x2A95}, + {"egs", 0x2A96}, + {"eqslantgtr", 0x2A96}, + {"elsdot", 0x2A97}, + {"egsdot", 0x2A98}, + {"el", 0x2A99}, + {"eg", 0x2A9A}, + {"siml", 0x2A9D}, + {"simg", 0x2A9E}, + {"simlE", 0x2A9F}, + {"simgE", 0x2AA0}, + {"LessLess", 0x2AA1}, + {"GreaterGreater", 0x2AA2}, + {"glj", 0x2AA4}, + {"gla", 0x2AA5}, + {"ltcc", 0x2AA6}, + {"gtcc", 0x2AA7}, + {"lescc", 0x2AA8}, + {"gescc", 0x2AA9}, + {"smt", 0x2AAA}, + {"lat", 0x2AAB}, + {"smte", 0x2AAC}, + {"late", 0x2AAD}, + {"bumpE", 0x2AAE}, + {"pre", 0x2AAF}, + {"preceq", 0x2AAF}, + {"PrecedesEqual", 0x2AAF}, + {"sce", 0x2AB0}, + {"succeq", 0x2AB0}, + {"SucceedsEqual", 0x2AB0}, + {"prE", 0x2AB3}, + {"scE", 0x2AB4}, + {"prnE", 0x2AB5}, + {"precneqq", 0x2AB5}, + {"scnE", 0x2AB6}, + {"succneqq", 0x2AB6}, + {"prap", 0x2AB7}, + {"precapprox", 0x2AB7}, + {"scap", 0x2AB8}, + {"succapprox", 0x2AB8}, + {"prnap", 0x2AB9}, + {"precnapprox", 0x2AB9}, + {"scnap", 0x2ABA}, + {"succnapprox", 0x2ABA}, + {"Pr", 0x2ABB}, + {"Sc", 0x2ABC}, + {"subdot", 0x2ABD}, + {"supdot", 0x2ABE}, + {"subplus", 0x2ABF}, + {"supplus", 0x2AC0}, + {"submult", 0x2AC1}, + {"supmult", 0x2AC2}, + {"subedot", 0x2AC3}, + {"supedot", 0x2AC4}, + {"subE", 0x2AC5}, + {"subseteqq", 0x2AC5}, + {"supE", 0x2AC6}, + {"supseteqq", 0x2AC6}, + {"subsim", 0x2AC7}, + {"supsim", 0x2AC8}, + {"subnE", 0x2ACB}, + {"subsetneqq", 0x2ACB}, + {"supnE", 0x2ACC}, + {"supsetneqq", 0x2ACC}, + {"csub", 0x2ACF}, + {"csup", 0x2AD0}, + {"csube", 0x2AD1}, + {"csupe", 0x2AD2}, + {"subsup", 0x2AD3}, + {"supsub", 0x2AD4}, + {"subsub", 0x2AD5}, + {"supsup", 0x2AD6}, + {"suphsub", 0x2AD7}, + {"supdsub", 0x2AD8}, + {"forkv", 0x2AD9}, + {"topfork", 0x2ADA}, + {"mlcp", 0x2ADB}, + {"Dashv", 0x2AE4}, + {"DoubleLeftTee", 0x2AE4}, + {"Vdashl", 0x2AE6}, + {"Barv", 0x2AE7}, + {"vBar", 0x2AE8}, + {"vBarv", 0x2AE9}, + {"Vbar", 0x2AEB}, + {"Not", 0x2AEC}, + {"bNot", 0x2AED}, + {"rnmid", 0x2AEE}, + {"cirmid", 0x2AEF}, + {"midcir", 0x2AF0}, + {"topcir", 0x2AF1}, + {"nhpar", 0x2AF2}, + {"parsim", 0x2AF3}, + {"parsl", 0x2AFD}, + {"fflig", 0xFB00}, + {"filig", 0xFB01}, + {"fllig", 0xFB02}, + {"ffilig", 0xFB03}, + {"ffllig", 0xFB04}, + {"Ascr", 0x1D49C}, + {"Cscr", 0x1D49E}, + {"Dscr", 0x1D49F}, + {"Gscr", 0x1D4A2}, + {"Jscr", 0x1D4A5}, + {"Kscr", 0x1D4A6}, + {"Nscr", 0x1D4A9}, + {"Oscr", 0x1D4AA}, + {"Pscr", 0x1D4AB}, + {"Qscr", 0x1D4AC}, + {"Sscr", 0x1D4AE}, + {"Tscr", 0x1D4AF}, + {"Uscr", 0x1D4B0}, + {"Vscr", 0x1D4B1}, + {"Wscr", 0x1D4B2}, + {"Xscr", 0x1D4B3}, + {"Yscr", 0x1D4B4}, + {"Zscr", 0x1D4B5}, + {"ascr", 0x1D4B6}, + {"bscr", 0x1D4B7}, + {"cscr", 0x1D4B8}, + {"dscr", 0x1D4B9}, + {"fscr", 0x1D4BB}, + {"hscr", 0x1D4BD}, + {"iscr", 0x1D4BE}, + {"jscr", 0x1D4BF}, + {"kscr", 0x1D4C0}, + {"lscr", 0x1D4C1}, + {"mscr", 0x1D4C2}, + {"nscr", 0x1D4C3}, + {"pscr", 0x1D4C5}, + {"qscr", 0x1D4C6}, + {"rscr", 0x1D4C7}, + {"sscr", 0x1D4C8}, + {"tscr", 0x1D4C9}, + {"uscr", 0x1D4CA}, + {"vscr", 0x1D4CB}, + {"wscr", 0x1D4CC}, + {"xscr", 0x1D4CD}, + {"yscr", 0x1D4CE}, + {"zscr", 0x1D4CF}, + {"Afr", 0x1D504}, + {"Bfr", 0x1D505}, + {"Dfr", 0x1D507}, + {"Efr", 0x1D508}, + {"Ffr", 0x1D509}, + {"Gfr", 0x1D50A}, + {"Jfr", 0x1D50D}, + {"Kfr", 0x1D50E}, + {"Lfr", 0x1D50F}, + {"Mfr", 0x1D510}, + {"Nfr", 0x1D511}, + {"Ofr", 0x1D512}, + {"Pfr", 0x1D513}, + {"Qfr", 0x1D514}, + {"Sfr", 0x1D516}, + {"Tfr", 0x1D517}, + {"Ufr", 0x1D518}, + {"Vfr", 0x1D519}, + {"Wfr", 0x1D51A}, + {"Xfr", 0x1D51B}, + {"Yfr", 0x1D51C}, + {"afr", 0x1D51E}, + {"bfr", 0x1D51F}, + {"cfr", 0x1D520}, + {"dfr", 0x1D521}, + {"efr", 0x1D522}, + {"ffr", 0x1D523}, + {"gfr", 0x1D524}, + {"hfr", 0x1D525}, + {"ifr", 0x1D526}, + {"jfr", 0x1D527}, + {"kfr", 0x1D528}, + {"lfr", 0x1D529}, + {"mfr", 0x1D52A}, + {"nfr", 0x1D52B}, + {"ofr", 0x1D52C}, + {"pfr", 0x1D52D}, + {"qfr", 0x1D52E}, + {"rfr", 0x1D52F}, + {"sfr", 0x1D530}, + {"tfr", 0x1D531}, + {"ufr", 0x1D532}, + {"vfr", 0x1D533}, + {"wfr", 0x1D534}, + {"xfr", 0x1D535}, + {"yfr", 0x1D536}, + {"zfr", 0x1D537}, + {"Aopf", 0x1D538}, + {"Bopf", 0x1D539}, + {"Dopf", 0x1D53B}, + {"Eopf", 0x1D53C}, + {"Fopf", 0x1D53D}, + {"Gopf", 0x1D53E}, + {"Iopf", 0x1D540}, + {"Jopf", 0x1D541}, + {"Kopf", 0x1D542}, + {"Lopf", 0x1D543}, + {"Mopf", 0x1D544}, + {"Oopf", 0x1D546}, + {"Sopf", 0x1D54A}, + {"Topf", 0x1D54B}, + {"Uopf", 0x1D54C}, + {"Vopf", 0x1D54D}, + {"Wopf", 0x1D54E}, + {"Xopf", 0x1D54F}, + {"Yopf", 0x1D550}, + {"aopf", 0x1D552}, + {"bopf", 0x1D553}, + {"copf", 0x1D554}, + {"dopf", 0x1D555}, + {"eopf", 0x1D556}, + {"fopf", 0x1D557}, + {"gopf", 0x1D558}, + {"hopf", 0x1D559}, + {"iopf", 0x1D55A}, + {"jopf", 0x1D55B}, + {"kopf", 0x1D55C}, + {"lopf", 0x1D55D}, + {"mopf", 0x1D55E}, + {"nopf", 0x1D55F}, + {"oopf", 0x1D560}, + {"popf", 0x1D561}, + {"qopf", 0x1D562}, + {"ropf", 0x1D563}, + {"sopf", 0x1D564}, + {"topf", 0x1D565}, + {"uopf", 0x1D566}, + {"vopf", 0x1D567}, + {"wopf", 0x1D568}, + {"xopf", 0x1D569}, + {"yopf", 0x1D56A}, + {"zopf", 0x1D56B}, +}; diff --git a/pixivmodels.cpp b/pixivmodels.cpp index 067ccf5..c253160 100644 --- a/pixivmodels.cpp +++ b/pixivmodels.cpp @@ -117,8 +117,8 @@ void from_json(const nlohmann::json& j, Illust& illust) { illust_details.at("upload_timestamp").get_to(illust.upload_time); if (full_data) { - if (illust_details.contains("comment") && illust_details["comment"].is_string()) { - illust.comment = illust_details["comment"].get(); + if (illust_details.contains("comment_html") && illust_details["comment_html"].is_string()) { + illust.comment_html = illust_details["comment_html"].get(); } illust_details.at("display_tags").get_to(illust.tags); } @@ -179,7 +179,7 @@ void from_json(const nlohmann::json& j, SearchResults& search_results) { // and i cba to use regex for it, especially when it's not even used in this context .upload_time = -1, - .comment = std::nullopt, + .comment_html = std::nullopt, .tags = std::move(tags), .images = {get_illust_images(i, std::nullopt)}, .page_count = i.at("pageCount").get() diff --git a/pixivmodels.h b/pixivmodels.h index 4745af4..11a8ecf 100644 --- a/pixivmodels.h +++ b/pixivmodels.h @@ -50,7 +50,7 @@ struct Illust { bool ai_generated; time_t upload_time; - std::optional comment; + std::optional comment_html; std::vector tags; std::vector images; size_t page_count; diff --git a/routes/artworks.cpp b/routes/artworks.cpp index f6d1559..7986f42 100644 --- a/routes/artworks.cpp +++ b/routes/artworks.cpp @@ -2,6 +2,8 @@ #include "routes.h" #include "../blankie/murl.h" +#include "../blankie/escape.h" +#include "../blankie/unescape.h" #include "../servehelper.h" #include "../numberhelper.h" #include "../pixivclient.h" @@ -9,10 +11,9 @@ static inline Element generate_user_link(const httplib::Request& req, const Config& config, const Illust& illust); static inline Element generate_images(const httplib::Request& req, const Config& config, const Illust& illust); static inline Element generate_preview_images(const httplib::Request& req, const Config& config, const Illust& illust); -static inline Nodes parse_description_line(const httplib::Request& req, const Config& config, std::string str); -static inline Element generate_description(const httplib::Request& req, const Config& config, const std::string& description); static inline Element generate_illust_tags(const httplib::Request& req, const Config& config, const Illust& illust); -static inline std::string generate_description_text(const httplib::Request& req, const Config& config, std::string description); +static inline blankie::html::HTMLString fix_description_links(const httplib::Request& req, const Config& config, blankie::html::HTMLString str); +static inline std::string generate_description_text(const httplib::Request& req, const Config& config, blankie::html::HTMLString description); static inline Nodes generate_ogp_nodes(const httplib::Request& req, const Config& config, const Illust& illust, bool preview); static inline bool is_true(const std::string& str); @@ -48,8 +49,8 @@ void artworks_route(const httplib::Request& req, httplib::Response& res, const C !preview ? generate_images(req, config, illust) : generate_preview_images(req, config, illust), Element("br") }); - if (illust.comment) { - body.nodes.push_back(generate_description(req, config, *illust.comment)); + if (illust.comment_html) { + body.nodes.push_back(Element("p", {fix_description_links(req, config, blankie::html::HTMLString(*illust.comment_html))})); } body.nodes.push_back(generate_illust_tags(req, config, illust)); body.nodes.push_back(Element("p", {time_to_string(illust.upload_time)})); @@ -122,61 +123,6 @@ static inline Element generate_preview_images(const httplib::Request& req, const return div; } -static inline Nodes parse_description_line(const httplib::Request& req, const Config& config, std::string str) { - Nodes nodes; - std::smatch sm; - - while (std::regex_search(str, sm, blankie::murl::full_url_regex)) { - std::string prefix = sm.prefix(); - std::string url_str = sm.str(0); - std::string suffix = sm.suffix(); - - if (prefix.ends_with('(') && url_str.ends_with(')')) { - url_str.pop_back(); - suffix.insert(0, 1, ')'); - } - if (!prefix.empty()) { - nodes.push_back(std::move(prefix)); - } - - blankie::murl::Url url(std::move(url_str)); - url_str = url.is_host_equal("pixiv.net") || url.is_host_equal("www.pixiv.net") - ? proxy_pixiv_url(req, config, std::move(url)) - : url.to_string(); - nodes.push_back(Element("a", {{"href", url_str}}, {url_str})); - - str = std::move(suffix); - } - if (!str.empty()) { - nodes.push_back(std::move(str)); - } - - return nodes; -} - -static inline Element generate_description(const httplib::Request& req, const Config& config, const std::string& description) { - Element p("p"); - size_t pos = 0; - size_t last_pos = 0; - auto add = [&](std::string str) { - if (!p.nodes.empty()) { - p.nodes.push_back(Element("br")); - } - Nodes nodes = parse_description_line(req, config, std::move(str)); - p.nodes.insert(p.nodes.end(), nodes.begin(), nodes.end()); - }; - - while ((pos = description.find('\n', pos)) != std::string::npos) { - add(description.substr(last_pos, pos - last_pos)); - last_pos = ++pos; - } - if (description.size() > last_pos) { - add(description.substr(last_pos)); - } - - return p; -} - static inline Element generate_illust_tags(const httplib::Request& req, const Config& config, const Illust& illust) { Element div("div", {{"class", "illust-tags"}}, {}); @@ -198,33 +144,63 @@ static inline Element generate_illust_tags(const httplib::Request& req, const Co return div; } -static inline std::string generate_description_text(const httplib::Request& req, const Config& config, std::string description) { +const std::regex start_link_regex(""); +static inline blankie::html::HTMLString fix_description_links(const httplib::Request& req, const Config& config, blankie::html::HTMLString str) { + using namespace std::string_literals; + + blankie::html::HTMLString out; + std::smatch sm; + + out.str.reserve(str.str.size()); + while (std::regex_search(str.str, sm, start_link_regex)) { + out.str += sm.prefix(); + + std::string url_str; + blankie::murl::Url url(sm.str(1)); + if (url.is_host_equal("pixiv.net") || url.is_host_equal("www.pixiv.net")) { + url_str = proxy_pixiv_url(req, config, std::move(url)); + } else if (url.path == "/jump.php") { + url_str = blankie::murl::unescape(std::move(url.query)); + } else { + url_str = url.to_string(); + } + out.str += ""; + + str.str = sm.suffix(); + } + out.str += std::move(str.str); + + return out; +} + +const std::regex link_regex(".+?"); +const std::regex tag_regex("<(.+?)>"); +static inline std::string generate_description_text(const httplib::Request& req, const Config& config, blankie::html::HTMLString description) { + description = fix_description_links(req, config, std::move(description)); + std::string new_description; std::smatch sm; - new_description.reserve(description.size()); - while (std::regex_search(description, sm, blankie::murl::full_url_regex)) { - std::string prefix = sm.prefix(); - std::string url_str = sm.str(0); - std::string suffix = sm.suffix(); - - if (prefix.ends_with('(') && url_str.ends_with(')')) { - url_str.pop_back(); - suffix.insert(0, 1, ')'); - } - new_description += std::move(prefix); - - blankie::murl::Url url(std::move(url_str)); - url_str = url.is_host_equal("pixiv.net") || url.is_host_equal("www.pixiv.net") - ? proxy_pixiv_url(req, config, std::move(url)) - : url.to_string(); - new_description += std::move(url_str); - - description = std::move(suffix); + new_description.reserve(description.str.size()); + while (std::regex_search(description.str, sm, link_regex)) { + new_description += sm.prefix(); + new_description += sm.str(1); + description.str = sm.suffix(); } - new_description += std::move(description); + new_description += std::move(description.str); - return new_description; + description.str = std::move(new_description); + new_description.reserve(description.str.size()); + while (std::regex_search(description.str, sm, tag_regex)) { + new_description += sm.prefix(); + if (sm.str(1) == "br /") { + new_description += '\n'; + } + description.str = sm.suffix(); + } + new_description += std::move(description.str); + + return blankie::html::unescape(std::move(new_description)); } static inline Nodes generate_ogp_nodes(const httplib::Request& req, const Config& config, const Illust& illust, bool preview) { @@ -238,8 +214,8 @@ static inline Nodes generate_ogp_nodes(const httplib::Request& req, const Config Element("meta", {{"property", "og:site_name"}, {"content", "Pixwhile"}}, {}), Element("meta", {{"property", "og:url"}, {"content", std::move(url)}}, {}) }); - if (illust.comment) { - nodes.push_back(Element("meta", {{"property", "og:description"}, {"content", generate_description_text(req, config, *illust.comment)}}, {})); + if (illust.comment_html) { + nodes.push_back(Element("meta", {{"property", "og:description"}, {"content", generate_description_text(req, config, blankie::html::HTMLString(*illust.comment_html))}}, {})); } // i don't even know what multiple og:images do anymore