node/deps/ada/ada.cpp
Yagiz Nizipli 9de01cc4d1
deps: update ada to 3.2.2
PR-URL: https://github.com/nodejs/node/pull/57693
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Daniel Lemire <daniel@lemire.me>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
2025-04-04 10:21:01 +02:00

17432 lines
929 KiB
C++

/* auto-generated on 2025-03-30 13:24:42 -0400. Do not edit! */
/* begin file src/ada.cpp */
#include "ada.h"
/* begin file src/checkers.cpp */
#include <algorithm>
#include <array>
#include <string_view>
namespace ada::checkers {
ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept {
// The string is not empty and does not contain upper case ASCII characters.
//
// Optimization. To be considered as a possible ipv4, the string must end
// with 'x' or a lowercase hex character.
// Most of the time, this will be false so this simple check will save a lot
// of effort.
// If the address ends with a dot, we need to prune it (special case).
if (view.ends_with('.')) {
view.remove_suffix(1);
if (view.empty()) {
return false;
}
}
char last_char = view.back();
bool possible_ipv4 = (last_char >= '0' && last_char <= '9') ||
(last_char >= 'a' && last_char <= 'f') ||
last_char == 'x';
if (!possible_ipv4) {
return false;
}
// From the last character, find the last dot.
size_t last_dot = view.rfind('.');
if (last_dot != std::string_view::npos) {
// We have at least one dot.
view = view.substr(last_dot + 1);
}
/** Optimization opportunity: we have basically identified the last number of
the ipv4 if we return true here. We might as well parse it and have at
least one number parsed when we get to parse_ipv4. */
if (std::ranges::all_of(view, ada::checkers::is_digit)) {
return true;
}
// It could be hex (0x), but not if there is a single character.
if (view.size() == 1) {
return false;
}
// It must start with 0x.
if (!view.starts_with("0x")) {
return false;
}
// We must allow "0x".
if (view.size() == 2) {
return true;
}
// We have 0x followed by some characters, we need to check that they are
// hexadecimals.
return std::all_of(view.begin() + 2, view.end(),
ada::unicode::is_lowercase_hex);
}
// for use with path_signature, we include all characters that need percent
// encoding.
static constexpr std::array<uint8_t, 256> path_signature_table =
[]() consteval {
std::array<uint8_t, 256> result{};
for (size_t i = 0; i < 256; i++) {
if (i <= 0x20 || i == 0x22 || i == 0x23 || i == 0x3c || i == 0x3e ||
i == 0x3f || i == 0x60 || i == 0x7b || i == 0x7d || i > 0x7e) {
result[i] = 1;
} else if (i == 0x25) {
result[i] = 8;
} else if (i == 0x2e) {
result[i] = 4;
} else if (i == 0x5c) {
result[i] = 2;
} else {
result[i] = 0;
}
}
return result;
}();
ada_really_inline constexpr uint8_t path_signature(
std::string_view input) noexcept {
// The path percent-encode set is the query percent-encode set and U+003F (?),
// U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the
// C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#),
// U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0
// controls and all code points greater than U+007E (~).
size_t i = 0;
uint8_t accumulator{};
for (; i + 7 < input.size(); i += 8) {
accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
path_signature_table[uint8_t(input[i + 1])] |
path_signature_table[uint8_t(input[i + 2])] |
path_signature_table[uint8_t(input[i + 3])] |
path_signature_table[uint8_t(input[i + 4])] |
path_signature_table[uint8_t(input[i + 5])] |
path_signature_table[uint8_t(input[i + 6])] |
path_signature_table[uint8_t(input[i + 7])]);
}
for (; i < input.size(); i++) {
accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
}
return accumulator;
}
ada_really_inline constexpr bool verify_dns_length(
std::string_view input) noexcept {
if (input.back() == '.') {
if (input.size() > 254) return false;
} else if (input.size() > 253)
return false;
size_t start = 0;
while (start < input.size()) {
auto dot_location = input.find('.', start);
// If not found, it's likely the end of the domain
if (dot_location == std::string_view::npos) dot_location = input.size();
auto label_size = dot_location - start;
if (label_size > 63 || label_size == 0) return false;
start = dot_location + 1;
}
return true;
}
} // namespace ada::checkers
/* end file src/checkers.cpp */
/* begin file src/unicode.cpp */
ADA_PUSH_DISABLE_ALL_WARNINGS
/* begin file src/ada_idna.cpp */
/* auto-generated on 2025-03-08 13:17:11 -0500. Do not edit! */
/* begin file src/idna.cpp */
/* begin file src/unicode_transcoding.cpp */
#include <algorithm>
#include <cstdint>
#include <cstring>
namespace ada::idna {
size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
size_t pos = 0;
const char32_t* start{utf32_output};
while (pos < len) {
// try to convert the next block of 16 ASCII bytes
if (pos + 16 <= len) { // if it is safe to read 16 more
// bytes, check that they are ascii
uint64_t v1;
std::memcpy(&v1, data + pos, sizeof(uint64_t));
uint64_t v2;
std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
uint64_t v{v1 | v2};
if ((v & 0x8080808080808080) == 0) {
size_t final_pos = pos + 16;
while (pos < final_pos) {
*utf32_output++ = char32_t(buf[pos]);
pos++;
}
continue;
}
}
uint8_t leading_byte = data[pos]; // leading byte
if (leading_byte < 0b10000000) {
// converting one ASCII byte !!!
*utf32_output++ = char32_t(leading_byte);
pos++;
} else if ((leading_byte & 0b11100000) == 0b11000000) {
// We have a two-byte UTF-8
if (pos + 1 >= len) {
return 0;
} // minimal bound checking
if ((data[pos + 1] & 0b11000000) != 0b10000000) {
return 0;
}
// range check
uint32_t code_point =
(leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
if (code_point < 0x80 || 0x7ff < code_point) {
return 0;
}
*utf32_output++ = char32_t(code_point);
pos += 2;
} else if ((leading_byte & 0b11110000) == 0b11100000) {
// We have a three-byte UTF-8
if (pos + 2 >= len) {
return 0;
} // minimal bound checking
if ((data[pos + 1] & 0b11000000) != 0b10000000) {
return 0;
}
if ((data[pos + 2] & 0b11000000) != 0b10000000) {
return 0;
}
// range check
uint32_t code_point = (leading_byte & 0b00001111) << 12 |
(data[pos + 1] & 0b00111111) << 6 |
(data[pos + 2] & 0b00111111);
if (code_point < 0x800 || 0xffff < code_point ||
(0xd7ff < code_point && code_point < 0xe000)) {
return 0;
}
*utf32_output++ = char32_t(code_point);
pos += 3;
} else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000
// we have a 4-byte UTF-8 word.
if (pos + 3 >= len) {
return 0;
} // minimal bound checking
if ((data[pos + 1] & 0b11000000) != 0b10000000) {
return 0;
}
if ((data[pos + 2] & 0b11000000) != 0b10000000) {
return 0;
}
if ((data[pos + 3] & 0b11000000) != 0b10000000) {
return 0;
}
// range check
uint32_t code_point = (leading_byte & 0b00000111) << 18 |
(data[pos + 1] & 0b00111111) << 12 |
(data[pos + 2] & 0b00111111) << 6 |
(data[pos + 3] & 0b00111111);
if (code_point <= 0xffff || 0x10ffff < code_point) {
return 0;
}
*utf32_output++ = char32_t(code_point);
pos += 4;
} else {
return 0;
}
}
return utf32_output - start;
}
size_t utf8_length_from_utf32(const char32_t* buf, size_t len) {
// We are not BOM aware.
const uint32_t* p = reinterpret_cast<const uint32_t*>(buf);
size_t counter{0};
for (size_t i = 0; i != len; ++i) {
++counter; // ASCII
counter += static_cast<size_t>(p[i] > 0x7F); // two-byte
counter += static_cast<size_t>(p[i] > 0x7FF); // three-byte
counter += static_cast<size_t>(p[i] > 0xFFFF); // four-bytes
}
return counter;
}
size_t utf32_length_from_utf8(const char* buf, size_t len) {
const int8_t* p = reinterpret_cast<const int8_t*>(buf);
return std::count_if(p, std::next(p, len), [](int8_t c) {
// -65 is 0b10111111, anything larger in two-complement's
// should start a new code point.
return c > -65;
});
}
size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) {
const uint32_t* data = reinterpret_cast<const uint32_t*>(buf);
size_t pos = 0;
const char* start{utf8_output};
while (pos < len) {
// try to convert the next block of 2 ASCII characters
if (pos + 2 <= len) { // if it is safe to read 8 more
// bytes, check that they are ascii
uint64_t v;
std::memcpy(&v, data + pos, sizeof(uint64_t));
if ((v & 0xFFFFFF80FFFFFF80) == 0) {
*utf8_output++ = char(buf[pos]);
*utf8_output++ = char(buf[pos + 1]);
pos += 2;
continue;
}
}
uint32_t word = data[pos];
if ((word & 0xFFFFFF80) == 0) {
// will generate one UTF-8 bytes
*utf8_output++ = char(word);
pos++;
} else if ((word & 0xFFFFF800) == 0) {
// will generate two UTF-8 bytes
// we have 0b110XXXXX 0b10XXXXXX
*utf8_output++ = char((word >> 6) | 0b11000000);
*utf8_output++ = char((word & 0b111111) | 0b10000000);
pos++;
} else if ((word & 0xFFFF0000) == 0) {
// will generate three UTF-8 bytes
// we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
if (word >= 0xD800 && word <= 0xDFFF) {
return 0;
}
*utf8_output++ = char((word >> 12) | 0b11100000);
*utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
*utf8_output++ = char((word & 0b111111) | 0b10000000);
pos++;
} else {
// will generate four UTF-8 bytes
// we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX
// 0b10XXXXXX
if (word > 0x10FFFF) {
return 0;
}
*utf8_output++ = char((word >> 18) | 0b11110000);
*utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
*utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
*utf8_output++ = char((word & 0b111111) | 0b10000000);
pos++;
}
}
return utf8_output - start;
}
} // namespace ada::idna
/* end file src/unicode_transcoding.cpp */
/* begin file src/mapping.cpp */
#include <algorithm>
#include <array>
#include <string>
/* begin file src/mapping_tables.cpp */
// IDNA 16.0.0
// clang-format off
#ifndef ADA_IDNA_TABLES_H
#define ADA_IDNA_TABLES_H
#include <cstdint>
namespace ada::idna {
const uint32_t mappings[5236] =
{
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122, 32, 32, 776, 32, 772, 50, 51, 32, 769,
956, 32, 807, 49, 49, 8260, 52, 49, 8260, 50, 51, 8260, 52, 224, 225, 226, 227,
228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 257, 259, 261, 263, 265, 267,
269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299,
301, 303, 105, 775, 309, 311, 314, 316, 318, 108, 183, 322, 324, 326, 328, 700,
110, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359,
361, 363, 365, 367, 369, 371, 373, 375, 255, 378, 380, 382, 595, 387, 389, 596,
392, 598, 599, 396, 477, 601, 603, 402, 608, 611, 617, 616, 409, 623, 626, 629,
417, 419, 421, 640, 424, 643, 429, 648, 432, 650, 651, 436, 438, 658, 441, 445,
100, 382, 108, 106, 110, 106, 462, 464, 466, 468, 470, 472, 474, 476, 479, 481,
483, 485, 487, 489, 491, 493, 495, 100, 122, 501, 405, 447, 505, 507, 509, 511,
513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543,
414, 547, 549, 551, 553, 555, 557, 559, 561, 563, 11365, 572, 410, 11366, 578, 384,
649, 652, 583, 585, 587, 589, 591, 614, 633, 635, 641, 32, 774, 32, 775, 32, 778,
32, 808, 32, 771, 32, 779, 661, 768, 787, 776, 769, 953, 881, 883, 697, 887, 32,
953, 59, 1011, 32, 776, 769, 940, 941, 942, 943, 972, 973, 974, 945, 946, 947, 948,
949, 950, 951, 952, 954, 955, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967,
968, 969, 970, 971, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005,
1007, 1016, 1019, 891, 892, 893, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1072, 1073, 1074, 1075, 1076, 1077,
1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091,
1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1121, 1123,
1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151,
1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187,
1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215,
1231, 1218, 1220, 1222, 1224, 1226, 1228, 1230, 1233, 1235, 1237, 1239, 1241, 1243,
1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271,
1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299,
1301, 1303, 1305, 1307, 1309, 1311, 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327,
1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390,
1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404,
1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1381, 1410, 1575, 1652,
1608, 1652, 1735, 1652, 1610, 1652, 2325, 2364, 2326, 2364, 2327, 2364, 2332, 2364,
2337, 2364, 2338, 2364, 2347, 2364, 2351, 2364, 2465, 2492, 2466, 2492, 2479, 2492,
2610, 2620, 2616, 2620, 2582, 2620, 2583, 2620, 2588, 2620, 2603, 2620, 2849, 2876,
2850, 2876, 3661, 3634, 3789, 3762, 3755, 3737, 3755, 3745, 3851, 3906, 4023, 3916,
4023, 3921, 4023, 3926, 4023, 3931, 4023, 3904, 4021, 3953, 3954, 3953, 3956, 4018,
3968, 4018, 3953, 3968, 4019, 3968, 4019, 3953, 3968, 3986, 4023, 3996, 4023, 4001,
4023, 4006, 4023, 4011, 4023, 3984, 4021, 11520, 11521, 11522, 11523, 11524, 11525,
11526, 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, 11535, 11536, 11537,
11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549,
11550, 11551, 11552, 11553, 11554, 11555, 11556, 11557, 11559, 11565, 4316, 5104,
5105, 5106, 5107, 5108, 5109, 42571, 7306, 4304, 4305, 4306, 4307, 4308, 4309, 4310,
4311, 4312, 4313, 4314, 4315, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325,
4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339,
4340, 4341, 4342, 4343, 4344, 4345, 4346, 4349, 4350, 4351, 592, 593, 7426, 604,
7446, 7447, 7453, 7461, 594, 597, 607, 609, 613, 618, 7547, 669, 621, 7557, 671,
625, 624, 627, 628, 632, 642, 427, 7452, 656, 657, 7681, 7683, 7685, 7687, 7689,
7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717,
7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745,
7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773,
7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801,
7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 7829,
97, 702, 223, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861,
7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889,
7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917,
7919, 7921, 7923, 7925, 7927, 7929, 7931, 7933, 7935, 7936, 7937, 7938, 7939, 7940,
7941, 7942, 7943, 7952, 7953, 7954, 7955, 7956, 7957, 7968, 7969, 7970, 7971, 7972,
7973, 7974, 7975, 7984, 7985, 7986, 7987, 7988, 7989, 7990, 7991, 8000, 8001, 8002,
8003, 8004, 8005, 8017, 8019, 8021, 8023, 8032, 8033, 8034, 8035, 8036, 8037, 8038,
8039, 7936, 953, 7937, 953, 7938, 953, 7939, 953, 7940, 953, 7941, 953, 7942, 953,
7943, 953, 7968, 953, 7969, 953, 7970, 953, 7971, 953, 7972, 953, 7973, 953, 7974,
953, 7975, 953, 8032, 953, 8033, 953, 8034, 953, 8035, 953, 8036, 953, 8037, 953,
8038, 953, 8039, 953, 8048, 953, 945, 953, 940, 953, 8118, 953, 8112, 8113, 32,
787, 32, 834, 32, 776, 834, 8052, 953, 951, 953, 942, 953, 8134, 953, 8050, 32,
787, 768, 32, 787, 769, 32, 787, 834, 912, 8144, 8145, 8054, 32, 788, 768, 32, 788,
769, 32, 788, 834, 944, 8160, 8161, 8058, 8165, 32, 776, 768, 96, 8060, 953, 969,
953, 974, 953, 8182, 953, 8056, 8208, 32, 819, 8242, 8242, 8242, 8242, 8242, 8245,
8245, 8245, 8245, 8245, 33, 33, 32, 773, 63, 63, 63, 33, 33, 63, 48, 53, 54, 55,
56, 57, 43, 8722, 61, 40, 41, 97, 47, 99, 97, 47, 115, 176, 99, 99, 47, 111, 99,
47, 117, 176, 102, 115, 109, 116, 101, 108, 116, 109, 8526, 1488, 1489, 1490, 1491,
102, 97, 120, 8721, 49, 8260, 55, 49, 8260, 57, 49, 8260, 49, 48, 49, 8260, 51,
50, 8260, 51, 49, 8260, 53, 50, 8260, 53, 51, 8260, 53, 52, 8260, 53, 49, 8260,
54, 53, 8260, 54, 49, 8260, 56, 51, 8260, 56, 53, 8260, 56, 55, 8260, 56, 105, 105,
105, 105, 105, 105, 118, 118, 105, 118, 105, 105, 118, 105, 105, 105, 105, 120,
120, 105, 120, 105, 105, 8580, 48, 8260, 51, 8747, 8747, 8747, 8747, 8747, 8750,
8750, 8750, 8750, 8750, 12296, 12297, 49, 50, 49, 51, 49, 52, 49, 53, 49, 54, 49,
55, 49, 56, 49, 57, 50, 48, 40, 49, 41, 40, 50, 41, 40, 51, 41, 40, 52, 41, 40,
53, 41, 40, 54, 41, 40, 55, 41, 40, 56, 41, 40, 57, 41, 40, 49, 48, 41, 40, 49,
49, 41, 40, 49, 50, 41, 40, 49, 51, 41, 40, 49, 52, 41, 40, 49, 53, 41, 40, 49,
54, 41, 40, 49, 55, 41, 40, 49, 56, 41, 40, 49, 57, 41, 40, 50, 48, 41, 40, 97,
41, 40, 98, 41, 40, 99, 41, 40, 100, 41, 40, 101, 41, 40, 102, 41, 40, 103, 41,
40, 104, 41, 40, 105, 41, 40, 106, 41, 40, 107, 41, 40, 108, 41, 40, 109, 41, 40,
110, 41, 40, 111, 41, 40, 112, 41, 40, 113, 41, 40, 114, 41, 40, 115, 41, 40, 116,
41, 40, 117, 41, 40, 118, 41, 40, 119, 41, 40, 120, 41, 40, 121, 41, 40, 122, 41,
58, 58, 61, 61, 61, 10973, 824, 11312, 11313, 11314, 11315, 11316, 11317, 11318,
11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327, 11328, 11329, 11330,
11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342,
11343, 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354,
11355, 11356, 11357, 11358, 11359, 11361, 619, 7549, 637, 11368, 11370, 11372, 11379,
11382, 575, 576, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409,
11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433,
11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457,
11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481,
11483, 11485, 11487, 11489, 11491, 11500, 11502, 11507, 11617, 27597, 40863, 19968,
20008, 20022, 20031, 20057, 20101, 20108, 20128, 20154, 20799, 20837, 20843, 20866,
20886, 20907, 20960, 20981, 20992, 21147, 21241, 21269, 21274, 21304, 21313, 21340,
21353, 21378, 21430, 21448, 21475, 22231, 22303, 22763, 22786, 22794, 22805, 22823,
22899, 23376, 23424, 23544, 23567, 23586, 23608, 23662, 23665, 24027, 24037, 24049,
24062, 24178, 24186, 24191, 24308, 24318, 24331, 24339, 24400, 24417, 24435, 24515,
25096, 25142, 25163, 25903, 25908, 25991, 26007, 26020, 26041, 26080, 26085, 26352,
26376, 26408, 27424, 27490, 27513, 27571, 27595, 27604, 27611, 27663, 27668, 27700,
28779, 29226, 29238, 29243, 29247, 29255, 29273, 29275, 29356, 29572, 29577, 29916,
29926, 29976, 29983, 29992, 30000, 30091, 30098, 30326, 30333, 30382, 30399, 30446,
30683, 30690, 30707, 31034, 31160, 31166, 31348, 31435, 31481, 31859, 31992, 32566,
32593, 32650, 32701, 32769, 32780, 32786, 32819, 32895, 32905, 33251, 33258, 33267,
33276, 33292, 33307, 33311, 33390, 33394, 33400, 34381, 34411, 34880, 34892, 34915,
35198, 35211, 35282, 35328, 35895, 35910, 35925, 35960, 35997, 36196, 36208, 36275,
36523, 36554, 36763, 36784, 36789, 37009, 37193, 37318, 37324, 37329, 38263, 38272,
38428, 38582, 38585, 38632, 38737, 38750, 38754, 38761, 38859, 38893, 38899, 38913,
39080, 39131, 39135, 39318, 39321, 39340, 39592, 39640, 39647, 39717, 39727, 39730,
39740, 39770, 40165, 40565, 40575, 40613, 40635, 40643, 40653, 40657, 40697, 40701,
40718, 40723, 40736, 40763, 40778, 40786, 40845, 40860, 40864, 46, 12306, 21316,
21317, 32, 12441, 32, 12442, 12424, 12426, 12467, 12488, 4352, 4353, 4522, 4354,
4524, 4525, 4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, 4533, 4378, 4358, 4359,
4360, 4385, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4449, 4450,
4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464,
4465, 4466, 4467, 4468, 4469, 4372, 4373, 4551, 4552, 4556, 4558, 4563, 4567, 4569,
4380, 4573, 4575, 4381, 4382, 4384, 4386, 4387, 4391, 4393, 4395, 4396, 4397, 4398,
4399, 4402, 4406, 4416, 4423, 4428, 4593, 4594, 4439, 4440, 4441, 4484, 4485, 4488,
4497, 4498, 4500, 4510, 4513, 19977, 22235, 19978, 20013, 19979, 30002, 19993, 19969,
22825, 22320, 40, 4352, 41, 40, 4354, 41, 40, 4355, 41, 40, 4357, 41, 40, 4358,
41, 40, 4359, 41, 40, 4361, 41, 40, 4363, 41, 40, 4364, 41, 40, 4366, 41, 40, 4367,
41, 40, 4368, 41, 40, 4369, 41, 40, 4370, 41, 40, 44032, 41, 40, 45208, 41, 40,
45796, 41, 40, 46972, 41, 40, 47560, 41, 40, 48148, 41, 40, 49324, 41, 40, 50500,
41, 40, 51088, 41, 40, 52264, 41, 40, 52852, 41, 40, 53440, 41, 40, 54028, 41, 40,
54616, 41, 40, 51452, 41, 40, 50724, 51204, 41, 40, 50724, 54980, 41, 40, 19968,
41, 40, 20108, 41, 40, 19977, 41, 40, 22235, 41, 40, 20116, 41, 40, 20845, 41, 40,
19971, 41, 40, 20843, 41, 40, 20061, 41, 40, 21313, 41, 40, 26376, 41, 40, 28779,
41, 40, 27700, 41, 40, 26408, 41, 40, 37329, 41, 40, 22303, 41, 40, 26085, 41, 40,
26666, 41, 40, 26377, 41, 40, 31038, 41, 40, 21517, 41, 40, 29305, 41, 40, 36001,
41, 40, 31069, 41, 40, 21172, 41, 40, 20195, 41, 40, 21628, 41, 40, 23398, 41, 40,
30435, 41, 40, 20225, 41, 40, 36039, 41, 40, 21332, 41, 40, 31085, 41, 40, 20241,
41, 40, 33258, 41, 40, 33267, 41, 21839, 24188, 31631, 112, 116, 101, 50, 50, 50,
52, 50, 53, 50, 54, 50, 55, 50, 56, 50, 57, 51, 48, 51, 51, 51, 52, 51, 53, 52280,
44256, 51452, 51032, 50864, 31192, 30007, 36969, 20778, 21360, 27880, 38917, 20889,
27491, 24038, 21491, 21307, 23447, 22812, 51, 54, 51, 55, 51, 56, 51, 57, 52, 48,
52, 52, 52, 53, 52, 54, 52, 55, 52, 56, 52, 57, 53, 48, 49, 26376, 50, 26376, 51,
26376, 52, 26376, 53, 26376, 54, 26376, 55, 26376, 56, 26376, 57, 26376, 49, 48,
26376, 49, 49, 26376, 49, 50, 26376, 104, 103, 101, 114, 103, 101, 118, 108, 116,
100, 12450, 12452, 12454, 12456, 12458, 12459, 12461, 12463, 12465, 12469, 12471,
12473, 12475, 12477, 12479, 12481, 12484, 12486, 12490, 12491, 12492, 12493, 12494,
12495, 12498, 12501, 12504, 12507, 12510, 12511, 12512, 12513, 12514, 12516, 12518,
12520, 12521, 12522, 12523, 12524, 12525, 12527, 12528, 12529, 12530, 20196, 21644,
12450, 12497, 12540, 12488, 12450, 12523, 12501, 12449, 12450, 12531, 12506, 12450,
12450, 12540, 12523, 12452, 12491, 12531, 12464, 12452, 12531, 12481, 12454, 12457,
12531, 12456, 12473, 12463, 12540, 12489, 12456, 12540, 12459, 12540, 12458, 12531,
12473, 12458, 12540, 12512, 12459, 12452, 12522, 12459, 12521, 12483, 12488, 12459,
12525, 12522, 12540, 12460, 12525, 12531, 12460, 12531, 12510, 12462, 12460, 12462,
12491, 12540, 12461, 12517, 12522, 12540, 12462, 12523, 12480, 12540, 12461, 12525,
12461, 12525, 12464, 12521, 12512, 12461, 12525, 12513, 12540, 12488, 12523, 12461,
12525, 12527, 12483, 12488, 12464, 12521, 12512, 12488, 12531, 12463, 12523, 12476,
12452, 12525, 12463, 12525, 12540, 12493, 12465, 12540, 12473, 12467, 12523, 12490,
12467, 12540, 12509, 12469, 12452, 12463, 12523, 12469, 12531, 12481, 12540, 12512,
12471, 12522, 12531, 12464, 12475, 12531, 12481, 12475, 12531, 12488, 12480, 12540,
12473, 12487, 12471, 12489, 12523, 12490, 12494, 12494, 12483, 12488, 12495, 12452,
12484, 12497, 12540, 12475, 12531, 12488, 12497, 12540, 12484, 12496, 12540, 12524,
12523, 12500, 12450, 12473, 12488, 12523, 12500, 12463, 12523, 12500, 12467, 12499,
12523, 12501, 12449, 12521, 12483, 12489, 12501, 12451, 12540, 12488, 12502, 12483,
12471, 12455, 12523, 12501, 12521, 12531, 12504, 12463, 12479, 12540, 12523, 12506,
12477, 12506, 12491, 12498, 12504, 12523, 12484, 12506, 12531, 12473, 12506, 12540,
12472, 12505, 12540, 12479, 12509, 12452, 12531, 12488, 12508, 12523, 12488, 12507,
12531, 12509, 12531, 12489, 12507, 12540, 12523, 12507, 12540, 12531, 12510, 12452,
12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, 12510, 12523, 12463, 12510,
12531, 12471, 12519, 12531, 12511, 12463, 12525, 12531, 12511, 12522, 12511, 12522,
12496, 12540, 12523, 12513, 12460, 12513, 12460, 12488, 12531, 12516, 12540, 12489,
12516, 12540, 12523, 12518, 12450, 12531, 12522, 12483, 12488, 12523, 12522, 12521,
12523, 12500, 12540, 12523, 12540, 12502, 12523, 12524, 12512, 12524, 12531, 12488,
12466, 12531, 48, 28857, 49, 28857, 50, 28857, 51, 28857, 52, 28857, 53, 28857,
54, 28857, 55, 28857, 56, 28857, 57, 28857, 49, 48, 28857, 49, 49, 28857, 49, 50,
28857, 49, 51, 28857, 49, 52, 28857, 49, 53, 28857, 49, 54, 28857, 49, 55, 28857,
49, 56, 28857, 49, 57, 28857, 50, 48, 28857, 50, 49, 28857, 50, 50, 28857, 50, 51,
28857, 50, 52, 28857, 104, 112, 97, 100, 97, 97, 117, 98, 97, 114, 111, 118, 112,
99, 100, 109, 100, 109, 50, 100, 109, 51, 105, 117, 24179, 25104, 26157, 21644,
22823, 27491, 26126, 27835, 26666, 24335, 20250, 31038, 110, 97, 956, 97, 109, 97,
107, 97, 107, 98, 109, 98, 103, 98, 99, 97, 108, 107, 99, 97, 108, 112, 102, 110,
102, 956, 102, 956, 103, 109, 103, 107, 103, 104, 122, 107, 104, 122, 109, 104,
122, 116, 104, 122, 956, 108, 109, 108, 100, 108, 102, 109, 110, 109, 956, 109,
109, 109, 99, 109, 107, 109, 109, 109, 50, 99, 109, 50, 107, 109, 50, 109, 109,
51, 99, 109, 51, 107, 109, 51, 109, 8725, 115, 109, 8725, 115, 50, 107, 112, 97,
109, 112, 97, 103, 112, 97, 114, 97, 100, 114, 97, 100, 8725, 115, 114, 97, 100,
8725, 115, 50, 112, 115, 110, 115, 956, 115, 109, 115, 112, 118, 110, 118, 956,
118, 109, 118, 107, 118, 112, 119, 110, 119, 956, 119, 109, 119, 107, 119, 107,
969, 109, 969, 98, 113, 99, 8725, 107, 103, 100, 98, 103, 121, 104, 97, 105, 110,
107, 107, 107, 116, 108, 110, 108, 111, 103, 108, 120, 109, 105, 108, 109, 111,
108, 112, 104, 112, 112, 109, 112, 114, 115, 118, 119, 98, 118, 8725, 109, 97, 8725,
109, 49, 26085, 50, 26085, 51, 26085, 52, 26085, 53, 26085, 54, 26085, 55, 26085,
56, 26085, 57, 26085, 49, 48, 26085, 49, 49, 26085, 49, 50, 26085, 49, 51, 26085,
49, 52, 26085, 49, 53, 26085, 49, 54, 26085, 49, 55, 26085, 49, 56, 26085, 49, 57,
26085, 50, 48, 26085, 50, 49, 26085, 50, 50, 26085, 50, 51, 26085, 50, 52, 26085,
50, 53, 26085, 50, 54, 26085, 50, 55, 26085, 50, 56, 26085, 50, 57, 26085, 51, 48,
26085, 51, 49, 26085, 103, 97, 108, 42561, 42563, 42565, 42567, 42569, 42573, 42575,
42577, 42579, 42581, 42583, 42585, 42587, 42589, 42591, 42593, 42595, 42597, 42599,
42601, 42603, 42605, 42625, 42627, 42629, 42631, 42633, 42635, 42637, 42639, 42641,
42643, 42645, 42647, 42649, 42651, 42787, 42789, 42791, 42793, 42795, 42797, 42799,
42803, 42805, 42807, 42809, 42811, 42813, 42815, 42817, 42819, 42821, 42823, 42825,
42827, 42829, 42831, 42833, 42835, 42837, 42839, 42841, 42843, 42845, 42847, 42849,
42851, 42853, 42855, 42857, 42859, 42861, 42863, 42874, 42876, 7545, 42879, 42881,
42883, 42885, 42887, 42892, 42897, 42899, 42903, 42905, 42907, 42909, 42911, 42913,
42915, 42917, 42919, 42921, 620, 670, 647, 43859, 42933, 42935, 42937, 42939, 42941,
42943, 42945, 42947, 42900, 7566, 42952, 42954, 612, 42957, 42961, 42967, 42969,
42971, 411, 42998, 43831, 43858, 653, 5024, 5025, 5026, 5027, 5028, 5029, 5030,
5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044,
5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058,
5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072,
5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086,
5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100,
5101, 5102, 5103, 35912, 26356, 36040, 28369, 20018, 21477, 22865, 21895, 22856,
25078, 30313, 32645, 34367, 34746, 35064, 37007, 27138, 27931, 28889, 29662, 33853,
37226, 39409, 20098, 21365, 27396, 29211, 34349, 40478, 23888, 28651, 34253, 35172,
25289, 33240, 34847, 24266, 26391, 28010, 29436, 37070, 20358, 20919, 21214, 25796,
27347, 29200, 30439, 34310, 34396, 36335, 38706, 39791, 40442, 30860, 31103, 32160,
33737, 37636, 35542, 22751, 24324, 31840, 32894, 29282, 30922, 36034, 38647, 22744,
23650, 27155, 28122, 28431, 32047, 32311, 38475, 21202, 32907, 20956, 20940, 31260,
32190, 33777, 38517, 35712, 25295, 35582, 20025, 23527, 24594, 29575, 30064, 21271,
30971, 20415, 24489, 19981, 27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498,
27578, 27784, 25342, 33509, 25504, 30053, 20142, 20841, 20937, 26753, 31975, 33391,
35538, 37327, 21237, 21570, 24300, 26053, 28670, 31018, 38317, 39530, 40599, 40654,
26310, 27511, 36706, 24180, 24976, 25088, 25754, 28451, 29001, 29833, 31178, 32244,
32879, 36646, 34030, 36899, 37706, 21015, 21155, 21693, 28872, 35010, 24265, 24565,
25467, 27566, 31806, 29557, 22265, 23994, 24604, 29618, 29801, 32666, 32838, 37428,
38646, 38728, 38936, 20363, 31150, 37300, 38584, 24801, 20102, 20698, 23534, 23615,
26009, 29134, 30274, 34044, 36988, 26248, 38446, 21129, 26491, 26611, 27969, 28316,
29705, 30041, 30827, 32016, 39006, 25134, 38520, 20523, 23833, 28138, 36650, 24459,
24900, 26647, 38534, 21033, 21519, 23653, 26131, 26446, 26792, 27877, 29702, 30178,
32633, 35023, 35041, 38626, 21311, 28346, 21533, 29136, 29848, 34298, 38563, 40023,
40607, 26519, 28107, 33256, 31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050,
20999, 24230, 25299, 31958, 23429, 27934, 26292, 36667, 38477, 24275, 20800, 21952,
22618, 26228, 20958, 29482, 30410, 31036, 31070, 31077, 31119, 38742, 31934, 34322,
35576, 36920, 37117, 39151, 39164, 39208, 40372, 37086, 38583, 20398, 20711, 20813,
21193, 21220, 21329, 21917, 22022, 22120, 22592, 22696, 23652, 24724, 24936, 24974,
25074, 25935, 26082, 26257, 26757, 28023, 28186, 28450, 29038, 29227, 29730, 30865,
31049, 31048, 31056, 31062, 31117, 31118, 31296, 31361, 31680, 32265, 32321, 32626,
32773, 33261, 33401, 33879, 35088, 35222, 35585, 35641, 36051, 36104, 36790, 38627,
38911, 38971, 24693, 148206, 33304, 20006, 20917, 20840, 20352, 20805, 20864, 21191,
21242, 21845, 21913, 21986, 22707, 22852, 22868, 23138, 23336, 24274, 24281, 24425,
24493, 24792, 24910, 24840, 24928, 25140, 25540, 25628, 25682, 25942, 26395, 26454,
28379, 28363, 28702, 30631, 29237, 29359, 29809, 29958, 30011, 30237, 30239, 30427,
30452, 30538, 30528, 30924, 31409, 31867, 32091, 32574, 33618, 33775, 34681, 35137,
35206, 35519, 35531, 35565, 35722, 36664, 36978, 37273, 37494, 38524, 38875, 38923,
39698, 141386, 141380, 144341, 15261, 16408, 16441, 152137, 154832, 163539, 40771,
40846, 102, 102, 102, 105, 102, 108, 102, 102, 108, 1396, 1398, 1396, 1381, 1396,
1387, 1406, 1398, 1396, 1389, 1497, 1460, 1522, 1463, 1506, 1492, 1499, 1500, 1501,
1512, 1514, 1513, 1473, 1513, 1474, 1513, 1468, 1473, 1513, 1468, 1474, 1488, 1463,
1488, 1464, 1488, 1468, 1489, 1468, 1490, 1468, 1491, 1468, 1492, 1468, 1493, 1468,
1494, 1468, 1496, 1468, 1497, 1468, 1498, 1468, 1499, 1468, 1500, 1468, 1502, 1468,
1504, 1468, 1505, 1468, 1507, 1468, 1508, 1468, 1510, 1468, 1511, 1468, 1512, 1468,
1514, 1468, 1493, 1465, 1489, 1471, 1499, 1471, 1508, 1471, 1488, 1500, 1649, 1659,
1662, 1664, 1658, 1663, 1657, 1700, 1702, 1668, 1667, 1670, 1671, 1677, 1676, 1678,
1672, 1688, 1681, 1705, 1711, 1715, 1713, 1722, 1723, 1728, 1729, 1726, 1746, 1747,
1709, 1734, 1736, 1739, 1733, 1737, 1744, 1609, 1574, 1575, 1574, 1749, 1574, 1608,
1574, 1735, 1574, 1734, 1574, 1736, 1574, 1744, 1574, 1609, 1740, 1574, 1580, 1574,
1581, 1574, 1605, 1574, 1610, 1576, 1580, 1576, 1581, 1576, 1582, 1576, 1605, 1576,
1609, 1576, 1610, 1578, 1580, 1578, 1581, 1578, 1582, 1578, 1605, 1578, 1609, 1578,
1610, 1579, 1580, 1579, 1605, 1579, 1609, 1579, 1610, 1580, 1581, 1580, 1605, 1581,
1605, 1582, 1580, 1582, 1581, 1582, 1605, 1587, 1580, 1587, 1581, 1587, 1582, 1587,
1605, 1589, 1581, 1589, 1605, 1590, 1580, 1590, 1581, 1590, 1582, 1590, 1605, 1591,
1581, 1591, 1605, 1592, 1605, 1593, 1580, 1593, 1605, 1594, 1580, 1594, 1605, 1601,
1580, 1601, 1581, 1601, 1582, 1601, 1605, 1601, 1609, 1601, 1610, 1602, 1581, 1602,
1605, 1602, 1609, 1602, 1610, 1603, 1575, 1603, 1580, 1603, 1581, 1603, 1582, 1603,
1604, 1603, 1605, 1603, 1609, 1603, 1610, 1604, 1580, 1604, 1581, 1604, 1582, 1604,
1605, 1604, 1609, 1604, 1610, 1605, 1580, 1605, 1605, 1605, 1609, 1605, 1610, 1606,
1580, 1606, 1581, 1606, 1582, 1606, 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607,
1605, 1607, 1609, 1607, 1610, 1610, 1581, 1610, 1582, 1610, 1609, 1584, 1648, 1585,
1648, 1609, 1648, 32, 1612, 1617, 32, 1613, 1617, 32, 1614, 1617, 32, 1615, 1617,
32, 1616, 1617, 32, 1617, 1648, 1574, 1585, 1574, 1586, 1574, 1606, 1576, 1585,
1576, 1586, 1576, 1606, 1578, 1585, 1578, 1586, 1578, 1606, 1579, 1585, 1579, 1586,
1579, 1606, 1605, 1575, 1606, 1585, 1606, 1586, 1606, 1606, 1610, 1585, 1610, 1586,
1574, 1582, 1574, 1607, 1576, 1607, 1578, 1607, 1589, 1582, 1604, 1607, 1606, 1607,
1607, 1648, 1579, 1607, 1587, 1607, 1588, 1605, 1588, 1607, 1600, 1614, 1617, 1600,
1615, 1617, 1600, 1616, 1617, 1591, 1609, 1591, 1610, 1593, 1609, 1593, 1610, 1594,
1609, 1594, 1610, 1587, 1609, 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609, 1580,
1609, 1580, 1610, 1582, 1609, 1589, 1609, 1589, 1610, 1590, 1609, 1590, 1610, 1588,
1580, 1588, 1581, 1588, 1582, 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585, 1575,
1611, 1578, 1580, 1605, 1578, 1581, 1580, 1578, 1581, 1605, 1578, 1582, 1605, 1578,
1605, 1580, 1578, 1605, 1581, 1578, 1605, 1582, 1581, 1605, 1610, 1581, 1605, 1609,
1587, 1581, 1580, 1587, 1580, 1581, 1587, 1580, 1609, 1587, 1605, 1581, 1587, 1605,
1580, 1587, 1605, 1605, 1589, 1581, 1581, 1589, 1605, 1605, 1588, 1581, 1605, 1588,
1580, 1610, 1588, 1605, 1582, 1588, 1605, 1605, 1590, 1581, 1609, 1590, 1582, 1605,
1591, 1605, 1581, 1591, 1605, 1605, 1591, 1605, 1610, 1593, 1580, 1605, 1593, 1605,
1605, 1593, 1605, 1609, 1594, 1605, 1605, 1594, 1605, 1610, 1594, 1605, 1609, 1601,
1582, 1605, 1602, 1605, 1581, 1602, 1605, 1605, 1604, 1581, 1605, 1604, 1581, 1610,
1604, 1581, 1609, 1604, 1580, 1580, 1604, 1582, 1605, 1604, 1605, 1581, 1605, 1581,
1580, 1605, 1581, 1610, 1605, 1580, 1581, 1605, 1582, 1605, 1605, 1580, 1582, 1607,
1605, 1580, 1607, 1605, 1605, 1606, 1581, 1605, 1606, 1581, 1609, 1606, 1580, 1605,
1606, 1580, 1609, 1606, 1605, 1610, 1606, 1605, 1609, 1610, 1605, 1605, 1576, 1582,
1610, 1578, 1580, 1610, 1578, 1580, 1609, 1578, 1582, 1610, 1578, 1582, 1609, 1578,
1605, 1610, 1578, 1605, 1609, 1580, 1605, 1610, 1580, 1581, 1609, 1580, 1605, 1609,
1587, 1582, 1609, 1589, 1581, 1610, 1588, 1581, 1610, 1590, 1581, 1610, 1604, 1580,
1610, 1604, 1605, 1610, 1610, 1580, 1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602,
1605, 1610, 1606, 1581, 1610, 1593, 1605, 1610, 1603, 1605, 1610, 1606, 1580, 1581,
1605, 1582, 1610, 1604, 1580, 1605, 1603, 1605, 1605, 1580, 1581, 1610, 1581, 1580,
1610, 1605, 1580, 1610, 1601, 1605, 1610, 1576, 1581, 1610, 1587, 1582, 1610, 1606,
1580, 1610, 1589, 1604, 1746, 1602, 1604, 1746, 1575, 1604, 1604, 1607, 1575, 1603,
1576, 1585, 1605, 1581, 1605, 1583, 1589, 1604, 1593, 1605, 1585, 1587, 1608, 1604,
1593, 1604, 1610, 1607, 1608, 1587, 1604, 1605, 1589, 1604, 1609, 1589, 1604, 1609,
32, 1575, 1604, 1604, 1607, 32, 1593, 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605,
1580, 1604, 32, 1580, 1604, 1575, 1604, 1607, 1585, 1740, 1575, 1604, 44, 12289,
12310, 12311, 8212, 8211, 95, 123, 125, 12308, 12309, 12304, 12305, 12298, 12299,
12300, 12301, 12302, 12303, 91, 93, 35, 38, 42, 45, 60, 62, 92, 36, 37, 64, 32,
1611, 1600, 1611, 1600, 1617, 32, 1618, 1600, 1618, 1569, 1570, 1571, 1572, 1573,
1577, 1604, 1570, 1604, 1571, 1604, 1573, 34, 39, 94, 124, 126, 10629, 10630, 12539,
12453, 12515, 162, 163, 172, 166, 165, 8361, 9474, 8592, 8593, 8594, 8595, 9632,
9675, 66600, 66601, 66602, 66603, 66604, 66605, 66606, 66607, 66608, 66609, 66610,
66611, 66612, 66613, 66614, 66615, 66616, 66617, 66618, 66619, 66620, 66621, 66622,
66623, 66624, 66625, 66626, 66627, 66628, 66629, 66630, 66631, 66632, 66633, 66634,
66635, 66636, 66637, 66638, 66639, 66776, 66777, 66778, 66779, 66780, 66781, 66782,
66783, 66784, 66785, 66786, 66787, 66788, 66789, 66790, 66791, 66792, 66793, 66794,
66795, 66796, 66797, 66798, 66799, 66800, 66801, 66802, 66803, 66804, 66805, 66806,
66807, 66808, 66809, 66810, 66811, 66967, 66968, 66969, 66970, 66971, 66972, 66973,
66974, 66975, 66976, 66977, 66979, 66980, 66981, 66982, 66983, 66984, 66985, 66986,
66987, 66988, 66989, 66990, 66991, 66992, 66993, 66995, 66996, 66997, 66998, 66999,
67000, 67001, 67003, 67004, 720, 721, 665, 675, 43878, 677, 676, 7569, 600, 606,
681, 610, 667, 668, 615, 644, 682, 683, 122628, 42894, 622, 122629, 654, 122630,
630, 631, 634, 122632, 638, 680, 678, 43879, 679, 11377, 655, 673, 674, 664, 448,
449, 450, 122634, 122654, 68800, 68801, 68802, 68803, 68804, 68805, 68806, 68807,
68808, 68809, 68810, 68811, 68812, 68813, 68814, 68815, 68816, 68817, 68818, 68819,
68820, 68821, 68822, 68823, 68824, 68825, 68826, 68827, 68828, 68829, 68830, 68831,
68832, 68833, 68834, 68835, 68836, 68837, 68838, 68839, 68840, 68841, 68842, 68843,
68844, 68845, 68846, 68847, 68848, 68849, 68850, 68976, 68977, 68978, 68979, 68980,
68981, 68982, 68983, 68984, 68985, 68986, 68987, 68988, 68989, 68990, 68991, 68992,
68993, 68994, 68995, 68996, 68997, 71872, 71873, 71874, 71875, 71876, 71877, 71878,
71879, 71880, 71881, 71882, 71883, 71884, 71885, 71886, 71887, 71888, 71889, 71890,
71891, 71892, 71893, 71894, 71895, 71896, 71897, 71898, 71899, 71900, 71901, 71902,
71903, 93792, 93793, 93794, 93795, 93796, 93797, 93798, 93799, 93800, 93801, 93802,
93803, 93804, 93805, 93806, 93807, 93808, 93809, 93810, 93811, 93812, 93813, 93814,
93815, 93816, 93817, 93818, 93819, 93820, 93821, 93822, 93823, 119127, 119141, 119128,
119141, 119128, 119141, 119150, 119128, 119141, 119151, 119128, 119141, 119152,
119128, 119141, 119153, 119128, 119141, 119154, 119225, 119141, 119226, 119141,
119225, 119141, 119150, 119226, 119141, 119150, 119225, 119141, 119151, 119226,
119141, 119151, 305, 567, 8711, 8706, 125218, 125219, 125220, 125221, 125222, 125223,
125224, 125225, 125226, 125227, 125228, 125229, 125230, 125231, 125232, 125233,
125234, 125235, 125236, 125237, 125238, 125239, 125240, 125241, 125242, 125243,
125244, 125245, 125246, 125247, 125248, 125249, 125250, 125251, 1646, 1697, 1647,
48, 44, 49, 44, 50, 44, 51, 44, 52, 44, 53, 44, 54, 44, 55, 44, 56, 44, 57, 44,
12308, 115, 12309, 119, 122, 104, 118, 115, 100, 115, 115, 112, 112, 118, 119, 99,
109, 114, 100, 106, 12411, 12363, 12467, 12467, 23383, 21452, 22810, 35299, 20132,
26144, 28961, 21069, 24460, 20877, 26032, 21021, 32066, 36009, 22768, 21561, 28436,
25237, 25429, 36938, 25351, 25171, 31105, 31354, 21512, 28288, 30003, 21106, 21942,
37197, 12308, 26412, 12309, 12308, 19977, 12309, 12308, 20108, 12309, 12308, 23433,
12309, 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423, 12309, 12308, 21213,
12309, 12308, 25943, 12309, 24471, 21487, 20029, 20024, 20033, 131362, 20320, 20411,
20482, 20602, 20633, 20687, 13470, 132666, 20820, 20836, 20855, 132380, 13497, 20839,
132427, 20887, 20900, 20172, 20908, 168415, 20995, 13535, 21051, 21062, 21111, 13589,
21253, 21254, 21321, 21338, 21363, 21373, 21375, 133676, 28784, 21450, 21471, 133987,
21483, 21489, 21510, 21662, 21560, 21576, 21608, 21666, 21750, 21776, 21843, 21859,
21892, 21931, 21939, 21954, 22294, 22295, 22097, 22132, 22766, 22478, 22516, 22541,
22411, 22578, 22577, 22700, 136420, 22770, 22775, 22790, 22818, 22882, 136872, 136938,
23020, 23067, 23079, 23000, 23142, 14062, 14076, 23304, 23358, 137672, 23491, 23512,
23539, 138008, 23551, 23558, 24403, 14209, 23648, 23744, 23693, 138724, 23875, 138726,
23918, 23915, 23932, 24033, 24034, 14383, 24061, 24104, 24125, 24169, 14434, 139651,
14460, 24240, 24243, 24246, 172946, 140081, 33281, 24354, 14535, 144056, 156122,
24418, 24427, 14563, 24474, 24525, 24535, 24569, 24705, 14650, 14620, 141012, 24775,
24904, 24908, 24954, 25010, 24996, 25007, 25054, 25115, 25181, 25265, 25300, 25424,
142092, 25405, 25340, 25448, 25475, 25572, 142321, 25634, 25541, 25513, 14894, 25705,
25726, 25757, 25719, 14956, 25964, 143370, 26083, 26360, 26185, 15129, 15112, 15076,
20882, 20885, 26368, 26268, 32941, 17369, 26401, 26462, 26451, 144323, 15177, 26618,
26501, 26706, 144493, 26766, 26655, 26900, 26946, 27043, 27114, 27304, 145059, 27355,
15384, 27425, 145575, 27476, 15438, 27506, 27551, 27579, 146061, 138507, 146170,
27726, 146620, 27839, 27853, 27751, 27926, 27966, 28009, 28024, 28037, 146718, 27956,
28207, 28270, 15667, 28359, 147153, 28153, 28526, 147294, 147342, 28614, 28729,
28699, 15766, 28746, 28797, 28791, 28845, 132389, 28997, 148067, 29084, 148395,
29224, 29264, 149000, 29312, 29333, 149301, 149524, 29562, 29579, 16044, 29605,
16056, 29767, 29788, 29829, 29898, 16155, 29988, 150582, 30014, 150674, 139679,
30224, 151457, 151480, 151620, 16380, 16392, 151795, 151794, 151833, 151859, 30494,
30495, 30603, 16454, 16534, 152605, 30798, 16611, 153126, 153242, 153285, 31211,
16687, 31306, 31311, 153980, 154279, 31470, 16898, 154539, 31686, 31689, 16935,
154752, 31954, 17056, 31976, 31971, 32000, 155526, 32099, 17153, 32199, 32258, 32325,
17204, 156200, 156231, 17241, 156377, 32634, 156478, 32661, 32762, 156890, 156963,
32864, 157096, 32880, 144223, 17365, 32946, 33027, 17419, 33086, 23221, 157607,
157621, 144275, 144284, 33284, 36766, 17515, 33425, 33419, 33437, 21171, 33457,
33459, 33469, 33510, 158524, 33565, 33635, 33709, 33571, 33725, 33767, 33619, 33738,
33740, 33756, 158774, 159083, 158933, 17707, 34033, 34035, 34070, 160714, 34148,
159532, 17757, 17761, 159665, 159954, 17771, 34384, 34407, 34409, 34473, 34440,
34574, 34530, 34600, 34667, 34694, 17879, 34785, 34817, 17913, 34912, 161383, 35031,
35038, 17973, 35066, 13499, 161966, 162150, 18110, 18119, 35488, 162984, 36011,
36033, 36123, 36215, 163631, 133124, 36299, 36284, 36336, 133342, 36564, 165330,
165357, 37012, 37105, 37137, 165678, 37147, 37432, 37591, 37592, 37500, 37881, 37909,
166906, 38283, 18837, 38327, 167287, 18918, 38595, 23986, 38691, 168261, 168474,
19054, 19062, 38880, 168970, 19122, 169110, 38953, 169398, 39138, 19251, 39209,
39335, 39362, 39422, 19406, 170800, 40000, 40189, 19662, 19693, 40295, 172238, 19704,
172293, 172558, 172689, 19798, 40702, 40709, 40719, 40726, 173568,
};
const uint32_t table[8150][2] =
{
{0, 1}, {65, 16777219}, {66, 16777475}, {67, 16777731},
{68, 16777987}, {69, 16778243}, {70, 16778499}, {71, 16778755},
{72, 16779011}, {73, 16779267}, {74, 16779523}, {75, 16779779},
{76, 16780035}, {77, 16780291}, {78, 16780547}, {79, 16780803},
{80, 16781059}, {81, 16781315}, {82, 16781571}, {83, 16781827},
{84, 16782083}, {85, 16782339}, {86, 16782595}, {87, 16782851},
{88, 16783107}, {89, 16783363}, {90, 16783619}, {91, 1},
{128, 2}, {160, 16783875}, {161, 1}, {168, 33561347},
{169, 1}, {170, 16777219}, {171, 1}, {173, 0},
{174, 1}, {175, 33561859}, {176, 1}, {178, 16785155},
{179, 16785411}, {180, 33562883}, {181, 16786179}, {182, 1},
{184, 33563651}, {185, 16786947}, {186, 16780803}, {187, 1},
{188, 50341635}, {189, 50342403}, {190, 50343171}, {191, 1},
{192, 16789507}, {193, 16789763}, {194, 16790019}, {195, 16790275},
{196, 16790531}, {197, 16790787}, {198, 16791043}, {199, 16791299},
{200, 16791555}, {201, 16791811}, {202, 16792067}, {203, 16792323},
{204, 16792579}, {205, 16792835}, {206, 16793091}, {207, 16793347},
{208, 16793603}, {209, 16793859}, {210, 16794115}, {211, 16794371},
{212, 16794627}, {213, 16794883}, {214, 16795139}, {215, 1},
{216, 16795395}, {217, 16795651}, {218, 16795907}, {219, 16796163},
{220, 16796419}, {221, 16796675}, {222, 16796931}, {223, 1},
{256, 16797187}, {257, 1}, {258, 16797443}, {259, 1},
{260, 16797699}, {261, 1}, {262, 16797955}, {263, 1},
{264, 16798211}, {265, 1}, {266, 16798467}, {267, 1},
{268, 16798723}, {269, 1}, {270, 16798979}, {271, 1},
{272, 16799235}, {273, 1}, {274, 16799491}, {275, 1},
{276, 16799747}, {277, 1}, {278, 16800003}, {279, 1},
{280, 16800259}, {281, 1}, {282, 16800515}, {283, 1},
{284, 16800771}, {285, 1}, {286, 16801027}, {287, 1},
{288, 16801283}, {289, 1}, {290, 16801539}, {291, 1},
{292, 16801795}, {293, 1}, {294, 16802051}, {295, 1},
{296, 16802307}, {297, 1}, {298, 16802563}, {299, 1},
{300, 16802819}, {301, 1}, {302, 16803075}, {303, 1},
{304, 33580547}, {305, 1}, {306, 33556483}, {308, 16803843},
{309, 1}, {310, 16804099}, {311, 1}, {313, 16804355},
{314, 1}, {315, 16804611}, {316, 1}, {317, 16804867},
{318, 1}, {319, 33582339}, {321, 16805635}, {322, 1},
{323, 16805891}, {324, 1}, {325, 16806147}, {326, 1},
{327, 16806403}, {328, 1}, {329, 33583875}, {330, 16807171},
{331, 1}, {332, 16807427}, {333, 1}, {334, 16807683},
{335, 1}, {336, 16807939}, {337, 1}, {338, 16808195},
{339, 1}, {340, 16808451}, {341, 1}, {342, 16808707},
{343, 1}, {344, 16808963}, {345, 1}, {346, 16809219},
{347, 1}, {348, 16809475}, {349, 1}, {350, 16809731},
{351, 1}, {352, 16809987}, {353, 1}, {354, 16810243},
{355, 1}, {356, 16810499}, {357, 1}, {358, 16810755},
{359, 1}, {360, 16811011}, {361, 1}, {362, 16811267},
{363, 1}, {364, 16811523}, {365, 1}, {366, 16811779},
{367, 1}, {368, 16812035}, {369, 1}, {370, 16812291},
{371, 1}, {372, 16812547}, {373, 1}, {374, 16812803},
{375, 1}, {376, 16813059}, {377, 16813315}, {378, 1},
{379, 16813571}, {380, 1}, {381, 16813827}, {382, 1},
{383, 16781827}, {384, 1}, {385, 16814083}, {386, 16814339},
{387, 1}, {388, 16814595}, {389, 1}, {390, 16814851},
{391, 16815107}, {392, 1}, {393, 16815363}, {394, 16815619},
{395, 16815875}, {396, 1}, {398, 16816131}, {399, 16816387},
{400, 16816643}, {401, 16816899}, {402, 1}, {403, 16817155},
{404, 16817411}, {405, 1}, {406, 16817667}, {407, 16817923},
{408, 16818179}, {409, 1}, {412, 16818435}, {413, 16818691},
{414, 1}, {415, 16818947}, {416, 16819203}, {417, 1},
{418, 16819459}, {419, 1}, {420, 16819715}, {421, 1},
{422, 16819971}, {423, 16820227}, {424, 1}, {425, 16820483},
{426, 1}, {428, 16820739}, {429, 1}, {430, 16820995},
{431, 16821251}, {432, 1}, {433, 16821507}, {434, 16821763},
{435, 16822019}, {436, 1}, {437, 16822275}, {438, 1},
{439, 16822531}, {440, 16822787}, {441, 1}, {444, 16823043},
{445, 1}, {452, 33600515}, {455, 33601027}, {458, 33601539},
{461, 16824835}, {462, 1}, {463, 16825091}, {464, 1},
{465, 16825347}, {466, 1}, {467, 16825603}, {468, 1},
{469, 16825859}, {470, 1}, {471, 16826115}, {472, 1},
{473, 16826371}, {474, 1}, {475, 16826627}, {476, 1},
{478, 16826883}, {479, 1}, {480, 16827139}, {481, 1},
{482, 16827395}, {483, 1}, {484, 16827651}, {485, 1},
{486, 16827907}, {487, 1}, {488, 16828163}, {489, 1},
{490, 16828419}, {491, 1}, {492, 16828675}, {493, 1},
{494, 16828931}, {495, 1}, {497, 33606403}, {500, 16829699},
{501, 1}, {502, 16829955}, {503, 16830211}, {504, 16830467},
{505, 1}, {506, 16830723}, {507, 1}, {508, 16830979},
{509, 1}, {510, 16831235}, {511, 1}, {512, 16831491},
{513, 1}, {514, 16831747}, {515, 1}, {516, 16832003},
{517, 1}, {518, 16832259}, {519, 1}, {520, 16832515},
{521, 1}, {522, 16832771}, {523, 1}, {524, 16833027},
{525, 1}, {526, 16833283}, {527, 1}, {528, 16833539},
{529, 1}, {530, 16833795}, {531, 1}, {532, 16834051},
{533, 1}, {534, 16834307}, {535, 1}, {536, 16834563},
{537, 1}, {538, 16834819}, {539, 1}, {540, 16835075},
{541, 1}, {542, 16835331}, {543, 1}, {544, 16835587},
{545, 1}, {546, 16835843}, {547, 1}, {548, 16836099},
{549, 1}, {550, 16836355}, {551, 1}, {552, 16836611},
{553, 1}, {554, 16836867}, {555, 1}, {556, 16837123},
{557, 1}, {558, 16837379}, {559, 1}, {560, 16837635},
{561, 1}, {562, 16837891}, {563, 1}, {570, 16838147},
{571, 16838403}, {572, 1}, {573, 16838659}, {574, 16838915},
{575, 1}, {577, 16839171}, {578, 1}, {579, 16839427},
{580, 16839683}, {581, 16839939}, {582, 16840195}, {583, 1},
{584, 16840451}, {585, 1}, {586, 16840707}, {587, 1},
{588, 16840963}, {589, 1}, {590, 16841219}, {591, 1},
{688, 16779011}, {689, 16841475}, {690, 16779523}, {691, 16781571},
{692, 16841731}, {693, 16841987}, {694, 16842243}, {695, 16782851},
{696, 16783363}, {697, 1}, {728, 33619715}, {729, 33620227},
{730, 33620739}, {731, 33621251}, {732, 33621763}, {733, 33622275},
{734, 1}, {736, 16817411}, {737, 16780035}, {738, 16781827},
{739, 16783107}, {740, 16845571}, {741, 1}, {832, 16845827},
{833, 16785923}, {834, 1}, {835, 16846083}, {836, 33623555},
{837, 16846851}, {838, 1}, {847, 0}, {848, 1},
{880, 16847107}, {881, 1}, {882, 16847363}, {883, 1},
{884, 16847619}, {885, 1}, {886, 16847875}, {887, 1},
{888, 2}, {890, 33625347}, {891, 1}, {894, 16848643},
{895, 16848899}, {896, 2}, {900, 33562883}, {901, 50403587},
{902, 16849923}, {903, 16805379}, {904, 16850179}, {905, 16850435},
{906, 16850691}, {907, 2}, {908, 16850947}, {909, 2},
{910, 16851203}, {911, 16851459}, {912, 1}, {913, 16851715},
{914, 16851971}, {915, 16852227}, {916, 16852483}, {917, 16852739},
{918, 16852995}, {919, 16853251}, {920, 16853507}, {921, 16846851},
{922, 16853763}, {923, 16854019}, {924, 16786179}, {925, 16854275},
{926, 16854531}, {927, 16854787}, {928, 16855043}, {929, 16855299},
{930, 2}, {931, 16855555}, {932, 16855811}, {933, 16856067},
{934, 16856323}, {935, 16856579}, {936, 16856835}, {937, 16857091},
{938, 16857347}, {939, 16857603}, {940, 1}, {975, 16857859},
{976, 16851971}, {977, 16853507}, {978, 16856067}, {979, 16851203},
{980, 16857603}, {981, 16856323}, {982, 16855043}, {983, 1},
{984, 16858115}, {985, 1}, {986, 16858371}, {987, 1},
{988, 16858627}, {989, 1}, {990, 16858883}, {991, 1},
{992, 16859139}, {993, 1}, {994, 16859395}, {995, 1},
{996, 16859651}, {997, 1}, {998, 16859907}, {999, 1},
{1000, 16860163}, {1001, 1}, {1002, 16860419}, {1003, 1},
{1004, 16860675}, {1005, 1}, {1006, 16860931}, {1007, 1},
{1008, 16853763}, {1009, 16855299}, {1010, 16855555}, {1011, 1},
{1012, 16853507}, {1013, 16852739}, {1014, 1}, {1015, 16861187},
{1016, 1}, {1017, 16855555}, {1018, 16861443}, {1019, 1},
{1021, 16861699}, {1022, 16861955}, {1023, 16862211}, {1024, 16862467},
{1025, 16862723}, {1026, 16862979}, {1027, 16863235}, {1028, 16863491},
{1029, 16863747}, {1030, 16864003}, {1031, 16864259}, {1032, 16864515},
{1033, 16864771}, {1034, 16865027}, {1035, 16865283}, {1036, 16865539},
{1037, 16865795}, {1038, 16866051}, {1039, 16866307}, {1040, 16866563},
{1041, 16866819}, {1042, 16867075}, {1043, 16867331}, {1044, 16867587},
{1045, 16867843}, {1046, 16868099}, {1047, 16868355}, {1048, 16868611},
{1049, 16868867}, {1050, 16869123}, {1051, 16869379}, {1052, 16869635},
{1053, 16869891}, {1054, 16870147}, {1055, 16870403}, {1056, 16870659},
{1057, 16870915}, {1058, 16871171}, {1059, 16871427}, {1060, 16871683},
{1061, 16871939}, {1062, 16872195}, {1063, 16872451}, {1064, 16872707},
{1065, 16872963}, {1066, 16873219}, {1067, 16873475}, {1068, 16873731},
{1069, 16873987}, {1070, 16874243}, {1071, 16874499}, {1072, 1},
{1120, 16874755}, {1121, 1}, {1122, 16875011}, {1123, 1},
{1124, 16875267}, {1125, 1}, {1126, 16875523}, {1127, 1},
{1128, 16875779}, {1129, 1}, {1130, 16876035}, {1131, 1},
{1132, 16876291}, {1133, 1}, {1134, 16876547}, {1135, 1},
{1136, 16876803}, {1137, 1}, {1138, 16877059}, {1139, 1},
{1140, 16877315}, {1141, 1}, {1142, 16877571}, {1143, 1},
{1144, 16877827}, {1145, 1}, {1146, 16878083}, {1147, 1},
{1148, 16878339}, {1149, 1}, {1150, 16878595}, {1151, 1},
{1152, 16878851}, {1153, 1}, {1162, 16879107}, {1163, 1},
{1164, 16879363}, {1165, 1}, {1166, 16879619}, {1167, 1},
{1168, 16879875}, {1169, 1}, {1170, 16880131}, {1171, 1},
{1172, 16880387}, {1173, 1}, {1174, 16880643}, {1175, 1},
{1176, 16880899}, {1177, 1}, {1178, 16881155}, {1179, 1},
{1180, 16881411}, {1181, 1}, {1182, 16881667}, {1183, 1},
{1184, 16881923}, {1185, 1}, {1186, 16882179}, {1187, 1},
{1188, 16882435}, {1189, 1}, {1190, 16882691}, {1191, 1},
{1192, 16882947}, {1193, 1}, {1194, 16883203}, {1195, 1},
{1196, 16883459}, {1197, 1}, {1198, 16883715}, {1199, 1},
{1200, 16883971}, {1201, 1}, {1202, 16884227}, {1203, 1},
{1204, 16884483}, {1205, 1}, {1206, 16884739}, {1207, 1},
{1208, 16884995}, {1209, 1}, {1210, 16885251}, {1211, 1},
{1212, 16885507}, {1213, 1}, {1214, 16885763}, {1215, 1},
{1216, 16886019}, {1217, 16886275}, {1218, 1}, {1219, 16886531},
{1220, 1}, {1221, 16886787}, {1222, 1}, {1223, 16887043},
{1224, 1}, {1225, 16887299}, {1226, 1}, {1227, 16887555},
{1228, 1}, {1229, 16887811}, {1230, 1}, {1232, 16888067},
{1233, 1}, {1234, 16888323}, {1235, 1}, {1236, 16888579},
{1237, 1}, {1238, 16888835}, {1239, 1}, {1240, 16889091},
{1241, 1}, {1242, 16889347}, {1243, 1}, {1244, 16889603},
{1245, 1}, {1246, 16889859}, {1247, 1}, {1248, 16890115},
{1249, 1}, {1250, 16890371}, {1251, 1}, {1252, 16890627},
{1253, 1}, {1254, 16890883}, {1255, 1}, {1256, 16891139},
{1257, 1}, {1258, 16891395}, {1259, 1}, {1260, 16891651},
{1261, 1}, {1262, 16891907}, {1263, 1}, {1264, 16892163},
{1265, 1}, {1266, 16892419}, {1267, 1}, {1268, 16892675},
{1269, 1}, {1270, 16892931}, {1271, 1}, {1272, 16893187},
{1273, 1}, {1274, 16893443}, {1275, 1}, {1276, 16893699},
{1277, 1}, {1278, 16893955}, {1279, 1}, {1280, 16894211},
{1281, 1}, {1282, 16894467}, {1283, 1}, {1284, 16894723},
{1285, 1}, {1286, 16894979}, {1287, 1}, {1288, 16895235},
{1289, 1}, {1290, 16895491}, {1291, 1}, {1292, 16895747},
{1293, 1}, {1294, 16896003}, {1295, 1}, {1296, 16896259},
{1297, 1}, {1298, 16896515}, {1299, 1}, {1300, 16896771},
{1301, 1}, {1302, 16897027}, {1303, 1}, {1304, 16897283},
{1305, 1}, {1306, 16897539}, {1307, 1}, {1308, 16897795},
{1309, 1}, {1310, 16898051}, {1311, 1}, {1312, 16898307},
{1313, 1}, {1314, 16898563}, {1315, 1}, {1316, 16898819},
{1317, 1}, {1318, 16899075}, {1319, 1}, {1320, 16899331},
{1321, 1}, {1322, 16899587}, {1323, 1}, {1324, 16899843},
{1325, 1}, {1326, 16900099}, {1327, 1}, {1328, 2},
{1329, 16900355}, {1330, 16900611}, {1331, 16900867}, {1332, 16901123},
{1333, 16901379}, {1334, 16901635}, {1335, 16901891}, {1336, 16902147},
{1337, 16902403}, {1338, 16902659}, {1339, 16902915}, {1340, 16903171},
{1341, 16903427}, {1342, 16903683}, {1343, 16903939}, {1344, 16904195},
{1345, 16904451}, {1346, 16904707}, {1347, 16904963}, {1348, 16905219},
{1349, 16905475}, {1350, 16905731}, {1351, 16905987}, {1352, 16906243},
{1353, 16906499}, {1354, 16906755}, {1355, 16907011}, {1356, 16907267},
{1357, 16907523}, {1358, 16907779}, {1359, 16908035}, {1360, 16908291},
{1361, 16908547}, {1362, 16908803}, {1363, 16909059}, {1364, 16909315},
{1365, 16909571}, {1366, 16909827}, {1367, 2}, {1369, 1},
{1415, 33687299}, {1416, 1}, {1419, 2}, {1421, 1},
{1424, 2}, {1425, 1}, {1480, 2}, {1488, 1},
{1515, 2}, {1519, 1}, {1525, 2}, {1542, 1},
{1564, 2}, {1565, 1}, {1653, 33687811}, {1654, 33688323},
{1655, 33688835}, {1656, 33689347}, {1657, 1}, {1757, 2},
{1758, 1}, {1806, 2}, {1808, 1}, {1867, 2},
{1869, 1}, {1970, 2}, {1984, 1}, {2043, 2},
{2045, 1}, {2094, 2}, {2096, 1}, {2111, 2},
{2112, 1}, {2140, 2}, {2142, 1}, {2143, 2},
{2144, 1}, {2155, 2}, {2160, 1}, {2191, 2},
{2199, 1}, {2274, 2}, {2275, 1}, {2392, 33689859},
{2393, 33690371}, {2394, 33690883}, {2395, 33691395}, {2396, 33691907},
{2397, 33692419}, {2398, 33692931}, {2399, 33693443}, {2400, 1},
{2436, 2}, {2437, 1}, {2445, 2}, {2447, 1},
{2449, 2}, {2451, 1}, {2473, 2}, {2474, 1},
{2481, 2}, {2482, 1}, {2483, 2}, {2486, 1},
{2490, 2}, {2492, 1}, {2501, 2}, {2503, 1},
{2505, 2}, {2507, 1}, {2511, 2}, {2519, 1},
{2520, 2}, {2524, 33693955}, {2525, 33694467}, {2526, 2},
{2527, 33694979}, {2528, 1}, {2532, 2}, {2534, 1},
{2559, 2}, {2561, 1}, {2564, 2}, {2565, 1},
{2571, 2}, {2575, 1}, {2577, 2}, {2579, 1},
{2601, 2}, {2602, 1}, {2609, 2}, {2610, 1},
{2611, 33695491}, {2612, 2}, {2613, 1}, {2614, 33696003},
{2615, 2}, {2616, 1}, {2618, 2}, {2620, 1},
{2621, 2}, {2622, 1}, {2627, 2}, {2631, 1},
{2633, 2}, {2635, 1}, {2638, 2}, {2641, 1},
{2642, 2}, {2649, 33696515}, {2650, 33697027}, {2651, 33697539},
{2652, 1}, {2653, 2}, {2654, 33698051}, {2655, 2},
{2662, 1}, {2679, 2}, {2689, 1}, {2692, 2},
{2693, 1}, {2702, 2}, {2703, 1}, {2706, 2},
{2707, 1}, {2729, 2}, {2730, 1}, {2737, 2},
{2738, 1}, {2740, 2}, {2741, 1}, {2746, 2},
{2748, 1}, {2758, 2}, {2759, 1}, {2762, 2},
{2763, 1}, {2766, 2}, {2768, 1}, {2769, 2},
{2784, 1}, {2788, 2}, {2790, 1}, {2802, 2},
{2809, 1}, {2816, 2}, {2817, 1}, {2820, 2},
{2821, 1}, {2829, 2}, {2831, 1}, {2833, 2},
{2835, 1}, {2857, 2}, {2858, 1}, {2865, 2},
{2866, 1}, {2868, 2}, {2869, 1}, {2874, 2},
{2876, 1}, {2885, 2}, {2887, 1}, {2889, 2},
{2891, 1}, {2894, 2}, {2901, 1}, {2904, 2},
{2908, 33698563}, {2909, 33699075}, {2910, 2}, {2911, 1},
{2916, 2}, {2918, 1}, {2936, 2}, {2946, 1},
{2948, 2}, {2949, 1}, {2955, 2}, {2958, 1},
{2961, 2}, {2962, 1}, {2966, 2}, {2969, 1},
{2971, 2}, {2972, 1}, {2973, 2}, {2974, 1},
{2976, 2}, {2979, 1}, {2981, 2}, {2984, 1},
{2987, 2}, {2990, 1}, {3002, 2}, {3006, 1},
{3011, 2}, {3014, 1}, {3017, 2}, {3018, 1},
{3022, 2}, {3024, 1}, {3025, 2}, {3031, 1},
{3032, 2}, {3046, 1}, {3067, 2}, {3072, 1},
{3085, 2}, {3086, 1}, {3089, 2}, {3090, 1},
{3113, 2}, {3114, 1}, {3130, 2}, {3132, 1},
{3141, 2}, {3142, 1}, {3145, 2}, {3146, 1},
{3150, 2}, {3157, 1}, {3159, 2}, {3160, 1},
{3163, 2}, {3165, 1}, {3166, 2}, {3168, 1},
{3172, 2}, {3174, 1}, {3184, 2}, {3191, 1},
{3213, 2}, {3214, 1}, {3217, 2}, {3218, 1},
{3241, 2}, {3242, 1}, {3252, 2}, {3253, 1},
{3258, 2}, {3260, 1}, {3269, 2}, {3270, 1},
{3273, 2}, {3274, 1}, {3278, 2}, {3285, 1},
{3287, 2}, {3293, 1}, {3295, 2}, {3296, 1},
{3300, 2}, {3302, 1}, {3312, 2}, {3313, 1},
{3316, 2}, {3328, 1}, {3341, 2}, {3342, 1},
{3345, 2}, {3346, 1}, {3397, 2}, {3398, 1},
{3401, 2}, {3402, 1}, {3408, 2}, {3412, 1},
{3428, 2}, {3430, 1}, {3456, 2}, {3457, 1},
{3460, 2}, {3461, 1}, {3479, 2}, {3482, 1},
{3506, 2}, {3507, 1}, {3516, 2}, {3517, 1},
{3518, 2}, {3520, 1}, {3527, 2}, {3530, 1},
{3531, 2}, {3535, 1}, {3541, 2}, {3542, 1},
{3543, 2}, {3544, 1}, {3552, 2}, {3558, 1},
{3568, 2}, {3570, 1}, {3573, 2}, {3585, 1},
{3635, 33699587}, {3636, 1}, {3643, 2}, {3647, 1},
{3676, 2}, {3713, 1}, {3715, 2}, {3716, 1},
{3717, 2}, {3718, 1}, {3723, 2}, {3724, 1},
{3748, 2}, {3749, 1}, {3750, 2}, {3751, 1},
{3763, 33700099}, {3764, 1}, {3774, 2}, {3776, 1},
{3781, 2}, {3782, 1}, {3783, 2}, {3784, 1},
{3791, 2}, {3792, 1}, {3802, 2}, {3804, 33700611},
{3805, 33701123}, {3806, 1}, {3808, 2}, {3840, 1},
{3852, 16924419}, {3853, 1}, {3907, 33701891}, {3908, 1},
{3912, 2}, {3913, 1}, {3917, 33702403}, {3918, 1},
{3922, 33702915}, {3923, 1}, {3927, 33703427}, {3928, 1},
{3932, 33703939}, {3933, 1}, {3945, 33704451}, {3946, 1},
{3949, 2}, {3953, 1}, {3955, 33704963}, {3956, 1},
{3957, 33705475}, {3958, 33705987}, {3959, 50483715}, {3960, 33707267},
{3961, 50484995}, {3962, 1}, {3969, 33706755}, {3970, 1},
{3987, 33708547}, {3988, 1}, {3992, 2}, {3993, 1},
{3997, 33709059}, {3998, 1}, {4002, 33709571}, {4003, 1},
{4007, 33710083}, {4008, 1}, {4012, 33710595}, {4013, 1},
{4025, 33711107}, {4026, 1}, {4029, 2}, {4030, 1},
{4045, 2}, {4046, 1}, {4059, 2}, {4096, 1},
{4256, 16934403}, {4257, 16934659}, {4258, 16934915}, {4259, 16935171},
{4260, 16935427}, {4261, 16935683}, {4262, 16935939}, {4263, 16936195},
{4264, 16936451}, {4265, 16936707}, {4266, 16936963}, {4267, 16937219},
{4268, 16937475}, {4269, 16937731}, {4270, 16937987}, {4271, 16938243},
{4272, 16938499}, {4273, 16938755}, {4274, 16939011}, {4275, 16939267},
{4276, 16939523}, {4277, 16939779}, {4278, 16940035}, {4279, 16940291},
{4280, 16940547}, {4281, 16940803}, {4282, 16941059}, {4283, 16941315},
{4284, 16941571}, {4285, 16941827}, {4286, 16942083}, {4287, 16942339},
{4288, 16942595}, {4289, 16942851}, {4290, 16943107}, {4291, 16943363},
{4292, 16943619}, {4293, 16943875}, {4294, 2}, {4295, 16944131},
{4296, 2}, {4301, 16944387}, {4302, 2}, {4304, 1},
{4348, 16944643}, {4349, 1}, {4447, 0}, {4449, 1},
{4681, 2}, {4682, 1}, {4686, 2}, {4688, 1},
{4695, 2}, {4696, 1}, {4697, 2}, {4698, 1},
{4702, 2}, {4704, 1}, {4745, 2}, {4746, 1},
{4750, 2}, {4752, 1}, {4785, 2}, {4786, 1},
{4790, 2}, {4792, 1}, {4799, 2}, {4800, 1},
{4801, 2}, {4802, 1}, {4806, 2}, {4808, 1},
{4823, 2}, {4824, 1}, {4881, 2}, {4882, 1},
{4886, 2}, {4888, 1}, {4955, 2}, {4957, 1},
{4989, 2}, {4992, 1}, {5018, 2}, {5024, 1},
{5110, 2}, {5112, 16944899}, {5113, 16945155}, {5114, 16945411},
{5115, 16945667}, {5116, 16945923}, {5117, 16946179}, {5118, 2},
{5120, 1}, {5760, 2}, {5761, 1}, {5789, 2},
{5792, 1}, {5881, 2}, {5888, 1}, {5910, 2},
{5919, 1}, {5943, 2}, {5952, 1}, {5972, 2},
{5984, 1}, {5997, 2}, {5998, 1}, {6001, 2},
{6002, 1}, {6004, 2}, {6016, 1}, {6068, 0},
{6070, 1}, {6110, 2}, {6112, 1}, {6122, 2},
{6128, 1}, {6138, 2}, {6144, 1}, {6155, 0},
{6160, 1}, {6170, 2}, {6176, 1}, {6265, 2},
{6272, 1}, {6315, 2}, {6320, 1}, {6390, 2},
{6400, 1}, {6431, 2}, {6432, 1}, {6444, 2},
{6448, 1}, {6460, 2}, {6464, 1}, {6465, 2},
{6468, 1}, {6510, 2}, {6512, 1}, {6517, 2},
{6528, 1}, {6572, 2}, {6576, 1}, {6602, 2},
{6608, 1}, {6619, 2}, {6622, 1}, {6684, 2},
{6686, 1}, {6751, 2}, {6752, 1}, {6781, 2},
{6783, 1}, {6794, 2}, {6800, 1}, {6810, 2},
{6816, 1}, {6830, 2}, {6832, 1}, {6863, 2},
{6912, 1}, {6989, 2}, {6990, 1}, {7156, 2},
{7164, 1}, {7224, 2}, {7227, 1}, {7242, 2},
{7245, 1}, {7296, 16867075}, {7297, 16867587}, {7298, 16870147},
{7299, 16870915}, {7300, 16871171}, {7302, 16873219}, {7303, 16875011},
{7304, 16946435}, {7305, 16946691}, {7306, 1}, {7307, 2},
{7312, 16946947}, {7313, 16947203}, {7314, 16947459}, {7315, 16947715},
{7316, 16947971}, {7317, 16948227}, {7318, 16948483}, {7319, 16948739},
{7320, 16948995}, {7321, 16949251}, {7322, 16949507}, {7323, 16949763},
{7324, 16944643}, {7325, 16950019}, {7326, 16950275}, {7327, 16950531},
{7328, 16950787}, {7329, 16951043}, {7330, 16951299}, {7331, 16951555},
{7332, 16951811}, {7333, 16952067}, {7334, 16952323}, {7335, 16952579},
{7336, 16952835}, {7337, 16953091}, {7338, 16953347}, {7339, 16953603},
{7340, 16953859}, {7341, 16954115}, {7342, 16954371}, {7343, 16954627},
{7344, 16954883}, {7345, 16955139}, {7346, 16955395}, {7347, 16955651},
{7348, 16955907}, {7349, 16956163}, {7350, 16956419}, {7351, 16956675},
{7352, 16956931}, {7353, 16957187}, {7354, 16957443}, {7355, 2},
{7357, 16957699}, {7358, 16957955}, {7359, 16958211}, {7360, 1},
{7368, 2}, {7376, 1}, {7419, 2}, {7424, 1},
{7468, 16777219}, {7469, 16791043}, {7470, 16777475}, {7471, 1},
{7472, 16777987}, {7473, 16778243}, {7474, 16816131}, {7475, 16778755},
{7476, 16779011}, {7477, 16779267}, {7478, 16779523}, {7479, 16779779},
{7480, 16780035}, {7481, 16780291}, {7482, 16780547}, {7483, 1},
{7484, 16780803}, {7485, 16835843}, {7486, 16781059}, {7487, 16781571},
{7488, 16782083}, {7489, 16782339}, {7490, 16782851}, {7491, 16777219},
{7492, 16958467}, {7493, 16958723}, {7494, 16958979}, {7495, 16777475},
{7496, 16777987}, {7497, 16778243}, {7498, 16816387}, {7499, 16816643},
{7500, 16959235}, {7501, 16778755}, {7502, 1}, {7503, 16779779},
{7504, 16780291}, {7505, 16807171}, {7506, 16780803}, {7507, 16814851},
{7508, 16959491}, {7509, 16959747}, {7510, 16781059}, {7511, 16782083},
{7512, 16782339}, {7513, 16960003}, {7514, 16818435}, {7515, 16782595},
{7516, 16960259}, {7517, 16851971}, {7518, 16852227}, {7519, 16852483},
{7520, 16856323}, {7521, 16856579}, {7522, 16779267}, {7523, 16781571},
{7524, 16782339}, {7525, 16782595}, {7526, 16851971}, {7527, 16852227},
{7528, 16855299}, {7529, 16856323}, {7530, 16856579}, {7531, 1},
{7544, 16869891}, {7545, 1}, {7579, 16960515}, {7580, 16777731},
{7581, 16960771}, {7582, 16793603}, {7583, 16959235}, {7584, 16778499},
{7585, 16961027}, {7586, 16961283}, {7587, 16961539}, {7588, 16817923},
{7589, 16817667}, {7590, 16961795}, {7591, 16962051}, {7592, 16962307},
{7593, 16962563}, {7594, 16962819}, {7595, 16963075}, {7596, 16963331},
{7597, 16963587}, {7598, 16818691}, {7599, 16963843}, {7600, 16964099},
{7601, 16818947}, {7602, 16964355}, {7603, 16964611}, {7604, 16820483},
{7605, 16964867}, {7606, 16839683}, {7607, 16821507}, {7608, 16965123},
{7609, 16821763}, {7610, 16839939}, {7611, 16783619}, {7612, 16965379},
{7613, 16965635}, {7614, 16822531}, {7615, 16853507}, {7616, 1},
{7680, 16965891}, {7681, 1}, {7682, 16966147}, {7683, 1},
{7684, 16966403}, {7685, 1}, {7686, 16966659}, {7687, 1},
{7688, 16966915}, {7689, 1}, {7690, 16967171}, {7691, 1},
{7692, 16967427}, {7693, 1}, {7694, 16967683}, {7695, 1},
{7696, 16967939}, {7697, 1}, {7698, 16968195}, {7699, 1},
{7700, 16968451}, {7701, 1}, {7702, 16968707}, {7703, 1},
{7704, 16968963}, {7705, 1}, {7706, 16969219}, {7707, 1},
{7708, 16969475}, {7709, 1}, {7710, 16969731}, {7711, 1},
{7712, 16969987}, {7713, 1}, {7714, 16970243}, {7715, 1},
{7716, 16970499}, {7717, 1}, {7718, 16970755}, {7719, 1},
{7720, 16971011}, {7721, 1}, {7722, 16971267}, {7723, 1},
{7724, 16971523}, {7725, 1}, {7726, 16971779}, {7727, 1},
{7728, 16972035}, {7729, 1}, {7730, 16972291}, {7731, 1},
{7732, 16972547}, {7733, 1}, {7734, 16972803}, {7735, 1},
{7736, 16973059}, {7737, 1}, {7738, 16973315}, {7739, 1},
{7740, 16973571}, {7741, 1}, {7742, 16973827}, {7743, 1},
{7744, 16974083}, {7745, 1}, {7746, 16974339}, {7747, 1},
{7748, 16974595}, {7749, 1}, {7750, 16974851}, {7751, 1},
{7752, 16975107}, {7753, 1}, {7754, 16975363}, {7755, 1},
{7756, 16975619}, {7757, 1}, {7758, 16975875}, {7759, 1},
{7760, 16976131}, {7761, 1}, {7762, 16976387}, {7763, 1},
{7764, 16976643}, {7765, 1}, {7766, 16976899}, {7767, 1},
{7768, 16977155}, {7769, 1}, {7770, 16977411}, {7771, 1},
{7772, 16977667}, {7773, 1}, {7774, 16977923}, {7775, 1},
{7776, 16978179}, {7777, 1}, {7778, 16978435}, {7779, 1},
{7780, 16978691}, {7781, 1}, {7782, 16978947}, {7783, 1},
{7784, 16979203}, {7785, 1}, {7786, 16979459}, {7787, 1},
{7788, 16979715}, {7789, 1}, {7790, 16979971}, {7791, 1},
{7792, 16980227}, {7793, 1}, {7794, 16980483}, {7795, 1},
{7796, 16980739}, {7797, 1}, {7798, 16980995}, {7799, 1},
{7800, 16981251}, {7801, 1}, {7802, 16981507}, {7803, 1},
{7804, 16981763}, {7805, 1}, {7806, 16982019}, {7807, 1},
{7808, 16982275}, {7809, 1}, {7810, 16982531}, {7811, 1},
{7812, 16982787}, {7813, 1}, {7814, 16983043}, {7815, 1},
{7816, 16983299}, {7817, 1}, {7818, 16983555}, {7819, 1},
{7820, 16983811}, {7821, 1}, {7822, 16984067}, {7823, 1},
{7824, 16984323}, {7825, 1}, {7826, 16984579}, {7827, 1},
{7828, 16984835}, {7829, 1}, {7834, 33762307}, {7835, 16978179},
{7836, 1}, {7838, 16985603}, {7839, 1}, {7840, 16985859},
{7841, 1}, {7842, 16986115}, {7843, 1}, {7844, 16986371},
{7845, 1}, {7846, 16986627}, {7847, 1}, {7848, 16986883},
{7849, 1}, {7850, 16987139}, {7851, 1}, {7852, 16987395},
{7853, 1}, {7854, 16987651}, {7855, 1}, {7856, 16987907},
{7857, 1}, {7858, 16988163}, {7859, 1}, {7860, 16988419},
{7861, 1}, {7862, 16988675}, {7863, 1}, {7864, 16988931},
{7865, 1}, {7866, 16989187}, {7867, 1}, {7868, 16989443},
{7869, 1}, {7870, 16989699}, {7871, 1}, {7872, 16989955},
{7873, 1}, {7874, 16990211}, {7875, 1}, {7876, 16990467},
{7877, 1}, {7878, 16990723}, {7879, 1}, {7880, 16990979},
{7881, 1}, {7882, 16991235}, {7883, 1}, {7884, 16991491},
{7885, 1}, {7886, 16991747}, {7887, 1}, {7888, 16992003},
{7889, 1}, {7890, 16992259}, {7891, 1}, {7892, 16992515},
{7893, 1}, {7894, 16992771}, {7895, 1}, {7896, 16993027},
{7897, 1}, {7898, 16993283}, {7899, 1}, {7900, 16993539},
{7901, 1}, {7902, 16993795}, {7903, 1}, {7904, 16994051},
{7905, 1}, {7906, 16994307}, {7907, 1}, {7908, 16994563},
{7909, 1}, {7910, 16994819}, {7911, 1}, {7912, 16995075},
{7913, 1}, {7914, 16995331}, {7915, 1}, {7916, 16995587},
{7917, 1}, {7918, 16995843}, {7919, 1}, {7920, 16996099},
{7921, 1}, {7922, 16996355}, {7923, 1}, {7924, 16996611},
{7925, 1}, {7926, 16996867}, {7927, 1}, {7928, 16997123},
{7929, 1}, {7930, 16997379}, {7931, 1}, {7932, 16997635},
{7933, 1}, {7934, 16997891}, {7935, 1}, {7944, 16998147},
{7945, 16998403}, {7946, 16998659}, {7947, 16998915}, {7948, 16999171},
{7949, 16999427}, {7950, 16999683}, {7951, 16999939}, {7952, 1},
{7958, 2}, {7960, 17000195}, {7961, 17000451}, {7962, 17000707},
{7963, 17000963}, {7964, 17001219}, {7965, 17001475}, {7966, 2},
{7968, 1}, {7976, 17001731}, {7977, 17001987}, {7978, 17002243},
{7979, 17002499}, {7980, 17002755}, {7981, 17003011}, {7982, 17003267},
{7983, 17003523}, {7984, 1}, {7992, 17003779}, {7993, 17004035},
{7994, 17004291}, {7995, 17004547}, {7996, 17004803}, {7997, 17005059},
{7998, 17005315}, {7999, 17005571}, {8000, 1}, {8006, 2},
{8008, 17005827}, {8009, 17006083}, {8010, 17006339}, {8011, 17006595},
{8012, 17006851}, {8013, 17007107}, {8014, 2}, {8016, 1},
{8024, 2}, {8025, 17007363}, {8026, 2}, {8027, 17007619},
{8028, 2}, {8029, 17007875}, {8030, 2}, {8031, 17008131},
{8032, 1}, {8040, 17008387}, {8041, 17008643}, {8042, 17008899},
{8043, 17009155}, {8044, 17009411}, {8045, 17009667}, {8046, 17009923},
{8047, 17010179}, {8048, 1}, {8049, 16849923}, {8050, 1},
{8051, 16850179}, {8052, 1}, {8053, 16850435}, {8054, 1},
{8055, 16850691}, {8056, 1}, {8057, 16850947}, {8058, 1},
{8059, 16851203}, {8060, 1}, {8061, 16851459}, {8062, 2},
{8064, 33787651}, {8065, 33788163}, {8066, 33788675}, {8067, 33789187},
{8068, 33789699}, {8069, 33790211}, {8070, 33790723}, {8071, 33791235},
{8072, 33787651}, {8073, 33788163}, {8074, 33788675}, {8075, 33789187},
{8076, 33789699}, {8077, 33790211}, {8078, 33790723}, {8079, 33791235},
{8080, 33791747}, {8081, 33792259}, {8082, 33792771}, {8083, 33793283},
{8084, 33793795}, {8085, 33794307}, {8086, 33794819}, {8087, 33795331},
{8088, 33791747}, {8089, 33792259}, {8090, 33792771}, {8091, 33793283},
{8092, 33793795}, {8093, 33794307}, {8094, 33794819}, {8095, 33795331},
{8096, 33795843}, {8097, 33796355}, {8098, 33796867}, {8099, 33797379},
{8100, 33797891}, {8101, 33798403}, {8102, 33798915}, {8103, 33799427},
{8104, 33795843}, {8105, 33796355}, {8106, 33796867}, {8107, 33797379},
{8108, 33797891}, {8109, 33798403}, {8110, 33798915}, {8111, 33799427},
{8112, 1}, {8114, 33799939}, {8115, 33800451}, {8116, 33800963},
{8117, 2}, {8118, 1}, {8119, 33801475}, {8120, 17024771},
{8121, 17025027}, {8122, 17022723}, {8123, 16849923}, {8124, 33800451},
{8125, 33802499}, {8126, 16846851}, {8127, 33802499}, {8128, 33803011},
{8129, 50580739}, {8130, 33804291}, {8131, 33804803}, {8132, 33805315},
{8133, 2}, {8134, 1}, {8135, 33805827}, {8136, 17029123},
{8137, 16850179}, {8138, 17027075}, {8139, 16850435}, {8140, 33804803},
{8141, 50583811}, {8142, 50584579}, {8143, 50585347}, {8144, 1},
{8147, 17031683}, {8148, 2}, {8150, 1}, {8152, 17031939},
{8153, 17032195}, {8154, 17032451}, {8155, 16850691}, {8156, 2},
{8157, 50587139}, {8158, 50587907}, {8159, 50588675}, {8160, 1},
{8163, 17035011}, {8164, 1}, {8168, 17035267}, {8169, 17035523},
{8170, 17035779}, {8171, 16851203}, {8172, 17036035}, {8173, 50590723},
{8174, 50403587}, {8175, 17037059}, {8176, 2}, {8178, 33814531},
{8179, 33815043}, {8180, 33815555}, {8181, 2}, {8182, 1},
{8183, 33816067}, {8184, 17039363}, {8185, 16850947}, {8186, 17037315},
{8187, 16851459}, {8188, 33815043}, {8189, 33562883}, {8190, 33809923},
{8191, 2}, {8192, 16783875}, {8203, 0}, {8204, 1},
{8206, 2}, {8208, 1}, {8209, 17039619}, {8210, 1},
{8215, 33817091}, {8216, 1}, {8228, 2}, {8231, 1},
{8232, 2}, {8239, 16783875}, {8240, 1}, {8243, 33817603},
{8244, 50595331}, {8245, 1}, {8246, 33818883}, {8247, 50596611},
{8248, 1}, {8252, 33820163}, {8253, 1}, {8254, 33820675},
{8255, 1}, {8263, 33821187}, {8264, 33821699}, {8265, 33822211},
{8266, 1}, {8279, 67372035}, {8280, 1}, {8287, 16783875},
{8288, 0}, {8293, 2}, {8298, 0}, {8304, 17045507},
{8305, 16779267}, {8306, 2}, {8308, 16787715}, {8309, 17045763},
{8310, 17046019}, {8311, 17046275}, {8312, 17046531}, {8313, 17046787},
{8314, 17047043}, {8315, 17047299}, {8316, 17047555}, {8317, 17047811},
{8318, 17048067}, {8319, 16780547}, {8320, 17045507}, {8321, 16786947},
{8322, 16785155}, {8323, 16785411}, {8324, 16787715}, {8325, 17045763},
{8326, 17046019}, {8327, 17046275}, {8328, 17046531}, {8329, 17046787},
{8330, 17047043}, {8331, 17047299}, {8332, 17047555}, {8333, 17047811},
{8334, 17048067}, {8335, 2}, {8336, 16777219}, {8337, 16778243},
{8338, 16780803}, {8339, 16783107}, {8340, 16816387}, {8341, 16779011},
{8342, 16779779}, {8343, 16780035}, {8344, 16780291}, {8345, 16780547},
{8346, 16781059}, {8347, 16781827}, {8348, 16782083}, {8349, 2},
{8352, 1}, {8360, 33558787}, {8361, 1}, {8385, 2},
{8400, 1}, {8433, 2}, {8448, 50602755}, {8449, 50603523},
{8450, 16777731}, {8451, 33827075}, {8452, 1}, {8453, 50604803},
{8454, 50605571}, {8455, 16816643}, {8456, 1}, {8457, 33829123},
{8458, 16778755}, {8459, 16779011}, {8463, 16802051}, {8464, 16779267},
{8466, 16780035}, {8468, 1}, {8469, 16780547}, {8470, 33557763},
{8471, 1}, {8473, 16781059}, {8474, 16781315}, {8475, 16781571},
{8478, 1}, {8480, 33829635}, {8481, 50607363}, {8482, 33830915},
{8483, 1}, {8484, 16783619}, {8485, 1}, {8486, 16857091},
{8487, 1}, {8488, 16783619}, {8489, 1}, {8490, 16779779},
{8491, 16790787}, {8492, 16777475}, {8493, 16777731}, {8494, 1},
{8495, 16778243}, {8497, 16778499}, {8498, 17054211}, {8499, 16780291},
{8500, 16780803}, {8501, 17054467}, {8502, 17054723}, {8503, 17054979},
{8504, 17055235}, {8505, 16779267}, {8506, 1}, {8507, 50609923},
{8508, 16855043}, {8509, 16852227}, {8511, 16855043}, {8512, 17056259},
{8513, 1}, {8517, 16777987}, {8519, 16778243}, {8520, 16779267},
{8521, 16779523}, {8522, 1}, {8528, 50610947}, {8529, 50611715},
{8530, 67389699}, {8531, 50613507}, {8532, 50614275}, {8533, 50615043},
{8534, 50615811}, {8535, 50616579}, {8536, 50617347}, {8537, 50618115},
{8538, 50618883}, {8539, 50619651}, {8540, 50620419}, {8541, 50621187},
{8542, 50621955}, {8543, 33564419}, {8544, 16779267}, {8545, 33845507},
{8546, 50623235}, {8547, 33846787}, {8548, 16782595}, {8549, 33847299},
{8550, 50625027}, {8551, 67403011}, {8552, 33849603}, {8553, 16783107},
{8554, 33850115}, {8555, 50627843}, {8556, 16780035}, {8557, 16777731},
{8558, 16777987}, {8559, 16780291}, {8560, 16779267}, {8561, 33845507},
{8562, 50622723}, {8563, 33846787}, {8564, 16782595}, {8565, 33847299},
{8566, 50625027}, {8567, 67403011}, {8568, 33849603}, {8569, 16783107},
{8570, 33850115}, {8571, 50627843}, {8572, 16780035}, {8573, 16777731},
{8574, 16777987}, {8575, 16780291}, {8576, 1}, {8579, 17074179},
{8580, 1}, {8585, 50628867}, {8586, 1}, {8588, 2},
{8592, 1}, {8748, 33852419}, {8749, 50630147}, {8750, 1},
{8751, 33853699}, {8752, 50631427}, {8753, 1}, {9001, 17077763},
{9002, 17078019}, {9003, 1}, {9258, 2}, {9280, 1},
{9291, 2}, {9312, 16786947}, {9313, 16785155}, {9314, 16785411},
{9315, 16787715}, {9316, 17045763}, {9317, 17046019}, {9318, 17046275},
{9319, 17046531}, {9320, 17046787}, {9321, 33835779}, {9322, 33564163},
{9323, 33855491}, {9324, 33856003}, {9325, 33856515}, {9326, 33857027},
{9327, 33857539}, {9328, 33858051}, {9329, 33858563}, {9330, 33859075},
{9331, 33859587}, {9332, 50637315}, {9333, 50638083}, {9334, 50638851},
{9335, 50639619}, {9336, 50640387}, {9337, 50641155}, {9338, 50641923},
{9339, 50642691}, {9340, 50643459}, {9341, 67421443}, {9342, 67422467},
{9343, 67423491}, {9344, 67424515}, {9345, 67425539}, {9346, 67426563},
{9347, 67427587}, {9348, 67428611}, {9349, 67429635}, {9350, 67430659},
{9351, 67431683}, {9352, 2}, {9372, 50655491}, {9373, 50656259},
{9374, 50657027}, {9375, 50657795}, {9376, 50658563}, {9377, 50659331},
{9378, 50660099}, {9379, 50660867}, {9380, 50661635}, {9381, 50662403},
{9382, 50663171}, {9383, 50663939}, {9384, 50664707}, {9385, 50665475},
{9386, 50666243}, {9387, 50667011}, {9388, 50667779}, {9389, 50668547},
{9390, 50669315}, {9391, 50670083}, {9392, 50670851}, {9393, 50671619},
{9394, 50672387}, {9395, 50673155}, {9396, 50673923}, {9397, 50674691},
{9398, 16777219}, {9399, 16777475}, {9400, 16777731}, {9401, 16777987},
{9402, 16778243}, {9403, 16778499}, {9404, 16778755}, {9405, 16779011},
{9406, 16779267}, {9407, 16779523}, {9408, 16779779}, {9409, 16780035},
{9410, 16780291}, {9411, 16780547}, {9412, 16780803}, {9413, 16781059},
{9414, 16781315}, {9415, 16781571}, {9416, 16781827}, {9417, 16782083},
{9418, 16782339}, {9419, 16782595}, {9420, 16782851}, {9421, 16783107},
{9422, 16783363}, {9423, 16783619}, {9424, 16777219}, {9425, 16777475},
{9426, 16777731}, {9427, 16777987}, {9428, 16778243}, {9429, 16778499},
{9430, 16778755}, {9431, 16779011}, {9432, 16779267}, {9433, 16779523},
{9434, 16779779}, {9435, 16780035}, {9436, 16780291}, {9437, 16780547},
{9438, 16780803}, {9439, 16781059}, {9440, 16781315}, {9441, 16781571},
{9442, 16781827}, {9443, 16782083}, {9444, 16782339}, {9445, 16782595},
{9446, 16782851}, {9447, 16783107}, {9448, 16783363}, {9449, 16783619},
{9450, 17045507}, {9451, 1}, {10764, 67406851}, {10765, 1},
{10868, 50675459}, {10869, 33899011}, {10870, 50675971}, {10871, 1},
{10972, 33899523}, {10973, 1}, {11124, 2}, {11126, 1},
{11158, 2}, {11159, 1}, {11264, 17122819}, {11265, 17123075},
{11266, 17123331}, {11267, 17123587}, {11268, 17123843}, {11269, 17124099},
{11270, 17124355}, {11271, 17124611}, {11272, 17124867}, {11273, 17125123},
{11274, 17125379}, {11275, 17125635}, {11276, 17125891}, {11277, 17126147},
{11278, 17126403}, {11279, 17126659}, {11280, 17126915}, {11281, 17127171},
{11282, 17127427}, {11283, 17127683}, {11284, 17127939}, {11285, 17128195},
{11286, 17128451}, {11287, 17128707}, {11288, 17128963}, {11289, 17129219},
{11290, 17129475}, {11291, 17129731}, {11292, 17129987}, {11293, 17130243},
{11294, 17130499}, {11295, 17130755}, {11296, 17131011}, {11297, 17131267},
{11298, 17131523}, {11299, 17131779}, {11300, 17132035}, {11301, 17132291},
{11302, 17132547}, {11303, 17132803}, {11304, 17133059}, {11305, 17133315},
{11306, 17133571}, {11307, 17133827}, {11308, 17134083}, {11309, 17134339},
{11310, 17134595}, {11311, 17134851}, {11312, 1}, {11360, 17135107},
{11361, 1}, {11362, 17135363}, {11363, 17135619}, {11364, 17135875},
{11365, 1}, {11367, 17136131}, {11368, 1}, {11369, 17136387},
{11370, 1}, {11371, 17136643}, {11372, 1}, {11373, 16958723},
{11374, 16963331}, {11375, 16958467}, {11376, 16960515}, {11377, 1},
{11378, 17136899}, {11379, 1}, {11381, 17137155}, {11382, 1},
{11388, 16779523}, {11389, 16782595}, {11390, 17137411}, {11391, 17137667},
{11392, 17137923}, {11393, 1}, {11394, 17138179}, {11395, 1},
{11396, 17138435}, {11397, 1}, {11398, 17138691}, {11399, 1},
{11400, 17138947}, {11401, 1}, {11402, 17139203}, {11403, 1},
{11404, 17139459}, {11405, 1}, {11406, 17139715}, {11407, 1},
{11408, 17139971}, {11409, 1}, {11410, 17140227}, {11411, 1},
{11412, 17140483}, {11413, 1}, {11414, 17140739}, {11415, 1},
{11416, 17140995}, {11417, 1}, {11418, 17141251}, {11419, 1},
{11420, 17141507}, {11421, 1}, {11422, 17141763}, {11423, 1},
{11424, 17142019}, {11425, 1}, {11426, 17142275}, {11427, 1},
{11428, 17142531}, {11429, 1}, {11430, 17142787}, {11431, 1},
{11432, 17143043}, {11433, 1}, {11434, 17143299}, {11435, 1},
{11436, 17143555}, {11437, 1}, {11438, 17143811}, {11439, 1},
{11440, 17144067}, {11441, 1}, {11442, 17144323}, {11443, 1},
{11444, 17144579}, {11445, 1}, {11446, 17144835}, {11447, 1},
{11448, 17145091}, {11449, 1}, {11450, 17145347}, {11451, 1},
{11452, 17145603}, {11453, 1}, {11454, 17145859}, {11455, 1},
{11456, 17146115}, {11457, 1}, {11458, 17146371}, {11459, 1},
{11460, 17146627}, {11461, 1}, {11462, 17146883}, {11463, 1},
{11464, 17147139}, {11465, 1}, {11466, 17147395}, {11467, 1},
{11468, 17147651}, {11469, 1}, {11470, 17147907}, {11471, 1},
{11472, 17148163}, {11473, 1}, {11474, 17148419}, {11475, 1},
{11476, 17148675}, {11477, 1}, {11478, 17148931}, {11479, 1},
{11480, 17149187}, {11481, 1}, {11482, 17149443}, {11483, 1},
{11484, 17149699}, {11485, 1}, {11486, 17149955}, {11487, 1},
{11488, 17150211}, {11489, 1}, {11490, 17150467}, {11491, 1},
{11499, 17150723}, {11500, 1}, {11501, 17150979}, {11502, 1},
{11506, 17151235}, {11507, 1}, {11508, 2}, {11513, 1},
{11558, 2}, {11559, 1}, {11560, 2}, {11565, 1},
{11566, 2}, {11568, 1}, {11624, 2}, {11631, 17151491},
{11632, 1}, {11633, 2}, {11647, 1}, {11671, 2},
{11680, 1}, {11687, 2}, {11688, 1}, {11695, 2},
{11696, 1}, {11703, 2}, {11704, 1}, {11711, 2},
{11712, 1}, {11719, 2}, {11720, 1}, {11727, 2},
{11728, 1}, {11735, 2}, {11736, 1}, {11743, 2},
{11744, 1}, {11870, 2}, {11904, 1}, {11930, 2},
{11931, 1}, {11935, 17151747}, {11936, 1}, {12019, 17152003},
{12020, 2}, {12032, 17152259}, {12033, 17152515}, {12034, 17152771},
{12035, 17153027}, {12036, 17153283}, {12037, 17153539}, {12038, 17153795},
{12039, 17154051}, {12040, 17154307}, {12041, 17154563}, {12042, 17154819},
{12043, 17155075}, {12044, 17155331}, {12045, 17155587}, {12046, 17155843},
{12047, 17156099}, {12048, 17156355}, {12049, 17156611}, {12050, 17156867},
{12051, 17157123}, {12052, 17157379}, {12053, 17157635}, {12054, 17157891},
{12055, 17158147}, {12056, 17158403}, {12057, 17158659}, {12058, 17158915},
{12059, 17159171}, {12060, 17159427}, {12061, 17159683}, {12062, 17159939},
{12063, 17160195}, {12064, 17160451}, {12065, 17160707}, {12066, 17160963},
{12067, 17161219}, {12068, 17161475}, {12069, 17161731}, {12070, 17161987},
{12071, 17162243}, {12072, 17162499}, {12073, 17162755}, {12074, 17163011},
{12075, 17163267}, {12076, 17163523}, {12077, 17163779}, {12078, 17164035},
{12079, 17164291}, {12080, 17164547}, {12081, 17164803}, {12082, 17165059},
{12083, 17165315}, {12084, 17165571}, {12085, 17165827}, {12086, 17166083},
{12087, 17166339}, {12088, 17166595}, {12089, 17166851}, {12090, 17167107},
{12091, 17167363}, {12092, 17167619}, {12093, 17167875}, {12094, 17168131},
{12095, 17168387}, {12096, 17168643}, {12097, 17168899}, {12098, 17169155},
{12099, 17169411}, {12100, 17169667}, {12101, 17169923}, {12102, 17170179},
{12103, 17170435}, {12104, 17170691}, {12105, 17170947}, {12106, 17171203},
{12107, 17171459}, {12108, 17171715}, {12109, 17171971}, {12110, 17172227},
{12111, 17172483}, {12112, 17172739}, {12113, 17172995}, {12114, 17173251},
{12115, 17173507}, {12116, 17173763}, {12117, 17174019}, {12118, 17174275},
{12119, 17174531}, {12120, 17174787}, {12121, 17175043}, {12122, 17175299},
{12123, 17175555}, {12124, 17175811}, {12125, 17176067}, {12126, 17176323},
{12127, 17176579}, {12128, 17176835}, {12129, 17177091}, {12130, 17177347},
{12131, 17177603}, {12132, 17177859}, {12133, 17178115}, {12134, 17178371},
{12135, 17178627}, {12136, 17178883}, {12137, 17179139}, {12138, 17179395},
{12139, 17179651}, {12140, 17179907}, {12141, 17180163}, {12142, 17180419},
{12143, 17180675}, {12144, 17180931}, {12145, 17181187}, {12146, 17181443},
{12147, 17181699}, {12148, 17181955}, {12149, 17182211}, {12150, 17182467},
{12151, 17182723}, {12152, 17182979}, {12153, 17183235}, {12154, 17183491},
{12155, 17183747}, {12156, 17184003}, {12157, 17184259}, {12158, 17184515},
{12159, 17184771}, {12160, 17185027}, {12161, 17185283}, {12162, 17185539},
{12163, 17185795}, {12164, 17186051}, {12165, 17186307}, {12166, 17186563},
{12167, 17186819}, {12168, 17187075}, {12169, 17187331}, {12170, 17187587},
{12171, 17187843}, {12172, 17188099}, {12173, 17188355}, {12174, 17188611},
{12175, 17188867}, {12176, 17189123}, {12177, 17189379}, {12178, 17189635},
{12179, 17189891}, {12180, 17190147}, {12181, 17190403}, {12182, 17190659},
{12183, 17190915}, {12184, 17191171}, {12185, 17191427}, {12186, 17191683},
{12187, 17191939}, {12188, 17192195}, {12189, 17192451}, {12190, 17192707},
{12191, 17192963}, {12192, 17193219}, {12193, 17193475}, {12194, 17193731},
{12195, 17193987}, {12196, 17194243}, {12197, 17194499}, {12198, 17194755},
{12199, 17195011}, {12200, 17195267}, {12201, 17195523}, {12202, 17195779},
{12203, 17196035}, {12204, 17196291}, {12205, 17196547}, {12206, 17196803},
{12207, 17197059}, {12208, 17197315}, {12209, 17197571}, {12210, 17197827},
{12211, 17198083}, {12212, 17198339}, {12213, 17198595}, {12214, 17198851},
{12215, 17199107}, {12216, 17199363}, {12217, 17199619}, {12218, 17199875},
{12219, 17200131}, {12220, 17200387}, {12221, 17200643}, {12222, 17200899},
{12223, 17201155}, {12224, 17201411}, {12225, 17201667}, {12226, 17201923},
{12227, 17202179}, {12228, 17202435}, {12229, 17202691}, {12230, 17202947},
{12231, 17203203}, {12232, 17203459}, {12233, 17203715}, {12234, 17203971},
{12235, 17204227}, {12236, 17204483}, {12237, 17204739}, {12238, 17204995},
{12239, 17205251}, {12240, 17205507}, {12241, 17205763}, {12242, 17206019},
{12243, 17206275}, {12244, 17206531}, {12245, 17206787}, {12246, 2},
{12288, 16783875}, {12289, 1}, {12290, 17207043}, {12291, 1},
{12342, 17207299}, {12343, 1}, {12344, 17158147}, {12345, 17207555},
{12346, 17207811}, {12347, 1}, {12352, 2}, {12353, 1},
{12439, 2}, {12441, 1}, {12443, 33985283}, {12444, 33985795},
{12445, 1}, {12447, 33986307}, {12448, 1}, {12543, 33986819},
{12544, 2}, {12549, 1}, {12592, 2}, {12593, 17210115},
{12594, 17210371}, {12595, 17210627}, {12596, 17210883}, {12597, 17211139},
{12598, 17211395}, {12599, 17211651}, {12600, 17211907}, {12601, 17212163},
{12602, 17212419}, {12603, 17212675}, {12604, 17212931}, {12605, 17213187},
{12606, 17213443}, {12607, 17213699}, {12608, 17213955}, {12609, 17214211},
{12610, 17214467}, {12611, 17214723}, {12612, 17214979}, {12613, 17215235},
{12614, 17215491}, {12615, 17215747}, {12616, 17216003}, {12617, 17216259},
{12618, 17216515}, {12619, 17216771}, {12620, 17217027}, {12621, 17217283},
{12622, 17217539}, {12623, 17217795}, {12624, 17218051}, {12625, 17218307},
{12626, 17218563}, {12627, 17218819}, {12628, 17219075}, {12629, 17219331},
{12630, 17219587}, {12631, 17219843}, {12632, 17220099}, {12633, 17220355},
{12634, 17220611}, {12635, 17220867}, {12636, 17221123}, {12637, 17221379},
{12638, 17221635}, {12639, 17221891}, {12640, 17222147}, {12641, 17222403},
{12642, 17222659}, {12643, 17222915}, {12644, 0}, {12645, 17223171},
{12646, 17223427}, {12647, 17223683}, {12648, 17223939}, {12649, 17224195},
{12650, 17224451}, {12651, 17224707}, {12652, 17224963}, {12653, 17225219},
{12654, 17225475}, {12655, 17225731}, {12656, 17225987}, {12657, 17226243},
{12658, 17226499}, {12659, 17226755}, {12660, 17227011}, {12661, 17227267},
{12662, 17227523}, {12663, 17227779}, {12664, 17228035}, {12665, 17228291},
{12666, 17228547}, {12667, 17228803}, {12668, 17229059}, {12669, 17229315},
{12670, 17229571}, {12671, 17229827}, {12672, 17230083}, {12673, 17230339},
{12674, 17230595}, {12675, 17230851}, {12676, 17231107}, {12677, 17231363},
{12678, 17231619}, {12679, 17231875}, {12680, 17232131}, {12681, 17232387},
{12682, 17232643}, {12683, 17232899}, {12684, 17233155}, {12685, 17233411},
{12686, 17233667}, {12687, 2}, {12688, 1}, {12690, 17152259},
{12691, 17153795}, {12692, 17233923}, {12693, 17234179}, {12694, 17234435},
{12695, 17234691}, {12696, 17234947}, {12697, 17235203}, {12698, 17153283},
{12699, 17235459}, {12700, 17235715}, {12701, 17235971}, {12702, 17236227},
{12703, 17154307}, {12704, 1}, {12774, 2}, {12784, 1},
{12800, 50790915}, {12801, 50791683}, {12802, 50792451}, {12803, 50793219},
{12804, 50793987}, {12805, 50794755}, {12806, 50795523}, {12807, 50796291},
{12808, 50797059}, {12809, 50797827}, {12810, 50798595}, {12811, 50799363},
{12812, 50800131}, {12813, 50800899}, {12814, 50801667}, {12815, 50802435},
{12816, 50803203}, {12817, 50803971}, {12818, 50804739}, {12819, 50805507},
{12820, 50806275}, {12821, 50807043}, {12822, 50807811}, {12823, 50808579},
{12824, 50809347}, {12825, 50810115}, {12826, 50810883}, {12827, 50811651},
{12828, 50812419}, {12829, 67590403}, {12830, 67591427}, {12831, 2},
{12832, 50815235}, {12833, 50816003}, {12834, 50816771}, {12835, 50817539},
{12836, 50818307}, {12837, 50819075}, {12838, 50819843}, {12839, 50820611},
{12840, 50821379}, {12841, 50822147}, {12842, 50822915}, {12843, 50823683},
{12844, 50824451}, {12845, 50825219}, {12846, 50825987}, {12847, 50826755},
{12848, 50827523}, {12849, 50828291}, {12850, 50829059}, {12851, 50829827},
{12852, 50830595}, {12853, 50831363}, {12854, 50832131}, {12855, 50832899},
{12856, 50833667}, {12857, 50834435}, {12858, 50835203}, {12859, 50835971},
{12860, 50836739}, {12861, 50837507}, {12862, 50838275}, {12863, 50839043},
{12864, 50839811}, {12865, 50840579}, {12866, 50841347}, {12867, 50842115},
{12868, 17288451}, {12869, 17288707}, {12870, 17169155}, {12871, 17288963},
{12872, 1}, {12880, 50843651}, {12881, 33855747}, {12882, 34067203},
{12883, 33562371}, {12884, 34067715}, {12885, 34068227}, {12886, 34068739},
{12887, 34069251}, {12888, 34069763}, {12889, 34070275}, {12890, 34070787},
{12891, 33837571}, {12892, 33836803}, {12893, 34071299}, {12894, 34071811},
{12895, 34072323}, {12896, 17210115}, {12897, 17210883}, {12898, 17211651},
{12899, 17212163}, {12900, 17214211}, {12901, 17214467}, {12902, 17215235},
{12903, 17215747}, {12904, 17216003}, {12905, 17216515}, {12906, 17216771},
{12907, 17217027}, {12908, 17217283}, {12909, 17217539}, {12910, 17247491},
{12911, 17248259}, {12912, 17249027}, {12913, 17249795}, {12914, 17250563},
{12915, 17251331}, {12916, 17252099}, {12917, 17252867}, {12918, 17253635},
{12919, 17254403}, {12920, 17255171}, {12921, 17255939}, {12922, 17256707},
{12923, 17257475}, {12924, 34072835}, {12925, 34073347}, {12926, 17296643},
{12927, 1}, {12928, 17152259}, {12929, 17153795}, {12930, 17233923},
{12931, 17234179}, {12932, 17264131}, {12933, 17264899}, {12934, 17265667},
{12935, 17155075}, {12936, 17267203}, {12937, 17158147}, {12938, 17170947},
{12939, 17174019}, {12940, 17173763}, {12941, 17171203}, {12942, 17194755},
{12943, 17160195}, {12944, 17170435}, {12945, 17274115}, {12946, 17274883},
{12947, 17275651}, {12948, 17276419}, {12949, 17277187}, {12950, 17277955},
{12951, 17278723}, {12952, 17279491}, {12953, 17296899}, {12954, 17297155},
{12955, 17161731}, {12956, 17297411}, {12957, 17297667}, {12958, 17297923},
{12959, 17298179}, {12960, 17298435}, {12961, 17286403}, {12962, 17298691},
{12963, 17298947}, {12964, 17234435}, {12965, 17234691}, {12966, 17234947},
{12967, 17299203}, {12968, 17299459}, {12969, 17299715}, {12970, 17299971},
{12971, 17281795}, {12972, 17282563}, {12973, 17283331}, {12974, 17284099},
{12975, 17284867}, {12976, 17300227}, {12977, 34077699}, {12978, 34078211},
{12979, 34078723}, {12980, 34079235}, {12981, 34079747}, {12982, 33564931},
{12983, 34067971}, {12984, 34072067}, {12985, 34080259}, {12986, 34080771},
{12987, 34081283}, {12988, 34081795}, {12989, 34082307}, {12990, 34082819},
{12991, 34083331}, {12992, 34083843}, {12993, 34084355}, {12994, 34084867},
{12995, 34085379}, {12996, 34085891}, {12997, 34086403}, {12998, 34086915},
{12999, 34087427}, {13000, 34087939}, {13001, 50865667}, {13002, 50866435},
{13003, 50867203}, {13004, 34090755}, {13005, 50868483}, {13006, 34092035},
{13007, 50869763}, {13008, 17316099}, {13009, 17316355}, {13010, 17316611},
{13011, 17316867}, {13012, 17317123}, {13013, 17317379}, {13014, 17317635},
{13015, 17317891}, {13016, 17318147}, {13017, 17209603}, {13018, 17318403},
{13019, 17318659}, {13020, 17318915}, {13021, 17319171}, {13022, 17319427},
{13023, 17319683}, {13024, 17319939}, {13025, 17320195}, {13026, 17320451},
{13027, 17209859}, {13028, 17320707}, {13029, 17320963}, {13030, 17321219},
{13031, 17321475}, {13032, 17321731}, {13033, 17321987}, {13034, 17322243},
{13035, 17322499}, {13036, 17322755}, {13037, 17323011}, {13038, 17323267},
{13039, 17323523}, {13040, 17323779}, {13041, 17324035}, {13042, 17324291},
{13043, 17324547}, {13044, 17324803}, {13045, 17325059}, {13046, 17325315},
{13047, 17325571}, {13048, 17325827}, {13049, 17326083}, {13050, 17326339},
{13051, 17326595}, {13052, 17326851}, {13053, 17327107}, {13054, 17327363},
{13055, 34104835}, {13056, 67659779}, {13057, 67660803}, {13058, 67661827},
{13059, 50885635}, {13060, 67663619}, {13061, 50887427}, {13062, 50888195},
{13063, 84443395}, {13064, 67667459}, {13065, 50891267}, {13066, 50892035},
{13067, 50892803}, {13068, 67670787}, {13069, 67671811}, {13070, 50895619},
{13071, 50896387}, {13072, 34119939}, {13073, 50897667}, {13074, 67675651},
{13075, 67676675}, {13076, 34123267}, {13077, 84455427}, {13078, 101233923},
{13079, 84458243}, {13080, 50901507}, {13081, 84459523}, {13082, 84460803},
{13083, 67684867}, {13084, 50908675}, {13085, 50909443}, {13086, 50910211},
{13087, 67688195}, {13088, 84466435}, {13089, 67690499}, {13090, 50914307},
{13091, 50915075}, {13092, 50915843}, {13093, 34139395}, {13094, 34139907},
{13095, 34128643}, {13096, 34140419}, {13097, 50918147}, {13098, 50918915},
{13099, 84474115}, {13100, 50920963}, {13101, 67698947}, {13102, 84477187},
{13103, 50924035}, {13104, 34147587}, {13105, 34148099}, {13106, 84480259},
{13107, 67704323}, {13108, 84482563}, {13109, 50929411}, {13110, 84484611},
{13111, 34154243}, {13112, 50931971}, {13113, 50932739}, {13114, 50933507},
{13115, 50934275}, {13116, 50935043}, {13117, 67713027}, {13118, 50936835},
{13119, 34160387}, {13120, 50938115}, {13121, 50938883}, {13122, 50939651},
{13123, 67717635}, {13124, 50941443}, {13125, 50942211}, {13126, 50942979},
{13127, 84498179}, {13128, 67722243}, {13129, 34168835}, {13130, 84500995},
{13131, 34170627}, {13132, 67725571}, {13133, 67680003}, {13134, 50949379},
{13135, 50950147}, {13136, 50950915}, {13137, 67728899}, {13138, 34175491},
{13139, 50953219}, {13140, 67731203}, {13141, 34177795}, {13142, 84509955},
{13143, 50904323}, {13144, 34179587}, {13145, 34180099}, {13146, 34180611},
{13147, 34181123}, {13148, 34181635}, {13149, 34182147}, {13150, 34182659},
{13151, 34183171}, {13152, 34183683}, {13153, 34184195}, {13154, 50961923},
{13155, 50962691}, {13156, 50963459}, {13157, 50964227}, {13158, 50964995},
{13159, 50965763}, {13160, 50966531}, {13161, 50967299}, {13162, 50968067},
{13163, 50968835}, {13164, 50969603}, {13165, 50970371}, {13166, 50971139},
{13167, 50971907}, {13168, 50972675}, {13169, 50973443}, {13170, 34196995},
{13171, 34197507}, {13172, 50975235}, {13173, 34198787}, {13174, 34199299},
{13175, 34199811}, {13176, 50977539}, {13177, 50978307}, {13178, 34201859},
{13179, 34202371}, {13180, 34202883}, {13181, 34203395}, {13182, 34203907},
{13183, 67758851}, {13184, 34196483}, {13185, 34205443}, {13186, 34205955},
{13187, 34206467}, {13188, 34206979}, {13189, 34207491}, {13190, 34208003},
{13191, 34208515}, {13192, 50986243}, {13193, 67764227}, {13194, 34210819},
{13195, 34211331}, {13196, 34211843}, {13197, 34212355}, {13198, 34212867},
{13199, 34213379}, {13200, 34213891}, {13201, 50991619}, {13202, 50992387},
{13203, 50990851}, {13204, 50993155}, {13205, 34216707}, {13206, 34217219},
{13207, 34217731}, {13208, 33556995}, {13209, 34218243}, {13210, 34218755},
{13211, 34219267}, {13212, 34219779}, {13213, 34220291}, {13214, 34220803},
{13215, 50998531}, {13216, 50999299}, {13217, 34200579}, {13218, 51000067},
{13219, 51000835}, {13220, 51001603}, {13221, 34201347}, {13222, 51002371},
{13223, 51003139}, {13224, 67781123}, {13225, 34196483}, {13226, 51004931},
{13227, 51005699}, {13228, 51006467}, {13229, 51007235}, {13230, 84562435},
{13231, 101340931}, {13232, 34233603}, {13233, 34234115}, {13234, 34234627},
{13235, 34235139}, {13236, 34235651}, {13237, 34236163}, {13238, 34236675},
{13239, 34237187}, {13240, 34237699}, {13241, 34237187}, {13242, 34238211},
{13243, 34238723}, {13244, 34239235}, {13245, 34239747}, {13246, 34240259},
{13247, 34239747}, {13248, 34240771}, {13249, 34241283}, {13250, 2},
{13251, 34241795}, {13252, 33827331}, {13253, 33554947}, {13254, 67796739},
{13255, 2}, {13256, 34243331}, {13257, 34243843}, {13258, 34244355},
{13259, 34196227}, {13260, 34244867}, {13261, 34245379}, {13262, 34220803},
{13263, 34245891}, {13264, 33557251}, {13265, 34246403}, {13266, 51024131},
{13267, 34247683}, {13268, 34208003}, {13269, 51025411}, {13270, 51026179},
{13271, 34249731}, {13272, 2}, {13273, 51027459}, {13274, 34251011},
{13275, 34231811}, {13276, 34251523}, {13277, 34252035}, {13278, 51029763},
{13279, 51030531}, {13280, 34254083}, {13281, 34254595}, {13282, 34255107},
{13283, 34255619}, {13284, 34256131}, {13285, 34256643}, {13286, 34257155},
{13287, 34257667}, {13288, 34258179}, {13289, 51035907}, {13290, 51036675},
{13291, 51037443}, {13292, 51038211}, {13293, 51038979}, {13294, 51039747},
{13295, 51040515}, {13296, 51041283}, {13297, 51042051}, {13298, 51042819},
{13299, 51043587}, {13300, 51044355}, {13301, 51045123}, {13302, 51045891},
{13303, 51046659}, {13304, 51047427}, {13305, 51048195}, {13306, 51048963},
{13307, 51049731}, {13308, 51050499}, {13309, 51051267}, {13310, 51052035},
{13311, 51052803}, {13312, 1}, {42125, 2}, {42128, 1},
{42183, 2}, {42192, 1}, {42540, 2}, {42560, 17499139},
{42561, 1}, {42562, 17499395}, {42563, 1}, {42564, 17499651},
{42565, 1}, {42566, 17499907}, {42567, 1}, {42568, 17500163},
{42569, 1}, {42570, 16946435}, {42571, 1}, {42572, 17500419},
{42573, 1}, {42574, 17500675}, {42575, 1}, {42576, 17500931},
{42577, 1}, {42578, 17501187}, {42579, 1}, {42580, 17501443},
{42581, 1}, {42582, 17501699}, {42583, 1}, {42584, 17501955},
{42585, 1}, {42586, 17502211}, {42587, 1}, {42588, 17502467},
{42589, 1}, {42590, 17502723}, {42591, 1}, {42592, 17502979},
{42593, 1}, {42594, 17503235}, {42595, 1}, {42596, 17503491},
{42597, 1}, {42598, 17503747}, {42599, 1}, {42600, 17504003},
{42601, 1}, {42602, 17504259}, {42603, 1}, {42604, 17504515},
{42605, 1}, {42624, 17504771}, {42625, 1}, {42626, 17505027},
{42627, 1}, {42628, 17505283}, {42629, 1}, {42630, 17505539},
{42631, 1}, {42632, 17505795}, {42633, 1}, {42634, 17506051},
{42635, 1}, {42636, 17506307}, {42637, 1}, {42638, 17506563},
{42639, 1}, {42640, 17506819}, {42641, 1}, {42642, 17507075},
{42643, 1}, {42644, 17507331}, {42645, 1}, {42646, 17507587},
{42647, 1}, {42648, 17507843}, {42649, 1}, {42650, 17508099},
{42651, 1}, {42652, 16873219}, {42653, 16873731}, {42654, 1},
{42744, 2}, {42752, 1}, {42786, 17508355}, {42787, 1},
{42788, 17508611}, {42789, 1}, {42790, 17508867}, {42791, 1},
{42792, 17509123}, {42793, 1}, {42794, 17509379}, {42795, 1},
{42796, 17509635}, {42797, 1}, {42798, 17509891}, {42799, 1},
{42802, 17510147}, {42803, 1}, {42804, 17510403}, {42805, 1},
{42806, 17510659}, {42807, 1}, {42808, 17510915}, {42809, 1},
{42810, 17511171}, {42811, 1}, {42812, 17511427}, {42813, 1},
{42814, 17511683}, {42815, 1}, {42816, 17511939}, {42817, 1},
{42818, 17512195}, {42819, 1}, {42820, 17512451}, {42821, 1},
{42822, 17512707}, {42823, 1}, {42824, 17512963}, {42825, 1},
{42826, 17513219}, {42827, 1}, {42828, 17513475}, {42829, 1},
{42830, 17513731}, {42831, 1}, {42832, 17513987}, {42833, 1},
{42834, 17514243}, {42835, 1}, {42836, 17514499}, {42837, 1},
{42838, 17514755}, {42839, 1}, {42840, 17515011}, {42841, 1},
{42842, 17515267}, {42843, 1}, {42844, 17515523}, {42845, 1},
{42846, 17515779}, {42847, 1}, {42848, 17516035}, {42849, 1},
{42850, 17516291}, {42851, 1}, {42852, 17516547}, {42853, 1},
{42854, 17516803}, {42855, 1}, {42856, 17517059}, {42857, 1},
{42858, 17517315}, {42859, 1}, {42860, 17517571}, {42861, 1},
{42862, 17517827}, {42863, 1}, {42864, 17517827}, {42865, 1},
{42873, 17518083}, {42874, 1}, {42875, 17518339}, {42876, 1},
{42877, 17518595}, {42878, 17518851}, {42879, 1}, {42880, 17519107},
{42881, 1}, {42882, 17519363}, {42883, 1}, {42884, 17519619},
{42885, 1}, {42886, 17519875}, {42887, 1}, {42891, 17520131},
{42892, 1}, {42893, 16961539}, {42894, 1}, {42896, 17520387},
{42897, 1}, {42898, 17520643}, {42899, 1}, {42902, 17520899},
{42903, 1}, {42904, 17521155}, {42905, 1}, {42906, 17521411},
{42907, 1}, {42908, 17521667}, {42909, 1}, {42910, 17521923},
{42911, 1}, {42912, 17522179}, {42913, 1}, {42914, 17522435},
{42915, 1}, {42916, 17522691}, {42917, 1}, {42918, 17522947},
{42919, 1}, {42920, 17523203}, {42921, 1}, {42922, 16841475},
{42923, 16959235}, {42924, 16961283}, {42925, 17523459}, {42926, 16961795},
{42927, 1}, {42928, 17523715}, {42929, 17523971}, {42930, 16962307},
{42931, 17524227}, {42932, 17524483}, {42933, 1}, {42934, 17524739},
{42935, 1}, {42936, 17524995}, {42937, 1}, {42938, 17525251},
{42939, 1}, {42940, 17525507}, {42941, 1}, {42942, 17525763},
{42943, 1}, {42944, 17526019}, {42945, 1}, {42946, 17526275},
{42947, 1}, {42948, 17526531}, {42949, 16964611}, {42950, 17526787},
{42951, 17527043}, {42952, 1}, {42953, 17527299}, {42954, 1},
{42955, 17527555}, {42956, 17527811}, {42957, 1}, {42958, 2},
{42960, 17528067}, {42961, 1}, {42962, 2}, {42963, 1},
{42964, 2}, {42965, 1}, {42966, 17528323}, {42967, 1},
{42968, 17528579}, {42969, 1}, {42970, 17528835}, {42971, 1},
{42972, 17529091}, {42973, 2}, {42994, 16777731}, {42995, 16778499},
{42996, 16781315}, {42997, 17529347}, {42998, 1}, {43000, 16802051},
{43001, 16808195}, {43002, 1}, {43053, 2}, {43056, 1},
{43066, 2}, {43072, 1}, {43128, 2}, {43136, 1},
{43206, 2}, {43214, 1}, {43226, 2}, {43232, 1},
{43348, 2}, {43359, 1}, {43389, 2}, {43392, 1},
{43470, 2}, {43471, 1}, {43482, 2}, {43486, 1},
{43519, 2}, {43520, 1}, {43575, 2}, {43584, 1},
{43598, 2}, {43600, 1}, {43610, 2}, {43612, 1},
{43715, 2}, {43739, 1}, {43767, 2}, {43777, 1},
{43783, 2}, {43785, 1}, {43791, 2}, {43793, 1},
{43799, 2}, {43808, 1}, {43815, 2}, {43816, 1},
{43823, 2}, {43824, 1}, {43868, 17508867}, {43869, 17529603},
{43870, 17135363}, {43871, 17529859}, {43872, 1}, {43881, 17530115},
{43882, 1}, {43884, 2}, {43888, 17530371}, {43889, 17530627},
{43890, 17530883}, {43891, 17531139}, {43892, 17531395}, {43893, 17531651},
{43894, 17531907}, {43895, 17532163}, {43896, 17532419}, {43897, 17532675},
{43898, 17532931}, {43899, 17533187}, {43900, 17533443}, {43901, 17533699},
{43902, 17533955}, {43903, 17534211}, {43904, 17534467}, {43905, 17534723},
{43906, 17534979}, {43907, 17535235}, {43908, 17535491}, {43909, 17535747},
{43910, 17536003}, {43911, 17536259}, {43912, 17536515}, {43913, 17536771},
{43914, 17537027}, {43915, 17537283}, {43916, 17537539}, {43917, 17537795},
{43918, 17538051}, {43919, 17538307}, {43920, 17538563}, {43921, 17538819},
{43922, 17539075}, {43923, 17539331}, {43924, 17539587}, {43925, 17539843},
{43926, 17540099}, {43927, 17540355}, {43928, 17540611}, {43929, 17540867},
{43930, 17541123}, {43931, 17541379}, {43932, 17541635}, {43933, 17541891},
{43934, 17542147}, {43935, 17542403}, {43936, 17542659}, {43937, 17542915},
{43938, 17543171}, {43939, 17543427}, {43940, 17543683}, {43941, 17543939},
{43942, 17544195}, {43943, 17544451}, {43944, 17544707}, {43945, 17544963},
{43946, 17545219}, {43947, 17545475}, {43948, 17545731}, {43949, 17545987},
{43950, 17546243}, {43951, 17546499}, {43952, 17546755}, {43953, 17547011},
{43954, 17547267}, {43955, 17547523}, {43956, 17547779}, {43957, 17548035},
{43958, 17548291}, {43959, 17548547}, {43960, 17548803}, {43961, 17549059},
{43962, 17549315}, {43963, 17549571}, {43964, 17549827}, {43965, 17550083},
{43966, 17550339}, {43967, 17550595}, {43968, 1}, {44014, 2},
{44016, 1}, {44026, 2}, {44032, 1}, {55204, 2},
{55216, 1}, {55239, 2}, {55243, 1}, {55292, 2},
{63744, 17550851}, {63745, 17551107}, {63746, 17192707}, {63747, 17551363},
{63748, 17551619}, {63749, 17551875}, {63750, 17552131}, {63751, 17206531},
{63753, 17552387}, {63754, 17194755}, {63755, 17552643}, {63756, 17552899},
{63757, 17553155}, {63758, 17553411}, {63759, 17553667}, {63760, 17553923},
{63761, 17554179}, {63762, 17554435}, {63763, 17554691}, {63764, 17554947},
{63765, 17555203}, {63766, 17555459}, {63767, 17555715}, {63768, 17555971},
{63769, 17556227}, {63770, 17556483}, {63771, 17556739}, {63772, 17556995},
{63773, 17557251}, {63774, 17557507}, {63775, 17557763}, {63776, 17558019},
{63777, 17558275}, {63778, 17558531}, {63779, 17558787}, {63780, 17559043},
{63781, 17559299}, {63782, 17559555}, {63783, 17559811}, {63784, 17560067},
{63785, 17560323}, {63786, 17560579}, {63787, 17560835}, {63788, 17561091},
{63789, 17561347}, {63790, 17561603}, {63791, 17561859}, {63792, 17562115},
{63793, 17562371}, {63794, 17562627}, {63795, 17562883}, {63796, 17184003},
{63797, 17563139}, {63798, 17563395}, {63799, 17563651}, {63800, 17563907},
{63801, 17564163}, {63802, 17564419}, {63803, 17564675}, {63804, 17564931},
{63805, 17565187}, {63806, 17565443}, {63807, 17565699}, {63808, 17202691},
{63809, 17565955}, {63810, 17566211}, {63811, 17566467}, {63812, 17566723},
{63813, 17566979}, {63814, 17567235}, {63815, 17567491}, {63816, 17567747},
{63817, 17568003}, {63818, 17568259}, {63819, 17568515}, {63820, 17568771},
{63821, 17569027}, {63822, 17569283}, {63823, 17569539}, {63824, 17569795},
{63825, 17570051}, {63826, 17570307}, {63827, 17570563}, {63828, 17570819},
{63829, 17571075}, {63830, 17571331}, {63831, 17571587}, {63832, 17571843},
{63833, 17572099}, {63834, 17572355}, {63835, 17572611}, {63836, 17554947},
{63837, 17572867}, {63838, 17573123}, {63839, 17573379}, {63840, 17573635},
{63841, 17573891}, {63842, 17574147}, {63843, 17574403}, {63844, 17574659},
{63845, 17574915}, {63846, 17575171}, {63847, 17575427}, {63848, 17575683},
{63849, 17575939}, {63850, 17576195}, {63851, 17576451}, {63852, 17576707},
{63853, 17576963}, {63854, 17577219}, {63855, 17577475}, {63856, 17577731},
{63857, 17193219}, {63858, 17577987}, {63859, 17578243}, {63860, 17578499},
{63861, 17578755}, {63862, 17579011}, {63863, 17579267}, {63864, 17579523},
{63865, 17579779}, {63866, 17580035}, {63867, 17580291}, {63868, 17580547},
{63869, 17580803}, {63870, 17581059}, {63871, 17581315}, {63872, 17581571},
{63873, 17161731}, {63874, 17581827}, {63875, 17582083}, {63876, 17582339},
{63877, 17582595}, {63878, 17582851}, {63879, 17583107}, {63880, 17583363},
{63881, 17583619}, {63882, 17156867}, {63883, 17583875}, {63884, 17584131},
{63885, 17584387}, {63886, 17584643}, {63887, 17584899}, {63888, 17585155},
{63889, 17585411}, {63890, 17585667}, {63891, 17585923}, {63892, 17586179},
{63893, 17586435}, {63894, 17586691}, {63895, 17586947}, {63896, 17587203},
{63897, 17587459}, {63898, 17587715}, {63899, 17587971}, {63900, 17588227},
{63901, 17588483}, {63902, 17588739}, {63903, 17588995}, {63904, 17589251},
{63905, 17577475}, {63906, 17589507}, {63907, 17589763}, {63908, 17590019},
{63909, 17590275}, {63910, 17590531}, {63911, 17590787}, {63912, 17327619},
{63913, 17591043}, {63914, 17573379}, {63915, 17591299}, {63916, 17591555},
{63917, 17591811}, {63918, 17592067}, {63919, 17592323}, {63920, 17592579},
{63921, 17592835}, {63922, 17593091}, {63923, 17593347}, {63924, 17593603},
{63925, 17593859}, {63926, 17594115}, {63927, 17594371}, {63928, 17594627},
{63929, 17594883}, {63930, 17595139}, {63931, 17595395}, {63932, 17595651},
{63933, 17595907}, {63934, 17596163}, {63935, 17554947}, {63936, 17596419},
{63937, 17596675}, {63938, 17596931}, {63939, 17597187}, {63940, 17206275},
{63941, 17597443}, {63942, 17597699}, {63943, 17597955}, {63944, 17598211},
{63945, 17598467}, {63946, 17598723}, {63947, 17598979}, {63948, 17599235},
{63949, 17599491}, {63950, 17599747}, {63951, 17600003}, {63952, 17600259},
{63953, 17264899}, {63954, 17600515}, {63955, 17600771}, {63956, 17601027},
{63957, 17601283}, {63958, 17601539}, {63959, 17601795}, {63960, 17602051},
{63961, 17602307}, {63962, 17602563}, {63963, 17573891}, {63964, 17602819},
{63965, 17603075}, {63966, 17603331}, {63967, 17603587}, {63968, 17603843},
{63969, 17604099}, {63970, 17604355}, {63971, 17604611}, {63972, 17604867},
{63973, 17605123}, {63974, 17605379}, {63975, 17605635}, {63976, 17605891},
{63977, 17194499}, {63978, 17606147}, {63979, 17606403}, {63980, 17606659},
{63981, 17606915}, {63982, 17607171}, {63983, 17607427}, {63984, 17607683},
{63985, 17607939}, {63986, 17608195}, {63987, 17608451}, {63988, 17608707},
{63989, 17608963}, {63990, 17609219}, {63991, 17181955}, {63992, 17609475},
{63993, 17609731}, {63994, 17609987}, {63995, 17610243}, {63996, 17610499},
{63997, 17610755}, {63998, 17611011}, {63999, 17611267}, {64000, 17611523},
{64001, 17611779}, {64002, 17612035}, {64003, 17612291}, {64004, 17612547},
{64005, 17612803}, {64006, 17613059}, {64007, 17613315}, {64008, 17188867},
{64009, 17613571}, {64010, 17189635}, {64011, 17613827}, {64012, 17614083},
{64013, 17614339}, {64014, 1}, {64016, 17614595}, {64017, 1},
{64018, 17614851}, {64019, 1}, {64021, 17615107}, {64022, 17615363},
{64023, 17615619}, {64024, 17615875}, {64025, 17616131}, {64026, 17616387},
{64027, 17616643}, {64028, 17616899}, {64029, 17617155}, {64030, 17183747},
{64031, 1}, {64032, 17617411}, {64033, 1}, {64034, 17617667},
{64035, 1}, {64037, 17617923}, {64038, 17618179}, {64039, 1},
{64042, 17618435}, {64043, 17618691}, {64044, 17618947}, {64045, 17619203},
{64046, 17619459}, {64047, 17619715}, {64048, 17619971}, {64049, 17620227},
{64050, 17620483}, {64051, 17620739}, {64052, 17620995}, {64053, 17621251},
{64054, 17621507}, {64055, 17621763}, {64056, 17622019}, {64057, 17622275},
{64058, 17622531}, {64059, 17622787}, {64060, 17163523}, {64061, 17623043},
{64062, 17623299}, {64063, 17623555}, {64064, 17623811}, {64065, 17624067},
{64066, 17624323}, {64067, 17624579}, {64068, 17624835}, {64069, 17625091},
{64070, 17625347}, {64071, 17625603}, {64072, 17625859}, {64073, 17626115},
{64074, 17626371}, {64075, 17626627}, {64076, 17275651}, {64077, 17626883},
{64078, 17627139}, {64079, 17627395}, {64080, 17627651}, {64081, 17278723},
{64082, 17627907}, {64083, 17628163}, {64084, 17628419}, {64085, 17628675},
{64086, 17628931}, {64087, 17586691}, {64088, 17629187}, {64089, 17629443},
{64090, 17629699}, {64091, 17629955}, {64092, 17630211}, {64093, 17630467},
{64095, 17630723}, {64096, 17630979}, {64097, 17631235}, {64098, 17631491},
{64099, 17631747}, {64100, 17632003}, {64101, 17632259}, {64102, 17632515},
{64103, 17617923}, {64104, 17632771}, {64105, 17633027}, {64106, 17633283},
{64107, 17633539}, {64108, 17633795}, {64109, 17634051}, {64110, 2},
{64112, 17634307}, {64113, 17634563}, {64114, 17634819}, {64115, 17635075},
{64116, 17635331}, {64117, 17635587}, {64118, 17635843}, {64119, 17636099},
{64120, 17621507}, {64121, 17636355}, {64122, 17636611}, {64123, 17636867},
{64124, 17614595}, {64125, 17637123}, {64126, 17637379}, {64127, 17637635},
{64128, 17637891}, {64129, 17638147}, {64130, 17638403}, {64131, 17638659},
{64132, 17638915}, {64133, 17639171}, {64134, 17639427}, {64135, 17639683},
{64136, 17639939}, {64137, 17623555}, {64138, 17640195}, {64139, 17623811},
{64140, 17640451}, {64141, 17640707}, {64142, 17640963}, {64143, 17641219},
{64144, 17641475}, {64145, 17614851}, {64146, 17560323}, {64147, 17641731},
{64148, 17641987}, {64149, 17171971}, {64150, 17577731}, {64151, 17598723},
{64152, 17642243}, {64153, 17642499}, {64154, 17625603}, {64155, 17642755},
{64156, 17625859}, {64157, 17643011}, {64158, 17643267}, {64159, 17643523},
{64160, 17615363}, {64161, 17643779}, {64162, 17644035}, {64163, 17644291},
{64164, 17644547}, {64165, 17644803}, {64166, 17615619}, {64167, 17645059},
{64168, 17645315}, {64169, 17645571}, {64170, 17645827}, {64171, 17646083},
{64172, 17646339}, {64173, 17628931}, {64174, 17646595}, {64175, 17646851},
{64176, 17586691}, {64177, 17647107}, {64178, 17629955}, {64179, 17647363},
{64180, 17647619}, {64181, 17647875}, {64182, 17648131}, {64183, 17648387},
{64184, 17631235}, {64185, 17648643}, {64186, 17617667}, {64187, 17648899},
{64188, 17631491}, {64189, 17572867}, {64190, 17649155}, {64191, 17631747},
{64192, 17649411}, {64193, 17632259}, {64194, 17649667}, {64195, 17649923},
{64196, 17650179}, {64197, 17650435}, {64198, 17650691}, {64199, 17632771},
{64200, 17616899}, {64201, 17650947}, {64202, 17633027}, {64203, 17651203},
{64204, 17633283}, {64205, 17651459}, {64206, 17206531}, {64207, 17651715},
{64208, 17651971}, {64209, 17652227}, {64210, 17652483}, {64211, 17652739},
{64212, 17652995}, {64213, 17653251}, {64214, 17653507}, {64215, 17653763},
{64216, 17654019}, {64217, 17654275}, {64218, 2}, {64256, 34431747},
{64257, 34432259}, {64258, 34432771}, {64259, 51209219}, {64260, 51210499},
{64261, 33559043}, {64263, 2}, {64275, 34434051}, {64276, 34434563},
{64277, 34435075}, {64278, 34435587}, {64279, 34436099}, {64280, 2},
{64285, 34436611}, {64286, 1}, {64287, 34437123}, {64288, 17660419},
{64289, 17054467}, {64290, 17055235}, {64291, 17660675}, {64292, 17660931},
{64293, 17661187}, {64294, 17661443}, {64295, 17661699}, {64296, 17661955},
{64297, 17047043}, {64298, 34439427}, {64299, 34439939}, {64300, 51217667},
{64301, 51218435}, {64302, 34441987}, {64303, 34442499}, {64304, 34443011},
{64305, 34443523}, {64306, 34444035}, {64307, 34444547}, {64308, 34445059},
{64309, 34445571}, {64310, 34446083}, {64311, 2}, {64312, 34446595},
{64313, 34447107}, {64314, 34447619}, {64315, 34448131}, {64316, 34448643},
{64317, 2}, {64318, 34449155}, {64319, 2}, {64320, 34449667},
{64321, 34450179}, {64322, 2}, {64323, 34450691}, {64324, 34451203},
{64325, 2}, {64326, 34451715}, {64327, 34452227}, {64328, 34452739},
{64329, 34440451}, {64330, 34453251}, {64331, 34453763}, {64332, 34454275},
{64333, 34454787}, {64334, 34455299}, {64335, 34455811}, {64336, 17679107},
{64338, 17679363}, {64342, 17679619}, {64346, 17679875}, {64350, 17680131},
{64354, 17680387}, {64358, 17680643}, {64362, 17680899}, {64366, 17681155},
{64370, 17681411}, {64374, 17681667}, {64378, 17681923}, {64382, 17682179},
{64386, 17682435}, {64388, 17682691}, {64390, 17682947}, {64392, 17683203},
{64394, 17683459}, {64396, 17683715}, {64398, 17683971}, {64402, 17684227},
{64406, 17684483}, {64410, 17684739}, {64414, 17684995}, {64416, 17685251},
{64420, 17685507}, {64422, 17685763}, {64426, 17686019}, {64430, 17686275},
{64432, 17686531}, {64434, 1}, {64451, 2}, {64467, 17686787},
{64471, 16911619}, {64473, 17687043}, {64475, 17687299}, {64477, 33688835},
{64478, 17687555}, {64480, 17687811}, {64482, 17688067}, {64484, 17688323},
{64488, 17688579}, {64490, 34466051}, {64492, 34466563}, {64494, 34467075},
{64496, 34467587}, {64498, 34468099}, {64500, 34468611}, {64502, 34469123},
{64505, 34469635}, {64508, 17692931}, {64512, 34470403}, {64513, 34470915},
{64514, 34471427}, {64515, 34469635}, {64516, 34471939}, {64517, 34472451},
{64518, 34472963}, {64519, 34473475}, {64520, 34473987}, {64521, 34474499},
{64522, 34475011}, {64523, 34475523}, {64524, 34476035}, {64525, 34476547},
{64526, 34477059}, {64527, 34477571}, {64528, 34478083}, {64529, 34478595},
{64530, 34479107}, {64531, 34479619}, {64532, 34480131}, {64533, 34480643},
{64534, 34481155}, {64535, 34480899}, {64536, 34481667}, {64537, 34482179},
{64538, 34482691}, {64539, 34483203}, {64540, 34483715}, {64541, 34484227},
{64542, 34484739}, {64543, 34485251}, {64544, 34485763}, {64545, 34486275},
{64546, 34486787}, {64547, 34487299}, {64548, 34487811}, {64549, 34488323},
{64550, 34488835}, {64551, 34489347}, {64552, 34489859}, {64553, 34490371},
{64554, 34490883}, {64555, 34491395}, {64556, 34491907}, {64557, 34492419},
{64558, 34492931}, {64559, 34493443}, {64560, 34493955}, {64561, 34494467},
{64562, 34494979}, {64563, 34495491}, {64564, 34496003}, {64565, 34496515},
{64566, 34497027}, {64567, 34497539}, {64568, 34498051}, {64569, 34498563},
{64570, 34499075}, {64571, 34499587}, {64572, 34500099}, {64573, 34500611},
{64574, 34501123}, {64575, 34501635}, {64576, 34502147}, {64577, 34502659},
{64578, 34503171}, {64579, 34503683}, {64580, 34504195}, {64581, 34504707},
{64582, 34481411}, {64583, 34481923}, {64584, 34505219}, {64585, 34505731},
{64586, 34506243}, {64587, 34506755}, {64588, 34507267}, {64589, 34507779},
{64590, 34508291}, {64591, 34508803}, {64592, 34509315}, {64593, 34509827},
{64594, 34510339}, {64595, 34510851}, {64596, 34511363}, {64597, 34480387},
{64598, 34511875}, {64599, 34512387}, {64600, 34504451}, {64601, 34512899},
{64602, 34511619}, {64603, 34513411}, {64604, 34513923}, {64605, 34514435},
{64606, 51292163}, {64607, 51292931}, {64608, 51293699}, {64609, 51294467},
{64610, 51295235}, {64611, 51296003}, {64612, 34519555}, {64613, 34520067},
{64614, 34471427}, {64615, 34520579}, {64616, 34469635}, {64617, 34471939},
{64618, 34521091}, {64619, 34521603}, {64620, 34473987}, {64621, 34522115},
{64622, 34474499}, {64623, 34475011}, {64624, 34522627}, {64625, 34523139},
{64626, 34477059}, {64627, 34523651}, {64628, 34477571}, {64629, 34478083},
{64630, 34524163}, {64631, 34524675}, {64632, 34479107}, {64633, 34525187},
{64634, 34479619}, {64635, 34480131}, {64636, 34494467}, {64637, 34494979},
{64638, 34496515}, {64639, 34497027}, {64640, 34497539}, {64641, 34499587},
{64642, 34500099}, {64643, 34500611}, {64644, 34501123}, {64645, 34503171},
{64646, 34503683}, {64647, 34504195}, {64648, 34525699}, {64649, 34505219},
{64650, 34526211}, {64651, 34526723}, {64652, 34508291}, {64653, 34527235},
{64654, 34508803}, {64655, 34509315}, {64656, 34514435}, {64657, 34527747},
{64658, 34528259}, {64659, 34504451}, {64660, 34506499}, {64661, 34512899},
{64662, 34511619}, {64663, 34470403}, {64664, 34470915}, {64665, 34528771},
{64666, 34471427}, {64667, 34529283}, {64668, 34472451}, {64669, 34472963},
{64670, 34473475}, {64671, 34473987}, {64672, 34529795}, {64673, 34475523},
{64674, 34476035}, {64675, 34476547}, {64676, 34477059}, {64677, 34530307},
{64678, 34479107}, {64679, 34480643}, {64680, 34481155}, {64681, 34480899},
{64682, 34481667}, {64683, 34482179}, {64684, 34483203}, {64685, 34483715},
{64686, 34484227}, {64687, 34484739}, {64688, 34485251}, {64689, 34485763},
{64690, 34530819}, {64691, 34486275}, {64692, 34486787}, {64693, 34487299},
{64694, 34487811}, {64695, 34488323}, {64696, 34488835}, {64697, 34489859},
{64698, 34490371}, {64699, 34490883}, {64700, 34491395}, {64701, 34491907},
{64702, 34492419}, {64703, 34492931}, {64704, 34493443}, {64705, 34493955},
{64706, 34495491}, {64707, 34496003}, {64708, 34498051}, {64709, 34498563},
{64710, 34499075}, {64711, 34499587}, {64712, 34500099}, {64713, 34501635},
{64714, 34502147}, {64715, 34502659}, {64716, 34503171}, {64717, 34531331},
{64718, 34504707}, {64719, 34481411}, {64720, 34481923}, {64721, 34505219},
{64722, 34506755}, {64723, 34507267}, {64724, 34507779}, {64725, 34508291},
{64726, 34531843}, {64727, 34509827}, {64728, 34510339}, {64729, 34532355},
{64730, 34480387}, {64731, 34511875}, {64732, 34512387}, {64733, 34504451},
{64734, 34509571}, {64735, 34471427}, {64736, 34529283}, {64737, 34473987},
{64738, 34529795}, {64739, 34477059}, {64740, 34530307}, {64741, 34479107},
{64742, 34532867}, {64743, 34485251}, {64744, 34533379}, {64745, 34533891},
{64746, 34534403}, {64747, 34499587}, {64748, 34500099}, {64749, 34503171},
{64750, 34508291}, {64751, 34531843}, {64752, 34504451}, {64753, 34509571},
{64754, 51312131}, {64755, 51312899}, {64756, 51313667}, {64757, 34537219},
{64758, 34537731}, {64759, 34538243}, {64760, 34538755}, {64761, 34539267},
{64762, 34539779}, {64763, 34540291}, {64764, 34540803}, {64765, 34541315},
{64766, 34541827}, {64767, 34542339}, {64768, 34512131}, {64769, 34542851},
{64770, 34543363}, {64771, 34543875}, {64772, 34512643}, {64773, 34544387},
{64774, 34544899}, {64775, 34545411}, {64776, 34545923}, {64777, 34546435},
{64778, 34546947}, {64779, 34547459}, {64780, 34533891}, {64781, 34547971},
{64782, 34548483}, {64783, 34548995}, {64784, 34549507}, {64785, 34537219},
{64786, 34537731}, {64787, 34538243}, {64788, 34538755}, {64789, 34539267},
{64790, 34539779}, {64791, 34540291}, {64792, 34540803}, {64793, 34541315},
{64794, 34541827}, {64795, 34542339}, {64796, 34512131}, {64797, 34542851},
{64798, 34543363}, {64799, 34543875}, {64800, 34512643}, {64801, 34544387},
{64802, 34544899}, {64803, 34545411}, {64804, 34545923}, {64805, 34546435},
{64806, 34546947}, {64807, 34547459}, {64808, 34533891}, {64809, 34547971},
{64810, 34548483}, {64811, 34548995}, {64812, 34549507}, {64813, 34546435},
{64814, 34546947}, {64815, 34547459}, {64816, 34533891}, {64817, 34533379},
{64818, 34534403}, {64819, 34489347}, {64820, 34483715}, {64821, 34484227},
{64822, 34484739}, {64823, 34546435}, {64824, 34546947}, {64825, 34547459},
{64826, 34489347}, {64827, 34489859}, {64828, 34550019}, {64830, 1},
{64848, 51327747}, {64849, 51328515}, {64851, 51329283}, {64852, 51330051},
{64853, 51330819}, {64854, 51331587}, {64855, 51332355}, {64856, 51258371},
{64858, 51333123}, {64859, 51333891}, {64860, 51334659}, {64861, 51335427},
{64862, 51336195}, {64863, 51336963}, {64865, 51337731}, {64866, 51338499},
{64868, 51339267}, {64870, 51340035}, {64871, 51340803}, {64873, 51341571},
{64874, 51342339}, {64876, 51343107}, {64878, 51343875}, {64879, 51344643},
{64881, 51345411}, {64883, 51346179}, {64884, 51346947}, {64885, 51347715},
{64886, 51348483}, {64888, 51349251}, {64889, 51350019}, {64890, 51350787},
{64891, 51351555}, {64892, 51352323}, {64894, 51353091}, {64895, 51353859},
{64896, 51354627}, {64897, 51355395}, {64898, 51356163}, {64899, 51356931},
{64901, 51357699}, {64903, 51358467}, {64905, 51359235}, {64906, 51258627},
{64907, 51360003}, {64908, 51360771}, {64909, 51281923}, {64910, 51259139},
{64911, 51361539}, {64912, 2}, {64914, 51362307}, {64915, 51363075},
{64916, 51363843}, {64917, 51364611}, {64918, 51365379}, {64919, 51366147},
{64921, 51366915}, {64922, 51367683}, {64923, 51368451}, {64924, 51369219},
{64926, 51369987}, {64927, 51370755}, {64928, 51371523}, {64929, 51372291},
{64930, 51373059}, {64931, 51373827}, {64932, 51374595}, {64933, 51375363},
{64934, 51376131}, {64935, 51376899}, {64936, 51377667}, {64937, 51378435},
{64938, 51379203}, {64939, 51379971}, {64940, 51380739}, {64941, 51381507},
{64942, 51289091}, {64943, 51382275}, {64944, 51383043}, {64945, 51383811},
{64946, 51384579}, {64947, 51385347}, {64948, 51353091}, {64949, 51354627},
{64950, 51386115}, {64951, 51386883}, {64952, 51387651}, {64953, 51388419},
{64954, 51389187}, {64955, 51389955}, {64956, 51389187}, {64957, 51387651},
{64958, 51390723}, {64959, 51391491}, {64960, 51392259}, {64961, 51393027},
{64962, 51393795}, {64963, 51389955}, {64964, 51347715}, {64965, 51340035},
{64966, 51394563}, {64967, 51395331}, {64968, 2}, {64975, 1},
{64976, 2}, {65008, 51396099}, {65009, 51396867}, {65010, 68174851},
{65011, 68175875}, {65012, 68176899}, {65013, 68177923}, {65014, 68178947},
{65015, 68179971}, {65016, 68180995}, {65017, 51404803}, {65018, 303063811},
{65019, 135296259}, {65020, 68189443}, {65021, 1}, {65024, 0},
{65040, 17858819}, {65041, 17859075}, {65042, 2}, {65043, 17121027},
{65044, 16848643}, {65045, 17042947}, {65046, 17043971}, {65047, 17859331},
{65048, 17859587}, {65049, 2}, {65056, 1}, {65072, 2},
{65073, 17859843}, {65074, 17860099}, {65075, 17860355}, {65077, 17047811},
{65078, 17048067}, {65079, 17860611}, {65080, 17860867}, {65081, 17861123},
{65082, 17861379}, {65083, 17861635}, {65084, 17861891}, {65085, 17862147},
{65086, 17862403}, {65087, 17077763}, {65088, 17078019}, {65089, 17862659},
{65090, 17862915}, {65091, 17863171}, {65092, 17863427}, {65093, 1},
{65095, 17863683}, {65096, 17863939}, {65097, 33820675}, {65101, 17860355},
{65104, 17858819}, {65105, 17859075}, {65106, 2}, {65108, 16848643},
{65109, 17121027}, {65110, 17043971}, {65111, 17042947}, {65112, 17859843},
{65113, 17047811}, {65114, 17048067}, {65115, 17860611}, {65116, 17860867},
{65117, 17861123}, {65118, 17861379}, {65119, 17864195}, {65120, 17864451},
{65121, 17864707}, {65122, 17047043}, {65123, 17864963}, {65124, 17865219},
{65125, 17865475}, {65126, 17047555}, {65127, 2}, {65128, 17865731},
{65129, 17865987}, {65130, 17866243}, {65131, 17866499}, {65132, 2},
{65136, 34643971}, {65137, 34644483}, {65138, 34514947}, {65139, 1},
{65140, 34515715}, {65141, 2}, {65142, 34516483}, {65143, 34534915},
{65144, 34517251}, {65145, 34535683}, {65146, 34518019}, {65147, 34536451},
{65148, 34518787}, {65149, 34644995}, {65150, 34645507}, {65151, 34646019},
{65152, 17869315}, {65153, 17869571}, {65155, 17869827}, {65157, 17870083},
{65159, 17870339}, {65161, 17688835}, {65165, 16910595}, {65167, 17695235},
{65171, 17870595}, {65173, 17698307}, {65177, 17701379}, {65181, 17693443},
{65185, 17693955}, {65189, 17696515}, {65193, 17846019}, {65195, 17736195},
{65197, 17736707}, {65199, 17743107}, {65201, 17706499}, {65205, 17756675},
{65209, 17708547}, {65213, 17709571}, {65217, 17711619}, {65221, 17712643},
{65225, 17713155}, {65229, 17714179}, {65233, 17715203}, {65237, 17718275},
{65241, 17720323}, {65245, 17722627}, {65249, 17694467}, {65253, 17729539},
{65257, 17732611}, {65261, 16911107}, {65263, 17688579}, {65265, 16912131},
{65269, 34648067}, {65271, 34648579}, {65273, 34649091}, {65275, 34633987},
{65277, 2}, {65279, 0}, {65280, 2}, {65281, 17042947},
{65282, 17872387}, {65283, 17864195}, {65284, 17865987}, {65285, 17866243},
{65286, 17864451}, {65287, 17872643}, {65288, 17047811}, {65289, 17048067},
{65290, 17864707}, {65291, 17047043}, {65292, 17858819}, {65293, 17864963},
{65294, 17207043}, {65295, 17048579}, {65296, 17045507}, {65297, 16786947},
{65298, 16785155}, {65299, 16785411}, {65300, 16787715}, {65301, 17045763},
{65302, 17046019}, {65303, 17046275}, {65304, 17046531}, {65305, 17046787},
{65306, 17121027}, {65307, 16848643}, {65308, 17865219}, {65309, 17047555},
{65310, 17865475}, {65311, 17043971}, {65312, 17866499}, {65313, 16777219},
{65314, 16777475}, {65315, 16777731}, {65316, 16777987}, {65317, 16778243},
{65318, 16778499}, {65319, 16778755}, {65320, 16779011}, {65321, 16779267},
{65322, 16779523}, {65323, 16779779}, {65324, 16780035}, {65325, 16780291},
{65326, 16780547}, {65327, 16780803}, {65328, 16781059}, {65329, 16781315},
{65330, 16781571}, {65331, 16781827}, {65332, 16782083}, {65333, 16782339},
{65334, 16782595}, {65335, 16782851}, {65336, 16783107}, {65337, 16783363},
{65338, 16783619}, {65339, 17863683}, {65340, 17865731}, {65341, 17863939},
{65342, 17872899}, {65343, 17860355}, {65344, 17037059}, {65345, 16777219},
{65346, 16777475}, {65347, 16777731}, {65348, 16777987}, {65349, 16778243},
{65350, 16778499}, {65351, 16778755}, {65352, 16779011}, {65353, 16779267},
{65354, 16779523}, {65355, 16779779}, {65356, 16780035}, {65357, 16780291},
{65358, 16780547}, {65359, 16780803}, {65360, 16781059}, {65361, 16781315},
{65362, 16781571}, {65363, 16781827}, {65364, 16782083}, {65365, 16782339},
{65366, 16782595}, {65367, 16782851}, {65368, 16783107}, {65369, 16783363},
{65370, 16783619}, {65371, 17860611}, {65372, 17873155}, {65373, 17860867},
{65374, 17873411}, {65375, 17873667}, {65376, 17873923}, {65377, 17207043},
{65378, 17862659}, {65379, 17862915}, {65380, 17859075}, {65381, 17874179},
{65382, 17327363}, {65383, 17329923}, {65384, 17372931}, {65385, 17874435},
{65386, 17374467}, {65387, 17334019}, {65388, 17874691}, {65389, 17344259},
{65390, 17390083}, {65391, 17339651}, {65392, 17328643}, {65393, 17316099},
{65394, 17316355}, {65395, 17316611}, {65396, 17316867}, {65397, 17317123},
{65398, 17317379}, {65399, 17317635}, {65400, 17317891}, {65401, 17318147},
{65402, 17209603}, {65403, 17318403}, {65404, 17318659}, {65405, 17318915},
{65406, 17319171}, {65407, 17319427}, {65408, 17319683}, {65409, 17319939},
{65410, 17320195}, {65411, 17320451}, {65412, 17209859}, {65413, 17320707},
{65414, 17320963}, {65415, 17321219}, {65416, 17321475}, {65417, 17321731},
{65418, 17321987}, {65419, 17322243}, {65420, 17322499}, {65421, 17322755},
{65422, 17323011}, {65423, 17323267}, {65424, 17323523}, {65425, 17323779},
{65426, 17324035}, {65427, 17324291}, {65428, 17324547}, {65429, 17324803},
{65430, 17325059}, {65431, 17325315}, {65432, 17325571}, {65433, 17325827},
{65434, 17326083}, {65435, 17326339}, {65436, 17326595}, {65437, 17330435},
{65438, 17208323}, {65439, 17208835}, {65440, 0}, {65441, 17210115},
{65442, 17210371}, {65443, 17210627}, {65444, 17210883}, {65445, 17211139},
{65446, 17211395}, {65447, 17211651}, {65448, 17211907}, {65449, 17212163},
{65450, 17212419}, {65451, 17212675}, {65452, 17212931}, {65453, 17213187},
{65454, 17213443}, {65455, 17213699}, {65456, 17213955}, {65457, 17214211},
{65458, 17214467}, {65459, 17214723}, {65460, 17214979}, {65461, 17215235},
{65462, 17215491}, {65463, 17215747}, {65464, 17216003}, {65465, 17216259},
{65466, 17216515}, {65467, 17216771}, {65468, 17217027}, {65469, 17217283},
{65470, 17217539}, {65471, 2}, {65474, 17217795}, {65475, 17218051},
{65476, 17218307}, {65477, 17218563}, {65478, 17218819}, {65479, 17219075},
{65480, 2}, {65482, 17219331}, {65483, 17219587}, {65484, 17219843},
{65485, 17220099}, {65486, 17220355}, {65487, 17220611}, {65488, 2},
{65490, 17220867}, {65491, 17221123}, {65492, 17221379}, {65493, 17221635},
{65494, 17221891}, {65495, 17222147}, {65496, 2}, {65498, 17222403},
{65499, 17222659}, {65500, 17222915}, {65501, 2}, {65504, 17874947},
{65505, 17875203}, {65506, 17875459}, {65507, 33561859}, {65508, 17875715},
{65509, 17875971}, {65510, 17876227}, {65511, 2}, {65512, 17876483},
{65513, 17876739}, {65514, 17876995}, {65515, 17877251}, {65516, 17877507},
{65517, 17877763}, {65518, 17878019}, {65519, 2}, {65536, 1},
{65548, 2}, {65549, 1}, {65575, 2}, {65576, 1},
{65595, 2}, {65596, 1}, {65598, 2}, {65599, 1},
{65614, 2}, {65616, 1}, {65630, 2}, {65664, 1},
{65787, 2}, {65792, 1}, {65795, 2}, {65799, 1},
{65844, 2}, {65847, 1}, {65935, 2}, {65936, 1},
{65949, 2}, {65952, 1}, {65953, 2}, {66000, 1},
{66046, 2}, {66176, 1}, {66205, 2}, {66208, 1},
{66257, 2}, {66272, 1}, {66300, 2}, {66304, 1},
{66340, 2}, {66349, 1}, {66379, 2}, {66384, 1},
{66427, 2}, {66432, 1}, {66462, 2}, {66463, 1},
{66500, 2}, {66504, 1}, {66518, 2}, {66560, 17878275},
{66561, 17878531}, {66562, 17878787}, {66563, 17879043}, {66564, 17879299},
{66565, 17879555}, {66566, 17879811}, {66567, 17880067}, {66568, 17880323},
{66569, 17880579}, {66570, 17880835}, {66571, 17881091}, {66572, 17881347},
{66573, 17881603}, {66574, 17881859}, {66575, 17882115}, {66576, 17882371},
{66577, 17882627}, {66578, 17882883}, {66579, 17883139}, {66580, 17883395},
{66581, 17883651}, {66582, 17883907}, {66583, 17884163}, {66584, 17884419},
{66585, 17884675}, {66586, 17884931}, {66587, 17885187}, {66588, 17885443},
{66589, 17885699}, {66590, 17885955}, {66591, 17886211}, {66592, 17886467},
{66593, 17886723}, {66594, 17886979}, {66595, 17887235}, {66596, 17887491},
{66597, 17887747}, {66598, 17888003}, {66599, 17888259}, {66600, 1},
{66718, 2}, {66720, 1}, {66730, 2}, {66736, 17888515},
{66737, 17888771}, {66738, 17889027}, {66739, 17889283}, {66740, 17889539},
{66741, 17889795}, {66742, 17890051}, {66743, 17890307}, {66744, 17890563},
{66745, 17890819}, {66746, 17891075}, {66747, 17891331}, {66748, 17891587},
{66749, 17891843}, {66750, 17892099}, {66751, 17892355}, {66752, 17892611},
{66753, 17892867}, {66754, 17893123}, {66755, 17893379}, {66756, 17893635},
{66757, 17893891}, {66758, 17894147}, {66759, 17894403}, {66760, 17894659},
{66761, 17894915}, {66762, 17895171}, {66763, 17895427}, {66764, 17895683},
{66765, 17895939}, {66766, 17896195}, {66767, 17896451}, {66768, 17896707},
{66769, 17896963}, {66770, 17897219}, {66771, 17897475}, {66772, 2},
{66776, 1}, {66812, 2}, {66816, 1}, {66856, 2},
{66864, 1}, {66916, 2}, {66927, 1}, {66928, 17897731},
{66929, 17897987}, {66930, 17898243}, {66931, 17898499}, {66932, 17898755},
{66933, 17899011}, {66934, 17899267}, {66935, 17899523}, {66936, 17899779},
{66937, 17900035}, {66938, 17900291}, {66939, 2}, {66940, 17900547},
{66941, 17900803}, {66942, 17901059}, {66943, 17901315}, {66944, 17901571},
{66945, 17901827}, {66946, 17902083}, {66947, 17902339}, {66948, 17902595},
{66949, 17902851}, {66950, 17903107}, {66951, 17903363}, {66952, 17903619},
{66953, 17903875}, {66954, 17904131}, {66955, 2}, {66956, 17904387},
{66957, 17904643}, {66958, 17904899}, {66959, 17905155}, {66960, 17905411},
{66961, 17905667}, {66962, 17905923}, {66963, 2}, {66964, 17906179},
{66965, 17906435}, {66966, 2}, {66967, 1}, {66978, 2},
{66979, 1}, {66994, 2}, {66995, 1}, {67002, 2},
{67003, 1}, {67005, 2}, {67008, 1}, {67060, 2},
{67072, 1}, {67383, 2}, {67392, 1}, {67414, 2},
{67424, 1}, {67432, 2}, {67456, 1}, {67457, 17906691},
{67458, 17906947}, {67459, 16791043}, {67460, 17907203}, {67461, 16814083},
{67462, 2}, {67463, 17907459}, {67464, 17907715}, {67465, 17907971},
{67466, 17908227}, {67467, 16815363}, {67468, 16815619}, {67469, 17908483},
{67470, 17908739}, {67471, 17908995}, {67472, 17909251}, {67473, 17527555},
{67474, 17909507}, {67475, 16817155}, {67476, 17909763}, {67477, 16802051},
{67478, 17910019}, {67479, 17910275}, {67480, 17910531}, {67481, 17910787},
{67482, 17911043}, {67483, 17523459}, {67484, 17911299}, {67485, 17911555},
{67486, 17911811}, {67487, 17912067}, {67488, 17912323}, {67489, 17912579},
{67490, 16795395}, {67491, 17912835}, {67492, 17913091}, {67493, 16781315},
{67494, 17913347}, {67495, 17913603}, {67496, 17135875}, {67497, 17913859},
{67498, 16819971}, {67499, 17914115}, {67500, 17914371}, {67501, 17914627},
{67502, 17914883}, {67503, 16820995}, {67504, 17915139}, {67505, 2},
{67506, 17915395}, {67507, 17915651}, {67508, 17915907}, {67509, 17916163},
{67510, 17916419}, {67511, 17916675}, {67512, 17916931}, {67513, 17917187},
{67514, 17917443}, {67515, 2}, {67584, 1}, {67590, 2},
{67592, 1}, {67593, 2}, {67594, 1}, {67638, 2},
{67639, 1}, {67641, 2}, {67644, 1}, {67645, 2},
{67647, 1}, {67670, 2}, {67671, 1}, {67743, 2},
{67751, 1}, {67760, 2}, {67808, 1}, {67827, 2},
{67828, 1}, {67830, 2}, {67835, 1}, {67868, 2},
{67871, 1}, {67898, 2}, {67903, 1}, {67904, 2},
{67968, 1}, {68024, 2}, {68028, 1}, {68048, 2},
{68050, 1}, {68100, 2}, {68101, 1}, {68103, 2},
{68108, 1}, {68116, 2}, {68117, 1}, {68120, 2},
{68121, 1}, {68150, 2}, {68152, 1}, {68155, 2},
{68159, 1}, {68169, 2}, {68176, 1}, {68185, 2},
{68192, 1}, {68256, 2}, {68288, 1}, {68327, 2},
{68331, 1}, {68343, 2}, {68352, 1}, {68406, 2},
{68409, 1}, {68438, 2}, {68440, 1}, {68467, 2},
{68472, 1}, {68498, 2}, {68505, 1}, {68509, 2},
{68521, 1}, {68528, 2}, {68608, 1}, {68681, 2},
{68736, 17917699}, {68737, 17917955}, {68738, 17918211}, {68739, 17918467},
{68740, 17918723}, {68741, 17918979}, {68742, 17919235}, {68743, 17919491},
{68744, 17919747}, {68745, 17920003}, {68746, 17920259}, {68747, 17920515},
{68748, 17920771}, {68749, 17921027}, {68750, 17921283}, {68751, 17921539},
{68752, 17921795}, {68753, 17922051}, {68754, 17922307}, {68755, 17922563},
{68756, 17922819}, {68757, 17923075}, {68758, 17923331}, {68759, 17923587},
{68760, 17923843}, {68761, 17924099}, {68762, 17924355}, {68763, 17924611},
{68764, 17924867}, {68765, 17925123}, {68766, 17925379}, {68767, 17925635},
{68768, 17925891}, {68769, 17926147}, {68770, 17926403}, {68771, 17926659},
{68772, 17926915}, {68773, 17927171}, {68774, 17927427}, {68775, 17927683},
{68776, 17927939}, {68777, 17928195}, {68778, 17928451}, {68779, 17928707},
{68780, 17928963}, {68781, 17929219}, {68782, 17929475}, {68783, 17929731},
{68784, 17929987}, {68785, 17930243}, {68786, 17930499}, {68787, 2},
{68800, 1}, {68851, 2}, {68858, 1}, {68904, 2},
{68912, 1}, {68922, 2}, {68928, 1}, {68944, 17930755},
{68945, 17931011}, {68946, 17931267}, {68947, 17931523}, {68948, 17931779},
{68949, 17932035}, {68950, 17932291}, {68951, 17932547}, {68952, 17932803},
{68953, 17933059}, {68954, 17933315}, {68955, 17933571}, {68956, 17933827},
{68957, 17934083}, {68958, 17934339}, {68959, 17934595}, {68960, 17934851},
{68961, 17935107}, {68962, 17935363}, {68963, 17935619}, {68964, 17935875},
{68965, 17936131}, {68966, 2}, {68969, 1}, {68998, 2},
{69006, 1}, {69008, 2}, {69216, 1}, {69247, 2},
{69248, 1}, {69290, 2}, {69291, 1}, {69294, 2},
{69296, 1}, {69298, 2}, {69314, 1}, {69317, 2},
{69372, 1}, {69416, 2}, {69424, 1}, {69466, 2},
{69488, 1}, {69514, 2}, {69552, 1}, {69580, 2},
{69600, 1}, {69623, 2}, {69632, 1}, {69710, 2},
{69714, 1}, {69750, 2}, {69759, 1}, {69821, 2},
{69822, 1}, {69827, 2}, {69840, 1}, {69865, 2},
{69872, 1}, {69882, 2}, {69888, 1}, {69941, 2},
{69942, 1}, {69960, 2}, {69968, 1}, {70007, 2},
{70016, 1}, {70112, 2}, {70113, 1}, {70133, 2},
{70144, 1}, {70162, 2}, {70163, 1}, {70210, 2},
{70272, 1}, {70279, 2}, {70280, 1}, {70281, 2},
{70282, 1}, {70286, 2}, {70287, 1}, {70302, 2},
{70303, 1}, {70314, 2}, {70320, 1}, {70379, 2},
{70384, 1}, {70394, 2}, {70400, 1}, {70404, 2},
{70405, 1}, {70413, 2}, {70415, 1}, {70417, 2},
{70419, 1}, {70441, 2}, {70442, 1}, {70449, 2},
{70450, 1}, {70452, 2}, {70453, 1}, {70458, 2},
{70459, 1}, {70469, 2}, {70471, 1}, {70473, 2},
{70475, 1}, {70478, 2}, {70480, 1}, {70481, 2},
{70487, 1}, {70488, 2}, {70493, 1}, {70500, 2},
{70502, 1}, {70509, 2}, {70512, 1}, {70517, 2},
{70528, 1}, {70538, 2}, {70539, 1}, {70540, 2},
{70542, 1}, {70543, 2}, {70544, 1}, {70582, 2},
{70583, 1}, {70593, 2}, {70594, 1}, {70595, 2},
{70597, 1}, {70598, 2}, {70599, 1}, {70603, 2},
{70604, 1}, {70614, 2}, {70615, 1}, {70617, 2},
{70625, 1}, {70627, 2}, {70656, 1}, {70748, 2},
{70749, 1}, {70754, 2}, {70784, 1}, {70856, 2},
{70864, 1}, {70874, 2}, {71040, 1}, {71094, 2},
{71096, 1}, {71134, 2}, {71168, 1}, {71237, 2},
{71248, 1}, {71258, 2}, {71264, 1}, {71277, 2},
{71296, 1}, {71354, 2}, {71360, 1}, {71370, 2},
{71376, 1}, {71396, 2}, {71424, 1}, {71451, 2},
{71453, 1}, {71468, 2}, {71472, 1}, {71495, 2},
{71680, 1}, {71740, 2}, {71840, 17936387}, {71841, 17936643},
{71842, 17936899}, {71843, 17937155}, {71844, 17937411}, {71845, 17937667},
{71846, 17937923}, {71847, 17938179}, {71848, 17938435}, {71849, 17938691},
{71850, 17938947}, {71851, 17939203}, {71852, 17939459}, {71853, 17939715},
{71854, 17939971}, {71855, 17940227}, {71856, 17940483}, {71857, 17940739},
{71858, 17940995}, {71859, 17941251}, {71860, 17941507}, {71861, 17941763},
{71862, 17942019}, {71863, 17942275}, {71864, 17942531}, {71865, 17942787},
{71866, 17943043}, {71867, 17943299}, {71868, 17943555}, {71869, 17943811},
{71870, 17944067}, {71871, 17944323}, {71872, 1}, {71923, 2},
{71935, 1}, {71943, 2}, {71945, 1}, {71946, 2},
{71948, 1}, {71956, 2}, {71957, 1}, {71959, 2},
{71960, 1}, {71990, 2}, {71991, 1}, {71993, 2},
{71995, 1}, {72007, 2}, {72016, 1}, {72026, 2},
{72096, 1}, {72104, 2}, {72106, 1}, {72152, 2},
{72154, 1}, {72165, 2}, {72192, 1}, {72264, 2},
{72272, 1}, {72355, 2}, {72368, 1}, {72441, 2},
{72448, 1}, {72458, 2}, {72640, 1}, {72674, 2},
{72688, 1}, {72698, 2}, {72704, 1}, {72713, 2},
{72714, 1}, {72759, 2}, {72760, 1}, {72774, 2},
{72784, 1}, {72813, 2}, {72816, 1}, {72848, 2},
{72850, 1}, {72872, 2}, {72873, 1}, {72887, 2},
{72960, 1}, {72967, 2}, {72968, 1}, {72970, 2},
{72971, 1}, {73015, 2}, {73018, 1}, {73019, 2},
{73020, 1}, {73022, 2}, {73023, 1}, {73032, 2},
{73040, 1}, {73050, 2}, {73056, 1}, {73062, 2},
{73063, 1}, {73065, 2}, {73066, 1}, {73103, 2},
{73104, 1}, {73106, 2}, {73107, 1}, {73113, 2},
{73120, 1}, {73130, 2}, {73440, 1}, {73465, 2},
{73472, 1}, {73489, 2}, {73490, 1}, {73531, 2},
{73534, 1}, {73563, 2}, {73648, 1}, {73649, 2},
{73664, 1}, {73714, 2}, {73727, 1}, {74650, 2},
{74752, 1}, {74863, 2}, {74864, 1}, {74869, 2},
{74880, 1}, {75076, 2}, {77712, 1}, {77811, 2},
{77824, 1}, {78896, 2}, {78912, 1}, {78934, 2},
{78944, 1}, {82939, 2}, {82944, 1}, {83527, 2},
{90368, 1}, {90426, 2}, {92160, 1}, {92729, 2},
{92736, 1}, {92767, 2}, {92768, 1}, {92778, 2},
{92782, 1}, {92863, 2}, {92864, 1}, {92874, 2},
{92880, 1}, {92910, 2}, {92912, 1}, {92918, 2},
{92928, 1}, {92998, 2}, {93008, 1}, {93018, 2},
{93019, 1}, {93026, 2}, {93027, 1}, {93048, 2},
{93053, 1}, {93072, 2}, {93504, 1}, {93562, 2},
{93760, 17944579}, {93761, 17944835}, {93762, 17945091}, {93763, 17945347},
{93764, 17945603}, {93765, 17945859}, {93766, 17946115}, {93767, 17946371},
{93768, 17946627}, {93769, 17946883}, {93770, 17947139}, {93771, 17947395},
{93772, 17947651}, {93773, 17947907}, {93774, 17948163}, {93775, 17948419},
{93776, 17948675}, {93777, 17948931}, {93778, 17949187}, {93779, 17949443},
{93780, 17949699}, {93781, 17949955}, {93782, 17950211}, {93783, 17950467},
{93784, 17950723}, {93785, 17950979}, {93786, 17951235}, {93787, 17951491},
{93788, 17951747}, {93789, 17952003}, {93790, 17952259}, {93791, 17952515},
{93792, 1}, {93851, 2}, {93952, 1}, {94027, 2},
{94031, 1}, {94088, 2}, {94095, 1}, {94112, 2},
{94176, 1}, {94181, 2}, {94192, 1}, {94194, 2},
{94208, 1}, {100344, 2}, {100352, 1}, {101590, 2},
{101631, 1}, {101641, 2}, {110576, 1}, {110580, 2},
{110581, 1}, {110588, 2}, {110589, 1}, {110591, 2},
{110592, 1}, {110883, 2}, {110898, 1}, {110899, 2},
{110928, 1}, {110931, 2}, {110933, 1}, {110934, 2},
{110948, 1}, {110952, 2}, {110960, 1}, {111356, 2},
{113664, 1}, {113771, 2}, {113776, 1}, {113789, 2},
{113792, 1}, {113801, 2}, {113808, 1}, {113818, 2},
{113820, 1}, {113824, 0}, {113828, 2}, {117760, 1},
{117974, 16777219}, {117975, 16777475}, {117976, 16777731}, {117977, 16777987},
{117978, 16778243}, {117979, 16778499}, {117980, 16778755}, {117981, 16779011},
{117982, 16779267}, {117983, 16779523}, {117984, 16779779}, {117985, 16780035},
{117986, 16780291}, {117987, 16780547}, {117988, 16780803}, {117989, 16781059},
{117990, 16781315}, {117991, 16781571}, {117992, 16781827}, {117993, 16782083},
{117994, 16782339}, {117995, 16782595}, {117996, 16782851}, {117997, 16783107},
{117998, 16783363}, {117999, 16783619}, {118000, 17045507}, {118001, 16786947},
{118002, 16785155}, {118003, 16785411}, {118004, 16787715}, {118005, 17045763},
{118006, 17046019}, {118007, 17046275}, {118008, 17046531}, {118009, 17046787},
{118010, 2}, {118016, 1}, {118452, 2}, {118528, 1},
{118574, 2}, {118576, 1}, {118599, 2}, {118608, 1},
{118724, 2}, {118784, 1}, {119030, 2}, {119040, 1},
{119079, 2}, {119081, 1}, {119134, 34729987}, {119135, 34730499},
{119136, 51508227}, {119137, 51508995}, {119138, 51509763}, {119139, 51510531},
{119140, 51511299}, {119141, 1}, {119155, 0}, {119163, 1},
{119227, 34734851}, {119228, 34735363}, {119229, 51513091}, {119230, 51513859},
{119231, 51514627}, {119232, 51515395}, {119233, 1}, {119275, 2},
{119296, 1}, {119366, 2}, {119488, 1}, {119508, 2},
{119520, 1}, {119540, 2}, {119552, 1}, {119639, 2},
{119648, 1}, {119673, 2}, {119808, 16777219}, {119809, 16777475},
{119810, 16777731}, {119811, 16777987}, {119812, 16778243}, {119813, 16778499},
{119814, 16778755}, {119815, 16779011}, {119816, 16779267}, {119817, 16779523},
{119818, 16779779}, {119819, 16780035}, {119820, 16780291}, {119821, 16780547},
{119822, 16780803}, {119823, 16781059}, {119824, 16781315}, {119825, 16781571},
{119826, 16781827}, {119827, 16782083}, {119828, 16782339}, {119829, 16782595},
{119830, 16782851}, {119831, 16783107}, {119832, 16783363}, {119833, 16783619},
{119834, 16777219}, {119835, 16777475}, {119836, 16777731}, {119837, 16777987},
{119838, 16778243}, {119839, 16778499}, {119840, 16778755}, {119841, 16779011},
{119842, 16779267}, {119843, 16779523}, {119844, 16779779}, {119845, 16780035},
{119846, 16780291}, {119847, 16780547}, {119848, 16780803}, {119849, 16781059},
{119850, 16781315}, {119851, 16781571}, {119852, 16781827}, {119853, 16782083},
{119854, 16782339}, {119855, 16782595}, {119856, 16782851}, {119857, 16783107},
{119858, 16783363}, {119859, 16783619}, {119860, 16777219}, {119861, 16777475},
{119862, 16777731}, {119863, 16777987}, {119864, 16778243}, {119865, 16778499},
{119866, 16778755}, {119867, 16779011}, {119868, 16779267}, {119869, 16779523},
{119870, 16779779}, {119871, 16780035}, {119872, 16780291}, {119873, 16780547},
{119874, 16780803}, {119875, 16781059}, {119876, 16781315}, {119877, 16781571},
{119878, 16781827}, {119879, 16782083}, {119880, 16782339}, {119881, 16782595},
{119882, 16782851}, {119883, 16783107}, {119884, 16783363}, {119885, 16783619},
{119886, 16777219}, {119887, 16777475}, {119888, 16777731}, {119889, 16777987},
{119890, 16778243}, {119891, 16778499}, {119892, 16778755}, {119893, 2},
{119894, 16779267}, {119895, 16779523}, {119896, 16779779}, {119897, 16780035},
{119898, 16780291}, {119899, 16780547}, {119900, 16780803}, {119901, 16781059},
{119902, 16781315}, {119903, 16781571}, {119904, 16781827}, {119905, 16782083},
{119906, 16782339}, {119907, 16782595}, {119908, 16782851}, {119909, 16783107},
{119910, 16783363}, {119911, 16783619}, {119912, 16777219}, {119913, 16777475},
{119914, 16777731}, {119915, 16777987}, {119916, 16778243}, {119917, 16778499},
{119918, 16778755}, {119919, 16779011}, {119920, 16779267}, {119921, 16779523},
{119922, 16779779}, {119923, 16780035}, {119924, 16780291}, {119925, 16780547},
{119926, 16780803}, {119927, 16781059}, {119928, 16781315}, {119929, 16781571},
{119930, 16781827}, {119931, 16782083}, {119932, 16782339}, {119933, 16782595},
{119934, 16782851}, {119935, 16783107}, {119936, 16783363}, {119937, 16783619},
{119938, 16777219}, {119939, 16777475}, {119940, 16777731}, {119941, 16777987},
{119942, 16778243}, {119943, 16778499}, {119944, 16778755}, {119945, 16779011},
{119946, 16779267}, {119947, 16779523}, {119948, 16779779}, {119949, 16780035},
{119950, 16780291}, {119951, 16780547}, {119952, 16780803}, {119953, 16781059},
{119954, 16781315}, {119955, 16781571}, {119956, 16781827}, {119957, 16782083},
{119958, 16782339}, {119959, 16782595}, {119960, 16782851}, {119961, 16783107},
{119962, 16783363}, {119963, 16783619}, {119964, 16777219}, {119965, 2},
{119966, 16777731}, {119967, 16777987}, {119968, 2}, {119970, 16778755},
{119971, 2}, {119973, 16779523}, {119974, 16779779}, {119975, 2},
{119977, 16780547}, {119978, 16780803}, {119979, 16781059}, {119980, 16781315},
{119981, 2}, {119982, 16781827}, {119983, 16782083}, {119984, 16782339},
{119985, 16782595}, {119986, 16782851}, {119987, 16783107}, {119988, 16783363},
{119989, 16783619}, {119990, 16777219}, {119991, 16777475}, {119992, 16777731},
{119993, 16777987}, {119994, 2}, {119995, 16778499}, {119996, 2},
{119997, 16779011}, {119998, 16779267}, {119999, 16779523}, {120000, 16779779},
{120001, 16780035}, {120002, 16780291}, {120003, 16780547}, {120004, 2},
{120005, 16781059}, {120006, 16781315}, {120007, 16781571}, {120008, 16781827},
{120009, 16782083}, {120010, 16782339}, {120011, 16782595}, {120012, 16782851},
{120013, 16783107}, {120014, 16783363}, {120015, 16783619}, {120016, 16777219},
{120017, 16777475}, {120018, 16777731}, {120019, 16777987}, {120020, 16778243},
{120021, 16778499}, {120022, 16778755}, {120023, 16779011}, {120024, 16779267},
{120025, 16779523}, {120026, 16779779}, {120027, 16780035}, {120028, 16780291},
{120029, 16780547}, {120030, 16780803}, {120031, 16781059}, {120032, 16781315},
{120033, 16781571}, {120034, 16781827}, {120035, 16782083}, {120036, 16782339},
{120037, 16782595}, {120038, 16782851}, {120039, 16783107}, {120040, 16783363},
{120041, 16783619}, {120042, 16777219}, {120043, 16777475}, {120044, 16777731},
{120045, 16777987}, {120046, 16778243}, {120047, 16778499}, {120048, 16778755},
{120049, 16779011}, {120050, 16779267}, {120051, 16779523}, {120052, 16779779},
{120053, 16780035}, {120054, 16780291}, {120055, 16780547}, {120056, 16780803},
{120057, 16781059}, {120058, 16781315}, {120059, 16781571}, {120060, 16781827},
{120061, 16782083}, {120062, 16782339}, {120063, 16782595}, {120064, 16782851},
{120065, 16783107}, {120066, 16783363}, {120067, 16783619}, {120068, 16777219},
{120069, 16777475}, {120070, 2}, {120071, 16777987}, {120072, 16778243},
{120073, 16778499}, {120074, 16778755}, {120075, 2}, {120077, 16779523},
{120078, 16779779}, {120079, 16780035}, {120080, 16780291}, {120081, 16780547},
{120082, 16780803}, {120083, 16781059}, {120084, 16781315}, {120085, 2},
{120086, 16781827}, {120087, 16782083}, {120088, 16782339}, {120089, 16782595},
{120090, 16782851}, {120091, 16783107}, {120092, 16783363}, {120093, 2},
{120094, 16777219}, {120095, 16777475}, {120096, 16777731}, {120097, 16777987},
{120098, 16778243}, {120099, 16778499}, {120100, 16778755}, {120101, 16779011},
{120102, 16779267}, {120103, 16779523}, {120104, 16779779}, {120105, 16780035},
{120106, 16780291}, {120107, 16780547}, {120108, 16780803}, {120109, 16781059},
{120110, 16781315}, {120111, 16781571}, {120112, 16781827}, {120113, 16782083},
{120114, 16782339}, {120115, 16782595}, {120116, 16782851}, {120117, 16783107},
{120118, 16783363}, {120119, 16783619}, {120120, 16777219}, {120121, 16777475},
{120122, 2}, {120123, 16777987}, {120124, 16778243}, {120125, 16778499},
{120126, 16778755}, {120127, 2}, {120128, 16779267}, {120129, 16779523},
{120130, 16779779}, {120131, 16780035}, {120132, 16780291}, {120133, 2},
{120134, 16780803}, {120135, 2}, {120138, 16781827}, {120139, 16782083},
{120140, 16782339}, {120141, 16782595}, {120142, 16782851}, {120143, 16783107},
{120144, 16783363}, {120145, 2}, {120146, 16777219}, {120147, 16777475},
{120148, 16777731}, {120149, 16777987}, {120150, 16778243}, {120151, 16778499},
{120152, 16778755}, {120153, 16779011}, {120154, 16779267}, {120155, 16779523},
{120156, 16779779}, {120157, 16780035}, {120158, 16780291}, {120159, 16780547},
{120160, 16780803}, {120161, 16781059}, {120162, 16781315}, {120163, 16781571},
{120164, 16781827}, {120165, 16782083}, {120166, 16782339}, {120167, 16782595},
{120168, 16782851}, {120169, 16783107}, {120170, 16783363}, {120171, 16783619},
{120172, 16777219}, {120173, 16777475}, {120174, 16777731}, {120175, 16777987},
{120176, 16778243}, {120177, 16778499}, {120178, 16778755}, {120179, 16779011},
{120180, 16779267}, {120181, 16779523}, {120182, 16779779}, {120183, 16780035},
{120184, 16780291}, {120185, 16780547}, {120186, 16780803}, {120187, 16781059},
{120188, 16781315}, {120189, 16781571}, {120190, 16781827}, {120191, 16782083},
{120192, 16782339}, {120193, 16782595}, {120194, 16782851}, {120195, 16783107},
{120196, 16783363}, {120197, 16783619}, {120198, 16777219}, {120199, 16777475},
{120200, 16777731}, {120201, 16777987}, {120202, 16778243}, {120203, 16778499},
{120204, 16778755}, {120205, 16779011}, {120206, 16779267}, {120207, 16779523},
{120208, 16779779}, {120209, 16780035}, {120210, 16780291}, {120211, 16780547},
{120212, 16780803}, {120213, 16781059}, {120214, 16781315}, {120215, 16781571},
{120216, 16781827}, {120217, 16782083}, {120218, 16782339}, {120219, 16782595},
{120220, 16782851}, {120221, 16783107}, {120222, 16783363}, {120223, 16783619},
{120224, 16777219}, {120225, 16777475}, {120226, 16777731}, {120227, 16777987},
{120228, 16778243}, {120229, 16778499}, {120230, 16778755}, {120231, 16779011},
{120232, 16779267}, {120233, 16779523}, {120234, 16779779}, {120235, 16780035},
{120236, 16780291}, {120237, 16780547}, {120238, 16780803}, {120239, 16781059},
{120240, 16781315}, {120241, 16781571}, {120242, 16781827}, {120243, 16782083},
{120244, 16782339}, {120245, 16782595}, {120246, 16782851}, {120247, 16783107},
{120248, 16783363}, {120249, 16783619}, {120250, 16777219}, {120251, 16777475},
{120252, 16777731}, {120253, 16777987}, {120254, 16778243}, {120255, 16778499},
{120256, 16778755}, {120257, 16779011}, {120258, 16779267}, {120259, 16779523},
{120260, 16779779}, {120261, 16780035}, {120262, 16780291}, {120263, 16780547},
{120264, 16780803}, {120265, 16781059}, {120266, 16781315}, {120267, 16781571},
{120268, 16781827}, {120269, 16782083}, {120270, 16782339}, {120271, 16782595},
{120272, 16782851}, {120273, 16783107}, {120274, 16783363}, {120275, 16783619},
{120276, 16777219}, {120277, 16777475}, {120278, 16777731}, {120279, 16777987},
{120280, 16778243}, {120281, 16778499}, {120282, 16778755}, {120283, 16779011},
{120284, 16779267}, {120285, 16779523}, {120286, 16779779}, {120287, 16780035},
{120288, 16780291}, {120289, 16780547}, {120290, 16780803}, {120291, 16781059},
{120292, 16781315}, {120293, 16781571}, {120294, 16781827}, {120295, 16782083},
{120296, 16782339}, {120297, 16782595}, {120298, 16782851}, {120299, 16783107},
{120300, 16783363}, {120301, 16783619}, {120302, 16777219}, {120303, 16777475},
{120304, 16777731}, {120305, 16777987}, {120306, 16778243}, {120307, 16778499},
{120308, 16778755}, {120309, 16779011}, {120310, 16779267}, {120311, 16779523},
{120312, 16779779}, {120313, 16780035}, {120314, 16780291}, {120315, 16780547},
{120316, 16780803}, {120317, 16781059}, {120318, 16781315}, {120319, 16781571},
{120320, 16781827}, {120321, 16782083}, {120322, 16782339}, {120323, 16782595},
{120324, 16782851}, {120325, 16783107}, {120326, 16783363}, {120327, 16783619},
{120328, 16777219}, {120329, 16777475}, {120330, 16777731}, {120331, 16777987},
{120332, 16778243}, {120333, 16778499}, {120334, 16778755}, {120335, 16779011},
{120336, 16779267}, {120337, 16779523}, {120338, 16779779}, {120339, 16780035},
{120340, 16780291}, {120341, 16780547}, {120342, 16780803}, {120343, 16781059},
{120344, 16781315}, {120345, 16781571}, {120346, 16781827}, {120347, 16782083},
{120348, 16782339}, {120349, 16782595}, {120350, 16782851}, {120351, 16783107},
{120352, 16783363}, {120353, 16783619}, {120354, 16777219}, {120355, 16777475},
{120356, 16777731}, {120357, 16777987}, {120358, 16778243}, {120359, 16778499},
{120360, 16778755}, {120361, 16779011}, {120362, 16779267}, {120363, 16779523},
{120364, 16779779}, {120365, 16780035}, {120366, 16780291}, {120367, 16780547},
{120368, 16780803}, {120369, 16781059}, {120370, 16781315}, {120371, 16781571},
{120372, 16781827}, {120373, 16782083}, {120374, 16782339}, {120375, 16782595},
{120376, 16782851}, {120377, 16783107}, {120378, 16783363}, {120379, 16783619},
{120380, 16777219}, {120381, 16777475}, {120382, 16777731}, {120383, 16777987},
{120384, 16778243}, {120385, 16778499}, {120386, 16778755}, {120387, 16779011},
{120388, 16779267}, {120389, 16779523}, {120390, 16779779}, {120391, 16780035},
{120392, 16780291}, {120393, 16780547}, {120394, 16780803}, {120395, 16781059},
{120396, 16781315}, {120397, 16781571}, {120398, 16781827}, {120399, 16782083},
{120400, 16782339}, {120401, 16782595}, {120402, 16782851}, {120403, 16783107},
{120404, 16783363}, {120405, 16783619}, {120406, 16777219}, {120407, 16777475},
{120408, 16777731}, {120409, 16777987}, {120410, 16778243}, {120411, 16778499},
{120412, 16778755}, {120413, 16779011}, {120414, 16779267}, {120415, 16779523},
{120416, 16779779}, {120417, 16780035}, {120418, 16780291}, {120419, 16780547},
{120420, 16780803}, {120421, 16781059}, {120422, 16781315}, {120423, 16781571},
{120424, 16781827}, {120425, 16782083}, {120426, 16782339}, {120427, 16782595},
{120428, 16782851}, {120429, 16783107}, {120430, 16783363}, {120431, 16783619},
{120432, 16777219}, {120433, 16777475}, {120434, 16777731}, {120435, 16777987},
{120436, 16778243}, {120437, 16778499}, {120438, 16778755}, {120439, 16779011},
{120440, 16779267}, {120441, 16779523}, {120442, 16779779}, {120443, 16780035},
{120444, 16780291}, {120445, 16780547}, {120446, 16780803}, {120447, 16781059},
{120448, 16781315}, {120449, 16781571}, {120450, 16781827}, {120451, 16782083},
{120452, 16782339}, {120453, 16782595}, {120454, 16782851}, {120455, 16783107},
{120456, 16783363}, {120457, 16783619}, {120458, 16777219}, {120459, 16777475},
{120460, 16777731}, {120461, 16777987}, {120462, 16778243}, {120463, 16778499},
{120464, 16778755}, {120465, 16779011}, {120466, 16779267}, {120467, 16779523},
{120468, 16779779}, {120469, 16780035}, {120470, 16780291}, {120471, 16780547},
{120472, 16780803}, {120473, 16781059}, {120474, 16781315}, {120475, 16781571},
{120476, 16781827}, {120477, 16782083}, {120478, 16782339}, {120479, 16782595},
{120480, 16782851}, {120481, 16783107}, {120482, 16783363}, {120483, 16783619},
{120484, 17961731}, {120485, 17961987}, {120486, 2}, {120488, 16851715},
{120489, 16851971}, {120490, 16852227}, {120491, 16852483}, {120492, 16852739},
{120493, 16852995}, {120494, 16853251}, {120495, 16853507}, {120496, 16846851},
{120497, 16853763}, {120498, 16854019}, {120499, 16786179}, {120500, 16854275},
{120501, 16854531}, {120502, 16854787}, {120503, 16855043}, {120504, 16855299},
{120505, 16853507}, {120506, 16855555}, {120507, 16855811}, {120508, 16856067},
{120509, 16856323}, {120510, 16856579}, {120511, 16856835}, {120512, 16857091},
{120513, 17962243}, {120514, 16851715}, {120515, 16851971}, {120516, 16852227},
{120517, 16852483}, {120518, 16852739}, {120519, 16852995}, {120520, 16853251},
{120521, 16853507}, {120522, 16846851}, {120523, 16853763}, {120524, 16854019},
{120525, 16786179}, {120526, 16854275}, {120527, 16854531}, {120528, 16854787},
{120529, 16855043}, {120530, 16855299}, {120531, 16855555}, {120533, 16855811},
{120534, 16856067}, {120535, 16856323}, {120536, 16856579}, {120537, 16856835},
{120538, 16857091}, {120539, 17962499}, {120540, 16852739}, {120541, 16853507},
{120542, 16853763}, {120543, 16856323}, {120544, 16855299}, {120545, 16855043},
{120546, 16851715}, {120547, 16851971}, {120548, 16852227}, {120549, 16852483},
{120550, 16852739}, {120551, 16852995}, {120552, 16853251}, {120553, 16853507},
{120554, 16846851}, {120555, 16853763}, {120556, 16854019}, {120557, 16786179},
{120558, 16854275}, {120559, 16854531}, {120560, 16854787}, {120561, 16855043},
{120562, 16855299}, {120563, 16853507}, {120564, 16855555}, {120565, 16855811},
{120566, 16856067}, {120567, 16856323}, {120568, 16856579}, {120569, 16856835},
{120570, 16857091}, {120571, 17962243}, {120572, 16851715}, {120573, 16851971},
{120574, 16852227}, {120575, 16852483}, {120576, 16852739}, {120577, 16852995},
{120578, 16853251}, {120579, 16853507}, {120580, 16846851}, {120581, 16853763},
{120582, 16854019}, {120583, 16786179}, {120584, 16854275}, {120585, 16854531},
{120586, 16854787}, {120587, 16855043}, {120588, 16855299}, {120589, 16855555},
{120591, 16855811}, {120592, 16856067}, {120593, 16856323}, {120594, 16856579},
{120595, 16856835}, {120596, 16857091}, {120597, 17962499}, {120598, 16852739},
{120599, 16853507}, {120600, 16853763}, {120601, 16856323}, {120602, 16855299},
{120603, 16855043}, {120604, 16851715}, {120605, 16851971}, {120606, 16852227},
{120607, 16852483}, {120608, 16852739}, {120609, 16852995}, {120610, 16853251},
{120611, 16853507}, {120612, 16846851}, {120613, 16853763}, {120614, 16854019},
{120615, 16786179}, {120616, 16854275}, {120617, 16854531}, {120618, 16854787},
{120619, 16855043}, {120620, 16855299}, {120621, 16853507}, {120622, 16855555},
{120623, 16855811}, {120624, 16856067}, {120625, 16856323}, {120626, 16856579},
{120627, 16856835}, {120628, 16857091}, {120629, 17962243}, {120630, 16851715},
{120631, 16851971}, {120632, 16852227}, {120633, 16852483}, {120634, 16852739},
{120635, 16852995}, {120636, 16853251}, {120637, 16853507}, {120638, 16846851},
{120639, 16853763}, {120640, 16854019}, {120641, 16786179}, {120642, 16854275},
{120643, 16854531}, {120644, 16854787}, {120645, 16855043}, {120646, 16855299},
{120647, 16855555}, {120649, 16855811}, {120650, 16856067}, {120651, 16856323},
{120652, 16856579}, {120653, 16856835}, {120654, 16857091}, {120655, 17962499},
{120656, 16852739}, {120657, 16853507}, {120658, 16853763}, {120659, 16856323},
{120660, 16855299}, {120661, 16855043}, {120662, 16851715}, {120663, 16851971},
{120664, 16852227}, {120665, 16852483}, {120666, 16852739}, {120667, 16852995},
{120668, 16853251}, {120669, 16853507}, {120670, 16846851}, {120671, 16853763},
{120672, 16854019}, {120673, 16786179}, {120674, 16854275}, {120675, 16854531},
{120676, 16854787}, {120677, 16855043}, {120678, 16855299}, {120679, 16853507},
{120680, 16855555}, {120681, 16855811}, {120682, 16856067}, {120683, 16856323},
{120684, 16856579}, {120685, 16856835}, {120686, 16857091}, {120687, 17962243},
{120688, 16851715}, {120689, 16851971}, {120690, 16852227}, {120691, 16852483},
{120692, 16852739}, {120693, 16852995}, {120694, 16853251}, {120695, 16853507},
{120696, 16846851}, {120697, 16853763}, {120698, 16854019}, {120699, 16786179},
{120700, 16854275}, {120701, 16854531}, {120702, 16854787}, {120703, 16855043},
{120704, 16855299}, {120705, 16855555}, {120707, 16855811}, {120708, 16856067},
{120709, 16856323}, {120710, 16856579}, {120711, 16856835}, {120712, 16857091},
{120713, 17962499}, {120714, 16852739}, {120715, 16853507}, {120716, 16853763},
{120717, 16856323}, {120718, 16855299}, {120719, 16855043}, {120720, 16851715},
{120721, 16851971}, {120722, 16852227}, {120723, 16852483}, {120724, 16852739},
{120725, 16852995}, {120726, 16853251}, {120727, 16853507}, {120728, 16846851},
{120729, 16853763}, {120730, 16854019}, {120731, 16786179}, {120732, 16854275},
{120733, 16854531}, {120734, 16854787}, {120735, 16855043}, {120736, 16855299},
{120737, 16853507}, {120738, 16855555}, {120739, 16855811}, {120740, 16856067},
{120741, 16856323}, {120742, 16856579}, {120743, 16856835}, {120744, 16857091},
{120745, 17962243}, {120746, 16851715}, {120747, 16851971}, {120748, 16852227},
{120749, 16852483}, {120750, 16852739}, {120751, 16852995}, {120752, 16853251},
{120753, 16853507}, {120754, 16846851}, {120755, 16853763}, {120756, 16854019},
{120757, 16786179}, {120758, 16854275}, {120759, 16854531}, {120760, 16854787},
{120761, 16855043}, {120762, 16855299}, {120763, 16855555}, {120765, 16855811},
{120766, 16856067}, {120767, 16856323}, {120768, 16856579}, {120769, 16856835},
{120770, 16857091}, {120771, 17962499}, {120772, 16852739}, {120773, 16853507},
{120774, 16853763}, {120775, 16856323}, {120776, 16855299}, {120777, 16855043},
{120778, 16858627}, {120780, 2}, {120782, 17045507}, {120783, 16786947},
{120784, 16785155}, {120785, 16785411}, {120786, 16787715}, {120787, 17045763},
{120788, 17046019}, {120789, 17046275}, {120790, 17046531}, {120791, 17046787},
{120792, 17045507}, {120793, 16786947}, {120794, 16785155}, {120795, 16785411},
{120796, 16787715}, {120797, 17045763}, {120798, 17046019}, {120799, 17046275},
{120800, 17046531}, {120801, 17046787}, {120802, 17045507}, {120803, 16786947},
{120804, 16785155}, {120805, 16785411}, {120806, 16787715}, {120807, 17045763},
{120808, 17046019}, {120809, 17046275}, {120810, 17046531}, {120811, 17046787},
{120812, 17045507}, {120813, 16786947}, {120814, 16785155}, {120815, 16785411},
{120816, 16787715}, {120817, 17045763}, {120818, 17046019}, {120819, 17046275},
{120820, 17046531}, {120821, 17046787}, {120822, 17045507}, {120823, 16786947},
{120824, 16785155}, {120825, 16785411}, {120826, 16787715}, {120827, 17045763},
{120828, 17046019}, {120829, 17046275}, {120830, 17046531}, {120831, 17046787},
{120832, 1}, {121484, 2}, {121499, 1}, {121504, 2},
{121505, 1}, {121520, 2}, {122624, 1}, {122655, 2},
{122661, 1}, {122667, 2}, {122880, 1}, {122887, 2},
{122888, 1}, {122905, 2}, {122907, 1}, {122914, 2},
{122915, 1}, {122917, 2}, {122918, 1}, {122923, 2},
{122928, 16866563}, {122929, 16866819}, {122930, 16867075}, {122931, 16867331},
{122932, 16867587}, {122933, 16867843}, {122934, 16868099}, {122935, 16868355},
{122936, 16868611}, {122937, 16869123}, {122938, 16869379}, {122939, 16869635},
{122940, 16870147}, {122941, 16870403}, {122942, 16870659}, {122943, 16870915},
{122944, 16871171}, {122945, 16871427}, {122946, 16871683}, {122947, 16871939},
{122948, 16872195}, {122949, 16872451}, {122950, 16872707}, {122951, 16873475},
{122952, 16873987}, {122953, 16874243}, {122954, 17505795}, {122955, 16889091},
{122956, 16864003}, {122957, 16864515}, {122958, 16891139}, {122959, 16883715},
{122960, 16886019}, {122961, 16866563}, {122962, 16866819}, {122963, 16867075},
{122964, 16867331}, {122965, 16867587}, {122966, 16867843}, {122967, 16868099},
{122968, 16868355}, {122969, 16868611}, {122970, 16869123}, {122971, 16869379},
{122972, 16870147}, {122973, 16870403}, {122974, 16870915}, {122975, 16871427},
{122976, 16871683}, {122977, 16871939}, {122978, 16872195}, {122979, 16872451},
{122980, 16872707}, {122981, 16873219}, {122982, 16873475}, {122983, 16879875},
{122984, 16864003}, {122985, 16863747}, {122986, 16866307}, {122987, 16883203},
{122988, 17500931}, {122989, 16883971}, {122990, 2}, {123023, 1},
{123024, 2}, {123136, 1}, {123181, 2}, {123184, 1},
{123198, 2}, {123200, 1}, {123210, 2}, {123214, 1},
{123216, 2}, {123536, 1}, {123567, 2}, {123584, 1},
{123642, 2}, {123647, 1}, {123648, 2}, {124112, 1},
{124154, 2}, {124368, 1}, {124411, 2}, {124415, 1},
{124416, 2}, {124896, 1}, {124903, 2}, {124904, 1},
{124908, 2}, {124909, 1}, {124911, 2}, {124912, 1},
{124927, 2}, {124928, 1}, {125125, 2}, {125127, 1},
{125143, 2}, {125184, 17962755}, {125185, 17963011}, {125186, 17963267},
{125187, 17963523}, {125188, 17963779}, {125189, 17964035}, {125190, 17964291},
{125191, 17964547}, {125192, 17964803}, {125193, 17965059}, {125194, 17965315},
{125195, 17965571}, {125196, 17965827}, {125197, 17966083}, {125198, 17966339},
{125199, 17966595}, {125200, 17966851}, {125201, 17967107}, {125202, 17967363},
{125203, 17967619}, {125204, 17967875}, {125205, 17968131}, {125206, 17968387},
{125207, 17968643}, {125208, 17968899}, {125209, 17969155}, {125210, 17969411},
{125211, 17969667}, {125212, 17969923}, {125213, 17970179}, {125214, 17970435},
{125215, 17970691}, {125216, 17970947}, {125217, 17971203}, {125218, 1},
{125260, 2}, {125264, 1}, {125274, 2}, {125278, 1},
{125280, 2}, {126065, 1}, {126133, 2}, {126209, 1},
{126270, 2}, {126464, 16910595}, {126465, 17695235}, {126466, 17693443},
{126467, 17846019}, {126468, 2}, {126469, 16911107}, {126470, 17743107},
{126471, 17693955}, {126472, 17711619}, {126473, 16912131}, {126474, 17720323},
{126475, 17722627}, {126476, 17694467}, {126477, 17729539}, {126478, 17706499},
{126479, 17713155}, {126480, 17715203}, {126481, 17708547}, {126482, 17718275},
{126483, 17736707}, {126484, 17756675}, {126485, 17698307}, {126486, 17701379},
{126487, 17696515}, {126488, 17736195}, {126489, 17709571}, {126490, 17712643},
{126491, 17714179}, {126492, 17971459}, {126493, 17684995}, {126494, 17971715},
{126495, 17971971}, {126496, 2}, {126497, 17695235}, {126498, 17693443},
{126499, 2}, {126500, 17732611}, {126501, 2}, {126503, 17693955},
{126504, 2}, {126505, 16912131}, {126506, 17720323}, {126507, 17722627},
{126508, 17694467}, {126509, 17729539}, {126510, 17706499}, {126511, 17713155},
{126512, 17715203}, {126513, 17708547}, {126514, 17718275}, {126515, 2},
{126516, 17756675}, {126517, 17698307}, {126518, 17701379}, {126519, 17696515},
{126520, 2}, {126521, 17709571}, {126522, 2}, {126523, 17714179},
{126524, 2}, {126530, 17693443}, {126531, 2}, {126535, 17693955},
{126536, 2}, {126537, 16912131}, {126538, 2}, {126539, 17722627},
{126540, 2}, {126541, 17729539}, {126542, 17706499}, {126543, 17713155},
{126544, 2}, {126545, 17708547}, {126546, 17718275}, {126547, 2},
{126548, 17756675}, {126549, 2}, {126551, 17696515}, {126552, 2},
{126553, 17709571}, {126554, 2}, {126555, 17714179}, {126556, 2},
{126557, 17684995}, {126558, 2}, {126559, 17971971}, {126560, 2},
{126561, 17695235}, {126562, 17693443}, {126563, 2}, {126564, 17732611},
{126565, 2}, {126567, 17693955}, {126568, 17711619}, {126569, 16912131},
{126570, 17720323}, {126571, 2}, {126572, 17694467}, {126573, 17729539},
{126574, 17706499}, {126575, 17713155}, {126576, 17715203}, {126577, 17708547},
{126578, 17718275}, {126579, 2}, {126580, 17756675}, {126581, 17698307},
{126582, 17701379}, {126583, 17696515}, {126584, 2}, {126585, 17709571},
{126586, 17712643}, {126587, 17714179}, {126588, 17971459}, {126589, 2},
{126590, 17971715}, {126591, 2}, {126592, 16910595}, {126593, 17695235},
{126594, 17693443}, {126595, 17846019}, {126596, 17732611}, {126597, 16911107},
{126598, 17743107}, {126599, 17693955}, {126600, 17711619}, {126601, 16912131},
{126602, 2}, {126603, 17722627}, {126604, 17694467}, {126605, 17729539},
{126606, 17706499}, {126607, 17713155}, {126608, 17715203}, {126609, 17708547},
{126610, 17718275}, {126611, 17736707}, {126612, 17756675}, {126613, 17698307},
{126614, 17701379}, {126615, 17696515}, {126616, 17736195}, {126617, 17709571},
{126618, 17712643}, {126619, 17714179}, {126620, 2}, {126625, 17695235},
{126626, 17693443}, {126627, 17846019}, {126628, 2}, {126629, 16911107},
{126630, 17743107}, {126631, 17693955}, {126632, 17711619}, {126633, 16912131},
{126634, 2}, {126635, 17722627}, {126636, 17694467}, {126637, 17729539},
{126638, 17706499}, {126639, 17713155}, {126640, 17715203}, {126641, 17708547},
{126642, 17718275}, {126643, 17736707}, {126644, 17756675}, {126645, 17698307},
{126646, 17701379}, {126647, 17696515}, {126648, 17736195}, {126649, 17709571},
{126650, 17712643}, {126651, 17714179}, {126652, 2}, {126704, 1},
{126706, 2}, {126976, 1}, {127020, 2}, {127024, 1},
{127124, 2}, {127136, 1}, {127151, 2}, {127153, 1},
{127168, 2}, {127169, 1}, {127184, 2}, {127185, 1},
{127222, 2}, {127233, 34749443}, {127234, 34749955}, {127235, 34750467},
{127236, 34750979}, {127237, 34751491}, {127238, 34752003}, {127239, 34752515},
{127240, 34753027}, {127241, 34753539}, {127242, 34754051}, {127243, 1},
{127248, 50655491}, {127249, 50656259}, {127250, 50657027}, {127251, 50657795},
{127252, 50658563}, {127253, 50659331}, {127254, 50660099}, {127255, 50660867},
{127256, 50661635}, {127257, 50662403}, {127258, 50663171}, {127259, 50663939},
{127260, 50664707}, {127261, 50665475}, {127262, 50666243}, {127263, 50667011},
{127264, 50667779}, {127265, 50668547}, {127266, 50669315}, {127267, 50670083},
{127268, 50670851}, {127269, 50671619}, {127270, 50672387}, {127271, 50673155},
{127272, 50673923}, {127273, 50674691}, {127274, 51531779}, {127275, 16777731},
{127276, 16781571}, {127277, 33554947}, {127278, 34755331}, {127279, 1},
{127280, 16777219}, {127281, 16777475}, {127282, 16777731}, {127283, 16777987},
{127284, 16778243}, {127285, 16778499}, {127286, 16778755}, {127287, 16779011},
{127288, 16779267}, {127289, 16779523}, {127290, 16779779}, {127291, 16780035},
{127292, 16780291}, {127293, 16780547}, {127294, 16780803}, {127295, 16781059},
{127296, 16781315}, {127297, 16781571}, {127298, 16781827}, {127299, 16782083},
{127300, 16782339}, {127301, 16782595}, {127302, 16782851}, {127303, 16783107},
{127304, 16783363}, {127305, 16783619}, {127306, 34755843}, {127307, 34237187},
{127308, 34756355}, {127309, 34756867}, {127310, 51534595}, {127311, 34758147},
{127312, 1}, {127338, 34220035}, {127339, 34200067}, {127340, 34758659},
{127341, 1}, {127376, 34759171}, {127377, 1}, {127406, 2},
{127462, 1}, {127488, 34759683}, {127489, 34760195}, {127490, 17318403},
{127491, 2}, {127504, 17168387}, {127505, 17983491}, {127506, 17983747},
{127507, 17362179}, {127508, 17153795}, {127509, 17984003}, {127510, 17984259},
{127511, 17235971}, {127512, 17984515}, {127513, 17984771}, {127514, 17985027},
{127515, 17596163}, {127516, 17985283}, {127517, 17985539}, {127518, 17985795},
{127519, 17986051}, {127520, 17986307}, {127521, 17986563}, {127522, 17177603},
{127523, 17986819}, {127524, 17987075}, {127525, 17987331}, {127526, 17987587},
{127527, 17987843}, {127528, 17988099}, {127529, 17152259}, {127530, 17233923},
{127531, 17988355}, {127532, 17299203}, {127533, 17234691}, {127534, 17299459},
{127535, 17988611}, {127536, 17191939}, {127537, 17988867}, {127538, 17989123},
{127539, 17989379}, {127540, 17989635}, {127541, 17989891}, {127542, 17274883},
{127543, 17170947}, {127544, 17990147}, {127545, 17990403}, {127546, 17990659},
{127547, 17990915}, {127548, 2}, {127552, 51545603}, {127553, 51546371},
{127554, 51547139}, {127555, 51547907}, {127556, 51548675}, {127557, 51549443},
{127558, 51550211}, {127559, 51550979}, {127560, 51551747}, {127561, 2},
{127568, 17998083}, {127569, 17998339}, {127570, 2}, {127584, 1},
{127590, 2}, {127744, 1}, {128728, 2}, {128732, 1},
{128749, 2}, {128752, 1}, {128765, 2}, {128768, 1},
{128887, 2}, {128891, 1}, {128986, 2}, {128992, 1},
{129004, 2}, {129008, 1}, {129009, 2}, {129024, 1},
{129036, 2}, {129040, 1}, {129096, 2}, {129104, 1},
{129114, 2}, {129120, 1}, {129160, 2}, {129168, 1},
{129198, 2}, {129200, 1}, {129212, 2}, {129216, 1},
{129218, 2}, {129280, 1}, {129620, 2}, {129632, 1},
{129646, 2}, {129648, 1}, {129661, 2}, {129664, 1},
{129674, 2}, {129679, 1}, {129735, 2}, {129742, 1},
{129757, 2}, {129759, 1}, {129770, 2}, {129776, 1},
{129785, 2}, {129792, 1}, {129939, 2}, {129940, 1},
{130032, 17045507}, {130033, 16786947}, {130034, 16785155}, {130035, 16785411},
{130036, 16787715}, {130037, 17045763}, {130038, 17046019}, {130039, 17046275},
{130040, 17046531}, {130041, 17046787}, {130042, 2}, {131072, 1},
{173792, 2}, {173824, 1}, {177978, 2}, {177984, 1},
{178206, 2}, {178208, 1}, {183970, 2}, {183984, 1},
{191457, 2}, {191472, 1}, {192094, 2}, {194560, 17998595},
{194561, 17998851}, {194562, 17999107}, {194563, 17999363}, {194564, 17999619},
{194565, 17619971}, {194566, 17999875}, {194567, 18000131}, {194568, 18000387},
{194569, 18000643}, {194570, 17620227}, {194571, 18000899}, {194572, 18001155},
{194573, 18001411}, {194574, 17620483}, {194575, 18001667}, {194576, 18001923},
{194577, 18002179}, {194578, 18002435}, {194579, 18002691}, {194580, 18002947},
{194581, 17985795}, {194582, 18003203}, {194583, 18003459}, {194584, 18003715},
{194585, 18003971}, {194586, 18004227}, {194587, 17634563}, {194588, 18004483},
{194589, 17156355}, {194590, 18004739}, {194591, 18004995}, {194592, 18005251},
{194593, 18005507}, {194594, 17990403}, {194595, 18005763}, {194596, 18006019},
{194597, 17635843}, {194598, 17620739}, {194599, 17620995}, {194600, 17636099},
{194601, 18006275}, {194602, 18006531}, {194603, 17574403}, {194604, 18006787},
{194605, 17621251}, {194606, 18007043}, {194607, 18007299}, {194608, 18007555},
{194609, 18007811}, {194612, 18008067}, {194613, 18008323}, {194614, 18008579},
{194615, 18008835}, {194616, 18009091}, {194617, 18009347}, {194618, 18009603},
{194619, 18009859}, {194620, 18010115}, {194621, 18010371}, {194622, 18010627},
{194623, 18010883}, {194624, 18011139}, {194625, 18011395}, {194626, 18011651},
{194627, 18011907}, {194628, 18012163}, {194629, 18012419}, {194631, 17636611},
{194632, 18012675}, {194633, 18012931}, {194634, 18013187}, {194635, 18013443},
{194636, 17621763}, {194637, 18013699}, {194638, 18013955}, {194639, 18014211},
{194640, 17611523}, {194641, 18014467}, {194642, 18014723}, {194643, 18014979},
{194644, 18015235}, {194645, 18015491}, {194646, 18015747}, {194647, 18016003},
{194648, 18016259}, {194649, 18016515}, {194650, 18016771}, {194651, 18017027},
{194652, 18017283}, {194653, 17984003}, {194654, 18017539}, {194655, 18017795},
{194656, 18018051}, {194657, 18018307}, {194658, 18018563}, {194659, 18018819},
{194660, 18019075}, {194661, 18019331}, {194662, 18019587}, {194663, 18019843},
{194664, 18020099}, {194665, 18020355}, {194666, 18020611}, {194668, 18020867},
{194669, 18021123}, {194670, 18021379}, {194671, 17573379}, {194672, 18021635},
{194673, 18021891}, {194674, 18022147}, {194675, 18022403}, {194676, 18022659},
{194677, 17163011}, {194678, 18022915}, {194679, 18023171}, {194680, 17163523},
{194681, 18023427}, {194682, 18023683}, {194683, 18023939}, {194684, 18024195},
{194685, 18024451}, {194686, 18024707}, {194687, 18024963}, {194688, 18025219},
{194689, 18025475}, {194690, 18025731}, {194691, 18025987}, {194692, 18026243},
{194693, 18026499}, {194694, 18026755}, {194695, 18027011}, {194696, 18027267},
{194697, 18027523}, {194698, 18027779}, {194699, 18028035}, {194700, 18028291},
{194701, 18028547}, {194702, 17560067}, {194703, 18028803}, {194704, 17166083},
{194705, 18029059}, {194707, 18029315}, {194708, 18029571}, {194710, 18029827},
{194711, 18030083}, {194712, 18030339}, {194713, 18030595}, {194714, 18030851},
{194715, 18031107}, {194716, 18031363}, {194717, 18031619}, {194718, 18031875},
{194719, 18032131}, {194720, 18032387}, {194721, 18032643}, {194722, 18032899},
{194723, 17623043}, {194724, 18033155}, {194725, 18033411}, {194726, 18033667},
{194727, 18033923}, {194728, 17639683}, {194729, 18033923}, {194730, 18034179},
{194731, 17623555}, {194732, 18034435}, {194733, 18034691}, {194734, 18034947},
{194735, 18035203}, {194736, 17623811}, {194737, 17553155}, {194738, 17425411},
{194739, 18035459}, {194740, 18035715}, {194741, 18035971}, {194742, 18036227},
{194743, 18036483}, {194744, 18036739}, {194745, 18036995}, {194746, 18037251},
{194747, 18037507}, {194748, 18037763}, {194749, 18038019}, {194750, 18038275},
{194751, 18038531}, {194752, 18038787}, {194753, 18039043}, {194754, 18039299},
{194755, 18039555}, {194756, 18039811}, {194757, 18040067}, {194758, 18040323},
{194759, 18040579}, {194760, 17624067}, {194761, 18040835}, {194762, 18041091},
{194763, 18041347}, {194764, 18041603}, {194765, 18041859}, {194766, 18042115},
{194767, 17624579}, {194768, 18042371}, {194769, 18042627}, {194770, 18042883},
{194771, 18043139}, {194772, 18043395}, {194773, 18043651}, {194774, 18043907},
{194775, 18044163}, {194776, 17560323}, {194777, 17641731}, {194778, 18044419},
{194779, 18044675}, {194780, 18044931}, {194781, 18045187}, {194782, 18045443},
{194783, 18045699}, {194784, 18045955}, {194785, 18046211}, {194786, 17624835},
{194787, 18046467}, {194788, 18046723}, {194789, 18046979}, {194790, 18047235},
{194791, 17652483}, {194792, 18047491}, {194793, 18047747}, {194794, 18048003},
{194795, 18048259}, {194796, 18048515}, {194797, 18048771}, {194798, 18049027},
{194799, 18049283}, {194800, 18049539}, {194801, 18049795}, {194802, 18050051},
{194803, 18050307}, {194804, 18050563}, {194805, 17577731}, {194806, 18050819},
{194807, 18051075}, {194808, 18051331}, {194809, 18051587}, {194810, 18051843},
{194811, 18052099}, {194812, 18052355}, {194813, 18052611}, {194814, 18052867},
{194815, 18053123}, {194816, 18053379}, {194817, 17625091}, {194818, 17598723},
{194819, 18053635}, {194820, 18053891}, {194821, 18054147}, {194822, 18054403},
{194823, 18054659}, {194824, 18054915}, {194825, 18055171}, {194826, 18055427},
{194827, 17642499}, {194828, 18055683}, {194829, 18055939}, {194830, 18056195},
{194831, 18056451}, {194832, 18056707}, {194833, 18056963}, {194834, 18057219},
{194835, 18057475}, {194836, 17642755}, {194837, 18057731}, {194838, 18057987},
{194839, 18058243}, {194840, 18058499}, {194841, 18058755}, {194842, 18059011},
{194843, 18059267}, {194844, 18059523}, {194845, 18059779}, {194846, 18060035},
{194847, 18060291}, {194848, 18060547}, {194849, 17643267}, {194850, 18060803},
{194851, 18061059}, {194852, 18061315}, {194853, 18061571}, {194854, 18061827},
{194855, 18062083}, {194856, 18062339}, {194857, 18062595}, {194858, 18062851},
{194859, 18063107}, {194860, 18063363}, {194862, 18063619}, {194863, 18063875},
{194864, 17643779}, {194865, 18064131}, {194866, 18064387}, {194867, 18064643},
{194868, 18064899}, {194869, 18065155}, {194870, 18065411}, {194871, 18065667},
{194872, 17574147}, {194873, 18065923}, {194874, 18066179}, {194875, 18066435},
{194876, 18066691}, {194877, 18066947}, {194878, 18067203}, {194879, 18067459},
{194880, 17645315}, {194881, 18067715}, {194882, 18067971}, {194883, 18068227},
{194884, 18068483}, {194885, 18068739}, {194886, 18068995}, {194888, 17645571},
{194889, 17652995}, {194890, 18069251}, {194891, 18069507}, {194892, 18069763},
{194893, 18070019}, {194894, 18070275}, {194895, 17564675}, {194896, 17646083},
{194897, 18070531}, {194898, 18070787}, {194899, 17627651}, {194900, 18071043},
{194901, 18071299}, {194902, 17616643}, {194903, 18071555}, {194904, 18071811},
{194905, 17628419}, {194906, 18072067}, {194907, 18072323}, {194908, 18072579},
{194909, 18072835}, {194911, 18073091}, {194912, 18073347}, {194913, 18073603},
{194914, 18073859}, {194915, 18074115}, {194916, 18074371}, {194917, 18074627},
{194918, 18074883}, {194919, 18075139}, {194920, 18075395}, {194921, 18075651},
{194922, 18075907}, {194923, 18076163}, {194924, 18076419}, {194925, 18076675},
{194926, 18076931}, {194927, 18077187}, {194928, 18077443}, {194929, 18077699},
{194930, 18077955}, {194931, 18078211}, {194932, 18078467}, {194933, 18078723},
{194934, 18078979}, {194935, 18079235}, {194936, 18079491}, {194937, 18079747},
{194938, 17629955}, {194939, 18080003}, {194940, 18080259}, {194941, 18080515},
{194942, 18080771}, {194943, 18081027}, {194944, 18081283}, {194945, 18081539},
{194946, 18081795}, {194947, 18082051}, {194948, 18082307}, {194949, 18082563},
{194950, 18082819}, {194951, 18083075}, {194952, 18083331}, {194953, 18083587},
{194954, 18083843}, {194955, 18029315}, {194956, 18084099}, {194957, 18084355},
{194958, 18084611}, {194959, 18084867}, {194960, 18085123}, {194961, 18085379},
{194962, 18085635}, {194963, 18085891}, {194964, 18086147}, {194965, 18086403},
{194966, 18086659}, {194967, 18086915}, {194968, 17578499}, {194969, 18087171},
{194970, 18087427}, {194971, 18087683}, {194972, 18087939}, {194973, 18088195},
{194974, 18088451}, {194975, 17630723}, {194976, 18088707}, {194977, 18088963},
{194978, 18089219}, {194979, 18089475}, {194980, 18089731}, {194981, 18089987},
{194982, 18090243}, {194983, 18090499}, {194984, 18090755}, {194985, 18091011},
{194986, 18091267}, {194987, 18091523}, {194988, 18091779}, {194989, 18092035},
{194990, 18092291}, {194991, 18092547}, {194992, 18092803}, {194993, 18093059},
{194994, 18093315}, {194995, 18093571}, {194996, 17563395}, {194997, 18093827},
{194998, 18094083}, {194999, 18094339}, {195000, 18094595}, {195001, 18094851},
{195002, 18095107}, {195003, 17647875}, {195004, 18095363}, {195005, 18095619},
{195006, 18095875}, {195007, 18096131}, {195008, 18096387}, {195009, 18096643},
{195010, 18096899}, {195011, 18097155}, {195012, 17189123}, {195013, 18097411},
{195014, 18097667}, {195015, 18097923}, {195016, 18098179}, {195017, 18098435},
{195018, 18098691}, {195019, 18098947}, {195020, 18099203}, {195021, 18099459},
{195022, 18099715}, {195023, 18099971}, {195024, 17649155}, {195025, 17649411},
{195026, 17190915}, {195027, 18100227}, {195028, 18100483}, {195029, 18100739},
{195030, 18100995}, {195031, 18101251}, {195032, 18101507}, {195033, 18101763},
{195034, 18102019}, {195035, 18102275}, {195036, 18102531}, {195037, 18102787},
{195038, 18103043}, {195039, 17649667}, {195040, 18103299}, {195041, 18103555},
{195042, 18103811}, {195043, 18104067}, {195044, 18104323}, {195045, 18104579},
{195046, 18104835}, {195047, 18105091}, {195048, 18105347}, {195049, 18105603},
{195050, 18105859}, {195051, 18106115}, {195052, 18106371}, {195053, 18106627},
{195054, 18106883}, {195055, 18107139}, {195056, 18107395}, {195057, 18107651},
{195058, 18107907}, {195059, 18108163}, {195060, 18108419}, {195061, 18108675},
{195062, 18108931}, {195063, 18109187}, {195064, 18109443}, {195065, 18109699},
{195066, 18109955}, {195067, 18110211}, {195068, 18110467}, {195069, 18110723},
{195070, 17651203}, {195072, 18110979}, {195073, 18111235}, {195074, 18111491},
{195075, 18111747}, {195076, 18112003}, {195077, 18112259}, {195078, 18112515},
{195079, 18112771}, {195080, 18113027}, {195081, 18113283}, {195082, 17651459},
{195083, 18113539}, {195084, 18113795}, {195085, 18114051}, {195086, 18114307},
{195087, 18114563}, {195088, 18114819}, {195089, 18115075}, {195090, 18115331},
{195091, 18115587}, {195092, 18115843}, {195093, 17203203}, {195094, 18116099},
{195095, 17204227}, {195096, 18116355}, {195097, 18116611}, {195098, 18116867},
{195099, 18117123}, {195100, 17205507}, {195101, 18117379}, {195102, 2},
{196608, 1}, {201547, 2}, {201552, 1}, {205744, 2},
{917760, 0}, {918000, 2}
};
} // namespace ada::idna
#endif // ADA_IDNA_TABLES_H
/* end file src/mapping_tables.cpp */
namespace ada::idna {
// This can be greatly accelerated. For now we just use a simply
// binary search. In practice, you should *not* do that.
uint32_t find_range_index(uint32_t key) {
////////////////
// This could be implemented with std::lower_bound, but we roll our own
// because we want to allow further optimizations in the future.
////////////////
uint32_t len = std::size(table);
uint32_t low = 0;
uint32_t high = len - 1;
while (low <= high) {
uint32_t middle_index = (low + high) >> 1; // cannot overflow
uint32_t middle_value = table[middle_index][0];
if (middle_value < key) {
low = middle_index + 1;
} else if (middle_value > key) {
high = middle_index - 1;
} else {
return middle_index; // perfect match
}
}
return low == 0 ? 0 : low - 1;
}
void ascii_map(char* input, size_t length) {
auto broadcast = [](uint8_t v) -> uint64_t {
return 0x101010101010101ull * v;
};
uint64_t broadcast_80 = broadcast(0x80);
uint64_t broadcast_Ap = broadcast(128 - 'A');
uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
size_t i = 0;
for (; i + 7 < length; i += 8) {
uint64_t word{};
memcpy(&word, input + i, sizeof(word));
word ^=
(((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
memcpy(input + i, &word, sizeof(word));
}
if (i < length) {
uint64_t word{};
memcpy(&word, input + i, length - i);
word ^=
(((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
memcpy(input + i, &word, length - i);
}
}
// Map the characters according to IDNA, returning the empty string on error.
std::u32string map(std::u32string_view input) {
// [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
// For each code point in the domain_name string, look up the status
// value in Section 5, [IDNA Mapping
// Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table),
// and take the following actions:
// * disallowed: Leave the code point unchanged in the string, and
// record that there was an error.
// * ignored: Remove the code point from the string. This is
// equivalent to mapping the code point to an empty string.
// * mapped: Replace the code point in the string by the value for
// the mapping in Section 5, [IDNA Mapping
// Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table).
// * valid: Leave the code point unchanged in the string.
static std::u32string error = U"";
std::u32string answer;
answer.reserve(input.size());
for (char32_t x : input) {
size_t index = find_range_index(x);
uint32_t descriptor = table[index][1];
uint8_t code = uint8_t(descriptor);
switch (code) {
case 0:
break; // nothing to do, ignored
case 1:
answer.push_back(x); // valid, we just copy it to output
break;
case 2:
return error; // disallowed
// case 3 :
default:
// We have a mapping
{
size_t char_count = (descriptor >> 24);
uint16_t char_index = uint16_t(descriptor >> 8);
for (size_t idx = char_index; idx < char_index + char_count; idx++) {
answer.push_back(mappings[idx]);
}
}
}
}
return answer;
}
} // namespace ada::idna
/* end file src/mapping.cpp */
/* begin file src/normalization.cpp */
/* begin file src/normalization_tables.cpp */
// IDNA 15.0.0
// clang-format off
#ifndef ADA_IDNA_NORMALIZATION_TABLES_H
#define ADA_IDNA_NORMALIZATION_TABLES_H
#include <cstdint>
/**
* Unicode Standard Annex #15
*
* UNICODE NORMALIZATION FORMS
* https://www.unicode.org/reports/tr15/
*
* See https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/data/data_norm.h for reference.
*/
namespace ada::idna {
const uint8_t decomposition_index[4352] = {
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 16, 7, 17, 18, 19, 20, 21, 22, 23, 24, 7,
7, 7, 7, 7, 25, 7, 26, 27, 28, 29, 30, 31, 32, 33, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 34, 35, 7, 7, 7,
36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 37, 38, 39, 40, 41, 42, 43, 7, 7, 7, 7, 7, 7, 7, 44, 7, 7,
7, 7, 7, 7, 7, 7, 45, 46, 7, 47, 48, 49, 7, 7, 7, 50, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 51, 7, 52, 53, 54, 55, 56, 7, 7, 7,
7, 7, 7, 7, 7, 57, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 58,
59, 7, 60, 61, 62, 7, 7, 7, 7, 7, 7, 7, 7, 63, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
64, 65, 66, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7};
const uint16_t decomposition_block[67][257] = {
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 8, 8, 8, 8,
8, 8, 8, 9, 16, 17, 20, 20, 20, 20, 21, 28, 28, 29, 33,
37, 45, 48, 48, 49, 57, 61, 64, 65, 77, 89, 100, 100, 108, 116,
124, 132, 140, 148, 148, 156, 164, 172, 180, 188, 196, 204, 212, 220, 220,
228, 236, 244, 252, 260, 268, 268, 268, 276, 284, 292, 300, 308, 308, 308,
316, 324, 332, 340, 348, 356, 356, 364, 372, 380, 388, 396, 404, 412, 420,
428, 428, 436, 444, 452, 460, 468, 476, 476, 476, 484, 492, 500, 508, 516,
516, 524},
{524, 532, 540, 548, 556, 564, 572, 580, 588, 596, 604, 612,
620, 628, 636, 644, 652, 652, 652, 660, 668, 676, 684, 692,
700, 708, 716, 724, 732, 740, 748, 756, 764, 772, 780, 788,
796, 804, 812, 812, 812, 820, 828, 836, 844, 852, 860, 868,
876, 884, 885, 893, 900, 908, 916, 924, 932, 932, 940, 948,
956, 964, 972, 981, 989, 996, 996, 996, 1004, 1012, 1020, 1028,
1036, 1045, 1052, 1052, 1052, 1060, 1068, 1076, 1084, 1092, 1100, 1100,
1100, 1108, 1116, 1124, 1132, 1140, 1148, 1156, 1164, 1172, 1180, 1188,
1196, 1204, 1212, 1220, 1228, 1236, 1244, 1244, 1244, 1252, 1260, 1268,
1276, 1284, 1292, 1300, 1308, 1316, 1324, 1332, 1340, 1348, 1356, 1364,
1372, 1380, 1388, 1396, 1404, 1412, 1420, 1429, 1432, 1432, 1432, 1432,
1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432,
1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432,
1432, 1432, 1432, 1432, 1432, 1440, 1448, 1448, 1448, 1448, 1448, 1448,
1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1456, 1464, 1464, 1464,
1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464,
1464, 1464, 1464, 1464, 1465, 1477, 1489, 1501, 1509, 1517, 1525, 1533,
1541, 1548, 1556, 1564, 1572, 1580, 1588, 1596, 1604, 1612, 1624, 1636,
1648, 1660, 1672, 1684, 1696, 1708, 1708, 1720, 1732, 1744, 1756, 1764,
1772, 1772, 1772, 1780, 1788, 1796, 1804, 1812, 1820, 1832, 1844, 1852,
1860, 1869, 1877, 1885, 1892, 1900, 1908, 1908, 1908, 1916, 1924, 1936,
1948, 1956, 1964, 1972, 1980},
{1980, 1988, 1996, 2004, 2012, 2020, 2028, 2036, 2044, 2052, 2060, 2068,
2076, 2084, 2092, 2100, 2108, 2116, 2124, 2132, 2140, 2148, 2156, 2164,
2172, 2180, 2188, 2196, 2204, 2204, 2204, 2212, 2220, 2220, 2220, 2220,
2220, 2220, 2220, 2228, 2236, 2244, 2252, 2264, 2276, 2288, 2300, 2308,
2316, 2328, 2340, 2348, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2357, 2361, 2365, 2369,
2373, 2377, 2381, 2385, 2389, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2393, 2401, 2409, 2417, 2425, 2433, 2440, 2440, 2441, 2445, 2449, 2453,
2457, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460},
{2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
2460, 2460, 2460, 2460, 2460, 2464, 2468, 2468, 2472, 2480, 2480, 2480,
2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480,
2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480,
2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480,
2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2484, 2484, 2484,
2484, 2484, 2485, 2492, 2492, 2492, 2492, 2496, 2496, 2496, 2496, 2496,
2497, 2506, 2512, 2520, 2524, 2532, 2540, 2548, 2548, 2556, 2556, 2564,
2572, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584,
2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584,
2584, 2584, 2584, 2592, 2600, 2608, 2616, 2624, 2632, 2644, 2644, 2644,
2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644,
2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2652,
2660, 2668, 2676, 2684, 2685, 2689, 2693, 2698, 2706, 2713, 2717, 2720,
2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720,
2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720,
2721, 2725, 2729, 2732, 2733, 2737, 2740, 2740, 2740, 2741, 2744, 2744,
2744, 2744, 2744, 2744, 2744},
{2744, 2752, 2760, 2760, 2768, 2768, 2768, 2768, 2776, 2776, 2776, 2776,
2776, 2784, 2792, 2800, 2800, 2800, 2800, 2800, 2800, 2800, 2800, 2800,
2800, 2800, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808,
2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808,
2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2816, 2816,
2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816,
2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2824, 2832, 2832,
2840, 2840, 2840, 2840, 2848, 2848, 2848, 2848, 2848, 2856, 2864, 2872,
2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872,
2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2880,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
2888, 2888, 2896, 2904, 2904, 2904, 2904, 2904, 2904, 2904, 2904, 2904,
2904, 2904, 2904, 2904, 2904, 2912, 2920, 2928, 2936, 2936, 2936, 2944,
2952, 2952, 2952, 2960, 2968, 2976, 2984, 2992, 3000, 3000, 3000, 3008,
3016, 3024, 3032, 3040, 3048, 3048, 3048, 3056, 3064, 3072, 3080, 3088,
3096, 3104, 3112, 3120, 3128, 3136, 3144, 3144, 3144, 3152, 3160, 3160,
3160, 3160, 3160, 3160, 3160},
{3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
3160, 3160, 3160, 3161, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168},
{3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168,
3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3176,
3184, 3192, 3200, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208,
3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3209, 3217, 3225,
3233, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
3240, 3248, 3248, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256,
3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264,
3264, 3264, 3264, 3264, 3264, 3264, 3272, 3272, 3272, 3272, 3272, 3272,
3272, 3272, 3280, 3280, 3280, 3288, 3288, 3288, 3288, 3288, 3288, 3288,
3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288,
3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288,
3288, 3288, 3288, 3288, 3288, 3296, 3304, 3312, 3320, 3328, 3336, 3344,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352,
3360, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368,
3368, 3368, 3368, 3368, 3368, 3376, 3384, 3384, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392},
{3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392,
3392, 3392, 3392, 3392, 3400, 3400, 3400, 3408, 3408, 3408, 3408, 3408,
3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408,
3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408,
3408, 3408, 3408, 3408, 3408, 3408, 3416, 3424, 3432, 3432, 3432, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440},
{3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440,
3440, 3448, 3448, 3448, 3456, 3464, 3464, 3464, 3464, 3464, 3464, 3464,
3464, 3464, 3464, 3464, 3464, 3464, 3464, 3464, 3464, 3472, 3480, 3480,
3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480,
3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480,
3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480,
3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480,
3480, 3480, 3480, 3480, 3480, 3488, 3488, 3488, 3488, 3488, 3488, 3488,
3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488,
3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488,
3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488,
3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3496,
3504, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512},
{3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512,
3512, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520,
3520, 3528, 3528, 3528, 3528, 3528, 3528, 3528, 3536, 3544, 3544, 3552,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564},
{3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564,
3564, 3564, 3564, 3572, 3580, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588,
3588, 3588, 3588, 3596, 3596, 3604, 3616, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624},
{3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624,
3624, 3624, 3624, 3625, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632,
3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3633,
3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640,
3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640,
3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640,
3640, 3640, 3640, 3640, 3641, 3649, 3656, 3656, 3656, 3656, 3656, 3656,
3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656,
3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656,
3656, 3656, 3656, 3656, 3656},
{3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656,
3657, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660,
3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660,
3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660,
3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660,
3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3668, 3668, 3668, 3668,
3668, 3668, 3668, 3668, 3668, 3668, 3676, 3676, 3676, 3676, 3676, 3684,
3684, 3684, 3684, 3684, 3692, 3692, 3692, 3692, 3692, 3700, 3700, 3700,
3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3708, 3708,
3708, 3708, 3708, 3708, 3708, 3708, 3708, 3708, 3716, 3716, 3724, 3733,
3744, 3753, 3764, 3764, 3764, 3764, 3764, 3764, 3764, 3764, 3772, 3772,
3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772,
3772, 3772, 3772, 3772, 3780, 3780, 3780, 3780, 3780, 3780, 3780, 3780,
3780, 3780, 3788, 3788, 3788, 3788, 3788, 3796, 3796, 3796, 3796, 3796,
3804, 3804, 3804, 3804, 3804, 3812, 3812, 3812, 3812, 3812, 3812, 3812,
3812, 3812, 3812, 3812, 3812, 3812, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820},
{3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820,
3820, 3820, 3820, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828,
3829, 3832, 3832, 3832, 3832},
{3832, 3832, 3832, 3832, 3832, 3832, 3832, 3840, 3840, 3848, 3848, 3856,
3856, 3864, 3864, 3872, 3872, 3872, 3872, 3880, 3880, 3880, 3880, 3880,
3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880,
3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880,
3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880,
3888, 3888, 3896, 3896, 3896, 3904, 3912, 3912, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920},
{3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920,
3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3921, 3925, 3929, 3932,
3933, 3937, 3941, 3945, 3949, 3953, 3957, 3961, 3965, 3969, 3973, 3976,
3977, 3981, 3985, 3989, 3993, 3997, 4001, 4005, 4009, 4013, 4017, 4021,
4025, 4029, 4033, 4037, 4041, 4045, 4048, 4049, 4053, 4057, 4061, 4065,
4069, 4073, 4077, 4081, 4085, 4089, 4093, 4097, 4101, 4105, 4109, 4113,
4117, 4121, 4125, 4129, 4133, 4137, 4141, 4145, 4149, 4153, 4157, 4160,
4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160,
4161, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164,
4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164,
4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4165,
4169, 4173, 4177, 4181, 4185, 4189, 4193, 4197, 4201, 4205, 4209, 4213,
4217, 4221, 4225, 4229, 4233, 4237, 4241, 4245, 4249, 4253, 4257, 4261,
4265, 4269, 4273, 4277, 4281, 4285, 4289, 4293, 4297, 4301, 4305, 4309,
4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312,
4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312,
4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312,
4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312,
4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312,
4312, 4312, 4312, 4312, 4312},
{4312, 4320, 4328, 4336, 4344, 4352, 4360, 4368, 4376, 4388, 4400, 4408,
4416, 4424, 4432, 4440, 4448, 4456, 4464, 4472, 4480, 4492, 4504, 4516,
4528, 4536, 4544, 4552, 4560, 4572, 4584, 4592, 4600, 4608, 4616, 4624,
4632, 4640, 4648, 4656, 4664, 4672, 4680, 4688, 4696, 4704, 4712, 4724,
4736, 4744, 4752, 4760, 4768, 4776, 4784, 4792, 4800, 4812, 4824, 4832,
4840, 4848, 4856, 4864, 4872, 4880, 4888, 4896, 4904, 4912, 4920, 4928,
4936, 4944, 4952, 4960, 4968, 4980, 4992, 5004, 5016, 5028, 5040, 5052,
5064, 5072, 5080, 5088, 5096, 5104, 5112, 5120, 5128, 5140, 5152, 5160,
5168, 5176, 5184, 5192, 5200, 5212, 5224, 5236, 5248, 5260, 5272, 5280,
5288, 5296, 5304, 5312, 5320, 5328, 5336, 5344, 5352, 5360, 5368, 5376,
5384, 5396, 5408, 5420, 5432, 5440, 5448, 5456, 5464, 5472, 5480, 5488,
5496, 5504, 5512, 5520, 5528, 5536, 5544, 5552, 5560, 5568, 5576, 5584,
5592, 5600, 5608, 5616, 5624, 5632, 5640, 5648, 5656, 5664, 5673, 5682,
5688, 5688, 5688, 5688, 5688, 5696, 5704, 5712, 5720, 5732, 5744, 5756,
5768, 5780, 5792, 5804, 5816, 5828, 5840, 5852, 5864, 5876, 5888, 5900,
5912, 5924, 5936, 5948, 5960, 5968, 5976, 5984, 5992, 6000, 6008, 6020,
6032, 6044, 6056, 6068, 6080, 6092, 6104, 6116, 6128, 6136, 6144, 6152,
6160, 6168, 6176, 6184, 6192, 6204, 6216, 6228, 6240, 6252, 6264, 6276,
6288, 6300, 6312, 6324, 6336, 6348, 6360, 6372, 6384, 6396, 6408, 6420,
6432, 6440, 6448, 6456, 6464, 6476, 6488, 6500, 6512, 6524, 6536, 6548,
6560, 6572, 6584, 6592, 6600, 6608, 6616, 6624, 6632, 6640, 6648, 6648,
6648, 6648, 6648, 6648, 6648},
{6648, 6656, 6664, 6676, 6688, 6700, 6712, 6724, 6736, 6744, 6752, 6764,
6776, 6788, 6800, 6812, 6824, 6832, 6840, 6852, 6864, 6876, 6888, 6888,
6888, 6896, 6904, 6916, 6928, 6940, 6952, 6952, 6952, 6960, 6968, 6980,
6992, 7004, 7016, 7028, 7040, 7048, 7056, 7068, 7080, 7092, 7104, 7116,
7128, 7136, 7144, 7156, 7168, 7180, 7192, 7204, 7216, 7224, 7232, 7244,
7256, 7268, 7280, 7292, 7304, 7312, 7320, 7332, 7344, 7356, 7368, 7368,
7368, 7376, 7384, 7396, 7408, 7420, 7432, 7432, 7432, 7440, 7448, 7460,
7472, 7484, 7496, 7508, 7520, 7520, 7528, 7528, 7540, 7540, 7552, 7552,
7564, 7572, 7580, 7592, 7604, 7616, 7628, 7640, 7652, 7660, 7668, 7680,
7692, 7704, 7716, 7728, 7740, 7748, 7756, 7764, 7772, 7780, 7788, 7796,
7804, 7812, 7820, 7828, 7836, 7844, 7852, 7852, 7852, 7864, 7876, 7892,
7908, 7924, 7940, 7956, 7972, 7984, 7996, 8012, 8028, 8044, 8060, 8076,
8092, 8104, 8116, 8132, 8148, 8164, 8180, 8196, 8212, 8224, 8236, 8252,
8268, 8284, 8300, 8316, 8332, 8344, 8356, 8372, 8388, 8404, 8420, 8436,
8452, 8464, 8476, 8492, 8508, 8524, 8540, 8556, 8572, 8580, 8588, 8600,
8608, 8620, 8620, 8628, 8640, 8648, 8656, 8664, 8672, 8681, 8688, 8693,
8701, 8710, 8716, 8728, 8736, 8748, 8748, 8756, 8768, 8776, 8784, 8792,
8800, 8810, 8818, 8826, 8832, 8840, 8848, 8860, 8872, 8872, 8872, 8880,
8892, 8900, 8908, 8916, 8924, 8926, 8934, 8942, 8948, 8956, 8964, 8976,
8988, 8996, 9004, 9012, 9024, 9032, 9040, 9048, 9056, 9066, 9074, 9080,
9084, 9084, 9084, 9096, 9104, 9116, 9116, 9124, 9136, 9144, 9152, 9160,
9168, 9178, 9181, 9188, 9190},
{9190, 9194, 9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9232,
9232, 9232, 9232, 9232, 9232, 9233, 9236, 9236, 9236, 9236, 9236, 9237,
9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244,
9245, 9249, 9257, 9268, 9268, 9268, 9268, 9268, 9268, 9268, 9268, 9269,
9272, 9272, 9272, 9273, 9281, 9292, 9293, 9301, 9312, 9312, 9312, 9312,
9313, 9320, 9321, 9328, 9328, 9328, 9328, 9328, 9328, 9328, 9328, 9329,
9337, 9345, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352,
9352, 9352, 9352, 9353, 9368, 9368, 9368, 9368, 9368, 9368, 9368, 9369,
9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372,
9372, 9372, 9372, 9372, 9373, 9377, 9380, 9380, 9381, 9385, 9389, 9393,
9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429, 9433, 9437, 9441,
9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477, 9481, 9485, 9488,
9489, 9493, 9497, 9501, 9505, 9509, 9513, 9517, 9521, 9525, 9529, 9533,
9537, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540,
9541, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548,
9548, 9548, 9548, 9548, 9549},
{9549, 9561, 9573, 9577, 9584, 9585, 9597, 9609, 9612, 9613,
9621, 9625, 9629, 9633, 9637, 9641, 9645, 9649, 9653, 9657,
9660, 9661, 9665, 9672, 9672, 9673, 9677, 9681, 9685, 9689,
9692, 9692, 9693, 9701, 9713, 9720, 9721, 9724, 9724, 9728,
9729, 9732, 9732, 9736, 9745, 9749, 9752, 9753, 9757, 9761,
9764, 9765, 9769, 9773, 9777, 9781, 9785, 9789, 9792, 9793,
9805, 9809, 9813, 9817, 9821, 9824, 9824, 9824, 9824, 9825,
9829, 9833, 9837, 9841, 9844, 9844, 9844, 9844, 9844, 9844,
9845, 9857, 9869, 9885, 9897, 9909, 9921, 9933, 9945, 9957,
9969, 9981, 9993, 10005, 10017, 10029, 10037, 10041, 10049, 10061,
10069, 10073, 10081, 10093, 10109, 10117, 10121, 10129, 10141, 10145,
10149, 10153, 10157, 10161, 10169, 10181, 10189, 10193, 10201, 10213,
10229, 10237, 10241, 10249, 10261, 10265, 10269, 10273, 10276, 10276,
10276, 10276, 10276, 10276, 10276, 10276, 10276, 10277, 10288, 10288,
10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288,
10288, 10288, 10288, 10288, 10288, 10296, 10304, 10304, 10304, 10304,
10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304,
10304, 10304, 10304, 10304, 10304, 10312, 10312, 10312, 10312, 10312,
10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312,
10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312,
10312, 10312, 10312, 10312, 10312, 10312, 10320, 10328, 10336, 10336,
10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336,
10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336,
10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336,
10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336,
10336, 10336, 10336, 10336, 10336, 10336, 10336},
{10336, 10336, 10336, 10336, 10336, 10344, 10344, 10344, 10344, 10344,
10352, 10352, 10352, 10360, 10360, 10360, 10360, 10360, 10360, 10360,
10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360,
10360, 10360, 10360, 10360, 10360, 10360, 10360, 10368, 10368, 10376,
10376, 10376, 10376, 10376, 10377, 10385, 10396, 10397, 10405, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10424, 10424, 10424, 10432,
10432, 10432, 10440, 10440, 10448, 10448, 10448, 10448, 10448, 10448,
10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448,
10448, 10448, 10448, 10448, 10448, 10448, 10448, 10456, 10456, 10464,
10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464,
10472, 10480, 10488, 10496, 10504, 10504, 10504, 10512, 10520, 10520,
10520, 10528, 10536, 10536, 10536, 10536, 10536, 10536, 10536, 10544,
10552, 10552, 10552, 10560, 10568, 10568, 10568, 10576, 10584, 10584,
10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584,
10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584,
10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584,
10584, 10584, 10584, 10592, 10600, 10608, 10616, 10616, 10616, 10616,
10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616,
10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616,
10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616,
10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616,
10616, 10616, 10616, 10616, 10616, 10624, 10632, 10640, 10648, 10648,
10648, 10648, 10648, 10648, 10648, 10656, 10664, 10672, 10680, 10680,
10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680,
10680, 10680, 10680, 10680, 10680, 10680, 10680},
{10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680,
10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680,
10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680,
10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680,
10680, 10680, 10684, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688},
{10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688,
10688, 10688, 10688, 10688, 10688, 10688, 10689, 10693, 10697, 10701,
10705, 10709, 10713, 10717, 10721, 10725, 10733, 10741, 10749, 10757,
10765, 10773, 10781, 10789, 10797, 10805, 10813, 10825, 10837, 10849,
10861, 10873, 10885, 10897, 10909, 10921, 10937, 10953, 10969, 10985,
11001, 11017, 11033, 11049, 11065, 11081, 11097, 11105, 11113, 11121,
11129, 11137, 11145, 11153, 11161, 11169, 11181, 11193, 11205, 11217,
11229, 11241, 11253, 11265, 11277, 11289, 11301, 11313, 11325, 11337,
11349, 11361, 11373, 11385, 11397, 11409, 11421, 11433, 11445, 11457,
11469, 11481, 11493, 11505, 11517, 11529, 11541, 11553, 11565, 11577,
11589, 11601, 11613, 11617, 11621, 11625, 11629, 11633, 11637, 11641,
11645, 11649, 11653, 11657, 11661, 11665, 11669, 11673, 11677, 11681,
11685, 11689, 11693, 11697, 11701, 11705, 11709, 11713, 11717, 11721,
11725, 11729, 11733, 11737, 11741, 11745, 11749, 11753, 11757, 11761,
11765, 11769, 11773, 11777, 11781, 11785, 11789, 11793, 11797, 11801,
11805, 11809, 11813, 11817, 11821, 11824, 11824, 11824, 11824, 11824,
11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824,
11824, 11824, 11824, 11824, 11824, 11824, 11824},
{11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824,
11824, 11824, 11825, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840,
11840, 11840, 11840, 11840, 11840, 11840, 11841, 11853, 11861, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872,
11872, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880},
{11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880,
11880, 11880, 11880, 11880, 11881, 11885, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888},
{11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888,
11888, 11889, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892},
{11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892,
11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11893,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896,
11896, 11896, 11896, 11897, 11900, 11900, 11900, 11900, 11900, 11900,
11900, 11900, 11900, 11900, 11900, 11900, 11901},
{11901, 11905, 11909, 11913, 11917, 11921, 11925, 11929, 11933, 11937,
11941, 11945, 11949, 11953, 11957, 11961, 11965, 11969, 11973, 11977,
11981, 11985, 11989, 11993, 11997, 12001, 12005, 12009, 12013, 12017,
12021, 12025, 12029, 12033, 12037, 12041, 12045, 12049, 12053, 12057,
12061, 12065, 12069, 12073, 12077, 12081, 12085, 12089, 12093, 12097,
12101, 12105, 12109, 12113, 12117, 12121, 12125, 12129, 12133, 12137,
12141, 12145, 12149, 12153, 12157, 12161, 12165, 12169, 12173, 12177,
12181, 12185, 12189, 12193, 12197, 12201, 12205, 12209, 12213, 12217,
12221, 12225, 12229, 12233, 12237, 12241, 12245, 12249, 12253, 12257,
12261, 12265, 12269, 12273, 12277, 12281, 12285, 12289, 12293, 12297,
12301, 12305, 12309, 12313, 12317, 12321, 12325, 12329, 12333, 12337,
12341, 12345, 12349, 12353, 12357, 12361, 12365, 12369, 12373, 12377,
12381, 12385, 12389, 12393, 12397, 12401, 12405, 12409, 12413, 12417,
12421, 12425, 12429, 12433, 12437, 12441, 12445, 12449, 12453, 12457,
12461, 12465, 12469, 12473, 12477, 12481, 12485, 12489, 12493, 12497,
12501, 12505, 12509, 12513, 12517, 12521, 12525, 12529, 12533, 12537,
12541, 12545, 12549, 12553, 12557, 12561, 12565, 12569, 12573, 12577,
12581, 12585, 12589, 12593, 12597, 12601, 12605, 12609, 12613, 12617,
12621, 12625, 12629, 12633, 12637, 12641, 12645, 12649, 12653, 12657,
12661, 12665, 12669, 12673, 12677, 12681, 12685, 12689, 12693, 12697,
12701, 12705, 12709, 12713, 12717, 12721, 12725, 12729, 12733, 12737,
12741, 12745, 12749, 12753, 12756, 12756, 12756, 12756, 12756, 12756,
12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756,
12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756,
12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756,
12756, 12756, 12756, 12756, 12756, 12756, 12757},
{12757, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760,
12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760,
12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760,
12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760,
12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760,
12760, 12760, 12760, 12760, 12761, 12764, 12765, 12769, 12773, 12776,
12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776,
12776, 12776, 12776, 12776, 12776, 12776, 12776, 12784, 12784, 12792,
12792, 12800, 12800, 12808, 12808, 12816, 12816, 12824, 12824, 12832,
12832, 12840, 12840, 12848, 12848, 12856, 12856, 12864, 12864, 12872,
12872, 12872, 12880, 12880, 12888, 12888, 12896, 12896, 12896, 12896,
12896, 12896, 12896, 12904, 12912, 12912, 12920, 12928, 12928, 12936,
12944, 12944, 12952, 12960, 12960, 12968, 12976, 12976, 12976, 12976,
12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976,
12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12984,
12984, 12984, 12984, 12984, 12984, 12985, 12993, 13000, 13000, 13009,
13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016,
13016, 13016, 13016, 13024, 13024, 13032, 13032, 13040, 13040, 13048,
13048, 13056, 13056, 13064, 13064, 13072, 13072, 13080, 13080, 13088,
13088, 13096, 13096, 13104, 13104, 13112, 13112, 13112, 13120, 13120,
13128, 13128, 13136, 13136, 13136, 13136, 13136, 13136, 13136, 13144,
13152, 13152, 13160, 13168, 13168, 13176, 13184, 13184, 13192, 13200,
13200, 13208, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216,
13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216,
13216, 13216, 13216, 13216, 13216, 13224, 13224, 13224, 13232, 13240,
13248, 13256, 13256, 13256, 13256, 13265, 13272},
{13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272,
13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272,
13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272,
13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272,
13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13273,
13277, 13281, 13285, 13289, 13293, 13297, 13301, 13305, 13309, 13313,
13317, 13321, 13325, 13329, 13333, 13337, 13341, 13345, 13349, 13353,
13357, 13361, 13365, 13369, 13373, 13377, 13381, 13385, 13389, 13393,
13397, 13401, 13405, 13409, 13413, 13417, 13421, 13425, 13429, 13433,
13437, 13441, 13445, 13449, 13453, 13457, 13461, 13465, 13469, 13473,
13477, 13481, 13485, 13489, 13493, 13497, 13501, 13505, 13509, 13513,
13517, 13521, 13525, 13529, 13533, 13537, 13541, 13545, 13549, 13553,
13557, 13561, 13565, 13569, 13573, 13577, 13581, 13585, 13589, 13593,
13597, 13601, 13605, 13609, 13613, 13617, 13621, 13625, 13629, 13633,
13637, 13641, 13645, 13648, 13648, 13648, 13649, 13653, 13657, 13661,
13665, 13669, 13673, 13677, 13681, 13685, 13689, 13693, 13697, 13701,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704,
13704, 13704, 13704, 13704, 13704, 13704, 13705},
{13705, 13717, 13729, 13741, 13753, 13765, 13777, 13789, 13801, 13813,
13825, 13837, 13849, 13861, 13873, 13889, 13905, 13921, 13937, 13953,
13969, 13985, 14001, 14017, 14033, 14049, 14065, 14081, 14097, 14113,
14141, 14164, 14165, 14177, 14189, 14201, 14213, 14225, 14237, 14249,
14261, 14273, 14285, 14297, 14309, 14321, 14333, 14345, 14357, 14369,
14381, 14393, 14405, 14417, 14429, 14441, 14453, 14465, 14477, 14489,
14501, 14513, 14525, 14537, 14549, 14561, 14573, 14585, 14597, 14601,
14605, 14609, 14612, 14612, 14612, 14612, 14612, 14612, 14612, 14612,
14613, 14625, 14633, 14641, 14649, 14657, 14665, 14673, 14681, 14689,
14697, 14705, 14713, 14721, 14729, 14737, 14745, 14749, 14753, 14757,
14761, 14765, 14769, 14773, 14777, 14781, 14785, 14789, 14793, 14797,
14801, 14809, 14817, 14825, 14833, 14841, 14849, 14857, 14865, 14873,
14881, 14889, 14897, 14905, 14913, 14933, 14949, 14956, 14957, 14961,
14965, 14969, 14973, 14977, 14981, 14985, 14989, 14993, 14997, 15001,
15005, 15009, 15013, 15017, 15021, 15025, 15029, 15033, 15037, 15041,
15045, 15049, 15053, 15057, 15061, 15065, 15069, 15073, 15077, 15081,
15085, 15089, 15093, 15097, 15101, 15105, 15109, 15113, 15117, 15121,
15125, 15129, 15133, 15137, 15141, 15145, 15149, 15153, 15161, 15169,
15177, 15185, 15193, 15201, 15209, 15217, 15225, 15233, 15241, 15249,
15257, 15265, 15273, 15281, 15289, 15297, 15305, 15313, 15321, 15329,
15337, 15345, 15357, 15369, 15381, 15389, 15401, 15409, 15421, 15425,
15429, 15433, 15437, 15441, 15445, 15449, 15453, 15457, 15461, 15465,
15469, 15473, 15477, 15481, 15485, 15489, 15493, 15497, 15501, 15505,
15509, 15513, 15517, 15521, 15525, 15529, 15533, 15537, 15541, 15545,
15549, 15553, 15557, 15561, 15565, 15569, 15573, 15577, 15581, 15585,
15589, 15593, 15597, 15601, 15605, 15609, 15617},
{15617, 15637, 15653, 15673, 15685, 15705, 15717, 15729, 15753, 15769,
15781, 15793, 15805, 15821, 15837, 15853, 15869, 15885, 15901, 15917,
15941, 15949, 15973, 15997, 16017, 16033, 16057, 16081, 16097, 16109,
16121, 16137, 16153, 16173, 16193, 16205, 16217, 16233, 16245, 16257,
16265, 16273, 16285, 16297, 16321, 16337, 16357, 16381, 16397, 16409,
16421, 16445, 16461, 16485, 16497, 16517, 16529, 16545, 16557, 16573,
16593, 16609, 16629, 16645, 16653, 16673, 16685, 16697, 16713, 16725,
16737, 16749, 16769, 16785, 16793, 16817, 16829, 16849, 16865, 16881,
16893, 16905, 16921, 16929, 16945, 16965, 16973, 16997, 17009, 17017,
17025, 17033, 17041, 17049, 17057, 17065, 17073, 17081, 17089, 17101,
17113, 17125, 17137, 17149, 17161, 17173, 17185, 17197, 17209, 17221,
17233, 17245, 17257, 17269, 17281, 17289, 17297, 17309, 17317, 17325,
17333, 17345, 17357, 17365, 17373, 17381, 17389, 17397, 17413, 17421,
17429, 17437, 17445, 17453, 17461, 17469, 17477, 17489, 17505, 17513,
17521, 17529, 17537, 17545, 17553, 17561, 17573, 17585, 17597, 17609,
17617, 17625, 17633, 17641, 17649, 17657, 17665, 17673, 17681, 17689,
17701, 17713, 17721, 17733, 17745, 17757, 17765, 17777, 17789, 17805,
17813, 17825, 17837, 17849, 17861, 17881, 17905, 17913, 17921, 17929,
17937, 17945, 17953, 17961, 17969, 17977, 17985, 17993, 18001, 18009,
18017, 18025, 18033, 18041, 18049, 18065, 18073, 18081, 18089, 18105,
18117, 18125, 18133, 18141, 18149, 18157, 18165, 18173, 18181, 18189,
18197, 18209, 18217, 18225, 18237, 18249, 18257, 18273, 18285, 18293,
18301, 18309, 18317, 18329, 18341, 18349, 18357, 18365, 18373, 18381,
18389, 18397, 18405, 18413, 18425, 18437, 18449, 18461, 18473, 18485,
18497, 18509, 18521, 18533, 18545, 18557, 18569, 18581, 18593, 18605,
18617, 18629, 18641, 18653, 18665, 18677, 18688},
{18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688,
18688, 18688, 18688, 18688, 18688, 18688, 18689, 18693, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696},
{18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696,
18696, 18696, 18697, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700,
18700, 18700, 18701, 18705, 18709, 18712, 18712, 18712, 18713, 18717,
18720, 18720, 18720, 18720, 18720, 18720, 18720},
{18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720,
18720, 18720, 18721, 18725, 18729, 18733, 18736, 18736, 18736, 18736,
18736, 18736, 18736, 18736, 18736, 18737, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740,
18740, 18740, 18740, 18740, 18740, 18740, 18740},
{18740, 18744, 18748, 18752, 18756, 18760, 18764, 18768, 18772, 18776,
18780, 18784, 18788, 18792, 18796, 18800, 18804, 18808, 18812, 18816,
18820, 18824, 18828, 18832, 18836, 18840, 18844, 18848, 18852, 18856,
18860, 18864, 18868, 18872, 18876, 18880, 18884, 18888, 18892, 18896,
18900, 18904, 18908, 18912, 18916, 18920, 18924, 18928, 18932, 18936,
18940, 18944, 18948, 18952, 18956, 18960, 18964, 18968, 18972, 18976,
18980, 18984, 18988, 18992, 18996, 19000, 19004, 19008, 19012, 19016,
19020, 19024, 19028, 19032, 19036, 19040, 19044, 19048, 19052, 19056,
19060, 19064, 19068, 19072, 19076, 19080, 19084, 19088, 19092, 19096,
19100, 19104, 19108, 19112, 19116, 19120, 19124, 19128, 19132, 19136,
19140, 19144, 19148, 19152, 19156, 19160, 19164, 19168, 19172, 19176,
19180, 19184, 19188, 19192, 19196, 19200, 19204, 19208, 19212, 19216,
19220, 19224, 19228, 19232, 19236, 19240, 19244, 19248, 19252, 19256,
19260, 19264, 19268, 19272, 19276, 19280, 19284, 19288, 19292, 19296,
19300, 19304, 19308, 19312, 19316, 19320, 19324, 19328, 19332, 19336,
19340, 19344, 19348, 19352, 19356, 19360, 19364, 19368, 19372, 19376,
19380, 19384, 19388, 19392, 19396, 19400, 19404, 19408, 19412, 19416,
19420, 19424, 19428, 19432, 19436, 19440, 19444, 19448, 19452, 19456,
19460, 19464, 19468, 19472, 19476, 19480, 19484, 19488, 19492, 19496,
19500, 19504, 19508, 19512, 19516, 19520, 19524, 19528, 19532, 19536,
19540, 19544, 19548, 19552, 19556, 19560, 19564, 19568, 19572, 19576,
19580, 19584, 19588, 19592, 19596, 19600, 19604, 19608, 19612, 19616,
19620, 19624, 19628, 19632, 19636, 19640, 19644, 19648, 19652, 19656,
19660, 19664, 19668, 19672, 19676, 19680, 19684, 19688, 19692, 19696,
19700, 19704, 19708, 19712, 19716, 19720, 19724, 19728, 19732, 19736,
19740, 19744, 19748, 19752, 19756, 19760, 19764},
{19764, 19768, 19772, 19776, 19780, 19784, 19788, 19792, 19796, 19800,
19804, 19808, 19812, 19816, 19820, 19820, 19820, 19824, 19824, 19828,
19828, 19828, 19832, 19836, 19840, 19844, 19848, 19852, 19856, 19860,
19864, 19868, 19868, 19872, 19872, 19876, 19876, 19876, 19880, 19884,
19884, 19884, 19884, 19888, 19892, 19896, 19900, 19904, 19908, 19912,
19916, 19920, 19924, 19928, 19932, 19936, 19940, 19944, 19948, 19952,
19956, 19960, 19964, 19968, 19972, 19976, 19980, 19984, 19988, 19992,
19996, 20000, 20004, 20008, 20012, 20016, 20020, 20024, 20028, 20032,
20036, 20040, 20044, 20048, 20052, 20056, 20060, 20064, 20068, 20072,
20076, 20080, 20084, 20088, 20092, 20096, 20100, 20104, 20108, 20112,
20116, 20120, 20124, 20128, 20132, 20136, 20140, 20144, 20148, 20152,
20156, 20156, 20156, 20160, 20164, 20168, 20172, 20176, 20180, 20184,
20188, 20192, 20196, 20200, 20204, 20208, 20212, 20216, 20220, 20224,
20228, 20232, 20236, 20240, 20244, 20248, 20252, 20256, 20260, 20264,
20268, 20272, 20276, 20280, 20284, 20288, 20292, 20296, 20300, 20304,
20308, 20312, 20316, 20320, 20324, 20328, 20332, 20336, 20340, 20344,
20348, 20352, 20356, 20360, 20364, 20368, 20372, 20376, 20380, 20384,
20388, 20392, 20396, 20400, 20404, 20408, 20412, 20416, 20420, 20424,
20428, 20432, 20436, 20440, 20444, 20448, 20452, 20456, 20460, 20464,
20468, 20472, 20476, 20480, 20484, 20488, 20492, 20496, 20500, 20504,
20508, 20512, 20516, 20520, 20524, 20528, 20532, 20536, 20540, 20544,
20548, 20552, 20556, 20560, 20564, 20568, 20572, 20576, 20580, 20580,
20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580,
20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580,
20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580,
20580, 20580, 20580, 20580, 20580, 20580, 20581},
{20581, 20589, 20597, 20605, 20617, 20629, 20637, 20644, 20644, 20644,
20644, 20644, 20644, 20644, 20644, 20644, 20644, 20644, 20644, 20645,
20653, 20661, 20669, 20677, 20684, 20684, 20684, 20684, 20684, 20684,
20692, 20692, 20701, 20705, 20709, 20713, 20717, 20721, 20725, 20729,
20733, 20737, 20740, 20748, 20756, 20768, 20780, 20788, 20796, 20804,
20812, 20820, 20828, 20836, 20844, 20852, 20852, 20860, 20868, 20876,
20884, 20892, 20892, 20900, 20900, 20908, 20916, 20916, 20924, 20932,
20932, 20940, 20948, 20956, 20964, 20972, 20980, 20988, 20996, 21005,
21013, 21017, 21021, 21025, 21029, 21033, 21037, 21041, 21045, 21049,
21053, 21057, 21061, 21065, 21069, 21073, 21077, 21081, 21085, 21089,
21093, 21097, 21101, 21105, 21109, 21113, 21117, 21121, 21125, 21129,
21133, 21137, 21141, 21145, 21149, 21153, 21157, 21161, 21165, 21169,
21173, 21177, 21181, 21185, 21189, 21193, 21197, 21201, 21205, 21209,
21213, 21217, 21221, 21225, 21229, 21233, 21237, 21241, 21245, 21249,
21253, 21257, 21261, 21265, 21269, 21273, 21277, 21281, 21285, 21289,
21293, 21297, 21301, 21305, 21309, 21313, 21317, 21321, 21325, 21329,
21333, 21337, 21341, 21345, 21349, 21357, 21365, 21369, 21373, 21377,
21381, 21385, 21389, 21393, 21397, 21401, 21405, 21413, 21420, 21420,
21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420,
21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420,
21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420,
21420, 21421, 21425, 21429, 21433, 21437, 21441, 21445, 21449, 21453,
21457, 21461, 21469, 21473, 21477, 21481, 21485, 21489, 21493, 21497,
21501, 21505, 21509, 21513, 21517, 21529, 21541, 21553, 21565, 21577,
21589, 21601, 21613, 21625, 21637, 21649, 21661, 21673, 21685, 21697,
21709, 21721, 21733, 21737, 21741, 21745, 21749},
{21749, 21761, 21773, 21785, 21797, 21809, 21817, 21825, 21833, 21841,
21849, 21857, 21865, 21873, 21881, 21889, 21897, 21905, 21913, 21921,
21929, 21937, 21945, 21953, 21961, 21969, 21977, 21985, 21993, 22001,
22009, 22017, 22025, 22033, 22041, 22049, 22057, 22065, 22073, 22081,
22089, 22097, 22105, 22113, 22121, 22129, 22137, 22145, 22153, 22161,
22169, 22177, 22185, 22193, 22201, 22209, 22217, 22225, 22233, 22241,
22249, 22257, 22265, 22273, 22281, 22289, 22297, 22305, 22313, 22321,
22329, 22337, 22345, 22353, 22361, 22369, 22377, 22385, 22393, 22401,
22409, 22417, 22425, 22433, 22441, 22449, 22457, 22465, 22473, 22481,
22489, 22497, 22505, 22513, 22521, 22533, 22545, 22557, 22569, 22581,
22593, 22605, 22617, 22629, 22641, 22653, 22665, 22673, 22681, 22689,
22697, 22705, 22713, 22721, 22729, 22737, 22745, 22753, 22761, 22769,
22777, 22785, 22793, 22801, 22809, 22817, 22825, 22833, 22841, 22849,
22857, 22865, 22873, 22881, 22889, 22897, 22905, 22913, 22921, 22929,
22937, 22945, 22953, 22961, 22969, 22977, 22985, 22993, 23001, 23009,
23017, 23025, 23037, 23049, 23061, 23073, 23085, 23093, 23101, 23109,
23117, 23125, 23133, 23141, 23149, 23157, 23165, 23173, 23181, 23189,
23197, 23205, 23213, 23221, 23229, 23237, 23245, 23253, 23261, 23269,
23277, 23285, 23293, 23301, 23309, 23317, 23325, 23333, 23341, 23349,
23357, 23365, 23373, 23381, 23389, 23397, 23405, 23413, 23421, 23429,
23437, 23445, 23453, 23461, 23469, 23477, 23485, 23493, 23501, 23509,
23517, 23525, 23533, 23541, 23549, 23557, 23565, 23573, 23581, 23589,
23597, 23605, 23613, 23621, 23633, 23645, 23653, 23661, 23669, 23677,
23685, 23693, 23701, 23709, 23717, 23725, 23733, 23741, 23749, 23757,
23765, 23773, 23781, 23793, 23805, 23817, 23825, 23833, 23841, 23849,
23857, 23865, 23873, 23881, 23889, 23897, 23905},
{23905, 23913, 23921, 23929, 23937, 23945, 23953, 23961, 23969, 23977,
23985, 23993, 24001, 24009, 24017, 24025, 24033, 24041, 24049, 24057,
24065, 24073, 24081, 24089, 24097, 24105, 24113, 24121, 24129, 24137,
24145, 24153, 24161, 24169, 24177, 24185, 24193, 24201, 24209, 24217,
24225, 24233, 24241, 24249, 24257, 24265, 24273, 24281, 24289, 24297,
24305, 24313, 24321, 24329, 24337, 24345, 24353, 24361, 24369, 24377,
24385, 24393, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400,
24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400,
24401, 24413, 24425, 24437, 24449, 24461, 24473, 24485, 24497, 24509,
24521, 24533, 24545, 24557, 24569, 24581, 24593, 24605, 24617, 24629,
24641, 24653, 24665, 24677, 24689, 24701, 24713, 24725, 24737, 24749,
24761, 24773, 24785, 24797, 24809, 24821, 24833, 24845, 24857, 24869,
24881, 24893, 24905, 24917, 24929, 24941, 24953, 24965, 24977, 24989,
25001, 25013, 25025, 25037, 25049, 25061, 25073, 25085, 25097, 25109,
25121, 25133, 25145, 25157, 25168, 25168, 25169, 25181, 25193, 25205,
25217, 25229, 25241, 25253, 25265, 25277, 25289, 25301, 25313, 25325,
25337, 25349, 25361, 25373, 25385, 25397, 25409, 25421, 25433, 25445,
25457, 25469, 25481, 25493, 25505, 25517, 25529, 25541, 25553, 25565,
25577, 25589, 25601, 25613, 25625, 25637, 25649, 25661, 25673, 25685,
25697, 25709, 25721, 25733, 25745, 25757, 25769, 25781, 25793, 25805,
25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816,
25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816,
25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816,
25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816,
25817, 25829, 25841, 25857, 25873, 25889, 25905, 25921, 25937, 25953,
25965, 26037, 26069, 26084, 26084, 26084, 26084},
{26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084,
26084, 26084, 26084, 26084, 26084, 26084, 26085, 26089, 26093, 26097,
26101, 26105, 26109, 26113, 26117, 26121, 26132, 26132, 26132, 26132,
26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132,
26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26133, 26141,
26145, 26149, 26153, 26157, 26161, 26165, 26169, 26173, 26177, 26181,
26185, 26189, 26193, 26197, 26201, 26205, 26209, 26213, 26217, 26220,
26220, 26221, 26225, 26229, 26237, 26245, 26253, 26261, 26265, 26269,
26273, 26277, 26281, 26284, 26285, 26289, 26293, 26297, 26301, 26305,
26309, 26313, 26317, 26321, 26325, 26329, 26333, 26337, 26341, 26345,
26349, 26353, 26357, 26360, 26361, 26365, 26369, 26373, 26376, 26376,
26376, 26376, 26377, 26385, 26393, 26400, 26401, 26408, 26409, 26417,
26425, 26433, 26441, 26449, 26457, 26465, 26473, 26481, 26489, 26493,
26501, 26509, 26517, 26525, 26533, 26541, 26549, 26557, 26565, 26573,
26581, 26589, 26593, 26597, 26601, 26605, 26609, 26613, 26617, 26621,
26625, 26629, 26633, 26637, 26641, 26645, 26649, 26653, 26657, 26661,
26665, 26669, 26673, 26677, 26681, 26685, 26689, 26693, 26697, 26701,
26705, 26709, 26713, 26717, 26721, 26725, 26729, 26733, 26737, 26741,
26745, 26749, 26753, 26757, 26761, 26765, 26769, 26773, 26777, 26781,
26785, 26789, 26793, 26797, 26801, 26805, 26809, 26813, 26817, 26821,
26825, 26829, 26833, 26837, 26841, 26845, 26849, 26853, 26857, 26861,
26865, 26869, 26873, 26877, 26881, 26885, 26889, 26893, 26897, 26901,
26905, 26909, 26913, 26917, 26921, 26925, 26929, 26933, 26937, 26941,
26945, 26949, 26953, 26957, 26961, 26965, 26969, 26973, 26977, 26981,
26985, 26989, 26993, 26997, 27001, 27005, 27017, 27029, 27041, 27053,
27065, 27077, 27085, 27092, 27092, 27092, 27092},
{27092, 27093, 27097, 27101, 27105, 27109, 27113, 27117, 27121, 27125,
27129, 27133, 27137, 27141, 27145, 27149, 27153, 27157, 27161, 27165,
27169, 27173, 27177, 27181, 27185, 27189, 27193, 27197, 27201, 27205,
27209, 27213, 27217, 27221, 27225, 27229, 27233, 27237, 27241, 27245,
27249, 27253, 27257, 27261, 27265, 27269, 27273, 27277, 27281, 27285,
27289, 27293, 27297, 27301, 27305, 27309, 27313, 27317, 27321, 27325,
27329, 27333, 27337, 27341, 27345, 27349, 27353, 27357, 27361, 27365,
27369, 27373, 27377, 27381, 27385, 27389, 27393, 27397, 27401, 27405,
27409, 27413, 27417, 27421, 27425, 27429, 27433, 27437, 27441, 27445,
27449, 27453, 27457, 27461, 27465, 27469, 27473, 27477, 27481, 27485,
27489, 27493, 27497, 27501, 27505, 27509, 27513, 27517, 27521, 27525,
27529, 27533, 27537, 27541, 27545, 27549, 27553, 27557, 27561, 27565,
27569, 27573, 27577, 27581, 27585, 27589, 27593, 27597, 27601, 27605,
27609, 27613, 27617, 27621, 27625, 27629, 27633, 27637, 27641, 27645,
27649, 27653, 27657, 27661, 27665, 27669, 27673, 27677, 27681, 27685,
27689, 27693, 27697, 27701, 27705, 27709, 27713, 27717, 27721, 27725,
27729, 27733, 27737, 27741, 27745, 27749, 27753, 27757, 27761, 27765,
27769, 27773, 27777, 27781, 27785, 27789, 27793, 27797, 27801, 27805,
27809, 27813, 27817, 27821, 27825, 27829, 27833, 27837, 27841, 27845,
27849, 27852, 27852, 27852, 27853, 27857, 27861, 27865, 27869, 27873,
27876, 27876, 27877, 27881, 27885, 27889, 27893, 27897, 27900, 27900,
27901, 27905, 27909, 27913, 27917, 27921, 27924, 27924, 27925, 27929,
27933, 27936, 27936, 27936, 27937, 27941, 27945, 27949, 27957, 27961,
27965, 27968, 27969, 27973, 27977, 27981, 27985, 27989, 27993, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996},
{27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996,
27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27997,
28001, 28005, 28009, 28013, 28016, 28017, 28021, 28025, 28029, 28033,
28037, 28041, 28045, 28049, 28053, 28057, 28061, 28065, 28069, 28073,
28077, 28081, 28085, 28089, 28093, 28097, 28101, 28105, 28109, 28113,
28117, 28121, 28125, 28129, 28133, 28137, 28141, 28145, 28149, 28153,
28157, 28161, 28165, 28169, 28173, 28177, 28181, 28184, 28185, 28189,
28193, 28197, 28201, 28205, 28209, 28213, 28217, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220},
{28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220,
28220, 28220, 28220, 28220, 28220, 28228, 28228, 28236, 28236, 28236,
28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236,
28236, 28236, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244},
{28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244,
28244, 28244, 28244, 28244, 28244, 28244, 28244, 28252, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260},
{28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260,
28260, 28260, 28260, 28260, 28260, 28260, 28268, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276},
{28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276,
28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28284, 28292,
28292, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300},
{28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300,
28300, 28300, 28300, 28300, 28300, 28300, 28300, 28308, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316},
{28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316,
28316, 28316, 28316, 28316, 28316, 28316, 28316, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324},
{28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324,
28324, 28324, 28324, 28324, 28324, 28332, 28340, 28352, 28364, 28376,
28388, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400,
28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28408, 28416,
28428, 28440, 28452, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464},
{28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464,
28464, 28464, 28464, 28464, 28464, 28464, 28465},
{28465, 28469, 28473, 28477, 28481, 28485, 28489, 28493, 28497, 28501,
28505, 28509, 28513, 28517, 28521, 28525, 28529, 28533, 28537, 28541,
28545, 28549, 28553, 28557, 28561, 28565, 28569, 28573, 28577, 28581,
28585, 28589, 28593, 28597, 28601, 28605, 28609, 28613, 28617, 28621,
28625, 28629, 28633, 28637, 28641, 28645, 28649, 28653, 28657, 28661,
28665, 28669, 28673, 28677, 28681, 28685, 28689, 28693, 28697, 28701,
28705, 28709, 28713, 28717, 28721, 28725, 28729, 28733, 28737, 28741,
28745, 28749, 28753, 28757, 28761, 28765, 28769, 28773, 28777, 28781,
28785, 28789, 28793, 28797, 28801, 28804, 28805, 28809, 28813, 28817,
28821, 28825, 28829, 28833, 28837, 28841, 28845, 28849, 28853, 28857,
28861, 28865, 28869, 28873, 28877, 28881, 28885, 28889, 28893, 28897,
28901, 28905, 28909, 28913, 28917, 28921, 28925, 28929, 28933, 28937,
28941, 28945, 28949, 28953, 28957, 28961, 28965, 28969, 28973, 28977,
28981, 28985, 28989, 28993, 28997, 29001, 29005, 29009, 29013, 29017,
29021, 29025, 29029, 29033, 29037, 29041, 29045, 29049, 29053, 29057,
29061, 29065, 29069, 29073, 29077, 29081, 29085, 29088, 29089, 29093,
29096, 29096, 29097, 29100, 29100, 29101, 29105, 29108, 29108, 29109,
29113, 29117, 29121, 29124, 29125, 29129, 29133, 29137, 29141, 29145,
29149, 29153, 29157, 29161, 29165, 29169, 29172, 29173, 29176, 29177,
29181, 29185, 29189, 29193, 29197, 29201, 29204, 29205, 29209, 29213,
29217, 29221, 29225, 29229, 29233, 29237, 29241, 29245, 29249, 29253,
29257, 29261, 29265, 29269, 29273, 29277, 29281, 29285, 29289, 29293,
29297, 29301, 29305, 29309, 29313, 29317, 29321, 29325, 29329, 29333,
29337, 29341, 29345, 29349, 29353, 29357, 29361, 29365, 29369, 29373,
29377, 29381, 29385, 29389, 29393, 29397, 29401, 29405, 29409, 29413,
29417, 29421, 29425, 29429, 29433, 29437, 29441},
{29441, 29445, 29449, 29453, 29457, 29461, 29464, 29465, 29469, 29473,
29477, 29480, 29480, 29481, 29485, 29489, 29493, 29497, 29501, 29505,
29509, 29512, 29513, 29517, 29521, 29525, 29529, 29533, 29537, 29540,
29541, 29545, 29549, 29553, 29557, 29561, 29565, 29569, 29573, 29577,
29581, 29585, 29589, 29593, 29597, 29601, 29605, 29609, 29613, 29617,
29621, 29625, 29629, 29633, 29637, 29641, 29645, 29649, 29652, 29653,
29657, 29661, 29665, 29668, 29669, 29673, 29677, 29681, 29685, 29688,
29689, 29692, 29692, 29692, 29693, 29697, 29701, 29705, 29709, 29713,
29717, 29720, 29721, 29725, 29729, 29733, 29737, 29741, 29745, 29749,
29753, 29757, 29761, 29765, 29769, 29773, 29777, 29781, 29785, 29789,
29793, 29797, 29801, 29805, 29809, 29813, 29817, 29821, 29825, 29829,
29833, 29837, 29841, 29845, 29849, 29853, 29857, 29861, 29865, 29869,
29873, 29877, 29881, 29885, 29889, 29893, 29897, 29901, 29905, 29909,
29913, 29917, 29921, 29925, 29929, 29933, 29937, 29941, 29945, 29949,
29953, 29957, 29961, 29965, 29969, 29973, 29977, 29981, 29985, 29989,
29993, 29997, 30001, 30005, 30009, 30013, 30017, 30021, 30025, 30029,
30033, 30037, 30041, 30045, 30049, 30053, 30057, 30061, 30065, 30069,
30073, 30077, 30081, 30085, 30089, 30093, 30097, 30101, 30105, 30109,
30113, 30117, 30121, 30125, 30129, 30133, 30137, 30141, 30145, 30149,
30153, 30157, 30161, 30165, 30169, 30173, 30177, 30181, 30185, 30189,
30193, 30197, 30201, 30205, 30209, 30213, 30217, 30221, 30225, 30229,
30233, 30237, 30241, 30245, 30249, 30253, 30257, 30261, 30265, 30269,
30273, 30277, 30281, 30285, 30289, 30293, 30297, 30301, 30305, 30309,
30313, 30317, 30321, 30325, 30329, 30333, 30337, 30341, 30345, 30349,
30353, 30357, 30361, 30365, 30369, 30373, 30377, 30381, 30385, 30389,
30393, 30397, 30401, 30405, 30409, 30413, 30417},
{30417, 30421, 30425, 30429, 30433, 30437, 30441, 30445, 30449, 30453,
30457, 30461, 30465, 30469, 30473, 30477, 30481, 30485, 30489, 30493,
30497, 30501, 30505, 30509, 30513, 30517, 30521, 30525, 30529, 30533,
30537, 30541, 30545, 30549, 30553, 30557, 30561, 30565, 30569, 30573,
30577, 30581, 30585, 30589, 30593, 30597, 30601, 30605, 30609, 30613,
30617, 30621, 30625, 30629, 30633, 30637, 30641, 30645, 30649, 30653,
30657, 30661, 30665, 30669, 30673, 30677, 30681, 30685, 30689, 30693,
30697, 30701, 30705, 30709, 30713, 30717, 30721, 30725, 30729, 30733,
30737, 30741, 30745, 30749, 30753, 30757, 30761, 30765, 30769, 30773,
30777, 30781, 30785, 30789, 30793, 30797, 30801, 30805, 30809, 30813,
30817, 30821, 30825, 30829, 30833, 30837, 30841, 30845, 30849, 30853,
30857, 30861, 30865, 30869, 30873, 30877, 30881, 30885, 30889, 30893,
30897, 30901, 30905, 30909, 30913, 30917, 30921, 30925, 30929, 30933,
30937, 30941, 30945, 30949, 30953, 30957, 30961, 30965, 30969, 30973,
30977, 30981, 30985, 30989, 30993, 30997, 31001, 31005, 31009, 31013,
31017, 31021, 31025, 31029, 31033, 31037, 31041, 31045, 31049, 31053,
31057, 31061, 31065, 31069, 31073, 31077, 31080, 31080, 31081, 31085,
31089, 31093, 31097, 31101, 31105, 31109, 31113, 31117, 31121, 31125,
31129, 31133, 31137, 31141, 31145, 31149, 31153, 31157, 31161, 31165,
31169, 31173, 31177, 31181, 31185, 31189, 31193, 31197, 31201, 31205,
31209, 31213, 31217, 31221, 31225, 31229, 31233, 31237, 31241, 31245,
31249, 31253, 31257, 31261, 31265, 31269, 31273, 31277, 31281, 31285,
31289, 31293, 31297, 31301, 31305, 31309, 31313, 31317, 31321, 31325,
31329, 31333, 31337, 31341, 31345, 31349, 31353, 31357, 31361, 31365,
31369, 31373, 31377, 31381, 31385, 31389, 31393, 31397, 31401, 31405,
31409, 31413, 31417, 31421, 31425, 31429, 31433},
{31433, 31437, 31441, 31445, 31449, 31453, 31457, 31461, 31465, 31469,
31473, 31477, 31481, 31485, 31489, 31493, 31497, 31501, 31505, 31509,
31513, 31517, 31521, 31525, 31529, 31533, 31537, 31541, 31545, 31549,
31553, 31557, 31561, 31565, 31569, 31573, 31577, 31581, 31585, 31589,
31593, 31597, 31601, 31605, 31609, 31613, 31617, 31621, 31625, 31629,
31633, 31637, 31641, 31645, 31649, 31653, 31657, 31661, 31665, 31669,
31673, 31677, 31681, 31685, 31689, 31693, 31697, 31701, 31705, 31709,
31713, 31717, 31721, 31725, 31729, 31733, 31737, 31741, 31745, 31749,
31753, 31757, 31761, 31765, 31769, 31773, 31777, 31781, 31785, 31789,
31793, 31797, 31801, 31805, 31809, 31813, 31817, 31821, 31825, 31829,
31833, 31837, 31841, 31845, 31849, 31853, 31857, 31861, 31865, 31869,
31873, 31877, 31881, 31885, 31889, 31893, 31897, 31901, 31905, 31909,
31913, 31917, 31921, 31925, 31929, 31933, 31937, 31941, 31945, 31949,
31953, 31957, 31961, 31965, 31969, 31973, 31977, 31981, 31985, 31989,
31993, 31997, 32001, 32005, 32009, 32013, 32017, 32021, 32025, 32029,
32033, 32037, 32041, 32045, 32049, 32053, 32057, 32061, 32065, 32069,
32073, 32077, 32081, 32085, 32089, 32093, 32097, 32101, 32105, 32109,
32113, 32117, 32121, 32125, 32129, 32133, 32137, 32141, 32145, 32149,
32153, 32157, 32161, 32165, 32169, 32173, 32177, 32181, 32185, 32189,
32193, 32197, 32201, 32205, 32209, 32213, 32217, 32221, 32225, 32229,
32233, 32237, 32241, 32245, 32248, 32248, 32249, 32253, 32257, 32261,
32265, 32269, 32273, 32277, 32281, 32285, 32289, 32293, 32297, 32301,
32305, 32309, 32313, 32317, 32321, 32325, 32329, 32333, 32337, 32341,
32345, 32349, 32353, 32357, 32361, 32365, 32369, 32373, 32377, 32381,
32385, 32389, 32393, 32397, 32401, 32405, 32409, 32413, 32417, 32421,
32425, 32429, 32433, 32437, 32441, 32445, 32448},
{32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448,
32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448,
32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448,
32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448,
32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32449, 32453,
32457, 32461, 32465, 32469, 32473, 32477, 32481, 32485, 32489, 32493,
32497, 32501, 32505, 32509, 32513, 32517, 32521, 32525, 32529, 32533,
32537, 32541, 32545, 32549, 32553, 32557, 32561, 32565, 32569, 32573,
32577, 32581, 32585, 32589, 32593, 32597, 32601, 32605, 32609, 32613,
32617, 32621, 32625, 32629, 32633, 32637, 32641, 32645, 32649, 32653,
32657, 32661, 32665, 32669, 32673, 32677, 32681, 32685, 32689, 32693,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696},
{32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696,
32696, 32696, 32696, 32696, 32696, 32696, 32697},
{32697, 32701, 32705, 32709, 32712, 32713, 32717, 32721, 32725, 32729,
32733, 32737, 32741, 32745, 32749, 32753, 32757, 32761, 32765, 32769,
32773, 32777, 32781, 32785, 32789, 32793, 32797, 32801, 32805, 32809,
32813, 32817, 32820, 32821, 32825, 32828, 32829, 32832, 32832, 32833,
32836, 32837, 32841, 32845, 32849, 32853, 32857, 32861, 32865, 32869,
32873, 32876, 32877, 32881, 32885, 32889, 32892, 32893, 32896, 32897,
32900, 32900, 32900, 32900, 32900, 32900, 32901, 32904, 32904, 32904,
32904, 32905, 32908, 32909, 32912, 32913, 32916, 32917, 32921, 32925,
32928, 32929, 32933, 32936, 32937, 32940, 32940, 32941, 32944, 32945,
32948, 32949, 32952, 32953, 32956, 32957, 32960, 32961, 32965, 32968,
32969, 32972, 32972, 32973, 32977, 32981, 32985, 32988, 32989, 32993,
32997, 33001, 33005, 33009, 33013, 33016, 33017, 33021, 33025, 33029,
33032, 33033, 33037, 33041, 33045, 33048, 33049, 33052, 33053, 33057,
33061, 33065, 33069, 33073, 33077, 33081, 33085, 33089, 33092, 33093,
33097, 33101, 33105, 33109, 33113, 33117, 33121, 33125, 33129, 33133,
33137, 33141, 33145, 33149, 33153, 33157, 33160, 33160, 33160, 33160,
33160, 33161, 33165, 33169, 33172, 33173, 33177, 33181, 33185, 33189,
33192, 33193, 33197, 33201, 33205, 33209, 33213, 33217, 33221, 33225,
33229, 33233, 33237, 33241, 33245, 33249, 33253, 33257, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260},
{33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260,
33260, 33260, 33260, 33260, 33260, 33260, 33261},
{33261, 33269, 33277, 33285, 33293, 33301, 33309, 33317, 33325, 33333,
33341, 33348, 33348, 33348, 33348, 33348, 33349, 33361, 33373, 33385,
33397, 33409, 33421, 33433, 33445, 33457, 33469, 33481, 33493, 33505,
33517, 33529, 33541, 33553, 33565, 33577, 33589, 33601, 33613, 33625,
33637, 33649, 33661, 33673, 33677, 33681, 33689, 33696, 33697, 33701,
33705, 33709, 33713, 33717, 33721, 33725, 33729, 33733, 33737, 33741,
33745, 33749, 33753, 33757, 33761, 33765, 33769, 33773, 33777, 33781,
33785, 33789, 33793, 33797, 33801, 33809, 33817, 33825, 33833, 33845,
33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852,
33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852,
33852, 33852, 33852, 33852, 33852, 33852, 33853, 33861, 33869, 33876,
33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876,
33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876,
33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876,
33876, 33876, 33876, 33876, 33877, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884,
33884, 33884, 33884, 33884, 33884, 33884, 33885},
{33885, 33893, 33901, 33904, 33904, 33904, 33904, 33904, 33904, 33904,
33904, 33904, 33904, 33904, 33904, 33904, 33905, 33909, 33913, 33917,
33925, 33929, 33933, 33937, 33941, 33945, 33949, 33953, 33957, 33961,
33965, 33969, 33973, 33977, 33981, 33985, 33989, 33993, 33997, 34001,
34005, 34009, 34013, 34017, 34021, 34025, 34029, 34033, 34037, 34041,
34045, 34049, 34053, 34057, 34061, 34065, 34069, 34073, 34077, 34081,
34084, 34084, 34084, 34084, 34085, 34097, 34109, 34121, 34133, 34145,
34157, 34169, 34181, 34192, 34192, 34192, 34192, 34192, 34192, 34192,
34193, 34197, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200},
{34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200,
34201, 34205, 34209, 34213, 34217, 34221, 34225, 34229, 34233, 34237,
34240, 34240, 34240, 34240, 34240, 34240, 34240},
{34240, 34244, 34248, 34252, 34256, 34260, 34264, 34268, 34272, 34276,
34280, 34284, 34288, 34292, 34296, 34300, 34304, 34308, 34312, 34316,
34320, 34324, 34328, 34332, 34336, 34340, 34344, 34348, 34352, 34356,
34360, 34364, 34368, 34372, 34376, 34380, 34384, 34388, 34392, 34396,
34400, 34404, 34408, 34412, 34416, 34420, 34424, 34428, 34432, 34436,
34440, 34444, 34448, 34452, 34456, 34460, 34464, 34468, 34472, 34476,
34480, 34484, 34488, 34492, 34496, 34500, 34504, 34508, 34512, 34516,
34520, 34524, 34528, 34532, 34536, 34540, 34544, 34548, 34552, 34556,
34560, 34564, 34568, 34572, 34576, 34580, 34584, 34588, 34592, 34596,
34600, 34604, 34608, 34612, 34616, 34620, 34624, 34628, 34632, 34636,
34640, 34644, 34648, 34652, 34656, 34660, 34664, 34668, 34672, 34676,
34680, 34684, 34688, 34692, 34696, 34700, 34704, 34708, 34712, 34716,
34720, 34724, 34728, 34732, 34736, 34740, 34744, 34748, 34752, 34756,
34760, 34764, 34768, 34772, 34776, 34780, 34784, 34788, 34792, 34796,
34800, 34804, 34808, 34812, 34816, 34820, 34824, 34828, 34832, 34836,
34840, 34844, 34848, 34852, 34856, 34860, 34864, 34868, 34872, 34876,
34880, 34884, 34888, 34892, 34896, 34900, 34904, 34908, 34912, 34916,
34920, 34924, 34928, 34932, 34936, 34940, 34944, 34948, 34952, 34956,
34960, 34964, 34968, 34972, 34976, 34980, 34984, 34988, 34992, 34996,
35000, 35004, 35008, 35012, 35016, 35020, 35024, 35028, 35032, 35036,
35040, 35044, 35048, 35052, 35056, 35060, 35064, 35068, 35072, 35076,
35080, 35084, 35088, 35092, 35096, 35100, 35104, 35108, 35112, 35116,
35120, 35124, 35128, 35132, 35136, 35140, 35144, 35148, 35152, 35156,
35160, 35164, 35168, 35172, 35176, 35180, 35184, 35188, 35192, 35196,
35200, 35204, 35208, 35212, 35216, 35220, 35224, 35228, 35232, 35236,
35240, 35244, 35248, 35252, 35256, 35260, 35264},
{35264, 35268, 35272, 35276, 35280, 35284, 35288, 35292, 35296, 35300,
35304, 35308, 35312, 35316, 35320, 35324, 35328, 35332, 35336, 35340,
35344, 35348, 35352, 35356, 35360, 35364, 35368, 35372, 35376, 35380,
35384, 35388, 35392, 35396, 35400, 35404, 35408, 35412, 35416, 35420,
35424, 35428, 35432, 35436, 35440, 35444, 35448, 35452, 35456, 35460,
35464, 35468, 35472, 35476, 35480, 35484, 35488, 35492, 35496, 35500,
35504, 35508, 35512, 35516, 35520, 35524, 35528, 35532, 35536, 35540,
35544, 35548, 35552, 35556, 35560, 35564, 35568, 35572, 35576, 35580,
35584, 35588, 35592, 35596, 35600, 35604, 35608, 35612, 35616, 35620,
35624, 35628, 35632, 35636, 35640, 35644, 35648, 35652, 35656, 35660,
35664, 35668, 35672, 35676, 35680, 35684, 35688, 35692, 35696, 35700,
35704, 35708, 35712, 35716, 35720, 35724, 35728, 35732, 35736, 35740,
35744, 35748, 35752, 35756, 35760, 35764, 35768, 35772, 35776, 35780,
35784, 35788, 35792, 35796, 35800, 35804, 35808, 35812, 35816, 35820,
35824, 35828, 35832, 35836, 35840, 35844, 35848, 35852, 35856, 35860,
35864, 35868, 35872, 35876, 35880, 35884, 35888, 35892, 35896, 35900,
35904, 35908, 35912, 35916, 35920, 35924, 35928, 35932, 35936, 35940,
35944, 35948, 35952, 35956, 35960, 35964, 35968, 35972, 35976, 35980,
35984, 35988, 35992, 35996, 36000, 36004, 36008, 36012, 36016, 36020,
36024, 36028, 36032, 36036, 36040, 36044, 36048, 36052, 36056, 36060,
36064, 36068, 36072, 36076, 36080, 36084, 36088, 36092, 36096, 36100,
36104, 36108, 36112, 36116, 36120, 36124, 36128, 36132, 36136, 36140,
36144, 36148, 36152, 36156, 36160, 36164, 36168, 36172, 36176, 36180,
36184, 36188, 36192, 36196, 36200, 36204, 36208, 36212, 36216, 36220,
36224, 36228, 36232, 36236, 36240, 36244, 36248, 36252, 36256, 36260,
36264, 36268, 36272, 36276, 36280, 36284, 36288},
{36288, 36292, 36296, 36300, 36304, 36308, 36312, 36316, 36320, 36324,
36328, 36332, 36336, 36340, 36344, 36348, 36352, 36356, 36360, 36364,
36368, 36372, 36376, 36380, 36384, 36388, 36392, 36396, 36400, 36404,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408,
36408, 36408, 36408, 36408, 36408, 36408, 36408}};
const char32_t decomposition_data[9102] = {
0, 32, 32, 776, 97, 32, 772, 50, 51,
32, 769, 956, 32, 807, 49, 111, 49, 8260,
52, 49, 8260, 50, 51, 8260, 52, 65, 768,
65, 769, 65, 770, 65, 771, 65, 776, 65,
778, 67, 807, 69, 768, 69, 769, 69, 770,
69, 776, 73, 768, 73, 769, 73, 770, 73,
776, 78, 771, 79, 768, 79, 769, 79, 770,
79, 771, 79, 776, 85, 768, 85, 769, 85,
770, 85, 776, 89, 769, 97, 768, 97, 769,
97, 770, 97, 771, 97, 776, 97, 778, 99,
807, 101, 768, 101, 769, 101, 770, 101, 776,
105, 768, 105, 769, 105, 770, 105, 776, 110,
771, 111, 768, 111, 769, 111, 770, 111, 771,
111, 776, 117, 768, 117, 769, 117, 770, 117,
776, 121, 769, 121, 776, 65, 772, 97, 772,
65, 774, 97, 774, 65, 808, 97, 808, 67,
769, 99, 769, 67, 770, 99, 770, 67, 775,
99, 775, 67, 780, 99, 780, 68, 780, 100,
780, 69, 772, 101, 772, 69, 774, 101, 774,
69, 775, 101, 775, 69, 808, 101, 808, 69,
780, 101, 780, 71, 770, 103, 770, 71, 774,
103, 774, 71, 775, 103, 775, 71, 807, 103,
807, 72, 770, 104, 770, 73, 771, 105, 771,
73, 772, 105, 772, 73, 774, 105, 774, 73,
808, 105, 808, 73, 775, 73, 74, 105, 106,
74, 770, 106, 770, 75, 807, 107, 807, 76,
769, 108, 769, 76, 807, 108, 807, 76, 780,
108, 780, 76, 183, 108, 183, 78, 769, 110,
769, 78, 807, 110, 807, 78, 780, 110, 780,
700, 110, 79, 772, 111, 772, 79, 774, 111,
774, 79, 779, 111, 779, 82, 769, 114, 769,
82, 807, 114, 807, 82, 780, 114, 780, 83,
769, 115, 769, 83, 770, 115, 770, 83, 807,
115, 807, 83, 780, 115, 780, 84, 807, 116,
807, 84, 780, 116, 780, 85, 771, 117, 771,
85, 772, 117, 772, 85, 774, 117, 774, 85,
778, 117, 778, 85, 779, 117, 779, 85, 808,
117, 808, 87, 770, 119, 770, 89, 770, 121,
770, 89, 776, 90, 769, 122, 769, 90, 775,
122, 775, 90, 780, 122, 780, 115, 79, 795,
111, 795, 85, 795, 117, 795, 68, 90, 780,
68, 122, 780, 100, 122, 780, 76, 74, 76,
106, 108, 106, 78, 74, 78, 106, 110, 106,
65, 780, 97, 780, 73, 780, 105, 780, 79,
780, 111, 780, 85, 780, 117, 780, 85, 776,
772, 117, 776, 772, 85, 776, 769, 117, 776,
769, 85, 776, 780, 117, 776, 780, 85, 776,
768, 117, 776, 768, 65, 776, 772, 97, 776,
772, 65, 775, 772, 97, 775, 772, 198, 772,
230, 772, 71, 780, 103, 780, 75, 780, 107,
780, 79, 808, 111, 808, 79, 808, 772, 111,
808, 772, 439, 780, 658, 780, 106, 780, 68,
90, 68, 122, 100, 122, 71, 769, 103, 769,
78, 768, 110, 768, 65, 778, 769, 97, 778,
769, 198, 769, 230, 769, 216, 769, 248, 769,
65, 783, 97, 783, 65, 785, 97, 785, 69,
783, 101, 783, 69, 785, 101, 785, 73, 783,
105, 783, 73, 785, 105, 785, 79, 783, 111,
783, 79, 785, 111, 785, 82, 783, 114, 783,
82, 785, 114, 785, 85, 783, 117, 783, 85,
785, 117, 785, 83, 806, 115, 806, 84, 806,
116, 806, 72, 780, 104, 780, 65, 775, 97,
775, 69, 807, 101, 807, 79, 776, 772, 111,
776, 772, 79, 771, 772, 111, 771, 772, 79,
775, 111, 775, 79, 775, 772, 111, 775, 772,
89, 772, 121, 772, 104, 614, 106, 114, 633,
635, 641, 119, 121, 32, 774, 32, 775, 32,
778, 32, 808, 32, 771, 32, 779, 611, 108,
115, 120, 661, 768, 769, 787, 776, 769, 697,
32, 837, 59, 32, 769, 168, 769, 913, 769,
183, 917, 769, 919, 769, 921, 769, 927, 769,
933, 769, 937, 769, 953, 776, 769, 921, 776,
933, 776, 945, 769, 949, 769, 951, 769, 953,
769, 965, 776, 769, 953, 776, 965, 776, 959,
769, 965, 769, 969, 769, 946, 952, 933, 978,
769, 978, 776, 966, 960, 954, 961, 962, 920,
949, 931, 1045, 768, 1045, 776, 1043, 769, 1030,
776, 1050, 769, 1048, 768, 1059, 774, 1048, 774,
1080, 774, 1077, 768, 1077, 776, 1075, 769, 1110,
776, 1082, 769, 1080, 768, 1091, 774, 1140, 783,
1141, 783, 1046, 774, 1078, 774, 1040, 774, 1072,
774, 1040, 776, 1072, 776, 1045, 774, 1077, 774,
1240, 776, 1241, 776, 1046, 776, 1078, 776, 1047,
776, 1079, 776, 1048, 772, 1080, 772, 1048, 776,
1080, 776, 1054, 776, 1086, 776, 1256, 776, 1257,
776, 1069, 776, 1101, 776, 1059, 772, 1091, 772,
1059, 776, 1091, 776, 1059, 779, 1091, 779, 1063,
776, 1095, 776, 1067, 776, 1099, 776, 1381, 1410,
1575, 1619, 1575, 1620, 1608, 1620, 1575, 1621, 1610,
1620, 1575, 1652, 1608, 1652, 1735, 1652, 1610, 1652,
1749, 1620, 1729, 1620, 1746, 1620, 2344, 2364, 2352,
2364, 2355, 2364, 2325, 2364, 2326, 2364, 2327, 2364,
2332, 2364, 2337, 2364, 2338, 2364, 2347, 2364, 2351,
2364, 2503, 2494, 2503, 2519, 2465, 2492, 2466, 2492,
2479, 2492, 2610, 2620, 2616, 2620, 2582, 2620, 2583,
2620, 2588, 2620, 2603, 2620, 2887, 2902, 2887, 2878,
2887, 2903, 2849, 2876, 2850, 2876, 2962, 3031, 3014,
3006, 3015, 3006, 3014, 3031, 3142, 3158, 3263, 3285,
3270, 3285, 3270, 3286, 3270, 3266, 3270, 3266, 3285,
3398, 3390, 3399, 3390, 3398, 3415, 3545, 3530, 3545,
3535, 3545, 3535, 3530, 3545, 3551, 3661, 3634, 3789,
3762, 3755, 3737, 3755, 3745, 3851, 3906, 4023, 3916,
4023, 3921, 4023, 3926, 4023, 3931, 4023, 3904, 4021,
3953, 3954, 3953, 3956, 4018, 3968, 4018, 3953, 3968,
4019, 3968, 4019, 3953, 3968, 3953, 3968, 3986, 4023,
3996, 4023, 4001, 4023, 4006, 4023, 4011, 4023, 3984,
4021, 4133, 4142, 4316, 6917, 6965, 6919, 6965, 6921,
6965, 6923, 6965, 6925, 6965, 6929, 6965, 6970, 6965,
6972, 6965, 6974, 6965, 6975, 6965, 6978, 6965, 65,
198, 66, 68, 69, 398, 71, 72, 73, 74,
75, 76, 77, 78, 79, 546, 80, 82, 84,
85, 87, 97, 592, 593, 7426, 98, 100, 101,
601, 603, 604, 103, 107, 109, 331, 111, 596,
7446, 7447, 112, 116, 117, 7453, 623, 118, 7461,
946, 947, 948, 966, 967, 105, 114, 117, 118,
946, 947, 961, 966, 967, 1085, 594, 99, 597,
240, 604, 102, 607, 609, 613, 616, 617, 618,
7547, 669, 621, 7557, 671, 625, 624, 626, 627,
628, 629, 632, 642, 643, 427, 649, 650, 7452,
651, 652, 122, 656, 657, 658, 952, 65, 805,
97, 805, 66, 775, 98, 775, 66, 803, 98,
803, 66, 817, 98, 817, 67, 807, 769, 99,
807, 769, 68, 775, 100, 775, 68, 803, 100,
803, 68, 817, 100, 817, 68, 807, 100, 807,
68, 813, 100, 813, 69, 772, 768, 101, 772,
768, 69, 772, 769, 101, 772, 769, 69, 813,
101, 813, 69, 816, 101, 816, 69, 807, 774,
101, 807, 774, 70, 775, 102, 775, 71, 772,
103, 772, 72, 775, 104, 775, 72, 803, 104,
803, 72, 776, 104, 776, 72, 807, 104, 807,
72, 814, 104, 814, 73, 816, 105, 816, 73,
776, 769, 105, 776, 769, 75, 769, 107, 769,
75, 803, 107, 803, 75, 817, 107, 817, 76,
803, 108, 803, 76, 803, 772, 108, 803, 772,
76, 817, 108, 817, 76, 813, 108, 813, 77,
769, 109, 769, 77, 775, 109, 775, 77, 803,
109, 803, 78, 775, 110, 775, 78, 803, 110,
803, 78, 817, 110, 817, 78, 813, 110, 813,
79, 771, 769, 111, 771, 769, 79, 771, 776,
111, 771, 776, 79, 772, 768, 111, 772, 768,
79, 772, 769, 111, 772, 769, 80, 769, 112,
769, 80, 775, 112, 775, 82, 775, 114, 775,
82, 803, 114, 803, 82, 803, 772, 114, 803,
772, 82, 817, 114, 817, 83, 775, 115, 775,
83, 803, 115, 803, 83, 769, 775, 115, 769,
775, 83, 780, 775, 115, 780, 775, 83, 803,
775, 115, 803, 775, 84, 775, 116, 775, 84,
803, 116, 803, 84, 817, 116, 817, 84, 813,
116, 813, 85, 804, 117, 804, 85, 816, 117,
816, 85, 813, 117, 813, 85, 771, 769, 117,
771, 769, 85, 772, 776, 117, 772, 776, 86,
771, 118, 771, 86, 803, 118, 803, 87, 768,
119, 768, 87, 769, 119, 769, 87, 776, 119,
776, 87, 775, 119, 775, 87, 803, 119, 803,
88, 775, 120, 775, 88, 776, 120, 776, 89,
775, 121, 775, 90, 770, 122, 770, 90, 803,
122, 803, 90, 817, 122, 817, 104, 817, 116,
776, 119, 778, 121, 778, 97, 702, 383, 775,
65, 803, 97, 803, 65, 777, 97, 777, 65,
770, 769, 97, 770, 769, 65, 770, 768, 97,
770, 768, 65, 770, 777, 97, 770, 777, 65,
770, 771, 97, 770, 771, 65, 803, 770, 97,
803, 770, 65, 774, 769, 97, 774, 769, 65,
774, 768, 97, 774, 768, 65, 774, 777, 97,
774, 777, 65, 774, 771, 97, 774, 771, 65,
803, 774, 97, 803, 774, 69, 803, 101, 803,
69, 777, 101, 777, 69, 771, 101, 771, 69,
770, 769, 101, 770, 769, 69, 770, 768, 101,
770, 768, 69, 770, 777, 101, 770, 777, 69,
770, 771, 101, 770, 771, 69, 803, 770, 101,
803, 770, 73, 777, 105, 777, 73, 803, 105,
803, 79, 803, 111, 803, 79, 777, 111, 777,
79, 770, 769, 111, 770, 769, 79, 770, 768,
111, 770, 768, 79, 770, 777, 111, 770, 777,
79, 770, 771, 111, 770, 771, 79, 803, 770,
111, 803, 770, 79, 795, 769, 111, 795, 769,
79, 795, 768, 111, 795, 768, 79, 795, 777,
111, 795, 777, 79, 795, 771, 111, 795, 771,
79, 795, 803, 111, 795, 803, 85, 803, 117,
803, 85, 777, 117, 777, 85, 795, 769, 117,
795, 769, 85, 795, 768, 117, 795, 768, 85,
795, 777, 117, 795, 777, 85, 795, 771, 117,
795, 771, 85, 795, 803, 117, 795, 803, 89,
768, 121, 768, 89, 803, 121, 803, 89, 777,
121, 777, 89, 771, 121, 771, 945, 787, 945,
788, 945, 787, 768, 945, 788, 768, 945, 787,
769, 945, 788, 769, 945, 787, 834, 945, 788,
834, 913, 787, 913, 788, 913, 787, 768, 913,
788, 768, 913, 787, 769, 913, 788, 769, 913,
787, 834, 913, 788, 834, 949, 787, 949, 788,
949, 787, 768, 949, 788, 768, 949, 787, 769,
949, 788, 769, 917, 787, 917, 788, 917, 787,
768, 917, 788, 768, 917, 787, 769, 917, 788,
769, 951, 787, 951, 788, 951, 787, 768, 951,
788, 768, 951, 787, 769, 951, 788, 769, 951,
787, 834, 951, 788, 834, 919, 787, 919, 788,
919, 787, 768, 919, 788, 768, 919, 787, 769,
919, 788, 769, 919, 787, 834, 919, 788, 834,
953, 787, 953, 788, 953, 787, 768, 953, 788,
768, 953, 787, 769, 953, 788, 769, 953, 787,
834, 953, 788, 834, 921, 787, 921, 788, 921,
787, 768, 921, 788, 768, 921, 787, 769, 921,
788, 769, 921, 787, 834, 921, 788, 834, 959,
787, 959, 788, 959, 787, 768, 959, 788, 768,
959, 787, 769, 959, 788, 769, 927, 787, 927,
788, 927, 787, 768, 927, 788, 768, 927, 787,
769, 927, 788, 769, 965, 787, 965, 788, 965,
787, 768, 965, 788, 768, 965, 787, 769, 965,
788, 769, 965, 787, 834, 965, 788, 834, 933,
788, 933, 788, 768, 933, 788, 769, 933, 788,
834, 969, 787, 969, 788, 969, 787, 768, 969,
788, 768, 969, 787, 769, 969, 788, 769, 969,
787, 834, 969, 788, 834, 937, 787, 937, 788,
937, 787, 768, 937, 788, 768, 937, 787, 769,
937, 788, 769, 937, 787, 834, 937, 788, 834,
945, 768, 945, 769, 949, 768, 949, 769, 951,
768, 951, 769, 953, 768, 953, 769, 959, 768,
959, 769, 965, 768, 965, 769, 969, 768, 969,
769, 945, 787, 837, 945, 788, 837, 945, 787,
768, 837, 945, 788, 768, 837, 945, 787, 769,
837, 945, 788, 769, 837, 945, 787, 834, 837,
945, 788, 834, 837, 913, 787, 837, 913, 788,
837, 913, 787, 768, 837, 913, 788, 768, 837,
913, 787, 769, 837, 913, 788, 769, 837, 913,
787, 834, 837, 913, 788, 834, 837, 951, 787,
837, 951, 788, 837, 951, 787, 768, 837, 951,
788, 768, 837, 951, 787, 769, 837, 951, 788,
769, 837, 951, 787, 834, 837, 951, 788, 834,
837, 919, 787, 837, 919, 788, 837, 919, 787,
768, 837, 919, 788, 768, 837, 919, 787, 769,
837, 919, 788, 769, 837, 919, 787, 834, 837,
919, 788, 834, 837, 969, 787, 837, 969, 788,
837, 969, 787, 768, 837, 969, 788, 768, 837,
969, 787, 769, 837, 969, 788, 769, 837, 969,
787, 834, 837, 969, 788, 834, 837, 937, 787,
837, 937, 788, 837, 937, 787, 768, 837, 937,
788, 768, 837, 937, 787, 769, 837, 937, 788,
769, 837, 937, 787, 834, 837, 937, 788, 834,
837, 945, 774, 945, 772, 945, 768, 837, 945,
837, 945, 769, 837, 945, 834, 945, 834, 837,
913, 774, 913, 772, 913, 768, 913, 769, 913,
837, 32, 787, 953, 32, 787, 32, 834, 168,
834, 951, 768, 837, 951, 837, 951, 769, 837,
951, 834, 951, 834, 837, 917, 768, 917, 769,
919, 768, 919, 769, 919, 837, 8127, 768, 8127,
769, 8127, 834, 953, 774, 953, 772, 953, 776,
768, 953, 776, 769, 953, 834, 953, 776, 834,
921, 774, 921, 772, 921, 768, 921, 769, 8190,
768, 8190, 769, 8190, 834, 965, 774, 965, 772,
965, 776, 768, 965, 776, 769, 961, 787, 961,
788, 965, 834, 965, 776, 834, 933, 774, 933,
772, 933, 768, 933, 769, 929, 788, 168, 768,
168, 769, 96, 969, 768, 837, 969, 837, 969,
769, 837, 969, 834, 969, 834, 837, 927, 768,
927, 769, 937, 768, 937, 769, 937, 837, 180,
32, 788, 8194, 8195, 32, 32, 32, 32, 32,
32, 32, 32, 32, 8208, 32, 819, 46, 46,
46, 46, 46, 46, 32, 8242, 8242, 8242, 8242,
8242, 8245, 8245, 8245, 8245, 8245, 33, 33, 32,
773, 63, 63, 63, 33, 33, 63, 8242, 8242,
8242, 8242, 32, 48, 105, 52, 53, 54, 55,
56, 57, 43, 8722, 61, 40, 41, 110, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57,
43, 8722, 61, 40, 41, 97, 101, 111, 120,
601, 104, 107, 108, 109, 110, 112, 115, 116,
82, 115, 97, 47, 99, 97, 47, 115, 67,
176, 67, 99, 47, 111, 99, 47, 117, 400,
176, 70, 103, 72, 72, 72, 104, 295, 73,
73, 76, 108, 78, 78, 111, 80, 81, 82,
82, 82, 83, 77, 84, 69, 76, 84, 77,
90, 937, 90, 75, 65, 778, 66, 67, 101,
69, 70, 77, 111, 1488, 1489, 1490, 1491, 105,
70, 65, 88, 960, 947, 915, 928, 8721, 68,
100, 101, 105, 106, 49, 8260, 55, 49, 8260,
57, 49, 8260, 49, 48, 49, 8260, 51, 50,
8260, 51, 49, 8260, 53, 50, 8260, 53, 51,
8260, 53, 52, 8260, 53, 49, 8260, 54, 53,
8260, 54, 49, 8260, 56, 51, 8260, 56, 53,
8260, 56, 55, 8260, 56, 49, 8260, 73, 73,
73, 73, 73, 73, 73, 86, 86, 86, 73,
86, 73, 73, 86, 73, 73, 73, 73, 88,
88, 88, 73, 88, 73, 73, 76, 67, 68,
77, 105, 105, 105, 105, 105, 105, 105, 118,
118, 118, 105, 118, 105, 105, 118, 105, 105,
105, 105, 120, 120, 120, 105, 120, 105, 105,
108, 99, 100, 109, 48, 8260, 51, 8592, 824,
8594, 824, 8596, 824, 8656, 824, 8660, 824, 8658,
824, 8707, 824, 8712, 824, 8715, 824, 8739, 824,
8741, 824, 8747, 8747, 8747, 8747, 8747, 8750, 8750,
8750, 8750, 8750, 8764, 824, 8771, 824, 8773, 824,
8776, 824, 61, 824, 8801, 824, 8781, 824, 60,
824, 62, 824, 8804, 824, 8805, 824, 8818, 824,
8819, 824, 8822, 824, 8823, 824, 8826, 824, 8827,
824, 8834, 824, 8835, 824, 8838, 824, 8839, 824,
8866, 824, 8872, 824, 8873, 824, 8875, 824, 8828,
824, 8829, 824, 8849, 824, 8850, 824, 8882, 824,
8883, 824, 8884, 824, 8885, 824, 12296, 12297, 49,
50, 51, 52, 53, 54, 55, 56, 57, 49,
48, 49, 49, 49, 50, 49, 51, 49, 52,
49, 53, 49, 54, 49, 55, 49, 56, 49,
57, 50, 48, 40, 49, 41, 40, 50, 41,
40, 51, 41, 40, 52, 41, 40, 53, 41,
40, 54, 41, 40, 55, 41, 40, 56, 41,
40, 57, 41, 40, 49, 48, 41, 40, 49,
49, 41, 40, 49, 50, 41, 40, 49, 51,
41, 40, 49, 52, 41, 40, 49, 53, 41,
40, 49, 54, 41, 40, 49, 55, 41, 40,
49, 56, 41, 40, 49, 57, 41, 40, 50,
48, 41, 49, 46, 50, 46, 51, 46, 52,
46, 53, 46, 54, 46, 55, 46, 56, 46,
57, 46, 49, 48, 46, 49, 49, 46, 49,
50, 46, 49, 51, 46, 49, 52, 46, 49,
53, 46, 49, 54, 46, 49, 55, 46, 49,
56, 46, 49, 57, 46, 50, 48, 46, 40,
97, 41, 40, 98, 41, 40, 99, 41, 40,
100, 41, 40, 101, 41, 40, 102, 41, 40,
103, 41, 40, 104, 41, 40, 105, 41, 40,
106, 41, 40, 107, 41, 40, 108, 41, 40,
109, 41, 40, 110, 41, 40, 111, 41, 40,
112, 41, 40, 113, 41, 40, 114, 41, 40,
115, 41, 40, 116, 41, 40, 117, 41, 40,
118, 41, 40, 119, 41, 40, 120, 41, 40,
121, 41, 40, 122, 41, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 97, 98, 99, 100, 101,
102, 103, 104, 105, 106, 107, 108, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 48, 8747, 8747, 8747, 8747, 58,
58, 61, 61, 61, 61, 61, 61, 10973, 824,
106, 86, 11617, 27597, 40863, 19968, 20008, 20022, 20031,
20057, 20101, 20108, 20128, 20154, 20799, 20837, 20843, 20866,
20886, 20907, 20960, 20981, 20992, 21147, 21241, 21269, 21274,
21304, 21313, 21340, 21353, 21378, 21430, 21448, 21475, 22231,
22303, 22763, 22786, 22794, 22805, 22823, 22899, 23376, 23424,
23544, 23567, 23586, 23608, 23662, 23665, 24027, 24037, 24049,
24062, 24178, 24186, 24191, 24308, 24318, 24331, 24339, 24400,
24417, 24435, 24515, 25096, 25142, 25163, 25903, 25908, 25991,
26007, 26020, 26041, 26080, 26085, 26352, 26376, 26408, 27424,
27490, 27513, 27571, 27595, 27604, 27611, 27663, 27668, 27700,
28779, 29226, 29238, 29243, 29247, 29255, 29273, 29275, 29356,
29572, 29577, 29916, 29926, 29976, 29983, 29992, 30000, 30091,
30098, 30326, 30333, 30382, 30399, 30446, 30683, 30690, 30707,
31034, 31160, 31166, 31348, 31435, 31481, 31859, 31992, 32566,
32593, 32650, 32701, 32769, 32780, 32786, 32819, 32895, 32905,
33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394,
33400, 34381, 34411, 34880, 34892, 34915, 35198, 35211, 35282,
35328, 35895, 35910, 35925, 35960, 35997, 36196, 36208, 36275,
36523, 36554, 36763, 36784, 36789, 37009, 37193, 37318, 37324,
37329, 38263, 38272, 38428, 38582, 38585, 38632, 38737, 38750,
38754, 38761, 38859, 38893, 38899, 38913, 39080, 39131, 39135,
39318, 39321, 39340, 39592, 39640, 39647, 39717, 39727, 39730,
39740, 39770, 40165, 40565, 40575, 40613, 40635, 40643, 40653,
40657, 40697, 40701, 40718, 40723, 40736, 40763, 40778, 40786,
40845, 40860, 40864, 32, 12306, 21313, 21316, 21317, 12363,
12441, 12365, 12441, 12367, 12441, 12369, 12441, 12371, 12441,
12373, 12441, 12375, 12441, 12377, 12441, 12379, 12441, 12381,
12441, 12383, 12441, 12385, 12441, 12388, 12441, 12390, 12441,
12392, 12441, 12399, 12441, 12399, 12442, 12402, 12441, 12402,
12442, 12405, 12441, 12405, 12442, 12408, 12441, 12408, 12442,
12411, 12441, 12411, 12442, 12358, 12441, 32, 12441, 32,
12442, 12445, 12441, 12424, 12426, 12459, 12441, 12461, 12441,
12463, 12441, 12465, 12441, 12467, 12441, 12469, 12441, 12471,
12441, 12473, 12441, 12475, 12441, 12477, 12441, 12479, 12441,
12481, 12441, 12484, 12441, 12486, 12441, 12488, 12441, 12495,
12441, 12495, 12442, 12498, 12441, 12498, 12442, 12501, 12441,
12501, 12442, 12504, 12441, 12504, 12442, 12507, 12441, 12507,
12442, 12454, 12441, 12527, 12441, 12528, 12441, 12529, 12441,
12530, 12441, 12541, 12441, 12467, 12488, 4352, 4353, 4522,
4354, 4524, 4525, 4355, 4356, 4357, 4528, 4529, 4530,
4531, 4532, 4533, 4378, 4358, 4359, 4360, 4385, 4361,
4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370,
4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457,
4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466,
4467, 4468, 4469, 4448, 4372, 4373, 4551, 4552, 4556,
4558, 4563, 4567, 4569, 4380, 4573, 4575, 4381, 4382,
4384, 4386, 4387, 4391, 4393, 4395, 4396, 4397, 4398,
4399, 4402, 4406, 4416, 4423, 4428, 4593, 4594, 4439,
4440, 4441, 4484, 4485, 4488, 4497, 4498, 4500, 4510,
4513, 19968, 20108, 19977, 22235, 19978, 20013, 19979, 30002,
20057, 19993, 19969, 22825, 22320, 20154, 40, 4352, 41,
40, 4354, 41, 40, 4355, 41, 40, 4357, 41,
40, 4358, 41, 40, 4359, 41, 40, 4361, 41,
40, 4363, 41, 40, 4364, 41, 40, 4366, 41,
40, 4367, 41, 40, 4368, 41, 40, 4369, 41,
40, 4370, 41, 40, 4352, 4449, 41, 40, 4354,
4449, 41, 40, 4355, 4449, 41, 40, 4357, 4449,
41, 40, 4358, 4449, 41, 40, 4359, 4449, 41,
40, 4361, 4449, 41, 40, 4363, 4449, 41, 40,
4364, 4449, 41, 40, 4366, 4449, 41, 40, 4367,
4449, 41, 40, 4368, 4449, 41, 40, 4369, 4449,
41, 40, 4370, 4449, 41, 40, 4364, 4462, 41,
40, 4363, 4457, 4364, 4453, 4523, 41, 40, 4363,
4457, 4370, 4462, 41, 40, 19968, 41, 40, 20108,
41, 40, 19977, 41, 40, 22235, 41, 40, 20116,
41, 40, 20845, 41, 40, 19971, 41, 40, 20843,
41, 40, 20061, 41, 40, 21313, 41, 40, 26376,
41, 40, 28779, 41, 40, 27700, 41, 40, 26408,
41, 40, 37329, 41, 40, 22303, 41, 40, 26085,
41, 40, 26666, 41, 40, 26377, 41, 40, 31038,
41, 40, 21517, 41, 40, 29305, 41, 40, 36001,
41, 40, 31069, 41, 40, 21172, 41, 40, 20195,
41, 40, 21628, 41, 40, 23398, 41, 40, 30435,
41, 40, 20225, 41, 40, 36039, 41, 40, 21332,
41, 40, 31085, 41, 40, 20241, 41, 40, 33258,
41, 40, 33267, 41, 21839, 24188, 25991, 31631, 80,
84, 69, 50, 49, 50, 50, 50, 51, 50,
52, 50, 53, 50, 54, 50, 55, 50, 56,
50, 57, 51, 48, 51, 49, 51, 50, 51,
51, 51, 52, 51, 53, 4352, 4354, 4355, 4357,
4358, 4359, 4361, 4363, 4364, 4366, 4367, 4368, 4369,
4370, 4352, 4449, 4354, 4449, 4355, 4449, 4357, 4449,
4358, 4449, 4359, 4449, 4361, 4449, 4363, 4449, 4364,
4449, 4366, 4449, 4367, 4449, 4368, 4449, 4369, 4449,
4370, 4449, 4366, 4449, 4535, 4352, 4457, 4364, 4462,
4363, 4468, 4363, 4462, 19968, 20108, 19977, 22235, 20116,
20845, 19971, 20843, 20061, 21313, 26376, 28779, 27700, 26408,
37329, 22303, 26085, 26666, 26377, 31038, 21517, 29305, 36001,
31069, 21172, 31192, 30007, 22899, 36969, 20778, 21360, 27880,
38917, 20241, 20889, 27491, 19978, 20013, 19979, 24038, 21491,
21307, 23447, 23398, 30435, 20225, 36039, 21332, 22812, 51,
54, 51, 55, 51, 56, 51, 57, 52, 48,
52, 49, 52, 50, 52, 51, 52, 52, 52,
53, 52, 54, 52, 55, 52, 56, 52, 57,
53, 48, 49, 26376, 50, 26376, 51, 26376, 52,
26376, 53, 26376, 54, 26376, 55, 26376, 56, 26376,
57, 26376, 49, 48, 26376, 49, 49, 26376, 49,
50, 26376, 72, 103, 101, 114, 103, 101, 86,
76, 84, 68, 12450, 12452, 12454, 12456, 12458, 12459,
12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, 12477,
12479, 12481, 12484, 12486, 12488, 12490, 12491, 12492, 12493,
12494, 12495, 12498, 12501, 12504, 12507, 12510, 12511, 12512,
12513, 12514, 12516, 12518, 12520, 12521, 12522, 12523, 12524,
12525, 12527, 12528, 12529, 12530, 20196, 21644, 12450, 12495,
12442, 12540, 12488, 12450, 12523, 12501, 12449, 12450, 12531,
12504, 12442, 12450, 12450, 12540, 12523, 12452, 12491, 12531,
12463, 12441, 12452, 12531, 12481, 12454, 12457, 12531, 12456,
12473, 12463, 12540, 12488, 12441, 12456, 12540, 12459, 12540,
12458, 12531, 12473, 12458, 12540, 12512, 12459, 12452, 12522,
12459, 12521, 12483, 12488, 12459, 12525, 12522, 12540, 12459,
12441, 12525, 12531, 12459, 12441, 12531, 12510, 12461, 12441,
12459, 12441, 12461, 12441, 12491, 12540, 12461, 12517, 12522,
12540, 12461, 12441, 12523, 12479, 12441, 12540, 12461, 12525,
12461, 12525, 12463, 12441, 12521, 12512, 12461, 12525, 12513,
12540, 12488, 12523, 12461, 12525, 12527, 12483, 12488, 12463,
12441, 12521, 12512, 12463, 12441, 12521, 12512, 12488, 12531,
12463, 12523, 12475, 12441, 12452, 12525, 12463, 12525, 12540,
12493, 12465, 12540, 12473, 12467, 12523, 12490, 12467, 12540,
12507, 12442, 12469, 12452, 12463, 12523, 12469, 12531, 12481,
12540, 12512, 12471, 12522, 12531, 12463, 12441, 12475, 12531,
12481, 12475, 12531, 12488, 12479, 12441, 12540, 12473, 12486,
12441, 12471, 12488, 12441, 12523, 12488, 12531, 12490, 12494,
12494, 12483, 12488, 12495, 12452, 12484, 12495, 12442, 12540,
12475, 12531, 12488, 12495, 12442, 12540, 12484, 12495, 12441,
12540, 12524, 12523, 12498, 12442, 12450, 12473, 12488, 12523,
12498, 12442, 12463, 12523, 12498, 12442, 12467, 12498, 12441,
12523, 12501, 12449, 12521, 12483, 12488, 12441, 12501, 12451,
12540, 12488, 12501, 12441, 12483, 12471, 12455, 12523, 12501,
12521, 12531, 12504, 12463, 12479, 12540, 12523, 12504, 12442,
12477, 12504, 12442, 12491, 12498, 12504, 12523, 12484, 12504,
12442, 12531, 12473, 12504, 12442, 12540, 12471, 12441, 12504,
12441, 12540, 12479, 12507, 12442, 12452, 12531, 12488, 12507,
12441, 12523, 12488, 12507, 12531, 12507, 12442, 12531, 12488,
12441, 12507, 12540, 12523, 12507, 12540, 12531, 12510, 12452,
12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, 12510,
12523, 12463, 12510, 12531, 12471, 12519, 12531, 12511, 12463,
12525, 12531, 12511, 12522, 12511, 12522, 12495, 12441, 12540,
12523, 12513, 12459, 12441, 12513, 12459, 12441, 12488, 12531,
12513, 12540, 12488, 12523, 12516, 12540, 12488, 12441, 12516,
12540, 12523, 12518, 12450, 12531, 12522, 12483, 12488, 12523,
12522, 12521, 12523, 12498, 12442, 12540, 12523, 12540, 12501,
12441, 12523, 12524, 12512, 12524, 12531, 12488, 12465, 12441,
12531, 12527, 12483, 12488, 48, 28857, 49, 28857, 50,
28857, 51, 28857, 52, 28857, 53, 28857, 54, 28857,
55, 28857, 56, 28857, 57, 28857, 49, 48, 28857,
49, 49, 28857, 49, 50, 28857, 49, 51, 28857,
49, 52, 28857, 49, 53, 28857, 49, 54, 28857,
49, 55, 28857, 49, 56, 28857, 49, 57, 28857,
50, 48, 28857, 50, 49, 28857, 50, 50, 28857,
50, 51, 28857, 50, 52, 28857, 104, 80, 97,
100, 97, 65, 85, 98, 97, 114, 111, 86,
112, 99, 100, 109, 100, 109, 50, 100, 109,
51, 73, 85, 24179, 25104, 26157, 21644, 22823, 27491,
26126, 27835, 26666, 24335, 20250, 31038, 112, 65, 110,
65, 956, 65, 109, 65, 107, 65, 75, 66,
77, 66, 71, 66, 99, 97, 108, 107, 99,
97, 108, 112, 70, 110, 70, 956, 70, 956,
103, 109, 103, 107, 103, 72, 122, 107, 72,
122, 77, 72, 122, 71, 72, 122, 84, 72,
122, 956, 108, 109, 108, 100, 108, 107, 108,
102, 109, 110, 109, 956, 109, 109, 109, 99,
109, 107, 109, 109, 109, 50, 99, 109, 50,
109, 50, 107, 109, 50, 109, 109, 51, 99,
109, 51, 109, 51, 107, 109, 51, 109, 8725,
115, 109, 8725, 115, 50, 80, 97, 107, 80,
97, 77, 80, 97, 71, 80, 97, 114, 97,
100, 114, 97, 100, 8725, 115, 114, 97, 100,
8725, 115, 50, 112, 115, 110, 115, 956, 115,
109, 115, 112, 86, 110, 86, 956, 86, 109,
86, 107, 86, 77, 86, 112, 87, 110, 87,
956, 87, 109, 87, 107, 87, 77, 87, 107,
937, 77, 937, 97, 46, 109, 46, 66, 113,
99, 99, 99, 100, 67, 8725, 107, 103, 67,
111, 46, 100, 66, 71, 121, 104, 97, 72,
80, 105, 110, 75, 75, 75, 77, 107, 116,
108, 109, 108, 110, 108, 111, 103, 108, 120,
109, 98, 109, 105, 108, 109, 111, 108, 80,
72, 112, 46, 109, 46, 80, 80, 77, 80,
82, 115, 114, 83, 118, 87, 98, 86, 8725,
109, 65, 8725, 109, 49, 26085, 50, 26085, 51,
26085, 52, 26085, 53, 26085, 54, 26085, 55, 26085,
56, 26085, 57, 26085, 49, 48, 26085, 49, 49,
26085, 49, 50, 26085, 49, 51, 26085, 49, 52,
26085, 49, 53, 26085, 49, 54, 26085, 49, 55,
26085, 49, 56, 26085, 49, 57, 26085, 50, 48,
26085, 50, 49, 26085, 50, 50, 26085, 50, 51,
26085, 50, 52, 26085, 50, 53, 26085, 50, 54,
26085, 50, 55, 26085, 50, 56, 26085, 50, 57,
26085, 51, 48, 26085, 51, 49, 26085, 103, 97,
108, 1098, 1100, 42863, 67, 70, 81, 294, 339,
42791, 43831, 619, 43858, 653, 35912, 26356, 36554, 36040,
28369, 20018, 21477, 40860, 40860, 22865, 37329, 21895, 22856,
25078, 30313, 32645, 34367, 34746, 35064, 37007, 27138, 27931,
28889, 29662, 33853, 37226, 39409, 20098, 21365, 27396, 29211,
34349, 40478, 23888, 28651, 34253, 35172, 25289, 33240, 34847,
24266, 26391, 28010, 29436, 37070, 20358, 20919, 21214, 25796,
27347, 29200, 30439, 32769, 34310, 34396, 36335, 38706, 39791,
40442, 30860, 31103, 32160, 33737, 37636, 40575, 35542, 22751,
24324, 31840, 32894, 29282, 30922, 36034, 38647, 22744, 23650,
27155, 28122, 28431, 32047, 32311, 38475, 21202, 32907, 20956,
20940, 31260, 32190, 33777, 38517, 35712, 25295, 27138, 35582,
20025, 23527, 24594, 29575, 30064, 21271, 30971, 20415, 24489,
19981, 27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498,
27578, 36784, 27784, 25342, 33509, 25504, 30053, 20142, 20841,
20937, 26753, 31975, 33391, 35538, 37327, 21237, 21570, 22899,
24300, 26053, 28670, 31018, 38317, 39530, 40599, 40654, 21147,
26310, 27511, 36706, 24180, 24976, 25088, 25754, 28451, 29001,
29833, 31178, 32244, 32879, 36646, 34030, 36899, 37706, 21015,
21155, 21693, 28872, 35010, 35498, 24265, 24565, 25467, 27566,
31806, 29557, 20196, 22265, 23527, 23994, 24604, 29618, 29801,
32666, 32838, 37428, 38646, 38728, 38936, 20363, 31150, 37300,
38584, 24801, 20102, 20698, 23534, 23615, 26009, 27138, 29134,
30274, 34044, 36988, 40845, 26248, 38446, 21129, 26491, 26611,
27969, 28316, 29705, 30041, 30827, 32016, 39006, 20845, 25134,
38520, 20523, 23833, 28138, 36650, 24459, 24900, 26647, 29575,
38534, 21033, 21519, 23653, 26131, 26446, 26792, 27877, 29702,
30178, 32633, 35023, 35041, 37324, 38626, 21311, 28346, 21533,
29136, 29848, 34298, 38563, 40023, 40607, 26519, 28107, 33256,
31435, 31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050,
20999, 24230, 25299, 31958, 23429, 27934, 26292, 36667, 34892,
38477, 35211, 24275, 20800, 21952, 22618, 26228, 20958, 29482,
30410, 31036, 31070, 31077, 31119, 38742, 31934, 32701, 34322,
35576, 36920, 37117, 39151, 39164, 39208, 40372, 37086, 38583,
20398, 20711, 20813, 21193, 21220, 21329, 21917, 22022, 22120,
22592, 22696, 23652, 23662, 24724, 24936, 24974, 25074, 25935,
26082, 26257, 26757, 28023, 28186, 28450, 29038, 29227, 29730,
30865, 31038, 31049, 31048, 31056, 31062, 31069, 31117, 31118,
31296, 31361, 31680, 32244, 32265, 32321, 32626, 32773, 33261,
33401, 33401, 33879, 35088, 35222, 35585, 35641, 36051, 36104,
36790, 36920, 38627, 38911, 38971, 24693, 148206, 33304, 20006,
20917, 20840, 20352, 20805, 20864, 21191, 21242, 21917, 21845,
21913, 21986, 22618, 22707, 22852, 22868, 23138, 23336, 24274,
24281, 24425, 24493, 24792, 24910, 24840, 24974, 24928, 25074,
25140, 25540, 25628, 25682, 25942, 26228, 26391, 26395, 26454,
27513, 27578, 27969, 28379, 28363, 28450, 28702, 29038, 30631,
29237, 29359, 29482, 29809, 29958, 30011, 30237, 30239, 30410,
30427, 30452, 30538, 30528, 30924, 31409, 31680, 31867, 32091,
32244, 32574, 32773, 33618, 33775, 34681, 35137, 35206, 35222,
35519, 35576, 35531, 35585, 35582, 35565, 35641, 35722, 36104,
36664, 36978, 37273, 37494, 38524, 38627, 38742, 38875, 38911,
38923, 38971, 39698, 40860, 141386, 141380, 144341, 15261, 16408,
16441, 152137, 154832, 163539, 40771, 40846, 102, 102, 102,
105, 102, 108, 102, 102, 105, 102, 102, 108,
115, 116, 115, 116, 1396, 1398, 1396, 1381, 1396,
1387, 1406, 1398, 1396, 1389, 1497, 1460, 1522, 1463,
1506, 1488, 1491, 1492, 1499, 1500, 1501, 1512, 1514,
43, 1513, 1473, 1513, 1474, 1513, 1468, 1473, 1513,
1468, 1474, 1488, 1463, 1488, 1464, 1488, 1468, 1489,
1468, 1490, 1468, 1491, 1468, 1492, 1468, 1493, 1468,
1494, 1468, 1496, 1468, 1497, 1468, 1498, 1468, 1499,
1468, 1500, 1468, 1502, 1468, 1504, 1468, 1505, 1468,
1507, 1468, 1508, 1468, 1510, 1468, 1511, 1468, 1512,
1468, 1513, 1468, 1514, 1468, 1493, 1465, 1489, 1471,
1499, 1471, 1508, 1471, 1488, 1500, 1649, 1649, 1659,
1659, 1659, 1659, 1662, 1662, 1662, 1662, 1664, 1664,
1664, 1664, 1658, 1658, 1658, 1658, 1663, 1663, 1663,
1663, 1657, 1657, 1657, 1657, 1700, 1700, 1700, 1700,
1702, 1702, 1702, 1702, 1668, 1668, 1668, 1668, 1667,
1667, 1667, 1667, 1670, 1670, 1670, 1670, 1671, 1671,
1671, 1671, 1677, 1677, 1676, 1676, 1678, 1678, 1672,
1672, 1688, 1688, 1681, 1681, 1705, 1705, 1705, 1705,
1711, 1711, 1711, 1711, 1715, 1715, 1715, 1715, 1713,
1713, 1713, 1713, 1722, 1722, 1723, 1723, 1723, 1723,
1749, 1620, 1749, 1620, 1729, 1729, 1729, 1729, 1726,
1726, 1726, 1726, 1746, 1746, 1746, 1620, 1746, 1620,
1709, 1709, 1709, 1709, 1735, 1735, 1734, 1734, 1736,
1736, 1735, 1652, 1739, 1739, 1733, 1733, 1737, 1737,
1744, 1744, 1744, 1744, 1609, 1609, 1610, 1620, 1575,
1610, 1620, 1575, 1610, 1620, 1749, 1610, 1620, 1749,
1610, 1620, 1608, 1610, 1620, 1608, 1610, 1620, 1735,
1610, 1620, 1735, 1610, 1620, 1734, 1610, 1620, 1734,
1610, 1620, 1736, 1610, 1620, 1736, 1610, 1620, 1744,
1610, 1620, 1744, 1610, 1620, 1744, 1610, 1620, 1609,
1610, 1620, 1609, 1610, 1620, 1609, 1740, 1740, 1740,
1740, 1610, 1620, 1580, 1610, 1620, 1581, 1610, 1620,
1605, 1610, 1620, 1609, 1610, 1620, 1610, 1576, 1580,
1576, 1581, 1576, 1582, 1576, 1605, 1576, 1609, 1576,
1610, 1578, 1580, 1578, 1581, 1578, 1582, 1578, 1605,
1578, 1609, 1578, 1610, 1579, 1580, 1579, 1605, 1579,
1609, 1579, 1610, 1580, 1581, 1580, 1605, 1581, 1580,
1581, 1605, 1582, 1580, 1582, 1581, 1582, 1605, 1587,
1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589, 1581,
1589, 1605, 1590, 1580, 1590, 1581, 1590, 1582, 1590,
1605, 1591, 1581, 1591, 1605, 1592, 1605, 1593, 1580,
1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580, 1601,
1581, 1601, 1582, 1601, 1605, 1601, 1609, 1601, 1610,
1602, 1581, 1602, 1605, 1602, 1609, 1602, 1610, 1603,
1575, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604,
1603, 1605, 1603, 1609, 1603, 1610, 1604, 1580, 1604,
1581, 1604, 1582, 1604, 1605, 1604, 1609, 1604, 1610,
1605, 1580, 1605, 1581, 1605, 1582, 1605, 1605, 1605,
1609, 1605, 1610, 1606, 1580, 1606, 1581, 1606, 1582,
1606, 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607,
1605, 1607, 1609, 1607, 1610, 1610, 1580, 1610, 1581,
1610, 1582, 1610, 1605, 1610, 1609, 1610, 1610, 1584,
1648, 1585, 1648, 1609, 1648, 32, 1612, 1617, 32,
1613, 1617, 32, 1614, 1617, 32, 1615, 1617, 32,
1616, 1617, 32, 1617, 1648, 1610, 1620, 1585, 1610,
1620, 1586, 1610, 1620, 1605, 1610, 1620, 1606, 1610,
1620, 1609, 1610, 1620, 1610, 1576, 1585, 1576, 1586,
1576, 1605, 1576, 1606, 1576, 1609, 1576, 1610, 1578,
1585, 1578, 1586, 1578, 1605, 1578, 1606, 1578, 1609,
1578, 1610, 1579, 1585, 1579, 1586, 1579, 1605, 1579,
1606, 1579, 1609, 1579, 1610, 1601, 1609, 1601, 1610,
1602, 1609, 1602, 1610, 1603, 1575, 1603, 1604, 1603,
1605, 1603, 1609, 1603, 1610, 1604, 1605, 1604, 1609,
1604, 1610, 1605, 1575, 1605, 1605, 1606, 1585, 1606,
1586, 1606, 1605, 1606, 1606, 1606, 1609, 1606, 1610,
1609, 1648, 1610, 1585, 1610, 1586, 1610, 1605, 1610,
1606, 1610, 1609, 1610, 1610, 1610, 1620, 1580, 1610,
1620, 1581, 1610, 1620, 1582, 1610, 1620, 1605, 1610,
1620, 1607, 1576, 1580, 1576, 1581, 1576, 1582, 1576,
1605, 1576, 1607, 1578, 1580, 1578, 1581, 1578, 1582,
1578, 1605, 1578, 1607, 1579, 1605, 1580, 1581, 1580,
1605, 1581, 1580, 1581, 1605, 1582, 1580, 1582, 1605,
1587, 1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589,
1581, 1589, 1582, 1589, 1605, 1590, 1580, 1590, 1581,
1590, 1582, 1590, 1605, 1591, 1581, 1592, 1605, 1593,
1580, 1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580,
1601, 1581, 1601, 1582, 1601, 1605, 1602, 1581, 1602,
1605, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604,
1603, 1605, 1604, 1580, 1604, 1581, 1604, 1582, 1604,
1605, 1604, 1607, 1605, 1580, 1605, 1581, 1605, 1582,
1605, 1605, 1606, 1580, 1606, 1581, 1606, 1582, 1606,
1605, 1606, 1607, 1607, 1580, 1607, 1605, 1607, 1648,
1610, 1580, 1610, 1581, 1610, 1582, 1610, 1605, 1610,
1607, 1610, 1620, 1605, 1610, 1620, 1607, 1576, 1605,
1576, 1607, 1578, 1605, 1578, 1607, 1579, 1605, 1579,
1607, 1587, 1605, 1587, 1607, 1588, 1605, 1588, 1607,
1603, 1604, 1603, 1605, 1604, 1605, 1606, 1605, 1606,
1607, 1610, 1605, 1610, 1607, 1600, 1614, 1617, 1600,
1615, 1617, 1600, 1616, 1617, 1591, 1609, 1591, 1610,
1593, 1609, 1593, 1610, 1594, 1609, 1594, 1610, 1587,
1609, 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609,
1581, 1610, 1580, 1609, 1580, 1610, 1582, 1609, 1582,
1610, 1589, 1609, 1589, 1610, 1590, 1609, 1590, 1610,
1588, 1580, 1588, 1581, 1588, 1582, 1588, 1605, 1588,
1585, 1587, 1585, 1589, 1585, 1590, 1585, 1591, 1609,
1591, 1610, 1593, 1609, 1593, 1610, 1594, 1609, 1594,
1610, 1587, 1609, 1587, 1610, 1588, 1609, 1588, 1610,
1581, 1609, 1581, 1610, 1580, 1609, 1580, 1610, 1582,
1609, 1582, 1610, 1589, 1609, 1589, 1610, 1590, 1609,
1590, 1610, 1588, 1580, 1588, 1581, 1588, 1582, 1588,
1605, 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585,
1588, 1580, 1588, 1581, 1588, 1582, 1588, 1605, 1587,
1607, 1588, 1607, 1591, 1605, 1587, 1580, 1587, 1581,
1587, 1582, 1588, 1580, 1588, 1581, 1588, 1582, 1591,
1605, 1592, 1605, 1575, 1611, 1575, 1611, 1578, 1580,
1605, 1578, 1581, 1580, 1578, 1581, 1580, 1578, 1581,
1605, 1578, 1582, 1605, 1578, 1605, 1580, 1578, 1605,
1581, 1578, 1605, 1582, 1580, 1605, 1581, 1580, 1605,
1581, 1581, 1605, 1610, 1581, 1605, 1609, 1587, 1581,
1580, 1587, 1580, 1581, 1587, 1580, 1609, 1587, 1605,
1581, 1587, 1605, 1581, 1587, 1605, 1580, 1587, 1605,
1605, 1587, 1605, 1605, 1589, 1581, 1581, 1589, 1581,
1581, 1589, 1605, 1605, 1588, 1581, 1605, 1588, 1581,
1605, 1588, 1580, 1610, 1588, 1605, 1582, 1588, 1605,
1582, 1588, 1605, 1605, 1588, 1605, 1605, 1590, 1581,
1609, 1590, 1582, 1605, 1590, 1582, 1605, 1591, 1605,
1581, 1591, 1605, 1581, 1591, 1605, 1605, 1591, 1605,
1610, 1593, 1580, 1605, 1593, 1605, 1605, 1593, 1605,
1605, 1593, 1605, 1609, 1594, 1605, 1605, 1594, 1605,
1610, 1594, 1605, 1609, 1601, 1582, 1605, 1601, 1582,
1605, 1602, 1605, 1581, 1602, 1605, 1605, 1604, 1581,
1605, 1604, 1581, 1610, 1604, 1581, 1609, 1604, 1580,
1580, 1604, 1580, 1580, 1604, 1582, 1605, 1604, 1582,
1605, 1604, 1605, 1581, 1604, 1605, 1581, 1605, 1581,
1580, 1605, 1581, 1605, 1605, 1581, 1610, 1605, 1580,
1581, 1605, 1580, 1605, 1605, 1582, 1580, 1605, 1582,
1605, 1605, 1580, 1582, 1607, 1605, 1580, 1607, 1605,
1605, 1606, 1581, 1605, 1606, 1581, 1609, 1606, 1580,
1605, 1606, 1580, 1605, 1606, 1580, 1609, 1606, 1605,
1610, 1606, 1605, 1609, 1610, 1605, 1605, 1610, 1605,
1605, 1576, 1582, 1610, 1578, 1580, 1610, 1578, 1580,
1609, 1578, 1582, 1610, 1578, 1582, 1609, 1578, 1605,
1610, 1578, 1605, 1609, 1580, 1605, 1610, 1580, 1581,
1609, 1580, 1605, 1609, 1587, 1582, 1609, 1589, 1581,
1610, 1588, 1581, 1610, 1590, 1581, 1610, 1604, 1580,
1610, 1604, 1605, 1610, 1610, 1581, 1610, 1610, 1580,
1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602, 1605,
1610, 1606, 1581, 1610, 1602, 1605, 1581, 1604, 1581,
1605, 1593, 1605, 1610, 1603, 1605, 1610, 1606, 1580,
1581, 1605, 1582, 1610, 1604, 1580, 1605, 1603, 1605,
1605, 1604, 1580, 1605, 1606, 1580, 1581, 1580, 1581,
1610, 1581, 1580, 1610, 1605, 1580, 1610, 1601, 1605,
1610, 1576, 1581, 1610, 1603, 1605, 1605, 1593, 1580,
1605, 1589, 1605, 1605, 1587, 1582, 1610, 1606, 1580,
1610, 1589, 1604, 1746, 1602, 1604, 1746, 1575, 1604,
1604, 1607, 1575, 1603, 1576, 1585, 1605, 1581, 1605,
1583, 1589, 1604, 1593, 1605, 1585, 1587, 1608, 1604,
1593, 1604, 1610, 1607, 1608, 1587, 1604, 1605, 1589,
1604, 1609, 1589, 1604, 1609, 32, 1575, 1604, 1604,
1607, 32, 1593, 1604, 1610, 1607, 32, 1608, 1587,
1604, 1605, 1580, 1604, 32, 1580, 1604, 1575, 1604,
1607, 1585, 1740, 1575, 1604, 44, 12289, 12290, 58,
59, 33, 63, 12310, 12311, 46, 46, 46, 46,
46, 8212, 8211, 95, 95, 40, 41, 123, 125,
12308, 12309, 12304, 12305, 12298, 12299, 12296, 12297, 12300,
12301, 12302, 12303, 91, 93, 32, 773, 32, 773,
32, 773, 32, 773, 95, 95, 95, 44, 12289,
46, 59, 58, 63, 33, 8212, 40, 41, 123,
125, 12308, 12309, 35, 38, 42, 43, 45, 60,
62, 61, 92, 36, 37, 64, 32, 1611, 1600,
1611, 32, 1612, 32, 1613, 32, 1614, 1600, 1614,
32, 1615, 1600, 1615, 32, 1616, 1600, 1616, 32,
1617, 1600, 1617, 32, 1618, 1600, 1618, 1569, 1575,
1619, 1575, 1619, 1575, 1620, 1575, 1620, 1608, 1620,
1608, 1620, 1575, 1621, 1575, 1621, 1610, 1620, 1610,
1620, 1610, 1620, 1610, 1620, 1575, 1575, 1576, 1576,
1576, 1576, 1577, 1577, 1578, 1578, 1578, 1578, 1579,
1579, 1579, 1579, 1580, 1580, 1580, 1580, 1581, 1581,
1581, 1581, 1582, 1582, 1582, 1582, 1583, 1583, 1584,
1584, 1585, 1585, 1586, 1586, 1587, 1587, 1587, 1587,
1588, 1588, 1588, 1588, 1589, 1589, 1589, 1589, 1590,
1590, 1590, 1590, 1591, 1591, 1591, 1591, 1592, 1592,
1592, 1592, 1593, 1593, 1593, 1593, 1594, 1594, 1594,
1594, 1601, 1601, 1601, 1601, 1602, 1602, 1602, 1602,
1603, 1603, 1603, 1603, 1604, 1604, 1604, 1604, 1605,
1605, 1605, 1605, 1606, 1606, 1606, 1606, 1607, 1607,
1607, 1607, 1608, 1608, 1609, 1609, 1610, 1610, 1610,
1610, 1604, 1575, 1619, 1604, 1575, 1619, 1604, 1575,
1620, 1604, 1575, 1620, 1604, 1575, 1621, 1604, 1575,
1621, 1604, 1575, 1604, 1575, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90,
91, 92, 93, 94, 95, 96, 97, 98, 99,
100, 101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 111, 112, 113, 114, 115, 116, 117,
118, 119, 120, 121, 122, 123, 124, 125, 126,
10629, 10630, 12290, 12300, 12301, 12289, 12539, 12530, 12449,
12451, 12453, 12455, 12457, 12515, 12517, 12519, 12483, 12540,
12450, 12452, 12454, 12456, 12458, 12459, 12461, 12463, 12465,
12467, 12469, 12471, 12473, 12475, 12477, 12479, 12481, 12484,
12486, 12488, 12490, 12491, 12492, 12493, 12494, 12495, 12498,
12501, 12504, 12507, 12510, 12511, 12512, 12513, 12514, 12516,
12518, 12520, 12521, 12522, 12523, 12524, 12525, 12527, 12531,
12441, 12442, 4448, 4352, 4353, 4522, 4354, 4524, 4525,
4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, 4533,
4378, 4358, 4359, 4360, 4385, 4361, 4362, 4363, 4364,
4365, 4366, 4367, 4368, 4369, 4370, 4449, 4450, 4451,
4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460,
4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469,
162, 163, 172, 32, 772, 166, 165, 8361, 9474,
8592, 8593, 8594, 8595, 9632, 9675, 720, 721, 230,
665, 595, 675, 43878, 677, 676, 598, 599, 7569,
600, 606, 681, 612, 610, 608, 667, 295, 668,
615, 644, 682, 683, 620, 122628, 42894, 622, 122629,
654, 122630, 248, 630, 631, 113, 634, 122632, 637,
638, 640, 680, 678, 43879, 679, 648, 11377, 655,
673, 674, 664, 448, 449, 450, 122634, 122654, 69785,
69818, 69787, 69818, 69797, 69818, 69937, 69927, 69938, 69927,
70471, 70462, 70471, 70487, 70841, 70842, 70841, 70832, 70841,
70845, 71096, 71087, 71097, 71087, 71989, 71984, 119127, 119141,
119128, 119141, 119128, 119141, 119150, 119128, 119141, 119151, 119128,
119141, 119152, 119128, 119141, 119153, 119128, 119141, 119154, 119225,
119141, 119226, 119141, 119225, 119141, 119150, 119226, 119141, 119150,
119225, 119141, 119151, 119226, 119141, 119151, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 80, 81, 82, 83, 84, 85,
86, 87, 88, 89, 90, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 97, 98, 99, 100, 101, 102,
103, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90,
97, 98, 99, 100, 101, 102, 103, 104, 105,
106, 107, 108, 109, 110, 111, 112, 113, 114,
115, 116, 117, 118, 119, 120, 121, 122, 65,
67, 68, 71, 74, 75, 78, 79, 80, 81,
83, 84, 85, 86, 87, 88, 89, 90, 97,
98, 99, 100, 102, 104, 105, 106, 107, 108,
109, 110, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 65, 66, 68, 69, 70, 71, 74,
75, 76, 77, 78, 79, 80, 81, 83, 84,
85, 86, 87, 88, 89, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 65, 66, 68, 69, 70,
71, 73, 74, 75, 76, 77, 79, 83, 84,
85, 86, 87, 88, 89, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122,
65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106,
107, 108, 109, 110, 111, 112, 113, 114, 115,
116, 117, 118, 119, 120, 121, 122, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 97, 98, 99,
100, 101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 111, 112, 113, 114, 115, 116, 117,
118, 119, 120, 121, 122, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 97, 98, 99, 100, 101,
102, 103, 104, 105, 106, 107, 108, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 305, 567, 913, 914, 915, 916, 917, 918,
919, 920, 921, 922, 923, 924, 925, 926, 927,
928, 929, 920, 931, 932, 933, 934, 935, 936,
937, 8711, 945, 946, 947, 948, 949, 950, 951,
952, 953, 954, 955, 956, 957, 958, 959, 960,
961, 962, 963, 964, 965, 966, 967, 968, 969,
8706, 949, 952, 954, 966, 961, 960, 913, 914,
915, 916, 917, 918, 919, 920, 921, 922, 923,
924, 925, 926, 927, 928, 929, 920, 931, 932,
933, 934, 935, 936, 937, 8711, 945, 946, 947,
948, 949, 950, 951, 952, 953, 954, 955, 956,
957, 958, 959, 960, 961, 962, 963, 964, 965,
966, 967, 968, 969, 8706, 949, 952, 954, 966,
961, 960, 913, 914, 915, 916, 917, 918, 919,
920, 921, 922, 923, 924, 925, 926, 927, 928,
929, 920, 931, 932, 933, 934, 935, 936, 937,
8711, 945, 946, 947, 948, 949, 950, 951, 952,
953, 954, 955, 956, 957, 958, 959, 960, 961,
962, 963, 964, 965, 966, 967, 968, 969, 8706,
949, 952, 954, 966, 961, 960, 913, 914, 915,
916, 917, 918, 919, 920, 921, 922, 923, 924,
925, 926, 927, 928, 929, 920, 931, 932, 933,
934, 935, 936, 937, 8711, 945, 946, 947, 948,
949, 950, 951, 952, 953, 954, 955, 956, 957,
958, 959, 960, 961, 962, 963, 964, 965, 966,
967, 968, 969, 8706, 949, 952, 954, 966, 961,
960, 913, 914, 915, 916, 917, 918, 919, 920,
921, 922, 923, 924, 925, 926, 927, 928, 929,
920, 931, 932, 933, 934, 935, 936, 937, 8711,
945, 946, 947, 948, 949, 950, 951, 952, 953,
954, 955, 956, 957, 958, 959, 960, 961, 962,
963, 964, 965, 966, 967, 968, 969, 8706, 949,
952, 954, 966, 961, 960, 988, 989, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57,
48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 1072, 1073, 1074, 1075, 1076, 1077,
1078, 1079, 1080, 1082, 1083, 1084, 1086, 1087, 1088,
1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1099,
1101, 1102, 42633, 1241, 1110, 1112, 1257, 1199, 1231,
1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080,
1082, 1083, 1086, 1087, 1089, 1091, 1092, 1093, 1094,
1095, 1096, 1098, 1099, 1169, 1110, 1109, 1119, 1195,
42577, 1201, 1575, 1576, 1580, 1583, 1608, 1586, 1581,
1591, 1610, 1603, 1604, 1605, 1606, 1587, 1593, 1601,
1589, 1602, 1585, 1588, 1578, 1579, 1582, 1584, 1590,
1592, 1594, 1646, 1722, 1697, 1647, 1576, 1580, 1607,
1581, 1610, 1603, 1604, 1605, 1606, 1587, 1593, 1601,
1589, 1602, 1588, 1578, 1579, 1582, 1590, 1594, 1580,
1581, 1610, 1604, 1606, 1587, 1593, 1589, 1602, 1588,
1582, 1590, 1594, 1722, 1647, 1576, 1580, 1607, 1581,
1591, 1610, 1603, 1605, 1606, 1587, 1593, 1601, 1589,
1602, 1588, 1578, 1579, 1582, 1590, 1592, 1594, 1646,
1697, 1575, 1576, 1580, 1583, 1607, 1608, 1586, 1581,
1591, 1610, 1604, 1605, 1606, 1587, 1593, 1601, 1589,
1602, 1585, 1588, 1578, 1579, 1582, 1584, 1590, 1592,
1594, 1576, 1580, 1583, 1608, 1586, 1581, 1591, 1610,
1604, 1605, 1606, 1587, 1593, 1601, 1589, 1602, 1585,
1588, 1578, 1579, 1582, 1584, 1590, 1592, 1594, 48,
46, 48, 44, 49, 44, 50, 44, 51, 44,
52, 44, 53, 44, 54, 44, 55, 44, 56,
44, 57, 44, 40, 65, 41, 40, 66, 41,
40, 67, 41, 40, 68, 41, 40, 69, 41,
40, 70, 41, 40, 71, 41, 40, 72, 41,
40, 73, 41, 40, 74, 41, 40, 75, 41,
40, 76, 41, 40, 77, 41, 40, 78, 41,
40, 79, 41, 40, 80, 41, 40, 81, 41,
40, 82, 41, 40, 83, 41, 40, 84, 41,
40, 85, 41, 40, 86, 41, 40, 87, 41,
40, 88, 41, 40, 89, 41, 40, 90, 41,
12308, 83, 12309, 67, 82, 67, 68, 87, 90,
65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 72,
86, 77, 86, 83, 68, 83, 83, 80, 80,
86, 87, 67, 77, 67, 77, 68, 77, 82,
68, 74, 12411, 12363, 12467, 12467, 12469, 25163, 23383,
21452, 12486, 12441, 20108, 22810, 35299, 22825, 20132, 26144,
28961, 26009, 21069, 24460, 20877, 26032, 21021, 32066, 29983,
36009, 22768, 21561, 28436, 25237, 25429, 19968, 19977, 36938,
24038, 20013, 21491, 25351, 36208, 25171, 31105, 31354, 21512,
28288, 26377, 26376, 30003, 21106, 21942, 37197, 12308, 26412,
12309, 12308, 19977, 12309, 12308, 20108, 12309, 12308, 23433,
12309, 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423,
12309, 12308, 21213, 12309, 12308, 25943, 12309, 24471, 21487,
48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 20029, 20024, 20033, 131362, 20320, 20398, 20411, 20482,
20602, 20633, 20711, 20687, 13470, 132666, 20813, 20820, 20836,
20855, 132380, 13497, 20839, 20877, 132427, 20887, 20900, 20172,
20908, 20917, 168415, 20981, 20995, 13535, 21051, 21062, 21106,
21111, 13589, 21191, 21193, 21220, 21242, 21253, 21254, 21271,
21321, 21329, 21338, 21363, 21373, 21375, 21375, 21375, 133676,
28784, 21450, 21471, 133987, 21483, 21489, 21510, 21662, 21560,
21576, 21608, 21666, 21750, 21776, 21843, 21859, 21892, 21892,
21913, 21931, 21939, 21954, 22294, 22022, 22295, 22097, 22132,
20999, 22766, 22478, 22516, 22541, 22411, 22578, 22577, 22700,
136420, 22770, 22775, 22790, 22810, 22818, 22882, 136872, 136938,
23020, 23067, 23079, 23000, 23142, 14062, 14076, 23304, 23358,
23358, 137672, 23491, 23512, 23527, 23539, 138008, 23551, 23558,
24403, 23586, 14209, 23648, 23662, 23744, 23693, 138724, 23875,
138726, 23918, 23915, 23932, 24033, 24034, 14383, 24061, 24104,
24125, 24169, 14434, 139651, 14460, 24240, 24243, 24246, 24266,
172946, 24318, 140081, 140081, 33281, 24354, 24354, 14535, 144056,
156122, 24418, 24427, 14563, 24474, 24525, 24535, 24569, 24705,
14650, 14620, 24724, 141012, 24775, 24904, 24908, 24910, 24908,
24954, 24974, 25010, 24996, 25007, 25054, 25074, 25078, 25104,
25115, 25181, 25265, 25300, 25424, 142092, 25405, 25340, 25448,
25475, 25572, 142321, 25634, 25541, 25513, 14894, 25705, 25726,
25757, 25719, 14956, 25935, 25964, 143370, 26083, 26360, 26185,
15129, 26257, 15112, 15076, 20882, 20885, 26368, 26268, 32941,
17369, 26391, 26395, 26401, 26462, 26451, 144323, 15177, 26618,
26501, 26706, 26757, 144493, 26766, 26655, 26900, 15261, 26946,
27043, 27114, 27304, 145059, 27355, 15384, 27425, 145575, 27476,
15438, 27506, 27551, 27578, 27579, 146061, 138507, 146170, 27726,
146620, 27839, 27853, 27751, 27926, 27966, 28023, 27969, 28009,
28024, 28037, 146718, 27956, 28207, 28270, 15667, 28363, 28359,
147153, 28153, 28526, 147294, 147342, 28614, 28729, 28702, 28699,
15766, 28746, 28797, 28791, 28845, 132389, 28997, 148067, 29084,
148395, 29224, 29237, 29264, 149000, 29312, 29333, 149301, 149524,
29562, 29579, 16044, 29605, 16056, 16056, 29767, 29788, 29809,
29829, 29898, 16155, 29988, 150582, 30014, 150674, 30064, 139679,
30224, 151457, 151480, 151620, 16380, 16392, 30452, 151795, 151794,
151833, 151859, 30494, 30495, 30495, 30538, 16441, 30603, 16454,
16534, 152605, 30798, 30860, 30924, 16611, 153126, 31062, 153242,
153285, 31119, 31211, 16687, 31296, 31306, 31311, 153980, 154279,
154279, 31470, 16898, 154539, 31686, 31689, 16935, 154752, 31954,
17056, 31976, 31971, 32000, 155526, 32099, 17153, 32199, 32258,
32325, 17204, 156200, 156231, 17241, 156377, 32634, 156478, 32661,
32762, 32773, 156890, 156963, 32864, 157096, 32880, 144223, 17365,
32946, 33027, 17419, 33086, 23221, 157607, 157621, 144275, 144284,
33281, 33284, 36766, 17515, 33425, 33419, 33437, 21171, 33457,
33459, 33469, 33510, 158524, 33509, 33565, 33635, 33709, 33571,
33725, 33767, 33879, 33619, 33738, 33740, 33756, 158774, 159083,
158933, 17707, 34033, 34035, 34070, 160714, 34148, 159532, 17757,
17761, 159665, 159954, 17771, 34384, 34396, 34407, 34409, 34473,
34440, 34574, 34530, 34681, 34600, 34667, 34694, 17879, 34785,
34817, 17913, 34912, 34915, 161383, 35031, 35038, 17973, 35066,
13499, 161966, 162150, 18110, 18119, 35488, 35565, 35722, 35925,
162984, 36011, 36033, 36123, 36215, 163631, 133124, 36299, 36284,
36336, 133342, 36564, 36664, 165330, 165357, 37012, 37105, 37137,
165678, 37147, 37432, 37591, 37592, 37500, 37881, 37909, 166906,
38283, 18837, 38327, 167287, 18918, 38595, 23986, 38691, 168261,
168474, 19054, 19062, 38880, 168970, 19122, 169110, 38923, 38923,
38953, 169398, 39138, 19251, 39209, 39335, 39362, 39422, 19406,
170800, 39698, 40000, 40189, 19662, 19693, 40295, 172238, 19704,
172293, 172558, 172689, 40635, 19798, 40697, 40702, 40709, 40719,
40726, 40763, 173568};
const uint8_t canonical_combining_class_index[4352] = {
0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0,
15, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 24, 25, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 28, 29, 30,
31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 32, 0, 0, 33, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0,
37, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 52,
53, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 55, 56, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 61, 56, 62, 0, 63, 0, 0, 0, 64, 65, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0};
const uint8_t canonical_combining_class_block[67][256] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220,
220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220,
220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220,
220, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230,
230, 230, 220, 220, 0, 230, 230, 230, 220, 220, 220, 220, 230, 232, 220,
220, 230, 233, 234, 234, 233, 234, 234, 233, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230,
230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 230, 230, 230, 230,
220, 230, 230, 230, 222, 220, 230, 230, 230, 230, 230, 230, 220, 220, 220,
220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25,
0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, 220, 230, 230, 230,
230, 230, 220, 230, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230,
230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220,
220, 230, 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230,
230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230,
230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230,
230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220,
220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 230, 220, 220, 220, 230, 230, 230, 230, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 220, 220, 220,
220, 220, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 0, 220, 230, 230, 220, 230, 230, 220, 230, 230, 230, 220, 220, 220,
27, 28, 29, 230, 230, 230, 220, 230, 230, 220, 220, 230, 230, 230, 230,
230},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 230, 220, 230, 230, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 103, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 118, 118, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 122, 122, 122, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 0, 132, 0, 0, 0,
0, 0, 130, 130, 130, 130, 0, 0, 130, 0, 230, 230, 9, 0, 230,
230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230,
230, 230, 230, 230, 230, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230,
230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 0, 220, 220, 230, 230,
220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 230, 230, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230, 230, 230,
230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230,
230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220, 230,
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0,
0, 0, 0, 0, 230, 0, 0, 0, 230, 230, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 220,
230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220, 202, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 232, 228, 228, 220, 218, 230, 233, 220, 230,
220},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0,
0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220,
230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 218, 228, 232, 222, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230,
0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220,
220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0,
230, 230, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 230, 230, 230, 230, 230, 230, 230, 220, 220, 220, 220, 220, 220,
220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0,
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220,
230, 230, 230, 220, 230, 220, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 230, 220, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0,
230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 7, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216,
216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220,
220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230, 230, 230,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230, 230,
230, 230, 230, 230, 0, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 232, 220, 230, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220, 220, 220, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
const uint8_t composition_index[4352] = {
0, 1, 2, 3, 4, 5, 6, 5, 5, 7, 5, 8, 9, 10, 5, 5, 11, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 12, 5, 5, 13, 14, 5, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 18, 19, 5, 20, 21, 22, 5, 5, 5, 23, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
const uint16_t composition_block[67][257] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 5, 7, 7, 7, 39, 45, 55, 67, 101, 103, 117, 131, 161,
163, 173, 185, 191, 209, 241, 245, 245, 261, 275, 289, 327, 331, 343, 347,
365, 377, 377, 377, 377, 377, 377, 377, 409, 415, 425, 437, 471, 473, 487,
503, 531, 535, 545, 557, 563, 581, 613, 617, 617, 633, 647, 663, 701, 705,
719, 723, 743, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755,
755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755,
755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755,
755, 755, 755, 755, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
769, 769, 771, 773, 777, 779, 779, 779, 787, 787, 787, 787, 787, 789, 789,
789, 789, 789, 797, 803, 805, 805, 807, 807, 807, 807, 815, 815, 815, 815,
815, 815, 823, 823, 825, 827, 831, 833, 833, 833, 841, 841, 841, 841, 841,
843, 843, 843, 843, 843, 851, 857, 859, 859, 861, 861, 861, 861, 869, 869,
869, 869},
{869, 869, 869, 877, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885,
885, 885, 885, 885, 889, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893,
893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893,
893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893,
893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893,
893, 893, 897, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901,
901, 903, 905, 905, 905, 905, 905, 907, 909, 909, 909, 909, 909, 909, 909,
911, 913, 915, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917,
917, 917, 917, 917, 917, 917, 917, 917, 919, 919, 919, 919, 919, 919, 919,
919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919,
919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 929, 939, 939, 939,
939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 949, 959, 959, 959,
959, 959, 959, 959, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961,
961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961,
961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961,
961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 963, 965, 965, 965, 965,
965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965,
965, 965},
{965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965,
965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965,
965, 965, 965, 965, 965, 965, 965, 965, 965, 967, 969, 971, 973, 973, 973,
973, 973, 975, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979},
{979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979,
979, 979, 993, 993, 993, 993, 1001, 1001, 1011, 1011, 1025, 1025,
1025, 1025, 1025, 1025, 1033, 1033, 1035, 1035, 1035, 1035, 1047, 1047,
1047, 1047, 1057, 1057, 1057, 1059, 1059, 1061, 1061, 1061, 1077, 1077,
1077, 1077, 1085, 1085, 1097, 1097, 1113, 1113, 1113, 1113, 1113, 1113,
1121, 1121, 1125, 1125, 1125, 1125, 1141, 1141, 1141, 1141, 1153, 1159,
1165, 1165, 1165, 1167, 1167, 1167, 1167, 1171, 1171, 1171, 1171, 1171,
1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171,
1171, 1171, 1171, 1171, 1171},
{1171, 1171, 1171, 1171, 1171, 1171, 1171, 1173, 1173, 1173, 1173, 1173,
1173, 1173, 1173, 1173, 1173, 1177, 1177, 1177, 1179, 1179, 1185, 1189,
1191, 1199, 1199, 1201, 1201, 1201, 1201, 1203, 1203, 1203, 1203, 1203,
1211, 1211, 1211, 1211, 1213, 1213, 1213, 1213, 1215, 1215, 1217, 1217,
1217, 1221, 1221, 1221, 1223, 1223, 1229, 1233, 1235, 1243, 1243, 1245,
1245, 1245, 1245, 1247, 1247, 1247, 1247, 1247, 1255, 1255, 1255, 1255,
1257, 1257, 1257, 1257, 1259, 1259, 1261, 1261, 1261, 1261, 1261, 1261,
1261, 1261, 1261, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263,
1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263,
1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1265, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
1267, 1269, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
1271, 1271, 1271, 1271, 1271, 1273, 1275, 1275, 1275, 1275, 1275, 1275,
1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275,
1275, 1275, 1275, 1275, 1275},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275,
1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275,
1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275,
1275, 1275, 1275, 1275, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
1281, 1283, 1283, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285,
1285, 1285, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
1287, 1287, 1287, 1287, 1287, 1287, 1287, 1289, 1289, 1289, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291},
{1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291,
1291, 1291, 1291, 1291, 1291, 1293, 1293, 1293, 1293, 1293, 1293, 1293,
1293, 1295, 1295, 1295, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301},
{1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307,
1307, 1307, 1307, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309,
1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309,
1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309,
1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309,
1309, 1309, 1309, 1309, 1309, 1309, 1309, 1313, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315},
{1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315,
1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317,
1319, 1319, 1319, 1319, 1319, 1319, 1319, 1325, 1325, 1325, 1325, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327},
{1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1331,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333,
1333, 1333, 1339, 1339, 1339, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1341, 1341, 1341},
{1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341,
1341, 1341, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343,
1343, 1343, 1343, 1343, 1343},
{1343, 1343, 1343, 1343, 1343, 1343, 1345, 1345, 1347, 1347, 1349, 1349,
1351, 1351, 1353, 1353, 1353, 1353, 1355, 1355, 1355, 1355, 1355, 1355,
1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355,
1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355,
1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1357,
1357, 1359, 1359, 1361, 1363, 1363, 1363, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365},
{1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365,
1365, 1365, 1365, 1365, 1365, 1365, 1365, 1367, 1369, 1369, 1369, 1369,
1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369,
1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369,
1369, 1369, 1369, 1369, 1369, 1369, 1369, 1371, 1373, 1373, 1373, 1373,
1373, 1373, 1373, 1375, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377,
1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377,
1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377,
1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377,
1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377,
1377, 1377, 1377, 1377, 1377, 1381, 1385, 1385, 1385, 1385, 1385, 1385,
1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385,
1385, 1385, 1385, 1385, 1385, 1387, 1389, 1389, 1389, 1389, 1389, 1389,
1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389,
1389, 1391, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393,
1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393,
1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393,
1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393,
1393, 1393, 1393, 1393, 1393},
{1393, 1401, 1409, 1411, 1413, 1415, 1417, 1419, 1421, 1429, 1437, 1439,
1441, 1443, 1445, 1447, 1449, 1453, 1457, 1457, 1457, 1457, 1457, 1457,
1457, 1461, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1473, 1481, 1483,
1485, 1487, 1489, 1491, 1493, 1501, 1509, 1511, 1513, 1515, 1517, 1519,
1521, 1527, 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1539, 1545, 1545,
1545, 1545, 1545, 1545, 1545, 1549, 1553, 1553, 1553, 1553, 1553, 1553,
1553, 1557, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1567, 1573, 1573,
1573, 1573, 1573, 1573, 1573, 1573, 1579, 1579, 1579, 1579, 1579, 1579,
1579, 1587, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1615, 1623, 1625,
1627, 1629, 1631, 1633, 1635, 1637, 1637, 1637, 1637, 1639, 1639, 1639,
1639, 1639, 1639, 1639, 1639, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
1641, 1641, 1641, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643,
1649, 1649, 1649, 1649, 1649, 1649, 1649, 1651, 1651, 1651, 1651, 1651,
1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651,
1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651,
1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651,
1651, 1651, 1651, 1651, 1651, 1651, 1651, 1653, 1653, 1653, 1653, 1653,
1653, 1653, 1653, 1659, 1659},
{1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
1659, 1661, 1661, 1663, 1663, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
1665, 1665, 1665, 1665, 1665, 1667, 1667, 1669, 1669, 1671, 1671, 1671,
1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671,
1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671,
1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671,
1671, 1671, 1671, 1671, 1671},
{1671, 1671, 1671, 1671, 1673, 1673, 1673, 1673, 1673, 1675, 1675, 1675,
1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677,
1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677,
1679, 1679, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
1681, 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1685, 1685, 1687, 1687,
1687, 1689, 1689, 1689, 1689, 1689, 1691, 1691, 1691, 1691, 1691, 1691,
1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691,
1691, 1691, 1693, 1693, 1693, 1695, 1697, 1697, 1697, 1697, 1697, 1697,
1697, 1697, 1697, 1697, 1697, 1697, 1697, 1699, 1701, 1701, 1701, 1703,
1705, 1705, 1705, 1707, 1709, 1711, 1713, 1713, 1713, 1713, 1713, 1715,
1717, 1717, 1717, 1719, 1721, 1721, 1721, 1721, 1721, 1721, 1721, 1721,
1721, 1721, 1723, 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1725,
1725, 1725, 1725, 1725, 1725, 1725, 1725, 1727, 1727, 1727, 1727, 1727,
1727, 1729, 1731, 1731, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1735,
1737, 1739, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741},
{1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741,
1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1743,
1743, 1743, 1743, 1743, 1745, 1745, 1747, 1747, 1749, 1749, 1751, 1751,
1753, 1753, 1755, 1755, 1757, 1757, 1759, 1759, 1761, 1761, 1763, 1763,
1765, 1765, 1767, 1767, 1767, 1769, 1769, 1771, 1771, 1773, 1773, 1773,
1773, 1773, 1773, 1773, 1777, 1777, 1777, 1781, 1781, 1781, 1785, 1785,
1785, 1789, 1789, 1789, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793,
1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793,
1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793,
1793, 1793, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1797,
1797, 1797, 1797, 1797, 1799, 1799, 1801, 1801, 1803, 1803, 1805, 1805,
1807, 1807, 1809, 1809, 1811, 1811, 1813, 1813, 1815, 1815, 1817, 1817,
1819, 1819, 1821, 1821, 1821, 1823, 1823, 1825, 1825, 1827, 1827, 1827,
1827, 1827, 1827, 1827, 1831, 1831, 1831, 1835, 1835, 1835, 1839, 1839,
1839, 1843, 1843, 1843, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847,
1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847,
1849, 1851, 1853, 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855,
1855, 1855, 1857, 1857, 1857},
{1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857,
1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1859, 1859,
1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863},
{1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863,
1863, 1863, 1865, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867},
{1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871},
{1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871,
1871, 1871, 1871, 1871, 1871, 1871, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877},
{1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
1877, 1877, 1877, 1877, 1877, 1879, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881},
{1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
1881, 1881, 1881, 1881, 1881, 1881, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
1883, 1883, 1883, 1883, 1883}};
const char32_t composition_data[1883] = {
0, 824, 8814, 824, 8800, 824, 8815, 768, 192, 769, 193,
770, 194, 771, 195, 772, 256, 774, 258, 775, 550, 776,
196, 777, 7842, 778, 197, 780, 461, 783, 512, 785, 514,
803, 7840, 805, 7680, 808, 260, 775, 7682, 803, 7684, 817,
7686, 769, 262, 770, 264, 775, 266, 780, 268, 807, 199,
775, 7690, 780, 270, 803, 7692, 807, 7696, 813, 7698, 817,
7694, 768, 200, 769, 201, 770, 202, 771, 7868, 772, 274,
774, 276, 775, 278, 776, 203, 777, 7866, 780, 282, 783,
516, 785, 518, 803, 7864, 807, 552, 808, 280, 813, 7704,
816, 7706, 775, 7710, 769, 500, 770, 284, 772, 7712, 774,
286, 775, 288, 780, 486, 807, 290, 770, 292, 775, 7714,
776, 7718, 780, 542, 803, 7716, 807, 7720, 814, 7722, 768,
204, 769, 205, 770, 206, 771, 296, 772, 298, 774, 300,
775, 304, 776, 207, 777, 7880, 780, 463, 783, 520, 785,
522, 803, 7882, 808, 302, 816, 7724, 770, 308, 769, 7728,
780, 488, 803, 7730, 807, 310, 817, 7732, 769, 313, 780,
317, 803, 7734, 807, 315, 813, 7740, 817, 7738, 769, 7742,
775, 7744, 803, 7746, 768, 504, 769, 323, 771, 209, 775,
7748, 780, 327, 803, 7750, 807, 325, 813, 7754, 817, 7752,
768, 210, 769, 211, 770, 212, 771, 213, 772, 332, 774,
334, 775, 558, 776, 214, 777, 7886, 779, 336, 780, 465,
783, 524, 785, 526, 795, 416, 803, 7884, 808, 490, 769,
7764, 775, 7766, 769, 340, 775, 7768, 780, 344, 783, 528,
785, 530, 803, 7770, 807, 342, 817, 7774, 769, 346, 770,
348, 775, 7776, 780, 352, 803, 7778, 806, 536, 807, 350,
775, 7786, 780, 356, 803, 7788, 806, 538, 807, 354, 813,
7792, 817, 7790, 768, 217, 769, 218, 770, 219, 771, 360,
772, 362, 774, 364, 776, 220, 777, 7910, 778, 366, 779,
368, 780, 467, 783, 532, 785, 534, 795, 431, 803, 7908,
804, 7794, 808, 370, 813, 7798, 816, 7796, 771, 7804, 803,
7806, 768, 7808, 769, 7810, 770, 372, 775, 7814, 776, 7812,
803, 7816, 775, 7818, 776, 7820, 768, 7922, 769, 221, 770,
374, 771, 7928, 772, 562, 775, 7822, 776, 376, 777, 7926,
803, 7924, 769, 377, 770, 7824, 775, 379, 780, 381, 803,
7826, 817, 7828, 768, 224, 769, 225, 770, 226, 771, 227,
772, 257, 774, 259, 775, 551, 776, 228, 777, 7843, 778,
229, 780, 462, 783, 513, 785, 515, 803, 7841, 805, 7681,
808, 261, 775, 7683, 803, 7685, 817, 7687, 769, 263, 770,
265, 775, 267, 780, 269, 807, 231, 775, 7691, 780, 271,
803, 7693, 807, 7697, 813, 7699, 817, 7695, 768, 232, 769,
233, 770, 234, 771, 7869, 772, 275, 774, 277, 775, 279,
776, 235, 777, 7867, 780, 283, 783, 517, 785, 519, 803,
7865, 807, 553, 808, 281, 813, 7705, 816, 7707, 775, 7711,
769, 501, 770, 285, 772, 7713, 774, 287, 775, 289, 780,
487, 807, 291, 770, 293, 775, 7715, 776, 7719, 780, 543,
803, 7717, 807, 7721, 814, 7723, 817, 7830, 768, 236, 769,
237, 770, 238, 771, 297, 772, 299, 774, 301, 776, 239,
777, 7881, 780, 464, 783, 521, 785, 523, 803, 7883, 808,
303, 816, 7725, 770, 309, 780, 496, 769, 7729, 780, 489,
803, 7731, 807, 311, 817, 7733, 769, 314, 780, 318, 803,
7735, 807, 316, 813, 7741, 817, 7739, 769, 7743, 775, 7745,
803, 7747, 768, 505, 769, 324, 771, 241, 775, 7749, 780,
328, 803, 7751, 807, 326, 813, 7755, 817, 7753, 768, 242,
769, 243, 770, 244, 771, 245, 772, 333, 774, 335, 775,
559, 776, 246, 777, 7887, 779, 337, 780, 466, 783, 525,
785, 527, 795, 417, 803, 7885, 808, 491, 769, 7765, 775,
7767, 769, 341, 775, 7769, 780, 345, 783, 529, 785, 531,
803, 7771, 807, 343, 817, 7775, 769, 347, 770, 349, 775,
7777, 780, 353, 803, 7779, 806, 537, 807, 351, 775, 7787,
776, 7831, 780, 357, 803, 7789, 806, 539, 807, 355, 813,
7793, 817, 7791, 768, 249, 769, 250, 770, 251, 771, 361,
772, 363, 774, 365, 776, 252, 777, 7911, 778, 367, 779,
369, 780, 468, 783, 533, 785, 535, 795, 432, 803, 7909,
804, 7795, 808, 371, 813, 7799, 816, 7797, 771, 7805, 803,
7807, 768, 7809, 769, 7811, 770, 373, 775, 7815, 776, 7813,
778, 7832, 803, 7817, 775, 7819, 776, 7821, 768, 7923, 769,
253, 770, 375, 771, 7929, 772, 563, 775, 7823, 776, 255,
777, 7927, 778, 7833, 803, 7925, 769, 378, 770, 7825, 775,
380, 780, 382, 803, 7827, 817, 7829, 768, 8173, 769, 901,
834, 8129, 768, 7846, 769, 7844, 771, 7850, 777, 7848, 772,
478, 769, 506, 769, 508, 772, 482, 769, 7688, 768, 7872,
769, 7870, 771, 7876, 777, 7874, 769, 7726, 768, 7890, 769,
7888, 771, 7894, 777, 7892, 769, 7756, 772, 556, 776, 7758,
772, 554, 769, 510, 768, 475, 769, 471, 772, 469, 780,
473, 768, 7847, 769, 7845, 771, 7851, 777, 7849, 772, 479,
769, 507, 769, 509, 772, 483, 769, 7689, 768, 7873, 769,
7871, 771, 7877, 777, 7875, 769, 7727, 768, 7891, 769, 7889,
771, 7895, 777, 7893, 769, 7757, 772, 557, 776, 7759, 772,
555, 769, 511, 768, 476, 769, 472, 772, 470, 780, 474,
768, 7856, 769, 7854, 771, 7860, 777, 7858, 768, 7857, 769,
7855, 771, 7861, 777, 7859, 768, 7700, 769, 7702, 768, 7701,
769, 7703, 768, 7760, 769, 7762, 768, 7761, 769, 7763, 775,
7780, 775, 7781, 775, 7782, 775, 7783, 769, 7800, 769, 7801,
776, 7802, 776, 7803, 775, 7835, 768, 7900, 769, 7898, 771,
7904, 777, 7902, 803, 7906, 768, 7901, 769, 7899, 771, 7905,
777, 7903, 803, 7907, 768, 7914, 769, 7912, 771, 7918, 777,
7916, 803, 7920, 768, 7915, 769, 7913, 771, 7919, 777, 7917,
803, 7921, 780, 494, 772, 492, 772, 493, 772, 480, 772,
481, 774, 7708, 774, 7709, 772, 560, 772, 561, 780, 495,
768, 8122, 769, 902, 772, 8121, 774, 8120, 787, 7944, 788,
7945, 837, 8124, 768, 8136, 769, 904, 787, 7960, 788, 7961,
768, 8138, 769, 905, 787, 7976, 788, 7977, 837, 8140, 768,
8154, 769, 906, 772, 8153, 774, 8152, 776, 938, 787, 7992,
788, 7993, 768, 8184, 769, 908, 787, 8008, 788, 8009, 788,
8172, 768, 8170, 769, 910, 772, 8169, 774, 8168, 776, 939,
788, 8025, 768, 8186, 769, 911, 787, 8040, 788, 8041, 837,
8188, 837, 8116, 837, 8132, 768, 8048, 769, 940, 772, 8113,
774, 8112, 787, 7936, 788, 7937, 834, 8118, 837, 8115, 768,
8050, 769, 941, 787, 7952, 788, 7953, 768, 8052, 769, 942,
787, 7968, 788, 7969, 834, 8134, 837, 8131, 768, 8054, 769,
943, 772, 8145, 774, 8144, 776, 970, 787, 7984, 788, 7985,
834, 8150, 768, 8056, 769, 972, 787, 8000, 788, 8001, 787,
8164, 788, 8165, 768, 8058, 769, 973, 772, 8161, 774, 8160,
776, 971, 787, 8016, 788, 8017, 834, 8166, 768, 8060, 769,
974, 787, 8032, 788, 8033, 834, 8182, 837, 8179, 768, 8146,
769, 912, 834, 8151, 768, 8162, 769, 944, 834, 8167, 837,
8180, 769, 979, 776, 980, 776, 1031, 774, 1232, 776, 1234,
769, 1027, 768, 1024, 774, 1238, 776, 1025, 774, 1217, 776,
1244, 776, 1246, 768, 1037, 772, 1250, 774, 1049, 776, 1252,
769, 1036, 776, 1254, 772, 1262, 774, 1038, 776, 1264, 779,
1266, 776, 1268, 776, 1272, 776, 1260, 774, 1233, 776, 1235,
769, 1107, 768, 1104, 774, 1239, 776, 1105, 774, 1218, 776,
1245, 776, 1247, 768, 1117, 772, 1251, 774, 1081, 776, 1253,
769, 1116, 776, 1255, 772, 1263, 774, 1118, 776, 1265, 779,
1267, 776, 1269, 776, 1273, 776, 1261, 776, 1111, 783, 1142,
783, 1143, 776, 1242, 776, 1243, 776, 1258, 776, 1259, 1619,
1570, 1620, 1571, 1621, 1573, 1620, 1572, 1620, 1574, 1620, 1730,
1620, 1747, 1620, 1728, 2364, 2345, 2364, 2353, 2364, 2356, 2494,
2507, 2519, 2508, 2878, 2891, 2902, 2888, 2903, 2892, 3031, 2964,
3006, 3018, 3031, 3020, 3006, 3019, 3158, 3144, 3285, 3264, 3266,
3274, 3285, 3271, 3286, 3272, 3285, 3275, 3390, 3402, 3415, 3404,
3390, 3403, 3530, 3546, 3535, 3548, 3551, 3550, 3530, 3549, 4142,
4134, 6965, 6918, 6965, 6920, 6965, 6922, 6965, 6924, 6965, 6926,
6965, 6930, 6965, 6971, 6965, 6973, 6965, 6976, 6965, 6977, 6965,
6979, 772, 7736, 772, 7737, 772, 7772, 772, 7773, 775, 7784,
775, 7785, 770, 7852, 774, 7862, 770, 7853, 774, 7863, 770,
7878, 770, 7879, 770, 7896, 770, 7897, 768, 7938, 769, 7940,
834, 7942, 837, 8064, 768, 7939, 769, 7941, 834, 7943, 837,
8065, 837, 8066, 837, 8067, 837, 8068, 837, 8069, 837, 8070,
837, 8071, 768, 7946, 769, 7948, 834, 7950, 837, 8072, 768,
7947, 769, 7949, 834, 7951, 837, 8073, 837, 8074, 837, 8075,
837, 8076, 837, 8077, 837, 8078, 837, 8079, 768, 7954, 769,
7956, 768, 7955, 769, 7957, 768, 7962, 769, 7964, 768, 7963,
769, 7965, 768, 7970, 769, 7972, 834, 7974, 837, 8080, 768,
7971, 769, 7973, 834, 7975, 837, 8081, 837, 8082, 837, 8083,
837, 8084, 837, 8085, 837, 8086, 837, 8087, 768, 7978, 769,
7980, 834, 7982, 837, 8088, 768, 7979, 769, 7981, 834, 7983,
837, 8089, 837, 8090, 837, 8091, 837, 8092, 837, 8093, 837,
8094, 837, 8095, 768, 7986, 769, 7988, 834, 7990, 768, 7987,
769, 7989, 834, 7991, 768, 7994, 769, 7996, 834, 7998, 768,
7995, 769, 7997, 834, 7999, 768, 8002, 769, 8004, 768, 8003,
769, 8005, 768, 8010, 769, 8012, 768, 8011, 769, 8013, 768,
8018, 769, 8020, 834, 8022, 768, 8019, 769, 8021, 834, 8023,
768, 8027, 769, 8029, 834, 8031, 768, 8034, 769, 8036, 834,
8038, 837, 8096, 768, 8035, 769, 8037, 834, 8039, 837, 8097,
837, 8098, 837, 8099, 837, 8100, 837, 8101, 837, 8102, 837,
8103, 768, 8042, 769, 8044, 834, 8046, 837, 8104, 768, 8043,
769, 8045, 834, 8047, 837, 8105, 837, 8106, 837, 8107, 837,
8108, 837, 8109, 837, 8110, 837, 8111, 837, 8114, 837, 8130,
837, 8178, 837, 8119, 768, 8141, 769, 8142, 834, 8143, 837,
8135, 837, 8183, 768, 8157, 769, 8158, 834, 8159, 824, 8602,
824, 8603, 824, 8622, 824, 8653, 824, 8655, 824, 8654, 824,
8708, 824, 8713, 824, 8716, 824, 8740, 824, 8742, 824, 8769,
824, 8772, 824, 8775, 824, 8777, 824, 8813, 824, 8802, 824,
8816, 824, 8817, 824, 8820, 824, 8821, 824, 8824, 824, 8825,
824, 8832, 824, 8833, 824, 8928, 824, 8929, 824, 8836, 824,
8837, 824, 8840, 824, 8841, 824, 8930, 824, 8931, 824, 8876,
824, 8877, 824, 8878, 824, 8879, 824, 8938, 824, 8939, 824,
8940, 824, 8941, 12441, 12436, 12441, 12364, 12441, 12366, 12441, 12368,
12441, 12370, 12441, 12372, 12441, 12374, 12441, 12376, 12441, 12378, 12441,
12380, 12441, 12382, 12441, 12384, 12441, 12386, 12441, 12389, 12441, 12391,
12441, 12393, 12441, 12400, 12442, 12401, 12441, 12403, 12442, 12404, 12441,
12406, 12442, 12407, 12441, 12409, 12442, 12410, 12441, 12412, 12442, 12413,
12441, 12446, 12441, 12532, 12441, 12460, 12441, 12462, 12441, 12464, 12441,
12466, 12441, 12468, 12441, 12470, 12441, 12472, 12441, 12474, 12441, 12476,
12441, 12478, 12441, 12480, 12441, 12482, 12441, 12485, 12441, 12487, 12441,
12489, 12441, 12496, 12442, 12497, 12441, 12499, 12442, 12500, 12441, 12502,
12442, 12503, 12441, 12505, 12442, 12506, 12441, 12508, 12442, 12509, 12441,
12535, 12441, 12536, 12441, 12537, 12441, 12538, 12441, 12542, 69818, 69786,
69818, 69788, 69818, 69803, 69927, 69934, 69927, 69935, 70462, 70475, 70487,
70476, 70832, 70844, 70842, 70843, 70845, 70846, 71087, 71098, 71087, 71099,
71984, 71992};
} // namespace ada::idna
#endif // ADA_IDNA_NORMALIZATION_TABLES_H
/* end file src/normalization_tables.cpp */
namespace ada::idna {
// See
// https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/impl_norm.h#L467
constexpr char32_t hangul_sbase = 0xAC00;
constexpr char32_t hangul_tbase = 0x11A7;
constexpr char32_t hangul_vbase = 0x1161;
constexpr char32_t hangul_lbase = 0x1100;
constexpr char32_t hangul_lcount = 19;
constexpr char32_t hangul_vcount = 21;
constexpr char32_t hangul_tcount = 28;
constexpr char32_t hangul_ncount = hangul_vcount * hangul_tcount;
constexpr char32_t hangul_scount =
hangul_lcount * hangul_vcount * hangul_tcount;
std::pair<bool, size_t> compute_decomposition_length(
const std::u32string_view input) noexcept {
bool decomposition_needed{false};
size_t additional_elements{0};
for (char32_t current_character : input) {
size_t decomposition_length{0};
if (current_character >= hangul_sbase &&
current_character < hangul_sbase + hangul_scount) {
decomposition_length = 2;
if ((current_character - hangul_sbase) % hangul_tcount) {
decomposition_length = 3;
}
} else if (current_character < 0x110000) {
const uint8_t di = decomposition_index[current_character >> 8];
const uint16_t* const decomposition =
decomposition_block[di] + (current_character % 256);
decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
if ((decomposition_length > 0) && (decomposition[0] & 1)) {
decomposition_length = 0;
}
}
if (decomposition_length != 0) {
decomposition_needed = true;
additional_elements += decomposition_length - 1;
}
}
return {decomposition_needed, additional_elements};
}
void decompose(std::u32string& input, size_t additional_elements) {
input.resize(input.size() + additional_elements);
for (size_t descending_idx = input.size(),
input_count = descending_idx - additional_elements;
input_count--;) {
if (input[input_count] >= hangul_sbase &&
input[input_count] < hangul_sbase + hangul_scount) {
// Hangul decomposition.
char32_t s_index = input[input_count] - hangul_sbase;
if (s_index % hangul_tcount != 0) {
input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
}
input[--descending_idx] =
hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
} else if (input[input_count] < 0x110000) {
// Check decomposition_data.
const uint16_t* decomposition =
decomposition_block[decomposition_index[input[input_count] >> 8]] +
(input[input_count] % 256);
uint16_t decomposition_length =
(decomposition[1] >> 2) - (decomposition[0] >> 2);
if (decomposition_length > 0 && (decomposition[0] & 1)) {
decomposition_length = 0;
}
if (decomposition_length > 0) {
// Non-recursive decomposition.
while (decomposition_length-- > 0) {
input[--descending_idx] = decomposition_data[(decomposition[0] >> 2) +
decomposition_length];
}
} else {
// No decomposition.
input[--descending_idx] = input[input_count];
}
} else {
// Non-Unicode character.
input[--descending_idx] = input[input_count];
}
}
}
uint8_t get_ccc(char32_t c) noexcept {
return c < 0x110000 ? canonical_combining_class_block
[canonical_combining_class_index[c >> 8]][c % 256]
: 0;
}
void sort_marks(std::u32string& input) {
for (size_t idx = 1; idx < input.size(); idx++) {
uint8_t ccc = get_ccc(input[idx]);
if (ccc == 0) {
continue;
} // Skip non-combining characters.
auto current_character = input[idx];
size_t back_idx = idx;
while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
input[back_idx] = input[back_idx - 1];
back_idx--;
}
input[back_idx] = current_character;
}
}
void decompose_nfc(std::u32string& input) {
/**
* Decompose the domain_name string to Unicode Normalization Form C.
* @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
*/
auto [decomposition_needed, additional_elements] =
compute_decomposition_length(input);
if (decomposition_needed) {
decompose(input, additional_elements);
}
sort_marks(input);
}
void compose(std::u32string& input) {
/**
* Compose the domain_name string to Unicode Normalization Form C.
* @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
*/
size_t input_count{0};
size_t composition_count{0};
for (; input_count < input.size(); input_count++, composition_count++) {
input[composition_count] = input[input_count];
if (input[input_count] >= hangul_lbase &&
input[input_count] < hangul_lbase + hangul_lcount) {
if (input_count + 1 < input.size() &&
input[input_count + 1] >= hangul_vbase &&
input[input_count + 1] < hangul_vbase + hangul_vcount) {
input[composition_count] =
hangul_sbase +
((input[input_count] - hangul_lbase) * hangul_vcount +
input[input_count + 1] - hangul_vbase) *
hangul_tcount;
input_count++;
if (input_count + 1 < input.size() &&
input[input_count + 1] > hangul_tbase &&
input[input_count + 1] < hangul_tbase + hangul_tcount) {
input[composition_count] += input[++input_count] - hangul_tbase;
}
}
} else if (input[input_count] >= hangul_sbase &&
input[input_count] < hangul_sbase + hangul_scount) {
if ((input[input_count] - hangul_sbase) % hangul_tcount &&
input_count + 1 < input.size() &&
input[input_count + 1] > hangul_tbase &&
input[input_count + 1] < hangul_tbase + hangul_tcount) {
input[composition_count] += input[++input_count] - hangul_tbase;
}
} else if (input[input_count] < 0x110000) {
const uint16_t* composition =
&composition_block[composition_index[input[input_count] >> 8]]
[input[input_count] % 256];
size_t initial_composition_count = composition_count;
for (int32_t previous_ccc = -1; input_count + 1 < input.size();
input_count++) {
uint8_t ccc = get_ccc(input[input_count + 1]);
if (composition[1] != composition[0] && previous_ccc < ccc) {
// Try finding a composition.
int left = composition[0];
int right = composition[1];
while (left + 2 < right) {
// mean without overflow
int middle = left + (((right - left) >> 1) & ~1);
if (composition_data[middle] <= input[input_count + 1]) {
left = middle;
}
if (composition_data[middle] >= input[input_count + 1]) {
right = middle;
}
}
if (composition_data[left] == input[input_count + 1]) {
input[initial_composition_count] = composition_data[left + 1];
composition =
&composition_block
[composition_index[composition_data[left + 1] >> 8]]
[composition_data[left + 1] % 256];
continue;
}
}
if (ccc == 0) {
break;
} // Not a combining character.
previous_ccc = ccc;
input[++composition_count] = input[input_count + 1];
}
}
}
if (composition_count < input_count) {
input.resize(composition_count);
}
}
void normalize(std::u32string& input) {
/**
* Normalize the domain_name string to Unicode Normalization Form C.
* @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
*/
decompose_nfc(input);
compose(input);
}
} // namespace ada::idna
/* end file src/normalization.cpp */
/* begin file src/punycode.cpp */
#include <cstdint>
namespace ada::idna {
constexpr int32_t base = 36;
constexpr int32_t tmin = 1;
constexpr int32_t tmax = 26;
constexpr int32_t skew = 38;
constexpr int32_t damp = 700;
constexpr int32_t initial_bias = 72;
constexpr uint32_t initial_n = 128;
static constexpr int32_t char_to_digit_value(char value) {
if (value >= 'a' && value <= 'z') return value - 'a';
if (value >= '0' && value <= '9') return value - '0' + 26;
return -1;
}
static constexpr char digit_to_char(int32_t digit) {
return digit < 26 ? char(digit + 97) : char(digit + 22);
}
static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
if (firsttime) {
d = d / damp;
} else {
d = d / 2;
}
d += d / n;
int32_t k = 0;
while (d > ((base - tmin) * tmax) / 2) {
d /= base - tmin;
k += base;
}
return k + (((base - tmin + 1) * d) / (d + skew));
}
bool punycode_to_utf32(std::string_view input, std::u32string &out) {
// See https://github.com/whatwg/url/issues/803
if (input.starts_with("xn--")) {
return false;
}
int32_t written_out{0};
out.reserve(out.size() + input.size());
uint32_t n = initial_n;
int32_t i = 0;
int32_t bias = initial_bias;
// grab ascii content
size_t end_of_ascii = input.find_last_of('-');
if (end_of_ascii != std::string_view::npos) {
for (uint8_t c : input.substr(0, end_of_ascii)) {
if (c >= 0x80) {
return false;
}
out.push_back(c);
written_out++;
}
input.remove_prefix(end_of_ascii + 1);
}
while (!input.empty()) {
int32_t oldi = i;
int32_t w = 1;
for (int32_t k = base;; k += base) {
if (input.empty()) {
return false;
}
uint8_t code_point = input.front();
input.remove_prefix(1);
int32_t digit = char_to_digit_value(code_point);
if (digit < 0) {
return false;
}
if (digit > (0x7fffffff - i) / w) {
return false;
}
i = i + digit * w;
int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
if (digit < t) {
break;
}
if (w > 0x7fffffff / (base - t)) {
return false;
}
w = w * (base - t);
}
bias = adapt(i - oldi, written_out + 1, oldi == 0);
if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
return false;
}
n = n + i / (written_out + 1);
i = i % (written_out + 1);
if (n < 0x80) {
return false;
}
out.insert(out.begin() + i, n);
written_out++;
++i;
}
return true;
}
bool verify_punycode(std::string_view input) {
if (input.starts_with("xn--")) {
return false;
}
size_t written_out{0};
uint32_t n = initial_n;
int32_t i = 0;
int32_t bias = initial_bias;
// grab ascii content
size_t end_of_ascii = input.find_last_of('-');
if (end_of_ascii != std::string_view::npos) {
for (uint8_t c : input.substr(0, end_of_ascii)) {
if (c >= 0x80) {
return false;
}
written_out++;
}
input.remove_prefix(end_of_ascii + 1);
}
while (!input.empty()) {
int32_t oldi = i;
int32_t w = 1;
for (int32_t k = base;; k += base) {
if (input.empty()) {
return false;
}
uint8_t code_point = input.front();
input.remove_prefix(1);
int32_t digit = char_to_digit_value(code_point);
if (digit < 0) {
return false;
}
if (digit > (0x7fffffff - i) / w) {
return false;
}
i = i + digit * w;
int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
if (digit < t) {
break;
}
if (w > 0x7fffffff / (base - t)) {
return false;
}
w = w * (base - t);
}
bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0);
if (i / (written_out + 1) > 0x7fffffff - n) {
return false;
}
n = n + i / int32_t(written_out + 1);
i = i % int32_t(written_out + 1);
if (n < 0x80) {
return false;
}
written_out++;
++i;
}
return true;
}
bool utf32_to_punycode(std::u32string_view input, std::string &out) {
out.reserve(input.size() + out.size());
uint32_t n = initial_n;
int32_t d = 0;
int32_t bias = initial_bias;
size_t h = 0;
// first push the ascii content
for (uint32_t c : input) {
if (c < 0x80) {
++h;
out.push_back(char(c));
}
if (c > 0x10ffff || (c >= 0xd880 && c < 0xe000)) {
return false;
}
}
size_t b = h;
if (b > 0) {
out.push_back('-');
}
while (h < input.size()) {
uint32_t m = 0x10FFFF;
for (auto code_point : input) {
if (code_point >= n && code_point < m) m = code_point;
}
if ((m - n) > (0x7fffffff - d) / (h + 1)) {
return false;
}
d = d + int32_t((m - n) * (h + 1));
n = m;
for (auto c : input) {
if (c < n) {
if (d == 0x7fffffff) {
return false;
}
++d;
}
if (c == n) {
int32_t q = d;
for (int32_t k = base;; k += base) {
int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
if (q < t) {
break;
}
out.push_back(digit_to_char(t + ((q - t) % (base - t))));
q = (q - t) / (base - t);
}
out.push_back(digit_to_char(q));
bias = adapt(d, int32_t(h + 1), h == b);
d = 0;
++h;
}
}
++d;
++n;
}
return true;
}
} // namespace ada::idna
/* end file src/punycode.cpp */
/* begin file src/validity.cpp */
#include <algorithm>
#include <string_view>
namespace ada::idna {
enum direction : uint8_t {
NONE,
BN,
CS,
ES,
ON,
EN,
L,
R,
NSM,
AL,
AN,
ET,
WS,
RLO,
LRO,
PDF,
RLE,
RLI,
FSI,
PDI,
LRI,
B,
S,
LRE
};
struct directions {
uint32_t start_code;
uint32_t final_code;
direction direct;
};
static directions dir_table[] = {
{0x0, 0x8, direction::BN}, {0x9, 0x9, direction::S},
{0xa, 0xa, direction::B}, {0xb, 0xb, direction::S},
{0xc, 0xc, direction::WS}, {0xd, 0xd, direction::B},
{0xe, 0x1b, direction::BN}, {0x1c, 0x1e, direction::B},
{0x1f, 0x1f, direction::S}, {0x20, 0x20, direction::WS},
{0x21, 0x22, direction::ON}, {0x23, 0x25, direction::ET},
{0x26, 0x2a, direction::ON}, {0x2b, 0x2b, direction::ES},
{0x2c, 0x2c, direction::CS}, {0x2d, 0x2d, direction::ES},
{0x2e, 0x2f, direction::CS}, {0x30, 0x39, direction::EN},
{0x3a, 0x3a, direction::CS}, {0x3b, 0x40, direction::ON},
{0x41, 0x5a, direction::L}, {0x5b, 0x60, direction::ON},
{0x61, 0x7a, direction::L}, {0x7b, 0x7e, direction::ON},
{0x7f, 0x84, direction::BN}, {0x85, 0x85, direction::B},
{0x86, 0x9f, direction::BN}, {0xa0, 0xa0, direction::CS},
{0xa1, 0xa1, direction::ON}, {0xa2, 0xa5, direction::ET},
{0xa6, 0xa9, direction::ON}, {0xaa, 0xaa, direction::L},
{0xab, 0xac, direction::ON}, {0xad, 0xad, direction::BN},
{0xae, 0xaf, direction::ON}, {0xb0, 0xb1, direction::ET},
{0xb2, 0xb3, direction::EN}, {0xb4, 0xb4, direction::ON},
{0xb5, 0xb5, direction::L}, {0xb6, 0xb8, direction::ON},
{0xb9, 0xb9, direction::EN}, {0xba, 0xba, direction::L},
{0xbb, 0xbf, direction::ON}, {0xc0, 0xd6, direction::L},
{0xd7, 0xd7, direction::ON}, {0xd8, 0xf6, direction::L},
{0xf7, 0xf7, direction::ON}, {0xf8, 0x2b8, direction::L},
{0x2b9, 0x2ba, direction::ON}, {0x2bb, 0x2c1, direction::L},
{0x2c2, 0x2cf, direction::ON}, {0x2d0, 0x2d1, direction::L},
{0x2d2, 0x2df, direction::ON}, {0x2e0, 0x2e4, direction::L},
{0x2e5, 0x2ed, direction::ON}, {0x2ee, 0x2ee, direction::L},
{0x2ef, 0x2ff, direction::ON}, {0x300, 0x36f, direction::NSM},
{0x370, 0x373, direction::L}, {0x374, 0x375, direction::ON},
{0x376, 0x377, direction::L}, {0x37a, 0x37d, direction::L},
{0x37e, 0x37e, direction::ON}, {0x37f, 0x37f, direction::L},
{0x384, 0x385, direction::ON}, {0x386, 0x386, direction::L},
{0x387, 0x387, direction::ON}, {0x388, 0x38a, direction::L},
{0x38c, 0x38c, direction::L}, {0x38e, 0x3a1, direction::L},
{0x3a3, 0x3f5, direction::L}, {0x3f6, 0x3f6, direction::ON},
{0x3f7, 0x482, direction::L}, {0x483, 0x489, direction::NSM},
{0x48a, 0x52f, direction::L}, {0x531, 0x556, direction::L},
{0x559, 0x589, direction::L}, {0x58a, 0x58a, direction::ON},
{0x58d, 0x58e, direction::ON}, {0x58f, 0x58f, direction::ET},
{0x591, 0x5bd, direction::NSM}, {0x5be, 0x5be, direction::R},
{0x5bf, 0x5bf, direction::NSM}, {0x5c0, 0x5c0, direction::R},
{0x5c1, 0x5c2, direction::NSM}, {0x5c3, 0x5c3, direction::R},
{0x5c4, 0x5c5, direction::NSM}, {0x5c6, 0x5c6, direction::R},
{0x5c7, 0x5c7, direction::NSM}, {0x5d0, 0x5ea, direction::R},
{0x5ef, 0x5f4, direction::R}, {0x600, 0x605, direction::AN},
{0x606, 0x607, direction::ON}, {0x608, 0x608, direction::AL},
{0x609, 0x60a, direction::ET}, {0x60b, 0x60b, direction::AL},
{0x60c, 0x60c, direction::CS}, {0x60d, 0x60d, direction::AL},
{0x60e, 0x60f, direction::ON}, {0x610, 0x61a, direction::NSM},
{0x61b, 0x61c, direction::AL}, {0x61e, 0x64a, direction::AL},
{0x64b, 0x65f, direction::NSM}, {0x660, 0x669, direction::AN},
{0x66a, 0x66a, direction::ET}, {0x66b, 0x66c, direction::AN},
{0x66d, 0x66f, direction::AL}, {0x670, 0x670, direction::NSM},
{0x671, 0x6d5, direction::AL}, {0x6d6, 0x6dc, direction::NSM},
{0x6dd, 0x6dd, direction::AN}, {0x6de, 0x6de, direction::ON},
{0x6df, 0x6e4, direction::NSM}, {0x6e5, 0x6e6, direction::AL},
{0x6e7, 0x6e8, direction::NSM}, {0x6e9, 0x6e9, direction::ON},
{0x6ea, 0x6ed, direction::NSM}, {0x6ee, 0x6ef, direction::AL},
{0x6f0, 0x6f9, direction::EN}, {0x6fa, 0x70d, direction::AL},
{0x70f, 0x710, direction::AL}, {0x711, 0x711, direction::NSM},
{0x712, 0x72f, direction::AL}, {0x730, 0x74a, direction::NSM},
{0x74d, 0x7a5, direction::AL}, {0x7a6, 0x7b0, direction::NSM},
{0x7b1, 0x7b1, direction::AL}, {0x7c0, 0x7ea, direction::R},
{0x7eb, 0x7f3, direction::NSM}, {0x7f4, 0x7f5, direction::R},
{0x7f6, 0x7f9, direction::ON}, {0x7fa, 0x7fa, direction::R},
{0x7fd, 0x7fd, direction::NSM}, {0x7fe, 0x815, direction::R},
{0x816, 0x819, direction::NSM}, {0x81a, 0x81a, direction::R},
{0x81b, 0x823, direction::NSM}, {0x824, 0x824, direction::R},
{0x825, 0x827, direction::NSM}, {0x828, 0x828, direction::R},
{0x829, 0x82d, direction::NSM}, {0x830, 0x83e, direction::R},
{0x840, 0x858, direction::R}, {0x859, 0x85b, direction::NSM},
{0x85e, 0x85e, direction::R}, {0x860, 0x86a, direction::AL},
{0x8a0, 0x8b4, direction::AL}, {0x8b6, 0x8c7, direction::AL},
{0x8d3, 0x8e1, direction::NSM}, {0x8e2, 0x8e2, direction::AN},
{0x8e3, 0x902, direction::NSM}, {0x903, 0x939, direction::L},
{0x93a, 0x93a, direction::NSM}, {0x93b, 0x93b, direction::L},
{0x93c, 0x93c, direction::NSM}, {0x93d, 0x940, direction::L},
{0x941, 0x948, direction::NSM}, {0x949, 0x94c, direction::L},
{0x94d, 0x94d, direction::NSM}, {0x94e, 0x950, direction::L},
{0x951, 0x957, direction::NSM}, {0x958, 0x961, direction::L},
{0x962, 0x963, direction::NSM}, {0x964, 0x980, direction::L},
{0x981, 0x981, direction::NSM}, {0x982, 0x983, direction::L},
{0x985, 0x98c, direction::L}, {0x98f, 0x990, direction::L},
{0x993, 0x9a8, direction::L}, {0x9aa, 0x9b0, direction::L},
{0x9b2, 0x9b2, direction::L}, {0x9b6, 0x9b9, direction::L},
{0x9bc, 0x9bc, direction::NSM}, {0x9bd, 0x9c0, direction::L},
{0x9c1, 0x9c4, direction::NSM}, {0x9c7, 0x9c8, direction::L},
{0x9cb, 0x9cc, direction::L}, {0x9cd, 0x9cd, direction::NSM},
{0x9ce, 0x9ce, direction::L}, {0x9d7, 0x9d7, direction::L},
{0x9dc, 0x9dd, direction::L}, {0x9df, 0x9e1, direction::L},
{0x9e2, 0x9e3, direction::NSM}, {0x9e6, 0x9f1, direction::L},
{0x9f2, 0x9f3, direction::ET}, {0x9f4, 0x9fa, direction::L},
{0x9fb, 0x9fb, direction::ET}, {0x9fc, 0x9fd, direction::L},
{0x9fe, 0x9fe, direction::NSM}, {0xa01, 0xa02, direction::NSM},
{0xa03, 0xa03, direction::L}, {0xa05, 0xa0a, direction::L},
{0xa0f, 0xa10, direction::L}, {0xa13, 0xa28, direction::L},
{0xa2a, 0xa30, direction::L}, {0xa32, 0xa33, direction::L},
{0xa35, 0xa36, direction::L}, {0xa38, 0xa39, direction::L},
{0xa3c, 0xa3c, direction::NSM}, {0xa3e, 0xa40, direction::L},
{0xa41, 0xa42, direction::NSM}, {0xa47, 0xa48, direction::NSM},
{0xa4b, 0xa4d, direction::NSM}, {0xa51, 0xa51, direction::NSM},
{0xa59, 0xa5c, direction::L}, {0xa5e, 0xa5e, direction::L},
{0xa66, 0xa6f, direction::L}, {0xa70, 0xa71, direction::NSM},
{0xa72, 0xa74, direction::L}, {0xa75, 0xa75, direction::NSM},
{0xa76, 0xa76, direction::L}, {0xa81, 0xa82, direction::NSM},
{0xa83, 0xa83, direction::L}, {0xa85, 0xa8d, direction::L},
{0xa8f, 0xa91, direction::L}, {0xa93, 0xaa8, direction::L},
{0xaaa, 0xab0, direction::L}, {0xab2, 0xab3, direction::L},
{0xab5, 0xab9, direction::L}, {0xabc, 0xabc, direction::NSM},
{0xabd, 0xac0, direction::L}, {0xac1, 0xac5, direction::NSM},
{0xac7, 0xac8, direction::NSM}, {0xac9, 0xac9, direction::L},
{0xacb, 0xacc, direction::L}, {0xacd, 0xacd, direction::NSM},
{0xad0, 0xad0, direction::L}, {0xae0, 0xae1, direction::L},
{0xae2, 0xae3, direction::NSM}, {0xae6, 0xaf0, direction::L},
{0xaf1, 0xaf1, direction::ET}, {0xaf9, 0xaf9, direction::L},
{0xafa, 0xaff, direction::NSM}, {0xb01, 0xb01, direction::NSM},
{0xb02, 0xb03, direction::L}, {0xb05, 0xb0c, direction::L},
{0xb0f, 0xb10, direction::L}, {0xb13, 0xb28, direction::L},
{0xb2a, 0xb30, direction::L}, {0xb32, 0xb33, direction::L},
{0xb35, 0xb39, direction::L}, {0xb3c, 0xb3c, direction::NSM},
{0xb3d, 0xb3e, direction::L}, {0xb3f, 0xb3f, direction::NSM},
{0xb40, 0xb40, direction::L}, {0xb41, 0xb44, direction::NSM},
{0xb47, 0xb48, direction::L}, {0xb4b, 0xb4c, direction::L},
{0xb4d, 0xb4d, direction::NSM}, {0xb55, 0xb56, direction::NSM},
{0xb57, 0xb57, direction::L}, {0xb5c, 0xb5d, direction::L},
{0xb5f, 0xb61, direction::L}, {0xb62, 0xb63, direction::NSM},
{0xb66, 0xb77, direction::L}, {0xb82, 0xb82, direction::NSM},
{0xb83, 0xb83, direction::L}, {0xb85, 0xb8a, direction::L},
{0xb8e, 0xb90, direction::L}, {0xb92, 0xb95, direction::L},
{0xb99, 0xb9a, direction::L}, {0xb9c, 0xb9c, direction::L},
{0xb9e, 0xb9f, direction::L}, {0xba3, 0xba4, direction::L},
{0xba8, 0xbaa, direction::L}, {0xbae, 0xbb9, direction::L},
{0xbbe, 0xbbf, direction::L}, {0xbc0, 0xbc0, direction::NSM},
{0xbc1, 0xbc2, direction::L}, {0xbc6, 0xbc8, direction::L},
{0xbca, 0xbcc, direction::L}, {0xbcd, 0xbcd, direction::NSM},
{0xbd0, 0xbd0, direction::L}, {0xbd7, 0xbd7, direction::L},
{0xbe6, 0xbf2, direction::L}, {0xbf3, 0xbf8, direction::ON},
{0xbf9, 0xbf9, direction::ET}, {0xbfa, 0xbfa, direction::ON},
{0xc00, 0xc00, direction::NSM}, {0xc01, 0xc03, direction::L},
{0xc04, 0xc04, direction::NSM}, {0xc05, 0xc0c, direction::L},
{0xc0e, 0xc10, direction::L}, {0xc12, 0xc28, direction::L},
{0xc2a, 0xc39, direction::L}, {0xc3d, 0xc3d, direction::L},
{0xc3e, 0xc40, direction::NSM}, {0xc41, 0xc44, direction::L},
{0xc46, 0xc48, direction::NSM}, {0xc4a, 0xc4d, direction::NSM},
{0xc55, 0xc56, direction::NSM}, {0xc58, 0xc5a, direction::L},
{0xc60, 0xc61, direction::L}, {0xc62, 0xc63, direction::NSM},
{0xc66, 0xc6f, direction::L}, {0xc77, 0xc77, direction::L},
{0xc78, 0xc7e, direction::ON}, {0xc7f, 0xc80, direction::L},
{0xc81, 0xc81, direction::NSM}, {0xc82, 0xc8c, direction::L},
{0xc8e, 0xc90, direction::L}, {0xc92, 0xca8, direction::L},
{0xcaa, 0xcb3, direction::L}, {0xcb5, 0xcb9, direction::L},
{0xcbc, 0xcbc, direction::NSM}, {0xcbd, 0xcc4, direction::L},
{0xcc6, 0xcc8, direction::L}, {0xcca, 0xccb, direction::L},
{0xccc, 0xccd, direction::NSM}, {0xcd5, 0xcd6, direction::L},
{0xcde, 0xcde, direction::L}, {0xce0, 0xce1, direction::L},
{0xce2, 0xce3, direction::NSM}, {0xce6, 0xcef, direction::L},
{0xcf1, 0xcf2, direction::L}, {0xd00, 0xd01, direction::NSM},
{0xd02, 0xd0c, direction::L}, {0xd0e, 0xd10, direction::L},
{0xd12, 0xd3a, direction::L}, {0xd3b, 0xd3c, direction::NSM},
{0xd3d, 0xd40, direction::L}, {0xd41, 0xd44, direction::NSM},
{0xd46, 0xd48, direction::L}, {0xd4a, 0xd4c, direction::L},
{0xd4d, 0xd4d, direction::NSM}, {0xd4e, 0xd4f, direction::L},
{0xd54, 0xd61, direction::L}, {0xd62, 0xd63, direction::NSM},
{0xd66, 0xd7f, direction::L}, {0xd81, 0xd81, direction::NSM},
{0xd82, 0xd83, direction::L}, {0xd85, 0xd96, direction::L},
{0xd9a, 0xdb1, direction::L}, {0xdb3, 0xdbb, direction::L},
{0xdbd, 0xdbd, direction::L}, {0xdc0, 0xdc6, direction::L},
{0xdca, 0xdca, direction::NSM}, {0xdcf, 0xdd1, direction::L},
{0xdd2, 0xdd4, direction::NSM}, {0xdd6, 0xdd6, direction::NSM},
{0xdd8, 0xddf, direction::L}, {0xde6, 0xdef, direction::L},
{0xdf2, 0xdf4, direction::L}, {0xe01, 0xe30, direction::L},
{0xe31, 0xe31, direction::NSM}, {0xe32, 0xe33, direction::L},
{0xe34, 0xe3a, direction::NSM}, {0xe3f, 0xe3f, direction::ET},
{0xe40, 0xe46, direction::L}, {0xe47, 0xe4e, direction::NSM},
{0xe4f, 0xe5b, direction::L}, {0xe81, 0xe82, direction::L},
{0xe84, 0xe84, direction::L}, {0xe86, 0xe8a, direction::L},
{0xe8c, 0xea3, direction::L}, {0xea5, 0xea5, direction::L},
{0xea7, 0xeb0, direction::L}, {0xeb1, 0xeb1, direction::NSM},
{0xeb2, 0xeb3, direction::L}, {0xeb4, 0xebc, direction::NSM},
{0xebd, 0xebd, direction::L}, {0xec0, 0xec4, direction::L},
{0xec6, 0xec6, direction::L}, {0xec8, 0xecd, direction::NSM},
{0xed0, 0xed9, direction::L}, {0xedc, 0xedf, direction::L},
{0xf00, 0xf17, direction::L}, {0xf18, 0xf19, direction::NSM},
{0xf1a, 0xf34, direction::L}, {0xf35, 0xf35, direction::NSM},
{0xf36, 0xf36, direction::L}, {0xf37, 0xf37, direction::NSM},
{0xf38, 0xf38, direction::L}, {0xf39, 0xf39, direction::NSM},
{0xf3a, 0xf3d, direction::ON}, {0xf3e, 0xf47, direction::L},
{0xf49, 0xf6c, direction::L}, {0xf71, 0xf7e, direction::NSM},
{0xf7f, 0xf7f, direction::L}, {0xf80, 0xf84, direction::NSM},
{0xf85, 0xf85, direction::L}, {0xf86, 0xf87, direction::NSM},
{0xf88, 0xf8c, direction::L}, {0xf8d, 0xf97, direction::NSM},
{0xf99, 0xfbc, direction::NSM}, {0xfbe, 0xfc5, direction::L},
{0xfc6, 0xfc6, direction::NSM}, {0xfc7, 0xfcc, direction::L},
{0xfce, 0xfda, direction::L}, {0x1000, 0x102c, direction::L},
{0x102d, 0x1030, direction::NSM}, {0x1031, 0x1031, direction::L},
{0x1032, 0x1037, direction::NSM}, {0x1038, 0x1038, direction::L},
{0x1039, 0x103a, direction::NSM}, {0x103b, 0x103c, direction::L},
{0x103d, 0x103e, direction::NSM}, {0x103f, 0x1057, direction::L},
{0x1058, 0x1059, direction::NSM}, {0x105a, 0x105d, direction::L},
{0x105e, 0x1060, direction::NSM}, {0x1061, 0x1070, direction::L},
{0x1071, 0x1074, direction::NSM}, {0x1075, 0x1081, direction::L},
{0x1082, 0x1082, direction::NSM}, {0x1083, 0x1084, direction::L},
{0x1085, 0x1086, direction::NSM}, {0x1087, 0x108c, direction::L},
{0x108d, 0x108d, direction::NSM}, {0x108e, 0x109c, direction::L},
{0x109d, 0x109d, direction::NSM}, {0x109e, 0x10c5, direction::L},
{0x10c7, 0x10c7, direction::L}, {0x10cd, 0x10cd, direction::L},
{0x10d0, 0x1248, direction::L}, {0x124a, 0x124d, direction::L},
{0x1250, 0x1256, direction::L}, {0x1258, 0x1258, direction::L},
{0x125a, 0x125d, direction::L}, {0x1260, 0x1288, direction::L},
{0x128a, 0x128d, direction::L}, {0x1290, 0x12b0, direction::L},
{0x12b2, 0x12b5, direction::L}, {0x12b8, 0x12be, direction::L},
{0x12c0, 0x12c0, direction::L}, {0x12c2, 0x12c5, direction::L},
{0x12c8, 0x12d6, direction::L}, {0x12d8, 0x1310, direction::L},
{0x1312, 0x1315, direction::L}, {0x1318, 0x135a, direction::L},
{0x135d, 0x135f, direction::NSM}, {0x1360, 0x137c, direction::L},
{0x1380, 0x138f, direction::L}, {0x1390, 0x1399, direction::ON},
{0x13a0, 0x13f5, direction::L}, {0x13f8, 0x13fd, direction::L},
{0x1400, 0x1400, direction::ON}, {0x1401, 0x167f, direction::L},
{0x1680, 0x1680, direction::WS}, {0x1681, 0x169a, direction::L},
{0x169b, 0x169c, direction::ON}, {0x16a0, 0x16f8, direction::L},
{0x1700, 0x170c, direction::L}, {0x170e, 0x1711, direction::L},
{0x1712, 0x1714, direction::NSM}, {0x1720, 0x1731, direction::L},
{0x1732, 0x1734, direction::NSM}, {0x1735, 0x1736, direction::L},
{0x1740, 0x1751, direction::L}, {0x1752, 0x1753, direction::NSM},
{0x1760, 0x176c, direction::L}, {0x176e, 0x1770, direction::L},
{0x1772, 0x1773, direction::NSM}, {0x1780, 0x17b3, direction::L},
{0x17b4, 0x17b5, direction::NSM}, {0x17b6, 0x17b6, direction::L},
{0x17b7, 0x17bd, direction::NSM}, {0x17be, 0x17c5, direction::L},
{0x17c6, 0x17c6, direction::NSM}, {0x17c7, 0x17c8, direction::L},
{0x17c9, 0x17d3, direction::NSM}, {0x17d4, 0x17da, direction::L},
{0x17db, 0x17db, direction::ET}, {0x17dc, 0x17dc, direction::L},
{0x17dd, 0x17dd, direction::NSM}, {0x17e0, 0x17e9, direction::L},
{0x17f0, 0x17f9, direction::ON}, {0x1800, 0x180a, direction::ON},
{0x180b, 0x180d, direction::NSM}, {0x180e, 0x180e, direction::BN},
{0x1810, 0x1819, direction::L}, {0x1820, 0x1878, direction::L},
{0x1880, 0x1884, direction::L}, {0x1885, 0x1886, direction::NSM},
{0x1887, 0x18a8, direction::L}, {0x18a9, 0x18a9, direction::NSM},
{0x18aa, 0x18aa, direction::L}, {0x18b0, 0x18f5, direction::L},
{0x1900, 0x191e, direction::L}, {0x1920, 0x1922, direction::NSM},
{0x1923, 0x1926, direction::L}, {0x1927, 0x1928, direction::NSM},
{0x1929, 0x192b, direction::L}, {0x1930, 0x1931, direction::L},
{0x1932, 0x1932, direction::NSM}, {0x1933, 0x1938, direction::L},
{0x1939, 0x193b, direction::NSM}, {0x1940, 0x1940, direction::ON},
{0x1944, 0x1945, direction::ON}, {0x1946, 0x196d, direction::L},
{0x1970, 0x1974, direction::L}, {0x1980, 0x19ab, direction::L},
{0x19b0, 0x19c9, direction::L}, {0x19d0, 0x19da, direction::L},
{0x19de, 0x19ff, direction::ON}, {0x1a00, 0x1a16, direction::L},
{0x1a17, 0x1a18, direction::NSM}, {0x1a19, 0x1a1a, direction::L},
{0x1a1b, 0x1a1b, direction::NSM}, {0x1a1e, 0x1a55, direction::L},
{0x1a56, 0x1a56, direction::NSM}, {0x1a57, 0x1a57, direction::L},
{0x1a58, 0x1a5e, direction::NSM}, {0x1a60, 0x1a60, direction::NSM},
{0x1a61, 0x1a61, direction::L}, {0x1a62, 0x1a62, direction::NSM},
{0x1a63, 0x1a64, direction::L}, {0x1a65, 0x1a6c, direction::NSM},
{0x1a6d, 0x1a72, direction::L}, {0x1a73, 0x1a7c, direction::NSM},
{0x1a7f, 0x1a7f, direction::NSM}, {0x1a80, 0x1a89, direction::L},
{0x1a90, 0x1a99, direction::L}, {0x1aa0, 0x1aad, direction::L},
{0x1ab0, 0x1ac0, direction::NSM}, {0x1b00, 0x1b03, direction::NSM},
{0x1b04, 0x1b33, direction::L}, {0x1b34, 0x1b34, direction::NSM},
{0x1b35, 0x1b35, direction::L}, {0x1b36, 0x1b3a, direction::NSM},
{0x1b3b, 0x1b3b, direction::L}, {0x1b3c, 0x1b3c, direction::NSM},
{0x1b3d, 0x1b41, direction::L}, {0x1b42, 0x1b42, direction::NSM},
{0x1b43, 0x1b4b, direction::L}, {0x1b50, 0x1b6a, direction::L},
{0x1b6b, 0x1b73, direction::NSM}, {0x1b74, 0x1b7c, direction::L},
{0x1b80, 0x1b81, direction::NSM}, {0x1b82, 0x1ba1, direction::L},
{0x1ba2, 0x1ba5, direction::NSM}, {0x1ba6, 0x1ba7, direction::L},
{0x1ba8, 0x1ba9, direction::NSM}, {0x1baa, 0x1baa, direction::L},
{0x1bab, 0x1bad, direction::NSM}, {0x1bae, 0x1be5, direction::L},
{0x1be6, 0x1be6, direction::NSM}, {0x1be7, 0x1be7, direction::L},
{0x1be8, 0x1be9, direction::NSM}, {0x1bea, 0x1bec, direction::L},
{0x1bed, 0x1bed, direction::NSM}, {0x1bee, 0x1bee, direction::L},
{0x1bef, 0x1bf1, direction::NSM}, {0x1bf2, 0x1bf3, direction::L},
{0x1bfc, 0x1c2b, direction::L}, {0x1c2c, 0x1c33, direction::NSM},
{0x1c34, 0x1c35, direction::L}, {0x1c36, 0x1c37, direction::NSM},
{0x1c3b, 0x1c49, direction::L}, {0x1c4d, 0x1c88, direction::L},
{0x1c90, 0x1cba, direction::L}, {0x1cbd, 0x1cc7, direction::L},
{0x1cd0, 0x1cd2, direction::NSM}, {0x1cd3, 0x1cd3, direction::L},
{0x1cd4, 0x1ce0, direction::NSM}, {0x1ce1, 0x1ce1, direction::L},
{0x1ce2, 0x1ce8, direction::NSM}, {0x1ce9, 0x1cec, direction::L},
{0x1ced, 0x1ced, direction::NSM}, {0x1cee, 0x1cf3, direction::L},
{0x1cf4, 0x1cf4, direction::NSM}, {0x1cf5, 0x1cf7, direction::L},
{0x1cf8, 0x1cf9, direction::NSM}, {0x1cfa, 0x1cfa, direction::L},
{0x1d00, 0x1dbf, direction::L}, {0x1dc0, 0x1df9, direction::NSM},
{0x1dfb, 0x1dff, direction::NSM}, {0x1e00, 0x1f15, direction::L},
{0x1f18, 0x1f1d, direction::L}, {0x1f20, 0x1f45, direction::L},
{0x1f48, 0x1f4d, direction::L}, {0x1f50, 0x1f57, direction::L},
{0x1f59, 0x1f59, direction::L}, {0x1f5b, 0x1f5b, direction::L},
{0x1f5d, 0x1f5d, direction::L}, {0x1f5f, 0x1f7d, direction::L},
{0x1f80, 0x1fb4, direction::L}, {0x1fb6, 0x1fbc, direction::L},
{0x1fbd, 0x1fbd, direction::ON}, {0x1fbe, 0x1fbe, direction::L},
{0x1fbf, 0x1fc1, direction::ON}, {0x1fc2, 0x1fc4, direction::L},
{0x1fc6, 0x1fcc, direction::L}, {0x1fcd, 0x1fcf, direction::ON},
{0x1fd0, 0x1fd3, direction::L}, {0x1fd6, 0x1fdb, direction::L},
{0x1fdd, 0x1fdf, direction::ON}, {0x1fe0, 0x1fec, direction::L},
{0x1fed, 0x1fef, direction::ON}, {0x1ff2, 0x1ff4, direction::L},
{0x1ff6, 0x1ffc, direction::L}, {0x1ffd, 0x1ffe, direction::ON},
{0x2000, 0x200a, direction::WS}, {0x200b, 0x200d, direction::BN},
{0x200e, 0x200e, direction::L}, {0x200f, 0x200f, direction::R},
{0x2010, 0x2027, direction::ON}, {0x2028, 0x2028, direction::WS},
{0x2029, 0x2029, direction::B}, {0x202a, 0x202a, direction::LRE},
{0x202b, 0x202b, direction::RLE}, {0x202c, 0x202c, direction::PDF},
{0x202d, 0x202d, direction::LRO}, {0x202e, 0x202e, direction::RLO},
{0x202f, 0x202f, direction::CS}, {0x2030, 0x2034, direction::ET},
{0x2035, 0x2043, direction::ON}, {0x2044, 0x2044, direction::CS},
{0x2045, 0x205e, direction::ON}, {0x205f, 0x205f, direction::WS},
{0x2060, 0x2064, direction::BN}, {0x2066, 0x2066, direction::LRI},
{0x2067, 0x2067, direction::RLI}, {0x2068, 0x2068, direction::FSI},
{0x2069, 0x2069, direction::PDI}, {0x206a, 0x206f, direction::BN},
{0x2070, 0x2070, direction::EN}, {0x2071, 0x2071, direction::L},
{0x2074, 0x2079, direction::EN}, {0x207a, 0x207b, direction::ES},
{0x207c, 0x207e, direction::ON}, {0x207f, 0x207f, direction::L},
{0x2080, 0x2089, direction::EN}, {0x208a, 0x208b, direction::ES},
{0x208c, 0x208e, direction::ON}, {0x2090, 0x209c, direction::L},
{0x20a0, 0x20bf, direction::ET}, {0x20d0, 0x20f0, direction::NSM},
{0x2100, 0x2101, direction::ON}, {0x2102, 0x2102, direction::L},
{0x2103, 0x2106, direction::ON}, {0x2107, 0x2107, direction::L},
{0x2108, 0x2109, direction::ON}, {0x210a, 0x2113, direction::L},
{0x2114, 0x2114, direction::ON}, {0x2115, 0x2115, direction::L},
{0x2116, 0x2118, direction::ON}, {0x2119, 0x211d, direction::L},
{0x211e, 0x2123, direction::ON}, {0x2124, 0x2124, direction::L},
{0x2125, 0x2125, direction::ON}, {0x2126, 0x2126, direction::L},
{0x2127, 0x2127, direction::ON}, {0x2128, 0x2128, direction::L},
{0x2129, 0x2129, direction::ON}, {0x212a, 0x212d, direction::L},
{0x212e, 0x212e, direction::ET}, {0x212f, 0x2139, direction::L},
{0x213a, 0x213b, direction::ON}, {0x213c, 0x213f, direction::L},
{0x2140, 0x2144, direction::ON}, {0x2145, 0x2149, direction::L},
{0x214a, 0x214d, direction::ON}, {0x214e, 0x214f, direction::L},
{0x2150, 0x215f, direction::ON}, {0x2160, 0x2188, direction::L},
{0x2189, 0x218b, direction::ON}, {0x2190, 0x2211, direction::ON},
{0x2212, 0x2212, direction::ES}, {0x2213, 0x2213, direction::ET},
{0x2214, 0x2335, direction::ON}, {0x2336, 0x237a, direction::L},
{0x237b, 0x2394, direction::ON}, {0x2395, 0x2395, direction::L},
{0x2396, 0x2426, direction::ON}, {0x2440, 0x244a, direction::ON},
{0x2460, 0x2487, direction::ON}, {0x2488, 0x249b, direction::EN},
{0x249c, 0x24e9, direction::L}, {0x24ea, 0x26ab, direction::ON},
{0x26ac, 0x26ac, direction::L}, {0x26ad, 0x27ff, direction::ON},
{0x2800, 0x28ff, direction::L}, {0x2900, 0x2b73, direction::ON},
{0x2b76, 0x2b95, direction::ON}, {0x2b97, 0x2bff, direction::ON},
{0x2c00, 0x2c2e, direction::L}, {0x2c30, 0x2c5e, direction::L},
{0x2c60, 0x2ce4, direction::L}, {0x2ce5, 0x2cea, direction::ON},
{0x2ceb, 0x2cee, direction::L}, {0x2cef, 0x2cf1, direction::NSM},
{0x2cf2, 0x2cf3, direction::L}, {0x2cf9, 0x2cff, direction::ON},
{0x2d00, 0x2d25, direction::L}, {0x2d27, 0x2d27, direction::L},
{0x2d2d, 0x2d2d, direction::L}, {0x2d30, 0x2d67, direction::L},
{0x2d6f, 0x2d70, direction::L}, {0x2d7f, 0x2d7f, direction::NSM},
{0x2d80, 0x2d96, direction::L}, {0x2da0, 0x2da6, direction::L},
{0x2da8, 0x2dae, direction::L}, {0x2db0, 0x2db6, direction::L},
{0x2db8, 0x2dbe, direction::L}, {0x2dc0, 0x2dc6, direction::L},
{0x2dc8, 0x2dce, direction::L}, {0x2dd0, 0x2dd6, direction::L},
{0x2dd8, 0x2dde, direction::L}, {0x2de0, 0x2dff, direction::NSM},
{0x2e00, 0x2e52, direction::ON}, {0x2e80, 0x2e99, direction::ON},
{0x2e9b, 0x2ef3, direction::ON}, {0x2f00, 0x2fd5, direction::ON},
{0x2ff0, 0x2ffb, direction::ON}, {0x3000, 0x3000, direction::WS},
{0x3001, 0x3004, direction::ON}, {0x3005, 0x3007, direction::L},
{0x3008, 0x3020, direction::ON}, {0x3021, 0x3029, direction::L},
{0x302a, 0x302d, direction::NSM}, {0x302e, 0x302f, direction::L},
{0x3030, 0x3030, direction::ON}, {0x3031, 0x3035, direction::L},
{0x3036, 0x3037, direction::ON}, {0x3038, 0x303c, direction::L},
{0x303d, 0x303f, direction::ON}, {0x3041, 0x3096, direction::L},
{0x3099, 0x309a, direction::NSM}, {0x309b, 0x309c, direction::ON},
{0x309d, 0x309f, direction::L}, {0x30a0, 0x30a0, direction::ON},
{0x30a1, 0x30fa, direction::L}, {0x30fb, 0x30fb, direction::ON},
{0x30fc, 0x30ff, direction::L}, {0x3105, 0x312f, direction::L},
{0x3131, 0x318e, direction::L}, {0x3190, 0x31bf, direction::L},
{0x31c0, 0x31e3, direction::ON}, {0x31f0, 0x321c, direction::L},
{0x321d, 0x321e, direction::ON}, {0x3220, 0x324f, direction::L},
{0x3250, 0x325f, direction::ON}, {0x3260, 0x327b, direction::L},
{0x327c, 0x327e, direction::ON}, {0x327f, 0x32b0, direction::L},
{0x32b1, 0x32bf, direction::ON}, {0x32c0, 0x32cb, direction::L},
{0x32cc, 0x32cf, direction::ON}, {0x32d0, 0x3376, direction::L},
{0x3377, 0x337a, direction::ON}, {0x337b, 0x33dd, direction::L},
{0x33de, 0x33df, direction::ON}, {0x33e0, 0x33fe, direction::L},
{0x33ff, 0x33ff, direction::ON}, {0x3400, 0x4dbf, direction::L},
{0x4dc0, 0x4dff, direction::ON}, {0x4e00, 0x9ffc, direction::L},
{0xa000, 0xa48c, direction::L}, {0xa490, 0xa4c6, direction::ON},
{0xa4d0, 0xa60c, direction::L}, {0xa60d, 0xa60f, direction::ON},
{0xa610, 0xa62b, direction::L}, {0xa640, 0xa66e, direction::L},
{0xa66f, 0xa672, direction::NSM}, {0xa673, 0xa673, direction::ON},
{0xa674, 0xa67d, direction::NSM}, {0xa67e, 0xa67f, direction::ON},
{0xa680, 0xa69d, direction::L}, {0xa69e, 0xa69f, direction::NSM},
{0xa6a0, 0xa6ef, direction::L}, {0xa6f0, 0xa6f1, direction::NSM},
{0xa6f2, 0xa6f7, direction::L}, {0xa700, 0xa721, direction::ON},
{0xa722, 0xa787, direction::L}, {0xa788, 0xa788, direction::ON},
{0xa789, 0xa7bf, direction::L}, {0xa7c2, 0xa7ca, direction::L},
{0xa7f5, 0xa801, direction::L}, {0xa802, 0xa802, direction::NSM},
{0xa803, 0xa805, direction::L}, {0xa806, 0xa806, direction::NSM},
{0xa807, 0xa80a, direction::L}, {0xa80b, 0xa80b, direction::NSM},
{0xa80c, 0xa824, direction::L}, {0xa825, 0xa826, direction::NSM},
{0xa827, 0xa827, direction::L}, {0xa828, 0xa82b, direction::ON},
{0xa82c, 0xa82c, direction::NSM}, {0xa830, 0xa837, direction::L},
{0xa838, 0xa839, direction::ET}, {0xa840, 0xa873, direction::L},
{0xa874, 0xa877, direction::ON}, {0xa880, 0xa8c3, direction::L},
{0xa8c4, 0xa8c5, direction::NSM}, {0xa8ce, 0xa8d9, direction::L},
{0xa8e0, 0xa8f1, direction::NSM}, {0xa8f2, 0xa8fe, direction::L},
{0xa8ff, 0xa8ff, direction::NSM}, {0xa900, 0xa925, direction::L},
{0xa926, 0xa92d, direction::NSM}, {0xa92e, 0xa946, direction::L},
{0xa947, 0xa951, direction::NSM}, {0xa952, 0xa953, direction::L},
{0xa95f, 0xa97c, direction::L}, {0xa980, 0xa982, direction::NSM},
{0xa983, 0xa9b2, direction::L}, {0xa9b3, 0xa9b3, direction::NSM},
{0xa9b4, 0xa9b5, direction::L}, {0xa9b6, 0xa9b9, direction::NSM},
{0xa9ba, 0xa9bb, direction::L}, {0xa9bc, 0xa9bd, direction::NSM},
{0xa9be, 0xa9cd, direction::L}, {0xa9cf, 0xa9d9, direction::L},
{0xa9de, 0xa9e4, direction::L}, {0xa9e5, 0xa9e5, direction::NSM},
{0xa9e6, 0xa9fe, direction::L}, {0xaa00, 0xaa28, direction::L},
{0xaa29, 0xaa2e, direction::NSM}, {0xaa2f, 0xaa30, direction::L},
{0xaa31, 0xaa32, direction::NSM}, {0xaa33, 0xaa34, direction::L},
{0xaa35, 0xaa36, direction::NSM}, {0xaa40, 0xaa42, direction::L},
{0xaa43, 0xaa43, direction::NSM}, {0xaa44, 0xaa4b, direction::L},
{0xaa4c, 0xaa4c, direction::NSM}, {0xaa4d, 0xaa4d, direction::L},
{0xaa50, 0xaa59, direction::L}, {0xaa5c, 0xaa7b, direction::L},
{0xaa7c, 0xaa7c, direction::NSM}, {0xaa7d, 0xaaaf, direction::L},
{0xaab0, 0xaab0, direction::NSM}, {0xaab1, 0xaab1, direction::L},
{0xaab2, 0xaab4, direction::NSM}, {0xaab5, 0xaab6, direction::L},
{0xaab7, 0xaab8, direction::NSM}, {0xaab9, 0xaabd, direction::L},
{0xaabe, 0xaabf, direction::NSM}, {0xaac0, 0xaac0, direction::L},
{0xaac1, 0xaac1, direction::NSM}, {0xaac2, 0xaac2, direction::L},
{0xaadb, 0xaaeb, direction::L}, {0xaaec, 0xaaed, direction::NSM},
{0xaaee, 0xaaf5, direction::L}, {0xaaf6, 0xaaf6, direction::NSM},
{0xab01, 0xab06, direction::L}, {0xab09, 0xab0e, direction::L},
{0xab11, 0xab16, direction::L}, {0xab20, 0xab26, direction::L},
{0xab28, 0xab2e, direction::L}, {0xab30, 0xab69, direction::L},
{0xab6a, 0xab6b, direction::ON}, {0xab70, 0xabe4, direction::L},
{0xabe5, 0xabe5, direction::NSM}, {0xabe6, 0xabe7, direction::L},
{0xabe8, 0xabe8, direction::NSM}, {0xabe9, 0xabec, direction::L},
{0xabed, 0xabed, direction::NSM}, {0xabf0, 0xabf9, direction::L},
{0xac00, 0xd7a3, direction::L}, {0xd7b0, 0xd7c6, direction::L},
{0xd7cb, 0xd7fb, direction::L}, {0xd800, 0xfa6d, direction::L},
{0xfa70, 0xfad9, direction::L}, {0xfb00, 0xfb06, direction::L},
{0xfb13, 0xfb17, direction::L}, {0xfb1d, 0xfb1d, direction::R},
{0xfb1e, 0xfb1e, direction::NSM}, {0xfb1f, 0xfb28, direction::R},
{0xfb29, 0xfb29, direction::ES}, {0xfb2a, 0xfb36, direction::R},
{0xfb38, 0xfb3c, direction::R}, {0xfb3e, 0xfb3e, direction::R},
{0xfb40, 0xfb41, direction::R}, {0xfb43, 0xfb44, direction::R},
{0xfb46, 0xfb4f, direction::R}, {0xfb50, 0xfbc1, direction::AL},
{0xfbd3, 0xfd3d, direction::AL}, {0xfd3e, 0xfd3f, direction::ON},
{0xfd50, 0xfd8f, direction::AL}, {0xfd92, 0xfdc7, direction::AL},
{0xfdf0, 0xfdfc, direction::AL}, {0xfdfd, 0xfdfd, direction::ON},
{0xfe00, 0xfe0f, direction::NSM}, {0xfe10, 0xfe19, direction::ON},
{0xfe20, 0xfe2f, direction::NSM}, {0xfe30, 0xfe4f, direction::ON},
{0xfe50, 0xfe50, direction::CS}, {0xfe51, 0xfe51, direction::ON},
{0xfe52, 0xfe52, direction::CS}, {0xfe54, 0xfe54, direction::ON},
{0xfe55, 0xfe55, direction::CS}, {0xfe56, 0xfe5e, direction::ON},
{0xfe5f, 0xfe5f, direction::ET}, {0xfe60, 0xfe61, direction::ON},
{0xfe62, 0xfe63, direction::ES}, {0xfe64, 0xfe66, direction::ON},
{0xfe68, 0xfe68, direction::ON}, {0xfe69, 0xfe6a, direction::ET},
{0xfe6b, 0xfe6b, direction::ON}, {0xfe70, 0xfe74, direction::AL},
{0xfe76, 0xfefc, direction::AL}, {0xfeff, 0xfeff, direction::BN},
{0xff01, 0xff02, direction::ON}, {0xff03, 0xff05, direction::ET},
{0xff06, 0xff0a, direction::ON}, {0xff0b, 0xff0b, direction::ES},
{0xff0c, 0xff0c, direction::CS}, {0xff0d, 0xff0d, direction::ES},
{0xff0e, 0xff0f, direction::CS}, {0xff10, 0xff19, direction::EN},
{0xff1a, 0xff1a, direction::CS}, {0xff1b, 0xff20, direction::ON},
{0xff21, 0xff3a, direction::L}, {0xff3b, 0xff40, direction::ON},
{0xff41, 0xff5a, direction::L}, {0xff5b, 0xff65, direction::ON},
{0xff66, 0xffbe, direction::L}, {0xffc2, 0xffc7, direction::L},
{0xffca, 0xffcf, direction::L}, {0xffd2, 0xffd7, direction::L},
{0xffda, 0xffdc, direction::L}, {0xffe0, 0xffe1, direction::ET},
{0xffe2, 0xffe4, direction::ON}, {0xffe5, 0xffe6, direction::ET},
{0xffe8, 0xffee, direction::ON}, {0xfff9, 0xfffd, direction::ON},
{0x10000, 0x1000b, direction::L}, {0x1000d, 0x10026, direction::L},
{0x10028, 0x1003a, direction::L}, {0x1003c, 0x1003d, direction::L},
{0x1003f, 0x1004d, direction::L}, {0x10050, 0x1005d, direction::L},
{0x10080, 0x100fa, direction::L}, {0x10100, 0x10100, direction::L},
{0x10101, 0x10101, direction::ON}, {0x10102, 0x10102, direction::L},
{0x10107, 0x10133, direction::L}, {0x10137, 0x1013f, direction::L},
{0x10140, 0x1018c, direction::ON}, {0x1018d, 0x1018e, direction::L},
{0x10190, 0x1019c, direction::ON}, {0x101a0, 0x101a0, direction::ON},
{0x101d0, 0x101fc, direction::L}, {0x101fd, 0x101fd, direction::NSM},
{0x10280, 0x1029c, direction::L}, {0x102a0, 0x102d0, direction::L},
{0x102e0, 0x102e0, direction::NSM}, {0x102e1, 0x102fb, direction::EN},
{0x10300, 0x10323, direction::L}, {0x1032d, 0x1034a, direction::L},
{0x10350, 0x10375, direction::L}, {0x10376, 0x1037a, direction::NSM},
{0x10380, 0x1039d, direction::L}, {0x1039f, 0x103c3, direction::L},
{0x103c8, 0x103d5, direction::L}, {0x10400, 0x1049d, direction::L},
{0x104a0, 0x104a9, direction::L}, {0x104b0, 0x104d3, direction::L},
{0x104d8, 0x104fb, direction::L}, {0x10500, 0x10527, direction::L},
{0x10530, 0x10563, direction::L}, {0x1056f, 0x1056f, direction::L},
{0x10600, 0x10736, direction::L}, {0x10740, 0x10755, direction::L},
{0x10760, 0x10767, direction::L}, {0x10800, 0x10805, direction::R},
{0x10808, 0x10808, direction::R}, {0x1080a, 0x10835, direction::R},
{0x10837, 0x10838, direction::R}, {0x1083c, 0x1083c, direction::R},
{0x1083f, 0x10855, direction::R}, {0x10857, 0x1089e, direction::R},
{0x108a7, 0x108af, direction::R}, {0x108e0, 0x108f2, direction::R},
{0x108f4, 0x108f5, direction::R}, {0x108fb, 0x1091b, direction::R},
{0x1091f, 0x1091f, direction::ON}, {0x10920, 0x10939, direction::R},
{0x1093f, 0x1093f, direction::R}, {0x10980, 0x109b7, direction::R},
{0x109bc, 0x109cf, direction::R}, {0x109d2, 0x10a00, direction::R},
{0x10a01, 0x10a03, direction::NSM}, {0x10a05, 0x10a06, direction::NSM},
{0x10a0c, 0x10a0f, direction::NSM}, {0x10a10, 0x10a13, direction::R},
{0x10a15, 0x10a17, direction::R}, {0x10a19, 0x10a35, direction::R},
{0x10a38, 0x10a3a, direction::NSM}, {0x10a3f, 0x10a3f, direction::NSM},
{0x10a40, 0x10a48, direction::R}, {0x10a50, 0x10a58, direction::R},
{0x10a60, 0x10a9f, direction::R}, {0x10ac0, 0x10ae4, direction::R},
{0x10ae5, 0x10ae6, direction::NSM}, {0x10aeb, 0x10af6, direction::R},
{0x10b00, 0x10b35, direction::R}, {0x10b39, 0x10b3f, direction::ON},
{0x10b40, 0x10b55, direction::R}, {0x10b58, 0x10b72, direction::R},
{0x10b78, 0x10b91, direction::R}, {0x10b99, 0x10b9c, direction::R},
{0x10ba9, 0x10baf, direction::R}, {0x10c00, 0x10c48, direction::R},
{0x10c80, 0x10cb2, direction::R}, {0x10cc0, 0x10cf2, direction::R},
{0x10cfa, 0x10cff, direction::R}, {0x10d00, 0x10d23, direction::AL},
{0x10d24, 0x10d27, direction::NSM}, {0x10d30, 0x10d39, direction::AN},
{0x10e60, 0x10e7e, direction::AN}, {0x10e80, 0x10ea9, direction::R},
{0x10eab, 0x10eac, direction::NSM}, {0x10ead, 0x10ead, direction::R},
{0x10eb0, 0x10eb1, direction::R}, {0x10f00, 0x10f27, direction::R},
{0x10f30, 0x10f45, direction::AL}, {0x10f46, 0x10f50, direction::NSM},
{0x10f51, 0x10f59, direction::AL}, {0x10fb0, 0x10fcb, direction::R},
{0x10fe0, 0x10ff6, direction::R}, {0x11000, 0x11000, direction::L},
{0x11001, 0x11001, direction::NSM}, {0x11002, 0x11037, direction::L},
{0x11038, 0x11046, direction::NSM}, {0x11047, 0x1104d, direction::L},
{0x11052, 0x11065, direction::ON}, {0x11066, 0x1106f, direction::L},
{0x1107f, 0x11081, direction::NSM}, {0x11082, 0x110b2, direction::L},
{0x110b3, 0x110b6, direction::NSM}, {0x110b7, 0x110b8, direction::L},
{0x110b9, 0x110ba, direction::NSM}, {0x110bb, 0x110c1, direction::L},
{0x110cd, 0x110cd, direction::L}, {0x110d0, 0x110e8, direction::L},
{0x110f0, 0x110f9, direction::L}, {0x11100, 0x11102, direction::NSM},
{0x11103, 0x11126, direction::L}, {0x11127, 0x1112b, direction::NSM},
{0x1112c, 0x1112c, direction::L}, {0x1112d, 0x11134, direction::NSM},
{0x11136, 0x11147, direction::L}, {0x11150, 0x11172, direction::L},
{0x11173, 0x11173, direction::NSM}, {0x11174, 0x11176, direction::L},
{0x11180, 0x11181, direction::NSM}, {0x11182, 0x111b5, direction::L},
{0x111b6, 0x111be, direction::NSM}, {0x111bf, 0x111c8, direction::L},
{0x111c9, 0x111cc, direction::NSM}, {0x111cd, 0x111ce, direction::L},
{0x111cf, 0x111cf, direction::NSM}, {0x111d0, 0x111df, direction::L},
{0x111e1, 0x111f4, direction::L}, {0x11200, 0x11211, direction::L},
{0x11213, 0x1122e, direction::L}, {0x1122f, 0x11231, direction::NSM},
{0x11232, 0x11233, direction::L}, {0x11234, 0x11234, direction::NSM},
{0x11235, 0x11235, direction::L}, {0x11236, 0x11237, direction::NSM},
{0x11238, 0x1123d, direction::L}, {0x1123e, 0x1123e, direction::NSM},
{0x11280, 0x11286, direction::L}, {0x11288, 0x11288, direction::L},
{0x1128a, 0x1128d, direction::L}, {0x1128f, 0x1129d, direction::L},
{0x1129f, 0x112a9, direction::L}, {0x112b0, 0x112de, direction::L},
{0x112df, 0x112df, direction::NSM}, {0x112e0, 0x112e2, direction::L},
{0x112e3, 0x112ea, direction::NSM}, {0x112f0, 0x112f9, direction::L},
{0x11300, 0x11301, direction::NSM}, {0x11302, 0x11303, direction::L},
{0x11305, 0x1130c, direction::L}, {0x1130f, 0x11310, direction::L},
{0x11313, 0x11328, direction::L}, {0x1132a, 0x11330, direction::L},
{0x11332, 0x11333, direction::L}, {0x11335, 0x11339, direction::L},
{0x1133b, 0x1133c, direction::NSM}, {0x1133d, 0x1133f, direction::L},
{0x11340, 0x11340, direction::NSM}, {0x11341, 0x11344, direction::L},
{0x11347, 0x11348, direction::L}, {0x1134b, 0x1134d, direction::L},
{0x11350, 0x11350, direction::L}, {0x11357, 0x11357, direction::L},
{0x1135d, 0x11363, direction::L}, {0x11366, 0x1136c, direction::NSM},
{0x11370, 0x11374, direction::NSM}, {0x11400, 0x11437, direction::L},
{0x11438, 0x1143f, direction::NSM}, {0x11440, 0x11441, direction::L},
{0x11442, 0x11444, direction::NSM}, {0x11445, 0x11445, direction::L},
{0x11446, 0x11446, direction::NSM}, {0x11447, 0x1145b, direction::L},
{0x1145d, 0x1145d, direction::L}, {0x1145e, 0x1145e, direction::NSM},
{0x1145f, 0x11461, direction::L}, {0x11480, 0x114b2, direction::L},
{0x114b3, 0x114b8, direction::NSM}, {0x114b9, 0x114b9, direction::L},
{0x114ba, 0x114ba, direction::NSM}, {0x114bb, 0x114be, direction::L},
{0x114bf, 0x114c0, direction::NSM}, {0x114c1, 0x114c1, direction::L},
{0x114c2, 0x114c3, direction::NSM}, {0x114c4, 0x114c7, direction::L},
{0x114d0, 0x114d9, direction::L}, {0x11580, 0x115b1, direction::L},
{0x115b2, 0x115b5, direction::NSM}, {0x115b8, 0x115bb, direction::L},
{0x115bc, 0x115bd, direction::NSM}, {0x115be, 0x115be, direction::L},
{0x115bf, 0x115c0, direction::NSM}, {0x115c1, 0x115db, direction::L},
{0x115dc, 0x115dd, direction::NSM}, {0x11600, 0x11632, direction::L},
{0x11633, 0x1163a, direction::NSM}, {0x1163b, 0x1163c, direction::L},
{0x1163d, 0x1163d, direction::NSM}, {0x1163e, 0x1163e, direction::L},
{0x1163f, 0x11640, direction::NSM}, {0x11641, 0x11644, direction::L},
{0x11650, 0x11659, direction::L}, {0x11660, 0x1166c, direction::ON},
{0x11680, 0x116aa, direction::L}, {0x116ab, 0x116ab, direction::NSM},
{0x116ac, 0x116ac, direction::L}, {0x116ad, 0x116ad, direction::NSM},
{0x116ae, 0x116af, direction::L}, {0x116b0, 0x116b5, direction::NSM},
{0x116b6, 0x116b6, direction::L}, {0x116b7, 0x116b7, direction::NSM},
{0x116b8, 0x116b8, direction::L}, {0x116c0, 0x116c9, direction::L},
{0x11700, 0x1171a, direction::L}, {0x1171d, 0x1171f, direction::NSM},
{0x11720, 0x11721, direction::L}, {0x11722, 0x11725, direction::NSM},
{0x11726, 0x11726, direction::L}, {0x11727, 0x1172b, direction::NSM},
{0x11730, 0x1173f, direction::L}, {0x11800, 0x1182e, direction::L},
{0x1182f, 0x11837, direction::NSM}, {0x11838, 0x11838, direction::L},
{0x11839, 0x1183a, direction::NSM}, {0x1183b, 0x1183b, direction::L},
{0x118a0, 0x118f2, direction::L}, {0x118ff, 0x11906, direction::L},
{0x11909, 0x11909, direction::L}, {0x1190c, 0x11913, direction::L},
{0x11915, 0x11916, direction::L}, {0x11918, 0x11935, direction::L},
{0x11937, 0x11938, direction::L}, {0x1193b, 0x1193c, direction::NSM},
{0x1193d, 0x1193d, direction::L}, {0x1193e, 0x1193e, direction::NSM},
{0x1193f, 0x11942, direction::L}, {0x11943, 0x11943, direction::NSM},
{0x11944, 0x11946, direction::L}, {0x11950, 0x11959, direction::L},
{0x119a0, 0x119a7, direction::L}, {0x119aa, 0x119d3, direction::L},
{0x119d4, 0x119d7, direction::NSM}, {0x119da, 0x119db, direction::NSM},
{0x119dc, 0x119df, direction::L}, {0x119e0, 0x119e0, direction::NSM},
{0x119e1, 0x119e4, direction::L}, {0x11a00, 0x11a00, direction::L},
{0x11a01, 0x11a06, direction::NSM}, {0x11a07, 0x11a08, direction::L},
{0x11a09, 0x11a0a, direction::NSM}, {0x11a0b, 0x11a32, direction::L},
{0x11a33, 0x11a38, direction::NSM}, {0x11a39, 0x11a3a, direction::L},
{0x11a3b, 0x11a3e, direction::NSM}, {0x11a3f, 0x11a46, direction::L},
{0x11a47, 0x11a47, direction::NSM}, {0x11a50, 0x11a50, direction::L},
{0x11a51, 0x11a56, direction::NSM}, {0x11a57, 0x11a58, direction::L},
{0x11a59, 0x11a5b, direction::NSM}, {0x11a5c, 0x11a89, direction::L},
{0x11a8a, 0x11a96, direction::NSM}, {0x11a97, 0x11a97, direction::L},
{0x11a98, 0x11a99, direction::NSM}, {0x11a9a, 0x11aa2, direction::L},
{0x11ac0, 0x11af8, direction::L}, {0x11c00, 0x11c08, direction::L},
{0x11c0a, 0x11c2f, direction::L}, {0x11c30, 0x11c36, direction::NSM},
{0x11c38, 0x11c3d, direction::NSM}, {0x11c3e, 0x11c45, direction::L},
{0x11c50, 0x11c6c, direction::L}, {0x11c70, 0x11c8f, direction::L},
{0x11c92, 0x11ca7, direction::NSM}, {0x11ca9, 0x11ca9, direction::L},
{0x11caa, 0x11cb0, direction::NSM}, {0x11cb1, 0x11cb1, direction::L},
{0x11cb2, 0x11cb3, direction::NSM}, {0x11cb4, 0x11cb4, direction::L},
{0x11cb5, 0x11cb6, direction::NSM}, {0x11d00, 0x11d06, direction::L},
{0x11d08, 0x11d09, direction::L}, {0x11d0b, 0x11d30, direction::L},
{0x11d31, 0x11d36, direction::NSM}, {0x11d3a, 0x11d3a, direction::NSM},
{0x11d3c, 0x11d3d, direction::NSM}, {0x11d3f, 0x11d45, direction::NSM},
{0x11d46, 0x11d46, direction::L}, {0x11d47, 0x11d47, direction::NSM},
{0x11d50, 0x11d59, direction::L}, {0x11d60, 0x11d65, direction::L},
{0x11d67, 0x11d68, direction::L}, {0x11d6a, 0x11d8e, direction::L},
{0x11d90, 0x11d91, direction::NSM}, {0x11d93, 0x11d94, direction::L},
{0x11d95, 0x11d95, direction::NSM}, {0x11d96, 0x11d96, direction::L},
{0x11d97, 0x11d97, direction::NSM}, {0x11d98, 0x11d98, direction::L},
{0x11da0, 0x11da9, direction::L}, {0x11ee0, 0x11ef2, direction::L},
{0x11ef3, 0x11ef4, direction::NSM}, {0x11ef5, 0x11ef8, direction::L},
{0x11fb0, 0x11fb0, direction::L}, {0x11fc0, 0x11fd4, direction::L},
{0x11fd5, 0x11fdc, direction::ON}, {0x11fdd, 0x11fe0, direction::ET},
{0x11fe1, 0x11ff1, direction::ON}, {0x11fff, 0x12399, direction::L},
{0x12400, 0x1246e, direction::L}, {0x12470, 0x12474, direction::L},
{0x12480, 0x12543, direction::L}, {0x13000, 0x1342e, direction::L},
{0x13430, 0x13438, direction::L}, {0x14400, 0x14646, direction::L},
{0x16800, 0x16a38, direction::L}, {0x16a40, 0x16a5e, direction::L},
{0x16a60, 0x16a69, direction::L}, {0x16a6e, 0x16a6f, direction::L},
{0x16ad0, 0x16aed, direction::L}, {0x16af0, 0x16af4, direction::NSM},
{0x16af5, 0x16af5, direction::L}, {0x16b00, 0x16b2f, direction::L},
{0x16b30, 0x16b36, direction::NSM}, {0x16b37, 0x16b45, direction::L},
{0x16b50, 0x16b59, direction::L}, {0x16b5b, 0x16b61, direction::L},
{0x16b63, 0x16b77, direction::L}, {0x16b7d, 0x16b8f, direction::L},
{0x16e40, 0x16e9a, direction::L}, {0x16f00, 0x16f4a, direction::L},
{0x16f4f, 0x16f4f, direction::NSM}, {0x16f50, 0x16f87, direction::L},
{0x16f8f, 0x16f92, direction::NSM}, {0x16f93, 0x16f9f, direction::L},
{0x16fe0, 0x16fe1, direction::L}, {0x16fe2, 0x16fe2, direction::ON},
{0x16fe3, 0x16fe3, direction::L}, {0x16fe4, 0x16fe4, direction::NSM},
{0x16ff0, 0x16ff1, direction::L}, {0x17000, 0x187f7, direction::L},
{0x18800, 0x18cd5, direction::L}, {0x18d00, 0x18d08, direction::L},
{0x1b000, 0x1b11e, direction::L}, {0x1b150, 0x1b152, direction::L},
{0x1b164, 0x1b167, direction::L}, {0x1b170, 0x1b2fb, direction::L},
{0x1bc00, 0x1bc6a, direction::L}, {0x1bc70, 0x1bc7c, direction::L},
{0x1bc80, 0x1bc88, direction::L}, {0x1bc90, 0x1bc99, direction::L},
{0x1bc9c, 0x1bc9c, direction::L}, {0x1bc9d, 0x1bc9e, direction::NSM},
{0x1bc9f, 0x1bc9f, direction::L}, {0x1bca0, 0x1bca3, direction::BN},
{0x1d000, 0x1d0f5, direction::L}, {0x1d100, 0x1d126, direction::L},
{0x1d129, 0x1d166, direction::L}, {0x1d167, 0x1d169, direction::NSM},
{0x1d16a, 0x1d172, direction::L}, {0x1d173, 0x1d17a, direction::BN},
{0x1d17b, 0x1d182, direction::NSM}, {0x1d183, 0x1d184, direction::L},
{0x1d185, 0x1d18b, direction::NSM}, {0x1d18c, 0x1d1a9, direction::L},
{0x1d1aa, 0x1d1ad, direction::NSM}, {0x1d1ae, 0x1d1e8, direction::L},
{0x1d200, 0x1d241, direction::ON}, {0x1d242, 0x1d244, direction::NSM},
{0x1d245, 0x1d245, direction::ON}, {0x1d2e0, 0x1d2f3, direction::L},
{0x1d300, 0x1d356, direction::ON}, {0x1d360, 0x1d378, direction::L},
{0x1d400, 0x1d454, direction::L}, {0x1d456, 0x1d49c, direction::L},
{0x1d49e, 0x1d49f, direction::L}, {0x1d4a2, 0x1d4a2, direction::L},
{0x1d4a5, 0x1d4a6, direction::L}, {0x1d4a9, 0x1d4ac, direction::L},
{0x1d4ae, 0x1d4b9, direction::L}, {0x1d4bb, 0x1d4bb, direction::L},
{0x1d4bd, 0x1d4c3, direction::L}, {0x1d4c5, 0x1d505, direction::L},
{0x1d507, 0x1d50a, direction::L}, {0x1d50d, 0x1d514, direction::L},
{0x1d516, 0x1d51c, direction::L}, {0x1d51e, 0x1d539, direction::L},
{0x1d53b, 0x1d53e, direction::L}, {0x1d540, 0x1d544, direction::L},
{0x1d546, 0x1d546, direction::L}, {0x1d54a, 0x1d550, direction::L},
{0x1d552, 0x1d6a5, direction::L}, {0x1d6a8, 0x1d6da, direction::L},
{0x1d6db, 0x1d6db, direction::ON}, {0x1d6dc, 0x1d714, direction::L},
{0x1d715, 0x1d715, direction::ON}, {0x1d716, 0x1d74e, direction::L},
{0x1d74f, 0x1d74f, direction::ON}, {0x1d750, 0x1d788, direction::L},
{0x1d789, 0x1d789, direction::ON}, {0x1d78a, 0x1d7c2, direction::L},
{0x1d7c3, 0x1d7c3, direction::ON}, {0x1d7c4, 0x1d7cb, direction::L},
{0x1d7ce, 0x1d7ff, direction::EN}, {0x1d800, 0x1d9ff, direction::L},
{0x1da00, 0x1da36, direction::NSM}, {0x1da37, 0x1da3a, direction::L},
{0x1da3b, 0x1da6c, direction::NSM}, {0x1da6d, 0x1da74, direction::L},
{0x1da75, 0x1da75, direction::NSM}, {0x1da76, 0x1da83, direction::L},
{0x1da84, 0x1da84, direction::NSM}, {0x1da85, 0x1da8b, direction::L},
{0x1da9b, 0x1da9f, direction::NSM}, {0x1daa1, 0x1daaf, direction::NSM},
{0x1e000, 0x1e006, direction::NSM}, {0x1e008, 0x1e018, direction::NSM},
{0x1e01b, 0x1e021, direction::NSM}, {0x1e023, 0x1e024, direction::NSM},
{0x1e026, 0x1e02a, direction::NSM}, {0x1e100, 0x1e12c, direction::L},
{0x1e130, 0x1e136, direction::NSM}, {0x1e137, 0x1e13d, direction::L},
{0x1e140, 0x1e149, direction::L}, {0x1e14e, 0x1e14f, direction::L},
{0x1e2c0, 0x1e2eb, direction::L}, {0x1e2ec, 0x1e2ef, direction::NSM},
{0x1e2f0, 0x1e2f9, direction::L}, {0x1e2ff, 0x1e2ff, direction::ET},
{0x1e800, 0x1e8c4, direction::R}, {0x1e8c7, 0x1e8cf, direction::R},
{0x1e8d0, 0x1e8d6, direction::NSM}, {0x1e900, 0x1e943, direction::R},
{0x1e944, 0x1e94a, direction::NSM}, {0x1e94b, 0x1e94b, direction::R},
{0x1e950, 0x1e959, direction::R}, {0x1e95e, 0x1e95f, direction::R},
{0x1ec71, 0x1ecb4, direction::AL}, {0x1ed01, 0x1ed3d, direction::AL},
{0x1ee00, 0x1ee03, direction::AL}, {0x1ee05, 0x1ee1f, direction::AL},
{0x1ee21, 0x1ee22, direction::AL}, {0x1ee24, 0x1ee24, direction::AL},
{0x1ee27, 0x1ee27, direction::AL}, {0x1ee29, 0x1ee32, direction::AL},
{0x1ee34, 0x1ee37, direction::AL}, {0x1ee39, 0x1ee39, direction::AL},
{0x1ee3b, 0x1ee3b, direction::AL}, {0x1ee42, 0x1ee42, direction::AL},
{0x1ee47, 0x1ee47, direction::AL}, {0x1ee49, 0x1ee49, direction::AL},
{0x1ee4b, 0x1ee4b, direction::AL}, {0x1ee4d, 0x1ee4f, direction::AL},
{0x1ee51, 0x1ee52, direction::AL}, {0x1ee54, 0x1ee54, direction::AL},
{0x1ee57, 0x1ee57, direction::AL}, {0x1ee59, 0x1ee59, direction::AL},
{0x1ee5b, 0x1ee5b, direction::AL}, {0x1ee5d, 0x1ee5d, direction::AL},
{0x1ee5f, 0x1ee5f, direction::AL}, {0x1ee61, 0x1ee62, direction::AL},
{0x1ee64, 0x1ee64, direction::AL}, {0x1ee67, 0x1ee6a, direction::AL},
{0x1ee6c, 0x1ee72, direction::AL}, {0x1ee74, 0x1ee77, direction::AL},
{0x1ee79, 0x1ee7c, direction::AL}, {0x1ee7e, 0x1ee7e, direction::AL},
{0x1ee80, 0x1ee89, direction::AL}, {0x1ee8b, 0x1ee9b, direction::AL},
{0x1eea1, 0x1eea3, direction::AL}, {0x1eea5, 0x1eea9, direction::AL},
{0x1eeab, 0x1eebb, direction::AL}, {0x1eef0, 0x1eef1, direction::ON},
{0x1f000, 0x1f02b, direction::ON}, {0x1f030, 0x1f093, direction::ON},
{0x1f0a0, 0x1f0ae, direction::ON}, {0x1f0b1, 0x1f0bf, direction::ON},
{0x1f0c1, 0x1f0cf, direction::ON}, {0x1f0d1, 0x1f0f5, direction::ON},
{0x1f100, 0x1f10a, direction::EN}, {0x1f10b, 0x1f10f, direction::ON},
{0x1f110, 0x1f12e, direction::L}, {0x1f12f, 0x1f12f, direction::ON},
{0x1f130, 0x1f169, direction::L}, {0x1f16a, 0x1f16f, direction::ON},
{0x1f170, 0x1f1ac, direction::L}, {0x1f1ad, 0x1f1ad, direction::ON},
{0x1f1e6, 0x1f202, direction::L}, {0x1f210, 0x1f23b, direction::L},
{0x1f240, 0x1f248, direction::L}, {0x1f250, 0x1f251, direction::L},
{0x1f260, 0x1f265, direction::ON}, {0x1f300, 0x1f6d7, direction::ON},
{0x1f6e0, 0x1f6ec, direction::ON}, {0x1f6f0, 0x1f6fc, direction::ON},
{0x1f700, 0x1f773, direction::ON}, {0x1f780, 0x1f7d8, direction::ON},
{0x1f7e0, 0x1f7eb, direction::ON}, {0x1f800, 0x1f80b, direction::ON},
{0x1f810, 0x1f847, direction::ON}, {0x1f850, 0x1f859, direction::ON},
{0x1f860, 0x1f887, direction::ON}, {0x1f890, 0x1f8ad, direction::ON},
{0x1f8b0, 0x1f8b1, direction::ON}, {0x1f900, 0x1f978, direction::ON},
{0x1f97a, 0x1f9cb, direction::ON}, {0x1f9cd, 0x1fa53, direction::ON},
{0x1fa60, 0x1fa6d, direction::ON}, {0x1fa70, 0x1fa74, direction::ON},
{0x1fa78, 0x1fa7a, direction::ON}, {0x1fa80, 0x1fa86, direction::ON},
{0x1fa90, 0x1faa8, direction::ON}, {0x1fab0, 0x1fab6, direction::ON},
{0x1fac0, 0x1fac2, direction::ON}, {0x1fad0, 0x1fad6, direction::ON},
{0x1fb00, 0x1fb92, direction::ON}, {0x1fb94, 0x1fbca, direction::ON},
{0x1fbf0, 0x1fbf9, direction::EN}, {0x20000, 0x2a6dd, direction::L},
{0x2a700, 0x2b734, direction::L}, {0x2b740, 0x2b81d, direction::L},
{0x2b820, 0x2cea1, direction::L}, {0x2ceb0, 0x2ebe0, direction::L},
{0x2f800, 0x2fa1d, direction::L}, {0x30000, 0x3134a, direction::L},
{0xe0001, 0xe0001, direction::BN}, {0xe0020, 0xe007f, direction::BN},
{0xe0100, 0xe01ef, direction::NSM}, {0xf0000, 0xffffd, direction::L},
{0x100000, 0x10fffd, direction::L}};
// CheckJoiners and CheckBidi are true for URL specification.
inline static direction find_direction(uint32_t code_point) noexcept {
auto it = std::lower_bound(
std::begin(dir_table), std::end(dir_table), code_point,
[](const directions& d, uint32_t c) { return d.final_code < c; });
// next check is almost surely in vain, but we use it for safety.
if (it == std::end(dir_table)) {
return direction::NONE;
}
// We have that d.final_code >= c.
if (code_point >= it->start_code) {
return it->direct;
}
return direction::NONE;
}
inline static size_t find_last_not_of_nsm(
const std::u32string_view label) noexcept {
for (int i = static_cast<int>(label.size() - 1); i >= 0; i--)
if (find_direction(label[i]) != direction::NSM) return i;
return std::u32string_view::npos;
}
// An RTL label is a label that contains at least one character of type R, AL,
// or AN. https://www.rfc-editor.org/rfc/rfc5893#section-2
inline static bool is_rtl_label(const std::u32string_view label) noexcept {
const size_t mask =
(1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
size_t directions = 0;
for (size_t i = 0; i < label.size(); i++) {
directions |= 1u << find_direction(label[i]);
}
return (directions & mask) != 0;
}
bool is_label_valid(const std::u32string_view label) {
if (label.empty()) {
return true;
}
///////////////
// We have a normalization step which ensures that we are in NFC.
// If we receive punycode, we normalize and check that the normalized
// version matches the original.
// --------------------------------------
// The label must be in Unicode Normalization Form NFC.
// Current URL standard indicatest that CheckHyphens is set to false.
// ---------------------------------------
// If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
// in both the third and fourth positions. If CheckHyphens, the label must
// neither begin nor end with a U+002D HYPHEN-MINUS character.
// This is not necessary because we segment the
// labels by '.'.
// ---------------------------------------
// The label must not contain a U+002E ( . ) FULL STOP.
// if (label.find('.') != std::string_view::npos) return false;
// The label must not begin with a combining mark, that is:
// General_Category=Mark.
constexpr static uint32_t combining[] = {
0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307,
0x308, 0x309, 0x30a, 0x30b, 0x30c, 0x30d, 0x30e, 0x30f,
0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, 0x317,
0x318, 0x319, 0x31a, 0x31b, 0x31c, 0x31d, 0x31e, 0x31f,
0x320, 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x327,
0x328, 0x329, 0x32a, 0x32b, 0x32c, 0x32d, 0x32e, 0x32f,
0x330, 0x331, 0x332, 0x333, 0x334, 0x335, 0x336, 0x337,
0x338, 0x339, 0x33a, 0x33b, 0x33c, 0x33d, 0x33e, 0x33f,
0x340, 0x341, 0x342, 0x343, 0x344, 0x345, 0x346, 0x347,
0x348, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34f,
0x350, 0x351, 0x352, 0x353, 0x354, 0x355, 0x356, 0x357,
0x358, 0x359, 0x35a, 0x35b, 0x35c, 0x35d, 0x35e, 0x35f,
0x360, 0x361, 0x362, 0x363, 0x364, 0x365, 0x366, 0x367,
0x368, 0x369, 0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f,
0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 0x489, 0x591,
0x592, 0x593, 0x594, 0x595, 0x596, 0x597, 0x598, 0x599,
0x59a, 0x59b, 0x59c, 0x59d, 0x59e, 0x59f, 0x5a0, 0x5a1,
0x5a2, 0x5a3, 0x5a4, 0x5a5, 0x5a6, 0x5a7, 0x5a8, 0x5a9,
0x5aa, 0x5ab, 0x5ac, 0x5ad, 0x5ae, 0x5af, 0x5b0, 0x5b1,
0x5b2, 0x5b3, 0x5b4, 0x5b5, 0x5b6, 0x5b7, 0x5b8, 0x5b9,
0x5ba, 0x5bb, 0x5bc, 0x5bd, 0x5bf, 0x5c1, 0x5c2, 0x5c4,
0x5c5, 0x5c7, 0x610, 0x611, 0x612, 0x613, 0x614, 0x615,
0x616, 0x617, 0x618, 0x619, 0x61a, 0x64b, 0x64c, 0x64d,
0x64e, 0x64f, 0x650, 0x651, 0x652, 0x653, 0x654, 0x655,
0x656, 0x657, 0x658, 0x659, 0x65a, 0x65b, 0x65c, 0x65d,
0x65e, 0x65f, 0x670, 0x6d6, 0x6d7, 0x6d8, 0x6d9, 0x6da,
0x6db, 0x6dc, 0x6df, 0x6e0, 0x6e1, 0x6e2, 0x6e3, 0x6e4,
0x6e7, 0x6e8, 0x6ea, 0x6eb, 0x6ec, 0x6ed, 0x711, 0x730,
0x731, 0x732, 0x733, 0x734, 0x735, 0x736, 0x737, 0x738,
0x739, 0x73a, 0x73b, 0x73c, 0x73d, 0x73e, 0x73f, 0x740,
0x741, 0x742, 0x743, 0x744, 0x745, 0x746, 0x747, 0x748,
0x749, 0x74a, 0x7a6, 0x7a7, 0x7a8, 0x7a9, 0x7aa, 0x7ab,
0x7ac, 0x7ad, 0x7ae, 0x7af, 0x7b0, 0x7eb, 0x7ec, 0x7ed,
0x7ee, 0x7ef, 0x7f0, 0x7f1, 0x7f2, 0x7f3, 0x7fd, 0x816,
0x817, 0x818, 0x819, 0x81b, 0x81c, 0x81d, 0x81e, 0x81f,
0x820, 0x821, 0x822, 0x823, 0x825, 0x826, 0x827, 0x829,
0x82a, 0x82b, 0x82c, 0x82d, 0x859, 0x85a, 0x85b, 0x8d3,
0x8d4, 0x8d5, 0x8d6, 0x8d7, 0x8d8, 0x8d9, 0x8da, 0x8db,
0x8dc, 0x8dd, 0x8de, 0x8df, 0x8e0, 0x8e1, 0x8e3, 0x8e4,
0x8e5, 0x8e6, 0x8e7, 0x8e8, 0x8e9, 0x8ea, 0x8eb, 0x8ec,
0x8ed, 0x8ee, 0x8ef, 0x8f0, 0x8f1, 0x8f2, 0x8f3, 0x8f4,
0x8f5, 0x8f6, 0x8f7, 0x8f8, 0x8f9, 0x8fa, 0x8fb, 0x8fc,
0x8fd, 0x8fe, 0x8ff, 0x900, 0x901, 0x902, 0x903, 0x93a,
0x93b, 0x93c, 0x93e, 0x93f, 0x940, 0x941, 0x942, 0x943,
0x944, 0x945, 0x946, 0x947, 0x948, 0x949, 0x94a, 0x94b,
0x94c, 0x94d, 0x94e, 0x94f, 0x951, 0x952, 0x953, 0x954,
0x955, 0x956, 0x957, 0x962, 0x963, 0x981, 0x982, 0x983,
0x9bc, 0x9be, 0x9bf, 0x9c0, 0x9c1, 0x9c2, 0x9c3, 0x9c4,
0x9c7, 0x9c8, 0x9cb, 0x9cc, 0x9cd, 0x9d7, 0x9e2, 0x9e3,
0x9fe, 0xa01, 0xa02, 0xa03, 0xa3c, 0xa3e, 0xa3f, 0xa40,
0xa41, 0xa42, 0xa47, 0xa48, 0xa4b, 0xa4c, 0xa4d, 0xa51,
0xa70, 0xa71, 0xa75, 0xa81, 0xa82, 0xa83, 0xabc, 0xabe,
0xabf, 0xac0, 0xac1, 0xac2, 0xac3, 0xac4, 0xac5, 0xac7,
0xac8, 0xac9, 0xacb, 0xacc, 0xacd, 0xae2, 0xae3, 0xafa,
0xafb, 0xafc, 0xafd, 0xafe, 0xaff, 0xb01, 0xb02, 0xb03,
0xb3c, 0xb3e, 0xb3f, 0xb40, 0xb41, 0xb42, 0xb43, 0xb44,
0xb47, 0xb48, 0xb4b, 0xb4c, 0xb4d, 0xb55, 0xb56, 0xb57,
0xb62, 0xb63, 0xb82, 0xbbe, 0xbbf, 0xbc0, 0xbc1, 0xbc2,
0xbc6, 0xbc7, 0xbc8, 0xbca, 0xbcb, 0xbcc, 0xbcd, 0xbd7,
0xc00, 0xc01, 0xc02, 0xc03, 0xc04, 0xc3e, 0xc3f, 0xc40,
0xc41, 0xc42, 0xc43, 0xc44, 0xc46, 0xc47, 0xc48, 0xc4a,
0xc4b, 0xc4c, 0xc4d, 0xc55, 0xc56, 0xc62, 0xc63, 0xc81,
0xc82, 0xc83, 0xcbc, 0xcbe, 0xcbf, 0xcc0, 0xcc1, 0xcc2,
0xcc3, 0xcc4, 0xcc6, 0xcc7, 0xcc8, 0xcca, 0xccb, 0xccc,
0xccd, 0xcd5, 0xcd6, 0xce2, 0xce3, 0xd00, 0xd01, 0xd02,
0xd03, 0xd3b, 0xd3c, 0xd3e, 0xd3f, 0xd40, 0xd41, 0xd42,
0xd43, 0xd44, 0xd46, 0xd47, 0xd48, 0xd4a, 0xd4b, 0xd4c,
0xd4d, 0xd57, 0xd62, 0xd63, 0xd81, 0xd82, 0xd83, 0xdca,
0xdcf, 0xdd0, 0xdd1, 0xdd2, 0xdd3, 0xdd4, 0xdd6, 0xdd8,
0xdd9, 0xdda, 0xddb, 0xddc, 0xddd, 0xdde, 0xddf, 0xdf2,
0xdf3, 0xe31, 0xe34, 0xe35, 0xe36, 0xe37, 0xe38, 0xe39,
0xe3a, 0xe47, 0xe48, 0xe49, 0xe4a, 0xe4b, 0xe4c, 0xe4d,
0xe4e, 0xeb1, 0xeb4, 0xeb5, 0xeb6, 0xeb7, 0xeb8, 0xeb9,
0xeba, 0xebb, 0xebc, 0xec8, 0xec9, 0xeca, 0xecb, 0xecc,
0xecd, 0xf18, 0xf19, 0xf35, 0xf37, 0xf39, 0xf3e, 0xf3f,
0xf71, 0xf72, 0xf73, 0xf74, 0xf75, 0xf76, 0xf77, 0xf78,
0xf79, 0xf7a, 0xf7b, 0xf7c, 0xf7d, 0xf7e, 0xf7f, 0xf80,
0xf81, 0xf82, 0xf83, 0xf84, 0xf86, 0xf87, 0xf8d, 0xf8e,
0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96,
0xf97, 0xf99, 0xf9a, 0xf9b, 0xf9c, 0xf9d, 0xf9e, 0xf9f,
0xfa0, 0xfa1, 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0xfa7,
0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0xfaf,
0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6, 0xfb7,
0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfc6, 0x102b, 0x102c,
0x102d, 0x102e, 0x102f, 0x1030, 0x1031, 0x1032, 0x1033, 0x1034,
0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103a, 0x103b, 0x103c,
0x103d, 0x103e, 0x1056, 0x1057, 0x1058, 0x1059, 0x105e, 0x105f,
0x1060, 0x1062, 0x1063, 0x1064, 0x1067, 0x1068, 0x1069, 0x106a,
0x106b, 0x106c, 0x106d, 0x1071, 0x1072, 0x1073, 0x1074, 0x1082,
0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108a,
0x108b, 0x108c, 0x108d, 0x108f, 0x109a, 0x109b, 0x109c, 0x109d,
0x135d, 0x135e, 0x135f, 0x1712, 0x1713, 0x1714, 0x1732, 0x1733,
0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 0x17b4, 0x17b5, 0x17b6,
0x17b7, 0x17b8, 0x17b9, 0x17ba, 0x17bb, 0x17bc, 0x17bd, 0x17be,
0x17bf, 0x17c0, 0x17c1, 0x17c2, 0x17c3, 0x17c4, 0x17c5, 0x17c6,
0x17c7, 0x17c8, 0x17c9, 0x17ca, 0x17cb, 0x17cc, 0x17cd, 0x17ce,
0x17cf, 0x17d0, 0x17d1, 0x17d2, 0x17d3, 0x17dd, 0x180b, 0x180c,
0x180d, 0x1885, 0x1886, 0x18a9, 0x1920, 0x1921, 0x1922, 0x1923,
0x1924, 0x1925, 0x1926, 0x1927, 0x1928, 0x1929, 0x192a, 0x192b,
0x1930, 0x1931, 0x1932, 0x1933, 0x1934, 0x1935, 0x1936, 0x1937,
0x1938, 0x1939, 0x193a, 0x193b, 0x1a17, 0x1a18, 0x1a19, 0x1a1a,
0x1a1b, 0x1a55, 0x1a56, 0x1a57, 0x1a58, 0x1a59, 0x1a5a, 0x1a5b,
0x1a5c, 0x1a5d, 0x1a5e, 0x1a60, 0x1a61, 0x1a62, 0x1a63, 0x1a64,
0x1a65, 0x1a66, 0x1a67, 0x1a68, 0x1a69, 0x1a6a, 0x1a6b, 0x1a6c,
0x1a6d, 0x1a6e, 0x1a6f, 0x1a70, 0x1a71, 0x1a72, 0x1a73, 0x1a74,
0x1a75, 0x1a76, 0x1a77, 0x1a78, 0x1a79, 0x1a7a, 0x1a7b, 0x1a7c,
0x1a7f, 0x1ab0, 0x1ab1, 0x1ab2, 0x1ab3, 0x1ab4, 0x1ab5, 0x1ab6,
0x1ab7, 0x1ab8, 0x1ab9, 0x1aba, 0x1abb, 0x1abc, 0x1abd, 0x1abe,
0x1abf, 0x1ac0, 0x1b00, 0x1b01, 0x1b02, 0x1b03, 0x1b04, 0x1b34,
0x1b35, 0x1b36, 0x1b37, 0x1b38, 0x1b39, 0x1b3a, 0x1b3b, 0x1b3c,
0x1b3d, 0x1b3e, 0x1b3f, 0x1b40, 0x1b41, 0x1b42, 0x1b43, 0x1b44,
0x1b6b, 0x1b6c, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b70, 0x1b71, 0x1b72,
0x1b73, 0x1b80, 0x1b81, 0x1b82, 0x1ba1, 0x1ba2, 0x1ba3, 0x1ba4,
0x1ba5, 0x1ba6, 0x1ba7, 0x1ba8, 0x1ba9, 0x1baa, 0x1bab, 0x1bac,
0x1bad, 0x1be6, 0x1be7, 0x1be8, 0x1be9, 0x1bea, 0x1beb, 0x1bec,
0x1bed, 0x1bee, 0x1bef, 0x1bf0, 0x1bf1, 0x1bf2, 0x1bf3, 0x1c24,
0x1c25, 0x1c26, 0x1c27, 0x1c28, 0x1c29, 0x1c2a, 0x1c2b, 0x1c2c,
0x1c2d, 0x1c2e, 0x1c2f, 0x1c30, 0x1c31, 0x1c32, 0x1c33, 0x1c34,
0x1c35, 0x1c36, 0x1c37, 0x1cd0, 0x1cd1, 0x1cd2, 0x1cd4, 0x1cd5,
0x1cd6, 0x1cd7, 0x1cd8, 0x1cd9, 0x1cda, 0x1cdb, 0x1cdc, 0x1cdd,
0x1cde, 0x1cdf, 0x1ce0, 0x1ce1, 0x1ce2, 0x1ce3, 0x1ce4, 0x1ce5,
0x1ce6, 0x1ce7, 0x1ce8, 0x1ced, 0x1cf4, 0x1cf7, 0x1cf8, 0x1cf9,
0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3, 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7,
0x1dc8, 0x1dc9, 0x1dca, 0x1dcb, 0x1dcc, 0x1dcd, 0x1dce, 0x1dcf,
0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3, 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7,
0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf,
0x1de0, 0x1de1, 0x1de2, 0x1de3, 0x1de4, 0x1de5, 0x1de6, 0x1de7,
0x1de8, 0x1de9, 0x1dea, 0x1deb, 0x1dec, 0x1ded, 0x1dee, 0x1def,
0x1df0, 0x1df1, 0x1df2, 0x1df3, 0x1df4, 0x1df5, 0x1df6, 0x1df7,
0x1df8, 0x1df9, 0x1dfb, 0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x20d0,
0x20d1, 0x20d2, 0x20d3, 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8,
0x20d9, 0x20da, 0x20db, 0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0,
0x20e1, 0x20e2, 0x20e3, 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8,
0x20e9, 0x20ea, 0x20eb, 0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0,
0x2cef, 0x2cf0, 0x2cf1, 0x2d7f, 0x2de0, 0x2de1, 0x2de2, 0x2de3,
0x2de4, 0x2de5, 0x2de6, 0x2de7, 0x2de8, 0x2de9, 0x2dea, 0x2deb,
0x2dec, 0x2ded, 0x2dee, 0x2def, 0x2df0, 0x2df1, 0x2df2, 0x2df3,
0x2df4, 0x2df5, 0x2df6, 0x2df7, 0x2df8, 0x2df9, 0x2dfa, 0x2dfb,
0x2dfc, 0x2dfd, 0x2dfe, 0x2dff, 0x302a, 0x302b, 0x302c, 0x302d,
0x302e, 0x302f, 0x3099, 0x309a, 0xa66f, 0xa670, 0xa671, 0xa672,
0xa674, 0xa675, 0xa676, 0xa677, 0xa678, 0xa679, 0xa67a, 0xa67b,
0xa67c, 0xa67d, 0xa69e, 0xa69f, 0xa6f0, 0xa6f1, 0xa802, 0xa806,
0xa80b, 0xa823, 0xa824, 0xa825, 0xa826, 0xa827, 0xa82c, 0xa880,
0xa881, 0xa8b4, 0xa8b5, 0xa8b6, 0xa8b7, 0xa8b8, 0xa8b9, 0xa8ba,
0xa8bb, 0xa8bc, 0xa8bd, 0xa8be, 0xa8bf, 0xa8c0, 0xa8c1, 0xa8c2,
0xa8c3, 0xa8c4, 0xa8c5, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3, 0xa8e4,
0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa8ea, 0xa8eb, 0xa8ec,
0xa8ed, 0xa8ee, 0xa8ef, 0xa8f0, 0xa8f1, 0xa8ff, 0xa926, 0xa927,
0xa928, 0xa929, 0xa92a, 0xa92b, 0xa92c, 0xa92d, 0xa947, 0xa948,
0xa949, 0xa94a, 0xa94b, 0xa94c, 0xa94d, 0xa94e, 0xa94f, 0xa950,
0xa951, 0xa952, 0xa953, 0xa980, 0xa981, 0xa982, 0xa983, 0xa9b3,
0xa9b4, 0xa9b5, 0xa9b6, 0xa9b7, 0xa9b8, 0xa9b9, 0xa9ba, 0xa9bb,
0xa9bc, 0xa9bd, 0xa9be, 0xa9bf, 0xa9c0, 0xa9e5, 0xaa29, 0xaa2a,
0xaa2b, 0xaa2c, 0xaa2d, 0xaa2e, 0xaa2f, 0xaa30, 0xaa31, 0xaa32,
0xaa33, 0xaa34, 0xaa35, 0xaa36, 0xaa43, 0xaa4c, 0xaa4d, 0xaa7b,
0xaa7c, 0xaa7d, 0xaab0, 0xaab2, 0xaab3, 0xaab4, 0xaab7, 0xaab8,
0xaabe, 0xaabf, 0xaac1, 0xaaeb, 0xaaec, 0xaaed, 0xaaee, 0xaaef,
0xaaf5, 0xaaf6, 0xabe3, 0xabe4, 0xabe5, 0xabe6, 0xabe7, 0xabe8,
0xabe9, 0xabea, 0xabec, 0xabed, 0xfb1e, 0xfe00, 0xfe01, 0xfe02,
0xfe03, 0xfe04, 0xfe05, 0xfe06, 0xfe07, 0xfe08, 0xfe09, 0xfe0a,
0xfe0b, 0xfe0c, 0xfe0d, 0xfe0e, 0xfe0f, 0xfe20, 0xfe21, 0xfe22,
0xfe23, 0xfe24, 0xfe25, 0xfe26, 0xfe27, 0xfe28, 0xfe29, 0xfe2a,
0xfe2b, 0xfe2c, 0xfe2d, 0xfe2e, 0xfe2f, 0x101fd, 0x102e0, 0x10376,
0x10377, 0x10378, 0x10379, 0x1037a, 0x10a01, 0x10a02, 0x10a03, 0x10a05,
0x10a06, 0x10a0c, 0x10a0d, 0x10a0e, 0x10a0f, 0x10a38, 0x10a39, 0x10a3a,
0x10a3f, 0x10ae5, 0x10ae6, 0x10d24, 0x10d25, 0x10d26, 0x10d27, 0x10eab,
0x10eac, 0x10f46, 0x10f47, 0x10f48, 0x10f49, 0x10f4a, 0x10f4b, 0x10f4c,
0x10f4d, 0x10f4e, 0x10f4f, 0x10f50, 0x11000, 0x11001, 0x11002, 0x11038,
0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f, 0x11040,
0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x1107f, 0x11080,
0x11081, 0x11082, 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5,
0x110b6, 0x110b7, 0x110b8, 0x110b9, 0x110ba, 0x11100, 0x11101, 0x11102,
0x11127, 0x11128, 0x11129, 0x1112a, 0x1112b, 0x1112c, 0x1112d, 0x1112e,
0x1112f, 0x11130, 0x11131, 0x11132, 0x11133, 0x11134, 0x11145, 0x11146,
0x11173, 0x11180, 0x11181, 0x11182, 0x111b3, 0x111b4, 0x111b5, 0x111b6,
0x111b7, 0x111b8, 0x111b9, 0x111ba, 0x111bb, 0x111bc, 0x111bd, 0x111be,
0x111bf, 0x111c0, 0x111c9, 0x111ca, 0x111cb, 0x111cc, 0x111ce, 0x111cf,
0x1122c, 0x1122d, 0x1122e, 0x1122f, 0x11230, 0x11231, 0x11232, 0x11233,
0x11234, 0x11235, 0x11236, 0x11237, 0x1123e, 0x112df, 0x112e0, 0x112e1,
0x112e2, 0x112e3, 0x112e4, 0x112e5, 0x112e6, 0x112e7, 0x112e8, 0x112e9,
0x112ea, 0x11300, 0x11301, 0x11302, 0x11303, 0x1133b, 0x1133c, 0x1133e,
0x1133f, 0x11340, 0x11341, 0x11342, 0x11343, 0x11344, 0x11347, 0x11348,
0x1134b, 0x1134c, 0x1134d, 0x11357, 0x11362, 0x11363, 0x11366, 0x11367,
0x11368, 0x11369, 0x1136a, 0x1136b, 0x1136c, 0x11370, 0x11371, 0x11372,
0x11373, 0x11374, 0x11435, 0x11436, 0x11437, 0x11438, 0x11439, 0x1143a,
0x1143b, 0x1143c, 0x1143d, 0x1143e, 0x1143f, 0x11440, 0x11441, 0x11442,
0x11443, 0x11444, 0x11445, 0x11446, 0x1145e, 0x114b0, 0x114b1, 0x114b2,
0x114b3, 0x114b4, 0x114b5, 0x114b6, 0x114b7, 0x114b8, 0x114b9, 0x114ba,
0x114bb, 0x114bc, 0x114bd, 0x114be, 0x114bf, 0x114c0, 0x114c1, 0x114c2,
0x114c3, 0x115af, 0x115b0, 0x115b1, 0x115b2, 0x115b3, 0x115b4, 0x115b5,
0x115b8, 0x115b9, 0x115ba, 0x115bb, 0x115bc, 0x115bd, 0x115be, 0x115bf,
0x115c0, 0x115dc, 0x115dd, 0x11630, 0x11631, 0x11632, 0x11633, 0x11634,
0x11635, 0x11636, 0x11637, 0x11638, 0x11639, 0x1163a, 0x1163b, 0x1163c,
0x1163d, 0x1163e, 0x1163f, 0x11640, 0x116ab, 0x116ac, 0x116ad, 0x116ae,
0x116af, 0x116b0, 0x116b1, 0x116b2, 0x116b3, 0x116b4, 0x116b5, 0x116b6,
0x116b7, 0x1171d, 0x1171e, 0x1171f, 0x11720, 0x11721, 0x11722, 0x11723,
0x11724, 0x11725, 0x11726, 0x11727, 0x11728, 0x11729, 0x1172a, 0x1172b,
0x1182c, 0x1182d, 0x1182e, 0x1182f, 0x11830, 0x11831, 0x11832, 0x11833,
0x11834, 0x11835, 0x11836, 0x11837, 0x11838, 0x11839, 0x1183a, 0x11930,
0x11931, 0x11932, 0x11933, 0x11934, 0x11935, 0x11937, 0x11938, 0x1193b,
0x1193c, 0x1193d, 0x1193e, 0x11940, 0x11942, 0x11943, 0x119d1, 0x119d2,
0x119d3, 0x119d4, 0x119d5, 0x119d6, 0x119d7, 0x119da, 0x119db, 0x119dc,
0x119dd, 0x119de, 0x119df, 0x119e0, 0x119e4, 0x11a01, 0x11a02, 0x11a03,
0x11a04, 0x11a05, 0x11a06, 0x11a07, 0x11a08, 0x11a09, 0x11a0a, 0x11a33,
0x11a34, 0x11a35, 0x11a36, 0x11a37, 0x11a38, 0x11a39, 0x11a3b, 0x11a3c,
0x11a3d, 0x11a3e, 0x11a47, 0x11a51, 0x11a52, 0x11a53, 0x11a54, 0x11a55,
0x11a56, 0x11a57, 0x11a58, 0x11a59, 0x11a5a, 0x11a5b, 0x11a8a, 0x11a8b,
0x11a8c, 0x11a8d, 0x11a8e, 0x11a8f, 0x11a90, 0x11a91, 0x11a92, 0x11a93,
0x11a94, 0x11a95, 0x11a96, 0x11a97, 0x11a98, 0x11a99, 0x11c2f, 0x11c30,
0x11c31, 0x11c32, 0x11c33, 0x11c34, 0x11c35, 0x11c36, 0x11c38, 0x11c39,
0x11c3a, 0x11c3b, 0x11c3c, 0x11c3d, 0x11c3e, 0x11c3f, 0x11c92, 0x11c93,
0x11c94, 0x11c95, 0x11c96, 0x11c97, 0x11c98, 0x11c99, 0x11c9a, 0x11c9b,
0x11c9c, 0x11c9d, 0x11c9e, 0x11c9f, 0x11ca0, 0x11ca1, 0x11ca2, 0x11ca3,
0x11ca4, 0x11ca5, 0x11ca6, 0x11ca7, 0x11ca9, 0x11caa, 0x11cab, 0x11cac,
0x11cad, 0x11cae, 0x11caf, 0x11cb0, 0x11cb1, 0x11cb2, 0x11cb3, 0x11cb4,
0x11cb5, 0x11cb6, 0x11d31, 0x11d32, 0x11d33, 0x11d34, 0x11d35, 0x11d36,
0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d40, 0x11d41, 0x11d42, 0x11d43,
0x11d44, 0x11d45, 0x11d47, 0x11d8a, 0x11d8b, 0x11d8c, 0x11d8d, 0x11d8e,
0x11d90, 0x11d91, 0x11d93, 0x11d94, 0x11d95, 0x11d96, 0x11d97, 0x11ef3,
0x11ef4, 0x11ef5, 0x11ef6, 0x16af0, 0x16af1, 0x16af2, 0x16af3, 0x16af4,
0x16b30, 0x16b31, 0x16b32, 0x16b33, 0x16b34, 0x16b35, 0x16b36, 0x16f4f,
0x16f51, 0x16f52, 0x16f53, 0x16f54, 0x16f55, 0x16f56, 0x16f57, 0x16f58,
0x16f59, 0x16f5a, 0x16f5b, 0x16f5c, 0x16f5d, 0x16f5e, 0x16f5f, 0x16f60,
0x16f61, 0x16f62, 0x16f63, 0x16f64, 0x16f65, 0x16f66, 0x16f67, 0x16f68,
0x16f69, 0x16f6a, 0x16f6b, 0x16f6c, 0x16f6d, 0x16f6e, 0x16f6f, 0x16f70,
0x16f71, 0x16f72, 0x16f73, 0x16f74, 0x16f75, 0x16f76, 0x16f77, 0x16f78,
0x16f79, 0x16f7a, 0x16f7b, 0x16f7c, 0x16f7d, 0x16f7e, 0x16f7f, 0x16f80,
0x16f81, 0x16f82, 0x16f83, 0x16f84, 0x16f85, 0x16f86, 0x16f87, 0x16f8f,
0x16f90, 0x16f91, 0x16f92, 0x16fe4, 0x16ff0, 0x16ff1, 0x1bc9d, 0x1bc9e,
0x1d165, 0x1d166, 0x1d167, 0x1d168, 0x1d169, 0x1d16d, 0x1d16e, 0x1d16f,
0x1d170, 0x1d171, 0x1d172, 0x1d17b, 0x1d17c, 0x1d17d, 0x1d17e, 0x1d17f,
0x1d180, 0x1d181, 0x1d182, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189,
0x1d18a, 0x1d18b, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243,
0x1d244, 0x1da00, 0x1da01, 0x1da02, 0x1da03, 0x1da04, 0x1da05, 0x1da06,
0x1da07, 0x1da08, 0x1da09, 0x1da0a, 0x1da0b, 0x1da0c, 0x1da0d, 0x1da0e,
0x1da0f, 0x1da10, 0x1da11, 0x1da12, 0x1da13, 0x1da14, 0x1da15, 0x1da16,
0x1da17, 0x1da18, 0x1da19, 0x1da1a, 0x1da1b, 0x1da1c, 0x1da1d, 0x1da1e,
0x1da1f, 0x1da20, 0x1da21, 0x1da22, 0x1da23, 0x1da24, 0x1da25, 0x1da26,
0x1da27, 0x1da28, 0x1da29, 0x1da2a, 0x1da2b, 0x1da2c, 0x1da2d, 0x1da2e,
0x1da2f, 0x1da30, 0x1da31, 0x1da32, 0x1da33, 0x1da34, 0x1da35, 0x1da36,
0x1da3b, 0x1da3c, 0x1da3d, 0x1da3e, 0x1da3f, 0x1da40, 0x1da41, 0x1da42,
0x1da43, 0x1da44, 0x1da45, 0x1da46, 0x1da47, 0x1da48, 0x1da49, 0x1da4a,
0x1da4b, 0x1da4c, 0x1da4d, 0x1da4e, 0x1da4f, 0x1da50, 0x1da51, 0x1da52,
0x1da53, 0x1da54, 0x1da55, 0x1da56, 0x1da57, 0x1da58, 0x1da59, 0x1da5a,
0x1da5b, 0x1da5c, 0x1da5d, 0x1da5e, 0x1da5f, 0x1da60, 0x1da61, 0x1da62,
0x1da63, 0x1da64, 0x1da65, 0x1da66, 0x1da67, 0x1da68, 0x1da69, 0x1da6a,
0x1da6b, 0x1da6c, 0x1da75, 0x1da84, 0x1da9b, 0x1da9c, 0x1da9d, 0x1da9e,
0x1da9f, 0x1daa1, 0x1daa2, 0x1daa3, 0x1daa4, 0x1daa5, 0x1daa6, 0x1daa7,
0x1daa8, 0x1daa9, 0x1daaa, 0x1daab, 0x1daac, 0x1daad, 0x1daae, 0x1daaf,
0x1e000, 0x1e001, 0x1e002, 0x1e003, 0x1e004, 0x1e005, 0x1e006, 0x1e008,
0x1e009, 0x1e00a, 0x1e00b, 0x1e00c, 0x1e00d, 0x1e00e, 0x1e00f, 0x1e010,
0x1e011, 0x1e012, 0x1e013, 0x1e014, 0x1e015, 0x1e016, 0x1e017, 0x1e018,
0x1e01b, 0x1e01c, 0x1e01d, 0x1e01e, 0x1e01f, 0x1e020, 0x1e021, 0x1e023,
0x1e024, 0x1e026, 0x1e027, 0x1e028, 0x1e029, 0x1e02a, 0x1e130, 0x1e131,
0x1e132, 0x1e133, 0x1e134, 0x1e135, 0x1e136, 0x1e2ec, 0x1e2ed, 0x1e2ee,
0x1e2ef, 0x1e8d0, 0x1e8d1, 0x1e8d2, 0x1e8d3, 0x1e8d4, 0x1e8d5, 0x1e8d6,
0x1e944, 0x1e945, 0x1e946, 0x1e947, 0x1e948, 0x1e949, 0x1e94a, 0xe0100,
0xe0101, 0xe0102, 0xe0103, 0xe0104, 0xe0105, 0xe0106, 0xe0107, 0xe0108,
0xe0109, 0xe010a, 0xe010b, 0xe010c, 0xe010d, 0xe010e, 0xe010f, 0xe0110,
0xe0111, 0xe0112, 0xe0113, 0xe0114, 0xe0115, 0xe0116, 0xe0117, 0xe0118,
0xe0119, 0xe011a, 0xe011b, 0xe011c, 0xe011d, 0xe011e, 0xe011f, 0xe0120,
0xe0121, 0xe0122, 0xe0123, 0xe0124, 0xe0125, 0xe0126, 0xe0127, 0xe0128,
0xe0129, 0xe012a, 0xe012b, 0xe012c, 0xe012d, 0xe012e, 0xe012f, 0xe0130,
0xe0131, 0xe0132, 0xe0133, 0xe0134, 0xe0135, 0xe0136, 0xe0137, 0xe0138,
0xe0139, 0xe013a, 0xe013b, 0xe013c, 0xe013d, 0xe013e, 0xe013f, 0xe0140,
0xe0141, 0xe0142, 0xe0143, 0xe0144, 0xe0145, 0xe0146, 0xe0147, 0xe0148,
0xe0149, 0xe014a, 0xe014b, 0xe014c, 0xe014d, 0xe014e, 0xe014f, 0xe0150,
0xe0151, 0xe0152, 0xe0153, 0xe0154, 0xe0155, 0xe0156, 0xe0157, 0xe0158,
0xe0159, 0xe015a, 0xe015b, 0xe015c, 0xe015d, 0xe015e, 0xe015f, 0xe0160,
0xe0161, 0xe0162, 0xe0163, 0xe0164, 0xe0165, 0xe0166, 0xe0167, 0xe0168,
0xe0169, 0xe016a, 0xe016b, 0xe016c, 0xe016d, 0xe016e, 0xe016f, 0xe0170,
0xe0171, 0xe0172, 0xe0173, 0xe0174, 0xe0175, 0xe0176, 0xe0177, 0xe0178,
0xe0179, 0xe017a, 0xe017b, 0xe017c, 0xe017d, 0xe017e, 0xe017f, 0xe0180,
0xe0181, 0xe0182, 0xe0183, 0xe0184, 0xe0185, 0xe0186, 0xe0187, 0xe0188,
0xe0189, 0xe018a, 0xe018b, 0xe018c, 0xe018d, 0xe018e, 0xe018f, 0xe0190,
0xe0191, 0xe0192, 0xe0193, 0xe0194, 0xe0195, 0xe0196, 0xe0197, 0xe0198,
0xe0199, 0xe019a, 0xe019b, 0xe019c, 0xe019d, 0xe019e, 0xe019f, 0xe01a0,
0xe01a1, 0xe01a2, 0xe01a3, 0xe01a4, 0xe01a5, 0xe01a6, 0xe01a7, 0xe01a8,
0xe01a9, 0xe01aa, 0xe01ab, 0xe01ac, 0xe01ad, 0xe01ae, 0xe01af, 0xe01b0,
0xe01b1, 0xe01b2, 0xe01b3, 0xe01b4, 0xe01b5, 0xe01b6, 0xe01b7, 0xe01b8,
0xe01b9, 0xe01ba, 0xe01bb, 0xe01bc, 0xe01bd, 0xe01be, 0xe01bf, 0xe01c0,
0xe01c1, 0xe01c2, 0xe01c3, 0xe01c4, 0xe01c5, 0xe01c6, 0xe01c7, 0xe01c8,
0xe01c9, 0xe01ca, 0xe01cb, 0xe01cc, 0xe01cd, 0xe01ce, 0xe01cf, 0xe01d0,
0xe01d1, 0xe01d2, 0xe01d3, 0xe01d4, 0xe01d5, 0xe01d6, 0xe01d7, 0xe01d8,
0xe01d9, 0xe01da, 0xe01db, 0xe01dc, 0xe01dd, 0xe01de, 0xe01df, 0xe01e0,
0xe01e1, 0xe01e2, 0xe01e3, 0xe01e4, 0xe01e5, 0xe01e6, 0xe01e7, 0xe01e8,
0xe01e9, 0xe01ea, 0xe01eb, 0xe01ec, 0xe01ed, 0xe01ee, 0xe01ef};
if (std::binary_search(std::begin(combining), std::end(combining),
label.front())) {
return false;
}
// We verify this next step as part of the mapping:
// ---------------------------------------------
// Each code point in the label must only have certain status values
// according to Section 5, IDNA Mapping Table:
// - For Transitional Processing, each value must be valid.
// - For Nontransitional Processing, each value must be either valid or
// deviation.
// If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
// A, in The Unicode Code Points and Internationalized Domain Names for
// Applications (IDNA) [IDNA2008].
constexpr static uint32_t virama[] = {
0x094D, 0x09CD, 0x0A4D, 0x0ACD, 0x0B4D, 0x0BCD, 0x0C4D, 0x0CCD,
0x0D3B, 0x0D3C, 0x0D4D, 0x0DCA, 0x0E3A, 0x0EBA, 0x0F84, 0x1039,
0x103A, 0x1714, 0x1734, 0x17D2, 0x1A60, 0x1B44, 0x1BAA, 0x1BAB,
0x1BF2, 0x1BF3, 0x2D7F, 0xA806, 0xA82C, 0xA8C4, 0xA953, 0xA9C0,
0xAAF6, 0xABED, 0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
constexpr static uint32_t R[] = {
0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
constexpr static uint32_t L[] = {0xa872};
constexpr static uint32_t D[] = {
0x620, 0x626, 0x628, 0x62a, 0x62b, 0x62c, 0x62d, 0x62e, 0x633,
0x634, 0x635, 0x636, 0x637, 0x638, 0x639, 0x63a, 0x63b, 0x63c,
0x63d, 0x63e, 0x63f, 0x641, 0x642, 0x643, 0x644, 0x645, 0x646,
0x647, 0x649, 0x64a, 0x66e, 0x66f, 0x678, 0x679, 0x67a, 0x67b,
0x67c, 0x67d, 0x67e, 0x67f, 0x680, 0x681, 0x682, 0x683, 0x684,
0x685, 0x686, 0x687, 0x69a, 0x69b, 0x69c, 0x69d, 0x69e, 0x69f,
0x6a0, 0x6a1, 0x6a2, 0x6a3, 0x6a4, 0x6a5, 0x6a6, 0x6a7, 0x6a8,
0x6a9, 0x6aa, 0x6ab, 0x6ac, 0x6ad, 0x6ae, 0x6af, 0x6b0, 0x6b1,
0x6b2, 0x6b3, 0x6b4, 0x6b5, 0x6b6, 0x6b7, 0x6b8, 0x6b9, 0x6ba,
0x6bb, 0x6bc, 0x6bd, 0x6be, 0x6bf, 0x6c1, 0x6c2, 0x6cc, 0x6ce,
0x6d0, 0x6d1, 0x6fa, 0x6fb, 0x6fc, 0x6ff, 0x712, 0x713, 0x714,
0x71a, 0x71b, 0x71c, 0x71d, 0x71f, 0x720, 0x721, 0x722, 0x723,
0x724, 0x725, 0x726, 0x727, 0x729, 0x72b, 0x72d, 0x72e, 0x74e,
0x74f, 0x750, 0x751, 0x752, 0x753, 0x754, 0x755, 0x756, 0x757,
0x758, 0x75c, 0x75d, 0x75e, 0x75f, 0x760, 0x761, 0x762, 0x763,
0x764, 0x765, 0x766, 0x850, 0x851, 0x852, 0x853, 0x855, 0x8a0,
0x8a2, 0x8a3, 0x8a4, 0x8a5, 0x8a6, 0x8a7, 0x8a8, 0x8a9, 0x1807,
0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
0xa870, 0xa871};
for (size_t i = 0; i < label.size(); i++) {
uint32_t c = label[i];
if (c == 0x200c) {
if (i > 0) {
if (std::binary_search(std::begin(virama), std::end(virama),
label[i - 1])) {
return true;
}
}
if ((i == 0) || (i + 1 >= label.size())) {
return false;
}
// we go backward looking for L or D
auto is_l_or_d = [](uint32_t code) {
return std::binary_search(std::begin(L), std::end(L), code) ||
std::binary_search(std::begin(D), std::end(D), code);
};
auto is_r_or_d = [](uint32_t code) {
return std::binary_search(std::begin(R), std::end(R), code) ||
std::binary_search(std::begin(D), std::end(D), code);
};
std::u32string_view before = label.substr(0, i);
std::u32string_view after = label.substr(i + 1);
return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
before.end()) &&
(std::find_if(after.begin(), after.end(), is_r_or_d) !=
after.end());
} else if (c == 0x200d) {
if (i > 0) {
if (std::binary_search(std::begin(virama), std::end(virama),
label[i - 1])) {
return true;
}
}
return false;
}
}
// If CheckBidi, and if the domain name is a Bidi domain name, then the label
// must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
// Section 2.
// The following rule, consisting of six conditions, applies to labels
// in Bidi domain names. The requirements that this rule satisfies are
// described in Section 3. All of the conditions must be satisfied for
// the rule to be satisfied.
//
// 1. The first character must be a character with Bidi property L, R,
// or AL. If it has the R or AL property, it is an RTL label; if it
// has the L property, it is an LTR label.
//
// 2. In an RTL label, only characters with the Bidi properties R, AL,
// AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
//
// 3. In an RTL label, the end of the label must be a character with
// Bidi property R, AL, EN, or AN, followed by zero or more
// characters with Bidi property NSM.
//
// 4. In an RTL label, if an EN is present, no AN may be present, and
// vice versa.
//
// 5. In an LTR label, only characters with the Bidi properties L, EN,
// ES, CS, ET, ON, BN, or NSM are allowed.
//
// 6. In an LTR label, the end of the label must be a character with
// Bidi property L or EN, followed by zero or more characters with
// Bidi property NSM.
size_t last_non_nsm_char = find_last_not_of_nsm(label);
if (last_non_nsm_char == std::u32string_view::npos) {
return false;
}
// A "Bidi domain name" is a domain name that contains at least one RTL label.
// The following rule, consisting of six conditions, applies to labels in Bidi
// domain names.
if (is_rtl_label(label)) {
// The first character must be a character with Bidi property L, R,
// or AL. If it has the R or AL property, it is an RTL label; if it
// has the L property, it is an LTR label.
if (find_direction(label[0]) == direction::L) {
// Eval as LTR
// In an LTR label, only characters with the Bidi properties L, EN,
// ES, CS, ET, ON, BN, or NSM are allowed.
for (size_t i = 0; i < last_non_nsm_char; i++) {
const direction d = find_direction(label[i]);
if (!(d == direction::L || d == direction::EN || d == direction::ES ||
d == direction::CS || d == direction::ET || d == direction::ON ||
d == direction::BN || d == direction::NSM)) {
return false;
}
if ((i == last_non_nsm_char) &&
!(d == direction::L || d == direction::EN)) {
return false;
}
}
return true;
} else {
// Eval as RTL
bool has_an = false;
bool has_en = false;
for (size_t i = 0; i <= last_non_nsm_char; i++) {
const direction d = find_direction(label[i]);
// In an RTL label, if an EN is present, no AN may be present, and vice
// versa.
if ((d == direction::EN && ((has_en = true) && has_an)) ||
(d == direction::AN && ((has_an = true) && has_en))) {
return false;
}
if (!(d == direction::R || d == direction::AL || d == direction::AN ||
d == direction::EN || d == direction::ES || d == direction::CS ||
d == direction::ET || d == direction::ON || d == direction::BN ||
d == direction::NSM)) {
return false;
}
if (i == last_non_nsm_char &&
!(d == direction::R || d == direction::AL || d == direction::AN ||
d == direction::EN)) {
return false;
}
}
return true;
}
}
return true;
}
} // namespace ada::idna
/* end file src/validity.cpp */
/* begin file src/to_ascii.cpp */
#include <algorithm>
#include <cstdint>
#include <ranges>
namespace ada::idna {
bool constexpr is_ascii(std::u32string_view view) {
for (uint32_t c : view) {
if (c >= 0x80) {
return false;
}
}
return true;
}
bool constexpr is_ascii(std::string_view view) {
for (uint8_t c : view) {
if (c >= 0x80) {
return false;
}
}
return true;
}
constexpr static uint8_t is_forbidden_domain_code_point_table[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static_assert(sizeof(is_forbidden_domain_code_point_table) == 256);
inline bool is_forbidden_domain_code_point(const char c) noexcept {
return is_forbidden_domain_code_point_table[uint8_t(c)];
}
bool contains_forbidden_domain_code_point(std::string_view view) {
return std::ranges::any_of(view, is_forbidden_domain_code_point);
}
// We return "" on error.
static std::string from_ascii_to_ascii(std::string_view ut8_string) {
static const std::string error = "";
// copy and map
// we could be more efficient by avoiding the copy when unnecessary.
std::string mapped_string = std::string(ut8_string);
ascii_map(mapped_string.data(), mapped_string.size());
std::string out;
size_t label_start = 0;
while (label_start != mapped_string.size()) {
size_t loc_dot = mapped_string.find('.', label_start);
bool is_last_label = (loc_dot == std::string_view::npos);
size_t label_size = is_last_label ? mapped_string.size() - label_start
: loc_dot - label_start;
size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
std::string_view label_view(mapped_string.data() + label_start, label_size);
label_start += label_size_with_dot;
if (label_size == 0) {
// empty label? Nothing to do.
} else if (label_view.starts_with("xn--")) {
// The xn-- part is the expensive game.
out.append(label_view);
std::string_view puny_segment_ascii(
out.data() + out.size() - label_view.size() + 4,
label_view.size() - 4);
std::u32string tmp_buffer;
bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
if (!is_ok) {
return error;
}
// If the input is just ASCII, it should not have been encoded
// as punycode.
// https://github.com/whatwg/url/issues/760
if (is_ascii(tmp_buffer)) {
return error;
}
std::u32string post_map = ada::idna::map(tmp_buffer);
if (tmp_buffer != post_map) {
return error;
}
std::u32string pre_normal = post_map;
normalize(post_map);
if (post_map != pre_normal) {
return error;
}
if (post_map.empty()) {
return error;
}
if (!is_label_valid(post_map)) {
return error;
}
} else {
out.append(label_view);
}
if (!is_last_label) {
out.push_back('.');
}
}
return out;
}
// We return "" on error.
std::string to_ascii(std::string_view ut8_string) {
if (is_ascii(ut8_string)) {
return from_ascii_to_ascii(ut8_string);
}
static const std::string error = "";
// We convert to UTF-32
size_t utf32_length =
ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
std::u32string utf32(utf32_length, '\0');
size_t actual_utf32_length = ada::idna::utf8_to_utf32(
ut8_string.data(), ut8_string.size(), utf32.data());
if (actual_utf32_length == 0) {
return error;
}
// mapping
utf32 = ada::idna::map(utf32);
normalize(utf32);
std::string out;
size_t label_start = 0;
while (label_start != utf32.size()) {
size_t loc_dot = utf32.find('.', label_start);
bool is_last_label = (loc_dot == std::string_view::npos);
size_t label_size =
is_last_label ? utf32.size() - label_start : loc_dot - label_start;
size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
std::u32string_view label_view(utf32.data() + label_start, label_size);
label_start += label_size_with_dot;
if (label_size == 0) {
// empty label? Nothing to do.
} else if (label_view.starts_with(U"xn--")) {
// we do not need to check, e.g., Xn-- because mapping goes to lower case
for (char32_t c : label_view) {
if (c >= 0x80) {
return error;
}
out += (unsigned char)(c);
}
std::string_view puny_segment_ascii(
out.data() + out.size() - label_view.size() + 4,
label_view.size() - 4);
std::u32string tmp_buffer;
bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
if (!is_ok) {
return error;
}
// If the input is just ASCII, it should not have been encoded
// as punycode.
// https://github.com/whatwg/url/issues/760
if (is_ascii(tmp_buffer)) {
return error;
}
std::u32string post_map = ada::idna::map(tmp_buffer);
if (tmp_buffer != post_map) {
return error;
}
std::u32string pre_normal = post_map;
normalize(post_map);
if (post_map != pre_normal) {
return error;
}
if (post_map.empty()) {
return error;
}
if (!is_label_valid(post_map)) {
return error;
}
} else {
// The fast path here is an ascii label.
if (is_ascii(label_view)) {
// no validation needed.
for (char32_t c : label_view) {
out += (unsigned char)(c);
}
} else {
// slow path.
// first check validity.
if (!is_label_valid(label_view)) {
return error;
}
// It is valid! So now we must encode it as punycode...
out.append("xn--");
bool is_ok = ada::idna::utf32_to_punycode(label_view, out);
if (!is_ok) {
return error;
}
}
}
if (!is_last_label) {
out.push_back('.');
}
}
return out;
}
} // namespace ada::idna
/* end file src/to_ascii.cpp */
/* begin file src/to_unicode.cpp */
#include <algorithm>
#include <string>
namespace ada::idna {
std::string to_unicode(std::string_view input) {
std::string output;
output.reserve(input.size());
size_t label_start = 0;
while (label_start < input.size()) {
size_t loc_dot = input.find('.', label_start);
bool is_last_label = (loc_dot == std::string_view::npos);
size_t label_size =
is_last_label ? input.size() - label_start : loc_dot - label_start;
auto label_view = std::string_view(input.data() + label_start, label_size);
if (label_view.starts_with("xn--") && ada::idna::is_ascii(label_view)) {
label_view.remove_prefix(4);
if (ada::idna::verify_punycode(label_view)) {
std::u32string tmp_buffer;
if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) {
auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(),
tmp_buffer.size());
std::string final_utf8(utf8_size, '\0');
ada::idna::utf32_to_utf8(tmp_buffer.data(), tmp_buffer.size(),
final_utf8.data());
output.append(final_utf8);
} else {
// ToUnicode never fails. If any step fails, then the original input
// sequence is returned immediately in that step.
output.append(
std::string_view(input.data() + label_start, label_size));
}
} else {
output.append(std::string_view(input.data() + label_start, label_size));
}
} else {
output.append(label_view);
}
if (!is_last_label) {
output.push_back('.');
}
label_start += label_size + 1;
}
return output;
}
} // namespace ada::idna
/* end file src/to_unicode.cpp */
/* begin file src/identifier.cpp */
#include <algorithm>
#include <array>
#include <string>
/* begin file src/id_tables.cpp */
// IDNA 16.0.0
// clang-format off
#ifndef ADA_IDNA_IDENTIFIER_TABLES_H
#define ADA_IDNA_IDENTIFIER_TABLES_H
#include <cstdint>
namespace ada::idna {
const uint32_t id_continue[1393][2] =
{
{48, 57}, {65, 90}, {95, 95}, {97, 122},
{170, 170}, {181, 181}, {183, 183}, {186, 186},
{192, 214}, {216, 246}, {248, 442}, {443, 443},
{444, 447}, {448, 451}, {452, 659}, {660, 660},
{661, 687}, {688, 705}, {710, 721}, {736, 740},
{748, 748}, {750, 750}, {768, 879}, {880, 883},
{884, 884}, {886, 887}, {890, 890}, {891, 893},
{895, 895}, {902, 902}, {903, 903}, {904, 906},
{908, 908}, {910, 929}, {931, 1013}, {1015, 1153},
{1155, 1159}, {1162, 1327}, {1329, 1366}, {1369, 1369},
{1376, 1416}, {1425, 1469}, {1471, 1471}, {1473, 1474},
{1476, 1477}, {1479, 1479}, {1488, 1514}, {1519, 1522},
{1552, 1562}, {1568, 1599}, {1600, 1600}, {1601, 1610},
{1611, 1631}, {1632, 1641}, {1646, 1647}, {1648, 1648},
{1649, 1747}, {1749, 1749}, {1750, 1756}, {1759, 1764},
{1765, 1766}, {1767, 1768}, {1770, 1773}, {1774, 1775},
{1776, 1785}, {1786, 1788}, {1791, 1791}, {1808, 1808},
{1809, 1809}, {1810, 1839}, {1840, 1866}, {1869, 1957},
{1958, 1968}, {1969, 1969}, {1984, 1993}, {1994, 2026},
{2027, 2035}, {2036, 2037}, {2042, 2042}, {2045, 2045},
{2048, 2069}, {2070, 2073}, {2074, 2074}, {2075, 2083},
{2084, 2084}, {2085, 2087}, {2088, 2088}, {2089, 2093},
{2112, 2136}, {2137, 2139}, {2144, 2154}, {2160, 2183},
{2185, 2190}, {2199, 2207}, {2208, 2248}, {2249, 2249},
{2250, 2273}, {2275, 2306}, {2307, 2307}, {2308, 2361},
{2362, 2362}, {2363, 2363}, {2364, 2364}, {2365, 2365},
{2366, 2368}, {2369, 2376}, {2377, 2380}, {2381, 2381},
{2382, 2383}, {2384, 2384}, {2385, 2391}, {2392, 2401},
{2402, 2403}, {2406, 2415}, {2417, 2417}, {2418, 2432},
{2433, 2433}, {2434, 2435}, {2437, 2444}, {2447, 2448},
{2451, 2472}, {2474, 2480}, {2482, 2482}, {2486, 2489},
{2492, 2492}, {2493, 2493}, {2494, 2496}, {2497, 2500},
{2503, 2504}, {2507, 2508}, {2509, 2509}, {2510, 2510},
{2519, 2519}, {2524, 2525}, {2527, 2529}, {2530, 2531},
{2534, 2543}, {2544, 2545}, {2556, 2556}, {2558, 2558},
{2561, 2562}, {2563, 2563}, {2565, 2570}, {2575, 2576},
{2579, 2600}, {2602, 2608}, {2610, 2611}, {2613, 2614},
{2616, 2617}, {2620, 2620}, {2622, 2624}, {2625, 2626},
{2631, 2632}, {2635, 2637}, {2641, 2641}, {2649, 2652},
{2654, 2654}, {2662, 2671}, {2672, 2673}, {2674, 2676},
{2677, 2677}, {2689, 2690}, {2691, 2691}, {2693, 2701},
{2703, 2705}, {2707, 2728}, {2730, 2736}, {2738, 2739},
{2741, 2745}, {2748, 2748}, {2749, 2749}, {2750, 2752},
{2753, 2757}, {2759, 2760}, {2761, 2761}, {2763, 2764},
{2765, 2765}, {2768, 2768}, {2784, 2785}, {2786, 2787},
{2790, 2799}, {2809, 2809}, {2810, 2815}, {2817, 2817},
{2818, 2819}, {2821, 2828}, {2831, 2832}, {2835, 2856},
{2858, 2864}, {2866, 2867}, {2869, 2873}, {2876, 2876},
{2877, 2877}, {2878, 2878}, {2879, 2879}, {2880, 2880},
{2881, 2884}, {2887, 2888}, {2891, 2892}, {2893, 2893},
{2901, 2902}, {2903, 2903}, {2908, 2909}, {2911, 2913},
{2914, 2915}, {2918, 2927}, {2929, 2929}, {2946, 2946},
{2947, 2947}, {2949, 2954}, {2958, 2960}, {2962, 2965},
{2969, 2970}, {2972, 2972}, {2974, 2975}, {2979, 2980},
{2984, 2986}, {2990, 3001}, {3006, 3007}, {3008, 3008},
{3009, 3010}, {3014, 3016}, {3018, 3020}, {3021, 3021},
{3024, 3024}, {3031, 3031}, {3046, 3055}, {3072, 3072},
{3073, 3075}, {3076, 3076}, {3077, 3084}, {3086, 3088},
{3090, 3112}, {3114, 3129}, {3132, 3132}, {3133, 3133},
{3134, 3136}, {3137, 3140}, {3142, 3144}, {3146, 3149},
{3157, 3158}, {3160, 3162}, {3165, 3165}, {3168, 3169},
{3170, 3171}, {3174, 3183}, {3200, 3200}, {3201, 3201},
{3202, 3203}, {3205, 3212}, {3214, 3216}, {3218, 3240},
{3242, 3251}, {3253, 3257}, {3260, 3260}, {3261, 3261},
{3262, 3262}, {3263, 3263}, {3264, 3268}, {3270, 3270},
{3271, 3272}, {3274, 3275}, {3276, 3277}, {3285, 3286},
{3293, 3294}, {3296, 3297}, {3298, 3299}, {3302, 3311},
{3313, 3314}, {3315, 3315}, {3328, 3329}, {3330, 3331},
{3332, 3340}, {3342, 3344}, {3346, 3386}, {3387, 3388},
{3389, 3389}, {3390, 3392}, {3393, 3396}, {3398, 3400},
{3402, 3404}, {3405, 3405}, {3406, 3406}, {3412, 3414},
{3415, 3415}, {3423, 3425}, {3426, 3427}, {3430, 3439},
{3450, 3455}, {3457, 3457}, {3458, 3459}, {3461, 3478},
{3482, 3505}, {3507, 3515}, {3517, 3517}, {3520, 3526},
{3530, 3530}, {3535, 3537}, {3538, 3540}, {3542, 3542},
{3544, 3551}, {3558, 3567}, {3570, 3571}, {3585, 3632},
{3633, 3633}, {3634, 3635}, {3636, 3642}, {3648, 3653},
{3654, 3654}, {3655, 3662}, {3664, 3673}, {3713, 3714},
{3716, 3716}, {3718, 3722}, {3724, 3747}, {3749, 3749},
{3751, 3760}, {3761, 3761}, {3762, 3763}, {3764, 3772},
{3773, 3773}, {3776, 3780}, {3782, 3782}, {3784, 3790},
{3792, 3801}, {3804, 3807}, {3840, 3840}, {3864, 3865},
{3872, 3881}, {3893, 3893}, {3895, 3895}, {3897, 3897},
{3902, 3903}, {3904, 3911}, {3913, 3948}, {3953, 3966},
{3967, 3967}, {3968, 3972}, {3974, 3975}, {3976, 3980},
{3981, 3991}, {3993, 4028}, {4038, 4038}, {4096, 4138},
{4139, 4140}, {4141, 4144}, {4145, 4145}, {4146, 4151},
{4152, 4152}, {4153, 4154}, {4155, 4156}, {4157, 4158},
{4159, 4159}, {4160, 4169}, {4176, 4181}, {4182, 4183},
{4184, 4185}, {4186, 4189}, {4190, 4192}, {4193, 4193},
{4194, 4196}, {4197, 4198}, {4199, 4205}, {4206, 4208},
{4209, 4212}, {4213, 4225}, {4226, 4226}, {4227, 4228},
{4229, 4230}, {4231, 4236}, {4237, 4237}, {4238, 4238},
{4239, 4239}, {4240, 4249}, {4250, 4252}, {4253, 4253},
{4256, 4293}, {4295, 4295}, {4301, 4301}, {4304, 4346},
{4348, 4348}, {4349, 4351}, {4352, 4680}, {4682, 4685},
{4688, 4694}, {4696, 4696}, {4698, 4701}, {4704, 4744},
{4746, 4749}, {4752, 4784}, {4786, 4789}, {4792, 4798},
{4800, 4800}, {4802, 4805}, {4808, 4822}, {4824, 4880},
{4882, 4885}, {4888, 4954}, {4957, 4959}, {4969, 4977},
{4992, 5007}, {5024, 5109}, {5112, 5117}, {5121, 5740},
{5743, 5759}, {5761, 5786}, {5792, 5866}, {5870, 5872},
{5873, 5880}, {5888, 5905}, {5906, 5908}, {5909, 5909},
{5919, 5937}, {5938, 5939}, {5940, 5940}, {5952, 5969},
{5970, 5971}, {5984, 5996}, {5998, 6000}, {6002, 6003},
{6016, 6067}, {6068, 6069}, {6070, 6070}, {6071, 6077},
{6078, 6085}, {6086, 6086}, {6087, 6088}, {6089, 6099},
{6103, 6103}, {6108, 6108}, {6109, 6109}, {6112, 6121},
{6155, 6157}, {6159, 6159}, {6160, 6169}, {6176, 6210},
{6211, 6211}, {6212, 6264}, {6272, 6276}, {6277, 6278},
{6279, 6312}, {6313, 6313}, {6314, 6314}, {6320, 6389},
{6400, 6430}, {6432, 6434}, {6435, 6438}, {6439, 6440},
{6441, 6443}, {6448, 6449}, {6450, 6450}, {6451, 6456},
{6457, 6459}, {6470, 6479}, {6480, 6509}, {6512, 6516},
{6528, 6571}, {6576, 6601}, {6608, 6617}, {6618, 6618},
{6656, 6678}, {6679, 6680}, {6681, 6682}, {6683, 6683},
{6688, 6740}, {6741, 6741}, {6742, 6742}, {6743, 6743},
{6744, 6750}, {6752, 6752}, {6753, 6753}, {6754, 6754},
{6755, 6756}, {6757, 6764}, {6765, 6770}, {6771, 6780},
{6783, 6783}, {6784, 6793}, {6800, 6809}, {6823, 6823},
{6832, 6845}, {6847, 6862}, {6912, 6915}, {6916, 6916},
{6917, 6963}, {6964, 6964}, {6965, 6965}, {6966, 6970},
{6971, 6971}, {6972, 6972}, {6973, 6977}, {6978, 6978},
{6979, 6980}, {6981, 6988}, {6992, 7001}, {7019, 7027},
{7040, 7041}, {7042, 7042}, {7043, 7072}, {7073, 7073},
{7074, 7077}, {7078, 7079}, {7080, 7081}, {7082, 7082},
{7083, 7085}, {7086, 7087}, {7088, 7097}, {7098, 7141},
{7142, 7142}, {7143, 7143}, {7144, 7145}, {7146, 7148},
{7149, 7149}, {7150, 7150}, {7151, 7153}, {7154, 7155},
{7168, 7203}, {7204, 7211}, {7212, 7219}, {7220, 7221},
{7222, 7223}, {7232, 7241}, {7245, 7247}, {7248, 7257},
{7258, 7287}, {7288, 7293}, {7296, 7306}, {7312, 7354},
{7357, 7359}, {7376, 7378}, {7380, 7392}, {7393, 7393},
{7394, 7400}, {7401, 7404}, {7405, 7405}, {7406, 7411},
{7412, 7412}, {7413, 7414}, {7415, 7415}, {7416, 7417},
{7418, 7418}, {7424, 7467}, {7468, 7530}, {7531, 7543},
{7544, 7544}, {7545, 7578}, {7579, 7615}, {7616, 7679},
{7680, 7957}, {7960, 7965}, {7968, 8005}, {8008, 8013},
{8016, 8023}, {8025, 8025}, {8027, 8027}, {8029, 8029},
{8031, 8061}, {8064, 8116}, {8118, 8124}, {8126, 8126},
{8130, 8132}, {8134, 8140}, {8144, 8147}, {8150, 8155},
{8160, 8172}, {8178, 8180}, {8182, 8188}, {8204, 8205},
{8255, 8256}, {8276, 8276}, {8305, 8305}, {8319, 8319},
{8336, 8348}, {8400, 8412}, {8417, 8417}, {8421, 8432},
{8450, 8450}, {8455, 8455}, {8458, 8467}, {8469, 8469},
{8472, 8472}, {8473, 8477}, {8484, 8484}, {8486, 8486},
{8488, 8488}, {8490, 8493}, {8494, 8494}, {8495, 8500},
{8501, 8504}, {8505, 8505}, {8508, 8511}, {8517, 8521},
{8526, 8526}, {8544, 8578}, {8579, 8580}, {8581, 8584},
{11264, 11387}, {11388, 11389}, {11390, 11492}, {11499, 11502},
{11503, 11505}, {11506, 11507}, {11520, 11557}, {11559, 11559},
{11565, 11565}, {11568, 11623}, {11631, 11631}, {11647, 11647},
{11648, 11670}, {11680, 11686}, {11688, 11694}, {11696, 11702},
{11704, 11710}, {11712, 11718}, {11720, 11726}, {11728, 11734},
{11736, 11742}, {11744, 11775}, {12293, 12293}, {12294, 12294},
{12295, 12295}, {12321, 12329}, {12330, 12333}, {12334, 12335},
{12337, 12341}, {12344, 12346}, {12347, 12347}, {12348, 12348},
{12353, 12438}, {12441, 12442}, {12443, 12444}, {12445, 12446},
{12447, 12447}, {12449, 12538}, {12539, 12539}, {12540, 12542},
{12543, 12543}, {12549, 12591}, {12593, 12686}, {12704, 12735},
{12784, 12799}, {13312, 19903}, {19968, 40980}, {40981, 40981},
{40982, 42124}, {42192, 42231}, {42232, 42237}, {42240, 42507},
{42508, 42508}, {42512, 42527}, {42528, 42537}, {42538, 42539},
{42560, 42605}, {42606, 42606}, {42607, 42607}, {42612, 42621},
{42623, 42623}, {42624, 42651}, {42652, 42653}, {42654, 42655},
{42656, 42725}, {42726, 42735}, {42736, 42737}, {42775, 42783},
{42786, 42863}, {42864, 42864}, {42865, 42887}, {42888, 42888},
{42891, 42894}, {42895, 42895}, {42896, 42957}, {42960, 42961},
{42963, 42963}, {42965, 42972}, {42994, 42996}, {42997, 42998},
{42999, 42999}, {43000, 43001}, {43002, 43002}, {43003, 43009},
{43010, 43010}, {43011, 43013}, {43014, 43014}, {43015, 43018},
{43019, 43019}, {43020, 43042}, {43043, 43044}, {43045, 43046},
{43047, 43047}, {43052, 43052}, {43072, 43123}, {43136, 43137},
{43138, 43187}, {43188, 43203}, {43204, 43205}, {43216, 43225},
{43232, 43249}, {43250, 43255}, {43259, 43259}, {43261, 43262},
{43263, 43263}, {43264, 43273}, {43274, 43301}, {43302, 43309},
{43312, 43334}, {43335, 43345}, {43346, 43347}, {43360, 43388},
{43392, 43394}, {43395, 43395}, {43396, 43442}, {43443, 43443},
{43444, 43445}, {43446, 43449}, {43450, 43451}, {43452, 43453},
{43454, 43456}, {43471, 43471}, {43472, 43481}, {43488, 43492},
{43493, 43493}, {43494, 43494}, {43495, 43503}, {43504, 43513},
{43514, 43518}, {43520, 43560}, {43561, 43566}, {43567, 43568},
{43569, 43570}, {43571, 43572}, {43573, 43574}, {43584, 43586},
{43587, 43587}, {43588, 43595}, {43596, 43596}, {43597, 43597},
{43600, 43609}, {43616, 43631}, {43632, 43632}, {43633, 43638},
{43642, 43642}, {43643, 43643}, {43644, 43644}, {43645, 43645},
{43646, 43695}, {43696, 43696}, {43697, 43697}, {43698, 43700},
{43701, 43702}, {43703, 43704}, {43705, 43709}, {43710, 43711},
{43712, 43712}, {43713, 43713}, {43714, 43714}, {43739, 43740},
{43741, 43741}, {43744, 43754}, {43755, 43755}, {43756, 43757},
{43758, 43759}, {43762, 43762}, {43763, 43764}, {43765, 43765},
{43766, 43766}, {43777, 43782}, {43785, 43790}, {43793, 43798},
{43808, 43814}, {43816, 43822}, {43824, 43866}, {43868, 43871},
{43872, 43880}, {43881, 43881}, {43888, 43967}, {43968, 44002},
{44003, 44004}, {44005, 44005}, {44006, 44007}, {44008, 44008},
{44009, 44010}, {44012, 44012}, {44013, 44013}, {44016, 44025},
{44032, 55203}, {55216, 55238}, {55243, 55291}, {63744, 64109},
{64112, 64217}, {64256, 64262}, {64275, 64279}, {64285, 64285},
{64286, 64286}, {64287, 64296}, {64298, 64310}, {64312, 64316},
{64318, 64318}, {64320, 64321}, {64323, 64324}, {64326, 64433},
{64467, 64829}, {64848, 64911}, {64914, 64967}, {65008, 65019},
{65024, 65039}, {65056, 65071}, {65075, 65076}, {65101, 65103},
{65136, 65140}, {65142, 65276}, {65296, 65305}, {65313, 65338},
{65343, 65343}, {65345, 65370}, {65381, 65381}, {65382, 65391},
{65392, 65392}, {65393, 65437}, {65438, 65439}, {65440, 65470},
{65474, 65479}, {65482, 65487}, {65490, 65495}, {65498, 65500},
{65536, 65547}, {65549, 65574}, {65576, 65594}, {65596, 65597},
{65599, 65613}, {65616, 65629}, {65664, 65786}, {65856, 65908},
{66045, 66045}, {66176, 66204}, {66208, 66256}, {66272, 66272},
{66304, 66335}, {66349, 66368}, {66369, 66369}, {66370, 66377},
{66378, 66378}, {66384, 66421}, {66422, 66426}, {66432, 66461},
{66464, 66499}, {66504, 66511}, {66513, 66517}, {66560, 66639},
{66640, 66717}, {66720, 66729}, {66736, 66771}, {66776, 66811},
{66816, 66855}, {66864, 66915}, {66928, 66938}, {66940, 66954},
{66956, 66962}, {66964, 66965}, {66967, 66977}, {66979, 66993},
{66995, 67001}, {67003, 67004}, {67008, 67059}, {67072, 67382},
{67392, 67413}, {67424, 67431}, {67456, 67461}, {67463, 67504},
{67506, 67514}, {67584, 67589}, {67592, 67592}, {67594, 67637},
{67639, 67640}, {67644, 67644}, {67647, 67669}, {67680, 67702},
{67712, 67742}, {67808, 67826}, {67828, 67829}, {67840, 67861},
{67872, 67897}, {67968, 68023}, {68030, 68031}, {68096, 68096},
{68097, 68099}, {68101, 68102}, {68108, 68111}, {68112, 68115},
{68117, 68119}, {68121, 68149}, {68152, 68154}, {68159, 68159},
{68192, 68220}, {68224, 68252}, {68288, 68295}, {68297, 68324},
{68325, 68326}, {68352, 68405}, {68416, 68437}, {68448, 68466},
{68480, 68497}, {68608, 68680}, {68736, 68786}, {68800, 68850},
{68864, 68899}, {68900, 68903}, {68912, 68921}, {68928, 68937},
{68938, 68941}, {68942, 68942}, {68943, 68943}, {68944, 68965},
{68969, 68973}, {68975, 68975}, {68976, 68997}, {69248, 69289},
{69291, 69292}, {69296, 69297}, {69314, 69316}, {69372, 69375},
{69376, 69404}, {69415, 69415}, {69424, 69445}, {69446, 69456},
{69488, 69505}, {69506, 69509}, {69552, 69572}, {69600, 69622},
{69632, 69632}, {69633, 69633}, {69634, 69634}, {69635, 69687},
{69688, 69702}, {69734, 69743}, {69744, 69744}, {69745, 69746},
{69747, 69748}, {69749, 69749}, {69759, 69761}, {69762, 69762},
{69763, 69807}, {69808, 69810}, {69811, 69814}, {69815, 69816},
{69817, 69818}, {69826, 69826}, {69840, 69864}, {69872, 69881},
{69888, 69890}, {69891, 69926}, {69927, 69931}, {69932, 69932},
{69933, 69940}, {69942, 69951}, {69956, 69956}, {69957, 69958},
{69959, 69959}, {69968, 70002}, {70003, 70003}, {70006, 70006},
{70016, 70017}, {70018, 70018}, {70019, 70066}, {70067, 70069},
{70070, 70078}, {70079, 70080}, {70081, 70084}, {70089, 70092},
{70094, 70094}, {70095, 70095}, {70096, 70105}, {70106, 70106},
{70108, 70108}, {70144, 70161}, {70163, 70187}, {70188, 70190},
{70191, 70193}, {70194, 70195}, {70196, 70196}, {70197, 70197},
{70198, 70199}, {70206, 70206}, {70207, 70208}, {70209, 70209},
{70272, 70278}, {70280, 70280}, {70282, 70285}, {70287, 70301},
{70303, 70312}, {70320, 70366}, {70367, 70367}, {70368, 70370},
{70371, 70378}, {70384, 70393}, {70400, 70401}, {70402, 70403},
{70405, 70412}, {70415, 70416}, {70419, 70440}, {70442, 70448},
{70450, 70451}, {70453, 70457}, {70459, 70460}, {70461, 70461},
{70462, 70463}, {70464, 70464}, {70465, 70468}, {70471, 70472},
{70475, 70477}, {70480, 70480}, {70487, 70487}, {70493, 70497},
{70498, 70499}, {70502, 70508}, {70512, 70516}, {70528, 70537},
{70539, 70539}, {70542, 70542}, {70544, 70581}, {70583, 70583},
{70584, 70586}, {70587, 70592}, {70594, 70594}, {70597, 70597},
{70599, 70602}, {70604, 70605}, {70606, 70606}, {70607, 70607},
{70608, 70608}, {70609, 70609}, {70610, 70610}, {70611, 70611},
{70625, 70626}, {70656, 70708}, {70709, 70711}, {70712, 70719},
{70720, 70721}, {70722, 70724}, {70725, 70725}, {70726, 70726},
{70727, 70730}, {70736, 70745}, {70750, 70750}, {70751, 70753},
{70784, 70831}, {70832, 70834}, {70835, 70840}, {70841, 70841},
{70842, 70842}, {70843, 70846}, {70847, 70848}, {70849, 70849},
{70850, 70851}, {70852, 70853}, {70855, 70855}, {70864, 70873},
{71040, 71086}, {71087, 71089}, {71090, 71093}, {71096, 71099},
{71100, 71101}, {71102, 71102}, {71103, 71104}, {71128, 71131},
{71132, 71133}, {71168, 71215}, {71216, 71218}, {71219, 71226},
{71227, 71228}, {71229, 71229}, {71230, 71230}, {71231, 71232},
{71236, 71236}, {71248, 71257}, {71296, 71338}, {71339, 71339},
{71340, 71340}, {71341, 71341}, {71342, 71343}, {71344, 71349},
{71350, 71350}, {71351, 71351}, {71352, 71352}, {71360, 71369},
{71376, 71395}, {71424, 71450}, {71453, 71453}, {71454, 71454},
{71455, 71455}, {71456, 71457}, {71458, 71461}, {71462, 71462},
{71463, 71467}, {71472, 71481}, {71488, 71494}, {71680, 71723},
{71724, 71726}, {71727, 71735}, {71736, 71736}, {71737, 71738},
{71840, 71903}, {71904, 71913}, {71935, 71942}, {71945, 71945},
{71948, 71955}, {71957, 71958}, {71960, 71983}, {71984, 71989},
{71991, 71992}, {71995, 71996}, {71997, 71997}, {71998, 71998},
{71999, 71999}, {72000, 72000}, {72001, 72001}, {72002, 72002},
{72003, 72003}, {72016, 72025}, {72096, 72103}, {72106, 72144},
{72145, 72147}, {72148, 72151}, {72154, 72155}, {72156, 72159},
{72160, 72160}, {72161, 72161}, {72163, 72163}, {72164, 72164},
{72192, 72192}, {72193, 72202}, {72203, 72242}, {72243, 72248},
{72249, 72249}, {72250, 72250}, {72251, 72254}, {72263, 72263},
{72272, 72272}, {72273, 72278}, {72279, 72280}, {72281, 72283},
{72284, 72329}, {72330, 72342}, {72343, 72343}, {72344, 72345},
{72349, 72349}, {72368, 72440}, {72640, 72672}, {72688, 72697},
{72704, 72712}, {72714, 72750}, {72751, 72751}, {72752, 72758},
{72760, 72765}, {72766, 72766}, {72767, 72767}, {72768, 72768},
{72784, 72793}, {72818, 72847}, {72850, 72871}, {72873, 72873},
{72874, 72880}, {72881, 72881}, {72882, 72883}, {72884, 72884},
{72885, 72886}, {72960, 72966}, {72968, 72969}, {72971, 73008},
{73009, 73014}, {73018, 73018}, {73020, 73021}, {73023, 73029},
{73030, 73030}, {73031, 73031}, {73040, 73049}, {73056, 73061},
{73063, 73064}, {73066, 73097}, {73098, 73102}, {73104, 73105},
{73107, 73108}, {73109, 73109}, {73110, 73110}, {73111, 73111},
{73112, 73112}, {73120, 73129}, {73440, 73458}, {73459, 73460},
{73461, 73462}, {73472, 73473}, {73474, 73474}, {73475, 73475},
{73476, 73488}, {73490, 73523}, {73524, 73525}, {73526, 73530},
{73534, 73535}, {73536, 73536}, {73537, 73537}, {73538, 73538},
{73552, 73561}, {73562, 73562}, {73648, 73648}, {73728, 74649},
{74752, 74862}, {74880, 75075}, {77712, 77808}, {77824, 78895},
{78912, 78912}, {78913, 78918}, {78919, 78933}, {78944, 82938},
{82944, 83526}, {90368, 90397}, {90398, 90409}, {90410, 90412},
{90413, 90415}, {90416, 90425}, {92160, 92728}, {92736, 92766},
{92768, 92777}, {92784, 92862}, {92864, 92873}, {92880, 92909},
{92912, 92916}, {92928, 92975}, {92976, 92982}, {92992, 92995},
{93008, 93017}, {93027, 93047}, {93053, 93071}, {93504, 93506},
{93507, 93546}, {93547, 93548}, {93552, 93561}, {93760, 93823},
{93952, 94026}, {94031, 94031}, {94032, 94032}, {94033, 94087},
{94095, 94098}, {94099, 94111}, {94176, 94177}, {94179, 94179},
{94180, 94180}, {94192, 94193}, {94208, 100343}, {100352, 101589},
{101631, 101640}, {110576, 110579}, {110581, 110587}, {110589, 110590},
{110592, 110882}, {110898, 110898}, {110928, 110930}, {110933, 110933},
{110948, 110951}, {110960, 111355}, {113664, 113770}, {113776, 113788},
{113792, 113800}, {113808, 113817}, {113821, 113822}, {118000, 118009},
{118528, 118573}, {118576, 118598}, {119141, 119142}, {119143, 119145},
{119149, 119154}, {119163, 119170}, {119173, 119179}, {119210, 119213},
{119362, 119364}, {119808, 119892}, {119894, 119964}, {119966, 119967},
{119970, 119970}, {119973, 119974}, {119977, 119980}, {119982, 119993},
{119995, 119995}, {119997, 120003}, {120005, 120069}, {120071, 120074},
{120077, 120084}, {120086, 120092}, {120094, 120121}, {120123, 120126},
{120128, 120132}, {120134, 120134}, {120138, 120144}, {120146, 120485},
{120488, 120512}, {120514, 120538}, {120540, 120570}, {120572, 120596},
{120598, 120628}, {120630, 120654}, {120656, 120686}, {120688, 120712},
{120714, 120744}, {120746, 120770}, {120772, 120779}, {120782, 120831},
{121344, 121398}, {121403, 121452}, {121461, 121461}, {121476, 121476},
{121499, 121503}, {121505, 121519}, {122624, 122633}, {122634, 122634},
{122635, 122654}, {122661, 122666}, {122880, 122886}, {122888, 122904},
{122907, 122913}, {122915, 122916}, {122918, 122922}, {122928, 122989},
{123023, 123023}, {123136, 123180}, {123184, 123190}, {123191, 123197},
{123200, 123209}, {123214, 123214}, {123536, 123565}, {123566, 123566},
{123584, 123627}, {123628, 123631}, {123632, 123641}, {124112, 124138},
{124139, 124139}, {124140, 124143}, {124144, 124153}, {124368, 124397},
{124398, 124399}, {124400, 124400}, {124401, 124410}, {124896, 124902},
{124904, 124907}, {124909, 124910}, {124912, 124926}, {124928, 125124},
{125136, 125142}, {125184, 125251}, {125252, 125258}, {125259, 125259},
{125264, 125273}, {126464, 126467}, {126469, 126495}, {126497, 126498},
{126500, 126500}, {126503, 126503}, {126505, 126514}, {126516, 126519},
{126521, 126521}, {126523, 126523}, {126530, 126530}, {126535, 126535},
{126537, 126537}, {126539, 126539}, {126541, 126543}, {126545, 126546},
{126548, 126548}, {126551, 126551}, {126553, 126553}, {126555, 126555},
{126557, 126557}, {126559, 126559}, {126561, 126562}, {126564, 126564},
{126567, 126570}, {126572, 126578}, {126580, 126583}, {126585, 126588},
{126590, 126590}, {126592, 126601}, {126603, 126619}, {126625, 126627},
{126629, 126633}, {126635, 126651}, {130032, 130041}, {131072, 173791},
{173824, 177977}, {177984, 178205}, {178208, 183969}, {183984, 191456},
{191472, 192093}, {194560, 195101}, {196608, 201546}, {201552, 205743},
{917760, 917999}
};
const uint32_t id_start[763][2] =
{
{65, 90}, {97, 122}, {170, 170}, {181, 181},
{186, 186}, {192, 214}, {216, 246}, {248, 442},
{443, 443}, {444, 447}, {448, 451}, {452, 659},
{660, 660}, {661, 687}, {688, 705}, {710, 721},
{736, 740}, {748, 748}, {750, 750}, {880, 883},
{884, 884}, {886, 887}, {890, 890}, {891, 893},
{895, 895}, {902, 902}, {904, 906}, {908, 908},
{910, 929}, {931, 1013}, {1015, 1153}, {1162, 1327},
{1329, 1366}, {1369, 1369}, {1376, 1416}, {1488, 1514},
{1519, 1522}, {1568, 1599}, {1600, 1600}, {1601, 1610},
{1646, 1647}, {1649, 1747}, {1749, 1749}, {1765, 1766},
{1774, 1775}, {1786, 1788}, {1791, 1791}, {1808, 1808},
{1810, 1839}, {1869, 1957}, {1969, 1969}, {1994, 2026},
{2036, 2037}, {2042, 2042}, {2048, 2069}, {2074, 2074},
{2084, 2084}, {2088, 2088}, {2112, 2136}, {2144, 2154},
{2160, 2183}, {2185, 2190}, {2208, 2248}, {2249, 2249},
{2308, 2361}, {2365, 2365}, {2384, 2384}, {2392, 2401},
{2417, 2417}, {2418, 2432}, {2437, 2444}, {2447, 2448},
{2451, 2472}, {2474, 2480}, {2482, 2482}, {2486, 2489},
{2493, 2493}, {2510, 2510}, {2524, 2525}, {2527, 2529},
{2544, 2545}, {2556, 2556}, {2565, 2570}, {2575, 2576},
{2579, 2600}, {2602, 2608}, {2610, 2611}, {2613, 2614},
{2616, 2617}, {2649, 2652}, {2654, 2654}, {2674, 2676},
{2693, 2701}, {2703, 2705}, {2707, 2728}, {2730, 2736},
{2738, 2739}, {2741, 2745}, {2749, 2749}, {2768, 2768},
{2784, 2785}, {2809, 2809}, {2821, 2828}, {2831, 2832},
{2835, 2856}, {2858, 2864}, {2866, 2867}, {2869, 2873},
{2877, 2877}, {2908, 2909}, {2911, 2913}, {2929, 2929},
{2947, 2947}, {2949, 2954}, {2958, 2960}, {2962, 2965},
{2969, 2970}, {2972, 2972}, {2974, 2975}, {2979, 2980},
{2984, 2986}, {2990, 3001}, {3024, 3024}, {3077, 3084},
{3086, 3088}, {3090, 3112}, {3114, 3129}, {3133, 3133},
{3160, 3162}, {3165, 3165}, {3168, 3169}, {3200, 3200},
{3205, 3212}, {3214, 3216}, {3218, 3240}, {3242, 3251},
{3253, 3257}, {3261, 3261}, {3293, 3294}, {3296, 3297},
{3313, 3314}, {3332, 3340}, {3342, 3344}, {3346, 3386},
{3389, 3389}, {3406, 3406}, {3412, 3414}, {3423, 3425},
{3450, 3455}, {3461, 3478}, {3482, 3505}, {3507, 3515},
{3517, 3517}, {3520, 3526}, {3585, 3632}, {3634, 3635},
{3648, 3653}, {3654, 3654}, {3713, 3714}, {3716, 3716},
{3718, 3722}, {3724, 3747}, {3749, 3749}, {3751, 3760},
{3762, 3763}, {3773, 3773}, {3776, 3780}, {3782, 3782},
{3804, 3807}, {3840, 3840}, {3904, 3911}, {3913, 3948},
{3976, 3980}, {4096, 4138}, {4159, 4159}, {4176, 4181},
{4186, 4189}, {4193, 4193}, {4197, 4198}, {4206, 4208},
{4213, 4225}, {4238, 4238}, {4256, 4293}, {4295, 4295},
{4301, 4301}, {4304, 4346}, {4348, 4348}, {4349, 4351},
{4352, 4680}, {4682, 4685}, {4688, 4694}, {4696, 4696},
{4698, 4701}, {4704, 4744}, {4746, 4749}, {4752, 4784},
{4786, 4789}, {4792, 4798}, {4800, 4800}, {4802, 4805},
{4808, 4822}, {4824, 4880}, {4882, 4885}, {4888, 4954},
{4992, 5007}, {5024, 5109}, {5112, 5117}, {5121, 5740},
{5743, 5759}, {5761, 5786}, {5792, 5866}, {5870, 5872},
{5873, 5880}, {5888, 5905}, {5919, 5937}, {5952, 5969},
{5984, 5996}, {5998, 6000}, {6016, 6067}, {6103, 6103},
{6108, 6108}, {6176, 6210}, {6211, 6211}, {6212, 6264},
{6272, 6276}, {6277, 6278}, {6279, 6312}, {6314, 6314},
{6320, 6389}, {6400, 6430}, {6480, 6509}, {6512, 6516},
{6528, 6571}, {6576, 6601}, {6656, 6678}, {6688, 6740},
{6823, 6823}, {6917, 6963}, {6981, 6988}, {7043, 7072},
{7086, 7087}, {7098, 7141}, {7168, 7203}, {7245, 7247},
{7258, 7287}, {7288, 7293}, {7296, 7306}, {7312, 7354},
{7357, 7359}, {7401, 7404}, {7406, 7411}, {7413, 7414},
{7418, 7418}, {7424, 7467}, {7468, 7530}, {7531, 7543},
{7544, 7544}, {7545, 7578}, {7579, 7615}, {7680, 7957},
{7960, 7965}, {7968, 8005}, {8008, 8013}, {8016, 8023},
{8025, 8025}, {8027, 8027}, {8029, 8029}, {8031, 8061},
{8064, 8116}, {8118, 8124}, {8126, 8126}, {8130, 8132},
{8134, 8140}, {8144, 8147}, {8150, 8155}, {8160, 8172},
{8178, 8180}, {8182, 8188}, {8305, 8305}, {8319, 8319},
{8336, 8348}, {8450, 8450}, {8455, 8455}, {8458, 8467},
{8469, 8469}, {8472, 8472}, {8473, 8477}, {8484, 8484},
{8486, 8486}, {8488, 8488}, {8490, 8493}, {8494, 8494},
{8495, 8500}, {8501, 8504}, {8505, 8505}, {8508, 8511},
{8517, 8521}, {8526, 8526}, {8544, 8578}, {8579, 8580},
{8581, 8584}, {11264, 11387}, {11388, 11389}, {11390, 11492},
{11499, 11502}, {11506, 11507}, {11520, 11557}, {11559, 11559},
{11565, 11565}, {11568, 11623}, {11631, 11631}, {11648, 11670},
{11680, 11686}, {11688, 11694}, {11696, 11702}, {11704, 11710},
{11712, 11718}, {11720, 11726}, {11728, 11734}, {11736, 11742},
{12293, 12293}, {12294, 12294}, {12295, 12295}, {12321, 12329},
{12337, 12341}, {12344, 12346}, {12347, 12347}, {12348, 12348},
{12353, 12438}, {12443, 12444}, {12445, 12446}, {12447, 12447},
{12449, 12538}, {12540, 12542}, {12543, 12543}, {12549, 12591},
{12593, 12686}, {12704, 12735}, {12784, 12799}, {13312, 19903},
{19968, 40980}, {40981, 40981}, {40982, 42124}, {42192, 42231},
{42232, 42237}, {42240, 42507}, {42508, 42508}, {42512, 42527},
{42538, 42539}, {42560, 42605}, {42606, 42606}, {42623, 42623},
{42624, 42651}, {42652, 42653}, {42656, 42725}, {42726, 42735},
{42775, 42783}, {42786, 42863}, {42864, 42864}, {42865, 42887},
{42888, 42888}, {42891, 42894}, {42895, 42895}, {42896, 42957},
{42960, 42961}, {42963, 42963}, {42965, 42972}, {42994, 42996},
{42997, 42998}, {42999, 42999}, {43000, 43001}, {43002, 43002},
{43003, 43009}, {43011, 43013}, {43015, 43018}, {43020, 43042},
{43072, 43123}, {43138, 43187}, {43250, 43255}, {43259, 43259},
{43261, 43262}, {43274, 43301}, {43312, 43334}, {43360, 43388},
{43396, 43442}, {43471, 43471}, {43488, 43492}, {43494, 43494},
{43495, 43503}, {43514, 43518}, {43520, 43560}, {43584, 43586},
{43588, 43595}, {43616, 43631}, {43632, 43632}, {43633, 43638},
{43642, 43642}, {43646, 43695}, {43697, 43697}, {43701, 43702},
{43705, 43709}, {43712, 43712}, {43714, 43714}, {43739, 43740},
{43741, 43741}, {43744, 43754}, {43762, 43762}, {43763, 43764},
{43777, 43782}, {43785, 43790}, {43793, 43798}, {43808, 43814},
{43816, 43822}, {43824, 43866}, {43868, 43871}, {43872, 43880},
{43881, 43881}, {43888, 43967}, {43968, 44002}, {44032, 55203},
{55216, 55238}, {55243, 55291}, {63744, 64109}, {64112, 64217},
{64256, 64262}, {64275, 64279}, {64285, 64285}, {64287, 64296},
{64298, 64310}, {64312, 64316}, {64318, 64318}, {64320, 64321},
{64323, 64324}, {64326, 64433}, {64467, 64829}, {64848, 64911},
{64914, 64967}, {65008, 65019}, {65136, 65140}, {65142, 65276},
{65313, 65338}, {65345, 65370}, {65382, 65391}, {65392, 65392},
{65393, 65437}, {65438, 65439}, {65440, 65470}, {65474, 65479},
{65482, 65487}, {65490, 65495}, {65498, 65500}, {65536, 65547},
{65549, 65574}, {65576, 65594}, {65596, 65597}, {65599, 65613},
{65616, 65629}, {65664, 65786}, {65856, 65908}, {66176, 66204},
{66208, 66256}, {66304, 66335}, {66349, 66368}, {66369, 66369},
{66370, 66377}, {66378, 66378}, {66384, 66421}, {66432, 66461},
{66464, 66499}, {66504, 66511}, {66513, 66517}, {66560, 66639},
{66640, 66717}, {66736, 66771}, {66776, 66811}, {66816, 66855},
{66864, 66915}, {66928, 66938}, {66940, 66954}, {66956, 66962},
{66964, 66965}, {66967, 66977}, {66979, 66993}, {66995, 67001},
{67003, 67004}, {67008, 67059}, {67072, 67382}, {67392, 67413},
{67424, 67431}, {67456, 67461}, {67463, 67504}, {67506, 67514},
{67584, 67589}, {67592, 67592}, {67594, 67637}, {67639, 67640},
{67644, 67644}, {67647, 67669}, {67680, 67702}, {67712, 67742},
{67808, 67826}, {67828, 67829}, {67840, 67861}, {67872, 67897},
{67968, 68023}, {68030, 68031}, {68096, 68096}, {68112, 68115},
{68117, 68119}, {68121, 68149}, {68192, 68220}, {68224, 68252},
{68288, 68295}, {68297, 68324}, {68352, 68405}, {68416, 68437},
{68448, 68466}, {68480, 68497}, {68608, 68680}, {68736, 68786},
{68800, 68850}, {68864, 68899}, {68938, 68941}, {68942, 68942},
{68943, 68943}, {68944, 68965}, {68975, 68975}, {68976, 68997},
{69248, 69289}, {69296, 69297}, {69314, 69316}, {69376, 69404},
{69415, 69415}, {69424, 69445}, {69488, 69505}, {69552, 69572},
{69600, 69622}, {69635, 69687}, {69745, 69746}, {69749, 69749},
{69763, 69807}, {69840, 69864}, {69891, 69926}, {69956, 69956},
{69959, 69959}, {69968, 70002}, {70006, 70006}, {70019, 70066},
{70081, 70084}, {70106, 70106}, {70108, 70108}, {70144, 70161},
{70163, 70187}, {70207, 70208}, {70272, 70278}, {70280, 70280},
{70282, 70285}, {70287, 70301}, {70303, 70312}, {70320, 70366},
{70405, 70412}, {70415, 70416}, {70419, 70440}, {70442, 70448},
{70450, 70451}, {70453, 70457}, {70461, 70461}, {70480, 70480},
{70493, 70497}, {70528, 70537}, {70539, 70539}, {70542, 70542},
{70544, 70581}, {70583, 70583}, {70609, 70609}, {70611, 70611},
{70656, 70708}, {70727, 70730}, {70751, 70753}, {70784, 70831},
{70852, 70853}, {70855, 70855}, {71040, 71086}, {71128, 71131},
{71168, 71215}, {71236, 71236}, {71296, 71338}, {71352, 71352},
{71424, 71450}, {71488, 71494}, {71680, 71723}, {71840, 71903},
{71935, 71942}, {71945, 71945}, {71948, 71955}, {71957, 71958},
{71960, 71983}, {71999, 71999}, {72001, 72001}, {72096, 72103},
{72106, 72144}, {72161, 72161}, {72163, 72163}, {72192, 72192},
{72203, 72242}, {72250, 72250}, {72272, 72272}, {72284, 72329},
{72349, 72349}, {72368, 72440}, {72640, 72672}, {72704, 72712},
{72714, 72750}, {72768, 72768}, {72818, 72847}, {72960, 72966},
{72968, 72969}, {72971, 73008}, {73030, 73030}, {73056, 73061},
{73063, 73064}, {73066, 73097}, {73112, 73112}, {73440, 73458},
{73474, 73474}, {73476, 73488}, {73490, 73523}, {73648, 73648},
{73728, 74649}, {74752, 74862}, {74880, 75075}, {77712, 77808},
{77824, 78895}, {78913, 78918}, {78944, 82938}, {82944, 83526},
{90368, 90397}, {92160, 92728}, {92736, 92766}, {92784, 92862},
{92880, 92909}, {92928, 92975}, {92992, 92995}, {93027, 93047},
{93053, 93071}, {93504, 93506}, {93507, 93546}, {93547, 93548},
{93760, 93823}, {93952, 94026}, {94032, 94032}, {94099, 94111},
{94176, 94177}, {94179, 94179}, {94208, 100343}, {100352, 101589},
{101631, 101640}, {110576, 110579}, {110581, 110587}, {110589, 110590},
{110592, 110882}, {110898, 110898}, {110928, 110930}, {110933, 110933},
{110948, 110951}, {110960, 111355}, {113664, 113770}, {113776, 113788},
{113792, 113800}, {113808, 113817}, {119808, 119892}, {119894, 119964},
{119966, 119967}, {119970, 119970}, {119973, 119974}, {119977, 119980},
{119982, 119993}, {119995, 119995}, {119997, 120003}, {120005, 120069},
{120071, 120074}, {120077, 120084}, {120086, 120092}, {120094, 120121},
{120123, 120126}, {120128, 120132}, {120134, 120134}, {120138, 120144},
{120146, 120485}, {120488, 120512}, {120514, 120538}, {120540, 120570},
{120572, 120596}, {120598, 120628}, {120630, 120654}, {120656, 120686},
{120688, 120712}, {120714, 120744}, {120746, 120770}, {120772, 120779},
{122624, 122633}, {122634, 122634}, {122635, 122654}, {122661, 122666},
{122928, 122989}, {123136, 123180}, {123191, 123197}, {123214, 123214},
{123536, 123565}, {123584, 123627}, {124112, 124138}, {124139, 124139},
{124368, 124397}, {124400, 124400}, {124896, 124902}, {124904, 124907},
{124909, 124910}, {124912, 124926}, {124928, 125124}, {125184, 125251},
{125259, 125259}, {126464, 126467}, {126469, 126495}, {126497, 126498},
{126500, 126500}, {126503, 126503}, {126505, 126514}, {126516, 126519},
{126521, 126521}, {126523, 126523}, {126530, 126530}, {126535, 126535},
{126537, 126537}, {126539, 126539}, {126541, 126543}, {126545, 126546},
{126548, 126548}, {126551, 126551}, {126553, 126553}, {126555, 126555},
{126557, 126557}, {126559, 126559}, {126561, 126562}, {126564, 126564},
{126567, 126570}, {126572, 126578}, {126580, 126583}, {126585, 126588},
{126590, 126590}, {126592, 126601}, {126603, 126619}, {126625, 126627},
{126629, 126633}, {126635, 126651}, {131072, 173791}, {173824, 177977},
{177984, 178205}, {178208, 183969}, {183984, 191456}, {191472, 192093},
{194560, 195101}, {196608, 201546}, {201552, 205743}
};
} // namespace ada::idna
#endif // ADA_IDNA_IDENTIFIER_TABLES_H
/* end file src/id_tables.cpp */
namespace ada::idna {
constexpr bool is_ascii_letter(char32_t c) noexcept {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
constexpr bool is_ascii_letter_or_digit(char32_t c) noexcept {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9');
}
bool valid_name_code_point(char32_t code_point, bool first) {
// https://tc39.es/ecma262/#prod-IdentifierStart
// Fast paths:
if (first &&
(code_point == '$' || code_point == '_' || is_ascii_letter(code_point))) {
return true;
}
if (!first && (code_point == '$' || is_ascii_letter_or_digit(code_point))) {
return true;
}
// Slow path...
if (code_point == 0xffffffff) {
return false; // minimal error handling
}
if (first) {
auto iter = std::lower_bound(
std::begin(ada::idna::id_start), std::end(ada::idna::id_start),
code_point,
[](const uint32_t* range, uint32_t cp) { return range[1] < cp; });
return iter != std::end(id_start) && code_point >= (*iter)[0];
} else {
auto iter = std::lower_bound(
std::begin(id_continue), std::end(id_continue), code_point,
[](const uint32_t* range, uint32_t cp) { return range[1] < cp; });
return iter != std::end(id_start) && code_point >= (*iter)[0];
}
}
} // namespace ada::idna
/* end file src/identifier.cpp */
/* end file src/idna.cpp */
/* end file src/ada_idna.cpp */
ADA_POP_DISABLE_WARNINGS
#include <algorithm>
#if ADA_NEON
#include <arm_neon.h>
#elif ADA_SSE2
#include <emmintrin.h>
#endif
namespace ada::unicode {
constexpr bool is_tabs_or_newline(char c) noexcept {
return c == '\r' || c == '\n' || c == '\t';
}
constexpr uint64_t broadcast(uint8_t v) noexcept {
return 0x101010101010101ull * v;
}
constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
uint64_t broadcast_80 = broadcast(0x80);
uint64_t broadcast_Ap = broadcast(128 - 'A');
uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
uint64_t non_ascii = 0;
size_t i = 0;
for (; i + 7 < length; i += 8) {
uint64_t word{};
memcpy(&word, input + i, sizeof(word));
non_ascii |= (word & broadcast_80);
word ^=
(((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
memcpy(input + i, &word, sizeof(word));
}
if (i < length) {
uint64_t word{};
memcpy(&word, input + i, length - i);
non_ascii |= (word & broadcast_80);
word ^=
(((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
memcpy(input + i, &word, length - i);
}
return non_ascii == 0;
}
#if ADA_NEON
ada_really_inline bool has_tabs_or_newline(
std::string_view user_input) noexcept {
// first check for short strings in which case we do it naively.
if (user_input.size() < 16) { // slow path
return std::any_of(user_input.begin(), user_input.end(),
is_tabs_or_newline);
}
// fast path for long strings (expected to be common)
size_t i = 0;
/**
* The fastest way to check for `\t` (==9), '\n'(== 10) and `\r` (==13) relies
* on table lookup instruction. We notice that these are all unique numbers
* between 0..15. Let's prepare a special register, where we put '\t' in the
* 9th position, '\n' - 10th and '\r' - 13th. Then we shuffle this register by
* input register. If the input had `\t` in position X then this shuffled
* register will also have '\t' in that position. Comparing input with this
* shuffled register will mark us all interesting characters in the input.
*
* credit for algorithmic idea: @aqrit, credit for description:
* @DenisYaroshevskiy
*/
static uint8_t rnt_array[16] = {1, 0, 0, 0, 0, 0, 0, 0,
0, 9, 10, 0, 0, 13, 0, 0};
const uint8x16_t rnt = vld1q_u8(rnt_array);
// m['0xd', '0xa', '0x9']
uint8x16_t running{0};
for (; i + 15 < user_input.size(); i += 16) {
uint8x16_t word = vld1q_u8((const uint8_t*)user_input.data() + i);
running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word));
}
if (i < user_input.size()) {
uint8x16_t word =
vld1q_u8((const uint8_t*)user_input.data() + user_input.length() - 16);
running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word));
}
return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0;
}
#elif ADA_SSE2
ada_really_inline bool has_tabs_or_newline(
std::string_view user_input) noexcept {
// first check for short strings in which case we do it naively.
if (user_input.size() < 16) { // slow path
return std::any_of(user_input.begin(), user_input.end(),
is_tabs_or_newline);
}
// fast path for long strings (expected to be common)
size_t i = 0;
const __m128i mask1 = _mm_set1_epi8('\r');
const __m128i mask2 = _mm_set1_epi8('\n');
const __m128i mask3 = _mm_set1_epi8('\t');
// If we supported SSSE3, we could use the algorithm that we use for NEON.
__m128i running{0};
for (; i + 15 < user_input.size(); i += 16) {
__m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
running = _mm_or_si128(
_mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
_mm_cmpeq_epi8(word, mask2))),
_mm_cmpeq_epi8(word, mask3));
}
if (i < user_input.size()) {
__m128i word = _mm_loadu_si128(
(const __m128i*)(user_input.data() + user_input.length() - 16));
running = _mm_or_si128(
_mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
_mm_cmpeq_epi8(word, mask2))),
_mm_cmpeq_epi8(word, mask3));
}
return _mm_movemask_epi8(running) != 0;
}
#else
ada_really_inline bool has_tabs_or_newline(
std::string_view user_input) noexcept {
auto has_zero_byte = [](uint64_t v) {
return ((v - 0x0101010101010101) & ~(v) & 0x8080808080808080);
};
size_t i = 0;
uint64_t mask1 = broadcast('\r');
uint64_t mask2 = broadcast('\n');
uint64_t mask3 = broadcast('\t');
uint64_t running{0};
for (; i + 7 < user_input.size(); i += 8) {
uint64_t word{};
memcpy(&word, user_input.data() + i, sizeof(word));
uint64_t xor1 = word ^ mask1;
uint64_t xor2 = word ^ mask2;
uint64_t xor3 = word ^ mask3;
running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
}
if (i < user_input.size()) {
uint64_t word{};
memcpy(&word, user_input.data() + i, user_input.size() - i);
uint64_t xor1 = word ^ mask1;
uint64_t xor2 = word ^ mask2;
uint64_t xor3 = word ^ mask3;
running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
}
return running;
}
#endif
// A forbidden host code point is U+0000 NULL, U+0009 TAB, U+000A LF, U+000D CR,
// U+0020 SPACE, U+0023 (#), U+002F (/), U+003A (:), U+003C (<), U+003E (>),
// U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), or
// U+007C (|).
constexpr static std::array<uint8_t, 256> is_forbidden_host_code_point_table =
[]() consteval {
std::array<uint8_t, 256> result{};
for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<',
'>', '?', '@', '[', '\\', ']', '^', '|'}) {
result[c] = true;
}
return result;
}();
ada_really_inline constexpr bool is_forbidden_host_code_point(
const char c) noexcept {
return is_forbidden_host_code_point_table[uint8_t(c)];
}
constexpr static std::array<uint8_t, 256> is_forbidden_domain_code_point_table =
[]() consteval {
std::array<uint8_t, 256> result{};
for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<',
'>', '?', '@', '[', '\\', ']', '^', '|', '%'}) {
result[c] = true;
}
for (uint8_t c = 0; c <= 32; c++) {
result[c] = true;
}
for (size_t c = 127; c < 255; c++) {
result[c] = true;
}
return result;
}();
static_assert(sizeof(is_forbidden_domain_code_point_table) == 256);
ada_really_inline constexpr bool is_forbidden_domain_code_point(
const char c) noexcept {
return is_forbidden_domain_code_point_table[uint8_t(c)];
}
ada_really_inline constexpr bool contains_forbidden_domain_code_point(
const char* input, size_t length) noexcept {
size_t i = 0;
uint8_t accumulator{};
for (; i + 4 <= length; i += 4) {
accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
}
for (; i < length; i++) {
accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
}
return accumulator;
}
constexpr static std::array<uint8_t, 256>
is_forbidden_domain_code_point_table_or_upper = []() consteval {
std::array<uint8_t, 256> result{};
for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<',
'>', '?', '@', '[', '\\', ']', '^', '|', '%'}) {
result[c] = 1;
}
for (uint8_t c = 'A'; c <= 'Z'; c++) {
result[c] = 2;
}
for (uint8_t c = 0; c <= 32; c++) {
result[c] = 1;
}
for (size_t c = 127; c < 255; c++) {
result[c] = 1;
}
return result;
}();
ada_really_inline constexpr uint8_t
contains_forbidden_domain_code_point_or_upper(const char* input,
size_t length) noexcept {
size_t i = 0;
uint8_t accumulator{};
for (; i + 4 <= length; i += 4) {
accumulator |=
is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
accumulator |=
is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
accumulator |=
is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
accumulator |=
is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
}
for (; i < length; i++) {
accumulator |=
is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
}
return accumulator;
}
// std::isalnum(c) || c == '+' || c == '-' || c == '.') is true for
constexpr static std::array<bool, 256> is_alnum_plus_table = []() consteval {
std::array<bool, 256> result{};
for (size_t c = 0; c < 256; c++) {
result[c] = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || c == '+' || c == '-' || c == '.';
}
return result;
}();
ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
return is_alnum_plus_table[uint8_t(c)];
// A table is almost surely much faster than the
// following under most compilers: return
// return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
}
ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f');
}
ada_really_inline constexpr bool is_ascii_digit(const char c) noexcept {
// An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),
// inclusive.
return (c >= '0' && c <= '9');
}
ada_really_inline constexpr bool is_ascii(const char32_t c) noexcept {
// If code point is between U+0000 and U+007F inclusive, then return true.
return c <= 0x7F;
}
ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
return (unsigned char)c <= ' ';
}
ada_really_inline constexpr bool is_ascii_tab_or_newline(
const char c) noexcept {
return c == '\t' || c == '\n' || c == '\r';
}
constexpr std::string_view table_is_double_dot_path_segment[] = {
"..", "%2e.", ".%2e", "%2e%2e"};
ada_really_inline constexpr bool is_double_dot_path_segment(
std::string_view input) noexcept {
// This will catch most cases:
// The length must be 2,4 or 6.
// We divide by two and require
// that the result be between 1 and 3 inclusively.
uint64_t half_length = uint64_t(input.size()) / 2;
if (half_length - 1 > 2) {
return false;
}
// We have a string of length 2, 4 or 6.
// We now check the first character:
if ((input[0] != '.') && (input[0] != '%')) {
return false;
}
// We are unlikely the get beyond this point.
int hash_value = (input.size() + (unsigned)(input[0])) & 3;
const std::string_view target = table_is_double_dot_path_segment[hash_value];
if (target.size() != input.size()) {
return false;
}
// We almost never get here.
// Optimizing the rest is relatively unimportant.
auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
uint16_t A, B;
memcpy(&A, a.data(), sizeof(A));
memcpy(&B, b.data(), sizeof(B));
return A == B;
};
if (!prefix_equal_unsafe(input, target)) {
return false;
}
for (size_t i = 2; i < input.size(); i++) {
char c = input[i];
if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
return false;
}
}
return true;
// The above code might be a bit better than the code below. Compilers
// are not stupid and may use the fact that these strings have length 2,4 and
// 6 and other tricks.
// return input == ".." ||
// input == ".%2e" || input == ".%2E" ||
// input == "%2e." || input == "%2E." ||
// input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
// "%2e%2E";
}
ada_really_inline constexpr bool is_single_dot_path_segment(
std::string_view input) noexcept {
return input == "." || input == "%2e" || input == "%2E";
}
ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
constexpr static char hex_to_binary_table[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11,
12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15};
unsigned constexpr convert_hex_to_binary(const char c) noexcept {
return hex_to_binary_table[c - '0'];
}
std::string percent_decode(const std::string_view input, size_t first_percent) {
// next line is for safety only, we expect users to avoid calling
// percent_decode when first_percent is outside the range.
if (first_percent == std::string_view::npos) {
return std::string(input);
}
std::string dest;
dest.reserve(input.length());
dest.append(input.substr(0, first_percent));
const char* pointer = input.data() + first_percent;
const char* end = input.data() + input.size();
// Optimization opportunity: if the following code gets
// called often, it can be optimized quite a bit.
while (pointer < end) {
const char ch = pointer[0];
size_t remaining = end - pointer - 1;
if (ch != '%' || remaining < 2 ||
( // ch == '%' && // It is unnecessary to check that ch == '%'.
(!is_ascii_hex_digit(pointer[1]) ||
!is_ascii_hex_digit(pointer[2])))) {
dest += ch;
pointer++;
} else {
unsigned a = convert_hex_to_binary(pointer[1]);
unsigned b = convert_hex_to_binary(pointer[2]);
char c = static_cast<char>(a * 16 + b);
dest += c;
pointer += 3;
}
}
return dest;
}
std::string percent_encode(const std::string_view input,
const uint8_t character_set[]) {
auto pointer = std::ranges::find_if(input, [character_set](const char c) {
return character_sets::bit_at(character_set, c);
});
// Optimization: Don't iterate if percent encode is not required
if (pointer == input.end()) {
return std::string(input);
}
std::string result;
result.reserve(input.length()); // in the worst case, percent encoding might
// produce 3 characters.
result.append(input.substr(0, std::distance(input.begin(), pointer)));
for (; pointer != input.end(); pointer++) {
if (character_sets::bit_at(character_set, *pointer)) {
result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
} else {
result += *pointer;
}
}
return result;
}
template <bool append>
bool percent_encode(const std::string_view input, const uint8_t character_set[],
std::string& out) {
ada_log("percent_encode ", input, " to output string while ",
append ? "appending" : "overwriting");
auto pointer =
std::find_if(input.begin(), input.end(), [character_set](const char c) {
return character_sets::bit_at(character_set, c);
});
ada_log("percent_encode done checking, moved to ",
std::distance(input.begin(), pointer));
// Optimization: Don't iterate if percent encode is not required
if (pointer == input.end()) {
ada_log("percent_encode encoding not needed.");
return false;
}
if constexpr (!append) {
out.clear();
}
ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
" bytes");
out.append(input.data(), std::distance(input.begin(), pointer));
ada_log("percent_encode processing ", std::distance(pointer, input.end()),
" bytes");
for (; pointer != input.end(); pointer++) {
if (character_sets::bit_at(character_set, *pointer)) {
out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
} else {
out += *pointer;
}
}
return true;
}
bool to_ascii(std::optional<std::string>& out, const std::string_view plain,
size_t first_percent) {
std::string percent_decoded_buffer;
std::string_view input = plain;
if (first_percent != std::string_view::npos) {
percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
input = percent_decoded_buffer;
}
// input is a non-empty UTF-8 string, must be percent decoded
std::string idna_ascii = ada::idna::to_ascii(input);
if (idna_ascii.empty() || contains_forbidden_domain_code_point(
idna_ascii.data(), idna_ascii.size())) {
return false;
}
out = std::move(idna_ascii);
return true;
}
std::string percent_encode(const std::string_view input,
const uint8_t character_set[], size_t index) {
std::string out;
out.append(input.data(), index);
auto pointer = input.begin() + index;
for (; pointer != input.end(); pointer++) {
if (character_sets::bit_at(character_set, *pointer)) {
out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
} else {
out += *pointer;
}
}
return out;
}
} // namespace ada::unicode
/* end file src/unicode.cpp */
/* begin file src/serializers.cpp */
#include <array>
#include <charconv>
#include <string>
namespace ada::serializers {
void find_longest_sequence_of_ipv6_pieces(
const std::array<uint16_t, 8>& address, size_t& compress,
size_t& compress_length) noexcept {
for (size_t i = 0; i < 8; i++) {
if (address[i] == 0) {
size_t next = i + 1;
while (next != 8 && address[next] == 0) ++next;
const size_t count = next - i;
if (compress_length < count) {
compress_length = count;
compress = i;
if (next == 8) break;
i = next;
}
}
}
}
std::string ipv6(const std::array<uint16_t, 8>& address) noexcept {
size_t compress_length = 0; // The length of a long sequence of zeros.
size_t compress = 0; // The start of a long sequence of zeros.
find_longest_sequence_of_ipv6_pieces(address, compress, compress_length);
if (compress_length <= 1) {
// Optimization opportunity: Find a faster way then snprintf for imploding
// and return here.
compress = compress_length = 8;
}
std::string output(4 * 8 + 7 + 2, '\0');
size_t piece_index = 0;
char* point = output.data();
char* point_end = output.data() + output.size();
*point++ = '[';
while (true) {
if (piece_index == compress) {
*point++ = ':';
// If we skip a value initially, we need to write '::', otherwise
// a single ':' will do since it follows a previous ':'.
if (piece_index == 0) {
*point++ = ':';
}
piece_index += compress_length;
if (piece_index == 8) {
break;
}
}
point = std::to_chars(point, point_end, address[piece_index], 16).ptr;
piece_index++;
if (piece_index == 8) {
break;
}
*point++ = ':';
}
*point++ = ']';
output.resize(point - output.data());
return output;
}
std::string ipv4(const uint64_t address) noexcept {
std::string output(15, '\0');
char* point = output.data();
char* point_end = output.data() + output.size();
point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr;
for (int i = 2; i >= 0; i--) {
*point++ = '.';
point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr;
}
output.resize(point - output.data());
return output;
}
} // namespace ada::serializers
/* end file src/serializers.cpp */
/* begin file src/implementation.cpp */
#include <string_view>
namespace ada {
template <class result_type>
ada_warn_unused tl::expected<result_type, errors> parse(
std::string_view input, const result_type* base_url) {
result_type u =
ada::parser::parse_url_impl<result_type, true>(input, base_url);
if (!u.is_valid) {
return tl::unexpected(errors::type_error);
}
return u;
}
template ada::result<url> parse<url>(std::string_view input,
const url* base_url = nullptr);
template ada::result<url_aggregator> parse<url_aggregator>(
std::string_view input, const url_aggregator* base_url = nullptr);
std::string href_from_file(std::string_view input) {
// This is going to be much faster than constructing a URL.
std::string tmp_buffer;
std::string_view internal_input;
if (unicode::has_tabs_or_newline(input)) {
tmp_buffer = input;
helpers::remove_ascii_tab_or_newline(tmp_buffer);
internal_input = tmp_buffer;
} else {
internal_input = input;
}
std::string path;
if (internal_input.empty()) {
path = "/";
} else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
helpers::parse_prepared_path(internal_input.substr(1),
ada::scheme::type::FILE, path);
} else {
helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path);
}
return "file://" + path;
}
bool can_parse(std::string_view input, const std::string_view* base_input) {
ada::url_aggregator base_aggregator;
ada::url_aggregator* base_pointer = nullptr;
if (base_input != nullptr) {
base_aggregator = ada::parser::parse_url_impl<ada::url_aggregator, false>(
*base_input, nullptr);
if (!base_aggregator.is_valid) {
return false;
}
base_pointer = &base_aggregator;
}
ada::url_aggregator result =
ada::parser::parse_url_impl<ada::url_aggregator, false>(input,
base_pointer);
return result.is_valid;
}
ada_warn_unused std::string to_string(ada::encoding_type type) {
switch (type) {
case ada::encoding_type::UTF8:
return "UTF-8";
case ada::encoding_type::UTF_16LE:
return "UTF-16LE";
case ada::encoding_type::UTF_16BE:
return "UTF-16BE";
default:
unreachable();
}
}
} // namespace ada
/* end file src/implementation.cpp */
/* begin file src/helpers.cpp */
#include <cstring>
#include <sstream>
namespace ada::helpers {
template <typename out_iter>
void encode_json(std::string_view view, out_iter out) {
// trivial implementation. could be faster.
const char* hexvalues =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
for (uint8_t c : view) {
if (c == '\\') {
*out++ = '\\';
*out++ = '\\';
} else if (c == '"') {
*out++ = '\\';
*out++ = '"';
} else if (c <= 0x1f) {
*out++ = '\\';
*out++ = 'u';
*out++ = '0';
*out++ = '0';
*out++ = hexvalues[2 * c];
*out++ = hexvalues[2 * c + 1];
} else {
*out++ = c;
}
}
}
ada_unused std::string get_state(ada::state s) {
switch (s) {
case ada::state::AUTHORITY:
return "Authority";
case ada::state::SCHEME_START:
return "Scheme Start";
case ada::state::SCHEME:
return "Scheme";
case ada::state::HOST:
return "Host";
case ada::state::NO_SCHEME:
return "No Scheme";
case ada::state::FRAGMENT:
return "Fragment";
case ada::state::RELATIVE_SCHEME:
return "Relative Scheme";
case ada::state::RELATIVE_SLASH:
return "Relative Slash";
case ada::state::FILE:
return "File";
case ada::state::FILE_HOST:
return "File Host";
case ada::state::FILE_SLASH:
return "File Slash";
case ada::state::PATH_OR_AUTHORITY:
return "Path or Authority";
case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES:
return "Special Authority Ignore Slashes";
case ada::state::SPECIAL_AUTHORITY_SLASHES:
return "Special Authority Slashes";
case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY:
return "Special Relative or Authority";
case ada::state::QUERY:
return "Query";
case ada::state::PATH:
return "Path";
case ada::state::PATH_START:
return "Path Start";
case ada::state::OPAQUE_PATH:
return "Opaque Path";
case ada::state::PORT:
return "Port";
default:
return "unknown state";
}
}
ada_really_inline std::optional<std::string_view> prune_hash(
std::string_view& input) noexcept {
// compiles down to 20--30 instructions including a class to memchr (C
// function). this function should be quite fast.
size_t location_of_first = input.find('#');
if (location_of_first == std::string_view::npos) {
return std::nullopt;
}
std::string_view hash = input;
hash.remove_prefix(location_of_first + 1);
input.remove_suffix(input.size() - location_of_first);
return hash;
}
ada_really_inline bool shorten_path(std::string& path,
ada::scheme::type type) noexcept {
// Let path be url's path.
// If url's scheme is "file", path's size is 1, and path[0] is a normalized
// Windows drive letter, then return.
if (type == ada::scheme::type::FILE &&
path.find('/', 1) == std::string_view::npos && !path.empty()) {
if (checkers::is_normalized_windows_drive_letter(
helpers::substring(path, 1))) {
return false;
}
}
// Remove path's last item, if any.
size_t last_delimiter = path.rfind('/');
if (last_delimiter != std::string::npos) {
path.erase(last_delimiter);
return true;
}
return false;
}
ada_really_inline bool shorten_path(std::string_view& path,
ada::scheme::type type) noexcept {
// Let path be url's path.
// If url's scheme is "file", path's size is 1, and path[0] is a normalized
// Windows drive letter, then return.
if (type == ada::scheme::type::FILE &&
path.find('/', 1) == std::string_view::npos && !path.empty()) {
if (checkers::is_normalized_windows_drive_letter(
helpers::substring(path, 1))) {
return false;
}
}
// Remove path's last item, if any.
if (!path.empty()) {
size_t slash_loc = path.rfind('/');
if (slash_loc != std::string_view::npos) {
path.remove_suffix(path.size() - slash_loc);
return true;
}
}
return false;
}
ada_really_inline void remove_ascii_tab_or_newline(
std::string& input) noexcept {
// if this ever becomes a performance issue, we could use an approach similar
// to has_tabs_or_newline
std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
}
ada_really_inline constexpr std::string_view substring(std::string_view input,
size_t pos) noexcept {
ADA_ASSERT_TRUE(pos <= input.size());
// The following is safer but unneeded if we have the above line:
// return pos > input.size() ? std::string_view() : input.substr(pos);
return input.substr(pos);
}
ada_really_inline void resize(std::string_view& input, size_t pos) noexcept {
ADA_ASSERT_TRUE(pos <= input.size());
input.remove_suffix(input.size() - pos);
}
// computes the number of trailing zeroes
// this is a private inline function only defined in this source file.
ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
#ifdef ADA_REGULAR_VISUAL_STUDIO
unsigned long ret;
// Search the mask data from least significant bit (LSB)
// to the most significant bit (MSB) for a set bit (1).
_BitScanForward(&ret, input_num);
return (int)ret;
#else // ADA_REGULAR_VISUAL_STUDIO
return __builtin_ctzl(input_num);
#endif // ADA_REGULAR_VISUAL_STUDIO
}
// starting at index location, this finds the next location of a character
// :, /, \\, ? or [. If none is found, view.size() is returned.
// For use within get_host_delimiter_location.
#if ADA_NEON
// The ada_make_uint8x16_t macro is necessary because Visual Studio does not
// support direct initialization of uint8x16_t. See
// https://developercommunity.visualstudio.com/t/error-C2078:-too-many-initializers-whe/402911?q=backend+neon
#ifndef ada_make_uint8x16_t
#define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
x13, x14, x15, x16) \
([=]() { \
static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
x9, x10, x11, x12, x13, x14, x15, x16}; \
return vld1q_u8(array); \
}())
#endif
ada_really_inline size_t find_next_host_delimiter_special(
std::string_view view, size_t location) noexcept {
// first check for short strings in which case we do it naively.
if (view.size() - location < 16) { // slow path
for (size_t i = location; i < view.size(); i++) {
if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
view[i] == '?' || view[i] == '[') {
return i;
}
}
return size_t(view.size());
}
auto to_bitmask = [](uint8x16_t input) -> uint16_t {
uint8x16_t bit_mask =
ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
uint8x16_t minput = vandq_u8(input, bit_mask);
uint8x16_t tmp = vpaddq_u8(minput, minput);
tmp = vpaddq_u8(tmp, tmp);
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
};
// fast path for long strings (expected to be common)
size_t i = location;
uint8x16_t low_mask =
ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03);
uint8x16_t high_mask =
ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
uint8x16_t fmask = vmovq_n_u8(0xf);
uint8x16_t zero{0};
for (; i + 15 < view.size(); i += 16) {
uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i);
uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
uint8x16_t classify = vandq_u8(lowpart, highpart);
if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
uint8x16_t is_zero = vceqq_u8(classify, zero);
uint16_t is_non_zero = ~to_bitmask(is_zero);
return i + trailing_zeroes(is_non_zero);
}
}
if (i < view.size()) {
uint8x16_t word =
vld1q_u8((const uint8_t*)view.data() + view.length() - 16);
uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
uint8x16_t classify = vandq_u8(lowpart, highpart);
if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
uint8x16_t is_zero = vceqq_u8(classify, zero);
uint16_t is_non_zero = ~to_bitmask(is_zero);
return view.length() - 16 + trailing_zeroes(is_non_zero);
}
}
return size_t(view.size());
}
#elif ADA_SSE2
ada_really_inline size_t find_next_host_delimiter_special(
std::string_view view, size_t location) noexcept {
// first check for short strings in which case we do it naively.
if (view.size() - location < 16) { // slow path
for (size_t i = location; i < view.size(); i++) {
if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
view[i] == '?' || view[i] == '[') {
return i;
}
}
return size_t(view.size());
}
// fast path for long strings (expected to be common)
size_t i = location;
const __m128i mask1 = _mm_set1_epi8(':');
const __m128i mask2 = _mm_set1_epi8('/');
const __m128i mask3 = _mm_set1_epi8('\\');
const __m128i mask4 = _mm_set1_epi8('?');
const __m128i mask5 = _mm_set1_epi8('[');
for (; i + 15 < view.size(); i += 16) {
__m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
__m128i m1 = _mm_cmpeq_epi8(word, mask1);
__m128i m2 = _mm_cmpeq_epi8(word, mask2);
__m128i m3 = _mm_cmpeq_epi8(word, mask3);
__m128i m4 = _mm_cmpeq_epi8(word, mask4);
__m128i m5 = _mm_cmpeq_epi8(word, mask5);
__m128i m = _mm_or_si128(
_mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
int mask = _mm_movemask_epi8(m);
if (mask != 0) {
return i + trailing_zeroes(mask);
}
}
if (i < view.size()) {
__m128i word =
_mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
__m128i m1 = _mm_cmpeq_epi8(word, mask1);
__m128i m2 = _mm_cmpeq_epi8(word, mask2);
__m128i m3 = _mm_cmpeq_epi8(word, mask3);
__m128i m4 = _mm_cmpeq_epi8(word, mask4);
__m128i m5 = _mm_cmpeq_epi8(word, mask5);
__m128i m = _mm_or_si128(
_mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
int mask = _mm_movemask_epi8(m);
if (mask != 0) {
return view.length() - 16 + trailing_zeroes(mask);
}
}
return size_t(view.length());
}
#else
// : / [ \\ ?
static constexpr std::array<uint8_t, 256> special_host_delimiters =
[]() consteval {
std::array<uint8_t, 256> result{};
for (int i : {':', '/', '[', '\\', '?'}) {
result[i] = 1;
}
return result;
}();
// credit: @the-moisrex recommended a table-based approach
ada_really_inline size_t find_next_host_delimiter_special(
std::string_view view, size_t location) noexcept {
auto const str = view.substr(location);
for (auto pos = str.begin(); pos != str.end(); ++pos) {
if (special_host_delimiters[(uint8_t)*pos]) {
return pos - str.begin() + location;
}
}
return size_t(view.size());
}
#endif
// starting at index location, this finds the next location of a character
// :, /, ? or [. If none is found, view.size() is returned.
// For use within get_host_delimiter_location.
#if ADA_NEON
ada_really_inline size_t find_next_host_delimiter(std::string_view view,
size_t location) noexcept {
// first check for short strings in which case we do it naively.
if (view.size() - location < 16) { // slow path
for (size_t i = location; i < view.size(); i++) {
if (view[i] == ':' || view[i] == '/' || view[i] == '?' ||
view[i] == '[') {
return i;
}
}
return size_t(view.size());
}
auto to_bitmask = [](uint8x16_t input) -> uint16_t {
uint8x16_t bit_mask =
ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
uint8x16_t minput = vandq_u8(input, bit_mask);
uint8x16_t tmp = vpaddq_u8(minput, minput);
tmp = vpaddq_u8(tmp, tmp);
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
};
// fast path for long strings (expected to be common)
size_t i = location;
uint8x16_t low_mask =
ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03);
uint8x16_t high_mask =
ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
uint8x16_t fmask = vmovq_n_u8(0xf);
uint8x16_t zero{0};
for (; i + 15 < view.size(); i += 16) {
uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i);
uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
uint8x16_t classify = vandq_u8(lowpart, highpart);
if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
uint8x16_t is_zero = vceqq_u8(classify, zero);
uint16_t is_non_zero = ~to_bitmask(is_zero);
return i + trailing_zeroes(is_non_zero);
}
}
if (i < view.size()) {
uint8x16_t word =
vld1q_u8((const uint8_t*)view.data() + view.length() - 16);
uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
uint8x16_t classify = vandq_u8(lowpart, highpart);
if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
uint8x16_t is_zero = vceqq_u8(classify, zero);
uint16_t is_non_zero = ~to_bitmask(is_zero);
return view.length() - 16 + trailing_zeroes(is_non_zero);
}
}
return size_t(view.size());
}
#elif ADA_SSE2
ada_really_inline size_t find_next_host_delimiter(std::string_view view,
size_t location) noexcept {
// first check for short strings in which case we do it naively.
if (view.size() - location < 16) { // slow path
for (size_t i = location; i < view.size(); i++) {
if (view[i] == ':' || view[i] == '/' || view[i] == '?' ||
view[i] == '[') {
return i;
}
}
return size_t(view.size());
}
// fast path for long strings (expected to be common)
size_t i = location;
const __m128i mask1 = _mm_set1_epi8(':');
const __m128i mask2 = _mm_set1_epi8('/');
const __m128i mask4 = _mm_set1_epi8('?');
const __m128i mask5 = _mm_set1_epi8('[');
for (; i + 15 < view.size(); i += 16) {
__m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
__m128i m1 = _mm_cmpeq_epi8(word, mask1);
__m128i m2 = _mm_cmpeq_epi8(word, mask2);
__m128i m4 = _mm_cmpeq_epi8(word, mask4);
__m128i m5 = _mm_cmpeq_epi8(word, mask5);
__m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
int mask = _mm_movemask_epi8(m);
if (mask != 0) {
return i + trailing_zeroes(mask);
}
}
if (i < view.size()) {
__m128i word =
_mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
__m128i m1 = _mm_cmpeq_epi8(word, mask1);
__m128i m2 = _mm_cmpeq_epi8(word, mask2);
__m128i m4 = _mm_cmpeq_epi8(word, mask4);
__m128i m5 = _mm_cmpeq_epi8(word, mask5);
__m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
int mask = _mm_movemask_epi8(m);
if (mask != 0) {
return view.length() - 16 + trailing_zeroes(mask);
}
}
return size_t(view.length());
}
#else
// : / [ ?
static constexpr std::array<uint8_t, 256> host_delimiters = []() consteval {
std::array<uint8_t, 256> result{};
for (int i : {':', '/', '?', '['}) {
result[i] = 1;
}
return result;
}();
// credit: @the-moisrex recommended a table-based approach
ada_really_inline size_t find_next_host_delimiter(std::string_view view,
size_t location) noexcept {
auto const str = view.substr(location);
for (auto pos = str.begin(); pos != str.end(); ++pos) {
if (host_delimiters[(uint8_t)*pos]) {
return pos - str.begin() + location;
}
}
return size_t(view.size());
}
#endif
ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
const bool is_special, std::string_view& view) noexcept {
/**
* The spec at https://url.spec.whatwg.org/#hostname-state expects us to
* compute a variable called insideBrackets but this variable is only used
* once, to check whether a ':' character was found outside brackets. Exact
* text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
* It is conceptually simpler and arguably more efficient to just return a
* Boolean indicating whether ':' was found outside brackets.
*/
const size_t view_size = view.size();
size_t location = 0;
bool found_colon = false;
/**
* Performance analysis:
*
* We are basically seeking the end of the hostname which can be indicated
* by the end of the view, or by one of the characters ':', '/', '?', '\\'
* (where '\\' is only applicable for special URLs). However, these must
* appear outside a bracket range. E.g., if you have [something?]fd: then the
* '?' does not count.
*
* So we can skip ahead to the next delimiter, as long as we include '[' in
* the set of delimiters, and that we handle it first.
*
* So the trick is to have a fast function that locates the next delimiter.
* Unless we find '[', then it only needs to be called once! Ideally, such a
* function would be provided by the C++ standard library, but it seems that
* find_first_of is not very fast, so we are forced to roll our own.
*
* We do not break into two loops for speed, but for clarity.
*/
if (is_special) {
// We move to the next delimiter.
location = find_next_host_delimiter_special(view, location);
// Unless we find '[' then we are going only going to have to call
// find_next_host_delimiter_special once.
for (; location < view_size;
location = find_next_host_delimiter_special(view, location)) {
if (view[location] == '[') {
location = view.find(']', location);
if (location == std::string_view::npos) {
// performance: view.find might get translated to a memchr, which
// has no notion of std::string_view::npos, so the code does not
// reflect the assembly.
location = view_size;
break;
}
} else {
found_colon = view[location] == ':';
break;
}
}
} else {
// We move to the next delimiter.
location = find_next_host_delimiter(view, location);
// Unless we find '[' then we are going only going to have to call
// find_next_host_delimiter_special once.
for (; location < view_size;
location = find_next_host_delimiter(view, location)) {
if (view[location] == '[') {
location = view.find(']', location);
if (location == std::string_view::npos) {
// performance: view.find might get translated to a memchr, which
// has no notion of std::string_view::npos, so the code does not
// reflect the assembly.
location = view_size;
break;
}
} else {
found_colon = view[location] == ':';
break;
}
}
}
// performance: remove_suffix may translate into a single instruction.
view.remove_suffix(view_size - location);
return {location, found_colon};
}
void trim_c0_whitespace(std::string_view& input) noexcept {
while (!input.empty() &&
ada::unicode::is_c0_control_or_space(input.front())) {
input.remove_prefix(1);
}
while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
input.remove_suffix(1);
}
}
ada_really_inline void parse_prepared_path(std::string_view input,
ada::scheme::type type,
std::string& path) {
ada_log("parse_prepared_path ", input);
uint8_t accumulator = checkers::path_signature(input);
// Let us first detect a trivial case.
// If it is special, we check that we have no dot, no %, no \ and no
// character needing percent encoding. Otherwise, we check that we have no %,
// no dot, and no character needing percent encoding.
constexpr uint8_t need_encoding = 1;
constexpr uint8_t backslash_char = 2;
constexpr uint8_t dot_char = 4;
constexpr uint8_t percent_char = 8;
bool special = type != ada::scheme::NOT_SPECIAL;
bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
checkers::is_windows_drive_letter(input));
bool trivial_path =
(special ? (accumulator == 0)
: ((accumulator & (need_encoding | dot_char | percent_char)) ==
0)) &&
(!may_need_slow_file_handling);
if (accumulator == dot_char && !may_need_slow_file_handling) {
// '4' means that we have at least one dot, but nothing that requires
// percent encoding or decoding. The only part that is not trivial is
// that we may have single dots and double dots path segments.
// If we have such segments, then we either have a path that begins
// with '.' (easy to check), or we have the sequence './'.
// Note: input cannot be empty, it must at least contain one character ('.')
// Note: we know that '\' is not present.
if (input[0] != '.') {
size_t slashdot = input.find("/.");
if (slashdot == std::string_view::npos) { // common case
trivial_path = true;
} else { // uncommon
// only three cases matter: /./, /.. or a final /
trivial_path =
!(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
input[slashdot + 2] == '/');
}
}
}
if (trivial_path) {
ada_log("parse_path trivial");
path += '/';
path += input;
return;
}
// We are going to need to look a bit at the path, but let us see if we can
// ignore percent encoding *and* backslashes *and* percent characters.
// Except for the trivial case, this is likely to capture 99% of paths out
// there.
bool fast_path =
(special &&
(accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
(type != ada::scheme::type::FILE);
if (fast_path) {
ada_log("parse_prepared_path fast");
// Here we don't need to worry about \ or percent encoding.
// We also do not have a file protocol. We might have dots, however,
// but dots must as appear as '.', and they cannot be encoded because
// the symbol '%' is not present.
size_t previous_location = 0; // We start at 0.
do {
size_t new_location = input.find('/', previous_location);
// std::string_view path_view = input;
// We process the last segment separately:
if (new_location == std::string_view::npos) {
std::string_view path_view = input.substr(previous_location);
if (path_view == "..") { // The path ends with ..
// e.g., if you receive ".." with an empty path, you go to "/".
if (path.empty()) {
path = '/';
return;
}
// Fast case where we have nothing to do:
if (path.back() == '/') {
return;
}
// If you have the path "/joe/myfriend",
// then you delete 'myfriend'.
path.resize(path.rfind('/') + 1);
return;
}
path += '/';
if (path_view != ".") {
path.append(path_view);
}
return;
} else {
// This is a non-final segment.
std::string_view path_view =
input.substr(previous_location, new_location - previous_location);
previous_location = new_location + 1;
if (path_view == "..") {
size_t last_delimiter = path.rfind('/');
if (last_delimiter != std::string::npos) {
path.erase(last_delimiter);
}
} else if (path_view != ".") {
path += '/';
path.append(path_view);
}
}
} while (true);
} else {
ada_log("parse_path slow");
// we have reached the general case
bool needs_percent_encoding = (accumulator & 1);
std::string path_buffer_tmp;
do {
size_t location = (special && (accumulator & 2))
? input.find_first_of("/\\")
: input.find('/');
std::string_view path_view = input;
if (location != std::string_view::npos) {
path_view.remove_suffix(path_view.size() - location);
input.remove_prefix(location + 1);
}
// path_buffer is either path_view or it might point at a percent encoded
// temporary file.
std::string_view path_buffer =
(needs_percent_encoding &&
ada::unicode::percent_encode<false>(
path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
? path_buffer_tmp
: path_view;
if (unicode::is_double_dot_path_segment(path_buffer)) {
if ((helpers::shorten_path(path, type) || special) &&
location == std::string_view::npos) {
path += '/';
}
} else if (unicode::is_single_dot_path_segment(path_buffer) &&
(location == std::string_view::npos)) {
path += '/';
}
// Otherwise, if path_buffer is not a single-dot path segment, then:
else if (!unicode::is_single_dot_path_segment(path_buffer)) {
// If url's scheme is "file", url's path is empty, and path_buffer is a
// Windows drive letter, then replace the second code point in
// path_buffer with U+003A (:).
if (type == ada::scheme::type::FILE && path.empty() &&
checkers::is_windows_drive_letter(path_buffer)) {
path += '/';
path += path_buffer[0];
path += ':';
path_buffer.remove_prefix(2);
path.append(path_buffer);
} else {
// Append path_buffer to url's path.
path += '/';
path.append(path_buffer);
}
}
if (location == std::string_view::npos) {
return;
}
} while (true);
}
}
bool overlaps(std::string_view input1, const std::string& input2) noexcept {
ada_log("helpers::overlaps check if string_view '", input1, "' [",
input1.size(), " bytes] is part of string '", input2, "' [",
input2.size(), " bytes]");
return !input1.empty() && !input2.empty() && input1.data() >= input2.data() &&
input1.data() < input2.data() + input2.size();
}
template <class url_type>
ada_really_inline void strip_trailing_spaces_from_opaque_path(
url_type& url) noexcept {
ada_log("helpers::strip_trailing_spaces_from_opaque_path");
if (!url.has_opaque_path) return;
if (url.has_hash()) return;
if (url.has_search()) return;
auto path = std::string(url.get_pathname());
while (!path.empty() && path.back() == ' ') {
path.resize(path.size() - 1);
}
url.update_base_pathname(path);
}
// @ / \\ ?
static constexpr std::array<uint8_t, 256> authority_delimiter_special =
[]() consteval {
std::array<uint8_t, 256> result{};
for (uint8_t i : {'@', '/', '\\', '?'}) {
result[i] = 1;
}
return result;
}();
// credit: @the-moisrex recommended a table-based approach
ada_really_inline size_t
find_authority_delimiter_special(std::string_view view) noexcept {
// performance note: we might be able to gain further performance
// with SIMD instrinsics.
for (auto pos = view.begin(); pos != view.end(); ++pos) {
if (authority_delimiter_special[(uint8_t)*pos]) {
return pos - view.begin();
}
}
return size_t(view.size());
}
// @ / ?
static constexpr std::array<uint8_t, 256> authority_delimiter = []() consteval {
std::array<uint8_t, 256> result{};
for (uint8_t i : {'@', '/', '?'}) {
result[i] = 1;
}
return result;
}();
// credit: @the-moisrex recommended a table-based approach
ada_really_inline size_t
find_authority_delimiter(std::string_view view) noexcept {
// performance note: we might be able to gain further performance
// with SIMD instrinsics.
for (auto pos = view.begin(); pos != view.end(); ++pos) {
if (authority_delimiter[(uint8_t)*pos]) {
return pos - view.begin();
}
}
return size_t(view.size());
}
} // namespace ada::helpers
namespace ada {
ada_warn_unused std::string to_string(ada::state state) {
return ada::helpers::get_state(state);
}
#undef ada_make_uint8x16_t
} // namespace ada
/* end file src/helpers.cpp */
/* begin file src/url.cpp */
#include <numeric>
#include <algorithm>
#include <string>
#include <string_view>
namespace ada {
bool url::parse_opaque_host(std::string_view input) {
ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
if (std::ranges::any_of(input.begin(), input.end(),
ada::unicode::is_forbidden_host_code_point)) {
return is_valid = false;
}
// Return the result of running UTF-8 percent-encode on input using the C0
// control percent-encode set.
host = ada::unicode::percent_encode(
input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE);
return true;
}
bool url::parse_ipv4(std::string_view input) {
ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]");
if (input.back() == '.') {
input.remove_suffix(1);
}
size_t digit_count{0};
int pure_decimal_count = 0; // entries that are decimal
std::string_view original_input =
input; // we might use this if pure_decimal_count == 4.
uint64_t ipv4{0};
// we could unroll for better performance?
for (; (digit_count < 4) && !(input.empty()); digit_count++) {
uint32_t
segment_result{}; // If any number exceeds 32 bits, we have an error.
bool is_hex = checkers::has_hex_prefix(input);
if (is_hex && ((input.length() == 2) ||
((input.length() > 2) && (input[2] == '.')))) {
// special case
segment_result = 0;
input.remove_prefix(2);
} else {
std::from_chars_result r{};
if (is_hex) {
r = std::from_chars(input.data() + 2, input.data() + input.size(),
segment_result, 16);
} else if ((input.length() >= 2) && input[0] == '0' &&
checkers::is_digit(input[1])) {
r = std::from_chars(input.data() + 1, input.data() + input.size(),
segment_result, 8);
} else {
pure_decimal_count++;
r = std::from_chars(input.data(), input.data() + input.size(),
segment_result, 10);
}
if (r.ec != std::errc()) {
return is_valid = false;
}
input.remove_prefix(r.ptr - input.data());
}
if (input.empty()) {
// We have the last value.
// At this stage, ipv4 contains digit_count*8 bits.
// So we have 32-digit_count*8 bits left.
if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
return is_valid = false;
}
ipv4 <<= (32 - digit_count * 8);
ipv4 |= segment_result;
goto final;
} else {
// There is more, so that the value must no be larger than 255
// and we must have a '.'.
if ((segment_result > 255) || (input[0] != '.')) {
return is_valid = false;
}
ipv4 <<= 8;
ipv4 |= segment_result;
input.remove_prefix(1); // remove '.'
}
}
if ((digit_count != 4) || (!input.empty())) {
return is_valid = false;
}
final:
// We could also check r.ptr to see where the parsing ended.
if (pure_decimal_count == 4) {
host = original_input; // The original input was already all decimal and we
// validated it.
} else {
host = ada::serializers::ipv4(ipv4); // We have to reserialize the address.
}
host_type = IPV4;
return true;
}
bool url::parse_ipv6(std::string_view input) {
ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
if (input.empty()) {
return is_valid = false;
}
// Let address be a new IPv6 address whose IPv6 pieces are all 0.
std::array<uint16_t, 8> address{};
// Let pieceIndex be 0.
int piece_index = 0;
// Let compress be null.
std::optional<int> compress{};
// Let pointer be a pointer for input.
std::string_view::iterator pointer = input.begin();
// If c is U+003A (:), then:
if (input[0] == ':') {
// If remaining does not start with U+003A (:), validation error, return
// failure.
if (input.size() == 1 || input[1] != ':') {
ada_log("parse_ipv6 starts with : but the rest does not start with :");
return is_valid = false;
}
// Increase pointer by 2.
pointer += 2;
// Increase pieceIndex by 1 and then set compress to pieceIndex.
compress = ++piece_index;
}
// While c is not the EOF code point:
while (pointer != input.end()) {
// If pieceIndex is 8, validation error, return failure.
if (piece_index == 8) {
ada_log("parse_ipv6 piece_index == 8");
return is_valid = false;
}
// If c is U+003A (:), then:
if (*pointer == ':') {
// If compress is non-null, validation error, return failure.
if (compress.has_value()) {
ada_log("parse_ipv6 compress is non-null");
return is_valid = false;
}
// Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
// then continue.
pointer++;
compress = ++piece_index;
continue;
}
// Let value and length be 0.
uint16_t value = 0, length = 0;
// While length is less than 4 and c is an ASCII hex digit,
// set value to value times 0x10 + c interpreted as hexadecimal number, and
// increase pointer and length by 1.
while (length < 4 && pointer != input.end() &&
unicode::is_ascii_hex_digit(*pointer)) {
// https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
pointer++;
length++;
}
// If c is U+002E (.), then:
if (pointer != input.end() && *pointer == '.') {
// If length is 0, validation error, return failure.
if (length == 0) {
ada_log("parse_ipv6 length is 0");
return is_valid = false;
}
// Decrease pointer by length.
pointer -= length;
// If pieceIndex is greater than 6, validation error, return failure.
if (piece_index > 6) {
ada_log("parse_ipv6 piece_index > 6");
return is_valid = false;
}
// Let numbersSeen be 0.
int numbers_seen = 0;
// While c is not the EOF code point:
while (pointer != input.end()) {
// Let ipv4Piece be null.
std::optional<uint16_t> ipv4_piece{};
// If numbersSeen is greater than 0, then:
if (numbers_seen > 0) {
// If c is a U+002E (.) and numbersSeen is less than 4, then increase
// pointer by 1.
if (*pointer == '.' && numbers_seen < 4) {
pointer++;
}
// Otherwise, validation error, return failure.
else {
ada_log("parse_ipv6 Otherwise, validation error, return failure");
return is_valid = false;
}
}
// If c is not an ASCII digit, validation error, return failure.
if (pointer == input.end() || !checkers::is_digit(*pointer)) {
ada_log(
"parse_ipv6 If c is not an ASCII digit, validation error, return "
"failure");
return is_valid = false;
}
// While c is an ASCII digit:
while (pointer != input.end() && checkers::is_digit(*pointer)) {
// Let number be c interpreted as decimal number.
int number = *pointer - '0';
// If ipv4Piece is null, then set ipv4Piece to number.
if (!ipv4_piece.has_value()) {
ipv4_piece = number;
}
// Otherwise, if ipv4Piece is 0, validation error, return failure.
else if (ipv4_piece == 0) {
ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
return is_valid = false;
}
// Otherwise, set ipv4Piece to ipv4Piece times 10 + number.
else {
ipv4_piece = *ipv4_piece * 10 + number;
}
// If ipv4Piece is greater than 255, validation error, return failure.
if (ipv4_piece > 255) {
ada_log("parse_ipv6 ipv4_piece > 255");
return is_valid = false;
}
// Increase pointer by 1.
pointer++;
}
// Set address[pieceIndex] to address[pieceIndex] times 0x100 +
// ipv4Piece.
// https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
address[piece_index] =
uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
// Increase numbersSeen by 1.
numbers_seen++;
// If numbersSeen is 2 or 4, then increase pieceIndex by 1.
if (numbers_seen == 2 || numbers_seen == 4) {
piece_index++;
}
}
// If numbersSeen is not 4, validation error, return failure.
if (numbers_seen != 4) {
return is_valid = false;
}
// Break.
break;
}
// Otherwise, if c is U+003A (:):
else if ((pointer != input.end()) && (*pointer == ':')) {
// Increase pointer by 1.
pointer++;
// If c is the EOF code point, validation error, return failure.
if (pointer == input.end()) {
ada_log(
"parse_ipv6 If c is the EOF code point, validation error, return "
"failure");
return is_valid = false;
}
}
// Otherwise, if c is not the EOF code point, validation error, return
// failure.
else if (pointer != input.end()) {
ada_log(
"parse_ipv6 Otherwise, if c is not the EOF code point, validation "
"error, return failure");
return is_valid = false;
}
// Set address[pieceIndex] to value.
address[piece_index] = value;
// Increase pieceIndex by 1.
piece_index++;
}
// If compress is non-null, then:
if (compress.has_value()) {
// Let swaps be pieceIndex - compress.
int swaps = piece_index - *compress;
// Set pieceIndex to 7.
piece_index = 7;
// While pieceIndex is not 0 and swaps is greater than 0,
// swap address[pieceIndex] with address[compress + swaps - 1], and then
// decrease both pieceIndex and swaps by 1.
while (piece_index != 0 && swaps > 0) {
std::swap(address[piece_index], address[*compress + swaps - 1]);
piece_index--;
swaps--;
}
}
// Otherwise, if compress is null and pieceIndex is not 8, validation error,
// return failure.
else if (piece_index != 8) {
ada_log(
"parse_ipv6 if compress is null and pieceIndex is not 8, validation "
"error, return failure");
return is_valid = false;
}
host = ada::serializers::ipv6(address);
ada_log("parse_ipv6 ", *host);
host_type = IPV6;
return true;
}
template <bool has_state_override>
ada_really_inline bool url::parse_scheme(const std::string_view input) {
auto parsed_type = ada::scheme::get_scheme_type(input);
bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
/**
* In the common case, we will immediately recognize a special scheme (e.g.,
*http, https), in which case, we can go really fast.
**/
if (is_input_special) { // fast path!!!
if constexpr (has_state_override) {
// If url's scheme is not a special scheme and buffer is a special scheme,
// then return.
if (is_special() != is_input_special) {
return false;
}
// If url includes credentials or has a non-null port, and buffer is
// "file", then return.
if ((has_credentials() || port.has_value()) &&
parsed_type == ada::scheme::type::FILE) {
return false;
}
// If url's scheme is "file" and its host is an empty host, then return.
// An empty host is the empty string.
if (type == ada::scheme::type::FILE && host.has_value() &&
host.value().empty()) {
return false;
}
}
type = parsed_type;
if constexpr (has_state_override) {
// This is uncommon.
uint16_t urls_scheme_port = get_special_port();
if (urls_scheme_port) {
// If url's port is url's scheme's default port, then set url's port to
// null.
if (port.has_value() && *port == urls_scheme_port) {
port = std::nullopt;
}
}
}
} else { // slow path
std::string _buffer(input);
// Next function is only valid if the input is ASCII and returns false
// otherwise, but it seems that we always have ascii content so we do not
// need to check the return value.
// bool is_ascii =
unicode::to_lower_ascii(_buffer.data(), _buffer.size());
if constexpr (has_state_override) {
// If url's scheme is a special scheme and buffer is not a special scheme,
// then return. If url's scheme is not a special scheme and buffer is a
// special scheme, then return.
if (is_special() != ada::scheme::is_special(_buffer)) {
return true;
}
// If url includes credentials or has a non-null port, and buffer is
// "file", then return.
if ((has_credentials() || port.has_value()) && _buffer == "file") {
return true;
}
// If url's scheme is "file" and its host is an empty host, then return.
// An empty host is the empty string.
if (type == ada::scheme::type::FILE && host.has_value() &&
host.value().empty()) {
return true;
}
}
set_scheme(std::move(_buffer));
if constexpr (has_state_override) {
// This is uncommon.
uint16_t urls_scheme_port = get_special_port();
if (urls_scheme_port) {
// If url's port is url's scheme's default port, then set url's port to
// null.
if (port.has_value() && *port == urls_scheme_port) {
port = std::nullopt;
}
}
}
}
return true;
}
ada_really_inline bool url::parse_host(std::string_view input) {
ada_log("parse_host ", input, " [", input.size(), " bytes]");
if (input.empty()) {
return is_valid = false;
} // technically unnecessary.
// If input starts with U+005B ([), then:
if (input[0] == '[') {
// If input does not end with U+005D (]), validation error, return failure.
if (input.back() != ']') {
return is_valid = false;
}
ada_log("parse_host ipv6");
// Return the result of IPv6 parsing input with its leading U+005B ([) and
// trailing U+005D (]) removed.
input.remove_prefix(1);
input.remove_suffix(1);
return parse_ipv6(input);
}
// If isNotSpecial is true, then return the result of opaque-host parsing
// input.
if (!is_special()) {
return parse_opaque_host(input);
}
// Let domain be the result of running UTF-8 decode without BOM on the
// percent-decoding of input. Let asciiDomain be the result of running domain
// to ASCII with domain and false. The most common case is an ASCII input, in
// which case we do not need to call the expensive 'to_ascii' if a few
// conditions are met: no '%' and no 'xn-' subsequence.
std::string buffer = std::string(input);
// This next function checks that the result is ascii, but we are going to
// to check anyhow with is_forbidden.
// bool is_ascii =
unicode::to_lower_ascii(buffer.data(), buffer.size());
bool is_forbidden = unicode::contains_forbidden_domain_code_point(
buffer.data(), buffer.size());
if (is_forbidden == 0 && buffer.find("xn-") == std::string_view::npos) {
// fast path
host = std::move(buffer);
if (checkers::is_ipv4(host.value())) {
ada_log("parse_host fast path ipv4");
return parse_ipv4(host.value());
}
ada_log("parse_host fast path ", *host);
return true;
}
ada_log("parse_host calling to_ascii");
is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
if (!is_valid) {
ada_log("parse_host to_ascii returns false");
return is_valid = false;
}
ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
" bytes]");
if (std::any_of(host.value().begin(), host.value().end(),
ada::unicode::is_forbidden_domain_code_point)) {
host = std::nullopt;
return is_valid = false;
}
// If asciiDomain ends in a number, then return the result of IPv4 parsing
// asciiDomain.
if (checkers::is_ipv4(host.value())) {
ada_log("parse_host got ipv4 ", *host);
return parse_ipv4(host.value());
}
return true;
}
ada_really_inline void url::parse_path(std::string_view input) {
ada_log("parse_path ", input);
std::string tmp_buffer;
std::string_view internal_input;
if (unicode::has_tabs_or_newline(input)) {
tmp_buffer = input;
// Optimization opportunity: Instead of copying and then pruning, we could
// just directly build the string from user_input.
helpers::remove_ascii_tab_or_newline(tmp_buffer);
internal_input = tmp_buffer;
} else {
internal_input = input;
}
// If url is special, then:
if (is_special()) {
if (internal_input.empty()) {
path = "/";
} else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
helpers::parse_prepared_path(internal_input.substr(1), type, path);
} else {
helpers::parse_prepared_path(internal_input, type, path);
}
} else if (!internal_input.empty()) {
if (internal_input[0] == '/') {
helpers::parse_prepared_path(internal_input.substr(1), type, path);
} else {
helpers::parse_prepared_path(internal_input, type, path);
}
} else {
if (!host.has_value()) {
path = "/";
}
}
}
[[nodiscard]] std::string url::to_string() const {
if (!is_valid) {
return "null";
}
std::string answer;
auto back = std::back_insert_iterator(answer);
answer.append("{\n");
answer.append("\t\"protocol\":\"");
helpers::encode_json(get_protocol(), back);
answer.append("\",\n");
if (has_credentials()) {
answer.append("\t\"username\":\"");
helpers::encode_json(username, back);
answer.append("\",\n");
answer.append("\t\"password\":\"");
helpers::encode_json(password, back);
answer.append("\",\n");
}
if (host.has_value()) {
answer.append("\t\"host\":\"");
helpers::encode_json(host.value(), back);
answer.append("\",\n");
}
if (port.has_value()) {
answer.append("\t\"port\":\"");
answer.append(std::to_string(port.value()));
answer.append("\",\n");
}
answer.append("\t\"path\":\"");
helpers::encode_json(path, back);
answer.append("\",\n");
answer.append("\t\"opaque path\":");
answer.append((has_opaque_path ? "true" : "false"));
if (has_search()) {
answer.append(",\n");
answer.append("\t\"query\":\"");
helpers::encode_json(query.value(), back);
answer.append("\"");
}
if (hash.has_value()) {
answer.append(",\n");
answer.append("\t\"hash\":\"");
helpers::encode_json(hash.value(), back);
answer.append("\"");
}
answer.append("\n}");
return answer;
}
[[nodiscard]] bool url::has_valid_domain() const noexcept {
if (!host.has_value()) {
return false;
}
return checkers::verify_dns_length(host.value());
}
[[nodiscard]] std::string url::get_origin() const noexcept {
if (is_special()) {
// Return a new opaque origin.
if (type == scheme::FILE) {
return "null";
}
return ada::helpers::concat(get_protocol(), "//", get_host());
}
if (non_special_scheme == "blob") {
if (!path.empty()) {
auto result = ada::parse<ada::url>(path);
if (result &&
(result->type == scheme::HTTP || result->type == scheme::HTTPS)) {
// If pathURL's scheme is not "http" and not "https", then return a
// new opaque origin.
return ada::helpers::concat(result->get_protocol(), "//",
result->get_host());
}
}
}
// Return a new opaque origin.
return "null";
}
[[nodiscard]] std::string url::get_protocol() const noexcept {
if (is_special()) {
return helpers::concat(ada::scheme::details::is_special_list[type], ":");
}
// We only move the 'scheme' if it is non-special.
return helpers::concat(non_special_scheme, ":");
}
[[nodiscard]] std::string url::get_host() const noexcept {
// If url's host is null, then return the empty string.
// If url's port is null, return url's host, serialized.
// Return url's host, serialized, followed by U+003A (:) and url's port,
// serialized.
if (!host.has_value()) {
return "";
}
if (port.has_value()) {
return host.value() + ":" + get_port();
}
return host.value();
}
[[nodiscard]] std::string url::get_hostname() const noexcept {
return host.value_or("");
}
[[nodiscard]] std::string url::get_search() const noexcept {
// If this's URL's query is either null or the empty string, then return the
// empty string. Return U+003F (?), followed by this's URL's query.
return (!query.has_value() || (query.value().empty())) ? ""
: "?" + query.value();
}
[[nodiscard]] const std::string& url::get_username() const noexcept {
return username;
}
[[nodiscard]] const std::string& url::get_password() const noexcept {
return password;
}
[[nodiscard]] std::string url::get_port() const noexcept {
return port.has_value() ? std::to_string(port.value()) : "";
}
[[nodiscard]] std::string url::get_hash() const noexcept {
// If this's URL's fragment is either null or the empty string, then return
// the empty string. Return U+0023 (#), followed by this's URL's fragment.
return (!hash.has_value() || (hash.value().empty())) ? ""
: "#" + hash.value();
}
template <bool override_hostname>
bool url::set_host_or_hostname(const std::string_view input) {
if (has_opaque_path) {
return false;
}
std::optional<std::string> previous_host = host;
std::optional<uint16_t> previous_port = port;
size_t host_end_pos = input.find('#');
std::string _host(input.data(), host_end_pos != std::string_view::npos
? host_end_pos
: input.size());
helpers::remove_ascii_tab_or_newline(_host);
std::string_view new_host(_host);
// If url's scheme is "file", then set state to file host state, instead of
// host state.
if (type != ada::scheme::type::FILE) {
std::string_view host_view(_host.data(), _host.length());
auto [location, found_colon] =
helpers::get_host_delimiter_location(is_special(), host_view);
// Otherwise, if c is U+003A (:) and insideBrackets is false, then:
// Note: the 'found_colon' value is true if and only if a colon was
// encountered while not inside brackets.
if (found_colon) {
if constexpr (override_hostname) {
return false;
}
std::string_view buffer = new_host.substr(location + 1);
if (!buffer.empty()) {
set_port(buffer);
}
}
// If url is special and host_view is the empty string, validation error,
// return failure. Otherwise, if state override is given, host_view is the
// empty string, and either url includes credentials or url's port is
// non-null, return.
else if (host_view.empty() &&
(is_special() || has_credentials() || port.has_value())) {
return false;
}
// Let host be the result of host parsing host_view with url is not special.
if (host_view.empty() && !is_special()) {
host = "";
return true;
}
bool succeeded = parse_host(host_view);
if (!succeeded) {
host = std::move(previous_host);
update_base_port(previous_port);
}
return succeeded;
}
size_t location = new_host.find_first_of("/\\?");
if (location != std::string_view::npos) {
new_host.remove_suffix(new_host.length() - location);
}
if (new_host.empty()) {
// Set url's host to the empty string.
host = "";
} else {
// Let host be the result of host parsing buffer with url is not special.
if (!parse_host(new_host)) {
host = std::move(previous_host);
update_base_port(previous_port);
return false;
}
// If host is "localhost", then set host to the empty string.
if (host == "localhost") {
host = "";
}
}
return true;
}
bool url::set_host(const std::string_view input) {
return set_host_or_hostname<false>(input);
}
bool url::set_hostname(const std::string_view input) {
return set_host_or_hostname<true>(input);
}
bool url::set_username(const std::string_view input) {
if (cannot_have_credentials_or_port()) {
return false;
}
username = ada::unicode::percent_encode(
input, character_sets::USERINFO_PERCENT_ENCODE);
return true;
}
bool url::set_password(const std::string_view input) {
if (cannot_have_credentials_or_port()) {
return false;
}
password = ada::unicode::percent_encode(
input, character_sets::USERINFO_PERCENT_ENCODE);
return true;
}
bool url::set_port(const std::string_view input) {
if (cannot_have_credentials_or_port()) {
return false;
}
std::string trimmed(input);
helpers::remove_ascii_tab_or_newline(trimmed);
if (trimmed.empty()) {
port = std::nullopt;
return true;
}
// Input should not start with a non-digit character.
if (!ada::unicode::is_ascii_digit(trimmed.front())) {
return false;
}
// Revert changes if parse_port fails.
std::optional<uint16_t> previous_port = port;
parse_port(trimmed);
if (is_valid) {
return true;
}
port = std::move(previous_port);
is_valid = true;
return false;
}
void url::set_hash(const std::string_view input) {
if (input.empty()) {
hash = std::nullopt;
helpers::strip_trailing_spaces_from_opaque_path(*this);
return;
}
std::string new_value;
new_value = input[0] == '#' ? input.substr(1) : input;
helpers::remove_ascii_tab_or_newline(new_value);
hash = unicode::percent_encode(new_value,
ada::character_sets::FRAGMENT_PERCENT_ENCODE);
}
void url::set_search(const std::string_view input) {
if (input.empty()) {
query = std::nullopt;
helpers::strip_trailing_spaces_from_opaque_path(*this);
return;
}
std::string new_value;
new_value = input[0] == '?' ? input.substr(1) : input;
helpers::remove_ascii_tab_or_newline(new_value);
auto query_percent_encode_set =
is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
: ada::character_sets::QUERY_PERCENT_ENCODE;
query = ada::unicode::percent_encode(new_value, query_percent_encode_set);
}
bool url::set_pathname(const std::string_view input) {
if (has_opaque_path) {
return false;
}
path.clear();
parse_path(input);
return true;
}
bool url::set_protocol(const std::string_view input) {
std::string view(input);
helpers::remove_ascii_tab_or_newline(view);
if (view.empty()) {
return true;
}
// Schemes should start with alpha values.
if (!checkers::is_alpha(view[0])) {
return false;
}
view.append(":");
std::string::iterator pointer =
std::ranges::find_if_not(view, unicode::is_alnum_plus);
if (pointer != view.end() && *pointer == ':') {
return parse_scheme<true>(
std::string_view(view.data(), pointer - view.begin()));
}
return false;
}
bool url::set_href(const std::string_view input) {
ada::result<ada::url> out = ada::parse<ada::url>(input);
if (out) {
*this = *out;
}
return out.has_value();
}
} // namespace ada
/* end file src/url.cpp */
/* begin file src/parser.cpp */
#include <limits>
namespace ada::parser {
template <class result_type, bool store_values>
result_type parse_url_impl(std::string_view user_input,
const result_type* base_url) {
// We can specialize the implementation per type.
// Important: result_type_is_ada_url is evaluated at *compile time*. This
// means that doing if constexpr(result_type_is_ada_url) { something } else {
// something else } is free (at runtime). This means that ada::url_aggregator
// and ada::url **do not have to support the exact same API**.
constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
constexpr bool result_type_is_ada_url_aggregator =
std::is_same_v<url_aggregator, result_type>;
static_assert(result_type_is_ada_url ||
result_type_is_ada_url_aggregator); // We don't support
// anything else for now.
ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
" bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
")");
state state = state::SCHEME_START;
result_type url{};
// We refuse to parse URL strings that exceed 4GB. Such strings are almost
// surely the result of a bug or are otherwise a security concern.
if (user_input.size() > std::numeric_limits<uint32_t>::max()) [[unlikely]] {
url.is_valid = false;
}
// Going forward, user_input.size() is in [0,
// std::numeric_limits<uint32_t>::max). If we are provided with an invalid
// base, or the optional_url was invalid, we must return.
if (base_url != nullptr) {
url.is_valid &= base_url->is_valid;
}
if (!url.is_valid) {
return url;
}
if constexpr (result_type_is_ada_url_aggregator && store_values) {
// Most of the time, we just need user_input.size().
// In some instances, we may need a bit more.
///////////////////////////
// This is *very* important. This line should *not* be removed
// hastily. There are principled reasons why reserve is important
// for performance. If you have a benchmark with small inputs,
// it may not matter, but in other instances, it could.
////
// This rounds up to the next power of two.
// We know that user_input.size() is in [0,
// std::numeric_limits<uint32_t>::max).
uint32_t reserve_capacity =
(0xFFFFFFFF >>
helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
1;
url.reserve(reserve_capacity);
}
std::string tmp_buffer;
std::string_view url_data;
if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
tmp_buffer = user_input;
// Optimization opportunity: Instead of copying and then pruning, we could
// just directly build the string from user_input.
helpers::remove_ascii_tab_or_newline(tmp_buffer);
url_data = tmp_buffer;
} else [[likely]] {
url_data = user_input;
}
// Leading and trailing control characters are uncommon and easy to deal with
// (no performance concern).
helpers::trim_c0_whitespace(url_data);
// Optimization opportunity. Most websites do not have fragment.
std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
// We add it last so that an implementation like ada::url_aggregator
// can append it last to its internal buffer, thus improving performance.
// Here url_data no longer has its fragment.
// We are going to access the data from url_data (it is immutable).
// At any given time, we are pointing at byte 'input_position' in url_data.
// The input_position variable should range from 0 to input_size.
// It is illegal to access url_data at input_size.
size_t input_position = 0;
const size_t input_size = url_data.size();
// Keep running the following state machine by switching on state.
// If after a run pointer points to the EOF code point, go to the next step.
// Otherwise, increase pointer by 1 and continue with the state machine.
// We never decrement input_position.
while (input_position <= input_size) {
ada_log("In parsing at ", input_position, " out of ", input_size,
" in state ", ada::to_string(state));
switch (state) {
case state::SCHEME_START: {
ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
// If c is an ASCII alpha, append c, lowercased, to buffer, and set
// state to scheme state.
if ((input_position != input_size) &&
checkers::is_alpha(url_data[input_position])) {
state = state::SCHEME;
input_position++;
} else {
// Otherwise, if state override is not given, set state to no scheme
// state and decrease pointer by 1.
state = state::NO_SCHEME;
}
break;
}
case state::SCHEME: {
ada_log("SCHEME ", helpers::substring(url_data, input_position));
// If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
// append c, lowercased, to buffer.
while ((input_position != input_size) &&
(unicode::is_alnum_plus(url_data[input_position]))) {
input_position++;
}
// Otherwise, if c is U+003A (:), then:
if ((input_position != input_size) &&
(url_data[input_position] == ':')) {
ada_log("SCHEME the scheme should be ",
url_data.substr(0, input_position));
if constexpr (result_type_is_ada_url) {
if (!url.parse_scheme(url_data.substr(0, input_position))) {
return url;
}
} else {
// we pass the colon along instead of painfully adding it back.
if (!url.parse_scheme_with_colon(
url_data.substr(0, input_position + 1))) {
return url;
}
}
ada_log("SCHEME the scheme is ", url.get_protocol());
// If url's scheme is "file", then:
if (url.type == scheme::type::FILE) {
// Set state to file state.
state = state::FILE;
}
// Otherwise, if url is special, base is non-null, and base's scheme
// is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
// != nullptr is false.
else if (url.is_special() && base_url != nullptr &&
base_url->type == url.type) {
// Set state to special relative or authority state.
state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
}
// Otherwise, if url is special, set state to special authority
// slashes state.
else if (url.is_special()) {
state = state::SPECIAL_AUTHORITY_SLASHES;
}
// Otherwise, if remaining starts with an U+002F (/), set state to
// path or authority state and increase pointer by 1.
else if (input_position + 1 < input_size &&
url_data[input_position + 1] == '/') {
state = state::PATH_OR_AUTHORITY;
input_position++;
}
// Otherwise, set url's path to the empty string and set state to
// opaque path state.
else {
state = state::OPAQUE_PATH;
}
}
// Otherwise, if state override is not given, set buffer to the empty
// string, state to no scheme state, and start over (from the first code
// point in input).
else {
state = state::NO_SCHEME;
input_position = 0;
break;
}
input_position++;
break;
}
case state::NO_SCHEME: {
ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
// If base is null, or base has an opaque path and c is not U+0023 (#),
// validation error, return failure.
if (base_url == nullptr ||
(base_url->has_opaque_path && !fragment.has_value())) {
ada_log("NO_SCHEME validation error");
url.is_valid = false;
return url;
}
// Otherwise, if base has an opaque path and c is U+0023 (#),
// set url's scheme to base's scheme, url's path to base's path, url's
// query to base's query, and set state to fragment state.
else if (base_url->has_opaque_path && fragment.has_value() &&
input_position == input_size) {
ada_log("NO_SCHEME opaque base with fragment");
url.copy_scheme(*base_url);
url.has_opaque_path = base_url->has_opaque_path;
if constexpr (result_type_is_ada_url) {
url.path = base_url->path;
url.query = base_url->query;
} else {
url.update_base_pathname(base_url->get_pathname());
url.update_base_search(base_url->get_search());
}
url.update_unencoded_base_hash(*fragment);
return url;
}
// Otherwise, if base's scheme is not "file", set state to relative
// state and decrease pointer by 1.
else if (base_url->type != scheme::type::FILE) {
ada_log("NO_SCHEME non-file relative path");
state = state::RELATIVE_SCHEME;
}
// Otherwise, set state to file state and decrease pointer by 1.
else {
ada_log("NO_SCHEME file base type");
state = state::FILE;
}
break;
}
case state::AUTHORITY: {
ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
// most URLs have no @. Having no @ tells us that we don't have to worry
// about AUTHORITY. Of course, we could have @ and still not have to
// worry about AUTHORITY.
// TODO: Instead of just collecting a bool, collect the location of the
// '@' and do something useful with it.
// TODO: We could do various processing early on, using a single pass
// over the string to collect information about it, e.g., telling us
// whether there is a @ and if so, where (or how many).
// Check if url data contains an @.
if (url_data.find('@', input_position) == std::string_view::npos) {
state = state::HOST;
break;
}
bool at_sign_seen{false};
bool password_token_seen{false};
/**
* We expect something of the sort...
* https://user:pass@example.com:1234/foo/bar?baz#quux
* --------^
*/
do {
std::string_view view = url_data.substr(input_position);
// The delimiters are @, /, ? \\.
size_t location =
url.is_special() ? helpers::find_authority_delimiter_special(view)
: helpers::find_authority_delimiter(view);
std::string_view authority_view = view.substr(0, location);
size_t end_of_authority = input_position + authority_view.size();
// If c is U+0040 (@), then:
if ((end_of_authority != input_size) &&
(url_data[end_of_authority] == '@')) {
// If atSignSeen is true, then prepend "%40" to buffer.
if (at_sign_seen) {
if (password_token_seen) {
if constexpr (result_type_is_ada_url) {
url.password += "%40";
} else {
url.append_base_password("%40");
}
} else {
if constexpr (result_type_is_ada_url) {
url.username += "%40";
} else {
url.append_base_username("%40");
}
}
}
at_sign_seen = true;
if (!password_token_seen) {
size_t password_token_location = authority_view.find(':');
password_token_seen =
password_token_location != std::string_view::npos;
if constexpr (store_values) {
if (!password_token_seen) {
if constexpr (result_type_is_ada_url) {
url.username += unicode::percent_encode(
authority_view,
character_sets::USERINFO_PERCENT_ENCODE);
} else {
url.append_base_username(unicode::percent_encode(
authority_view,
character_sets::USERINFO_PERCENT_ENCODE));
}
} else {
if constexpr (result_type_is_ada_url) {
url.username += unicode::percent_encode(
authority_view.substr(0, password_token_location),
character_sets::USERINFO_PERCENT_ENCODE);
url.password += unicode::percent_encode(
authority_view.substr(password_token_location + 1),
character_sets::USERINFO_PERCENT_ENCODE);
} else {
url.append_base_username(unicode::percent_encode(
authority_view.substr(0, password_token_location),
character_sets::USERINFO_PERCENT_ENCODE));
url.append_base_password(unicode::percent_encode(
authority_view.substr(password_token_location + 1),
character_sets::USERINFO_PERCENT_ENCODE));
}
}
}
} else if constexpr (store_values) {
if constexpr (result_type_is_ada_url) {
url.password += unicode::percent_encode(
authority_view, character_sets::USERINFO_PERCENT_ENCODE);
} else {
url.append_base_password(unicode::percent_encode(
authority_view, character_sets::USERINFO_PERCENT_ENCODE));
}
}
}
// Otherwise, if one of the following is true:
// - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
// - url is special and c is U+005C (\)
else if (end_of_authority == input_size ||
url_data[end_of_authority] == '/' ||
url_data[end_of_authority] == '?' ||
(url.is_special() && url_data[end_of_authority] == '\\')) {
// If atSignSeen is true and authority_view is the empty string,
// validation error, return failure.
if (at_sign_seen && authority_view.empty()) {
url.is_valid = false;
return url;
}
state = state::HOST;
break;
}
if (end_of_authority == input_size) {
if constexpr (store_values) {
if (fragment.has_value()) {
url.update_unencoded_base_hash(*fragment);
}
}
return url;
}
input_position = end_of_authority + 1;
} while (true);
break;
}
case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
helpers::substring(url_data, input_position));
// If c is U+002F (/) and remaining starts with U+002F (/),
// then set state to special authority ignore slashes state and increase
// pointer by 1.
if (url_data.substr(input_position, 2) == "//") {
state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
input_position += 2;
} else {
// Otherwise, validation error, set state to relative state and
// decrease pointer by 1.
state = state::RELATIVE_SCHEME;
}
break;
}
case state::PATH_OR_AUTHORITY: {
ada_log("PATH_OR_AUTHORITY ",
helpers::substring(url_data, input_position));
// If c is U+002F (/), then set state to authority state.
if ((input_position != input_size) &&
(url_data[input_position] == '/')) {
state = state::AUTHORITY;
input_position++;
} else {
// Otherwise, set state to path state, and decrease pointer by 1.
state = state::PATH;
}
break;
}
case state::RELATIVE_SCHEME: {
ada_log("RELATIVE_SCHEME ",
helpers::substring(url_data, input_position));
// Set url's scheme to base's scheme.
url.copy_scheme(*base_url);
// If c is U+002F (/), then set state to relative slash state.
if ((input_position != input_size) &&
(url_data[input_position] == '/')) {
ada_log(
"RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
"slash state");
state = state::RELATIVE_SLASH;
} else if (url.is_special() && (input_position != input_size) &&
(url_data[input_position] == '\\')) {
// Otherwise, if url is special and c is U+005C (\), validation error,
// set state to relative slash state.
ada_log(
"RELATIVE_SCHEME if url is special and c is U+005C, validation "
"error, set state to relative slash state");
state = state::RELATIVE_SLASH;
} else {
ada_log("RELATIVE_SCHEME otherwise");
// Set url's username to base's username, url's password to base's
// password, url's host to base's host, url's port to base's port,
// url's path to a clone of base's path, and url's query to base's
// query.
if constexpr (result_type_is_ada_url) {
url.username = base_url->username;
url.password = base_url->password;
url.host = base_url->host;
url.port = base_url->port;
// cloning the base path includes cloning the has_opaque_path flag
url.has_opaque_path = base_url->has_opaque_path;
url.path = base_url->path;
url.query = base_url->query;
} else {
url.update_base_authority(base_url->get_href(),
base_url->get_components());
url.update_host_to_base_host(base_url->get_hostname());
url.update_base_port(base_url->retrieve_base_port());
// cloning the base path includes cloning the has_opaque_path flag
url.has_opaque_path = base_url->has_opaque_path;
url.update_base_pathname(base_url->get_pathname());
url.update_base_search(base_url->get_search());
}
url.has_opaque_path = base_url->has_opaque_path;
// If c is U+003F (?), then set url's query to the empty string, and
// state to query state.
if ((input_position != input_size) &&
(url_data[input_position] == '?')) {
state = state::QUERY;
}
// Otherwise, if c is not the EOF code point:
else if (input_position != input_size) {
// Set url's query to null.
url.clear_search();
if constexpr (result_type_is_ada_url) {
// Shorten url's path.
helpers::shorten_path(url.path, url.type);
} else {
std::string_view path = url.get_pathname();
if (helpers::shorten_path(path, url.type)) {
url.update_base_pathname(std::move(std::string(path)));
}
}
// Set state to path state and decrease pointer by 1.
state = state::PATH;
break;
}
}
input_position++;
break;
}
case state::RELATIVE_SLASH: {
ada_log("RELATIVE_SLASH ",
helpers::substring(url_data, input_position));
// If url is special and c is U+002F (/) or U+005C (\), then:
if (url.is_special() && (input_position != input_size) &&
(url_data[input_position] == '/' ||
url_data[input_position] == '\\')) {
// Set state to special authority ignore slashes state.
state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
}
// Otherwise, if c is U+002F (/), then set state to authority state.
else if ((input_position != input_size) &&
(url_data[input_position] == '/')) {
state = state::AUTHORITY;
}
// Otherwise, set
// - url's username to base's username,
// - url's password to base's password,
// - url's host to base's host,
// - url's port to base's port,
// - state to path state, and then, decrease pointer by 1.
else {
if constexpr (result_type_is_ada_url) {
url.username = base_url->username;
url.password = base_url->password;
url.host = base_url->host;
url.port = base_url->port;
} else {
url.update_base_authority(base_url->get_href(),
base_url->get_components());
url.update_host_to_base_host(base_url->get_hostname());
url.update_base_port(base_url->retrieve_base_port());
}
state = state::PATH;
break;
}
input_position++;
break;
}
case state::SPECIAL_AUTHORITY_SLASHES: {
ada_log("SPECIAL_AUTHORITY_SLASHES ",
helpers::substring(url_data, input_position));
// If c is U+002F (/) and remaining starts with U+002F (/),
// then set state to special authority ignore slashes state and increase
// pointer by 1.
if (url_data.substr(input_position, 2) == "//") {
input_position += 2;
}
[[fallthrough]];
}
case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
helpers::substring(url_data, input_position));
// If c is neither U+002F (/) nor U+005C (\), then set state to
// authority state and decrease pointer by 1.
while ((input_position != input_size) &&
((url_data[input_position] == '/') ||
(url_data[input_position] == '\\'))) {
input_position++;
}
state = state::AUTHORITY;
break;
}
case state::QUERY: {
ada_log("QUERY ", helpers::substring(url_data, input_position));
if constexpr (store_values) {
// Let queryPercentEncodeSet be the special-query percent-encode set
// if url is special; otherwise the query percent-encode set.
const uint8_t* query_percent_encode_set =
url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
: character_sets::QUERY_PERCENT_ENCODE;
// Percent-encode after encoding, with encoding, buffer, and
// queryPercentEncodeSet, and append the result to url's query.
url.update_base_search(url_data.substr(input_position),
query_percent_encode_set);
ada_log("QUERY update_base_search completed ");
if (fragment.has_value()) {
url.update_unencoded_base_hash(*fragment);
}
}
return url;
}
case state::HOST: {
ada_log("HOST ", helpers::substring(url_data, input_position));
std::string_view host_view = url_data.substr(input_position);
auto [location, found_colon] =
helpers::get_host_delimiter_location(url.is_special(), host_view);
input_position = (location != std::string_view::npos)
? input_position + location
: input_size;
// Otherwise, if c is U+003A (:) and insideBrackets is false, then:
// Note: the 'found_colon' value is true if and only if a colon was
// encountered while not inside brackets.
if (found_colon) {
// If buffer is the empty string, validation error, return failure.
// Let host be the result of host parsing buffer with url is not
// special.
ada_log("HOST parsing ", host_view);
if (!url.parse_host(host_view)) {
return url;
}
ada_log("HOST parsing results in ", url.get_hostname());
// Set url's host to host, buffer to the empty string, and state to
// port state.
state = state::PORT;
input_position++;
}
// Otherwise, if one of the following is true:
// - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
// - url is special and c is U+005C (\)
// The get_host_delimiter_location function either brings us to
// the colon outside of the bracket, or to one of those characters.
else {
// If url is special and host_view is the empty string, validation
// error, return failure.
if (host_view.empty() && url.is_special()) {
url.is_valid = false;
return url;
}
ada_log("HOST parsing ", host_view, " href=", url.get_href());
// Let host be the result of host parsing host_view with url is not
// special.
if (host_view.empty()) {
url.update_base_hostname("");
} else if (!url.parse_host(host_view)) {
return url;
}
ada_log("HOST parsing results in ", url.get_hostname(),
" href=", url.get_href());
// Set url's host to host, and state to path start state.
state = state::PATH_START;
}
break;
}
case state::OPAQUE_PATH: {
ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
std::string_view view = url_data.substr(input_position);
// If c is U+003F (?), then set url's query to the empty string and
// state to query state.
size_t location = view.find('?');
if (location != std::string_view::npos) {
view.remove_suffix(view.size() - location);
state = state::QUERY;
input_position += location + 1;
} else {
input_position = input_size + 1;
}
url.has_opaque_path = true;
// This is a really unlikely scenario in real world. We should not seek
// to optimize it.
if (view.ends_with(' ')) {
std::string modified_view =
std::string(view.begin(), view.end() - 1) + "%20";
url.update_base_pathname(unicode::percent_encode(
modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
} else {
url.update_base_pathname(unicode::percent_encode(
view, character_sets::C0_CONTROL_PERCENT_ENCODE));
}
break;
}
case state::PORT: {
ada_log("PORT ", helpers::substring(url_data, input_position));
std::string_view port_view = url_data.substr(input_position);
input_position += url.parse_port(port_view, true);
if (!url.is_valid) {
return url;
}
state = state::PATH_START;
[[fallthrough]];
}
case state::PATH_START: {
ada_log("PATH_START ", helpers::substring(url_data, input_position));
// If url is special, then:
if (url.is_special()) {
// Set state to path state.
state = state::PATH;
// Optimization: Avoiding going into PATH state improves the
// performance of urls ending with /.
if (input_position == input_size) {
if constexpr (store_values) {
url.update_base_pathname("/");
if (fragment.has_value()) {
url.update_unencoded_base_hash(*fragment);
}
}
return url;
}
// If c is neither U+002F (/) nor U+005C (\), then decrease pointer
// by 1. We know that (input_position == input_size) is impossible
// here, because of the previous if-check.
if ((url_data[input_position] != '/') &&
(url_data[input_position] != '\\')) {
break;
}
}
// Otherwise, if state override is not given and c is U+003F (?),
// set url's query to the empty string and state to query state.
else if ((input_position != input_size) &&
(url_data[input_position] == '?')) {
state = state::QUERY;
}
// Otherwise, if c is not the EOF code point:
else if (input_position != input_size) {
// Set state to path state.
state = state::PATH;
// If c is not U+002F (/), then decrease pointer by 1.
if (url_data[input_position] != '/') {
break;
}
}
input_position++;
break;
}
case state::PATH: {
ada_log("PATH ", helpers::substring(url_data, input_position));
std::string_view view = url_data.substr(input_position);
// Most time, we do not need percent encoding.
// Furthermore, we can immediately locate the '?'.
size_t locofquestionmark = view.find('?');
if (locofquestionmark != std::string_view::npos) {
state = state::QUERY;
view.remove_suffix(view.size() - locofquestionmark);
input_position += locofquestionmark + 1;
} else {
input_position = input_size + 1;
}
if constexpr (store_values) {
if constexpr (result_type_is_ada_url) {
helpers::parse_prepared_path(view, url.type, url.path);
} else {
url.consume_prepared_path(view);
ADA_ASSERT_TRUE(url.validate());
}
}
break;
}
case state::FILE_SLASH: {
ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
// If c is U+002F (/) or U+005C (\), then:
if ((input_position != input_size) &&
(url_data[input_position] == '/' ||
url_data[input_position] == '\\')) {
ada_log("FILE_SLASH c is U+002F or U+005C");
// Set state to file host state.
state = state::FILE_HOST;
input_position++;
} else {
ada_log("FILE_SLASH otherwise");
// If base is non-null and base's scheme is "file", then:
// Note: it is unsafe to do base_url->scheme unless you know that
// base_url_has_value() is true.
if (base_url != nullptr && base_url->type == scheme::type::FILE) {
// Set url's host to base's host.
if constexpr (result_type_is_ada_url) {
url.host = base_url->host;
} else {
url.update_host_to_base_host(base_url->get_host());
}
// If the code point substring from pointer to the end of input does
// not start with a Windows drive letter and base's path[0] is a
// normalized Windows drive letter, then append base's path[0] to
// url's path.
if (!base_url->get_pathname().empty()) {
if (!checkers::is_windows_drive_letter(
url_data.substr(input_position))) {
std::string_view first_base_url_path =
base_url->get_pathname().substr(1);
size_t loc = first_base_url_path.find('/');
if (loc != std::string_view::npos) {
helpers::resize(first_base_url_path, loc);
}
if (checkers::is_normalized_windows_drive_letter(
first_base_url_path)) {
if constexpr (result_type_is_ada_url) {
url.path += '/';
url.path += first_base_url_path;
} else {
url.append_base_pathname(
helpers::concat("/", first_base_url_path));
}
}
}
}
}
// Set state to path state, and decrease pointer by 1.
state = state::PATH;
}
break;
}
case state::FILE_HOST: {
ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
std::string_view view = url_data.substr(input_position);
size_t location = view.find_first_of("/\\?");
std::string_view file_host_buffer(
view.data(),
(location != std::string_view::npos) ? location : view.size());
if (checkers::is_windows_drive_letter(file_host_buffer)) {
state = state::PATH;
} else if (file_host_buffer.empty()) {
// Set url's host to the empty string.
if constexpr (result_type_is_ada_url) {
url.host = "";
} else {
url.update_base_hostname("");
}
// Set state to path start state.
state = state::PATH_START;
} else {
size_t consumed_bytes = file_host_buffer.size();
input_position += consumed_bytes;
// Let host be the result of host parsing buffer with url is not
// special.
if (!url.parse_host(file_host_buffer)) {
return url;
}
if constexpr (result_type_is_ada_url) {
// If host is "localhost", then set host to the empty string.
if (url.host.has_value() && url.host.value() == "localhost") {
url.host = "";
}
} else {
if (url.get_hostname() == "localhost") {
url.update_base_hostname("");
}
}
// Set buffer to the empty string and state to path start state.
state = state::PATH_START;
}
break;
}
case state::FILE: {
ada_log("FILE ", helpers::substring(url_data, input_position));
std::string_view file_view = url_data.substr(input_position);
url.set_protocol_as_file();
if constexpr (result_type_is_ada_url) {
// Set url's host to the empty string.
url.host = "";
} else {
url.update_base_hostname("");
}
// If c is U+002F (/) or U+005C (\), then:
if (input_position != input_size &&
(url_data[input_position] == '/' ||
url_data[input_position] == '\\')) {
ada_log("FILE c is U+002F or U+005C");
// Set state to file slash state.
state = state::FILE_SLASH;
}
// Otherwise, if base is non-null and base's scheme is "file":
else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
// Set url's host to base's host, url's path to a clone of base's
// path, and url's query to base's query.
ada_log("FILE base non-null");
if constexpr (result_type_is_ada_url) {
url.host = base_url->host;
url.path = base_url->path;
url.query = base_url->query;
} else {
url.update_host_to_base_host(base_url->get_hostname());
url.update_base_pathname(base_url->get_pathname());
url.update_base_search(base_url->get_search());
}
url.has_opaque_path = base_url->has_opaque_path;
// If c is U+003F (?), then set url's query to the empty string and
// state to query state.
if (input_position != input_size && url_data[input_position] == '?') {
state = state::QUERY;
}
// Otherwise, if c is not the EOF code point:
else if (input_position != input_size) {
// Set url's query to null.
url.clear_search();
// If the code point substring from pointer to the end of input does
// not start with a Windows drive letter, then shorten url's path.
if (!checkers::is_windows_drive_letter(file_view)) {
if constexpr (result_type_is_ada_url) {
helpers::shorten_path(url.path, url.type);
} else {
std::string_view path = url.get_pathname();
if (helpers::shorten_path(path, url.type)) {
url.update_base_pathname(std::move(std::string(path)));
}
}
}
// Otherwise:
else {
// Set url's path to an empty list.
url.clear_pathname();
url.has_opaque_path = true;
}
// Set state to path state and decrease pointer by 1.
state = state::PATH;
break;
}
}
// Otherwise, set state to path state, and decrease pointer by 1.
else {
ada_log("FILE go to path");
state = state::PATH;
break;
}
input_position++;
break;
}
default:
unreachable();
}
}
if constexpr (store_values) {
if (fragment.has_value()) {
url.update_unencoded_base_hash(*fragment);
}
}
return url;
}
template url parse_url_impl(std::string_view user_input,
const url* base_url = nullptr);
template url_aggregator parse_url_impl(
std::string_view user_input, const url_aggregator* base_url = nullptr);
template <class result_type>
result_type parse_url(std::string_view user_input,
const result_type* base_url) {
return parse_url_impl<result_type, true>(user_input, base_url);
}
template url parse_url<url>(std::string_view user_input,
const url* base_url = nullptr);
template url_aggregator parse_url<url_aggregator>(
std::string_view user_input, const url_aggregator* base_url = nullptr);
} // namespace ada::parser
/* end file src/parser.cpp */
/* begin file src/url_components.cpp */
#include <string>
namespace ada {
[[nodiscard]] std::string url_components::to_string() const {
std::string answer;
auto back = std::back_insert_iterator(answer);
answer.append("{\n");
answer.append("\t\"protocol_end\":\"");
helpers::encode_json(std::to_string(protocol_end), back);
answer.append("\",\n");
answer.append("\t\"username_end\":\"");
helpers::encode_json(std::to_string(username_end), back);
answer.append("\",\n");
answer.append("\t\"host_start\":\"");
helpers::encode_json(std::to_string(host_start), back);
answer.append("\",\n");
answer.append("\t\"host_end\":\"");
helpers::encode_json(std::to_string(host_end), back);
answer.append("\",\n");
answer.append("\t\"port\":\"");
helpers::encode_json(std::to_string(port), back);
answer.append("\",\n");
answer.append("\t\"pathname_start\":\"");
helpers::encode_json(std::to_string(pathname_start), back);
answer.append("\",\n");
answer.append("\t\"search_start\":\"");
helpers::encode_json(std::to_string(search_start), back);
answer.append("\",\n");
answer.append("\t\"hash_start\":\"");
helpers::encode_json(std::to_string(hash_start), back);
answer.append("\",\n");
answer.append("\n}");
return answer;
}
} // namespace ada
/* end file src/url_components.cpp */
/* begin file src/url_aggregator.cpp */
#include <string>
#include <string_view>
namespace ada {
template <bool has_state_override>
[[nodiscard]] ada_really_inline bool url_aggregator::parse_scheme_with_colon(
const std::string_view input_with_colon) {
ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
std::string_view input{input_with_colon};
input.remove_suffix(1);
auto parsed_type = ada::scheme::get_scheme_type(input);
const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
/**
* In the common case, we will immediately recognize a special scheme (e.g.,
*http, https), in which case, we can go really fast.
**/
if (is_input_special) { // fast path!!!
if constexpr (has_state_override) {
// If url's scheme is not a special scheme and buffer is a special scheme,
// then return.
if (is_special() != is_input_special) {
return false;
}
// If url includes credentials or has a non-null port, and buffer is
// "file", then return.
if ((has_credentials() || components.port != url_components::omitted) &&
parsed_type == ada::scheme::type::FILE) {
return false;
}
// If url's scheme is "file" and its host is an empty host, then return.
// An empty host is the empty string.
if (type == ada::scheme::type::FILE &&
components.host_start == components.host_end) {
return false;
}
}
type = parsed_type;
set_scheme_from_view_with_colon(input_with_colon);
if constexpr (has_state_override) {
// This is uncommon.
uint16_t urls_scheme_port = get_special_port();
// If url's port is url's scheme's default port, then set url's port to
// null.
if (components.port == urls_scheme_port) {
clear_port();
}
}
} else { // slow path
std::string _buffer(input);
// Next function is only valid if the input is ASCII and returns false
// otherwise, but it seems that we always have ascii content so we do not
// need to check the return value.
unicode::to_lower_ascii(_buffer.data(), _buffer.size());
if constexpr (has_state_override) {
// If url's scheme is a special scheme and buffer is not a special scheme,
// then return. If url's scheme is not a special scheme and buffer is a
// special scheme, then return.
if (is_special() != ada::scheme::is_special(_buffer)) {
return true;
}
// If url includes credentials or has a non-null port, and buffer is
// "file", then return.
if ((has_credentials() || components.port != url_components::omitted) &&
_buffer == "file") {
return true;
}
// If url's scheme is "file" and its host is an empty host, then return.
// An empty host is the empty string.
if (type == ada::scheme::type::FILE &&
components.host_start == components.host_end) {
return true;
}
}
set_scheme(_buffer);
if constexpr (has_state_override) {
// This is uncommon.
uint16_t urls_scheme_port = get_special_port();
// If url's port is url's scheme's default port, then set url's port to
// null.
if (components.port == urls_scheme_port) {
clear_port();
}
}
}
ADA_ASSERT_TRUE(validate());
return true;
}
inline void url_aggregator::copy_scheme(const url_aggregator& u) noexcept {
ada_log("url_aggregator::copy_scheme ", u.buffer);
ADA_ASSERT_TRUE(validate());
// next line could overflow but unsigned arithmetic has well-defined
// overflows.
uint32_t new_difference = u.components.protocol_end - components.protocol_end;
type = u.type;
buffer.erase(0, components.protocol_end);
buffer.insert(0, u.get_protocol());
components.protocol_end = u.components.protocol_end;
// No need to update the components
if (new_difference == 0) {
return;
}
// Update the rest of the components.
components.username_end += new_difference;
components.host_start += new_difference;
components.host_end += new_difference;
components.pathname_start += new_difference;
if (components.search_start != url_components::omitted) {
components.search_start += new_difference;
}
if (components.hash_start != url_components::omitted) {
components.hash_start += new_difference;
}
ADA_ASSERT_TRUE(validate());
}
inline void url_aggregator::set_scheme_from_view_with_colon(
std::string_view new_scheme_with_colon) noexcept {
ada_log("url_aggregator::set_scheme_from_view_with_colon ",
new_scheme_with_colon);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
new_scheme_with_colon.back() == ':');
// next line could overflow but unsigned arithmetic has well-defined
// overflows.
uint32_t new_difference =
uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
if (buffer.empty()) {
buffer.append(new_scheme_with_colon);
} else {
buffer.erase(0, components.protocol_end);
buffer.insert(0, new_scheme_with_colon);
}
components.protocol_end += new_difference;
// Update the rest of the components.
components.username_end += new_difference;
components.host_start += new_difference;
components.host_end += new_difference;
components.pathname_start += new_difference;
if (components.search_start != url_components::omitted) {
components.search_start += new_difference;
}
if (components.hash_start != url_components::omitted) {
components.hash_start += new_difference;
}
ADA_ASSERT_TRUE(validate());
}
inline void url_aggregator::set_scheme(std::string_view new_scheme) noexcept {
ada_log("url_aggregator::set_scheme ", new_scheme);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':');
// next line could overflow but unsigned arithmetic has well-defined
// overflows.
uint32_t new_difference =
uint32_t(new_scheme.size()) - components.protocol_end + 1;
type = ada::scheme::get_scheme_type(new_scheme);
if (buffer.empty()) {
buffer.append(helpers::concat(new_scheme, ":"));
} else {
buffer.erase(0, components.protocol_end);
buffer.insert(0, helpers::concat(new_scheme, ":"));
}
components.protocol_end = uint32_t(new_scheme.size() + 1);
// Update the rest of the components.
components.username_end += new_difference;
components.host_start += new_difference;
components.host_end += new_difference;
components.pathname_start += new_difference;
if (components.search_start != url_components::omitted) {
components.search_start += new_difference;
}
if (components.hash_start != url_components::omitted) {
components.hash_start += new_difference;
}
ADA_ASSERT_TRUE(validate());
}
bool url_aggregator::set_protocol(const std::string_view input) {
ada_log("url_aggregator::set_protocol ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
std::string view(input);
helpers::remove_ascii_tab_or_newline(view);
if (view.empty()) {
return true;
}
// Schemes should start with alpha values.
if (!checkers::is_alpha(view[0])) {
return false;
}
view.append(":");
std::string::iterator pointer =
std::ranges::find_if_not(view, unicode::is_alnum_plus);
if (pointer != view.end() && *pointer == ':') {
return parse_scheme_with_colon<true>(
std::string_view(view.data(), pointer - view.begin() + 1));
}
return false;
}
bool url_aggregator::set_username(const std::string_view input) {
ada_log("url_aggregator::set_username '", input, "' ");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (cannot_have_credentials_or_port()) {
return false;
}
size_t idx = ada::unicode::percent_encode_index(
input, character_sets::USERINFO_PERCENT_ENCODE);
if (idx == input.size()) {
update_base_username(input);
} else {
// We only create a temporary string if we have to!
update_base_username(ada::unicode::percent_encode(
input, character_sets::USERINFO_PERCENT_ENCODE, idx));
}
ADA_ASSERT_TRUE(validate());
return true;
}
bool url_aggregator::set_password(const std::string_view input) {
ada_log("url_aggregator::set_password '", input, "'");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (cannot_have_credentials_or_port()) {
return false;
}
size_t idx = ada::unicode::percent_encode_index(
input, character_sets::USERINFO_PERCENT_ENCODE);
if (idx == input.size()) {
update_base_password(input);
} else {
// We only create a temporary string if we have to!
update_base_password(ada::unicode::percent_encode(
input, character_sets::USERINFO_PERCENT_ENCODE, idx));
}
ADA_ASSERT_TRUE(validate());
return true;
}
bool url_aggregator::set_port(const std::string_view input) {
ada_log("url_aggregator::set_port ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (cannot_have_credentials_or_port()) {
return false;
}
std::string trimmed(input);
helpers::remove_ascii_tab_or_newline(trimmed);
if (trimmed.empty()) {
clear_port();
return true;
}
// Input should not start with a non-digit character.
if (!ada::unicode::is_ascii_digit(trimmed.front())) {
return false;
}
// Revert changes if parse_port fails.
uint32_t previous_port = components.port;
parse_port(trimmed);
if (is_valid) {
return true;
}
update_base_port(previous_port);
is_valid = true;
ADA_ASSERT_TRUE(validate());
return false;
}
bool url_aggregator::set_pathname(const std::string_view input) {
ada_log("url_aggregator::set_pathname ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (has_opaque_path) {
return false;
}
clear_pathname();
parse_path(input);
if (get_pathname().starts_with("//") && !has_authority() && !has_dash_dot()) {
buffer.insert(components.pathname_start, "/.");
components.pathname_start += 2;
}
ADA_ASSERT_TRUE(validate());
return true;
}
ada_really_inline void url_aggregator::parse_path(std::string_view input) {
ada_log("url_aggregator::parse_path ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
std::string tmp_buffer;
std::string_view internal_input;
if (unicode::has_tabs_or_newline(input)) {
tmp_buffer = input;
// Optimization opportunity: Instead of copying and then pruning, we could
// just directly build the string from user_input.
helpers::remove_ascii_tab_or_newline(tmp_buffer);
internal_input = tmp_buffer;
} else {
internal_input = input;
}
// If url is special, then:
if (is_special()) {
if (internal_input.empty()) {
update_base_pathname("/");
} else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
consume_prepared_path(internal_input.substr(1));
} else {
consume_prepared_path(internal_input);
}
} else if (!internal_input.empty()) {
if (internal_input[0] == '/') {
consume_prepared_path(internal_input.substr(1));
} else {
consume_prepared_path(internal_input);
}
} else {
// Non-special URLs with an empty host can have their paths erased
// Path-only URLs cannot have their paths erased
if (components.host_start == components.host_end && !has_authority()) {
update_base_pathname("/");
}
}
ADA_ASSERT_TRUE(validate());
}
void url_aggregator::set_search(const std::string_view input) {
ada_log("url_aggregator::set_search ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (input.empty()) {
clear_search();
helpers::strip_trailing_spaces_from_opaque_path(*this);
return;
}
std::string new_value;
new_value = input[0] == '?' ? input.substr(1) : input;
helpers::remove_ascii_tab_or_newline(new_value);
auto query_percent_encode_set =
is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
: ada::character_sets::QUERY_PERCENT_ENCODE;
update_base_search(new_value, query_percent_encode_set);
ADA_ASSERT_TRUE(validate());
}
void url_aggregator::set_hash(const std::string_view input) {
ada_log("url_aggregator::set_hash ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (input.empty()) {
if (components.hash_start != url_components::omitted) {
buffer.resize(components.hash_start);
components.hash_start = url_components::omitted;
}
helpers::strip_trailing_spaces_from_opaque_path(*this);
return;
}
std::string new_value;
new_value = input[0] == '#' ? input.substr(1) : input;
helpers::remove_ascii_tab_or_newline(new_value);
update_unencoded_base_hash(new_value);
ADA_ASSERT_TRUE(validate());
}
bool url_aggregator::set_href(const std::string_view input) {
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]");
ada::result<url_aggregator> out = ada::parse<url_aggregator>(input);
ada_log("url_aggregator::set_href, success :", out.has_value());
if (out) {
ada_log("url_aggregator::set_href, parsed ", out->to_string());
// TODO: Figure out why the following line puts test to never finish.
*this = *out;
}
return out.has_value();
}
ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(),
" bytes]");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (input.empty()) {
return is_valid = false;
} // technically unnecessary.
// If input starts with U+005B ([), then:
if (input[0] == '[') {
// If input does not end with U+005D (]), validation error, return failure.
if (input.back() != ']') {
return is_valid = false;
}
ada_log("parse_host ipv6");
// Return the result of IPv6 parsing input with its leading U+005B ([) and
// trailing U+005D (]) removed.
input.remove_prefix(1);
input.remove_suffix(1);
return parse_ipv6(input);
}
// If isNotSpecial is true, then return the result of opaque-host parsing
// input.
if (!is_special()) {
return parse_opaque_host(input);
}
// Let domain be the result of running UTF-8 decode without BOM on the
// percent-decoding of input. Let asciiDomain be the result of running domain
// to ASCII with domain and false. The most common case is an ASCII input, in
// which case we do not need to call the expensive 'to_ascii' if a few
// conditions are met: no '%' and no 'xn-' subsequence.
// Often, the input does not contain any forbidden code points, and no upper
// case ASCII letter, then we can just copy it to the buffer. We want to
// optimize for such a common case.
uint8_t is_forbidden_or_upper =
unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
input.size());
// Minor optimization opportunity:
// contains_forbidden_domain_code_point_or_upper could be extend to check for
// the presence of characters that cannot appear in the ipv4 address and we
// could also check whether x and n and - are present, and so we could skip
// some of the checks below. However, the gains are likely to be small, and
// the code would be more complex.
if (is_forbidden_or_upper == 0 &&
input.find("xn-") == std::string_view::npos) {
// fast path
update_base_hostname(input);
if (checkers::is_ipv4(get_hostname())) {
ada_log("parse_host fast path ipv4");
return parse_ipv4(get_hostname(), true);
}
ada_log("parse_host fast path ", get_hostname());
return true;
}
// We have encountered at least one forbidden code point or the input contains
// 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
// conversion.
ada_log("parse_host calling to_ascii");
std::optional<std::string> host = std::string(get_hostname());
is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
if (!is_valid) {
ada_log("parse_host to_ascii returns false");
return is_valid = false;
}
ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
" bytes]");
if (std::any_of(host.value().begin(), host.value().end(),
ada::unicode::is_forbidden_domain_code_point)) {
return is_valid = false;
}
// If asciiDomain ends in a number, then return the result of IPv4 parsing
// asciiDomain.
if (checkers::is_ipv4(host.value())) {
ada_log("parse_host got ipv4 ", *host);
return parse_ipv4(host.value(), false);
}
update_base_hostname(host.value());
ADA_ASSERT_TRUE(validate());
return true;
}
template <bool override_hostname>
bool url_aggregator::set_host_or_hostname(const std::string_view input) {
ada_log("url_aggregator::set_host_or_hostname ", input);
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (has_opaque_path) {
return false;
}
std::string previous_host(get_hostname());
uint32_t previous_port = components.port;
size_t host_end_pos = input.find('#');
std::string _host(input.data(), host_end_pos != std::string_view::npos
? host_end_pos
: input.size());
helpers::remove_ascii_tab_or_newline(_host);
std::string_view new_host(_host);
// If url's scheme is "file", then set state to file host state, instead of
// host state.
if (type != ada::scheme::type::FILE) {
std::string_view host_view(_host.data(), _host.length());
auto [location, found_colon] =
helpers::get_host_delimiter_location(is_special(), host_view);
// Otherwise, if c is U+003A (:) and insideBrackets is false, then:
// Note: the 'found_colon' value is true if and only if a colon was
// encountered while not inside brackets.
if (found_colon) {
if constexpr (override_hostname) {
return false;
}
std::string_view sub_buffer = new_host.substr(location + 1);
if (!sub_buffer.empty()) {
set_port(sub_buffer);
}
}
// If url is special and host_view is the empty string, validation error,
// return failure. Otherwise, if state override is given, host_view is the
// empty string, and either url includes credentials or url's port is
// non-null, return.
else if (host_view.empty() &&
(is_special() || has_credentials() || has_port())) {
return false;
}
// Let host be the result of host parsing host_view with url is not special.
if (host_view.empty() && !is_special()) {
if (has_hostname()) {
clear_hostname(); // easy!
} else if (has_dash_dot()) {
add_authority_slashes_if_needed();
delete_dash_dot();
}
return true;
}
bool succeeded = parse_host(host_view);
if (!succeeded) {
update_base_hostname(previous_host);
update_base_port(previous_port);
} else if (has_dash_dot()) {
// Should remove dash_dot from pathname
delete_dash_dot();
}
return succeeded;
}
size_t location = new_host.find_first_of("/\\?");
if (location != std::string_view::npos) {
new_host.remove_suffix(new_host.length() - location);
}
if (new_host.empty()) {
// Set url's host to the empty string.
clear_hostname();
} else {
// Let host be the result of host parsing buffer with url is not special.
if (!parse_host(new_host)) {
update_base_hostname(previous_host);
update_base_port(previous_port);
return false;
}
// If host is "localhost", then set host to the empty string.
if (helpers::substring(buffer, components.host_start,
components.host_end) == "localhost") {
clear_hostname();
}
}
ADA_ASSERT_TRUE(validate());
return true;
}
bool url_aggregator::set_host(const std::string_view input) {
ada_log("url_aggregator::set_host '", input, "'");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
return set_host_or_hostname<false>(input);
}
bool url_aggregator::set_hostname(const std::string_view input) {
ada_log("url_aggregator::set_hostname '", input, "'");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
return set_host_or_hostname<true>(input);
}
[[nodiscard]] std::string url_aggregator::get_origin() const noexcept {
ada_log("url_aggregator::get_origin");
if (is_special()) {
// Return a new opaque origin.
if (type == scheme::FILE) {
return "null";
}
return helpers::concat(get_protocol(), "//", get_host());
}
if (get_protocol() == "blob:") {
std::string_view path = get_pathname();
if (!path.empty()) {
auto out = ada::parse<ada::url_aggregator>(path);
if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) {
// If pathURL's scheme is not "http" and not "https", then return a
// new opaque origin.
return helpers::concat(out->get_protocol(), "//", out->get_host());
}
}
}
// Return a new opaque origin.
return "null";
}
[[nodiscard]] std::string_view url_aggregator::get_username() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_username");
if (has_non_empty_username()) {
return helpers::substring(buffer, components.protocol_end + 2,
components.username_end);
}
return "";
}
[[nodiscard]] std::string_view url_aggregator::get_password() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_password");
if (has_non_empty_password()) {
return helpers::substring(buffer, components.username_end + 1,
components.host_start);
}
return "";
}
[[nodiscard]] std::string_view url_aggregator::get_port() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_port");
if (components.port == url_components::omitted) {
return "";
}
return helpers::substring(buffer, components.host_end + 1,
components.pathname_start);
}
[[nodiscard]] std::string_view url_aggregator::get_hash() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_hash");
// If this's URL's fragment is either null or the empty string, then return
// the empty string. Return U+0023 (#), followed by this's URL's fragment.
if (components.hash_start == url_components::omitted) {
return "";
}
if (buffer.size() - components.hash_start <= 1) {
return "";
}
return helpers::substring(buffer, components.hash_start);
}
[[nodiscard]] std::string_view url_aggregator::get_host() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_host");
// Technically, we should check if there is a hostname, but
// the code below works even if there isn't.
// if(!has_hostname()) { return ""; }
size_t start = components.host_start;
if (components.host_end > components.host_start &&
buffer[components.host_start] == '@') {
start++;
}
// if we have an empty host, then the space between components.host_end and
// components.pathname_start may be occupied by /.
if (start == components.host_end) {
return {};
}
return helpers::substring(buffer, start, components.pathname_start);
}
[[nodiscard]] std::string_view url_aggregator::get_hostname() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_hostname");
// Technically, we should check if there is a hostname, but
// the code below works even if there isn't.
// if(!has_hostname()) { return ""; }
size_t start = components.host_start;
// So host_start is not where the host begins.
if (components.host_end > components.host_start &&
buffer[components.host_start] == '@') {
start++;
}
return helpers::substring(buffer, start, components.host_end);
}
[[nodiscard]] std::string_view url_aggregator::get_search() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_search");
// If this's URL's query is either null or the empty string, then return the
// empty string. Return U+003F (?), followed by this's URL's query.
if (components.search_start == url_components::omitted) {
return "";
}
auto ending_index = uint32_t(buffer.size());
if (components.hash_start != url_components::omitted) {
ending_index = components.hash_start;
}
if (ending_index - components.search_start <= 1) {
return "";
}
return helpers::substring(buffer, components.search_start, ending_index);
}
[[nodiscard]] std::string_view url_aggregator::get_protocol() const noexcept
ada_lifetime_bound {
ada_log("url_aggregator::get_protocol");
return helpers::substring(buffer, 0, components.protocol_end);
}
[[nodiscard]] std::string ada::url_aggregator::to_string() const {
ada_log("url_aggregator::to_string buffer:", buffer, " [", buffer.size(),
" bytes]");
if (!is_valid) {
return "null";
}
std::string answer;
auto back = std::back_insert_iterator(answer);
answer.append("{\n");
answer.append("\t\"buffer\":\"");
helpers::encode_json(buffer, back);
answer.append("\",\n");
answer.append("\t\"protocol\":\"");
helpers::encode_json(get_protocol(), back);
answer.append("\",\n");
if (has_credentials()) {
answer.append("\t\"username\":\"");
helpers::encode_json(get_username(), back);
answer.append("\",\n");
answer.append("\t\"password\":\"");
helpers::encode_json(get_password(), back);
answer.append("\",\n");
}
answer.append("\t\"host\":\"");
helpers::encode_json(get_host(), back);
answer.append("\",\n");
answer.append("\t\"path\":\"");
helpers::encode_json(get_pathname(), back);
answer.append("\",\n");
answer.append("\t\"opaque path\":");
answer.append((has_opaque_path ? "true" : "false"));
answer.append(",\n");
if (components.search_start != url_components::omitted) {
answer.append("\t\"query\":\"");
helpers::encode_json(get_search(), back);
answer.append("\",\n");
}
if (components.hash_start != url_components::omitted) {
answer.append("\t\"fragment\":\"");
helpers::encode_json(get_hash(), back);
answer.append("\",\n");
}
auto convert_offset_to_string = [](uint32_t offset) -> std::string {
if (offset == url_components::omitted) {
return "null";
} else {
return std::to_string(offset);
}
};
answer.append("\t\"protocol_end\":");
answer.append(convert_offset_to_string(components.protocol_end));
answer.append(",\n");
answer.append("\t\"username_end\":");
answer.append(convert_offset_to_string(components.username_end));
answer.append(",\n");
answer.append("\t\"host_start\":");
answer.append(convert_offset_to_string(components.host_start));
answer.append(",\n");
answer.append("\t\"host_end\":");
answer.append(convert_offset_to_string(components.host_end));
answer.append(",\n");
answer.append("\t\"port\":");
answer.append(convert_offset_to_string(components.port));
answer.append(",\n");
answer.append("\t\"pathname_start\":");
answer.append(convert_offset_to_string(components.pathname_start));
answer.append(",\n");
answer.append("\t\"search_start\":");
answer.append(convert_offset_to_string(components.search_start));
answer.append(",\n");
answer.append("\t\"hash_start\":");
answer.append(convert_offset_to_string(components.hash_start));
answer.append("\n}");
return answer;
}
[[nodiscard]] bool url_aggregator::has_valid_domain() const noexcept {
if (components.host_start == components.host_end) {
return false;
}
return checkers::verify_dns_length(get_hostname());
}
bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) {
ada_log("parse_ipv4 ", input, " [", input.size(),
" bytes], overlaps with buffer: ",
helpers::overlaps(input, buffer) ? "yes" : "no");
ADA_ASSERT_TRUE(validate());
const bool trailing_dot = (input.back() == '.');
if (trailing_dot) {
input.remove_suffix(1);
}
size_t digit_count{0};
int pure_decimal_count = 0; // entries that are decimal
uint64_t ipv4{0};
// we could unroll for better performance?
for (; (digit_count < 4) && !(input.empty()); digit_count++) {
uint32_t
segment_result{}; // If any number exceeds 32 bits, we have an error.
bool is_hex = checkers::has_hex_prefix(input);
if (is_hex && ((input.length() == 2) ||
((input.length() > 2) && (input[2] == '.')))) {
// special case
segment_result = 0;
input.remove_prefix(2);
} else {
std::from_chars_result r{};
if (is_hex) {
ada_log("parse_ipv4 trying to parse hex number");
r = std::from_chars(input.data() + 2, input.data() + input.size(),
segment_result, 16);
} else if ((input.length() >= 2) && input[0] == '0' &&
checkers::is_digit(input[1])) {
ada_log("parse_ipv4 trying to parse octal number");
r = std::from_chars(input.data() + 1, input.data() + input.size(),
segment_result, 8);
} else {
ada_log("parse_ipv4 trying to parse decimal number");
pure_decimal_count++;
r = std::from_chars(input.data(), input.data() + input.size(),
segment_result, 10);
}
if (r.ec != std::errc()) {
ada_log("parse_ipv4 parsing failed");
return is_valid = false;
}
ada_log("parse_ipv4 parsed ", segment_result);
input.remove_prefix(r.ptr - input.data());
}
if (input.empty()) {
// We have the last value.
// At this stage, ipv4 contains digit_count*8 bits.
// So we have 32-digit_count*8 bits left.
if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) {
return is_valid = false;
}
ipv4 <<= (32 - digit_count * 8);
ipv4 |= segment_result;
goto final;
} else {
// There is more, so that the value must no be larger than 255
// and we must have a '.'.
if ((segment_result > 255) || (input[0] != '.')) {
return is_valid = false;
}
ipv4 <<= 8;
ipv4 |= segment_result;
input.remove_prefix(1); // remove '.'
}
}
if ((digit_count != 4) || (!input.empty())) {
ada_log("parse_ipv4 found invalid (more than 4 numbers or empty) ");
return is_valid = false;
}
final:
ada_log("url_aggregator::parse_ipv4 completed ", get_href(),
" host: ", get_host());
// We could also check r.ptr to see where the parsing ended.
if (in_place && pure_decimal_count == 4 && !trailing_dot) {
ada_log(
"url_aggregator::parse_ipv4 completed and was already correct in the "
"buffer");
// The original input was already all decimal and we validated it. So we
// don't need to do anything.
} else {
ada_log("url_aggregator::parse_ipv4 completed and we need to update it");
// Optimization opportunity: Get rid of unnecessary string return in ipv4
// serializer.
// TODO: This is likely a bug because it goes back update_base_hostname, not
// what we want to do.
update_base_hostname(
ada::serializers::ipv4(ipv4)); // We have to reserialize the address.
}
host_type = IPV4;
ADA_ASSERT_TRUE(validate());
return true;
}
bool url_aggregator::parse_ipv6(std::string_view input) {
// TODO: Implement in_place optimization: we know that input points
// in the buffer, so we can just check whether the buffer is already
// well formatted.
// TODO: Find a way to merge parse_ipv6 with url.cpp implementation.
ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (input.empty()) {
return is_valid = false;
}
// Let address be a new IPv6 address whose IPv6 pieces are all 0.
std::array<uint16_t, 8> address{};
// Let pieceIndex be 0.
int piece_index = 0;
// Let compress be null.
std::optional<int> compress{};
// Let pointer be a pointer for input.
std::string_view::iterator pointer = input.begin();
// If c is U+003A (:), then:
if (input[0] == ':') {
// If remaining does not start with U+003A (:), validation error, return
// failure.
if (input.size() == 1 || input[1] != ':') {
ada_log("parse_ipv6 starts with : but the rest does not start with :");
return is_valid = false;
}
// Increase pointer by 2.
pointer += 2;
// Increase pieceIndex by 1 and then set compress to pieceIndex.
compress = ++piece_index;
}
// While c is not the EOF code point:
while (pointer != input.end()) {
// If pieceIndex is 8, validation error, return failure.
if (piece_index == 8) {
ada_log("parse_ipv6 piece_index == 8");
return is_valid = false;
}
// If c is U+003A (:), then:
if (*pointer == ':') {
// If compress is non-null, validation error, return failure.
if (compress.has_value()) {
ada_log("parse_ipv6 compress is non-null");
return is_valid = false;
}
// Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
// then continue.
pointer++;
compress = ++piece_index;
continue;
}
// Let value and length be 0.
uint16_t value = 0, length = 0;
// While length is less than 4 and c is an ASCII hex digit,
// set value to value times 0x10 + c interpreted as hexadecimal number, and
// increase pointer and length by 1.
while (length < 4 && pointer != input.end() &&
unicode::is_ascii_hex_digit(*pointer)) {
// https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
pointer++;
length++;
}
// If c is U+002E (.), then:
if (pointer != input.end() && *pointer == '.') {
// If length is 0, validation error, return failure.
if (length == 0) {
ada_log("parse_ipv6 length is 0");
return is_valid = false;
}
// Decrease pointer by length.
pointer -= length;
// If pieceIndex is greater than 6, validation error, return failure.
if (piece_index > 6) {
ada_log("parse_ipv6 piece_index > 6");
return is_valid = false;
}
// Let numbersSeen be 0.
int numbers_seen = 0;
// While c is not the EOF code point:
while (pointer != input.end()) {
// Let ipv4Piece be null.
std::optional<uint16_t> ipv4_piece{};
// If numbersSeen is greater than 0, then:
if (numbers_seen > 0) {
// If c is a U+002E (.) and numbersSeen is less than 4, then increase
// pointer by 1.
if (*pointer == '.' && numbers_seen < 4) {
pointer++;
} else {
// Otherwise, validation error, return failure.
ada_log("parse_ipv6 Otherwise, validation error, return failure");
return is_valid = false;
}
}
// If c is not an ASCII digit, validation error, return failure.
if (pointer == input.end() || !checkers::is_digit(*pointer)) {
ada_log(
"parse_ipv6 If c is not an ASCII digit, validation error, return "
"failure");
return is_valid = false;
}
// While c is an ASCII digit:
while (pointer != input.end() && checkers::is_digit(*pointer)) {
// Let number be c interpreted as decimal number.
int number = *pointer - '0';
// If ipv4Piece is null, then set ipv4Piece to number.
if (!ipv4_piece.has_value()) {
ipv4_piece = number;
}
// Otherwise, if ipv4Piece is 0, validation error, return failure.
else if (ipv4_piece == 0) {
ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
return is_valid = false;
}
// Otherwise, set ipv4Piece to ipv4Piece times 10 + number.
else {
ipv4_piece = *ipv4_piece * 10 + number;
}
// If ipv4Piece is greater than 255, validation error, return failure.
if (ipv4_piece > 255) {
ada_log("parse_ipv6 ipv4_piece > 255");
return is_valid = false;
}
// Increase pointer by 1.
pointer++;
}
// Set address[pieceIndex] to address[pieceIndex] times 0x100 +
// ipv4Piece.
// https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
address[piece_index] =
uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
// Increase numbersSeen by 1.
numbers_seen++;
// If numbersSeen is 2 or 4, then increase pieceIndex by 1.
if (numbers_seen == 2 || numbers_seen == 4) {
piece_index++;
}
}
// If numbersSeen is not 4, validation error, return failure.
if (numbers_seen != 4) {
return is_valid = false;
}
// Break.
break;
}
// Otherwise, if c is U+003A (:):
else if ((pointer != input.end()) && (*pointer == ':')) {
// Increase pointer by 1.
pointer++;
// If c is the EOF code point, validation error, return failure.
if (pointer == input.end()) {
ada_log(
"parse_ipv6 If c is the EOF code point, validation error, return "
"failure");
return is_valid = false;
}
}
// Otherwise, if c is not the EOF code point, validation error, return
// failure.
else if (pointer != input.end()) {
ada_log(
"parse_ipv6 Otherwise, if c is not the EOF code point, validation "
"error, return failure");
return is_valid = false;
}
// Set address[pieceIndex] to value.
address[piece_index] = value;
// Increase pieceIndex by 1.
piece_index++;
}
// If compress is non-null, then:
if (compress.has_value()) {
// Let swaps be pieceIndex - compress.
int swaps = piece_index - *compress;
// Set pieceIndex to 7.
piece_index = 7;
// While pieceIndex is not 0 and swaps is greater than 0,
// swap address[pieceIndex] with address[compress + swaps - 1], and then
// decrease both pieceIndex and swaps by 1.
while (piece_index != 0 && swaps > 0) {
std::swap(address[piece_index], address[*compress + swaps - 1]);
piece_index--;
swaps--;
}
}
// Otherwise, if compress is null and pieceIndex is not 8, validation error,
// return failure.
else if (piece_index != 8) {
ada_log(
"parse_ipv6 if compress is null and pieceIndex is not 8, validation "
"error, return failure");
return is_valid = false;
}
// TODO: Optimization opportunity: Get rid of unnecessary string creation.
// TODO: This is likely a bug because it goes back update_base_hostname, not
// what we want to do.
update_base_hostname(ada::serializers::ipv6(address));
ada_log("parse_ipv6 ", get_hostname());
ADA_ASSERT_TRUE(validate());
host_type = IPV6;
return true;
}
bool url_aggregator::parse_opaque_host(std::string_view input) {
ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
if (std::any_of(input.begin(), input.end(),
ada::unicode::is_forbidden_host_code_point)) {
return is_valid = false;
}
// Return the result of running UTF-8 percent-encode on input using the C0
// control percent-encode set.
size_t idx = ada::unicode::percent_encode_index(
input, character_sets::C0_CONTROL_PERCENT_ENCODE);
if (idx == input.size()) {
update_base_hostname(input);
} else {
// We only create a temporary string if we need to.
update_base_hostname(ada::unicode::percent_encode(
input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx));
}
ADA_ASSERT_TRUE(validate());
return true;
}
[[nodiscard]] std::string url_aggregator::to_diagram() const {
if (!is_valid) {
return "invalid";
}
std::string answer;
answer.append(buffer);
answer.append(" [");
answer.append(std::to_string(buffer.size()));
answer.append(" bytes]");
answer.append("\n");
// first line
std::string line1;
line1.resize(buffer.size(), ' ');
if (components.hash_start != url_components::omitted) {
line1[components.hash_start] = '|';
}
if (components.search_start != url_components::omitted) {
line1[components.search_start] = '|';
}
if (components.pathname_start != buffer.size()) {
line1[components.pathname_start] = '|';
}
if (components.host_end != buffer.size()) {
line1[components.host_end] = '|';
}
if (components.host_start != buffer.size()) {
line1[components.host_start] = '|';
}
if (components.username_end != buffer.size()) {
line1[components.username_end] = '|';
}
if (components.protocol_end != buffer.size()) {
line1[components.protocol_end] = '|';
}
answer.append(line1);
answer.append("\n");
std::string line2 = line1;
if (components.hash_start != url_components::omitted) {
line2[components.hash_start] = '`';
line1[components.hash_start] = ' ';
for (size_t i = components.hash_start + 1; i < line2.size(); i++) {
line2[i] = '-';
}
line2.append(" hash_start");
answer.append(line2);
answer.append("\n");
}
std::string line3 = line1;
if (components.search_start != url_components::omitted) {
line3[components.search_start] = '`';
line1[components.search_start] = ' ';
for (size_t i = components.search_start + 1; i < line3.size(); i++) {
line3[i] = '-';
}
line3.append(" search_start ");
line3.append(std::to_string(components.search_start));
answer.append(line3);
answer.append("\n");
}
std::string line4 = line1;
if (components.pathname_start != buffer.size()) {
line4[components.pathname_start] = '`';
line1[components.pathname_start] = ' ';
for (size_t i = components.pathname_start + 1; i < line4.size(); i++) {
line4[i] = '-';
}
line4.append(" pathname_start ");
line4.append(std::to_string(components.pathname_start));
answer.append(line4);
answer.append("\n");
}
std::string line5 = line1;
if (components.host_end != buffer.size()) {
line5[components.host_end] = '`';
line1[components.host_end] = ' ';
for (size_t i = components.host_end + 1; i < line5.size(); i++) {
line5[i] = '-';
}
line5.append(" host_end ");
line5.append(std::to_string(components.host_end));
answer.append(line5);
answer.append("\n");
}
std::string line6 = line1;
if (components.host_start != buffer.size()) {
line6[components.host_start] = '`';
line1[components.host_start] = ' ';
for (size_t i = components.host_start + 1; i < line6.size(); i++) {
line6[i] = '-';
}
line6.append(" host_start ");
line6.append(std::to_string(components.host_start));
answer.append(line6);
answer.append("\n");
}
std::string line7 = line1;
if (components.username_end != buffer.size()) {
line7[components.username_end] = '`';
line1[components.username_end] = ' ';
for (size_t i = components.username_end + 1; i < line7.size(); i++) {
line7[i] = '-';
}
line7.append(" username_end ");
line7.append(std::to_string(components.username_end));
answer.append(line7);
answer.append("\n");
}
std::string line8 = line1;
if (components.protocol_end != buffer.size()) {
line8[components.protocol_end] = '`';
line1[components.protocol_end] = ' ';
for (size_t i = components.protocol_end + 1; i < line8.size(); i++) {
line8[i] = '-';
}
line8.append(" protocol_end ");
line8.append(std::to_string(components.protocol_end));
answer.append(line8);
answer.append("\n");
}
if (components.hash_start == url_components::omitted) {
answer.append("note: hash omitted\n");
}
if (components.search_start == url_components::omitted) {
answer.append("note: search omitted\n");
}
if (components.protocol_end > buffer.size()) {
answer.append("warning: protocol_end overflows\n");
}
if (components.username_end > buffer.size()) {
answer.append("warning: username_end overflows\n");
}
if (components.host_start > buffer.size()) {
answer.append("warning: host_start overflows\n");
}
if (components.host_end > buffer.size()) {
answer.append("warning: host_end overflows\n");
}
if (components.pathname_start > buffer.size()) {
answer.append("warning: pathname_start overflows\n");
}
return answer;
}
void url_aggregator::delete_dash_dot() {
ada_log("url_aggregator::delete_dash_dot");
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(has_dash_dot());
buffer.erase(components.host_end, 2);
components.pathname_start -= 2;
if (components.search_start != url_components::omitted) {
components.search_start -= 2;
}
if (components.hash_start != url_components::omitted) {
components.hash_start -= 2;
}
ADA_ASSERT_TRUE(validate());
ADA_ASSERT_TRUE(!has_dash_dot());
}
inline void url_aggregator::consume_prepared_path(std::string_view input) {
ada_log("url_aggregator::consume_prepared_path ", input);
/***
* This is largely duplicated code from helpers::parse_prepared_path, which is
* unfortunate. This particular function is nearly identical, except that it
* is a method on url_aggregator. The idea is that the trivial path (which is
* very common) merely appends to the buffer. This is the same trivial path as
* with helpers::parse_prepared_path, except that we have the additional check
* for is_at_path(). Otherwise, we grab a copy of the current path and we
* modify it, and then insert it back into the buffer.
*/
uint8_t accumulator = checkers::path_signature(input);
// Let us first detect a trivial case.
// If it is special, we check that we have no dot, no %, no \ and no
// character needing percent encoding. Otherwise, we check that we have no %,
// no dot, and no character needing percent encoding.
constexpr uint8_t need_encoding = 1;
constexpr uint8_t backslash_char = 2;
constexpr uint8_t dot_char = 4;
constexpr uint8_t percent_char = 8;
bool special = type != ada::scheme::NOT_SPECIAL;
bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
checkers::is_windows_drive_letter(input));
bool trivial_path =
(special ? (accumulator == 0)
: ((accumulator & (need_encoding | dot_char | percent_char)) ==
0)) &&
(!may_need_slow_file_handling);
if (accumulator == dot_char && !may_need_slow_file_handling) {
// '4' means that we have at least one dot, but nothing that requires
// percent encoding or decoding. The only part that is not trivial is
// that we may have single dots and double dots path segments.
// If we have such segments, then we either have a path that begins
// with '.' (easy to check), or we have the sequence './'.
// Note: input cannot be empty, it must at least contain one character ('.')
// Note: we know that '\' is not present.
if (input[0] != '.') {
size_t slashdot = input.find("/.");
if (slashdot == std::string_view::npos) { // common case
trivial_path = true;
} else { // uncommon
// only three cases matter: /./, /.. or a final /
trivial_path =
!(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
input[slashdot + 2] == '/');
}
}
}
if (trivial_path && is_at_path()) {
ada_log("parse_path trivial");
buffer += '/';
buffer += input;
return;
}
std::string path = std::string(get_pathname());
// We are going to need to look a bit at the path, but let us see if we can
// ignore percent encoding *and* backslashes *and* percent characters.
// Except for the trivial case, this is likely to capture 99% of paths out
// there.
bool fast_path =
(special &&
(accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
(type != ada::scheme::type::FILE);
if (fast_path) {
ada_log("parse_prepared_path fast");
// Here we don't need to worry about \ or percent encoding.
// We also do not have a file protocol. We might have dots, however,
// but dots must as appear as '.', and they cannot be encoded because
// the symbol '%' is not present.
size_t previous_location = 0; // We start at 0.
do {
size_t new_location = input.find('/', previous_location);
// std::string_view path_view = input;
// We process the last segment separately:
if (new_location == std::string_view::npos) {
std::string_view path_view = input.substr(previous_location);
if (path_view == "..") { // The path ends with ..
// e.g., if you receive ".." with an empty path, you go to "/".
if (path.empty()) {
path = '/';
update_base_pathname(path);
return;
}
// Fast case where we have nothing to do:
if (path.back() == '/') {
update_base_pathname(path);
return;
}
// If you have the path "/joe/myfriend",
// then you delete 'myfriend'.
path.resize(path.rfind('/') + 1);
update_base_pathname(path);
return;
}
path += '/';
if (path_view != ".") {
path.append(path_view);
}
update_base_pathname(path);
return;
} else {
// This is a non-final segment.
std::string_view path_view =
input.substr(previous_location, new_location - previous_location);
previous_location = new_location + 1;
if (path_view == "..") {
size_t last_delimiter = path.rfind('/');
if (last_delimiter != std::string::npos) {
path.erase(last_delimiter);
}
} else if (path_view != ".") {
path += '/';
path.append(path_view);
}
}
} while (true);
} else {
ada_log("parse_path slow");
// we have reached the general case
bool needs_percent_encoding = (accumulator & 1);
std::string path_buffer_tmp;
do {
size_t location = (special && (accumulator & 2))
? input.find_first_of("/\\")
: input.find('/');
std::string_view path_view = input;
if (location != std::string_view::npos) {
path_view.remove_suffix(path_view.size() - location);
input.remove_prefix(location + 1);
}
// path_buffer is either path_view or it might point at a percent encoded
// temporary string.
std::string_view path_buffer =
(needs_percent_encoding &&
ada::unicode::percent_encode<false>(
path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
? path_buffer_tmp
: path_view;
if (unicode::is_double_dot_path_segment(path_buffer)) {
if ((helpers::shorten_path(path, type) || special) &&
location == std::string_view::npos) {
path += '/';
}
} else if (unicode::is_single_dot_path_segment(path_buffer) &&
(location == std::string_view::npos)) {
path += '/';
}
// Otherwise, if path_buffer is not a single-dot path segment, then:
else if (!unicode::is_single_dot_path_segment(path_buffer)) {
// If url's scheme is "file", url's path is empty, and path_buffer is a
// Windows drive letter, then replace the second code point in
// path_buffer with U+003A (:).
if (type == ada::scheme::type::FILE && path.empty() &&
checkers::is_windows_drive_letter(path_buffer)) {
path += '/';
path += path_buffer[0];
path += ':';
path_buffer.remove_prefix(2);
path.append(path_buffer);
} else {
// Append path_buffer to url's path.
path += '/';
path.append(path_buffer);
}
}
if (location == std::string_view::npos) {
update_base_pathname(path);
return;
}
} while (true);
}
}
} // namespace ada
/* end file src/url_aggregator.cpp */
#if ADA_INCLUDE_URL_PATTERN
/* begin file src/url_pattern.cpp */
#if ADA_INCLUDE_URL_PATTERN
#include <algorithm>
#include <optional>
#include <string>
namespace ada {
tl::expected<url_pattern_init, errors> url_pattern_init::process(
const url_pattern_init& init, url_pattern_init::process_type type,
std::optional<std::string_view> protocol,
std::optional<std::string_view> username,
std::optional<std::string_view> password,
std::optional<std::string_view> hostname,
std::optional<std::string_view> port,
std::optional<std::string_view> pathname,
std::optional<std::string_view> search,
std::optional<std::string_view> hash) {
// Let result be the result of creating a new URLPatternInit.
auto result = url_pattern_init{};
// If protocol is not null, set result["protocol"] to protocol.
if (protocol.has_value()) result.protocol = *protocol;
// If username is not null, set result["username"] to username.
if (username.has_value()) result.username = *username;
// If password is not null, set result["password"] to password.
if (password.has_value()) result.password = *password;
// If hostname is not null, set result["hostname"] to hostname.
if (hostname.has_value()) result.hostname = *hostname;
// If port is not null, set result["port"] to port.
if (port.has_value()) result.port = *port;
// If pathname is not null, set result["pathname"] to pathname.
if (pathname.has_value()) result.pathname = *pathname;
// If search is not null, set result["search"] to search.
if (search.has_value()) result.search = *search;
// If hash is not null, set result["hash"] to hash.
if (hash.has_value()) result.hash = *hash;
// Let baseURL be null.
std::optional<url_aggregator> base_url{};
// If init["baseURL"] exists:
if (init.base_url.has_value()) {
// Set baseURL to the result of parsing init["baseURL"].
auto parsing_result = ada::parse<url_aggregator>(*init.base_url);
// If baseURL is failure, then throw a TypeError.
if (!parsing_result) {
return tl::unexpected(errors::type_error);
}
base_url = std::move(*parsing_result);
// If init["protocol"] does not exist, then set result["protocol"] to the
// result of processing a base URL string given baseURL's scheme and type.
if (!init.protocol.has_value()) {
ADA_ASSERT_TRUE(base_url.has_value());
std::string_view base_url_protocol = base_url->get_protocol();
if (base_url_protocol.ends_with(":")) base_url_protocol.remove_suffix(1);
result.protocol =
url_pattern_helpers::process_base_url_string(base_url_protocol, type);
}
// If type is not "pattern" and init contains none of "protocol",
// "hostname", "port" and "username", then set result["username"] to the
// result of processing a base URL string given baseURL's username and type.
if (type != process_type::pattern && !init.protocol && !init.hostname &&
!init.port && !init.username) {
result.username = url_pattern_helpers::process_base_url_string(
base_url->get_username(), type);
}
// TODO: Optimization opportunity: Merge this with the previous check.
// If type is not "pattern" and init contains none of "protocol",
// "hostname", "port", "username" and "password", then set
// result["password"] to the result of processing a base URL string given
// baseURL's password and type.
if (type != process_type::pattern && !init.protocol && !init.hostname &&
!init.port && !init.username && !init.password) {
result.password = url_pattern_helpers::process_base_url_string(
base_url->get_password(), type);
}
// If init contains neither "protocol" nor "hostname", then:
if (!init.protocol && !init.hostname) {
// Let baseHost be baseURL's host.
// If baseHost is null, then set baseHost to the empty string.
auto base_host = base_url->get_hostname();
// Set result["hostname"] to the result of processing a base URL string
// given baseHost and type.
result.hostname =
url_pattern_helpers::process_base_url_string(base_host, type);
}
// If init contains none of "protocol", "hostname", and "port", then:
if (!init.protocol && !init.hostname && !init.port) {
// If baseURL's port is null, then set result["port"] to the empty string.
// Otherwise, set result["port"] to baseURL's port, serialized.
result.port = base_url->get_port();
}
// If init contains none of "protocol", "hostname", "port", and "pathname",
// then set result["pathname"] to the result of processing a base URL string
// given the result of URL path serializing baseURL and type.
if (!init.protocol && !init.hostname && !init.port && !init.pathname) {
result.pathname = url_pattern_helpers::process_base_url_string(
base_url->get_pathname(), type);
}
// If init contains none of "protocol", "hostname", "port", "pathname", and
// "search", then:
if (!init.protocol && !init.hostname && !init.port && !init.pathname &&
!init.search) {
// Let baseQuery be baseURL's query.
// Set result["search"] to the result of processing a base URL string
// given baseQuery and type.
result.search = url_pattern_helpers::process_base_url_string(
base_url->get_search(), type);
}
// If init contains none of "protocol", "hostname", "port", "pathname",
// "search", and "hash", then:
if (!init.protocol && !init.hostname && !init.port && !init.pathname &&
!init.search && !init.hash) {
// Let baseFragment be baseURL's fragment.
// Set result["hash"] to the result of processing a base URL string given
// baseFragment and type.
result.hash = url_pattern_helpers::process_base_url_string(
base_url->get_hash(), type);
}
}
// If init["protocol"] exists, then set result["protocol"] to the result of
// process protocol for init given init["protocol"] and type.
if (init.protocol) {
auto process_result = process_protocol(*init.protocol, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.protocol = std::move(*process_result);
}
// If init["username"] exists, then set result["username"] to the result of
// process username for init given init["username"] and type.
if (init.username.has_value()) {
auto process_result = process_username(*init.username, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.username = std::move(*process_result);
}
// If init["password"] exists, then set result["password"] to the result of
// process password for init given init["password"] and type.
if (init.password.has_value()) {
auto process_result = process_password(*init.password, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.password = std::move(*process_result);
}
// If init["hostname"] exists, then set result["hostname"] to the result of
// process hostname for init given init["hostname"] and type.
if (init.hostname.has_value()) {
auto process_result = process_hostname(*init.hostname, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.hostname = std::move(*process_result);
}
// If init["port"] exists, then set result["port"] to the result of process
// port for init given init["port"], result["protocol"], and type.
if (init.port) {
auto process_result =
process_port(*init.port, result.protocol.value_or("fake"), type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.port = std::move(*process_result);
}
// If init["pathname"] exists:
if (init.pathname.has_value()) {
// Set result["pathname"] to init["pathname"].
result.pathname = init.pathname;
// If the following are all true:
// - baseURL is not null;
// - baseURL has an opaque path; and
// - the result of running is an absolute pathname given result["pathname"]
// and type is false,
if (base_url && !base_url->has_opaque_path &&
!url_pattern_helpers::is_absolute_pathname(*result.pathname, type)) {
// Let baseURLPath be the result of running process a base URL string
// given the result of URL path serializing baseURL and type.
// TODO: Optimization opportunity: Avoid returning a string if no slash
// exist.
std::string base_url_path = url_pattern_helpers::process_base_url_string(
base_url->get_pathname(), type);
// Let slash index be the index of the last U+002F (/) code point found in
// baseURLPath, interpreted as a sequence of code points, or null if there
// are no instances of the code point.
auto slash_index = base_url_path.find_last_of('/');
// If slash index is not null:
if (slash_index != std::string::npos) {
// Let new pathname be the code point substring from 0 to slash index +
// 1 within baseURLPath.
base_url_path.resize(slash_index + 1);
// Append result["pathname"] to the end of new pathname.
ADA_ASSERT_TRUE(result.pathname.has_value());
base_url_path.append(std::move(*result.pathname));
// Set result["pathname"] to new pathname.
result.pathname = std::move(base_url_path);
}
}
// Set result["pathname"] to the result of process pathname for init given
// result["pathname"], result["protocol"], and type.
auto pathname_processing_result =
process_pathname(*result.pathname, result.protocol.value_or(""), type);
if (!pathname_processing_result) {
return tl::unexpected(pathname_processing_result.error());
}
result.pathname = std::move(*pathname_processing_result);
}
// If init["search"] exists then set result["search"] to the result of process
// search for init given init["search"] and type.
if (init.search) {
auto process_result = process_search(*init.search, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.search = std::move(*process_result);
}
// If init["hash"] exists then set result["hash"] to the result of process
// hash for init given init["hash"] and type.
if (init.hash) {
auto process_result = process_hash(*init.hash, type);
if (!process_result) {
return tl::unexpected(process_result.error());
}
result.hash = std::move(*process_result);
}
// Return result.
return result;
}
tl::expected<std::string, errors> url_pattern_init::process_protocol(
std::string_view value, process_type type) {
ada_log("process_protocol=", value, " [", type, "]");
// Let strippedValue be the given value with a single trailing U+003A (:)
// removed, if any.
if (value.ends_with(":")) {
value.remove_suffix(1);
}
// If type is "pattern" then return strippedValue.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a protocol given strippedValue.
return url_pattern_helpers::canonicalize_protocol(value);
}
tl::expected<std::string, errors> url_pattern_init::process_username(
std::string_view value, process_type type) {
// If type is "pattern" then return value.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a username given value.
return url_pattern_helpers::canonicalize_username(value);
}
tl::expected<std::string, errors> url_pattern_init::process_password(
std::string_view value, process_type type) {
// If type is "pattern" then return value.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a password given value.
return url_pattern_helpers::canonicalize_password(value);
}
tl::expected<std::string, errors> url_pattern_init::process_hostname(
std::string_view value, process_type type) {
ada_log("process_hostname value=", value, " type=", type);
// If type is "pattern" then return value.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a hostname given value.
return url_pattern_helpers::canonicalize_hostname(value);
}
tl::expected<std::string, errors> url_pattern_init::process_port(
std::string_view port, std::string_view protocol, process_type type) {
// If type is "pattern" then return portValue.
if (type == process_type::pattern) {
return std::string(port);
}
// Return the result of running canonicalize a port given portValue and
// protocolValue.
return url_pattern_helpers::canonicalize_port_with_protocol(port, protocol);
}
tl::expected<std::string, errors> url_pattern_init::process_pathname(
std::string_view value, std::string_view protocol, process_type type) {
// If type is "pattern" then return pathnameValue.
if (type == process_type::pattern) {
return std::string(value);
}
// If protocolValue is a special scheme or the empty string, then return the
// result of running canonicalize a pathname given pathnameValue.
if (protocol.empty() || scheme::is_special(protocol)) {
return url_pattern_helpers::canonicalize_pathname(value);
}
// Return the result of running canonicalize an opaque pathname given
// pathnameValue.
return url_pattern_helpers::canonicalize_opaque_pathname(value);
}
tl::expected<std::string, errors> url_pattern_init::process_search(
std::string_view value, process_type type) {
// Let strippedValue be the given value with a single leading U+003F (?)
// removed, if any.
if (value.starts_with("?")) {
value.remove_prefix(1);
}
ADA_ASSERT_TRUE(!value.starts_with("?"));
// If type is "pattern" then return strippedValue.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a search given strippedValue.
return url_pattern_helpers::canonicalize_search(value);
}
tl::expected<std::string, errors> url_pattern_init::process_hash(
std::string_view value, process_type type) {
// Let strippedValue be the given value with a single leading U+0023 (#)
// removed, if any.
if (value.starts_with("#")) {
value.remove_prefix(1);
}
ADA_ASSERT_TRUE(!value.starts_with("#"));
// If type is "pattern" then return strippedValue.
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a hash given strippedValue.
return url_pattern_helpers::canonicalize_hash(value);
}
} // namespace ada
#endif // ADA_INCLUDE_URL_PATTERN
/* end file src/url_pattern.cpp */
/* begin file src/url_pattern_helpers.cpp */
#if ADA_INCLUDE_URL_PATTERN
#include <algorithm>
#include <optional>
#include <string>
namespace ada::url_pattern_helpers {
std::tuple<std::string, std::vector<std::string>>
generate_regular_expression_and_name_list(
const std::vector<url_pattern_part>& part_list,
url_pattern_compile_component_options options) {
// Let result be "^"
std::string result = "^";
// Let name list be a new list
std::vector<std::string> name_list{};
// For each part of part list:
for (const url_pattern_part& part : part_list) {
// If part's type is "fixed-text":
if (part.type == url_pattern_part_type::FIXED_TEXT) {
// If part's modifier is "none"
if (part.modifier == url_pattern_part_modifier::none) {
// Append the result of running escape a regexp string given part's
// value
result += escape_regexp_string(part.value);
} else {
// A "fixed-text" part with a modifier uses a non capturing group
// (?:<fixed text>)<modifier>
// Append "(?:" to the end of result.
result.append("(?:");
// Append the result of running escape a regexp string given part's
// value to the end of result.
result.append(escape_regexp_string(part.value));
// Append ")" to the end of result.
result.append(")");
// Append the result of running convert a modifier to a string given
// part's modifier to the end of result.
result.append(convert_modifier_to_string(part.modifier));
}
continue;
}
// Assert: part's name is not the empty string
ADA_ASSERT_TRUE(!part.name.empty());
// Append part's name to name list
name_list.push_back(part.name);
// Let regexp value be part's value
std::string regexp_value = part.value;
// If part's type is "segment-wildcard"
if (part.type == url_pattern_part_type::SEGMENT_WILDCARD) {
// then set regexp value to the result of running generate a segment
// wildcard regexp given options.
regexp_value = generate_segment_wildcard_regexp(options);
}
// Otherwise if part's type is "full-wildcard"
else if (part.type == url_pattern_part_type::FULL_WILDCARD) {
// then set regexp value to full wildcard regexp value.
regexp_value = ".*";
}
// If part's prefix is the empty string and part's suffix is the empty
// string
if (part.prefix.empty() && part.suffix.empty()) {
// If part's modifier is "none" or "optional"
if (part.modifier == url_pattern_part_modifier::none ||
part.modifier == url_pattern_part_modifier::optional) {
// (<regexp value>)<modifier>
result += "(" + regexp_value + ")" +
convert_modifier_to_string(part.modifier);
} else {
// ((?:<regexp value>)<modifier>)
result += "((?:" + regexp_value + ")" +
convert_modifier_to_string(part.modifier) + ")";
}
continue;
}
// If part's modifier is "none" or "optional"
if (part.modifier == url_pattern_part_modifier::none ||
part.modifier == url_pattern_part_modifier::optional) {
// (?:<prefix>(<regexp value>)<suffix>)<modifier>
result += "(?:" + escape_regexp_string(part.prefix) + "(" + regexp_value +
")" + escape_regexp_string(part.suffix) + ")" +
convert_modifier_to_string(part.modifier);
continue;
}
// Assert: part's modifier is "zero-or-more" or "one-or-more"
ADA_ASSERT_TRUE(part.modifier == url_pattern_part_modifier::zero_or_more ||
part.modifier == url_pattern_part_modifier::one_or_more);
// Assert: part's prefix is not the empty string or part's suffix is not the
// empty string
ADA_ASSERT_TRUE(!part.prefix.empty() || !part.suffix.empty());
// (?:<prefix>((?:<regexp value>)(?:<suffix><prefix>(?:<regexp
// value>))*)<suffix>)?
// Append "(?:" to the end of result.
result.append("(?:");
// Append the result of running escape a regexp string given part's prefix
// to the end of result.
result.append(escape_regexp_string(part.prefix));
// Append "((?:" to the end of result.
result.append("((?:");
// Append regexp value to the end of result.
result.append(regexp_value);
// Append ")(?:" to the end of result.
result.append(")(?:");
// Append the result of running escape a regexp string given part's suffix
// to the end of result.
result.append(escape_regexp_string(part.suffix));
// Append the result of running escape a regexp string given part's prefix
// to the end of result.
result.append(escape_regexp_string(part.prefix));
// Append "(?:" to the end of result.
result.append("(?:");
// Append regexp value to the end of result.
result.append(regexp_value);
// Append "))*)" to the end of result.
result.append("))*)");
// Append the result of running escape a regexp string given part's suffix
// to the end of result.
result.append(escape_regexp_string(part.suffix));
// Append ")" to the end of result.
result.append(")");
// If part's modifier is "zero-or-more" then append "?" to the end of result
if (part.modifier == url_pattern_part_modifier::zero_or_more) {
result += "?";
}
}
// Append "$" to the end of result
result += "$";
// Return (result, name list)
return {std::move(result), std::move(name_list)};
}
bool is_ipv6_address(std::string_view input) noexcept {
// If input's code point length is less than 2, then return false.
if (input.size() < 2) return false;
// Let input code points be input interpreted as a list of code points.
// If input code points[0] is U+005B ([), then return true.
if (input.front() == '[') return true;
// If input code points[0] is U+007B ({) and input code points[1] is U+005B
// ([), then return true.
if (input.starts_with("{[")) return true;
// If input code points[0] is U+005C (\) and input code points[1] is U+005B
// ([), then return true.
return input.starts_with("\\[");
}
std::string convert_modifier_to_string(url_pattern_part_modifier modifier) {
// TODO: Optimize this.
switch (modifier) {
// If modifier is "zero-or-more", then return "*".
case url_pattern_part_modifier::zero_or_more:
return "*";
// If modifier is "optional", then return "?".
case url_pattern_part_modifier::optional:
return "?";
// If modifier is "one-or-more", then return "+".
case url_pattern_part_modifier::one_or_more:
return "+";
// Return the empty string.
default:
return "";
}
}
std::string generate_segment_wildcard_regexp(
url_pattern_compile_component_options options) {
// Let result be "[^".
std::string result = "[^";
// Append the result of running escape a regexp string given options's
// delimiter code point to the end of result.
result.append(escape_regexp_string(options.get_delimiter()));
// Append "]+?" to the end of result.
result.append("]+?");
// Return result.
ada_log("generate_segment_wildcard_regexp result: ", result);
return result;
}
tl::expected<std::string, errors> canonicalize_protocol(
std::string_view input) {
ada_log("canonicalize_protocol called with input=", input);
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// IMPORTANT: Deviation from the spec. We remove the trailing ':' here.
if (input.ends_with(":")) {
input.remove_suffix(1);
}
// Let dummyURL be a new URL record.
// Let parseResult be the result of running the basic URL parser given value
// followed by "://dummy.test", with dummyURL as url.
if (auto dummy_url = ada::parse<url_aggregator>(
std::string(input) + "://dummy.test", nullptr)) {
// IMPORTANT: Deviation from the spec. We remove the trailing ':' here.
// Since URL parser always return protocols ending with `:`
auto protocol = dummy_url->get_protocol();
protocol.remove_suffix(1);
return std::string(protocol);
}
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_username(
std::string_view input) {
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
auto url = ada::parse<url_aggregator>("fake://dummy.test", nullptr);
ADA_ASSERT_TRUE(url.has_value());
// Set the username given dummyURL and value.
if (!url->set_username(input)) {
return tl::unexpected(errors::type_error);
}
// Return dummyURL's username.
return std::string(url->get_username());
}
tl::expected<std::string, errors> canonicalize_password(
std::string_view input) {
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// Set the password given dummyURL and value.
auto url = ada::parse<url_aggregator>("fake://dummy.test", nullptr);
ADA_ASSERT_TRUE(url.has_value());
if (!url->set_password(input)) {
return tl::unexpected(errors::type_error);
}
// Return dummyURL's password.
return std::string(url->get_password());
}
tl::expected<std::string, errors> canonicalize_hostname(
std::string_view input) {
ada_log("canonicalize_hostname input=", input);
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// Let parseResult be the result of running the basic URL parser given value
// with dummyURL as url and hostname state as state override.
// IMPORTANT: The protocol needs to be a special protocol, otherwise the
// hostname will not be converted using IDNA.
auto url = ada::parse<url_aggregator>("https://dummy.test", nullptr);
ADA_ASSERT_TRUE(url);
// if (!isValidHostnameInput(hostname)) return kj::none;
if (!url->set_hostname(input)) {
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
// Return dummyURL's host, serialized, or empty string if it is null.
return std::string(url->get_hostname());
}
tl::expected<std::string, errors> canonicalize_ipv6_hostname(
std::string_view input) {
ada_log("canonicalize_ipv6_hostname input=", input);
// TODO: Optimization opportunity: Use lookup table to speed up checking
if (std::ranges::any_of(input, [](char c) {
return c != '[' && c != ']' && c != ':' &&
!unicode::is_ascii_hex_digit(c);
})) {
return tl::unexpected(errors::type_error);
}
// Append the result of running ASCII lowercase given code point to the end of
// result.
auto hostname = std::string(input);
unicode::to_lower_ascii(hostname.data(), hostname.size());
return hostname;
}
tl::expected<std::string, errors> canonicalize_port(
std::string_view port_value) {
// If portValue is the empty string, return portValue.
if (port_value.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// If protocolValue was given, then set dummyURL's scheme to protocolValue.
// Let parseResult be the result of running basic URL parser given portValue
// with dummyURL as url and port state as state override.
auto url = ada::parse<url_aggregator>("fake://dummy.test", nullptr);
ADA_ASSERT_TRUE(url);
if (url->set_port(port_value)) {
// Return dummyURL's port, serialized, or empty string if it is null.
return std::string(url->get_port());
}
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_port_with_protocol(
std::string_view port_value, std::string_view protocol) {
// If portValue is the empty string, return portValue.
if (port_value.empty()) [[unlikely]] {
return "";
}
// TODO: Remove this
// We have an empty protocol because get_protocol() returns an empty string
// We should handle this in the caller rather than here.
if (protocol.empty()) {
protocol = "fake";
} else if (protocol.ends_with(":")) {
protocol.remove_suffix(1);
}
// Let dummyURL be a new URL record.
// If protocolValue was given, then set dummyURL's scheme to protocolValue.
// Let parseResult be the result of running basic URL parser given portValue
// with dummyURL as url and port state as state override.
auto url = ada::parse<url_aggregator>(std::string(protocol) + "://dummy.test",
nullptr);
// TODO: Remove has_port() check.
// This is actually a bug with url parser where set_port() returns true for
// "invalid80" port value.
if (url && url->set_port(port_value) && url->has_port()) {
// Return dummyURL's port, serialized, or empty string if it is null.
return std::string(url->get_port());
}
// TODO: Remove this once the previous has_port() check is removed.
if (url) {
if (scheme::is_special(protocol) && url->get_port().empty()) {
return "";
}
}
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_pathname(
std::string_view input) {
// If value is the empty string, then return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let leading slash be true if the first code point in value is U+002F (/)
// and otherwise false.
const bool leading_slash = input.starts_with("/");
// Let modified value be "/-" if leading slash is false and otherwise the
// empty string.
const auto modified_value = leading_slash ? "" : "/-";
const auto full_url =
std::string("fake://fake-url") + modified_value + std::string(input);
if (auto url = ada::parse<url_aggregator>(full_url, nullptr)) {
const auto pathname = url->get_pathname();
// If leading slash is false, then set result to the code point substring
// from 2 to the end of the string within result.
return leading_slash ? std::string(pathname)
: std::string(pathname.substr(2));
}
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_opaque_pathname(
std::string_view input) {
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// Set dummyURL's path to the empty string.
// Let parseResult be the result of running URL parsing given value with
// dummyURL as url and opaque path state as state override.
if (auto url =
ada::parse<url_aggregator>("fake:" + std::string(input), nullptr)) {
// Return the result of URL path serializing dummyURL.
return std::string(url->get_pathname());
}
// If parseResult is failure, then throw a TypeError.
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_search(std::string_view input) {
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// Set dummyURL's query to the empty string.
// Let parseResult be the result of running basic URL parser given value with
// dummyURL as url and query state as state override.
auto url = ada::parse<url_aggregator>("fake://dummy.test", nullptr);
ADA_ASSERT_TRUE(url.has_value());
url->set_search(input);
if (url->has_search()) {
const auto search = url->get_search();
return std::string(search.substr(1));
}
return tl::unexpected(errors::type_error);
}
tl::expected<std::string, errors> canonicalize_hash(std::string_view input) {
// If value is the empty string, return value.
if (input.empty()) [[unlikely]] {
return "";
}
// Let dummyURL be a new URL record.
// Set dummyURL's fragment to the empty string.
// Let parseResult be the result of running basic URL parser given value with
// dummyURL as url and fragment state as state override.
auto url = ada::parse<url_aggregator>("fake://dummy.test", nullptr);
ADA_ASSERT_TRUE(url.has_value());
url->set_hash(input);
// Return dummyURL's fragment.
if (url->has_hash()) {
const auto hash = url->get_hash();
return std::string(hash.substr(1));
}
return tl::unexpected(errors::type_error);
}
tl::expected<std::vector<token>, errors> tokenize(std::string_view input,
token_policy policy) {
ada_log("tokenize input: ", input);
// Let tokenizer be a new tokenizer.
// Set tokenizer's input to input.
// Set tokenizer's policy to policy.
auto tokenizer = Tokenizer(input, policy);
// While tokenizer's index is less than tokenizer's input's code point length:
while (tokenizer.index < tokenizer.input.size()) {
// Run seek and get the next code point given tokenizer and tokenizer's
// index.
tokenizer.seek_and_get_next_code_point(tokenizer.index);
// If tokenizer's code point is U+002A (*):
if (tokenizer.code_point == '*') {
// Run add a token with default position and length given tokenizer and
// "asterisk".
tokenizer.add_token_with_defaults(token_type::ASTERISK);
ada_log("add ASTERISK token");
// Continue.
continue;
}
// If tokenizer's code point is U+002B (+) or U+003F (?):
if (tokenizer.code_point == '+' || tokenizer.code_point == '?') {
// Run add a token with default position and length given tokenizer and
// "other-modifier".
tokenizer.add_token_with_defaults(token_type::OTHER_MODIFIER);
// Continue.
continue;
}
// If tokenizer's code point is U+005C (\):
if (tokenizer.code_point == '\\') {
// If tokenizer's index is equal to tokenizer's input's code point length
// - 1:
if (tokenizer.index == tokenizer.input.size() - 1) {
// Run process a tokenizing error given tokenizer, tokenizer's next
// index, and tokenizer's index.
if (auto error = tokenizer.process_tokenizing_error(
tokenizer.next_index, tokenizer.index)) {
ada_log("process_tokenizing_error failed");
return tl::unexpected(*error);
}
continue;
}
// Let escaped index be tokenizer's next index.
auto escaped_index = tokenizer.next_index;
// Run get the next code point given tokenizer.
tokenizer.get_next_code_point();
// Run add a token with default length given tokenizer, "escaped-char",
// tokenizer's next index, and escaped index.
tokenizer.add_token_with_default_length(
token_type::ESCAPED_CHAR, tokenizer.next_index, escaped_index);
ada_log("add ESCAPED_CHAR token on next_index ", tokenizer.next_index,
" with escaped index ", escaped_index);
// Continue.
continue;
}
// If tokenizer's code point is U+007B ({):
if (tokenizer.code_point == '{') {
// Run add a token with default position and length given tokenizer and
// "open".
tokenizer.add_token_with_defaults(token_type::OPEN);
ada_log("add OPEN token");
continue;
}
// If tokenizer's code point is U+007D (}):
if (tokenizer.code_point == '}') {
// Run add a token with default position and length given tokenizer and
// "close".
tokenizer.add_token_with_defaults(token_type::CLOSE);
ada_log("add CLOSE token");
continue;
}
// If tokenizer's code point is U+003A (:):
if (tokenizer.code_point == ':') {
// Let name position be tokenizer's next index.
auto name_position = tokenizer.next_index;
// Let name start be name position.
auto name_start = name_position;
// While name position is less than tokenizer's input's code point length:
while (name_position < tokenizer.input.size()) {
// Run seek and get the next code point given tokenizer and name
// position.
tokenizer.seek_and_get_next_code_point(name_position);
// Let first code point be true if name position equals name start and
// false otherwise.
bool first_code_point = name_position == name_start;
// Let valid code point be the result of running is a valid name code
// point given tokenizer's code point and first code point.
auto valid_code_point =
idna::valid_name_code_point(tokenizer.code_point, first_code_point);
ada_log("tokenizer.code_point=", uint32_t(tokenizer.code_point),
" first_code_point=", first_code_point,
" valid_code_point=", valid_code_point);
// If valid code point is false break.
if (!valid_code_point) break;
// Set name position to tokenizer's next index.
name_position = tokenizer.next_index;
}
// If name position is less than or equal to name start:
if (name_position <= name_start) {
// Run process a tokenizing error given tokenizer, name start, and
// tokenizer's index.
if (auto error = tokenizer.process_tokenizing_error(name_start,
tokenizer.index)) {
ada_log("process_tokenizing_error failed");
return tl::unexpected(*error);
}
// Continue
continue;
}
// Run add a token with default length given tokenizer, "name", name
// position, and name start.
tokenizer.add_token_with_default_length(token_type::NAME, name_position,
name_start);
continue;
}
// If tokenizer's code point is U+0028 (():
if (tokenizer.code_point == '(') {
// Let depth be 1.
size_t depth = 1;
// Let regexp position be tokenizer's next index.
auto regexp_position = tokenizer.next_index;
// Let regexp start be regexp position.
auto regexp_start = regexp_position;
// Let error be false.
bool error = false;
// While regexp position is less than tokenizer's input's code point
// length:
while (regexp_position < tokenizer.input.size()) {
// Run seek and get the next code point given tokenizer and regexp
// position.
tokenizer.seek_and_get_next_code_point(regexp_position);
// TODO: Optimization opportunity: The next 2 if statements can be
// merged. If the result of running is ASCII given tokenizer's code
// point is false:
if (!unicode::is_ascii(tokenizer.code_point)) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
// Set error to true.
error = true;
break;
}
// If regexp position equals regexp start and tokenizer's code point is
// U+003F (?):
if (regexp_position == regexp_start && tokenizer.code_point == '?') {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
// Set error to true;
error = true;
break;
}
// If tokenizer's code point is U+005C (\):
if (tokenizer.code_point == '\\') {
// If regexp position equals tokenizer's input's code point length - 1
if (regexp_position == tokenizer.input.size() - 1) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
// Set error to true.
error = true;
break;
}
// Run get the next code point given tokenizer.
tokenizer.get_next_code_point();
// If the result of running is ASCII given tokenizer's code point is
// false:
if (!unicode::is_ascii(tokenizer.code_point)) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index);
process_error.has_value()) {
return tl::unexpected(*process_error);
}
// Set error to true.
error = true;
break;
}
// Set regexp position to tokenizer's next index.
regexp_position = tokenizer.next_index;
continue;
}
// If tokenizer's code point is U+0029 ()):
if (tokenizer.code_point == ')') {
// Decrement depth by 1.
depth--;
// If depth is 0:
if (depth == 0) {
// Set regexp position to tokenizer's next index.
regexp_position = tokenizer.next_index;
// Break.
break;
}
} else if (tokenizer.code_point == '(') {
// Otherwise if tokenizer's code point is U+0028 (():
// Increment depth by 1.
depth++;
// If regexp position equals tokenizer's input's code point length -
// 1:
if (regexp_position == tokenizer.input.size() - 1) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
// Set error to true.
error = true;
break;
}
// Let temporary position be tokenizer's next index.
auto temporary_position = tokenizer.next_index;
// Run get the next code point given tokenizer.
tokenizer.get_next_code_point();
// If tokenizer's code point is not U+003F (?):
if (tokenizer.code_point != '?') {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
// Set error to true.
error = true;
break;
}
// Set tokenizer's next index to temporary position.
tokenizer.next_index = temporary_position;
}
// Set regexp position to tokenizer's next index.
regexp_position = tokenizer.next_index;
}
// If error is true continue.
if (error) continue;
// If depth is not zero:
if (depth != 0) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
return tl::unexpected(*process_error);
}
continue;
}
// Let regexp length be regexp position - regexp start - 1.
auto regexp_length = regexp_position - regexp_start - 1;
// If regexp length is zero:
if (regexp_length == 0) {
// Run process a tokenizing error given tokenizer, regexp start, and
// tokenizer's index.
if (auto process_error = tokenizer.process_tokenizing_error(
regexp_start, tokenizer.index)) {
ada_log("process_tokenizing_error failed");
return tl::unexpected(*process_error);
}
continue;
}
// Run add a token given tokenizer, "regexp", regexp position, regexp
// start, and regexp length.
tokenizer.add_token(token_type::REGEXP, regexp_position, regexp_start,
regexp_length);
continue;
}
// Run add a token with default position and length given tokenizer and
// "char".
tokenizer.add_token_with_defaults(token_type::CHAR);
}
// Run add a token with default length given tokenizer, "end", tokenizer's
// index, and tokenizer's index.
tokenizer.add_token_with_default_length(token_type::END, tokenizer.index,
tokenizer.index);
ada_log("tokenizer.token_list size is: ", tokenizer.token_list.size());
// Return tokenizer's token list.
return tokenizer.token_list;
}
std::string escape_pattern_string(std::string_view input) {
ada_log("escape_pattern_string called with input=", input);
if (input.empty()) [[unlikely]] {
return "";
}
// Assert: input is an ASCII string.
ADA_ASSERT_TRUE(ada::idna::is_ascii(input));
// Let result be the empty string.
std::string result{};
result.reserve(input.size());
// TODO: Optimization opportunity: Use a lookup table
constexpr auto should_escape = [](const char c) {
return c == '+' || c == '*' || c == '?' || c == ':' || c == '{' ||
c == '}' || c == '(' || c == ')' || c == '\\';
};
// While index is less than input's length:
for (const auto& c : input) {
if (should_escape(c)) {
// then append U+005C (\) to the end of result.
result.append("\\");
}
// Append c to the end of result.
result += c;
}
// Return result.
return result;
}
namespace {
constexpr std::array<uint8_t, 256> escape_regexp_table = []() consteval {
std::array<uint8_t, 256> out{};
for (auto& c : {'.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '[', ']',
'|', '/', '\\'}) {
out[c] = 1;
}
return out;
}();
constexpr bool should_escape_regexp_char(char c) {
return escape_regexp_table[(uint8_t)c];
}
} // namespace
std::string escape_regexp_string(std::string_view input) {
// Assert: input is an ASCII string.
ADA_ASSERT_TRUE(idna::is_ascii(input));
// Let result be the empty string.
std::string result{};
result.reserve(input.size());
for (const auto& c : input) {
// TODO: Optimize this even further
if (should_escape_regexp_char(c)) {
result.append(std::string("\\") + c);
} else {
result.push_back(c);
}
}
return result;
}
std::string process_base_url_string(std::string_view input,
url_pattern_init::process_type type) {
// If type is not "pattern" return input.
if (type != url_pattern_init::process_type::pattern) {
return std::string(input);
}
// Return the result of escaping a pattern string given input.
return escape_pattern_string(input);
}
constexpr bool is_absolute_pathname(
std::string_view input, url_pattern_init::process_type type) noexcept {
// If input is the empty string, then return false.
if (input.empty()) [[unlikely]] {
return false;
}
// If input[0] is U+002F (/), then return true.
if (input.starts_with("/")) return true;
// If type is "url", then return false.
if (type == url_pattern_init::process_type::url) return false;
// If input's code point length is less than 2, then return false.
if (input.size() < 2) return false;
// If input[0] is U+005C (\) and input[1] is U+002F (/), then return true.
// If input[0] is U+007B ({) and input[1] is U+002F (/), then return true.
// Return false.
return input[1] == '/' && (input[0] == '\\' || input[0] == '{');
}
std::string generate_pattern_string(
std::vector<url_pattern_part>& part_list,
url_pattern_compile_component_options& options) {
// Let result be the empty string.
std::string result{};
// Let index list be the result of getting the indices for part list.
// For each index of index list:
for (size_t index = 0; index < part_list.size(); index++) {
// Let part be part list[index].
auto part = part_list[index];
// Let previous part be part list[index - 1] if index is greater than 0,
// otherwise let it be null.
// TODO: Optimization opportunity. Find a way to avoid making a copy here.
std::optional<url_pattern_part> previous_part =
index == 0 ? std::nullopt : std::optional(part_list[index - 1]);
// Let next part be part list[index + 1] if index is less than index list's
// size - 1, otherwise let it be null.
std::optional<url_pattern_part> next_part =
index < part_list.size() - 1 ? std::optional(part_list[index + 1])
: std::nullopt;
// If part's type is "fixed-text" then:
if (part.type == url_pattern_part_type::FIXED_TEXT) {
// If part's modifier is "none" then:
if (part.modifier == url_pattern_part_modifier::none) {
// Append the result of running escape a pattern string given part's
// value to the end of result.
result.append(escape_pattern_string(part.value));
continue;
}
// Append "{" to the end of result.
result += "{";
// Append the result of running escape a pattern string given part's value
// to the end of result.
result.append(escape_pattern_string(part.value));
// Append "}" to the end of result.
result += "}";
// Append the result of running convert a modifier to a string given
// part's modifier to the end of result.
result.append(convert_modifier_to_string(part.modifier));
continue;
}
// Let custom name be true if part's name[0] is not an ASCII digit;
// otherwise false.
bool custom_name = !unicode::is_ascii_digit(part.name[0]);
// Let needs grouping be true if at least one of the following are true,
// otherwise let it be false:
// - part's suffix is not the empty string.
// - part's prefix is not the empty string and is not options's prefix code
// point.
bool needs_grouping =
!part.suffix.empty() ||
(!part.prefix.empty() && part.prefix[0] != options.get_prefix()[0]);
// If all of the following are true:
// - needs grouping is false; and
// - custom name is true; and
// - part's type is "segment-wildcard"; and
// - part's modifier is "none"; and
// - next part is not null; and
// - next part's prefix is the empty string; and
// - next part's suffix is the empty string
if (!needs_grouping && custom_name &&
part.type == url_pattern_part_type::SEGMENT_WILDCARD &&
part.modifier == url_pattern_part_modifier::none &&
next_part.has_value() && next_part->prefix.empty() &&
next_part->suffix.empty()) {
// If next part's type is "fixed-text":
if (next_part->type == url_pattern_part_type::FIXED_TEXT) {
// Set needs grouping to true if the result of running is a valid name
// code point given next part's value's first code point and the boolean
// false is true.
if (idna::valid_name_code_point(next_part->value[0], false)) {
needs_grouping = true;
}
} else {
// Set needs grouping to true if next part's name[0] is an ASCII digit.
needs_grouping = !next_part->name.empty() &&
unicode::is_ascii_digit(next_part->name[0]);
}
}
// If all of the following are true:
// - needs grouping is false; and
// - part's prefix is the empty string; and
// - previous part is not null; and
// - previous part's type is "fixed-text"; and
// - previous part's value's last code point is options's prefix code point.
// then set needs grouping to true.
if (!needs_grouping && part.prefix.empty() && previous_part.has_value() &&
previous_part->type == url_pattern_part_type::FIXED_TEXT &&
!options.get_prefix().empty() &&
previous_part->value.at(previous_part->value.size() - 1) ==
options.get_prefix()[0]) {
needs_grouping = true;
}
// Assert: part's name is not the empty string or null.
ADA_ASSERT_TRUE(!part.name.empty());
// If needs grouping is true, then append "{" to the end of result.
if (needs_grouping) {
result.append("{");
}
// Append the result of running escape a pattern string given part's prefix
// to the end of result.
result.append(escape_pattern_string(part.prefix));
// If custom name is true:
if (custom_name) {
// Append ":" to the end of result.
result.append(":");
// Append part's name to the end of result.
result.append(part.name);
}
// If part's type is "regexp" then:
if (part.type == url_pattern_part_type::REGEXP) {
// Append "(" to the end of result.
result.append("(");
// Append part's value to the end of result.
result.append(part.value);
// Append ")" to the end of result.
result.append(")");
} else if (part.type == url_pattern_part_type::SEGMENT_WILDCARD &&
!custom_name) {
// Otherwise if part's type is "segment-wildcard" and custom name is
// false: Append "(" to the end of result.
result.append("(");
// Append the result of running generate a segment wildcard regexp given
// options to the end of result.
result.append(generate_segment_wildcard_regexp(options));
// Append ")" to the end of result.
result.append(")");
} else if (part.type == url_pattern_part_type::FULL_WILDCARD) {
// Otherwise if part's type is "full-wildcard":
// If custom name is false and one of the following is true:
// - previous part is null; or
// - previous part's type is "fixed-text"; or
// - previous part's modifier is not "none"; or
// - needs grouping is true; or
// - part's prefix is not the empty string
// - then append "*" to the end of result.
if (!custom_name &&
(!previous_part.has_value() ||
previous_part->type == url_pattern_part_type::FIXED_TEXT ||
previous_part->modifier != url_pattern_part_modifier::none ||
needs_grouping || !part.prefix.empty())) {
result.append("*");
} else {
// Append "(" to the end of result.
// Append full wildcard regexp value to the end of result.
// Append ")" to the end of result.
result.append("(.*)");
}
}
// If all of the following are true:
// - part's type is "segment-wildcard"; and
// - custom name is true; and
// - part's suffix is not the empty string; and
// - The result of running is a valid name code point given part's suffix's
// first code point and the boolean false is true then append U+005C (\) to
// the end of result.
if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && custom_name &&
!part.suffix.empty() &&
idna::valid_name_code_point(part.suffix[0], false)) {
result.append("\\");
}
// Append the result of running escape a pattern string given part's suffix
// to the end of result.
result.append(escape_pattern_string(part.suffix));
// If needs grouping is true, then append "}" to the end of result.
if (needs_grouping) result.append("}");
// Append the result of running convert a modifier to a string given part's
// modifier to the end of result.
result.append(convert_modifier_to_string(part.modifier));
}
// Return result.
return result;
}
} // namespace ada::url_pattern_helpers
#endif // ADA_INCLUDE_URL_PATTERN
/* end file src/url_pattern_helpers.cpp */
/* begin file src/url_pattern_regex.cpp */
#if ADA_INCLUDE_URL_PATTERN
namespace ada::url_pattern_regex {
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
std::optional<std::regex> std_regex_provider::create_instance(
std::string_view pattern, bool ignore_case) {
// Let flags be an empty string.
// If options's ignore case is true then set flags to "vi".
// Otherwise set flags to "v"
auto flags = ignore_case
? std::regex::icase | std::regex_constants::ECMAScript
: std::regex_constants::ECMAScript;
try {
return std::regex(pattern.data(), pattern.size(), flags);
} catch (const std::regex_error& e) {
(void)e;
ada_log("std_regex_provider::create_instance failed:", e.what());
return std::nullopt;
}
}
std::optional<std::vector<std::optional<std::string>>>
std_regex_provider::regex_search(std::string_view input,
const std::regex& pattern) {
std::string input_str(
input.begin(),
input.end()); // Convert string_view to string for regex_search
std::smatch match_result;
if (!std::regex_search(input_str, match_result, pattern,
std::regex_constants::match_any)) {
return std::nullopt;
}
std::vector<std::optional<std::string>> matches;
// If input is empty, let's assume the result will be empty as well.
if (input.empty() || match_result.empty()) {
return matches;
}
matches.reserve(match_result.size());
for (size_t i = 1; i < match_result.size(); ++i) {
if (auto entry = match_result[i]; entry.matched) {
matches.emplace_back(entry.str());
}
}
return matches;
}
bool std_regex_provider::regex_match(std::string_view input,
const std::regex& pattern) {
return std::regex_match(input.begin(), input.end(), pattern);
}
#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
} // namespace ada::url_pattern_regex
#endif // ADA_INCLUDE_URL_PATTERN
/* end file src/url_pattern_regex.cpp */
#endif // ADA_INCLUDE_URL_PATTERN
/* begin file src/ada_c.cpp */
ada::result<ada::url_aggregator>& get_instance(void* result) noexcept {
return *(ada::result<ada::url_aggregator>*)result;
}
extern "C" {
typedef void* ada_url;
typedef void* ada_url_search_params;
typedef void* ada_strings;
typedef void* ada_url_search_params_keys_iter;
typedef void* ada_url_search_params_values_iter;
typedef void* ada_url_search_params_entries_iter;
struct ada_string {
const char* data;
size_t length;
};
struct ada_owned_string {
const char* data;
size_t length;
};
struct ada_string_pair {
ada_string key;
ada_string value;
};
ada_string ada_string_create(const char* data, size_t length) {
ada_string out{};
out.data = data;
out.length = length;
return out;
}
struct ada_url_components {
/*
* By using 32-bit integers, we implicitly assume that the URL string
* cannot exceed 4 GB.
*
* https://user:pass@example.com:1234/foo/bar?baz#quux
* | | | | ^^^^| | |
* | | | | | | | `----- hash_start
* | | | | | | `--------- search_start
* | | | | | `----------------- pathname_start
* | | | | `--------------------- port
* | | | `----------------------- host_end
* | | `---------------------------------- host_start
* | `--------------------------------------- username_end
* `--------------------------------------------- protocol_end
*/
uint32_t protocol_end;
/**
* Username end is not `omitted` by default (-1) to make username and password
* getters less costly to implement.
*/
uint32_t username_end;
uint32_t host_start;
uint32_t host_end;
uint32_t port;
uint32_t pathname_start;
uint32_t search_start;
uint32_t hash_start;
};
ada_url ada_parse(const char* input, size_t length) noexcept {
return new ada::result<ada::url_aggregator>(
ada::parse<ada::url_aggregator>(std::string_view(input, length)));
}
ada_url ada_parse_with_base(const char* input, size_t input_length,
const char* base, size_t base_length) noexcept {
auto base_out =
ada::parse<ada::url_aggregator>(std::string_view(base, base_length));
if (!base_out) {
return new ada::result<ada::url_aggregator>(base_out);
}
return new ada::result<ada::url_aggregator>(ada::parse<ada::url_aggregator>(
std::string_view(input, input_length), &base_out.value()));
}
bool ada_can_parse(const char* input, size_t length) noexcept {
return ada::can_parse(std::string_view(input, length));
}
bool ada_can_parse_with_base(const char* input, size_t input_length,
const char* base, size_t base_length) noexcept {
std::string_view base_view(base, base_length);
return ada::can_parse(std::string_view(input, input_length), &base_view);
}
void ada_free(ada_url result) noexcept {
auto* r = (ada::result<ada::url_aggregator>*)result;
delete r;
}
ada_url ada_copy(ada_url input) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(input);
return new ada::result<ada::url_aggregator>(r);
}
bool ada_is_valid(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
return r.has_value();
}
// caller must free the result with ada_free_owned_string
ada_owned_string ada_get_origin(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
ada_owned_string owned{};
if (!r) {
owned.data = nullptr;
owned.length = 0;
return owned;
}
std::string out = r->get_origin();
owned.length = out.size();
owned.data = new char[owned.length];
memcpy((void*)owned.data, out.data(), owned.length);
return owned;
}
void ada_free_owned_string(ada_owned_string owned) noexcept {
delete[] owned.data;
}
ada_string ada_get_href(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_href();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_username(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_username();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_password(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_password();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_port(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_port();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_hash(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_hash();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_host(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_host();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_hostname(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_hostname();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_pathname(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_pathname();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_search(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_search();
return ada_string_create(out.data(), out.length());
}
ada_string ada_get_protocol(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view out = r->get_protocol();
return ada_string_create(out.data(), out.length());
}
uint8_t ada_get_host_type(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return 0;
}
return r->host_type;
}
uint8_t ada_get_scheme_type(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return 0;
}
return r->type;
}
bool ada_set_href(ada_url result, const char* input, size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_href(std::string_view(input, length));
}
bool ada_set_host(ada_url result, const char* input, size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_host(std::string_view(input, length));
}
bool ada_set_hostname(ada_url result, const char* input,
size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_hostname(std::string_view(input, length));
}
bool ada_set_protocol(ada_url result, const char* input,
size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_protocol(std::string_view(input, length));
}
bool ada_set_username(ada_url result, const char* input,
size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_username(std::string_view(input, length));
}
bool ada_set_password(ada_url result, const char* input,
size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_password(std::string_view(input, length));
}
bool ada_set_port(ada_url result, const char* input, size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_port(std::string_view(input, length));
}
bool ada_set_pathname(ada_url result, const char* input,
size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->set_pathname(std::string_view(input, length));
}
/**
* Update the search/query of the URL.
*
* If a URL has `?` as the search value, passing empty string to this function
* does not remove the attribute. If you need to remove it, please use
* `ada_clear_search` method.
*/
void ada_set_search(ada_url result, const char* input, size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (r) {
r->set_search(std::string_view(input, length));
}
}
/**
* Update the hash/fragment of the URL.
*
* If a URL has `#` as the hash value, passing empty string to this function
* does not remove the attribute. If you need to remove it, please use
* `ada_clear_hash` method.
*/
void ada_set_hash(ada_url result, const char* input, size_t length) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (r) {
r->set_hash(std::string_view(input, length));
}
}
void ada_clear_port(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (r) {
r->clear_port();
}
}
/**
* Removes the hash of the URL.
*
* Despite `ada_set_hash` method, this function allows the complete
* removal of the hash attribute, even if it has a value of `#`.
*/
void ada_clear_hash(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (r) {
r->clear_hash();
}
}
/**
* Removes the search of the URL.
*
* Despite `ada_set_search` method, this function allows the complete
* removal of the search attribute, even if it has a value of `?`.
*/
void ada_clear_search(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (r) {
r->clear_search();
}
}
bool ada_has_credentials(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_credentials();
}
bool ada_has_empty_hostname(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_empty_hostname();
}
bool ada_has_hostname(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_hostname();
}
bool ada_has_non_empty_username(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_non_empty_username();
}
bool ada_has_non_empty_password(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_non_empty_password();
}
bool ada_has_port(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_port();
}
bool ada_has_password(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_password();
}
bool ada_has_hash(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_hash();
}
bool ada_has_search(ada_url result) noexcept {
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return false;
}
return r->has_search();
}
// returns a pointer to the internal url_aggregator::url_components
const ada_url_components* ada_get_components(ada_url result) noexcept {
static_assert(sizeof(ada_url_components) == sizeof(ada::url_components));
ada::result<ada::url_aggregator>& r = get_instance(result);
if (!r) {
return nullptr;
}
return reinterpret_cast<const ada_url_components*>(&r->get_components());
}
ada_owned_string ada_idna_to_unicode(const char* input, size_t length) {
std::string out = ada::idna::to_unicode(std::string_view(input, length));
ada_owned_string owned{};
owned.length = out.length();
owned.data = new char[owned.length];
memcpy((void*)owned.data, out.data(), owned.length);
return owned;
}
ada_owned_string ada_idna_to_ascii(const char* input, size_t length) {
std::string out = ada::idna::to_ascii(std::string_view(input, length));
ada_owned_string owned{};
owned.length = out.size();
owned.data = new char[owned.length];
memcpy((void*)owned.data, out.data(), owned.length);
return owned;
}
ada_url_search_params ada_parse_search_params(const char* input,
size_t length) {
return new ada::result<ada::url_search_params>(
ada::url_search_params(std::string_view(input, length)));
}
void ada_free_search_params(ada_url_search_params result) {
auto* r = (ada::result<ada::url_search_params>*)result;
delete r;
}
ada_owned_string ada_search_params_to_string(ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) return ada_owned_string{nullptr, 0};
std::string out = r->to_string();
ada_owned_string owned{};
owned.length = out.size();
owned.data = new char[owned.length];
memcpy((void*)owned.data, out.data(), owned.length);
return owned;
}
size_t ada_search_params_size(ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return 0;
}
return r->size();
}
void ada_search_params_sort(ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->sort();
}
}
void ada_search_params_reset(ada_url_search_params result, const char* input,
size_t length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->reset(std::string_view(input, length));
}
}
void ada_search_params_append(ada_url_search_params result, const char* key,
size_t key_length, const char* value,
size_t value_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->append(std::string_view(key, key_length),
std::string_view(value, value_length));
}
}
void ada_search_params_set(ada_url_search_params result, const char* key,
size_t key_length, const char* value,
size_t value_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->set(std::string_view(key, key_length),
std::string_view(value, value_length));
}
}
void ada_search_params_remove(ada_url_search_params result, const char* key,
size_t key_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->remove(std::string_view(key, key_length));
}
}
void ada_search_params_remove_value(ada_url_search_params result,
const char* key, size_t key_length,
const char* value, size_t value_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (r) {
r->remove(std::string_view(key, key_length),
std::string_view(value, value_length));
}
}
bool ada_search_params_has(ada_url_search_params result, const char* key,
size_t key_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return false;
}
return r->has(std::string_view(key, key_length));
}
bool ada_search_params_has_value(ada_url_search_params result, const char* key,
size_t key_length, const char* value,
size_t value_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return false;
}
return r->has(std::string_view(key, key_length),
std::string_view(value, value_length));
}
ada_string ada_search_params_get(ada_url_search_params result, const char* key,
size_t key_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return ada_string_create(nullptr, 0);
}
auto found = r->get(std::string_view(key, key_length));
if (!found.has_value()) {
return ada_string_create(nullptr, 0);
}
return ada_string_create(found->data(), found->length());
}
ada_strings ada_search_params_get_all(ada_url_search_params result,
const char* key, size_t key_length) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return new ada::result<std::vector<std::string>>(
std::vector<std::string>());
}
return new ada::result<std::vector<std::string>>(
r->get_all(std::string_view(key, key_length)));
}
ada_url_search_params_keys_iter ada_search_params_get_keys(
ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return new ada::result<ada::url_search_params_keys_iter>(
ada::url_search_params_keys_iter());
}
return new ada::result<ada::url_search_params_keys_iter>(r->get_keys());
}
ada_url_search_params_values_iter ada_search_params_get_values(
ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return new ada::result<ada::url_search_params_values_iter>(
ada::url_search_params_values_iter());
}
return new ada::result<ada::url_search_params_values_iter>(r->get_values());
}
ada_url_search_params_entries_iter ada_search_params_get_entries(
ada_url_search_params result) {
ada::result<ada::url_search_params>& r =
*(ada::result<ada::url_search_params>*)result;
if (!r) {
return new ada::result<ada::url_search_params_entries_iter>(
ada::url_search_params_entries_iter());
}
return new ada::result<ada::url_search_params_entries_iter>(r->get_entries());
}
void ada_free_strings(ada_strings result) {
auto* r = (ada::result<std::vector<std::string>>*)result;
delete r;
}
size_t ada_strings_size(ada_strings result) {
auto* r = (ada::result<std::vector<std::string>>*)result;
if (!r) {
return 0;
}
return (*r)->size();
}
ada_string ada_strings_get(ada_strings result, size_t index) {
auto* r = (ada::result<std::vector<std::string>>*)result;
if (!r) {
return ada_string_create(nullptr, 0);
}
std::string_view view = (*r)->at(index);
return ada_string_create(view.data(), view.length());
}
void ada_free_search_params_keys_iter(ada_url_search_params_keys_iter result) {
auto* r = (ada::result<ada::url_search_params_keys_iter>*)result;
delete r;
}
ada_string ada_search_params_keys_iter_next(
ada_url_search_params_keys_iter result) {
auto* r = (ada::result<ada::url_search_params_keys_iter>*)result;
if (!r) {
return ada_string_create(nullptr, 0);
}
auto next = (*r)->next();
if (!next.has_value()) {
return ada_string_create(nullptr, 0);
}
return ada_string_create(next->data(), next->length());
}
bool ada_search_params_keys_iter_has_next(
ada_url_search_params_keys_iter result) {
auto* r = (ada::result<ada::url_search_params_keys_iter>*)result;
if (!r) {
return false;
}
return (*r)->has_next();
}
void ada_free_search_params_values_iter(
ada_url_search_params_values_iter result) {
auto* r = (ada::result<ada::url_search_params_values_iter>*)result;
delete r;
}
ada_string ada_search_params_values_iter_next(
ada_url_search_params_values_iter result) {
auto* r = (ada::result<ada::url_search_params_values_iter>*)result;
if (!r) {
return ada_string_create(nullptr, 0);
}
auto next = (*r)->next();
if (!next.has_value()) {
return ada_string_create(nullptr, 0);
}
return ada_string_create(next->data(), next->length());
}
bool ada_search_params_values_iter_has_next(
ada_url_search_params_values_iter result) {
auto* r = (ada::result<ada::url_search_params_values_iter>*)result;
if (!r) {
return false;
}
return (*r)->has_next();
}
void ada_free_search_params_entries_iter(
ada_url_search_params_entries_iter result) {
auto* r = (ada::result<ada::url_search_params_entries_iter>*)result;
delete r;
}
ada_string_pair ada_search_params_entries_iter_next(
ada_url_search_params_entries_iter result) {
auto* r = (ada::result<ada::url_search_params_entries_iter>*)result;
if (!r) return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)};
auto next = (*r)->next();
if (!next.has_value()) {
return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)};
}
return ada_string_pair{
ada_string_create(next->first.data(), next->first.length()),
ada_string_create(next->second.data(), next->second.length())};
}
bool ada_search_params_entries_iter_has_next(
ada_url_search_params_entries_iter result) {
auto* r = (ada::result<ada::url_search_params_entries_iter>*)result;
if (!r) {
return false;
}
return (*r)->has_next();
}
} // extern "C"
/* end file src/ada_c.cpp */
/* end file src/ada.cpp */