diff --git a/deps/ada/ada.cpp b/deps/ada/ada.cpp index d7f9b3a92c5330..6a0ad8375dd28b 100644 --- a/deps/ada/ada.cpp +++ b/deps/ada/ada.cpp @@ -1,28 +1,29 @@ -/* auto-generated on 2024-09-02 20:07:32 -0400. Do not edit! */ +/* auto-generated on 2025-01-08 10:36:11 -0500. Do not edit! */ /* begin file src/ada.cpp */ #include "ada.h" /* begin file src/checkers.cpp */ #include +#include +#include namespace ada::checkers { -ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept { +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. - char last_char = view.back(); // If the address ends with a dot, we need to prune it (special case). - if (last_char == '.') { + if (view.ends_with('.')) { view.remove_suffix(1); if (view.empty()) { return false; } - last_char = view.back(); } + char last_char = view.back(); bool possible_ipv4 = (last_char >= '0' && last_char <= '9') || (last_char >= 'a' && last_char <= 'f') || last_char == 'x'; @@ -38,7 +39,7 @@ ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept { /** 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::all_of(view.begin(), view.end(), ada::checkers::is_digit)) { + 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. @@ -46,7 +47,7 @@ ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept { return false; } // It must start with 0x. - if (!std::equal(view.begin(), view.begin() + 2, "0x")) { + if (!view.starts_with("0x")) { return false; } // We must allow "0x". @@ -62,7 +63,7 @@ ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept { // for use with path_signature, we include all characters that need percent // encoding. static constexpr std::array path_signature_table = - []() constexpr { + []() consteval { std::array result{}; for (size_t i = 0; i < 256; i++) { if (i <= 0x20 || i == 0x22 || i == 0x23 || i == 0x3c || i == 0x3e || @@ -133,7 +134,7 @@ ada_really_inline constexpr bool verify_dns_length( ADA_PUSH_DISABLE_ALL_WARNINGS /* begin file src/ada_idna.cpp */ -/* auto-generated on 2023-09-19 15:58:51 -0400. Do not edit! */ +/* auto-generated on 2024-12-18 09:44:34 -0500. Do not edit! */ /* begin file src/idna.cpp */ /* begin file src/unicode_transcoding.cpp */ @@ -325,7 +326,7 @@ size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) { #include /* begin file src/mapping_tables.cpp */ -// IDNA 15.0.0 +// IDNA 15.1.0 // clang-format off #ifndef ADA_IDNA_TABLES_H @@ -334,7 +335,7 @@ size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) { namespace ada::idna { -const uint32_t mappings[5164] = +const uint32_t mappings[5165] = { 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, @@ -387,7 +388,7 @@ const uint32_t mappings[5164] = 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, 115, 115, 7841, + 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, @@ -667,56 +668,56 @@ const uint32_t mappings[5164] = 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, 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, 23304, 23358, 137672, 23491, 23512, 23539, 138008, - 23551, 23558, 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, 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, - 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, 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, + 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, 23304, 23358, 137672, 23491, 23512, 23539, + 138008, 23551, 23558, 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, 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, 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, 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[8000][2] = +const uint32_t table[8002][2] = { {0, 1}, {65, 16777219}, {66, 16777475}, {67, 16777731}, {68, 16777987}, {69, 16778243}, {70, 16778499}, {71, 16778755}, @@ -1128,150 +1129,150 @@ const uint32_t table[8000][2] = {7818, 16973315}, {7819, 1}, {7820, 16973571}, {7821, 1}, {7822, 16973827}, {7823, 1}, {7824, 16974083}, {7825, 1}, {7826, 16974339}, {7827, 1}, {7828, 16974595}, {7829, 1}, - {7834, 33752067}, {7835, 16967939}, {7836, 1}, {7838, 33752579}, - {7839, 1}, {7840, 16975875}, {7841, 1}, {7842, 16976131}, - {7843, 1}, {7844, 16976387}, {7845, 1}, {7846, 16976643}, - {7847, 1}, {7848, 16976899}, {7849, 1}, {7850, 16977155}, - {7851, 1}, {7852, 16977411}, {7853, 1}, {7854, 16977667}, - {7855, 1}, {7856, 16977923}, {7857, 1}, {7858, 16978179}, - {7859, 1}, {7860, 16978435}, {7861, 1}, {7862, 16978691}, - {7863, 1}, {7864, 16978947}, {7865, 1}, {7866, 16979203}, - {7867, 1}, {7868, 16979459}, {7869, 1}, {7870, 16979715}, - {7871, 1}, {7872, 16979971}, {7873, 1}, {7874, 16980227}, - {7875, 1}, {7876, 16980483}, {7877, 1}, {7878, 16980739}, - {7879, 1}, {7880, 16980995}, {7881, 1}, {7882, 16981251}, - {7883, 1}, {7884, 16981507}, {7885, 1}, {7886, 16981763}, - {7887, 1}, {7888, 16982019}, {7889, 1}, {7890, 16982275}, - {7891, 1}, {7892, 16982531}, {7893, 1}, {7894, 16982787}, - {7895, 1}, {7896, 16983043}, {7897, 1}, {7898, 16983299}, - {7899, 1}, {7900, 16983555}, {7901, 1}, {7902, 16983811}, - {7903, 1}, {7904, 16984067}, {7905, 1}, {7906, 16984323}, - {7907, 1}, {7908, 16984579}, {7909, 1}, {7910, 16984835}, - {7911, 1}, {7912, 16985091}, {7913, 1}, {7914, 16985347}, - {7915, 1}, {7916, 16985603}, {7917, 1}, {7918, 16985859}, - {7919, 1}, {7920, 16986115}, {7921, 1}, {7922, 16986371}, - {7923, 1}, {7924, 16986627}, {7925, 1}, {7926, 16986883}, - {7927, 1}, {7928, 16987139}, {7929, 1}, {7930, 16987395}, - {7931, 1}, {7932, 16987651}, {7933, 1}, {7934, 16987907}, - {7935, 1}, {7944, 16988163}, {7945, 16988419}, {7946, 16988675}, - {7947, 16988931}, {7948, 16989187}, {7949, 16989443}, {7950, 16989699}, - {7951, 16989955}, {7952, 1}, {7958, 2}, {7960, 16990211}, - {7961, 16990467}, {7962, 16990723}, {7963, 16990979}, {7964, 16991235}, - {7965, 16991491}, {7966, 2}, {7968, 1}, {7976, 16991747}, - {7977, 16992003}, {7978, 16992259}, {7979, 16992515}, {7980, 16992771}, - {7981, 16993027}, {7982, 16993283}, {7983, 16993539}, {7984, 1}, - {7992, 16993795}, {7993, 16994051}, {7994, 16994307}, {7995, 16994563}, - {7996, 16994819}, {7997, 16995075}, {7998, 16995331}, {7999, 16995587}, - {8000, 1}, {8006, 2}, {8008, 16995843}, {8009, 16996099}, - {8010, 16996355}, {8011, 16996611}, {8012, 16996867}, {8013, 16997123}, - {8014, 2}, {8016, 1}, {8024, 2}, {8025, 16997379}, - {8026, 2}, {8027, 16997635}, {8028, 2}, {8029, 16997891}, - {8030, 2}, {8031, 16998147}, {8032, 1}, {8040, 16998403}, - {8041, 16998659}, {8042, 16998915}, {8043, 16999171}, {8044, 16999427}, - {8045, 16999683}, {8046, 16999939}, {8047, 17000195}, {8048, 1}, + {7834, 33752067}, {7835, 16967939}, {7836, 1}, {7838, 16975363}, + {7839, 1}, {7840, 16975619}, {7841, 1}, {7842, 16975875}, + {7843, 1}, {7844, 16976131}, {7845, 1}, {7846, 16976387}, + {7847, 1}, {7848, 16976643}, {7849, 1}, {7850, 16976899}, + {7851, 1}, {7852, 16977155}, {7853, 1}, {7854, 16977411}, + {7855, 1}, {7856, 16977667}, {7857, 1}, {7858, 16977923}, + {7859, 1}, {7860, 16978179}, {7861, 1}, {7862, 16978435}, + {7863, 1}, {7864, 16978691}, {7865, 1}, {7866, 16978947}, + {7867, 1}, {7868, 16979203}, {7869, 1}, {7870, 16979459}, + {7871, 1}, {7872, 16979715}, {7873, 1}, {7874, 16979971}, + {7875, 1}, {7876, 16980227}, {7877, 1}, {7878, 16980483}, + {7879, 1}, {7880, 16980739}, {7881, 1}, {7882, 16980995}, + {7883, 1}, {7884, 16981251}, {7885, 1}, {7886, 16981507}, + {7887, 1}, {7888, 16981763}, {7889, 1}, {7890, 16982019}, + {7891, 1}, {7892, 16982275}, {7893, 1}, {7894, 16982531}, + {7895, 1}, {7896, 16982787}, {7897, 1}, {7898, 16983043}, + {7899, 1}, {7900, 16983299}, {7901, 1}, {7902, 16983555}, + {7903, 1}, {7904, 16983811}, {7905, 1}, {7906, 16984067}, + {7907, 1}, {7908, 16984323}, {7909, 1}, {7910, 16984579}, + {7911, 1}, {7912, 16984835}, {7913, 1}, {7914, 16985091}, + {7915, 1}, {7916, 16985347}, {7917, 1}, {7918, 16985603}, + {7919, 1}, {7920, 16985859}, {7921, 1}, {7922, 16986115}, + {7923, 1}, {7924, 16986371}, {7925, 1}, {7926, 16986627}, + {7927, 1}, {7928, 16986883}, {7929, 1}, {7930, 16987139}, + {7931, 1}, {7932, 16987395}, {7933, 1}, {7934, 16987651}, + {7935, 1}, {7944, 16987907}, {7945, 16988163}, {7946, 16988419}, + {7947, 16988675}, {7948, 16988931}, {7949, 16989187}, {7950, 16989443}, + {7951, 16989699}, {7952, 1}, {7958, 2}, {7960, 16989955}, + {7961, 16990211}, {7962, 16990467}, {7963, 16990723}, {7964, 16990979}, + {7965, 16991235}, {7966, 2}, {7968, 1}, {7976, 16991491}, + {7977, 16991747}, {7978, 16992003}, {7979, 16992259}, {7980, 16992515}, + {7981, 16992771}, {7982, 16993027}, {7983, 16993283}, {7984, 1}, + {7992, 16993539}, {7993, 16993795}, {7994, 16994051}, {7995, 16994307}, + {7996, 16994563}, {7997, 16994819}, {7998, 16995075}, {7999, 16995331}, + {8000, 1}, {8006, 2}, {8008, 16995587}, {8009, 16995843}, + {8010, 16996099}, {8011, 16996355}, {8012, 16996611}, {8013, 16996867}, + {8014, 2}, {8016, 1}, {8024, 2}, {8025, 16997123}, + {8026, 2}, {8027, 16997379}, {8028, 2}, {8029, 16997635}, + {8030, 2}, {8031, 16997891}, {8032, 1}, {8040, 16998147}, + {8041, 16998403}, {8042, 16998659}, {8043, 16998915}, {8044, 16999171}, + {8045, 16999427}, {8046, 16999683}, {8047, 16999939}, {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, 33777667}, {8065, 33778179}, - {8066, 33778691}, {8067, 33779203}, {8068, 33779715}, {8069, 33780227}, - {8070, 33780739}, {8071, 33781251}, {8072, 33777667}, {8073, 33778179}, - {8074, 33778691}, {8075, 33779203}, {8076, 33779715}, {8077, 33780227}, - {8078, 33780739}, {8079, 33781251}, {8080, 33781763}, {8081, 33782275}, - {8082, 33782787}, {8083, 33783299}, {8084, 33783811}, {8085, 33784323}, - {8086, 33784835}, {8087, 33785347}, {8088, 33781763}, {8089, 33782275}, - {8090, 33782787}, {8091, 33783299}, {8092, 33783811}, {8093, 33784323}, - {8094, 33784835}, {8095, 33785347}, {8096, 33785859}, {8097, 33786371}, - {8098, 33786883}, {8099, 33787395}, {8100, 33787907}, {8101, 33788419}, - {8102, 33788931}, {8103, 33789443}, {8104, 33785859}, {8105, 33786371}, - {8106, 33786883}, {8107, 33787395}, {8108, 33787907}, {8109, 33788419}, - {8110, 33788931}, {8111, 33789443}, {8112, 1}, {8114, 33789955}, - {8115, 33790467}, {8116, 33790979}, {8117, 2}, {8118, 1}, - {8119, 33791491}, {8120, 17014787}, {8121, 17015043}, {8122, 17012739}, - {8123, 16849923}, {8124, 33790467}, {8125, 33792515}, {8126, 16846851}, - {8127, 33792515}, {8128, 33793027}, {8129, 50570755}, {8130, 33794307}, - {8131, 33794819}, {8132, 33795331}, {8133, 2}, {8134, 1}, - {8135, 33795843}, {8136, 17019139}, {8137, 16850179}, {8138, 17017091}, - {8139, 16850435}, {8140, 33794819}, {8141, 50573827}, {8142, 50574595}, - {8143, 50575363}, {8144, 1}, {8147, 17021699}, {8148, 2}, - {8150, 1}, {8152, 17021955}, {8153, 17022211}, {8154, 17022467}, - {8155, 16850691}, {8156, 2}, {8157, 50577155}, {8158, 50577923}, - {8159, 50578691}, {8160, 1}, {8163, 17025027}, {8164, 1}, - {8168, 17025283}, {8169, 17025539}, {8170, 17025795}, {8171, 16851203}, - {8172, 17026051}, {8173, 50580739}, {8174, 50403587}, {8175, 17027075}, - {8176, 2}, {8178, 33804547}, {8179, 33805059}, {8180, 33805571}, - {8181, 2}, {8182, 1}, {8183, 33806083}, {8184, 17029379}, - {8185, 16850947}, {8186, 17027331}, {8187, 16851459}, {8188, 33805059}, - {8189, 33562883}, {8190, 33799939}, {8191, 2}, {8192, 16783875}, + {8061, 16851459}, {8062, 2}, {8064, 33777411}, {8065, 33777923}, + {8066, 33778435}, {8067, 33778947}, {8068, 33779459}, {8069, 33779971}, + {8070, 33780483}, {8071, 33780995}, {8072, 33777411}, {8073, 33777923}, + {8074, 33778435}, {8075, 33778947}, {8076, 33779459}, {8077, 33779971}, + {8078, 33780483}, {8079, 33780995}, {8080, 33781507}, {8081, 33782019}, + {8082, 33782531}, {8083, 33783043}, {8084, 33783555}, {8085, 33784067}, + {8086, 33784579}, {8087, 33785091}, {8088, 33781507}, {8089, 33782019}, + {8090, 33782531}, {8091, 33783043}, {8092, 33783555}, {8093, 33784067}, + {8094, 33784579}, {8095, 33785091}, {8096, 33785603}, {8097, 33786115}, + {8098, 33786627}, {8099, 33787139}, {8100, 33787651}, {8101, 33788163}, + {8102, 33788675}, {8103, 33789187}, {8104, 33785603}, {8105, 33786115}, + {8106, 33786627}, {8107, 33787139}, {8108, 33787651}, {8109, 33788163}, + {8110, 33788675}, {8111, 33789187}, {8112, 1}, {8114, 33789699}, + {8115, 33790211}, {8116, 33790723}, {8117, 2}, {8118, 1}, + {8119, 33791235}, {8120, 17014531}, {8121, 17014787}, {8122, 17012483}, + {8123, 16849923}, {8124, 33790211}, {8125, 33792259}, {8126, 16846851}, + {8127, 33792259}, {8128, 33792771}, {8129, 50570499}, {8130, 33794051}, + {8131, 33794563}, {8132, 33795075}, {8133, 2}, {8134, 1}, + {8135, 33795587}, {8136, 17018883}, {8137, 16850179}, {8138, 17016835}, + {8139, 16850435}, {8140, 33794563}, {8141, 50573571}, {8142, 50574339}, + {8143, 50575107}, {8144, 1}, {8147, 17021443}, {8148, 2}, + {8150, 1}, {8152, 17021699}, {8153, 17021955}, {8154, 17022211}, + {8155, 16850691}, {8156, 2}, {8157, 50576899}, {8158, 50577667}, + {8159, 50578435}, {8160, 1}, {8163, 17024771}, {8164, 1}, + {8168, 17025027}, {8169, 17025283}, {8170, 17025539}, {8171, 16851203}, + {8172, 17025795}, {8173, 50580483}, {8174, 50403587}, {8175, 17026819}, + {8176, 2}, {8178, 33804291}, {8179, 33804803}, {8180, 33805315}, + {8181, 2}, {8182, 1}, {8183, 33805827}, {8184, 17029123}, + {8185, 16850947}, {8186, 17027075}, {8187, 16851459}, {8188, 33804803}, + {8189, 33562883}, {8190, 33799683}, {8191, 2}, {8192, 16783875}, {8203, 0}, {8204, 1}, {8206, 2}, {8208, 1}, - {8209, 17029635}, {8210, 1}, {8215, 33807107}, {8216, 1}, + {8209, 17029379}, {8210, 1}, {8215, 33806851}, {8216, 1}, {8228, 2}, {8231, 1}, {8232, 2}, {8239, 16783875}, - {8240, 1}, {8243, 33807619}, {8244, 50585347}, {8245, 1}, - {8246, 33808899}, {8247, 50586627}, {8248, 1}, {8252, 33810179}, - {8253, 1}, {8254, 33810691}, {8255, 1}, {8263, 33811203}, - {8264, 33811715}, {8265, 33812227}, {8266, 1}, {8279, 67362051}, + {8240, 1}, {8243, 33807363}, {8244, 50585091}, {8245, 1}, + {8246, 33808643}, {8247, 50586371}, {8248, 1}, {8252, 33809923}, + {8253, 1}, {8254, 33810435}, {8255, 1}, {8263, 33810947}, + {8264, 33811459}, {8265, 33811971}, {8266, 1}, {8279, 67361795}, {8280, 1}, {8287, 16783875}, {8288, 0}, {8289, 2}, - {8292, 0}, {8293, 2}, {8304, 17035523}, {8305, 16779267}, - {8306, 2}, {8308, 16787715}, {8309, 17035779}, {8310, 17036035}, - {8311, 17036291}, {8312, 17036547}, {8313, 17036803}, {8314, 17037059}, - {8315, 17037315}, {8316, 17037571}, {8317, 17037827}, {8318, 17038083}, - {8319, 16780547}, {8320, 17035523}, {8321, 16786947}, {8322, 16785155}, - {8323, 16785411}, {8324, 16787715}, {8325, 17035779}, {8326, 17036035}, - {8327, 17036291}, {8328, 17036547}, {8329, 17036803}, {8330, 17037059}, - {8331, 17037315}, {8332, 17037571}, {8333, 17037827}, {8334, 17038083}, + {8292, 0}, {8293, 2}, {8304, 17035267}, {8305, 16779267}, + {8306, 2}, {8308, 16787715}, {8309, 17035523}, {8310, 17035779}, + {8311, 17036035}, {8312, 17036291}, {8313, 17036547}, {8314, 17036803}, + {8315, 17037059}, {8316, 17037315}, {8317, 17037571}, {8318, 17037827}, + {8319, 16780547}, {8320, 17035267}, {8321, 16786947}, {8322, 16785155}, + {8323, 16785411}, {8324, 16787715}, {8325, 17035523}, {8326, 17035779}, + {8327, 17036035}, {8328, 17036291}, {8329, 17036547}, {8330, 17036803}, + {8331, 17037059}, {8332, 17037315}, {8333, 17037571}, {8334, 17037827}, {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, 50592771}, {8449, 50593539}, {8450, 16777731}, - {8451, 33817091}, {8452, 1}, {8453, 50594819}, {8454, 50595587}, - {8455, 16816643}, {8456, 1}, {8457, 33819139}, {8458, 16778755}, + {8433, 2}, {8448, 50592515}, {8449, 50593283}, {8450, 16777731}, + {8451, 33816835}, {8452, 1}, {8453, 50594563}, {8454, 50595331}, + {8455, 16816643}, {8456, 1}, {8457, 33818883}, {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, 33819651}, {8481, 50597379}, {8482, 33820931}, {8483, 1}, + {8480, 33819395}, {8481, 50597123}, {8482, 33820675}, {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, 2}, {8499, 16780291}, {8500, 16780803}, - {8501, 17044227}, {8502, 17044483}, {8503, 17044739}, {8504, 17044995}, - {8505, 16779267}, {8506, 1}, {8507, 50599683}, {8508, 16855043}, - {8509, 16852227}, {8511, 16855043}, {8512, 17046019}, {8513, 1}, + {8501, 17043971}, {8502, 17044227}, {8503, 17044483}, {8504, 17044739}, + {8505, 16779267}, {8506, 1}, {8507, 50599427}, {8508, 16855043}, + {8509, 16852227}, {8511, 16855043}, {8512, 17045763}, {8513, 1}, {8517, 16777987}, {8519, 16778243}, {8520, 16779267}, {8521, 16779523}, - {8522, 1}, {8528, 50600707}, {8529, 50601475}, {8530, 67379459}, - {8531, 50603267}, {8532, 50604035}, {8533, 50604803}, {8534, 50605571}, - {8535, 50606339}, {8536, 50607107}, {8537, 50607875}, {8538, 50608643}, - {8539, 50609411}, {8540, 50610179}, {8541, 50610947}, {8542, 50611715}, - {8543, 33564419}, {8544, 16779267}, {8545, 33835267}, {8546, 50612995}, - {8547, 33836547}, {8548, 16782595}, {8549, 33837059}, {8550, 50614787}, - {8551, 67392771}, {8552, 33839363}, {8553, 16783107}, {8554, 33839875}, - {8555, 50617603}, {8556, 16780035}, {8557, 16777731}, {8558, 16777987}, - {8559, 16780291}, {8560, 16779267}, {8561, 33835267}, {8562, 50612483}, - {8563, 33836547}, {8564, 16782595}, {8565, 33837059}, {8566, 50614787}, - {8567, 67392771}, {8568, 33839363}, {8569, 16783107}, {8570, 33839875}, - {8571, 50617603}, {8572, 16780035}, {8573, 16777731}, {8574, 16777987}, + {8522, 1}, {8528, 50600451}, {8529, 50601219}, {8530, 67379203}, + {8531, 50603011}, {8532, 50603779}, {8533, 50604547}, {8534, 50605315}, + {8535, 50606083}, {8536, 50606851}, {8537, 50607619}, {8538, 50608387}, + {8539, 50609155}, {8540, 50609923}, {8541, 50610691}, {8542, 50611459}, + {8543, 33564419}, {8544, 16779267}, {8545, 33835011}, {8546, 50612739}, + {8547, 33836291}, {8548, 16782595}, {8549, 33836803}, {8550, 50614531}, + {8551, 67392515}, {8552, 33839107}, {8553, 16783107}, {8554, 33839619}, + {8555, 50617347}, {8556, 16780035}, {8557, 16777731}, {8558, 16777987}, + {8559, 16780291}, {8560, 16779267}, {8561, 33835011}, {8562, 50612227}, + {8563, 33836291}, {8564, 16782595}, {8565, 33836803}, {8566, 50614531}, + {8567, 67392515}, {8568, 33839107}, {8569, 16783107}, {8570, 33839619}, + {8571, 50617347}, {8572, 16780035}, {8573, 16777731}, {8574, 16777987}, {8575, 16780291}, {8576, 1}, {8579, 2}, {8580, 1}, - {8585, 50618371}, {8586, 1}, {8588, 2}, {8592, 1}, - {8748, 33841923}, {8749, 50619651}, {8750, 1}, {8751, 33843203}, - {8752, 50620931}, {8753, 1}, {9001, 17067267}, {9002, 17067523}, + {8585, 50618115}, {8586, 1}, {8588, 2}, {8592, 1}, + {8748, 33841667}, {8749, 50619395}, {8750, 1}, {8751, 33842947}, + {8752, 50620675}, {8753, 1}, {9001, 17067011}, {9002, 17067267}, {9003, 1}, {9255, 2}, {9280, 1}, {9291, 2}, {9312, 16786947}, {9313, 16785155}, {9314, 16785411}, {9315, 16787715}, - {9316, 17035779}, {9317, 17036035}, {9318, 17036291}, {9319, 17036547}, - {9320, 17036803}, {9321, 33825539}, {9322, 33564163}, {9323, 33844995}, - {9324, 33845507}, {9325, 33846019}, {9326, 33846531}, {9327, 33847043}, - {9328, 33847555}, {9329, 33848067}, {9330, 33848579}, {9331, 33849091}, - {9332, 50626819}, {9333, 50627587}, {9334, 50628355}, {9335, 50629123}, - {9336, 50629891}, {9337, 50630659}, {9338, 50631427}, {9339, 50632195}, - {9340, 50632963}, {9341, 67410947}, {9342, 67411971}, {9343, 67412995}, - {9344, 67414019}, {9345, 67415043}, {9346, 67416067}, {9347, 67417091}, - {9348, 67418115}, {9349, 67419139}, {9350, 67420163}, {9351, 67421187}, - {9352, 2}, {9372, 50644995}, {9373, 50645763}, {9374, 50646531}, - {9375, 50647299}, {9376, 50648067}, {9377, 50648835}, {9378, 50649603}, - {9379, 50650371}, {9380, 50651139}, {9381, 50651907}, {9382, 50652675}, - {9383, 50653443}, {9384, 50654211}, {9385, 50654979}, {9386, 50655747}, - {9387, 50656515}, {9388, 50657283}, {9389, 50658051}, {9390, 50658819}, - {9391, 50659587}, {9392, 50660355}, {9393, 50661123}, {9394, 50661891}, - {9395, 50662659}, {9396, 50663427}, {9397, 50664195}, {9398, 16777219}, + {9316, 17035523}, {9317, 17035779}, {9318, 17036035}, {9319, 17036291}, + {9320, 17036547}, {9321, 33825283}, {9322, 33564163}, {9323, 33844739}, + {9324, 33845251}, {9325, 33845763}, {9326, 33846275}, {9327, 33846787}, + {9328, 33847299}, {9329, 33847811}, {9330, 33848323}, {9331, 33848835}, + {9332, 50626563}, {9333, 50627331}, {9334, 50628099}, {9335, 50628867}, + {9336, 50629635}, {9337, 50630403}, {9338, 50631171}, {9339, 50631939}, + {9340, 50632707}, {9341, 67410691}, {9342, 67411715}, {9343, 67412739}, + {9344, 67413763}, {9345, 67414787}, {9346, 67415811}, {9347, 67416835}, + {9348, 67417859}, {9349, 67418883}, {9350, 67419907}, {9351, 67420931}, + {9352, 2}, {9372, 50644739}, {9373, 50645507}, {9374, 50646275}, + {9375, 50647043}, {9376, 50647811}, {9377, 50648579}, {9378, 50649347}, + {9379, 50650115}, {9380, 50650883}, {9381, 50651651}, {9382, 50652419}, + {9383, 50653187}, {9384, 50653955}, {9385, 50654723}, {9386, 50655491}, + {9387, 50656259}, {9388, 50657027}, {9389, 50657795}, {9390, 50658563}, + {9391, 50659331}, {9392, 50660099}, {9393, 50660867}, {9394, 50661635}, + {9395, 50662403}, {9396, 50663171}, {9397, 50663939}, {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}, @@ -1284,343 +1285,343 @@ const uint32_t table[8000][2] = {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, 17035523}, - {9451, 1}, {10764, 67396355}, {10765, 1}, {10868, 50664963}, - {10869, 33888515}, {10870, 50665475}, {10871, 1}, {10972, 33889027}, + {9447, 16783107}, {9448, 16783363}, {9449, 16783619}, {9450, 17035267}, + {9451, 1}, {10764, 67396099}, {10765, 1}, {10868, 50664707}, + {10869, 33888259}, {10870, 50665219}, {10871, 1}, {10972, 33888771}, {10973, 1}, {11124, 2}, {11126, 1}, {11158, 2}, - {11159, 1}, {11264, 17112323}, {11265, 17112579}, {11266, 17112835}, - {11267, 17113091}, {11268, 17113347}, {11269, 17113603}, {11270, 17113859}, - {11271, 17114115}, {11272, 17114371}, {11273, 17114627}, {11274, 17114883}, - {11275, 17115139}, {11276, 17115395}, {11277, 17115651}, {11278, 17115907}, - {11279, 17116163}, {11280, 17116419}, {11281, 17116675}, {11282, 17116931}, - {11283, 17117187}, {11284, 17117443}, {11285, 17117699}, {11286, 17117955}, - {11287, 17118211}, {11288, 17118467}, {11289, 17118723}, {11290, 17118979}, - {11291, 17119235}, {11292, 17119491}, {11293, 17119747}, {11294, 17120003}, - {11295, 17120259}, {11296, 17120515}, {11297, 17120771}, {11298, 17121027}, - {11299, 17121283}, {11300, 17121539}, {11301, 17121795}, {11302, 17122051}, - {11303, 17122307}, {11304, 17122563}, {11305, 17122819}, {11306, 17123075}, - {11307, 17123331}, {11308, 17123587}, {11309, 17123843}, {11310, 17124099}, - {11311, 17124355}, {11312, 1}, {11360, 17124611}, {11361, 1}, - {11362, 17124867}, {11363, 17125123}, {11364, 17125379}, {11365, 1}, - {11367, 17125635}, {11368, 1}, {11369, 17125891}, {11370, 1}, - {11371, 17126147}, {11372, 1}, {11373, 16948483}, {11374, 16953091}, - {11375, 16948227}, {11376, 16950275}, {11377, 1}, {11378, 17126403}, - {11379, 1}, {11381, 17126659}, {11382, 1}, {11388, 16779523}, - {11389, 16782595}, {11390, 17126915}, {11391, 17127171}, {11392, 17127427}, - {11393, 1}, {11394, 17127683}, {11395, 1}, {11396, 17127939}, - {11397, 1}, {11398, 17128195}, {11399, 1}, {11400, 17128451}, - {11401, 1}, {11402, 17128707}, {11403, 1}, {11404, 17128963}, - {11405, 1}, {11406, 17129219}, {11407, 1}, {11408, 17129475}, - {11409, 1}, {11410, 17129731}, {11411, 1}, {11412, 17129987}, - {11413, 1}, {11414, 17130243}, {11415, 1}, {11416, 17130499}, - {11417, 1}, {11418, 17130755}, {11419, 1}, {11420, 17131011}, - {11421, 1}, {11422, 17131267}, {11423, 1}, {11424, 17131523}, - {11425, 1}, {11426, 17131779}, {11427, 1}, {11428, 17132035}, - {11429, 1}, {11430, 17132291}, {11431, 1}, {11432, 17132547}, - {11433, 1}, {11434, 17132803}, {11435, 1}, {11436, 17133059}, - {11437, 1}, {11438, 17133315}, {11439, 1}, {11440, 17133571}, - {11441, 1}, {11442, 17133827}, {11443, 1}, {11444, 17134083}, - {11445, 1}, {11446, 17134339}, {11447, 1}, {11448, 17134595}, - {11449, 1}, {11450, 17134851}, {11451, 1}, {11452, 17135107}, - {11453, 1}, {11454, 17135363}, {11455, 1}, {11456, 17135619}, - {11457, 1}, {11458, 17135875}, {11459, 1}, {11460, 17136131}, - {11461, 1}, {11462, 17136387}, {11463, 1}, {11464, 17136643}, - {11465, 1}, {11466, 17136899}, {11467, 1}, {11468, 17137155}, - {11469, 1}, {11470, 17137411}, {11471, 1}, {11472, 17137667}, - {11473, 1}, {11474, 17137923}, {11475, 1}, {11476, 17138179}, - {11477, 1}, {11478, 17138435}, {11479, 1}, {11480, 17138691}, - {11481, 1}, {11482, 17138947}, {11483, 1}, {11484, 17139203}, - {11485, 1}, {11486, 17139459}, {11487, 1}, {11488, 17139715}, - {11489, 1}, {11490, 17139971}, {11491, 1}, {11499, 17140227}, - {11500, 1}, {11501, 17140483}, {11502, 1}, {11506, 17140739}, + {11159, 1}, {11264, 17112067}, {11265, 17112323}, {11266, 17112579}, + {11267, 17112835}, {11268, 17113091}, {11269, 17113347}, {11270, 17113603}, + {11271, 17113859}, {11272, 17114115}, {11273, 17114371}, {11274, 17114627}, + {11275, 17114883}, {11276, 17115139}, {11277, 17115395}, {11278, 17115651}, + {11279, 17115907}, {11280, 17116163}, {11281, 17116419}, {11282, 17116675}, + {11283, 17116931}, {11284, 17117187}, {11285, 17117443}, {11286, 17117699}, + {11287, 17117955}, {11288, 17118211}, {11289, 17118467}, {11290, 17118723}, + {11291, 17118979}, {11292, 17119235}, {11293, 17119491}, {11294, 17119747}, + {11295, 17120003}, {11296, 17120259}, {11297, 17120515}, {11298, 17120771}, + {11299, 17121027}, {11300, 17121283}, {11301, 17121539}, {11302, 17121795}, + {11303, 17122051}, {11304, 17122307}, {11305, 17122563}, {11306, 17122819}, + {11307, 17123075}, {11308, 17123331}, {11309, 17123587}, {11310, 17123843}, + {11311, 17124099}, {11312, 1}, {11360, 17124355}, {11361, 1}, + {11362, 17124611}, {11363, 17124867}, {11364, 17125123}, {11365, 1}, + {11367, 17125379}, {11368, 1}, {11369, 17125635}, {11370, 1}, + {11371, 17125891}, {11372, 1}, {11373, 16948483}, {11374, 16953091}, + {11375, 16948227}, {11376, 16950275}, {11377, 1}, {11378, 17126147}, + {11379, 1}, {11381, 17126403}, {11382, 1}, {11388, 16779523}, + {11389, 16782595}, {11390, 17126659}, {11391, 17126915}, {11392, 17127171}, + {11393, 1}, {11394, 17127427}, {11395, 1}, {11396, 17127683}, + {11397, 1}, {11398, 17127939}, {11399, 1}, {11400, 17128195}, + {11401, 1}, {11402, 17128451}, {11403, 1}, {11404, 17128707}, + {11405, 1}, {11406, 17128963}, {11407, 1}, {11408, 17129219}, + {11409, 1}, {11410, 17129475}, {11411, 1}, {11412, 17129731}, + {11413, 1}, {11414, 17129987}, {11415, 1}, {11416, 17130243}, + {11417, 1}, {11418, 17130499}, {11419, 1}, {11420, 17130755}, + {11421, 1}, {11422, 17131011}, {11423, 1}, {11424, 17131267}, + {11425, 1}, {11426, 17131523}, {11427, 1}, {11428, 17131779}, + {11429, 1}, {11430, 17132035}, {11431, 1}, {11432, 17132291}, + {11433, 1}, {11434, 17132547}, {11435, 1}, {11436, 17132803}, + {11437, 1}, {11438, 17133059}, {11439, 1}, {11440, 17133315}, + {11441, 1}, {11442, 17133571}, {11443, 1}, {11444, 17133827}, + {11445, 1}, {11446, 17134083}, {11447, 1}, {11448, 17134339}, + {11449, 1}, {11450, 17134595}, {11451, 1}, {11452, 17134851}, + {11453, 1}, {11454, 17135107}, {11455, 1}, {11456, 17135363}, + {11457, 1}, {11458, 17135619}, {11459, 1}, {11460, 17135875}, + {11461, 1}, {11462, 17136131}, {11463, 1}, {11464, 17136387}, + {11465, 1}, {11466, 17136643}, {11467, 1}, {11468, 17136899}, + {11469, 1}, {11470, 17137155}, {11471, 1}, {11472, 17137411}, + {11473, 1}, {11474, 17137667}, {11475, 1}, {11476, 17137923}, + {11477, 1}, {11478, 17138179}, {11479, 1}, {11480, 17138435}, + {11481, 1}, {11482, 17138691}, {11483, 1}, {11484, 17138947}, + {11485, 1}, {11486, 17139203}, {11487, 1}, {11488, 17139459}, + {11489, 1}, {11490, 17139715}, {11491, 1}, {11499, 17139971}, + {11500, 1}, {11501, 17140227}, {11502, 1}, {11506, 17140483}, {11507, 1}, {11508, 2}, {11513, 1}, {11558, 2}, {11559, 1}, {11560, 2}, {11565, 1}, {11566, 2}, - {11568, 1}, {11624, 2}, {11631, 17140995}, {11632, 1}, + {11568, 1}, {11624, 2}, {11631, 17140739}, {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, 17141251}, {11936, 1}, {12019, 17141507}, {12020, 2}, - {12032, 17141763}, {12033, 17142019}, {12034, 17142275}, {12035, 17142531}, - {12036, 17142787}, {12037, 17143043}, {12038, 17143299}, {12039, 17143555}, - {12040, 17143811}, {12041, 17144067}, {12042, 17144323}, {12043, 17144579}, - {12044, 17144835}, {12045, 17145091}, {12046, 17145347}, {12047, 17145603}, - {12048, 17145859}, {12049, 17146115}, {12050, 17146371}, {12051, 17146627}, - {12052, 17146883}, {12053, 17147139}, {12054, 17147395}, {12055, 17147651}, - {12056, 17147907}, {12057, 17148163}, {12058, 17148419}, {12059, 17148675}, - {12060, 17148931}, {12061, 17149187}, {12062, 17149443}, {12063, 17149699}, - {12064, 17149955}, {12065, 17150211}, {12066, 17150467}, {12067, 17150723}, - {12068, 17150979}, {12069, 17151235}, {12070, 17151491}, {12071, 17151747}, - {12072, 17152003}, {12073, 17152259}, {12074, 17152515}, {12075, 17152771}, - {12076, 17153027}, {12077, 17153283}, {12078, 17153539}, {12079, 17153795}, - {12080, 17154051}, {12081, 17154307}, {12082, 17154563}, {12083, 17154819}, - {12084, 17155075}, {12085, 17155331}, {12086, 17155587}, {12087, 17155843}, - {12088, 17156099}, {12089, 17156355}, {12090, 17156611}, {12091, 17156867}, - {12092, 17157123}, {12093, 17157379}, {12094, 17157635}, {12095, 17157891}, - {12096, 17158147}, {12097, 17158403}, {12098, 17158659}, {12099, 17158915}, - {12100, 17159171}, {12101, 17159427}, {12102, 17159683}, {12103, 17159939}, - {12104, 17160195}, {12105, 17160451}, {12106, 17160707}, {12107, 17160963}, - {12108, 17161219}, {12109, 17161475}, {12110, 17161731}, {12111, 17161987}, - {12112, 17162243}, {12113, 17162499}, {12114, 17162755}, {12115, 17163011}, - {12116, 17163267}, {12117, 17163523}, {12118, 17163779}, {12119, 17164035}, - {12120, 17164291}, {12121, 17164547}, {12122, 17164803}, {12123, 17165059}, - {12124, 17165315}, {12125, 17165571}, {12126, 17165827}, {12127, 17166083}, - {12128, 17166339}, {12129, 17166595}, {12130, 17166851}, {12131, 17167107}, - {12132, 17167363}, {12133, 17167619}, {12134, 17167875}, {12135, 17168131}, - {12136, 17168387}, {12137, 17168643}, {12138, 17168899}, {12139, 17169155}, - {12140, 17169411}, {12141, 17169667}, {12142, 17169923}, {12143, 17170179}, - {12144, 17170435}, {12145, 17170691}, {12146, 17170947}, {12147, 17171203}, - {12148, 17171459}, {12149, 17171715}, {12150, 17171971}, {12151, 17172227}, - {12152, 17172483}, {12153, 17172739}, {12154, 17172995}, {12155, 17173251}, - {12156, 17173507}, {12157, 17173763}, {12158, 17174019}, {12159, 17174275}, - {12160, 17174531}, {12161, 17174787}, {12162, 17175043}, {12163, 17175299}, - {12164, 17175555}, {12165, 17175811}, {12166, 17176067}, {12167, 17176323}, - {12168, 17176579}, {12169, 17176835}, {12170, 17177091}, {12171, 17177347}, - {12172, 17177603}, {12173, 17177859}, {12174, 17178115}, {12175, 17178371}, - {12176, 17178627}, {12177, 17178883}, {12178, 17179139}, {12179, 17179395}, - {12180, 17179651}, {12181, 17179907}, {12182, 17180163}, {12183, 17180419}, - {12184, 17180675}, {12185, 17180931}, {12186, 17181187}, {12187, 17181443}, - {12188, 17181699}, {12189, 17181955}, {12190, 17182211}, {12191, 17182467}, - {12192, 17182723}, {12193, 17182979}, {12194, 17183235}, {12195, 17183491}, - {12196, 17183747}, {12197, 17184003}, {12198, 17184259}, {12199, 17184515}, - {12200, 17184771}, {12201, 17185027}, {12202, 17185283}, {12203, 17185539}, - {12204, 17185795}, {12205, 17186051}, {12206, 17186307}, {12207, 17186563}, - {12208, 17186819}, {12209, 17187075}, {12210, 17187331}, {12211, 17187587}, - {12212, 17187843}, {12213, 17188099}, {12214, 17188355}, {12215, 17188611}, - {12216, 17188867}, {12217, 17189123}, {12218, 17189379}, {12219, 17189635}, - {12220, 17189891}, {12221, 17190147}, {12222, 17190403}, {12223, 17190659}, - {12224, 17190915}, {12225, 17191171}, {12226, 17191427}, {12227, 17191683}, - {12228, 17191939}, {12229, 17192195}, {12230, 17192451}, {12231, 17192707}, - {12232, 17192963}, {12233, 17193219}, {12234, 17193475}, {12235, 17193731}, - {12236, 17193987}, {12237, 17194243}, {12238, 17194499}, {12239, 17194755}, - {12240, 17195011}, {12241, 17195267}, {12242, 17195523}, {12243, 17195779}, - {12244, 17196035}, {12245, 17196291}, {12246, 2}, {12288, 16783875}, - {12289, 1}, {12290, 17196547}, {12291, 1}, {12342, 17196803}, - {12343, 1}, {12344, 17147651}, {12345, 17197059}, {12346, 17197315}, + {11935, 17140995}, {11936, 1}, {12019, 17141251}, {12020, 2}, + {12032, 17141507}, {12033, 17141763}, {12034, 17142019}, {12035, 17142275}, + {12036, 17142531}, {12037, 17142787}, {12038, 17143043}, {12039, 17143299}, + {12040, 17143555}, {12041, 17143811}, {12042, 17144067}, {12043, 17144323}, + {12044, 17144579}, {12045, 17144835}, {12046, 17145091}, {12047, 17145347}, + {12048, 17145603}, {12049, 17145859}, {12050, 17146115}, {12051, 17146371}, + {12052, 17146627}, {12053, 17146883}, {12054, 17147139}, {12055, 17147395}, + {12056, 17147651}, {12057, 17147907}, {12058, 17148163}, {12059, 17148419}, + {12060, 17148675}, {12061, 17148931}, {12062, 17149187}, {12063, 17149443}, + {12064, 17149699}, {12065, 17149955}, {12066, 17150211}, {12067, 17150467}, + {12068, 17150723}, {12069, 17150979}, {12070, 17151235}, {12071, 17151491}, + {12072, 17151747}, {12073, 17152003}, {12074, 17152259}, {12075, 17152515}, + {12076, 17152771}, {12077, 17153027}, {12078, 17153283}, {12079, 17153539}, + {12080, 17153795}, {12081, 17154051}, {12082, 17154307}, {12083, 17154563}, + {12084, 17154819}, {12085, 17155075}, {12086, 17155331}, {12087, 17155587}, + {12088, 17155843}, {12089, 17156099}, {12090, 17156355}, {12091, 17156611}, + {12092, 17156867}, {12093, 17157123}, {12094, 17157379}, {12095, 17157635}, + {12096, 17157891}, {12097, 17158147}, {12098, 17158403}, {12099, 17158659}, + {12100, 17158915}, {12101, 17159171}, {12102, 17159427}, {12103, 17159683}, + {12104, 17159939}, {12105, 17160195}, {12106, 17160451}, {12107, 17160707}, + {12108, 17160963}, {12109, 17161219}, {12110, 17161475}, {12111, 17161731}, + {12112, 17161987}, {12113, 17162243}, {12114, 17162499}, {12115, 17162755}, + {12116, 17163011}, {12117, 17163267}, {12118, 17163523}, {12119, 17163779}, + {12120, 17164035}, {12121, 17164291}, {12122, 17164547}, {12123, 17164803}, + {12124, 17165059}, {12125, 17165315}, {12126, 17165571}, {12127, 17165827}, + {12128, 17166083}, {12129, 17166339}, {12130, 17166595}, {12131, 17166851}, + {12132, 17167107}, {12133, 17167363}, {12134, 17167619}, {12135, 17167875}, + {12136, 17168131}, {12137, 17168387}, {12138, 17168643}, {12139, 17168899}, + {12140, 17169155}, {12141, 17169411}, {12142, 17169667}, {12143, 17169923}, + {12144, 17170179}, {12145, 17170435}, {12146, 17170691}, {12147, 17170947}, + {12148, 17171203}, {12149, 17171459}, {12150, 17171715}, {12151, 17171971}, + {12152, 17172227}, {12153, 17172483}, {12154, 17172739}, {12155, 17172995}, + {12156, 17173251}, {12157, 17173507}, {12158, 17173763}, {12159, 17174019}, + {12160, 17174275}, {12161, 17174531}, {12162, 17174787}, {12163, 17175043}, + {12164, 17175299}, {12165, 17175555}, {12166, 17175811}, {12167, 17176067}, + {12168, 17176323}, {12169, 17176579}, {12170, 17176835}, {12171, 17177091}, + {12172, 17177347}, {12173, 17177603}, {12174, 17177859}, {12175, 17178115}, + {12176, 17178371}, {12177, 17178627}, {12178, 17178883}, {12179, 17179139}, + {12180, 17179395}, {12181, 17179651}, {12182, 17179907}, {12183, 17180163}, + {12184, 17180419}, {12185, 17180675}, {12186, 17180931}, {12187, 17181187}, + {12188, 17181443}, {12189, 17181699}, {12190, 17181955}, {12191, 17182211}, + {12192, 17182467}, {12193, 17182723}, {12194, 17182979}, {12195, 17183235}, + {12196, 17183491}, {12197, 17183747}, {12198, 17184003}, {12199, 17184259}, + {12200, 17184515}, {12201, 17184771}, {12202, 17185027}, {12203, 17185283}, + {12204, 17185539}, {12205, 17185795}, {12206, 17186051}, {12207, 17186307}, + {12208, 17186563}, {12209, 17186819}, {12210, 17187075}, {12211, 17187331}, + {12212, 17187587}, {12213, 17187843}, {12214, 17188099}, {12215, 17188355}, + {12216, 17188611}, {12217, 17188867}, {12218, 17189123}, {12219, 17189379}, + {12220, 17189635}, {12221, 17189891}, {12222, 17190147}, {12223, 17190403}, + {12224, 17190659}, {12225, 17190915}, {12226, 17191171}, {12227, 17191427}, + {12228, 17191683}, {12229, 17191939}, {12230, 17192195}, {12231, 17192451}, + {12232, 17192707}, {12233, 17192963}, {12234, 17193219}, {12235, 17193475}, + {12236, 17193731}, {12237, 17193987}, {12238, 17194243}, {12239, 17194499}, + {12240, 17194755}, {12241, 17195011}, {12242, 17195267}, {12243, 17195523}, + {12244, 17195779}, {12245, 17196035}, {12246, 2}, {12288, 16783875}, + {12289, 1}, {12290, 17196291}, {12291, 1}, {12342, 17196547}, + {12343, 1}, {12344, 17147395}, {12345, 17196803}, {12346, 17197059}, {12347, 1}, {12352, 2}, {12353, 1}, {12439, 2}, - {12441, 1}, {12443, 33974787}, {12444, 33975299}, {12445, 1}, - {12447, 33975811}, {12448, 1}, {12543, 33976323}, {12544, 2}, - {12549, 1}, {12592, 2}, {12593, 17199619}, {12594, 17199875}, - {12595, 17200131}, {12596, 17200387}, {12597, 17200643}, {12598, 17200899}, - {12599, 17201155}, {12600, 17201411}, {12601, 17201667}, {12602, 17201923}, - {12603, 17202179}, {12604, 17202435}, {12605, 17202691}, {12606, 17202947}, - {12607, 17203203}, {12608, 17203459}, {12609, 17203715}, {12610, 17203971}, - {12611, 17204227}, {12612, 17204483}, {12613, 17204739}, {12614, 17204995}, - {12615, 17205251}, {12616, 17205507}, {12617, 17205763}, {12618, 17206019}, - {12619, 17206275}, {12620, 17206531}, {12621, 17206787}, {12622, 17207043}, - {12623, 17207299}, {12624, 17207555}, {12625, 17207811}, {12626, 17208067}, - {12627, 17208323}, {12628, 17208579}, {12629, 17208835}, {12630, 17209091}, - {12631, 17209347}, {12632, 17209603}, {12633, 17209859}, {12634, 17210115}, - {12635, 17210371}, {12636, 17210627}, {12637, 17210883}, {12638, 17211139}, - {12639, 17211395}, {12640, 17211651}, {12641, 17211907}, {12642, 17212163}, - {12643, 17212419}, {12644, 2}, {12645, 17212675}, {12646, 17212931}, - {12647, 17213187}, {12648, 17213443}, {12649, 17213699}, {12650, 17213955}, - {12651, 17214211}, {12652, 17214467}, {12653, 17214723}, {12654, 17214979}, - {12655, 17215235}, {12656, 17215491}, {12657, 17215747}, {12658, 17216003}, - {12659, 17216259}, {12660, 17216515}, {12661, 17216771}, {12662, 17217027}, - {12663, 17217283}, {12664, 17217539}, {12665, 17217795}, {12666, 17218051}, - {12667, 17218307}, {12668, 17218563}, {12669, 17218819}, {12670, 17219075}, - {12671, 17219331}, {12672, 17219587}, {12673, 17219843}, {12674, 17220099}, - {12675, 17220355}, {12676, 17220611}, {12677, 17220867}, {12678, 17221123}, - {12679, 17221379}, {12680, 17221635}, {12681, 17221891}, {12682, 17222147}, - {12683, 17222403}, {12684, 17222659}, {12685, 17222915}, {12686, 17223171}, - {12687, 2}, {12688, 1}, {12690, 17141763}, {12691, 17143299}, - {12692, 17223427}, {12693, 17223683}, {12694, 17223939}, {12695, 17224195}, - {12696, 17224451}, {12697, 17224707}, {12698, 17142787}, {12699, 17224963}, - {12700, 17225219}, {12701, 17225475}, {12702, 17225731}, {12703, 17143811}, - {12704, 1}, {12772, 2}, {12784, 1}, {12800, 50780419}, - {12801, 50781187}, {12802, 50781955}, {12803, 50782723}, {12804, 50783491}, - {12805, 50784259}, {12806, 50785027}, {12807, 50785795}, {12808, 50786563}, - {12809, 50787331}, {12810, 50788099}, {12811, 50788867}, {12812, 50789635}, - {12813, 50790403}, {12814, 50791171}, {12815, 50791939}, {12816, 50792707}, - {12817, 50793475}, {12818, 50794243}, {12819, 50795011}, {12820, 50795779}, - {12821, 50796547}, {12822, 50797315}, {12823, 50798083}, {12824, 50798851}, - {12825, 50799619}, {12826, 50800387}, {12827, 50801155}, {12828, 50801923}, - {12829, 67579907}, {12830, 67580931}, {12831, 2}, {12832, 50804739}, - {12833, 50805507}, {12834, 50806275}, {12835, 50807043}, {12836, 50807811}, - {12837, 50808579}, {12838, 50809347}, {12839, 50810115}, {12840, 50810883}, - {12841, 50811651}, {12842, 50812419}, {12843, 50813187}, {12844, 50813955}, - {12845, 50814723}, {12846, 50815491}, {12847, 50816259}, {12848, 50817027}, - {12849, 50817795}, {12850, 50818563}, {12851, 50819331}, {12852, 50820099}, - {12853, 50820867}, {12854, 50821635}, {12855, 50822403}, {12856, 50823171}, - {12857, 50823939}, {12858, 50824707}, {12859, 50825475}, {12860, 50826243}, - {12861, 50827011}, {12862, 50827779}, {12863, 50828547}, {12864, 50829315}, - {12865, 50830083}, {12866, 50830851}, {12867, 50831619}, {12868, 17277955}, - {12869, 17278211}, {12870, 17158659}, {12871, 17278467}, {12872, 1}, - {12880, 50833155}, {12881, 33845251}, {12882, 34056707}, {12883, 33562371}, - {12884, 34057219}, {12885, 34057731}, {12886, 34058243}, {12887, 34058755}, - {12888, 34059267}, {12889, 34059779}, {12890, 34060291}, {12891, 33827331}, - {12892, 33826563}, {12893, 34060803}, {12894, 34061315}, {12895, 34061827}, - {12896, 17199619}, {12897, 17200387}, {12898, 17201155}, {12899, 17201667}, - {12900, 17203715}, {12901, 17203971}, {12902, 17204739}, {12903, 17205251}, - {12904, 17205507}, {12905, 17206019}, {12906, 17206275}, {12907, 17206531}, - {12908, 17206787}, {12909, 17207043}, {12910, 17236995}, {12911, 17237763}, - {12912, 17238531}, {12913, 17239299}, {12914, 17240067}, {12915, 17240835}, - {12916, 17241603}, {12917, 17242371}, {12918, 17243139}, {12919, 17243907}, - {12920, 17244675}, {12921, 17245443}, {12922, 17246211}, {12923, 17246979}, - {12924, 34062339}, {12925, 34062851}, {12926, 17286147}, {12927, 1}, - {12928, 17141763}, {12929, 17143299}, {12930, 17223427}, {12931, 17223683}, - {12932, 17253635}, {12933, 17254403}, {12934, 17255171}, {12935, 17144579}, - {12936, 17256707}, {12937, 17147651}, {12938, 17160451}, {12939, 17163523}, - {12940, 17163267}, {12941, 17160707}, {12942, 17184259}, {12943, 17149699}, - {12944, 17159939}, {12945, 17263619}, {12946, 17264387}, {12947, 17265155}, - {12948, 17265923}, {12949, 17266691}, {12950, 17267459}, {12951, 17268227}, - {12952, 17268995}, {12953, 17286403}, {12954, 17286659}, {12955, 17151235}, - {12956, 17286915}, {12957, 17287171}, {12958, 17287427}, {12959, 17287683}, - {12960, 17287939}, {12961, 17275907}, {12962, 17288195}, {12963, 17288451}, - {12964, 17223939}, {12965, 17224195}, {12966, 17224451}, {12967, 17288707}, - {12968, 17288963}, {12969, 17289219}, {12970, 17289475}, {12971, 17271299}, - {12972, 17272067}, {12973, 17272835}, {12974, 17273603}, {12975, 17274371}, - {12976, 17289731}, {12977, 34067203}, {12978, 34067715}, {12979, 34068227}, - {12980, 34068739}, {12981, 34069251}, {12982, 33564931}, {12983, 34057475}, - {12984, 34061571}, {12985, 34069763}, {12986, 34070275}, {12987, 34070787}, - {12988, 34071299}, {12989, 34071811}, {12990, 34072323}, {12991, 34072835}, - {12992, 34073347}, {12993, 34073859}, {12994, 34074371}, {12995, 34074883}, - {12996, 34075395}, {12997, 34075907}, {12998, 34076419}, {12999, 34076931}, - {13000, 34077443}, {13001, 50855171}, {13002, 50855939}, {13003, 50856707}, - {13004, 34080259}, {13005, 50857987}, {13006, 34081539}, {13007, 50859267}, - {13008, 17305603}, {13009, 17305859}, {13010, 17306115}, {13011, 17306371}, - {13012, 17306627}, {13013, 17306883}, {13014, 17307139}, {13015, 17307395}, - {13016, 17307651}, {13017, 17199107}, {13018, 17307907}, {13019, 17308163}, - {13020, 17308419}, {13021, 17308675}, {13022, 17308931}, {13023, 17309187}, - {13024, 17309443}, {13025, 17309699}, {13026, 17309955}, {13027, 17199363}, - {13028, 17310211}, {13029, 17310467}, {13030, 17310723}, {13031, 17310979}, - {13032, 17311235}, {13033, 17311491}, {13034, 17311747}, {13035, 17312003}, - {13036, 17312259}, {13037, 17312515}, {13038, 17312771}, {13039, 17313027}, - {13040, 17313283}, {13041, 17313539}, {13042, 17313795}, {13043, 17314051}, - {13044, 17314307}, {13045, 17314563}, {13046, 17314819}, {13047, 17315075}, - {13048, 17315331}, {13049, 17315587}, {13050, 17315843}, {13051, 17316099}, - {13052, 17316355}, {13053, 17316611}, {13054, 17316867}, {13055, 34094339}, - {13056, 67649283}, {13057, 67650307}, {13058, 67651331}, {13059, 50875139}, - {13060, 67653123}, {13061, 50876931}, {13062, 50877699}, {13063, 84432899}, - {13064, 67656963}, {13065, 50880771}, {13066, 50881539}, {13067, 50882307}, - {13068, 67660291}, {13069, 67661315}, {13070, 50885123}, {13071, 50885891}, - {13072, 34109443}, {13073, 50887171}, {13074, 67665155}, {13075, 67666179}, - {13076, 34112771}, {13077, 84444931}, {13078, 101223427}, {13079, 84447747}, - {13080, 50891011}, {13081, 84449027}, {13082, 84450307}, {13083, 67674371}, - {13084, 50898179}, {13085, 50898947}, {13086, 50899715}, {13087, 67677699}, - {13088, 84455939}, {13089, 67680003}, {13090, 50903811}, {13091, 50904579}, - {13092, 50905347}, {13093, 34128899}, {13094, 34129411}, {13095, 34118147}, - {13096, 34129923}, {13097, 50907651}, {13098, 50908419}, {13099, 84463619}, - {13100, 50910467}, {13101, 67688451}, {13102, 84466691}, {13103, 50913539}, - {13104, 34137091}, {13105, 34137603}, {13106, 84469763}, {13107, 67693827}, - {13108, 84472067}, {13109, 50918915}, {13110, 84474115}, {13111, 34143747}, - {13112, 50921475}, {13113, 50922243}, {13114, 50923011}, {13115, 50923779}, - {13116, 50924547}, {13117, 67702531}, {13118, 50926339}, {13119, 34149891}, - {13120, 50927619}, {13121, 50928387}, {13122, 50929155}, {13123, 67707139}, - {13124, 50930947}, {13125, 50931715}, {13126, 50932483}, {13127, 84487683}, - {13128, 67711747}, {13129, 34158339}, {13130, 84490499}, {13131, 34160131}, - {13132, 67715075}, {13133, 67669507}, {13134, 50938883}, {13135, 50939651}, - {13136, 50940419}, {13137, 67718403}, {13138, 34164995}, {13139, 50942723}, - {13140, 67720707}, {13141, 34167299}, {13142, 84499459}, {13143, 50893827}, - {13144, 34169091}, {13145, 34169603}, {13146, 34170115}, {13147, 34170627}, - {13148, 34171139}, {13149, 34171651}, {13150, 34172163}, {13151, 34172675}, - {13152, 34173187}, {13153, 34173699}, {13154, 50951427}, {13155, 50952195}, - {13156, 50952963}, {13157, 50953731}, {13158, 50954499}, {13159, 50955267}, - {13160, 50956035}, {13161, 50956803}, {13162, 50957571}, {13163, 50958339}, - {13164, 50959107}, {13165, 50959875}, {13166, 50960643}, {13167, 50961411}, - {13168, 50962179}, {13169, 50962947}, {13170, 34186499}, {13171, 34187011}, - {13172, 50964739}, {13173, 34188291}, {13174, 34188803}, {13175, 34189315}, - {13176, 50967043}, {13177, 50967811}, {13178, 34191363}, {13179, 34191875}, - {13180, 34192387}, {13181, 34192899}, {13182, 34193411}, {13183, 67748355}, - {13184, 34185987}, {13185, 34194947}, {13186, 34195459}, {13187, 34195971}, - {13188, 34196483}, {13189, 34196995}, {13190, 34197507}, {13191, 34198019}, - {13192, 50975747}, {13193, 67753731}, {13194, 34200323}, {13195, 34200835}, - {13196, 34201347}, {13197, 34201859}, {13198, 34202371}, {13199, 34202883}, - {13200, 34203395}, {13201, 50981123}, {13202, 50981891}, {13203, 50980355}, - {13204, 50982659}, {13205, 34206211}, {13206, 34206723}, {13207, 34207235}, - {13208, 33556995}, {13209, 34207747}, {13210, 34208259}, {13211, 34208771}, - {13212, 34209283}, {13213, 34209795}, {13214, 34210307}, {13215, 50988035}, - {13216, 50988803}, {13217, 34190083}, {13218, 50989571}, {13219, 50990339}, - {13220, 50991107}, {13221, 34190851}, {13222, 50991875}, {13223, 50992643}, - {13224, 67770627}, {13225, 34185987}, {13226, 50994435}, {13227, 50995203}, - {13228, 50995971}, {13229, 50996739}, {13230, 84551939}, {13231, 101330435}, - {13232, 34223107}, {13233, 34223619}, {13234, 34224131}, {13235, 34224643}, - {13236, 34225155}, {13237, 34225667}, {13238, 34226179}, {13239, 34226691}, - {13240, 34227203}, {13241, 34226691}, {13242, 34227715}, {13243, 34228227}, - {13244, 34228739}, {13245, 34229251}, {13246, 34229763}, {13247, 34229251}, - {13248, 34230275}, {13249, 34230787}, {13250, 2}, {13251, 34231299}, - {13252, 33817347}, {13253, 33554947}, {13254, 67786243}, {13255, 2}, - {13256, 34232835}, {13257, 34233347}, {13258, 34233859}, {13259, 34185731}, - {13260, 34234371}, {13261, 34234883}, {13262, 34210307}, {13263, 34235395}, - {13264, 33557251}, {13265, 34235907}, {13266, 51013635}, {13267, 34237187}, - {13268, 34197507}, {13269, 51014915}, {13270, 51015683}, {13271, 34239235}, - {13272, 2}, {13273, 51016963}, {13274, 34240515}, {13275, 34221315}, - {13276, 34241027}, {13277, 34241539}, {13278, 51019267}, {13279, 51020035}, - {13280, 34243587}, {13281, 34244099}, {13282, 34244611}, {13283, 34245123}, - {13284, 34245635}, {13285, 34246147}, {13286, 34246659}, {13287, 34247171}, - {13288, 34247683}, {13289, 51025411}, {13290, 51026179}, {13291, 51026947}, - {13292, 51027715}, {13293, 51028483}, {13294, 51029251}, {13295, 51030019}, - {13296, 51030787}, {13297, 51031555}, {13298, 51032323}, {13299, 51033091}, - {13300, 51033859}, {13301, 51034627}, {13302, 51035395}, {13303, 51036163}, - {13304, 51036931}, {13305, 51037699}, {13306, 51038467}, {13307, 51039235}, - {13308, 51040003}, {13309, 51040771}, {13310, 51041539}, {13311, 51042307}, + {12441, 1}, {12443, 33974531}, {12444, 33975043}, {12445, 1}, + {12447, 33975555}, {12448, 1}, {12543, 33976067}, {12544, 2}, + {12549, 1}, {12592, 2}, {12593, 17199363}, {12594, 17199619}, + {12595, 17199875}, {12596, 17200131}, {12597, 17200387}, {12598, 17200643}, + {12599, 17200899}, {12600, 17201155}, {12601, 17201411}, {12602, 17201667}, + {12603, 17201923}, {12604, 17202179}, {12605, 17202435}, {12606, 17202691}, + {12607, 17202947}, {12608, 17203203}, {12609, 17203459}, {12610, 17203715}, + {12611, 17203971}, {12612, 17204227}, {12613, 17204483}, {12614, 17204739}, + {12615, 17204995}, {12616, 17205251}, {12617, 17205507}, {12618, 17205763}, + {12619, 17206019}, {12620, 17206275}, {12621, 17206531}, {12622, 17206787}, + {12623, 17207043}, {12624, 17207299}, {12625, 17207555}, {12626, 17207811}, + {12627, 17208067}, {12628, 17208323}, {12629, 17208579}, {12630, 17208835}, + {12631, 17209091}, {12632, 17209347}, {12633, 17209603}, {12634, 17209859}, + {12635, 17210115}, {12636, 17210371}, {12637, 17210627}, {12638, 17210883}, + {12639, 17211139}, {12640, 17211395}, {12641, 17211651}, {12642, 17211907}, + {12643, 17212163}, {12644, 2}, {12645, 17212419}, {12646, 17212675}, + {12647, 17212931}, {12648, 17213187}, {12649, 17213443}, {12650, 17213699}, + {12651, 17213955}, {12652, 17214211}, {12653, 17214467}, {12654, 17214723}, + {12655, 17214979}, {12656, 17215235}, {12657, 17215491}, {12658, 17215747}, + {12659, 17216003}, {12660, 17216259}, {12661, 17216515}, {12662, 17216771}, + {12663, 17217027}, {12664, 17217283}, {12665, 17217539}, {12666, 17217795}, + {12667, 17218051}, {12668, 17218307}, {12669, 17218563}, {12670, 17218819}, + {12671, 17219075}, {12672, 17219331}, {12673, 17219587}, {12674, 17219843}, + {12675, 17220099}, {12676, 17220355}, {12677, 17220611}, {12678, 17220867}, + {12679, 17221123}, {12680, 17221379}, {12681, 17221635}, {12682, 17221891}, + {12683, 17222147}, {12684, 17222403}, {12685, 17222659}, {12686, 17222915}, + {12687, 2}, {12688, 1}, {12690, 17141507}, {12691, 17143043}, + {12692, 17223171}, {12693, 17223427}, {12694, 17223683}, {12695, 17223939}, + {12696, 17224195}, {12697, 17224451}, {12698, 17142531}, {12699, 17224707}, + {12700, 17224963}, {12701, 17225219}, {12702, 17225475}, {12703, 17143555}, + {12704, 1}, {12772, 2}, {12784, 1}, {12800, 50780163}, + {12801, 50780931}, {12802, 50781699}, {12803, 50782467}, {12804, 50783235}, + {12805, 50784003}, {12806, 50784771}, {12807, 50785539}, {12808, 50786307}, + {12809, 50787075}, {12810, 50787843}, {12811, 50788611}, {12812, 50789379}, + {12813, 50790147}, {12814, 50790915}, {12815, 50791683}, {12816, 50792451}, + {12817, 50793219}, {12818, 50793987}, {12819, 50794755}, {12820, 50795523}, + {12821, 50796291}, {12822, 50797059}, {12823, 50797827}, {12824, 50798595}, + {12825, 50799363}, {12826, 50800131}, {12827, 50800899}, {12828, 50801667}, + {12829, 67579651}, {12830, 67580675}, {12831, 2}, {12832, 50804483}, + {12833, 50805251}, {12834, 50806019}, {12835, 50806787}, {12836, 50807555}, + {12837, 50808323}, {12838, 50809091}, {12839, 50809859}, {12840, 50810627}, + {12841, 50811395}, {12842, 50812163}, {12843, 50812931}, {12844, 50813699}, + {12845, 50814467}, {12846, 50815235}, {12847, 50816003}, {12848, 50816771}, + {12849, 50817539}, {12850, 50818307}, {12851, 50819075}, {12852, 50819843}, + {12853, 50820611}, {12854, 50821379}, {12855, 50822147}, {12856, 50822915}, + {12857, 50823683}, {12858, 50824451}, {12859, 50825219}, {12860, 50825987}, + {12861, 50826755}, {12862, 50827523}, {12863, 50828291}, {12864, 50829059}, + {12865, 50829827}, {12866, 50830595}, {12867, 50831363}, {12868, 17277699}, + {12869, 17277955}, {12870, 17158403}, {12871, 17278211}, {12872, 1}, + {12880, 50832899}, {12881, 33844995}, {12882, 34056451}, {12883, 33562371}, + {12884, 34056963}, {12885, 34057475}, {12886, 34057987}, {12887, 34058499}, + {12888, 34059011}, {12889, 34059523}, {12890, 34060035}, {12891, 33827075}, + {12892, 33826307}, {12893, 34060547}, {12894, 34061059}, {12895, 34061571}, + {12896, 17199363}, {12897, 17200131}, {12898, 17200899}, {12899, 17201411}, + {12900, 17203459}, {12901, 17203715}, {12902, 17204483}, {12903, 17204995}, + {12904, 17205251}, {12905, 17205763}, {12906, 17206019}, {12907, 17206275}, + {12908, 17206531}, {12909, 17206787}, {12910, 17236739}, {12911, 17237507}, + {12912, 17238275}, {12913, 17239043}, {12914, 17239811}, {12915, 17240579}, + {12916, 17241347}, {12917, 17242115}, {12918, 17242883}, {12919, 17243651}, + {12920, 17244419}, {12921, 17245187}, {12922, 17245955}, {12923, 17246723}, + {12924, 34062083}, {12925, 34062595}, {12926, 17285891}, {12927, 1}, + {12928, 17141507}, {12929, 17143043}, {12930, 17223171}, {12931, 17223427}, + {12932, 17253379}, {12933, 17254147}, {12934, 17254915}, {12935, 17144323}, + {12936, 17256451}, {12937, 17147395}, {12938, 17160195}, {12939, 17163267}, + {12940, 17163011}, {12941, 17160451}, {12942, 17184003}, {12943, 17149443}, + {12944, 17159683}, {12945, 17263363}, {12946, 17264131}, {12947, 17264899}, + {12948, 17265667}, {12949, 17266435}, {12950, 17267203}, {12951, 17267971}, + {12952, 17268739}, {12953, 17286147}, {12954, 17286403}, {12955, 17150979}, + {12956, 17286659}, {12957, 17286915}, {12958, 17287171}, {12959, 17287427}, + {12960, 17287683}, {12961, 17275651}, {12962, 17287939}, {12963, 17288195}, + {12964, 17223683}, {12965, 17223939}, {12966, 17224195}, {12967, 17288451}, + {12968, 17288707}, {12969, 17288963}, {12970, 17289219}, {12971, 17271043}, + {12972, 17271811}, {12973, 17272579}, {12974, 17273347}, {12975, 17274115}, + {12976, 17289475}, {12977, 34066947}, {12978, 34067459}, {12979, 34067971}, + {12980, 34068483}, {12981, 34068995}, {12982, 33564931}, {12983, 34057219}, + {12984, 34061315}, {12985, 34069507}, {12986, 34070019}, {12987, 34070531}, + {12988, 34071043}, {12989, 34071555}, {12990, 34072067}, {12991, 34072579}, + {12992, 34073091}, {12993, 34073603}, {12994, 34074115}, {12995, 34074627}, + {12996, 34075139}, {12997, 34075651}, {12998, 34076163}, {12999, 34076675}, + {13000, 34077187}, {13001, 50854915}, {13002, 50855683}, {13003, 50856451}, + {13004, 34080003}, {13005, 50857731}, {13006, 34081283}, {13007, 50859011}, + {13008, 17305347}, {13009, 17305603}, {13010, 17305859}, {13011, 17306115}, + {13012, 17306371}, {13013, 17306627}, {13014, 17306883}, {13015, 17307139}, + {13016, 17307395}, {13017, 17198851}, {13018, 17307651}, {13019, 17307907}, + {13020, 17308163}, {13021, 17308419}, {13022, 17308675}, {13023, 17308931}, + {13024, 17309187}, {13025, 17309443}, {13026, 17309699}, {13027, 17199107}, + {13028, 17309955}, {13029, 17310211}, {13030, 17310467}, {13031, 17310723}, + {13032, 17310979}, {13033, 17311235}, {13034, 17311491}, {13035, 17311747}, + {13036, 17312003}, {13037, 17312259}, {13038, 17312515}, {13039, 17312771}, + {13040, 17313027}, {13041, 17313283}, {13042, 17313539}, {13043, 17313795}, + {13044, 17314051}, {13045, 17314307}, {13046, 17314563}, {13047, 17314819}, + {13048, 17315075}, {13049, 17315331}, {13050, 17315587}, {13051, 17315843}, + {13052, 17316099}, {13053, 17316355}, {13054, 17316611}, {13055, 34094083}, + {13056, 67649027}, {13057, 67650051}, {13058, 67651075}, {13059, 50874883}, + {13060, 67652867}, {13061, 50876675}, {13062, 50877443}, {13063, 84432643}, + {13064, 67656707}, {13065, 50880515}, {13066, 50881283}, {13067, 50882051}, + {13068, 67660035}, {13069, 67661059}, {13070, 50884867}, {13071, 50885635}, + {13072, 34109187}, {13073, 50886915}, {13074, 67664899}, {13075, 67665923}, + {13076, 34112515}, {13077, 84444675}, {13078, 101223171}, {13079, 84447491}, + {13080, 50890755}, {13081, 84448771}, {13082, 84450051}, {13083, 67674115}, + {13084, 50897923}, {13085, 50898691}, {13086, 50899459}, {13087, 67677443}, + {13088, 84455683}, {13089, 67679747}, {13090, 50903555}, {13091, 50904323}, + {13092, 50905091}, {13093, 34128643}, {13094, 34129155}, {13095, 34117891}, + {13096, 34129667}, {13097, 50907395}, {13098, 50908163}, {13099, 84463363}, + {13100, 50910211}, {13101, 67688195}, {13102, 84466435}, {13103, 50913283}, + {13104, 34136835}, {13105, 34137347}, {13106, 84469507}, {13107, 67693571}, + {13108, 84471811}, {13109, 50918659}, {13110, 84473859}, {13111, 34143491}, + {13112, 50921219}, {13113, 50921987}, {13114, 50922755}, {13115, 50923523}, + {13116, 50924291}, {13117, 67702275}, {13118, 50926083}, {13119, 34149635}, + {13120, 50927363}, {13121, 50928131}, {13122, 50928899}, {13123, 67706883}, + {13124, 50930691}, {13125, 50931459}, {13126, 50932227}, {13127, 84487427}, + {13128, 67711491}, {13129, 34158083}, {13130, 84490243}, {13131, 34159875}, + {13132, 67714819}, {13133, 67669251}, {13134, 50938627}, {13135, 50939395}, + {13136, 50940163}, {13137, 67718147}, {13138, 34164739}, {13139, 50942467}, + {13140, 67720451}, {13141, 34167043}, {13142, 84499203}, {13143, 50893571}, + {13144, 34168835}, {13145, 34169347}, {13146, 34169859}, {13147, 34170371}, + {13148, 34170883}, {13149, 34171395}, {13150, 34171907}, {13151, 34172419}, + {13152, 34172931}, {13153, 34173443}, {13154, 50951171}, {13155, 50951939}, + {13156, 50952707}, {13157, 50953475}, {13158, 50954243}, {13159, 50955011}, + {13160, 50955779}, {13161, 50956547}, {13162, 50957315}, {13163, 50958083}, + {13164, 50958851}, {13165, 50959619}, {13166, 50960387}, {13167, 50961155}, + {13168, 50961923}, {13169, 50962691}, {13170, 34186243}, {13171, 34186755}, + {13172, 50964483}, {13173, 34188035}, {13174, 34188547}, {13175, 34189059}, + {13176, 50966787}, {13177, 50967555}, {13178, 34191107}, {13179, 34191619}, + {13180, 34192131}, {13181, 34192643}, {13182, 34193155}, {13183, 67748099}, + {13184, 34185731}, {13185, 34194691}, {13186, 34195203}, {13187, 34195715}, + {13188, 34196227}, {13189, 34196739}, {13190, 34197251}, {13191, 34197763}, + {13192, 50975491}, {13193, 67753475}, {13194, 34200067}, {13195, 34200579}, + {13196, 34201091}, {13197, 34201603}, {13198, 34202115}, {13199, 34202627}, + {13200, 34203139}, {13201, 50980867}, {13202, 50981635}, {13203, 50980099}, + {13204, 50982403}, {13205, 34205955}, {13206, 34206467}, {13207, 34206979}, + {13208, 33556995}, {13209, 34207491}, {13210, 34208003}, {13211, 34208515}, + {13212, 34209027}, {13213, 34209539}, {13214, 34210051}, {13215, 50987779}, + {13216, 50988547}, {13217, 34189827}, {13218, 50989315}, {13219, 50990083}, + {13220, 50990851}, {13221, 34190595}, {13222, 50991619}, {13223, 50992387}, + {13224, 67770371}, {13225, 34185731}, {13226, 50994179}, {13227, 50994947}, + {13228, 50995715}, {13229, 50996483}, {13230, 84551683}, {13231, 101330179}, + {13232, 34222851}, {13233, 34223363}, {13234, 34223875}, {13235, 34224387}, + {13236, 34224899}, {13237, 34225411}, {13238, 34225923}, {13239, 34226435}, + {13240, 34226947}, {13241, 34226435}, {13242, 34227459}, {13243, 34227971}, + {13244, 34228483}, {13245, 34228995}, {13246, 34229507}, {13247, 34228995}, + {13248, 34230019}, {13249, 34230531}, {13250, 2}, {13251, 34231043}, + {13252, 33817091}, {13253, 33554947}, {13254, 67785987}, {13255, 2}, + {13256, 34232579}, {13257, 34233091}, {13258, 34233603}, {13259, 34185475}, + {13260, 34234115}, {13261, 34234627}, {13262, 34210051}, {13263, 34235139}, + {13264, 33557251}, {13265, 34235651}, {13266, 51013379}, {13267, 34236931}, + {13268, 34197251}, {13269, 51014659}, {13270, 51015427}, {13271, 34238979}, + {13272, 2}, {13273, 51016707}, {13274, 34240259}, {13275, 34221059}, + {13276, 34240771}, {13277, 34241283}, {13278, 51019011}, {13279, 51019779}, + {13280, 34243331}, {13281, 34243843}, {13282, 34244355}, {13283, 34244867}, + {13284, 34245379}, {13285, 34245891}, {13286, 34246403}, {13287, 34246915}, + {13288, 34247427}, {13289, 51025155}, {13290, 51025923}, {13291, 51026691}, + {13292, 51027459}, {13293, 51028227}, {13294, 51028995}, {13295, 51029763}, + {13296, 51030531}, {13297, 51031299}, {13298, 51032067}, {13299, 51032835}, + {13300, 51033603}, {13301, 51034371}, {13302, 51035139}, {13303, 51035907}, + {13304, 51036675}, {13305, 51037443}, {13306, 51038211}, {13307, 51038979}, + {13308, 51039747}, {13309, 51040515}, {13310, 51041283}, {13311, 51042051}, {13312, 1}, {42125, 2}, {42128, 1}, {42183, 2}, - {42192, 1}, {42540, 2}, {42560, 17488643}, {42561, 1}, - {42562, 17488899}, {42563, 1}, {42564, 17489155}, {42565, 1}, - {42566, 17489411}, {42567, 1}, {42568, 17489667}, {42569, 1}, - {42570, 16936451}, {42571, 1}, {42572, 17489923}, {42573, 1}, - {42574, 17490179}, {42575, 1}, {42576, 17490435}, {42577, 1}, - {42578, 17490691}, {42579, 1}, {42580, 17490947}, {42581, 1}, - {42582, 17491203}, {42583, 1}, {42584, 17491459}, {42585, 1}, - {42586, 17491715}, {42587, 1}, {42588, 17491971}, {42589, 1}, - {42590, 17492227}, {42591, 1}, {42592, 17492483}, {42593, 1}, - {42594, 17492739}, {42595, 1}, {42596, 17492995}, {42597, 1}, - {42598, 17493251}, {42599, 1}, {42600, 17493507}, {42601, 1}, - {42602, 17493763}, {42603, 1}, {42604, 17494019}, {42605, 1}, - {42624, 17494275}, {42625, 1}, {42626, 17494531}, {42627, 1}, - {42628, 17494787}, {42629, 1}, {42630, 17495043}, {42631, 1}, - {42632, 17495299}, {42633, 1}, {42634, 17495555}, {42635, 1}, - {42636, 17495811}, {42637, 1}, {42638, 17496067}, {42639, 1}, - {42640, 17496323}, {42641, 1}, {42642, 17496579}, {42643, 1}, - {42644, 17496835}, {42645, 1}, {42646, 17497091}, {42647, 1}, - {42648, 17497347}, {42649, 1}, {42650, 17497603}, {42651, 1}, + {42192, 1}, {42540, 2}, {42560, 17488387}, {42561, 1}, + {42562, 17488643}, {42563, 1}, {42564, 17488899}, {42565, 1}, + {42566, 17489155}, {42567, 1}, {42568, 17489411}, {42569, 1}, + {42570, 16936451}, {42571, 1}, {42572, 17489667}, {42573, 1}, + {42574, 17489923}, {42575, 1}, {42576, 17490179}, {42577, 1}, + {42578, 17490435}, {42579, 1}, {42580, 17490691}, {42581, 1}, + {42582, 17490947}, {42583, 1}, {42584, 17491203}, {42585, 1}, + {42586, 17491459}, {42587, 1}, {42588, 17491715}, {42589, 1}, + {42590, 17491971}, {42591, 1}, {42592, 17492227}, {42593, 1}, + {42594, 17492483}, {42595, 1}, {42596, 17492739}, {42597, 1}, + {42598, 17492995}, {42599, 1}, {42600, 17493251}, {42601, 1}, + {42602, 17493507}, {42603, 1}, {42604, 17493763}, {42605, 1}, + {42624, 17494019}, {42625, 1}, {42626, 17494275}, {42627, 1}, + {42628, 17494531}, {42629, 1}, {42630, 17494787}, {42631, 1}, + {42632, 17495043}, {42633, 1}, {42634, 17495299}, {42635, 1}, + {42636, 17495555}, {42637, 1}, {42638, 17495811}, {42639, 1}, + {42640, 17496067}, {42641, 1}, {42642, 17496323}, {42643, 1}, + {42644, 17496579}, {42645, 1}, {42646, 17496835}, {42647, 1}, + {42648, 17497091}, {42649, 1}, {42650, 17497347}, {42651, 1}, {42652, 16873219}, {42653, 16873731}, {42654, 1}, {42744, 2}, - {42752, 1}, {42786, 17497859}, {42787, 1}, {42788, 17498115}, - {42789, 1}, {42790, 17498371}, {42791, 1}, {42792, 17498627}, - {42793, 1}, {42794, 17498883}, {42795, 1}, {42796, 17499139}, - {42797, 1}, {42798, 17499395}, {42799, 1}, {42802, 17499651}, - {42803, 1}, {42804, 17499907}, {42805, 1}, {42806, 17500163}, - {42807, 1}, {42808, 17500419}, {42809, 1}, {42810, 17500675}, - {42811, 1}, {42812, 17500931}, {42813, 1}, {42814, 17501187}, - {42815, 1}, {42816, 17501443}, {42817, 1}, {42818, 17501699}, - {42819, 1}, {42820, 17501955}, {42821, 1}, {42822, 17502211}, - {42823, 1}, {42824, 17502467}, {42825, 1}, {42826, 17502723}, - {42827, 1}, {42828, 17502979}, {42829, 1}, {42830, 17503235}, - {42831, 1}, {42832, 17503491}, {42833, 1}, {42834, 17503747}, - {42835, 1}, {42836, 17504003}, {42837, 1}, {42838, 17504259}, - {42839, 1}, {42840, 17504515}, {42841, 1}, {42842, 17504771}, - {42843, 1}, {42844, 17505027}, {42845, 1}, {42846, 17505283}, - {42847, 1}, {42848, 17505539}, {42849, 1}, {42850, 17505795}, - {42851, 1}, {42852, 17506051}, {42853, 1}, {42854, 17506307}, - {42855, 1}, {42856, 17506563}, {42857, 1}, {42858, 17506819}, - {42859, 1}, {42860, 17507075}, {42861, 1}, {42862, 17507331}, - {42863, 1}, {42864, 17507331}, {42865, 1}, {42873, 17507587}, - {42874, 1}, {42875, 17507843}, {42876, 1}, {42877, 17508099}, - {42878, 17508355}, {42879, 1}, {42880, 17508611}, {42881, 1}, - {42882, 17508867}, {42883, 1}, {42884, 17509123}, {42885, 1}, - {42886, 17509379}, {42887, 1}, {42891, 17509635}, {42892, 1}, - {42893, 16951299}, {42894, 1}, {42896, 17509891}, {42897, 1}, - {42898, 17510147}, {42899, 1}, {42902, 17510403}, {42903, 1}, - {42904, 17510659}, {42905, 1}, {42906, 17510915}, {42907, 1}, - {42908, 17511171}, {42909, 1}, {42910, 17511427}, {42911, 1}, - {42912, 17511683}, {42913, 1}, {42914, 17511939}, {42915, 1}, - {42916, 17512195}, {42917, 1}, {42918, 17512451}, {42919, 1}, - {42920, 17512707}, {42921, 1}, {42922, 16841475}, {42923, 16948995}, - {42924, 16951043}, {42925, 17512963}, {42926, 16951555}, {42927, 1}, - {42928, 17513219}, {42929, 17513475}, {42930, 16952067}, {42931, 17513731}, - {42932, 17513987}, {42933, 1}, {42934, 17514243}, {42935, 1}, - {42936, 17514499}, {42937, 1}, {42938, 17514755}, {42939, 1}, - {42940, 17515011}, {42941, 1}, {42942, 17515267}, {42943, 1}, - {42944, 17515523}, {42945, 1}, {42946, 17515779}, {42947, 1}, - {42948, 17516035}, {42949, 16954371}, {42950, 17516291}, {42951, 17516547}, - {42952, 1}, {42953, 17516803}, {42954, 1}, {42955, 2}, - {42960, 17517059}, {42961, 1}, {42962, 2}, {42963, 1}, - {42964, 2}, {42965, 1}, {42966, 17517315}, {42967, 1}, - {42968, 17517571}, {42969, 1}, {42970, 2}, {42994, 16777731}, - {42995, 16778499}, {42996, 16781315}, {42997, 17517827}, {42998, 1}, + {42752, 1}, {42786, 17497603}, {42787, 1}, {42788, 17497859}, + {42789, 1}, {42790, 17498115}, {42791, 1}, {42792, 17498371}, + {42793, 1}, {42794, 17498627}, {42795, 1}, {42796, 17498883}, + {42797, 1}, {42798, 17499139}, {42799, 1}, {42802, 17499395}, + {42803, 1}, {42804, 17499651}, {42805, 1}, {42806, 17499907}, + {42807, 1}, {42808, 17500163}, {42809, 1}, {42810, 17500419}, + {42811, 1}, {42812, 17500675}, {42813, 1}, {42814, 17500931}, + {42815, 1}, {42816, 17501187}, {42817, 1}, {42818, 17501443}, + {42819, 1}, {42820, 17501699}, {42821, 1}, {42822, 17501955}, + {42823, 1}, {42824, 17502211}, {42825, 1}, {42826, 17502467}, + {42827, 1}, {42828, 17502723}, {42829, 1}, {42830, 17502979}, + {42831, 1}, {42832, 17503235}, {42833, 1}, {42834, 17503491}, + {42835, 1}, {42836, 17503747}, {42837, 1}, {42838, 17504003}, + {42839, 1}, {42840, 17504259}, {42841, 1}, {42842, 17504515}, + {42843, 1}, {42844, 17504771}, {42845, 1}, {42846, 17505027}, + {42847, 1}, {42848, 17505283}, {42849, 1}, {42850, 17505539}, + {42851, 1}, {42852, 17505795}, {42853, 1}, {42854, 17506051}, + {42855, 1}, {42856, 17506307}, {42857, 1}, {42858, 17506563}, + {42859, 1}, {42860, 17506819}, {42861, 1}, {42862, 17507075}, + {42863, 1}, {42864, 17507075}, {42865, 1}, {42873, 17507331}, + {42874, 1}, {42875, 17507587}, {42876, 1}, {42877, 17507843}, + {42878, 17508099}, {42879, 1}, {42880, 17508355}, {42881, 1}, + {42882, 17508611}, {42883, 1}, {42884, 17508867}, {42885, 1}, + {42886, 17509123}, {42887, 1}, {42891, 17509379}, {42892, 1}, + {42893, 16951299}, {42894, 1}, {42896, 17509635}, {42897, 1}, + {42898, 17509891}, {42899, 1}, {42902, 17510147}, {42903, 1}, + {42904, 17510403}, {42905, 1}, {42906, 17510659}, {42907, 1}, + {42908, 17510915}, {42909, 1}, {42910, 17511171}, {42911, 1}, + {42912, 17511427}, {42913, 1}, {42914, 17511683}, {42915, 1}, + {42916, 17511939}, {42917, 1}, {42918, 17512195}, {42919, 1}, + {42920, 17512451}, {42921, 1}, {42922, 16841475}, {42923, 16948995}, + {42924, 16951043}, {42925, 17512707}, {42926, 16951555}, {42927, 1}, + {42928, 17512963}, {42929, 17513219}, {42930, 16952067}, {42931, 17513475}, + {42932, 17513731}, {42933, 1}, {42934, 17513987}, {42935, 1}, + {42936, 17514243}, {42937, 1}, {42938, 17514499}, {42939, 1}, + {42940, 17514755}, {42941, 1}, {42942, 17515011}, {42943, 1}, + {42944, 17515267}, {42945, 1}, {42946, 17515523}, {42947, 1}, + {42948, 17515779}, {42949, 16954371}, {42950, 17516035}, {42951, 17516291}, + {42952, 1}, {42953, 17516547}, {42954, 1}, {42955, 2}, + {42960, 17516803}, {42961, 1}, {42962, 2}, {42963, 1}, + {42964, 2}, {42965, 1}, {42966, 17517059}, {42967, 1}, + {42968, 17517315}, {42969, 1}, {42970, 2}, {42994, 16777731}, + {42995, 16778499}, {42996, 16781315}, {42997, 17517571}, {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}, @@ -1631,375 +1632,375 @@ const uint32_t table[8000][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, 17498371}, - {43869, 17518083}, {43870, 17124867}, {43871, 17518339}, {43872, 1}, - {43881, 17518595}, {43882, 1}, {43884, 2}, {43888, 17518851}, - {43889, 17519107}, {43890, 17519363}, {43891, 17519619}, {43892, 17519875}, - {43893, 17520131}, {43894, 17520387}, {43895, 17520643}, {43896, 17520899}, - {43897, 17521155}, {43898, 17521411}, {43899, 17521667}, {43900, 17521923}, - {43901, 17522179}, {43902, 17522435}, {43903, 17522691}, {43904, 17522947}, - {43905, 17523203}, {43906, 17523459}, {43907, 17523715}, {43908, 17523971}, - {43909, 17524227}, {43910, 17524483}, {43911, 17524739}, {43912, 17524995}, - {43913, 17525251}, {43914, 17525507}, {43915, 17525763}, {43916, 17526019}, - {43917, 17526275}, {43918, 17526531}, {43919, 17526787}, {43920, 17527043}, - {43921, 17527299}, {43922, 17527555}, {43923, 17527811}, {43924, 17528067}, - {43925, 17528323}, {43926, 17528579}, {43927, 17528835}, {43928, 17529091}, - {43929, 17529347}, {43930, 17529603}, {43931, 17529859}, {43932, 17530115}, - {43933, 17530371}, {43934, 17530627}, {43935, 17530883}, {43936, 17531139}, - {43937, 17531395}, {43938, 17531651}, {43939, 17531907}, {43940, 17532163}, - {43941, 17532419}, {43942, 17532675}, {43943, 17532931}, {43944, 17533187}, - {43945, 17533443}, {43946, 17533699}, {43947, 17533955}, {43948, 17534211}, - {43949, 17534467}, {43950, 17534723}, {43951, 17534979}, {43952, 17535235}, - {43953, 17535491}, {43954, 17535747}, {43955, 17536003}, {43956, 17536259}, - {43957, 17536515}, {43958, 17536771}, {43959, 17537027}, {43960, 17537283}, - {43961, 17537539}, {43962, 17537795}, {43963, 17538051}, {43964, 17538307}, - {43965, 17538563}, {43966, 17538819}, {43967, 17539075}, {43968, 1}, + {43816, 1}, {43823, 2}, {43824, 1}, {43868, 17498115}, + {43869, 17517827}, {43870, 17124611}, {43871, 17518083}, {43872, 1}, + {43881, 17518339}, {43882, 1}, {43884, 2}, {43888, 17518595}, + {43889, 17518851}, {43890, 17519107}, {43891, 17519363}, {43892, 17519619}, + {43893, 17519875}, {43894, 17520131}, {43895, 17520387}, {43896, 17520643}, + {43897, 17520899}, {43898, 17521155}, {43899, 17521411}, {43900, 17521667}, + {43901, 17521923}, {43902, 17522179}, {43903, 17522435}, {43904, 17522691}, + {43905, 17522947}, {43906, 17523203}, {43907, 17523459}, {43908, 17523715}, + {43909, 17523971}, {43910, 17524227}, {43911, 17524483}, {43912, 17524739}, + {43913, 17524995}, {43914, 17525251}, {43915, 17525507}, {43916, 17525763}, + {43917, 17526019}, {43918, 17526275}, {43919, 17526531}, {43920, 17526787}, + {43921, 17527043}, {43922, 17527299}, {43923, 17527555}, {43924, 17527811}, + {43925, 17528067}, {43926, 17528323}, {43927, 17528579}, {43928, 17528835}, + {43929, 17529091}, {43930, 17529347}, {43931, 17529603}, {43932, 17529859}, + {43933, 17530115}, {43934, 17530371}, {43935, 17530627}, {43936, 17530883}, + {43937, 17531139}, {43938, 17531395}, {43939, 17531651}, {43940, 17531907}, + {43941, 17532163}, {43942, 17532419}, {43943, 17532675}, {43944, 17532931}, + {43945, 17533187}, {43946, 17533443}, {43947, 17533699}, {43948, 17533955}, + {43949, 17534211}, {43950, 17534467}, {43951, 17534723}, {43952, 17534979}, + {43953, 17535235}, {43954, 17535491}, {43955, 17535747}, {43956, 17536003}, + {43957, 17536259}, {43958, 17536515}, {43959, 17536771}, {43960, 17537027}, + {43961, 17537283}, {43962, 17537539}, {43963, 17537795}, {43964, 17538051}, + {43965, 17538307}, {43966, 17538563}, {43967, 17538819}, {43968, 1}, {44014, 2}, {44016, 1}, {44026, 2}, {44032, 1}, {55204, 2}, {55216, 1}, {55239, 2}, {55243, 1}, - {55292, 2}, {63744, 17539331}, {63745, 17539587}, {63746, 17182211}, - {63747, 17539843}, {63748, 17540099}, {63749, 17540355}, {63750, 17540611}, - {63751, 17196035}, {63753, 17540867}, {63754, 17184259}, {63755, 17541123}, - {63756, 17541379}, {63757, 17541635}, {63758, 17541891}, {63759, 17542147}, - {63760, 17542403}, {63761, 17542659}, {63762, 17542915}, {63763, 17543171}, - {63764, 17543427}, {63765, 17543683}, {63766, 17543939}, {63767, 17544195}, - {63768, 17544451}, {63769, 17544707}, {63770, 17544963}, {63771, 17545219}, - {63772, 17545475}, {63773, 17545731}, {63774, 17545987}, {63775, 17546243}, - {63776, 17546499}, {63777, 17546755}, {63778, 17547011}, {63779, 17547267}, - {63780, 17547523}, {63781, 17547779}, {63782, 17548035}, {63783, 17548291}, - {63784, 17548547}, {63785, 17548803}, {63786, 17549059}, {63787, 17549315}, - {63788, 17549571}, {63789, 17549827}, {63790, 17550083}, {63791, 17550339}, - {63792, 17550595}, {63793, 17550851}, {63794, 17551107}, {63795, 17551363}, - {63796, 17173507}, {63797, 17551619}, {63798, 17551875}, {63799, 17552131}, - {63800, 17552387}, {63801, 17552643}, {63802, 17552899}, {63803, 17553155}, - {63804, 17553411}, {63805, 17553667}, {63806, 17553923}, {63807, 17554179}, - {63808, 17192195}, {63809, 17554435}, {63810, 17554691}, {63811, 17554947}, - {63812, 17555203}, {63813, 17555459}, {63814, 17555715}, {63815, 17555971}, - {63816, 17556227}, {63817, 17556483}, {63818, 17556739}, {63819, 17556995}, - {63820, 17557251}, {63821, 17557507}, {63822, 17557763}, {63823, 17558019}, - {63824, 17558275}, {63825, 17558531}, {63826, 17558787}, {63827, 17559043}, - {63828, 17559299}, {63829, 17559555}, {63830, 17559811}, {63831, 17560067}, - {63832, 17560323}, {63833, 17560579}, {63834, 17560835}, {63835, 17561091}, - {63836, 17543427}, {63837, 17561347}, {63838, 17561603}, {63839, 17561859}, - {63840, 17562115}, {63841, 17562371}, {63842, 17562627}, {63843, 17562883}, - {63844, 17563139}, {63845, 17563395}, {63846, 17563651}, {63847, 17563907}, - {63848, 17564163}, {63849, 17564419}, {63850, 17564675}, {63851, 17564931}, - {63852, 17565187}, {63853, 17565443}, {63854, 17565699}, {63855, 17565955}, - {63856, 17566211}, {63857, 17182723}, {63858, 17566467}, {63859, 17566723}, - {63860, 17566979}, {63861, 17567235}, {63862, 17567491}, {63863, 17567747}, - {63864, 17568003}, {63865, 17568259}, {63866, 17568515}, {63867, 17568771}, - {63868, 17569027}, {63869, 17569283}, {63870, 17569539}, {63871, 17569795}, - {63872, 17570051}, {63873, 17151235}, {63874, 17570307}, {63875, 17570563}, - {63876, 17570819}, {63877, 17571075}, {63878, 17571331}, {63879, 17571587}, - {63880, 17571843}, {63881, 17572099}, {63882, 17146371}, {63883, 17572355}, - {63884, 17572611}, {63885, 17572867}, {63886, 17573123}, {63887, 17573379}, - {63888, 17573635}, {63889, 17573891}, {63890, 17574147}, {63891, 17574403}, - {63892, 17574659}, {63893, 17574915}, {63894, 17575171}, {63895, 17575427}, - {63896, 17575683}, {63897, 17575939}, {63898, 17576195}, {63899, 17576451}, - {63900, 17576707}, {63901, 17576963}, {63902, 17577219}, {63903, 17577475}, - {63904, 17577731}, {63905, 17565955}, {63906, 17577987}, {63907, 17578243}, - {63908, 17578499}, {63909, 17578755}, {63910, 17579011}, {63911, 17579267}, - {63912, 17317123}, {63913, 17579523}, {63914, 17561859}, {63915, 17579779}, - {63916, 17580035}, {63917, 17580291}, {63918, 17580547}, {63919, 17580803}, - {63920, 17581059}, {63921, 17581315}, {63922, 17581571}, {63923, 17581827}, - {63924, 17582083}, {63925, 17582339}, {63926, 17582595}, {63927, 17582851}, - {63928, 17583107}, {63929, 17583363}, {63930, 17583619}, {63931, 17583875}, - {63932, 17584131}, {63933, 17584387}, {63934, 17584643}, {63935, 17543427}, - {63936, 17584899}, {63937, 17585155}, {63938, 17585411}, {63939, 17585667}, - {63940, 17195779}, {63941, 17585923}, {63942, 17586179}, {63943, 17586435}, - {63944, 17586691}, {63945, 17586947}, {63946, 17587203}, {63947, 17587459}, - {63948, 17587715}, {63949, 17587971}, {63950, 17588227}, {63951, 17588483}, - {63952, 17588739}, {63953, 17254403}, {63954, 17588995}, {63955, 17589251}, - {63956, 17589507}, {63957, 17589763}, {63958, 17590019}, {63959, 17590275}, - {63960, 17590531}, {63961, 17590787}, {63962, 17591043}, {63963, 17562371}, - {63964, 17591299}, {63965, 17591555}, {63966, 17591811}, {63967, 17592067}, - {63968, 17592323}, {63969, 17592579}, {63970, 17592835}, {63971, 17593091}, - {63972, 17593347}, {63973, 17593603}, {63974, 17593859}, {63975, 17594115}, - {63976, 17594371}, {63977, 17184003}, {63978, 17594627}, {63979, 17594883}, - {63980, 17595139}, {63981, 17595395}, {63982, 17595651}, {63983, 17595907}, - {63984, 17596163}, {63985, 17596419}, {63986, 17596675}, {63987, 17596931}, - {63988, 17597187}, {63989, 17597443}, {63990, 17597699}, {63991, 17171459}, - {63992, 17597955}, {63993, 17598211}, {63994, 17598467}, {63995, 17598723}, - {63996, 17598979}, {63997, 17599235}, {63998, 17599491}, {63999, 17599747}, - {64000, 17600003}, {64001, 17600259}, {64002, 17600515}, {64003, 17600771}, - {64004, 17601027}, {64005, 17601283}, {64006, 17601539}, {64007, 17601795}, - {64008, 17178371}, {64009, 17602051}, {64010, 17179139}, {64011, 17602307}, - {64012, 17602563}, {64013, 17602819}, {64014, 1}, {64016, 17603075}, - {64017, 1}, {64018, 17603331}, {64019, 1}, {64021, 17603587}, - {64022, 17603843}, {64023, 17604099}, {64024, 17604355}, {64025, 17604611}, - {64026, 17604867}, {64027, 17605123}, {64028, 17605379}, {64029, 17605635}, - {64030, 17173251}, {64031, 1}, {64032, 17605891}, {64033, 1}, - {64034, 17606147}, {64035, 1}, {64037, 17606403}, {64038, 17606659}, - {64039, 1}, {64042, 17606915}, {64043, 17607171}, {64044, 17607427}, - {64045, 17607683}, {64046, 17607939}, {64047, 17608195}, {64048, 17608451}, - {64049, 17608707}, {64050, 17608963}, {64051, 17609219}, {64052, 17609475}, - {64053, 17609731}, {64054, 17609987}, {64055, 17610243}, {64056, 17610499}, - {64057, 17610755}, {64058, 17611011}, {64059, 17611267}, {64060, 17153027}, - {64061, 17611523}, {64062, 17611779}, {64063, 17612035}, {64064, 17612291}, - {64065, 17612547}, {64066, 17612803}, {64067, 17613059}, {64068, 17613315}, - {64069, 17613571}, {64070, 17613827}, {64071, 17614083}, {64072, 17614339}, - {64073, 17614595}, {64074, 17614851}, {64075, 17615107}, {64076, 17265155}, - {64077, 17615363}, {64078, 17615619}, {64079, 17615875}, {64080, 17616131}, - {64081, 17268227}, {64082, 17616387}, {64083, 17616643}, {64084, 17616899}, - {64085, 17617155}, {64086, 17617411}, {64087, 17575171}, {64088, 17617667}, - {64089, 17617923}, {64090, 17618179}, {64091, 17618435}, {64092, 17618691}, - {64093, 17618947}, {64095, 17619203}, {64096, 17619459}, {64097, 17619715}, - {64098, 17619971}, {64099, 17620227}, {64100, 17620483}, {64101, 17620739}, - {64102, 17620995}, {64103, 17606403}, {64104, 17621251}, {64105, 17621507}, - {64106, 17621763}, {64107, 17622019}, {64108, 17622275}, {64109, 17622531}, - {64110, 2}, {64112, 17622787}, {64113, 17623043}, {64114, 17623299}, - {64115, 17623555}, {64116, 17623811}, {64117, 17624067}, {64118, 17624323}, - {64119, 17624579}, {64120, 17609987}, {64121, 17624835}, {64122, 17625091}, - {64123, 17625347}, {64124, 17603075}, {64125, 17625603}, {64126, 17625859}, - {64127, 17626115}, {64128, 17626371}, {64129, 17626627}, {64130, 17626883}, - {64131, 17627139}, {64132, 17627395}, {64133, 17627651}, {64134, 17627907}, - {64135, 17628163}, {64136, 17628419}, {64137, 17612035}, {64138, 17628675}, - {64139, 17612291}, {64140, 17628931}, {64141, 17629187}, {64142, 17629443}, - {64143, 17629699}, {64144, 17629955}, {64145, 17603331}, {64146, 17548803}, - {64147, 17630211}, {64148, 17630467}, {64149, 17161475}, {64150, 17566211}, - {64151, 17587203}, {64152, 17630723}, {64153, 17630979}, {64154, 17614083}, - {64155, 17631235}, {64156, 17614339}, {64157, 17631491}, {64158, 17631747}, - {64159, 17632003}, {64160, 17603843}, {64161, 17632259}, {64162, 17632515}, - {64163, 17632771}, {64164, 17633027}, {64165, 17633283}, {64166, 17604099}, - {64167, 17633539}, {64168, 17633795}, {64169, 17634051}, {64170, 17634307}, - {64171, 17634563}, {64172, 17634819}, {64173, 17617411}, {64174, 17635075}, - {64175, 17635331}, {64176, 17575171}, {64177, 17635587}, {64178, 17618435}, - {64179, 17635843}, {64180, 17636099}, {64181, 17636355}, {64182, 17636611}, - {64183, 17636867}, {64184, 17619715}, {64185, 17637123}, {64186, 17606147}, - {64187, 17637379}, {64188, 17619971}, {64189, 17561347}, {64190, 17637635}, - {64191, 17620227}, {64192, 17637891}, {64193, 17620739}, {64194, 17638147}, - {64195, 17638403}, {64196, 17638659}, {64197, 17638915}, {64198, 17639171}, - {64199, 17621251}, {64200, 17605379}, {64201, 17639427}, {64202, 17621507}, - {64203, 17639683}, {64204, 17621763}, {64205, 17639939}, {64206, 17196035}, - {64207, 17640195}, {64208, 17640451}, {64209, 17640707}, {64210, 17640963}, - {64211, 17641219}, {64212, 17641475}, {64213, 17641731}, {64214, 17641987}, - {64215, 17642243}, {64216, 17642499}, {64217, 17642755}, {64218, 2}, - {64256, 34420227}, {64257, 34420739}, {64258, 34421251}, {64259, 51197699}, - {64260, 51198979}, {64261, 33559043}, {64263, 2}, {64275, 34422531}, - {64276, 34423043}, {64277, 34423555}, {64278, 34424067}, {64279, 34424579}, - {64280, 2}, {64285, 34425091}, {64286, 1}, {64287, 34425603}, - {64288, 17648899}, {64289, 17044227}, {64290, 17044995}, {64291, 17649155}, - {64292, 17649411}, {64293, 17649667}, {64294, 17649923}, {64295, 17650179}, - {64296, 17650435}, {64297, 17037059}, {64298, 34427907}, {64299, 34428419}, - {64300, 51206147}, {64301, 51206915}, {64302, 34430467}, {64303, 34430979}, - {64304, 34431491}, {64305, 34432003}, {64306, 34432515}, {64307, 34433027}, - {64308, 34433539}, {64309, 34434051}, {64310, 34434563}, {64311, 2}, - {64312, 34435075}, {64313, 34435587}, {64314, 34436099}, {64315, 34436611}, - {64316, 34437123}, {64317, 2}, {64318, 34437635}, {64319, 2}, - {64320, 34438147}, {64321, 34438659}, {64322, 2}, {64323, 34439171}, - {64324, 34439683}, {64325, 2}, {64326, 34440195}, {64327, 34440707}, - {64328, 34441219}, {64329, 34428931}, {64330, 34441731}, {64331, 34442243}, - {64332, 34442755}, {64333, 34443267}, {64334, 34443779}, {64335, 34444291}, - {64336, 17667587}, {64338, 17667843}, {64342, 17668099}, {64346, 17668355}, - {64350, 17668611}, {64354, 17668867}, {64358, 17669123}, {64362, 17669379}, - {64366, 17669635}, {64370, 17669891}, {64374, 17670147}, {64378, 17670403}, - {64382, 17670659}, {64386, 17670915}, {64388, 17671171}, {64390, 17671427}, - {64392, 17671683}, {64394, 17671939}, {64396, 17672195}, {64398, 17672451}, - {64402, 17672707}, {64406, 17672963}, {64410, 17673219}, {64414, 17673475}, - {64416, 17673731}, {64420, 17673987}, {64422, 17674243}, {64426, 17674499}, - {64430, 17674755}, {64432, 17675011}, {64434, 1}, {64451, 2}, - {64467, 17675267}, {64471, 16911363}, {64473, 17675523}, {64475, 17675779}, - {64477, 33688579}, {64478, 17676035}, {64480, 17676291}, {64482, 17676547}, - {64484, 17676803}, {64488, 17677059}, {64490, 34454531}, {64492, 34455043}, - {64494, 34455555}, {64496, 34456067}, {64498, 34456579}, {64500, 34457091}, - {64502, 34457603}, {64505, 34458115}, {64508, 17681411}, {64512, 34458883}, - {64513, 34459395}, {64514, 34459907}, {64515, 34458115}, {64516, 34460419}, - {64517, 34460931}, {64518, 34461443}, {64519, 34461955}, {64520, 34462467}, - {64521, 34462979}, {64522, 34463491}, {64523, 34464003}, {64524, 34464515}, - {64525, 34465027}, {64526, 34465539}, {64527, 34466051}, {64528, 34466563}, - {64529, 34467075}, {64530, 34467587}, {64531, 34468099}, {64532, 34468611}, - {64533, 34469123}, {64534, 34469635}, {64535, 34469379}, {64536, 34470147}, - {64537, 34470659}, {64538, 34471171}, {64539, 34471683}, {64540, 34472195}, - {64541, 34472707}, {64542, 34473219}, {64543, 34473731}, {64544, 34474243}, - {64545, 34474755}, {64546, 34475267}, {64547, 34475779}, {64548, 34476291}, - {64549, 34476803}, {64550, 34477315}, {64551, 34477827}, {64552, 34478339}, - {64553, 34478851}, {64554, 34479363}, {64555, 34479875}, {64556, 34480387}, - {64557, 34480899}, {64558, 34481411}, {64559, 34481923}, {64560, 34482435}, - {64561, 34482947}, {64562, 34483459}, {64563, 34483971}, {64564, 34484483}, - {64565, 34484995}, {64566, 34485507}, {64567, 34486019}, {64568, 34486531}, - {64569, 34487043}, {64570, 34487555}, {64571, 34488067}, {64572, 34488579}, - {64573, 34489091}, {64574, 34489603}, {64575, 34490115}, {64576, 34490627}, - {64577, 34491139}, {64578, 34491651}, {64579, 34492163}, {64580, 34492675}, - {64581, 34493187}, {64582, 34469891}, {64583, 34470403}, {64584, 34493699}, - {64585, 34494211}, {64586, 34494723}, {64587, 34495235}, {64588, 34495747}, - {64589, 34496259}, {64590, 34496771}, {64591, 34497283}, {64592, 34497795}, - {64593, 34498307}, {64594, 34498819}, {64595, 34499331}, {64596, 34499843}, - {64597, 34468867}, {64598, 34500355}, {64599, 34500867}, {64600, 34492931}, - {64601, 34501379}, {64602, 34500099}, {64603, 34501891}, {64604, 34502403}, - {64605, 34502915}, {64606, 51280643}, {64607, 51281411}, {64608, 51282179}, - {64609, 51282947}, {64610, 51283715}, {64611, 51284483}, {64612, 34508035}, - {64613, 34508547}, {64614, 34459907}, {64615, 34509059}, {64616, 34458115}, - {64617, 34460419}, {64618, 34509571}, {64619, 34510083}, {64620, 34462467}, - {64621, 34510595}, {64622, 34462979}, {64623, 34463491}, {64624, 34511107}, - {64625, 34511619}, {64626, 34465539}, {64627, 34512131}, {64628, 34466051}, - {64629, 34466563}, {64630, 34512643}, {64631, 34513155}, {64632, 34467587}, - {64633, 34513667}, {64634, 34468099}, {64635, 34468611}, {64636, 34482947}, - {64637, 34483459}, {64638, 34484995}, {64639, 34485507}, {64640, 34486019}, - {64641, 34488067}, {64642, 34488579}, {64643, 34489091}, {64644, 34489603}, - {64645, 34491651}, {64646, 34492163}, {64647, 34492675}, {64648, 34514179}, - {64649, 34493699}, {64650, 34514691}, {64651, 34515203}, {64652, 34496771}, - {64653, 34515715}, {64654, 34497283}, {64655, 34497795}, {64656, 34502915}, - {64657, 34516227}, {64658, 34516739}, {64659, 34492931}, {64660, 34494979}, - {64661, 34501379}, {64662, 34500099}, {64663, 34458883}, {64664, 34459395}, - {64665, 34517251}, {64666, 34459907}, {64667, 34517763}, {64668, 34460931}, - {64669, 34461443}, {64670, 34461955}, {64671, 34462467}, {64672, 34518275}, - {64673, 34464003}, {64674, 34464515}, {64675, 34465027}, {64676, 34465539}, - {64677, 34518787}, {64678, 34467587}, {64679, 34469123}, {64680, 34469635}, - {64681, 34469379}, {64682, 34470147}, {64683, 34470659}, {64684, 34471683}, - {64685, 34472195}, {64686, 34472707}, {64687, 34473219}, {64688, 34473731}, - {64689, 34474243}, {64690, 34519299}, {64691, 34474755}, {64692, 34475267}, - {64693, 34475779}, {64694, 34476291}, {64695, 34476803}, {64696, 34477315}, - {64697, 34478339}, {64698, 34478851}, {64699, 34479363}, {64700, 34479875}, - {64701, 34480387}, {64702, 34480899}, {64703, 34481411}, {64704, 34481923}, - {64705, 34482435}, {64706, 34483971}, {64707, 34484483}, {64708, 34486531}, - {64709, 34487043}, {64710, 34487555}, {64711, 34488067}, {64712, 34488579}, - {64713, 34490115}, {64714, 34490627}, {64715, 34491139}, {64716, 34491651}, - {64717, 34519811}, {64718, 34493187}, {64719, 34469891}, {64720, 34470403}, - {64721, 34493699}, {64722, 34495235}, {64723, 34495747}, {64724, 34496259}, - {64725, 34496771}, {64726, 34520323}, {64727, 34498307}, {64728, 34498819}, - {64729, 34520835}, {64730, 34468867}, {64731, 34500355}, {64732, 34500867}, - {64733, 34492931}, {64734, 34498051}, {64735, 34459907}, {64736, 34517763}, - {64737, 34462467}, {64738, 34518275}, {64739, 34465539}, {64740, 34518787}, - {64741, 34467587}, {64742, 34521347}, {64743, 34473731}, {64744, 34521859}, - {64745, 34522371}, {64746, 34522883}, {64747, 34488067}, {64748, 34488579}, - {64749, 34491651}, {64750, 34496771}, {64751, 34520323}, {64752, 34492931}, - {64753, 34498051}, {64754, 51300611}, {64755, 51301379}, {64756, 51302147}, - {64757, 34525699}, {64758, 34526211}, {64759, 34526723}, {64760, 34527235}, - {64761, 34527747}, {64762, 34528259}, {64763, 34528771}, {64764, 34529283}, - {64765, 34529795}, {64766, 34530307}, {64767, 34530819}, {64768, 34500611}, - {64769, 34531331}, {64770, 34531843}, {64771, 34532355}, {64772, 34501123}, - {64773, 34532867}, {64774, 34533379}, {64775, 34533891}, {64776, 34534403}, - {64777, 34534915}, {64778, 34535427}, {64779, 34535939}, {64780, 34522371}, - {64781, 34536451}, {64782, 34536963}, {64783, 34537475}, {64784, 34537987}, - {64785, 34525699}, {64786, 34526211}, {64787, 34526723}, {64788, 34527235}, - {64789, 34527747}, {64790, 34528259}, {64791, 34528771}, {64792, 34529283}, - {64793, 34529795}, {64794, 34530307}, {64795, 34530819}, {64796, 34500611}, - {64797, 34531331}, {64798, 34531843}, {64799, 34532355}, {64800, 34501123}, - {64801, 34532867}, {64802, 34533379}, {64803, 34533891}, {64804, 34534403}, - {64805, 34534915}, {64806, 34535427}, {64807, 34535939}, {64808, 34522371}, - {64809, 34536451}, {64810, 34536963}, {64811, 34537475}, {64812, 34537987}, - {64813, 34534915}, {64814, 34535427}, {64815, 34535939}, {64816, 34522371}, - {64817, 34521859}, {64818, 34522883}, {64819, 34477827}, {64820, 34472195}, - {64821, 34472707}, {64822, 34473219}, {64823, 34534915}, {64824, 34535427}, - {64825, 34535939}, {64826, 34477827}, {64827, 34478339}, {64828, 34538499}, - {64830, 1}, {64848, 51316227}, {64849, 51316995}, {64851, 51317763}, - {64852, 51318531}, {64853, 51319299}, {64854, 51320067}, {64855, 51320835}, - {64856, 51246851}, {64858, 51321603}, {64859, 51322371}, {64860, 51323139}, - {64861, 51323907}, {64862, 51324675}, {64863, 51325443}, {64865, 51326211}, - {64866, 51326979}, {64868, 51327747}, {64870, 51328515}, {64871, 51329283}, - {64873, 51330051}, {64874, 51330819}, {64876, 51331587}, {64878, 51332355}, - {64879, 51333123}, {64881, 51333891}, {64883, 51334659}, {64884, 51335427}, - {64885, 51336195}, {64886, 51336963}, {64888, 51337731}, {64889, 51338499}, - {64890, 51339267}, {64891, 51340035}, {64892, 51340803}, {64894, 51341571}, - {64895, 51342339}, {64896, 51343107}, {64897, 51343875}, {64898, 51344643}, - {64899, 51345411}, {64901, 51346179}, {64903, 51346947}, {64905, 51347715}, - {64906, 51247107}, {64907, 51348483}, {64908, 51349251}, {64909, 51270403}, - {64910, 51247619}, {64911, 51350019}, {64912, 2}, {64914, 51350787}, - {64915, 51351555}, {64916, 51352323}, {64917, 51353091}, {64918, 51353859}, - {64919, 51354627}, {64921, 51355395}, {64922, 51356163}, {64923, 51356931}, - {64924, 51357699}, {64926, 51358467}, {64927, 51359235}, {64928, 51360003}, - {64929, 51360771}, {64930, 51361539}, {64931, 51362307}, {64932, 51363075}, - {64933, 51363843}, {64934, 51364611}, {64935, 51365379}, {64936, 51366147}, - {64937, 51366915}, {64938, 51367683}, {64939, 51368451}, {64940, 51369219}, - {64941, 51369987}, {64942, 51277571}, {64943, 51370755}, {64944, 51371523}, - {64945, 51372291}, {64946, 51373059}, {64947, 51373827}, {64948, 51341571}, - {64949, 51343107}, {64950, 51374595}, {64951, 51375363}, {64952, 51376131}, - {64953, 51376899}, {64954, 51377667}, {64955, 51378435}, {64956, 51377667}, - {64957, 51376131}, {64958, 51379203}, {64959, 51379971}, {64960, 51380739}, - {64961, 51381507}, {64962, 51382275}, {64963, 51378435}, {64964, 51336195}, - {64965, 51328515}, {64966, 51383043}, {64967, 51383811}, {64968, 2}, - {64975, 1}, {64976, 2}, {65008, 51384579}, {65009, 51385347}, - {65010, 68163331}, {65011, 68164355}, {65012, 68165379}, {65013, 68166403}, - {65014, 68167427}, {65015, 68168451}, {65016, 68169475}, {65017, 51393283}, - {65018, 303052291}, {65019, 135284739}, {65020, 68177923}, {65021, 1}, - {65024, 0}, {65040, 17847299}, {65041, 17847555}, {65042, 2}, - {65043, 17110531}, {65044, 16848643}, {65045, 17032963}, {65046, 17033987}, - {65047, 17847811}, {65048, 17848067}, {65049, 2}, {65056, 1}, - {65072, 2}, {65073, 17848323}, {65074, 17848579}, {65075, 17848835}, - {65077, 17037827}, {65078, 17038083}, {65079, 17849091}, {65080, 17849347}, - {65081, 17849603}, {65082, 17849859}, {65083, 17850115}, {65084, 17850371}, - {65085, 17850627}, {65086, 17850883}, {65087, 17067267}, {65088, 17067523}, - {65089, 17851139}, {65090, 17851395}, {65091, 17851651}, {65092, 17851907}, - {65093, 1}, {65095, 17852163}, {65096, 17852419}, {65097, 33810691}, - {65101, 17848835}, {65104, 17847299}, {65105, 17847555}, {65106, 2}, - {65108, 16848643}, {65109, 17110531}, {65110, 17033987}, {65111, 17032963}, - {65112, 17848323}, {65113, 17037827}, {65114, 17038083}, {65115, 17849091}, - {65116, 17849347}, {65117, 17849603}, {65118, 17849859}, {65119, 17852675}, - {65120, 17852931}, {65121, 17853187}, {65122, 17037059}, {65123, 17853443}, - {65124, 17853699}, {65125, 17853955}, {65126, 17037571}, {65127, 2}, - {65128, 17854211}, {65129, 17854467}, {65130, 17854723}, {65131, 17854979}, - {65132, 2}, {65136, 34632451}, {65137, 34632963}, {65138, 34503427}, - {65139, 1}, {65140, 34504195}, {65141, 2}, {65142, 34504963}, - {65143, 34523395}, {65144, 34505731}, {65145, 34524163}, {65146, 34506499}, - {65147, 34524931}, {65148, 34507267}, {65149, 34633475}, {65150, 34633987}, - {65151, 34634499}, {65152, 17857795}, {65153, 17858051}, {65155, 17858307}, - {65157, 17858563}, {65159, 17858819}, {65161, 17677315}, {65165, 16910339}, - {65167, 17683715}, {65171, 17859075}, {65173, 17686787}, {65177, 17689859}, - {65181, 17681923}, {65185, 17682435}, {65189, 17684995}, {65193, 17834499}, - {65195, 17724675}, {65197, 17725187}, {65199, 17731587}, {65201, 17694979}, - {65205, 17745155}, {65209, 17697027}, {65213, 17698051}, {65217, 17700099}, - {65221, 17701123}, {65225, 17701635}, {65229, 17702659}, {65233, 17703683}, - {65237, 17706755}, {65241, 17708803}, {65245, 17711107}, {65249, 17682947}, - {65253, 17718019}, {65257, 17721091}, {65261, 16910851}, {65263, 17677059}, - {65265, 16911875}, {65269, 34636547}, {65271, 34637059}, {65273, 34637571}, - {65275, 34622467}, {65277, 2}, {65279, 0}, {65280, 2}, - {65281, 17032963}, {65282, 17860867}, {65283, 17852675}, {65284, 17854467}, - {65285, 17854723}, {65286, 17852931}, {65287, 17861123}, {65288, 17037827}, - {65289, 17038083}, {65290, 17853187}, {65291, 17037059}, {65292, 17847299}, - {65293, 17853443}, {65294, 17196547}, {65295, 17038595}, {65296, 17035523}, + {55292, 2}, {63744, 17539075}, {63745, 17539331}, {63746, 17181955}, + {63747, 17539587}, {63748, 17539843}, {63749, 17540099}, {63750, 17540355}, + {63751, 17195779}, {63753, 17540611}, {63754, 17184003}, {63755, 17540867}, + {63756, 17541123}, {63757, 17541379}, {63758, 17541635}, {63759, 17541891}, + {63760, 17542147}, {63761, 17542403}, {63762, 17542659}, {63763, 17542915}, + {63764, 17543171}, {63765, 17543427}, {63766, 17543683}, {63767, 17543939}, + {63768, 17544195}, {63769, 17544451}, {63770, 17544707}, {63771, 17544963}, + {63772, 17545219}, {63773, 17545475}, {63774, 17545731}, {63775, 17545987}, + {63776, 17546243}, {63777, 17546499}, {63778, 17546755}, {63779, 17547011}, + {63780, 17547267}, {63781, 17547523}, {63782, 17547779}, {63783, 17548035}, + {63784, 17548291}, {63785, 17548547}, {63786, 17548803}, {63787, 17549059}, + {63788, 17549315}, {63789, 17549571}, {63790, 17549827}, {63791, 17550083}, + {63792, 17550339}, {63793, 17550595}, {63794, 17550851}, {63795, 17551107}, + {63796, 17173251}, {63797, 17551363}, {63798, 17551619}, {63799, 17551875}, + {63800, 17552131}, {63801, 17552387}, {63802, 17552643}, {63803, 17552899}, + {63804, 17553155}, {63805, 17553411}, {63806, 17553667}, {63807, 17553923}, + {63808, 17191939}, {63809, 17554179}, {63810, 17554435}, {63811, 17554691}, + {63812, 17554947}, {63813, 17555203}, {63814, 17555459}, {63815, 17555715}, + {63816, 17555971}, {63817, 17556227}, {63818, 17556483}, {63819, 17556739}, + {63820, 17556995}, {63821, 17557251}, {63822, 17557507}, {63823, 17557763}, + {63824, 17558019}, {63825, 17558275}, {63826, 17558531}, {63827, 17558787}, + {63828, 17559043}, {63829, 17559299}, {63830, 17559555}, {63831, 17559811}, + {63832, 17560067}, {63833, 17560323}, {63834, 17560579}, {63835, 17560835}, + {63836, 17543171}, {63837, 17561091}, {63838, 17561347}, {63839, 17561603}, + {63840, 17561859}, {63841, 17562115}, {63842, 17562371}, {63843, 17562627}, + {63844, 17562883}, {63845, 17563139}, {63846, 17563395}, {63847, 17563651}, + {63848, 17563907}, {63849, 17564163}, {63850, 17564419}, {63851, 17564675}, + {63852, 17564931}, {63853, 17565187}, {63854, 17565443}, {63855, 17565699}, + {63856, 17565955}, {63857, 17182467}, {63858, 17566211}, {63859, 17566467}, + {63860, 17566723}, {63861, 17566979}, {63862, 17567235}, {63863, 17567491}, + {63864, 17567747}, {63865, 17568003}, {63866, 17568259}, {63867, 17568515}, + {63868, 17568771}, {63869, 17569027}, {63870, 17569283}, {63871, 17569539}, + {63872, 17569795}, {63873, 17150979}, {63874, 17570051}, {63875, 17570307}, + {63876, 17570563}, {63877, 17570819}, {63878, 17571075}, {63879, 17571331}, + {63880, 17571587}, {63881, 17571843}, {63882, 17146115}, {63883, 17572099}, + {63884, 17572355}, {63885, 17572611}, {63886, 17572867}, {63887, 17573123}, + {63888, 17573379}, {63889, 17573635}, {63890, 17573891}, {63891, 17574147}, + {63892, 17574403}, {63893, 17574659}, {63894, 17574915}, {63895, 17575171}, + {63896, 17575427}, {63897, 17575683}, {63898, 17575939}, {63899, 17576195}, + {63900, 17576451}, {63901, 17576707}, {63902, 17576963}, {63903, 17577219}, + {63904, 17577475}, {63905, 17565699}, {63906, 17577731}, {63907, 17577987}, + {63908, 17578243}, {63909, 17578499}, {63910, 17578755}, {63911, 17579011}, + {63912, 17316867}, {63913, 17579267}, {63914, 17561603}, {63915, 17579523}, + {63916, 17579779}, {63917, 17580035}, {63918, 17580291}, {63919, 17580547}, + {63920, 17580803}, {63921, 17581059}, {63922, 17581315}, {63923, 17581571}, + {63924, 17581827}, {63925, 17582083}, {63926, 17582339}, {63927, 17582595}, + {63928, 17582851}, {63929, 17583107}, {63930, 17583363}, {63931, 17583619}, + {63932, 17583875}, {63933, 17584131}, {63934, 17584387}, {63935, 17543171}, + {63936, 17584643}, {63937, 17584899}, {63938, 17585155}, {63939, 17585411}, + {63940, 17195523}, {63941, 17585667}, {63942, 17585923}, {63943, 17586179}, + {63944, 17586435}, {63945, 17586691}, {63946, 17586947}, {63947, 17587203}, + {63948, 17587459}, {63949, 17587715}, {63950, 17587971}, {63951, 17588227}, + {63952, 17588483}, {63953, 17254147}, {63954, 17588739}, {63955, 17588995}, + {63956, 17589251}, {63957, 17589507}, {63958, 17589763}, {63959, 17590019}, + {63960, 17590275}, {63961, 17590531}, {63962, 17590787}, {63963, 17562115}, + {63964, 17591043}, {63965, 17591299}, {63966, 17591555}, {63967, 17591811}, + {63968, 17592067}, {63969, 17592323}, {63970, 17592579}, {63971, 17592835}, + {63972, 17593091}, {63973, 17593347}, {63974, 17593603}, {63975, 17593859}, + {63976, 17594115}, {63977, 17183747}, {63978, 17594371}, {63979, 17594627}, + {63980, 17594883}, {63981, 17595139}, {63982, 17595395}, {63983, 17595651}, + {63984, 17595907}, {63985, 17596163}, {63986, 17596419}, {63987, 17596675}, + {63988, 17596931}, {63989, 17597187}, {63990, 17597443}, {63991, 17171203}, + {63992, 17597699}, {63993, 17597955}, {63994, 17598211}, {63995, 17598467}, + {63996, 17598723}, {63997, 17598979}, {63998, 17599235}, {63999, 17599491}, + {64000, 17599747}, {64001, 17600003}, {64002, 17600259}, {64003, 17600515}, + {64004, 17600771}, {64005, 17601027}, {64006, 17601283}, {64007, 17601539}, + {64008, 17178115}, {64009, 17601795}, {64010, 17178883}, {64011, 17602051}, + {64012, 17602307}, {64013, 17602563}, {64014, 1}, {64016, 17602819}, + {64017, 1}, {64018, 17603075}, {64019, 1}, {64021, 17603331}, + {64022, 17603587}, {64023, 17603843}, {64024, 17604099}, {64025, 17604355}, + {64026, 17604611}, {64027, 17604867}, {64028, 17605123}, {64029, 17605379}, + {64030, 17172995}, {64031, 1}, {64032, 17605635}, {64033, 1}, + {64034, 17605891}, {64035, 1}, {64037, 17606147}, {64038, 17606403}, + {64039, 1}, {64042, 17606659}, {64043, 17606915}, {64044, 17607171}, + {64045, 17607427}, {64046, 17607683}, {64047, 17607939}, {64048, 17608195}, + {64049, 17608451}, {64050, 17608707}, {64051, 17608963}, {64052, 17609219}, + {64053, 17609475}, {64054, 17609731}, {64055, 17609987}, {64056, 17610243}, + {64057, 17610499}, {64058, 17610755}, {64059, 17611011}, {64060, 17152771}, + {64061, 17611267}, {64062, 17611523}, {64063, 17611779}, {64064, 17612035}, + {64065, 17612291}, {64066, 17612547}, {64067, 17612803}, {64068, 17613059}, + {64069, 17613315}, {64070, 17613571}, {64071, 17613827}, {64072, 17614083}, + {64073, 17614339}, {64074, 17614595}, {64075, 17614851}, {64076, 17264899}, + {64077, 17615107}, {64078, 17615363}, {64079, 17615619}, {64080, 17615875}, + {64081, 17267971}, {64082, 17616131}, {64083, 17616387}, {64084, 17616643}, + {64085, 17616899}, {64086, 17617155}, {64087, 17574915}, {64088, 17617411}, + {64089, 17617667}, {64090, 17617923}, {64091, 17618179}, {64092, 17618435}, + {64093, 17618691}, {64095, 17618947}, {64096, 17619203}, {64097, 17619459}, + {64098, 17619715}, {64099, 17619971}, {64100, 17620227}, {64101, 17620483}, + {64102, 17620739}, {64103, 17606147}, {64104, 17620995}, {64105, 17621251}, + {64106, 17621507}, {64107, 17621763}, {64108, 17622019}, {64109, 17622275}, + {64110, 2}, {64112, 17622531}, {64113, 17622787}, {64114, 17623043}, + {64115, 17623299}, {64116, 17623555}, {64117, 17623811}, {64118, 17624067}, + {64119, 17624323}, {64120, 17609731}, {64121, 17624579}, {64122, 17624835}, + {64123, 17625091}, {64124, 17602819}, {64125, 17625347}, {64126, 17625603}, + {64127, 17625859}, {64128, 17626115}, {64129, 17626371}, {64130, 17626627}, + {64131, 17626883}, {64132, 17627139}, {64133, 17627395}, {64134, 17627651}, + {64135, 17627907}, {64136, 17628163}, {64137, 17611779}, {64138, 17628419}, + {64139, 17612035}, {64140, 17628675}, {64141, 17628931}, {64142, 17629187}, + {64143, 17629443}, {64144, 17629699}, {64145, 17603075}, {64146, 17548547}, + {64147, 17629955}, {64148, 17630211}, {64149, 17161219}, {64150, 17565955}, + {64151, 17586947}, {64152, 17630467}, {64153, 17630723}, {64154, 17613827}, + {64155, 17630979}, {64156, 17614083}, {64157, 17631235}, {64158, 17631491}, + {64159, 17631747}, {64160, 17603587}, {64161, 17632003}, {64162, 17632259}, + {64163, 17632515}, {64164, 17632771}, {64165, 17633027}, {64166, 17603843}, + {64167, 17633283}, {64168, 17633539}, {64169, 17633795}, {64170, 17634051}, + {64171, 17634307}, {64172, 17634563}, {64173, 17617155}, {64174, 17634819}, + {64175, 17635075}, {64176, 17574915}, {64177, 17635331}, {64178, 17618179}, + {64179, 17635587}, {64180, 17635843}, {64181, 17636099}, {64182, 17636355}, + {64183, 17636611}, {64184, 17619459}, {64185, 17636867}, {64186, 17605891}, + {64187, 17637123}, {64188, 17619715}, {64189, 17561091}, {64190, 17637379}, + {64191, 17619971}, {64192, 17637635}, {64193, 17620483}, {64194, 17637891}, + {64195, 17638147}, {64196, 17638403}, {64197, 17638659}, {64198, 17638915}, + {64199, 17620995}, {64200, 17605123}, {64201, 17639171}, {64202, 17621251}, + {64203, 17639427}, {64204, 17621507}, {64205, 17639683}, {64206, 17195779}, + {64207, 17639939}, {64208, 17640195}, {64209, 17640451}, {64210, 17640707}, + {64211, 17640963}, {64212, 17641219}, {64213, 17641475}, {64214, 17641731}, + {64215, 17641987}, {64216, 17642243}, {64217, 17642499}, {64218, 2}, + {64256, 34419971}, {64257, 34420483}, {64258, 34420995}, {64259, 51197443}, + {64260, 51198723}, {64261, 33559043}, {64263, 2}, {64275, 34422275}, + {64276, 34422787}, {64277, 34423299}, {64278, 34423811}, {64279, 34424323}, + {64280, 2}, {64285, 34424835}, {64286, 1}, {64287, 34425347}, + {64288, 17648643}, {64289, 17043971}, {64290, 17044739}, {64291, 17648899}, + {64292, 17649155}, {64293, 17649411}, {64294, 17649667}, {64295, 17649923}, + {64296, 17650179}, {64297, 17036803}, {64298, 34427651}, {64299, 34428163}, + {64300, 51205891}, {64301, 51206659}, {64302, 34430211}, {64303, 34430723}, + {64304, 34431235}, {64305, 34431747}, {64306, 34432259}, {64307, 34432771}, + {64308, 34433283}, {64309, 34433795}, {64310, 34434307}, {64311, 2}, + {64312, 34434819}, {64313, 34435331}, {64314, 34435843}, {64315, 34436355}, + {64316, 34436867}, {64317, 2}, {64318, 34437379}, {64319, 2}, + {64320, 34437891}, {64321, 34438403}, {64322, 2}, {64323, 34438915}, + {64324, 34439427}, {64325, 2}, {64326, 34439939}, {64327, 34440451}, + {64328, 34440963}, {64329, 34428675}, {64330, 34441475}, {64331, 34441987}, + {64332, 34442499}, {64333, 34443011}, {64334, 34443523}, {64335, 34444035}, + {64336, 17667331}, {64338, 17667587}, {64342, 17667843}, {64346, 17668099}, + {64350, 17668355}, {64354, 17668611}, {64358, 17668867}, {64362, 17669123}, + {64366, 17669379}, {64370, 17669635}, {64374, 17669891}, {64378, 17670147}, + {64382, 17670403}, {64386, 17670659}, {64388, 17670915}, {64390, 17671171}, + {64392, 17671427}, {64394, 17671683}, {64396, 17671939}, {64398, 17672195}, + {64402, 17672451}, {64406, 17672707}, {64410, 17672963}, {64414, 17673219}, + {64416, 17673475}, {64420, 17673731}, {64422, 17673987}, {64426, 17674243}, + {64430, 17674499}, {64432, 17674755}, {64434, 1}, {64451, 2}, + {64467, 17675011}, {64471, 16911363}, {64473, 17675267}, {64475, 17675523}, + {64477, 33688579}, {64478, 17675779}, {64480, 17676035}, {64482, 17676291}, + {64484, 17676547}, {64488, 17676803}, {64490, 34454275}, {64492, 34454787}, + {64494, 34455299}, {64496, 34455811}, {64498, 34456323}, {64500, 34456835}, + {64502, 34457347}, {64505, 34457859}, {64508, 17681155}, {64512, 34458627}, + {64513, 34459139}, {64514, 34459651}, {64515, 34457859}, {64516, 34460163}, + {64517, 34460675}, {64518, 34461187}, {64519, 34461699}, {64520, 34462211}, + {64521, 34462723}, {64522, 34463235}, {64523, 34463747}, {64524, 34464259}, + {64525, 34464771}, {64526, 34465283}, {64527, 34465795}, {64528, 34466307}, + {64529, 34466819}, {64530, 34467331}, {64531, 34467843}, {64532, 34468355}, + {64533, 34468867}, {64534, 34469379}, {64535, 34469123}, {64536, 34469891}, + {64537, 34470403}, {64538, 34470915}, {64539, 34471427}, {64540, 34471939}, + {64541, 34472451}, {64542, 34472963}, {64543, 34473475}, {64544, 34473987}, + {64545, 34474499}, {64546, 34475011}, {64547, 34475523}, {64548, 34476035}, + {64549, 34476547}, {64550, 34477059}, {64551, 34477571}, {64552, 34478083}, + {64553, 34478595}, {64554, 34479107}, {64555, 34479619}, {64556, 34480131}, + {64557, 34480643}, {64558, 34481155}, {64559, 34481667}, {64560, 34482179}, + {64561, 34482691}, {64562, 34483203}, {64563, 34483715}, {64564, 34484227}, + {64565, 34484739}, {64566, 34485251}, {64567, 34485763}, {64568, 34486275}, + {64569, 34486787}, {64570, 34487299}, {64571, 34487811}, {64572, 34488323}, + {64573, 34488835}, {64574, 34489347}, {64575, 34489859}, {64576, 34490371}, + {64577, 34490883}, {64578, 34491395}, {64579, 34491907}, {64580, 34492419}, + {64581, 34492931}, {64582, 34469635}, {64583, 34470147}, {64584, 34493443}, + {64585, 34493955}, {64586, 34494467}, {64587, 34494979}, {64588, 34495491}, + {64589, 34496003}, {64590, 34496515}, {64591, 34497027}, {64592, 34497539}, + {64593, 34498051}, {64594, 34498563}, {64595, 34499075}, {64596, 34499587}, + {64597, 34468611}, {64598, 34500099}, {64599, 34500611}, {64600, 34492675}, + {64601, 34501123}, {64602, 34499843}, {64603, 34501635}, {64604, 34502147}, + {64605, 34502659}, {64606, 51280387}, {64607, 51281155}, {64608, 51281923}, + {64609, 51282691}, {64610, 51283459}, {64611, 51284227}, {64612, 34507779}, + {64613, 34508291}, {64614, 34459651}, {64615, 34508803}, {64616, 34457859}, + {64617, 34460163}, {64618, 34509315}, {64619, 34509827}, {64620, 34462211}, + {64621, 34510339}, {64622, 34462723}, {64623, 34463235}, {64624, 34510851}, + {64625, 34511363}, {64626, 34465283}, {64627, 34511875}, {64628, 34465795}, + {64629, 34466307}, {64630, 34512387}, {64631, 34512899}, {64632, 34467331}, + {64633, 34513411}, {64634, 34467843}, {64635, 34468355}, {64636, 34482691}, + {64637, 34483203}, {64638, 34484739}, {64639, 34485251}, {64640, 34485763}, + {64641, 34487811}, {64642, 34488323}, {64643, 34488835}, {64644, 34489347}, + {64645, 34491395}, {64646, 34491907}, {64647, 34492419}, {64648, 34513923}, + {64649, 34493443}, {64650, 34514435}, {64651, 34514947}, {64652, 34496515}, + {64653, 34515459}, {64654, 34497027}, {64655, 34497539}, {64656, 34502659}, + {64657, 34515971}, {64658, 34516483}, {64659, 34492675}, {64660, 34494723}, + {64661, 34501123}, {64662, 34499843}, {64663, 34458627}, {64664, 34459139}, + {64665, 34516995}, {64666, 34459651}, {64667, 34517507}, {64668, 34460675}, + {64669, 34461187}, {64670, 34461699}, {64671, 34462211}, {64672, 34518019}, + {64673, 34463747}, {64674, 34464259}, {64675, 34464771}, {64676, 34465283}, + {64677, 34518531}, {64678, 34467331}, {64679, 34468867}, {64680, 34469379}, + {64681, 34469123}, {64682, 34469891}, {64683, 34470403}, {64684, 34471427}, + {64685, 34471939}, {64686, 34472451}, {64687, 34472963}, {64688, 34473475}, + {64689, 34473987}, {64690, 34519043}, {64691, 34474499}, {64692, 34475011}, + {64693, 34475523}, {64694, 34476035}, {64695, 34476547}, {64696, 34477059}, + {64697, 34478083}, {64698, 34478595}, {64699, 34479107}, {64700, 34479619}, + {64701, 34480131}, {64702, 34480643}, {64703, 34481155}, {64704, 34481667}, + {64705, 34482179}, {64706, 34483715}, {64707, 34484227}, {64708, 34486275}, + {64709, 34486787}, {64710, 34487299}, {64711, 34487811}, {64712, 34488323}, + {64713, 34489859}, {64714, 34490371}, {64715, 34490883}, {64716, 34491395}, + {64717, 34519555}, {64718, 34492931}, {64719, 34469635}, {64720, 34470147}, + {64721, 34493443}, {64722, 34494979}, {64723, 34495491}, {64724, 34496003}, + {64725, 34496515}, {64726, 34520067}, {64727, 34498051}, {64728, 34498563}, + {64729, 34520579}, {64730, 34468611}, {64731, 34500099}, {64732, 34500611}, + {64733, 34492675}, {64734, 34497795}, {64735, 34459651}, {64736, 34517507}, + {64737, 34462211}, {64738, 34518019}, {64739, 34465283}, {64740, 34518531}, + {64741, 34467331}, {64742, 34521091}, {64743, 34473475}, {64744, 34521603}, + {64745, 34522115}, {64746, 34522627}, {64747, 34487811}, {64748, 34488323}, + {64749, 34491395}, {64750, 34496515}, {64751, 34520067}, {64752, 34492675}, + {64753, 34497795}, {64754, 51300355}, {64755, 51301123}, {64756, 51301891}, + {64757, 34525443}, {64758, 34525955}, {64759, 34526467}, {64760, 34526979}, + {64761, 34527491}, {64762, 34528003}, {64763, 34528515}, {64764, 34529027}, + {64765, 34529539}, {64766, 34530051}, {64767, 34530563}, {64768, 34500355}, + {64769, 34531075}, {64770, 34531587}, {64771, 34532099}, {64772, 34500867}, + {64773, 34532611}, {64774, 34533123}, {64775, 34533635}, {64776, 34534147}, + {64777, 34534659}, {64778, 34535171}, {64779, 34535683}, {64780, 34522115}, + {64781, 34536195}, {64782, 34536707}, {64783, 34537219}, {64784, 34537731}, + {64785, 34525443}, {64786, 34525955}, {64787, 34526467}, {64788, 34526979}, + {64789, 34527491}, {64790, 34528003}, {64791, 34528515}, {64792, 34529027}, + {64793, 34529539}, {64794, 34530051}, {64795, 34530563}, {64796, 34500355}, + {64797, 34531075}, {64798, 34531587}, {64799, 34532099}, {64800, 34500867}, + {64801, 34532611}, {64802, 34533123}, {64803, 34533635}, {64804, 34534147}, + {64805, 34534659}, {64806, 34535171}, {64807, 34535683}, {64808, 34522115}, + {64809, 34536195}, {64810, 34536707}, {64811, 34537219}, {64812, 34537731}, + {64813, 34534659}, {64814, 34535171}, {64815, 34535683}, {64816, 34522115}, + {64817, 34521603}, {64818, 34522627}, {64819, 34477571}, {64820, 34471939}, + {64821, 34472451}, {64822, 34472963}, {64823, 34534659}, {64824, 34535171}, + {64825, 34535683}, {64826, 34477571}, {64827, 34478083}, {64828, 34538243}, + {64830, 1}, {64848, 51315971}, {64849, 51316739}, {64851, 51317507}, + {64852, 51318275}, {64853, 51319043}, {64854, 51319811}, {64855, 51320579}, + {64856, 51246595}, {64858, 51321347}, {64859, 51322115}, {64860, 51322883}, + {64861, 51323651}, {64862, 51324419}, {64863, 51325187}, {64865, 51325955}, + {64866, 51326723}, {64868, 51327491}, {64870, 51328259}, {64871, 51329027}, + {64873, 51329795}, {64874, 51330563}, {64876, 51331331}, {64878, 51332099}, + {64879, 51332867}, {64881, 51333635}, {64883, 51334403}, {64884, 51335171}, + {64885, 51335939}, {64886, 51336707}, {64888, 51337475}, {64889, 51338243}, + {64890, 51339011}, {64891, 51339779}, {64892, 51340547}, {64894, 51341315}, + {64895, 51342083}, {64896, 51342851}, {64897, 51343619}, {64898, 51344387}, + {64899, 51345155}, {64901, 51345923}, {64903, 51346691}, {64905, 51347459}, + {64906, 51246851}, {64907, 51348227}, {64908, 51348995}, {64909, 51270147}, + {64910, 51247363}, {64911, 51349763}, {64912, 2}, {64914, 51350531}, + {64915, 51351299}, {64916, 51352067}, {64917, 51352835}, {64918, 51353603}, + {64919, 51354371}, {64921, 51355139}, {64922, 51355907}, {64923, 51356675}, + {64924, 51357443}, {64926, 51358211}, {64927, 51358979}, {64928, 51359747}, + {64929, 51360515}, {64930, 51361283}, {64931, 51362051}, {64932, 51362819}, + {64933, 51363587}, {64934, 51364355}, {64935, 51365123}, {64936, 51365891}, + {64937, 51366659}, {64938, 51367427}, {64939, 51368195}, {64940, 51368963}, + {64941, 51369731}, {64942, 51277315}, {64943, 51370499}, {64944, 51371267}, + {64945, 51372035}, {64946, 51372803}, {64947, 51373571}, {64948, 51341315}, + {64949, 51342851}, {64950, 51374339}, {64951, 51375107}, {64952, 51375875}, + {64953, 51376643}, {64954, 51377411}, {64955, 51378179}, {64956, 51377411}, + {64957, 51375875}, {64958, 51378947}, {64959, 51379715}, {64960, 51380483}, + {64961, 51381251}, {64962, 51382019}, {64963, 51378179}, {64964, 51335939}, + {64965, 51328259}, {64966, 51382787}, {64967, 51383555}, {64968, 2}, + {64975, 1}, {64976, 2}, {65008, 51384323}, {65009, 51385091}, + {65010, 68163075}, {65011, 68164099}, {65012, 68165123}, {65013, 68166147}, + {65014, 68167171}, {65015, 68168195}, {65016, 68169219}, {65017, 51393027}, + {65018, 303052035}, {65019, 135284483}, {65020, 68177667}, {65021, 1}, + {65024, 0}, {65040, 17847043}, {65041, 17847299}, {65042, 2}, + {65043, 17110275}, {65044, 16848643}, {65045, 17032707}, {65046, 17033731}, + {65047, 17847555}, {65048, 17847811}, {65049, 2}, {65056, 1}, + {65072, 2}, {65073, 17848067}, {65074, 17848323}, {65075, 17848579}, + {65077, 17037571}, {65078, 17037827}, {65079, 17848835}, {65080, 17849091}, + {65081, 17849347}, {65082, 17849603}, {65083, 17849859}, {65084, 17850115}, + {65085, 17850371}, {65086, 17850627}, {65087, 17067011}, {65088, 17067267}, + {65089, 17850883}, {65090, 17851139}, {65091, 17851395}, {65092, 17851651}, + {65093, 1}, {65095, 17851907}, {65096, 17852163}, {65097, 33810435}, + {65101, 17848579}, {65104, 17847043}, {65105, 17847299}, {65106, 2}, + {65108, 16848643}, {65109, 17110275}, {65110, 17033731}, {65111, 17032707}, + {65112, 17848067}, {65113, 17037571}, {65114, 17037827}, {65115, 17848835}, + {65116, 17849091}, {65117, 17849347}, {65118, 17849603}, {65119, 17852419}, + {65120, 17852675}, {65121, 17852931}, {65122, 17036803}, {65123, 17853187}, + {65124, 17853443}, {65125, 17853699}, {65126, 17037315}, {65127, 2}, + {65128, 17853955}, {65129, 17854211}, {65130, 17854467}, {65131, 17854723}, + {65132, 2}, {65136, 34632195}, {65137, 34632707}, {65138, 34503171}, + {65139, 1}, {65140, 34503939}, {65141, 2}, {65142, 34504707}, + {65143, 34523139}, {65144, 34505475}, {65145, 34523907}, {65146, 34506243}, + {65147, 34524675}, {65148, 34507011}, {65149, 34633219}, {65150, 34633731}, + {65151, 34634243}, {65152, 17857539}, {65153, 17857795}, {65155, 17858051}, + {65157, 17858307}, {65159, 17858563}, {65161, 17677059}, {65165, 16910339}, + {65167, 17683459}, {65171, 17858819}, {65173, 17686531}, {65177, 17689603}, + {65181, 17681667}, {65185, 17682179}, {65189, 17684739}, {65193, 17834243}, + {65195, 17724419}, {65197, 17724931}, {65199, 17731331}, {65201, 17694723}, + {65205, 17744899}, {65209, 17696771}, {65213, 17697795}, {65217, 17699843}, + {65221, 17700867}, {65225, 17701379}, {65229, 17702403}, {65233, 17703427}, + {65237, 17706499}, {65241, 17708547}, {65245, 17710851}, {65249, 17682691}, + {65253, 17717763}, {65257, 17720835}, {65261, 16910851}, {65263, 17676803}, + {65265, 16911875}, {65269, 34636291}, {65271, 34636803}, {65273, 34637315}, + {65275, 34622211}, {65277, 2}, {65279, 0}, {65280, 2}, + {65281, 17032707}, {65282, 17860611}, {65283, 17852419}, {65284, 17854211}, + {65285, 17854467}, {65286, 17852675}, {65287, 17860867}, {65288, 17037571}, + {65289, 17037827}, {65290, 17852931}, {65291, 17036803}, {65292, 17847043}, + {65293, 17853187}, {65294, 17196291}, {65295, 17038339}, {65296, 17035267}, {65297, 16786947}, {65298, 16785155}, {65299, 16785411}, {65300, 16787715}, - {65301, 17035779}, {65302, 17036035}, {65303, 17036291}, {65304, 17036547}, - {65305, 17036803}, {65306, 17110531}, {65307, 16848643}, {65308, 17853699}, - {65309, 17037571}, {65310, 17853955}, {65311, 17033987}, {65312, 17854979}, + {65301, 17035523}, {65302, 17035779}, {65303, 17036035}, {65304, 17036291}, + {65305, 17036547}, {65306, 17110275}, {65307, 16848643}, {65308, 17853443}, + {65309, 17037315}, {65310, 17853699}, {65311, 17033731}, {65312, 17854723}, {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, 17852163}, {65340, 17854211}, - {65341, 17852419}, {65342, 17861379}, {65343, 17848835}, {65344, 17027075}, + {65337, 16783363}, {65338, 16783619}, {65339, 17851907}, {65340, 17853955}, + {65341, 17852163}, {65342, 17861123}, {65343, 17848579}, {65344, 17026819}, {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, 17849091}, {65372, 17861635}, - {65373, 17849347}, {65374, 17861891}, {65375, 17862147}, {65376, 17862403}, - {65377, 17196547}, {65378, 17851139}, {65379, 17851395}, {65380, 17847555}, - {65381, 17862659}, {65382, 17316867}, {65383, 17319427}, {65384, 17362435}, - {65385, 17862915}, {65386, 17363971}, {65387, 17323523}, {65388, 17863171}, - {65389, 17333763}, {65390, 17379587}, {65391, 17329155}, {65392, 17318147}, - {65393, 17305603}, {65394, 17305859}, {65395, 17306115}, {65396, 17306371}, - {65397, 17306627}, {65398, 17306883}, {65399, 17307139}, {65400, 17307395}, - {65401, 17307651}, {65402, 17199107}, {65403, 17307907}, {65404, 17308163}, - {65405, 17308419}, {65406, 17308675}, {65407, 17308931}, {65408, 17309187}, - {65409, 17309443}, {65410, 17309699}, {65411, 17309955}, {65412, 17199363}, - {65413, 17310211}, {65414, 17310467}, {65415, 17310723}, {65416, 17310979}, - {65417, 17311235}, {65418, 17311491}, {65419, 17311747}, {65420, 17312003}, - {65421, 17312259}, {65422, 17312515}, {65423, 17312771}, {65424, 17313027}, - {65425, 17313283}, {65426, 17313539}, {65427, 17313795}, {65428, 17314051}, - {65429, 17314307}, {65430, 17314563}, {65431, 17314819}, {65432, 17315075}, - {65433, 17315331}, {65434, 17315587}, {65435, 17315843}, {65436, 17316099}, - {65437, 17319939}, {65438, 17197827}, {65439, 17198339}, {65440, 2}, - {65441, 17199619}, {65442, 17199875}, {65443, 17200131}, {65444, 17200387}, - {65445, 17200643}, {65446, 17200899}, {65447, 17201155}, {65448, 17201411}, - {65449, 17201667}, {65450, 17201923}, {65451, 17202179}, {65452, 17202435}, - {65453, 17202691}, {65454, 17202947}, {65455, 17203203}, {65456, 17203459}, - {65457, 17203715}, {65458, 17203971}, {65459, 17204227}, {65460, 17204483}, - {65461, 17204739}, {65462, 17204995}, {65463, 17205251}, {65464, 17205507}, - {65465, 17205763}, {65466, 17206019}, {65467, 17206275}, {65468, 17206531}, - {65469, 17206787}, {65470, 17207043}, {65471, 2}, {65474, 17207299}, - {65475, 17207555}, {65476, 17207811}, {65477, 17208067}, {65478, 17208323}, - {65479, 17208579}, {65480, 2}, {65482, 17208835}, {65483, 17209091}, - {65484, 17209347}, {65485, 17209603}, {65486, 17209859}, {65487, 17210115}, - {65488, 2}, {65490, 17210371}, {65491, 17210627}, {65492, 17210883}, - {65493, 17211139}, {65494, 17211395}, {65495, 17211651}, {65496, 2}, - {65498, 17211907}, {65499, 17212163}, {65500, 17212419}, {65501, 2}, - {65504, 17863427}, {65505, 17863683}, {65506, 17863939}, {65507, 33561859}, - {65508, 17864195}, {65509, 17864451}, {65510, 17864707}, {65511, 2}, - {65512, 17864963}, {65513, 17865219}, {65514, 17865475}, {65515, 17865731}, - {65516, 17865987}, {65517, 17866243}, {65518, 17866499}, {65519, 2}, + {65369, 16783363}, {65370, 16783619}, {65371, 17848835}, {65372, 17861379}, + {65373, 17849091}, {65374, 17861635}, {65375, 17861891}, {65376, 17862147}, + {65377, 17196291}, {65378, 17850883}, {65379, 17851139}, {65380, 17847299}, + {65381, 17862403}, {65382, 17316611}, {65383, 17319171}, {65384, 17362179}, + {65385, 17862659}, {65386, 17363715}, {65387, 17323267}, {65388, 17862915}, + {65389, 17333507}, {65390, 17379331}, {65391, 17328899}, {65392, 17317891}, + {65393, 17305347}, {65394, 17305603}, {65395, 17305859}, {65396, 17306115}, + {65397, 17306371}, {65398, 17306627}, {65399, 17306883}, {65400, 17307139}, + {65401, 17307395}, {65402, 17198851}, {65403, 17307651}, {65404, 17307907}, + {65405, 17308163}, {65406, 17308419}, {65407, 17308675}, {65408, 17308931}, + {65409, 17309187}, {65410, 17309443}, {65411, 17309699}, {65412, 17199107}, + {65413, 17309955}, {65414, 17310211}, {65415, 17310467}, {65416, 17310723}, + {65417, 17310979}, {65418, 17311235}, {65419, 17311491}, {65420, 17311747}, + {65421, 17312003}, {65422, 17312259}, {65423, 17312515}, {65424, 17312771}, + {65425, 17313027}, {65426, 17313283}, {65427, 17313539}, {65428, 17313795}, + {65429, 17314051}, {65430, 17314307}, {65431, 17314563}, {65432, 17314819}, + {65433, 17315075}, {65434, 17315331}, {65435, 17315587}, {65436, 17315843}, + {65437, 17319683}, {65438, 17197571}, {65439, 17198083}, {65440, 2}, + {65441, 17199363}, {65442, 17199619}, {65443, 17199875}, {65444, 17200131}, + {65445, 17200387}, {65446, 17200643}, {65447, 17200899}, {65448, 17201155}, + {65449, 17201411}, {65450, 17201667}, {65451, 17201923}, {65452, 17202179}, + {65453, 17202435}, {65454, 17202691}, {65455, 17202947}, {65456, 17203203}, + {65457, 17203459}, {65458, 17203715}, {65459, 17203971}, {65460, 17204227}, + {65461, 17204483}, {65462, 17204739}, {65463, 17204995}, {65464, 17205251}, + {65465, 17205507}, {65466, 17205763}, {65467, 17206019}, {65468, 17206275}, + {65469, 17206531}, {65470, 17206787}, {65471, 2}, {65474, 17207043}, + {65475, 17207299}, {65476, 17207555}, {65477, 17207811}, {65478, 17208067}, + {65479, 17208323}, {65480, 2}, {65482, 17208579}, {65483, 17208835}, + {65484, 17209091}, {65485, 17209347}, {65486, 17209603}, {65487, 17209859}, + {65488, 2}, {65490, 17210115}, {65491, 17210371}, {65492, 17210627}, + {65493, 17210883}, {65494, 17211139}, {65495, 17211395}, {65496, 2}, + {65498, 17211651}, {65499, 17211907}, {65500, 17212163}, {65501, 2}, + {65504, 17863171}, {65505, 17863427}, {65506, 17863683}, {65507, 33561859}, + {65508, 17863939}, {65509, 17864195}, {65510, 17864451}, {65511, 2}, + {65512, 17864707}, {65513, 17864963}, {65514, 17865219}, {65515, 17865475}, + {65516, 17865731}, {65517, 17865987}, {65518, 17866243}, {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}, @@ -2011,56 +2012,56 @@ const uint32_t table[8000][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, 17866755}, {66561, 17867011}, {66562, 17867267}, {66563, 17867523}, - {66564, 17867779}, {66565, 17868035}, {66566, 17868291}, {66567, 17868547}, - {66568, 17868803}, {66569, 17869059}, {66570, 17869315}, {66571, 17869571}, - {66572, 17869827}, {66573, 17870083}, {66574, 17870339}, {66575, 17870595}, - {66576, 17870851}, {66577, 17871107}, {66578, 17871363}, {66579, 17871619}, - {66580, 17871875}, {66581, 17872131}, {66582, 17872387}, {66583, 17872643}, - {66584, 17872899}, {66585, 17873155}, {66586, 17873411}, {66587, 17873667}, - {66588, 17873923}, {66589, 17874179}, {66590, 17874435}, {66591, 17874691}, - {66592, 17874947}, {66593, 17875203}, {66594, 17875459}, {66595, 17875715}, - {66596, 17875971}, {66597, 17876227}, {66598, 17876483}, {66599, 17876739}, + {66560, 17866499}, {66561, 17866755}, {66562, 17867011}, {66563, 17867267}, + {66564, 17867523}, {66565, 17867779}, {66566, 17868035}, {66567, 17868291}, + {66568, 17868547}, {66569, 17868803}, {66570, 17869059}, {66571, 17869315}, + {66572, 17869571}, {66573, 17869827}, {66574, 17870083}, {66575, 17870339}, + {66576, 17870595}, {66577, 17870851}, {66578, 17871107}, {66579, 17871363}, + {66580, 17871619}, {66581, 17871875}, {66582, 17872131}, {66583, 17872387}, + {66584, 17872643}, {66585, 17872899}, {66586, 17873155}, {66587, 17873411}, + {66588, 17873667}, {66589, 17873923}, {66590, 17874179}, {66591, 17874435}, + {66592, 17874691}, {66593, 17874947}, {66594, 17875203}, {66595, 17875459}, + {66596, 17875715}, {66597, 17875971}, {66598, 17876227}, {66599, 17876483}, {66600, 1}, {66718, 2}, {66720, 1}, {66730, 2}, - {66736, 17876995}, {66737, 17877251}, {66738, 17877507}, {66739, 17877763}, - {66740, 17878019}, {66741, 17878275}, {66742, 17878531}, {66743, 17878787}, - {66744, 17879043}, {66745, 17879299}, {66746, 17879555}, {66747, 17879811}, - {66748, 17880067}, {66749, 17880323}, {66750, 17880579}, {66751, 17880835}, - {66752, 17881091}, {66753, 17881347}, {66754, 17881603}, {66755, 17881859}, - {66756, 17882115}, {66757, 17882371}, {66758, 17882627}, {66759, 17882883}, - {66760, 17883139}, {66761, 17883395}, {66762, 17883651}, {66763, 17883907}, - {66764, 17884163}, {66765, 17884419}, {66766, 17884675}, {66767, 17884931}, - {66768, 17885187}, {66769, 17885443}, {66770, 17885699}, {66771, 17885955}, + {66736, 17876739}, {66737, 17876995}, {66738, 17877251}, {66739, 17877507}, + {66740, 17877763}, {66741, 17878019}, {66742, 17878275}, {66743, 17878531}, + {66744, 17878787}, {66745, 17879043}, {66746, 17879299}, {66747, 17879555}, + {66748, 17879811}, {66749, 17880067}, {66750, 17880323}, {66751, 17880579}, + {66752, 17880835}, {66753, 17881091}, {66754, 17881347}, {66755, 17881603}, + {66756, 17881859}, {66757, 17882115}, {66758, 17882371}, {66759, 17882627}, + {66760, 17882883}, {66761, 17883139}, {66762, 17883395}, {66763, 17883651}, + {66764, 17883907}, {66765, 17884163}, {66766, 17884419}, {66767, 17884675}, + {66768, 17884931}, {66769, 17885187}, {66770, 17885443}, {66771, 17885699}, {66772, 2}, {66776, 1}, {66812, 2}, {66816, 1}, {66856, 2}, {66864, 1}, {66916, 2}, {66927, 1}, - {66928, 17886211}, {66929, 17886467}, {66930, 17886723}, {66931, 17886979}, - {66932, 17887235}, {66933, 17887491}, {66934, 17887747}, {66935, 17888003}, - {66936, 17888259}, {66937, 17888515}, {66938, 17888771}, {66939, 2}, - {66940, 17889027}, {66941, 17889283}, {66942, 17889539}, {66943, 17889795}, - {66944, 17890051}, {66945, 17890307}, {66946, 17890563}, {66947, 17890819}, - {66948, 17891075}, {66949, 17891331}, {66950, 17891587}, {66951, 17891843}, - {66952, 17892099}, {66953, 17892355}, {66954, 17892611}, {66955, 2}, - {66956, 17892867}, {66957, 17893123}, {66958, 17893379}, {66959, 17893635}, - {66960, 17893891}, {66961, 17894147}, {66962, 17894403}, {66963, 2}, - {66964, 17894659}, {66965, 17894915}, {66966, 2}, {66967, 1}, + {66928, 17885955}, {66929, 17886211}, {66930, 17886467}, {66931, 17886723}, + {66932, 17886979}, {66933, 17887235}, {66934, 17887491}, {66935, 17887747}, + {66936, 17888003}, {66937, 17888259}, {66938, 17888515}, {66939, 2}, + {66940, 17888771}, {66941, 17889027}, {66942, 17889283}, {66943, 17889539}, + {66944, 17889795}, {66945, 17890051}, {66946, 17890307}, {66947, 17890563}, + {66948, 17890819}, {66949, 17891075}, {66950, 17891331}, {66951, 17891587}, + {66952, 17891843}, {66953, 17892099}, {66954, 17892355}, {66955, 2}, + {66956, 17892611}, {66957, 17892867}, {66958, 17893123}, {66959, 17893379}, + {66960, 17893635}, {66961, 17893891}, {66962, 17894147}, {66963, 2}, + {66964, 17894403}, {66965, 17894659}, {66966, 2}, {66967, 1}, {66978, 2}, {66979, 1}, {66994, 2}, {66995, 1}, {67002, 2}, {67003, 1}, {67005, 2}, {67072, 1}, {67383, 2}, {67392, 1}, {67414, 2}, {67424, 1}, - {67432, 2}, {67456, 1}, {67457, 17895171}, {67458, 17895427}, - {67459, 16791043}, {67460, 17895683}, {67461, 16814083}, {67462, 2}, - {67463, 17895939}, {67464, 17896195}, {67465, 17896451}, {67466, 17896707}, - {67467, 16815363}, {67468, 16815619}, {67469, 17896963}, {67470, 17897219}, - {67471, 17897475}, {67472, 17897731}, {67473, 17897987}, {67474, 17898243}, - {67475, 16817155}, {67476, 17898499}, {67477, 16802051}, {67478, 17898755}, - {67479, 17899011}, {67480, 17899267}, {67481, 17899523}, {67482, 17899779}, - {67483, 17512963}, {67484, 17900035}, {67485, 17900291}, {67486, 17900547}, - {67487, 17900803}, {67488, 17901059}, {67489, 17901315}, {67490, 16795395}, - {67491, 17901571}, {67492, 17901827}, {67493, 16781315}, {67494, 17902083}, - {67495, 17902339}, {67496, 17125379}, {67497, 17902595}, {67498, 16819971}, - {67499, 17902851}, {67500, 17903107}, {67501, 17903363}, {67502, 17903619}, - {67503, 16820995}, {67504, 17903875}, {67505, 2}, {67506, 17904131}, - {67507, 17904387}, {67508, 17904643}, {67509, 17904899}, {67510, 17905155}, - {67511, 17905411}, {67512, 17905667}, {67513, 17905923}, {67514, 17906179}, + {67432, 2}, {67456, 1}, {67457, 17894915}, {67458, 17895171}, + {67459, 16791043}, {67460, 17895427}, {67461, 16814083}, {67462, 2}, + {67463, 17895683}, {67464, 17895939}, {67465, 17896195}, {67466, 17896451}, + {67467, 16815363}, {67468, 16815619}, {67469, 17896707}, {67470, 17896963}, + {67471, 17897219}, {67472, 17897475}, {67473, 17897731}, {67474, 17897987}, + {67475, 16817155}, {67476, 17898243}, {67477, 16802051}, {67478, 17898499}, + {67479, 17898755}, {67480, 17899011}, {67481, 17899267}, {67482, 17899523}, + {67483, 17512707}, {67484, 17899779}, {67485, 17900035}, {67486, 17900291}, + {67487, 17900547}, {67488, 17900803}, {67489, 17901059}, {67490, 16795395}, + {67491, 17901315}, {67492, 17901571}, {67493, 16781315}, {67494, 17901827}, + {67495, 17902083}, {67496, 17125123}, {67497, 17902339}, {67498, 16819971}, + {67499, 17902595}, {67500, 17902851}, {67501, 17903107}, {67502, 17903363}, + {67503, 16820995}, {67504, 17903619}, {67505, 2}, {67506, 17903875}, + {67507, 17904131}, {67508, 17904387}, {67509, 17904643}, {67510, 17904899}, + {67511, 17905155}, {67512, 17905411}, {67513, 17905667}, {67514, 17905923}, {67515, 2}, {67584, 1}, {67590, 2}, {67592, 1}, {67593, 2}, {67594, 1}, {67638, 2}, {67639, 1}, {67641, 2}, {67644, 1}, {67645, 2}, {67647, 1}, @@ -2077,20 +2078,20 @@ const uint32_t table[8000][2] = {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, 17906435}, - {68737, 17906691}, {68738, 17906947}, {68739, 17907203}, {68740, 17907459}, - {68741, 17907715}, {68742, 17907971}, {68743, 17908227}, {68744, 17908483}, - {68745, 17908739}, {68746, 17908995}, {68747, 17909251}, {68748, 17909507}, - {68749, 17909763}, {68750, 17910019}, {68751, 17910275}, {68752, 17910531}, - {68753, 17910787}, {68754, 17911043}, {68755, 17911299}, {68756, 17911555}, - {68757, 17911811}, {68758, 17912067}, {68759, 17912323}, {68760, 17912579}, - {68761, 17912835}, {68762, 17913091}, {68763, 17913347}, {68764, 17913603}, - {68765, 17913859}, {68766, 17914115}, {68767, 17914371}, {68768, 17914627}, - {68769, 17914883}, {68770, 17915139}, {68771, 17915395}, {68772, 17915651}, - {68773, 17915907}, {68774, 17916163}, {68775, 17916419}, {68776, 17916675}, - {68777, 17916931}, {68778, 17917187}, {68779, 17917443}, {68780, 17917699}, - {68781, 17917955}, {68782, 17918211}, {68783, 17918467}, {68784, 17918723}, - {68785, 17918979}, {68786, 17919235}, {68787, 2}, {68800, 1}, + {68528, 2}, {68608, 1}, {68681, 2}, {68736, 17906179}, + {68737, 17906435}, {68738, 17906691}, {68739, 17906947}, {68740, 17907203}, + {68741, 17907459}, {68742, 17907715}, {68743, 17907971}, {68744, 17908227}, + {68745, 17908483}, {68746, 17908739}, {68747, 17908995}, {68748, 17909251}, + {68749, 17909507}, {68750, 17909763}, {68751, 17910019}, {68752, 17910275}, + {68753, 17910531}, {68754, 17910787}, {68755, 17911043}, {68756, 17911299}, + {68757, 17911555}, {68758, 17911811}, {68759, 17912067}, {68760, 17912323}, + {68761, 17912579}, {68762, 17912835}, {68763, 17913091}, {68764, 17913347}, + {68765, 17913603}, {68766, 17913859}, {68767, 17914115}, {68768, 17914371}, + {68769, 17914627}, {68770, 17914883}, {68771, 17915139}, {68772, 17915395}, + {68773, 17915651}, {68774, 17915907}, {68775, 17916163}, {68776, 17916419}, + {68777, 17916675}, {68778, 17916931}, {68779, 17917187}, {68780, 17917443}, + {68781, 17917699}, {68782, 17917955}, {68783, 17918211}, {68784, 17918467}, + {68785, 17918723}, {68786, 17918979}, {68787, 2}, {68800, 1}, {68851, 2}, {68858, 1}, {68904, 2}, {68912, 1}, {68922, 2}, {69216, 1}, {69247, 2}, {69248, 1}, {69290, 2}, {69291, 1}, {69294, 2}, {69296, 1}, @@ -2121,15 +2122,15 @@ const uint32_t table[8000][2] = {71258, 2}, {71264, 1}, {71277, 2}, {71296, 1}, {71354, 2}, {71360, 1}, {71370, 2}, {71424, 1}, {71451, 2}, {71453, 1}, {71468, 2}, {71472, 1}, - {71495, 2}, {71680, 1}, {71740, 2}, {71840, 17919491}, - {71841, 17919747}, {71842, 17920003}, {71843, 17920259}, {71844, 17920515}, - {71845, 17920771}, {71846, 17921027}, {71847, 17921283}, {71848, 17921539}, - {71849, 17921795}, {71850, 17922051}, {71851, 17922307}, {71852, 17922563}, - {71853, 17922819}, {71854, 17923075}, {71855, 17923331}, {71856, 17923587}, - {71857, 17923843}, {71858, 17924099}, {71859, 17924355}, {71860, 17924611}, - {71861, 17924867}, {71862, 17925123}, {71863, 17925379}, {71864, 17925635}, - {71865, 17925891}, {71866, 17926147}, {71867, 17926403}, {71868, 17926659}, - {71869, 17926915}, {71870, 17927171}, {71871, 17927427}, {71872, 1}, + {71495, 2}, {71680, 1}, {71740, 2}, {71840, 17919235}, + {71841, 17919491}, {71842, 17919747}, {71843, 17920003}, {71844, 17920259}, + {71845, 17920515}, {71846, 17920771}, {71847, 17921027}, {71848, 17921283}, + {71849, 17921539}, {71850, 17921795}, {71851, 17922051}, {71852, 17922307}, + {71853, 17922563}, {71854, 17922819}, {71855, 17923075}, {71856, 17923331}, + {71857, 17923587}, {71858, 17923843}, {71859, 17924099}, {71860, 17924355}, + {71861, 17924611}, {71862, 17924867}, {71863, 17925123}, {71864, 17925379}, + {71865, 17925635}, {71866, 17925891}, {71867, 17926147}, {71868, 17926403}, + {71869, 17926659}, {71870, 17926915}, {71871, 17927171}, {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}, @@ -2160,15 +2161,15 @@ const uint32_t table[8000][2] = {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}, {93760, 17927683}, - {93761, 17927939}, {93762, 17928195}, {93763, 17928451}, {93764, 17928707}, - {93765, 17928963}, {93766, 17929219}, {93767, 17929475}, {93768, 17929731}, - {93769, 17929987}, {93770, 17930243}, {93771, 17930499}, {93772, 17930755}, - {93773, 17931011}, {93774, 17931267}, {93775, 17931523}, {93776, 17931779}, - {93777, 17932035}, {93778, 17932291}, {93779, 17932547}, {93780, 17932803}, - {93781, 17933059}, {93782, 17933315}, {93783, 17933571}, {93784, 17933827}, - {93785, 17934083}, {93786, 17934339}, {93787, 17934595}, {93788, 17934851}, - {93789, 17935107}, {93790, 17935363}, {93791, 17935619}, {93792, 1}, + {93048, 2}, {93053, 1}, {93072, 2}, {93760, 17927427}, + {93761, 17927683}, {93762, 17927939}, {93763, 17928195}, {93764, 17928451}, + {93765, 17928707}, {93766, 17928963}, {93767, 17929219}, {93768, 17929475}, + {93769, 17929731}, {93770, 17929987}, {93771, 17930243}, {93772, 17930499}, + {93773, 17930755}, {93774, 17931011}, {93775, 17931267}, {93776, 17931523}, + {93777, 17931779}, {93778, 17932035}, {93779, 17932291}, {93780, 17932547}, + {93781, 17932803}, {93782, 17933059}, {93783, 17933315}, {93784, 17933571}, + {93785, 17933827}, {93786, 17934083}, {93787, 17934339}, {93788, 17934595}, + {93789, 17934851}, {93790, 17935107}, {93791, 17935363}, {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}, @@ -2183,11 +2184,11 @@ const uint32_t table[8000][2] = {113824, 0}, {113828, 2}, {118528, 1}, {118574, 2}, {118576, 1}, {118599, 2}, {118608, 1}, {118724, 2}, {118784, 1}, {119030, 2}, {119040, 1}, {119079, 2}, - {119081, 1}, {119134, 34713091}, {119135, 34713603}, {119136, 51491331}, - {119137, 51492099}, {119138, 51492867}, {119139, 51493635}, {119140, 51494403}, - {119141, 1}, {119155, 2}, {119163, 1}, {119227, 34717955}, - {119228, 34718467}, {119229, 51496195}, {119230, 51496963}, {119231, 51497731}, - {119232, 51498499}, {119233, 1}, {119275, 2}, {119296, 1}, + {119081, 1}, {119134, 34712835}, {119135, 34713347}, {119136, 51491075}, + {119137, 51491843}, {119138, 51492611}, {119139, 51493379}, {119140, 51494147}, + {119141, 1}, {119155, 2}, {119163, 1}, {119227, 34717699}, + {119228, 34718211}, {119229, 51495939}, {119230, 51496707}, {119231, 51497475}, + {119232, 51498243}, {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}, @@ -2357,21 +2358,21 @@ const uint32_t table[8000][2] = {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, 17944835}, - {120485, 17945091}, {120486, 2}, {120488, 16851715}, {120489, 16851971}, + {120481, 16783107}, {120482, 16783363}, {120483, 16783619}, {120484, 17944579}, + {120485, 17944835}, {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, 17945347}, + {120510, 16856579}, {120511, 16856835}, {120512, 16857091}, {120513, 17945091}, {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, 17945603}, {120540, 16852739}, {120541, 16853507}, {120542, 16853763}, + {120539, 17945347}, {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}, @@ -2379,13 +2380,13 @@ const uint32_t table[8000][2] = {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, 17945347}, {120572, 16851715}, {120573, 16851971}, {120574, 16852227}, + {120571, 17945091}, {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, 17945603}, {120598, 16852739}, {120599, 16853507}, + {120596, 16857091}, {120597, 17945347}, {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}, @@ -2393,13 +2394,13 @@ const uint32_t table[8000][2] = {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, 17945347}, {120630, 16851715}, {120631, 16851971}, + {120628, 16857091}, {120629, 17945091}, {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, 17945603}, {120656, 16852739}, + {120653, 16856835}, {120654, 16857091}, {120655, 17945347}, {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}, @@ -2407,13 +2408,13 @@ const uint32_t table[8000][2] = {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, 17945347}, {120688, 16851715}, + {120685, 16856835}, {120686, 16857091}, {120687, 17945091}, {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, 17945603}, + {120710, 16856579}, {120711, 16856835}, {120712, 16857091}, {120713, 17945347}, {120714, 16852739}, {120715, 16853507}, {120716, 16853763}, {120717, 16856323}, {120718, 16855299}, {120719, 16855043}, {120720, 16851715}, {120721, 16851971}, {120722, 16852227}, {120723, 16852483}, {120724, 16852739}, {120725, 16852995}, @@ -2421,28 +2422,28 @@ const uint32_t table[8000][2] = {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, 17945347}, + {120742, 16856579}, {120743, 16856835}, {120744, 16857091}, {120745, 17945091}, {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, 17945603}, {120772, 16852739}, {120773, 16853507}, {120774, 16853763}, + {120771, 17945347}, {120772, 16852739}, {120773, 16853507}, {120774, 16853763}, {120775, 16856323}, {120776, 16855299}, {120777, 16855043}, {120778, 16858627}, - {120780, 2}, {120782, 17035523}, {120783, 16786947}, {120784, 16785155}, - {120785, 16785411}, {120786, 16787715}, {120787, 17035779}, {120788, 17036035}, - {120789, 17036291}, {120790, 17036547}, {120791, 17036803}, {120792, 17035523}, + {120780, 2}, {120782, 17035267}, {120783, 16786947}, {120784, 16785155}, + {120785, 16785411}, {120786, 16787715}, {120787, 17035523}, {120788, 17035779}, + {120789, 17036035}, {120790, 17036291}, {120791, 17036547}, {120792, 17035267}, {120793, 16786947}, {120794, 16785155}, {120795, 16785411}, {120796, 16787715}, - {120797, 17035779}, {120798, 17036035}, {120799, 17036291}, {120800, 17036547}, - {120801, 17036803}, {120802, 17035523}, {120803, 16786947}, {120804, 16785155}, - {120805, 16785411}, {120806, 16787715}, {120807, 17035779}, {120808, 17036035}, - {120809, 17036291}, {120810, 17036547}, {120811, 17036803}, {120812, 17035523}, + {120797, 17035523}, {120798, 17035779}, {120799, 17036035}, {120800, 17036291}, + {120801, 17036547}, {120802, 17035267}, {120803, 16786947}, {120804, 16785155}, + {120805, 16785411}, {120806, 16787715}, {120807, 17035523}, {120808, 17035779}, + {120809, 17036035}, {120810, 17036291}, {120811, 17036547}, {120812, 17035267}, {120813, 16786947}, {120814, 16785155}, {120815, 16785411}, {120816, 16787715}, - {120817, 17035779}, {120818, 17036035}, {120819, 17036291}, {120820, 17036547}, - {120821, 17036803}, {120822, 17035523}, {120823, 16786947}, {120824, 16785155}, - {120825, 16785411}, {120826, 16787715}, {120827, 17035779}, {120828, 17036035}, - {120829, 17036291}, {120830, 17036547}, {120831, 17036803}, {120832, 1}, + {120817, 17035523}, {120818, 17035779}, {120819, 17036035}, {120820, 17036291}, + {120821, 17036547}, {120822, 17035267}, {120823, 16786947}, {120824, 16785155}, + {120825, 16785411}, {120826, 16787715}, {120827, 17035523}, {120828, 17035779}, + {120829, 17036035}, {120830, 17036291}, {120831, 17036547}, {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}, @@ -2454,15 +2455,15 @@ const uint32_t table[8000][2] = {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, 17495299}, {122955, 16888835}, {122956, 16864003}, - {122957, 16864515}, {122958, 16890883}, {122959, 16883715}, {122960, 17945859}, + {122953, 16874243}, {122954, 17495043}, {122955, 16888835}, {122956, 16864003}, + {122957, 16864515}, {122958, 16890883}, {122959, 16883715}, {122960, 17945603}, {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, 17490435}, + {122985, 16863747}, {122986, 16866307}, {122987, 16883203}, {122988, 17490179}, {122989, 16883971}, {122990, 2}, {123023, 1}, {123024, 2}, {123136, 1}, {123181, 2}, {123184, 1}, {123198, 2}, {123200, 1}, {123210, 2}, {123214, 1}, {123216, 2}, @@ -2471,101 +2472,101 @@ const uint32_t table[8000][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, 17946115}, {125185, 17946371}, {125186, 17946627}, {125187, 17946883}, - {125188, 17947139}, {125189, 17947395}, {125190, 17947651}, {125191, 17947907}, - {125192, 17948163}, {125193, 17948419}, {125194, 17948675}, {125195, 17948931}, - {125196, 17949187}, {125197, 17949443}, {125198, 17949699}, {125199, 17949955}, - {125200, 17950211}, {125201, 17950467}, {125202, 17950723}, {125203, 17950979}, - {125204, 17951235}, {125205, 17951491}, {125206, 17951747}, {125207, 17952003}, - {125208, 17952259}, {125209, 17952515}, {125210, 17952771}, {125211, 17953027}, - {125212, 17953283}, {125213, 17953539}, {125214, 17953795}, {125215, 17954051}, - {125216, 17954307}, {125217, 17954563}, {125218, 1}, {125260, 2}, + {125184, 17945859}, {125185, 17946115}, {125186, 17946371}, {125187, 17946627}, + {125188, 17946883}, {125189, 17947139}, {125190, 17947395}, {125191, 17947651}, + {125192, 17947907}, {125193, 17948163}, {125194, 17948419}, {125195, 17948675}, + {125196, 17948931}, {125197, 17949187}, {125198, 17949443}, {125199, 17949699}, + {125200, 17949955}, {125201, 17950211}, {125202, 17950467}, {125203, 17950723}, + {125204, 17950979}, {125205, 17951235}, {125206, 17951491}, {125207, 17951747}, + {125208, 17952003}, {125209, 17952259}, {125210, 17952515}, {125211, 17952771}, + {125212, 17953027}, {125213, 17953283}, {125214, 17953539}, {125215, 17953795}, + {125216, 17954051}, {125217, 17954307}, {125218, 1}, {125260, 2}, {125264, 1}, {125274, 2}, {125278, 1}, {125280, 2}, {126065, 1}, {126133, 2}, {126209, 1}, {126270, 2}, - {126464, 16910339}, {126465, 17683715}, {126466, 17681923}, {126467, 17834499}, - {126468, 2}, {126469, 16910851}, {126470, 17731587}, {126471, 17682435}, - {126472, 17700099}, {126473, 16911875}, {126474, 17708803}, {126475, 17711107}, - {126476, 17682947}, {126477, 17718019}, {126478, 17694979}, {126479, 17701635}, - {126480, 17703683}, {126481, 17697027}, {126482, 17706755}, {126483, 17725187}, - {126484, 17745155}, {126485, 17686787}, {126486, 17689859}, {126487, 17684995}, - {126488, 17724675}, {126489, 17698051}, {126490, 17701123}, {126491, 17702659}, - {126492, 17954819}, {126493, 17673475}, {126494, 17955075}, {126495, 17955331}, - {126496, 2}, {126497, 17683715}, {126498, 17681923}, {126499, 2}, - {126500, 17721091}, {126501, 2}, {126503, 17682435}, {126504, 2}, - {126505, 16911875}, {126506, 17708803}, {126507, 17711107}, {126508, 17682947}, - {126509, 17718019}, {126510, 17694979}, {126511, 17701635}, {126512, 17703683}, - {126513, 17697027}, {126514, 17706755}, {126515, 2}, {126516, 17745155}, - {126517, 17686787}, {126518, 17689859}, {126519, 17684995}, {126520, 2}, - {126521, 17698051}, {126522, 2}, {126523, 17702659}, {126524, 2}, - {126530, 17681923}, {126531, 2}, {126535, 17682435}, {126536, 2}, - {126537, 16911875}, {126538, 2}, {126539, 17711107}, {126540, 2}, - {126541, 17718019}, {126542, 17694979}, {126543, 17701635}, {126544, 2}, - {126545, 17697027}, {126546, 17706755}, {126547, 2}, {126548, 17745155}, - {126549, 2}, {126551, 17684995}, {126552, 2}, {126553, 17698051}, - {126554, 2}, {126555, 17702659}, {126556, 2}, {126557, 17673475}, - {126558, 2}, {126559, 17955331}, {126560, 2}, {126561, 17683715}, - {126562, 17681923}, {126563, 2}, {126564, 17721091}, {126565, 2}, - {126567, 17682435}, {126568, 17700099}, {126569, 16911875}, {126570, 17708803}, - {126571, 2}, {126572, 17682947}, {126573, 17718019}, {126574, 17694979}, - {126575, 17701635}, {126576, 17703683}, {126577, 17697027}, {126578, 17706755}, - {126579, 2}, {126580, 17745155}, {126581, 17686787}, {126582, 17689859}, - {126583, 17684995}, {126584, 2}, {126585, 17698051}, {126586, 17701123}, - {126587, 17702659}, {126588, 17954819}, {126589, 2}, {126590, 17955075}, - {126591, 2}, {126592, 16910339}, {126593, 17683715}, {126594, 17681923}, - {126595, 17834499}, {126596, 17721091}, {126597, 16910851}, {126598, 17731587}, - {126599, 17682435}, {126600, 17700099}, {126601, 16911875}, {126602, 2}, - {126603, 17711107}, {126604, 17682947}, {126605, 17718019}, {126606, 17694979}, - {126607, 17701635}, {126608, 17703683}, {126609, 17697027}, {126610, 17706755}, - {126611, 17725187}, {126612, 17745155}, {126613, 17686787}, {126614, 17689859}, - {126615, 17684995}, {126616, 17724675}, {126617, 17698051}, {126618, 17701123}, - {126619, 17702659}, {126620, 2}, {126625, 17683715}, {126626, 17681923}, - {126627, 17834499}, {126628, 2}, {126629, 16910851}, {126630, 17731587}, - {126631, 17682435}, {126632, 17700099}, {126633, 16911875}, {126634, 2}, - {126635, 17711107}, {126636, 17682947}, {126637, 17718019}, {126638, 17694979}, - {126639, 17701635}, {126640, 17703683}, {126641, 17697027}, {126642, 17706755}, - {126643, 17725187}, {126644, 17745155}, {126645, 17686787}, {126646, 17689859}, - {126647, 17684995}, {126648, 17724675}, {126649, 17698051}, {126650, 17701123}, - {126651, 17702659}, {126652, 2}, {126704, 1}, {126706, 2}, + {126464, 16910339}, {126465, 17683459}, {126466, 17681667}, {126467, 17834243}, + {126468, 2}, {126469, 16910851}, {126470, 17731331}, {126471, 17682179}, + {126472, 17699843}, {126473, 16911875}, {126474, 17708547}, {126475, 17710851}, + {126476, 17682691}, {126477, 17717763}, {126478, 17694723}, {126479, 17701379}, + {126480, 17703427}, {126481, 17696771}, {126482, 17706499}, {126483, 17724931}, + {126484, 17744899}, {126485, 17686531}, {126486, 17689603}, {126487, 17684739}, + {126488, 17724419}, {126489, 17697795}, {126490, 17700867}, {126491, 17702403}, + {126492, 17954563}, {126493, 17673219}, {126494, 17954819}, {126495, 17955075}, + {126496, 2}, {126497, 17683459}, {126498, 17681667}, {126499, 2}, + {126500, 17720835}, {126501, 2}, {126503, 17682179}, {126504, 2}, + {126505, 16911875}, {126506, 17708547}, {126507, 17710851}, {126508, 17682691}, + {126509, 17717763}, {126510, 17694723}, {126511, 17701379}, {126512, 17703427}, + {126513, 17696771}, {126514, 17706499}, {126515, 2}, {126516, 17744899}, + {126517, 17686531}, {126518, 17689603}, {126519, 17684739}, {126520, 2}, + {126521, 17697795}, {126522, 2}, {126523, 17702403}, {126524, 2}, + {126530, 17681667}, {126531, 2}, {126535, 17682179}, {126536, 2}, + {126537, 16911875}, {126538, 2}, {126539, 17710851}, {126540, 2}, + {126541, 17717763}, {126542, 17694723}, {126543, 17701379}, {126544, 2}, + {126545, 17696771}, {126546, 17706499}, {126547, 2}, {126548, 17744899}, + {126549, 2}, {126551, 17684739}, {126552, 2}, {126553, 17697795}, + {126554, 2}, {126555, 17702403}, {126556, 2}, {126557, 17673219}, + {126558, 2}, {126559, 17955075}, {126560, 2}, {126561, 17683459}, + {126562, 17681667}, {126563, 2}, {126564, 17720835}, {126565, 2}, + {126567, 17682179}, {126568, 17699843}, {126569, 16911875}, {126570, 17708547}, + {126571, 2}, {126572, 17682691}, {126573, 17717763}, {126574, 17694723}, + {126575, 17701379}, {126576, 17703427}, {126577, 17696771}, {126578, 17706499}, + {126579, 2}, {126580, 17744899}, {126581, 17686531}, {126582, 17689603}, + {126583, 17684739}, {126584, 2}, {126585, 17697795}, {126586, 17700867}, + {126587, 17702403}, {126588, 17954563}, {126589, 2}, {126590, 17954819}, + {126591, 2}, {126592, 16910339}, {126593, 17683459}, {126594, 17681667}, + {126595, 17834243}, {126596, 17720835}, {126597, 16910851}, {126598, 17731331}, + {126599, 17682179}, {126600, 17699843}, {126601, 16911875}, {126602, 2}, + {126603, 17710851}, {126604, 17682691}, {126605, 17717763}, {126606, 17694723}, + {126607, 17701379}, {126608, 17703427}, {126609, 17696771}, {126610, 17706499}, + {126611, 17724931}, {126612, 17744899}, {126613, 17686531}, {126614, 17689603}, + {126615, 17684739}, {126616, 17724419}, {126617, 17697795}, {126618, 17700867}, + {126619, 17702403}, {126620, 2}, {126625, 17683459}, {126626, 17681667}, + {126627, 17834243}, {126628, 2}, {126629, 16910851}, {126630, 17731331}, + {126631, 17682179}, {126632, 17699843}, {126633, 16911875}, {126634, 2}, + {126635, 17710851}, {126636, 17682691}, {126637, 17717763}, {126638, 17694723}, + {126639, 17701379}, {126640, 17703427}, {126641, 17696771}, {126642, 17706499}, + {126643, 17724931}, {126644, 17744899}, {126645, 17686531}, {126646, 17689603}, + {126647, 17684739}, {126648, 17724419}, {126649, 17697795}, {126650, 17700867}, + {126651, 17702403}, {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, 34732803}, {127234, 34733315}, {127235, 34733827}, {127236, 34734339}, - {127237, 34734851}, {127238, 34735363}, {127239, 34735875}, {127240, 34736387}, - {127241, 34736899}, {127242, 34737411}, {127243, 1}, {127248, 50644995}, - {127249, 50645763}, {127250, 50646531}, {127251, 50647299}, {127252, 50648067}, - {127253, 50648835}, {127254, 50649603}, {127255, 50650371}, {127256, 50651139}, - {127257, 50651907}, {127258, 50652675}, {127259, 50653443}, {127260, 50654211}, - {127261, 50654979}, {127262, 50655747}, {127263, 50656515}, {127264, 50657283}, - {127265, 50658051}, {127266, 50658819}, {127267, 50659587}, {127268, 50660355}, - {127269, 50661123}, {127270, 50661891}, {127271, 50662659}, {127272, 50663427}, - {127273, 50664195}, {127274, 51515139}, {127275, 16777731}, {127276, 16781571}, - {127277, 33554947}, {127278, 34738691}, {127279, 1}, {127280, 16777219}, + {127233, 34732547}, {127234, 34733059}, {127235, 34733571}, {127236, 34734083}, + {127237, 34734595}, {127238, 34735107}, {127239, 34735619}, {127240, 34736131}, + {127241, 34736643}, {127242, 34737155}, {127243, 1}, {127248, 50644739}, + {127249, 50645507}, {127250, 50646275}, {127251, 50647043}, {127252, 50647811}, + {127253, 50648579}, {127254, 50649347}, {127255, 50650115}, {127256, 50650883}, + {127257, 50651651}, {127258, 50652419}, {127259, 50653187}, {127260, 50653955}, + {127261, 50654723}, {127262, 50655491}, {127263, 50656259}, {127264, 50657027}, + {127265, 50657795}, {127266, 50658563}, {127267, 50659331}, {127268, 50660099}, + {127269, 50660867}, {127270, 50661635}, {127271, 50662403}, {127272, 50663171}, + {127273, 50663939}, {127274, 51514883}, {127275, 16777731}, {127276, 16781571}, + {127277, 33554947}, {127278, 34738435}, {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, 34739203}, {127307, 34226691}, {127308, 34739715}, - {127309, 33752579}, {127310, 51517443}, {127311, 34740995}, {127312, 1}, - {127338, 34209539}, {127339, 34189571}, {127340, 34741507}, {127341, 1}, - {127376, 34742019}, {127377, 1}, {127406, 2}, {127462, 1}, - {127488, 34742531}, {127489, 34743043}, {127490, 17307907}, {127491, 2}, - {127504, 17157891}, {127505, 17966339}, {127506, 17966595}, {127507, 17351683}, - {127508, 17143299}, {127509, 17966851}, {127510, 17967107}, {127511, 17225475}, - {127512, 17967363}, {127513, 17967619}, {127514, 17967875}, {127515, 17584643}, - {127516, 17968131}, {127517, 17968387}, {127518, 17968643}, {127519, 17968899}, - {127520, 17969155}, {127521, 17969411}, {127522, 17167107}, {127523, 17969667}, - {127524, 17969923}, {127525, 17970179}, {127526, 17970435}, {127527, 17970691}, - {127528, 17970947}, {127529, 17141763}, {127530, 17223427}, {127531, 17971203}, - {127532, 17288707}, {127533, 17224195}, {127534, 17288963}, {127535, 17971459}, - {127536, 17181443}, {127537, 17971715}, {127538, 17971971}, {127539, 17972227}, - {127540, 17972483}, {127541, 17972739}, {127542, 17264387}, {127543, 17160451}, - {127544, 17972995}, {127545, 17973251}, {127546, 17973507}, {127547, 17973763}, - {127548, 2}, {127552, 51528451}, {127553, 51529219}, {127554, 51529987}, - {127555, 51530755}, {127556, 51531523}, {127557, 51532291}, {127558, 51533059}, - {127559, 51533827}, {127560, 51534595}, {127561, 2}, {127568, 17980931}, - {127569, 17981187}, {127570, 2}, {127584, 1}, {127590, 2}, + {127305, 16783619}, {127306, 34738947}, {127307, 34226435}, {127308, 34739459}, + {127309, 34739971}, {127310, 51517699}, {127311, 34741251}, {127312, 1}, + {127338, 34209283}, {127339, 34189315}, {127340, 34741763}, {127341, 1}, + {127376, 34742275}, {127377, 1}, {127406, 2}, {127462, 1}, + {127488, 34742787}, {127489, 34743299}, {127490, 17307651}, {127491, 2}, + {127504, 17157635}, {127505, 17966595}, {127506, 17966851}, {127507, 17351427}, + {127508, 17143043}, {127509, 17967107}, {127510, 17967363}, {127511, 17225219}, + {127512, 17967619}, {127513, 17967875}, {127514, 17968131}, {127515, 17584387}, + {127516, 17968387}, {127517, 17968643}, {127518, 17968899}, {127519, 17969155}, + {127520, 17969411}, {127521, 17969667}, {127522, 17166851}, {127523, 17969923}, + {127524, 17970179}, {127525, 17970435}, {127526, 17970691}, {127527, 17970947}, + {127528, 17971203}, {127529, 17141507}, {127530, 17223171}, {127531, 17971459}, + {127532, 17288451}, {127533, 17223939}, {127534, 17288707}, {127535, 17971715}, + {127536, 17181187}, {127537, 17971971}, {127538, 17972227}, {127539, 17972483}, + {127540, 17972739}, {127541, 17972995}, {127542, 17264131}, {127543, 17160195}, + {127544, 17973251}, {127545, 17973507}, {127546, 17973763}, {127547, 17974019}, + {127548, 2}, {127552, 51528707}, {127553, 51529475}, {127554, 51530243}, + {127555, 51531011}, {127556, 51531779}, {127557, 51532547}, {127558, 51533315}, + {127559, 51534083}, {127560, 51534851}, {127561, 2}, {127568, 17981187}, + {127569, 17981443}, {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}, @@ -2578,152 +2579,152 @@ const uint32_t table[8000][2] = {129727, 1}, {129734, 2}, {129742, 1}, {129756, 2}, {129760, 1}, {129769, 2}, {129776, 1}, {129785, 2}, {129792, 1}, {129939, 2}, {129940, 1}, {129995, 2}, - {130032, 17035523}, {130033, 16786947}, {130034, 16785155}, {130035, 16785411}, - {130036, 16787715}, {130037, 17035779}, {130038, 17036035}, {130039, 17036291}, - {130040, 17036547}, {130041, 17036803}, {130042, 2}, {131072, 1}, + {130032, 17035267}, {130033, 16786947}, {130034, 16785155}, {130035, 16785411}, + {130036, 16787715}, {130037, 17035523}, {130038, 17035779}, {130039, 17036035}, + {130040, 17036291}, {130041, 17036547}, {130042, 2}, {131072, 1}, {173792, 2}, {173824, 1}, {177978, 2}, {177984, 1}, {178206, 2}, {178208, 1}, {183970, 2}, {183984, 1}, - {191457, 2}, {194560, 17981443}, {194561, 17981699}, {194562, 17981955}, - {194563, 17982211}, {194564, 17982467}, {194565, 17608451}, {194566, 17982723}, - {194567, 17982979}, {194568, 17983235}, {194569, 17983491}, {194570, 17608707}, - {194571, 17983747}, {194572, 17984003}, {194573, 17984259}, {194574, 17608963}, - {194575, 17984515}, {194576, 17984771}, {194577, 17985027}, {194578, 17985283}, - {194579, 17985539}, {194580, 17985795}, {194581, 17968643}, {194582, 17986051}, - {194583, 17986307}, {194584, 17986563}, {194585, 17986819}, {194586, 17987075}, - {194587, 17623043}, {194588, 17987331}, {194589, 17145859}, {194590, 17987587}, - {194591, 17987843}, {194592, 17988099}, {194593, 17988355}, {194594, 17973251}, - {194595, 17988611}, {194596, 17988867}, {194597, 17624323}, {194598, 17609219}, - {194599, 17609475}, {194600, 17624579}, {194601, 17989123}, {194602, 17989379}, - {194603, 17562883}, {194604, 17989635}, {194605, 17609731}, {194606, 17989891}, - {194607, 17990147}, {194608, 17990403}, {194609, 17990659}, {194612, 17990915}, - {194613, 17991171}, {194614, 17991427}, {194615, 17991683}, {194616, 17991939}, - {194617, 17992195}, {194618, 17992451}, {194619, 17992707}, {194620, 17992963}, - {194621, 17993219}, {194622, 17993475}, {194623, 17993731}, {194624, 17993987}, - {194625, 17994243}, {194626, 17994499}, {194627, 17994755}, {194628, 17995011}, - {194629, 17995267}, {194631, 17625091}, {194632, 17995523}, {194633, 17995779}, - {194634, 17996035}, {194635, 17996291}, {194636, 17610243}, {194637, 17996547}, - {194638, 17996803}, {194639, 17997059}, {194640, 17600003}, {194641, 17997315}, - {194642, 17997571}, {194643, 17997827}, {194644, 17998083}, {194645, 17998339}, - {194646, 17998595}, {194647, 17998851}, {194648, 17999107}, {194649, 17999363}, - {194650, 17999619}, {194651, 17999875}, {194652, 18000131}, {194653, 17966851}, - {194654, 18000387}, {194655, 18000643}, {194656, 18000899}, {194657, 18001155}, - {194658, 18001411}, {194659, 18001667}, {194660, 18001923}, {194661, 18002179}, - {194662, 18002435}, {194663, 18002691}, {194664, 2}, {194665, 18002947}, - {194666, 18003203}, {194668, 18003459}, {194669, 18003715}, {194670, 18003971}, - {194671, 17561859}, {194672, 18004227}, {194673, 18004483}, {194674, 18004739}, - {194675, 18004995}, {194676, 2}, {194677, 17152515}, {194678, 18005251}, - {194679, 18005507}, {194680, 17153027}, {194681, 18005763}, {194682, 18006019}, - {194683, 18006275}, {194684, 18006531}, {194685, 18006787}, {194686, 18007043}, - {194687, 18007299}, {194688, 18007555}, {194689, 18007811}, {194690, 18008067}, - {194691, 18008323}, {194692, 18008579}, {194693, 18008835}, {194694, 18009091}, - {194695, 18009347}, {194696, 18009603}, {194697, 18009859}, {194698, 18010115}, - {194699, 18010371}, {194700, 18010627}, {194701, 18010883}, {194702, 17548547}, - {194703, 18011139}, {194704, 17155587}, {194705, 18011395}, {194707, 18011651}, - {194708, 18011907}, {194710, 18012163}, {194711, 18012419}, {194712, 18012675}, - {194713, 18012931}, {194714, 18013187}, {194715, 18013443}, {194716, 18013699}, - {194717, 18013955}, {194718, 18014211}, {194719, 18014467}, {194720, 18014723}, - {194721, 18014979}, {194722, 18015235}, {194723, 17611523}, {194724, 18015491}, - {194725, 18015747}, {194726, 18016003}, {194727, 18016259}, {194728, 17628163}, - {194729, 18016259}, {194730, 18016515}, {194731, 17612035}, {194732, 18016771}, - {194733, 18017027}, {194734, 18017283}, {194735, 18017539}, {194736, 17612291}, - {194737, 17541635}, {194738, 17414915}, {194739, 18017795}, {194740, 18018051}, - {194741, 18018307}, {194742, 18018563}, {194743, 18018819}, {194744, 18019075}, - {194745, 18019331}, {194746, 18019587}, {194747, 18019843}, {194748, 18020099}, - {194749, 18020355}, {194750, 18020611}, {194751, 18020867}, {194752, 18021123}, - {194753, 18021379}, {194754, 18021635}, {194755, 18021891}, {194756, 18022147}, - {194757, 18022403}, {194758, 18022659}, {194759, 18022915}, {194760, 17612547}, - {194761, 18023171}, {194762, 18023427}, {194763, 18023683}, {194764, 18023939}, - {194765, 18024195}, {194766, 18024451}, {194767, 17613059}, {194768, 18024707}, - {194769, 18024963}, {194770, 18025219}, {194771, 18025475}, {194772, 18025731}, - {194773, 18025987}, {194774, 18026243}, {194775, 18026499}, {194776, 17548803}, - {194777, 17630211}, {194778, 18026755}, {194779, 18027011}, {194780, 18027267}, - {194781, 18027523}, {194782, 18027779}, {194783, 18028035}, {194784, 18028291}, - {194785, 18028547}, {194786, 17613315}, {194787, 18028803}, {194788, 18029059}, - {194789, 18029315}, {194790, 18029571}, {194791, 17640963}, {194792, 18029827}, - {194793, 18030083}, {194794, 18030339}, {194795, 18030595}, {194796, 18030851}, - {194797, 18031107}, {194798, 18031363}, {194799, 18031619}, {194800, 18031875}, - {194801, 18032131}, {194802, 18032387}, {194803, 18032643}, {194804, 18032899}, - {194805, 17566211}, {194806, 18033155}, {194807, 18033411}, {194808, 18033667}, - {194809, 18033923}, {194810, 18034179}, {194811, 18034435}, {194812, 18034691}, - {194813, 18034947}, {194814, 18035203}, {194815, 18035459}, {194816, 18035715}, - {194817, 17613571}, {194818, 17587203}, {194819, 18035971}, {194820, 18036227}, - {194821, 18036483}, {194822, 18036739}, {194823, 18036995}, {194824, 18037251}, - {194825, 18037507}, {194826, 18037763}, {194827, 17630979}, {194828, 18038019}, - {194829, 18038275}, {194830, 18038531}, {194831, 18038787}, {194832, 18039043}, - {194833, 18039299}, {194834, 18039555}, {194835, 18039811}, {194836, 17631235}, - {194837, 18040067}, {194838, 18040323}, {194839, 18040579}, {194840, 18040835}, - {194841, 18041091}, {194842, 18041347}, {194843, 18041603}, {194844, 18041859}, - {194845, 18042115}, {194846, 18042371}, {194847, 2}, {194848, 18042627}, - {194849, 17631747}, {194850, 18042883}, {194851, 18043139}, {194852, 18043395}, - {194853, 18043651}, {194854, 18043907}, {194855, 18044163}, {194856, 18044419}, - {194857, 18044675}, {194858, 18044931}, {194859, 18045187}, {194860, 18045443}, - {194862, 18045699}, {194863, 18045955}, {194864, 17632259}, {194865, 18046211}, - {194866, 18046467}, {194867, 18046723}, {194868, 18046979}, {194869, 18047235}, - {194870, 18047491}, {194871, 18047747}, {194872, 17562627}, {194873, 18048003}, - {194874, 18048259}, {194875, 18048515}, {194876, 18048771}, {194877, 18049027}, - {194878, 18049283}, {194879, 18049539}, {194880, 17633795}, {194881, 18049795}, - {194882, 18050051}, {194883, 18050307}, {194884, 18050563}, {194885, 18050819}, - {194886, 18051075}, {194888, 17634051}, {194889, 17641475}, {194890, 18051331}, - {194891, 18051587}, {194892, 18051843}, {194893, 18052099}, {194894, 18052355}, - {194895, 17553155}, {194896, 17634563}, {194897, 18052611}, {194898, 18052867}, - {194899, 17616131}, {194900, 18053123}, {194901, 18053379}, {194902, 17605123}, - {194903, 18053635}, {194904, 18053891}, {194905, 17616899}, {194906, 18054147}, - {194907, 18054403}, {194908, 18054659}, {194909, 18054915}, {194911, 2}, - {194912, 18055171}, {194913, 18055427}, {194914, 18055683}, {194915, 18055939}, - {194916, 18056195}, {194917, 18056451}, {194918, 18056707}, {194919, 18056963}, - {194920, 18057219}, {194921, 18057475}, {194922, 18057731}, {194923, 18057987}, - {194924, 18058243}, {194925, 18058499}, {194926, 18058755}, {194927, 18059011}, - {194928, 18059267}, {194929, 18059523}, {194930, 18059779}, {194931, 18060035}, - {194932, 18060291}, {194933, 18060547}, {194934, 18060803}, {194935, 18061059}, - {194936, 18061315}, {194937, 18061571}, {194938, 17618435}, {194939, 18061827}, - {194940, 18062083}, {194941, 18062339}, {194942, 18062595}, {194943, 18062851}, - {194944, 18063107}, {194945, 18063363}, {194946, 18063619}, {194947, 18063875}, - {194948, 18064131}, {194949, 18064387}, {194950, 18064643}, {194951, 18064899}, - {194952, 18065155}, {194953, 18065411}, {194954, 18065667}, {194955, 18011651}, - {194956, 18065923}, {194957, 18066179}, {194958, 18066435}, {194959, 18066691}, - {194960, 18066947}, {194961, 18067203}, {194962, 18067459}, {194963, 18067715}, - {194964, 18067971}, {194965, 18068227}, {194966, 18068483}, {194967, 18068739}, - {194968, 17566979}, {194969, 18068995}, {194970, 18069251}, {194971, 18069507}, - {194972, 18069763}, {194973, 18070019}, {194974, 18070275}, {194975, 17619203}, - {194976, 18070531}, {194977, 18070787}, {194978, 18071043}, {194979, 18071299}, - {194980, 18071555}, {194981, 18071811}, {194982, 18072067}, {194983, 18072323}, - {194984, 18072579}, {194985, 18072835}, {194986, 18073091}, {194987, 18073347}, - {194988, 18073603}, {194989, 18073859}, {194990, 18074115}, {194991, 18074371}, - {194992, 18074627}, {194993, 18074883}, {194994, 18075139}, {194995, 18075395}, - {194996, 17551875}, {194997, 18075651}, {194998, 18075907}, {194999, 18076163}, - {195000, 18076419}, {195001, 18076675}, {195002, 18076931}, {195003, 17636355}, - {195004, 18077187}, {195005, 18077443}, {195006, 18077699}, {195007, 2}, - {195008, 18077955}, {195009, 18078211}, {195010, 18078467}, {195011, 18078723}, - {195012, 17178627}, {195013, 18078979}, {195014, 18079235}, {195015, 18079491}, - {195016, 18079747}, {195017, 18080003}, {195018, 18080259}, {195019, 18080515}, - {195020, 18080771}, {195021, 18081027}, {195022, 18081283}, {195023, 18081539}, - {195024, 17637635}, {195025, 17637891}, {195026, 17180419}, {195027, 18081795}, - {195028, 18082051}, {195029, 18082307}, {195030, 18082563}, {195031, 18082819}, - {195032, 18083075}, {195033, 18083331}, {195034, 18083587}, {195035, 18083843}, - {195036, 18084099}, {195037, 18084355}, {195038, 18084611}, {195039, 17638147}, - {195040, 18084867}, {195041, 18085123}, {195042, 18085379}, {195043, 18085635}, - {195044, 18085891}, {195045, 18086147}, {195046, 18086403}, {195047, 18086659}, - {195048, 18086915}, {195049, 18087171}, {195050, 18087427}, {195051, 18087683}, - {195052, 18087939}, {195053, 18088195}, {195054, 18088451}, {195055, 18088707}, - {195056, 18088963}, {195057, 18089219}, {195058, 18089475}, {195059, 18089731}, - {195060, 18089987}, {195061, 18090243}, {195062, 18090499}, {195063, 18090755}, - {195064, 18091011}, {195065, 18091267}, {195066, 18091523}, {195067, 18091779}, - {195068, 18092035}, {195069, 18092291}, {195070, 17639683}, {195072, 18092547}, - {195073, 18092803}, {195074, 18093059}, {195075, 18093315}, {195076, 18093571}, - {195077, 18093827}, {195078, 18094083}, {195079, 18094339}, {195080, 18094595}, - {195081, 18094851}, {195082, 17639939}, {195083, 18095107}, {195084, 18095363}, - {195085, 18095619}, {195086, 18095875}, {195087, 18096131}, {195088, 18096387}, - {195089, 18096643}, {195090, 18096899}, {195091, 18097155}, {195092, 18097411}, - {195093, 17192707}, {195094, 18097667}, {195095, 17193731}, {195096, 18097923}, - {195097, 18098179}, {195098, 18098435}, {195099, 18098691}, {195100, 17195011}, - {195101, 18098947}, {195102, 2}, {196608, 1}, {201547, 2}, - {201552, 1}, {205744, 2}, {917760, 0}, {918000, 2} + {191457, 2}, {191472, 1}, {192094, 2}, {194560, 17981699}, + {194561, 17981955}, {194562, 17982211}, {194563, 17982467}, {194564, 17982723}, + {194565, 17608195}, {194566, 17982979}, {194567, 17983235}, {194568, 17983491}, + {194569, 17983747}, {194570, 17608451}, {194571, 17984003}, {194572, 17984259}, + {194573, 17984515}, {194574, 17608707}, {194575, 17984771}, {194576, 17985027}, + {194577, 17985283}, {194578, 17985539}, {194579, 17985795}, {194580, 17986051}, + {194581, 17968899}, {194582, 17986307}, {194583, 17986563}, {194584, 17986819}, + {194585, 17987075}, {194586, 17987331}, {194587, 17622787}, {194588, 17987587}, + {194589, 17145603}, {194590, 17987843}, {194591, 17988099}, {194592, 17988355}, + {194593, 17988611}, {194594, 17973507}, {194595, 17988867}, {194596, 17989123}, + {194597, 17624067}, {194598, 17608963}, {194599, 17609219}, {194600, 17624323}, + {194601, 17989379}, {194602, 17989635}, {194603, 17562627}, {194604, 17989891}, + {194605, 17609475}, {194606, 17990147}, {194607, 17990403}, {194608, 17990659}, + {194609, 17990915}, {194612, 17991171}, {194613, 17991427}, {194614, 17991683}, + {194615, 17991939}, {194616, 17992195}, {194617, 17992451}, {194618, 17992707}, + {194619, 17992963}, {194620, 17993219}, {194621, 17993475}, {194622, 17993731}, + {194623, 17993987}, {194624, 17994243}, {194625, 17994499}, {194626, 17994755}, + {194627, 17995011}, {194628, 17995267}, {194629, 17995523}, {194631, 17624835}, + {194632, 17995779}, {194633, 17996035}, {194634, 17996291}, {194635, 17996547}, + {194636, 17609987}, {194637, 17996803}, {194638, 17997059}, {194639, 17997315}, + {194640, 17599747}, {194641, 17997571}, {194642, 17997827}, {194643, 17998083}, + {194644, 17998339}, {194645, 17998595}, {194646, 17998851}, {194647, 17999107}, + {194648, 17999363}, {194649, 17999619}, {194650, 17999875}, {194651, 18000131}, + {194652, 18000387}, {194653, 17967107}, {194654, 18000643}, {194655, 18000899}, + {194656, 18001155}, {194657, 18001411}, {194658, 18001667}, {194659, 18001923}, + {194660, 18002179}, {194661, 18002435}, {194662, 18002691}, {194663, 18002947}, + {194664, 2}, {194665, 18003203}, {194666, 18003459}, {194668, 18003715}, + {194669, 18003971}, {194670, 18004227}, {194671, 17561603}, {194672, 18004483}, + {194673, 18004739}, {194674, 18004995}, {194675, 18005251}, {194676, 2}, + {194677, 17152259}, {194678, 18005507}, {194679, 18005763}, {194680, 17152771}, + {194681, 18006019}, {194682, 18006275}, {194683, 18006531}, {194684, 18006787}, + {194685, 18007043}, {194686, 18007299}, {194687, 18007555}, {194688, 18007811}, + {194689, 18008067}, {194690, 18008323}, {194691, 18008579}, {194692, 18008835}, + {194693, 18009091}, {194694, 18009347}, {194695, 18009603}, {194696, 18009859}, + {194697, 18010115}, {194698, 18010371}, {194699, 18010627}, {194700, 18010883}, + {194701, 18011139}, {194702, 17548291}, {194703, 18011395}, {194704, 17155331}, + {194705, 18011651}, {194707, 18011907}, {194708, 18012163}, {194710, 18012419}, + {194711, 18012675}, {194712, 18012931}, {194713, 18013187}, {194714, 18013443}, + {194715, 18013699}, {194716, 18013955}, {194717, 18014211}, {194718, 18014467}, + {194719, 18014723}, {194720, 18014979}, {194721, 18015235}, {194722, 18015491}, + {194723, 17611267}, {194724, 18015747}, {194725, 18016003}, {194726, 18016259}, + {194727, 18016515}, {194728, 17627907}, {194729, 18016515}, {194730, 18016771}, + {194731, 17611779}, {194732, 18017027}, {194733, 18017283}, {194734, 18017539}, + {194735, 18017795}, {194736, 17612035}, {194737, 17541379}, {194738, 17414659}, + {194739, 18018051}, {194740, 18018307}, {194741, 18018563}, {194742, 18018819}, + {194743, 18019075}, {194744, 18019331}, {194745, 18019587}, {194746, 18019843}, + {194747, 18020099}, {194748, 18020355}, {194749, 18020611}, {194750, 18020867}, + {194751, 18021123}, {194752, 18021379}, {194753, 18021635}, {194754, 18021891}, + {194755, 18022147}, {194756, 18022403}, {194757, 18022659}, {194758, 18022915}, + {194759, 18023171}, {194760, 17612291}, {194761, 18023427}, {194762, 18023683}, + {194763, 18023939}, {194764, 18024195}, {194765, 18024451}, {194766, 18024707}, + {194767, 17612803}, {194768, 18024963}, {194769, 18025219}, {194770, 18025475}, + {194771, 18025731}, {194772, 18025987}, {194773, 18026243}, {194774, 18026499}, + {194775, 18026755}, {194776, 17548547}, {194777, 17629955}, {194778, 18027011}, + {194779, 18027267}, {194780, 18027523}, {194781, 18027779}, {194782, 18028035}, + {194783, 18028291}, {194784, 18028547}, {194785, 18028803}, {194786, 17613059}, + {194787, 18029059}, {194788, 18029315}, {194789, 18029571}, {194790, 18029827}, + {194791, 17640707}, {194792, 18030083}, {194793, 18030339}, {194794, 18030595}, + {194795, 18030851}, {194796, 18031107}, {194797, 18031363}, {194798, 18031619}, + {194799, 18031875}, {194800, 18032131}, {194801, 18032387}, {194802, 18032643}, + {194803, 18032899}, {194804, 18033155}, {194805, 17565955}, {194806, 18033411}, + {194807, 18033667}, {194808, 18033923}, {194809, 18034179}, {194810, 18034435}, + {194811, 18034691}, {194812, 18034947}, {194813, 18035203}, {194814, 18035459}, + {194815, 18035715}, {194816, 18035971}, {194817, 17613315}, {194818, 17586947}, + {194819, 18036227}, {194820, 18036483}, {194821, 18036739}, {194822, 18036995}, + {194823, 18037251}, {194824, 18037507}, {194825, 18037763}, {194826, 18038019}, + {194827, 17630723}, {194828, 18038275}, {194829, 18038531}, {194830, 18038787}, + {194831, 18039043}, {194832, 18039299}, {194833, 18039555}, {194834, 18039811}, + {194835, 18040067}, {194836, 17630979}, {194837, 18040323}, {194838, 18040579}, + {194839, 18040835}, {194840, 18041091}, {194841, 18041347}, {194842, 18041603}, + {194843, 18041859}, {194844, 18042115}, {194845, 18042371}, {194846, 18042627}, + {194847, 2}, {194848, 18042883}, {194849, 17631491}, {194850, 18043139}, + {194851, 18043395}, {194852, 18043651}, {194853, 18043907}, {194854, 18044163}, + {194855, 18044419}, {194856, 18044675}, {194857, 18044931}, {194858, 18045187}, + {194859, 18045443}, {194860, 18045699}, {194862, 18045955}, {194863, 18046211}, + {194864, 17632003}, {194865, 18046467}, {194866, 18046723}, {194867, 18046979}, + {194868, 18047235}, {194869, 18047491}, {194870, 18047747}, {194871, 18048003}, + {194872, 17562371}, {194873, 18048259}, {194874, 18048515}, {194875, 18048771}, + {194876, 18049027}, {194877, 18049283}, {194878, 18049539}, {194879, 18049795}, + {194880, 17633539}, {194881, 18050051}, {194882, 18050307}, {194883, 18050563}, + {194884, 18050819}, {194885, 18051075}, {194886, 18051331}, {194888, 17633795}, + {194889, 17641219}, {194890, 18051587}, {194891, 18051843}, {194892, 18052099}, + {194893, 18052355}, {194894, 18052611}, {194895, 17552899}, {194896, 17634307}, + {194897, 18052867}, {194898, 18053123}, {194899, 17615875}, {194900, 18053379}, + {194901, 18053635}, {194902, 17604867}, {194903, 18053891}, {194904, 18054147}, + {194905, 17616643}, {194906, 18054403}, {194907, 18054659}, {194908, 18054915}, + {194909, 18055171}, {194911, 2}, {194912, 18055427}, {194913, 18055683}, + {194914, 18055939}, {194915, 18056195}, {194916, 18056451}, {194917, 18056707}, + {194918, 18056963}, {194919, 18057219}, {194920, 18057475}, {194921, 18057731}, + {194922, 18057987}, {194923, 18058243}, {194924, 18058499}, {194925, 18058755}, + {194926, 18059011}, {194927, 18059267}, {194928, 18059523}, {194929, 18059779}, + {194930, 18060035}, {194931, 18060291}, {194932, 18060547}, {194933, 18060803}, + {194934, 18061059}, {194935, 18061315}, {194936, 18061571}, {194937, 18061827}, + {194938, 17618179}, {194939, 18062083}, {194940, 18062339}, {194941, 18062595}, + {194942, 18062851}, {194943, 18063107}, {194944, 18063363}, {194945, 18063619}, + {194946, 18063875}, {194947, 18064131}, {194948, 18064387}, {194949, 18064643}, + {194950, 18064899}, {194951, 18065155}, {194952, 18065411}, {194953, 18065667}, + {194954, 18065923}, {194955, 18011907}, {194956, 18066179}, {194957, 18066435}, + {194958, 18066691}, {194959, 18066947}, {194960, 18067203}, {194961, 18067459}, + {194962, 18067715}, {194963, 18067971}, {194964, 18068227}, {194965, 18068483}, + {194966, 18068739}, {194967, 18068995}, {194968, 17566723}, {194969, 18069251}, + {194970, 18069507}, {194971, 18069763}, {194972, 18070019}, {194973, 18070275}, + {194974, 18070531}, {194975, 17618947}, {194976, 18070787}, {194977, 18071043}, + {194978, 18071299}, {194979, 18071555}, {194980, 18071811}, {194981, 18072067}, + {194982, 18072323}, {194983, 18072579}, {194984, 18072835}, {194985, 18073091}, + {194986, 18073347}, {194987, 18073603}, {194988, 18073859}, {194989, 18074115}, + {194990, 18074371}, {194991, 18074627}, {194992, 18074883}, {194993, 18075139}, + {194994, 18075395}, {194995, 18075651}, {194996, 17551619}, {194997, 18075907}, + {194998, 18076163}, {194999, 18076419}, {195000, 18076675}, {195001, 18076931}, + {195002, 18077187}, {195003, 17636099}, {195004, 18077443}, {195005, 18077699}, + {195006, 18077955}, {195007, 2}, {195008, 18078211}, {195009, 18078467}, + {195010, 18078723}, {195011, 18078979}, {195012, 17178371}, {195013, 18079235}, + {195014, 18079491}, {195015, 18079747}, {195016, 18080003}, {195017, 18080259}, + {195018, 18080515}, {195019, 18080771}, {195020, 18081027}, {195021, 18081283}, + {195022, 18081539}, {195023, 18081795}, {195024, 17637379}, {195025, 17637635}, + {195026, 17180163}, {195027, 18082051}, {195028, 18082307}, {195029, 18082563}, + {195030, 18082819}, {195031, 18083075}, {195032, 18083331}, {195033, 18083587}, + {195034, 18083843}, {195035, 18084099}, {195036, 18084355}, {195037, 18084611}, + {195038, 18084867}, {195039, 17637891}, {195040, 18085123}, {195041, 18085379}, + {195042, 18085635}, {195043, 18085891}, {195044, 18086147}, {195045, 18086403}, + {195046, 18086659}, {195047, 18086915}, {195048, 18087171}, {195049, 18087427}, + {195050, 18087683}, {195051, 18087939}, {195052, 18088195}, {195053, 18088451}, + {195054, 18088707}, {195055, 18088963}, {195056, 18089219}, {195057, 18089475}, + {195058, 18089731}, {195059, 18089987}, {195060, 18090243}, {195061, 18090499}, + {195062, 18090755}, {195063, 18091011}, {195064, 18091267}, {195065, 18091523}, + {195066, 18091779}, {195067, 18092035}, {195068, 18092291}, {195069, 18092547}, + {195070, 17639427}, {195072, 18092803}, {195073, 18093059}, {195074, 18093315}, + {195075, 18093571}, {195076, 18093827}, {195077, 18094083}, {195078, 18094339}, + {195079, 18094595}, {195080, 18094851}, {195081, 18095107}, {195082, 17639683}, + {195083, 18095363}, {195084, 18095619}, {195085, 18095875}, {195086, 18096131}, + {195087, 18096387}, {195088, 18096643}, {195089, 18096899}, {195090, 18097155}, + {195091, 18097411}, {195092, 18097667}, {195093, 17192451}, {195094, 18097923}, + {195095, 17193475}, {195096, 18098179}, {195097, 18098435}, {195098, 18098691}, + {195099, 18098947}, {195100, 17194755}, {195101, 18099203}, {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 { @@ -9522,22 +9523,6 @@ bool is_label_valid(const std::u32string_view label) { namespace ada::idna { -bool begins_with(std::u32string_view view, std::u32string_view prefix) { - if (view.size() < prefix.size()) { - return false; - } - // constexpr as of C++20 - return std::equal(prefix.begin(), prefix.end(), view.begin()); -} - -bool begins_with(std::string_view view, std::string_view prefix) { - if (view.size() < prefix.size()) { - return false; - } - // constexpr as of C++20 - return std::equal(prefix.begin(), prefix.end(), view.begin()); -} - bool constexpr is_ascii(std::u32string_view view) { for (uint32_t c : view) { if (c >= 0x80) { @@ -9600,7 +9585,7 @@ static std::string from_ascii_to_ascii(std::string_view ut8_string) { label_start += label_size_with_dot; if (label_size == 0) { // empty label? Nothing to do. - } else if (begins_with(label_view, "xn--")) { + } else if (label_view.starts_with("xn--")) { // The xn-- part is the expensive game. out.append(label_view); std::string_view puny_segment_ascii( @@ -9667,7 +9652,7 @@ std::string to_ascii(std::string_view ut8_string) { label_start += label_size_with_dot; if (label_size == 0) { // empty label? Nothing to do. - } else if (begins_with(label_view, U"xn--")) { + } 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) { @@ -9746,8 +9731,7 @@ std::string to_unicode(std::string_view input) { is_last_label ? input.size() - label_start : loc_dot - label_start; auto label_view = std::string_view(input.data() + label_start, label_size); - if (ada::idna::begins_with(label_view, "xn--") && - ada::idna::is_ascii(label_view)) { + 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; @@ -9782,6 +9766,644 @@ std::string to_unicode(std::string_view input) { } } // namespace ada::idna /* end file src/to_unicode.cpp */ +/* begin file src/identifier.cpp */ + +#include +#include +#include + +/* begin file src/id_tables.cpp */ +// IDNA 15.1.0 + +// clang-format off +#ifndef ADA_IDNA_IDENTIFIER_TABLES_H +#define ADA_IDNA_IDENTIFIER_TABLES_H +#include + +namespace ada::idna { + +const uint32_t id_continue[1344][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}, {2200, 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, 7304}, {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, 42954}, {42960, 42961}, + {42963, 42963}, {42965, 42969}, {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}, {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}, {69248, 69289}, {69291, 69292}, + {69296, 69297}, {69373, 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}, {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}, + {71424, 71450}, {71453, 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}, {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}, + {73648, 73648}, {73728, 74649}, {74752, 74862}, {74880, 75075}, + {77712, 77808}, {77824, 78895}, {78912, 78912}, {78913, 78918}, + {78919, 78933}, {82944, 83526}, {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}, {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}, + {101632, 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}, {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}, {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[740][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, 7304}, {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, 42954}, + {42960, 42961}, {42963, 42963}, {42965, 42969}, {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}, {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}, {69248, 69289}, {69296, 69297}, {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}, {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}, {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}, {82944, 83526}, {92160, 92728}, + {92736, 92766}, {92784, 92862}, {92880, 92909}, {92928, 92975}, + {92992, 92995}, {93027, 93047}, {93053, 93071}, {93760, 93823}, + {93952, 94026}, {94032, 94032}, {94099, 94111}, {94176, 94177}, + {94179, 94179}, {94208, 100343}, {100352, 101589}, {101632, 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}, {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 { +// return 0xffffffff in case of error +// We do not fully validate the input +uint32_t get_first_code_point(std::string_view input) { + constexpr uint32_t error = 0xffffffff; + // Check if the input is empty + if (input.empty()) { + return error; + } + + uint32_t code_point = 0; + size_t number_bytes = 0; + unsigned char first_byte = input[0]; + + if ((first_byte & 0x80) == 0) { + // 1-byte character (ASCII) + return first_byte; + } else if ((first_byte & 0xE0) == 0xC0) { + // 2-byte character + code_point = first_byte & 0x1F; + number_bytes = 2; + } else if ((first_byte & 0xF0) == 0xE0) { + // 3-byte character + code_point = first_byte & 0x0F; + number_bytes = 3; + } else if ((first_byte & 0xF8) == 0xF0) { + // 4-byte character + code_point = first_byte & 0x07; + number_bytes = 4; + } else { + return error; + } + + // Decode the remaining bytes + for (size_t i = 1; i < number_bytes; ++i) { + if (i >= input.size()) { + return error; + } + unsigned char byte = input[i]; + if ((byte & 0xC0) != 0x80) { + return error; + } + code_point = (code_point << 6) | (byte & 0x3F); + } + return code_point; +} + +bool is_ascii_letter(char32_t c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +bool is_ascii_letter_or_digit(char32_t c) { + 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 code_point) { + return range[1] < code_point; + }); + 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 code_point) { + return range[1] < code_point; + }); + 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 @@ -9935,7 +10557,7 @@ ada_really_inline bool has_tabs_or_newline( // U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), or // U+007C (|). constexpr static std::array is_forbidden_host_code_point_table = - []() constexpr { + []() consteval { std::array result{}; for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|'}) { @@ -9950,7 +10572,7 @@ ada_really_inline constexpr bool is_forbidden_host_code_point( } constexpr static std::array is_forbidden_domain_code_point_table = - []() constexpr { + []() consteval { std::array result{}; for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { @@ -9989,7 +10611,7 @@ ada_really_inline constexpr bool contains_forbidden_domain_code_point( } constexpr static std::array - is_forbidden_domain_code_point_table_or_upper = []() constexpr { + is_forbidden_domain_code_point_table_or_upper = []() consteval { std::array result{}; for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { @@ -10030,7 +10652,7 @@ contains_forbidden_domain_code_point_or_upper(const char* input, } // std::isalnum(c) || c == '+' || c == '-' || c == '.') is true for -constexpr static std::array is_alnum_plus_table = []() constexpr { +constexpr static std::array is_alnum_plus_table = []() consteval { std::array result{}; for (size_t c = 0; c < 256; c++) { result[c] = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || @@ -10051,6 +10673,17 @@ ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept { (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 <= ' '; } @@ -10063,7 +10696,7 @@ ada_really_inline constexpr bool is_ascii_tab_or_newline( constexpr std::string_view table_is_double_dot_path_segment[] = { "..", "%2e.", ".%2e", "%2e%2e"}; -ada_really_inline ada_constexpr bool is_double_dot_path_segment( +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. @@ -10151,7 +10784,6 @@ std::string percent_decode(const std::string_view input, size_t first_percent) { !is_ascii_hex_digit(pointer[2])))) { dest += ch; pointer++; - continue; } else { unsigned a = convert_hex_to_binary(pointer[1]); unsigned b = convert_hex_to_binary(pointer[2]); @@ -10165,10 +10797,9 @@ std::string percent_decode(const std::string_view input, size_t first_percent) { std::string percent_encode(const std::string_view input, const uint8_t character_set[]) { - auto pointer = - std::find_if(input.begin(), input.end(), [character_set](const char c) { - return character_sets::bit_at(character_set, c); - }); + 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); @@ -10207,7 +10838,7 @@ bool percent_encode(const std::string_view input, const uint8_t character_set[], ada_log("percent_encode encoding not needed."); return false; } - if (!append) { + if constexpr (!append) { out.clear(); } ada_log("percent_encode appending ", std::distance(input.begin(), pointer), @@ -10261,8 +10892,8 @@ std::string percent_encode(const std::string_view input, } // namespace ada::unicode /* end file src/unicode.cpp */ /* begin file src/serializers.cpp */ - #include +#include #include namespace ada::serializers { @@ -10348,12 +10979,12 @@ std::string ipv4(const uint64_t address) noexcept { namespace ada { template -ada_warn_unused tl::expected parse( +ada_warn_unused tl::expected parse( std::string_view input, const result_type* base_url) { result_type u = ada::parser::parse_url_impl(input, base_url); if (!u.is_valid) { - return tl::unexpected(errors::generic_error); + return tl::unexpected(errors::type_error); } return u; } @@ -10418,12 +11049,16 @@ ada_warn_unused std::string to_string(ada::encoding_type type) { } } +ada_warn_unused tl::expected parse_url_pattern( + std::variant input, + const std::string_view* base_url, const url_pattern_options* options) { + return parser::parse_url_pattern_impl(std::move(input), base_url, options); +} + } // namespace ada /* end file src/implementation.cpp */ /* begin file src/helpers.cpp */ -#include -#include #include #include @@ -10517,13 +11152,11 @@ ada_really_inline std::optional prune_hash( ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type) noexcept { - size_t first_delimiter = path.find_first_of('/', 1); - // 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 && - first_delimiter == std::string_view::npos && !path.empty()) { + path.find('/', 1) == std::string_view::npos && !path.empty()) { if (checkers::is_normalized_windows_drive_letter( helpers::substring(path, 1))) { return false; @@ -10542,13 +11175,11 @@ ada_really_inline bool shorten_path(std::string& path, ada_really_inline bool shorten_path(std::string_view& path, ada::scheme::type type) noexcept { - size_t first_delimiter = path.find_first_of('/', 1); - // 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 && - first_delimiter == std::string_view::npos && !path.empty()) { + path.find('/', 1) == std::string_view::npos && !path.empty()) { if (checkers::is_normalized_windows_drive_letter( helpers::substring(path, 1))) { return false; @@ -10571,15 +11202,11 @@ 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 - input.erase(std::remove_if(input.begin(), input.end(), - [](char c) { - return ada::unicode::is_ascii_tab_or_newline(c); - }), - input.end()); + std::erase_if(input, ada::unicode::is_ascii_tab_or_newline); } -ada_really_inline std::string_view substring(std::string_view input, - size_t pos) noexcept { +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); @@ -10736,7 +11363,7 @@ ada_really_inline size_t find_next_host_delimiter_special( #else // : / [ \\ ? static constexpr std::array special_host_delimiters = - []() constexpr { + []() consteval { std::array result{}; for (int i : {':', '/', '[', '\\', '?'}) { result[i] = 1; @@ -10868,7 +11495,7 @@ ada_really_inline size_t find_next_host_delimiter(std::string_view view, } #else // : / [ ? -static constexpr std::array host_delimiters = []() constexpr { +static constexpr std::array host_delimiters = []() consteval { std::array result{}; for (int i : {':', '/', '?', '['}) { result[i] = 1; @@ -10968,7 +11595,7 @@ ada_really_inline std::pair get_host_delimiter_location( return {location, found_colon}; } -ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept { +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); @@ -11163,7 +11790,7 @@ ada_really_inline void strip_trailing_spaces_from_opaque_path( // @ / \\ ? static constexpr std::array authority_delimiter_special = - []() constexpr { + []() consteval { std::array result{}; for (uint8_t i : {'@', '/', '\\', '?'}) { result[i] = 1; @@ -11184,7 +11811,7 @@ find_authority_delimiter_special(std::string_view view) noexcept { } // @ / ? -static constexpr std::array authority_delimiter = []() constexpr { +static constexpr std::array authority_delimiter = []() consteval { std::array result{}; for (uint8_t i : {'@', '/', '?'}) { result[i] = 1; @@ -11218,13 +11845,14 @@ ada_warn_unused std::string to_string(ada::state state) { #include #include #include +#include namespace ada { bool url::parse_opaque_host(std::string_view input) { ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); - if (std::any_of(input.begin(), input.end(), - ada::unicode::is_forbidden_host_code_point)) { + if (std::ranges::any_of(input.begin(), input.end(), + ada::unicode::is_forbidden_host_code_point)) { return is_valid = false; } @@ -11549,7 +12177,7 @@ ada_really_inline bool url::parse_scheme(const std::string_view input) { *http, https), in which case, we can go really fast. **/ if (is_input_special) { // fast path!!! - if (has_state_override) { + 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) { @@ -11573,7 +12201,7 @@ ada_really_inline bool url::parse_scheme(const std::string_view input) { type = parsed_type; - if (has_state_override) { + if constexpr (has_state_override) { // This is uncommon. uint16_t urls_scheme_port = get_special_port(); @@ -11593,7 +12221,7 @@ ada_really_inline bool url::parse_scheme(const std::string_view input) { // bool is_ascii = unicode::to_lower_ascii(_buffer.data(), _buffer.size()); - if (has_state_override) { + 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. @@ -11617,7 +12245,7 @@ ada_really_inline bool url::parse_scheme(const std::string_view input) { set_scheme(std::move(_buffer)); - if (has_state_override) { + if constexpr (has_state_override) { // This is uncommon. uint16_t urls_scheme_port = get_special_port(); @@ -11726,18 +12354,14 @@ ada_really_inline void url::parse_path(std::string_view input) { path = "/"; } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { helpers::parse_prepared_path(internal_input.substr(1), type, path); - return; } else { helpers::parse_prepared_path(internal_input, type, path); - return; } } else if (!internal_input.empty()) { if (internal_input[0] == '/') { helpers::parse_prepared_path(internal_input.substr(1), type, path); - return; } else { helpers::parse_prepared_path(internal_input, type, path); - return; } } else { if (!host.has_value()) { @@ -11802,17 +12426,6 @@ ada_really_inline void url::parse_path(std::string_view input) { return checkers::verify_dns_length(host.value()); } -} // namespace ada -/* end file src/url.cpp */ -/* begin file src/url-getters.cpp */ -/** - * @file url-getters.cpp - * Includes all the getters of `ada::url` - */ - -#include - -namespace ada { [[nodiscard]] std::string url::get_origin() const noexcept { if (is_special()) { // Return a new opaque origin. @@ -11865,10 +12478,6 @@ namespace ada { return host.value_or(""); } -[[nodiscard]] std::string_view url::get_pathname() const noexcept { - return path; -} - [[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. @@ -11895,19 +12504,6 @@ namespace ada { : "#" + hash.value(); } -} // namespace ada -/* end file src/url-getters.cpp */ -/* begin file src/url-setters.cpp */ -/** - * @file url-setters.cpp - * Includes all the setters of `ada::url` - */ - -#include -#include - -namespace ada { - template bool url::set_host_or_hostname(const std::string_view input) { if (has_opaque_path) { @@ -11935,7 +12531,7 @@ bool url::set_host_or_hostname(const std::string_view input) { // Note: the 'found_colon' value is true if and only if a colon was // encountered while not inside brackets. if (found_colon) { - if (override_hostname) { + if constexpr (override_hostname) { return false; } std::string_view buffer = new_host.substr(location + 1); @@ -12075,8 +12671,7 @@ void url::set_search(const std::string_view input) { is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE : ada::character_sets::QUERY_PERCENT_ENCODE; - query = ada::unicode::percent_encode(std::string_view(new_value), - query_percent_encode_set); + query = ada::unicode::percent_encode(new_value, query_percent_encode_set); } bool url::set_pathname(const std::string_view input) { @@ -12103,7 +12698,7 @@ bool url::set_protocol(const std::string_view input) { view.append(":"); std::string::iterator pointer = - std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus); + std::ranges::find_if_not(view, unicode::is_alnum_plus); if (pointer != view.end() && *pointer == ':') { return parse_scheme( @@ -12116,23 +12711,14 @@ bool url::set_href(const std::string_view input) { ada::result out = ada::parse(input); if (out) { - username = out->username; - password = out->password; - host = out->host; - port = out->port; - path = out->path; - query = out->query; - hash = out->hash; - type = out->type; - non_special_scheme = out->non_special_scheme; - has_opaque_path = out->has_opaque_path; + *this = *out; } return out.has_value(); } } // namespace ada -/* end file src/url-setters.cpp */ +/* end file src/url.cpp */ /* begin file src/parser.cpp */ #include @@ -12148,10 +12734,9 @@ result_type parse_url_impl(std::string_view user_input, // 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::value; + constexpr bool result_type_is_ada_url = std::is_same_v; constexpr bool result_type_is_ada_url_aggregator = - std::is_same::value; + std::is_same_v; static_assert(result_type_is_ada_url || result_type_is_ada_url_aggregator); // We don't support // anything else for now. @@ -12160,12 +12745,12 @@ result_type parse_url_impl(std::string_view user_input, " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), ")"); - ada::state state = ada::state::SCHEME_START; + 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::max()) { + if (user_input.size() > std::numeric_limits::max()) [[unlikely]] { url.is_valid = false; } // Going forward, user_input.size() is in [0, @@ -12196,20 +12781,19 @@ result_type parse_url_impl(std::string_view user_input, url.reserve(reserve_capacity); } std::string tmp_buffer; - std::string_view internal_input; - if (unicode::has_tabs_or_newline(user_input)) { + 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); - internal_input = tmp_buffer; - } else { - internal_input = user_input; + 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). - std::string_view url_data = internal_input; helpers::trim_c0_whitespace(url_data); // Optimization opportunity. Most websites do not have fragment. @@ -12232,27 +12816,27 @@ result_type parse_url_impl(std::string_view user_input, ada_log("In parsing at ", input_position, " out of ", input_size, " in state ", ada::to_string(state)); switch (state) { - case ada::state::SCHEME_START: { + 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 = ada::state::SCHEME; + 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 = ada::state::NO_SCHEME; + state = state::NO_SCHEME; } break; } - case ada::state::SCHEME: { + 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) && - (ada::unicode::is_alnum_plus(url_data[input_position]))) { + (unicode::is_alnum_plus(url_data[input_position]))) { input_position++; } // Otherwise, if c is U+003A (:), then: @@ -12274,9 +12858,9 @@ result_type parse_url_impl(std::string_view user_input, ada_log("SCHEME the scheme is ", url.get_protocol()); // If url's scheme is "file", then: - if (url.type == ada::scheme::type::FILE) { + if (url.type == scheme::type::FILE) { // Set state to file state. - state = ada::state::FILE; + 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 @@ -12284,38 +12868,38 @@ result_type parse_url_impl(std::string_view user_input, else if (url.is_special() && base_url != nullptr && base_url->type == url.type) { // Set state to special relative or authority state. - state = ada::state::SPECIAL_RELATIVE_OR_AUTHORITY; + state = state::SPECIAL_RELATIVE_OR_AUTHORITY; } // Otherwise, if url is special, set state to special authority // slashes state. else if (url.is_special()) { - state = ada::state::SPECIAL_AUTHORITY_SLASHES; + 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 = ada::state::PATH_OR_AUTHORITY; + 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 = ada::state::OPAQUE_PATH; + 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 = ada::state::NO_SCHEME; + state = state::NO_SCHEME; input_position = 0; break; } input_position++; break; } - case ada::state::NO_SCHEME: { + 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. @@ -12346,18 +12930,18 @@ result_type parse_url_impl(std::string_view user_input, } // Otherwise, if base's scheme is not "file", set state to relative // state and decrease pointer by 1. - else if (base_url->type != ada::scheme::type::FILE) { + else if (base_url->type != scheme::type::FILE) { ada_log("NO_SCHEME non-file relative path"); - state = ada::state::RELATIVE_SCHEME; + state = state::RELATIVE_SCHEME; } // Otherwise, set state to file state and decrease pointer by 1. else { ada_log("NO_SCHEME file base type"); - state = ada::state::FILE; + state = state::FILE; } break; } - case ada::state::AUTHORITY: { + 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 @@ -12367,11 +12951,10 @@ result_type parse_url_impl(std::string_view user_input, // 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). - const bool contains_ampersand = - (url_data.find('@', input_position) != std::string_view::npos); - if (!contains_ampersand) { - state = ada::state::HOST; + // 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}; @@ -12382,12 +12965,12 @@ result_type parse_url_impl(std::string_view user_input, * --------^ */ do { - std::string_view view = helpers::substring(url_data, input_position); + 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.data(), location); + 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) && @@ -12468,7 +13051,7 @@ result_type parse_url_impl(std::string_view user_input, url.is_valid = false; return url; } - state = ada::state::HOST; + state = state::HOST; break; } if (end_of_authority == input_size) { @@ -12484,42 +13067,41 @@ result_type parse_url_impl(std::string_view user_input, break; } - case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: { + 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. - std::string_view view = helpers::substring(url_data, input_position); - if (ada::checkers::begins_with(view, "//")) { - state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + 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 = ada::state::RELATIVE_SCHEME; + state = state::RELATIVE_SCHEME; } break; } - case ada::state::PATH_OR_AUTHORITY: { + 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 = ada::state::AUTHORITY; + state = state::AUTHORITY; input_position++; } else { // Otherwise, set state to path state, and decrease pointer by 1. - state = ada::state::PATH; + state = state::PATH; } break; } - case ada::state::RELATIVE_SCHEME: { + case state::RELATIVE_SCHEME: { ada_log("RELATIVE_SCHEME ", helpers::substring(url_data, input_position)); @@ -12532,7 +13114,7 @@ result_type parse_url_impl(std::string_view user_input, ada_log( "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " "slash state"); - state = ada::state::RELATIVE_SLASH; + 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, @@ -12540,7 +13122,7 @@ result_type parse_url_impl(std::string_view user_input, ada_log( "RELATIVE_SCHEME if url is special and c is U+005C, validation " "error, set state to relative slash state"); - state = ada::state::RELATIVE_SLASH; + state = state::RELATIVE_SLASH; } else { ada_log("RELATIVE_SCHEME otherwise"); // Set url's username to base's username, url's password to base's @@ -12559,9 +13141,7 @@ result_type parse_url_impl(std::string_view user_input, } else { url.update_base_authority(base_url->get_href(), base_url->get_components()); - // TODO: Get rid of set_hostname and replace it with - // update_base_hostname - url.set_hostname(base_url->get_hostname()); + 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; @@ -12575,7 +13155,7 @@ result_type parse_url_impl(std::string_view user_input, // state to query state. if ((input_position != input_size) && (url_data[input_position] == '?')) { - state = ada::state::QUERY; + state = state::QUERY; } // Otherwise, if c is not the EOF code point: else if (input_position != input_size) { @@ -12587,18 +13167,18 @@ result_type parse_url_impl(std::string_view user_input, } else { std::string_view path = url.get_pathname(); if (helpers::shorten_path(path, url.type)) { - url.update_base_pathname(std::string(path)); + url.update_base_pathname(std::move(std::string(path))); } } // Set state to path state and decrease pointer by 1. - state = ada::state::PATH; + state = state::PATH; break; } } input_position++; break; } - case ada::state::RELATIVE_SLASH: { + case state::RELATIVE_SLASH: { ada_log("RELATIVE_SLASH ", helpers::substring(url_data, input_position)); @@ -12607,12 +13187,12 @@ result_type parse_url_impl(std::string_view user_input, (url_data[input_position] == '/' || url_data[input_position] == '\\')) { // Set state to special authority ignore slashes state. - state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + 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 = ada::state::AUTHORITY; + state = state::AUTHORITY; } // Otherwise, set // - url's username to base's username, @@ -12629,33 +13209,30 @@ result_type parse_url_impl(std::string_view user_input, } else { url.update_base_authority(base_url->get_href(), base_url->get_components()); - // TODO: Get rid of set_hostname and replace it with - // update_base_hostname - url.set_hostname(base_url->get_hostname()); + url.update_host_to_base_host(base_url->get_hostname()); url.update_base_port(base_url->retrieve_base_port()); } - state = ada::state::PATH; + state = state::PATH; break; } input_position++; break; } - case ada::state::SPECIAL_AUTHORITY_SLASHES: { + 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. - std::string_view view = helpers::substring(url_data, input_position); - if (ada::checkers::begins_with(view, "//")) { + if (url_data.substr(input_position, 2) == "//") { input_position += 2; } [[fallthrough]]; } - case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { + case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", helpers::substring(url_data, input_position)); @@ -12666,23 +13243,22 @@ result_type parse_url_impl(std::string_view user_input, (url_data[input_position] == '\\'))) { input_position++; } - state = ada::state::AUTHORITY; + state = state::AUTHORITY; break; } - case ada::state::QUERY: { + 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() - ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE - : ada::character_sets::QUERY_PERCENT_ENCODE; + 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(helpers::substring(url_data, input_position), + url.update_base_search(url_data.substr(input_position), query_percent_encode_set); ada_log("QUERY update_base_search completed "); if (fragment.has_value()) { @@ -12691,11 +13267,10 @@ result_type parse_url_impl(std::string_view user_input, } return url; } - case ada::state::HOST: { + case state::HOST: { ada_log("HOST ", helpers::substring(url_data, input_position)); - std::string_view host_view = - 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) @@ -12715,7 +13290,7 @@ result_type parse_url_impl(std::string_view user_input, 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 = ada::state::PORT; + state = state::PORT; input_position++; } // Otherwise, if one of the following is true: @@ -12726,7 +13301,7 @@ result_type parse_url_impl(std::string_view user_input, else { // If url is special and host_view is the empty string, validation // error, return failure. - if (url.is_special() && host_view.empty()) { + if (host_view.empty() && url.is_special()) { url.is_valid = false; return url; } @@ -12742,20 +13317,20 @@ result_type parse_url_impl(std::string_view user_input, " href=", url.get_href()); // Set url's host to host, and state to path start state. - state = ada::state::PATH_START; + state = state::PATH_START; } break; } - case ada::state::OPAQUE_PATH: { + case state::OPAQUE_PATH: { ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); - std::string_view view = 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 = ada::state::QUERY; + state = state::QUERY; input_position += location + 1; } else { input_position = input_size + 1; @@ -12767,25 +13342,23 @@ result_type parse_url_impl(std::string_view user_input, view, character_sets::C0_CONTROL_PERCENT_ENCODE)); break; } - case ada::state::PORT: { + case state::PORT: { ada_log("PORT ", helpers::substring(url_data, input_position)); - std::string_view port_view = - helpers::substring(url_data, input_position); - size_t consumed_bytes = url.parse_port(port_view, true); - input_position += consumed_bytes; + 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 ada::state::PATH_START: { + 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 = ada::state::PATH; + state = state::PATH; // Optimization: Avoiding going into PATH state improves the // performance of urls ending with /. @@ -12810,12 +13383,12 @@ result_type parse_url_impl(std::string_view user_input, // set url's query to the empty string and state to query state. else if ((input_position != input_size) && (url_data[input_position] == '?')) { - state = ada::state::QUERY; + state = state::QUERY; } // Otherwise, if c is not the EOF code point: else if (input_position != input_size) { // Set state to path state. - state = ada::state::PATH; + state = state::PATH; // If c is not U+002F (/), then decrease pointer by 1. if (url_data[input_position] != '/') { @@ -12826,15 +13399,15 @@ result_type parse_url_impl(std::string_view user_input, input_position++; break; } - case ada::state::PATH: { - std::string_view view = helpers::substring(url_data, input_position); + 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 = ada::state::QUERY; + state = state::QUERY; view.remove_suffix(view.size() - locofquestionmark); input_position += locofquestionmark + 1; } else { @@ -12850,7 +13423,7 @@ result_type parse_url_impl(std::string_view user_input, } break; } - case ada::state::FILE_SLASH: { + case state::FILE_SLASH: { ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); // If c is U+002F (/) or U+005C (\), then: @@ -12859,21 +13432,19 @@ result_type parse_url_impl(std::string_view user_input, url_data[input_position] == '\\')) { ada_log("FILE_SLASH c is U+002F or U+005C"); // Set state to file host state. - state = ada::state::FILE_HOST; + 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 == ada::scheme::type::FILE) { + 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 { - // TODO: Optimization opportunity. - url.set_host(base_url->get_host()); + 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 @@ -12881,7 +13452,7 @@ result_type parse_url_impl(std::string_view user_input, // url's path. if (!base_url->get_pathname().empty()) { if (!checkers::is_windows_drive_letter( - helpers::substring(url_data, input_position))) { + 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('/'); @@ -12903,14 +13474,14 @@ result_type parse_url_impl(std::string_view user_input, } // Set state to path state, and decrease pointer by 1. - state = ada::state::PATH; + state = state::PATH; } break; } - case ada::state::FILE_HOST: { - std::string_view view = helpers::substring(url_data, input_position); + 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( @@ -12918,7 +13489,7 @@ result_type parse_url_impl(std::string_view user_input, (location != std::string_view::npos) ? location : view.size()); if (checkers::is_windows_drive_letter(file_host_buffer)) { - state = ada::state::PATH; + state = state::PATH; } else if (file_host_buffer.empty()) { // Set url's host to the empty string. if constexpr (result_type_is_ada_url) { @@ -12927,7 +13498,7 @@ result_type parse_url_impl(std::string_view user_input, url.update_base_hostname(""); } // Set state to path start state. - state = ada::state::PATH_START; + state = state::PATH_START; } else { size_t consumed_bytes = file_host_buffer.size(); input_position += consumed_bytes; @@ -12949,15 +13520,14 @@ result_type parse_url_impl(std::string_view user_input, } // Set buffer to the empty string and state to path start state. - state = ada::state::PATH_START; + state = state::PATH_START; } break; } - case ada::state::FILE: { + case state::FILE: { ada_log("FILE ", helpers::substring(url_data, input_position)); - std::string_view file_view = - 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) { @@ -12972,11 +13542,10 @@ result_type parse_url_impl(std::string_view user_input, url_data[input_position] == '\\')) { ada_log("FILE c is U+002F or U+005C"); // Set state to file slash state. - state = ada::state::FILE_SLASH; + state = state::FILE_SLASH; } // Otherwise, if base is non-null and base's scheme is "file": - else if (base_url != nullptr && - base_url->type == ada::scheme::type::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"); @@ -12985,9 +13554,7 @@ result_type parse_url_impl(std::string_view user_input, url.path = base_url->path; url.query = base_url->query; } else { - // TODO: Get rid of set_hostname and replace it with - // update_base_hostname - url.set_hostname(base_url->get_hostname()); + 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()); } @@ -12996,7 +13563,7 @@ result_type parse_url_impl(std::string_view user_input, // 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 = ada::state::QUERY; + state = state::QUERY; } // Otherwise, if c is not the EOF code point: else if (input_position != input_size) { @@ -13010,7 +13577,7 @@ result_type parse_url_impl(std::string_view user_input, } else { std::string_view path = url.get_pathname(); if (helpers::shorten_path(path, url.type)) { - url.update_base_pathname(std::string(path)); + url.update_base_pathname(std::move(std::string(path))); } } } @@ -13022,14 +13589,14 @@ result_type parse_url_impl(std::string_view user_input, } // Set state to path state and decrease pointer by 1. - state = ada::state::PATH; + state = state::PATH; break; } } // Otherwise, set state to path state, and decrease pointer by 1. else { ada_log("FILE go to path"); - state = ada::state::PATH; + state = state::PATH; break; } @@ -13037,7 +13604,7 @@ result_type parse_url_impl(std::string_view user_input, break; } default: - ada::unreachable(); + unreachable(); } } if constexpr (store_values) { @@ -13048,6 +13615,258 @@ result_type parse_url_impl(std::string_view user_input, return url; } +tl::expected parse_url_pattern_impl( + std::variant input, + const std::string_view* base_url, const url_pattern_options* options) { + // Let init be null. + url_pattern_init init; + + // If input is a scalar value string then: + if (std::holds_alternative(input)) { + // Set init to the result of running parse a constructor string given input. + auto parse_result = url_pattern_helpers::constructor_string_parser::parse( + std::get(input)); + if (!parse_result) { + ada_log("constructor_string_parser::parse failed"); + return tl::unexpected(parse_result.error()); + } + init = std::move(*parse_result); + // If baseURL is null and init["protocol"] does not exist, then throw a + // TypeError. + if (!base_url && !init.protocol) { + ada_log("base url is null and protocol is not set"); + return tl::unexpected(errors::type_error); + } + + // If baseURL is not null, set init["baseURL"] to baseURL. + if (base_url) { + init.base_url = std::string(*base_url); + } + } else { + // Assert: input is a URLPatternInit. + ADA_ASSERT_TRUE(std::holds_alternative(input)); + // If baseURL is not null, then throw a TypeError. + if (base_url) { + ada_log("base url is not null"); + return tl::unexpected(errors::type_error); + } + // Optimization: Avoid copy by moving the input value. + // Set init to input. + init = std::move(std::get(input)); + } + + // Let processedInit be the result of process a URLPatternInit given init, + // "pattern", null, null, null, null, null, null, null, and null. + // TODO: Make "pattern" an enum to avoid creating a string everytime. + auto processed_init = url_pattern_init::process(init, "pattern"); + if (!processed_init) { + ada_log("url_pattern_init::process failed for init and 'pattern'"); + return tl::unexpected(processed_init.error()); + } + + // For each componentName of « "protocol", "username", "password", "hostname", + // "port", "pathname", "search", "hash" If processedInit[componentName] does + // not exist, then set processedInit[componentName] to "*". + ADA_ASSERT_TRUE(processed_init.has_value()); + if (!processed_init->protocol) processed_init->protocol = "*"; + if (!processed_init->username) processed_init->username = "*"; + if (!processed_init->password) processed_init->password = "*"; + if (!processed_init->hostname) processed_init->hostname = "*"; + if (!processed_init->port) processed_init->port = "*"; + if (!processed_init->pathname) processed_init->pathname = "*"; + if (!processed_init->search) processed_init->search = "*"; + if (!processed_init->hash) processed_init->hash = "*"; + + ada_log("-- processed_init->protocol: ", processed_init->protocol.value()); + ada_log("-- processed_init->username: ", processed_init->username.value()); + ada_log("-- processed_init->password: ", processed_init->password.value()); + ada_log("-- processed_init->hostname: ", processed_init->hostname.value()); + ada_log("-- processed_init->port: ", processed_init->port.value()); + ada_log("-- processed_init->pathname: ", processed_init->pathname.value()); + ada_log("-- processed_init->search: ", processed_init->search.value()); + ada_log("-- processed_init->hash: ", processed_init->hash.value()); + + // If processedInit["protocol"] is a special scheme and processedInit["port"] + // is a string which represents its corresponding default port in radix-10 + // using ASCII digits then set processedInit["port"] to the empty string. + // TODO: Optimization opportunity. + if (scheme::is_special(*processed_init->protocol)) { + std::string_view port = processed_init->port.value(); + helpers::trim_c0_whitespace(port); + if (std::to_string(scheme::get_special_port(*processed_init->protocol)) == + port) { + processed_init->port->clear(); + } + } + + // Let urlPattern be a new URL pattern. + auto url_pattern_ = url_pattern{}; + + // Set urlPattern’s protocol component to the result of compiling a component + // given processedInit["protocol"], canonicalize a protocol, and default + // options. + auto protocol_component = url_pattern_component::compile( + processed_init->protocol.value(), + url_pattern_helpers::canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol ", + processed_init->protocol.value()); + return tl::unexpected(protocol_component.error()); + } + url_pattern_.protocol_component = std::move(*protocol_component); + + // Set urlPattern’s username component to the result of compiling a component + // given processedInit["username"], canonicalize a username, and default + // options. + auto username_component = url_pattern_component::compile( + processed_init->username.value(), + url_pattern_helpers::canonicalize_username, + url_pattern_compile_component_options::DEFAULT); + if (!username_component) { + ada_log("url_pattern_component::compile failed for username ", + processed_init->username.value()); + return tl::unexpected(username_component.error()); + } + url_pattern_.username_component = std::move(*username_component); + + // Set urlPattern’s password component to the result of compiling a component + // given processedInit["password"], canonicalize a password, and default + // options. + auto password_component = url_pattern_component::compile( + processed_init->password.value(), + url_pattern_helpers::canonicalize_password, + url_pattern_compile_component_options::DEFAULT); + if (!password_component) { + ada_log("url_pattern_component::compile failed for password ", + processed_init->password.value()); + return tl::unexpected(password_component.error()); + } + url_pattern_.password_component = std::move(*password_component); + + // TODO: Optimization opportunity. The following if statement can be + // simplified. + // If the result running hostname pattern is an IPv6 address given + // processedInit["hostname"] is true, then set urlPattern’s hostname component + // to the result of compiling a component given processedInit["hostname"], + // canonicalize an IPv6 hostname, and hostname options. + if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) { + ada_log("processed_init->hostname is ipv6 address"); + // then set urlPattern’s hostname component to the result of compiling a + // component given processedInit["hostname"], canonicalize an IPv6 hostname, + // and hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_ipv6_hostname, + url_pattern_compile_component_options::DEFAULT); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for ipv6 hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } else { + // Otherwise, set urlPattern’s hostname component to the result of compiling + // a component given processedInit["hostname"], canonicalize a hostname, and + // hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_hostname, + url_pattern_compile_component_options::HOSTNAME); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } + + // Set urlPattern’s port component to the result of compiling a component + // given processedInit["port"], canonicalize a port, and default options. + auto port_component = url_pattern_component::compile( + processed_init->port.value(), url_pattern_helpers::canonicalize_port, + url_pattern_compile_component_options::DEFAULT); + if (!port_component) { + ada_log("url_pattern_component::compile failed for port ", + processed_init->port.value()); + return tl::unexpected(port_component.error()); + } + url_pattern_.port_component = std::move(*port_component); + + // Let compileOptions be a copy of the default options with the ignore case + // property set to options["ignoreCase"]. + auto compile_options = url_pattern_compile_component_options::DEFAULT; + if (options) { + compile_options.ignore_case = options->ignore_case; + } + + // TODO: Optimization opportunity: Simplify this if statement. + // If the result of running protocol component matches a special scheme given + // urlPattern’s protocol component is true, then: + if (url_pattern_helpers::protocol_component_matches_special_scheme( + url_pattern_.protocol_component)) { + // Let pathCompileOptions be copy of the pathname options with the ignore + // case property set to options["ignoreCase"]. + auto path_compile_options = url_pattern_compile_component_options::PATHNAME; + if (options) { + path_compile_options.ignore_case = options->ignore_case; + } + + // Set urlPattern’s pathname component to the result of compiling a + // component given processedInit["pathname"], canonicalize a pathname, and + // pathCompileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_pathname, path_compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } else { + // Otherwise set urlPattern’s pathname component to the result of compiling + // a component given processedInit["pathname"], canonicalize an opaque + // pathname, and compileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_opaque_pathname, compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for opaque pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } + + // Set urlPattern’s search component to the result of compiling a component + // given processedInit["search"], canonicalize a search, and compileOptions. + auto search_component = url_pattern_component::compile( + processed_init->search.value(), url_pattern_helpers::canonicalize_search, + compile_options); + if (!search_component) { + ada_log("url_pattern_component::compile failed for search ", + processed_init->search.value()); + return tl::unexpected(search_component.error()); + } + url_pattern_.search_component = std::move(*search_component); + + // Set urlPattern’s hash component to the result of compiling a component + // given processedInit["hash"], canonicalize a hash, and compileOptions. + auto hash_component = url_pattern_component::compile( + processed_init->hash.value(), url_pattern_helpers::canonicalize_hash, + compile_options); + if (!hash_component) { + ada_log("url_pattern_component::compile failed for hash ", + processed_init->hash.value()); + return tl::unexpected(hash_component.error()); + } + url_pattern_.hash_component = std::move(*hash_component); + + // Return urlPattern. + return url_pattern_; +} + template url parse_url_impl(std::string_view user_input, const url* base_url = nullptr); template url_aggregator parse_url_impl( @@ -13072,81 +13891,6 @@ template url_aggregator parse_url( namespace ada { -[[nodiscard]] bool url_components::check_offset_consistency() const noexcept { - /** - * 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 - */ - // These conditions can be made more strict. - uint32_t index = 0; - - if (protocol_end == url_components::omitted) { - return false; - } - if (protocol_end < index) { - return false; - } - index = protocol_end; - - if (username_end == url_components::omitted) { - return false; - } - if (username_end < index) { - return false; - } - index = username_end; - - if (host_start == url_components::omitted) { - return false; - } - if (host_start < index) { - return false; - } - index = host_start; - - if (port != url_components::omitted) { - if (port > 0xffff) { - return false; - } - uint32_t port_length = helpers::fast_digit_count(port) + 1; - if (index + port_length < index) { - return false; - } - index += port_length; - } - - if (pathname_start == url_components::omitted) { - return false; - } - if (pathname_start < index) { - return false; - } - index = pathname_start; - - if (search_start != url_components::omitted) { - if (search_start < index) { - return false; - } - index = search_start; - } - - if (hash_start != url_components::omitted) { - if (hash_start < index) { - return false; - } - } - - return true; -} - [[nodiscard]] std::string url_components::to_string() const { std::string answer; auto back = std::back_insert_iterator(answer); @@ -13205,13 +13949,13 @@ template std::string_view input{input_with_colon}; input.remove_suffix(1); auto parsed_type = ada::scheme::get_scheme_type(input); - bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); + 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 (has_state_override) { + 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) { @@ -13236,7 +13980,7 @@ template type = parsed_type; set_scheme_from_view_with_colon(input_with_colon); - if (has_state_override) { + if constexpr (has_state_override) { // This is uncommon. uint16_t urls_scheme_port = get_special_port(); @@ -13253,7 +13997,7 @@ template // need to check the return value. unicode::to_lower_ascii(_buffer.data(), _buffer.size()); - if (has_state_override) { + 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. @@ -13278,7 +14022,7 @@ template set_scheme(_buffer); - if (has_state_override) { + if constexpr (has_state_override) { // This is uncommon. uint16_t urls_scheme_port = get_special_port(); @@ -13407,7 +14151,7 @@ bool url_aggregator::set_protocol(const std::string_view input) { view.append(":"); std::string::iterator pointer = - std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus); + std::ranges::find_if_not(view, unicode::is_alnum_plus); if (pointer != view.end() && *pointer == ':') { return parse_scheme_with_colon( @@ -13499,8 +14243,7 @@ bool url_aggregator::set_pathname(const std::string_view input) { } clear_pathname(); parse_path(input); - if (checkers::begins_with(get_pathname(), "//") && !has_authority() && - !has_dash_dot()) { + if (get_pathname().starts_with("//") && !has_authority() && !has_dash_dot()) { buffer.insert(components.pathname_start, "/."); components.pathname_start += 2; } @@ -13724,7 +14467,7 @@ bool url_aggregator::set_host_or_hostname(const std::string_view input) { // Note: the 'found_colon' value is true if and only if a colon was // encountered while not inside brackets. if (found_colon) { - if (override_hostname) { + if constexpr (override_hostname) { return false; } std::string_view sub_buffer = new_host.substr(location + 1); @@ -13908,21 +14651,6 @@ bool url_aggregator::set_hostname(const std::string_view input) { return helpers::substring(buffer, start, components.host_end); } -[[nodiscard]] std::string_view url_aggregator::get_pathname() const noexcept - ada_lifetime_bound { - ada_log("url_aggregator::get_pathname pathname_start = ", - components.pathname_start, " buffer.size() = ", buffer.size(), - " components.search_start = ", components.search_start, - " components.hash_start = ", components.hash_start); - auto ending_index = uint32_t(buffer.size()); - if (components.search_start != url_components::omitted) { - ending_index = components.search_start; - } else if (components.hash_start != url_components::omitted) { - ending_index = components.hash_start; - } - return helpers::substring(buffer, components.pathname_start, ending_index); -} - [[nodiscard]] std::string_view url_aggregator::get_search() const noexcept ada_lifetime_bound { ada_log("url_aggregator::get_search"); @@ -14562,191 +15290,21 @@ bool url_aggregator::parse_opaque_host(std::string_view input) { return answer; } -[[nodiscard]] bool url_aggregator::validate() const noexcept { - if (!is_valid) { - return true; - } - if (!components.check_offset_consistency()) { - ada_log("url_aggregator::validate inconsistent components \n", - to_diagram()); - return false; - } - // We have a credible components struct, but let us investivate more - // carefully: - /** - * 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 - */ - if (components.protocol_end == url_components::omitted) { - ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram()); - return false; - } - if (components.username_end == url_components::omitted) { - ada_log("url_aggregator::validate omitted username_end \n", to_diagram()); - return false; - } - if (components.host_start == url_components::omitted) { - ada_log("url_aggregator::validate omitted host_start \n", to_diagram()); - return false; - } - if (components.host_end == url_components::omitted) { - ada_log("url_aggregator::validate omitted host_end \n", to_diagram()); - return false; - } - if (components.pathname_start == url_components::omitted) { - ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram()); - return false; - } - - if (components.protocol_end > buffer.size()) { - ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram()); - return false; - } - if (components.username_end > buffer.size()) { - ada_log("url_aggregator::validate username_end overflow \n", to_diagram()); - return false; - } - if (components.host_start > buffer.size()) { - ada_log("url_aggregator::validate host_start overflow \n", to_diagram()); - return false; - } - if (components.host_end > buffer.size()) { - ada_log("url_aggregator::validate host_end overflow \n", to_diagram()); - return false; - } - if (components.pathname_start > buffer.size()) { - ada_log("url_aggregator::validate pathname_start overflow \n", - to_diagram()); - return false; - } - - if (components.protocol_end > 0) { - if (buffer[components.protocol_end - 1] != ':') { - ada_log( - "url_aggregator::validate missing : at the end of the protocol \n", - to_diagram()); - return false; - } +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.username_end != buffer.size() && - components.username_end > components.protocol_end + 2) { - if (buffer[components.username_end] != ':' && - buffer[components.username_end] != '@') { - ada_log( - "url_aggregator::validate missing : or @ at the end of the username " - "\n", - to_diagram()); - return false; - } + if (components.hash_start != url_components::omitted) { + components.hash_start -= 2; } - - if (components.host_start != buffer.size()) { - if (components.host_start > components.username_end) { - if (buffer[components.host_start] != '@') { - ada_log( - "url_aggregator::validate missing @ at the end of the password \n", - to_diagram()); - return false; - } - } else if (components.host_start == components.username_end && - components.host_end > components.host_start) { - if (components.host_start == components.protocol_end + 2) { - if (buffer[components.protocol_end] != '/' || - buffer[components.protocol_end + 1] != '/') { - ada_log( - "url_aggregator::validate missing // between protocol and host " - "\n", - to_diagram()); - return false; - } - } else { - if (components.host_start > components.protocol_end && - buffer[components.host_start] != '@') { - ada_log( - "url_aggregator::validate missing @ at the end of the username " - "\n", - to_diagram()); - return false; - } - } - } else { - if (components.host_end != components.host_start) { - ada_log("url_aggregator::validate expected omitted host \n", - to_diagram()); - return false; - } - } - } - if (components.host_end != buffer.size() && - components.pathname_start > components.host_end) { - if (components.pathname_start == components.host_end + 2 && - buffer[components.host_end] == '/' && - buffer[components.host_end + 1] == '.') { - if (components.pathname_start + 1 >= buffer.size() || - buffer[components.pathname_start] != '/' || - buffer[components.pathname_start + 1] != '/') { - ada_log( - "url_aggregator::validate expected the path to begin with // \n", - to_diagram()); - return false; - } - } else if (buffer[components.host_end] != ':') { - ada_log("url_aggregator::validate missing : at the port \n", - to_diagram()); - return false; - } - } - if (components.pathname_start != buffer.size() && - components.pathname_start < components.search_start && - components.pathname_start < components.hash_start && !has_opaque_path) { - if (buffer[components.pathname_start] != '/') { - ada_log("url_aggregator::validate missing / at the path \n", - to_diagram()); - return false; - } - } - if (components.search_start != url_components::omitted) { - if (buffer[components.search_start] != '?') { - ada_log("url_aggregator::validate missing ? at the search \n", - to_diagram()); - return false; - } - } - if (components.hash_start != url_components::omitted) { - if (buffer[components.hash_start] != '#') { - ada_log("url_aggregator::validate missing # at the hash \n", - to_diagram()); - return false; - } - } - - return true; -} - -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()); -} + 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); @@ -14922,6 +15480,2105 @@ inline void url_aggregator::consume_prepared_path(std::string_view input) { } } // namespace ada /* end file src/url_aggregator.cpp */ +/* begin file src/url_pattern.cpp */ + +#include +#include +#include +#include + +namespace ada { +// The default options is an options struct with delimiter code point set to +// the empty string and prefix code point set to the empty string. +url_pattern_compile_component_options + url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt); + +// The hostname options is an options struct with delimiter code point set +// "." and prefix code point set to the empty string. +url_pattern_compile_component_options + url_pattern_compile_component_options::HOSTNAME('.', std::nullopt); + +// The pathname options is an options struct with delimiter code point set +// "/" and prefix code point set to "/". +url_pattern_compile_component_options + url_pattern_compile_component_options::PATHNAME('/', '/'); + +tl::expected url_pattern_init::process( + url_pattern_init init, std::string_view type, + std::optional protocol, + std::optional username, + std::optional password, + std::optional hostname, + std::optional port, + std::optional pathname, + std::optional search, + std::optional 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 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(*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 != "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 != "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. + 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. + std::string new_pathname = base_url_path.substr(0, slash_index + 1); + // Append result["pathname"] to the end of new pathname. + ADA_ASSERT_TRUE(result.pathname.has_value()); + new_pathname.append(result.pathname.value()); + // Set result["pathname"] to new pathname. + result.pathname = std::move(new_pathname); + } + } + + // 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 url_pattern_init::process_protocol( + std::string_view value, std::string_view 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 == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a protocol given strippedValue. + return url_pattern_helpers::canonicalize_protocol(value); +} + +tl::expected url_pattern_init::process_username( + std::string_view value, std::string_view type) { + // If type is "pattern" then return value. + if (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 url_pattern_init::process_password( + std::string_view value, std::string_view type) { + // If type is "pattern" then return value. + if (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 url_pattern_init::process_hostname( + std::string_view value, std::string_view type) { + ada_log("process_hostname value=", value, " type=", type); + // If type is "pattern" then return value. + if (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 url_pattern_init::process_port( + std::string_view port, std::string_view protocol, std::string_view type) { + // If type is "pattern" then return portValue. + if (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 url_pattern_init::process_pathname( + std::string_view value, std::string_view protocol, std::string_view type) { + // If type is "pattern" then return pathnameValue. + if (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 url_pattern_init::process_search( + std::string_view value, std::string_view 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 == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a search given strippedValue. + return url_pattern_helpers::canonicalize_search(value); +} + +tl::expected url_pattern_init::process_hash( + std::string_view value, std::string_view 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 == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a hash given strippedValue. + return url_pattern_helpers::canonicalize_hash(value); +} + +std::string url_pattern_options::to_string() const { + std::string answer; + answer.append("{\n"); + answer.append("\t\"ignore_case\":\""); + answer.append(ignore_case ? "true" : "false"); + answer.append("\",\n"); + answer.append("}"); + return answer; +} + +std::string url_pattern_init::to_string() const { + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + + if (protocol.has_value()) { + answer.append("\t\"protocol\":\""); + helpers::encode_json(protocol.value(), back); + answer.append("\",\n"); + } + + if (username.has_value()) { + answer.append("\t\"username\":\""); + helpers::encode_json(username.value(), back); + answer.append("\",\n"); + } + + if (password.has_value()) { + answer.append("\t\"password\":\""); + helpers::encode_json(password.value(), back); + answer.append("\",\n"); + } + + if (hostname.has_value()) { + answer.append("\t\"hostname\":\""); + helpers::encode_json(hostname.value(), back); + answer.append("\",\n"); + } + + if (port.has_value()) { + answer.append("\t\"port\":\""); + helpers::encode_json(port.value(), back); + answer.append("\",\n"); + } + + if (pathname.has_value()) { + answer.append("\t\"pathname\":\""); + helpers::encode_json(pathname.value(), back); + answer.append("\",\n"); + } + + if (search.has_value()) { + answer.append("\t\"search\":\""); + helpers::encode_json(search.value(), back); + answer.append("\",\n"); + } + + if (hash.has_value()) { + answer.append("\t\"hash\":\""); + helpers::encode_json(hash.value(), back); + answer.append("\",\n"); + } + + if (base_url.has_value()) { + answer.append("\t\"base_url\":\""); + helpers::encode_json(base_url.value(), back); + answer.append("\",\n"); + } + + answer.append("}"); + return answer; +} + +template +tl::expected url_pattern_component::compile( + std::string_view input, F& encoding_callback, + url_pattern_compile_component_options& options) { + ada_log("url_pattern_component::compile input: ", input); + // Let part list be the result of running parse a pattern string given input, + // options, and encoding callback. + auto part_list = url_pattern_helpers::parse_pattern_string(input, options, + encoding_callback); + + if (!part_list) { + ada_log("parse_pattern_string failed"); + return tl::unexpected(part_list.error()); + } + + // Let (regular expression string, name list) be the result of running + // generate a regular expression and name list given part list and options. + auto [regular_expression_string, name_list] = + url_pattern_helpers::generate_regular_expression_and_name_list(*part_list, + options); + + ada_log("regular expression string: ", regular_expression_string); + + // 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 = options.ignore_case + ? std::regex::icase | std::regex_constants::ECMAScript + : std::regex_constants::ECMAScript; + + // Let pattern string be the result of running generate a pattern + // string given part list and options. + auto pattern_string = + url_pattern_helpers::generate_pattern_string(*part_list, options); + + // Let regular expression be RegExpCreate(regular expression string, + // flags). If this throws an exception, catch it, and throw a + // TypeError. + std::regex regular_expression; + try { + regular_expression = std::regex(regular_expression_string, flags); + } catch (std::regex_error& error) { + (void)error; + ada_log("std::regex_error: ", error.what()); + return tl::unexpected(errors::type_error); + } + + // For each part of part list: + // - If part’s type is "regexp", then set has regexp groups to true. + const auto has_regexp = [](const auto& part) { return part.is_regexp(); }; + const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp); + + ada_log("has regexp groups: ", has_regexp_groups); + + // Return a new component whose pattern string is pattern string, regular + // expression is regular expression, group name list is name list, and has + // regexp groups is has regexp groups. + return url_pattern_component(std::move(pattern_string), + std::move(regular_expression), flags, + std::move(name_list), has_regexp_groups); +} + +result> url_pattern::exec( + const url_pattern_input& input, std::string_view* base_url = nullptr) { + // Return the result of match given this's associated URL pattern, input, and + // baseURL if given. + return match(input, base_url); +} + +result url_pattern::test(const url_pattern_input& input, + std::string_view* base_url = nullptr) { + // TODO: Optimization opportunity. Rather than returning `url_pattern_result` + // Implement a fast path just like `can_parse()` in ada_url. + // Let result be the result of match given this's associated URL pattern, + // input, and baseURL if given. + // If result is null, return false. + if (auto result = match(input, base_url); result.has_value()) { + return result->has_value(); + } + return tl::unexpected(errors::type_error); +} + +result> url_pattern::match( + const url_pattern_input& input, std::string_view* base_url_string) { + std::string protocol{}; + std::string username{}; + std::string password{}; + std::string hostname{}; + std::string port{}; + std::string pathname{}; + std::string search{}; + std::string hash{}; + + // Let inputs be an empty list. + // Append input to inputs. + std::vector inputs{input}; + + // If input is a URLPatternInit then: + if (std::holds_alternative(input)) { + ada_log( + "url_pattern::match called with url_pattern_init and base_url_string=", + base_url_string); + // If baseURLString was given, throw a TypeError. + if (base_url_string) { + ada_log("failed to match because base_url_string was given"); + return tl::unexpected(errors::type_error); + } + + // Let applyResult be the result of process a URLPatternInit given input, + // "url", protocol, username, password, hostname, port, pathname, search, + // and hash. + auto apply_result = url_pattern_init::process( + std::get(input), "url", protocol, username, password, + hostname, port, pathname, search, hash); + + // If this throws an exception, catch it, and return null. + if (!apply_result.has_value()) { + ada_log("match returned std::nullopt because process threw"); + return std::nullopt; + } + + // Set protocol to applyResult["protocol"]. + ADA_ASSERT_TRUE(apply_result->protocol.has_value()); + protocol = apply_result->protocol.value(); + + // Set username to applyResult["username"]. + ADA_ASSERT_TRUE(apply_result->username.has_value()); + username = apply_result->username.value(); + + // Set password to applyResult["password"]. + ADA_ASSERT_TRUE(apply_result->password.has_value()); + password = apply_result->password.value(); + + // Set hostname to applyResult["hostname"]. + ADA_ASSERT_TRUE(apply_result->hostname.has_value()); + hostname = apply_result->hostname.value(); + + // Set port to applyResult["port"]. + ADA_ASSERT_TRUE(apply_result->port.has_value()); + port = apply_result->port.value(); + + // Set pathname to applyResult["pathname"]. + ADA_ASSERT_TRUE(apply_result->pathname.has_value()); + pathname = apply_result->pathname.value(); + + // Set search to applyResult["search"]. + ADA_ASSERT_TRUE(apply_result->search.has_value()); + if (apply_result->search->starts_with("?")) { + search = apply_result->search->substr(1); + } else { + search = apply_result->search.value(); + } + + // Set hash to applyResult["hash"]. + ADA_ASSERT_TRUE(apply_result->hash.has_value()); + ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#")); + hash = apply_result->hash.value(); + } else { + ADA_ASSERT_TRUE(std::holds_alternative(input)); + + // Let baseURL be null. + result base_url; + + // If baseURLString was given, then: + if (base_url_string) { + // Let baseURL be the result of parsing baseURLString. + base_url = ada::parse(*base_url_string, nullptr); + + // If baseURL is failure, return null. + if (!base_url) { + ada_log("match returned std::nullopt because failed to parse base_url=", + *base_url_string); + return std::nullopt; + } + + // Append baseURLString to inputs. + inputs.emplace_back(*base_url_string); + } + + url_aggregator* base_url_value = + base_url.has_value() ? &base_url.value() : nullptr; + + // Set url to the result of parsing input given baseURL. + auto url = ada::parse(std::get(input), + base_url_value); + + // If url is failure, return null. + if (!url) { + ada_log("match returned std::nullopt because url failed"); + return std::nullopt; + } + + // Set protocol to url’s scheme. + // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038 + protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1); + // Set username to url’s username. + username = url->get_username(); + // Set password to url’s password. + password = url->get_password(); + // Set hostname to url’s host, serialized, or the empty string if the value + // is null. + hostname = url->get_hostname(); + // Set port to url’s port, serialized, or the empty string if the value is + // null. + port = url->get_port(); + // Set pathname to the result of URL path serializing url. + pathname = url->get_pathname(); + // Set search to url’s query or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232 + if (url->has_search()) { + ADA_ASSERT_TRUE(url->get_search().starts_with("?")); + search = url->get_search().substr(1); + } else { + search = ""; + } + // Set hash to url’s fragment or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is + // removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242 + if (url->has_hash()) { + ADA_ASSERT_TRUE(url->get_hash().starts_with("#")); + hash = url->get_hash().substr(1); + } else { + hash = ""; + } + } + + auto regex_flags = std::regex_constants::match_any; + + // Let protocolExecResult be RegExpBuiltinExec(urlPattern’s protocol + // component's regular expression, protocol). + std::smatch protocol_exec_result_value; + auto protocol_exec_result = + std::regex_search(protocol, protocol_exec_result_value, + protocol_component.regexp, regex_flags); + + // Let usernameExecResult be RegExpBuiltinExec(urlPattern’s username + // component's regular expression, username). + std::smatch username_exec_result_value; + auto username_exec_result = + std::regex_search(username, username_exec_result_value, + username_component.regexp, regex_flags); + + // Let passwordExecResult be RegExpBuiltinExec(urlPattern’s password + // component's regular expression, password). + std::smatch password_exec_result_value; + auto password_exec_result = + std::regex_search(password, password_exec_result_value, + password_component.regexp, regex_flags); + + // Let hostnameExecResult be RegExpBuiltinExec(urlPattern’s hostname + // component's regular expression, hostname). + std::smatch hostname_exec_result_value; + auto hostname_exec_result = + std::regex_search(hostname, hostname_exec_result_value, + hostname_component.regexp, regex_flags); + + // Let portExecResult be RegExpBuiltinExec(urlPattern’s port component's + // regular expression, port). + std::smatch port_exec_result_value; + auto port_exec_result = std::regex_search(port, port_exec_result_value, + port_component.regexp, regex_flags); + + // Let pathnameExecResult be RegExpBuiltinExec(urlPattern’s pathname + // component's regular expression, pathname). + std::smatch pathname_exec_result_value; + auto pathname_exec_result = + std::regex_search(pathname, pathname_exec_result_value, + pathname_component.regexp, regex_flags); + + // Let searchExecResult be RegExpBuiltinExec(urlPattern’s search component's + // regular expression, search). + std::smatch search_exec_result_value; + auto search_exec_result = std::regex_search( + search, search_exec_result_value, search_component.regexp, regex_flags); + + // Let hashExecResult be RegExpBuiltinExec(urlPattern’s hash component's + // regular expression, hash). + std::smatch hash_exec_result_value; + auto hash_exec_result = std::regex_search(hash, hash_exec_result_value, + hash_component.regexp, regex_flags); + + // If protocolExecResult, usernameExecResult, passwordExecResult, + // hostnameExecResult, portExecResult, pathnameExecResult, searchExecResult, + // or hashExecResult are null then return null. + if (!protocol_exec_result || !username_exec_result || !password_exec_result || + !hostname_exec_result || !port_exec_result || !pathname_exec_result || + !search_exec_result || !hash_exec_result) { + return std::nullopt; + } + + // Let result be a new URLPatternResult. + auto result = url_pattern_result{}; + // Set result["inputs"] to inputs. + result.inputs = std::move(inputs); + // Set result["protocol"] to the result of creating a component match result + // given urlPattern’s protocol component, protocol, and protocolExecResult. + result.protocol = protocol_component.create_component_match_result( + protocol, protocol_exec_result_value); + + // Set result["username"] to the result of creating a component match result + // given urlPattern’s username component, username, and usernameExecResult. + result.username = username_component.create_component_match_result( + username, username_exec_result_value); + + // Set result["password"] to the result of creating a component match result + // given urlPattern’s password component, password, and passwordExecResult. + result.password = password_component.create_component_match_result( + password, password_exec_result_value); + + // Set result["hostname"] to the result of creating a component match result + // given urlPattern’s hostname component, hostname, and hostnameExecResult. + result.hostname = hostname_component.create_component_match_result( + hostname, hostname_exec_result_value); + + // Set result["port"] to the result of creating a component match result given + // urlPattern’s port component, port, and portExecResult. + result.port = port_component.create_component_match_result( + port, port_exec_result_value); + + // Set result["pathname"] to the result of creating a component match result + // given urlPattern’s pathname component, pathname, and pathnameExecResult. + result.pathname = pathname_component.create_component_match_result( + pathname, pathname_exec_result_value); + + // Set result["search"] to the result of creating a component match result + // given urlPattern’s search component, search, and searchExecResult. + result.search = search_component.create_component_match_result( + search, search_exec_result_value); + + // Set result["hash"] to the result of creating a component match result given + // urlPattern’s hash component, hash, and hashExecResult. + result.hash = hash_component.create_component_match_result( + hash, hash_exec_result_value); + + return result; +} + +} // namespace ada +/* end file src/url_pattern.cpp */ +/* begin file src/url_pattern_helpers.cpp */ + +#include +#include +#include + +namespace ada::url_pattern_helpers { + +std::tuple> +generate_regular_expression_and_name_list( + std::vector& part_list, + url_pattern_compile_component_options options) { + // Let result be "^" + std::string result = "^"; + + // Let name list be a new list + std::vector name_list{}; + const std::string full_wildcard_regexp_value = ".*"; + + // 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 + // (?:) + // 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 = full_wildcard_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) { + // () + result += "(" + regexp_value + ")" + + convert_modifier_to_string(part.modifier); + } else { + // ((?:)) + 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) { + // (?:()) + 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()); + + // (?:((?:)(?:(?:))*))? + // 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 {result, 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; +} + +bool protocol_component_matches_special_scheme( + url_pattern_component& component) { + auto regex = component.regexp; + return std::regex_match("http", regex) || std::regex_match("https", regex) || + std::regex_match("ws", regex) || std::regex_match("wss", regex) || + std::regex_match("ftp", regex); +} + +inline std::optional +constructor_string_parser::compute_protocol_matches_special_scheme_flag() { + ada_log( + "constructor_string_parser::compute_protocol_matches_special_scheme_" + "flag"); + // Let protocol string be the result of running make a component string given + // parser. + auto protocol_string = make_component_string(); + // Let protocol component be the result of compiling a component given + // protocol string, canonicalize a protocol, and default options. + auto protocol_component = url_pattern_component::compile( + protocol_string, canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol_string ", + protocol_string); + return protocol_component.error(); + } + // If the result of running protocol component matches a special scheme given + // protocol component is true, then set parser’s protocol matches a special + // scheme flag to true. + if (protocol_component_matches_special_scheme(*protocol_component)) { + protocol_matches_a_special_scheme_flag = true; + } + return std::nullopt; +} + +tl::expected 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( + 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 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("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 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("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 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("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 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 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("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 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(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 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(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 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("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 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("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 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("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 constructor_string_parser::parse( + std::string_view input) { + ada_log("constructor_string_parser::parse input=", input); + // Let parser be a new constructor string parser whose input is input and + // token list is the result of running tokenize given input and "lenient". + auto token_list = tokenize(input, token_policy::LENIENT); + if (!token_list) { + return tl::unexpected(token_list.error()); + } + auto parser = constructor_string_parser(input, std::move(*token_list)); + + // While parser’s token index is less than parser’s token list size: + while (parser.token_index < parser.token_list.size()) { + // Set parser’s token increment to 1. + parser.token_increment = 1; + + // If parser’s token list[parser’s token index]'s type is "end" then: + if (parser.token_list[parser.token_index].type == token_type::END) { + // If parser’s state is "init": + if (parser.state == State::INIT) { + // Run rewind given parser. + parser.rewind(); + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash" and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true: Run change state given parser, "search" and 1. + parser.change_state(State::SEARCH, 1); + } else { + // Run change state given parser, "pathname" and 0. + parser.change_state(State::PATHNAME, 0); + } + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + if (parser.state == State::AUTHORITY) { + // If parser’s state is "authority": + // Run rewind and set state given parser, and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + // Run change state given parser, "done" and 0. + parser.change_state(State::DONE, 0); + // Break. + break; + } + + // If the result of running is a group open given parser is true: + if (parser.is_group_open()) { + // Increment parser’s group depth by 1. + parser.group_depth += 1; + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + } + + // If parser’s group depth is greater than 0: + if (parser.group_depth > 0) { + // If the result of running is a group close given parser is true, then + // decrement parser’s group depth by 1. + if (parser.is_group_close()) { + parser.group_depth -= 1; + } else { + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + continue; + } + } + + // Switch on parser’s state and run the associated steps: + switch (parser.state) { + case State::INIT: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run rewind and set state given parser and "protocol". + parser.rewind(); + parser.change_state(State::PROTOCOL, 0); + } + break; + } + case State::PROTOCOL: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run compute protocol matches a special scheme flag given parser. + if (const auto error = + parser.compute_protocol_matches_special_scheme_flag()) { + ada_log("compute_protocol_matches_special_scheme_flag failed"); + return tl::unexpected(*error); + } + // Let next state be "pathname". + auto next_state = State::PATHNAME; + // Let skip be 1. + auto skip = 1; + // If the result of running next is authority slashes given parser is + // true: + if (parser.next_is_authority_slashes()) { + // Set next state to "authority". + next_state = State::AUTHORITY; + // Set skip to 3. + skip = 3; + } else if (parser.protocol_matches_a_special_scheme_flag) { + // Otherwise if parser’s protocol matches a special scheme flag is + // true, then set next state to "authority". + next_state = State::AUTHORITY; + } + + // Run change state given parser, next state, and skip. + parser.change_state(next_state, skip); + } + break; + } + case State::AUTHORITY: { + // If the result of running is an identity terminator given parser is + // true, then run rewind and set state given parser and "username". + if (parser.is_an_identity_terminator()) { + parser.rewind(); + parser.change_state(State::USERNAME, 0); + } else if (parser.is_pathname_start() || parser.is_search_prefix() || + parser.is_hash_prefix()) { + // Otherwise if any of the following are true: + // - the result of running is a pathname start given parser; + // - the result of running is a search prefix given parser; or + // - the result of running is a hash prefix given parser, + // then run rewind and set state given parser and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + } + break; + } + case State::USERNAME: { + // If the result of running is a password prefix given parser is true, + // then run change state given parser, "password", and 1. + if (parser.is_password_prefix()) { + parser.change_state(State::PASSWORD, 1); + } else if (parser.is_an_identity_terminator()) { + // Otherwise if the result of running is an identity terminator given + // parser is true, then run change state given parser, "hostname", + // and 1. + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::PASSWORD: { + // If the result of running is an identity terminator given parser is + // true, then run change state given parser, "hostname", and 1. + if (parser.is_an_identity_terminator()) { + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::HOSTNAME: { + // If the result of running is an IPv6 open given parser is true, then + // increment parser’s hostname IPv6 bracket depth by 1. + if (parser.is_an_ipv6_open()) { + parser.hostname_ipv6_bracket_depth += 1; + } else if (parser.is_an_ipv6_close()) { + // Otherwise if the result of running is an IPv6 close given parser is + // true, then decrement parser’s hostname IPv6 bracket depth by 1. + parser.hostname_ipv6_bracket_depth -= 1; + } else if (parser.is_port_prefix() && + parser.hostname_ipv6_bracket_depth == 0) { + // Otherwise if the result of running is a port prefix given parser is + // true and parser’s hostname IPv6 bracket depth is zero, then run + // change state given parser, "port", and 1. + parser.change_state(State::PORT, 1); + } else if (parser.is_pathname_start()) { + // Otherwise if the result of running is a pathname start given parser + // is true, then run change state given parser, "pathname", and 0. + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + + break; + } + case State::PORT: { + // If the result of running is a pathname start given parser is true, + // then run change state given parser, "pathname", and 0. + if (parser.is_pathname_start()) { + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::PATHNAME: { + // If the result of running is a search prefix given parser is true, + // then run change state given parser, "search", and 1. + if (parser.is_search_prefix()) { + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::SEARCH: { + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash", and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } + } + case State::HASH: { + // Do nothing + break; + } + default: { + // Assert: This step is never reached. + unreachable(); + } + } + + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + } + + // If parser’s result contains "hostname" and not "port", then set parser’s + // result["port"] to the empty string. + if (parser.result.hostname && !parser.result.port) { + parser.result.port = ""; + } + + // Return parser’s result. + return parser.result; +} + +tl::expected, 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 escape_regexp_table = []() consteval { + std::array 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, + std::string_view type) { + // If type is not "pattern" return input. + if (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, + std::string_view 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") 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.starts_with("\\/")) return true; + // If input[0] is U+007B ({) and input[1] is U+002F (/), then return true. + if (input.starts_with("{/")) return true; + // Return false. + return false; +} + +std::string generate_pattern_string( + std::vector& 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 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 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 +/* end file src/url_pattern_helpers.cpp */ /* begin file src/ada_c.cpp */ ada::result& get_instance(void* result) noexcept { diff --git a/deps/ada/ada.gyp b/deps/ada/ada.gyp index 55cea0033e4fbd..4f871e3f68afb1 100644 --- a/deps/ada/ada.gyp +++ b/deps/ada/ada.gyp @@ -11,7 +11,17 @@ 'direct_dependent_settings': { 'include_dirs': ['.'], }, - 'sources': [ '<@(ada_sources)' ] + 'sources': [ '<@(ada_sources)' ], + 'cflags_cc': ['-fexceptions'], + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', # -fexceptions + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeTypeInfo': 'true', + 'ExceptionHandling': 1, + }, + }, }, ] } diff --git a/deps/ada/ada.h b/deps/ada/ada.h index 4b00198e6a4bac..3b49ce9670e00b 100644 --- a/deps/ada/ada.h +++ b/deps/ada/ada.h @@ -1,4 +1,4 @@ -/* auto-generated on 2024-09-02 20:07:32 -0400. Do not edit! */ +/* auto-generated on 2025-01-08 10:36:11 -0500. Do not edit! */ /* begin file include/ada.h */ /** * @file ada.h @@ -8,7 +8,7 @@ #define ADA_H /* begin file include/ada/ada_idna.h */ -/* auto-generated on 2023-09-19 15:58:51 -0400. Do not edit! */ +/* auto-generated on 2024-12-18 09:44:34 -0500. Do not edit! */ /* begin file include/idna.h */ #ifndef ADA_IDNA_H #define ADA_IDNA_H @@ -129,9 +129,6 @@ std::string to_ascii(std::string_view ut8_string); // https://url.spec.whatwg.org/#forbidden-domain-code-point bool contains_forbidden_domain_code_point(std::string_view ascii_string); -bool begins_with(std::u32string_view view, std::u32string_view prefix); -bool begins_with(std::string_view view, std::string_view prefix); - bool constexpr is_ascii(std::u32string_view view); bool constexpr is_ascii(std::string_view view); @@ -154,6 +151,29 @@ std::string to_unicode(std::string_view input); #endif // ADA_IDNA_TO_UNICODE_H /* end file include/ada/idna/to_unicode.h */ +/* begin file include/ada/idna/identifier.h */ +#ifndef ADA_IDNA_IDENTIFIER_H +#define ADA_IDNA_IDENTIFIER_H + +#include +#include + +namespace ada::idna { + +// Access the first code point of the input string. +// Verify if it is valid name code point given a Unicode code point and a +// boolean first: If first is true return the result of checking if code point +// is contained in the IdentifierStart set of code points. Otherwise return the +// result of checking if code point is contained in the IdentifierPart set of +// code points. Returns false if the input is empty or the code point is not +// valid. There is minimal Unicode error handling: the input should be valid +// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point +bool valid_name_code_point(char32_t input, bool first); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/identifier.h */ #endif /* end file include/idna.h */ @@ -186,6 +206,10 @@ std::string to_unicode(std::string_view input); #ifndef ADA_COMMON_DEFS_H #define ADA_COMMON_DEFS_H +// https://en.cppreference.com/w/cpp/feature_test#Library_features +// detect C++20 features +#include + #ifdef _MSC_VER #define ADA_VISUAL_STUDIO 1 /** @@ -230,13 +254,6 @@ std::string to_unicode(std::string_view input); #define ada_unused #define ada_warn_unused -#ifndef ada_likely -#define ada_likely(x) x -#endif -#ifndef ada_unlikely -#define ada_unlikely(x) x -#endif - #define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push)) #define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) #define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \ @@ -268,13 +285,6 @@ std::string to_unicode(std::string_view input); #define ada_unused __attribute__((unused)) #define ada_warn_unused __attribute__((warn_unused_result)) -#ifndef ada_likely -#define ada_likely(x) __builtin_expect(!!(x), 1) -#endif -#ifndef ada_unlikely -#define ada_unlikely(x) __builtin_expect(!!(x), 0) -#endif - #define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push") // gcc doesn't seem to disable all warnings with all and extra, add warnings // here as necessary @@ -354,52 +364,6 @@ namespace ada { } } // namespace ada -#if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ <= 8 -#define ADA_OLD_GCC 1 -#endif // __GNUC__ <= 8 -#endif // defined(__GNUC__) && !defined(__clang__) - -#if ADA_OLD_GCC -#define ada_constexpr -#else -#define ada_constexpr constexpr -#endif - -#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) -#define ADA_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#elif defined(_WIN32) -#define ADA_IS_BIG_ENDIAN 0 -#else -#if defined(__APPLE__) || \ - defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined - // __ORDER_BIG_ENDIAN__ -#include -#elif defined(sun) || \ - defined(__sun) // defined(__APPLE__) || defined(__FreeBSD__) -#include -#else // defined(__APPLE__) || defined(__FreeBSD__) - -#ifdef __has_include -#if __has_include() -#include -#endif //__has_include() -#endif //__has_include - -#endif // defined(__APPLE__) || defined(__FreeBSD__) - -#ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) -#define ADA_IS_BIG_ENDIAN 0 -#endif - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define ADA_IS_BIG_ENDIAN 0 -#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define ADA_IS_BIG_ENDIAN 1 -#endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - -#endif // defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ - // Unless the programmer has already set ADA_DEVELOPMENT_CHECKS, // we want to set it under debug builds. We detect a debug build // under Visual Studio when the _DEBUG macro is set. Under the other @@ -491,6 +455,13 @@ namespace ada { #define ada_lifetime_bound #endif +#ifdef __cpp_lib_format +#if __cpp_lib_format >= 202110L +#include +#define ADA_HAS_FORMAT 1 +#endif +#endif + #endif // ADA_COMMON_DEFS_H /* end file include/ada/common_defs.h */ #include @@ -503,7 +474,7 @@ namespace ada { * @brief Includes the definitions for unicode character sets. */ namespace ada::character_sets { -ada_really_inline bool bit_at(const uint8_t a[], uint8_t i); +ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i); } // namespace ada::character_sets #endif // ADA_CHARACTER_SETS_H @@ -1012,7 +983,7 @@ constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = { // F8 F9 FA FB FC FD FE FF 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; -ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) { +ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) { return !!(a[i >> 3] & (1 << (i & 7))); } @@ -1028,23 +999,19 @@ ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) { #ifndef ADA_CHECKERS_INL_H #define ADA_CHECKERS_INL_H - -#include +#include #include -#include namespace ada::checkers { -inline bool has_hex_prefix_unsafe(std::string_view input) { +constexpr bool has_hex_prefix_unsafe(std::string_view input) { // This is actually efficient code, see has_hex_prefix for the assembly. - uint32_t value_one = 1; - bool is_little_endian = (reinterpret_cast(&value_one)[0] == 1); - uint16_t word0x{}; - std::memcpy(&word0x, "0x", 2); // we would use bit_cast in C++20 and the - // function could be constexpr. - uint16_t two_first_bytes{}; - std::memcpy(&two_first_bytes, input.data(), 2); - if (is_little_endian) { + constexpr bool is_little_endian = std::endian::native == std::endian::little; + constexpr uint16_t word0x = 0x7830; + uint16_t two_first_bytes = + static_cast(input[0]) | + static_cast((static_cast(input[1]) << 8)); + if constexpr (is_little_endian) { two_first_bytes |= 0x2000; } else { two_first_bytes |= 0x020; @@ -1052,7 +1019,7 @@ inline bool has_hex_prefix_unsafe(std::string_view input) { return two_first_bytes == word0x; } -inline bool has_hex_prefix(std::string_view input) { +constexpr bool has_hex_prefix(std::string_view input) { return input.size() >= 2 && has_hex_prefix_unsafe(input); } @@ -1064,26 +1031,18 @@ constexpr bool is_alpha(char x) noexcept { return (to_lower(x) >= 'a') && (to_lower(x) <= 'z'); } -inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept { +constexpr bool is_windows_drive_letter(std::string_view input) noexcept { return input.size() >= 2 && (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) && ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' || input[2] == '?' || input[2] == '#')); } -inline constexpr bool is_normalized_windows_drive_letter( +constexpr bool is_normalized_windows_drive_letter( std::string_view input) noexcept { return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':')); } -ada_really_inline bool begins_with(std::string_view view, - std::string_view prefix) { - // in C++20, you have view.begins_with(prefix) - // std::equal is constexpr in C++20 - return view.size() >= prefix.size() && - std::equal(prefix.begin(), prefix.end(), view.begin()); -} - } // namespace ada::checkers #endif // ADA_CHECKERS_INL_H @@ -1097,65 +1056,31 @@ ada_really_inline bool begins_with(std::string_view view, #ifndef ADA_LOG_H #define ADA_LOG_H -#include // To enable logging, set ADA_LOGGING to 1: #ifndef ADA_LOGGING #define ADA_LOGGING 0 #endif -namespace ada { - -/** - * Private function used for logging messages. - * @private - */ -template -ada_really_inline void inner_log([[maybe_unused]] T t) { -#if ADA_LOGGING - std::cout << t << std::endl; -#endif -} - -/** - * Private function used for logging messages. - * @private - */ -template -ada_really_inline void inner_log([[maybe_unused]] T t, - [[maybe_unused]] Args... args) { #if ADA_LOGGING - std::cout << t; - inner_log(args...); -#endif -} +#include +#endif // ADA_LOGGING -/** - * Log a message. - * @private - */ -template -ada_really_inline void log([[maybe_unused]] T t, - [[maybe_unused]] Args... args) { -#if ADA_LOGGING - std::cout << "ADA_LOG: " << t; - inner_log(args...); -#endif -} +namespace ada { /** - * Log a message. + * Log a message. If you want to have no overhead when logging is disabled, use + * the ada_log macro. * @private */ -template -ada_really_inline void log([[maybe_unused]] T t) { +template +constexpr ada_really_inline void log([[maybe_unused]] Args... args) { #if ADA_LOGGING - std::cout << "ADA_LOG: " << t << std::endl; -#endif + ((std::cout << "ADA_LOG: ") << ... << args) << std::endl; +#endif // ADA_LOGGING } } // namespace ada #if ADA_LOGGING - #ifndef ada_log #define ada_log(...) \ do { \ @@ -1413,7 +1338,7 @@ struct url_components { * @return true if the offset values are * consistent with a possible URL string */ - [[nodiscard]] bool check_offset_consistency() const noexcept; + [[nodiscard]] constexpr bool check_offset_consistency() const noexcept; /** * Converts a url_components to JSON stringified version. @@ -1421,7 +1346,6 @@ struct url_components { [[nodiscard]] std::string to_string() const; }; // struct url_components - } // namespace ada #endif /* end file include/ada/url_components.h */ @@ -1435,7 +1359,6 @@ struct url_components { #include -#include #include /** @@ -1563,7 +1486,7 @@ struct url_base { * A URL is special if its scheme is a special scheme. A URL is not special if * its scheme is not a special scheme. */ - [[nodiscard]] ada_really_inline bool is_special() const noexcept; + [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept; /** * The origin getter steps are to return the serialization of this's URL's @@ -1640,6 +1563,10 @@ struct url_base { #include #include +#if ADA_DEVELOPMENT_CHECKS +#include +#endif // ADA_DEVELOPMENT_CHECKS + /** * These functions are not part of our public API and may * change at any time. @@ -1716,8 +1643,8 @@ ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept; * Return the substring from input going from index pos to the end. * This function cannot throw. */ -ada_really_inline std::string_view substring(std::string_view input, - size_t pos) noexcept; +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos) noexcept; /** * @private @@ -1730,9 +1657,9 @@ bool overlaps(std::string_view input1, const std::string& input2) noexcept; * Return the substring from input going from index pos1 to the pos2 (non * included). The length of the substring is pos2 - pos1. */ -ada_really_inline std::string_view substring(const std::string& input, - size_t pos1, - size_t pos2) noexcept { +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos1, + size_t pos2) noexcept { #if ADA_DEVELOPMENT_CHECKS if (pos2 < pos1) { std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")" @@ -1740,7 +1667,7 @@ ada_really_inline std::string_view substring(const std::string& input, abort(); } #endif - return std::string_view(input.data() + pos1, pos2 - pos1); + return input.substr(pos1, pos2 - pos1); } /** @@ -1756,14 +1683,14 @@ ada_really_inline void resize(std::string_view& input, size_t pos) noexcept; * and whether a colon was found outside brackets. Used by the host parser. */ ada_really_inline std::pair get_host_delimiter_location( - const bool is_special, std::string_view& view) noexcept; + bool is_special, std::string_view& view) noexcept; /** * @private * Removes leading and trailing C0 control and whitespace characters from * string. */ -ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept; +void trim_c0_whitespace(std::string_view& input) noexcept; /** * @private @@ -1867,8 +1794,8 @@ inline int fast_digit_count(uint32_t x) noexcept { #ifndef ADA_PARSER_H #define ADA_PARSER_H -#include #include +#include /* begin file include/ada/expected.h */ /** @@ -4398,6 +4325,10 @@ void swap(expected &lhs, namespace ada { struct url_aggregator; struct url; +class url_pattern; +struct url_pattern_options; +struct url_pattern_init; +enum class errors : uint8_t; } // namespace ada /** @@ -4411,7 +4342,7 @@ namespace ada::parser { * parameter that can be used to resolve relative URLs. If the base_url is * provided, the user_input is resolved against the base_url. */ -template +template result_type parse_url(std::string_view user_input, const result_type* base_url = nullptr); @@ -4420,7 +4351,7 @@ extern template url_aggregator parse_url( extern template url parse_url(std::string_view user_input, const url* base_url); -template +template result_type parse_url_impl(std::string_view user_input, const result_type* base_url = nullptr); @@ -4428,6 +4359,11 @@ extern template url_aggregator parse_url_impl( std::string_view user_input, const url_aggregator* base_url); extern template url parse_url_impl(std::string_view user_input, const url* base_url); + +tl::expected parse_url_pattern_impl( + std::variant input, + const std::string_view* base_url, const url_pattern_options* options); + } // namespace ada::parser #endif // ADA_PARSER_H @@ -4530,7 +4466,6 @@ constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept { #include -#include #include /** @@ -4691,6 +4626,20 @@ ada_really_inline constexpr bool is_alnum_plus(char c) noexcept; */ ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept; +/** + * @private + * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), + * inclusive. + */ +ada_really_inline constexpr bool is_ascii_digit(char c) noexcept; + +/** + * @private + * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII + * character. + */ +ada_really_inline constexpr bool is_ascii(char32_t c) noexcept; + /** * @private * Checks if the input is a C0 control or space character. @@ -4714,7 +4663,7 @@ ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept; * @details A double-dot path segment must be ".." or an ASCII case-insensitive * match for ".%2e", "%2e.", or "%2e%2e". */ -ada_really_inline ada_constexpr bool is_double_dot_path_segment( +ada_really_inline constexpr bool is_double_dot_path_segment( std::string_view input) noexcept; /** @@ -4811,325 +4760,52 @@ constexpr bool to_lower_ascii(char* input, size_t length) noexcept; #include #include +/* begin file include/ada/url_pattern.h */ +/** + * @file url_pattern.h + * @brief Declaration for the URLPattern implementation. + */ +#ifndef ADA_URL_PATTERN_H +#define ADA_URL_PATTERN_H -namespace ada { +/* begin file include/ada/implementation.h */ +/** + * @file implementation.h + * @brief Definitions for user facing functions for parsing URL and it's + * components. + */ +#ifndef ADA_IMPLEMENTATION_H +#define ADA_IMPLEMENTATION_H +#include +#include + +/* begin file include/ada/url.h */ /** - * @brief Lightweight URL struct. - * - * @details The url_aggregator class aims to minimize temporary memory - * allocation while representing a parsed URL. Internally, it contains a single - * normalized URL (the href), and it makes available the components, mostly - * using std::string_view. + * @file url.h + * @brief Declaration for the URL */ -struct url_aggregator : url_base { - url_aggregator() = default; - url_aggregator(const url_aggregator &u) = default; - url_aggregator(url_aggregator &&u) noexcept = default; - url_aggregator &operator=(url_aggregator &&u) noexcept = default; - url_aggregator &operator=(const url_aggregator &u) = default; - ~url_aggregator() override = default; +#ifndef ADA_URL_H +#define ADA_URL_H - bool set_href(std::string_view input); - bool set_host(std::string_view input); - bool set_hostname(std::string_view input); - bool set_protocol(std::string_view input); - bool set_username(std::string_view input); - bool set_password(std::string_view input); - bool set_port(std::string_view input); - bool set_pathname(std::string_view input); - void set_search(std::string_view input); - void set_hash(std::string_view input); +#include +#include +#include +#include +#include +#include - [[nodiscard]] bool has_valid_domain() const noexcept override; - /** - * The origin getter steps are to return the serialization of this's URL's - * origin. [HTML] - * @return a newly allocated string. - * @see https://url.spec.whatwg.org/#concept-url-origin - */ - [[nodiscard]] std::string get_origin() const noexcept override; - /** - * Return the normalized string. - * This function does not allocate memory. - * It is highly efficient. - * @return a constant reference to the underlying normalized URL. - * @see https://url.spec.whatwg.org/#dom-url-href - * @see https://url.spec.whatwg.org/#concept-url-serializer - */ - [[nodiscard]] inline std::string_view get_href() const noexcept - ada_lifetime_bound; - /** - * The username getter steps are to return this's URL's username. - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-username - */ - [[nodiscard]] std::string_view get_username() const noexcept - ada_lifetime_bound; - /** - * The password getter steps are to return this's URL's password. - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-password - */ - [[nodiscard]] std::string_view get_password() const noexcept - ada_lifetime_bound; - /** - * Return this's URL's port, serialized. - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-port - */ - [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound; - /** - * Return U+0023 (#), followed by this's URL's fragment. - * This function does not allocate memory. - * @return a lightweight std::string_view.. - * @see https://url.spec.whatwg.org/#dom-url-hash - */ - [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound; - /** - * Return url's host, serialized, followed by U+003A (:) and url's port, - * serialized. - * This function does not allocate memory. - * When there is no host, this function returns the empty view. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-host - */ - [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound; - /** - * Return this's URL's host, serialized. - * This function does not allocate memory. - * When there is no host, this function returns the empty view. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-hostname - */ - [[nodiscard]] std::string_view get_hostname() const noexcept - ada_lifetime_bound; - /** - * The pathname getter steps are to return the result of URL path serializing - * this's URL. - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-pathname - */ - [[nodiscard]] std::string_view get_pathname() const noexcept - ada_lifetime_bound; - /** - * Compute the pathname length in bytes without instantiating a view or a - * string. - * @return size of the pathname in bytes - * @see https://url.spec.whatwg.org/#dom-url-pathname - */ - [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept; - /** - * Return U+003F (?), followed by this's URL's query. - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-search - */ - [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound; - /** - * The protocol getter steps are to return this's URL's scheme, followed by - * U+003A (:). - * This function does not allocate memory. - * @return a lightweight std::string_view. - * @see https://url.spec.whatwg.org/#dom-url-protocol - */ - [[nodiscard]] std::string_view get_protocol() const noexcept - ada_lifetime_bound; +/* begin file include/ada/checkers.h */ +/** + * @file checkers.h + * @brief Declarations for URL specific checkers used within Ada. + */ +#ifndef ADA_CHECKERS_H +#define ADA_CHECKERS_H - /** - * A URL includes credentials if its username or password is not the empty - * string. - */ - [[nodiscard]] ada_really_inline bool has_credentials() const noexcept; - /** - * Useful for implementing efficient serialization for the URL. - * - * 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 - * - * Inspired after servo/url - * - * @return a constant reference to the underlying component attribute. - * - * @see - * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31 - */ - [[nodiscard]] ada_really_inline const ada::url_components &get_components() - const noexcept; - /** - * Returns a string representation of this URL. - */ - [[nodiscard]] std::string to_string() const override; - /** - * Returns a string diagram of this URL. - */ - [[nodiscard]] std::string to_diagram() const; - - /** - * Verifies that the parsed URL could be valid. Useful for debugging purposes. - * @return true if the URL is valid, otherwise return true of the offsets are - * possible. - */ - [[nodiscard]] bool validate() const noexcept; - - /** @return true if it has an host but it is the empty string */ - [[nodiscard]] inline bool has_empty_hostname() const noexcept; - /** @return true if it has a host (included an empty host) */ - [[nodiscard]] inline bool has_hostname() const noexcept; - /** @return true if the URL has a non-empty username */ - [[nodiscard]] inline bool has_non_empty_username() const noexcept; - /** @return true if the URL has a non-empty password */ - [[nodiscard]] inline bool has_non_empty_password() const noexcept; - /** @return true if the URL has a (non default) port */ - [[nodiscard]] inline bool has_port() const noexcept; - /** @return true if the URL has a password */ - [[nodiscard]] inline bool has_password() const noexcept; - /** @return true if the URL has a hash component */ - [[nodiscard]] inline bool has_hash() const noexcept override; - /** @return true if the URL has a search component */ - [[nodiscard]] inline bool has_search() const noexcept override; - - inline void clear_port(); - inline void clear_hash(); - inline void clear_search() override; - - private: - friend ada::url_aggregator ada::parser::parse_url( - std::string_view, const ada::url_aggregator *); - friend void ada::helpers::strip_trailing_spaces_from_opaque_path< - ada::url_aggregator>(ada::url_aggregator &url) noexcept; - friend ada::url_aggregator ada::parser::parse_url_impl< - ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *); - friend ada::url_aggregator - ada::parser::parse_url_impl( - std::string_view, const ada::url_aggregator *); - - std::string buffer{}; - url_components components{}; - - /** - * Returns true if neither the search, nor the hash nor the pathname - * have been set. - * @return true if the buffer is ready to receive the path. - */ - [[nodiscard]] ada_really_inline bool is_at_path() const noexcept; - - inline void add_authority_slashes_if_needed() noexcept; - - /** - * To optimize performance, you may indicate how much memory to allocate - * within this instance. - */ - inline void reserve(uint32_t capacity); - - ada_really_inline size_t parse_port( - std::string_view view, bool check_trailing_content) noexcept override; - - ada_really_inline size_t parse_port(std::string_view view) noexcept override { - return this->parse_port(view, false); - } - - /** - * Return true on success. The 'in_place' parameter indicates whether the - * the string_view input is pointing in the buffer. When in_place is false, - * we must nearly always update the buffer. - * @see https://url.spec.whatwg.org/#concept-ipv4-parser - */ - [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place); - - /** - * Return true on success. - * @see https://url.spec.whatwg.org/#concept-ipv6-parser - */ - [[nodiscard]] bool parse_ipv6(std::string_view input); - - /** - * Return true on success. - * @see https://url.spec.whatwg.org/#concept-opaque-host-parser - */ - [[nodiscard]] bool parse_opaque_host(std::string_view input); - - ada_really_inline void parse_path(std::string_view input); - - /** - * A URL cannot have a username/password/port if its host is null or the empty - * string, or its scheme is "file". - */ - [[nodiscard]] inline bool cannot_have_credentials_or_port() const; - - template - bool set_host_or_hostname(std::string_view input); - - ada_really_inline bool parse_host(std::string_view input); - - inline void update_base_authority(std::string_view base_buffer, - const ada::url_components &base); - inline void update_unencoded_base_hash(std::string_view input); - inline void update_base_hostname(std::string_view input); - inline void update_base_search(std::string_view input); - inline void update_base_search(std::string_view input, - const uint8_t *query_percent_encode_set); - inline void update_base_pathname(std::string_view input); - inline void update_base_username(std::string_view input); - inline void append_base_username(std::string_view input); - inline void update_base_password(std::string_view input); - inline void append_base_password(std::string_view input); - inline void update_base_port(uint32_t input); - inline void append_base_pathname(std::string_view input); - [[nodiscard]] inline uint32_t retrieve_base_port() const; - inline void clear_hostname(); - inline void clear_password(); - inline void clear_pathname() override; - [[nodiscard]] inline bool has_dash_dot() const noexcept; - void delete_dash_dot(); - inline void consume_prepared_path(std::string_view input); - template - [[nodiscard]] ada_really_inline bool parse_scheme_with_colon( - std::string_view input); - ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end, - std::string_view input); - [[nodiscard]] inline bool has_authority() const noexcept; - inline void set_protocol_as_file(); - inline void set_scheme(std::string_view new_scheme) noexcept; - /** - * Fast function to set the scheme from a view with a colon in the - * buffer, does not change type. - */ - inline void set_scheme_from_view_with_colon( - std::string_view new_scheme_with_colon) noexcept; - inline void copy_scheme(const url_aggregator &u) noexcept; - -}; // url_aggregator - -inline std::ostream &operator<<(std::ostream &out, const ada::url &u); -} // namespace ada - -#endif -/* end file include/ada/url_aggregator.h */ -/* begin file include/ada/checkers.h */ -/** - * @file checkers.h - * @brief Declarations for URL specific checkers used within Ada. - */ -#ifndef ADA_CHECKERS_H -#define ADA_CHECKERS_H - - -#include #include +#include /** * These functions are not part of our public API and may @@ -5164,12 +4840,12 @@ constexpr bool is_alpha(char x) noexcept; * * @see has_hex_prefix */ -inline bool has_hex_prefix_unsafe(std::string_view input); +constexpr bool has_hex_prefix_unsafe(std::string_view input); /** * @private * Check whether a string starts with 0x or 0X. */ -inline bool has_hex_prefix(std::string_view input); +constexpr bool has_hex_prefix(std::string_view input); /** * @private @@ -5200,20 +4876,13 @@ inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept; inline constexpr bool is_normalized_windows_drive_letter( std::string_view input) noexcept; -/** - * @private - * @warning Will be removed when Ada requires C++20. - */ -ada_really_inline bool begins_with(std::string_view view, - std::string_view prefix); - /** * @private * Returns true if an input is an ipv4 address. It is assumed that the string * does not contain uppercase ASCII characters (the input should have been * lowered cased before calling this function) and is not empty. */ -ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept; +ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept; /** * @private @@ -5243,21 +4912,6 @@ ada_really_inline constexpr bool verify_dns_length( #endif // ADA_CHECKERS_H /* end file include/ada/checkers.h */ -/* begin file include/ada/url.h */ -/** - * @file url.h - * @brief Declaration for the URL - */ -#ifndef ADA_URL_H -#define ADA_URL_H - -#include -#include -#include -#include -#include -#include - namespace ada { @@ -5387,7 +5041,7 @@ struct url : url_base { * @return a newly allocated string. * @see https://url.spec.whatwg.org/#dom-url-pathname */ - [[nodiscard]] std::string_view get_pathname() const noexcept; + [[nodiscard]] constexpr std::string_view get_pathname() const noexcept; /** * Compute the pathname length in bytes without instantiating a view or a @@ -5521,9 +5175,9 @@ struct url : url_base { [[nodiscard]] ada_really_inline ada::url_components get_components() const noexcept; /** @return true if the URL has a hash component */ - [[nodiscard]] inline bool has_hash() const noexcept override; + [[nodiscard]] constexpr bool has_hash() const noexcept override; /** @return true if the URL has a search component */ - [[nodiscard]] inline bool has_search() const noexcept override; + [[nodiscard]] constexpr bool has_search() const noexcept override; private: friend ada::url ada::parser::parse_url(std::string_view, @@ -5540,10 +5194,9 @@ struct url : url_base { inline void update_unencoded_base_hash(std::string_view input); inline void update_base_hostname(std::string_view input); - inline void update_base_search(std::string_view input); inline void update_base_search(std::string_view input, const uint8_t query_percent_encode_set[]); - inline void update_base_search(std::optional input); + inline void update_base_search(std::optional &&input); inline void update_base_pathname(std::string_view input); inline void update_base_username(std::string_view input); inline void update_base_password(std::string_view input); @@ -5599,12 +5252,6 @@ struct url : url_base { return this->parse_port(view, false); } - /** - * Take the scheme from another URL. The scheme string is copied from the - * provided url. - */ - inline void copy_scheme(const ada::url &u); - /** * Parse the host from the provided input. We assume that * the input does not contain spaces or tabs. Control @@ -5618,9 +5265,9 @@ struct url : url_base { template [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input); - inline void clear_pathname() override; - inline void clear_search() override; - inline void set_protocol_as_file(); + constexpr void clear_pathname() override; + constexpr void clear_search() override; + constexpr void set_protocol_as_file(); /** * Parse the path from the provided input. @@ -5645,7 +5292,13 @@ struct url : url_base { * Take the scheme from another URL. The scheme string is moved from the * provided url. */ - inline void copy_scheme(ada::url &&u) noexcept; + constexpr void copy_scheme(ada::url &&u) noexcept; + + /** + * Take the scheme from another URL. The scheme string is copied from the + * provided url. + */ + constexpr void copy_scheme(const ada::url &u); }; // struct url @@ -5655,52 +5308,761 @@ inline std::ostream &operator<<(std::ostream &out, const ada::url &u); #endif // ADA_URL_H /* end file include/ada/url.h */ -#include -#include -#if ADA_REGULAR_VISUAL_STUDIO -#include -#endif // ADA_REGULAR_VISUAL_STUDIO - namespace ada { +enum class errors : uint8_t { type_error }; -[[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept { - return type != ada::scheme::NOT_SPECIAL; -} +template +using result = tl::expected; -[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept { - return ada::scheme::get_special_port(type); -} +/** + * The URL parser takes a scalar value string input, with an optional null or + * base URL base (default null). The parser assumes the input is a valid ASCII + * or UTF-8 string. + * + * @param input the string input to analyze (must be valid ASCII or UTF-8) + * @param base_url the optional URL input to use as a base url. + * @return a parsed URL. + */ +template +ada_warn_unused ada::result parse( + std::string_view input, const result_type* base_url = nullptr); -[[nodiscard]] ada_really_inline uint16_t -url_base::scheme_default_port() const noexcept { - return scheme::get_special_port(type); -} +extern template ada::result parse(std::string_view input, + const url* base_url); +extern template ada::result parse( + std::string_view input, const url_aggregator* base_url); -} // namespace ada +/** + * Verifies whether the URL strings can be parsed. The function assumes + * that the inputs are valid ASCII or UTF-8 strings. + * @see https://url.spec.whatwg.org/#dom-url-canparse + * @return If URL can be parsed or not. + */ +bool can_parse(std::string_view input, + const std::string_view* base_input = nullptr); -#endif // ADA_URL_BASE_INL_H -/* end file include/ada/url_base-inl.h */ -/* begin file include/ada/url-inl.h */ /** - * @file url-inl.h - * @brief Definitions for the URL + * Implementation of the URL pattern parsing algorithm. + * @see https://urlpattern.spec.whatwg.org + * + * @param input valid UTF-8 string or URLPatternInit struct + * @param base_url an optional valid UTF-8 string + * @param options an optional url_pattern_options struct + * @return url_pattern instance */ -#ifndef ADA_URL_INL_H -#define ADA_URL_INL_H +ada_warn_unused tl::expected parse_url_pattern( + std::variant input, + const std::string_view* base_url = nullptr, + const url_pattern_options* options = nullptr); + +/** + * Computes a href string from a file path. The function assumes + * that the input is a valid ASCII or UTF-8 string. + * @return a href string (starts with file:://) + */ +std::string href_from_file(std::string_view path); +} // namespace ada +#endif // ADA_IMPLEMENTATION_H +/* end file include/ada/implementation.h */ -#include +#include #include -#if ADA_REGULAR_VISUAL_STUDIO -#include -#endif // ADA_REGULAR_VISUAL_STUDIO +#include +#include +#include namespace ada { -[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept { - return !username.empty() || !password.empty(); -} -[[nodiscard]] ada_really_inline bool url::has_port() const noexcept { - return port.has_value(); + +namespace parser { +template +tl::expected parse_url_pattern_impl( + std::variant input, + const std::string_view* base_url, const url_pattern_options* options); +} + +// Important: C++20 allows us to use concept rather than `using` or `typedef +// and allows functions with second argument, which is optional (using either +// std::nullopt or a parameter with default value) +template +concept url_pattern_encoding_callback = requires(F f, std::string_view sv) { + { f(sv) } -> std::same_as>; +}; + +// A structure providing matching patterns for individual components +// of a URL. When a URLPattern is created, or when a URLPattern is +// used to match or test against a URL, the input can be given as +// either a string or a URLPatternInit struct. If a string is given, +// it will be parsed to create a URLPatternInit. The URLPatternInit +// API is defined as part of the URLPattern specification. +struct url_pattern_init { + // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit + static tl::expected process( + url_pattern_init init, std::string_view type, + std::optional protocol = std::nullopt, + std::optional username = std::nullopt, + std::optional password = std::nullopt, + std::optional hostname = std::nullopt, + std::optional port = std::nullopt, + std::optional pathname = std::nullopt, + std::optional search = std::nullopt, + std::optional hash = std::nullopt); + + // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init + static tl::expected process_protocol( + std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-username-for-init + static tl::expected process_username( + std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-password-for-init + static tl::expected process_password( + std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init + static tl::expected process_hostname( + std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-port-for-init + static tl::expected process_port( + std::string_view port, std::string_view protocol, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init + static tl::expected process_pathname( + std::string_view value, std::string_view protocol, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-search-for-init + static tl::expected process_search( + std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init + static tl::expected process_hash(std::string_view value, + std::string_view type); + + [[nodiscard]] std::string to_string() const; + + bool operator==(const url_pattern_init&) const; + + std::optional protocol{}; + std::optional username{}; + std::optional password{}; + std::optional hostname{}; + std::optional port{}; + std::optional pathname{}; + std::optional search{}; + std::optional hash{}; + std::optional base_url{}; +}; + +enum class url_pattern_part_type : uint8_t { + // The part represents a simple fixed text string. + FIXED_TEXT, + // The part represents a matching group with a custom regular expression. + REGEXP, + // The part represents a matching group that matches code points up to the + // next separator code point. This is typically used for a named group like + // ":foo" that does not have a custom regular expression. + SEGMENT_WILDCARD, + // The part represents a matching group that greedily matches all code points. + // This is typically used for the "*" wildcard matching group. + FULL_WILDCARD, +}; + +enum class url_pattern_part_modifier : uint8_t { + // The part does not have a modifier. + NONE, + // The part has an optional modifier indicated by the U+003F (?) code point. + OPTIONAL, + // The part has a "zero or more" modifier indicated by the U+002A (*) code + // point. + ZERO_OR_MORE, + // The part has a "one or more" modifier indicated by the U+002B (+) code + // point. + ONE_OR_MORE, +}; + +// @see https://urlpattern.spec.whatwg.org/#part +class url_pattern_part { + public: + url_pattern_part(url_pattern_part_type _type, std::string&& _value, + url_pattern_part_modifier _modifier) + : type(_type), value(_value), modifier(_modifier) {} + + url_pattern_part(url_pattern_part_type _type, std::string&& _value, + url_pattern_part_modifier _modifier, std::string&& _name, + std::string&& _prefix, std::string&& _suffix) + : type(_type), + value(_value), + modifier(_modifier), + name(_name), + prefix(_prefix), + suffix(_suffix) {} + // A part has an associated type, a string, which must be set upon creation. + url_pattern_part_type type; + // A part has an associated value, a string, which must be set upon creation. + std::string value; + // A part has an associated modifier a string, which must be set upon + // creation. + url_pattern_part_modifier modifier; + // A part has an associated name, a string, initially the empty string. + std::string name{}; + // A part has an associated prefix, a string, initially the empty string. + std::string prefix{}; + // A part has an associated suffix, a string, initially the empty string. + std::string suffix{}; + + inline bool is_regexp() const noexcept; +}; + +// @see https://urlpattern.spec.whatwg.org/#options-header +struct url_pattern_compile_component_options { + url_pattern_compile_component_options() = default; + explicit url_pattern_compile_component_options( + std::optional new_delimiter = std::nullopt, + std::optional new_prefix = std::nullopt) + : delimiter(new_delimiter), prefix(new_prefix) {} + + std::string_view get_delimiter() const ada_warn_unused; + std::string_view get_prefix() const ada_warn_unused; + + // @see https://urlpattern.spec.whatwg.org/#options-ignore-case + bool ignore_case = false; + + static url_pattern_compile_component_options DEFAULT; + static url_pattern_compile_component_options HOSTNAME; + static url_pattern_compile_component_options PATHNAME; + + private: + // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point + std::optional delimiter{}; + // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point + std::optional prefix{}; +}; + +// A struct providing the URLPattern matching results for a single +// URL component. The URLPatternComponentResult is only ever used +// as a member attribute of a URLPatternResult struct. The +// URLPatternComponentResult API is defined as part of the URLPattern +// specification. +struct url_pattern_component_result { + std::string input; + std::unordered_map groups; + + bool operator==(const url_pattern_component_result&) const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_component_result& result, + std::ostream* os) { + *os << "input: '" << result.input << "', group: "; + for (const auto& group : result.groups) { + *os << "(" << group.first << ", " << group.second << ") "; + } + } +#endif // ADA_TESTING +}; + +class url_pattern_component { + public: + url_pattern_component() = default; + + // This function explicitly takes a std::string because it is moved. + // To avoid unnecessary copy, move each value while calling the constructor. + url_pattern_component(std::string&& new_pattern, std::regex&& new_regexp, + std::regex_constants::syntax_option_type new_flags, + std::vector&& new_group_name_list, + bool new_has_regexp_groups) + : regexp(std::move(new_regexp)), + pattern(std::move(new_pattern)), + flags(new_flags), + group_name_list(new_group_name_list), + has_regexp_groups(new_has_regexp_groups) {} + + // @see https://urlpattern.spec.whatwg.org/#compile-a-component + template + static tl::expected compile( + std::string_view input, F& encoding_callback, + url_pattern_compile_component_options& options); + + // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result + url_pattern_component_result create_component_match_result( + std::string_view input, const std::smatch& exec_result); + + std::string to_string() const; + + std::regex regexp{}; + std::string pattern{}; + std::regex_constants::syntax_option_type flags = std::regex::ECMAScript; + std::vector group_name_list{}; + bool has_regexp_groups = false; +}; + +using url_pattern_input = std::variant; + +// A struct providing the URLPattern matching results for all +// components of a URL. The URLPatternResult API is defined as +// part of the URLPattern specification. +struct url_pattern_result { + std::vector inputs; + url_pattern_component_result protocol; + url_pattern_component_result username; + url_pattern_component_result password; + url_pattern_component_result hostname; + url_pattern_component_result port; + url_pattern_component_result pathname; + url_pattern_component_result search; + url_pattern_component_result hash; +}; + +struct url_pattern_options { + bool ignore_case = false; + + std::string to_string() const; +}; + +// URLPattern is a Web Platform standard API for matching URLs against a +// pattern syntax (think of it as a regular expression for URLs). It is +// defined in https://wicg.github.io/urlpattern. +// More information about the URL Pattern syntax can be found at +// https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API +class url_pattern { + public: + url_pattern() = default; + explicit url_pattern(std::optional&& input, + std::optional&& base_url, + std::optional&& options); + + /** + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec + */ + result> exec(const url_pattern_input& input, + std::string_view* base_url); + + /** + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test + */ + result test(const url_pattern_input& input, std::string_view* base_url); + + /** + * @see https://urlpattern.spec.whatwg.org/#url-pattern-match + * This function expects a valid UTF-8 string if input is a string. + */ + result> match( + const url_pattern_input& input, std::string_view* base_url_string); + + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol + std::string_view get_protocol() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username + std::string_view get_username() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password + std::string_view get_password() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname + std::string_view get_hostname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port + std::string_view get_port() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname + std::string_view get_pathname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search + std::string_view get_search() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash + std::string_view get_hash() const ada_lifetime_bound; + + // If ignoreCase is true, the JavaScript regular expression created for each + // pattern must use the `vi` flag. Otherwise, they must use the `v` flag. + bool ignore_case() const; + + // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups + bool has_regexp_groups() const; + + std::string to_string() const; + + url_pattern_component protocol_component{}; + url_pattern_component username_component{}; + url_pattern_component password_component{}; + url_pattern_component hostname_component{}; + url_pattern_component port_component{}; + url_pattern_component pathname_component{}; + url_pattern_component search_component{}; + url_pattern_component hash_component{}; + bool ignore_case_ = false; + + template + friend tl::expected parser::parse_url_pattern_impl( + std::variant input, + const std::string_view* base_url, const url_pattern_options* options); +}; + +} // namespace ada + +#endif +/* end file include/ada/url_pattern.h */ + +namespace ada { + +/** + * @brief Lightweight URL struct. + * + * @details The url_aggregator class aims to minimize temporary memory + * allocation while representing a parsed URL. Internally, it contains a single + * normalized URL (the href), and it makes available the components, mostly + * using std::string_view. + */ +struct url_aggregator : url_base { + url_aggregator() = default; + url_aggregator(const url_aggregator &u) = default; + url_aggregator(url_aggregator &&u) noexcept = default; + url_aggregator &operator=(url_aggregator &&u) noexcept = default; + url_aggregator &operator=(const url_aggregator &u) = default; + ~url_aggregator() override = default; + + bool set_href(std::string_view input); + bool set_host(std::string_view input); + bool set_hostname(std::string_view input); + bool set_protocol(std::string_view input); + bool set_username(std::string_view input); + bool set_password(std::string_view input); + bool set_port(std::string_view input); + bool set_pathname(std::string_view input); + void set_search(std::string_view input); + void set_hash(std::string_view input); + + [[nodiscard]] bool has_valid_domain() const noexcept override; + /** + * The origin getter steps are to return the serialization of this's URL's + * origin. [HTML] + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] std::string get_origin() const noexcept override; + /** + * Return the normalized string. + * This function does not allocate memory. + * It is highly efficient. + * @return a constant reference to the underlying normalized URL. + * @see https://url.spec.whatwg.org/#dom-url-href + * @see https://url.spec.whatwg.org/#concept-url-serializer + */ + [[nodiscard]] constexpr std::string_view get_href() const noexcept + ada_lifetime_bound; + /** + * The username getter steps are to return this's URL's username. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + [[nodiscard]] std::string_view get_username() const noexcept + ada_lifetime_bound; + /** + * The password getter steps are to return this's URL's password. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + [[nodiscard]] std::string_view get_password() const noexcept + ada_lifetime_bound; + /** + * Return this's URL's port, serialized. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound; + /** + * Return U+0023 (#), followed by this's URL's fragment. + * This function does not allocate memory. + * @return a lightweight std::string_view.. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound; + /** + * Return url's host, serialized, followed by U+003A (:) and url's port, + * serialized. + * This function does not allocate memory. + * When there is no host, this function returns the empty view. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound; + /** + * Return this's URL's host, serialized. + * This function does not allocate memory. + * When there is no host, this function returns the empty view. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + [[nodiscard]] std::string_view get_hostname() const noexcept + ada_lifetime_bound; + /** + * The pathname getter steps are to return the result of URL path serializing + * this's URL. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] constexpr std::string_view get_pathname() const noexcept + ada_lifetime_bound; + /** + * Compute the pathname length in bytes without instantiating a view or a + * string. + * @return size of the pathname in bytes + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept; + /** + * Return U+003F (?), followed by this's URL's query. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound; + /** + * The protocol getter steps are to return this's URL's scheme, followed by + * U+003A (:). + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + [[nodiscard]] std::string_view get_protocol() const noexcept + ada_lifetime_bound; + + /** + * A URL includes credentials if its username or password is not the empty + * string. + */ + [[nodiscard]] ada_really_inline constexpr bool has_credentials() + const noexcept; + + /** + * Useful for implementing efficient serialization for the URL. + * + * 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 + * + * Inspired after servo/url + * + * @return a constant reference to the underlying component attribute. + * + * @see + * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31 + */ + [[nodiscard]] ada_really_inline const url_components &get_components() + const noexcept; + /** + * Returns a string representation of this URL. + */ + [[nodiscard]] std::string to_string() const override; + /** + * Returns a string diagram of this URL. + */ + [[nodiscard]] std::string to_diagram() const; + + /** + * Verifies that the parsed URL could be valid. Useful for debugging purposes. + * @return true if the URL is valid, otherwise return true of the offsets are + * possible. + */ + [[nodiscard]] constexpr bool validate() const noexcept; + + /** @return true if it has an host but it is the empty string */ + [[nodiscard]] constexpr bool has_empty_hostname() const noexcept; + /** @return true if it has a host (included an empty host) */ + [[nodiscard]] constexpr bool has_hostname() const noexcept; + /** @return true if the URL has a non-empty username */ + [[nodiscard]] constexpr bool has_non_empty_username() const noexcept; + /** @return true if the URL has a non-empty password */ + [[nodiscard]] constexpr bool has_non_empty_password() const noexcept; + /** @return true if the URL has a (non default) port */ + [[nodiscard]] constexpr bool has_port() const noexcept; + /** @return true if the URL has a password */ + [[nodiscard]] constexpr bool has_password() const noexcept; + /** @return true if the URL has a hash component */ + [[nodiscard]] constexpr bool has_hash() const noexcept override; + /** @return true if the URL has a search component */ + [[nodiscard]] constexpr bool has_search() const noexcept override; + + inline void clear_port(); + inline void clear_hash(); + inline void clear_search() override; + + private: + // helper methods + friend void helpers::strip_trailing_spaces_from_opaque_path( + url_aggregator &url) noexcept; + // parse_url methods + friend url_aggregator parser::parse_url( + std::string_view, const url_aggregator *); + + friend url_aggregator parser::parse_url_impl( + std::string_view, const url_aggregator *); + friend url_aggregator parser::parse_url_impl( + std::string_view, const url_aggregator *); + // url_pattern methods + friend tl::expected parse_url_pattern_impl( + std::variant input, + const std::string_view *base_url, const url_pattern_options *options); + + std::string buffer{}; + url_components components{}; + + /** + * Returns true if neither the search, nor the hash nor the pathname + * have been set. + * @return true if the buffer is ready to receive the path. + */ + [[nodiscard]] ada_really_inline bool is_at_path() const noexcept; + + inline void add_authority_slashes_if_needed() noexcept; + + /** + * To optimize performance, you may indicate how much memory to allocate + * within this instance. + */ + constexpr void reserve(uint32_t capacity); + + ada_really_inline size_t parse_port( + std::string_view view, bool check_trailing_content) noexcept override; + + ada_really_inline size_t parse_port(std::string_view view) noexcept override { + return this->parse_port(view, false); + } + + /** + * Return true on success. The 'in_place' parameter indicates whether the + * the string_view input is pointing in the buffer. When in_place is false, + * we must nearly always update the buffer. + * @see https://url.spec.whatwg.org/#concept-ipv4-parser + */ + [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv6-parser + */ + [[nodiscard]] bool parse_ipv6(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + [[nodiscard]] bool parse_opaque_host(std::string_view input); + + ada_really_inline void parse_path(std::string_view input); + + /** + * A URL cannot have a username/password/port if its host is null or the empty + * string, or its scheme is "file". + */ + [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const; + + template + bool set_host_or_hostname(std::string_view input); + + ada_really_inline bool parse_host(std::string_view input); + + inline void update_base_authority(std::string_view base_buffer, + const url_components &base); + inline void update_unencoded_base_hash(std::string_view input); + inline void update_base_hostname(std::string_view input); + inline void update_base_search(std::string_view input); + inline void update_base_search(std::string_view input, + const uint8_t *query_percent_encode_set); + inline void update_base_pathname(std::string_view input); + inline void update_base_username(std::string_view input); + inline void append_base_username(std::string_view input); + inline void update_base_password(std::string_view input); + inline void append_base_password(std::string_view input); + inline void update_base_port(uint32_t input); + inline void append_base_pathname(std::string_view input); + [[nodiscard]] inline uint32_t retrieve_base_port() const; + constexpr void clear_hostname(); + constexpr void clear_password(); + constexpr void clear_pathname() override; + [[nodiscard]] constexpr bool has_dash_dot() const noexcept; + void delete_dash_dot(); + inline void consume_prepared_path(std::string_view input); + template + [[nodiscard]] ada_really_inline bool parse_scheme_with_colon( + std::string_view input); + ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end, + std::string_view input); + [[nodiscard]] constexpr bool has_authority() const noexcept; + constexpr void set_protocol_as_file(); + inline void set_scheme(std::string_view new_scheme) noexcept; + /** + * Fast function to set the scheme from a view with a colon in the + * buffer, does not change type. + */ + inline void set_scheme_from_view_with_colon( + std::string_view new_scheme_with_colon) noexcept; + inline void copy_scheme(const url_aggregator &u) noexcept; + + inline void update_host_to_base_host(const std::string_view input) noexcept; + +}; // url_aggregator + +inline std::ostream &operator<<(std::ostream &out, const url &u); +} // namespace ada + +#endif +/* end file include/ada/url_aggregator.h */ + +#include +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { + +[[nodiscard]] ada_really_inline constexpr bool url_base::is_special() + const noexcept { + return type != ada::scheme::NOT_SPECIAL; +} + +[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept { + return ada::scheme::get_special_port(type); +} + +[[nodiscard]] ada_really_inline uint16_t +url_base::scheme_default_port() const noexcept { + return scheme::get_special_port(type); +} + +} // namespace ada + +#endif // ADA_URL_BASE_INL_H +/* end file include/ada/url_base-inl.h */ +/* begin file include/ada/url-inl.h */ +/** + * @file url-inl.h + * @brief Definitions for the URL + */ +#ifndef ADA_URL_INL_H +#define ADA_URL_INL_H + + +#include +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { +[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept { + return !username.empty() || !password.empty(); +} +[[nodiscard]] ada_really_inline bool url::has_port() const noexcept { + return port.has_value(); } [[nodiscard]] inline bool url::cannot_have_credentials_or_port() const { return !host.has_value() || host.value().empty() || @@ -5723,6 +6085,10 @@ inline std::ostream &operator<<(std::ostream &out, const ada::url &u) { return path.size(); } +[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept { + return path; +} + [[nodiscard]] ada_really_inline ada::url_components url::get_components() const noexcept { url_components out{}; @@ -5761,7 +6127,7 @@ inline std::ostream &operator<<(std::ostream &out, const ada::url &u) { out.host_start = out.protocol_end; out.host_end = out.host_start; - if (!has_opaque_path && checkers::begins_with(path, "//")) { + if (!has_opaque_path && path.starts_with("//")) { // If url's host is null, url does not have an opaque path, url's path's // size is greater than 1, and url's path[0] is the empty string, then // append U+002F (/) followed by U+002E (.) to output. @@ -5808,8 +6174,8 @@ inline void url::update_base_search(std::string_view input, query = ada::unicode::percent_encode(input, query_percent_encode_set); } -inline void url::update_base_search(std::optional input) { - query = input; +inline void url::update_base_search(std::optional &&input) { + query = std::move(input); } inline void url::update_base_pathname(const std::string_view input) { @@ -5828,19 +6194,19 @@ inline void url::update_base_port(std::optional input) { port = input; } -inline void url::clear_pathname() { path.clear(); } +constexpr void url::clear_pathname() { path.clear(); } -inline void url::clear_search() { query = std::nullopt; } +constexpr void url::clear_search() { query = std::nullopt; } -[[nodiscard]] inline bool url::has_hash() const noexcept { +[[nodiscard]] constexpr bool url::has_hash() const noexcept { return hash.has_value(); } -[[nodiscard]] inline bool url::has_search() const noexcept { +[[nodiscard]] constexpr bool url::has_search() const noexcept { return query.has_value(); } -inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; } +constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; } inline void url::set_scheme(std::string &&new_scheme) noexcept { type = ada::scheme::get_scheme_type(new_scheme); @@ -5850,12 +6216,12 @@ inline void url::set_scheme(std::string &&new_scheme) noexcept { } } -inline void url::copy_scheme(ada::url &&u) noexcept { +constexpr void url::copy_scheme(ada::url &&u) noexcept { non_special_scheme = u.non_special_scheme; type = u.type; } -inline void url::copy_scheme(const ada::url &u) { +constexpr void url::copy_scheme(const ada::url &u) { non_special_scheme = u.non_special_scheme; type = u.type; } @@ -5876,7 +6242,7 @@ inline void url::copy_scheme(const ada::url &u) { if (port.has_value()) { output += ":" + get_port(); } - } else if (!has_opaque_path && checkers::begins_with(path, "//")) { + } else if (!has_opaque_path && path.starts_with("//")) { // If url's host is null, url does not have an opaque path, url's path's // size is greater than 1, and url's path[0] is the empty string, then // append U+002F (/) followed by U+002E (.) to output. @@ -5908,7 +6274,7 @@ ada_really_inline size_t url::parse_port(std::string_view view, return 0; } ada_log("parse_port: ", parsed_port); - const size_t consumed = size_t(r.ptr - view.data()); + const auto consumed = size_t(r.ptr - view.data()); ada_log("parse_port: consumed ", consumed); if (check_trailing_content) { is_valid &= @@ -5921,9 +6287,8 @@ ada_really_inline size_t url::parse_port(std::string_view view, auto default_port = scheme_default_port(); bool is_port_valid = (default_port == 0 && parsed_port == 0) || (default_port != parsed_port); - port = (r.ec == std::errc() && is_port_valid) - ? std::optional(parsed_port) - : std::nullopt; + port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port) + : std::nullopt; } return consumed; } @@ -5932,6 +6297,96 @@ ada_really_inline size_t url::parse_port(std::string_view view, #endif // ADA_URL_H /* end file include/ada/url-inl.h */ +/* begin file include/ada/url_components-inl.h */ +/** + * @file url_components.h + * @brief Declaration for the URL Components + */ +#ifndef ADA_URL_COMPONENTS_INL_H +#define ADA_URL_COMPONENTS_INL_H + + +namespace ada { + +[[nodiscard]] constexpr bool url_components::check_offset_consistency() + const noexcept { + /** + * 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 + */ + // These conditions can be made more strict. + uint32_t index = 0; + + if (protocol_end == url_components::omitted) { + return false; + } + if (protocol_end < index) { + return false; + } + index = protocol_end; + + if (username_end == url_components::omitted) { + return false; + } + if (username_end < index) { + return false; + } + index = username_end; + + if (host_start == url_components::omitted) { + return false; + } + if (host_start < index) { + return false; + } + index = host_start; + + if (port != url_components::omitted) { + if (port > 0xffff) { + return false; + } + uint32_t port_length = helpers::fast_digit_count(port) + 1; + if (index + port_length < index) { + return false; + } + index += port_length; + } + + if (pathname_start == url_components::omitted) { + return false; + } + if (pathname_start < index) { + return false; + } + index = pathname_start; + + if (search_start != url_components::omitted) { + if (search_start < index) { + return false; + } + index = search_start; + } + + if (hash_start != url_components::omitted) { + if (hash_start < index) { + return false; + } + } + + return true; +} + +} // namespace ada +#endif +/* end file include/ada/url_components-inl.h */ /* begin file include/ada/url_aggregator-inl.h */ /** * @file url_aggregator-inl.h @@ -5947,7 +6402,6 @@ ada_really_inline size_t url::parse_port(std::string_view view, */ #ifndef ADA_UNICODE_INL_H #define ADA_UNICODE_INL_H -#include /** * Unicode operations. These functions are not part of our public API and may @@ -5960,11 +6414,32 @@ ada_really_inline size_t url::parse_port(std::string_view view, namespace ada::unicode { ada_really_inline size_t percent_encode_index(const std::string_view input, const uint8_t character_set[]) { - return std::distance( - input.begin(), - std::find_if(input.begin(), input.end(), [character_set](const char c) { - return character_sets::bit_at(character_set, c); - })); + const char* data = input.data(); + const size_t size = input.size(); + + // Process 8 bytes at a time using unrolled loop + size_t i = 0; + for (; i + 8 <= size; i += 8) { + unsigned char chunk[8]; + std::memcpy(&chunk, data + i, + 8); // entices compiler to unconditionally process 8 characters + + // Check 8 characters at once + for (size_t j = 0; j < 8; j++) { + if (character_sets::bit_at(character_set, chunk[j])) { + return i + j; + } + } + } + + // Handle remaining bytes + for (; i < size; i++) { + if (character_sets::bit_at(character_set, data[i])) { + return i; + } + } + + return size; } } // namespace ada::unicode @@ -5982,7 +6457,7 @@ inline void url_aggregator::update_base_authority( base.protocol_end, base.host_start - base.protocol_end); ada_log("url_aggregator::update_base_authority ", input); - bool input_starts_with_dash = checkers::begins_with(input, "//"); + bool input_starts_with_dash = input.starts_with("//"); uint32_t diff = components.host_start - components.protocol_end; buffer.erase(components.protocol_end, @@ -6222,9 +6697,8 @@ inline void url_aggregator::update_base_pathname(const std::string_view input) { ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); ADA_ASSERT_TRUE(validate()); - const bool begins_with_dashdash = checkers::begins_with(input, "//"); + const bool begins_with_dashdash = input.starts_with("//"); if (!begins_with_dashdash && has_dash_dot()) { - ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram()); // We must delete the ./ delete_dash_dot(); } @@ -6247,8 +6721,6 @@ inline void url_aggregator::update_base_pathname(const std::string_view input) { if (components.hash_start != url_components::omitted) { components.hash_start += difference; } - ada_log("url_aggregator::update_base_pathname end '", input, "' [", - input.size(), " bytes] \n", to_diagram()); ADA_ASSERT_TRUE(validate()); } @@ -6367,8 +6839,8 @@ inline void url_aggregator::append_base_username(const std::string_view input) { ADA_ASSERT_TRUE(validate()); } -inline void url_aggregator::clear_password() { - ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram()); +constexpr void url_aggregator::clear_password() { + ada_log("url_aggregator::clear_password ", to_string()); ADA_ASSERT_TRUE(validate()); if (!has_password()) { return; @@ -6589,7 +7061,7 @@ inline void url_aggregator::clear_hash() { ADA_ASSERT_TRUE(validate()); } -inline void url_aggregator::clear_pathname() { +constexpr void url_aggregator::clear_pathname() { ada_log("url_aggregator::clear_pathname"); ADA_ASSERT_TRUE(validate()); uint32_t ending_index = uint32_t(buffer.size()); @@ -6624,7 +7096,7 @@ inline void url_aggregator::clear_pathname() { ada_log("url_aggregator::clear_pathname completed, running checks... ok"); } -inline void url_aggregator::clear_hostname() { +constexpr void url_aggregator::clear_hostname() { ada_log("url_aggregator::clear_hostname"); ADA_ASSERT_TRUE(validate()); if (!has_authority()) { @@ -6661,22 +7133,22 @@ inline void url_aggregator::clear_hostname() { ADA_ASSERT_TRUE(validate()); } -[[nodiscard]] inline bool url_aggregator::has_hash() const noexcept { +[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept { ada_log("url_aggregator::has_hash"); return components.hash_start != url_components::omitted; } -[[nodiscard]] inline bool url_aggregator::has_search() const noexcept { +[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept { ada_log("url_aggregator::has_search"); return components.search_start != url_components::omitted; } -ada_really_inline bool url_aggregator::has_credentials() const noexcept { +constexpr bool url_aggregator::has_credentials() const noexcept { ada_log("url_aggregator::has_credentials"); return has_non_empty_username() || has_non_empty_password(); } -inline bool url_aggregator::cannot_have_credentials_or_port() const { +constexpr bool url_aggregator::cannot_have_credentials_or_port() const { ada_log("url_aggregator::cannot_have_credentials_or_port"); return type == ada::scheme::type::FILE || components.host_start == components.host_end; @@ -6687,7 +7159,8 @@ url_aggregator::get_components() const noexcept { return components; } -[[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept { +[[nodiscard]] constexpr bool ada::url_aggregator::has_authority() + const noexcept { ada_log("url_aggregator::has_authority"); // Performance: instead of doing this potentially expensive check, we could // have a boolean in the struct. @@ -6722,28 +7195,28 @@ inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept { ADA_ASSERT_TRUE(validate()); } -inline void ada::url_aggregator::reserve(uint32_t capacity) { +constexpr void ada::url_aggregator::reserve(uint32_t capacity) { buffer.reserve(capacity); } -inline bool url_aggregator::has_non_empty_username() const noexcept { +constexpr bool url_aggregator::has_non_empty_username() const noexcept { ada_log("url_aggregator::has_non_empty_username"); return components.protocol_end + 2 < components.username_end; } -inline bool url_aggregator::has_non_empty_password() const noexcept { +constexpr bool url_aggregator::has_non_empty_password() const noexcept { ada_log("url_aggregator::has_non_empty_password"); return components.host_start - components.username_end > 0; } -inline bool url_aggregator::has_password() const noexcept { +constexpr bool url_aggregator::has_password() const noexcept { ada_log("url_aggregator::has_password"); // This function does not care about the length of the password return components.host_start > components.username_end && buffer[components.username_end] == ':'; } -inline bool url_aggregator::has_empty_hostname() const noexcept { +constexpr bool url_aggregator::has_empty_hostname() const noexcept { if (!has_hostname()) { return false; } @@ -6756,18 +7229,18 @@ inline bool url_aggregator::has_empty_hostname() const noexcept { return components.username_end != components.host_start; } -inline bool url_aggregator::has_hostname() const noexcept { +constexpr bool url_aggregator::has_hostname() const noexcept { return has_authority(); } -inline bool url_aggregator::has_port() const noexcept { +constexpr bool url_aggregator::has_port() const noexcept { ada_log("url_aggregator::has_port"); // A URL cannot have a username/password/port if its host is null or the empty // string, or its scheme is "file". return has_hostname() && components.pathname_start != components.host_end; } -[[nodiscard]] inline bool url_aggregator::has_dash_dot() const noexcept { +[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept { // If url's host is null, url does not have an opaque path, url's path's size // is greater than 1, and url's path[0] is the empty string, then append // U+002F (/) followed by U+002E (.) to output. @@ -6799,8 +7272,8 @@ inline bool url_aggregator::has_port() const noexcept { buffer[components.host_end + 1] == '.'; } -[[nodiscard]] inline std::string_view url_aggregator::get_href() const noexcept - ada_lifetime_bound { +[[nodiscard]] constexpr std::string_view url_aggregator::get_href() + const noexcept ada_lifetime_bound { ada_log("url_aggregator::get_href"); return buffer; } @@ -6844,7 +7317,7 @@ ada_really_inline size_t url_aggregator::parse_port( return consumed; } -inline void url_aggregator::set_protocol_as_file() { +constexpr void url_aggregator::set_protocol_as_file() { ada_log("url_aggregator::set_protocol_as_file "); ADA_ASSERT_TRUE(validate()); type = ada::scheme::type::FILE; @@ -6866,18 +7339,225 @@ inline void url_aggregator::set_protocol_as_file() { components.host_end += new_difference; components.pathname_start += new_difference; if (components.search_start != url_components::omitted) { - components.search_start += new_difference; + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept { + if (!is_valid) { + return true; + } + if (!components.check_offset_consistency()) { + ada_log("url_aggregator::validate inconsistent components \n", + to_diagram()); + return false; + } + // We have a credible components struct, but let us investivate more + // carefully: + /** + * 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 + */ + if (components.protocol_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram()); + return false; + } + if (components.username_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted username_end \n", to_diagram()); + return false; + } + if (components.host_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_start \n", to_diagram()); + return false; + } + if (components.host_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_end \n", to_diagram()); + return false; + } + if (components.pathname_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram()); + return false; + } + + if (components.protocol_end > buffer.size()) { + ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram()); + return false; + } + if (components.username_end > buffer.size()) { + ada_log("url_aggregator::validate username_end overflow \n", to_diagram()); + return false; + } + if (components.host_start > buffer.size()) { + ada_log("url_aggregator::validate host_start overflow \n", to_diagram()); + return false; + } + if (components.host_end > buffer.size()) { + ada_log("url_aggregator::validate host_end overflow \n", to_diagram()); + return false; + } + if (components.pathname_start > buffer.size()) { + ada_log("url_aggregator::validate pathname_start overflow \n", + to_diagram()); + return false; + } + + if (components.protocol_end > 0) { + if (buffer[components.protocol_end - 1] != ':') { + ada_log( + "url_aggregator::validate missing : at the end of the protocol \n", + to_diagram()); + return false; + } + } + + if (components.username_end != buffer.size() && + components.username_end > components.protocol_end + 2) { + if (buffer[components.username_end] != ':' && + buffer[components.username_end] != '@') { + ada_log( + "url_aggregator::validate missing : or @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + + if (components.host_start != buffer.size()) { + if (components.host_start > components.username_end) { + if (buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the password \n", + to_diagram()); + return false; + } + } else if (components.host_start == components.username_end && + components.host_end > components.host_start) { + if (components.host_start == components.protocol_end + 2) { + if (buffer[components.protocol_end] != '/' || + buffer[components.protocol_end + 1] != '/') { + ada_log( + "url_aggregator::validate missing // between protocol and host " + "\n", + to_diagram()); + return false; + } + } else { + if (components.host_start > components.protocol_end && + buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + } else { + if (components.host_end != components.host_start) { + ada_log("url_aggregator::validate expected omitted host \n", + to_diagram()); + return false; + } + } + } + if (components.host_end != buffer.size() && + components.pathname_start > components.host_end) { + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + if (components.pathname_start + 1 >= buffer.size() || + buffer[components.pathname_start] != '/' || + buffer[components.pathname_start + 1] != '/') { + ada_log( + "url_aggregator::validate expected the path to begin with // \n", + to_diagram()); + return false; + } + } else if (buffer[components.host_end] != ':') { + ada_log("url_aggregator::validate missing : at the port \n", + to_diagram()); + return false; + } + } + if (components.pathname_start != buffer.size() && + components.pathname_start < components.search_start && + components.pathname_start < components.hash_start && !has_opaque_path) { + if (buffer[components.pathname_start] != '/') { + ada_log("url_aggregator::validate missing / at the path \n", + to_diagram()); + return false; + } + } + if (components.search_start != url_components::omitted) { + if (buffer[components.search_start] != '?') { + ada_log("url_aggregator::validate missing ? at the search \n", + to_diagram()); + return false; + } } if (components.hash_start != url_components::omitted) { - components.hash_start += new_difference; + if (buffer[components.hash_start] != '#') { + ada_log("url_aggregator::validate missing # at the hash \n", + to_diagram()); + return false; + } } - ADA_ASSERT_TRUE(validate()); + + return true; +} + +[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname() + const noexcept ada_lifetime_bound { + ada_log("url_aggregator::get_pathname pathname_start = ", + components.pathname_start, " buffer.size() = ", buffer.size(), + " components.search_start = ", components.search_start, + " components.hash_start = ", components.hash_start); + auto ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + return helpers::substring(buffer, components.pathname_start, ending_index); } inline std::ostream &operator<<(std::ostream &out, const ada::url_aggregator &u) { return out << u.to_string(); } + +void url_aggregator::update_host_to_base_host( + const std::string_view input) noexcept { + ada_log("url_aggregator::update_host_to_base_host ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (type != ada::scheme::type::FILE) { + // Let host be the result of host parsing host_view with url is not special. + if (input.empty() && !is_special()) { + if (has_hostname()) { + clear_hostname(); + } else if (has_dash_dot()) { + add_authority_slashes_if_needed(); + delete_dash_dot(); + } + return; + } + } + update_base_hostname(input); + ADA_ASSERT_TRUE(validate()); + return; +} } // namespace ada #endif // ADA_URL_AGGREGATOR_INL_H @@ -6927,7 +7607,9 @@ struct url_search_params { * @see * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js */ - url_search_params(const std::string_view input) { initialize(input); } + explicit url_search_params(const std::string_view input) { + initialize(input); + } url_search_params(const url_search_params &u) = default; url_search_params(url_search_params &&u) noexcept = default; @@ -7057,7 +7739,7 @@ struct url_search_params_iter { */ inline std::optional next(); - inline bool has_next(); + inline bool has_next() const; private: static url_search_params EMPTY; @@ -7083,6 +7765,7 @@ struct url_search_params_iter { #include #include +#include #include #include #include @@ -7108,14 +7791,14 @@ inline void url_search_params::initialize(std::string_view input) { if (equal == std::string_view::npos) { std::string name(current); - std::replace(name.begin(), name.end(), '+', ' '); + std::ranges::replace(name, '+', ' '); params.emplace_back(unicode::percent_decode(name, name.find('%')), ""); } else { std::string name(current.substr(0, equal)); std::string value(current.substr(equal + 1)); - std::replace(name.begin(), name.end(), '+', ' '); - std::replace(value.begin(), value.end(), '+', ' '); + std::ranges::replace(name, '+', ' '); + std::ranges::replace(value, '+', ' '); params.emplace_back(unicode::percent_decode(name, name.find('%')), unicode::percent_decode(value, value.find('%'))); @@ -7147,8 +7830,8 @@ inline size_t url_search_params::size() const noexcept { return params.size(); } inline std::optional url_search_params::get( const std::string_view key) { - auto entry = std::find_if(params.begin(), params.end(), - [&key](auto ¶m) { return param.first == key; }); + auto entry = std::ranges::find_if( + params, [&key](auto ¶m) { return param.first == key; }); if (entry == params.end()) { return std::nullopt; @@ -7171,17 +7854,16 @@ inline std::vector url_search_params::get_all( } inline bool url_search_params::has(const std::string_view key) noexcept { - auto entry = std::find_if(params.begin(), params.end(), - [&key](auto ¶m) { return param.first == key; }); + auto entry = std::ranges::find_if( + params, [&key](auto ¶m) { return param.first == key; }); return entry != params.end(); } inline bool url_search_params::has(std::string_view key, std::string_view value) noexcept { - auto entry = - std::find_if(params.begin(), params.end(), [&key, &value](auto ¶m) { - return param.first == key && param.second == value; - }); + auto entry = std::ranges::find_if(params, [&key, &value](auto ¶m) { + return param.first == key && param.second == value; + }); return entry != params.end(); } @@ -7193,8 +7875,8 @@ inline std::string url_search_params::to_string() const { auto value = ada::unicode::percent_encode(params[i].second, character_set); // Performance optimization: Move this inside percent_encode. - std::replace(key.begin(), key.end(), ' ', '+'); - std::replace(value.begin(), value.end(), ' ', '+'); + std::ranges::replace(key, ' ', '+'); + std::ranges::replace(value, ' ', '+'); if (i != 0) { out += "&"; @@ -7210,7 +7892,7 @@ inline void url_search_params::set(const std::string_view key, const std::string_view value) { const auto find = [&key](auto ¶m) { return param.first == key; }; - auto it = std::find_if(params.begin(), params.end(), find); + auto it = std::ranges::find_if(params, find); if (it == params.end()) { params.emplace_back(key, value); @@ -7222,27 +7904,21 @@ inline void url_search_params::set(const std::string_view key, } inline void url_search_params::remove(const std::string_view key) { - params.erase( - std::remove_if(params.begin(), params.end(), - [&key](auto ¶m) { return param.first == key; }), - params.end()); + std::erase_if(params, [&key](auto ¶m) { return param.first == key; }); } inline void url_search_params::remove(const std::string_view key, const std::string_view value) { - params.erase(std::remove_if(params.begin(), params.end(), - [&key, &value](auto ¶m) { - return param.first == key && - param.second == value; - }), - params.end()); + std::erase_if(params, [&key, &value](auto ¶m) { + return param.first == key && param.second == value; + }); } inline void url_search_params::sort() { - std::stable_sort(params.begin(), params.end(), - [](const key_value_pair &lhs, const key_value_pair &rhs) { - return lhs.first < rhs.first; - }); + std::ranges::stable_sort( + params, [](const key_value_pair &lhs, const key_value_pair &rhs) { + return lhs.first < rhs.first; + }); } inline url_search_params_keys_iter url_search_params::get_keys() { @@ -7264,7 +7940,7 @@ inline url_search_params_entries_iter url_search_params::get_entries() { } template -inline bool url_search_params_iter::has_next() { +inline bool url_search_params_iter::has_next() const { return pos < params.params.size(); } @@ -7297,86 +7973,1285 @@ url_search_params_entries_iter::next() { #endif // ADA_URL_SEARCH_PARAMS_INL_H /* end file include/ada/url_search_params-inl.h */ - -// Public API -/* begin file include/ada/ada_version.h */ +/* begin file include/ada/url_pattern-inl.h */ /** - * @file ada_version.h - * @brief Definitions for Ada's version number. + * @file url_pattern-inl.h + * @brief Declaration for the URLPattern inline functions. */ -#ifndef ADA_ADA_VERSION_H -#define ADA_ADA_VERSION_H +#ifndef ADA_URL_PATTERN_INL_H +#define ADA_URL_PATTERN_INL_H -#define ADA_VERSION "2.9.2" + +#include namespace ada { -enum { - ADA_VERSION_MAJOR = 2, - ADA_VERSION_MINOR = 9, - ADA_VERSION_REVISION = 2, -}; +inline bool url_pattern_init::operator==(const url_pattern_init& other) const { + return protocol == other.protocol && username == other.username && + password == other.password && hostname == other.hostname && + port == other.port && search == other.search && hash == other.hash && + pathname == other.pathname; +} + +inline bool url_pattern_component_result::operator==( + const url_pattern_component_result& other) const { + return input == other.input && groups == other.groups; +} + +inline std::string url_pattern_component::to_string() const { +#ifdef ADA_HAS_FORMAT + return std::format(R"({{"pattern": "{}", "has_regexp_groups": {}}})", pattern, + has_regexp_groups ? "true" : "false" //, + ); +#else + return ""; +#endif +} + +inline url_pattern_component_result +url_pattern_component::create_component_match_result( + std::string_view input, const std::smatch& exec_result) { + // Let result be a new URLPatternComponentResult. + // Set result["input"] to input. + // Let groups be a record. + auto result = + url_pattern_component_result{.input = std::string(input), .groups = {}}; + + // If input is empty, then groups will always be empty. + if (input.empty()) { + result.groups.insert({"0", ""}); + return result; + } + + // Optimization: Let's reserve the size. + result.groups.reserve(exec_result.size() - 1); + + size_t group_index = 0; + // Let index be 1. + // While index is less than Get(execResult, "length"): + for (size_t index = 1; index < exec_result.size(); index++) { + // Let name be component’s group name list[index - 1]. + // Let value be Get(execResult, ToString(index)). + // Set groups[name] to value. + auto exec = exec_result[index]; + if (!exec.matched) continue; + result.groups.insert({ + group_name_list[group_index], + exec.str(), + }); + + group_index++; + } + return result; +} + +inline std::string url_pattern::to_string() const { +#ifdef ADA_HAS_FORMAT + return std::format( + R"({{"protocol_component": "{}", "username_component": {}, "password_component": {}, "hostname_component": {}, "port_component": {}, "pathname_component": {}, "search_component": {}, "hash_component": {}, "ignore_case": {}}})", + protocol_component.to_string(), username_component.to_string(), + password_component.to_string(), hostname_component.to_string(), + port_component.to_string(), pathname_component.to_string(), + search_component.to_string(), hash_component.to_string(), + ignore_case_ ? "true" : "false"); +#else + return ""; +#endif +} + +inline std::string_view url_pattern::get_protocol() const ada_lifetime_bound { + // Return this's associated URL pattern's protocol component's pattern string. + return protocol_component.pattern; +} +inline std::string_view url_pattern::get_username() const ada_lifetime_bound { + // Return this's associated URL pattern's username component's pattern string. + return username_component.pattern; +} +inline std::string_view url_pattern::get_password() const ada_lifetime_bound { + // Return this's associated URL pattern's password component's pattern string. + return password_component.pattern; +} +inline std::string_view url_pattern::get_hostname() const ada_lifetime_bound { + // Return this's associated URL pattern's hostname component's pattern string. + return hostname_component.pattern; +} +inline std::string_view url_pattern::get_port() const ada_lifetime_bound { + // Return this's associated URL pattern's port component's pattern string. + return port_component.pattern; +} +inline std::string_view url_pattern::get_pathname() const ada_lifetime_bound { + // Return this's associated URL pattern's pathname component's pattern string. + return pathname_component.pattern; +} +inline std::string_view url_pattern::get_search() const ada_lifetime_bound { + // Return this's associated URL pattern's search component's pattern string. + return search_component.pattern; +} +inline std::string_view url_pattern::get_hash() const ada_lifetime_bound { + // Return this's associated URL pattern's hash component's pattern string. + return hash_component.pattern; +} + +inline bool url_pattern::ignore_case() const { return ignore_case_; } + +inline bool url_pattern::has_regexp_groups() const { + // If this's associated URL pattern's has regexp groups, then return true. + return protocol_component.has_regexp_groups || + username_component.has_regexp_groups || + password_component.has_regexp_groups || + hostname_component.has_regexp_groups || + port_component.has_regexp_groups || + pathname_component.has_regexp_groups || + search_component.has_regexp_groups || hash_component.has_regexp_groups; +} + +inline bool url_pattern_part::is_regexp() const noexcept { + return type == url_pattern_part_type::REGEXP; +} +inline std::string_view url_pattern_compile_component_options::get_delimiter() + const { + if (delimiter) { + return {&delimiter.value(), 1}; + } + return {}; +} + +inline std::string_view url_pattern_compile_component_options::get_prefix() + const { + if (prefix) { + return {&prefix.value(), 1}; + } + return {}; +} } // namespace ada -#endif // ADA_ADA_VERSION_H -/* end file include/ada/ada_version.h */ -/* begin file include/ada/implementation.h */ +#endif +/* end file include/ada/url_pattern-inl.h */ +/* begin file include/ada/url_pattern_helpers.h */ /** - * @file implementation.h - * @brief Definitions for user facing functions for parsing URL and it's - * components. + * @file url_pattern_helpers.h + * @brief Declaration for the URLPattern helpers. */ -#ifndef ADA_IMPLEMENTATION_H -#define ADA_IMPLEMENTATION_H +#ifndef ADA_URL_PATTERN_HELPERS_H +#define ADA_URL_PATTERN_HELPERS_H + #include -#include +#include +#include +namespace ada::url_pattern_helpers { + +// @see https://urlpattern.spec.whatwg.org/#token +enum class token_type : uint8_t { + INVALID_CHAR, // 0 + OPEN, // 1 + CLOSE, // 2 + REGEXP, // 3 + NAME, // 4 + CHAR, // 5 + ESCAPED_CHAR, // 6 + OTHER_MODIFIER, // 7 + ASTERISK, // 8 + END, // 9 +}; -namespace ada { -enum class errors { generic_error }; +std::string to_string(token_type type); -template -using result = tl::expected; +// @see https://urlpattern.spec.whatwg.org/#tokenize-policy +enum class token_policy { + STRICT, + LENIENT, +}; -/** - * The URL parser takes a scalar value string input, with an optional null or - * base URL base (default null). The parser assumes the input is a valid ASCII - * or UTF-8 string. - * - * @param input the string input to analyze (must be valid ASCII or UTF-8) - * @param base_url the optional URL input to use as a base url. - * @return a parsed URL. - */ -template -ada_warn_unused ada::result parse( - std::string_view input, const result_type* base_url = nullptr); +// @see https://urlpattern.spec.whatwg.org/#tokens +class Token { + public: + Token(token_type _type, size_t _index, std::string&& _value) + : type(_type), index(_index), value(std::move(_value)) {} -extern template ada::result parse(std::string_view input, - const url* base_url); -extern template ada::result parse( - std::string_view input, const url_aggregator* base_url); + // A token has an associated type, a string, initially "invalid-char". + token_type type = token_type::INVALID_CHAR; + + // A token has an associated index, a number, initially 0. It is the position + // of the first code point in the pattern string represented by the token. + size_t index = 0; + + // A token has an associated value, a string, initially the empty string. It + // contains the code points from the pattern string represented by the token. + std::string value{}; +}; + +// @see https://urlpattern.spec.whatwg.org/#pattern-parser +template +class url_pattern_parser { + public: + url_pattern_parser(F& encoding_callback_, + std::string_view segment_wildcard_regexp_) + : encoding_callback(encoding_callback_), + segment_wildcard_regexp(segment_wildcard_regexp_) {} + + bool can_continue() const { return index < tokens.size(); } + + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token + Token* try_consume_token(token_type type); + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token + Token* try_consume_modifier_token(); + // @see + // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token + Token* try_consume_regexp_or_wildcard_token(Token* name_token); + // @see https://urlpattern.spec.whatwg.org/#consume-text + std::string consume_text(); + // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token + bool consume_required_token(token_type type); + // @see + // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value + std::optional maybe_add_part_from_the_pending_fixed_value() + ada_warn_unused; + // @see https://urlpattern.spec.whatwg.org/#add-a-part + std::optional add_part(std::string_view prefix, Token* name_token, + Token* regexp_or_wildcard_token, + std::string_view suyffix, + Token* modifier_token) ada_warn_unused; + + std::vector tokens{}; + F& encoding_callback; + std::string segment_wildcard_regexp; + std::vector parts{}; + std::string pending_fixed_value{}; + size_t index = 0; + size_t next_numeric_name = 0; +}; + +// @see https://urlpattern.spec.whatwg.org/#tokenizer +class Tokenizer { + public: + explicit Tokenizer(std::string_view new_input, token_policy new_policy) + : input(new_input), policy(new_policy) {} + + // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point + void get_next_code_point(); + + // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point + void seek_and_get_next_code_point(size_t index); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token + + void add_token(token_type type, size_t next_position, size_t value_position, + size_t value_length); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length + void add_token_with_default_length(token_type type, size_t next_position, + size_t value_position); + + // @see + // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length + void add_token_with_defaults(token_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error + std::optional process_tokenizing_error( + size_t next_position, size_t value_position) ada_warn_unused; + + // has an associated input, a pattern string, initially the empty string. + std::string input; + // has an associated policy, a tokenize policy, initially "strict". + token_policy policy; + // has an associated token list, a token list, initially an empty list. + std::vector token_list{}; + // has an associated index, a number, initially 0. + size_t index = 0; + // has an associated next index, a number, initially 0. + size_t next_index = 0; + // has an associated code point, a Unicode code point, initially null. + char32_t code_point{}; +}; + +// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser +struct constructor_string_parser { + explicit constructor_string_parser(std::string_view new_input, + std::vector&& new_token_list) + : input(new_input), token_list(std::move(new_token_list)) {} + + // @see https://urlpattern.spec.whatwg.org/#rewind + void rewind(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix + bool is_hash_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix + bool is_search_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string + static tl::expected parse(std::string_view input); + + // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state + enum class State { + INIT, + PROTOCOL, + AUTHORITY, + USERNAME, + PASSWORD, + HOSTNAME, + PORT, + PATHNAME, + SEARCH, + HASH, + DONE, + }; + + // @see https://urlpattern.spec.whatwg.org/#change-state + void change_state(State state, size_t skip); + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-open + bool is_group_open() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-close + bool is_group_close() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix + bool is_protocol_suffix(); + + // @see + // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag + std::optional compute_protocol_matches_special_scheme_flag(); + + // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes + bool next_is_authority_slashes(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator + bool is_an_identity_terminator(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start + bool is_pathname_start(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix + bool is_password_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open + bool is_an_ipv6_open(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close + bool is_an_ipv6_close(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix + bool is_port_prefix(); + + // has an associated input, a string, which must be set upon creation. + std::string input; + // has an associated token list, a token list, which must be set upon + // creation. + std::vector token_list; + // has an associated result, a URLPatternInit, initially set to a new + // URLPatternInit. + url_pattern_init result{}; + // has an associated component start, a number, initially set to 0. + size_t component_start = 0; + // has an associated token index, a number, initially set to 0. + size_t token_index = 0; + // has an associated token increment, a number, initially set to 1. + size_t token_increment = 1; + // has an associated group depth, a number, initially set to 0. + size_t group_depth = 0; + // has an associated hostname IPv6 bracket depth, a number, initially set to + // 0. + size_t hostname_ipv6_bracket_depth = 0; + // has an associated protocol matches a special scheme flag, a boolean, + // initially set to false. + bool protocol_matches_a_special_scheme_flag = false; + // has an associated state, a string, initially set to "init". + State state = State::INIT; + + private: + // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char + bool is_non_special_pattern_char(size_t index, std::string_view value); + + // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token + const Token* get_safe_token(size_t index); + + // @see https://urlpattern.spec.whatwg.org/#make-a-component-string + std::string make_component_string(); +}; +// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol +tl::expected canonicalize_protocol(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-username +tl::expected canonicalize_username(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_password(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_hostname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname +tl::expected canonicalize_ipv6_hostname( + std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected canonicalize_port(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected canonicalize_port_with_protocol( + std::string_view input, std::string_view protocol); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname +tl::expected canonicalize_pathname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname +tl::expected canonicalize_opaque_pathname( + std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-search +tl::expected canonicalize_search(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash +tl::expected canonicalize_hash(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#tokenize +tl::expected, errors> tokenize(std::string_view input, + token_policy policy); + +// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string +std::string process_base_url_string(std::string_view input, + std::string_view type); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string +std::string escape_pattern_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string +std::string escape_regexp_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname +constexpr bool is_absolute_pathname(std::string_view input, + std::string_view type) noexcept; + +// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string +template +tl::expected, errors> parse_pattern_string( + std::string_view input, url_pattern_compile_component_options& options, + F& encoding_callback); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string +std::string generate_pattern_string( + std::vector& part_list, + url_pattern_compile_component_options& options); + +// @see +// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list +std::tuple> +generate_regular_expression_and_name_list( + std::vector& part_list, + url_pattern_compile_component_options options); + +// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address +bool is_ipv6_address(std::string_view input) noexcept; + +// @see +// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme +bool protocol_component_matches_special_scheme( + ada::url_pattern_component& input); + +// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string +std::string convert_modifier_to_string(url_pattern_part_modifier modifier); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp +std::string generate_segment_wildcard_regexp( + url_pattern_compile_component_options options); + +} // namespace ada::url_pattern_helpers + +#endif +/* end file include/ada/url_pattern_helpers.h */ +/* begin file include/ada/url_pattern_helpers-inl.h */ /** - * Verifies whether the URL strings can be parsed. The function assumes - * that the inputs are valid ASCII or UTF-8 strings. - * @see https://url.spec.whatwg.org/#dom-url-canparse - * @return If URL can be parsed or not. + * @file url_pattern_helpers-inl.h + * @brief Declaration for the URLPattern helpers. */ -bool can_parse(std::string_view input, - const std::string_view* base_input = nullptr); +#ifndef ADA_URL_PATTERN_HELPERS_INL_H +#define ADA_URL_PATTERN_HELPERS_INL_H + + +namespace ada::url_pattern_helpers { +inline std::string to_string(token_type type) { + switch (type) { + case token_type::INVALID_CHAR: + return "INVALID_CHAR"; + case token_type::OPEN: + return "OPEN"; + case token_type::CLOSE: + return "CLOSE"; + case token_type::REGEXP: + return "REGEXP"; + case token_type::NAME: + return "NAME"; + case token_type::CHAR: + return "CHAR"; + case token_type::ESCAPED_CHAR: + return "ESCAPED_CHAR"; + case token_type::OTHER_MODIFIER: + return "OTHER_MODIFIER"; + case token_type::ASTERISK: + return "ASTERISK"; + case token_type::END: + return "END"; + default: + ada::unreachable(); + } +} + +inline void constructor_string_parser::rewind() { + // Set parser’s token index to parser’s component start. + token_index = component_start; + // Set parser’s token increment to 0. + token_increment = 0; +} + +inline bool constructor_string_parser::is_hash_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index and "#". + return is_non_special_pattern_char(token_index, "#"); +} + +inline bool constructor_string_parser::is_search_prefix() { + // If result of running is a non-special pattern char given parser, parser’s + // token index and "?" is true, then return true. + if (is_non_special_pattern_char(token_index, "?")) { + return true; + } + + // If parser’s token list[parser’s token index]'s value is not "?", then + // return false. + if (token_list[token_index].value != "?") { + return false; + } + + // If previous index is less than 0, then return true. + if (token_index == 0) return true; + // Let previous index be parser’s token index − 1. + auto previous_index = token_index - 1; + // Let previous token be the result of running get a safe token given parser + // and previous index. + auto previous_token = get_safe_token(previous_index); + ADA_ASSERT_TRUE(previous_token); + // If any of the following are true, then return false: + // - previous token’s type is "name". + // - previous token’s type is "regexp". + // - previous token’s type is "close". + // - previous token’s type is "asterisk". + return !(previous_token->type == token_type::NAME || + previous_token->type == token_type::REGEXP || + previous_token->type == token_type::CLOSE || + previous_token->type == token_type::ASTERISK); +} + +inline bool constructor_string_parser::is_non_special_pattern_char( + size_t index, std::string_view value) { + // Let token be the result of running get a safe token given parser and index. + auto token = get_safe_token(index); + ADA_ASSERT_TRUE(token); + + // If token’s value is not value, then return false. + if (token->value != value) { + return false; + } + + // If any of the following are true: + // - token’s type is "char"; + // - token’s type is "escaped-char"; or + // - token’s type is "invalid-char", + // - then return true. + return token->type == token_type::CHAR || + token->type == token_type::ESCAPED_CHAR || + token->type == token_type::INVALID_CHAR; +} + +inline const Token* constructor_string_parser::get_safe_token(size_t index) { + // If index is less than parser’s token list's size, then return parser’s + // token list[index]. + if (index < token_list.size()) [[likely]] { + return &token_list[index]; + } + + // Assert: parser’s token list's size is greater than or equal to 1. + ADA_ASSERT_TRUE(!token_list.empty()); + + // Let token be parser’s token list[last index]. + // Assert: token’s type is "end". + ADA_ASSERT_TRUE(token_list.back().type == token_type::END); + + // Return token. + return &token_list.back(); +} + +inline bool constructor_string_parser::is_group_open() const { + // If parser’s token list[parser’s token index]'s type is "open", then return + // true. + return token_list[token_index].type == token_type::OPEN; +} + +inline bool constructor_string_parser::is_group_close() const { + // If parser’s token list[parser’s token index]'s type is "close", then return + // true. + return token_list[token_index].type == token_type::CLOSE; +} + +inline bool constructor_string_parser::next_is_authority_slashes() { + // If the result of running is a non-special pattern char given parser, + // parser’s token index + 1, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 1, "/")) { + return false; + } + // If the result of running is a non-special pattern char given parser, + // parser’s token index + 2, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 2, "/")) { + return false; + } + return true; +} + +inline bool constructor_string_parser::is_protocol_suffix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +inline void constructor_string_parser::change_state(State new_state, + size_t skip) { + // If parser’s state is not "init", not "authority", and not "done", then set + // parser’s result[parser’s state] to the result of running make a component + // string given parser. + if (state != State::INIT && state != State::AUTHORITY && + state != State::DONE) { + auto value = make_component_string(); + // TODO: Simplify this. + switch (state) { + case State::PROTOCOL: { + result.protocol = value; + break; + } + case State::USERNAME: { + result.username = value; + break; + } + case State::PASSWORD: { + result.password = value; + break; + } + case State::HOSTNAME: { + result.hostname = value; + break; + } + case State::PORT: { + result.port = value; + break; + } + case State::PATHNAME: { + result.pathname = value; + break; + } + case State::SEARCH: { + result.search = value; + break; + } + case State::HASH: { + result.hash = value; + break; + } + default: + ada::unreachable(); + } + } + + // If parser’s state is not "init" and new state is not "done", then: + if (state != State::INIT && new_state != State::DONE) { + // If parser’s state is "protocol", "authority", "username", or "password"; + // new state is "port", "pathname", "search", or "hash"; and parser’s + // result["hostname"] does not exist, then set parser’s result["hostname"] + // to the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD) && + (new_state == State::PORT || new_state == State::PATHNAME || + new_state == State::SEARCH || new_state == State::HASH) && + !result.hostname) + result.hostname = ""; + } + + // If parser’s state is "protocol", "authority", "username", "password", + // "hostname", or "port"; new state is "search" or "hash"; and parser’s + // result["pathname"] does not exist, then: + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT) && + (new_state == State::SEARCH || new_state == State::HASH) && + !result.pathname) { + if (protocol_matches_a_special_scheme_flag) { + result.pathname = "/"; + } else { + // Otherwise, set parser’s result["pathname"] to the empty string. + result.pathname = ""; + } + } + + // If parser’s state is "protocol", "authority", "username", "password", + // "hostname", "port", or "pathname"; new state is "hash"; and parser’s + // result["search"] does not exist, then set parser’s result["search"] to + // the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT || + state == State::PATHNAME) && + new_state == State::HASH && !result.search) { + result.search = ""; + } + + // Set parser’s state to new state. + state = new_state; + // Increment parser’s token index by skip. + token_index += skip; + // Set parser’s component start to parser’s token index. + component_start = token_index; + // Set parser’s token increment to 0. + token_increment = 0; +} + +inline std::string constructor_string_parser::make_component_string() { + // Assert: parser’s token index is less than parser’s token list's size. + ADA_ASSERT_TRUE(token_index < token_list.size()); + + // Let token be parser’s token list[parser’s token index]. + // Let end index be token’s index. + const auto end_index = token_list[token_index].index; + // Let component start token be the result of running get a safe token given + // parser and parser’s component start. + const auto component_start_token = get_safe_token(component_start); + ADA_ASSERT_TRUE(component_start_token); + // Let component start input index be component start token’s index. + const auto component_start_input_index = component_start_token->index; + // Return the code point substring from component start input index to end + // index within parser’s input. + return input.substr(component_start_input_index, + end_index - component_start_input_index); +} + +inline bool constructor_string_parser::is_an_identity_terminator() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "@". + return is_non_special_pattern_char(token_index, "@"); +} + +inline bool constructor_string_parser::is_pathname_start() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "/". + return is_non_special_pattern_char(token_index, "/"); +} + +inline bool constructor_string_parser::is_password_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +inline bool constructor_string_parser::is_an_ipv6_open() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "[". + return is_non_special_pattern_char(token_index, "["); +} + +inline bool constructor_string_parser::is_an_ipv6_close() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "]". + return is_non_special_pattern_char(token_index, "]"); +} + +inline bool constructor_string_parser::is_port_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +inline void Tokenizer::get_next_code_point() { + ada_log("Tokenizer::get_next_code_point called with index=", next_index); + ADA_ASSERT_TRUE(next_index < input.size()); + // this assumes that we have a valid, non-truncated UTF-8 stream. + code_point = 0; + size_t number_bytes = 0; + unsigned char first_byte = input[next_index]; + + if ((first_byte & 0x80) == 0) { + // 1-byte character (ASCII) + next_index++; + code_point = first_byte; + ada_log("Tokenizer::get_next_code_point returning ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + return; + } + ada_log("Tokenizer::get_next_code_point read first byte=", + uint32_t(first_byte)); + if ((first_byte & 0xE0) == 0xC0) { + code_point = first_byte & 0x1F; + number_bytes = 2; + ada_log("Tokenizer::get_next_code_point two bytes"); + } else if ((first_byte & 0xF0) == 0xE0) { + code_point = first_byte & 0x0F; + number_bytes = 3; + ada_log("Tokenizer::get_next_code_point three bytes"); + } else if ((first_byte & 0xF8) == 0xF0) { + code_point = first_byte & 0x07; + number_bytes = 4; + ada_log("Tokenizer::get_next_code_point four bytes"); + } + ADA_ASSERT_TRUE(number_bytes + next_index <= input.size()); + + for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) { + unsigned char byte = input[i]; + ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte)); + code_point = (code_point << 6) | (byte & 0x3F); + } + ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + next_index += number_bytes; +} + +inline void Tokenizer::seek_and_get_next_code_point(size_t new_index) { + ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=", + new_index); + // Set tokenizer’s next index to index. + next_index = new_index; + // Run get the next code point given tokenizer. + get_next_code_point(); +} + +inline void Tokenizer::add_token(token_type type, size_t next_position, + size_t value_position, size_t value_length) { + ada_log("Tokenizer::add_token called with type=", to_string(type), + " next_position=", next_position, " value_position=", value_position); + ADA_ASSERT_TRUE(next_position >= value_position); + + // Let token be a new token. + // Set token’s type to type. + // Set token’s index to tokenizer’s index. + // Set token’s value to the code point substring from value position with + // length value length within tokenizer’s input. + // Append token to the back of tokenizer’s token list. + token_list.emplace_back(type, index, + input.substr(value_position, value_length)); + // Set tokenizer’s index to next position. + index = next_position; +} + +inline void Tokenizer::add_token_with_default_length(token_type type, + size_t next_position, + size_t value_position) { + // Let computed length be next position − value position. + auto computed_length = next_position - value_position; + // Run add a token given tokenizer, type, next position, value position, and + // computed length. + add_token(type, next_position, value_position, computed_length); +} + +inline void Tokenizer::add_token_with_defaults(token_type type) { + ada_log("Tokenizer::add_token_with_defaults called with type=", + to_string(type)); + // Run add a token with default length given tokenizer, type, tokenizer’s next + // index, and tokenizer’s index. + add_token_with_default_length(type, next_index, index); +} + +inline ada_warn_unused std::optional +Tokenizer::process_tokenizing_error(size_t next_position, + size_t value_position) { + // If tokenizer’s policy is "strict", then throw a TypeError. + if (policy == token_policy::STRICT) { + ada_log("process_tokenizing_error failed with next_position=", + next_position, " value_position=", value_position); + return errors::type_error; + } + // Assert: tokenizer’s policy is "lenient". + ADA_ASSERT_TRUE(policy == token_policy::LENIENT); + // Run add a token with default length given tokenizer, "invalid-char", next + // position, and value position. + add_token_with_default_length(token_type::INVALID_CHAR, next_position, + value_position); + return std::nullopt; +} + +template +Token* url_pattern_parser::try_consume_modifier_token() { + // Let token be the result of running try to consume a token given parser and + // "other-modifier". + auto token = try_consume_token(token_type::OTHER_MODIFIER); + // If token is not null, then return token. + if (token) return token; + // Set token to the result of running try to consume a token given parser and + // "asterisk". + // Return token. + return try_consume_token(token_type::ASTERISK); +} + +template +Token* url_pattern_parser::try_consume_regexp_or_wildcard_token( + Token* name_token) { + // Let token be the result of running try to consume a token given parser and + // "regexp". + auto token = try_consume_token(token_type::REGEXP); + // If name token is null and token is null, then set token to the result of + // running try to consume a token given parser and "asterisk". + if (!name_token && !token) { + token = try_consume_token(token_type::ASTERISK); + } + // Return token. + return token; +} + +template +Token* url_pattern_parser::try_consume_token(token_type type) { + ada_log("url_pattern_parser::try_consume_token called with type=", + to_string(type)); + // Assert: parser’s index is less than parser’s token list size. + ADA_ASSERT_TRUE(index < tokens.size()); + // Let next token be parser’s token list[parser’s index]. + auto& next_token = tokens[index]; + // If next token’s type is not type return null. + if (next_token.type != type) return nullptr; + // Increase parser’s index by 1. + index++; + // Return next token. + return &next_token; +} + +template +std::string url_pattern_parser::consume_text() { + // Let result be the empty string. + std::string result{}; + // While true: + while (true) { + // Let token be the result of running try to consume a token given parser + // and "char". + auto token = try_consume_token(token_type::CHAR); + // If token is null, then set token to the result of running try to consume + // a token given parser and "escaped-char". + if (!token) token = try_consume_token(token_type::ESCAPED_CHAR); + // If token is null, then break. + if (!token) break; + // Append token’s value to the end of result. + result.append(token->value); + } + // Return result. + return result; +} + +template +bool url_pattern_parser::consume_required_token(token_type type) { + ada_log("url_pattern_parser::consume_required_token called with type=", + to_string(type)); + // Let result be the result of running try to consume a token given parser and + // type. + return try_consume_token(type) != nullptr; +} + +template +std::optional +url_pattern_parser::maybe_add_part_from_the_pending_fixed_value() { + // If parser’s pending fixed value is the empty string, then return. + if (pending_fixed_value.empty()) { + ada_log("pending_fixed_value is empty"); + return std::nullopt; + } + // Let encoded value be the result of running parser’s encoding callback given + // parser’s pending fixed value. + auto encoded_value = encoding_callback(pending_fixed_value); + if (!encoded_value) { + ada_log("failed to encode pending_fixed_value: ", pending_fixed_value); + return encoded_value.error(); + } + // Set parser’s pending fixed value to the empty string. + pending_fixed_value.clear(); + // Let part be a new part whose type is "fixed-text", value is encoded value, + // and modifier is "none". + // Append part to parser’s part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), + url_pattern_part_modifier::NONE); + return std::nullopt; +} + +template +std::optional url_pattern_parser::add_part( + std::string_view prefix, Token* name_token, Token* regexp_or_wildcard_token, + std::string_view suffix, Token* modifier_token) { + // Let modifier be "none". + auto modifier = url_pattern_part_modifier::NONE; + // If modifier token is not null: + if (modifier_token) { + // If modifier token’s value is "?" then set modifier to "optional". + if (modifier_token->value == "?") { + modifier = url_pattern_part_modifier::OPTIONAL; + } else if (modifier_token->value == "*") { + // Otherwise if modifier token’s value is "*" then set modifier to + // "zero-or-more". + modifier = url_pattern_part_modifier::ZERO_OR_MORE; + } else if (modifier_token->value == "+") { + // Otherwise if modifier token’s value is "+" then set modifier to + // "one-or-more". + modifier = url_pattern_part_modifier::ONE_OR_MORE; + } + } + // If name token is null and regexp or wildcard token is null and modifier + // is "none": + if (!name_token && !regexp_or_wildcard_token && + modifier == url_pattern_part_modifier::NONE) { + // Append prefix to the end of parser’s pending fixed value. + pending_fixed_value.append(prefix); + return std::nullopt; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = maybe_add_part_from_the_pending_fixed_value()) { + return *error; + } + // If name token is null and regexp or wildcard token is null: + if (!name_token && !regexp_or_wildcard_token) { + // Assert: suffix is the empty string. + ADA_ASSERT_TRUE(suffix.empty()); + // If prefix is the empty string, then return. + if (prefix.empty()) return std::nullopt; + // Let encoded value be the result of running parser’s encoding callback + // given prefix. + auto encoded_value = encoding_callback(prefix); + if (!encoded_value) { + return encoded_value.error(); + } + // Let part be a new part whose type is "fixed-text", value is encoded + // value, and modifier is modifier. + // Append part to parser’s part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), modifier); + return std::nullopt; + } + // Let regexp value be the empty string. + std::string regexp_value{}; + // If regexp or wildcard token is null, then set regexp value to parser’s + // segment wildcard regexp. + if (!regexp_or_wildcard_token) { + regexp_value = segment_wildcard_regexp; + } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) { + // Otherwise if regexp or wildcard token’s type is "asterisk", then set + // regexp value to the full wildcard regexp value. + regexp_value = ".*"; + } else { + // Otherwise set regexp value to regexp or wildcard token’s value. + regexp_value = regexp_or_wildcard_token->value; + } + // Let type be "regexp". + auto type = url_pattern_part_type::REGEXP; + // If regexp value is parser’s segment wildcard regexp: + if (regexp_value == segment_wildcard_regexp) { + // Set type to "segment-wildcard". + type = url_pattern_part_type::SEGMENT_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } else if (regexp_value == ".*") { + // Otherwise if regexp value is the full wildcard regexp value: + // Set type to "full-wildcard". + type = url_pattern_part_type::FULL_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } + // Let name be the empty string. + std::string name{}; + // If name token is not null, then set name to name token’s value. + if (name_token) { + name = name_token->value; + } else if (regexp_or_wildcard_token) { + // Otherwise if regexp or wildcard token is not null: + // Set name to parser’s next numeric name, serialized. + // TODO: Make sure this is correct. + name = std::to_string(next_numeric_name); + // Increment parser’s next numeric name by 1. + next_numeric_name++; + } + // If the result of running is a duplicate name given parser and name is + // true, then throw a TypeError. + if (std::ranges::any_of( + parts, [&name](const auto& part) { return part.name == name; })) { + return errors::type_error; + } + // Let encoded prefix be the result of running parser’s encoding callback + // given prefix. + auto encoded_prefix = encoding_callback(prefix); + if (!encoded_prefix) return encoded_prefix.error(); + // Let encoded suffix be the result of running parser’s encoding callback + // given suffix. + auto encoded_suffix = encoding_callback(suffix); + if (!encoded_suffix) return encoded_suffix.error(); + // Let part be a new part whose type is type, value is regexp value, + // modifier is modifier, name is name, prefix is encoded prefix, and suffix + // is encoded suffix. + // Append part to parser’s part list. + parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name), + std::move(*encoded_prefix), std::move(*encoded_suffix)); + return std::nullopt; +} + +template +tl::expected, errors> parse_pattern_string( + std::string_view input, url_pattern_compile_component_options& options, + F& encoding_callback) { + ada_log("parse_pattern_string input=", input); + // Let parser be a new pattern parser whose encoding callback is encoding + // callback and segment wildcard regexp is the result of running generate a + // segment wildcard regexp given options. + auto parser = url_pattern_parser( + encoding_callback, generate_segment_wildcard_regexp(options)); + // Set parser’s token list to the result of running tokenize given input and + // "strict". + auto tokenize_result = tokenize(input, token_policy::STRICT); + if (!tokenize_result) { + ada_log("parse_pattern_string tokenize failed"); + return tl::unexpected(tokenize_result.error()); + } + parser.tokens = std::move(*tokenize_result); + + // While parser’s index is less than parser’s token list's size: + while (parser.can_continue()) { + // Let char token be the result of running try to consume a token given + // parser and "char". + auto char_token = parser.try_consume_token(token_type::CHAR); + // Let name token be the result of running try to consume a token given + // parser and "name". + auto name_token = parser.try_consume_token(token_type::NAME); + // Let regexp or wildcard token be the result of running try to consume a + // regexp or wildcard token given parser and name token. + auto regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // If name token is not null or regexp or wildcard token is not null: + if (name_token || regexp_or_wildcard_token) { + // Let prefix be the empty string. + std::string prefix{}; + // If char token is not null then set prefix to char token’s value. + if (char_token) prefix = char_token->value; + // If prefix is not the empty string and not options’s prefix code point: + if (!prefix.empty() && prefix != options.get_prefix()) { + // Append prefix to the end of parser’s pending fixed value. + parser.pending_fixed_value.append(prefix); + // Set prefix to the empty string. + prefix.clear(); + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed"); + return tl::unexpected(*error); + } + // Let modifier token be the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, the empty string, and modifier token. + if (auto error = + parser.add_part(prefix, name_token, regexp_or_wildcard_token, "", + modifier_token)) { + ada_log("parser.add_part failed"); + return tl::unexpected(*error); + } + // Continue. + continue; + } + + // Let fixed token be char token. + auto fixed_token = char_token; + // If fixed token is null, then set fixed token to the result of running try + // to consume a token given parser and "escaped-char". + if (!fixed_token) + fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR); + // If fixed token is not null: + if (fixed_token) { + // Append fixed token’s value to parser’s pending fixed value. + parser.pending_fixed_value.append(fixed_token->value); + // Continue. + continue; + } + // Let open token be the result of running try to consume a token given + // parser and "open". + auto open_token = parser.try_consume_token(token_type::OPEN); + // If open token is not null: + if (open_token) { + // Set prefix be the result of running consume text given parser. + auto prefix_ = parser.consume_text(); + // Set name token to the result of running try to consume a token given + // parser and "name". + name_token = parser.try_consume_token(token_type::NAME); + // Set regexp or wildcard token to the result of running try to consume a + // regexp or wildcard token given parser and name token. + regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // Let suffix be the result of running consume text given parser. + auto suffix_ = parser.consume_text(); + // Run consume a required token given parser and "close". + if (!parser.consume_required_token(token_type::CLOSE)) { + ada_log("parser.consume_required_token failed"); + return tl::unexpected(errors::type_error); + } + // Set modifier token to the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, suffix, and modifier token. + if (auto error = + parser.add_part(prefix_, name_token, regexp_or_wildcard_token, + suffix_, modifier_token)) { + return tl::unexpected(*error); + } + // Continue. + continue; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992"); + return tl::unexpected(*error); + } + // Run consume a required token given parser and "end". + if (!parser.consume_required_token(token_type::END)) { + return tl::unexpected(errors::type_error); + } + } + ada_log("parser.parts size is: ", parser.parts.size()); + // Return parser’s part list. + return parser.parts; +} +} // namespace ada::url_pattern_helpers + +#endif +/* end file include/ada/url_pattern_helpers-inl.h */ + +// Public API +/* begin file include/ada/ada_version.h */ /** - * Computes a href string from a file path. The function assumes - * that the input is a valid ASCII or UTF-8 string. - * @return a href string (starts with file:://) + * @file ada_version.h + * @brief Definitions for Ada's version number. */ -std::string href_from_file(std::string_view path); +#ifndef ADA_ADA_VERSION_H +#define ADA_ADA_VERSION_H + +#define ADA_VERSION "2.9.2" + +namespace ada { + +enum { + ADA_VERSION_MAJOR = 2, + ADA_VERSION_MINOR = 9, + ADA_VERSION_REVISION = 2, +}; + } // namespace ada -#endif // ADA_IMPLEMENTATION_H -/* end file include/ada/implementation.h */ +#endif // ADA_ADA_VERSION_H +/* end file include/ada/ada_version.h */ #endif // ADA_H /* end file include/ada.h */ diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js index d7d9b60b1c8e94..f0a0cd7132dc48 100644 --- a/lib/internal/bootstrap/web/exposed-window-or-worker.js +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -19,6 +19,7 @@ const { defineLazyProperties, defineReplaceableLazyAttribute, exposeLazyInterfaces, + exposeInterface, } = require('internal/util'); const { @@ -26,6 +27,10 @@ const { ERR_NO_CRYPTO, } = require('internal/errors').codes; +const { installObjectURLMethods, URLPattern } = require('internal/url'); +// https://urlpattern.spec.whatwg.org/#urlpattern-class +exposeInterface(globalThis, 'URLPattern', URLPattern); + // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope const timers = require('timers'); defineOperation(globalThis, 'clearInterval', timers.clearInterval); @@ -63,7 +68,6 @@ exposeLazyInterfaces(globalThis, 'perf_hooks', [ defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); // https://w3c.github.io/FileAPI/#creating-revoking -const { installObjectURLMethods } = require('internal/url'); installObjectURLMethods(); let fetchImpl; diff --git a/lib/internal/url.js b/lib/internal/url.js index f6e58e196860fc..90d37813e8b2ed 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -32,6 +32,7 @@ const { decodeURIComponent, } = primordials; +const { URLPattern } = internalBinding('url_pattern'); const { inspect } = require('internal/util/inspect'); const { encodeStr, @@ -1574,6 +1575,7 @@ module.exports = { toPathIfFileURL, installObjectURLMethods, URL, + URLPattern, URLSearchParams, URLParse: URL.parse, domainToASCII, diff --git a/lib/url.js b/lib/url.js index 31299653610002..c23d9c51c20033 100644 --- a/lib/url.js +++ b/lib/url.js @@ -30,6 +30,7 @@ const { decodeURIComponent, } = primordials; +const { URLPattern } = internalBinding('url_pattern'); const { toASCII } = internalBinding('encoding_binding'); const { encodeStr, hexTable } = require('internal/querystring'); const querystring = require('querystring'); @@ -1029,6 +1030,7 @@ module.exports = { // WHATWG API URL, + URLPattern, URLSearchParams, domainToASCII, domainToUnicode, diff --git a/node.gyp b/node.gyp index 1633ed2d832fc5..473c86b1504aee 100644 --- a/node.gyp +++ b/node.gyp @@ -146,6 +146,7 @@ 'src/node_trace_events.cc', 'src/node_types.cc', 'src/node_url.cc', + 'src/node_url_pattern.cc', 'src/node_util.cc', 'src/node_v8.cc', 'src/node_wasi.cc', @@ -275,6 +276,7 @@ 'src/node_stat_watcher.h', 'src/node_union_bytes.h', 'src/node_url.h', + 'src/node_url_pattern.h', 'src/node_version.h', 'src/node_v8.h', 'src/node_v8_platform-inl.h', diff --git a/src/env_properties.h b/src/env_properties.h index d9e18cbc4515ac..04fe8918dddbc1 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -78,6 +78,7 @@ V(async_ids_stack_string, "async_ids_stack") \ V(attributes_string, "attributes") \ V(base_string, "base") \ + V(base_url_string, "baseURL") \ V(bits_string, "bits") \ V(block_list_string, "blockList") \ V(buffer_string, "buffer") \ @@ -178,6 +179,9 @@ V(get_data_clone_error_string, "_getDataCloneError") \ V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \ V(gid_string, "gid") \ + V(groups_string, "groups") \ + V(has_regexp_groups_string, "hasRegExpGroups") \ + V(hash_string, "hash") \ V(h2_string, "h2") \ V(handle_string, "handle") \ V(hash_algorithm_string, "hashAlgorithm") \ @@ -185,6 +189,7 @@ V(homedir_string, "homedir") \ V(host_string, "host") \ V(hostmaster_string, "hostmaster") \ + V(hostname_string, "hostname") \ V(http_1_1_string, "http/1.1") \ V(id_string, "id") \ V(identity_string, "identity") \ @@ -192,6 +197,7 @@ V(infoaccess_string, "infoAccess") \ V(inherit_string, "inherit") \ V(input_string, "input") \ + V(inputs_string, "inputs") \ V(internal_binding_string, "internalBinding") \ V(internal_string, "internal") \ V(ipv4_string, "IPv4") \ @@ -279,6 +285,7 @@ V(parse_error_string, "Parse Error") \ V(password_string, "password") \ V(path_string, "path") \ + V(pathname_string, "pathname") \ V(pending_handle_string, "pendingHandle") \ V(permission_string, "permission") \ V(pid_string, "pid") \ @@ -294,6 +301,7 @@ V(priority_string, "priority") \ V(process_string, "process") \ V(promise_string, "promise") \ + V(protocol_string, "protocol") \ V(prototype_string, "prototype") \ V(psk_string, "psk") \ V(pubkey_string, "pubkey") \ @@ -321,6 +329,7 @@ V(scheme_string, "scheme") \ V(scopeid_string, "scopeid") \ V(script_name_string, "scriptName") \ + V(search_string, "search") \ V(serial_number_string, "serialNumber") \ V(serial_string, "serial") \ V(servername_string, "servername") \ diff --git a/src/node_binding.cc b/src/node_binding.cc index c2ef9b36d5b296..e93f3312cc6425 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -4,6 +4,7 @@ #include "node_builtins.h" #include "node_errors.h" #include "node_external_reference.h" +#include "node_url_pattern.h" #include "util.h" #include @@ -87,6 +88,7 @@ V(types) \ V(udp_wrap) \ V(url) \ + V(url_pattern) \ V(util) \ V(uv) \ V(v8) \ diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 8d49a119c21832..3976a0e9fb23d4 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -180,6 +180,7 @@ class ExternalReferenceRegistry { V(tty_wrap) \ V(udp_wrap) \ V(url) \ + V(url_pattern) \ V(util) \ V(pipe_wrap) \ V(sea) \ diff --git a/src/node_url_pattern.cc b/src/node_url_pattern.cc new file mode 100644 index 00000000000000..b23b2c2a424457 --- /dev/null +++ b/src/node_url_pattern.cc @@ -0,0 +1,632 @@ +#include "node_url_pattern.h" +#include "base_object-inl.h" +#include "debug_utils-inl.h" +#include "env-inl.h" +#include "memory_tracker-inl.h" +#include "node.h" +#include "node_errors.h" +#include "node_mem-inl.h" +#include "path.h" +#include "util-inl.h" + +namespace node::url_pattern { + +using v8::Array; +using v8::Context; +using v8::DontDelete; +using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; +using v8::Isolate; +using v8::Local; +using v8::LocalVector; +using v8::MaybeLocal; +using v8::Name; +using v8::Object; +using v8::PropertyAttribute; +using v8::ReadOnly; +using v8::String; +using v8::Value; + +URLPattern::URLPattern(Environment* env, + Local object, + ada::url_pattern&& url_pattern) + : BaseObject(env, object), url_pattern_(std::move(url_pattern)) { + MakeWeak(); +} + +void URLPattern::MemoryInfo(MemoryTracker* tracker) const { + // TODO(anonrig): Implement this. +} + +void URLPattern::New(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + CHECK(args.IsConstructCall()); + + // If no arguments are passed, then we parse the empty URLPattern. + if (args.Length() == 0) { + auto url_pattern = parse_url_pattern(ada::url_pattern_init{}); + CHECK(url_pattern); + new URLPattern(env, args.This(), std::move(*url_pattern)); + return; + } + + std::optional init{}; + std::optional input{}; + std::optional base_url{}; + std::optional options{}; + + // Following patterns are supported: + // - new URLPattern(input) + // - new URLPattern(input, baseURL) + // - new URLPattern(input, options) + // - new URLPattern(input, baseURL, options) + if (args[0]->IsString()) { + BufferValue input_buffer(env->isolate(), args[0]); + CHECK_NOT_NULL(*input_buffer); + input = input_buffer.ToString(); + } else if (args[0]->IsObject()) { + init = URLPatternInit::FromJsObject(env, args[0].As()); + } else { + env->ThrowTypeError("input must be an object or a string."); + return; + } + + // The next argument can be baseURL or options. + if (args.Length() > 1) { + if (args[1]->IsString()) { + BufferValue base_url_buffer(env->isolate(), args[1]); + CHECK_NOT_NULL(*base_url_buffer); + base_url = base_url_buffer.ToString(); + } else if (args[1]->IsObject()) { + CHECK(!options.has_value()); + options = URLPatternOptions::FromJsObject(env, args[0].As()); + } else { + env->ThrowTypeError("baseURL or options must be provided"); + return; + } + + // Only remaining argument can be options. + if (args.Length() > 2) { + if (!args[2]->IsObject()) { + THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object"); + return; + } + CHECK(!options.has_value()); + options = URLPatternOptions::FromJsObject(env, args[2].As()); + } + } + + // Either url_pattern_init or input as a string must be provided. + CHECK_IMPLIES(init.has_value(), !input.has_value()); + + tl::expected url_pattern; + + std::string_view base_url_view{}; + if (base_url) base_url_view = {base_url->data(), base_url->size()}; + if (init.has_value()) { + url_pattern = + parse_url_pattern(*init, + base_url ? &base_url_view : nullptr, + options.has_value() ? &options.value() : nullptr); + } else { + url_pattern = + parse_url_pattern(*input, + base_url ? &base_url_view : nullptr, + options.has_value() ? &options.value() : nullptr); + } + + if (!url_pattern) { + env->ThrowTypeError("Failed to construct URLPattern"); + return; + } + + new URLPattern(env, args.This(), std::move(*url_pattern)); +} + +MaybeLocal URLPattern::URLPatternInit::ToJsObject( + Environment* env, const ada::url_pattern_init& init) { + auto isolate = env->isolate(); + auto context = env->context(); + auto result = Object::New(isolate); + if (init.protocol) { + USE(result->Set(context, + env->protocol_string(), + ToV8Value(context, *init.protocol).ToLocalChecked())); + } + if (init.username) { + USE(result->Set(context, + env->username_string(), + ToV8Value(context, *init.username).ToLocalChecked())); + } + if (init.password) { + USE(result->Set(context, + env->password_string(), + ToV8Value(context, *init.password).ToLocalChecked())); + } + if (init.hostname) { + USE(result->Set(context, + env->hostname_string(), + ToV8Value(context, *init.hostname).ToLocalChecked())); + } + if (init.port) { + USE(result->Set(context, + env->port_string(), + ToV8Value(context, *init.port).ToLocalChecked())); + } + if (init.pathname) { + USE(result->Set(context, + env->pathname_string(), + ToV8Value(context, *init.pathname).ToLocalChecked())); + } + if (init.search) { + USE(result->Set(context, + env->search_string(), + ToV8Value(context, *init.search).ToLocalChecked())); + } + if (init.hash) { + USE(result->Set(context, + env->hash_string(), + ToV8Value(context, *init.hash).ToLocalChecked())); + } + if (init.base_url) { + USE(result->Set(context, + env->base_url_string(), + ToV8Value(context, *init.base_url).ToLocalChecked())); + } + return result; +} + +ada::url_pattern_init URLPattern::URLPatternInit::FromJsObject( + Environment* env, Local obj) { + ada::url_pattern_init init{}; + Local components[] = { + env->protocol_string(), + env->username_string(), + env->password_string(), + env->hostname_string(), + env->port_string(), + env->pathname_string(), + env->search_string(), + env->hash_string(), + env->base_url_string(), + }; + Local value; + auto isolate = env->isolate(); + auto set_parameter = [&](Local component, + std::string_view utf8_value) { + // TODO(anonrig): Optimization opportunity. + // Get rid of calling env->xxx_string() for every component match. + if (component == env->protocol_string()) { + init.protocol = std::string(utf8_value); + } else if (component == env->username_string()) { + init.username = std::string(utf8_value); + } else if (component == env->password_string()) { + init.password = std::string(utf8_value); + } else if (component == env->hostname_string()) { + init.hostname = std::string(utf8_value); + } else if (component == env->port_string()) { + init.port = std::string(utf8_value); + } else if (component == env->pathname_string()) { + init.pathname = std::string(utf8_value); + } else if (component == env->search_string()) { + init.search = std::string(utf8_value); + } else if (component == env->hash_string()) { + init.hash = std::string(utf8_value); + } else if (component == env->base_url_string()) { + init.base_url = std::string(utf8_value); + } + }; + for (const auto& component : components) { + if (obj->Get(env->context(), component).ToLocal(&value)) { + if (value->IsString()) { + Utf8Value utf8_value(isolate, value); + set_parameter(component, utf8_value.ToStringView()); + } + } + } + return init; +} + +Local URLPattern::URLPatternComponentResult::ToJSObject( + Environment* env, const ada::url_pattern_component_result& result) { + auto isolate = env->isolate(); + auto context = env->context(); + const auto parse_groups = + [&](std::unordered_map groups) { + // TODO(@anonrig): Use predefined object constructor to avoid calling + // Set on each key. + auto res = Object::New(isolate); + for (const auto& group : groups) { + USE(res->Set(context, + ToV8Value(context, group.first).ToLocalChecked(), + ToV8Value(context, group.second).ToLocalChecked())); + } + return res; + }; + Local names[] = {env->input_string(), env->groups_string()}; + Local values[] = { + ToV8Value(env->context(), result.input).ToLocalChecked(), + parse_groups(result.groups), + }; + DCHECK_EQ(arraysize(names), arraysize(values)); + return Object::New( + isolate, Object::New(isolate), names, values, arraysize(names)); +} + +Local URLPattern::URLPatternResult::ToJSObject( + Environment* env, const ada::url_pattern_result& result) { + auto isolate = env->isolate(); + Local names[] = { + env->inputs_string(), + env->protocol_string(), + env->username_string(), + env->password_string(), + env->hostname_string(), + env->port_string(), + env->pathname_string(), + env->search_string(), + env->hash_string(), + }; + LocalVector inputs(isolate, result.inputs.size()); + size_t index = 0; + for (auto& input : result.inputs) { + if (std::holds_alternative(input)) { + auto input_str = std::get(input); + inputs[index] = ToV8Value(env->context(), input_str).ToLocalChecked(); + } else { + DCHECK(std::holds_alternative(input)); + auto init = std::get(input); + inputs[index] = URLPatternInit::ToJsObject(env, init).ToLocalChecked(); + } + index++; + } + Local values[] = { + Array::New(isolate, inputs.data(), inputs.size()), + URLPatternComponentResult::ToJSObject(env, result.protocol), + URLPatternComponentResult::ToJSObject(env, result.username), + URLPatternComponentResult::ToJSObject(env, result.password), + URLPatternComponentResult::ToJSObject(env, result.hostname), + URLPatternComponentResult::ToJSObject(env, result.port), + URLPatternComponentResult::ToJSObject(env, result.pathname), + URLPatternComponentResult::ToJSObject(env, result.search), + URLPatternComponentResult::ToJSObject(env, result.hash), + }; + DCHECK_EQ(arraysize(names), arraysize(values)); + return Object::New( + isolate, Object::New(isolate), names, values, arraysize(names)); +} + +ada::url_pattern_options URLPattern::URLPatternOptions::FromJsObject( + Environment* env, Local obj) { + ada::url_pattern_options options{}; + Local ignore_case; + if (obj->Get(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "ignoreCase")) + .ToLocal(&ignore_case)) { + options.ignore_case = ignore_case->IsTrue(); + } + return options; +} + +MaybeLocal URLPattern::Hash() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_hash()); +} + +MaybeLocal URLPattern::Hostname() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_hostname()); +} + +MaybeLocal URLPattern::Password() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_password()); +} + +MaybeLocal URLPattern::Pathname() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_pathname()); +} + +MaybeLocal URLPattern::Port() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_port()); +} + +MaybeLocal URLPattern::Protocol() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_protocol()); +} + +MaybeLocal URLPattern::Search() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_search()); +} + +MaybeLocal URLPattern::Username() const { + auto context = env()->context(); + return ToV8Value(context, url_pattern_.get_username()); +} + +bool URLPattern::HasRegExpGroups() const { + return url_pattern_.has_regexp_groups(); +} + +// Instance methods + +MaybeLocal URLPattern::Exec(Environment* env, + const ada::url_pattern_input& input, + std::optional* baseURL) { + if (auto result = + url_pattern_.exec(input, baseURL ? &baseURL->value() : nullptr)) { + if (result->has_value()) { + return URLPatternResult::ToJSObject(env, result->value()); + } + return Null(env->isolate()); + } + env->ThrowTypeError("Failed to exec URLPattern"); + return {}; +} + +bool URLPattern::Test(Environment* env, + const ada::url_pattern_input& input, + std::optional* baseURL) { + if (auto result = + url_pattern_.test(input, baseURL ? &baseURL->value() : nullptr)) { + return *result; + } + env->ThrowTypeError("Failed to test URLPattern"); + return false; +} + +// V8 Methods + +void URLPattern::Exec(const FunctionCallbackInfo& args) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, args.This()); + if (args.Length() == 0) { // input, [baseURL] + return args.GetReturnValue().SetNull(); + } + auto env = Environment::GetCurrent(args); + + ada::url_pattern_input input; + std::optional baseURL{}; + std::string input_base; + if (args[0]->IsString()) { + Utf8Value input_value(env->isolate(), args[0].As()); + input_base = input_value.ToString(); + input = std::string_view(input_base); + } else if (args[0]->IsObject()) { + input = URLPatternInit::FromJsObject(env, args[0].As()); + } else { + THROW_ERR_INVALID_ARG_TYPE( + env, "URLPattern input needs to be a string or an object"); + return; + } + + if (args.Length() > 1 && args[1]->IsString()) { + Utf8Value base_url_value(env->isolate(), args[1].As()); + baseURL = base_url_value.ToStringView(); + } + + Local result; + std::optional baseURL_opt = + baseURL ? std::optional(*baseURL) : std::nullopt; + if (!url_pattern->Exec(env, input, baseURL_opt).ToLocal(&result)) { + return; + } + args.GetReturnValue().Set(result); +} + +void URLPattern::Test(const FunctionCallbackInfo& args) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, args.This()); + if (args.Length() == 0) { // input, [baseURL] + return args.GetReturnValue().Set(false); + } + auto env = Environment::GetCurrent(args); + + ada::url_pattern_input input; + std::optional baseURL{}; + std::string input_base; + if (args[0]->IsString()) { + Utf8Value input_value(env->isolate(), args[0].As()); + input_base = input_value.ToString(); + input = std::string_view(input_base); + } else if (args[0]->IsObject()) { + input = URLPatternInit::FromJsObject(env, args[0].As()); + } else { + THROW_ERR_INVALID_ARG_TYPE( + env, "URLPattern input needs to be a string or an object"); + return; + } + + if (args.Length() > 1 && args[1]->IsString()) { + Utf8Value base_url_value(env->isolate(), args[1].As()); + baseURL = base_url_value.ToStringView(); + } + + std::optional baseURL_opt = + baseURL ? std::optional(*baseURL) : std::nullopt; + args.GetReturnValue().Set(url_pattern->Test(env, input, baseURL_opt)); +} + +void URLPattern::Protocol(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Protocol().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Username(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Username().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Password(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Password().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Hostname(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Hostname().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Port(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Port().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Pathname(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Pathname().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Search(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Search().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::Hash(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + Local result; + if (!url_pattern->Hash().ToLocal(&result)) { + return; + } + info.GetReturnValue().Set(result); +} + +void URLPattern::HasRegexpGroups(const FunctionCallbackInfo& info) { + URLPattern* url_pattern; + ASSIGN_OR_RETURN_UNWRAP(&url_pattern, info.This()); + info.GetReturnValue().Set(url_pattern->HasRegExpGroups()); +} + +static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(URLPattern::New); + registry->Register(URLPattern::Protocol); + registry->Register(URLPattern::Username); + registry->Register(URLPattern::Password); + registry->Register(URLPattern::Hostname); + registry->Register(URLPattern::Port); + registry->Register(URLPattern::Pathname); + registry->Register(URLPattern::Search); + registry->Register(URLPattern::Hash); + registry->Register(URLPattern::HasRegexpGroups); + registry->Register(URLPattern::Exec); + registry->Register(URLPattern::Test); +} + +static void Initialize(Local target, + Local unused, + Local context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + Isolate* isolate = env->isolate(); + auto attributes = static_cast(ReadOnly | DontDelete); + auto ctor_tmpl = NewFunctionTemplate(isolate, URLPattern::New); + auto instance_template = ctor_tmpl->InstanceTemplate(); + auto prototype_template = ctor_tmpl->PrototypeTemplate(); + ctor_tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "URLPattern")); + + instance_template->SetInternalFieldCount(URLPattern::kInternalFieldCount); + prototype_template->SetAccessorProperty( + env->protocol_string(), + FunctionTemplate::New(isolate, URLPattern::Protocol), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->username_string(), + FunctionTemplate::New(isolate, URLPattern::Username), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->password_string(), + FunctionTemplate::New(isolate, URLPattern::Password), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->hostname_string(), + FunctionTemplate::New(isolate, URLPattern::Hostname), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->port_string(), + FunctionTemplate::New(isolate, URLPattern::Port), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->pathname_string(), + FunctionTemplate::New(isolate, URLPattern::Pathname), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->search_string(), + FunctionTemplate::New(isolate, URLPattern::Search), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->hash_string(), + FunctionTemplate::New(isolate, URLPattern::Hash), + Local(), + attributes); + + prototype_template->SetAccessorProperty( + env->has_regexp_groups_string(), + FunctionTemplate::New(isolate, URLPattern::HasRegexpGroups), + Local(), + attributes); + + SetProtoMethodNoSideEffect(isolate, ctor_tmpl, "exec", URLPattern::Exec); + SetProtoMethodNoSideEffect(isolate, ctor_tmpl, "test", URLPattern::Test); + SetConstructorFunction(context, target, "URLPattern", ctor_tmpl); +} + +} // namespace node::url_pattern + +NODE_BINDING_CONTEXT_AWARE_INTERNAL(url_pattern, node::url_pattern::Initialize) +NODE_BINDING_EXTERNAL_REFERENCE(url_pattern, + node::url_pattern::RegisterExternalReferences) diff --git a/src/node_url_pattern.h b/src/node_url_pattern.h new file mode 100644 index 00000000000000..8a57e393913d26 --- /dev/null +++ b/src/node_url_pattern.h @@ -0,0 +1,88 @@ +#ifndef SRC_NODE_URL_PATTERN_H_ +#define SRC_NODE_URL_PATTERN_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "ada.h" +#include "base_object.h" +#include "node_mem.h" +#include "util.h" + +namespace node::url_pattern { + +class URLPattern : public BaseObject { + public: + URLPattern(Environment* env, + v8::Local object, + ada::url_pattern&& url_pattern); + + void MemoryInfo(MemoryTracker* tracker) const override; + static void New(const v8::FunctionCallbackInfo& args); + + // V8 APIs + static void Exec(const v8::FunctionCallbackInfo& info); + static void Test(const v8::FunctionCallbackInfo& info); + + static void Hash(const v8::FunctionCallbackInfo& info); + static void Hostname(const v8::FunctionCallbackInfo& info); + static void Password(const v8::FunctionCallbackInfo& info); + static void Pathname(const v8::FunctionCallbackInfo& info); + static void Port(const v8::FunctionCallbackInfo& info); + static void Protocol(const v8::FunctionCallbackInfo& info); + static void Search(const v8::FunctionCallbackInfo& info); + static void Username(const v8::FunctionCallbackInfo& info); + static void HasRegexpGroups(const v8::FunctionCallbackInfo& info); + + SET_MEMORY_INFO_NAME(URLPattern) + SET_SELF_SIZE(URLPattern) + + class URLPatternInit { + public: + static ada::url_pattern_init FromJsObject(Environment* env, + v8::Local obj); + static v8::MaybeLocal ToJsObject( + Environment* env, const ada::url_pattern_init& init); + }; + + class URLPatternOptions { + public: + static ada::url_pattern_options FromJsObject(Environment* env, + v8::Local obj); + }; + + class URLPatternResult { + public: + static v8::Local ToJSObject( + Environment* env, const ada::url_pattern_result& result); + }; + + class URLPatternComponentResult { + public: + static v8::Local ToJSObject( + Environment* env, const ada::url_pattern_component_result& result); + }; + + private: + ada::url_pattern url_pattern_; + // Getter methods + v8::MaybeLocal Hash() const; + v8::MaybeLocal Hostname() const; + v8::MaybeLocal Password() const; + v8::MaybeLocal Pathname() const; + v8::MaybeLocal Port() const; + v8::MaybeLocal Protocol() const; + v8::MaybeLocal Search() const; + v8::MaybeLocal Username() const; + bool HasRegExpGroups() const; + v8::MaybeLocal Exec(Environment* env, + const ada::url_pattern_input& input, + std::optional* baseURL); + bool Test(Environment* env, + const ada::url_pattern_input& input, + std::optional* baseURL); +}; + +} // namespace node::url_pattern + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#endif // SRC_NODE_URL_PATTERN_H_ diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index cc97c8787a2c98..67955f0ae6a07e 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -29,6 +29,7 @@ Last update: - resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources - streams: https://github.com/web-platform-tests/wpt/tree/bc9dcbbf1a/streams - url: https://github.com/web-platform-tests/wpt/tree/6fa3fe8a92/url +- urlpattern: https://github.com/web-platform-tests/wpt/tree/1b56d89a26/urlpattern - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi diff --git a/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml b/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml new file mode 100644 index 00000000000000..cb82ba5cda2918 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: urlpattern + files: "**" diff --git a/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-test-data.json b/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-test-data.json new file mode 100644 index 00000000000000..0043ac08bca554 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-test-data.json @@ -0,0 +1,152 @@ +[ + { + "component": "pathname", + "left": { "pathname": "/foo/a" }, + "right": { "pathname": "/foo/b" }, + "expected": -1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/b" }, + "right": { "pathname": "/foo/bar" }, + "expected": -1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/bar" }, + "right": { "pathname": "/foo/:bar" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/" }, + "right": { "pathname": "/foo/:bar" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/:bar" }, + "right": { "pathname": "/foo/*" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/{bar}" }, + "right": { "pathname": "/foo/(bar)" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/{bar}" }, + "right": { "pathname": "/foo/{bar}+" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/{bar}+" }, + "right": { "pathname": "/foo/{bar}?" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/{bar}?" }, + "right": { "pathname": "/foo/{bar}*" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/(123)" }, + "right": { "pathname": "/foo/(12)" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/:b" }, + "right": { "pathname": "/foo/:a" }, + "expected": 0 + }, + { + "component": "pathname", + "left": { "pathname": "*/foo" }, + "right": { "pathname": "*" }, + "expected": 1 + }, + { + "component": "port", + "left": { "port": "9" }, + "right": { "port": "100" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "foo/:bar?/baz" }, + "right": { "pathname": "foo/{:bar}?/baz" }, + "expected": -1 + }, + { + "component": "pathname", + "left": { "pathname": "foo/:bar?/baz" }, + "right": { "pathname": "foo{/:bar}?/baz" }, + "expected": 0 + }, + { + "component": "pathname", + "left": { "pathname": "foo/:bar?/baz" }, + "right": { "pathname": "fo{o/:bar}?/baz" }, + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "foo/:bar?/baz" }, + "right": { "pathname": "foo{/:bar/}?baz" }, + "expected": -1 + }, + { + "component": "pathname", + "left": "https://a.example.com/b?a", + "right": "https://b.example.com/a?b", + "expected": 1 + }, + { + "component": "pathname", + "left": { "pathname": "/foo/{bar}/baz" }, + "right": { "pathname": "/foo/bar/baz" }, + "expected": 0 + }, + { + "component": "protocol", + "left": { "protocol": "a" }, + "right": { "protocol": "b" }, + "expected": -1 + }, + { + "component": "username", + "left": { "username": "a" }, + "right": { "username": "b" }, + "expected": -1 + }, + { + "component": "password", + "left": { "password": "a" }, + "right": { "password": "b" }, + "expected": -1 + }, + { + "component": "hostname", + "left": { "hostname": "a" }, + "right": { "hostname": "b" }, + "expected": -1 + }, + { + "component": "search", + "left": { "search": "a" }, + "right": { "search": "b" }, + "expected": -1 + }, + { + "component": "hash", + "left": { "hash": "a" }, + "right": { "hash": "b" }, + "expected": -1 + } +] diff --git a/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-tests.tentative.js b/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-tests.tentative.js new file mode 100644 index 00000000000000..b92b53ee45cd98 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/resources/urlpattern-compare-tests.tentative.js @@ -0,0 +1,26 @@ +function runTests(data) { + for (let entry of data) { + test(function() { + const left = new URLPattern(entry.left); + const right = new URLPattern(entry.right); + + assert_equals(URLPattern.compareComponent(entry.component, left, right), entry.expected); + + // We have to coerce to an integer here in order to avoid asserting + // that `+0` is `-0`. + const reverse_expected = ~~(entry.expected * -1); + assert_equals(URLPattern.compareComponent(entry.component, right, left), reverse_expected, "reverse order"); + + assert_equals(URLPattern.compareComponent(entry.component, left, left), 0, "left equality"); + assert_equals(URLPattern.compareComponent(entry.component, right, right), 0, "right equality"); + }, `Component: ${entry.component} ` + + `Left: ${JSON.stringify(entry.left)} ` + + `Right: ${JSON.stringify(entry.right)}`); + } +} + +promise_test(async function() { + const response = await fetch('resources/urlpattern-compare-test-data.json'); + const data = await response.json(); + runTests(data); +}, 'Loading data...'); diff --git a/test/fixtures/wpt/urlpattern/resources/urlpattern-hasregexpgroups-tests.js b/test/fixtures/wpt/urlpattern/resources/urlpattern-hasregexpgroups-tests.js new file mode 100644 index 00000000000000..4be886e4a5390d --- /dev/null +++ b/test/fixtures/wpt/urlpattern/resources/urlpattern-hasregexpgroups-tests.js @@ -0,0 +1,18 @@ +test(() => { + assert_implements('hasRegExpGroups' in URLPattern.prototype, "hasRegExpGroups is not implemented"); + assert_false(new URLPattern({}).hasRegExpGroups, "match-everything pattern"); + for (let component of ['protocol', 'username', 'password', 'hostname', 'port', 'pathname', 'search', 'hash']) { + assert_false(new URLPattern({[component]: '*'}).hasRegExpGroups, `wildcard in ${component}`); + assert_false(new URLPattern({[component]: ':foo'}).hasRegExpGroups, `segment wildcard in ${component}`); + assert_false(new URLPattern({[component]: ':foo?'}).hasRegExpGroups, `optional segment wildcard in ${component}`); + assert_true(new URLPattern({[component]: ':foo(hi)'}).hasRegExpGroups, `named regexp group in ${component}`); + assert_true(new URLPattern({[component]: '(hi)'}).hasRegExpGroups, `anonymous regexp group in ${component}`); + if (component !== 'protocol' && component !== 'port') { + // These components are more narrow in what they accept in any case. + assert_false(new URLPattern({[component]: 'a-{:hello}-z-*-a'}).hasRegExpGroups, `wildcards mixed in with fixed text and wildcards in ${component}`); + assert_true(new URLPattern({[component]: 'a-(hi)-z-(lo)-a'}).hasRegExpGroups, `regexp groups mixed in with fixed text and wildcards in ${component}`); + } + } + assert_false(new URLPattern({pathname: '/a/:foo/:baz?/b/*'}).hasRegExpGroups, "complex pathname with no regexp"); + assert_true(new URLPattern({pathname: '/a/:foo/:baz([a-z]+)?/b/*'}).hasRegExpGroups, "complex pathname with regexp"); +}, ''); diff --git a/test/fixtures/wpt/urlpattern/resources/urlpatterntestdata.json b/test/fixtures/wpt/urlpattern/resources/urlpatterntestdata.json new file mode 100644 index 00000000000000..058079bb6d17ac --- /dev/null +++ b/test/fixtures/wpt/urlpattern/resources/urlpatterntestdata.json @@ -0,0 +1,2857 @@ +[ + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/ba" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/bar/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [ "https://example.com/foo/bar" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": { "0": "example.com" } }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": { "0": "https" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [ "https://example.com/foo/bar/baz" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar" }], + "expected_match": { + "hostname": { "input": "example.com", "groups": { "0": "example.com" } }, + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://example.com" }], + "expected_match": { + "hostname": { "input": "example.com", "groups": { "0": "example.com" } }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": { "0": "https" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/bar/baz", + "baseURL": "https://example.com" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar", "search": "otherquery", + "hash": "otherhash" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hash": { "input": "otherhash", "groups": { "0": "otherhash" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "otherquery", "groups": { "0": "otherquery" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar", "search": "otherquery", + "hash": "otherhash" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hash": { "input": "otherhash", "groups": { "0": "otherhash" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "otherquery", "groups": { "0": "otherquery" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?otherquery#otherhash" }], + "inputs": [{ "protocol": "https", "hostname": "example.com", + "pathname": "/foo/bar", "search": "otherquery", + "hash": "otherhash" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hash": { "input": "otherhash", "groups": { "0": "otherhash" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "otherquery", "groups": { "0": "otherquery" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "https://example.com/foo/bar" ], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "https://example.com/foo/bar?otherquery#otherhash" ], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hash": { "input": "otherhash", "groups": { "0": "otherhash" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "otherquery", "groups": { "0": "otherquery" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "https://example.com/foo/bar?query#hash" ], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hash": { "input": "hash", "groups": { "0": "hash" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "query", "groups": { "0": "query" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "https://example.com/foo/bar/baz" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "https://other.com/foo/bar" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [ "http://other.com/foo/bar" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://example.com" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar/baz", + "baseURL": "https://example.com" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://other.com" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar", + "baseURL": "https://example.com?query#hash" }], + "inputs": [{ "pathname": "/foo/bar", "baseURL": "http://example.com" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/([^\\/]+?)" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar" }], + "inputs": [{ "pathname": "/foo/index.html" }], + "expected_match": { + "pathname": { "input": "/foo/index.html", "groups": { "bar": "index.html" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar" }], + "inputs": [{ "pathname": "/foo/bar/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_obj": { + "pathname": "/foo/*" + }, + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_obj": { + "pathname": "/foo/*" + }, + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_obj": { + "pathname": "/foo/*" + }, + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)" }], + "inputs": [{ "pathname": "/foo" }], + "expected_obj": { + "pathname": "/foo/*" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar(.*)" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar(.*)" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar(.*)" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "bar": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar(.*)" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar?" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar?" }], + "inputs": [{ "pathname": "/foo" }], + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "bar": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar?" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar?" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar?" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar+" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar+" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar+" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar+" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar+" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar*" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar*" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar*" }], + "inputs": [{ "pathname": "/foo" }], + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "bar": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/:bar*" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/:bar*" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/foo" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "0": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/foo" }], + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "0": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)?" }], + "inputs": [{ "pathname": "/fo" }], + "expected_obj": { + "pathname": "/foo/*?" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*?" }], + "inputs": [{ "pathname": "/fo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/foo" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)+" }], + "inputs": [{ "pathname": "/fo" }], + "expected_obj": { + "pathname": "/foo/*+" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/*+" }], + "inputs": [{ "pathname": "/fo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": { + "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/foo" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "0": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/foo" }], + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "/foo", "groups": { "0": null } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": { + "pathname": { "input": "/foo/", "groups": { "0": "" } } + } + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/foobar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/(.*)*" }], + "inputs": [{ "pathname": "/fo" }], + "expected_obj": { + "pathname": "/foo/**" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/**" }], + "inputs": [{ "pathname": "/fo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}" }], + "inputs": [{ "pathname": "/foo" }], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}?" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}?" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}?" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": { + "pathname": { "input": "/foo", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}?" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}+" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}+" }], + "inputs": [{ "pathname": "/foo/bar/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}+" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}+" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}+" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}*" }], + "inputs": [{ "pathname": "/foo/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}*" }], + "inputs": [{ "pathname": "/foo/bar/bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar/bar", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}*" }], + "inputs": [{ "pathname": "/foo/bar/baz" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo{/bar}*" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": { + "pathname": { "input": "/foo", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/foo{/bar}*" }], + "inputs": [{ "pathname": "/foo/" }], + "expected_match": null + }, + { + "pattern": [{ "protocol": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "username": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "password": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "pathname": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "search": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hash": "(café)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "protocol": ":café" }], + "inputs": [{ "protocol": "foo" }], + "expected_match": { + "protocol": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "username": ":café" }], + "inputs": [{ "username": "foo" }], + "expected_match": { + "username": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "password": ":café" }], + "inputs": [{ "password": "foo" }], + "expected_match": { + "password": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "hostname": ":café" }], + "inputs": [{ "hostname": "foo" }], + "expected_match": { + "hostname": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "pathname": "/:café" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": { + "pathname": { "input": "/foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "search": ":café" }], + "inputs": [{ "search": "foo" }], + "expected_match": { + "search": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "hash": ":café" }], + "inputs": [{ "hash": "foo" }], + "expected_match": { + "hash": { "input": "foo", "groups": { "café": "foo" } } + } + }, + { + "pattern": [{ "protocol": ":\u2118" }], + "inputs": [{ "protocol": "foo" }], + "expected_match": { + "protocol": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "username": ":\u2118" }], + "inputs": [{ "username": "foo" }], + "expected_match": { + "username": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "password": ":\u2118" }], + "inputs": [{ "password": "foo" }], + "expected_match": { + "password": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "hostname": ":\u2118" }], + "inputs": [{ "hostname": "foo" }], + "expected_match": { + "hostname": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "pathname": "/:\u2118" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": { + "pathname": { "input": "/foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "search": ":\u2118" }], + "inputs": [{ "search": "foo" }], + "expected_match": { + "search": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "hash": ":\u2118" }], + "inputs": [{ "hash": "foo" }], + "expected_match": { + "hash": { "input": "foo", "groups": { "\u2118": "foo" } } + } + }, + { + "pattern": [{ "protocol": ":\u3400" }], + "inputs": [{ "protocol": "foo" }], + "expected_match": { + "protocol": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "username": ":\u3400" }], + "inputs": [{ "username": "foo" }], + "expected_match": { + "username": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "password": ":\u3400" }], + "inputs": [{ "password": "foo" }], + "expected_match": { + "password": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "hostname": ":\u3400" }], + "inputs": [{ "hostname": "foo" }], + "expected_match": { + "hostname": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "pathname": "/:\u3400" }], + "inputs": [{ "pathname": "/foo" }], + "expected_match": { + "pathname": { "input": "/foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "search": ":\u3400" }], + "inputs": [{ "search": "foo" }], + "expected_match": { + "search": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "hash": ":\u3400" }], + "inputs": [{ "hash": "foo" }], + "expected_match": { + "hash": { "input": "foo", "groups": { "\u3400": "foo" } } + } + }, + { + "pattern": [{ "protocol": "(.*)" }], + "inputs": [{ "protocol" : "café" }], + "expected_obj": { + "protocol": "*" + }, + "expected_match": null + }, + { + "pattern": [{ "protocol": "(.*)" }], + "inputs": [{ "protocol": "cafe" }], + "expected_obj": { + "protocol": "*" + }, + "expected_match": { + "protocol": { "input": "cafe", "groups": { "0": "cafe" }} + } + }, + { + "pattern": [{ "protocol": "foo-bar" }], + "inputs": [{ "protocol": "foo-bar" }], + "expected_match": { + "protocol": { "input": "foo-bar", "groups": {} } + } + }, + { + "pattern": [{ "username": "caf%C3%A9" }], + "inputs": [{ "username" : "café" }], + "expected_match": { + "username": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "username": "café" }], + "inputs": [{ "username" : "café" }], + "expected_obj": { + "username": "caf%C3%A9" + }, + "expected_match": { + "username": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "username": "caf%c3%a9" }], + "inputs": [{ "username" : "café" }], + "expected_match": null + }, + { + "pattern": [{ "password": "caf%C3%A9" }], + "inputs": [{ "password" : "café" }], + "expected_match": { + "password": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "password": "café" }], + "inputs": [{ "password" : "café" }], + "expected_obj": { + "password": "caf%C3%A9" + }, + "expected_match": { + "password": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "password": "caf%c3%a9" }], + "inputs": [{ "password" : "café" }], + "expected_match": null + }, + { + "pattern": [{ "hostname": "xn--caf-dma.com" }], + "inputs": [{ "hostname" : "café.com" }], + "expected_match": { + "hostname": { "input": "xn--caf-dma.com", "groups": {}} + } + }, + { + "pattern": [{ "hostname": "café.com" }], + "inputs": [{ "hostname" : "café.com" }], + "expected_obj": { + "hostname": "xn--caf-dma.com" + }, + "expected_match": { + "hostname": { "input": "xn--caf-dma.com", "groups": {}} + } + }, + { + "pattern": [{ "port": "" }], + "inputs": [{ "protocol": "http", "port": "80" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "protocol": { "input": "http", "groups": { "0": "http" }} + } + }, + { + "pattern": [{ "protocol": "http", "port": "80" }], + "inputs": [{ "protocol": "http", "port": "80" }], + "exactly_empty_components": [ "port" ], + "expected_match": { + "protocol": { "input": "http", "groups": {}} + } + }, + { + "pattern": [{ "protocol": "http", "port": "80{20}?" }], + "inputs": [{ "protocol": "http", "port": "80" }], + "expected_match": null + }, + { + "pattern": [{ "protocol": "http", "port": "80 " }], + "inputs": [{ "protocol": "http", "port": "80" }], + "expected_obj": "error" + }, + { + "pattern": [{ "port": "80" }], + "inputs": [{ "protocol": "http", "port": "80" }], + "expected_match": null + }, + { + "pattern": [{ "protocol": "http{s}?", "port": "80" }], + "inputs": [{ "protocol": "http", "port": "80" }], + "expected_match": null + }, + { + "pattern": [{ "port": "80" }], + "inputs": [{ "port": "80" }], + "expected_match": { + "port": { "input": "80", "groups": {}} + } + }, + { + "pattern": [{ "port": "(.*)" }], + "inputs": [{ "port": "invalid80" }], + "expected_obj": { + "port": "*" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "/foo/./bar" }], + "expected_match": { + "pathname": { "input": "/foo/bar", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo/baz" }], + "inputs": [{ "pathname": "/foo/bar/../baz" }], + "expected_match": { + "pathname": { "input": "/foo/baz", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/caf%C3%A9" }], + "inputs": [{ "pathname": "/café" }], + "expected_match": { + "pathname": { "input": "/caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/café" }], + "inputs": [{ "pathname": "/café" }], + "expected_obj": { + "pathname": "/caf%C3%A9" + }, + "expected_match": { + "pathname": { "input": "/caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/caf%c3%a9" }], + "inputs": [{ "pathname": "/café" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "foo/bar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }], + "expected_match": { + "protocol": { "input": "https", "groups": { "0": "https" }}, + "hostname": { "input": "example.com", "groups": { "0": "example.com" }}, + "pathname": { "input": "/foo/bar", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo/../bar" }], + "inputs": [{ "pathname": "/bar" }], + "expected_obj": { + "pathname": "/bar" + }, + "expected_match": { + "pathname": { "input": "/bar", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "./foo/bar", "baseURL": "https://example.com" }], + "inputs": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {}}, + "hostname": { "input": "example.com", "groups": {}}, + "pathname": { "input": "/foo/bar", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "", "baseURL": "https://example.com" }], + "inputs": [{ "pathname": "/", "baseURL": "https://example.com" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {}}, + "hostname": { "input": "example.com", "groups": {}}, + "pathname": { "input": "/", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "{/bar}", "baseURL": "https://example.com/foo/" }], + "inputs": [{ "pathname": "./bar", "baseURL": "https://example.com/foo/" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/bar" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "\\/bar", "baseURL": "https://example.com/foo/" }], + "inputs": [{ "pathname": "./bar", "baseURL": "https://example.com/foo/" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/bar" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "b", "baseURL": "https://example.com/foo/" }], + "inputs": [{ "pathname": "./b", "baseURL": "https://example.com/foo/" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/foo/b" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {}}, + "hostname": { "input": "example.com", "groups": {}}, + "pathname": { "input": "/foo/b", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "foo/bar" }], + "inputs": [ "https://example.com/foo/bar" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }], + "inputs": [ "https://example.com/foo/bar" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/foo/bar" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {}}, + "hostname": { "input": "example.com", "groups": {}}, + "pathname": { "input": "/foo/bar", "groups": {}} + } + }, + { + "pattern": [{ "pathname": ":name.html", "baseURL": "https://example.com" }], + "inputs": [ "https://example.com/foo.html"] , + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/:name.html" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {}}, + "hostname": { "input": "example.com", "groups": {}}, + "pathname": { "input": "/foo.html", "groups": { "name": "foo" }} + } + }, + { + "pattern": [{ "search": "q=caf%C3%A9" }], + "inputs": [{ "search": "q=café" }], + "expected_match": { + "search": { "input": "q=caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "search": "q=café" }], + "inputs": [{ "search": "q=café" }], + "expected_obj": { + "search": "q=caf%C3%A9" + }, + "expected_match": { + "search": { "input": "q=caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "search": "q=caf%c3%a9" }], + "inputs": [{ "search": "q=café" }], + "expected_match": null + }, + { + "pattern": [{ "hash": "caf%C3%A9" }], + "inputs": [{ "hash": "café" }], + "expected_match": { + "hash": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "hash": "café" }], + "inputs": [{ "hash": "café" }], + "expected_obj": { + "hash": "caf%C3%A9" + }, + "expected_match": { + "hash": { "input": "caf%C3%A9", "groups": {}} + } + }, + { + "pattern": [{ "hash": "caf%c3%a9" }], + "inputs": [{ "hash": "café" }], + "expected_match": null + }, + { + "pattern": [{ "protocol": "about", "pathname": "(blank|sourcedoc)" }], + "inputs": [ "about:blank" ], + "expected_match": { + "protocol": { "input": "about", "groups": {}}, + "pathname": { "input": "blank", "groups": { "0": "blank" }} + } + }, + { + "pattern": [{ "protocol": "data", "pathname": ":number([0-9]+)" }], + "inputs": [ "data:8675309" ], + "expected_match": { + "protocol": { "input": "data", "groups": {}}, + "pathname": { "input": "8675309", "groups": { "number": "8675309" }} + } + }, + { + "pattern": [{ "pathname": "/(\\m)" }], + "expected_obj": "error" + }, + { + "pattern": [{ "pathname": "/foo!" }], + "inputs": [{ "pathname": "/foo!" }], + "expected_match": { + "pathname": { "input": "/foo!", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo\\:" }], + "inputs": [{ "pathname": "/foo:" }], + "expected_match": { + "pathname": { "input": "/foo:", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo\\{" }], + "inputs": [{ "pathname": "/foo{" }], + "expected_obj": { + "pathname": "/foo%7B" + }, + "expected_match": { + "pathname": { "input": "/foo%7B", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo\\(" }], + "inputs": [{ "pathname": "/foo(" }], + "expected_match": { + "pathname": { "input": "/foo(", "groups": {}} + } + }, + { + "pattern": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "expected_match": { + "protocol": { "input": "javascript", "groups": {}}, + "pathname": { "input": "var x = 1;", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "var x = 1;" }], + "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "expected_obj": { + "pathname": "var%20x%20=%201;" + }, + "expected_match": null + }, + { + "pattern": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "inputs": [{ "baseURL": "javascript:var x = 1;" }], + "expected_match": { + "protocol": { "input": "javascript", "groups": {}}, + "pathname": { "input": "var x = 1;", "groups": {}} + } + }, + { + "pattern": [{ "protocol": "(data|javascript)", "pathname": "var x = 1;" }], + "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "expected_match": { + "protocol": { "input": "javascript", "groups": {"0": "javascript"}}, + "pathname": { "input": "var x = 1;", "groups": {}} + } + }, + { + "pattern": [{ "protocol": "(https|javascript)", "pathname": "var x = 1;" }], + "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }], + "expected_obj": { + "pathname": "var%20x%20=%201;" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "var x = 1;" }], + "inputs": [{ "pathname": "var x = 1;" }], + "expected_obj": { + "pathname": "var%20x%20=%201;" + }, + "expected_match": { + "pathname": { "input": "var%20x%20=%201;", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [ "./foo/bar", "https://example.com" ], + "expected_match": { + "hostname": { "input": "example.com", "groups": { "0": "example.com" } }, + "pathname": { "input": "/foo/bar", "groups": {} }, + "protocol": { "input": "https", "groups": { "0": "https" } } + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }], + "inputs": [ { "pathname": "/foo/bar" }, "https://example.com" ], + "expected_match": "error" + }, + { + "pattern": [ "https://example.com:8080/foo?bar#baz" ], + "inputs": [{ "pathname": "/foo", "search": "bar", "hash": "baz", + "baseURL": "https://example.com:8080" }], + "expected_obj": { + "protocol": "https", + "username": "*", + "password": "*", + "hostname": "example.com", + "port": "8080", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "search": { "input": "bar", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [ "/foo?bar#baz", "https://example.com:8080" ], + "inputs": [{ "pathname": "/foo", "search": "bar", "hash": "baz", + "baseURL": "https://example.com:8080" }], + "expected_obj": { + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "search": { "input": "bar", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [ "/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "example.com/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "http{s}?://{*.}?example.com/:product/:endpoint" ], + "inputs": [ "https://sub.example.com/foo/bar" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http{s}?", + "hostname": "{*.}?example.com", + "pathname": "/:product/:endpoint" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "sub.example.com", "groups": { "0": "sub" } }, + "pathname": { "input": "/foo/bar", "groups": { "product": "foo", + "endpoint": "bar" } } + } + }, + { + "pattern": [ "https://example.com?foo" ], + "inputs": [ "https://example.com/?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com#foo" ], + "inputs": [ "https://example.com/#foo" ], + "exactly_empty_components": [ "port", "search" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/", + "hash": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "hash": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com:8080?foo" ], + "inputs": [ "https://example.com:8080/?foo" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "port": "8080", + "pathname": "/", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com:8080#foo" ], + "inputs": [ "https://example.com:8080/#foo" ], + "exactly_empty_components": [ "search" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "port": "8080", + "pathname": "/", + "hash": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "hash": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/?foo" ], + "inputs": [ "https://example.com/?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/#foo" ], + "inputs": [ "https://example.com/#foo" ], + "exactly_empty_components": [ "port", "search" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/", + "hash": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "hash": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/*?foo" ], + "inputs": [ "https://example.com/?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/*?foo" + }, + "expected_match": null + }, + { + "pattern": [ "https://example.com/*\\?foo" ], + "inputs": [ "https://example.com/?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/*", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "" } }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/:name?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/:name?foo" + }, + "expected_match": null + }, + { + "pattern": [ "https://example.com/:name\\?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/:name", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/bar", "groups": { "name": "bar" } }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/(bar)?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/(bar)?foo" + }, + "expected_match": null + }, + { + "pattern": [ "https://example.com/(bar)\\?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/(bar)", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/bar", "groups": { "0": "bar" } }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/{bar}?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/{bar}?foo" + }, + "expected_match": null + }, + { + "pattern": [ "https://example.com/{bar}\\?foo" ], + "inputs": [ "https://example.com/bar?foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/bar", + "search": "foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/bar", "groups": {} }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "https://example.com/" ], + "inputs": [ "https://example.com:8080/" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "port": "", + "pathname": "/" + }, + "expected_match": null + }, + { + "pattern": [ "data:foobar" ], + "inputs": [ "data:foobar" ], + "expected_obj": "error" + }, + { + "pattern": [ "data\\:foobar" ], + "inputs": [ "data:foobar" ], + "exactly_empty_components": [ "hostname", "port" ], + "expected_obj": { + "protocol": "data", + "pathname": "foobar" + }, + "expected_match": { + "protocol": { "input": "data", "groups": {} }, + "pathname": { "input": "foobar", "groups": {} } + } + }, + { + "pattern": [ "https://{sub.}?example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "{sub.}?example.com", + "pathname": "/foo" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} } + } + }, + { + "pattern": [ "https://{sub.}?example{.com/}foo" ], + "inputs": [ "https://example.com/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "{https://}example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "https://(sub.)?example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "(sub.)?example.com", + "pathname": "/foo" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": { "0": null } }, + "pathname": { "input": "/foo", "groups": {} } + } + }, + { + "pattern": [ "https://(sub.)?example(.com/)foo" ], + "inputs": [ "https://example.com/foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "(sub.)?example(.com/)foo", + "pathname": "*" + }, + "expected_match": null + }, + { + "pattern": [ "(https://)example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "https://{sub{.}}example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "https://(sub(?:.))?example.com/foo" ], + "inputs": [ "https://example.com/foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "(sub(?:.))?example.com", + "pathname": "/foo" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": { "0": null } }, + "pathname": { "input": "/foo", "groups": {} } + } + }, + { + "pattern": [ "file:///foo/bar" ], + "inputs": [ "file:///foo/bar" ], + "exactly_empty_components": [ "hostname", "port" ], + "expected_obj": { + "protocol": "file", + "pathname": "/foo/bar" + }, + "expected_match": { + "protocol": { "input": "file", "groups": {} }, + "pathname": { "input": "/foo/bar", "groups": {} } + } + }, + { + "pattern": [ "data:" ], + "inputs": [ "data:" ], + "exactly_empty_components": [ "hostname", "port", "pathname" ], + "expected_obj": { + "protocol": "data" + }, + "expected_match": { + "protocol": { "input": "data", "groups": {} } + } + }, + { + "pattern": [ "foo://bar" ], + "inputs": [ "foo://bad_url_browser_interop" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "foo", + "hostname": "bar" + }, + "expected_match": null + }, + { + "pattern": [ "(café)://foo" ], + "expected_obj": "error" + }, + { + "pattern": [ "https://example.com/foo?bar#baz" ], + "inputs": [{ "protocol": "https:", + "search": "?bar", + "hash": "#baz", + "baseURL": "http://example.com/foo" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": null + }, + { + "pattern": [{ "protocol": "http{s}?:", + "search": "?bar", + "hash": "#baz" }], + "inputs": [ "http://example.com/foo?bar#baz" ], + "expected_obj": { + "protocol": "http{s}?", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "example.com", "groups": { "0": "example.com" }}, + "pathname": { "input": "/foo", "groups": { "0": "/foo" }}, + "search": { "input": "bar", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [ "?bar#baz", "https://example.com/foo" ], + "inputs": [ "?bar#baz", "https://example.com/foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "search": { "input": "bar", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [ "?bar", "https://example.com/foo#baz" ], + "inputs": [ "?bar", "https://example.com/foo#snafu" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/foo", + "search": "bar", + "hash": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "search": { "input": "bar", "groups": {} } + } + }, + { + "pattern": [ "#baz", "https://example.com/foo?bar" ], + "inputs": [ "#baz", "https://example.com/foo?bar" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "search": { "input": "bar", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [ "#baz", "https://example.com/foo" ], + "inputs": [ "#baz", "https://example.com/foo" ], + "exactly_empty_components": [ "port", "search" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/foo", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/foo", "groups": {} }, + "hash": { "input": "baz", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "*" }], + "inputs": [ "foo", "data:data-urls-cannot-be-base-urls" ], + "expected_match": null + }, + { + "pattern": [{ "pathname": "*" }], + "inputs": [ "foo", "not|a|valid|url" ], + "expected_match": null + }, + { + "pattern": [ "https://foo\\:bar@example.com" ], + "inputs": [ "https://foo:bar@example.com" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "username": "foo", + "password": "bar", + "hostname": "example.com", + "pathname": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "username": { "input": "foo", "groups": {} }, + "password": { "input": "bar", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "/" } } + } + }, + { + "pattern": [ "https://foo@example.com" ], + "inputs": [ "https://foo@example.com" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "username": "foo", + "hostname": "example.com", + "pathname": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "username": { "input": "foo", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "/" } } + } + }, + { + "pattern": [ "https://\\:bar@example.com" ], + "inputs": [ "https://:bar@example.com" ], + "exactly_empty_components": [ "username", "port" ], + "expected_obj": { + "protocol": "https", + "password": "bar", + "hostname": "example.com", + "pathname": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "password": { "input": "bar", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "/" } } + } + }, + { + "pattern": [ "https://:user::pass@example.com" ], + "inputs": [ "https://foo:bar@example.com" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "username": ":user", + "password": ":pass", + "hostname": "example.com", + "pathname": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "username": { "input": "foo", "groups": { "user": "foo" } }, + "password": { "input": "bar", "groups": { "pass": "bar" } }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "/" } } + } + }, + { + "pattern": [ "https\\:foo\\:bar@example.com" ], + "inputs": [ "https:foo:bar@example.com" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "username": "foo", + "password": "bar", + "hostname": "example.com", + "pathname": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "username": { "input": "foo", "groups": {} }, + "password": { "input": "bar", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": { "0": "/" } } + } + }, + { + "pattern": [ "data\\:foo\\:bar@example.com" ], + "inputs": [ "data:foo:bar@example.com" ], + "exactly_empty_components": [ "hostname", "port" ], + "expected_obj": { + "protocol": "data", + "pathname": "foo\\:bar@example.com" + }, + "expected_match": { + "protocol": { "input": "data", "groups": {} }, + "pathname": { "input": "foo:bar@example.com", "groups": {} } + } + }, + { + "pattern": [ "https://foo{\\:}bar@example.com" ], + "inputs": [ "https://foo:bar@example.com" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "username": "foo%3Abar", + "hostname": "example.com" + }, + "expected_match": null + }, + { + "pattern": [ "data{\\:}channel.html", "https://example.com" ], + "inputs": [ "https://example.com/data:channel.html" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "pathname": "/data\\:channel.html", + "search": "*", + "hash": "*" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/data:channel.html", "groups": {} } + } + }, + { + "pattern": [ "http://[\\:\\:1]/" ], + "inputs": [ "http://[::1]/" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http", + "hostname": "[\\:\\:1]", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "[::1]", "groups": {} }, + "pathname": { "input": "/", "groups": {} } + } + }, + { + "pattern": [ "http://[\\:\\:1]:8080/" ], + "inputs": [ "http://[::1]:8080/" ], + "expected_obj": { + "protocol": "http", + "hostname": "[\\:\\:1]", + "port": "8080", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "[::1]", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/", "groups": {} } + } + }, + { + "pattern": [ "http://[\\:\\:a]/" ], + "inputs": [ "http://[::a]/" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http", + "hostname": "[\\:\\:a]", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "[::a]", "groups": {} }, + "pathname": { "input": "/", "groups": {} } + } + }, + { + "pattern": [ "http://[:address]/" ], + "inputs": [ "http://[::1]/" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http", + "hostname": "[:address]", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "[::1]", "groups": { "address": "::1" }}, + "pathname": { "input": "/", "groups": {} } + } + }, + { + "pattern": [ "http://[\\:\\:AB\\::num]/" ], + "inputs": [ "http://[::ab:1]/" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http", + "hostname": "[\\:\\:ab\\::num]", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {} }, + "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }}, + "pathname": { "input": "/", "groups": {} } + } + }, + { + "pattern": [{ "hostname": "[\\:\\:AB\\::num]" }], + "inputs": [{ "hostname": "[::ab:1]" }], + "expected_obj": { + "hostname": "[\\:\\:ab\\::num]" + }, + "expected_match": { + "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }} + } + }, + { + "pattern": [{ "hostname": "[\\:\\:xY\\::num]" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "{[\\:\\:ab\\::num]}" }], + "inputs": [{ "hostname": "[::ab:1]" }], + "expected_match": { + "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }} + } + }, + { + "pattern": [{ "hostname": "{[\\:\\:fé\\::num]}" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "{[\\:\\::num\\:1]}" }], + "inputs": [{ "hostname": "[::ab:1]" }], + "expected_match": { + "hostname": { "input": "[::ab:1]", "groups": { "num": "ab" }} + } + }, + { + "pattern": [{ "hostname": "{[\\:\\::num\\:fé]}" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "[*\\:1]" }], + "inputs": [{ "hostname": "[::ab:1]" }], + "expected_match": { + "hostname": { "input": "[::ab:1]", "groups": { "0": "::ab" }} + } + }, + { + "pattern": [{ "hostname": "*\\:1]" }], + "expected_obj": "error" + }, + { + "pattern": [ "https://foo{{@}}example.com" ], + "inputs": [ "https://foo@example.com" ], + "expected_obj": "error" + }, + { + "pattern": [ "https://foo{@example.com" ], + "inputs": [ "https://foo@example.com" ], + "expected_obj": "error" + }, + { + "pattern": [ "data\\:text/javascript,let x = 100/:tens?5;" ], + "inputs": [ "data:text/javascript,let x = 100/5;" ], + "exactly_empty_components": [ "hostname", "port" ], + "expected_obj": { + "protocol": "data", + "pathname": "text/javascript,let x = 100/:tens?5;" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "protocol": { "input": "data", "groups": {} }, + "pathname": { "input": "text/javascript,let x = 100/5;", "groups": { "tens": null } } + } + }, + { + "pattern": [{ "pathname": "/:id/:id" }], + "expected_obj": "error" + }, + { + "pattern": [{ "pathname": "/foo", "baseURL": "" }], + "expected_obj": "error" + }, + { + "pattern": [ "/foo", "" ], + "expected_obj": "error" + }, + { + "pattern": [{ "pathname": "/foo" }, "https://example.com" ], + "expected_obj": "error" + }, + { + "pattern": [{ "pathname": ":name*" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "pathname": ":name+" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "pathname": ":name" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "protocol": ":name*" }], + "inputs": [{ "protocol": "foobar" }], + "expected_match": { + "protocol": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "protocol": ":name+" }], + "inputs": [{ "protocol": "foobar" }], + "expected_match": { + "protocol": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "protocol": ":name" }], + "inputs": [{ "protocol": "foobar" }], + "expected_match": { + "protocol": { "input": "foobar", "groups": { "name": "foobar" }} + } + }, + { + "pattern": [{ "hostname": "bad hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad#hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad%hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad/hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad\\:hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "badhostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad?hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad@hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad[hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad]hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad\\\\hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad^hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad|hostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad\nhostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad\rhostname" }], + "expected_obj": "error" + }, + { + "pattern": [{ "hostname": "bad\thostname" }], + "expected_obj": "error" + }, + { + "pattern": [{}], + "inputs": ["https://example.com/"], + "expected_match": { + "protocol": { "input": "https", "groups": { "0": "https" }}, + "hostname": { "input": "example.com", "groups": { "0": "example.com" }}, + "pathname": { "input": "/", "groups": { "0": "/" }} + } + }, + { + "pattern": [], + "inputs": ["https://example.com/"], + "expected_match": { + "protocol": { "input": "https", "groups": { "0": "https" }}, + "hostname": { "input": "example.com", "groups": { "0": "example.com" }}, + "pathname": { "input": "/", "groups": { "0": "/" }} + } + }, + { + "pattern": [], + "inputs": [{}], + "expected_match": {} + }, + { + "pattern": [], + "inputs": [], + "expected_match": { "inputs": [{}] } + }, + { + "pattern": [{ "pathname": "(foo)(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "barbaz" }} + } + }, + { + "pattern": [{ "pathname": "{(foo)bar}(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "baz" }} + } + }, + { + "pattern": [{ "pathname": "(foo)?(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": "(foo)?*" + }, + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "barbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}(barbaz)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "foo", "0": "barbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}{(.*)}" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": "{:foo}(.*)" + }, + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}{(.*)bar}" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": ":foo{*bar}" + }, + "expected_match": null + }, + { + "pattern": [{ "pathname": "{:foo}{bar(.*)}" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": ":foo{bar*}" + }, + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "foo", "0": "baz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}:bar(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": ":foo:bar(.*)" + }, + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "bar": "oobarbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}?(.*)" }], + "inputs": [{ "pathname": "foobarbaz" }], + "expected_obj": { + "pathname": ":foo?*" + }, + "expected_match": { + "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }} + } + }, + { + "pattern": [{ "pathname": "{:foo\\bar}" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": "{:foo\\.bar}" }], + "inputs": [{ "pathname": "foo.bar" }], + "expected_obj": { + "pathname": "{:foo.bar}" + }, + "expected_match": { + "pathname": { "input": "foo.bar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": "{:foo(foo)bar}" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": "{:foo}bar" }], + "inputs": [{ "pathname": "foobar" }], + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": ":foo\\bar" }], + "inputs": [{ "pathname": "foobar" }], + "expected_obj": { + "pathname": "{:foo}bar" + }, + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": ":foo{}(.*)" }], + "inputs": [{ "pathname": "foobar" }], + "expected_obj": { + "pathname": "{:foo}(.*)" + }, + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "f", "0": "oobar" }} + } + }, + { + "pattern": [{ "pathname": ":foo{}bar" }], + "inputs": [{ "pathname": "foobar" }], + "expected_obj": { + "pathname": "{:foo}bar" + }, + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": ":foo{}?bar" }], + "inputs": [{ "pathname": "foobar" }], + "expected_obj": { + "pathname": "{:foo}bar" + }, + "expected_match": { + "pathname": { "input": "foobar", "groups": { "foo": "foo" }} + } + }, + { + "pattern": [{ "pathname": "*{}**?" }], + "inputs": [{ "pathname": "foobar" }], + "expected_obj": { + "pathname": "*(.*)?" + }, + "//": "The `null` below is translated to undefined in the test harness.", + "expected_match": { + "pathname": { "input": "foobar", "groups": { "0": "foobar", "1": null }} + } + }, + { + "pattern": [{ "pathname": ":foo(baz)(.*)" }], + "inputs": [{ "pathname": "bazbar" }], + "expected_match": { + "pathname": { "input": "bazbar", "groups": { "foo": "baz", "0": "bar" }} + } + }, + { + "pattern": [{ "pathname": ":foo(baz)bar" }], + "inputs": [{ "pathname": "bazbar" }], + "expected_match": { + "pathname": { "input": "bazbar", "groups": { "foo": "baz" }} + } + }, + { + "pattern": [{ "pathname": "*/*" }], + "inputs": [{ "pathname": "foo/bar" }], + "expected_match": { + "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }} + } + }, + { + "pattern": [{ "pathname": "*\\/*" }], + "inputs": [{ "pathname": "foo/bar" }], + "expected_obj": { + "pathname": "*/{*}" + }, + "expected_match": { + "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }} + } + }, + { + "pattern": [{ "pathname": "*/{*}" }], + "inputs": [{ "pathname": "foo/bar" }], + "expected_match": { + "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }} + } + }, + { + "pattern": [{ "pathname": "*//*" }], + "inputs": [{ "pathname": "foo/bar" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/:foo." }], + "inputs": [{ "pathname": "/bar." }], + "expected_match": { + "pathname": { "input": "/bar.", "groups": { "foo": "bar" } } + } + }, + { + "pattern": [{ "pathname": "/:foo.." }], + "inputs": [{ "pathname": "/bar.." }], + "expected_match": { + "pathname": { "input": "/bar..", "groups": { "foo": "bar" } } + } + }, + { + "pattern": [{ "pathname": "./foo" }], + "inputs": [{ "pathname": "./foo" }], + "expected_match": { + "pathname": { "input": "./foo", "groups": {}} + } + }, + { + "pattern": [{ "pathname": "../foo" }], + "inputs": [{ "pathname": "../foo" }], + "expected_match": { + "pathname": { "input": "../foo", "groups": {}} + } + }, + { + "pattern": [{ "pathname": ":foo./" }], + "inputs": [{ "pathname": "bar./" }], + "expected_match": { + "pathname": { "input": "bar./", "groups": { "foo": "bar" }} + } + }, + { + "pattern": [{ "pathname": ":foo../" }], + "inputs": [{ "pathname": "bar../" }], + "expected_match": { + "pathname": { "input": "bar../", "groups": { "foo": "bar" }} + } + }, + { + "pattern": [{ "pathname": "/:foo\\bar" }], + "inputs": [{ "pathname": "/bazbar" }], + "expected_obj": { + "pathname": "{/:foo}bar" + }, + "expected_match": { + "pathname": { "input": "/bazbar", "groups": { "foo": "baz" }} + } + }, + { + "pattern": [{ "pathname": "/foo/bar" }, { "ignoreCase": true }], + "inputs": [{ "pathname": "/FOO/BAR" }], + "expected_match": { + "pathname": { "input": "/FOO/BAR", "groups": {} } + } + }, + { + "pattern": [{ "ignoreCase": true }], + "inputs": [{ "pathname": "/FOO/BAR" }], + "expected_match": { + "pathname": { "input": "/FOO/BAR", "groups": { "0": "/FOO/BAR" } } + } + }, + { + "pattern": [ "https://example.com:8080/foo?bar#baz", + { "ignoreCase": true }], + "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ", + "baseURL": "https://example.com:8080" }], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "port": "8080", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/FOO", "groups": {} }, + "search": { "input": "BAR", "groups": {} }, + "hash": { "input": "BAZ", "groups": {} } + } + }, + { + "pattern": [ "/foo?bar#baz", "https://example.com:8080", + { "ignoreCase": true }], + "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ", + "baseURL": "https://example.com:8080" }], + "expected_obj": { + "protocol": "https", + "hostname": "example.com", + "port": "8080", + "pathname": "/foo", + "search": "bar", + "hash": "baz" + }, + "expected_match": { + "protocol": { "input": "https", "groups": {} }, + "hostname": { "input": "example.com", "groups": {} }, + "port": { "input": "8080", "groups": {} }, + "pathname": { "input": "/FOO", "groups": {} }, + "search": { "input": "BAR", "groups": {} }, + "hash": { "input": "BAZ", "groups": {} } + } + }, + { + "pattern": [ "/foo?bar#baz", { "ignoreCase": true }, + "https://example.com:8080" ], + "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ", + "baseURL": "https://example.com:8080" }], + "expected_obj": "error" + }, + { + "pattern": [{ "search": "foo", "baseURL": "https://example.com/a/+/b" }], + "inputs": [{ "search": "foo", "baseURL": "https://example.com/a/+/b" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "pathname": "/a/\\+/b" + }, + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/a/+/b", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [{ "hash": "foo", "baseURL": "https://example.com/?q=*&v=?&hmm={}&umm=()" }], + "inputs": [{ "hash": "foo", "baseURL": "https://example.com/?q=*&v=?&hmm={}&umm=()" }], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "search": "q=\\*&v=\\?&hmm=\\{\\}&umm=\\(\\)" + }, + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "q=*&v=?&hmm={}&umm=()", "groups": {} }, + "hash": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [ "#foo", "https://example.com/?q=*&v=?&hmm={}&umm=()" ], + "inputs": [ "https://example.com/?q=*&v=?&hmm={}&umm=()#foo" ], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "search": "q=\\*&v=\\?&hmm=\\{\\}&umm=\\(\\)", + "hash": "foo" + }, + "expected_match": { + "hostname": { "input": "example.com", "groups": {} }, + "pathname": { "input": "/", "groups": {} }, + "protocol": { "input": "https", "groups": {} }, + "search": { "input": "q=*&v=?&hmm={}&umm=()", "groups": {} }, + "hash": { "input": "foo", "groups": {} } + } + }, + { + "pattern": [{ "pathname": "/([[a-z]--a])" }], + "inputs": [{ "pathname": "/a" }], + "expected_match": null + }, + { + "pattern": [{ "pathname": "/([[a-z]--a])" }], + "inputs": [{ "pathname": "/z" }], + "expected_match": { + "pathname": { "input": "/z", "groups": { "0": "z" } } + } + }, + { + "pattern": [{ "pathname": "/([\\d&&[0-1]])" }], + "inputs": [{ "pathname": "/0" }], + "expected_match": { + "pathname": { "input": "/0", "groups": { "0": "0" } } + } + }, + { + "pattern": [{ "pathname": "/([\\d&&[0-1]])" }], + "inputs": [{ "pathname": "/3" }], + "expected_match": null + } +] diff --git a/test/fixtures/wpt/urlpattern/resources/urlpatterntests.js b/test/fixtures/wpt/urlpattern/resources/urlpatterntests.js new file mode 100644 index 00000000000000..761f96b6fd3392 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/resources/urlpatterntests.js @@ -0,0 +1,188 @@ +const kComponents = [ + 'protocol', + 'username', + 'password', + 'hostname', + 'port', + 'password', + 'pathname', + 'search', + 'hash', +]; + +function runTests(data) { + for (let entry of data) { + test(function() { + if (entry.expected_obj === 'error') { + assert_throws_js(TypeError, _ => new URLPattern(...entry.pattern), + 'URLPattern() constructor'); + return; + } + + const pattern = new URLPattern(...entry.pattern); + + // If the expected_obj property is not present we will automatically + // fill it with the most likely expected values. + entry.expected_obj = entry.expected_obj || {}; + + // The compiled URLPattern object should have a property for each + // component exposing the compiled pattern string. + for (let component of kComponents) { + // If the test case explicitly provides an expected pattern string, + // then use that. This is necessary in cases where the original + // construction pattern gets canonicalized, etc. + let expected = entry.expected_obj[component]; + + // If there is no explicit expected pattern string, then compute + // the expected value based on the URLPattern constructor args. + if (expected == undefined) { + // First determine if there is a baseURL present in the pattern + // input. A baseURL can be the source for many component patterns. + let baseURL = null; + if (entry.pattern.length > 0 && entry.pattern[0].baseURL) { + baseURL = new URL(entry.pattern[0].baseURL); + } else if (entry.pattern.length > 1 && + typeof entry.pattern[1] === 'string') { + baseURL = new URL(entry.pattern[1]); + } + + const EARLIER_COMPONENTS = { + protocol: [], + hostname: ["protocol"], + port: ["protocol", "hostname"], + username: [], + password: [], + pathname: ["protocol", "hostname", "port"], + search: ["protocol", "hostname", "port", "pathname"], + hash: ["protocol", "hostname", "port", "pathname", "search"], + }; + + // We automatically populate the expected pattern string using + // the following options in priority order: + // + // 1. If the original input explicitly provided a pattern, then + // echo that back as the expected value. + // 2. If an "earlier" component is specified, then a wildcard + // will be used rather than inheriting from the base URL. + // 3. If the baseURL exists and provides a component value then + // use that for the expected pattern. + // 4. Otherwise fall back on the default pattern of `*` for an + // empty component pattern. + // + // Note that username and password are never inherited, and will only + // need to match if explicitly specified. + if (entry.exactly_empty_components && + entry.exactly_empty_components.includes(component)) { + expected = ''; + } else if (typeof entry.pattern[0] === 'object' && + entry.pattern[0][component]) { + expected = entry.pattern[0][component]; + } else if (typeof entry.pattern[0] === 'object' && + EARLIER_COMPONENTS[component].some(c => c in entry.pattern[0])) { + expected = '*'; + } else if (baseURL && component !== 'username' && component !== 'password') { + let base_value = baseURL[component]; + // Unfortunately some URL() getters include separator chars; e.g. + // the trailing `:` for the protocol. Strip those off if necessary. + if (component === 'protocol') + base_value = base_value.substring(0, base_value.length - 1); + else if (component === 'search' || component === 'hash') + base_value = base_value.substring(1, base_value.length); + expected = base_value; + } else { + expected = '*'; + } + } + + // Finally, assert that the compiled object property matches the + // expected property. + assert_equals(pattern[component], expected, + `compiled pattern property '${component}'`); + } + + if (entry.expected_match === 'error') { + assert_throws_js(TypeError, _ => pattern.test(...entry.inputs), + 'test() result'); + assert_throws_js(TypeError, _ => pattern.exec(...entry.inputs), + 'exec() result'); + return; + } + + // First, validate the test() method by converting the expected result to + // a truthy value. + assert_equals(pattern.test(...entry.inputs), !!entry.expected_match, + 'test() result'); + + // Next, start validating the exec() method. + const exec_result = pattern.exec(...entry.inputs); + + // On a failed match exec() returns null. + if (!entry.expected_match || typeof entry.expected_match !== "object") { + assert_equals(exec_result, entry.expected_match, 'exec() failed match result'); + return; + } + + if (!entry.expected_match.inputs) + entry.expected_match.inputs = entry.inputs; + + // Next verify the result.input is correct. This may be a structured + // URLPatternInit dictionary object or a URL string. + assert_equals(exec_result.inputs.length, + entry.expected_match.inputs.length, + 'exec() result.inputs.length'); + for (let i = 0; i < exec_result.inputs.length; ++i) { + const input = exec_result.inputs[i]; + const expected_input = entry.expected_match.inputs[i]; + if (typeof input === 'string') { + assert_equals(input, expected_input, `exec() result.inputs[${i}]`); + continue; + } + for (let component of kComponents) { + assert_equals(input[component], expected_input[component], + `exec() result.inputs[${i}][${component}]`); + } + } + + // Next we will compare the URLPatternComponentResult for each of these + // expected components. + for (let component of kComponents) { + let expected_obj = entry.expected_match[component]; + + // If the test expectations don't include a component object, then + // we auto-generate one. This is convenient for the many cases + // where the pattern has a default wildcard or empty string pattern + // for a component and the input is essentially empty. + if (!expected_obj) { + expected_obj = { input: '', groups: {} }; + + // Next, we must treat default wildcards differently than empty string + // patterns. The wildcard results in a capture group, but the empty + // string pattern does not. The expectation object must list which + // components should be empty instead of wildcards in + // |exactly_empty_components|. + if (!entry.exactly_empty_components || + !entry.exactly_empty_components.includes(component)) { + expected_obj.groups['0'] = ''; + } + } + // JSON does not allow us to use undefined directly, so the data file + // contains null instead. Translate to the expected undefined value + // here. + for (const key in expected_obj.groups) { + if (expected_obj.groups[key] === null) { + expected_obj.groups[key] = undefined; + } + } + assert_object_equals(exec_result[component], expected_obj, + `exec() result for ${component}`); + } + }, `Pattern: ${JSON.stringify(entry.pattern)} ` + + `Inputs: ${JSON.stringify(entry.inputs)}`); + } +} + +promise_test(async function() { + const response = await fetch('resources/urlpatterntestdata.json'); + const data = await response.json(); + runTests(data); +}, 'Loading data...'); diff --git a/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.any.js b/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.any.js new file mode 100644 index 00000000000000..91e9f24f850b13 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.any.js @@ -0,0 +1,2 @@ +// META: global=window,worker +// META: script=resources/urlpattern-compare-tests.tentative.js diff --git a/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.https.any.js b/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.https.any.js new file mode 100644 index 00000000000000..91e9f24f850b13 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern-compare.tentative.https.any.js @@ -0,0 +1,2 @@ +// META: global=window,worker +// META: script=resources/urlpattern-compare-tests.tentative.js diff --git a/test/fixtures/wpt/urlpattern/urlpattern-hasregexpgroups.any.js b/test/fixtures/wpt/urlpattern/urlpattern-hasregexpgroups.any.js new file mode 100644 index 00000000000000..33133d2511b065 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern-hasregexpgroups.any.js @@ -0,0 +1,2 @@ +// META: global=window,worker +// META: script=resources/urlpattern-hasregexpgroups-tests.js diff --git a/test/fixtures/wpt/urlpattern/urlpattern.any.js b/test/fixtures/wpt/urlpattern/urlpattern.any.js new file mode 100644 index 00000000000000..7d47d22609bf8e --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern.any.js @@ -0,0 +1,2 @@ +// META: global=window,worker +// META: script=resources/urlpatterntests.js diff --git a/test/fixtures/wpt/urlpattern/urlpattern.https.any.js b/test/fixtures/wpt/urlpattern/urlpattern.https.any.js new file mode 100644 index 00000000000000..7d47d22609bf8e --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern.https.any.js @@ -0,0 +1,2 @@ +// META: global=window,worker +// META: script=resources/urlpatterntests.js diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 2560056dba990d..1ab3619ec85c8f 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -75,6 +75,10 @@ "commit": "6fa3fe8a929be45422cd46a8961e647e13d0cab8", "path": "url" }, + "urlpattern": { + "commit": "1b56d89a261b86dedfd2854b53c1732e435f1f57", + "path": "urlpattern" + }, "user-timing": { "commit": "5ae85bf8267ac617833dc013dee9774c9e2a18b7", "path": "user-timing" diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index c75ee390dcd195..bdaf12df02e58d 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -74,6 +74,7 @@ expected.beforePreExec = new Set([ 'NativeModule internal/querystring', 'NativeModule querystring', 'Internal Binding url', + 'Internal Binding url_pattern', 'Internal Binding blob', 'NativeModule internal/url', 'NativeModule util', diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json index d361048874d72d..0d9e23893d0597 100644 --- a/test/wpt/status/url.json +++ b/test/wpt/status/url.json @@ -1,7 +1,4 @@ { - "idlharness-shadowrealm.window.js": { - "skip": "ShadowRealm support is not enabled" - }, "percent-encoding.window.js": { "skip": "TODO: port from .window.js" }, @@ -19,13 +16,7 @@ "expected": [ "\uD87E\uDC68.com (using URL)", "\uD87E\uDC68.com (using URL.host)", - "\uD87E\uDC68.com (using URL.hostname)", - "\u1E9E.com (using URL)", - "\u1E9E.com (using URL.host)", - "\u1E9E.com (using URL.hostname)", - "\u1E9E.foo.com (using URL)", - "\u1E9E.foo.com (using URL.host)", - "\u1E9E.foo.com (using URL.hostname)" + "\uD87E\uDC68.com (using URL.hostname)" ] } }, diff --git a/test/wpt/status/urlpattern.json b/test/wpt/status/urlpattern.json new file mode 100644 index 00000000000000..b8c2c68a3a54a1 --- /dev/null +++ b/test/wpt/status/urlpattern.json @@ -0,0 +1,169 @@ +{ + "resources/urlpattern-compare-tests.tentative.js": { + "skip": "compareComponent function is not yet included in the URLPattern spec" + }, + "urlpattern-compare.tentative.any.js": { + "skip": "compareComponent function is not yet included in the URLPattern spec" + }, + "urlpattern-compare.tentative.https.any.js": { + "skip": "compareComponent function is not yet included in the URLPattern spec" + }, + "urlpattern.any.js": { + "fail": { + "expected": [ + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?otherquery#otherhash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar?otherquery#otherhash\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar?query#hash\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}]", + "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"port\":\"\"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"protocol\":\"http\",\"port\":\"80\"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"protocol\":\"http\",\"port\":\"80 \"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"pathname\":\"./foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"pathname\":\"foo/bar\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"pathname\":\"/\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"b\",\"baseURL\":\"https://example.com/foo/\"}] Inputs: [{\"pathname\":\"./b\",\"baseURL\":\"https://example.com/foo/\"}]", + "Pattern: [{\"pathname\":\"foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [\"https://example.com/foo/bar\"]", + "Pattern: [{\"pathname\":\":name.html\",\"baseURL\":\"https://example.com\"}] Inputs: [\"https://example.com/foo.html\"]", + "Pattern: [{\"pathname\":\"/(\\\\m)\"}] Inputs: undefined", + "Pattern: [\"http{s}?://{*.}?example.com/:product/:endpoint\"] Inputs: [\"https://sub.example.com/foo/bar\"]", + "Pattern: [\"https://example.com?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com#foo\"] Inputs: [\"https://example.com/#foo\"]", + "Pattern: [\"https://example.com:8080#foo\"] Inputs: [\"https://example.com:8080/#foo\"]", + "Pattern: [\"https://example.com/?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com/#foo\"] Inputs: [\"https://example.com/#foo\"]", + "Pattern: [\"https://example.com/*\\\\?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com/:name\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"https://example.com/(bar)\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"https://example.com/{bar}\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"data\\\\:foobar\"] Inputs: [\"data:foobar\"]", + "Pattern: [\"https://{sub.}?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://{sub.}?example{.com/}foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"file:///foo/bar\"] Inputs: [\"file:///foo/bar\"]", + "Pattern: [\"data:\"] Inputs: [\"data:\"]", + "Pattern: [\"?bar#baz\",\"https://example.com/foo\"] Inputs: [\"?bar#baz\",\"https://example.com/foo\"]", + "Pattern: [\"?bar\",\"https://example.com/foo#baz\"] Inputs: [\"?bar\",\"https://example.com/foo#snafu\"]", + "Pattern: [\"#baz\",\"https://example.com/foo?bar\"] Inputs: [\"#baz\",\"https://example.com/foo?bar\"]", + "Pattern: [\"#baz\",\"https://example.com/foo\"] Inputs: [\"#baz\",\"https://example.com/foo\"]", + "Pattern: [\"https://foo\\\\:bar@example.com\"] Inputs: [\"https://foo:bar@example.com\"]", + "Pattern: [\"https://foo@example.com\"] Inputs: [\"https://foo@example.com\"]", + "Pattern: [\"https://\\\\:bar@example.com\"] Inputs: [\"https://:bar@example.com\"]", + "Pattern: [\"https://:user::pass@example.com\"] Inputs: [\"https://foo:bar@example.com\"]", + "Pattern: [\"https\\\\:foo\\\\:bar@example.com\"] Inputs: [\"https:foo:bar@example.com\"]", + "Pattern: [\"data\\\\:foo\\\\:bar@example.com\"] Inputs: [\"data:foo:bar@example.com\"]", + "Pattern: [\"data{\\\\:}channel.html\",\"https://example.com\"] Inputs: [\"https://example.com/data:channel.html\"]", + "Pattern: [\"http://[\\\\:\\\\:1]/\"] Inputs: [\"http://[::1]/\"]", + "Pattern: [\"http://[\\\\:\\\\:a]/\"] Inputs: [\"http://[::a]/\"]", + "Pattern: [\"http://[:address]/\"] Inputs: [\"http://[::1]/\"]", + "Pattern: [\"http://[\\\\:\\\\:AB\\\\::num]/\"] Inputs: [\"http://[::ab:1]/\"]", + "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", + "Pattern: [{\"hostname\":\"bad#hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad/hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\\\\\\\hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\nhostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\rhostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\thostname\"}] Inputs: undefined", + "Pattern: [] Inputs: []", + "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", + "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", + "Pattern: [{\"search\":\"foo\",\"baseURL\":\"https://example.com/a/+/b\"}] Inputs: [{\"search\":\"foo\",\"baseURL\":\"https://example.com/a/+/b\"}]", + "Pattern: [{\"hash\":\"foo\",\"baseURL\":\"https://example.com/?q=*&v=?&hmm={}&umm=()\"}] Inputs: [{\"hash\":\"foo\",\"baseURL\":\"https://example.com/?q=*&v=?&hmm={}&umm=()\"}]", + "Pattern: [\"#foo\",\"https://example.com/?q=*&v=?&hmm={}&umm=()\"] Inputs: [\"https://example.com/?q=*&v=?&hmm={}&umm=()#foo\"]", + "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/z\"}]", + "Pattern: [{\"pathname\":\"/([\\\\d&&[0-1]])\"}] Inputs: [{\"pathname\":\"/0\"}]" + ] + } + }, + "urlpattern.https.any.js": { + "fail": { + "expected": [ + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?otherquery#otherhash\"}] Inputs: [{\"protocol\":\"https\",\"hostname\":\"example.com\",\"pathname\":\"/foo/bar\",\"search\":\"otherquery\",\"hash\":\"otherhash\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar?otherquery#otherhash\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [\"https://example.com/foo/bar?query#hash\"]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}] Inputs: [{\"pathname\":\"/foo/bar\",\"baseURL\":\"https://example.com?query#hash\"}]", + "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", + "Pattern: [{\"port\":\"\"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"protocol\":\"http\",\"port\":\"80\"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"protocol\":\"http\",\"port\":\"80 \"}] Inputs: [{\"protocol\":\"http\",\"port\":\"80\"}]", + "Pattern: [{\"pathname\":\"./foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"pathname\":\"foo/bar\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"\",\"baseURL\":\"https://example.com\"}] Inputs: [{\"pathname\":\"/\",\"baseURL\":\"https://example.com\"}]", + "Pattern: [{\"pathname\":\"b\",\"baseURL\":\"https://example.com/foo/\"}] Inputs: [{\"pathname\":\"./b\",\"baseURL\":\"https://example.com/foo/\"}]", + "Pattern: [{\"pathname\":\"foo/bar\",\"baseURL\":\"https://example.com\"}] Inputs: [\"https://example.com/foo/bar\"]", + "Pattern: [{\"pathname\":\":name.html\",\"baseURL\":\"https://example.com\"}] Inputs: [\"https://example.com/foo.html\"]", + "Pattern: [{\"pathname\":\"/(\\\\m)\"}] Inputs: undefined", + "Pattern: [\"http{s}?://{*.}?example.com/:product/:endpoint\"] Inputs: [\"https://sub.example.com/foo/bar\"]", + "Pattern: [\"https://example.com?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com#foo\"] Inputs: [\"https://example.com/#foo\"]", + "Pattern: [\"https://example.com:8080#foo\"] Inputs: [\"https://example.com:8080/#foo\"]", + "Pattern: [\"https://example.com/?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com/#foo\"] Inputs: [\"https://example.com/#foo\"]", + "Pattern: [\"https://example.com/*\\\\?foo\"] Inputs: [\"https://example.com/?foo\"]", + "Pattern: [\"https://example.com/:name\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"https://example.com/(bar)\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"https://example.com/{bar}\\\\?foo\"] Inputs: [\"https://example.com/bar?foo\"]", + "Pattern: [\"data\\\\:foobar\"] Inputs: [\"data:foobar\"]", + "Pattern: [\"https://{sub.}?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://{sub.}?example{.com/}foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", + "Pattern: [\"file:///foo/bar\"] Inputs: [\"file:///foo/bar\"]", + "Pattern: [\"data:\"] Inputs: [\"data:\"]", + "Pattern: [\"?bar#baz\",\"https://example.com/foo\"] Inputs: [\"?bar#baz\",\"https://example.com/foo\"]", + "Pattern: [\"?bar\",\"https://example.com/foo#baz\"] Inputs: [\"?bar\",\"https://example.com/foo#snafu\"]", + "Pattern: [\"#baz\",\"https://example.com/foo?bar\"] Inputs: [\"#baz\",\"https://example.com/foo?bar\"]", + "Pattern: [\"#baz\",\"https://example.com/foo\"] Inputs: [\"#baz\",\"https://example.com/foo\"]", + "Pattern: [\"https://foo\\\\:bar@example.com\"] Inputs: [\"https://foo:bar@example.com\"]", + "Pattern: [\"https://foo@example.com\"] Inputs: [\"https://foo@example.com\"]", + "Pattern: [\"https://\\\\:bar@example.com\"] Inputs: [\"https://:bar@example.com\"]", + "Pattern: [\"https://:user::pass@example.com\"] Inputs: [\"https://foo:bar@example.com\"]", + "Pattern: [\"https\\\\:foo\\\\:bar@example.com\"] Inputs: [\"https:foo:bar@example.com\"]", + "Pattern: [\"data\\\\:foo\\\\:bar@example.com\"] Inputs: [\"data:foo:bar@example.com\"]", + "Pattern: [\"data{\\\\:}channel.html\",\"https://example.com\"] Inputs: [\"https://example.com/data:channel.html\"]", + "Pattern: [\"http://[\\\\:\\\\:1]/\"] Inputs: [\"http://[::1]/\"]", + "Pattern: [\"http://[\\\\:\\\\:a]/\"] Inputs: [\"http://[::a]/\"]", + "Pattern: [\"http://[:address]/\"] Inputs: [\"http://[::1]/\"]", + "Pattern: [\"http://[\\\\:\\\\:AB\\\\::num]/\"] Inputs: [\"http://[::ab:1]/\"]", + "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", + "Pattern: [{\"hostname\":\"bad#hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad/hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\\\\\\\hostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\nhostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\rhostname\"}] Inputs: undefined", + "Pattern: [{\"hostname\":\"bad\\thostname\"}] Inputs: undefined", + "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", + "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", + "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", + "Pattern: [{\"search\":\"foo\",\"baseURL\":\"https://example.com/a/+/b\"}] Inputs: [{\"search\":\"foo\",\"baseURL\":\"https://example.com/a/+/b\"}]", + "Pattern: [{\"hash\":\"foo\",\"baseURL\":\"https://example.com/?q=*&v=?&hmm={}&umm=()\"}] Inputs: [{\"hash\":\"foo\",\"baseURL\":\"https://example.com/?q=*&v=?&hmm={}&umm=()\"}]", + "Pattern: [\"#foo\",\"https://example.com/?q=*&v=?&hmm={}&umm=()\"] Inputs: [\"https://example.com/?q=*&v=?&hmm={}&umm=()#foo\"]", + "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/z\"}]", + "Pattern: [{\"pathname\":\"/([\\\\d&&[0-1]])\"}] Inputs: [{\"pathname\":\"/0\"}]", + "Pattern: [] Inputs: []" + ] + } + } +} \ No newline at end of file diff --git a/test/wpt/test-urlpattern.js b/test/wpt/test-urlpattern.js new file mode 100644 index 00000000000000..e024e5f8feae2a --- /dev/null +++ b/test/wpt/test-urlpattern.js @@ -0,0 +1,8 @@ +'use strict'; + +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('urlpattern'); + +runner.pretendGlobalThisAs('Window'); +runner.runJsTests(); diff --git a/typings/globals.d.ts b/typings/globals.d.ts index b37ce9428fd8f2..6e13d589f62c69 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -14,6 +14,7 @@ import { SymbolsBinding } from './internalBinding/symbols'; import { TimersBinding } from './internalBinding/timers'; import { TypesBinding } from './internalBinding/types'; import { URLBinding } from './internalBinding/url'; +import { URLPatternBinding } from "./internalBinding/url_pattern"; import { UtilBinding } from './internalBinding/util'; import { WASIBinding } from './internalBinding/wasi'; import { WorkerBinding } from './internalBinding/worker'; @@ -38,6 +39,7 @@ interface InternalBindingMap { timers: TimersBinding; types: TypesBinding; url: URLBinding; + url_pattern: URLPatternBinding; util: UtilBinding; wasi: WASIBinding; worker: WorkerBinding; diff --git a/typings/internalBinding/url_pattern.d.ts b/typings/internalBinding/url_pattern.d.ts new file mode 100644 index 00000000000000..516d34d5141f9e --- /dev/null +++ b/typings/internalBinding/url_pattern.d.ts @@ -0,0 +1,20 @@ +export class URLPattern { + protocol: string + username: string + password: string + hostname: string + port: string + pathname: string + search: string + hash: string + + constructor(input: Record | string, options?: { ignoreCase: boolean }); + constructor(input: Record | string, baseUrl?: string, options?: { ignoreCase: boolean }); + + exec(input: string | Record, baseURL?: string): null | Record; + test(input: string | Record, baseURL?: string): boolean; +} + +export interface URLPatternBinding { + URLPattern: URLPattern; +}