/src/ada-url/build/singleheader/ada.cpp
Line | Count | Source |
1 | | /* auto-generated on 2026-11-07 22:18:56 -0500. Do not edit! */ |
2 | | /* begin file src/ada.cpp */ |
3 | | #include "ada.h" |
4 | | /* begin file src/checkers.cpp */ |
5 | | |
6 | | #include <algorithm> |
7 | | #include <array> |
8 | | #include <cstddef> |
9 | | #include <cstdint> |
10 | | #include <string_view> |
11 | | |
12 | | namespace ada::checkers { |
13 | | |
14 | 33.8k | ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept { |
15 | | // The string is not empty and does not contain upper case ASCII characters. |
16 | 33.8k | if (!last_label_may_be_a_number(view)) { |
17 | 24.7k | return false; |
18 | 24.7k | } |
19 | | // If the address ends with a dot, we need to prune it (special case). |
20 | 9.03k | if (view.ends_with('.')) { |
21 | 438 | view.remove_suffix(1); |
22 | 438 | } |
23 | | // From the last character, find the last dot. |
24 | 9.03k | size_t last_dot = view.rfind('.'); |
25 | 9.03k | if (last_dot != std::string_view::npos) { |
26 | | // We have at least one dot. |
27 | 2.50k | view.remove_prefix(last_dot + 1); |
28 | 2.50k | } |
29 | | /** Optimization opportunity: we have basically identified the last number of |
30 | | the ipv4 if we return true here. We might as well parse it and have at |
31 | | least one number parsed when we get to parse_ipv4. */ |
32 | 9.03k | if (std::ranges::all_of(view, ada::checkers::is_digit)) { |
33 | 4.27k | return true; |
34 | 4.27k | } |
35 | | // It could be hex (0x), but not if there is a single character. |
36 | 4.75k | if (view.size() == 1) { |
37 | 0 | return false; |
38 | 0 | } |
39 | | // It must start with 0x. |
40 | 4.75k | if (!view.starts_with("0x")) { |
41 | 2.37k | return false; |
42 | 2.37k | } |
43 | | // We must allow "0x". |
44 | 2.38k | if (view.size() == 2) { |
45 | 249 | return true; |
46 | 249 | } |
47 | | // We have 0x followed by some characters, we need to check that they are |
48 | | // hexadecimals. |
49 | 2.13k | view.remove_prefix(2); |
50 | 2.13k | return std::ranges::all_of(view, ada::unicode::is_lowercase_hex); |
51 | 2.38k | } |
52 | | |
53 | | // for use with path_signature, we include all characters that need percent |
54 | | // encoding. |
55 | | static constexpr std::array<uint8_t, 256> path_signature_table = |
56 | | []() consteval { |
57 | | std::array<uint8_t, 256> result{}; |
58 | | for (size_t i = 0; i < 256; i++) { |
59 | | if (i <= 0x20 || i == 0x22 || i == 0x23 || i == 0x3c || i == 0x3e || |
60 | | i == 0x3f || i == 0x5e || i == 0x60 || i == 0x7b || i == 0x7d || |
61 | | i > 0x7e) { |
62 | | result[i] = 1; |
63 | | } else if (i == 0x25) { |
64 | | result[i] = 8; |
65 | | } else if (i == 0x2e) { |
66 | | result[i] = 4; |
67 | | } else if (i == 0x5c) { |
68 | | result[i] = 2; |
69 | | } else { |
70 | | result[i] = 0; |
71 | | } |
72 | | } |
73 | | return result; |
74 | | }(); |
75 | | |
76 | | ada_really_inline constexpr uint8_t path_signature( |
77 | 20.6k | std::string_view input) noexcept { |
78 | | // The path percent-encode set is the query percent-encode set and U+003F (?), |
79 | | // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the |
80 | | // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#), |
81 | | // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0 |
82 | | // controls and all code points greater than U+007E (~). |
83 | 20.6k | size_t i = 0; |
84 | 20.6k | uint8_t accumulator{}; |
85 | 69.8k | for (; i + 7 < input.size(); i += 8) { |
86 | 49.1k | accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] | |
87 | 49.1k | path_signature_table[uint8_t(input[i + 1])] | |
88 | 49.1k | path_signature_table[uint8_t(input[i + 2])] | |
89 | 49.1k | path_signature_table[uint8_t(input[i + 3])] | |
90 | 49.1k | path_signature_table[uint8_t(input[i + 4])] | |
91 | 49.1k | path_signature_table[uint8_t(input[i + 5])] | |
92 | 49.1k | path_signature_table[uint8_t(input[i + 6])] | |
93 | 49.1k | path_signature_table[uint8_t(input[i + 7])]); |
94 | 49.1k | } |
95 | 56.8k | for (; i < input.size(); i++) { |
96 | 36.1k | accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]); |
97 | 36.1k | } |
98 | 20.6k | return accumulator; |
99 | 20.6k | } |
100 | | |
101 | | ada_really_inline constexpr bool verify_dns_length( |
102 | 0 | std::string_view input) noexcept { |
103 | 0 | if (input.empty()) return false; |
104 | 0 | if (input.back() == '.') { |
105 | 0 | if (input.size() > 254) return false; |
106 | 0 | } else if (input.size() > 253) |
107 | 0 | return false; |
108 | | |
109 | 0 | size_t start = 0; |
110 | 0 | while (start < input.size()) { |
111 | 0 | auto dot_location = input.find('.', start); |
112 | | // If not found, it's likely the end of the domain |
113 | 0 | if (dot_location == std::string_view::npos) dot_location = input.size(); |
114 | |
|
115 | 0 | auto label_size = dot_location - start; |
116 | 0 | if (label_size > 63 || label_size == 0) return false; |
117 | | |
118 | 0 | start = dot_location + 1; |
119 | 0 | } |
120 | | |
121 | 0 | return true; |
122 | 0 | } |
123 | | |
124 | | } // namespace ada::checkers |
125 | | /* end file src/checkers.cpp */ |
126 | | /* begin file src/unicode.cpp */ |
127 | | |
128 | | |
129 | | ADA_PUSH_DISABLE_ALL_WARNINGS |
130 | | /* begin file src/ada_idna.cpp */ |
131 | | /* auto-generated on 2026-10-09 11:29:39 -0400. Do not edit! */ |
132 | | /* begin file src/idna.cpp */ |
133 | | /* begin file src/unicode_transcoding.cpp */ |
134 | | /* begin file include/ada/idna/unicode_transcoding.h */ |
135 | | #ifndef ADA_IDNA_UNICODE_TRANSCODING_H |
136 | | #define ADA_IDNA_UNICODE_TRANSCODING_H |
137 | | |
138 | | #include <string> |
139 | | #include <string_view> |
140 | | |
141 | | namespace ada::idna { |
142 | | |
143 | | size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output); |
144 | | |
145 | | size_t utf8_length_from_utf32(const char32_t* buf, size_t len); |
146 | | |
147 | | size_t utf32_length_from_utf8(const char* buf, size_t len); |
148 | | |
149 | | size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output); |
150 | | |
151 | | } // namespace ada::idna |
152 | | |
153 | | #endif // ADA_IDNA_UNICODE_TRANSCODING_H |
154 | | /* end file include/ada/idna/unicode_transcoding.h */ |
155 | | |
156 | | #include <algorithm> |
157 | | #include <cstdint> |
158 | | #include <cstring> |
159 | | |
160 | | namespace ada::idna { |
161 | | |
162 | 13.1k | size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) { |
163 | 13.1k | const uint8_t* data = reinterpret_cast<const uint8_t*>(buf); |
164 | 13.1k | size_t pos = 0; |
165 | 13.1k | const char32_t* start{utf32_output}; |
166 | 180k | while (pos < len) { |
167 | | // try to convert the next block of 16 ASCII bytes |
168 | 168k | if (pos + 16 <= len) { // if it is safe to read 16 more |
169 | | // bytes, check that they are ascii |
170 | 96.5k | uint64_t v1; |
171 | 96.5k | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
172 | 96.5k | uint64_t v2; |
173 | 96.5k | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
174 | 96.5k | uint64_t v{v1 | v2}; |
175 | 96.5k | if ((v & 0x8080808080808080) == 0) { |
176 | 7.86k | size_t final_pos = pos + 16; |
177 | 133k | while (pos < final_pos) { |
178 | 125k | *utf32_output++ = char32_t(buf[pos]); |
179 | 125k | pos++; |
180 | 125k | } |
181 | 7.86k | continue; |
182 | 7.86k | } |
183 | 96.5k | } |
184 | 160k | uint8_t leading_byte = data[pos]; // leading byte |
185 | 160k | if (leading_byte < 0b10000000) { |
186 | | // converting one ASCII byte !!! |
187 | 92.4k | *utf32_output++ = char32_t(leading_byte); |
188 | 92.4k | pos++; |
189 | 92.4k | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
190 | | // We have a two-byte UTF-8 |
191 | 20.1k | if (pos + 1 >= len) { |
192 | 150 | return 0; |
193 | 150 | } // minimal bound checking |
194 | 20.0k | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
195 | 156 | return 0; |
196 | 156 | } |
197 | | // range check |
198 | 19.8k | uint32_t code_point = |
199 | 19.8k | (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); |
200 | 19.8k | if (code_point < 0x80 || 0x7ff < code_point) { |
201 | 12 | return 0; |
202 | 12 | } |
203 | 19.8k | *utf32_output++ = char32_t(code_point); |
204 | 19.8k | pos += 2; |
205 | 47.5k | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
206 | | // We have a three-byte UTF-8 |
207 | 45.8k | if (pos + 2 >= len) { |
208 | 30 | return 0; |
209 | 30 | } // minimal bound checking |
210 | | |
211 | 45.8k | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
212 | 54 | return 0; |
213 | 54 | } |
214 | 45.7k | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
215 | 15 | return 0; |
216 | 15 | } |
217 | | // range check |
218 | 45.7k | uint32_t code_point = (leading_byte & 0b00001111) << 12 | |
219 | 45.7k | (data[pos + 1] & 0b00111111) << 6 | |
220 | 45.7k | (data[pos + 2] & 0b00111111); |
221 | 45.7k | if (code_point < 0x800 || 0xffff < code_point || |
222 | 45.7k | (0xd7ff < code_point && code_point < 0xe000)) { |
223 | 33 | return 0; |
224 | 33 | } |
225 | 45.7k | *utf32_output++ = char32_t(code_point); |
226 | 45.7k | pos += 3; |
227 | 45.7k | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
228 | | // we have a 4-byte UTF-8 word. |
229 | 1.44k | if (pos + 3 >= len) { |
230 | 45 | return 0; |
231 | 45 | } // minimal bound checking |
232 | 1.39k | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
233 | 18 | return 0; |
234 | 18 | } |
235 | 1.38k | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
236 | 15 | return 0; |
237 | 15 | } |
238 | 1.36k | if ((data[pos + 3] & 0b11000000) != 0b10000000) { |
239 | 18 | return 0; |
240 | 18 | } |
241 | | |
242 | | // range check |
243 | 1.34k | uint32_t code_point = (leading_byte & 0b00000111) << 18 | |
244 | 1.34k | (data[pos + 1] & 0b00111111) << 12 | |
245 | 1.34k | (data[pos + 2] & 0b00111111) << 6 | |
246 | 1.34k | (data[pos + 3] & 0b00111111); |
247 | 1.34k | if (code_point <= 0xffff || 0x10ffff < code_point) { |
248 | 33 | return 0; |
249 | 33 | } |
250 | 1.31k | *utf32_output++ = char32_t(code_point); |
251 | 1.31k | pos += 4; |
252 | 1.31k | } else { |
253 | 306 | return 0; |
254 | 306 | } |
255 | 160k | } |
256 | 12.2k | return utf32_output - start; |
257 | 13.1k | } |
258 | | |
259 | 0 | size_t utf8_length_from_utf32(const char32_t* buf, size_t len) { |
260 | | // We are not BOM aware. |
261 | 0 | const uint32_t* p = reinterpret_cast<const uint32_t*>(buf); |
262 | 0 | size_t counter{0}; |
263 | 0 | for (size_t i = 0; i != len; ++i) { |
264 | 0 | ++counter; // ASCII |
265 | 0 | counter += static_cast<size_t>(p[i] > 0x7F); // two-byte |
266 | 0 | counter += static_cast<size_t>(p[i] > 0x7FF); // three-byte |
267 | 0 | counter += static_cast<size_t>(p[i] > 0xFFFF); // four-bytes |
268 | 0 | } |
269 | 0 | return counter; |
270 | 0 | } |
271 | | |
272 | 13.2k | size_t utf32_length_from_utf8(const char* buf, size_t len) { |
273 | 13.2k | const int8_t* p = reinterpret_cast<const int8_t*>(buf); |
274 | 414k | return std::count_if(p, std::next(p, len), [](int8_t c) { |
275 | | // -65 is 0b10111111, anything larger in two-complement's |
276 | | // should start a new code point. |
277 | 414k | return c > -65; |
278 | 414k | }); |
279 | 13.2k | } |
280 | | |
281 | 0 | size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) { |
282 | 0 | const uint32_t* data = reinterpret_cast<const uint32_t*>(buf); |
283 | 0 | size_t pos = 0; |
284 | 0 | const char* start{utf8_output}; |
285 | 0 | while (pos < len) { |
286 | | // try to convert the next block of 2 ASCII characters |
287 | 0 | if (pos + 2 <= len) { // if it is safe to read 8 more |
288 | | // bytes, check that they are ascii |
289 | 0 | uint64_t v; |
290 | 0 | std::memcpy(&v, data + pos, sizeof(uint64_t)); |
291 | 0 | if ((v & 0xFFFFFF80FFFFFF80) == 0) { |
292 | 0 | *utf8_output++ = char(buf[pos]); |
293 | 0 | *utf8_output++ = char(buf[pos + 1]); |
294 | 0 | pos += 2; |
295 | 0 | continue; |
296 | 0 | } |
297 | 0 | } |
298 | 0 | uint32_t word = data[pos]; |
299 | 0 | if ((word & 0xFFFFFF80) == 0) { |
300 | | // will generate one UTF-8 bytes |
301 | 0 | *utf8_output++ = char(word); |
302 | 0 | pos++; |
303 | 0 | } else if ((word & 0xFFFFF800) == 0) { |
304 | | // will generate two UTF-8 bytes |
305 | | // we have 0b110XXXXX 0b10XXXXXX |
306 | 0 | *utf8_output++ = char((word >> 6) | 0b11000000); |
307 | 0 | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
308 | 0 | pos++; |
309 | 0 | } else if ((word & 0xFFFF0000) == 0) { |
310 | | // will generate three UTF-8 bytes |
311 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
312 | 0 | if (word >= 0xD800 && word <= 0xDFFF) { |
313 | 0 | return 0; |
314 | 0 | } |
315 | 0 | *utf8_output++ = char((word >> 12) | 0b11100000); |
316 | 0 | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
317 | 0 | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
318 | 0 | pos++; |
319 | 0 | } else { |
320 | | // will generate four UTF-8 bytes |
321 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX |
322 | | // 0b10XXXXXX |
323 | 0 | if (word > 0x10FFFF) { |
324 | 0 | return 0; |
325 | 0 | } |
326 | 0 | *utf8_output++ = char((word >> 18) | 0b11110000); |
327 | 0 | *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); |
328 | 0 | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
329 | 0 | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
330 | 0 | pos++; |
331 | 0 | } |
332 | 0 | } |
333 | 0 | return utf8_output - start; |
334 | 0 | } |
335 | | } // namespace ada::idna |
336 | | /* end file src/unicode_transcoding.cpp */ |
337 | | /* begin file src/mapping.cpp */ |
338 | | /* begin file include/ada/idna/mapping.h */ |
339 | | #ifndef ADA_IDNA_MAPPING_H |
340 | | #define ADA_IDNA_MAPPING_H |
341 | | |
342 | | #include <string> |
343 | | #include <string_view> |
344 | | |
345 | | namespace ada::idna { |
346 | | |
347 | | // If the input is ascii, then the mapping is just -> lower case. |
348 | | void ascii_map(char* input, size_t length); |
349 | | // Map the characters according to IDNA, returning the empty string on error. |
350 | | std::u32string map(std::u32string_view input); |
351 | | // Map into an existing buffer (cleared on entry). Returns false if any code |
352 | | // point is disallowed. Reusing the buffer avoids repeated heap allocations |
353 | | // when called in a loop over multiple labels. |
354 | | bool map(std::u32string_view input, std::u32string& out); |
355 | | |
356 | | } // namespace ada::idna |
357 | | |
358 | | #endif |
359 | | /* end file include/ada/idna/mapping.h */ |
360 | | |
361 | | #include <array> |
362 | | #include <cstring> |
363 | | #include <cstdint> |
364 | | #include <string> |
365 | | |
366 | | /* begin file src/table_store.hpp */ |
367 | | // Runtime store for compressed Unicode/IDNA tables. |
368 | | // Large tables are DEFLATE-compressed (read-only) and expanded once on first |
369 | | // use into a heap buffer so the working set does not bloat the on-disk binary. |
370 | | // Hot-path lookups use the same O(1) multi-stage layout as the pre-compression |
371 | | // code; compression only affects on-disk size and one-time init. |
372 | | // |
373 | | // Thread-safe without mutex: atomic CAS + spin-wait. ensure_tables() returns |
374 | | // false if initialization fails (OOM, corrupt blob); callers must treat that |
375 | | // as a hard error and not touch table pointers. |
376 | | |
377 | | /* begin file src/raw_inflate.hpp */ |
378 | | // Minimal raw DEFLATE inflater (RFC 1951), enough for zlib raw streams. |
379 | | // Returns number of output bytes written, or 0 on failure. |
380 | | #include <cstdint> |
381 | | #include <cstring> |
382 | | |
383 | | namespace ada::idna::deflate { |
384 | | |
385 | | struct BitReader { |
386 | | const uint8_t* p; |
387 | | const uint8_t* end; |
388 | | uint32_t acc = 0; |
389 | | int bits = 0; |
390 | | |
391 | | explicit BitReader(const uint8_t* data, size_t len) |
392 | 1 | : p(data), end(data + len) {} |
393 | | |
394 | 475k | bool ensure(int n) { |
395 | 540k | while (bits < n) { |
396 | 65.3k | if (p >= end) return false; |
397 | 65.3k | acc |= uint32_t(*p++) << bits; |
398 | 65.3k | bits += 8; |
399 | 65.3k | } |
400 | 475k | return true; |
401 | 475k | } |
402 | 475k | uint32_t get(int n) { |
403 | 475k | if (!ensure(n)) return UINT32_MAX; |
404 | 475k | uint32_t v = acc & ((1u << n) - 1); |
405 | 475k | acc >>= n; |
406 | 475k | bits -= n; |
407 | 475k | return v; |
408 | 475k | } |
409 | 0 | void align_byte() { |
410 | 0 | acc >>= (bits & 7); |
411 | 0 | bits -= (bits & 7); |
412 | 0 | } |
413 | | }; |
414 | | |
415 | | struct Huff { |
416 | | // canonical codes: for each length, list of symbols |
417 | | // Fast path: table for codes up to max_bits |
418 | | static constexpr int MAXBITS = 15; |
419 | | uint8_t lengths[288]{}; |
420 | | int counts[MAXBITS + 1]{}; |
421 | | int first_code[MAXBITS + 1]{}; |
422 | | int16_t symbols[288]{}; |
423 | | int nsymbols = 0; |
424 | | int max_bits = 0; |
425 | | |
426 | | // Base index into symbols[] for each code length (used by decode). |
427 | | int base_idx[MAXBITS + 1]{}; |
428 | | |
429 | 16 | bool build(const uint8_t* lens, int n) { |
430 | 16 | std::memset(counts, 0, sizeof(counts)); |
431 | 16 | std::memset(first_code, 0, sizeof(first_code)); |
432 | 16 | std::memset(base_idx, 0, sizeof(base_idx)); |
433 | 16 | nsymbols = n; |
434 | 16 | max_bits = 0; |
435 | 1.99k | for (int i = 0; i < n; i++) { |
436 | 1.97k | lengths[i] = lens[i]; |
437 | 1.97k | if (lens[i]) { |
438 | 1.93k | counts[lens[i]]++; |
439 | 1.93k | if (lens[i] > max_bits) max_bits = lens[i]; |
440 | 1.93k | } |
441 | 1.97k | } |
442 | | // Canonical first code for each bit length (RFC 1951). |
443 | 16 | int code = 0; |
444 | 256 | for (int bits = 1; bits <= MAXBITS; bits++) { |
445 | 240 | code = (code + counts[bits - 1]) << 1; |
446 | 240 | first_code[bits] = code; |
447 | 240 | } |
448 | 16 | int idx = 0; |
449 | 159 | for (int bits = 1; bits <= max_bits; bits++) { |
450 | 143 | base_idx[bits] = idx; |
451 | | // assign symbols in symbol order for codes of this length |
452 | 21.8k | for (int sym = 0; sym < n; sym++) { |
453 | 21.6k | if (lengths[sym] == bits) { |
454 | 1.93k | symbols[idx++] = static_cast<int16_t>(sym); |
455 | 1.93k | } |
456 | 21.6k | } |
457 | 143 | } |
458 | 16 | return true; |
459 | 16 | } |
460 | | |
461 | 71.4k | int decode(BitReader& br) const { |
462 | 71.4k | if (max_bits == 0) return -1; |
463 | 71.4k | int code = 0; |
464 | 442k | for (int len = 1; len <= max_bits; len++) { |
465 | 442k | uint32_t b = br.get(1); |
466 | 442k | if (b == UINT32_MAX) return -1; |
467 | 442k | code = (code << 1) | int(b); |
468 | 442k | int first = first_code[len]; |
469 | 442k | int cnt = counts[len]; |
470 | 442k | if (cnt && code - first < cnt) { |
471 | 71.4k | return symbols[base_idx[len] + (code - first)]; |
472 | 71.4k | } |
473 | 442k | } |
474 | 0 | return -1; |
475 | 71.4k | } |
476 | | }; |
477 | | |
478 | | // Fixed Huffman tables are built once at dynamic initialization (before main / |
479 | | // single-threaded), so concurrent first-use of inflate cannot race. |
480 | 2 | inline Huff make_fixed_litlen_huff() { |
481 | 2 | Huff h; |
482 | 2 | uint8_t lens[288]; |
483 | | // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8 |
484 | 290 | for (int i = 0; i <= 143; i++) lens[i] = 8; |
485 | 226 | for (int i = 144; i <= 255; i++) lens[i] = 9; |
486 | 50 | for (int i = 256; i <= 279; i++) lens[i] = 7; |
487 | 18 | for (int i = 280; i <= 287; i++) lens[i] = 8; |
488 | 2 | h.build(lens, 288); |
489 | 2 | return h; |
490 | 2 | } |
491 | | |
492 | 2 | inline Huff make_fixed_dist_huff() { |
493 | 2 | Huff h; |
494 | 2 | uint8_t lens[32]; |
495 | 66 | for (int i = 0; i < 32; i++) lens[i] = 5; |
496 | 2 | h.build(lens, 32); |
497 | 2 | return h; |
498 | 2 | } |
499 | | |
500 | | // NOLINTNEXTLINE(cert-err58-cpp) -- intentional process-lifetime tables |
501 | | inline const Huff kFixedLitLenHuff = make_fixed_litlen_huff(); |
502 | | // NOLINTNEXTLINE(cert-err58-cpp) |
503 | | inline const Huff kFixedDistHuff = make_fixed_dist_huff(); |
504 | | |
505 | 0 | inline int fixed_litlen(BitReader& br) { return kFixedLitLenHuff.decode(br); } |
506 | | |
507 | 0 | inline int fixed_dist(BitReader& br) { return kFixedDistHuff.decode(br); } |
508 | | |
509 | | // length and distance base tables |
510 | | static const uint16_t len_base[29] = { |
511 | | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, |
512 | | 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; |
513 | | static const uint8_t len_extra[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
514 | | 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, |
515 | | 4, 4, 4, 4, 5, 5, 5, 5, 0}; |
516 | | static const uint16_t dist_base[30] = { |
517 | | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, |
518 | | 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, |
519 | | 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; |
520 | | static const uint8_t dist_extra[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, |
521 | | 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, |
522 | | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; |
523 | | |
524 | | inline size_t inflate_raw(const uint8_t* src, size_t src_len, uint8_t* dst, |
525 | 1 | size_t dst_cap) { |
526 | 1 | BitReader br(src, src_len); |
527 | 1 | size_t out = 0; |
528 | 4 | for (;;) { |
529 | 4 | uint32_t bfinal = br.get(1); |
530 | 4 | uint32_t btype = br.get(2); |
531 | 4 | if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0; |
532 | 4 | if (btype == 0) { |
533 | | // stored |
534 | 0 | br.align_byte(); |
535 | 0 | if (!br.ensure(16)) return 0; |
536 | | // read 16+16 from bit buffer awkwardly - use byte path |
537 | | // Align: bits is multiple of 8 |
538 | | // Get len from remaining bits then bytes |
539 | 0 | uint32_t len = br.get(16); |
540 | 0 | uint32_t nlen = br.get(16); |
541 | 0 | if (len == UINT32_MAX || nlen == UINT32_MAX) return 0; |
542 | 0 | if ((len ^ 0xFFFF) != nlen) return 0; |
543 | | // After get, may have bits in acc from previous - for stored, should be |
544 | | // byte aligned Copy len bytes from p |
545 | 0 | if (br.bits != 0) { |
546 | | // leftover bits should be 0 if aligned |
547 | 0 | } |
548 | 0 | if (size_t(br.end - br.p) < len) return 0; |
549 | 0 | if (out + len > dst_cap) return 0; |
550 | 0 | std::memcpy(dst + out, br.p, len); |
551 | 0 | br.p += len; |
552 | 0 | out += len; |
553 | 4 | } else if (btype == 1 || btype == 2) { |
554 | 4 | Huff lit, dist; |
555 | 4 | if (btype == 1) { |
556 | | // use fixed via functions |
557 | 4 | } else { |
558 | | // dynamic |
559 | 4 | uint32_t hlit = br.get(5); |
560 | 4 | if (hlit == UINT32_MAX) return 0; |
561 | 4 | hlit += 257; |
562 | 4 | uint32_t hdist = br.get(5); |
563 | 4 | if (hdist == UINT32_MAX) return 0; |
564 | 4 | hdist += 1; |
565 | 4 | uint32_t hclen = br.get(4); |
566 | 4 | if (hclen == UINT32_MAX) return 0; |
567 | 4 | hclen += 4; |
568 | 4 | static const int order[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, |
569 | 4 | 11, 4, 12, 3, 13, 2, 14, 1, 15}; |
570 | 4 | uint8_t clen[19]{}; |
571 | 69 | for (uint32_t i = 0; i < hclen; i++) { |
572 | 65 | uint32_t v = br.get(3); |
573 | 65 | if (v == UINT32_MAX) return 0; |
574 | 65 | clen[order[i]] = uint8_t(v); |
575 | 65 | } |
576 | 4 | Huff cl; |
577 | 4 | if (!cl.build(clen, 19)) return 0; |
578 | 4 | uint8_t lens[288 + 32]{}; |
579 | 4 | uint32_t n = hlit + hdist; |
580 | 1.04k | for (uint32_t i = 0; i < n;) { |
581 | 1.03k | int sym = cl.decode(br); |
582 | 1.03k | if (sym < 0) return 0; |
583 | 1.03k | if (sym < 16) { |
584 | 973 | lens[i++] = uint8_t(sym); |
585 | 973 | } else if (sym == 16) { |
586 | 63 | uint32_t rep = br.get(2); |
587 | 63 | if (rep == UINT32_MAX) return 0; |
588 | 63 | rep += 3; |
589 | 63 | if (i == 0) return 0; |
590 | 63 | uint8_t v = lens[i - 1]; |
591 | 350 | while (rep--) lens[i++] = v; |
592 | 63 | } else if (sym == 17) { |
593 | 0 | uint32_t rep = br.get(3); |
594 | 0 | if (rep == UINT32_MAX) return 0; |
595 | 0 | rep += 3; |
596 | 0 | while (rep--) lens[i++] = 0; |
597 | 0 | } else if (sym == 18) { |
598 | 0 | uint32_t rep = br.get(7); |
599 | 0 | if (rep == UINT32_MAX) return 0; |
600 | 0 | rep += 11; |
601 | 0 | while (rep--) lens[i++] = 0; |
602 | 0 | } else |
603 | 0 | return 0; |
604 | 1.03k | } |
605 | 4 | if (!lit.build(lens, int(hlit))) return 0; |
606 | 4 | if (!dist.build(lens + hlit, int(hdist))) return 0; |
607 | 4 | } |
608 | 54.4k | for (;;) { |
609 | 54.4k | int sym; |
610 | 54.4k | if (btype == 1) |
611 | 0 | sym = fixed_litlen(br); |
612 | 54.4k | else |
613 | 54.4k | sym = lit.decode(br); |
614 | 54.4k | if (sym < 0) return 0; |
615 | 54.4k | if (sym < 256) { |
616 | 38.5k | if (out >= dst_cap) return 0; |
617 | 38.5k | dst[out++] = uint8_t(sym); |
618 | 38.5k | } else if (sym == 256) { |
619 | 4 | break; |
620 | 15.9k | } else { |
621 | 15.9k | int len_code = sym - 257; |
622 | 15.9k | if (len_code < 0 || len_code > 28) return 0; |
623 | 15.9k | uint32_t extra = br.get(len_extra[len_code]); |
624 | 15.9k | if (len_extra[len_code] && extra == UINT32_MAX) return 0; |
625 | 15.9k | uint32_t length = |
626 | 15.9k | len_base[len_code] + (len_extra[len_code] ? extra : 0); |
627 | 15.9k | int dsym; |
628 | 15.9k | if (btype == 1) |
629 | 0 | dsym = fixed_dist(br); |
630 | 15.9k | else |
631 | 15.9k | dsym = dist.decode(br); |
632 | 15.9k | if (dsym < 0 || dsym > 29) return 0; |
633 | 15.9k | uint32_t dextra = br.get(dist_extra[dsym]); |
634 | 15.9k | if (dist_extra[dsym] && dextra == UINT32_MAX) return 0; |
635 | 15.9k | uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0); |
636 | 15.9k | if (distance > out || out + length > dst_cap) return 0; |
637 | 193k | for (uint32_t k = 0; k < length; k++) { |
638 | 177k | dst[out] = dst[out - distance]; |
639 | 177k | out++; |
640 | 177k | } |
641 | 15.9k | } |
642 | 54.4k | } |
643 | 4 | } else { |
644 | 0 | return 0; // reserved |
645 | 0 | } |
646 | 4 | if (bfinal) break; |
647 | 4 | } |
648 | 1 | return out; |
649 | 1 | } |
650 | | |
651 | | } // namespace ada::idna::deflate |
652 | | /* end file src/raw_inflate.hpp */ |
653 | | /* begin file src/table_blob.inc */ |
654 | | // Auto-generated by scripts/pack_tables.py - do not edit. |
655 | | // Compressed Unicode/IDNA tables (raw DEFLATE). |
656 | | // clang-format off |
657 | | #ifndef ADA_IDNA_TABLE_BLOB_H |
658 | | #define ADA_IDNA_TABLE_BLOB_H |
659 | | #include <cstdint> |
660 | | #include <cstddef> |
661 | | namespace ada::idna::table_blob { |
662 | | constexpr size_t uncompressed_size = 216077; |
663 | | constexpr size_t compressed_size = 65331; |
664 | | constexpr uint32_t uncompressed_crc32 = 0xC16EA7DEu; |
665 | | constexpr size_t decomposition_block_rows = 70; |
666 | | constexpr size_t decomposition_block_cols = 257; |
667 | | constexpr size_t ccc_block_rows = 69; |
668 | | constexpr size_t ccc_block_cols = 256; |
669 | | constexpr size_t composition_block_rows = 27; |
670 | | constexpr size_t composition_block_cols = 257; |
671 | | constexpr size_t id_continue_count = 1437; |
672 | | constexpr size_t id_start_count = 789; |
673 | | constexpr size_t dir_table_count = 1608; |
674 | | constexpr size_t combining_range_count = 333; |
675 | | constexpr size_t joining_table_count = 533; |
676 | | // Offsets into the decompressed buffer: |
677 | | constexpr size_t off_idna_stage1 = 0; |
678 | | constexpr size_t count_idna_stage1 = 4081; |
679 | | constexpr size_t off_idna_stage2 = 8162; |
680 | | constexpr size_t count_idna_stage2 = 11712; |
681 | | constexpr size_t off_idna_bool_blocks = 31592; |
682 | | constexpr size_t count_idna_bool_blocks = 225; |
683 | | constexpr size_t off_idna_utf8_mappings = 33392; |
684 | | constexpr size_t count_idna_utf8_mappings = 17651; |
685 | | constexpr size_t off_decomposition_index = 51043; |
686 | | constexpr size_t count_decomposition_index = 4352; |
687 | | constexpr size_t off_decomposition_block = 55396; |
688 | | constexpr size_t count_decomposition_block = 17990; |
689 | | constexpr size_t off_decomposition_data = 91376; |
690 | | constexpr size_t count_decomposition_data = 9255; |
691 | | constexpr size_t off_ccc_index = 128396; |
692 | | constexpr size_t count_ccc_index = 4352; |
693 | | constexpr size_t off_ccc_block = 132748; |
694 | | constexpr size_t count_ccc_block = 17664; |
695 | | constexpr size_t off_composition_index = 150412; |
696 | | constexpr size_t count_composition_index = 4352; |
697 | | constexpr size_t off_composition_block = 154764; |
698 | | constexpr size_t count_composition_block = 6939; |
699 | | constexpr size_t off_composition_data = 168644; |
700 | | constexpr size_t count_composition_data = 1923; |
701 | | constexpr size_t off_id_continue_flat = 176336; |
702 | | constexpr size_t count_id_continue_flat = 2874; |
703 | | constexpr size_t off_id_start_flat = 187832; |
704 | | constexpr size_t count_id_start_flat = 1578; |
705 | | constexpr size_t off_dir_start = 194144; |
706 | | constexpr size_t count_dir_start = 1608; |
707 | | constexpr size_t off_dir_final = 200576; |
708 | | constexpr size_t count_dir_final = 1608; |
709 | | constexpr size_t off_dir_value = 207008; |
710 | | constexpr size_t count_dir_value = 1608; |
711 | | constexpr size_t off_combining_flat = 208616; |
712 | | constexpr size_t count_combining_flat = 666; |
713 | | constexpr size_t off_joining_start = 211280; |
714 | | constexpr size_t count_joining_start = 533; |
715 | | constexpr size_t off_joining_final = 213412; |
716 | | constexpr size_t count_joining_final = 533; |
717 | | constexpr size_t off_joining_value = 215544; |
718 | | constexpr size_t count_joining_value = 533; |
719 | | alignas(8) inline constexpr uint8_t compressed[] = { |
720 | | 0xec,0x9c,0x09,0x40,0x54,0x55,0xfb,0xff,0x1f,0x18,0x59,0x94,0x65,0x9c,0x19,0xb6, |
721 | | 0x51,0x61,0x10,0x18,0x98,0x61,0x9f,0x19,0x18,0x76,0x66,0x58,0xda,0xcb,0xb6,0xb7, |
722 | | 0x3d,0x2b,0xf7,0xdc,0xb7,0xb4,0xb4,0xd2,0xcb,0x2e,0x28,0xe0,0x86,0x0a,0xb2,0x08, |
723 | | 0x8a,0x1b,0xa2,0x02,0xa2,0xec,0x60,0x88,0x8a,0xa5,0x88,0x88,0x65,0x6f,0x96,0x9a, |
724 | | 0x20,0x58,0x5a,0x56,0xb6,0x58,0x32,0xff,0xef,0xbd,0x33,0xa0,0x99,0xbd,0xf5,0x96, |
725 | | 0xbd,0xbf,0xdf,0xfb,0xfb,0x37,0x0f,0x9f,0x73,0xce,0x3d,0xf7,0x9c,0xf3,0x3c,0xe7, |
726 | | 0xb9,0xe7,0x9e,0x7b,0xce,0x1d,0x80,0x18,0x22,0x2d,0x31,0xd4,0x44,0x64,0xa4,0x35, |
727 | | 0x62,0x8c,0x9a,0x8c,0xc8,0x58,0x6b,0xcc,0x18,0x13,0xd3,0x64,0x4c,0x3c,0x2d,0x8f, |
728 | | 0xe1,0x35,0xf1,0x68,0x90,0x76,0x10,0x33,0xa8,0x69,0x10,0x99,0x18,0x31,0xc6,0x8c, |
729 | | 0xd6,0x84,0x18,0x1e,0x33,0x88,0x31,0x61,0x4c,0x19,0x33,0xc6,0x9c,0x19,0xcc,0x0c, |
730 | | 0x61,0x2c,0x18,0x62,0x18,0x13,0x4b,0xa6,0xc9,0x84,0x4c,0xb5,0xa6,0x56,0x8c,0x35, |
731 | | 0xc3,0x67,0x18,0xd3,0xa1,0x8c,0x80,0x11,0x32,0x22,0xc6,0x86,0xb1,0x65,0xec,0x18, |
732 | | 0x7b,0xc6,0x81,0x11,0x33,0x4d,0xa6,0xc3,0x18,0x32,0xd3,0x9a,0x31,0x66,0x4d,0x66, |
733 | | 0x64,0x3e,0x1c,0xf5,0x88,0xd1,0x9a,0x33,0xe6,0xd0,0x67,0x4e,0xdc,0xd1,0x08,0xc6, |
734 | | 0x91,0x71,0x62,0x24,0x8c,0x33,0x33,0x92,0xa1,0xc1,0xfa,0xbc,0x9f,0x8b,0x0b,0xe3, |
735 | | 0xca,0xb8,0x31,0x52,0x46,0x3b,0xd8,0x9d,0x61,0x06,0xbb,0x32,0x1e,0x8c,0x8c,0x91, |
736 | | 0x33,0x9e,0x8c,0x17,0xe3,0xcd,0xf8,0x30,0xbe,0x8c,0x1f,0xe3,0x8f,0x52,0x0a,0xa0, |
737 | | 0x64,0x54,0x4c,0x00,0xd3,0x34,0x38,0x90,0xa1,0x21,0xda,0x21,0xcc,0x10,0x68,0x19, |
738 | | 0x42,0x16,0x5a,0x0b,0xc6,0xa2,0xc9,0x82,0x2c,0xb5,0x96,0x8c,0x65,0x93,0x25,0x59, |
739 | | 0x69,0xad,0xd4,0x0c,0x63,0xd5,0x64,0x45,0xd6,0xb0,0xc5,0x5a,0xaf,0x83,0x31,0xc4, |
740 | | 0x41,0x4c,0x93,0x35,0xf1,0xb5,0xfc,0x3b,0xd9,0x71,0x27,0x61,0xf8,0x4d,0x6c,0xd9, |
741 | | 0xa1,0xc4,0x04,0xeb,0xfb,0x36,0x94,0x19,0xda,0x34,0x94,0x04,0x21,0x8c,0x56,0x10, |
742 | | 0xca,0x84,0x21,0x27,0x9c,0x61,0x04,0x4d,0x02,0x12,0x6a,0x85,0x8c,0xb0,0x49,0x48, |
743 | | 0xa2,0x08,0x46,0x2b,0x62,0x44,0x4d,0x22,0xb2,0xd1,0xda,0x44,0x32,0x8c,0x4d,0x93, |
744 | | 0x0d,0xd9,0x6a,0x6d,0x19,0xdb,0x26,0x5b,0xb2,0xd3,0xda,0xfd,0x5e,0xbd,0x7f,0xcb, |
745 | | 0xdf,0xf2,0xb7,0xfc,0x35,0xa2,0x61,0xb4,0x03,0xe9,0x28,0x86,0xb1,0x6b,0xb2,0x8b, |
746 | | 0x66,0xc8,0x5e,0x6b,0xcf,0xd8,0x37,0xd9,0xc7,0x30,0x48,0x33,0xb1,0xe0,0x1e,0x70, |
747 | | 0x2f,0x73,0x1f,0x73,0x3f,0xe2,0x07,0x98,0x07,0x19,0x72,0xd0,0x3a,0x3c,0xf4,0xb7, |
748 | | 0xf7,0xfe,0x42,0x79,0x98,0x79,0x84,0x19,0xf5,0xb7,0x70,0xc2,0x38,0x34,0x39,0x90, |
749 | | 0x58,0x2b,0x66,0xc4,0x4d,0x62,0x1a,0xa6,0x1d,0xc6,0x0c,0x6b,0x1a,0x46,0xc3,0xb5, |
750 | | 0xc3,0x99,0xe1,0x4d,0xc3,0x69,0x84,0x76,0x04,0x33,0xa2,0x69,0x04,0x39,0x6a,0x1d, |
751 | | 0x19,0xc7,0x26,0x47,0x72,0xd2,0x3a,0x31,0x4e,0x4d,0x4e,0x24,0xd1,0x4a,0x1e,0x65, |
752 | | 0x1e,0x83,0x27,0x1f,0x67,0x9e,0x40,0xf8,0x24,0xf3,0x0f,0xae,0xad,0xa7,0x98,0xa7, |
753 | | 0x99,0x67,0x98,0x67,0x99,0xe7,0x98,0xe7,0x19,0x46,0x82,0x67,0xa6,0x84,0x9c,0x5f, |
754 | | 0x60,0xb4,0xce,0x8c,0xf3,0x8b,0x03,0xbe,0xbf,0x8f,0x19,0xcd,0x34,0x39,0x8f,0x62, |
755 | | 0x5e,0x62,0x5e,0x66,0x5e,0x61,0xc6,0x30,0x63,0x99,0x71,0xcc,0x78,0x66,0x02,0x33, |
756 | | 0x91,0x99,0xc4,0xbc,0xca,0x4c,0x66,0xa6,0x30,0x53,0x99,0x69,0x68,0x8b,0x98,0xe9, |
757 | | 0x0c,0x8d,0x9c,0xc1,0xcc,0x64,0xb4,0x23,0x67,0x71,0xad,0xcf,0x66,0xe6,0x30,0x73, |
758 | | 0x99,0x17,0x98,0xd7,0x98,0x79,0xcc,0x7c,0x9c,0x7f,0x9d,0x79,0x83,0x59,0xc0,0x2c, |
759 | | 0x64,0xde,0x44,0xfa,0x2d,0xe6,0x6d,0x66,0x11,0xb3,0x98,0x61,0x98,0x38,0x26,0x9e, |
760 | | 0x49,0x60,0x12,0x91,0x97,0x04,0x92,0xb9,0x9a,0x29,0xcc,0x12,0xa4,0x53,0x99,0x34, |
761 | | 0x66,0x29,0xb3,0x8c,0x49,0xe7,0xf2,0x32,0xd8,0xbe,0x8f,0xcc,0x64,0x96,0x33,0x2b, |
762 | | 0x98,0x95,0xcc,0x2a,0x9c,0x5f,0xcd,0x64,0x61,0x7d,0xb0,0x86,0x59,0x8b,0x33,0xeb, |
763 | | 0x98,0x6c,0x26,0x87,0x59,0x8f,0x54,0x2e,0x93,0xc7,0xe4,0x33,0x05,0x06,0x6f,0x6d, |
764 | | 0x60,0x0a,0x99,0x22,0x66,0x23,0xb3,0xe9,0x5f,0x8e,0xaf,0x71,0x9c,0xfd,0xfd,0x52, |
765 | | 0x3c,0x90,0x4a,0xbf,0x4b,0xd7,0x6c,0x33,0xb3,0xe5,0x37,0xc7,0xf8,0x56,0x66,0xdb, |
766 | | 0xff,0xe0,0x1d,0xf6,0xf8,0x1d,0xf2,0xd2,0xff,0x4f,0xde,0x3f,0x69,0x7f,0xb0,0xde, |
767 | | 0xed,0xde,0x71,0x65,0xb6,0x33,0x25,0xcc,0x0e,0xa4,0x4a,0x99,0x9d,0x77,0xd4,0xd0, |
768 | | 0x34,0x92,0x5c,0x76,0xe1,0xfc,0x6e,0xa6,0x8c,0x29,0xff,0xff,0x64,0xa6,0xae,0x60, |
769 | | 0xf6,0x70,0xbe,0xfa,0xd7,0xe3,0xbd,0x92,0xd9,0xfb,0xff,0xd9,0xac,0xbd,0x6f,0xa0, |
770 | | 0xef,0x5a,0x97,0xaa,0x5b,0x3c,0x91,0x71,0xd7,0x34,0x10,0x53,0xcd,0x30,0x2e,0xff, |
771 | | 0x73,0x3d,0xd4,0xf7,0xa7,0xc9,0xe5,0xd6,0xeb,0x5c,0xc3,0xd4,0x32,0x75,0xdc,0x9a, |
772 | | 0xaa,0xde,0x90,0x23,0x63,0x43,0x57,0xad,0x2b,0xe3,0x4a,0x4c,0x03,0x9e,0x00,0x8d, |
773 | | 0x6c,0x1d,0xfd,0xdd,0xe2,0x4a,0x6e,0x5a,0x37,0xc6,0xad,0xc9,0x8d,0xa4,0x5a,0x29, |
774 | | 0x23,0x6d,0x92,0x92,0xbb,0xd6,0x9d,0x71,0x6f,0x72,0x27,0x0f,0xad,0x07,0xe3,0x71, |
775 | | 0xa7,0x71,0xb4,0x1f,0xf5,0xde,0xf9,0x4d,0xbb,0x9a,0x3c,0x48,0xa6,0x95,0x31,0xb2, |
776 | | 0x26,0x59,0x33,0x8e,0x0f,0x30,0x2d,0x03,0xe7,0x0e,0x32,0x87,0x6e,0x2b,0x7d,0xd8, |
777 | | 0x10,0xb7,0x1a,0xe2,0x23,0x86,0xf8,0x5d,0x83,0xc6,0xf7,0x18,0x92,0x1f,0xfd,0x15, |
778 | | 0x4d,0xc7,0x98,0x36,0x84,0xc7,0x0d,0x47,0x5a,0x39,0x23,0x6f,0x92,0xb7,0x0f,0x9c, |
779 | | 0xf5,0x42,0xed,0x13,0x4c,0x07,0x43,0x9e,0x5a,0x4f,0xc6,0xf3,0x24,0xd3,0xe4,0x49, |
780 | | 0x5e,0x77,0x9a,0x57,0x7e,0x2e,0x9d,0x86,0xf8,0x14,0xf3,0x3e,0xf3,0x01,0x73,0x9a, |
781 | | 0xf9,0xf0,0x96,0x73,0xff,0x04,0x1f,0x71,0xa9,0x33,0x8c,0xd6,0xeb,0xdf,0x9d,0xbf, |
782 | | 0xfe,0x96,0xbf,0xe5,0x6f,0xf9,0x5b,0xfe,0x96,0x7f,0x25,0xaf,0xfe,0xaf,0xb1,0xe4, |
783 | | 0xe3,0xff,0x42,0xef,0xd5,0xfd,0x7f,0x33,0x4e,0x3e,0xb9,0x43,0xde,0x92,0xbb,0xbb, |
784 | | 0xef,0xf7,0x6a,0xf2,0x22,0x6f,0xad,0x37,0xe3,0xdd,0xe4,0x4d,0x3e,0x5a,0x1f,0xc6, |
785 | | 0xe7,0xcf,0xed,0x5f,0xfe,0xf7,0xc8,0xd9,0xbf,0xe7,0x19,0x4e,0xd2,0xfe,0x7e,0xbb, |
786 | | 0xf5,0xb7,0xfc,0x2d,0x7f,0xcb,0xff,0x49,0xf9,0x7b,0x7e,0xff,0xab,0x45,0xa7,0x33, |
787 | | 0x22,0x1e,0x99,0x90,0x19,0x0d,0x26,0x0b,0xb2,0x22,0x3e,0x09,0x48,0x44,0xb6,0x64, |
788 | | 0x4f,0x62,0x1a,0x4e,0x8e,0x24,0xa1,0x91,0xe4,0x4a,0x52,0xf2,0x20,0x39,0x79,0x91, |
789 | | 0x0f,0xf9,0x91,0x82,0x54,0xa4,0xbb,0x6b,0x9f,0xbe,0x3f,0x29,0x81,0xb7,0xd9,0x12, |
790 | | 0x44,0x6c,0x8f,0xd8,0x14,0x21,0x0c,0xe3,0x52,0x1a,0x8a,0xa2,0x18,0xba,0x8f,0x4b, |
791 | | 0x3f,0x48,0xa3,0xd0,0x2b,0x9d,0xee,0x31,0x7a,0x9a,0x5e,0x44,0x3c,0x96,0x26,0xd0, |
792 | | 0xab,0x34,0x95,0x66,0xd0,0x6c,0x7a,0x8d,0x5e,0xa7,0x85,0xf4,0x36,0xdc,0x92,0x40, |
793 | | 0xc9,0x94,0x4a,0xcb,0x28,0x93,0x56,0x52,0x16,0xad,0xa3,0xf5,0x94,0x4f,0x85,0xb4, |
794 | | 0x09,0xe5,0xb7,0xd0,0x76,0x2a,0xa5,0xdd,0x54,0x41,0x7b,0xa9,0xfa,0x2e,0xf8,0xa1, |
795 | | 0x0e,0x6d,0x34,0x82,0x77,0x40,0x0b,0x38,0x0c,0xde,0x05,0xc7,0x40,0x3b,0x38,0x09, |
796 | | 0xde,0x07,0x1f,0x82,0x33,0xe0,0x2c,0xf8,0x14,0x74,0x83,0x5e,0xf0,0x39,0xf8,0x02, |
797 | | 0x7c,0x05,0xae,0x81,0xef,0xc1,0x8f,0xa0,0x8f,0xf5,0x83,0x91,0x4e,0x37,0x08,0x98, |
798 | | 0x1b,0x99,0x1b,0x59,0x20,0xb6,0x36,0x62,0x35,0x0a,0x10,0xda,0x00,0x7b,0x30,0xcc, |
799 | | 0x68,0x98,0x91,0x13,0xe2,0x91,0xc0,0x0d,0x78,0x00,0x4f,0x23,0x5f,0x84,0x0a,0x10, |
800 | | 0x00,0x82,0x40,0x28,0x88,0x00,0x5a,0x10,0x03,0xee,0x05,0x0f,0x80,0x87,0xc1,0xa3, |
801 | | 0xe0,0x09,0xf0,0x14,0x78,0x16,0xbc,0x00,0x5e,0x02,0x63,0xc0,0x78,0x30,0x09,0x4c, |
802 | | 0x01,0xd3,0xc1,0x2c,0x30,0xd7,0x68,0x3e,0xc2,0x05,0xe0,0x2d,0x20,0x85,0x95,0x8b, |
803 | | 0x8d,0xe2,0x91,0x4a,0x02,0x4b,0x8c,0x96,0x22,0xcc,0x30,0x5a,0x61,0xb4,0x9a,0xb3, |
804 | | 0x74,0xad,0x51,0x8e,0x51,0x9e,0xd1,0x06,0xa4,0x37,0x1a,0x6d,0x46,0xb8,0xcd,0x68, |
805 | | 0x87,0xd1,0x2e,0x23,0xbd,0xdf,0xca,0x8d,0x2a,0x91,0xaa,0x32,0xaa,0x45,0xd8,0x00, |
806 | | 0xf6,0x83,0x03,0x46,0x87,0x10,0x1e,0xe1,0x4a,0x1c,0x45,0x78,0xdc,0xa8,0x03,0xe1, |
807 | | 0x29,0xa3,0xd3,0x46,0x1f,0x21,0xfe,0x04,0x9c,0x37,0xea,0x32,0xd4,0xef,0x31,0xfa, |
808 | | 0xf9,0x75,0xf8,0xcc,0x88,0x95,0x2f,0x38,0xf9,0x8a,0x93,0x6b,0x28,0xf1,0x3d,0xf8, |
809 | | 0x11,0xf4,0x01,0x23,0x63,0x78,0x13,0x98,0x81,0x21,0xc6,0x6c,0x1d,0x2b,0x84,0x43, |
810 | | 0x81,0x08,0xd8,0x01,0x31,0x18,0x01,0x24,0xc0,0x05,0x48,0xb9,0x52,0x32,0x63,0x56, |
811 | | 0xbc,0x90,0xf6,0x35,0x56,0x18,0x07,0x20,0x0e,0x02,0xa1,0x20,0x02,0x68,0x41,0x0c, |
812 | | 0xb8,0x17,0x3c,0x00,0x1e,0x06,0x8f,0x82,0x27,0xc0,0x53,0xe0,0x59,0xf0,0x02,0x78, |
813 | | 0x09,0x8c,0x01,0xe3,0xc1,0x24,0x30,0x05,0x4c,0x07,0xb3,0xc0,0x5c,0x30,0x1f,0x2c, |
814 | | 0x00,0x6f,0x81,0xc5,0x20,0x1e,0x24,0x81,0x25,0x60,0xa9,0xf1,0xcf,0xfb,0x9a,0x61, |
815 | | 0xbc,0x12,0x39,0x59,0xc6,0xeb,0xb8,0xfc,0x5c,0x84,0x05,0xc6,0x45,0xc6,0xc5,0xc6, |
816 | | 0x5b,0x91,0x2a,0x01,0x3b,0x41,0x19,0xd8,0x63,0xac,0xfb,0xaf,0xff,0xf0,0x69,0x9f, |
817 | | 0xb1,0x08,0x33,0x58,0x8d,0x71,0xbd,0x71,0x93,0xb1,0x0f,0x66,0xaf,0x3f,0xd7,0x5e, |
818 | | 0xb3,0xf1,0x21,0xe3,0x77,0x8d,0xdb,0x8c,0x3b,0x8c,0xdf,0xe7,0xbc,0xb3,0xd9,0xc8, |
819 | | 0x1e,0xb3,0xa3,0x1f,0xfd,0xf3,0x0f,0xfa,0xea,0x63,0xe3,0x73,0xa8,0x79,0xc1,0xf8, |
820 | | 0xa2,0xf1,0xe7,0x77,0x68,0x81,0xfe,0xf4,0x0c,0xf3,0x05,0x5a,0xfd,0x0a,0x5c,0x03, |
821 | | 0xdf,0x1b,0xeb,0xe7,0xdb,0x1f,0xfb,0x35,0x19,0x1b,0xf1,0xfa,0xe7,0xd1,0x18,0x1a, |
822 | | 0xc4,0x1b,0xc2,0xb3,0xe2,0x0d,0xe5,0x89,0x78,0x76,0xc8,0x15,0x83,0x11,0x3c,0x09, |
823 | | 0x0f,0x23,0x99,0x27,0xe5,0xc9,0x78,0x5e,0x3c,0x5f,0x9e,0x82,0x17,0xc0,0x0b,0xe2, |
824 | | 0x7d,0x6e,0x1c,0xca,0x8b,0xe0,0xdd,0x47,0x5a,0x5e,0x0c,0xef,0x5e,0xde,0x03,0xbc, |
825 | | 0x87,0x51,0xf2,0x51,0xde,0x13,0xbc,0xa7,0x78,0xcf,0xf2,0x5e,0xe0,0xbd,0xc4,0x1b, |
826 | | 0xc3,0x1b,0xcf,0x9b,0xc4,0xbb,0x3b,0x57,0x6f,0x0a,0x74,0x07,0xa1,0xe5,0x11,0x68, |
827 | | 0xf1,0x59,0xe8,0xc2,0x98,0x07,0xb3,0xc0,0x5c,0x30,0x1f,0x2c,0x00,0x6f,0x81,0xc5, |
828 | | 0x20,0x1e,0x24,0x81,0x25,0x60,0x29,0xc8,0x00,0xa1,0xb0,0xef,0x51,0xc4,0x41,0xb0, |
829 | | 0x5f,0xa7,0x5b,0x01,0x1e,0xe5,0xad,0xe6,0xac,0x5b,0xcb,0xcb,0xe1,0xe5,0xf1,0x36, |
830 | | 0xf0,0x36,0xf2,0x36,0xf3,0xb6,0xf1,0x76,0xf0,0x76,0xf1,0xca,0x79,0x95,0xbc,0x2a, |
831 | | 0x5e,0x2d,0xaf,0x81,0xb7,0x9f,0x77,0x80,0x77,0x88,0x77,0x84,0x77,0x94,0x77,0x9c, |
832 | | 0xd7,0xc1,0x3b,0xc5,0x3b,0xcd,0xfb,0x88,0xf7,0x09,0xef,0x3c,0xaf,0x8b,0xd7,0xc3, |
833 | | 0xfb,0x8c,0x77,0x85,0x77,0x95,0xf7,0x0d,0xef,0x3b,0xde,0x75,0xde,0x0d,0x1e,0xdc, |
834 | | 0x36,0xc8,0x74,0xd0,0xe0,0x41,0x96,0x83,0xf8,0x83,0x84,0x83,0x6c,0x07,0x39,0x0c, |
835 | | 0x1a,0x3e,0xc8,0x69,0xd0,0xc8,0x41,0x6e,0x83,0x3c,0x06,0x79,0x0e,0xf2,0x19,0xf4, |
836 | | 0x57,0x8f,0x6f,0x7f,0x68,0x50,0x01,0x35,0x08,0x01,0xe1,0x40,0x03,0xa2,0xc1,0x3d, |
837 | | 0xe0,0x7e,0xf0,0x10,0x18,0x05,0x1e,0x07,0xff,0x00,0xcf,0x80,0xe7,0xc1,0x68,0xf0, |
838 | | 0xca,0x1d,0x2c,0x1c,0x87,0xbc,0x89,0x60,0x32,0x98,0x06,0x66,0x82,0x39,0x60,0x1e, |
839 | | 0x78,0x03,0xbc,0x09,0x16,0x81,0x38,0x90,0x08,0x52,0x40,0x1a,0x48,0x07,0xcb,0xc1, |
840 | | 0x2a,0xb0,0x06,0x64,0x83,0x5c,0x50,0x00,0x8a,0x40,0x31,0xd8,0x0a,0x4a,0xc0,0x4e, |
841 | | 0x50,0x06,0xf6,0x0c,0xda,0x87,0xb0,0x06,0xd4,0x83,0x26,0xd0,0x0c,0x0e,0x82,0x56, |
842 | | 0xce,0xb2,0xf7,0x10,0xb6,0x81,0x13,0xa0,0x13,0x7c,0x00,0xfe,0x09,0x3e,0x06,0xe7, |
843 | | 0xc0,0x05,0x70,0x11,0x5c,0x02,0x97,0xc1,0x97,0xe0,0x6b,0xf0,0x2d,0xf8,0x01,0xfc, |
844 | | 0xc4,0xb6,0x02,0x8c,0x4d,0x74,0x3a,0x13,0x60,0x0e,0x2c,0x80,0x35,0x10,0x00,0x1b, |
845 | | 0x60,0x0f,0x86,0x01,0x47,0xe0,0x0c,0x5c,0x81,0x3b,0x90,0x03,0x6f,0xe0,0x07,0x94, |
846 | | 0x20,0x10,0x04,0x83,0x30,0x10,0x09,0xa2,0x40,0x2c,0xb8,0x0f,0x3c,0x08,0x1e,0x01, |
847 | | 0x8f,0x81,0x27,0xc1,0xd3,0xe0,0x39,0x13,0xf6,0x7e,0x7b,0xd1,0xe4,0x65,0x93,0xb1, |
848 | | 0x26,0x13,0x4c,0x5e,0x35,0x99,0x6a,0x32,0xc3,0x64,0xb6,0xc9,0x6b,0x26,0xaf,0x9b, |
849 | | 0x2c,0x34,0x79,0xdb,0x84,0x31,0x49,0x30,0x49,0x36,0x49,0x35,0x59,0x66,0x92,0x69, |
850 | | 0xb2,0xd2,0x24,0xcb,0x64,0x9d,0xc9,0x7a,0x93,0x7c,0x93,0x42,0x93,0x4d,0x26,0x5b, |
851 | | 0x4c,0xb6,0x9b,0x94,0x9a,0xec,0x36,0xa9,0x30,0xd9,0x6b,0x52,0x6d,0x52,0x67,0xd2, |
852 | | 0x68,0xf2,0x8e,0x49,0x8b,0xc9,0x61,0x93,0x77,0x4d,0xfa,0x74,0x33,0x4c,0xfe,0xca, |
853 | | 0xd1,0x74,0xcc,0xd0,0xfa,0x42,0x58,0xd3,0xbf,0x3e,0xfb,0xbf,0xf2,0xe9,0x30,0xf9, |
854 | | 0xc0,0xe4,0x8c,0xc9,0xf9,0x3f,0xe9,0xbf,0x8b,0x26,0x57,0x4c,0xae,0x99,0xfc,0x64, |
855 | | 0xc2,0x33,0x1d,0x62,0x2a,0x30,0x75,0x30,0xbd,0xbb,0x2b,0xe1,0x5b,0xe3,0x3b,0xad, |
856 | | 0x8e,0x6f,0xe6,0x48,0x4c,0xdd,0x4d,0xfb,0x74,0x3e,0xa6,0xb7,0xd7,0xfe,0x63,0x3a, |
857 | | 0x6f,0xbf,0xce,0x37,0xf5,0xfd,0xfb,0x2d,0xf7,0xdd,0xe1,0x38,0xc0,0x94,0x0d,0xc3, |
858 | | 0x4c,0x6f,0x6d,0xb1,0xef,0x37,0xf5,0xdd,0xde,0x67,0xbd,0x44,0x9b,0x3e,0x60,0xfa, |
859 | | 0x98,0x29,0x9b,0xfb,0x8c,0xe9,0xed,0xde,0xf9,0xf7,0x77,0x1b,0xff,0xca,0xff,0xbf, |
860 | | 0x56,0x8a,0x95,0x97,0x4c,0x27,0x98,0xf6,0xdd,0xd1,0x93,0x7f,0xdc,0x82,0xbf,0xee, |
861 | | 0x33,0xcd,0x54,0xf7,0x2b,0xd7,0xb7,0x6f,0xe0,0x1a,0xf5,0xfd,0x8b,0x6b,0xf8,0xfb, |
862 | | 0xae,0xfa,0xaf,0xd7,0x9a,0x6b,0xfa,0xaf,0x47,0xdf,0xaf,0xb5,0xd0,0xf7,0xab,0x3e, |
863 | | 0x5c,0x68,0x1a,0x67,0x7a,0x37,0xf6,0x8f,0xbf,0xf6,0x59,0x62,0xfa,0x9f,0x9c,0x9b, |
864 | | 0x96,0x99,0xfe,0xb2,0xc7,0xab,0x06,0xf2,0x72,0x06,0x52,0x85,0x03,0xa9,0xad,0xbf, |
865 | | 0x6a,0xdf,0x2e,0xd3,0x5f,0xde,0x53,0x7b,0x91,0x57,0x6f,0x7a,0xc0,0xf4,0x5d,0xd3, |
866 | | 0x4e,0xd3,0x8f,0x6e,0xab,0xd9,0xfd,0x3b,0x7a,0x7a,0xf9,0x0e,0xf6,0x7d,0x33,0x90, |
867 | | 0xf7,0xe3,0x40,0xca,0xd8,0xac,0x3f,0x35,0xd8,0xec,0xd7,0xda,0x1a,0x6a,0x76,0x37, |
868 | | 0x9f,0x2c,0xf6,0x66,0xc3,0xcd,0x24,0x66,0xae,0x66,0x1e,0x66,0x5e,0x66,0x7e,0x66, |
869 | | 0x2a,0xb3,0x20,0xb3,0x30,0x33,0x8d,0x59,0x8c,0xd9,0x7d,0x66,0x0f,0x99,0x3d,0x6a, |
870 | | 0xf6,0xa4,0xd9,0x33,0x66,0x2f,0x98,0xbd,0x6c,0x36,0xce,0x6c,0x92,0xd9,0x54,0xb3, |
871 | | 0x99,0x66,0x73,0xcd,0x5e,0x37,0x7b,0xd3,0x6c,0xb1,0x59,0x82,0x59,0x8a,0xd9,0x52, |
872 | | 0xb3,0x4c,0xb3,0x55,0x66,0x6b,0xcd,0xd6,0x9b,0x15,0x98,0x6d,0x34,0xdb,0x62,0x56, |
873 | | 0x62,0xd6,0xa7,0xdb,0x65,0x76,0x73,0x64,0x54,0x98,0xfd,0x95,0x77,0xe7,0x3e,0xb3, |
874 | | 0xbb,0xd1,0x0a,0x11,0x91,0xee,0xbf,0xe6,0xc3,0xfa,0xb3,0xd6,0xac,0xd1,0xac,0xd9, |
875 | | 0xec,0x90,0xd9,0xbb,0x66,0x6d,0x66,0x7d,0xff,0xc1,0xd5,0xc5,0xbf,0xe7,0x29,0x1a, |
876 | | 0xf8,0xfc,0xd6,0x1c,0xfe,0x67,0x3f,0xa7,0xb0,0xb3,0xb8,0xce,0x63,0xf7,0x10,0xa6, |
877 | | 0xd8,0x37,0xa8,0x06,0x75,0x98,0xbd,0x6f,0x76,0xab,0x86,0x7f,0x9a,0x7d,0x62,0xf6, |
878 | | 0xa9,0xd9,0x45,0xb3,0xcf,0xcc,0xbe,0x30,0xfb,0xda,0xec,0x3b,0xb3,0x1f,0xcd,0x74, |
879 | | 0x66,0x3c,0x73,0x33,0xf3,0x7d,0x66,0x16,0xe6,0x7c,0x73,0x91,0xb9,0xbd,0xf9,0x70, |
880 | | 0x73,0x89,0xb9,0xab,0xb9,0x87,0xb9,0x97,0xb9,0x9f,0xb9,0xca,0x3c,0xc8,0x3c,0xcc, |
881 | | 0x5c,0x63,0x1e,0x63,0x7e,0x9f,0xf9,0x43,0xe6,0x8f,0x9a,0x3f,0x69,0xfe,0x8c,0xf9, |
882 | | 0x0b,0xe6,0x2f,0x9b,0x8f,0x33,0x9f,0x64,0x3e,0xd5,0x7c,0xa6,0xf9,0x5c,0xf3,0xd7, |
883 | | 0xcd,0xdf,0x34,0x5f,0x6c,0xce,0xb6,0x9c,0x60,0x9e,0x62,0xbe,0xd4,0xfc,0xaf,0xf2, |
884 | | 0xb7,0x11,0xbd,0x46,0x3c,0x78,0x8f,0x7d,0xaf,0xb8,0xd6,0xe8,0xf6,0xf7,0x8a,0x58, |
885 | | 0x6b,0xd3,0x5c,0x63,0x09,0xf6,0xe5,0xec,0x7b,0x45,0x1f,0x32,0xa2,0x4c,0xf3,0x95, |
886 | | 0xe6,0x59,0xe6,0x3c,0xee,0x3d,0x24,0xfb,0xd6,0x27,0xdb,0xdc,0x0a,0xa5,0x6c,0x51, |
887 | | 0xda,0xd7,0xc8,0x91,0x96,0x18,0xe5,0x9a,0x6f,0x30,0x97,0x70,0xa5,0x37,0x99,0x97, |
888 | | 0x1b,0x79,0xd1,0x56,0x73,0xfd,0xae,0x94,0xdd,0x73,0x0a,0xd0,0x0e,0xfb,0x76,0x92, |
889 | | 0xcd,0x79,0x98,0xcb,0xf9,0x75,0xbb,0xbe,0xbb,0x2b,0x3b,0xd3,0x1d,0xe6,0x26,0xb4, |
890 | | 0xcb,0x7c,0x25,0x65,0x9b,0x5b,0x50,0xb9,0x79,0xa5,0x79,0x95,0xf9,0x0e,0xa3,0x6d, |
891 | | 0x46,0xb5,0xe6,0x0d,0xe6,0xef,0x98,0xb7,0x98,0x1f,0x36,0x7f,0xcf,0xbc,0xcd,0xfc, |
892 | | 0x84,0x79,0xa5,0x51,0xa7,0xf9,0x07,0xe6,0x55,0x46,0xff,0x34,0xff,0xd8,0xfc,0x88, |
893 | | 0xd1,0x39,0xf3,0x22,0xe3,0x53,0x46,0x17,0xcc,0x4f,0x1b,0x15,0x1b,0xab,0xa8,0xc7, |
894 | | 0xfc,0x33,0xf3,0xf3,0x46,0x41,0xbc,0x2b,0xb8,0x02,0x5f,0x81,0x6f,0xc1,0x75,0xd0, |
895 | | 0x07,0x8c,0x07,0xeb,0x74,0xa6,0x60,0x08,0xb0,0x06,0x42,0x60,0x07,0x86,0x01,0x27, |
896 | | 0xe0,0x02,0xdc,0x81,0x27,0xf0,0x05,0x4a,0xa0,0x06,0xa1,0x20,0x12,0x44,0x83,0x7b, |
897 | | 0xc1,0x83,0x60,0x14,0x78,0x02,0x3c,0x0d,0x9e,0x07,0x2f,0x81,0xb1,0x60,0x22,0x98, |
898 | | 0x02,0x66,0x80,0x39,0x60,0x3e,0x58,0x08,0x16,0x81,0x78,0x90,0x0c,0xd2,0x40,0x06, |
899 | | 0x58,0x09,0xd6,0x80,0x1c,0x90,0x0f,0x8a,0xc0,0x66,0xb0,0x1d,0xec,0x04,0xe5,0x60, |
900 | | 0x2f,0xa8,0x01,0x0d,0xe0,0x1d,0x70,0x10,0x1c,0x01,0xc7,0xc0,0x09,0x70,0x0a,0x7c, |
901 | | 0x08,0x3e,0x06,0xe7,0x41,0x37,0xb8,0x04,0xae,0x80,0xaf,0xc0,0xb7,0xe0,0x3a,0xe8, |
902 | | 0x03,0xc6,0x43,0xd0,0x7f,0x30,0x04,0x58,0x03,0x21,0xb0,0x1b,0x72,0xd3,0xfb,0xc3, |
903 | | 0x86,0xb0,0x5a,0xe1,0x0b,0xe4,0x8d,0x04,0x52,0x20,0x07,0x3e,0x40,0x01,0x02,0x41, |
904 | | 0x08,0x88,0x00,0x51,0xe0,0x1e,0xf0,0x00,0x78,0x04,0x3c,0x0e,0x9e,0x02,0xcf,0x81, |
905 | | 0xd1,0x60,0x0c,0x98,0x00,0x26,0x83,0xe9,0x60,0x36,0x98,0x07,0x16,0x80,0xb7,0x41, |
906 | | 0x1c,0x48,0x02,0xa9,0x20,0x1d,0xac,0x00,0x59,0x20,0x1b,0xe4,0x81,0x42,0x50,0x0c, |
907 | | 0xb6,0x81,0x52,0x50,0x06,0x2a,0x41,0x35,0xa8,0x07,0xfb,0x41,0x0b,0x68,0x05,0x47, |
908 | | 0x41,0x3b,0xe8,0x04,0xa7,0xc1,0x99,0x21,0xbf,0x1c,0x59,0xe7,0x86,0x74,0x0d,0xe9, |
909 | | 0x1d,0x72,0x79,0xc8,0xd5,0x21,0xd7,0x86,0xfc,0x30,0xe4,0xc6,0x90,0xdb,0xe7,0x1d, |
910 | | 0x23,0x0b,0x13,0x8b,0xc1,0x16,0x56,0x16,0x02,0x0b,0x5b,0x8b,0x3b,0xcd,0x3f,0x62, |
911 | | 0x0b,0x47,0x8b,0x91,0x16,0x52,0x0b,0xb9,0x85,0x8f,0x85,0xc2,0x22,0xd0,0xe2,0xf6, |
912 | | 0xf3,0x21,0x16,0x11,0x16,0x51,0x16,0xf7,0x58,0x3c,0x60,0xf1,0x88,0xc5,0xe3,0x16, |
913 | | 0x4f,0x59,0xdc,0xde,0xfe,0x73,0x16,0xa3,0x2d,0xc6,0x58,0x4c,0xb0,0x98,0x6c,0x31, |
914 | | 0xfd,0x8e,0xed,0xf7,0xe9,0x66,0x23,0x7f,0x1e,0x58,0x00,0xde,0xfe,0x45,0xfb,0x71, |
915 | | 0x16,0x49,0x16,0xa9,0x16,0xe9,0x16,0x2b,0x2c,0xb2,0x2c,0xb2,0x2d,0xf2,0x70,0x7e, |
916 | | 0x08,0xee,0xb8,0xa1,0x40,0x04,0xec,0x80,0x18,0x8c,0x00,0x12,0xee,0xdd,0x53,0xa1, |
917 | | 0xc5,0x16,0x8b,0x52,0x8b,0x0a,0x8b,0x6a,0x8b,0x46,0x8b,0x16,0x8b,0x77,0x2d,0x6e, |
918 | | 0x3f,0x6e,0xb7,0x78,0xdf,0xe2,0x8c,0xc5,0xa7,0x16,0xbd,0x16,0x5f,0x58,0x5c,0xb3, |
919 | | 0xf8,0xf1,0x17,0xc7,0x46,0x96,0x66,0x96,0x56,0x96,0x22,0x4b,0xb1,0xa5,0xc4,0x52, |
920 | | 0x6a,0xe9,0x65,0x79,0xfb,0x31,0x6b,0x93,0xc2,0x32,0xc8,0x32,0xdc,0x92,0xed,0x4b, |
921 | | 0x94,0xe5,0x7d,0x96,0x0f,0x59,0x3e,0x6a,0x39,0x84,0x17,0x64,0xf9,0xa4,0xe5,0xe7, |
922 | | 0xc6,0x4f,0x5a,0x3e,0x63,0xf9,0x82,0xe5,0x18,0xcb,0x49,0x96,0xd3,0xb8,0xf3,0xb3, |
923 | | 0x2d,0x5f,0xb7,0x1c,0xca,0x7b,0xd3,0x52,0xc4,0x9b,0x64,0xb9,0xd8,0x32,0xc9,0x72, |
924 | | 0xa9,0xa5,0xbe,0x57,0x2b,0x2c,0xfb,0x7d,0xb1,0xda,0x72,0x9d,0x65,0xae,0x25,0xfb, |
925 | | 0x86,0x6c,0x83,0xe5,0x66,0xcb,0x1d,0x86,0xf3,0xe5,0x96,0xfd,0xfd,0xaf,0xb4,0xac, |
926 | | 0xb6,0xac,0xb7,0x1c,0xc1,0xdb,0x6f,0xd9,0x62,0x39,0x88,0xf7,0x2e,0x57,0xef,0xa8, |
927 | | 0x65,0x87,0xe5,0x07,0x5c,0xfb,0x67,0x2c,0x3f,0xb5,0x14,0xf3,0x2e,0x5a,0x4a,0x78, |
928 | | 0x1d,0x96,0x31,0xf4,0x99,0x25,0xfb,0xfd,0xc5,0x9d,0x44,0xff,0xdc,0xd1,0xeb,0xfc, |
929 | | 0xc2,0xf2,0xa6,0x77,0xbf,0xb6,0xfc,0xd7,0xfb,0x0a,0xdd,0xaf,0x7c,0x3b,0xf2,0x9d, |
930 | | 0x65,0x1f,0x6a,0x9a,0x5b,0xf1,0xad,0x06,0xc6,0x09,0x52,0x23,0xac,0x6e,0x6f,0xc5, |
931 | | 0xd9,0xca,0xd5,0xca,0xdd,0xea,0xd7,0xe7,0x3d,0xf9,0x6d,0xe7,0x02,0x6f,0x3e,0x28, |
932 | | 0xe9,0xa6,0xd6,0x5b,0x32,0x49,0x6d,0x25,0xe0,0xce,0x04,0x5b,0x85,0x5a,0x85,0x5b, |
933 | | 0x45,0x5a,0x69,0xad,0xa2,0xad,0x62,0xad,0xee,0xb5,0x7a,0xd0,0xea,0x61,0xab,0x51, |
934 | | 0x56,0xc3,0x71,0x7e,0x14,0xb1,0xdf,0xcf,0xdc,0xf9,0x3c,0xfb,0x1c,0x19,0x4c,0x8e, |
935 | | 0xe4,0x87,0x67,0x02,0x7f,0xe0,0xe9,0x21,0xe1,0xbe,0x8f,0xf2,0xb9,0xe3,0x37,0x51, |
936 | | 0x8f,0x59,0xfd,0x7b,0x33,0xf9,0x93,0x56,0xcf,0x58,0x99,0xd0,0x0b,0xa8,0xf5,0xb2, |
937 | | 0xd5,0x38,0xab,0x3c,0xf6,0x1b,0x0b,0x2b,0xf6,0x69,0xa5,0x97,0x6b,0x78,0x6a,0x09, |
938 | | 0xa0,0xd5,0x1e,0x7a,0x86,0xd3,0x54,0xae,0x6d,0xfd,0x37,0x62,0xac,0xb0,0x47,0x33, |
939 | | 0xac,0x66,0x5b,0xcd,0x43,0x3e,0x6b,0xc9,0x18,0x9e,0x3e,0xb6,0xa5,0xd9,0xdc,0x77, |
940 | | 0x6a,0x58,0x05,0x73,0xdf,0xaa,0xbd,0x61,0x25,0x46,0x1f,0xde,0xb2,0x5a,0x6c,0x15, |
941 | | 0x6f,0x95,0x04,0x7f,0x60,0x77,0x61,0xf5,0x00,0x9e,0x55,0x32,0xde,0x03,0xbc,0x65, |
942 | | 0x03,0xf6,0x9a,0x71,0xcf,0x3e,0xf6,0x29,0x79,0xab,0x7d,0xcb,0xad,0xd6,0x58,0xe5, |
943 | | 0x5a,0x6d,0xb4,0xda,0x66,0xb5,0xcb,0xaa,0xd2,0xaa,0xd6,0x6a,0xbf,0xd5,0x21,0xab, |
944 | | 0xa3,0x56,0x1d,0x56,0xa7,0xad,0x3e,0xb1,0xea,0xb2,0xfa,0x0c,0xad,0x7d,0x69,0xf5, |
945 | | 0xb5,0xd5,0x77,0x56,0x5e,0x74,0xdd,0xea,0x86,0x95,0x91,0xb5,0xa9,0xb5,0x1f,0x0d, |
946 | | 0xb6,0xb6,0xb4,0xb6,0xe7,0xbe,0xd3,0x13,0xd3,0x6f,0x9d,0x37,0xac,0xc9,0xad,0x6f, |
947 | | 0x6a,0xb4,0xb1,0xbe,0x7d,0xf7,0xf0,0xdf,0xf8,0x19,0x66,0x3d,0x12,0xfd,0xf0,0xb2, |
948 | | 0x56,0x5a,0xff,0xa7,0x35,0x87,0x5b,0x6b,0xff,0xb4,0xce,0xdf,0xbf,0x7f,0xbd,0xc3, |
949 | | 0xdd,0x63,0x7d,0x9f,0xf5,0x83,0xd6,0x8f,0x58,0x3f,0x66,0xfd,0xa4,0xf5,0xd3,0xd6, |
950 | | 0xcf,0x59,0xbf,0x68,0xfd,0xb2,0xf5,0x58,0xeb,0x09,0xd6,0x93,0xad,0xa7,0x5b,0xcf, |
951 | | 0xb6,0x9e,0x67,0xbd,0xc0,0xfa,0x6d,0xeb,0x38,0xeb,0x24,0xeb,0x54,0xeb,0x0c,0xeb, |
952 | | 0x55,0xd6,0xeb,0xac,0xf3,0xac,0x8b,0xac,0xb7,0x58,0xef,0xb0,0x2e,0xb3,0xde,0x6b, |
953 | | 0x5d,0x6b,0xfd,0x7b,0xf5,0x36,0x59,0x1f,0xb0,0x3e,0x6c,0xfd,0x9e,0xf5,0x71,0xeb, |
954 | | 0x93,0xd6,0x1f,0x58,0x7f,0x64,0x7d,0xd6,0xfa,0x82,0x75,0x8f,0xf5,0xe7,0xd6,0x5f, |
955 | | 0x5a,0x7f,0x63,0xfd,0xbd,0xf5,0x4f,0xd6,0xc4,0x1f,0xc4,0x37,0xe7,0x5b,0xf2,0x87, |
956 | | 0xf2,0x6d,0xf8,0x0e,0xfc,0x11,0x7c,0x67,0xbe,0x1b,0xff,0x8f,0x7c,0xd3,0xfc,0x47, |
957 | | 0xea,0xa8,0xad,0xfe,0xfc,0x55,0x94,0xf1,0x75,0xff,0xa7,0x3e,0x81,0xfc,0x10,0x7e, |
958 | | 0xf8,0x5d,0xec,0x93,0xf6,0x2e,0xb5,0x75,0x2f,0xff,0x41,0xfe,0x28,0xfe,0x13,0xfc, |
959 | | 0xa7,0xf9,0xcf,0xf3,0x5f,0xe2,0x8f,0xe5,0x4f,0xe4,0x4f,0xe1,0xcf,0xe0,0xcf,0xe1, |
960 | | 0xcf,0xe7,0x2f,0xe4,0x2f,0xe2,0xc7,0xf3,0x93,0xf9,0x69,0xfc,0x0c,0xfe,0x4a,0xfe, |
961 | | 0x1a,0x7e,0x0e,0x3f,0x9f,0x5f,0xc4,0xdf,0xcc,0xdf,0xce,0xdf,0xc9,0x2f,0xe7,0xef, |
962 | | 0xe5,0xd7,0xf0,0x1b,0xf8,0xef,0xf0,0x0f,0xf2,0x8f,0xf0,0x8f,0xf1,0x4f,0xf0,0x4f, |
963 | | 0xf1,0x3f,0xe4,0x7f,0xcc,0x3f,0xcf,0xef,0xe6,0x5f,0xe2,0x5f,0xe1,0x7f,0xc5,0xff, |
964 | | 0x96,0x7f,0x9d,0xdf,0xc7,0x37,0x1e,0xfa,0x57,0xfb,0xd5,0x14,0x1a,0x86,0x0c,0xb5, |
965 | | 0x1a,0x2a,0xe0,0x34,0xd9,0x20,0x74,0x00,0x23,0xc0,0x4a,0xec,0x01,0x32,0xcd,0x77, |
966 | | 0x60,0x3d,0xef,0xcc,0x9d,0x73,0xfb,0x99,0x2d,0x22,0x8c,0x57,0xd9,0x50,0xaf,0xa1, |
967 | | 0xbe,0xc8,0x55,0x02,0x35,0x08,0x05,0x91,0x20,0x1a,0xdc,0x0b,0x1e,0x04,0xa3,0xc0, |
968 | | 0x13,0xe0,0x69,0xf0,0x3c,0x78,0x09,0x8c,0x05,0x13,0xc1,0x14,0x30,0x03,0xcc,0x01, |
969 | | 0xf3,0xc1,0x42,0xb0,0x08,0xc4,0x83,0x64,0x90,0x06,0x32,0x58,0x4b,0xc0,0x1a,0x90, |
970 | | 0x03,0xf2,0x41,0x11,0xd8,0x0c,0xb6,0x83,0x9d,0xa0,0x1c,0xec,0x05,0x35,0xa0,0x01, |
971 | | 0xbc,0x03,0x0e,0x82,0x23,0xe0,0x18,0x38,0x01,0x4e,0x81,0x0f,0xc1,0xc7,0xe0,0x3c, |
972 | | 0xe8,0x06,0x97,0xc0,0x15,0xf0,0xd5,0x2f,0xbc,0xfc,0x2d,0x72,0xae,0x0f,0xe4,0xf6, |
973 | | 0x0d,0xd5,0xfd,0xc7,0xde,0x77,0xfe,0x7c,0x96,0x32,0x16,0xe8,0xfe,0xd0,0xdb,0xbf, |
974 | | 0xdf,0xfb,0x86,0xdb,0x54,0xf0,0xdf,0x71,0xf7,0x0f,0x11,0xfc,0x9a,0x07,0xac,0x05, |
975 | | 0x42,0x81,0x9d,0x60,0x98,0xc0,0x49,0xe0,0x22,0x70,0x17,0x78,0x0a,0x7c,0x05,0x4a, |
976 | | 0x81,0x5a,0x10,0x2a,0x88,0x14,0x44,0x0b,0xee,0x15,0x3c,0x28,0x18,0x25,0x78,0x42, |
977 | | 0xf0,0xb4,0xe0,0x79,0xc1,0x4b,0x82,0xb1,0x82,0x89,0x82,0x29,0x82,0x19,0x82,0x39, |
978 | | 0x82,0xf9,0x82,0x85,0x82,0x45,0x82,0x78,0x41,0xb2,0x20,0x4d,0x90,0x21,0x58,0x29, |
979 | | 0x58,0x23,0xc8,0x11,0xe4,0x0b,0x8a,0x04,0x9b,0x05,0xdb,0x05,0x3b,0x05,0xe5,0x82, |
980 | | 0xbd,0x82,0x1a,0x41,0x83,0xe0,0x1d,0xc1,0x41,0xc1,0x11,0xc1,0x31,0xc1,0x09,0xc1, |
981 | | 0x29,0xc1,0x87,0x82,0x8f,0x05,0xe7,0x05,0xdd,0x82,0x4b,0x82,0x2b,0x82,0xaf,0x04, |
982 | | 0xdf,0x0a,0xae,0x0b,0xfa,0x04,0xc6,0x42,0x53,0xe1,0x10,0xa1,0xb5,0x50,0x28,0xb4, |
983 | | 0x13,0x0e,0x13,0x3a,0x09,0x5d,0x84,0xee,0x42,0x4f,0xa1,0xaf,0x50,0x29,0x54,0x0b, |
984 | | 0x43,0x85,0x91,0xc2,0x68,0xe1,0xbd,0xc2,0x07,0x85,0xa3,0x84,0x4f,0x08,0x9f,0x16, |
985 | | 0x3e,0x2f,0x7c,0x49,0x38,0x56,0x38,0x51,0x38,0x45,0x38,0x43,0x38,0x47,0x38,0x5f, |
986 | | 0xb8,0x50,0xb8,0x48,0x18,0x2f,0x4c,0x16,0xa6,0x09,0x33,0x84,0x2b,0x85,0x6b,0x84, |
987 | | 0x39,0xc2,0x7c,0x61,0x91,0x70,0xb3,0x70,0xbb,0x70,0xa7,0xb0,0x5c,0xb8,0x57,0x58, |
988 | | 0x23,0x6c,0x10,0xbe,0x23,0x3c,0x28,0x3c,0x22,0x3c,0x26,0x3c,0x21,0x3c,0x25,0xfc, |
989 | | 0x50,0xf8,0xb1,0xf0,0xbc,0xb0,0x5b,0x78,0x49,0x78,0x45,0xf8,0x95,0xf0,0x5b,0xe1, |
990 | | 0x75,0x61,0x9f,0xd0,0x58,0x64,0x2a,0x1a,0x22,0xb2,0x16,0x09,0x45,0x76,0xa2,0x61, |
991 | | 0x22,0x27,0x91,0x8b,0xc8,0x5d,0xe4,0x29,0xf2,0x15,0x29,0x45,0x6a,0x51,0xa8,0x28, |
992 | | 0x52,0x14,0x2d,0xba,0x57,0xf4,0xa0,0x68,0x94,0xe8,0x09,0xd1,0xd3,0xa2,0xe7,0x45, |
993 | | 0x2f,0x89,0xc6,0x8a,0x26,0x8a,0xa6,0x88,0x66,0x88,0xe6,0x88,0xe6,0x8b,0x16,0x8a, |
994 | | 0x16,0x89,0xe2,0x45,0xc9,0xa2,0x34,0x51,0x86,0x68,0xa5,0x68,0x8d,0x28,0x47,0x94, |
995 | | 0x2f,0x2a,0x12,0x6d,0x16,0x6d,0x17,0xed,0x14,0x95,0x8b,0xf6,0x8a,0x6a,0x44,0x0d, |
996 | | 0xa2,0x77,0x44,0x07,0x45,0x47,0x44,0xc7,0x44,0x27,0x44,0xa7,0x44,0x1f,0x8a,0x3e, |
997 | | 0x16,0x9d,0x17,0x75,0x8b,0x2e,0x89,0xae,0x88,0xbe,0x12,0x7d,0x2b,0xba,0x2e,0xea, |
998 | | 0x13,0x19,0xdb,0x98,0xda,0x0c,0xb1,0xb1,0xb6,0x11,0xda,0xd8,0xd9,0x0c,0xb3,0x71, |
999 | | 0xb2,0x71,0xb1,0x71,0xb7,0xf1,0xb4,0xf1,0xb5,0x51,0xda,0xa8,0x6d,0x42,0x6d,0x22, |
1000 | | 0x6d,0xa2,0x6d,0xee,0xb5,0x79,0xd0,0x66,0x94,0xcd,0x13,0x36,0x4f,0xdb,0x3c,0x6f, |
1001 | | 0xf3,0x92,0xcd,0x58,0x9b,0x3e,0xdd,0xdd,0x17,0x76,0x87,0x30,0xd1,0xe6,0x3f,0x33, |
1002 | | 0x0a,0x5f,0x85,0x9e,0x29,0x82,0x69,0x36,0xb3,0x6c,0xfe,0xcc,0xdd,0xcd,0x7e,0x5e, |
1003 | | 0xb3,0x59,0xc0,0xb5,0xb1,0xc8,0xe6,0xbf,0xfb,0xa9,0x9c,0x64,0xf3,0x57,0xcf,0x8b, |
1004 | | 0x7d,0xba,0x65,0x36,0xcb,0x6d,0x56,0xdb,0xac,0xb3,0xc9,0xb5,0xd9,0x60,0xb3,0xc9, |
1005 | | 0x66,0xab,0xcd,0x0e,0x9b,0xdd,0x36,0x7b,0x6c,0xaa,0x6c,0xea,0x6c,0x9a,0x6c,0x0e, |
1006 | | 0xd8,0x1c,0xb6,0x79,0xcf,0xe6,0xb8,0xcd,0x49,0x9b,0x0f,0x6c,0x3e,0xb2,0x39,0x6b, |
1007 | | 0x73,0xc1,0xa6,0xc7,0xe6,0x73,0x9b,0x2f,0x6d,0xbe,0xb1,0xf9,0xde,0xe6,0x27,0x1b, |
1008 | | 0xb2,0x1d,0x64,0x6b,0x6e,0x6b,0x69,0x3b,0xd4,0xd6,0xc6,0xd6,0xc1,0x76,0x84,0xad, |
1009 | | 0xb3,0xad,0x9b,0xad,0xcc,0xd6,0xdb,0xd6,0xdf,0x36,0xc0,0x36,0xd8,0x36,0xdc,0x56, |
1010 | | 0x6b,0x1b,0x6b,0x7b,0xbf,0xed,0xc3,0xb6,0x8f,0xd9,0xfe,0xc3,0x96,0xe8,0x59,0xdb, |
1011 | | 0x17,0x6d,0x5f,0xb1,0x1d,0x6f,0xfb,0xaa,0xed,0x34,0xdb,0x59,0xb6,0xaf,0xd9,0xbe, |
1012 | | 0x61,0xfb,0x96,0x2d,0x63,0x9b,0x68,0xbb,0xc4,0x76,0x99,0xed,0x72,0xdb,0xd5,0xb6, |
1013 | | 0xeb,0x6c,0x73,0x6d,0x37,0xd8,0x6e,0xb2,0xdd,0x6a,0xbb,0xc3,0x76,0xb7,0xed,0x1e, |
1014 | | 0xdb,0x2a,0xdb,0x3a,0xdb,0x26,0xdb,0x03,0xb6,0x87,0x6d,0xdf,0xb3,0x3d,0x6e,0x7b, |
1015 | | 0xd2,0xf6,0x03,0xdb,0x8f,0x6c,0xcf,0xda,0x5e,0xb0,0xed,0xb1,0xfd,0xdc,0xf6,0x4b, |
1016 | | 0xdb,0x6f,0x6c,0xbf,0xb7,0xfd,0xc9,0x56,0xef,0x15,0x6b,0xcc,0x4c,0x64,0x37,0xc8, |
1017 | | 0xce,0xdc,0xce,0xd2,0x6e,0xa8,0x9d,0x8d,0x9d,0x93,0xc0,0xc1,0x6e,0x84,0x9d,0xb3, |
1018 | | 0x9d,0x9b,0x9d,0xef,0x9f,0x9e,0x7f,0x65,0x76,0xbe,0x76,0x01,0x76,0xa1,0x76,0x5a, |
1019 | | 0xbb,0x7b,0xed,0x1e,0xb6,0x7b,0xc2,0xee,0x59,0xbb,0x97,0xec,0xc6,0xdb,0x4d,0xb1, |
1020 | | 0x9b,0x65,0x37,0xdf,0xee,0x2d,0xbb,0x78,0xbb,0x25,0x76,0x19,0x76,0xab,0xed,0x72, |
1021 | | 0xec,0x36,0xd8,0x6d,0xb6,0xdb,0x61,0x57,0x6e,0x57,0x65,0xd7,0x60,0x77,0xc0,0xee, |
1022 | | 0x88,0xdd,0x71,0xbb,0x53,0x76,0x9f,0xd8,0xf5,0xe9,0x7a,0xec,0xae,0xd8,0x7d,0x63, |
1023 | | 0x77,0xdd,0x8e,0xec,0x4d,0xed,0x2d,0xed,0x85,0xf6,0x0e,0xf6,0x4e,0xf6,0x6e,0xf6, |
1024 | | 0x9e,0xf6,0xfe,0xf6,0x6a,0xfb,0x70,0xfb,0x68,0xfb,0xfb,0xed,0x47,0xd9,0xff,0xc3, |
1025 | | 0xfe,0x79,0xfb,0x57,0xec,0x27,0xda,0x4f,0xb3,0x9f,0x63,0xff,0x86,0xfd,0x22,0xfb, |
1026 | | 0x44,0xfb,0x34,0xfb,0xe5,0xf6,0x6b,0xec,0x73,0xed,0x8b,0xec,0xb7,0xda,0xef,0xb4, |
1027 | | 0xdf,0x63,0x5f,0x63,0xdf,0x64,0x7f,0xc0,0xde,0x4e,0x78,0xd8,0xfe,0x76,0xfb,0xde, |
1028 | | 0xb3,0x3f,0x6e,0xdf,0x61,0x7f,0xca,0xfe,0xb4,0xfd,0x47,0xf6,0x9f,0xd8,0x9f,0xb7, |
1029 | | 0xef,0xb2,0xef,0xb1,0xff,0xcc,0xfe,0x8a,0xfd,0x55,0xfb,0x6f,0xec,0xbf,0xb3,0xbf, |
1030 | | 0x6e,0xbf,0x0c,0x57,0x76,0x13,0xae,0x29,0x7b,0x15,0x3f,0xe2,0xae,0xdf,0xcd,0xab, |
1031 | | 0x77,0xc3,0xde,0xc8,0xc1,0xc4,0x61,0xb0,0x83,0x95,0x83,0xc0,0xc1,0xd6,0x41,0xec, |
1032 | | 0xe0,0xe8,0x30,0xd2,0x41,0xea,0x20,0x77,0xf0,0x71,0x50,0x38,0x04,0x3a,0x84,0x3b, |
1033 | | 0xc4,0x38,0xdc,0xf4,0xed,0x7d,0x0e,0x0f,0x39,0x3c,0xea,0x10,0x2a,0x78,0xd2,0x61, |
1034 | | 0x8a,0x40,0x89,0xb9,0xf6,0x25,0xcc,0xc2,0x9b,0x45,0x69,0x02,0x4f,0xe1,0x33,0x0e, |
1035 | | 0x2f,0x38,0xbc,0xec,0x30,0xce,0x61,0x92,0xc3,0x54,0x87,0x99,0x0e,0x73,0x1d,0x5e, |
1036 | | 0x77,0x78,0xd3,0xa1,0x48,0xb0,0xd8,0x21,0xc1,0x21,0xc5,0x61,0xa9,0x43,0xa6,0xc3, |
1037 | | 0x2a,0x87,0xb5,0x0e,0xeb,0x1d,0xf4,0xd7,0xa6,0xc0,0x61,0xa3,0xc3,0x16,0x87,0x12, |
1038 | | 0x87,0x5d,0x0e,0x15,0x0e,0xfb,0x1c,0x6a,0x1d,0x1a,0x1d,0x9a,0x1d,0x0e,0x39,0x1c, |
1039 | | 0x71,0x38,0xea,0x70,0xdc,0xa1,0xc3,0xe1,0x94,0xc3,0x69,0x87,0x8f,0x1c,0x3e,0x71, |
1040 | | 0x38,0xef,0xd0,0xe5,0xd0,0xe3,0xf0,0x99,0xc3,0x15,0x87,0xab,0x0e,0xdf,0x38,0xfc, |
1041 | | 0xe0,0xd0,0xe7,0xc0,0x13,0x9b,0x8b,0xad,0xc4,0x42,0xb1,0xbd,0x78,0x84,0x78,0xa4, |
1042 | | 0xd8,0x43,0xec,0x23,0x56,0x89,0xd5,0xe2,0x50,0x71,0x84,0x38,0x4a,0x7c,0x8f,0xf8, |
1043 | | 0x01,0xf1,0x23,0xe2,0xc7,0xc5,0x4f,0x89,0x9f,0x13,0x8f,0x16,0x8f,0x11,0x4f,0x10, |
1044 | | 0x4f,0x16,0x4f,0x17,0xcf,0x16,0xcf,0x13,0x2f,0x10,0xbf,0x2d,0x8e,0x13,0x27,0x89, |
1045 | | 0x53,0xc5,0xe9,0xe2,0x15,0xe2,0x2c,0x71,0xb6,0x38,0x4f,0x5c,0x28,0x2e,0x16,0x6f, |
1046 | | 0x13,0x97,0x8a,0xcb,0xc4,0x95,0xe2,0x6a,0x71,0xbd,0x78,0xbf,0xb8,0x45,0xdc,0x2a, |
1047 | | 0x3e,0x2a,0x6e,0x17,0x77,0x8a,0x4f,0x8b,0xcf,0x88,0xcf,0x89,0xbb,0xc4,0xbd,0xe2, |
1048 | | 0xcb,0xe2,0xab,0xe2,0x6b,0xe2,0x1f,0xc4,0x37,0xc4,0x83,0x86,0x09,0x86,0x39,0x0d, |
1049 | | 0xf3,0x1a,0x16,0x38,0x2c,0x7a,0xd8,0xc3,0xc3,0x9e,0x1e,0x36,0x71,0xd8,0xdc,0x61, |
1050 | | 0x6f,0x0f,0x4b,0x19,0xb6,0x62,0x58,0xfe,0xb0,0x92,0x61,0x95,0xc3,0x1a,0x87,0x1d, |
1051 | | 0x1c,0x76,0x7c,0xd8,0x99,0x61,0x97,0x86,0x5d,0x1d,0x66,0x34,0xdc,0x66,0xb8,0xdb, |
1052 | | 0x70,0xdf,0xe1,0x91,0xc3,0x47,0x0d,0x7f,0x61,0xf8,0x84,0xe1,0x33,0x87,0x2f,0x18, |
1053 | | 0x9e,0x3c,0x7c,0xcd,0xf0,0x8d,0xc3,0x4b,0x87,0xef,0x1b,0xbe,0x7f,0xf8,0xe1,0xe1, |
1054 | | 0x6d,0xc3,0x4f,0x0d,0x3f,0x33,0xfc,0xe2,0xf0,0xab,0xc3,0x8d,0x46,0x58,0x8c,0x70, |
1055 | | 0x18,0x21,0x1b,0xa1,0x1c,0x11,0x32,0x42,0x3b,0xe2,0xb1,0x11,0xa3,0x47,0x4c,0x1f, |
1056 | | 0xf1,0xfa,0x88,0x94,0x11,0x19,0x23,0xd6,0x8d,0x28,0x1a,0xb1,0x63,0xc4,0xde,0x11, |
1057 | | 0x4d,0x23,0x8e,0x8e,0x78,0x7f,0xc4,0xc7,0x23,0x7a,0x46,0x7c,0x35,0xe2,0xa7,0x11, |
1058 | | 0x83,0x1d,0x45,0x8e,0x8e,0x8e,0x1e,0x8e,0x41,0x8e,0xb1,0x8e,0x0f,0x39,0xbe,0xe0, |
1059 | | 0x38,0xd6,0x71,0xa6,0xe3,0x5b,0x8e,0xc9,0x8e,0xcb,0x1d,0x73,0x1c,0xb7,0x38,0xee, |
1060 | | 0x74,0xac,0x72,0x6c,0x71,0x7c,0xcf,0xf1,0x23,0xc7,0x6e,0xc7,0xcf,0x1c,0xbf,0x74, |
1061 | | 0xbc,0xe6,0x78,0xdd,0x51,0xe7,0x38,0xc8,0x69,0xb0,0x93,0xb5,0x93,0xc8,0xc9,0xc1, |
1062 | | 0xc9,0xc9,0xc9,0xcd,0xc9,0xd3,0xc9,0xdf,0x49,0xed,0x14,0xee,0x14,0xed,0x74,0xbf, |
1063 | | 0xd3,0x28,0xa7,0x7f,0x38,0x3d,0xef,0xf4,0x8a,0xd3,0x44,0xa7,0x69,0x4e,0x73,0x9c, |
1064 | | 0xe6,0x3b,0x2d,0x70,0x7a,0xcb,0x89,0x71,0x4a,0x70,0x4a,0x76,0x4a,0x75,0x4a,0x77, |
1065 | | 0x5a,0xe1,0xb4,0xda,0x69,0xbd,0x53,0x91,0xd3,0x36,0xa7,0xdd,0x4e,0xf5,0x4e,0x4d, |
1066 | | 0x4e,0xcd,0x4e,0x87,0x9c,0x8e,0x38,0x1d,0x75,0x3a,0xee,0xd4,0xe1,0x74,0xca,0xe9, |
1067 | | 0x43,0xa7,0x4f,0x9c,0xce,0x3b,0x75,0x39,0xf5,0x3a,0x5d,0x76,0xfa,0xd2,0xe9,0x6b, |
1068 | | 0xa7,0x6f,0x9d,0xae,0x3b,0xf5,0x39,0x19,0x4b,0x4c,0x25,0x43,0x24,0x56,0x92,0xa1, |
1069 | | 0x12,0x91,0xc4,0x4e,0x22,0x96,0x38,0x4a,0x9c,0x25,0xae,0x12,0x77,0x89,0xa7,0xc4, |
1070 | | 0x57,0xa2,0x90,0x04,0x4a,0x42,0x24,0x11,0x12,0xad,0x24,0x56,0xf2,0xa0,0xa4,0xde, |
1071 | | 0xe9,0x71,0xc9,0x53,0x92,0xe7,0x24,0xa3,0x25,0x63,0x24,0x93,0x25,0x73,0x24,0xf3, |
1072 | | 0x24,0x6f,0x48,0xde,0x92,0x2c,0x96,0xc4,0x4b,0x92,0x24,0xa9,0x92,0x65,0x20,0x53, |
1073 | | 0xb2,0x52,0x92,0x25,0xc9,0x96,0xe4,0x82,0x02,0xc9,0x46,0x49,0x9f,0x6e,0x8b,0x64, |
1074 | | 0xbb,0xa4,0x54,0xb2,0x1b,0xa9,0x7d,0x92,0x1a,0x49,0xbd,0xa4,0x49,0xd2,0x2c,0x39, |
1075 | | 0x88,0xf6,0x5b,0x25,0xef,0x49,0xda,0x24,0x27,0x24,0xa7,0x24,0xc7,0x9d,0x4e,0x4b, |
1076 | | 0xce,0x48,0xce,0xa1,0xc4,0x05,0x49,0x8f,0xe4,0x33,0xc9,0x15,0xc9,0x55,0xc9,0x37, |
1077 | | 0x92,0xeb,0x12,0x72,0x36,0x71,0x1e,0xe2,0xcc,0x77,0xb6,0x71,0x16,0x3b,0x3b,0x39, |
1078 | | 0xbb,0x3a,0xcb,0x9c,0x7d,0x9c,0x55,0xce,0x21,0xce,0x1a,0xe7,0x7b,0x9c,0x1f,0x72, |
1079 | | 0x7e,0xdc,0xf9,0x19,0xe7,0xd1,0xce,0xe3,0x9c,0x27,0x3b,0xcf,0x74,0x9e,0xe7,0xfc, |
1080 | | 0xa6,0x73,0x9c,0x73,0x8a,0x73,0xba,0xf3,0x2a,0xe7,0x6c,0xe7,0x02,0xe7,0x62,0xe7, |
1081 | | 0x12,0xe7,0x32,0xe7,0x4a,0x67,0x9d,0xae,0x1a,0xd4,0x83,0xfd,0xa0,0x05,0x74,0x98, |
1082 | | 0xe9,0x74,0xad,0x88,0x8f,0x82,0x76,0xd0,0x09,0x4e,0x83,0x33,0xe0,0x1c,0xe8,0x02, |
1083 | | 0xbd,0xe0,0x32,0xb8,0x0a,0xae,0x81,0x1f,0xc0,0x0d,0x60,0x34,0x52,0xa7,0x33,0x01, |
1084 | | 0x83,0x47,0xfe,0xbe,0xf9,0xc7,0x0a,0xe5,0x04,0xc0,0x16,0x88,0x81,0x23,0x18,0x09, |
1085 | | 0xa4,0x40,0x0e,0x7c,0x80,0x02,0x04,0x82,0x10,0x10,0x01,0xa2,0x80,0xd3,0x20,0xb7, |
1086 | | 0x41,0xff,0x5b,0x9e,0x62,0xf7,0xc0,0x9e,0x07,0xc0,0x23,0xe0,0x71,0xf0,0x14,0x78, |
1087 | | 0x0e,0x8c,0x36,0xf8,0x60,0x0c,0xe2,0x09,0x60,0x32,0x98,0x0e,0x66,0x83,0x79,0x60, |
1088 | | 0x01,0x78,0x1b,0xc4,0x81,0x24,0x90,0x0a,0xd2,0xc1,0x0a,0x90,0x05,0xb2,0x41,0x1e, |
1089 | | 0x28,0x04,0xc5,0x60,0x1b,0x28,0x05,0x65,0xa0,0x12,0x54,0x83,0x7a,0xb0,0x1f,0xb4, |
1090 | | 0x80,0x56,0x70,0x14,0xb4,0x83,0x4e,0x70,0xda,0xc0,0xcf,0x3f,0x67,0x90,0x73,0x0e, |
1091 | | 0x74,0x8d,0xec,0x45,0x78,0x19,0x5c,0x05,0xd7,0xc0,0x0f,0x03,0x65,0x6f,0x20,0x55, |
1092 | | 0xc5,0x7d,0x37,0x66,0xe4,0x82,0xeb,0xe9,0x62,0xf8,0x4e,0x1b,0xb1,0x15,0x10,0x00, |
1093 | | 0x5b,0x20,0x06,0x8e,0x60,0x24,0x90,0x02,0x39,0xf0,0x01,0xfb,0x8c,0xb3,0xcd,0x2b, |
1094 | | 0xcd,0x15,0x2e,0xb5,0x68,0x21,0xc0,0x25,0xc8,0xe5,0x1d,0xf3,0x50,0x97,0x48,0xe4, |
1095 | | 0x47,0x83,0x7b,0xc1,0x83,0x60,0x14,0x78,0x02,0x3c,0x0d,0x9e,0x07,0x2f,0xb9,0x7c, |
1096 | | 0x6c,0x3e,0xd6,0x65,0x22,0x52,0x53,0xc0,0x0c,0x97,0xd9,0x08,0xe7,0x81,0x05,0xe0, |
1097 | | 0x6d,0x10,0x07,0x92,0x40,0x2a,0x48,0x07,0x2b,0x5c,0x56,0xbb,0xf4,0xaf,0x1c,0xd6, |
1098 | | 0xba,0xfc,0xab,0x15,0x9e,0x94,0x4c,0xc8,0x82,0x46,0x52,0x0e,0xd7,0x8b,0x6b,0x14, |
1099 | | 0x6a,0x74,0x37,0xae,0xf9,0x23,0x23,0xf3,0x5d,0x86,0x0c,0x2d,0x72,0xf9,0xe5,0x99, |
1100 | | 0xcd,0x5c,0xde,0x36,0x97,0x52,0xce,0xaa,0x32,0x97,0x4a,0x97,0x6a,0x97,0x7a,0x97, |
1101 | | 0xfd,0x2e,0x2d,0x2e,0xad,0x2e,0x47,0x5d,0xda,0x5d,0x3a,0x5d,0x4e,0xbb,0x9c,0x71, |
1102 | | 0x39,0xe7,0xd2,0xe5,0xd2,0xeb,0x72,0xd9,0xe5,0xaa,0xcb,0x35,0x97,0x1f,0x5c,0x6e, |
1103 | | 0xb8,0x18,0xb9,0x9a,0xb8,0x0e,0x76,0xb5,0x72,0x15,0xb8,0xda,0xba,0x8a,0x5d,0x1d, |
1104 | | 0x5d,0x47,0xba,0x4a,0x5d,0xe5,0xae,0x3e,0xae,0x0a,0xd7,0x40,0xd7,0x10,0xd7,0x08, |
1105 | | 0xd7,0x28,0xd7,0x7b,0x5c,0x1f,0x70,0x7d,0xc4,0xf5,0x71,0xd7,0xa7,0x5c,0x9f,0x73, |
1106 | | 0x1d,0xed,0x3a,0xc6,0x75,0x82,0xeb,0x64,0xd7,0xe9,0xae,0xb3,0x5d,0xe7,0xb9,0x2e, |
1107 | | 0x70,0x7d,0xdb,0x35,0xce,0x35,0xc9,0x35,0xd5,0x35,0xdd,0x75,0x85,0x6b,0x96,0x6b, |
1108 | | 0xb6,0x6b,0x9e,0x6b,0xa1,0x6b,0xb1,0xeb,0x36,0xd7,0x52,0xd7,0x32,0xd7,0x4a,0xd7, |
1109 | | 0x6a,0xd7,0x7a,0xd7,0xfd,0xae,0x2d,0xae,0xad,0xae,0x47,0x5d,0xdb,0x5d,0x3b,0x5d, |
1110 | | 0x4f,0xbb,0x9e,0x71,0x3d,0xe7,0xda,0xe5,0xda,0xeb,0x7a,0xd9,0xf5,0xaa,0xeb,0x35, |
1111 | | 0xd7,0x64,0xd1,0x0f,0xae,0x37,0x5c,0x8d,0xdc,0x4c,0xdc,0x5e,0xc2,0x3a,0x7b,0xb0, |
1112 | | 0xdb,0x66,0x91,0x95,0x9b,0xc0,0xcd,0xd6,0x4d,0xec,0xe6,0xe8,0x36,0xd2,0x4d,0xea, |
1113 | | 0x26,0x77,0xf3,0x71,0x53,0xb8,0x05,0xba,0x85,0xb8,0x45,0xb8,0x45,0xb9,0xdd,0xe3, |
1114 | | 0xf6,0x80,0xdb,0x23,0x6e,0x8f,0xbb,0x3d,0xe5,0xf6,0x9c,0xdb,0x68,0xb7,0x31,0x6e, |
1115 | | 0x13,0xdc,0x26,0xbb,0x4d,0x77,0x9b,0xed,0x36,0xcf,0x6d,0x81,0xdb,0xdb,0x6e,0x71, |
1116 | | 0x6e,0x49,0x6e,0xa9,0x6e,0xe9,0x6e,0x2b,0xdc,0xb2,0xdc,0xb2,0xdd,0xf2,0xdc,0x0a, |
1117 | | 0xdd,0x8a,0xdd,0xb6,0xb9,0x95,0xba,0xf5,0x09,0xcb,0xdc,0x2a,0xdd,0xaa,0xdd,0xea, |
1118 | | 0xdd,0xf6,0xbb,0xb5,0xb8,0xb5,0xba,0x1d,0x75,0x6b,0x77,0xeb,0x74,0x3b,0xed,0xe6, |
1119 | | 0x62,0x73,0xc6,0xed,0x9c,0x5b,0x97,0x5b,0xaf,0xdb,0x65,0xb7,0xab,0x6e,0xd7,0xdc, |
1120 | | 0x7e,0x70,0xbb,0xe1,0x66,0x24,0x35,0x91,0x0e,0x96,0x5a,0x49,0x05,0x52,0x5b,0xa9, |
1121 | | 0x58,0xea,0x28,0x1d,0x29,0x95,0x4a,0xe5,0x52,0x1f,0xa9,0x42,0x1a,0x28,0x0d,0x91, |
1122 | | 0x46,0x48,0xa3,0xa4,0xf7,0x48,0x15,0x6e,0x0f,0x48,0x1f,0x91,0x3e,0x2e,0x7d,0x4a, |
1123 | | 0xfa,0x9c,0x74,0xb4,0x74,0x8c,0x74,0x82,0x74,0xb2,0x74,0xba,0x74,0xb6,0x74,0x9e, |
1124 | | 0x74,0x81,0xf4,0x6d,0x69,0x9c,0x34,0x49,0x9a,0x2a,0x4d,0x97,0xae,0x90,0x66,0x49, |
1125 | | 0x33,0x44,0xd9,0xd2,0x3c,0x69,0xa1,0xb4,0x58,0xba,0x4d,0x5a,0x2a,0x2d,0x93,0x56, |
1126 | | 0x4a,0xab,0xa5,0xf5,0xd2,0xfd,0xd2,0x16,0x69,0xab,0xf4,0xa8,0xb4,0x5d,0x5a,0x24, |
1127 | | 0xe8,0x94,0x9e,0x96,0x9e,0x91,0x9e,0x93,0x76,0x49,0x7b,0xa5,0x97,0xa5,0x57,0xa5, |
1128 | | 0x4f,0x0b,0xae,0x49,0x7f,0x90,0xde,0x90,0x1a,0xb9,0x9b,0xb8,0x0f,0x76,0xb7,0x72, |
1129 | | 0x17,0xb8,0xdb,0xba,0x8b,0xdd,0x1d,0xdd,0x47,0xba,0x4b,0xdd,0xe5,0xee,0x3e,0xee, |
1130 | | 0x0a,0xf7,0x40,0xf7,0x10,0xf7,0x08,0xf7,0x28,0xf7,0x7b,0xdc,0x1f,0x70,0x5f,0x21, |
1131 | | 0x7d,0xc4,0xfd,0x71,0xf7,0xa7,0xdc,0x9f,0x73,0x1f,0xed,0x3e,0xc6,0x7d,0x82,0xfb, |
1132 | | 0x64,0xf7,0xc7,0xa5,0xd3,0xdd,0x67,0xbb,0xcf,0x73,0x5f,0xe0,0xfe,0xb6,0x7b,0x9c, |
1133 | | 0x7b,0x92,0x7b,0xaa,0x7b,0xba,0xfb,0x0a,0xf7,0x2c,0xf7,0x6c,0xf7,0x3c,0xf7,0x42, |
1134 | | 0xf7,0x62,0xf7,0x6d,0xee,0xa5,0xee,0x65,0xee,0x95,0xee,0xd5,0xee,0x0a,0xb7,0x7a, |
1135 | | 0xf7,0xfd,0xee,0x2d,0xee,0xad,0xee,0xcf,0xdb,0x1c,0x75,0x6f,0x77,0xef,0x74,0x3f, |
1136 | | 0xed,0x7e,0xc6,0xfd,0x9c,0x7b,0x97,0x7b,0xaf,0xfb,0x65,0xf7,0xab,0xee,0xd7,0xdc, |
1137 | | 0x7f,0x70,0x7f,0xc8,0xe1,0x86,0xbb,0x91,0x87,0x89,0xc7,0x60,0x0f,0x2b,0x0f,0x81, |
1138 | | 0x87,0xad,0x87,0xd8,0xc3,0xd1,0xe3,0x39,0xe9,0x48,0x0f,0xa9,0x87,0xdc,0xc3,0xc7, |
1139 | | 0x43,0xe1,0x11,0xe8,0x11,0xe2,0x11,0xe1,0x11,0xe5,0x71,0x8f,0xc7,0x03,0x1e,0x8f, |
1140 | | 0x78,0x3c,0xee,0x51,0x24,0x7a,0xca,0xe3,0x39,0x8f,0xd1,0x1e,0x63,0x3c,0x26,0x78, |
1141 | | 0x4c,0xf6,0x98,0xee,0x31,0xdb,0x63,0x9e,0xc7,0x02,0x8f,0xb7,0x3d,0xe2,0x3c,0x92, |
1142 | | 0x3c,0x3e,0x16,0xa6,0x7a,0xa4,0x7b,0xac,0xf0,0xc8,0xf2,0xc8,0xf6,0xc8,0xf3,0x28, |
1143 | | 0xf4,0x28,0xf6,0xd8,0xe6,0x51,0xea,0x51,0xe6,0x51,0xe9,0x51,0xed,0x51,0xef,0xb1, |
1144 | | 0xdf,0xa3,0xc5,0xe3,0x41,0x51,0xab,0xc7,0xd3,0xa2,0xa3,0x1e,0xed,0x1e,0x9d,0x1e, |
1145 | | 0xec,0x38,0x3e,0x8d,0xf0,0x0c,0x97,0x3a,0xe7,0xd1,0xe5,0xd1,0xeb,0x71,0xd9,0xe3, |
1146 | | 0xaa,0xc7,0x35,0x8f,0x1f,0x3c,0x6e,0x78,0x18,0xc9,0xae,0x0b,0x31,0x37,0xc8,0x30, |
1147 | | 0x2f,0xc8,0xb8,0x99,0x5c,0x26,0x90,0xe9,0xef,0x00,0x5b,0x99,0x58,0xe6,0x28,0x1b, |
1148 | | 0x29,0x93,0xca,0xe4,0x32,0x1f,0x99,0x42,0x16,0x28,0x0b,0x91,0x45,0xc8,0xa2,0x64, |
1149 | | 0xf7,0xc8,0x1e,0x90,0x3d,0x22,0x7b,0x5c,0xf6,0x94,0xec,0x39,0x59,0x83,0x60,0xb4, |
1150 | | 0x6c,0x8c,0x6c,0x82,0x6c,0xb2,0x6c,0xba,0x6c,0xb6,0x6c,0x9e,0x6c,0x81,0xec,0x6d, |
1151 | | 0x59,0x9c,0x2c,0x49,0x96,0x2a,0x4b,0x97,0xad,0x90,0x65,0xc9,0x5e,0x76,0xc8,0x96, |
1152 | | 0xe5,0xc9,0x0a,0x65,0xc5,0xb2,0x99,0x0e,0xdb,0x64,0xa5,0xb2,0x32,0x59,0xa5,0xac, |
1153 | | 0x5a,0x36,0xd2,0xbd,0x5e,0xb6,0x5f,0xd6,0x22,0x6b,0x95,0x1d,0x95,0xb5,0x43,0x3a, |
1154 | | 0x65,0xa7,0x65,0x67,0x64,0xe7,0x64,0x5d,0xb2,0x5e,0xd9,0x65,0xd9,0x55,0x99,0x95, |
1155 | | 0xec,0x9a,0xec,0x07,0xd9,0x0d,0x99,0x91,0xdc,0x44,0x3e,0x44,0xce,0xed,0xef,0xe5, |
1156 | | 0x42,0xb9,0x9d,0x7c,0x98,0xdc,0x49,0xee,0x22,0x77,0x97,0x7b,0xca,0xef,0x91,0xf9, |
1157 | | 0xca,0x95,0x72,0xb5,0xfc,0xb4,0x47,0xa8,0x3c,0x52,0x1e,0x2d,0xbf,0x57,0xfe,0xa0, |
1158 | | 0x7c,0x94,0xfc,0x09,0xf9,0xd3,0xf2,0xe7,0xe5,0x2f,0xc9,0xc7,0xca,0x27,0xca,0x27, |
1159 | | 0xc8,0xa6,0xc8,0x27,0xcb,0x66,0xc8,0xe7,0xc8,0xe7,0xcb,0x17,0xca,0x17,0xc9,0xcf, |
1160 | | 0x78,0x24,0xb9,0xc5,0xcb,0x93,0xe5,0xd1,0xc2,0x2c,0xe9,0x39,0xf7,0x34,0x79,0x86, |
1161 | | 0x3c,0x49,0xb6,0x52,0x9e,0x2a,0x5b,0x23,0xcf,0x91,0xe7,0xcb,0xbb,0x3c,0x8a,0xe4, |
1162 | | 0x9b,0xe5,0xdb,0xe5,0x3b,0xe5,0xe5,0xf2,0x5e,0x8f,0xbd,0xf2,0x1a,0x79,0x83,0xfc, |
1163 | | 0x1d,0xf9,0x41,0xf9,0x11,0x79,0xb5,0xec,0x98,0xfc,0x84,0x7c,0xa4,0xfb,0x29,0x79, |
1164 | | 0xab,0xec,0x43,0xf9,0xc7,0xf2,0xf3,0xf2,0x6e,0xf9,0x25,0xf9,0x19,0xd9,0x15,0xf9, |
1165 | | 0x60,0xd9,0x57,0xf2,0x73,0xb2,0x07,0xa4,0xdf,0xca,0xbb,0x64,0xd7,0xe5,0x97,0x65, |
1166 | | 0x7d,0x72,0x63,0x4f,0x53,0xcf,0x21,0x9e,0xd6,0x9e,0xd7,0x64,0x37,0x3c,0x84,0x9e, |
1167 | | 0x3f,0xc8,0xec,0x3c,0x6f,0xc8,0x86,0x79,0xbe,0x64,0xe3,0xe4,0xe9,0xea,0x29,0xf3, |
1168 | | 0xf4,0xf1,0x54,0x78,0x06,0x7a,0x86,0x78,0x46,0x7a,0xc6,0x78,0xde,0xef,0xf9,0xb0, |
1169 | | 0xe7,0xdd,0xdc,0xff,0x3e,0xe6,0xf9,0xa4,0xe7,0xd3,0x9e,0xcf,0x79,0x8e,0xf6,0x1c, |
1170 | | 0x03,0xf9,0xb5,0x52,0xe3,0x3d,0x27,0x7b,0xce,0xf0,0x9c,0xeb,0xf9,0xc6,0x2d,0x25, |
1171 | | 0xde,0xf6,0xd4,0xe9,0xe2,0x3d,0x53,0x3c,0xdf,0xb2,0x4a,0xb2,0x4a,0xf3,0x4c,0xf7, |
1172 | | 0x5c,0xee,0xb9,0xca,0x73,0x8d,0x67,0xb6,0x67,0xac,0x55,0xae,0x67,0xa1,0xe7,0x66, |
1173 | | 0xcf,0x52,0xcf,0x3d,0x9e,0xd5,0x9e,0x0d,0x9e,0xcd,0x9e,0x87,0x3d,0x8f,0x7a,0x9e, |
1174 | | 0xf0,0x7c,0xdf,0xf3,0x23,0xd4,0x3e,0xe7,0xd9,0xed,0xf9,0x99,0xe7,0x97,0x9e,0xd7, |
1175 | | 0x90,0xbe,0x0e,0x74,0x9e,0x83,0xbc,0xfa,0x74,0x83,0xbd,0xac,0x11,0x8a,0xbc,0x1c, |
1176 | | 0xbc,0x1c,0xbd,0x5c,0xbc,0x3c,0xbc,0xbc,0xbd,0x14,0x5e,0x6a,0xaf,0x30,0x2f,0xad, |
1177 | | 0xd7,0x3d,0x90,0xfb,0x0d,0xf2,0x90,0x41,0x46,0x19,0xe4,0x71,0x83,0xfc,0xc3,0x20, |
1178 | | 0xcf,0x18,0xe4,0x79,0x83,0x8c,0x36,0xc8,0x2b,0x06,0x19,0x67,0x90,0x89,0x06,0x99, |
1179 | | 0x6c,0x90,0x69,0x90,0x99,0x90,0x39,0x90,0x79,0x90,0x37,0x20,0x6f,0x42,0x16,0x19, |
1180 | | 0x24,0xce,0x20,0x89,0x06,0x49,0x31,0x48,0x1a,0x24,0xdd,0x20,0xcb,0x21,0xab,0x0c, |
1181 | | 0xb2,0xc6,0x20,0xd9,0x90,0x5c,0xc8,0x9f,0x7f,0xda,0x14,0x78,0xe9,0xa5,0x08,0x52, |
1182 | | 0x0c,0xd9,0x0a,0x39,0x63,0x52,0xe2,0x55,0xe2,0xb5,0x13,0x52,0x06,0xd9,0x63,0x90, |
1183 | | 0x7d,0x90,0x1a,0x48,0x23,0xe4,0x00,0xa4,0x15,0x72,0x0c,0xd2,0x01,0xf9,0x80,0x93, |
1184 | | 0x33,0x9c,0x9c,0x37,0x48,0x97,0xd7,0x25,0xaf,0x2f,0x70,0xfc,0x8d,0xd7,0x0f,0x5e, |
1185 | | 0x7d,0x5e,0x3c,0x6f,0x73,0x6f,0x2b,0x6f,0xa1,0xb7,0xbd,0xf7,0x08,0xef,0x91,0xde, |
1186 | | 0xee,0xde,0x5e,0xde,0xfe,0xde,0x81,0xde,0xa1,0xde,0x1a,0xef,0x58,0xef,0x07,0xbc, |
1187 | | 0x47,0x79,0x3f,0xe9,0xfd,0xac,0xf7,0x68,0xef,0xb1,0xde,0x93,0xbc,0xa7,0x79,0xcf, |
1188 | | 0xf6,0x9e,0xef,0xfd,0xa6,0x37,0xe3,0x9d,0xe4,0x9d,0xe6,0x9d,0xe9,0xbd,0xda,0x3b, |
1189 | | 0xdb,0x3b,0xdf,0x7b,0xa3,0xf7,0x56,0xef,0x52,0xef,0x72,0xef,0x7d,0xde,0x75,0xde, |
1190 | | 0xfb,0xbd,0x0f,0x7a,0xbf,0xeb,0x7d,0xdc,0xbb,0xd3,0xfb,0x43,0xef,0x4f,0xbc,0x2f, |
1191 | | 0x78,0xf7,0x7a,0x5f,0xf1,0xfe,0xda,0xfb,0x7b,0xef,0x1b,0xde,0xc6,0x3e,0x66,0x3e, |
1192 | | 0x96,0x3e,0x02,0x1f,0x3b,0x9f,0xe1,0x3e,0xce,0x3e,0x52,0x1f,0x4f,0x1f,0x3f,0x9f, |
1193 | | 0x00,0x9f,0x10,0x9f,0x48,0x9f,0x18,0x9f,0xfb,0x7d,0x1e,0xf1,0x79,0xc2,0xe7,0x19, |
1194 | | 0x9f,0x17,0x7d,0xc6,0xf8,0x4c,0xf4,0x99,0xea,0x33,0xcb,0x67,0x9e,0xcf,0x42,0x9f, |
1195 | | 0xc5,0x3e,0x89,0x3e,0xa9,0x3e,0x19,0x3e,0xab,0x7c,0xd6,0xf9,0xe4,0xf9,0x14,0xf9, |
1196 | | 0x6c,0xf1,0xd9,0xe1,0x53,0xe6,0xb3,0xd7,0xa7,0xce,0xe7,0x1d,0x9f,0xc3,0x3e,0xc7, |
1197 | | 0x7c,0x4e,0xfa,0x7c,0xe8,0xf3,0x89,0xcf,0x17,0x5e,0x17,0x7c,0xd8,0x9e,0xf4,0xfa, |
1198 | | 0x5c,0xf1,0x31,0xf7,0xfe,0xda,0x87,0xed,0xc9,0xf7,0x3e,0x37,0x7c,0xdc,0xbd,0x8d, |
1199 | | 0x7d,0xd9,0x9e,0x98,0xf9,0x5a,0xfa,0x86,0x7a,0x0b,0x7c,0xd9,0xde,0xb0,0x56,0xe9, |
1200 | | 0x2d,0xea,0xb7,0x45,0x6f,0x85,0x9d,0xef,0xfd,0x3e,0xc3,0x7d,0x9d,0x7d,0x27,0xfa, |
1201 | | 0x48,0x7d,0x59,0xed,0x65,0x3e,0x9e,0xbe,0x7e,0xbe,0xeb,0x7c,0x02,0x7c,0x59,0xbd, |
1202 | | 0xac,0xb7,0x42,0x7c,0xbf,0xf0,0x8a,0xf4,0xed,0xf7,0x56,0x8c,0x6f,0xbf,0xaf,0xee, |
1203 | | 0x47,0xdb,0x37,0x7d,0x74,0xab,0x87,0x1e,0xf1,0xbd,0xd5,0x47,0xbf,0xf4,0x10,0xeb, |
1204 | | 0x9d,0x9b,0x7e,0xe9,0xf7,0xc9,0x13,0xbe,0xfd,0x1e,0xe9,0xf7,0xc6,0x33,0xbe,0xac, |
1205 | | 0x2f,0x5e,0xf4,0xed,0xf7,0xc4,0x18,0xce,0x12,0xd6,0x06,0xbd,0xf6,0x89,0xbe,0x6f, |
1206 | | 0x7a,0x4f,0xf5,0x9d,0xe5,0x3b,0xcf,0x97,0x6d,0xc7,0x93,0xab,0xc1,0x96,0x5a,0xe8, |
1207 | | 0x1b,0xe7,0xbb,0xc4,0x37,0xd3,0x77,0xb5,0x6f,0xb6,0x6f,0xbe,0xef,0x46,0xdf,0xad, |
1208 | | 0xbe,0xa5,0xbe,0xe5,0xbe,0xfb,0x7c,0xeb,0x7c,0xf7,0xfb,0x1e,0xf4,0x7d,0xd7,0xf7, |
1209 | | 0xb8,0x6f,0xa7,0xef,0x87,0xbe,0x9f,0xf8,0x5e,0xf0,0xed,0xf5,0xbd,0xe2,0xfb,0xb5, |
1210 | | 0xef,0xf7,0xbe,0x37,0xd0,0x8a,0xb1,0x9f,0x99,0x9f,0xa5,0x9f,0xc0,0xef,0x8f,0xd6, |
1211 | | 0xeb,0x3f,0x9e,0x0a,0x7b,0x36,0x1a,0xbc,0xa1,0xcf,0x63,0x47,0x89,0x9d,0x9f,0x9d, |
1212 | | 0xdf,0xef,0x19,0xf9,0xc3,0xfd,0x5c,0x20,0x72,0x3f,0x7f,0xbf,0x20,0xbf,0x48,0xbf, |
1213 | | 0x7b,0xfc,0x1e,0x86,0x3c,0xe9,0xf7,0xbc,0xdf,0x18,0xbf,0x57,0xfd,0x66,0xfa,0xcd, |
1214 | | 0x87,0xbc,0xed,0x97,0x08,0x59,0x0a,0x59,0xe9,0x97,0x0d,0xd9,0xe0,0xb7,0x05,0xb2, |
1215 | | 0x13,0x52,0xe9,0x57,0x07,0x69,0x86,0x1c,0xf1,0x6b,0xf7,0xfb,0xc0,0xef,0x13,0x48, |
1216 | | 0xb7,0xdf,0x65,0xbf,0x6f,0xfc,0x7e,0xf4,0x33,0xf6,0x37,0xf6,0x1f,0xec,0x3f,0xd4, |
1217 | | 0xdf,0xde,0xdf,0xc9,0x5f,0xea,0x8f,0xc1,0xe1,0xaf,0x82,0x84,0x42,0xa2,0xfc,0xef, |
1218 | | 0xf7,0x7f,0xd4,0xff,0x69,0xff,0xd1,0xfe,0xe3,0xfd,0xa7,0xfa,0xb3,0x36,0xcc,0xf1, |
1219 | | 0x5f,0xe0,0xcf,0xf8,0xa7,0xf8,0x67,0xf8,0x67,0x41,0x72,0xfd,0x37,0xfa,0x6f,0xf7, |
1220 | | 0x2f,0x83,0x54,0xf9,0x37,0xfa,0x1f,0xf4,0x3f,0xea,0x7f,0xd2,0xff,0x9f,0xfe,0xe7, |
1221 | | 0xfd,0x7b,0xfd,0xbf,0xf4,0xff,0xce,0xbf,0xcf,0xdf,0x44,0x61,0xa9,0x10,0x29,0x86, |
1222 | | 0x29,0x46,0x2a,0x64,0x0a,0x3f,0x85,0x5a,0x11,0xa1,0x88,0x55,0x3c,0xa4,0x18,0x0c, |
1223 | | 0x4d,0x4f,0x28,0x9e,0x53,0xbc,0xa2,0x98,0xa4,0x98,0xa1,0x98,0x07,0x5e,0x51,0xbc, |
1224 | | 0xa5,0x48,0x50,0xa4,0x29,0x56,0x28,0xd6,0xe1,0xf8,0x03,0x58,0x5f,0xa0,0xd8,0xac, |
1225 | | 0xf8,0xe3,0xdf,0x84,0xde,0x59,0x4a,0x15,0x7b,0x14,0xb5,0x8a,0x03,0x8a,0xa3,0x8a, |
1226 | | 0x53,0x8a,0x4f,0x14,0x3d,0x8a,0xab,0x8a,0xeb,0x0a,0x23,0xa5,0xab,0x52,0xa5,0xbc, |
1227 | | 0xfd,0x37,0xfd,0xee,0xfc,0x09,0x57,0x46,0x2a,0xfb,0x74,0xd1,0x4a,0x9d,0x71,0xac, |
1228 | | 0xf2,0x5e,0xe5,0xfd,0xca,0x87,0x95,0xff,0xde,0x37,0x08,0x78,0xc2,0x28,0xff,0xa1, |
1229 | | 0x7c,0x16,0xc2,0xfe,0x3e,0xc3,0xf3,0xca,0x17,0x95,0x2f,0x29,0xc7,0x2a,0x27,0x2a, |
1230 | | 0xa7,0x28,0x67,0x28,0xe7,0x28,0xd9,0xef,0x8a,0xe7,0x2b,0x17,0x2a,0x17,0x29,0xe3, |
1231 | | 0x39,0x7b,0x92,0x95,0x4b,0x94,0x23,0xac,0xf4,0xf2,0x2c,0x57,0x4b,0xaf,0x1f,0x7a, |
1232 | | 0x8c,0xa3,0xa1,0x3f,0x56,0xf9,0xd8,0xcf,0xda,0x49,0x53,0x2e,0x53,0x66,0x28,0x63, |
1233 | | 0xad,0x96,0x2b,0x57,0x2a,0x57,0x2b,0x1f,0xb4,0xea,0xd3,0xad,0x51,0xae,0x53,0xe6, |
1234 | | 0x28,0x73,0x07,0xac,0xcc,0x57,0x16,0x29,0xb7,0xa0,0xed,0x12,0xe4,0xec,0x52,0x56, |
1235 | | 0x28,0xab,0x94,0x75,0xca,0xfd,0xca,0x16,0xe5,0x11,0xe5,0x31,0x65,0x87,0xf2,0x7d, |
1236 | | 0xe5,0x47,0xca,0x4f,0x20,0xe7,0x21,0x5d,0x90,0x1e,0xc8,0x67,0x06,0xb9,0x02,0xb9, |
1237 | | 0x6a,0x90,0x6f,0x20,0xdf,0x19,0xe4,0xba,0x41,0x6e,0x18,0x84,0x54,0x7a,0xe1,0x19, |
1238 | | 0xc4,0x14,0x32,0x18,0x62,0x09,0xe1,0x43,0x84,0x06,0xb1,0x35,0x88,0x83,0x41,0x86, |
1239 | | 0x1b,0xc4,0xc9,0x20,0x23,0x0d,0xe2,0x66,0x10,0x0f,0x83,0x78,0x1a,0xc4,0xc7,0x20, |
1240 | | 0xfe,0x06,0xe9,0xff,0xa8,0x0d,0x12,0x62,0x90,0x70,0x83,0x68,0x20,0xec,0xd3,0x20, |
1241 | | 0x5a,0xa5,0x97,0x7b,0x20,0x0f,0x42,0x1e,0x85,0xfc,0x03,0xa2,0xff,0x4d,0x95,0x3e, |
1242 | | 0x5d,0xac,0xf2,0x39,0x55,0x1a,0xe7,0xb5,0x65,0xca,0x17,0x54,0xac,0x77,0x59,0x8f, |
1243 | | 0x86,0x2b,0x97,0x2b,0x27,0xda,0x8c,0x56,0xdd,0xe9,0xf7,0x53,0xd8,0xd1,0xb0,0x12, |
1244 | | 0xde,0x5e,0x8d,0x2b,0x92,0xab,0xfc,0x23,0xdf,0x50,0x27,0x2b,0xd7,0xe0,0x4a,0xbf, |
1245 | | 0xac,0x7a,0x56,0xf9,0xae,0xe5,0x1f,0xa9,0xff,0xbc,0x72,0x8c,0xea,0x45,0xe5,0x38, |
1246 | | 0xd5,0x04,0xd5,0x64,0xd5,0x44,0x1b,0x76,0x04,0x45,0x2a,0xa7,0xab,0x7e,0x10,0xcf, |
1247 | | 0x56,0xcd,0x53,0x2d,0x50,0xbd,0xad,0x8a,0x53,0x25,0xa9,0x52,0x55,0xe9,0xaa,0x15, |
1248 | | 0xaa,0x2c,0xd5,0x5f,0xf5,0x06,0x2d,0x5b,0x95,0xa7,0x2a,0x54,0x11,0xfd,0x99,0xf7, |
1249 | | 0xcb,0xfa,0x31,0x7a,0xeb,0x5b,0x66,0xf6,0xf8,0xd6,0x37,0xcd,0xec,0xf1,0xad,0x6f, |
1250 | | 0x9b,0xd9,0x63,0xfd,0x1b,0x67,0x7d,0xdd,0x62,0xd5,0x56,0x55,0x89,0x2a,0x8c,0x76, |
1251 | | 0xaa,0xca,0x54,0x7b,0x70,0x4d,0xab,0x54,0x75,0xaa,0x26,0xd5,0x01,0xd5,0x61,0xd5, |
1252 | | 0x7b,0xaa,0xe3,0xaa,0xdf,0x9e,0x1f,0x4e,0xaa,0x4e,0xab,0x3e,0x56,0x7d,0xaa,0xea, |
1253 | | 0x51,0x5d,0x56,0x7d,0xa5,0xfa,0x4e,0xf5,0x93,0xca,0x28,0xc0,0x34,0xc0,0x22,0x60, |
1254 | | 0x68,0x80,0x6d,0xc0,0xb0,0x00,0x49,0x80,0x5b,0x80,0x3c,0xc0,0x37,0x40,0x15,0x10, |
1255 | | 0x1c,0x10,0x11,0x10,0x1d,0x70,0x5f,0xc0,0xc3,0x01,0x8f,0x07,0x3c,0x1d,0xf0,0x42, |
1256 | | 0xc0,0x2b,0x01,0x13,0x02,0xa6,0x04,0xcc,0x0c,0x78,0x2d,0x60,0x41,0xc0,0xa2,0x80, |
1257 | | 0x84,0x80,0x25,0x01,0xe9,0x01,0x2b,0x03,0xd6,0x06,0xfc,0xa7,0x7f,0x9f,0xfa,0xb7, |
1258 | | 0xbe,0x03,0xcd,0x0d,0x28,0x0c,0xd8,0x1c,0x50,0x12,0xb0,0x3b,0xa0,0x32,0xa0,0x26, |
1259 | | 0xa0,0x31,0xe0,0x40,0x40,0x6b,0xc0,0xb1,0x80,0x8e,0x80,0x0f,0x02,0xce,0x04,0x9c, |
1260 | | 0x0f,0xb8,0x18,0xf0,0x79,0xc0,0xd5,0x80,0x6f,0x03,0x7e,0x0c,0xa0,0x40,0x93,0xc0, |
1261 | | 0x21,0x81,0xfc,0x40,0x9b,0x40,0x71,0xa0,0x53,0xa0,0x6b,0xa0,0x2c,0xd0,0x27,0x50, |
1262 | | 0x19,0x18,0x14,0x18,0x1e,0x18,0x15,0x78,0x6f,0xe0,0x43,0x81,0x77,0xfb,0x5b,0x8a, |
1263 | | 0xbf,0xaa,0xbd,0xdb,0x67,0xe7,0xc7,0x02,0x9f,0x0a,0x7c,0x3e,0xf0,0xe5,0xc0,0xf1, |
1264 | | 0x81,0x93,0x03,0x67,0x04,0xce,0x0d,0x7c,0x23,0xf0,0xed,0xc0,0x78,0xf4,0x26,0x25, |
1265 | | 0x70,0x59,0xe0,0x8a,0xc0,0x35,0x81,0xeb,0x03,0x37,0x04,0x16,0x07,0x6e,0x0f,0xdc, |
1266 | | 0x15,0xb8,0x27,0xb0,0x3a,0xb0,0x21,0xb0,0x39,0xf0,0x70,0xe0,0x51,0x9c,0x3f,0x11, |
1267 | | 0xf8,0x7e,0xe0,0x47,0x81,0xe7,0x02,0xbb,0x03,0x3f,0x0b,0xfc,0x12,0xc7,0xd7,0x02, |
1268 | | 0xaf,0x07,0xf6,0xfd,0xe6,0xf7,0xc1,0xbf,0xef,0x7c,0xdf,0xcf,0x7e,0x63,0x4f,0x17, |
1269 | | 0x68,0xac,0x7e,0x8d,0x4c,0xd4,0x8b,0x8d,0xfa,0x74,0xe6,0x6a,0x0b,0x35,0x5f,0x2d, |
1270 | | 0x54,0xb3,0x7f,0x03,0x6f,0xab,0x16,0xab,0x47,0xa8,0x25,0xea,0x19,0x2e,0x2e,0xea, |
1271 | | 0x8d,0x46,0x52,0xf5,0x35,0x92,0xa9,0xbd,0xd4,0xbe,0x6a,0x85,0x3a,0x40,0xad,0x70, |
1272 | | 0x09,0x52,0x87,0xab,0xb5,0xea,0x18,0xf5,0xfd,0xea,0x87,0xd4,0x5b,0xe8,0x31,0xf5, |
1273 | | 0x6a,0x97,0x91,0xf4,0xa4,0xfa,0x69,0xb5,0x60,0xe8,0x0b,0xea,0x03,0x46,0x2f,0xa9, |
1274 | | 0xc7,0xa8,0xc7,0xab,0x5f,0x55,0x1f,0x37,0x9a,0xaa,0xee,0xd3,0xcd,0x54,0xcf,0x51, |
1275 | | 0xcf,0x53,0xbf,0xa1,0x7e,0x53,0xbd,0x48,0x1d,0xa7,0x4e,0x54,0xa7,0xaa,0x83,0x5c, |
1276 | | 0x32,0xd4,0x2b,0xd4,0x01,0x2e,0xab,0xd5,0xd9,0xea,0x7c,0xf5,0x46,0xf5,0x56,0x75, |
1277 | | 0xa9,0xba,0x5c,0xbd,0x4f,0x5d,0xa7,0xde,0xaf,0x3e,0xa8,0x7e,0x57,0x7d,0x5c,0xdd, |
1278 | | 0xa9,0xfe,0x50,0xfd,0x89,0xfa,0x82,0xba,0x57,0x7d,0x45,0xfd,0xb5,0xfa,0x7b,0xf5, |
1279 | | 0x0d,0xb5,0x71,0x90,0x59,0x90,0x65,0x90,0x20,0xc8,0x2e,0x68,0x78,0x90,0x73,0x90, |
1280 | | 0x34,0xc8,0x33,0xc8,0x2f,0x28,0x20,0x28,0x24,0x28,0x32,0x28,0x26,0xe8,0xfe,0xa0, |
1281 | | 0x47,0x82,0x9e,0x08,0x7a,0x26,0xe8,0xc5,0xa0,0x31,0x41,0x13,0x83,0xa6,0x06,0xcd, |
1282 | | 0x0a,0x9a,0x17,0xb4,0x30,0x68,0x71,0x50,0x62,0x50,0x6a,0x50,0x46,0xd0,0xaa,0xa0, |
1283 | | 0x3f,0xfe,0x0d,0xfc,0xba,0xa0,0xbc,0xa0,0xa2,0xa0,0x2d,0x41,0x3b,0x82,0xca,0x82, |
1284 | | 0xf6,0x06,0xd5,0x06,0x35,0x05,0xb5,0x04,0x1d,0x09,0x6a,0x0b,0x3a,0x19,0x74,0x3a, |
1285 | | 0xe8,0xe3,0xa0,0x4f,0x83,0x7a,0x82,0x2e,0x07,0x7d,0x15,0xf4,0x5d,0xd0,0x4f,0x41, |
1286 | | 0x46,0xc1,0x7f,0x64,0x44,0xfd,0xd9,0xf5,0x85,0x69,0xb0,0x45,0xf0,0xd0,0x60,0xdb, |
1287 | | 0xe0,0x61,0xc1,0x92,0x60,0xb7,0x60,0x79,0xb0,0x6f,0xb0,0x2a,0x38,0x38,0x38,0x22, |
1288 | | 0x38,0x3a,0xf8,0xbe,0xe0,0x87,0x83,0x1f,0x0f,0x7e,0x3a,0xf8,0x85,0xe0,0x57,0x82, |
1289 | | 0x27,0x04,0x4f,0x09,0x9e,0x19,0xfc,0x5a,0xf0,0x82,0xe0,0x45,0xc1,0x09,0xc1,0x4b, |
1290 | | 0x82,0xd3,0x83,0x57,0x06,0xaf,0x0d,0xce,0x0d,0x2e,0x0c,0xde,0x1c,0x5c,0x12,0xbc, |
1291 | | 0x3b,0xb8,0x32,0xb8,0x26,0xb8,0x31,0xf8,0x40,0x70,0x6b,0xf0,0xb1,0xe0,0x8e,0xe0, |
1292 | | 0x0f,0x82,0xcf,0x04,0x9f,0x0f,0xbe,0x18,0xfc,0x79,0xf0,0xd5,0xe0,0x6f,0x83,0x7f, |
1293 | | 0x0c,0xa6,0x10,0x93,0x90,0x21,0x21,0xfc,0x10,0x9b,0x10,0x71,0x88,0x53,0x88,0x6b, |
1294 | | 0x88,0x2c,0xc4,0x27,0x44,0x19,0x12,0x14,0x12,0x1e,0x12,0x15,0xf2,0x3f,0xf7,0x97, |
1295 | | 0x1c,0x7a,0xb9,0x37,0xe4,0xa1,0x90,0xc7,0x42,0x9e,0x0a,0x79,0x3e,0xe4,0xe5,0x90, |
1296 | | 0xf1,0x21,0x93,0x43,0x66,0x84,0xcc,0x0d,0x79,0x23,0xe4,0xed,0x90,0xf8,0x90,0x94, |
1297 | | 0x90,0x65,0x21,0x2b,0x42,0xd6,0x84,0xac,0x0f,0xd9,0x10,0x52,0x1c,0xb2,0x3d,0x64, |
1298 | | 0x57,0xc8,0x9e,0x90,0xea,0x90,0x86,0x90,0xbf,0xe2,0xbb,0xce,0xe6,0x90,0x23,0x21, |
1299 | | 0xed,0x21,0x1f,0x84,0xdc,0xf9,0x8a,0xea,0xfe,0xad,0xdf,0x00,0xf9,0xed,0xf1,0x79, |
1300 | | 0x6b,0xfe,0x2f,0x7f,0xfb,0xf5,0xee,0xfc,0xfd,0xd9,0x9d,0xff,0xa6,0xe2,0x8f,0xfc, |
1301 | | 0x2e,0xdc,0x2f,0xd7,0x2f,0x3f,0xff,0x8d,0xe1,0x3f,0xfe,0xf9,0x24,0xa4,0x27,0xe4, |
1302 | | 0x6a,0x48,0x5f,0x88,0x45,0xa8,0x43,0xa8,0x34,0xf4,0xf7,0xfd,0x3d,0xcd,0xaf,0xff, |
1303 | | 0x55,0xcd,0x7f,0xf2,0xa3,0x0c,0x0d,0x0b,0x8d,0x0d,0x7d,0x3c,0xf4,0xa5,0xd0,0xa9, |
1304 | | 0xa1,0xff,0xb3,0x96,0xfc,0xa7,0x7e,0x27,0xf2,0xcf,0xd7,0xe9,0xd3,0xfd,0xef,0xb2, |
1305 | | 0xad,0x4f,0xc7,0xd6,0x61,0xc7,0xb0,0x15,0x17,0xb2,0x75,0xd8,0xb8,0xbf,0x0e,0xfb, |
1306 | | 0xcd,0xc7,0x9d,0xf5,0xf4,0xe9,0x2c,0xc0,0xcf,0xf5,0xf4,0xe9,0xfe,0xe7,0x7d,0xdd, |
1307 | | 0xa7,0xbb,0xe9,0x6b,0x7d,0x7f,0x6e,0xad,0x73,0x7b,0x7f,0xfa,0x74,0x77,0x43,0xcf, |
1308 | | 0xcd,0x3a,0x7d,0x3a,0x47,0xea,0xff,0xc6,0xe8,0xee,0xe8,0xf9,0xbb,0xce,0xdf,0x75, |
1309 | | 0xfe,0x53,0x75,0xde,0x08,0x7d,0x33,0x74,0x51,0x68,0xdf,0xef,0xf8,0x6f,0x35,0x41, |
1310 | | 0xbc,0x9f,0xff,0xb7,0x9a,0xb8,0xd0,0xdf,0xae,0xf3,0xe8,0x6d,0x75,0x92,0x42,0x7d, |
1311 | | 0x51,0x2e,0x14,0xc7,0x0f,0xe3,0xfc,0xdf,0x3a,0xff,0x6f,0xe9,0x9c,0x0b,0x61,0xe7, |
1312 | | 0xc1,0x3b,0xad,0x9d,0xee,0x76,0x5e,0xea,0x6d,0xeb,0x8f,0x0c,0x1c,0xaf,0xe2,0xf2, |
1313 | | 0xd6,0x19,0xce,0xe4,0xfd,0x5b,0x2b,0x94,0x22,0x94,0xde,0x02,0x76,0x80,0x32,0x43, |
1314 | | 0xcd,0xbd,0x88,0x6b,0x41,0x13,0x68,0x01,0x47,0x40,0x1b,0x38,0x19,0xfa,0xdb,0x7b, |
1315 | | 0xa0,0x9b,0x9f,0x45,0xa1,0x3a,0x5d,0xdf,0x7f,0x50,0x4e,0x87,0x7e,0x1c,0xfa,0x69, |
1316 | | 0xe8,0x66,0xa3,0x9e,0xd0,0x02,0xe3,0x93,0x64,0x67,0xec,0x64,0x94,0x65,0xfc,0x79, |
1317 | | 0xe8,0xd5,0xd0,0x12,0xe3,0x6f,0x43,0xaf,0x87,0xce,0x32,0x5e,0xeb,0xa2,0x0b,0x35, |
1318 | | 0x0e,0x33,0x09,0x1b,0x12,0xc6,0x0f,0x13,0x86,0xd9,0x85,0x0d,0x0f,0x73,0x0e,0x73, |
1319 | | 0x0d,0xf3,0x08,0xf3,0x0a,0xf3,0x0b,0x53,0x85,0xa9,0xc3,0x42,0xc2,0xc2,0xc3,0x34, |
1320 | | 0x61,0xd1,0x61,0xf7,0x84,0xdd,0x1f,0xc6,0x5e,0xe3,0x87,0xc2,0x1e,0x0d,0x7b,0x32, |
1321 | | 0xec,0x99,0xb0,0xb1,0x2e,0x4b,0x8d,0x76,0x19,0xed,0x37,0x7a,0x21,0xec,0xa8,0xd1, |
1322 | | 0x4b,0x61,0xff,0xde,0x4e,0xfe,0xce,0x6f,0x5d,0xfa,0x7e,0x51,0xf7,0x66,0x2f,0x7e, |
1323 | | 0xf9,0xff,0xa3,0xf4,0xff,0x3d,0xea,0xce,0xff,0x3b,0x6a,0x24,0xf7,0x5f,0xa3,0x1c, |
1324 | | 0x47,0x7e,0x30,0xa8,0x9c,0x57,0xc5,0xfb,0x72,0x50,0xf6,0xa0,0x3d,0x83,0xee,0xdc, |
1325 | | 0x02,0x5b,0x9f,0xf7,0xb3,0xba,0xec,0x7f,0x9d,0x9a,0x86,0x7a,0xbb,0x78,0x47,0x79, |
1326 | | 0xab,0x06,0xb5,0x3b,0xe7,0x0e,0xfa,0x3d,0x5e,0x1e,0x17,0xf6,0x6a,0xd8,0xf4,0xb0, |
1327 | | 0x39,0x61,0xaf,0x87,0xbd,0x15,0x16,0x17,0x96,0x1c,0xb6,0x34,0x6c,0x79,0x58,0x56, |
1328 | | 0x58,0x4e,0x58,0x41,0xd8,0xa6,0xb0,0x6d,0x61,0x3b,0xc3,0x2a,0xc2,0xaa,0xc2,0xea, |
1329 | | 0xc3,0xde,0x09,0x3b,0x14,0xf6,0x5e,0x58,0x7b,0xd8,0xa9,0xb0,0x7f,0x86,0x9d,0x0d, |
1330 | | 0xeb,0x0a,0xbb,0x14,0xf6,0x45,0xd8,0x37,0x61,0x3f,0x84,0xf5,0x85,0xf1,0xc2,0xcd, |
1331 | | 0xc3,0xff,0xcc,0xfa,0x97,0x7d,0xc7,0x7c,0x43,0x69,0xaa,0xea,0xd3,0x69,0x54,0x7c, |
1332 | | 0x15,0xa9,0x9c,0x54,0xd1,0xdc,0xbb,0x5d,0xf6,0x7d,0xae,0x50,0xe5,0xa6,0xf2,0x54, |
1333 | | 0x39,0xa8,0x7c,0x54,0x96,0x2a,0x5b,0x15,0xfb,0xe6,0x99,0xa7,0x1a,0xac,0x1a,0xae, |
1334 | | 0x1a,0xa9,0xf2,0x50,0x59,0x85,0xa7,0x79,0x0d,0x0d,0x17,0x85,0xf7,0xe9,0xd8,0xfa, |
1335 | | 0x7d,0xba,0x70,0xfd,0xfb,0x5c,0x84,0x77,0xaa,0xdf,0xa7,0xeb,0xaf,0x8f,0xf5,0x21, |
1336 | | 0xf0,0xf8,0xd9,0x9b,0xc1,0x1b,0x03,0x6f,0xcb,0xf5,0xf5,0xfb,0x74,0x2a,0xa0,0xaf, |
1337 | | 0xdf,0xa7,0xeb,0xaf,0xcf,0x9e,0xbf,0xb5,0x7e,0x1a,0xfb,0x8d,0xed,0x2f,0xf4,0xeb, |
1338 | | 0xed,0xc7,0xdc,0xf1,0x2f,0xf4,0xeb,0xed,0xef,0xd3,0x0d,0x05,0xfd,0xfd,0x67,0xdf, |
1339 | | 0x57,0xf7,0xf7,0x9f,0xd5,0xff,0x5b,0xfd,0xbf,0x69,0xfd,0x2f,0xfd,0xf7,0xef,0xd5, |
1340 | | 0xb7,0x0b,0x17,0x87,0x8f,0x08,0x97,0x84,0xbb,0x84,0x4b,0xc3,0x65,0xe1,0x5e,0xe1, |
1341 | | 0xbe,0xe1,0x8a,0x5b,0xae,0xe8,0x1f,0xf9,0x3b,0xaf,0x80,0x70,0x13,0x3c,0xa1,0x4b, |
1342 | | 0x25,0xe1,0xe1,0x7f,0x6c,0x7f,0xa3,0x09,0x4f,0x95,0x44,0x87,0x2f,0x0a,0xbd,0x27, |
1343 | | 0xfc,0x81,0x3f,0x34,0xb6,0x1e,0x0e,0x7f,0x34,0xfc,0x89,0xf0,0xbb,0xb3,0x3f,0x7b, |
1344 | | 0x2a,0xfc,0xee,0xbc,0x27,0xf9,0x35,0x79,0x36,0xfc,0xe5,0xf0,0xc9,0xe2,0x5f,0x3f, |
1345 | | 0x3f,0x44,0x38,0x31,0x7c,0x4a,0xf8,0x8c,0x70,0x77,0xc1,0x9c,0xf0,0xf9,0xe1,0xce, |
1346 | | 0x76,0x0b,0xc3,0x17,0x85,0xc7,0x87,0x57,0xbb,0x27,0x87,0xa7,0x85,0x67,0x84,0xaf, |
1347 | | 0x0c,0x5f,0x13,0x9e,0x13,0x9e,0x23,0xcc,0x0f,0x2f,0x0a,0xdf,0x1c,0xbe,0x3d,0x7c, |
1348 | | 0x67,0x78,0x79,0xb8,0xb5,0x80,0xec,0xf6,0x86,0x17,0x38,0x58,0xda,0x6d,0x74,0xa8, |
1349 | | 0x09,0x5f,0x28,0x6a,0x08,0x7f,0x27,0xfc,0x60,0xf8,0x91,0xf0,0x63,0xe1,0x2f,0x38, |
1350 | | 0x28,0x85,0x27,0xc2,0x4f,0x85,0x7f,0x18,0xfe,0x71,0x78,0x7f,0xfb,0xe7,0xc3,0x3f, |
1351 | | 0x0f,0xff,0x36,0x9c,0x22,0x86,0x44,0xd8,0x44,0x38,0x45,0xc8,0x22,0x94,0x11,0x3f, |
1352 | | 0xd7,0x1f,0x1e,0xa1,0x8d,0xf8,0xbd,0xef,0x2f,0xfe,0xea,0xf7,0x1f,0x7f,0xe4,0x73, |
1353 | | 0xe7,0xf7,0x1f,0x37,0xf5,0xc7,0x46,0xdc,0x1f,0xf1,0x70,0xc4,0x63,0x11,0x4f,0x45, |
1354 | | 0xf8,0xc8,0x9e,0x8b,0x18,0x1d,0x31,0x26,0x62,0x42,0x84,0x42,0x36,0x39,0x62,0x7a, |
1355 | | 0xc4,0xec,0x88,0x40,0xd9,0xfc,0x88,0x85,0x11,0x8b,0x22,0xe2,0x23,0x52,0x22,0x96, |
1356 | | 0x46,0x64,0x84,0x67,0x46,0xac,0x8e,0x58,0x17,0x91,0x1b,0xb1,0x21,0x42,0x28,0xdf, |
1357 | | 0x14,0x31,0x4a,0xb0,0x2d,0xa2,0x34,0xa2,0x2c,0xa2,0x32,0xe2,0x54,0x78,0x75,0x44, |
1358 | | 0x7d,0x84,0xbb,0x9c,0xfd,0x2d,0x1f,0x4f,0xf9,0xfe,0x88,0x96,0x88,0x31,0xd2,0xd6, |
1359 | | 0x88,0x28,0xd9,0xd1,0x88,0xf6,0x88,0xce,0x88,0xd3,0x9c,0x9c,0x89,0x38,0x1f,0xd1, |
1360 | | 0x1d,0x71,0x29,0xe2,0x4a,0xc4,0xd7,0x11,0xdf,0x45,0xfc,0x18,0xa1,0x8b,0xe0,0x45, |
1361 | | 0x9a,0x45,0x5a,0x44,0xf2,0x23,0x45,0x91,0xf6,0x91,0xc3,0x23,0x25,0x91,0xae,0x10, |
1362 | | 0xa5,0xdc,0x23,0xd2,0x2b,0xd2,0x2f,0x52,0x15,0xf9,0x80,0x2c,0x28,0x32,0x2c,0x52, |
1363 | | 0x13,0xb9,0xcd,0x23,0x26,0xf2,0xbe,0xc8,0x87,0x22,0x1f,0x8d,0x7c,0x32,0xf2,0x99, |
1364 | | 0xc8,0x17,0x22,0x5f,0x8e,0x1c,0x17,0xf9,0x6a,0xe4,0xb4,0xc8,0x59,0x91,0x73,0xc2, |
1365 | | 0x5f,0x8b,0x7c,0x23,0xf2,0xad,0xc8,0xb8,0xc8,0xe4,0xc8,0xb4,0xc8,0x8c,0xc8,0x95, |
1366 | | 0x91,0x6b,0x22,0x73,0x22,0xf3,0x23,0x8b,0x22,0x37,0x43,0xb6,0x47,0xee,0x8a,0xac, |
1367 | | 0x88,0x7c,0x5c,0xba,0x2f,0xb2,0x36,0xb2,0x29,0xf2,0x40,0xe4,0xe1,0xc8,0xbd,0x82, |
1368 | | 0xf7,0x22,0x8f,0x47,0x36,0x08,0x4e,0x46,0x7e,0x10,0xf9,0x51,0xe4,0xb9,0xc8,0xae, |
1369 | | 0xc8,0x4b,0x91,0x57,0x22,0xbf,0x8a,0xfc,0x36,0xf2,0x7a,0x64,0x5f,0xa4,0xb1,0xc6, |
1370 | | 0x54,0x33,0x44,0x63,0xad,0x11,0x6a,0xec,0x34,0xc3,0x35,0x12,0x8d,0xab,0xc6,0x43, |
1371 | | 0x13,0xe7,0xe6,0xa5,0xe9,0x16,0xf8,0x6b,0xfc,0x35,0x81,0x9a,0x10,0x48,0x84,0x26, |
1372 | | 0x4a,0x73,0xaf,0xe6,0x21,0xcd,0xa3,0x9a,0x27,0x35,0xcf,0x68,0x5e,0xd0,0xbc,0xac, |
1373 | | 0x19,0xa7,0x99,0xa4,0x99,0xaa,0x99,0xa9,0x19,0x2d,0x9b,0xab,0x79,0x43,0xf3,0x96, |
1374 | | 0x86,0xd1,0x8c,0x95,0x33,0x9a,0x44,0xcd,0x04,0xd9,0x12,0xcd,0x32,0xcd,0x72,0xcd, |
1375 | | 0x6a,0xcd,0x64,0x99,0xad,0xdb,0x3a,0x4d,0xae,0x66,0x83,0x66,0x93,0x66,0xab,0x66, |
1376 | | 0x87,0x66,0xb7,0xa6,0x52,0x53,0xad,0xa9,0xd7,0xec,0xd7,0xb4,0x68,0x5a,0x35,0xc7, |
1377 | | 0x34,0x27,0x34,0xa7,0x34,0x1f,0x6a,0x3e,0xd6,0x9c,0xd7,0x74,0x6b,0x2e,0x69,0xae, |
1378 | | 0x68,0xa6,0xcb,0xbe,0xd2,0x7c,0xab,0xf9,0x51,0xa3,0xd3,0xf0,0xb4,0x66,0xda,0x79, |
1379 | | 0x32,0x0b,0x2d,0x5f,0x2b,0xd2,0xda,0x6b,0x87,0x6b,0x25,0x5a,0x57,0xad,0x87,0x96, |
1380 | | 0xfd,0x5d,0x24,0x2f,0xad,0x9f,0x56,0xa5,0x0d,0xd2,0x86,0x6b,0xb5,0xda,0x58,0xed, |
1381 | | 0xfd,0xda,0x05,0xb2,0x87,0xb5,0x8f,0x6b,0x9f,0xd2,0x3e,0xa7,0xf5,0xf1,0x1c,0xad, |
1382 | | 0x1d,0xa3,0x9d,0xa0,0x9d,0xac,0x9d,0xae,0x9d,0xa3,0x9d,0xaf,0x5d,0xa8,0x5d,0xa4, |
1383 | | 0x4d,0xd0,0xa6,0x68,0x97,0x6a,0x33,0xb5,0x59,0xd2,0x55,0xda,0xb5,0xda,0x5c,0x6d, |
1384 | | 0xa1,0x76,0xb3,0x76,0xbb,0x76,0x97,0xb6,0x42,0xbb,0x4f,0x5b,0xab,0x6d,0xd4,0xbe, |
1385 | | 0x2d,0x3b,0xe7,0xde,0xac,0x3d,0xa4,0x7d,0x57,0xdb,0xa6,0x3d,0xa9,0xfd,0x40,0xfb, |
1386 | | 0x91,0xf6,0xac,0x36,0x43,0x7e,0x41,0xdb,0xa3,0xbd,0xac,0xbd,0xaa,0xbd,0xa6,0xbd, |
1387 | | 0xae,0xd5,0x69,0x79,0x51,0x2b,0xe5,0x66,0x51,0x16,0x51,0xfc,0x28,0x51,0x94,0x7d, |
1388 | | 0xd4,0xf0,0x28,0x49,0x94,0x5b,0x94,0x2c,0xca,0x27,0x4a,0x11,0xa5,0x8e,0xca,0x91, |
1389 | | 0x87,0x46,0x45,0x46,0xc5,0x44,0xdd,0x17,0xf5,0x50,0xd4,0x63,0x51,0x4f,0x45,0x3d, |
1390 | | 0x17,0x35,0x3a,0x6a,0x4c,0xd4,0x04,0xc8,0xe4,0xa8,0xe9,0x51,0x45,0xf2,0xd9,0x51, |
1391 | | 0xf3,0xa2,0x16,0x44,0xbd,0x1d,0x15,0x17,0x95,0x1c,0x95,0x16,0x35,0x5a,0x9a,0x19, |
1392 | | 0xb5,0x3a,0x6a,0x5d,0x54,0x5e,0x54,0x51,0xd4,0x96,0xa8,0x92,0xa8,0x1a,0xf9,0xae, |
1393 | | 0xa8,0x3d,0x51,0xd5,0x51,0x0d,0x51,0xcd,0x51,0x87,0x20,0x0d,0xf2,0x40,0xcf,0x77, |
1394 | | 0xa3,0xda,0xa2,0x3a,0xa2,0xde,0x8f,0xfa,0x28,0xaa,0xd5,0xed,0xa0,0xfc,0x6c,0xd4, |
1395 | | 0x85,0xa8,0x62,0x59,0x6f,0xd4,0x95,0xa8,0x1f,0x3c,0xbe,0x8e,0xfa,0x2e,0xaa,0x4c, |
1396 | | 0xf6,0x63,0x94,0x2e,0x8a,0x17,0x6d,0x0e,0xb1,0x8a,0x16,0x44,0xdb,0x46,0x0f,0x8b, |
1397 | | 0x76,0x8a,0x76,0x89,0x76,0x8f,0xf6,0x8a,0xf6,0x8b,0x56,0x45,0x07,0x45,0x87,0x45, |
1398 | | 0x6b,0xa2,0x63,0xa3,0xef,0x8f,0x7e,0x38,0xfa,0xb1,0xe8,0x7f,0x44,0x3f,0x1b,0xfd, |
1399 | | 0x62,0xf4,0x98,0xe8,0x89,0xd1,0x53,0xa2,0x67,0x46,0xcf,0x8d,0x7e,0x23,0xfa,0xad, |
1400 | | 0xe8,0x56,0x19,0x13,0x9d,0x14,0x9d,0x16,0x9d,0x11,0xbd,0x2a,0x7a,0x6d,0x74,0x6e, |
1401 | | 0xf4,0x86,0xe8,0x4d,0xd1,0x5b,0xa3,0x77,0x44,0xef,0x8e,0xde,0x13,0x5d,0x1d,0xdd, |
1402 | | 0x10,0xdd,0x1c,0x1d,0xa8,0x39,0x1c,0xfd,0x5e,0xf4,0xf1,0xe8,0x93,0xd1,0x1f,0x44, |
1403 | | 0x7f,0x14,0x7d,0x36,0xfa,0x42,0x74,0x4f,0xf4,0xe7,0xd1,0x5f,0x46,0x7f,0x13,0x5d, |
1404 | | 0x28,0xfd,0x21,0xfa,0x46,0xb4,0x51,0x8c,0x49,0xcc,0xe0,0x18,0xab,0x98,0x4e,0x99, |
1405 | | 0x20,0xc6,0x36,0x46,0x1c,0xe3,0x18,0x33,0x32,0xc6,0x3d,0xc6,0x2b,0xc6,0x3f,0x26, |
1406 | | 0x20,0x26,0x38,0x26,0x3c,0x46,0x1b,0x73,0x4f,0xcc,0x03,0x31,0xa3,0x62,0x9e,0x88, |
1407 | | 0x79,0x3a,0xe6,0x85,0x98,0x57,0x62,0xc6,0xc7,0x54,0xba,0xbd,0x1a,0x33,0x2d,0x66, |
1408 | | 0x56,0xcc,0x6b,0x31,0x6f,0xc4,0xbc,0x15,0x73,0x5e,0xce,0xc4,0x24,0xc6,0x2c,0x89, |
1409 | | 0x59,0x16,0xb3,0x3c,0x66,0x75,0xcc,0xba,0x98,0xdc,0x98,0x51,0xa2,0x0d,0x31,0xc5, |
1410 | | 0x31,0xdb,0x62,0x4a,0x63,0xca,0x62,0x2a,0x63,0xaa,0x63,0x1a,0x62,0x9a,0x63,0x0e, |
1411 | | 0xc5,0xbc,0x1b,0xf3,0xad,0xfc,0xba,0x7c,0x8a,0xa8,0x2d,0xe6,0x64,0xcc,0x07,0x31, |
1412 | | 0x1f,0xc5,0x9c,0x8d,0xb9,0x10,0xd3,0x1b,0x73,0x25,0xe6,0xab,0x98,0x6f,0x63,0xae, |
1413 | | 0xc7,0xe8,0x62,0xfa,0xe4,0xbc,0x58,0xf3,0x58,0xab,0x58,0x41,0xac,0x6d,0xac,0x38, |
1414 | | 0xd6,0x29,0xd6,0x25,0xd6,0x3d,0xd6,0x33,0xd6,0x37,0x56,0x19,0xab,0x8e,0x0d,0x8d, |
1415 | | 0xd5,0xc4,0xc6,0xc4,0xde,0x17,0xfb,0x50,0xec,0x63,0xb1,0xff,0x88,0x7d,0x36,0xf6, |
1416 | | 0xc5,0xd8,0x57,0x62,0x27,0xc4,0x4e,0x89,0x9d,0x11,0x3b,0x27,0x76,0x7e,0xec,0x9b, |
1417 | | 0xb1,0x8b,0x63,0xed,0x3c,0xed,0x3c,0x13,0x63,0x97,0xc4,0xa6,0xc7,0xae,0x88,0xcd, |
1418 | | 0x8a,0xcd,0x8e,0xcd,0x8b,0x2d,0x8c,0x2d,0x8e,0xdd,0x16,0x3b,0xcc,0x73,0x67,0x6c, |
1419 | | 0x79,0xec,0xde,0xd8,0x9a,0xd8,0x86,0xd8,0x77,0x62,0x0f,0xc5,0xbe,0x1b,0x7b,0x3c, |
1420 | | 0xb6,0x33,0xd6,0xd3,0xe6,0xc3,0xd8,0x50,0x9b,0x8f,0x63,0xcf,0xc7,0x76,0xc7,0x5e, |
1421 | | 0x8a,0x1d,0x65,0x73,0x25,0xf6,0x6e,0xac,0x72,0x6f,0x7b,0x1f,0xca,0xfe,0x77,0x9a, |
1422 | | 0x14,0x09,0x35,0xe9,0x74,0x5f,0xf4,0xbf,0x64,0xe5,0x42,0x8d,0xe1,0xe8,0xe2,0xad, |
1423 | | 0x73,0x1b,0x8f,0x7e,0x96,0xab,0xd1,0x2d,0x46,0xf8,0xa8,0x8e,0xfb,0xcf,0x52,0xcc, |
1424 | | 0x40,0xa9,0x1f,0xd9,0xff,0x21,0x51,0xf0,0x83,0x4e,0x77,0xa3,0xe5,0xeb,0x2b,0x8d, |
1425 | | 0x38,0xba,0x71,0xf9,0xeb,0xc6,0x30,0x23,0x6a,0xd3,0xf1,0xfa,0xae,0x70,0xf9,0x97, |
1426 | | 0xbf,0xfe,0xfc,0x50,0xc4,0x29,0x87,0x43,0xba,0xe6,0x43,0x11,0x71,0xac,0x6e,0x33, |
1427 | | 0xdd,0x27,0x37,0x90,0xaf,0xfb,0xfa,0x93,0x88,0x57,0x82,0xda,0xd8,0xb6,0xb8,0xe3, |
1428 | | 0x2f,0xd8,0xe3,0x59,0x6d,0x3a,0x6b,0xe2,0x8e,0x59,0xe3,0x6e,0x7c,0xa9,0x6b,0x63, |
1429 | | 0x57,0x71,0xba,0xc5,0x3f,0x41,0x93,0xdf,0xe2,0xc4,0x97,0x75,0x4d,0xba,0x11,0xac, |
1430 | | 0x5d,0x7c,0xae,0x5f,0x9f,0xe8,0xcc,0xb8,0x38,0x62,0x71,0x04,0x57,0x81,0x0b,0xd9, |
1431 | | 0x83,0xc5,0x06,0xeb,0x22,0x74,0xb7,0xf4,0x41,0x62,0xf0,0x00,0xfb,0x5c,0x90,0xdc, |
1432 | | 0xfa,0x92,0x14,0x9d,0x83,0x11,0x8b,0x89,0x6d,0x56,0xf7,0x09,0xfb,0x9f,0x81,0xd0, |
1433 | | 0x5b,0x9e,0xbe,0xac,0x6e,0xe0,0x3f,0x69,0x69,0xd8,0xfc,0xc5,0x3a,0xbe,0x8e,0x7f, |
1434 | | 0x95,0x3b,0x94,0xe8,0xfd,0xc3,0xe7,0x5a,0x3d,0x64,0x28,0xd4,0x66,0x88,0x59,0x03, |
1435 | | 0x0a,0xb8,0x36,0x34,0x37,0xdf,0xc5,0x1a,0xbc,0x6d,0xf8,0xf0,0xbf,0x34,0x24,0xbe, |
1436 | | 0xd7,0x7d,0xda,0xff,0x22,0x5b,0xaf,0x51,0xdf,0xb2,0xfe,0xff,0x8c,0xe3,0x32,0xd0, |
1437 | | 0xad,0x4d,0x37,0x3a,0x73,0xcd,0xd3,0x62,0xc3,0xa7,0xdf,0x38,0x3e,0xf7,0x2d,0xc1, |
1438 | | 0xcd,0x0f,0x67,0xad,0xa1,0x97,0x8b,0x6f,0x7d,0x23,0xce,0x1f,0x18,0x0f,0xfa,0x58, |
1439 | | 0xa2,0xe3,0x69,0x9a,0x0c,0x7d,0xd5,0xf1,0x19,0x2e,0xa7,0x51,0xd7,0x6c,0xe8,0x83, |
1440 | | 0xbe,0xb6,0x46,0xf7,0xb5,0xfe,0x7f,0x48,0xd0,0xf7,0xec,0xf1,0xa2,0x45,0x8b,0xe8, |
1441 | | 0xa6,0x66,0x7d,0x5d,0x3e,0xfb,0xbf,0xb6,0xbf,0xef,0xd7,0x60,0x18,0x77,0x5f,0x70, |
1442 | | 0x8d,0xec,0x43,0x19,0xcd,0x2d,0xe3,0xd0,0x2c,0x85,0x8b,0x32,0xd9,0x93,0x12,0xa3, |
1443 | | 0x9b,0x23,0x54,0x73,0xd3,0x62,0xae,0xef,0xdc,0xdf,0x80,0xf3,0xcf,0x0e,0x5c,0x03, |
1444 | | 0x36,0x6c,0xd4,0xbb,0x5c,0x73,0xb3,0x16,0xdd,0xec,0x18,0xd7,0x6b,0xe4,0x6b,0xb8, |
1445 | | 0xe1,0xd3,0xb8,0xc2,0x50,0x9c,0xeb,0x04,0x33,0x70,0x2f,0x04,0x7d,0xaf,0x57,0xae, |
1446 | | 0x4b,0xd0,0x7b,0x77,0xc0,0x2e,0x5c,0x8f,0x9f,0xb8,0xc4,0xcc,0x2f,0xbf,0x80,0x2b, |
1447 | | 0x35,0x29,0x18,0x19,0x46,0xb7,0x7e,0xc7,0xc0,0x35,0xf4,0x7d,0xbf,0x37,0x35,0x7d, |
1448 | | 0x7a,0x93,0x59,0xb3,0x78,0x4e,0xd4,0x87,0xf3,0x46,0xb7,0xde,0x6f,0x66,0x3f,0x19, |
1449 | | 0xec,0x83,0x7f,0x7f,0xf6,0xdd,0x84,0xde,0x73,0x61,0x3c,0xfa,0xa9,0x6f,0xe0,0x48, |
1450 | | 0x7f,0x95,0xfb,0xad,0xe1,0xae,0x11,0xeb,0x77,0xb6,0x09,0x4d,0xff,0xcd,0xf6,0x89, |
1451 | | 0x19,0x71,0xa3,0x95,0x37,0x70,0xeb,0xd2,0xcd,0xab,0xcb,0xbe,0x61,0xd6,0xdf,0x8d, |
1452 | | 0x86,0x66,0xf0,0x59,0x5c,0x0f,0x07,0xf4,0xff,0x47,0x2a,0x33,0x1d,0x4f,0x7f,0x9f, |
1453 | | 0x5e,0xfe,0xb1,0x20,0x24,0xee,0x6c,0x9b,0x04,0xe5,0x1f,0xe2,0xfc,0xa4,0x2b,0xfe, |
1454 | | 0xae,0xd1,0xc8,0x54,0xaf,0xf9,0x0b,0xb6,0x2e,0x6b,0xf3,0xcd,0x7e,0x68,0xf4,0xc3, |
1455 | | 0x09,0x1f,0xd4,0xe0,0x41,0x0d,0x0d,0xcc,0x26,0x3c,0xfd,0xc5,0xe6,0xee,0x2f,0x3e, |
1456 | | 0x6b,0xc9,0xcf,0xe6,0x1b,0xc3,0xdf,0xf0,0x9b,0x31,0x8b,0xbf,0x9a,0xc9,0xea,0xf9, |
1457 | | 0x61,0x31,0x0d,0x98,0x46,0x06,0x57,0xff,0x24,0xd1,0xeb,0x1b,0xf8,0x70,0x7d,0x34, |
1458 | | 0xbb,0xc5,0x5f,0x86,0xf6,0x78,0xac,0xee,0x1b,0xfa,0x5b,0xeb,0xe6,0xd8,0x46,0x23, |
1459 | | 0x7d,0xb8,0x17,0xb8,0x6e,0x2f,0xde,0xc3,0xda,0xdd,0xc8,0x96,0x59,0xfc,0x63,0xbf, |
1460 | | 0x97,0xf8,0x3a,0x1e,0xaf,0xdf,0x26,0x23,0x9d,0xbe,0x81,0x43,0x3f,0xd7,0x60,0xb8, |
1461 | | 0xcf,0x74,0x3c,0x86,0x4f,0xfd,0xd7,0xfa,0xd6,0xfb,0xd4,0xec,0x96,0x5c,0x0d,0x0d, |
1462 | | 0xdc,0xdf,0xcd,0x03,0x05,0x16,0x73,0xba,0x34,0x1a,0xac,0x04,0x75,0x3f,0xc2,0x94, |
1463 | | 0xb3,0xba,0x81,0xb1,0xa6,0xbf,0x15,0x74,0x29,0x86,0x92,0xcc,0xcd,0xef,0xaa,0x24, |
1464 | | 0xb4,0xb8,0xbf,0xa7,0x8c,0x7e,0xc4,0xb3,0xe5,0xfb,0xe7,0xdc,0x5b,0xcc,0xa3,0x2f, |
1465 | | 0x66,0x12,0x76,0x30,0x5f,0x1a,0x0d,0x5c,0x47,0xc3,0x3d,0xc2,0x47,0xe7,0x1d,0xcf, |
1466 | | 0x0e,0xcc,0xde,0x9a,0x9b,0x37,0x9e,0xe6,0x67,0xf7,0x04,0x9f,0x0c,0x63,0xc4,0x08, |
1467 | | 0xc9,0xef,0xfb,0xf4,0xbd,0x93,0x70,0x05,0x99,0x5b,0xae,0x97,0x04,0x2d,0x34,0xdf, |
1468 | | 0x3a,0x4a,0x07,0xbc,0x90,0x40,0x3f,0x9f,0x89,0x52,0xf4,0xa3,0x56,0x3f,0xaa,0x17, |
1469 | | 0xcf,0xd4,0x2d,0x2e,0x30,0x5c,0x79,0x78,0xbb,0xf9,0xd6,0xff,0xd8,0xa3,0xff,0x48, |
1470 | | 0xfa,0x53,0xfa,0x9b,0x96,0xfb,0xbf,0x6d,0xb0,0x69,0x71,0xff,0x0a,0x5d,0x9f,0xdd, |
1471 | | 0xa4,0x2f,0xf3,0x35,0xec,0x90,0x70,0xd7,0x8d,0x7f,0x73,0x04,0xb1,0xd7,0x75,0xe0, |
1472 | | 0x5e,0xd7,0xe8,0xf8,0x3c,0xc3,0x9d,0xc6,0xe5,0x68,0x74,0x92,0xc5,0x57,0x31,0x88, |
1473 | | 0x33,0xd9,0x1b,0xf1,0x3b,0xdd,0x2d,0xf3,0xef,0xcd,0x99,0xc4,0x30,0x87,0xd3,0x18, |
1474 | | 0x1a,0x4b,0xe3,0x68,0x3c,0x4d,0xa0,0x89,0x34,0x89,0x5e,0xa5,0xc9,0x34,0x85,0xa6, |
1475 | | 0xd2,0x34,0x9a,0x4e,0x33,0x68,0x26,0xcd,0xa2,0xd9,0x34,0x87,0xe6,0xd2,0x6b,0x34, |
1476 | | 0x8f,0xe6,0xd3,0xeb,0xf4,0x06,0x2d,0xa0,0x85,0xe4,0x4c,0xce,0xef,0x2d,0x01,0x89, |
1477 | | 0xc4,0xfe,0x2e,0x9a,0xf3,0x7b,0x71,0x74,0xac,0x0e,0xd1,0x16,0xec,0x25,0x15,0xe7, |
1478 | | 0xe3,0x12,0x03,0xb8,0x10,0xa7,0xb8,0x74,0xf3,0x06,0x6a,0x2e,0xa4,0xe6,0x22,0x6a, |
1479 | | 0xde,0x48,0xcd,0x9b,0xa8,0xb9,0x98,0x9a,0x37,0x53,0xf3,0x16,0x6a,0xde,0x4a,0xcd, |
1480 | | 0xdb,0xa8,0x79,0x3b,0x35,0x97,0x50,0xf3,0x0e,0x6a,0x2e,0xa5,0xe6,0x9d,0xd4,0xbc, |
1481 | | 0x8b,0x9a,0x77,0x53,0x73,0x19,0x35,0x97,0x53,0x73,0x05,0x35,0xef,0xa1,0xe6,0x4a, |
1482 | | 0x6a,0xde,0x4b,0xcd,0x55,0xd4,0x5c,0x4d,0xcd,0x35,0xd4,0x5c,0x4b,0xcd,0x75,0xd4, |
1483 | | 0x5c,0x4f,0xcd,0x0d,0x74,0x20,0x8e,0x0e,0x24,0xd0,0x81,0x24,0x3a,0x90,0x42,0x07, |
1484 | | 0x52,0xe9,0xc0,0x52,0x3a,0x90,0x4e,0x07,0x32,0xe9,0xc0,0x0a,0x3a,0xb0,0x8a,0x0e, |
1485 | | 0x64,0xd1,0x81,0xb5,0x74,0x20,0x9b,0x0e,0xac,0xa7,0x03,0x79,0x74,0xa0,0x80,0x0e, |
1486 | | 0x14,0xd2,0x81,0x8d,0x74,0xa0,0x98,0x0e,0x6c,0xa1,0x03,0xdb,0xe8,0x40,0x09,0x1d, |
1487 | | 0x28,0xa5,0x03,0xbb,0x68,0xf2,0x7b,0x29,0x34,0x79,0x0a,0x1d,0xa8,0xa4,0x03,0xfb, |
1488 | | 0xe8,0x40,0x0d,0x1d,0xa8,0xa3,0x03,0x0d,0x34,0xed,0x9d,0x7d,0xd4,0x12,0x4f,0x2d, |
1489 | | 0x89,0xd4,0x92,0x4c,0x2d,0x4b,0xe8,0x48,0xdd,0x0c,0x6a,0x59,0x4a,0x2d,0xe9,0xd4, |
1490 | | 0x92,0x49,0x2d,0x2b,0xa8,0x65,0x15,0xb5,0x64,0x51,0xcb,0x5a,0x6a,0xc9,0xa6,0x96, |
1491 | | 0xf5,0xd4,0x92,0x47,0x2d,0x05,0xd4,0x52,0x48,0x2d,0x1b,0xa9,0xa5,0x98,0x5a,0xb6, |
1492 | | 0x50,0xcb,0x36,0x6a,0x29,0xa1,0x96,0x52,0x6a,0xd9,0x45,0x2d,0x65,0xd4,0x52,0x41, |
1493 | | 0x2d,0x95,0xd4,0xb2,0x8f,0x9a,0x1b,0xa9,0xa5,0x86,0x5a,0xea,0xa8,0xa5,0x81,0x5a, |
1494 | | 0x57,0xd1,0xc1,0x04,0x3a,0x98,0x44,0xad,0xab,0xe9,0xe0,0x12,0x6a,0x5d,0x43,0xad, |
1495 | | 0x6b,0xe9,0xe0,0x32,0x3a,0x94,0x47,0xad,0xd9,0xd4,0xba,0x9e,0x0e,0xae,0xa4,0xd6, |
1496 | | 0x0d,0xd4,0xba,0x91,0x5a,0xb7,0x51,0xeb,0x56,0x3a,0x88,0xcc,0x5d,0xd4,0x5a,0x4e, |
1497 | | 0xad,0x95,0x74,0xb0,0x90,0x0e,0x6e,0xa4,0x83,0xc5,0x74,0x84,0xa1,0x83,0x5b,0xe9, |
1498 | | 0x08,0xda,0x29,0xa5,0x23,0x4b,0xe8,0xe0,0x6e,0x3a,0x92,0x46,0x47,0x96,0xd2,0xc1, |
1499 | | 0x3d,0x74,0x70,0x2f,0x1d,0x59,0x49,0x07,0xab,0xe9,0x60,0x3d,0x8d,0x87,0xbe,0x69, |
1500 | | 0x53,0x68,0xc6,0x14,0x3a,0x94,0x41,0x87,0x96,0xd3,0xa1,0x95,0x74,0x68,0x35,0x1d, |
1501 | | 0x5a,0x43,0x87,0xd6,0xd1,0xa1,0x1c,0x3a,0x94,0x4b,0x87,0x0a,0xe8,0x50,0x21,0x1d, |
1502 | | 0xda,0x48,0x87,0x8a,0xe9,0xd0,0x16,0x3a,0xb4,0x8d,0x0e,0x95,0xd0,0xa1,0x52,0x3a, |
1503 | | 0xb4,0x8b,0xc6,0x2f,0xa4,0x43,0x50,0x99,0x45,0x07,0x1b,0xe9,0x50,0x35,0x1d,0xaa, |
1504 | | 0xa5,0x43,0xf5,0x74,0xa8,0x91,0x0e,0xc7,0xd1,0xe1,0x04,0x3a,0x9c,0x44,0x87,0x53, |
1505 | | 0xe8,0x70,0x2a,0x1d,0x5e,0x4a,0x87,0xd3,0xe9,0x70,0x26,0x1d,0x5e,0x41,0x87,0x57, |
1506 | | 0xd1,0xe1,0x2c,0x3a,0xbc,0x96,0x0e,0x67,0xd3,0xe1,0xf5,0x74,0x38,0x8f,0x0e,0x17, |
1507 | | 0xd0,0xc1,0x7c,0x3a,0xbc,0x91,0x0e,0x17,0xd3,0xe1,0x2d,0x74,0x78,0x1b,0x1d,0x2e, |
1508 | | 0xa1,0xc3,0xa5,0x74,0x78,0x17,0x1d,0x2e,0xa3,0xc3,0x15,0x74,0xbe,0x0c,0x27,0xea, |
1509 | | 0xe8,0x60,0x0e,0x52,0x9b,0xa9,0x35,0x9e,0x0e,0x32,0x74,0x24,0x95,0x8e,0x2c,0xa3, |
1510 | | 0xd6,0x14,0x6a,0x4d,0xa5,0xd6,0xa5,0xd4,0x9a,0x4e,0xad,0x99,0xd4,0x8a,0xb3,0xd5, |
1511 | | 0xd4,0x5a,0x4b,0x47,0xe2,0x30,0xf0,0x92,0x41,0x0a,0x48,0x03,0x5b,0x41,0x02,0x58, |
1512 | | 0x4a,0x47,0xb2,0xe8,0x3d,0x86,0x30,0x38,0xdf,0x5b,0x45,0xef,0x2d,0x61,0x07,0x69, |
1513 | | 0x35,0x1d,0x2d,0xa3,0xa3,0x15,0x74,0x04,0x89,0x7d,0xe4,0x8c,0xe3,0x30,0x6a,0xab, |
1514 | | 0x60,0x07,0x33,0x7b,0x76,0x07,0xe1,0x8a,0x1f,0x2b,0xa5,0x63,0x3b,0xe9,0xd8,0x2e, |
1515 | | 0x6a,0x5b,0x46,0x6d,0xe9,0xd4,0x96,0x41,0xc7,0xca,0xe8,0x58,0x39,0x1d,0xab,0xa0, |
1516 | | 0x63,0x7b,0xe8,0x58,0x25,0x1d,0xdb,0x4b,0xc7,0x50,0xac,0x8a,0x8e,0xd5,0xd0,0xb1, |
1517 | | 0x5a,0x3a,0x56,0x4f,0xc7,0x1a,0xe8,0x58,0x23,0xb5,0x31,0xd4,0x16,0x47,0x6d,0x09, |
1518 | | 0xd4,0x96,0x48,0x6d,0x49,0xd4,0x96,0x4c,0x6d,0x29,0xd4,0xb6,0x84,0xda,0x52,0xa9, |
1519 | | 0x2d,0x8d,0xda,0x96,0x52,0xdb,0x5a,0x6a,0xcb,0xa6,0xb6,0xf5,0xd4,0x96,0x47,0x6d, |
1520 | | 0x05,0xd4,0x56,0x48,0x6d,0x1b,0xa9,0xad,0x98,0xda,0xb6,0x50,0xdb,0x36,0x6a,0x2b, |
1521 | | 0xa1,0xb6,0x52,0x6a,0x83,0xde,0x2a,0x6a,0xab,0xa5,0xa3,0xf8,0xa9,0xa3,0xa3,0xf5, |
1522 | | 0xd4,0xbe,0x9c,0xda,0x57,0x50,0xfb,0x4a,0x6a,0x5f,0x45,0xed,0xab,0xa9,0x3d,0x8b, |
1523 | | 0xda,0xd7,0x50,0xfb,0x5a,0x6a,0x5f,0x47,0xed,0xd9,0xd4,0x9e,0x43,0xed,0xeb,0xa9, |
1524 | | 0x3d,0x97,0xda,0xf3,0xa8,0x3d,0x9f,0xda,0x0b,0xe8,0xf8,0x6e,0x3a,0x5e,0x46,0xc7, |
1525 | | 0xcb,0xe9,0x78,0x05,0x1d,0xdf,0x43,0xc7,0x2b,0xe9,0xf8,0x5e,0x3a,0xbe,0x8f,0x8e, |
1526 | | 0x57,0xd1,0xf1,0x6a,0x3a,0x5e,0x43,0xc7,0x6b,0xe9,0x78,0x1d,0x1d,0xaf,0xa7,0xe3, |
1527 | | 0x0d,0x74,0xbc,0x91,0xda,0x19,0x6a,0x8f,0xa3,0xf6,0x78,0x6a,0x4f,0xa0,0xf6,0x44, |
1528 | | 0x6a,0x4f,0xa2,0xf6,0x64,0x6a,0x4f,0xa1,0xf6,0x25,0xd4,0x9e,0x4a,0xed,0x69,0xd4, |
1529 | | 0xbe,0x94,0xda,0x97,0x51,0x7b,0x3a,0xb5,0x67,0x50,0x7b,0x26,0xb5,0x17,0x52,0xfb, |
1530 | | 0x46,0x6a,0x2f,0xa6,0xf6,0x2d,0xd4,0xbe,0x8d,0xda,0x4b,0xa8,0xbd,0x94,0xda,0x77, |
1531 | | 0x51,0x7b,0x19,0xb5,0x57,0x50,0x7b,0x25,0xb5,0xef,0xa3,0xf6,0x6a,0x6a,0xaf,0xa5, |
1532 | | 0x76,0x18,0xdf,0x48,0x27,0xe2,0xe8,0xc4,0x52,0x3a,0x91,0x4e,0x27,0x32,0xe9,0xc4, |
1533 | | 0x0a,0x3a,0xb1,0x8a,0x4e,0x64,0xd1,0x89,0xb5,0x74,0x22,0x9b,0x4e,0xac,0xa7,0x13, |
1534 | | 0x79,0x74,0xa2,0x80,0x4e,0x14,0xd2,0x89,0x8d,0x74,0xa2,0x98,0x4e,0x6c,0xa1,0x13, |
1535 | | 0xdb,0xe8,0x44,0x09,0x9d,0x28,0xa5,0x13,0xbb,0xe8,0x44,0x19,0x9d,0xa8,0xa0,0x13, |
1536 | | 0x95,0x74,0x62,0x1f,0x9d,0xa8,0xa6,0x13,0xb5,0x74,0xa2,0x9e,0x4e,0x34,0x52,0x47, |
1537 | | 0x26,0x75,0xc4,0x53,0x47,0x22,0x75,0x24,0x53,0xc7,0x12,0xea,0x48,0xa3,0x8e,0x65, |
1538 | | 0xd4,0x91,0x41,0x1d,0x2b,0xa8,0x63,0x15,0x75,0x64,0x51,0xc7,0x5a,0xea,0xc8,0xa6, |
1539 | | 0x8e,0xf5,0xd4,0x91,0x47,0x1d,0x05,0xd4,0x51,0x48,0x1d,0x1b,0xa9,0xa3,0x98,0x3a, |
1540 | | 0xb6,0x50,0xc7,0x36,0xea,0x28,0xa1,0x8e,0x52,0xea,0xd8,0x45,0x1d,0x65,0xd4,0x51, |
1541 | | 0x41,0x1d,0x95,0xd4,0xb1,0x8f,0x3a,0xaa,0xa9,0xa3,0x96,0x3a,0xea,0xa9,0xa3,0x91, |
1542 | | 0x4e,0xc6,0xd1,0xc9,0x04,0x3a,0x99,0x44,0x27,0x53,0xe8,0x64,0x2a,0x9d,0x5c,0x4a, |
1543 | | 0x27,0xd3,0xe9,0x64,0x26,0x9d,0x5c,0x41,0x27,0x57,0xd1,0xc9,0x2c,0x3a,0xb9,0x96, |
1544 | | 0x4e,0x66,0xd3,0xc9,0xf5,0x74,0x32,0x8f,0x4e,0x16,0xd0,0xc9,0x42,0x3a,0xb9,0x91, |
1545 | | 0x4e,0x16,0xd3,0xc9,0x2d,0x74,0x72,0x1b,0x9d,0x2c,0xa1,0x93,0xa5,0x74,0x72,0x17, |
1546 | | 0x75,0x16,0x52,0x67,0x11,0x75,0x6e,0xa4,0xce,0x4d,0xd4,0x59,0x4c,0x9d,0x9b,0xa9, |
1547 | | 0x73,0x0b,0x75,0x6e,0xa5,0xce,0x6d,0xd4,0xb9,0x9d,0x3a,0x4b,0xa8,0x73,0x07,0x75, |
1548 | | 0x96,0x52,0xe7,0x4e,0xea,0x44,0xe1,0xdd,0xd4,0x59,0x46,0x9d,0xe5,0xd4,0x59,0x41, |
1549 | | 0x9d,0x7b,0xa8,0xb3,0x92,0x3a,0xf7,0x52,0xe7,0x3e,0xea,0xac,0xa2,0xce,0x6a,0xea, |
1550 | | 0xac,0xa1,0xce,0x5a,0xea,0xac,0xa3,0xce,0x7a,0xea,0x6c,0xa0,0xce,0x46,0x3a,0xc5, |
1551 | | 0xd0,0xa9,0x38,0x3a,0x15,0x4f,0xa7,0x12,0xe8,0x54,0x22,0x9d,0x4a,0xa2,0x53,0xc9, |
1552 | | 0xd0,0x82,0x8c,0x0f,0xb6,0x9c,0xde,0x43,0xa7,0x97,0x20,0xf8,0x67,0x0a,0x9b,0x4a, |
1553 | | 0x43,0x70,0x76,0x53,0xd6,0xd9,0x4d,0x75,0x88,0xd6,0xe8,0xa3,0xb5,0xfa,0x28,0x57, |
1554 | | 0x1f,0x15,0xea,0xa3,0x22,0x7d,0x54,0xa2,0x8f,0x76,0x71,0xd1,0xe6,0xc2,0xb3,0x9b, |
1555 | | 0xd9,0xa8,0x48,0x1f,0xed,0xe2,0xa2,0xad,0xe5,0x67,0xb7,0xb2,0x51,0x95,0x3e,0x5a, |
1556 | | 0xa3,0x8f,0xd6,0xea,0xa3,0x5c,0x7d,0x54,0xc2,0x45,0x3b,0x0a,0xcf,0xee,0x60,0xa3, |
1557 | | 0x22,0x2e,0xaa,0x4e,0x3f,0x5b,0x55,0x4e,0x67,0x6b,0xd3,0xcf,0xd6,0x20,0xaa,0x29, |
1558 | | 0x39,0x5b,0x93,0xad,0x8f,0x0a,0xe9,0x6c,0xdd,0x52,0x3a,0x5b,0x1f,0x7f,0xb6,0x61, |
1559 | | 0x1f,0xa2,0x65,0xfa,0x68,0x85,0x3e,0x5a,0xa3,0x8f,0xd6,0xeb,0x23,0xe6,0x6c,0x43, |
1560 | | 0x25,0xa2,0xb2,0xb3,0xf5,0xe5,0xfa,0x08,0x9d,0x6b,0x28,0x3f,0xdb,0xc0,0x70,0x11, |
1561 | | 0x32,0xb8,0x54,0x45,0x7f,0x64,0xc8,0xe8,0xcf,0x5f,0xc9,0x35,0xd2,0x90,0xab,0x8f, |
1562 | | 0x0a,0xf5,0xd1,0x66,0x7d,0x54,0xa2,0x8f,0x96,0xb3,0x0a,0xce,0xef,0x61,0x40,0x1c, |
1563 | | 0x88,0x07,0x09,0x20,0x11,0x24,0x81,0x64,0x90,0x02,0x96,0x80,0x54,0x90,0x06,0x96, |
1564 | | 0x82,0x65,0x20,0x1d,0x64,0x80,0x4c,0xb0,0x1c,0xac,0x00,0x2b,0xc1,0x2a,0xb0,0x1a, |
1565 | | 0x64,0x81,0x35,0x60,0x2d,0x58,0x07,0xb2,0x01,0xa6,0xba,0x3d,0xeb,0x41,0x2e,0xc8, |
1566 | | 0x03,0xf9,0xa0,0x00,0x6c,0x00,0x85,0xa0,0x08,0x6c,0x04,0x9b,0x40,0x31,0xd8,0x02, |
1567 | | 0x4a,0xe9,0x5c,0x42,0x2e,0x9d,0xcb,0xdc,0x0d,0xca,0x40,0x39,0xa8,0x00,0x7b,0x40, |
1568 | | 0x25,0x5d,0xca,0x5e,0x4a,0xe7,0xca,0xd3,0x50,0x66,0x39,0x58,0x01,0x56,0x82,0x55, |
1569 | | 0x60,0x35,0xc8,0x02,0x6b,0xc0,0x5a,0xb0,0x0e,0x64,0x83,0x1c,0xb0,0x1e,0xe4,0x81, |
1570 | | 0x7c,0x50,0x00,0x36,0x80,0x42,0x50,0x04,0x36,0x82,0x4d,0xa0,0x18,0x6c,0x06,0x5b, |
1571 | | 0xc0,0x56,0xb0,0x0d,0x6c,0x07,0x25,0x60,0x07,0x60,0xed,0xda,0x09,0x76,0x01,0xd8, |
1572 | | 0x96,0x00,0xdb,0x12,0x60,0x5b,0x02,0x6c,0x4b,0x80,0x6d,0x09,0x95,0x60,0x2f,0xd8, |
1573 | | 0x07,0xaa,0x40,0x35,0xa8,0x01,0xf5,0xa0,0x01,0x34,0x52,0xeb,0x72,0x6a,0x85,0xc5, |
1574 | | 0xf0,0x7a,0x2b,0x3a,0x08,0x67,0x9d,0x83,0xb3,0xce,0xc1,0x31,0xe7,0xd0,0xf9,0x56, |
1575 | | 0x3c,0x0b,0xb3,0xa8,0xb5,0x80,0x5a,0x0b,0xa9,0x15,0x87,0x50,0x5d,0x89,0x27,0x00, |
1576 | | 0x1e,0x95,0x50,0xbc,0x37,0x89,0x8e,0xe0,0x4c,0x19,0xb5,0xee,0xa6,0xd6,0x0a,0x6a, |
1577 | | 0xdd,0x43,0xad,0x55,0x74,0x04,0x4f,0x10,0x18,0x07,0xe7,0x1e,0x59,0x4e,0x47,0xd0, |
1578 | | 0x70,0x55,0x1c,0x48,0x00,0x49,0x20,0x05,0xa4,0x02,0xb8,0xab,0x2a,0x1d,0x64,0x02, |
1579 | | 0xb6,0x0c,0x5c,0x55,0x05,0x37,0x55,0x41,0x73,0x15,0xdc,0x53,0x05,0xd7,0x54,0xc1, |
1580 | | 0x82,0x2a,0xb8,0xa5,0x0a,0x2e,0xa9,0x82,0x3b,0xaa,0xe0,0x8a,0x2a,0xb8,0xa1,0x0a, |
1581 | | 0x2e,0xa8,0x82,0x86,0x2a,0x58,0x50,0x85,0x6e,0x57,0xa1,0xcb,0x55,0xe8,0x6e,0x15, |
1582 | | 0xba,0x5a,0x85,0x6e,0x56,0xa1,0x8b,0x55,0xb5,0x00,0x5d,0xac,0x6a,0xa4,0x73,0xd5, |
1583 | | 0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0, |
1584 | | 0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f, |
1585 | | 0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d, |
1586 | | 0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd, |
1587 | | 0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0xd5,0xd0,0x5f,0x0d,0xfd,0x35, |
1588 | | 0xd0,0x5f,0x03,0xfd,0x35,0xd0,0x5f,0x03,0xfd,0x35,0xd0,0x5f,0x03,0xfd,0x35,0xd0, |
1589 | | 0x5f,0x03,0xfd,0x35,0xd0,0x5f,0x03,0xfd,0x35,0x59,0x34,0xe6,0x48,0x03,0x35,0x43, |
1590 | | 0x25,0x6e,0xce,0x73,0x35,0x50,0x59,0x03,0x95,0x35,0x50,0x59,0x03,0x95,0x35,0x50, |
1591 | | 0x59,0x03,0x95,0x35,0x50,0x59,0x03,0x95,0x35,0x50,0x59,0x03,0x95,0x35,0x50,0x59, |
1592 | | 0x03,0x95,0x35,0x50,0x59,0x03,0x95,0x35,0x50,0x59,0x0b,0x95,0xb5,0x50,0x59,0x0b, |
1593 | | 0x95,0xb5,0x50,0x59,0x0b,0x95,0xb5,0x50,0x59,0x0b,0x95,0xb5,0x50,0x59,0x0b,0x95, |
1594 | | 0xb5,0x50,0x59,0x8b,0x2e,0xd7,0xa2,0xcb,0xb5,0xe8,0x72,0x2d,0xba,0x5c,0x8b,0x2e, |
1595 | | 0xd7,0x42,0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x2d,0xf4,0xd7, |
1596 | | 0x42,0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x2d,0xf4,0xd7,0x42, |
1597 | | 0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x2d,0xf4,0xd7,0x42,0x7f,0x1d,0x03,0x60,0x43,0x5d, |
1598 | | 0x3c,0x80,0x1d,0x75,0x89,0x00,0xb6,0xd4,0x25,0x03,0xd8,0x53,0x87,0xbb,0xa4,0x0e, |
1599 | | 0x36,0xd4,0xe1,0x2e,0xa9,0x83,0x1d,0x75,0xb8,0x4b,0xea,0x60,0x4b,0x1d,0xee,0x80, |
1600 | | 0x3a,0xe8,0xae,0xc3,0x1d,0x50,0x07,0xfd,0x75,0xb8,0x03,0xea,0x60,0x43,0x1d,0xee, |
1601 | | 0x80,0x3a,0xd8,0x51,0x87,0x11,0x5e,0x07,0xdd,0x75,0x18,0xe1,0x75,0xd0,0x5f,0x87, |
1602 | | 0x11,0x5e,0x07,0x1b,0xea,0x30,0xc2,0xeb,0x60,0x47,0x3d,0xf4,0xd6,0x43,0x6f,0x3d, |
1603 | | 0xf4,0xd6,0x43,0x6f,0x3d,0xf4,0xd6,0x43,0x6f,0x3d,0x74,0xd5,0x43,0x4f,0x3d,0x74, |
1604 | | 0xd4,0xa3,0xbf,0xf5,0xd0,0x53,0x0f,0x3d,0xf5,0xd0,0x53,0x0f,0x3d,0xf5,0xd0,0x53, |
1605 | | 0x0f,0x3d,0xf5,0xd0,0x53,0xcf,0xea,0x61,0xb0,0x4e,0x41,0x0f,0xb8,0x30,0x9e,0x0b, |
1606 | | 0x13,0xb8,0x30,0x91,0x0b,0x93,0xb8,0x30,0x99,0x0b,0x53,0xb8,0x70,0x03,0x17,0x16, |
1607 | | 0x72,0x61,0x11,0x17,0x6e,0xe4,0xc2,0x4d,0x5c,0x58,0xcc,0x85,0x9b,0xb9,0x70,0x0b, |
1608 | | 0x1b,0xd6,0x73,0xe5,0xeb,0xb9,0xf2,0xf5,0x5c,0xf9,0x7a,0xae,0x7c,0x3d,0x57,0xbe, |
1609 | | 0x9e,0x2b,0x5f,0xcf,0x95,0xaf,0xd7,0x97,0xdf,0x8d,0xf0,0x58,0x19,0x1b,0xec,0x60, |
1610 | | 0x8f,0x1b,0xf6,0x72,0x21,0xbc,0xd1,0x50,0xc6,0x9e,0xc5,0x72,0x6a,0x15,0x39,0x1f, |
1611 | | 0x8d,0x67,0x97,0x55,0x47,0xd9,0xbe,0xef,0x61,0x8b,0xee,0x63,0x83,0x9d,0x6c,0xc9, |
1612 | | 0x46,0xce,0x56,0xcc,0xde,0x38,0xc3,0x96,0xc5,0x1a,0x8d,0x0d,0xd9,0x75,0xdc,0x2a, |
1613 | | 0x94,0x3f,0x86,0xcb,0xd1,0xc8,0xc2,0xba,0x69,0x2f,0x32,0x57,0x73,0x05,0x56,0x73, |
1614 | | 0x05,0x56,0xb3,0x05,0xa0,0xa9,0x11,0x3e,0x6b,0x64,0x7d,0x86,0xd9,0xa3,0xb1,0x98, |
1615 | | 0x5b,0xc0,0x31,0xf4,0x0a,0x8e,0xeb,0xd0,0x76,0x5b,0x2a,0x1b,0x64,0x70,0xba,0x38, |
1616 | | 0xdb,0xea,0xab,0xd8,0x33,0x6c,0x75,0x3a,0xcf,0x2c,0x47,0x8c,0x85,0x26,0x53,0x8e, |
1617 | | 0x1f,0x43,0xa4,0x4f,0x55,0xe2,0xc7,0x10,0xb1,0xa9,0x91,0x23,0x51,0x30,0x89,0xd8, |
1618 | | 0x2d,0xec,0x48,0x1a,0xa9,0xb9,0x59,0x94,0x2d,0xed,0x4f,0x01,0x14,0x48,0x6a,0x0a, |
1619 | | 0xa2,0x60,0x0a,0x21,0x2f,0x3a,0xbf,0x64,0x25,0x45,0x90,0x8c,0xe4,0x34,0x67,0x2e, |
1620 | | 0x8d,0xf1,0x1b,0x07,0xe6,0xd2,0x3b,0xbb,0xc7,0xd1,0x38,0xbf,0x99,0x60,0x1e,0xd2, |
1621 | | 0x13,0x69,0xc6,0x4c,0x9a,0x3b,0x9d,0x5e,0x9b,0x30,0x8d,0x5e,0x9b,0x4e,0xe7,0x93, |
1622 | | 0x32,0xe8,0xfd,0xe5,0xf4,0xfe,0x0a,0x7a,0x7f,0x25,0xbd,0xbf,0x8a,0x26,0x8e,0x79, |
1623 | | 0x03,0xad,0xac,0xe0,0x76,0x4e,0x41,0x5c,0x18,0xc2,0x85,0x0a,0x7f,0x2e,0x52,0x91, |
1624 | | 0x92,0x0b,0xd9,0x74,0x20,0x97,0x0e,0xe4,0xb6,0x57,0x81,0x14,0xc0,0x85,0x6c,0xbe, |
1625 | | 0x9a,0x02,0xb9,0x90,0x4d,0x07,0x73,0x67,0x83,0xb9,0x9c,0x60,0x0a,0xe2,0x42,0x36, |
1626 | | 0x9f,0x26,0x4f,0xc6,0x0f,0x98,0x4f,0xf3,0x27,0xe3,0x87,0x03,0x87,0x6f,0xd0,0x1b, |
1627 | | 0x93,0xf1,0x33,0x99,0xce,0x27,0x27,0x92,0x3f,0xa7,0xea,0xfc,0x92,0x12,0xfc,0x18, |
1628 | | 0x22,0x7d,0x6a,0x27,0x7e,0x0c,0x11,0x9b,0xfa,0x94,0x59,0x02,0x52,0x89,0xb5,0x11, |
1629 | | 0x3b,0x3f,0x25,0x29,0x60,0x20,0x36,0x7f,0x30,0x07,0x56,0xa0,0x17,0xd0,0x19,0x42, |
1630 | | 0x4a,0x7f,0x92,0x29,0xe4,0x24,0x53,0x02,0x15,0x08,0x00,0x81,0x40,0x0d,0x82,0x40, |
1631 | | 0x30,0x08,0x01,0x0a,0x7f,0x36,0x60,0x4b,0x2a,0xd8,0xa2,0x0a,0xb6,0xac,0x82,0x2d, |
1632 | | 0xac,0x60,0x4b,0x2b,0xd8,0xe2,0x0a,0xb6,0xbc,0x82,0xad,0xa0,0x60,0x6b,0x28,0xd9, |
1633 | | 0x1a,0x63,0xc0,0x58,0x30,0x0e,0x8c,0x07,0x13,0xc0,0x44,0x30,0x09,0xbc,0x0a,0x26, |
1634 | | 0x83,0x29,0x60,0x2a,0x98,0x06,0xa6,0x83,0x19,0x60,0x26,0x98,0x05,0x66,0x83,0x39, |
1635 | | 0x60,0x2e,0x78,0x0d,0xcc,0x03,0xf3,0xc1,0xeb,0xe0,0x0d,0xb0,0x00,0x2c,0x94,0xdf, |
1636 | | 0x74,0x03,0xeb,0x89,0xd0,0xd0,0x08,0x8a,0x60,0x7f,0x22,0xe8,0x7c,0x49,0xde,0x7b, |
1637 | | 0x55,0x74,0x7e,0xf7,0x6e,0x50,0x06,0x30,0x92,0x76,0x63,0x78,0xed,0xde,0x03,0x30, |
1638 | | 0x9c,0x76,0xef,0x05,0xfb,0x00,0x5b,0xa6,0x1a,0xd4,0x80,0x5a,0x50,0x07,0xea,0x41, |
1639 | | 0x03,0x68,0xc4,0x6e,0x07,0xcb,0x8d,0x32,0x2c,0x37,0xca,0xb0,0xdc,0x28,0xc3,0x72, |
1640 | | 0xa3,0x0c,0xcb,0x8d,0x32,0x2c,0x37,0xca,0xb0,0xdc,0x28,0xc3,0x72,0xa3,0x0c,0xcb, |
1641 | | 0x8d,0x32,0x2c,0x37,0xca,0xb0,0xdc,0x28,0xc3,0x72,0xa3,0x0c,0xcb,0x8d,0x32,0x2c, |
1642 | | 0x37,0xca,0xb0,0xdc,0x28,0xc3,0x72,0xa3,0x0c,0xcb,0x8d,0x32,0x2c,0x37,0xca,0xb0, |
1643 | | 0xdc,0x28,0xc3,0x72,0xa3,0x0c,0x43,0xbd,0x0c,0xcb,0x8d,0x32,0x2c,0x37,0xca,0xb0, |
1644 | | 0xdc,0x28,0xc3,0x72,0xa3,0x0c,0xcb,0x8d,0x32,0x76,0x67,0x85,0xe5,0x46,0x19,0x96, |
1645 | | 0x1b,0x65,0x58,0x6e,0x94,0x61,0xb9,0x51,0x86,0xe5,0x46,0x19,0x9e,0xa8,0x98,0x53, |
1646 | | 0x2b,0xeb,0xa9,0x15,0x56,0x95,0x6d,0x05,0xdb,0xc1,0x0e,0xc0,0xee,0xca,0xf6,0xd2, |
1647 | | 0x61,0x3c,0x9b,0x61,0x63,0x39,0x6c,0x2c,0x87,0x7d,0xe5,0xb0,0xad,0x1c,0x76,0x95, |
1648 | | 0xc3,0xa6,0x72,0xd8,0x53,0x0e,0x5b,0xca,0x61,0x47,0x39,0x6c,0x28,0x87,0xfe,0x72, |
1649 | | 0xe8,0x2e,0x87,0xde,0x72,0xe8,0x2c,0x87,0xbe,0x72,0xe8,0x2a,0x87,0x9e,0x72,0x2c, |
1650 | | 0x69,0xca,0xb1,0x9c,0x29,0xc7,0x52,0xa6,0x1c,0x4b,0x99,0xf2,0x6d,0x00,0x43,0xab, |
1651 | | 0xbc,0x14,0xec,0x02,0xf0,0x61,0x39,0x34,0x96,0xc3,0x77,0xe5,0xf0,0x5b,0x39,0x7c, |
1652 | | 0x56,0x0e,0x7f,0x95,0xc3,0xaa,0x72,0xf8,0xa9,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0xfa, |
1653 | | 0x2b,0xa0,0xbf,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0xfa,0x2b, |
1654 | | 0xa0,0xbf,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0xfa,0x2b,0xa0, |
1655 | | 0xbf,0x02,0xfa,0x2b,0xa0,0xbf,0x02,0x3d,0xab,0xc0,0x58,0xae,0x80,0xae,0xca,0x42, |
1656 | | 0xea,0xde,0x95,0x4e,0xbd,0x0d,0x05,0x74,0xa1,0x8a,0x01,0x5b,0xc1,0x5e,0xd0,0x48, |
1657 | | 0x17,0xf0,0xfc,0xbd,0x80,0x67,0xe5,0x85,0x9a,0x65,0x60,0x03,0xa8,0xa1,0xae,0xc4, |
1658 | | 0x46,0xea,0x4a,0x2a,0x06,0x25,0xd4,0x95,0x1c,0x0f,0xd6,0x00,0xa4,0x53,0x36,0x80, |
1659 | | 0x4a,0xea,0x5a,0xc2,0x50,0x57,0xda,0x7a,0xea,0x5a,0x5a,0x4d,0x5d,0xcb,0xb2,0x40, |
1660 | | 0x0e,0xa8,0xa2,0xae,0xf4,0x38,0x90,0x0b,0xb6,0x51,0x57,0x06,0xea,0x65,0xec,0xa5, |
1661 | | 0xae,0xcc,0x25,0x60,0x23,0x75,0xad,0x5f,0x4b,0x5d,0xb9,0x05,0xd4,0xb5,0x11,0xed, |
1662 | | 0x6c,0xc2,0xb9,0x4d,0x69,0x00,0x75,0x37,0x6d,0xa1,0xae,0xe2,0x0a,0xea,0x2a,0x5d, |
1663 | | 0x4e,0x5d,0x3b,0xd1,0xee,0x2e,0xb4,0xb3,0x3b,0x13,0x14,0x01,0xa4,0xcb,0x76,0x82, |
1664 | | 0x32,0xea,0xda,0x07,0x7d,0xfb,0x60,0xd3,0x3e,0x36,0xdd,0x40,0x5d,0xd5,0xe5,0x00, |
1665 | | 0xb6,0xe2,0x99,0xdf,0x55,0xbb,0x07,0x20,0x0f,0x2b,0xec,0x2e,0x3c,0xe0,0xba,0xea, |
1666 | | 0xd1,0x16,0x1e,0x38,0x5d,0xf5,0x68,0xb7,0x31,0x81,0xba,0x97,0x2c,0x01,0x7b,0xa9, |
1667 | | 0x3b,0x75,0x29,0x75,0xaf,0xde,0x05,0xf6,0x50,0xf7,0x9a,0x14,0xb0,0x16,0x6c,0x02, |
1668 | | 0xd5,0xd4,0xbd,0x76,0x03,0x28,0xa6,0xee,0xf5,0xbb,0xa9,0x3b,0x17,0xe5,0x73,0xb7, |
1669 | | 0x52,0xf7,0x0e,0xe4,0x95,0x16,0x01,0x9c,0xdf,0x59,0x01,0x1f,0xa2,0xfe,0xae,0xd5, |
1670 | | 0x60,0x3d,0x75,0xc3,0xc6,0xee,0xdd,0x48,0xe3,0x3e,0xb8,0x18,0x57,0x42,0x17,0x97, |
1671 | | 0x6c,0x07,0x7b,0x41,0x2d,0x68,0xa4,0x8b,0xa9,0x29,0x20,0x1b,0xac,0xa7,0x8b,0x69, |
1672 | | 0x3b,0xe8,0x62,0x46,0x22,0x48,0xa5,0x8b,0xab,0x72,0xc1,0x66,0xba,0xb8,0x7a,0x1d, |
1673 | | 0x28,0x00,0x5b,0xc1,0x6e,0xba,0xb8,0x66,0x29,0x58,0x49,0x17,0xb3,0xd1,0x46,0x76, |
1674 | | 0x3d,0x5d,0xcc,0xd9,0x09,0xd0,0xce,0x7a,0xc4,0x05,0x68,0xa3,0xa0,0x08,0x54,0xd0, |
1675 | | 0xc5,0x4d,0x35,0x74,0x71,0x73,0x15,0x68,0xa0,0x8b,0xdb,0xa0,0xbb,0x04,0xf5,0x4a, |
1676 | | 0xaa,0xe9,0x22,0x46,0xf1,0xc5,0x0a,0xe4,0xe3,0xe1,0x7c,0x11,0x0f,0xe0,0x8b,0x0d, |
1677 | | 0x69,0xa0,0x9e,0x7a,0x98,0x38,0xb0,0x0c,0xac,0x04,0x15,0xd4,0x13,0xd7,0x48,0x3d, |
1678 | | 0xf1,0xa9,0xd4,0x93,0xb2,0x11,0x6c,0x07,0xc8,0x4b,0xa9,0xa3,0x9e,0x25,0x28,0xb3, |
1679 | | 0x64,0x3d,0x28,0xa0,0x9e,0xd4,0x9d,0xa0,0x1c,0x54,0x51,0x4f,0x76,0x3a,0x28,0xa1, |
1680 | | 0x9e,0x42,0x06,0xa0,0x4c,0x21,0xea,0x15,0x37,0x50,0xcf,0xe6,0xa5,0xd4,0xb3,0x05, |
1681 | | 0x6d,0x6e,0x45,0x3e,0xee,0xff,0x1e,0xdc,0xc7,0x3d,0xb8,0x1f,0x7b,0xca,0x50,0x07, |
1682 | | 0xf7,0x42,0x4f,0xe5,0x26,0xb0,0x9b,0x7a,0xf6,0xa2,0x7d,0x2c,0xa6,0x7a,0x6a,0xd3, |
1683 | | 0xa8,0xa7,0x01,0xed,0xe3,0x31,0xda,0x83,0xed,0x47,0x6f,0xfc,0x0a,0xea,0x4d,0x4a, |
1684 | | 0xa5,0xde,0x94,0x64,0xb0,0x0c,0xe0,0x38,0x6b,0x1f,0xf5,0xae,0x61,0xa8,0x77,0x5d, |
1685 | | 0x2e,0xf5,0xe6,0xec,0x05,0xd5,0xd4,0xbb,0x7e,0x2b,0xf5,0xe6,0xe1,0x5c,0x5e,0x3e, |
1686 | | 0x28,0x02,0xdb,0xa8,0xb7,0x60,0x29,0x28,0x05,0x15,0xd4,0xbb,0x21,0x8e,0x7a,0x8b, |
1687 | | 0x50,0x66,0xe3,0x7a,0x50,0x40,0xbd,0x9b,0xd7,0x80,0x6c,0xb0,0x83,0x7a,0xb7,0x23, |
1688 | | 0xbf,0x64,0x1d,0x40,0xfe,0x8e,0x62,0xb0,0x0b,0x94,0x83,0x3a,0xea,0x2d,0xcd,0xa1, |
1689 | | 0xde,0x0a,0xe4,0x61,0x1d,0xd9,0x8b,0x31,0xd4,0x8b,0xc5,0x5f,0x2f,0x16,0x75,0xbd, |
1690 | | 0x58,0xc8,0xf5,0x62,0xe1,0xd6,0x8b,0x45,0x5b,0x2f,0x16,0x5a,0xbd,0x58,0x64,0xf5, |
1691 | | 0xd6,0x65,0x80,0x55,0x60,0x03,0x40,0x99,0xfa,0x34,0xb0,0x12,0xf7,0x13,0x7b,0x4f, |
1692 | | 0xc1,0xd6,0x86,0x0d,0xe4,0x8b,0xe7,0xc4,0x4a,0x8c,0xfc,0x44,0x90,0x44,0xce,0x9f, |
1693 | | 0xc6,0x67,0xb3,0x41,0x0e,0x7d,0x1a,0xbf,0xe4,0xd3,0xf8,0x34,0x44,0x15,0x9f,0x26, |
1694 | | 0x2c,0xa1,0x73,0x89,0x58,0x32,0x25,0x62,0xc9,0x94,0x8c,0x95,0x7d,0x22,0x96,0x0e, |
1695 | | 0xc9,0xd8,0x54,0x24,0x63,0x99,0x97,0x88,0xe5,0x53,0x22,0x96,0x4f,0x89,0x58,0x3e, |
1696 | | 0x25,0xe3,0xf1,0x9f,0x8c,0x85,0x46,0x32,0x16,0x10,0xc9,0x58,0x76,0x25,0x63,0xd9, |
1697 | | 0x95,0x8c,0x65,0x57,0x22,0x36,0x31,0x89,0x58,0xd2,0x25,0x62,0x49,0x97,0xc8,0xb6, |
1698 | | 0x85,0xe5,0x41,0x22,0x96,0x9a,0x89,0xd8,0x08,0x25,0x62,0xb9,0x99,0xb8,0x0c,0x60, |
1699 | | 0xc9,0x99,0x98,0x01,0xb0,0xec,0x4c,0xc4,0x1a,0x23,0x11,0x6b,0x8c,0x44,0x2c,0xfb, |
1700 | | 0x92,0x50,0x36,0x09,0xcb,0xaf,0x24,0x2c,0xbf,0x92,0xb0,0xfc,0xc2,0xdd,0x7d,0x2e, |
1701 | | 0x09,0xcb,0xaf,0x24,0x2c,0xbf,0x92,0xb0,0xd1,0x49,0xc2,0x92,0x33,0x09,0x36,0xe1, |
1702 | | 0x8e,0x3f,0x97,0x04,0x9b,0x92,0x60,0x53,0x12,0x36,0x3a,0x49,0x58,0x7e,0x26,0xc1, |
1703 | | 0x9e,0x24,0xd8,0x93,0x04,0x7b,0x92,0x60,0x4f,0x12,0xec,0x49,0x62,0xed,0xc1,0x32, |
1704 | | 0x32,0x11,0x4b,0xbc,0x14,0xd8,0x93,0x02,0x7b,0x70,0x15,0xcf,0xa5,0x40,0x77,0x0a, |
1705 | | 0x96,0x7e,0x29,0x58,0xf6,0xa5,0x60,0x99,0x9b,0x88,0x3d,0x4e,0x0a,0x96,0xb9,0x29, |
1706 | | 0x58,0xe6,0x26,0x22,0x4e,0xc4,0xe6,0x2b,0x11,0x4b,0x9b,0x44,0xd8,0x92,0x08,0x5b, |
1707 | | 0x12,0xa1,0x3f,0x11,0xba,0x13,0xa1,0x37,0x11,0x7a,0x13,0x59,0x5f,0x40,0x6f,0x22, |
1708 | | 0xf4,0x26,0x42,0x5f,0x22,0x96,0x9a,0x49,0xf0,0x59,0x12,0x74,0x24,0xb1,0xed,0xc3, |
1709 | | 0x8e,0x14,0xd6,0x0e,0xb4,0x9f,0x84,0xcd,0x5d,0x12,0x74,0xe0,0x79,0x7e,0x2e,0x99, |
1710 | | 0xf5,0x1b,0x6c,0x48,0x46,0x7f,0x93,0xd1,0xdf,0x64,0xd8,0x96,0x0c,0x5d,0xc9,0x85, |
1711 | | 0x98,0xe5,0x52,0x31,0xfb,0xac,0x47,0x9c,0x06,0x4a,0x01,0xee,0x98,0xd5,0xe5,0x88, |
1712 | | 0x31,0xf3,0x61,0xb7,0xd4,0xb5,0x09,0xb3,0x55,0xee,0x6e,0x92,0xe1,0xe2,0xc8,0xd9, |
1713 | | 0x30,0x9e,0x0b,0x13,0xb8,0x30,0x89,0x0b,0x93,0xb9,0x30,0x85,0x0b,0x53,0xb9,0x70, |
1714 | | 0x29,0x17,0x2e,0xe3,0xc2,0x0c,0x2e,0xcc,0xe4,0xc2,0xe5,0x5c,0xb8,0x82,0x0b,0x57, |
1715 | | 0x22,0xbc,0xb4,0x9b,0x6d,0xf3,0xb3,0xf8,0x75,0x6c,0xb8,0x74,0x13,0x1b,0xe6,0xd5, |
1716 | | 0xb1,0xe1,0x96,0x25,0x6c,0xb8,0x7b,0x35,0xc2,0xcf,0xe3,0x77,0xb0,0x61,0x56,0x22, |
1717 | | 0x1b,0xe6,0xb3,0x2d,0x7c,0xbe,0x7b,0x2b,0x1b,0x56,0xef,0x41,0x78,0x39,0x81,0x6d, |
1718 | | 0xe1,0xf2,0x32,0x56,0xd7,0xe5,0x2c,0xb6,0x9d,0xcf,0x37,0xb2,0x2d,0x7c,0xbe,0x6e, |
1719 | | 0xd3,0xe7,0x1b,0x12,0xf5,0x89,0xcb,0xeb,0xd9,0x04,0xa6,0x76,0x36,0xac,0x59,0xc6, |
1720 | | 0xa5,0x59,0x3b,0xd1,0x6d,0x2e,0x87,0xd5,0xd2,0x95,0x54,0xca,0xe5,0x27,0x70,0xe9, |
1721 | | 0x12,0x36,0x5d,0x9d,0xc7,0xa6,0xd3,0xe3,0x10,0x62,0xca,0x43,0x88,0x89,0x8c,0x4d, |
1722 | | 0xef,0xde,0xc3,0xe5,0xb0,0x36,0xe0,0xb6,0x64,0xcb,0xe4,0x16,0xb0,0x39,0x6b,0x8b, |
1723 | | 0xd9,0x70,0xc3,0x76,0xee,0x2c,0xdb,0xfe,0xc5,0x4d,0x0d,0xec,0xd9,0xe5,0xe9,0x6c, |
1724 | | 0x3a,0xb5,0x1a,0x61,0x4f,0x79,0x21,0x9b,0x2e,0xe6,0x5a,0x4e,0x63,0xdb,0xb9,0x50, |
1725 | | 0xbb,0x91,0x4d,0xaf,0x60,0x6d,0xee,0x2a,0xdd,0xcc,0x9e,0x5d,0xcf,0xe6,0x5c,0xa8, |
1726 | | 0x63,0xf5,0xf6,0x54,0xa4,0x70,0x36,0xac,0xe6,0x6a,0x71,0x16,0xd6,0xb1,0x1a,0x31, |
1727 | | 0x35,0x71,0x61,0x85,0x9c,0xba,0xb2,0xf0,0x34,0xa8,0xae,0xa3,0x8b,0x3b,0x33,0x69, |
1728 | | 0xd6,0x6b,0x13,0x48,0xa9,0x20,0xa5,0x92,0x94,0x58,0x2f,0x06,0x90,0x12,0x2b,0x45, |
1729 | | 0x35,0x29,0x83,0x48,0x19,0x4c,0xca,0x10,0x52,0xf9,0x93,0x4a,0x41,0x2a,0x25,0xa9, |
1730 | | 0x54,0xa4,0x0a,0x20,0x55,0x20,0xc1,0xff,0x04,0xef,0x13,0x7c,0x4f,0xf0,0x3c,0xc1, |
1731 | | 0xef,0x04,0xaf,0x13,0x7c,0x4e,0xf0,0x38,0xc1,0xdf,0x04,0x6f,0x13,0x7c,0x4d,0xf0, |
1732 | | 0x34,0xc1,0xcf,0x04,0x2f,0x23,0xaf,0xea,0x52,0xc5,0x06,0x82,0xab,0x3f,0xcf,0xc3, |
1733 | | 0x51,0xce,0x6e,0x3c,0x18,0x57,0xe3,0x81,0xc8,0x0e,0x9f,0x04,0x3c,0x34,0xf3,0x08, |
1734 | | 0x7e,0xc0,0x43,0x02,0x13,0xfa,0x26,0x3c,0x78,0x96,0xa7,0x63,0xa2,0xaf,0xc6,0xc4, |
1735 | | 0x57,0x48,0xe8,0x3b,0x1e,0x8e,0x98,0x98,0xb7,0xb0,0x13,0x3c,0x26,0xb4,0x38,0x0c, |
1736 | | 0xaf,0xc4,0xed,0x98,0x16,0xf0,0x60,0xa9,0xc0,0x84,0xb4,0x01,0x0f,0x5b,0xec,0xc6, |
1737 | | 0xba,0x92,0xb3,0xf1,0x60,0xc1,0x83,0x71,0xdf,0x66,0x3c,0x20,0xf1,0xa0,0x5a,0x56, |
1738 | | 0x8b,0x07,0x20,0x1e,0x92,0xa5,0x78,0x38,0xac,0xdf,0x88,0x32,0x98,0xb8,0xb1,0x00, |
1739 | | 0x80,0x6f,0x30,0x44,0x73,0x49,0xa5,0x26,0x55,0x10,0xa9,0xb0,0xec,0x0d,0xa1,0x00, |
1740 | | 0xac,0xce,0x15,0x14,0xa0,0xa4,0x00,0x15,0x05,0x04,0x50,0x00,0xd6,0xc8,0x6a,0x0a, |
1741 | | 0x08,0xa2,0x80,0x60,0x0a,0x08,0xa1,0x40,0x2c,0x56,0xd9,0x47,0x98,0x92,0x0d,0x54, |
1742 | | 0x6c,0x10,0xc0,0x06,0x81,0x6c,0xa0,0x66,0x83,0x20,0x36,0x08,0x66,0x83,0x10,0x36, |
1743 | | 0x50,0xf8,0x73,0x21,0x57,0x47,0xc1,0x55,0x7a,0x75,0x12,0x4d,0x98,0x03,0xe6,0xd3, |
1744 | | 0xb4,0xd7,0xc6,0x63,0xee,0x2a,0x02,0x9b,0xc0,0x66,0xb0,0x15,0x6c,0x07,0x25,0xa0, |
1745 | | 0x14,0xec,0x02,0x65,0xec,0xfc,0x06,0x2a,0xc1,0x3e,0x50,0x0d,0x6a,0x41,0x3d,0x68, |
1746 | | 0xa4,0x4f,0x13,0xe2,0x40,0x22,0x48,0x26,0x76,0x12,0xfc,0x34,0x01,0xf3,0x61,0xc2, |
1747 | | 0x52,0xb0,0x0c,0xa4,0x83,0x0c,0x90,0x09,0x56,0x82,0x2c,0xb0,0x0e,0xac,0x07,0xf9, |
1748 | | 0xa0,0x00,0x6c,0x00,0x85,0x00,0x76,0x24,0xc0,0x8e,0x04,0xd8,0x91,0x00,0x3b,0x12, |
1749 | | 0xb6,0x01,0xd8,0x92,0x00,0x5b,0x12,0x76,0x00,0xd8,0x93,0x00,0x7b,0x12,0x76,0x03, |
1750 | | 0xd8,0x94,0x80,0x9b,0xbc,0x76,0x53,0xd7,0xca,0x65,0x6c,0x17,0x3e,0x4d,0x58,0xf1, |
1751 | | 0x69,0x42,0x1d,0xa7,0x9f,0x3d,0x28,0x81,0xa6,0x4f,0xe3,0x0b,0xf5,0x07,0x98,0x9b, |
1752 | | 0x73,0xf4,0xbd,0x2c,0xe2,0xca,0xb0,0x7d,0xdb,0x04,0x13,0xd9,0x33,0xf1,0xbb,0xf5, |
1753 | | 0x07,0x15,0x5c,0x37,0xe2,0x37,0x7f,0x1a,0xbf,0x0d,0x07,0xac,0x23,0xd0,0x4f,0x74, |
1754 | | 0x9f,0xab,0x90,0xca,0x1d,0x23,0x15,0x8f,0x76,0xeb,0x58,0x0f,0x71,0x55,0xab,0xf5, |
1755 | | 0xa9,0x3a,0xae,0x07,0x38,0xc5,0xb6,0xc3,0xf9,0x0e,0xa6,0x7f,0x9a,0x90,0xa0,0x37, |
1756 | | 0x06,0x07,0xa5,0xc8,0xd6,0xd7,0xdb,0xc1,0x1d,0x54,0xe8,0x53,0x15,0x9c,0x07,0xe2, |
1757 | | 0x77,0xe2,0x80,0x8b,0x58,0x83,0xd8,0x42,0x28,0x51,0x3c,0x50,0x63,0x27,0xd7,0x17, |
1758 | | 0x66,0xe0,0x4c,0xa9,0x21,0x82,0xe1,0x9c,0x96,0x0d,0xfd,0xc7,0x09,0x85,0xfa,0xfe, |
1759 | | 0xeb,0xbb,0xa7,0xcf,0xda,0x35,0x60,0xc5,0xcd,0xc2,0x86,0x14,0x57,0x92,0x35,0x64, |
1760 | | 0x17,0xab,0x20,0xbe,0x8e,0x33,0xbe,0x54,0x7f,0x5c,0xca,0xb5,0x94,0xce,0x5e,0x79, |
1761 | | 0xae,0xd3,0xd5,0xfa,0xe7,0x5b,0x09,0x77,0x65,0xd9,0x14,0xce,0xe6,0xb1,0xe3,0x81, |
1762 | | 0xad,0xc4,0x35,0xc0,0x1d,0x70,0x3e,0x1c,0x70,0xc7,0x3e,0xae,0x0b,0x06,0x07,0xd7, |
1763 | | 0x0e,0x38,0x58,0x9f,0x62,0x47,0x09,0xd3,0xdf,0x76,0x42,0x0a,0x37,0xac,0x12,0x52, |
1764 | | 0xf5,0x57,0x5a,0x6f,0x57,0x42,0x9a,0x7e,0xdc,0x64,0xf4,0x77,0x21,0x21,0x93,0x33, |
1765 | | 0x91,0x1d,0x67,0xdc,0x95,0xbe,0xa5,0x25,0xfd,0x95,0x67,0xcf,0x2c,0xe7,0x52,0x3b, |
1766 | | 0xf4,0x0d,0xad,0x66,0xaf,0x37,0x2e,0xa2,0xc1,0x27,0xec,0xf1,0xae,0x81,0x14,0xab, |
1767 | | 0x62,0x95,0xfe,0x88,0x1d,0x28,0xfd,0x57,0x2c,0x55,0x7f,0xbc,0xb1,0x7f,0x2c,0x25, |
1768 | | 0xac,0x61,0xb3,0xd1,0x99,0xf8,0x2d,0xfd,0x85,0x13,0xf4,0x03,0x24,0x61,0x1d,0xdb, |
1769 | | 0x5c,0x7c,0x63,0xff,0x88,0x62,0x87,0x58,0x3d,0x17,0xb1,0xd7,0x71,0x25,0x57,0x80, |
1770 | | 0x75,0x59,0xa2,0x3e,0x4f,0x3f,0x5c,0xd8,0x14,0x4c,0xaf,0x42,0x2a,0x9b,0x4b,0xb1, |
1771 | | 0xb7,0x4f,0x5e,0xff,0x00,0x64,0xf5,0xe5,0x72,0x95,0xd8,0xd4,0x7a,0xbd,0x9a,0x3c, |
1772 | | 0xee,0x54,0xaa,0x3e,0xc3,0xa0,0x4a,0x9f,0x62,0xcf,0xe6,0xf7,0x5f,0x82,0xd2,0xfe, |
1773 | | 0x03,0xae,0x40,0x3e,0xd7,0x99,0x4c,0x7d,0xaa,0x84,0xbb,0x8b,0xd9,0x54,0x05,0x77, |
1774 | | 0x59,0xb6,0xe8,0xab,0x16,0xf4,0x5f,0x6b,0xfd,0x01,0x77,0xa7,0x15,0x70,0x17,0x6d, |
1775 | | 0xf9,0x80,0xa2,0x42,0x6e,0x6c,0x72,0xd1,0xc0,0x85,0xb9,0x75,0x9c,0x25,0x6c,0xea, |
1776 | | 0xbf,0x3f,0x0c,0x29,0x36,0x6f,0xb3,0xfe,0xa6,0x23,0xae,0xad,0x84,0x81,0xa2,0xdb, |
1777 | | 0xf5,0x37,0x74,0x09,0xeb,0x7e,0x76,0x34,0xb3,0xa9,0x3a,0xce,0xc1,0xdc,0xfd,0xad, |
1778 | | 0x9f,0x06,0xf4,0xb7,0x05,0xd6,0x54,0xe5,0xfa,0x16,0xfa,0x47,0xb0,0xff,0x45,0xb8, |
1779 | | 0x4f,0xc1,0x06,0x4a,0x36,0x50,0xb1,0x41,0x00,0x1b,0x04,0xb2,0x81,0x9a,0x0d,0x82, |
1780 | | 0xd8,0x20,0x98,0x0d,0x42,0xb8,0xc2,0xfa,0x2a,0x5c,0x1d,0x05,0x57,0x49,0xc1,0xd5, |
1781 | | 0x52,0x70,0xd5,0x14,0x5c,0x3d,0x05,0x57,0x51,0xc1,0xd5,0x54,0x70,0x55,0x15,0x5c, |
1782 | | 0x5d,0x25,0x57,0x57,0xa9,0xd7,0xc7,0xd5,0x55,0x72,0x75,0x95,0x5c,0xdd,0x57,0x67, |
1783 | | 0x8d,0xa1,0xf1,0x63,0x68,0xcc,0x3c,0x1a,0x3b,0x66,0x0e,0xcd,0x9c,0x4f,0xb3,0xc6, |
1784 | | 0xd1,0xf8,0xe9,0xf8,0x51,0x02,0x15,0x4d,0x9e,0x87,0xe7,0x59,0x45,0xf7,0x92,0xe5, |
1785 | | 0xd4,0xbd,0xae,0x94,0x9d,0x9d,0xb0,0x07,0x62,0x9f,0x04,0xdd,0xeb,0x32,0xba,0xb1, |
1786 | | 0x13,0xc4,0x83,0xa5,0xab,0x2e,0xf3,0x42,0x5d,0x0e,0xfb,0x64,0x41,0x4b,0x33,0xc6, |
1787 | | 0xd0,0xb1,0xba,0x31,0x34,0x7d,0x0c,0x4d,0xc5,0xcf,0x58,0x9a,0x3e,0x96,0x26,0x8d, |
1788 | | 0xa5,0x71,0x63,0xa6,0xd1,0x54,0x36,0x98,0x35,0x91,0x66,0x4c,0x44,0x09,0x96,0x49, |
1789 | | 0x34,0x7d,0x12,0x4d,0x9d,0x44,0xaf,0x2e,0xa4,0xa9,0x60,0x3a,0x98,0x04,0x5e,0x03, |
1790 | | 0xc7,0xea,0xa6,0xd1,0xf4,0x69,0x34,0x1e,0xb5,0xa6,0xd1,0xc4,0xe9,0x34,0x63,0x3a, |
1791 | | 0xb2,0xa6,0xd3,0xf4,0xe9,0x34,0x6e,0x3a,0x4d,0x65,0x13,0x4a,0xa4,0x94,0x84,0x9f, |
1792 | | 0xa9,0x6c,0x04,0x3b,0xc7,0x01,0xfc,0x4c,0x65,0xa3,0xf3,0x4b,0xb2,0xe6,0xea,0x43, |
1793 | | 0x9c,0x87,0x51,0xd3,0xc1,0x24,0x30,0x67,0xcc,0x78,0x16,0xee,0xb4,0x21,0x56,0xd2, |
1794 | | 0xac,0xb9,0x34,0x63,0x2e,0x9a,0x47,0x8d,0xb9,0x34,0x6b,0x3e,0xcd,0x98,0x8f,0x83, |
1795 | | 0xf9,0x34,0x7d,0x3e,0x4d,0x85,0x2f,0x5e,0xa7,0x19,0xaf,0xe3,0xf8,0x75,0x9a,0xfe, |
1796 | | 0x3a,0x4d,0xc5,0x4f,0x5b,0x2a,0x4d,0x07,0x63,0x67,0xd3,0xb8,0x71,0x34,0x6e,0x3c, |
1797 | | 0x8d,0x43,0x23,0xe8,0xc3,0x78,0x74,0x73,0x01,0xbd,0x3a,0x06,0xde,0xa4,0xc9,0x33, |
1798 | | 0x68,0xea,0x54,0x9a,0xfa,0x1a,0x4d,0x9b,0x4e,0xd3,0x66,0xd0,0xb4,0x99,0x93,0x68, |
1799 | | 0xda,0x1b,0x34,0x7d,0x32,0xba,0x34,0x13,0x1e,0x78,0x95,0x66,0xcd,0x9a,0x4e,0xb3, |
1800 | | 0xe6,0xd0,0x5c,0xfc,0xcc,0xa7,0xd7,0xc7,0xd2,0x7c,0xb4,0x31,0x9d,0xc6,0x70,0xa1, |
1801 | | 0x82,0xdd,0xd6,0x29,0xd9,0x40,0xc5,0x06,0x01,0x6c,0x10,0xc8,0x06,0x6a,0x36,0x08, |
1802 | | 0x62,0x83,0x60,0x36,0x08,0x61,0x03,0x3c,0x0b,0xd9,0x90,0xab,0xa3,0xe0,0x2a,0x29, |
1803 | | 0xb8,0x5a,0x0a,0xae,0x9a,0x82,0xab,0xa7,0xe0,0x2a,0x2a,0xb8,0x9a,0x0a,0xae,0xaa, |
1804 | | 0x82,0xab,0xab,0xe4,0xea,0x2a,0xf5,0xfa,0xb8,0xba,0x4a,0xae,0xae,0x92,0xab,0xab, |
1805 | | 0xe4,0xea,0x2a,0xb9,0xba,0x4a,0xae,0xae,0x92,0xab,0xab,0xe4,0xea,0xaa,0xb8,0xba, |
1806 | | 0x2a,0xae,0xee,0x24,0x5c,0xd5,0x4b,0xd9,0x71,0x20,0x01,0x24,0x81,0x14,0x90,0x0a, |
1807 | | 0xd2,0x41,0x26,0x58,0x01,0x56,0x81,0x2c,0xb0,0x16,0x64,0x83,0xf5,0x20,0x0f,0x14, |
1808 | | 0x80,0x42,0xb0,0x11,0x14,0x83,0x2d,0x60,0x1b,0x28,0x01,0xa5,0x74,0x29,0x07,0xed, |
1809 | | 0xe6,0xa0,0xdd,0x1c,0xb4,0x9b,0x83,0x76,0x73,0xd0,0x6e,0xce,0x52,0x80,0xb6,0x73, |
1810 | | 0xd0,0x76,0x0e,0xda,0xce,0x41,0xdb,0x39,0x68,0x3b,0x07,0x6d,0xe7,0xa0,0xed,0x1c, |
1811 | | 0xb4,0x9d,0x8b,0xf6,0x72,0xd1,0x5e,0x2e,0xda,0xcb,0x45,0x7b,0xb9,0x68,0x2f,0x17, |
1812 | | 0xed,0xe5,0xee,0x02,0x15,0xa0,0x12,0xec,0x03,0xd5,0xa0,0x16,0xd4,0x83,0x46,0xba, |
1813 | | 0x94,0x07,0x7d,0x79,0xd0,0x97,0x07,0x7d,0x79,0xd0,0x97,0x07,0x7d,0x79,0xd0,0x97, |
1814 | | 0x07,0x7d,0x79,0xd0,0x87,0xad,0xdd,0xa5,0x3c,0xe8,0xcb,0x83,0xbe,0x3c,0xe8,0xcb, |
1815 | | 0x83,0xbe,0x3c,0xe8,0xcb,0x43,0x5f,0xf2,0xd0,0x97,0x3c,0xf4,0x25,0x0f,0xba,0xf3, |
1816 | | 0xa0,0x3b,0x0f,0xba,0xb1,0xfd,0xbb,0x94,0x07,0xdd,0x79,0xd0,0x9d,0x07,0xdd,0x79, |
1817 | | 0x35,0xa0,0x8e,0xce,0x55,0x42,0x6f,0x1e,0xf4,0xe5,0x43,0x5f,0x3e,0xf4,0xe5,0x43, |
1818 | | 0x5f,0x3e,0xf4,0xe5,0x2f,0x03,0xd0,0x91,0x0f,0x1d,0xf9,0x68,0x3f,0x1f,0xed,0xe7, |
1819 | | 0xa3,0xfd,0x7c,0xb4,0x9f,0x8f,0xf6,0xf3,0xd1,0x7e,0x3e,0xda,0xcf,0x47,0xfb,0xf9, |
1820 | | 0x68,0x3f,0x7f,0x1b,0xb5,0xee,0xa0,0x23,0xf9,0x74,0x04,0x95,0x4b,0xd9,0x4a,0xe8, |
1821 | | 0x58,0x3e,0x3a,0x96,0x0f,0x05,0xf9,0xe8,0x58,0x3e,0x3a,0x96,0x0f,0x45,0x05,0x50, |
1822 | | 0x54,0xc0,0x2a,0xc2,0x4e,0x63,0x6f,0x06,0xd2,0x4b,0x40,0x1a,0xb5,0x6e,0x42,0x84, |
1823 | | 0xbe,0x15,0xa0,0x6f,0x05,0xd0,0x5b,0x80,0x26,0x0a,0xd0,0xb7,0x02,0xe8,0x2e,0x80, |
1824 | | 0x6e,0x6c,0xe5,0x0f,0xae,0xa7,0xd6,0x7d,0xd4,0x5a,0x87,0x83,0xbd,0x74,0x69,0x07, |
1825 | | 0xda,0x2e,0x5d,0x49,0x47,0x50,0xa7,0x14,0x7e,0x29,0xc5,0x26,0x27,0x03,0x1b,0xa4, |
1826 | | 0x0c,0x6c,0xd8,0x32,0xb0,0x49,0xca,0xc0,0x26,0x29,0x03,0x1b,0xb6,0x0c,0x6c,0xd8, |
1827 | | 0x32,0xb0,0x61,0xcb,0xc0,0x86,0x29,0x03,0x1b,0xb6,0x0c,0x6c,0x9a,0x32,0xb0,0x61, |
1828 | | 0xcb,0xc0,0xc6,0x29,0x03,0x1b,0xa7,0x0c,0x6c,0x9c,0x32,0xb0,0x71,0xca,0xc0,0xc6, |
1829 | | 0x29,0x03,0x1b,0xb6,0x0c,0x6c,0x94,0x32,0xb0,0x51,0xca,0xc0,0x86,0x2d,0x03,0x1b, |
1830 | | 0xb6,0x0c,0x6c,0xd8,0x32,0xb0,0x99,0xca,0xd8,0x07,0xaa,0x40,0x35,0xa8,0x01,0xb5, |
1831 | | 0x00,0xfe,0xcb,0xa8,0x07,0x0d,0xa0,0x91,0xce,0x65,0x62,0xc3,0x95,0x89,0x4d,0x6a, |
1832 | | 0x26,0x36,0xa8,0x99,0xd8,0x98,0x66,0x62,0x83,0x95,0x89,0x0d,0x56,0x26,0x36,0x9f, |
1833 | | 0x99,0xd8,0x88,0x65,0x62,0xa3,0x95,0x89,0x8d,0x67,0x26,0x36,0x9e,0x99,0xd8,0x78, |
1834 | | 0x66,0xc2,0xe6,0x4c,0x6c,0x3c,0x33,0xb1,0xf9,0xcb,0xc4,0xc6,0x33,0x13,0x1b,0xcf, |
1835 | | 0x4c,0x6c,0xc4,0x32,0xb1,0x11,0xcb,0xc4,0x66,0x30,0x13,0x2e,0xca,0xc4,0x46,0x31, |
1836 | | 0x73,0x0d,0xc0,0xc6,0x2d,0x13,0x1b,0xb7,0x4c,0x6c,0xdc,0x32,0xb1,0xa1,0xcd,0x5c, |
1837 | | 0x0f,0xd8,0x6f,0xfa,0xb0,0x39,0xcc,0xc4,0x86,0x2d,0x13,0x1b,0xc5,0x4c,0xf4,0x3f, |
1838 | | 0x13,0xfd,0xcf,0x44,0xff,0x33,0xd1,0xff,0x4c,0xf4,0x3f,0x13,0xfd,0xcf,0x44,0xff, |
1839 | | 0x33,0xd1,0xff,0x4c,0xf4,0x3f,0x13,0xfd,0xcf,0x44,0xff,0x33,0xd1,0xff,0x4c,0xf4, |
1840 | | 0x3f,0x13,0xfd,0xcf,0x44,0xff,0x33,0x77,0x51,0x4f,0xd9,0x12,0xea,0x5e,0xbf,0x07, |
1841 | | 0xab,0x67,0xc4,0xd8,0xc6,0x5f,0xa8,0x2a,0xc7,0x0a,0xbb,0x98,0xba,0x8a,0xb1,0xea, |
1842 | | 0x5e,0x83,0x15,0x75,0x31,0xf2,0x53,0xd8,0xd7,0x2c,0xdb,0xe8,0x62,0x43,0x12,0xf5, |
1843 | | 0xac,0x6b,0xa4,0x9e,0xfc,0x1a,0xea,0xd9,0x58,0x45,0xbd,0xf1,0x99,0xd4,0xbd,0x35, |
1844 | | 0x9e,0xba,0xf7,0xac,0xa7,0x8b,0x09,0xd9,0x74,0x11,0x36,0xf5,0x2c,0xaf,0xa7,0x5e, |
1845 | | 0x6c,0x8e,0x7b,0xb7,0x94,0x61,0x17,0x10,0x8f,0x15,0x79,0x25,0x75,0xef,0x48,0xa4, |
1846 | | 0x8b,0xec,0xeb,0x92,0x75,0xa5,0xd4,0x5b,0x95,0x4f,0x5d,0x95,0x98,0xcd,0x1b,0x4b, |
1847 | | 0xa8,0x67,0x6d,0x3a,0xf5,0x14,0x6f,0xa2,0xee,0xa5,0xec,0x2b,0x96,0x75,0xd4,0xb3, |
1848 | | 0xa1,0x80,0xba,0x6a,0xd3,0xb0,0x53,0x58,0x4b,0xdd,0x95,0xdb,0xe9,0xe2,0xd2,0x3a, |
1849 | | 0xea,0xc5,0xba,0xe5,0x42,0x43,0x32,0x76,0x00,0xfb,0xa8,0x6b,0x69,0x3e,0x75,0xaf, |
1850 | | 0x4a,0xa4,0xee,0x92,0x55,0x68,0x6f,0x39,0x56,0xfe,0x5b,0xd0,0x66,0x32,0xf5,0x64, |
1851 | | 0xe7,0x52,0xcf,0xbe,0x5d,0xd4,0x9b,0x5b,0x4e,0xbd,0xa5,0x88,0xf7,0xd5,0xd0,0xc5, |
1852 | | 0xa2,0x65,0xd8,0x5d,0x34,0xd2,0xc5,0xbd,0x1b,0xa8,0x07,0xfe,0xef,0x5d,0x96,0x48, |
1853 | | 0x3d,0x25,0x6b,0xa8,0x6b,0x23,0x74,0xd4,0xc1,0x9e,0x32,0xe4,0xc7,0x35,0x60,0x27, |
1854 | | 0x52,0x44,0x17,0x37,0xa6,0xa1,0xff,0xf1,0xd4,0xbb,0x1e,0x3a,0x36,0xae,0xa3,0xae, |
1855 | | 0xb2,0x22,0xf4,0x6b,0x15,0x75,0xef,0xcb,0xa1,0xee,0xba,0x4c,0xba,0xb8,0x67,0x17, |
1856 | | 0x5d,0xac,0xc2,0xee,0x24,0x7b,0x29,0x6c,0x58,0x49,0x3d,0xf1,0x88,0x53,0x72,0x01, |
1857 | | 0x74,0x6c,0xcd,0x85,0x8e,0x06,0xe8,0x28,0xc3,0xf9,0x4a,0xea,0xd9,0xc9,0xa0,0x3f, |
1858 | | 0x99,0xd0,0xd5,0x00,0x5f,0x56,0x53,0xd7,0xae,0x2d,0xd4,0xcd,0xac,0xa4,0x8b,0x19, |
1859 | | 0x29,0x74,0x31,0x6b,0x37,0x76,0x2e,0x6b,0xa1,0xaf,0x16,0x7d,0x6a,0xa4,0xae,0x86, |
1860 | | 0x6d,0x28,0x93,0x8e,0x9d,0xce,0x32,0xea,0xce,0xaa,0x82,0x9e,0x22,0xf8,0x3e,0x81, |
1861 | | 0xba,0x0a,0xf3,0xe9,0x62,0x2e,0x76,0x34,0x2b,0xe0,0x97,0xed,0xd8,0x39,0xed,0xac, |
1862 | | 0xa1,0xee,0x72,0x5c,0x87,0xa5,0xd0,0xb3,0xb4,0x98,0xba,0x31,0xe6,0x2f,0x66,0x15, |
1863 | | 0xc3,0xbf,0x3b,0xb1,0xcb,0xc2,0x8e,0x29,0x25,0x95,0xba,0x8b,0xe2,0xe8,0x62,0x05, |
1864 | | 0xfc,0x91,0x8a,0x6b,0x5a,0xb2,0x92,0x7a,0x53,0xb0,0x11,0x5c,0x5a,0x49,0x5d,0x2b, |
1865 | | 0x70,0x0d,0x6a,0x77,0x50,0xf7,0xda,0x24,0xf8,0x1c,0xfd,0xdd,0x84,0x6b,0xb3,0x06, |
1866 | | 0xd7,0x61,0x1b,0xe2,0x9a,0xb5,0xd4,0x5b,0x9b,0x81,0xeb,0x9f,0x8c,0xdd,0xd5,0x3e, |
1867 | | 0xea,0xa9,0x87,0x7e,0xec,0xed,0xba,0x93,0x71,0x7d,0x96,0xa0,0x1f,0x2b,0xd9,0xfe, |
1868 | | 0x6f,0xa4,0x8b,0x49,0xd8,0xb9,0xad,0x04,0x5b,0xd2,0xe8,0xe2,0xff,0x63,0xd7,0x6d, |
1869 | | 0x80,0x9a,0xba,0xd6,0xfd,0xff,0x85,0x82,0x12,0x0b,0x05,0x94,0x28,0x58,0xb0,0xa0, |
1870 | | 0x44,0xc5,0x12,0x48,0x4e,0x93,0x96,0x60,0x68,0x45,0x41,0x09,0x24,0xbc,0xa3,0xa0, |
1871 | | 0xa0,0xd2,0x02,0x26,0x90,0x28,0x81,0x04,0x08,0x24,0x90,0x57,0x48,0x42,0xc2,0x4b, |
1872 | | 0x05,0x0a,0x15,0x5a,0x50,0x50,0xb0,0x60,0x45,0x88,0x82,0x05,0x2b,0x77,0x64,0xae, |
1873 | | 0xf4,0x27,0x33,0x32,0x23,0xb7,0xd2,0xca,0x8c,0x9c,0x12,0x24,0x77,0x64,0x06,0x7e, |
1874 | | 0x23,0xff,0x29,0xff,0x91,0x99,0xff,0xb3,0x42,0xdb,0x7f,0xcf,0xb9,0xe7,0xdc,0xf3, |
1875 | | 0xd6,0xd3,0x7b,0x7b,0x4a,0x3e,0xac,0xef,0x5e,0x7b,0xad,0xbd,0xd7,0x5e,0xeb,0x79, |
1876 | | 0x9e,0xb5,0xf6,0xde,0x24,0xb7,0x20,0x56,0x14,0x70,0x8d,0xc1,0xcb,0x68,0xee,0xfc, |
1877 | | 0x35,0x64,0x91,0x5f,0x42,0x16,0xa3,0x1e,0x99,0xb5,0xf0,0x36,0xa6,0x87,0x37,0xb4, |
1878 | | 0x0f,0x86,0x20,0x16,0xb4,0x10,0x1f,0xf8,0xba,0x3a,0x64,0xfe,0x02,0xfc,0x6f,0x84, |
1879 | | 0x1b,0xf5,0xb5,0x6b,0xe8,0xd9,0x75,0xb8,0x3e,0xc4,0x03,0xbc,0x67,0x20,0xf3,0x05, |
1880 | | 0xb0,0xcd,0x4d,0x18,0x97,0x1c,0xec,0x07,0x73,0xef,0x59,0x0d,0x8e,0xaf,0x8f,0xa0, |
1881 | | 0xed,0x32,0x64,0xd1,0xf6,0x81,0x2f,0x6e,0x22,0x4b,0xb3,0x16,0xde,0x00,0x1b,0xc0, |
1882 | | 0x56,0x15,0xe8,0xd9,0x65,0xb8,0x56,0x19,0x94,0x7f,0xd4,0x8f,0x66,0xe1,0xfd,0x66, |
1883 | | 0xe6,0x36,0xc4,0x84,0xea,0x23,0xb0,0x2f,0xd8,0xe0,0xfa,0x17,0x68,0xb6,0x1e,0xe2, |
1884 | | 0xaf,0xbc,0x12,0xe2,0x54,0x09,0xfd,0x82,0xb8,0x51,0x0c,0xa2,0xd9,0x8f,0xe0,0xfc, |
1885 | | 0x06,0xa8,0xd7,0x83,0x7d,0x9a,0xa1,0x0f,0x9f,0xf4,0x42,0x5c,0x29,0xd0,0xec,0x6d, |
1886 | | 0xb8,0x66,0x35,0x8c,0xa7,0x0e,0xce,0x69,0xfd,0x14,0xec,0x5e,0x8d,0x2c,0x60,0xf3, |
1887 | | 0x59,0x2d,0x5c,0xa3,0xb1,0x1f,0x99,0xe5,0x9f,0x22,0x73,0x1f,0xbc,0x71,0xde,0xba, |
1888 | | 0x0a,0xe3,0x84,0xb7,0x51,0xb8,0xfe,0xac,0x06,0xe2,0xae,0x05,0xec,0xf5,0x11,0x5c, |
1889 | | 0x57,0x0b,0x36,0xaf,0x06,0xfb,0xf6,0x80,0x2f,0x1a,0x20,0x4e,0x9a,0xc1,0x86,0x17, |
1890 | | 0x3b,0xc0,0x8f,0xed,0xd0,0x6e,0x19,0x7a,0xf6,0x21,0xc4,0xd4,0x10,0xbc,0xe1,0x5e, |
1891 | | 0x82,0x38,0xb8,0xd4,0x0a,0x63,0x01,0xbb,0x1a,0xa0,0x8f,0xf8,0xdf,0xc5,0xd5,0xcd, |
1892 | | 0xd0,0x4f,0x88,0xdd,0x0f,0x20,0xde,0x3f,0xbc,0x0d,0xed,0x81,0xfd,0x7a,0xa0,0xdd, |
1893 | | 0xdb,0x9f,0xa0,0x59,0x58,0x73,0x67,0x6f,0x55,0xc0,0x5c,0xe8,0x40,0xcf,0xba,0xc0, |
1894 | | 0xc7,0x37,0x20,0x6e,0x2a,0xe4,0xe8,0x99,0xb2,0x11,0xcd,0x75,0x83,0x1d,0x3e,0x97, |
1895 | | 0xa3,0x39,0xc3,0x4d,0xb8,0x3e,0xb4,0xa3,0x85,0xb9,0x79,0xfb,0x32,0xc4,0x04,0xcc, |
1896 | | 0x85,0x5e,0x88,0xeb,0x6b,0xe0,0xdf,0x3e,0x18,0xc3,0x47,0xe0,0x1f,0xfc,0x6f,0x37, |
1897 | | 0xb8,0xff,0x99,0x3f,0x3f,0x0f,0xf1,0x21,0x47,0xe6,0x0f,0x21,0xb5,0x82,0x2f,0x1b, |
1898 | | 0xfb,0x20,0x56,0x20,0xb6,0x0c,0x30,0xb7,0x2e,0x80,0x2f,0xdb,0x06,0x61,0x8e,0xc0, |
1899 | | 0x7e,0x3b,0xf4,0xfb,0x72,0x15,0xd8,0xbb,0x1e,0xae,0x09,0x31,0xd6,0x00,0x31,0xfe, |
1900 | | 0x29,0xcc,0x6f,0x39,0x24,0x15,0xcc,0xe7,0x4b,0x30,0xa7,0x2e,0x81,0x4d,0xdb,0xe0, |
1901 | | 0x8d,0xfc,0x26,0xf8,0x00,0xde,0xb4,0x2c,0x1f,0xdd,0x02,0xbf,0x80,0x6d,0x55,0x57, |
1902 | | 0xe0,0x1a,0x70,0x2d,0x98,0xc3,0xe6,0x0a,0xf0,0xab,0x11,0xaf,0x1b,0xf0,0x56,0x0f, |
1903 | | 0xf3,0xd2,0xdc,0xd8,0x01,0xd7,0x85,0x6b,0x83,0x6d,0xcc,0x3d,0x30,0xcf,0x95,0xb5, |
1904 | | 0x60,0x47,0xb0,0x53,0x19,0xd8,0xab,0xfc,0x06,0xc4,0x3c,0xac,0x1f,0x60,0xab,0x59, |
1905 | | 0xb8,0x8f,0xce,0x5e,0x84,0xfe,0x9b,0x6e,0xa1,0xd9,0x7e,0x1c,0x73,0x60,0x3f,0x0d, |
1906 | | 0xc4,0x8b,0x16,0x7c,0x53,0x0d,0xf9,0x8b,0x35,0xd0,0x47,0xf0,0x17,0xac,0x45,0xcf, |
1907 | | 0xda,0xc1,0x76,0xed,0xd0,0xcf,0xcb,0x46,0x48,0xe0,0xef,0x4e,0xb0,0xcf,0x55,0x88, |
1908 | | 0xfd,0xcf,0x60,0xdb,0x0f,0xc7,0x0c,0x40,0x7e,0xe8,0x06,0x9a,0x93,0xc3,0x5a,0x55, |
1909 | | 0xde,0x0d,0xf3,0x01,0xfc,0x50,0xf3,0x21,0x9a,0x6b,0xab,0x46,0x73,0x97,0xeb,0xd1, |
1910 | | 0x5c,0x17,0xcc,0xab,0x2e,0x28,0xeb,0x3d,0x8f,0xe6,0xfa,0x20,0x4e,0xef,0x40,0x9c, |
1911 | | 0x5d,0x00,0x1f,0x7c,0xf2,0x05,0xc4,0x1a,0xc4,0x88,0xc2,0x84,0x16,0xda,0x2a,0xae, |
1912 | | 0xa1,0x39,0x2d,0x18,0xbc,0xff,0x32,0x2c,0x3c,0x30,0x89,0xa0,0xd3,0x33,0x77,0x60, |
1913 | | 0x20,0x1a,0x0d,0xec,0xc3,0xb6,0x02,0x8c,0x5f,0x01,0x4e,0xa8,0xab,0x83,0xc1,0x36, |
1914 | | 0x82,0x81,0xc1,0xc1,0x17,0x7b,0x61,0xb1,0x54,0x43,0xaa,0x45,0xe6,0x4e,0xd8,0xef, |
1915 | | 0x82,0x41,0x7f,0xfe,0x01,0x24,0xa8,0x1f,0x82,0x80,0xb9,0xd3,0x0d,0x81,0xdb,0x00, |
1916 | | 0x06,0x80,0xc1,0xab,0x61,0x32,0x6b,0x5a,0x20,0xe0,0x60,0xb2,0xc1,0x0d,0x63,0xb6, |
1917 | | 0xba,0x09,0xcd,0xd6,0x7c,0x00,0x06,0xa9,0x87,0xc5,0xef,0x02,0x04,0x14,0x6c,0x3f, |
1918 | | 0x87,0xed,0xe7,0x10,0xf8,0x72,0x70,0x10,0xdc,0x6c,0x9f,0x69,0x4d,0xe8,0x99,0x1e, |
1919 | | 0x16,0xa2,0x9a,0x1e,0xf4,0xac,0x16,0x82,0xac,0xf6,0x73,0xf4,0xac,0x01,0x82,0xa9, |
1920 | | 0xe1,0x13,0x70,0x26,0x2c,0xc0,0xb0,0x88,0x3f,0x6b,0x06,0xa7,0x36,0x83,0x21,0x2e, |
1921 | | 0xc1,0xc2,0x74,0x15,0x8e,0xeb,0x81,0x63,0x4c,0x50,0x37,0x08,0x4e,0x35,0x82,0x53, |
1922 | | 0xf1,0x82,0xdf,0x0c,0x83,0x6f,0x07,0x23,0x5c,0x86,0x85,0xf3,0x2a,0x2c,0xe6,0x9f, |
1923 | | 0x42,0xc0,0x7d,0x0a,0x86,0xba,0x06,0x8b,0xe0,0x20,0x38,0x5c,0x01,0x8b,0x68,0x59, |
1924 | | 0x23,0xb2,0xe8,0xc0,0x30,0x8d,0xe0,0x74,0xb8,0x09,0x5b,0x5a,0x2a,0x90,0xa5,0xeb, |
1925 | | 0x03,0xb4,0x70,0xb1,0x55,0x8f,0x45,0x8d,0x16,0x2e,0xc1,0x3d,0xea,0xdb,0x6b,0xcd, |
1926 | | 0x68,0x46,0x0e,0x66,0x92,0x0f,0xa0,0x85,0x76,0x9d,0x0e,0xa4,0xb7,0x1a,0x2d,0x5c, |
1927 | | 0x81,0xb0,0xb3,0x0c,0xa9,0x90,0xe5,0x4e,0x25,0xca,0xcc,0x44,0x99,0x3c,0x94,0x09, |
1928 | | 0x4f,0xd1,0x78,0x03,0xdb,0x3c,0x11,0x9a,0xe8,0xc3,0x3f,0x65,0xea,0xc3,0x3f,0x81, |
1929 | | 0xea,0xc3,0xbf,0x7a,0xba,0xb3,0xba,0xdb,0x8d,0xbe,0x6a,0xfc,0x8f,0x3e,0xf4,0xd5, |
1930 | | 0x8d,0xff,0xb8,0x85,0xbe,0xba,0x88,0xbe,0xaa,0x45,0x5f,0x5d,0x40,0x5f,0x35,0xa1, |
1931 | | 0xaf,0x9a,0xd1,0x57,0x1d,0xe8,0xab,0xab,0xe8,0xab,0xce,0xaf,0x14,0x58,0x94,0x20, |
1932 | | 0xff,0x31,0x68,0xcd,0xc3,0x06,0xf6,0xaa,0xf1,0x19,0xd5,0xff,0xd1,0x8f,0x65,0x10, |
1933 | | 0x7d,0x55,0x83,0xe5,0x03,0x2c,0xe7,0xb1,0xd4,0x62,0xa9,0xc3,0x52,0x8f,0xa5,0x01, |
1934 | | 0x4b,0x23,0x96,0x8f,0xb0,0x5c,0xc0,0xd2,0x84,0xe5,0x63,0x2c,0x2d,0x58,0x5a,0xb1, |
1935 | | 0x5c,0xc2,0xd2,0x86,0xe5,0x32,0x96,0x2b,0x58,0x3a,0xb0,0x74,0x62,0xb9,0xba,0xda, |
1936 | | 0xe8,0x00,0xbe,0xda,0x17,0xb8,0x95,0x2f,0xf0,0xc1,0x20,0xd5,0xd0,0xe3,0xc9,0x1e, |
1937 | | 0x34,0xf9,0x39,0x9a,0xbc,0x83,0xbe,0x96,0xa3,0xc9,0xdb,0x68,0xf2,0x0b,0x34,0x39, |
1938 | | 0x80,0xbe,0x6e,0x43,0x5f,0x5f,0x46,0x5f,0xab,0xd1,0xd7,0x2a,0xf4,0x75,0x19,0xfa, |
1939 | | 0xba,0x1c,0x7d,0x6d,0x44,0x5f,0x1b,0xd0,0xd7,0x95,0xe8,0x6b,0x2d,0xfa,0xba,0x01, |
1940 | | 0x7d,0x5d,0x83,0xbe,0xee,0x44,0x5f,0x7f,0x86,0xbe,0xee,0x45,0x5f,0xf7,0xa0,0xaf, |
1941 | | 0x6f,0xa3,0xaf,0x3f,0x47,0xdf,0xc8,0xd1,0x37,0x0a,0xf4,0xf5,0x1d,0xf4,0xcd,0x07, |
1942 | | 0xe8,0x9b,0xf3,0xe8,0xeb,0x6e,0xf4,0x4d,0x39,0xfa,0xa6,0x0c,0x7d,0xa3,0x45,0xdf, |
1943 | | 0x54,0xa0,0x6f,0x34,0xe8,0x1b,0x1d,0xfa,0xa6,0x1a,0x4d,0xea,0xd0,0xe3,0xcb,0x8f, |
1944 | | 0xaf,0x80,0x7c,0x53,0x07,0x32,0xa9,0xc5,0xb9,0x72,0x2c,0x65,0x58,0xac,0xbb,0xd5, |
1945 | | 0xb8,0x02,0x8e,0x36,0xe0,0x43,0xbb,0xb0,0x74,0xe3,0x12,0x0d,0x16,0x3d,0x7a,0xdc, |
1946 | | 0x81,0xcb,0x3a,0x70,0x59,0xc7,0xe3,0x6b,0x20,0xb8,0xa2,0x03,0xb7,0xdb,0x81,0x6b, |
1947 | | 0xaf,0xe2,0xda,0xab,0xb8,0xf6,0x2a,0xae,0xbd,0x8a,0x6b,0xaf,0xe2,0xda,0xab,0xb8, |
1948 | | 0xf6,0x53,0x5c,0xfb,0x29,0x2e,0xfb,0x14,0x97,0x7d,0x8a,0xcb,0xba,0xf0,0xc1,0x5d, |
1949 | | 0xb8,0xac,0x1b,0xd7,0x76,0xe3,0xdc,0x35,0x9c,0xbb,0x86,0x2b,0xae,0xe1,0xdd,0x5e, |
1950 | | 0xbc,0xdb,0x8b,0x77,0x7b,0x71,0xa3,0xbd,0xb8,0xcc,0x84,0x77,0x4d,0x38,0x77,0x13, |
1951 | | 0xd7,0xde,0xc4,0xbb,0x37,0x71,0xed,0x4d,0x5c,0x76,0x0b,0xef,0xde,0xc2,0xb9,0x7e, |
1952 | | 0x2c,0x03,0xf8,0x90,0x01,0x9c,0xbb,0x8d,0x73,0xb7,0x21,0x37,0xa9,0x80,0x1c,0x48, |
1953 | | 0x37,0x96,0x6b,0x20,0xd6,0x32,0xe8,0x15,0x88,0x1e,0x4d,0x2a,0x71,0x85,0x12,0x97, |
1954 | | 0x29,0x71,0x99,0x12,0x97,0xa9,0xc0,0x70,0x20,0x5d,0x58,0xba,0xb1,0xc0,0x69,0xaa, |
1955 | | 0x49,0x35,0x16,0x0d,0x16,0x1d,0x16,0x38,0x4e,0x8d,0x0f,0x51,0xe3,0x43,0xd4,0xf8, |
1956 | | 0x10,0x35,0xae,0x55,0xe3,0x5a,0x35,0xae,0xd5,0xe0,0x5a,0x0d,0xae,0xd5,0xe0,0x5a, |
1957 | | 0x0d,0xae,0xd5,0xe0,0x5a,0x0d,0xae,0x2d,0xc3,0xb5,0x65,0xb8,0xb6,0x0c,0xd7,0x96, |
1958 | | 0xe1,0xda,0x32,0x5c,0x5b,0x86,0x6b,0xcb,0x71,0x6d,0x39,0x2e,0x2b,0xc7,0x65,0xe5, |
1959 | | 0xb8,0x4c,0x8f,0xcb,0xf4,0xf8,0x0c,0x3d,0x3e,0x43,0x8f,0x6b,0xf5,0xb8,0x56,0x8f, |
1960 | | 0xad,0x7b,0x7d,0xf2,0x3a,0x7a,0xdc,0x03,0x32,0xa9,0x03,0xf1,0x9a,0x34,0x4c,0xd6, |
1961 | | 0x80,0x1a,0xad,0x5a,0x69,0xd5,0x2a,0xab,0x56,0x5b,0xb5,0x06,0x1f,0x7d,0xf9,0x71, |
1962 | | 0x0f,0x96,0x1b,0xd8,0xdf,0x65,0xd8,0xcb,0x3d,0x58,0x6e,0x60,0x07,0x97,0x61,0xb7, |
1963 | | 0xf6,0x60,0xb9,0x81,0x3d,0x5a,0x86,0x3d,0xda,0x83,0xe5,0x06,0x76,0x66,0x19,0x1e, |
1964 | | 0xd2,0x15,0xdc,0xf3,0x1e,0x2c,0x37,0x70,0xa7,0xcb,0x70,0xb7,0x7a,0xb0,0xdc,0xc0, |
1965 | | 0x3d,0xc2,0x51,0x86,0x9d,0x74,0x79,0xb2,0x1c,0xb7,0x57,0x8e,0x5b,0x29,0xc7,0xce, |
1966 | | 0xb4,0xda,0xa9,0x1c,0x9f,0x51,0x8e,0xc7,0x75,0x1d,0x1f,0x5c,0x8e,0x1b,0x2d,0xc7, |
1967 | | 0xfe,0x06,0xe9,0xc3,0xde,0xeb,0xc3,0xb5,0x72,0x6b,0xc7,0x61,0x53,0xb5,0xba,0xc1, |
1968 | | 0x5d,0x07,0x5f,0xeb,0xb0,0xe8,0xb1,0x9b,0x75,0x58,0xf4,0xd8,0xcd,0x3a,0x2c,0x7a, |
1969 | | 0xdc,0x82,0x0e,0x8b,0x1e,0xb7,0xa0,0xc3,0xa2,0xc7,0x81,0xa6,0xc3,0x82,0x23,0x10, |
1970 | | 0xe7,0xba,0x70,0xee,0x1a,0xce,0x5d,0xc3,0x39,0x13,0xce,0x99,0x70,0xee,0x26,0xce, |
1971 | | 0xdd,0xb4,0x9e,0x8b,0x63,0xa7,0x0f,0x47,0x56,0x1f,0x1e,0x43,0x1f,0x1e,0x7a,0x2f, |
1972 | | 0x16,0x13,0x96,0x9b,0x58,0xae,0x4c,0x56,0x58,0xe7,0x80,0x35,0xec,0x57,0x03,0xfa, |
1973 | | 0xea,0x6a,0x48,0x5f,0x5d,0x0d,0xe5,0xab,0x56,0xff,0x5b,0x37,0xdd,0xab,0x9b,0x6b, |
1974 | | 0xd6,0xe8,0xc7,0x7b,0xdd,0xd6,0x10,0xb0,0x6e,0x74,0xd6,0x78,0x5f,0x0d,0xfb,0xae, |
1975 | | 0xd5,0xc0,0xef,0x5a,0x1d,0x83,0xf5,0xc8,0xde,0xd5,0x56,0x7a,0xad,0xd1,0x83,0xa7, |
1976 | | 0xc2,0xf7,0x93,0xc1,0x6a,0xa3,0xd5,0xeb,0xf5,0xad,0x8e,0xa8,0x6f,0xf5,0x0a,0x7d, |
1977 | | 0xab,0x75,0x37,0x57,0x47,0x7d,0x73,0xb5,0x2f,0xb7,0x56,0x1b,0xbb,0xb5,0x5a,0x77, |
1978 | | 0x6b,0xf5,0xea,0x03,0xab,0x9d,0x1f,0x58,0x2d,0x1c,0x58,0xed,0xcb,0xed,0xd5,0xbd, |
1979 | | 0xdb,0xab,0x87,0xdc,0x5e,0x8d,0x57,0x85,0xb5,0x15,0x3c,0x49,0xbe,0x9f,0x2b,0xd6, |
1980 | | 0x38,0xb7,0x5e,0xdd,0xba,0xd1,0xaf,0x6e,0x74,0xd6,0x09,0xb1,0x3a,0x25,0xae,0xad, |
1981 | | 0x4e,0x85,0xef,0xa3,0xbf,0xfb,0xfb,0x99,0x60,0x9d,0x01,0xab,0x27,0x68,0xac,0xa3, |
1982 | | 0xc5,0x9b,0xd5,0xc2,0x6b,0xab,0x87,0x5c,0x5b,0xdd,0xeb,0xc2,0x61,0x52,0xbe,0x3a, |
1983 | | 0x83,0xca,0x57,0xaf,0x57,0xb6,0x7a,0x7a,0xd9,0xea,0x85,0xca,0x56,0xcf,0x2b,0xb3, |
1984 | | 0x1a,0x0b,0x4f,0x1e,0xeb,0x94,0x5a,0xed,0xae,0x7e,0x75,0x0c,0x1d,0xab,0xfe,0xbd, |
1985 | | 0xba,0x6a,0x9e,0xab,0xab,0x66,0xbd,0xfa,0x43,0xe1,0xb5,0xd5,0xa5,0xca,0x3a,0xcc, |
1986 | | 0xab,0xab,0x63,0xef,0x5a,0xdd,0xeb,0x5a,0x35,0x5d,0xd7,0x0f,0xce,0xb1,0x1e,0x69, |
1987 | | 0x5a,0x0d,0xa0,0xbe,0xd5,0xcd,0xcd,0x1f,0x06,0xdd,0x65,0xdd,0xac,0x5e,0x5d,0xbf, |
1988 | | 0x5a,0xa8,0x5f,0x2d,0xd4,0xaf,0x16,0x6a,0x56,0x37,0xca,0x1f,0xe6,0x7c,0xf7,0x6a, |
1989 | | 0xe0,0x5a,0xf7,0x54,0x3f,0x2e,0x04,0xdf,0xaf,0x11,0x3f,0xb4,0xa9,0x59,0xad,0xd3, |
1990 | | 0xac,0xf6,0x45,0x6f,0x5d,0x2f,0xbf,0xb7,0x19,0xde,0x28,0x56,0xfb,0xd9,0xb1,0x5a, |
1991 | | 0xd7,0xbb,0x7a,0x5e,0xd9,0xea,0x30,0x4d,0x93,0x6a,0xb8,0x2f,0xc0,0xf5,0xf0,0x06, |
1992 | | 0x82,0x54,0x6d,0x9d,0x6c,0x90,0x51,0x59,0xa7,0xf7,0xaa,0x13,0x1e,0x7f,0x66,0x3d, |
1993 | | 0x70,0x75,0x9d,0xec,0x81,0xe0,0xd2,0xc2,0xda,0x06,0x7b,0x6a,0xeb,0x54,0x9c,0xd4, |
1994 | | 0x42,0x89,0xda,0x1a,0x6e,0xd6,0xc5,0x6c,0x75,0xe3,0xf5,0x43,0x63,0x5e,0x3f,0x1c, |
1995 | | 0xe8,0xf5,0xff,0x1f,0xd8,0x35,0xa9,0xf6,0xc2,0x62,0x3d,0x06,0x2e,0xd7,0xf3,0x8d, |
1996 | | 0x01,0x67,0x91,0x1f,0xfa,0x56,0xae,0x40,0x41,0xc8,0x1b,0xbd,0x0b,0xb9,0x7a,0x48, |
1997 | | 0x1f,0xa2,0xdf,0xcb,0xf1,0x8f,0xac,0xce,0xa3,0x53,0xa8,0x18,0xc9,0xa0,0xa4,0x16, |
1998 | | 0x12,0x3c,0x38,0xc8,0xab,0x21,0xd5,0x40,0xd2,0x43,0xaa,0x80,0x64,0x80,0x64,0x84, |
1999 | | 0x54,0x09,0xa9,0x0a,0x9d,0x40,0xa9,0x68,0x17,0xda,0x8d,0xf6,0x21,0x32,0x62,0xa2, |
2000 | | 0x77,0x50,0x0a,0xf2,0x41,0x24,0x74,0x00,0x56,0xb2,0x0a,0xbc,0x32,0x54,0xe0,0x05, |
2001 | | 0x0f,0x2f,0x77,0x78,0xb1,0xb3,0x2e,0x1c,0x78,0xbd,0xb3,0x2e,0x1d,0x78,0xc9,0xb3, |
2002 | | 0x2e,0x1e,0x78,0xd5,0xc3,0x19,0xbc,0xfc,0x7d,0x80,0x33,0x60,0xa0,0x56,0xf4,0xf8, |
2003 | | 0x22,0x7a,0x7c,0x09,0x3d,0x6e,0x43,0x8f,0xdb,0x61,0xb1,0x42,0xf8,0x8e,0xd9,0x81, |
2004 | | 0x1e,0x77,0x42,0x50,0xc0,0x9a,0x84,0xac,0xf7,0x29,0x84,0xe7,0x15,0x98,0x0c,0xaf, |
2005 | | 0xaf,0x08,0x2f,0x80,0xbd,0x10,0x08,0x60,0x16,0x88,0x03,0x98,0x4c,0x70,0xe3,0x01, |
2006 | | 0xdb,0xc1,0x5c,0x01,0xc7,0x80,0xe1,0xc1,0x75,0x08,0xdf,0x29,0x70,0x70,0x22,0xab, |
2007 | | 0x35,0xd1,0xaa,0x5b,0x2f,0x62,0xb9,0x84,0xa5,0x1d,0xcb,0x15,0xb4,0x13,0xed,0x41, |
2008 | | 0x01,0xe8,0x24,0x92,0xa2,0x12,0xf4,0xfb,0xcb,0x1a,0x48,0xf8,0xfb,0x1d,0xfc,0xbd, |
2009 | | 0x0f,0xfe,0x5a,0xe5,0x12,0xa4,0x76,0x48,0x57,0x20,0xe1,0x7f,0xeb,0xc2,0xbe,0x0a, |
2010 | | 0xf6,0xe1,0xd9,0xfa,0x5b,0x95,0x0a,0xad,0xfe,0x83,0x17,0x7f,0xbd,0xd0,0x88,0xf0, |
2011 | | 0xd7,0xe4,0xff,0x76,0x11,0xfd,0xdb,0x25,0xf4,0x6f,0x5d,0xe8,0xdf,0x2e,0xa3,0x7f, |
2012 | | 0x6b,0x47,0xbf,0x87,0x53,0x7e,0x5f,0xab,0x44,0xbf,0x87,0xd7,0xb6,0xdf,0x97,0xd5, |
2013 | | 0x40,0xfa,0x00,0xd2,0x79,0xf4,0xfb,0xfa,0x16,0xf4,0xfb,0x0f,0x2b,0xd0,0x42,0x75, |
2014 | | 0x75,0x07,0x96,0x4e,0x2c,0x57,0xb1,0x7c,0x8a,0xa5,0x0b,0x4b,0x37,0x96,0x6b,0x58, |
2015 | | 0x3e,0xc3,0x72,0x1d,0x4b,0x0f,0x96,0x1b,0x58,0x7a,0xb1,0xf4,0x61,0x31,0x61,0xb9, |
2016 | | 0x89,0xe5,0x16,0x96,0x7e,0x2c,0x03,0x58,0x6e,0x63,0xf9,0x1c,0xcb,0x20,0x96,0x21, |
2017 | | 0x2c,0x77,0xb0,0x7c,0x01,0x52,0x23,0xc7,0xa2,0xc0,0xa2,0xc4,0xa2,0xc2,0xa2,0xc6, |
2018 | | 0xa2,0xc1,0x52,0x86,0xa5,0x1c,0x8b,0x16,0x8b,0x0e,0x8b,0x1e,0x0b,0xee,0x73,0x8d, |
2019 | | 0x01,0x8b,0x11,0x4b,0x25,0x96,0x2a,0x90,0xf3,0x0d,0x58,0x1a,0xb1,0x7c,0x84,0xe5, |
2020 | | 0x02,0x96,0x26,0x2c,0xcd,0x58,0x3e,0xc6,0xf2,0x09,0x96,0x16,0x2c,0xad,0x58,0x2e, |
2021 | | 0x62,0xb9,0x84,0xa5,0x0d,0x4b,0x3b,0x96,0xcb,0x58,0xae,0x60,0xc1,0x76,0x39,0x8f, |
2022 | | 0xed,0x72,0x1e,0xdb,0xe5,0x3c,0xb6,0xcb,0x79,0x6c,0x97,0xf3,0xd8,0x2e,0xe7,0xb1, |
2023 | | 0x5d,0xce,0x63,0xbb,0x9c,0xc7,0x76,0x39,0x8f,0xed,0x72,0x1e,0xdb,0xe5,0x3c,0xb6, |
2024 | | 0xcb,0x79,0x6c,0x97,0xf3,0xd8,0x2e,0xe7,0xb1,0x5d,0xce,0x63,0xbb,0x9c,0xc7,0x76, |
2025 | | 0x39,0x8f,0xed,0x72,0x1e,0xdb,0xe5,0x3c,0xb6,0x4b,0xfd,0x87,0x58,0x70,0xc7,0xeb, |
2026 | | 0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71, |
2027 | | 0xc7,0xeb,0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71,0xc7,0xeb,0x71,0x9f,0xeb,0x71,0x9f, |
2028 | | 0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb, |
2029 | | 0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71, |
2030 | | 0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x9f,0xeb,0x71,0x77,0xeb,0x71,0x77,0xeb,0x71,0x77, |
2031 | | 0xeb,0x71,0x77,0xeb,0x71,0x77,0xeb,0x71,0x77,0xeb,0x71,0x77,0xeb,0xad,0x3d,0x1d, |
2032 | | 0x44,0xff,0xa7,0x1a,0xfd,0x9f,0x1a,0xf4,0x65,0x23,0xfa,0xf2,0x12,0xfa,0xcf,0xee, |
2033 | | 0xcb,0xe8,0xcb,0x76,0xf4,0x65,0x1b,0x9a,0xbe,0x59,0x83,0x46,0x1b,0xd0,0xe8,0xc7, |
2034 | | 0xe8,0xcb,0x4e,0x34,0x7a,0x11,0x7d,0x79,0x01,0x7d,0xd9,0x84,0x46,0xaf,0xa0,0x2f, |
2035 | | 0xd5,0xe8,0xcb,0xab,0xe8,0x4b,0xe8,0x42,0xf3,0xa0,0x1a,0xfd,0xe7,0xc7,0x95,0x68, |
2036 | | 0xf4,0x1a,0xce,0x6b,0xd0,0x97,0x95,0x78,0x5b,0x86,0x46,0x6f,0xa2,0xd1,0xdb,0x38, |
2037 | | 0xab,0x45,0xa3,0x77,0xd0,0x97,0x1d,0xe8,0xcb,0xcb,0xd0,0x30,0x9c,0x79,0x05,0xfd, |
2038 | | 0xbe,0xa7,0x07,0x7d,0x59,0x85,0xbe,0x6c,0x45,0x5f,0x42,0x93,0x0d,0xe8,0xdf,0xe5, |
2039 | | 0xe8,0xdf,0x15,0xe8,0xdf,0x95,0xf8,0x68,0x3d,0x16,0xb8,0x5c,0x3d,0xfa,0xf2,0x43, |
2040 | | 0x9c,0xc5,0x01,0xd1,0x8b,0x83,0xa9,0x17,0x07,0x53,0x2f,0x0e,0xa6,0x5e,0x1c,0x4c, |
2041 | | 0xbd,0x38,0x98,0x7a,0x71,0x30,0xf5,0xe2,0x60,0xea,0xc5,0xc1,0xd4,0x8b,0x83,0xa9, |
2042 | | 0x17,0x07,0x53,0x2f,0x0e,0xa6,0x5e,0xeb,0xb9,0x38,0x98,0x7a,0x71,0x30,0xf5,0xe2, |
2043 | | 0x60,0xea,0xc5,0xc1,0x84,0x5f,0x55,0xaa,0x7b,0x6b,0xb0,0x7c,0x80,0xe5,0x3c,0x96, |
2044 | | 0x5a,0x2c,0x75,0x58,0xea,0xb1,0x60,0xdf,0xf5,0x62,0xdf,0xf5,0x62,0xdf,0xf5,0x62, |
2045 | | 0xdf,0xf5,0x62,0xdf,0xf5,0x62,0xdf,0xf5,0x62,0xdf,0xf5,0x62,0xdf,0xf5,0x62,0xdf, |
2046 | | 0xf5,0x62,0xdf,0xf5,0x62,0xdf,0xf5,0xe2,0xa0,0xeb,0xc5,0x0e,0xec,0xc5,0x0e,0xec, |
2047 | | 0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5, |
2048 | | 0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x0e, |
2049 | | 0xec,0xc5,0x0e,0xec,0xc5,0x0e,0xec,0xc5,0x41,0x67,0xc2,0xbb,0x26,0xbc,0x6b,0xb2, |
2050 | | 0xee,0x62,0xa7,0x9a,0xb0,0x53,0x4d,0xd8,0xa9,0x26,0xec,0x54,0x13,0x76,0xaa,0x09, |
2051 | | 0x3b,0xd5,0x84,0x9d,0x6a,0xc2,0x31,0x68,0xc2,0x9e,0x35,0xe1,0xb9,0x69,0xc2,0x73, |
2052 | | 0xd3,0x84,0xe7,0xa6,0x09,0xcf,0xcd,0x9b,0xd8,0x9c,0x37,0xb1,0x39,0x6f,0x62,0x73, |
2053 | | 0xde,0xc4,0xe6,0xbc,0x89,0xcd,0x79,0x13,0xcc,0x59,0x73,0x49,0x8e,0x45,0x81,0x45, |
2054 | | 0x89,0x45,0x85,0x45,0x8d,0xc5,0x5a,0x5b,0x86,0xa5,0x1c,0x8b,0x16,0x8b,0x0e,0x8b, |
2055 | | 0x1e,0x4b,0x05,0x16,0x03,0x16,0x23,0x96,0x4a,0x2c,0x55,0x58,0xaa,0xb1,0xd4,0x60, |
2056 | | 0xf9,0x00,0xcb,0x79,0x2c,0xb5,0x58,0xea,0xb0,0xd4,0x63,0xf9,0x10,0x4b,0x03,0x96, |
2057 | | 0x46,0x2c,0x1f,0x61,0xb9,0x80,0xa5,0x09,0x4b,0x33,0x96,0x8f,0xb1,0x80,0xb1,0xeb, |
2058 | | 0x07,0x5a,0xb0,0xb4,0x62,0xb9,0x88,0xe5,0x12,0x96,0x36,0x2c,0xed,0x58,0x2e,0x63, |
2059 | | 0xb9,0x82,0xa5,0x03,0x4b,0x27,0x96,0xab,0x58,0x3e,0xc5,0xd2,0x85,0xa5,0x1b,0xcb, |
2060 | | 0x35,0x2c,0x9f,0x61,0xb9,0x8e,0xa5,0x07,0xcb,0x0d,0x2c,0xbd,0x58,0xfa,0xb0,0x98, |
2061 | | 0xb0,0xdc,0xc4,0x72,0x0b,0x4b,0x3f,0x96,0x01,0x2c,0xb7,0xb1,0x7c,0x8e,0x65,0x10, |
2062 | | 0xcb,0x10,0x96,0x3b,0x58,0xc0,0xba,0xf5,0xb7,0x71,0xc5,0x6d,0x5c,0x71,0x1b,0x57, |
2063 | | 0xdc,0xc6,0x15,0xb7,0x71,0xc5,0xe7,0x72,0x2c,0x0a,0x2c,0x4a,0x2c,0x2a,0x2c,0x6a, |
2064 | | 0x2c,0x1a,0x2c,0x65,0x58,0xca,0xb1,0x68,0xb1,0xe8,0xb0,0xe8,0xb1,0x54,0x60,0x31, |
2065 | | 0x60,0x31,0x62,0xa9,0xc4,0x52,0x85,0xa5,0x1a,0x4b,0x0d,0x96,0x0f,0xb0,0x9c,0x47, |
2066 | | 0xdf,0x2a,0xce,0x7f,0xab,0xe8,0xb0,0x7e,0xf5,0x8b,0x7f,0x73,0x80,0xbf,0x30,0xc4, |
2067 | | 0xb7,0x9a,0x0e,0xfc,0x9d,0xe4,0x42,0xb3,0xe6,0x43,0x48,0xed,0x38,0xd3,0xf0,0x07, |
2068 | | 0x19,0x48,0xd7,0x7e,0xba,0xf3,0xd9,0x4f,0x77,0xae,0xff,0x74,0xa7,0xe7,0xa7,0x3b, |
2069 | | 0x60,0xac,0xe6,0xb2,0x81,0xef,0x5b,0x2a,0xbb,0xfd,0x43,0x66,0xe0,0x27,0x4d,0xae, |
2070 | | 0x96,0xfe,0xb0,0x33,0xf0,0x93,0xf6,0x7f,0xac,0xf9,0x0c,0xdd,0xeb,0x41,0xf7,0x6f, |
2071 | | 0xa1,0xbc,0x3c,0xf4,0x7b,0x6d,0x39,0x24,0xbc,0x08,0x0c,0x29,0xb0,0xe8,0xb0,0x54, |
2072 | | 0x60,0xc1,0x2b,0xca,0xd0,0x07,0x58,0x3a,0xb1,0xe0,0x45,0x67,0xa8,0x1b,0x0b,0x6e, |
2073 | | 0x6a,0xa8,0x17,0x8b,0x09,0xcb,0x2d,0x2c,0x03,0x58,0x3e,0xc7,0x32,0x84,0xe5,0x0b, |
2074 | | 0x2c,0x78,0x25,0x19,0x6a,0xc0,0xd2,0x88,0xa6,0xfb,0xac,0x99,0x6a,0xbc,0xb8,0xdc, |
2075 | | 0x41,0xd3,0x78,0x46,0x34,0x0f,0x7e,0x81,0xee,0xf7,0xa3,0xfb,0xf8,0xd4,0x41,0xeb, |
2076 | | 0x92,0x06,0xcb,0x60,0x19,0x2c,0x7e,0xf8,0xc8,0xc1,0x2e,0x2c,0x4d,0xe8,0xcb,0xf3, |
2077 | | 0x50,0xf0,0x11,0x9c,0xae,0x81,0x24,0x87,0x54,0x8e,0x46,0xbf,0x40,0x5f,0xc2,0x82, |
2078 | | 0x77,0x0d,0x7d,0xf9,0x19,0xba,0xdf,0x8a,0xee,0xf7,0xa1,0xfb,0x26,0x74,0xff,0x26, |
2079 | | 0x1c,0x87,0xbf,0x5d,0xa9,0x83,0x6d,0x39,0x24,0x3d,0xfa,0xb2,0x05,0x37,0x01,0xe3, |
2080 | | 0xf9,0xb8,0xed,0x22,0x96,0x4b,0x58,0xda,0xb0,0xb4,0x63,0xb9,0x8c,0xe5,0x0a,0x96, |
2081 | | 0x0e,0x2c,0x9d,0x58,0xae,0x62,0xf9,0x14,0x4b,0x17,0x96,0x6e,0x2c,0xd7,0xb0,0x7c, |
2082 | | 0x86,0xe5,0x3a,0x96,0x1e,0x2c,0x37,0xb0,0xf4,0x62,0xe9,0xc3,0x62,0xc2,0x72,0x13, |
2083 | | 0xcb,0x2d,0x2c,0xfd,0x58,0x06,0xb0,0xdc,0xc6,0xf2,0x39,0x96,0x41,0x2c,0x43,0x58, |
2084 | | 0xee,0x60,0x81,0xe1,0x7f,0xdc,0x2e,0xc7,0xa2,0xc0,0xa2,0xc4,0x02,0x4f,0x36,0xd7, |
2085 | | 0xd0,0xd7,0xad,0x68,0xf2,0x33,0x44,0xf1,0x43,0x54,0x3f,0xf4,0x3b,0x3f,0xf4,0xa6, |
2086 | | 0x1f,0xa2,0xf9,0x21,0xba,0x1f,0x7a,0xcb,0x0f,0xbd,0xed,0x87,0x02,0xfd,0x10,0x03, |
2087 | | 0x3f,0xf5,0xd5,0xe6,0xe1,0xa7,0xba,0x82,0x22,0xc4,0xcd,0x47,0x79,0xe9,0x28,0x27, |
2088 | | 0x27,0x1f,0x15,0xbc,0x8f,0x04,0xf0,0x97,0x8e,0x04,0xb9,0x28,0x3d,0x0b,0x82,0xf2, |
2089 | | 0xf3,0x6f,0x15,0x15,0xd6,0xdf,0x3b,0x28,0xf1,0xef,0x57,0x3f,0x44,0xe6,0x2a,0xfc, |
2090 | | 0x83,0x96,0x72,0x64,0x6e,0xfb,0x08,0xcd,0x5d,0xb9,0x84,0x66,0x6e,0xb7,0xa1,0xd9, |
2091 | | 0x86,0x16,0xf4,0x4c,0xdd,0x8a,0xcc,0x3a,0x23,0x32,0xdf,0x31,0x20,0x73,0x99,0x11, |
2092 | | 0xcd,0xc2,0x8d,0xcc,0xac,0x6d,0x46,0xcf,0x4c,0x4a,0x34,0x77,0xa3,0x13,0x99,0x2f, |
2093 | | 0xc1,0x3e,0x3c,0x7b,0xcc,0x0e,0xd6,0xa2,0x59,0x7d,0x1d,0x9a,0x35,0xd6,0x21,0x8b, |
2094 | | 0x42,0x8f,0x66,0x0d,0xe5,0x68,0x56,0x77,0x1e,0x3d,0xbb,0xac,0x40,0xcf,0x3a,0xf1, |
2095 | | 0x3f,0x5a,0xb5,0x68,0xf6,0xb6,0x1c,0x3d,0xab,0x85,0xeb,0xe9,0x6e,0x20,0x33,0xdc, |
2096 | | 0xf7,0x2c,0x1a,0xfc,0x8c,0x59,0x3b,0xdb,0xd4,0xb5,0xfa,0x14,0x5a,0x3b,0xd3,0xaf, |
2097 | | 0xfb,0x21,0x77,0xdb,0xf0,0x7d,0xce,0x7c,0xed,0x87,0xb2,0x67,0xca,0x81,0xef,0x73, |
2098 | | 0xd0,0xf0,0x0f,0x65,0x17,0x3e,0xfc,0xe1,0xb8,0x8a,0xe6,0x1f,0x6a,0xeb,0xac,0x65, |
2099 | | 0xe6,0x3b,0x78,0x54,0x9f,0xa1,0x99,0xfe,0x21,0x48,0xfd,0x68,0x66,0x00,0x8c,0xd9, |
2100 | | 0xa2,0xbe,0x88,0x66,0x86,0x5a,0xd0,0xcc,0x9d,0xcf,0x91,0x59,0xae,0x44,0x66,0x05, |
2101 | | 0x74,0x0d,0x9e,0xe3,0xcc,0xf8,0xf7,0x04,0x1f,0xc0,0x7a,0xd6,0xd2,0x00,0x05,0x1a, |
2102 | | 0xfc,0x73,0xa9,0x36,0x48,0xe0,0xb0,0x96,0xda,0x26,0xa8,0x19,0x80,0x1d,0x88,0x86, |
2103 | | 0x96,0xba,0x0a,0xb0,0x02,0xb4,0x5b,0xd6,0x86,0x66,0x3e,0xc7,0x16,0x81,0x48,0xe8, |
2104 | | 0x2c,0xff,0x04,0x4c,0x02,0xcf,0x85,0xe7,0xf1,0x16,0xda,0xd5,0x95,0x41,0xba,0x85, |
2105 | | 0xbe,0xad,0xc5,0x3f,0x2f,0xd6,0x40,0x82,0x7d,0xa3,0x0e,0xd2,0x47,0x90,0x60,0xf8, |
2106 | | 0xc6,0x21,0x48,0xe0,0xe3,0x96,0x8e,0x2e,0xf4,0x4c,0x01,0xf6,0xab,0xd2,0x43,0x82, |
2107 | | 0x75,0xb4,0x05,0xff,0xa6,0xaa,0xea,0x53,0x48,0x3d,0x60,0x30,0x38,0x0b,0x7a,0x64, |
2108 | | 0x86,0xa7,0x3b,0x33,0x3c,0x91,0x99,0x6b,0x3a,0x60,0xff,0x22,0x32,0xc3,0xf3,0x8d, |
2109 | | 0xb9,0xb6,0x1a,0x99,0xeb,0xce,0x43,0x82,0xe3,0xeb,0xd5,0x90,0xe0,0x1c,0x78,0xae, |
2110 | | 0x30,0x7f,0x08,0x23,0x6a,0xaa,0x87,0x04,0x5d,0x6c,0xac,0x81,0xd4,0x07,0x0e,0xba, |
2111 | | 0x86,0xcc,0x9f,0x54,0x42,0x82,0x7c,0x0b,0x38,0xf2,0x63,0x18,0x42,0x0b,0x38,0xa0, |
2112 | | 0x05,0xae,0x71,0x11,0xba,0xdf,0x0a,0x8f,0x62,0xe6,0x4b,0x50,0x70,0xe9,0x16,0x78, |
2113 | | 0x1f,0x2e,0x0a,0xf3,0xc1,0xdc,0x0e,0x73,0xa2,0xf5,0x23,0x08,0xfd,0xd6,0x0b,0x57, |
2114 | | 0x91,0xf9,0x4a,0x17,0x32,0x77,0x5c,0x80,0x74,0x05,0xf2,0x0d,0xc8,0xdc,0x79,0x19, |
2115 | | 0x7d,0x7b,0xe1,0x1a,0xa4,0x41,0x64,0xee,0x82,0xae,0x75,0x41,0xd4,0xb6,0x5e,0x81, |
2116 | | 0xcc,0x67,0x2a,0x48,0x70,0xc0,0x67,0x10,0xfd,0xad,0x5d,0x38,0xf3,0x05,0x32,0x5f, |
2117 | | 0x87,0x36,0x87,0x60,0x21,0xfc,0x58,0x81,0xcc,0x3d,0x2d,0xc8,0x0c,0x4f,0x0e,0xe6, |
2118 | | 0x1b,0xb0,0x6c,0xb6,0xde,0x82,0x0b,0x9b,0x54,0x38,0x73,0x19,0x32,0xd0,0x4d,0x13, |
2119 | | 0x0c,0x03,0x6e,0x8e,0xe6,0x5b,0x10,0x73,0xb7,0x2e,0xa2,0x6f,0x5b,0x3e,0x83,0x2d, |
2120 | | 0x18,0xab,0x1f,0x86,0x0e,0x5e,0x34,0xc3,0x9d,0xe3,0xdb,0x56,0xe8,0xd9,0xc5,0x32, |
2121 | | 0xb0,0x76,0x2b,0x1c,0x78,0x1b,0x8c,0x77,0x1b,0xc6,0x7d,0x1b,0xa6,0xd7,0xd5,0x4a, |
2122 | | 0xfc,0x1f,0x51,0x43,0x0f,0x9a,0xd3,0xc2,0x85,0x06,0xe1,0x74,0x7c,0x4b,0xbc,0xa4, |
2123 | | 0x87,0xf9,0x76,0xb9,0x1c,0x2c,0x8f,0xbf,0x4d,0x81,0x65,0xea,0xdb,0x4b,0x60,0xb3, |
2124 | | 0x3b,0xb0,0xff,0x05,0xd8,0xe2,0x0b,0xb0,0xd3,0x17,0x10,0xbc,0x4a,0x05,0xfa,0x16, |
2125 | | 0xa6,0xe3,0xb7,0x6d,0x70,0x6f,0xbb,0x78,0x01,0x22,0x19,0x66,0xc2,0xac,0x06,0xff, |
2126 | | 0x57,0xd8,0x00,0xe9,0x36,0x9a,0x2d,0xbb,0x01,0x09,0x66,0x44,0xd9,0x67,0x68,0xb6, |
2127 | | 0x1c,0x7f,0x35,0x81,0xbf,0x92,0xb9,0x00,0x11,0xde,0x0c,0x51,0xdf,0x83,0x66,0x2b, |
2128 | | 0xe0,0x1c,0x23,0x2c,0x5f,0x17,0xbb,0xe0,0x04,0xc3,0x10,0x14,0x0c,0x42,0x41,0x07, |
2129 | | 0x9a,0xad,0x54,0xa1,0xd9,0x2a,0x58,0x56,0x2e,0x7e,0x06,0x47,0x55,0x5f,0x84,0x1d, |
2130 | | 0x0d,0x14,0xc2,0x38,0x3a,0xae,0xa1,0xd9,0x9a,0x4e,0x48,0x77,0xd0,0xec,0x07,0xd0, |
2131 | | 0x4a,0x0d,0x04,0x4c,0x67,0x17,0x9a,0xad,0x03,0x97,0x5c,0x82,0x17,0xb1,0xd9,0x0f, |
2132 | | 0x2f,0xa1,0xd9,0x0b,0xfd,0x68,0xb6,0x51,0x87,0xbe,0xed,0x82,0x37,0x0d,0x30,0xf4, |
2133 | | 0xb7,0x9f,0x82,0xc5,0xe0,0x75,0xc2,0x5c,0x06,0x13,0xad,0x49,0x8e,0x66,0x3f,0x6a, |
2134 | | 0x42,0x73,0x70,0x57,0x99,0xa9,0x6a,0x84,0xfd,0x56,0x34,0xdb,0x0c,0x5d,0x6b,0x3e, |
2135 | | 0x8f,0xff,0x1d,0x0c,0x06,0xea,0xd6,0xa1,0xd9,0x4f,0xa0,0xef,0x1f,0xc3,0x15,0x5b, |
2136 | | 0xc1,0x36,0x97,0x6a,0xba,0xd1,0xec,0xc5,0x4a,0x34,0xdb,0xf2,0x09,0x9a,0x6d,0x83, |
2137 | | 0x0e,0xc3,0xc2,0x32,0x7b,0x19,0xae,0x72,0xe5,0x2a,0x9a,0xbd,0x0a,0xbe,0xbe,0xf4, |
2138 | | 0x11,0xec,0x7c,0x7a,0x01,0x7d,0x7b,0xbd,0x01,0xcd,0x76,0xc1,0xdd,0xfc,0xd2,0xc5, |
2139 | | 0x2b,0x68,0xb6,0x1b,0x5e,0x12,0x7b,0xe0,0xac,0x6e,0x30,0xc1,0x35,0x38,0xf3,0x1a, |
2140 | | 0xac,0x58,0x97,0xae,0x62,0xff,0xf5,0xc1,0x8d,0xe0,0xd2,0xa7,0x70,0x05,0xa8,0x5e, |
2141 | | 0xb8,0x74,0x03,0x46,0x7c,0xe3,0x0b,0x34,0x0b,0xcf,0x75,0xb3,0x3d,0x70,0x5e,0x5f, |
2142 | | 0x3d,0x24,0x18,0x9c,0x09,0x06,0x09,0x4f,0x41,0xb3,0xf8,0x41,0xe6,0x12,0xfe,0x4a, |
2143 | | 0xa4,0xaf,0x0f,0xcd,0xf6,0x83,0x1d,0xe1,0x76,0xff,0x6d,0x5f,0x2f,0x9a,0xc5,0x37, |
2144 | | 0xd8,0x4b,0x70,0xcf,0x9c,0xbd,0x05,0x9e,0x18,0x82,0x05,0xf5,0xd2,0x10,0x4c,0xc4, |
2145 | | 0x4b,0x77,0xe0,0x9a,0x5f,0x94,0xa1,0x67,0xf2,0x01,0x48,0xd0,0xa9,0x9b,0xf5,0x30, |
2146 | | 0x59,0xf4,0x90,0x86,0x20,0xdd,0x42,0xcf,0x60,0xdc,0x30,0x39,0xdb,0xd1,0x33,0x0d, |
2147 | | 0x34,0xdc,0xa6,0xbb,0x84,0x9e,0x95,0x81,0xf7,0xda,0x2a,0xf1,0xef,0xd9,0x3b,0xd0, |
2148 | | 0x33,0x1d,0x78,0xa3,0xad,0x41,0x8b,0x9e,0xe9,0x61,0xd1,0x81,0x85,0x69,0xa1,0xad, |
2149 | | 0x09,0x7f,0x95,0xd0,0x52,0x8b,0x9e,0x19,0x6f,0xa3,0x67,0x95,0xb0,0xfa,0xdd,0xc6, |
2150 | | 0x3f,0x6d,0x87,0xf7,0xba,0xdb,0xfd,0xe8,0x19,0xbc,0xf8,0x3c,0xab,0x69,0x42,0xcf, |
2151 | | 0x3e,0xd0,0xa0,0x67,0xe7,0xe1,0x35,0x78,0xf0,0x02,0x2c,0x55,0xe0,0xb7,0xb6,0xeb, |
2152 | | 0x37,0x21,0x03,0xf1,0xdd,0x76,0x03,0x87,0x57,0xd9,0x27,0xe8,0x59,0x03,0x6e,0xf9, |
2153 | | 0x4e,0x2b,0x16,0x88,0xad,0x76,0x85,0x1a,0x7d,0xfb,0xc5,0x20,0x9a,0x91,0xc3,0x23, |
2154 | | 0x42,0x3b,0xbc,0x16,0x82,0xc0,0x0d,0xa0,0x5d,0xdd,0x88,0xa5,0x17,0x3d,0x6b,0xc2, |
2155 | | 0xdf,0x1e,0xc2,0x69,0x30,0xef,0x66,0x14,0x65,0x68,0x46,0x09,0x4f,0x57,0xed,0xf8, |
2156 | | 0x6b,0xa7,0xd6,0x4a,0x34,0x03,0xaf,0x96,0x0b,0xed,0x0d,0x70,0xb3,0x69,0xff,0x08, |
2157 | | 0x1e,0xb0,0xda,0x2f,0xc0,0xd5,0xaf,0x7c,0x8a,0x66,0xd4,0x9f,0xc1,0xa2,0x09,0x63, |
2158 | | 0xed,0x84,0x67,0x8a,0xf6,0x76,0xb8,0x3b,0xb4,0x5f,0xbd,0x82,0x9e,0x7d,0x7a,0x0d, |
2159 | | 0xcd,0xe0,0x7b,0x71,0xfb,0x35,0x18,0xe3,0x67,0x60,0x9a,0xcf,0x74,0x50,0x00,0xcb, |
2160 | | 0x52,0xfb,0x0d,0x18,0x23,0x3c,0x36,0xcf,0xe8,0x61,0xc1,0x86,0x07,0xda,0x67,0xf0, |
2161 | | 0xb4,0xfb,0x0c,0xee,0x87,0x0b,0xed,0x77,0xe0,0x28,0x13,0xac,0xe6,0x06,0x58,0x85, |
2162 | | 0x6f,0xc1,0x10,0xfb,0x95,0xe8,0xd9,0x80,0x06,0xf6,0xe1,0xce,0x74,0x19,0xcc,0xb4, |
2163 | | 0x70,0x59,0x57,0x8e,0x66,0x8c,0xd0,0xd7,0xcb,0x15,0x8d,0xe8,0xd9,0x10,0xdc,0x92, |
2164 | | 0x2e,0x1b,0xee,0xa0,0x67,0x77,0xea,0xd0,0xb3,0x2f,0xf0,0x0e,0x7e,0xb3,0xbb,0x5c, |
2165 | | 0x7b,0x09,0xcd,0x29,0xe0,0x7e,0x79,0x19,0xde,0x76,0xe6,0x60,0xc1,0x5a,0xb8,0x64, |
2166 | | 0xfc,0x04,0x82,0xae,0x0e,0x82,0xef,0x06,0x9a,0x53,0xab,0xd0,0x4c,0x75,0x05,0x6c, |
2167 | | 0xef,0x20,0xf3,0x55,0xb0,0xf1,0xe5,0x8f,0xaf,0x60,0x81,0xdc,0xa5,0x4a,0x1c,0x8b, |
2168 | | 0x95,0x10,0xa4,0x5a,0x35,0x9a,0xbb,0xf3,0x31,0x9a,0xa9,0xf9,0x14,0xcd,0xe9,0x6b, |
2169 | | 0x20,0xc1,0xf1,0x7a,0xfc,0x63,0xd3,0x5e,0xd8,0xc2,0x94,0xb5,0x6e,0x87,0xd0,0x5c, |
2170 | | 0x05,0x98,0xe2,0x72,0xd7,0x20,0x9a,0x33,0x34,0xa3,0x39,0x23,0x5c,0xb6,0xb2,0x1b, |
2171 | | 0xf2,0x78,0x0b,0x95,0x55,0x57,0xa0,0xec,0x3c,0x6c,0xf5,0x90,0x0c,0x90,0xc0,0xdf, |
2172 | | 0x97,0xc1,0x3f,0x0b,0x97,0x61,0xe1,0x58,0xb8,0x0c,0x2f,0x0a,0x33,0xb5,0xd0,0x3e, |
2173 | | 0xbc,0x19,0xce,0xc1,0x3b,0xe1,0x5c,0x2d,0x18,0xfa,0x0a,0x3e,0xb6,0x0e,0xfc,0x78, |
2174 | | 0x19,0x1e,0x19,0x66,0xea,0x9a,0x21,0x81,0xe3,0x2e,0xdf,0x81,0xfb,0xf4,0x15,0x15, |
2175 | | 0x18,0xac,0x0e,0x8e,0x6f,0xac,0x86,0x04,0x4d,0x37,0x76,0xa2,0xb9,0x8f,0x70,0xd2, |
2176 | | 0xa2,0xb9,0xa6,0x4a,0x34,0x77,0xe1,0x22,0x6c,0x61,0xc0,0xcd,0x70,0xcc,0xc7,0xe0, |
2177 | | 0xb8,0x0f,0x3f,0x44,0x73,0x9f,0xb4,0xa2,0xb9,0x16,0x05,0xe4,0x07,0xd0,0x5c,0x2b, |
2178 | | 0x58,0xe4,0x0a,0x3e,0x11,0x1e,0x95,0xe7,0xe0,0x59,0x78,0xa6,0xc1,0x04,0x5b,0x58, |
2179 | | 0x45,0x3e,0x80,0x19,0x72,0xe5,0x22,0x04,0xf2,0x95,0xf6,0xcb,0x68,0xe6,0xa3,0x3b, |
2180 | | 0x68,0xe6,0x42,0x39,0x9a,0xbb,0x8a,0x0f,0xbf,0x01,0xed,0xdd,0x80,0xf6,0xe0,0xc5, |
2181 | | 0x69,0xae,0xef,0x02,0x9a,0xc3,0xef,0x08,0x57,0x06,0xe1,0xf9,0xa1,0xa5,0x05,0x2c, |
2182 | | 0x84,0xbf,0x6c,0xbc,0x09,0x83,0xbf,0x05,0x26,0x6e,0x81,0x16,0xe7,0x3e,0x87,0x67, |
2183 | | 0xf2,0x8e,0x0f,0x3f,0xc0,0xd2,0x8d,0x2c,0xca,0x5a,0x64,0x51,0xf5,0x20,0x8b,0x1a, |
2184 | | 0x9e,0x2f,0x3b,0x9a,0xae,0x41,0xe6,0x02,0xb2,0x68,0xfb,0x91,0xa5,0xe2,0x43,0x48, |
2185 | | 0x0d,0xc8,0xa2,0x1b,0x44,0x96,0xaa,0x01,0x64,0xa9,0x86,0x70,0xef,0xf8,0xec,0x36, |
2186 | | 0xb2,0xd4,0x43,0xcc,0x5d,0x86,0x1b,0x32,0x7e,0xbf,0xec,0x80,0x6b,0xcd,0x5c,0xb9, |
2187 | | 0x8c,0x2c,0x17,0x60,0x91,0xbe,0x79,0x03,0x59,0x9a,0x20,0xf6,0x3a,0xf1,0xe4,0xe9, |
2188 | | 0xd4,0x7e,0x84,0x66,0x3a,0x21,0xb8,0x3a,0xe1,0x9e,0xfc,0x09,0x74,0xb3,0xb3,0x5a, |
2189 | | 0x8f,0x66,0xae,0x42,0x14,0x77,0x7e,0x50,0x8f,0x2c,0x2d,0xf0,0xf0,0xd3,0x89,0x6f, |
2190 | | 0xd7,0x97,0xe0,0xde,0xd9,0xd5,0x8b,0x2c,0xf0,0x34,0x64,0xb9,0x7c,0x05,0x59,0xae, |
2191 | | 0x28,0x21,0xc1,0xe8,0x3e,0x83,0xe9,0xdf,0xd9,0x75,0x1d,0x59,0x7a,0xe4,0xc8,0xd2, |
2192 | | 0x0b,0x77,0x5b,0x78,0xab,0x9b,0x81,0xd7,0x27,0x8b,0x09,0x02,0xe1,0x2a,0xfe,0xc5, |
2193 | | 0x40,0x2f,0x4c,0x94,0xab,0x6a,0xb8,0xd4,0x55,0x2d,0x1c,0x7b,0x15,0x22,0x60,0xc6, |
2194 | | 0x04,0x2d,0x7f,0x7e,0x07,0x59,0xe0,0xed,0xd4,0x32,0x58,0x05,0x09,0xbc,0x75,0xb5, |
2195 | | 0x41,0x8e,0x90,0xcd,0xba,0xf5,0xb6,0x76,0x1b,0x36,0x6e,0xb4,0x27,0x6c,0x7a,0xc5, |
2196 | | 0xc1,0xf1,0x55,0xa7,0x8d,0x3f,0x7e,0x9c,0x37,0xba,0x6c,0xde,0xe2,0x4a,0xdc,0xba, |
2197 | | 0xcd,0xcd,0xba,0xeb,0xbe,0x71,0xfb,0x6b,0x1e,0x9e,0x3b,0x5e,0xf7,0xf2,0xde,0xf8, |
2198 | | 0x8b,0x7f,0x76,0xee,0x02,0xf1,0xf9,0x59,0x9b,0x24,0xed,0xde,0xb3,0xd7,0x77,0xdf, |
2199 | | 0x1b,0xd6,0xbc,0xdf,0x46,0xf2,0x0f,0xc5,0xfe,0x01,0x1b,0x29,0xd4,0xdf,0x41,0xe6, |
2200 | | 0xcd,0x9f,0xe9,0x3a,0xb4,0x9f,0xe4,0xe9,0x3f,0x43,0x7b,0x6f,0xfd,0xf9,0xaa,0xb7, |
2201 | | 0xb1,0x04,0x6e,0xdc,0xc8,0x08,0xda,0xcf,0xfc,0xbe,0x28,0xf8,0x9d,0x3f,0x38,0xe2, |
2202 | | 0xdd,0x8d,0x1b,0x0f,0x84,0xfc,0xb0,0x73,0x70,0xe3,0x6f,0xf8,0x73,0x28,0x34,0x6c, |
2203 | | 0xe3,0xda,0x67,0xed,0xb3,0xf6,0x59,0xfb,0xac,0x7d,0xd6,0x3e,0x6b,0x9f,0xb5,0xcf, |
2204 | | 0xda,0x67,0xed,0xb3,0xf6,0x59,0xfb,0xac,0x7d,0x7e,0x3b,0x1f,0x64,0xbb,0xc6,0x3f, |
2205 | | 0x84,0x1d,0xb2,0xff,0x03,0x08,0xc8,0x19,0xb9,0x20,0xd7,0xef,0x21,0x22,0x0f,0xc0, |
2206 | | 0x13,0x79,0x23,0x12,0x22,0x23,0x0a,0x40,0x45,0x0c,0x14,0x8c,0x0e,0xa0,0x10,0xc4, |
2207 | | 0x41,0xc9,0x28,0x1d,0xe0,0x23,0x11,0x92,0x22,0x35,0x32,0xa0,0x5a,0xa0,0x09,0xb5, |
2208 | | 0xa1,0x2e,0xd4,0x87,0x06,0xd1,0x3d,0xf4,0x00,0x3d,0x42,0x4f,0x80,0x19,0xf4,0x1c, |
2209 | | 0xbd,0x40,0x2f,0x91,0xad,0x8d,0x83,0x15,0x57,0x1b,0x0f,0x1b,0x1f,0x1b,0x3f,0x1b, |
2210 | | 0x9a,0x15,0xa6,0x4d,0xa8,0x0d,0xdb,0x26,0xc1,0x26,0xc5,0x26,0x1d,0xe0,0xdb,0x88, |
2211 | | 0x6c,0xa4,0x36,0x6a,0x1b,0x83,0x4d,0xad,0x4d,0x93,0x4d,0x9b,0x4d,0x17,0xd0,0x67, |
2212 | | 0x33,0x68,0x73,0xcf,0xe6,0x81,0xcd,0x23,0x9b,0x27,0x56,0x66,0x6c,0x9e,0xdb,0xbc, |
2213 | | 0xb0,0x79,0x69,0x63,0xbb,0xce,0x76,0x9d,0x03,0xe0,0xba,0xce,0x63,0x9d,0xcf,0x3a, |
2214 | | 0xbf,0x75,0xb4,0x75,0xcc,0x75,0xa1,0xeb,0xd8,0xeb,0x12,0xd6,0xa5,0xac,0x4b,0x5f, |
2215 | | 0xc7,0x5f,0x27,0x5a,0x27,0x5d,0xa7,0x5e,0x67,0xb0,0x52,0xbb,0xae,0x69,0x5d,0xdb, |
2216 | | 0xba,0xae,0x75,0x7d,0xeb,0x06,0xd7,0xdd,0x5b,0xf7,0x60,0xdd,0xa3,0x75,0x4f,0xd6, |
2217 | | 0xcd,0xac,0x7b,0xbe,0xee,0xc5,0xba,0x97,0xeb,0x6c,0xd7,0x3b,0xac,0x77,0x5d,0xef, |
2218 | | 0xb1,0xde,0x67,0xbd,0x9f,0x15,0xda,0x7a,0xe6,0xfa,0xd0,0xf5,0xec,0xf5,0x09,0xeb, |
2219 | | 0x53,0xd6,0xa7,0xaf,0xe7,0xaf,0x17,0xad,0x17,0xaf,0x97,0xad,0x57,0xaf,0x37,0xac, |
2220 | | 0xaf,0x5d,0xdf,0xb4,0xbe,0x0d,0xe8,0x5a,0xdf,0xb7,0x7e,0x70,0xfd,0xbd,0xf5,0x0f, |
2221 | | 0xd6,0x4f,0xac,0x9f,0x5a,0x3f,0x63,0xe5,0xf9,0xfa,0x17,0xeb,0x5f,0xae,0xb7,0xb5, |
2222 | | 0x75,0xb0,0x25,0xda,0x7a,0x58,0xf1,0xb1,0xf5,0xb3,0xa5,0xd9,0x32,0x6d,0x43,0x6d, |
2223 | | 0xd9,0x56,0x12,0x6c,0x53,0x6c,0xd3,0x6d,0xf9,0xb6,0x22,0x5b,0xa9,0xad,0xda,0xd6, |
2224 | | 0x60,0x5b,0x6b,0xdb,0x64,0xdb,0x66,0xdb,0x65,0xdb,0x67,0x3b,0x68,0x7b,0xcf,0xf6, |
2225 | | 0x81,0xed,0x23,0xdb,0x27,0x56,0x66,0x6c,0x9f,0xdb,0xbe,0xb0,0x7d,0x69,0x6b,0x6b, |
2226 | | 0xe7,0x60,0xe7,0x6a,0xe7,0x61,0xe7,0x63,0xe7,0x67,0x47,0xb3,0x63,0xda,0x85,0xda, |
2227 | | 0xb1,0xed,0x12,0xec,0x52,0xec,0xd2,0xed,0xf8,0x76,0x22,0x3b,0xa9,0x9d,0xda,0xce, |
2228 | | 0x60,0x57,0x67,0xd7,0xf0,0x0f,0xd3,0x62,0xd7,0xf1,0xdf,0x70,0xdd,0xae,0xff,0xaf, |
2229 | | 0x62,0xc0,0x6e,0xc4,0x6e,0xdc,0x6e,0xca,0xce,0x6c,0x37,0x6f,0xb7,0x64,0xb7,0x62, |
2230 | | 0x67,0xb7,0xc1,0x61,0x83,0xeb,0x06,0x8f,0x0d,0x3e,0x1b,0xfc,0x36,0xd0,0x36,0x30, |
2231 | | 0x37,0x84,0x6e,0x60,0x6f,0x48,0xda,0x90,0xbe,0x21,0x67,0x83,0x74,0x83,0x76,0x43, |
2232 | | 0xed,0x86,0x96,0x0d,0x5d,0x40,0xff,0x86,0x7b,0x1b,0x1e,0x6e,0x78,0xb2,0x61,0x66, |
2233 | | 0xc3,0x73,0x2b,0x2f,0x36,0xbc,0xdc,0x60,0xbb,0xd1,0x61,0xa3,0xeb,0x46,0x8f,0x8d, |
2234 | | 0x7b,0x37,0xd2,0x36,0x32,0x37,0x86,0x6e,0xe4,0x6c,0x4c,0xdc,0x98,0xba,0x31,0x7d, |
2235 | | 0x23,0x7f,0xa3,0xc8,0x8a,0x74,0xa3,0x7a,0x63,0xf5,0xc6,0xa6,0x8d,0x6d,0x1b,0xbb, |
2236 | | 0x36,0xf6,0x6d,0x1c,0x04,0xee,0x6d,0x7c,0xb0,0xf1,0xd1,0xc6,0x27,0x1b,0x67,0x36, |
2237 | | 0x3e,0xdf,0xf8,0x62,0xe3,0xcb,0x8d,0xb6,0xf6,0x0e,0xf6,0xae,0xf6,0x1e,0xf6,0x3e, |
2238 | | 0xf6,0x7e,0xf6,0x34,0x7b,0xa6,0x7d,0xa8,0x3d,0xdb,0x3e,0xc1,0x3e,0xc5,0x3e,0xdd, |
2239 | | 0x9e,0x6f,0x2f,0xb2,0x97,0xda,0xab,0xed,0x0d,0xf6,0xb5,0xf6,0x4d,0x56,0xda,0xec, |
2240 | | 0xbb,0xfe,0x80,0x3e,0xfb,0x41,0xfb,0x7b,0xf6,0x0f,0xec,0x1f,0xdb,0xcf,0xd8,0x2f, |
2241 | | 0xd8,0xbf,0xb4,0xb7,0x25,0x38,0x10,0xdc,0x08,0x3e,0x04,0x3f,0x02,0xed,0x37,0x0a, |
2242 | | 0x9d,0xc0,0x20,0x04,0x13,0x42,0x08,0x61,0x04,0x16,0x81,0x43,0x88,0x25,0x24,0x12, |
2243 | | 0x92,0xfe,0x21,0x92,0x09,0x69,0x04,0x1e,0x41,0x48,0x90,0x10,0x14,0x04,0x2d,0xa0, |
2244 | | 0x23,0x18,0x09,0x35,0x84,0x3a,0x42,0x23,0xa1,0xe9,0x57,0x4b,0x0b,0xa1,0x0d,0xe8, |
2245 | | 0x20,0x5c,0xff,0x27,0xd3,0xf7,0x23,0x26,0xc2,0xe0,0xf7,0xdc,0xfd,0x91,0x61,0xc2, |
2246 | | 0x97,0x84,0x87,0x84,0xc7,0x84,0x27,0x84,0x19,0xc2,0x73,0xc2,0x0b,0xe0,0x25,0x60, |
2247 | | 0xbb,0xc9,0x61,0x93,0xdb,0xdf,0x81,0xd7,0xa6,0xbd,0x9b,0x28,0x9b,0x02,0x37,0x1d, |
2248 | | 0xd8,0x14,0xbe,0x29,0xe1,0xef,0x20,0x65,0x53,0xfa,0x26,0xfe,0x26,0xd1,0x26,0xe9, |
2249 | | 0x26,0xd9,0x26,0xc5,0x26,0xcd,0x26,0xfd,0xa6,0x0f,0x36,0x35,0x6e,0x6a,0xde,0xd4, |
2250 | | 0xf2,0x37,0xd3,0xba,0xa9,0x7d,0x53,0xe7,0xa6,0xae,0x4d,0xdd,0x9b,0x7a,0x36,0xf5, |
2251 | | 0x59,0x31,0x6d,0xea,0xff,0x23,0xee,0x6e,0xba,0x0f,0x3c,0xfc,0x9e,0xc7,0x3f,0xf2, |
2252 | | 0x74,0xd3,0xdc,0xa6,0x85,0x3f,0xc9,0x77,0xff,0x20,0xe8,0x95,0xbf,0x05,0xfb,0x57, |
2253 | | 0x9c,0x01,0xb7,0xef,0xf1,0xfa,0x91,0xbd,0xaf,0x50,0x5e,0x09,0xfc,0x1b,0x39,0xf0, |
2254 | | 0x4a,0xf8,0xff,0x42,0x62,0x5e,0x49,0xfa,0x6f,0x38,0xfd,0x0a,0xf7,0x95,0x9c,0x57, |
2255 | | 0x0a,0xad,0xc8,0x5f,0xd1,0x5a,0xa9,0x7e,0xa5,0xe1,0x95,0x96,0x57,0x3a,0x5e,0xb9, |
2256 | | 0xfe,0x4a,0xbf,0x95,0xbb,0xaf,0xdc,0x7f,0xe5,0xe1,0x2b,0x8f,0x5f,0x79,0xfa,0xca, |
2257 | | 0x9c,0x95,0x85,0x57,0xbe,0x7b,0x05,0x39,0xd8,0x3b,0x38,0x3b,0xb8,0x39,0x78,0x39, |
2258 | | 0xec,0x75,0xa0,0x38,0x04,0x3a,0x1c,0x70,0x08,0xb7,0x12,0xe3,0x90,0xf4,0xab,0x26, |
2259 | | 0xd9,0x21,0xe5,0x9f,0x48,0xaa,0x43,0xba,0x95,0x0c,0x07,0x9e,0x03,0x7f,0x8d,0xbf, |
2260 | | 0x01,0x91,0x83,0xd4,0x41,0xed,0x60,0x70,0xa8,0xfd,0x5f,0x4c,0x9d,0x43,0xb3,0x43, |
2261 | | 0xbb,0x43,0xb7,0x43,0xdf,0xff,0x32,0x06,0x81,0x7b,0x7f,0x91,0x07,0xff,0x34,0xd0, |
2262 | | 0xda,0xe7,0x37,0xfe,0xf9,0x67,0x44,0xd5,0xa3,0x3f,0xe2,0x89,0x95,0x99,0x9f,0x89, |
2263 | | 0xe7,0x0e,0x2f,0x1c,0x5e,0x3a,0xd8,0x3a,0x3a,0x38,0xba,0x3a,0x7a,0x38,0xfa,0xfc, |
2264 | | 0x8b,0xe2,0xe7,0x48,0xfb,0x0b,0x30,0x1d,0x43,0x01,0xf6,0xaf,0x86,0x04,0x2b,0x29, |
2265 | | 0x3f,0x0b,0xe9,0x8e,0x7c,0x47,0x91,0x15,0xe9,0x1a,0xff,0x82,0xa8,0xad,0x18,0x1c, |
2266 | | 0x6b,0xff,0x02,0x4d,0x8e,0x6d,0xbf,0x28,0x5d,0xbf,0x20,0x7d,0x8e,0x83,0x8e,0xf7, |
2267 | | 0x7e,0xb3,0x3c,0xf8,0x8d,0xf1,0xe8,0x0f,0x78,0xe2,0x38,0x03,0x3c,0x77,0xfc,0xee, |
2268 | | 0x37,0x0e,0x7a,0xd5,0xfe,0x55,0xe7,0x35,0xfe,0x2c,0x6e,0x80,0xd7,0xab,0x7e,0xaf, |
2269 | | 0xd2,0x7e,0x35,0xd0,0x5f,0x65,0xfe,0xa6,0x09,0x7e,0x35,0xf4,0x67,0x26,0xec,0x55, |
2270 | | 0xce,0xab,0x09,0xff,0x54,0x12,0x5f,0x4d,0xfa,0x45,0x39,0xfd,0x27,0xe0,0xfe,0x48, |
2271 | | 0xce,0x8f,0x14,0xfe,0x88,0xfc,0xcf,0xa2,0xfd,0x13,0x54,0x03,0x0d,0xaf,0xb6,0xbe, |
2272 | | 0xda,0xf5,0xaa,0xe9,0xd5,0xbb,0x7f,0xc4,0xfd,0xbf,0x82,0x87,0x7f,0x82,0xc7,0x3f, |
2273 | | 0xf2,0xf4,0x47,0xe6,0x7e,0x64,0xe1,0xcf,0xf2,0xdd,0xbf,0x30,0xc8,0x69,0x8d,0x5f, |
2274 | | 0x07,0x36,0x4e,0xb6,0x7f,0x12,0x07,0xc0,0x15,0xf0,0x00,0x7c,0x00,0xbf,0xef,0xa1, |
2275 | | 0xfd,0xec,0x30,0x81,0x50,0x2b,0x6c,0xa7,0x04,0x20,0x65,0x8d,0x7f,0x31,0x52,0x9d, |
2276 | | 0xd2,0x9c,0x32,0x9c,0xb8,0x4e,0x3c,0x27,0x81,0x93,0xd0,0x49,0xec,0x24,0x71,0x92, |
2277 | | 0x39,0x29,0x9c,0x34,0x4e,0x3a,0x27,0xa3,0x53,0x8d,0x53,0xad,0x53,0x9d,0x53,0xa3, |
2278 | | 0x53,0xb3,0x53,0xab,0x53,0xbb,0x53,0xa7,0x53,0xb7,0x53,0x8f,0x93,0xc9,0x69,0xc0, |
2279 | | 0x69,0xc8,0x69,0xd8,0x69,0xc4,0x69,0xd4,0x69,0xcc,0x69,0xdc,0x69,0xc2,0x69,0xd2, |
2280 | | 0xe9,0x89,0xd3,0x94,0xd3,0xb4,0x93,0xd9,0xc9,0xe2,0x34,0xef,0xb4,0xe8,0xb4,0xe4, |
2281 | | 0xb4,0xec,0xb4,0xe2,0x64,0xe3,0x6c,0xe7,0x4c,0x70,0x76,0x74,0x76,0x71,0x26,0x3a, |
2282 | | 0xbb,0x3b,0x7b,0x3a,0x7b,0x3b,0x93,0x9c,0x7d,0x9d,0xc9,0xce,0x54,0x67,0xba,0x33, |
2283 | | 0xc3,0x39,0xd8,0x39,0xc4,0x39,0xcc,0x99,0xe5,0xcc,0xfe,0xb3,0x70,0x9c,0x63,0x7e, |
2284 | | 0x06,0x62,0x9d,0x13,0x9d,0x93,0x9d,0x53,0x9d,0xd3,0x9c,0x33,0x9c,0x79,0xce,0x02, |
2285 | | 0x67,0xa1,0xb3,0xd8,0x59,0xe2,0x2c,0x73,0x56,0x38,0x6b,0x9c,0x75,0xce,0x46,0xe7, |
2286 | | 0x1a,0xe7,0x3a,0xe7,0x46,0xe7,0x66,0xe7,0x56,0xe7,0x76,0xe7,0x4e,0xe7,0x6e,0xe7, |
2287 | | 0x1e,0x67,0x93,0xf3,0x80,0xf3,0x90,0xf3,0xb0,0xf3,0x88,0xf3,0xa8,0xf3,0x98,0xf3, |
2288 | | 0xb8,0xf3,0x84,0xf3,0xa4,0xf3,0x94,0xf3,0xb4,0xf3,0xcc,0xff,0x02,0x9e,0x3b,0xbf, |
2289 | | 0x70,0x7e,0xe9,0x6c,0xeb,0xe2,0xe0,0xe2,0xea,0xe2,0xe1,0xe2,0xe3,0x42,0x71,0x61, |
2290 | | 0xba,0x84,0xba,0xb0,0x5d,0x12,0x5c,0x52,0x5c,0xd2,0x5d,0xf8,0x2e,0x22,0x17,0xa9, |
2291 | | 0x8b,0xda,0xc5,0xe0,0xd2,0xe0,0xd2,0xe6,0x72,0xdd,0x65,0xd0,0xe5,0x9e,0xcb,0x03, |
2292 | | 0x97,0x47,0x2e,0x4f,0x5c,0xe6,0x5c,0x5e,0xb8,0xbc,0x74,0xb1,0xdd,0xec,0xb0,0xd9, |
2293 | | 0x75,0xb3,0xc7,0x66,0x9f,0xcd,0x7e,0x9b,0x69,0x9b,0x99,0x9b,0x43,0x37,0xb3,0x37, |
2294 | | 0x27,0x6c,0x4e,0xd9,0x9c,0xbe,0x99,0xbf,0x59,0xb4,0x59,0xbe,0xd9,0xb0,0xb9,0x76, |
2295 | | 0x73,0xd3,0xe6,0xb6,0xcd,0x5d,0x9b,0xfb,0x36,0x0f,0x6e,0xbe,0xb7,0xf9,0xc1,0xe6, |
2296 | | 0xc7,0x9b,0x67,0x36,0x3f,0xdf,0xfc,0x62,0xf3,0xcb,0xcd,0xb6,0x5b,0x1c,0xb6,0xb8, |
2297 | | 0x6e,0xf1,0xd8,0xe2,0xb3,0xc5,0x6f,0x0b,0x6d,0x0b,0x73,0x4b,0xe8,0x16,0xf6,0x96, |
2298 | | 0x84,0x2d,0x29,0x5b,0xd2,0xb7,0xf0,0xb7,0x88,0xb6,0xc8,0xb7,0x18,0xb6,0x34,0x6c, |
2299 | | 0x69,0xdb,0x72,0x7d,0xcb,0xe0,0x96,0xfb,0x5b,0x1e,0x6d,0x79,0xb2,0x65,0x66,0xcb, |
2300 | | 0xf3,0x2d,0x2f,0xb6,0xbc,0xdc,0x62,0xeb,0xea,0xe0,0xea,0xea,0xea,0xe5,0xea,0xe7, |
2301 | | 0x4a,0x73,0x65,0xba,0x86,0xba,0xb2,0x5d,0x13,0x5c,0x53,0x5c,0xb9,0xae,0x22,0x57, |
2302 | | 0xb9,0xab,0xc1,0xb5,0xc1,0xb5,0xcd,0xb5,0xcb,0xb5,0xcf,0x75,0xd0,0xf5,0x9e,0xeb, |
2303 | | 0x03,0xd7,0x47,0xae,0x4f,0x5c,0x67,0x5c,0x9f,0xbb,0xbe,0x70,0x7d,0xe9,0x6a,0x4b, |
2304 | | 0x74,0x20,0xba,0x12,0xbd,0x88,0x7e,0xc4,0x40,0x62,0x28,0x91,0x4d,0x4c,0x20,0xa6, |
2305 | | 0x10,0xd3,0x89,0x7c,0xa2,0x88,0x28,0x25,0xaa,0x89,0x06,0x62,0x2d,0xb1,0x89,0xd8, |
2306 | | 0x46,0xec,0x22,0xf6,0x11,0x07,0x89,0xf7,0x88,0x0f,0x88,0x8f,0x88,0x4f,0x88,0x33, |
2307 | | 0xc4,0xe7,0xc4,0x17,0xc4,0x97,0x44,0xdb,0xad,0x0e,0x5b,0x5d,0xb7,0x7a,0x6c,0xf5, |
2308 | | 0xd9,0xea,0xb7,0x95,0xbe,0xf5,0x9d,0xad,0xa1,0x3f,0xc2,0xde,0x9a,0xb0,0x35,0x65, |
2309 | | 0x6b,0xfa,0xd6,0x9c,0xad,0xd2,0xad,0xda,0xad,0xb5,0x5b,0x5b,0xb6,0x76,0x6d,0xed, |
2310 | | 0xdf,0x7a,0x6f,0xeb,0xc3,0xad,0x4f,0xb6,0xce,0x6d,0x7d,0xb1,0x15,0x6d,0x73,0xd8, |
2311 | | 0xe6,0xb6,0xcd,0x67,0x1b,0x65,0x1b,0x73,0x5b,0xf8,0xb6,0x84,0x6d,0x29,0xdb,0xd2, |
2312 | | 0xb7,0xf1,0xb7,0x89,0xb6,0x49,0xb7,0xa9,0xb7,0x55,0x6f,0x6b,0xda,0xd6,0xb1,0xad, |
2313 | | 0x6f,0xdb,0xdd,0x6d,0x0f,0xb6,0x3d,0xde,0x36,0xb3,0x6d,0x61,0xdb,0xcb,0x6d,0xb6, |
2314 | | 0x6e,0x0e,0x6e,0xae,0x6e,0x1e,0x6e,0x3e,0x6e,0x7e,0x6e,0x34,0x37,0xa6,0x5b,0xb8, |
2315 | | 0x5b,0x82,0xdb,0x69,0x37,0xbe,0x5b,0xa1,0x9b,0xda,0xad,0xda,0xad,0xc9,0xad,0xc3, |
2316 | | 0xad,0xcf,0xed,0xae,0xdb,0x03,0xb7,0xc7,0x6e,0x33,0x6e,0x0b,0x6e,0x2f,0xdd,0xec, |
2317 | | 0xdd,0x5d,0xdd,0xbd,0xdc,0xfd,0xdc,0x69,0xee,0x4c,0xf7,0x50,0x77,0xb6,0x7b,0x92, |
2318 | | 0x7b,0xba,0x7b,0x8e,0xbb,0xd4,0x5d,0xeb,0x5e,0xeb,0xde,0xe2,0xde,0xe5,0xde,0xef, |
2319 | | 0x7e,0xcf,0xfd,0x81,0xfb,0x23,0xf7,0x27,0xee,0x33,0xee,0xcf,0xdd,0x5f,0xb8,0xbf, |
2320 | | 0x74,0xb7,0xdd,0xfe,0x87,0x38,0x6c,0x77,0xdd,0xee,0xb5,0xdd,0x6f,0x7b,0xe0,0xf6, |
2321 | | 0xd0,0xed,0x31,0xdb,0x53,0xb6,0xa7,0x6f,0xe7,0x6f,0x2f,0xdc,0xae,0xde,0x5e,0xbd, |
2322 | | 0xbd,0x69,0x7b,0xc7,0xf6,0xbe,0xed,0x83,0xdb,0xef,0x6d,0x7f,0xb8,0xfd,0xc9,0xf6, |
2323 | | 0xb9,0xed,0x2f,0xac,0xbc,0xdc,0x6e,0xfb,0x9a,0xf3,0x6b,0x1e,0xaf,0xed,0x7d,0x8d, |
2324 | | 0x66,0x85,0xf9,0x5a,0xe8,0x6b,0x31,0xaf,0xa5,0xbc,0xc6,0x7d,0x4d,0xf4,0x9a,0xfc, |
2325 | | 0x35,0xc3,0x6b,0xb5,0xaf,0x35,0xbd,0xd6,0xf1,0x5a,0xdf,0x6b,0x77,0x5f,0x7b,0xf0, |
2326 | | 0xda,0xe3,0xd7,0x66,0x5e,0x7b,0xfe,0xda,0x8b,0xd7,0x90,0x87,0x83,0x87,0x9b,0x87, |
2327 | | 0x8f,0x07,0xc5,0x83,0xe9,0x11,0xea,0xc1,0xf6,0x48,0xf2,0x48,0xf7,0xc8,0xf1,0x90, |
2328 | | 0x7a,0x68,0x3d,0x6a,0x3d,0x9a,0x3c,0xda,0x3c,0xae,0x7b,0x0c,0x7a,0xdc,0xf7,0x78, |
2329 | | 0x64,0xe5,0x89,0xc7,0x8c,0xc7,0x82,0xc7,0x4b,0x0f,0x7b,0x4f,0x57,0x2b,0x1e,0x9e, |
2330 | | 0x3e,0x9e,0x14,0x4f,0xa6,0x67,0xb8,0x67,0x82,0xe7,0x69,0x4f,0x3e,0x20,0x02,0xe4, |
2331 | | 0x80,0x01,0x68,0xf0,0x6c,0xf1,0xec,0xf0,0xec,0xf3,0xbc,0xeb,0xf9,0xc0,0xf3,0xb1, |
2332 | | 0xe7,0x8c,0xe7,0x82,0xe7,0x77,0x9e,0x68,0x87,0xc3,0x0e,0xb7,0x1d,0x3e,0x3b,0x28, |
2333 | | 0x3b,0x98,0x3b,0xc2,0x77,0xc4,0xec,0x48,0xda,0x71,0x7a,0x07,0x77,0x47,0xce,0x8e, |
2334 | | 0xc2,0x1d,0xf2,0x1d,0xda,0x1d,0xd5,0x3b,0x1a,0x76,0xb4,0xec,0xe8,0xd8,0x71,0x7d, |
2335 | | 0x47,0xbf,0x95,0x7b,0x3b,0x1e,0xee,0x78,0xba,0x63,0x61,0x07,0x7a,0xdd,0xf9,0x75, |
2336 | | 0xaf,0xd7,0x29,0xaf,0x33,0x5f,0x0f,0x7f,0x3d,0xe9,0x75,0xee,0xeb,0x85,0xaf,0x6b, |
2337 | | 0x5f,0x6f,0x78,0xbd,0xe3,0xf5,0xbe,0xd7,0xef,0xbe,0xfe,0xf0,0xf5,0xa7,0xaf,0x2f, |
2338 | | 0xbc,0x8e,0xbc,0x9c,0xbd,0xbc,0xbc,0xfc,0xbc,0x02,0xbd,0xc2,0xbd,0x92,0xbc,0xb8, |
2339 | | 0x5e,0x85,0x5e,0x5a,0xaf,0x06,0xaf,0x36,0xaf,0xeb,0x5e,0x77,0xbd,0x1e,0x7a,0x3d, |
2340 | | 0xf5,0x5a,0xf0,0x42,0xde,0xce,0xde,0x1e,0xde,0x7b,0xbd,0x03,0xbd,0xc3,0xbd,0x93, |
2341 | | 0xbc,0xb9,0xde,0x85,0xde,0x5a,0xef,0x6a,0xef,0x06,0xef,0x36,0xef,0x2e,0xef,0x7e, |
2342 | | 0xe0,0xae,0xf7,0x03,0xef,0x47,0xde,0x4f,0xbc,0x67,0xbc,0x9f,0x7b,0x2f,0x79,0xbf, |
2343 | | 0xf4,0xb6,0xd9,0x49,0xd8,0xb9,0x79,0xa7,0xdb,0x4e,0x9f,0x9d,0x7e,0x3b,0x03,0x81, |
2344 | | 0x03,0x3b,0xd9,0x3b,0x13,0x76,0xa6,0xec,0x4c,0xdf,0xc9,0xdf,0x99,0xbf,0xb3,0x64, |
2345 | | 0x67,0xd9,0x4e,0xc3,0xce,0xda,0x9d,0x4d,0x3b,0x3b,0x76,0xf6,0x59,0x19,0xdc,0x79, |
2346 | | 0x7f,0xe7,0xc3,0x9d,0x8f,0x77,0x3e,0xdd,0x39,0xb7,0xf3,0x3f,0x77,0xfe,0xdf,0x9d, |
2347 | | 0xff,0xef,0x4e,0xb4,0xcb,0x7e,0x97,0xf3,0x2e,0x8f,0x5d,0x7b,0x77,0x51,0x76,0x05, |
2348 | | 0xee,0x3a,0xb0,0x8b,0xbd,0x2b,0x61,0x57,0xca,0xae,0xf4,0x5d,0xfc,0x5d,0xf9,0xbb, |
2349 | | 0x4a,0x76,0xa9,0x77,0x69,0xad,0xd4,0xee,0x6a,0xda,0xd5,0x01,0x5c,0xdf,0x35,0xb8, |
2350 | | 0xeb,0xde,0xae,0x07,0xbb,0x1e,0xed,0x7a,0xb2,0x6b,0x76,0x97,0x65,0xd7,0xc2,0xae, |
2351 | | 0xff,0x0b,0xfc,0x3f,0xbb,0x96,0x77,0xad,0xec,0xb2,0xf1,0xb1,0xf3,0x21,0xf8,0x38, |
2352 | | 0xfa,0xb8,0xf8,0x10,0x7d,0xdc,0x7d,0x3c,0x7e,0x82,0xa7,0x8f,0xd7,0x8f,0x78,0xfb, |
2353 | | 0xec,0xfd,0x33,0xf8,0xfa,0x90,0x7d,0xe8,0x3e,0x07,0xfe,0x88,0x10,0x9f,0x50,0x2b, |
2354 | | 0x61,0x3e,0x1c,0x9f,0x24,0x9f,0x64,0x9f,0x34,0x1f,0xfe,0xf7,0x08,0x7c,0x44,0x3e, |
2355 | | 0x62,0x1f,0xe9,0x1f,0x21,0xf3,0xd1,0xf8,0x18,0x7d,0x6a,0xff,0x2c,0x75,0x3e,0x6d, |
2356 | | 0x7f,0x40,0xbb,0x4f,0xc7,0x5f,0xa0,0xd3,0xa7,0xdb,0xe7,0x3a,0xd0,0xe3,0x63,0xf2, |
2357 | | 0x19,0xf0,0x19,0xf2,0x19,0xf6,0x19,0xf1,0x19,0xf5,0x19,0xf3,0x19,0xf7,0x99,0xf0, |
2358 | | 0x99,0xf4,0x99,0xf2,0x99,0xf6,0x31,0xfb,0x58,0x7c,0xe6,0x7d,0x16,0x7d,0x96,0x7c, |
2359 | | 0x96,0x7d,0x56,0x7c,0x6c,0x48,0x76,0x24,0x02,0xc9,0x91,0xe4,0x42,0x22,0x92,0xdc, |
2360 | | 0x49,0x1e,0x24,0x4f,0x92,0x37,0x89,0x44,0xf2,0x25,0x91,0x49,0x54,0x12,0x9d,0xc4, |
2361 | | 0x20,0x05,0x93,0x42,0x48,0x61,0x24,0x16,0x89,0x43,0x8a,0x25,0x25,0x92,0x92,0x49, |
2362 | | 0x29,0x7f,0x44,0x2a,0x29,0xfd,0x57,0x45,0x06,0x20,0x24,0xc9,0x48,0x0a,0x92,0x96, |
2363 | | 0xa4,0x23,0xd5,0x91,0x5a,0x49,0x6d,0xa4,0x76,0x52,0x37,0xa9,0x87,0x64,0x22,0x0d, |
2364 | | 0x90,0x86,0x48,0xc3,0xa4,0x11,0xd2,0x28,0x69,0x8c,0x34,0x4e,0x7a,0x44,0x9a,0x20, |
2365 | | 0x4d,0x92,0x9e,0x02,0xd3,0x24,0x33,0xc9,0x42,0x9a,0x27,0x2d,0x92,0x5e,0x00,0x4b, |
2366 | | 0xa4,0x15,0x12,0x61,0xb7,0xf3,0x6e,0x97,0xdd,0xae,0x80,0xdb,0x6e,0xf7,0xdd,0x1e, |
2367 | | 0x80,0xd7,0x6e,0xdf,0xdd,0xe4,0xdd,0x94,0xdd,0xd4,0xdd,0xf4,0xdd,0x8c,0xdd,0xcc, |
2368 | | 0xdd,0xc1,0xbb,0x43,0x76,0x87,0xed,0x66,0xed,0xe6,0xec,0x8e,0xdd,0x9d,0xb8,0x3b, |
2369 | | 0x69,0x77,0xf2,0xee,0x8c,0xdd,0xbc,0xdd,0x82,0xdd,0xc2,0xdd,0xe2,0xdd,0x85,0xdf, |
2370 | | 0x23,0xd9,0x2d,0xdb,0xad,0xd8,0xad,0xd9,0xad,0xdb,0x6d,0xf8,0x09,0xc6,0xdd,0x8d, |
2371 | | 0xbb,0xdb,0x77,0x9b,0x76,0x0f,0xef,0x1e,0xdb,0x3d,0xb9,0xdb,0xbc,0x7b,0x71,0xf7, |
2372 | | 0xca,0x6e,0xc2,0x1e,0xe2,0x1e,0xef,0x3d,0xe4,0x3d,0x8c,0x3d,0x61,0x7b,0x38,0x7b, |
2373 | | 0x62,0xf7,0x24,0xef,0xc9,0xd8,0x23,0xd8,0x23,0xdc,0x23,0xd9,0xa3,0xd9,0x53,0xb7, |
2374 | | 0xa7,0x79,0x4f,0xeb,0x9e,0xce,0x3d,0xa6,0x3d,0x03,0x7b,0x86,0xf6,0x0c,0xef,0x19, |
2375 | | 0xd9,0x33,0xba,0x67,0x7c,0xcf,0xd4,0x1e,0xf3,0x1e,0xcb,0x9e,0xc5,0x3d,0x2b,0x7b, |
2376 | | 0x1c,0xf7,0x12,0xf7,0xba,0xef,0xf5,0xde,0x4b,0xde,0x4b,0xdd,0x4b,0xdf,0xcb,0xd8, |
2377 | | 0xcb,0xfc,0x2f,0x04,0xef,0x0d,0xff,0x8b,0xc4,0xec,0x4d,0xfa,0xab,0x38,0xfd,0x0f, |
2378 | | 0xc1,0xdd,0x9b,0xb3,0xb7,0xf0,0x17,0x44,0xfe,0x23,0x5a,0x2b,0xd5,0x7f,0x23,0x0d, |
2379 | | 0x40,0xcb,0x8f,0xb4,0xee,0xed,0xdc,0xdb,0xb7,0xd7,0xb4,0x77,0x68,0xef,0xfd,0xbf, |
2380 | | 0xc8,0x43,0x2b,0x8f,0xad,0x3c,0x05,0xe6,0xfe,0x26,0x16,0x80,0xef,0xfe,0x24,0xc8, |
2381 | | 0xd7,0xde,0xd7,0xd9,0xd7,0xcd,0xd7,0xcb,0xca,0x5e,0x5f,0x8a,0x95,0x40,0xdf,0x03, |
2382 | | 0x7f,0x40,0xb8,0x6f,0x8c,0x95,0x24,0xdf,0xd3,0x56,0xb8,0xbe,0x39,0x3f,0x0b,0x85, |
2383 | | 0xbe,0x72,0x5f,0xad,0x6f,0xf5,0x3f,0x9d,0x06,0xdf,0x16,0xdf,0x0e,0xdf,0xeb,0x7f, |
2384 | | 0x40,0xbf,0xef,0x5d,0xdf,0xfb,0xbe,0x0f,0xff,0xc7,0x78,0xe4,0xfb,0x78,0x8d,0x35, |
2385 | | 0x7e,0x21,0x26,0x7d,0xa7,0x7c,0xa7,0x7d,0xcd,0xbe,0x16,0xdf,0x79,0xdf,0x45,0xdf, |
2386 | | 0x25,0xdf,0x65,0xdf,0x15,0x5f,0xbb,0x7d,0x8e,0xfb,0x88,0xfb,0x3c,0xf7,0x91,0xf6, |
2387 | | 0x91,0xf7,0xd1,0xf7,0x05,0xef,0x0b,0xdb,0xc7,0xd9,0x97,0xb8,0x2f,0x6d,0x9f,0x60, |
2388 | | 0x9f,0x64,0x9f,0x66,0x5f,0xcd,0xbe,0xe6,0x7d,0x9d,0xfb,0x4c,0xfb,0x86,0xf7,0x8d, |
2389 | | 0xef,0x9b,0xde,0xb7,0xb8,0xcf,0xe6,0x0d,0x97,0x37,0xbc,0xdf,0xa0,0xbe,0x11,0xf2, |
2390 | | 0x46,0xec,0x1b,0x69,0x6f,0x08,0xdf,0x90,0xbc,0xa1,0x78,0x43,0xf7,0x46,0xcd,0x1b, |
2391 | | 0x8d,0x6f,0xb4,0xbe,0xd1,0xf9,0x46,0xcf,0x1b,0x03,0x6f,0x8c,0xbc,0x31,0xfe,0xc6, |
2392 | | 0xd4,0x1b,0x96,0x37,0x96,0xde,0xb0,0xf1,0x73,0xf4,0x73,0xf7,0x23,0xf9,0x51,0xfd, |
2393 | | 0x82,0xfd,0x58,0x7e,0x89,0x7e,0x69,0x7e,0x02,0x3f,0x89,0x9f,0xc6,0xaf,0xc6,0xaf, |
2394 | | 0xd9,0xaf,0xd3,0xcf,0xe4,0x37,0xec,0x37,0xe6,0x37,0xe9,0x67,0xf6,0x5b,0xf4,0x5b, |
2395 | | 0xf1,0x23,0x90,0x89,0x64,0x6f,0x32,0x99,0xcc,0x20,0x87,0x91,0x63,0xc9,0xa9,0x64, |
2396 | | 0x1e,0x59,0x4c,0x96,0x90,0x65,0x64,0x05,0x59,0x43,0xd6,0x91,0x8d,0xe4,0x1a,0x72, |
2397 | | 0x1d,0xb9,0x91,0xdc,0x4c,0x6e,0x25,0xb7,0x93,0x3b,0xc9,0xdd,0xe4,0x1e,0xb2,0x89, |
2398 | | 0x3c,0x40,0x1e,0x22,0x0f,0x93,0x47,0xc8,0xa3,0xe4,0x31,0xf2,0x38,0x79,0x82,0x3c, |
2399 | | 0x49,0x9e,0x22,0x4f,0x93,0xcd,0x64,0x0b,0x79,0x9e,0xbc,0x48,0x5e,0x22,0x2f,0x93, |
2400 | | 0x57,0xc8,0x36,0xfe,0x76,0xfe,0x04,0x7f,0x47,0x7f,0x17,0x7f,0xa2,0xbf,0xbb,0xbf, |
2401 | | 0xa7,0xbf,0xb7,0x3f,0xc9,0xdf,0xd7,0x9f,0xec,0x4f,0xf5,0xa7,0xfb,0x33,0xfc,0x83, |
2402 | | 0xfd,0x43,0xfc,0xc3,0xfc,0xc3,0x7f,0x06,0x58,0xfe,0x49,0xff,0x52,0x24,0xfb,0x67, |
2403 | | 0xf8,0x0b,0xfc,0x0b,0xff,0x85,0x90,0xaf,0xf1,0x0f,0xa1,0xf0,0xd7,0xf8,0x6b,0xd7, |
2404 | | 0xf8,0x97,0x47,0xe7,0x6f,0x58,0x63,0x8d,0x7f,0x22,0x46,0xff,0xea,0x5f,0x05,0x35, |
2405 | | 0xfe,0xb5,0x7f,0x86,0x3a,0xa0,0xd1,0xbf,0xd9,0xbf,0xd5,0xbf,0xdd,0xbf,0xd3,0xbf, |
2406 | | 0xdb,0xbf,0xc7,0xdf,0xe4,0x3f,0xe0,0x3f,0xe4,0x3f,0xec,0x3f,0xe2,0x3f,0xea,0x3f, |
2407 | | 0xe6,0x3f,0xee,0x3f,0xe1,0x3f,0xe9,0x3f,0xe5,0x3f,0xed,0x6f,0xf6,0xb7,0xf8,0xcf, |
2408 | | 0xfb,0x2f,0xfa,0x2f,0xf9,0x2f,0xfb,0xaf,0xf8,0xdb,0x04,0xd8,0x05,0x10,0x02,0x1c, |
2409 | | 0x03,0x5c,0x02,0x88,0x01,0xee,0x01,0x9e,0x01,0xde,0x01,0xa4,0x00,0xdf,0x00,0x72, |
2410 | | 0x00,0x35,0x80,0x1e,0xc0,0x08,0x08,0x0e,0x08,0x09,0x08,0x0b,0x60,0x05,0x70,0x02, |
2411 | | 0x62,0x03,0x12,0x03,0x92,0x03,0x52,0x03,0xd2,0x02,0x32,0x02,0x78,0x01,0x82,0x00, |
2412 | | 0x61,0x80,0x38,0x40,0x12,0x20,0x0b,0x50,0x04,0x68,0x02,0x74,0x01,0xc6,0x80,0x9a, |
2413 | | 0x80,0xba,0x80,0xc6,0x80,0xe6,0x80,0xd6,0x80,0xf6,0x80,0xce,0x80,0xee,0x80,0x9e, |
2414 | | 0x00,0x53,0xc0,0x40,0xc0,0x50,0xc0,0x70,0xc0,0x48,0xc0,0x68,0xc0,0x58,0xc0,0x78, |
2415 | | 0xc0,0x44,0xc0,0x64,0xc0,0x54,0xc0,0x74,0x80,0x39,0xc0,0x12,0x30,0x1f,0xb0,0x18, |
2416 | | 0xb0,0x14,0xb0,0x1c,0xb0,0x12,0x60,0x43,0xb1,0xa3,0x10,0x28,0x8e,0x14,0x17,0x0a, |
2417 | | 0x91,0xe2,0x4e,0xf1,0xa4,0x78,0x53,0x48,0xf0,0xa2,0x47,0xa6,0x50,0x29,0x74,0x0a, |
2418 | | 0x83,0x12,0x4c,0x09,0xa1,0x84,0x51,0x58,0x14,0x0e,0x25,0x96,0x92,0x48,0x49,0xa6, |
2419 | | 0xa4,0x52,0xd2,0x28,0x19,0x14,0x1e,0x45,0x40,0x11,0x52,0xc4,0x14,0x09,0x45,0x46, |
2420 | | 0x51,0x50,0x34,0x14,0x1d,0xc5,0x48,0xa9,0xa1,0xd4,0x51,0x1a,0x29,0xcd,0x94,0x56, |
2421 | | 0x4a,0x3b,0xa5,0x93,0xd2,0x4d,0xe9,0xa1,0x98,0x28,0x03,0x94,0x21,0xca,0x30,0x65, |
2422 | | 0x84,0x32,0x4a,0x19,0xa3,0x8c,0x53,0x26,0x28,0x93,0x94,0x29,0xca,0x34,0xc5,0x4c, |
2423 | | 0xb1,0x50,0xe6,0x29,0x8b,0x94,0x25,0xca,0x32,0x65,0x85,0x62,0x43,0xb5,0xa3,0x12, |
2424 | | 0xa8,0x8e,0x54,0x17,0x2a,0x91,0xea,0x4e,0xf5,0xa4,0x7a,0x53,0x49,0x54,0x5f,0x2a, |
2425 | | 0x99,0x4a,0xa5,0xd2,0xa9,0x0c,0x6a,0x30,0x35,0x84,0x1a,0x46,0x65,0x51,0x39,0xd4, |
2426 | | 0x58,0x6a,0x22,0x35,0x99,0x9a,0x4a,0x4d,0xa3,0x66,0x50,0x79,0x54,0x01,0x55,0x48, |
2427 | | 0x15,0x53,0x25,0x54,0x19,0x55,0x41,0xd5,0x50,0x75,0x54,0x23,0xb5,0x86,0x5a,0x47, |
2428 | | 0x6d,0xa4,0x36,0x53,0x5b,0xa9,0xed,0xd4,0x4e,0x6a,0x37,0xb5,0x87,0x6a,0xa2,0x0e, |
2429 | | 0x50,0x87,0xa8,0xc3,0xd4,0x11,0xea,0x28,0x75,0x8c,0x3a,0x4e,0x9d,0xa0,0x4e,0x52, |
2430 | | 0xa7,0xa8,0xd3,0x54,0x33,0xd5,0x42,0x7d,0xfe,0x4f,0x60,0x1e,0x58,0xf8,0xc5,0x58, |
2431 | | 0xa4,0xbe,0xa0,0x2e,0x51,0x97,0xa9,0x2b,0x54,0xf4,0xbb,0xbf,0x8c,0x3d,0xe0,0x0c, |
2432 | | 0xb8,0x01,0x5e,0xc0,0x5e,0x80,0x02,0x04,0x02,0x07,0x80,0x70,0x20,0x06,0x48,0x02, |
2433 | | 0x4e,0x5b,0xe1,0x02,0x39,0x40,0xe1,0x1f,0x20,0xff,0x9d,0x16,0xa8,0xfe,0x5d,0x03, |
2434 | | 0xd0,0xf2,0xbb,0x0e,0xe0,0xfa,0xef,0xfa,0x81,0xbb,0xbf,0xbb,0xff,0x37,0xf1,0xf0, |
2435 | | 0x27,0x8c,0xff,0x6e,0xf2,0x77,0x4f,0x01,0xcb,0xef,0x16,0xfe,0x2c,0xdf,0x01,0xe8, |
2436 | | 0x4d,0xf4,0xa6,0x3d,0xe0,0x0c,0xb8,0x01,0x5e,0xc0,0x5e,0x80,0x02,0x04,0x02,0x07, |
2437 | | 0x80,0x70,0x20,0xc6,0x4a,0x12,0x70,0x1a,0xe0,0xfe,0x01,0x39,0x6f,0x16,0x02,0xf2, |
2438 | | 0x37,0xb5,0x40,0xf5,0x9b,0x0d,0x40,0xcb,0x9b,0x1d,0xc0,0xf5,0x37,0xfb,0xff,0x26, |
2439 | | 0xee,0x5a,0xb9,0xff,0xe6,0xc3,0x37,0x1f,0xbf,0xf9,0xf4,0x7b,0x2c,0x6f,0x2e,0xfc, |
2440 | | 0x02,0x2c,0xbe,0xb9,0xf4,0xe6,0xf2,0x9b,0x2b,0x6f,0xda,0xd0,0xec,0x68,0x04,0x9a, |
2441 | | 0x23,0xcd,0x85,0x46,0xa4,0xb9,0xd3,0x3c,0x69,0xde,0x34,0x12,0xcd,0x97,0x46,0xa6, |
2442 | | 0x51,0x69,0x74,0x1a,0x83,0x16,0x4c,0x0b,0xa1,0x85,0xd1,0x58,0x34,0x0e,0x2d,0x96, |
2443 | | 0x96,0x48,0x4b,0xa6,0xa5,0xd2,0xd2,0x68,0x19,0x34,0x1e,0x4d,0x40,0x13,0xd2,0xc4, |
2444 | | 0x34,0x09,0x4d,0x46,0x53,0xd0,0x34,0x34,0x1d,0xcd,0x48,0xab,0xa1,0xd5,0xd1,0x1a, |
2445 | | 0x69,0xcd,0xb4,0x56,0x5a,0x3b,0xad,0x93,0xd6,0x4d,0xeb,0xa1,0x99,0x68,0x03,0xb4, |
2446 | | 0x21,0xda,0x30,0x6d,0x84,0x36,0x4a,0x1b,0xa3,0x8d,0xd3,0x26,0x68,0x93,0xb4,0x29, |
2447 | | 0xda,0x34,0xcd,0x4c,0xb3,0xd0,0xe6,0x69,0x8b,0xb4,0x25,0xda,0x32,0x6d,0x85,0x66, |
2448 | | 0x43,0xb7,0xa3,0x13,0xe8,0x8e,0x74,0x17,0x3a,0x91,0xee,0x4e,0xf7,0xa4,0x7b,0xd3, |
2449 | | 0x49,0x74,0x5f,0x3a,0x99,0x4e,0xa5,0xd3,0xe9,0x0c,0x7a,0x30,0x3d,0x84,0x1e,0x46, |
2450 | | 0x67,0xd1,0x39,0xf4,0x58,0x7a,0x22,0x3d,0x99,0x9e,0x4a,0x4f,0xa3,0x67,0xd0,0xb9, |
2451 | | 0x56,0x78,0x74,0x01,0x5d,0x48,0x17,0xd3,0x25,0x74,0x19,0x5d,0x41,0xd7,0xd0,0x75, |
2452 | | 0x74,0x23,0xbd,0x86,0x5e,0x47,0x6f,0xa4,0x37,0xd3,0x5b,0x7e,0xe5,0xb4,0x02,0xdd, |
2453 | | 0xf4,0x01,0xfa,0x08,0x7d,0x9c,0x3e,0x45,0xb7,0xd0,0x97,0xe8,0x36,0x6f,0x39,0xbe, |
2454 | | 0xe5,0xfe,0x16,0xe9,0x2d,0xea,0x5b,0xc1,0x6f,0xb1,0xde,0x4a,0x7e,0x8b,0xf7,0x96, |
2455 | | 0xe4,0x2d,0xdd,0x5b,0x8d,0x6f,0x75,0xbe,0x35,0xf0,0xd6,0xe8,0x5b,0x93,0x6f,0x59, |
2456 | | 0xde,0x5a,0x7e,0x8b,0xf0,0xb6,0xfb,0xdb,0xbe,0x6f,0x33,0xde,0x4e,0x7c,0x9b,0xff, |
2457 | | 0xb6,0xe0,0x6d,0xc9,0xdb,0x9a,0xb7,0x6b,0xde,0x6e,0x7e,0xbb,0xf3,0x6d,0xd3,0xdb, |
2458 | | 0xc3,0x6f,0x8f,0xbd,0x3d,0xf9,0xb6,0xf9,0xed,0xc5,0xb7,0x57,0xde,0x26,0x04,0x12, |
2459 | | 0x03,0xbd,0x03,0xc9,0x81,0x8c,0xc0,0xb0,0xc0,0xd8,0xc0,0xd4,0x40,0x5e,0xa0,0x38, |
2460 | | 0x50,0x11,0x68,0x0c,0x6c,0x0c,0x6c,0x0f,0xec,0x09,0x1c,0x0a,0x1c,0x0d,0x9c,0x08, |
2461 | | 0x9c,0x0e,0x9c,0x0f,0x5c,0x0e,0xb4,0x63,0xb8,0x30,0x3c,0x19,0xde,0x0c,0x12,0xc3, |
2462 | | 0x97,0xe1,0xf7,0x47,0x90,0x19,0x0c,0x46,0x08,0x83,0xc5,0x88,0x65,0x24,0x33,0xd2, |
2463 | | 0x18,0x3c,0x86,0x90,0x21,0x61,0x28,0x18,0x3a,0x46,0x0d,0xa3,0x91,0xd1,0xca,0xe8, |
2464 | | 0x64,0xf4,0x30,0x4c,0x8c,0x01,0xc6,0x10,0x63,0x98,0x31,0xc2,0x18,0x65,0x8c,0x31, |
2465 | | 0xc6,0x19,0x13,0x8c,0x49,0xc6,0x14,0x63,0x9a,0x61,0x66,0x58,0x18,0x8b,0x8c,0x65, |
2466 | | 0x86,0x4d,0x10,0x21,0xc8,0x25,0xc8,0x3d,0xc8,0x3b,0xc8,0x37,0x88,0x1a,0xc4,0x08, |
2467 | | 0x0a,0x09,0x62,0x05,0xc5,0x06,0x25,0x07,0x09,0x82,0x64,0x41,0xea,0x20,0x4d,0x90, |
2468 | | 0x2e,0xc8,0x18,0x54,0x13,0x54,0x17,0xd4,0x18,0xd4,0x1c,0xd4,0x1a,0xd4,0x1e,0xd4, |
2469 | | 0x19,0xd4,0x1d,0xd4,0x13,0x64,0x0a,0x1a,0x08,0x1a,0x0a,0x1a,0x0e,0x1a,0x09,0x1a, |
2470 | | 0x0d,0x1a,0x0b,0x1a,0x0f,0x9a,0x08,0x9a,0x0c,0x9a,0x0a,0x9a,0x0e,0x32,0x07,0x59, |
2471 | | 0x82,0xe6,0x83,0x16,0x83,0x96,0x82,0x96,0x83,0x56,0x82,0x6c,0xf6,0xdb,0xed,0x27, |
2472 | | 0xec,0x77,0xdc,0xef,0xb2,0x9f,0xb8,0xdf,0x7d,0xbf,0xe7,0x7e,0xef,0xfd,0xa4,0xfd, |
2473 | | 0xbe,0xfb,0xc9,0xfb,0xa9,0xfb,0xe9,0xfb,0x19,0xfb,0x83,0xf7,0x87,0xec,0x0f,0xdb, |
2474 | | 0xcf,0xda,0x1f,0xbb,0x3f,0x79,0x7f,0xda,0x7e,0xde,0x7e,0xe1,0x7e,0xc9,0x7e,0xc5, |
2475 | | 0x7e,0xdd,0xfe,0x9a,0xfd,0x8d,0xfb,0x5b,0xf7,0x77,0xee,0xef,0xd9,0x3f,0xb0,0x7f, |
2476 | | 0x78,0xff,0xe8,0xfe,0xf1,0xfd,0x93,0xfb,0xa7,0xf7,0x5b,0xf6,0x2f,0xee,0x5f,0xde, |
2477 | | 0x6f,0xc3,0x24,0x30,0x89,0x4c,0x6f,0x26,0x99,0x49,0x67,0x86,0x30,0x59,0xcc,0x44, |
2478 | | 0x66,0x32,0x33,0x95,0x99,0xc6,0xcc,0x60,0xf2,0x98,0x02,0xa6,0x90,0x29,0x66,0x4a, |
2479 | | 0x98,0x32,0xa6,0x82,0xa9,0x61,0xea,0x98,0x46,0x66,0x0d,0xb3,0x8e,0xd9,0xc8,0x6c, |
2480 | | 0x66,0xb6,0x32,0xdb,0x99,0x9d,0xcc,0x6e,0x66,0x0f,0xd3,0xc4,0x1c,0x60,0x0e,0x31, |
2481 | | 0x87,0x99,0x23,0xcc,0x51,0xe6,0x18,0x73,0x9c,0x39,0xc1,0x9c,0x64,0x4e,0x31,0xa7, |
2482 | | 0x99,0x66,0xa6,0x85,0x39,0xcf,0x5c,0x64,0x2e,0x31,0x97,0x99,0x2b,0x4c,0x9b,0x60, |
2483 | | 0xbb,0x60,0x42,0xb0,0x63,0xb0,0x4b,0xb0,0x3b,0x40,0x0e,0x0e,0x0e,0x8e,0x0d,0x4e, |
2484 | | 0x0d,0x16,0x06,0xcb,0x82,0x75,0xc1,0xad,0xc1,0x3d,0xc1,0x43,0xc1,0xa3,0xc1,0x13, |
2485 | | 0xc1,0xe6,0xe0,0xa5,0x60,0xbb,0x77,0x88,0xef,0x90,0xde,0xa1,0xbf,0x13,0xf6,0x4e, |
2486 | | 0xea,0x3b,0x19,0xef,0xc8,0xde,0xa9,0x7b,0xa7,0xf3,0x9d,0x81,0x77,0xc6,0xdf,0xb1, |
2487 | | 0xbc,0xb3,0xfc,0x8e,0xdd,0xbb,0x2e,0xef,0x7a,0xbf,0x4b,0x7d,0x37,0xec,0xdd,0xe4, |
2488 | | 0x77,0x33,0xde,0x15,0xbe,0xab,0x78,0xd7,0xf8,0x6e,0xe3,0xbb,0xad,0xef,0x76,0xbe, |
2489 | | 0x6b,0x7a,0x77,0xf8,0xdd,0xc9,0x77,0x2d,0xef,0xae,0xbc,0x4b,0x3c,0x40,0x3a,0x40, |
2490 | | 0x3d,0x10,0x7c,0x20,0xf1,0x40,0xc6,0x01,0xd9,0x01,0xdd,0x81,0xe6,0x03,0x9d,0x07, |
2491 | | 0x06,0x0e,0x8c,0x1c,0x98,0x38,0x60,0x39,0xb0,0x7c,0xc0,0x31,0xc4,0x33,0x84,0x14, |
2492 | | 0xc2,0x08,0x09,0x0b,0x89,0x0d,0x49,0x0b,0x11,0x84,0x48,0x42,0x34,0x21,0x8d,0x21, |
2493 | | 0x9d,0x21,0x3d,0x21,0xa3,0x21,0x13,0x21,0x96,0x90,0xe5,0x10,0xc2,0x41,0xe2,0x41, |
2494 | | 0xef,0x83,0xd4,0x83,0x8c,0x83,0xac,0x83,0xa9,0x07,0x33,0x0e,0xca,0x0e,0xea,0x0e, |
2495 | | 0xd6,0x1c,0x6c,0x3c,0xd8,0x7a,0xb0,0xf3,0x60,0xcf,0xc1,0x81,0x83,0xc3,0x07,0x47, |
2496 | | 0x0f,0x8e,0x1f,0x9c,0x3c,0x68,0x3e,0xb8,0x78,0x70,0xe5,0x20,0xe1,0x10,0xf1,0x90, |
2497 | | 0xf7,0x21,0xf2,0x21,0xc6,0xa1,0xb0,0x43,0xb1,0x87,0x52,0x0f,0xf1,0x0e,0x89,0x0f, |
2498 | | 0x29,0x0e,0x19,0x0f,0x35,0x1e,0x6a,0x3d,0xd4,0x79,0xc8,0x74,0x68,0xe8,0xd0,0xc8, |
2499 | | 0xa1,0xb1,0x43,0x93,0x87,0xcc,0x87,0xe6,0x0f,0x2d,0x1d,0x5a,0x39,0x64,0x17,0xea, |
2500 | | 0x18,0xea,0x19,0x4a,0x0a,0x25,0x87,0xd2,0x43,0x83,0x43,0xc3,0x42,0x39,0xa1,0x89, |
2501 | | 0xa1,0xa9,0xa1,0xbc,0x50,0x49,0xa8,0x22,0x54,0x17,0x5a,0x13,0xda,0x18,0xda,0x1a, |
2502 | | 0xda,0x19,0xda,0x13,0x3a,0x14,0x3a,0x1a,0x3a,0x11,0x3a,0x1d,0x6a,0x09,0x5d,0x0c, |
2503 | | 0x5d,0x0e,0xb5,0x09,0x23,0x84,0xb9,0x84,0xb9,0x87,0x79,0x87,0xf9,0x86,0x51,0xc3, |
2504 | | 0x82,0xc3,0x58,0x61,0xb1,0x61,0xa9,0x61,0xbc,0x30,0x71,0x98,0x2c,0x4c,0x17,0x56, |
2505 | | 0x17,0xd6,0x1e,0xd6,0x1d,0x36,0x10,0x36,0x12,0x36,0x1e,0x36,0x15,0xb6,0x18,0x46, |
2506 | | 0x38,0xec,0x72,0xd8,0xfd,0xb0,0xf7,0x61,0xdf,0xc3,0xd4,0xc3,0x8c,0xc3,0x21,0x87, |
2507 | | 0x59,0x87,0x63,0x0f,0x27,0x1f,0x4e,0x3b,0xcc,0x3b,0x2c,0x3c,0x2c,0x39,0xac,0x38, |
2508 | | 0xac,0x3b,0x5c,0x73,0xb8,0xf1,0x70,0xe7,0xe1,0x9e,0xc3,0x03,0x87,0x87,0x0f,0x8f, |
2509 | | 0x1f,0x9e,0x3a,0x6c,0x3e,0x3c,0x7f,0x78,0xe9,0xf0,0xca,0x61,0xbb,0x23,0x8e,0x47, |
2510 | | 0x88,0x47,0x3c,0x8f,0x90,0x8e,0x90,0x8f,0x30,0x8e,0x84,0x1c,0x61,0x1d,0x49,0x3c, |
2511 | | 0x92,0x76,0x84,0x77,0x44,0x72,0x44,0x73,0xc4,0x78,0xa4,0xee,0x48,0xf3,0x91,0xf6, |
2512 | | 0x23,0x3d,0x47,0x86,0x8e,0x8c,0x1c,0x19,0x3b,0x32,0x71,0x64,0xea,0x88,0xf9,0xc8, |
2513 | | 0xfc,0x91,0xa5,0x23,0x2b,0x47,0xec,0xc2,0x5d,0xc2,0x3d,0xc3,0x7d,0xc3,0xe9,0xe1, |
2514 | | 0x21,0xe1,0x9c,0xf0,0xe4,0xf0,0x8c,0x70,0x61,0xb8,0x2c,0x5c,0x17,0x5e,0x17,0xde, |
2515 | | 0x1a,0xde,0x1d,0x3e,0x10,0x3e,0x12,0x3e,0x1e,0x3e,0x15,0x6e,0x09,0x5f,0x0a,0xb7, |
2516 | | 0x61,0x39,0xb2,0xdc,0xd6,0xf8,0x3b,0x71,0x67,0x79,0xb2,0xbc,0xd6,0xf8,0x15,0xe0, |
2517 | | 0xcd,0xf2,0xf9,0x8d,0x43,0x62,0xf9,0xb2,0xc8,0x2c,0x2a,0x8b,0x66,0x85,0xce,0x62, |
2518 | | 0xb0,0x98,0xff,0x12,0x04,0xb3,0x42,0x58,0x61,0x2c,0x16,0x8b,0xfd,0x5f,0xe0,0xb0, |
2519 | | 0x62,0xd6,0xf8,0x9b,0x48,0x60,0x25,0xb1,0x52,0x58,0xa7,0x59,0xe9,0x2c,0x2e,0x8b, |
2520 | | 0xcf,0xca,0x61,0x89,0x58,0x85,0x2c,0x29,0x4b,0xce,0x52,0xb3,0xb4,0x2c,0x03,0xab, |
2521 | | 0x9a,0x55,0xcb,0x6a,0x60,0x35,0xb1,0x5a,0x58,0x6d,0xac,0x0e,0x56,0x17,0xeb,0x3a, |
2522 | | 0xab,0x8f,0xd5,0xcf,0x1a,0x64,0xdd,0x65,0xdd,0x63,0xdd,0x67,0x3d,0x60,0x3d,0x64, |
2523 | | 0x3d,0x62,0x3d,0x66,0x3d,0x61,0x3d,0x65,0xcd,0xb0,0xe6,0x58,0xcf,0x59,0x0b,0xac, |
2524 | | 0x17,0xac,0xef,0x58,0x2f,0x59,0x28,0xc2,0x36,0xc2,0x3e,0xc2,0x21,0xc2,0x39,0xc2, |
2525 | | 0x35,0xc2,0x2d,0xc2,0x23,0xc2,0x2b,0xc2,0x27,0x62,0x6f,0x84,0x5f,0x04,0x25,0x82, |
2526 | | 0x16,0x11,0x18,0xc1,0x8c,0x38,0x10,0x11,0x1a,0x11,0x1e,0xc1,0x8e,0x88,0x89,0x48, |
2527 | | 0x88,0x48,0x8a,0x48,0x89,0x38,0x1d,0x91,0x1e,0xc1,0x8d,0xe0,0x47,0xe4,0x44,0x88, |
2528 | | 0x22,0x0a,0x23,0xa4,0x11,0xf2,0x08,0x75,0x84,0x36,0xc2,0x10,0x51,0x1d,0x51,0x1b, |
2529 | | 0xd1,0x10,0xd1,0x14,0xd1,0x12,0xd1,0x16,0xd1,0x11,0xd1,0x15,0x71,0x3d,0xa2,0x2f, |
2530 | | 0xa2,0x3f,0x62,0x30,0xe2,0x6e,0xc4,0xbd,0x88,0xfb,0x11,0x0f,0x22,0x1e,0x46,0x3c, |
2531 | | 0x8a,0x78,0x1c,0xf1,0x24,0xe2,0x69,0xc4,0x4c,0xc4,0x5c,0xc4,0xf3,0x88,0x85,0x88, |
2532 | | 0x17,0x11,0xdf,0x45,0xbc,0x8c,0x40,0x91,0xb6,0x91,0xf6,0x91,0x0e,0x91,0xce,0x91, |
2533 | | 0xae,0x91,0x6e,0x91,0x1e,0x91,0x5e,0x91,0x3e,0x91,0x7b,0x23,0xfd,0x22,0x29,0x91, |
2534 | | 0xb4,0xc8,0xc0,0x48,0x66,0xe4,0x81,0xc8,0xd0,0xc8,0xf0,0x48,0x76,0x64,0x4c,0x64, |
2535 | | 0x42,0x64,0x52,0x64,0x4a,0xe4,0xe9,0xc8,0xf4,0x48,0x6e,0x24,0x3f,0x32,0x27,0x52, |
2536 | | 0x14,0x59,0x18,0x29,0x8d,0x94,0x47,0xaa,0x23,0xb5,0x91,0x86,0xc8,0xea,0xc8,0xda, |
2537 | | 0xc8,0x86,0xc8,0xa6,0xc8,0x96,0xc8,0xb6,0xc8,0x8e,0xc8,0xae,0xc8,0xeb,0x91,0x7d, |
2538 | | 0x91,0xfd,0x91,0x83,0x91,0x77,0x23,0xef,0x45,0xde,0x8f,0x7c,0x10,0xf9,0x30,0xf2, |
2539 | | 0x51,0xe4,0xe3,0xc8,0x27,0x91,0x4f,0x23,0x67,0x22,0xe7,0x22,0x9f,0x47,0x2e,0x44, |
2540 | | 0xbe,0x88,0xfc,0x2e,0xf2,0x65,0x24,0x62,0xdb,0xb2,0xed,0xd9,0x0e,0x6c,0x67,0xb6, |
2541 | | 0x2b,0xdb,0x8d,0xed,0xc1,0xf6,0x62,0xfb,0xb0,0xf7,0xb2,0xfd,0xd8,0x14,0x36,0x8d, |
2542 | | 0x1d,0xc8,0x66,0xb2,0x0f,0xb0,0x43,0xd9,0xe1,0x6c,0x36,0x3b,0x86,0x9d,0xc0,0x4e, |
2543 | | 0x62,0xa7,0xb0,0x4f,0xb3,0xd3,0xd9,0x5c,0x36,0x9f,0x9d,0xc3,0x16,0xb1,0x0b,0xd9, |
2544 | | 0x52,0xb6,0x9c,0xad,0x66,0x6b,0xd9,0x06,0x76,0x35,0xbb,0x96,0xdd,0xc0,0x6e,0x62, |
2545 | | 0xb7,0xb0,0xdb,0xd8,0x1d,0xec,0x2e,0xf6,0x75,0x76,0x1f,0xbb,0x9f,0x3d,0xc8,0xbe, |
2546 | | 0xcb,0xbe,0xc7,0xbe,0xcf,0x7e,0xc0,0x7e,0xc8,0x7e,0xc4,0x7e,0xcc,0x7e,0xc2,0x7e, |
2547 | | 0xca,0x9e,0x61,0xcf,0xb1,0x9f,0xb3,0x17,0xd8,0x2f,0xd8,0xdf,0xb1,0x5f,0xb2,0x11, |
2548 | | 0xc7,0x96,0x63,0xcf,0x71,0xe0,0x38,0x73,0x5c,0x39,0x6e,0x1c,0x0f,0x8e,0x17,0xc7, |
2549 | | 0x87,0xb3,0x97,0xe3,0xc7,0xa1,0x70,0x68,0x9c,0x40,0x0e,0x93,0x73,0x80,0x13,0xca, |
2550 | | 0x09,0xe7,0xb0,0x39,0x31,0x40,0x02,0x27,0x89,0x93,0xc2,0x39,0xcd,0x49,0xe7,0x70, |
2551 | | 0x39,0x7c,0x4e,0x0e,0x47,0xc4,0x29,0xe4,0x48,0x39,0x72,0x8e,0x9a,0xa3,0xb5,0x62, |
2552 | | 0x00,0xaa,0xad,0xd4,0x72,0x1a,0x38,0x4d,0x9c,0x16,0x4e,0x1b,0xa7,0x83,0xd3,0xc5, |
2553 | | 0xb9,0xce,0xe9,0xe3,0xf4,0x03,0x83,0xc0,0x5d,0x2b,0xf7,0x38,0xf7,0xbf,0xe7,0x01, |
2554 | | 0xe7,0x21,0xe7,0x11,0xe7,0x31,0xe7,0x09,0xe7,0x29,0x67,0x86,0x33,0xc7,0x79,0xce, |
2555 | | 0x59,0xe0,0xbc,0xe0,0x7c,0xc7,0x79,0xc9,0x41,0x51,0xb6,0x51,0xf6,0x51,0x0e,0x51, |
2556 | | 0xce,0x51,0xae,0x51,0x6e,0x51,0x1e,0x51,0x5e,0x51,0x3e,0x51,0x7b,0xa3,0xfc,0xa2, |
2557 | | 0x28,0x51,0xb4,0xa8,0xc0,0x28,0x66,0xd4,0x81,0xa8,0xd0,0xa8,0xf0,0x28,0x76,0x54, |
2558 | | 0x4c,0x54,0x42,0x54,0x52,0x54,0x4a,0xd4,0xe9,0xa8,0xf4,0x28,0x6e,0x14,0x3f,0x2a, |
2559 | | 0x27,0x4a,0x14,0x55,0x18,0x25,0x8d,0x92,0x47,0xa9,0xa3,0xb4,0x51,0x86,0xa8,0xea, |
2560 | | 0xa8,0xda,0xa8,0x86,0xa8,0xa6,0xa8,0x96,0xa8,0xb6,0xa8,0x8e,0xa8,0xae,0xa8,0xeb, |
2561 | | 0x51,0x7d,0x51,0xfd,0x51,0x83,0x51,0x77,0xa3,0xee,0x45,0xdd,0x8f,0x7a,0x10,0xf5, |
2562 | | 0x30,0xea,0x51,0xd4,0x63,0x2b,0x4f,0xa2,0x9e,0x46,0xcd,0x44,0xcd,0x45,0x3d,0x8f, |
2563 | | 0x5a,0x88,0x7a,0x11,0xf5,0x5d,0xd4,0xcb,0x28,0x14,0x6d,0x1b,0x6d,0x1f,0xed,0x10, |
2564 | | 0xed,0x1c,0xed,0x1a,0xed,0x16,0xed,0x11,0xed,0x15,0xed,0x13,0xbd,0x37,0xda,0x2f, |
2565 | | 0x9a,0x12,0x4d,0x8b,0x0e,0x8c,0x66,0x46,0x1f,0x88,0x0e,0x8d,0x0e,0x8f,0x66,0x47, |
2566 | | 0xc7,0x44,0x27,0x44,0x27,0x45,0xa7,0x44,0x9f,0x8e,0x4e,0x8f,0xe6,0x46,0xf3,0xa3, |
2567 | | 0x73,0xa2,0x45,0xd1,0x85,0xd1,0xd2,0x68,0x79,0xb4,0x3a,0x5a,0x1b,0x6d,0x88,0xae, |
2568 | | 0x8e,0xae,0x8d,0x6e,0x88,0x6e,0x8a,0x6e,0x89,0x6e,0x8b,0xee,0x88,0xee,0x8a,0xbe, |
2569 | | 0x1e,0xdd,0x17,0xdd,0x1f,0x3d,0x18,0x7d,0x37,0xfa,0x5e,0xf4,0xfd,0xe8,0x07,0xd1, |
2570 | | 0x0f,0xa3,0x1f,0x45,0x3f,0x8e,0x7e,0x12,0xfd,0x34,0x7a,0x26,0x7a,0x2e,0xfa,0x79, |
2571 | | 0xf4,0x42,0xf4,0x8b,0xe8,0xef,0xa2,0x5f,0x46,0xa3,0x18,0xdb,0x18,0xfb,0x18,0x87, |
2572 | | 0x18,0xe7,0x18,0xd7,0x18,0xb7,0x18,0x8f,0x18,0xaf,0x18,0x9f,0x98,0xbd,0x31,0x7e, |
2573 | | 0x31,0x94,0x18,0x5a,0x4c,0x60,0x0c,0x33,0xe6,0x40,0x4c,0x68,0x4c,0x78,0x0c,0x3b, |
2574 | | 0x26,0x26,0x26,0x21,0x26,0x29,0x26,0x25,0xe6,0x74,0x4c,0x7a,0x0c,0x37,0x86,0x1f, |
2575 | | 0x93,0x13,0x23,0x8a,0x29,0x8c,0x91,0xc6,0xc8,0x7f,0x46,0x14,0x80,0x2e,0xa6,0x26, |
2576 | | 0xa6,0x31,0xa6,0x3d,0xa6,0x27,0x66,0x20,0xe6,0xee,0x9f,0x61,0x38,0x66,0x34,0x66, |
2577 | | 0x3c,0x66,0x32,0x66,0x3a,0x66,0xee,0x27,0x2c,0x00,0xcb,0x31,0x2b,0x31,0x36,0xb1, |
2578 | | 0x76,0xb1,0x84,0x58,0xc7,0x58,0x97,0x58,0x62,0xac,0x7b,0xac,0x67,0xac,0x57,0xec, |
2579 | | 0xde,0x58,0x4a,0x2c,0x33,0x36,0x3c,0x36,0x26,0x36,0x29,0xf6,0x74,0x2c,0x37,0x36, |
2580 | | 0x27,0xb6,0x30,0x56,0x1e,0xab,0x8d,0xad,0x06,0x1a,0x62,0x5b,0x62,0x3b,0x62,0xaf, |
2581 | | 0xc7,0xf6,0x03,0x77,0x81,0xfb,0xb1,0x0f,0x81,0xc7,0xb1,0x4f,0x81,0xb9,0xd8,0x85, |
2582 | | 0xd8,0xef,0x62,0x51,0x9c,0x7d,0x9c,0x73,0x9c,0x5b,0x9c,0x57,0x9c,0x6f,0x1c,0x35, |
2583 | | 0x8e,0x1e,0xc7,0x88,0x0b,0x8e,0x0b,0x89,0x0b,0x8b,0x63,0xc5,0x71,0xe2,0x62,0xe3, |
2584 | | 0x12,0xe3,0x92,0xe3,0x52,0xe3,0xd2,0xe2,0x32,0xe2,0x78,0x71,0x82,0x38,0x61,0x9c, |
2585 | | 0x38,0x4e,0x12,0x27,0x8b,0x53,0xc4,0x69,0xe2,0x74,0x71,0xc6,0xb8,0x9a,0xb8,0xba, |
2586 | | 0xb8,0xc6,0xb8,0xe6,0xb8,0xd6,0xb8,0xf6,0xb8,0xce,0xb8,0xee,0xb8,0x9e,0x38,0x53, |
2587 | | 0xdc,0x40,0xdc,0x50,0xdc,0x70,0xdc,0x48,0xdc,0x68,0xdc,0x58,0xdc,0x78,0xdc,0x44, |
2588 | | 0xdc,0x64,0xdc,0x54,0xdc,0x74,0x9c,0x39,0xce,0x12,0x37,0x1f,0xb7,0x18,0xb7,0x14, |
2589 | | 0xb7,0x1c,0xb7,0x12,0x67,0x13,0x6f,0x17,0x4f,0x88,0x77,0x8c,0x77,0x89,0x27,0xc6, |
2590 | | 0xbb,0xc7,0x7b,0xc6,0x7b,0xc7,0x93,0xe2,0x7d,0xe3,0xc9,0xf1,0xd4,0x78,0x7a,0x3c, |
2591 | | 0x23,0x3e,0x38,0x3e,0x24,0x3e,0x2c,0x9e,0x15,0xcf,0x89,0x8f,0x8d,0x4f,0x8c,0x4f, |
2592 | | 0x8e,0x4f,0x8d,0x4f,0x8b,0xcf,0x88,0xe7,0xc5,0x0b,0xe2,0x85,0xf1,0xe2,0x78,0x49, |
2593 | | 0xbc,0x2c,0x5e,0x11,0xaf,0x8b,0xaf,0x89,0xaf,0x8b,0x6f,0x8c,0x6f,0x8e,0x6f,0x8d, |
2594 | | 0x6f,0x8f,0xef,0x8c,0xef,0x8e,0xef,0x89,0x37,0xc5,0x0f,0xc4,0x0f,0xc7,0xdf,0xff, |
2595 | | 0x87,0x19,0x8d,0x1f,0x8b,0x1f,0x8f,0x9f,0x88,0x9f,0x8c,0x9f,0x8a,0x9f,0x8e,0x37, |
2596 | | 0xc7,0x5b,0xe2,0xe7,0xe3,0x17,0xe3,0x97,0xe3,0x57,0xe2,0x6d,0x12,0xec,0x12,0x08, |
2597 | | 0x09,0x8e,0x09,0x2e,0x09,0xc4,0x04,0xf7,0x04,0xcf,0x04,0xef,0x04,0x52,0x82,0x6f, |
2598 | | 0x02,0x3d,0x21,0x24,0x81,0x93,0x90,0x9c,0x90,0x91,0x20,0x4c,0x90,0x25,0xe8,0x12, |
2599 | | 0xea,0x12,0x5a,0x13,0xba,0x13,0x06,0x12,0x46,0x12,0xc6,0x13,0xa6,0x12,0x2c,0x09, |
2600 | | 0x4b,0x09,0x36,0x89,0x76,0x89,0x84,0x44,0xc7,0x44,0x17,0xc0,0x33,0xd1,0x37,0x91, |
2601 | | 0x9e,0x18,0x92,0xc8,0x49,0x4c,0x4c,0x4c,0x4d,0xcc,0x48,0x14,0x24,0x8a,0x13,0x65, |
2602 | | 0x89,0x9a,0x44,0x63,0x62,0x5d,0x62,0x73,0x62,0x7b,0x62,0x77,0xa2,0x29,0x71,0x28, |
2603 | | 0x71,0x24,0x71,0x2c,0x71,0x22,0x71,0x2a,0xd1,0x9c,0x38,0x9f,0xb8,0x94,0xb8,0x92, |
2604 | | 0x68,0x77,0xd4,0xf1,0x28,0xf1,0xa8,0xe7,0x51,0xd2,0x51,0xf2,0x51,0xfa,0xd1,0xe0, |
2605 | | 0xa3,0x61,0x47,0x39,0x47,0x13,0x8f,0xa6,0x1e,0xcd,0x38,0x2a,0x38,0x2a,0x3e,0x2a, |
2606 | | 0x3b,0xaa,0x39,0x6a,0x3c,0x5a,0x77,0xb4,0xf9,0x68,0xfb,0xd1,0xee,0xa3,0xa6,0xa3, |
2607 | | 0x43,0x47,0x47,0x8e,0x8e,0x1d,0x9d,0x38,0x3a,0x75,0xd4,0x7c,0x74,0xfe,0xe8,0xd2, |
2608 | | 0xd1,0x95,0xa3,0x76,0xc7,0x1c,0x8f,0x11,0x8f,0x79,0x1e,0x23,0x1d,0x23,0x1f,0xa3, |
2609 | | 0x1f,0x0b,0x3e,0x16,0x76,0x8c,0x73,0x2c,0xf1,0x58,0xea,0xb1,0x8c,0x63,0x82,0x63, |
2610 | | 0xe2,0x63,0xb2,0x63,0x9a,0x63,0xc6,0x63,0x75,0xc7,0x9a,0x8f,0xb5,0x1f,0xeb,0x3e, |
2611 | | 0x66,0x3a,0x36,0x74,0x6c,0xe4,0xd8,0xd8,0xb1,0x89,0x63,0x53,0xc7,0xcc,0xc7,0xe6, |
2612 | | 0x8f,0x2d,0x1d,0x5b,0x39,0x66,0x97,0xe4,0x98,0x44,0x4c,0xf2,0x4e,0x22,0x27,0x31, |
2613 | | 0x92,0xc2,0x92,0x62,0x93,0x52,0x93,0x78,0x49,0xe2,0x24,0x45,0x92,0x31,0xa9,0x31, |
2614 | | 0xa9,0x3d,0xa9,0x3b,0xc9,0x94,0x34,0x94,0x34,0x92,0x34,0x96,0x34,0x91,0x34,0x95, |
2615 | | 0x64,0x4e,0x9a,0x4f,0x5a,0x4a,0x5a,0x49,0xb2,0x4b,0x76,0x4c,0x26,0x26,0x7b,0x26, |
2616 | | 0x93,0x92,0xc9,0xc9,0xf4,0xe4,0xe0,0xe4,0xb0,0x64,0x4e,0x72,0x62,0x72,0x6a,0x72, |
2617 | | 0x46,0xb2,0x20,0x59,0x9c,0x2c,0x4b,0xd6,0x24,0x1b,0x93,0xeb,0x92,0x9b,0x93,0xdb, |
2618 | | 0x93,0xbb,0x93,0x4d,0xc9,0x43,0xc9,0x23,0xc9,0x63,0xc9,0x13,0xc9,0x53,0xc9,0xe6, |
2619 | | 0xe4,0xf9,0xe4,0xa5,0xe4,0x95,0x64,0xbb,0xe3,0x8e,0xc7,0xdd,0x8f,0x93,0x8e,0x53, |
2620 | | 0x8f,0x07,0x1f,0x67,0x1d,0x8f,0x3d,0x9e,0x7c,0x3c,0xed,0x38,0xef,0xb8,0xf0,0xb8, |
2621 | | 0xe4,0xb8,0xe2,0xb8,0xee,0x78,0xcd,0xf1,0xc6,0xe3,0xad,0xc7,0x3b,0x8f,0xf7,0x1c, |
2622 | | 0x1f,0x38,0x3e,0x7c,0x7c,0xf4,0xf8,0xf8,0xf1,0xc9,0xe3,0xd3,0xc7,0x2d,0xc7,0x17, |
2623 | | 0x8f,0x2f,0x1f,0xb7,0x39,0x41,0x38,0xe1,0x72,0xc2,0xfd,0x84,0xf7,0x09,0xdf,0x13, |
2624 | | 0xd4,0x13,0x8c,0x13,0x21,0x27,0x58,0x27,0x62,0x4f,0x24,0x9f,0x48,0x3b,0xc1,0x3b, |
2625 | | 0x21,0x3c,0x21,0x39,0xa1,0x38,0xa1,0x3b,0x51,0x73,0xa2,0xf1,0x44,0xeb,0x89,0xce, |
2626 | | 0x13,0x3d,0x27,0x06,0x4e,0x0c,0x9f,0x18,0x3d,0x31,0x7e,0x62,0xf2,0xc4,0xf4,0x09, |
2627 | | 0xcb,0x89,0xc5,0x13,0xcb,0x27,0x6c,0x52,0x08,0x29,0x2e,0x29,0xee,0x29,0xde,0x29, |
2628 | | 0xbe,0x29,0xd4,0x14,0x46,0x4a,0x48,0x0a,0x2b,0x25,0x36,0x25,0x39,0x25,0x2d,0x45, |
2629 | | 0x90,0x22,0x49,0x51,0xa4,0xe8,0x52,0x6a,0x52,0x1a,0x53,0x5a,0x53,0x3a,0x53,0x7a, |
2630 | | 0x52,0x06,0x52,0x86,0x53,0x46,0x53,0xc6,0x53,0x26,0x53,0xa6,0x53,0x2c,0x29,0x8b, |
2631 | | 0x29,0xcb,0x29,0x36,0xa9,0x8e,0xa9,0xee,0xa9,0xa4,0x54,0x72,0x2a,0x3d,0x35,0x38, |
2632 | | 0x35,0x2c,0x95,0x93,0x9a,0x98,0x9a,0x9a,0x9a,0x91,0x2a,0x48,0x15,0xa7,0xca,0x00, |
2633 | | 0x4d,0xaa,0x31,0xb5,0x2e,0xb5,0x39,0xb5,0x3d,0xb5,0x3b,0xd5,0x94,0x3a,0x94,0x3a, |
2634 | | 0x92,0x3a,0x96,0x3a,0x91,0x3a,0x95,0x6a,0x4e,0x9d,0x4f,0x5d,0x4a,0x5d,0x49,0xb5, |
2635 | | 0x3b,0xe9,0x78,0x92,0x78,0xd2,0xf3,0x24,0xe9,0x24,0xf9,0x24,0xfd,0x64,0xf0,0xc9, |
2636 | | 0xb0,0x93,0x9c,0x93,0x89,0x27,0x53,0x4f,0x66,0x9c,0x14,0x9c,0x14,0x9f,0x94,0x9d, |
2637 | | 0xd4,0x9c,0x34,0x9e,0xac,0x3b,0xd9,0x7c,0xb2,0xfd,0x64,0xf7,0x49,0xd3,0xc9,0xa1, |
2638 | | 0x93,0x23,0x27,0xc7,0x4e,0x4e,0x9c,0x9c,0x3a,0x69,0x3e,0x39,0x7f,0x72,0xe9,0xe4, |
2639 | | 0xca,0x49,0xbb,0x53,0x8e,0xa7,0x88,0xa7,0x3c,0x4f,0x91,0x4e,0x91,0x4f,0xd1,0x4f, |
2640 | | 0x05,0x9f,0x0a,0x3b,0xc5,0x39,0x95,0x78,0x2a,0xf5,0x54,0xc6,0x29,0xfe,0x5f,0x81, |
2641 | | 0xe0,0x94,0xe4,0x94,0xe6,0x54,0xcd,0xa9,0xe6,0x53,0x9d,0xa7,0x4c,0xa7,0x86,0x4f, |
2642 | | 0x8d,0x9d,0x9a,0x3c,0x65,0x3e,0xb5,0x78,0x6a,0xe5,0x14,0xe1,0x34,0xf1,0xb4,0xf7, |
2643 | | 0x69,0xf2,0x69,0xc6,0xe9,0xb0,0xd3,0xb1,0xa7,0x53,0x4f,0xf3,0x4e,0x8b,0x4f,0x2b, |
2644 | | 0x4e,0x1b,0x4f,0x37,0x9e,0x6e,0x3f,0xdd,0x73,0x7a,0xe8,0xf4,0xe8,0xe9,0x89,0xd3, |
2645 | | 0xd3,0xa7,0xe7,0x4f,0x2f,0x9f,0xb6,0x4b,0x73,0x49,0xf3,0x4c,0xf3,0x4d,0xa3,0xa7, |
2646 | | 0x85,0xa4,0x71,0xd2,0x92,0xd3,0x32,0xd2,0x84,0x69,0xb2,0x34,0x5d,0x5a,0x5d,0x5a, |
2647 | | 0x6b,0x5a,0x77,0xda,0x40,0xda,0x48,0xda,0x78,0xda,0x54,0x9a,0x25,0x6d,0x29,0xcd, |
2648 | | 0xe6,0x3d,0xc7,0xf7,0xdc,0xdf,0x23,0xbd,0x47,0x7d,0x2f,0xf8,0x3d,0xd6,0x7b,0x89, |
2649 | | 0xef,0xa5,0xbd,0xc7,0x07,0x04,0xef,0x49,0xde,0xd3,0xbc,0x57,0xf3,0x5e,0xf3,0x7b, |
2650 | | 0x9d,0xef,0x99,0xde,0x1b,0x7e,0x6f,0xec,0xbd,0xc9,0xf7,0xcc,0xef,0x2d,0xbe,0xb7, |
2651 | | 0xf2,0x1e,0xe1,0x7d,0xe2,0xfb,0xde,0xef,0x93,0xdf,0x67,0xbc,0x1f,0xf6,0x7e,0xec, |
2652 | | 0xfb,0xa9,0xef,0xf3,0xde,0x17,0xbf,0xaf,0x78,0xdf,0xf8,0x7e,0xe3,0xfb,0xed,0xef, |
2653 | | 0xf7,0xbc,0x3f,0xf4,0xfe,0xe8,0xfb,0x13,0xef,0x4f,0xbf,0x3f,0xff,0xfe,0xf2,0xfb, |
2654 | | 0x76,0xe9,0x2e,0xe9,0x9e,0xe9,0xbe,0xe9,0xf4,0xf4,0x90,0x74,0x4e,0x7a,0x72,0x7a, |
2655 | | 0x46,0xba,0x30,0x5d,0x96,0xae,0x4b,0xaf,0x4b,0x6f,0x4d,0xef,0x4e,0x1f,0x48,0x1f, |
2656 | | 0x49,0x1f,0x4f,0x9f,0x4a,0xb7,0xa4,0xbf,0xf8,0x99,0x59,0x4a,0xb7,0xc9,0x70,0xcc, |
2657 | | 0xf0,0xcc,0x20,0x67,0x04,0x67,0x70,0x32,0x52,0x33,0x04,0x19,0xb2,0x0c,0x5d,0xc6, |
2658 | | 0x78,0xc6,0x62,0x06,0xca,0xfc,0xeb,0xb0,0xc9,0xb4,0xcb,0x24,0x64,0x3a,0x66,0xba, |
2659 | | 0x64,0x12,0x33,0xdd,0x33,0x3d,0x33,0xbd,0x33,0x49,0x99,0x94,0xbf,0x01,0x6a,0x26, |
2660 | | 0x23,0x33,0x38,0x33,0x24,0x33,0x2c,0x93,0x95,0xc9,0xc9,0x8c,0xcd,0x4c,0xcc,0x4c, |
2661 | | 0xce,0x4c,0xcd,0x4c,0xcb,0xcc,0xc8,0xe4,0x65,0x0a,0x32,0x85,0x99,0xe2,0x4c,0x49, |
2662 | | 0xa6,0x2c,0x53,0x91,0xa9,0xc9,0xd4,0x02,0xba,0x4c,0x63,0x66,0x4d,0x66,0x63,0x66, |
2663 | | 0x6b,0x66,0x67,0x66,0x4f,0xa6,0x29,0x73,0x20,0x73,0x28,0x73,0x38,0x73,0x24,0xf3, |
2664 | | 0x7e,0xe6,0x68,0xe6,0x58,0xe6,0x78,0xe6,0x44,0xe6,0x64,0xe6,0x54,0xe6,0x74,0xa6, |
2665 | | 0x39,0xd3,0x92,0x39,0x9f,0xb9,0x98,0xb9,0x94,0xb9,0x9c,0xb9,0x92,0x69,0x73,0xc6, |
2666 | | 0xee,0x0c,0xe1,0x8c,0xe3,0x19,0x97,0x33,0xae,0x67,0x88,0x67,0xdc,0xcf,0x78,0x9e, |
2667 | | 0xf1,0x3e,0xe3,0xf3,0x3d,0xa4,0x33,0xe4,0x33,0xf4,0x33,0xcc,0x33,0xc1,0x67,0x42, |
2668 | | 0xcf,0x84,0x9d,0xe1,0x9c,0x49,0x3c,0x93,0x7a,0x26,0xe3,0x8c,0xe0,0x8c,0xf8,0x8c, |
2669 | | 0xec,0x8c,0xe6,0x8c,0xf1,0x4c,0xdd,0x99,0xc6,0x33,0xad,0x67,0x3a,0xcf,0xf4,0x9c, |
2670 | | 0x19,0x38,0x33,0x7c,0x66,0xf4,0xcc,0xf8,0x99,0xc9,0x33,0xd3,0x67,0x2c,0x67,0x16, |
2671 | | 0xcf,0x2c,0x9f,0x59,0x39,0x63,0xc3,0xb5,0xe3,0x12,0xb8,0x8e,0x5c,0x17,0x2e,0x91, |
2672 | | 0xeb,0xce,0xf5,0xe4,0x7a,0x73,0x49,0x5c,0x5f,0x2e,0x99,0x4b,0xe5,0xd2,0xb9,0x0c, |
2673 | | 0x6e,0x30,0x37,0x84,0x1b,0xc6,0x65,0x71,0x39,0xdc,0x58,0x6e,0x22,0x37,0x99,0x9b, |
2674 | | 0xca,0x4d,0xe3,0x66,0x70,0x79,0x5c,0x01,0x57,0xc8,0x15,0x73,0x25,0x5c,0x19,0x57, |
2675 | | 0xc1,0xd5,0x70,0x75,0x5c,0x23,0xb7,0x86,0x5b,0xc7,0x6d,0xe4,0x36,0x73,0x5b,0xb9, |
2676 | | 0xed,0xdc,0x4e,0x6e,0x37,0xb7,0x87,0x6b,0xe2,0x0e,0x70,0x87,0xb8,0xc3,0xdc,0x11, |
2677 | | 0xee,0x28,0x77,0x8c,0x3b,0xce,0x9d,0xe0,0x4e,0x72,0xa7,0xb8,0xd3,0x5c,0x33,0xd7, |
2678 | | 0xc2,0x9d,0xe7,0x2e,0x72,0x97,0xb8,0xcb,0xdc,0x15,0xae,0x0d,0xcf,0x8e,0x47,0xe0, |
2679 | | 0x39,0xf2,0x5c,0x78,0x44,0x9e,0x3b,0xcf,0x93,0xe7,0xcd,0x23,0xf1,0x7c,0x79,0x64, |
2680 | | 0x1e,0x95,0x47,0xe7,0x31,0x78,0xc1,0xbc,0x10,0x5e,0x18,0x8f,0xc5,0xe3,0xf0,0x62, |
2681 | | 0x79,0x89,0xbc,0x64,0x5e,0x2a,0x2f,0x8d,0x97,0xc1,0xe3,0xf1,0x04,0x3c,0x21,0x4f, |
2682 | | 0xcc,0x93,0xf0,0x64,0x3c,0x05,0x4f,0xc3,0xd3,0xf1,0x8c,0xbc,0x1a,0x5e,0x1d,0xaf, |
2683 | | 0x91,0xd7,0xce,0xeb,0xe1,0x0d,0xf1,0x46,0x79,0x13,0xbc,0x69,0x9e,0x85,0xb7,0xf0, |
2684 | | 0x23,0x8b,0xbc,0x25,0xde,0x32,0x6f,0x85,0x67,0x93,0x65,0x97,0x45,0xc8,0x72,0xcc, |
2685 | | 0x72,0xc9,0x22,0x66,0xb9,0x67,0x79,0x66,0x79,0x67,0x91,0xb2,0x7c,0xb3,0xc8,0x59, |
2686 | | 0xd4,0x2c,0x7a,0x16,0x23,0x2b,0x38,0x2b,0x24,0x2b,0x2c,0x8b,0x95,0xc5,0xc9,0x8a, |
2687 | | 0xcd,0x4a,0xcc,0x4a,0xce,0x4a,0xcd,0x4a,0xcb,0xca,0xc8,0xe2,0x65,0x09,0xb2,0x84, |
2688 | | 0x59,0xe2,0x2c,0x49,0x96,0x2c,0x4b,0x91,0xa5,0xc9,0xd2,0x65,0x19,0xb3,0x6a,0xb2, |
2689 | | 0xea,0xb2,0x1a,0xb3,0x9a,0xb3,0x5a,0xb3,0xda,0xb3,0x3a,0xb3,0xba,0xb3,0x7a,0xb2, |
2690 | | 0x4c,0x59,0x03,0x59,0x43,0x59,0xc3,0x59,0x23,0x59,0xa3,0x59,0x63,0x59,0xe3,0x59, |
2691 | | 0x13,0x59,0x93,0x59,0x53,0x59,0xd3,0x59,0xe6,0x2c,0x4b,0xd6,0x7c,0xd6,0x62,0xd6, |
2692 | | 0x52,0xd6,0x72,0xd6,0x4a,0x96,0x4d,0xb6,0x5d,0x36,0x21,0xdb,0x31,0xdb,0x25,0x9b, |
2693 | | 0x98,0xed,0x9e,0xed,0x99,0xed,0x9d,0x4d,0xca,0xf6,0xcd,0x26,0x67,0x53,0xb3,0xe9, |
2694 | | 0xd9,0x8c,0xec,0xe0,0xec,0x90,0xec,0xb0,0x6c,0x56,0x36,0x27,0x3b,0x36,0x3b,0x31, |
2695 | | 0x3b,0x39,0x3b,0x35,0x3b,0x2d,0x3b,0x23,0x9b,0x97,0x2d,0xc8,0x16,0x66,0x8b,0xb3, |
2696 | | 0x25,0xd9,0xb2,0x6c,0x45,0xb6,0x26,0x5b,0x97,0x6d,0xcc,0xae,0xc9,0xae,0xcb,0x6e, |
2697 | | 0xcc,0x6e,0xce,0x6e,0xcd,0x6e,0xcf,0xee,0xcc,0xee,0xce,0xee,0xc9,0x36,0x65,0x0f, |
2698 | | 0x64,0x0f,0x65,0x0f,0x67,0x8f,0x64,0x8f,0x66,0x8f,0x65,0x8f,0x67,0x4f,0x64,0x4f, |
2699 | | 0x66,0x4f,0x65,0x4f,0x67,0x9b,0xb3,0x2d,0xd9,0xf3,0xd9,0x8b,0xd9,0x4b,0xd9,0xcb, |
2700 | | 0xd9,0x2b,0xd9,0x36,0x7c,0x3b,0x3e,0x81,0xef,0xc8,0x77,0xe1,0x13,0xf9,0xee,0x7c, |
2701 | | 0x4f,0xbe,0x37,0x9f,0xc4,0xf7,0xe5,0x93,0xf9,0x54,0x3e,0x9d,0xcf,0xe0,0x07,0xf3, |
2702 | | 0x43,0xf8,0x61,0x7c,0x16,0x9f,0xc3,0x8f,0xe5,0x27,0xf2,0x93,0xf9,0xa9,0xfc,0x34, |
2703 | | 0x7e,0x06,0x9f,0xc7,0x17,0xf0,0x85,0x7c,0x31,0x5f,0xc2,0x97,0xf1,0x15,0x7c,0x0d, |
2704 | | 0x5f,0xc7,0x37,0xf2,0x6b,0xf8,0x75,0xfc,0x46,0x7e,0x33,0xbf,0x95,0xdf,0xce,0xef, |
2705 | | 0xe4,0x77,0xf3,0x7b,0xf8,0x26,0xfe,0x00,0x7f,0x88,0x3f,0xcc,0x1f,0xe1,0x8f,0xf2, |
2706 | | 0xc7,0xf8,0xe3,0xfc,0x09,0xfe,0x24,0x7f,0x8a,0x3f,0xcd,0x37,0xf3,0xe7,0xac,0x58, |
2707 | | 0xf8,0xf3,0xfc,0x45,0xfe,0x12,0x7f,0x99,0xbf,0xc2,0x47,0x02,0x24,0xb0,0x11,0xd8, |
2708 | | 0x09,0x08,0x02,0x47,0x81,0x8b,0x80,0x28,0x70,0x03,0xdc,0x05,0x9e,0x02,0x6f,0x01, |
2709 | | 0x49,0xe0,0x2b,0x20,0x0b,0x28,0x00,0x55,0x40,0x17,0x30,0x04,0x4c,0x2b,0xc1,0x82, |
2710 | | 0x10,0x41,0x98,0x80,0x25,0x88,0x15,0x24,0x0a,0x92,0x05,0x29,0x82,0x54,0x41,0x9a, |
2711 | | 0x20,0x43,0xc0,0x13,0x08,0x04,0x42,0x81,0x58,0x50,0xb8,0xc6,0xaf,0x12,0xf9,0xdf, |
2712 | | 0x85,0x76,0x8d,0xbf,0x13,0x9d,0xc0,0x28,0xa8,0x11,0xd4,0x09,0x1a,0x05,0x4d,0x82, |
2713 | | 0x66,0x41,0xab,0xa0,0x5d,0xd0,0x29,0xe8,0x16,0xf4,0x08,0x4c,0x82,0x01,0xc1,0x90, |
2714 | | 0x60,0x58,0x30,0x22,0x18,0x15,0x8c,0x09,0xc6,0x05,0x13,0x82,0x49,0xc1,0x94,0x60, |
2715 | | 0x5a,0x60,0x16,0x58,0x04,0xf3,0x82,0x45,0xc1,0x92,0x60,0x59,0xb0,0x22,0xb0,0x39, |
2716 | | 0x6b,0x77,0x96,0x70,0xd6,0xf1,0xac,0xcb,0x59,0xe2,0x59,0xf7,0xb3,0x9e,0x67,0xbd, |
2717 | | 0xcf,0x92,0xce,0xfa,0x9e,0x25,0x9f,0xa5,0x9e,0xa5,0x9f,0x65,0x9c,0x0d,0x3e,0x1b, |
2718 | | 0x72,0x36,0xf4,0x6c,0xd8,0x59,0xd6,0x59,0xce,0xd9,0xd8,0xb3,0x89,0x67,0x93,0xcf, |
2719 | | 0xa6,0x9e,0x4d,0x3b,0x9b,0x71,0x96,0x77,0x56,0x70,0x56,0x78,0x56,0x7c,0x56,0x72, |
2720 | | 0x56,0xba,0xc6,0xaf,0x12,0x35,0x60,0xf8,0x6f,0xa9,0x5d,0xc3,0x4a,0xd3,0xd9,0xb6, |
2721 | | 0x35,0xd6,0xf8,0xbb,0xe8,0x3a,0xdb,0xf7,0x8b,0x32,0x08,0xdc,0xfb,0x2f,0x3c,0xb0, |
2722 | | 0xf2,0xe8,0x17,0xe2,0x09,0x30,0x73,0xf6,0xf9,0x1a,0xbf,0x09,0x5e,0x9c,0x7d,0x09, |
2723 | | 0xd8,0x9e,0x5b,0xe3,0xb7,0x89,0xc3,0x39,0xd7,0xdf,0x30,0x1e,0x6b,0xfc,0xcb,0xe1, |
2724 | | 0x73,0xce,0xef,0x1c,0xed,0x1c,0xf3,0x5c,0xe8,0xb9,0x98,0x73,0x29,0xe7,0xb8,0x6b, |
2725 | | 0xac,0xf1,0x3f,0x4a,0xce,0xb9,0xc2,0x73,0xea,0x35,0x7e,0x61,0x34,0xe7,0x8c,0xe7, |
2726 | | 0xea,0xce,0x35,0x9f,0x6b,0x5b,0x63,0x8d,0x35,0xfe,0x69,0xb4,0x9f,0xeb,0x3c,0xd7, |
2727 | | 0x7d,0xae,0xe7,0x9c,0xe9,0xdc,0xc0,0xb9,0xa1,0x73,0xc3,0xe7,0x46,0xce,0x8d,0x9e, |
2728 | | 0x1b,0x3b,0x37,0x7e,0x6e,0xe2,0xdc,0xe4,0xb9,0xa9,0x73,0xd3,0xe7,0xcc,0xe7,0x2c, |
2729 | | 0xe7,0xe6,0xcf,0x2d,0x9e,0x5b,0x3a,0xb7,0x7c,0x6e,0xe5,0x9c,0x4d,0x8e,0x5d,0x0e, |
2730 | | 0x21,0xc7,0x31,0xc7,0x25,0x87,0x98,0xe3,0x9e,0xe3,0x99,0xe3,0x9d,0x43,0xca,0xf1, |
2731 | | 0xcd,0x21,0xe7,0x50,0x73,0x68,0xff,0x42,0x30,0x73,0x42,0x73,0x62,0x72,0x52,0x72, |
2732 | | 0xb8,0x39,0xa2,0x1c,0xf9,0xaf,0x0a,0x6d,0x4e,0x75,0x4e,0x53,0x4e,0x47,0x4e,0x5f, |
2733 | | 0xce,0xdd,0xff,0x61,0x86,0x73,0x46,0x72,0x46,0x73,0xc6,0x72,0xc6,0x73,0x26,0x72, |
2734 | | 0x26,0x73,0xa6,0x72,0xa6,0x73,0xcc,0x39,0x96,0x9c,0xf9,0x9c,0xc5,0x9c,0xa5,0x9c, |
2735 | | 0xe5,0x9c,0x95,0x1c,0x1b,0xa1,0x9d,0x90,0x20,0x74,0x14,0xba,0x08,0x89,0x42,0x77, |
2736 | | 0xa1,0xa7,0xd0,0x5b,0x48,0x12,0xfa,0x0a,0xc9,0x42,0xaa,0x90,0x2e,0x64,0x08,0x83, |
2737 | | 0x85,0x21,0xc2,0x30,0x21,0x4b,0xc8,0x11,0xc6,0x0a,0x13,0x85,0xc9,0xc2,0x54,0x61, |
2738 | | 0x9a,0x30,0x43,0xc8,0x13,0x0a,0x84,0x42,0xa1,0x58,0x28,0x11,0xca,0x84,0x0a,0xa1, |
2739 | | 0x46,0xa8,0x13,0x1a,0x85,0x35,0xc2,0x3a,0x61,0xa3,0xb0,0x59,0xd8,0x2a,0x6c,0x17, |
2740 | | 0x76,0x0a,0xbb,0x85,0x3d,0x42,0x93,0x70,0x40,0x38,0x24,0x1c,0x16,0x8e,0x08,0x47, |
2741 | | 0x85,0x63,0xc2,0x71,0xe1,0x84,0x70,0x52,0x38,0x25,0x9c,0x16,0x9a,0x85,0x16,0xe1, |
2742 | | 0xbc,0x70,0x51,0xb8,0x24,0x5c,0x16,0xae,0x08,0x6d,0x72,0xed,0x72,0x09,0xb9,0x8e, |
2743 | | 0xb9,0x2e,0xb9,0xae,0xb9,0xc4,0x5c,0xf7,0x5c,0xcf,0x5c,0xef,0x5c,0x52,0xae,0x6f, |
2744 | | 0x2e,0x39,0x97,0x9a,0x4b,0xcf,0x65,0xe4,0x06,0xe7,0x86,0xe4,0x86,0xe5,0xb2,0x72, |
2745 | | 0x39,0xb9,0xb1,0xb9,0x89,0xb9,0xc9,0xb9,0xa9,0xb9,0x69,0xb9,0x19,0xb9,0xbc,0x5c, |
2746 | | 0x41,0xae,0x30,0x57,0x9c,0x2b,0xc9,0x95,0xe5,0x2a,0x72,0x35,0xb9,0xba,0x5c,0x63, |
2747 | | 0x6e,0x4d,0x6e,0x5d,0x6e,0x63,0x6e,0x73,0x6e,0x6b,0x6e,0x7b,0x6e,0x67,0x6e,0x77, |
2748 | | 0x6e,0x4f,0xae,0x29,0x77,0x20,0x77,0x28,0x77,0x38,0x77,0x24,0x77,0x34,0x77,0x2c, |
2749 | | 0x77,0x3c,0x77,0x22,0x77,0x32,0x77,0x2a,0x77,0x3a,0xd7,0x9c,0x6b,0xc9,0x9d,0xcf, |
2750 | | 0x5d,0xcc,0x5d,0xca,0x5d,0xce,0x5d,0xc9,0xb5,0xc9,0xb3,0xcb,0x23,0xe4,0x39,0xe6, |
2751 | | 0xb9,0xe4,0x11,0xf3,0xdc,0xf3,0x3c,0xf3,0xbc,0xf3,0x48,0x79,0xbe,0x79,0xe4,0x3c, |
2752 | | 0x4a,0x1e,0x35,0x8f,0x9e,0x17,0x08,0x30,0xf2,0x98,0x40,0x70,0x5e,0x48,0x5e,0x28, |
2753 | | 0x10,0x96,0xc7,0xca,0xe3,0xe4,0xc5,0xe6,0x25,0xe4,0x25,0xe6,0x25,0xe7,0xa5,0xe6, |
2754 | | 0xa5,0xe5,0x65,0xe4,0xf1,0xf2,0x04,0x79,0xc2,0x3c,0x71,0x9e,0x24,0x4f,0x96,0xa7, |
2755 | | 0xc8,0x53,0xe7,0x69,0xf2,0xb4,0x79,0xba,0x3c,0x63,0x5e,0x4d,0x5e,0x5d,0x5e,0x63, |
2756 | | 0x5e,0x73,0x5e,0x6b,0x5e,0x5b,0x5e,0x7b,0x5e,0x67,0x5e,0x77,0x5e,0x4f,0x9e,0x29, |
2757 | | 0x6f,0x20,0x6f,0x28,0x6f,0x38,0x6f,0x24,0x6f,0x34,0x6f,0x2c,0x6f,0x3c,0x6f,0x22, |
2758 | | 0x6f,0x32,0x6f,0x2a,0x6f,0x3a,0xcf,0x9c,0x67,0xc9,0x9b,0xcf,0x5b,0xcc,0x5b,0xca, |
2759 | | 0x5b,0xce,0x5b,0xc9,0xb3,0x11,0xd9,0x89,0x08,0x22,0x47,0x91,0x8b,0x88,0x28,0x72, |
2760 | | 0x17,0x79,0x8a,0xbc,0x45,0x24,0x91,0xaf,0x88,0x2c,0xa2,0x8a,0xe8,0x22,0x86,0x28, |
2761 | | 0x58,0x14,0x22,0x0a,0x13,0xb1,0x44,0x1c,0x51,0xac,0x28,0x51,0x94,0x2c,0x4a,0x15, |
2762 | | 0xa5,0x89,0x32,0x44,0x3c,0x91,0x40,0x24,0x14,0x89,0x45,0x12,0x91,0x4c,0xa4,0x10, |
2763 | | 0x69,0x44,0x3a,0x91,0x51,0x54,0x03,0xd4,0x89,0x1a,0x45,0xcd,0xa2,0x56,0x51,0xbb, |
2764 | | 0xa8,0x43,0xd4,0x29,0xea,0x16,0xf5,0x88,0x4c,0xa2,0x7e,0x60,0x40,0x34,0x24,0x1a, |
2765 | | 0x16,0x8d,0x88,0x46,0x45,0x63,0xa2,0x71,0xd1,0x84,0xe8,0xb1,0x68,0x52,0x34,0x25, |
2766 | | 0x9a,0x16,0x99,0x45,0x16,0xd1,0xbc,0x68,0x51,0xf4,0x42,0xb4,0x24,0x5a,0x16,0xad, |
2767 | | 0x88,0x6c,0xc4,0x76,0x62,0x82,0xd8,0x51,0xec,0x22,0x26,0x8a,0xdd,0xc5,0x9e,0x62, |
2768 | | 0x6f,0x31,0x49,0xec,0x2b,0x26,0x8b,0xa9,0x62,0xba,0x98,0x21,0x0e,0x16,0x87,0x88, |
2769 | | 0xc3,0xc4,0x2c,0x31,0x47,0x1c,0x2b,0x4e,0x14,0x27,0x8b,0x53,0xc5,0x69,0xe2,0x74, |
2770 | | 0x71,0x86,0x98,0x27,0x16,0x88,0x85,0x62,0x91,0x58,0x2c,0x96,0x88,0x65,0x62,0x85, |
2771 | | 0x58,0x23,0xd6,0x8a,0x75,0x62,0x83,0x15,0xa3,0xb8,0x46,0x5c,0x27,0x6e,0x14,0x37, |
2772 | | 0x8b,0x5b,0xc5,0xed,0xe2,0x0e,0x71,0xa7,0xb8,0x5b,0xdc,0x23,0x36,0x89,0x07,0xc4, |
2773 | | 0x43,0xe2,0x61,0xf1,0x88,0x78,0x54,0x3c,0x26,0x1e,0x17,0x4f,0x88,0x27,0xc5,0x53, |
2774 | | 0xe2,0x69,0xb1,0x59,0x6c,0x11,0xcf,0x8b,0x17,0xc5,0x4b,0xe2,0x65,0xf1,0x8a,0xd8, |
2775 | | 0x26,0xdf,0x2e,0x9f,0x90,0xef,0x98,0xef,0x92,0x4f,0xcc,0x77,0xcf,0xf7,0xcc,0xf7, |
2776 | | 0xce,0x27,0xe5,0xfb,0xe6,0x93,0xf3,0xa9,0xf9,0xf4,0x7c,0x46,0x7e,0x70,0x7e,0x48, |
2777 | | 0x7e,0x58,0x3e,0x2b,0x9f,0x93,0x1f,0x9b,0x9f,0x98,0x9f,0x9c,0x9f,0x9a,0x9f,0x96, |
2778 | | 0x9f,0x91,0xcf,0xcb,0x17,0xe4,0x0b,0xf3,0xc5,0xf9,0x92,0x7c,0x59,0xbe,0x22,0x5f, |
2779 | | 0x93,0xaf,0xcb,0x37,0xe6,0xd7,0xe4,0xd7,0xe5,0x37,0xe6,0x37,0xe7,0xb7,0xe6,0xb7, |
2780 | | 0xe7,0x77,0xe6,0x77,0xe7,0xf7,0xe4,0x9b,0xf2,0x07,0xf2,0x87,0xf2,0x87,0xf3,0x47, |
2781 | | 0xf2,0x47,0xf3,0xc7,0xf2,0xc7,0xf3,0x27,0xf2,0x27,0xf3,0xa7,0xf2,0xa7,0xf3,0xcd, |
2782 | | 0xf9,0x96,0xfc,0xf9,0xfc,0xc5,0xfc,0xa5,0xfc,0xe5,0xfc,0x95,0x7c,0x9b,0x02,0xbb, |
2783 | | 0x02,0x42,0x81,0x63,0x81,0x4b,0x01,0xb1,0xc0,0xbd,0xc0,0xb3,0xc0,0xbb,0x80,0x54, |
2784 | | 0xe0,0x5b,0x40,0x2e,0xa0,0x16,0xd0,0x0b,0x18,0x05,0xc1,0x05,0x21,0x05,0x61,0x05, |
2785 | | 0xac,0x02,0x4e,0x41,0x6c,0x41,0x62,0x41,0x72,0x41,0x6a,0x41,0x5a,0x41,0x46,0x01, |
2786 | | 0xaf,0x40,0x50,0x20,0x2c,0x10,0x17,0x48,0x0a,0x64,0x05,0x8a,0x02,0x4d,0x81,0xae, |
2787 | | 0xc0,0x58,0x50,0x53,0x50,0x57,0xd0,0x58,0xd0,0x5c,0xd0,0x5a,0xd0,0x5e,0xd0,0x59, |
2788 | | 0xd0,0x5d,0xd0,0x53,0x60,0x2a,0x18,0x28,0x18,0x2a,0x18,0x2e,0x18,0x29,0x18,0x2d, |
2789 | | 0x18,0x2b,0x18,0x2f,0x98,0x28,0x98,0x2c,0x98,0x2a,0x98,0x2e,0x30,0x17,0x58,0x0a, |
2790 | | 0xe6,0x0b,0x16,0x0b,0x96,0x0a,0x96,0x0b,0x56,0x0a,0x6c,0x0a,0xed,0x0a,0x09,0x85, |
2791 | | 0x8e,0x85,0x2e,0x85,0xc4,0x42,0xf7,0x42,0xcf,0x42,0xef,0x42,0x52,0xa1,0x6f,0x21, |
2792 | | 0xb9,0x90,0x5a,0x48,0x2f,0x64,0x14,0x06,0x17,0x86,0x14,0x86,0x15,0xb2,0x0a,0x39, |
2793 | | 0x85,0xb1,0x85,0x89,0x85,0xc9,0x85,0xa9,0x85,0x69,0x40,0x46,0x21,0xaf,0x50,0x50, |
2794 | | 0x28,0x2c,0x14,0x17,0x4a,0x0a,0x65,0x85,0x8a,0x42,0x4d,0xa1,0xae,0xd0,0x58,0x58, |
2795 | | 0x53,0x58,0x57,0xd8,0x58,0xd8,0x5c,0xd8,0x5a,0xd8,0x5e,0xd8,0x59,0xd8,0x5d,0xd8, |
2796 | | 0x53,0x68,0x2a,0x1c,0x28,0x1c,0x2a,0x1c,0x2e,0x1c,0x29,0x1c,0x2d,0x1c,0x2b,0x1c, |
2797 | | 0x2f,0x9c,0x28,0x9c,0x2c,0x9c,0x2a,0x9c,0x2e,0x34,0x17,0x5a,0x0a,0xe7,0x0b,0x17, |
2798 | | 0x0b,0x97,0x0a,0x97,0x0b,0x57,0x0a,0x6d,0x24,0x76,0x12,0x82,0xc4,0x51,0xe2,0x22, |
2799 | | 0x21,0x4a,0xdc,0x25,0x9e,0x12,0x6f,0x09,0x49,0xe2,0x2b,0x21,0x4b,0xa8,0x12,0xba, |
2800 | | 0x84,0x21,0x09,0x96,0x84,0x48,0xc2,0x24,0x2c,0x09,0x47,0x12,0x2b,0x49,0x94,0x24, |
2801 | | 0x4b,0x52,0x25,0x69,0x92,0x0c,0x09,0x4f,0x22,0x90,0x08,0x25,0x62,0x89,0x44,0x22, |
2802 | | 0x93,0x28,0x24,0x1a,0x89,0x4e,0x62,0x94,0xd4,0x48,0xea,0x24,0x8d,0x92,0x66,0x49, |
2803 | | 0xab,0xa4,0x5d,0xd2,0x29,0xe9,0x96,0xf4,0x48,0x4c,0x92,0x01,0xc9,0x90,0x64,0x58, |
2804 | | 0x32,0x22,0x19,0x95,0x8c,0x49,0xc6,0x25,0x13,0x92,0x49,0xc9,0x94,0x64,0x5a,0x62, |
2805 | | 0x96,0x58,0x24,0xf3,0x92,0x45,0xc9,0x92,0x64,0x59,0xb2,0x22,0xb1,0x29,0xb2,0x2b, |
2806 | | 0x22,0x14,0x39,0x16,0xb9,0x14,0x11,0x8b,0xdc,0x8b,0x3c,0x8b,0xbc,0x8b,0x48,0x45, |
2807 | | 0xbe,0x45,0xe4,0x22,0x6a,0x11,0xbd,0x88,0x51,0x14,0x5c,0x14,0x52,0x14,0x56,0xc4, |
2808 | | 0x2a,0xe2,0x14,0xc5,0x16,0x25,0x16,0x25,0x17,0xa5,0x16,0xa5,0x15,0x65,0x14,0xf1, |
2809 | | 0x8a,0x04,0x45,0xc2,0x22,0x71,0x91,0xa4,0x48,0x56,0xa4,0x28,0xd2,0x14,0xe9,0x8a, |
2810 | | 0x8c,0x45,0x35,0x45,0x75,0x45,0x8d,0x45,0xcd,0x45,0xad,0x45,0xed,0x45,0x9d,0x45, |
2811 | | 0xdd,0x45,0x3d,0x45,0xa6,0xa2,0x81,0xa2,0xa1,0xa2,0xe1,0xa2,0x91,0xa2,0xd1,0xa2, |
2812 | | 0xb1,0xa2,0xf1,0xa2,0x89,0xa2,0xc9,0xa2,0xa9,0xa2,0xe9,0x22,0x73,0x91,0xa5,0x68, |
2813 | | 0xbe,0x68,0xb1,0x68,0xa9,0x68,0xb9,0xe8,0x65,0xd1,0x4a,0x91,0x4d,0xb1,0x5d,0x31, |
2814 | | 0xa1,0xd8,0xb1,0xd8,0xa5,0x98,0x58,0xec,0x5e,0xec,0x59,0xec,0x5d,0x4c,0x2a,0xf6, |
2815 | | 0x2d,0x26,0x17,0x53,0x8b,0xe9,0xc5,0x8c,0xe2,0xe0,0xe2,0x90,0xe2,0xb0,0x62,0x56, |
2816 | | 0x31,0xa7,0x38,0xb6,0x38,0xb1,0x38,0xb9,0x38,0xb5,0x38,0xad,0x38,0xa3,0x98,0x57, |
2817 | | 0x2c,0x28,0x16,0x16,0x8b,0x8b,0x25,0xc5,0xb2,0x62,0x45,0xb1,0xa6,0x58,0x57,0x6c, |
2818 | | 0x2c,0xae,0x29,0xae,0x2b,0x6e,0x2c,0x6e,0x2e,0x6e,0x2d,0x6e,0x2f,0xee,0x2c,0xee, |
2819 | | 0x2e,0xee,0x29,0x36,0x15,0x0f,0x14,0x0f,0x15,0x0f,0x17,0x8f,0x14,0x8f,0x16,0x8f, |
2820 | | 0x15,0x8f,0x17,0x4f,0x14,0x4f,0x16,0x4f,0x15,0x4f,0x17,0x9b,0x8b,0x2d,0xc5,0xf3, |
2821 | | 0xc5,0x8b,0xc5,0x4b,0xc5,0xcb,0xc5,0x2b,0xc5,0x36,0x52,0x3b,0x29,0x41,0xea,0x28, |
2822 | | 0x75,0x91,0x12,0xa5,0xee,0x52,0x4f,0xa9,0xb7,0x94,0x24,0xf5,0x95,0x92,0xa5,0x54, |
2823 | | 0x29,0x5d,0xca,0x90,0x06,0x4b,0x43,0xa4,0x61,0x52,0x96,0x94,0x23,0x8d,0x95,0x26, |
2824 | | 0x4a,0x93,0xa5,0xa9,0x40,0x9a,0x34,0x43,0xca,0x93,0x0a,0xa4,0x42,0xa9,0x58,0x2a, |
2825 | | 0x91,0xca,0xa4,0x0a,0xa9,0x46,0xaa,0x93,0x1a,0xa5,0x35,0xd2,0x3a,0x69,0xa3,0xb4, |
2826 | | 0x59,0xda,0x2a,0x6d,0x97,0x76,0x4a,0xbb,0xa5,0x3d,0x52,0x93,0x74,0x40,0x3a,0x24, |
2827 | | 0x1d,0x96,0x8e,0x48,0x47,0xa5,0x63,0xd2,0x71,0xe9,0x84,0x74,0x52,0x3a,0x25,0x9d, |
2828 | | 0x96,0x9a,0xa5,0x16,0xe9,0xbc,0x74,0x51,0xba,0x24,0x5d,0x96,0xae,0x48,0x6d,0x64, |
2829 | | 0x76,0x32,0x82,0xcc,0x51,0xe6,0x22,0x23,0xca,0xdc,0x65,0x9e,0x32,0x6f,0x19,0x49, |
2830 | | 0xe6,0x2b,0x23,0xcb,0xa8,0x32,0xba,0x8c,0x21,0x0b,0x96,0x85,0xc8,0xc2,0x64,0x2c, |
2831 | | 0x19,0x47,0x16,0x2b,0x4b,0x94,0x25,0xcb,0x52,0x65,0x69,0xb2,0x0c,0x19,0x4f,0x26, |
2832 | | 0x90,0x09,0x65,0x62,0x99,0x44,0x26,0x93,0x29,0x64,0x1a,0x99,0x4e,0x66,0x94,0xd5, |
2833 | | 0xc8,0xea,0x64,0x8d,0xb2,0x66,0x59,0xab,0xac,0x5d,0xd6,0x29,0xeb,0x96,0xf5,0xc8, |
2834 | | 0x4c,0xb2,0x01,0xd9,0x90,0x6c,0x58,0x36,0x22,0x1b,0x95,0x8d,0xc9,0xc6,0x65,0x13, |
2835 | | 0xb2,0x49,0xd9,0x94,0x6c,0x5a,0x66,0x96,0x59,0x64,0xf3,0xb2,0x45,0xd9,0x92,0x6c, |
2836 | | 0x59,0xb6,0x22,0xb3,0x29,0xb1,0x2b,0x21,0x94,0x38,0x96,0xb8,0x94,0x10,0x4b,0xdc, |
2837 | | 0x4b,0x3c,0x4b,0xbc,0x4b,0x48,0x25,0xbe,0x25,0xe4,0x12,0x6a,0x09,0xbd,0x84,0x51, |
2838 | | 0x12,0x5c,0x12,0x52,0x12,0x56,0xc2,0x2a,0xe1,0x94,0xc4,0x96,0x24,0x96,0x24,0x97, |
2839 | | 0xa4,0x96,0xa4,0x95,0x64,0x94,0xf0,0x4a,0x04,0x25,0xc2,0x12,0x71,0x89,0xa4,0x44, |
2840 | | 0x56,0xa2,0x28,0xd1,0x94,0xe8,0x4a,0x8c,0x25,0x35,0x25,0x75,0x25,0x8d,0x25,0xcd, |
2841 | | 0x25,0xad,0x25,0xed,0x25,0x9d,0x25,0xdd,0x25,0x3d,0x25,0xa6,0x92,0x81,0x92,0xa1, |
2842 | | 0x92,0xe1,0x92,0x91,0x92,0xd1,0x92,0xb1,0x92,0xf1,0x92,0x89,0x92,0xc9,0x92,0xa9, |
2843 | | 0x92,0xe9,0x12,0x73,0x89,0xa5,0x64,0xbe,0x64,0xb1,0x64,0xa9,0x64,0xb9,0x64,0xa5, |
2844 | | 0xc4,0xa6,0xd4,0xae,0x94,0x50,0xea,0x58,0xea,0x52,0x4a,0x2c,0x75,0x2f,0xf5,0x2c, |
2845 | | 0xf5,0x2e,0x25,0x95,0xfa,0x96,0x92,0x4b,0xa9,0xa5,0xf4,0x52,0x46,0x69,0x70,0x69, |
2846 | | 0x48,0x69,0x58,0x29,0xab,0x94,0x53,0x1a,0x5b,0x9a,0x58,0x9a,0x5c,0x9a,0x5a,0x9a, |
2847 | | 0x56,0x9a,0x51,0xca,0x2b,0x15,0x94,0x0a,0x4b,0xc5,0xa5,0x92,0x52,0x59,0xa9,0xa2, |
2848 | | 0x54,0x53,0xaa,0x2b,0x35,0x00,0xc6,0xd2,0x9a,0xd2,0xba,0xd2,0xc6,0xd2,0xe6,0xd2, |
2849 | | 0xd6,0xd2,0xf6,0xd2,0xce,0xd2,0xee,0xd2,0x9e,0x52,0x53,0xe9,0x40,0xe9,0x50,0xe9, |
2850 | | 0x70,0xe9,0x48,0xe9,0x68,0xe9,0x58,0xe9,0x78,0xe9,0x44,0xe9,0x64,0xe9,0x54,0xe9, |
2851 | | 0x74,0xa9,0xb9,0xd4,0x52,0x3a,0x5f,0xba,0x58,0xba,0x54,0xba,0x5c,0xba,0x52,0x6a, |
2852 | | 0x23,0xb7,0x93,0x13,0xe4,0x8e,0x72,0x17,0x39,0x51,0xee,0x2e,0xf7,0x94,0x7b,0xcb, |
2853 | | 0x49,0x72,0x5f,0x39,0x59,0x4e,0x95,0xd3,0xe5,0x0c,0x79,0xb0,0x3c,0x44,0x1e,0x26, |
2854 | | 0x67,0xc9,0x39,0xf2,0x58,0x79,0xc2,0x1a,0x7f,0x35,0x89,0xf2,0xa4,0x5f,0x94,0x64, |
2855 | | 0x79,0xaa,0x3c,0x4d,0x9e,0x21,0xe7,0xc9,0x05,0x72,0xa1,0x5c,0x2c,0x97,0xc8,0x65, |
2856 | | 0x72,0x85,0x5c,0x23,0xd7,0xc9,0x8d,0xf2,0x1a,0x79,0x9d,0xbc,0x51,0xde,0x2c,0x6f, |
2857 | | 0x95,0xb7,0xcb,0x3b,0xe5,0xdd,0xf2,0x1e,0xb9,0x49,0x3e,0x20,0x1f,0x92,0x0f,0xcb, |
2858 | | 0x47,0xe4,0xa3,0xf2,0x31,0xf9,0xb8,0x7c,0x42,0x3e,0x29,0x9f,0x92,0x4f,0xcb,0xcd, |
2859 | | 0x72,0x8b,0x7c,0x5e,0xbe,0x28,0x5f,0x92,0x2f,0xcb,0x57,0xe4,0x36,0x0a,0x3b,0x05, |
2860 | | 0x41,0xe1,0xa8,0x70,0x51,0x10,0x15,0xee,0x0a,0x4f,0x85,0xb7,0xc2,0xe7,0x9f,0x0e, |
2861 | | 0x49,0xe1,0xab,0x20,0x2b,0xa8,0x0a,0xba,0x82,0xa1,0x08,0x56,0x84,0x28,0xc2,0x14, |
2862 | | 0x2c,0x05,0x47,0x11,0xab,0x48,0x54,0x24,0x2b,0x52,0x15,0x69,0x8a,0x0c,0x05,0x4f, |
2863 | | 0x21,0x50,0x08,0x15,0x62,0x85,0x44,0x21,0x53,0x28,0x14,0x1a,0x85,0x4e,0x61,0x54, |
2864 | | 0xd4,0x28,0xea,0x14,0x8d,0x8a,0x66,0x45,0xab,0xa2,0x5d,0xd1,0xa9,0xe8,0x56,0xf4, |
2865 | | 0x28,0x4c,0x8a,0x01,0xc5,0x90,0x62,0x58,0x31,0xa2,0x18,0x55,0x8c,0x29,0xc6,0x15, |
2866 | | 0x13,0x8a,0x49,0xc5,0x94,0x62,0x5a,0x61,0x56,0x58,0x14,0xf3,0x8a,0x45,0xc5,0x92, |
2867 | | 0x62,0x59,0xb1,0xa2,0xb0,0x51,0xda,0x29,0x09,0x4a,0x47,0xa5,0x8b,0x92,0xa8,0x74, |
2868 | | 0x57,0x7a,0xac,0xf1,0x57,0xe0,0xa9,0xf4,0x56,0x92,0x94,0xbe,0x4a,0x3f,0x25,0x59, |
2869 | | 0x49,0x55,0xd2,0x95,0x0c,0x65,0xb0,0x32,0x44,0x19,0xa6,0x64,0x29,0x39,0xca,0x58, |
2870 | | 0x65,0xa2,0x32,0x59,0x99,0xaa,0x4c,0x53,0x66,0x28,0x79,0x4a,0x81,0x52,0xa8,0x14, |
2871 | | 0x2b,0x25,0x4a,0x99,0x52,0xa1,0xd4,0x28,0x75,0x4a,0xa3,0xb2,0x46,0x59,0xa7,0x6c, |
2872 | | 0x50,0x36,0x2a,0x9b,0x95,0x2d,0xca,0x56,0x65,0x1b,0xd0,0xae,0xec,0x50,0x76,0x2a, |
2873 | | 0xbb,0x95,0x3d,0x4a,0x93,0x72,0x40,0x39,0xa4,0x1c,0x56,0x8e,0x28,0x47,0x95,0x63, |
2874 | | 0xca,0x87,0xca,0x71,0xe5,0x84,0x72,0x52,0x39,0xa5,0x7c,0xaa,0x9c,0x56,0xce,0x28, |
2875 | | 0xcd,0xca,0xb9,0x9f,0x60,0x51,0x3e,0xff,0x9e,0x79,0xe5,0x82,0x72,0x51,0xf9,0x42, |
2876 | | 0xb9,0xa4,0xfc,0x4e,0xb9,0xac,0x5c,0x51,0xda,0xa8,0x6c,0x55,0x76,0x2a,0x82,0xca, |
2877 | | 0x41,0xe5,0xa8,0x72,0x06,0x5c,0x54,0xae,0x2a,0xa2,0xca,0x4d,0xe5,0xae,0xf2,0x50, |
2878 | | 0x79,0xaa,0xbc,0x54,0xde,0x2a,0x1f,0x15,0x49,0xe5,0xab,0xf2,0x53,0x91,0x55,0x14, |
2879 | | 0x80,0xaa,0xa2,0xab,0x18,0xaa,0x60,0xd5,0x01,0x55,0x88,0x2a,0x4c,0xc5,0x52,0x71, |
2880 | | 0x54,0xb1,0xaa,0x44,0x55,0xb2,0x2a,0x45,0x95,0xaa,0x4a,0x53,0x65,0xa8,0x78,0x2a, |
2881 | | 0xbe,0x4a,0xa0,0x12,0xaa,0xc4,0x2a,0x89,0x4a,0xaa,0x92,0xa9,0xe4,0x2a,0x85,0x4a, |
2882 | | 0xa3,0xd2,0xa9,0x8c,0xaa,0x1a,0x55,0x9d,0xaa,0x51,0xd5,0xac,0x6a,0x55,0xb5,0xab, |
2883 | | 0x3a,0x54,0x9d,0xaa,0x6e,0x55,0x8f,0xca,0xa4,0x1a,0x50,0x0d,0xa9,0x86,0x55,0x23, |
2884 | | 0xaa,0x51,0xd5,0x98,0x6a,0x5c,0x35,0xa1,0x9a,0x54,0x4d,0xa9,0xa6,0x55,0x66,0x95, |
2885 | | 0x45,0xf5,0xfc,0x47,0xe6,0x55,0x8b,0xaa,0x25,0xd5,0x77,0xaa,0x65,0xd5,0x8a,0xca, |
2886 | | 0x46,0x6d,0xa7,0x26,0xa8,0x1d,0xd4,0x8e,0x6a,0x17,0x35,0x51,0xed,0xae,0xf6,0x54, |
2887 | | 0x7b,0xab,0x49,0x6a,0x5f,0x35,0x59,0x4d,0x55,0xd3,0xd5,0x0c,0x75,0xb0,0x3a,0x44, |
2888 | | 0x1d,0xa6,0x66,0xa9,0x39,0xea,0x98,0xff,0x35,0xc4,0xaa,0x93,0xd5,0x69,0x6a,0x9e, |
2889 | | 0x5a,0xa8,0x96,0xa8,0x15,0x6a,0x9d,0xba,0x46,0xdd,0xa8,0x6e,0x55,0x77,0xfc,0x48, |
2890 | | 0xa7,0xda,0xa4,0x1e,0x56,0x8f,0xa9,0x27,0xd5,0x66,0xf5,0xa2,0x7a,0x45,0x4d,0xd0, |
2891 | | 0x10,0x35,0xde,0x1a,0xb2,0x86,0xa1,0x09,0xd3,0xc4,0x6a,0x52,0x35,0x3c,0x8d,0x58, |
2892 | | 0xa3,0xd0,0x18,0x35,0x8d,0x9a,0x76,0x4d,0x8f,0x66,0x48,0x33,0xaa,0x99,0xd0,0x4c, |
2893 | | 0x6b,0xe6,0x35,0x8b,0x9a,0x25,0xcd,0x8a,0xc6,0xb6,0xcc,0xae,0x8c,0x50,0xe6,0x58, |
2894 | | 0xe6,0x52,0x46,0x2c,0x73,0x2f,0xf3,0x2c,0xf3,0x2e,0x23,0x95,0xf9,0x96,0x91,0xcb, |
2895 | | 0xa8,0x65,0xf4,0x32,0x46,0x59,0x70,0x59,0x48,0x59,0x58,0x19,0xab,0x8c,0x53,0x16, |
2896 | | 0x5b,0x96,0x58,0x96,0x5c,0x96,0x5a,0x96,0x56,0x96,0x51,0xc6,0x2b,0x13,0x94,0x89, |
2897 | | 0xcb,0x64,0x65,0x9a,0x32,0x63,0x59,0x63,0x59,0xcb,0xdf,0x41,0x6b,0x59,0x67,0x59, |
2898 | | 0x4f,0x59,0xff,0xcf,0xc2,0x40,0xd9,0xdd,0x7f,0x69,0x86,0x81,0xd1,0xb2,0xf1,0xb2, |
2899 | | 0x47,0x7f,0x96,0x89,0xb2,0xc9,0xb2,0xa9,0xb2,0xe9,0x32,0x4b,0xd9,0x7c,0xd9,0x62, |
2900 | | 0xd9,0x52,0xd9,0x72,0xd9,0x4a,0x99,0x4d,0xb9,0x5d,0x39,0xa1,0xdc,0xb1,0xdc,0xa5, |
2901 | | 0x9c,0x58,0xee,0x5e,0xee,0x59,0xee,0x5d,0x4e,0x2a,0xf7,0x2d,0x27,0x97,0x53,0xcb, |
2902 | | 0xe9,0xe5,0x8c,0xf2,0xe0,0xf2,0x90,0xf2,0xb0,0x72,0x56,0x39,0xa7,0x3c,0xb6,0x3c, |
2903 | | 0xb1,0x3c,0xb9,0x3c,0xb5,0x3c,0xad,0x3c,0xa3,0x9c,0x57,0x2e,0x28,0x17,0x96,0x8b, |
2904 | | 0xcb,0x25,0xe5,0xb2,0x72,0x45,0xb9,0xa6,0x5c,0xfb,0x3d,0xba,0xf2,0xba,0xf2,0xd6, |
2905 | | 0xf2,0xee,0xf2,0x81,0xf2,0x91,0xf2,0xf1,0xf2,0xa9,0x72,0x4b,0xf9,0x8b,0x3f,0x60, |
2906 | | 0xa9,0x7c,0xb9,0xfc,0xe5,0x1a,0x6b,0xac,0xf1,0x77,0xb2,0x52,0x6e,0xa3,0xb5,0xd3, |
2907 | | 0x12,0xb4,0x8e,0x5a,0x17,0x2d,0x51,0xeb,0xae,0xf5,0xd4,0x7a,0x6b,0x7d,0xfe,0x88, |
2908 | | 0xbd,0x5a,0x3f,0x2d,0x45,0x4b,0xd3,0x06,0x6a,0x99,0xda,0x03,0xda,0x50,0x6d,0xb8, |
2909 | | 0x96,0xad,0x8d,0xd1,0x26,0x68,0x93,0xb4,0x29,0xda,0xd3,0xda,0x74,0x2d,0x57,0xcb, |
2910 | | 0xd7,0xe6,0x68,0x45,0xda,0x42,0xad,0x54,0x2b,0xd7,0xaa,0xb5,0x5a,0xad,0x41,0x5b, |
2911 | | 0xad,0xad,0xd5,0x36,0x68,0x9b,0xb4,0x2d,0xda,0x36,0x6d,0x87,0xb6,0x4b,0x7b,0x5d, |
2912 | | 0xdb,0xa7,0xed,0xd7,0x0e,0x6a,0xef,0x6a,0xef,0x69,0xef,0x6b,0x1f,0x68,0x1f,0x6a, |
2913 | | 0x1f,0x69,0x1f,0x6b,0x9f,0x68,0x9f,0x6a,0x67,0xb4,0x73,0xda,0xe7,0xda,0x05,0xed, |
2914 | | 0x0b,0xed,0x77,0xda,0x97,0x5a,0xa4,0xb3,0xd5,0xd9,0xeb,0x1c,0x74,0xce,0x3a,0x57, |
2915 | | 0x9d,0x9b,0xce,0x43,0xe7,0xa5,0xf3,0xd1,0xed,0xd5,0xf9,0xe9,0x28,0x3a,0x9a,0x2e, |
2916 | | 0x50,0xc7,0xd4,0x1d,0xd0,0x85,0xea,0xc2,0x75,0x6c,0x5d,0x8c,0x2e,0x41,0x97,0xa4, |
2917 | | 0x4b,0xd1,0x9d,0xd6,0xa5,0xeb,0xb8,0x3a,0xbe,0x2e,0x47,0x27,0xd2,0x15,0xea,0xa4, |
2918 | | 0x3a,0xb9,0x4e,0xad,0xd3,0xea,0x0c,0xba,0x6a,0x5d,0xad,0xae,0x41,0xd7,0xa4,0x6b, |
2919 | | 0xd1,0xb5,0xe9,0x3a,0x74,0x5d,0xba,0xeb,0xba,0x3e,0x5d,0xbf,0x6e,0x50,0x77,0x57, |
2920 | | 0x77,0x4f,0x77,0x5f,0xf7,0x40,0xf7,0x50,0xf7,0x48,0xf7,0x58,0xf7,0x44,0xf7,0x54, |
2921 | | 0x37,0xa3,0x9b,0xd3,0x3d,0xd7,0x2d,0xe8,0x5e,0xe8,0xbe,0xd3,0xbd,0xd4,0x21,0xbd, |
2922 | | 0xad,0xde,0x5e,0xef,0xa0,0x77,0xd6,0xbb,0xea,0xdd,0xf4,0x1e,0x7a,0x2f,0xbd,0x8f, |
2923 | | 0x7e,0xaf,0xde,0x4f,0x4f,0xd1,0xd3,0xf4,0x81,0x7a,0xa6,0xfe,0x80,0x3e,0x54,0x1f, |
2924 | | 0xae,0x67,0xeb,0x63,0xf4,0x09,0xfa,0x24,0x7d,0x8a,0xfe,0xb4,0x3e,0x5d,0xcf,0xd5, |
2925 | | 0xf3,0xf5,0x39,0x7a,0x91,0xbe,0x50,0x2f,0xd5,0xcb,0xf5,0x6a,0xbd,0x56,0x6f,0xd0, |
2926 | | 0x57,0xeb,0x6b,0xf5,0x0d,0xfa,0x26,0x7d,0x8b,0xbe,0x4d,0xdf,0xa1,0xef,0xd2,0x5f, |
2927 | | 0xd7,0xf7,0xe9,0xfb,0xf5,0x83,0xfa,0xbb,0xfa,0x7b,0xfa,0xfb,0xfa,0x07,0xfa,0x87, |
2928 | | 0xfa,0x47,0xfa,0xc7,0xfa,0x27,0xfa,0xa7,0xfa,0x19,0xfd,0x9c,0xfe,0xb9,0x7e,0x41, |
2929 | | 0xff,0x42,0xff,0x9d,0xfe,0xa5,0x1e,0x55,0xd8,0x56,0xd8,0x57,0x38,0x54,0x38,0x57, |
2930 | | 0xb8,0x56,0xb8,0x55,0x78,0x54,0x78,0x55,0xf8,0x54,0xec,0xad,0xf0,0xab,0xa0,0x54, |
2931 | | 0xd0,0x2a,0x02,0x2b,0x98,0x15,0x07,0x2a,0x42,0x2b,0xc2,0x2b,0xd8,0x15,0x31,0x15, |
2932 | | 0x09,0x15,0x49,0x15,0x29,0x15,0xa7,0x2b,0xd2,0x2b,0xb8,0x15,0xfc,0x8a,0x9c,0x0a, |
2933 | | 0x51,0x45,0x61,0x85,0xb4,0x42,0x5e,0xa1,0xae,0xd0,0x56,0x18,0x2a,0xaa,0x2b,0x6a, |
2934 | | 0x2b,0x1a,0x2a,0x9a,0x2a,0x5a,0x2a,0xda,0x2a,0x3a,0x2a,0xba,0x2a,0xae,0x57,0xf4, |
2935 | | 0x55,0xf4,0x57,0x0c,0x56,0xdc,0xad,0xb8,0x57,0x71,0xbf,0xe2,0x41,0xc5,0xc3,0x8a, |
2936 | | 0x47,0x15,0x8f,0x2b,0x9e,0x54,0x3c,0xad,0x98,0xa9,0x98,0xab,0x78,0x5e,0xb1,0x50, |
2937 | | 0xf1,0xa2,0xe2,0xbb,0x8a,0x97,0x15,0xc8,0x60,0x6b,0xb0,0x37,0x38,0x18,0x9c,0x0d, |
2938 | | 0xae,0x06,0x37,0x83,0x87,0xc1,0xcb,0xe0,0x03,0xec,0x35,0xf8,0x19,0x28,0x06,0x9a, |
2939 | | 0x21,0xd0,0xc0,0x34,0x1c,0x30,0x84,0x1a,0xc2,0x0d,0x6c,0x43,0x8c,0x21,0xc1,0x90, |
2940 | | 0x64,0x48,0x31,0x9c,0x36,0xa4,0x1b,0xb8,0x06,0xbe,0x21,0xc7,0x20,0x32,0x14,0x1a, |
2941 | | 0xa4,0x06,0xb9,0x41,0x6d,0xd0,0x1a,0x0c,0x86,0x6a,0x43,0xad,0xa1,0xc1,0xd0,0x64, |
2942 | | 0x68,0x31,0xb4,0x19,0x3a,0x0c,0x5d,0x86,0xeb,0x86,0x3e,0x43,0xbf,0x61,0xd0,0x70, |
2943 | | 0xd7,0x70,0xcf,0x70,0xdf,0xf0,0xc0,0xf0,0xd0,0xf0,0xc8,0xf0,0xd8,0xf0,0xc4,0xf0, |
2944 | | 0xd4,0x30,0x63,0x98,0x33,0x3c,0x37,0x2c,0x18,0x5e,0x18,0xbe,0x33,0xbc,0x34,0x20, |
2945 | | 0xa3,0xad,0xd1,0xde,0xe8,0x60,0x74,0x36,0xba,0x1a,0xdd,0x8c,0x1e,0x46,0x2f,0xa3, |
2946 | | 0x8f,0x71,0xaf,0xd1,0xcf,0x48,0x31,0xd2,0x8c,0x81,0x46,0xa6,0xf1,0x80,0x31,0xd4, |
2947 | | 0x18,0x6e,0x64,0x1b,0x63,0x8c,0x09,0xc6,0x24,0x63,0x8a,0xf1,0xb4,0x31,0xdd,0xc8, |
2948 | | 0x35,0xf2,0x8d,0x39,0x46,0x91,0xb1,0xd0,0x28,0x35,0xca,0x8d,0x6a,0xa3,0xd6,0x68, |
2949 | | 0x30,0x56,0x1b,0x6b,0x8d,0x0d,0xc6,0x26,0x63,0x8b,0xb1,0xcd,0xd8,0x61,0xec,0x32, |
2950 | | 0x5e,0x37,0xf6,0x19,0xfb,0x8d,0x83,0xc6,0xbb,0xc6,0x7b,0xc6,0xfb,0xc6,0x07,0xc6, |
2951 | | 0x87,0xc6,0x47,0xc6,0xc7,0xc6,0x27,0xc6,0xa7,0xc6,0x19,0xe3,0x9c,0xf1,0xb9,0x71, |
2952 | | 0xc1,0xf8,0xc2,0xf8,0x9d,0xf1,0xa5,0x11,0x55,0xda,0x56,0xda,0x57,0x3a,0x54,0x3a, |
2953 | | 0x57,0xba,0x56,0xba,0x55,0x7a,0x54,0x7a,0x55,0xfa,0x54,0xee,0xad,0xf4,0xab,0xa4, |
2954 | | 0x54,0xd2,0x2a,0x03,0x2b,0x99,0x95,0x07,0x2a,0x43,0x2b,0xc3,0x2b,0xd9,0x95,0x31, |
2955 | | 0x95,0x09,0x95,0x49,0x95,0x29,0x95,0xa7,0x2b,0xd3,0x2b,0xb9,0x95,0xfc,0xca,0x9c, |
2956 | | 0x4a,0x51,0x65,0x61,0xa5,0xb4,0x52,0x5e,0xa9,0xae,0xd4,0x56,0x1a,0x2a,0xab,0x2b, |
2957 | | 0x6b,0x2b,0x1b,0x2a,0x9b,0x2a,0x5b,0x2a,0xdb,0x2a,0x3b,0x2a,0xbb,0x2a,0xaf,0x57, |
2958 | | 0xf6,0x55,0xf6,0x57,0x0e,0x56,0xde,0xad,0xbc,0x57,0x79,0xbf,0xf2,0x41,0xe5,0xc3, |
2959 | | 0xca,0x47,0x95,0x8f,0x2b,0x9f,0x54,0x3e,0xad,0x9c,0xa9,0x9c,0xab,0x7c,0x5e,0xb9, |
2960 | | 0x50,0xf9,0xa2,0xf2,0xbb,0xca,0x97,0x95,0xa8,0xca,0xb6,0xca,0xbe,0xca,0xa1,0xca, |
2961 | | 0xb9,0xca,0xb5,0xca,0xad,0xca,0xa3,0xca,0xab,0xca,0xa7,0x6a,0x6f,0x95,0x5f,0x15, |
2962 | | 0xa5,0x8a,0x56,0x15,0x58,0xc5,0xac,0x3a,0x50,0x15,0x5a,0x15,0x5e,0xc5,0xae,0x8a, |
2963 | | 0xa9,0x4a,0xa8,0x4a,0xaa,0x4a,0xa9,0x3a,0x5d,0x95,0x5e,0xc5,0xad,0xe2,0x57,0xe5, |
2964 | | 0x54,0x89,0xaa,0x0a,0xab,0xa4,0x55,0xf2,0x2a,0x75,0x95,0xb6,0xca,0x50,0x55,0x5d, |
2965 | | 0x55,0x5b,0xd5,0x50,0xd5,0x54,0xd5,0x52,0xd5,0x56,0xd5,0x51,0xd5,0x55,0x75,0xbd, |
2966 | | 0xaa,0xaf,0xaa,0xbf,0xea,0xff,0x63,0xef,0x4c,0x00,0x74,0xaa,0x1a,0x3e,0x7e,0x9f, |
2967 | | 0x67,0xe6,0x99,0x31,0x28,0x84,0x4a,0xb2,0x4e,0x96,0x30,0x63,0x76,0xc6,0x3a,0x86, |
2968 | | 0xc7,0x18,0xc2,0xc8,0x96,0xb4,0x18,0xb2,0x65,0xdf,0x97,0x54,0x96,0x44,0xab,0x51, |
2969 | | 0xa9,0xb4,0xd2,0x4a,0x2a,0x5b,0x92,0xb2,0x57,0x88,0x94,0x68,0x51,0xa6,0x08,0x49, |
2970 | | 0x24,0xa4,0xde,0x37,0xa5,0xfa,0x7e,0x67,0xee,0xff,0xe6,0x78,0x3e,0xde,0xf4,0xd6, |
2971 | | 0xdb,0x3a,0xcf,0xf1,0xf3,0x3f,0xe7,0xdc,0x73,0xcf,0x7e,0xce,0x3d,0x77,0x9d,0xa5, |
2972 | | 0x53,0x56,0x4e,0x79,0x65,0xca,0xba,0x29,0xaf,0x4f,0xd9,0x34,0xe5,0xed,0x29,0x5b, |
2973 | | 0xa7,0xe4,0x4e,0xd9,0x31,0x65,0xf7,0x94,0xbd,0x53,0x3e,0x9f,0x72,0x68,0xca,0x57, |
2974 | | 0x53,0xbe,0x99,0x72,0x6c,0x8a,0x93,0x13,0x9e,0x53,0x20,0xa7,0x70,0x4e,0xd1,0x9c, |
2975 | | 0x12,0x39,0xe7,0xe6,0x9c,0x9f,0x53,0x3e,0xe7,0x02,0x4c,0xd5,0x9c,0x1a,0x39,0x71, |
2976 | | 0x39,0x49,0x39,0xb5,0x73,0xea,0xe5,0xa4,0xe5,0x34,0xc9,0x69,0x96,0x73,0x51,0x4e, |
2977 | | 0x56,0x4e,0xbb,0x9c,0x4b,0x72,0x2e,0xcb,0xe9,0x92,0x73,0x55,0x4e,0xaf,0x9c,0xbe, |
2978 | | 0x39,0x03,0x73,0x86,0xe6,0x8c,0xcc,0x19,0x93,0x33,0x36,0xe7,0x86,0x9c,0xc9,0x39, |
2979 | | 0xb7,0xe6,0xe4,0xe4,0xdc,0x95,0x73,0x6f,0xce,0x03,0xf9,0xe6,0x6f,0x60,0xcc,0xdf, |
2980 | | 0x1f,0x2f,0x2f,0x0a,0x84,0x39,0x4e,0xb6,0xec,0xe1,0xd8,0x13,0xd0,0x44,0xb9,0x7d, |
2981 | | 0xb8,0x97,0x86,0xb9,0xf6,0x2a,0x68,0x3c,0x3a,0xc0,0x71,0xb5,0x09,0x9e,0x49,0x96, |
2982 | | 0xdd,0xdb,0xcf,0xf3,0x6f,0x64,0x12,0x09,0x73,0xd5,0x27,0xf5,0x4b,0xc3,0xa4,0x05, |
2983 | | 0xa4,0x05,0xd1,0xc6,0x4a,0x23,0xa8,0xfd,0x82,0xda,0x2f,0xa8,0xfd,0x82,0x0a,0x9f, |
2984 | | 0xa9,0xed,0x99,0xda,0x9e,0xa9,0xed,0x99,0xda,0xde,0x4a,0xf1,0xb7,0x56,0xb8,0xd6, |
2985 | | 0x0a,0xd7,0x5a,0xe1,0x5a,0x5b,0xdb,0x4d,0xf8,0xf6,0x0a,0xd7,0x5e,0xe1,0xda,0x2b, |
2986 | | 0x5c,0x7b,0x6d,0xef,0x24,0xff,0x6c,0x85,0xcb,0xb6,0xdc,0x7e,0x69,0x98,0xd4,0xab, |
2987 | | 0x4b,0x53,0x9e,0x6e,0x2a,0x4f,0x77,0xed,0xd7,0x5d,0xfb,0x75,0xd7,0x7e,0xdd,0x15, |
2988 | | 0xbe,0xb7,0xb6,0xf7,0xd6,0xf6,0xde,0xda,0xde,0x5b,0xdb,0xfb,0x2b,0xfe,0x01,0x0a, |
2989 | | 0x37,0x40,0xe1,0x06,0x28,0xdc,0x00,0x6b,0xbb,0x09,0x3f,0x4c,0xe1,0x86,0x29,0xdc, |
2990 | | 0x30,0x85,0x1b,0xa6,0xed,0xa3,0xe4,0x3f,0xca,0xaa,0xff,0x70,0xe5,0x3b,0x5c,0xee, |
2991 | | 0x08,0xb9,0x23,0xe4,0xae,0x2a,0x77,0x55,0xb5,0x93,0x4f,0xe5,0xf3,0xc9,0xed,0x97, |
2992 | | 0xdb,0x2f,0x77,0xa4,0xdc,0x91,0x72,0x17,0x96,0xdb,0x68,0x13,0xe9,0x55,0xd2,0xa0, |
2993 | | 0xd2,0xed,0x2e,0x0d,0x2a,0xdd,0xee,0xd2,0xa0,0xe2,0xe9,0x2e,0x0d,0x2a,0x1f,0xdd, |
2994 | | 0xa5,0x41,0xc5,0xd3,0x5d,0x9a,0xa1,0x7c,0xf4,0x94,0x66,0x28,0x9e,0x9e,0xd2,0x0c, |
2995 | | 0xc5,0xd3,0x53,0x9a,0xa1,0x76,0xea,0x29,0x6d,0xa6,0xfd,0x7a,0x59,0xfd,0x2a,0x4c, |
2996 | | 0xed,0x11,0x26,0x77,0xb8,0xdc,0xe1,0x72,0x47,0xc8,0x1d,0x21,0x77,0x55,0xb9,0xab, |
2997 | | 0xca,0x1d,0x29,0x6d,0xee,0xb8,0xfe,0x57,0xcb,0x6e,0xe2,0xbf,0x5a,0xda,0x42,0xe9, |
2998 | | 0xf7,0x91,0x5e,0xa4,0xfa,0xed,0x2b,0xbd,0x48,0xfe,0x7d,0xad,0xed,0x85,0xe5,0x2e, |
2999 | | 0x2c,0xf7,0x62,0xc7,0x75,0x1b,0x6d,0xa5,0xfd,0xfa,0x4b,0x5b,0x69,0xbf,0xfe,0xd2, |
3000 | | 0x56,0xda,0xaf,0xbf,0x74,0xa9,0xdf,0xb5,0xb7,0x56,0xb9,0x06,0x48,0x5b,0xab,0x5c, |
3001 | | 0x03,0xa4,0xc6,0x5d,0x48,0x6e,0xa3,0x17,0x2b,0xfe,0xc1,0xd2,0x8b,0x15,0xff,0x60, |
3002 | | 0xe9,0xc5,0x8a,0x7f,0xb0,0xb4,0xad,0xc2,0x0d,0x91,0xb6,0x55,0xf9,0x87,0x48,0xdb, |
3003 | | 0x6a,0xbf,0x21,0xd2,0xb6,0xda,0x6f,0x88,0xb4,0x9d,0xfc,0x87,0x4a,0xdb,0xc9,0x7f, |
3004 | | 0xa8,0xb4,0xbd,0xda,0x69,0x98,0xb4,0xbd,0xca,0x31,0x4c,0xda,0x5e,0xe5,0x18,0x26, |
3005 | | 0x6d,0xaf,0xf1,0x3a,0x4c,0xda,0x5e,0xe5,0x1a,0x26,0x6d,0xaf,0x76,0x1c,0x26,0xed, |
3006 | | 0xa8,0x7c,0x8e,0x90,0x76,0x92,0x8e,0xb2,0xdc,0x66,0x5c,0x5d,0xaa,0xf2,0x8d,0x96, |
3007 | | 0x5e,0xaa,0x7e,0x30,0x5a,0x7a,0xa9,0xf2,0x3b,0xda,0x2a,0x9f,0xa9,0xdb,0xd2,0xaa, |
3008 | | 0xdb,0xd2,0x4a,0xbb,0xb4,0xd2,0x2e,0xad,0xb1,0x73,0xa9,0x35,0x8e,0x46,0x5b,0x63, |
3009 | | 0x69,0xb4,0xd5,0x0f,0x4c,0xdf,0xba,0x48,0xfd,0xac,0xaf,0xb4,0x95,0xfc,0x5b,0xc9, |
3010 | | 0xdd,0x5f,0xda,0x48,0xfb,0x65,0x4b,0x33,0xa5,0xbd,0xa5,0xad,0xa5,0x03,0xac,0xfa, |
3011 | | 0x2d,0xac,0x3c,0x15,0xb6,0xe6,0xc9,0x70,0x6b,0x8e,0x09,0xb7,0xfc,0x7d,0x96,0xbf, |
3012 | | 0xcf,0xf2,0x2f,0x6c,0xf9,0xdb,0xf1,0x38,0x96,0xbf,0x63,0x1d,0x27,0xc2,0xad,0x39, |
3013 | | 0xd6,0x9b,0xa7,0x22,0x2d,0x7f,0xcf,0xbe,0x46,0xed,0xbc,0x47,0x9a,0xa1,0x7c,0xf6, |
3014 | | 0x94,0xb6,0x90,0xf6,0xb1,0xca,0x57,0x55,0xe5,0xab,0x6a,0xb9,0xc3,0x2d,0x3f,0x63, |
3015 | | 0x5f,0xec,0x73,0xc3,0xdf,0xe1,0x77,0xf5,0x6a,0xab,0x1d,0x4c,0x9b,0x78,0xed,0xe1, |
3016 | | 0xb5,0x45,0x86,0xda,0xbd,0xa7,0x35,0xfe,0x1c,0x8d,0x37,0xc7,0x3a,0xee,0xf9,0xac, |
3017 | | 0x63,0x86,0x4f,0xf9,0xf7,0x29,0xff,0x46,0xb7,0x4a,0xbf,0xb1,0x8e,0xa3,0x45,0xb4, |
3018 | | 0x4f,0x11,0xb9,0x8b,0xc9,0x5d,0x4c,0xf3,0x61,0x11,0xcd,0x87,0x45,0xe4,0x2e,0x26, |
3019 | | 0x77,0x31,0xb5,0x6f,0x11,0xb5,0x6f,0x11,0xb9,0x8b,0xc9,0x5d,0x4c,0xe5,0x2f,0xa2, |
3020 | | 0xb2,0x17,0x91,0xbb,0x98,0xdc,0xc5,0x34,0x9e,0x8b,0x68,0x3c,0x17,0x91,0xbb,0x98, |
3021 | | 0xdc,0xc5,0xd4,0x8e,0x45,0xd4,0x86,0x45,0xe4,0x2e,0x26,0x77,0x31,0x8d,0xe7,0xca, |
3022 | | 0xea,0xef,0x95,0x35,0x7e,0x2b,0x6b,0xfc,0x56,0xd6,0xfc,0x5b,0x58,0xf3,0x6f,0x61, |
3023 | | 0xab,0x9d,0xb3,0xad,0xf9,0xdf,0x3b,0xae,0x56,0xb1,0x8e,0xe3,0xe1,0xd6,0x31,0x30, |
3024 | | 0xdc,0x3a,0xce,0x87,0x5b,0xc7,0x48,0xcf,0x3f,0x52,0x7e,0x91,0x96,0x3b,0xdc,0xf2, |
3025 | | 0x0b,0xd7,0x38,0x0e,0xd7,0xb8,0x0e,0x57,0x7e,0x7a,0xf8,0xdd,0x76,0x37,0x65,0x1d, |
3026 | | 0x85,0xfd,0x1a,0x18,0xe7,0x77,0xe7,0x82,0x51,0x5a,0x33,0x45,0x68,0xbd,0x14,0x29, |
3027 | | 0x2d,0x28,0xad,0x2a,0x0d,0x93,0x9a,0xb9,0xa5,0x9b,0xdf,0x1d,0x9f,0xa6,0x2e,0x46, |
3028 | | 0xc2,0x34,0xbf,0xdb,0x37,0x4c,0x3b,0x17,0x0f,0x3b,0x3e,0x66,0x96,0xf8,0xdd,0x7d, |
3029 | | 0x82,0xd8,0xeb,0x5a,0x6b,0xb3,0x59,0xd2,0xa9,0x0a,0x67,0xe6,0xfd,0x69,0xb2,0xdf, |
3030 | | 0x23,0x9d,0x2e,0x7d,0x58,0xfa,0xb8,0x74,0xb6,0x17,0xb7,0x95,0xce,0x74,0xd9,0x1f, |
3031 | | 0x97,0xce,0x97,0xff,0x22,0x2f,0x7e,0x6b,0x1f,0xa3,0xaf,0xda,0x79,0x94,0xdd,0xf3, |
3032 | | 0x5b,0x61,0x85,0x31,0xfa,0x9a,0x74,0x01,0xbc,0xa0,0x34,0x36,0xcb,0x6f,0xb3,0xf6, |
3033 | | 0x59,0x03,0x2b,0xe1,0x45,0x58,0x05,0xab,0xe1,0x5e,0xa5,0xff,0x28,0x94,0x0c,0x77, |
3034 | | 0xeb,0xc7,0xa8,0x09,0x5f,0x3c,0xdc,0xdd,0x3f,0x42,0xee,0xf3,0xe4,0x3e,0x57,0xe1, |
3035 | | 0xa2,0xc3,0xdd,0xf6,0x38,0x57,0x5a,0x5b,0x9a,0xac,0xed,0xc9,0xda,0x2f,0x51,0xfb, |
3036 | | 0x75,0x90,0xbb,0x8e,0xdc,0xb5,0x15,0xae,0xb1,0xf6,0x1b,0x1a,0xae,0xbe,0x2d,0x3d, |
3037 | | 0x5b,0xfe,0x29,0xd2,0xa2,0xd2,0x38,0xcb,0x5d,0x40,0xee,0x02,0xca,0xb7,0x97,0xbe, |
3038 | | 0xd1,0xad,0xf2,0x7f,0x5f,0x7a,0xb6,0x34,0x45,0x7a,0x8e,0xb4,0x96,0xd4,0x94,0x23, |
3039 | | 0x5c,0xf9,0x0a,0x97,0xbb,0x80,0xdc,0x46,0xcb,0x4a,0x1b,0x48,0xf7,0x4a,0x3f,0x93, |
3040 | | 0xc6,0x48,0x5b,0x4a,0xa3,0x15,0x4f,0x63,0x69,0xb4,0xfc,0x1b,0x5b,0xdb,0x0b,0xc9, |
3041 | | 0x6d,0xb4,0x8a,0xfc,0x33,0xa4,0xd5,0xa5,0x2d,0xa4,0x3d,0x03,0x8c,0x4b,0x18,0x0f, |
3042 | | 0x7d,0x60,0x18,0x54,0x89,0x60,0xcc,0x47,0xb8,0xda,0x0e,0x9a,0x49,0x8d,0xbb,0x3d, |
3043 | | 0x34,0xb7,0xdc,0x43,0xb5,0xdd,0xe8,0x5a,0x69,0x73,0xe9,0x3b,0x0a,0xb7,0x4a,0xba, |
3044 | | 0x59,0x5a,0x35,0xca,0x71,0xea,0x41,0x9c,0x34,0x51,0x5a,0x52,0x7a,0xb6,0xf4,0x1c, |
3045 | | 0xe9,0xf9,0xd2,0x0a,0xd2,0x8a,0xd2,0xea,0xd2,0x9a,0xd2,0xb5,0xb0,0x5c,0xfa,0x1e, |
3046 | | 0xcc,0x84,0xa5,0xf0,0x88,0x74,0xae,0x34,0xa1,0x20,0xe1,0xa1,0xb6,0xf4,0x6c,0xe9, |
3047 | | 0x39,0xd2,0xf3,0xa5,0xd5,0xa5,0x19,0x85,0xe8,0x67,0x85,0x5c,0x6d,0x20,0xed,0x08, |
3048 | | 0x15,0xa0,0x1e,0x54,0x94,0xde,0x01,0xef,0xc1,0x1a,0x58,0x0e,0x6b,0xa5,0x6b,0xe4, |
3049 | | 0xdf,0xb4,0x30,0xf1,0xc0,0x0a,0x78,0x07,0xd6,0x58,0xfa,0xae,0x74,0xb5,0xa5,0x66, |
3050 | | 0x5b,0xd3,0x33,0x48,0x13,0x32,0xa4,0xc6,0xdd,0x11,0xde,0x87,0xf5,0xd2,0x37,0x2d, |
3051 | | 0xf5,0xfc,0xb6,0x43,0xcb,0x33,0x29,0x2b,0x6c,0x84,0x05,0x30,0x07,0xa6,0x4b,0x67, |
3052 | | 0x42,0xa1,0x22,0x8e,0x93,0x0e,0x8b,0xe1,0x22,0x69,0x1b,0x69,0x07,0x69,0x67,0x69, |
3053 | | 0x1a,0x2c,0x82,0x41,0x30,0x58,0x3a,0x14,0x16,0xc0,0x58,0xe9,0x20,0xd9,0x17,0x5a, |
3054 | | 0xea,0xf9,0x79,0x7a,0x87,0xe2,0x7b,0x40,0x3a,0x53,0xfa,0x84,0x74,0x8e,0x34,0x47, |
3055 | | 0xe9,0x55,0x2a,0xea,0x38,0xb1,0x90,0x0b,0x81,0xd2,0x8c,0x43,0x88,0x94,0x46,0x49, |
3056 | | 0x0b,0x49,0xcf,0x90,0x16,0x93,0xd6,0x91,0xd6,0x93,0x36,0x90,0x36,0x94,0xa6,0x4b, |
3057 | | 0xcd,0xf1,0xca,0x1c,0xc3,0xd3,0xb5,0x26,0x30,0xc7,0xab,0xdb,0x7d,0xee,0x7a,0xc0, |
3058 | | 0x1c,0xdb,0xbc,0xf3,0x80,0x16,0x5a,0xa3,0xb5,0xd4,0x9a,0xcc,0x1c,0x87,0x2a,0x32, |
3059 | | 0xcf,0x67,0x39,0xee,0x31,0xd5,0x1c,0x17,0xcd,0xb1,0xd3,0xac,0x37,0xcd,0xb1,0x2f, |
3060 | | 0x8b,0x6d,0x6d,0xc0,0x5f,0xc6,0x71,0xba,0x6a,0x9d,0x61,0x8e,0x81,0x9d,0xf0,0xeb, |
3061 | | 0x0c,0x97,0xf9,0xdd,0xb5,0x86,0x59,0xd7,0xf4,0x33,0xf1,0xfb,0xdc,0xe3,0x59,0x3b, |
3062 | | 0xfc,0xcf,0x66,0x9f,0x73,0x60,0xa0,0xe3,0x1e,0x67,0xcd,0xb1,0xb8,0x0c,0xee,0x01, |
3063 | | 0x6c,0x1b,0x8e,0xbd,0x52,0x19,0x77,0x5e,0x5e,0x08,0xcf,0x69,0x1e,0x5e,0xab,0x35, |
3064 | | 0xc1,0x60,0x85,0x37,0xe1,0xbc,0x30,0xab,0xac,0x30,0xf5,0x19,0xfb,0x17,0xfb,0xdd, |
3065 | | 0xf3,0xbb,0xf6,0xe8,0x21,0xc7,0xcd,0x4b,0x0f,0xf4,0x4a,0x34,0x1b,0xba,0x43,0x2f, |
3066 | | 0xe8,0x6d,0x8e,0x9f,0xe6,0xb8,0x49,0x7a,0x0f,0xa2,0xfd,0x60,0x22,0xf6,0x87,0xd1, |
3067 | | 0x41,0x30,0x10,0x06,0xc3,0x10,0x18,0x0a,0xc3,0x60,0x24,0x8c,0x87,0x09,0x30,0x87, |
3068 | | 0x32,0xdd,0x84,0xde,0x0c,0xe7,0xb3,0xdf,0x2d,0xe8,0xad,0x7e,0x77,0xbd,0x95,0x83, |
3069 | | 0x4e,0xf5,0xbb,0xeb,0xb3,0x17,0xb4,0x6e,0xa8,0xa4,0x75,0x83,0xd1,0x74,0x1d,0x93, |
3070 | | 0xbb,0x4a,0x8d,0x3b,0x5a,0xee,0x68,0xb9,0xe3,0xe5,0x8e,0xb7,0xae,0x47,0xf8,0xac, |
3071 | | 0x73,0x79,0x9f,0xd6,0x7b,0x91,0x5a,0x73,0x47,0xca,0x1d,0x2d,0x77,0xb4,0xdc,0xf1, |
3072 | | 0x72,0xc7,0xcb,0x5d,0x45,0xee,0x2a,0x72,0xc7,0xc8,0x1d,0x63,0x9d,0xff,0x3a,0xd6, |
3073 | | 0x39,0xb0,0x63,0xf9,0xfb,0x2c,0x7f,0xef,0x7a,0x48,0x8c,0xfc,0xbc,0xfd,0xe3,0xe4, |
3074 | | 0x8e,0xb3,0xd6,0x47,0x11,0xd6,0x1a,0xc9,0xd8,0x9b,0x2a,0xbf,0x3d,0xac,0xf3,0xde, |
3075 | | 0x70,0xad,0x4f,0xc3,0xb5,0xee,0x8a,0xd4,0x3a,0x27,0x52,0xee,0x68,0xb9,0xa3,0xe5, |
3076 | | 0x2e,0x20,0x77,0x01,0xb9,0xab,0xc8,0xed,0x9d,0x37,0xc7,0xca,0x1d,0xab,0x75,0x65, |
3077 | | 0x9c,0xfa,0x50,0x9c,0x75,0x7d,0xc6,0x67,0x5d,0xdb,0xf0,0x69,0x3d,0xee,0xd3,0x7a, |
3078 | | 0xdc,0x73,0x47,0xcb,0x1d,0x2d,0x77,0xbc,0xdc,0xf1,0x3a,0xbf,0x89,0xd6,0x79,0x6f, |
3079 | | 0xb4,0xe5,0x0e,0xb7,0xfc,0xc2,0xe5,0x1f,0x2f,0x3f,0x6f,0xbf,0x18,0xb9,0x8d,0xb6, |
3080 | | 0x54,0x7a,0xfd,0xa4,0x2d,0x55,0xee,0x7e,0xd2,0x96,0x8a,0xab,0x9f,0xb4,0x95,0xfc, |
3081 | | 0xfb,0x4b,0x5b,0xc9,0xbf,0xbf,0xb5,0x3d,0x5e,0xee,0x78,0xb9,0x63,0xe4,0x8e,0xb1, |
3082 | | 0xd6,0xa3,0x3e,0x6b,0x3d,0xea,0xb3,0xfc,0x0b,0x58,0xfe,0x05,0xc2,0x8e,0x9f,0x87, |
3083 | | 0x3b,0xd6,0xb9,0xb8,0x63,0xf9,0xfb,0x2c,0x7f,0x63,0xcf,0x52,0x39,0x06,0x3a,0xc7, |
3084 | | 0xdd,0x91,0x72,0x47,0x6a,0x9d,0x1e,0xa9,0x75,0xba,0xe7,0x8e,0x96,0x3b,0xda,0x72, |
3085 | | 0x87,0x5b,0x7e,0xe1,0xf2,0x8f,0x97,0x5f,0xbc,0xd6,0xef,0x91,0x5a,0xbf,0x47,0xca, |
3086 | | 0x1d,0x2d,0x77,0xb4,0x75,0x7e,0x1f,0x69,0x9d,0xe3,0x47,0x5a,0xe7,0xf1,0x91,0xd6, |
3087 | | 0xb9,0xbc,0xbd,0x7f,0xa4,0x15,0x47,0xa4,0xce,0x0b,0x22,0x75,0x5e,0xe0,0xb9,0xa3, |
3088 | | 0xe5,0x8e,0x96,0x3b,0x5e,0xee,0x78,0xb9,0x63,0xe4,0x8e,0xd1,0x79,0xc7,0x05,0x3a, |
3089 | | 0xef,0xb8,0x40,0xee,0x38,0xb9,0xe3,0xe4,0x8e,0x91,0x3b,0xc6,0xba,0x6e,0xe0,0xb3, |
3090 | | 0xae,0x1d,0xf8,0xac,0xeb,0x07,0x05,0xac,0x6b,0x08,0xc6,0xde,0x41,0x61,0x86,0x4b, |
3091 | | 0x3b,0x28,0x5f,0xc3,0xa5,0x1d,0x75,0x9e,0x37,0x42,0xda,0x51,0x75,0x31,0x42,0xda, |
3092 | | 0x51,0x63,0x60,0x84,0xb4,0xa3,0xca,0x39,0x42,0xda,0x51,0xf1,0x8c,0x90,0x5e,0x22, |
3093 | | 0xff,0x91,0xd2,0x4b,0xb4,0xdf,0x48,0xeb,0x3a,0x65,0xa4,0xce,0x57,0xbc,0xeb,0x0b, |
3094 | | 0x7e,0x5d,0x5f,0xf0,0xcb,0x1d,0x2d,0x77,0xb4,0xdc,0xf1,0x72,0xc7,0x6b,0xdc,0x7a, |
3095 | | 0xf5,0xe9,0xe5,0xab,0xa0,0xe2,0x2b,0xa8,0x79,0x74,0x39,0x73,0xeb,0xf5,0x3e,0x37, |
3096 | | 0xfe,0x46,0x8a,0x27,0x5b,0x6a,0xdc,0x51,0x72,0x47,0x59,0xd7,0x7b,0xed,0x6b,0xa5, |
3097 | | 0xf6,0x75,0x60,0xc7,0xf2,0x77,0x2c,0xff,0x28,0xcb,0xdf,0x8e,0x27,0xcc,0xf2,0x0f, |
3098 | | 0xb3,0xd2,0xf7,0x5b,0x79,0xf0,0x5b,0xd7,0x2f,0x7d,0xd6,0x35,0x4c,0x9f,0xe5,0xef, |
3099 | | 0x58,0xfe,0x8e,0xe5,0x1f,0x65,0xf9,0x47,0x59,0xfe,0x61,0x96,0xbf,0x9d,0x6e,0x84, |
3100 | | 0x95,0xae,0x77,0x9d,0x32,0x5a,0x73,0x6e,0xb4,0xdc,0x51,0x72,0x47,0xc9,0x1d,0x26, |
3101 | | 0x77,0x98,0x75,0x5d,0xdb,0xbe,0x26,0x6c,0x5f,0xef,0x76,0x2c,0x7f,0xc7,0xf2,0x8f, |
3102 | | 0xb2,0xfc,0xa3,0x2c,0xff,0x30,0xcb,0x3f,0xcc,0xca,0x8f,0xdf,0xca,0x93,0x77,0x3d, |
3103 | | 0x33,0x4a,0x73,0x70,0x94,0xdc,0xd1,0x72,0x47,0x6b,0x7e,0x89,0xd6,0xdc,0xe2,0xb9, |
3104 | | 0xa3,0xe4,0x8e,0xb2,0xae,0xa3,0xdb,0xd7,0xa0,0xed,0xeb,0xeb,0x8e,0xe5,0xef,0x58, |
3105 | | 0xfe,0x51,0x96,0xbf,0x1d,0x4f,0x98,0xe5,0x1f,0x66,0xa5,0xef,0xb7,0xf2,0xe0,0x5d, |
3106 | | 0xb7,0x2f,0x6d,0xa5,0x5b,0xda,0x4a,0xb7,0xb4,0x95,0x6e,0x69,0x2b,0xdd,0xd2,0x56, |
3107 | | 0xba,0xa5,0xad,0x74,0x4b,0x5b,0xe9,0x96,0xb6,0xd2,0x35,0xf6,0x68,0xcb,0x3f,0x5a, |
3108 | | 0xe3,0x3f,0x5a,0x63,0xdf,0x73,0x47,0xc9,0x1d,0x65,0x5d,0xa3,0xf3,0x59,0xd7,0xe9, |
3109 | | 0x7c,0x96,0xbf,0x63,0xf9,0x3b,0x96,0x7f,0x94,0xe5,0x6f,0xc7,0x13,0x66,0xf9,0x87, |
3110 | | 0x59,0xfe,0xd1,0x96,0x7f,0xb4,0xc6,0xbb,0xa3,0xf1,0xe9,0xc8,0x1d,0x2d,0xb7,0xb7, |
3111 | | 0x3d,0x4a,0xee,0x28,0xb9,0xc3,0xe4,0x0e,0xd3,0xb9,0x7d,0x71,0x69,0x09,0xcb,0xed, |
3112 | | 0x58,0x7e,0x8e,0xe5,0xef,0xb3,0xfc,0x7d,0x96,0x7f,0xba,0xe5,0x9f,0xae,0x6b,0x11, |
3113 | | 0xc5,0xa5,0x25,0x2c,0xb7,0x63,0xf9,0x39,0x96,0xbf,0xcf,0xf2,0xf7,0x59,0xfe,0xe9, |
3114 | | 0x96,0x7f,0xba,0xae,0x01,0x14,0x97,0x96,0xb0,0xdc,0x8e,0xe5,0xe7,0x58,0xfe,0x3e, |
3115 | | 0xcb,0xdf,0xd8,0xa7,0xc9,0x7f,0x9a,0xfc,0xa6,0x59,0xfb,0x4f,0xb3,0xf6,0x9f,0x66, |
3116 | | 0xed,0x3f,0xcd,0xda,0x7f,0xb1,0xfc,0x17,0xcb,0x6f,0xb1,0xb5,0xff,0x62,0x6b,0xff, |
3117 | | 0xc5,0xd6,0xfe,0x8b,0x4f,0xb2,0x7f,0xba,0xe5,0x9f,0xae,0xeb,0x34,0xc5,0xa5,0x25, |
3118 | | 0x2c,0xb7,0x63,0xf9,0x39,0x96,0xbf,0xcf,0xf2,0xf7,0x59,0xfe,0xe9,0x96,0x7f,0xba, |
3119 | | 0xae,0xc7,0x14,0x97,0x96,0xb0,0xdc,0x8e,0xe5,0xe7,0x58,0xfe,0x3e,0xcb,0xdf,0x67, |
3120 | | 0xf9,0xa7,0x5b,0xfe,0xe9,0xba,0x46,0x54,0x5c,0x5a,0xc2,0x72,0x3b,0x96,0x9f,0x63, |
3121 | | 0xf9,0xfb,0x2c,0x7f,0x9f,0xe5,0x9f,0x6e,0xf9,0xa7,0xeb,0x7a,0x51,0x71,0x69,0x09, |
3122 | | 0xcb,0xed,0x58,0x7e,0x8e,0xe5,0xef,0xb3,0xfc,0xbd,0xeb,0x5b,0xc5,0xa5,0x25,0x2c, |
3123 | | 0xb7,0x63,0xf9,0x39,0x96,0xbf,0xcf,0xf2,0xf7,0xae,0x53,0x15,0x97,0x96,0xb0,0xdc, |
3124 | | 0x8e,0xe5,0xe7,0x58,0xfe,0x3e,0xcb,0xdf,0xde,0x3f,0xdd,0xf2,0x4f,0xd7,0x75,0xae, |
3125 | | 0x12,0x96,0x3a,0x96,0xdd,0x67,0xd9,0xd3,0x75,0x8d,0xac,0xb8,0xb4,0x84,0xe5,0x76, |
3126 | | 0x2c,0x3f,0xc7,0xf2,0xf7,0x59,0xfe,0x3e,0xcb,0x3f,0xdd,0xf2,0x4f,0xd7,0xb5,0xbe, |
3127 | | 0xe2,0xd2,0x12,0x96,0xdb,0xb1,0xfc,0x1c,0xcb,0xdf,0x67,0xf9,0xfb,0x2c,0xff,0x74, |
3128 | | 0xcb,0xdf,0x1b,0xf7,0x4e,0xc8,0x75,0x42,0x27,0xe4,0x7a,0xa1,0x13,0x72,0xdd,0xd0, |
3129 | | 0xb1,0xae,0x1f,0xae,0xb0,0xda,0xd4,0xab,0x43,0x27,0xe4,0x9a,0xa1,0x63,0x5d,0x3b, |
3130 | | 0xf4,0xe6,0x9c,0xa0,0x35,0xe7,0x04,0x43,0xe6,0xae,0x60,0xc8,0xfc,0x15,0x0c,0x99, |
3131 | | 0xc3,0x82,0x21,0xf3,0x58,0x30,0x64,0x2e,0x0b,0x86,0xcc,0x67,0x41,0x6b,0x4e,0x0a, |
3132 | | 0x5a,0x73,0x52,0x30,0x64,0x6e,0x0b,0x86,0xcc,0x6f,0xc1,0x90,0x39,0x2e,0x18,0x32, |
3133 | | 0xcf,0x05,0x43,0xe6,0xba,0x60,0xc8,0x7c,0x17,0xb4,0xe6,0x8c,0xa0,0x35,0x67,0x04, |
3134 | | 0x43,0xe6,0x9e,0x60,0xc8,0xfc,0x13,0x0c,0x99,0x83,0x82,0x21,0xf3,0x50,0x30,0x64, |
3135 | | 0x2e,0x0a,0x86,0xcc,0x47,0x41,0x6b,0x4e,0x09,0x5a,0x73,0x4a,0x30,0x64,0x6e,0x0a, |
3136 | | 0x86,0xcc,0x4f,0xc1,0x90,0x39,0x2a,0x18,0x32,0x4f,0x05,0x43,0xe6,0xaa,0x60,0xc8, |
3137 | | 0x7c,0x15,0xb4,0xfa,0x6f,0xd0,0xea,0xbf,0xc1,0x90,0x71,0x10,0x0c,0x19,0x0b,0xc1, |
3138 | | 0x90,0xf1,0x10,0x0c,0x19,0x13,0xc1,0x90,0x71,0x11,0x0c,0x19,0x1b,0x41,0xab,0x7f, |
3139 | | 0x07,0xad,0xfe,0x1d,0x0c,0x19,0x27,0xc1,0x90,0xb1,0x12,0x0c,0x19,0x2f,0xc1,0x90, |
3140 | | 0x31,0x13,0x0c,0x19,0x37,0xc1,0x90,0xb1,0xe3,0xf5,0xb3,0x08,0x69,0xb8,0x35,0x9e, |
3141 | | 0xbc,0x6d,0x41,0x6b,0x6c,0x79,0xf6,0x74,0x4b,0xbd,0x3e,0x13,0x21,0x0d,0x97,0x3a, |
3142 | | 0xd6,0x3d,0x81,0xa9,0x0a,0x67,0xee,0x19,0x78,0xc7,0x03,0xcf,0x6e,0x34,0x5d,0xf7, |
3143 | | 0x11,0xd2,0xad,0xf1,0xea,0xf5,0x89,0xa0,0x35,0x76,0x3d,0x7b,0xba,0xa5,0x41,0x1d, |
3144 | | 0x23,0xbd,0xe3,0xa6,0x77,0x3c,0x72,0xac,0xfb,0x0f,0xf7,0x28,0xdc,0x8a,0x72,0x1a, |
3145 | | 0xeb,0xe5,0x34,0xf6,0xcb,0x1d,0x3f,0xb6,0x44,0x48,0xc3,0xad,0xfb,0x08,0x4e,0xc8, |
3146 | | 0xbd,0x89,0x25,0xd6,0xb1,0xa8,0x80,0x75,0xfc,0x88,0x90,0x86,0x4b,0x1d,0xeb,0x9e, |
3147 | | 0xc7,0x0f,0x4a,0xf3,0x87,0x72,0xc7,0xdd,0xde,0xfc,0x1c,0x21,0x0d,0xb7,0xee,0x59, |
3148 | | 0x38,0x21,0xf7,0x34,0x56,0xa9,0xfd,0x56,0x59,0xc7,0x84,0x74,0x2b,0x8c,0x37,0xbf, |
3149 | | 0x47,0x48,0xc3,0xa5,0x8e,0x75,0x9f,0x65,0xa6,0xf6,0x9d,0xa5,0x75,0x9a,0x77,0xcf, |
3150 | | 0xa6,0x8b,0x73,0x7c,0x7e,0xf3,0xfa,0x64,0xd0,0x9a,0xeb,0x3c,0x7b,0xba,0xa5,0x41, |
3151 | | 0x1d,0xb3,0x1c,0xeb,0x7e,0xce,0x6c,0x6b,0xee,0xf6,0xdc,0x26,0xdc,0x73,0xba,0x4f, |
3152 | | 0x64,0xd2,0xf6,0x63,0x09,0x2b,0x7f,0xfc,0x99,0x9f,0xff,0x44,0x51,0x85,0x4b,0x64, |
3153 | | 0xbf,0x58,0xe7,0xe4,0x98,0xed,0x09,0xe5,0xff,0x3f,0xc9,0x27,0xa1,0x82,0xe3,0x62, |
3154 | | 0xf6,0x09,0x10,0x67,0x43,0xe7,0x38,0xde,0xb6,0x86,0x27,0x89,0xcf,0x84,0x8f,0xd3, |
3155 | | 0xf3,0x12,0xe6,0x79,0xa2,0x64,0x48,0x81,0x5a,0x50,0x1b,0x52,0xa1,0x3a,0x9c,0x55, |
3156 | | 0xd1,0x71,0xea,0x9b,0xfb,0x6b,0x70,0xa1,0xee,0x6b,0xc7,0xe9,0xb9,0x24,0xef,0x99, |
3157 | | 0xa4,0x5f,0xb2,0x7f,0xb6,0xae,0xab,0x0e,0xd0,0x3d,0x39,0x73,0x7d,0xb5,0x97,0xae, |
3158 | | 0xab,0xf6,0xd5,0xb5,0x55,0x93,0xc6,0x40,0xdd,0xb7,0x33,0xe7,0xcb,0xde,0xfd,0xbf, |
3159 | | 0xd1,0xba,0x76,0x3b,0x44,0xf1,0xd4,0x74,0xdc,0x6b,0x87,0x9e,0xdd,0xf8,0x9b,0xeb, |
3160 | | 0x8a,0xf3,0xa4,0xdd,0xe4,0x3f,0xc0,0xb2,0x9b,0x35,0x7e,0x8e,0xcf,0x0d,0x63,0xae, |
3161 | | 0xd9,0xf5,0xd4,0x75,0x63,0x8f,0xbc,0xeb,0x6d,0x3e,0xf7,0xbc,0x2d,0x53,0xd7,0x90, |
3162 | | 0xfb,0xea,0x1a,0x72,0x2b,0xc5,0x65,0xae,0xfd,0xb4,0x51,0x5e,0x3c,0xda,0xea,0x5a, |
3163 | | 0x73,0x3b,0x5d,0x93,0xbe,0x48,0xf6,0x96,0xba,0x7f,0x3d,0x5b,0xd7,0x04,0x5a,0x38, |
3164 | | 0xc7,0xef,0x4d,0xa7,0x2b,0x9f,0xdd,0xb5,0x4f,0x53,0x85,0x37,0x69,0x6c,0x0a,0x38, |
3165 | | 0xce,0x5b,0xb0,0x19,0xb6,0x04,0xdc,0x76,0x6a,0xaa,0x7d,0xcd,0xb5,0x89,0x95,0xba, |
3166 | | 0x56,0x7c,0x27,0xcc,0x80,0x62,0x15,0xdd,0x6b,0x9f,0xde,0x75,0x6b,0xef,0x39,0x18, |
3167 | | 0xef,0xf9,0xb1,0x5a,0x96,0x3d,0xd5,0xb2,0xc7,0x5b,0xed,0x69,0xdc,0x89,0x6a,0x57, |
3168 | | 0xcf,0xee,0xf9,0x27,0x5b,0xfe,0xc9,0xd6,0xb3,0x68,0xc9,0x6a,0x7f,0xcf,0xee,0x85, |
3169 | | 0x4f,0x51,0x9f,0xf0,0xec,0x9e,0x7f,0x6d,0x6b,0xdf,0xda,0x56,0x98,0xda,0xea,0x3b, |
3170 | | 0x9e,0xdd,0x0b,0xef,0xb5,0xc3,0xc9,0xe8,0x60,0x91,0x69,0x69,0xa8,0xdd,0xe3,0x12, |
3171 | | 0x8b,0x4c,0x4b,0xbd,0x76,0x6e,0xac,0x7b,0x0a,0x2d,0x55,0x7f,0xa7,0x62,0xb8,0x45, |
3172 | | 0x6f,0x4b,0x43,0xed,0x1e,0x23,0x2d,0x7a,0x5b,0xda,0x5b,0x7d,0xab,0x9b,0xda,0xad, |
3173 | | 0x9f,0xda,0xc2,0xab,0xfb,0x1c,0x06,0x6f,0x6d,0xf3,0x4c,0x84,0xf4,0x2e,0xe9,0x26, |
3174 | | 0xe9,0xdb,0xd2,0xcd,0xd2,0xb0,0x8a,0xae,0x16,0x90,0x16,0x92,0x46,0x4b,0x2b,0x49, |
3175 | | 0xab,0x57,0xfc,0xff,0xc4,0x9e,0x84,0x7a,0x0a,0xdf,0x58,0x1a,0x94,0x36,0x93,0x9a, |
3176 | | 0x71,0x6d,0x34,0x5b,0xee,0x96,0xd2,0x7a,0xf2,0x6f,0x20,0xbd,0x4a,0xfe,0xdd,0xa5, |
3177 | | 0x83,0xa5,0x43,0xa4,0xc3,0xa5,0x23,0xa4,0xa3,0xa5,0xd7,0x48,0xc7,0x4b,0x27,0x48, |
3178 | | 0x6f,0x94,0x4e,0x92,0x3e,0x22,0x9d,0x25,0x9d,0x2d,0x9d,0x23,0x1d,0x23,0xbd,0x56, |
3179 | | 0x3a,0x55,0x7a,0x87,0x74,0x81,0x74,0xa1,0xf4,0x39,0xe9,0x22,0xaf,0x3e,0x69,0x94, |
3180 | | 0xa8,0xb8,0xd3,0x9b,0xf3,0xec,0xf1,0x14,0x6f,0xcd,0x93,0xf1,0xce,0xf1,0xf1,0xe4, |
3181 | | 0x3d,0xd7,0xe9,0x8d,0x17,0x6f,0x7c,0x78,0x63,0xd4,0xeb,0xff,0xa9,0xda,0x37,0x4e, |
3182 | | 0xf3,0x67,0xbc,0xe6,0xd0,0xaa,0xf2,0xf7,0xec,0x89,0x96,0x3d,0xc9,0xb2,0x27,0x5b, |
3183 | | 0xf6,0x14,0xcb,0x5e,0xcb,0xb2,0xd7,0xb6,0xec,0xa9,0x96,0xdd,0x2b,0x87,0xed,0x8e, |
3184 | | 0x0f,0x71,0x27,0x84,0xb8,0x13,0x43,0xdc,0x49,0x21,0xee,0xe4,0x10,0x77,0x4a,0x88, |
3185 | | 0xbb,0x56,0x88,0xbb,0x76,0x88,0x3b,0x35,0xa4,0xfc,0x5e,0xfe,0xe2,0x75,0xdc,0x4c, |
3186 | | 0x90,0x26,0x4a,0x93,0xa4,0xc9,0xd2,0x14,0x69,0x2d,0x69,0x6d,0x69,0xaa,0xd4,0x2b, |
3187 | | 0x73,0xac,0x55,0xde,0x58,0xab,0xac,0xb1,0x56,0x39,0x63,0xad,0x32,0xc6,0x5a,0xe5, |
3188 | | 0x8b,0xb5,0xca,0x16,0x6b,0x95,0x2b,0xd6,0x2a,0x53,0xac,0x55,0x9e,0x58,0xab,0x2c, |
3189 | | 0xb1,0x2a,0x5b,0xb6,0x55,0xce,0xae,0x96,0xbd,0x9b,0x65,0xbf,0xca,0xb2,0x77,0xb7, |
3190 | | 0xec,0x3d,0x2c,0x7b,0x4f,0xcb,0xde,0xcb,0xb2,0xf7,0xb6,0xec,0x57,0x5b,0xf6,0x3e, |
3191 | | 0x96,0xbd,0xaf,0x65,0xef,0x67,0xd9,0xfb,0x5b,0xf6,0x01,0x96,0x7d,0xa0,0x65,0x1f, |
3192 | | 0x64,0xd9,0x07,0x5b,0xf6,0x21,0x96,0x7d,0xa8,0x65,0x1f,0x66,0xd9,0x87,0x5b,0xf6, |
3193 | | 0x11,0x96,0x7d,0xa4,0x65,0x1f,0x65,0xd9,0x47,0xcb,0xde,0xc8,0x39,0x7e,0x3c,0x6d, |
3194 | | 0x62,0x1d,0x4f,0x4f,0xe7,0xbe,0xb0,0x7d,0x3c,0x6f,0x6b,0xdd,0x1b,0xee,0xa0,0xfb, |
3195 | | 0xc3,0xe6,0x38,0xd1,0x49,0xc7,0xf1,0x6c,0xb5,0x49,0x37,0xeb,0x58,0xdb,0x43,0x75, |
3196 | | 0xdd,0xcb,0x3a,0xee,0x86,0xae,0x67,0x06,0xa8,0x8e,0x06,0xa9,0x4e,0x86,0x58,0xf7, |
3197 | | 0x8a,0x87,0xab,0xac,0x23,0xad,0x75,0x8e,0xe9,0x0f,0xa1,0x73,0x74,0x1d,0xc7,0xa5, |
3198 | | 0xfe,0x29,0xf8,0xb0,0x9a,0x3b,0x5f,0x5d,0xad,0xbc,0x67,0xc7,0x38,0xce,0x46,0x32, |
3199 | | 0xf2,0xf0,0xc3,0x6e,0x61,0xab,0x42,0x0a,0x34,0x84,0x4e,0x30,0x11,0x6e,0x85,0x19, |
3200 | | 0xf0,0xa2,0xf1,0xa7,0x12,0xba,0x43,0x1f,0x18,0x0f,0x77,0xc3,0x1c,0xd8,0x01,0x5f, |
3201 | | 0xab,0x82,0xee,0x87,0xa3,0x50,0x92,0x8a,0x3a,0x0f,0x6a,0x43,0x23,0xb8,0x0c,0x7a, |
3202 | | 0xc3,0x78,0x78,0x1e,0xd6,0xc1,0x2e,0x78,0x8f,0x8c,0x94,0xa3,0x12,0xf7,0x53,0x89, |
3203 | | 0x7e,0x2a,0xb1,0x20,0x94,0x84,0x2a,0x30,0x04,0xb2,0x3a,0x3b,0xce,0x58,0xf8,0x06, |
3204 | | 0x8a,0x5c,0xe6,0x38,0x15,0xa1,0x36,0xf4,0x87,0x41,0xb0,0xed,0x72,0xc7,0xf9,0x04, |
3205 | | 0x0e,0xc3,0x0f,0x30,0xf8,0x0a,0xea,0x07,0xae,0x87,0xaf,0xe0,0x07,0x28,0x74,0x25, |
3206 | | 0xe7,0x11,0x90,0x05,0xd9,0x30,0x04,0x5e,0x86,0x02,0x34,0x54,0x0a,0xb4,0x80,0x9a, |
3207 | | 0x34,0x54,0x12,0x4c,0x82,0x7b,0xe0,0x31,0x58,0x02,0x3b,0xe0,0x13,0x38,0x44,0x23, |
3208 | | 0x16,0xa0,0x11,0xab,0x42,0x79,0xea,0xac,0x2b,0x8c,0x82,0x85,0xb0,0x01,0xde,0x86, |
3209 | | 0x6d,0x50,0x84,0x46,0x2d,0x01,0x49,0xd0,0x87,0x06,0xad,0x46,0x63,0xa6,0x40,0x5d, |
3210 | | 0x68,0x08,0x19,0xd0,0x09,0x3a,0xc3,0xd3,0x70,0x03,0x0d,0x7d,0x13,0xe4,0xd2,0xd8, |
3211 | | 0x7b,0xe0,0x5c,0x1a,0xbc,0x1c,0x54,0x85,0x38,0xb8,0x05,0xee,0x80,0xe1,0x74,0x82, |
3212 | | 0x6b,0xe1,0x59,0x58,0x01,0x5f,0xc0,0x36,0x3a,0xc5,0x4e,0x38,0x02,0x75,0xe8,0x18, |
3213 | | 0x2f,0xc0,0x72,0x18,0x4a,0x07,0xd9,0x00,0x47,0x61,0xc8,0x18,0xea,0x0e,0x52,0xae, |
3214 | | 0xa7,0x0f,0xc3,0xcd,0xb0,0x0c,0x7c,0x63,0x1d,0xa7,0x30,0x9c,0x05,0x89,0x70,0x3d, |
3215 | | 0xdc,0x04,0xbb,0xc6,0x39,0xce,0x3e,0x38,0x02,0xc7,0xa0,0xf0,0x78,0xc7,0x29,0x0d, |
3216 | | 0xe5,0xa0,0x3f,0x0c,0x86,0x91,0xd0,0xf2,0x46,0xca,0x07,0x69,0x93,0x19,0x2f,0xd0, |
3217 | | 0x0d,0xae,0xbb,0x89,0xfc,0xc2,0x66,0x70,0x6e,0x66,0x5e,0xbb,0x95,0x31,0x06,0xed, |
3218 | | 0x61,0x24,0x3c,0x08,0x57,0xdd,0x46,0x3f,0x87,0x85,0x30,0xe7,0x76,0xc7,0x59,0x0f, |
3219 | | 0xf7,0x4f,0x61,0xbd,0x0d,0x8b,0x60,0x6a,0x0e,0x63,0x71,0xaa,0xe3,0xac,0x81,0xd7, |
3220 | | 0xe1,0x2d,0x18,0x31,0x8d,0x3e,0x00,0xe7,0xdf,0x4d,0xdf,0x81,0x25,0xb0,0x17,0xda, |
3221 | | 0xdc,0xe3,0x38,0x57,0x40,0x57,0xe8,0x0d,0x1b,0xe0,0x00,0x1c,0x01,0xdf,0xbd,0x1c, |
3222 | | 0xef,0x61,0x1b,0x6c,0x87,0xbb,0xa7,0x73,0x5e,0x0a,0x4f,0xc3,0xac,0xfb,0x1c,0x67, |
3223 | | 0x2b,0x6c,0x87,0x4a,0xf7,0xd3,0xf6,0x90,0x00,0xf5,0xe0,0x52,0xf8,0xe4,0x01,0xc6, |
3224 | | 0xdd,0x43,0xd4,0x09,0x3c,0x0e,0x2f,0xc1,0xcb,0xb0,0x11,0xde,0x82,0xa3,0xf0,0x3d, |
3225 | | 0x9c,0xc9,0xb8,0x29,0x0e,0xe5,0xa1,0x2e,0x34,0x87,0x8b,0xe1,0x36,0x78,0x00,0x66, |
3226 | | 0x3c,0xec,0x9e,0x47,0x9d,0x15,0xe7,0x8e,0x81,0x26,0x10,0x84,0x16,0xb8,0xa7,0x43, |
3227 | | 0x4b,0x69,0x6b,0x69,0x1b,0x69,0x5b,0x69,0x7b,0x69,0x47,0x69,0x27,0x69,0x67,0xe9, |
3228 | | 0xe5,0xd2,0x2b,0xa5,0xd9,0xd2,0xab,0xa4,0x3d,0xa4,0xbd,0xa4,0x03,0x2c,0xbd,0x0f, |
3229 | | 0x06,0xcb,0x3d,0x58,0xee,0x61,0x72,0x0f,0x93,0x7b,0xa4,0xdc,0x23,0xe5,0xbe,0x46, |
3230 | | 0xee,0x6b,0xe4,0x6e,0x2a,0xb7,0x29,0xa3,0xa7,0xc6,0xff,0x41,0xf9,0x4f,0x86,0x9b, |
3231 | | 0x61,0x8e,0xdc,0xcf,0x48,0xe7,0x4a,0xe7,0x4b,0x17,0x4a,0x17,0x49,0x17,0x4b,0x97, |
3232 | | 0x48,0x5f,0x92,0x2e,0x93,0xae,0x90,0xae,0x92,0xbe,0x22,0x5d,0x23,0x5d,0x27,0x7d, |
3233 | | 0xd3,0x52,0x93,0xaf,0xcd,0x72,0x6f,0x96,0xfb,0x1d,0xb9,0xdf,0x91,0x7b,0xab,0xdc, |
3234 | | 0x5b,0xe5,0xde,0x26,0xf7,0x36,0xb9,0x9f,0x90,0xfb,0xa0,0xf4,0x90,0xf4,0xb0,0xf4, |
3235 | | 0x4b,0xe9,0xf7,0x56,0xb9,0x4c,0x5e,0x9c,0x62,0xf4,0x47,0x78,0x0a,0xfc,0xf0,0x34, |
3236 | | 0x3c,0x03,0x61,0x10,0x0e,0x01,0x98,0x07,0xf3,0x61,0x01,0x2c,0x84,0xe7,0x60,0x11, |
3237 | | 0x9c,0x07,0x11,0x10,0x09,0x05,0xa0,0x02,0x44,0x41,0x41,0x28,0x04,0x85,0xe1,0x0c, |
3238 | | 0x38,0x13,0x8a,0x40,0x51,0x28,0x06,0x67,0x41,0x36,0x74,0x85,0x6e,0x70,0x15,0x74, |
3239 | | 0x87,0x1e,0xd0,0x13,0x7a,0x41,0x6f,0xb8,0x1a,0xfa,0x40,0x5f,0xe8,0x07,0xfd,0x61, |
3240 | | 0x00,0x0c,0x84,0x41,0x30,0x18,0x86,0xc0,0x50,0x18,0x06,0x5d,0xa0,0x04,0x94,0x84, |
3241 | | 0xb5,0xb0,0x0e,0x5e,0x87,0x37,0x60,0x0b,0xbc,0x07,0xef,0xc3,0xf9,0xf0,0x21,0x6c, |
3242 | | 0x87,0x32,0x50,0x16,0xca,0x43,0x45,0x88,0x86,0x2a,0x70,0x21,0x54,0x87,0x1a,0x10, |
3243 | | 0x03,0xb1,0x50,0x13,0x12,0x20,0x05,0xd2,0x20,0x03,0x2e,0x82,0xc3,0xf0,0x25,0x74, |
3244 | | 0x84,0x4b,0xa0,0x13,0xdc,0x00,0x13,0x61,0x32,0x4c,0x85,0x3b,0xe0,0x2e,0x78,0x08, |
3245 | | 0x66,0x16,0x73,0x8f,0x69,0xe6,0xf8,0x15,0x05,0xdb,0x38,0xce,0x14,0x44,0x63,0xa0, |
3246 | | 0x10,0x24,0x0c,0x73,0x8f,0x71,0xa5,0xc0,0x07,0x17,0x72,0xac,0x89,0xeb,0xe8,0x1e, |
3247 | | 0xe7,0xcc,0xba,0xc1,0xb4,0x99,0xb7,0x86,0xf0,0x5b,0xf6,0x30,0xcb,0x1e,0xb0,0xec, |
3248 | | 0x11,0x96,0x3d,0xd2,0xb2,0x47,0x59,0xf6,0x42,0x96,0xbd,0xb0,0x65,0x3f,0xd3,0xb2, |
3249 | | 0x17,0xb1,0xec,0x45,0x2d,0x7b,0x31,0xcb,0x7e,0x96,0x65,0x77,0xd4,0xce,0x76,0x5e, |
3250 | | 0xb3,0x43,0xf2,0x9b,0x1d,0x92,0xe7,0xec,0x90,0x7c,0x67,0x87,0xe4,0x3d,0x3b,0x24, |
3251 | | 0xff,0xd9,0x21,0x65,0xc8,0x0e,0x29,0x47,0x76,0x48,0x59,0xb2,0x43,0xca,0x93,0x1d, |
3252 | | 0x52,0xa6,0xec,0x90,0x72,0x65,0x87,0x94,0x2d,0x34,0xfe,0xfe,0x21,0xe9,0xf7,0x56, |
3253 | | 0xbf,0x37,0xfd,0x79,0xce,0x49,0xb6,0x9d,0x15,0xb2,0x8f,0xe9,0x07,0x9e,0xfd,0x56, |
3254 | | 0xcb,0x1e,0x65,0xd9,0x4d,0xff,0xf0,0xec,0x77,0x59,0xfe,0xfd,0xda,0x58,0x75,0x69, |
3255 | | 0xf9,0xf7,0xb1,0xfc,0x2f,0xb7,0xfc,0xcd,0x3c,0xef,0xd9,0xcd,0x7a,0xe1,0xa7,0xf0, |
3256 | | 0x03,0xad,0x73,0xb0,0xbe,0xc7,0xed,0x55,0xad,0x30,0xe6,0x58,0xe7,0xd9,0xcd,0x9a, |
3257 | | 0xc8,0xb3,0x9b,0xf5,0x87,0x67,0xaf,0xd6,0xcb,0xca,0xbf,0xb5,0x6f,0x83,0x51,0xc7, |
3258 | | 0xed,0x67,0xb4,0xb3,0xd6,0xc2,0x83,0x8f,0xdb,0x67,0xde,0x6a,0xe5,0xd9,0x0a,0xff, |
3259 | | 0xdc,0xc5,0xc7,0xed,0xbb,0xac,0xb2,0x8c,0xb1,0xe2,0xe9,0xd1,0xd9,0x0a,0x33,0xfc, |
3260 | | 0xb8,0xdd,0xd7,0xfa,0xb8,0x7d,0xad,0x15,0x7f,0x3b,0xab,0x1e,0xfa,0x59,0x69,0x15, |
3261 | | 0xb3,0xc2,0x9b,0x75,0x86,0x67,0x3f,0x22,0x7b,0x6b,0x16,0xd6,0x63,0xae,0x70,0xd7, |
3262 | | 0x61,0x53,0xae,0x71,0xd7,0xde,0xde,0x35,0xb3,0x04,0xeb,0x5c,0x2b,0xc1,0x3a,0xd7, |
3263 | | 0x4e,0xd0,0x79,0x56,0x82,0x73,0xfc,0x3a,0x54,0x8a,0xb4,0x96,0xb4,0xb6,0x34,0x55, |
3264 | | 0xfb,0xc4,0x59,0xe7,0xdb,0x89,0x56,0x5c,0x89,0xd6,0xf9,0x7b,0xa2,0xe2,0x73,0x34, |
3265 | | 0x6f,0x87,0x69,0xae,0xf6,0xe6,0xe3,0x28,0x6b,0x0e,0x3e,0xd9,0xfc,0xeb,0x8d,0x4d, |
3266 | | 0x6f,0x4c,0x7a,0x63,0xd1,0x1b,0x83,0xde,0xd8,0xf3,0xc6,0x9c,0x37,0xd6,0xbc,0x31, |
3267 | | 0xe6,0x8d,0x2d,0x6f,0x4c,0x79,0x63,0xc9,0x1b,0x43,0xde,0xd8,0x39,0x2b,0x24,0xdc, |
3268 | | 0x62,0xa5,0xed,0x8d,0x93,0xfe,0x8a,0x73,0xa8,0xb4,0xff,0x49,0xe6,0x46,0xd3,0xe7, |
3269 | | 0x4d,0x5f,0x37,0x7d,0xdc,0xf4,0x6d,0xd3,0xa7,0x4d,0x5f,0x36,0x7d,0xd8,0xf4,0x5d, |
3270 | | 0xd3,0x67,0x4d,0x5f,0x35,0x7d,0xd4,0xf4,0x4d,0xd3,0x27,0x4d,0x5f,0x34,0x7d,0xd0, |
3271 | | 0xf4,0x3d,0xd3,0xe7,0x4c,0x5f,0x33,0x7d,0xcc,0xf4,0x2d,0xd3,0xa7,0xb6,0xa2,0xb5, |
3272 | | 0x86,0xb9,0xeb,0xf8,0xde,0xac,0xeb,0xaa,0x11,0xef,0x40,0xe2,0xdc,0x4b,0x5c,0x81, |
3273 | | 0x7b,0xdd,0xbe,0x30,0x1d,0xbf,0x6e,0x7d,0x4e,0x9c,0x9b,0xf7,0xb0,0x8e,0x3f,0x42, |
3274 | | 0xb8,0xba,0x70,0x4f,0x67,0xb7,0xef,0x99,0x3e,0x67,0xfa,0x9a,0xe9,0x63,0xa6,0x6f, |
3275 | | 0x9d,0xdf,0xc9,0x6d,0x9f,0x14,0xb5,0x53,0x2d,0xa9,0x77,0xfd,0x30,0x55,0x6d,0x18, |
3276 | | 0x67,0x5d,0x4f,0x49,0xb2,0xfa,0x8a,0xd7,0xc6,0x49,0xd6,0xb5,0x9a,0x24,0xc5,0x97, |
3277 | | 0xa4,0xf8,0x92,0x14,0x5f,0x92,0xe2,0x4b,0xb6,0xae,0xdd,0x98,0x7a,0x49,0x90,0x26, |
3278 | | 0x4a,0x93,0xa4,0xc9,0xd2,0x14,0x69,0x2d,0x69,0x6d,0x69,0xaa,0xd4,0xbb,0x9e,0xe0, |
3279 | | 0xd9,0xe3,0x2d,0xbb,0x17,0x77,0x33,0x9d,0x3b,0x76,0xd7,0x79,0xa1,0x67,0xef,0x60, |
3280 | | 0x5d,0x43,0x36,0xe7,0xb3,0x8f,0x10,0xd1,0x63,0x5a,0xa3,0xcc,0x82,0xa7,0xb4,0xee, |
3281 | | 0x7a,0x46,0xeb,0xad,0xf9,0x5a,0x8f,0x2c,0xd2,0xfa,0x6a,0x89,0xd6,0x55,0xcb,0xb4, |
3282 | | 0x9e,0x5a,0xa5,0x75,0xd4,0x1a,0xad,0x59,0xd6,0xc3,0x06,0x78,0x1d,0x36,0xc2,0x1b, |
3283 | | 0x5a,0x47,0x6d,0xd6,0x7a,0x69,0xab,0xd6,0x45,0x1f,0xc1,0x76,0xd8,0x01,0x1f,0xc3, |
3284 | | 0x4e,0xd8,0x0d,0x7b,0x60,0x2f,0x7c,0x06,0xfb,0x60,0x3f,0x7c,0x0e,0x07,0xb4,0x7e, |
3285 | | 0x3a,0xa4,0x75,0x93,0x59,0x33,0xed,0x36,0x7d,0xb1,0x9d,0x5b,0x06,0x6f,0xad,0x76, |
3286 | | 0x4c,0xf9,0x78,0x44,0xfb,0x9a,0x34,0x67,0xca,0x7d,0xc4,0x5a,0xa3,0x3d,0x22,0x8e, |
3287 | | 0x29,0xdc,0x63,0xca,0xf7,0x11,0x6b,0x9d,0xf9,0x98,0xdc,0xab,0x54,0x3f,0xb3,0xe5, |
3288 | | 0x9e,0xa5,0x7a,0x98,0x6b,0xa5,0x37,0x5d,0xfe,0xc7,0x54,0x7f,0xc7,0x54,0x97,0x47, |
3289 | | 0x14,0xf6,0x29,0xf9,0xed,0xd0,0xf6,0xc7,0x54,0xbe,0x39,0x2a,0xeb,0xcb,0x8a,0x67, |
3290 | | 0x8e,0xca,0xba,0xcf,0x8a,0x6b,0xba,0xfc,0x8e,0x58,0xee,0x23,0xaa,0x43,0x6f,0x6d, |
3291 | | 0x1c,0xba,0x56,0xde,0xa0,0xfd,0x8d,0xfb,0x13,0x2b,0x3e,0x6f,0xfb,0x7e,0x6b,0x3d, |
3292 | | 0xec,0xf9,0x1f,0xb0,0xd4,0xab,0x83,0xcf,0x94,0x67,0xcf,0xff,0x63,0xab,0xcc,0xfb, |
3293 | | 0x2d,0xff,0x83,0x56,0x19,0x42,0xf7,0x0d,0x75,0xaf,0xb3,0xea,0x79,0xbf,0xb5,0x4e, |
3294 | | 0x7f,0xcc,0x4a,0xfb,0x80,0xd2,0xd9,0xa8,0x3e,0x78,0x4c,0xf5,0xb8,0x50,0xfb,0xac, |
3295 | | 0x97,0xfd,0x98,0xb5,0xce,0x5e,0xa4,0x38,0xbc,0x78,0x17,0x59,0xed,0xe7,0xd5,0xfd, |
3296 | | 0x62,0xd5,0x85,0xdd,0xce,0x2f,0x59,0xe1,0x3c,0xfb,0xba,0x90,0xfa,0x59,0x62,0x9d, |
3297 | | 0x27,0x2c,0xb6,0xda,0x7c,0xbf,0x55,0x9e,0xf5,0xea,0xef,0x6f,0x58,0x75,0xf1,0xa6, |
3298 | | 0xf2,0xf4,0x4a,0x48,0x1f,0xb5,0xd3,0xb1,0xfd,0x5f,0xb1,0xce,0x3f,0x8e,0xa9,0xef, |
3299 | | 0xef,0xb7,0xce,0x3d,0x1e,0x51,0x5e,0xd6,0x85,0xf8,0xcf,0x0d,0x71,0x2f,0xb4,0xce, |
3300 | | 0x5b,0xec,0x71,0x60,0xf7,0x35,0xef,0x1c,0xe6,0x51,0xab,0x4d,0xbd,0x73,0x9b,0x97, |
3301 | | 0x55,0xce,0x27,0xad,0xfd,0x3f,0xb3,0xc6,0xd0,0x5c,0xd5,0x8f,0x37,0x7e,0xbc,0x71, |
3302 | | 0xb5,0xcc,0xb2,0x6f,0x50,0x1e,0xb6,0x2a,0xcc,0x2b,0xd6,0x36,0x6f,0x5c,0x6c,0xb5, |
3303 | | 0xca,0xbe,0xd8,0x3a,0x8f,0xf2,0xca,0xbf,0xc2,0x6a,0xdf,0xc7,0xac,0x3a,0xdb,0x16, |
3304 | | 0x52,0xff,0xdb,0xb4,0x6d,0x9b,0x15,0xff,0x3a,0xeb,0x3c,0xcc,0xcb,0xa7,0x67,0xf7, |
3305 | | 0xc6,0xcf,0x63,0x56,0x7f,0xf3,0xdc,0xfb,0x65,0x7f,0x59,0x6d,0xf1,0x91,0xfc,0xe6, |
3306 | | 0xca,0x7e,0x44,0x79,0xfd,0x54,0xf6,0xed,0x56,0x1c,0x9e,0x7b,0x9f,0xa5,0x76,0x7b, |
3307 | | 0xee,0xd7,0x18,0xf2,0xc6,0xab,0x6d,0xf7,0xfa,0x51,0xe8,0x18,0xdb,0x1d,0x32,0xcf, |
3308 | | 0xec,0xb6,0xe2,0xda,0x63,0xcd,0x6d,0xfb,0xac,0xb6,0xdd,0x2f,0xf7,0x67,0x21,0xfd, |
3309 | | 0xc2,0xdb,0xef,0x98,0xd5,0xd6,0xde,0x1c,0xbb,0x43,0xea,0xd5,0xdd,0x7c,0x6b,0xae, |
3310 | | 0xb1,0xc7,0xb7,0x39,0xf6,0x2c,0x19,0xe8,0x1e,0x6f,0x8c,0x26,0x48,0x13,0xa5,0x49, |
3311 | | 0xd2,0x64,0x69,0x8a,0xb4,0x96,0xb4,0xb6,0x34,0xd5,0x8a,0xc7,0x8e,0x33,0xde,0xb2, |
3312 | | 0x27,0x58,0xf6,0x44,0xcb,0x9e,0x64,0xd9,0x93,0x2d,0x7b,0x8a,0x65,0xaf,0x65,0xd9, |
3313 | | 0x6b,0x5b,0xf6,0x54,0x2b,0xdf,0x71,0x96,0xdd,0x2e,0x4f,0x82,0x65,0x4f,0xb4,0xec, |
3314 | | 0x5e,0xba,0xbd,0x74,0x7d,0x37,0x5b,0xd7,0x6b,0xb3,0x75,0xad,0xb8,0xbd,0xae,0xe3, |
3315 | | 0x66,0xeb,0xb8,0x3b,0x40,0xc7,0xdc,0x81,0x21,0xf7,0xe3,0x3c,0x4d,0xb0,0xec,0x89, |
3316 | | 0xba,0x9e,0x6c,0xe2,0x18,0xc2,0x5a,0xb6,0x28,0x11,0xc5,0xf4,0x70,0x8f,0x71,0xe6, |
3317 | | 0xba,0xa6,0x59,0xef,0x9c,0x89,0xfb,0xa5,0xbe,0xee,0x1a,0xaa,0xc8,0x95,0x9c,0xe7, |
3318 | | 0xb7,0x76,0xd7,0x51,0x03,0x95,0x7e,0x7f,0xe9,0x52,0x3d,0xf3,0xdc,0x4f,0xee,0x3e, |
3319 | | 0xd2,0x16,0xba,0x9e,0xdd,0x52,0x9a,0x21,0xf5,0xee,0x77,0xf7,0x55,0x58,0xdb,0x3d, |
3320 | | 0x50,0xd7,0xbc,0xfb,0x4b,0x97,0x86,0x1d,0xd7,0x9e,0x4a,0xc3,0x7b,0x87,0xc9,0xbb, |
3321 | | 0xef,0x3d,0x5a,0x6e,0xcf,0xde,0xd2,0xb2,0x67,0x58,0xf6,0x76,0x96,0x7d,0x69,0xd8, |
3322 | | 0xf1,0x6b,0xdb,0x7d,0x55,0x2f,0x7d,0xad,0x6b,0xde,0x3d,0xac,0xeb,0xde,0xfd,0x14, |
3323 | | 0xbe,0x9f,0x73,0x9c,0x6e,0xd2,0x3e,0xce,0x89,0xfe,0x09,0xd6,0xb6,0x04,0x4b,0xfb, |
3324 | | 0x84,0xf8,0x79,0x6d,0xd0,0xcd,0xb2,0x7b,0xda,0x27,0xc4,0xaf,0x64,0x45,0xf7,0x5a, |
3325 | | 0xbb,0x6d,0x4f,0xb0,0xfa,0x44,0x1f,0xcb,0xde,0xd2,0xb2,0x67,0x58,0xf6,0xc1,0x56, |
3326 | | 0xff,0xb1,0xed,0x5e,0x7c,0x27,0xf3,0x4b,0xb0,0x9e,0x61,0xe8,0x2f,0x5d,0x1a,0x76, |
3327 | | 0x3c,0x2f,0x43,0xb4,0xbd,0x83,0xb6,0x77,0xd0,0xf6,0x0e,0xda,0xde,0x41,0x79,0xeb, |
3328 | | 0xa0,0x7c,0x79,0x7d,0xb3,0xa3,0xc2,0x77,0x54,0xf8,0x8e,0x0a,0xdf,0x51,0xe1,0x3b, |
3329 | | 0x2a,0xbc,0xe7,0x9e,0xad,0x77,0x6d,0x66,0xeb,0x79,0xfa,0x58,0x85,0x8f,0x55,0x7f, |
3330 | | 0x1a,0xa4,0x7a,0xec,0x66,0xf5,0xfb,0xc6,0x2a,0x87,0xd7,0x4f,0x1a,0x6b,0x7c,0xc4, |
3331 | | 0x6a,0xbb,0xd7,0x1f,0x47,0xe9,0x9e,0x47,0xb6,0xfa,0x46,0x96,0xee,0x7f,0xf4,0x57, |
3332 | | 0xff,0xf5,0x68,0xa9,0xbc,0x0c,0x75,0x4e,0xec,0x37,0xfd,0xa5,0x03,0x94,0x4e,0x5f, |
3333 | | 0xdd,0x03,0xe9,0xa7,0xb1,0xd9,0xcf,0xba,0x47,0xde,0x4f,0xe1,0xfa,0x2a,0x9d,0x66, |
3334 | | 0xaa,0x0f,0xbb,0x3c,0x59,0xc2,0x6b,0x47,0xef,0x59,0x91,0xc1,0xba,0xaf,0x33,0x5c, |
3335 | | 0xf5,0xd2,0x55,0xf5,0x69,0xca,0xe8,0x8d,0x3b,0xcf,0x1e,0xaf,0xf3,0xf1,0x04,0x69, |
3336 | | 0xa2,0x34,0x49,0x9a,0x2c,0x4d,0x91,0xd6,0x92,0xd6,0x96,0xa6,0x4a,0xbd,0xb9,0xd2, |
3337 | | 0xb3,0xc7,0x5b,0xf6,0x04,0xcb,0x9e,0x68,0xd9,0x93,0x2c,0x7b,0xb2,0x65,0x4f,0xb1, |
3338 | | 0xec,0xb5,0x2c,0x7b,0x6d,0xcb,0x9e,0x6a,0xe5,0x3b,0xce,0xb2,0xdb,0xe5,0x49,0xb0, |
3339 | | 0xec,0x89,0x96,0x3d,0xc9,0xb2,0x27,0x5b,0xf6,0x14,0xcb,0x5e,0xcb,0xb2,0xd7,0xb6, |
3340 | | 0xec,0xa9,0x56,0x3d,0xc5,0x59,0x76,0x2f,0xdd,0x9e,0xd6,0xfc,0xd4,0x3c,0x9c,0x73, |
3341 | | 0x1a,0x18,0xf0,0xa4,0xdb,0x1e,0x8d,0x35,0x4f,0x99,0x5b,0x4b,0x95,0x7d,0xf8,0x41, |
3342 | | 0x15,0xb6,0xd5,0x9a,0x43,0x7f,0xf1,0xd3,0x7e,0xe8,0x6d,0x68,0x33,0xce,0x09,0xbf, |
3343 | | 0xea,0xe1,0xde,0x4b,0x58,0x87,0xfd,0x2d,0x3a,0x4e,0x02,0xe7,0x14,0x9f,0xb4,0x75, |
3344 | | 0xaf,0xc3,0x1b,0xda,0x74,0x72,0xcf,0x5d,0x27,0x31,0x29,0x37,0xc3,0xfe,0x2f,0x12, |
3345 | | 0xed,0x4d,0x83,0x4f,0xbc,0xde,0x71,0x1a,0xde,0xe8,0x38,0x2f,0x4e,0x72,0x9c,0x6f, |
3346 | | 0x26,0x3b,0xce,0x14,0xce,0x53,0xfd,0x57,0x3b,0x4e,0x69,0x1a,0xfb,0x7d,0x3a,0xd0, |
3347 | | 0x47,0x74,0x90,0xfa,0x37,0x38,0xce,0xd5,0xec,0x7b,0x78,0xba,0xe3,0x8c,0x27,0xde, |
3348 | | 0x61,0xc4,0x1b,0x4e,0x87,0x2d,0x4d,0xc7,0x89,0x61,0xdf,0xb2,0x0f,0xd1,0x9f,0x38, |
3349 | | 0x67,0xdd,0x4f,0x07,0xdc,0x38,0x91,0x31,0x70,0x93,0xe3,0xbc,0x46,0x27,0xda,0x3a, |
3350 | | 0x8e,0x73,0x65,0xe2,0x5c,0xcf,0x31,0xe0,0x1c,0x0a,0x7a,0x35,0x71,0x1e,0x63,0x9f, |
3351 | | 0x37,0x48,0xe3,0x46,0xe6,0xfb,0xc5,0x14,0xec,0x23,0x3a,0xe1,0x2b,0x0c,0x9a,0x2d, |
3352 | | 0xa4,0x59,0x94,0x6d,0x9f,0x0e,0x77,0xef,0xcd,0x44,0x10,0xef,0x65,0x70,0xf0,0x36, |
3353 | | 0xca,0x72,0x0f,0x75,0x72,0xbf,0xe3,0x7c,0xfb,0x20,0xc7,0x10,0x06,0xc0,0xf5,0x0c, |
3354 | | 0xac,0x19,0xd7,0x92,0xc6,0x04,0xf2,0x71,0xa7,0x7b,0x9f,0xe2,0xdd,0x9b,0x59,0xa7, |
3355 | | 0x5c,0x82,0x9b,0x63,0x49,0x97,0x31,0x8e,0x73,0x1d,0x71,0x74,0x25,0xbe,0xf5,0x84, |
3356 | | 0x5f,0x4d,0x9d,0xfc,0xfb,0x6e,0xf2,0xc3,0xf6,0xae,0x97,0x39,0x4e,0x71,0xd2,0xfa, |
3357 | | 0x80,0xbc,0x14,0x21,0xbf,0x35,0x89,0xa7,0xd6,0x75,0x8c,0x43,0xb6,0x6f,0x26,0x2f, |
3358 | | 0xb7,0xb0,0x5f,0x2e,0xf9,0x7a,0x1d,0xce,0x67,0x32,0x5f,0xce,0xf6,0xc3,0xa4,0x33, |
3359 | | 0x8c,0xed,0x63,0x6f,0x61,0x0d,0xd4,0xd5,0xad,0x9f,0x1f,0x48,0x2f,0x95,0xba,0xf8, |
3360 | | 0x94,0x73,0xf3,0xb3,0xba,0x50,0xaf,0xd4,0xd3,0x40,0xce,0xf5,0xcf,0xa1,0x6e,0xbe, |
3361 | | 0x23,0xcd,0x15,0x94,0x6f,0x36,0x79,0x39,0x83,0x30,0xaf,0xd3,0xb8,0x23,0x69,0xeb, |
3362 | | 0x8a,0xc4,0xf5,0x32,0xdb,0xaf,0x20,0x1f,0xbe,0x11,0x1c,0x23,0xa9,0xd7,0xa7,0x88, |
3363 | | 0xe7,0xc5,0x3e,0xee,0xfd,0x9f,0xc9,0x84,0xfb,0x81,0xf8,0x3f,0x19,0x4f,0xf9,0x98, |
3364 | | 0x6c,0xba,0x13,0xdf,0xb3,0xec,0xdf,0x9b,0xbc,0xbc,0x06,0xe3,0x98,0x4c,0x3e,0xa5, |
3365 | | 0x6c,0x03,0xd8,0xbe,0x99,0xfd,0xde,0xa4,0x4d,0xbe,0x26,0xcf,0xe9,0xed,0xdc,0x6b, |
3366 | | 0x0c,0x9f,0x53,0xcf,0xaf,0x92,0xce,0x0f,0x94,0xab,0x1a,0x75,0xf4,0xcc,0x34,0xea, |
3367 | | 0xfc,0x3e,0xc7,0xb9,0x87,0xfa,0x79,0xe3,0x21,0xf7,0xde,0xe4,0x1a,0xfa,0xc9,0x08, |
3368 | | 0x73,0xff,0x8e,0xf4,0x86,0x12,0x3e,0x47,0x37,0x6c,0xef,0xa3,0x0d,0xa2,0xd9,0x2f, |
3369 | | 0x93,0x09,0xef,0x26,0x26,0xa2,0xf5,0xec,0xff,0x15,0xf9,0x1d,0x40,0x7d,0x54,0x26, |
3370 | | 0xec,0x17,0xe4,0x35,0x9a,0x76,0x6b,0x4e,0x7d,0x9f,0x43,0x3c,0x8f,0xc2,0x32,0xd2, |
3371 | | 0x5d,0x47,0x1f,0x59,0x3d,0xd9,0x2d,0xc7,0x6b,0xc4,0xf7,0x35,0x65,0xbe,0x86,0xbc, |
3372 | | 0x3f,0x4b,0x1a,0x0d,0xc8,0xeb,0xb0,0x21,0xee,0xf9,0xed,0xd1,0x0e,0x6e,0x5d,0xbd, |
3373 | | 0x48,0x3f,0x39,0x9f,0xfa,0x5a,0x80,0x7f,0x6f,0xd2,0xb9,0x8f,0xfe,0xd7,0x94,0x34, |
3374 | | 0x92,0xee,0xa0,0x4f,0x52,0xc7,0xcd,0x68,0xeb,0x73,0xef,0xa5,0x1d,0xa8,0xbf,0x67, |
3375 | | 0xcd,0x75,0x14,0xca,0xf8,0x02,0xfe,0x1f,0xb3,0xcf,0x8d,0xc4,0xf3,0x01,0x13,0xd7, |
3376 | | 0x17,0xc4,0xd3,0x90,0x76,0x9c,0xde,0xdd,0x6d,0x8b,0x37,0xc8,0x73,0x3a,0xfd,0xe6, |
3377 | | 0x18,0x79,0x1c,0x93,0xe3,0xde,0x7f,0x9a,0x4c,0x39,0x63,0xd9,0xef,0x26,0xf2,0x79, |
3378 | | 0x0d,0x7d,0xef,0x08,0x34,0xa2,0xcd,0x1f,0x60,0x6c,0x44,0x91,0x6e,0x27,0xea,0xb6, |
3379 | | 0x0f,0xed,0x54,0x94,0x32,0x5e,0x71,0xaf,0x7b,0xed,0x27,0x96,0x7a,0x18,0xc9,0x3e, |
3380 | | 0xd5,0x49,0xa3,0x14,0xf9,0xdc,0x47,0xf8,0x6a,0x94,0xfd,0x16,0xca,0xd4,0x84,0x7a, |
3381 | | 0x3a,0xa7,0x97,0xdb,0xce,0x37,0x12,0xe6,0x42,0xe2,0x2d,0x42,0xf9,0xbb,0x9b,0xfe, |
3382 | | 0x44,0x5a,0xad,0x88,0x7f,0x16,0xdb,0x3f,0xa1,0x0d,0x23,0x88,0x7f,0x27,0xf1,0x8f, |
3383 | | 0xa2,0x6c,0x6f,0x52,0x37,0x1f,0x4f,0x76,0xef,0xe5,0xed,0x64,0xbf,0x86,0xb4,0xff, |
3384 | | 0x8b,0xe4,0xa1,0x0c,0xfb,0x6e,0x22,0xdf,0xf7,0x12,0xf6,0x5b,0xc6,0xcc,0xa3,0x6c, |
3385 | | 0xeb,0xf8,0x80,0xe3,0x3c,0x4c,0x3b,0xdd,0x43,0x5c,0x1b,0x48,0x7b,0xef,0x38,0xf7, |
3386 | | 0x3e,0x66,0xf9,0x6b,0x1c,0xe7,0x0e,0xea,0x72,0x25,0xfd,0x79,0x3a,0xf5,0x7d,0x09, |
3387 | | 0xfd,0x70,0xa5,0xb9,0x57,0x4d,0xbf,0xac,0x43,0x3e,0x22,0xe1,0x09,0xea,0x7e,0x0b, |
3388 | | 0xf9,0x7f,0x97,0x70,0x13,0xa9,0x9f,0xb2,0xec,0xff,0x1c,0xf9,0xaa,0x3b,0xc5,0xbd, |
3389 | | 0x3f,0xd9,0xf2,0x6e,0xf7,0xde,0xe4,0x16,0xc2,0xa5,0x51,0xd6,0x95,0xcc,0x03,0x97, |
3390 | | 0xd2,0x0f,0x87,0x12,0xe6,0x23,0xdc,0xd5,0x28,0xd7,0x7a,0xea,0xb0,0x1e,0x75,0x7e, |
3391 | | 0x05,0x74,0x87,0x29,0xd0,0x81,0xf6,0x58,0x3e,0xc6,0xbd,0x67,0x7a,0x16,0xe3,0xf1, |
3392 | | 0x1b,0xda,0xb9,0x36,0x75,0xfc,0x3d,0x1c,0xa4,0xde,0x8e,0x41,0x55,0xe6,0x85,0xe7, |
3393 | | 0x18,0x9b,0x1f,0xe1,0xb7,0x98,0x74,0x9e,0xa5,0xed,0x3e,0xa5,0x0e,0x5b,0x9a,0x7e, |
3394 | | 0x4b,0xde,0x76,0x43,0x1b,0xca,0xfd,0x20,0x69,0x46,0xd0,0x0f,0x7a,0x41,0x1a,0x69, |
3395 | | 0xcf,0x82,0xab,0x74,0x2f,0xfb,0x2e,0xda,0xb7,0x17,0x75,0x7c,0x3b,0x7c,0x09,0xad, |
3396 | | 0x69,0xdb,0x9d,0x30,0x95,0xfc,0x4d,0xa4,0x5e,0x47,0x50,0x9e,0xf3,0xa8,0xb7,0x8a, |
3397 | | 0xf4,0xd1,0xfe,0xd4,0x5b,0x75,0xea,0xa2,0x22,0x75,0x37,0x75,0xa4,0xbb,0x6e,0xcc, |
3398 | | 0x84,0x66,0x90,0x65,0xf2,0x3c,0xca,0xbd,0x06,0x77,0x1b,0xdc,0x0e,0x69,0xd4,0xe1, |
3399 | | 0x38,0x58,0x79,0x8d,0xdb,0xa7,0xa3,0x18,0xef,0x8d,0x60,0x30,0x65,0x0a,0xd0,0xf7, |
3400 | | 0x0e,0x50,0xcf,0xa3,0xc6,0xbb,0x74,0xa4,0x0f,0x15,0xa5,0x9e,0xee,0x06,0x1f,0xf5, |
3401 | | 0x9c,0x0a,0x5b,0x98,0x3f,0x0a,0x30,0x0f,0x3d,0x3f,0xc5,0x2d,0xfb,0x2e,0xca,0xf8, |
3402 | | 0x23,0xf5,0x52,0x97,0xb2,0x0f,0x23,0xdf,0x5f,0xa4,0xfb,0x9d,0x73,0xd9,0xb7,0x32, |
3403 | | 0x6d,0xb2,0x88,0x32,0xf7,0x82,0xb1,0xd4,0x41,0xd0,0x28,0xac,0xa5,0xfc,0xdf,0x5e, |
3404 | | 0xec,0x96,0xbf,0x3d,0x4c,0x87,0x9d,0xaa,0xff,0x85,0xd0,0x84,0xb1,0xdb,0x0e,0xba, |
3405 | | 0x5e,0x4a,0x5d,0xd2,0x76,0x9b,0x69,0xa3,0xf7,0xa1,0x37,0xfd,0xee,0x19,0xd8,0x4a, |
3406 | | 0x1a,0xad,0xa8,0x93,0x02,0xaa,0x9f,0x2e,0xaa,0xa3,0x24,0xda,0xfb,0x15,0xc6,0xda, |
3407 | | 0xf9,0x8c,0xdd,0x8b,0xa1,0x43,0x77,0xb7,0x3d,0xcd,0x5c,0x5b,0x1a,0x3a,0xf4,0x74, |
3408 | | 0xef,0xd1,0x9b,0xf9,0xc5,0xf4,0xfd,0x6d,0xd4,0xdf,0x06,0xd5,0x61,0xd9,0x81,0x6e, |
3409 | | 0x3d,0x3e,0xc9,0x3c,0x94,0x4c,0x5d,0xce,0x1d,0xec,0xf6,0x81,0x41,0xd4,0x69,0x04, |
3410 | | 0x7d,0xb7,0x2e,0x94,0xa1,0x3f,0x94,0x1b,0xee,0xf6,0x8b,0x6d,0xf0,0x15,0x34,0x27, |
3411 | | 0x7c,0x1a,0xbc,0x4e,0xbd,0xcf,0x57,0x9d,0x5e,0x43,0xff,0xe8,0x7c,0xad,0x5b,0xb7, |
3412 | | 0x0d,0x54,0xa7,0x17,0xd3,0x37,0x0f,0xc2,0x28,0x8e,0x2b,0x8d,0xa8,0xcb,0x1b,0x55, |
3413 | | 0xa7,0x2b,0x6e,0x76,0xfb,0xd0,0x86,0x9b,0xdd,0xfa,0x35,0xf3,0xe8,0x81,0x9b,0xdd, |
3414 | | 0x7a,0xbe,0xf9,0x16,0xb7,0x9e,0x6b,0x53,0xcf,0x83,0xa9,0xe7,0xe9,0x8c,0x99,0xe1, |
3415 | | 0xcc,0x0b,0x63,0xee,0x76,0xeb,0xdc,0xf4,0xc5,0x6d,0xf7,0xb8,0x75,0x5f,0xe8,0x5e, |
3416 | | 0xb7,0xfe,0xcf,0xba,0xdf,0x3d,0xbe,0x35,0xaf,0xea,0x77,0x9a,0xc0,0x3b,0x89,0x7e, |
3417 | | 0xe7,0xc1,0xba,0xcc,0x21,0x69,0xc4,0x09,0x99,0x17,0xfb,0x9d,0x4d,0x97,0xf9,0x9d, |
3418 | | 0x2d,0xd7,0xf9,0x9d,0xc6,0x84,0xbb,0xfd,0x61,0x77,0xfd,0xed,0xd1,0x5b,0xda,0xf7, |
3419 | | 0x24,0x7e,0x9e,0xbf,0xf7,0x2c,0x8a,0xa7,0x43,0x03,0xe4,0x2b,0xe0,0x6a,0x77,0xa9, |
3420 | | 0xf9,0xde,0xc8,0x75,0x96,0x7f,0x3f,0x78,0x1f,0x9e,0x83,0x2f,0x61,0x31,0xec,0x0c, |
3421 | | 0xb8,0xcf,0xad,0x9a,0xe7,0x55,0xdf,0x86,0x6d,0x90,0x0b,0x1f,0xc2,0x5e,0xd8,0x17, |
3422 | | 0x70,0x9f,0x09,0xfe,0x0c,0x5d,0x15,0x70,0x75,0xb5,0x74,0xa9,0xe5,0xb7,0x54,0xfe, |
3423 | | 0x9b,0x14,0xaf,0xd1,0x17,0xa4,0x4b,0xf5,0x5c,0xec,0x52,0x3d,0x1b,0xbb,0x54,0xe9, |
3424 | | 0x2d,0x55,0x9a,0x46,0xdf,0x91,0xbe,0x2b,0xdd,0x2a,0x7d,0x5f,0xfa,0x81,0x74,0x9b, |
3425 | | 0x34,0x57,0xfa,0x91,0x74,0x87,0xf4,0x63,0xe9,0x2e,0xe9,0x6e,0xe9,0x1e,0xe9,0xa7, |
3426 | | 0xd2,0xbd,0x52,0x2f,0xef,0xfb,0xac,0x7c,0x2c,0x51,0x7e,0x57,0x28,0xbd,0x15,0x8a, |
3427 | | 0x67,0x85,0xca,0x63,0xd2,0x1e,0x14,0xe1,0x72,0x4d,0x08,0xd7,0x85,0x30,0x36,0x84, |
3428 | | 0xd1,0x21,0x5c,0x1f,0xc2,0xa8,0x10,0x1e,0x0b,0xe1,0x89,0x10,0x6e,0x08,0x61,0x42, |
3429 | | 0x08,0x37,0x86,0x30,0x29,0x84,0xdb,0xc4,0xad,0xe2,0x76,0x31,0x59,0xdc,0x2b,0xa6, |
3430 | | 0x8a,0xd9,0x21,0xcc,0x0d,0x61,0x61,0x08,0xf3,0x43,0x78,0x51,0xbc,0x14,0x82,0xf7, |
3431 | | 0x2d,0x1b,0xfb,0x9b,0x36,0x36,0xcb,0x43,0xd8,0x6c,0x61,0x7f,0xfb,0xe6,0x99,0x10, |
3432 | | 0xd6,0x8a,0x35,0x62,0x9d,0xf0,0xbe,0xa5,0xb3,0x41,0xbc,0x2a,0x5e,0x13,0x9b,0x42, |
3433 | | 0xc8,0x14,0xf6,0xb7,0x79,0x4e,0x66,0x7f,0xe7,0x14,0xf6,0x66,0xa7,0xb0,0xaf,0x3d, |
3434 | | 0x85,0x7d,0xcd,0x29,0xec,0xeb,0x4e,0x61,0xdf,0x74,0x1a,0xf6,0xcc,0xff,0x60,0x7f, |
3435 | | 0x3d,0x04,0x6f,0x5b,0x0d,0xcb,0x1e,0x63,0xd9,0x83,0xa7,0x88,0xcb,0x68,0x55,0xed, |
3436 | | 0x57,0x55,0xfb,0x18,0x8d,0x95,0x06,0xa5,0x99,0x52,0x13,0xbe,0x9a,0xc2,0x57,0x53, |
3437 | | 0xf8,0x6a,0x0a,0x5f,0x4d,0xe1,0xab,0x29,0x7c,0x35,0x85,0xaf,0xae,0xf0,0xd5,0xb5, |
3438 | | 0xbd,0xba,0xb6,0x57,0xd7,0xf6,0x1a,0x8a,0xa7,0x86,0xb6,0xc7,0x58,0x7e,0x41,0xc5, |
3439 | | 0x5d,0x43,0x1a,0x23,0x35,0xfe,0x89,0xf2,0x4f,0x94,0x7f,0xa2,0xb6,0x25,0x6a,0x7b, |
3440 | | 0xb2,0xfc,0x93,0xe5,0x4e,0x51,0xf8,0x14,0xf9,0xa7,0x28,0x7c,0x8a,0xb6,0xd7,0x92, |
3441 | | 0x7f,0x2d,0xb9,0x6b,0x4b,0x53,0xb5,0x5f,0xaa,0xdc,0x75,0xe4,0xae,0x23,0x77,0x23, |
3442 | | 0xb9,0x1b,0x69,0xff,0x46,0x8a,0xb7,0x91,0xb5,0x3d,0x53,0x6a,0xca,0x9b,0xae,0x70, |
3443 | | 0xe9,0xda,0x9e,0xae,0xed,0xe9,0xda,0xde,0x58,0x7d,0xb4,0xb1,0xe2,0x6d,0xac,0xf0, |
3444 | | 0x8d,0x15,0xaf,0xd1,0x26,0xd2,0xa0,0x34,0x53,0xda,0x5c,0xdb,0x6a,0x48,0x63,0xa4, |
3445 | | 0xb1,0xd2,0xa0,0x34,0x53,0xda,0x5c,0x7e,0x76,0xdd,0x07,0xad,0x3a,0xf6,0xc8,0xb4, |
3446 | | 0xfa,0x50,0x53,0x85,0x6f,0xaa,0xf0,0x4d,0x15,0xbe,0xa9,0xc2,0x34,0x55,0xf8,0xa6, |
3447 | | 0x0a,0x9f,0xa1,0xf0,0x19,0xda,0x9e,0xa1,0xed,0x19,0xda,0xde,0xdc,0xea,0xb7,0x5e, |
3448 | | 0x9f,0x8d,0xb5,0xf2,0xd6,0xdc,0xea,0xb3,0x86,0x38,0x18,0x08,0xf1,0xd2,0x4c,0xa9, |
3449 | | 0x79,0x76,0xea,0x22,0xb4,0x8d,0xec,0x2d,0x2d,0x7b,0x2b,0xcb,0xde,0xda,0xb2,0x67, |
3450 | | 0x59,0xf6,0x36,0x8a,0xc7,0x1b,0x1b,0xf1,0x96,0x3d,0xe1,0x14,0x63,0xa9,0xe9,0xcf, |
3451 | | 0x8c,0xab,0x78,0x69,0x42,0xc8,0x78,0x6a,0x7a,0x8a,0x71,0x15,0x2f,0x4d,0x08,0x19, |
3452 | | 0x4f,0x4d,0x4f,0x31,0xae,0xe2,0xa5,0x09,0x21,0xe3,0xab,0xe9,0x49,0xc6,0xd9,0xc9, |
3453 | | 0xfa,0xe1,0xa9,0xfa,0xdd,0xcf,0xf5,0xaf,0x53,0xf5,0xa3,0x2a,0x56,0x9f,0x69,0xaa, |
3454 | | 0xfc,0x35,0x55,0xfe,0xec,0xfe,0xd1,0xf4,0x24,0xfd,0x24,0xd3,0xaa,0x7f,0xaf,0xee, |
3455 | | 0x13,0x42,0xfa,0x41,0xd3,0x93,0xf4,0x87,0x9f,0x9b,0xfb,0x62,0x4f,0xd1,0x76,0x19, |
3456 | | 0xa7,0x39,0xf7,0x65,0x9c,0xe6,0x9c,0x97,0x61,0xb5,0xc1,0x2f,0x99,0xd3,0x7e,0xe9, |
3457 | | 0x5c,0x16,0xfb,0x5f,0xcc,0x69,0xbf,0xd5,0x5c,0x16,0x3a,0x77,0x9d,0xee,0x1c,0x75, |
3458 | | 0x3a,0x73,0x52,0xc6,0x69,0xcc,0x45,0xa7,0x33,0xf7,0x64,0x9c,0x62,0xce,0x19,0x78, |
3459 | | 0x9a,0x73,0x4d,0xc6,0xcf,0xf4,0x97,0xd0,0x7e,0x71,0xb2,0xf6,0xaf,0x2e,0x77,0xa2, |
3460 | | 0xd5,0xbe,0xc6,0x9d,0x24,0x77,0x92,0xdc,0x27,0xab,0xa7,0xe0,0x49,0xca,0x13,0x9a, |
3461 | | 0xbf,0xb4,0x88,0xe3,0x73,0x9a,0xb1,0xb7,0xb6,0xec,0xde,0x9c,0x56,0x4b,0xe3,0xa4, |
3462 | | 0x96,0xf6,0x4b,0x95,0x3b,0x55,0xee,0x3a,0x72,0xd7,0x91,0x3b,0x51,0xee,0x44,0xb9, |
3463 | | 0x93,0xe4,0x4e,0xb2,0xea,0x2b,0xd3,0xaa,0xb7,0x1a,0x72,0xd7,0xb0,0xea,0x31,0xd3, |
3464 | | 0xaa,0xcf,0x64,0xb9,0x93,0xe5,0x4e,0x91,0x3b,0xc5,0x8a,0xbf,0x86,0x34,0x46,0x1a, |
3465 | | 0x1b,0x52,0x47,0xf1,0xca,0x4f,0xbc,0xe2,0x89,0xd7,0xfe,0xf1,0xff,0x80,0xf2,0xfd, |
3466 | | 0xdc,0xfe,0x76,0x9f,0xca,0xb0,0xd6,0x2d,0xa7,0x9a,0x4b,0x4e,0x15,0x5f,0xe8,0x7a, |
3467 | | 0xc7,0xcc,0xe1,0x2d,0x2c,0xad,0x66,0x8d,0xc9,0x6a,0xd6,0x5c,0x76,0x32,0x7b,0xd0, |
3468 | | 0x9a,0x1b,0x83,0xd6,0xf8,0xa8,0x61,0xd9,0x63,0x2c,0x7b,0xec,0x49,0xe6,0x48,0xcf, |
3469 | | 0x1e,0x63,0xf5,0xf9,0x18,0x6b,0x1d,0x92,0x68,0x85,0x4d,0xb4,0xe6,0xd5,0x44,0xab, |
3470 | | 0xcd,0x12,0xad,0x78,0x4e,0x66,0xaf,0x61,0xd9,0x83,0x21,0xf6,0x64,0x2b,0xfd,0x50, |
3471 | | 0x7b,0xd0,0x6a,0xbb,0x98,0x53,0xd8,0x6b,0x58,0xed,0x1f,0x0c,0x69,0x33,0xdb,0x1e, |
3472 | | 0x0c,0xb1,0xa7,0x58,0x7d,0x30,0xc5,0xaa,0x43,0xdb,0x5e,0xcb,0x2a,0xcb,0xc9,0xec, |
3473 | | 0x76,0x98,0xe6,0xd6,0x7c,0x1f,0xb4,0xe6,0xfc,0x53,0xd9,0x33,0xad,0xe3,0x40,0xd0, |
3474 | | 0xb2,0x37,0xb7,0xec,0x99,0xd6,0x31,0x21,0x18,0x62,0x4f,0xb7,0xf2,0x93,0x6e,0xc5, |
3475 | | 0xd3,0xc4,0xaa,0x9f,0x26,0xd6,0xf8,0x6a,0x62,0x95,0xd7,0x3b,0x3e,0xd4,0x38,0x89, |
3476 | | 0x3d,0xd6,0xda,0x37,0x36,0x64,0x9e,0x8c,0x09,0xb1,0x9f,0xac,0x1f,0x05,0x2d,0x7b, |
3477 | | 0xf3,0x90,0xe3,0xb3,0x7d,0xbc,0x09,0xed,0x8f,0xf6,0x71,0xc7,0x3b,0x56,0xdb,0xc7, |
3478 | | 0xa8,0x8c,0x90,0xe3,0x52,0x4c,0x88,0x3d,0xd3,0x3a,0x5e,0x05,0x4f,0x61,0xcf,0xb4, |
3479 | | 0xe6,0xfa,0xe6,0x96,0x3d,0xd3,0xca,0x6b,0x30,0xc4,0x5e,0xd5,0x9a,0x83,0xaa,0x59, |
3480 | | 0xfd,0xad,0x9a,0x15,0x67,0xb5,0x90,0x30,0xb1,0x96,0x7f,0xd0,0xf2,0x0f,0x5a,0x73, |
3481 | | 0x5c,0x30,0xe4,0x7c,0xcc,0xf6,0xcf,0xb4,0xe6,0x91,0x4c,0x6b,0x5c,0x34,0xb7,0xfa, |
3482 | | 0x7f,0x73,0xab,0x0f,0xdb,0xe7,0x21,0xf6,0x9a,0xb1,0x79,0xc8,0xb1,0xd7,0x3e,0x1e, |
3483 | | 0x37,0x3f,0x49,0x59,0x9b,0x5b,0x7d,0xa9,0xb9,0x55,0xb7,0xcd,0x43,0xfa,0x9b,0xdd, |
3484 | | 0xc7,0x52,0xad,0xf0,0x8d,0x4f,0x72,0xde,0x62,0xaf,0x2b,0xec,0x7c,0x06,0xad,0xf0, |
3485 | | 0xc1,0x10,0xff,0xa6,0x21,0x6b,0xba,0x18,0xab,0x1c,0x35,0x42,0xfa,0x55,0x73,0x6b, |
3486 | | 0xbd,0xd4,0xdc,0x5a,0x5b,0x36,0x0f,0x89,0xdf,0x1e,0x9b,0xc9,0x21,0x73,0x51,0x6c, |
3487 | | 0x48,0x9e,0xbd,0xe3,0x4d,0x13,0x5d,0x3b,0x49,0xb7,0xec,0x55,0x64,0xf7,0xd6,0x50, |
3488 | | 0xde,0x1a,0xde,0x3b,0xff,0xb0,0xc7,0x41,0x4d,0x2b,0x1e,0xaf,0x9e,0xbc,0x63,0x50, |
3489 | | 0x33,0xcb,0xbf,0x89,0xb5,0xd6,0x68,0xa6,0xed,0x4d,0xac,0xbc,0x36,0xb1,0xfa,0x81, |
3490 | | 0x67,0xcf,0xfb,0x1b,0x2b,0x21,0x79,0x31,0x7e,0xa1,0xf1,0x19,0xbf,0xd0,0x38,0xbd, |
3491 | | 0xb1,0x6e,0xb6,0x79,0xf6,0x2a,0x56,0x3c,0xf1,0xba,0xce,0xe1,0xf9,0xd5,0x30,0xcf, |
3492 | | 0x4d,0xc7,0x39,0x8e,0x3f,0xce,0x7d,0x5f,0xaf,0xae,0xf5,0x1d,0x86,0xb3,0xf1,0x3b, |
3493 | | 0x27,0xee,0xe4,0xdf,0x7d,0x28,0x41,0x02,0xc5,0xe1,0x4a,0xc7,0xc5,0xfb,0x66,0xc2, |
3494 | | 0x35,0x70,0xad,0xd9,0xce,0x7e,0x25,0xa1,0x28,0x14,0x83,0x82,0x50,0x28,0xee,0xf8, |
3495 | | 0xfb,0xc9,0x85,0xe1,0x0c,0x38,0x13,0x8a,0x98,0xf7,0x88,0xcc,0x73,0xe0,0xd6,0xb7, |
3496 | | 0x21,0x4e,0xa5,0x5e,0x7a,0x06,0x2f,0xef,0xb1,0xca,0x77,0x1d,0xeb,0x5b,0x12,0x26, |
3497 | | 0x7f,0xa7,0xca,0x53,0xb4,0xb9,0x87,0x6b,0x9e,0x5f,0xd7,0x77,0x1f,0x62,0x1c,0xf7, |
3498 | | 0x3d,0xf0,0x06,0x7a,0x37,0xf1,0x32,0xf3,0x9d,0x48,0xf3,0xad,0x58,0x48,0x53,0x9e, |
3499 | | 0x5a,0x68,0x4d,0xd8,0xc2,0x3a,0x3f,0xf6,0xce,0x8d,0xbd,0xf3,0x62,0x6f,0x2d,0xe9, |
3500 | | 0x9d,0x1b,0x7b,0xeb,0x49,0xef,0xfc,0xd8,0x5b,0x53,0x7a,0xe7,0xc8,0x69,0xd6,0x39, |
3501 | | 0xf3,0xc5,0x72,0x1b,0xad,0x10,0x71,0xe2,0xb7,0xb2,0xed,0x6f,0x66,0x87,0x7e,0x3b, |
3502 | | 0x3b,0xf4,0x1b,0xda,0xa1,0xdf,0xd2,0x3e,0x95,0x56,0x11,0x55,0x43,0xb8,0x50,0x54, |
3503 | | 0x0b,0xa1,0x7a,0x08,0x35,0x42,0x88,0x09,0x21,0x36,0x84,0x9a,0x22,0x4e,0xc4,0x8b, |
3504 | | 0x04,0x91,0x18,0x42,0x52,0x08,0xc9,0x21,0xa4,0x84,0x50,0x2b,0x84,0xda,0x21,0xa4, |
3505 | | 0x86,0x50,0x27,0x84,0x46,0x21,0xa4,0x87,0xd0,0x38,0x84,0x26,0x21,0x04,0x43,0x68, |
3506 | | 0x1a,0x42,0x46,0x08,0xcd,0x44,0xe6,0x49,0xce,0xc1,0x9b,0x5b,0xe3,0xb6,0xed,0x29, |
3507 | | 0xec,0xed,0x4e,0x61,0x6f,0x7f,0x0a,0xbb,0xa7,0x66,0x6c,0x54,0x74,0xdc,0x31,0xe0, |
3508 | | 0xf5,0x71,0x33,0x16,0xaa,0x58,0x63,0xd8,0x1b,0x17,0x35,0x34,0x36,0x62,0xf5,0x3d, |
3509 | | 0x92,0xd3,0xfd,0x96,0x8a,0x37,0x8f,0xd4,0xd3,0x78,0x6a,0xa0,0x71,0x99,0xf6,0x3b, |
3510 | | 0xbe,0xfb,0xdc,0x59,0xe3,0xd8,0xcc,0x29,0x57,0x68,0xbe,0xe8,0xf2,0x3b,0xbe,0x13, |
3511 | | 0x6d,0xe6,0x9c,0x31,0x9a,0x77,0xae,0x83,0x89,0x54,0xec,0x8d,0x17,0xba,0xf3,0xac, |
3512 | | 0x37,0xf7,0x99,0xb9,0xeb,0x3b,0x3d,0x77,0x3e,0x53,0xcf,0xcc,0x3e,0xae,0xe7,0x63, |
3513 | | 0xcd,0x73,0xe1,0xbb,0xf4,0x9c,0xf5,0xa7,0x7a,0x4e,0xf2,0x58,0xdc,0x5f,0xef,0xd9, |
3514 | | 0xfa,0x23,0x7a,0xde,0xd3,0x3c,0x27,0xda,0xa5,0xd8,0xdf,0xeb,0xfd,0xc3,0x47,0x28, |
3515 | | 0xce,0xa3,0xf0,0xb4,0xf5,0x37,0xd3,0x9e,0x40,0x1f,0x37,0xcf,0xb0,0xe1,0xe1,0xaf, |
3516 | | 0xe4,0x7e,0x17,0x65,0x6a,0x05,0xf7,0xbb,0x28,0x77,0xc2,0x0c,0xfc,0x36,0x54,0x32, |
3517 | | 0xf7,0x03,0x7d,0x79,0xdf,0xce,0xfd,0x40,0xba,0xc9,0xef,0x38,0x6f,0xf9,0xdd,0xbf, |
3518 | | 0xf5,0x32,0x1d,0x6d,0x0b,0x8f,0x9a,0x6f,0xa7,0xcf,0x21,0x3e,0xf4,0x31,0xe8,0x00, |
3519 | | 0x1d,0xcd,0xb7,0xcd,0xcb,0xd0,0xd7,0xd1,0x2b,0x60,0x36,0x5c,0x05,0x5d,0xa1,0x0b, |
3520 | | 0xdc,0xef,0x77,0xbf,0x09,0xf4,0x80,0xf9,0x06,0x3c,0xdc,0x00,0x4f,0x99,0xef,0xa5, |
3521 | | 0x9b,0xbf,0x2f,0x02,0xe1,0xdb,0x7d,0xce,0xed,0x4f,0x52,0x36,0xec,0x01,0x63,0x47, |
3522 | | 0x23,0x50,0xf3,0x37,0x65,0x86,0x9b,0xbf,0x5f,0xe2,0x77,0xfb,0xf8,0x68,0xb4,0x00, |
3523 | | 0xfe,0xd7,0xa2,0xd7,0xc1,0x58,0x98,0x05,0x4f,0x98,0x78,0xc9,0xd3,0x93,0xe8,0x64, |
3524 | | 0x13,0x96,0x49,0x62,0x0a,0x3a,0x13,0x1e,0x81,0x7b,0x61,0x25,0xe9,0xaf,0x82,0xd5, |
3525 | | 0x50,0x90,0x38,0xca,0xc2,0x24,0xfc,0xef,0x86,0x7b,0xe0,0x21,0x28,0x84,0xdf,0xf4, |
3526 | | 0xa2,0x3e,0xe7,0x45,0xb8,0x5f,0xfa,0xb8,0x34,0xbe,0x98,0xcf,0xa9,0x02,0x09,0xd2, |
3527 | | 0x8c,0xe2,0x3e,0xa7,0x41,0x71,0x57,0x3b,0xc2,0x78,0x78,0x0d,0x6e,0x80,0x97,0xe0, |
3528 | | 0x16,0x58,0x0d,0x39,0xf2,0x5f,0x6d,0xf1,0x82,0xd4,0xf8,0x2f,0x29,0x41,0xfc,0x25, |
3529 | | 0x5c,0x9d,0x27,0x5d,0x06,0x2f,0x94,0xf4,0x39,0x73,0x61,0x89,0x34,0xb9,0x94,0xcf, |
3530 | | 0x89,0x83,0xb2,0xd9,0xc7,0xb9,0x50,0x5a,0x4e,0xf6,0x72,0x72,0x97,0xb7,0xc2,0x94, |
3531 | | 0xb3,0xc2,0x96,0xb3,0xfc,0x4d,0x98,0x9e,0xfd,0x5c,0xba,0x85,0xa8,0xa1,0xad,0xde, |
3532 | | 0x8b,0x5e,0xa7,0x71,0xbc,0x4e,0xe3,0x73,0xaf,0xc6,0xd4,0xef,0x35,0x67,0x9e,0xee, |
3533 | | 0xfc,0xde,0xf1,0x2d,0x9f,0xd3,0x1d,0x2e,0x09,0xd1,0xfe,0x96,0x7d,0x80,0x65,0x1f, |
3534 | | 0x68,0xd9,0x07,0x59,0xf6,0xc1,0xb0,0x44,0xf6,0x17,0xa5,0x4b,0xac,0xb8,0x5e,0xb4, |
3535 | | 0xec,0x4b,0xac,0x78,0x5f,0xb4,0xec,0x7f,0xb7,0x6f,0x69,0xfc,0x19,0xca,0xf3,0x77, |
3536 | | 0x2a,0xcb,0x6f,0xdd,0x36,0x5e,0x59,0x32,0xac,0xbc,0x87,0xe6,0xf9,0x97,0xe6,0xb7, |
3537 | | 0xc7,0xcf,0xe4,0xf3,0x9f,0x5e,0xe7,0xe9,0x27,0x29,0xcb,0xcf,0x95,0xe1,0x3f,0xe5, |
3538 | | 0xff,0x8f,0xce,0xfb,0xc9,0xda,0xa0,0xf5,0x9f,0x2c,0xcf,0xf9,0xf3,0x69,0x7e,0x79, |
3539 | | 0xf2,0xcb,0x93,0x5f,0x9e,0xbf,0x5b,0x79,0xe2,0x39,0x27,0xa9,0xc5,0xf9,0xc7,0x76, |
3540 | | 0xc7,0xfd,0x1e,0xf2,0x1d,0xfa,0x2e,0xe9,0x5d,0xfa,0x6e,0xf1,0xdd,0xfa,0x4e,0xf1, |
3541 | | 0xbd,0xfa,0x76,0xf0,0x7d,0x70,0x3f,0x3c,0x00,0x0f,0xc2,0x43,0xfa,0xde,0xee,0x0c, |
3542 | | 0x7d,0xcf,0xf7,0x5e,0xfd,0x3d,0xc2,0xc7,0xf4,0x9d,0xdf,0x27,0xe0,0x49,0xf3,0x7d, |
3543 | | 0x47,0x7d,0x7f,0x37,0xb2,0xa2,0xfb,0x8d,0x66,0xfb,0x6f,0x6a,0x99,0x6f,0xa2,0x3f, |
3544 | | 0xaf,0x6f,0x27,0xbf,0xa0,0xef,0x18,0x9b,0xbf,0x73,0xf8,0x92,0xfe,0xc6,0xf6,0x32, |
3545 | | 0x58,0xae,0x6f,0xa1,0xaf,0xb4,0xfe,0xfe,0xe1,0xcb,0xf0,0x8a,0xbe,0x39,0xec,0xfd, |
3546 | | 0xcd,0xad,0x75,0xfa,0x26,0xb0,0xbf,0xa2,0x1b,0xef,0x0b,0x8a,0x6b,0x8d,0xf6,0x5b, |
3547 | | 0x19,0x96,0x5f,0xce,0xfc,0x72,0xe6,0x97,0xf3,0xcf,0x5c,0xce,0x5c,0xf8,0x30,0xec, |
3548 | | 0xf4,0xcf,0xbf,0xff,0xec,0xe1,0xcc,0xdc,0xda,0x71,0x3b,0xe7,0xf9,0xd0,0x09,0xcc, |
3549 | | 0xdf,0xb6,0x3d,0xb7,0x8c,0xe3,0x8c,0x65,0xee,0x2d,0x06,0x9f,0x40,0x3a,0xdc,0x07, |
3550 | | 0x59,0x6c,0x6f,0x00,0x99,0xe6,0xef,0x49,0x11,0xa6,0x21,0xf6,0x87,0xf0,0x1f,0x83, |
3551 | | 0xbb,0x36,0xa4,0x42,0x75,0xfc,0x4a,0xc1,0x8d,0xe6,0xfa,0x12,0x61,0x6a,0x60,0x3f, |
3552 | | 0x1f,0xee,0xc4,0x7d,0x1f,0xee,0x40,0x19,0xf3,0x47,0x0c,0x69,0x4b,0xb8,0xde,0xfc, |
3553 | | 0x1d,0x41,0x78,0x16,0xe6,0x42,0x05,0x48,0x82,0x64,0x48,0xf1,0x1f,0x6f,0x8f,0x71, |
3554 | | 0x84,0x9d,0xf6,0xa4,0xe3,0x4c,0x42,0x6f,0x86,0xdb,0x61,0x32,0xe9,0x4e,0x87,0xc7, |
3555 | | 0x61,0x06,0x61,0x9f,0x41,0xa3,0x48,0xc7,0xfc,0xcd,0xd6,0x78,0x48,0x08,0x77,0xff, |
3556 | | 0x3e,0x6c,0x52,0xb8,0xfb,0x77,0x5b,0xcd,0xdf,0x66,0x35,0x7f,0x8f,0xd5,0xfc,0xcd, |
3557 | | 0x55,0xf3,0x77,0x62,0xeb,0x42,0xbd,0x70,0xf7,0x6f,0xae,0x36,0x84,0x34,0x68,0x04, |
3558 | | 0xe9,0xe1,0xee,0xdf,0x4d,0x6d,0x02,0x41,0x68,0x1a,0xee,0xfe,0xdd,0xd4,0x66,0xe1, |
3559 | | 0xee,0xdf,0x4b,0x35,0x7f,0x83,0xb5,0x15,0xdc,0xf4,0x84,0xfb,0xf7,0x5f,0xcd,0xdf, |
3560 | | 0x9e,0xbd,0x24,0xdc,0xfd,0x5b,0xad,0x73,0xe1,0xcd,0x70,0xe7,0x17,0xe5,0xc1,0x4b, |
3561 | | 0xbf,0xd1,0x7f,0x48,0xb7,0xb9,0xd2,0x9e,0xaa,0xf4,0xda,0xc3,0x95,0x30,0x07,0xda, |
3562 | | 0x90,0x8f,0xf9,0xe1,0xc7,0xef,0x0f,0xd5,0xd0,0xbd,0x9b,0x66,0xba,0x57,0x13,0x63, |
3563 | | 0x3d,0x2b,0xd4,0x38,0xe4,0x59,0xab,0x44,0xdd,0x5f,0x69,0xa4,0xfb,0x34,0xe9,0xd6, |
3564 | | 0x33,0x38,0xde,0x7d,0xa4,0x58,0xdd,0x03,0x4a,0xd1,0xbd,0x19,0x73,0xff,0xa5,0xbf, |
3565 | | 0x9e,0x8f,0x9f,0x09,0x03,0xac,0x74,0x33,0x42,0xee,0xf9,0xfe,0x5c,0x5a,0xa1,0xe9, |
3566 | | 0xa4,0x58,0xcf,0xe6,0xd9,0xf7,0xd3,0xed,0xfd,0xed,0x7d,0xed,0x7d,0x5e,0x3c,0x45, |
3567 | | 0x5e,0x6a,0x85,0xdc,0x83,0xfe,0x25,0x79,0xb1,0xcb,0x3b,0x33,0xe2,0xff,0xd7,0x71, |
3568 | | 0xc6,0x29,0xea,0xf9,0xb7,0xa8,0xe3,0x9f,0x6b,0xcb,0xdf,0x22,0x0d,0xef,0xdb,0xc0, |
3569 | | 0x71,0xba,0x7f,0x14,0x2f,0x4d,0x90,0x26,0x4a,0x93,0xa4,0xc9,0xd2,0x14,0x69,0x2d, |
3570 | | 0x69,0x6d,0x69,0xaa,0xb4,0xaa,0xd6,0xa2,0xde,0x37,0xba,0xd2,0x2d,0x7b,0x63,0xcb, |
3571 | | 0xde,0xc4,0xb2,0x07,0x2d,0x7b,0x53,0xcb,0x9e,0x61,0xd9,0x9b,0x59,0xf6,0x4c,0xcb, |
3572 | | 0xde,0xdc,0xb2,0xb7,0xb0,0xec,0x17,0x59,0xf6,0x96,0x96,0xbd,0x95,0x65,0x6f,0x6d, |
3573 | | 0xd9,0xb3,0x2c,0x7b,0x1b,0xcb,0x7e,0xb1,0x65,0x6f,0x6b,0xd9,0xdb,0x59,0xf6,0xf6, |
3574 | | 0x96,0xbd,0x83,0x65,0xef,0x68,0xd9,0x2f,0xb1,0xec,0x9d,0x2c,0xfb,0xa5,0xb2,0x9b, |
3575 | | 0x7b,0xde,0x26,0x7e,0x73,0xdf,0xbb,0xb1,0xd2,0xf5,0xd6,0xf2,0x1d,0x15,0xee,0xf7, |
3576 | | 0x5a,0xe3,0x37,0x0b,0xf9,0x46,0x40,0x5b,0xa5,0xd7,0x56,0x78,0xef,0xc4,0x7b,0xfb, |
3577 | | 0x36,0x56,0x58,0x4f,0xbd,0xef,0xdd,0x5f,0x2c,0xbb,0xc9,0x93,0xf9,0xfe,0x67,0x0b, |
3578 | | 0xdd,0xf3,0xf2,0xee,0x7b,0x99,0x6f,0xe8,0x76,0xec,0xec,0x38,0xaf,0xb7,0x3d,0xfe, |
3579 | | 0x7d,0x1d,0xf3,0x7d,0xb1,0xf3,0xc8,0xc8,0xae,0x9b,0xdc,0xef,0x2b,0x3e,0x86,0xbb, |
3580 | | 0x3c,0x27,0x18,0x15,0x06,0xb9,0xef,0xae,0xb6,0x24,0xd2,0x5b,0xaf,0x74,0x9c,0xdb, |
3581 | | 0x28,0xcc,0x3c,0xdc,0x65,0xcc,0xbb,0xbc,0xd7,0xba,0xdf,0xbf,0x9d,0x7d,0xab,0xe3, |
3582 | | 0x1c,0xa2,0x20,0xa9,0x14,0xae,0x04,0x27,0x1c,0xd3,0x88,0xbf,0x7d,0x37,0xb7,0x12, |
3583 | | 0xcc,0x37,0xcb,0x9a,0xe7,0xb8,0xdf,0x09,0x33,0xdf,0x0c,0x33,0xdf,0x0a,0x8b,0xec, |
3584 | | 0xe6,0x7e,0x57,0xb6,0x2d,0xe1,0xc6,0x71,0xe2,0x31,0x9a,0x13,0x8f,0x02,0xec,0x3b, |
3585 | | 0xb6,0xbf,0xfb,0x8d,0xb2,0xbc,0xef,0x74,0x11,0xef,0x60,0xd2,0x78,0x9e,0xca,0x6a, |
3586 | | 0x39,0xd5,0x6d,0xa7,0x1a,0x3d,0xdd,0x76,0x32,0x76,0x13,0xaf,0x67,0xbf,0xd5,0xb2, |
3587 | | 0xdf,0xd4,0xf9,0xb8,0xdd,0x7c,0x33,0xc4,0xb3,0x9b,0xb4,0x3c,0xfb,0x7b,0xc3,0x8f, |
3588 | | 0xdb,0x3f,0xbc,0xf8,0xb8,0xbd,0x63,0x77,0xd7,0x7e,0x0f,0xe5,0x3c,0xd8,0xf6,0xf4, |
3589 | | 0x8f,0xe7,0xf5,0x49,0xbf,0xb6,0xf9,0x06,0x1b,0x54,0xf4,0xf9,0x9d,0x2e,0xad,0xdd, |
3590 | | 0xf7,0x4a,0x5f,0x02,0x3f,0x0d,0x36,0x1a,0xa6,0x67,0xb9,0xef,0x99,0xbe,0x09,0x0f, |
3591 | | 0x25,0x99,0xb9,0xc0,0x9f,0xf7,0xce,0x69,0x3b,0xb8,0x0a,0x46,0x98,0x77,0xb8,0x03, |
3592 | | 0x7e,0x67,0x09,0xdb,0x7a,0xb6,0x71,0xeb,0xb9,0x05,0xee,0x7b,0xd0,0xc7,0xcc,0x3b, |
3593 | | 0xde,0xc4,0xfd,0x74,0x1b,0xf7,0x9d,0xcd,0xed,0x53,0xfd,0x79,0xdf,0x70,0x0e,0x23, |
3594 | | 0xef,0xdb,0x09,0x5f,0x17,0x6d,0x7a,0xb1,0x5b,0x5f,0x23,0x4c,0x79,0x92,0xdd,0xf7, |
3595 | | 0x38,0xbd,0xf7,0x59,0xcd,0xfb,0x9c,0x01,0xca,0x13,0xd1,0xd6,0x7d,0xe7,0x3b,0xb3, |
3596 | | 0xad,0xfb,0x8e,0xeb,0xa5,0x30,0x04,0xae,0x85,0xeb,0x2d,0x6a,0x14,0xf4,0x3b,0x03, |
3597 | | 0xa9,0xbb,0xf5,0xd8,0xb7,0x43,0xb7,0x42,0x7e,0x67,0x3f,0x7a,0xd8,0xc4,0x41,0x3b, |
3598 | | 0x3d,0x04,0xb5,0xa1,0x19,0xf4,0x32,0xdf,0x02,0x83,0x7f,0x41,0x51,0xda,0xaa,0x2d, |
3599 | | 0x74,0x83,0x1b,0x84,0x79,0x7f,0x74,0x0e,0x2c,0x84,0xd5,0x70,0x76,0x47,0xf7,0xbd, |
3600 | | 0xda,0x73,0xd0,0x36,0xe8,0xd0,0x0e,0xee,0x3b,0xc1,0x5f,0xd0,0x7f,0xde,0xc0,0xef, |
3601 | | 0x2b,0x38,0x03,0xfb,0x2d,0x68,0x02,0x1a,0x0f,0x4f,0xc3,0xee,0x12,0x7e,0xe7,0x4b, |
3602 | | 0xf4,0xdf,0x10,0xd1,0xc9,0xed,0xab,0x15,0xcd,0x7b,0xa8,0x30,0xeb,0x6c,0xbf,0xb3, |
3603 | | 0x0f,0x3e,0xc7,0x5e,0x9a,0x81,0x54,0x05,0xb6,0x62,0xef,0x81,0x7e,0x41,0x63,0x1d, |
3604 | | 0x83,0x02,0xf4,0x8b,0x06,0x62,0x5d,0x29,0xbf,0xf3,0x32,0xba,0xb5,0xb3,0xfb,0x9e, |
3605 | | 0xf7,0x11,0x38,0xb7,0xb4,0xdf,0xf9,0x11,0x8d,0xb8,0x8c,0x32,0x5c,0xe9,0x7e,0xbb, |
3606 | | 0x7a,0x1c,0x8d,0xdc,0x45,0xef,0xfc,0xae,0x84,0xdb,0x60,0x77,0x19,0xbf,0xd3,0x98, |
3607 | | 0xbe,0xbc,0x07,0xed,0x8f,0xf6,0x81,0x31,0xf0,0x31,0xec,0x84,0x9a,0x74,0x8a,0xef, |
3608 | | 0xd1,0xaa,0x57,0xd0,0x2f,0xcc,0x7b,0xb1,0xd0,0x15,0xbf,0x09,0x2c,0xb4,0xc6,0xa0, |
3609 | | 0xf3,0x70,0x2f,0x84,0xe7,0xaf,0x70,0xbf,0x35,0x70,0xc7,0xa3,0xfe,0xbc,0xef,0x5e, |
3610 | | 0xc7,0x47,0xfb,0xf3,0xf0,0x8d,0x27,0xed,0x2b,0x5d,0xd6,0x12,0xfe,0x85,0x04,0xbf, |
3611 | | 0xf3,0x41,0xb6,0xdf,0xe9,0x8a,0xbb,0x0f,0xec,0xc2,0xef,0x3e,0x74,0x23,0xbc,0x07, |
3612 | | 0x47,0x61,0x5c,0x17,0xfa,0x13,0x1d,0xf1,0xfc,0x54,0xf7,0xdd,0xe4,0xb7,0x2b,0xfb, |
3613 | | 0x9d,0xb5,0x68,0xb3,0x6c,0xe6,0xa3,0x6c,0xf7,0x7d,0x5c,0xa3,0xa3,0xf5,0x4e,0xee, |
3614 | | 0x02,0x78,0x0c,0xe6,0xc2,0x47,0x7a,0x3f,0xd7,0x7c,0x63,0xc1,0x7c,0xfb,0xa6,0x34, |
3615 | | 0x5c,0x0e,0xf3,0xe1,0x6d,0xc8,0x62,0xac,0x16,0xae,0xee,0x77,0xea,0xa3,0xc7,0x70, |
3616 | | 0xf7,0x42,0x27,0xc0,0x6e,0x38,0x8c,0x7f,0xc5,0xab,0x58,0xcf,0x63,0x9f,0x0d,0xb1, |
3617 | | 0x75,0x28,0x2f,0xee,0xeb,0xe0,0x41,0x18,0x01,0x7d,0xeb,0xb8,0xef,0x47,0xf7,0xed, |
3618 | | 0x6e,0x9e,0x71,0xf2,0x3b,0xbb,0xd0,0x6f,0x98,0x57,0x32,0xa1,0x54,0x5d,0xf7,0x9d, |
3619 | | 0xe9,0x02,0xe8,0x6e,0xc2,0xdd,0x41,0x9f,0x9e,0xd6,0xc6,0xbd,0xa8,0xf1,0x00,0xfe, |
3620 | | 0xcf,0x8c,0x65,0xbd,0xd7,0xf8,0xf8,0x3b,0xc2,0x15,0xe0,0x0a,0x68,0x0b,0x2f,0x27, |
3621 | | 0xfa,0x9d,0x4c,0xf6,0xfb,0x16,0xfb,0x44,0xb8,0xb8,0x97,0xfb,0xee,0x75,0x3f,0x16, |
3622 | | 0xb3,0xb7,0xa3,0xe5,0xa0,0x44,0x6f,0x27,0xef,0xfd,0xda,0x74,0xf4,0x51,0xd8,0x07, |
3623 | | 0xb3,0xae,0xc6,0xce,0x42,0x77,0x1b,0x7a,0x6e,0x3d,0xe2,0xec,0xc3,0xf9,0x0e,0x0b, |
3624 | | 0xe9,0x76,0x68,0x2b,0xdc,0x83,0xcd,0x37,0xd6,0xf5,0x1e,0xf2,0x4b,0x70,0x5b,0x1d, |
3625 | | 0xbf,0x53,0x88,0xb6,0xfe,0x16,0x6d,0xd5,0x97,0xf3,0x9b,0x7a,0x7e,0x67,0x05,0xba, |
3626 | | 0x11,0x7a,0xc2,0xd9,0xfd,0xe8,0x53,0xfd,0xdc,0x77,0xbe,0xcd,0x7b,0xcb,0xbd,0x61, |
3627 | | 0x24,0x4c,0x84,0xb2,0xf5,0xfd,0x4e,0x12,0x5a,0x93,0x79,0xad,0x3f,0x24,0xd6,0x77, |
3628 | | 0xdf,0x69,0x5e,0x0b,0x6f,0x35,0xf0,0x3b,0x47,0xd9,0xd6,0x9f,0xf9,0xf2,0x8a,0x86, |
3629 | | 0xe4,0x19,0xd6,0x60,0x4f,0x1d,0xe8,0xbe,0xef,0x5c,0x1a,0xee,0x26,0x7c,0x73,0xf4, |
3630 | | 0x5a,0x18,0x01,0xcf,0x40,0x25,0xe6,0x84,0x20,0x73,0x72,0xb7,0x74,0xbf,0xf3,0x00, |
3631 | | 0x3a,0xa7,0xb1,0xdf,0xa9,0x3a,0xd8,0x7d,0x2f,0x3a,0x0b,0x0a,0x34,0xf5,0x3b,0x63, |
3632 | | 0xd1,0x69,0xc6,0x2f,0xc3,0xef,0x94,0x68,0xe6,0x77,0x46,0x0f,0x61,0x3c,0xc1,0xd3, |
3633 | | 0x0d,0x58,0xbb,0xa3,0x2f,0x34,0x70,0xc9,0x18,0xea,0x38,0x97,0x0d,0x75,0xdf,0xa3, |
3634 | | 0x9e,0x68,0xbe,0xa3,0x00,0xa5,0x1b,0x3a,0xce,0x05,0xcc,0xbd,0x29,0x17,0xf9,0x9d, |
3635 | | 0x06,0xe6,0x7b,0xe6,0xa8,0xf9,0x56,0xc4,0xc3,0xf4,0xdf,0xa2,0xcc,0x9b,0x33,0x5b, |
3636 | | 0xfb,0x9d,0x17,0xa0,0x49,0x96,0xdf,0x39,0x46,0xd8,0x02,0x69,0xee,0xbb,0xd6,0x47, |
3637 | | 0x70,0x7f,0x09,0xa5,0xda,0xf8,0x9d,0x44,0x28,0x3b,0x82,0x36,0x10,0xe6,0x3d,0x6c, |
3638 | | 0xf3,0x7e,0xf3,0x2d,0x68,0x53,0xf4,0xee,0x34,0xf3,0x4d,0x01,0xea,0x73,0xa4,0xfb, |
3639 | | 0x8d,0x0c,0xf3,0x7e,0xf6,0x2e,0xfc,0x2a,0x77,0xf0,0xe7,0xbd,0x0f,0x7f,0x1f,0xfa, |
3640 | | 0x2a,0x98,0x77,0xfa,0xf7,0x43,0xcd,0x46,0xee,0x7b,0xf1,0xcd,0xa1,0x35,0x8c,0xe9, |
3641 | | 0xe4,0x77,0x9e,0xbc,0xd4,0xe5,0x0b,0xdc,0x7e,0x0e,0xce,0x73,0x3a,0x53,0x7f,0xd7, |
3642 | | 0x30,0xe7,0x41,0x15,0xdc,0x63,0x2f,0xf3,0x3b,0x9b,0xc7,0x70,0x9e,0x82,0x7d,0x2f, |
3643 | | 0xba,0x4b,0x0f,0x9b,0xdc,0x78,0xa5,0xdf,0xe9,0x86,0xfa,0xe8,0x57,0x6b,0x51,0xff, |
3644 | | 0x75,0x1c,0xcf,0x21,0x09,0x77,0xd5,0xae,0x7e,0x27,0x03,0x3a,0x61,0x7f,0x1f,0x1d, |
3645 | | 0x7d,0x3d,0x6d,0xcb,0xc9,0xd9,0x34,0xf4,0x5b,0xbd,0x2b,0xfe,0xc1,0x55,0x7e,0x27, |
3646 | | 0xba,0x3b,0x73,0x3c,0xf6,0x59,0xe8,0x40,0xf4,0x4a,0xfa,0xe2,0x3b,0xec,0xb3,0x00, |
3647 | | 0x7b,0xd8,0x38,0xc7,0x29,0xc4,0xc1,0xb7,0x01,0xba,0x88,0xf9,0xe7,0xc9,0x9e,0x7e, |
3648 | | 0x67,0x11,0xdc,0x49,0x98,0x07,0x12,0xdd,0xf1,0x1d,0x0e,0x0f,0x4d,0x61,0x3c,0x13, |
3649 | | 0x6e,0x2a,0xf6,0x5b,0xe0,0x41,0x58,0xc8,0x3c,0x38,0xdf,0x28,0x2c,0x83,0x3d,0x50, |
3650 | | 0xaf,0x8f,0x3f,0xef,0x1b,0x1b,0x65,0x26,0xd0,0xe6,0xf0,0x0c,0x44,0xc3,0x32,0xf8, |
3651 | | 0x74,0x82,0xfb,0x0d,0x80,0xb6,0xe8,0x7a,0x78,0x1d,0x72,0x21,0xa5,0xaf,0xdf,0xe9, |
3652 | | 0xd3,0x8f,0x3c,0xa1,0xd5,0x59,0xac,0x1c,0x26,0xcc,0x11,0x38,0x7b,0x22,0xe1,0x86, |
3653 | | 0xf8,0x9d,0xab,0xd0,0x1a,0x03,0xfc,0xce,0xe5,0x6c,0xcb,0x86,0xf9,0xd8,0x37,0x0f, |
3654 | | 0x64,0x1f,0xec,0x59,0xfa,0x96,0x49,0x4f,0xe8,0x0d,0xb3,0x61,0x32,0x9c,0x39,0x89, |
3655 | | 0xf9,0xed,0x46,0xf7,0x1d,0xf9,0xaa,0xd0,0x07,0x6e,0x84,0xf7,0xd8,0xe7,0x63,0xd4, |
3656 | | 0x37,0x99,0xb9,0x08,0x7b,0x17,0x7d,0x5f,0xbe,0xe7,0x70,0xbf,0xf3,0x1e,0xfa,0x11, |
3657 | | 0x24,0xb3,0x58,0xfa,0x16,0x7d,0x89,0x63,0xd5,0xb3,0x23,0xfd,0x4e,0x8f,0x51,0x7e, |
3658 | | 0x67,0x39,0x7e,0x6b,0x61,0x86,0xde,0xa9,0x37,0xef,0xd3,0x9b,0x6f,0xcf,0xcf,0xe2, |
3659 | | 0xc4,0x76,0x0e,0xba,0x0a,0x4a,0xb3,0x46,0x18,0x01,0x35,0x39,0x69,0x0d,0x2f,0xe0, |
3660 | | 0x77,0x36,0x60,0x5f,0x0a,0x87,0xe0,0x23,0xdc,0x6f,0xdf,0xee,0xbe,0x7f,0xbf,0x99, |
3661 | | 0x13,0xda,0x03,0x70,0x17,0xeb,0x8c,0xc3,0x50,0x8c,0xf5,0x42,0xec,0x24,0xbf,0x53, |
3662 | | 0x1a,0xad,0x7d,0x07,0x79,0x84,0xad,0xe6,0xdd,0x7c,0x38,0x7a,0x27,0xc7,0xc7,0xbb, |
3663 | | 0xc8,0xcf,0x2d,0x7e,0xe7,0x96,0x69,0x8c,0x13,0x16,0x6f,0x8b,0xa7,0x99,0x74,0xfc, |
3664 | | 0xce,0x1e,0xec,0x2f,0xdf,0x4d,0x3b,0x32,0x7f,0x47,0xdf,0x43,0xbf,0xe0,0x38,0x7b, |
3665 | | 0xde,0x1d,0xcc,0xf3,0x2c,0xa4,0x86,0xc3,0x0e,0xfc,0x0a,0xde,0xe5,0x77,0x16,0x60, |
3666 | | 0xbf,0x1b,0x35,0xef,0xf5,0x1b,0x2e,0x84,0xe7,0xa7,0xf9,0x9d,0x9d,0x68,0x22,0x8b, |
3667 | | 0xc0,0x0b,0xa7,0xd3,0xee,0xb0,0x1a,0x7e,0x80,0x37,0xf0,0x8b,0xbb,0xdf,0x9f,0xf7, |
3668 | | 0xfe,0x7f,0xda,0x03,0x1c,0x1f,0xe0,0x0d,0x16,0x8a,0x07,0xa0,0xe7,0x83,0xd8,0x39, |
3669 | | 0x99,0xfe,0x06,0x7b,0x60,0xa6,0xdf,0x39,0xf3,0x11,0xbf,0x33,0x15,0xcc,0x77,0xec, |
3670 | | 0x3b,0xb4,0x74,0xbf,0x5f,0xff,0x03,0x04,0x1e,0x76,0x9c,0x22,0x70,0xb6,0xbe,0x5f, |
3671 | | 0x9f,0xf7,0xa0,0x09,0xd5,0xee,0x0f,0x0b,0x0f,0x44,0x44,0x16,0x88,0x2a,0x58,0xa8, |
3672 | | 0xf0,0x19,0x67,0x12,0x24,0xef,0xb3,0xcd,0x67,0x15,0x2f,0x51,0xf2,0x6c,0xe6,0x4d, |
3673 | | 0xe7,0xf8,0xef,0xdc,0x52,0x1c,0x33,0x9d,0x3f,0xe2,0x57,0xda,0x39,0xbf,0x4c,0xd9, |
3674 | | 0x72,0xbf,0x71,0xa4,0xee,0x5f,0x4b,0xab,0x18,0x7d,0x81,0xeb,0xac,0xc4,0xe4,0x51, |
3675 | | 0xa5,0xea,0x85,0xd5,0xaa,0xd7,0x88,0x89,0xad,0x19,0x17,0x9f,0x90,0xe8,0x24,0x25, |
3676 | | 0xe7,0x2d,0xd3,0x7e,0xdd,0xaf,0x96,0x67,0xa9,0xed,0x3d,0xb6,0xf7,0x9b,0xfd,0xea, |
3677 | | 0x9e,0xcc,0xb3,0x5e,0xfd,0x13,0x9c,0x0d,0x52,0x1b,0x3a,0x69,0x8d,0xd2,0x9d,0xc6, |
3678 | | 0x4d,0x9c,0xfc,0x5f,0xfe,0x2f,0xff,0x97,0xff,0xcb,0xff,0xe5,0xff,0xf2,0x7f,0xf9, |
3679 | | 0xbf,0xfc,0x5f,0xfe,0x2f,0xff,0x97,0xff,0xcb,0xff,0xe5,0xff,0xf2,0x7f,0xff,0xd0, |
3680 | | 0xdf,0x9e,0x93,0xfd,0xf6,0xe6,0xf2,0xdb,0xbb,0xd5,0xfc,0x9f,0xbb,0x7e,0xfd,0xf1, |
3681 | | 0xff,0xf5,0xf3,0x99,0x9f,0xb1,0x78,0xe1,0x0f,0xed,0x71,0x1d,0xb9,0xb9,0x4e,0xde, |
3682 | | 0xff,0x38,0x88,0x62,0xcf,0x67,0xfb,0xf6,0x99,0x7f,0x27,0x44,0x9d,0x5f,0xe3,0x27, |
3683 | | 0x6f,0x82,0xfc,0x6a,0xd0,0x2f,0xaf,0x53,0x99,0xff,0x3e,0x52,0xf7,0x72,0xfb,0x5c, |
3684 | | 0x9e,0xdf,0x47,0xbb,0xf7,0xe4,0x5d,0xa3,0x2c,0x62,0x2e,0x4f,0xe6,0x5d,0x9f,0x3c, |
3685 | | 0xc7,0x5c,0x94,0xdc,0x93,0xeb,0x9c,0x55,0xb0,0xe4,0x6f,0x3b,0x1e,0xca,0x96,0x2b, |
3686 | | 0xff,0x4b,0x77,0x2d,0x6d,0xae,0x51,0x96,0xaf,0x50,0xd1,0x64,0x79,0x8f,0x4a,0x91, |
3687 | | 0x1b,0x1a,0x28,0xfa,0xf7,0x1c,0xd5,0xae,0x25,0x37,0x4f,0x9d,0x93,0xe5,0xe6,0x24, |
3688 | | 0xbf,0x0b,0x7e,0x26,0x66,0xb7,0x25,0x4c,0x8b,0x98,0x7f,0x79,0xd1,0xbb,0x66,0xcf, |
3689 | | 0x5f,0x64,0xaa,0xcb,0x3d,0x9e,0xd1,0xdc,0xff,0x14,0xf4,0xf8,0xd4,0xe8,0xfc,0xe4, |
3690 | | 0xfa,0x25,0xfd,0x38,0x37,0xf7,0x57,0xe5,0x55,0xd3,0xeb,0x2f,0x2c,0x5e,0xae,0x3d, |
3691 | | 0x2d,0x2b,0xf7,0x6a,0x31,0x77,0x2b,0x9d,0x54,0x3d,0x33,0xf7,0x57,0xcf,0x3b,0x91, |
3692 | | 0xa1,0x1e,0x51,0xea,0x20,0xbf,0x53,0x83,0x9e,0x34,0xfd,0x5f,0x56,0xcd,0x7f,0x70, |
3693 | | 0xfa,0x4e,0x7e,0xfa,0xbf,0xe5,0xef,0xcf,0x52,0xfe,0x76,0x9d,0xff,0x09,0xf5,0x1f, |
3694 | | 0x15,0xf5,0xa7,0x6a,0xff,0xdf,0x37,0xf1,0x9e,0x3d,0x4f,0x4c,0xaf,0x0f,0xbf,0xdf, |
3695 | | 0x33,0xfd,0xe1,0xc3,0x4f,0x4c,0x7f,0xf4,0x68,0xf3,0x04,0xdc,0x6f,0xb8,0x0c,0xfb, |
3696 | | 0x4f,0x47,0xaf,0x5c,0xcc,0xd6,0xff,0x32,0xe2,0x71,0xe3,0x9d,0x1b,0xf2,0x2c,0xe3, |
3697 | | 0xf9,0xf1,0x3f,0xc7,0xad,0x28,0xe7,0xd7,0x1e,0x32,0x72,0x7f,0xef,0xce,0x16,0x79, |
3698 | | 0x92,0xde,0xff,0x1b,0x54,0xfa,0xdf,0xef,0xcc,0xe6,0xaf,0x98,0xed,0x9f,0x6b,0xda, |
3699 | | 0xa8,0x3f,0x77,0xee,0x7f,0xab,0xe5,0xcd,0x9f,0xeb,0xb7,0xfb,0x4f,0x96,0x9f,0x8f, |
3700 | | 0xf6,0xfc,0xdd,0x46,0xeb,0x89,0xa7,0x79,0xff,0xcb,0xa3,0xf2,0xf1,0x8b,0x41,0xbf, |
3701 | | 0x38,0x99,0x13,0x2f,0x09,0x38,0xb9,0xb9,0xf6,0xd9,0x76,0xe8,0x2f,0xf7,0x04,0xcb, |
3702 | | 0xbe,0xbc,0xa0,0xff,0x83,0x75,0x57,0xd4,0xe9,0xd6,0xe9,0xaf,0xba,0x06,0xf6,0x6b, |
3703 | | 0x0e,0x38,0x91,0xbf,0x51,0x3c,0xa7,0x5e,0x7a,0xfe,0x99,0x0e,0x39,0x3e,0xaf,0x7b, |
3704 | | 0x98,0xff,0x1d,0x9f,0xfb,0xb3,0x8e,0xaf,0x7b,0xf2,0xc2,0xfd,0x5d,0x0e,0xb1,0xb9, |
3705 | | 0xc7,0xfb,0xf8,0xbe,0x77,0x73,0xd7,0xef,0x39,0x9d,0xdf,0xde,0xdd,0xbb,0x73,0x3f, |
3706 | | 0xd8,0xf3,0x59,0xee,0xdf,0x6f,0x0e,0xdb,0xb3,0xc7,0xe7,0x33,0x25,0xf4,0x19,0xf1, |
3707 | | 0x1a,0x1b,0x7b,0xee,0x1e,0x5d,0xb2,0x76,0xfe,0xd1,0xbf,0x3f,0xdb,0x8a,0x2c,0xea, |
3708 | | 0x77,0x28,0xf0,0x7f,0xfc,0x9d,0x7e,0x4c,0x1f,0xec,0xde,0xfb,0xd1,0x8e,0x1d,0xbf, |
3709 | | 0x5b,0xcd,0x14,0x28,0xf0,0xb7,0xec,0x7f,0x27,0xb6,0xc9,0xcf,0xb7,0xde,0x6f,0xdf, |
3710 | | 0x1f,0xfe,0xfb,0x6e,0xf8,0x67,0x5d,0xf7,0x47,0xfd,0xa2,0xfe,0xff,0x2b,0x2e,0x09, |
3711 | | 0xe4,0xfe,0x29,0xaa,0x29,0xf2,0xaf,0x73,0x2e,0xf6,0xbf,0x18,0x40,0x79,0xb7,0x71, |
3712 | | 0xd4,0x8c,0xe6,0xbe,0xc4,0x9f,0x72,0xda,0xfd,0xeb,0x0d,0x94,0x93,0xfe,0xce,0x73, |
3713 | | 0xfe,0xe9,0xbf,0x3d,0xf6,0x4d,0xd8,0xdc,0xfc,0xfb,0xd4,0x7f,0xab,0x5f,0x6e,0x7e, |
3714 | | 0x11,0xff,0xc0,0x51,0xf5,0x67,0xac,0xac,0xd3,0xce,0xd4,0x1e,0x5f,0xee,0x5f,0xe7, |
3715 | | 0x40,0xf2,0x2b,0x4f,0x73,0x7f,0x93,0xc6,0xca,0x7f,0xca,0xe7,0x7f,0xb3,0x74,0xb7, |
3716 | | 0x5b,0xf9,0x34,0x8e,0x4f,0x79,0x0f,0xae,0xe8,0x61,0x88,0x5f,0xf9,0x8c,0xc6,0x09, |
3717 | | 0xb1,0xba,0x0f,0xc2,0xfc,0x37,0x11,0xee,0xf9,0x1b,0x5c,0x85,0x89,0xfa,0x6f,0x43, |
3718 | | 0xfe,0xf7,0xf3,0x47,0x54,0xe4,0x6f,0xd4,0xa9,0x7e,0xf1,0xa0,0xfc,0xb5,0x17,0x50, |
3719 | | 0x23,0xff,0x37,0x35,0xff,0x3b,0x5e,0x92,0x8d,0x8a,0xfc,0xeb,0x75,0xd1,0xc8,0xdf, |
3720 | | 0xfc,0x50,0x15,0x79,0xfa,0xcf,0x5f,0x1c,0x3f,0xf5,0xfe,0xdf,0x1e,0x06,0xa2,0xa2, |
3721 | | 0xa2,0xfe,0x90,0xb1,0x1f,0x79,0xca,0xb3,0xd5,0xfc,0xce,0xf8,0xb7,0x2e,0x7c,0xd4, |
3722 | | 0x3f,0xa8,0xd8,0x51,0x4e,0xfe,0x2f,0x7f,0xd8,0xfd,0xff,0x95,0xc0,0x9f,0xba,0x22, |
3723 | | 0xa2,0x7e,0x9f,0x38,0xa3,0xfe,0xa1,0xa3,0x2d,0x7f,0x4e,0xf8,0xdf,0x3c,0x0a,0x17, |
3724 | | 0xf5,0x17,0x9b,0x03,0xfe,0x31,0x33,0x5e,0x7e,0x7f,0xff,0x6b,0xff,0x7e,0x7a,0x16, |
3725 | | 0xe6,0xbf,0x3f,0x5f,0xce,0xbf,0x90,0xf5,0x17,0xfe,0x45,0x44,0xfc,0xa5,0x7a,0xeb, |
3726 | | 0x9f,0x25,0x23,0xbf,0xee,0x42,0xe1,0xd6,0xad,0xee,0xa0,0xdb,0xb9,0xd5,0xfc,0x8e, |
3727 | | 0xc7,0xe9,0xfe,0x7e,0x7a,0xa8,0xf1,0xe7,0x47,0xde,0x9f,0xb1,0x8d,0x4e,0xcc,0x96, |
3728 | | 0x55,0x3e,0x53,0xe4,0xad,0x3f,0x5f,0x35,0x7f,0x78,0xee,0x4f,0x7c,0xd9,0x6f,0xcf, |
3729 | | 0x09,0xef,0x4e,0xba,0x9b,0x7e,0xbf,0x8b,0xf7,0xf9,0x13,0xeb,0xff,0xb0,0x7a,0xfe, |
3730 | | 0xe9,0x07,0xae,0xbd,0x7b,0xff,0xf1,0x8f,0x3f,0xe6,0xfe,0x33,0x07,0xcd,0x9e,0x9f, |
3731 | | 0x46,0xc0,0xdf,0x7d,0x96,0xf9,0xe9,0x98,0xfa,0xbb,0x1f,0x43,0xfe,0xa2,0xd7,0xc3, |
3732 | | 0xdc,0xaf,0xbf,0x06,0x02,0x91,0x81,0x02,0x51,0x05,0x03,0x81,0x42,0x81,0x9f,0x7e, |
3733 | | 0x85,0x03,0x81,0x33,0xce,0x0c,0x14,0x29,0x1a,0xb0,0x7f,0xc5,0x02,0x7f,0xc3,0xdf, |
3734 | | 0x59,0xc7,0xad,0xc5,0x4b,0x04,0x4a,0x9e,0x7d,0x0e,0x96,0x73,0x7f,0xa3,0xb8,0x4b, |
3735 | | 0x59,0xf6,0xf3,0x02,0xf9,0xbf,0xfc,0x5f,0xfe,0x2f,0xff,0x97,0xff,0xcb,0xff,0xe5, |
3736 | | 0xff,0xf2,0x7f,0xf9,0xbf,0xfc,0x5f,0xfe,0x2f,0xff,0x97,0xff,0xcb,0xff,0xe5,0xff, |
3737 | | 0xfe,0x80,0x9f,0xcf,0xf9,0xa3,0x4c,0x98,0x13,0x70,0x22,0xf3,0x4c,0x15,0x27,0xc6, |
3738 | | 0xa9,0xe5,0x34,0x76,0xba,0x3b,0x3d,0x9d,0x61,0xce,0x04,0x67,0xa6,0xf3,0xa8,0xf3, |
3739 | | 0x8c,0xb3,0xc4,0x59,0xe1,0xbc,0xe5,0x1c,0x76,0xbe,0xc6,0x04,0x7c,0xc5,0x7d,0x15, |
3740 | | 0x7c,0x19,0xbe,0x16,0xbe,0x8e,0xbe,0xce,0xbe,0x7e,0xbe,0x51,0x27,0x98,0xe9,0xbe, |
3741 | | 0x87,0x7d,0xb3,0x7d,0x8b,0x7c,0xef,0xf9,0xde,0xf7,0x7d,0xea,0xfb,0xb7,0xaf,0xb8, |
3742 | | 0xff,0x1c,0x7f,0x05,0x7f,0x8c,0x3f,0xd1,0x1f,0xf4,0x77,0xf7,0xf7,0xc6,0x8c,0xf2, |
3743 | | 0x4f,0xf2,0xdf,0xe3,0x5f,0xe6,0x5f,0xe5,0x7f,0xd3,0xbf,0xc5,0xff,0xa9,0xff,0xc8, |
3744 | | 0xff,0xd0,0x1c,0xfd,0x2f,0x8c,0x2f,0xcc,0x17,0x16,0x16,0x16,0x08,0x8b,0x0a,0x2b, |
3745 | | 0x94,0x67,0x8a,0xff,0x64,0x4a,0xfe,0x64,0xca,0x84,0x45,0x87,0x55,0xc2,0x54,0x91, |
3746 | | 0xa9,0x69,0x99,0x5a,0x98,0xd4,0xb0,0xba,0x61,0x0d,0xc3,0x1a,0xe5,0x99,0xcc,0x9f, |
3747 | | 0x4c,0x8b,0x9f,0x4c,0xdb,0xb0,0x4e,0x61,0x9d,0x31,0x97,0xcb,0x74,0x3f,0xc1,0xf4, |
3748 | | 0x0b,0x1b,0xf6,0x1f,0xcd,0xa8,0xb0,0x6b,0x7f,0x77,0x33,0x2e,0x6c,0xe2,0x29,0xcd, |
3749 | | 0xa4,0xb0,0x9b,0x7e,0x32,0xb7,0x84,0xdd,0x76,0x82,0x99,0x12,0x36,0x35,0xec,0xce, |
3750 | | 0xb0,0x69,0xa7,0x69,0xee,0xf9,0xd5,0x66,0x66,0xd8,0x9c,0xff,0x60,0x16,0x85,0xad, |
3751 | | 0x38,0xc1,0xac,0xfa,0x5d,0xcc,0xcb,0x61,0xaf,0xfe,0x41,0x66,0x6d,0xd8,0x6b,0x61, |
3752 | | 0x1b,0xc2,0x36,0xfe,0x64,0xde,0x0c,0x7b,0xeb,0x6f,0x61,0xb6,0xe4,0x9b,0x7f,0xb4, |
3753 | | 0xf9,0x58,0xe6,0x33,0xcc,0x11,0x8c,0x2f,0xfc,0xb8,0x89,0xc2,0x14,0x92,0x39,0x47, |
3754 | | 0xa6,0x42,0x9e,0x89,0xc6,0x54,0xca,0x33,0xc9,0x32,0xf5,0x31,0x99,0x98,0x4e,0x96, |
3755 | | 0xc9,0xc6,0x74,0x97,0x19,0x26,0x33,0x2e,0x7c,0x52,0xf8,0x6d,0x79,0x66,0x8a,0xcc, |
3756 | | 0x9d,0xbf,0x9b,0x99,0x76,0x12,0x33,0x3d,0xcf,0xdc,0x8f,0x99,0x19,0xfe,0x78,0xf8, |
3757 | | 0x93,0xe1,0x73,0x31,0xf3,0x65,0x16,0xfe,0x64,0x5e,0x92,0x59,0x26,0xb3,0x02,0xb3, |
3758 | | 0x2a,0xcf,0xbc,0x9a,0x67,0xd6,0x62,0x36,0x86,0xbf,0x15,0xbe,0x25,0x7c,0x1b,0xe6, |
3759 | | 0x43,0x99,0xed,0x3f,0x99,0x4f,0x65,0x3e,0x93,0xd9,0x8f,0x39,0xf0,0xff,0xcc,0xc1, |
3760 | | 0x5f,0x61,0x0e,0x87,0x1f,0xf9,0x5b,0x98,0xaf,0xc3,0xff,0xfd,0x1f,0xcd,0xd1,0xf0, |
3761 | | 0xef,0x7e,0x91,0xc9,0x7f,0xba,0xe2,0x9f,0xfe,0xfb,0x2e,0xfc,0xb7,0x35,0xbe,0xc0, |
3762 | | 0xaf,0x35,0x2c,0x89,0xff,0x61,0xe7,0x63,0x91,0x3f,0x6b,0xa2,0xf2,0x4c,0xa1,0xbf, |
3763 | | 0x88,0x39,0x23,0xc4,0x14,0xc9,0x33,0xc5,0xf2,0xcd,0x69,0x99,0x92,0xff,0x78,0x53, |
3764 | | 0xfa,0x4f,0x69,0xca,0xfc,0x4e,0xa6,0x42,0x20,0xfa,0x1f,0x6e,0x2a,0xfd,0xe3,0x4c, |
3765 | | 0x95,0x13,0x4c,0x8c,0x4c,0xcd,0x7f,0xac,0x49,0x0c,0x24,0xe7,0x9b,0x9f,0x35,0x75, |
3766 | | 0xf3,0x4c,0xfd,0x3f,0xa1,0x69,0x98,0x6f,0xfe,0xe2,0xa6,0x11,0xa6,0x31,0x26,0x88, |
3767 | | 0xc9,0xc0,0x64,0xca,0xb4,0xf8,0xcd,0x4d,0x4b,0x4c,0x6b,0x4c,0x9b,0x40,0xdb,0x3c, |
3768 | | 0xd3,0x3e,0xdf,0xfc,0x43,0x4c,0xc7,0x40,0xa7,0xdf,0xc4,0x74,0x0e,0x5c,0x7e,0x82, |
3769 | | 0xb9,0x32,0x90,0xfd,0x87,0x99,0xee,0x81,0xde,0xbf,0xc8,0xf4,0x09,0xf4,0x3b,0x2d, |
3770 | | 0x33,0x20,0x30,0xe8,0x77,0x32,0xa3,0x02,0xe3,0x02,0x13,0x02,0x13,0x03,0x93,0x02, |
3771 | | 0x37,0x05,0x6e,0x09,0xdc,0x16,0x98,0x16,0x78,0x30,0xf0,0x70,0x60,0x66,0xe0,0xd1, |
3772 | | 0xc0,0xe3,0x81,0x27,0x03,0xb3,0x03,0xcf,0x04,0xe6,0x9f,0x60,0x16,0x05,0x96,0x9c, |
3773 | | 0x60,0x56,0x05,0x5e,0x0b,0x6c,0x08,0x6c,0x0c,0xbc,0x19,0x78,0x2b,0xb0,0x25,0xf0, |
3774 | | 0x4e,0xe0,0xc3,0xc0,0x27,0x81,0x4f,0x03,0x9f,0x05,0xf6,0x07,0x0e,0x04,0x0e,0x06, |
3775 | | 0x0e,0x07,0xfe,0x1d,0xf8,0xfe,0x04,0x13,0x16,0x11,0x75,0x82,0x39,0x23,0xa2,0xd8, |
3776 | | 0x09,0xa6,0x64,0x44,0xa9,0x13,0x4c,0xb9,0x88,0x4a,0x21,0xa6,0xfa,0x09,0x26,0x31, |
3777 | | 0xa2,0x6e,0x44,0xfd,0x88,0x86,0x11,0x8d,0x22,0x1a,0x47,0x04,0x23,0x32,0x22,0x5a, |
3778 | | 0x47,0x74,0x8c,0xe8,0x14,0xd1,0x39,0xe2,0xf2,0x88,0x2b,0x23,0xb2,0x23,0xba,0x45, |
3779 | | 0x74,0x97,0xe9,0x19,0x62,0x7a,0xff,0x01,0xa6,0xcf,0xff,0x33,0x83,0x4e,0x30,0x43, |
3780 | | 0xfe,0xc7,0x66,0x58,0x88,0xb9,0x26,0xdf,0x9c,0x86,0xb9,0x16,0x73,0x3d,0x66,0xdc, |
3781 | | 0x1f,0x64,0x26,0x60,0x26,0x62,0x26,0xfd,0x8f,0xcd,0x4d,0x3f,0x99,0x5b,0xf2,0xcc, |
3782 | | 0x6d,0xbf,0xd0,0x4c,0xc1,0x4c,0xfd,0x45,0xe6,0xce,0x13,0xcc,0x34,0xcc,0x3d,0x79, |
3783 | | 0x66,0xfa,0x4f,0xe6,0xfe,0xd3,0x34,0x0f,0xe6,0x99,0x87,0x23,0x66,0x9e,0xd2,0x3c, |
3784 | | 0x1a,0xf1,0x78,0x9e,0x79,0x32,0x62,0x76,0x9e,0x99,0x13,0xf1,0x4c,0xc4,0xdc,0x88, |
3785 | | 0xf9,0x3f,0x99,0x85,0x11,0x8b,0xf2,0xcc,0xe2,0x88,0x25,0x27,0x31,0x2f,0x45,0x2c, |
3786 | | 0xfb,0x19,0xb3,0xc2,0x32,0xab,0x22,0x5e,0xc6,0xbc,0x7a,0x82,0x59,0x1b,0xf1,0x5a, |
3787 | | 0xc4,0x86,0x88,0x8d,0xf9,0xe6,0x67,0xcd,0x9b,0x3f,0x99,0xb7,0x30,0x5b,0x30,0xef, |
3788 | | 0x60,0xde,0xc3,0xbc,0x8f,0xd9,0x86,0xf9,0x10,0xb3,0x1d,0xf3,0x31,0x66,0x17,0xe6, |
3789 | | 0x13,0xcc,0xa7,0x79,0xe6,0x33,0xcc,0x7e,0xcc,0x81,0x13,0xcc,0xe1,0x3c,0xf3,0x75, |
3790 | | 0x9e,0x39,0x9a,0x67,0xbe,0xcf,0x33,0xbe,0xc8,0x5f,0x6f,0xc2,0xfe,0x9f,0x39,0x7e, |
3791 | | 0x21,0xd7,0xfc,0xa2,0x30,0x85,0x30,0x67,0x60,0x8a,0x60,0x8a,0x61,0x8a,0x63,0x4a, |
3792 | | 0x62,0xce,0xc1,0x94,0xc2,0x94,0xc6,0x94,0xc9,0x33,0xe5,0x30,0x15,0x30,0xd1,0x27, |
3793 | | 0x98,0x2a,0x79,0xa6,0x7a,0x9e,0xa9,0x99,0x67,0x12,0xf3,0x4c,0xad,0xd3,0x34,0xa9, |
3794 | | 0x91,0x75,0x23,0xeb,0x47,0x36,0x3c,0xa9,0x69,0x94,0x6f,0xfe,0x32,0xa6,0x71,0x88, |
3795 | | 0x09,0xe6,0x9b,0x3f,0xd4,0x64,0x60,0x32,0x4f,0x62,0x5a,0xe4,0x9b,0x53,0x98,0x96, |
3796 | | 0x91,0xad,0xf3,0x4d,0xbe,0x39,0x4d,0xd3,0xf6,0x0f,0x31,0xed,0x31,0x1d,0x4f,0x30, |
3797 | | 0x9d,0x7e,0x32,0x9d,0x7f,0x07,0x93,0x9d,0x6f,0xfe,0x51,0xa6,0x67,0xbe,0xf9,0x47, |
3798 | | 0x9b,0xde,0x91,0x7d,0xfe,0xb1,0xa6,0x5f,0xbe,0xf9,0xdb,0x99,0x61,0x79,0x66,0x54, |
3799 | | 0xe4,0x35,0x27,0x98,0x6b,0xf3,0x4d,0xbe,0xf9,0xdd,0xcd,0xf5,0x32,0xe3,0x30,0x13, |
3800 | | 0xf2,0xcd,0x2f,0x30,0xee,0xf3,0xa2,0xb5,0xc3,0x1c,0xa7,0x7f,0x45,0x57,0xbb,0x48, |
3801 | | 0x07,0xa0,0x0e,0xba,0xd2,0x7c,0x5a,0x07,0x5d,0x85,0xfa,0xd1,0xd5,0xc6,0x1b,0x7d, |
3802 | | 0x19,0x0d,0x0f,0x73,0x3f,0x6d,0x18,0x81,0xfa,0xd1,0x48,0xb4,0xb2,0xdf,0x71,0x0a, |
3803 | | 0xa0,0xaf,0x98,0x8f,0xac,0xa2,0x8f,0x94,0x75,0x9c,0x82,0xe8,0xab,0xb8,0x0b,0xa3, |
3804 | | 0x1b,0x09,0x57,0xc4,0xec,0x47,0xb8,0x62,0x66,0x3f,0x34,0x1a,0x9d,0x41,0xb8,0x4a, |
3805 | | 0xc6,0x1f,0xad,0x8a,0x86,0x2b,0x3e,0x7f,0x59,0x77,0x7b,0x38,0x1a,0x8f,0x46,0x94, |
3806 | | 0x75,0xf3,0x13,0xe1,0x73,0xf3,0x53,0x40,0xe1,0x0a,0xfa,0xdc,0xf8,0x0b,0xa3,0x55, |
3807 | | 0xd0,0xb5,0x8e,0xfc,0xcb,0xba,0xfe,0x67,0xfa,0xdc,0x78,0x0a,0x97,0x75,0xb7,0x17, |
3808 | | 0x45,0x63,0xd0,0xb3,0x14,0xef,0x99,0x65,0xdd,0xf2,0xae,0x53,0x79,0x5f,0x53,0x79, |
3809 | | 0xd7,0xab,0xbc,0x4b,0xcb,0xba,0xe5,0x3d,0x4b,0xe5,0x2d,0xa1,0x74,0xcf,0xf6,0xb9, |
3810 | | 0xe5,0xdd,0xa0,0xf2,0xbe,0xa8,0xf4,0xce,0x53,0x39,0xc3,0x55,0xce,0x08,0x95,0xf3, |
3811 | | 0x05,0xa5,0x5f,0xd5,0xef,0x96,0xf3,0x5c,0x9f,0x9b,0x8f,0x73,0xf1,0x8f,0x33,0xfb, |
3812 | | 0x95,0x75,0xe3,0x2d,0xab,0x72,0x7e,0xa5,0x72,0x9e,0xef,0x73,0xd3,0x2f,0x5f,0xd6, |
3813 | | 0x4d,0xbf,0xac,0xd2,0x2f,0xaf,0x72,0xef,0x51,0xb9,0x2b,0x2a,0xfc,0x05,0xda,0x5e, |
3814 | | 0xb1,0xac,0x9b,0xbf,0xca,0xca,0x57,0x59,0xe5,0xe3,0x02,0x2f,0x1f,0x68,0x2c,0x5a, |
3815 | | 0x4d,0xe5,0x7f,0x5d,0xe5,0xdf,0xa8,0xf2,0xbf,0xa1,0xf2,0x57,0x55,0xfa,0xd5,0x54, |
3816 | | 0xfe,0x1a,0x8a,0x3f,0x4e,0xe5,0x7f,0x53,0xe5,0x5f,0xa7,0x74,0xde,0x54,0xf9,0x0b, |
3817 | | 0xa8,0xfc,0x05,0x95,0xee,0x7a,0xb5,0x6f,0xac,0xcf,0x2d,0x6f,0x8d,0xb2,0x6e,0x3a, |
3818 | | 0x49,0x3e,0x37,0xdd,0x38,0xed,0xbf,0x57,0xed,0x95,0xa0,0x7c,0xa6,0xf8,0xdc,0x76, |
3819 | | 0x4a,0x52,0xbd,0xa4,0xaa,0xdc,0xf5,0x15,0x2e,0x45,0xe1,0xea,0xaa,0x3e,0xeb,0xa9, |
3820 | | 0x5d,0xeb,0x28,0x7c,0x03,0xd5,0x6b,0x9a,0xfa,0x53,0xba,0xca,0xfb,0x8d,0xd2,0x6d, |
3821 | | 0xec,0x73,0xcb,0xf9,0x96,0xfa,0x4d,0x13,0xe5,0x23,0x43,0xf1,0x37,0x55,0xfc,0x41, |
3822 | | 0xc5,0xdf,0x5c,0xf1,0x37,0x53,0x3c,0x9b,0x55,0x6f,0x5b,0x54,0x6f,0x6f,0xab,0xde, |
3823 | | 0xde,0xd1,0x38,0xb9,0x48,0xf5,0xd6,0x4a,0xf5,0x16,0xab,0x71,0xf2,0xae,0xea,0xed, |
3824 | | 0x0d,0xe2,0x29,0x84,0x66,0xa9,0x5c,0x6f,0xa9,0xfe,0x0a,0xab,0xfe,0xce,0x44,0x4b, |
3825 | | 0x9b,0x71,0xa2,0xfc,0xbc,0xae,0x7a,0xdc,0xa7,0xfc,0xb7,0x53,0xf9,0x3a,0xa8,0xbc, |
3826 | | 0xed,0x94,0xce,0x25,0x2a,0xc7,0x25,0x8a,0xaf,0xa8,0xe2,0x3b,0x4b,0xed,0x71,0xa9, |
3827 | | 0xca,0xd5,0x41,0xf5,0x7b,0x85,0xf6,0xbf,0x54,0xfd,0xe8,0x32,0xc5,0xd3,0x45,0xf1, |
3828 | | 0x74,0x51,0xfa,0x5d,0x71,0x57,0x36,0xfd,0xd6,0xef,0xee,0x7f,0x85,0xc2,0x5d,0xad, |
3829 | | 0x70,0x57,0x29,0x5c,0x5f,0x85,0x3b,0x4f,0xe1,0xba,0xaa,0xfe,0x06,0xaa,0xfe,0xfa, |
3830 | | 0xab,0xfe,0xde,0x57,0xfd,0x7d,0xa0,0xfa,0xdb,0xa6,0xfa,0xeb,0xa5,0x7e,0x77,0xb5, |
3831 | | 0xea,0xaf,0xaf,0xfa,0x5b,0xae,0xea,0x6d,0x8f,0xe6,0x97,0xfe,0x3e,0xb7,0xfe,0x06, |
3832 | | 0xaa,0xfe,0xb6,0xa8,0xbc,0x25,0x54,0xde,0xb3,0x55,0x7f,0x73,0x95,0xaf,0xdd,0xec, |
3833 | | 0x77,0x01,0x3a,0x58,0xf5,0x38,0x58,0xf9,0x1a,0xae,0x71,0x38,0xb4,0xac,0x9b,0xfe, |
3834 | | 0x18,0xf5,0x97,0xeb,0x94,0xcf,0xb1,0xaa,0x9f,0xf1,0xea,0xb7,0x43,0x55,0xee,0x1b, |
3835 | | 0x35,0xce,0x6e,0x50,0xf8,0xc9,0x6a,0x8f,0x9b,0xe5,0x7f,0xab,0xf6,0xff,0x52,0xfb, |
3836 | | 0x7f,0xa8,0x72,0x0e,0x57,0xbf,0xfb,0x46,0xf3,0x4b,0x82,0xdf,0xdd,0xef,0x76,0xed, |
3837 | | 0x37,0xd2,0xe7,0x96,0xf3,0x5f,0x8a,0xf7,0x2b,0xed,0x3f,0x4a,0xed,0x93,0xa3,0x74, |
3838 | | 0xae,0x51,0xb9,0xaf,0x55,0xf9,0xee,0x50,0xfd,0xde,0xa5,0x74,0x77,0xa8,0x7e,0x3f, |
3839 | | 0x56,0xba,0x3b,0x55,0xbf,0xbb,0xd4,0x3f,0x7d,0xaa,0xdf,0x30,0x95,0xa7,0x8a,0xfa, |
3840 | | 0xe7,0x6e,0xd5,0xf3,0xa3,0xaa,0xe7,0x4f,0x34,0x8f,0xbf,0xa1,0xfa,0xf5,0xa9,0x7e, |
3841 | | 0xc3,0xd4,0x9f,0x66,0x6a,0x1e,0xf7,0xa9,0x5e,0x03,0x8a,0x2f,0x4c,0xf9,0x0f,0x28, |
3842 | | 0x5f,0x91,0x2a,0x47,0xa4,0xca,0x11,0xa5,0x70,0x85,0x54,0x8e,0x33,0x34,0x9f,0x7d, |
3843 | | 0xaa,0xf1,0x58,0x48,0xfd,0xaa,0x88,0xca,0x77,0x86,0xfa,0x6d,0x31,0xcd,0xe3,0xc5, |
3844 | | 0x15,0x6f,0x11,0x95,0x77,0xaf,0xca,0xfb,0x99,0xca,0xbb,0x4f,0xe5,0x5d,0xa6,0x7a, |
3845 | | 0x2e,0xae,0xf2,0x96,0x54,0xba,0xe7,0xa8,0x5f,0xed,0x57,0x79,0x5f,0x52,0x7a,0xa5, |
3846 | | 0x55,0xce,0x80,0xca,0x19,0xa9,0x72,0x2e,0x51,0xfa,0x17,0x6a,0x1e,0x2f,0xa5,0xfe, |
3847 | | 0x53,0x4a,0xfd,0xa7,0xb4,0xda,0xa5,0x9c,0xca,0xf9,0xb5,0xca,0x59,0x46,0xfd,0xb9, |
3848 | | 0x82,0xe6,0xf1,0x72,0x4a,0xbf,0x82,0xca,0xfd,0xa9,0xca,0x1d,0xad,0xf0,0x95,0xb4, |
3849 | | 0x3d,0x5a,0xfd,0xa1,0x8a,0xf2,0x55,0x4e,0xf9,0xa8,0xe4,0xe5,0x43,0xf3,0x78,0x75, |
3850 | | 0xd5,0xc3,0xdd,0xaa,0x87,0xcf,0x55,0x0f,0x07,0x54,0x0f,0x5f,0xa8,0x1e,0x2e,0x54, |
3851 | | 0x3e,0xaa,0xab,0x1e,0x62,0x54,0xfe,0x83,0x2a,0xff,0x6b,0x4a,0x67,0x93,0xca,0x1f, |
3852 | | 0xa5,0xf2,0x17,0x52,0xba,0x1b,0xd4,0xbe,0x35,0x35,0x8f,0xc7,0x68,0x3c,0x24,0xab, |
3853 | | 0x1c,0x87,0x34,0x2f,0xc5,0x2b,0x9e,0xcf,0xd4,0x6e,0x89,0xca,0x6f,0x2d,0xcd,0x37, |
3854 | | 0xc9,0xaa,0x9f,0x3a,0xda,0xaf,0x81,0xc2,0xd5,0x52,0xb8,0x7a,0xaa,0xd7,0xfa,0x2a, |
3855 | | 0x57,0x5d,0x85,0x6f,0xa8,0xfa,0x6d,0xa4,0x7e,0xd5,0x58,0xe5,0x3d,0xaa,0x74,0x9b, |
3856 | | 0x68,0x5c,0x1d,0x56,0xff,0x09,0x2a,0x1f,0xcd,0x14,0x7f,0x86,0xe2,0x6f,0xaa,0xf8, |
3857 | | 0x5b,0x28,0xfe,0x4c,0x6f,0x9c,0xaa,0xde,0x8e,0xa8,0xde,0xbe,0x52,0xbd,0x7d,0xad, |
3858 | | 0xf1,0xd2,0x52,0xf5,0xd6,0x5a,0xed,0x53,0x53,0xe3,0xe5,0x5f,0xaa,0xbf,0x37,0x35, |
3859 | | 0x9f,0xb7,0x51,0xb9,0x36,0xab,0x1e,0xcf,0x50,0x3d,0x16,0xd1,0x7c,0x34,0x53,0xf9, |
3860 | | 0xd9,0xa8,0xfa,0xdc,0xaf,0xfc,0xb7,0x57,0xf9,0x3a,0xaa,0xbc,0xed,0x95,0x4e,0x27, |
3861 | | 0x95,0xa3,0x93,0xe2,0x2b,0xa6,0xf8,0x8a,0xab,0x5d,0x3a,0xab,0x5c,0x1d,0x55,0xbf, |
3862 | | 0x57,0x6a,0xff,0xce,0xea,0x4f,0x97,0x2b,0x9e,0x6c,0xc5,0x93,0xad,0xf4,0xbb,0x69, |
3863 | | 0x9e,0x2e,0xa5,0x79,0xfa,0x4a,0x85,0xeb,0xa3,0x7e,0x77,0x8f,0xc2,0x77,0x57,0xf8, |
3864 | | 0x7e,0x0a,0x5f,0x5a,0xe1,0xbb,0xa9,0x1e,0x07,0xa9,0x1e,0x07,0x78,0xed,0xa1,0x7a, |
3865 | | 0xfc,0x56,0xf5,0xf8,0x9d,0xea,0xb1,0xb7,0xfa,0x5f,0x1f,0xd5,0x63,0x3f,0xf5,0xbf, |
3866 | | 0x63,0xaa,0xbf,0x4f,0x35,0xdf,0x0c,0xd0,0xbc,0x3e,0x48,0xf5,0xf8,0xb6,0xca,0x5d, |
3867 | | 0x52,0xe5,0x3e,0x47,0xf5,0x38,0x4f,0xf9,0xfa,0x44,0xf3,0xfa,0x10,0xd5,0xe7,0x10, |
3868 | | 0xe5,0x6b,0x84,0xc6,0xe5,0x30,0xcd,0xeb,0xd7,0xaa,0xdf,0x5c,0xaf,0x7c,0x8e,0x53, |
3869 | | 0x3d,0x4d,0x50,0x3f,0x1e,0xa6,0xf2,0x4f,0x52,0xf9,0x27,0x2a,0x3f,0xf7,0x6a,0xbf, |
3870 | | 0x9b,0xd4,0x3e,0xb7,0x68,0xfb,0x6d,0x8a,0xe7,0x88,0xe2,0xf9,0x5e,0xe5,0x1d,0xa1, |
3871 | | 0x7e,0x78,0x54,0xf3,0x4e,0xa2,0xe6,0xf7,0x29,0xda,0xef,0x47,0x95,0xf7,0xdf,0x8a, |
3872 | | 0x7f,0xba,0xe2,0xff,0x5a,0xf1,0x8c,0x56,0xbb,0x4d,0x55,0x7a,0x63,0x54,0x0f,0xd7, |
3873 | | 0xa9,0xbc,0x77,0xaa,0xbe,0xa7,0x29,0xfd,0x03,0xe5,0xdc,0xfd,0x26,0x9a,0x35,0x8e, |
3874 | | 0x59,0xb7,0x97,0x73,0xfd,0x9f,0x50,0x7c,0x8f,0xa9,0xfc,0x4f,0x95,0x75,0xd3,0x9d, |
3875 | | 0xa5,0x7c,0x7d,0xa4,0x7e,0xf7,0xad,0xf4,0x98,0xda,0x67,0xa7,0xdc,0x05,0x14,0xff, |
3876 | | 0x4a,0xc5,0xb3,0x5c,0xf1,0xbc,0xa2,0x78,0x56,0xcb,0x3f,0xd6,0x5b,0x0f,0xc9,0xbd, |
3877 | | 0x49,0xe1,0xde,0x55,0xb8,0xb7,0xe5,0x7f,0x91,0xd2,0xad,0xa1,0x71,0xd3,0x4a,0xee, |
3878 | | 0x6a,0x7e,0x77,0xfb,0x0f,0x3e,0x37,0x9e,0x6d,0x4a,0xff,0x3d,0xe5,0xe7,0x1d,0x95, |
3879 | | 0xff,0x7d,0x6d,0x7f,0x52,0xf1,0x3d,0xae,0x74,0xe6,0x28,0x9d,0xd9,0x8a,0x6f,0xbb, |
3880 | | 0xf6,0xff,0x4e,0xfa,0xbd,0xe2,0xd9,0x25,0x77,0x94,0xf2,0xbb,0x4a,0xf1,0xac,0x50, |
3881 | | 0x3c,0xaf,0x2a,0x9e,0x97,0xe5,0x5f,0x53,0xe1,0xb6,0xc8,0xfd,0x96,0xc2,0xbd,0xa7, |
3882 | | 0x70,0xef,0xc8,0xbf,0xa5,0xd2,0x8d,0x51,0xb9,0x5a,0xcb,0x5d,0x5d,0xe5,0xfa,0x51, |
3883 | | 0xf9,0xce,0x55,0xfa,0x5b,0x95,0x9f,0x77,0x55,0xae,0x0f,0xb4,0x7d,0x9e,0xe2,0x7b, |
3884 | | 0x56,0xe9,0x3c,0xa7,0x74,0x16,0x28,0x1f,0xf3,0xb5,0x7d,0xae,0xb6,0x2f,0xd2,0xf6, |
3885 | | 0x85,0xda,0x5e,0x42,0xdb,0xcf,0x96,0xbb,0xa4,0xdc,0xe7,0xc8,0x9d,0x25,0xf7,0xc5, |
3886 | | 0x72,0xb7,0x91,0xbb,0xad,0xfa,0xd9,0x55,0xd2,0xee,0xd2,0x1e,0xd2,0x9e,0x0a,0x37, |
3887 | | 0xd2,0x5b,0x87,0xa8,0x1f,0x8f,0x96,0x5e,0xa3,0x70,0xf7,0x2b,0xde,0x5c,0x85,0xfb, |
3888 | | 0x40,0xf9,0xdc,0xa1,0x7c,0x7e,0xa4,0x7e,0xbe,0x53,0xe1,0x3e,0x54,0xb8,0x6d,0x0a, |
3889 | | 0xf7,0xb1,0xc2,0x6d,0x57,0xb8,0x5d,0x0a,0xb7,0x4f,0xe1,0xf6,0x2a,0xdc,0x17,0x0a, |
3890 | | 0xf7,0xb9,0xc2,0x1d,0x52,0xb8,0xfd,0x0a,0xf7,0x99,0xc2,0x1d,0x54,0xb8,0x03,0x0a, |
3891 | | 0x77,0x58,0xf3,0xd9,0x17,0xaa,0xff,0xcf,0xa5,0x07,0xa4,0x3b,0xa4,0x1f,0x6b,0x7e, |
3892 | | 0x3a,0x5f,0xc7,0xeb,0x32,0x6a,0xcf,0x38,0xbf,0xab,0xf1,0x7e,0x37,0x9e,0x83,0x6a, |
3893 | | 0xb7,0x17,0x35,0xfe,0x6e,0x0c,0x73,0xb7,0x2f,0x29,0xe7,0xee,0xf7,0x02,0x5a,0xdc, |
3894 | | 0x8c,0x23,0xb4,0x84,0xe9,0x77,0x68,0xd0,0x9c,0x57,0x6a,0x7c,0xae,0xd3,0x7e,0x93, |
3895 | | 0xc3,0xdc,0x70,0xe7,0x2a,0x5c,0x29,0x6d,0x5f,0xaf,0xed,0x37,0x69,0x7b,0x55,0x6d, |
3896 | | 0xbf,0x50,0xf1,0xbc,0xae,0x70,0x1f,0x28,0xdc,0xcd,0x4a,0xff,0x7d,0xa5,0xbf,0xb5, |
3897 | | 0x9c,0xdb,0x3e,0x4f,0x69,0xff,0xda,0xda,0x3f,0x55,0xfb,0x7d,0xa3,0xfd,0x6e,0xd5, |
3898 | | 0xf6,0x66,0xda,0x9e,0x29,0xfd,0x5c,0xe1,0xf6,0x29,0xdc,0xed,0x8a,0xff,0x33,0xc5, |
3899 | | 0xbf,0x57,0xf1,0xcf,0x09,0x73,0xc3,0x77,0x52,0xf8,0x6f,0x15,0x7e,0x8a,0xe2,0xed, |
3900 | | 0xa5,0xf8,0x7a,0x2b,0xdf,0xc7,0xa4,0xcf,0x49,0x5f,0xd1,0x7e,0x03,0xb5,0xdf,0xd3, |
3901 | | 0x4a,0x67,0xbe,0xd2,0x99,0xa7,0x7a,0x74,0x14,0x8f,0xaf,0x9c,0x3b,0xcf,0x3d,0xaf, |
3902 | | 0xfd,0x17,0x6a,0xff,0xc1,0xda,0xff,0x19,0xa5,0x5b,0x54,0xe1,0x8b,0x69,0xfb,0x50, |
3903 | | 0x6d,0x7f,0x56,0xdb,0xcb,0x6b,0x7b,0x05,0xc5,0xb7,0x46,0xf1,0xbd,0xac,0xf0,0xc3, |
3904 | | 0x15,0x7e,0xae,0xf2,0xf3,0x96,0xf2,0xb3,0x49,0xe5,0x5e,0xaf,0x78,0xe2,0x14,0x4f, |
3905 | | 0xbc,0xe2,0x79,0x57,0xfb,0x8f,0xd4,0xfe,0xaf,0x2b,0x5c,0x9a,0xc2,0x35,0x52,0x79, |
3906 | | 0x76,0xcb,0xfd,0x89,0xc2,0x8f,0x56,0xf8,0x8d,0x4a,0xef,0x63,0xa5,0xb7,0x43,0xe9, |
3907 | | 0x6d,0x50,0x3c,0x59,0xda,0xaf,0x8d,0xd2,0xdb,0xa3,0xfd,0xc7,0x68,0xff,0x37,0x14, |
3908 | | 0xae,0x8b,0xc2,0x65,0x2b,0xdc,0xbf,0x54,0xbe,0x23,0x0a,0xbf,0x59,0xe1,0x73,0x74, |
3909 | | 0xdc,0x78,0x4f,0xfe,0x3b,0xe5,0x3f,0x4f,0xfe,0x9f,0x6a,0xbf,0xaf,0xe4,0xbf,0x25, |
3910 | | 0xcc,0xcd,0xcf,0xdb,0xd2,0xc8,0x70,0xd5,0x4b,0xb8,0xeb,0xde,0x1c,0xee,0x86,0x0b, |
3911 | | 0x0b,0x77,0xe3,0x73,0xb4,0xfd,0x5d,0x6d,0xf7,0xc9,0xbd,0x4a,0xee,0x5c,0xe9,0x47, |
3912 | | 0x0a,0x7f,0x46,0xb8,0x8e,0x43,0x0a,0x57,0x4a,0xdb,0x77,0x2b,0xde,0xc2,0x72,0xef, |
3913 | | 0x51,0xb8,0x2f,0x14,0xee,0x4c,0xf9,0x1f,0x0a,0x77,0xd7,0x0f,0x5f,0xca,0xfd,0x95, |
3914 | | 0xf4,0x1b,0xe9,0xe7,0x0a,0xff,0x96,0xdc,0x5b,0x14,0x6f,0x5b,0xa5,0x9f,0xa5,0xed, |
3915 | | 0xef,0x69,0x7b,0x1b,0xb9,0x57,0xcb,0xfd,0xa1,0x74,0xbb,0xc2,0x5f,0xae,0x7c,0xec, |
3916 | | 0x52,0xb8,0x54,0x6d,0xff,0x44,0xf1,0x5e,0x26,0xf7,0xa7,0x0a,0x77,0x50,0xe1,0xae, |
3917 | | 0x90,0xff,0x61,0xe5,0xf7,0x88,0xdc,0x5f,0x4b,0x8f,0x4a,0x0f,0x48,0x3b,0x86,0xbb, |
3918 | | 0xeb,0xa0,0xe1,0xd2,0x11,0xf2,0xff,0x40,0xba,0x4d,0xba,0x4f,0xba,0x1f,0x6d,0x1b, |
3919 | | 0xe1,0x38,0x15,0xa1,0x1d,0x44,0x43,0x7b,0xa8,0x24,0xf7,0x05,0xd2,0xca,0xd2,0xd5, |
3920 | | 0xd2,0x2d,0xd2,0x95,0x50,0x2f,0x8a,0xf9,0x26,0xca,0xd5,0x78,0x69,0x12,0x2c,0x87, |
3921 | | 0x0d,0xf0,0x1e,0xbc,0x0e,0x0d,0x0a,0xb1,0x9e,0x86,0x0e,0xd0,0x0c,0x3a,0xc2,0x45, |
3922 | | 0xf0,0x1e,0xdc,0x05,0xcb,0x61,0xbd,0xdc,0xaf,0xcb,0xbd,0xc1,0x84,0x2f,0x4c,0x78, |
3923 | | 0x78,0x07,0x56,0xc2,0x6a,0x58,0x2f,0xf7,0x5a,0x78,0x17,0xd6,0xc9,0xbd,0x01,0x1a, |
3924 | | 0x9c,0xe1,0x38,0xcd,0xa1,0x23,0x5c,0x74,0x86,0xeb,0x6e,0x01,0xeb,0xe1,0x03,0x78, |
3925 | | 0x13,0x72,0x61,0x3b,0x7c,0x24,0xff,0x0f,0x21,0xb6,0x28,0xe5,0x84,0xe4,0xd2,0xd4, |
3926 | | 0x7d,0x69,0x57,0x0b,0x48,0x0b,0x4a,0x0b,0x4b,0xcf,0x94,0x9e,0x25,0xad,0x2b,0xad, |
3927 | | 0x2f,0x4d,0x93,0x36,0x92,0x36,0x2e,0xed,0xb6,0x6b,0x6d,0x1d,0x27,0x52,0xa5,0x97, |
3928 | | 0x49,0x2f,0xd7,0xf1,0xb1,0x97,0xb4,0xb7,0xd6,0x9b,0x4f,0xeb,0xf8,0xf2,0xbc,0xdc, |
3929 | | 0xcf,0xc8,0xbd,0x58,0xee,0x35,0xd2,0xb5,0xd2,0xad,0xd2,0xf7,0x75,0xbc,0xf3,0x6b, |
3930 | | 0x3c,0x86,0x6b,0x7c,0x47,0x68,0x9c,0x8e,0xd5,0x38,0x0e,0xd3,0xf6,0x80,0xb6,0x47, |
3931 | | 0x6a,0xfb,0x38,0xe9,0x78,0xe9,0x04,0xe9,0x0d,0xd2,0x89,0xd2,0x1b,0xa5,0x93,0x14, |
3932 | | 0x5f,0x41,0xc5,0x57,0x58,0xf1,0x9d,0xa9,0xed,0x93,0xb5,0xbd,0x90,0xb6,0x9f,0xa1, |
3933 | | 0xed,0x45,0xb4,0xfd,0x26,0xe9,0xcd,0xd2,0x5b,0xa4,0xb7,0x4a,0x6f,0x93,0xde,0x2e, |
3934 | | 0x9d,0xa2,0xf8,0xce,0x52,0x7c,0x25,0xe4,0x2e,0x2e,0x77,0x49,0xb9,0xcf,0x93,0xfb, |
3935 | | 0x7c,0xb9,0x4b,0xcb,0x5d,0x46,0xee,0x8a,0x72,0x5f,0xa0,0xfc,0x54,0x56,0xfc,0x39, |
3936 | | 0xda,0x1e,0xad,0xed,0x95,0xb4,0xbd,0x8a,0xb6,0x4f,0x95,0xde,0x21,0xbd,0x53,0x7a, |
3937 | | 0x97,0x74,0x9a,0xf4,0x6e,0xe9,0x3d,0x8a,0xaf,0x9a,0xe2,0xab,0xa1,0xf8,0x62,0xb5, |
3938 | | 0xfd,0x5e,0x6d,0xaf,0xae,0xed,0x31,0xda,0x5e,0x53,0xdb,0xa7,0x4b,0xef,0x93,0xde, |
3939 | | 0x2f,0x7d,0x40,0xfa,0xa0,0xf4,0x21,0xe9,0xc3,0x8a,0x2f,0x41,0xf1,0x25,0x29,0xbe, |
3940 | | 0x14,0xf9,0x27,0xca,0x3f,0x59,0xfe,0xb5,0xe4,0x5f,0x47,0xfe,0xf5,0xe4,0xdf,0x40, |
3941 | | 0xfe,0x75,0xe5,0x5f,0x5f,0xfe,0x0d,0xe5,0x9f,0x2e,0xff,0x26,0x72,0x37,0x96,0x3b, |
3942 | | 0x28,0x77,0x73,0xb9,0x2f,0x92,0xbb,0x85,0xdc,0x2d,0xe5,0xbe,0x58,0xee,0x76,0x8a, |
3943 | | 0xb7,0x83,0xfc,0xdb,0xca,0xbf,0xbd,0xfc,0x3b,0xca,0xbf,0xb3,0xfc,0x2f,0x97,0xff, |
3944 | | 0x95,0xf2,0xef,0x2a,0xff,0xab,0xe4,0xdf,0x43,0xf5,0x30,0x43,0xdb,0xbb,0x69,0x7b, |
3945 | | 0x77,0x6d,0xef,0xa9,0xed,0x33,0xa5,0x8f,0x48,0x1f,0x95,0x3e,0x26,0x7d,0x5c,0xfa, |
3946 | | 0x84,0xf4,0x49,0xc5,0x77,0xb5,0xe2,0xeb,0xab,0xf8,0xfa,0x6b,0xfb,0x2c,0x6d,0xef, |
3947 | | 0xa3,0xed,0xfd,0xb4,0x7d,0x80,0xb6,0xcf,0x96,0x3e,0x25,0x9d,0x23,0x7d,0x5a,0xfa, |
3948 | | 0x8c,0xf4,0x59,0xe9,0x5c,0xe9,0x02,0xe9,0x6a,0xe9,0x97,0xd2,0xc5,0x4a,0x6f,0xa3, |
3949 | | 0x77,0x5c,0x57,0x7a,0x6f,0x6a,0xfb,0x5a,0xe9,0xbf,0x15,0xee,0x43,0x85,0xfb,0x48, |
3950 | | 0xe1,0xb6,0x97,0x73,0xef,0xeb,0xdc,0x57,0xc1,0xd5,0xfb,0xa5,0xcf,0x4a,0x37,0x4a, |
3951 | | 0xdf,0x94,0xbe,0x21,0x0d,0xd7,0xfd,0xa0,0x28,0x69,0x61,0xe9,0x05,0xd2,0xca,0xd2, |
3952 | | 0x46,0xd2,0x26,0xd2,0x0c,0x69,0xa6,0xb4,0x9f,0xb4,0xab,0x74,0xa0,0x74,0x90,0x74, |
3953 | | 0xa8,0x74,0x98,0x74,0xa4,0x74,0x94,0x74,0xac,0x74,0x9c,0x74,0x87,0xf4,0x63,0xe9, |
3954 | | 0x0d,0xd2,0x89,0xd2,0xc9,0xd2,0x9b,0xa4,0x3b,0xa5,0xbb,0xa4,0x4f,0x4b,0x9f,0x91, |
3955 | | 0x3e,0x2b,0x9d,0x2b,0xdd,0x27,0xdd,0x2f,0xfd,0x5c,0x7a,0x00,0x9d,0x1e,0xc7,0xf8, |
3956 | | 0x8f,0x73,0xf5,0x22,0x69,0x2b,0x69,0x96,0xf4,0x62,0x69,0x3b,0x69,0x07,0xe9,0x25, |
3957 | | 0xd2,0x4b,0xa5,0x97,0x49,0xaf,0x90,0x76,0x91,0x76,0x95,0x76,0x97,0xf6,0x94,0xf6, |
3958 | | 0x96,0x0e,0x84,0xfb,0x60,0x90,0xdc,0x43,0xe4,0x1e,0x2a,0xf7,0x70,0xb9,0x47,0xc8, |
3959 | | 0x3d,0x4a,0xee,0xd1,0x72,0x8f,0x91,0xfb,0x5a,0xb9,0x1f,0x92,0x7e,0x25,0x7d,0x5a, |
3960 | | 0xfa,0xac,0x74,0x9e,0x74,0x81,0xf4,0x39,0xe9,0xf3,0xd2,0x17,0xa4,0x2f,0x4a,0x97, |
3961 | | 0x4a,0x97,0x4b,0x57,0x4a,0x57,0x4b,0x5f,0x95,0xae,0x95,0xbe,0x26,0xdd,0xa4,0x7c, |
3962 | | 0xbd,0x25,0xf7,0x16,0xb9,0xdf,0x96,0xfb,0x5d,0xb9,0xdf,0x93,0xfb,0x7d,0xb9,0x3f, |
3963 | | 0x90,0x3b,0x57,0xee,0x0f,0xe5,0xfe,0xb7,0xf4,0x1b,0xe9,0x51,0xe9,0xb7,0xd2,0x1f, |
3964 | | 0xe2,0xdc,0xe3,0xf0,0x6b,0x01,0x5f,0x9e,0xee,0x46,0x5f,0x2c,0xea,0x73,0xee,0x2b, |
3965 | | 0xea,0xea,0x03,0xd2,0x39,0x50,0xa5,0x98,0xcf,0x89,0x2d,0xe6,0x6a,0x4d,0x68,0x50, |
3966 | | 0xdc,0xe7,0xb4,0x80,0x8e,0x70,0x11,0xbc,0x06,0x13,0xe0,0x25,0x98,0x08,0xab,0xe1, |
3967 | | 0x76,0xf9,0x4f,0x85,0x17,0x60,0xad,0xfc,0x5f,0x95,0xff,0x3a,0x98,0x57,0xc2,0xe7, |
3968 | | 0x2c,0x85,0x17,0xe1,0x25,0x58,0x06,0xcb,0x61,0x6e,0x49,0xfc,0x4a,0xba,0xfa,0x12, |
3969 | | 0xc4,0x95,0xf2,0x39,0xb5,0xa1,0x6c,0xb6,0xcf,0xa9,0x00,0xe5,0x20,0x1a,0xca,0x43, |
3970 | | 0x25,0xb8,0x10,0x2a,0xca,0xbf,0xb2,0xfc,0xab,0xca,0x5d,0x45,0x7a,0x01,0xf4,0xec, |
3971 | | 0xe7,0x73,0x7a,0xf7,0x73,0xb5,0x97,0xf4,0x6a,0xa0,0x2a,0x9c,0x54,0x68,0x04,0x97, |
3972 | | 0xc2,0x95,0x22,0x1b,0x46,0xc3,0x53,0x62,0x91,0x58,0x2c,0x5e,0x14,0xe6,0x5e,0xb1, |
3973 | | 0xb9,0x9f,0x65,0xfe,0x14,0x9a,0xb9,0x0e,0xfa,0x8d,0xf1,0xe7,0xbc,0xf8,0x25,0xb1, |
3974 | | 0x14,0x56,0xc0,0x4a,0x78,0x19,0x5e,0x81,0x3b,0x39,0x7f,0xbe,0x0b,0xa6,0xc1,0xdd, |
3975 | | 0x30,0x17,0xe6,0xc1,0x2a,0x58,0x03,0x6f,0xc1,0x0e,0xd8,0x0d,0x9f,0x8b,0x2f,0x84, |
3976 | | 0x99,0xe7,0x06,0x98,0xb9,0xc4,0x5c,0xe7,0x33,0x73,0x88,0x18,0x6e,0xd6,0xc3,0xe6, |
3977 | | 0x1c,0x4a,0x5c,0x63,0xae,0xf7,0x99,0x6b,0x7d,0xe2,0x46,0x31,0x49,0x4c,0xd6,0xf9, |
3978 | | 0xf2,0xad,0xc2,0x9c,0xdb,0xce,0x34,0xc7,0x08,0xb3,0xfe,0x36,0x73,0xaa,0x99,0x77, |
3979 | | 0x58,0x3f,0x4f,0x80,0x49,0x70,0x33,0xd4,0x0c,0xb0,0x06,0x86,0x0e,0x70,0x09,0x74, |
3980 | | 0x82,0x2e,0x30,0x19,0x6e,0x81,0x5b,0x61,0x2a,0x2c,0x83,0x15,0x62,0x15,0xac,0x86, |
3981 | | 0x57,0xe0,0x55,0x58,0x1b,0x30,0xfd,0x8e,0x3e,0x0f,0xfb,0xe0,0x20,0x7c,0x09,0x45, |
3982 | | 0x59,0x6b,0x9f,0x07,0xe5,0xa1,0x21,0xa4,0x89,0x46,0xd0,0x1c,0x5a,0xc0,0x95,0xd0, |
3983 | | 0x05,0x7a,0x43,0x7f,0x18,0x00,0x03,0xc5,0x20,0xad,0xdb,0xdf,0x11,0xef,0x42,0x2e, |
3984 | | 0x6c,0x87,0xdd,0xf0,0x09,0xec,0x81,0x4f,0x61,0x2f,0xec,0x83,0x03,0xf0,0x05,0x1c, |
3985 | | 0x84,0x43,0x70,0x14,0xbe,0x85,0x63,0xf0,0xa3,0x28,0x1a,0xe9,0x52,0x4c,0x9c,0x05, |
3986 | | 0x35,0x21,0x0e,0x9a,0x43,0x4b,0x78,0x1c,0x9e,0x80,0x79,0x30,0x5f,0xac,0x84,0xd7, |
3987 | | 0x60,0x3d,0xec,0x83,0xfd,0x70,0x04,0xbe,0x82,0xaf,0xe1,0x5b,0xf1,0xbd,0x70,0x0a, |
3988 | | 0xb0,0xae,0x83,0xb3,0xa1,0x14,0x9c,0x27,0x4a,0x43,0x34,0x5c,0x20,0x2a,0x41,0x15, |
3989 | | 0xa8,0x2a,0x2e,0x84,0x18,0x48,0x83,0x4b,0xa0,0x13,0x74,0x86,0x2e,0x70,0x35,0x0c, |
3990 | | 0x84,0x49,0x70,0x13,0x4c,0x81,0x7b,0xe0,0x61,0x98,0x01,0xeb,0xe0,0x35,0xb1,0x1e, |
3991 | | 0x3e,0x86,0x5d,0xe0,0xe7,0x7c,0x26,0x4c,0x84,0x43,0x2a,0xd4,0x11,0x75,0x45,0x3d, |
3992 | | 0x51,0x5f,0x34,0x80,0x34,0x68,0x04,0xcd,0x20,0x13,0x2e,0x82,0x96,0xa2,0x15,0xb4, |
3993 | | 0x86,0x2c,0xd1,0x06,0x3a,0xc2,0x25,0x90,0x0d,0x5d,0xa1,0x1b,0xf4,0x80,0x01,0x30, |
3994 | | 0x48,0x0c,0x86,0xb1,0x30,0x4e,0x8c,0x87,0x09,0x30,0x11,0x6e,0x85,0x29,0x90,0x03, |
3995 | | 0x77,0xc2,0x2c,0x78,0x0a,0xe6,0xc1,0x02,0xf1,0x3c,0x2c,0x81,0xa5,0x62,0x99,0x30, |
3996 | | 0xe7,0x6f,0x2b,0x61,0x15,0xbc,0x02,0x6b,0x61,0x9d,0xce,0xe9,0xcc,0xf9,0xdc,0x46, |
3997 | | 0xf1,0x86,0x78,0x4f,0xe4,0xc2,0x87,0xb0,0x1d,0x3e,0x86,0x9d,0xb0,0x0b,0xf6,0xc0, |
3998 | | 0x41,0x38,0x04,0x87,0xe1,0x98,0xf8,0x41,0xf8,0x0a,0x52,0xaf,0x10,0x26,0x02,0x50, |
3999 | | 0x10,0x8a,0x40,0x51,0x28,0x0e,0x55,0xa1,0x1a,0xc4,0x41,0x02,0x24,0x42,0x32,0xa4, |
4000 | | 0x40,0x6d,0x48,0x85,0x7a,0xa2,0x01,0xa4,0x41,0x23,0x48,0x87,0x0c,0x68,0x06,0x2d, |
4001 | | 0xa0,0x25,0xb4,0x11,0x9d,0xe0,0x32,0xb8,0x42,0xf4,0x80,0x01,0x30,0x10,0x06,0xc1, |
4002 | | 0x60,0x18,0x0a,0xc3,0xc4,0x38,0x18,0x0f,0x13,0xc4,0x44,0xb8,0x0d,0xa6,0xc0,0x54, |
4003 | | 0xb8,0x13,0x66,0xc1,0x53,0x30,0x0f,0x16,0xc0,0x42,0x58,0x04,0x4b,0x60,0xa9,0x58, |
4004 | | 0x26,0x96,0xc3,0x4a,0x58,0x05,0xaf,0xc2,0x5a,0x58,0x07,0xaf,0x89,0x0d,0xf0,0x3a, |
4005 | | 0x6c,0x14,0x9b,0xc4,0x0e,0xf8,0x18,0x76,0xc2,0x2e,0xd8,0x03,0x07,0xe1,0xa8,0xf8, |
4006 | | 0x16,0x7e,0x04,0x5f,0x21,0x17,0x3f,0x84,0x41,0x00,0x0a,0x43,0x11,0x28,0x0a,0xc5, |
4007 | | 0xa1,0x2a,0x54,0x83,0x38,0x48,0x80,0x44,0x48,0x86,0x54,0xa8,0x27,0xea,0x8b,0x06, |
4008 | | 0xa2,0xa1,0x48,0x13,0x8d,0xa0,0x09,0x64,0xe8,0xfc,0xbe,0x85,0xce,0xef,0x5b,0x8a, |
4009 | | 0xb6,0x3a,0xf7,0xef,0x28,0x2e,0x83,0xcb,0xe1,0x4a,0xc8,0x86,0xae,0xd0,0x0d,0x7a, |
4010 | | 0xc0,0x00,0x18,0x24,0xc6,0x8b,0x09,0x62,0x22,0xdc,0x0c,0xb7,0x43,0x0e,0xdc,0x01, |
4011 | | 0xd3,0x60,0x3a,0xdc,0x07,0x0f,0x88,0x87,0xe0,0x61,0x78,0x14,0x1e,0x83,0x59,0xf0, |
4012 | | 0x14,0x3c,0x0b,0x4b,0x74,0x7d,0x61,0x05,0xac,0x14,0xab,0x60,0x35,0xac,0x81,0x75, |
4013 | | 0xba,0x16,0x61,0xae,0x43,0x6c,0x14,0x9b,0xc4,0x7b,0x62,0x0f,0x1c,0x2c,0x64,0x6e, |
4014 | | 0x7c,0xbb,0xf8,0x20,0x0c,0xc2,0x45,0x00,0x0a,0xc3,0x99,0x50,0x14,0xce,0x82,0xaa, |
4015 | | 0x50,0x0d,0x52,0xa1,0x9e,0xa8,0x2f,0x1a,0x40,0x1a,0x34,0x82,0x26,0xd0,0x54,0xd7, |
4016 | | 0x3d,0x9a,0x43,0x4b,0x68,0x5f,0xd8,0xbd,0x16,0x72,0x09,0x5c,0x0a,0x97,0xc1,0xe5, |
4017 | | 0xd0,0x05,0xb2,0xa1,0x2b,0x74,0x83,0x1e,0x30,0x00,0xc6,0x8a,0x71,0x62,0x3c,0x4c, |
4018 | | 0x80,0x89,0x70,0x2b,0xdc,0x0e,0x39,0x70,0x07,0xcc,0x82,0xa7,0x60,0x21,0x2c,0x82, |
4019 | | 0x25,0xb0,0x54,0x2c,0x13,0xcb,0xc5,0x0a,0x61,0xae,0xc5,0xbc,0x02,0x6b,0xc4,0x5a, |
4020 | | 0x5d,0x87,0x59,0xaf,0xeb,0x30,0xaf,0xc3,0x46,0x5d,0x97,0x31,0xd7,0x68,0x72,0xe1, |
4021 | | 0x23,0xd8,0x01,0x1f,0xc3,0x4e,0xd8,0x05,0x7b,0xe0,0x20,0x1c,0x86,0x2f,0xe1,0x88, |
4022 | | 0x70,0xce,0xa0,0x4e,0xc1,0x0f,0x61,0x10,0x0e,0x85,0xe1,0x4c,0x28,0x0a,0x67,0x41, |
4023 | | 0x1d,0xa8,0x0b,0xf5,0xa0,0xbe,0x30,0xd7,0x7b,0xd2,0xa0,0x11,0x34,0x81,0xa6,0xd0, |
4024 | | 0x4c,0xd7,0x84,0xcc,0xf5,0xa0,0x96,0xa2,0x95,0x68,0x07,0x1d,0x74,0xbd,0xc8,0x70, |
4025 | | 0x25,0x64,0x43,0x57,0xe8,0x06,0x3d,0x60,0x00,0x8c,0x86,0xeb,0x61,0x9c,0x18,0x0f, |
4026 | | 0x13,0x60,0x22,0xdc,0x0d,0xf7,0xc1,0x7c,0x58,0x08,0x2f,0xc1,0x32,0xb1,0x12,0xd6, |
4027 | | 0xe8,0x3a,0xd3,0x7a,0x5d,0x7f,0x7a,0x0b,0x36,0xc3,0xdb,0xf0,0xae,0xd8,0xaa,0x6b, |
4028 | | 0x52,0x7b,0xe0,0x20,0x7c,0x09,0x47,0x4c,0x1d,0x9c,0xc9,0xb8,0x84,0x78,0x91,0x00, |
4029 | | 0x89,0x90,0x04,0x75,0x20,0x0d,0x82,0xd0,0x54,0x64,0x40,0x2b,0xc8,0x82,0x4e,0x30, |
4030 | | 0x0e,0xc6,0xc3,0x0d,0xe2,0x46,0xb8,0x19,0x6e,0x85,0x47,0xe1,0x71,0xf1,0x24,0xcc, |
4031 | | 0x83,0xf9,0x62,0x01,0x2c,0x84,0xe7,0x60,0x29,0x2c,0x13,0x2b,0xe1,0x15,0x58,0x23, |
4032 | | 0xd6,0xc1,0x1b,0xb0,0x09,0xde,0x87,0x5c,0xd8,0x0e,0x4e,0x11,0x97,0x73,0xa1,0x14, |
4033 | | 0x94,0x87,0x0b,0x21,0x59,0xd4,0x12,0xa9,0xa2,0x01,0x34,0x84,0x34,0xc8,0x80,0x4c, |
4034 | | 0xe8,0x0b,0x83,0xe0,0x3a,0xb8,0x5e,0x8c,0x85,0x1b,0xe0,0x46,0x98,0x04,0x93,0xe1, |
4035 | | 0x56,0xb8,0x0d,0xee,0x81,0xe9,0xb0,0x14,0xd6,0x08,0xa7,0x28,0x63,0x0e,0xaa,0x43, |
4036 | | 0x0d,0x88,0x81,0x38,0x88,0x17,0x09,0x50,0x0b,0x6a,0x8b,0x54,0xa8,0x03,0x75,0xa1, |
4037 | | 0x1e,0xd4,0x87,0x06,0xd0,0x50,0xa4,0x41,0x26,0x64,0x41,0x7b,0xe8,0x00,0x1d,0xe1, |
4038 | | 0x12,0xe8,0x04,0x97,0xc2,0xe5,0x70,0x05,0x74,0x81,0x6c,0xd1,0x15,0xae,0x82,0xee, |
4039 | | 0xd0,0x03,0x7a,0x42,0x3f,0xe8,0x0f,0x03,0x61,0x10,0x0c,0x85,0x61,0x30,0x0e,0xc6, |
4040 | | 0x8b,0x09,0x70,0x03,0x4c,0x84,0x1b,0x61,0x12,0xdc,0x0a,0xb7,0x89,0xdb,0xc5,0x14, |
4041 | | 0x91,0x03,0xd3,0xe1,0x3e,0x78,0x00,0x1e,0x14,0x33,0xe0,0x55,0x58,0x2b,0x36,0x8a, |
4042 | | 0x4d,0xf0,0x2d,0x1c,0x13,0xdf,0xc3,0x8f,0xe0,0x14,0x63,0xdc,0x9c,0xc5,0xb8,0x81, |
4043 | | 0x96,0x90,0x05,0x1d,0xe0,0x12,0x71,0x29,0x5c,0x0e,0x5d,0x60,0x32,0xdc,0x0c,0xb7, |
4044 | | 0x41,0x0e,0xcc,0x83,0x05,0xb0,0x08,0x5e,0x80,0xe5,0xb0,0x52,0xac,0x86,0x57,0x61, |
4045 | | 0x1d,0xbc,0x0b,0x5b,0xa1,0x68,0x71,0xc6,0x33,0x94,0x84,0x73,0xe1,0x52,0xb8,0x1c, |
4046 | | 0xae,0x84,0xde,0x30,0x08,0xc6,0xc2,0x14,0x98,0x01,0x5f,0xc3,0x37,0xf0,0x3d,0xf8, |
4047 | | 0x4a,0xd0,0x4f,0xce,0x66,0x8c,0xc2,0xf5,0x30,0x0e,0xee,0x83,0x19,0xb0,0x0f,0xbe, |
4048 | | 0x80,0x43,0x70,0x18,0xbe,0x01,0xe7,0x1c,0x8a,0x06,0x67,0x41,0x09,0x28,0x29,0xca, |
4049 | | 0x41,0x3c,0x24,0x40,0x22,0x24,0x89,0x34,0x68,0x03,0x17,0x43,0x5b,0xe8,0x02,0x7d, |
4050 | | 0xa1,0x3f,0x0c,0x84,0xc1,0x30,0x04,0xc6,0xc2,0x42,0x78,0x0e,0x16,0xc1,0xf3,0x62, |
4051 | | 0x31,0x2c,0x83,0xe5,0xf0,0x2a,0xac,0x11,0x6b,0x61,0x1d,0xbc,0x06,0x5b,0xe0,0x3d, |
4052 | | 0x91,0x2b,0x3e,0x14,0x3b,0xe0,0x33,0x28,0x74,0x2e,0x53,0x22,0x14,0x11,0x45,0xa1, |
4053 | | 0x14,0x94,0x87,0x74,0x68,0x2c,0x9a,0xc0,0x48,0x18,0x0b,0x37,0xc0,0x44,0xb8,0x11, |
4054 | | 0x26,0xc1,0x2c,0x98,0x2d,0x9e,0x12,0xf3,0xe0,0x6b,0x70,0x4a,0x39,0x4e,0x59,0x28, |
4055 | | 0x0f,0x15,0x21,0x1a,0x2a,0x43,0x15,0xa8,0x0a,0x17,0x42,0x75,0x88,0x83,0x78,0x48, |
4056 | | 0x10,0x89,0x50,0x1b,0x52,0xa1,0x2e,0x34,0x85,0xd6,0x90,0x05,0xfd,0x60,0x20,0x0c, |
4057 | | 0x85,0xb1,0x30,0x07,0xe6,0xc1,0x6b,0xb0,0x09,0xde,0x87,0x0f,0x84,0x73,0x1e,0x6b, |
4058 | | 0x7b,0x38,0x07,0xce,0x85,0x52,0x70,0x1e,0x94,0x16,0xe5,0xa1,0x1d,0xb4,0x17,0x1d, |
4059 | | 0x44,0x47,0x71,0x09,0x5c,0x01,0x5d,0x44,0xb6,0xe8,0x2a,0xba,0xc1,0x55,0xd0,0x1d, |
4060 | | 0xfa,0x42,0x3f,0x18,0x0c,0x43,0x60,0x0c,0x5c,0x2f,0xc6,0xc2,0x4d,0x90,0x03,0xd3, |
4061 | | 0xe1,0x49,0x31,0x0f,0x96,0xc1,0x0a,0x38,0x04,0x4e,0x69,0x8e,0x4b,0xe6,0xba,0xbe, |
4062 | | 0x08,0x40,0x22,0x24,0x89,0x64,0x91,0x02,0x75,0x74,0x8f,0xc0,0x50,0x4f,0xd4,0xd7, |
4063 | | 0xfd,0x81,0x74,0x61,0xee,0x11,0x34,0x81,0x20,0x5c,0x04,0x59,0xd0,0x09,0xfa,0xc0, |
4064 | | 0x10,0x18,0x0b,0xe3,0x60,0xbc,0x98,0x00,0x33,0x60,0xa6,0x78,0x04,0x1e,0x87,0x27, |
4065 | | 0xe0,0x49,0x98,0x05,0xb3,0xe1,0x29,0x31,0x07,0x9e,0x81,0x67,0x61,0x2e,0xcc,0x83, |
4066 | | 0x25,0xf0,0x22,0x7c,0x02,0x7b,0xc4,0xa7,0x62,0x2f,0x7c,0x06,0xfb,0xe0,0x73,0x38, |
4067 | | 0x20,0xbe,0x10,0x07,0xe1,0x30,0x7c,0x09,0x47,0xc0,0x39,0x9f,0x3e,0x03,0x17,0x40, |
4068 | | 0x75,0xa8,0x01,0x89,0x90,0x04,0xc9,0x90,0x02,0xb5,0x20,0x0d,0x32,0xa1,0x25,0xb4, |
4069 | | 0x86,0x2c,0xe8,0x04,0x97,0xc2,0x08,0x18,0x09,0xd7,0xc2,0x58,0xb8,0x19,0x72,0xe0, |
4070 | | 0x45,0x58,0x06,0x2b,0x60,0x13,0x6c,0x86,0xb7,0x61,0x07,0x7c,0x2c,0x76,0xc2,0x5e, |
4071 | | 0xf8,0x0c,0x3e,0x87,0x03,0xe2,0x0b,0x38,0x02,0x5f,0x89,0xaf,0xe1,0x5f,0xf0,0x6f, |
4072 | | 0xf1,0x0d,0x1c,0x85,0x6f,0x85,0x53,0x86,0xfc,0x43,0x0d,0xb8,0x1a,0xfa,0xc0,0x08, |
4073 | | 0x18,0x29,0x46,0xc1,0x7d,0x70,0x3f,0xac,0x80,0x95,0xf0,0x63,0x19,0xf7,0x19,0x75, |
4074 | | 0x73,0xdf,0xc1,0xdc,0xa3,0x37,0xf7,0x17,0xcc,0xbd,0x63,0x73,0x1d,0xdc,0xdc,0x33, |
4075 | | 0x37,0xd7,0xbb,0xcd,0x3d,0x59,0x73,0x1d,0xbb,0x93,0xe8,0x2c,0x2e,0x17,0xe6,0x5a, |
4076 | | 0xf6,0xb5,0xe5,0xdc,0x7b,0x33,0xe6,0xbe,0xb7,0xb9,0x77,0x6d,0x9e,0x03,0x58,0x2e, |
4077 | | 0xcc,0xb5,0x5f,0x73,0x1f,0xdc,0xdc,0x83,0x36,0xf7,0xf5,0xcd,0x3d,0xe6,0x2d,0xe5, |
4078 | | 0xdc,0x7b,0xc9,0xdb,0xca,0xb9,0xf7,0x80,0xcd,0xfd,0x78,0x73,0x6d,0xd8,0xdc,0x87, |
4079 | | 0x35,0xf7,0x72,0xcd,0x7d,0xf4,0xc2,0xe5,0x99,0x37,0xa0,0x21,0xa4,0x41,0x3b,0x31, |
4080 | | 0x48,0x5c,0x2f,0xa6,0xc0,0xc3,0xb0,0x09,0x72,0xe1,0x63,0xf1,0x09,0x1c,0x02,0x7f, |
4081 | | 0x05,0x97,0x48,0x51,0x10,0x8a,0x43,0x49,0x71,0xae,0x28,0x05,0x65,0xe0,0x02,0x51, |
4082 | | 0x59,0x54,0x15,0xd5,0x20,0x06,0x62,0x45,0x4d,0x48,0x82,0x64,0x73,0x6d,0x19,0x52, |
4083 | | 0x45,0x3d,0x68,0x08,0x41,0xc8,0x84,0x56,0xa2,0x0b,0x8c,0x87,0x09,0x70,0x03,0x4c, |
4084 | | 0x84,0xc9,0xe0,0xd4,0x70,0x9c,0x6b,0x60,0x0c,0x5c,0x0b,0xd7,0xc1,0x6e,0xd8,0x0f, |
4085 | | 0x5f,0xc0,0x41,0x38,0x0c,0x5f,0xc2,0x11,0x70,0x62,0x1c,0xa7,0x12,0x54,0x11,0x31, |
4086 | | 0x22,0x0e,0x7a,0xc2,0x00,0x71,0xbd,0x18,0x0b,0x77,0xc3,0x0c,0x78,0x02,0x66,0xc1, |
4087 | | 0xb3,0x30,0x0f,0x9e,0x87,0x17,0x60,0x39,0xac,0x84,0x35,0xb0,0x0e,0xde,0x80,0x4d, |
4088 | | 0xf0,0x2e,0x6c,0x85,0x8f,0x60,0x07,0xfc,0x08,0x81,0x38,0x97,0x08,0x11,0x29,0x2a, |
4089 | | 0xc0,0x85,0x50,0x0d,0x62,0x20,0x16,0x6a,0x42,0x3c,0x24,0x43,0x6d,0xa8,0x03,0x75, |
4090 | | 0x45,0x3d,0xd1,0x08,0xee,0xd6,0xf5,0x4b,0x73,0xad,0xf3,0x7e,0x78,0x00,0x1e,0xd4, |
4091 | | 0x75,0xdc,0x87,0xc5,0x4c,0x5d,0xe7,0xfc,0x4e,0x1c,0xd3,0xf5,0xce,0x1f,0x45,0x20, |
4092 | | 0x9e,0xf4,0x20,0x1e,0x6e,0x87,0x19,0xb0,0x02,0x0e,0xc1,0x8f,0xe0,0x24,0xe1,0x6e, |
4093 | | 0x89,0xb6,0xe2,0xf8,0x39,0x83,0xb6,0x17,0x67,0xc3,0xad,0x8f,0x51,0x5e,0xf8,0x37, |
4094 | | 0x7c,0x03,0xdf,0x83,0xf3,0x38,0xc7,0xae,0x27,0xe8,0x87,0xa2,0x28,0x94,0x83,0xf2, |
4095 | | 0x70,0x21,0x54,0x83,0xea,0x90,0x06,0xfd,0xa0,0xbf,0x18,0x20,0x86,0xc2,0xb5,0x70, |
4096 | | 0xbd,0x18,0x0b,0xf7,0xc3,0x03,0xf0,0x20,0x3c,0x04,0x0f,0xc3,0x0c,0xf8,0x04,0xf6, |
4097 | | 0xc0,0x41,0x38,0x04,0x87,0xe1,0x9c,0x27,0x49,0x0f,0x2a,0xc2,0x00,0x18,0x28,0x06, |
4098 | | 0xc1,0x24,0x98,0x2c,0x6e,0x81,0xdb,0x61,0x8a,0xc8,0x81,0x0f,0x61,0xa7,0x38,0x0c, |
4099 | | 0x5f,0xc1,0xd7,0xf0,0x2f,0xf8,0xb7,0xf8,0x06,0x8e,0xc2,0xb7,0xe2,0x3b,0xf0,0xcd, |
4100 | | 0x62,0xac,0x88,0x30,0x08,0x40,0x84,0x88,0x84,0x82,0x50,0x48,0x14,0x86,0x8a,0x10, |
4101 | | 0x0d,0x17,0x40,0x25,0xa8,0x0c,0x55,0x44,0x0d,0x91,0x06,0x43,0x60,0x2c,0x8c,0x83, |
4102 | | 0xf1,0xb0,0x10,0x9e,0x83,0x97,0xe1,0x15,0x78,0x15,0x36,0xc1,0xfb,0xb0,0x03,0x0e, |
4103 | | 0xc3,0x97,0xf0,0x6f,0xf8,0x4e,0x7c,0x0f,0x3f,0xc0,0x8f,0xc2,0x99,0xed,0x38,0x51, |
4104 | | 0x50,0x10,0x2a,0x41,0x65,0x88,0x81,0x38,0x68,0x0a,0x19,0xd0,0x06,0x2e,0x86,0xb6, |
4105 | | 0xd0,0x05,0xc6,0xc0,0x58,0x18,0x0f,0x13,0xc4,0x0d,0xb0,0x00,0x16,0x8a,0xe7,0x60, |
4106 | | 0x11,0x3c,0x0f,0x4b,0xe0,0x45,0x78,0x09,0x96,0xc2,0x32,0x58,0x0e,0x2b,0xe1,0x4d, |
4107 | | 0xb1,0x09,0xde,0x87,0x1d,0xb0,0x1b,0x3e,0x11,0x7b,0xc4,0xa7,0x70,0x10,0x0e,0xc1, |
4108 | | 0x51,0xf8,0x16,0x7e,0x98,0xed,0x5e,0x7c,0xae,0x0a,0x17,0x42,0x2c,0xd4,0x84,0x38, |
4109 | | 0x88,0x87,0x04,0x48,0x84,0x24,0x48,0x86,0x14,0x48,0x83,0x74,0x68,0x2c,0x9a,0x40, |
4110 | | 0x0b,0xb8,0x48,0xb4,0x14,0x59,0xd0,0x09,0xba,0xc0,0x00,0x18,0x28,0x06,0xc1,0x70, |
4111 | | 0x18,0x2d,0xae,0x11,0x63,0xc4,0xb5,0xe2,0x3a,0x98,0x0b,0xf3,0xc4,0x7c,0xb1,0x00, |
4112 | | 0x9e,0x83,0x45,0xf0,0x3c,0x2c,0x86,0x17,0x60,0x09,0x2c,0x83,0xe5,0xb0,0x02,0x56, |
4113 | | 0x8a,0x55,0x62,0xb5,0xd8,0x06,0xb9,0xf0,0xa1,0xd8,0x01,0xfb,0x60,0xbf,0xf8,0x1c, |
4114 | | 0x0e,0xc0,0x17,0x70,0x10,0xbe,0x14,0x47,0xe0,0x2b,0xf8,0x5a,0xfc,0x4b,0xf8,0xe6, |
4115 | | 0xd0,0x2f,0x21,0x0a,0xce,0x84,0x62,0x70,0x36,0x94,0x87,0xca,0x50,0x15,0x62,0x21, |
4116 | | 0x0e,0x2e,0x85,0xcb,0xe0,0x4a,0xe8,0x02,0xbd,0xa0,0xb7,0xe8,0x0b,0xfd,0x60,0x20, |
4117 | | 0xac,0x80,0x95,0xb0,0x13,0x76,0xc1,0x6e,0xf8,0x44,0xec,0x81,0x4f,0x61,0xaf,0xf8, |
4118 | | 0x0c,0xf6,0xc1,0xe7,0xe2,0x80,0x38,0x04,0x47,0xc1,0x79,0x9a,0xf3,0xd4,0xf7,0xa8, |
4119 | | 0x43,0x58,0x03,0x1b,0xe0,0x3b,0x30,0x0f,0x11,0xf7,0xfb,0x96,0xf4,0xe0,0x7d,0xf3, |
4120 | | 0x20,0xf1,0x77,0x94,0x03,0x8a,0xc3,0x39,0x50,0x46,0x94,0x15,0xe5,0xa0,0x2a,0x54, |
4121 | | 0x83,0x14,0xa8,0x0d,0xf5,0xa0,0x81,0x48,0x83,0x46,0xd0,0x18,0x9a,0x40,0x53,0x98, |
4122 | | 0x0f,0x5b,0xa0,0xfe,0xf7,0xf4,0x07,0x98,0x02,0x77,0xc0,0x5a,0x38,0x04,0xdf,0x99, |
4123 | | 0x07,0x7a,0x7f,0x60,0x3d,0x0e,0xe5,0xa1,0x26,0x24,0x42,0x12,0xb4,0x84,0xd6,0x30, |
4124 | | 0x10,0x86,0xc2,0x70,0x38,0x06,0x45,0x7f,0xe4,0x18,0x09,0x15,0xa0,0x0e,0x34,0x14, |
4125 | | 0x8d,0xe0,0x52,0xe8,0x2e,0x7a,0xc0,0x00,0x18,0x28,0x06,0xc1,0x83,0xf0,0x10,0x3c, |
4126 | | 0x0c,0x33,0x60,0x39,0xac,0x86,0xb5,0xb0,0x1e,0xde,0x84,0xcd,0xf0,0x1e,0x7c,0x00, |
4127 | | 0xb9,0xe6,0x41,0x62,0xc7,0xe7,0x14,0x82,0x33,0xa0,0x32,0x54,0x85,0x3a,0x50,0x0f, |
4128 | | 0xea,0x43,0x43,0x68,0x09,0x59,0x70,0x39,0x8c,0x85,0x6f,0x21,0xcd,0xe7,0x73,0x86, |
4129 | | 0xc2,0xf7,0x62,0xac,0xdf,0xe7,0x3c,0x00,0x33,0x60,0x13,0xec,0x10,0xe6,0xe5,0x90, |
4130 | | 0x72,0x10,0x03,0x69,0xd0,0x48,0xa4,0x43,0x26,0x34,0x17,0x59,0x30,0x0c,0x86,0xc3, |
4131 | | 0x68,0x18,0x0b,0x0f,0xc2,0x0c,0x78,0x19,0xd6,0xc1,0x9b,0xf0,0x16,0xbc,0x63,0x5e, |
4132 | | 0x38,0x09,0xf7,0x39,0xad,0x21,0x0b,0x1e,0x84,0x19,0x30,0x1b,0xe6,0xc1,0x16,0xd8, |
4133 | | 0x0a,0xdf,0x99,0x17,0x02,0x03,0x3e,0xa7,0x0a,0xc4,0x41,0x37,0x18,0x08,0xa3,0x61, |
4134 | | 0x0c,0xdc,0x0c,0xb7,0xc2,0x1d,0x70,0x17,0x4c,0x83,0x7b,0x60,0x26,0x3c,0x0a,0xf3, |
4135 | | 0x61,0x21,0x2c,0x81,0x97,0x60,0x29,0xac,0x84,0x23,0xe6,0x05,0x95,0x08,0x9f,0x93, |
4136 | | 0x12,0x49,0x99,0xa0,0x3d,0x74,0x81,0x9e,0x30,0x16,0x26,0xc2,0x24,0x98,0x07,0x0b, |
4137 | | 0x60,0x85,0x79,0x61,0xa5,0x80,0xcf,0x09,0x40,0x01,0x51,0x10,0x92,0xa1,0x16,0xd4, |
4138 | | 0x86,0x7a,0xa2,0x21,0xb4,0x87,0x2e,0x30,0x1c,0xc6,0xc2,0x43,0xb0,0x03,0xbe,0x84, |
4139 | | 0xaf,0xe0,0x6b,0xf3,0x02,0x63,0x94,0xcf,0x29,0x09,0xe5,0x21,0x15,0xd2,0xa0,0x13, |
4140 | | 0x8c,0x85,0xc5,0xb0,0x1c,0x56,0x98,0x17,0x64,0x0a,0xba,0xf8,0x20,0x0c,0x02,0x10, |
4141 | | 0x01,0x85,0xa1,0x08,0x14,0x85,0xe2,0x50,0x12,0xce,0x81,0x52,0x90,0x0c,0xb5,0xa1, |
4142 | | 0x0e,0x34,0x14,0x5d,0x60,0x0c,0x8c,0x85,0x07,0x60,0x25,0xac,0x85,0xd7,0x60,0x37, |
4143 | | 0x7c,0x02,0x7b,0x4c,0x5a,0x85,0xd8,0x1f,0xd2,0xa0,0x3d,0x74,0x81,0xc1,0x30,0x16, |
4144 | | 0xa6,0xe6,0xbd,0xa8,0xe3,0x73,0x9a,0xc1,0x58,0x58,0x00,0x2b,0xe1,0x4b,0xf3,0x02, |
4145 | | 0xe6,0x19,0x3e,0x27,0x1a,0x2e,0x80,0x2a,0x10,0x07,0xa9,0x90,0x06,0x99,0xd0,0x1c, |
4146 | | 0x5a,0x42,0x2b,0xd1,0x5a,0x64,0x41,0x77,0xe8,0x0d,0xfd,0x60,0x80,0x18,0x08,0x13, |
4147 | | 0x61,0xec,0x99,0xf4,0x0b,0x98,0x03,0x4f,0xc3,0x3c,0x98,0x0f,0xab,0xe1,0x15,0x78, |
4148 | | 0x55,0xac,0x81,0xb5,0xb0,0x01,0xde,0x84,0xf7,0xe1,0x0b,0x38,0x04,0x3f,0x9a,0x17, |
4149 | | 0x41,0x8b,0xf8,0x9c,0xf3,0xa1,0x8a,0x88,0x83,0x20,0x34,0x85,0x2c,0x18,0x08,0xe3, |
4150 | | 0x60,0x3c,0x4c,0x84,0x79,0xf0,0x0a,0xec,0x80,0x7f,0x99,0x17,0x90,0x8a,0xba,0xf8, |
4151 | | 0x84,0x5f,0x84,0x41,0x2d,0xa8,0x0d,0x4d,0xa1,0x07,0x0c,0x80,0x81,0x62,0x10,0x0c, |
4152 | | 0x86,0x21,0x30,0x14,0x86,0x89,0xeb,0x61,0x1c,0x8c,0x17,0x13,0x60,0x2e,0xcc,0x83, |
4153 | | 0x05,0xb0,0x10,0x9e,0x87,0xc5,0xf0,0x02,0x2c,0xd1,0x3d,0xe9,0xd5,0x62,0x13,0xec, |
4154 | | 0x85,0x43,0x70,0xd4,0xe4,0xad,0x18,0xf9,0x81,0x30,0xa8,0xac,0xfb,0xd5,0xd5,0xa1, |
4155 | | 0x86,0x88,0x81,0x24,0x48,0x81,0x86,0xd0,0x44,0x04,0xa1,0x29,0x64,0x88,0x2c,0x18, |
4156 | | 0x0c,0x43,0xc4,0x70,0x31,0x16,0xc6,0xc1,0x78,0x31,0x01,0x16,0xc0,0x42,0x58,0x04, |
4157 | | 0xcf,0xc3,0x72,0x58,0x01,0x2b,0x61,0x15,0xbc,0x02,0xaf,0xc1,0xeb,0xf0,0x86,0x78, |
4158 | | 0x53,0x6c,0x82,0xf7,0xe1,0x03,0x91,0x2b,0xcc,0xcb,0xb6,0xc5,0xa0,0x38,0x54,0x87, |
4159 | | 0x1a,0x10,0x0b,0x35,0x21,0x1e,0x12,0x20,0x11,0x92,0x44,0xb2,0x48,0x81,0x5a,0xd0, |
4160 | | 0x40,0x34,0x84,0x34,0x68,0x24,0xc6,0xc2,0x8d,0x30,0x59,0xdc,0x0c,0xb7,0xc1,0x14, |
4161 | | 0x78,0x10,0x1e,0x86,0x59,0x30,0x0f,0x3e,0x82,0xed,0x62,0x07,0xec,0x84,0x5d,0xb0, |
4162 | | 0x0f,0x0e,0xc1,0x51,0xf3,0x42,0x70,0x71,0xfa,0x01,0xf8,0x21,0x0c,0x02,0x50,0x18, |
4163 | | 0x8a,0x40,0x51,0x28,0x0e,0x55,0xa1,0x1a,0xc4,0x41,0x02,0x24,0x42,0x32,0xa4,0x42, |
4164 | | 0x5d,0xa8,0x07,0xf5,0x85,0x79,0xae,0xa0,0x21,0xa4,0x89,0x46,0xd0,0x04,0x32,0xa0, |
4165 | | 0x99,0x9e,0x39,0x68,0x09,0x59,0xa2,0xa3,0xb8,0x1c,0xb2,0xa1,0x2b,0x74,0x83,0x1e, |
4166 | | 0xd0,0x17,0x06,0xc2,0x50,0x18,0x0b,0x37,0xc1,0x2d,0xe2,0x76,0x91,0x03,0x8b,0x60, |
4167 | | 0xb1,0x30,0xcf,0x29,0xbc,0xa8,0xe7,0x18,0x56,0xea,0x79,0x05,0xef,0x99,0x85,0x57, |
4168 | | 0xf5,0x0c,0xc3,0x7a,0x78,0x1d,0x36,0xc2,0x1b,0xe2,0x4d,0xb1,0x49,0xbc,0x25,0x36, |
4169 | | 0x8b,0x2d,0xe2,0x63,0xd8,0x69,0x5e,0xc0,0x2b,0x41,0xbb,0x41,0x32,0xd4,0x82,0xda, |
4170 | | 0xd0,0x10,0xd2,0xa0,0x11,0xa4,0x43,0x13,0x08,0x8a,0xa6,0x22,0x03,0x9a,0x43,0x16, |
4171 | | 0x74,0x82,0x2b,0xc4,0x95,0x90,0x0d,0x63,0xcd,0xb3,0x13,0x25,0xdc,0xe7,0x2a,0x16, |
4172 | | 0xc0,0x42,0x78,0x01,0x96,0x88,0x17,0xad,0x67,0x2d,0xcc,0x73,0x16,0x2b,0x60,0x25, |
4173 | | 0xac,0x12,0xab,0xe1,0x65,0x78,0x05,0x5e,0x85,0xb5,0x62,0x13,0xbc,0x6f,0xe2,0x2f, |
4174 | | 0xe9,0x73,0x9e,0xd5,0x73,0x19,0xf3,0x61,0x01,0x2c,0x82,0x17,0xf4,0x9c,0xc6,0x52, |
4175 | | 0x58,0x06,0xcb,0xc5,0x0a,0x58,0x09,0x5b,0x61,0x1b,0xe4,0xc2,0x87,0xe6,0xc5,0xc3, |
4176 | | 0xb3,0xe9,0xcb,0x10,0x07,0x09,0x90,0x08,0x75,0xa0,0x2e,0xd4,0x83,0xfa,0xa2,0x81, |
4177 | | 0x68,0x08,0x69,0xd0,0x44,0x64,0x41,0x27,0x18,0x0b,0x4f,0xc1,0x1c,0xf1,0xb4,0x78, |
4178 | | 0x46,0x3c,0x0b,0x73,0x61,0x1e,0x2c,0x82,0xe7,0xc5,0x62,0xf1,0x82,0x58,0x09,0xaf, |
4179 | | 0xc1,0x26,0xd8,0x65,0x5e,0x6c,0x3f,0xc7,0xe7,0x9c,0x07,0x65,0x44,0x59,0x51,0x4e, |
4180 | | 0x94,0x87,0x0a,0x50,0x11,0x2a,0x41,0x65,0x51,0x05,0xaa,0x43,0x1c,0xa4,0x42,0x1a, |
4181 | | 0x34,0x35,0x2f,0x58,0x9e,0x8b,0x3f,0xd4,0x80,0x58,0xa8,0x09,0xb5,0xa0,0xb6,0x48, |
4182 | | 0x85,0x3a,0x30,0x03,0xb6,0xc3,0x0e,0xf8,0x0c,0x7e,0x84,0x88,0x52,0x3e,0x27,0x4a, |
4183 | | 0x14,0x86,0xe2,0x50,0x12,0xce,0x86,0x73,0xa1,0x66,0x29,0xf7,0xf9,0x98,0x64,0xa8, |
4184 | | 0xa5,0xe7,0x64,0xea,0x42,0x3d,0xa8,0x2f,0x1a,0x88,0x86,0x22,0x4d,0x34,0x12,0xe9, |
4185 | | 0xa2,0xb1,0xc8,0x82,0x4e,0x30,0x03,0x9e,0x84,0xa7,0x60,0x13,0xbc,0x05,0x5b,0xe0, |
4186 | | 0x6d,0x78,0x0f,0x3e,0x80,0x6d,0x90,0x0b,0xdb,0x61,0x87,0xf8,0x58,0xec,0x12,0xbb, |
4187 | | 0x45,0xde,0xc7,0x01,0xc0,0x07,0x05,0xa1,0x10,0x24,0x40,0x22,0xd4,0x86,0x54,0x51, |
4188 | | 0x47,0xd4,0x85,0x06,0x90,0x21,0xb2,0x44,0x1b,0xe8,0x00,0x1d,0xe1,0x12,0xe8,0x04, |
4189 | | 0x9d,0xe1,0x32,0xb8,0x09,0x6e,0x86,0xbb,0xe1,0x1e,0x71,0x2f,0x4c,0x87,0x07,0xc5, |
4190 | | 0x3c,0xf8,0xc6,0xe4,0xa1,0xb4,0x4b,0x17,0x91,0x2d,0xba,0xc2,0x55,0xd0,0x5d,0xf4, |
4191 | | 0x10,0x3d,0xc5,0x4a,0xd8,0x01,0x87,0xe0,0xa8,0x79,0x51,0xf6,0x7c,0xd6,0x43,0x50, |
4192 | | 0x10,0x62,0xa1,0xa6,0x88,0x83,0x14,0xa8,0x0d,0xf5,0xa1,0x81,0x68,0x28,0xd2,0x44, |
4193 | | 0x16,0x74,0x82,0xc1,0x30,0x05,0xee,0x80,0x27,0x61,0xb6,0x78,0x0a,0xe6,0xc1,0x7c, |
4194 | | 0xb1,0x00,0x16,0xc2,0x73,0x62,0x11,0x3c,0x6f,0x3e,0x94,0x50,0x86,0xfe,0x02,0x05, |
4195 | | 0x20,0x0a,0x0a,0x41,0x1c,0xc4,0x43,0x0a,0xd4,0x11,0xf5,0xa0,0x3e,0x34,0x84,0x20, |
4196 | | 0x34,0x15,0x19,0x22,0x0b,0x3a,0x41,0x17,0xe8,0x0e,0x3d,0xa1,0x17,0x5c,0x0d,0x37, |
4197 | | 0xc1,0xcd,0x70,0x3b,0xe4,0xc0,0x54,0xb8,0x13,0xee,0x82,0x69,0xe2,0x6e,0x71,0x8f, |
4198 | | 0xb8,0x57,0xcc,0x80,0xd9,0x30,0x0f,0xb6,0xc2,0xfb,0xe2,0x03,0xd8,0x06,0x3b,0xe0, |
4199 | | 0x33,0x38,0x24,0x0e,0x8b,0x1d,0x65,0x59,0x5f,0xc1,0x11,0xf8,0x0a,0xbe,0x86,0x7f, |
4200 | | 0x99,0x0f,0x41,0x94,0xa3,0x2f,0x81,0x5f,0x84,0x89,0x70,0x28,0x0a,0x67,0x41,0x22, |
4201 | | 0x24,0x41,0x32,0xa4,0x40,0x1d,0x68,0x00,0x0d,0x21,0x4d,0x34,0x12,0xe9,0x22,0x0b, |
4202 | | 0x3a,0xc1,0xa5,0x62,0x9e,0x30,0x1f,0x9d,0x98,0x6e,0x5e,0x50,0xbe,0x80,0xf5,0x0d, |
4203 | | 0x0c,0x83,0xeb,0x61,0x2c,0x34,0xae,0xc4,0x7e,0x70,0x63,0x65,0xea,0xa5,0x26,0xf9, |
4204 | | 0xcf,0x7b,0x41,0x98,0x7e,0x90,0x44,0x1a,0xa2,0x11,0x34,0x85,0x0c,0x68,0x0f,0x5d, |
4205 | | 0xe0,0x5b,0xf3,0x01,0x86,0x26,0xf8,0x9b,0x17,0x72,0xb3,0x99,0x6f,0xb2,0xdd,0xe7, |
4206 | | 0xdc,0xcc,0x33,0x6d,0xd5,0xa0,0x06,0xc4,0x40,0x4d,0x88,0x83,0x54,0xf3,0xe2,0x6a, |
4207 | | 0x2f,0xfa,0xd4,0xd5,0xc4,0x09,0x57,0x40,0x17,0xe8,0x0d,0x03,0x61,0x39,0xac,0x84, |
4208 | | 0xd7,0x60,0x13,0x1c,0x80,0x43,0xf0,0x95,0xf9,0x90,0x40,0x1f,0xe2,0x81,0x38,0x48, |
4209 | | 0x81,0x34,0x68,0x0c,0x59,0xd0,0x09,0xba,0xc1,0x08,0xb8,0x16,0xa6,0x98,0xed,0xfd, |
4210 | | 0xa8,0x0f,0x68,0xac,0xe7,0xe4,0xfa,0x40,0x5f,0x18,0x08,0xa3,0x20,0xad,0x3f,0xe5, |
4211 | | 0x87,0x19,0xf0,0x02,0xbc,0x04,0x5b,0xcc,0x07,0x09,0x06,0x70,0x9c,0x82,0xd6,0x22, |
4212 | | 0x4b,0xb4,0x81,0x49,0x30,0x05,0xee,0x80,0x3b,0xe1,0x61,0xd8,0x01,0x1f,0xc3,0x2e, |
4213 | | 0xb1,0x5b,0x1c,0x82,0xc3,0xf0,0x25,0x1c,0x81,0xaf,0xe0,0x5f,0xe6,0xc5,0xd8,0x81, |
4214 | | 0xf4,0x99,0x5b,0x99,0x1f,0xa1,0xfc,0x6d,0xd4,0x3f,0x7c,0x09,0xce,0xed,0xf4,0xc7, |
4215 | | 0xa9,0xe4,0x07,0x36,0xc3,0xa1,0xb9,0xec,0x07,0x5f,0xc3,0x77,0xf0,0x3d,0xfc,0x60, |
4216 | | 0x3e,0x84,0x30,0x8f,0x75,0xc9,0x7c,0xe6,0x1e,0x91,0x05,0x17,0x43,0x7b,0x71,0x15, |
4217 | | 0xf4,0x82,0x81,0xf0,0xdd,0x02,0xf7,0x01,0xbe,0xab,0x61,0x20,0x8c,0x81,0xb1,0x30, |
4218 | | 0x19,0x72,0x60,0x3a,0x3c,0x08,0x0f,0xc1,0xa1,0xd7,0x99,0x0f,0xc0,0x7c,0x04,0x24, |
4219 | | 0x06,0xe2,0xa0,0x29,0x54,0x79,0x8b,0xf4,0xa0,0x3b,0xf4,0x80,0x9e,0xd0,0x1b,0xfa, |
4220 | | 0xc1,0x60,0xb8,0x06,0xc6,0xc3,0x44,0xb8,0x05,0x9e,0x82,0x67,0x20,0x7d,0x33,0xc7, |
4221 | | 0x3b,0xc8,0x82,0x8b,0xa1,0x33,0x5c,0x06,0x57,0x8a,0xb1,0x30,0xce,0xbc,0x60,0xfd, |
4222 | | 0xb6,0xcf,0x69,0x07,0x1d,0xe0,0x01,0x78,0x08,0x1e,0x86,0x47,0xc4,0xe3,0xf0,0x04, |
4223 | | 0xcc,0x86,0xa7,0xe1,0x59,0x58,0x02,0x2f,0x89,0x65,0xf0,0x32,0xbc,0x0a,0x81,0x77, |
4224 | | 0x7c,0x4e,0x24,0x14,0x84,0x33,0xa0,0x04,0x9c,0x0d,0xe7,0x43,0x59,0x48,0x85,0xba, |
4225 | | 0xd0,0x00,0xd2,0xa0,0x09,0x34,0x15,0xcd,0x21,0x0b,0x2e,0x86,0x27,0xde,0x65,0x2d, |
4226 | | 0x09,0x2b,0x61,0x35,0x7c,0x00,0xb9,0xf0,0x2d,0x1c,0x83,0x12,0xef,0x11,0x2f,0x24, |
4227 | | 0x41,0x0a,0xb4,0x82,0x2c,0xe8,0x0f,0x03,0x61,0x32,0xdc,0x0c,0xb3,0xe0,0x29,0x58, |
4228 | | 0x0d,0xaf,0xc0,0x06,0x78,0x03,0x7e,0x34,0x2f,0xc6,0x7e,0xc0,0xbe,0x50,0x17,0xfa, |
4229 | | 0xc2,0x30,0x71,0x83,0xb8,0x1f,0x1e,0x86,0x99,0x30,0xd7,0xbc,0x60,0xba,0x9d,0x79, |
4230 | | 0x11,0x0a,0x8a,0x42,0x70,0x3d,0x8c,0x85,0x71,0x90,0x03,0x77,0xc3,0x46,0xf8,0xd1, |
4231 | | 0xbc,0x40,0xbb,0x83,0xf9,0x14,0x0a,0xc0,0xb9,0x50,0x1a,0x2a,0x40,0x34,0x5c,0x00, |
4232 | | 0x95,0xa1,0x1a,0xc4,0x41,0x3f,0x98,0x22,0xcc,0xcb,0x93,0x35,0x20,0x0e,0x52,0xa0, |
4233 | | 0x16,0xd4,0x87,0x34,0xc8,0x84,0x56,0x22,0x67,0x27,0xed,0x0c,0xcf,0x8a,0x95,0xb0, |
4234 | | 0x1f,0x3e,0x87,0x83,0x70,0x08,0x8e,0xc2,0xa6,0xdd,0xac,0xbb,0x61,0xbf,0xf8,0x1c, |
4235 | | 0x0e,0xc2,0x21,0x38,0x0a,0x9b,0x3e,0x61,0x9c,0xc3,0x17,0x70,0x10,0x0e,0x89,0xc3, |
4236 | | 0xf0,0x2d,0xac,0xdc,0xc3,0x7a,0x1e,0x76,0xc0,0x4e,0xd8,0x25,0x76,0xc3,0x27,0xb0, |
4237 | | 0x47,0x7c,0x0a,0x07,0xe0,0x0b,0x38,0x08,0x87,0xe0,0x2b,0xf8,0x5a,0xfc,0x20,0x7e, |
4238 | | 0x14,0x3b,0x3e,0x65,0x3f,0xd8,0x0b,0xfb,0xe1,0x00,0x7c,0x01,0x87,0xe0,0x07,0xf3, |
4239 | | 0x41,0x87,0xbd,0xb4,0x19,0x6c,0x82,0x77,0xcd,0x87,0x6d,0x3e,0x63,0x2e,0x81,0x26, |
4240 | | 0xd0,0x1c,0x5a,0x88,0x2c,0xe8,0x64,0x3e,0x94,0xf0,0x05,0xf3,0xf7,0xff,0xb5,0x77, |
4241 | | 0x1e,0xf0,0x55,0x97,0x67,0x1b,0x3e,0xe7,0xe4,0xe4,0x70,0x92,0x20,0xe0,0xc0,0x2d, |
4242 | | 0x6e,0xd9,0x10,0x99,0x0a,0x08,0x41,0x51,0x1c,0x1f,0x05,0xdc,0x48,0x15,0xc4,0x8d, |
4243 | | 0x03,0x04,0xdc,0x16,0x11,0x44,0xc5,0x89,0x6d,0xb5,0x9f,0xa3,0x8a,0xf5,0x73,0xa0, |
4244 | | 0x82,0x51,0xd0,0x82,0x20,0x04,0x71,0xcb,0x12,0x5c,0x75,0x31,0xac,0x7e,0x28,0x22, |
4245 | | 0xcb,0x09,0x6a,0xbe,0xfb,0x3d,0xff,0xeb,0x21,0x0f,0x7f,0x73,0x04,0xac,0xfd,0xd5, |
4246 | | 0xfe,0xbe,0x26,0xbd,0x01,0x43,0x20,0x83,0x24,0x7d,0xf2,0x5e,0xcf,0x75,0xbf,0x4a, |
4247 | | 0xa1,0xb2,0xab,0xb2,0xbb,0xb2,0x87,0xb2,0x17,0xa9,0x4f,0x1a,0x2a,0x2d,0x94,0x56, |
4248 | | 0x4a,0x5b,0x65,0x7f,0xd2,0x9e,0x1c,0x48,0xba,0x92,0xc3,0xc8,0x11,0xa4,0x9b,0xd2, |
4249 | | 0x5d,0xe9,0xa9,0x1c,0xa9,0x1c,0x4d,0x8e,0x23,0xbd,0x48,0x6f,0x72,0x22,0xe9,0x43, |
4250 | | 0x4e,0x56,0xfa,0x29,0xa7,0x92,0x33,0x94,0xfe,0xca,0x39,0xca,0x20,0x65,0x88,0x72, |
4251 | | 0x91,0x72,0x89,0x72,0xb9,0x32,0x94,0x0c,0x53,0x46,0x29,0xd7,0x2b,0x77,0x2a,0xf7, |
4252 | | 0x2a,0xf7,0x29,0xf7,0x2b,0x63,0x95,0x47,0x94,0x29,0xca,0xca,0x75,0xfa,0x77,0x0d, |
4253 | | 0xe2,0x76,0x22,0x95,0x58,0xf8,0x40,0x2a,0x91,0x78,0x30,0x95,0xa8,0x37,0x29,0x95, |
4254 | | 0xd8,0x4d,0x19,0x37,0x27,0x95,0x28,0x57,0x16,0x2d,0x4b,0x25,0x56,0x2a,0x27,0x86, |
4255 | | 0x85,0xe0,0x6f,0x52,0x89,0x5d,0xd6,0x46,0x8b,0xc1,0x87,0x6f,0x5d,0xa0,0xef,0x8d, |
4256 | | 0x0a,0x12,0x97,0xb4,0x0a,0x32,0x62,0x41,0xa2,0xd3,0x77,0x05,0xb9,0x05,0x9b,0x15, |
4257 | | 0x8a,0xed,0x37,0xe7,0xdb,0x6b,0xfe,0x57,0xed,0x33,0xff,0xdc,0x3d,0xe6,0x4d,0xdd, |
4258 | | 0x5f,0xde,0xd4,0xbd,0xe5,0xf8,0x3e,0x72,0xbe,0x3d,0x64,0xdb,0x3b,0x8e,0xef,0x1b, |
4259 | | 0xdb,0x7e,0xb1,0xed,0x13,0xe7,0xdb,0x23,0xb6,0xfd,0x61,0xdb,0x1b,0xb6,0x7d,0x61, |
4260 | | 0xdb,0x13,0x8e,0xef,0x07,0xdb,0x5e,0xb0,0xed,0x03,0xdb,0x1e,0xb0,0xed,0xff,0xda, |
4261 | | 0xde,0x6f,0xbe,0x7d,0xdf,0xf8,0x9e,0xaf,0xed,0xf3,0xda,0xde,0xae,0xed,0xe3,0xda, |
4262 | | 0x1e,0x6e,0x7c,0xef,0x76,0x73,0xf7,0x6c,0x6d,0xbf,0xd6,0xf6,0x66,0xe3,0xfb,0xb2, |
4263 | | 0xf1,0xfd,0xd8,0x9f,0xbb,0x07,0x1b,0xdf,0x6b,0xb5,0x3d,0xd6,0xcd,0xdd,0x57,0xb5, |
4264 | | 0x3d,0xd5,0xf8,0xde,0xa9,0xed,0x99,0x6e,0xee,0x3e,0xa9,0xed,0x91,0xc6,0xf7,0x3f, |
4265 | | 0x6d,0xdf,0xf3,0x97,0xde,0xf3,0xb4,0xbd,0xcd,0x8d,0xed,0x63,0xda,0x1e,0x66,0xbe, |
4266 | | 0xfd,0x4a,0xdb,0xa7,0xdc,0xd4,0xfd,0x49,0xdb,0x9b,0x8c,0xef,0x3d,0xda,0x9e,0x63, |
4267 | | 0xbe,0x7d,0x46,0xdb,0x63,0x8c,0xef,0x27,0xda,0x5e,0xa2,0xed,0x21,0x6e,0xea,0xde, |
4268 | | 0xa1,0xed,0x0f,0xda,0xde,0x60,0x7c,0x5f,0x70,0x73,0xf7,0x03,0x6d,0x2f,0x30,0xdf, |
4269 | | 0x3e,0x60,0x7c,0xff,0x2f,0xbe,0xcf,0x67,0xfb,0x7a,0xb6,0x97,0x67,0x7b,0x75,0xb6, |
4270 | | 0x4f,0x67,0xfb,0x73,0xb6,0x37,0x67,0xfb,0x72,0xb6,0x27,0x67,0xfb,0x71,0xb6,0xf7, |
4271 | | 0xf6,0xef,0xb6,0xd7,0xf6,0x4b,0xef,0xb1,0xd9,0xde,0x9a,0xed,0xa9,0xc5,0xf7,0xd3, |
4272 | | 0x6c,0x2f,0x2d,0xbe,0x5f,0xb6,0xb9,0x7b,0x63,0xf9,0xf6,0xc5,0x36,0xb6,0xe7,0x65, |
4273 | | 0x7b,0x5d,0xb6,0xbf,0x65,0xfb,0x54,0xb6,0x2f,0x65,0xfb,0x4e,0xb6,0xcf,0x64,0xfb, |
4274 | | 0x49,0xb6,0x97,0x64,0x7b,0x45,0xb6,0x2f,0xb4,0xa9,0x7b,0x42,0xb6,0x07,0x64,0xfb, |
4275 | | 0x3f,0xb6,0xf7,0xf3,0x73,0xf7,0x7c,0x7e,0xad,0xfb,0x3d,0xf9,0xf6,0x78,0xfe,0xdd, |
4276 | | 0xf7,0x75,0x36,0x77,0x4f,0xe7,0x97,0xda,0xcf,0xd9,0xd8,0x5e,0xce,0xa6,0xee,0xe1, |
4277 | | 0x6c,0x6c,0xff,0xe6,0x5f,0xb5,0x77,0x93,0x6f,0xdf,0x26,0xdf,0x7e,0x4d,0x7c,0xaf, |
4278 | | 0xe6,0x5f,0xb5,0x4f,0x63,0x7b,0x34,0xb6,0x3f,0x63,0x7b,0x33,0xb6,0x17,0x63,0xfb, |
4279 | | 0x30,0xf9,0xf6,0x5d,0x6c,0xbf,0xc5,0xf6,0x5a,0x6c,0x8f,0xc5,0xf6,0x56,0x6c,0x0f, |
4280 | | 0xc5,0xf6,0x4f,0xe2,0x7b,0x27,0xf1,0x7d,0x13,0xdb,0x23,0xb1,0xfd,0x91,0x8d,0xed, |
4281 | | 0x89,0xd8,0x3e,0x88,0xed,0x81,0xd8,0xfe,0x87,0xed,0x7d,0xd8,0xbe,0xc7,0xc6,0xf6, |
4282 | | 0x3c,0xe2,0xfb,0x1c,0xff,0xec,0xfd,0x8d,0x7f,0x74,0xff,0xe2,0x9f,0xb5,0x77,0x11, |
4283 | | 0xdf,0xab,0xb0,0x7d,0x0a,0xdb,0xa3,0xf8,0xb5,0xec,0x4f,0xc4,0xf7,0x26,0x36,0x77, |
4284 | | 0x5f,0x62,0x73,0xf7,0x24,0xfe,0xb3,0x1f,0x51,0xfd,0x7e,0x44,0xbe,0x3d,0x88,0x8d, |
4285 | | 0xed,0x3d,0xfc,0xa3,0xfb,0x0e,0x1b,0xdb,0x6b,0xc8,0xb7,0xcf,0xb0,0xb1,0x3d,0x06, |
4286 | | 0xdb,0x5f,0xc8,0xb7,0xb7,0x60,0xfb,0x0a,0xf1,0x3d,0x05,0xdb,0x47,0xb0,0xbd,0x03, |
4287 | | 0xdb,0x37,0xb0,0xfd,0x02,0xdb,0x1b,0xb0,0x3d,0x01,0xdb,0x03,0x88,0xf3,0x7f,0xe3, |
4288 | | 0xfe,0xc6,0xf9,0x8d,0xe7,0x6f,0x8c,0xd7,0x1b,0x77,0xdf,0x5c,0xde,0xbe,0xb9,0xfc, |
4289 | | 0xdc,0xb8,0xb9,0xf1,0x70,0xe3,0xe0,0x9b,0xca,0xbb,0x8d,0x53,0x1b,0x9f,0x36,0x2e, |
4290 | | 0x6d,0x9c,0x39,0xce,0x95,0xe3,0x5c,0xd8,0x78,0xb0,0xf1,0x5d,0xe3,0xba,0xc6,0x69, |
4291 | | 0x8d,0xcf,0x1a,0x67,0x35,0xae,0x1a,0xe7,0xa2,0xc6,0x3d,0x37,0x95,0x77,0x1a,0xc7, |
4292 | | 0x34,0x7e,0x19,0xe7,0x94,0x71,0xfe,0x68,0xdc,0xd1,0x78,0xa3,0xf1,0x45,0xe3,0x89, |
4293 | | 0xc6,0x0d,0xf3,0xf1,0x41,0xe3,0x7d,0x71,0xce,0x67,0xfc,0xce,0xb8,0x5d,0x3e,0xfe, |
4294 | | 0x66,0x7c,0x2d,0x1f,0x4f,0x33,0x3e,0x96,0x8f,0x8b,0xc5,0x39,0x98,0xf1,0xae,0x38, |
4295 | | 0xe7,0xfa,0x47,0x39,0x95,0xf1,0xa9,0x7c,0x5c,0x2a,0xce,0x9d,0x8c,0x37,0x19,0x67, |
4296 | | 0x32,0xbe,0x64,0x5c,0x69,0x53,0x79,0xd2,0xc6,0x38,0x92,0xf1,0xa3,0x7c,0xbc,0xe8, |
4297 | | 0xd7,0xce,0x87,0xfe,0xbf,0xf1,0x99,0xcd,0xe5,0x2c,0xc6,0x4f,0x8c,0x9b,0x18,0x2f, |
4298 | | 0x89,0x73,0x12,0xe3,0x23,0x71,0x1e,0x62,0xfc,0xc3,0xb8,0x47,0x9c,0x77,0x18,0xe7, |
4299 | | 0x30,0xbe,0x61,0x5c,0xe3,0xe7,0xf2,0x0c,0xe3,0x18,0xc6,0x2f,0xfe,0xc3,0x2d,0x22, |
4300 | | 0x6e,0xf1,0x8b,0xf1,0x8a,0xd0,0x0d,0xac,0x14,0x2b,0xa6,0x9f,0x6f,0xa1,0xd4,0x8a, |
4301 | | 0x8e,0x4a,0x42,0x05,0x66,0x42,0xdf,0xfe,0x27,0xc2,0xb7,0xd8,0x7b,0x2a,0xfb,0x28, |
4302 | | 0x8d,0xa3,0x6f,0xb7,0xc3,0xb7,0xd2,0x89,0x66,0x4a,0xe8,0x74,0x69,0xa7,0xb4,0xa7, |
4303 | | 0xd7,0xa5,0x37,0xdc,0xe3,0x32,0xe5,0x0a,0x65,0xa4,0x72,0xb5,0xa2,0x6f,0x2d,0x13, |
4304 | | 0xf7,0x2a,0x7f,0x51,0x1e,0x80,0x87,0x84,0x6f,0x09,0xc6,0x29,0xe3,0x95,0x72,0xe5, |
4305 | | 0x09,0x65,0x22,0x8c,0xe4,0x29,0x65,0x32,0x9c,0x64,0x0a,0xac,0xe4,0x2d,0x58,0xc9, |
4306 | | 0xd7,0xb0,0x92,0xc9,0x7a,0xd3,0xa6,0x28,0xcf,0x2a,0xf3,0x94,0xf9,0xb0,0x8f,0x8f, |
4307 | | 0xe0,0x1d,0x2b,0xe8,0x70,0x19,0xe8,0x78,0x47,0xe0,0x1c,0x43,0xe1,0x1b,0x57,0xb9, |
4308 | | 0x9e,0x96,0x6b,0x1d,0xdb,0x08,0x5c,0xe3,0x2b,0xb8,0xc6,0x08,0xb8,0xc6,0xbe,0xf0, |
4309 | | 0x8c,0xeb,0xe0,0x18,0x37,0x2a,0x37,0xd3,0xc1,0x32,0x8d,0xfe,0x95,0x0a,0x3a,0x58, |
4310 | | 0x66,0xd2,0xc1,0xf2,0x02,0x1d,0x2c,0xf3,0x60,0x1d,0x89,0x8c,0xfe,0xa7,0x64,0x95, |
4311 | | 0x22,0xa5,0x44,0xa9,0xa9,0x6c,0xa1,0xd4,0xca,0x44,0xbd,0x2c,0x3b,0xd1,0xbf,0x12, |
4312 | | 0xba,0x57,0xfa,0x2b,0x67,0x2b,0xe7,0xba,0xde,0x95,0xd0,0xb5,0xf2,0xbe,0xf2,0x01, |
4313 | | 0x7d,0x2b,0x1f,0xd1,0xb3,0xf2,0x09,0x3d,0x2b,0x9f,0xd3,0xaf,0x12,0x98,0x48,0x6d, |
4314 | | 0xd7,0xa3,0x52,0x0a,0x07,0x79,0xc0,0x75,0xa6,0x2c,0x83,0x81,0x7c,0xe5,0xfa,0x51, |
4315 | | 0x7e,0xa8,0x11,0xf5,0xa2,0x58,0x1f,0x8a,0xf5,0xa0,0x58,0xff,0x49,0x29,0x1c,0x24, |
4316 | | 0x74,0x9f,0x9c,0x04,0x0b,0x09,0x1c,0x64,0x34,0x7d,0x27,0x63,0xe8,0x37,0x59,0x42, |
4317 | | 0xbf,0x49,0x81,0xeb,0x32,0xb1,0x0e,0x93,0xce,0x74,0x96,0x58,0x57,0x49,0x4f,0x98, |
4318 | | 0x48,0xe8,0x25,0x39,0xd5,0x75,0x8f,0x8c,0x84,0x85,0xfc,0x01,0x06,0x62,0xec,0xc3, |
4319 | | 0xba,0x45,0x66,0xd0,0x25,0xf2,0xaa,0xeb,0x0f,0xb1,0xde,0x90,0x85,0xf4,0x85,0x84, |
4320 | | 0xae,0x90,0xd5,0xca,0x17,0xca,0x3a,0xd7,0x13,0x92,0x74,0xdd,0x20,0xb5,0x61,0x21, |
4321 | | 0x8d,0x60,0x20,0xad,0x61,0x1f,0xd6,0xfd,0xd1,0x99,0xce,0x8f,0x23,0x5c,0xcf,0x87, |
4322 | | 0xf5,0x7b,0x0c,0x84,0x87,0x84,0x3e,0x8f,0x0b,0xe9,0xf4,0xb0,0x2e,0x8f,0x9b,0x61, |
4323 | | 0x22,0x0f,0xc3,0x42,0x9e,0x74,0x7d,0x1d,0x33,0xe8,0xe7,0xb0,0x5e,0x8e,0xd9,0x8e, |
4324 | | 0x89,0x2c,0xa1,0x83,0x63,0x95,0xeb,0xdf,0xb0,0xde,0x8d,0x42,0xf8,0xc8,0xd6,0x70, |
4325 | | 0x91,0x16,0xf0,0x10,0xeb,0xd5,0xe8,0xe4,0x3a,0x34,0xba,0xd2,0x9d,0x61,0x9d,0x19, |
4326 | | 0xd6,0x95,0xd1,0x87,0x8e,0x8c,0xd3,0x5d,0x1f,0xc6,0x48,0xf8,0xc8,0xef,0xe1,0x22, |
4327 | | 0xc6,0x43,0xee,0x83,0x83,0x8c,0xa7,0xe7,0xc2,0xfa,0x2d,0x5e,0xa0,0xd7,0x62,0xb6, |
4328 | | 0xeb,0xb2,0x08,0x3d,0x16,0x6b,0x94,0x6f,0x95,0xb5,0x25,0x55,0x5d,0x16,0xd6,0x61, |
4329 | | 0x51,0x0b,0x56,0xd2,0xc8,0xf5,0x55,0x74,0xa4,0xa7,0xe2,0x10,0xfa,0x29,0x8e,0x81, |
4330 | | 0x9b,0xfc,0x16,0x5e,0xd2,0x8f,0x1e,0x8a,0x8b,0x94,0x8b,0x95,0x2b,0x5c,0x07,0xc5, |
4331 | | 0x4d,0x30,0x93,0x87,0x61,0x25,0xd6,0x31,0xf1,0x02,0xdd,0x11,0xb3,0xe8,0x8c,0x78, |
4332 | | 0x0f,0x66,0xb2,0x84,0x8e,0x88,0x55,0x7c,0xa1,0x4b,0xc1,0x4c,0xb6,0xa2,0xfb,0xe1, |
4333 | | 0x00,0xba,0x1e,0x0e,0xa1,0xe3,0xa1,0x9b,0xe3,0x26,0xfd,0xe8,0x6f,0xb0,0xbe,0x86, |
4334 | | 0x91,0xf0,0x92,0x09,0x8e,0x91,0x58,0x27,0xc3,0x7c,0xd7,0xc3,0xf0,0x31,0xfd,0x0b, |
4335 | | 0x49,0xd7,0xb9,0x10,0xfa,0x16,0x3a,0xc1,0x4f,0x42,0xc7,0x42,0x77,0xd8,0x89,0x31, |
4336 | | 0x93,0x1b,0x1c,0x27,0xb1,0xfe,0x84,0x89,0x8e,0x91,0x58,0x57,0xc2,0x3c,0x18,0x89, |
4337 | | 0x75,0x23,0xec,0x48,0x1f,0x42,0x1b,0xfa,0x10,0xf6,0xa3,0x0f,0xa1,0x1d,0x9d,0x08, |
4338 | | 0x87,0xd1,0x81,0x60,0xdd,0x07,0x23,0xe9,0x3e,0xb8,0x96,0xce,0x83,0xd0,0x77,0x30, |
4339 | | 0x8d,0xae,0x83,0x17,0x95,0x39,0xb0,0x95,0xa6,0xae,0xdf,0xc0,0x7a,0x0d,0xda,0xd3, |
4340 | | 0x67,0xd0,0x89,0xbe,0x82,0x13,0xe8,0x29,0x38,0x99,0xfe,0x81,0x0b,0x5c,0xe7,0xc0, |
4341 | | 0x48,0xba,0x06,0xac,0x63,0x20,0x74,0x08,0xdc,0xed,0x18,0x4b,0xe0,0x2b,0x87,0xc3, |
4342 | | 0x4f,0x8c,0x9b,0xf4,0x85,0x97,0x8c,0x86,0x93,0x4c,0x72,0x6c,0xe4,0x25,0x98,0xc8, |
4343 | | 0x56,0xb0,0x90,0xe0,0xf7,0xf7,0x85,0x87,0x8c,0x86,0x87,0x04,0x16,0x92,0xd8,0x26, |
4344 | | 0x62,0x21,0xc3,0x60,0x20,0x77,0xc2,0x40,0x12,0x38,0xfb,0xe6,0xea,0xb7,0x70,0x7e, |
4345 | | 0xfe,0x91,0x70,0x8f,0xf3,0xf0,0xf1,0x87,0xe1,0xe1,0x9b,0x7f,0x3f,0xcd,0x39,0xf7, |
4346 | | 0xc1,0xb7,0x7f,0x5d,0x79,0xd7,0x79,0xf6,0xc1,0xb1,0x5f,0xa9,0x24,0xb6,0x8f,0x3c, |
4347 | | 0xfb,0x5a,0xce,0xb1,0xdf,0x0d,0x26,0x32,0x12,0x16,0x32,0xd6,0x71,0x90,0x04,0xbe, |
4348 | | 0xfc,0x9e,0x78,0xf2,0x0d,0xf1,0xe3,0xcd,0x8b,0x0f,0x4e,0x7c,0x99,0xd2,0x05,0x2f, |
4349 | | 0x7e,0x20,0x7c,0xa4,0x1c,0xff,0xfd,0x03,0xf8,0xc8,0x76,0xf8,0xee,0xc1,0x73,0xaf, |
4350 | | 0xe7,0xbc,0xf6,0xe3,0x9d,0xcb,0x6e,0x0e,0xfb,0x69,0xb8,0xeb,0x83,0x9d,0xaf,0x1e, |
4351 | | 0x5c,0xf5,0x31,0x38,0xea,0x09,0x7c,0xf4,0x56,0x31,0xff,0xfc,0x37,0xb8,0xe4,0x43, |
4352 | | 0x70,0xc9,0x87,0xe3,0x8c,0x3f,0x80,0x2b,0x6e,0x8e,0xf8,0x78,0xe7,0x81,0x2f,0xc5, |
4353 | | 0xff,0x5e,0xee,0x9c,0xef,0xe0,0x7b,0x7f,0xb7,0x53,0xe4,0x77,0xb7,0xc2,0xeb,0x6e, |
4354 | | 0x0f,0x9f,0x19,0x0d,0x7f,0x09,0x8e,0xf6,0x02,0x1c,0x6d,0x73,0xb3,0x3f,0x71,0x3e, |
4355 | | 0xb6,0x79,0xd8,0xdf,0x38,0x16,0x53,0x01,0x63,0xd9,0x1e,0xb6,0x72,0x28,0x4c,0xa5, |
4356 | | 0x97,0xe3,0x28,0x7d,0xe0,0x27,0x81,0x9d,0x3c,0x03,0x37,0x99,0x0e,0x3b,0x09,0xdc, |
4357 | | 0x64,0x36,0xdc,0x24,0x30,0x93,0xf7,0x61,0x26,0xcb,0x61,0x26,0x81,0x97,0x7c,0xcf, |
4358 | | 0x70,0x54,0xa2,0xd4,0x52,0x6a,0x2b,0x75,0x94,0x06,0x4a,0x43,0xa5,0x91,0xd2,0x58, |
4359 | | 0x69,0xa2,0x34,0x55,0x9a,0x29,0xcd,0x95,0x52,0xa5,0xb5,0xd2,0x45,0x39,0x58,0xe9, |
4360 | | 0xa3,0xf4,0x55,0x4e,0x57,0xce,0x50,0xce,0x54,0xce,0x52,0xfa,0x2b,0x03,0xe1,0x31, |
4361 | | 0x43,0x94,0x4b,0x95,0xcb,0xe1,0x32,0xc3,0x94,0xeb,0x94,0x1b,0x94,0xd1,0xca,0x18, |
4362 | | 0x5c,0xeb,0x04,0x9c,0xa6,0x00,0x4e,0x93,0x85,0xd5,0x6c,0x03,0xa7,0xd9,0x16,0x46, |
4363 | | 0x53,0x0f,0x3e,0xb3,0x37,0x7c,0xa6,0x3e,0x7c,0xa6,0x21,0x8c,0xc6,0xd8,0x4c,0x3b, |
4364 | | 0x58,0x4c,0x19,0x2c,0xe6,0x70,0x38,0x4c,0x0f,0x58,0xcc,0x28,0x65,0xb4,0xb2,0xd5, |
4365 | | 0x1e,0xfa,0xff,0x23,0x65,0x1b,0xa5,0x8d,0x06,0xc5,0xcb,0x94,0x5b,0x95,0xdb,0x94, |
4366 | | 0xb2,0xbd,0xf4,0xbc,0xca,0xb5,0xca,0x5d,0xca,0xa7,0xca,0xa3,0x1a,0x24,0xc7,0x85, |
4367 | | 0x61,0xb2,0x81,0xd2,0x50,0xff,0xbf,0xc9,0x50,0xf9,0x11,0xcc,0x66,0x05,0xcc,0xe6, |
4368 | | 0x5b,0x06,0xcd,0xfa,0x8e,0xd3,0x0c,0x70,0x0e,0xf5,0x18,0xd8,0x4c,0x39,0x4c,0xa6, |
4369 | | 0x02,0x16,0x33,0x0f,0x06,0xb3,0x88,0x21,0xb5,0xaf,0x32,0x4c,0xb9,0x33,0x0c,0xac, |
4370 | | 0xcd,0xf5,0xf9,0xd9,0x3c,0x1a,0x5c,0x93,0xf0,0x99,0x2c,0x4c,0xa6,0x11,0x8e,0x74, |
4371 | | 0x29,0x6c,0xa6,0x0d,0x6c,0xe6,0x00,0x58,0xcc,0xed,0xb0,0x98,0xc0,0x61,0xc6,0xc0, |
4372 | | 0x5f,0xcc,0x7b,0x2e,0x84,0xb7,0x8c,0x56,0x2a,0x94,0x15,0xf0,0x96,0x5d,0x5a,0xe8, |
4373 | | 0xc3,0x44,0xe9,0xa1,0xf4,0x55,0x2e,0x57,0xae,0x50,0x1e,0x57,0x2a,0x94,0x59,0xca, |
4374 | | 0x3c,0xe5,0xa2,0x96,0x7a,0xbf,0x29,0x1f,0x28,0x8b,0x94,0xca,0x96,0x11,0xa7,0xa9, |
4375 | | 0x80,0xd3,0x8c,0x86,0xcb,0x6c,0x01,0x7f,0x29,0xc3,0x69,0x1e,0x8c,0xd7,0x3c,0x14, |
4376 | | 0xde,0x72,0x37,0x9c,0x25,0x38,0xcb,0xab,0xc3,0xa0,0x0d,0x5f,0x09,0x1c,0x65,0x94, |
4377 | | 0xe3,0x25,0xe6,0x13,0x9b,0x47,0x6c,0xfe,0xf0,0xde,0xb8,0xc2,0x0d,0x70,0x85,0x4b, |
4378 | | 0x95,0xfd,0x60,0x23,0x43,0x70,0x86,0x83,0x1f,0x3c,0x07,0x2f,0x78,0xb5,0x73,0x7f, |
4379 | | 0x83,0xef,0xdb,0x0c,0xcf,0x37,0x38,0xbe,0x7d,0x70,0x7b,0x47,0x38,0x8f,0xf7,0x29, |
4380 | | 0xfc,0xdd,0xa9,0x78,0xbb,0x81,0x93,0x7c,0xe0,0xfc,0xdc,0x04,0xfe,0x6d,0x73,0xbc, |
4381 | | 0xdb,0x96,0xf8,0xb6,0x65,0xce,0xb1,0xfd,0x2f,0xe7,0xd5,0xfe,0xd6,0xb9,0xb2,0xe5, |
4382 | | 0xce,0x8b,0x7d,0x12,0x1f,0x76,0x32,0x1e,0x6c,0x85,0x73,0x5f,0xdf,0xc5,0x6d,0xfd, |
4383 | | 0xdc,0x79,0xab,0x45,0xf0,0x8e,0xdd,0xe0,0x1c,0x81,0x71,0xf4,0x87,0x65,0x0c,0x74, |
4384 | | 0xbe,0xa9,0x79,0xa6,0xe6,0x95,0x06,0xa6,0x51,0x0e,0xcb,0x08,0xdf,0x9c,0x0c,0x84, |
4385 | | 0x5f,0x6c,0xed,0x9c,0xd1,0xc0,0x2d,0x1a,0xc2,0x2d,0xf6,0x73,0xac,0xe2,0x20,0x18, |
4386 | | 0x45,0x0f,0x65,0x26,0x9c,0xa2,0x23,0x9c,0x62,0x34,0x9c,0xe2,0x25,0x38,0xc5,0xf7, |
4387 | | 0xf8,0xa1,0x75,0xf0,0x43,0x4b,0x95,0x1e,0x4a,0x4f,0xe5,0x48,0xe5,0x68,0xe5,0x18, |
4388 | | 0xe5,0x58,0xa5,0x8f,0xd2,0x57,0xe9,0xa7,0x9c,0xaa,0x9c,0xa9,0x9c,0xa5,0x9c,0x8d, |
4389 | | 0x43,0x1a,0x38,0x47,0xa5,0x92,0xac,0xd4,0xc7,0x80,0x92,0x51,0x4a,0x94,0x9a,0xca, |
4390 | | 0x16,0x4a,0xad,0xca,0xc8,0x2d,0xdd,0x51,0xd9,0x09,0xbf,0xb4,0x3d,0x3c,0xa4,0x37, |
4391 | | 0x3c,0xe4,0x59,0x38,0xc7,0x7c,0xf8,0xc6,0x22,0x65,0x89,0xf2,0x91,0xb2,0x54,0xf9, |
4392 | | 0x16,0xde,0xb1,0x05,0x9c,0xa3,0x03,0x7c,0xa3,0x07,0x5c,0x23,0x5c,0x08,0x96,0x54, |
4393 | | 0x52,0x4a,0x0d,0xa5,0x6d,0x32,0xe2,0x1c,0x37,0x2a,0xa3,0x95,0x31,0xca,0x3c,0xe7, |
4394 | | 0x8b,0x8e,0xc1,0x11,0x5d,0x0c,0xf7,0x68,0x0a,0xd7,0xb8,0x10,0xae,0x71,0x0f,0x3c, |
4395 | | 0x23,0x81,0xdf,0x59,0x0e,0xb7,0x48,0xc0,0x2b,0x06,0xc0,0x29,0x6e,0x80,0x4f,0xfc, |
4396 | | 0x09,0x2e,0x31,0x01,0x1e,0x51,0x01,0x87,0x28,0x83,0x3f,0x0c,0x83,0x3b,0x3c,0x01, |
4397 | | 0x6f,0x30,0xce,0xd0,0xd6,0xb1,0x85,0xe3,0x94,0x07,0xe1,0x09,0x81,0x25,0xac,0x53, |
4398 | | 0x76,0x85,0x23,0x74,0x82,0x1f,0x4c,0x55,0xe6,0x17,0x45,0x4e,0x65,0x21,0x2e,0x65, |
4399 | | 0x1d,0xd8,0xc1,0x0e,0xb8,0x93,0xc1,0x99,0x2c,0x53,0x7a,0xc0,0x10,0x2a,0x70,0x24, |
4400 | | 0x97,0xc1,0x0c,0xf6,0x87,0x19,0x1c,0xaf,0x5c,0xac,0xdc,0xae,0x8c,0x85,0x17,0x0c, |
4401 | | 0x83,0x13,0xac,0x85,0x13,0xec,0x85,0x0f,0x59,0x06,0x2f,0x08,0xae,0xe3,0x79,0x70, |
4402 | | 0x81,0x9b,0x94,0xbe,0xb5,0x22,0x2e,0x10,0x1c,0xc7,0x71,0xb0,0x81,0xc0,0x05,0x5e, |
4403 | | 0xc6,0x67,0x9c,0x07,0x0f,0x58,0x09,0x0f,0x28,0xc5,0x5b,0xec,0x09,0x07,0x08,0xce, |
4404 | | 0xe2,0xd5,0xb0,0x80,0x45,0xb5,0xab,0x3c,0xc5,0x14,0x5e,0x62,0x57,0xe5,0x48,0xdc, |
4405 | | 0x44,0x73,0x12,0x07,0x3b,0x0f,0x71,0x38,0xbe,0xe1,0x5f,0xf1,0x0c,0xa7,0xe0,0x18, |
4406 | | 0xce,0x86,0x17,0xac,0xc4,0x2f,0x2c,0xc0,0x2b,0x34,0x9f,0xb0,0x0d,0xbc,0x20,0x78, |
4407 | | 0x82,0x43,0x70,0x04,0x87,0xe3,0x02,0x4e,0xc7,0xfd,0x9b,0xed,0x7c,0xbf,0xc5,0xf0, |
4408 | | 0x82,0xad,0xf1,0xf9,0x5a,0x38,0x87,0x2f,0xf8,0x7b,0xfb,0x39,0x77,0xcf,0x9c,0x3d, |
4409 | | 0x63,0x07,0x37,0xc3,0x0c,0xca,0x9d,0x97,0xf7,0x21,0x3e,0x5e,0x02,0x0f,0xaf,0x10, |
4410 | | 0x7e,0xb0,0x35,0xdc,0xa0,0x05,0xbc,0xa0,0x3d,0xac,0xc0,0xbc,0xba,0xae,0xf8,0x74, |
4411 | | 0x3d,0x9c,0x43,0x77,0x3a,0xce,0xdc,0x30,0xc7,0x0d,0x46,0xc3,0x0a,0xa6,0x38,0x17, |
4412 | | 0xee,0x45,0x1c,0xb8,0x39,0xce,0x7b,0x7b,0xcd,0xb9,0x6e,0x6f,0xe1,0xba,0x25,0x70, |
4413 | | 0xdb,0xca,0x70,0xda,0x0e,0x76,0x1e,0xdb,0x89,0xce,0x5d,0x1b,0x86,0xab,0x36,0xd9, |
4414 | | 0xf9,0x69,0xd3,0x9d,0x93,0xf6,0x1c,0x0e,0xda,0x30,0x9c,0xb3,0x49,0xb8,0x66,0xe6, |
4415 | | 0x98,0xcd,0xc0,0x2d,0x4b,0xe0,0x92,0xb5,0x77,0xfe,0x58,0x70,0xc7,0x3a,0xe3,0x8c, |
4416 | | 0xf5,0x85,0x49,0x3c,0xe2,0x3c,0xb1,0xf1,0xf8,0x61,0x4f,0x39,0x27,0xac,0x02,0x17, |
4417 | | 0x2c,0xe1,0xfc,0x2f,0xf3,0xbe,0xf6,0x70,0xae,0x57,0x29,0x0c,0xa3,0xb9,0xf3,0xb8, |
4418 | | 0xda,0xc3,0x33,0x02,0xcb,0x30,0x86,0x51,0x17,0x76,0xd1,0x16,0x37,0xeb,0x00,0xe7, |
4419 | | 0x63,0x05,0xdf,0xaa,0x0b,0xce,0xd5,0x18,0x18,0xc6,0xeb,0xb8,0x55,0xef,0x39,0x9f, |
4420 | | 0xca,0xbc,0xa9,0x1a,0x4a,0x11,0x2c,0xa3,0x25,0xbe,0x54,0xf0,0xa4,0x3a,0x39,0x47, |
4421 | | 0xaa,0x27,0x6e,0x54,0x2f,0xd8,0xc6,0x75,0xce,0x83,0xba,0x03,0xbe,0x91,0x70,0xce, |
4422 | | 0x53,0x3f,0xe7,0x39,0x99,0xdf,0xb4,0x12,0xde,0x51,0x8c,0xc7,0xb4,0x1f,0xee,0x52, |
4423 | | 0x70,0x95,0x06,0xe2,0x28,0x99,0x9b,0x64,0x4e,0x92,0xb9,0x48,0x09,0x18,0x48,0x09, |
4424 | | 0xee,0x91,0x39,0x47,0x9d,0x9c,0x67,0xd4,0x03,0x1e,0x72,0x06,0x1c,0x64,0x34,0x1e, |
4425 | | 0xd1,0xad,0xce,0x1d,0x32,0x67,0xa8,0x1c,0x37,0x68,0xa5,0xe3,0x20,0x6b,0xf0,0x80, |
4426 | | 0x12,0xb0,0x90,0xad,0xf0,0x7b,0x3a,0x3a,0xa7,0x27,0xb8,0x3c,0x07,0x39,0x87,0xa7, |
4427 | | 0x42,0x79,0x43,0x79,0x5f,0x59,0xac,0x54,0xee,0x1a,0x31,0x92,0xc0,0x43,0x46,0xc3, |
4428 | | 0x41,0xcc,0xd3,0xe9,0x0a,0x07,0xc9,0x5d,0xa8,0x87,0x93,0xd3,0x08,0x17,0xa7,0x14, |
4429 | | 0x16,0x52,0x86,0x7b,0x73,0x1e,0xce,0xcd,0x3c,0x5c,0x9b,0x2f,0x61,0x21,0xc1,0xb3, |
4430 | | 0x69,0x8b,0x5f,0xd3,0x1b,0x1e,0xf2,0x3b,0x38,0x48,0x19,0xbc,0x63,0x0a,0x9c,0xc3, |
4431 | | 0x3c,0x99,0x9b,0xe1,0x1c,0x81,0x71,0x2c,0x71,0x3e,0xcc,0x4a,0xb8,0x46,0x60,0x1a, |
4432 | | 0xc3,0x60,0x19,0x63,0x60,0x18,0x5f,0xc2,0x2e,0x02,0xb7,0x30,0x5e,0x61,0x9c,0x22, |
4433 | | 0x30,0x8a,0x04,0x6c,0x62,0x18,0x4c,0xe2,0x2e,0x9c,0x95,0x7b,0x94,0x31,0x81,0x4f, |
4434 | | 0xcc,0x4a,0x26,0xde,0x9c,0x15,0xf9,0x2b,0x6b,0x83,0xbf,0x32,0x5b,0x9f,0x87,0x73, |
4435 | | 0xf4,0xf9,0xac,0xbc,0x3f,0x27,0xf2,0x59,0x82,0xcb,0xd2,0x23,0x5c,0x6e,0x1b,0x2e, |
4436 | | 0x46,0x7c,0x2d,0x72,0x5a,0x1a,0xe2,0xb2,0xf4,0x57,0x06,0xe3,0xb1,0x8c,0xc0,0x63, |
4437 | | 0xb9,0x01,0x8f,0x65,0xbc,0xf2,0x89,0xb2,0x2c,0x5c,0xec,0x3a,0x3f,0x72,0x5a,0x0e, |
4438 | | 0xc6,0x69,0x09,0x3e,0xcb,0x89,0x4a,0x85,0xb2,0x28,0x78,0x2c,0x0b,0xf4,0xfe,0x5c, |
4439 | | 0x10,0xf1,0x92,0x63,0xe1,0x24,0xc6,0x47,0xc6,0xc2,0x45,0x8c,0x87,0x04,0x16,0x52, |
4440 | | 0x03,0x06,0xb2,0x2d,0xec,0xa3,0x3d,0xcc,0xc3,0x58,0x47,0xe0,0x1c,0x81,0x71,0xcc, |
4441 | | 0x80,0x71,0xbc,0x0b,0xe3,0x58,0x07,0xe3,0xa8,0x0b,0xe3,0x68,0x0d,0xe3,0xe8,0x0e, |
4442 | | 0xe3,0x18,0x00,0xe3,0x18,0x05,0xe3,0x18,0x0b,0xe3,0x98,0x09,0xe3,0x08,0xfe,0x49, |
4443 | | 0xee,0x02,0xb3,0x77,0xf4,0xef,0x8b,0x7f,0x72,0x2e,0xee,0xc9,0x85,0xb8,0x27,0x23, |
4444 | | 0xf1,0x4f,0x82,0x7b,0x92,0xbb,0xcc,0x0d,0xee,0x31,0x1b,0xaf,0x24,0x8b,0x4f,0xb2, |
4445 | | 0x27,0x1e,0x49,0xa9,0x73,0x47,0x4a,0x61,0x20,0x65,0x8e,0x7f,0x98,0x1f,0xf2,0x19, |
4446 | | 0x5e,0x48,0x25,0x1c,0xe4,0x33,0x3c,0x90,0x79,0xf8,0x1f,0x81,0x7f,0x54,0xc2,0x40, |
4447 | | 0x16,0x39,0xcf,0xc3,0xfc,0x8e,0xcf,0xe1,0x1f,0xe6,0x73,0x2c,0x82,0x77,0x2c,0x87, |
4448 | | 0x73,0x04,0xc6,0xf1,0x22,0xce,0x46,0x02,0x57,0xc3,0x1c,0x8d,0x93,0x94,0xf3,0x3f, |
4449 | | 0xd3,0xd7,0xa1,0xe5,0x11,0xf3,0x28,0x84,0x75,0xec,0xe5,0xf8,0x46,0x2b,0xc7,0x34, |
4450 | | 0x0e,0x74,0x1c,0xc3,0xf8,0x45,0x4f,0xc7,0x2c,0x7a,0x39,0x4e,0x61,0x7c,0xc2,0xb8, |
4451 | | 0xc4,0x39,0xf0,0x88,0x4b,0x1c,0x83,0xb8,0x1e,0xf6,0x70,0x3f,0xcc,0x61,0x65,0x60, |
4452 | | 0x0e,0x2b,0xf5,0xfe,0x52,0xc6,0x28,0x8f,0x2b,0x33,0x94,0xd7,0xc2,0x25,0x9c,0xab, |
4453 | | 0xf4,0xf5,0x47,0xa9,0xa3,0x34,0x57,0x4a,0x95,0xfe,0xca,0x40,0x65,0x9c,0x32,0x5e, |
4454 | | 0xf9,0x38,0xfc,0xfe,0x6a,0xbd,0x9f,0x95,0x1e,0x4a,0x5f,0x25,0xb1,0x46,0x1f,0x23, |
4455 | | 0x5f,0xe9,0xef,0x56,0x12,0x5f,0xeb,0xeb,0xb0,0xf2,0xae,0xb2,0x48,0x59,0xa9,0xd4, |
4456 | | 0xf9,0x46,0xcf,0xab,0xf4,0x55,0x46,0x2b,0xe5,0x4a,0x85,0x32,0x2f,0x5c,0xa8,0xfc, |
4457 | | 0xad,0x9e,0xbe,0x56,0x2f,0x43,0x19,0xa6,0xbc,0xa4,0xcc,0x52,0x16,0x2a,0x2b,0xc2, |
4458 | | 0x05,0x83,0xeb,0x34,0xe3,0xad,0x8b,0xfc,0x8e,0xb5,0xf8,0x1d,0x81,0x95,0x04,0x4e, |
4459 | | 0x12,0x18,0x49,0xe0,0x23,0x81,0x8d,0x04,0x38,0x10,0x98,0x48,0xe0,0x21,0xc9,0x44, |
4460 | | 0x2d,0x7d,0x3b,0x5f,0x2b,0x3a,0xa8,0x4b,0x44,0x07,0x5f,0xd9,0x3c,0x7c,0x64,0xa7, |
4461 | | 0xe8,0x78,0x61,0x3d,0x1f,0x09,0x57,0x99,0xef,0xad,0x34,0x8a,0xf1,0x91,0xe6,0xf4, |
4462 | | 0xdd,0x07,0x3e,0x52,0x86,0x13,0xd2,0x17,0x27,0x64,0xa8,0x72,0x15,0x7c,0xe4,0x1e, |
4463 | | 0xc7,0x47,0xee,0x8f,0xbe,0x95,0xca,0xf1,0x91,0x47,0xe1,0x23,0x8f,0x29,0x8f,0x2b, |
4464 | | 0x13,0x1c,0x1f,0x99,0xe4,0xf8,0xc8,0x74,0x3c,0x92,0xb7,0xf0,0x48,0x02,0x1f,0xd1, |
4465 | | 0x9b,0x9a,0x78,0x1a,0x2f,0x64,0x2e,0x5e,0xc8,0x42,0xbc,0x90,0xe5,0xf0,0x91,0xca, |
4466 | | 0x54,0xd4,0x6f,0x1f,0x9c,0x90,0x0b,0x70,0x41,0x7e,0xe7,0xf8,0xc8,0x48,0xc7,0x47, |
4467 | | 0xcc,0xff,0xb8,0x17,0xe7,0x23,0xf0,0x91,0xe1,0x69,0x7d,0x4f,0x89,0xf3,0x11,0x7c, |
4468 | | 0x8f,0x51,0xf0,0x91,0xe0,0x78,0xdc,0x04,0x1f,0x79,0x26,0xc6,0x47,0x9e,0x85,0x8f, |
4469 | | 0x3c,0x0f,0x1f,0x79,0x19,0x17,0xe4,0x0b,0xa5,0x30,0xa3,0xef,0x45,0xe1,0x23,0xc5, |
4470 | | 0x31,0x3e,0x52,0x9b,0xce,0xfa,0xc3,0xe9,0xa6,0x3f,0x0b,0x3e,0x72,0x8e,0xeb,0xa6, |
4471 | | 0x7f,0x83,0x1e,0x7a,0xe3,0x23,0x7f,0xc7,0x13,0x59,0x0a,0x1f,0x59,0x8e,0x2f,0x12, |
4472 | | 0xba,0xe7,0xb7,0x70,0x5d,0xf3,0xcd,0xe9,0x97,0xbf,0xdf,0xf5,0xca,0x7f,0x4a,0x87, |
4473 | | 0x7c,0xf0,0x43,0xbe,0x75,0x7c,0xa4,0xae,0xeb,0x8c,0xb7,0xae,0x78,0xeb,0x88,0x0f, |
4474 | | 0xdd,0xf0,0x1d,0x71,0x44,0x7a,0xc3,0x47,0xfa,0xe3,0x86,0xdc,0x42,0x17,0xfc,0xcb, |
4475 | | 0x74,0xbf,0x2f,0xa1,0xfb,0x7d,0xff,0x18,0x1f,0x29,0xa3,0xd3,0xdd,0xfa,0xdc,0x7b, |
4476 | | 0xd0,0xdd,0x7e,0x32,0x9d,0xed,0xd6,0xcf,0x3e,0x02,0x57,0x64,0x34,0x8e,0x88,0xf9, |
4477 | | 0x21,0xd6,0xbf,0x5e,0x41,0xd7,0xfa,0x4b,0xae,0x63,0xdd,0xf8,0xc8,0xfb,0xf8,0x21, |
4478 | | 0x1f,0xe2,0x87,0xac,0x51,0xd6,0xc2,0x47,0xbe,0x87,0x8f,0x58,0x7f,0x7a,0x31,0xae, |
4479 | | 0x48,0x03,0x1c,0x91,0x96,0xb8,0x21,0xd6,0x8f,0x5e,0x46,0x27,0xfa,0xa1,0xae,0x0b, |
4480 | | 0xdd,0x5c,0x91,0x01,0xf4,0x9e,0x0f,0x71,0x7c,0xc4,0xfa,0xce,0x6f,0xc4,0x19,0x79, |
4481 | | 0x08,0x57,0x64,0x82,0xeb,0x34,0xaf,0xa0,0xbf,0xdc,0xba,0xcb,0x67,0x39,0x3e,0xb2, |
4482 | | 0x98,0x8e,0xf2,0x95,0x8e,0x8f,0x58,0x37,0x79,0x01,0xfe,0x48,0x1d,0xbc,0x91,0x52, |
4483 | | 0x7c,0x11,0xeb,0x1e,0xef,0xe8,0xf8,0x48,0x17,0xba,0xc5,0xad,0x57,0xdc,0xfa,0xc4, |
4484 | | 0x4f,0xc4,0x21,0x09,0xfd,0xe1,0x17,0x39,0x3e,0x72,0x1d,0xee,0xc8,0xad,0xce,0x19, |
4485 | | 0xb9,0x07,0x4f,0xe4,0x61,0xfc,0x10,0xeb,0x00,0x7f,0x96,0xde,0xef,0x59,0x31,0x3e, |
4486 | | 0xb2,0x5a,0xf9,0x26,0xc6,0x47,0xac,0xe7,0xbb,0x26,0x2e,0x49,0x03,0xd7,0xe9,0x7d, |
4487 | | 0x00,0x3d,0xde,0x5d,0xe8,0xef,0xee,0x46,0x6f,0xf7,0x09,0xf8,0x24,0x27,0xd3,0xd3, |
4488 | | 0x3d,0x00,0x3e,0x32,0xd4,0xf5,0x74,0xdf,0x80,0x53,0xf2,0x10,0x2e,0x89,0xf5,0x70, |
4489 | | 0x3f,0x47,0xb7,0xf6,0xab,0x74,0x6a,0xbf,0x89,0x53,0xb2,0x98,0x0e,0xed,0x15,0x74, |
4490 | | 0x66,0x27,0x71,0x4a,0xea,0xe0,0x92,0x74,0xa0,0x0b,0xbb,0x0b,0x1d,0xd8,0xd6,0x7f, |
4491 | | 0xdd,0x1d,0x97,0xe4,0x14,0xd7,0x69,0x3d,0x02,0x9f,0xe4,0x71,0xe7,0x91,0x58,0x6f, |
4492 | | 0xf5,0x6b,0xae,0xab,0x7a,0x21,0xfd,0xd4,0x5f,0x6c,0x51,0xd5,0x4b,0xdd,0x92,0x2e, |
4493 | | 0xea,0x4e,0x38,0x25,0xa1,0x7f,0xba,0xb7,0xf3,0x4a,0xae,0x73,0x2e,0x89,0x75,0x4c, |
4494 | | 0x4f,0x70,0xbd,0xd2,0xe6,0x8f,0xcc,0xa1,0x43,0x3a,0xf8,0x23,0xdb,0xd1,0x1b,0xdd, |
4495 | | 0x2a,0x0f,0x1f,0x39,0x00,0xaf,0xe4,0x1c,0xd7,0x0f,0x7d,0x15,0x7c,0xe4,0x1a,0x1c, |
4496 | | 0x93,0x3f,0xd1,0x05,0xfd,0x3c,0x7c,0x64,0x96,0xf2,0x4e,0xed,0xa8,0x07,0xda,0x3a, |
4497 | | 0xa0,0xad,0xfb,0xb9,0x1d,0x7d,0xcf,0x1d,0xe9,0x73,0xee,0x85,0x87,0xd2,0x17,0xef, |
4498 | | 0x64,0x88,0xeb,0x65,0xbe,0x8a,0x2e,0x66,0xeb,0x61,0xb6,0x9e,0xe5,0xe7,0x1d,0x1f, |
4499 | | 0x39,0x14,0xbf,0xc4,0xdc,0x92,0x13,0xf1,0x49,0x6e,0xc4,0x23,0x79,0xd2,0xf9,0x23, |
4500 | | 0xcf,0xe3,0x8c,0xd4,0xc1,0x15,0x39,0x81,0xee,0xe3,0xcb,0x71,0x45,0x6e,0xc7,0x15, |
4501 | | 0xf9,0x1e,0x3e,0x12,0xfc,0x90,0x61,0xf8,0x21,0x77,0xe1,0x83,0x6c,0xe9,0xfa,0x8c, |
4502 | | 0xf7,0xa5,0xc3,0xb8,0x0d,0x4e,0xc8,0x51,0x38,0x21,0x03,0xe9,0x2a,0x9e,0xe0,0x3a, |
4503 | | 0x8a,0x9f,0x71,0xbd,0xc4,0x2f,0xd1,0x45,0xfc,0x4e,0x8c,0x8f,0x84,0xfe,0xe1,0x6f, |
4504 | | 0x95,0x62,0x3a,0x88,0x8d,0x8f,0xec,0x80,0x33,0x72,0x15,0xae,0xc8,0x43,0x8e,0x8f, |
4505 | | 0x04,0x47,0xa4,0x1e,0x5d,0xc2,0xfb,0xd0,0x21,0xdc,0xd8,0x75,0x07,0xef,0x47,0x5f, |
4506 | | 0x70,0xe0,0x23,0x07,0xe3,0x90,0x0c,0xc1,0x1d,0x79,0x99,0x4e,0xe0,0xca,0x1d,0x22, |
4507 | | 0x77,0x64,0x7b,0xd7,0x05,0x7c,0x8c,0xe3,0x23,0x27,0xc5,0xf8,0xc8,0xa9,0x74,0xfb, |
4508 | | 0x0e,0x72,0x9d,0xbe,0xa3,0xe8,0xf1,0x1d,0x47,0x6f,0x6f,0x81,0xeb,0xe9,0x0d,0x7c, |
4509 | | 0x64,0x7f,0xfc,0x93,0xfe,0xf4,0xec,0x5e,0x41,0xcf,0xee,0xbd,0xf4,0xe9,0x3e,0xe8, |
4510 | | 0x7a,0x74,0xc7,0xb9,0xae,0xdc,0xff,0xa5,0x1f,0xf7,0x33,0xc7,0x47,0x56,0xd1,0x85, |
4511 | | 0xdb,0x98,0xee,0xdb,0xd6,0x74,0xde,0x1e,0x86,0xa3,0x12,0xfc,0x94,0x17,0xe9,0xaf, |
4512 | | 0x5d,0xe0,0xfa,0x6b,0x97,0xba,0xce,0x5a,0xeb,0xaa,0xfd,0xda,0xf5,0xd2,0x4e,0xa7, |
4513 | | 0x63,0xb6,0x2e,0xee,0xc9,0xc1,0x38,0x27,0xc7,0xc5,0xf8,0xc8,0xef,0x70,0x4b,0xa6, |
4514 | | 0x3a,0x3e,0x32,0x03,0xaf,0x24,0x38,0x25,0x73,0x71,0x4a,0x82,0x4f,0xb2,0x10,0x9f, |
4515 | | 0x64,0x05,0x3e,0x49,0x70,0x49,0x7e,0x50,0x8a,0xe9,0x8b,0x35,0x3e,0x52,0x7f,0x13, |
4516 | | 0xf8,0x48,0x2b,0xe5,0x20,0xf8,0xc8,0x49,0xf0,0x91,0x53,0xab,0xe1,0x23,0x03,0x1c, |
4517 | | 0x1f,0xb9,0x44,0xb9,0x4c,0x19,0x0a,0x1f,0x19,0xa5,0x5c,0xef,0xfc,0x95,0xe7,0xe8, |
4518 | | 0x9d,0x4d,0xc2,0x47,0x32,0xf0,0x91,0x22,0x3c,0x96,0x6d,0x9c,0xc7,0x12,0xfc,0x95, |
4519 | | 0x3d,0x7f,0x82,0x8f,0x98,0xbf,0x12,0x3c,0x95,0xf6,0x78,0x2a,0x5d,0xf0,0x54,0xba, |
4520 | | 0x29,0xdd,0x95,0x3e,0x78,0x29,0xd7,0x2b,0x5b,0xee,0x51,0xc5,0x47,0x5a,0xef,0xa9, |
4521 | | 0xd9,0x4f,0xf9,0x23,0x7c,0xa4,0xe1,0x5e,0x9a,0x3b,0x94,0x6b,0x94,0x3b,0x95,0x4f, |
4522 | | 0x94,0x47,0xf6,0x89,0xf8,0x48,0x65,0x7d,0xa5,0x81,0x3e,0x8e,0x34,0x50,0x56,0x36, |
4523 | | 0x8e,0x7c,0x96,0x4f,0xf1,0x59,0x56,0xe1,0xb3,0x54,0x36,0xa9,0xf2,0x59,0x9a,0xe2, |
4524 | | 0xb0,0x0c,0x84,0x8f,0xdc,0x86,0xbb,0x32,0x1e,0x67,0x65,0x1a,0xae,0xca,0x1c,0x1c, |
4525 | | 0x95,0x0f,0xe8,0x8e,0x3d,0xb1,0x99,0xbe,0x76,0x2b,0xb7,0x2b,0x6b,0x94,0x37,0x34, |
4526 | | 0xb4,0x56,0xc2,0x47,0xd2,0xf8,0x2a,0xbb,0xe1,0xab,0x34,0xa5,0x3f,0xb6,0x14,0x6f, |
4527 | | 0xa5,0x2d,0x9e,0x4a,0x27,0x3c,0x95,0x3b,0xf0,0x54,0xee,0x81,0x8f,0x58,0x37,0x6c, |
4528 | | 0x70,0x52,0x9a,0xe3,0xa2,0x04,0x0f,0xe5,0x23,0xf8,0xc8,0xce,0x2d,0xf4,0x79,0xad, |
4529 | | 0x74,0x57,0xfa,0x28,0x97,0x29,0x43,0x95,0x72,0x65,0xba,0xf2,0xaa,0x32,0x57,0xb9, |
4530 | | 0xb0,0xa5,0xde,0x6f,0xca,0xfb,0xca,0x42,0xe5,0x07,0xf8,0x48,0x70,0x58,0x2a,0xbb, |
4531 | | 0x45,0xce,0xca,0x0b,0xff,0x13,0xb9,0x29,0xb5,0x71,0x52,0x82,0x87,0x32,0x08,0x3e, |
4532 | | 0x62,0x9d,0xaf,0x7f,0xa6,0xdf,0x75,0x05,0x7d,0xae,0x5f,0x2b,0xbb,0x3b,0xd7,0xc4, |
4533 | | 0x9c,0x12,0xeb,0x5c,0xb5,0xae,0x55,0xeb,0x58,0xdd,0xcb,0xf5,0xa9,0x36,0x86,0x8f, |
4534 | | 0xb4,0x55,0xf6,0xc7,0x1b,0xb9,0x88,0xfe,0xd4,0xe7,0xe9,0x4d,0x5d,0xe5,0xfa,0x51, |
4535 | | 0xf7,0xa6,0x0b,0xf5,0x10,0x3a,0x50,0x8f,0xc2,0x19,0x19,0xee,0xba,0x4e,0x9f,0xa4, |
4536 | | 0xdf,0x74,0x0a,0xbd,0xa6,0xb3,0xe9,0x31,0xb5,0x0e,0xd3,0xe0,0x8c,0x34,0xa0,0x9b, |
4537 | | 0xb4,0x94,0x4e,0xd2,0x56,0x74,0x91,0x5a,0x0f,0xe9,0x11,0x8e,0x8f,0xf4,0x72,0x7d, |
4538 | | 0xa2,0x8f,0x39,0x3e,0x32,0x11,0x5f,0x64,0x12,0xbe,0xc8,0xf4,0x18,0x1f,0x59,0x46, |
4539 | | 0xef,0xa7,0x75,0x7b,0x66,0xf0,0x41,0xb6,0xc5,0x03,0x69,0x86,0xe7,0x71,0x36,0x9e, |
4540 | | 0x87,0x75,0x72,0x5a,0x17,0xa7,0x75,0x6f,0x86,0xce,0xcd,0xfb,0x70,0x3d,0x82,0xe7, |
4541 | | 0x71,0x2e,0x7e,0x47,0xc6,0x79,0x1d,0xf5,0x70,0x3a,0x1a,0xe2,0x74,0x98,0xcf,0xd1, |
4542 | | 0x19,0x87,0xa3,0xbb,0xf2,0xac,0x32,0x1f,0x87,0xa3,0x3b,0x0e,0xc7,0x2d,0x38,0x1c, |
4543 | | 0x73,0x95,0xef,0x94,0xca,0xef,0xa3,0xee,0xcc,0x1d,0xe8,0xce,0xec,0x9e,0x87,0x8f, |
4544 | | 0x9c,0x04,0x1f,0x39,0x59,0x39,0x45,0x39,0x1d,0x3e,0xd2,0x1f,0x3e,0x32,0x04,0x07, |
4545 | | 0x24,0xf0,0x91,0x54,0xa5,0x3e,0x06,0x94,0xe2,0x18,0x1f,0xa9,0x4d,0xef,0x66,0xe0, |
4546 | | 0x23,0xbb,0xe1,0x8a,0x94,0xb9,0xce,0xcd,0x69,0x78,0x20,0x73,0xf1,0x3f,0x82,0xfb, |
4547 | | 0xb1,0x58,0xf9,0xbb,0xf2,0xb1,0xf2,0xb9,0xf2,0x7d,0xf8,0x3b,0xf1,0x40,0xda,0xe1, |
4548 | | 0x7f,0x74,0xc3,0xfb,0x58,0x1b,0xe3,0x23,0x2d,0x95,0x4e,0xca,0x0d,0xca,0x4d,0xca, |
4549 | | 0x5d,0xf0,0x91,0xef,0xe0,0x23,0x77,0xb9,0x1e,0xcd,0x75,0xca,0x9e,0x78,0x1f,0x17, |
4550 | | 0xd0,0x8f,0xf9,0x67,0x7c,0x8f,0xe0,0x78,0xfc,0x99,0xee,0xcb,0x05,0x38,0x1d,0xf5, |
4551 | | 0x71,0x39,0x2e,0xc5,0xe1,0xf8,0x3d,0xee,0xc6,0xbd,0x38,0x1b,0x93,0x71,0x35,0x82, |
4552 | | 0xa7,0xd1,0x06,0x3f,0xe3,0x0c,0xbc,0x8c,0x72,0x7c,0x0c,0x73,0x31,0x5a,0x3b,0xff, |
4553 | | 0xe2,0x18,0x5c,0x8b,0xc7,0x70,0x2d,0x82,0x67,0xb1,0x53,0x51,0xc4,0x47,0xf6,0xc7, |
4554 | | 0xaf,0x08,0x6e,0xc5,0x5c,0xbc,0x8a,0x02,0xba,0x26,0x6b,0xe3,0x56,0x6c,0x87,0x53, |
4555 | | 0x61,0xbd,0x92,0x87,0x2a,0xc7,0x2b,0xf7,0xe0,0x52,0x84,0xfe,0xc8,0xaf,0x8a,0x23, |
4556 | | 0x9f,0xa2,0x13,0x3e,0xc5,0x20,0x3c,0x8a,0xbb,0x94,0xc7,0x4a,0x22,0x97,0xe2,0x09, |
4557 | | 0x1c,0x8a,0xca,0x9a,0x91,0x43,0x51,0x9f,0xae,0xc8,0xc3,0x70,0x26,0xce,0x85,0x8f, |
4558 | | 0x04,0x5f,0xe2,0x66,0x65,0x28,0xce,0xc4,0xa3,0xf0,0x91,0xc7,0x71,0x24,0x5e,0xa1, |
4559 | | 0xeb,0xf1,0x6d,0x5c,0x89,0xd0,0xf3,0x58,0x1f,0x3f,0x22,0x74,0x3a,0xf6,0xc2,0x91, |
4560 | | 0x08,0x7d,0x8e,0xa3,0x94,0x57,0x5d,0x97,0x63,0x12,0x4f,0x22,0x74,0x36,0x76,0x53, |
4561 | | 0x4e,0x73,0xbd,0x8d,0x83,0x5c,0x57,0xe3,0x95,0xf4,0x31,0x3e,0x45,0x0f,0x63,0xe8, |
4562 | | 0x60,0x9c,0xe1,0xf8,0xc8,0x52,0xfa,0x17,0x53,0xf8,0x14,0xd6,0xb9,0xd8,0x0a,0x9f, |
4563 | | 0x62,0x90,0xeb,0x51,0xbc,0x92,0xae,0xc4,0xd0,0x93,0xf8,0x92,0xeb,0x45,0x0c,0x7c, |
4564 | | 0x64,0xa1,0xf2,0xc5,0x96,0x91,0x4b,0xd1,0x8c,0xae,0xc3,0x96,0x8e,0x8f,0x84,0x6e, |
4565 | | 0xc3,0x03,0xe0,0x23,0xd6,0x6b,0x68,0x7e,0xc5,0x8d,0x38,0x15,0x63,0x5d,0x77,0xe1, |
4566 | | 0x12,0xfa,0x0a,0x43,0x57,0x61,0x92,0x8e,0xc2,0x9a,0xb8,0x15,0x0d,0x70,0x2a,0x5a, |
4567 | | 0xe2,0x52,0x74,0x70,0xdd,0x83,0x5d,0xe8,0x1b,0xec,0xe6,0xf8,0xc8,0x29,0x74,0x0a, |
4568 | | 0x0e,0x71,0x6e,0xc5,0x4d,0xf8,0x14,0x4f,0xbb,0xbe,0xc0,0xe7,0xe9,0x08,0x9c,0x9d, |
4569 | | 0x87,0x8f,0xbc,0xa1,0xbc,0x4d,0x0f,0x60,0x5b,0x7a,0xff,0x3a,0xbb,0xbe,0xbf,0xc0, |
4570 | | 0x47,0x7a,0x3b,0x3e,0x72,0x32,0x5d,0x7e,0x93,0x1c,0x1f,0x99,0xe6,0x7a,0xfb,0x66, |
4571 | | 0xe2,0x62,0x84,0x7e,0xbe,0xc7,0xe9,0xe3,0x9b,0xe2,0x7a,0xf8,0x2a,0x70,0x33,0x42, |
4572 | | 0xef,0x5e,0x0b,0x7a,0xf6,0x3a,0x38,0x3e,0x62,0xbd,0x7a,0xa1,0x4f,0xef,0x1c,0xd7, |
4573 | | 0xa7,0x67,0x7c,0xe4,0x31,0xd7,0x9d,0x17,0xf8,0xc8,0x64,0xba,0xf2,0x42,0x4f,0xde, |
4574 | | 0x8e,0x31,0x3e,0xb2,0xbb,0xeb,0xc3,0x6b,0x8c,0xe3,0xd1,0xcc,0x75,0xdd,0xb5,0x83, |
4575 | | 0x8f,0xac,0x76,0x9e,0xc7,0xd6,0xb8,0x1d,0xad,0xe9,0xae,0xeb,0xe0,0xf8,0x88,0x75, |
4576 | | 0xd2,0x1d,0x42,0x1f,0xdd,0x83,0xf4,0xcf,0xbd,0x45,0xef,0x9c,0x75,0xce,0x59,0xb7, |
4577 | | 0x5c,0x46,0xc9,0xd2,0x2d,0xd7,0x82,0x4e,0xb9,0x76,0x74,0xc8,0x1d,0xe2,0xf8,0xc8, |
4578 | | 0xb1,0xf4,0xc6,0xf5,0xc6,0xfb,0xb0,0xae,0xb8,0xd0,0x11,0xf7,0x17,0xe7,0x7e,0x18, |
4579 | | 0x1f,0x39,0x35,0xc6,0x47,0x16,0xd3,0xfb,0x96,0xa5,0xe7,0xad,0x0d,0xfd,0x6e,0x07, |
4580 | | 0x2b,0xe7,0xe0,0x82,0x58,0x7f,0x9b,0xf5,0xb6,0x59,0x5f,0x5b,0xe8,0x69,0xcb,0xe0, |
4581 | | 0x87,0x94,0xba,0x5e,0xb6,0x03,0x5c,0x17,0x5b,0x57,0xfa,0xd7,0x4e,0xc3,0x13,0xb9, |
4582 | | 0x89,0x9e,0xb5,0x3f,0x56,0xc3,0x47,0xc6,0xe2,0x88,0x7c,0xe2,0xf8,0xc8,0x6a,0x7a, |
4583 | | 0xd2,0xbe,0xa9,0x17,0xf5,0xa3,0xd5,0xa1,0xff,0xac,0x9d,0xeb,0x3d,0x33,0x3e,0xd2, |
4584 | | 0xcb,0xf1,0x91,0xd7,0x95,0xf7,0x94,0x45,0xca,0xaa,0x5d,0x23,0x87,0xe4,0x20,0x5c, |
4585 | | 0x91,0xd5,0xcd,0xf5,0x67,0xe9,0x31,0x3b,0x84,0xfe,0xb2,0xe0,0x88,0x04,0x3f,0x64, |
4586 | | 0x17,0xfa,0xca,0x9a,0xd0,0x53,0x16,0x3a,0xca,0xf6,0xc3,0x11,0x39,0x0b,0x47,0xe4, |
4587 | | 0x65,0x1c,0x91,0x2f,0xe0,0x23,0xcd,0xe9,0x20,0x3b,0x98,0xee,0xb1,0x93,0x71,0x45, |
4588 | | 0x82,0x27,0x12,0xba,0xc5,0xee,0xc0,0x05,0x09,0x1e,0x88,0x75,0x89,0x5d,0x43,0x6f, |
4589 | | 0xd8,0x3d,0xf8,0x1f,0x9e,0x8f,0x04,0xef,0xe3,0x1d,0x7c,0x8f,0xe0,0x7a,0xdc,0x82, |
4590 | | 0xe3,0xb1,0x06,0xb7,0x23,0x78,0x1d,0xe6,0x74,0x98,0xcb,0x71,0x26,0xfe,0x46,0x7f, |
4591 | | 0xbc,0x8d,0x6b,0xf1,0x35,0xee,0xa2,0xcf,0x2b,0xf0,0x91,0xfb,0x94,0x37,0x66,0x25, |
4592 | | 0x13,0x2b,0xe8,0xf6,0xfa,0x4e,0x99,0x30,0x47,0x9f,0xd3,0xca,0xeb,0xca,0xf7,0x73, |
4593 | | 0xa2,0xae,0xaf,0xd0,0xf3,0x35,0x53,0xf9,0x72,0x9e,0x3e,0xfe,0xe9,0xfb,0x3a,0x9d, |
4594 | | 0x9e,0xaf,0xd0,0xf1,0x75,0x29,0x1d,0x5f,0x57,0xd1,0xf1,0x35,0x96,0x8e,0xaf,0xa5, |
4595 | | 0xca,0xa7,0x4a,0xa5,0xd2,0x99,0xbe,0xaf,0xc0,0x47,0x4e,0xa0,0xeb,0x2b,0xf4,0x7b, |
4596 | | 0x2d,0x50,0xd6,0x28,0xc7,0x2e,0x48,0x26,0x2e,0x5e,0x10,0xb9,0x24,0x77,0x39,0x87, |
4597 | | 0xe4,0x01,0xbc,0x11,0x73,0x46,0x66,0xe2,0x89,0x14,0xe3,0x87,0xec,0x8c,0x17,0xd2, |
4598 | | 0xd1,0xf9,0x20,0x3d,0x70,0x40,0x2a,0xe0,0x23,0xef,0xc0,0x47,0xd6,0xc2,0x47,0x82, |
4599 | | 0xff,0x51,0x17,0xff,0xa3,0x35,0xfe,0x47,0x77,0xfc,0x8f,0x01,0xf8,0x1f,0xa3,0xf0, |
4600 | | 0x3f,0xc6,0xe2,0x7f,0xcc,0xc4,0xff,0x08,0xdd,0x5c,0x95,0x7f,0x8b,0xba,0xb9,0xda, |
4601 | | 0xd1,0xcd,0x35,0x04,0x3e,0x32,0x02,0x3e,0x72,0x3d,0xdd,0x5c,0xa1,0x97,0x6b,0xe7, |
4602 | | 0x77,0x23,0x2f,0xe4,0x36,0x7c,0x90,0x0c,0x7d,0x5b,0xbb,0xd3,0xb3,0xd5,0xc8,0xf5, |
4603 | | 0x6b,0x35,0xa1,0x53,0xeb,0x00,0xba,0xb4,0xba,0x2f,0xae,0xea,0xd0,0x5a,0x46,0x6f, |
4604 | | 0xd6,0xb7,0xf0,0x91,0x65,0xf4,0x64,0x85,0x8e,0xac,0xe5,0x74,0x63,0xad,0x85,0x8f, |
4605 | | 0x7c,0xe0,0xba,0xb0,0xac,0x03,0x6b,0x39,0xbd,0x57,0xd6,0x79,0x15,0x9c,0x90,0x8f, |
4606 | | 0x71,0x41,0x3e,0xc7,0x01,0x09,0xfe,0xc7,0x5c,0xfa,0xac,0x0e,0x72,0x3d,0x56,0xa1, |
4607 | | 0xbf,0xaa,0x8f,0x32,0xf1,0x33,0xbd,0x6e,0xcb,0x23,0x1f,0x64,0x57,0xe7,0x81,0xd4, |
4608 | | 0xc7,0xfd,0x68,0xfb,0x13,0x7c,0xa4,0xbb,0xf3,0x3a,0xaa,0xe3,0x23,0xe6,0x6e,0xf4, |
4609 | | 0xc7,0xd7,0xb8,0xc8,0x79,0x1a,0xa3,0x70,0x33,0xee,0xc3,0xc9,0x08,0x3e,0xc6,0x2a, |
4610 | | 0xa5,0xf1,0xca,0x64,0xe2,0x0f,0xca,0x78,0x65,0xba,0x32,0x57,0xf9,0x52,0x29,0x5e, |
4611 | | 0xa5,0x99,0x46,0x69,0x06,0x1f,0x39,0x4b,0x19,0xa0,0x3c,0xea,0xf8,0x48,0x6a,0xb5, |
4612 | | 0x5e,0x4f,0xe5,0x50,0xa5,0xa7,0x72,0x9a,0xf2,0xb7,0xaf,0x92,0x89,0xcf,0x94,0xef, |
4613 | | 0x94,0xbf,0x39,0x3e,0xb2,0x4c,0x29,0xf9,0x46,0x6f,0x8f,0xd2,0x4b,0xb9,0x46,0x19, |
4614 | | 0xa7,0x4c,0x51,0x66,0x28,0x6f,0x2b,0xc7,0xad,0xd5,0xbf,0xa3,0x72,0xb9,0xf2,0x02, |
4615 | | 0x7c,0xe4,0x7d,0x65,0x99,0xb2,0x56,0xf9,0xfd,0x3a,0xbd,0xff,0xe9,0xbe,0x0a,0x7c, |
4616 | | 0x24,0xb8,0x24,0xf5,0x70,0x48,0x16,0xe1,0x8e,0x04,0x6f,0xe4,0x70,0x7c,0x91,0xe0, |
4617 | | 0x8a,0x04,0x3e,0x72,0x45,0x22,0xea,0xb7,0xfa,0xbe,0xb2,0xb6,0x52,0x27,0x91,0xdc, |
4618 | | 0xb6,0xee,0xb6,0x35,0xeb,0x26,0xf5,0x43,0xba,0x24,0x5d,0x90,0x2a,0x48,0x15,0xa6, |
4619 | | 0xd2,0x19,0x3d,0x26,0xeb,0x26,0x53,0x7a,0x8a,0x7e,0x91,0x2e,0x29,0xd4,0x4f,0x85, |
4620 | | 0x99,0xf4,0x86,0x8f,0x59,0xfd,0xc0,0xaf,0x33,0xe1,0x17,0xd9,0xdc,0x8f,0xe9,0x92, |
4621 | | 0x6c,0x0d,0x7b,0xac,0x51,0x9c,0x2e,0x2a,0x29,0x4a,0x15,0xa5,0xb3,0x45,0xd9,0xe2, |
4622 | | 0x92,0xe2,0xa2,0xf0,0x53,0xf8,0xb5,0x52,0x58,0x14,0xfe,0x4b,0x8f,0x7a,0xb6,0x74, |
4623 | | 0x0d,0xf7,0x47,0xb2,0x35,0x8a,0x8a,0x8a,0xc3,0x33,0x66,0x33,0x1b,0x3e,0x46,0x0f, |
4624 | | 0xb9,0x5f,0x65,0xa3,0x5f,0x95,0xe8,0x31,0x6b,0xbf,0x11,0x7e,0x27,0x9b,0xfb,0xaf, |
4625 | | 0xd8,0xb3,0x47,0xcf,0x9f,0xf5,0xcf,0xcb,0x73,0xac,0x7f,0xee,0xaa,0x87,0x2c,0xd1, |
4626 | | 0x1b,0x9e,0xb5,0x17,0x93,0xfb,0x8b,0xa3,0xa7,0xa7,0x79,0xe6,0x6c,0x55,0xb2,0xee, |
4627 | | 0x95,0x5a,0xff,0x77,0x65,0x79,0x59,0xfa,0xb9,0x64,0xc3,0x57,0x3d,0x53,0xf5,0x1a, |
4628 | | 0x66,0xd3,0xeb,0x7f,0x95,0xf5,0x4f,0xae,0xf6,0xed,0xce,0x6c,0xf8,0x4a,0xe6,0xde, |
4629 | | 0xf3,0x35,0x33,0xe9,0xcc,0xfa,0x97,0xec,0xfe,0x44,0x78,0x91,0xe9,0x74,0x36,0x99, |
4630 | | 0x75,0x2f,0x34,0x7a,0x86,0x74,0xee,0x9f,0x2a,0xf7,0x66,0xac,0x7f,0xb9,0xbc,0xae, |
4631 | | 0xd9,0xec,0xfa,0xe7,0x8a,0xbf,0x02,0xfe,0x3d,0x51,0xf5,0xb4,0xaa,0x87,0x74,0xf4, |
4632 | | 0xea,0xf0,0x73,0xcd,0x64,0xa6,0x46,0xba,0x66,0xdd,0xed,0xea,0xd4,0xae,0xb5,0x45, |
4633 | | 0xaa,0x24,0x9d,0xd2,0x13,0xb6,0xd9,0x72,0xab,0xad,0x93,0x85,0x99,0xc2,0x82,0x74, |
4634 | | 0x2e,0x25,0xd9,0x74,0xfc,0x63,0x49,0xaf,0xf3,0xfa,0x5f,0xa7,0x0b,0x4a,0xa2,0x9f, |
4635 | | 0xed,0x43,0x2e,0x9d,0x7b,0x85,0xd3,0xeb,0xdf,0xf3,0xbc,0x17,0xd2,0xb9,0x87,0x9a, |
4636 | | 0xf6,0xbb,0xb9,0x9f,0xab,0x3e,0x1c,0x7f,0xfc,0x22,0xf8,0x3d,0x7d,0xf4,0x45,0x6f, |
4637 | | 0x7f,0xf4,0x9c,0xf6,0x16,0xa5,0xb3,0xb9,0xd7,0x21,0xf6,0x66,0x67,0xab,0xfe,0x99, |
4638 | | 0xfd,0x7f,0xfe,0xf8,0x9d,0x93,0xc9,0xa4,0x37,0xfc,0xc8,0xcb,0xe8,0x23,0xb9,0xa0, |
4639 | | 0x46,0xee,0xa1,0x28,0x6d,0x8f,0xe1,0x65,0xa7,0x72,0x8f,0xfa,0x54,0x4b,0xeb,0x87, |
4640 | | 0xa2,0xa2,0xe4,0x86,0x9f,0x75,0xb9,0x3f,0x5a,0xa2,0xa7,0xa5,0xab,0xde,0xbb,0x99, |
4641 | | 0xe8,0x9d,0x10,0x5e,0x58,0x61,0x26,0x53,0xed,0x87,0x44,0xf4,0x12,0xab,0x1e,0xd2, |
4642 | | 0xb9,0x1f,0xf5,0x71,0x9b,0xfb,0x31,0xf7,0x6b,0x7b,0x62,0xee,0x35,0xca,0x16,0x17, |
4643 | | 0xd7,0xc8,0xea,0xbf,0x8b,0xc3,0xd3,0xf5,0xa9,0x98,0x2e,0xd2,0xe7,0x5d,0xee,0x93, |
4644 | | 0xb1,0x46,0x0d,0xde,0x39,0xd9,0x6a,0xde,0xe6,0x0d,0x3f,0x2c,0x63,0x1f,0xa3,0x3f, |
4645 | | 0xfa,0x34,0xcd,0x64,0x32,0xf6,0x39,0x97,0xcd,0xfc,0xf8,0xef,0x88,0xbf,0x8f,0x37, |
4646 | | 0x78,0x81,0xe9,0xea,0x5e,0x90,0x7f,0xf7,0x56,0xfd,0x66,0xbe,0x0f,0x5b,0xf7,0x0a, |
4647 | | 0x65,0xfd,0x4b,0xc8,0x44,0x5f,0x28,0xb2,0x1b,0xfe,0x2d,0x99,0xd8,0x2b,0x17,0xbe, |
4648 | | 0xf4,0x65,0x36,0xfc,0x04,0xca,0x64,0xaa,0x3e,0xe5,0xfd,0xdb,0x99,0xae,0xfe,0x9f, |
4649 | | 0x24,0x9b,0x49,0xea,0xe3,0x3d,0xf7,0x41,0xba,0xfe,0xe5,0x27,0xb3,0xf6,0xa1,0x97, |
4650 | | 0xb5,0x2f,0x98,0xd5,0x3d,0x54,0xf7,0x81,0x5b,0x58,0xf5,0xb6,0x65,0xd3,0xbc,0x11, |
4651 | | 0x1b,0xbc,0x87,0x4a,0xdc,0x97,0xc6,0xaa,0x37,0xbd,0x46,0xf4,0x65,0x55,0xff,0xc8, |
4652 | | 0x1b,0x7d,0x88,0x3e,0xa1,0xd2,0x85,0xe9,0xaa,0xaf,0xea,0x99,0xdc,0x53,0x32,0xe9, |
4653 | | 0x6a,0x1e,0x0a,0xab,0x5e,0xf5,0x64,0xf8,0x52,0x63,0xf7,0xac,0x8f,0x80,0x27,0x6f, |
4654 | | 0xea,0xbd,0xe6,0x76,0x8f,0xb9,0xdd,0x57,0x6e,0xf7,0x93,0xc7,0xef,0x23,0x8f,0xdf, |
4655 | | 0x43,0x6e,0xf7,0x8b,0xdb,0xbd,0xe2,0x76,0x9f,0xb8,0xdd,0x1b,0x6e,0xf7,0x84,0xdb, |
4656 | | 0xfd,0xe0,0x76,0x2f,0xb8,0xdd,0x07,0x6e,0xf7,0x80,0xdb,0xfd,0xdf,0x76,0xcf,0xb7, |
4657 | | 0xbf,0xd7,0xdb,0xbc,0xb7,0x0e,0xdc,0xd7,0xdd,0xdd,0xdd,0xc3,0x6d,0xf7,0x6f,0x1b, |
4658 | | 0xc7,0xb5,0xfb,0xb2,0xa7,0x55,0x73,0x3f,0xf6,0x6c,0x77,0x1f,0xb6,0xdd,0x7f,0xfd, |
4659 | | 0x43,0xcc,0x61,0xf3,0xf7,0x54,0xff,0xd4,0xfd,0xd4,0x76,0x0f,0xb5,0xbf,0x7f,0x7a, |
4660 | | 0x84,0xbb,0x47,0x7a,0x9a,0xbb,0x37,0xda,0x7b,0x69,0x76,0x2f,0xf4,0xda,0x18,0x6b, |
4661 | | 0xed,0xe0,0xb8,0x6a,0xfc,0xbe,0x66,0xef,0x9c,0xd9,0x7d,0xcc,0x76,0xff,0xf2,0xb4, |
4662 | | 0x6a,0xee,0x47,0x9e,0xed,0xee,0x43,0x4e,0xc0,0x44,0xed,0x5e,0xe3,0x8e,0x1b,0xb9, |
4663 | | 0xc7,0xd8,0xee,0x2b,0xbe,0x92,0x7b,0x89,0xed,0xbe,0xe1,0x69,0xee,0x5e,0x61,0xbb, |
4664 | | 0x4f,0xd8,0xdf,0x23,0x6c,0xf7,0x06,0xfb,0x7b,0x82,0x0b,0xdc,0x3d,0xc0,0x1d,0xab, |
4665 | | 0xb9,0xf7,0xb7,0x9b,0xbb,0xdf,0xd7,0xee,0xf5,0x35,0xe6,0xe9,0xef,0xe5,0xad,0xee, |
4666 | | 0x3e,0x5e,0xbb,0x87,0xd7,0xee,0xdf,0xb5,0x7b,0x77,0xed,0x9e,0x5d,0xbb,0x2f,0xd7, |
4667 | | 0xee,0xc9,0xb5,0xfb,0x70,0xed,0xde,0xdb,0x8d,0xdd,0x77,0x7b,0x7e,0xec,0x3e,0xdb, |
4668 | | 0x7c,0xf7,0xd8,0x36,0x86,0x4d,0x1e,0x0b,0x9b,0xb4,0xfb,0x65,0xed,0x5e,0x59,0xbb, |
4669 | | 0x4f,0xd6,0xee,0x91,0x1d,0x0e,0x9b,0xb4,0x7b,0x61,0xef,0x80,0x51,0xda,0xbd,0xaa, |
4670 | | 0xe6,0x52,0x99,0x47,0x65,0xf7,0x9b,0xda,0x7d,0xa6,0x13,0x61,0x81,0x76,0x0f,0x69, |
4671 | | 0xfc,0xfe,0x51,0xeb,0x87,0xb3,0xfb,0x44,0x77,0x73,0xf7,0x83,0x06,0xae,0xb7,0x9d, |
4672 | | 0xe3,0x75,0xc6,0xe9,0xfc,0x3d,0x9b,0xe5,0xee,0x1e,0x4d,0xf3,0x95,0xba,0xc4,0xee, |
4673 | | 0xbb,0x1c,0x0e,0x87,0x1b,0x07,0x73,0x0b,0x6c,0x6d,0x2f,0x98,0x9a,0xbf,0x07,0x72, |
4674 | | 0xa9,0xbb,0xef,0xf1,0x8b,0x18,0x3f,0xb3,0xfb,0x19,0xe7,0xc1,0x93,0xec,0x1e,0x40, |
4675 | | 0xbb,0xd7,0xcf,0xee,0xe3,0x6b,0x04,0x27,0xb1,0xfb,0xf3,0x06,0xc0,0x22,0xec,0xfe, |
4676 | | 0x39,0xbb,0x67,0xce,0xee,0x95,0xb3,0xfb,0xdd,0xec,0x5e,0x37,0xbb,0xcf,0x6d,0xcf, |
4677 | | 0xd8,0xbd,0x6d,0x76,0x5f,0xdb,0x44,0x18,0x83,0xdd,0xcb,0x66,0xf7,0xaf,0xd9,0x7d, |
4678 | | 0x6b,0x5d,0xe1,0x0b,0xde,0xbd,0xa8,0x70,0xf7,0xa0,0x35,0x84,0x19,0xd8,0xbd,0x65, |
4679 | | 0xc6,0x0b,0x2e,0x73,0x1e,0x45,0xb9,0xbb,0x5f,0xcc,0xee,0x15,0xb3,0xfb,0xc4,0xec, |
4680 | | 0x1e,0xb1,0x65,0xdc,0x0b,0x66,0x9c,0xe0,0x43,0x77,0xff,0x56,0x38,0xff,0xb7,0xfb, |
4681 | | 0xb2,0xe2,0xf7,0x5a,0xd9,0x3d,0x50,0x76,0xef,0x93,0xdd,0xe3,0x94,0xef,0xde,0xa1, |
4682 | | 0xf8,0xfd,0x42,0x76,0x7f,0x90,0xdd,0xff,0x63,0xf7,0xf9,0xd8,0xbd,0x3d,0x76,0x2f, |
4683 | | 0x8f,0xdd,0xc7,0x63,0xf7,0xee,0xd8,0x7d,0x3b,0x09,0xb7,0xaf,0x7e,0x88,0xbb,0x3f, |
4684 | | 0xc7,0xee,0xcd,0xb1,0x3d,0xf5,0xf2,0xd8,0x3d,0x38,0x76,0xef,0x4d,0x7d,0xce,0x5c, |
4685 | | 0xed,0x3e,0x1b,0xbb,0xbf,0xc6,0x76,0xd2,0x27,0x70,0x2f,0xcd,0xcb,0xb1,0x73,0xd7, |
4686 | | 0x26,0xb1,0x7b,0x63,0xec,0xbe,0x98,0x85,0x9c,0x9f,0x26,0x38,0x3b,0xb5,0xfb,0x5a, |
4687 | | 0x3a,0xe6,0xb9,0x97,0xc5,0xee,0x63,0xc9,0x77,0x0f,0xcb,0xa4,0x4d,0xb8,0x57,0x65, |
4688 | | 0x9e,0xbb,0x37,0xc5,0xee,0x4b,0x69,0xcd,0xb9,0xa8,0xdd,0x77,0x52,0xce,0xb9,0xe7, |
4689 | | 0x63,0xee,0xfe,0x91,0x0a,0x77,0xbf,0x48,0x29,0xe7,0x9a,0x8f,0x70,0x66,0xb9,0x0b, |
4690 | | 0xe7,0x91,0x4d,0x38,0x83,0xac,0xee,0xbe,0x8c,0x8e,0xee,0x5e,0x0c,0x3b,0x77,0x7c, |
4691 | | 0xcd,0xdd,0x73,0xb1,0xc8,0xdd,0x63,0x61,0xf7,0x57,0xf8,0xfd,0x6b,0x7f,0x4f,0x45, |
4692 | | 0x4f,0xce,0x16,0xaf,0xe3,0x4c,0xb1,0x2f,0xe7,0x86,0xcd,0xdd,0x7d,0x10,0x9d,0x62, |
4693 | | 0xf7,0x3c,0x84,0x73,0xc1,0x8d,0xdd,0xd3,0x60,0xf7,0x33,0x54,0x77,0xff,0xc2,0x9f, |
4694 | | 0xdc,0xbd,0x09,0x6b,0x62,0xf7,0x23,0xd8,0xbd,0x08,0xad,0xdc,0xfd,0x07,0x07,0xba, |
4695 | | 0xfb,0x0d,0xec,0x7e,0x02,0xbb,0x97,0xa0,0x1e,0xe7,0x78,0x76,0x6f,0x80,0xdd,0x17, |
4696 | | 0x60,0x7d,0xfe,0xf1,0x1e,0xff,0x78,0x5f,0xbf,0xf5,0xe1,0xff,0x54,0x0f,0xfe,0x2f, |
4697 | | 0xda,0x7f,0xbf,0xb9,0x3d,0xf0,0x9b,0xd8,0xeb,0x6e,0x7d,0xee,0xd6,0xe3,0x6e,0x3d, |
4698 | | 0xed,0xd6,0xcf,0x6e,0x3d,0xec,0xd6,0xbb,0x6e,0xbd,0xea,0xd6,0xa7,0x6e,0x3d,0xea, |
4699 | | 0xd6,0x9f,0x6e,0x3d,0xe8,0xd6,0x7f,0x6e,0xbd,0xdc,0x61,0x97,0x32,0xc1,0x9c,0x79, |
4700 | | 0x8b,0x9b,0x2d,0x9f,0x63,0xa6,0x0c,0xf3,0xe4,0xce,0x99,0xa8,0x8f,0x7a,0x0f,0x65, |
4701 | | 0x1f,0xa5,0xbe,0xd2,0x40,0x69,0xa8,0x34,0x52,0x9a,0x2b,0x2d,0x5d,0x4f,0xf5,0xa1, |
4702 | | 0xca,0x61,0xcc,0xa0,0xe7,0xb9,0x9e,0x86,0x0b,0x94,0x8b,0x95,0x6b,0x95,0x3b,0x94, |
4703 | | 0x0a,0x65,0x86,0x32,0x53,0x99,0xa5,0xcc,0x56,0xe6,0x28,0x73,0x95,0x79,0xca,0x7c, |
4704 | | 0xf6,0x17,0xdf,0x64,0x6e,0xfd,0x5f,0xd7,0xe7,0xb0,0x96,0x5e,0xeb,0xda,0x6e,0x67, |
4705 | | 0x31,0x74,0x3a,0xd4,0x55,0x76,0x54,0xea,0x29,0xbb,0x2a,0x0d,0x94,0x86,0x4a,0x23, |
4706 | | 0xa5,0xb1,0xd2,0x44,0x69,0xca,0x7e,0xa3,0xf5,0x3f,0xfc,0x46,0xe9,0xa5,0xfc,0x56, |
4707 | | 0x39,0x5b,0x39,0x57,0x39,0x5f,0x19,0xa4,0x0c,0x56,0x2e,0x50,0x2e,0x56,0x2e,0x65, |
4708 | | 0x2e,0x7e,0x85,0xb9,0x78,0xad,0x9b,0x89,0x77,0x62,0x16,0x6e,0x48,0x17,0x44,0x67, |
4709 | | 0xe5,0x10,0xe5,0x50,0xe5,0x30,0xe5,0x70,0xe5,0x68,0xe5,0x18,0xe5,0x58,0xe6,0xe4, |
4710 | | 0xd0,0x13,0xd1,0x4f,0x39,0x43,0x39,0x53,0x39,0x8b,0xde,0x88,0x11,0xca,0xd5,0x74, |
4711 | | 0x68,0xdf,0xc4,0xae,0xa4,0xf5,0x48,0x3c,0xac,0x8c,0x57,0x1e,0x53,0x1e,0x57,0x26, |
4712 | | 0x28,0x93,0x95,0xa7,0x99,0xb5,0xc3,0x9c,0x6d,0x33,0x76,0x67,0xf6,0x25,0x7b,0x32, |
4713 | | 0x5f,0x5f,0xc9,0x4c,0x3d,0x83,0x19,0x7a,0x89,0x9b,0x99,0x3b,0x54,0xd3,0xe9,0x30, |
4714 | | 0xd0,0xcd,0xc4,0x53,0x5d,0x3f,0x83,0xcd,0xbf,0xd6,0xc1,0xd0,0x81,0x1d,0xc2,0xce, |
4715 | | 0x6e,0xc6,0xed,0xc7,0x5c,0x5b,0xc1,0x1c,0xeb,0xe7,0xd7,0x8e,0xb1,0x6e,0x83,0x7e, |
4716 | | 0xcc,0xa9,0x61,0x3e,0x9d,0xce,0x6c,0x3a,0x8b,0x59,0x34,0xc1,0xec,0xd9,0x99,0x39, |
4717 | | 0xb3,0x1f,0xb3,0xe5,0x2b,0xae,0x53,0xc0,0xe6,0xc6,0xae,0x6e,0x56,0x7c,0x89,0x19, |
4718 | | 0xb1,0xb5,0x9b,0x0b,0xcf,0xc7,0xf1,0xbf,0xda,0xb9,0xfd,0x61,0xf6,0x6b,0x8a,0xc7, |
4719 | | 0xbf,0x3f,0xfe,0xfe,0xf1,0xcc,0x7f,0xe7,0x33,0xe7,0x8d,0x64,0xd6,0xb3,0xf9,0x6e, |
4720 | | 0x2b,0xe6,0xba,0x23,0x99,0xe7,0x26,0xe2,0xc1,0xbf,0x80,0xff,0x1e,0xe6,0xb9,0x1a, |
4721 | | 0xdb,0x47,0xfb,0x5c,0x25,0xcc,0x73,0xbb,0x55,0xe3,0xb8,0xef,0x86,0xd7,0xde,0x02, |
4722 | | 0x97,0xdd,0x66,0xba,0x63,0x9d,0x9b,0xde,0x0f,0x27,0x7d,0xb0,0x9b,0xeb,0x12,0xcc, |
4723 | | 0x73,0x6d,0xb8,0xeb,0xfc,0x40,0xe6,0xba,0x61,0x38,0xe7,0x0f,0xe1,0x9a,0x7f,0x8c, |
4724 | | 0x63,0xbe,0x1c,0xb7,0xbc,0x09,0x3e,0xf9,0x3c,0xe6,0xba,0x25,0x6e,0xa6,0xfb,0x86, |
4725 | | 0x59,0xae,0xc4,0xed,0x27,0x35,0xc2,0xc3,0xee,0x8f,0x4b,0xbd,0xa2,0x49,0xd5,0x4c, |
4726 | | 0xd7,0x88,0x59,0xce,0xee,0x10,0xbe,0x9b,0xd9,0x2d,0xe5,0xe6,0xb5,0xbd,0xdd,0xdd, |
4727 | | 0xba,0x83,0x70,0x64,0x17,0xb9,0xb9,0xac,0x2b,0xf3,0xd8,0x04,0x1c,0xd8,0xa9,0x6e, |
4728 | | 0x16,0xdb,0x17,0xc7,0xd5,0x66,0xb1,0xcb,0xdd,0xfc,0xf5,0x57,0xe6,0xae,0x19,0x38, |
4729 | | 0xab,0x61,0xce,0xfa,0x88,0x3d,0x0b,0x9b,0xb1,0x12,0xcc,0x56,0x61,0x67,0x21,0x78, |
4730 | | 0x97,0x36,0x5b,0x5d,0x58,0xb0,0xa1,0x77,0x68,0xae,0x61,0xf0,0x0b,0x9f,0x77,0xdd, |
4731 | | 0x84,0xb3,0x95,0x39,0xca,0x02,0xe5,0x2d,0xe5,0x6d,0xe5,0x7d,0xe5,0x03,0x65,0xb1, |
4732 | | 0xbb,0xb3,0x31,0xf8,0x88,0x2b,0x8a,0xa3,0xbe,0xc2,0x2b,0x95,0xe1,0xca,0x08,0xe5, |
4733 | | 0x6a,0x65,0x94,0x72,0x9d,0x72,0x83,0x72,0xa3,0x72,0x93,0x32,0x1a,0x1e,0x1f,0x5c, |
4734 | | 0xc5,0x71,0x25,0x91,0x9f,0x98,0x54,0xf6,0x70,0xf7,0x37,0x9e,0xc5,0xdc,0x16,0x1c, |
4735 | | 0xc4,0x99,0x74,0x12,0xbe,0xea,0x1c,0xc4,0xe0,0x1f,0xb6,0x54,0x5a,0x39,0x0f,0xf1, |
4736 | | 0x68,0x5c,0xc4,0x21,0xca,0x85,0xcc,0x75,0xc1,0x47,0x7c,0x42,0x99,0xa8,0x4c,0x52, |
4737 | | 0x26,0x2b,0x53,0x94,0x67,0x94,0x69,0xca,0x0c,0xe5,0x59,0xfa,0x0b,0x5f,0x56,0x5e, |
4738 | | 0x81,0xd1,0x27,0x99,0x03,0x6d,0xfe,0xbb,0x02,0x3f,0x71,0xb2,0x9b,0xf9,0xea,0xe3, |
4739 | | 0x20,0xda,0x8c,0xf7,0x14,0xb3,0x5d,0x98,0xe9,0x9a,0xc3,0xcd,0xdb,0xb8,0x99,0x6e, |
4740 | | 0x21,0xbe,0x60,0x82,0x59,0xae,0xcc,0x39,0x7f,0x53,0xe0,0xd5,0xf3,0xdc,0xec,0xb5, |
4741 | | 0x1f,0xde,0x9e,0xcd,0x5e,0x13,0xe0,0xcf,0xd3,0xf1,0xf2,0x9e,0xc0,0xc3,0x9b,0xce, |
4742 | | 0xec,0xd5,0x12,0xae,0xdc,0x89,0xd9,0x6b,0x1c,0x6e,0x9d,0xcd,0x60,0xbb,0xe2,0xcf, |
4743 | | 0x05,0x77,0xae,0xb9,0xf9,0x72,0xcc,0x5e,0x07,0x39,0xef,0x6d,0x11,0x33,0x56,0x4b, |
4744 | | 0x66,0x2b,0x9b,0xa9,0x7a,0x31,0x53,0xfd,0x37,0x33,0x55,0x3f,0x98,0x6c,0x69,0x6c, |
4745 | | 0xa6,0x7a,0x18,0x1f,0xed,0xc9,0x9d,0x7f,0xec,0x9f,0x75,0x65,0x6e,0xba,0xd5,0xcd, |
4746 | | 0x4c,0x6b,0x98,0x95,0xda,0xc0,0x46,0x6d,0x36,0x2a,0x65,0x26,0xaa,0x87,0xf7,0xb5, |
4747 | | 0x92,0x59,0xa8,0x3b,0xb3,0xcf,0xdf,0x99,0x75,0xc6,0x4c,0xad,0x72,0xa4,0xea,0xe3, |
4748 | | 0x44,0x0d,0x66,0x9e,0x79,0x98,0x39,0xa6,0x37,0x73,0x4a,0x7b,0x37,0x9b,0xac,0xf7, |
4749 | | 0x83,0xaa,0xf1,0x81,0x6c,0xee,0xb0,0x79,0xe3,0x33,0xe6,0x8c,0x0f,0xdd,0x6c,0x61, |
4750 | | 0x33,0x85,0x79,0x3a,0xde,0x15,0x09,0x33,0x45,0x38,0xbb,0x0a,0xe7,0x56,0x76,0x66, |
4751 | | 0xf5,0x2c,0xe7,0x54,0xe1,0x8c,0x6a,0x47,0x37,0x53,0xec,0x5d,0xcd,0x4c,0xd1,0x4c, |
4752 | | 0x69,0xe1,0xee,0xbf,0xe8,0xca,0x4c,0x61,0x9e,0x83,0xb9,0x0d,0x83,0x95,0x8b,0x94, |
4753 | | 0x6b,0x94,0xdb,0x95,0xe9,0xcc,0x14,0xcf,0x2a,0xaf,0x56,0x33,0x53,0xbc,0xe6,0xee, |
4754 | | 0xcc,0x78,0x8f,0x73,0xb0,0xa5,0xce,0x81,0xf8,0xae,0x9a,0x99,0x62,0x1b,0x65,0x07, |
4755 | | 0x65,0x17,0x66,0x8a,0xfa,0x79,0x66,0x8a,0x66,0xce,0x99,0x08,0x33,0xc5,0xf1,0x4a, |
4756 | | 0x6f,0xa5,0xbf,0x72,0x8e,0x32,0xd0,0xcd,0x14,0x43,0x94,0x8b,0x94,0x4b,0x94,0x2b, |
4757 | | 0x38,0x67,0x33,0xb7,0xc2,0x66,0x8a,0x1d,0x38,0x5f,0xab,0xcf,0xb9,0x5a,0x98,0x29, |
4758 | | 0x0e,0x56,0xba,0xba,0x99,0xe2,0x28,0x37,0x53,0x98,0x5f,0x11,0x66,0x8a,0xd3,0xdc, |
4759 | | 0x4c,0x11,0x5c,0x8b,0xe1,0xca,0x48,0x66,0x8a,0x1b,0xdd,0x4c,0x11,0xce,0xe7,0xc6, |
4760 | | 0x2a,0x8f,0x32,0x53,0x94,0x2b,0x4f,0x28,0x93,0x98,0x29,0x5e,0xe2,0xec,0x2e,0xe5, |
4761 | | 0xce,0xed,0x0e,0x65,0xa6,0x38,0xce,0x9d,0xd7,0x4d,0xe5,0x8c,0x6e,0xb6,0x3b,0x8b, |
4762 | | 0x4b,0x31,0x53,0xc4,0x3d,0x08,0x3b,0x6b,0x1b,0xce,0x4c,0x61,0x4e,0xc3,0x6c,0xce, |
4763 | | 0xd3,0x2a,0x63,0x33,0x45,0x17,0xe7,0x22,0x9c,0xf2,0x13,0x33,0x45,0x59,0xcc,0x07, |
4764 | | 0x38,0xa5,0x9a,0x99,0x62,0x36,0x67,0x5b,0x49,0xce,0xb2,0xba,0x30,0x53,0x9c,0xe2, |
4765 | | 0x66,0x8a,0xd7,0xdd,0x4c,0xd1,0xce,0x9d,0x41,0x4d,0xe5,0xdc,0x69,0x87,0xd8,0x4c, |
4766 | | 0x31,0x94,0xf3,0xa5,0x6b,0xdc,0x3e,0x7c,0x98,0x29,0x4a,0xd9,0x7d,0x6f,0xc7,0xb9, |
4767 | | 0x52,0x2f,0xce,0x93,0xec,0xec,0xe8,0x6a,0x37,0x53,0x84,0xf3,0xa2,0x6d,0xd8,0x29, |
4768 | | 0x3f,0x8a,0xf3,0xa1,0x27,0xd9,0x1d,0x7f,0xc1,0x9d,0x13,0xd9,0x4c,0x61,0xe7,0x44, |
4769 | | 0x17,0x57,0xb3,0x17,0xbe,0x07,0xbb,0xe0,0x2d,0x38,0x27,0xda,0xde,0xcd,0x14,0x27, |
4770 | | 0xb9,0x99,0xe2,0x1c,0x77,0x5e,0x64,0x7b,0xdb,0xad,0xe8,0xb2,0xb1,0x99,0x62,0x30, |
4771 | | 0xbb,0xda,0xf7,0xb3,0xa3,0x6d,0xe7,0x44,0x9f,0x30,0x53,0x84,0x7d,0xec,0x96,0x9c, |
4772 | | 0x17,0xcd,0x67,0xdf,0x7a,0xa9,0x9b,0x29,0xc2,0xf9,0x50,0xa5,0x9b,0x29,0x6a,0xb3, |
4773 | | 0xd3,0x7c,0x2a,0xbb,0xca,0xe1,0xbc,0xc8,0xce,0x8a,0xc2,0x19,0x51,0x53,0xce,0x86, |
4774 | | 0x06,0x71,0x26,0x74,0x8f,0x3b,0x0b,0xb2,0x99,0x62,0x1f,0x66,0x8a,0xf3,0x99,0x29, |
4775 | | 0x9e,0x77,0xe7,0x3d,0x4d,0xd9,0x23,0x1d,0xce,0x4c,0x31,0x99,0x9d,0xd1,0x30,0x53, |
4776 | | 0x34,0x63,0x37,0xb4,0x4d,0x35,0x33,0xc5,0x44,0xce,0x72,0xec,0x1c,0x67,0x79,0x9e, |
4777 | | 0x99,0xa2,0x36,0x67,0x35,0x61,0xa6,0x58,0xe7,0x66,0x8a,0x70,0x4e,0xe3,0x77,0xf5, |
4778 | | 0xec,0x5c,0xe6,0x39,0x37,0x53,0xbc,0xc2,0x4c,0x31,0x5f,0x79,0x93,0x99,0xe2,0x3d, |
4779 | | 0x66,0x8a,0x45,0x6e,0xa6,0x08,0x67,0x38,0x9f,0x57,0x33,0x53,0x8c,0x54,0xae,0x65, |
4780 | | 0xa6,0xb8,0xde,0xcd,0x14,0x37,0xbb,0x99,0xe2,0x51,0x65,0x3c,0x33,0xc5,0xee,0x6e, |
4781 | | 0xa6,0xa8,0xcf,0x59,0xd0,0xa3,0xae,0xef,0xf8,0x45,0xce,0x83,0x6c,0x6f,0xaf,0x05, |
4782 | | 0x33,0x45,0x17,0xce,0x85,0x8e,0x62,0xa6,0x18,0xac,0x5c,0xe0,0xf6,0xf8,0xc2,0x4c, |
4783 | | 0x31,0x41,0x79,0x8a,0x99,0xe2,0x69,0x65,0x2a,0x33,0xc5,0x74,0x66,0x8a,0x99,0x79, |
4784 | | 0x66,0x0a,0x3b,0x57,0x1a,0xc2,0x5e,0xdf,0x53,0xee,0x2c,0x29,0xc5,0xee,0x5e,0x2b, |
4785 | | 0x66,0x8a,0x2b,0xd9,0xd3,0x9b,0xc5,0x4c,0xb1,0x2f,0x33,0x45,0xdb,0xd8,0x4c,0xf1, |
4786 | | 0x29,0xfb,0x75,0x1d,0x98,0x29,0x6c,0x4f,0xae,0x22,0x36,0x53,0x84,0xb3,0x9c,0x4e, |
4787 | | 0xec,0xba,0xd9,0x4c,0x31,0x89,0x99,0xa2,0x82,0x33,0x9d,0x27,0xd9,0x5d,0xab,0xe0, |
4788 | | 0x2c,0xa7,0x1d,0x33,0x45,0x99,0x9b,0x29,0x9e,0x8c,0xcd,0x14,0x7b,0x73,0xbe,0xd3, |
4789 | | 0x96,0xf3,0x9d,0x0e,0x6e,0xa6,0xb0,0x5d,0xb1,0x30,0x53,0x14,0xb3,0x13,0x66,0x67, |
4790 | | 0x35,0xc7,0x72,0x4e,0x73,0x9b,0x3b,0xa7,0x39,0x95,0x99,0xc2,0x76,0xba,0x3a,0x71, |
4791 | | 0x46,0x53,0xce,0x0e,0x57,0x38,0xa7,0x89,0xef,0x6c,0x75,0xe5,0x1c,0xc6,0xcf,0x14, |
4792 | | 0x5f,0xb0,0x7b,0xd5,0x2e,0x36,0x53,0x94,0x71,0xc6,0xd2,0x90,0x33,0x96,0x70,0xbe, |
4793 | | 0x62,0x67,0x2b,0x76,0x96,0x72,0x37,0x7b,0x47,0xb6,0x57,0xd4,0x80,0xf3,0x92,0xe1, |
4794 | | 0x9c,0x8f,0x84,0xb3,0x91,0x2e,0x9c,0x85,0xb4,0x71,0x67,0x1e,0x57,0xb9,0x9d,0x9a, |
4795 | | 0xea,0x76,0x68,0xc2,0x4c,0x61,0xe7,0x18,0xe1,0xfc,0x22,0x9c,0x5d,0xac,0x70,0x33, |
4796 | | 0x85,0x9d,0x55,0xd8,0x6e,0xcb,0x11,0xcc,0x14,0xb6,0x5f,0x51,0xb8,0xfe,0x21,0x05, |
4797 | | 0xf3,0x4d,0x25,0x95,0xc2,0x54,0x61,0x3a,0x9d,0x72,0x8f,0xe9,0xf0,0x2c,0xe9,0x94, |
4798 | | 0x9e,0x5c,0xe8,0x9f,0x5c,0xe8,0x9f,0x49,0x7f,0x28,0x59,0x18,0x3d,0x9f,0xfd,0x76, |
4799 | | 0x2a,0xf7,0x67,0x93,0xa9,0xdc,0xef,0xf2,0x37,0x16,0xfe,0xf3,0x1f,0x52,0x7a,0x3d, |
4800 | | 0x52,0xb9,0xc7,0x4d,0x7a,0x48,0x56,0xf7,0x57,0x14,0x6c,0xea,0xcb,0x4a,0xa7,0xd3, |
4801 | | 0x05,0xe9,0x54,0x41,0xf4,0x5e,0x4a,0x6d,0xf8,0x5e,0xcb,0x3d,0x99,0xf7,0x5c,0x41, |
4802 | | 0x61,0xf4,0x5e,0xc8,0xfd,0xc8,0x73,0xe4,0x7e,0x28,0x28,0xfc,0xf5,0x3c,0xe4,0xde, |
4803 | | 0x63,0xff,0x07, |
4804 | | }; |
4805 | | } // namespace ada::idna::table_blob |
4806 | | #endif |
4807 | | /* end file src/table_blob.inc */ |
4808 | | |
4809 | | #include <atomic> |
4810 | | #include <bit> |
4811 | | #include <cstdint> |
4812 | | #include <cstddef> |
4813 | | #include <new> |
4814 | | |
4815 | | namespace ada::idna { |
4816 | | |
4817 | | // table_blob.inc is packed little-endian (see scripts/pack_tables.py). After |
4818 | | // inflate the multi-byte sections must be converted to host endianness so |
4819 | | // big-endian platforms (s390x) can load uint16_t/uint32_t/uint64_t natively. |
4820 | | // CRC is checked on the raw little-endian payload before any conversion. |
4821 | | namespace detail { |
4822 | | |
4823 | | template <typename T> |
4824 | 0 | inline void bswap_inplace(T* data, size_t count) noexcept { |
4825 | 0 | if constexpr (std::endian::native == std::endian::little) { |
4826 | 0 | (void)data; |
4827 | 0 | (void)count; |
4828 | 0 | return; |
4829 | 0 | } |
4830 | 0 | for (size_t i = 0; i < count; ++i) { |
4831 | 0 | if constexpr (sizeof(T) == 2) { |
4832 | 0 | #if defined(__GNUC__) || defined(__clang__) |
4833 | 0 | data[i] = |
4834 | 0 | static_cast<T>(__builtin_bswap16(static_cast<uint16_t>(data[i]))); |
4835 | 0 | #else |
4836 | 0 | const auto v = static_cast<uint16_t>(data[i]); |
4837 | 0 | data[i] = static_cast<T>(static_cast<uint16_t>((v >> 8) | (v << 8))); |
4838 | 0 | #endif |
4839 | 0 | } else if constexpr (sizeof(T) == 4) { |
4840 | 0 | #if defined(__GNUC__) || defined(__clang__) |
4841 | 0 | data[i] = |
4842 | 0 | static_cast<T>(__builtin_bswap32(static_cast<uint32_t>(data[i]))); |
4843 | 0 | #else |
4844 | 0 | auto v = static_cast<uint32_t>(data[i]); |
4845 | 0 | v = ((v & 0x000000FFu) << 24) | ((v & 0x0000FF00u) << 8) | |
4846 | 0 | ((v & 0x00FF0000u) >> 8) | ((v & 0xFF000000u) >> 24); |
4847 | 0 | data[i] = static_cast<T>(v); |
4848 | 0 | #endif |
4849 | 0 | } else if constexpr (sizeof(T) == 8) { |
4850 | 0 | #if defined(__GNUC__) || defined(__clang__) |
4851 | 0 | data[i] = |
4852 | 0 | static_cast<T>(__builtin_bswap64(static_cast<uint64_t>(data[i]))); |
4853 | 0 | #else |
4854 | 0 | auto v = static_cast<uint64_t>(data[i]); |
4855 | 0 | v = ((v & 0x00000000000000FFull) << 56) | |
4856 | 0 | ((v & 0x000000000000FF00ull) << 40) | |
4857 | 0 | ((v & 0x0000000000FF0000ull) << 24) | |
4858 | 0 | ((v & 0x00000000FF000000ull) << 8) | |
4859 | 0 | ((v & 0x000000FF00000000ull) >> 8) | |
4860 | 0 | ((v & 0x0000FF0000000000ull) >> 24) | |
4861 | 0 | ((v & 0x00FF000000000000ull) >> 40) | |
4862 | 0 | ((v & 0xFF00000000000000ull) >> 56); |
4863 | 0 | data[i] = static_cast<T>(v); |
4864 | 0 | #endif |
4865 | 0 | } else { |
4866 | 0 | static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); |
4867 | 0 | } |
4868 | 0 | } |
4869 | 0 | } Unexecuted instantiation: void ada::idna::detail::bswap_inplace<unsigned short>(unsigned short*, unsigned long) Unexecuted instantiation: void ada::idna::detail::bswap_inplace<unsigned int>(unsigned int*, unsigned long) Unexecuted instantiation: void ada::idna::detail::bswap_inplace<unsigned long>(unsigned long*, unsigned long) |
4870 | | |
4871 | | // Convert every multi-byte section of the inflated little-endian blob to host |
4872 | | // order. Single-byte sections are left unchanged. Safe no-op on little-endian. |
4873 | 1 | inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept { |
4874 | 1 | if constexpr (std::endian::native == std::endian::little) { |
4875 | 1 | (void)buffer; |
4876 | 1 | return; |
4877 | 1 | } |
4878 | 0 | auto u16 = [&](size_t off, size_t count) { |
4879 | 1 | bswap_inplace(reinterpret_cast<uint16_t*>(buffer + off), count); |
4880 | 1 | }; |
4881 | 1 | auto u32 = [&](size_t off, size_t count) { |
4882 | 1 | bswap_inplace(reinterpret_cast<uint32_t*>(buffer + off), count); |
4883 | 1 | }; |
4884 | 1 | auto u64 = [&](size_t off, size_t count) { |
4885 | 1 | bswap_inplace(reinterpret_cast<uint64_t*>(buffer + off), count); |
4886 | 1 | }; |
4887 | | |
4888 | 1 | u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1); |
4889 | 1 | u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2); |
4890 | 1 | u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks); |
4891 | 1 | u16(table_blob::off_decomposition_block, |
4892 | 1 | table_blob::count_decomposition_block); |
4893 | 1 | u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data); |
4894 | 1 | u16(table_blob::off_composition_block, table_blob::count_composition_block); |
4895 | 1 | u32(table_blob::off_composition_data, table_blob::count_composition_data); |
4896 | 1 | u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat); |
4897 | 1 | u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat); |
4898 | 1 | u32(table_blob::off_dir_start, table_blob::count_dir_start); |
4899 | 1 | u32(table_blob::off_dir_final, table_blob::count_dir_final); |
4900 | 1 | u32(table_blob::off_combining_flat, table_blob::count_combining_flat); |
4901 | 1 | u32(table_blob::off_joining_start, table_blob::count_joining_start); |
4902 | 1 | u32(table_blob::off_joining_final, table_blob::count_joining_final); |
4903 | 1 | } |
4904 | | |
4905 | | } // namespace detail |
4906 | | |
4907 | | // --- Blob layout invariants -------------------------------------------------- |
4908 | | static_assert(table_blob::count_decomposition_index == 4352); |
4909 | | static_assert(table_blob::count_ccc_index == 4352); |
4910 | | static_assert(table_blob::count_composition_index == 4352); |
4911 | | static_assert(table_blob::count_decomposition_block == |
4912 | | table_blob::decomposition_block_rows * |
4913 | | table_blob::decomposition_block_cols); |
4914 | | static_assert(table_blob::count_ccc_block == |
4915 | | table_blob::ccc_block_rows * table_blob::ccc_block_cols); |
4916 | | static_assert(table_blob::count_composition_block == |
4917 | | table_blob::composition_block_rows * |
4918 | | table_blob::composition_block_cols); |
4919 | | static_assert(table_blob::count_dir_start == table_blob::dir_table_count && |
4920 | | table_blob::count_dir_final == table_blob::dir_table_count && |
4921 | | table_blob::count_dir_value == table_blob::dir_table_count); |
4922 | | static_assert( |
4923 | | table_blob::count_joining_start == table_blob::joining_table_count && |
4924 | | table_blob::count_joining_final == table_blob::joining_table_count && |
4925 | | table_blob::count_joining_value == table_blob::joining_table_count); |
4926 | | static_assert(table_blob::count_id_continue_flat == |
4927 | | table_blob::id_continue_count * 2); |
4928 | | static_assert(table_blob::count_id_start_flat == |
4929 | | table_blob::id_start_count * 2); |
4930 | | static_assert(table_blob::count_combining_flat == |
4931 | | table_blob::combining_range_count * 2); |
4932 | | static_assert(table_blob::off_idna_stage1 % alignof(uint16_t) == 0); |
4933 | | static_assert(table_blob::off_idna_stage2 % alignof(uint16_t) == 0); |
4934 | | static_assert(table_blob::off_idna_bool_blocks % alignof(uint64_t) == 0); |
4935 | | static_assert(table_blob::off_decomposition_block % alignof(uint16_t) == 0); |
4936 | | static_assert(table_blob::off_decomposition_data % alignof(char32_t) == 0); |
4937 | | static_assert(table_blob::off_composition_block % alignof(uint16_t) == 0); |
4938 | | static_assert(table_blob::off_composition_data % alignof(char32_t) == 0); |
4939 | | static_assert(table_blob::off_id_continue_flat % alignof(uint32_t) == 0); |
4940 | | static_assert(table_blob::off_id_start_flat % alignof(uint32_t) == 0); |
4941 | | static_assert(table_blob::off_dir_start % alignof(uint32_t) == 0); |
4942 | | static_assert(table_blob::off_dir_final % alignof(uint32_t) == 0); |
4943 | | static_assert(table_blob::off_combining_flat % alignof(uint32_t) == 0); |
4944 | | static_assert(table_blob::off_joining_start % alignof(uint32_t) == 0); |
4945 | | static_assert(table_blob::off_joining_final % alignof(uint32_t) == 0); |
4946 | | static_assert(table_blob::compressed_size == sizeof(table_blob::compressed)); |
4947 | | |
4948 | | // Every section must lie entirely inside the uncompressed buffer. |
4949 | | #define ADA_IDNA_SECTION_IN_BOUNDS(off, count, width) \ |
4950 | | static_assert((off) + (count) * (width) <= table_blob::uncompressed_size, \ |
4951 | | #off " overflows uncompressed buffer") |
4952 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_stage1, |
4953 | | table_blob::count_idna_stage1, 2); |
4954 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_stage2, |
4955 | | table_blob::count_idna_stage2, 2); |
4956 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_bool_blocks, |
4957 | | table_blob::count_idna_bool_blocks, 8); |
4958 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_idna_utf8_mappings, |
4959 | | table_blob::count_idna_utf8_mappings, 1); |
4960 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_index, |
4961 | | table_blob::count_decomposition_index, 1); |
4962 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_block, |
4963 | | table_blob::count_decomposition_block, 2); |
4964 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_decomposition_data, |
4965 | | table_blob::count_decomposition_data, 4); |
4966 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_ccc_index, |
4967 | | table_blob::count_ccc_index, 1); |
4968 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_ccc_block, |
4969 | | table_blob::count_ccc_block, 1); |
4970 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_index, |
4971 | | table_blob::count_composition_index, 1); |
4972 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_block, |
4973 | | table_blob::count_composition_block, 2); |
4974 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_composition_data, |
4975 | | table_blob::count_composition_data, 4); |
4976 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_id_continue_flat, |
4977 | | table_blob::count_id_continue_flat, 4); |
4978 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_id_start_flat, |
4979 | | table_blob::count_id_start_flat, 4); |
4980 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_start, |
4981 | | table_blob::count_dir_start, 4); |
4982 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_final, |
4983 | | table_blob::count_dir_final, 4); |
4984 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_dir_value, |
4985 | | table_blob::count_dir_value, 1); |
4986 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_combining_flat, |
4987 | | table_blob::count_combining_flat, 4); |
4988 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_joining_start, |
4989 | | table_blob::count_joining_start, 4); |
4990 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_joining_final, |
4991 | | table_blob::count_joining_final, 4); |
4992 | | ADA_IDNA_SECTION_IN_BOUNDS(table_blob::off_joining_value, |
4993 | | table_blob::count_joining_value, 1); |
4994 | | #undef ADA_IDNA_SECTION_IN_BOUNDS |
4995 | | |
4996 | | // --- Mapping ----------------------------------------------------------------- |
4997 | | inline const uint16_t* idna_stage1 = nullptr; |
4998 | | inline const uint16_t* idna_stage2 = nullptr; |
4999 | | inline const uint64_t* idna_bool_blocks = nullptr; |
5000 | | inline const uint8_t* idna_utf8_mappings = nullptr; |
5001 | | |
5002 | | // --- Normalization (O(1) multi-stage) ---------------------------------------- |
5003 | | inline const uint8_t* decomposition_index = nullptr; |
5004 | | inline const uint16_t* decomposition_block_flat = nullptr; |
5005 | | inline const char32_t* decomposition_data = nullptr; |
5006 | | inline const uint8_t* ccc_index = nullptr; |
5007 | | inline const uint8_t* ccc_block_flat = nullptr; |
5008 | | inline const uint8_t* composition_index = nullptr; |
5009 | | inline const uint16_t* composition_block_flat = nullptr; |
5010 | | inline const char32_t* composition_data = nullptr; |
5011 | | |
5012 | | // --- Identifier -------------------------------------------------------------- |
5013 | | // Pointer-to-array alias. CF17 vs CF22 disagree on spacing inside (*)[2]. |
5014 | | // clang-format off |
5015 | | using range_pair_ptr = const uint32_t(*)[2]; |
5016 | | // clang-format on |
5017 | | inline range_pair_ptr id_continue = nullptr; |
5018 | | inline range_pair_ptr id_start = nullptr; |
5019 | | |
5020 | | // --- Validity (const SoA) ---------------------------------------------------- |
5021 | | inline const uint32_t* dir_start = nullptr; |
5022 | | inline const uint32_t* dir_final = nullptr; |
5023 | | inline const uint8_t* dir_value = nullptr; |
5024 | | inline range_pair_ptr combining_ranges = nullptr; |
5025 | | inline const uint32_t* joining_start = nullptr; |
5026 | | inline const uint32_t* joining_final = nullptr; |
5027 | | inline const uint8_t* joining_value = nullptr; |
5028 | | |
5029 | | inline constexpr size_t id_continue_count = table_blob::id_continue_count; |
5030 | | inline constexpr size_t id_start_count = table_blob::id_start_count; |
5031 | | inline constexpr size_t dir_table_count = table_blob::dir_table_count; |
5032 | | inline constexpr size_t joining_table_count = table_blob::joining_table_count; |
5033 | | inline constexpr size_t combining_range_count = |
5034 | | table_blob::combining_range_count; |
5035 | | inline constexpr size_t idna_utf8_mappings_size = |
5036 | | table_blob::count_idna_utf8_mappings; |
5037 | | inline constexpr size_t decomposition_data_size = |
5038 | | table_blob::count_decomposition_data; |
5039 | | inline constexpr size_t composition_data_size = |
5040 | | table_blob::count_composition_data; |
5041 | | |
5042 | | inline constexpr size_t kDecompBlockCols = |
5043 | | table_blob::decomposition_block_cols; // 257 |
5044 | | inline constexpr size_t kCccBlockCols = table_blob::ccc_block_cols; // 256 |
5045 | | inline constexpr size_t kCompBlockCols = |
5046 | | table_blob::composition_block_cols; // 257 |
5047 | | inline constexpr size_t kDecompBlockRows = table_blob::decomposition_block_rows; |
5048 | | inline constexpr size_t kCccBlockRows = table_blob::ccc_block_rows; |
5049 | | inline constexpr size_t kCompBlockRows = table_blob::composition_block_rows; |
5050 | | |
5051 | | // Init state: 0=uninit, 1=in progress, 2=ready, 3=failed. |
5052 | | inline constexpr uint8_t kTablesUninit = 0; |
5053 | | inline constexpr uint8_t kTablesInProgress = 1; |
5054 | | inline constexpr uint8_t kTablesReady = 2; |
5055 | | inline constexpr uint8_t kTablesFailed = 3; |
5056 | | |
5057 | | inline std::atomic<uint8_t> tables_init_state{kTablesUninit}; |
5058 | | // Process-lifetime allocation published only by the winning init thread. |
5059 | | // Never freed: shared read-only data for the process. Do not dlclose a DSO |
5060 | | // that owns this buffer while other code may still call into ada::idna. |
5061 | | inline uint8_t* tables_buffer = nullptr; |
5062 | | |
5063 | | // Cap spin-wait so a stuck peer cannot hang the process forever. |
5064 | | inline constexpr uint64_t kTablesSpinLimit = 1'000'000'000ull; |
5065 | | |
5066 | | // ISO HDLC / zlib CRC-32 of the uncompressed table payload. |
5067 | | [[nodiscard]] inline uint32_t crc32_ieee(const uint8_t* data, |
5068 | 1 | size_t len) noexcept { |
5069 | 1 | uint32_t c = 0xFFFFFFFFu; |
5070 | 216k | for (size_t i = 0; i < len; ++i) { |
5071 | 216k | c ^= data[i]; |
5072 | 1.94M | for (int k = 0; k < 8; ++k) { |
5073 | 1.72M | const uint32_t mask = 0u - (c & 1u); |
5074 | 1.72M | c = (c >> 1) ^ (0xEDB88320u & mask); |
5075 | 1.72M | } |
5076 | 216k | } |
5077 | 1 | return ~c; |
5078 | 1 | } |
5079 | | |
5080 | 21.1k | [[nodiscard]] inline bool tables_are_ready() noexcept { |
5081 | 21.1k | return tables_init_state.load(std::memory_order_acquire) == kTablesReady; |
5082 | 21.1k | } |
5083 | | |
5084 | | // Returns true only when all table pointers are safe to use. |
5085 | 67.1k | [[nodiscard]] inline bool ensure_tables() noexcept { |
5086 | 67.1k | uint8_t state = tables_init_state.load(std::memory_order_acquire); |
5087 | 67.1k | if (state == kTablesReady) { |
5088 | 67.1k | return true; |
5089 | 67.1k | } |
5090 | 1 | if (state == kTablesFailed) { |
5091 | 0 | return false; |
5092 | 0 | } |
5093 | | |
5094 | 1 | uint8_t expected = kTablesUninit; |
5095 | 1 | if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress, |
5096 | 1 | std::memory_order_acq_rel, |
5097 | 1 | std::memory_order_acquire)) { |
5098 | 1 | uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size]; |
5099 | 1 | if (buffer == nullptr) { |
5100 | 0 | tables_init_state.store(kTablesFailed, std::memory_order_release); |
5101 | 0 | return false; |
5102 | 0 | } |
5103 | | |
5104 | 1 | const size_t n = deflate::inflate_raw(table_blob::compressed, |
5105 | 1 | table_blob::compressed_size, buffer, |
5106 | 1 | table_blob::uncompressed_size); |
5107 | 1 | if (n != table_blob::uncompressed_size || |
5108 | 1 | crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) { |
5109 | 0 | delete[] buffer; |
5110 | 0 | tables_init_state.store(kTablesFailed, std::memory_order_release); |
5111 | 0 | return false; |
5112 | 0 | } |
5113 | | |
5114 | | // LE payload verified; convert multi-byte fields for big-endian hosts. |
5115 | 1 | detail::convert_table_blob_to_host_endian(buffer); |
5116 | | |
5117 | 21 | auto at = [&](size_t off) noexcept -> const uint8_t* { |
5118 | 21 | return buffer + off; |
5119 | 21 | }; |
5120 | | |
5121 | | // Publish all non-atomic pointers before READY. Waiters synchronize via |
5122 | | // acquire on tables_init_state and then observe these writes. |
5123 | 1 | idna_stage1 = |
5124 | 1 | reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage1)); |
5125 | 1 | idna_stage2 = |
5126 | 1 | reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage2)); |
5127 | 1 | idna_bool_blocks = |
5128 | 1 | reinterpret_cast<const uint64_t*>(at(table_blob::off_idna_bool_blocks)); |
5129 | 1 | idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings); |
5130 | | |
5131 | 1 | decomposition_index = at(table_blob::off_decomposition_index); |
5132 | 1 | decomposition_block_flat = reinterpret_cast<const uint16_t*>( |
5133 | 1 | at(table_blob::off_decomposition_block)); |
5134 | 1 | decomposition_data = reinterpret_cast<const char32_t*>( |
5135 | 1 | at(table_blob::off_decomposition_data)); |
5136 | 1 | ccc_index = at(table_blob::off_ccc_index); |
5137 | 1 | ccc_block_flat = at(table_blob::off_ccc_block); |
5138 | 1 | composition_index = at(table_blob::off_composition_index); |
5139 | 1 | composition_block_flat = reinterpret_cast<const uint16_t*>( |
5140 | 1 | at(table_blob::off_composition_block)); |
5141 | 1 | composition_data = |
5142 | 1 | reinterpret_cast<const char32_t*>(at(table_blob::off_composition_data)); |
5143 | | |
5144 | 1 | id_continue = |
5145 | 1 | reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_continue_flat)); |
5146 | 1 | id_start = |
5147 | 1 | reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_start_flat)); |
5148 | | |
5149 | 1 | dir_start = |
5150 | 1 | reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_start)); |
5151 | 1 | dir_final = |
5152 | 1 | reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_final)); |
5153 | 1 | dir_value = at(table_blob::off_dir_value); |
5154 | 1 | combining_ranges = |
5155 | 1 | reinterpret_cast<range_pair_ptr>(at(table_blob::off_combining_flat)); |
5156 | 1 | joining_start = |
5157 | 1 | reinterpret_cast<const uint32_t*>(at(table_blob::off_joining_start)); |
5158 | 1 | joining_final = |
5159 | 1 | reinterpret_cast<const uint32_t*>(at(table_blob::off_joining_final)); |
5160 | 1 | joining_value = at(table_blob::off_joining_value); |
5161 | | |
5162 | 1 | tables_buffer = buffer; |
5163 | 1 | tables_init_state.store(kTablesReady, std::memory_order_release); |
5164 | 1 | return true; |
5165 | 1 | } |
5166 | | |
5167 | | // Another thread owns init (or finished between our loads). |
5168 | 0 | for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) { |
5169 | 0 | state = tables_init_state.load(std::memory_order_acquire); |
5170 | 0 | if (state == kTablesReady) { |
5171 | 0 | return true; |
5172 | 0 | } |
5173 | 0 | if (state == kTablesFailed) { |
5174 | 0 | return false; |
5175 | 0 | } |
5176 | 0 | #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ |
5177 | 0 | defined(_M_IX86) |
5178 | 0 | #if defined(__GNUC__) || defined(__clang__) |
5179 | 0 | __builtin_ia32_pause(); |
5180 | 0 | #endif |
5181 | | #elif defined(__aarch64__) || defined(_M_ARM64) |
5182 | | #if defined(__GNUC__) || defined(__clang__) |
5183 | | asm volatile("yield" ::: "memory"); |
5184 | | #endif |
5185 | | #endif |
5186 | 0 | } |
5187 | | // Timed out waiting for a peer - treat as failure rather than hang. |
5188 | 0 | return false; |
5189 | 0 | } |
5190 | | |
5191 | | // O(1) multi-stage accessors. Block indices from the tables are uint8_t and |
5192 | | // theoretically can be out of range if the blob is corrupt; clamp to a valid |
5193 | | // empty/default row (index 0) instead of reading OOB. |
5194 | 1.06M | inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept { |
5195 | 1.06M | if (bi >= kDecompBlockRows) { |
5196 | 0 | bi = 0; |
5197 | 0 | } |
5198 | 1.06M | return decomposition_block_flat + static_cast<size_t>(bi) * kDecompBlockCols; |
5199 | 1.06M | } |
5200 | | |
5201 | 1.56M | inline const uint8_t* ccc_block_row(uint8_t bi) noexcept { |
5202 | 1.56M | if (bi >= kCccBlockRows) { |
5203 | 0 | bi = 0; |
5204 | 0 | } |
5205 | 1.56M | return ccc_block_flat + static_cast<size_t>(bi) * kCccBlockCols; |
5206 | 1.56M | } |
5207 | | |
5208 | 560k | inline const uint16_t* composition_block_row(uint8_t bi) noexcept { |
5209 | 560k | if (bi >= kCompBlockRows) { |
5210 | 0 | bi = 0; |
5211 | 0 | } |
5212 | 560k | return composition_block_flat + static_cast<size_t>(bi) * kCompBlockCols; |
5213 | 560k | } |
5214 | | |
5215 | | } // namespace ada::idna |
5216 | | /* end file src/table_store.hpp */ |
5217 | | /* begin file src/mapping_tables.cpp */ |
5218 | | // IDNA 18.0.0 |
5219 | | // Two-level compressed mapping table (constants only). |
5220 | | // Array payloads are stored in the DEFLATE blob (see table_store.hpp / |
5221 | | // scripts/pack_tables.py). |
5222 | | // Regenerate with: python3 scripts/idna_table.py --write |
5223 | | // Logical table size: 51037 bytes (49.8 KB) |
5224 | | // stage1: 8162 bytes (4081 uint16_t entries) |
5225 | | // stage2: 23424 bytes (183 mixed blocks x 64) |
5226 | | // bool_blocks: 1800 bytes (225 uint64_t words) |
5227 | | // utf8 maps: 17651 bytes |
5228 | | |
5229 | | // clang-format off |
5230 | | #ifndef ADA_IDNA_MAPPING_TABLE_H |
5231 | | #define ADA_IDNA_MAPPING_TABLE_H |
5232 | | #include <cstdint> |
5233 | | |
5234 | | namespace ada::idna { |
5235 | | |
5236 | | // Block size for two-level table (2^6 = 64 code points per block). |
5237 | | constexpr uint32_t IDNA_BLOCK_BITS = 6u; |
5238 | | constexpr uint32_t IDNA_BLOCK_SIZE = 64u; |
5239 | | constexpr uint32_t IDNA_BLOCK_MASK = 63u; |
5240 | | |
5241 | | // Sentinel values stored in stage2 / returned by lookup. |
5242 | | constexpr uint16_t IDNA_VALID = 0xFFFF; // code point is valid as-is |
5243 | | constexpr uint16_t IDNA_DISALLOWED = 0xFFFE; // code point is disallowed |
5244 | | constexpr uint16_t IDNA_IGNORED = 0x0000; // ignored (index into empty UTF-8 entry) |
5245 | | |
5246 | | // Bit 15 of a stage1 entry: set = boolean block, clear = mixed block. |
5247 | | constexpr uint16_t IDNA_BOOL_FLAG = 0x8000; |
5248 | | |
5249 | | // Two-level table covers code points [0, IDNA_LOW_RANGE_END). |
5250 | | // Derived from the highest non-disallowed code point below the high-ignored range, |
5251 | | // rounded up to the next 64-code-point block boundary. |
5252 | | constexpr uint32_t IDNA_LOW_RANGE_END = 0x0003FC40; |
5253 | | |
5254 | | // Variation selectors supplement: U+E0100..U+E01EF are all ignored. |
5255 | | // These are handled with a simple range check; everything else above |
5256 | | // IDNA_LOW_RANGE_END is disallowed. |
5257 | | constexpr uint32_t IDNA_HIGH_IGNORED_START = 0x000E0100; |
5258 | | constexpr uint32_t IDNA_HIGH_IGNORED_END = 0x000E01F0; // exclusive |
5259 | | |
5260 | | // Large arrays (idna_stage1/stage2/bool_blocks/utf8_mappings) live in table_blob. |
5261 | | |
5262 | | } // namespace ada::idna |
5263 | | #endif // ADA_IDNA_MAPPING_TABLE_H |
5264 | | /* end file src/mapping_tables.cpp */ |
5265 | | |
5266 | | namespace ada::idna { |
5267 | | |
5268 | | // --- O(1) two-level table lookup --------------------------------------------- |
5269 | | // |
5270 | | // Returns one of: |
5271 | | // IDNA_VALID - keep code point in output unchanged |
5272 | | // IDNA_DISALLOWED - code point is not allowed (map() returns error) |
5273 | | // IDNA_IGNORED - code point is ignored (index 0 = empty UTF-8 entry) |
5274 | | // other - byte offset into idna_utf8_mappings[] (null-terminated) |
5275 | | // |
5276 | | // Assumes ensure_tables() has already been called by the public entry point. |
5277 | 690k | static uint16_t idna_lookup(uint32_t cp) noexcept { |
5278 | 690k | if (cp < IDNA_LOW_RANGE_END) { |
5279 | 688k | uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS]; |
5280 | 688k | if (ref & IDNA_BOOL_FLAG) { |
5281 | 300k | uint32_t bit_idx = |
5282 | 300k | static_cast<uint32_t>(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE + |
5283 | 300k | (cp & IDNA_BLOCK_MASK); |
5284 | 300k | bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u; |
5285 | 300k | return is_valid ? IDNA_VALID : IDNA_DISALLOWED; |
5286 | 300k | } |
5287 | 388k | return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)]; |
5288 | 688k | } |
5289 | | |
5290 | 2.31k | if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) { |
5291 | 1.96k | return IDNA_IGNORED; |
5292 | 1.96k | } |
5293 | | |
5294 | 345 | return IDNA_DISALLOWED; |
5295 | 2.31k | } |
5296 | | |
5297 | | // Advances *ptr past one well-formed UTF-8 code point from the mapping table. |
5298 | 413k | static char32_t utf8_next(const uint8_t*& ptr) noexcept { |
5299 | 413k | uint8_t b0 = *ptr++; |
5300 | 413k | if (b0 < 0x80u) return static_cast<char32_t>(b0); |
5301 | 306k | if (b0 < 0xE0u) { |
5302 | 185k | uint32_t cp = (b0 & 0x1Fu) << 6; |
5303 | 185k | cp |= (*ptr++ & 0x3Fu); |
5304 | 185k | return static_cast<char32_t>(cp); |
5305 | 185k | } |
5306 | 121k | if (b0 < 0xF0u) { |
5307 | 119k | uint32_t cp = (b0 & 0x0Fu) << 12; |
5308 | 119k | cp |= ((*ptr++ & 0x3Fu) << 6); |
5309 | 119k | cp |= (*ptr++ & 0x3Fu); |
5310 | 119k | return static_cast<char32_t>(cp); |
5311 | 119k | } |
5312 | 1.68k | uint32_t cp = (b0 & 0x07u) << 18; |
5313 | 1.68k | cp |= ((*ptr++ & 0x3Fu) << 12); |
5314 | 1.68k | cp |= ((*ptr++ & 0x3Fu) << 6); |
5315 | 1.68k | cp |= (*ptr++ & 0x3Fu); |
5316 | 1.68k | return static_cast<char32_t>(cp); |
5317 | 121k | } |
5318 | | |
5319 | | // Count UTF-8 code points in a null-terminated mapping string (trusted table). |
5320 | 103k | static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept { |
5321 | 103k | size_t n = 0; |
5322 | 518k | while (*ptr != 0) { |
5323 | 415k | ++n; |
5324 | 415k | if (*ptr < 0x80u) { |
5325 | 107k | ++ptr; |
5326 | 308k | } else if (*ptr < 0xE0u) { |
5327 | 185k | ptr += 2; |
5328 | 185k | } else if (*ptr < 0xF0u) { |
5329 | 121k | ptr += 3; |
5330 | 121k | } else { |
5331 | 1.68k | ptr += 4; |
5332 | 1.68k | } |
5333 | 415k | } |
5334 | 103k | return n; |
5335 | 103k | } |
5336 | | |
5337 | | // --- ASCII fast path --------------------------------------------------------- |
5338 | 6.28k | void ascii_map(char* input, size_t length) { |
5339 | 18.8k | auto broadcast = [](uint8_t v) -> uint64_t { |
5340 | 18.8k | return 0x101010101010101ull * v; |
5341 | 18.8k | }; |
5342 | 6.28k | uint64_t broadcast_80 = broadcast(0x80); |
5343 | 6.28k | uint64_t broadcast_Ap = broadcast(128 - 'A'); |
5344 | 6.28k | uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); |
5345 | 6.28k | size_t i = 0; |
5346 | | |
5347 | 54.2k | for (; i + 7 < length; i += 8) { |
5348 | 47.9k | uint64_t word{}; |
5349 | 47.9k | std::memcpy(&word, input + i, sizeof(word)); |
5350 | 47.9k | word ^= |
5351 | 47.9k | (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; |
5352 | 47.9k | std::memcpy(input + i, &word, sizeof(word)); |
5353 | 47.9k | } |
5354 | 6.28k | if (i < length) { |
5355 | 5.46k | uint64_t word{}; |
5356 | 5.46k | std::memcpy(&word, input + i, length - i); |
5357 | 5.46k | word ^= |
5358 | 5.46k | (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; |
5359 | 5.46k | std::memcpy(input + i, &word, length - i); |
5360 | 5.46k | } |
5361 | 6.28k | } |
5362 | | |
5363 | | // Two-pass map: first validate + exact size, then write once (no growth |
5364 | | // realloc). |
5365 | 19.3k | bool map(std::u32string_view input, std::u32string& out) { |
5366 | | // [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap). |
5367 | 19.3k | out.clear(); |
5368 | 19.3k | if (!ensure_tables()) { |
5369 | 0 | return false; |
5370 | 0 | } |
5371 | | |
5372 | | // Pass 1: validate and compute exact output length. |
5373 | 19.3k | size_t out_size = 0; |
5374 | 346k | for (char32_t x : input) { |
5375 | 346k | uint16_t status = idna_lookup(static_cast<uint32_t>(x)); |
5376 | 346k | if (status == IDNA_DISALLOWED) { |
5377 | 543 | return false; |
5378 | 543 | } |
5379 | 345k | if (status == IDNA_VALID) { |
5380 | 242k | ++out_size; |
5381 | 242k | continue; |
5382 | 242k | } |
5383 | 103k | if (static_cast<size_t>(status) >= idna_utf8_mappings_size) { |
5384 | 0 | return false; |
5385 | 0 | } |
5386 | 103k | out_size += utf8_count_codepoints(idna_utf8_mappings + status); |
5387 | 103k | } |
5388 | | |
5389 | | // Pass 2: write into a single allocation. |
5390 | 18.7k | out.resize(out_size); |
5391 | 18.7k | size_t w = 0; |
5392 | 344k | for (char32_t x : input) { |
5393 | 344k | uint16_t status = idna_lookup(static_cast<uint32_t>(x)); |
5394 | 344k | if (status == IDNA_VALID) { |
5395 | 241k | out[w++] = x; |
5396 | 241k | continue; |
5397 | 241k | } |
5398 | | // IGNORED or mapped (status already validated in pass 1). |
5399 | 102k | const uint8_t* ptr = idna_utf8_mappings + status; |
5400 | 516k | while (*ptr != 0) { |
5401 | 413k | out[w++] = utf8_next(ptr); |
5402 | 413k | } |
5403 | 102k | } |
5404 | 18.7k | return true; |
5405 | 19.3k | } |
5406 | | |
5407 | 0 | std::u32string map(std::u32string_view input) { |
5408 | 0 | std::u32string answer; |
5409 | 0 | if (!map(input, answer)) { |
5410 | 0 | return {}; |
5411 | 0 | } |
5412 | 0 | return answer; |
5413 | 0 | } |
5414 | | |
5415 | | } // namespace ada::idna |
5416 | | /* end file src/mapping.cpp */ |
5417 | | /* begin file src/normalization.cpp */ |
5418 | | /* begin file include/ada/idna/normalization.h */ |
5419 | | #ifndef ADA_IDNA_NORMALIZATION_H |
5420 | | #define ADA_IDNA_NORMALIZATION_H |
5421 | | |
5422 | | #include <string> |
5423 | | #include <string_view> |
5424 | | |
5425 | | namespace ada::idna { |
5426 | | |
5427 | | // Returns true if `input` is already in Unicode Normalization Form C. |
5428 | | // Requires that internal tables have been loaded (call ensure via normalize |
5429 | | // or map first, or this returns false if tables are unavailable). |
5430 | | [[nodiscard]] bool is_already_nfc(std::u32string_view input) noexcept; |
5431 | | |
5432 | | // Normalize the characters according to IDNA (Unicode Normalization Form C). |
5433 | | // Returns false if the internal Unicode tables could not be loaded; in that |
5434 | | // case `input` is left unchanged. Skips work when the string is already NFC. |
5435 | | [[nodiscard]] bool normalize(std::u32string& input); |
5436 | | |
5437 | | } // namespace ada::idna |
5438 | | #endif |
5439 | | /* end file include/ada/idna/normalization.h */ |
5440 | | /* begin file src/normalization_tables.cpp */ |
5441 | | // Normalization table helpers. |
5442 | | // Array payloads live in the DEFLATE blob (table_store.hpp). |
5443 | | // Regenerate with: python3 scripts/unicode_data_table.py --write |
5444 | | // clang-format off |
5445 | | #ifndef ADA_IDNA_NORMALIZATION_TABLES_H |
5446 | | #define ADA_IDNA_NORMALIZATION_TABLES_H |
5447 | | |
5448 | | namespace ada::idna { |
5449 | | |
5450 | | // Accessors and multi-stage tables are provided by table_store.hpp after |
5451 | | // ensure_tables(). Lookup code matches the classic O(1) uni-algo layout. |
5452 | | |
5453 | | } // namespace ada::idna |
5454 | | #endif // ADA_IDNA_NORMALIZATION_TABLES_H |
5455 | | /* end file src/normalization_tables.cpp */ |
5456 | | |
5457 | | #include <cstdint> |
5458 | | |
5459 | | namespace ada::idna { |
5460 | | |
5461 | | // See |
5462 | | // https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/impl_norm.h#L467 |
5463 | | constexpr char32_t hangul_sbase = 0xAC00; |
5464 | | constexpr char32_t hangul_tbase = 0x11A7; |
5465 | | constexpr char32_t hangul_vbase = 0x1161; |
5466 | | constexpr char32_t hangul_lbase = 0x1100; |
5467 | | constexpr char32_t hangul_lcount = 19; |
5468 | | constexpr char32_t hangul_vcount = 21; |
5469 | | constexpr char32_t hangul_tcount = 28; |
5470 | | constexpr char32_t hangul_ncount = hangul_vcount * hangul_tcount; |
5471 | | constexpr char32_t hangul_scount = |
5472 | | hangul_lcount * hangul_vcount * hangul_tcount; |
5473 | | |
5474 | | // Canonical decomposition length (0 if none / compatibility-only / Hangul |
5475 | | // syllable). Length 1 means a singleton mapping (character is not NFC form). |
5476 | | // Length >= 2 means a primary composite that is already the NFC form of its |
5477 | | // decomposition (e.g. U+00E9 LATIN SMALL LETTER E WITH ACUTE). |
5478 | 455k | static size_t canonical_decomp_length(char32_t current_character) noexcept { |
5479 | 455k | if (current_character >= hangul_sbase && |
5480 | 15.9k | current_character < hangul_sbase + hangul_scount) { |
5481 | | // Hangul precomposed syllables are NFC. |
5482 | 8.87k | return 0; |
5483 | 8.87k | } |
5484 | 447k | if (current_character >= 0x110000) { |
5485 | 0 | return 0; |
5486 | 0 | } |
5487 | 447k | const uint8_t di = decomposition_index[current_character >> 8]; |
5488 | 447k | const uint16_t* const decomposition = |
5489 | 447k | decomposition_block_row(di) + (current_character % 256); |
5490 | 447k | size_t decomposition_length = |
5491 | 447k | (decomposition[1] >> 2) - (decomposition[0] >> 2); |
5492 | 447k | if ((decomposition_length > 0) && (decomposition[0] & 1)) { |
5493 | 0 | decomposition_length = 0; // compatibility-only: ignored for NFC |
5494 | 0 | } |
5495 | 447k | return decomposition_length; |
5496 | 447k | } |
5497 | | |
5498 | | std::pair<bool, size_t> compute_decomposition_length( |
5499 | 5.65k | const std::u32string_view input) noexcept { |
5500 | 5.65k | bool decomposition_needed{false}; |
5501 | 5.65k | size_t additional_elements{0}; |
5502 | 83.7k | for (char32_t current_character : input) { |
5503 | 83.7k | size_t decomposition_length{0}; |
5504 | | |
5505 | 83.7k | if (current_character >= hangul_sbase && |
5506 | 7.89k | current_character < hangul_sbase + hangul_scount) { |
5507 | | // Full NFD-style Hangul decomp for the decompose() step. |
5508 | 4.87k | decomposition_length = 2; |
5509 | 4.87k | if ((current_character - hangul_sbase) % hangul_tcount) { |
5510 | 2.07k | decomposition_length = 3; |
5511 | 2.07k | } |
5512 | 78.8k | } else if (current_character < 0x110000) { |
5513 | 78.8k | const uint8_t di = decomposition_index[current_character >> 8]; |
5514 | 78.8k | const uint16_t* const decomposition = |
5515 | 78.8k | decomposition_block_row(di) + (current_character % 256); |
5516 | 78.8k | decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2); |
5517 | 78.8k | if ((decomposition_length > 0) && (decomposition[0] & 1)) { |
5518 | 0 | decomposition_length = 0; |
5519 | 0 | } |
5520 | 78.8k | } |
5521 | 83.7k | if (decomposition_length != 0) { |
5522 | 17.5k | decomposition_needed = true; |
5523 | 17.5k | additional_elements += decomposition_length - 1; |
5524 | 17.5k | } |
5525 | 83.7k | } |
5526 | 5.65k | return {decomposition_needed, additional_elements}; |
5527 | 5.65k | } |
5528 | | |
5529 | 4.54k | void decompose(std::u32string& input, size_t additional_elements) { |
5530 | 4.54k | input.resize(input.size() + additional_elements); |
5531 | 4.54k | for (size_t descending_idx = input.size(), |
5532 | 4.54k | input_count = descending_idx - additional_elements; |
5533 | 51.0k | input_count--;) { |
5534 | 46.4k | if (input[input_count] >= hangul_sbase && |
5535 | 6.58k | input[input_count] < hangul_sbase + hangul_scount) { |
5536 | | // Hangul decomposition. |
5537 | 4.87k | char32_t s_index = input[input_count] - hangul_sbase; |
5538 | 4.87k | if (s_index % hangul_tcount != 0) { |
5539 | 2.07k | input[--descending_idx] = hangul_tbase + s_index % hangul_tcount; |
5540 | 2.07k | } |
5541 | 4.87k | input[--descending_idx] = |
5542 | 4.87k | hangul_vbase + (s_index % hangul_ncount) / hangul_tcount; |
5543 | 4.87k | input[--descending_idx] = hangul_lbase + s_index / hangul_ncount; |
5544 | 41.6k | } else if (input[input_count] < 0x110000) { |
5545 | 41.6k | const uint16_t* decomposition = |
5546 | 41.6k | decomposition_block_row( |
5547 | 41.6k | decomposition_index[input[input_count] >> 8]) + |
5548 | 41.6k | (input[input_count] % 256); |
5549 | 41.6k | uint16_t decomposition_length = |
5550 | 41.6k | (decomposition[1] >> 2) - (decomposition[0] >> 2); |
5551 | 41.6k | if (decomposition_length > 0 && (decomposition[0] & 1)) { |
5552 | 0 | decomposition_length = 0; |
5553 | 0 | } |
5554 | 41.6k | if (decomposition_length > 0) { |
5555 | 12.7k | const size_t base = static_cast<size_t>(decomposition[0] >> 2); |
5556 | 12.7k | if (base + decomposition_length > decomposition_data_size) { |
5557 | 0 | input[--descending_idx] = input[input_count]; |
5558 | 12.7k | } else { |
5559 | 41.1k | while (decomposition_length-- > 0) { |
5560 | 28.4k | input[--descending_idx] = |
5561 | 28.4k | decomposition_data[base + decomposition_length]; |
5562 | 28.4k | } |
5563 | 12.7k | } |
5564 | 28.8k | } else { |
5565 | 28.8k | input[--descending_idx] = input[input_count]; |
5566 | 28.8k | } |
5567 | 41.6k | } else { |
5568 | 0 | input[--descending_idx] = input[input_count]; |
5569 | 0 | } |
5570 | 46.4k | } |
5571 | 4.54k | } |
5572 | | |
5573 | 1.56M | uint8_t get_ccc(char32_t c) noexcept { |
5574 | 1.56M | if (c >= 0x110000) { |
5575 | 0 | return 0; |
5576 | 0 | } |
5577 | 1.56M | return ccc_block_row(ccc_index[c >> 8])[c % 256]; |
5578 | 1.56M | } |
5579 | | |
5580 | 5.65k | void sort_marks(std::u32string& input) { |
5581 | 106k | for (size_t idx = 1; idx < input.size(); idx++) { |
5582 | 100k | uint8_t ccc = get_ccc(input[idx]); |
5583 | 100k | if (ccc == 0) { |
5584 | 72.3k | continue; |
5585 | 72.3k | } |
5586 | 28.3k | auto current_character = input[idx]; |
5587 | 28.3k | size_t back_idx = idx; |
5588 | 38.5k | while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) { |
5589 | 10.1k | input[back_idx] = input[back_idx - 1]; |
5590 | 10.1k | back_idx--; |
5591 | 10.1k | } |
5592 | 28.3k | input[back_idx] = current_character; |
5593 | 28.3k | } |
5594 | 5.65k | } |
5595 | | |
5596 | 5.65k | void decompose_nfc(std::u32string& input) { |
5597 | | /** |
5598 | | * Decompose the domain_name string to Unicode Normalization Form C. |
5599 | | * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose |
5600 | | */ |
5601 | 5.65k | auto [decomposition_needed, additional_elements] = |
5602 | 5.65k | compute_decomposition_length(input); |
5603 | 5.65k | if (decomposition_needed) { |
5604 | 4.54k | decompose(input, additional_elements); |
5605 | 4.54k | } |
5606 | 5.65k | sort_marks(input); |
5607 | 5.65k | } |
5608 | | |
5609 | | // Returns true if the composition row of a starter has a pair with `second`. |
5610 | | static bool has_composition(const uint16_t* composition, |
5611 | 114k | char32_t second) noexcept { |
5612 | 114k | int left = composition[0]; |
5613 | 114k | int right = composition[1]; |
5614 | 114k | if (left < 0 || right <= left || |
5615 | 94.5k | static_cast<size_t>(right) > composition_data_size) { |
5616 | 20.3k | return false; |
5617 | 20.3k | } |
5618 | 260k | while (left + 2 < right) { |
5619 | 165k | int middle = left + (((right - left) >> 1) & ~1); |
5620 | 165k | if (composition_data[static_cast<size_t>(middle)] <= second) { |
5621 | 11.1k | left = middle; |
5622 | 11.1k | } |
5623 | 165k | if (composition_data[static_cast<size_t>(middle)] >= second) { |
5624 | 155k | right = middle; |
5625 | 155k | } |
5626 | 165k | } |
5627 | 94.5k | return static_cast<size_t>(left + 1) < composition_data_size && |
5628 | 94.5k | composition_data[static_cast<size_t>(left)] == second; |
5629 | 114k | } |
5630 | | |
5631 | | // Returns true if a composition step would change the string. |
5632 | 12.1k | static bool would_compose(std::u32string_view input) noexcept { |
5633 | 405k | for (size_t input_count = 0; input_count < input.size();) { |
5634 | 395k | const char32_t current = input[input_count]; |
5635 | 395k | if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) { |
5636 | 6.95k | if (input_count + 1 < input.size() && |
5637 | 6.71k | input[input_count + 1] >= hangul_vbase && |
5638 | 1.61k | input[input_count + 1] < hangul_vbase + hangul_vcount) { |
5639 | 300 | return true; |
5640 | 300 | } |
5641 | 6.65k | ++input_count; |
5642 | 6.65k | continue; |
5643 | 6.95k | } |
5644 | 388k | if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) { |
5645 | 4.42k | if ((current - hangul_sbase) % hangul_tcount == 0 && |
5646 | 2.77k | input_count + 1 < input.size() && |
5647 | 2.66k | input[input_count + 1] > hangul_tbase && |
5648 | 2.03k | input[input_count + 1] < hangul_tbase + hangul_tcount) { |
5649 | 120 | return true; |
5650 | 120 | } |
5651 | 4.30k | ++input_count; |
5652 | 4.30k | continue; |
5653 | 4.42k | } |
5654 | 384k | if (current < 0x110000) { |
5655 | 384k | const uint16_t* composition = |
5656 | 384k | composition_block_row(composition_index[current >> 8]) + |
5657 | 384k | (current % 256); |
5658 | 384k | int32_t previous_ccc = -1; |
5659 | 384k | size_t j = input_count; |
5660 | 392k | for (; j + 1 < input.size(); ++j) { |
5661 | 383k | uint8_t ccc = get_ccc(input[j + 1]); |
5662 | 383k | if (composition[1] != composition[0] && previous_ccc < ccc && |
5663 | 89.8k | has_composition(composition, input[j + 1])) { |
5664 | 1.89k | return true; |
5665 | 1.89k | } |
5666 | 381k | if (ccc == 0) { |
5667 | 373k | break; |
5668 | 373k | } |
5669 | 8.30k | previous_ccc = ccc; |
5670 | 8.30k | } |
5671 | 382k | input_count = j + 1; |
5672 | 382k | continue; |
5673 | 384k | } |
5674 | 0 | ++input_count; |
5675 | 0 | } |
5676 | 9.84k | return false; |
5677 | 12.1k | } |
5678 | | |
5679 | | // Trailing canonical combining class of a character: the combining class of the |
5680 | | // last code point of its canonical decomposition, or the character's own class |
5681 | | // when it has none. A precomposed starter such as U+00E1 (a + U+0301, class |
5682 | | // 230) has class 0 but a nonzero trailing class, so a following mark of lower |
5683 | | // class reorders past the hidden mark during normalization. |
5684 | 455k | static uint8_t trailing_ccc(char32_t c) noexcept { |
5685 | 455k | const size_t length = canonical_decomp_length(c); |
5686 | 455k | if (length == 0) { |
5687 | 426k | return get_ccc(c); |
5688 | 426k | } |
5689 | 29.5k | const uint16_t* const decomposition = |
5690 | 29.5k | decomposition_block_row(decomposition_index[c >> 8]) + (c % 256); |
5691 | 29.5k | const size_t base = decomposition[0] >> 2; |
5692 | 29.5k | return get_ccc(decomposition_data[base + length - 1]); |
5693 | 455k | } |
5694 | | |
5695 | | void compose(std::u32string& input); |
5696 | | |
5697 | | // A character that has a canonical decomposition is in NFC form only if that |
5698 | | // decomposition composes back to exactly it. Singletons never do (e.g. U+212B |
5699 | | // ANGSTROM SIGN). Composition exclusions do not either: their decomposition |
5700 | | // composes to a different primary composite (e.g. U+1F71 -> U+03B1 U+0301 -> |
5701 | | // U+03AC) or does not compose at all (e.g. U+0958 DEVANAGARI LETTER QA -> |
5702 | | // U+0915 U+093C), and non-starter decompositions such as U+0344 -> U+0308 |
5703 | | // U+0301 stay decomposed. All are NFC_Quick_Check=No and must be normalized. |
5704 | | // Since Unicode 16 the first code point of a decomposition can also compose |
5705 | | // with the preceding character: U+16121 is U+1611E U+1611E, so U+1611E U+16121 |
5706 | | // normalizes to U+16121 U+1611E. |
5707 | 483k | static bool decomposition_is_not_nfc(char32_t previous, char32_t c) noexcept { |
5708 | 483k | if (c >= hangul_sbase && c < hangul_sbase + hangul_scount) { |
5709 | 12.7k | return false; |
5710 | 12.7k | } |
5711 | 470k | if (c >= 0x110000) { |
5712 | 0 | return false; |
5713 | 0 | } |
5714 | 470k | const uint16_t* const decomposition = |
5715 | 470k | decomposition_block_row(decomposition_index[c >> 8]) + (c % 256); |
5716 | 470k | const size_t length = (decomposition[1] >> 2) - (decomposition[0] >> 2); |
5717 | 470k | if (length == 0 || (decomposition[0] & 1)) { |
5718 | 437k | return false; // no canonical decomposition (or compatibility-only) |
5719 | 437k | } |
5720 | 33.0k | if (length == 1) { |
5721 | 0 | return true; // singleton |
5722 | 0 | } |
5723 | 33.0k | const size_t base = decomposition[0] >> 2; |
5724 | 33.0k | if (base + length > decomposition_data_size) { |
5725 | 0 | return false; |
5726 | 0 | } |
5727 | | // Recompose the canonical decomposition; if it does not collapse back to c, |
5728 | | // then c is an exclusion / non-starter decomposition and is not NFC. |
5729 | 33.0k | std::u32string decomposed(decomposition_data + base, |
5730 | 33.0k | decomposition_data + base + length); |
5731 | 33.0k | compose(decomposed); |
5732 | 33.0k | if (!(decomposed.size() == 1 && decomposed[0] == c)) { |
5733 | 0 | return true; |
5734 | 0 | } |
5735 | 33.0k | return previous < 0x110000 && |
5736 | 25.0k | has_composition( |
5737 | 25.0k | composition_block_row(composition_index[previous >> 8]) + |
5738 | 25.0k | (previous % 256), |
5739 | 25.0k | decomposition_data[base]); |
5740 | 33.0k | } |
5741 | | |
5742 | 21.1k | bool is_already_nfc(std::u32string_view input) noexcept { |
5743 | 21.1k | if (input.empty()) { |
5744 | 0 | return true; |
5745 | 0 | } |
5746 | 21.1k | if (!tables_are_ready() && !ensure_tables()) { |
5747 | 0 | return false; |
5748 | 0 | } |
5749 | | // 1) A character whose canonical decomposition does not compose back to it is |
5750 | | // not NFC: singletons (e.g. U+212B), composition exclusions (e.g. U+0958) |
5751 | | // and non-starter decompositions (e.g. U+0344), or one whose |
5752 | | // decomposition starts with a code point that composes with the previous |
5753 | | // character (e.g. U+1611E U+16121). |
5754 | 21.1k | char32_t previous = 0x110000; // none |
5755 | 483k | for (char32_t c : input) { |
5756 | 483k | if (decomposition_is_not_nfc(previous, c)) { |
5757 | 30 | return false; |
5758 | 30 | } |
5759 | 483k | previous = c; |
5760 | 483k | } |
5761 | | // 2) Combining marks already in canonical order. prev_ccc carries the |
5762 | | // trailing class of the previous character's canonical decomposition so a |
5763 | | // composite starter followed by a lower-class mark is caught. |
5764 | 21.1k | uint8_t prev_ccc = 0; |
5765 | 464k | for (char32_t c : input) { |
5766 | 464k | uint8_t ccc = get_ccc(c); |
5767 | 464k | if (ccc != 0 && prev_ccc > ccc) { |
5768 | 8.96k | return false; |
5769 | 8.96k | } |
5770 | 455k | prev_ccc = trailing_ccc(c); |
5771 | 455k | } |
5772 | | // 3) No pairwise composition would apply (including Hangul L+V / LV+T). |
5773 | 12.1k | return !would_compose(input); |
5774 | 21.1k | } |
5775 | | |
5776 | 38.6k | void compose(std::u32string& input) { |
5777 | | /** |
5778 | | * Compose the domain_name string to Unicode Normalization Form C. |
5779 | | * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose |
5780 | | */ |
5781 | 38.6k | size_t input_count{0}; |
5782 | 38.6k | size_t composition_count{0}; |
5783 | 142k | for (; input_count < input.size(); input_count++, composition_count++) { |
5784 | 103k | input[composition_count] = input[input_count]; |
5785 | 103k | if (input[input_count] >= hangul_lbase && |
5786 | 20.1k | input[input_count] < hangul_lbase + hangul_lcount) { |
5787 | 8.77k | if (input_count + 1 < input.size() && |
5788 | 8.73k | input[input_count + 1] >= hangul_vbase && |
5789 | 5.61k | input[input_count + 1] < hangul_vbase + hangul_vcount) { |
5790 | 5.04k | input[composition_count] = |
5791 | 5.04k | hangul_sbase + |
5792 | 5.04k | ((input[input_count] - hangul_lbase) * hangul_vcount + |
5793 | 5.04k | input[input_count + 1] - hangul_vbase) * |
5794 | 5.04k | hangul_tcount; |
5795 | 5.04k | input_count++; |
5796 | 5.04k | if (input_count + 1 < input.size() && |
5797 | 4.89k | input[input_count + 1] > hangul_tbase && |
5798 | 2.69k | input[input_count + 1] < hangul_tbase + hangul_tcount) { |
5799 | 2.13k | input[composition_count] += input[++input_count] - hangul_tbase; |
5800 | 2.13k | } |
5801 | 5.04k | } |
5802 | 94.6k | } else if (input[input_count] >= hangul_sbase && |
5803 | 3.88k | input[input_count] < hangul_sbase + hangul_scount) { |
5804 | 0 | if ((input[input_count] - hangul_sbase) % hangul_tcount == 0 && |
5805 | 0 | input_count + 1 < input.size() && |
5806 | 0 | input[input_count + 1] > hangul_tbase && |
5807 | 0 | input[input_count + 1] < hangul_tbase + hangul_tcount) { |
5808 | 0 | input[composition_count] += input[++input_count] - hangul_tbase; |
5809 | 0 | } |
5810 | 94.6k | } else if (input[input_count] < 0x110000) { |
5811 | 94.6k | const uint16_t* composition = |
5812 | 94.6k | composition_block_row(composition_index[input[input_count] >> 8]) + |
5813 | 94.6k | (input[input_count] % 256); |
5814 | 94.6k | size_t initial_composition_count = composition_count; |
5815 | 163k | for (int32_t previous_ccc = -1; input_count + 1 < input.size(); |
5816 | 124k | input_count++) { |
5817 | 124k | uint8_t ccc = get_ccc(input[input_count + 1]); |
5818 | | |
5819 | 124k | if (composition[1] != composition[0] && previous_ccc < ccc) { |
5820 | 71.7k | int left = composition[0]; |
5821 | 71.7k | int right = composition[1]; |
5822 | 71.7k | if (left < 0 || right < left || |
5823 | 71.7k | static_cast<size_t>(right) > composition_data_size) { |
5824 | 0 | break; |
5825 | 0 | } |
5826 | 163k | while (left + 2 < right) { |
5827 | 91.8k | int middle = left + (((right - left) >> 1) & ~1); |
5828 | 91.8k | if (composition_data[static_cast<size_t>(middle)] <= |
5829 | 91.8k | input[input_count + 1]) { |
5830 | 65.9k | left = middle; |
5831 | 65.9k | } |
5832 | 91.8k | if (composition_data[static_cast<size_t>(middle)] >= |
5833 | 91.8k | input[input_count + 1]) { |
5834 | 64.2k | right = middle; |
5835 | 64.2k | } |
5836 | 91.8k | } |
5837 | 71.7k | if (static_cast<size_t>(left + 1) < composition_data_size && |
5838 | 71.7k | composition_data[static_cast<size_t>(left)] == |
5839 | 71.7k | input[input_count + 1]) { |
5840 | 56.3k | char32_t composed = composition_data[static_cast<size_t>(left + 1)]; |
5841 | 56.3k | input[initial_composition_count] = composed; |
5842 | 56.3k | composition = |
5843 | 56.3k | composition_block_row(composition_index[composed >> 8]) + |
5844 | 56.3k | (composed % 256); |
5845 | 56.3k | continue; |
5846 | 56.3k | } |
5847 | 71.7k | } |
5848 | | |
5849 | 68.3k | if (ccc == 0) { |
5850 | 56.2k | break; |
5851 | 56.2k | } |
5852 | 12.0k | previous_ccc = ccc; |
5853 | 12.0k | input[++composition_count] = input[input_count + 1]; |
5854 | 12.0k | } |
5855 | 94.6k | } |
5856 | 103k | } |
5857 | | |
5858 | 38.6k | if (composition_count < input_count) { |
5859 | 38.3k | input.resize(composition_count); |
5860 | 38.3k | } |
5861 | 38.6k | } |
5862 | | |
5863 | 5.65k | bool normalize(std::u32string& input) { |
5864 | | /** |
5865 | | * Normalize the characters according to IDNA (Unicode Normalization Form C). |
5866 | | * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize |
5867 | | */ |
5868 | 5.65k | if (!ensure_tables() || decomposition_index == nullptr || |
5869 | 5.65k | composition_index == nullptr) { |
5870 | 0 | return false; |
5871 | 0 | } |
5872 | 5.65k | if (is_already_nfc(input)) { |
5873 | 0 | return true; |
5874 | 0 | } |
5875 | 5.65k | decompose_nfc(input); |
5876 | 5.65k | compose(input); |
5877 | 5.65k | return true; |
5878 | 5.65k | } |
5879 | | |
5880 | | } // namespace ada::idna |
5881 | | /* end file src/normalization.cpp */ |
5882 | | /* begin file src/punycode.cpp */ |
5883 | | /* begin file include/ada/idna/punycode.h */ |
5884 | | #ifndef ADA_IDNA_PUNYCODE_H |
5885 | | #define ADA_IDNA_PUNYCODE_H |
5886 | | |
5887 | | #include <string> |
5888 | | #include <string_view> |
5889 | | |
5890 | | namespace ada::idna { |
5891 | | |
5892 | | bool punycode_to_utf32(std::string_view input, std::u32string& out); |
5893 | | bool verify_punycode(std::string_view input); |
5894 | | bool utf32_to_punycode(std::u32string_view input, std::string& out); |
5895 | | |
5896 | | } // namespace ada::idna |
5897 | | |
5898 | | #endif // ADA_IDNA_PUNYCODE_H |
5899 | | /* end file include/ada/idna/punycode.h */ |
5900 | | |
5901 | | #include <cstdint> |
5902 | | |
5903 | | namespace ada::idna { |
5904 | | |
5905 | | constexpr int32_t base = 36; |
5906 | | constexpr int32_t tmin = 1; |
5907 | | constexpr int32_t tmax = 26; |
5908 | | constexpr int32_t skew = 38; |
5909 | | constexpr int32_t damp = 700; |
5910 | | constexpr int32_t initial_bias = 72; |
5911 | | constexpr uint32_t initial_n = 128; |
5912 | | |
5913 | 93.3k | static constexpr int32_t char_to_digit_value(char value) { |
5914 | 93.3k | if (value >= 'a' && value <= 'z') return value - 'a'; |
5915 | 10.5k | if (value >= '0' && value <= '9') return value - '0' + 26; |
5916 | 69 | return -1; |
5917 | 10.5k | } |
5918 | | |
5919 | 404k | static constexpr char digit_to_char(int32_t digit) { |
5920 | 404k | return digit < 26 ? char(digit + 97) : char(digit + 22); |
5921 | 404k | } |
5922 | | |
5923 | 207k | static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) { |
5924 | 207k | if (firsttime) { |
5925 | 41.8k | d = d / damp; |
5926 | 165k | } else { |
5927 | 165k | d = d / 2; |
5928 | 165k | } |
5929 | 207k | d += d / n; |
5930 | 207k | int32_t k = 0; |
5931 | 292k | while (d > ((base - tmin) * tmax) / 2) { |
5932 | 85.2k | d /= base - tmin; |
5933 | 85.2k | k += base; |
5934 | 85.2k | } |
5935 | 207k | return k + (((base - tmin + 1) * d) / (d + skew)); |
5936 | 207k | } |
5937 | | |
5938 | 7.66k | bool punycode_to_utf32(std::string_view input, std::u32string &out) { |
5939 | 7.66k | int32_t written_out{0}; |
5940 | 7.66k | out.reserve(out.size() + input.size()); |
5941 | 7.66k | uint32_t n = initial_n; |
5942 | 7.66k | int32_t i = 0; |
5943 | 7.66k | int32_t bias = initial_bias; |
5944 | | // grab ascii content |
5945 | | // RFC 3492 section 6.2: copy the code points before the last delimiter, |
5946 | | // then consume the delimiter only "if more than zero code points were |
5947 | | // consumed". With a leading delimiter, b == 0, decoding starts at the |
5948 | | // delimiter itself, which is not a digit, and fails. This matches the |
5949 | | // reference implementation in appendix C (`in = b > 0 ? b + 1 : 0`). |
5950 | 7.66k | size_t end_of_ascii = input.find_last_of('-'); |
5951 | 7.66k | if (end_of_ascii != std::string_view::npos && end_of_ascii > 0) { |
5952 | 9.34k | for (uint8_t c : input.substr(0, end_of_ascii)) { |
5953 | 9.34k | if (c >= 0x80) { |
5954 | 0 | return false; |
5955 | 0 | } |
5956 | 9.34k | out.push_back(c); |
5957 | 9.34k | written_out++; |
5958 | 9.34k | } |
5959 | 975 | input.remove_prefix(end_of_ascii + 1); |
5960 | 975 | } |
5961 | 77.3k | while (!input.empty()) { |
5962 | 69.9k | int32_t oldi = i; |
5963 | 69.9k | int32_t w = 1; |
5964 | 93.5k | for (int32_t k = base;; k += base) { |
5965 | 93.5k | if (input.empty()) { |
5966 | 189 | return false; |
5967 | 189 | } |
5968 | 93.3k | uint8_t code_point = input.front(); |
5969 | 93.3k | input.remove_prefix(1); |
5970 | 93.3k | int32_t digit = char_to_digit_value(code_point); |
5971 | 93.3k | if (digit < 0) { |
5972 | 69 | return false; |
5973 | 69 | } |
5974 | 93.2k | if (digit > (0x7fffffff - i) / w) { |
5975 | 21 | return false; |
5976 | 21 | } |
5977 | 93.2k | i = i + digit * w; |
5978 | 93.2k | int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; |
5979 | 93.2k | if (digit < t) { |
5980 | 69.7k | break; |
5981 | 69.7k | } |
5982 | 23.5k | if (w > 0x7fffffff / (base - t)) { |
5983 | 0 | return false; |
5984 | 0 | } |
5985 | 23.5k | w = w * (base - t); |
5986 | 23.5k | } |
5987 | 69.7k | bias = adapt(i - oldi, written_out + 1, oldi == 0); |
5988 | 69.7k | if (i / (written_out + 1) > int32_t(0x7fffffff - n)) { |
5989 | 57 | return false; |
5990 | 57 | } |
5991 | 69.6k | n = n + i / (written_out + 1); |
5992 | 69.6k | i = i % (written_out + 1); |
5993 | 69.6k | if (n < 0x80) { |
5994 | 0 | return false; |
5995 | 0 | } |
5996 | 69.6k | out.insert(out.begin() + i, n); |
5997 | 69.6k | written_out++; |
5998 | 69.6k | ++i; |
5999 | 69.6k | } |
6000 | | // See https://github.com/whatwg/url/issues/803 |
6001 | | // Reject labels whose decoded form begins with "xn--" (double-encoded ACE). |
6002 | 7.33k | if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' && |
6003 | 87 | out[3] == U'-') { |
6004 | 12 | return false; |
6005 | 12 | } |
6006 | 7.32k | return true; |
6007 | 7.33k | } |
6008 | | |
6009 | 0 | bool verify_punycode(std::string_view input) { |
6010 | | // Track only the first 4 decoded code points to check for the "xn--" prefix. |
6011 | | // This avoids heap allocation while still detecting double-encoded ACE |
6012 | | // labels. |
6013 | 0 | uint32_t first4[4]{}; |
6014 | 0 | size_t written_out{0}; |
6015 | 0 | uint32_t n = initial_n; |
6016 | 0 | int32_t i = 0; |
6017 | 0 | int32_t bias = initial_bias; |
6018 | | // grab ascii content |
6019 | 0 | size_t end_of_ascii = input.find_last_of('-'); |
6020 | 0 | if (end_of_ascii != std::string_view::npos) { |
6021 | 0 | for (uint8_t c : input.substr(0, end_of_ascii)) { |
6022 | 0 | if (c >= 0x80) { |
6023 | 0 | return false; |
6024 | 0 | } |
6025 | 0 | if (written_out < 4) { |
6026 | 0 | first4[written_out] = c; |
6027 | 0 | } |
6028 | 0 | written_out++; |
6029 | 0 | } |
6030 | 0 | input.remove_prefix(end_of_ascii + 1); |
6031 | 0 | } |
6032 | 0 | while (!input.empty()) { |
6033 | 0 | int32_t oldi = i; |
6034 | 0 | int32_t w = 1; |
6035 | 0 | for (int32_t k = base;; k += base) { |
6036 | 0 | if (input.empty()) { |
6037 | 0 | return false; |
6038 | 0 | } |
6039 | 0 | uint8_t code_point = input.front(); |
6040 | 0 | input.remove_prefix(1); |
6041 | 0 | int32_t digit = char_to_digit_value(code_point); |
6042 | 0 | if (digit < 0) { |
6043 | 0 | return false; |
6044 | 0 | } |
6045 | 0 | if (digit > (0x7fffffff - i) / w) { |
6046 | 0 | return false; |
6047 | 0 | } |
6048 | 0 | i = i + digit * w; |
6049 | 0 | int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; |
6050 | 0 | if (digit < t) { |
6051 | 0 | break; |
6052 | 0 | } |
6053 | 0 | if (w > 0x7fffffff / (base - t)) { |
6054 | 0 | return false; |
6055 | 0 | } |
6056 | 0 | w = w * (base - t); |
6057 | 0 | } |
6058 | 0 | bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0); |
6059 | 0 | if (i / (written_out + 1) > 0x7fffffff - n) { |
6060 | 0 | return false; |
6061 | 0 | } |
6062 | 0 | n = n + i / int32_t(written_out + 1); |
6063 | 0 | i = i % int32_t(written_out + 1); |
6064 | 0 | if (n < 0x80) { |
6065 | 0 | return false; |
6066 | 0 | } |
6067 | | // Simulate insert at position i, maintaining only the first 4 slots. |
6068 | 0 | size_t insert_pos = size_t(i); |
6069 | 0 | if (insert_pos < 4) { |
6070 | 0 | for (size_t j = 3; j > insert_pos; j--) { |
6071 | 0 | first4[j] = first4[j - 1]; |
6072 | 0 | } |
6073 | 0 | first4[insert_pos] = n; |
6074 | 0 | } |
6075 | 0 | written_out++; |
6076 | 0 | ++i; |
6077 | 0 | } |
6078 | | // See https://github.com/whatwg/url/issues/803 |
6079 | | // Reject labels whose decoded form begins with "xn--" (double-encoded ACE). |
6080 | 0 | if (written_out >= 4 && first4[0] == U'x' && first4[1] == U'n' && |
6081 | 0 | first4[2] == U'-' && first4[3] == U'-') { |
6082 | 0 | return false; |
6083 | 0 | } |
6084 | 0 | return true; |
6085 | 0 | } |
6086 | | |
6087 | 34.4k | bool utf32_to_punycode(std::u32string_view input, std::string &out) { |
6088 | 34.4k | out.reserve(input.size() + out.size()); |
6089 | 34.4k | uint32_t n = initial_n; |
6090 | 34.4k | int32_t d = 0; |
6091 | 34.4k | int32_t bias = initial_bias; |
6092 | 34.4k | size_t h = 0; |
6093 | | // first push the ascii content |
6094 | 153k | for (uint32_t c : input) { |
6095 | 153k | if (c < 0x80) { |
6096 | 15.9k | ++h; |
6097 | 15.9k | out.push_back(char(c)); |
6098 | 15.9k | } |
6099 | 153k | if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) { |
6100 | 0 | return false; |
6101 | 0 | } |
6102 | 153k | } |
6103 | 34.4k | size_t b = h; |
6104 | 34.4k | if (b > 0) { |
6105 | 4.84k | out.push_back('-'); |
6106 | 4.84k | } |
6107 | 150k | while (h < input.size()) { |
6108 | 116k | uint32_t m = 0x10FFFF; |
6109 | 668k | for (auto code_point : input) { |
6110 | 668k | if (code_point >= n && code_point < m) m = code_point; |
6111 | 668k | } |
6112 | | |
6113 | 116k | if ((m - n) > (0x7fffffff - d) / (h + 1)) { |
6114 | 0 | return false; |
6115 | 0 | } |
6116 | 116k | d = d + int32_t((m - n) * (h + 1)); |
6117 | 116k | n = m; |
6118 | 668k | for (auto c : input) { |
6119 | 668k | if (c < n) { |
6120 | 278k | if (d == 0x7fffffff) { |
6121 | 0 | return false; |
6122 | 0 | } |
6123 | 278k | ++d; |
6124 | 278k | } |
6125 | 668k | if (c == n) { |
6126 | 137k | int32_t q = d; |
6127 | 404k | for (int32_t k = base;; k += base) { |
6128 | 404k | int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; |
6129 | | |
6130 | 404k | if (q < t) { |
6131 | 137k | break; |
6132 | 137k | } |
6133 | 266k | out.push_back(digit_to_char(t + ((q - t) % (base - t)))); |
6134 | 266k | q = (q - t) / (base - t); |
6135 | 266k | } |
6136 | 137k | out.push_back(digit_to_char(q)); |
6137 | 137k | bias = adapt(d, int32_t(h + 1), h == b); |
6138 | 137k | d = 0; |
6139 | 137k | ++h; |
6140 | 137k | } |
6141 | 668k | } |
6142 | 116k | ++d; |
6143 | 116k | ++n; |
6144 | 116k | } |
6145 | 34.4k | return true; |
6146 | 34.4k | } |
6147 | | |
6148 | | } // namespace ada::idna |
6149 | | /* end file src/punycode.cpp */ |
6150 | | /* begin file src/validity.cpp */ |
6151 | | |
6152 | | #include <algorithm> |
6153 | | #include <span> |
6154 | | #include <string_view> |
6155 | | |
6156 | | namespace ada::idna { |
6157 | | |
6158 | | // Values stored in dir_value; keep in sync with BIDI_CLASSES in |
6159 | | // scripts/unicode_data_table.py. |
6160 | | enum direction : uint8_t { |
6161 | | NONE, |
6162 | | BN, |
6163 | | CS, |
6164 | | ES, |
6165 | | ON, |
6166 | | EN, |
6167 | | L, |
6168 | | R, |
6169 | | NSM, |
6170 | | AL, |
6171 | | AN, |
6172 | | ET, |
6173 | | WS, |
6174 | | RLO, |
6175 | | LRO, |
6176 | | PDF, |
6177 | | RLE, |
6178 | | RLI, |
6179 | | FSI, |
6180 | | PDI, |
6181 | | LRI, |
6182 | | B, |
6183 | | S, |
6184 | | LRE |
6185 | | }; |
6186 | | |
6187 | | // Values stored in joining_value; keep in sync with JOINING_TYPES in |
6188 | | // scripts/unicode_data_table.py. Code points without a range are U. |
6189 | | enum class joining_type : uint8_t { U, C, D, L, R, T }; |
6190 | | |
6191 | | // Bidi direction and Joining_Type ranges live in the compressed blob as const |
6192 | | // SoA arrays (dir_* and joining_*). See table_store.hpp layout asserts. |
6193 | | // Regenerate with: python3 scripts/unicode_data_table.py --write |
6194 | | |
6195 | | // Defined in normalization.cpp. |
6196 | | uint8_t get_ccc(char32_t c) noexcept; |
6197 | | |
6198 | | // CheckJoiners and CheckBidi are true for URL specification. |
6199 | | |
6200 | | // Returns the index of the range [start[i], last[i]] that contains code_point, |
6201 | | // or count if there is none. `last` must be sorted. |
6202 | | inline static size_t find_range(const uint32_t* start, const uint32_t* last, |
6203 | 364k | size_t count, uint32_t code_point) noexcept { |
6204 | 364k | size_t lo = 0, hi = count; |
6205 | 4.29M | while (lo < hi) { |
6206 | 3.93M | size_t mid = lo + (hi - lo) / 2; |
6207 | 3.93M | if (last[mid] < code_point) { |
6208 | 1.39M | lo = mid + 1; |
6209 | 2.53M | } else { |
6210 | 2.53M | hi = mid; |
6211 | 2.53M | } |
6212 | 3.93M | } |
6213 | 364k | return lo < count && code_point >= start[lo] ? lo : count; |
6214 | 364k | } |
6215 | | |
6216 | | // Assumes ensure_tables() has already been called by is_label_valid(). |
6217 | 359k | inline static direction find_direction(uint32_t code_point) noexcept { |
6218 | 359k | size_t i = find_range(dir_start, dir_final, dir_table_count, code_point); |
6219 | 359k | return i == dir_table_count ? direction::NONE |
6220 | 359k | : static_cast<direction>(dir_value[i]); |
6221 | 359k | } |
6222 | | |
6223 | | // Assumes ensure_tables() has already been called by is_label_valid(). |
6224 | 4.94k | inline static joining_type find_joining_type(uint32_t code_point) noexcept { |
6225 | 4.94k | size_t i = |
6226 | 4.94k | find_range(joining_start, joining_final, joining_table_count, code_point); |
6227 | 4.94k | return i == joining_table_count ? joining_type::U |
6228 | 4.94k | : static_cast<joining_type>(joining_value[i]); |
6229 | 4.94k | } |
6230 | | |
6231 | | // The ContextJ rules for U+200C and U+200D from RFC 5892 Appendix A. |
6232 | 41.9k | inline static bool is_contextj_valid(std::u32string_view label) noexcept { |
6233 | 41.9k | constexpr uint8_t virama_ccc = 9; |
6234 | 302k | for (size_t i = 0; i < label.size(); i++) { |
6235 | 260k | if (label[i] != 0x200C && label[i] != 0x200D) { |
6236 | 258k | continue; |
6237 | 258k | } |
6238 | | // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; |
6239 | 1.83k | if (i > 0 && get_ccc(label[i - 1]) == virama_ccc) { |
6240 | 381 | continue; |
6241 | 381 | } |
6242 | 1.45k | if (label[i] == 0x200D) { |
6243 | 39 | return false; |
6244 | 39 | } |
6245 | | // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C |
6246 | | // (Joining_Type:T)*(Joining_Type:{R,D})) Then True; |
6247 | 1.41k | joining_type before = joining_type::U; |
6248 | 2.32k | for (size_t j = i; j > 0;) { |
6249 | 2.31k | before = find_joining_type(label[--j]); |
6250 | 2.31k | if (before != joining_type::T) { |
6251 | 1.39k | break; |
6252 | 1.39k | } |
6253 | 2.31k | } |
6254 | 1.41k | if (before != joining_type::L && before != joining_type::D) { |
6255 | 177 | return false; |
6256 | 177 | } |
6257 | 1.23k | joining_type after = joining_type::U; |
6258 | 2.75k | for (size_t j = i + 1; j < label.size(); j++) { |
6259 | 2.63k | after = find_joining_type(label[j]); |
6260 | 2.63k | if (after != joining_type::T) { |
6261 | 1.11k | break; |
6262 | 1.11k | } |
6263 | 2.63k | } |
6264 | 1.23k | if (after != joining_type::R && after != joining_type::D) { |
6265 | 261 | return false; |
6266 | 261 | } |
6267 | 1.23k | } |
6268 | 41.4k | return true; |
6269 | 41.9k | } |
6270 | | |
6271 | | inline static size_t find_last_not_of_nsm( |
6272 | 41.4k | const std::u32string_view label) noexcept { |
6273 | 49.4k | for (int i = static_cast<int>(label.size() - 1); i >= 0; i--) |
6274 | 49.4k | if (find_direction(label[i]) != direction::NSM) return i; |
6275 | | |
6276 | 0 | return std::u32string_view::npos; |
6277 | 41.4k | } |
6278 | | |
6279 | | // An RTL label is a label that contains at least one character of type R, AL, |
6280 | | // or AN. https://www.rfc-editor.org/rfc/rfc5893#section-2 |
6281 | 41.4k | inline static bool is_rtl_label(const std::u32string_view label) noexcept { |
6282 | 41.4k | const size_t mask = |
6283 | 41.4k | (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN); |
6284 | | |
6285 | 41.4k | size_t directions = 0; |
6286 | 299k | for (size_t i = 0; i < label.size(); i++) { |
6287 | 257k | directions |= 1u << find_direction(label[i]); |
6288 | 257k | } |
6289 | 41.4k | return (directions & mask) != 0; |
6290 | 41.4k | } |
6291 | | |
6292 | 42.2k | bool is_label_valid(const std::u32string_view label) { |
6293 | 42.2k | if (label.empty()) { |
6294 | 0 | return true; |
6295 | 0 | } |
6296 | 42.2k | if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr || |
6297 | 42.2k | dir_final == nullptr || dir_value == nullptr || |
6298 | 42.2k | joining_start == nullptr || joining_final == nullptr || |
6299 | 42.2k | joining_value == nullptr) { |
6300 | 0 | return false; |
6301 | 0 | } |
6302 | | |
6303 | | /////////////// |
6304 | | // We have a normalization step which ensures that we are in NFC. |
6305 | | // If we receive punycode, we normalize and check that the normalized |
6306 | | // version matches the original. |
6307 | | // -------------------------------------- |
6308 | | // The label must be in Unicode Normalization Form NFC. |
6309 | | |
6310 | | // Current URL standard indicatest that CheckHyphens is set to false. |
6311 | | // --------------------------------------- |
6312 | | // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character |
6313 | | // in both the third and fourth positions. If CheckHyphens, the label must |
6314 | | // neither begin nor end with a U+002D HYPHEN-MINUS character. |
6315 | | |
6316 | | // This is not necessary because we segment the |
6317 | | // labels by '.'. |
6318 | | // --------------------------------------- |
6319 | | // The label must not contain a U+002E ( . ) FULL STOP. |
6320 | | // if (label.find('.') != std::string_view::npos) return false; |
6321 | | |
6322 | | // The label must not begin with a combining mark. |
6323 | | // Range membership via lower_bound on range end. |
6324 | 42.2k | const std::span<const uint32_t[2]> comb_span{combining_ranges, |
6325 | 42.2k | combining_range_count}; |
6326 | 42.2k | const auto comb_it = std::ranges::lower_bound( |
6327 | 345k | comb_span, label.front(), {}, [](const auto& range) { return range[1]; }); |
6328 | 42.2k | if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) { |
6329 | 306 | return false; |
6330 | 306 | } |
6331 | | // We verify this next step as part of the mapping: |
6332 | | // --------------------------------------------- |
6333 | | // Each code point in the label must only have certain status values |
6334 | | // according to Section 5, IDNA Mapping Table: |
6335 | | // - For Transitional Processing, each value must be valid. |
6336 | | // - For Nontransitional Processing, each value must be either valid or |
6337 | | // deviation. |
6338 | | |
6339 | | // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix |
6340 | | // A, in The Unicode Code Points and Internationalized Domain Names for |
6341 | | // Applications (IDNA) [IDNA2008]. |
6342 | 41.9k | if (!is_contextj_valid(label)) { |
6343 | 477 | return false; |
6344 | 477 | } |
6345 | | |
6346 | | // If CheckBidi, and if the domain name is a Bidi domain name, then the label |
6347 | | // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, |
6348 | | // Section 2. |
6349 | | |
6350 | | // The following rule, consisting of six conditions, applies to labels |
6351 | | // in Bidi domain names. The requirements that this rule satisfies are |
6352 | | // described in Section 3. All of the conditions must be satisfied for |
6353 | | // the rule to be satisfied. |
6354 | | // |
6355 | | // 1. The first character must be a character with Bidi property L, R, |
6356 | | // or AL. If it has the R or AL property, it is an RTL label; if it |
6357 | | // has the L property, it is an LTR label. |
6358 | | // |
6359 | | // 2. In an RTL label, only characters with the Bidi properties R, AL, |
6360 | | // AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
6361 | | // |
6362 | | // 3. In an RTL label, the end of the label must be a character with |
6363 | | // Bidi property R, AL, EN, or AN, followed by zero or more |
6364 | | // characters with Bidi property NSM. |
6365 | | // |
6366 | | // 4. In an RTL label, if an EN is present, no AN may be present, and |
6367 | | // vice versa. |
6368 | | // |
6369 | | // 5. In an LTR label, only characters with the Bidi properties L, EN, |
6370 | | // ES, CS, ET, ON, BN, or NSM are allowed. |
6371 | | // |
6372 | | // 6. In an LTR label, the end of the label must be a character with |
6373 | | // Bidi property L or EN, followed by zero or more characters with |
6374 | | // Bidi property NSM. |
6375 | | |
6376 | 41.4k | size_t last_non_nsm_char = find_last_not_of_nsm(label); |
6377 | 41.4k | if (last_non_nsm_char == std::u32string_view::npos) { |
6378 | 0 | return false; |
6379 | 0 | } |
6380 | | |
6381 | | // A "Bidi domain name" is a domain name that contains at least one RTL label. |
6382 | | // The following rule, consisting of six conditions, applies to labels in Bidi |
6383 | | // domain names. |
6384 | 41.4k | if (is_rtl_label(label)) { |
6385 | | // The first character must be a character with Bidi property L, R, |
6386 | | // or AL. If it has the R or AL property, it is an RTL label; if it |
6387 | | // has the L property, it is an LTR label. |
6388 | | |
6389 | 7.11k | if (find_direction(label[0]) == direction::L) { |
6390 | | // Eval as LTR |
6391 | | |
6392 | | // In an LTR label, only characters with the Bidi properties L, EN, |
6393 | | // ES, CS, ET, ON, BN, or NSM are allowed. |
6394 | 10.4k | for (size_t i = 0; i <= last_non_nsm_char; i++) { |
6395 | 10.4k | const direction d = find_direction(label[i]); |
6396 | 10.4k | if (!(d == direction::L || d == direction::EN || d == direction::ES || |
6397 | 5.99k | d == direction::CS || d == direction::ET || d == direction::ON || |
6398 | 2.76k | d == direction::BN || d == direction::NSM)) { |
6399 | 504 | return false; |
6400 | 504 | } |
6401 | 10.4k | } |
6402 | | |
6403 | 0 | const direction last_dir = find_direction(label[last_non_nsm_char]); |
6404 | 0 | if (!(last_dir == direction::L || last_dir == direction::EN)) { |
6405 | 0 | return false; |
6406 | 0 | } |
6407 | | |
6408 | 0 | return true; |
6409 | |
|
6410 | 6.60k | } else { |
6411 | | // Eval as RTL |
6412 | | |
6413 | | // The first character must be R or AL; a leading AN (or any other |
6414 | | // direction) does not start a valid RTL label. |
6415 | 6.60k | const direction first_dir = find_direction(label[0]); |
6416 | 6.60k | if (first_dir != direction::R && first_dir != direction::AL) { |
6417 | 51 | return false; |
6418 | 51 | } |
6419 | | |
6420 | 6.55k | bool has_an = false; |
6421 | 6.55k | bool has_en = false; |
6422 | 34.2k | for (size_t i = 0; i <= last_non_nsm_char; i++) { |
6423 | 28.1k | const direction d = find_direction(label[i]); |
6424 | | |
6425 | | // In an RTL label, if an EN is present, no AN may be present, and vice |
6426 | | // versa. |
6427 | 28.1k | if ((d == direction::EN && ((has_en = true) && has_an)) || |
6428 | 28.1k | (d == direction::AN && ((has_an = true) && has_en))) { |
6429 | 18 | return false; |
6430 | 18 | } |
6431 | | |
6432 | 28.1k | if (!(d == direction::R || d == direction::AL || d == direction::AN || |
6433 | 10.2k | d == direction::EN || d == direction::ES || d == direction::CS || |
6434 | 6.25k | d == direction::ET || d == direction::ON || d == direction::BN || |
6435 | 1.63k | d == direction::NSM)) { |
6436 | 261 | return false; |
6437 | 261 | } |
6438 | | |
6439 | 27.9k | if (i == last_non_nsm_char && |
6440 | 6.27k | !(d == direction::R || d == direction::AL || d == direction::AN || |
6441 | 738 | d == direction::EN)) { |
6442 | 201 | return false; |
6443 | 201 | } |
6444 | 27.9k | } |
6445 | | |
6446 | 6.07k | return true; |
6447 | 6.55k | } |
6448 | 7.11k | } |
6449 | | |
6450 | 34.3k | return true; |
6451 | 41.4k | } |
6452 | | |
6453 | | } // namespace ada::idna |
6454 | | /* end file src/validity.cpp */ |
6455 | | /* begin file src/to_ascii.cpp */ |
6456 | | /* begin file include/ada/idna/to_ascii.h */ |
6457 | | #ifndef ADA_IDNA_TO_ASCII_H |
6458 | | #define ADA_IDNA_TO_ASCII_H |
6459 | | |
6460 | | #include <string> |
6461 | | #include <string_view> |
6462 | | |
6463 | | /* begin file include/ada/idna/limits.h */ |
6464 | | #ifndef ADA_IDNA_LIMITS_H |
6465 | | #define ADA_IDNA_LIMITS_H |
6466 | | |
6467 | | #include <cstddef> |
6468 | | |
6469 | | namespace ada::idna { |
6470 | | |
6471 | | // Maximum accepted UTF-8 domain length for non-ASCII to_ascii input and for |
6472 | | // to_unicode input. |
6473 | | // Bounds heap growth under untrusted input (DoS resistance). DNS wire limits |
6474 | | // are smaller; this allows long Unicode labels used in URL tests/fixtures. |
6475 | | inline constexpr size_t max_domain_input_bytes = 16384; |
6476 | | |
6477 | | } // namespace ada::idna |
6478 | | |
6479 | | #endif // ADA_IDNA_LIMITS_H |
6480 | | /* end file include/ada/idna/limits.h */ |
6481 | | |
6482 | | namespace ada::idna { |
6483 | | |
6484 | | // Converts a domain (e.g., www.google.com) possibly containing international |
6485 | | // characters to an ascii domain (with punycode). It will not do percent |
6486 | | // decoding: percent decoding should be done prior to calling this function. We |
6487 | | // do not remove tabs and spaces, they should have been removed prior to calling |
6488 | | // this function. We also do not trim control characters. We also assume that |
6489 | | // the input is not empty. We return "" on error. Non-ASCII inputs longer than |
6490 | | // max_domain_input_bytes are rejected; ASCII inputs of any length are accepted |
6491 | | // (they are only lowercased). |
6492 | | // |
6493 | | // This function may accept or even produce invalid domains (WHATWG carve-outs). |
6494 | | std::string to_ascii(std::string_view ut8_string); |
6495 | | |
6496 | | // Same as to_ascii, but writes into `out` and returns false on error without |
6497 | | // relying on empty-string ambiguity. |
6498 | | [[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out); |
6499 | | |
6500 | | // Returns true if the string contains a forbidden code point according to the |
6501 | | // WHATGL URL specification: |
6502 | | // https://url.spec.whatwg.org/#forbidden-domain-code-point |
6503 | | bool contains_forbidden_domain_code_point(std::string_view ascii_string); |
6504 | | |
6505 | | bool constexpr is_ascii(std::u32string_view view); |
6506 | | bool constexpr is_ascii(std::string_view view); |
6507 | | |
6508 | | } // namespace ada::idna |
6509 | | |
6510 | | #endif // ADA_IDNA_TO_ASCII_H |
6511 | | /* end file include/ada/idna/to_ascii.h */ |
6512 | | |
6513 | | #include <algorithm> |
6514 | | #include <cstdint> |
6515 | | #include <cstring> |
6516 | | #include <ranges> |
6517 | | |
6518 | | /* begin file include/ada/idna/validity.h */ |
6519 | | #ifndef ADA_IDNA_VALIDITY_H |
6520 | | #define ADA_IDNA_VALIDITY_H |
6521 | | |
6522 | | #include <string> |
6523 | | #include <string_view> |
6524 | | |
6525 | | namespace ada::idna { |
6526 | | |
6527 | | /** |
6528 | | * @see https://www.unicode.org/reports/tr46/#Validity_Criteria |
6529 | | */ |
6530 | | bool is_label_valid(std::u32string_view label); |
6531 | | |
6532 | | } // namespace ada::idna |
6533 | | |
6534 | | #endif // ADA_IDNA_VALIDITY_H |
6535 | | /* end file include/ada/idna/validity.h */ |
6536 | | |
6537 | | #ifdef ADA_USE_SIMDUTF |
6538 | | #include "simdutf.h" |
6539 | | #endif |
6540 | | |
6541 | | namespace ada::idna { |
6542 | | |
6543 | 67.2k | bool constexpr is_ascii(std::u32string_view view) { |
6544 | 245k | for (uint32_t c : view) { |
6545 | 245k | if (c >= 0x80) { |
6546 | 58.7k | return false; |
6547 | 58.7k | } |
6548 | 245k | } |
6549 | 8.51k | return true; |
6550 | 67.2k | } |
6551 | | |
6552 | 19.5k | bool constexpr is_ascii(std::string_view view) { |
6553 | 492k | for (uint8_t c : view) { |
6554 | 492k | if (c >= 0x80) { |
6555 | 13.2k | return false; |
6556 | 13.2k | } |
6557 | 492k | } |
6558 | 6.28k | return true; |
6559 | 19.5k | } |
6560 | | |
6561 | | constexpr static uint8_t is_forbidden_domain_code_point_table[] = { |
6562 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6563 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, |
6564 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, |
6565 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, |
6566 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
6567 | | 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6568 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6569 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6570 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6571 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
6572 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; |
6573 | | |
6574 | | static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); |
6575 | | |
6576 | 0 | inline bool is_forbidden_domain_code_point(const char c) noexcept { |
6577 | 0 | return is_forbidden_domain_code_point_table[uint8_t(c)]; |
6578 | 0 | } |
6579 | | |
6580 | 0 | bool contains_forbidden_domain_code_point(std::string_view view) { |
6581 | 0 | return std::ranges::any_of(view, is_forbidden_domain_code_point); |
6582 | 0 | } |
6583 | | |
6584 | | // Per the WHATWG URL "domain to ASCII" algorithm, when beStrict is false and |
6585 | | // the input domain is an ASCII string, the result is the input lowercased, |
6586 | | // regardless of the outcome of Unicode ToASCII. |
6587 | | // |
6588 | | // See https://url.spec.whatwg.org/#concept-domain-to-ascii |
6589 | 6.28k | static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) { |
6590 | 6.28k | out.assign(ut8_string); |
6591 | 6.28k | ascii_map(out.data(), out.size()); |
6592 | 6.28k | } |
6593 | | |
6594 | | // Append ASCII code units from a UTF-32 label (all values < 0x80). |
6595 | 12.9k | static void append_ascii_label(std::string& out, std::u32string_view label) { |
6596 | 12.9k | const size_t old = out.size(); |
6597 | 12.9k | out.resize(old + label.size()); |
6598 | 12.9k | char* dest = out.data() + old; |
6599 | 173k | for (char32_t c : label) { |
6600 | 173k | *dest++ = static_cast<char>(c); |
6601 | 173k | } |
6602 | 12.9k | } |
6603 | | |
6604 | | // True if label begins with "xn--" (already lowercased by mapping). |
6605 | 49.2k | static bool is_ace_prefix(std::u32string_view label) noexcept { |
6606 | 49.2k | return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' && |
6607 | 8.74k | label[2] == U'-' && label[3] == U'-'; |
6608 | 49.2k | } |
6609 | | |
6610 | 19.5k | [[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) { |
6611 | 19.5k | out.clear(); |
6612 | | // The ASCII path is a single same-size copy, so it needs no length bound. |
6613 | | // Checking first would reject the (longer) ASCII output of a non-ASCII input |
6614 | | // that was accepted, breaking to_ascii(to_ascii(x)) == to_ascii(x). |
6615 | 19.5k | if (is_ascii(ut8_string)) { |
6616 | 6.28k | from_ascii_to_ascii(ut8_string, out); |
6617 | 6.28k | return true; |
6618 | 6.28k | } |
6619 | 13.2k | if (ut8_string.size() > max_domain_input_bytes) { |
6620 | 0 | return false; |
6621 | 0 | } |
6622 | | |
6623 | | #ifdef ADA_USE_SIMDUTF |
6624 | | size_t utf32_length = |
6625 | | simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size()); |
6626 | | if (utf32_length == 0 && !ut8_string.empty()) { |
6627 | | return false; |
6628 | | } |
6629 | | std::u32string working(utf32_length, U'\0'); |
6630 | | size_t actual_utf32_length = simdutf::convert_utf8_to_utf32( |
6631 | | ut8_string.data(), ut8_string.size(), working.data()); |
6632 | | #else |
6633 | 13.2k | size_t utf32_length = |
6634 | 13.2k | ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size()); |
6635 | 13.2k | if (utf32_length == 0 && !ut8_string.empty()) { |
6636 | 123 | return false; |
6637 | 123 | } |
6638 | 13.1k | std::u32string working(utf32_length, U'\0'); |
6639 | 13.1k | size_t actual_utf32_length = ada::idna::utf8_to_utf32( |
6640 | 13.1k | ut8_string.data(), ut8_string.size(), working.data()); |
6641 | 13.1k | #endif |
6642 | 13.1k | if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) { |
6643 | 885 | return false; |
6644 | 885 | } |
6645 | 12.2k | working.resize(actual_utf32_length); |
6646 | | |
6647 | | // Map into a second buffer with exact sizing (no growth reallocs). |
6648 | 12.2k | std::u32string mapped; |
6649 | 12.2k | if (!ada::idna::map(working, mapped)) { |
6650 | 120 | return false; |
6651 | 120 | } |
6652 | | // Drop UTF-32 input; reuse `working` as scratch for ACE validation below. |
6653 | 12.1k | working.clear(); |
6654 | | |
6655 | | // Skip NFC when already normalized (ASCII is a fast subset of this check). |
6656 | 12.1k | if (!is_ascii(mapped) && !is_already_nfc(mapped)) { |
6657 | 1.62k | if (!normalize(mapped)) { |
6658 | 0 | return false; |
6659 | 0 | } |
6660 | 1.62k | } |
6661 | | |
6662 | | // Estimate ASCII output size (punycode may expand non-ASCII labels). |
6663 | 12.1k | out.reserve(mapped.size() + 8); |
6664 | | |
6665 | | // Walk labels with a single pointer scan (no repeated string::find). |
6666 | 12.1k | const char32_t* p = mapped.data(); |
6667 | 12.1k | const char32_t* const end = p + mapped.size(); |
6668 | 12.1k | std::u32string post_map; |
6669 | | |
6670 | 60.9k | while (p < end) { |
6671 | 52.3k | const char32_t* label_begin = p; |
6672 | 454k | while (p < end && *p != U'.') { |
6673 | 401k | ++p; |
6674 | 401k | } |
6675 | 52.3k | const size_t label_size = static_cast<size_t>(p - label_begin); |
6676 | 52.3k | std::u32string_view label_view(label_begin, label_size); |
6677 | 52.3k | const bool is_last_label = (p == end); |
6678 | 52.3k | if (p < end) { |
6679 | 40.7k | ++p; // skip dot |
6680 | 40.7k | } |
6681 | | |
6682 | 52.3k | if (label_size == 0) { |
6683 | | // empty label |
6684 | 49.2k | } else if (is_ace_prefix(label_view)) { |
6685 | 137k | for (char32_t c : label_view) { |
6686 | 137k | if (c >= 0x80) { |
6687 | 36 | out.clear(); |
6688 | 36 | return false; |
6689 | 36 | } |
6690 | 137k | } |
6691 | 7.66k | append_ascii_label(out, label_view); |
6692 | 7.66k | std::string_view puny_segment_ascii( |
6693 | 7.66k | out.data() + (out.size() - label_size) + 4, label_size - 4); |
6694 | 7.66k | working.clear(); |
6695 | 7.66k | if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) { |
6696 | 348 | out.clear(); |
6697 | 348 | return false; |
6698 | 348 | } |
6699 | 7.32k | if (is_ascii(working)) { |
6700 | 234 | out.clear(); |
6701 | 234 | return false; |
6702 | 234 | } |
6703 | 7.08k | if (!ada::idna::map(working, post_map) || working != post_map) { |
6704 | 711 | out.clear(); |
6705 | 711 | return false; |
6706 | 711 | } |
6707 | | // Mapping must be stable; NFC must not change the mapped form either. |
6708 | 6.37k | if (!is_ascii(post_map) && !is_already_nfc(post_map)) { |
6709 | 4.02k | if (!normalize(post_map) || post_map != working) { |
6710 | 354 | out.clear(); |
6711 | 354 | return false; |
6712 | 354 | } |
6713 | 4.02k | } |
6714 | 6.02k | if (post_map.empty() || !is_label_valid(post_map)) { |
6715 | 99 | out.clear(); |
6716 | 99 | return false; |
6717 | 99 | } |
6718 | 41.4k | } else if (is_ascii(label_view)) { |
6719 | 5.30k | append_ascii_label(out, label_view); |
6720 | 36.1k | } else { |
6721 | 36.1k | if (!is_label_valid(label_view)) { |
6722 | 1.71k | out.clear(); |
6723 | 1.71k | return false; |
6724 | 1.71k | } |
6725 | 34.4k | out.append("xn--"); |
6726 | 34.4k | if (!ada::idna::utf32_to_punycode(label_view, out)) { |
6727 | 0 | out.clear(); |
6728 | 0 | return false; |
6729 | 0 | } |
6730 | 34.4k | } |
6731 | 48.8k | if (!is_last_label) { |
6732 | 40.6k | out.push_back('.'); |
6733 | 40.6k | } |
6734 | 48.8k | } |
6735 | 8.60k | return true; |
6736 | 12.1k | } |
6737 | | |
6738 | 19.5k | std::string to_ascii(std::string_view ut8_string) { |
6739 | 19.5k | std::string out; |
6740 | 19.5k | if (!to_ascii(ut8_string, out)) { |
6741 | 4.62k | return {}; |
6742 | 4.62k | } |
6743 | 14.8k | return out; |
6744 | 19.5k | } |
6745 | | } // namespace ada::idna |
6746 | | /* end file src/to_ascii.cpp */ |
6747 | | /* begin file src/to_unicode.cpp */ |
6748 | | /* begin file include/ada/idna/to_unicode.h */ |
6749 | | #ifndef ADA_IDNA_TO_UNICODE_H |
6750 | | #define ADA_IDNA_TO_UNICODE_H |
6751 | | |
6752 | | #include <string> |
6753 | | #include <string_view> |
6754 | | |
6755 | | |
6756 | | namespace ada::idna { |
6757 | | |
6758 | | // UTS #46 ToUnicode. Never fails per the standard: on step failure the original |
6759 | | // label is kept. Inputs longer than max_domain_input_bytes are returned |
6760 | | // unchanged as a safety measure under untrusted input. |
6761 | | std::string to_unicode(std::string_view input); |
6762 | | |
6763 | | // Writes into `out`. Returns false only if the input exceeds |
6764 | | // max_domain_input_bytes (out is left empty). Otherwise always returns true |
6765 | | // (ToUnicode does not fail). |
6766 | | [[nodiscard]] bool to_unicode(std::string_view input, std::string& out); |
6767 | | |
6768 | | } // namespace ada::idna |
6769 | | |
6770 | | #endif // ADA_IDNA_TO_UNICODE_H |
6771 | | /* end file include/ada/idna/to_unicode.h */ |
6772 | | |
6773 | | #include <algorithm> |
6774 | | #include <string> |
6775 | | |
6776 | | /* begin file include/idna.h */ |
6777 | | #ifndef ADA_IDNA_H |
6778 | | #define ADA_IDNA_H |
6779 | | |
6780 | | /* begin file include/ada/idna/identifier.h */ |
6781 | | #ifndef ADA_IDNA_IDENTIFIER_H |
6782 | | #define ADA_IDNA_IDENTIFIER_H |
6783 | | |
6784 | | #include <string> |
6785 | | #include <string_view> |
6786 | | |
6787 | | namespace ada::idna { |
6788 | | |
6789 | | // Verify if it is valid name code point given a Unicode code point and a |
6790 | | // boolean first: If first is true return the result of checking if code point |
6791 | | // is contained in the IdentifierStart set of code points. Otherwise return the |
6792 | | // result of checking if code point is contained in the IdentifierPart set of |
6793 | | // code points. Returns false if the input is empty or the code point is not |
6794 | | // valid. There is minimal Unicode error handling: the input should be valid |
6795 | | // UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point |
6796 | | bool valid_name_code_point(char32_t code_point, bool first); |
6797 | | |
6798 | | } // namespace ada::idna |
6799 | | |
6800 | | #endif |
6801 | | /* end file include/ada/idna/identifier.h */ |
6802 | | |
6803 | | #endif |
6804 | | /* end file include/idna.h */ |
6805 | | |
6806 | | #ifdef ADA_USE_SIMDUTF |
6807 | | #include "simdutf.h" |
6808 | | #endif |
6809 | | |
6810 | | namespace ada::idna { |
6811 | | |
6812 | 0 | [[nodiscard]] bool to_unicode(std::string_view input, std::string& output) { |
6813 | 0 | output.clear(); |
6814 | 0 | if (input.size() > max_domain_input_bytes) { |
6815 | 0 | return false; |
6816 | 0 | } |
6817 | 0 | output.reserve(input.size()); |
6818 | |
|
6819 | 0 | size_t label_start = 0; |
6820 | 0 | std::u32string tmp_buffer; |
6821 | 0 | std::u32string post_map; |
6822 | 0 | while (label_start < input.size()) { |
6823 | 0 | size_t loc_dot = input.find('.', label_start); |
6824 | 0 | bool is_last_label = (loc_dot == std::string_view::npos); |
6825 | 0 | size_t label_size = |
6826 | 0 | is_last_label ? input.size() - label_start : loc_dot - label_start; |
6827 | 0 | auto label_view = std::string_view(input.data() + label_start, label_size); |
6828 | |
|
6829 | 0 | if (label_view.starts_with("xn--") && ada::idna::is_ascii(label_view)) { |
6830 | 0 | label_view.remove_prefix(4); |
6831 | 0 | tmp_buffer.clear(); |
6832 | 0 | if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) { |
6833 | | // Per UTS #46, the decoded label must be re-validated. Reject decodings |
6834 | | // that are pure ASCII (xn-- encoding of an ASCII-only label), or whose |
6835 | | // mapping/normalization is not stable, or that fail label validity. |
6836 | 0 | bool accept_decoded = true; |
6837 | 0 | if (ada::idna::is_ascii(tmp_buffer)) { |
6838 | 0 | accept_decoded = false; |
6839 | 0 | } else { |
6840 | 0 | post_map.clear(); |
6841 | 0 | if (!ada::idna::map(tmp_buffer, post_map) || post_map != tmp_buffer) { |
6842 | 0 | accept_decoded = false; |
6843 | 0 | } else if (!ada::idna::normalize(post_map) || |
6844 | 0 | post_map != tmp_buffer || post_map.empty() || |
6845 | 0 | !ada::idna::is_label_valid(post_map)) { |
6846 | 0 | accept_decoded = false; |
6847 | 0 | } |
6848 | 0 | } |
6849 | |
|
6850 | 0 | if (accept_decoded) { |
6851 | | #ifdef ADA_USE_SIMDUTF |
6852 | | auto utf8_size = simdutf::utf8_length_from_utf32(tmp_buffer.data(), |
6853 | | tmp_buffer.size()); |
6854 | | size_t old_size = output.size(); |
6855 | | output.resize(old_size + utf8_size); |
6856 | | size_t written = simdutf::convert_utf32_to_utf8( |
6857 | | tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size); |
6858 | | if (written != utf8_size) { |
6859 | | output.resize(old_size); |
6860 | | output.append( |
6861 | | std::string_view(input.data() + label_start, label_size)); |
6862 | | } |
6863 | | #else |
6864 | 0 | auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(), |
6865 | 0 | tmp_buffer.size()); |
6866 | 0 | size_t old_size = output.size(); |
6867 | 0 | output.resize(old_size + utf8_size); |
6868 | 0 | size_t written = ada::idna::utf32_to_utf8( |
6869 | 0 | tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size); |
6870 | 0 | if (written != utf8_size) { |
6871 | 0 | output.resize(old_size); |
6872 | 0 | output.append( |
6873 | 0 | std::string_view(input.data() + label_start, label_size)); |
6874 | 0 | } |
6875 | 0 | #endif |
6876 | 0 | } else { |
6877 | | // ToUnicode never fails. If any step fails, return the original |
6878 | | // input sequence for the label. |
6879 | 0 | output.append( |
6880 | 0 | std::string_view(input.data() + label_start, label_size)); |
6881 | 0 | } |
6882 | 0 | } else { |
6883 | 0 | output.append(std::string_view(input.data() + label_start, label_size)); |
6884 | 0 | } |
6885 | 0 | } else { |
6886 | 0 | output.append(label_view); |
6887 | 0 | } |
6888 | |
|
6889 | 0 | if (!is_last_label) { |
6890 | 0 | output.push_back('.'); |
6891 | 0 | } |
6892 | |
|
6893 | 0 | label_start += label_size + 1; |
6894 | 0 | } |
6895 | |
|
6896 | 0 | return true; |
6897 | 0 | } |
6898 | | |
6899 | 0 | std::string to_unicode(std::string_view input) { |
6900 | 0 | std::string output; |
6901 | 0 | if (!to_unicode(input, output)) { |
6902 | | // Over-limit input: return original (ToUnicode never fails in the sense of |
6903 | | // producing no answer for valid-length inputs). |
6904 | 0 | return std::string(input); |
6905 | 0 | } |
6906 | 0 | return output; |
6907 | 0 | } |
6908 | | } // namespace ada::idna |
6909 | | /* end file src/to_unicode.cpp */ |
6910 | | /* begin file src/identifier.cpp */ |
6911 | | |
6912 | | #include <algorithm> |
6913 | | #include <array> |
6914 | | #include <span> |
6915 | | #include <string> |
6916 | | |
6917 | | /* begin file src/id_tables.cpp */ |
6918 | | // IDNA 18.0.0 |
6919 | | // Identifier range tables are stored in the compressed blob (table_store.hpp). |
6920 | | // Regenerate with: python3 scripts/derived_table.py --write |
6921 | | // id_continue: 1437 ranges |
6922 | | // id_start: 789 ranges |
6923 | | |
6924 | | // clang-format off |
6925 | | #ifndef ADA_IDNA_IDENTIFIER_TABLES_H |
6926 | | #define ADA_IDNA_IDENTIFIER_TABLES_H |
6927 | | #include <cstdint> |
6928 | | |
6929 | | namespace ada::idna { |
6930 | | |
6931 | | // id_continue / id_start pointers and counts are provided by table_store.hpp. |
6932 | | |
6933 | | } // namespace ada::idna |
6934 | | #endif // ADA_IDNA_IDENTIFIER_TABLES_H |
6935 | | /* end file src/id_tables.cpp */ |
6936 | | |
6937 | | namespace ada::idna { |
6938 | 0 | constexpr bool is_ascii_letter(char32_t c) noexcept { |
6939 | 0 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
6940 | 0 | } |
6941 | | |
6942 | 0 | constexpr bool is_ascii_letter_or_digit(char32_t c) noexcept { |
6943 | 0 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || |
6944 | 0 | (c >= '0' && c <= '9'); |
6945 | 0 | } |
6946 | | |
6947 | 0 | bool valid_name_code_point(char32_t code_point, bool first) { |
6948 | | // https://tc39.es/ecma262/#prod-IdentifierStart |
6949 | | |
6950 | | // Fast paths (no table needed) |
6951 | 0 | if (first && (code_point == U'$' || code_point == U'_' || |
6952 | 0 | is_ascii_letter(code_point))) { |
6953 | 0 | return true; |
6954 | 0 | } |
6955 | 0 | if (!first && (code_point == U'$' || is_ascii_letter_or_digit(code_point))) { |
6956 | 0 | return true; |
6957 | 0 | } |
6958 | | |
6959 | | // Minimal error handling for invalid code point |
6960 | 0 | if (code_point > 0x10FFFF) { |
6961 | 0 | return false; |
6962 | 0 | } |
6963 | 0 | if (code_point >= 0xD800 && code_point <= 0xDFFF) { |
6964 | 0 | return false; |
6965 | 0 | } |
6966 | | |
6967 | 0 | if (!ensure_tables() || id_start == nullptr || id_continue == nullptr) { |
6968 | 0 | return false; |
6969 | 0 | } |
6970 | | |
6971 | | // Slow path: binary search through the appropriate Unicode range table. |
6972 | | // Each entry is a [low, high] inclusive range. |
6973 | 0 | const std::span<const uint32_t[2]> ranges = |
6974 | 0 | first ? std::span<const uint32_t[2]>{ada::idna::id_start, |
6975 | 0 | ada::idna::id_start_count} |
6976 | 0 | : std::span<const uint32_t[2]>{ada::idna::id_continue, |
6977 | 0 | ada::idna::id_continue_count}; |
6978 | |
|
6979 | 0 | const auto iter = std::ranges::lower_bound( |
6980 | 0 | ranges, code_point, {}, |
6981 | 0 | [](const auto& range) { return range[1]; }); // project to range-high |
6982 | |
|
6983 | 0 | return iter != ranges.end() && code_point >= (*iter)[0]; |
6984 | 0 | } |
6985 | | } // namespace ada::idna |
6986 | | /* end file src/identifier.cpp */ |
6987 | | /* end file src/idna.cpp */ |
6988 | | /* end file src/ada_idna.cpp */ |
6989 | | ADA_POP_DISABLE_WARNINGS |
6990 | | |
6991 | | #include <algorithm> |
6992 | | #include <array> |
6993 | | #include <cstdint> |
6994 | | #include <cstring> |
6995 | | #include <iterator> |
6996 | | #include <optional> |
6997 | | #include <string> |
6998 | | #include <string_view> |
6999 | | #include <utility> |
7000 | | #if ADA_SSSE3 |
7001 | | #include <tmmintrin.h> |
7002 | | #elif ADA_NEON |
7003 | | #include <arm_neon.h> |
7004 | | #elif ADA_SSE2 |
7005 | | #include <emmintrin.h> |
7006 | | #elif ADA_LSX |
7007 | | #include <lsxintrin.h> |
7008 | | #elif ADA_RVV |
7009 | | #include <riscv_vector.h> |
7010 | | #endif |
7011 | | |
7012 | | #include <ranges> |
7013 | | |
7014 | | namespace ada::unicode { |
7015 | | |
7016 | 340k | constexpr bool is_tabs_or_newline(char c) noexcept { |
7017 | 340k | return c == '\r' || c == '\n' || c == '\t'; |
7018 | 340k | } |
7019 | | |
7020 | 118k | constexpr uint64_t broadcast(uint8_t v) noexcept { |
7021 | 118k | return 0x101010101010101ull * v; |
7022 | 118k | } |
7023 | | |
7024 | 39.5k | constexpr bool to_lower_ascii(char* input, size_t length) noexcept { |
7025 | 39.5k | uint64_t broadcast_80 = broadcast(0x80); |
7026 | 39.5k | uint64_t broadcast_Ap = broadcast(128 - 'A'); |
7027 | 39.5k | uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); |
7028 | 39.5k | uint64_t non_ascii = 0; |
7029 | 39.5k | size_t i = 0; |
7030 | | |
7031 | 49.4k | for (; i + 7 < length; i += 8) { |
7032 | 9.87k | uint64_t word{}; |
7033 | 9.87k | memcpy(&word, input + i, sizeof(word)); |
7034 | 9.87k | non_ascii |= (word & broadcast_80); |
7035 | 9.87k | word ^= |
7036 | 9.87k | (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; |
7037 | 9.87k | memcpy(input + i, &word, sizeof(word)); |
7038 | 9.87k | } |
7039 | 39.5k | if (i < length) { |
7040 | 38.6k | uint64_t word{}; |
7041 | 38.6k | memcpy(&word, input + i, length - i); |
7042 | 38.6k | non_ascii |= (word & broadcast_80); |
7043 | 38.6k | word ^= |
7044 | 38.6k | (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; |
7045 | 38.6k | memcpy(input + i, &word, length - i); |
7046 | 38.6k | } |
7047 | 39.5k | return non_ascii == 0; |
7048 | 39.5k | } |
7049 | | #if ADA_SSSE3 |
7050 | | ada_really_inline bool has_tabs_or_newline( |
7051 | | std::string_view user_input) noexcept { |
7052 | | // first check for short strings in which case we do it naively. |
7053 | | if (user_input.size() < 16) { // slow path |
7054 | | return std::ranges::any_of(user_input, is_tabs_or_newline); |
7055 | | } |
7056 | | // fast path for long strings (expected to be common) |
7057 | | // Using SSSE3's _mm_shuffle_epi8 for table lookup (same approach as NEON) |
7058 | | size_t i = 0; |
7059 | | // Lookup table where positions 9, 10, 13 contain their own values |
7060 | | // Everything else is set to 1 so it won't match |
7061 | | const __m128i rnt = |
7062 | | _mm_setr_epi8(1, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 13, 0, 0); |
7063 | | __m128i running = _mm_setzero_si128(); |
7064 | | for (; i + 15 < user_input.size(); i += 16) { |
7065 | | __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i)); |
7066 | | // Shuffle the lookup table using input bytes as indices |
7067 | | __m128i shuffled = _mm_shuffle_epi8(rnt, word); |
7068 | | // Compare: if shuffled value matches input, we found \t, \n, or \r |
7069 | | __m128i matches = _mm_cmpeq_epi8(shuffled, word); |
7070 | | running = _mm_or_si128(running, matches); |
7071 | | } |
7072 | | if (i < user_input.size()) { |
7073 | | __m128i word = _mm_loadu_si128( |
7074 | | (const __m128i*)(user_input.data() + user_input.length() - 16)); |
7075 | | __m128i shuffled = _mm_shuffle_epi8(rnt, word); |
7076 | | __m128i matches = _mm_cmpeq_epi8(shuffled, word); |
7077 | | running = _mm_or_si128(running, matches); |
7078 | | } |
7079 | | return _mm_movemask_epi8(running) != 0; |
7080 | | } |
7081 | | #elif ADA_NEON |
7082 | | ada_really_inline bool has_tabs_or_newline( |
7083 | | std::string_view user_input) noexcept { |
7084 | | // first check for short strings in which case we do it naively. |
7085 | | if (user_input.size() < 16) { // slow path |
7086 | | return std::ranges::any_of(user_input, is_tabs_or_newline); |
7087 | | } |
7088 | | // fast path for long strings (expected to be common) |
7089 | | size_t i = 0; |
7090 | | /** |
7091 | | * The fastest way to check for `\t` (==9), '\n'(== 10) and `\r` (==13) relies |
7092 | | * on table lookup instruction. We notice that these are all unique numbers |
7093 | | * between 0..15. Let's prepare a special register, where we put '\t' in the |
7094 | | * 9th position, '\n' - 10th and '\r' - 13th. Then we shuffle this register by |
7095 | | * input register. If the input had `\t` in position X then this shuffled |
7096 | | * register will also have '\t' in that position. Comparing input with this |
7097 | | * shuffled register will mark us all interesting characters in the input. |
7098 | | * |
7099 | | * credit for algorithmic idea: @aqrit, credit for description: |
7100 | | * @DenisYaroshevskiy |
7101 | | */ |
7102 | | static uint8_t rnt_array[16] = {1, 0, 0, 0, 0, 0, 0, 0, |
7103 | | 0, 9, 10, 0, 0, 13, 0, 0}; |
7104 | | const uint8x16_t rnt = vld1q_u8(rnt_array); |
7105 | | // m['0xd', '0xa', '0x9'] |
7106 | | uint8x16_t running{0}; |
7107 | | for (; i + 15 < user_input.size(); i += 16) { |
7108 | | uint8x16_t word = vld1q_u8((const uint8_t*)user_input.data() + i); |
7109 | | |
7110 | | running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); |
7111 | | } |
7112 | | if (i < user_input.size()) { |
7113 | | uint8x16_t word = |
7114 | | vld1q_u8((const uint8_t*)user_input.data() + user_input.length() - 16); |
7115 | | running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); |
7116 | | } |
7117 | | // `running` accumulates comparison results, so every lane is 0x00 or 0xFF: |
7118 | | // narrowing to four bits per lane and testing against zero is cheaper than a |
7119 | | // horizontal maximum. The double compare (ADA_NEON_SAFE_ZERO_CHECK set to 0) |
7120 | | // avoids a GPR transfer but is incorrect if flush-to-zero is enabled. |
7121 | | uint8x8_t narrowed = vshrn_n_u16(vreinterpretq_u16_u8(running), 4); |
7122 | | #if ADA_NEON_SAFE_ZERO_CHECK |
7123 | | return vget_lane_u64(vreinterpret_u64_u8(narrowed), 0) != 0; |
7124 | | #else |
7125 | | return vdupd_lane_f64(vreinterpret_f64_u8(narrowed), 0) != 0.0; |
7126 | | #endif |
7127 | | } |
7128 | | #elif ADA_SSE2 |
7129 | | ada_really_inline bool has_tabs_or_newline( |
7130 | 127k | std::string_view user_input) noexcept { |
7131 | | // first check for short strings in which case we do it naively. |
7132 | 127k | if (user_input.size() < 16) { // slow path |
7133 | 95.4k | return std::ranges::any_of(user_input, is_tabs_or_newline); |
7134 | 95.4k | } |
7135 | | // fast path for long strings (expected to be common) |
7136 | 32.4k | size_t i = 0; |
7137 | 32.4k | const __m128i mask1 = _mm_set1_epi8('\r'); |
7138 | 32.4k | const __m128i mask2 = _mm_set1_epi8('\n'); |
7139 | 32.4k | const __m128i mask3 = _mm_set1_epi8('\t'); |
7140 | | // If we supported SSSE3, we could use the algorithm that we use for NEON. |
7141 | 32.4k | __m128i running{0}; |
7142 | 163k | for (; i + 15 < user_input.size(); i += 16) { |
7143 | 131k | __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i)); |
7144 | 131k | running = _mm_or_si128( |
7145 | 131k | _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), |
7146 | 131k | _mm_cmpeq_epi8(word, mask2))), |
7147 | 131k | _mm_cmpeq_epi8(word, mask3)); |
7148 | 131k | } |
7149 | 32.4k | if (i < user_input.size()) { |
7150 | 28.3k | __m128i word = _mm_loadu_si128( |
7151 | 28.3k | (const __m128i*)(user_input.data() + user_input.length() - 16)); |
7152 | 28.3k | running = _mm_or_si128( |
7153 | 28.3k | _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), |
7154 | 28.3k | _mm_cmpeq_epi8(word, mask2))), |
7155 | 28.3k | _mm_cmpeq_epi8(word, mask3)); |
7156 | 28.3k | } |
7157 | 32.4k | return _mm_movemask_epi8(running) != 0; |
7158 | 127k | } |
7159 | | #elif ADA_LSX |
7160 | | ada_really_inline bool has_tabs_or_newline( |
7161 | | std::string_view user_input) noexcept { |
7162 | | // first check for short strings in which case we do it naively. |
7163 | | if (user_input.size() < 16) { // slow path |
7164 | | return std::ranges::any_of(user_input, is_tabs_or_newline); |
7165 | | } |
7166 | | // fast path for long strings (expected to be common) |
7167 | | size_t i = 0; |
7168 | | const __m128i mask1 = __lsx_vrepli_b('\r'); |
7169 | | const __m128i mask2 = __lsx_vrepli_b('\n'); |
7170 | | const __m128i mask3 = __lsx_vrepli_b('\t'); |
7171 | | // If we supported SSSE3, we could use the algorithm that we use for NEON. |
7172 | | __m128i running{0}; |
7173 | | for (; i + 15 < user_input.size(); i += 16) { |
7174 | | __m128i word = __lsx_vld((const __m128i*)(user_input.data() + i), 0); |
7175 | | running = __lsx_vor_v( |
7176 | | __lsx_vor_v(running, __lsx_vor_v(__lsx_vseq_b(word, mask1), |
7177 | | __lsx_vseq_b(word, mask2))), |
7178 | | __lsx_vseq_b(word, mask3)); |
7179 | | } |
7180 | | if (i < user_input.size()) { |
7181 | | __m128i word = __lsx_vld( |
7182 | | (const __m128i*)(user_input.data() + user_input.length() - 16), 0); |
7183 | | running = __lsx_vor_v( |
7184 | | __lsx_vor_v(running, __lsx_vor_v(__lsx_vseq_b(word, mask1), |
7185 | | __lsx_vseq_b(word, mask2))), |
7186 | | __lsx_vseq_b(word, mask3)); |
7187 | | } |
7188 | | if (__lsx_bz_v(running)) return false; |
7189 | | return true; |
7190 | | } |
7191 | | #elif ADA_RVV |
7192 | | ada_really_inline bool has_tabs_or_newline( |
7193 | | std::string_view user_input) noexcept { |
7194 | | uint8_t* src = (uint8_t*)user_input.data(); |
7195 | | for (size_t vl, n = user_input.size(); n > 0; n -= vl, src += vl) { |
7196 | | vl = __riscv_vsetvl_e8m1(n); |
7197 | | vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); |
7198 | | vbool8_t m1 = __riscv_vmseq(v, '\r', vl); |
7199 | | vbool8_t m2 = __riscv_vmseq(v, '\n', vl); |
7200 | | vbool8_t m3 = __riscv_vmseq(v, '\t', vl); |
7201 | | vbool8_t m = __riscv_vmor(__riscv_vmor(m1, m2, vl), m3, vl); |
7202 | | long idx = __riscv_vfirst(m, vl); |
7203 | | if (idx >= 0) return true; |
7204 | | } |
7205 | | return false; |
7206 | | } |
7207 | | #else |
7208 | | ada_really_inline bool has_tabs_or_newline( |
7209 | | std::string_view user_input) noexcept { |
7210 | | auto has_zero_byte = [](uint64_t v) { |
7211 | | return ((v - 0x0101010101010101) & ~(v) & 0x8080808080808080); |
7212 | | }; |
7213 | | size_t i = 0; |
7214 | | uint64_t mask1 = broadcast('\r'); |
7215 | | uint64_t mask2 = broadcast('\n'); |
7216 | | uint64_t mask3 = broadcast('\t'); |
7217 | | uint64_t running{0}; |
7218 | | for (; i + 7 < user_input.size(); i += 8) { |
7219 | | uint64_t word{}; |
7220 | | memcpy(&word, user_input.data() + i, sizeof(word)); |
7221 | | uint64_t xor1 = word ^ mask1; |
7222 | | uint64_t xor2 = word ^ mask2; |
7223 | | uint64_t xor3 = word ^ mask3; |
7224 | | running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); |
7225 | | } |
7226 | | if (i < user_input.size()) { |
7227 | | uint64_t word{}; |
7228 | | memcpy(&word, user_input.data() + i, user_input.size() - i); |
7229 | | uint64_t xor1 = word ^ mask1; |
7230 | | uint64_t xor2 = word ^ mask2; |
7231 | | uint64_t xor3 = word ^ mask3; |
7232 | | running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); |
7233 | | } |
7234 | | return running; |
7235 | | } |
7236 | | #endif |
7237 | | |
7238 | | // A forbidden host code point is U+0000 NULL, U+0009 TAB, U+000A LF, U+000D CR, |
7239 | | // U+0020 SPACE, U+0023 (#), U+002F (/), U+003A (:), U+003C (<), U+003E (>), |
7240 | | // U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), or |
7241 | | // U+007C (|). |
7242 | | constexpr static std::array<uint8_t, 256> is_forbidden_host_code_point_table = |
7243 | | []() consteval { |
7244 | | std::array<uint8_t, 256> result{}; |
7245 | | for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', |
7246 | | '>', '?', '@', '[', '\\', ']', '^', '|'}) { |
7247 | | result[c] = true; |
7248 | | } |
7249 | | return result; |
7250 | | }(); |
7251 | | |
7252 | | ada_really_inline constexpr bool is_forbidden_host_code_point( |
7253 | 70.8k | const char c) noexcept { |
7254 | 70.8k | return is_forbidden_host_code_point_table[uint8_t(c)]; |
7255 | 70.8k | } |
7256 | | |
7257 | | constexpr static std::array<uint8_t, 256> is_forbidden_domain_code_point_table = |
7258 | | []() consteval { |
7259 | | std::array<uint8_t, 256> result{}; |
7260 | | for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', |
7261 | | '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { |
7262 | | result[c] = true; |
7263 | | } |
7264 | | for (uint8_t c = 0; c <= 32; c++) { |
7265 | | result[c] = true; |
7266 | | } |
7267 | | for (size_t c = 127; c < 256; c++) { |
7268 | | result[c] = true; |
7269 | | } |
7270 | | return result; |
7271 | | }(); |
7272 | | |
7273 | | static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); |
7274 | | |
7275 | | ada_really_inline constexpr bool is_forbidden_domain_code_point( |
7276 | 1.05M | const char c) noexcept { |
7277 | 1.05M | return is_forbidden_domain_code_point_table[uint8_t(c)]; |
7278 | 1.05M | } |
7279 | | |
7280 | | ada_really_inline constexpr bool contains_forbidden_domain_code_point( |
7281 | 14.8k | const char* input, size_t length) noexcept { |
7282 | 14.8k | size_t i = 0; |
7283 | 14.8k | uint8_t accumulator{}; |
7284 | 284k | for (; i + 4 <= length; i += 4) { |
7285 | 270k | accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; |
7286 | 270k | accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])]; |
7287 | 270k | accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])]; |
7288 | 270k | accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])]; |
7289 | 270k | } |
7290 | 38.0k | for (; i < length; i++) { |
7291 | 23.1k | accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; |
7292 | 23.1k | } |
7293 | 14.8k | return accumulator; |
7294 | 14.8k | } |
7295 | | |
7296 | | constexpr static std::array<uint8_t, 256> |
7297 | | is_forbidden_domain_code_point_table_or_upper = []() consteval { |
7298 | | std::array<uint8_t, 256> result{}; |
7299 | | for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', |
7300 | | '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { |
7301 | | result[c] = 1; |
7302 | | } |
7303 | | for (uint8_t c = 'A'; c <= 'Z'; c++) { |
7304 | | result[c] = 2; |
7305 | | } |
7306 | | for (uint8_t c = 0; c <= 32; c++) { |
7307 | | result[c] = 1; |
7308 | | } |
7309 | | for (size_t c = 127; c < 256; c++) { |
7310 | | result[c] = 1; |
7311 | | } |
7312 | | return result; |
7313 | | }(); |
7314 | | |
7315 | | ada_really_inline constexpr uint8_t |
7316 | | contains_forbidden_domain_code_point_or_upper(const char* input, |
7317 | 42.5k | size_t length) noexcept { |
7318 | 42.5k | size_t i = 0; |
7319 | 42.5k | uint8_t accumulator{}; |
7320 | 276k | for (; i + 4 <= length; i += 4) { |
7321 | 234k | accumulator |= |
7322 | 234k | is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; |
7323 | 234k | accumulator |= |
7324 | 234k | is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])]; |
7325 | 234k | accumulator |= |
7326 | 234k | is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])]; |
7327 | 234k | accumulator |= |
7328 | 234k | is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])]; |
7329 | 234k | } |
7330 | 104k | for (; i < length; i++) { |
7331 | 61.8k | accumulator |= |
7332 | 61.8k | is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; |
7333 | 61.8k | } |
7334 | 42.5k | return accumulator; |
7335 | 42.5k | } |
7336 | | |
7337 | | // std::isalnum(c) || c == '+' || c == '-' || c == '.') is true for |
7338 | | constexpr static std::array<bool, 256> is_alnum_plus_table = []() consteval { |
7339 | | std::array<bool, 256> result{}; |
7340 | | for (size_t c = 0; c < 256; c++) { |
7341 | | result[c] = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || |
7342 | | (c >= 'A' && c <= 'Z') || c == '+' || c == '-' || c == '.'; |
7343 | | } |
7344 | | return result; |
7345 | | }(); |
7346 | | |
7347 | 181k | ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept { |
7348 | 181k | return is_alnum_plus_table[uint8_t(c)]; |
7349 | | // A table is almost surely much faster than the |
7350 | | // following under most compilers: return |
7351 | | // return (std::isalnum(c) || c == '+' || c == '-' || c == '.'); |
7352 | 181k | } |
7353 | | |
7354 | 22.9k | ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept { |
7355 | 22.9k | return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || |
7356 | 10.3k | (c >= 'a' && c <= 'f'); |
7357 | 22.9k | } |
7358 | | |
7359 | 0 | ada_really_inline constexpr bool is_ascii_digit(const char c) noexcept { |
7360 | | // An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), |
7361 | | // inclusive. |
7362 | 0 | return (c >= '0' && c <= '9'); |
7363 | 0 | } |
7364 | | |
7365 | 0 | ada_really_inline constexpr bool is_ascii(const char32_t c) noexcept { |
7366 | | // If code point is between U+0000 and U+007F inclusive, then return true. |
7367 | 0 | return c <= 0x7F; |
7368 | 0 | } |
7369 | | |
7370 | 151k | ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept { |
7371 | 151k | return (unsigned char)c <= ' '; |
7372 | 151k | } |
7373 | | |
7374 | | ada_really_inline constexpr bool is_ascii_tab_or_newline( |
7375 | 46.3k | const char c) noexcept { |
7376 | 46.3k | return c == '\t' || c == '\n' || c == '\r'; |
7377 | 46.3k | } |
7378 | | |
7379 | | constexpr std::string_view table_is_double_dot_path_segment[] = { |
7380 | | "..", "%2e.", ".%2e", "%2e%2e"}; |
7381 | | |
7382 | | ada_really_inline constexpr bool is_double_dot_path_segment( |
7383 | 59.7k | std::string_view input) noexcept { |
7384 | | // This will catch most cases: |
7385 | | // The length must be 2,4 or 6. |
7386 | | // We divide by two and require |
7387 | | // that the result be between 1 and 3 inclusively. |
7388 | 59.7k | uint64_t half_length = uint64_t(input.size()) / 2; |
7389 | 59.7k | if (half_length - 1 > 2) { |
7390 | 34.0k | return false; |
7391 | 34.0k | } |
7392 | | // We have a string of length 2, 4 or 6. |
7393 | | // We now check the first character: |
7394 | 25.6k | if ((input[0] != '.') && (input[0] != '%')) { |
7395 | 5.25k | return false; |
7396 | 5.25k | } |
7397 | | // We are unlikely the get beyond this point. |
7398 | 20.4k | int hash_value = (input.size() + (unsigned)(input[0])) & 3; |
7399 | 20.4k | const std::string_view target = table_is_double_dot_path_segment[hash_value]; |
7400 | 20.4k | if (target.size() != input.size()) { |
7401 | 5.67k | return false; |
7402 | 5.67k | } |
7403 | | // We almost never get here. |
7404 | | // Optimizing the rest is relatively unimportant. |
7405 | 14.7k | auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) { |
7406 | 14.7k | uint16_t A, B; |
7407 | 14.7k | memcpy(&A, a.data(), sizeof(A)); |
7408 | 14.7k | memcpy(&B, b.data(), sizeof(B)); |
7409 | 14.7k | return A == B; |
7410 | 14.7k | }; |
7411 | 14.7k | if (!prefix_equal_unsafe(input, target)) { |
7412 | 3.02k | return false; |
7413 | 3.02k | } |
7414 | 16.8k | for (size_t i = 2; i < input.size(); i++) { |
7415 | 8.06k | char c = input[i]; |
7416 | 8.06k | if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) { |
7417 | 2.94k | return false; |
7418 | 2.94k | } |
7419 | 8.06k | } |
7420 | 8.77k | return true; |
7421 | | // The above code might be a bit better than the code below. Compilers |
7422 | | // are not stupid and may use the fact that these strings have length 2,4 and |
7423 | | // 6 and other tricks. |
7424 | | // return input == ".." || |
7425 | | // input == ".%2e" || input == ".%2E" || |
7426 | | // input == "%2e." || input == "%2E." || |
7427 | | // input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input == |
7428 | | // "%2e%2E"; |
7429 | 11.7k | } |
7430 | | |
7431 | | ada_really_inline constexpr bool is_single_dot_path_segment( |
7432 | 101k | std::string_view input) noexcept { |
7433 | 101k | return input == "." || input == "%2e" || input == "%2E"; |
7434 | 101k | } |
7435 | | |
7436 | 25.5k | ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept { |
7437 | 25.5k | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); |
7438 | 25.5k | } |
7439 | | |
7440 | | constexpr static char hex_to_binary_table[] = { |
7441 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, |
7442 | | 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7443 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; |
7444 | 12.4k | unsigned constexpr convert_hex_to_binary(const char c) noexcept { |
7445 | 12.4k | return hex_to_binary_table[c - '0']; |
7446 | 12.4k | } |
7447 | | |
7448 | 4.03k | std::string percent_decode(const std::string_view input, size_t first_percent) { |
7449 | | // next line is for safety only, we expect users to avoid calling |
7450 | | // percent_decode when first_percent is outside the range. |
7451 | 4.03k | if (first_percent == std::string_view::npos) { |
7452 | 0 | return std::string(input); |
7453 | 0 | } |
7454 | | |
7455 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) |
7456 | 4.03k | const char* const src = input.data(); |
7457 | 4.03k | const char* const end = src + input.size(); |
7458 | | |
7459 | | // Decoding never grows the string, so a single pre-sized buffer written via |
7460 | | // bulk memcpy of the plain runs (then shrunk to the final length) avoids the |
7461 | | // byte-at-a-time appends of the naive version. |
7462 | 4.03k | std::string out(input.size(), '\0'); |
7463 | 4.03k | char* d = out.data(); |
7464 | 4.03k | char* const d0 = d; |
7465 | | |
7466 | 4.03k | std::memcpy(d, src, first_percent); |
7467 | 4.03k | d += first_percent; |
7468 | | |
7469 | 4.03k | const char* p = src + first_percent; |
7470 | 21.5k | while (p < end) { |
7471 | 17.5k | if (*p == '%') { |
7472 | | // Decode runs of valid %XX tightly (common for nested/encoded URLs). |
7473 | 18.0k | while (p + 2 < end && *p == '%') { |
7474 | 14.0k | if (!is_ascii_hex_digit(p[1]) || !is_ascii_hex_digit(p[2])) { |
7475 | 7.78k | break; |
7476 | 7.78k | } |
7477 | 6.23k | *d++ = static_cast<char>(convert_hex_to_binary(p[1]) * 16 + |
7478 | 6.23k | convert_hex_to_binary(p[2])); |
7479 | 6.23k | p += 3; |
7480 | 6.23k | } |
7481 | 11.8k | if (p < end && *p == '%') { |
7482 | | // Not a valid escape (too few chars left or bad hex): copy '%' |
7483 | | // literally and keep scanning after it. |
7484 | 8.59k | *d++ = *p++; |
7485 | 8.59k | } |
7486 | 11.8k | } else { |
7487 | 5.75k | const char* q = static_cast<const char*>( |
7488 | 5.75k | std::memchr(p, '%', static_cast<size_t>(end - p))); |
7489 | 5.75k | const char* run_end = q ? q : end; |
7490 | 5.75k | const size_t n = static_cast<size_t>(run_end - p); |
7491 | 5.75k | std::memcpy(d, p, n); |
7492 | 5.75k | d += n; |
7493 | 5.75k | p = run_end; |
7494 | 5.75k | } |
7495 | 17.5k | } |
7496 | | |
7497 | 4.03k | out.resize(static_cast<size_t>(d - d0)); |
7498 | 4.03k | return out; |
7499 | 4.03k | } |
7500 | | |
7501 | | // 0..15 for hex digits, 0xFF otherwise - validate and decode with two loads. |
7502 | | constexpr static std::array<uint8_t, 256> unhex_table = []() consteval { |
7503 | | std::array<uint8_t, 256> t{}; |
7504 | | for (size_t i = 0; i < 256; ++i) { |
7505 | | t[i] = 0xFF; |
7506 | | } |
7507 | | for (uint8_t i = 0; i < 10; ++i) { |
7508 | | t[static_cast<size_t>('0') + i] = i; |
7509 | | } |
7510 | | for (uint8_t i = 0; i < 6; ++i) { |
7511 | | t[static_cast<size_t>('A') + i] = static_cast<uint8_t>(10 + i); |
7512 | | t[static_cast<size_t>('a') + i] = static_cast<uint8_t>(10 + i); |
7513 | | } |
7514 | | return t; |
7515 | | }(); |
7516 | | |
7517 | 0 | std::string form_urlencoded_decode(const std::string_view input) { |
7518 | 0 | const size_t len = input.size(); |
7519 | 0 | if (len == 0) [[unlikely]] { |
7520 | 0 | return {}; |
7521 | 0 | } |
7522 | | |
7523 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) |
7524 | 0 | const char* const src = input.data(); |
7525 | 0 | const char* const end = src + len; |
7526 | 0 | const char* p = src; |
7527 | | |
7528 | | // Advance over the untransformed prefix. |
7529 | 0 | while (p < end && *p != '+' && *p != '%') { |
7530 | 0 | ++p; |
7531 | 0 | } |
7532 | 0 | if (p == end) { |
7533 | 0 | return std::string(input); |
7534 | 0 | } |
7535 | | |
7536 | | // Output is always at most as long as the input: write into a single |
7537 | | // pre-sized buffer, then shrink to the final length. |
7538 | 0 | std::string out(len, '\0'); |
7539 | 0 | char* d = out.data(); |
7540 | 0 | char* const d0 = d; |
7541 | |
|
7542 | 0 | const size_t prefix = static_cast<size_t>(p - src); |
7543 | 0 | std::memcpy(d, src, prefix); |
7544 | 0 | d += prefix; |
7545 | |
|
7546 | 0 | while (p < end) { |
7547 | 0 | const char c = *p; |
7548 | 0 | if (c == '+') { |
7549 | 0 | *d++ = ' '; |
7550 | 0 | ++p; |
7551 | 0 | } else if (c == '%') { |
7552 | | // Decode runs of valid %XX tightly (common for nested URL query values). |
7553 | 0 | while (p + 2 < end && *p == '%') { |
7554 | 0 | const uint8_t hi = unhex_table[static_cast<uint8_t>(p[1])]; |
7555 | 0 | const uint8_t lo = unhex_table[static_cast<uint8_t>(p[2])]; |
7556 | 0 | if ((hi | lo) >= 16) { |
7557 | 0 | break; |
7558 | 0 | } |
7559 | 0 | *d++ = static_cast<char>((hi << 4) | lo); |
7560 | 0 | p += 3; |
7561 | 0 | } |
7562 | 0 | if (p < end && *p == '%') { |
7563 | | // Invalid escape: copy '%' literally and continue. |
7564 | 0 | *d++ = *p++; |
7565 | 0 | } |
7566 | 0 | } else { |
7567 | | // Copy a plain run until the next '+' or '%'. |
7568 | 0 | const char* start = p; |
7569 | 0 | ++p; |
7570 | 0 | while (p < end && *p != '+' && *p != '%') { |
7571 | 0 | ++p; |
7572 | 0 | } |
7573 | 0 | const size_t n = static_cast<size_t>(p - start); |
7574 | 0 | std::memcpy(d, start, n); |
7575 | 0 | d += n; |
7576 | 0 | } |
7577 | 0 | } |
7578 | |
|
7579 | 0 | out.resize(static_cast<size_t>(d - d0)); |
7580 | 0 | return out; |
7581 | 0 | } |
7582 | | |
7583 | | void percent_encode_suffix(const char* p, const char* end, |
7584 | | const uint8_t character_set[], std::string& out); |
7585 | | |
7586 | | std::string percent_encode(const std::string_view input, |
7587 | 22.8k | const uint8_t character_set[]) { |
7588 | 104k | auto pointer = std::ranges::find_if(input, [character_set](const char c) { |
7589 | 104k | return character_sets::bit_at(character_set, c); |
7590 | 104k | }); |
7591 | | // Optimization: Don't iterate if percent encode is not required |
7592 | 22.8k | if (pointer == input.end()) { |
7593 | 18.8k | return std::string(input); |
7594 | 18.8k | } |
7595 | | |
7596 | 4.01k | std::string result; |
7597 | 4.01k | result.reserve(input.length()); // in the worst case, percent encoding might |
7598 | | // produce 3 characters. |
7599 | 4.01k | result.append(input.substr(0, std::distance(input.begin(), pointer))); |
7600 | 4.01k | if (static_cast<size_t>(input.end() - pointer) >= 48) { |
7601 | 645 | percent_encode_suffix(&*pointer, input.data() + input.size(), character_set, |
7602 | 645 | result); |
7603 | 3.37k | } else { |
7604 | 28.4k | for (; pointer != input.end(); pointer++) { |
7605 | 25.0k | if (character_sets::bit_at(character_set, *pointer)) { |
7606 | 21.6k | result.append(character_sets::hex + uint8_t(*pointer) * 4, 3); |
7607 | 21.6k | } else { |
7608 | 3.43k | result += *pointer; |
7609 | 3.43k | } |
7610 | 25.0k | } |
7611 | 3.37k | } |
7612 | 4.01k | return result; |
7613 | 22.8k | } |
7614 | | |
7615 | | template <bool append> |
7616 | | bool percent_encode(const std::string_view input, const uint8_t character_set[], |
7617 | 27.0k | std::string& out) { |
7618 | 27.0k | ada_log("percent_encode ", input, " to output string while ", |
7619 | 27.0k | append ? "appending" : "overwriting"); |
7620 | 67.4k | auto pointer = std::ranges::find_if(input, [character_set](const char c) { |
7621 | 67.4k | return character_sets::bit_at(character_set, c); |
7622 | 67.4k | }); ada::unicode::percent_encode<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)::{lambda(char)#1}::operator()(char) constLine | Count | Source | 7620 | 67.4k | auto pointer = std::ranges::find_if(input, [character_set](const char c) { | 7621 | 67.4k | return character_sets::bit_at(character_set, c); | 7622 | 67.4k | }); |
Unexecuted instantiation: ada::unicode::percent_encode<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)::{lambda(char)#1}::operator()(char) const |
7623 | 27.0k | ada_log("percent_encode done checking, moved to ", |
7624 | 27.0k | std::distance(input.begin(), pointer)); |
7625 | | |
7626 | | // Optimization: Don't iterate if percent encode is not required |
7627 | 27.0k | if (pointer == input.end()) { |
7628 | 16.5k | ada_log("percent_encode encoding not needed."); |
7629 | 16.5k | return false; |
7630 | 16.5k | } |
7631 | 10.5k | if constexpr (!append) { |
7632 | 0 | out.clear(); |
7633 | 0 | } |
7634 | 10.5k | ada_log("percent_encode appending ", std::distance(input.begin(), pointer), |
7635 | 10.5k | " bytes"); |
7636 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) |
7637 | 10.5k | out.append(input.data(), std::distance(input.begin(), pointer)); |
7638 | 10.5k | ada_log("percent_encode processing ", std::distance(pointer, input.end()), |
7639 | 10.5k | " bytes"); |
7640 | 119k | for (; pointer != input.end(); pointer++) { |
7641 | 109k | if (character_sets::bit_at(character_set, *pointer)) { |
7642 | 99.6k | out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); |
7643 | 99.6k | } else { |
7644 | 9.60k | out += *pointer; |
7645 | 9.60k | } |
7646 | 109k | } |
7647 | 10.5k | return true; |
7648 | 27.0k | } bool ada::unicode::percent_encode<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 7617 | 27.0k | std::string& out) { | 7618 | 27.0k | ada_log("percent_encode ", input, " to output string while ", | 7619 | 27.0k | append ? "appending" : "overwriting"); | 7620 | 27.0k | auto pointer = std::ranges::find_if(input, [character_set](const char c) { | 7621 | 27.0k | return character_sets::bit_at(character_set, c); | 7622 | 27.0k | }); | 7623 | 27.0k | ada_log("percent_encode done checking, moved to ", | 7624 | 27.0k | std::distance(input.begin(), pointer)); | 7625 | | | 7626 | | // Optimization: Don't iterate if percent encode is not required | 7627 | 27.0k | if (pointer == input.end()) { | 7628 | 16.5k | ada_log("percent_encode encoding not needed."); | 7629 | 16.5k | return false; | 7630 | 16.5k | } | 7631 | | if constexpr (!append) { | 7632 | | out.clear(); | 7633 | | } | 7634 | 10.5k | ada_log("percent_encode appending ", std::distance(input.begin(), pointer), | 7635 | 10.5k | " bytes"); | 7636 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) | 7637 | 10.5k | out.append(input.data(), std::distance(input.begin(), pointer)); | 7638 | 10.5k | ada_log("percent_encode processing ", std::distance(pointer, input.end()), | 7639 | 10.5k | " bytes"); | 7640 | 119k | for (; pointer != input.end(); pointer++) { | 7641 | 109k | if (character_sets::bit_at(character_set, *pointer)) { | 7642 | 99.6k | out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); | 7643 | 99.6k | } else { | 7644 | 9.60k | out += *pointer; | 7645 | 9.60k | } | 7646 | 109k | } | 7647 | 10.5k | return true; | 7648 | 27.0k | } |
Unexecuted instantiation: bool ada::unicode::percent_encode<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) |
7649 | | |
7650 | | template bool percent_encode<true>(std::string_view input, |
7651 | | const uint8_t character_set[], |
7652 | | std::string& out); |
7653 | | template bool percent_encode<false>(std::string_view input, |
7654 | | const uint8_t character_set[], |
7655 | | std::string& out); |
7656 | | |
7657 | | bool to_ascii(std::optional<std::string>& out, const std::string_view plain, |
7658 | 19.5k | size_t first_percent) { |
7659 | 19.5k | std::string percent_decoded_buffer; |
7660 | 19.5k | std::string_view input = plain; |
7661 | 19.5k | if (first_percent != std::string_view::npos) { |
7662 | 1.12k | percent_decoded_buffer = unicode::percent_decode(plain, first_percent); |
7663 | 1.12k | input = percent_decoded_buffer; |
7664 | 1.12k | } |
7665 | | // input is a non-empty UTF-8 string, must be percent decoded |
7666 | 19.5k | std::string idna_ascii = ada::idna::to_ascii(input); |
7667 | 19.5k | if (idna_ascii.empty() || contains_forbidden_domain_code_point( |
7668 | 14.8k | idna_ascii.data(), idna_ascii.size())) { |
7669 | 5.77k | return false; |
7670 | 5.77k | } |
7671 | 13.7k | out = std::move(idna_ascii); |
7672 | 13.7k | return true; |
7673 | 19.5k | } |
7674 | | |
7675 | | std::string percent_encode(const std::string_view input, |
7676 | 480 | const uint8_t character_set[], size_t index) { |
7677 | 480 | std::string out; |
7678 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) |
7679 | 480 | out.append(input.data(), index); |
7680 | 480 | auto pointer = input.begin() + index; |
7681 | 480 | if (static_cast<size_t>(input.end() - pointer) >= 48) { |
7682 | 182 | percent_encode_suffix(&*pointer, input.data() + input.size(), character_set, |
7683 | 182 | out); |
7684 | 298 | } else { |
7685 | 2.83k | for (; pointer != input.end(); pointer++) { |
7686 | 2.54k | if (character_sets::bit_at(character_set, *pointer)) { |
7687 | 2.10k | out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); |
7688 | 2.10k | } else { |
7689 | 432 | out += *pointer; |
7690 | 432 | } |
7691 | 2.54k | } |
7692 | 298 | } |
7693 | 480 | return out; |
7694 | 480 | } |
7695 | | |
7696 | | } // namespace ada::unicode |
7697 | | /* end file src/unicode.cpp */ |
7698 | | #if !defined(ADA_PERCENT_ENCODE_SIMD_SEPARATE_TU) |
7699 | | /* begin file src/unicode_percent_encode.cpp */ |
7700 | | #include <cstdint> |
7701 | | |
7702 | | |
7703 | | |
7704 | | #include <cstring> |
7705 | | #include <string> |
7706 | | #if ADA_SSSE3 |
7707 | | #include <tmmintrin.h> |
7708 | | #define ADA_UNICODE_SSSE3 1 |
7709 | | #elif ADA_NEON |
7710 | | #include <arm_neon.h> |
7711 | | #elif ADA_RVV |
7712 | | #include <riscv_vector.h> |
7713 | | #endif |
7714 | | |
7715 | | // gcc/clang honor target("ssse3") on an SSE2 translation unit. clang-cl and |
7716 | | // MSVC do not: they still compile the function as SSE2, then reject |
7717 | | // always_inline _mm_shuffle_epi8. Same approach as parser.cpp. |
7718 | | #if !ADA_UNICODE_SSSE3 && (defined(__x86_64__) || defined(__amd64__)) && \ |
7719 | | defined(__GNUC__) && !defined(_MSC_VER) |
7720 | | #include <tmmintrin.h> |
7721 | | #define ADA_UNICODE_SSSE3 1 |
7722 | | #define ADA_UNICODE_NEED_SSSE3_TARGET 1 |
7723 | | #endif |
7724 | | #ifndef ADA_UNICODE_SSSE3 |
7725 | | #define ADA_UNICODE_SSSE3 0 |
7726 | | #endif |
7727 | | #ifdef ADA_UNICODE_NEED_SSSE3_TARGET |
7728 | | // noinline: these functions must not be inlined into a caller that also |
7729 | | // contains the CPU check. A target("ssse3") function can use SSSE3 in its |
7730 | | // prologue, before any check inside it would run. |
7731 | | #define ADA_UNICODE_SIMD __attribute__((target("ssse3"), noinline)) |
7732 | | #else |
7733 | | #define ADA_UNICODE_SIMD ada_really_inline |
7734 | | #endif |
7735 | | |
7736 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
7737 | | #include <intrin.h> |
7738 | | #endif |
7739 | | |
7740 | | namespace ada::unicode { |
7741 | | namespace { |
7742 | | |
7743 | | #if ADA_UNICODE_SSSE3 || ADA_NEON |
7744 | 46.4k | ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept { |
7745 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
7746 | | unsigned long ret; |
7747 | | _BitScanForward(&ret, input_num); |
7748 | | return static_cast<int>(ret); |
7749 | | #else |
7750 | 46.4k | return __builtin_ctz(input_num); |
7751 | 46.4k | #endif |
7752 | 46.4k | } |
7753 | | |
7754 | | // Append one window whose set bits mark bytes that need encoding. |
7755 | | ada_really_inline void encode_mask_window(const char* p, uint32_t mask, |
7756 | 3.86k | size_t width, std::string& out) { |
7757 | 3.86k | uint64_t bits = mask; |
7758 | 3.86k | size_t off = 0; |
7759 | 50.2k | while (bits != 0) { |
7760 | 46.4k | const int zero_run = trailing_zeroes32(static_cast<uint32_t>(bits)); |
7761 | 46.4k | if (zero_run != 0) { |
7762 | 2.99k | out.append(p + off, static_cast<size_t>(zero_run)); |
7763 | 2.99k | } |
7764 | 46.4k | off += static_cast<size_t>(zero_run); |
7765 | 46.4k | out.append(character_sets::hex + uint8_t(p[off]) * 4, 3); |
7766 | 46.4k | ++off; |
7767 | 46.4k | bits >>= static_cast<unsigned>(zero_run + 1); |
7768 | 46.4k | } |
7769 | 3.86k | if (off < width) { |
7770 | 1.06k | out.append(p + off, width - off); |
7771 | 1.06k | } |
7772 | 3.86k | } |
7773 | | #endif // ADA_UNICODE_SSSE3 || ADA_NEON |
7774 | | |
7775 | | ada_really_inline void percent_encode_to_scalar(const char* p, const char* end, |
7776 | | const uint8_t character_set[], |
7777 | 827 | std::string& out) { |
7778 | 3.37k | for (; p != end; ++p) { |
7779 | 2.54k | if (character_sets::bit_at(character_set, *p)) { |
7780 | 1.97k | out.append(character_sets::hex + uint8_t(*p) * 4, 3); |
7781 | 1.97k | } else { |
7782 | 564 | out += *p; |
7783 | 564 | } |
7784 | 2.54k | } |
7785 | 827 | } |
7786 | | |
7787 | | #if ADA_UNICODE_SSSE3 |
7788 | | // Classify 16 input bytes against the 32-byte character_set bitmap: |
7789 | | // bit_at(cs, b) == cs[b >> 3] & (1 << (b & 7)). pshufb looks up the two |
7790 | | // 16-byte halves of that bitmap; no per-call nibble table is built. |
7791 | | struct ssse3_percent_tables { |
7792 | | __m128i cs_lo; |
7793 | | __m128i cs_hi; |
7794 | | __m128i pow2; |
7795 | | __m128i mask_0f; |
7796 | | __m128i mask_07; |
7797 | | __m128i zero; |
7798 | | }; |
7799 | | |
7800 | | ADA_UNICODE_SIMD ssse3_percent_tables |
7801 | 827 | load_ssse3_percent_tables(const uint8_t character_set[]) noexcept { |
7802 | 827 | ssse3_percent_tables t{}; |
7803 | 827 | t.cs_lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set)); |
7804 | 827 | t.cs_hi = |
7805 | 827 | _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set + 16)); |
7806 | | // 1 << (0..7), duplicated so pshufb(index & 7) works for every lane. |
7807 | 827 | t.pow2 = |
7808 | 827 | _mm_setr_epi8(1, 2, 4, 8, 16, 32, 64, -128, 1, 2, 4, 8, 16, 32, 64, -128); |
7809 | 827 | t.mask_0f = _mm_set1_epi8(0x0F); |
7810 | 827 | t.mask_07 = _mm_set1_epi8(0x07); |
7811 | 827 | t.zero = _mm_setzero_si128(); |
7812 | 827 | return t; |
7813 | 827 | } |
7814 | | |
7815 | | ADA_UNICODE_SIMD int ssse3_percent_mask( |
7816 | 4.44k | __m128i word, const ssse3_percent_tables& tables) noexcept { |
7817 | 4.44k | const __m128i idx = _mm_and_si128(_mm_srli_epi16(word, 3), tables.mask_0f); |
7818 | 4.44k | const __m128i lo = _mm_shuffle_epi8(tables.cs_lo, idx); |
7819 | 4.44k | const __m128i hi = _mm_shuffle_epi8(tables.cs_hi, idx); |
7820 | | // Bytes 0x80-0xFF are signed-negative; select the high half of the bitmap. |
7821 | 4.44k | const __m128i high_byte = _mm_cmpgt_epi8(tables.zero, word); |
7822 | 4.44k | const __m128i cs_byte = _mm_or_si128(_mm_and_si128(hi, high_byte), |
7823 | 4.44k | _mm_andnot_si128(high_byte, lo)); |
7824 | 4.44k | const __m128i bits = |
7825 | 4.44k | _mm_shuffle_epi8(tables.pow2, _mm_and_si128(word, tables.mask_07)); |
7826 | 4.44k | const __m128i hits = _mm_and_si128(cs_byte, bits); |
7827 | 4.44k | return _mm_movemask_epi8(_mm_cmpeq_epi8(hits, tables.zero)) ^ 0xFFFF; |
7828 | 4.44k | } |
7829 | | |
7830 | | ADA_UNICODE_SIMD void percent_encode_to_ssse3( |
7831 | | const char* p, const char* end, const uint8_t character_set[], |
7832 | 827 | const ssse3_percent_tables& tables, std::string& out) { |
7833 | | // Pair 16-byte windows so a fully clean 32-byte run is one append. |
7834 | 2.77k | while (p + 32 <= end) { |
7835 | 1.95k | const __m128i word0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p)); |
7836 | 1.95k | const __m128i word1 = |
7837 | 1.95k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16)); |
7838 | 1.95k | const int mask0 = ssse3_percent_mask(word0, tables); |
7839 | 1.95k | const int mask1 = ssse3_percent_mask(word1, tables); |
7840 | 1.95k | if ((mask0 | mask1) == 0) { |
7841 | 126 | out.append(p, 32); |
7842 | 1.82k | } else { |
7843 | 1.82k | if (mask0 == 0) { |
7844 | 108 | out.append(p, 16); |
7845 | 1.71k | } else { |
7846 | 1.71k | encode_mask_window(p, static_cast<uint32_t>(mask0), 16, out); |
7847 | 1.71k | } |
7848 | 1.82k | if (mask1 == 0) { |
7849 | 178 | out.append(p + 16, 16); |
7850 | 1.64k | } else { |
7851 | 1.64k | encode_mask_window(p + 16, static_cast<uint32_t>(mask1), 16, out); |
7852 | 1.64k | } |
7853 | 1.82k | } |
7854 | 1.95k | p += 32; |
7855 | 1.95k | } |
7856 | 827 | if (p + 16 <= end) { |
7857 | 543 | const __m128i word = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p)); |
7858 | 543 | const int mask = ssse3_percent_mask(word, tables); |
7859 | 543 | if (mask == 0) { |
7860 | 49 | out.append(p, 16); |
7861 | 494 | } else { |
7862 | 494 | encode_mask_window(p, static_cast<uint32_t>(mask), 16, out); |
7863 | 494 | } |
7864 | 543 | p += 16; |
7865 | 543 | } |
7866 | 827 | percent_encode_to_scalar(p, end, character_set, out); |
7867 | 827 | } |
7868 | | #endif // ADA_UNICODE_SSSE3 |
7869 | | |
7870 | | #if ADA_NEON |
7871 | | ada_really_inline uint8x16x2_t |
7872 | | load_neon_percent_table(const uint8_t character_set[]) noexcept { |
7873 | | uint8x16x2_t table{}; |
7874 | | table.val[0] = vld1q_u8(character_set); |
7875 | | table.val[1] = vld1q_u8(character_set + 16); |
7876 | | return table; |
7877 | | } |
7878 | | |
7879 | | ada_really_inline uint8x16_t neon_percent_hits(uint8x16_t word, |
7880 | | uint8x16x2_t table) noexcept { |
7881 | | const uint8x16_t cs_bytes = vqtbl2q_u8(table, vshrq_n_u8(word, 3)); |
7882 | | const uint8x16_t bit_mask = vshlq_u8( |
7883 | | vdupq_n_u8(1), vreinterpretq_s8_u8(vandq_u8(word, vdupq_n_u8(7)))); |
7884 | | return vandq_u8(cs_bytes, bit_mask); |
7885 | | } |
7886 | | |
7887 | | ada_really_inline uint32_t neon_percent_mask(uint8x16_t hits) noexcept { |
7888 | | const uint8x16_t cmp = vcgtq_u8(hits, vdupq_n_u8(0)); |
7889 | | const uint8x16_t bit = {1, 2, 4, 8, 16, 32, 64, 128, |
7890 | | 1, 2, 4, 8, 16, 32, 64, 128}; |
7891 | | const uint8x16_t masked = vandq_u8(cmp, bit); |
7892 | | return static_cast<uint32_t>(vaddv_u8(vget_low_u8(masked))) | |
7893 | | (static_cast<uint32_t>(vaddv_u8(vget_high_u8(masked))) << 8); |
7894 | | } |
7895 | | |
7896 | | ada_really_inline void percent_encode_to_neon(const char* p, const char* end, |
7897 | | const uint8_t character_set[], |
7898 | | uint8x16x2_t table, |
7899 | | std::string& out) { |
7900 | | while (p + 32 <= end) { |
7901 | | const uint8x16_t hits0 = |
7902 | | neon_percent_hits(vld1q_u8(reinterpret_cast<const uint8_t*>(p)), table); |
7903 | | const uint8x16_t hits1 = neon_percent_hits( |
7904 | | vld1q_u8(reinterpret_cast<const uint8_t*>(p + 16)), table); |
7905 | | const bool clean0 = vmaxvq_u32(vreinterpretq_u32_u8(hits0)) == 0; |
7906 | | const bool clean1 = vmaxvq_u32(vreinterpretq_u32_u8(hits1)) == 0; |
7907 | | if (clean0 && clean1) { |
7908 | | out.append(p, 32); |
7909 | | } else { |
7910 | | if (clean0) { |
7911 | | out.append(p, 16); |
7912 | | } else { |
7913 | | encode_mask_window(p, neon_percent_mask(hits0), 16, out); |
7914 | | } |
7915 | | if (clean1) { |
7916 | | out.append(p + 16, 16); |
7917 | | } else { |
7918 | | encode_mask_window(p + 16, neon_percent_mask(hits1), 16, out); |
7919 | | } |
7920 | | } |
7921 | | p += 32; |
7922 | | } |
7923 | | if (p + 16 <= end) { |
7924 | | const uint8x16_t hits = |
7925 | | neon_percent_hits(vld1q_u8(reinterpret_cast<const uint8_t*>(p)), table); |
7926 | | if (vmaxvq_u32(vreinterpretq_u32_u8(hits)) == 0) { |
7927 | | out.append(p, 16); |
7928 | | } else { |
7929 | | encode_mask_window(p, neon_percent_mask(hits), 16, out); |
7930 | | } |
7931 | | p += 16; |
7932 | | } |
7933 | | percent_encode_to_scalar(p, end, character_set, out); |
7934 | | } |
7935 | | #endif // ADA_NEON |
7936 | | |
7937 | | #if ADA_RVV |
7938 | | ada_really_inline void percent_encode_to_rvv(const char* p, const char* end, |
7939 | | const uint8_t character_set[], |
7940 | | std::string& out) { |
7941 | | while (p < end) { |
7942 | | const size_t remaining = static_cast<size_t>(end - p); |
7943 | | const size_t vl = __riscv_vsetvl_e8m1(remaining); |
7944 | | const vuint8m1_t word = |
7945 | | __riscv_vle8_v_u8m1(reinterpret_cast<const uint8_t*>(p), vl); |
7946 | | const vuint8m1_t cs_bytes = |
7947 | | __riscv_vluxei8(character_set, __riscv_vsrl(word, 3, vl), vl); |
7948 | | const vuint8m1_t bit_mask = __riscv_vsll(__riscv_vmv_v_x_u8m1(1, vl), |
7949 | | __riscv_vand(word, 7, vl), vl); |
7950 | | const long idx = __riscv_vfirst( |
7951 | | __riscv_vmsne(__riscv_vand(cs_bytes, bit_mask, vl), 0, vl), vl); |
7952 | | if (idx < 0) { |
7953 | | out.append(p, vl); |
7954 | | p += vl; |
7955 | | continue; |
7956 | | } |
7957 | | if (idx > 0) { |
7958 | | out.append(p, static_cast<size_t>(idx)); |
7959 | | p += idx; |
7960 | | } |
7961 | | out.append(character_sets::hex + uint8_t(*p) * 4, 3); |
7962 | | ++p; |
7963 | | } |
7964 | | } |
7965 | | #endif // ADA_RVV |
7966 | | |
7967 | | #if ADA_UNICODE_SSSE3 || ADA_NEON || ADA_RVV |
7968 | | // Setter and existing percent_encode benches are 2-44 bytes. Table setup |
7969 | | // plus mask walking costs more instructions than bit_at on those inputs |
7970 | | // (especially dense USERINFO). SIMD pays off on the remaining suffix. |
7971 | | static constexpr size_t kPercentEncodeSimdMin = 48; |
7972 | | |
7973 | | void percent_encode_to_wide(const char* p, const char* end, |
7974 | 827 | const uint8_t character_set[], std::string& out) { |
7975 | | // Worst case every byte becomes %XX. Avoids realloc while walking windows. |
7976 | 827 | out.reserve(out.size() + static_cast<size_t>(end - p) * 3); |
7977 | 827 | #if ADA_UNICODE_SSSE3 |
7978 | 827 | const ssse3_percent_tables tables = load_ssse3_percent_tables(character_set); |
7979 | 827 | percent_encode_to_ssse3(p, end, character_set, tables, out); |
7980 | | #elif ADA_NEON |
7981 | | percent_encode_to_neon(p, end, character_set, |
7982 | | load_neon_percent_table(character_set), out); |
7983 | | #elif ADA_RVV |
7984 | | percent_encode_to_rvv(p, end, character_set, out); |
7985 | | #endif |
7986 | 827 | } |
7987 | | #endif |
7988 | | |
7989 | | } // namespace |
7990 | | |
7991 | | void percent_encode_suffix(const char* p, const char* end, |
7992 | 827 | const uint8_t character_set[], std::string& out) { |
7993 | 827 | #if ADA_UNICODE_SSSE3 || ADA_NEON || ADA_RVV |
7994 | 827 | #ifdef ADA_UNICODE_NEED_SSSE3_TARGET |
7995 | 827 | static const bool ssse3_supported = __builtin_cpu_supports("ssse3") != 0; |
7996 | 827 | const bool use_wide = ssse3_supported; |
7997 | | #else |
7998 | | const bool use_wide = true; |
7999 | | #endif |
8000 | 827 | if (use_wide && static_cast<size_t>(end - p) >= kPercentEncodeSimdMin) { |
8001 | 827 | percent_encode_to_wide(p, end, character_set, out); |
8002 | 827 | return; |
8003 | 827 | } |
8004 | 0 | #endif |
8005 | 0 | percent_encode_to_scalar(p, end, character_set, out); |
8006 | 0 | } |
8007 | | |
8008 | | } // namespace ada::unicode |
8009 | | /* end file src/unicode_percent_encode.cpp */ |
8010 | | #endif |
8011 | | /* begin file src/serializers.cpp */ |
8012 | | |
8013 | | #include <array> |
8014 | | #include <cstdint> |
8015 | | #include <cstring> |
8016 | | #include <string> |
8017 | | |
8018 | | namespace ada::serializers { |
8019 | | namespace { |
8020 | | |
8021 | | // Digit pair LUT for fast decimal write: index 0..99 -> two chars. |
8022 | 0 | constexpr std::array<char, 200> make_digit_pairs() noexcept { |
8023 | 0 | std::array<char, 200> t{}; |
8024 | 0 | for (size_t i = 0; i < 100; ++i) { |
8025 | 0 | t[i * 2] = static_cast<char>('0' + i / 10); |
8026 | 0 | t[i * 2 + 1] = static_cast<char>('0' + i % 10); |
8027 | 0 | } |
8028 | 0 | return t; |
8029 | 0 | } |
8030 | | |
8031 | | constexpr auto digit_pairs = make_digit_pairs(); |
8032 | | |
8033 | 17.2k | ada_really_inline char* write_u8(char* p, uint8_t v) noexcept { |
8034 | 17.2k | if (v < 10) { |
8035 | 14.3k | *p++ = static_cast<char>('0' + v); |
8036 | 14.3k | } else if (v < 100) { |
8037 | 1.20k | std::memcpy(p, &digit_pairs[static_cast<size_t>(v) * 2], 2); |
8038 | 1.20k | p += 2; |
8039 | 1.69k | } else { |
8040 | 1.69k | *p++ = static_cast<char>('0' + v / 100); |
8041 | 1.69k | std::memcpy(p, &digit_pairs[static_cast<size_t>(v % 100) * 2], 2); |
8042 | 1.69k | p += 2; |
8043 | 1.69k | } |
8044 | 17.2k | return p; |
8045 | 17.2k | } |
8046 | | |
8047 | 2.37k | ada_really_inline char* write_hex_u16(char* p, uint16_t v) noexcept { |
8048 | 2.37k | static constexpr char kHex[] = "0123456789abcdef"; |
8049 | 2.37k | if (v >= 0x1000) { |
8050 | 252 | *p++ = kHex[(v >> 12) & 0xf]; |
8051 | 252 | *p++ = kHex[(v >> 8) & 0xf]; |
8052 | 252 | *p++ = kHex[(v >> 4) & 0xf]; |
8053 | 252 | *p++ = kHex[v & 0xf]; |
8054 | 2.12k | } else if (v >= 0x100) { |
8055 | 300 | *p++ = kHex[(v >> 8) & 0xf]; |
8056 | 300 | *p++ = kHex[(v >> 4) & 0xf]; |
8057 | 300 | *p++ = kHex[v & 0xf]; |
8058 | 1.82k | } else if (v >= 0x10) { |
8059 | 333 | *p++ = kHex[(v >> 4) & 0xf]; |
8060 | 333 | *p++ = kHex[v & 0xf]; |
8061 | 1.49k | } else { |
8062 | 1.49k | *p++ = kHex[v & 0xf]; |
8063 | 1.49k | } |
8064 | 2.37k | return p; |
8065 | 2.37k | } |
8066 | | |
8067 | | } // namespace |
8068 | | |
8069 | | void find_longest_sequence_of_ipv6_pieces( |
8070 | | const std::array<uint16_t, 8>& address, size_t& compress, |
8071 | 978 | size_t& compress_length) noexcept { |
8072 | 978 | compress = 0; |
8073 | 978 | compress_length = 0; |
8074 | 978 | size_t i = 0; |
8075 | 4.20k | while (i < 8) { |
8076 | 3.22k | if (address[i] != 0) { |
8077 | 2.01k | ++i; |
8078 | 2.01k | continue; |
8079 | 2.01k | } |
8080 | 1.20k | size_t next = i + 1; |
8081 | 5.80k | while (next < 8 && address[next] == 0) { |
8082 | 4.59k | ++next; |
8083 | 4.59k | } |
8084 | 1.20k | const size_t count = next - i; |
8085 | 1.20k | if (count > compress_length) { |
8086 | 1.01k | compress_length = count; |
8087 | 1.01k | compress = i; |
8088 | 1.01k | } |
8089 | 1.20k | i = next; |
8090 | 1.20k | } |
8091 | 978 | } |
8092 | | |
8093 | 978 | std::string ipv6(const std::array<uint16_t, 8>& address) { |
8094 | 978 | size_t compress = 0; |
8095 | 978 | size_t compress_length = 0; |
8096 | 978 | find_longest_sequence_of_ipv6_pieces(address, compress, compress_length); |
8097 | | |
8098 | | // Skip compression when the longest zero run is a single piece. |
8099 | 978 | if (compress_length <= 1) { |
8100 | 117 | compress = compress_length = 8; |
8101 | 117 | } |
8102 | | |
8103 | | // Max: '[' + 8*4 hex + 7 ':' + ']' = 41 |
8104 | 978 | char output[4 * 8 + 7 + 2]; |
8105 | 978 | char* point = output; |
8106 | 978 | *point++ = '['; |
8107 | 978 | size_t piece_index = 0; |
8108 | 2.83k | while (true) { |
8109 | 2.83k | if (piece_index == compress) { |
8110 | 861 | *point++ = ':'; |
8111 | | // If we skip a value initially, we need to write '::'. |
8112 | 861 | if (piece_index == 0) { |
8113 | 537 | *point++ = ':'; |
8114 | 537 | } |
8115 | 861 | piece_index += compress_length; |
8116 | 861 | if (piece_index == 8) { |
8117 | 456 | break; |
8118 | 456 | } |
8119 | 861 | } |
8120 | 2.37k | point = write_hex_u16(point, address[piece_index]); |
8121 | 2.37k | ++piece_index; |
8122 | 2.37k | if (piece_index == 8) { |
8123 | 522 | break; |
8124 | 522 | } |
8125 | 1.85k | *point++ = ':'; |
8126 | 1.85k | } |
8127 | 978 | *point++ = ']'; |
8128 | 978 | return std::string(output, static_cast<size_t>(point - output)); |
8129 | 978 | } |
8130 | | |
8131 | 4.30k | std::string ipv4(const uint64_t address) { |
8132 | 4.30k | std::string output(15, '\0'); |
8133 | 4.30k | char* point = output.data(); |
8134 | 4.30k | point = write_u8(point, static_cast<uint8_t>(address >> 24)); |
8135 | 4.30k | *point++ = '.'; |
8136 | 4.30k | point = write_u8(point, static_cast<uint8_t>(address >> 16)); |
8137 | 4.30k | *point++ = '.'; |
8138 | 4.30k | point = write_u8(point, static_cast<uint8_t>(address >> 8)); |
8139 | 4.30k | *point++ = '.'; |
8140 | 4.30k | point = write_u8(point, static_cast<uint8_t>(address)); |
8141 | 4.30k | output.resize(static_cast<size_t>(point - output.data())); |
8142 | 4.30k | return output; |
8143 | 4.30k | } |
8144 | | |
8145 | | } // namespace ada::serializers |
8146 | | /* end file src/serializers.cpp */ |
8147 | | /* begin file src/implementation.cpp */ |
8148 | | |
8149 | | #include <array> |
8150 | | #include <atomic> |
8151 | | #include <cstdint> |
8152 | | #include <cstring> |
8153 | | #include <limits> |
8154 | | #include <optional> |
8155 | | #include <string> |
8156 | | #include <string_view> |
8157 | | |
8158 | | |
8159 | | namespace ada { |
8160 | | |
8161 | | static std::atomic<uint32_t> max_input_length_{ |
8162 | | std::numeric_limits<uint32_t>::max()}; |
8163 | | |
8164 | 0 | void set_max_input_length(uint32_t length) { |
8165 | 0 | max_input_length_.store(length, std::memory_order_relaxed); |
8166 | 0 | } |
8167 | | |
8168 | 159k | uint32_t get_max_input_length() { |
8169 | 159k | return max_input_length_.load(std::memory_order_relaxed); |
8170 | 159k | } |
8171 | | |
8172 | | namespace { |
8173 | | |
8174 | | constexpr std::array<uint8_t, 256> clean_http_host_byte = []() consteval { |
8175 | | std::array<uint8_t, 256> result{}; |
8176 | | for (size_t i = 0; i < result.size(); ++i) { |
8177 | | const auto c = static_cast<uint8_t>(i); |
8178 | | result[i] = |
8179 | | static_cast<uint8_t>((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || |
8180 | | c == '-' || c == '.' || c == '_' || c == '~'); |
8181 | | } |
8182 | | return result; |
8183 | | }(); |
8184 | | |
8185 | | // SWAR: eight ASCII host bytes in [a-z0-9-._~] without 8 table lookups. |
8186 | | // High bits must be clear first so the range subtracts cannot borrow |
8187 | | // across bytes. |
8188 | | // High-bit-cleared ASCII only. Subtracts cannot borrow across bytes because |
8189 | | // each (hi|0x80) byte is >= 0x80 and each data byte is <= 0x7F. Do not use |
8190 | | // has-zero (x-ones)&~x: a match followed by match^1 (e.g. "./" or "_^") |
8191 | | // produces a false positive via borrow. |
8192 | | ada_really_inline uint64_t swar_in_range(uint64_t w, uint8_t lo, |
8193 | 7.76k | uint8_t hi) noexcept { |
8194 | 7.76k | constexpr uint64_t k_ones = 0x0101010101010101ull; |
8195 | 7.76k | constexpr uint64_t k_high = 0x8080808080808080ull; |
8196 | 7.76k | const uint64_t ge_lo = (w | k_high) - (k_ones * lo); |
8197 | 7.76k | const uint64_t le_hi = ((k_ones * hi) | k_high) - w; |
8198 | 7.76k | return ge_lo & le_hi & k_high; |
8199 | 7.76k | } |
8200 | | |
8201 | | ada_really_inline bool eight_clean_http_host_bytes( |
8202 | 1.30k | const uint8_t* input) noexcept { |
8203 | 1.30k | uint64_t w = 0; |
8204 | 1.30k | std::memcpy(&w, input, 8); |
8205 | 1.30k | constexpr uint64_t k_high = 0x8080808080808080ull; |
8206 | 1.30k | if ((w & k_high) != 0) { |
8207 | 10 | return false; |
8208 | 10 | } |
8209 | 1.29k | const uint64_t ok = swar_in_range(w, 'a', 'z') | swar_in_range(w, '0', '9') | |
8210 | 1.29k | swar_in_range(w, '-', '-') | swar_in_range(w, '.', '.') | |
8211 | 1.29k | swar_in_range(w, '_', '_') | swar_in_range(w, '~', '~'); |
8212 | 1.29k | return ok == k_high; |
8213 | 1.30k | } |
8214 | | |
8215 | | // Minimal front end for the overwhelmingly common already-canonical HTTP(S) |
8216 | | // case. It deliberately handles fewer inputs than |
8217 | | // try_can_parse_absolute_fast: anything requiring normalization or detailed |
8218 | | // host parsing falls through to that broader validator. |
8219 | | #if defined(_MSC_VER) || \ |
8220 | | (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
8221 | | constexpr bool k_can_parse_little_endian = true; |
8222 | | #else |
8223 | | constexpr bool k_can_parse_little_endian = false; |
8224 | | #endif |
8225 | | |
8226 | 32.4k | std::optional<bool> try_can_parse_clean_http(std::string_view input) noexcept { |
8227 | 32.4k | const auto* bytes = reinterpret_cast<const uint8_t*>(input.data()); |
8228 | 32.4k | const size_t length = input.size(); |
8229 | 32.4k | if (length < 7) { |
8230 | 15.1k | return std::nullopt; |
8231 | 15.1k | } |
8232 | | |
8233 | 17.3k | size_t authority_start; |
8234 | 17.3k | if constexpr (k_can_parse_little_endian) { |
8235 | 17.3k | if (length >= 8) { |
8236 | 15.9k | uint64_t first8 = 0; |
8237 | 15.9k | std::memcpy(&first8, bytes, 8); |
8238 | 15.9k | if (first8 == 0x2f2f3a7370747468ull) { // "https://" |
8239 | 8 | authority_start = 8; |
8240 | 15.9k | } else if ((first8 & 0x00ffffffffffffffull) == |
8241 | 15.9k | 0x002f2f3a70747468ull) { // "http://" |
8242 | 357 | authority_start = 7; |
8243 | 15.6k | } else { |
8244 | 15.6k | return std::nullopt; |
8245 | 15.6k | } |
8246 | 15.9k | } else if (bytes[0] == 'h' && bytes[1] == 't' && bytes[2] == 't' && |
8247 | 52 | bytes[3] == 'p' && bytes[4] == ':' && bytes[5] == '/' && |
8248 | 7 | bytes[6] == '/') { |
8249 | 2 | authority_start = 7; |
8250 | 1.36k | } else { |
8251 | 1.36k | return std::nullopt; |
8252 | 1.36k | } |
8253 | | } else { |
8254 | | uint32_t first4{}; |
8255 | | std::memcpy(&first4, bytes, 4); |
8256 | | if (first4 != 0x68747470u) { // "http" |
8257 | | return std::nullopt; |
8258 | | } |
8259 | | if (length >= 8 && bytes[4] == 's' && bytes[5] == ':' && bytes[6] == '/' && |
8260 | | bytes[7] == '/') { |
8261 | | authority_start = 8; |
8262 | | } else if (bytes[4] == ':' && bytes[5] == '/' && bytes[6] == '/') { |
8263 | | authority_start = 7; |
8264 | | } else { |
8265 | | return std::nullopt; |
8266 | | } |
8267 | | } |
8268 | | |
8269 | 17.3k | if (authority_start >= length) { |
8270 | 2 | return false; |
8271 | 2 | } |
8272 | | |
8273 | 17.3k | size_t cursor = authority_start; |
8274 | 18.4k | while (cursor + 8 <= length && eight_clean_http_host_bytes(bytes + cursor)) { |
8275 | 1.12k | cursor += 8; |
8276 | 1.12k | } |
8277 | 17.9k | while (cursor < length) { |
8278 | 967 | const uint8_t c = bytes[cursor]; |
8279 | 967 | if (c == '/' || c == '?' || c == '#') { |
8280 | 225 | break; |
8281 | 225 | } |
8282 | 742 | if (!clean_http_host_byte[c]) { |
8283 | 109 | return std::nullopt; |
8284 | 109 | } |
8285 | 633 | ++cursor; |
8286 | 633 | } |
8287 | | |
8288 | 17.2k | const size_t host_length = cursor - authority_start; |
8289 | 17.2k | if (host_length == 0) { |
8290 | | // Extra special-scheme slashes are normalization, not an empty host. |
8291 | 3 | if (bytes[authority_start] == '/' || bytes[authority_start] == '\\') { |
8292 | 1 | return std::nullopt; |
8293 | 1 | } |
8294 | 2 | return false; |
8295 | 3 | } |
8296 | 17.2k | if (host_length > 253 || bytes[cursor - 1] == '.') { |
8297 | 38 | return std::nullopt; |
8298 | 38 | } |
8299 | | |
8300 | 17.2k | const std::string_view host(input.data() + authority_start, host_length); |
8301 | 17.2k | if (checkers::last_label_may_be_a_number(host)) { |
8302 | 21 | return std::nullopt; |
8303 | 21 | } |
8304 | 17.1k | if (host.find('x') != std::string_view::npos && |
8305 | 86 | host.find("xn-") != std::string_view::npos) { |
8306 | 25 | return std::nullopt; |
8307 | 25 | } |
8308 | | |
8309 | | // Once a special URL has a valid host, path/query/fragment bytes cannot make |
8310 | | // it structurally invalid: the full parser percent-encodes them as needed. |
8311 | 17.1k | return true; |
8312 | 17.1k | } |
8313 | | |
8314 | | // @private |
8315 | | // Fast-path validator for can_parse. |
8316 | | // |
8317 | | // Validates absolute special (non-file) URLs without constructing any |
8318 | | // url_aggregator object and without running the state machine. |
8319 | | // Performs a single forward scan over the input bytes. |
8320 | | // |
8321 | | // Returns: |
8322 | | // true -- URL is structurally valid |
8323 | | // false -- URL is definitely invalid |
8324 | | // nullopt -- edge case; fall through to the full parser |
8325 | | // (credentials, IDNA, IPv4/6, tabs/newlines, relative URLs, ...) |
8326 | | std::optional<bool> try_can_parse_absolute_fast( |
8327 | 32.3k | std::string_view input) noexcept { |
8328 | 32.3k | const uint8_t* b = reinterpret_cast<const uint8_t*>(input.data()); |
8329 | 32.3k | size_t len = input.size(); |
8330 | | |
8331 | | // -- Inline C0 whitespace trim (no allocation) -------------------------- |
8332 | | // Note: \t (0x09), \n (0x0a), \r (0x0d) are all <= 0x20, so any |
8333 | | // leading/trailing tabs or newlines are correctly stripped here, matching |
8334 | | // the WHATWG spec's "remove leading/trailing C0 control and space" step. |
8335 | 33.7k | while (len > 0 && b[0] <= 0x20) { |
8336 | 1.43k | b++; |
8337 | 1.43k | len--; |
8338 | 1.43k | } |
8339 | 33.8k | while (len > 0 && b[len - 1] <= 0x20) { |
8340 | 1.57k | len--; |
8341 | 1.57k | } |
8342 | 32.3k | if (len == 0) return false; |
8343 | | |
8344 | | // -- Scheme detection ----------------------------------------------------- |
8345 | | // Fast path for HTTP and HTTPS (covers ~90%+ of real-world URLs). |
8346 | | // Avoids the general scheme loop, buffer copy, and perfect hash lookup. |
8347 | | // We know HTTP and HTTPS are special non-file schemes, so no further |
8348 | | // scheme_type checks are needed on the fast path -- only `pos` matters. |
8349 | 19.8k | size_t pos; |
8350 | | |
8351 | 19.8k | if (len >= 7 && (b[0] | 0x20) == 'h' && (b[1] | 0x20) == 't' && |
8352 | 387 | (b[2] | 0x20) == 't' && (b[3] | 0x20) == 'p') { |
8353 | 337 | if (b[4] == ':' && b[5] == '/' && b[6] == '/') { |
8354 | 189 | pos = 7; |
8355 | 189 | goto skip_extra_slashes; |
8356 | 189 | } |
8357 | 148 | if (len >= 8 && (b[4] | 0x20) == 's' && b[5] == ':' && b[6] == '/' && |
8358 | 8 | b[7] == '/') { |
8359 | 7 | pos = 8; |
8360 | 7 | goto skip_extra_slashes; |
8361 | 7 | } |
8362 | | // Fall through: could be "httpe://", tabs in scheme, etc. |
8363 | 148 | } |
8364 | | |
8365 | 19.6k | { |
8366 | | // General scheme detection for ws, wss, ftp, and edge cases. |
8367 | 19.6k | if (!checkers::is_alpha(static_cast<char>(b[0]))) return false; |
8368 | | |
8369 | | // Scan for ':' within the first 7 bytes. All special schemes are <= 5 |
8370 | | // chars ("https"), so any URL whose first ':' is beyond byte 6 is either |
8371 | | // non-special or relative -- both require the full parser. |
8372 | 18.7k | size_t colon_pos = 0; |
8373 | 40.1k | for (size_t i = 1;; ++i) { |
8374 | 40.1k | if (i >= 7 || i >= len) return std::nullopt; |
8375 | 39.8k | const char c = static_cast<char>(b[i]); |
8376 | 39.8k | if (c == ':') { |
8377 | 18.1k | colon_pos = i; |
8378 | 18.1k | break; |
8379 | 18.1k | } |
8380 | | // Tabs/newlines in the scheme require the full parser to strip them. |
8381 | 21.7k | if (c == '\t' || c == '\n' || c == '\r') return std::nullopt; |
8382 | 21.7k | if (!unicode::is_alnum_plus(c)) return false; |
8383 | 21.7k | } |
8384 | | |
8385 | | // Lowercase scheme bytes inline and classify via the existing perfect |
8386 | | // hash. |
8387 | 18.1k | char scheme_buf[6]; |
8388 | 18.1k | scheme_buf[0] = static_cast<char>(b[0] | 0x20); |
8389 | 38.8k | for (size_t i = 1; i < colon_pos; ++i) |
8390 | 20.6k | scheme_buf[i] = static_cast<char>(b[i] | 0x20); |
8391 | | |
8392 | 18.1k | const ada::scheme::type scheme_type = |
8393 | 18.1k | ada::scheme::get_scheme_type({scheme_buf, colon_pos}); |
8394 | | |
8395 | | // Only handle special, non-file schemes. |
8396 | 18.1k | if (scheme_type == ada::scheme::NOT_SPECIAL) return std::nullopt; |
8397 | 15.5k | if (scheme_type == ada::scheme::FILE) return std::nullopt; |
8398 | | |
8399 | | // Per WHATWG, special URLs don't require "//": "http:example.com" is valid |
8400 | | // (SPECIAL_AUTHORITY_IGNORE_SLASHES just skips leading slashes and |
8401 | | // proceeds to AUTHORITY). Defer to the inline fallback for any input |
8402 | | // without "://". |
8403 | 13.7k | pos = colon_pos + 1; |
8404 | 13.7k | if (pos + 2 > len || b[pos] != '/' || b[pos + 1] != '/') { |
8405 | 6.28k | return std::nullopt; |
8406 | 6.28k | } |
8407 | 7.43k | pos += 2; |
8408 | 7.43k | } |
8409 | | |
8410 | 7.63k | skip_extra_slashes: |
8411 | | // SPECIAL_AUTHORITY_IGNORE_SLASHES: the full parser skips any additional |
8412 | | // leading '/' or '\' after the initial "//". Mirror that here so we don't |
8413 | | // mis-identify the host as empty when there are extra slashes. |
8414 | 8.13k | while (pos < len && (b[pos] == '/' || b[pos] == '\\')) { |
8415 | 507 | ++pos; |
8416 | 507 | } |
8417 | | |
8418 | | // Early IPv6 bail-out: if the authority starts with '[', it's an IPv6 |
8419 | | // literal which requires the full parser. Checking here avoids scanning |
8420 | | // the entire bracketed address only to bail out afterward. |
8421 | 7.63k | if (pos < len && b[pos] == '[') return std::nullopt; |
8422 | | |
8423 | | // -- Merged authority + host scan ------------------------------------------ |
8424 | | // A single forward pass over the authority bytes that simultaneously: |
8425 | | // - finds the authority end and port colon |
8426 | | // - validates host characters (forbidden domain code points) |
8427 | | // - tracks IPv4 indicators (all-decimal-dots, last non-dot char) |
8428 | | // - detects xn-- prefixes (IDNA punycode) |
8429 | | // - detects tabs/newlines (which require the full parser to strip) |
8430 | | // This replaces 4 separate scans over the host bytes. |
8431 | 7.53k | const size_t auth_start = pos; |
8432 | 7.53k | size_t auth_end = pos; |
8433 | 7.53k | size_t port_colon = SIZE_MAX; |
8434 | 7.53k | bool all_dec_dots = true; |
8435 | | |
8436 | 50.3k | for (; auth_end < len; ++auth_end) { |
8437 | 50.0k | const uint8_t c = b[auth_end]; |
8438 | | |
8439 | | // Non-ASCII -> needs IDNA processing -> full parser. |
8440 | 50.0k | if (c >= 0x80) return std::nullopt; |
8441 | | |
8442 | | // Authority delimiters. |
8443 | 50.0k | if (c == '/' || c == '?' || c == '#' || c == '\\') break; |
8444 | | |
8445 | | // Port separator. |
8446 | 44.4k | if (c == ':') { |
8447 | 2.12k | if (port_colon == SIZE_MAX) port_colon = auth_end; |
8448 | 2.12k | continue; |
8449 | 2.12k | } |
8450 | | |
8451 | | // Credentials or percent-encoding -> full parser. |
8452 | 42.3k | if (c == '@' || c == '%') return std::nullopt; |
8453 | | |
8454 | | // Tabs/newlines anywhere in the authority require the full parser to |
8455 | | // strip them before validation. Without this, a tab in the port (e.g. |
8456 | | // "http://host:8\t0/") would be mis-rejected by port validation. |
8457 | 42.0k | if (c == '\t' || c == '\n' || c == '\r') return std::nullopt; |
8458 | | |
8459 | | // Skip remaining host-specific checks for port bytes. Port digits are |
8460 | | // validated separately below, and no forbidden-domain-code-point check |
8461 | | // is needed on port characters. |
8462 | 42.0k | if (port_colon != SIZE_MAX) continue; |
8463 | | |
8464 | | // -- Host byte validation (inlined) ------------------------------------ |
8465 | | // Forbidden domain code points that are not already caught above: |
8466 | | // C0 controls and space (0x00-0x20), DEL (0x7F), <, >, [, ], ^, |. |
8467 | | // At this stage, the input may still be userinfo or be normalized later |
8468 | | // (e.g., percent-encoded), so we do not reject here and defer to the |
8469 | | // parser. Characters already caught: >= 0x80 (non-ASCII), '/' '?' '#' '\\' |
8470 | | // (delimiters), ':' (port), '@' '%' (bail), '\t' '\n' '\r' (bail). |
8471 | 39.4k | if (c <= 0x20 || c == 0x7F || c == '<' || c == '>' || c == '[' || |
8472 | 39.4k | c == ']' || c == '^' || c == '|') { |
8473 | 16 | return std::nullopt; |
8474 | 16 | } |
8475 | | |
8476 | | // Track whether host is all decimal digits and dots (potential IPv4). |
8477 | 39.3k | if (c != '.' && (c < '0' || c > '9')) all_dec_dots = false; |
8478 | | |
8479 | | // Detect xn-- prefix inline (IDNA punycode -> needs full parser). |
8480 | | // Checking at every position mirrors the original behavior: any |
8481 | | // occurrence of "xn--" in the host (not just at label boundaries) |
8482 | | // triggers a bail-out to the full IDNA validator. |
8483 | 39.3k | if ((c | 0x20) == 'x' && auth_end + 4 <= len && |
8484 | 5.73k | (b[auth_end + 1] | 0x20) == 'n' && b[auth_end + 2] == '-' && |
8485 | 1.68k | b[auth_end + 3] == '-') { |
8486 | 1.39k | return std::nullopt; |
8487 | 1.39k | } |
8488 | 39.3k | } |
8489 | | |
8490 | 5.81k | const size_t host_end = (port_colon != SIZE_MAX) ? port_colon : auth_end; |
8491 | | |
8492 | | // Empty host is invalid for special URLs. |
8493 | 5.81k | if (auth_start == host_end) return false; |
8494 | | |
8495 | | // -- IPv4 handling --------------------------------------------------------- |
8496 | 5.77k | const char* host_ptr = reinterpret_cast<const char*>(b + auth_start); |
8497 | 5.77k | const size_t host_len = host_end - auth_start; |
8498 | | |
8499 | 5.77k | if (all_dec_dots) { |
8500 | | // Host is all decimal digits and dots -> try the fast IPv4 parser. |
8501 | 1.35k | if (checkers::try_parse_ipv4_fast({host_ptr, host_len}) != |
8502 | 1.35k | checkers::ipv4_fast_fail) { |
8503 | | // Valid decimal IPv4 host. Do NOT return true yet: the port still |
8504 | | // needs to be validated below before we can declare the URL valid. |
8505 | 663 | goto validate_port; |
8506 | 663 | } |
8507 | | // Fast IPv4 parsing failed (e.g. host is ".", "..", "1.2.3.500"). |
8508 | | // Such hosts may still be valid domain names; defer to the full parser. |
8509 | 689 | return std::nullopt; |
8510 | 1.35k | } |
8511 | | |
8512 | 4.42k | if (checkers::last_label_may_be_a_number({host_ptr, host_len})) { |
8513 | 285 | return std::nullopt; |
8514 | 285 | } |
8515 | | |
8516 | | // -- Port validation ------------------------------------------------------- |
8517 | 4.80k | validate_port: |
8518 | 4.80k | if (port_colon != SIZE_MAX) { |
8519 | 1.60k | const uint8_t* pp = b + port_colon + 1; |
8520 | 1.60k | size_t pl = auth_end - port_colon - 1; |
8521 | 1.60k | if (pl > 0) { |
8522 | | // Strip leading zeros: "0000001" == 1, "0000000000000" == 0, both valid. |
8523 | | // Only the significant digits count toward the 5-digit maximum. |
8524 | 1.72k | while (pl > 0 && *pp == '0') { |
8525 | 530 | ++pp; |
8526 | 530 | --pl; |
8527 | 530 | } |
8528 | 1.19k | if (pl > 5) return false; // significant digits > 99999 |
8529 | 1.18k | uint32_t pv = 0; |
8530 | 2.45k | for (size_t i = 0; i < pl; ++i) { |
8531 | 1.27k | if (pp[i] < '0' || pp[i] > '9') return false; |
8532 | 1.26k | pv = pv * 10 + (pp[i] - '0'); |
8533 | 1.26k | } |
8534 | 1.17k | if (pv > 65535) return false; |
8535 | 1.17k | } |
8536 | 1.60k | } |
8537 | | |
8538 | | // Path, query, and fragment are structurally always valid for can_parse -- |
8539 | | // the parser would encode whatever is there. |
8540 | 4.78k | return true; |
8541 | 4.80k | } |
8542 | | |
8543 | | } // namespace |
8544 | | |
8545 | | template <class result_type> |
8546 | | ada_warn_unused tl::expected<result_type, errors> parse( |
8547 | 98.0k | std::string_view input, const result_type* base_url) { |
8548 | 98.0k | result_type u = ada::parser::parse_url_impl<result_type>(input, base_url); |
8549 | 98.0k | if (!u.is_valid) { |
8550 | 49.9k | return tl::unexpected(errors::type_error); |
8551 | 49.9k | } |
8552 | 48.1k | return u; |
8553 | 98.0k | } tl::expected<ada::url, ada::errors> ada::parse<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url const*) Line | Count | Source | 8547 | 49.0k | std::string_view input, const result_type* base_url) { | 8548 | 49.0k | result_type u = ada::parser::parse_url_impl<result_type>(input, base_url); | 8549 | 49.0k | if (!u.is_valid) { | 8550 | 24.9k | return tl::unexpected(errors::type_error); | 8551 | 24.9k | } | 8552 | 24.0k | return u; | 8553 | 49.0k | } |
tl::expected<ada::url_aggregator, ada::errors> ada::parse<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*) Line | Count | Source | 8547 | 49.0k | std::string_view input, const result_type* base_url) { | 8548 | 49.0k | result_type u = ada::parser::parse_url_impl<result_type>(input, base_url); | 8549 | 49.0k | if (!u.is_valid) { | 8550 | 24.9k | return tl::unexpected(errors::type_error); | 8551 | 24.9k | } | 8552 | 24.0k | return u; | 8553 | 49.0k | } |
|
8554 | | |
8555 | | template ada::result<url> parse<url>(std::string_view input, |
8556 | | const url* base_url = nullptr); |
8557 | | template ada::result<url_aggregator> parse<url_aggregator>( |
8558 | | std::string_view input, const url_aggregator* base_url = nullptr); |
8559 | | |
8560 | 0 | std::string href_from_file(std::string_view input) { |
8561 | | // Match ada::parse / setters: refuse inputs that already exceed the limit. |
8562 | | // Path percent-encoding can still expand the result, so we also check the |
8563 | | // final href below. |
8564 | 0 | const uint32_t max_length = ada::get_max_input_length(); |
8565 | 0 | if (input.size() > max_length) { |
8566 | 0 | return {}; |
8567 | 0 | } |
8568 | | |
8569 | | // This is going to be much faster than constructing a URL. |
8570 | 0 | std::string tmp_buffer; |
8571 | 0 | std::string_view internal_input; |
8572 | 0 | if (unicode::has_tabs_or_newline(input)) { |
8573 | 0 | tmp_buffer = input; |
8574 | 0 | helpers::remove_ascii_tab_or_newline(tmp_buffer); |
8575 | 0 | internal_input = tmp_buffer; |
8576 | 0 | } else { |
8577 | 0 | internal_input = input; |
8578 | 0 | } |
8579 | 0 | std::string path; |
8580 | 0 | if (internal_input.empty()) { |
8581 | 0 | path = "/"; |
8582 | 0 | } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { |
8583 | 0 | helpers::parse_prepared_path(internal_input.substr(1), |
8584 | 0 | ada::scheme::type::FILE, path); |
8585 | 0 | } else { |
8586 | 0 | helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path); |
8587 | 0 | } |
8588 | 0 | std::string result = "file://" + path; |
8589 | 0 | if (result.size() > max_length) { |
8590 | 0 | return {}; |
8591 | 0 | } |
8592 | 0 | return result; |
8593 | 0 | } |
8594 | | |
8595 | 44.6k | bool can_parse(std::string_view input, const std::string_view* base_input) { |
8596 | | // Must match parse().has_value(), including post-normalization max length. |
8597 | | // Percent-encoding expands a byte by at most 3x, but IDNA expands more: a |
8598 | | // 3-byte UTF-8 label such as U+337F becomes the 17-byte "xn--6oqv20b1zgzxr", |
8599 | | // so a dotted host sustains 4.5x. When the input (plus base, if any) fits in |
8600 | | // max_length/5, the normalized href cannot exceed max_length, so |
8601 | | // validation-only parsing (store_values=false) is safe. |
8602 | | |
8603 | | // Hot path first: absolute special URLs, no base. Avoid loading max_length |
8604 | | // until we need it (common absolute-fast true/false cases). |
8605 | 44.6k | if (base_input == nullptr) { |
8606 | 32.4k | auto r = try_can_parse_clean_http(input); |
8607 | 32.4k | if (!r.has_value()) { |
8608 | 32.3k | r = try_can_parse_absolute_fast(input); |
8609 | 32.3k | } |
8610 | 32.4k | if (r.has_value()) { |
8611 | 18.6k | if (!*r) { |
8612 | 13.6k | return false; |
8613 | 13.6k | } |
8614 | | // size <= max/5 => normalized href cannot exceed max (4.5x expansion). |
8615 | | // Check this first: default max is ~4GB so almost all URLs return true. |
8616 | 4.95k | const uint32_t max_length = ada::get_max_input_length(); |
8617 | 4.95k | if (input.size() <= static_cast<size_t>(max_length) / 5) { |
8618 | 4.95k | return true; |
8619 | 4.95k | } |
8620 | 0 | if (input.size() > max_length) { |
8621 | 0 | return false; |
8622 | 0 | } |
8623 | 0 | return ada::parser::parse_url_impl<ada::url_aggregator, true>(input, |
8624 | 0 | nullptr) |
8625 | 0 | .is_valid; |
8626 | 0 | } |
8627 | 32.4k | } |
8628 | | |
8629 | 26.0k | const uint32_t max_length = ada::get_max_input_length(); |
8630 | 26.0k | if (input.size() > max_length) { |
8631 | 0 | return false; |
8632 | 0 | } |
8633 | 26.0k | if (base_input != nullptr && base_input->size() > max_length) { |
8634 | 0 | return false; |
8635 | 0 | } |
8636 | | |
8637 | | // Relative resolution combines base + input; bound the sum so 4.5x expansion |
8638 | | // of either side cannot push the final href past max_length. |
8639 | 26.0k | const size_t combined = |
8640 | 26.0k | input.size() + (base_input == nullptr ? 0 : base_input->size()); |
8641 | 26.0k | const bool size_safe = combined <= static_cast<size_t>(max_length) / 5; |
8642 | | |
8643 | 26.0k | if (size_safe) { |
8644 | | // Validation-only: no buffer build, host still fully checked. |
8645 | 26.0k | ada::url_aggregator base_agg; |
8646 | 26.0k | ada::url_aggregator* base_ptr = nullptr; |
8647 | 26.0k | if (base_input != nullptr) { |
8648 | 12.1k | base_agg = ada::parser::parse_url_impl<ada::url_aggregator, false>( |
8649 | 12.1k | *base_input, nullptr); |
8650 | 12.1k | if (!base_agg.is_valid) { |
8651 | 7.82k | return false; |
8652 | 7.82k | } |
8653 | 4.35k | base_ptr = &base_agg; |
8654 | 4.35k | } |
8655 | 18.1k | return ada::parser::parse_url_impl<ada::url_aggregator, false>(input, |
8656 | 18.1k | base_ptr) |
8657 | 18.1k | .is_valid; |
8658 | 26.0k | } |
8659 | | |
8660 | | // Near the limit: full parse so post-normalization length matches parse(). |
8661 | 0 | if (base_input == nullptr) { |
8662 | 0 | return ada::parser::parse_url_impl<ada::url_aggregator, true>(input, |
8663 | 0 | nullptr) |
8664 | 0 | .is_valid; |
8665 | 0 | } |
8666 | 0 | ada::url_aggregator base_agg = |
8667 | 0 | ada::parser::parse_url_impl<ada::url_aggregator, true>(*base_input, |
8668 | 0 | nullptr); |
8669 | 0 | if (!base_agg.is_valid) { |
8670 | 0 | return false; |
8671 | 0 | } |
8672 | 0 | return ada::parser::parse_url_impl<ada::url_aggregator, true>(input, |
8673 | 0 | &base_agg) |
8674 | 0 | .is_valid; |
8675 | 0 | } |
8676 | | |
8677 | 0 | ada_warn_unused std::string_view to_string(ada::encoding_type type) { |
8678 | 0 | switch (type) { |
8679 | 0 | case ada::encoding_type::UTF8: |
8680 | 0 | return "UTF-8"; |
8681 | 0 | case ada::encoding_type::UTF_16LE: |
8682 | 0 | return "UTF-16LE"; |
8683 | 0 | case ada::encoding_type::UTF_16BE: |
8684 | 0 | return "UTF-16BE"; |
8685 | 0 | default: |
8686 | 0 | unreachable(); |
8687 | 0 | } |
8688 | 0 | } |
8689 | | |
8690 | | } // namespace ada |
8691 | | /* end file src/implementation.cpp */ |
8692 | | /* begin file src/helpers.cpp */ |
8693 | | #include <array> |
8694 | | #include <cstdint> |
8695 | | #include <cstring> |
8696 | | #include <optional> |
8697 | | #include <sstream> |
8698 | | #include <string> |
8699 | | #include <string_view> |
8700 | | #include <utility> |
8701 | | |
8702 | | |
8703 | | #if ADA_SSSE3 |
8704 | | #include <tmmintrin.h> |
8705 | | #endif |
8706 | | |
8707 | | namespace ada::helpers { |
8708 | | |
8709 | | template <typename out_iter> |
8710 | 0 | void encode_json(std::string_view view, out_iter out) { |
8711 | | // trivial implementation. could be faster. |
8712 | 0 | const char* hexvalues = |
8713 | 0 | "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; |
8714 | 0 | for (uint8_t c : view) { |
8715 | 0 | if (c == '\\') { |
8716 | 0 | *out++ = '\\'; |
8717 | 0 | *out++ = '\\'; |
8718 | 0 | } else if (c == '"') { |
8719 | 0 | *out++ = '\\'; |
8720 | 0 | *out++ = '"'; |
8721 | 0 | } else if (c <= 0x1f) { |
8722 | 0 | *out++ = '\\'; |
8723 | 0 | *out++ = 'u'; |
8724 | 0 | *out++ = '0'; |
8725 | 0 | *out++ = '0'; |
8726 | 0 | *out++ = hexvalues[2 * c]; |
8727 | 0 | *out++ = hexvalues[2 * c + 1]; |
8728 | 0 | } else { |
8729 | 0 | *out++ = c; |
8730 | 0 | } |
8731 | 0 | } |
8732 | 0 | } |
8733 | | |
8734 | 0 | ada_unused std::string get_state(ada::state s) { |
8735 | 0 | switch (s) { |
8736 | 0 | case ada::state::AUTHORITY: |
8737 | 0 | return "Authority"; |
8738 | 0 | case ada::state::SCHEME_START: |
8739 | 0 | return "Scheme Start"; |
8740 | 0 | case ada::state::SCHEME: |
8741 | 0 | return "Scheme"; |
8742 | 0 | case ada::state::HOST: |
8743 | 0 | return "Host"; |
8744 | 0 | case ada::state::NO_SCHEME: |
8745 | 0 | return "No Scheme"; |
8746 | 0 | case ada::state::FRAGMENT: |
8747 | 0 | return "Fragment"; |
8748 | 0 | case ada::state::RELATIVE_SCHEME: |
8749 | 0 | return "Relative Scheme"; |
8750 | 0 | case ada::state::RELATIVE_SLASH: |
8751 | 0 | return "Relative Slash"; |
8752 | 0 | case ada::state::FILE: |
8753 | 0 | return "File"; |
8754 | 0 | case ada::state::FILE_HOST: |
8755 | 0 | return "File Host"; |
8756 | 0 | case ada::state::FILE_SLASH: |
8757 | 0 | return "File Slash"; |
8758 | 0 | case ada::state::PATH_OR_AUTHORITY: |
8759 | 0 | return "Path or Authority"; |
8760 | 0 | case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: |
8761 | 0 | return "Special Authority Ignore Slashes"; |
8762 | 0 | case ada::state::SPECIAL_AUTHORITY_SLASHES: |
8763 | 0 | return "Special Authority Slashes"; |
8764 | 0 | case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: |
8765 | 0 | return "Special Relative or Authority"; |
8766 | 0 | case ada::state::QUERY: |
8767 | 0 | return "Query"; |
8768 | 0 | case ada::state::PATH: |
8769 | 0 | return "Path"; |
8770 | 0 | case ada::state::PATH_START: |
8771 | 0 | return "Path Start"; |
8772 | 0 | case ada::state::OPAQUE_PATH: |
8773 | 0 | return "Opaque Path"; |
8774 | 0 | case ada::state::PORT: |
8775 | 0 | return "Port"; |
8776 | 0 | default: |
8777 | 0 | return "unknown state"; |
8778 | 0 | } |
8779 | 0 | } |
8780 | | |
8781 | | ada_really_inline std::optional<std::string_view> prune_hash( |
8782 | 117k | std::string_view& input) noexcept { |
8783 | | // compiles down to 20--30 instructions including a class to memchr (C |
8784 | | // function). this function should be quite fast. |
8785 | 117k | size_t location_of_first = input.find('#'); |
8786 | 117k | if (location_of_first == std::string_view::npos) { |
8787 | 114k | return std::nullopt; |
8788 | 114k | } |
8789 | 3.39k | std::string_view hash = input; |
8790 | 3.39k | hash.remove_prefix(location_of_first + 1); |
8791 | 3.39k | input.remove_suffix(input.size() - location_of_first); |
8792 | 3.39k | return hash; |
8793 | 117k | } |
8794 | | |
8795 | 9.37k | ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type) { |
8796 | | // Let path be url's path. |
8797 | | // If url's scheme is "file", path's size is 1, and path[0] is a normalized |
8798 | | // Windows drive letter, then return. |
8799 | 9.37k | if (type == ada::scheme::type::FILE && |
8800 | 2.90k | path.find('/', 1) == std::string_view::npos && !path.empty()) { |
8801 | 1.44k | if (checkers::is_normalized_windows_drive_letter( |
8802 | 1.44k | helpers::substring(path, 1))) { |
8803 | 738 | return false; |
8804 | 738 | } |
8805 | 1.44k | } |
8806 | | |
8807 | | // Remove path's last item, if any. |
8808 | 8.63k | size_t last_delimiter = path.rfind('/'); |
8809 | 8.63k | if (last_delimiter != std::string::npos) { |
8810 | 4.41k | path.erase(last_delimiter); |
8811 | 4.41k | return true; |
8812 | 4.41k | } |
8813 | | |
8814 | 4.21k | return false; |
8815 | 8.63k | } |
8816 | | |
8817 | | ada_really_inline bool shorten_path(std::string_view& path, |
8818 | 1.34k | ada::scheme::type type) { |
8819 | | // Let path be url's path. |
8820 | | // If url's scheme is "file", path's size is 1, and path[0] is a normalized |
8821 | | // Windows drive letter, then return. |
8822 | 1.34k | if (type == ada::scheme::type::FILE && |
8823 | 152 | path.find('/', 1) == std::string_view::npos && !path.empty()) { |
8824 | 56 | if (checkers::is_normalized_windows_drive_letter( |
8825 | 56 | helpers::substring(path, 1))) { |
8826 | 2 | return false; |
8827 | 2 | } |
8828 | 56 | } |
8829 | | |
8830 | | // Remove path's last item, if any. |
8831 | 1.34k | if (!path.empty()) { |
8832 | 589 | size_t slash_loc = path.rfind('/'); |
8833 | 589 | if (slash_loc != std::string_view::npos) { |
8834 | 589 | path.remove_suffix(path.size() - slash_loc); |
8835 | 589 | return true; |
8836 | 589 | } |
8837 | 589 | } |
8838 | | |
8839 | 758 | return false; |
8840 | 1.34k | } |
8841 | | |
8842 | 1.08k | ada_really_inline void remove_ascii_tab_or_newline(std::string& input) { |
8843 | | // Fast path: inputs with no tab/newline (the common case) avoid the |
8844 | | // per-character erase_if scan. has_tabs_or_newline uses SIMD for inputs |
8845 | | // >= 16 bytes, making this check much cheaper than erase_if's scalar |
8846 | | // predicate walk when there is nothing to remove. |
8847 | 1.08k | if (!ada::unicode::has_tabs_or_newline(input)) { |
8848 | 0 | return; |
8849 | 0 | } |
8850 | 1.08k | std::erase_if(input, ada::unicode::is_ascii_tab_or_newline); |
8851 | 1.08k | } |
8852 | | |
8853 | | ada_really_inline constexpr std::string_view substring(std::string_view input, |
8854 | 1.50k | size_t pos) { |
8855 | 1.50k | ADA_ASSERT_TRUE(pos <= input.size()); |
8856 | | // The following is safer but unneeded if we have the above line: |
8857 | | // return pos > input.size() ? std::string_view() : input.substr(pos); |
8858 | 1.50k | return input.substr(pos); |
8859 | 1.50k | } |
8860 | | |
8861 | 22 | ada_really_inline void resize(std::string_view& input, size_t pos) noexcept { |
8862 | 22 | ADA_ASSERT_TRUE(pos <= input.size()); |
8863 | 22 | input.remove_suffix(input.size() - pos); |
8864 | 22 | } |
8865 | | |
8866 | | // computes the number of trailing zeroes |
8867 | | // this is a private inline function only defined in this source file. |
8868 | 10.2k | ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept { |
8869 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
8870 | | unsigned long ret; |
8871 | | // Search the mask data from least significant bit (LSB) |
8872 | | // to the most significant bit (MSB) for a set bit (1). |
8873 | | _BitScanForward(&ret, input_num); |
8874 | | return (int)ret; |
8875 | | #else // ADA_REGULAR_VISUAL_STUDIO |
8876 | 10.2k | return __builtin_ctzl(input_num); |
8877 | 10.2k | #endif // ADA_REGULAR_VISUAL_STUDIO |
8878 | 10.2k | } |
8879 | | |
8880 | | #if ADA_NEON |
8881 | | // computes the number of trailing zeroes of a 64-bit word |
8882 | | // this is a private inline function only defined in this source file. |
8883 | | ada_really_inline int trailing_zeroes64(uint64_t input_num) noexcept { |
8884 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
8885 | | unsigned long ret; |
8886 | | _BitScanForward64(&ret, input_num); |
8887 | | return (int)ret; |
8888 | | #else // ADA_REGULAR_VISUAL_STUDIO |
8889 | | return __builtin_ctzll(input_num); |
8890 | | #endif // ADA_REGULAR_VISUAL_STUDIO |
8891 | | } |
8892 | | |
8893 | | // Given a NEON register whose lanes are all either 0x00 or 0xFF (i.e., the |
8894 | | // result of a comparison), produce a 64-bit value with four bits set per |
8895 | | // matching input byte, and zero bits elsewhere. Narrowing by four bits per |
8896 | | // 16-bit lane is cheaper than materializing a 16-bit bitmask. |
8897 | | // |
8898 | | // With ADA_NEON_SAFE_ZERO_CHECK set to 0, the "any match?" test instead |
8899 | | // treats the nibble mask as an IEEE 754 double and compares it against zero, |
8900 | | // avoiding a transfer to a general-purpose register on the common no-match |
8901 | | // path. Negative zero cannot occur (each byte is 0x00, 0x0F, 0xF0 or 0xFF), |
8902 | | // but a mask with only low bits set is a denormal: if flush-to-zero is |
8903 | | // enabled, those compare equal to 0.0. Do not use this on arbitrary vectors. |
8904 | | ada_really_inline uint8x8_t to_nibble_mask(uint8x16_t comparison) noexcept { |
8905 | | return vshrn_n_u16(vreinterpretq_u16_u8(comparison), 4); |
8906 | | } |
8907 | | |
8908 | | ada_really_inline bool any_set(uint8x8_t nibble_mask) noexcept { |
8909 | | #if ADA_NEON_SAFE_ZERO_CHECK |
8910 | | return vget_lane_u64(vreinterpret_u64_u8(nibble_mask), 0) != 0; |
8911 | | #else |
8912 | | return vdupd_lane_f64(vreinterpret_f64_u8(nibble_mask), 0) != 0.0; |
8913 | | #endif |
8914 | | } |
8915 | | |
8916 | | // index of the first matching byte; only meaningful when any_set is true. |
8917 | | ada_really_inline size_t first_set(uint8x8_t nibble_mask) noexcept { |
8918 | | return size_t(trailing_zeroes64( |
8919 | | vget_lane_u64(vreinterpret_u64_u8(nibble_mask), 0))) >> |
8920 | | 2; |
8921 | | } |
8922 | | #endif // ADA_NEON |
8923 | | |
8924 | | // starting at index location, this finds the next location of a character |
8925 | | // :, /, \\, ? or [. If none is found, view.size() is returned. |
8926 | | // For use within get_host_delimiter_location. |
8927 | | #if ADA_SSSE3 |
8928 | | ada_really_inline size_t find_next_host_delimiter_special( |
8929 | | std::string_view view, size_t location) noexcept { |
8930 | | // first check for short strings in which case we do it naively. |
8931 | | if (view.size() - location < 16) { // slow path |
8932 | | for (size_t i = location; i < view.size(); i++) { |
8933 | | if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || |
8934 | | view[i] == '?' || view[i] == '[') { |
8935 | | return i; |
8936 | | } |
8937 | | } |
8938 | | return size_t(view.size()); |
8939 | | } |
8940 | | // fast path for long strings (expected to be common) |
8941 | | // Using SSSE3's _mm_shuffle_epi8 for table lookup (same approach as NEON) |
8942 | | size_t i = location; |
8943 | | const __m128i low_mask = |
8944 | | _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
8945 | | 0x01, 0x04, 0x04, 0x00, 0x00, 0x03); |
8946 | | const __m128i high_mask = |
8947 | | _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, |
8948 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
8949 | | const __m128i fmask = _mm_set1_epi8(0xf); |
8950 | | const __m128i zero = _mm_setzero_si128(); |
8951 | | for (; i + 15 < view.size(); i += 16) { |
8952 | | __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); |
8953 | | __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); |
8954 | | __m128i highpart = _mm_shuffle_epi8( |
8955 | | high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); |
8956 | | __m128i classify = _mm_and_si128(lowpart, highpart); |
8957 | | __m128i is_zero = _mm_cmpeq_epi8(classify, zero); |
8958 | | // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 |
8959 | | // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to |
8960 | | // avoid false positives. |
8961 | | int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; |
8962 | | if (mask != 0) { |
8963 | | return i + trailing_zeroes(static_cast<uint32_t>(mask)); |
8964 | | } |
8965 | | } |
8966 | | if (i < view.size()) { |
8967 | | __m128i word = |
8968 | | _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); |
8969 | | __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); |
8970 | | __m128i highpart = _mm_shuffle_epi8( |
8971 | | high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); |
8972 | | __m128i classify = _mm_and_si128(lowpart, highpart); |
8973 | | __m128i is_zero = _mm_cmpeq_epi8(classify, zero); |
8974 | | // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 |
8975 | | // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to |
8976 | | // avoid false positives. |
8977 | | int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; |
8978 | | if (mask != 0) { |
8979 | | return view.length() - 16 + trailing_zeroes(static_cast<uint32_t>(mask)); |
8980 | | } |
8981 | | } |
8982 | | return size_t(view.size()); |
8983 | | } |
8984 | | #elif ADA_NEON |
8985 | | // The ada_make_uint8x16_t macro is necessary because Visual Studio does not |
8986 | | // support direct initialization of uint8x16_t. See |
8987 | | // https://developercommunity.visualstudio.com/t/error-C2078:-too-many-initializers-whe/402911?q=backend+neon |
8988 | | #ifndef ada_make_uint8x16_t |
8989 | | #define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \ |
8990 | | x13, x14, x15, x16) \ |
8991 | | ([=]() { \ |
8992 | | static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \ |
8993 | | x9, x10, x11, x12, x13, x14, x15, x16}; \ |
8994 | | return vld1q_u8(array); \ |
8995 | | }()) |
8996 | | #endif |
8997 | | |
8998 | | ada_really_inline size_t find_next_host_delimiter_special( |
8999 | | std::string_view view, size_t location) noexcept { |
9000 | | // first check for short strings in which case we do it naively. |
9001 | | if (view.size() - location < 16) { // slow path |
9002 | | for (size_t i = location; i < view.size(); i++) { |
9003 | | if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || |
9004 | | view[i] == '?' || view[i] == '[') { |
9005 | | return i; |
9006 | | } |
9007 | | } |
9008 | | return size_t(view.size()); |
9009 | | } |
9010 | | // fast path for long strings (expected to be common) |
9011 | | size_t i = location; |
9012 | | uint8x16_t low_mask = |
9013 | | ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
9014 | | 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03); |
9015 | | uint8x16_t high_mask = |
9016 | | ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, |
9017 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
9018 | | uint8x16_t fmask = vmovq_n_u8(0xf); |
9019 | | for (; i + 15 < view.size(); i += 16) { |
9020 | | uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); |
9021 | | uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); |
9022 | | uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); |
9023 | | // vtstq_u8 gives us 0xFF where (lowpart & highpart) is non-zero and 0x00 |
9024 | | // elsewhere: unlike the plain AND, that is a proper comparison mask, which |
9025 | | // is what to_nibble_mask requires. |
9026 | | uint8x8_t matches = to_nibble_mask(vtstq_u8(lowpart, highpart)); |
9027 | | if (any_set(matches)) { |
9028 | | return i + first_set(matches); |
9029 | | } |
9030 | | } |
9031 | | |
9032 | | if (i < view.size()) { |
9033 | | uint8x16_t word = |
9034 | | vld1q_u8((const uint8_t*)view.data() + view.length() - 16); |
9035 | | uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); |
9036 | | uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); |
9037 | | uint8x8_t matches = to_nibble_mask(vtstq_u8(lowpart, highpart)); |
9038 | | if (any_set(matches)) { |
9039 | | return view.length() - 16 + first_set(matches); |
9040 | | } |
9041 | | } |
9042 | | return size_t(view.size()); |
9043 | | } |
9044 | | #elif ADA_SSE2 |
9045 | | ada_really_inline size_t find_next_host_delimiter_special( |
9046 | 41.5k | std::string_view view, size_t location) noexcept { |
9047 | | // first check for short strings in which case we do it naively. |
9048 | 41.5k | if (view.size() - location < 16) { // slow path |
9049 | 148k | for (size_t i = location; i < view.size(); i++) { |
9050 | 134k | if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || |
9051 | 122k | view[i] == '?' || view[i] == '[') { |
9052 | 13.4k | return i; |
9053 | 13.4k | } |
9054 | 134k | } |
9055 | 14.3k | return size_t(view.size()); |
9056 | 27.8k | } |
9057 | | // fast path for long strings (expected to be common) |
9058 | 13.7k | size_t i = location; |
9059 | 13.7k | const __m128i mask1 = _mm_set1_epi8(':'); |
9060 | 13.7k | const __m128i mask2 = _mm_set1_epi8('/'); |
9061 | 13.7k | const __m128i mask3 = _mm_set1_epi8('\\'); |
9062 | 13.7k | const __m128i mask4 = _mm_set1_epi8('?'); |
9063 | 13.7k | const __m128i mask5 = _mm_set1_epi8('['); |
9064 | | |
9065 | 52.3k | for (; i + 15 < view.size(); i += 16) { |
9066 | 44.4k | __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); |
9067 | 44.4k | __m128i m1 = _mm_cmpeq_epi8(word, mask1); |
9068 | 44.4k | __m128i m2 = _mm_cmpeq_epi8(word, mask2); |
9069 | 44.4k | __m128i m3 = _mm_cmpeq_epi8(word, mask3); |
9070 | 44.4k | __m128i m4 = _mm_cmpeq_epi8(word, mask4); |
9071 | 44.4k | __m128i m5 = _mm_cmpeq_epi8(word, mask5); |
9072 | 44.4k | __m128i m = _mm_or_si128( |
9073 | 44.4k | _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); |
9074 | 44.4k | int mask = _mm_movemask_epi8(m); |
9075 | 44.4k | if (mask != 0) { |
9076 | 5.86k | return i + trailing_zeroes(mask); |
9077 | 5.86k | } |
9078 | 44.4k | } |
9079 | 7.90k | if (i < view.size()) { |
9080 | 7.28k | __m128i word = |
9081 | 7.28k | _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); |
9082 | 7.28k | __m128i m1 = _mm_cmpeq_epi8(word, mask1); |
9083 | 7.28k | __m128i m2 = _mm_cmpeq_epi8(word, mask2); |
9084 | 7.28k | __m128i m3 = _mm_cmpeq_epi8(word, mask3); |
9085 | 7.28k | __m128i m4 = _mm_cmpeq_epi8(word, mask4); |
9086 | 7.28k | __m128i m5 = _mm_cmpeq_epi8(word, mask5); |
9087 | 7.28k | __m128i m = _mm_or_si128( |
9088 | 7.28k | _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); |
9089 | 7.28k | int mask = _mm_movemask_epi8(m); |
9090 | 7.28k | if (mask != 0) { |
9091 | 2.97k | return view.length() - 16 + trailing_zeroes(mask); |
9092 | 2.97k | } |
9093 | 7.28k | } |
9094 | 4.92k | return size_t(view.length()); |
9095 | 7.90k | } |
9096 | | #elif ADA_LSX |
9097 | | ada_really_inline size_t find_next_host_delimiter_special( |
9098 | | std::string_view view, size_t location) noexcept { |
9099 | | // first check for short strings in which case we do it naively. |
9100 | | if (view.size() - location < 16) { // slow path |
9101 | | for (size_t i = location; i < view.size(); i++) { |
9102 | | if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || |
9103 | | view[i] == '?' || view[i] == '[') { |
9104 | | return i; |
9105 | | } |
9106 | | } |
9107 | | return size_t(view.size()); |
9108 | | } |
9109 | | // fast path for long strings (expected to be common) |
9110 | | size_t i = location; |
9111 | | const __m128i mask1 = __lsx_vrepli_b(':'); |
9112 | | const __m128i mask2 = __lsx_vrepli_b('/'); |
9113 | | const __m128i mask3 = __lsx_vrepli_b('\\'); |
9114 | | const __m128i mask4 = __lsx_vrepli_b('?'); |
9115 | | const __m128i mask5 = __lsx_vrepli_b('['); |
9116 | | |
9117 | | for (; i + 15 < view.size(); i += 16) { |
9118 | | __m128i word = __lsx_vld((const __m128i*)(view.data() + i), 0); |
9119 | | __m128i m1 = __lsx_vseq_b(word, mask1); |
9120 | | __m128i m2 = __lsx_vseq_b(word, mask2); |
9121 | | __m128i m3 = __lsx_vseq_b(word, mask3); |
9122 | | __m128i m4 = __lsx_vseq_b(word, mask4); |
9123 | | __m128i m5 = __lsx_vseq_b(word, mask5); |
9124 | | __m128i m = |
9125 | | __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5); |
9126 | | int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); |
9127 | | if (mask != 0) { |
9128 | | return i + trailing_zeroes(mask); |
9129 | | } |
9130 | | } |
9131 | | if (i < view.size()) { |
9132 | | __m128i word = |
9133 | | __lsx_vld((const __m128i*)(view.data() + view.length() - 16), 0); |
9134 | | __m128i m1 = __lsx_vseq_b(word, mask1); |
9135 | | __m128i m2 = __lsx_vseq_b(word, mask2); |
9136 | | __m128i m3 = __lsx_vseq_b(word, mask3); |
9137 | | __m128i m4 = __lsx_vseq_b(word, mask4); |
9138 | | __m128i m5 = __lsx_vseq_b(word, mask5); |
9139 | | __m128i m = |
9140 | | __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5); |
9141 | | int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); |
9142 | | if (mask != 0) { |
9143 | | return view.length() - 16 + trailing_zeroes(mask); |
9144 | | } |
9145 | | } |
9146 | | return size_t(view.length()); |
9147 | | } |
9148 | | #elif ADA_RVV |
9149 | | ada_really_inline size_t find_next_host_delimiter_special( |
9150 | | std::string_view view, size_t location) noexcept { |
9151 | | // The LUT approach was a bit slower on the SpacemiT X60, but I could see it |
9152 | | // being faster on future hardware. |
9153 | | #if 0 |
9154 | | // LUT generated using: s=":/\\?["; list(zip([((ord(c)>>2)&0xF)for c in s],s)) |
9155 | | static const uint8_t tbl[16] = { |
9156 | | 0xF, 0, 0, 0, 0, 0, '[', '\\', 0, 0, 0, '/', 0, 0, ':', '?' |
9157 | | }; |
9158 | | vuint8m1_t vtbl = __riscv_vle8_v_u8m1(tbl, 16); |
9159 | | #endif |
9160 | | uint8_t* src = (uint8_t*)view.data() + location; |
9161 | | for (size_t vl, n = view.size() - location; n > 0; |
9162 | | n -= vl, src += vl, location += vl) { |
9163 | | vl = __riscv_vsetvl_e8m1(n); |
9164 | | vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); |
9165 | | #if 0 |
9166 | | vuint8m1_t vidx = __riscv_vand(__riscv_vsrl(v, 2, vl), 0xF, vl); |
9167 | | vuint8m1_t vlut = __riscv_vrgather(vtbl, vidx, vl); |
9168 | | vbool8_t m = __riscv_vmseq(v, vlut, vl); |
9169 | | #else |
9170 | | vbool8_t m1 = __riscv_vmseq(v, ':', vl); |
9171 | | vbool8_t m2 = __riscv_vmseq(v, '/', vl); |
9172 | | vbool8_t m3 = __riscv_vmseq(v, '?', vl); |
9173 | | vbool8_t m4 = __riscv_vmseq(v, '[', vl); |
9174 | | vbool8_t m5 = __riscv_vmseq(v, '\\', vl); |
9175 | | vbool8_t m = __riscv_vmor( |
9176 | | __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl), |
9177 | | m5, vl); |
9178 | | #endif |
9179 | | long idx = __riscv_vfirst(m, vl); |
9180 | | if (idx >= 0) return location + idx; |
9181 | | } |
9182 | | return size_t(view.size()); |
9183 | | } |
9184 | | #else |
9185 | | // : / [ \\ ? |
9186 | | static constexpr std::array<uint8_t, 256> special_host_delimiters = |
9187 | | []() consteval { |
9188 | | std::array<uint8_t, 256> result{}; |
9189 | | for (int i : {':', '/', '[', '\\', '?'}) { |
9190 | | result[i] = 1; |
9191 | | } |
9192 | | return result; |
9193 | | }(); |
9194 | | // credit: @the-moisrex recommended a table-based approach |
9195 | | ada_really_inline size_t find_next_host_delimiter_special( |
9196 | | std::string_view view, size_t location) noexcept { |
9197 | | auto const str = view.substr(location); |
9198 | | for (auto pos = str.begin(); pos != str.end(); ++pos) { |
9199 | | if (special_host_delimiters[(uint8_t)*pos]) { |
9200 | | return pos - str.begin() + location; |
9201 | | } |
9202 | | } |
9203 | | return size_t(view.size()); |
9204 | | } |
9205 | | #endif |
9206 | | |
9207 | | // starting at index location, this finds the next location of a character |
9208 | | // :, /, ? or [. If none is found, view.size() is returned. |
9209 | | // For use within get_host_delimiter_location. |
9210 | | #if ADA_SSSE3 |
9211 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9212 | | size_t location) noexcept { |
9213 | | // first check for short strings in which case we do it naively. |
9214 | | if (view.size() - location < 16) { // slow path |
9215 | | for (size_t i = location; i < view.size(); i++) { |
9216 | | if (view[i] == ':' || view[i] == '/' || view[i] == '?' || |
9217 | | view[i] == '[') { |
9218 | | return i; |
9219 | | } |
9220 | | } |
9221 | | return size_t(view.size()); |
9222 | | } |
9223 | | // fast path for long strings (expected to be common) |
9224 | | size_t i = location; |
9225 | | // Lookup tables for bit classification: |
9226 | | // ':' (0x3A): low[0xA]=0x01, high[0x3]=0x01 -> match |
9227 | | // '/' (0x2F): low[0xF]=0x02, high[0x2]=0x02 -> match |
9228 | | // '?' (0x3F): low[0xF]=0x01, high[0x3]=0x01 -> match |
9229 | | // '[' (0x5B): low[0xB]=0x04, high[0x5]=0x04 -> match |
9230 | | const __m128i low_mask = |
9231 | | _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
9232 | | 0x01, 0x04, 0x00, 0x00, 0x00, 0x03); |
9233 | | const __m128i high_mask = |
9234 | | _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, |
9235 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
9236 | | const __m128i fmask = _mm_set1_epi8(0xf); |
9237 | | const __m128i zero = _mm_setzero_si128(); |
9238 | | |
9239 | | for (; i + 15 < view.size(); i += 16) { |
9240 | | __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); |
9241 | | __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); |
9242 | | __m128i highpart = _mm_shuffle_epi8( |
9243 | | high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); |
9244 | | __m128i classify = _mm_and_si128(lowpart, highpart); |
9245 | | __m128i is_zero = _mm_cmpeq_epi8(classify, zero); |
9246 | | // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 |
9247 | | // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to |
9248 | | // avoid false positives. |
9249 | | int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; |
9250 | | if (mask != 0) { |
9251 | | return i + trailing_zeroes(static_cast<uint32_t>(mask)); |
9252 | | } |
9253 | | } |
9254 | | |
9255 | | if (i < view.size()) { |
9256 | | __m128i word = |
9257 | | _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); |
9258 | | __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask)); |
9259 | | __m128i highpart = _mm_shuffle_epi8( |
9260 | | high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask)); |
9261 | | __m128i classify = _mm_and_si128(lowpart, highpart); |
9262 | | __m128i is_zero = _mm_cmpeq_epi8(classify, zero); |
9263 | | // _mm_movemask_epi8 returns a 16-bit mask in bits 0-15, with bits 16-31 |
9264 | | // zero. After NOT (~), bits 16-31 become 1. We must mask to 16 bits to |
9265 | | // avoid false positives. |
9266 | | int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF; |
9267 | | if (mask != 0) { |
9268 | | return view.length() - 16 + trailing_zeroes(static_cast<uint32_t>(mask)); |
9269 | | } |
9270 | | } |
9271 | | return size_t(view.size()); |
9272 | | } |
9273 | | #elif ADA_NEON |
9274 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9275 | | size_t location) noexcept { |
9276 | | // first check for short strings in which case we do it naively. |
9277 | | if (view.size() - location < 16) { // slow path |
9278 | | for (size_t i = location; i < view.size(); i++) { |
9279 | | if (view[i] == ':' || view[i] == '/' || view[i] == '?' || |
9280 | | view[i] == '[') { |
9281 | | return i; |
9282 | | } |
9283 | | } |
9284 | | return size_t(view.size()); |
9285 | | } |
9286 | | // fast path for long strings (expected to be common) |
9287 | | size_t i = location; |
9288 | | uint8x16_t low_mask = |
9289 | | ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
9290 | | 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03); |
9291 | | uint8x16_t high_mask = |
9292 | | ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, |
9293 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
9294 | | uint8x16_t fmask = vmovq_n_u8(0xf); |
9295 | | for (; i + 15 < view.size(); i += 16) { |
9296 | | uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); |
9297 | | uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); |
9298 | | uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); |
9299 | | // vtstq_u8 gives us 0xFF where (lowpart & highpart) is non-zero and 0x00 |
9300 | | // elsewhere: unlike the plain AND, that is a proper comparison mask, which |
9301 | | // is what to_nibble_mask requires. |
9302 | | uint8x8_t matches = to_nibble_mask(vtstq_u8(lowpart, highpart)); |
9303 | | if (any_set(matches)) { |
9304 | | return i + first_set(matches); |
9305 | | } |
9306 | | } |
9307 | | |
9308 | | if (i < view.size()) { |
9309 | | uint8x16_t word = |
9310 | | vld1q_u8((const uint8_t*)view.data() + view.length() - 16); |
9311 | | uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); |
9312 | | uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); |
9313 | | uint8x8_t matches = to_nibble_mask(vtstq_u8(lowpart, highpart)); |
9314 | | if (any_set(matches)) { |
9315 | | return view.length() - 16 + first_set(matches); |
9316 | | } |
9317 | | } |
9318 | | return size_t(view.size()); |
9319 | | } |
9320 | | #elif ADA_SSE2 |
9321 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9322 | 4.26k | size_t location) noexcept { |
9323 | | // first check for short strings in which case we do it naively. |
9324 | 4.26k | if (view.size() - location < 16) { // slow path |
9325 | 5.83k | for (size_t i = location; i < view.size(); i++) { |
9326 | 4.74k | if (view[i] == ':' || view[i] == '/' || view[i] == '?' || |
9327 | 4.20k | view[i] == '[') { |
9328 | 1.05k | return i; |
9329 | 1.05k | } |
9330 | 4.74k | } |
9331 | 1.09k | return size_t(view.size()); |
9332 | 2.14k | } |
9333 | | // fast path for long strings (expected to be common) |
9334 | 2.11k | size_t i = location; |
9335 | 2.11k | const __m128i mask1 = _mm_set1_epi8(':'); |
9336 | 2.11k | const __m128i mask2 = _mm_set1_epi8('/'); |
9337 | 2.11k | const __m128i mask4 = _mm_set1_epi8('?'); |
9338 | 2.11k | const __m128i mask5 = _mm_set1_epi8('['); |
9339 | | |
9340 | 6.43k | for (; i + 15 < view.size(); i += 16) { |
9341 | 5.66k | __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); |
9342 | 5.66k | __m128i m1 = _mm_cmpeq_epi8(word, mask1); |
9343 | 5.66k | __m128i m2 = _mm_cmpeq_epi8(word, mask2); |
9344 | 5.66k | __m128i m4 = _mm_cmpeq_epi8(word, mask4); |
9345 | 5.66k | __m128i m5 = _mm_cmpeq_epi8(word, mask5); |
9346 | 5.66k | __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); |
9347 | 5.66k | int mask = _mm_movemask_epi8(m); |
9348 | 5.66k | if (mask != 0) { |
9349 | 1.34k | return i + trailing_zeroes(mask); |
9350 | 1.34k | } |
9351 | 5.66k | } |
9352 | 768 | if (i < view.size()) { |
9353 | 474 | __m128i word = |
9354 | 474 | _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); |
9355 | 474 | __m128i m1 = _mm_cmpeq_epi8(word, mask1); |
9356 | 474 | __m128i m2 = _mm_cmpeq_epi8(word, mask2); |
9357 | 474 | __m128i m4 = _mm_cmpeq_epi8(word, mask4); |
9358 | 474 | __m128i m5 = _mm_cmpeq_epi8(word, mask5); |
9359 | 474 | __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); |
9360 | 474 | int mask = _mm_movemask_epi8(m); |
9361 | 474 | if (mask != 0) { |
9362 | 87 | return view.length() - 16 + trailing_zeroes(mask); |
9363 | 87 | } |
9364 | 474 | } |
9365 | 681 | return size_t(view.length()); |
9366 | 768 | } |
9367 | | #elif ADA_LSX |
9368 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9369 | | size_t location) noexcept { |
9370 | | // first check for short strings in which case we do it naively. |
9371 | | if (view.size() - location < 16) { // slow path |
9372 | | for (size_t i = location; i < view.size(); i++) { |
9373 | | if (view[i] == ':' || view[i] == '/' || view[i] == '?' || |
9374 | | view[i] == '[') { |
9375 | | return i; |
9376 | | } |
9377 | | } |
9378 | | return size_t(view.size()); |
9379 | | } |
9380 | | // fast path for long strings (expected to be common) |
9381 | | size_t i = location; |
9382 | | const __m128i mask1 = __lsx_vrepli_b(':'); |
9383 | | const __m128i mask2 = __lsx_vrepli_b('/'); |
9384 | | const __m128i mask4 = __lsx_vrepli_b('?'); |
9385 | | const __m128i mask5 = __lsx_vrepli_b('['); |
9386 | | |
9387 | | for (; i + 15 < view.size(); i += 16) { |
9388 | | __m128i word = __lsx_vld((const __m128i*)(view.data() + i), 0); |
9389 | | __m128i m1 = __lsx_vseq_b(word, mask1); |
9390 | | __m128i m2 = __lsx_vseq_b(word, mask2); |
9391 | | __m128i m4 = __lsx_vseq_b(word, mask4); |
9392 | | __m128i m5 = __lsx_vseq_b(word, mask5); |
9393 | | __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5)); |
9394 | | int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); |
9395 | | if (mask != 0) { |
9396 | | return i + trailing_zeroes(mask); |
9397 | | } |
9398 | | } |
9399 | | if (i < view.size()) { |
9400 | | __m128i word = |
9401 | | __lsx_vld((const __m128i*)(view.data() + view.length() - 16), 0); |
9402 | | __m128i m1 = __lsx_vseq_b(word, mask1); |
9403 | | __m128i m2 = __lsx_vseq_b(word, mask2); |
9404 | | __m128i m4 = __lsx_vseq_b(word, mask4); |
9405 | | __m128i m5 = __lsx_vseq_b(word, mask5); |
9406 | | __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5)); |
9407 | | int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0); |
9408 | | if (mask != 0) { |
9409 | | return view.length() - 16 + trailing_zeroes(mask); |
9410 | | } |
9411 | | } |
9412 | | return size_t(view.length()); |
9413 | | } |
9414 | | #elif ADA_RVV |
9415 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9416 | | size_t location) noexcept { |
9417 | | uint8_t* src = (uint8_t*)view.data() + location; |
9418 | | for (size_t vl, n = view.size() - location; n > 0; |
9419 | | n -= vl, src += vl, location += vl) { |
9420 | | vl = __riscv_vsetvl_e8m1(n); |
9421 | | vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl); |
9422 | | vbool8_t m1 = __riscv_vmseq(v, ':', vl); |
9423 | | vbool8_t m2 = __riscv_vmseq(v, '/', vl); |
9424 | | vbool8_t m3 = __riscv_vmseq(v, '?', vl); |
9425 | | vbool8_t m4 = __riscv_vmseq(v, '[', vl); |
9426 | | vbool8_t m = |
9427 | | __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl); |
9428 | | long idx = __riscv_vfirst(m, vl); |
9429 | | if (idx >= 0) return location + idx; |
9430 | | } |
9431 | | return size_t(view.size()); |
9432 | | } |
9433 | | #else |
9434 | | // : / [ ? |
9435 | | static constexpr std::array<uint8_t, 256> host_delimiters = []() consteval { |
9436 | | std::array<uint8_t, 256> result{}; |
9437 | | for (int i : {':', '/', '?', '['}) { |
9438 | | result[i] = 1; |
9439 | | } |
9440 | | return result; |
9441 | | }(); |
9442 | | // credit: @the-moisrex recommended a table-based approach |
9443 | | ada_really_inline size_t find_next_host_delimiter(std::string_view view, |
9444 | | size_t location) noexcept { |
9445 | | auto const str = view.substr(location); |
9446 | | for (auto pos = str.begin(); pos != str.end(); ++pos) { |
9447 | | if (host_delimiters[(uint8_t)*pos]) { |
9448 | | return pos - str.begin() + location; |
9449 | | } |
9450 | | } |
9451 | | return size_t(view.size()); |
9452 | | } |
9453 | | #endif |
9454 | | |
9455 | | ada_really_inline std::pair<size_t, bool> get_host_delimiter_location( |
9456 | 40.7k | const bool is_special, std::string_view& view) noexcept { |
9457 | | /** |
9458 | | * The spec at https://url.spec.whatwg.org/#hostname-state expects us to |
9459 | | * compute a variable called insideBrackets but this variable is only used |
9460 | | * once, to check whether a ':' character was found outside brackets. Exact |
9461 | | * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:". |
9462 | | * It is conceptually simpler and arguably more efficient to just return a |
9463 | | * Boolean indicating whether ':' was found outside brackets. |
9464 | | */ |
9465 | 40.7k | const size_t view_size = view.size(); |
9466 | 40.7k | size_t location = 0; |
9467 | 40.7k | bool found_colon = false; |
9468 | | /** |
9469 | | * Performance analysis: |
9470 | | * |
9471 | | * We are basically seeking the end of the hostname which can be indicated |
9472 | | * by the end of the view, or by one of the characters ':', '/', '?', '\\' |
9473 | | * (where '\\' is only applicable for special URLs). However, these must |
9474 | | * appear outside a bracket range. E.g., if you have [something?]fd: then the |
9475 | | * '?' does not count. |
9476 | | * |
9477 | | * So we can skip ahead to the next delimiter, as long as we include '[' in |
9478 | | * the set of delimiters, and that we handle it first. |
9479 | | * |
9480 | | * So the trick is to have a fast function that locates the next delimiter. |
9481 | | * Unless we find '[', then it only needs to be called once! Ideally, such a |
9482 | | * function would be provided by the C++ standard library, but it seems that |
9483 | | * find_first_of is not very fast, so we are forced to roll our own. |
9484 | | * |
9485 | | * We do not break into two loops for speed, but for clarity. |
9486 | | */ |
9487 | 40.7k | if (is_special) { |
9488 | | // We move to the next delimiter. |
9489 | 38.1k | location = find_next_host_delimiter_special(view, location); |
9490 | | // Unless we find '[' then we are going only going to have to call |
9491 | | // find_next_host_delimiter_special once. |
9492 | 41.5k | for (; location < view_size; |
9493 | 38.1k | location = find_next_host_delimiter_special(view, location)) { |
9494 | 22.2k | if (view[location] == '[') { |
9495 | 3.56k | location = view.find(']', location); |
9496 | 3.56k | if (location == std::string_view::npos) { |
9497 | | // performance: view.find might get translated to a memchr, which |
9498 | | // has no notion of std::string_view::npos, so the code does not |
9499 | | // reflect the assembly. |
9500 | 159 | location = view_size; |
9501 | 159 | break; |
9502 | 159 | } |
9503 | 18.7k | } else { |
9504 | 18.7k | found_colon = view[location] == ':'; |
9505 | 18.7k | break; |
9506 | 18.7k | } |
9507 | 22.2k | } |
9508 | 38.1k | } else { |
9509 | | // We move to the next delimiter. |
9510 | 2.60k | location = find_next_host_delimiter(view, location); |
9511 | | // Unless we find '[' then we are going only going to have to call |
9512 | | // find_next_host_delimiter_special once. |
9513 | 4.26k | for (; location < view_size; |
9514 | 2.60k | location = find_next_host_delimiter(view, location)) { |
9515 | 2.49k | if (view[location] == '[') { |
9516 | 1.73k | location = view.find(']', location); |
9517 | 1.73k | if (location == std::string_view::npos) { |
9518 | | // performance: view.find might get translated to a memchr, which |
9519 | | // has no notion of std::string_view::npos, so the code does not |
9520 | | // reflect the assembly. |
9521 | 69 | location = view_size; |
9522 | 69 | break; |
9523 | 69 | } |
9524 | 1.73k | } else { |
9525 | 759 | found_colon = view[location] == ':'; |
9526 | 759 | break; |
9527 | 759 | } |
9528 | 2.49k | } |
9529 | 2.60k | } |
9530 | | // performance: remove_suffix may translate into a single instruction. |
9531 | 40.7k | view.remove_suffix(view_size - location); |
9532 | 40.7k | return {location, found_colon}; |
9533 | 40.7k | } |
9534 | | |
9535 | 117k | void trim_c0_whitespace(std::string_view& input) noexcept { |
9536 | 120k | while (!input.empty() && |
9537 | 71.8k | ada::unicode::is_c0_control_or_space(input.front())) { |
9538 | 2.64k | input.remove_prefix(1); |
9539 | 2.64k | } |
9540 | 124k | while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) { |
9541 | 6.25k | input.remove_suffix(1); |
9542 | 6.25k | } |
9543 | 117k | } |
9544 | | |
9545 | | ada_really_inline void parse_prepared_path(std::string_view input, |
9546 | | ada::scheme::type type, |
9547 | 10.3k | std::string& path) { |
9548 | 10.3k | ada_log("parse_prepared_path ", input); |
9549 | 10.3k | uint8_t accumulator = checkers::path_signature(input); |
9550 | | // Let us first detect a trivial case. |
9551 | | // If it is special, we check that we have no dot, no %, no \ and no |
9552 | | // character needing percent encoding. Otherwise, we check that we have no %, |
9553 | | // no dot, and no character needing percent encoding. |
9554 | 10.3k | constexpr uint8_t need_encoding = 1; |
9555 | 10.3k | constexpr uint8_t backslash_char = 2; |
9556 | 10.3k | constexpr uint8_t dot_char = 4; |
9557 | 10.3k | constexpr uint8_t percent_char = 8; |
9558 | 10.3k | bool special = type != ada::scheme::NOT_SPECIAL; |
9559 | 10.3k | bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && |
9560 | 1.53k | checkers::is_windows_drive_letter(input)); |
9561 | 10.3k | bool trivial_path = |
9562 | 10.3k | (special ? (accumulator == 0) |
9563 | 10.3k | : ((accumulator & (need_encoding | dot_char | percent_char)) == |
9564 | 1.51k | 0)) && |
9565 | 4.77k | (!may_need_slow_file_handling); |
9566 | 10.3k | if (accumulator == dot_char && !may_need_slow_file_handling) { |
9567 | | // '4' means that we have at least one dot, but nothing that requires |
9568 | | // percent encoding or decoding. The only part that is not trivial is |
9569 | | // that we may have single dots and double dots path segments. |
9570 | | // If we have such segments, then we either have a path that begins |
9571 | | // with '.' (easy to check), or we have the sequence './'. |
9572 | | // Note: input cannot be empty, it must at least contain one character ('.') |
9573 | | // Note: we know that '\' is not present. |
9574 | 1.46k | if (input[0] != '.') { |
9575 | 777 | size_t slashdot = 0; |
9576 | 777 | bool dot_is_file = true; |
9577 | 5.23k | for (;;) { |
9578 | 5.23k | slashdot = input.find("/.", slashdot); |
9579 | 5.23k | if (slashdot == std::string_view::npos) { // common case |
9580 | 777 | break; |
9581 | 4.45k | } else { // uncommon |
9582 | | // only three cases matter: /./, /.. or a final / |
9583 | 4.45k | slashdot += 2; |
9584 | 4.45k | dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' || |
9585 | 1.73k | input[slashdot] == '/'); |
9586 | 4.45k | } |
9587 | 5.23k | } |
9588 | 777 | trivial_path = dot_is_file; |
9589 | 777 | } |
9590 | 1.46k | } |
9591 | 10.3k | if (trivial_path) { |
9592 | 4.89k | ada_log("parse_path trivial"); |
9593 | 4.89k | path += '/'; |
9594 | 4.89k | path += input; |
9595 | 4.89k | return; |
9596 | 4.89k | } |
9597 | | // We are going to need to look a bit at the path, but let us see if we can |
9598 | | // ignore percent encoding *and* backslashes *and* percent characters. |
9599 | | // Except for the trivial case, this is likely to capture 99% of paths out |
9600 | | // there. |
9601 | 5.42k | bool fast_path = |
9602 | 5.42k | (special && |
9603 | 4.30k | (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && |
9604 | 1.20k | (type != ada::scheme::type::FILE); |
9605 | 5.42k | if (fast_path) { |
9606 | 1.04k | ada_log("parse_prepared_path fast"); |
9607 | | // Here we don't need to worry about \ or percent encoding. |
9608 | | // We also do not have a file protocol. We might have dots, however, |
9609 | | // but dots must as appear as '.', and they cannot be encoded because |
9610 | | // the symbol '%' is not present. |
9611 | 1.04k | size_t previous_location = 0; // We start at 0. |
9612 | 13.8k | do { |
9613 | 13.8k | size_t new_location = input.find('/', previous_location); |
9614 | | // std::string_view path_view = input; |
9615 | | // We process the last segment separately: |
9616 | 13.8k | if (new_location == std::string_view::npos) { |
9617 | 1.04k | std::string_view path_view = input.substr(previous_location); |
9618 | 1.04k | if (path_view == "..") { // The path ends with .. |
9619 | | // e.g., if you receive ".." with an empty path, you go to "/". |
9620 | 126 | if (path.empty()) { |
9621 | 49 | path = '/'; |
9622 | 49 | return; |
9623 | 49 | } |
9624 | | // Fast case where we have nothing to do: |
9625 | 77 | if (path.back() == '/') { |
9626 | 26 | return; |
9627 | 26 | } |
9628 | | // If you have the path "/joe/myfriend", |
9629 | | // then you delete 'myfriend'. |
9630 | 51 | path.resize(path.rfind('/') + 1); |
9631 | 51 | return; |
9632 | 77 | } |
9633 | 914 | path += '/'; |
9634 | 914 | if (path_view != ".") { |
9635 | 698 | path.append(path_view); |
9636 | 698 | } |
9637 | 914 | return; |
9638 | 12.8k | } else { |
9639 | | // This is a non-final segment. |
9640 | 12.8k | std::string_view path_view = |
9641 | 12.8k | input.substr(previous_location, new_location - previous_location); |
9642 | 12.8k | previous_location = new_location + 1; |
9643 | 12.8k | if (path_view == "..") { |
9644 | 2.75k | size_t last_delimiter = path.rfind('/'); |
9645 | 2.75k | if (last_delimiter != std::string::npos) { |
9646 | 1.11k | path.erase(last_delimiter); |
9647 | 1.11k | } |
9648 | 10.0k | } else if (path_view != ".") { |
9649 | 8.34k | path += '/'; |
9650 | 8.34k | path.append(path_view); |
9651 | 8.34k | } |
9652 | 12.8k | } |
9653 | 13.8k | } while (true); |
9654 | 4.38k | } else { |
9655 | 4.38k | ada_log("parse_path slow"); |
9656 | | // we have reached the general case |
9657 | 4.38k | bool needs_percent_encoding = (accumulator & 1); |
9658 | 29.8k | do { |
9659 | 29.8k | size_t location = (special && (accumulator & 2)) |
9660 | 29.8k | ? input.find_first_of("/\\") |
9661 | 29.8k | : input.find('/'); |
9662 | 29.8k | std::string_view path_view = input; |
9663 | 29.8k | if (location != std::string_view::npos) { |
9664 | 25.4k | path_view.remove_suffix(path_view.size() - location); |
9665 | 25.4k | input.remove_prefix(location + 1); |
9666 | 25.4k | } |
9667 | | // Path encoding preserves dots and percent signs, so normalize first. |
9668 | 29.8k | if (unicode::is_double_dot_path_segment(path_view)) { |
9669 | 4.38k | helpers::shorten_path(path, type); |
9670 | 4.38k | if (location == std::string_view::npos) { |
9671 | 253 | path += '/'; |
9672 | 253 | } |
9673 | 25.4k | } else if (unicode::is_single_dot_path_segment(path_view) && |
9674 | 1.33k | (location == std::string_view::npos)) { |
9675 | 115 | path += '/'; |
9676 | 115 | } |
9677 | | // Otherwise, if path_view is not a single-dot path segment, then: |
9678 | 25.3k | else if (!unicode::is_single_dot_path_segment(path_view)) { |
9679 | | // If url's scheme is "file", url's path is empty, and path_view is a |
9680 | | // Windows drive letter, then replace the second code point in |
9681 | | // path_view with U+003A (:). |
9682 | 24.1k | if (type == ada::scheme::type::FILE && path.empty() && |
9683 | 818 | path_view.size() == 2 && |
9684 | 341 | checkers::is_windows_drive_letter(path_view)) { |
9685 | 137 | path += '/'; |
9686 | 137 | path += path_view[0]; |
9687 | 137 | path += ':'; |
9688 | 137 | path_view.remove_prefix(2); |
9689 | 137 | path.append(path_view); |
9690 | 24.0k | } else { |
9691 | | // Append encoded bytes directly to the pathname. |
9692 | 24.0k | path += '/'; |
9693 | 24.0k | if (!needs_percent_encoding || |
9694 | 12.2k | !ada::unicode::percent_encode<true>( |
9695 | 19.2k | path_view, character_sets::PATH_PERCENT_ENCODE, path)) { |
9696 | 19.2k | path.append(path_view); |
9697 | 19.2k | } |
9698 | 24.0k | } |
9699 | 24.1k | } |
9700 | 29.8k | if (location == std::string_view::npos) { |
9701 | 4.38k | return; |
9702 | 4.38k | } |
9703 | 29.8k | } while (true); |
9704 | 4.38k | } |
9705 | 5.42k | } |
9706 | | |
9707 | 40 | bool overlaps(std::string_view input1, const std::string& input2) noexcept { |
9708 | 40 | ada_log("helpers::overlaps check if string_view '", input1, "' [", |
9709 | 40 | input1.size(), " bytes] is part of string '", input2, "' [", |
9710 | 40 | input2.size(), " bytes]"); |
9711 | 40 | return !input1.empty() && !input2.empty() && input1.data() >= input2.data() && |
9712 | 11 | input1.data() < input2.data() + input2.size(); |
9713 | 40 | } |
9714 | | |
9715 | | template <class url_type> |
9716 | 0 | ada_really_inline void strip_trailing_spaces_from_opaque_path(url_type& url) { |
9717 | 0 | ada_log("helpers::strip_trailing_spaces_from_opaque_path"); |
9718 | 0 | if (!url.has_opaque_path) return; |
9719 | 0 | if (url.has_hash()) return; |
9720 | 0 | if (url.has_search()) return; |
9721 | | |
9722 | 0 | auto path = std::string(url.get_pathname()); |
9723 | 0 | while (!path.empty() && path.back() == ' ') { |
9724 | 0 | path.resize(path.size() - 1); |
9725 | 0 | } |
9726 | 0 | url.update_base_pathname(path); |
9727 | 0 | } Unexecuted instantiation: void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(ada::url&) Unexecuted instantiation: void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url_aggregator>(ada::url_aggregator&) |
9728 | | |
9729 | | // @ / \\ ? |
9730 | | static constexpr std::array<uint8_t, 256> authority_delimiter_special = |
9731 | | []() consteval { |
9732 | | std::array<uint8_t, 256> result{}; |
9733 | | for (uint8_t i : {'@', '/', '\\', '?'}) { |
9734 | | result[i] = 1; |
9735 | | } |
9736 | | return result; |
9737 | | }(); |
9738 | | // credit: @the-moisrex recommended a table-based approach |
9739 | | ada_really_inline size_t |
9740 | 20.6k | find_authority_delimiter_special(std::string_view view) noexcept { |
9741 | | // performance note: we might be able to gain further performance |
9742 | | // with SIMD intrinsics. |
9743 | 137k | for (auto pos = view.begin(); pos != view.end(); ++pos) { |
9744 | 135k | if (authority_delimiter_special[(uint8_t)*pos]) { |
9745 | 18.6k | return pos - view.begin(); |
9746 | 18.6k | } |
9747 | 135k | } |
9748 | 2.00k | return size_t(view.size()); |
9749 | 20.6k | } |
9750 | | |
9751 | | // @ / ? |
9752 | | static constexpr std::array<uint8_t, 256> authority_delimiter = []() consteval { |
9753 | | std::array<uint8_t, 256> result{}; |
9754 | | for (uint8_t i : {'@', '/', '?'}) { |
9755 | | result[i] = 1; |
9756 | | } |
9757 | | return result; |
9758 | | }(); |
9759 | | // credit: @the-moisrex recommended a table-based approach |
9760 | | ada_really_inline size_t |
9761 | 2.19k | find_authority_delimiter(std::string_view view) noexcept { |
9762 | | // performance note: we might be able to gain further performance |
9763 | | // with SIMD instrinsics. |
9764 | 35.9k | for (auto pos = view.begin(); pos != view.end(); ++pos) { |
9765 | 35.6k | if (authority_delimiter[(uint8_t)*pos]) { |
9766 | 1.86k | return pos - view.begin(); |
9767 | 1.86k | } |
9768 | 35.6k | } |
9769 | 324 | return size_t(view.size()); |
9770 | 2.19k | } |
9771 | | |
9772 | | } // namespace ada::helpers |
9773 | | |
9774 | | namespace ada { |
9775 | 0 | ada_warn_unused std::string to_string(ada::state state) { |
9776 | 0 | return ada::helpers::get_state(state); |
9777 | 0 | } |
9778 | | #undef ada_make_uint8x16_t |
9779 | | } // namespace ada |
9780 | | /* end file src/helpers.cpp */ |
9781 | | /* begin file src/url.cpp */ |
9782 | | /* begin file include/ada/url_ip-inl.h */ |
9783 | | /** |
9784 | | * @file url_ip-inl.h |
9785 | | * @brief Shared IPv4/IPv6 parsing helpers used by url and url_aggregator. |
9786 | | * |
9787 | | * Not part of the public API. Defined inline so the single-TU amalgamation |
9788 | | * (ada.cpp) can include them from multiple translation-unit sources once. |
9789 | | */ |
9790 | | #ifndef ADA_URL_IP_INL_H |
9791 | | #define ADA_URL_IP_INL_H |
9792 | | |
9793 | | |
9794 | | #include <array> |
9795 | | #include <cstddef> |
9796 | | #include <cstdint> |
9797 | | |
9798 | | // The IPv6 kernel needs vpermi2b/vpermb (VBMI) and vpcompressb/vpexpandb |
9799 | | // (VBMI2) on top of ADA_AVX512's BW+VL. |
9800 | | #if defined(ADA_AVX512) && defined(__AVX512VBMI__) && defined(__AVX512VBMI2__) |
9801 | | #define ADA_AVX512_IPV6 1 |
9802 | | #endif |
9803 | | |
9804 | | #if defined(ADA_AVX512) |
9805 | | #include <immintrin.h> |
9806 | | #endif |
9807 | | |
9808 | | namespace ada::detail { |
9809 | | |
9810 | | // 256-entry: 0xff = not hex, else nibble value. |
9811 | 0 | inline constexpr std::array<uint8_t, 256> make_hex_nibble_table() noexcept { |
9812 | 0 | std::array<uint8_t, 256> t{}; |
9813 | 0 | for (size_t i = 0; i < 256; ++i) { |
9814 | 0 | t[i] = 0xff; |
9815 | 0 | } |
9816 | 0 | for (size_t d = 0; d < 10; ++d) { |
9817 | 0 | t[size_t{'0'} + d] = static_cast<uint8_t>(d); |
9818 | 0 | } |
9819 | 0 | for (size_t d = 0; d < 6; ++d) { |
9820 | 0 | t[size_t{'a'} + d] = static_cast<uint8_t>(10 + d); |
9821 | 0 | t[size_t{'A'} + d] = static_cast<uint8_t>(10 + d); |
9822 | 0 | } |
9823 | 0 | return t; |
9824 | 0 | } |
9825 | | |
9826 | | inline constexpr auto hex_nibble = make_hex_nibble_table(); |
9827 | | |
9828 | | inline bool parse_ipv4_number(const char*& p, const char* end, uint64_t& value, |
9829 | 6.79k | bool& is_pure_decimal) noexcept { |
9830 | 6.79k | is_pure_decimal = false; |
9831 | 6.79k | if (p >= end) [[unlikely]] { |
9832 | 0 | return false; |
9833 | 0 | } |
9834 | 6.79k | if (end - p >= 2 && p[0] == '0' && ((p[1] | 0x20) == 'x')) { |
9835 | 1.42k | p += 2; |
9836 | 1.42k | if (p == end || *p == '.') { |
9837 | 312 | value = 0; |
9838 | 312 | return true; |
9839 | 312 | } |
9840 | 1.11k | uint64_t v = 0; |
9841 | 1.11k | int digits = 0; |
9842 | 7.19k | while (p < end && *p != '.') { |
9843 | 6.36k | const uint8_t nib = hex_nibble[static_cast<unsigned char>(*p)]; |
9844 | 6.36k | if (nib == 0xff) [[unlikely]] { |
9845 | 21 | return false; |
9846 | 21 | } |
9847 | 6.34k | if (v > (0xFFFFFFFFULL >> 4)) [[unlikely]] { |
9848 | 261 | return false; |
9849 | 261 | } |
9850 | 6.08k | v = (v << 4) | nib; |
9851 | 6.08k | ++p; |
9852 | 6.08k | ++digits; |
9853 | 6.08k | } |
9854 | 834 | if (digits == 0) [[unlikely]] { |
9855 | 0 | return false; |
9856 | 0 | } |
9857 | 834 | value = v; |
9858 | 834 | return true; |
9859 | 834 | } |
9860 | 5.36k | if (end - p >= 2 && p[0] == '0' && p[1] >= '0' && p[1] <= '9') { |
9861 | 477 | ++p; |
9862 | 477 | uint64_t v = 0; |
9863 | 3.56k | while (p < end && *p != '.') { |
9864 | 3.17k | const char c = *p; |
9865 | 3.17k | if (c < '0' || c > '7') [[unlikely]] { |
9866 | 60 | return false; |
9867 | 60 | } |
9868 | 3.11k | if (v > (0xFFFFFFFFULL >> 3)) [[unlikely]] { |
9869 | 30 | return false; |
9870 | 30 | } |
9871 | 3.08k | v = (v << 3) | static_cast<uint64_t>(c - '0'); |
9872 | 3.08k | ++p; |
9873 | 3.08k | } |
9874 | 387 | value = v; |
9875 | 387 | return true; |
9876 | 477 | } |
9877 | 4.88k | if (*p < '0' || *p > '9') [[unlikely]] { |
9878 | 432 | return false; |
9879 | 432 | } |
9880 | 4.45k | is_pure_decimal = true; |
9881 | 4.45k | uint64_t v = static_cast<uint64_t>(*p - '0'); |
9882 | 4.45k | ++p; |
9883 | 8.86k | while (p < end && *p != '.') { |
9884 | 4.58k | const char c = *p; |
9885 | 4.58k | if (c < '0' || c > '9') [[unlikely]] { |
9886 | 81 | return false; |
9887 | 81 | } |
9888 | 4.50k | if (v > 429496729ULL) [[unlikely]] { |
9889 | 78 | return false; |
9890 | 78 | } |
9891 | 4.42k | v = v * 10u + static_cast<uint64_t>(c - '0'); |
9892 | 4.42k | if (v > 0xFFFFFFFFULL) [[unlikely]] { |
9893 | 12 | return false; |
9894 | 12 | } |
9895 | 4.41k | ++p; |
9896 | 4.41k | } |
9897 | 4.28k | value = v; |
9898 | 4.28k | return true; |
9899 | 4.45k | } |
9900 | | |
9901 | | // Parse up to 4 hex digits. Returns digit count (0 if none). |
9902 | | inline int parse_hex_piece(const char*& pointer, const char* end, |
9903 | 2.90k | uint16_t& value) noexcept { |
9904 | 2.90k | if (pointer == end) { |
9905 | 0 | return 0; |
9906 | 0 | } |
9907 | 2.90k | const uint8_t n0 = hex_nibble[static_cast<unsigned char>(*pointer)]; |
9908 | 2.90k | if (n0 == 0xff) { |
9909 | 126 | return 0; |
9910 | 126 | } |
9911 | 2.78k | uint32_t v = n0; |
9912 | 2.78k | ++pointer; |
9913 | 2.78k | int length = 1; |
9914 | 2.78k | if (pointer != end) { |
9915 | 2.51k | const uint8_t n1 = hex_nibble[static_cast<unsigned char>(*pointer)]; |
9916 | 2.51k | if (n1 != 0xff) { |
9917 | 990 | v = (v << 4) | n1; |
9918 | 990 | ++pointer; |
9919 | 990 | ++length; |
9920 | 990 | if (pointer != end) { |
9921 | 903 | const uint8_t n2 = hex_nibble[static_cast<unsigned char>(*pointer)]; |
9922 | 903 | if (n2 != 0xff) { |
9923 | 594 | v = (v << 4) | n2; |
9924 | 594 | ++pointer; |
9925 | 594 | ++length; |
9926 | 594 | if (pointer != end) { |
9927 | 498 | const uint8_t n3 = hex_nibble[static_cast<unsigned char>(*pointer)]; |
9928 | 498 | if (n3 != 0xff) { |
9929 | 258 | v = (v << 4) | n3; |
9930 | 258 | ++pointer; |
9931 | 258 | ++length; |
9932 | 258 | } |
9933 | 498 | } |
9934 | 594 | } |
9935 | 903 | } |
9936 | 990 | } |
9937 | 2.51k | } |
9938 | 2.78k | value = static_cast<uint16_t>(v); |
9939 | 2.78k | return length; |
9940 | 2.90k | } |
9941 | | |
9942 | | #if defined(ADA_AVX512_IPV6) |
9943 | | // Gather each group's up-to-four nibbles and fold them into eight hextets. |
9944 | | // `prev` is the byte before each group, so an index that runs off the front of |
9945 | | // a short group clamps onto a colon, which translates to zero: no write mask. |
9946 | | ada_really_inline void ipv6_gather(__m128i ends, __m128i prev, __m512i nib, |
9947 | | std::array<uint16_t, 8>& address) noexcept { |
9948 | | const __m256i grp = |
9949 | | _mm256_setr_epi8(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, |
9950 | | 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7); |
9951 | | const __m256i off = _mm256_setr_epi8( |
9952 | | -4, -3, -2, -1, -4, -3, -2, -1, -4, -3, -2, -1, -4, -3, -2, -1, -4, -3, |
9953 | | -2, -1, -4, -3, -2, -1, -4, -3, -2, -1, -4, -3, -2, -1); |
9954 | | const __m256i idx = _mm256_max_epi8( |
9955 | | _mm256_add_epi8( |
9956 | | _mm256_permutexvar_epi8(grp, _mm256_castsi128_si256(ends)), off), |
9957 | | _mm256_permutexvar_epi8(grp, _mm256_castsi128_si256(prev))); |
9958 | | const __m256i gathered = _mm512_castsi512_si256( |
9959 | | _mm512_permutexvar_epi8(_mm512_castsi256_si512(idx), nib)); |
9960 | | // (a,b) -> 16a+b are the sixteen address bytes; 256*hi+lo pairs them. |
9961 | | const __m256i hextets = _mm256_madd_epi16( |
9962 | | _mm256_maddubs_epi16(gathered, _mm256_set1_epi16(0x0110)), |
9963 | | _mm256_set1_epi32(0x00010100)); |
9964 | | _mm_storeu_si128(reinterpret_cast<__m128i*>(address.data()), |
9965 | | _mm256_cvtepi32_epi16(hextets)); |
9966 | | } |
9967 | | |
9968 | | // Parse an IPv6 host with one masked 512-bit load. Derived from |
9969 | | // vtlmks/ipv6-avx512 (Peter Fors, MIT). |
9970 | | // |
9971 | | // Returns false when the input is outside this kernel's grammar and the caller |
9972 | | // must run the scalar parser. Otherwise `valid` receives the verdict, and |
9973 | | // `address` the eight hextets when valid. |
9974 | | ada_really_inline bool try_parse_ipv6_avx512(const char* data, size_t len, |
9975 | | std::array<uint16_t, 8>& address, |
9976 | | bool& valid) noexcept { |
9977 | | if (len < 2 || len > 45) [[unlikely]] { |
9978 | | return false; |
9979 | | } |
9980 | | // ':' rather than 0x80 for the colon, so a clamped index reads a zero nibble. |
9981 | | alignas(64) static constexpr uint8_t hex_lo[64] = { |
9982 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9983 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9984 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9985 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9986 | | 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, |
9987 | | 0x07, 0x08, 0x09, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80}; |
9988 | | alignas(64) static constexpr uint8_t hex_hi[64] = { |
9989 | | 0x80, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, |
9990 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9991 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9992 | | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, |
9993 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
9994 | | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; |
9995 | | alignas(64) static constexpr uint8_t iota[64] = { |
9996 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
9997 | | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
9998 | | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, |
9999 | | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; |
10000 | | |
10001 | | const __mmask64 active = |
10002 | | static_cast<__mmask64>(_bzhi_u64(~0ULL, static_cast<uint32_t>(len))); |
10003 | | const __m512i colon = _mm512_set1_epi8(':'); |
10004 | | // Merging ':' into the tail makes the terminator at `len` a real colon, so |
10005 | | // the compress mask below never has to be rebuilt in a general register. |
10006 | | const __m512i v = _mm512_mask_loadu_epi8(colon, active, data); |
10007 | | const __mmask64 mcolon = _mm512_cmpeq_epi8_mask(v, colon); |
10008 | | |
10009 | | // An embedded dotted quad is the one valid form this kernel does not cover. |
10010 | | // Because that is the only gap, every other input it does not accept is |
10011 | | // invalid, which is what makes `valid = false` below safe. |
10012 | | if (_mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('.'))) [[unlikely]] { |
10013 | | return false; |
10014 | | } |
10015 | | |
10016 | | const __m512i nib = _mm512_permutex2var_epi8(_mm512_load_si512(hex_lo), v, |
10017 | | _mm512_load_si512(hex_hi)); |
10018 | | const __m128i comp = _mm512_castsi512_si128( |
10019 | | _mm512_maskz_compress_epi8(mcolon, _mm512_load_si512(iota))); |
10020 | | const __m128i lane0 = |
10021 | | _mm_setr_epi8(-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); |
10022 | | const __m128i prev = _mm_or_si128(_mm_bslli_si128(comp, 1), lane0); |
10023 | | const __m128i width = _mm_sub_epi8(comp, prev); // one too large |
10024 | | |
10025 | | const uint64_t mc = static_cast<uint64_t>(mcolon); |
10026 | | const uint64_t act = static_cast<uint64_t>(active); |
10027 | | const uint64_t dc = mc & (mc >> 1) & (act >> 1); // a "::" inside [0, len) |
10028 | | |
10029 | | if (!dc) { |
10030 | | ipv6_gather(comp, prev, nib, address); |
10031 | | // nib | (v & 0x80): one scan for non-hex bytes and for bytes whose high |
10032 | | // bit made vpermi2b alias a legal one. |
10033 | | const __m512i fused = _mm512_ternarylogic_epi32( |
10034 | | nib, v, _mm512_set1_epi8(static_cast<char>(0x80)), 0xf8); |
10035 | | // Lanes 8..15 bound against 255, which an unsigned byte cannot exceed. |
10036 | | const __m128i wmax = |
10037 | | _mm_setr_epi8(3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1); |
10038 | | __mmask64 err = _kandn_mask64(mcolon, _mm512_movepi8_mask(fused)); |
10039 | | err = _kor_mask64( |
10040 | | err, static_cast<__mmask64>(static_cast<uint16_t>(_mm_cmpgt_epu8_mask( |
10041 | | _mm_sub_epi8(width, _mm_set1_epi8(2)), wmax)))); |
10042 | | valid = (_mm_popcnt_u64(mc & act) == 7) && !err; |
10043 | | return true; |
10044 | | } |
10045 | | |
10046 | | // Drop the zero-width gap field(s), then expand the surviving head and tail |
10047 | | // fields into eight slots with all-zero groups inserted at the gap. |
10048 | | const uint32_t head = static_cast<uint32_t>(_mm_popcnt_u64(mc & (dc - 1))) + |
10049 | | static_cast<uint32_t>(dc > 1); |
10050 | | const __mmask16 keep = _mm_cmpgt_epi8_mask(width, _mm_set1_epi8(1)); |
10051 | | const uint32_t kept = static_cast<uint32_t>(_mm_popcnt_u32(keep)); |
10052 | | const __mmask16 slots = static_cast<__mmask16>( |
10053 | | ~(_bzhi_u32(0xFFFFFFFFu, 8 - kept) << head) & 0xFFu); |
10054 | | // Inserted groups take prev = -1, so their indices clamp to byte 63, a tail |
10055 | | // colon, and read zero. |
10056 | | ipv6_gather(_mm_maskz_expand_epi8(slots, _mm_maskz_compress_epi8(keep, comp)), |
10057 | | _mm_mask_expand_epi8(_mm_set1_epi8(-1), slots, |
10058 | | _mm_maskz_compress_epi8(keep, prev)), |
10059 | | nib, address); |
10060 | | |
10061 | | uint64_t err = _mm512_movepi8_mask(v); // high-bit bytes |
10062 | | err |= _mm512_movepi8_mask(nib) & ~mc; // non-hex |
10063 | | err |= _blsr_u64(dc); // a second "::" |
10064 | | err |= static_cast<uint64_t>(kept >= 8); // "::" elides nothing |
10065 | | err |= _mm_cmpgt_epu8_mask(width, _mm_set1_epi8(5)) & keep; // group > 4 |
10066 | | err |= (mc & 1ULL) & ~dc; // leading lone ':' |
10067 | | err |= ((mc >> (len - 1)) & 1ULL) & ~(dc >> (len - 2)); // trailing lone ':' |
10068 | | valid = !err; |
10069 | | return true; |
10070 | | } |
10071 | | #endif // ADA_AVX512_IPV6 |
10072 | | |
10073 | | } // namespace ada::detail |
10074 | | |
10075 | | #endif // ADA_URL_IP_INL_H |
10076 | | /* end file include/ada/url_ip-inl.h */ |
10077 | | |
10078 | | #include <algorithm> |
10079 | | #include <array> |
10080 | | #include <cstddef> |
10081 | | #include <cstdint> |
10082 | | #include <iterator> |
10083 | | #include <numeric> |
10084 | | #include <optional> |
10085 | | #include <ranges> |
10086 | | #include <string> |
10087 | | #include <string_view> |
10088 | | #include <utility> |
10089 | | |
10090 | | namespace ada { |
10091 | | |
10092 | 598 | bool url::parse_opaque_host(std::string_view input) { |
10093 | 598 | ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); |
10094 | 598 | if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { |
10095 | 13 | return is_valid = false; |
10096 | 13 | } |
10097 | | |
10098 | | // Return the result of running UTF-8 percent-encode on input using the C0 |
10099 | | // control percent-encode set. |
10100 | 585 | host = ada::unicode::percent_encode( |
10101 | 585 | input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE); |
10102 | 585 | return true; |
10103 | 598 | } |
10104 | | |
10105 | 1.84k | bool url::parse_ipv4(std::string_view input) { |
10106 | 1.84k | ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]"); |
10107 | 1.84k | if (input.empty()) { |
10108 | 0 | return is_valid = false; |
10109 | 0 | } |
10110 | 1.84k | std::string_view original_input = input; |
10111 | 1.84k | if (original_input.back() == '.') { |
10112 | 60 | original_input.remove_suffix(1); |
10113 | 60 | } |
10114 | 1.84k | if (input.back() == '.') { |
10115 | 60 | input.remove_suffix(1); |
10116 | 60 | if (input.empty()) { |
10117 | 0 | return is_valid = false; |
10118 | 0 | } |
10119 | 60 | } |
10120 | | |
10121 | 1.84k | const uint64_t fast = checkers::try_parse_ipv4_fast(input); |
10122 | 1.84k | if (fast < checkers::ipv4_fast_fail) [[likely]] { |
10123 | 20 | host = original_input; |
10124 | 20 | host_type = IPV4; |
10125 | 20 | return true; |
10126 | 20 | } |
10127 | | |
10128 | 1.82k | const char* p = input.data(); |
10129 | 1.82k | const char* end = p + input.size(); |
10130 | 1.82k | uint64_t ipv4 = 0; |
10131 | 1.82k | int digit_count = 0; |
10132 | 1.82k | int pure_decimal_count = 0; |
10133 | | |
10134 | 2.27k | for (; digit_count < 4 && p < end; ++digit_count) { |
10135 | 2.26k | uint64_t segment = 0; |
10136 | 2.26k | bool pure = false; |
10137 | 2.26k | if (!detail::parse_ipv4_number(p, end, segment, pure)) { |
10138 | 325 | return is_valid = false; |
10139 | 325 | } |
10140 | 1.93k | if (pure) { |
10141 | 1.42k | ++pure_decimal_count; |
10142 | 1.42k | } |
10143 | 1.93k | if (p >= end) { |
10144 | 1.46k | const unsigned shift = static_cast<unsigned>(32 - digit_count * 8); |
10145 | 1.46k | if (segment >= (uint64_t{1} << shift)) { |
10146 | 26 | return is_valid = false; |
10147 | 26 | } |
10148 | 1.43k | ipv4 = (ipv4 << shift) | segment; |
10149 | 1.43k | host = (pure_decimal_count == 4) ? std::string(original_input) |
10150 | 1.43k | : ada::serializers::ipv4(ipv4); |
10151 | 1.43k | host_type = IPV4; |
10152 | 1.43k | return true; |
10153 | 1.46k | } |
10154 | 478 | if (segment > 255 || *p != '.') { |
10155 | 29 | return is_valid = false; |
10156 | 29 | } |
10157 | 449 | ipv4 = (ipv4 << 8) | segment; |
10158 | 449 | ++p; |
10159 | 449 | } |
10160 | 9 | if (digit_count != 4 || p != end) { |
10161 | 9 | return is_valid = false; |
10162 | 9 | } |
10163 | 0 | host = (pure_decimal_count == 4) ? std::string(original_input) |
10164 | 0 | : ada::serializers::ipv4(ipv4); |
10165 | 0 | host_type = IPV4; |
10166 | 0 | return true; |
10167 | 9 | } |
10168 | | |
10169 | 518 | bool url::parse_ipv6(std::string_view input) { |
10170 | 518 | ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); |
10171 | 518 | if (input.empty() || input.size() > 45) [[unlikely]] { |
10172 | 31 | return is_valid = false; |
10173 | 31 | } |
10174 | 487 | std::array<uint16_t, 8> address{}; |
10175 | | #if defined(ADA_AVX512_IPV6) |
10176 | | if (bool simd_valid; detail::try_parse_ipv6_avx512(input.data(), input.size(), |
10177 | | address, simd_valid)) { |
10178 | | if (!simd_valid) [[unlikely]] { |
10179 | | return is_valid = false; |
10180 | | } |
10181 | | host = ada::serializers::ipv6(address); |
10182 | | host_type = IPV6; |
10183 | | return true; |
10184 | | } |
10185 | | address = {}; |
10186 | | #endif |
10187 | 487 | const char* pointer = input.data(); |
10188 | 487 | const char* const end = pointer + input.size(); |
10189 | 487 | int piece_index = 0; |
10190 | 487 | int compress = -1; |
10191 | | |
10192 | 487 | if (*pointer == ':') { |
10193 | 187 | if (input.size() == 1 || pointer[1] != ':') [[unlikely]] { |
10194 | 7 | return is_valid = false; |
10195 | 7 | } |
10196 | 180 | pointer += 2; |
10197 | 180 | compress = ++piece_index; |
10198 | 180 | } |
10199 | | |
10200 | 1.44k | while (pointer != end) { |
10201 | 1.11k | if (piece_index == 8) [[unlikely]] { |
10202 | 3 | return is_valid = false; |
10203 | 3 | } |
10204 | 1.10k | if (*pointer == ':') { |
10205 | 139 | if (compress != -1) [[unlikely]] { |
10206 | 3 | return is_valid = false; |
10207 | 3 | } |
10208 | 136 | ++pointer; |
10209 | 136 | compress = ++piece_index; |
10210 | 136 | continue; |
10211 | 139 | } |
10212 | | |
10213 | 969 | uint16_t value = 0; |
10214 | 969 | const int length = detail::parse_hex_piece(pointer, end, value); |
10215 | | |
10216 | 969 | if (pointer != end && *pointer == '.') { |
10217 | 91 | if (length == 0) [[unlikely]] { |
10218 | 4 | return is_valid = false; |
10219 | 4 | } |
10220 | 87 | pointer -= length; |
10221 | 87 | if (piece_index > 6) [[unlikely]] { |
10222 | 3 | return is_valid = false; |
10223 | 3 | } |
10224 | | |
10225 | 84 | int numbers_seen = 0; |
10226 | 249 | while (pointer != end) { |
10227 | 219 | int ipv4_piece = -1; |
10228 | 219 | if (numbers_seen > 0) { |
10229 | 135 | if (*pointer == '.' && numbers_seen < 4) { |
10230 | 115 | ++pointer; |
10231 | 115 | } else { |
10232 | 20 | return is_valid = false; |
10233 | 20 | } |
10234 | 135 | } |
10235 | 199 | if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] { |
10236 | 25 | return is_valid = false; |
10237 | 25 | } |
10238 | 174 | ipv4_piece = *pointer - '0'; |
10239 | 174 | ++pointer; |
10240 | 174 | if (pointer != end && *pointer >= '0' && *pointer <= '9') { |
10241 | 58 | if (ipv4_piece == 0) [[unlikely]] { |
10242 | 4 | return is_valid = false; |
10243 | 4 | } |
10244 | 54 | ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); |
10245 | 54 | ++pointer; |
10246 | 54 | if (pointer != end && *pointer >= '0' && *pointer <= '9') { |
10247 | 24 | ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); |
10248 | 24 | ++pointer; |
10249 | 24 | if (ipv4_piece > 255) [[unlikely]] { |
10250 | 5 | return is_valid = false; |
10251 | 5 | } |
10252 | 24 | } |
10253 | 54 | } |
10254 | 165 | address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>( |
10255 | 165 | address[static_cast<size_t>(piece_index)] * 0x100 + |
10256 | 165 | static_cast<uint16_t>(ipv4_piece)); |
10257 | 165 | ++numbers_seen; |
10258 | 165 | if (numbers_seen == 2 || numbers_seen == 4) { |
10259 | 69 | ++piece_index; |
10260 | 69 | } |
10261 | 165 | } |
10262 | 30 | if (numbers_seen != 4) [[unlikely]] { |
10263 | 18 | return is_valid = false; |
10264 | 18 | } |
10265 | 12 | break; |
10266 | 30 | } |
10267 | | |
10268 | 878 | if (length == 0) [[unlikely]] { |
10269 | 38 | return is_valid = false; |
10270 | 38 | } |
10271 | | |
10272 | 840 | if (pointer != end && *pointer == ':') { |
10273 | 646 | ++pointer; |
10274 | 646 | if (pointer == end) [[unlikely]] { |
10275 | 3 | return is_valid = false; |
10276 | 3 | } |
10277 | 646 | } else if (pointer != end) [[unlikely]] { |
10278 | 9 | return is_valid = false; |
10279 | 9 | } |
10280 | | |
10281 | 828 | address[static_cast<size_t>(piece_index)] = value; |
10282 | 828 | ++piece_index; |
10283 | 828 | } |
10284 | | |
10285 | 345 | if (compress != -1) { |
10286 | 307 | const int right = piece_index - compress; |
10287 | 307 | if (right > 0) { |
10288 | 159 | const size_t dest = static_cast<size_t>(8 - right); |
10289 | 159 | const size_t src = static_cast<size_t>(compress); |
10290 | 159 | if (dest != src) { |
10291 | 387 | for (size_t i = static_cast<size_t>(right); i-- > 0;) { |
10292 | 248 | address[dest + i] = address[src + i]; |
10293 | 248 | address[src + i] = 0; |
10294 | 248 | } |
10295 | 139 | } |
10296 | 159 | } |
10297 | 307 | } else if (piece_index != 8) [[unlikely]] { |
10298 | 19 | return is_valid = false; |
10299 | 19 | } |
10300 | | |
10301 | 326 | host = ada::serializers::ipv6(address); |
10302 | 326 | ada_log("parse_ipv6 ", *host); |
10303 | 326 | host_type = IPV6; |
10304 | 326 | return true; |
10305 | 345 | } |
10306 | | |
10307 | | template <bool has_state_override> |
10308 | 21.0k | ada_really_inline bool url::parse_scheme(const std::string_view input) { |
10309 | 21.0k | auto parsed_type = ada::scheme::get_scheme_type(input); |
10310 | 21.0k | bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); |
10311 | | /** |
10312 | | * In the common case, we will immediately recognize a special scheme (e.g., |
10313 | | *http, https), in which case, we can go really fast. |
10314 | | **/ |
10315 | 21.0k | if (is_input_special) { // fast path!!! |
10316 | 10.2k | if constexpr (has_state_override) { |
10317 | | // If url's scheme is not a special scheme and buffer is a special scheme, |
10318 | | // then return. |
10319 | 0 | if (is_special() != is_input_special) { |
10320 | 0 | return false; |
10321 | 0 | } |
10322 | | |
10323 | | // If url includes credentials or has a non-null port, and buffer is |
10324 | | // "file", then return. |
10325 | 0 | if ((has_credentials() || port.has_value()) && |
10326 | 0 | parsed_type == ada::scheme::type::FILE) { |
10327 | 0 | return false; |
10328 | 0 | } |
10329 | | |
10330 | | // If url's scheme is "file" and its host is an empty host, then return. |
10331 | | // An empty host is the empty string. |
10332 | 0 | if (type == ada::scheme::type::FILE && host.has_value() && |
10333 | 0 | host->empty()) { |
10334 | 0 | return false; |
10335 | 0 | } |
10336 | 0 | } |
10337 | | |
10338 | 0 | type = parsed_type; |
10339 | | |
10340 | 10.2k | if constexpr (has_state_override) { |
10341 | | // This is uncommon. |
10342 | 0 | uint16_t urls_scheme_port = get_special_port(); |
10343 | |
|
10344 | 0 | if (urls_scheme_port) { |
10345 | | // If url's port is url's scheme's default port, then set url's port to |
10346 | | // null. |
10347 | 0 | if (port.has_value() && *port == urls_scheme_port) { |
10348 | 0 | port = std::nullopt; |
10349 | 0 | } |
10350 | 0 | } |
10351 | 0 | } |
10352 | 10.7k | } else { // slow path |
10353 | 10.7k | std::string _buffer(input); |
10354 | | // Next function is only valid if the input is ASCII and returns false |
10355 | | // otherwise, but it seems that we always have ascii content so we do not |
10356 | | // need to check the return value. |
10357 | | // bool is_ascii = |
10358 | 10.7k | unicode::to_lower_ascii(_buffer.data(), _buffer.size()); |
10359 | | |
10360 | 10.7k | if constexpr (has_state_override) { |
10361 | | // The state-override validation errors below ("return" in the WHATWG URL |
10362 | | // parser) leave the URL unchanged. The setter contract is |
10363 | | // "true on success, false if the scheme is invalid" -- the fast path |
10364 | | // above already returns false here, so the slow path must agree. |
10365 | | |
10366 | | // If url's scheme is a special scheme and buffer is not a special scheme, |
10367 | | // then return. If url's scheme is not a special scheme and buffer is a |
10368 | | // special scheme, then return. |
10369 | 0 | if (is_special() != ada::scheme::is_special(_buffer)) { |
10370 | 0 | return false; |
10371 | 0 | } |
10372 | | |
10373 | | // If url includes credentials or has a non-null port, and buffer is |
10374 | | // "file", then return. |
10375 | 0 | if ((has_credentials() || port.has_value()) && _buffer == "file") { |
10376 | 0 | return false; |
10377 | 0 | } |
10378 | | |
10379 | | // If url's scheme is "file" and its host is an empty host, then return. |
10380 | | // An empty host is the empty string. |
10381 | 0 | if (type == ada::scheme::type::FILE && host.has_value() && |
10382 | 0 | host->empty()) { |
10383 | 0 | return false; |
10384 | 0 | } |
10385 | 0 | } |
10386 | | |
10387 | 0 | set_scheme(std::move(_buffer)); |
10388 | | |
10389 | 10.7k | if constexpr (has_state_override) { |
10390 | | // This is uncommon. |
10391 | 0 | uint16_t urls_scheme_port = get_special_port(); |
10392 | |
|
10393 | 0 | if (urls_scheme_port) { |
10394 | | // If url's port is url's scheme's default port, then set url's port to |
10395 | | // null. |
10396 | 0 | if (port.has_value() && *port == urls_scheme_port) { |
10397 | 0 | port = std::nullopt; |
10398 | 0 | } |
10399 | 0 | } |
10400 | 0 | } |
10401 | 10.7k | } |
10402 | | |
10403 | 0 | return true; |
10404 | 21.0k | } Unexecuted instantiation: bool ada::url::parse_scheme<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) bool ada::url::parse_scheme<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 10308 | 21.0k | ada_really_inline bool url::parse_scheme(const std::string_view input) { | 10309 | 21.0k | auto parsed_type = ada::scheme::get_scheme_type(input); | 10310 | 21.0k | bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); | 10311 | | /** | 10312 | | * In the common case, we will immediately recognize a special scheme (e.g., | 10313 | | *http, https), in which case, we can go really fast. | 10314 | | **/ | 10315 | 21.0k | if (is_input_special) { // fast path!!! | 10316 | | if constexpr (has_state_override) { | 10317 | | // If url's scheme is not a special scheme and buffer is a special scheme, | 10318 | | // then return. | 10319 | | if (is_special() != is_input_special) { | 10320 | | return false; | 10321 | | } | 10322 | | | 10323 | | // If url includes credentials or has a non-null port, and buffer is | 10324 | | // "file", then return. | 10325 | | if ((has_credentials() || port.has_value()) && | 10326 | | parsed_type == ada::scheme::type::FILE) { | 10327 | | return false; | 10328 | | } | 10329 | | | 10330 | | // If url's scheme is "file" and its host is an empty host, then return. | 10331 | | // An empty host is the empty string. | 10332 | | if (type == ada::scheme::type::FILE && host.has_value() && | 10333 | | host->empty()) { | 10334 | | return false; | 10335 | | } | 10336 | | } | 10337 | | | 10338 | 10.2k | type = parsed_type; | 10339 | | | 10340 | | if constexpr (has_state_override) { | 10341 | | // This is uncommon. | 10342 | | uint16_t urls_scheme_port = get_special_port(); | 10343 | | | 10344 | | if (urls_scheme_port) { | 10345 | | // If url's port is url's scheme's default port, then set url's port to | 10346 | | // null. | 10347 | | if (port.has_value() && *port == urls_scheme_port) { | 10348 | | port = std::nullopt; | 10349 | | } | 10350 | | } | 10351 | | } | 10352 | 10.7k | } else { // slow path | 10353 | 10.7k | std::string _buffer(input); | 10354 | | // Next function is only valid if the input is ASCII and returns false | 10355 | | // otherwise, but it seems that we always have ascii content so we do not | 10356 | | // need to check the return value. | 10357 | | // bool is_ascii = | 10358 | 10.7k | unicode::to_lower_ascii(_buffer.data(), _buffer.size()); | 10359 | | | 10360 | | if constexpr (has_state_override) { | 10361 | | // The state-override validation errors below ("return" in the WHATWG URL | 10362 | | // parser) leave the URL unchanged. The setter contract is | 10363 | | // "true on success, false if the scheme is invalid" -- the fast path | 10364 | | // above already returns false here, so the slow path must agree. | 10365 | | | 10366 | | // If url's scheme is a special scheme and buffer is not a special scheme, | 10367 | | // then return. If url's scheme is not a special scheme and buffer is a | 10368 | | // special scheme, then return. | 10369 | | if (is_special() != ada::scheme::is_special(_buffer)) { | 10370 | | return false; | 10371 | | } | 10372 | | | 10373 | | // If url includes credentials or has a non-null port, and buffer is | 10374 | | // "file", then return. | 10375 | | if ((has_credentials() || port.has_value()) && _buffer == "file") { | 10376 | | return false; | 10377 | | } | 10378 | | | 10379 | | // If url's scheme is "file" and its host is an empty host, then return. | 10380 | | // An empty host is the empty string. | 10381 | | if (type == ada::scheme::type::FILE && host.has_value() && | 10382 | | host->empty()) { | 10383 | | return false; | 10384 | | } | 10385 | | } | 10386 | | | 10387 | 10.7k | set_scheme(std::move(_buffer)); | 10388 | | | 10389 | | if constexpr (has_state_override) { | 10390 | | // This is uncommon. | 10391 | | uint16_t urls_scheme_port = get_special_port(); | 10392 | | | 10393 | | if (urls_scheme_port) { | 10394 | | // If url's port is url's scheme's default port, then set url's port to | 10395 | | // null. | 10396 | | if (port.has_value() && *port == urls_scheme_port) { | 10397 | | port = std::nullopt; | 10398 | | } | 10399 | | } | 10400 | | } | 10401 | 10.7k | } | 10402 | | | 10403 | 21.0k | return true; | 10404 | 21.0k | } |
|
10405 | | |
10406 | 15.2k | ada_really_inline bool url::parse_host(std::string_view input) { |
10407 | 15.2k | ada_log("parse_host ", input, " [", input.size(), " bytes]"); |
10408 | 15.2k | if (input.empty()) { |
10409 | 19 | return is_valid = false; |
10410 | 19 | } // technically unnecessary. |
10411 | | // If input starts with U+005B ([), then: |
10412 | 15.1k | if (input[0] == '[') { |
10413 | | // If input does not end with U+005D (]), validation error, return failure. |
10414 | 678 | if (input.back() != ']') { |
10415 | 160 | return is_valid = false; |
10416 | 160 | } |
10417 | 518 | ada_log("parse_host ipv6"); |
10418 | | |
10419 | | // Return the result of IPv6 parsing input with its leading U+005B ([) and |
10420 | | // trailing U+005D (]) removed. |
10421 | 518 | input.remove_prefix(1); |
10422 | 518 | input.remove_suffix(1); |
10423 | 518 | return parse_ipv6(input); |
10424 | 678 | } |
10425 | | |
10426 | | // If isNotSpecial is true, then return the result of opaque-host parsing |
10427 | | // input. |
10428 | 14.5k | if (!is_special()) { |
10429 | 598 | return parse_opaque_host(input); |
10430 | 598 | } |
10431 | | |
10432 | | // Fast path: try to parse as pure decimal IPv4 first. |
10433 | 13.9k | const uint64_t fast_result = checkers::try_parse_ipv4_fast(input); |
10434 | 13.9k | if (fast_result < checkers::ipv4_fast_fail) { |
10435 | 937 | if (!input.empty() && input.back() == '.') { |
10436 | 24 | host = input.substr(0, input.size() - 1); |
10437 | 913 | } else { |
10438 | 913 | host = input; |
10439 | 913 | } |
10440 | 937 | host_type = IPV4; |
10441 | 937 | is_valid = true; |
10442 | 937 | ada_log("parse_host fast path decimal ipv4"); |
10443 | 937 | return true; |
10444 | 937 | } |
10445 | | // Let domain be the result of running UTF-8 decode without BOM on the |
10446 | | // percent-decoding of input. Let asciiDomain be the result of running domain |
10447 | | // to ASCII with domain and false. The most common case is an ASCII input, in |
10448 | | // which case we do not need to call the expensive 'to_ascii' if a few |
10449 | | // conditions are met: no '%' and no 'xn-' subsequence. |
10450 | 12.9k | const uint8_t forbidden_or_upper = |
10451 | 12.9k | unicode::contains_forbidden_domain_code_point_or_upper(input.data(), |
10452 | 12.9k | input.size()); |
10453 | 12.9k | static constexpr std::string_view xn_dash{"xn-", 3}; |
10454 | 12.9k | if ((forbidden_or_upper & 1) == 0) { |
10455 | 7.72k | host = std::string(input); |
10456 | 7.72k | if ((forbidden_or_upper & 2) != 0) { |
10457 | 1.36k | unicode::to_lower_ascii(host->data(), host->size()); |
10458 | 1.36k | } |
10459 | 7.72k | if (host->find('-') == std::string_view::npos || |
10460 | 5.82k | host->find(xn_dash) == std::string_view::npos) { |
10461 | 5.82k | if (checkers::is_ipv4(*host)) { |
10462 | 1.38k | ada_log("parse_host fast path ipv4"); |
10463 | 1.38k | return parse_ipv4(*host); |
10464 | 1.38k | } |
10465 | 4.44k | ada_log("parse_host fast path ", *host); |
10466 | 4.44k | is_valid = true; |
10467 | 4.44k | return true; |
10468 | 5.82k | } |
10469 | 7.72k | } else if (const size_t first_percent = input.find('%'); |
10470 | 5.24k | first_percent != std::string_view::npos) { |
10471 | 971 | std::string decoded = unicode::percent_decode(input, first_percent); |
10472 | 971 | const uint8_t decoded_flags = |
10473 | 971 | unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(), |
10474 | 971 | decoded.size()); |
10475 | 971 | if ((decoded_flags & 1) == 0) { |
10476 | 643 | if ((decoded_flags & 2) != 0) { |
10477 | 291 | unicode::to_lower_ascii(decoded.data(), decoded.size()); |
10478 | 291 | } |
10479 | 643 | if (decoded.find('-') == std::string_view::npos || |
10480 | 597 | decoded.find(xn_dash) == std::string_view::npos) { |
10481 | 597 | host = std::move(decoded); |
10482 | 597 | if (checkers::is_ipv4(*host)) { |
10483 | 255 | return parse_ipv4(*host); |
10484 | 255 | } |
10485 | 342 | is_valid = true; |
10486 | 342 | return true; |
10487 | 597 | } |
10488 | 643 | } |
10489 | 971 | } |
10490 | 6.54k | ada_log("parse_host calling to_ascii"); |
10491 | 6.54k | is_valid = ada::unicode::to_ascii(host, input, input.find('%')); |
10492 | 6.54k | if (!is_valid || !host.has_value()) { |
10493 | 1.92k | ada_log("parse_host to_ascii returns false"); |
10494 | 1.92k | return is_valid = false; |
10495 | 1.92k | } |
10496 | 4.61k | ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), |
10497 | 4.61k | " bytes]"); |
10498 | | |
10499 | 4.61k | if (std::any_of(host->begin(), host->end(), |
10500 | 4.61k | ada::unicode::is_forbidden_domain_code_point)) { |
10501 | 0 | host = std::nullopt; |
10502 | 0 | return is_valid = false; |
10503 | 0 | } |
10504 | | |
10505 | | // If asciiDomain ends in a number, then return the result of IPv4 parsing |
10506 | | // asciiDomain. |
10507 | 4.61k | if (checkers::is_ipv4(*host)) { |
10508 | 201 | ada_log("parse_host got ipv4 ", *host); |
10509 | 201 | return parse_ipv4(*host); |
10510 | 201 | } |
10511 | | |
10512 | 4.41k | return true; |
10513 | 4.61k | } |
10514 | | |
10515 | 2.19k | ada_really_inline void url::parse_path(std::string_view input) { |
10516 | 2.19k | ada_log("parse_path ", input); |
10517 | 2.19k | std::string tmp_buffer; |
10518 | 2.19k | std::string_view internal_input; |
10519 | 2.19k | if (unicode::has_tabs_or_newline(input)) { |
10520 | 0 | tmp_buffer = input; |
10521 | | // Optimization opportunity: Instead of copying and then pruning, we could |
10522 | | // just directly build the string from user_input. |
10523 | 0 | helpers::remove_ascii_tab_or_newline(tmp_buffer); |
10524 | 0 | internal_input = tmp_buffer; |
10525 | 2.19k | } else { |
10526 | 2.19k | internal_input = input; |
10527 | 2.19k | } |
10528 | | |
10529 | | // If url is special, then: |
10530 | 2.19k | if (is_special()) { |
10531 | 2.19k | if (internal_input.empty()) { |
10532 | 111 | path = "/"; |
10533 | 2.08k | } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { |
10534 | 2.08k | helpers::parse_prepared_path(internal_input.substr(1), type, path); |
10535 | 2.08k | } else { |
10536 | 0 | helpers::parse_prepared_path(internal_input, type, path); |
10537 | 0 | } |
10538 | 2.19k | } else if (!internal_input.empty()) { |
10539 | 0 | if (internal_input[0] == '/') { |
10540 | 0 | helpers::parse_prepared_path(internal_input.substr(1), type, path); |
10541 | 0 | } else { |
10542 | 0 | helpers::parse_prepared_path(internal_input, type, path); |
10543 | 0 | } |
10544 | 0 | } else { |
10545 | 0 | if (!host.has_value()) { |
10546 | 0 | path = "/"; |
10547 | 0 | } |
10548 | 0 | } |
10549 | 2.19k | } |
10550 | | |
10551 | 0 | [[nodiscard]] std::string url::to_string() const { |
10552 | 0 | if (!is_valid) { |
10553 | 0 | return "null"; |
10554 | 0 | } |
10555 | 0 | std::string answer; |
10556 | 0 | auto back = std::back_insert_iterator(answer); |
10557 | 0 | answer.append("{\n"); |
10558 | 0 | answer.append("\t\"protocol\":\""); |
10559 | 0 | helpers::encode_json(get_protocol(), back); |
10560 | 0 | answer.append("\",\n"); |
10561 | 0 | if (has_credentials()) { |
10562 | 0 | answer.append("\t\"username\":\""); |
10563 | 0 | helpers::encode_json(username, back); |
10564 | 0 | answer.append("\",\n"); |
10565 | 0 | answer.append("\t\"password\":\""); |
10566 | 0 | helpers::encode_json(password, back); |
10567 | 0 | answer.append("\",\n"); |
10568 | 0 | } |
10569 | 0 | if (host.has_value()) { |
10570 | 0 | answer.append("\t\"host\":\""); |
10571 | 0 | helpers::encode_json(host.value(), back); |
10572 | 0 | answer.append("\",\n"); |
10573 | 0 | } |
10574 | 0 | if (port.has_value()) { |
10575 | 0 | answer.append("\t\"port\":\""); |
10576 | 0 | answer.append(std::to_string(port.value())); |
10577 | 0 | answer.append("\",\n"); |
10578 | 0 | } |
10579 | 0 | answer.append("\t\"path\":\""); |
10580 | 0 | helpers::encode_json(path, back); |
10581 | 0 | answer.append("\",\n"); |
10582 | 0 | answer.append("\t\"opaque path\":"); |
10583 | 0 | answer.append((has_opaque_path ? "true" : "false")); |
10584 | 0 | if (has_search()) { |
10585 | 0 | answer.append(",\n"); |
10586 | 0 | answer.append("\t\"query\":\""); |
10587 | | // NOLINTNEXTLINE(bugprone-unchecked-optional-access) |
10588 | 0 | helpers::encode_json(query.value(), back); |
10589 | 0 | answer.append("\""); |
10590 | 0 | } |
10591 | 0 | if (hash.has_value()) { |
10592 | 0 | answer.append(",\n"); |
10593 | 0 | answer.append("\t\"hash\":\""); |
10594 | 0 | helpers::encode_json(hash.value(), back); |
10595 | 0 | answer.append("\""); |
10596 | 0 | } |
10597 | 0 | answer.append("\n}"); |
10598 | 0 | return answer; |
10599 | 0 | } |
10600 | | |
10601 | 0 | [[nodiscard]] bool url::has_valid_domain() const noexcept { |
10602 | 0 | if (!host.has_value()) { |
10603 | 0 | return false; |
10604 | 0 | } |
10605 | 0 | return checkers::verify_dns_length(*host); |
10606 | 0 | } |
10607 | | |
10608 | 0 | [[nodiscard]] std::string url::get_origin() const { |
10609 | 0 | if (is_special()) { |
10610 | | // Return a new opaque origin. |
10611 | 0 | if (type == scheme::FILE) { |
10612 | 0 | return "null"; |
10613 | 0 | } |
10614 | 0 | return ada::helpers::concat(get_protocol(), "//", get_host()); |
10615 | 0 | } |
10616 | | |
10617 | 0 | if (non_special_scheme == "blob") { |
10618 | 0 | if (!path.empty()) { |
10619 | 0 | auto result = ada::parse<ada::url>(path); |
10620 | 0 | if (result && |
10621 | 0 | (result->type == scheme::HTTP || result->type == scheme::HTTPS)) { |
10622 | | // If pathURL's scheme is not "http" and not "https", then return a |
10623 | | // new opaque origin. |
10624 | 0 | return ada::helpers::concat(result->get_protocol(), "//", |
10625 | 0 | result->get_host()); |
10626 | 0 | } |
10627 | 0 | } |
10628 | 0 | } |
10629 | | |
10630 | | // Return a new opaque origin. |
10631 | 0 | return "null"; |
10632 | 0 | } |
10633 | | |
10634 | 0 | [[nodiscard]] std::string url::get_protocol() const { |
10635 | 0 | if (is_special()) { |
10636 | 0 | return helpers::concat(ada::scheme::details::is_special_list[type], ":"); |
10637 | 0 | } |
10638 | | // We only move the 'scheme' if it is non-special. |
10639 | 0 | return helpers::concat(non_special_scheme, ":"); |
10640 | 0 | } |
10641 | | |
10642 | 0 | [[nodiscard]] std::string url::get_host() const { |
10643 | | // If url's host is null, then return the empty string. |
10644 | | // If url's port is null, return url's host, serialized. |
10645 | | // Return url's host, serialized, followed by U+003A (:) and url's port, |
10646 | | // serialized. |
10647 | 0 | if (!host.has_value()) { |
10648 | 0 | return ""; |
10649 | 0 | } |
10650 | 0 | if (port.has_value()) { |
10651 | 0 | return host.value() + ":" + get_port(); |
10652 | 0 | } |
10653 | 0 | return host.value(); |
10654 | 0 | } |
10655 | | |
10656 | 0 | [[nodiscard]] std::string url::get_hostname() const { |
10657 | 0 | return host.value_or(""); |
10658 | 0 | } |
10659 | | |
10660 | 0 | [[nodiscard]] std::string url::get_search() const { |
10661 | | // If this's URL's query is either null or the empty string, then return the |
10662 | | // empty string. Return U+003F (?), followed by this's URL's query. |
10663 | 0 | return (!query.has_value() || (query->empty())) ? "" : "?" + query.value(); |
10664 | 0 | } |
10665 | | |
10666 | 0 | [[nodiscard]] const std::string& url::get_username() const noexcept { |
10667 | 0 | return username; |
10668 | 0 | } |
10669 | | |
10670 | 0 | [[nodiscard]] const std::string& url::get_password() const noexcept { |
10671 | 0 | return password; |
10672 | 0 | } |
10673 | | |
10674 | 0 | [[nodiscard]] std::string url::get_port() const { |
10675 | 0 | return port.has_value() ? std::to_string(port.value()) : ""; |
10676 | 0 | } |
10677 | | |
10678 | 0 | [[nodiscard]] std::string url::get_hash() const { |
10679 | | // If this's URL's fragment is either null or the empty string, then return |
10680 | | // the empty string. Return U+0023 (#), followed by this's URL's fragment. |
10681 | 0 | return (!hash.has_value() || (hash->empty())) ? "" : "#" + hash.value(); |
10682 | 0 | } |
10683 | | |
10684 | 0 | bool url::needs_rollback_snapshot(size_t input_len) const noexcept { |
10685 | 0 | return get_href_size() + input_len + 16 > ada::get_max_input_length(); |
10686 | 0 | } |
10687 | | |
10688 | | template <bool override_hostname> |
10689 | 0 | bool url::set_host_or_hostname(const std::string_view input) { |
10690 | 0 | if (has_opaque_path) { |
10691 | 0 | return false; |
10692 | 0 | } |
10693 | | |
10694 | 0 | url saved_url(*this); |
10695 | |
|
10696 | 0 | size_t host_end_pos = input.find('#'); |
10697 | 0 | std::string _host(input.data(), host_end_pos != std::string_view::npos |
10698 | 0 | ? host_end_pos |
10699 | 0 | : input.size()); |
10700 | 0 | helpers::remove_ascii_tab_or_newline(_host); |
10701 | 0 | std::string_view new_host(_host); |
10702 | |
|
10703 | 0 | auto check_url_size = [&]() -> bool { |
10704 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10705 | 0 | *this = std::move(saved_url); |
10706 | 0 | return false; |
10707 | 0 | } |
10708 | 0 | return true; |
10709 | 0 | }; Unexecuted instantiation: ada::url::set_host_or_hostname<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#1}::operator()() constUnexecuted instantiation: ada::url::set_host_or_hostname<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#1}::operator()() const |
10710 | | |
10711 | | // If url's scheme is "file", then set state to file host state, instead of |
10712 | | // host state. |
10713 | 0 | if (type != ada::scheme::type::FILE) { |
10714 | 0 | std::string_view host_view(_host.data(), _host.length()); |
10715 | 0 | auto [location, found_colon] = |
10716 | 0 | helpers::get_host_delimiter_location(is_special(), host_view); |
10717 | | |
10718 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: |
10719 | | // Note: the 'found_colon' value is true if and only if a colon was |
10720 | | // encountered while not inside brackets. |
10721 | 0 | if (found_colon) { |
10722 | | // If buffer is the empty string, host-missing validation error, return |
10723 | | // failure. |
10724 | 0 | std::string_view buffer = host_view.substr(0, location); |
10725 | 0 | if (buffer.empty()) { |
10726 | 0 | return false; |
10727 | 0 | } |
10728 | | |
10729 | | // If state override is given and state override is hostname state, then |
10730 | | // return failure. |
10731 | 0 | if constexpr (override_hostname) { |
10732 | 0 | return false; |
10733 | 0 | } |
10734 | | |
10735 | | // Let host be the result of host parsing buffer with url is not special. |
10736 | 0 | bool succeeded = parse_host(buffer); |
10737 | 0 | if (!succeeded) { |
10738 | 0 | *this = std::move(saved_url); |
10739 | 0 | return false; |
10740 | 0 | } |
10741 | | |
10742 | | // Set url's host to host, buffer to the empty string, and state to port |
10743 | | // state. |
10744 | 0 | std::string_view port_buffer = new_host.substr(location + 1); |
10745 | 0 | if (!port_buffer.empty()) { |
10746 | 0 | set_port(port_buffer); |
10747 | 0 | } |
10748 | 0 | return check_url_size(); |
10749 | 0 | } |
10750 | | // Otherwise, if one of the following is true: |
10751 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
10752 | | // - url is special and c is U+005C (\) |
10753 | 0 | else { |
10754 | | // If url is special and host_view is the empty string, host-missing |
10755 | | // validation error, return failure. |
10756 | 0 | if (host_view.empty() && is_special()) { |
10757 | 0 | return false; |
10758 | 0 | } |
10759 | | |
10760 | | // Otherwise, if state override is given, host_view is the empty string, |
10761 | | // and either url includes credentials or url's port is non-null, then |
10762 | | // return failure. |
10763 | 0 | if (host_view.empty() && (has_credentials() || port.has_value())) { |
10764 | 0 | return false; |
10765 | 0 | } |
10766 | | |
10767 | | // Let host be the result of host parsing host_view with url is not |
10768 | | // special. |
10769 | 0 | if (host_view.empty() && !is_special()) { |
10770 | 0 | host = ""; |
10771 | 0 | return check_url_size(); |
10772 | 0 | } |
10773 | | |
10774 | 0 | bool succeeded = parse_host(host_view); |
10775 | 0 | if (!succeeded) { |
10776 | 0 | *this = std::move(saved_url); |
10777 | 0 | return false; |
10778 | 0 | } |
10779 | 0 | return check_url_size(); |
10780 | 0 | } |
10781 | 0 | } |
10782 | | |
10783 | 0 | size_t location = new_host.find_first_of("/\\?"); |
10784 | 0 | if (location != std::string_view::npos) { |
10785 | 0 | new_host.remove_suffix(new_host.length() - location); |
10786 | 0 | } |
10787 | |
|
10788 | 0 | if (new_host.empty()) { |
10789 | | // Set url's host to the empty string. |
10790 | 0 | host = ""; |
10791 | 0 | } else { |
10792 | | // Let host be the result of host parsing buffer with url is not special. |
10793 | 0 | if (!parse_host(new_host)) { |
10794 | 0 | *this = std::move(saved_url); |
10795 | 0 | return false; |
10796 | 0 | } |
10797 | | |
10798 | | // If host is "localhost", then set host to the empty string. |
10799 | 0 | if (host == "localhost") { |
10800 | 0 | host = ""; |
10801 | 0 | } |
10802 | 0 | } |
10803 | 0 | return check_url_size(); |
10804 | 0 | } Unexecuted instantiation: bool ada::url::set_host_or_hostname<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: bool ada::url::set_host_or_hostname<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
10805 | | |
10806 | 0 | bool url::set_host(const std::string_view input) { |
10807 | 0 | return set_host_or_hostname<false>(input); |
10808 | 0 | } |
10809 | | |
10810 | 0 | bool url::set_hostname(const std::string_view input) { |
10811 | 0 | return set_host_or_hostname<true>(input); |
10812 | 0 | } |
10813 | | |
10814 | 0 | bool url::set_username(const std::string_view input) { |
10815 | 0 | if (cannot_have_credentials_or_port()) { |
10816 | 0 | return false; |
10817 | 0 | } |
10818 | 0 | auto previous_username = std::move(username); |
10819 | 0 | username = ada::unicode::percent_encode( |
10820 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
10821 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10822 | 0 | username = std::move(previous_username); |
10823 | 0 | return false; |
10824 | 0 | } |
10825 | 0 | return true; |
10826 | 0 | } |
10827 | | |
10828 | 0 | bool url::set_password(const std::string_view input) { |
10829 | 0 | if (cannot_have_credentials_or_port()) { |
10830 | 0 | return false; |
10831 | 0 | } |
10832 | 0 | auto previous_password = std::move(password); |
10833 | 0 | password = ada::unicode::percent_encode( |
10834 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
10835 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10836 | 0 | password = std::move(previous_password); |
10837 | 0 | return false; |
10838 | 0 | } |
10839 | 0 | return true; |
10840 | 0 | } |
10841 | | |
10842 | 0 | bool url::set_port(const std::string_view input) { |
10843 | 0 | if (cannot_have_credentials_or_port()) { |
10844 | 0 | return false; |
10845 | 0 | } |
10846 | | |
10847 | 0 | if (input.empty()) { |
10848 | 0 | port = std::nullopt; |
10849 | 0 | return true; |
10850 | 0 | } |
10851 | | |
10852 | 0 | std::string trimmed(input); |
10853 | 0 | helpers::remove_ascii_tab_or_newline(trimmed); |
10854 | |
|
10855 | 0 | if (trimmed.empty()) { |
10856 | 0 | return true; |
10857 | 0 | } |
10858 | | |
10859 | | // Input should not start with a non-digit character. |
10860 | 0 | if (!ada::unicode::is_ascii_digit(trimmed.front())) { |
10861 | 0 | return false; |
10862 | 0 | } |
10863 | | |
10864 | | // Find the first non-digit character to determine the length of digits |
10865 | 0 | auto first_non_digit = |
10866 | 0 | std::ranges::find_if_not(trimmed, ada::unicode::is_ascii_digit); |
10867 | 0 | std::string_view digits_to_parse = |
10868 | 0 | std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); |
10869 | | |
10870 | | // Revert changes if parse_port fails. |
10871 | 0 | std::optional<uint16_t> previous_port = port; |
10872 | 0 | parse_port(digits_to_parse); |
10873 | 0 | if (is_valid) { |
10874 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10875 | 0 | port = std::move(previous_port); |
10876 | 0 | return false; |
10877 | 0 | } |
10878 | 0 | return true; |
10879 | 0 | } |
10880 | 0 | port = std::move(previous_port); |
10881 | 0 | is_valid = true; |
10882 | 0 | return false; |
10883 | 0 | } |
10884 | | |
10885 | 0 | void url::set_hash(const std::string_view input) { |
10886 | 0 | if (input.empty()) { |
10887 | 0 | hash = std::nullopt; |
10888 | 0 | helpers::strip_trailing_spaces_from_opaque_path(*this); |
10889 | 0 | return; |
10890 | 0 | } |
10891 | | |
10892 | 0 | std::string new_value; |
10893 | 0 | new_value = input[0] == '#' ? input.substr(1) : input; |
10894 | 0 | helpers::remove_ascii_tab_or_newline(new_value); |
10895 | 0 | auto previous_hash = std::move(hash); |
10896 | 0 | hash = unicode::percent_encode(new_value, |
10897 | 0 | ada::character_sets::FRAGMENT_PERCENT_ENCODE); |
10898 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10899 | 0 | hash = std::move(previous_hash); |
10900 | 0 | } |
10901 | 0 | } |
10902 | | |
10903 | 0 | void url::set_search(const std::string_view input) { |
10904 | 0 | if (input.empty()) { |
10905 | 0 | query = std::nullopt; |
10906 | 0 | helpers::strip_trailing_spaces_from_opaque_path(*this); |
10907 | 0 | return; |
10908 | 0 | } |
10909 | | |
10910 | 0 | std::string new_value; |
10911 | 0 | new_value = input[0] == '?' ? input.substr(1) : input; |
10912 | 0 | helpers::remove_ascii_tab_or_newline(new_value); |
10913 | |
|
10914 | 0 | auto query_percent_encode_set = |
10915 | 0 | is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE |
10916 | 0 | : ada::character_sets::QUERY_PERCENT_ENCODE; |
10917 | |
|
10918 | 0 | auto previous_query = std::move(query); |
10919 | 0 | query = ada::unicode::percent_encode(new_value, query_percent_encode_set); |
10920 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10921 | 0 | query = std::move(previous_query); |
10922 | 0 | } |
10923 | 0 | } |
10924 | | |
10925 | 0 | bool url::set_pathname(const std::string_view input) { |
10926 | 0 | if (has_opaque_path) { |
10927 | 0 | return false; |
10928 | 0 | } |
10929 | 0 | auto previous_path = std::move(path); |
10930 | 0 | path.clear(); |
10931 | 0 | parse_path(input); |
10932 | 0 | if (get_href_size() > ada::get_max_input_length()) { |
10933 | 0 | path = std::move(previous_path); |
10934 | 0 | return false; |
10935 | 0 | } |
10936 | 0 | return true; |
10937 | 0 | } |
10938 | | |
10939 | 0 | bool url::set_protocol(const std::string_view input) { |
10940 | 0 | std::string view(input); |
10941 | 0 | helpers::remove_ascii_tab_or_newline(view); |
10942 | 0 | if (view.empty()) { |
10943 | 0 | return true; |
10944 | 0 | } |
10945 | | |
10946 | | // Schemes should start with alpha values. |
10947 | 0 | if (!checkers::is_alpha(view[0])) { |
10948 | 0 | return false; |
10949 | 0 | } |
10950 | | |
10951 | 0 | view.append(":"); |
10952 | |
|
10953 | 0 | std::string::iterator pointer = |
10954 | 0 | std::ranges::find_if_not(view, unicode::is_alnum_plus); |
10955 | |
|
10956 | 0 | if (pointer != view.end() && *pointer == ':') { |
10957 | 0 | std::optional<url> saved_url; |
10958 | 0 | if (needs_rollback_snapshot(view.size())) { |
10959 | 0 | saved_url = *this; |
10960 | 0 | } |
10961 | 0 | bool result = parse_scheme<true>( |
10962 | 0 | std::string_view(view.data(), pointer - view.begin())); |
10963 | 0 | if (result && saved_url && get_href_size() > ada::get_max_input_length()) { |
10964 | 0 | *this = std::move(*saved_url); |
10965 | 0 | return false; |
10966 | 0 | } |
10967 | 0 | return result; |
10968 | 0 | } |
10969 | 0 | return false; |
10970 | 0 | } |
10971 | | |
10972 | 0 | bool url::set_href(const std::string_view input) { |
10973 | 0 | ada::result<ada::url> out = ada::parse<ada::url>(input); |
10974 | |
|
10975 | 0 | if (out) { |
10976 | | // The parser enforces get_max_input_length() on both the input and the |
10977 | | // normalized result. This is a defense-in-depth check. |
10978 | 0 | if (out->get_href_size() > ada::get_max_input_length()) { |
10979 | 0 | return false; |
10980 | 0 | } |
10981 | 0 | *this = std::move(*out); |
10982 | 0 | } |
10983 | | |
10984 | 0 | return out.has_value(); |
10985 | 0 | } |
10986 | | |
10987 | | } // namespace ada |
10988 | | /* end file src/url.cpp */ |
10989 | | /* begin file src/parser.cpp */ |
10990 | | |
10991 | | #include <array> |
10992 | | #include <bit> |
10993 | | #include <charconv> |
10994 | | #include <cstdint> |
10995 | | #include <cstring> |
10996 | | #include <limits> |
10997 | | #include <optional> |
10998 | | #include <ranges> |
10999 | | #include <string> |
11000 | | #include <string_view> |
11001 | | #include <utility> |
11002 | | |
11003 | | |
11004 | | #if ADA_NEON |
11005 | | #include <arm_neon.h> |
11006 | | #elif defined(__SSSE3__) |
11007 | | #include <tmmintrin.h> |
11008 | | #define ADA_PARSER_SSSE3 1 |
11009 | | #elif (defined(__x86_64__) || defined(__amd64__)) && defined(__GNUC__) && \ |
11010 | | !defined(_MSC_VER) |
11011 | | // gcc/clang honor target("ssse3"). clang-cl and MSVC do not: they still |
11012 | | // compile the function as SSE2, then reject always_inline _mm_shuffle_epi8. |
11013 | | #include <tmmintrin.h> |
11014 | | #define ADA_PARSER_SSSE3 1 |
11015 | | #define ADA_PARSER_NEED_SSSE3_TARGET 1 |
11016 | | #elif ADA_SSE2 |
11017 | | #include <emmintrin.h> |
11018 | | #endif |
11019 | | #ifndef ADA_PARSER_SSSE3 |
11020 | | #define ADA_PARSER_SSSE3 0 |
11021 | | #endif |
11022 | | |
11023 | | #ifdef ADA_PARSER_NEED_SSSE3_TARGET |
11024 | | // Scan loops stay on the default ISA (SSE2 for generic x86-64). pshufb lives |
11025 | | // in a noinline SSSE3 function so the CPU check is not inside a function the |
11026 | | // compiler is free to compile entirely with SSSE3 instructions. |
11027 | | #define ADA_PARSER_SIMD ada_really_inline |
11028 | | #define ADA_PARSER_SSSE3_FN __attribute__((target("ssse3"), noinline)) |
11029 | | #else |
11030 | | #define ADA_PARSER_SIMD ada_really_inline |
11031 | | #define ADA_PARSER_SSSE3_FN ada_really_inline |
11032 | | #endif |
11033 | | |
11034 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
11035 | | #include <intrin.h> |
11036 | | #endif |
11037 | | |
11038 | | namespace ada::parser { |
11039 | | |
11040 | | // Classification tables and 16-byte run scanners for the absolute-URL fast |
11041 | | // path. Inspired by oven-sh/WebKit#452 and #454: scan 16 bytes at a time |
11042 | | // (nibble-table pshufb/tbl when SSSE3 or NEON is available), and when the |
11043 | | // path/query/fragment is not already canonical, keep the parsed host and |
11044 | | // finish with the existing path helpers instead of re-parsing from scratch. |
11045 | | namespace { |
11046 | | |
11047 | | // 0 = host byte, 1 = host delimiter (/ ? # :), 2 = reject |
11048 | | constexpr std::array<uint8_t, 256> k_host_class = []() consteval { |
11049 | | std::array<uint8_t, 256> t{}; |
11050 | | for (size_t i = 0; i < 256; ++i) { |
11051 | | t[i] = 2; |
11052 | | } |
11053 | | for (size_t i = 0x21; i <= 0x7E; ++i) { |
11054 | | t[i] = 0; |
11055 | | } |
11056 | | for (uint8_t c : |
11057 | | {'#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { |
11058 | | t[c] = 2; |
11059 | | } |
11060 | | t[static_cast<uint8_t>('/')] = 1; |
11061 | | t[static_cast<uint8_t>('?')] = 1; |
11062 | | t[static_cast<uint8_t>('#')] = 1; |
11063 | | t[static_cast<uint8_t>(':')] = 1; |
11064 | | return t; |
11065 | | }(); |
11066 | | |
11067 | | // Path: 0 = copy, 1 = ?/#, 2 = needs work. Apostrophe is copyable in a path. |
11068 | | constexpr std::array<uint8_t, 256> k_path = []() consteval { |
11069 | | std::array<uint8_t, 256> t{}; |
11070 | | for (size_t i = 0; i < 256; ++i) { |
11071 | | t[i] = 2; |
11072 | | } |
11073 | | for (uint8_t c = 0x21; c <= 0x7E; ++c) { |
11074 | | t[c] = 0; |
11075 | | } |
11076 | | for (uint8_t c : {static_cast<uint8_t>('"'), static_cast<uint8_t>('<'), |
11077 | | static_cast<uint8_t>('>'), static_cast<uint8_t>('`'), |
11078 | | static_cast<uint8_t>('{'), static_cast<uint8_t>('}'), |
11079 | | static_cast<uint8_t>('^'), static_cast<uint8_t>('\\'), |
11080 | | static_cast<uint8_t>('%')}) { |
11081 | | t[c] = 2; |
11082 | | } |
11083 | | t[static_cast<uint8_t>('?')] = 1; |
11084 | | t[static_cast<uint8_t>('#')] = 1; |
11085 | | return t; |
11086 | | }(); |
11087 | | |
11088 | | // Special-query: 0 = copy, 1 = #, 2 = needs work. Apostrophe must be encoded. |
11089 | | constexpr std::array<uint8_t, 256> k_query = []() consteval { |
11090 | | std::array<uint8_t, 256> t{}; |
11091 | | for (size_t i = 0; i < 256; ++i) { |
11092 | | t[i] = 2; |
11093 | | } |
11094 | | for (uint8_t c = 0x21; c <= 0x7E; ++c) { |
11095 | | t[c] = 0; |
11096 | | } |
11097 | | for (uint8_t c : {static_cast<uint8_t>('"'), static_cast<uint8_t>('<'), |
11098 | | static_cast<uint8_t>('>'), static_cast<uint8_t>('\'')}) { |
11099 | | t[c] = 2; |
11100 | | } |
11101 | | t[static_cast<uint8_t>('#')] = 1; |
11102 | | return t; |
11103 | | }(); |
11104 | | |
11105 | | // Fragment: 0 = copy, 2 = needs work. '?' '#' '%' are copyable. |
11106 | | constexpr std::array<uint8_t, 256> k_hash = []() consteval { |
11107 | | std::array<uint8_t, 256> t{}; |
11108 | | for (size_t i = 0; i < 256; ++i) { |
11109 | | t[i] = 2; |
11110 | | } |
11111 | | for (uint8_t c = 0x21; c <= 0x7E; ++c) { |
11112 | | t[c] = 0; |
11113 | | } |
11114 | | for (uint8_t c : {static_cast<uint8_t>('"'), static_cast<uint8_t>('<'), |
11115 | | static_cast<uint8_t>('>'), static_cast<uint8_t>('`')}) { |
11116 | | t[c] = 2; |
11117 | | } |
11118 | | return t; |
11119 | | }(); |
11120 | | |
11121 | | // Nibble tables for pshufb / tbl classification (oven-sh/WebKit#454). |
11122 | | // A byte is a stop when low[b & 0xF] & high[b >> 4] != 0. High nibbles whose |
11123 | | // sixteen bytes share a stop pattern share a bit, so any set with at most |
11124 | | // eight distinct patterns fits. Tables are built from the scalar class |
11125 | | // arrays, so the vector and scalar paths cannot disagree. |
11126 | | struct nibble_tables { |
11127 | | alignas(16) uint8_t low[16]{}; |
11128 | | alignas(16) uint8_t high[16]{}; |
11129 | | bool fits{true}; |
11130 | | }; |
11131 | | |
11132 | | consteval nibble_tables make_stop_nibble_tables( |
11133 | | const std::array<uint8_t, 256>& cls) { |
11134 | | nibble_tables t{}; |
11135 | | uint16_t patterns[16]{}; |
11136 | | for (int hi = 0; hi < 16; ++hi) { |
11137 | | for (int lo = 0; lo < 16; ++lo) { |
11138 | | if (cls[static_cast<size_t>((hi << 4) | lo)] != 0) { |
11139 | | patterns[hi] = static_cast<uint16_t>(patterns[hi] | (1u << lo)); |
11140 | | } |
11141 | | } |
11142 | | } |
11143 | | int bits_used = 0; |
11144 | | for (int hi = 0; hi < 16; ++hi) { |
11145 | | if (patterns[hi] == 0 || t.high[hi] != 0) { |
11146 | | continue; |
11147 | | } |
11148 | | if (bits_used == 8) { |
11149 | | t.fits = false; |
11150 | | return t; |
11151 | | } |
11152 | | const uint8_t bit = static_cast<uint8_t>(1u << bits_used++); |
11153 | | for (int other = hi; other < 16; ++other) { |
11154 | | if (patterns[other] == patterns[hi]) { |
11155 | | t.high[other] = static_cast<uint8_t>(t.high[other] | bit); |
11156 | | } |
11157 | | } |
11158 | | for (int lo = 0; lo < 16; ++lo) { |
11159 | | if ((patterns[hi] & (1u << lo)) != 0) { |
11160 | | t.low[lo] = static_cast<uint8_t>(t.low[lo] | bit); |
11161 | | } |
11162 | | } |
11163 | | } |
11164 | | return t; |
11165 | | } |
11166 | | |
11167 | | constexpr nibble_tables k_host_nibbles = make_stop_nibble_tables(k_host_class); |
11168 | | constexpr nibble_tables k_path_nibbles = make_stop_nibble_tables(k_path); |
11169 | | constexpr nibble_tables k_query_nibbles = make_stop_nibble_tables(k_query); |
11170 | | constexpr nibble_tables k_hash_nibbles = make_stop_nibble_tables(k_hash); |
11171 | | static_assert(k_host_nibbles.fits); |
11172 | | static_assert(k_path_nibbles.fits); |
11173 | | static_assert(k_query_nibbles.fits); |
11174 | | static_assert(k_hash_nibbles.fits); |
11175 | | |
11176 | | // WHATWG serializes a port as its decimal value with no leading zeros. |
11177 | 2.37k | ada_really_inline uint32_t port_decimal_digit_count(uint32_t port) noexcept { |
11178 | 2.37k | uint32_t digits = 1; |
11179 | 3.19k | while (port >= 10) { |
11180 | 818 | port /= 10; |
11181 | 818 | ++digits; |
11182 | 818 | } |
11183 | 2.37k | return digits; |
11184 | 2.37k | } |
11185 | | |
11186 | | ada_really_inline void append_canonical_port(std::string& buffer, |
11187 | 664 | uint32_t port) { |
11188 | 664 | buffer += ':'; |
11189 | 664 | char port_buf[5]; |
11190 | 664 | auto [ptr, ec] = std::to_chars(port_buf, port_buf + 5, port); |
11191 | 664 | (void)ec; |
11192 | 664 | buffer.append(port_buf, static_cast<size_t>(ptr - port_buf)); |
11193 | 664 | } |
11194 | | |
11195 | 11.1k | ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept { |
11196 | | #ifdef ADA_REGULAR_VISUAL_STUDIO |
11197 | | unsigned long ret; |
11198 | | _BitScanForward(&ret, input_num); |
11199 | | return static_cast<int>(ret); |
11200 | | #else |
11201 | 11.1k | return __builtin_ctz(input_num); |
11202 | 11.1k | #endif |
11203 | 11.1k | } |
11204 | | |
11205 | 0 | ada_really_inline int trailing_zeroes64(uint64_t input_num) noexcept { |
11206 | 0 | #ifdef ADA_REGULAR_VISUAL_STUDIO |
11207 | 0 | unsigned long ret; |
11208 | 0 | _BitScanForward64(&ret, input_num); |
11209 | 0 | return static_cast<int>(ret); |
11210 | 0 | #else |
11211 | 0 | return __builtin_ctzll(input_num); |
11212 | 0 | #endif |
11213 | 0 | } |
11214 | | |
11215 | | #if ADA_PARSER_SSSE3 |
11216 | 26.7k | ADA_PARSER_SIMD __m128i nibble_load(const uint8_t* t) noexcept { |
11217 | 26.7k | return _mm_load_si128(reinterpret_cast<const __m128i*>(t)); |
11218 | 26.7k | } |
11219 | | |
11220 | | // Non-zero lanes are stops. Tables are passed in so the scan loops can hoist |
11221 | | // the loads out of the 16-byte iteration. |
11222 | | ADA_PARSER_SSSE3_FN int ssse3_nibble_mask(__m128i w, __m128i lo_tbl, |
11223 | 37.2k | __m128i hi_tbl) noexcept { |
11224 | 37.2k | const __m128i nibble = _mm_set1_epi8(0x0F); |
11225 | 37.2k | const __m128i lo = _mm_and_si128(w, nibble); |
11226 | 37.2k | const __m128i hi = _mm_and_si128(_mm_srli_epi16(w, 4), nibble); |
11227 | 37.2k | const __m128i hit = |
11228 | 37.2k | _mm_and_si128(_mm_shuffle_epi8(lo_tbl, lo), _mm_shuffle_epi8(hi_tbl, hi)); |
11229 | 37.2k | return _mm_movemask_epi8(_mm_cmpeq_epi8(hit, _mm_setzero_si128())) ^ 0xFFFF; |
11230 | 37.2k | } |
11231 | | #endif // ADA_PARSER_SSSE3 |
11232 | | |
11233 | | #if ADA_SSE2 |
11234 | | #if !ADA_PARSER_SSSE3 |
11235 | | // Signed < 0x21 matches 0x00-0x20 and 0x80-0xFF; 0x7F is checked separately. |
11236 | | ada_really_inline __m128i sse2_ctrl_or_nonascii(__m128i w) noexcept { |
11237 | | return _mm_or_si128(_mm_cmplt_epi8(w, _mm_set1_epi8(0x21)), |
11238 | | _mm_cmpeq_epi8(w, _mm_set1_epi8(0x7F))); |
11239 | | } |
11240 | | |
11241 | | ada_really_inline int sse2_host_stop(__m128i w) noexcept { |
11242 | | const __m128i ctrl = sse2_ctrl_or_nonascii(w); |
11243 | | const __m128i is_upper = _mm_and_si128( |
11244 | | _mm_cmpgt_epi8(w, _mm_set1_epi8(static_cast<char>('A' - 1))), |
11245 | | _mm_cmplt_epi8(w, _mm_set1_epi8(static_cast<char>('Z' + 1)))); |
11246 | | const __m128i at = _mm_sub_epi8(w, _mm_set1_epi8('@')); |
11247 | | const __m128i at_through_caret = |
11248 | | _mm_cmpeq_epi8(_mm_min_epu8(at, _mm_set1_epi8('^' - '@')), at); |
11249 | | const __m128i at_not_upper = _mm_andnot_si128(is_upper, at_through_caret); |
11250 | | const __m128i spec = _mm_or_si128( |
11251 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('#')), |
11252 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('%'))), |
11253 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('/')), |
11254 | | _mm_cmpeq_epi8(w, _mm_set1_epi8(':')))), |
11255 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('<')), |
11256 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('>'))), |
11257 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('?')), |
11258 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('|'))))); |
11259 | | return _mm_movemask_epi8( |
11260 | | _mm_or_si128(_mm_or_si128(ctrl, at_not_upper), spec)); |
11261 | | } |
11262 | | |
11263 | | ada_really_inline int sse2_path_stop(__m128i w) noexcept { |
11264 | | const __m128i ctrl = sse2_ctrl_or_nonascii(w); |
11265 | | const __m128i spec = _mm_or_si128( |
11266 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('"')), |
11267 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('#'))), |
11268 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('%')), |
11269 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('<')))), |
11270 | | _mm_or_si128( |
11271 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('>')), |
11272 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('?'))), |
11273 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('\\')), |
11274 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('^')))), |
11275 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('`')), |
11276 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('{'))), |
11277 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('}'))))); |
11278 | | return _mm_movemask_epi8(_mm_or_si128(ctrl, spec)); |
11279 | | } |
11280 | | |
11281 | | ada_really_inline int sse2_query_stop(__m128i w) noexcept { |
11282 | | const __m128i ctrl = sse2_ctrl_or_nonascii(w); |
11283 | | const __m128i spec = _mm_or_si128( |
11284 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('"')), |
11285 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('#'))), |
11286 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('<')), |
11287 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('>'))), |
11288 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('\'')))); |
11289 | | return _mm_movemask_epi8(_mm_or_si128(ctrl, spec)); |
11290 | | } |
11291 | | |
11292 | | ada_really_inline int sse2_hash_stop(__m128i w) noexcept { |
11293 | | const __m128i ctrl = sse2_ctrl_or_nonascii(w); |
11294 | | const __m128i spec = |
11295 | | _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('"')), |
11296 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('<'))), |
11297 | | _mm_or_si128(_mm_cmpeq_epi8(w, _mm_set1_epi8('>')), |
11298 | | _mm_cmpeq_epi8(w, _mm_set1_epi8('`')))); |
11299 | | return _mm_movemask_epi8(_mm_or_si128(ctrl, spec)); |
11300 | | } |
11301 | | #endif // !ADA_PARSER_SSSE3 |
11302 | | |
11303 | 19.5k | ada_really_inline int sse2_uppercase(__m128i w) noexcept { |
11304 | 19.5k | return _mm_movemask_epi8(_mm_and_si128( |
11305 | 19.5k | _mm_cmpgt_epi8(w, _mm_set1_epi8(static_cast<char>('A' - 1))), |
11306 | 19.5k | _mm_cmplt_epi8(w, _mm_set1_epi8(static_cast<char>('Z' + 1))))); |
11307 | 19.5k | } |
11308 | | #endif // ADA_SSE2 |
11309 | | |
11310 | | #if ADA_NEON |
11311 | | ada_really_inline uint64_t neon_nibble_bits(uint8x16_t matches) noexcept { |
11312 | | const uint8x8_t nib = vshrn_n_u16(vreinterpretq_u16_u8(matches), 4); |
11313 | | return vget_lane_u64(vreinterpret_u64_u8(nib), 0); |
11314 | | } |
11315 | | |
11316 | | ada_really_inline uint64_t neon_table_stop(uint8x16_t w, uint8x16_t lo_tbl, |
11317 | | uint8x16_t hi_tbl) noexcept { |
11318 | | const uint8x16_t hit = |
11319 | | vandq_u8(vqtbl1q_u8(lo_tbl, vandq_u8(w, vdupq_n_u8(0x0F))), |
11320 | | vqtbl1q_u8(hi_tbl, vshrq_n_u8(w, 4))); |
11321 | | return neon_nibble_bits(vtstq_u8(hit, hit)); |
11322 | | } |
11323 | | |
11324 | | ada_really_inline uint64_t neon_uppercase(uint8x16_t w) noexcept { |
11325 | | return neon_nibble_bits( |
11326 | | vandq_u8(vcgeq_u8(w, vdupq_n_u8('A')), vcleq_u8(w, vdupq_n_u8('Z')))); |
11327 | | } |
11328 | | #endif // ADA_NEON |
11329 | | |
11330 | | // True when '@' appears in the authority before '/', '?', or '#'. |
11331 | | // One 16-byte window covers typical userinfo (SetHref's "user:pass@"). |
11332 | | // Longer userinfo still misses inside the never_inline fast path. No |
11333 | | // '@' is a single load + compare so the parse hot path stays cheap. |
11334 | | ada_really_inline bool authority_has_at(const uint8_t* p, size_t host_start, |
11335 | 4.54k | size_t n) noexcept { |
11336 | 4.54k | const size_t rem = n - host_start; |
11337 | 4.54k | if (rem == 0) { |
11338 | 0 | return false; |
11339 | 0 | } |
11340 | | #if ADA_NEON |
11341 | | if (rem >= 16) { |
11342 | | const uint8x16_t w = vld1q_u8(p + host_start); |
11343 | | const uint64_t at = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('@'))); |
11344 | | if (at == 0) { |
11345 | | return false; |
11346 | | } |
11347 | | const uint64_t delim = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('/'))) | |
11348 | | neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('?'))) | |
11349 | | neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('#'))); |
11350 | | return delim == 0 || std::countr_zero(at) < std::countr_zero(delim); |
11351 | | } |
11352 | | #elif ADA_SSE2 |
11353 | 4.54k | if (rem >= 16) { |
11354 | 1.38k | const __m128i w = |
11355 | 1.38k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + host_start)); |
11356 | 1.38k | const uint16_t at = static_cast<uint16_t>( |
11357 | 1.38k | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('@')))); |
11358 | 1.38k | if (at == 0) { |
11359 | 1.30k | return false; |
11360 | 1.30k | } |
11361 | 78 | const uint16_t delim = static_cast<uint16_t>( |
11362 | 78 | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) | |
11363 | 78 | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('?'))) | |
11364 | 78 | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('#')))); |
11365 | 78 | return delim == 0 || std::countr_zero(at) < std::countr_zero(delim); |
11366 | 1.38k | } |
11367 | 3.16k | #endif |
11368 | 3.16k | const size_t lim = host_start + rem; |
11369 | 16.4k | for (size_t i = host_start; i < lim; ++i) { |
11370 | 14.9k | const uint8_t c = p[i]; |
11371 | 14.9k | if (c == '@') { |
11372 | 20 | return true; |
11373 | 20 | } |
11374 | 14.9k | if (c == '/' || c == '?' || c == '#') { |
11375 | 1.64k | return false; |
11376 | 1.64k | } |
11377 | 14.9k | } |
11378 | 1.50k | return false; |
11379 | 3.16k | } |
11380 | | |
11381 | | #if ADA_PARSER_SSSE3 |
11382 | | // True when this process can execute the SSSE3 scanners. When the binary was |
11383 | | // built for SSSE3, the check is a constant. Otherwise it is cached from the |
11384 | | // CPU and the scanners fall back to the scalar loops below. |
11385 | 27.1k | ada_really_inline bool parser_use_ssse3() noexcept { |
11386 | 27.1k | #ifdef ADA_PARSER_NEED_SSSE3_TARGET |
11387 | 27.1k | static const bool supported = __builtin_cpu_supports("ssse3") != 0; |
11388 | 27.1k | return supported; |
11389 | | #else |
11390 | | return true; |
11391 | | #endif |
11392 | 27.1k | } |
11393 | | #endif |
11394 | | |
11395 | | // Returns false if a forbidden host code point is found. On success, *end is |
11396 | | // the first / ? # or len. has_upper / has_x only count host bytes, not the |
11397 | | // path/query bytes that may sit in the same SIMD window after the delimiter. |
11398 | | ADA_PARSER_SIMD bool scan_plain_host(const uint8_t* b, size_t start, size_t len, |
11399 | | size_t& end, bool& has_upper, |
11400 | 13.8k | bool& has_x) noexcept { |
11401 | 13.8k | has_upper = false; |
11402 | 13.8k | has_x = false; |
11403 | 13.8k | size_t i = start; |
11404 | 13.8k | #if ADA_PARSER_SSSE3 |
11405 | 13.8k | if (parser_use_ssse3() && (len - start >= 16)) { |
11406 | 7.09k | const __m128i lo_tbl = nibble_load(k_host_nibbles.low); |
11407 | 7.09k | const __m128i hi_tbl = nibble_load(k_host_nibbles.high); |
11408 | 7.09k | const __m128i x_splat = _mm_set1_epi8('x'); |
11409 | 19.5k | auto visit = [&](size_t at) noexcept -> bool { |
11410 | 19.5k | const __m128i w = |
11411 | 19.5k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at)); |
11412 | 19.5k | const int up = sse2_uppercase(w); |
11413 | 19.5k | const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat)); |
11414 | 19.5k | const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl); |
11415 | 19.5k | if (mask == 0) { |
11416 | 12.6k | if (up != 0) { |
11417 | 840 | has_upper = true; |
11418 | 840 | } |
11419 | 12.6k | if (xs != 0) { |
11420 | 9.70k | has_x = true; |
11421 | 9.70k | } |
11422 | 12.6k | return false; |
11423 | 12.6k | } |
11424 | 6.95k | const int hit = trailing_zeroes32(static_cast<uint32_t>(mask)); |
11425 | 6.95k | const int valid = (1 << hit) - 1; |
11426 | 6.95k | if ((up & valid) != 0) { |
11427 | 714 | has_upper = true; |
11428 | 714 | } |
11429 | 6.95k | if ((xs & valid) != 0) { |
11430 | 1.32k | has_x = true; |
11431 | 1.32k | } |
11432 | 6.95k | end = at + static_cast<size_t>(hit); |
11433 | 6.95k | return true; |
11434 | 19.5k | }; |
11435 | 12.5k | for (; i + 32 <= len; i += 32) { |
11436 | 8.69k | if (visit(i) || visit(i + 16)) { |
11437 | 3.19k | return k_host_class[b[end]] == 1; |
11438 | 3.19k | } |
11439 | 8.69k | } |
11440 | 5.24k | for (; i + 16 <= len; i += 16) { |
11441 | 3.33k | if (visit(i)) { |
11442 | 1.98k | return k_host_class[b[end]] == 1; |
11443 | 1.98k | } |
11444 | 3.33k | } |
11445 | | // Overlapping tail only after a full 16-byte step so the window cannot |
11446 | | // start before `start` (a prior '/' would otherwise look like a host stop). |
11447 | 1.91k | if (i > start && i < len) { |
11448 | 1.83k | if (visit(len - 16) && end >= i) { |
11449 | 1.77k | return k_host_class[b[end]] == 1; |
11450 | 1.77k | } |
11451 | 64 | end = len; |
11452 | 64 | return true; |
11453 | 1.83k | } |
11454 | 1.91k | } |
11455 | | #elif ADA_SSE2 |
11456 | | const __m128i x_splat = _mm_set1_epi8('x'); |
11457 | | for (; i + 32 <= len; i += 32) { |
11458 | | for (size_t off = 0; off < 32; off += 16) { |
11459 | | const __m128i w = |
11460 | | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + off)); |
11461 | | const int up = sse2_uppercase(w); |
11462 | | const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat)); |
11463 | | const int mask = sse2_host_stop(w); |
11464 | | if (mask != 0) { |
11465 | | const int hit = trailing_zeroes32(static_cast<uint32_t>(mask)); |
11466 | | const int valid = (1 << hit) - 1; |
11467 | | if ((up & valid) != 0) { |
11468 | | has_upper = true; |
11469 | | } |
11470 | | if ((xs & valid) != 0) { |
11471 | | has_x = true; |
11472 | | } |
11473 | | end = i + off + static_cast<size_t>(hit); |
11474 | | return k_host_class[b[end]] == 1; |
11475 | | } |
11476 | | if (up != 0) { |
11477 | | has_upper = true; |
11478 | | } |
11479 | | if (xs != 0) { |
11480 | | has_x = true; |
11481 | | } |
11482 | | } |
11483 | | } |
11484 | | for (; i + 16 <= len; i += 16) { |
11485 | | const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); |
11486 | | const int up = sse2_uppercase(w); |
11487 | | const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat)); |
11488 | | const int mask = sse2_host_stop(w); |
11489 | | if (mask != 0) { |
11490 | | const int hit = trailing_zeroes32(static_cast<uint32_t>(mask)); |
11491 | | const int valid = (1 << hit) - 1; |
11492 | | if ((up & valid) != 0) { |
11493 | | has_upper = true; |
11494 | | } |
11495 | | if ((xs & valid) != 0) { |
11496 | | has_x = true; |
11497 | | } |
11498 | | end = i + static_cast<size_t>(hit); |
11499 | | return k_host_class[b[end]] == 1; |
11500 | | } |
11501 | | if (up != 0) { |
11502 | | has_upper = true; |
11503 | | } |
11504 | | if (xs != 0) { |
11505 | | has_x = true; |
11506 | | } |
11507 | | } |
11508 | | #elif ADA_NEON |
11509 | | if (len - start >= 16) { |
11510 | | const uint8x16_t lo_tbl = vld1q_u8(k_host_nibbles.low); |
11511 | | const uint8x16_t hi_tbl = vld1q_u8(k_host_nibbles.high); |
11512 | | const uint8x16_t x_splat = vdupq_n_u8('x'); |
11513 | | auto visit = [&](size_t at) noexcept -> bool { |
11514 | | const uint8x16_t w = vld1q_u8(b + at); |
11515 | | const uint64_t up = neon_uppercase(w); |
11516 | | const uint64_t xs = neon_nibble_bits(vceqq_u8(w, x_splat)); |
11517 | | const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl); |
11518 | | if (bits == 0) { |
11519 | | if (up != 0) { |
11520 | | has_upper = true; |
11521 | | } |
11522 | | if (xs != 0) { |
11523 | | has_x = true; |
11524 | | } |
11525 | | return false; |
11526 | | } |
11527 | | const size_t hit = static_cast<size_t>(trailing_zeroes64(bits)) >> 2; |
11528 | | const uint64_t valid = (hit == 0) ? 0 : (uint64_t{1} << (hit * 4)) - 1; |
11529 | | if ((up & valid) != 0) { |
11530 | | has_upper = true; |
11531 | | } |
11532 | | if ((xs & valid) != 0) { |
11533 | | has_x = true; |
11534 | | } |
11535 | | end = at + hit; |
11536 | | return true; |
11537 | | }; |
11538 | | for (; i + 32 <= len; i += 32) { |
11539 | | if (visit(i) || visit(i + 16)) { |
11540 | | return k_host_class[b[end]] == 1; |
11541 | | } |
11542 | | } |
11543 | | for (; i + 16 <= len; i += 16) { |
11544 | | if (visit(i)) { |
11545 | | return k_host_class[b[end]] == 1; |
11546 | | } |
11547 | | } |
11548 | | if (i > start && i < len) { |
11549 | | if (visit(len - 16) && end >= i) { |
11550 | | return k_host_class[b[end]] == 1; |
11551 | | } |
11552 | | end = len; |
11553 | | return true; |
11554 | | } |
11555 | | } |
11556 | | #endif |
11557 | 27.9k | for (; i < len; ++i) { |
11558 | 27.5k | const uint8_t c = b[i]; |
11559 | 27.5k | const uint8_t cls = k_host_class[c]; |
11560 | 27.5k | if (cls == 1) { |
11561 | 6.39k | end = i; |
11562 | 6.39k | return true; |
11563 | 6.39k | } |
11564 | 21.2k | if (cls == 2) { |
11565 | 162 | return false; |
11566 | 162 | } |
11567 | 21.0k | if (c >= 'A' && c <= 'Z') { |
11568 | 792 | has_upper = true; |
11569 | 20.2k | } else if (c == 'x') { |
11570 | 2.93k | has_x = true; |
11571 | 2.93k | } |
11572 | 21.0k | } |
11573 | 310 | end = len; |
11574 | 310 | return true; |
11575 | 6.86k | } |
11576 | | |
11577 | | ada_really_inline void note_possible_dot_segment( |
11578 | | const uint8_t* b, size_t pos, size_t run_start, |
11579 | 4.15k | bool& maybe_dot_segment) noexcept { |
11580 | 4.15k | if (pos == run_start || b[pos - 1] == '/') { |
11581 | 2.10k | maybe_dot_segment = true; |
11582 | 2.10k | } |
11583 | 4.15k | } |
11584 | | |
11585 | | #if ADA_PARSER_SSSE3 || ADA_SSE2 |
11586 | | // valid_mask selects bytes in this 16-byte window that belong to the path |
11587 | | // (bits after a stop are cleared). A '.' starts a possible dot-segment when |
11588 | | // it is the first path byte or immediately follows '/'. |
11589 | | ada_really_inline void note_dots_in_window(const uint8_t* b, size_t i, |
11590 | | size_t run_start, __m128i w, |
11591 | | int valid_mask, |
11592 | 10.3k | bool& maybe_dot_segment) noexcept { |
11593 | 10.3k | if (maybe_dot_segment || valid_mask == 0) { |
11594 | 3.73k | return; |
11595 | 3.73k | } |
11596 | 6.61k | const int dots = |
11597 | 6.61k | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('.'))) & valid_mask; |
11598 | 6.61k | if (dots == 0) { |
11599 | 2.43k | return; |
11600 | 2.43k | } |
11601 | 4.18k | const int slashes = |
11602 | 4.18k | _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) & valid_mask; |
11603 | 4.18k | if (((dots & 1) != 0 && (i == run_start || b[i - 1] == '/')) || |
11604 | 3.44k | (dots & (slashes << 1)) != 0) { |
11605 | 1.50k | maybe_dot_segment = true; |
11606 | 1.50k | } |
11607 | 4.18k | } |
11608 | | #endif |
11609 | | |
11610 | | #if ADA_NEON |
11611 | | // Each NEON match nibble occupies 4 bits, so a '.' immediately after '/' is |
11612 | | // (slashes << 4) rather than (slashes << 1). |
11613 | | ada_really_inline void note_dots_in_window_neon( |
11614 | | const uint8_t* b, size_t i, size_t run_start, uint8x16_t w, |
11615 | | uint64_t valid_bits, bool& maybe_dot_segment) noexcept { |
11616 | | if (maybe_dot_segment || valid_bits == 0) { |
11617 | | return; |
11618 | | } |
11619 | | const uint64_t dots = |
11620 | | neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('.'))) & valid_bits; |
11621 | | if (dots == 0) { |
11622 | | return; |
11623 | | } |
11624 | | const uint64_t slashes = |
11625 | | neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('/'))) & valid_bits; |
11626 | | if (((dots & 0xF) != 0 && (i == run_start || b[i - 1] == '/')) || |
11627 | | (dots & (slashes << 4)) != 0) { |
11628 | | maybe_dot_segment = true; |
11629 | | } |
11630 | | } |
11631 | | #endif |
11632 | | |
11633 | | // Advance i to the first path-class 1 or 2 character (or len). |
11634 | | ADA_PARSER_SIMD void scan_path_run(const uint8_t* b, size_t& i, size_t len, |
11635 | 10.2k | bool& maybe_dot_segment) noexcept { |
11636 | 10.2k | const size_t run_start = i; |
11637 | 10.2k | #if ADA_PARSER_SSSE3 |
11638 | 10.2k | if (parser_use_ssse3() && (i + 16 <= len)) { |
11639 | 4.53k | const __m128i lo_tbl = nibble_load(k_path_nibbles.low); |
11640 | 4.53k | const __m128i hi_tbl = nibble_load(k_path_nibbles.high); |
11641 | 7.50k | for (; i + 32 <= len; i += 32) { |
11642 | 4.90k | const __m128i w0 = |
11643 | 4.90k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); |
11644 | 4.90k | const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl); |
11645 | 4.90k | if (m0 != 0) { |
11646 | 1.47k | const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m0)); |
11647 | 1.47k | note_dots_in_window(b, i, run_start, w0, (1 << hit_bit) - 1, |
11648 | 1.47k | maybe_dot_segment); |
11649 | 1.47k | i += static_cast<size_t>(hit_bit); |
11650 | 1.47k | return; |
11651 | 1.47k | } |
11652 | 3.43k | note_dots_in_window(b, i, run_start, w0, 0xFFFF, maybe_dot_segment); |
11653 | 3.43k | const __m128i w1 = |
11654 | 3.43k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16)); |
11655 | 3.43k | const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl); |
11656 | 3.43k | if (m1 != 0) { |
11657 | 462 | const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m1)); |
11658 | 462 | note_dots_in_window(b, i + 16, run_start, w1, (1 << hit_bit) - 1, |
11659 | 462 | maybe_dot_segment); |
11660 | 462 | i += 16 + static_cast<size_t>(hit_bit); |
11661 | 462 | return; |
11662 | 462 | } |
11663 | 2.96k | note_dots_in_window(b, i + 16, run_start, w1, 0xFFFF, maybe_dot_segment); |
11664 | 2.96k | } |
11665 | 3.76k | for (; i + 16 <= len; i += 16) { |
11666 | 2.02k | const __m128i w = |
11667 | 2.02k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); |
11668 | 2.02k | const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl); |
11669 | 2.02k | if (mask != 0) { |
11670 | 858 | const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask)); |
11671 | 858 | note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1, |
11672 | 858 | maybe_dot_segment); |
11673 | 858 | i += static_cast<size_t>(hit_bit); |
11674 | 858 | return; |
11675 | 858 | } |
11676 | 1.16k | note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment); |
11677 | 1.16k | } |
11678 | 1.74k | if (i > run_start && i < len) { |
11679 | 1.06k | const __m128i w = |
11680 | 1.06k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); |
11681 | 1.06k | const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl); |
11682 | 1.06k | if (mask != 0) { |
11683 | 408 | const size_t hit = |
11684 | 408 | len - 16 + |
11685 | 408 | static_cast<size_t>(trailing_zeroes32(static_cast<uint32_t>(mask))); |
11686 | 408 | if (hit >= i) { |
11687 | 2.15k | for (size_t j = i; j < hit; ++j) { |
11688 | 1.74k | if (b[j] == '.') { |
11689 | 628 | note_possible_dot_segment(b, j, run_start, maybe_dot_segment); |
11690 | 628 | } |
11691 | 1.74k | } |
11692 | 408 | i = hit; |
11693 | 408 | return; |
11694 | 408 | } |
11695 | 408 | } |
11696 | 4.96k | for (size_t j = i; j < len; ++j) { |
11697 | 4.30k | if (b[j] == '.') { |
11698 | 1.31k | note_possible_dot_segment(b, j, run_start, maybe_dot_segment); |
11699 | 1.31k | } |
11700 | 4.30k | } |
11701 | 660 | i = len; |
11702 | 660 | return; |
11703 | 1.06k | } |
11704 | 1.74k | } |
11705 | | #elif ADA_SSE2 |
11706 | | for (; i + 16 <= len; i += 16) { |
11707 | | const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); |
11708 | | const int mask = sse2_path_stop(w); |
11709 | | if (mask != 0) { |
11710 | | const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask)); |
11711 | | note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1, |
11712 | | maybe_dot_segment); |
11713 | | i += static_cast<size_t>(hit_bit); |
11714 | | return; |
11715 | | } |
11716 | | note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment); |
11717 | | } |
11718 | | #elif ADA_NEON |
11719 | | if (i + 16 <= len) { |
11720 | | const uint8x16_t lo_tbl = vld1q_u8(k_path_nibbles.low); |
11721 | | const uint8x16_t hi_tbl = vld1q_u8(k_path_nibbles.high); |
11722 | | for (; i + 32 <= len; i += 32) { |
11723 | | const uint8x16_t w0 = vld1q_u8(b + i); |
11724 | | const uint64_t bits0 = neon_table_stop(w0, lo_tbl, hi_tbl); |
11725 | | if (bits0 != 0) { |
11726 | | const size_t hit_off = |
11727 | | static_cast<size_t>(trailing_zeroes64(bits0)) >> 2; |
11728 | | const uint64_t valid = |
11729 | | (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1; |
11730 | | note_dots_in_window_neon(b, i, run_start, w0, valid, maybe_dot_segment); |
11731 | | i += hit_off; |
11732 | | return; |
11733 | | } |
11734 | | note_dots_in_window_neon(b, i, run_start, w0, ~uint64_t{0}, |
11735 | | maybe_dot_segment); |
11736 | | const uint8x16_t w1 = vld1q_u8(b + i + 16); |
11737 | | const uint64_t bits1 = neon_table_stop(w1, lo_tbl, hi_tbl); |
11738 | | if (bits1 != 0) { |
11739 | | const size_t hit_off = |
11740 | | static_cast<size_t>(trailing_zeroes64(bits1)) >> 2; |
11741 | | const uint64_t valid = |
11742 | | (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1; |
11743 | | note_dots_in_window_neon(b, i + 16, run_start, w1, valid, |
11744 | | maybe_dot_segment); |
11745 | | i += 16 + hit_off; |
11746 | | return; |
11747 | | } |
11748 | | note_dots_in_window_neon(b, i + 16, run_start, w1, ~uint64_t{0}, |
11749 | | maybe_dot_segment); |
11750 | | } |
11751 | | for (; i + 16 <= len; i += 16) { |
11752 | | const uint8x16_t w = vld1q_u8(b + i); |
11753 | | const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl); |
11754 | | if (bits != 0) { |
11755 | | const size_t hit_off = |
11756 | | static_cast<size_t>(trailing_zeroes64(bits)) >> 2; |
11757 | | const uint64_t valid = |
11758 | | (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1; |
11759 | | note_dots_in_window_neon(b, i, run_start, w, valid, maybe_dot_segment); |
11760 | | i += hit_off; |
11761 | | return; |
11762 | | } |
11763 | | note_dots_in_window_neon(b, i, run_start, w, ~uint64_t{0}, |
11764 | | maybe_dot_segment); |
11765 | | } |
11766 | | if (i > run_start && i < len) { |
11767 | | const uint8x16_t w = vld1q_u8(b + len - 16); |
11768 | | const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl); |
11769 | | if (bits != 0) { |
11770 | | const size_t hit = |
11771 | | len - 16 + (static_cast<size_t>(trailing_zeroes64(bits)) >> 2); |
11772 | | if (hit >= i) { |
11773 | | for (size_t j = i; j < hit; ++j) { |
11774 | | if (b[j] == '.') { |
11775 | | note_possible_dot_segment(b, j, run_start, maybe_dot_segment); |
11776 | | } |
11777 | | } |
11778 | | i = hit; |
11779 | | return; |
11780 | | } |
11781 | | } |
11782 | | for (size_t j = i; j < len; ++j) { |
11783 | | if (b[j] == '.') { |
11784 | | note_possible_dot_segment(b, j, run_start, maybe_dot_segment); |
11785 | | } |
11786 | | } |
11787 | | i = len; |
11788 | | return; |
11789 | | } |
11790 | | } |
11791 | | #endif |
11792 | 13.3k | for (; i < len; ++i) { |
11793 | 9.02k | const uint8_t c = b[i]; |
11794 | 9.02k | const uint8_t cls = k_path[c]; |
11795 | 9.02k | if (cls != 0) { |
11796 | 2.07k | return; |
11797 | 2.07k | } |
11798 | 6.95k | if (c == '.') { |
11799 | 2.21k | note_possible_dot_segment(b, i, run_start, maybe_dot_segment); |
11800 | 2.21k | } |
11801 | 6.95k | } |
11802 | 6.40k | } |
11803 | | |
11804 | | // Advance i to the first class-table stop (or len). Query and hash share |
11805 | | // this loop; path keeps its own copy because it also tracks '.' segments. |
11806 | | #if ADA_PARSER_SSSE3 |
11807 | | #define ADA_SCAN_STOP_RUN(nibbles, cls, unused_sse2_stop) \ |
11808 | 2.98k | do { \ |
11809 | 2.98k | const size_t scan_start = i; \ |
11810 | 2.98k | if (parser_use_ssse3() && (i + 16 <= len)) { \ |
11811 | 1.73k | const __m128i lo_tbl = nibble_load((nibbles).low); \ |
11812 | 1.73k | const __m128i hi_tbl = nibble_load((nibbles).high); \ |
11813 | 3.66k | for (; i + 32 <= len; i += 32) { \ |
11814 | 2.43k | const __m128i w0 = \ |
11815 | 2.43k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); \ |
11816 | 2.43k | const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl); \ |
11817 | 2.43k | if (m0 != 0) { \ |
11818 | 296 | i += static_cast<size_t>( \ |
11819 | 296 | trailing_zeroes32(static_cast<uint32_t>(m0))); \ |
11820 | 296 | return; \ |
11821 | 296 | } \ |
11822 | 2.43k | const __m128i w1 = \ |
11823 | 2.14k | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16)); \ |
11824 | 2.14k | const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl); \ |
11825 | 2.14k | if (m1 != 0) { \ |
11826 | 208 | i += 16 + static_cast<size_t>( \ |
11827 | 208 | trailing_zeroes32(static_cast<uint32_t>(m1))); \ |
11828 | 208 | return; \ |
11829 | 208 | } \ |
11830 | 2.14k | } \ |
11831 | 1.90k | for (; i + 16 <= len; i += 16) { \ |
11832 | 956 | const __m128i w = \ |
11833 | 956 | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); \ |
11834 | 956 | const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl); \ |
11835 | 956 | if (mask != 0) { \ |
11836 | 274 | i += static_cast<size_t>( \ |
11837 | 274 | trailing_zeroes32(static_cast<uint32_t>(mask))); \ |
11838 | 274 | return; \ |
11839 | 274 | } \ |
11840 | 956 | } \ |
11841 | 1.22k | if (i > scan_start && i < len) { \ |
11842 | 700 | const __m128i w = \ |
11843 | 700 | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \ |
11844 | 700 | const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl); \ |
11845 | 700 | if (mask != 0) { \ |
11846 | 240 | const size_t hit = len - 16 + \ |
11847 | 240 | static_cast<size_t>(trailing_zeroes32( \ |
11848 | 240 | static_cast<uint32_t>(mask))); \ |
11849 | 240 | if (hit >= i) { \ |
11850 | 240 | i = hit; \ |
11851 | 240 | return; \ |
11852 | 240 | } \ |
11853 | 240 | } \ |
11854 | 700 | i = len; \ |
11855 | 460 | return; \ |
11856 | 700 | } \ |
11857 | 952 | } \ |
11858 | 4.82k | for (; i < len; ++i) { \ |
11859 | 3.67k | if ((cls)[b[i]] != 0) { \ |
11860 | 368 | return; \ |
11861 | 368 | } \ |
11862 | 3.67k | } \ |
11863 | 1.51k | } while (0) |
11864 | | #elif ADA_NEON |
11865 | | #define ADA_SCAN_STOP_RUN(nibbles, cls, unused_sse2_stop) \ |
11866 | | do { \ |
11867 | | const size_t scan_start = i; \ |
11868 | | if (i + 16 <= len) { \ |
11869 | | const uint8x16_t lo_tbl = vld1q_u8((nibbles).low); \ |
11870 | | const uint8x16_t hi_tbl = vld1q_u8((nibbles).high); \ |
11871 | | for (; i + 32 <= len; i += 32) { \ |
11872 | | const uint64_t bits0 = \ |
11873 | | neon_table_stop(vld1q_u8(b + i), lo_tbl, hi_tbl); \ |
11874 | | if (bits0 != 0) { \ |
11875 | | i += static_cast<size_t>(trailing_zeroes64(bits0)) >> 2; \ |
11876 | | return; \ |
11877 | | } \ |
11878 | | const uint64_t bits1 = \ |
11879 | | neon_table_stop(vld1q_u8(b + i + 16), lo_tbl, hi_tbl); \ |
11880 | | if (bits1 != 0) { \ |
11881 | | i += 16 + (static_cast<size_t>(trailing_zeroes64(bits1)) >> 2); \ |
11882 | | return; \ |
11883 | | } \ |
11884 | | } \ |
11885 | | for (; i + 16 <= len; i += 16) { \ |
11886 | | const uint8x16_t w = vld1q_u8(b + i); \ |
11887 | | const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl); \ |
11888 | | if (bits != 0) { \ |
11889 | | i += static_cast<size_t>(trailing_zeroes64(bits)) >> 2; \ |
11890 | | return; \ |
11891 | | } \ |
11892 | | } \ |
11893 | | if (i > scan_start && i < len) { \ |
11894 | | const uint8x16_t w = vld1q_u8(b + len - 16); \ |
11895 | | const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl); \ |
11896 | | if (bits != 0) { \ |
11897 | | const size_t hit = \ |
11898 | | len - 16 + (static_cast<size_t>(trailing_zeroes64(bits)) >> 2); \ |
11899 | | if (hit >= i) { \ |
11900 | | i = hit; \ |
11901 | | return; \ |
11902 | | } \ |
11903 | | } \ |
11904 | | i = len; \ |
11905 | | return; \ |
11906 | | } \ |
11907 | | } \ |
11908 | | for (; i < len; ++i) { \ |
11909 | | if ((cls)[b[i]] != 0) { \ |
11910 | | return; \ |
11911 | | } \ |
11912 | | } \ |
11913 | | } while (0) |
11914 | | #elif ADA_SSE2 |
11915 | | #define ADA_SCAN_STOP_RUN(nibbles, cls, sse2_stop) \ |
11916 | | do { \ |
11917 | | for (; i + 16 <= len; i += 16) { \ |
11918 | | const __m128i w = \ |
11919 | | _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i)); \ |
11920 | | const int mask = sse2_stop(w); \ |
11921 | | if (mask != 0) { \ |
11922 | | i += static_cast<size_t>( \ |
11923 | | trailing_zeroes32(static_cast<uint32_t>(mask))); \ |
11924 | | return; \ |
11925 | | } \ |
11926 | | } \ |
11927 | | for (; i < len; ++i) { \ |
11928 | | if ((cls)[b[i]] != 0) { \ |
11929 | | return; \ |
11930 | | } \ |
11931 | | } \ |
11932 | | } while (0) |
11933 | | #else |
11934 | | #define ADA_SCAN_STOP_RUN(nibbles, cls, unused_sse2_stop) \ |
11935 | | do { \ |
11936 | | for (; i < len; ++i) { \ |
11937 | | if ((cls)[b[i]] != 0) { \ |
11938 | | return; \ |
11939 | | } \ |
11940 | | } \ |
11941 | | } while (0) |
11942 | | #endif |
11943 | | |
11944 | | ADA_PARSER_SIMD void scan_query_run(const uint8_t* b, size_t& i, |
11945 | 1.45k | size_t len) noexcept { |
11946 | 1.45k | ADA_SCAN_STOP_RUN(k_query_nibbles, k_query, sse2_query_stop); |
11947 | 1.45k | } |
11948 | | |
11949 | | ADA_PARSER_SIMD void scan_hash_run(const uint8_t* b, size_t& i, |
11950 | 1.53k | size_t len) noexcept { |
11951 | 1.53k | ADA_SCAN_STOP_RUN(k_hash_nibbles, k_hash, sse2_hash_stop); |
11952 | 1.53k | } |
11953 | | |
11954 | | #undef ADA_SCAN_STOP_RUN |
11955 | | |
11956 | 1.63k | bool path_has_dot_segment(std::string_view path) noexcept { |
11957 | 1.63k | if (path.empty()) { |
11958 | 0 | return false; |
11959 | 0 | } |
11960 | | // "." / ".." at the start, with or without a leading '/'. |
11961 | 1.63k | const size_t i = (path[0] == '/') ? 1 : 0; |
11962 | 1.63k | if (i < path.size() && path[i] == '.') { |
11963 | 650 | const size_t after = i + 1; |
11964 | 650 | if (after == path.size() || path[after] == '/' || |
11965 | 416 | (after < path.size() && path[after] == '.' && |
11966 | 352 | (after + 1 == path.size() || path[after + 1] == '/'))) { |
11967 | 352 | return true; |
11968 | 352 | } |
11969 | 650 | } |
11970 | 1.28k | static constexpr std::string_view slash_dot{"/.", 2}; |
11971 | 1.28k | size_t p = i; |
11972 | 3.47k | while ((p = path.find(slash_dot, p)) != std::string_view::npos) { |
11973 | 2.80k | const size_t after = p + 2; |
11974 | 2.80k | if (after == path.size() || path[after] == '/' || |
11975 | 2.44k | (after < path.size() && path[after] == '.' && |
11976 | 696 | (after + 1 == path.size() || path[after + 1] == '/'))) { |
11977 | 610 | return true; |
11978 | 610 | } |
11979 | 2.19k | p = after; |
11980 | 2.19k | } |
11981 | 676 | return false; |
11982 | 1.28k | } |
11983 | | |
11984 | | } // namespace |
11985 | | |
11986 | | template <class result_type> |
11987 | | ada_never_inline bool finish_simple_absolute_with_port( |
11988 | | std::string_view input, result_type& out, ada::scheme::type scheme_type, |
11989 | | uint32_t protocol_end, size_t host_start, size_t host_end, size_t host_len, |
11990 | 3.76k | bool has_upper) { |
11991 | 3.76k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; |
11992 | 3.76k | constexpr bool is_aggregator = |
11993 | 3.76k | std::is_same_v<result_type, ada::url_aggregator>; |
11994 | 3.76k | static_assert(is_ada_url || is_aggregator); |
11995 | | |
11996 | 3.76k | const size_t len = input.size(); |
11997 | 3.76k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); |
11998 | 3.76k | size_t p = host_end + 1; |
11999 | 3.76k | uint32_t port_value = 0; |
12000 | 3.76k | bool any_digit = false; |
12001 | 8.14k | while (p < len && b[p] >= '0' && b[p] <= '9') { |
12002 | 4.40k | any_digit = true; |
12003 | 4.40k | port_value = port_value * 10 + static_cast<uint32_t>(b[p] - '0'); |
12004 | 4.40k | if (port_value > 65535) [[unlikely]] { |
12005 | 22 | return false; |
12006 | 22 | } |
12007 | 4.38k | ++p; |
12008 | 4.38k | } |
12009 | 3.73k | if (p < len && b[p] != '/' && b[p] != '?' && b[p] != '#') [[unlikely]] { |
12010 | 102 | return false; |
12011 | 102 | } |
12012 | 3.63k | uint32_t parsed_port = url_components::omitted; |
12013 | 3.63k | const uint16_t default_port = ada::scheme::get_special_port(scheme_type); |
12014 | 3.63k | if (any_digit && port_value != default_port) { |
12015 | 2.39k | parsed_port = port_value; |
12016 | 2.39k | } |
12017 | 3.63k | const size_t authority_end = p; |
12018 | | |
12019 | 3.63k | size_t i = authority_end; |
12020 | 3.63k | size_t path_start = host_end; |
12021 | 3.63k | size_t path_end = host_end; |
12022 | 3.63k | size_t query_start = std::string_view::npos; |
12023 | 3.63k | size_t hash_start = std::string_view::npos; |
12024 | 3.63k | bool has_path = false; |
12025 | 3.63k | bool maybe_dot_segment = false; |
12026 | 3.63k | bool rest_simple = true; |
12027 | | |
12028 | 3.63k | if (i < len && b[i] == '/') { |
12029 | 3.20k | has_path = true; |
12030 | 3.20k | path_start = i; |
12031 | 3.20k | ++i; |
12032 | 3.20k | scan_path_run(b, i, len, maybe_dot_segment); |
12033 | 3.20k | if (i < len) { |
12034 | 2.02k | const uint8_t cls = k_path[b[i]]; |
12035 | 2.02k | if (cls == 1) { |
12036 | 448 | path_end = i; |
12037 | 448 | if (b[i] == '?') { |
12038 | 286 | query_start = i; |
12039 | 286 | ++i; |
12040 | 286 | goto scan_query; |
12041 | 286 | } |
12042 | 162 | hash_start = i; |
12043 | 162 | ++i; |
12044 | 162 | goto scan_hash; |
12045 | 448 | } |
12046 | 1.57k | rest_simple = false; |
12047 | 49.3k | for (; i < len; ++i) { |
12048 | 47.9k | if (b[i] == '?') { |
12049 | 108 | path_end = i; |
12050 | 108 | query_start = i; |
12051 | 108 | ++i; |
12052 | 108 | goto scan_query_boundary; |
12053 | 108 | } |
12054 | 47.8k | if (b[i] == '#') { |
12055 | 34 | path_end = i; |
12056 | 34 | hash_start = i; |
12057 | 34 | ++i; |
12058 | 34 | goto after_rest; |
12059 | 34 | } |
12060 | 47.8k | } |
12061 | 1.43k | path_end = i; |
12062 | 1.43k | goto after_rest; |
12063 | 1.57k | } |
12064 | 1.17k | path_end = i; |
12065 | 1.17k | } else if (i < len && b[i] == '?') { |
12066 | 146 | query_start = i; |
12067 | 146 | ++i; |
12068 | 146 | goto scan_query; |
12069 | 286 | } else if (i < len && b[i] == '#') { |
12070 | 136 | hash_start = i; |
12071 | 136 | ++i; |
12072 | 136 | goto scan_hash; |
12073 | 136 | } |
12074 | 1.32k | goto after_rest; |
12075 | | |
12076 | 1.32k | scan_query: |
12077 | 432 | scan_query_run(b, i, len); |
12078 | 432 | if (i < len) { |
12079 | 222 | if (b[i] == '#') { |
12080 | 152 | hash_start = i; |
12081 | 152 | ++i; |
12082 | 152 | goto scan_hash; |
12083 | 152 | } |
12084 | 70 | rest_simple = false; |
12085 | 70 | goto scan_query_boundary; |
12086 | 222 | } |
12087 | 210 | goto after_rest; |
12088 | | |
12089 | 210 | scan_query_boundary: |
12090 | 2.93k | for (; i < len; ++i) { |
12091 | 2.79k | if (b[i] == '#') { |
12092 | 42 | hash_start = i; |
12093 | 42 | ++i; |
12094 | 42 | goto after_rest; |
12095 | 42 | } |
12096 | 2.79k | } |
12097 | 136 | goto after_rest; |
12098 | | |
12099 | 450 | scan_hash: |
12100 | 450 | scan_hash_run(b, i, len); |
12101 | 450 | if (i < len) { |
12102 | 112 | rest_simple = false; |
12103 | 112 | } |
12104 | | |
12105 | 3.63k | after_rest: |
12106 | 3.63k | if (rest_simple && maybe_dot_segment) { |
12107 | 686 | const std::string_view path_body(input.data() + path_start, |
12108 | 686 | path_end - path_start); |
12109 | 686 | if (path_has_dot_segment(path_body)) { |
12110 | 462 | rest_simple = false; |
12111 | 462 | } |
12112 | 686 | } |
12113 | | |
12114 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a |
12115 | | // trailing C0 control or space; this fast path does neither. A query or |
12116 | | // fragment reaching the helpers below would keep those bytes percent-encoded |
12117 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such |
12118 | | // inputs back to the slow path. |
12119 | 3.63k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || |
12120 | 2.16k | unicode::has_tabs_or_newline(input))) { |
12121 | 112 | return false; |
12122 | 112 | } |
12123 | | |
12124 | 3.52k | out.type = scheme_type; |
12125 | 3.52k | out.is_valid = true; |
12126 | 3.52k | out.has_opaque_path = false; |
12127 | 3.52k | out.host_type = DEFAULT; |
12128 | | |
12129 | 3.52k | const uint32_t port_bytes = (parsed_port != url_components::omitted) |
12130 | 3.52k | ? (1 + port_decimal_digit_count(parsed_port)) |
12131 | 3.52k | : 0; |
12132 | | |
12133 | 3.52k | if (!rest_simple) { |
12134 | 2.11k | const std::string_view path_view = |
12135 | 2.11k | has_path |
12136 | 2.11k | ? std::string_view(input.data() + path_start, path_end - path_start) |
12137 | 2.11k | : std::string_view{}; |
12138 | 2.11k | auto apply_query_and_hash = [&]() { |
12139 | 2.11k | if (query_start != std::string_view::npos) { |
12140 | 168 | const size_t q_end = |
12141 | 168 | (hash_start != std::string_view::npos) ? hash_start : len; |
12142 | 168 | out.update_base_search(std::string_view(input.data() + query_start + 1, |
12143 | 168 | q_end - query_start - 1), |
12144 | 168 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); |
12145 | 168 | } |
12146 | 2.11k | if (hash_start != std::string_view::npos) { |
12147 | 146 | out.update_unencoded_base_hash(std::string_view( |
12148 | 146 | input.data() + hash_start + 1, len - hash_start - 1)); |
12149 | 146 | } |
12150 | 2.11k | }; ada::parser::finish_simple_absolute_with_port<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url&, ada::scheme::type, unsigned int, unsigned long, unsigned long, unsigned long, bool)::{lambda()#1}::operator()() constLine | Count | Source | 12138 | 1.05k | auto apply_query_and_hash = [&]() { | 12139 | 1.05k | if (query_start != std::string_view::npos) { | 12140 | 84 | const size_t q_end = | 12141 | 84 | (hash_start != std::string_view::npos) ? hash_start : len; | 12142 | 84 | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12143 | 84 | q_end - query_start - 1), | 12144 | 84 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12145 | 84 | } | 12146 | 1.05k | if (hash_start != std::string_view::npos) { | 12147 | 73 | out.update_unencoded_base_hash(std::string_view( | 12148 | 73 | input.data() + hash_start + 1, len - hash_start - 1)); | 12149 | 73 | } | 12150 | 1.05k | }; |
ada::parser::finish_simple_absolute_with_port<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator&, ada::scheme::type, unsigned int, unsigned long, unsigned long, unsigned long, bool)::{lambda()#1}::operator()() constLine | Count | Source | 12138 | 1.05k | auto apply_query_and_hash = [&]() { | 12139 | 1.05k | if (query_start != std::string_view::npos) { | 12140 | 84 | const size_t q_end = | 12141 | 84 | (hash_start != std::string_view::npos) ? hash_start : len; | 12142 | 84 | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12143 | 84 | q_end - query_start - 1), | 12144 | 84 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12145 | 84 | } | 12146 | 1.05k | if (hash_start != std::string_view::npos) { | 12147 | 73 | out.update_unencoded_base_hash(std::string_view( | 12148 | 73 | input.data() + hash_start + 1, len - hash_start - 1)); | 12149 | 73 | } | 12150 | 1.05k | }; |
|
12151 | 2.11k | if constexpr (is_aggregator) { |
12152 | 1.05k | out.buffer.assign(input.substr(0, host_end)); |
12153 | 1.05k | if (parsed_port != url_components::omitted) { |
12154 | 577 | append_canonical_port(out.buffer, parsed_port); |
12155 | 577 | } |
12156 | 1.05k | if (has_upper) { |
12157 | 150 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); |
12158 | 150 | } |
12159 | 1.05k | out.components.protocol_end = protocol_end; |
12160 | 1.05k | out.components.username_end = protocol_end + 2; |
12161 | 1.05k | out.components.host_start = protocol_end + 2; |
12162 | 1.05k | out.components.host_end = static_cast<uint32_t>(host_end); |
12163 | 1.05k | out.components.port = parsed_port; |
12164 | 1.05k | out.components.pathname_start = static_cast<uint32_t>(out.buffer.size()); |
12165 | 1.05k | out.components.search_start = url_components::omitted; |
12166 | 1.05k | out.components.hash_start = url_components::omitted; |
12167 | 1.05k | out.parse_path(path_view); |
12168 | 1.05k | apply_query_and_hash(); |
12169 | 1.05k | } else { |
12170 | 1.05k | std::string host_str(input.substr(host_start, host_len)); |
12171 | 1.05k | if (has_upper) { |
12172 | 150 | unicode::to_lower_ascii(host_str.data(), host_str.size()); |
12173 | 150 | } |
12174 | 1.05k | out.host = std::move(host_str); |
12175 | 1.05k | if (parsed_port != url_components::omitted) { |
12176 | 577 | out.port = static_cast<uint16_t>(parsed_port); |
12177 | 577 | } |
12178 | 1.05k | out.parse_path(path_view); |
12179 | 1.05k | apply_query_and_hash(); |
12180 | 1.05k | } |
12181 | 2.11k | return true; |
12182 | 2.11k | } |
12183 | | |
12184 | 1.41k | const bool insert_slash = !has_path; |
12185 | 1.41k | if constexpr (is_aggregator) { |
12186 | 707 | const size_t out_len = |
12187 | 707 | host_end + port_bytes + (insert_slash ? 1 : 0) + (len - authority_end); |
12188 | 707 | const bool omit_port_bytes = parsed_port == url_components::omitted; |
12189 | 707 | if (out_len == len && !insert_slash && !omit_port_bytes) { |
12190 | 522 | out.buffer.assign(input); |
12191 | 522 | } else { |
12192 | 185 | out.buffer.clear(); |
12193 | 185 | out.buffer.reserve(out_len); |
12194 | 185 | out.buffer.append(input.substr(0, host_end)); |
12195 | 185 | if (parsed_port != url_components::omitted) { |
12196 | 87 | append_canonical_port(out.buffer, parsed_port); |
12197 | 87 | } |
12198 | 185 | if (insert_slash) { |
12199 | 147 | out.buffer.push_back('/'); |
12200 | 147 | } |
12201 | 185 | if (authority_end < len) { |
12202 | 110 | out.buffer.append(input.substr(authority_end)); |
12203 | 110 | } |
12204 | 185 | } |
12205 | 707 | if (has_upper) { |
12206 | 88 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); |
12207 | 88 | } |
12208 | 707 | const uint32_t pathname_start = |
12209 | 707 | static_cast<uint32_t>(host_end) + port_bytes; |
12210 | 707 | const int32_t tail_delta = static_cast<int32_t>(pathname_start) + |
12211 | 707 | (insert_slash ? 1 : 0) - |
12212 | 707 | static_cast<int32_t>(authority_end); |
12213 | 707 | out.components.protocol_end = protocol_end; |
12214 | 707 | out.components.username_end = protocol_end + 2; |
12215 | 707 | out.components.host_start = protocol_end + 2; |
12216 | 707 | out.components.host_end = static_cast<uint32_t>(host_end); |
12217 | 707 | out.components.port = parsed_port; |
12218 | 707 | out.components.pathname_start = pathname_start; |
12219 | 707 | out.components.search_start = |
12220 | 707 | (query_start != std::string_view::npos) |
12221 | 707 | ? static_cast<uint32_t>(static_cast<int32_t>(query_start) + |
12222 | 176 | tail_delta) |
12223 | 707 | : url_components::omitted; |
12224 | 707 | out.components.hash_start = |
12225 | 707 | (hash_start != std::string_view::npos) |
12226 | 707 | ? static_cast<uint32_t>(static_cast<int32_t>(hash_start) + |
12227 | 169 | tail_delta) |
12228 | 707 | : url_components::omitted; |
12229 | 707 | } else { |
12230 | 707 | std::string host_str(input.substr(host_start, host_len)); |
12231 | 707 | if (has_upper) { |
12232 | 88 | unicode::to_lower_ascii(host_str.data(), host_str.size()); |
12233 | 88 | } |
12234 | 707 | out.host = std::move(host_str); |
12235 | 707 | if (parsed_port != url_components::omitted) { |
12236 | 609 | out.port = static_cast<uint16_t>(parsed_port); |
12237 | 609 | } |
12238 | 707 | if (insert_slash) { |
12239 | 147 | out.path = "/"; |
12240 | 560 | } else { |
12241 | 560 | out.path.assign(input.data() + path_start, path_end - path_start); |
12242 | 560 | } |
12243 | 707 | if (query_start != std::string_view::npos) { |
12244 | 176 | const size_t q_end = |
12245 | 176 | (hash_start != std::string_view::npos) ? hash_start : len; |
12246 | 176 | out.query.emplace(input.data() + query_start + 1, |
12247 | 176 | q_end - query_start - 1); |
12248 | 176 | } |
12249 | 707 | if (hash_start != std::string_view::npos) { |
12250 | 169 | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); |
12251 | 169 | } |
12252 | 707 | } |
12253 | 1.41k | return true; |
12254 | 3.52k | } bool ada::parser::finish_simple_absolute_with_port<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url&, ada::scheme::type, unsigned int, unsigned long, unsigned long, unsigned long, bool) Line | Count | Source | 11990 | 1.88k | bool has_upper) { | 11991 | 1.88k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 11992 | 1.88k | constexpr bool is_aggregator = | 11993 | 1.88k | std::is_same_v<result_type, ada::url_aggregator>; | 11994 | 1.88k | static_assert(is_ada_url || is_aggregator); | 11995 | | | 11996 | 1.88k | const size_t len = input.size(); | 11997 | 1.88k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 11998 | 1.88k | size_t p = host_end + 1; | 11999 | 1.88k | uint32_t port_value = 0; | 12000 | 1.88k | bool any_digit = false; | 12001 | 4.07k | while (p < len && b[p] >= '0' && b[p] <= '9') { | 12002 | 2.20k | any_digit = true; | 12003 | 2.20k | port_value = port_value * 10 + static_cast<uint32_t>(b[p] - '0'); | 12004 | 2.20k | if (port_value > 65535) [[unlikely]] { | 12005 | 11 | return false; | 12006 | 11 | } | 12007 | 2.19k | ++p; | 12008 | 2.19k | } | 12009 | 1.86k | if (p < len && b[p] != '/' && b[p] != '?' && b[p] != '#') [[unlikely]] { | 12010 | 51 | return false; | 12011 | 51 | } | 12012 | 1.81k | uint32_t parsed_port = url_components::omitted; | 12013 | 1.81k | const uint16_t default_port = ada::scheme::get_special_port(scheme_type); | 12014 | 1.81k | if (any_digit && port_value != default_port) { | 12015 | 1.19k | parsed_port = port_value; | 12016 | 1.19k | } | 12017 | 1.81k | const size_t authority_end = p; | 12018 | | | 12019 | 1.81k | size_t i = authority_end; | 12020 | 1.81k | size_t path_start = host_end; | 12021 | 1.81k | size_t path_end = host_end; | 12022 | 1.81k | size_t query_start = std::string_view::npos; | 12023 | 1.81k | size_t hash_start = std::string_view::npos; | 12024 | 1.81k | bool has_path = false; | 12025 | 1.81k | bool maybe_dot_segment = false; | 12026 | 1.81k | bool rest_simple = true; | 12027 | | | 12028 | 1.81k | if (i < len && b[i] == '/') { | 12029 | 1.60k | has_path = true; | 12030 | 1.60k | path_start = i; | 12031 | 1.60k | ++i; | 12032 | 1.60k | scan_path_run(b, i, len, maybe_dot_segment); | 12033 | 1.60k | if (i < len) { | 12034 | 1.01k | const uint8_t cls = k_path[b[i]]; | 12035 | 1.01k | if (cls == 1) { | 12036 | 224 | path_end = i; | 12037 | 224 | if (b[i] == '?') { | 12038 | 143 | query_start = i; | 12039 | 143 | ++i; | 12040 | 143 | goto scan_query; | 12041 | 143 | } | 12042 | 81 | hash_start = i; | 12043 | 81 | ++i; | 12044 | 81 | goto scan_hash; | 12045 | 224 | } | 12046 | 789 | rest_simple = false; | 12047 | 24.6k | for (; i < len; ++i) { | 12048 | 23.9k | if (b[i] == '?') { | 12049 | 54 | path_end = i; | 12050 | 54 | query_start = i; | 12051 | 54 | ++i; | 12052 | 54 | goto scan_query_boundary; | 12053 | 54 | } | 12054 | 23.9k | if (b[i] == '#') { | 12055 | 17 | path_end = i; | 12056 | 17 | hash_start = i; | 12057 | 17 | ++i; | 12058 | 17 | goto after_rest; | 12059 | 17 | } | 12060 | 23.9k | } | 12061 | 718 | path_end = i; | 12062 | 718 | goto after_rest; | 12063 | 789 | } | 12064 | 589 | path_end = i; | 12065 | 589 | } else if (i < len && b[i] == '?') { | 12066 | 73 | query_start = i; | 12067 | 73 | ++i; | 12068 | 73 | goto scan_query; | 12069 | 143 | } else if (i < len && b[i] == '#') { | 12070 | 68 | hash_start = i; | 12071 | 68 | ++i; | 12072 | 68 | goto scan_hash; | 12073 | 68 | } | 12074 | 664 | goto after_rest; | 12075 | | | 12076 | 664 | scan_query: | 12077 | 216 | scan_query_run(b, i, len); | 12078 | 216 | if (i < len) { | 12079 | 111 | if (b[i] == '#') { | 12080 | 76 | hash_start = i; | 12081 | 76 | ++i; | 12082 | 76 | goto scan_hash; | 12083 | 76 | } | 12084 | 35 | rest_simple = false; | 12085 | 35 | goto scan_query_boundary; | 12086 | 111 | } | 12087 | 105 | goto after_rest; | 12088 | | | 12089 | 105 | scan_query_boundary: | 12090 | 1.46k | for (; i < len; ++i) { | 12091 | 1.39k | if (b[i] == '#') { | 12092 | 21 | hash_start = i; | 12093 | 21 | ++i; | 12094 | 21 | goto after_rest; | 12095 | 21 | } | 12096 | 1.39k | } | 12097 | 68 | goto after_rest; | 12098 | | | 12099 | 225 | scan_hash: | 12100 | 225 | scan_hash_run(b, i, len); | 12101 | 225 | if (i < len) { | 12102 | 56 | rest_simple = false; | 12103 | 56 | } | 12104 | | | 12105 | 1.81k | after_rest: | 12106 | 1.81k | if (rest_simple && maybe_dot_segment) { | 12107 | 343 | const std::string_view path_body(input.data() + path_start, | 12108 | 343 | path_end - path_start); | 12109 | 343 | if (path_has_dot_segment(path_body)) { | 12110 | 231 | rest_simple = false; | 12111 | 231 | } | 12112 | 343 | } | 12113 | | | 12114 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a | 12115 | | // trailing C0 control or space; this fast path does neither. A query or | 12116 | | // fragment reaching the helpers below would keep those bytes percent-encoded | 12117 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such | 12118 | | // inputs back to the slow path. | 12119 | 1.81k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || | 12120 | 1.08k | unicode::has_tabs_or_newline(input))) { | 12121 | 56 | return false; | 12122 | 56 | } | 12123 | | | 12124 | 1.76k | out.type = scheme_type; | 12125 | 1.76k | out.is_valid = true; | 12126 | 1.76k | out.has_opaque_path = false; | 12127 | 1.76k | out.host_type = DEFAULT; | 12128 | | | 12129 | 1.76k | const uint32_t port_bytes = (parsed_port != url_components::omitted) | 12130 | 1.76k | ? (1 + port_decimal_digit_count(parsed_port)) | 12131 | 1.76k | : 0; | 12132 | | | 12133 | 1.76k | if (!rest_simple) { | 12134 | 1.05k | const std::string_view path_view = | 12135 | 1.05k | has_path | 12136 | 1.05k | ? std::string_view(input.data() + path_start, path_end - path_start) | 12137 | 1.05k | : std::string_view{}; | 12138 | 1.05k | auto apply_query_and_hash = [&]() { | 12139 | 1.05k | if (query_start != std::string_view::npos) { | 12140 | 1.05k | const size_t q_end = | 12141 | 1.05k | (hash_start != std::string_view::npos) ? hash_start : len; | 12142 | 1.05k | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12143 | 1.05k | q_end - query_start - 1), | 12144 | 1.05k | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12145 | 1.05k | } | 12146 | 1.05k | if (hash_start != std::string_view::npos) { | 12147 | 1.05k | out.update_unencoded_base_hash(std::string_view( | 12148 | 1.05k | input.data() + hash_start + 1, len - hash_start - 1)); | 12149 | 1.05k | } | 12150 | 1.05k | }; | 12151 | | if constexpr (is_aggregator) { | 12152 | | out.buffer.assign(input.substr(0, host_end)); | 12153 | | if (parsed_port != url_components::omitted) { | 12154 | | append_canonical_port(out.buffer, parsed_port); | 12155 | | } | 12156 | | if (has_upper) { | 12157 | | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12158 | | } | 12159 | | out.components.protocol_end = protocol_end; | 12160 | | out.components.username_end = protocol_end + 2; | 12161 | | out.components.host_start = protocol_end + 2; | 12162 | | out.components.host_end = static_cast<uint32_t>(host_end); | 12163 | | out.components.port = parsed_port; | 12164 | | out.components.pathname_start = static_cast<uint32_t>(out.buffer.size()); | 12165 | | out.components.search_start = url_components::omitted; | 12166 | | out.components.hash_start = url_components::omitted; | 12167 | | out.parse_path(path_view); | 12168 | | apply_query_and_hash(); | 12169 | 1.05k | } else { | 12170 | 1.05k | std::string host_str(input.substr(host_start, host_len)); | 12171 | 1.05k | if (has_upper) { | 12172 | 150 | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12173 | 150 | } | 12174 | 1.05k | out.host = std::move(host_str); | 12175 | 1.05k | if (parsed_port != url_components::omitted) { | 12176 | 577 | out.port = static_cast<uint16_t>(parsed_port); | 12177 | 577 | } | 12178 | 1.05k | out.parse_path(path_view); | 12179 | 1.05k | apply_query_and_hash(); | 12180 | 1.05k | } | 12181 | 1.05k | return true; | 12182 | 1.05k | } | 12183 | | | 12184 | 707 | const bool insert_slash = !has_path; | 12185 | | if constexpr (is_aggregator) { | 12186 | | const size_t out_len = | 12187 | | host_end + port_bytes + (insert_slash ? 1 : 0) + (len - authority_end); | 12188 | | const bool omit_port_bytes = parsed_port == url_components::omitted; | 12189 | | if (out_len == len && !insert_slash && !omit_port_bytes) { | 12190 | | out.buffer.assign(input); | 12191 | | } else { | 12192 | | out.buffer.clear(); | 12193 | | out.buffer.reserve(out_len); | 12194 | | out.buffer.append(input.substr(0, host_end)); | 12195 | | if (parsed_port != url_components::omitted) { | 12196 | | append_canonical_port(out.buffer, parsed_port); | 12197 | | } | 12198 | | if (insert_slash) { | 12199 | | out.buffer.push_back('/'); | 12200 | | } | 12201 | | if (authority_end < len) { | 12202 | | out.buffer.append(input.substr(authority_end)); | 12203 | | } | 12204 | | } | 12205 | | if (has_upper) { | 12206 | | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12207 | | } | 12208 | | const uint32_t pathname_start = | 12209 | | static_cast<uint32_t>(host_end) + port_bytes; | 12210 | | const int32_t tail_delta = static_cast<int32_t>(pathname_start) + | 12211 | | (insert_slash ? 1 : 0) - | 12212 | | static_cast<int32_t>(authority_end); | 12213 | | out.components.protocol_end = protocol_end; | 12214 | | out.components.username_end = protocol_end + 2; | 12215 | | out.components.host_start = protocol_end + 2; | 12216 | | out.components.host_end = static_cast<uint32_t>(host_end); | 12217 | | out.components.port = parsed_port; | 12218 | | out.components.pathname_start = pathname_start; | 12219 | | out.components.search_start = | 12220 | | (query_start != std::string_view::npos) | 12221 | | ? static_cast<uint32_t>(static_cast<int32_t>(query_start) + | 12222 | | tail_delta) | 12223 | | : url_components::omitted; | 12224 | | out.components.hash_start = | 12225 | | (hash_start != std::string_view::npos) | 12226 | | ? static_cast<uint32_t>(static_cast<int32_t>(hash_start) + | 12227 | | tail_delta) | 12228 | | : url_components::omitted; | 12229 | 707 | } else { | 12230 | 707 | std::string host_str(input.substr(host_start, host_len)); | 12231 | 707 | if (has_upper) { | 12232 | 88 | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12233 | 88 | } | 12234 | 707 | out.host = std::move(host_str); | 12235 | 707 | if (parsed_port != url_components::omitted) { | 12236 | 609 | out.port = static_cast<uint16_t>(parsed_port); | 12237 | 609 | } | 12238 | 707 | if (insert_slash) { | 12239 | 147 | out.path = "/"; | 12240 | 560 | } else { | 12241 | 560 | out.path.assign(input.data() + path_start, path_end - path_start); | 12242 | 560 | } | 12243 | 707 | if (query_start != std::string_view::npos) { | 12244 | 176 | const size_t q_end = | 12245 | 176 | (hash_start != std::string_view::npos) ? hash_start : len; | 12246 | 176 | out.query.emplace(input.data() + query_start + 1, | 12247 | 176 | q_end - query_start - 1); | 12248 | 176 | } | 12249 | 707 | if (hash_start != std::string_view::npos) { | 12250 | 169 | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); | 12251 | 169 | } | 12252 | 707 | } | 12253 | 707 | return true; | 12254 | 1.76k | } |
bool ada::parser::finish_simple_absolute_with_port<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator&, ada::scheme::type, unsigned int, unsigned long, unsigned long, unsigned long, bool) Line | Count | Source | 11990 | 1.88k | bool has_upper) { | 11991 | 1.88k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 11992 | 1.88k | constexpr bool is_aggregator = | 11993 | 1.88k | std::is_same_v<result_type, ada::url_aggregator>; | 11994 | 1.88k | static_assert(is_ada_url || is_aggregator); | 11995 | | | 11996 | 1.88k | const size_t len = input.size(); | 11997 | 1.88k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 11998 | 1.88k | size_t p = host_end + 1; | 11999 | 1.88k | uint32_t port_value = 0; | 12000 | 1.88k | bool any_digit = false; | 12001 | 4.07k | while (p < len && b[p] >= '0' && b[p] <= '9') { | 12002 | 2.20k | any_digit = true; | 12003 | 2.20k | port_value = port_value * 10 + static_cast<uint32_t>(b[p] - '0'); | 12004 | 2.20k | if (port_value > 65535) [[unlikely]] { | 12005 | 11 | return false; | 12006 | 11 | } | 12007 | 2.19k | ++p; | 12008 | 2.19k | } | 12009 | 1.86k | if (p < len && b[p] != '/' && b[p] != '?' && b[p] != '#') [[unlikely]] { | 12010 | 51 | return false; | 12011 | 51 | } | 12012 | 1.81k | uint32_t parsed_port = url_components::omitted; | 12013 | 1.81k | const uint16_t default_port = ada::scheme::get_special_port(scheme_type); | 12014 | 1.81k | if (any_digit && port_value != default_port) { | 12015 | 1.19k | parsed_port = port_value; | 12016 | 1.19k | } | 12017 | 1.81k | const size_t authority_end = p; | 12018 | | | 12019 | 1.81k | size_t i = authority_end; | 12020 | 1.81k | size_t path_start = host_end; | 12021 | 1.81k | size_t path_end = host_end; | 12022 | 1.81k | size_t query_start = std::string_view::npos; | 12023 | 1.81k | size_t hash_start = std::string_view::npos; | 12024 | 1.81k | bool has_path = false; | 12025 | 1.81k | bool maybe_dot_segment = false; | 12026 | 1.81k | bool rest_simple = true; | 12027 | | | 12028 | 1.81k | if (i < len && b[i] == '/') { | 12029 | 1.60k | has_path = true; | 12030 | 1.60k | path_start = i; | 12031 | 1.60k | ++i; | 12032 | 1.60k | scan_path_run(b, i, len, maybe_dot_segment); | 12033 | 1.60k | if (i < len) { | 12034 | 1.01k | const uint8_t cls = k_path[b[i]]; | 12035 | 1.01k | if (cls == 1) { | 12036 | 224 | path_end = i; | 12037 | 224 | if (b[i] == '?') { | 12038 | 143 | query_start = i; | 12039 | 143 | ++i; | 12040 | 143 | goto scan_query; | 12041 | 143 | } | 12042 | 81 | hash_start = i; | 12043 | 81 | ++i; | 12044 | 81 | goto scan_hash; | 12045 | 224 | } | 12046 | 789 | rest_simple = false; | 12047 | 24.6k | for (; i < len; ++i) { | 12048 | 23.9k | if (b[i] == '?') { | 12049 | 54 | path_end = i; | 12050 | 54 | query_start = i; | 12051 | 54 | ++i; | 12052 | 54 | goto scan_query_boundary; | 12053 | 54 | } | 12054 | 23.9k | if (b[i] == '#') { | 12055 | 17 | path_end = i; | 12056 | 17 | hash_start = i; | 12057 | 17 | ++i; | 12058 | 17 | goto after_rest; | 12059 | 17 | } | 12060 | 23.9k | } | 12061 | 718 | path_end = i; | 12062 | 718 | goto after_rest; | 12063 | 789 | } | 12064 | 589 | path_end = i; | 12065 | 589 | } else if (i < len && b[i] == '?') { | 12066 | 73 | query_start = i; | 12067 | 73 | ++i; | 12068 | 73 | goto scan_query; | 12069 | 143 | } else if (i < len && b[i] == '#') { | 12070 | 68 | hash_start = i; | 12071 | 68 | ++i; | 12072 | 68 | goto scan_hash; | 12073 | 68 | } | 12074 | 664 | goto after_rest; | 12075 | | | 12076 | 664 | scan_query: | 12077 | 216 | scan_query_run(b, i, len); | 12078 | 216 | if (i < len) { | 12079 | 111 | if (b[i] == '#') { | 12080 | 76 | hash_start = i; | 12081 | 76 | ++i; | 12082 | 76 | goto scan_hash; | 12083 | 76 | } | 12084 | 35 | rest_simple = false; | 12085 | 35 | goto scan_query_boundary; | 12086 | 111 | } | 12087 | 105 | goto after_rest; | 12088 | | | 12089 | 105 | scan_query_boundary: | 12090 | 1.46k | for (; i < len; ++i) { | 12091 | 1.39k | if (b[i] == '#') { | 12092 | 21 | hash_start = i; | 12093 | 21 | ++i; | 12094 | 21 | goto after_rest; | 12095 | 21 | } | 12096 | 1.39k | } | 12097 | 68 | goto after_rest; | 12098 | | | 12099 | 225 | scan_hash: | 12100 | 225 | scan_hash_run(b, i, len); | 12101 | 225 | if (i < len) { | 12102 | 56 | rest_simple = false; | 12103 | 56 | } | 12104 | | | 12105 | 1.81k | after_rest: | 12106 | 1.81k | if (rest_simple && maybe_dot_segment) { | 12107 | 343 | const std::string_view path_body(input.data() + path_start, | 12108 | 343 | path_end - path_start); | 12109 | 343 | if (path_has_dot_segment(path_body)) { | 12110 | 231 | rest_simple = false; | 12111 | 231 | } | 12112 | 343 | } | 12113 | | | 12114 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a | 12115 | | // trailing C0 control or space; this fast path does neither. A query or | 12116 | | // fragment reaching the helpers below would keep those bytes percent-encoded | 12117 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such | 12118 | | // inputs back to the slow path. | 12119 | 1.81k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || | 12120 | 1.08k | unicode::has_tabs_or_newline(input))) { | 12121 | 56 | return false; | 12122 | 56 | } | 12123 | | | 12124 | 1.76k | out.type = scheme_type; | 12125 | 1.76k | out.is_valid = true; | 12126 | 1.76k | out.has_opaque_path = false; | 12127 | 1.76k | out.host_type = DEFAULT; | 12128 | | | 12129 | 1.76k | const uint32_t port_bytes = (parsed_port != url_components::omitted) | 12130 | 1.76k | ? (1 + port_decimal_digit_count(parsed_port)) | 12131 | 1.76k | : 0; | 12132 | | | 12133 | 1.76k | if (!rest_simple) { | 12134 | 1.05k | const std::string_view path_view = | 12135 | 1.05k | has_path | 12136 | 1.05k | ? std::string_view(input.data() + path_start, path_end - path_start) | 12137 | 1.05k | : std::string_view{}; | 12138 | 1.05k | auto apply_query_and_hash = [&]() { | 12139 | 1.05k | if (query_start != std::string_view::npos) { | 12140 | 1.05k | const size_t q_end = | 12141 | 1.05k | (hash_start != std::string_view::npos) ? hash_start : len; | 12142 | 1.05k | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12143 | 1.05k | q_end - query_start - 1), | 12144 | 1.05k | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12145 | 1.05k | } | 12146 | 1.05k | if (hash_start != std::string_view::npos) { | 12147 | 1.05k | out.update_unencoded_base_hash(std::string_view( | 12148 | 1.05k | input.data() + hash_start + 1, len - hash_start - 1)); | 12149 | 1.05k | } | 12150 | 1.05k | }; | 12151 | 1.05k | if constexpr (is_aggregator) { | 12152 | 1.05k | out.buffer.assign(input.substr(0, host_end)); | 12153 | 1.05k | if (parsed_port != url_components::omitted) { | 12154 | 577 | append_canonical_port(out.buffer, parsed_port); | 12155 | 577 | } | 12156 | 1.05k | if (has_upper) { | 12157 | 150 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12158 | 150 | } | 12159 | 1.05k | out.components.protocol_end = protocol_end; | 12160 | 1.05k | out.components.username_end = protocol_end + 2; | 12161 | 1.05k | out.components.host_start = protocol_end + 2; | 12162 | 1.05k | out.components.host_end = static_cast<uint32_t>(host_end); | 12163 | 1.05k | out.components.port = parsed_port; | 12164 | 1.05k | out.components.pathname_start = static_cast<uint32_t>(out.buffer.size()); | 12165 | 1.05k | out.components.search_start = url_components::omitted; | 12166 | 1.05k | out.components.hash_start = url_components::omitted; | 12167 | 1.05k | out.parse_path(path_view); | 12168 | 1.05k | apply_query_and_hash(); | 12169 | | } else { | 12170 | | std::string host_str(input.substr(host_start, host_len)); | 12171 | | if (has_upper) { | 12172 | | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12173 | | } | 12174 | | out.host = std::move(host_str); | 12175 | | if (parsed_port != url_components::omitted) { | 12176 | | out.port = static_cast<uint16_t>(parsed_port); | 12177 | | } | 12178 | | out.parse_path(path_view); | 12179 | | apply_query_and_hash(); | 12180 | | } | 12181 | 1.05k | return true; | 12182 | 1.05k | } | 12183 | | | 12184 | 707 | const bool insert_slash = !has_path; | 12185 | 707 | if constexpr (is_aggregator) { | 12186 | 707 | const size_t out_len = | 12187 | 707 | host_end + port_bytes + (insert_slash ? 1 : 0) + (len - authority_end); | 12188 | 707 | const bool omit_port_bytes = parsed_port == url_components::omitted; | 12189 | 707 | if (out_len == len && !insert_slash && !omit_port_bytes) { | 12190 | 522 | out.buffer.assign(input); | 12191 | 522 | } else { | 12192 | 185 | out.buffer.clear(); | 12193 | 185 | out.buffer.reserve(out_len); | 12194 | 185 | out.buffer.append(input.substr(0, host_end)); | 12195 | 185 | if (parsed_port != url_components::omitted) { | 12196 | 87 | append_canonical_port(out.buffer, parsed_port); | 12197 | 87 | } | 12198 | 185 | if (insert_slash) { | 12199 | 147 | out.buffer.push_back('/'); | 12200 | 147 | } | 12201 | 185 | if (authority_end < len) { | 12202 | 110 | out.buffer.append(input.substr(authority_end)); | 12203 | 110 | } | 12204 | 185 | } | 12205 | 707 | if (has_upper) { | 12206 | 88 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12207 | 88 | } | 12208 | 707 | const uint32_t pathname_start = | 12209 | 707 | static_cast<uint32_t>(host_end) + port_bytes; | 12210 | 707 | const int32_t tail_delta = static_cast<int32_t>(pathname_start) + | 12211 | 707 | (insert_slash ? 1 : 0) - | 12212 | 707 | static_cast<int32_t>(authority_end); | 12213 | 707 | out.components.protocol_end = protocol_end; | 12214 | 707 | out.components.username_end = protocol_end + 2; | 12215 | 707 | out.components.host_start = protocol_end + 2; | 12216 | 707 | out.components.host_end = static_cast<uint32_t>(host_end); | 12217 | 707 | out.components.port = parsed_port; | 12218 | 707 | out.components.pathname_start = pathname_start; | 12219 | 707 | out.components.search_start = | 12220 | 707 | (query_start != std::string_view::npos) | 12221 | 707 | ? static_cast<uint32_t>(static_cast<int32_t>(query_start) + | 12222 | 176 | tail_delta) | 12223 | 707 | : url_components::omitted; | 12224 | 707 | out.components.hash_start = | 12225 | 707 | (hash_start != std::string_view::npos) | 12226 | 707 | ? static_cast<uint32_t>(static_cast<int32_t>(hash_start) + | 12227 | 169 | tail_delta) | 12228 | 707 | : url_components::omitted; | 12229 | | } else { | 12230 | | std::string host_str(input.substr(host_start, host_len)); | 12231 | | if (has_upper) { | 12232 | | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12233 | | } | 12234 | | out.host = std::move(host_str); | 12235 | | if (parsed_port != url_components::omitted) { | 12236 | | out.port = static_cast<uint16_t>(parsed_port); | 12237 | | } | 12238 | | if (insert_slash) { | 12239 | | out.path = "/"; | 12240 | | } else { | 12241 | | out.path.assign(input.data() + path_start, path_end - path_start); | 12242 | | } | 12243 | | if (query_start != std::string_view::npos) { | 12244 | | const size_t q_end = | 12245 | | (hash_start != std::string_view::npos) ? hash_start : len; | 12246 | | out.query.emplace(input.data() + query_start + 1, | 12247 | | q_end - query_start - 1); | 12248 | | } | 12249 | | if (hash_start != std::string_view::npos) { | 12250 | | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); | 12251 | | } | 12252 | | } | 12253 | 707 | return true; | 12254 | 1.76k | } |
|
12255 | | |
12256 | | // Fast path for already-canonical special-scheme URLs of the shape |
12257 | | // scheme://host[/path][?query][#fragment]. When the host is a plain domain |
12258 | | // but the rest needs encoding or dot-segment normalization, the host is |
12259 | | // kept and the path/query/hash helpers finish the URL. |
12260 | | template <class result_type> |
12261 | | ada_never_inline bool try_parse_simple_absolute(std::string_view input, |
12262 | 88.0k | result_type& out) { |
12263 | 88.0k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; |
12264 | 88.0k | constexpr bool is_aggregator = |
12265 | 88.0k | std::is_same_v<result_type, ada::url_aggregator>; |
12266 | 88.0k | static_assert(is_ada_url || is_aggregator); |
12267 | | |
12268 | 88.0k | const size_t len = input.size(); |
12269 | | // Shortest accepted form is "ws://x" (6). |
12270 | 88.0k | if (len < 6) [[unlikely]] { |
12271 | 49.1k | return false; |
12272 | 49.1k | } |
12273 | 38.9k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); |
12274 | | |
12275 | 38.9k | size_t pos = 0; |
12276 | 38.9k | ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL; |
12277 | 38.9k | uint32_t protocol_end = 0; |
12278 | 38.9k | #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ |
12279 | 38.9k | defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64) |
12280 | | // One 8-byte load + integer compare is a single cmp/jcc on x86-64. |
12281 | | // Masked compares cover the shorter special schemes without extra loads. |
12282 | 38.9k | if (len >= 8) { |
12283 | 33.6k | uint64_t first8 = 0; |
12284 | 33.6k | std::memcpy(&first8, b, 8); |
12285 | 33.6k | if (first8 == 0x2f2f3a7370747468ull) { // "https://" |
12286 | 16 | pos = 8; |
12287 | 16 | scheme_type = ada::scheme::type::HTTPS; |
12288 | 16 | protocol_end = 6; |
12289 | 33.6k | } else if ((first8 & 0x00ffffffffffffffull) == |
12290 | 33.6k | 0x002f2f3a70747468ull) { // "http://" |
12291 | 738 | pos = 7; |
12292 | 738 | scheme_type = ada::scheme::type::HTTP; |
12293 | 738 | protocol_end = 5; |
12294 | 32.9k | } else if ((first8 & 0x0000ffffffffffffull) == |
12295 | 32.9k | 0x00002f2f3a737377ull) { // "wss://" |
12296 | 116 | pos = 6; |
12297 | 116 | scheme_type = ada::scheme::type::WSS; |
12298 | 116 | protocol_end = 4; |
12299 | 32.7k | } else if ((first8 & 0x0000ffffffffffffull) == |
12300 | 32.7k | 0x00002f2f3a707466ull) { // "ftp://" |
12301 | 36 | pos = 6; |
12302 | 36 | scheme_type = ada::scheme::type::FTP; |
12303 | 36 | protocol_end = 4; |
12304 | 32.7k | } else if ((first8 & 0x000000ffffffffffull) == |
12305 | 32.7k | 0x0000002f2f3a7377ull) { // "ws://" |
12306 | 14.2k | pos = 5; |
12307 | 14.2k | scheme_type = ada::scheme::type::WS; |
12308 | 14.2k | protocol_end = 3; |
12309 | 18.4k | } else { |
12310 | 18.4k | return false; |
12311 | 18.4k | } |
12312 | 33.6k | } else if (b[0] == 'w' && b[1] == 's') { |
12313 | 2.73k | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { |
12314 | 1.02k | pos = 5; |
12315 | 1.02k | scheme_type = ada::scheme::type::WS; |
12316 | 1.02k | protocol_end = 3; |
12317 | 1.70k | } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') { |
12318 | 10 | pos = 6; |
12319 | 10 | scheme_type = ada::scheme::type::WSS; |
12320 | 10 | protocol_end = 4; |
12321 | 1.69k | } else { |
12322 | 1.69k | return false; |
12323 | 1.69k | } |
12324 | 2.73k | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && |
12325 | 44 | b[4] == '/' && b[5] == '/') { |
12326 | 6 | pos = 6; |
12327 | 6 | scheme_type = ada::scheme::type::FTP; |
12328 | 6 | protocol_end = 4; |
12329 | 2.53k | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && |
12330 | 118 | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { |
12331 | 6 | pos = 7; |
12332 | 6 | scheme_type = ada::scheme::type::HTTP; |
12333 | 6 | protocol_end = 5; |
12334 | 2.53k | } else { |
12335 | 2.53k | return false; |
12336 | 2.53k | } |
12337 | | #else |
12338 | | // Big-endian / uncommon arches: byte-wise special-scheme match. |
12339 | | if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' && |
12340 | | b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') { |
12341 | | pos = 8; |
12342 | | scheme_type = ada::scheme::type::HTTPS; |
12343 | | protocol_end = 6; |
12344 | | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && |
12345 | | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { |
12346 | | pos = 7; |
12347 | | scheme_type = ada::scheme::type::HTTP; |
12348 | | protocol_end = 5; |
12349 | | } else if (b[0] == 'w' && b[1] == 's') { |
12350 | | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { |
12351 | | pos = 5; |
12352 | | scheme_type = ada::scheme::type::WS; |
12353 | | protocol_end = 3; |
12354 | | } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' && |
12355 | | b[5] == '/') { |
12356 | | pos = 6; |
12357 | | scheme_type = ada::scheme::type::WSS; |
12358 | | protocol_end = 4; |
12359 | | } else { |
12360 | | return false; |
12361 | | } |
12362 | | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && |
12363 | | b[4] == '/' && b[5] == '/') { |
12364 | | pos = 6; |
12365 | | scheme_type = ada::scheme::type::FTP; |
12366 | | protocol_end = 4; |
12367 | | } else { |
12368 | | return false; |
12369 | | } |
12370 | | #endif |
12371 | 16.2k | if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] { |
12372 | 34 | return false; |
12373 | 34 | } |
12374 | | |
12375 | | // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning. |
12376 | 16.1k | if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) { |
12377 | 2.31k | return false; |
12378 | 2.31k | } |
12379 | | |
12380 | 13.8k | const size_t host_start = pos; |
12381 | 13.8k | bool has_upper = false; |
12382 | 13.8k | bool has_x = false; |
12383 | 13.8k | size_t host_end = pos; |
12384 | 13.8k | if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) { |
12385 | 490 | return false; |
12386 | 490 | } |
12387 | 13.3k | if (host_start == host_end) [[unlikely]] { |
12388 | 96 | return false; |
12389 | 96 | } |
12390 | 13.3k | const size_t host_len = host_end - host_start; |
12391 | 13.3k | if (host_len > 253) [[unlikely]] { |
12392 | 176 | return false; |
12393 | 176 | } |
12394 | 13.1k | { |
12395 | 13.1k | std::string_view hv(input.data() + host_start, host_len); |
12396 | 13.1k | char host_buf[256]; |
12397 | 13.1k | if (has_upper) [[unlikely]] { |
12398 | 1.12k | std::memcpy(host_buf, input.data() + host_start, host_len); |
12399 | 1.12k | unicode::to_lower_ascii(host_buf, host_len); |
12400 | 1.12k | hv = std::string_view(host_buf, host_len); |
12401 | 1.12k | } |
12402 | 13.1k | if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] { |
12403 | 170 | return false; |
12404 | 170 | } |
12405 | | // Punycode is "xn--...". The host scan already notes a lowercase 'x'; |
12406 | | // uppercase 'X' is covered by has_upper after the in-place lower. |
12407 | 12.9k | static constexpr std::string_view xn{"xn-", 3}; |
12408 | 12.9k | if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos) |
12409 | 2.64k | [[unlikely]] { |
12410 | 2.64k | return false; |
12411 | 2.64k | } |
12412 | 12.9k | } |
12413 | | |
12414 | 10.3k | if (host_end < len && b[host_end] == ':') [[unlikely]] { |
12415 | 3.76k | return finish_simple_absolute_with_port(input, out, scheme_type, |
12416 | 3.76k | protocol_end, host_start, host_end, |
12417 | 3.76k | host_len, has_upper); |
12418 | 3.76k | } |
12419 | | |
12420 | 6.54k | size_t i = host_end; |
12421 | 6.54k | size_t path_start = host_end; |
12422 | 6.54k | size_t path_end = host_end; |
12423 | 6.54k | size_t query_start = std::string_view::npos; |
12424 | 6.54k | size_t hash_start = std::string_view::npos; |
12425 | 6.54k | bool has_path = false; |
12426 | 6.54k | bool maybe_dot_segment = false; |
12427 | 6.54k | bool rest_simple = true; |
12428 | | |
12429 | 6.54k | if (i < len && b[i] == '/') { |
12430 | 5.94k | has_path = true; |
12431 | 5.94k | path_start = i; |
12432 | 5.94k | ++i; |
12433 | 5.94k | scan_path_run(b, i, len, maybe_dot_segment); |
12434 | 5.94k | if (i < len) { |
12435 | 2.59k | const uint8_t cls = k_path[b[i]]; |
12436 | 2.59k | if (cls == 1) { |
12437 | 738 | path_end = i; |
12438 | 738 | if (b[i] == '?') { |
12439 | 444 | query_start = i; |
12440 | 444 | ++i; |
12441 | 444 | goto scan_query; |
12442 | 444 | } |
12443 | 294 | hash_start = i; |
12444 | 294 | ++i; |
12445 | 294 | goto scan_hash; |
12446 | 738 | } |
12447 | 1.85k | rest_simple = false; |
12448 | 1.85k | hash_start = input.find('#', i); |
12449 | 1.85k | query_start = input.substr(0, hash_start).find('?', i); |
12450 | 1.85k | if (query_start != std::string_view::npos) { |
12451 | 112 | path_end = query_start; |
12452 | 1.74k | } else { |
12453 | 1.74k | path_end = hash_start != std::string_view::npos ? hash_start : len; |
12454 | 1.74k | } |
12455 | 1.85k | goto after_rest; |
12456 | 2.59k | } |
12457 | 3.35k | path_end = i; |
12458 | 3.35k | } else if (i < len && b[i] == '?') { |
12459 | 138 | query_start = i; |
12460 | 138 | ++i; |
12461 | 138 | goto scan_query; |
12462 | 460 | } else if (i < len && b[i] == '#') { |
12463 | 142 | hash_start = i; |
12464 | 142 | ++i; |
12465 | 142 | goto scan_hash; |
12466 | 142 | } |
12467 | 3.67k | goto after_rest; |
12468 | | |
12469 | 3.67k | scan_query: |
12470 | 582 | scan_query_run(b, i, len); |
12471 | 582 | if (i < len) { |
12472 | 296 | if (b[i] == '#') { |
12473 | 204 | hash_start = i; |
12474 | 204 | ++i; |
12475 | 204 | goto scan_hash; |
12476 | 204 | } |
12477 | 92 | rest_simple = false; |
12478 | 92 | goto scan_query_boundary; |
12479 | 296 | } |
12480 | 286 | goto after_rest; |
12481 | | |
12482 | 286 | scan_query_boundary: |
12483 | 92 | hash_start = input.find('#', i); |
12484 | 92 | goto after_rest; |
12485 | | |
12486 | 640 | scan_hash: |
12487 | 640 | scan_hash_run(b, i, len); |
12488 | 640 | if (i < len) { |
12489 | 120 | rest_simple = false; |
12490 | 120 | } |
12491 | | |
12492 | 6.54k | after_rest: |
12493 | 6.54k | if (rest_simple && maybe_dot_segment) { |
12494 | 716 | const std::string_view path_body(input.data() + path_start, |
12495 | 716 | path_end - path_start); |
12496 | 716 | if (path_has_dot_segment(path_body)) { |
12497 | 304 | rest_simple = false; |
12498 | 304 | } |
12499 | 716 | } |
12500 | | |
12501 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a |
12502 | | // trailing C0 control or space; this fast path does neither. A query or |
12503 | | // fragment reaching the helpers below would keep those bytes percent-encoded |
12504 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such |
12505 | | // inputs back to the slow path. |
12506 | 6.54k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || |
12507 | 2.32k | unicode::has_tabs_or_newline(input))) { |
12508 | 84 | return false; |
12509 | 84 | } |
12510 | | |
12511 | 6.46k | out.type = scheme_type; |
12512 | 6.46k | out.is_valid = true; |
12513 | 6.46k | out.has_opaque_path = false; |
12514 | 6.46k | out.host_type = DEFAULT; |
12515 | | |
12516 | 6.46k | if (!rest_simple) { |
12517 | | // Host is a plain domain. Finish path/query/hash with |
12518 | | // the regular helpers |
12519 | | // so percent-encoding and dot segments do not re-parse the authority. |
12520 | 2.28k | const std::string_view path_view = |
12521 | 2.28k | has_path |
12522 | 2.28k | ? std::string_view(input.data() + path_start, path_end - path_start) |
12523 | 2.28k | : std::string_view{}; |
12524 | 2.28k | auto apply_query_and_hash = [&]() { |
12525 | 2.28k | if (query_start != std::string_view::npos) { |
12526 | 202 | const size_t q_end = |
12527 | 202 | (hash_start != std::string_view::npos) ? hash_start : len; |
12528 | 202 | out.update_base_search(std::string_view(input.data() + query_start + 1, |
12529 | 202 | q_end - query_start - 1), |
12530 | 202 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); |
12531 | 202 | } |
12532 | 2.28k | if (hash_start != std::string_view::npos) { |
12533 | 194 | out.update_unencoded_base_hash(std::string_view( |
12534 | 194 | input.data() + hash_start + 1, len - hash_start - 1)); |
12535 | 194 | } |
12536 | 2.28k | }; ada::parser::try_parse_simple_absolute<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url&)::{lambda()#1}::operator()() constLine | Count | Source | 12524 | 1.14k | auto apply_query_and_hash = [&]() { | 12525 | 1.14k | if (query_start != std::string_view::npos) { | 12526 | 101 | const size_t q_end = | 12527 | 101 | (hash_start != std::string_view::npos) ? hash_start : len; | 12528 | 101 | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12529 | 101 | q_end - query_start - 1), | 12530 | 101 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12531 | 101 | } | 12532 | 1.14k | if (hash_start != std::string_view::npos) { | 12533 | 97 | out.update_unencoded_base_hash(std::string_view( | 12534 | 97 | input.data() + hash_start + 1, len - hash_start - 1)); | 12535 | 97 | } | 12536 | 1.14k | }; |
ada::parser::try_parse_simple_absolute<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator&)::{lambda()#1}::operator()() constLine | Count | Source | 12524 | 1.14k | auto apply_query_and_hash = [&]() { | 12525 | 1.14k | if (query_start != std::string_view::npos) { | 12526 | 101 | const size_t q_end = | 12527 | 101 | (hash_start != std::string_view::npos) ? hash_start : len; | 12528 | 101 | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12529 | 101 | q_end - query_start - 1), | 12530 | 101 | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12531 | 101 | } | 12532 | 1.14k | if (hash_start != std::string_view::npos) { | 12533 | 97 | out.update_unencoded_base_hash(std::string_view( | 12534 | 97 | input.data() + hash_start + 1, len - hash_start - 1)); | 12535 | 97 | } | 12536 | 1.14k | }; |
|
12537 | 2.28k | if constexpr (is_aggregator) { |
12538 | 1.14k | out.buffer.assign(input.substr(0, host_end)); |
12539 | 1.14k | if (has_upper) { |
12540 | 152 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); |
12541 | 152 | } |
12542 | 1.14k | out.components.protocol_end = protocol_end; |
12543 | 1.14k | out.components.username_end = protocol_end + 2; |
12544 | 1.14k | out.components.host_start = protocol_end + 2; |
12545 | 1.14k | out.components.host_end = static_cast<uint32_t>(host_end); |
12546 | 1.14k | out.components.port = url_components::omitted; |
12547 | 1.14k | out.components.pathname_start = static_cast<uint32_t>(host_end); |
12548 | 1.14k | out.components.search_start = url_components::omitted; |
12549 | 1.14k | out.components.hash_start = url_components::omitted; |
12550 | 1.14k | out.parse_path(path_view); |
12551 | 1.14k | apply_query_and_hash(); |
12552 | 1.14k | } else { |
12553 | 1.14k | std::string host_str(input.substr(host_start, host_len)); |
12554 | 1.14k | if (has_upper) { |
12555 | 152 | unicode::to_lower_ascii(host_str.data(), host_str.size()); |
12556 | 152 | } |
12557 | 1.14k | out.host = std::move(host_str); |
12558 | 1.14k | out.parse_path(path_view); |
12559 | 1.14k | apply_query_and_hash(); |
12560 | 1.14k | } |
12561 | 2.28k | return true; |
12562 | 2.28k | } |
12563 | | |
12564 | 4.17k | const bool need_slash = !has_path; |
12565 | 4.17k | if constexpr (is_aggregator) { |
12566 | 2.08k | if (!need_slash) { |
12567 | | // assign copies once. resize()+memcpy would value-init then overwrite. |
12568 | 1.87k | out.buffer.assign(input); |
12569 | 1.87k | if (has_upper) { |
12570 | 35 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); |
12571 | 35 | } |
12572 | 1.87k | out.components.protocol_end = protocol_end; |
12573 | 1.87k | out.components.username_end = protocol_end + 2; |
12574 | 1.87k | out.components.host_start = protocol_end + 2; |
12575 | 1.87k | out.components.host_end = static_cast<uint32_t>(host_end); |
12576 | 1.87k | out.components.port = url_components::omitted; |
12577 | 1.87k | out.components.pathname_start = static_cast<uint32_t>(path_start); |
12578 | 1.87k | out.components.search_start = (query_start != std::string_view::npos) |
12579 | 1.87k | ? static_cast<uint32_t>(query_start) |
12580 | 1.87k | : url_components::omitted; |
12581 | 1.87k | out.components.hash_start = (hash_start != std::string_view::npos) |
12582 | 1.87k | ? static_cast<uint32_t>(hash_start) |
12583 | 1.87k | : url_components::omitted; |
12584 | 1.87k | } else { |
12585 | 215 | out.buffer.clear(); |
12586 | 215 | out.buffer.reserve(len + 1); |
12587 | 215 | out.buffer.append(input.substr(0, host_end)); |
12588 | 215 | out.buffer.push_back('/'); |
12589 | 215 | if (host_end < len) { |
12590 | 56 | out.buffer.append(input.substr(host_end)); |
12591 | 56 | } |
12592 | 215 | if (has_upper) { |
12593 | 92 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); |
12594 | 92 | } |
12595 | 215 | out.components.protocol_end = protocol_end; |
12596 | 215 | out.components.username_end = protocol_end + 2; |
12597 | 215 | out.components.host_start = protocol_end + 2; |
12598 | 215 | out.components.host_end = static_cast<uint32_t>(host_end); |
12599 | 215 | out.components.port = url_components::omitted; |
12600 | 215 | out.components.pathname_start = static_cast<uint32_t>(host_end); |
12601 | 215 | out.components.search_start = (query_start != std::string_view::npos) |
12602 | 215 | ? static_cast<uint32_t>(query_start + 1) |
12603 | 215 | : url_components::omitted; |
12604 | 215 | out.components.hash_start = (hash_start != std::string_view::npos) |
12605 | 215 | ? static_cast<uint32_t>(hash_start + 1) |
12606 | 215 | : url_components::omitted; |
12607 | 215 | } |
12608 | 2.08k | } else { |
12609 | 2.08k | std::string host_str(input.substr(host_start, host_len)); |
12610 | 2.08k | if (has_upper) { |
12611 | 127 | unicode::to_lower_ascii(host_str.data(), host_str.size()); |
12612 | 127 | } |
12613 | 2.08k | out.host = std::move(host_str); |
12614 | 2.08k | if (need_slash) { |
12615 | 215 | out.path = "/"; |
12616 | 1.87k | } else { |
12617 | 1.87k | out.path.assign(input.data() + path_start, path_end - path_start); |
12618 | 1.87k | } |
12619 | 2.08k | if (query_start != std::string_view::npos) { |
12620 | 239 | const size_t q_end = |
12621 | 239 | (hash_start != std::string_view::npos) ? hash_start : len; |
12622 | 239 | out.query.emplace(input.data() + query_start + 1, |
12623 | 239 | q_end - query_start - 1); |
12624 | 239 | } |
12625 | 2.08k | if (hash_start != std::string_view::npos) { |
12626 | 260 | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); |
12627 | 260 | } |
12628 | 2.08k | } |
12629 | 4.17k | return true; |
12630 | 6.46k | } bool ada::parser::try_parse_simple_absolute<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url&) Line | Count | Source | 12262 | 44.0k | result_type& out) { | 12263 | 44.0k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 12264 | 44.0k | constexpr bool is_aggregator = | 12265 | 44.0k | std::is_same_v<result_type, ada::url_aggregator>; | 12266 | 44.0k | static_assert(is_ada_url || is_aggregator); | 12267 | | | 12268 | 44.0k | const size_t len = input.size(); | 12269 | | // Shortest accepted form is "ws://x" (6). | 12270 | 44.0k | if (len < 6) [[unlikely]] { | 12271 | 24.5k | return false; | 12272 | 24.5k | } | 12273 | 19.4k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 12274 | | | 12275 | 19.4k | size_t pos = 0; | 12276 | 19.4k | ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL; | 12277 | 19.4k | uint32_t protocol_end = 0; | 12278 | 19.4k | #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ | 12279 | 19.4k | defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64) | 12280 | | // One 8-byte load + integer compare is a single cmp/jcc on x86-64. | 12281 | | // Masked compares cover the shorter special schemes without extra loads. | 12282 | 19.4k | if (len >= 8) { | 12283 | 16.8k | uint64_t first8 = 0; | 12284 | 16.8k | std::memcpy(&first8, b, 8); | 12285 | 16.8k | if (first8 == 0x2f2f3a7370747468ull) { // "https://" | 12286 | 8 | pos = 8; | 12287 | 8 | scheme_type = ada::scheme::type::HTTPS; | 12288 | 8 | protocol_end = 6; | 12289 | 16.8k | } else if ((first8 & 0x00ffffffffffffffull) == | 12290 | 16.8k | 0x002f2f3a70747468ull) { // "http://" | 12291 | 369 | pos = 7; | 12292 | 369 | scheme_type = ada::scheme::type::HTTP; | 12293 | 369 | protocol_end = 5; | 12294 | 16.4k | } else if ((first8 & 0x0000ffffffffffffull) == | 12295 | 16.4k | 0x00002f2f3a737377ull) { // "wss://" | 12296 | 58 | pos = 6; | 12297 | 58 | scheme_type = ada::scheme::type::WSS; | 12298 | 58 | protocol_end = 4; | 12299 | 16.3k | } else if ((first8 & 0x0000ffffffffffffull) == | 12300 | 16.3k | 0x00002f2f3a707466ull) { // "ftp://" | 12301 | 18 | pos = 6; | 12302 | 18 | scheme_type = ada::scheme::type::FTP; | 12303 | 18 | protocol_end = 4; | 12304 | 16.3k | } else if ((first8 & 0x000000ffffffffffull) == | 12305 | 16.3k | 0x0000002f2f3a7377ull) { // "ws://" | 12306 | 7.14k | pos = 5; | 12307 | 7.14k | scheme_type = ada::scheme::type::WS; | 12308 | 7.14k | protocol_end = 3; | 12309 | 9.23k | } else { | 12310 | 9.23k | return false; | 12311 | 9.23k | } | 12312 | 16.8k | } else if (b[0] == 'w' && b[1] == 's') { | 12313 | 1.36k | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { | 12314 | 511 | pos = 5; | 12315 | 511 | scheme_type = ada::scheme::type::WS; | 12316 | 511 | protocol_end = 3; | 12317 | 854 | } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') { | 12318 | 5 | pos = 6; | 12319 | 5 | scheme_type = ada::scheme::type::WSS; | 12320 | 5 | protocol_end = 4; | 12321 | 849 | } else { | 12322 | 849 | return false; | 12323 | 849 | } | 12324 | 1.36k | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && | 12325 | 22 | b[4] == '/' && b[5] == '/') { | 12326 | 3 | pos = 6; | 12327 | 3 | scheme_type = ada::scheme::type::FTP; | 12328 | 3 | protocol_end = 4; | 12329 | 1.26k | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && | 12330 | 59 | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { | 12331 | 3 | pos = 7; | 12332 | 3 | scheme_type = ada::scheme::type::HTTP; | 12333 | 3 | protocol_end = 5; | 12334 | 1.26k | } else { | 12335 | 1.26k | return false; | 12336 | 1.26k | } | 12337 | | #else | 12338 | | // Big-endian / uncommon arches: byte-wise special-scheme match. | 12339 | | if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' && | 12340 | | b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') { | 12341 | | pos = 8; | 12342 | | scheme_type = ada::scheme::type::HTTPS; | 12343 | | protocol_end = 6; | 12344 | | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && | 12345 | | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { | 12346 | | pos = 7; | 12347 | | scheme_type = ada::scheme::type::HTTP; | 12348 | | protocol_end = 5; | 12349 | | } else if (b[0] == 'w' && b[1] == 's') { | 12350 | | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { | 12351 | | pos = 5; | 12352 | | scheme_type = ada::scheme::type::WS; | 12353 | | protocol_end = 3; | 12354 | | } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' && | 12355 | | b[5] == '/') { | 12356 | | pos = 6; | 12357 | | scheme_type = ada::scheme::type::WSS; | 12358 | | protocol_end = 4; | 12359 | | } else { | 12360 | | return false; | 12361 | | } | 12362 | | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && | 12363 | | b[4] == '/' && b[5] == '/') { | 12364 | | pos = 6; | 12365 | | scheme_type = ada::scheme::type::FTP; | 12366 | | protocol_end = 4; | 12367 | | } else { | 12368 | | return false; | 12369 | | } | 12370 | | #endif | 12371 | 8.11k | if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] { | 12372 | 17 | return false; | 12373 | 17 | } | 12374 | | | 12375 | | // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning. | 12376 | 8.09k | if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) { | 12377 | 1.15k | return false; | 12378 | 1.15k | } | 12379 | | | 12380 | 6.94k | const size_t host_start = pos; | 12381 | 6.94k | bool has_upper = false; | 12382 | 6.94k | bool has_x = false; | 12383 | 6.94k | size_t host_end = pos; | 12384 | 6.94k | if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) { | 12385 | 245 | return false; | 12386 | 245 | } | 12387 | 6.69k | if (host_start == host_end) [[unlikely]] { | 12388 | 48 | return false; | 12389 | 48 | } | 12390 | 6.65k | const size_t host_len = host_end - host_start; | 12391 | 6.65k | if (host_len > 253) [[unlikely]] { | 12392 | 88 | return false; | 12393 | 88 | } | 12394 | 6.56k | { | 12395 | 6.56k | std::string_view hv(input.data() + host_start, host_len); | 12396 | 6.56k | char host_buf[256]; | 12397 | 6.56k | if (has_upper) [[unlikely]] { | 12398 | 563 | std::memcpy(host_buf, input.data() + host_start, host_len); | 12399 | 563 | unicode::to_lower_ascii(host_buf, host_len); | 12400 | 563 | hv = std::string_view(host_buf, host_len); | 12401 | 563 | } | 12402 | 6.56k | if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] { | 12403 | 85 | return false; | 12404 | 85 | } | 12405 | | // Punycode is "xn--...". The host scan already notes a lowercase 'x'; | 12406 | | // uppercase 'X' is covered by has_upper after the in-place lower. | 12407 | 6.47k | static constexpr std::string_view xn{"xn-", 3}; | 12408 | 6.47k | if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos) | 12409 | 1.32k | [[unlikely]] { | 12410 | 1.32k | return false; | 12411 | 1.32k | } | 12412 | 6.47k | } | 12413 | | | 12414 | 5.15k | if (host_end < len && b[host_end] == ':') [[unlikely]] { | 12415 | 1.88k | return finish_simple_absolute_with_port(input, out, scheme_type, | 12416 | 1.88k | protocol_end, host_start, host_end, | 12417 | 1.88k | host_len, has_upper); | 12418 | 1.88k | } | 12419 | | | 12420 | 3.27k | size_t i = host_end; | 12421 | 3.27k | size_t path_start = host_end; | 12422 | 3.27k | size_t path_end = host_end; | 12423 | 3.27k | size_t query_start = std::string_view::npos; | 12424 | 3.27k | size_t hash_start = std::string_view::npos; | 12425 | 3.27k | bool has_path = false; | 12426 | 3.27k | bool maybe_dot_segment = false; | 12427 | 3.27k | bool rest_simple = true; | 12428 | | | 12429 | 3.27k | if (i < len && b[i] == '/') { | 12430 | 2.97k | has_path = true; | 12431 | 2.97k | path_start = i; | 12432 | 2.97k | ++i; | 12433 | 2.97k | scan_path_run(b, i, len, maybe_dot_segment); | 12434 | 2.97k | if (i < len) { | 12435 | 1.29k | const uint8_t cls = k_path[b[i]]; | 12436 | 1.29k | if (cls == 1) { | 12437 | 369 | path_end = i; | 12438 | 369 | if (b[i] == '?') { | 12439 | 222 | query_start = i; | 12440 | 222 | ++i; | 12441 | 222 | goto scan_query; | 12442 | 222 | } | 12443 | 147 | hash_start = i; | 12444 | 147 | ++i; | 12445 | 147 | goto scan_hash; | 12446 | 369 | } | 12447 | 928 | rest_simple = false; | 12448 | 928 | hash_start = input.find('#', i); | 12449 | 928 | query_start = input.substr(0, hash_start).find('?', i); | 12450 | 928 | if (query_start != std::string_view::npos) { | 12451 | 56 | path_end = query_start; | 12452 | 872 | } else { | 12453 | 872 | path_end = hash_start != std::string_view::npos ? hash_start : len; | 12454 | 872 | } | 12455 | 928 | goto after_rest; | 12456 | 1.29k | } | 12457 | 1.67k | path_end = i; | 12458 | 1.67k | } else if (i < len && b[i] == '?') { | 12459 | 69 | query_start = i; | 12460 | 69 | ++i; | 12461 | 69 | goto scan_query; | 12462 | 230 | } else if (i < len && b[i] == '#') { | 12463 | 71 | hash_start = i; | 12464 | 71 | ++i; | 12465 | 71 | goto scan_hash; | 12466 | 71 | } | 12467 | 1.83k | goto after_rest; | 12468 | | | 12469 | 1.83k | scan_query: | 12470 | 291 | scan_query_run(b, i, len); | 12471 | 291 | if (i < len) { | 12472 | 148 | if (b[i] == '#') { | 12473 | 102 | hash_start = i; | 12474 | 102 | ++i; | 12475 | 102 | goto scan_hash; | 12476 | 102 | } | 12477 | 46 | rest_simple = false; | 12478 | 46 | goto scan_query_boundary; | 12479 | 148 | } | 12480 | 143 | goto after_rest; | 12481 | | | 12482 | 143 | scan_query_boundary: | 12483 | 46 | hash_start = input.find('#', i); | 12484 | 46 | goto after_rest; | 12485 | | | 12486 | 320 | scan_hash: | 12487 | 320 | scan_hash_run(b, i, len); | 12488 | 320 | if (i < len) { | 12489 | 60 | rest_simple = false; | 12490 | 60 | } | 12491 | | | 12492 | 3.27k | after_rest: | 12493 | 3.27k | if (rest_simple && maybe_dot_segment) { | 12494 | 358 | const std::string_view path_body(input.data() + path_start, | 12495 | 358 | path_end - path_start); | 12496 | 358 | if (path_has_dot_segment(path_body)) { | 12497 | 152 | rest_simple = false; | 12498 | 152 | } | 12499 | 358 | } | 12500 | | | 12501 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a | 12502 | | // trailing C0 control or space; this fast path does neither. A query or | 12503 | | // fragment reaching the helpers below would keep those bytes percent-encoded | 12504 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such | 12505 | | // inputs back to the slow path. | 12506 | 3.27k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || | 12507 | 1.16k | unicode::has_tabs_or_newline(input))) { | 12508 | 42 | return false; | 12509 | 42 | } | 12510 | | | 12511 | 3.23k | out.type = scheme_type; | 12512 | 3.23k | out.is_valid = true; | 12513 | 3.23k | out.has_opaque_path = false; | 12514 | 3.23k | out.host_type = DEFAULT; | 12515 | | | 12516 | 3.23k | if (!rest_simple) { | 12517 | | // Host is a plain domain. Finish path/query/hash with | 12518 | | // the regular helpers | 12519 | | // so percent-encoding and dot segments do not re-parse the authority. | 12520 | 1.14k | const std::string_view path_view = | 12521 | 1.14k | has_path | 12522 | 1.14k | ? std::string_view(input.data() + path_start, path_end - path_start) | 12523 | 1.14k | : std::string_view{}; | 12524 | 1.14k | auto apply_query_and_hash = [&]() { | 12525 | 1.14k | if (query_start != std::string_view::npos) { | 12526 | 1.14k | const size_t q_end = | 12527 | 1.14k | (hash_start != std::string_view::npos) ? hash_start : len; | 12528 | 1.14k | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12529 | 1.14k | q_end - query_start - 1), | 12530 | 1.14k | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12531 | 1.14k | } | 12532 | 1.14k | if (hash_start != std::string_view::npos) { | 12533 | 1.14k | out.update_unencoded_base_hash(std::string_view( | 12534 | 1.14k | input.data() + hash_start + 1, len - hash_start - 1)); | 12535 | 1.14k | } | 12536 | 1.14k | }; | 12537 | | if constexpr (is_aggregator) { | 12538 | | out.buffer.assign(input.substr(0, host_end)); | 12539 | | if (has_upper) { | 12540 | | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12541 | | } | 12542 | | out.components.protocol_end = protocol_end; | 12543 | | out.components.username_end = protocol_end + 2; | 12544 | | out.components.host_start = protocol_end + 2; | 12545 | | out.components.host_end = static_cast<uint32_t>(host_end); | 12546 | | out.components.port = url_components::omitted; | 12547 | | out.components.pathname_start = static_cast<uint32_t>(host_end); | 12548 | | out.components.search_start = url_components::omitted; | 12549 | | out.components.hash_start = url_components::omitted; | 12550 | | out.parse_path(path_view); | 12551 | | apply_query_and_hash(); | 12552 | 1.14k | } else { | 12553 | 1.14k | std::string host_str(input.substr(host_start, host_len)); | 12554 | 1.14k | if (has_upper) { | 12555 | 152 | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12556 | 152 | } | 12557 | 1.14k | out.host = std::move(host_str); | 12558 | 1.14k | out.parse_path(path_view); | 12559 | 1.14k | apply_query_and_hash(); | 12560 | 1.14k | } | 12561 | 1.14k | return true; | 12562 | 1.14k | } | 12563 | | | 12564 | 2.08k | const bool need_slash = !has_path; | 12565 | | if constexpr (is_aggregator) { | 12566 | | if (!need_slash) { | 12567 | | // assign copies once. resize()+memcpy would value-init then overwrite. | 12568 | | out.buffer.assign(input); | 12569 | | if (has_upper) { | 12570 | | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12571 | | } | 12572 | | out.components.protocol_end = protocol_end; | 12573 | | out.components.username_end = protocol_end + 2; | 12574 | | out.components.host_start = protocol_end + 2; | 12575 | | out.components.host_end = static_cast<uint32_t>(host_end); | 12576 | | out.components.port = url_components::omitted; | 12577 | | out.components.pathname_start = static_cast<uint32_t>(path_start); | 12578 | | out.components.search_start = (query_start != std::string_view::npos) | 12579 | | ? static_cast<uint32_t>(query_start) | 12580 | | : url_components::omitted; | 12581 | | out.components.hash_start = (hash_start != std::string_view::npos) | 12582 | | ? static_cast<uint32_t>(hash_start) | 12583 | | : url_components::omitted; | 12584 | | } else { | 12585 | | out.buffer.clear(); | 12586 | | out.buffer.reserve(len + 1); | 12587 | | out.buffer.append(input.substr(0, host_end)); | 12588 | | out.buffer.push_back('/'); | 12589 | | if (host_end < len) { | 12590 | | out.buffer.append(input.substr(host_end)); | 12591 | | } | 12592 | | if (has_upper) { | 12593 | | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12594 | | } | 12595 | | out.components.protocol_end = protocol_end; | 12596 | | out.components.username_end = protocol_end + 2; | 12597 | | out.components.host_start = protocol_end + 2; | 12598 | | out.components.host_end = static_cast<uint32_t>(host_end); | 12599 | | out.components.port = url_components::omitted; | 12600 | | out.components.pathname_start = static_cast<uint32_t>(host_end); | 12601 | | out.components.search_start = (query_start != std::string_view::npos) | 12602 | | ? static_cast<uint32_t>(query_start + 1) | 12603 | | : url_components::omitted; | 12604 | | out.components.hash_start = (hash_start != std::string_view::npos) | 12605 | | ? static_cast<uint32_t>(hash_start + 1) | 12606 | | : url_components::omitted; | 12607 | | } | 12608 | 2.08k | } else { | 12609 | 2.08k | std::string host_str(input.substr(host_start, host_len)); | 12610 | 2.08k | if (has_upper) { | 12611 | 127 | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12612 | 127 | } | 12613 | 2.08k | out.host = std::move(host_str); | 12614 | 2.08k | if (need_slash) { | 12615 | 215 | out.path = "/"; | 12616 | 1.87k | } else { | 12617 | 1.87k | out.path.assign(input.data() + path_start, path_end - path_start); | 12618 | 1.87k | } | 12619 | 2.08k | if (query_start != std::string_view::npos) { | 12620 | 239 | const size_t q_end = | 12621 | 239 | (hash_start != std::string_view::npos) ? hash_start : len; | 12622 | 239 | out.query.emplace(input.data() + query_start + 1, | 12623 | 239 | q_end - query_start - 1); | 12624 | 239 | } | 12625 | 2.08k | if (hash_start != std::string_view::npos) { | 12626 | 260 | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); | 12627 | 260 | } | 12628 | 2.08k | } | 12629 | 2.08k | return true; | 12630 | 3.23k | } |
bool ada::parser::try_parse_simple_absolute<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator&) Line | Count | Source | 12262 | 44.0k | result_type& out) { | 12263 | 44.0k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 12264 | 44.0k | constexpr bool is_aggregator = | 12265 | 44.0k | std::is_same_v<result_type, ada::url_aggregator>; | 12266 | 44.0k | static_assert(is_ada_url || is_aggregator); | 12267 | | | 12268 | 44.0k | const size_t len = input.size(); | 12269 | | // Shortest accepted form is "ws://x" (6). | 12270 | 44.0k | if (len < 6) [[unlikely]] { | 12271 | 24.5k | return false; | 12272 | 24.5k | } | 12273 | 19.4k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 12274 | | | 12275 | 19.4k | size_t pos = 0; | 12276 | 19.4k | ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL; | 12277 | 19.4k | uint32_t protocol_end = 0; | 12278 | 19.4k | #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ | 12279 | 19.4k | defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64) | 12280 | | // One 8-byte load + integer compare is a single cmp/jcc on x86-64. | 12281 | | // Masked compares cover the shorter special schemes without extra loads. | 12282 | 19.4k | if (len >= 8) { | 12283 | 16.8k | uint64_t first8 = 0; | 12284 | 16.8k | std::memcpy(&first8, b, 8); | 12285 | 16.8k | if (first8 == 0x2f2f3a7370747468ull) { // "https://" | 12286 | 8 | pos = 8; | 12287 | 8 | scheme_type = ada::scheme::type::HTTPS; | 12288 | 8 | protocol_end = 6; | 12289 | 16.8k | } else if ((first8 & 0x00ffffffffffffffull) == | 12290 | 16.8k | 0x002f2f3a70747468ull) { // "http://" | 12291 | 369 | pos = 7; | 12292 | 369 | scheme_type = ada::scheme::type::HTTP; | 12293 | 369 | protocol_end = 5; | 12294 | 16.4k | } else if ((first8 & 0x0000ffffffffffffull) == | 12295 | 16.4k | 0x00002f2f3a737377ull) { // "wss://" | 12296 | 58 | pos = 6; | 12297 | 58 | scheme_type = ada::scheme::type::WSS; | 12298 | 58 | protocol_end = 4; | 12299 | 16.3k | } else if ((first8 & 0x0000ffffffffffffull) == | 12300 | 16.3k | 0x00002f2f3a707466ull) { // "ftp://" | 12301 | 18 | pos = 6; | 12302 | 18 | scheme_type = ada::scheme::type::FTP; | 12303 | 18 | protocol_end = 4; | 12304 | 16.3k | } else if ((first8 & 0x000000ffffffffffull) == | 12305 | 16.3k | 0x0000002f2f3a7377ull) { // "ws://" | 12306 | 7.14k | pos = 5; | 12307 | 7.14k | scheme_type = ada::scheme::type::WS; | 12308 | 7.14k | protocol_end = 3; | 12309 | 9.23k | } else { | 12310 | 9.23k | return false; | 12311 | 9.23k | } | 12312 | 16.8k | } else if (b[0] == 'w' && b[1] == 's') { | 12313 | 1.36k | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { | 12314 | 511 | pos = 5; | 12315 | 511 | scheme_type = ada::scheme::type::WS; | 12316 | 511 | protocol_end = 3; | 12317 | 854 | } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') { | 12318 | 5 | pos = 6; | 12319 | 5 | scheme_type = ada::scheme::type::WSS; | 12320 | 5 | protocol_end = 4; | 12321 | 849 | } else { | 12322 | 849 | return false; | 12323 | 849 | } | 12324 | 1.36k | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && | 12325 | 22 | b[4] == '/' && b[5] == '/') { | 12326 | 3 | pos = 6; | 12327 | 3 | scheme_type = ada::scheme::type::FTP; | 12328 | 3 | protocol_end = 4; | 12329 | 1.26k | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && | 12330 | 59 | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { | 12331 | 3 | pos = 7; | 12332 | 3 | scheme_type = ada::scheme::type::HTTP; | 12333 | 3 | protocol_end = 5; | 12334 | 1.26k | } else { | 12335 | 1.26k | return false; | 12336 | 1.26k | } | 12337 | | #else | 12338 | | // Big-endian / uncommon arches: byte-wise special-scheme match. | 12339 | | if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' && | 12340 | | b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') { | 12341 | | pos = 8; | 12342 | | scheme_type = ada::scheme::type::HTTPS; | 12343 | | protocol_end = 6; | 12344 | | } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && | 12345 | | b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') { | 12346 | | pos = 7; | 12347 | | scheme_type = ada::scheme::type::HTTP; | 12348 | | protocol_end = 5; | 12349 | | } else if (b[0] == 'w' && b[1] == 's') { | 12350 | | if (b[2] == ':' && b[3] == '/' && b[4] == '/') { | 12351 | | pos = 5; | 12352 | | scheme_type = ada::scheme::type::WS; | 12353 | | protocol_end = 3; | 12354 | | } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' && | 12355 | | b[5] == '/') { | 12356 | | pos = 6; | 12357 | | scheme_type = ada::scheme::type::WSS; | 12358 | | protocol_end = 4; | 12359 | | } else { | 12360 | | return false; | 12361 | | } | 12362 | | } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' && | 12363 | | b[4] == '/' && b[5] == '/') { | 12364 | | pos = 6; | 12365 | | scheme_type = ada::scheme::type::FTP; | 12366 | | protocol_end = 4; | 12367 | | } else { | 12368 | | return false; | 12369 | | } | 12370 | | #endif | 12371 | 8.11k | if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] { | 12372 | 17 | return false; | 12373 | 17 | } | 12374 | | | 12375 | | // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning. | 12376 | 8.09k | if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) { | 12377 | 1.15k | return false; | 12378 | 1.15k | } | 12379 | | | 12380 | 6.94k | const size_t host_start = pos; | 12381 | 6.94k | bool has_upper = false; | 12382 | 6.94k | bool has_x = false; | 12383 | 6.94k | size_t host_end = pos; | 12384 | 6.94k | if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) { | 12385 | 245 | return false; | 12386 | 245 | } | 12387 | 6.69k | if (host_start == host_end) [[unlikely]] { | 12388 | 48 | return false; | 12389 | 48 | } | 12390 | 6.65k | const size_t host_len = host_end - host_start; | 12391 | 6.65k | if (host_len > 253) [[unlikely]] { | 12392 | 88 | return false; | 12393 | 88 | } | 12394 | 6.56k | { | 12395 | 6.56k | std::string_view hv(input.data() + host_start, host_len); | 12396 | 6.56k | char host_buf[256]; | 12397 | 6.56k | if (has_upper) [[unlikely]] { | 12398 | 563 | std::memcpy(host_buf, input.data() + host_start, host_len); | 12399 | 563 | unicode::to_lower_ascii(host_buf, host_len); | 12400 | 563 | hv = std::string_view(host_buf, host_len); | 12401 | 563 | } | 12402 | 6.56k | if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] { | 12403 | 85 | return false; | 12404 | 85 | } | 12405 | | // Punycode is "xn--...". The host scan already notes a lowercase 'x'; | 12406 | | // uppercase 'X' is covered by has_upper after the in-place lower. | 12407 | 6.47k | static constexpr std::string_view xn{"xn-", 3}; | 12408 | 6.47k | if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos) | 12409 | 1.32k | [[unlikely]] { | 12410 | 1.32k | return false; | 12411 | 1.32k | } | 12412 | 6.47k | } | 12413 | | | 12414 | 5.15k | if (host_end < len && b[host_end] == ':') [[unlikely]] { | 12415 | 1.88k | return finish_simple_absolute_with_port(input, out, scheme_type, | 12416 | 1.88k | protocol_end, host_start, host_end, | 12417 | 1.88k | host_len, has_upper); | 12418 | 1.88k | } | 12419 | | | 12420 | 3.27k | size_t i = host_end; | 12421 | 3.27k | size_t path_start = host_end; | 12422 | 3.27k | size_t path_end = host_end; | 12423 | 3.27k | size_t query_start = std::string_view::npos; | 12424 | 3.27k | size_t hash_start = std::string_view::npos; | 12425 | 3.27k | bool has_path = false; | 12426 | 3.27k | bool maybe_dot_segment = false; | 12427 | 3.27k | bool rest_simple = true; | 12428 | | | 12429 | 3.27k | if (i < len && b[i] == '/') { | 12430 | 2.97k | has_path = true; | 12431 | 2.97k | path_start = i; | 12432 | 2.97k | ++i; | 12433 | 2.97k | scan_path_run(b, i, len, maybe_dot_segment); | 12434 | 2.97k | if (i < len) { | 12435 | 1.29k | const uint8_t cls = k_path[b[i]]; | 12436 | 1.29k | if (cls == 1) { | 12437 | 369 | path_end = i; | 12438 | 369 | if (b[i] == '?') { | 12439 | 222 | query_start = i; | 12440 | 222 | ++i; | 12441 | 222 | goto scan_query; | 12442 | 222 | } | 12443 | 147 | hash_start = i; | 12444 | 147 | ++i; | 12445 | 147 | goto scan_hash; | 12446 | 369 | } | 12447 | 928 | rest_simple = false; | 12448 | 928 | hash_start = input.find('#', i); | 12449 | 928 | query_start = input.substr(0, hash_start).find('?', i); | 12450 | 928 | if (query_start != std::string_view::npos) { | 12451 | 56 | path_end = query_start; | 12452 | 872 | } else { | 12453 | 872 | path_end = hash_start != std::string_view::npos ? hash_start : len; | 12454 | 872 | } | 12455 | 928 | goto after_rest; | 12456 | 1.29k | } | 12457 | 1.67k | path_end = i; | 12458 | 1.67k | } else if (i < len && b[i] == '?') { | 12459 | 69 | query_start = i; | 12460 | 69 | ++i; | 12461 | 69 | goto scan_query; | 12462 | 230 | } else if (i < len && b[i] == '#') { | 12463 | 71 | hash_start = i; | 12464 | 71 | ++i; | 12465 | 71 | goto scan_hash; | 12466 | 71 | } | 12467 | 1.83k | goto after_rest; | 12468 | | | 12469 | 1.83k | scan_query: | 12470 | 291 | scan_query_run(b, i, len); | 12471 | 291 | if (i < len) { | 12472 | 148 | if (b[i] == '#') { | 12473 | 102 | hash_start = i; | 12474 | 102 | ++i; | 12475 | 102 | goto scan_hash; | 12476 | 102 | } | 12477 | 46 | rest_simple = false; | 12478 | 46 | goto scan_query_boundary; | 12479 | 148 | } | 12480 | 143 | goto after_rest; | 12481 | | | 12482 | 143 | scan_query_boundary: | 12483 | 46 | hash_start = input.find('#', i); | 12484 | 46 | goto after_rest; | 12485 | | | 12486 | 320 | scan_hash: | 12487 | 320 | scan_hash_run(b, i, len); | 12488 | 320 | if (i < len) { | 12489 | 60 | rest_simple = false; | 12490 | 60 | } | 12491 | | | 12492 | 3.27k | after_rest: | 12493 | 3.27k | if (rest_simple && maybe_dot_segment) { | 12494 | 358 | const std::string_view path_body(input.data() + path_start, | 12495 | 358 | path_end - path_start); | 12496 | 358 | if (path_has_dot_segment(path_body)) { | 12497 | 152 | rest_simple = false; | 12498 | 152 | } | 12499 | 358 | } | 12500 | | | 12501 | | // The slow path removes ASCII tab/newline anywhere in the input and trims a | 12502 | | // trailing C0 control or space; this fast path does neither. A query or | 12503 | | // fragment reaching the helpers below would keep those bytes percent-encoded | 12504 | | // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such | 12505 | | // inputs back to the slow path. | 12506 | 3.27k | if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) || | 12507 | 1.16k | unicode::has_tabs_or_newline(input))) { | 12508 | 42 | return false; | 12509 | 42 | } | 12510 | | | 12511 | 3.23k | out.type = scheme_type; | 12512 | 3.23k | out.is_valid = true; | 12513 | 3.23k | out.has_opaque_path = false; | 12514 | 3.23k | out.host_type = DEFAULT; | 12515 | | | 12516 | 3.23k | if (!rest_simple) { | 12517 | | // Host is a plain domain. Finish path/query/hash with | 12518 | | // the regular helpers | 12519 | | // so percent-encoding and dot segments do not re-parse the authority. | 12520 | 1.14k | const std::string_view path_view = | 12521 | 1.14k | has_path | 12522 | 1.14k | ? std::string_view(input.data() + path_start, path_end - path_start) | 12523 | 1.14k | : std::string_view{}; | 12524 | 1.14k | auto apply_query_and_hash = [&]() { | 12525 | 1.14k | if (query_start != std::string_view::npos) { | 12526 | 1.14k | const size_t q_end = | 12527 | 1.14k | (hash_start != std::string_view::npos) ? hash_start : len; | 12528 | 1.14k | out.update_base_search(std::string_view(input.data() + query_start + 1, | 12529 | 1.14k | q_end - query_start - 1), | 12530 | 1.14k | character_sets::SPECIAL_QUERY_PERCENT_ENCODE); | 12531 | 1.14k | } | 12532 | 1.14k | if (hash_start != std::string_view::npos) { | 12533 | 1.14k | out.update_unencoded_base_hash(std::string_view( | 12534 | 1.14k | input.data() + hash_start + 1, len - hash_start - 1)); | 12535 | 1.14k | } | 12536 | 1.14k | }; | 12537 | 1.14k | if constexpr (is_aggregator) { | 12538 | 1.14k | out.buffer.assign(input.substr(0, host_end)); | 12539 | 1.14k | if (has_upper) { | 12540 | 152 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12541 | 152 | } | 12542 | 1.14k | out.components.protocol_end = protocol_end; | 12543 | 1.14k | out.components.username_end = protocol_end + 2; | 12544 | 1.14k | out.components.host_start = protocol_end + 2; | 12545 | 1.14k | out.components.host_end = static_cast<uint32_t>(host_end); | 12546 | 1.14k | out.components.port = url_components::omitted; | 12547 | 1.14k | out.components.pathname_start = static_cast<uint32_t>(host_end); | 12548 | 1.14k | out.components.search_start = url_components::omitted; | 12549 | 1.14k | out.components.hash_start = url_components::omitted; | 12550 | 1.14k | out.parse_path(path_view); | 12551 | 1.14k | apply_query_and_hash(); | 12552 | | } else { | 12553 | | std::string host_str(input.substr(host_start, host_len)); | 12554 | | if (has_upper) { | 12555 | | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12556 | | } | 12557 | | out.host = std::move(host_str); | 12558 | | out.parse_path(path_view); | 12559 | | apply_query_and_hash(); | 12560 | | } | 12561 | 1.14k | return true; | 12562 | 1.14k | } | 12563 | | | 12564 | 2.08k | const bool need_slash = !has_path; | 12565 | 2.08k | if constexpr (is_aggregator) { | 12566 | 2.08k | if (!need_slash) { | 12567 | | // assign copies once. resize()+memcpy would value-init then overwrite. | 12568 | 1.87k | out.buffer.assign(input); | 12569 | 1.87k | if (has_upper) { | 12570 | 35 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12571 | 35 | } | 12572 | 1.87k | out.components.protocol_end = protocol_end; | 12573 | 1.87k | out.components.username_end = protocol_end + 2; | 12574 | 1.87k | out.components.host_start = protocol_end + 2; | 12575 | 1.87k | out.components.host_end = static_cast<uint32_t>(host_end); | 12576 | 1.87k | out.components.port = url_components::omitted; | 12577 | 1.87k | out.components.pathname_start = static_cast<uint32_t>(path_start); | 12578 | 1.87k | out.components.search_start = (query_start != std::string_view::npos) | 12579 | 1.87k | ? static_cast<uint32_t>(query_start) | 12580 | 1.87k | : url_components::omitted; | 12581 | 1.87k | out.components.hash_start = (hash_start != std::string_view::npos) | 12582 | 1.87k | ? static_cast<uint32_t>(hash_start) | 12583 | 1.87k | : url_components::omitted; | 12584 | 1.87k | } else { | 12585 | 215 | out.buffer.clear(); | 12586 | 215 | out.buffer.reserve(len + 1); | 12587 | 215 | out.buffer.append(input.substr(0, host_end)); | 12588 | 215 | out.buffer.push_back('/'); | 12589 | 215 | if (host_end < len) { | 12590 | 56 | out.buffer.append(input.substr(host_end)); | 12591 | 56 | } | 12592 | 215 | if (has_upper) { | 12593 | 92 | unicode::to_lower_ascii(out.buffer.data() + host_start, host_len); | 12594 | 92 | } | 12595 | 215 | out.components.protocol_end = protocol_end; | 12596 | 215 | out.components.username_end = protocol_end + 2; | 12597 | 215 | out.components.host_start = protocol_end + 2; | 12598 | 215 | out.components.host_end = static_cast<uint32_t>(host_end); | 12599 | 215 | out.components.port = url_components::omitted; | 12600 | 215 | out.components.pathname_start = static_cast<uint32_t>(host_end); | 12601 | 215 | out.components.search_start = (query_start != std::string_view::npos) | 12602 | 215 | ? static_cast<uint32_t>(query_start + 1) | 12603 | 215 | : url_components::omitted; | 12604 | 215 | out.components.hash_start = (hash_start != std::string_view::npos) | 12605 | 215 | ? static_cast<uint32_t>(hash_start + 1) | 12606 | 215 | : url_components::omitted; | 12607 | 215 | } | 12608 | | } else { | 12609 | | std::string host_str(input.substr(host_start, host_len)); | 12610 | | if (has_upper) { | 12611 | | unicode::to_lower_ascii(host_str.data(), host_str.size()); | 12612 | | } | 12613 | | out.host = std::move(host_str); | 12614 | | if (need_slash) { | 12615 | | out.path = "/"; | 12616 | | } else { | 12617 | | out.path.assign(input.data() + path_start, path_end - path_start); | 12618 | | } | 12619 | | if (query_start != std::string_view::npos) { | 12620 | | const size_t q_end = | 12621 | | (hash_start != std::string_view::npos) ? hash_start : len; | 12622 | | out.query.emplace(input.data() + query_start + 1, | 12623 | | q_end - query_start - 1); | 12624 | | } | 12625 | | if (hash_start != std::string_view::npos) { | 12626 | | out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1); | 12627 | | } | 12628 | | } | 12629 | 2.08k | return true; | 12630 | 3.23k | } |
|
12631 | | |
12632 | | // Fast path for `/path`, path-relative (`foo`, `c/d?q`), `?query`, and |
12633 | | // `#fragment` against a special-scheme base. Scheme-relative (`//`) and |
12634 | | // scheme-like first segments (`foo:bar`) stay on the state machine. |
12635 | | template <class result_type> |
12636 | | ada_never_inline bool try_parse_simple_relative(std::string_view input, |
12637 | | const result_type& base, |
12638 | 8.70k | result_type& out) { |
12639 | 8.70k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; |
12640 | 8.70k | constexpr bool is_aggregator = |
12641 | 8.70k | std::is_same_v<result_type, ada::url_aggregator>; |
12642 | 8.70k | static_assert(is_ada_url || is_aggregator); |
12643 | | |
12644 | 8.70k | if (!base.is_special() || base.type == ada::scheme::type::FILE || |
12645 | 5.40k | base.has_opaque_path || input.empty()) { |
12646 | 5.40k | return false; |
12647 | 5.40k | } |
12648 | 3.30k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); |
12649 | 3.30k | const size_t len = input.size(); |
12650 | 3.30k | const uint8_t first = b[0]; |
12651 | 3.30k | const bool path_relative = first != '/' && first != '?' && first != '#'; |
12652 | 3.30k | if (first == '/' && len > 1 && (b[1] == '/' || b[1] == '\\')) { |
12653 | 10 | return false; |
12654 | 10 | } |
12655 | | // A ':' before the first / ? # is a scheme, not a path segment. |
12656 | 3.29k | if (path_relative) { |
12657 | 2.84k | const size_t delim = input.find_first_of("/?#:"); |
12658 | 2.84k | if (delim != std::string_view::npos && input[delim] == ':') { |
12659 | 1.86k | return false; |
12660 | 1.86k | } |
12661 | 2.84k | } |
12662 | | |
12663 | 1.43k | size_t i = 0; |
12664 | 1.43k | size_t path_start = 0; |
12665 | 1.43k | size_t path_end = 0; |
12666 | 1.43k | size_t query_start = std::string_view::npos; |
12667 | 1.43k | size_t hash_start = std::string_view::npos; |
12668 | 1.43k | bool has_path = false; |
12669 | 1.43k | bool maybe_dot_segment = false; |
12670 | | |
12671 | 1.43k | if (first == '/' || path_relative) { |
12672 | 1.11k | has_path = true; |
12673 | 1.11k | path_start = 0; |
12674 | 1.11k | if (first == '/') { |
12675 | 134 | i = 1; |
12676 | 134 | } |
12677 | 1.11k | scan_path_run(b, i, len, maybe_dot_segment); |
12678 | 1.11k | if (i < len) { |
12679 | 650 | const uint8_t cls = k_path[b[i]]; |
12680 | 650 | if (cls == 2) { |
12681 | 314 | return false; |
12682 | 314 | } |
12683 | 650 | } |
12684 | 800 | path_end = i; |
12685 | 800 | if (i < len && b[i] == '?') { |
12686 | 228 | query_start = i; |
12687 | 228 | ++i; |
12688 | 228 | scan_query_run(b, i, len); |
12689 | 228 | if (i < len) { |
12690 | 178 | if (b[i] != '#') { |
12691 | 56 | return false; |
12692 | 56 | } |
12693 | 122 | hash_start = i; |
12694 | 122 | ++i; |
12695 | 122 | scan_hash_run(b, i, len); |
12696 | 122 | if (i < len) { |
12697 | 94 | return false; |
12698 | 94 | } |
12699 | 122 | } |
12700 | 572 | } else if (i < len && b[i] == '#') { |
12701 | 108 | hash_start = i; |
12702 | 108 | ++i; |
12703 | 108 | scan_hash_run(b, i, len); |
12704 | 108 | if (i < len) { |
12705 | 70 | return false; |
12706 | 70 | } |
12707 | 464 | } else if (i < len) { |
12708 | 0 | return false; |
12709 | 0 | } |
12710 | 800 | } else if (first == '?') { |
12711 | 212 | query_start = 0; |
12712 | 212 | i = 1; |
12713 | 212 | scan_query_run(b, i, len); |
12714 | 212 | if (i < len) { |
12715 | 176 | if (b[i] != '#') { |
12716 | 66 | return false; |
12717 | 66 | } |
12718 | 110 | hash_start = i; |
12719 | 110 | ++i; |
12720 | 110 | scan_hash_run(b, i, len); |
12721 | 110 | if (i < len) { |
12722 | 76 | return false; |
12723 | 76 | } |
12724 | 110 | } |
12725 | 212 | } else { |
12726 | 104 | hash_start = 0; |
12727 | 104 | i = 1; |
12728 | 104 | scan_hash_run(b, i, len); |
12729 | 104 | if (i < len) { |
12730 | 42 | return false; |
12731 | 42 | } |
12732 | 104 | } |
12733 | | |
12734 | 712 | if (has_path && maybe_dot_segment) { |
12735 | 236 | const std::string_view path_body(input.data() + path_start, |
12736 | 236 | path_end - path_start); |
12737 | 236 | if (path_has_dot_segment(path_body)) { |
12738 | 196 | return false; |
12739 | 196 | } |
12740 | 236 | } |
12741 | | |
12742 | 516 | out = base; |
12743 | 516 | out.is_valid = true; |
12744 | 516 | out.has_opaque_path = false; |
12745 | | |
12746 | 516 | const size_t q_end = |
12747 | 516 | (hash_start != std::string_view::npos) ? hash_start : len; |
12748 | 516 | const bool has_query = query_start != std::string_view::npos; |
12749 | 516 | const bool has_hash = hash_start != std::string_view::npos; |
12750 | 516 | const std::string_view query = |
12751 | 516 | has_query ? std::string_view(input.data() + query_start + 1, |
12752 | 142 | q_end - query_start - 1) |
12753 | 516 | : std::string_view{}; |
12754 | 516 | const std::string_view hash = |
12755 | 516 | has_hash ? std::string_view(input.data() + hash_start + 1, |
12756 | 160 | len - hash_start - 1) |
12757 | 516 | : std::string_view{}; |
12758 | | |
12759 | 516 | if constexpr (is_aggregator) { |
12760 | 258 | if (first == '/' || first == '?' || path_relative) { |
12761 | 227 | out.clear_hash(); |
12762 | 227 | out.clear_search(); |
12763 | 227 | } |
12764 | 258 | if (first == '/') { |
12765 | 33 | out.update_base_pathname(input.substr(path_start, path_end - path_start)); |
12766 | 225 | } else if (path_relative) { |
12767 | 159 | const std::string_view base_path = out.get_pathname(); |
12768 | 159 | const size_t slash = base_path.rfind('/'); |
12769 | 159 | const std::string_view prefix = (slash == std::string_view::npos) |
12770 | 159 | ? std::string_view("/") |
12771 | 159 | : base_path.substr(0, slash + 1); |
12772 | 159 | const std::string_view rel(input.data() + path_start, |
12773 | 159 | path_end - path_start); |
12774 | 159 | std::string new_path; |
12775 | 159 | new_path.reserve(prefix.size() + rel.size()); |
12776 | 159 | new_path.assign(prefix); |
12777 | 159 | new_path.append(rel); |
12778 | 159 | out.update_base_pathname(new_path); |
12779 | 159 | } |
12780 | 258 | if (has_query) { |
12781 | | // Do not use update_base_search: it strips a leading '?' and would |
12782 | | // collapse '??a=b' into '?a=b'. |
12783 | 71 | out.components.search_start = static_cast<uint32_t>(out.buffer.size()); |
12784 | 71 | out.buffer += '?'; |
12785 | 71 | out.buffer.append(query); |
12786 | 71 | } |
12787 | 258 | if (has_hash) { |
12788 | 80 | out.update_unencoded_base_hash(hash); |
12789 | 80 | } |
12790 | 258 | } else { |
12791 | 258 | if (first == '/' || first == '?' || path_relative) { |
12792 | 227 | out.hash.reset(); |
12793 | 227 | } |
12794 | 258 | if (first == '/') { |
12795 | 33 | out.query.reset(); |
12796 | 33 | out.path.assign(input.substr(path_start, path_end - path_start)); |
12797 | 225 | } else if (path_relative) { |
12798 | 159 | out.query.reset(); |
12799 | 159 | const size_t slash = out.path.rfind('/'); |
12800 | 159 | if (slash == std::string::npos) { |
12801 | 0 | out.path = '/'; |
12802 | 159 | } else { |
12803 | 159 | out.path.resize(slash + 1); |
12804 | 159 | } |
12805 | 159 | out.path.append(input.substr(path_start, path_end - path_start)); |
12806 | 159 | } |
12807 | 258 | if (has_query) { |
12808 | 71 | out.query.emplace(query); |
12809 | 71 | } |
12810 | 258 | if (has_hash) { |
12811 | 80 | out.hash.emplace(hash); |
12812 | 80 | } |
12813 | 258 | } |
12814 | 516 | return true; |
12815 | 712 | } bool ada::parser::try_parse_simple_relative<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url const&, ada::url&) Line | Count | Source | 12638 | 4.35k | result_type& out) { | 12639 | 4.35k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 12640 | 4.35k | constexpr bool is_aggregator = | 12641 | 4.35k | std::is_same_v<result_type, ada::url_aggregator>; | 12642 | 4.35k | static_assert(is_ada_url || is_aggregator); | 12643 | | | 12644 | 4.35k | if (!base.is_special() || base.type == ada::scheme::type::FILE || | 12645 | 2.70k | base.has_opaque_path || input.empty()) { | 12646 | 2.70k | return false; | 12647 | 2.70k | } | 12648 | 1.65k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 12649 | 1.65k | const size_t len = input.size(); | 12650 | 1.65k | const uint8_t first = b[0]; | 12651 | 1.65k | const bool path_relative = first != '/' && first != '?' && first != '#'; | 12652 | 1.65k | if (first == '/' && len > 1 && (b[1] == '/' || b[1] == '\\')) { | 12653 | 5 | return false; | 12654 | 5 | } | 12655 | | // A ':' before the first / ? # is a scheme, not a path segment. | 12656 | 1.64k | if (path_relative) { | 12657 | 1.42k | const size_t delim = input.find_first_of("/?#:"); | 12658 | 1.42k | if (delim != std::string_view::npos && input[delim] == ':') { | 12659 | 930 | return false; | 12660 | 930 | } | 12661 | 1.42k | } | 12662 | | | 12663 | 715 | size_t i = 0; | 12664 | 715 | size_t path_start = 0; | 12665 | 715 | size_t path_end = 0; | 12666 | 715 | size_t query_start = std::string_view::npos; | 12667 | 715 | size_t hash_start = std::string_view::npos; | 12668 | 715 | bool has_path = false; | 12669 | 715 | bool maybe_dot_segment = false; | 12670 | | | 12671 | 715 | if (first == '/' || path_relative) { | 12672 | 557 | has_path = true; | 12673 | 557 | path_start = 0; | 12674 | 557 | if (first == '/') { | 12675 | 67 | i = 1; | 12676 | 67 | } | 12677 | 557 | scan_path_run(b, i, len, maybe_dot_segment); | 12678 | 557 | if (i < len) { | 12679 | 325 | const uint8_t cls = k_path[b[i]]; | 12680 | 325 | if (cls == 2) { | 12681 | 157 | return false; | 12682 | 157 | } | 12683 | 325 | } | 12684 | 400 | path_end = i; | 12685 | 400 | if (i < len && b[i] == '?') { | 12686 | 114 | query_start = i; | 12687 | 114 | ++i; | 12688 | 114 | scan_query_run(b, i, len); | 12689 | 114 | if (i < len) { | 12690 | 89 | if (b[i] != '#') { | 12691 | 28 | return false; | 12692 | 28 | } | 12693 | 61 | hash_start = i; | 12694 | 61 | ++i; | 12695 | 61 | scan_hash_run(b, i, len); | 12696 | 61 | if (i < len) { | 12697 | 47 | return false; | 12698 | 47 | } | 12699 | 61 | } | 12700 | 286 | } else if (i < len && b[i] == '#') { | 12701 | 54 | hash_start = i; | 12702 | 54 | ++i; | 12703 | 54 | scan_hash_run(b, i, len); | 12704 | 54 | if (i < len) { | 12705 | 35 | return false; | 12706 | 35 | } | 12707 | 232 | } else if (i < len) { | 12708 | 0 | return false; | 12709 | 0 | } | 12710 | 400 | } else if (first == '?') { | 12711 | 106 | query_start = 0; | 12712 | 106 | i = 1; | 12713 | 106 | scan_query_run(b, i, len); | 12714 | 106 | if (i < len) { | 12715 | 88 | if (b[i] != '#') { | 12716 | 33 | return false; | 12717 | 33 | } | 12718 | 55 | hash_start = i; | 12719 | 55 | ++i; | 12720 | 55 | scan_hash_run(b, i, len); | 12721 | 55 | if (i < len) { | 12722 | 38 | return false; | 12723 | 38 | } | 12724 | 55 | } | 12725 | 106 | } else { | 12726 | 52 | hash_start = 0; | 12727 | 52 | i = 1; | 12728 | 52 | scan_hash_run(b, i, len); | 12729 | 52 | if (i < len) { | 12730 | 21 | return false; | 12731 | 21 | } | 12732 | 52 | } | 12733 | | | 12734 | 356 | if (has_path && maybe_dot_segment) { | 12735 | 118 | const std::string_view path_body(input.data() + path_start, | 12736 | 118 | path_end - path_start); | 12737 | 118 | if (path_has_dot_segment(path_body)) { | 12738 | 98 | return false; | 12739 | 98 | } | 12740 | 118 | } | 12741 | | | 12742 | 258 | out = base; | 12743 | 258 | out.is_valid = true; | 12744 | 258 | out.has_opaque_path = false; | 12745 | | | 12746 | 258 | const size_t q_end = | 12747 | 258 | (hash_start != std::string_view::npos) ? hash_start : len; | 12748 | 258 | const bool has_query = query_start != std::string_view::npos; | 12749 | 258 | const bool has_hash = hash_start != std::string_view::npos; | 12750 | 258 | const std::string_view query = | 12751 | 258 | has_query ? std::string_view(input.data() + query_start + 1, | 12752 | 71 | q_end - query_start - 1) | 12753 | 258 | : std::string_view{}; | 12754 | 258 | const std::string_view hash = | 12755 | 258 | has_hash ? std::string_view(input.data() + hash_start + 1, | 12756 | 80 | len - hash_start - 1) | 12757 | 258 | : std::string_view{}; | 12758 | | | 12759 | | if constexpr (is_aggregator) { | 12760 | | if (first == '/' || first == '?' || path_relative) { | 12761 | | out.clear_hash(); | 12762 | | out.clear_search(); | 12763 | | } | 12764 | | if (first == '/') { | 12765 | | out.update_base_pathname(input.substr(path_start, path_end - path_start)); | 12766 | | } else if (path_relative) { | 12767 | | const std::string_view base_path = out.get_pathname(); | 12768 | | const size_t slash = base_path.rfind('/'); | 12769 | | const std::string_view prefix = (slash == std::string_view::npos) | 12770 | | ? std::string_view("/") | 12771 | | : base_path.substr(0, slash + 1); | 12772 | | const std::string_view rel(input.data() + path_start, | 12773 | | path_end - path_start); | 12774 | | std::string new_path; | 12775 | | new_path.reserve(prefix.size() + rel.size()); | 12776 | | new_path.assign(prefix); | 12777 | | new_path.append(rel); | 12778 | | out.update_base_pathname(new_path); | 12779 | | } | 12780 | | if (has_query) { | 12781 | | // Do not use update_base_search: it strips a leading '?' and would | 12782 | | // collapse '??a=b' into '?a=b'. | 12783 | | out.components.search_start = static_cast<uint32_t>(out.buffer.size()); | 12784 | | out.buffer += '?'; | 12785 | | out.buffer.append(query); | 12786 | | } | 12787 | | if (has_hash) { | 12788 | | out.update_unencoded_base_hash(hash); | 12789 | | } | 12790 | 258 | } else { | 12791 | 258 | if (first == '/' || first == '?' || path_relative) { | 12792 | 227 | out.hash.reset(); | 12793 | 227 | } | 12794 | 258 | if (first == '/') { | 12795 | 33 | out.query.reset(); | 12796 | 33 | out.path.assign(input.substr(path_start, path_end - path_start)); | 12797 | 225 | } else if (path_relative) { | 12798 | 159 | out.query.reset(); | 12799 | 159 | const size_t slash = out.path.rfind('/'); | 12800 | 159 | if (slash == std::string::npos) { | 12801 | 0 | out.path = '/'; | 12802 | 159 | } else { | 12803 | 159 | out.path.resize(slash + 1); | 12804 | 159 | } | 12805 | 159 | out.path.append(input.substr(path_start, path_end - path_start)); | 12806 | 159 | } | 12807 | 258 | if (has_query) { | 12808 | 71 | out.query.emplace(query); | 12809 | 71 | } | 12810 | 258 | if (has_hash) { | 12811 | 80 | out.hash.emplace(hash); | 12812 | 80 | } | 12813 | 258 | } | 12814 | 258 | return true; | 12815 | 356 | } |
bool ada::parser::try_parse_simple_relative<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const&, ada::url_aggregator&) Line | Count | Source | 12638 | 4.35k | result_type& out) { | 12639 | 4.35k | constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>; | 12640 | 4.35k | constexpr bool is_aggregator = | 12641 | 4.35k | std::is_same_v<result_type, ada::url_aggregator>; | 12642 | 4.35k | static_assert(is_ada_url || is_aggregator); | 12643 | | | 12644 | 4.35k | if (!base.is_special() || base.type == ada::scheme::type::FILE || | 12645 | 2.70k | base.has_opaque_path || input.empty()) { | 12646 | 2.70k | return false; | 12647 | 2.70k | } | 12648 | 1.65k | const auto* b = reinterpret_cast<const uint8_t*>(input.data()); | 12649 | 1.65k | const size_t len = input.size(); | 12650 | 1.65k | const uint8_t first = b[0]; | 12651 | 1.65k | const bool path_relative = first != '/' && first != '?' && first != '#'; | 12652 | 1.65k | if (first == '/' && len > 1 && (b[1] == '/' || b[1] == '\\')) { | 12653 | 5 | return false; | 12654 | 5 | } | 12655 | | // A ':' before the first / ? # is a scheme, not a path segment. | 12656 | 1.64k | if (path_relative) { | 12657 | 1.42k | const size_t delim = input.find_first_of("/?#:"); | 12658 | 1.42k | if (delim != std::string_view::npos && input[delim] == ':') { | 12659 | 930 | return false; | 12660 | 930 | } | 12661 | 1.42k | } | 12662 | | | 12663 | 715 | size_t i = 0; | 12664 | 715 | size_t path_start = 0; | 12665 | 715 | size_t path_end = 0; | 12666 | 715 | size_t query_start = std::string_view::npos; | 12667 | 715 | size_t hash_start = std::string_view::npos; | 12668 | 715 | bool has_path = false; | 12669 | 715 | bool maybe_dot_segment = false; | 12670 | | | 12671 | 715 | if (first == '/' || path_relative) { | 12672 | 557 | has_path = true; | 12673 | 557 | path_start = 0; | 12674 | 557 | if (first == '/') { | 12675 | 67 | i = 1; | 12676 | 67 | } | 12677 | 557 | scan_path_run(b, i, len, maybe_dot_segment); | 12678 | 557 | if (i < len) { | 12679 | 325 | const uint8_t cls = k_path[b[i]]; | 12680 | 325 | if (cls == 2) { | 12681 | 157 | return false; | 12682 | 157 | } | 12683 | 325 | } | 12684 | 400 | path_end = i; | 12685 | 400 | if (i < len && b[i] == '?') { | 12686 | 114 | query_start = i; | 12687 | 114 | ++i; | 12688 | 114 | scan_query_run(b, i, len); | 12689 | 114 | if (i < len) { | 12690 | 89 | if (b[i] != '#') { | 12691 | 28 | return false; | 12692 | 28 | } | 12693 | 61 | hash_start = i; | 12694 | 61 | ++i; | 12695 | 61 | scan_hash_run(b, i, len); | 12696 | 61 | if (i < len) { | 12697 | 47 | return false; | 12698 | 47 | } | 12699 | 61 | } | 12700 | 286 | } else if (i < len && b[i] == '#') { | 12701 | 54 | hash_start = i; | 12702 | 54 | ++i; | 12703 | 54 | scan_hash_run(b, i, len); | 12704 | 54 | if (i < len) { | 12705 | 35 | return false; | 12706 | 35 | } | 12707 | 232 | } else if (i < len) { | 12708 | 0 | return false; | 12709 | 0 | } | 12710 | 400 | } else if (first == '?') { | 12711 | 106 | query_start = 0; | 12712 | 106 | i = 1; | 12713 | 106 | scan_query_run(b, i, len); | 12714 | 106 | if (i < len) { | 12715 | 88 | if (b[i] != '#') { | 12716 | 33 | return false; | 12717 | 33 | } | 12718 | 55 | hash_start = i; | 12719 | 55 | ++i; | 12720 | 55 | scan_hash_run(b, i, len); | 12721 | 55 | if (i < len) { | 12722 | 38 | return false; | 12723 | 38 | } | 12724 | 55 | } | 12725 | 106 | } else { | 12726 | 52 | hash_start = 0; | 12727 | 52 | i = 1; | 12728 | 52 | scan_hash_run(b, i, len); | 12729 | 52 | if (i < len) { | 12730 | 21 | return false; | 12731 | 21 | } | 12732 | 52 | } | 12733 | | | 12734 | 356 | if (has_path && maybe_dot_segment) { | 12735 | 118 | const std::string_view path_body(input.data() + path_start, | 12736 | 118 | path_end - path_start); | 12737 | 118 | if (path_has_dot_segment(path_body)) { | 12738 | 98 | return false; | 12739 | 98 | } | 12740 | 118 | } | 12741 | | | 12742 | 258 | out = base; | 12743 | 258 | out.is_valid = true; | 12744 | 258 | out.has_opaque_path = false; | 12745 | | | 12746 | 258 | const size_t q_end = | 12747 | 258 | (hash_start != std::string_view::npos) ? hash_start : len; | 12748 | 258 | const bool has_query = query_start != std::string_view::npos; | 12749 | 258 | const bool has_hash = hash_start != std::string_view::npos; | 12750 | 258 | const std::string_view query = | 12751 | 258 | has_query ? std::string_view(input.data() + query_start + 1, | 12752 | 71 | q_end - query_start - 1) | 12753 | 258 | : std::string_view{}; | 12754 | 258 | const std::string_view hash = | 12755 | 258 | has_hash ? std::string_view(input.data() + hash_start + 1, | 12756 | 80 | len - hash_start - 1) | 12757 | 258 | : std::string_view{}; | 12758 | | | 12759 | 258 | if constexpr (is_aggregator) { | 12760 | 258 | if (first == '/' || first == '?' || path_relative) { | 12761 | 227 | out.clear_hash(); | 12762 | 227 | out.clear_search(); | 12763 | 227 | } | 12764 | 258 | if (first == '/') { | 12765 | 33 | out.update_base_pathname(input.substr(path_start, path_end - path_start)); | 12766 | 225 | } else if (path_relative) { | 12767 | 159 | const std::string_view base_path = out.get_pathname(); | 12768 | 159 | const size_t slash = base_path.rfind('/'); | 12769 | 159 | const std::string_view prefix = (slash == std::string_view::npos) | 12770 | 159 | ? std::string_view("/") | 12771 | 159 | : base_path.substr(0, slash + 1); | 12772 | 159 | const std::string_view rel(input.data() + path_start, | 12773 | 159 | path_end - path_start); | 12774 | 159 | std::string new_path; | 12775 | 159 | new_path.reserve(prefix.size() + rel.size()); | 12776 | 159 | new_path.assign(prefix); | 12777 | 159 | new_path.append(rel); | 12778 | 159 | out.update_base_pathname(new_path); | 12779 | 159 | } | 12780 | 258 | if (has_query) { | 12781 | | // Do not use update_base_search: it strips a leading '?' and would | 12782 | | // collapse '??a=b' into '?a=b'. | 12783 | 71 | out.components.search_start = static_cast<uint32_t>(out.buffer.size()); | 12784 | 71 | out.buffer += '?'; | 12785 | 71 | out.buffer.append(query); | 12786 | 71 | } | 12787 | 258 | if (has_hash) { | 12788 | 80 | out.update_unencoded_base_hash(hash); | 12789 | 80 | } | 12790 | | } else { | 12791 | | if (first == '/' || first == '?' || path_relative) { | 12792 | | out.hash.reset(); | 12793 | | } | 12794 | | if (first == '/') { | 12795 | | out.query.reset(); | 12796 | | out.path.assign(input.substr(path_start, path_end - path_start)); | 12797 | | } else if (path_relative) { | 12798 | | out.query.reset(); | 12799 | | const size_t slash = out.path.rfind('/'); | 12800 | | if (slash == std::string::npos) { | 12801 | | out.path = '/'; | 12802 | | } else { | 12803 | | out.path.resize(slash + 1); | 12804 | | } | 12805 | | out.path.append(input.substr(path_start, path_end - path_start)); | 12806 | | } | 12807 | | if (has_query) { | 12808 | | out.query.emplace(query); | 12809 | | } | 12810 | | if (has_hash) { | 12811 | | out.hash.emplace(hash); | 12812 | | } | 12813 | | } | 12814 | 258 | return true; | 12815 | 356 | } |
|
12816 | | |
12817 | | template <class result_type, bool store_values> |
12818 | | result_type parse_url_impl(std::string_view user_input, |
12819 | 128k | const result_type* base_url) { |
12820 | | // We can specialize the implementation per type. |
12821 | | // Important: result_type_is_ada_url is evaluated at *compile time*. This |
12822 | | // means that doing if constexpr(result_type_is_ada_url) { something } else { |
12823 | | // something else } is free (at runtime). This means that ada::url_aggregator |
12824 | | // and ada::url **do not have to support the exact same API**. |
12825 | 128k | constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>; |
12826 | 128k | constexpr bool result_type_is_ada_url_aggregator = |
12827 | 128k | std::is_same_v<url_aggregator, result_type>; |
12828 | 128k | static_assert(result_type_is_ada_url || |
12829 | 128k | result_type_is_ada_url_aggregator); // We don't support |
12830 | | // anything else for now. |
12831 | | |
12832 | 128k | ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), |
12833 | 128k | " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), |
12834 | 128k | ")"); |
12835 | | |
12836 | 128k | result_type url{}; |
12837 | | |
12838 | 128k | const uint32_t max_input_length = ada::get_max_input_length(); |
12839 | | |
12840 | | // Normalization (percent-encoding, IDNA) can push the serialized URL past |
12841 | | // max_input_length even when the input fit under it. The check at the end of |
12842 | | // the state machine covers URLs that run to completion, but several states |
12843 | | // return early after appending a query or fragment, so run the same check on |
12844 | | // those exits too. Without this, a query- or fragment-terminated URL such as |
12845 | | // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent |
12846 | | // https://x/?<...> that takes the absolute fast path is rejected. |
12847 | 128k | const auto enforce_max_input_length = [&]() { |
12848 | 37.9k | if constexpr (store_values) { |
12849 | 37.6k | if (url.is_valid) { |
12850 | 37.6k | if constexpr (result_type_is_ada_url_aggregator) { |
12851 | 18.8k | if (url.buffer.size() > max_input_length) [[unlikely]] { |
12852 | 0 | url.is_valid = false; |
12853 | 0 | } |
12854 | 18.8k | } else { |
12855 | 18.8k | if (url.get_href_size() > max_input_length) [[unlikely]] { |
12856 | 0 | url.is_valid = false; |
12857 | 0 | } |
12858 | 18.8k | } |
12859 | 37.6k | } |
12860 | 37.6k | } |
12861 | 37.9k | }; ada::parser::parse_url_impl<ada::url, true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url const*)::{lambda()#1}::operator()() constLine | Count | Source | 12847 | 18.8k | const auto enforce_max_input_length = [&]() { | 12848 | 18.8k | if constexpr (store_values) { | 12849 | 18.8k | if (url.is_valid) { | 12850 | | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | | url.is_valid = false; | 12853 | | } | 12854 | 18.8k | } else { | 12855 | 18.8k | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | 0 | url.is_valid = false; | 12857 | 0 | } | 12858 | 18.8k | } | 12859 | 18.8k | } | 12860 | 18.8k | } | 12861 | 18.8k | }; |
ada::parser::parse_url_impl<ada::url_aggregator, true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*)::{lambda()#1}::operator()() constLine | Count | Source | 12847 | 18.8k | const auto enforce_max_input_length = [&]() { | 12848 | 18.8k | if constexpr (store_values) { | 12849 | 18.8k | if (url.is_valid) { | 12850 | 18.8k | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | 18.8k | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | 0 | url.is_valid = false; | 12853 | 0 | } | 12854 | | } else { | 12855 | | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | | url.is_valid = false; | 12857 | | } | 12858 | | } | 12859 | 18.8k | } | 12860 | 18.8k | } | 12861 | 18.8k | }; |
ada::parser::parse_url_impl<ada::url_aggregator, false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*)::{lambda()#1}::operator()() constLine | Count | Source | 12847 | 390 | const auto enforce_max_input_length = [&]() { | 12848 | | if constexpr (store_values) { | 12849 | | if (url.is_valid) { | 12850 | | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | | url.is_valid = false; | 12853 | | } | 12854 | | } else { | 12855 | | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | | url.is_valid = false; | 12857 | | } | 12858 | | } | 12859 | | } | 12860 | | } | 12861 | 390 | }; |
|
12862 | | |
12863 | | // We refuse to parse URL strings that exceed the maximum input length. |
12864 | | // By default, this is 4GB but can be configured via |
12865 | | // ada::set_max_input_length(). |
12866 | 128k | if (user_input.size() > max_input_length) [[unlikely]] { |
12867 | 0 | url.is_valid = false; |
12868 | 0 | } |
12869 | | // Going forward, user_input.size() is in [0, |
12870 | | // std::numeric_limits<uint32_t>::max). If we are provided with an invalid |
12871 | | // base, or the optional_url was invalid, we must return. |
12872 | 128k | if (base_url != nullptr) { |
12873 | 13.0k | url.is_valid &= base_url->is_valid; |
12874 | 13.0k | } |
12875 | 128k | if (!url.is_valid) { |
12876 | 0 | return url; |
12877 | 0 | } |
12878 | | |
12879 | | // Simple absolute / relative fast paths (before tabs/newline scan). |
12880 | 128k | if constexpr (store_values) { |
12881 | 98.0k | bool hit_fast_path = false; |
12882 | 98.0k | if (base_url == nullptr) { |
12883 | | // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline |
12884 | | // call so those URLs (including SetHref) do not pay for a miss. |
12885 | 89.3k | const auto* p = reinterpret_cast<const uint8_t*>(user_input.data()); |
12886 | 89.3k | const size_t n = user_input.size(); |
12887 | 89.3k | size_t host_start = 0; |
12888 | 89.3k | if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') { |
12889 | 4.49k | host_start = 7; |
12890 | 84.8k | } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') { |
12891 | 56 | host_start = 8; |
12892 | 56 | } |
12893 | 89.3k | const uint8_t host_first = host_start != 0 ? p[host_start] : 0; |
12894 | 89.3k | const bool skip_ip = |
12895 | 89.3k | host_first == '[' || (host_first >= '0' && host_first <= '9'); |
12896 | 89.3k | const bool skip_userinfo = |
12897 | 89.3k | host_start != 0 && authority_has_at(p, host_start, n); |
12898 | 89.3k | hit_fast_path = !skip_ip && !skip_userinfo && |
12899 | 88.0k | try_parse_simple_absolute(user_input, url); |
12900 | 89.3k | } else { |
12901 | 8.70k | hit_fast_path = try_parse_simple_relative(user_input, *base_url, url); |
12902 | 8.70k | } |
12903 | 98.0k | if (hit_fast_path) { |
12904 | 10.5k | if constexpr (result_type_is_ada_url_aggregator) { |
12905 | 5.25k | if (url.buffer.size() > max_input_length) [[unlikely]] { |
12906 | 0 | url.is_valid = false; |
12907 | 0 | } |
12908 | 5.25k | } else { |
12909 | | // For a small absolute input, even worst-case normalization cannot |
12910 | | // exceed the limit: percent encoding expands at most 3x and IDNA at |
12911 | | // most 4.5x. Avoid traversing every stored component on the common |
12912 | | // default-limit path. |
12913 | 5.25k | if ((base_url != nullptr || |
12914 | 4.99k | user_input.size() > static_cast<size_t>(max_input_length) / 5) && |
12915 | 258 | url.get_href_size() > max_input_length) [[unlikely]] { |
12916 | 0 | url.is_valid = false; |
12917 | 0 | } |
12918 | 5.25k | } |
12919 | 10.5k | return url; |
12920 | 10.5k | } |
12921 | 98.0k | } |
12922 | | |
12923 | 87.5k | state state = state::SCHEME_START; |
12924 | | |
12925 | 128k | std::string tmp_buffer; |
12926 | 128k | std::string_view url_data; |
12927 | 128k | if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { |
12928 | 1.08k | tmp_buffer = user_input; |
12929 | | // Optimization opportunity: Instead of copying and then pruning, we could |
12930 | | // just directly build the string from user_input. |
12931 | 1.08k | helpers::remove_ascii_tab_or_newline(tmp_buffer); |
12932 | 1.08k | url_data = tmp_buffer; |
12933 | 127k | } else [[likely]] { |
12934 | 127k | url_data = user_input; |
12935 | 127k | } |
12936 | | |
12937 | | // Leading and trailing control characters are uncommon and easy to deal with |
12938 | | // (no performance concern). |
12939 | 128k | helpers::trim_c0_whitespace(url_data); |
12940 | | |
12941 | 128k | if constexpr (result_type_is_ada_url_aggregator && store_values) { |
12942 | | // Most of the time, we just need user_input.size(). |
12943 | | // In some instances, we may need a bit more. |
12944 | | /////////////////////////// |
12945 | | // This is *very* important. This line should *not* be removed |
12946 | | // hastily. There are principled reasons why reserve is important |
12947 | | // for performance. If you have a benchmark with small inputs, |
12948 | | // it may not matter, but in other instances, it could. |
12949 | | //// |
12950 | | // This rounds up to the next power of two. |
12951 | | // We know that user_input.size() is in [0, |
12952 | | // std::numeric_limits<uint32_t>::max). |
12953 | 49.0k | uint32_t reserve_capacity = |
12954 | 49.0k | (0xFFFFFFFF >> |
12955 | 49.0k | helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + |
12956 | 49.0k | 1; |
12957 | 49.0k | url.reserve(reserve_capacity); |
12958 | 49.0k | } |
12959 | | |
12960 | | // Optimization opportunity. Most websites do not have fragment. |
12961 | 128k | std::optional<std::string_view> fragment = helpers::prune_hash(url_data); |
12962 | | // We add it last so that an implementation like ada::url_aggregator |
12963 | | // can append it last to its internal buffer, thus improving performance. |
12964 | | |
12965 | | // Here url_data no longer has its fragment. |
12966 | | // We are going to access the data from url_data (it is immutable). |
12967 | | // At any given time, we are pointing at byte 'input_position' in url_data. |
12968 | | // The input_position variable should range from 0 to input_size. |
12969 | | // It is illegal to access url_data at input_size. |
12970 | 128k | size_t input_position = 0; |
12971 | 128k | const size_t input_size = url_data.size(); |
12972 | | // Keep running the following state machine by switching on state. |
12973 | | // If after a run pointer points to the EOF code point, go to the next step. |
12974 | | // Otherwise, increase pointer by 1 and continue with the state machine. |
12975 | | // We never decrement input_position. |
12976 | 494k | while (input_position <= input_size) { |
12977 | 461k | ada_log("In parsing at ", input_position, " out of ", input_size, |
12978 | 461k | " in state ", ada::to_string(state)); |
12979 | 461k | switch (state) { |
12980 | 117k | case state::SCHEME_START: { |
12981 | 117k | ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); |
12982 | | // If c is an ASCII alpha, append c, lowercased, to buffer, and set |
12983 | | // state to scheme state. |
12984 | 117k | if ((input_position != input_size) && |
12985 | 68.7k | checkers::is_alpha(url_data[input_position])) { |
12986 | 65.2k | state = state::SCHEME; |
12987 | 65.2k | input_position++; |
12988 | 65.2k | } else { |
12989 | | // Otherwise, if state override is not given, set state to no scheme |
12990 | | // state and decrease pointer by 1. |
12991 | 52.6k | state = state::NO_SCHEME; |
12992 | 52.6k | } |
12993 | 117k | break; |
12994 | 0 | } |
12995 | 65.2k | case state::SCHEME: { |
12996 | 65.2k | ada_log("SCHEME ", helpers::substring(url_data, input_position)); |
12997 | | // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), |
12998 | | // append c, lowercased, to buffer. |
12999 | 160k | while ((input_position != input_size) && |
13000 | 159k | (unicode::is_alnum_plus(url_data[input_position]))) { |
13001 | 95.3k | input_position++; |
13002 | 95.3k | } |
13003 | | // Otherwise, if c is U+003A (:), then: |
13004 | 65.2k | if ((input_position != input_size) && |
13005 | 64.2k | (url_data[input_position] == ':')) { |
13006 | 63.1k | ada_log("SCHEME the scheme should be ", |
13007 | 63.1k | url_data.substr(0, input_position)); |
13008 | 63.1k | if constexpr (result_type_is_ada_url) { |
13009 | 21.0k | if (!url.parse_scheme(url_data.substr(0, input_position))) { |
13010 | 0 | return url; |
13011 | 0 | } |
13012 | 42.0k | } else { |
13013 | | // we pass the colon along instead of painfully adding it back. |
13014 | 42.0k | if (!url.parse_scheme_with_colon( |
13015 | 42.0k | url_data.substr(0, input_position + 1))) { |
13016 | 0 | return url; |
13017 | 0 | } |
13018 | 42.0k | } |
13019 | 63.1k | ada_log("SCHEME the scheme is ", url.get_protocol()); |
13020 | | |
13021 | | // If url's scheme is "file", then: |
13022 | | // NOLINTNEXTLINE(bugprone-branch-clone) |
13023 | 63.1k | if (url.type == scheme::type::FILE) { |
13024 | | // Set state to file state. |
13025 | 7.70k | state = state::FILE; |
13026 | 7.70k | } |
13027 | | // Otherwise, if url is special, base is non-null, and base's scheme |
13028 | | // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url |
13029 | | // != nullptr is false. |
13030 | 55.4k | else if (url.is_special() && base_url != nullptr && |
13031 | 6.72k | base_url->type == url.type) { |
13032 | | // Set state to special relative or authority state. |
13033 | 1.24k | state = state::SPECIAL_RELATIVE_OR_AUTHORITY; |
13034 | 1.24k | } |
13035 | | // Otherwise, if url is special, set state to special authority |
13036 | | // slashes state. |
13037 | 54.1k | else if (url.is_special()) { |
13038 | 38.0k | state = state::SPECIAL_AUTHORITY_SLASHES; |
13039 | 38.0k | } |
13040 | | // Otherwise, if remaining starts with an U+002F (/), set state to |
13041 | | // path or authority state and increase pointer by 1. |
13042 | 16.1k | else if (input_position + 1 < input_size && |
13043 | 9.30k | url_data[input_position + 1] == '/') { |
13044 | 6.58k | state = state::PATH_OR_AUTHORITY; |
13045 | 6.58k | input_position++; |
13046 | 6.58k | } |
13047 | | // Otherwise, set url's path to the empty string and set state to |
13048 | | // opaque path state. |
13049 | 9.52k | else { |
13050 | 9.52k | state = state::OPAQUE_PATH; |
13051 | 9.52k | } |
13052 | 63.1k | } |
13053 | | // Otherwise, if state override is not given, set buffer to the empty |
13054 | | // string, state to no scheme state, and start over (from the first code |
13055 | | // point in input). |
13056 | 2.07k | else { |
13057 | 2.07k | state = state::NO_SCHEME; |
13058 | 2.07k | input_position = 0; |
13059 | 2.07k | break; |
13060 | 2.07k | } |
13061 | 63.1k | input_position++; |
13062 | 63.1k | break; |
13063 | 65.2k | } |
13064 | 54.7k | case state::NO_SCHEME: { |
13065 | 54.7k | ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); |
13066 | | // The fragment was pruned from url_data before the state machine ran, |
13067 | | // so 'c is U+0023 (#)' holds exactly when a fragment was found and |
13068 | | // nothing else remains in front of it. |
13069 | 54.7k | const bool c_is_hash = |
13070 | 54.7k | fragment.has_value() && input_position == input_size; |
13071 | | // If base is null, or base has an opaque path and c is not U+0023 (#), |
13072 | | // validation error, return failure. |
13073 | 54.7k | if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) { |
13074 | 51.5k | ada_log("NO_SCHEME validation error"); |
13075 | 51.5k | url.is_valid = false; |
13076 | 51.5k | return url; |
13077 | 51.5k | } |
13078 | | // Otherwise, if base has an opaque path and c is U+0023 (#), |
13079 | | // set url's scheme to base's scheme, url's path to base's path, url's |
13080 | | // query to base's query, and set state to fragment state. |
13081 | 3.25k | else if (base_url->has_opaque_path && c_is_hash) { |
13082 | 135 | ada_log("NO_SCHEME opaque base with fragment"); |
13083 | 135 | url.copy_scheme(*base_url); |
13084 | 135 | url.has_opaque_path = base_url->has_opaque_path; |
13085 | | |
13086 | 135 | if constexpr (result_type_is_ada_url) { |
13087 | 45 | url.path = base_url->path; |
13088 | 45 | url.query = base_url->query; |
13089 | 90 | } else { |
13090 | 90 | url.update_base_pathname(base_url->get_pathname()); |
13091 | 90 | if (base_url->has_search()) { |
13092 | | // get_search() returns "" for an empty query string (URL ends |
13093 | | // with '?'). update_base_search("") would incorrectly clear the |
13094 | | // query, so pass "?" to preserve the empty query distinction. |
13095 | 21 | auto s = base_url->get_search(); |
13096 | 21 | url.update_base_search(s.empty() ? std::string_view("?") : s); |
13097 | 21 | } |
13098 | 90 | } |
13099 | 135 | url.update_unencoded_base_hash(*fragment); |
13100 | 135 | enforce_max_input_length(); |
13101 | 135 | return url; |
13102 | 135 | } |
13103 | | // Otherwise, if base's scheme is not "file", set state to relative |
13104 | | // state and decrease pointer by 1. |
13105 | | // NOLINTNEXTLINE(bugprone-branch-clone) |
13106 | 3.12k | else if (base_url->type != scheme::type::FILE) { |
13107 | 2.49k | ada_log("NO_SCHEME non-file relative path"); |
13108 | 2.49k | state = state::RELATIVE_SCHEME; |
13109 | 2.49k | } |
13110 | | // Otherwise, set state to file state and decrease pointer by 1. |
13111 | 627 | else { |
13112 | 627 | ada_log("NO_SCHEME file base type"); |
13113 | 627 | state = state::FILE; |
13114 | 627 | } |
13115 | 3.12k | break; |
13116 | 54.7k | } |
13117 | 41.7k | case state::AUTHORITY: { |
13118 | 41.7k | ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); |
13119 | | // most URLs have no @. Having no @ tells us that we don't have to worry |
13120 | | // about AUTHORITY. Of course, we could have @ and still not have to |
13121 | | // worry about AUTHORITY. |
13122 | | // TODO: Instead of just collecting a bool, collect the location of the |
13123 | | // '@' and do something useful with it. |
13124 | | // TODO: We could do various processing early on, using a single pass |
13125 | | // over the string to collect information about it, e.g., telling us |
13126 | | // whether there is a @ and if so, where (or how many). |
13127 | | |
13128 | | // Check if url data contains an @. |
13129 | 41.7k | if (url_data.find('@', input_position) == std::string_view::npos) { |
13130 | 38.0k | state = state::HOST; |
13131 | 38.0k | break; |
13132 | 38.0k | } |
13133 | 3.71k | bool at_sign_seen{false}; |
13134 | 3.71k | bool password_token_seen{false}; |
13135 | | /** |
13136 | | * We expect something of the sort... |
13137 | | * https://user:pass@example.com:1234/foo/bar?baz#quux |
13138 | | * --------^ |
13139 | | */ |
13140 | 22.8k | do { |
13141 | 22.8k | std::string_view view = url_data.substr(input_position); |
13142 | | // The delimiters are @, /, ? \\. |
13143 | 22.8k | size_t location = |
13144 | 22.8k | url.is_special() ? helpers::find_authority_delimiter_special(view) |
13145 | 22.8k | : helpers::find_authority_delimiter(view); |
13146 | 22.8k | std::string_view authority_view = view.substr(0, location); |
13147 | 22.8k | size_t end_of_authority = input_position + authority_view.size(); |
13148 | | // If c is U+0040 (@), then: |
13149 | 22.8k | if ((end_of_authority != input_size) && |
13150 | 20.5k | (url_data[end_of_authority] == '@')) { |
13151 | | // If atSignSeen is true, then prepend "%40" to buffer. |
13152 | 19.1k | if (at_sign_seen) { |
13153 | 15.8k | if (password_token_seen) { |
13154 | 6.65k | if constexpr (result_type_is_ada_url) { |
13155 | 2.21k | url.password += "%40"; |
13156 | 4.43k | } else { |
13157 | 4.43k | url.append_base_password("%40"); |
13158 | 4.43k | } |
13159 | 9.21k | } else { |
13160 | 9.21k | if constexpr (result_type_is_ada_url) { |
13161 | 3.07k | url.username += "%40"; |
13162 | 6.14k | } else { |
13163 | 6.14k | url.append_base_username("%40"); |
13164 | 6.14k | } |
13165 | 9.21k | } |
13166 | 15.8k | } |
13167 | | |
13168 | 19.1k | at_sign_seen = true; |
13169 | | |
13170 | 19.1k | if (!password_token_seen) { |
13171 | 12.4k | size_t password_token_location = authority_view.find(':'); |
13172 | 12.4k | password_token_seen = |
13173 | 12.4k | password_token_location != std::string_view::npos; |
13174 | | |
13175 | 12.4k | if constexpr (store_values) { |
13176 | 8.30k | if (!password_token_seen) { |
13177 | 7.50k | if constexpr (result_type_is_ada_url) { |
13178 | 3.75k | url.username += unicode::percent_encode( |
13179 | 3.75k | authority_view, |
13180 | 3.75k | character_sets::USERINFO_PERCENT_ENCODE); |
13181 | 3.75k | } else { |
13182 | 3.75k | url.append_base_username(unicode::percent_encode( |
13183 | 3.75k | authority_view, |
13184 | 3.75k | character_sets::USERINFO_PERCENT_ENCODE)); |
13185 | 3.75k | } |
13186 | 7.50k | } else { |
13187 | 802 | if constexpr (result_type_is_ada_url) { |
13188 | 401 | url.username += unicode::percent_encode( |
13189 | 401 | authority_view.substr(0, password_token_location), |
13190 | 401 | character_sets::USERINFO_PERCENT_ENCODE); |
13191 | 401 | url.password += unicode::percent_encode( |
13192 | 401 | authority_view.substr(password_token_location + 1), |
13193 | 401 | character_sets::USERINFO_PERCENT_ENCODE); |
13194 | 401 | } else { |
13195 | 401 | url.append_base_username(unicode::percent_encode( |
13196 | 401 | authority_view.substr(0, password_token_location), |
13197 | 401 | character_sets::USERINFO_PERCENT_ENCODE)); |
13198 | 401 | url.append_base_password(unicode::percent_encode( |
13199 | 401 | authority_view.substr(password_token_location + 1), |
13200 | 401 | character_sets::USERINFO_PERCENT_ENCODE)); |
13201 | 401 | } |
13202 | 802 | } |
13203 | 8.30k | } |
13204 | 12.4k | } else if constexpr (store_values) { |
13205 | 4.43k | if constexpr (result_type_is_ada_url) { |
13206 | 2.21k | url.password += unicode::percent_encode( |
13207 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE); |
13208 | 2.21k | } else { |
13209 | 2.21k | url.append_base_password(unicode::percent_encode( |
13210 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE)); |
13211 | 2.21k | } |
13212 | 4.43k | } |
13213 | 19.1k | } |
13214 | | // Otherwise, if one of the following is true: |
13215 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
13216 | | // - url is special and c is U+005C (\) |
13217 | 3.71k | else if (end_of_authority == input_size || |
13218 | 1.39k | url_data[end_of_authority] == '/' || |
13219 | 131 | url_data[end_of_authority] == '?' || |
13220 | 3.71k | (url.is_special() && url_data[end_of_authority] == '\\')) { |
13221 | | // If atSignSeen is true and authority_view is the empty string, |
13222 | | // validation error, return failure. |
13223 | 3.71k | if (at_sign_seen && authority_view.empty()) { |
13224 | 1.01k | url.is_valid = false; |
13225 | 1.01k | return url; |
13226 | 1.01k | } |
13227 | 2.70k | state = state::HOST; |
13228 | 2.70k | break; |
13229 | 3.71k | } |
13230 | 19.1k | if (end_of_authority == input_size) { |
13231 | 0 | if constexpr (store_values) { |
13232 | 0 | if (fragment.has_value()) { |
13233 | 0 | url.update_unencoded_base_hash(*fragment); |
13234 | 0 | } |
13235 | 0 | } |
13236 | 0 | enforce_max_input_length(); |
13237 | 0 | return url; |
13238 | 0 | } |
13239 | 19.1k | input_position = end_of_authority + 1; |
13240 | 19.1k | } while (true); |
13241 | | |
13242 | 2.70k | break; |
13243 | 3.71k | } |
13244 | 2.70k | case state::SPECIAL_RELATIVE_OR_AUTHORITY: { |
13245 | 1.24k | ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", |
13246 | 1.24k | helpers::substring(url_data, input_position)); |
13247 | | |
13248 | | // If c is U+002F (/) and remaining starts with U+002F (/), |
13249 | | // then set state to special authority ignore slashes state and increase |
13250 | | // pointer by 1. |
13251 | 1.24k | if (url_data.substr(input_position, 2) == "//") { |
13252 | 1.02k | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; |
13253 | 1.02k | input_position += 2; |
13254 | 1.02k | } else { |
13255 | | // Otherwise, validation error, set state to relative state and |
13256 | | // decrease pointer by 1. |
13257 | 216 | state = state::RELATIVE_SCHEME; |
13258 | 216 | } |
13259 | | |
13260 | 1.24k | break; |
13261 | 3.71k | } |
13262 | 6.58k | case state::PATH_OR_AUTHORITY: { |
13263 | 6.58k | ada_log("PATH_OR_AUTHORITY ", |
13264 | 6.58k | helpers::substring(url_data, input_position)); |
13265 | | |
13266 | | // If c is U+002F (/), then set state to authority state. |
13267 | 6.58k | if ((input_position != input_size) && |
13268 | 6.25k | (url_data[input_position] == '/')) { |
13269 | 2.66k | state = state::AUTHORITY; |
13270 | 2.66k | input_position++; |
13271 | 3.92k | } else { |
13272 | | // Otherwise, set state to path state, and decrease pointer by 1. |
13273 | 3.92k | state = state::PATH; |
13274 | 3.92k | } |
13275 | | |
13276 | 6.58k | break; |
13277 | 3.71k | } |
13278 | 2.70k | case state::RELATIVE_SCHEME: { |
13279 | 2.70k | ada_log("RELATIVE_SCHEME ", |
13280 | 2.70k | helpers::substring(url_data, input_position)); |
13281 | | |
13282 | | // Set url's scheme to base's scheme. |
13283 | 2.70k | url.copy_scheme(*base_url); |
13284 | | |
13285 | | // If c is U+002F (/), then set state to relative slash state. |
13286 | 2.70k | if ((input_position != input_size) && |
13287 | | // NOLINTNEXTLINE(bugprone-branch-clone) |
13288 | 2.23k | (url_data[input_position] == '/')) { |
13289 | 237 | ada_log( |
13290 | 237 | "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " |
13291 | 237 | "slash state"); |
13292 | 237 | state = state::RELATIVE_SLASH; |
13293 | 2.47k | } else if (url.is_special() && (input_position != input_size) && |
13294 | 1.71k | (url_data[input_position] == '\\')) { |
13295 | | // Otherwise, if url is special and c is U+005C (\), validation error, |
13296 | | // set state to relative slash state. |
13297 | 6 | ada_log( |
13298 | 6 | "RELATIVE_SCHEME if url is special and c is U+005C, validation " |
13299 | 6 | "error, set state to relative slash state"); |
13300 | 6 | state = state::RELATIVE_SLASH; |
13301 | 2.46k | } else { |
13302 | 2.46k | ada_log("RELATIVE_SCHEME otherwise"); |
13303 | | // Set url's username to base's username, url's password to base's |
13304 | | // password, url's host to base's host, url's port to base's port, |
13305 | | // url's path to a clone of base's path, and url's query to base's |
13306 | | // query. |
13307 | 2.46k | if constexpr (result_type_is_ada_url) { |
13308 | 747 | url.username = base_url->username; |
13309 | 747 | url.password = base_url->password; |
13310 | 747 | url.host = base_url->host; |
13311 | 747 | url.port = base_url->port; |
13312 | | // cloning the base path includes cloning the has_opaque_path flag |
13313 | 747 | url.has_opaque_path = base_url->has_opaque_path; |
13314 | 747 | url.path = base_url->path; |
13315 | 747 | url.query = base_url->query; |
13316 | 1.71k | } else { |
13317 | 1.71k | url.update_base_authority(base_url->get_href(), |
13318 | 1.71k | base_url->get_components()); |
13319 | 1.71k | url.update_host_to_base_host(base_url->get_hostname()); |
13320 | 1.71k | url.update_base_port(base_url->retrieve_base_port()); |
13321 | | // cloning the base path includes cloning the has_opaque_path flag |
13322 | 1.71k | url.has_opaque_path = base_url->has_opaque_path; |
13323 | 1.71k | url.update_base_pathname(base_url->get_pathname()); |
13324 | 1.71k | if (base_url->has_search()) { |
13325 | | // get_search() returns "" for an empty query string (URL ends |
13326 | | // with '?'). update_base_search("") would incorrectly clear the |
13327 | | // query, so pass "?" to preserve the empty query distinction. |
13328 | 85 | auto s = base_url->get_search(); |
13329 | 85 | url.update_base_search(s.empty() ? std::string_view("?") : s); |
13330 | 85 | } |
13331 | 1.71k | } |
13332 | | |
13333 | 2.46k | url.has_opaque_path = base_url->has_opaque_path; |
13334 | | |
13335 | | // If c is U+003F (?), then set url's query to the empty string, and |
13336 | | // state to query state. |
13337 | 2.46k | if ((input_position != input_size) && |
13338 | 1.99k | (url_data[input_position] == '?')) { |
13339 | 275 | state = state::QUERY; |
13340 | 275 | } |
13341 | | // Otherwise, if c is not the EOF code point: |
13342 | 2.19k | else if (input_position != input_size) { |
13343 | | // Set url's query to null. |
13344 | 1.71k | url.clear_search(); |
13345 | 1.71k | if constexpr (result_type_is_ada_url) { |
13346 | | // Shorten url's path. |
13347 | 519 | helpers::shorten_path(url.path, url.type); |
13348 | 1.19k | } else { |
13349 | 1.19k | std::string_view path = url.get_pathname(); |
13350 | 1.19k | if (helpers::shorten_path(path, url.type)) { |
13351 | 515 | url.update_base_pathname(std::move(std::string(path))); |
13352 | 515 | } |
13353 | 1.19k | } |
13354 | | // Set state to path state and decrease pointer by 1. |
13355 | 1.71k | state = state::PATH; |
13356 | 1.71k | break; |
13357 | 1.71k | } |
13358 | 2.46k | } |
13359 | 993 | input_position++; |
13360 | 993 | break; |
13361 | 2.70k | } |
13362 | 243 | case state::RELATIVE_SLASH: { |
13363 | 243 | ada_log("RELATIVE_SLASH ", |
13364 | 243 | helpers::substring(url_data, input_position)); |
13365 | | |
13366 | | // If url is special and c is U+002F (/) or U+005C (\), then: |
13367 | | // NOLINTNEXTLINE(bugprone-branch-clone) |
13368 | 243 | if (url.is_special() && (input_position != input_size) && |
13369 | 143 | (url_data[input_position] == '/' || |
13370 | 131 | url_data[input_position] == '\\')) { |
13371 | | // Set state to special authority ignore slashes state. |
13372 | 18 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; |
13373 | 18 | } |
13374 | | // Otherwise, if c is U+002F (/), then set state to authority state. |
13375 | 225 | else if ((input_position != input_size) && |
13376 | 155 | (url_data[input_position] == '/')) { |
13377 | 15 | state = state::AUTHORITY; |
13378 | 15 | } |
13379 | | // Otherwise, set |
13380 | | // - url's username to base's username, |
13381 | | // - url's password to base's password, |
13382 | | // - url's host to base's host, |
13383 | | // - url's port to base's port, |
13384 | | // - state to path state, and then, decrease pointer by 1. |
13385 | 210 | else { |
13386 | 210 | if constexpr (result_type_is_ada_url) { |
13387 | 59 | url.username = base_url->username; |
13388 | 59 | url.password = base_url->password; |
13389 | 59 | url.host = base_url->host; |
13390 | 59 | url.port = base_url->port; |
13391 | 151 | } else { |
13392 | 151 | url.update_base_authority(base_url->get_href(), |
13393 | 151 | base_url->get_components()); |
13394 | 151 | url.update_host_to_base_host(base_url->get_hostname()); |
13395 | 151 | url.update_base_port(base_url->retrieve_base_port()); |
13396 | 151 | } |
13397 | 210 | state = state::PATH; |
13398 | 210 | break; |
13399 | 210 | } |
13400 | | |
13401 | 33 | input_position++; |
13402 | 33 | break; |
13403 | 243 | } |
13404 | 38.0k | case state::SPECIAL_AUTHORITY_SLASHES: { |
13405 | 38.0k | ada_log("SPECIAL_AUTHORITY_SLASHES ", |
13406 | 38.0k | helpers::substring(url_data, input_position)); |
13407 | | |
13408 | | // If c is U+002F (/) and remaining starts with U+002F (/), |
13409 | | // then set state to special authority ignore slashes state and increase |
13410 | | // pointer by 1. |
13411 | 38.0k | if (url_data.substr(input_position, 2) == "//") { |
13412 | 9.69k | input_position += 2; |
13413 | 9.69k | } |
13414 | | |
13415 | 38.0k | [[fallthrough]]; |
13416 | 38.0k | } |
13417 | 39.1k | case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { |
13418 | 39.1k | ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", |
13419 | 39.1k | helpers::substring(url_data, input_position)); |
13420 | | |
13421 | | // If c is neither U+002F (/) nor U+005C (\), then set state to |
13422 | | // authority state and decrease pointer by 1. |
13423 | 41.8k | while ((input_position != input_size) && |
13424 | 41.5k | ((url_data[input_position] == '/') || |
13425 | 39.9k | (url_data[input_position] == '\\'))) { |
13426 | 2.69k | input_position++; |
13427 | 2.69k | } |
13428 | 39.1k | state = state::AUTHORITY; |
13429 | | |
13430 | 39.1k | break; |
13431 | 38.0k | } |
13432 | 2.47k | case state::QUERY: { |
13433 | 2.47k | ada_log("QUERY ", helpers::substring(url_data, input_position)); |
13434 | 2.47k | if constexpr (store_values) { |
13435 | | // Let queryPercentEncodeSet be the special-query percent-encode set |
13436 | | // if url is special; otherwise the query percent-encode set. |
13437 | 2.35k | const uint8_t* query_percent_encode_set = |
13438 | 2.35k | url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE |
13439 | 2.35k | : character_sets::QUERY_PERCENT_ENCODE; |
13440 | | |
13441 | | // Percent-encode after encoding, with encoding, buffer, and |
13442 | | // queryPercentEncodeSet, and append the result to url's query. |
13443 | 2.35k | url.update_base_search(url_data.substr(input_position), |
13444 | 2.35k | query_percent_encode_set); |
13445 | 2.35k | ada_log("QUERY update_base_search completed "); |
13446 | 2.35k | if (fragment.has_value()) { |
13447 | 614 | url.update_unencoded_base_hash(*fragment); |
13448 | 614 | } |
13449 | 2.35k | } |
13450 | 2.47k | enforce_max_input_length(); |
13451 | 2.47k | return url; |
13452 | 38.0k | } |
13453 | 40.7k | case state::HOST: { |
13454 | 40.7k | ada_log("HOST ", helpers::substring(url_data, input_position)); |
13455 | | |
13456 | 40.7k | std::string_view host_view = url_data.substr(input_position); |
13457 | 40.7k | auto [location, found_colon] = |
13458 | 40.7k | helpers::get_host_delimiter_location(url.is_special(), host_view); |
13459 | 40.7k | input_position = (location != std::string_view::npos) |
13460 | 40.7k | ? input_position + location |
13461 | 40.7k | : input_size; |
13462 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: |
13463 | | // Note: the 'found_colon' value is true if and only if a colon was |
13464 | | // encountered while not inside brackets. |
13465 | 40.7k | if (found_colon) { |
13466 | | // If buffer is the empty string, validation error, return failure. |
13467 | | // Let host be the result of host parsing buffer with url is not |
13468 | | // special. |
13469 | 7.46k | ada_log("HOST parsing ", host_view); |
13470 | 7.46k | if (!url.parse_host(host_view)) { |
13471 | 623 | return url; |
13472 | 623 | } |
13473 | 6.84k | ada_log("HOST parsing results in ", url.get_hostname()); |
13474 | | // Set url's host to host, buffer to the empty string, and state to |
13475 | | // port state. |
13476 | 6.84k | state = state::PORT; |
13477 | 6.84k | input_position++; |
13478 | 6.84k | } |
13479 | | // Otherwise, if one of the following is true: |
13480 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
13481 | | // - url is special and c is U+005C (\) |
13482 | | // The get_host_delimiter_location function either brings us to |
13483 | | // the colon outside of the bracket, or to one of those characters. |
13484 | 33.3k | else { |
13485 | | // If url is special and host_view is the empty string, validation |
13486 | | // error, return failure. |
13487 | 33.3k | if (host_view.empty() && url.is_special()) { |
13488 | 242 | url.is_valid = false; |
13489 | 242 | return url; |
13490 | 242 | } |
13491 | 33.0k | ada_log("HOST parsing ", host_view, " href=", url.get_href()); |
13492 | | // Let host be the result of host parsing host_view with url is not |
13493 | | // special. |
13494 | 33.0k | if (host_view.empty()) { |
13495 | 393 | url.update_base_hostname(""); |
13496 | 32.6k | } else if (!url.parse_host(host_view)) { |
13497 | 6.89k | return url; |
13498 | 6.89k | } |
13499 | 26.1k | ada_log("HOST parsing results in ", url.get_hostname(), |
13500 | 26.1k | " href=", url.get_href()); |
13501 | | |
13502 | | // Set url's host to host, and state to path start state. |
13503 | 26.1k | state = state::PATH_START; |
13504 | 26.1k | } |
13505 | | |
13506 | 33.0k | break; |
13507 | 40.7k | } |
13508 | 33.0k | case state::OPAQUE_PATH: { |
13509 | 9.52k | ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); |
13510 | | // Opaque path, query, and fragment are structurally always valid: |
13511 | | // the parser would just percent-encode whatever is there. When we |
13512 | | // are not storing values (can_parse), we can return immediately. |
13513 | | // We must set has_opaque_path = true before returning so that when |
13514 | | // this URL is used as an internal base inside can_parse, NO_SCHEME |
13515 | | // correctly rejects relative inputs against an opaque-path base |
13516 | | // (e.g. can_parse("", &"W:") must return false). |
13517 | 9.52k | if constexpr (!store_values) { |
13518 | 3.17k | url.has_opaque_path = true; |
13519 | 3.17k | return url; |
13520 | 3.17k | } |
13521 | 0 | std::string_view view = url_data.substr(input_position); |
13522 | | // If c is U+003F (?), then set url's query to the empty string and |
13523 | | // state to query state. |
13524 | 9.52k | size_t location = view.find('?'); |
13525 | 9.52k | if (location != std::string_view::npos) { |
13526 | 562 | view.remove_suffix(view.size() - location); |
13527 | 562 | state = state::QUERY; |
13528 | 562 | input_position += location + 1; |
13529 | 8.96k | } else { |
13530 | 8.96k | input_position = input_size + 1; |
13531 | 8.96k | } |
13532 | 9.52k | url.has_opaque_path = true; |
13533 | | |
13534 | | // This is a really unlikely scenario in real world. We should not seek |
13535 | | // to optimize it. |
13536 | 9.52k | if (view.ends_with(' ')) { |
13537 | 224 | std::string modified_view = |
13538 | 224 | std::string(view.substr(0, view.size() - 1)) + "%20"; |
13539 | 224 | url.update_base_pathname(unicode::percent_encode( |
13540 | 224 | modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); |
13541 | 9.30k | } else { |
13542 | 9.30k | url.update_base_pathname(unicode::percent_encode( |
13543 | 9.30k | view, character_sets::C0_CONTROL_PERCENT_ENCODE)); |
13544 | 9.30k | } |
13545 | 9.52k | break; |
13546 | 40.7k | } |
13547 | 6.84k | case state::PORT: { |
13548 | 6.84k | ada_log("PORT ", helpers::substring(url_data, input_position)); |
13549 | 6.84k | std::string_view port_view = url_data.substr(input_position); |
13550 | 6.84k | input_position += url.parse_port(port_view, true); |
13551 | 6.84k | if (!url.is_valid) { |
13552 | 334 | return url; |
13553 | 334 | } |
13554 | 6.51k | state = state::PATH_START; |
13555 | 6.51k | [[fallthrough]]; |
13556 | 6.51k | } |
13557 | 38.3k | case state::PATH_START: { |
13558 | 38.3k | ada_log("PATH_START ", helpers::substring(url_data, input_position)); |
13559 | | // Path, query, and fragment are structurally always valid: the |
13560 | | // parser would just percent-encode whatever is there. When we are |
13561 | | // not storing values (can_parse), we can return immediately since |
13562 | | // no subsequent state can invalidate the URL. |
13563 | 38.3k | if constexpr (!store_values) { |
13564 | 12.8k | return url; |
13565 | 12.8k | } |
13566 | | |
13567 | | // If url is special, then: |
13568 | 38.3k | if (url.is_special()) { |
13569 | | // Set state to path state. |
13570 | 24.0k | state = state::PATH; |
13571 | | |
13572 | | // Optimization: Avoiding going into PATH state improves the |
13573 | | // performance of urls ending with /. |
13574 | 24.0k | if (input_position == input_size) { |
13575 | 12.8k | if constexpr (store_values) { |
13576 | 12.8k | url.update_base_pathname("/"); |
13577 | 12.8k | if (fragment.has_value()) { |
13578 | 332 | url.update_unencoded_base_hash(*fragment); |
13579 | 332 | } |
13580 | 12.8k | } |
13581 | 12.8k | enforce_max_input_length(); |
13582 | 12.8k | return url; |
13583 | 12.8k | } |
13584 | | // If c is neither U+002F (/) nor U+005C (\), then decrease pointer |
13585 | | // by 1. We know that (input_position == input_size) is impossible |
13586 | | // here, because of the previous if-check. |
13587 | 11.1k | if ((url_data[input_position] != '/') && |
13588 | 774 | (url_data[input_position] != '\\')) { |
13589 | 746 | break; |
13590 | 746 | } |
13591 | 11.1k | } |
13592 | | // Otherwise, if state override is not given and c is U+003F (?), |
13593 | | // set url's query to the empty string and state to query state. |
13594 | 14.3k | else if ((input_position != input_size) && |
13595 | 320 | (url_data[input_position] == '?')) { |
13596 | 102 | state = state::QUERY; |
13597 | 102 | } |
13598 | | // Otherwise, if c is not the EOF code point: |
13599 | 14.2k | else if (input_position != input_size) { |
13600 | | // Set state to path state. |
13601 | 218 | state = state::PATH; |
13602 | | |
13603 | | // If c is not U+002F (/), then decrease pointer by 1. |
13604 | 218 | if (url_data[input_position] != '/') { |
13605 | 0 | break; |
13606 | 0 | } |
13607 | 218 | } |
13608 | | |
13609 | 24.7k | input_position++; |
13610 | 24.7k | break; |
13611 | 38.3k | } |
13612 | 19.1k | case state::PATH: { |
13613 | 19.1k | ada_log("PATH ", helpers::substring(url_data, input_position)); |
13614 | | // Path, query, and fragment are structurally always valid: the |
13615 | | // parser would just percent-encode whatever is there. When we are |
13616 | | // not storing values (can_parse), we can return immediately since |
13617 | | // no subsequent state can invalidate the URL. |
13618 | 19.1k | if constexpr (!store_values) { |
13619 | 2.72k | return url; |
13620 | 2.72k | } |
13621 | 0 | std::string_view view = url_data.substr(input_position); |
13622 | | |
13623 | | // Most time, we do not need percent encoding. |
13624 | | // Furthermore, we can immediately locate the '?'. |
13625 | 19.1k | size_t locofquestionmark = view.find('?'); |
13626 | 19.1k | if (locofquestionmark != std::string_view::npos) { |
13627 | 1.52k | state = state::QUERY; |
13628 | 1.52k | view.remove_suffix(view.size() - locofquestionmark); |
13629 | 1.52k | input_position += locofquestionmark + 1; |
13630 | 17.6k | } else { |
13631 | 17.6k | input_position = input_size + 1; |
13632 | 17.6k | } |
13633 | 19.1k | if constexpr (store_values) { |
13634 | 16.4k | if constexpr (result_type_is_ada_url) { |
13635 | 8.23k | helpers::parse_prepared_path(view, url.type, url.path); |
13636 | 8.23k | } else { |
13637 | 8.23k | url.consume_prepared_path(view); |
13638 | 8.23k | ADA_ASSERT_TRUE(url.validate()); |
13639 | 8.23k | } |
13640 | 16.4k | } |
13641 | 19.1k | break; |
13642 | 38.3k | } |
13643 | 6.60k | case state::FILE_SLASH: { |
13644 | 6.60k | ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); |
13645 | | |
13646 | | // If c is U+002F (/) or U+005C (\), then: |
13647 | 6.60k | if ((input_position != input_size) && |
13648 | 6.40k | (url_data[input_position] == '/' || |
13649 | 6.27k | url_data[input_position] == '\\')) { |
13650 | 6.27k | ada_log("FILE_SLASH c is U+002F or U+005C"); |
13651 | | // Set state to file host state. |
13652 | 6.27k | state = state::FILE_HOST; |
13653 | 6.27k | input_position++; |
13654 | 6.27k | } else { |
13655 | 330 | ada_log("FILE_SLASH otherwise"); |
13656 | | // If base is non-null and base's scheme is "file", then: |
13657 | | // Note: it is unsafe to do base_url->scheme unless you know that |
13658 | | // base_url_has_value() is true. |
13659 | 330 | if (base_url != nullptr && base_url->type == scheme::type::FILE) { |
13660 | | // Set url's host to base's host. |
13661 | 258 | if constexpr (result_type_is_ada_url) { |
13662 | 86 | url.host = base_url->host; |
13663 | 172 | } else { |
13664 | 172 | url.update_host_to_base_host(base_url->get_host()); |
13665 | 172 | } |
13666 | | // If the code point substring from pointer to the end of input does |
13667 | | // not start with a Windows drive letter and base's path[0] is a |
13668 | | // normalized Windows drive letter, then append base's path[0] to |
13669 | | // url's path. |
13670 | 258 | if (!base_url->get_pathname().empty()) { |
13671 | 172 | if (!checkers::is_windows_drive_letter( |
13672 | 172 | url_data.substr(input_position))) { |
13673 | 162 | std::string_view first_base_url_path = |
13674 | 162 | base_url->get_pathname().substr(1); |
13675 | 162 | size_t loc = first_base_url_path.find('/'); |
13676 | 162 | if (loc != std::string_view::npos) { |
13677 | 22 | helpers::resize(first_base_url_path, loc); |
13678 | 22 | } |
13679 | 162 | if (checkers::is_normalized_windows_drive_letter( |
13680 | 162 | first_base_url_path)) { |
13681 | 4 | if constexpr (result_type_is_ada_url) { |
13682 | 2 | url.path += '/'; |
13683 | 2 | url.path += first_base_url_path; |
13684 | 2 | } else { |
13685 | 2 | url.append_base_pathname( |
13686 | 2 | helpers::concat("/", first_base_url_path)); |
13687 | 2 | } |
13688 | 4 | } |
13689 | 162 | } |
13690 | 172 | } |
13691 | 258 | } |
13692 | | |
13693 | | // Set state to path state, and decrease pointer by 1. |
13694 | 330 | state = state::PATH; |
13695 | 330 | } |
13696 | | |
13697 | 6.60k | break; |
13698 | 38.3k | } |
13699 | 6.27k | case state::FILE_HOST: { |
13700 | 6.27k | ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); |
13701 | 6.27k | std::string_view view = url_data.substr(input_position); |
13702 | | |
13703 | 6.27k | size_t location = view.find_first_of("/\\?"); |
13704 | 6.27k | std::string_view file_host_buffer = view.substr( |
13705 | 6.27k | 0, (location != std::string_view::npos) ? location : view.size()); |
13706 | | |
13707 | 6.27k | if (checkers::is_windows_drive_letter(file_host_buffer)) { |
13708 | 36 | state = state::PATH; |
13709 | 6.24k | } else if (file_host_buffer.empty()) { |
13710 | | // Set url's host to the empty string. |
13711 | 771 | if constexpr (result_type_is_ada_url) { |
13712 | 257 | url.host = ""; |
13713 | 514 | } else { |
13714 | 514 | url.update_base_hostname(""); |
13715 | 514 | } |
13716 | | // Set state to path start state. |
13717 | 771 | state = state::PATH_START; |
13718 | 5.47k | } else { |
13719 | 5.47k | size_t consumed_bytes = file_host_buffer.size(); |
13720 | 5.47k | input_position += consumed_bytes; |
13721 | | // Let host be the result of host parsing buffer with url is not |
13722 | | // special. |
13723 | 5.47k | if (!url.parse_host(file_host_buffer)) { |
13724 | 564 | return url; |
13725 | 564 | } |
13726 | | |
13727 | 4.90k | if constexpr (result_type_is_ada_url) { |
13728 | | // If host is "localhost", then set host to the empty string. |
13729 | 1.63k | if (url.host.has_value() && url.host.value() == "localhost") { |
13730 | 12 | url.host = ""; |
13731 | 12 | } |
13732 | 3.27k | } else { |
13733 | 3.27k | if (url.get_hostname() == "localhost") { |
13734 | 24 | url.update_base_hostname(""); |
13735 | 24 | } |
13736 | 3.27k | } |
13737 | | |
13738 | | // Set buffer to the empty string and state to path start state. |
13739 | 4.90k | state = state::PATH_START; |
13740 | 4.90k | } |
13741 | | |
13742 | 5.71k | break; |
13743 | 6.27k | } |
13744 | 8.33k | case state::FILE: { |
13745 | 8.33k | ada_log("FILE ", helpers::substring(url_data, input_position)); |
13746 | 8.33k | std::string_view file_view = url_data.substr(input_position); |
13747 | | |
13748 | 8.33k | url.set_protocol_as_file(); |
13749 | 8.33k | if constexpr (result_type_is_ada_url) { |
13750 | | // Set url's host to the empty string. |
13751 | 2.77k | url.host = ""; |
13752 | 5.55k | } else { |
13753 | 5.55k | url.update_base_hostname(""); |
13754 | 5.55k | } |
13755 | | // If c is U+002F (/) or U+005C (\), then: |
13756 | 8.33k | if (input_position != input_size && |
13757 | 8.00k | (url_data[input_position] == '/' || |
13758 | 6.60k | url_data[input_position] == '\\')) { |
13759 | 6.60k | ada_log("FILE c is U+002F or U+005C"); |
13760 | | // Set state to file slash state. |
13761 | 6.60k | state = state::FILE_SLASH; |
13762 | 6.60k | } |
13763 | | // Otherwise, if base is non-null and base's scheme is "file": |
13764 | 1.72k | else if (base_url != nullptr && base_url->type == scheme::type::FILE) { |
13765 | | // Set url's host to base's host, url's path to a clone of base's |
13766 | | // path, and url's query to base's query. |
13767 | 420 | ada_log("FILE base non-null"); |
13768 | 420 | if constexpr (result_type_is_ada_url) { |
13769 | 140 | url.host = base_url->host; |
13770 | 140 | url.path = base_url->path; |
13771 | 140 | url.query = base_url->query; |
13772 | 280 | } else { |
13773 | 280 | url.update_host_to_base_host(base_url->get_hostname()); |
13774 | 280 | url.update_base_pathname(base_url->get_pathname()); |
13775 | 280 | if (base_url->has_search()) { |
13776 | | // get_search() returns "" for an empty query string (URL ends |
13777 | | // with '?'). update_base_search("") would incorrectly clear the |
13778 | | // query, so pass "?" to preserve the empty query distinction. |
13779 | 43 | auto s = base_url->get_search(); |
13780 | 43 | url.update_base_search(s.empty() ? std::string_view("?") : s); |
13781 | 43 | } |
13782 | 280 | } |
13783 | 420 | url.has_opaque_path = base_url->has_opaque_path; |
13784 | | |
13785 | | // If c is U+003F (?), then set url's query to the empty string and |
13786 | | // state to query state. |
13787 | 420 | if (input_position != input_size && url_data[input_position] == '?') { |
13788 | 12 | state = state::QUERY; |
13789 | 12 | } |
13790 | | // Otherwise, if c is not the EOF code point: |
13791 | 408 | else if (input_position != input_size) { |
13792 | | // Set url's query to null. |
13793 | 267 | url.clear_search(); |
13794 | | // If the code point substring from pointer to the end of input does |
13795 | | // not start with a Windows drive letter, then shorten url's path. |
13796 | 267 | if (!checkers::is_windows_drive_letter(file_view)) { |
13797 | 228 | if constexpr (result_type_is_ada_url) { |
13798 | 76 | helpers::shorten_path(url.path, url.type); |
13799 | 152 | } else { |
13800 | 152 | std::string_view path = url.get_pathname(); |
13801 | 152 | if (helpers::shorten_path(path, url.type)) { |
13802 | 74 | url.update_base_pathname(std::move(std::string(path))); |
13803 | 74 | } |
13804 | 152 | } |
13805 | 228 | } |
13806 | | // Otherwise: |
13807 | 39 | else { |
13808 | | // Set url's path to an empty list. |
13809 | 39 | url.clear_pathname(); |
13810 | 39 | url.has_opaque_path = true; |
13811 | 39 | } |
13812 | | |
13813 | | // Set state to path state and decrease pointer by 1. |
13814 | 267 | state = state::PATH; |
13815 | 267 | break; |
13816 | 267 | } |
13817 | 420 | } |
13818 | | // Otherwise, set state to path state, and decrease pointer by 1. |
13819 | 1.30k | else { |
13820 | 1.30k | ada_log("FILE go to path"); |
13821 | 1.30k | state = state::PATH; |
13822 | 1.30k | break; |
13823 | 1.30k | } |
13824 | | |
13825 | 6.76k | input_position++; |
13826 | 6.76k | break; |
13827 | 8.33k | } |
13828 | 0 | default: |
13829 | 0 | unreachable(); |
13830 | 461k | } |
13831 | 461k | } |
13832 | 33.0k | if constexpr (store_values) { |
13833 | 32.8k | if (fragment.has_value()) { |
13834 | 692 | url.update_unencoded_base_hash(*fragment); |
13835 | 692 | } |
13836 | 32.8k | } |
13837 | 33.0k | enforce_max_input_length(); |
13838 | 33.0k | return url; |
13839 | 128k | } ada::url ada::parser::parse_url_impl<ada::url, true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url const*) Line | Count | Source | 12819 | 49.0k | const result_type* base_url) { | 12820 | | // We can specialize the implementation per type. | 12821 | | // Important: result_type_is_ada_url is evaluated at *compile time*. This | 12822 | | // means that doing if constexpr(result_type_is_ada_url) { something } else { | 12823 | | // something else } is free (at runtime). This means that ada::url_aggregator | 12824 | | // and ada::url **do not have to support the exact same API**. | 12825 | 49.0k | constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>; | 12826 | 49.0k | constexpr bool result_type_is_ada_url_aggregator = | 12827 | 49.0k | std::is_same_v<url_aggregator, result_type>; | 12828 | 49.0k | static_assert(result_type_is_ada_url || | 12829 | 49.0k | result_type_is_ada_url_aggregator); // We don't support | 12830 | | // anything else for now. | 12831 | | | 12832 | 49.0k | ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), | 12833 | 49.0k | " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), | 12834 | 49.0k | ")"); | 12835 | | | 12836 | 49.0k | result_type url{}; | 12837 | | | 12838 | 49.0k | const uint32_t max_input_length = ada::get_max_input_length(); | 12839 | | | 12840 | | // Normalization (percent-encoding, IDNA) can push the serialized URL past | 12841 | | // max_input_length even when the input fit under it. The check at the end of | 12842 | | // the state machine covers URLs that run to completion, but several states | 12843 | | // return early after appending a query or fragment, so run the same check on | 12844 | | // those exits too. Without this, a query- or fragment-terminated URL such as | 12845 | | // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent | 12846 | | // https://x/?<...> that takes the absolute fast path is rejected. | 12847 | 49.0k | const auto enforce_max_input_length = [&]() { | 12848 | 49.0k | if constexpr (store_values) { | 12849 | 49.0k | if (url.is_valid) { | 12850 | 49.0k | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | 49.0k | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | 49.0k | url.is_valid = false; | 12853 | 49.0k | } | 12854 | 49.0k | } else { | 12855 | 49.0k | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | 49.0k | url.is_valid = false; | 12857 | 49.0k | } | 12858 | 49.0k | } | 12859 | 49.0k | } | 12860 | 49.0k | } | 12861 | 49.0k | }; | 12862 | | | 12863 | | // We refuse to parse URL strings that exceed the maximum input length. | 12864 | | // By default, this is 4GB but can be configured via | 12865 | | // ada::set_max_input_length(). | 12866 | 49.0k | if (user_input.size() > max_input_length) [[unlikely]] { | 12867 | 0 | url.is_valid = false; | 12868 | 0 | } | 12869 | | // Going forward, user_input.size() is in [0, | 12870 | | // std::numeric_limits<uint32_t>::max). If we are provided with an invalid | 12871 | | // base, or the optional_url was invalid, we must return. | 12872 | 49.0k | if (base_url != nullptr) { | 12873 | 4.35k | url.is_valid &= base_url->is_valid; | 12874 | 4.35k | } | 12875 | 49.0k | if (!url.is_valid) { | 12876 | 0 | return url; | 12877 | 0 | } | 12878 | | | 12879 | | // Simple absolute / relative fast paths (before tabs/newline scan). | 12880 | 49.0k | if constexpr (store_values) { | 12881 | 49.0k | bool hit_fast_path = false; | 12882 | 49.0k | if (base_url == nullptr) { | 12883 | | // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline | 12884 | | // call so those URLs (including SetHref) do not pay for a miss. | 12885 | 44.6k | const auto* p = reinterpret_cast<const uint8_t*>(user_input.data()); | 12886 | 44.6k | const size_t n = user_input.size(); | 12887 | 44.6k | size_t host_start = 0; | 12888 | 44.6k | if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') { | 12889 | 2.24k | host_start = 7; | 12890 | 42.4k | } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') { | 12891 | 28 | host_start = 8; | 12892 | 28 | } | 12893 | 44.6k | const uint8_t host_first = host_start != 0 ? p[host_start] : 0; | 12894 | 44.6k | const bool skip_ip = | 12895 | 44.6k | host_first == '[' || (host_first >= '0' && host_first <= '9'); | 12896 | 44.6k | const bool skip_userinfo = | 12897 | 44.6k | host_start != 0 && authority_has_at(p, host_start, n); | 12898 | 44.6k | hit_fast_path = !skip_ip && !skip_userinfo && | 12899 | 44.0k | try_parse_simple_absolute(user_input, url); | 12900 | 44.6k | } else { | 12901 | 4.35k | hit_fast_path = try_parse_simple_relative(user_input, *base_url, url); | 12902 | 4.35k | } | 12903 | 49.0k | if (hit_fast_path) { | 12904 | | if constexpr (result_type_is_ada_url_aggregator) { | 12905 | | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12906 | | url.is_valid = false; | 12907 | | } | 12908 | 5.25k | } else { | 12909 | | // For a small absolute input, even worst-case normalization cannot | 12910 | | // exceed the limit: percent encoding expands at most 3x and IDNA at | 12911 | | // most 4.5x. Avoid traversing every stored component on the common | 12912 | | // default-limit path. | 12913 | 5.25k | if ((base_url != nullptr || | 12914 | 4.99k | user_input.size() > static_cast<size_t>(max_input_length) / 5) && | 12915 | 258 | url.get_href_size() > max_input_length) [[unlikely]] { | 12916 | 0 | url.is_valid = false; | 12917 | 0 | } | 12918 | 5.25k | } | 12919 | 5.25k | return url; | 12920 | 5.25k | } | 12921 | 49.0k | } | 12922 | | | 12923 | 43.7k | state state = state::SCHEME_START; | 12924 | | | 12925 | 49.0k | std::string tmp_buffer; | 12926 | 49.0k | std::string_view url_data; | 12927 | 49.0k | if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { | 12928 | 404 | tmp_buffer = user_input; | 12929 | | // Optimization opportunity: Instead of copying and then pruning, we could | 12930 | | // just directly build the string from user_input. | 12931 | 404 | helpers::remove_ascii_tab_or_newline(tmp_buffer); | 12932 | 404 | url_data = tmp_buffer; | 12933 | 48.6k | } else [[likely]] { | 12934 | 48.6k | url_data = user_input; | 12935 | 48.6k | } | 12936 | | | 12937 | | // Leading and trailing control characters are uncommon and easy to deal with | 12938 | | // (no performance concern). | 12939 | 49.0k | helpers::trim_c0_whitespace(url_data); | 12940 | | | 12941 | | if constexpr (result_type_is_ada_url_aggregator && store_values) { | 12942 | | // Most of the time, we just need user_input.size(). | 12943 | | // In some instances, we may need a bit more. | 12944 | | /////////////////////////// | 12945 | | // This is *very* important. This line should *not* be removed | 12946 | | // hastily. There are principled reasons why reserve is important | 12947 | | // for performance. If you have a benchmark with small inputs, | 12948 | | // it may not matter, but in other instances, it could. | 12949 | | //// | 12950 | | // This rounds up to the next power of two. | 12951 | | // We know that user_input.size() is in [0, | 12952 | | // std::numeric_limits<uint32_t>::max). | 12953 | | uint32_t reserve_capacity = | 12954 | | (0xFFFFFFFF >> | 12955 | | helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + | 12956 | | 1; | 12957 | | url.reserve(reserve_capacity); | 12958 | | } | 12959 | | | 12960 | | // Optimization opportunity. Most websites do not have fragment. | 12961 | 49.0k | std::optional<std::string_view> fragment = helpers::prune_hash(url_data); | 12962 | | // We add it last so that an implementation like ada::url_aggregator | 12963 | | // can append it last to its internal buffer, thus improving performance. | 12964 | | | 12965 | | // Here url_data no longer has its fragment. | 12966 | | // We are going to access the data from url_data (it is immutable). | 12967 | | // At any given time, we are pointing at byte 'input_position' in url_data. | 12968 | | // The input_position variable should range from 0 to input_size. | 12969 | | // It is illegal to access url_data at input_size. | 12970 | 49.0k | size_t input_position = 0; | 12971 | 49.0k | const size_t input_size = url_data.size(); | 12972 | | // Keep running the following state machine by switching on state. | 12973 | | // If after a run pointer points to the EOF code point, go to the next step. | 12974 | | // Otherwise, increase pointer by 1 and continue with the state machine. | 12975 | | // We never decrement input_position. | 12976 | 181k | while (input_position <= input_size) { | 12977 | 164k | ada_log("In parsing at ", input_position, " out of ", input_size, | 12978 | 164k | " in state ", ada::to_string(state)); | 12979 | 164k | switch (state) { | 12980 | 43.7k | case state::SCHEME_START: { | 12981 | 43.7k | ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); | 12982 | | // If c is an ASCII alpha, append c, lowercased, to buffer, and set | 12983 | | // state to scheme state. | 12984 | 43.7k | if ((input_position != input_size) && | 12985 | 23.2k | checkers::is_alpha(url_data[input_position])) { | 12986 | 21.7k | state = state::SCHEME; | 12987 | 21.7k | input_position++; | 12988 | 21.9k | } else { | 12989 | | // Otherwise, if state override is not given, set state to no scheme | 12990 | | // state and decrease pointer by 1. | 12991 | 21.9k | state = state::NO_SCHEME; | 12992 | 21.9k | } | 12993 | 43.7k | break; | 12994 | 0 | } | 12995 | 21.7k | case state::SCHEME: { | 12996 | 21.7k | ada_log("SCHEME ", helpers::substring(url_data, input_position)); | 12997 | | // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), | 12998 | | // append c, lowercased, to buffer. | 12999 | 53.3k | while ((input_position != input_size) && | 13000 | 53.0k | (unicode::is_alnum_plus(url_data[input_position]))) { | 13001 | 31.5k | input_position++; | 13002 | 31.5k | } | 13003 | | // Otherwise, if c is U+003A (:), then: | 13004 | 21.7k | if ((input_position != input_size) && | 13005 | 21.4k | (url_data[input_position] == ':')) { | 13006 | 21.0k | ada_log("SCHEME the scheme should be ", | 13007 | 21.0k | url_data.substr(0, input_position)); | 13008 | 21.0k | if constexpr (result_type_is_ada_url) { | 13009 | 21.0k | if (!url.parse_scheme(url_data.substr(0, input_position))) { | 13010 | 0 | return url; | 13011 | 0 | } | 13012 | | } else { | 13013 | | // we pass the colon along instead of painfully adding it back. | 13014 | | if (!url.parse_scheme_with_colon( | 13015 | | url_data.substr(0, input_position + 1))) { | 13016 | | return url; | 13017 | | } | 13018 | | } | 13019 | 21.0k | ada_log("SCHEME the scheme is ", url.get_protocol()); | 13020 | | | 13021 | | // If url's scheme is "file", then: | 13022 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13023 | 21.0k | if (url.type == scheme::type::FILE) { | 13024 | | // Set state to file state. | 13025 | 2.56k | state = state::FILE; | 13026 | 2.56k | } | 13027 | | // Otherwise, if url is special, base is non-null, and base's scheme | 13028 | | // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url | 13029 | | // != nullptr is false. | 13030 | 18.4k | else if (url.is_special() && base_url != nullptr && | 13031 | 2.24k | base_url->type == url.type) { | 13032 | | // Set state to special relative or authority state. | 13033 | 414 | state = state::SPECIAL_RELATIVE_OR_AUTHORITY; | 13034 | 414 | } | 13035 | | // Otherwise, if url is special, set state to special authority | 13036 | | // slashes state. | 13037 | 18.0k | else if (url.is_special()) { | 13038 | 12.6k | state = state::SPECIAL_AUTHORITY_SLASHES; | 13039 | 12.6k | } | 13040 | | // Otherwise, if remaining starts with an U+002F (/), set state to | 13041 | | // path or authority state and increase pointer by 1. | 13042 | 5.37k | else if (input_position + 1 < input_size && | 13043 | 3.10k | url_data[input_position + 1] == '/') { | 13044 | 2.19k | state = state::PATH_OR_AUTHORITY; | 13045 | 2.19k | input_position++; | 13046 | 2.19k | } | 13047 | | // Otherwise, set url's path to the empty string and set state to | 13048 | | // opaque path state. | 13049 | 3.17k | else { | 13050 | 3.17k | state = state::OPAQUE_PATH; | 13051 | 3.17k | } | 13052 | 21.0k | } | 13053 | | // Otherwise, if state override is not given, set buffer to the empty | 13054 | | // string, state to no scheme state, and start over (from the first code | 13055 | | // point in input). | 13056 | 739 | else { | 13057 | 739 | state = state::NO_SCHEME; | 13058 | 739 | input_position = 0; | 13059 | 739 | break; | 13060 | 739 | } | 13061 | 21.0k | input_position++; | 13062 | 21.0k | break; | 13063 | 21.7k | } | 13064 | 22.7k | case state::NO_SCHEME: { | 13065 | 22.7k | ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); | 13066 | | // The fragment was pruned from url_data before the state machine ran, | 13067 | | // so 'c is U+0023 (#)' holds exactly when a fragment was found and | 13068 | | // nothing else remains in front of it. | 13069 | 22.7k | const bool c_is_hash = | 13070 | 22.7k | fragment.has_value() && input_position == input_size; | 13071 | | // If base is null, or base has an opaque path and c is not U+0023 (#), | 13072 | | // validation error, return failure. | 13073 | 22.7k | if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) { | 13074 | 21.7k | ada_log("NO_SCHEME validation error"); | 13075 | 21.7k | url.is_valid = false; | 13076 | 21.7k | return url; | 13077 | 21.7k | } | 13078 | | // Otherwise, if base has an opaque path and c is U+0023 (#), | 13079 | | // set url's scheme to base's scheme, url's path to base's path, url's | 13080 | | // query to base's query, and set state to fragment state. | 13081 | 999 | else if (base_url->has_opaque_path && c_is_hash) { | 13082 | 45 | ada_log("NO_SCHEME opaque base with fragment"); | 13083 | 45 | url.copy_scheme(*base_url); | 13084 | 45 | url.has_opaque_path = base_url->has_opaque_path; | 13085 | | | 13086 | 45 | if constexpr (result_type_is_ada_url) { | 13087 | 45 | url.path = base_url->path; | 13088 | 45 | url.query = base_url->query; | 13089 | | } else { | 13090 | | url.update_base_pathname(base_url->get_pathname()); | 13091 | | if (base_url->has_search()) { | 13092 | | // get_search() returns "" for an empty query string (URL ends | 13093 | | // with '?'). update_base_search("") would incorrectly clear the | 13094 | | // query, so pass "?" to preserve the empty query distinction. | 13095 | | auto s = base_url->get_search(); | 13096 | | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13097 | | } | 13098 | | } | 13099 | 45 | url.update_unencoded_base_hash(*fragment); | 13100 | 45 | enforce_max_input_length(); | 13101 | 45 | return url; | 13102 | 45 | } | 13103 | | // Otherwise, if base's scheme is not "file", set state to relative | 13104 | | // state and decrease pointer by 1. | 13105 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13106 | 954 | else if (base_url->type != scheme::type::FILE) { | 13107 | 745 | ada_log("NO_SCHEME non-file relative path"); | 13108 | 745 | state = state::RELATIVE_SCHEME; | 13109 | 745 | } | 13110 | | // Otherwise, set state to file state and decrease pointer by 1. | 13111 | 209 | else { | 13112 | 209 | ada_log("NO_SCHEME file base type"); | 13113 | 209 | state = state::FILE; | 13114 | 209 | } | 13115 | 954 | break; | 13116 | 22.7k | } | 13117 | 13.9k | case state::AUTHORITY: { | 13118 | 13.9k | ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); | 13119 | | // most URLs have no @. Having no @ tells us that we don't have to worry | 13120 | | // about AUTHORITY. Of course, we could have @ and still not have to | 13121 | | // worry about AUTHORITY. | 13122 | | // TODO: Instead of just collecting a bool, collect the location of the | 13123 | | // '@' and do something useful with it. | 13124 | | // TODO: We could do various processing early on, using a single pass | 13125 | | // over the string to collect information about it, e.g., telling us | 13126 | | // whether there is a @ and if so, where (or how many). | 13127 | | | 13128 | | // Check if url data contains an @. | 13129 | 13.9k | if (url_data.find('@', input_position) == std::string_view::npos) { | 13130 | 12.7k | state = state::HOST; | 13131 | 12.7k | break; | 13132 | 12.7k | } | 13133 | 1.22k | bool at_sign_seen{false}; | 13134 | 1.22k | bool password_token_seen{false}; | 13135 | | /** | 13136 | | * We expect something of the sort... | 13137 | | * https://user:pass@example.com:1234/foo/bar?baz#quux | 13138 | | * --------^ | 13139 | | */ | 13140 | 7.59k | do { | 13141 | 7.59k | std::string_view view = url_data.substr(input_position); | 13142 | | // The delimiters are @, /, ? \\. | 13143 | 7.59k | size_t location = | 13144 | 7.59k | url.is_special() ? helpers::find_authority_delimiter_special(view) | 13145 | 7.59k | : helpers::find_authority_delimiter(view); | 13146 | 7.59k | std::string_view authority_view = view.substr(0, location); | 13147 | 7.59k | size_t end_of_authority = input_position + authority_view.size(); | 13148 | | // If c is U+0040 (@), then: | 13149 | 7.59k | if ((end_of_authority != input_size) && | 13150 | 6.82k | (url_data[end_of_authority] == '@')) { | 13151 | | // If atSignSeen is true, then prepend "%40" to buffer. | 13152 | 6.37k | if (at_sign_seen) { | 13153 | 5.29k | if (password_token_seen) { | 13154 | 2.21k | if constexpr (result_type_is_ada_url) { | 13155 | 2.21k | url.password += "%40"; | 13156 | | } else { | 13157 | | url.append_base_password("%40"); | 13158 | | } | 13159 | 3.07k | } else { | 13160 | 3.07k | if constexpr (result_type_is_ada_url) { | 13161 | 3.07k | url.username += "%40"; | 13162 | | } else { | 13163 | | url.append_base_username("%40"); | 13164 | | } | 13165 | 3.07k | } | 13166 | 5.29k | } | 13167 | | | 13168 | 6.37k | at_sign_seen = true; | 13169 | | | 13170 | 6.37k | if (!password_token_seen) { | 13171 | 4.15k | size_t password_token_location = authority_view.find(':'); | 13172 | 4.15k | password_token_seen = | 13173 | 4.15k | password_token_location != std::string_view::npos; | 13174 | | | 13175 | 4.15k | if constexpr (store_values) { | 13176 | 4.15k | if (!password_token_seen) { | 13177 | 3.75k | if constexpr (result_type_is_ada_url) { | 13178 | 3.75k | url.username += unicode::percent_encode( | 13179 | 3.75k | authority_view, | 13180 | 3.75k | character_sets::USERINFO_PERCENT_ENCODE); | 13181 | | } else { | 13182 | | url.append_base_username(unicode::percent_encode( | 13183 | | authority_view, | 13184 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13185 | | } | 13186 | 3.75k | } else { | 13187 | 401 | if constexpr (result_type_is_ada_url) { | 13188 | 401 | url.username += unicode::percent_encode( | 13189 | 401 | authority_view.substr(0, password_token_location), | 13190 | 401 | character_sets::USERINFO_PERCENT_ENCODE); | 13191 | 401 | url.password += unicode::percent_encode( | 13192 | 401 | authority_view.substr(password_token_location + 1), | 13193 | 401 | character_sets::USERINFO_PERCENT_ENCODE); | 13194 | | } else { | 13195 | | url.append_base_username(unicode::percent_encode( | 13196 | | authority_view.substr(0, password_token_location), | 13197 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13198 | | url.append_base_password(unicode::percent_encode( | 13199 | | authority_view.substr(password_token_location + 1), | 13200 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13201 | | } | 13202 | 401 | } | 13203 | 4.15k | } | 13204 | 4.15k | } else if constexpr (store_values) { | 13205 | 2.21k | if constexpr (result_type_is_ada_url) { | 13206 | 2.21k | url.password += unicode::percent_encode( | 13207 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE); | 13208 | | } else { | 13209 | | url.append_base_password(unicode::percent_encode( | 13210 | | authority_view, character_sets::USERINFO_PERCENT_ENCODE)); | 13211 | | } | 13212 | 2.21k | } | 13213 | 6.37k | } | 13214 | | // Otherwise, if one of the following is true: | 13215 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13216 | | // - url is special and c is U+005C (\) | 13217 | 1.22k | else if (end_of_authority == input_size || | 13218 | 449 | url_data[end_of_authority] == '/' || | 13219 | 43 | url_data[end_of_authority] == '?' || | 13220 | 1.22k | (url.is_special() && url_data[end_of_authority] == '\\')) { | 13221 | | // If atSignSeen is true and authority_view is the empty string, | 13222 | | // validation error, return failure. | 13223 | 1.22k | if (at_sign_seen && authority_view.empty()) { | 13224 | 337 | url.is_valid = false; | 13225 | 337 | return url; | 13226 | 337 | } | 13227 | 888 | state = state::HOST; | 13228 | 888 | break; | 13229 | 1.22k | } | 13230 | 6.37k | if (end_of_authority == input_size) { | 13231 | 0 | if constexpr (store_values) { | 13232 | 0 | if (fragment.has_value()) { | 13233 | 0 | url.update_unencoded_base_hash(*fragment); | 13234 | 0 | } | 13235 | 0 | } | 13236 | 0 | enforce_max_input_length(); | 13237 | 0 | return url; | 13238 | 0 | } | 13239 | 6.37k | input_position = end_of_authority + 1; | 13240 | 6.37k | } while (true); | 13241 | | | 13242 | 888 | break; | 13243 | 1.22k | } | 13244 | 888 | case state::SPECIAL_RELATIVE_OR_AUTHORITY: { | 13245 | 414 | ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", | 13246 | 414 | helpers::substring(url_data, input_position)); | 13247 | | | 13248 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13249 | | // then set state to special authority ignore slashes state and increase | 13250 | | // pointer by 1. | 13251 | 414 | if (url_data.substr(input_position, 2) == "//") { | 13252 | 342 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13253 | 342 | input_position += 2; | 13254 | 342 | } else { | 13255 | | // Otherwise, validation error, set state to relative state and | 13256 | | // decrease pointer by 1. | 13257 | 72 | state = state::RELATIVE_SCHEME; | 13258 | 72 | } | 13259 | | | 13260 | 414 | break; | 13261 | 1.22k | } | 13262 | 2.19k | case state::PATH_OR_AUTHORITY: { | 13263 | 2.19k | ada_log("PATH_OR_AUTHORITY ", | 13264 | 2.19k | helpers::substring(url_data, input_position)); | 13265 | | | 13266 | | // If c is U+002F (/), then set state to authority state. | 13267 | 2.19k | if ((input_position != input_size) && | 13268 | 2.08k | (url_data[input_position] == '/')) { | 13269 | 887 | state = state::AUTHORITY; | 13270 | 887 | input_position++; | 13271 | 1.30k | } else { | 13272 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13273 | 1.30k | state = state::PATH; | 13274 | 1.30k | } | 13275 | | | 13276 | 2.19k | break; | 13277 | 1.22k | } | 13278 | 817 | case state::RELATIVE_SCHEME: { | 13279 | 817 | ada_log("RELATIVE_SCHEME ", | 13280 | 817 | helpers::substring(url_data, input_position)); | 13281 | | | 13282 | | // Set url's scheme to base's scheme. | 13283 | 817 | url.copy_scheme(*base_url); | 13284 | | | 13285 | | // If c is U+002F (/), then set state to relative slash state. | 13286 | 817 | if ((input_position != input_size) && | 13287 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13288 | 669 | (url_data[input_position] == '/')) { | 13289 | 68 | ada_log( | 13290 | 68 | "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " | 13291 | 68 | "slash state"); | 13292 | 68 | state = state::RELATIVE_SLASH; | 13293 | 749 | } else if (url.is_special() && (input_position != input_size) && | 13294 | 507 | (url_data[input_position] == '\\')) { | 13295 | | // Otherwise, if url is special and c is U+005C (\), validation error, | 13296 | | // set state to relative slash state. | 13297 | 2 | ada_log( | 13298 | 2 | "RELATIVE_SCHEME if url is special and c is U+005C, validation " | 13299 | 2 | "error, set state to relative slash state"); | 13300 | 2 | state = state::RELATIVE_SLASH; | 13301 | 747 | } else { | 13302 | 747 | ada_log("RELATIVE_SCHEME otherwise"); | 13303 | | // Set url's username to base's username, url's password to base's | 13304 | | // password, url's host to base's host, url's port to base's port, | 13305 | | // url's path to a clone of base's path, and url's query to base's | 13306 | | // query. | 13307 | 747 | if constexpr (result_type_is_ada_url) { | 13308 | 747 | url.username = base_url->username; | 13309 | 747 | url.password = base_url->password; | 13310 | 747 | url.host = base_url->host; | 13311 | 747 | url.port = base_url->port; | 13312 | | // cloning the base path includes cloning the has_opaque_path flag | 13313 | 747 | url.has_opaque_path = base_url->has_opaque_path; | 13314 | 747 | url.path = base_url->path; | 13315 | 747 | url.query = base_url->query; | 13316 | | } else { | 13317 | | url.update_base_authority(base_url->get_href(), | 13318 | | base_url->get_components()); | 13319 | | url.update_host_to_base_host(base_url->get_hostname()); | 13320 | | url.update_base_port(base_url->retrieve_base_port()); | 13321 | | // cloning the base path includes cloning the has_opaque_path flag | 13322 | | url.has_opaque_path = base_url->has_opaque_path; | 13323 | | url.update_base_pathname(base_url->get_pathname()); | 13324 | | if (base_url->has_search()) { | 13325 | | // get_search() returns "" for an empty query string (URL ends | 13326 | | // with '?'). update_base_search("") would incorrectly clear the | 13327 | | // query, so pass "?" to preserve the empty query distinction. | 13328 | | auto s = base_url->get_search(); | 13329 | | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13330 | | } | 13331 | | } | 13332 | | | 13333 | 747 | url.has_opaque_path = base_url->has_opaque_path; | 13334 | | | 13335 | | // If c is U+003F (?), then set url's query to the empty string, and | 13336 | | // state to query state. | 13337 | 747 | if ((input_position != input_size) && | 13338 | 599 | (url_data[input_position] == '?')) { | 13339 | 80 | state = state::QUERY; | 13340 | 80 | } | 13341 | | // Otherwise, if c is not the EOF code point: | 13342 | 667 | else if (input_position != input_size) { | 13343 | | // Set url's query to null. | 13344 | 519 | url.clear_search(); | 13345 | 519 | if constexpr (result_type_is_ada_url) { | 13346 | | // Shorten url's path. | 13347 | 519 | helpers::shorten_path(url.path, url.type); | 13348 | | } else { | 13349 | | std::string_view path = url.get_pathname(); | 13350 | | if (helpers::shorten_path(path, url.type)) { | 13351 | | url.update_base_pathname(std::move(std::string(path))); | 13352 | | } | 13353 | | } | 13354 | | // Set state to path state and decrease pointer by 1. | 13355 | 519 | state = state::PATH; | 13356 | 519 | break; | 13357 | 519 | } | 13358 | 747 | } | 13359 | 298 | input_position++; | 13360 | 298 | break; | 13361 | 817 | } | 13362 | 70 | case state::RELATIVE_SLASH: { | 13363 | 70 | ada_log("RELATIVE_SLASH ", | 13364 | 70 | helpers::substring(url_data, input_position)); | 13365 | | | 13366 | | // If url is special and c is U+002F (/) or U+005C (\), then: | 13367 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13368 | 70 | if (url.is_special() && (input_position != input_size) && | 13369 | 42 | (url_data[input_position] == '/' || | 13370 | 38 | url_data[input_position] == '\\')) { | 13371 | | // Set state to special authority ignore slashes state. | 13372 | 6 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13373 | 6 | } | 13374 | | // Otherwise, if c is U+002F (/), then set state to authority state. | 13375 | 64 | else if ((input_position != input_size) && | 13376 | 46 | (url_data[input_position] == '/')) { | 13377 | 5 | state = state::AUTHORITY; | 13378 | 5 | } | 13379 | | // Otherwise, set | 13380 | | // - url's username to base's username, | 13381 | | // - url's password to base's password, | 13382 | | // - url's host to base's host, | 13383 | | // - url's port to base's port, | 13384 | | // - state to path state, and then, decrease pointer by 1. | 13385 | 59 | else { | 13386 | 59 | if constexpr (result_type_is_ada_url) { | 13387 | 59 | url.username = base_url->username; | 13388 | 59 | url.password = base_url->password; | 13389 | 59 | url.host = base_url->host; | 13390 | 59 | url.port = base_url->port; | 13391 | | } else { | 13392 | | url.update_base_authority(base_url->get_href(), | 13393 | | base_url->get_components()); | 13394 | | url.update_host_to_base_host(base_url->get_hostname()); | 13395 | | url.update_base_port(base_url->retrieve_base_port()); | 13396 | | } | 13397 | 59 | state = state::PATH; | 13398 | 59 | break; | 13399 | 59 | } | 13400 | | | 13401 | 11 | input_position++; | 13402 | 11 | break; | 13403 | 70 | } | 13404 | 12.6k | case state::SPECIAL_AUTHORITY_SLASHES: { | 13405 | 12.6k | ada_log("SPECIAL_AUTHORITY_SLASHES ", | 13406 | 12.6k | helpers::substring(url_data, input_position)); | 13407 | | | 13408 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13409 | | // then set state to special authority ignore slashes state and increase | 13410 | | // pointer by 1. | 13411 | 12.6k | if (url_data.substr(input_position, 2) == "//") { | 13412 | 3.23k | input_position += 2; | 13413 | 3.23k | } | 13414 | | | 13415 | 12.6k | [[fallthrough]]; | 13416 | 12.6k | } | 13417 | 13.0k | case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { | 13418 | 13.0k | ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", | 13419 | 13.0k | helpers::substring(url_data, input_position)); | 13420 | | | 13421 | | // If c is neither U+002F (/) nor U+005C (\), then set state to | 13422 | | // authority state and decrease pointer by 1. | 13423 | 14.0k | while ((input_position != input_size) && | 13424 | 13.9k | ((url_data[input_position] == '/') || | 13425 | 13.3k | (url_data[input_position] == '\\'))) { | 13426 | 1.03k | input_position++; | 13427 | 1.03k | } | 13428 | 13.0k | state = state::AUTHORITY; | 13429 | | | 13430 | 13.0k | break; | 13431 | 12.6k | } | 13432 | 1.17k | case state::QUERY: { | 13433 | 1.17k | ada_log("QUERY ", helpers::substring(url_data, input_position)); | 13434 | 1.17k | if constexpr (store_values) { | 13435 | | // Let queryPercentEncodeSet be the special-query percent-encode set | 13436 | | // if url is special; otherwise the query percent-encode set. | 13437 | 1.17k | const uint8_t* query_percent_encode_set = | 13438 | 1.17k | url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE | 13439 | 1.17k | : character_sets::QUERY_PERCENT_ENCODE; | 13440 | | | 13441 | | // Percent-encode after encoding, with encoding, buffer, and | 13442 | | // queryPercentEncodeSet, and append the result to url's query. | 13443 | 1.17k | url.update_base_search(url_data.substr(input_position), | 13444 | 1.17k | query_percent_encode_set); | 13445 | 1.17k | ada_log("QUERY update_base_search completed "); | 13446 | 1.17k | if (fragment.has_value()) { | 13447 | 307 | url.update_unencoded_base_hash(*fragment); | 13448 | 307 | } | 13449 | 1.17k | } | 13450 | 1.17k | enforce_max_input_length(); | 13451 | 1.17k | return url; | 13452 | 12.6k | } | 13453 | 13.5k | case state::HOST: { | 13454 | 13.5k | ada_log("HOST ", helpers::substring(url_data, input_position)); | 13455 | | | 13456 | 13.5k | std::string_view host_view = url_data.substr(input_position); | 13457 | 13.5k | auto [location, found_colon] = | 13458 | 13.5k | helpers::get_host_delimiter_location(url.is_special(), host_view); | 13459 | 13.5k | input_position = (location != std::string_view::npos) | 13460 | 13.5k | ? input_position + location | 13461 | 13.5k | : input_size; | 13462 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: | 13463 | | // Note: the 'found_colon' value is true if and only if a colon was | 13464 | | // encountered while not inside brackets. | 13465 | 13.5k | if (found_colon) { | 13466 | | // If buffer is the empty string, validation error, return failure. | 13467 | | // Let host be the result of host parsing buffer with url is not | 13468 | | // special. | 13469 | 2.43k | ada_log("HOST parsing ", host_view); | 13470 | 2.43k | if (!url.parse_host(host_view)) { | 13471 | 211 | return url; | 13472 | 211 | } | 13473 | 2.22k | ada_log("HOST parsing results in ", url.get_hostname()); | 13474 | | // Set url's host to host, buffer to the empty string, and state to | 13475 | | // port state. | 13476 | 2.22k | state = state::PORT; | 13477 | 2.22k | input_position++; | 13478 | 2.22k | } | 13479 | | // Otherwise, if one of the following is true: | 13480 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13481 | | // - url is special and c is U+005C (\) | 13482 | | // The get_host_delimiter_location function either brings us to | 13483 | | // the colon outside of the bracket, or to one of those characters. | 13484 | 11.1k | else { | 13485 | | // If url is special and host_view is the empty string, validation | 13486 | | // error, return failure. | 13487 | 11.1k | if (host_view.empty() && url.is_special()) { | 13488 | 91 | url.is_valid = false; | 13489 | 91 | return url; | 13490 | 91 | } | 13491 | 11.0k | ada_log("HOST parsing ", host_view, " href=", url.get_href()); | 13492 | | // Let host be the result of host parsing host_view with url is not | 13493 | | // special. | 13494 | 11.0k | if (host_view.empty()) { | 13495 | 131 | url.update_base_hostname(""); | 13496 | 10.9k | } else if (!url.parse_host(host_view)) { | 13497 | 2.29k | return url; | 13498 | 2.29k | } | 13499 | 8.76k | ada_log("HOST parsing results in ", url.get_hostname(), | 13500 | 8.76k | " href=", url.get_href()); | 13501 | | | 13502 | | // Set url's host to host, and state to path start state. | 13503 | 8.76k | state = state::PATH_START; | 13504 | 8.76k | } | 13505 | | | 13506 | 10.9k | break; | 13507 | 13.5k | } | 13508 | 10.9k | case state::OPAQUE_PATH: { | 13509 | 3.17k | ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); | 13510 | | // Opaque path, query, and fragment are structurally always valid: | 13511 | | // the parser would just percent-encode whatever is there. When we | 13512 | | // are not storing values (can_parse), we can return immediately. | 13513 | | // We must set has_opaque_path = true before returning so that when | 13514 | | // this URL is used as an internal base inside can_parse, NO_SCHEME | 13515 | | // correctly rejects relative inputs against an opaque-path base | 13516 | | // (e.g. can_parse("", &"W:") must return false). | 13517 | | if constexpr (!store_values) { | 13518 | | url.has_opaque_path = true; | 13519 | | return url; | 13520 | | } | 13521 | 3.17k | std::string_view view = url_data.substr(input_position); | 13522 | | // If c is U+003F (?), then set url's query to the empty string and | 13523 | | // state to query state. | 13524 | 3.17k | size_t location = view.find('?'); | 13525 | 3.17k | if (location != std::string_view::npos) { | 13526 | 281 | view.remove_suffix(view.size() - location); | 13527 | 281 | state = state::QUERY; | 13528 | 281 | input_position += location + 1; | 13529 | 2.89k | } else { | 13530 | 2.89k | input_position = input_size + 1; | 13531 | 2.89k | } | 13532 | 3.17k | url.has_opaque_path = true; | 13533 | | | 13534 | | // This is a really unlikely scenario in real world. We should not seek | 13535 | | // to optimize it. | 13536 | 3.17k | if (view.ends_with(' ')) { | 13537 | 112 | std::string modified_view = | 13538 | 112 | std::string(view.substr(0, view.size() - 1)) + "%20"; | 13539 | 112 | url.update_base_pathname(unicode::percent_encode( | 13540 | 112 | modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13541 | 3.06k | } else { | 13542 | 3.06k | url.update_base_pathname(unicode::percent_encode( | 13543 | 3.06k | view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13544 | 3.06k | } | 13545 | 3.17k | break; | 13546 | 13.5k | } | 13547 | 2.22k | case state::PORT: { | 13548 | 2.22k | ada_log("PORT ", helpers::substring(url_data, input_position)); | 13549 | 2.22k | std::string_view port_view = url_data.substr(input_position); | 13550 | 2.22k | input_position += url.parse_port(port_view, true); | 13551 | 2.22k | if (!url.is_valid) { | 13552 | 118 | return url; | 13553 | 118 | } | 13554 | 2.11k | state = state::PATH_START; | 13555 | 2.11k | [[fallthrough]]; | 13556 | 2.11k | } | 13557 | 12.7k | case state::PATH_START: { | 13558 | 12.7k | ada_log("PATH_START ", helpers::substring(url_data, input_position)); | 13559 | | // Path, query, and fragment are structurally always valid: the | 13560 | | // parser would just percent-encode whatever is there. When we are | 13561 | | // not storing values (can_parse), we can return immediately since | 13562 | | // no subsequent state can invalidate the URL. | 13563 | | if constexpr (!store_values) { | 13564 | | return url; | 13565 | | } | 13566 | | | 13567 | | // If url is special, then: | 13568 | 12.7k | if (url.is_special()) { | 13569 | | // Set state to path state. | 13570 | 12.0k | state = state::PATH; | 13571 | | | 13572 | | // Optimization: Avoiding going into PATH state improves the | 13573 | | // performance of urls ending with /. | 13574 | 12.0k | if (input_position == input_size) { | 13575 | 6.42k | if constexpr (store_values) { | 13576 | 6.42k | url.update_base_pathname("/"); | 13577 | 6.42k | if (fragment.has_value()) { | 13578 | 166 | url.update_unencoded_base_hash(*fragment); | 13579 | 166 | } | 13580 | 6.42k | } | 13581 | 6.42k | enforce_max_input_length(); | 13582 | 6.42k | return url; | 13583 | 6.42k | } | 13584 | | // If c is neither U+002F (/) nor U+005C (\), then decrease pointer | 13585 | | // by 1. We know that (input_position == input_size) is impossible | 13586 | | // here, because of the previous if-check. | 13587 | 5.59k | if ((url_data[input_position] != '/') && | 13588 | 387 | (url_data[input_position] != '\\')) { | 13589 | 373 | break; | 13590 | 373 | } | 13591 | 5.59k | } | 13592 | | // Otherwise, if state override is not given and c is U+003F (?), | 13593 | | // set url's query to the empty string and state to query state. | 13594 | 755 | else if ((input_position != input_size) && | 13595 | 160 | (url_data[input_position] == '?')) { | 13596 | 51 | state = state::QUERY; | 13597 | 51 | } | 13598 | | // Otherwise, if c is not the EOF code point: | 13599 | 704 | else if (input_position != input_size) { | 13600 | | // Set state to path state. | 13601 | 109 | state = state::PATH; | 13602 | | | 13603 | | // If c is not U+002F (/), then decrease pointer by 1. | 13604 | 109 | if (url_data[input_position] != '/') { | 13605 | 0 | break; | 13606 | 0 | } | 13607 | 109 | } | 13608 | | | 13609 | 5.97k | input_position++; | 13610 | 5.97k | break; | 13611 | 12.7k | } | 13612 | 8.23k | case state::PATH: { | 13613 | 8.23k | ada_log("PATH ", helpers::substring(url_data, input_position)); | 13614 | | // Path, query, and fragment are structurally always valid: the | 13615 | | // parser would just percent-encode whatever is there. When we are | 13616 | | // not storing values (can_parse), we can return immediately since | 13617 | | // no subsequent state can invalidate the URL. | 13618 | | if constexpr (!store_values) { | 13619 | | return url; | 13620 | | } | 13621 | 8.23k | std::string_view view = url_data.substr(input_position); | 13622 | | | 13623 | | // Most time, we do not need percent encoding. | 13624 | | // Furthermore, we can immediately locate the '?'. | 13625 | 8.23k | size_t locofquestionmark = view.find('?'); | 13626 | 8.23k | if (locofquestionmark != std::string_view::npos) { | 13627 | 760 | state = state::QUERY; | 13628 | 760 | view.remove_suffix(view.size() - locofquestionmark); | 13629 | 760 | input_position += locofquestionmark + 1; | 13630 | 7.47k | } else { | 13631 | 7.47k | input_position = input_size + 1; | 13632 | 7.47k | } | 13633 | 8.23k | if constexpr (store_values) { | 13634 | 8.23k | if constexpr (result_type_is_ada_url) { | 13635 | 8.23k | helpers::parse_prepared_path(view, url.type, url.path); | 13636 | | } else { | 13637 | | url.consume_prepared_path(view); | 13638 | | ADA_ASSERT_TRUE(url.validate()); | 13639 | | } | 13640 | 8.23k | } | 13641 | 8.23k | break; | 13642 | 12.7k | } | 13643 | 2.20k | case state::FILE_SLASH: { | 13644 | 2.20k | ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); | 13645 | | | 13646 | | // If c is U+002F (/) or U+005C (\), then: | 13647 | 2.20k | if ((input_position != input_size) && | 13648 | 2.13k | (url_data[input_position] == '/' || | 13649 | 2.09k | url_data[input_position] == '\\')) { | 13650 | 2.09k | ada_log("FILE_SLASH c is U+002F or U+005C"); | 13651 | | // Set state to file host state. | 13652 | 2.09k | state = state::FILE_HOST; | 13653 | 2.09k | input_position++; | 13654 | 2.09k | } else { | 13655 | 110 | ada_log("FILE_SLASH otherwise"); | 13656 | | // If base is non-null and base's scheme is "file", then: | 13657 | | // Note: it is unsafe to do base_url->scheme unless you know that | 13658 | | // base_url_has_value() is true. | 13659 | 110 | if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13660 | | // Set url's host to base's host. | 13661 | 86 | if constexpr (result_type_is_ada_url) { | 13662 | 86 | url.host = base_url->host; | 13663 | | } else { | 13664 | | url.update_host_to_base_host(base_url->get_host()); | 13665 | | } | 13666 | | // If the code point substring from pointer to the end of input does | 13667 | | // not start with a Windows drive letter and base's path[0] is a | 13668 | | // normalized Windows drive letter, then append base's path[0] to | 13669 | | // url's path. | 13670 | 86 | if (!base_url->get_pathname().empty()) { | 13671 | 86 | if (!checkers::is_windows_drive_letter( | 13672 | 86 | url_data.substr(input_position))) { | 13673 | 81 | std::string_view first_base_url_path = | 13674 | 81 | base_url->get_pathname().substr(1); | 13675 | 81 | size_t loc = first_base_url_path.find('/'); | 13676 | 81 | if (loc != std::string_view::npos) { | 13677 | 11 | helpers::resize(first_base_url_path, loc); | 13678 | 11 | } | 13679 | 81 | if (checkers::is_normalized_windows_drive_letter( | 13680 | 81 | first_base_url_path)) { | 13681 | 2 | if constexpr (result_type_is_ada_url) { | 13682 | 2 | url.path += '/'; | 13683 | 2 | url.path += first_base_url_path; | 13684 | | } else { | 13685 | | url.append_base_pathname( | 13686 | | helpers::concat("/", first_base_url_path)); | 13687 | | } | 13688 | 2 | } | 13689 | 81 | } | 13690 | 86 | } | 13691 | 86 | } | 13692 | | | 13693 | | // Set state to path state, and decrease pointer by 1. | 13694 | 110 | state = state::PATH; | 13695 | 110 | } | 13696 | | | 13697 | 2.20k | break; | 13698 | 12.7k | } | 13699 | 2.09k | case state::FILE_HOST: { | 13700 | 2.09k | ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); | 13701 | 2.09k | std::string_view view = url_data.substr(input_position); | 13702 | | | 13703 | 2.09k | size_t location = view.find_first_of("/\\?"); | 13704 | 2.09k | std::string_view file_host_buffer = view.substr( | 13705 | 2.09k | 0, (location != std::string_view::npos) ? location : view.size()); | 13706 | | | 13707 | 2.09k | if (checkers::is_windows_drive_letter(file_host_buffer)) { | 13708 | 12 | state = state::PATH; | 13709 | 2.08k | } else if (file_host_buffer.empty()) { | 13710 | | // Set url's host to the empty string. | 13711 | 257 | if constexpr (result_type_is_ada_url) { | 13712 | 257 | url.host = ""; | 13713 | | } else { | 13714 | | url.update_base_hostname(""); | 13715 | | } | 13716 | | // Set state to path start state. | 13717 | 257 | state = state::PATH_START; | 13718 | 1.82k | } else { | 13719 | 1.82k | size_t consumed_bytes = file_host_buffer.size(); | 13720 | 1.82k | input_position += consumed_bytes; | 13721 | | // Let host be the result of host parsing buffer with url is not | 13722 | | // special. | 13723 | 1.82k | if (!url.parse_host(file_host_buffer)) { | 13724 | 188 | return url; | 13725 | 188 | } | 13726 | | | 13727 | 1.63k | if constexpr (result_type_is_ada_url) { | 13728 | | // If host is "localhost", then set host to the empty string. | 13729 | 1.63k | if (url.host.has_value() && url.host.value() == "localhost") { | 13730 | 12 | url.host = ""; | 13731 | 12 | } | 13732 | | } else { | 13733 | | if (url.get_hostname() == "localhost") { | 13734 | | url.update_base_hostname(""); | 13735 | | } | 13736 | | } | 13737 | | | 13738 | | // Set buffer to the empty string and state to path start state. | 13739 | 1.63k | state = state::PATH_START; | 13740 | 1.63k | } | 13741 | | | 13742 | 1.90k | break; | 13743 | 2.09k | } | 13744 | 2.77k | case state::FILE: { | 13745 | 2.77k | ada_log("FILE ", helpers::substring(url_data, input_position)); | 13746 | 2.77k | std::string_view file_view = url_data.substr(input_position); | 13747 | | | 13748 | 2.77k | url.set_protocol_as_file(); | 13749 | 2.77k | if constexpr (result_type_is_ada_url) { | 13750 | | // Set url's host to the empty string. | 13751 | 2.77k | url.host = ""; | 13752 | | } else { | 13753 | | url.update_base_hostname(""); | 13754 | | } | 13755 | | // If c is U+002F (/) or U+005C (\), then: | 13756 | 2.77k | if (input_position != input_size && | 13757 | 2.66k | (url_data[input_position] == '/' || | 13758 | 2.20k | url_data[input_position] == '\\')) { | 13759 | 2.20k | ada_log("FILE c is U+002F or U+005C"); | 13760 | | // Set state to file slash state. | 13761 | 2.20k | state = state::FILE_SLASH; | 13762 | 2.20k | } | 13763 | | // Otherwise, if base is non-null and base's scheme is "file": | 13764 | 574 | else if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13765 | | // Set url's host to base's host, url's path to a clone of base's | 13766 | | // path, and url's query to base's query. | 13767 | 140 | ada_log("FILE base non-null"); | 13768 | 140 | if constexpr (result_type_is_ada_url) { | 13769 | 140 | url.host = base_url->host; | 13770 | 140 | url.path = base_url->path; | 13771 | 140 | url.query = base_url->query; | 13772 | | } else { | 13773 | | url.update_host_to_base_host(base_url->get_hostname()); | 13774 | | url.update_base_pathname(base_url->get_pathname()); | 13775 | | if (base_url->has_search()) { | 13776 | | // get_search() returns "" for an empty query string (URL ends | 13777 | | // with '?'). update_base_search("") would incorrectly clear the | 13778 | | // query, so pass "?" to preserve the empty query distinction. | 13779 | | auto s = base_url->get_search(); | 13780 | | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13781 | | } | 13782 | | } | 13783 | 140 | url.has_opaque_path = base_url->has_opaque_path; | 13784 | | | 13785 | | // If c is U+003F (?), then set url's query to the empty string and | 13786 | | // state to query state. | 13787 | 140 | if (input_position != input_size && url_data[input_position] == '?') { | 13788 | 4 | state = state::QUERY; | 13789 | 4 | } | 13790 | | // Otherwise, if c is not the EOF code point: | 13791 | 136 | else if (input_position != input_size) { | 13792 | | // Set url's query to null. | 13793 | 89 | url.clear_search(); | 13794 | | // If the code point substring from pointer to the end of input does | 13795 | | // not start with a Windows drive letter, then shorten url's path. | 13796 | 89 | if (!checkers::is_windows_drive_letter(file_view)) { | 13797 | 76 | if constexpr (result_type_is_ada_url) { | 13798 | 76 | helpers::shorten_path(url.path, url.type); | 13799 | | } else { | 13800 | | std::string_view path = url.get_pathname(); | 13801 | | if (helpers::shorten_path(path, url.type)) { | 13802 | | url.update_base_pathname(std::move(std::string(path))); | 13803 | | } | 13804 | | } | 13805 | 76 | } | 13806 | | // Otherwise: | 13807 | 13 | else { | 13808 | | // Set url's path to an empty list. | 13809 | 13 | url.clear_pathname(); | 13810 | 13 | url.has_opaque_path = true; | 13811 | 13 | } | 13812 | | | 13813 | | // Set state to path state and decrease pointer by 1. | 13814 | 89 | state = state::PATH; | 13815 | 89 | break; | 13816 | 89 | } | 13817 | 140 | } | 13818 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13819 | 434 | else { | 13820 | 434 | ada_log("FILE go to path"); | 13821 | 434 | state = state::PATH; | 13822 | 434 | break; | 13823 | 434 | } | 13824 | | | 13825 | 2.25k | input_position++; | 13826 | 2.25k | break; | 13827 | 2.77k | } | 13828 | 0 | default: | 13829 | 0 | unreachable(); | 13830 | 164k | } | 13831 | 164k | } | 13832 | 16.4k | if constexpr (store_values) { | 13833 | 16.4k | if (fragment.has_value()) { | 13834 | 346 | url.update_unencoded_base_hash(*fragment); | 13835 | 346 | } | 13836 | 16.4k | } | 13837 | 16.4k | enforce_max_input_length(); | 13838 | 16.4k | return url; | 13839 | 49.0k | } |
ada::url_aggregator ada::parser::parse_url_impl<ada::url_aggregator, true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*) Line | Count | Source | 12819 | 49.0k | const result_type* base_url) { | 12820 | | // We can specialize the implementation per type. | 12821 | | // Important: result_type_is_ada_url is evaluated at *compile time*. This | 12822 | | // means that doing if constexpr(result_type_is_ada_url) { something } else { | 12823 | | // something else } is free (at runtime). This means that ada::url_aggregator | 12824 | | // and ada::url **do not have to support the exact same API**. | 12825 | 49.0k | constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>; | 12826 | 49.0k | constexpr bool result_type_is_ada_url_aggregator = | 12827 | 49.0k | std::is_same_v<url_aggregator, result_type>; | 12828 | 49.0k | static_assert(result_type_is_ada_url || | 12829 | 49.0k | result_type_is_ada_url_aggregator); // We don't support | 12830 | | // anything else for now. | 12831 | | | 12832 | 49.0k | ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), | 12833 | 49.0k | " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), | 12834 | 49.0k | ")"); | 12835 | | | 12836 | 49.0k | result_type url{}; | 12837 | | | 12838 | 49.0k | const uint32_t max_input_length = ada::get_max_input_length(); | 12839 | | | 12840 | | // Normalization (percent-encoding, IDNA) can push the serialized URL past | 12841 | | // max_input_length even when the input fit under it. The check at the end of | 12842 | | // the state machine covers URLs that run to completion, but several states | 12843 | | // return early after appending a query or fragment, so run the same check on | 12844 | | // those exits too. Without this, a query- or fragment-terminated URL such as | 12845 | | // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent | 12846 | | // https://x/?<...> that takes the absolute fast path is rejected. | 12847 | 49.0k | const auto enforce_max_input_length = [&]() { | 12848 | 49.0k | if constexpr (store_values) { | 12849 | 49.0k | if (url.is_valid) { | 12850 | 49.0k | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | 49.0k | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | 49.0k | url.is_valid = false; | 12853 | 49.0k | } | 12854 | 49.0k | } else { | 12855 | 49.0k | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | 49.0k | url.is_valid = false; | 12857 | 49.0k | } | 12858 | 49.0k | } | 12859 | 49.0k | } | 12860 | 49.0k | } | 12861 | 49.0k | }; | 12862 | | | 12863 | | // We refuse to parse URL strings that exceed the maximum input length. | 12864 | | // By default, this is 4GB but can be configured via | 12865 | | // ada::set_max_input_length(). | 12866 | 49.0k | if (user_input.size() > max_input_length) [[unlikely]] { | 12867 | 0 | url.is_valid = false; | 12868 | 0 | } | 12869 | | // Going forward, user_input.size() is in [0, | 12870 | | // std::numeric_limits<uint32_t>::max). If we are provided with an invalid | 12871 | | // base, or the optional_url was invalid, we must return. | 12872 | 49.0k | if (base_url != nullptr) { | 12873 | 4.35k | url.is_valid &= base_url->is_valid; | 12874 | 4.35k | } | 12875 | 49.0k | if (!url.is_valid) { | 12876 | 0 | return url; | 12877 | 0 | } | 12878 | | | 12879 | | // Simple absolute / relative fast paths (before tabs/newline scan). | 12880 | 49.0k | if constexpr (store_values) { | 12881 | 49.0k | bool hit_fast_path = false; | 12882 | 49.0k | if (base_url == nullptr) { | 12883 | | // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline | 12884 | | // call so those URLs (including SetHref) do not pay for a miss. | 12885 | 44.6k | const auto* p = reinterpret_cast<const uint8_t*>(user_input.data()); | 12886 | 44.6k | const size_t n = user_input.size(); | 12887 | 44.6k | size_t host_start = 0; | 12888 | 44.6k | if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') { | 12889 | 2.24k | host_start = 7; | 12890 | 42.4k | } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') { | 12891 | 28 | host_start = 8; | 12892 | 28 | } | 12893 | 44.6k | const uint8_t host_first = host_start != 0 ? p[host_start] : 0; | 12894 | 44.6k | const bool skip_ip = | 12895 | 44.6k | host_first == '[' || (host_first >= '0' && host_first <= '9'); | 12896 | 44.6k | const bool skip_userinfo = | 12897 | 44.6k | host_start != 0 && authority_has_at(p, host_start, n); | 12898 | 44.6k | hit_fast_path = !skip_ip && !skip_userinfo && | 12899 | 44.0k | try_parse_simple_absolute(user_input, url); | 12900 | 44.6k | } else { | 12901 | 4.35k | hit_fast_path = try_parse_simple_relative(user_input, *base_url, url); | 12902 | 4.35k | } | 12903 | 49.0k | if (hit_fast_path) { | 12904 | 5.25k | if constexpr (result_type_is_ada_url_aggregator) { | 12905 | 5.25k | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12906 | 0 | url.is_valid = false; | 12907 | 0 | } | 12908 | | } else { | 12909 | | // For a small absolute input, even worst-case normalization cannot | 12910 | | // exceed the limit: percent encoding expands at most 3x and IDNA at | 12911 | | // most 4.5x. Avoid traversing every stored component on the common | 12912 | | // default-limit path. | 12913 | | if ((base_url != nullptr || | 12914 | | user_input.size() > static_cast<size_t>(max_input_length) / 5) && | 12915 | | url.get_href_size() > max_input_length) [[unlikely]] { | 12916 | | url.is_valid = false; | 12917 | | } | 12918 | | } | 12919 | 5.25k | return url; | 12920 | 5.25k | } | 12921 | 49.0k | } | 12922 | | | 12923 | 43.7k | state state = state::SCHEME_START; | 12924 | | | 12925 | 49.0k | std::string tmp_buffer; | 12926 | 49.0k | std::string_view url_data; | 12927 | 49.0k | if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { | 12928 | 404 | tmp_buffer = user_input; | 12929 | | // Optimization opportunity: Instead of copying and then pruning, we could | 12930 | | // just directly build the string from user_input. | 12931 | 404 | helpers::remove_ascii_tab_or_newline(tmp_buffer); | 12932 | 404 | url_data = tmp_buffer; | 12933 | 48.6k | } else [[likely]] { | 12934 | 48.6k | url_data = user_input; | 12935 | 48.6k | } | 12936 | | | 12937 | | // Leading and trailing control characters are uncommon and easy to deal with | 12938 | | // (no performance concern). | 12939 | 49.0k | helpers::trim_c0_whitespace(url_data); | 12940 | | | 12941 | 49.0k | if constexpr (result_type_is_ada_url_aggregator && store_values) { | 12942 | | // Most of the time, we just need user_input.size(). | 12943 | | // In some instances, we may need a bit more. | 12944 | | /////////////////////////// | 12945 | | // This is *very* important. This line should *not* be removed | 12946 | | // hastily. There are principled reasons why reserve is important | 12947 | | // for performance. If you have a benchmark with small inputs, | 12948 | | // it may not matter, but in other instances, it could. | 12949 | | //// | 12950 | | // This rounds up to the next power of two. | 12951 | | // We know that user_input.size() is in [0, | 12952 | | // std::numeric_limits<uint32_t>::max). | 12953 | 49.0k | uint32_t reserve_capacity = | 12954 | 49.0k | (0xFFFFFFFF >> | 12955 | 49.0k | helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + | 12956 | 49.0k | 1; | 12957 | 49.0k | url.reserve(reserve_capacity); | 12958 | 49.0k | } | 12959 | | | 12960 | | // Optimization opportunity. Most websites do not have fragment. | 12961 | 49.0k | std::optional<std::string_view> fragment = helpers::prune_hash(url_data); | 12962 | | // We add it last so that an implementation like ada::url_aggregator | 12963 | | // can append it last to its internal buffer, thus improving performance. | 12964 | | | 12965 | | // Here url_data no longer has its fragment. | 12966 | | // We are going to access the data from url_data (it is immutable). | 12967 | | // At any given time, we are pointing at byte 'input_position' in url_data. | 12968 | | // The input_position variable should range from 0 to input_size. | 12969 | | // It is illegal to access url_data at input_size. | 12970 | 49.0k | size_t input_position = 0; | 12971 | 49.0k | const size_t input_size = url_data.size(); | 12972 | | // Keep running the following state machine by switching on state. | 12973 | | // If after a run pointer points to the EOF code point, go to the next step. | 12974 | | // Otherwise, increase pointer by 1 and continue with the state machine. | 12975 | | // We never decrement input_position. | 12976 | 181k | while (input_position <= input_size) { | 12977 | 164k | ada_log("In parsing at ", input_position, " out of ", input_size, | 12978 | 164k | " in state ", ada::to_string(state)); | 12979 | 164k | switch (state) { | 12980 | 43.7k | case state::SCHEME_START: { | 12981 | 43.7k | ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); | 12982 | | // If c is an ASCII alpha, append c, lowercased, to buffer, and set | 12983 | | // state to scheme state. | 12984 | 43.7k | if ((input_position != input_size) && | 12985 | 23.2k | checkers::is_alpha(url_data[input_position])) { | 12986 | 21.7k | state = state::SCHEME; | 12987 | 21.7k | input_position++; | 12988 | 21.9k | } else { | 12989 | | // Otherwise, if state override is not given, set state to no scheme | 12990 | | // state and decrease pointer by 1. | 12991 | 21.9k | state = state::NO_SCHEME; | 12992 | 21.9k | } | 12993 | 43.7k | break; | 12994 | 0 | } | 12995 | 21.7k | case state::SCHEME: { | 12996 | 21.7k | ada_log("SCHEME ", helpers::substring(url_data, input_position)); | 12997 | | // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), | 12998 | | // append c, lowercased, to buffer. | 12999 | 53.3k | while ((input_position != input_size) && | 13000 | 53.0k | (unicode::is_alnum_plus(url_data[input_position]))) { | 13001 | 31.5k | input_position++; | 13002 | 31.5k | } | 13003 | | // Otherwise, if c is U+003A (:), then: | 13004 | 21.7k | if ((input_position != input_size) && | 13005 | 21.4k | (url_data[input_position] == ':')) { | 13006 | 21.0k | ada_log("SCHEME the scheme should be ", | 13007 | 21.0k | url_data.substr(0, input_position)); | 13008 | | if constexpr (result_type_is_ada_url) { | 13009 | | if (!url.parse_scheme(url_data.substr(0, input_position))) { | 13010 | | return url; | 13011 | | } | 13012 | 21.0k | } else { | 13013 | | // we pass the colon along instead of painfully adding it back. | 13014 | 21.0k | if (!url.parse_scheme_with_colon( | 13015 | 21.0k | url_data.substr(0, input_position + 1))) { | 13016 | 0 | return url; | 13017 | 0 | } | 13018 | 21.0k | } | 13019 | 21.0k | ada_log("SCHEME the scheme is ", url.get_protocol()); | 13020 | | | 13021 | | // If url's scheme is "file", then: | 13022 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13023 | 21.0k | if (url.type == scheme::type::FILE) { | 13024 | | // Set state to file state. | 13025 | 2.56k | state = state::FILE; | 13026 | 2.56k | } | 13027 | | // Otherwise, if url is special, base is non-null, and base's scheme | 13028 | | // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url | 13029 | | // != nullptr is false. | 13030 | 18.4k | else if (url.is_special() && base_url != nullptr && | 13031 | 2.24k | base_url->type == url.type) { | 13032 | | // Set state to special relative or authority state. | 13033 | 414 | state = state::SPECIAL_RELATIVE_OR_AUTHORITY; | 13034 | 414 | } | 13035 | | // Otherwise, if url is special, set state to special authority | 13036 | | // slashes state. | 13037 | 18.0k | else if (url.is_special()) { | 13038 | 12.6k | state = state::SPECIAL_AUTHORITY_SLASHES; | 13039 | 12.6k | } | 13040 | | // Otherwise, if remaining starts with an U+002F (/), set state to | 13041 | | // path or authority state and increase pointer by 1. | 13042 | 5.37k | else if (input_position + 1 < input_size && | 13043 | 3.10k | url_data[input_position + 1] == '/') { | 13044 | 2.19k | state = state::PATH_OR_AUTHORITY; | 13045 | 2.19k | input_position++; | 13046 | 2.19k | } | 13047 | | // Otherwise, set url's path to the empty string and set state to | 13048 | | // opaque path state. | 13049 | 3.17k | else { | 13050 | 3.17k | state = state::OPAQUE_PATH; | 13051 | 3.17k | } | 13052 | 21.0k | } | 13053 | | // Otherwise, if state override is not given, set buffer to the empty | 13054 | | // string, state to no scheme state, and start over (from the first code | 13055 | | // point in input). | 13056 | 739 | else { | 13057 | 739 | state = state::NO_SCHEME; | 13058 | 739 | input_position = 0; | 13059 | 739 | break; | 13060 | 739 | } | 13061 | 21.0k | input_position++; | 13062 | 21.0k | break; | 13063 | 21.7k | } | 13064 | 22.7k | case state::NO_SCHEME: { | 13065 | 22.7k | ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); | 13066 | | // The fragment was pruned from url_data before the state machine ran, | 13067 | | // so 'c is U+0023 (#)' holds exactly when a fragment was found and | 13068 | | // nothing else remains in front of it. | 13069 | 22.7k | const bool c_is_hash = | 13070 | 22.7k | fragment.has_value() && input_position == input_size; | 13071 | | // If base is null, or base has an opaque path and c is not U+0023 (#), | 13072 | | // validation error, return failure. | 13073 | 22.7k | if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) { | 13074 | 21.7k | ada_log("NO_SCHEME validation error"); | 13075 | 21.7k | url.is_valid = false; | 13076 | 21.7k | return url; | 13077 | 21.7k | } | 13078 | | // Otherwise, if base has an opaque path and c is U+0023 (#), | 13079 | | // set url's scheme to base's scheme, url's path to base's path, url's | 13080 | | // query to base's query, and set state to fragment state. | 13081 | 999 | else if (base_url->has_opaque_path && c_is_hash) { | 13082 | 45 | ada_log("NO_SCHEME opaque base with fragment"); | 13083 | 45 | url.copy_scheme(*base_url); | 13084 | 45 | url.has_opaque_path = base_url->has_opaque_path; | 13085 | | | 13086 | | if constexpr (result_type_is_ada_url) { | 13087 | | url.path = base_url->path; | 13088 | | url.query = base_url->query; | 13089 | 45 | } else { | 13090 | 45 | url.update_base_pathname(base_url->get_pathname()); | 13091 | 45 | if (base_url->has_search()) { | 13092 | | // get_search() returns "" for an empty query string (URL ends | 13093 | | // with '?'). update_base_search("") would incorrectly clear the | 13094 | | // query, so pass "?" to preserve the empty query distinction. | 13095 | 21 | auto s = base_url->get_search(); | 13096 | 21 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13097 | 21 | } | 13098 | 45 | } | 13099 | 45 | url.update_unencoded_base_hash(*fragment); | 13100 | 45 | enforce_max_input_length(); | 13101 | 45 | return url; | 13102 | 45 | } | 13103 | | // Otherwise, if base's scheme is not "file", set state to relative | 13104 | | // state and decrease pointer by 1. | 13105 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13106 | 954 | else if (base_url->type != scheme::type::FILE) { | 13107 | 745 | ada_log("NO_SCHEME non-file relative path"); | 13108 | 745 | state = state::RELATIVE_SCHEME; | 13109 | 745 | } | 13110 | | // Otherwise, set state to file state and decrease pointer by 1. | 13111 | 209 | else { | 13112 | 209 | ada_log("NO_SCHEME file base type"); | 13113 | 209 | state = state::FILE; | 13114 | 209 | } | 13115 | 954 | break; | 13116 | 22.7k | } | 13117 | 13.9k | case state::AUTHORITY: { | 13118 | 13.9k | ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); | 13119 | | // most URLs have no @. Having no @ tells us that we don't have to worry | 13120 | | // about AUTHORITY. Of course, we could have @ and still not have to | 13121 | | // worry about AUTHORITY. | 13122 | | // TODO: Instead of just collecting a bool, collect the location of the | 13123 | | // '@' and do something useful with it. | 13124 | | // TODO: We could do various processing early on, using a single pass | 13125 | | // over the string to collect information about it, e.g., telling us | 13126 | | // whether there is a @ and if so, where (or how many). | 13127 | | | 13128 | | // Check if url data contains an @. | 13129 | 13.9k | if (url_data.find('@', input_position) == std::string_view::npos) { | 13130 | 12.7k | state = state::HOST; | 13131 | 12.7k | break; | 13132 | 12.7k | } | 13133 | 1.22k | bool at_sign_seen{false}; | 13134 | 1.22k | bool password_token_seen{false}; | 13135 | | /** | 13136 | | * We expect something of the sort... | 13137 | | * https://user:pass@example.com:1234/foo/bar?baz#quux | 13138 | | * --------^ | 13139 | | */ | 13140 | 7.59k | do { | 13141 | 7.59k | std::string_view view = url_data.substr(input_position); | 13142 | | // The delimiters are @, /, ? \\. | 13143 | 7.59k | size_t location = | 13144 | 7.59k | url.is_special() ? helpers::find_authority_delimiter_special(view) | 13145 | 7.59k | : helpers::find_authority_delimiter(view); | 13146 | 7.59k | std::string_view authority_view = view.substr(0, location); | 13147 | 7.59k | size_t end_of_authority = input_position + authority_view.size(); | 13148 | | // If c is U+0040 (@), then: | 13149 | 7.59k | if ((end_of_authority != input_size) && | 13150 | 6.82k | (url_data[end_of_authority] == '@')) { | 13151 | | // If atSignSeen is true, then prepend "%40" to buffer. | 13152 | 6.37k | if (at_sign_seen) { | 13153 | 5.29k | if (password_token_seen) { | 13154 | | if constexpr (result_type_is_ada_url) { | 13155 | | url.password += "%40"; | 13156 | 2.21k | } else { | 13157 | 2.21k | url.append_base_password("%40"); | 13158 | 2.21k | } | 13159 | 3.07k | } else { | 13160 | | if constexpr (result_type_is_ada_url) { | 13161 | | url.username += "%40"; | 13162 | 3.07k | } else { | 13163 | 3.07k | url.append_base_username("%40"); | 13164 | 3.07k | } | 13165 | 3.07k | } | 13166 | 5.29k | } | 13167 | | | 13168 | 6.37k | at_sign_seen = true; | 13169 | | | 13170 | 6.37k | if (!password_token_seen) { | 13171 | 4.15k | size_t password_token_location = authority_view.find(':'); | 13172 | 4.15k | password_token_seen = | 13173 | 4.15k | password_token_location != std::string_view::npos; | 13174 | | | 13175 | 4.15k | if constexpr (store_values) { | 13176 | 4.15k | if (!password_token_seen) { | 13177 | | if constexpr (result_type_is_ada_url) { | 13178 | | url.username += unicode::percent_encode( | 13179 | | authority_view, | 13180 | | character_sets::USERINFO_PERCENT_ENCODE); | 13181 | 3.75k | } else { | 13182 | 3.75k | url.append_base_username(unicode::percent_encode( | 13183 | 3.75k | authority_view, | 13184 | 3.75k | character_sets::USERINFO_PERCENT_ENCODE)); | 13185 | 3.75k | } | 13186 | 3.75k | } else { | 13187 | | if constexpr (result_type_is_ada_url) { | 13188 | | url.username += unicode::percent_encode( | 13189 | | authority_view.substr(0, password_token_location), | 13190 | | character_sets::USERINFO_PERCENT_ENCODE); | 13191 | | url.password += unicode::percent_encode( | 13192 | | authority_view.substr(password_token_location + 1), | 13193 | | character_sets::USERINFO_PERCENT_ENCODE); | 13194 | 401 | } else { | 13195 | 401 | url.append_base_username(unicode::percent_encode( | 13196 | 401 | authority_view.substr(0, password_token_location), | 13197 | 401 | character_sets::USERINFO_PERCENT_ENCODE)); | 13198 | 401 | url.append_base_password(unicode::percent_encode( | 13199 | 401 | authority_view.substr(password_token_location + 1), | 13200 | 401 | character_sets::USERINFO_PERCENT_ENCODE)); | 13201 | 401 | } | 13202 | 401 | } | 13203 | 4.15k | } | 13204 | 4.15k | } else if constexpr (store_values) { | 13205 | | if constexpr (result_type_is_ada_url) { | 13206 | | url.password += unicode::percent_encode( | 13207 | | authority_view, character_sets::USERINFO_PERCENT_ENCODE); | 13208 | 2.21k | } else { | 13209 | 2.21k | url.append_base_password(unicode::percent_encode( | 13210 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE)); | 13211 | 2.21k | } | 13212 | 2.21k | } | 13213 | 6.37k | } | 13214 | | // Otherwise, if one of the following is true: | 13215 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13216 | | // - url is special and c is U+005C (\) | 13217 | 1.22k | else if (end_of_authority == input_size || | 13218 | 449 | url_data[end_of_authority] == '/' || | 13219 | 43 | url_data[end_of_authority] == '?' || | 13220 | 1.22k | (url.is_special() && url_data[end_of_authority] == '\\')) { | 13221 | | // If atSignSeen is true and authority_view is the empty string, | 13222 | | // validation error, return failure. | 13223 | 1.22k | if (at_sign_seen && authority_view.empty()) { | 13224 | 337 | url.is_valid = false; | 13225 | 337 | return url; | 13226 | 337 | } | 13227 | 888 | state = state::HOST; | 13228 | 888 | break; | 13229 | 1.22k | } | 13230 | 6.37k | if (end_of_authority == input_size) { | 13231 | 0 | if constexpr (store_values) { | 13232 | 0 | if (fragment.has_value()) { | 13233 | 0 | url.update_unencoded_base_hash(*fragment); | 13234 | 0 | } | 13235 | 0 | } | 13236 | 0 | enforce_max_input_length(); | 13237 | 0 | return url; | 13238 | 0 | } | 13239 | 6.37k | input_position = end_of_authority + 1; | 13240 | 6.37k | } while (true); | 13241 | | | 13242 | 888 | break; | 13243 | 1.22k | } | 13244 | 888 | case state::SPECIAL_RELATIVE_OR_AUTHORITY: { | 13245 | 414 | ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", | 13246 | 414 | helpers::substring(url_data, input_position)); | 13247 | | | 13248 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13249 | | // then set state to special authority ignore slashes state and increase | 13250 | | // pointer by 1. | 13251 | 414 | if (url_data.substr(input_position, 2) == "//") { | 13252 | 342 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13253 | 342 | input_position += 2; | 13254 | 342 | } else { | 13255 | | // Otherwise, validation error, set state to relative state and | 13256 | | // decrease pointer by 1. | 13257 | 72 | state = state::RELATIVE_SCHEME; | 13258 | 72 | } | 13259 | | | 13260 | 414 | break; | 13261 | 1.22k | } | 13262 | 2.19k | case state::PATH_OR_AUTHORITY: { | 13263 | 2.19k | ada_log("PATH_OR_AUTHORITY ", | 13264 | 2.19k | helpers::substring(url_data, input_position)); | 13265 | | | 13266 | | // If c is U+002F (/), then set state to authority state. | 13267 | 2.19k | if ((input_position != input_size) && | 13268 | 2.08k | (url_data[input_position] == '/')) { | 13269 | 887 | state = state::AUTHORITY; | 13270 | 887 | input_position++; | 13271 | 1.30k | } else { | 13272 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13273 | 1.30k | state = state::PATH; | 13274 | 1.30k | } | 13275 | | | 13276 | 2.19k | break; | 13277 | 1.22k | } | 13278 | 817 | case state::RELATIVE_SCHEME: { | 13279 | 817 | ada_log("RELATIVE_SCHEME ", | 13280 | 817 | helpers::substring(url_data, input_position)); | 13281 | | | 13282 | | // Set url's scheme to base's scheme. | 13283 | 817 | url.copy_scheme(*base_url); | 13284 | | | 13285 | | // If c is U+002F (/), then set state to relative slash state. | 13286 | 817 | if ((input_position != input_size) && | 13287 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13288 | 669 | (url_data[input_position] == '/')) { | 13289 | 68 | ada_log( | 13290 | 68 | "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " | 13291 | 68 | "slash state"); | 13292 | 68 | state = state::RELATIVE_SLASH; | 13293 | 749 | } else if (url.is_special() && (input_position != input_size) && | 13294 | 507 | (url_data[input_position] == '\\')) { | 13295 | | // Otherwise, if url is special and c is U+005C (\), validation error, | 13296 | | // set state to relative slash state. | 13297 | 2 | ada_log( | 13298 | 2 | "RELATIVE_SCHEME if url is special and c is U+005C, validation " | 13299 | 2 | "error, set state to relative slash state"); | 13300 | 2 | state = state::RELATIVE_SLASH; | 13301 | 747 | } else { | 13302 | 747 | ada_log("RELATIVE_SCHEME otherwise"); | 13303 | | // Set url's username to base's username, url's password to base's | 13304 | | // password, url's host to base's host, url's port to base's port, | 13305 | | // url's path to a clone of base's path, and url's query to base's | 13306 | | // query. | 13307 | | if constexpr (result_type_is_ada_url) { | 13308 | | url.username = base_url->username; | 13309 | | url.password = base_url->password; | 13310 | | url.host = base_url->host; | 13311 | | url.port = base_url->port; | 13312 | | // cloning the base path includes cloning the has_opaque_path flag | 13313 | | url.has_opaque_path = base_url->has_opaque_path; | 13314 | | url.path = base_url->path; | 13315 | | url.query = base_url->query; | 13316 | 747 | } else { | 13317 | 747 | url.update_base_authority(base_url->get_href(), | 13318 | 747 | base_url->get_components()); | 13319 | 747 | url.update_host_to_base_host(base_url->get_hostname()); | 13320 | 747 | url.update_base_port(base_url->retrieve_base_port()); | 13321 | | // cloning the base path includes cloning the has_opaque_path flag | 13322 | 747 | url.has_opaque_path = base_url->has_opaque_path; | 13323 | 747 | url.update_base_pathname(base_url->get_pathname()); | 13324 | 747 | if (base_url->has_search()) { | 13325 | | // get_search() returns "" for an empty query string (URL ends | 13326 | | // with '?'). update_base_search("") would incorrectly clear the | 13327 | | // query, so pass "?" to preserve the empty query distinction. | 13328 | 85 | auto s = base_url->get_search(); | 13329 | 85 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13330 | 85 | } | 13331 | 747 | } | 13332 | | | 13333 | 747 | url.has_opaque_path = base_url->has_opaque_path; | 13334 | | | 13335 | | // If c is U+003F (?), then set url's query to the empty string, and | 13336 | | // state to query state. | 13337 | 747 | if ((input_position != input_size) && | 13338 | 599 | (url_data[input_position] == '?')) { | 13339 | 80 | state = state::QUERY; | 13340 | 80 | } | 13341 | | // Otherwise, if c is not the EOF code point: | 13342 | 667 | else if (input_position != input_size) { | 13343 | | // Set url's query to null. | 13344 | 519 | url.clear_search(); | 13345 | | if constexpr (result_type_is_ada_url) { | 13346 | | // Shorten url's path. | 13347 | | helpers::shorten_path(url.path, url.type); | 13348 | 519 | } else { | 13349 | 519 | std::string_view path = url.get_pathname(); | 13350 | 519 | if (helpers::shorten_path(path, url.type)) { | 13351 | 515 | url.update_base_pathname(std::move(std::string(path))); | 13352 | 515 | } | 13353 | 519 | } | 13354 | | // Set state to path state and decrease pointer by 1. | 13355 | 519 | state = state::PATH; | 13356 | 519 | break; | 13357 | 519 | } | 13358 | 747 | } | 13359 | 298 | input_position++; | 13360 | 298 | break; | 13361 | 817 | } | 13362 | 70 | case state::RELATIVE_SLASH: { | 13363 | 70 | ada_log("RELATIVE_SLASH ", | 13364 | 70 | helpers::substring(url_data, input_position)); | 13365 | | | 13366 | | // If url is special and c is U+002F (/) or U+005C (\), then: | 13367 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13368 | 70 | if (url.is_special() && (input_position != input_size) && | 13369 | 42 | (url_data[input_position] == '/' || | 13370 | 38 | url_data[input_position] == '\\')) { | 13371 | | // Set state to special authority ignore slashes state. | 13372 | 6 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13373 | 6 | } | 13374 | | // Otherwise, if c is U+002F (/), then set state to authority state. | 13375 | 64 | else if ((input_position != input_size) && | 13376 | 46 | (url_data[input_position] == '/')) { | 13377 | 5 | state = state::AUTHORITY; | 13378 | 5 | } | 13379 | | // Otherwise, set | 13380 | | // - url's username to base's username, | 13381 | | // - url's password to base's password, | 13382 | | // - url's host to base's host, | 13383 | | // - url's port to base's port, | 13384 | | // - state to path state, and then, decrease pointer by 1. | 13385 | 59 | else { | 13386 | | if constexpr (result_type_is_ada_url) { | 13387 | | url.username = base_url->username; | 13388 | | url.password = base_url->password; | 13389 | | url.host = base_url->host; | 13390 | | url.port = base_url->port; | 13391 | 59 | } else { | 13392 | 59 | url.update_base_authority(base_url->get_href(), | 13393 | 59 | base_url->get_components()); | 13394 | 59 | url.update_host_to_base_host(base_url->get_hostname()); | 13395 | 59 | url.update_base_port(base_url->retrieve_base_port()); | 13396 | 59 | } | 13397 | 59 | state = state::PATH; | 13398 | 59 | break; | 13399 | 59 | } | 13400 | | | 13401 | 11 | input_position++; | 13402 | 11 | break; | 13403 | 70 | } | 13404 | 12.6k | case state::SPECIAL_AUTHORITY_SLASHES: { | 13405 | 12.6k | ada_log("SPECIAL_AUTHORITY_SLASHES ", | 13406 | 12.6k | helpers::substring(url_data, input_position)); | 13407 | | | 13408 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13409 | | // then set state to special authority ignore slashes state and increase | 13410 | | // pointer by 1. | 13411 | 12.6k | if (url_data.substr(input_position, 2) == "//") { | 13412 | 3.23k | input_position += 2; | 13413 | 3.23k | } | 13414 | | | 13415 | 12.6k | [[fallthrough]]; | 13416 | 12.6k | } | 13417 | 13.0k | case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { | 13418 | 13.0k | ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", | 13419 | 13.0k | helpers::substring(url_data, input_position)); | 13420 | | | 13421 | | // If c is neither U+002F (/) nor U+005C (\), then set state to | 13422 | | // authority state and decrease pointer by 1. | 13423 | 14.0k | while ((input_position != input_size) && | 13424 | 13.9k | ((url_data[input_position] == '/') || | 13425 | 13.3k | (url_data[input_position] == '\\'))) { | 13426 | 1.03k | input_position++; | 13427 | 1.03k | } | 13428 | 13.0k | state = state::AUTHORITY; | 13429 | | | 13430 | 13.0k | break; | 13431 | 12.6k | } | 13432 | 1.17k | case state::QUERY: { | 13433 | 1.17k | ada_log("QUERY ", helpers::substring(url_data, input_position)); | 13434 | 1.17k | if constexpr (store_values) { | 13435 | | // Let queryPercentEncodeSet be the special-query percent-encode set | 13436 | | // if url is special; otherwise the query percent-encode set. | 13437 | 1.17k | const uint8_t* query_percent_encode_set = | 13438 | 1.17k | url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE | 13439 | 1.17k | : character_sets::QUERY_PERCENT_ENCODE; | 13440 | | | 13441 | | // Percent-encode after encoding, with encoding, buffer, and | 13442 | | // queryPercentEncodeSet, and append the result to url's query. | 13443 | 1.17k | url.update_base_search(url_data.substr(input_position), | 13444 | 1.17k | query_percent_encode_set); | 13445 | 1.17k | ada_log("QUERY update_base_search completed "); | 13446 | 1.17k | if (fragment.has_value()) { | 13447 | 307 | url.update_unencoded_base_hash(*fragment); | 13448 | 307 | } | 13449 | 1.17k | } | 13450 | 1.17k | enforce_max_input_length(); | 13451 | 1.17k | return url; | 13452 | 12.6k | } | 13453 | 13.5k | case state::HOST: { | 13454 | 13.5k | ada_log("HOST ", helpers::substring(url_data, input_position)); | 13455 | | | 13456 | 13.5k | std::string_view host_view = url_data.substr(input_position); | 13457 | 13.5k | auto [location, found_colon] = | 13458 | 13.5k | helpers::get_host_delimiter_location(url.is_special(), host_view); | 13459 | 13.5k | input_position = (location != std::string_view::npos) | 13460 | 13.5k | ? input_position + location | 13461 | 13.5k | : input_size; | 13462 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: | 13463 | | // Note: the 'found_colon' value is true if and only if a colon was | 13464 | | // encountered while not inside brackets. | 13465 | 13.5k | if (found_colon) { | 13466 | | // If buffer is the empty string, validation error, return failure. | 13467 | | // Let host be the result of host parsing buffer with url is not | 13468 | | // special. | 13469 | 2.43k | ada_log("HOST parsing ", host_view); | 13470 | 2.43k | if (!url.parse_host(host_view)) { | 13471 | 211 | return url; | 13472 | 211 | } | 13473 | 2.22k | ada_log("HOST parsing results in ", url.get_hostname()); | 13474 | | // Set url's host to host, buffer to the empty string, and state to | 13475 | | // port state. | 13476 | 2.22k | state = state::PORT; | 13477 | 2.22k | input_position++; | 13478 | 2.22k | } | 13479 | | // Otherwise, if one of the following is true: | 13480 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13481 | | // - url is special and c is U+005C (\) | 13482 | | // The get_host_delimiter_location function either brings us to | 13483 | | // the colon outside of the bracket, or to one of those characters. | 13484 | 11.1k | else { | 13485 | | // If url is special and host_view is the empty string, validation | 13486 | | // error, return failure. | 13487 | 11.1k | if (host_view.empty() && url.is_special()) { | 13488 | 91 | url.is_valid = false; | 13489 | 91 | return url; | 13490 | 91 | } | 13491 | 11.0k | ada_log("HOST parsing ", host_view, " href=", url.get_href()); | 13492 | | // Let host be the result of host parsing host_view with url is not | 13493 | | // special. | 13494 | 11.0k | if (host_view.empty()) { | 13495 | 131 | url.update_base_hostname(""); | 13496 | 10.9k | } else if (!url.parse_host(host_view)) { | 13497 | 2.29k | return url; | 13498 | 2.29k | } | 13499 | 8.76k | ada_log("HOST parsing results in ", url.get_hostname(), | 13500 | 8.76k | " href=", url.get_href()); | 13501 | | | 13502 | | // Set url's host to host, and state to path start state. | 13503 | 8.76k | state = state::PATH_START; | 13504 | 8.76k | } | 13505 | | | 13506 | 10.9k | break; | 13507 | 13.5k | } | 13508 | 10.9k | case state::OPAQUE_PATH: { | 13509 | 3.17k | ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); | 13510 | | // Opaque path, query, and fragment are structurally always valid: | 13511 | | // the parser would just percent-encode whatever is there. When we | 13512 | | // are not storing values (can_parse), we can return immediately. | 13513 | | // We must set has_opaque_path = true before returning so that when | 13514 | | // this URL is used as an internal base inside can_parse, NO_SCHEME | 13515 | | // correctly rejects relative inputs against an opaque-path base | 13516 | | // (e.g. can_parse("", &"W:") must return false). | 13517 | | if constexpr (!store_values) { | 13518 | | url.has_opaque_path = true; | 13519 | | return url; | 13520 | | } | 13521 | 3.17k | std::string_view view = url_data.substr(input_position); | 13522 | | // If c is U+003F (?), then set url's query to the empty string and | 13523 | | // state to query state. | 13524 | 3.17k | size_t location = view.find('?'); | 13525 | 3.17k | if (location != std::string_view::npos) { | 13526 | 281 | view.remove_suffix(view.size() - location); | 13527 | 281 | state = state::QUERY; | 13528 | 281 | input_position += location + 1; | 13529 | 2.89k | } else { | 13530 | 2.89k | input_position = input_size + 1; | 13531 | 2.89k | } | 13532 | 3.17k | url.has_opaque_path = true; | 13533 | | | 13534 | | // This is a really unlikely scenario in real world. We should not seek | 13535 | | // to optimize it. | 13536 | 3.17k | if (view.ends_with(' ')) { | 13537 | 112 | std::string modified_view = | 13538 | 112 | std::string(view.substr(0, view.size() - 1)) + "%20"; | 13539 | 112 | url.update_base_pathname(unicode::percent_encode( | 13540 | 112 | modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13541 | 3.06k | } else { | 13542 | 3.06k | url.update_base_pathname(unicode::percent_encode( | 13543 | 3.06k | view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13544 | 3.06k | } | 13545 | 3.17k | break; | 13546 | 13.5k | } | 13547 | 2.22k | case state::PORT: { | 13548 | 2.22k | ada_log("PORT ", helpers::substring(url_data, input_position)); | 13549 | 2.22k | std::string_view port_view = url_data.substr(input_position); | 13550 | 2.22k | input_position += url.parse_port(port_view, true); | 13551 | 2.22k | if (!url.is_valid) { | 13552 | 118 | return url; | 13553 | 118 | } | 13554 | 2.11k | state = state::PATH_START; | 13555 | 2.11k | [[fallthrough]]; | 13556 | 2.11k | } | 13557 | 12.7k | case state::PATH_START: { | 13558 | 12.7k | ada_log("PATH_START ", helpers::substring(url_data, input_position)); | 13559 | | // Path, query, and fragment are structurally always valid: the | 13560 | | // parser would just percent-encode whatever is there. When we are | 13561 | | // not storing values (can_parse), we can return immediately since | 13562 | | // no subsequent state can invalidate the URL. | 13563 | | if constexpr (!store_values) { | 13564 | | return url; | 13565 | | } | 13566 | | | 13567 | | // If url is special, then: | 13568 | 12.7k | if (url.is_special()) { | 13569 | | // Set state to path state. | 13570 | 12.0k | state = state::PATH; | 13571 | | | 13572 | | // Optimization: Avoiding going into PATH state improves the | 13573 | | // performance of urls ending with /. | 13574 | 12.0k | if (input_position == input_size) { | 13575 | 6.42k | if constexpr (store_values) { | 13576 | 6.42k | url.update_base_pathname("/"); | 13577 | 6.42k | if (fragment.has_value()) { | 13578 | 166 | url.update_unencoded_base_hash(*fragment); | 13579 | 166 | } | 13580 | 6.42k | } | 13581 | 6.42k | enforce_max_input_length(); | 13582 | 6.42k | return url; | 13583 | 6.42k | } | 13584 | | // If c is neither U+002F (/) nor U+005C (\), then decrease pointer | 13585 | | // by 1. We know that (input_position == input_size) is impossible | 13586 | | // here, because of the previous if-check. | 13587 | 5.59k | if ((url_data[input_position] != '/') && | 13588 | 387 | (url_data[input_position] != '\\')) { | 13589 | 373 | break; | 13590 | 373 | } | 13591 | 5.59k | } | 13592 | | // Otherwise, if state override is not given and c is U+003F (?), | 13593 | | // set url's query to the empty string and state to query state. | 13594 | 755 | else if ((input_position != input_size) && | 13595 | 160 | (url_data[input_position] == '?')) { | 13596 | 51 | state = state::QUERY; | 13597 | 51 | } | 13598 | | // Otherwise, if c is not the EOF code point: | 13599 | 704 | else if (input_position != input_size) { | 13600 | | // Set state to path state. | 13601 | 109 | state = state::PATH; | 13602 | | | 13603 | | // If c is not U+002F (/), then decrease pointer by 1. | 13604 | 109 | if (url_data[input_position] != '/') { | 13605 | 0 | break; | 13606 | 0 | } | 13607 | 109 | } | 13608 | | | 13609 | 5.97k | input_position++; | 13610 | 5.97k | break; | 13611 | 12.7k | } | 13612 | 8.23k | case state::PATH: { | 13613 | 8.23k | ada_log("PATH ", helpers::substring(url_data, input_position)); | 13614 | | // Path, query, and fragment are structurally always valid: the | 13615 | | // parser would just percent-encode whatever is there. When we are | 13616 | | // not storing values (can_parse), we can return immediately since | 13617 | | // no subsequent state can invalidate the URL. | 13618 | | if constexpr (!store_values) { | 13619 | | return url; | 13620 | | } | 13621 | 8.23k | std::string_view view = url_data.substr(input_position); | 13622 | | | 13623 | | // Most time, we do not need percent encoding. | 13624 | | // Furthermore, we can immediately locate the '?'. | 13625 | 8.23k | size_t locofquestionmark = view.find('?'); | 13626 | 8.23k | if (locofquestionmark != std::string_view::npos) { | 13627 | 760 | state = state::QUERY; | 13628 | 760 | view.remove_suffix(view.size() - locofquestionmark); | 13629 | 760 | input_position += locofquestionmark + 1; | 13630 | 7.47k | } else { | 13631 | 7.47k | input_position = input_size + 1; | 13632 | 7.47k | } | 13633 | 8.23k | if constexpr (store_values) { | 13634 | | if constexpr (result_type_is_ada_url) { | 13635 | | helpers::parse_prepared_path(view, url.type, url.path); | 13636 | 8.23k | } else { | 13637 | 8.23k | url.consume_prepared_path(view); | 13638 | 8.23k | ADA_ASSERT_TRUE(url.validate()); | 13639 | 8.23k | } | 13640 | 8.23k | } | 13641 | 8.23k | break; | 13642 | 12.7k | } | 13643 | 2.20k | case state::FILE_SLASH: { | 13644 | 2.20k | ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); | 13645 | | | 13646 | | // If c is U+002F (/) or U+005C (\), then: | 13647 | 2.20k | if ((input_position != input_size) && | 13648 | 2.13k | (url_data[input_position] == '/' || | 13649 | 2.09k | url_data[input_position] == '\\')) { | 13650 | 2.09k | ada_log("FILE_SLASH c is U+002F or U+005C"); | 13651 | | // Set state to file host state. | 13652 | 2.09k | state = state::FILE_HOST; | 13653 | 2.09k | input_position++; | 13654 | 2.09k | } else { | 13655 | 110 | ada_log("FILE_SLASH otherwise"); | 13656 | | // If base is non-null and base's scheme is "file", then: | 13657 | | // Note: it is unsafe to do base_url->scheme unless you know that | 13658 | | // base_url_has_value() is true. | 13659 | 110 | if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13660 | | // Set url's host to base's host. | 13661 | | if constexpr (result_type_is_ada_url) { | 13662 | | url.host = base_url->host; | 13663 | 86 | } else { | 13664 | 86 | url.update_host_to_base_host(base_url->get_host()); | 13665 | 86 | } | 13666 | | // If the code point substring from pointer to the end of input does | 13667 | | // not start with a Windows drive letter and base's path[0] is a | 13668 | | // normalized Windows drive letter, then append base's path[0] to | 13669 | | // url's path. | 13670 | 86 | if (!base_url->get_pathname().empty()) { | 13671 | 86 | if (!checkers::is_windows_drive_letter( | 13672 | 86 | url_data.substr(input_position))) { | 13673 | 81 | std::string_view first_base_url_path = | 13674 | 81 | base_url->get_pathname().substr(1); | 13675 | 81 | size_t loc = first_base_url_path.find('/'); | 13676 | 81 | if (loc != std::string_view::npos) { | 13677 | 11 | helpers::resize(first_base_url_path, loc); | 13678 | 11 | } | 13679 | 81 | if (checkers::is_normalized_windows_drive_letter( | 13680 | 81 | first_base_url_path)) { | 13681 | | if constexpr (result_type_is_ada_url) { | 13682 | | url.path += '/'; | 13683 | | url.path += first_base_url_path; | 13684 | 2 | } else { | 13685 | 2 | url.append_base_pathname( | 13686 | 2 | helpers::concat("/", first_base_url_path)); | 13687 | 2 | } | 13688 | 2 | } | 13689 | 81 | } | 13690 | 86 | } | 13691 | 86 | } | 13692 | | | 13693 | | // Set state to path state, and decrease pointer by 1. | 13694 | 110 | state = state::PATH; | 13695 | 110 | } | 13696 | | | 13697 | 2.20k | break; | 13698 | 12.7k | } | 13699 | 2.09k | case state::FILE_HOST: { | 13700 | 2.09k | ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); | 13701 | 2.09k | std::string_view view = url_data.substr(input_position); | 13702 | | | 13703 | 2.09k | size_t location = view.find_first_of("/\\?"); | 13704 | 2.09k | std::string_view file_host_buffer = view.substr( | 13705 | 2.09k | 0, (location != std::string_view::npos) ? location : view.size()); | 13706 | | | 13707 | 2.09k | if (checkers::is_windows_drive_letter(file_host_buffer)) { | 13708 | 12 | state = state::PATH; | 13709 | 2.08k | } else if (file_host_buffer.empty()) { | 13710 | | // Set url's host to the empty string. | 13711 | | if constexpr (result_type_is_ada_url) { | 13712 | | url.host = ""; | 13713 | 257 | } else { | 13714 | 257 | url.update_base_hostname(""); | 13715 | 257 | } | 13716 | | // Set state to path start state. | 13717 | 257 | state = state::PATH_START; | 13718 | 1.82k | } else { | 13719 | 1.82k | size_t consumed_bytes = file_host_buffer.size(); | 13720 | 1.82k | input_position += consumed_bytes; | 13721 | | // Let host be the result of host parsing buffer with url is not | 13722 | | // special. | 13723 | 1.82k | if (!url.parse_host(file_host_buffer)) { | 13724 | 188 | return url; | 13725 | 188 | } | 13726 | | | 13727 | | if constexpr (result_type_is_ada_url) { | 13728 | | // If host is "localhost", then set host to the empty string. | 13729 | | if (url.host.has_value() && url.host.value() == "localhost") { | 13730 | | url.host = ""; | 13731 | | } | 13732 | 1.63k | } else { | 13733 | 1.63k | if (url.get_hostname() == "localhost") { | 13734 | 12 | url.update_base_hostname(""); | 13735 | 12 | } | 13736 | 1.63k | } | 13737 | | | 13738 | | // Set buffer to the empty string and state to path start state. | 13739 | 1.63k | state = state::PATH_START; | 13740 | 1.63k | } | 13741 | | | 13742 | 1.90k | break; | 13743 | 2.09k | } | 13744 | 2.77k | case state::FILE: { | 13745 | 2.77k | ada_log("FILE ", helpers::substring(url_data, input_position)); | 13746 | 2.77k | std::string_view file_view = url_data.substr(input_position); | 13747 | | | 13748 | 2.77k | url.set_protocol_as_file(); | 13749 | | if constexpr (result_type_is_ada_url) { | 13750 | | // Set url's host to the empty string. | 13751 | | url.host = ""; | 13752 | 2.77k | } else { | 13753 | 2.77k | url.update_base_hostname(""); | 13754 | 2.77k | } | 13755 | | // If c is U+002F (/) or U+005C (\), then: | 13756 | 2.77k | if (input_position != input_size && | 13757 | 2.66k | (url_data[input_position] == '/' || | 13758 | 2.20k | url_data[input_position] == '\\')) { | 13759 | 2.20k | ada_log("FILE c is U+002F or U+005C"); | 13760 | | // Set state to file slash state. | 13761 | 2.20k | state = state::FILE_SLASH; | 13762 | 2.20k | } | 13763 | | // Otherwise, if base is non-null and base's scheme is "file": | 13764 | 574 | else if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13765 | | // Set url's host to base's host, url's path to a clone of base's | 13766 | | // path, and url's query to base's query. | 13767 | 140 | ada_log("FILE base non-null"); | 13768 | | if constexpr (result_type_is_ada_url) { | 13769 | | url.host = base_url->host; | 13770 | | url.path = base_url->path; | 13771 | | url.query = base_url->query; | 13772 | 140 | } else { | 13773 | 140 | url.update_host_to_base_host(base_url->get_hostname()); | 13774 | 140 | url.update_base_pathname(base_url->get_pathname()); | 13775 | 140 | if (base_url->has_search()) { | 13776 | | // get_search() returns "" for an empty query string (URL ends | 13777 | | // with '?'). update_base_search("") would incorrectly clear the | 13778 | | // query, so pass "?" to preserve the empty query distinction. | 13779 | 43 | auto s = base_url->get_search(); | 13780 | 43 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13781 | 43 | } | 13782 | 140 | } | 13783 | 140 | url.has_opaque_path = base_url->has_opaque_path; | 13784 | | | 13785 | | // If c is U+003F (?), then set url's query to the empty string and | 13786 | | // state to query state. | 13787 | 140 | if (input_position != input_size && url_data[input_position] == '?') { | 13788 | 4 | state = state::QUERY; | 13789 | 4 | } | 13790 | | // Otherwise, if c is not the EOF code point: | 13791 | 136 | else if (input_position != input_size) { | 13792 | | // Set url's query to null. | 13793 | 89 | url.clear_search(); | 13794 | | // If the code point substring from pointer to the end of input does | 13795 | | // not start with a Windows drive letter, then shorten url's path. | 13796 | 89 | if (!checkers::is_windows_drive_letter(file_view)) { | 13797 | | if constexpr (result_type_is_ada_url) { | 13798 | | helpers::shorten_path(url.path, url.type); | 13799 | 76 | } else { | 13800 | 76 | std::string_view path = url.get_pathname(); | 13801 | 76 | if (helpers::shorten_path(path, url.type)) { | 13802 | 74 | url.update_base_pathname(std::move(std::string(path))); | 13803 | 74 | } | 13804 | 76 | } | 13805 | 76 | } | 13806 | | // Otherwise: | 13807 | 13 | else { | 13808 | | // Set url's path to an empty list. | 13809 | 13 | url.clear_pathname(); | 13810 | 13 | url.has_opaque_path = true; | 13811 | 13 | } | 13812 | | | 13813 | | // Set state to path state and decrease pointer by 1. | 13814 | 89 | state = state::PATH; | 13815 | 89 | break; | 13816 | 89 | } | 13817 | 140 | } | 13818 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13819 | 434 | else { | 13820 | 434 | ada_log("FILE go to path"); | 13821 | 434 | state = state::PATH; | 13822 | 434 | break; | 13823 | 434 | } | 13824 | | | 13825 | 2.25k | input_position++; | 13826 | 2.25k | break; | 13827 | 2.77k | } | 13828 | 0 | default: | 13829 | 0 | unreachable(); | 13830 | 164k | } | 13831 | 164k | } | 13832 | 16.4k | if constexpr (store_values) { | 13833 | 16.4k | if (fragment.has_value()) { | 13834 | 346 | url.update_unencoded_base_hash(*fragment); | 13835 | 346 | } | 13836 | 16.4k | } | 13837 | 16.4k | enforce_max_input_length(); | 13838 | 16.4k | return url; | 13839 | 49.0k | } |
ada::url_aggregator ada::parser::parse_url_impl<ada::url_aggregator, false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*) Line | Count | Source | 12819 | 30.3k | const result_type* base_url) { | 12820 | | // We can specialize the implementation per type. | 12821 | | // Important: result_type_is_ada_url is evaluated at *compile time*. This | 12822 | | // means that doing if constexpr(result_type_is_ada_url) { something } else { | 12823 | | // something else } is free (at runtime). This means that ada::url_aggregator | 12824 | | // and ada::url **do not have to support the exact same API**. | 12825 | 30.3k | constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>; | 12826 | 30.3k | constexpr bool result_type_is_ada_url_aggregator = | 12827 | 30.3k | std::is_same_v<url_aggregator, result_type>; | 12828 | 30.3k | static_assert(result_type_is_ada_url || | 12829 | 30.3k | result_type_is_ada_url_aggregator); // We don't support | 12830 | | // anything else for now. | 12831 | | | 12832 | 30.3k | ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), | 12833 | 30.3k | " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), | 12834 | 30.3k | ")"); | 12835 | | | 12836 | 30.3k | result_type url{}; | 12837 | | | 12838 | 30.3k | const uint32_t max_input_length = ada::get_max_input_length(); | 12839 | | | 12840 | | // Normalization (percent-encoding, IDNA) can push the serialized URL past | 12841 | | // max_input_length even when the input fit under it. The check at the end of | 12842 | | // the state machine covers URLs that run to completion, but several states | 12843 | | // return early after appending a query or fragment, so run the same check on | 12844 | | // those exits too. Without this, a query- or fragment-terminated URL such as | 12845 | | // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent | 12846 | | // https://x/?<...> that takes the absolute fast path is rejected. | 12847 | 30.3k | const auto enforce_max_input_length = [&]() { | 12848 | 30.3k | if constexpr (store_values) { | 12849 | 30.3k | if (url.is_valid) { | 12850 | 30.3k | if constexpr (result_type_is_ada_url_aggregator) { | 12851 | 30.3k | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12852 | 30.3k | url.is_valid = false; | 12853 | 30.3k | } | 12854 | 30.3k | } else { | 12855 | 30.3k | if (url.get_href_size() > max_input_length) [[unlikely]] { | 12856 | 30.3k | url.is_valid = false; | 12857 | 30.3k | } | 12858 | 30.3k | } | 12859 | 30.3k | } | 12860 | 30.3k | } | 12861 | 30.3k | }; | 12862 | | | 12863 | | // We refuse to parse URL strings that exceed the maximum input length. | 12864 | | // By default, this is 4GB but can be configured via | 12865 | | // ada::set_max_input_length(). | 12866 | 30.3k | if (user_input.size() > max_input_length) [[unlikely]] { | 12867 | 0 | url.is_valid = false; | 12868 | 0 | } | 12869 | | // Going forward, user_input.size() is in [0, | 12870 | | // std::numeric_limits<uint32_t>::max). If we are provided with an invalid | 12871 | | // base, or the optional_url was invalid, we must return. | 12872 | 30.3k | if (base_url != nullptr) { | 12873 | 4.35k | url.is_valid &= base_url->is_valid; | 12874 | 4.35k | } | 12875 | 30.3k | if (!url.is_valid) { | 12876 | 0 | return url; | 12877 | 0 | } | 12878 | | | 12879 | | // Simple absolute / relative fast paths (before tabs/newline scan). | 12880 | | if constexpr (store_values) { | 12881 | | bool hit_fast_path = false; | 12882 | | if (base_url == nullptr) { | 12883 | | // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline | 12884 | | // call so those URLs (including SetHref) do not pay for a miss. | 12885 | | const auto* p = reinterpret_cast<const uint8_t*>(user_input.data()); | 12886 | | const size_t n = user_input.size(); | 12887 | | size_t host_start = 0; | 12888 | | if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') { | 12889 | | host_start = 7; | 12890 | | } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') { | 12891 | | host_start = 8; | 12892 | | } | 12893 | | const uint8_t host_first = host_start != 0 ? p[host_start] : 0; | 12894 | | const bool skip_ip = | 12895 | | host_first == '[' || (host_first >= '0' && host_first <= '9'); | 12896 | | const bool skip_userinfo = | 12897 | | host_start != 0 && authority_has_at(p, host_start, n); | 12898 | | hit_fast_path = !skip_ip && !skip_userinfo && | 12899 | | try_parse_simple_absolute(user_input, url); | 12900 | | } else { | 12901 | | hit_fast_path = try_parse_simple_relative(user_input, *base_url, url); | 12902 | | } | 12903 | | if (hit_fast_path) { | 12904 | | if constexpr (result_type_is_ada_url_aggregator) { | 12905 | | if (url.buffer.size() > max_input_length) [[unlikely]] { | 12906 | | url.is_valid = false; | 12907 | | } | 12908 | | } else { | 12909 | | // For a small absolute input, even worst-case normalization cannot | 12910 | | // exceed the limit: percent encoding expands at most 3x and IDNA at | 12911 | | // most 4.5x. Avoid traversing every stored component on the common | 12912 | | // default-limit path. | 12913 | | if ((base_url != nullptr || | 12914 | | user_input.size() > static_cast<size_t>(max_input_length) / 5) && | 12915 | | url.get_href_size() > max_input_length) [[unlikely]] { | 12916 | | url.is_valid = false; | 12917 | | } | 12918 | | } | 12919 | | return url; | 12920 | | } | 12921 | | } | 12922 | | | 12923 | 30.3k | state state = state::SCHEME_START; | 12924 | | | 12925 | 30.3k | std::string tmp_buffer; | 12926 | 30.3k | std::string_view url_data; | 12927 | 30.3k | if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { | 12928 | 277 | tmp_buffer = user_input; | 12929 | | // Optimization opportunity: Instead of copying and then pruning, we could | 12930 | | // just directly build the string from user_input. | 12931 | 277 | helpers::remove_ascii_tab_or_newline(tmp_buffer); | 12932 | 277 | url_data = tmp_buffer; | 12933 | 30.0k | } else [[likely]] { | 12934 | 30.0k | url_data = user_input; | 12935 | 30.0k | } | 12936 | | | 12937 | | // Leading and trailing control characters are uncommon and easy to deal with | 12938 | | // (no performance concern). | 12939 | 30.3k | helpers::trim_c0_whitespace(url_data); | 12940 | | | 12941 | | if constexpr (result_type_is_ada_url_aggregator && store_values) { | 12942 | | // Most of the time, we just need user_input.size(). | 12943 | | // In some instances, we may need a bit more. | 12944 | | /////////////////////////// | 12945 | | // This is *very* important. This line should *not* be removed | 12946 | | // hastily. There are principled reasons why reserve is important | 12947 | | // for performance. If you have a benchmark with small inputs, | 12948 | | // it may not matter, but in other instances, it could. | 12949 | | //// | 12950 | | // This rounds up to the next power of two. | 12951 | | // We know that user_input.size() is in [0, | 12952 | | // std::numeric_limits<uint32_t>::max). | 12953 | | uint32_t reserve_capacity = | 12954 | | (0xFFFFFFFF >> | 12955 | | helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + | 12956 | | 1; | 12957 | | url.reserve(reserve_capacity); | 12958 | | } | 12959 | | | 12960 | | // Optimization opportunity. Most websites do not have fragment. | 12961 | 30.3k | std::optional<std::string_view> fragment = helpers::prune_hash(url_data); | 12962 | | // We add it last so that an implementation like ada::url_aggregator | 12963 | | // can append it last to its internal buffer, thus improving performance. | 12964 | | | 12965 | | // Here url_data no longer has its fragment. | 12966 | | // We are going to access the data from url_data (it is immutable). | 12967 | | // At any given time, we are pointing at byte 'input_position' in url_data. | 12968 | | // The input_position variable should range from 0 to input_size. | 12969 | | // It is illegal to access url_data at input_size. | 12970 | 30.3k | size_t input_position = 0; | 12971 | 30.3k | const size_t input_size = url_data.size(); | 12972 | | // Keep running the following state machine by switching on state. | 12973 | | // If after a run pointer points to the EOF code point, go to the next step. | 12974 | | // Otherwise, increase pointer by 1 and continue with the state machine. | 12975 | | // We never decrement input_position. | 12976 | 131k | while (input_position <= input_size) { | 12977 | 131k | ada_log("In parsing at ", input_position, " out of ", input_size, | 12978 | 131k | " in state ", ada::to_string(state)); | 12979 | 131k | switch (state) { | 12980 | 30.3k | case state::SCHEME_START: { | 12981 | 30.3k | ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); | 12982 | | // If c is an ASCII alpha, append c, lowercased, to buffer, and set | 12983 | | // state to scheme state. | 12984 | 30.3k | if ((input_position != input_size) && | 12985 | 22.3k | checkers::is_alpha(url_data[input_position])) { | 12986 | 21.6k | state = state::SCHEME; | 12987 | 21.6k | input_position++; | 12988 | 21.6k | } else { | 12989 | | // Otherwise, if state override is not given, set state to no scheme | 12990 | | // state and decrease pointer by 1. | 12991 | 8.74k | state = state::NO_SCHEME; | 12992 | 8.74k | } | 12993 | 30.3k | break; | 12994 | 0 | } | 12995 | 21.6k | case state::SCHEME: { | 12996 | 21.6k | ada_log("SCHEME ", helpers::substring(url_data, input_position)); | 12997 | | // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), | 12998 | | // append c, lowercased, to buffer. | 12999 | 53.9k | while ((input_position != input_size) && | 13000 | 53.5k | (unicode::is_alnum_plus(url_data[input_position]))) { | 13001 | 32.2k | input_position++; | 13002 | 32.2k | } | 13003 | | // Otherwise, if c is U+003A (:), then: | 13004 | 21.6k | if ((input_position != input_size) && | 13005 | 21.2k | (url_data[input_position] == ':')) { | 13006 | 21.0k | ada_log("SCHEME the scheme should be ", | 13007 | 21.0k | url_data.substr(0, input_position)); | 13008 | | if constexpr (result_type_is_ada_url) { | 13009 | | if (!url.parse_scheme(url_data.substr(0, input_position))) { | 13010 | | return url; | 13011 | | } | 13012 | 21.0k | } else { | 13013 | | // we pass the colon along instead of painfully adding it back. | 13014 | 21.0k | if (!url.parse_scheme_with_colon( | 13015 | 21.0k | url_data.substr(0, input_position + 1))) { | 13016 | 0 | return url; | 13017 | 0 | } | 13018 | 21.0k | } | 13019 | 21.0k | ada_log("SCHEME the scheme is ", url.get_protocol()); | 13020 | | | 13021 | | // If url's scheme is "file", then: | 13022 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13023 | 21.0k | if (url.type == scheme::type::FILE) { | 13024 | | // Set state to file state. | 13025 | 2.56k | state = state::FILE; | 13026 | 2.56k | } | 13027 | | // Otherwise, if url is special, base is non-null, and base's scheme | 13028 | | // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url | 13029 | | // != nullptr is false. | 13030 | 18.4k | else if (url.is_special() && base_url != nullptr && | 13031 | 2.24k | base_url->type == url.type) { | 13032 | | // Set state to special relative or authority state. | 13033 | 414 | state = state::SPECIAL_RELATIVE_OR_AUTHORITY; | 13034 | 414 | } | 13035 | | // Otherwise, if url is special, set state to special authority | 13036 | | // slashes state. | 13037 | 18.0k | else if (url.is_special()) { | 13038 | 12.6k | state = state::SPECIAL_AUTHORITY_SLASHES; | 13039 | 12.6k | } | 13040 | | // Otherwise, if remaining starts with an U+002F (/), set state to | 13041 | | // path or authority state and increase pointer by 1. | 13042 | 5.37k | else if (input_position + 1 < input_size && | 13043 | 3.10k | url_data[input_position + 1] == '/') { | 13044 | 2.19k | state = state::PATH_OR_AUTHORITY; | 13045 | 2.19k | input_position++; | 13046 | 2.19k | } | 13047 | | // Otherwise, set url's path to the empty string and set state to | 13048 | | // opaque path state. | 13049 | 3.17k | else { | 13050 | 3.17k | state = state::OPAQUE_PATH; | 13051 | 3.17k | } | 13052 | 21.0k | } | 13053 | | // Otherwise, if state override is not given, set buffer to the empty | 13054 | | // string, state to no scheme state, and start over (from the first code | 13055 | | // point in input). | 13056 | 597 | else { | 13057 | 597 | state = state::NO_SCHEME; | 13058 | 597 | input_position = 0; | 13059 | 597 | break; | 13060 | 597 | } | 13061 | 21.0k | input_position++; | 13062 | 21.0k | break; | 13063 | 21.6k | } | 13064 | 9.34k | case state::NO_SCHEME: { | 13065 | 9.34k | ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); | 13066 | | // The fragment was pruned from url_data before the state machine ran, | 13067 | | // so 'c is U+0023 (#)' holds exactly when a fragment was found and | 13068 | | // nothing else remains in front of it. | 13069 | 9.34k | const bool c_is_hash = | 13070 | 9.34k | fragment.has_value() && input_position == input_size; | 13071 | | // If base is null, or base has an opaque path and c is not U+0023 (#), | 13072 | | // validation error, return failure. | 13073 | 9.34k | if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) { | 13074 | 8.08k | ada_log("NO_SCHEME validation error"); | 13075 | 8.08k | url.is_valid = false; | 13076 | 8.08k | return url; | 13077 | 8.08k | } | 13078 | | // Otherwise, if base has an opaque path and c is U+0023 (#), | 13079 | | // set url's scheme to base's scheme, url's path to base's path, url's | 13080 | | // query to base's query, and set state to fragment state. | 13081 | 1.25k | else if (base_url->has_opaque_path && c_is_hash) { | 13082 | 45 | ada_log("NO_SCHEME opaque base with fragment"); | 13083 | 45 | url.copy_scheme(*base_url); | 13084 | 45 | url.has_opaque_path = base_url->has_opaque_path; | 13085 | | | 13086 | | if constexpr (result_type_is_ada_url) { | 13087 | | url.path = base_url->path; | 13088 | | url.query = base_url->query; | 13089 | 45 | } else { | 13090 | 45 | url.update_base_pathname(base_url->get_pathname()); | 13091 | 45 | if (base_url->has_search()) { | 13092 | | // get_search() returns "" for an empty query string (URL ends | 13093 | | // with '?'). update_base_search("") would incorrectly clear the | 13094 | | // query, so pass "?" to preserve the empty query distinction. | 13095 | 0 | auto s = base_url->get_search(); | 13096 | 0 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13097 | 0 | } | 13098 | 45 | } | 13099 | 45 | url.update_unencoded_base_hash(*fragment); | 13100 | 45 | enforce_max_input_length(); | 13101 | 45 | return url; | 13102 | 45 | } | 13103 | | // Otherwise, if base's scheme is not "file", set state to relative | 13104 | | // state and decrease pointer by 1. | 13105 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13106 | 1.21k | else if (base_url->type != scheme::type::FILE) { | 13107 | 1.00k | ada_log("NO_SCHEME non-file relative path"); | 13108 | 1.00k | state = state::RELATIVE_SCHEME; | 13109 | 1.00k | } | 13110 | | // Otherwise, set state to file state and decrease pointer by 1. | 13111 | 209 | else { | 13112 | 209 | ada_log("NO_SCHEME file base type"); | 13113 | 209 | state = state::FILE; | 13114 | 209 | } | 13115 | 1.21k | break; | 13116 | 9.34k | } | 13117 | 13.9k | case state::AUTHORITY: { | 13118 | 13.9k | ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); | 13119 | | // most URLs have no @. Having no @ tells us that we don't have to worry | 13120 | | // about AUTHORITY. Of course, we could have @ and still not have to | 13121 | | // worry about AUTHORITY. | 13122 | | // TODO: Instead of just collecting a bool, collect the location of the | 13123 | | // '@' and do something useful with it. | 13124 | | // TODO: We could do various processing early on, using a single pass | 13125 | | // over the string to collect information about it, e.g., telling us | 13126 | | // whether there is a @ and if so, where (or how many). | 13127 | | | 13128 | | // Check if url data contains an @. | 13129 | 13.9k | if (url_data.find('@', input_position) == std::string_view::npos) { | 13130 | 12.6k | state = state::HOST; | 13131 | 12.6k | break; | 13132 | 12.6k | } | 13133 | 1.26k | bool at_sign_seen{false}; | 13134 | 1.26k | bool password_token_seen{false}; | 13135 | | /** | 13136 | | * We expect something of the sort... | 13137 | | * https://user:pass@example.com:1234/foo/bar?baz#quux | 13138 | | * --------^ | 13139 | | */ | 13140 | 7.64k | do { | 13141 | 7.64k | std::string_view view = url_data.substr(input_position); | 13142 | | // The delimiters are @, /, ? \\. | 13143 | 7.64k | size_t location = | 13144 | 7.64k | url.is_special() ? helpers::find_authority_delimiter_special(view) | 13145 | 7.64k | : helpers::find_authority_delimiter(view); | 13146 | 7.64k | std::string_view authority_view = view.substr(0, location); | 13147 | 7.64k | size_t end_of_authority = input_position + authority_view.size(); | 13148 | | // If c is U+0040 (@), then: | 13149 | 7.64k | if ((end_of_authority != input_size) && | 13150 | 6.86k | (url_data[end_of_authority] == '@')) { | 13151 | | // If atSignSeen is true, then prepend "%40" to buffer. | 13152 | 6.37k | if (at_sign_seen) { | 13153 | 5.29k | if (password_token_seen) { | 13154 | | if constexpr (result_type_is_ada_url) { | 13155 | | url.password += "%40"; | 13156 | 2.21k | } else { | 13157 | 2.21k | url.append_base_password("%40"); | 13158 | 2.21k | } | 13159 | 3.07k | } else { | 13160 | | if constexpr (result_type_is_ada_url) { | 13161 | | url.username += "%40"; | 13162 | 3.07k | } else { | 13163 | 3.07k | url.append_base_username("%40"); | 13164 | 3.07k | } | 13165 | 3.07k | } | 13166 | 5.29k | } | 13167 | | | 13168 | 6.37k | at_sign_seen = true; | 13169 | | | 13170 | 6.37k | if (!password_token_seen) { | 13171 | 4.15k | size_t password_token_location = authority_view.find(':'); | 13172 | 4.15k | password_token_seen = | 13173 | 4.15k | password_token_location != std::string_view::npos; | 13174 | | | 13175 | | if constexpr (store_values) { | 13176 | | if (!password_token_seen) { | 13177 | | if constexpr (result_type_is_ada_url) { | 13178 | | url.username += unicode::percent_encode( | 13179 | | authority_view, | 13180 | | character_sets::USERINFO_PERCENT_ENCODE); | 13181 | | } else { | 13182 | | url.append_base_username(unicode::percent_encode( | 13183 | | authority_view, | 13184 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13185 | | } | 13186 | | } else { | 13187 | | if constexpr (result_type_is_ada_url) { | 13188 | | url.username += unicode::percent_encode( | 13189 | | authority_view.substr(0, password_token_location), | 13190 | | character_sets::USERINFO_PERCENT_ENCODE); | 13191 | | url.password += unicode::percent_encode( | 13192 | | authority_view.substr(password_token_location + 1), | 13193 | | character_sets::USERINFO_PERCENT_ENCODE); | 13194 | | } else { | 13195 | | url.append_base_username(unicode::percent_encode( | 13196 | | authority_view.substr(0, password_token_location), | 13197 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13198 | | url.append_base_password(unicode::percent_encode( | 13199 | | authority_view.substr(password_token_location + 1), | 13200 | | character_sets::USERINFO_PERCENT_ENCODE)); | 13201 | | } | 13202 | | } | 13203 | | } | 13204 | 4.15k | } else if constexpr (store_values) { | 13205 | 2.21k | if constexpr (result_type_is_ada_url) { | 13206 | 2.21k | url.password += unicode::percent_encode( | 13207 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE); | 13208 | 2.21k | } else { | 13209 | 2.21k | url.append_base_password(unicode::percent_encode( | 13210 | 2.21k | authority_view, character_sets::USERINFO_PERCENT_ENCODE)); | 13211 | 2.21k | } | 13212 | 2.21k | } | 13213 | 6.37k | } | 13214 | | // Otherwise, if one of the following is true: | 13215 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13216 | | // - url is special and c is U+005C (\) | 13217 | 1.26k | else if (end_of_authority == input_size || | 13218 | 493 | url_data[end_of_authority] == '/' || | 13219 | 45 | url_data[end_of_authority] == '?' || | 13220 | 1.26k | (url.is_special() && url_data[end_of_authority] == '\\')) { | 13221 | | // If atSignSeen is true and authority_view is the empty string, | 13222 | | // validation error, return failure. | 13223 | 1.26k | if (at_sign_seen && authority_view.empty()) { | 13224 | 337 | url.is_valid = false; | 13225 | 337 | return url; | 13226 | 337 | } | 13227 | 932 | state = state::HOST; | 13228 | 932 | break; | 13229 | 1.26k | } | 13230 | 6.37k | if (end_of_authority == input_size) { | 13231 | | if constexpr (store_values) { | 13232 | | if (fragment.has_value()) { | 13233 | | url.update_unencoded_base_hash(*fragment); | 13234 | | } | 13235 | | } | 13236 | 0 | enforce_max_input_length(); | 13237 | 0 | return url; | 13238 | 0 | } | 13239 | 6.37k | input_position = end_of_authority + 1; | 13240 | 6.37k | } while (true); | 13241 | | | 13242 | 932 | break; | 13243 | 1.26k | } | 13244 | 932 | case state::SPECIAL_RELATIVE_OR_AUTHORITY: { | 13245 | 414 | ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", | 13246 | 414 | helpers::substring(url_data, input_position)); | 13247 | | | 13248 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13249 | | // then set state to special authority ignore slashes state and increase | 13250 | | // pointer by 1. | 13251 | 414 | if (url_data.substr(input_position, 2) == "//") { | 13252 | 342 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13253 | 342 | input_position += 2; | 13254 | 342 | } else { | 13255 | | // Otherwise, validation error, set state to relative state and | 13256 | | // decrease pointer by 1. | 13257 | 72 | state = state::RELATIVE_SCHEME; | 13258 | 72 | } | 13259 | | | 13260 | 414 | break; | 13261 | 1.26k | } | 13262 | 2.19k | case state::PATH_OR_AUTHORITY: { | 13263 | 2.19k | ada_log("PATH_OR_AUTHORITY ", | 13264 | 2.19k | helpers::substring(url_data, input_position)); | 13265 | | | 13266 | | // If c is U+002F (/), then set state to authority state. | 13267 | 2.19k | if ((input_position != input_size) && | 13268 | 2.08k | (url_data[input_position] == '/')) { | 13269 | 887 | state = state::AUTHORITY; | 13270 | 887 | input_position++; | 13271 | 1.30k | } else { | 13272 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13273 | 1.30k | state = state::PATH; | 13274 | 1.30k | } | 13275 | | | 13276 | 2.19k | break; | 13277 | 1.26k | } | 13278 | 1.07k | case state::RELATIVE_SCHEME: { | 13279 | 1.07k | ada_log("RELATIVE_SCHEME ", | 13280 | 1.07k | helpers::substring(url_data, input_position)); | 13281 | | | 13282 | | // Set url's scheme to base's scheme. | 13283 | 1.07k | url.copy_scheme(*base_url); | 13284 | | | 13285 | | // If c is U+002F (/), then set state to relative slash state. | 13286 | 1.07k | if ((input_position != input_size) && | 13287 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13288 | 896 | (url_data[input_position] == '/')) { | 13289 | 101 | ada_log( | 13290 | 101 | "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " | 13291 | 101 | "slash state"); | 13292 | 101 | state = state::RELATIVE_SLASH; | 13293 | 974 | } else if (url.is_special() && (input_position != input_size) && | 13294 | 701 | (url_data[input_position] == '\\')) { | 13295 | | // Otherwise, if url is special and c is U+005C (\), validation error, | 13296 | | // set state to relative slash state. | 13297 | 2 | ada_log( | 13298 | 2 | "RELATIVE_SCHEME if url is special and c is U+005C, validation " | 13299 | 2 | "error, set state to relative slash state"); | 13300 | 2 | state = state::RELATIVE_SLASH; | 13301 | 972 | } else { | 13302 | 972 | ada_log("RELATIVE_SCHEME otherwise"); | 13303 | | // Set url's username to base's username, url's password to base's | 13304 | | // password, url's host to base's host, url's port to base's port, | 13305 | | // url's path to a clone of base's path, and url's query to base's | 13306 | | // query. | 13307 | | if constexpr (result_type_is_ada_url) { | 13308 | | url.username = base_url->username; | 13309 | | url.password = base_url->password; | 13310 | | url.host = base_url->host; | 13311 | | url.port = base_url->port; | 13312 | | // cloning the base path includes cloning the has_opaque_path flag | 13313 | | url.has_opaque_path = base_url->has_opaque_path; | 13314 | | url.path = base_url->path; | 13315 | | url.query = base_url->query; | 13316 | 972 | } else { | 13317 | 972 | url.update_base_authority(base_url->get_href(), | 13318 | 972 | base_url->get_components()); | 13319 | 972 | url.update_host_to_base_host(base_url->get_hostname()); | 13320 | 972 | url.update_base_port(base_url->retrieve_base_port()); | 13321 | | // cloning the base path includes cloning the has_opaque_path flag | 13322 | 972 | url.has_opaque_path = base_url->has_opaque_path; | 13323 | 972 | url.update_base_pathname(base_url->get_pathname()); | 13324 | 972 | if (base_url->has_search()) { | 13325 | | // get_search() returns "" for an empty query string (URL ends | 13326 | | // with '?'). update_base_search("") would incorrectly clear the | 13327 | | // query, so pass "?" to preserve the empty query distinction. | 13328 | 0 | auto s = base_url->get_search(); | 13329 | 0 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13330 | 0 | } | 13331 | 972 | } | 13332 | | | 13333 | 972 | url.has_opaque_path = base_url->has_opaque_path; | 13334 | | | 13335 | | // If c is U+003F (?), then set url's query to the empty string, and | 13336 | | // state to query state. | 13337 | 972 | if ((input_position != input_size) && | 13338 | 793 | (url_data[input_position] == '?')) { | 13339 | 115 | state = state::QUERY; | 13340 | 115 | } | 13341 | | // Otherwise, if c is not the EOF code point: | 13342 | 857 | else if (input_position != input_size) { | 13343 | | // Set url's query to null. | 13344 | 678 | url.clear_search(); | 13345 | | if constexpr (result_type_is_ada_url) { | 13346 | | // Shorten url's path. | 13347 | | helpers::shorten_path(url.path, url.type); | 13348 | 678 | } else { | 13349 | 678 | std::string_view path = url.get_pathname(); | 13350 | 678 | if (helpers::shorten_path(path, url.type)) { | 13351 | 0 | url.update_base_pathname(std::move(std::string(path))); | 13352 | 0 | } | 13353 | 678 | } | 13354 | | // Set state to path state and decrease pointer by 1. | 13355 | 678 | state = state::PATH; | 13356 | 678 | break; | 13357 | 678 | } | 13358 | 972 | } | 13359 | 397 | input_position++; | 13360 | 397 | break; | 13361 | 1.07k | } | 13362 | 103 | case state::RELATIVE_SLASH: { | 13363 | 103 | ada_log("RELATIVE_SLASH ", | 13364 | 103 | helpers::substring(url_data, input_position)); | 13365 | | | 13366 | | // If url is special and c is U+002F (/) or U+005C (\), then: | 13367 | | // NOLINTNEXTLINE(bugprone-branch-clone) | 13368 | 103 | if (url.is_special() && (input_position != input_size) && | 13369 | 59 | (url_data[input_position] == '/' || | 13370 | 55 | url_data[input_position] == '\\')) { | 13371 | | // Set state to special authority ignore slashes state. | 13372 | 6 | state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; | 13373 | 6 | } | 13374 | | // Otherwise, if c is U+002F (/), then set state to authority state. | 13375 | 97 | else if ((input_position != input_size) && | 13376 | 63 | (url_data[input_position] == '/')) { | 13377 | 5 | state = state::AUTHORITY; | 13378 | 5 | } | 13379 | | // Otherwise, set | 13380 | | // - url's username to base's username, | 13381 | | // - url's password to base's password, | 13382 | | // - url's host to base's host, | 13383 | | // - url's port to base's port, | 13384 | | // - state to path state, and then, decrease pointer by 1. | 13385 | 92 | else { | 13386 | | if constexpr (result_type_is_ada_url) { | 13387 | | url.username = base_url->username; | 13388 | | url.password = base_url->password; | 13389 | | url.host = base_url->host; | 13390 | | url.port = base_url->port; | 13391 | 92 | } else { | 13392 | 92 | url.update_base_authority(base_url->get_href(), | 13393 | 92 | base_url->get_components()); | 13394 | 92 | url.update_host_to_base_host(base_url->get_hostname()); | 13395 | 92 | url.update_base_port(base_url->retrieve_base_port()); | 13396 | 92 | } | 13397 | 92 | state = state::PATH; | 13398 | 92 | break; | 13399 | 92 | } | 13400 | | | 13401 | 11 | input_position++; | 13402 | 11 | break; | 13403 | 103 | } | 13404 | 12.6k | case state::SPECIAL_AUTHORITY_SLASHES: { | 13405 | 12.6k | ada_log("SPECIAL_AUTHORITY_SLASHES ", | 13406 | 12.6k | helpers::substring(url_data, input_position)); | 13407 | | | 13408 | | // If c is U+002F (/) and remaining starts with U+002F (/), | 13409 | | // then set state to special authority ignore slashes state and increase | 13410 | | // pointer by 1. | 13411 | 12.6k | if (url_data.substr(input_position, 2) == "//") { | 13412 | 3.22k | input_position += 2; | 13413 | 3.22k | } | 13414 | | | 13415 | 12.6k | [[fallthrough]]; | 13416 | 12.6k | } | 13417 | 13.0k | case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { | 13418 | 13.0k | ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", | 13419 | 13.0k | helpers::substring(url_data, input_position)); | 13420 | | | 13421 | | // If c is neither U+002F (/) nor U+005C (\), then set state to | 13422 | | // authority state and decrease pointer by 1. | 13423 | 13.6k | while ((input_position != input_size) && | 13424 | 13.5k | ((url_data[input_position] == '/') || | 13425 | 13.2k | (url_data[input_position] == '\\'))) { | 13426 | 624 | input_position++; | 13427 | 624 | } | 13428 | 13.0k | state = state::AUTHORITY; | 13429 | | | 13430 | 13.0k | break; | 13431 | 12.6k | } | 13432 | 119 | case state::QUERY: { | 13433 | 119 | ada_log("QUERY ", helpers::substring(url_data, input_position)); | 13434 | | if constexpr (store_values) { | 13435 | | // Let queryPercentEncodeSet be the special-query percent-encode set | 13436 | | // if url is special; otherwise the query percent-encode set. | 13437 | | const uint8_t* query_percent_encode_set = | 13438 | | url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE | 13439 | | : character_sets::QUERY_PERCENT_ENCODE; | 13440 | | | 13441 | | // Percent-encode after encoding, with encoding, buffer, and | 13442 | | // queryPercentEncodeSet, and append the result to url's query. | 13443 | | url.update_base_search(url_data.substr(input_position), | 13444 | | query_percent_encode_set); | 13445 | | ada_log("QUERY update_base_search completed "); | 13446 | | if (fragment.has_value()) { | 13447 | | url.update_unencoded_base_hash(*fragment); | 13448 | | } | 13449 | | } | 13450 | 119 | enforce_max_input_length(); | 13451 | 119 | return url; | 13452 | 12.6k | } | 13453 | 13.5k | case state::HOST: { | 13454 | 13.5k | ada_log("HOST ", helpers::substring(url_data, input_position)); | 13455 | | | 13456 | 13.5k | std::string_view host_view = url_data.substr(input_position); | 13457 | 13.5k | auto [location, found_colon] = | 13458 | 13.5k | helpers::get_host_delimiter_location(url.is_special(), host_view); | 13459 | 13.5k | input_position = (location != std::string_view::npos) | 13460 | 13.5k | ? input_position + location | 13461 | 13.5k | : input_size; | 13462 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: | 13463 | | // Note: the 'found_colon' value is true if and only if a colon was | 13464 | | // encountered while not inside brackets. | 13465 | 13.5k | if (found_colon) { | 13466 | | // If buffer is the empty string, validation error, return failure. | 13467 | | // Let host be the result of host parsing buffer with url is not | 13468 | | // special. | 13469 | 2.59k | ada_log("HOST parsing ", host_view); | 13470 | 2.59k | if (!url.parse_host(host_view)) { | 13471 | 201 | return url; | 13472 | 201 | } | 13473 | 2.39k | ada_log("HOST parsing results in ", url.get_hostname()); | 13474 | | // Set url's host to host, buffer to the empty string, and state to | 13475 | | // port state. | 13476 | 2.39k | state = state::PORT; | 13477 | 2.39k | input_position++; | 13478 | 2.39k | } | 13479 | | // Otherwise, if one of the following is true: | 13480 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 13481 | | // - url is special and c is U+005C (\) | 13482 | | // The get_host_delimiter_location function either brings us to | 13483 | | // the colon outside of the bracket, or to one of those characters. | 13484 | 10.9k | else { | 13485 | | // If url is special and host_view is the empty string, validation | 13486 | | // error, return failure. | 13487 | 10.9k | if (host_view.empty() && url.is_special()) { | 13488 | 60 | url.is_valid = false; | 13489 | 60 | return url; | 13490 | 60 | } | 13491 | 10.9k | ada_log("HOST parsing ", host_view, " href=", url.get_href()); | 13492 | | // Let host be the result of host parsing host_view with url is not | 13493 | | // special. | 13494 | 10.9k | if (host_view.empty()) { | 13495 | 131 | url.update_base_hostname(""); | 13496 | 10.7k | } else if (!url.parse_host(host_view)) { | 13497 | 2.29k | return url; | 13498 | 2.29k | } | 13499 | 8.63k | ada_log("HOST parsing results in ", url.get_hostname(), | 13500 | 8.63k | " href=", url.get_href()); | 13501 | | | 13502 | | // Set url's host to host, and state to path start state. | 13503 | 8.63k | state = state::PATH_START; | 13504 | 8.63k | } | 13505 | | | 13506 | 11.0k | break; | 13507 | 13.5k | } | 13508 | 11.0k | case state::OPAQUE_PATH: { | 13509 | 3.17k | ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); | 13510 | | // Opaque path, query, and fragment are structurally always valid: | 13511 | | // the parser would just percent-encode whatever is there. When we | 13512 | | // are not storing values (can_parse), we can return immediately. | 13513 | | // We must set has_opaque_path = true before returning so that when | 13514 | | // this URL is used as an internal base inside can_parse, NO_SCHEME | 13515 | | // correctly rejects relative inputs against an opaque-path base | 13516 | | // (e.g. can_parse("", &"W:") must return false). | 13517 | 3.17k | if constexpr (!store_values) { | 13518 | 3.17k | url.has_opaque_path = true; | 13519 | 3.17k | return url; | 13520 | 3.17k | } | 13521 | 0 | std::string_view view = url_data.substr(input_position); | 13522 | | // If c is U+003F (?), then set url's query to the empty string and | 13523 | | // state to query state. | 13524 | 3.17k | size_t location = view.find('?'); | 13525 | 3.17k | if (location != std::string_view::npos) { | 13526 | 0 | view.remove_suffix(view.size() - location); | 13527 | 0 | state = state::QUERY; | 13528 | 0 | input_position += location + 1; | 13529 | 3.17k | } else { | 13530 | 3.17k | input_position = input_size + 1; | 13531 | 3.17k | } | 13532 | 3.17k | url.has_opaque_path = true; | 13533 | | | 13534 | | // This is a really unlikely scenario in real world. We should not seek | 13535 | | // to optimize it. | 13536 | 3.17k | if (view.ends_with(' ')) { | 13537 | 0 | std::string modified_view = | 13538 | 0 | std::string(view.substr(0, view.size() - 1)) + "%20"; | 13539 | 0 | url.update_base_pathname(unicode::percent_encode( | 13540 | 0 | modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13541 | 3.17k | } else { | 13542 | 3.17k | url.update_base_pathname(unicode::percent_encode( | 13543 | 3.17k | view, character_sets::C0_CONTROL_PERCENT_ENCODE)); | 13544 | 3.17k | } | 13545 | 3.17k | break; | 13546 | 13.5k | } | 13547 | 2.39k | case state::PORT: { | 13548 | 2.39k | ada_log("PORT ", helpers::substring(url_data, input_position)); | 13549 | 2.39k | std::string_view port_view = url_data.substr(input_position); | 13550 | 2.39k | input_position += url.parse_port(port_view, true); | 13551 | 2.39k | if (!url.is_valid) { | 13552 | 98 | return url; | 13553 | 98 | } | 13554 | 2.29k | state = state::PATH_START; | 13555 | 2.29k | [[fallthrough]]; | 13556 | 2.29k | } | 13557 | 12.8k | case state::PATH_START: { | 13558 | 12.8k | ada_log("PATH_START ", helpers::substring(url_data, input_position)); | 13559 | | // Path, query, and fragment are structurally always valid: the | 13560 | | // parser would just percent-encode whatever is there. When we are | 13561 | | // not storing values (can_parse), we can return immediately since | 13562 | | // no subsequent state can invalidate the URL. | 13563 | 12.8k | if constexpr (!store_values) { | 13564 | 12.8k | return url; | 13565 | 12.8k | } | 13566 | | | 13567 | | // If url is special, then: | 13568 | 12.8k | if (url.is_special()) { | 13569 | | // Set state to path state. | 13570 | 0 | state = state::PATH; | 13571 | | | 13572 | | // Optimization: Avoiding going into PATH state improves the | 13573 | | // performance of urls ending with /. | 13574 | 0 | if (input_position == input_size) { | 13575 | | if constexpr (store_values) { | 13576 | | url.update_base_pathname("/"); | 13577 | | if (fragment.has_value()) { | 13578 | | url.update_unencoded_base_hash(*fragment); | 13579 | | } | 13580 | | } | 13581 | 0 | enforce_max_input_length(); | 13582 | 0 | return url; | 13583 | 0 | } | 13584 | | // If c is neither U+002F (/) nor U+005C (\), then decrease pointer | 13585 | | // by 1. We know that (input_position == input_size) is impossible | 13586 | | // here, because of the previous if-check. | 13587 | 0 | if ((url_data[input_position] != '/') && | 13588 | 0 | (url_data[input_position] != '\\')) { | 13589 | 0 | break; | 13590 | 0 | } | 13591 | 0 | } | 13592 | | // Otherwise, if state override is not given and c is U+003F (?), | 13593 | | // set url's query to the empty string and state to query state. | 13594 | 12.8k | else if ((input_position != input_size) && | 13595 | 0 | (url_data[input_position] == '?')) { | 13596 | 0 | state = state::QUERY; | 13597 | 0 | } | 13598 | | // Otherwise, if c is not the EOF code point: | 13599 | 12.8k | else if (input_position != input_size) { | 13600 | | // Set state to path state. | 13601 | 0 | state = state::PATH; | 13602 | | | 13603 | | // If c is not U+002F (/), then decrease pointer by 1. | 13604 | 0 | if (url_data[input_position] != '/') { | 13605 | 0 | break; | 13606 | 0 | } | 13607 | 0 | } | 13608 | | | 13609 | 12.8k | input_position++; | 13610 | 12.8k | break; | 13611 | 12.8k | } | 13612 | 2.72k | case state::PATH: { | 13613 | 2.72k | ada_log("PATH ", helpers::substring(url_data, input_position)); | 13614 | | // Path, query, and fragment are structurally always valid: the | 13615 | | // parser would just percent-encode whatever is there. When we are | 13616 | | // not storing values (can_parse), we can return immediately since | 13617 | | // no subsequent state can invalidate the URL. | 13618 | 2.72k | if constexpr (!store_values) { | 13619 | 2.72k | return url; | 13620 | 2.72k | } | 13621 | 0 | std::string_view view = url_data.substr(input_position); | 13622 | | | 13623 | | // Most time, we do not need percent encoding. | 13624 | | // Furthermore, we can immediately locate the '?'. | 13625 | 2.72k | size_t locofquestionmark = view.find('?'); | 13626 | 2.72k | if (locofquestionmark != std::string_view::npos) { | 13627 | 0 | state = state::QUERY; | 13628 | 0 | view.remove_suffix(view.size() - locofquestionmark); | 13629 | 0 | input_position += locofquestionmark + 1; | 13630 | 2.72k | } else { | 13631 | 2.72k | input_position = input_size + 1; | 13632 | 2.72k | } | 13633 | | if constexpr (store_values) { | 13634 | | if constexpr (result_type_is_ada_url) { | 13635 | | helpers::parse_prepared_path(view, url.type, url.path); | 13636 | | } else { | 13637 | | url.consume_prepared_path(view); | 13638 | | ADA_ASSERT_TRUE(url.validate()); | 13639 | | } | 13640 | | } | 13641 | 2.72k | break; | 13642 | 12.8k | } | 13643 | 2.20k | case state::FILE_SLASH: { | 13644 | 2.20k | ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); | 13645 | | | 13646 | | // If c is U+002F (/) or U+005C (\), then: | 13647 | 2.20k | if ((input_position != input_size) && | 13648 | 2.13k | (url_data[input_position] == '/' || | 13649 | 2.09k | url_data[input_position] == '\\')) { | 13650 | 2.09k | ada_log("FILE_SLASH c is U+002F or U+005C"); | 13651 | | // Set state to file host state. | 13652 | 2.09k | state = state::FILE_HOST; | 13653 | 2.09k | input_position++; | 13654 | 2.09k | } else { | 13655 | 110 | ada_log("FILE_SLASH otherwise"); | 13656 | | // If base is non-null and base's scheme is "file", then: | 13657 | | // Note: it is unsafe to do base_url->scheme unless you know that | 13658 | | // base_url_has_value() is true. | 13659 | 110 | if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13660 | | // Set url's host to base's host. | 13661 | | if constexpr (result_type_is_ada_url) { | 13662 | | url.host = base_url->host; | 13663 | 86 | } else { | 13664 | 86 | url.update_host_to_base_host(base_url->get_host()); | 13665 | 86 | } | 13666 | | // If the code point substring from pointer to the end of input does | 13667 | | // not start with a Windows drive letter and base's path[0] is a | 13668 | | // normalized Windows drive letter, then append base's path[0] to | 13669 | | // url's path. | 13670 | 86 | if (!base_url->get_pathname().empty()) { | 13671 | 0 | if (!checkers::is_windows_drive_letter( | 13672 | 0 | url_data.substr(input_position))) { | 13673 | 0 | std::string_view first_base_url_path = | 13674 | 0 | base_url->get_pathname().substr(1); | 13675 | 0 | size_t loc = first_base_url_path.find('/'); | 13676 | 0 | if (loc != std::string_view::npos) { | 13677 | 0 | helpers::resize(first_base_url_path, loc); | 13678 | 0 | } | 13679 | 0 | if (checkers::is_normalized_windows_drive_letter( | 13680 | 0 | first_base_url_path)) { | 13681 | | if constexpr (result_type_is_ada_url) { | 13682 | | url.path += '/'; | 13683 | | url.path += first_base_url_path; | 13684 | 0 | } else { | 13685 | 0 | url.append_base_pathname( | 13686 | 0 | helpers::concat("/", first_base_url_path)); | 13687 | 0 | } | 13688 | 0 | } | 13689 | 0 | } | 13690 | 0 | } | 13691 | 86 | } | 13692 | | | 13693 | | // Set state to path state, and decrease pointer by 1. | 13694 | 110 | state = state::PATH; | 13695 | 110 | } | 13696 | | | 13697 | 2.20k | break; | 13698 | 12.8k | } | 13699 | 2.09k | case state::FILE_HOST: { | 13700 | 2.09k | ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); | 13701 | 2.09k | std::string_view view = url_data.substr(input_position); | 13702 | | | 13703 | 2.09k | size_t location = view.find_first_of("/\\?"); | 13704 | 2.09k | std::string_view file_host_buffer = view.substr( | 13705 | 2.09k | 0, (location != std::string_view::npos) ? location : view.size()); | 13706 | | | 13707 | 2.09k | if (checkers::is_windows_drive_letter(file_host_buffer)) { | 13708 | 12 | state = state::PATH; | 13709 | 2.08k | } else if (file_host_buffer.empty()) { | 13710 | | // Set url's host to the empty string. | 13711 | | if constexpr (result_type_is_ada_url) { | 13712 | | url.host = ""; | 13713 | 257 | } else { | 13714 | 257 | url.update_base_hostname(""); | 13715 | 257 | } | 13716 | | // Set state to path start state. | 13717 | 257 | state = state::PATH_START; | 13718 | 1.82k | } else { | 13719 | 1.82k | size_t consumed_bytes = file_host_buffer.size(); | 13720 | 1.82k | input_position += consumed_bytes; | 13721 | | // Let host be the result of host parsing buffer with url is not | 13722 | | // special. | 13723 | 1.82k | if (!url.parse_host(file_host_buffer)) { | 13724 | 188 | return url; | 13725 | 188 | } | 13726 | | | 13727 | | if constexpr (result_type_is_ada_url) { | 13728 | | // If host is "localhost", then set host to the empty string. | 13729 | | if (url.host.has_value() && url.host.value() == "localhost") { | 13730 | | url.host = ""; | 13731 | | } | 13732 | 1.63k | } else { | 13733 | 1.63k | if (url.get_hostname() == "localhost") { | 13734 | 12 | url.update_base_hostname(""); | 13735 | 12 | } | 13736 | 1.63k | } | 13737 | | | 13738 | | // Set buffer to the empty string and state to path start state. | 13739 | 1.63k | state = state::PATH_START; | 13740 | 1.63k | } | 13741 | | | 13742 | 1.90k | break; | 13743 | 2.09k | } | 13744 | 2.77k | case state::FILE: { | 13745 | 2.77k | ada_log("FILE ", helpers::substring(url_data, input_position)); | 13746 | 2.77k | std::string_view file_view = url_data.substr(input_position); | 13747 | | | 13748 | 2.77k | url.set_protocol_as_file(); | 13749 | | if constexpr (result_type_is_ada_url) { | 13750 | | // Set url's host to the empty string. | 13751 | | url.host = ""; | 13752 | 2.77k | } else { | 13753 | 2.77k | url.update_base_hostname(""); | 13754 | 2.77k | } | 13755 | | // If c is U+002F (/) or U+005C (\), then: | 13756 | 2.77k | if (input_position != input_size && | 13757 | 2.66k | (url_data[input_position] == '/' || | 13758 | 2.20k | url_data[input_position] == '\\')) { | 13759 | 2.20k | ada_log("FILE c is U+002F or U+005C"); | 13760 | | // Set state to file slash state. | 13761 | 2.20k | state = state::FILE_SLASH; | 13762 | 2.20k | } | 13763 | | // Otherwise, if base is non-null and base's scheme is "file": | 13764 | 574 | else if (base_url != nullptr && base_url->type == scheme::type::FILE) { | 13765 | | // Set url's host to base's host, url's path to a clone of base's | 13766 | | // path, and url's query to base's query. | 13767 | 140 | ada_log("FILE base non-null"); | 13768 | | if constexpr (result_type_is_ada_url) { | 13769 | | url.host = base_url->host; | 13770 | | url.path = base_url->path; | 13771 | | url.query = base_url->query; | 13772 | 140 | } else { | 13773 | 140 | url.update_host_to_base_host(base_url->get_hostname()); | 13774 | 140 | url.update_base_pathname(base_url->get_pathname()); | 13775 | 140 | if (base_url->has_search()) { | 13776 | | // get_search() returns "" for an empty query string (URL ends | 13777 | | // with '?'). update_base_search("") would incorrectly clear the | 13778 | | // query, so pass "?" to preserve the empty query distinction. | 13779 | 0 | auto s = base_url->get_search(); | 13780 | 0 | url.update_base_search(s.empty() ? std::string_view("?") : s); | 13781 | 0 | } | 13782 | 140 | } | 13783 | 140 | url.has_opaque_path = base_url->has_opaque_path; | 13784 | | | 13785 | | // If c is U+003F (?), then set url's query to the empty string and | 13786 | | // state to query state. | 13787 | 140 | if (input_position != input_size && url_data[input_position] == '?') { | 13788 | 4 | state = state::QUERY; | 13789 | 4 | } | 13790 | | // Otherwise, if c is not the EOF code point: | 13791 | 136 | else if (input_position != input_size) { | 13792 | | // Set url's query to null. | 13793 | 89 | url.clear_search(); | 13794 | | // If the code point substring from pointer to the end of input does | 13795 | | // not start with a Windows drive letter, then shorten url's path. | 13796 | 89 | if (!checkers::is_windows_drive_letter(file_view)) { | 13797 | | if constexpr (result_type_is_ada_url) { | 13798 | | helpers::shorten_path(url.path, url.type); | 13799 | 76 | } else { | 13800 | 76 | std::string_view path = url.get_pathname(); | 13801 | 76 | if (helpers::shorten_path(path, url.type)) { | 13802 | 0 | url.update_base_pathname(std::move(std::string(path))); | 13803 | 0 | } | 13804 | 76 | } | 13805 | 76 | } | 13806 | | // Otherwise: | 13807 | 13 | else { | 13808 | | // Set url's path to an empty list. | 13809 | 13 | url.clear_pathname(); | 13810 | 13 | url.has_opaque_path = true; | 13811 | 13 | } | 13812 | | | 13813 | | // Set state to path state and decrease pointer by 1. | 13814 | 89 | state = state::PATH; | 13815 | 89 | break; | 13816 | 89 | } | 13817 | 140 | } | 13818 | | // Otherwise, set state to path state, and decrease pointer by 1. | 13819 | 434 | else { | 13820 | 434 | ada_log("FILE go to path"); | 13821 | 434 | state = state::PATH; | 13822 | 434 | break; | 13823 | 434 | } | 13824 | | | 13825 | 2.25k | input_position++; | 13826 | 2.25k | break; | 13827 | 2.77k | } | 13828 | 0 | default: | 13829 | 0 | unreachable(); | 13830 | 131k | } | 13831 | 131k | } | 13832 | | if constexpr (store_values) { | 13833 | | if (fragment.has_value()) { | 13834 | | url.update_unencoded_base_hash(*fragment); | 13835 | | } | 13836 | | } | 13837 | 226 | enforce_max_input_length(); | 13838 | 226 | return url; | 13839 | 30.3k | } |
|
13840 | | |
13841 | | template bool try_parse_simple_absolute<url>(std::string_view, url&); |
13842 | | template bool try_parse_simple_absolute<url_aggregator>(std::string_view, |
13843 | | url_aggregator&); |
13844 | | template bool finish_simple_absolute_with_port<url>(std::string_view, url&, |
13845 | | ada::scheme::type, uint32_t, |
13846 | | size_t, size_t, size_t, |
13847 | | bool); |
13848 | | template bool finish_simple_absolute_with_port<url_aggregator>( |
13849 | | std::string_view, url_aggregator&, ada::scheme::type, uint32_t, size_t, |
13850 | | size_t, size_t, bool); |
13851 | | template bool try_parse_simple_relative<url>(std::string_view, const url&, |
13852 | | url&); |
13853 | | template bool try_parse_simple_relative<url_aggregator>(std::string_view, |
13854 | | const url_aggregator&, |
13855 | | url_aggregator&); |
13856 | | |
13857 | | template url parse_url_impl<url, true>(std::string_view user_input, |
13858 | | const url* base_url = nullptr); |
13859 | | template url_aggregator parse_url_impl<url_aggregator, true>( |
13860 | | std::string_view user_input, const url_aggregator* base_url = nullptr); |
13861 | | template url_aggregator parse_url_impl<url_aggregator, false>( |
13862 | | std::string_view user_input, const url_aggregator* base_url = nullptr); |
13863 | | |
13864 | | template <class result_type> |
13865 | | result_type parse_url(std::string_view user_input, |
13866 | 0 | const result_type* base_url) { |
13867 | 0 | return parse_url_impl<result_type, true>(user_input, base_url); |
13868 | 0 | } Unexecuted instantiation: ada::url ada::parser::parse_url<ada::url>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url const*) Unexecuted instantiation: ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, ada::url_aggregator const*) |
13869 | | |
13870 | | template url parse_url<url>(std::string_view user_input, |
13871 | | const url* base_url = nullptr); |
13872 | | template url_aggregator parse_url<url_aggregator>( |
13873 | | std::string_view user_input, const url_aggregator* base_url = nullptr); |
13874 | | } // namespace ada::parser |
13875 | | /* end file src/parser.cpp */ |
13876 | | /* begin file src/url_components.cpp */ |
13877 | | |
13878 | | #include <iterator> |
13879 | | #include <string> |
13880 | | |
13881 | | namespace ada { |
13882 | | |
13883 | 0 | [[nodiscard]] std::string url_components::to_string() const { |
13884 | 0 | std::string answer; |
13885 | 0 | auto back = std::back_insert_iterator(answer); |
13886 | 0 | answer.append("{\n"); |
13887 | |
|
13888 | 0 | answer.append("\t\"protocol_end\":\""); |
13889 | 0 | helpers::encode_json(std::to_string(protocol_end), back); |
13890 | 0 | answer.append("\",\n"); |
13891 | |
|
13892 | 0 | answer.append("\t\"username_end\":\""); |
13893 | 0 | helpers::encode_json(std::to_string(username_end), back); |
13894 | 0 | answer.append("\",\n"); |
13895 | |
|
13896 | 0 | answer.append("\t\"host_start\":\""); |
13897 | 0 | helpers::encode_json(std::to_string(host_start), back); |
13898 | 0 | answer.append("\",\n"); |
13899 | |
|
13900 | 0 | answer.append("\t\"host_end\":\""); |
13901 | 0 | helpers::encode_json(std::to_string(host_end), back); |
13902 | 0 | answer.append("\",\n"); |
13903 | |
|
13904 | 0 | answer.append("\t\"port\":\""); |
13905 | 0 | helpers::encode_json(std::to_string(port), back); |
13906 | 0 | answer.append("\",\n"); |
13907 | |
|
13908 | 0 | answer.append("\t\"pathname_start\":\""); |
13909 | 0 | helpers::encode_json(std::to_string(pathname_start), back); |
13910 | 0 | answer.append("\",\n"); |
13911 | |
|
13912 | 0 | answer.append("\t\"search_start\":\""); |
13913 | 0 | helpers::encode_json(std::to_string(search_start), back); |
13914 | 0 | answer.append("\",\n"); |
13915 | |
|
13916 | 0 | answer.append("\t\"hash_start\":\""); |
13917 | 0 | helpers::encode_json(std::to_string(hash_start), back); |
13918 | 0 | answer.append("\",\n"); |
13919 | |
|
13920 | 0 | answer.append("\n}"); |
13921 | 0 | return answer; |
13922 | 0 | } |
13923 | | |
13924 | | } // namespace ada |
13925 | | /* end file src/url_components.cpp */ |
13926 | | /* begin file src/url_aggregator.cpp */ |
13927 | | |
13928 | | #include <algorithm> |
13929 | | #include <array> |
13930 | | #include <cstdint> |
13931 | | #include <cstring> |
13932 | | #include <iterator> |
13933 | | #include <optional> |
13934 | | #include <ranges> |
13935 | | #include <string> |
13936 | | #include <string_view> |
13937 | | #include <utility> |
13938 | | |
13939 | | namespace { |
13940 | | |
13941 | | ada_really_inline void apply_shifted_non_scheme_offsets( |
13942 | 43.9k | ada::url_components& components, uint32_t new_difference) { |
13943 | 43.9k | components.username_end += new_difference; |
13944 | 43.9k | components.host_start += new_difference; |
13945 | 43.9k | components.host_end += new_difference; |
13946 | 43.9k | components.pathname_start += new_difference; |
13947 | 43.9k | if (components.search_start != ada::url_components::omitted) { |
13948 | 0 | components.search_start += new_difference; |
13949 | 0 | } |
13950 | 43.9k | if (components.hash_start != ada::url_components::omitted) { |
13951 | 0 | components.hash_start += new_difference; |
13952 | 0 | } |
13953 | 43.9k | } |
13954 | | |
13955 | | } // namespace |
13956 | | |
13957 | | namespace ada { |
13958 | | template <bool has_state_override> |
13959 | | [[nodiscard]] ada_really_inline bool url_aggregator::parse_scheme_with_colon( |
13960 | 42.0k | const std::string_view input_with_colon) { |
13961 | 42.0k | ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon); |
13962 | 42.0k | ADA_ASSERT_TRUE(validate()); |
13963 | 42.0k | ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer)); |
13964 | 42.0k | std::string_view input{input_with_colon}; |
13965 | 42.0k | input.remove_suffix(1); |
13966 | 42.0k | auto parsed_type = ada::scheme::get_scheme_type(input); |
13967 | 42.0k | const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); |
13968 | | /** |
13969 | | * In the common case, we will immediately recognize a special scheme (e.g., |
13970 | | *http, https), in which case, we can go really fast. |
13971 | | **/ |
13972 | 42.0k | if (is_input_special) { // fast path!!! |
13973 | 20.5k | if constexpr (has_state_override) { |
13974 | | // If url's scheme is not a special scheme and buffer is a special scheme, |
13975 | | // then return. |
13976 | 0 | if (is_special() != is_input_special) { |
13977 | 0 | return false; |
13978 | 0 | } |
13979 | | |
13980 | | // If url includes credentials or has a non-null port, and buffer is |
13981 | | // "file", then return. |
13982 | 0 | if ((has_credentials() || components.port != url_components::omitted) && |
13983 | 0 | parsed_type == ada::scheme::type::FILE) { |
13984 | 0 | return false; |
13985 | 0 | } |
13986 | | |
13987 | | // If url's scheme is "file" and its host is an empty host, then return. |
13988 | | // An empty host is the empty string. |
13989 | 0 | if (type == ada::scheme::type::FILE && |
13990 | 0 | components.host_start == components.host_end) { |
13991 | 0 | return false; |
13992 | 0 | } |
13993 | 0 | } |
13994 | | |
13995 | 0 | type = parsed_type; |
13996 | 20.5k | set_scheme_from_view_with_colon(input_with_colon); |
13997 | | |
13998 | 20.5k | if constexpr (has_state_override) { |
13999 | | // This is uncommon. |
14000 | 0 | uint16_t urls_scheme_port = get_special_port(); |
14001 | |
|
14002 | 0 | if (urls_scheme_port) { |
14003 | | // If url's port is url's scheme's default port, then set url's port to |
14004 | | // null. |
14005 | 0 | if (components.port == urls_scheme_port) { |
14006 | 0 | clear_port(); |
14007 | 0 | } |
14008 | 0 | } |
14009 | 0 | } |
14010 | 21.5k | } else { // slow path |
14011 | 21.5k | std::string _buffer(input); |
14012 | | // Next function is only valid if the input is ASCII and returns false |
14013 | | // otherwise, but it seems that we always have ascii content so we do not |
14014 | | // need to check the return value. |
14015 | 21.5k | unicode::to_lower_ascii(_buffer.data(), _buffer.size()); |
14016 | | |
14017 | 21.5k | if constexpr (has_state_override) { |
14018 | | // The state-override validation errors below ("return" in the WHATWG URL |
14019 | | // parser) leave the URL unchanged. The setter contract is |
14020 | | // "true on success, false if the scheme is invalid" -- the fast path |
14021 | | // above already returns false here, so the slow path must agree. |
14022 | | |
14023 | | // If url's scheme is a special scheme and buffer is not a special scheme, |
14024 | | // then return. If url's scheme is not a special scheme and buffer is a |
14025 | | // special scheme, then return. |
14026 | 0 | if (is_special() != ada::scheme::is_special(_buffer)) { |
14027 | 0 | return false; |
14028 | 0 | } |
14029 | | |
14030 | | // If url includes credentials or has a non-null port, and buffer is |
14031 | | // "file", then return. |
14032 | 0 | if ((has_credentials() || components.port != url_components::omitted) && |
14033 | 0 | _buffer == "file") { |
14034 | 0 | return false; |
14035 | 0 | } |
14036 | | |
14037 | | // If url's scheme is "file" and its host is an empty host, then return. |
14038 | | // An empty host is the empty string. |
14039 | 0 | if (type == ada::scheme::type::FILE && |
14040 | 0 | components.host_start == components.host_end) { |
14041 | 0 | return false; |
14042 | 0 | } |
14043 | 0 | } |
14044 | | |
14045 | 0 | set_scheme(_buffer); |
14046 | | |
14047 | 21.5k | if constexpr (has_state_override) { |
14048 | | // This is uncommon. |
14049 | 0 | uint16_t urls_scheme_port = get_special_port(); |
14050 | |
|
14051 | 0 | if (urls_scheme_port) { |
14052 | | // If url's port is url's scheme's default port, then set url's port to |
14053 | | // null. |
14054 | 0 | if (components.port == urls_scheme_port) { |
14055 | 0 | clear_port(); |
14056 | 0 | } |
14057 | 0 | } |
14058 | 0 | } |
14059 | 21.5k | } |
14060 | 0 | ADA_ASSERT_TRUE(validate()); |
14061 | 42.0k | return true; |
14062 | 42.0k | } bool ada::url_aggregator::parse_scheme_with_colon<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 13960 | 42.0k | const std::string_view input_with_colon) { | 13961 | 42.0k | ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon); | 13962 | 42.0k | ADA_ASSERT_TRUE(validate()); | 13963 | 42.0k | ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer)); | 13964 | 42.0k | std::string_view input{input_with_colon}; | 13965 | 42.0k | input.remove_suffix(1); | 13966 | 42.0k | auto parsed_type = ada::scheme::get_scheme_type(input); | 13967 | 42.0k | const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); | 13968 | | /** | 13969 | | * In the common case, we will immediately recognize a special scheme (e.g., | 13970 | | *http, https), in which case, we can go really fast. | 13971 | | **/ | 13972 | 42.0k | if (is_input_special) { // fast path!!! | 13973 | | if constexpr (has_state_override) { | 13974 | | // If url's scheme is not a special scheme and buffer is a special scheme, | 13975 | | // then return. | 13976 | | if (is_special() != is_input_special) { | 13977 | | return false; | 13978 | | } | 13979 | | | 13980 | | // If url includes credentials or has a non-null port, and buffer is | 13981 | | // "file", then return. | 13982 | | if ((has_credentials() || components.port != url_components::omitted) && | 13983 | | parsed_type == ada::scheme::type::FILE) { | 13984 | | return false; | 13985 | | } | 13986 | | | 13987 | | // If url's scheme is "file" and its host is an empty host, then return. | 13988 | | // An empty host is the empty string. | 13989 | | if (type == ada::scheme::type::FILE && | 13990 | | components.host_start == components.host_end) { | 13991 | | return false; | 13992 | | } | 13993 | | } | 13994 | | | 13995 | 20.5k | type = parsed_type; | 13996 | 20.5k | set_scheme_from_view_with_colon(input_with_colon); | 13997 | | | 13998 | | if constexpr (has_state_override) { | 13999 | | // This is uncommon. | 14000 | | uint16_t urls_scheme_port = get_special_port(); | 14001 | | | 14002 | | if (urls_scheme_port) { | 14003 | | // If url's port is url's scheme's default port, then set url's port to | 14004 | | // null. | 14005 | | if (components.port == urls_scheme_port) { | 14006 | | clear_port(); | 14007 | | } | 14008 | | } | 14009 | | } | 14010 | 21.5k | } else { // slow path | 14011 | 21.5k | std::string _buffer(input); | 14012 | | // Next function is only valid if the input is ASCII and returns false | 14013 | | // otherwise, but it seems that we always have ascii content so we do not | 14014 | | // need to check the return value. | 14015 | 21.5k | unicode::to_lower_ascii(_buffer.data(), _buffer.size()); | 14016 | | | 14017 | | if constexpr (has_state_override) { | 14018 | | // The state-override validation errors below ("return" in the WHATWG URL | 14019 | | // parser) leave the URL unchanged. The setter contract is | 14020 | | // "true on success, false if the scheme is invalid" -- the fast path | 14021 | | // above already returns false here, so the slow path must agree. | 14022 | | | 14023 | | // If url's scheme is a special scheme and buffer is not a special scheme, | 14024 | | // then return. If url's scheme is not a special scheme and buffer is a | 14025 | | // special scheme, then return. | 14026 | | if (is_special() != ada::scheme::is_special(_buffer)) { | 14027 | | return false; | 14028 | | } | 14029 | | | 14030 | | // If url includes credentials or has a non-null port, and buffer is | 14031 | | // "file", then return. | 14032 | | if ((has_credentials() || components.port != url_components::omitted) && | 14033 | | _buffer == "file") { | 14034 | | return false; | 14035 | | } | 14036 | | | 14037 | | // If url's scheme is "file" and its host is an empty host, then return. | 14038 | | // An empty host is the empty string. | 14039 | | if (type == ada::scheme::type::FILE && | 14040 | | components.host_start == components.host_end) { | 14041 | | return false; | 14042 | | } | 14043 | | } | 14044 | | | 14045 | 21.5k | set_scheme(_buffer); | 14046 | | | 14047 | | if constexpr (has_state_override) { | 14048 | | // This is uncommon. | 14049 | | uint16_t urls_scheme_port = get_special_port(); | 14050 | | | 14051 | | if (urls_scheme_port) { | 14052 | | // If url's port is url's scheme's default port, then set url's port to | 14053 | | // null. | 14054 | | if (components.port == urls_scheme_port) { | 14055 | | clear_port(); | 14056 | | } | 14057 | | } | 14058 | | } | 14059 | 21.5k | } | 14060 | 42.0k | ADA_ASSERT_TRUE(validate()); | 14061 | 42.0k | return true; | 14062 | 42.0k | } |
Unexecuted instantiation: bool ada::url_aggregator::parse_scheme_with_colon<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
14063 | | |
14064 | 1.98k | inline void url_aggregator::copy_scheme(const url_aggregator& u) { |
14065 | 1.98k | ada_log("url_aggregator::copy_scheme ", u.buffer); |
14066 | 1.98k | ADA_ASSERT_TRUE(validate()); |
14067 | | // next line could overflow but unsigned arithmetic has well-defined |
14068 | | // overflows. |
14069 | 1.98k | uint32_t new_difference = u.components.protocol_end - components.protocol_end; |
14070 | | |
14071 | 1.98k | type = u.type; |
14072 | 1.98k | buffer.erase(0, components.protocol_end); |
14073 | 1.98k | buffer.insert(0, u.get_protocol()); |
14074 | 1.98k | components.protocol_end = u.components.protocol_end; |
14075 | | |
14076 | | // No need to update the components |
14077 | 1.98k | if (new_difference == 0) { |
14078 | 144 | return; |
14079 | 144 | } |
14080 | | |
14081 | 1.83k | apply_shifted_non_scheme_offsets(components, new_difference); |
14082 | 1.83k | ADA_ASSERT_TRUE(validate()); |
14083 | 1.83k | } |
14084 | | |
14085 | | inline void url_aggregator::set_scheme_from_view_with_colon( |
14086 | 20.5k | std::string_view new_scheme_with_colon) { |
14087 | 20.5k | ada_log("url_aggregator::set_scheme_from_view_with_colon ", |
14088 | 20.5k | new_scheme_with_colon); |
14089 | 20.5k | ADA_ASSERT_TRUE(validate()); |
14090 | 20.5k | ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() && |
14091 | 20.5k | new_scheme_with_colon.back() == ':'); |
14092 | | // next line could overflow but unsigned arithmetic has well-defined |
14093 | | // overflows. |
14094 | 20.5k | uint32_t new_difference = |
14095 | 20.5k | uint32_t(new_scheme_with_colon.size()) - components.protocol_end; |
14096 | | |
14097 | 20.5k | if (buffer.empty()) { |
14098 | 20.5k | buffer.append(new_scheme_with_colon); |
14099 | 20.5k | } else { |
14100 | 0 | buffer.erase(0, components.protocol_end); |
14101 | 0 | buffer.insert(0, new_scheme_with_colon); |
14102 | 0 | } |
14103 | 20.5k | components.protocol_end += new_difference; |
14104 | | |
14105 | 20.5k | apply_shifted_non_scheme_offsets(components, new_difference); |
14106 | 20.5k | ADA_ASSERT_TRUE(validate()); |
14107 | 20.5k | } |
14108 | | |
14109 | 21.5k | inline void url_aggregator::set_scheme(std::string_view new_scheme) { |
14110 | 21.5k | ada_log("url_aggregator::set_scheme ", new_scheme); |
14111 | 21.5k | ADA_ASSERT_TRUE(validate()); |
14112 | 21.5k | ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':'); |
14113 | | // next line could overflow but unsigned arithmetic has well-defined |
14114 | | // overflows. |
14115 | 21.5k | uint32_t new_difference = |
14116 | 21.5k | uint32_t(new_scheme.size()) - components.protocol_end + 1; |
14117 | | |
14118 | 21.5k | type = ada::scheme::get_scheme_type(new_scheme); |
14119 | 21.5k | if (buffer.empty()) { |
14120 | 21.5k | buffer.append(helpers::concat(new_scheme, ":")); |
14121 | 21.5k | } else { |
14122 | 0 | buffer.erase(0, components.protocol_end); |
14123 | 0 | buffer.insert(0, helpers::concat(new_scheme, ":")); |
14124 | 0 | } |
14125 | 21.5k | components.protocol_end = uint32_t(new_scheme.size() + 1); |
14126 | | |
14127 | 21.5k | apply_shifted_non_scheme_offsets(components, new_difference); |
14128 | 21.5k | ADA_ASSERT_TRUE(validate()); |
14129 | 21.5k | } |
14130 | | |
14131 | 0 | bool url_aggregator::needs_rollback_snapshot(size_t input_len) const noexcept { |
14132 | | // 3x should cover worst-case percent-encoding of every input byte; the |
14133 | | // constant covers the handful of delimiter bytes a setter may add ("/.", "?", |
14134 | | // "#" and so on) |
14135 | 0 | return buffer.size() + input_len * 3 + 16 > ada::get_max_input_length(); |
14136 | 0 | } |
14137 | | |
14138 | 0 | bool url_aggregator::set_protocol(const std::string_view input) { |
14139 | 0 | ada_log("url_aggregator::set_protocol ", input); |
14140 | 0 | ADA_ASSERT_TRUE(validate()); |
14141 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14142 | 0 | std::string view(input); |
14143 | 0 | helpers::remove_ascii_tab_or_newline(view); |
14144 | 0 | if (view.empty()) { |
14145 | 0 | return true; |
14146 | 0 | } |
14147 | | |
14148 | | // Schemes should start with alpha values. |
14149 | 0 | if (!checkers::is_alpha(view[0])) { |
14150 | 0 | return false; |
14151 | 0 | } |
14152 | | |
14153 | 0 | view.append(":"); |
14154 | |
|
14155 | 0 | std::string::iterator pointer = |
14156 | 0 | std::ranges::find_if_not(view, unicode::is_alnum_plus); |
14157 | |
|
14158 | 0 | if (pointer != view.end() && *pointer == ':') { |
14159 | 0 | std::optional<url_aggregator> saved_url; |
14160 | 0 | if (needs_rollback_snapshot(view.size())) { |
14161 | 0 | saved_url = *this; |
14162 | 0 | } |
14163 | 0 | bool result = parse_scheme_with_colon<true>( |
14164 | 0 | view.substr(0, pointer - view.begin() + 1)); |
14165 | 0 | if (result && saved_url && buffer.size() > ada::get_max_input_length()) { |
14166 | 0 | *this = std::move(*saved_url); |
14167 | 0 | return false; |
14168 | 0 | } |
14169 | 0 | return result; |
14170 | 0 | } |
14171 | 0 | return false; |
14172 | 0 | } |
14173 | | |
14174 | 0 | bool url_aggregator::set_username(const std::string_view input) { |
14175 | 0 | ada_log("url_aggregator::set_username '", input, "' "); |
14176 | 0 | ADA_ASSERT_TRUE(validate()); |
14177 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14178 | 0 | if (cannot_have_credentials_or_port()) { |
14179 | 0 | return false; |
14180 | 0 | } |
14181 | 0 | std::optional<url_aggregator> saved_url; |
14182 | 0 | if (needs_rollback_snapshot(input.size())) { |
14183 | 0 | saved_url = *this; |
14184 | 0 | } |
14185 | 0 | size_t idx = ada::unicode::percent_encode_index( |
14186 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
14187 | 0 | if (idx == input.size()) { |
14188 | 0 | update_base_username(input); |
14189 | 0 | } else { |
14190 | | // We only create a temporary string if we have to! |
14191 | 0 | update_base_username(ada::unicode::percent_encode( |
14192 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE, idx)); |
14193 | 0 | } |
14194 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14195 | 0 | *this = std::move(*saved_url); |
14196 | 0 | return false; |
14197 | 0 | } |
14198 | 0 | ADA_ASSERT_TRUE(validate()); |
14199 | 0 | return true; |
14200 | 0 | } |
14201 | | |
14202 | 0 | bool url_aggregator::set_password(const std::string_view input) { |
14203 | 0 | ada_log("url_aggregator::set_password '", input, "'"); |
14204 | 0 | ADA_ASSERT_TRUE(validate()); |
14205 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14206 | 0 | if (cannot_have_credentials_or_port()) { |
14207 | 0 | return false; |
14208 | 0 | } |
14209 | 0 | std::optional<url_aggregator> saved_url; |
14210 | 0 | if (needs_rollback_snapshot(input.size())) { |
14211 | 0 | saved_url = *this; |
14212 | 0 | } |
14213 | 0 | size_t idx = ada::unicode::percent_encode_index( |
14214 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
14215 | 0 | if (idx == input.size()) { |
14216 | 0 | update_base_password(input); |
14217 | 0 | } else { |
14218 | | // We only create a temporary string if we have to! |
14219 | 0 | update_base_password(ada::unicode::percent_encode( |
14220 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE, idx)); |
14221 | 0 | } |
14222 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14223 | 0 | *this = std::move(*saved_url); |
14224 | 0 | return false; |
14225 | 0 | } |
14226 | 0 | ADA_ASSERT_TRUE(validate()); |
14227 | 0 | return true; |
14228 | 0 | } |
14229 | | |
14230 | 0 | bool url_aggregator::set_port(const std::string_view input) { |
14231 | 0 | ada_log("url_aggregator::set_port ", input); |
14232 | 0 | ADA_ASSERT_TRUE(validate()); |
14233 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14234 | 0 | if (cannot_have_credentials_or_port()) { |
14235 | 0 | return false; |
14236 | 0 | } |
14237 | | |
14238 | 0 | if (input.empty()) { |
14239 | 0 | clear_port(); |
14240 | 0 | return true; |
14241 | 0 | } |
14242 | | |
14243 | 0 | std::string trimmed(input); |
14244 | 0 | helpers::remove_ascii_tab_or_newline(trimmed); |
14245 | |
|
14246 | 0 | if (trimmed.empty()) { |
14247 | 0 | return true; |
14248 | 0 | } |
14249 | | |
14250 | | // Input should not start with a non-digit character. |
14251 | 0 | if (!ada::unicode::is_ascii_digit(trimmed.front())) { |
14252 | 0 | return false; |
14253 | 0 | } |
14254 | | |
14255 | | // Find the first non-digit character to determine the length of digits |
14256 | 0 | auto first_non_digit = |
14257 | 0 | std::ranges::find_if_not(trimmed, ada::unicode::is_ascii_digit); |
14258 | 0 | std::string_view digits_to_parse = |
14259 | 0 | std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); |
14260 | | |
14261 | | // parse_port only touches the buffer once the digits are already known to |
14262 | | // be in range, so an invalid port never mutates anything and needs no |
14263 | | // rollback; a valid one can only grow the buffer by a few bytes. |
14264 | 0 | std::optional<url_aggregator> saved_url; |
14265 | 0 | if (needs_rollback_snapshot(digits_to_parse.size())) { |
14266 | 0 | saved_url = *this; |
14267 | 0 | } |
14268 | 0 | parse_port(digits_to_parse); |
14269 | 0 | if (!is_valid) { |
14270 | 0 | is_valid = true; |
14271 | 0 | ADA_ASSERT_TRUE(validate()); |
14272 | 0 | return false; |
14273 | 0 | } |
14274 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14275 | 0 | *this = std::move(*saved_url); |
14276 | 0 | return false; |
14277 | 0 | } |
14278 | 0 | return true; |
14279 | 0 | } |
14280 | | |
14281 | 0 | bool url_aggregator::set_pathname(const std::string_view input) { |
14282 | 0 | ada_log("url_aggregator::set_pathname ", input); |
14283 | 0 | ADA_ASSERT_TRUE(validate()); |
14284 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14285 | 0 | if (has_opaque_path) { |
14286 | 0 | return false; |
14287 | 0 | } |
14288 | 0 | std::optional<url_aggregator> saved_url; |
14289 | 0 | if (needs_rollback_snapshot(input.size())) { |
14290 | 0 | saved_url = *this; |
14291 | 0 | } |
14292 | 0 | clear_pathname(); |
14293 | 0 | parse_path(input); |
14294 | 0 | if (get_pathname().starts_with("//") && !has_authority() && !has_dash_dot()) { |
14295 | 0 | buffer.insert(components.pathname_start, "/."); |
14296 | 0 | components.pathname_start += 2; |
14297 | 0 | if (components.search_start != url_components::omitted) { |
14298 | 0 | components.search_start += 2; |
14299 | 0 | } |
14300 | 0 | if (components.hash_start != url_components::omitted) { |
14301 | 0 | components.hash_start += 2; |
14302 | 0 | } |
14303 | 0 | } |
14304 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14305 | 0 | *this = std::move(*saved_url); |
14306 | 0 | return false; |
14307 | 0 | } |
14308 | 0 | ADA_ASSERT_TRUE(validate()); |
14309 | 0 | return true; |
14310 | 0 | } |
14311 | | |
14312 | 2.19k | ada_really_inline void url_aggregator::parse_path(std::string_view input) { |
14313 | 2.19k | ada_log("url_aggregator::parse_path ", input); |
14314 | 2.19k | ADA_ASSERT_TRUE(validate()); |
14315 | 2.19k | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14316 | 2.19k | std::string tmp_buffer; |
14317 | 2.19k | std::string_view internal_input; |
14318 | 2.19k | if (unicode::has_tabs_or_newline(input)) { |
14319 | 0 | tmp_buffer = input; |
14320 | | // Optimization opportunity: Instead of copying and then pruning, we could |
14321 | | // just directly build the string from user_input. |
14322 | 0 | helpers::remove_ascii_tab_or_newline(tmp_buffer); |
14323 | 0 | internal_input = tmp_buffer; |
14324 | 2.19k | } else { |
14325 | 2.19k | internal_input = input; |
14326 | 2.19k | } |
14327 | | |
14328 | | // If url is special, then: |
14329 | 2.19k | if (is_special()) { |
14330 | 2.19k | if (internal_input.empty()) { |
14331 | 111 | update_base_pathname("/"); |
14332 | 2.08k | } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { |
14333 | 2.08k | consume_prepared_path(internal_input.substr(1)); |
14334 | 2.08k | } else { |
14335 | 0 | consume_prepared_path(internal_input); |
14336 | 0 | } |
14337 | 2.19k | } else if (!internal_input.empty()) { |
14338 | 0 | if (internal_input[0] == '/') { |
14339 | 0 | consume_prepared_path(internal_input.substr(1)); |
14340 | 0 | } else { |
14341 | 0 | consume_prepared_path(internal_input); |
14342 | 0 | } |
14343 | 0 | } else { |
14344 | | // Non-special URLs with an empty host can have their paths erased |
14345 | | // Path-only URLs cannot have their paths erased |
14346 | 0 | if (components.host_start == components.host_end && !has_authority()) { |
14347 | 0 | update_base_pathname("/"); |
14348 | 0 | } |
14349 | 0 | } |
14350 | 2.19k | ADA_ASSERT_TRUE(validate()); |
14351 | 2.19k | } |
14352 | | |
14353 | 0 | void url_aggregator::set_search(const std::string_view input) { |
14354 | 0 | ada_log("url_aggregator::set_search ", input); |
14355 | 0 | ADA_ASSERT_TRUE(validate()); |
14356 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14357 | 0 | if (input.empty()) { |
14358 | 0 | clear_search(); |
14359 | 0 | helpers::strip_trailing_spaces_from_opaque_path(*this); |
14360 | 0 | return; |
14361 | 0 | } |
14362 | | |
14363 | 0 | std::string_view stripped = input[0] == '?' ? input.substr(1) : input; |
14364 | | // Fast path: no tabs/newlines (the common case) avoids the std::string |
14365 | | // allocation entirely by passing the view straight to update_base_search. |
14366 | 0 | std::string cleaned; |
14367 | 0 | std::string_view effective = stripped; |
14368 | 0 | if (unicode::has_tabs_or_newline(stripped)) { |
14369 | 0 | cleaned = stripped; |
14370 | 0 | helpers::remove_ascii_tab_or_newline(cleaned); |
14371 | 0 | effective = cleaned; |
14372 | 0 | } |
14373 | |
|
14374 | 0 | auto query_percent_encode_set = |
14375 | 0 | is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE |
14376 | 0 | : ada::character_sets::QUERY_PERCENT_ENCODE; |
14377 | |
|
14378 | 0 | std::optional<url_aggregator> saved_url; |
14379 | 0 | if (needs_rollback_snapshot(effective.size())) { |
14380 | 0 | saved_url = *this; |
14381 | 0 | } |
14382 | 0 | update_base_search(effective, query_percent_encode_set); |
14383 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14384 | 0 | *this = std::move(*saved_url); |
14385 | 0 | return; |
14386 | 0 | } |
14387 | 0 | ADA_ASSERT_TRUE(validate()); |
14388 | 0 | } |
14389 | | |
14390 | 0 | void url_aggregator::set_hash(const std::string_view input) { |
14391 | 0 | ada_log("url_aggregator::set_hash ", input); |
14392 | 0 | ADA_ASSERT_TRUE(validate()); |
14393 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14394 | 0 | if (input.empty()) { |
14395 | 0 | if (components.hash_start != url_components::omitted) { |
14396 | 0 | buffer.resize(components.hash_start); |
14397 | 0 | components.hash_start = url_components::omitted; |
14398 | 0 | } |
14399 | 0 | helpers::strip_trailing_spaces_from_opaque_path(*this); |
14400 | 0 | return; |
14401 | 0 | } |
14402 | | |
14403 | 0 | std::string_view stripped = input[0] == '#' ? input.substr(1) : input; |
14404 | | // Fast path: no tabs/newlines (the common case) avoids the std::string |
14405 | | // allocation entirely by passing the view straight through. |
14406 | 0 | std::string cleaned; |
14407 | 0 | std::string_view effective = stripped; |
14408 | 0 | if (unicode::has_tabs_or_newline(stripped)) { |
14409 | 0 | cleaned = stripped; |
14410 | 0 | helpers::remove_ascii_tab_or_newline(cleaned); |
14411 | 0 | effective = cleaned; |
14412 | 0 | } |
14413 | 0 | std::optional<url_aggregator> saved_url; |
14414 | 0 | if (needs_rollback_snapshot(effective.size())) { |
14415 | 0 | saved_url = *this; |
14416 | 0 | } |
14417 | 0 | update_unencoded_base_hash(effective); |
14418 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14419 | 0 | *this = std::move(*saved_url); |
14420 | 0 | return; |
14421 | 0 | } |
14422 | 0 | ADA_ASSERT_TRUE(validate()); |
14423 | 0 | } |
14424 | | |
14425 | 0 | bool url_aggregator::set_href(const std::string_view input) { |
14426 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14427 | 0 | ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]"); |
14428 | 0 | ada::result<url_aggregator> out = ada::parse<url_aggregator>(input); |
14429 | 0 | ada_log("url_aggregator::set_href, success :", out.has_value()); |
14430 | |
|
14431 | 0 | if (out) { |
14432 | | // The parser enforces get_max_input_length() on both the input and the |
14433 | | // normalized result. This is a defense-in-depth check. |
14434 | 0 | if (out->buffer.size() > ada::get_max_input_length()) { |
14435 | 0 | return false; |
14436 | 0 | } |
14437 | 0 | ada_log("url_aggregator::set_href, parsed ", out->to_string()); |
14438 | | // TODO: Figure out why the following line puts test to never finish. |
14439 | 0 | *this = std::move(*out); |
14440 | 0 | } |
14441 | | |
14442 | 0 | return out.has_value(); |
14443 | 0 | } |
14444 | | |
14445 | 30.4k | ada_really_inline bool url_aggregator::parse_host(std::string_view input) { |
14446 | 30.4k | ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(), |
14447 | 30.4k | " bytes]"); |
14448 | 30.4k | ADA_ASSERT_TRUE(validate()); |
14449 | 30.4k | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14450 | 30.4k | if (input.empty()) { |
14451 | 28 | return is_valid = false; |
14452 | 28 | } // technically unnecessary. |
14453 | | // If input starts with U+005B ([), then: |
14454 | 30.3k | if (input[0] == '[') { |
14455 | | // If input does not end with U+005D (]), validation error, return failure. |
14456 | 1.35k | if (input.back() != ']') { |
14457 | 320 | return is_valid = false; |
14458 | 320 | } |
14459 | 1.03k | ada_log("parse_host ipv6"); |
14460 | | |
14461 | | // Return the result of IPv6 parsing input with its leading U+005B ([) and |
14462 | | // trailing U+005D (]) removed. |
14463 | 1.03k | input.remove_prefix(1); |
14464 | 1.03k | input.remove_suffix(1); |
14465 | 1.03k | return parse_ipv6(input); |
14466 | 1.35k | } |
14467 | | |
14468 | | // If isNotSpecial is true, then return the result of opaque-host parsing |
14469 | | // input. |
14470 | 29.0k | if (!is_special()) { |
14471 | 1.19k | return parse_opaque_host(input); |
14472 | 1.19k | } |
14473 | | // Let domain be the result of running UTF-8 decode without BOM on the |
14474 | | // percent-decoding of input. Let asciiDomain be the result of running domain |
14475 | | // to ASCII with domain and false. The most common case is an ASCII input, in |
14476 | | // which case we do not need to call the expensive 'to_ascii' if a few |
14477 | | // conditions are met: no '%' and no 'xn-' subsequence. |
14478 | | |
14479 | | // Often, the input does not contain any forbidden code points, and no upper |
14480 | | // case ASCII letter, then we can just copy it to the buffer. We want to |
14481 | | // optimize for such a common case. |
14482 | | |
14483 | | // Fast path: try to parse as pure decimal IPv4 first. |
14484 | 27.8k | const uint64_t fast_result = checkers::try_parse_ipv4_fast(input); |
14485 | 27.8k | if (fast_result < checkers::ipv4_fast_fail) { |
14486 | 1.21k | if (!input.empty() && input.back() == '.') { |
14487 | 47 | update_base_hostname(input.substr(0, input.size() - 1)); |
14488 | 1.16k | } else { |
14489 | 1.16k | update_base_hostname(input); |
14490 | 1.16k | } |
14491 | 1.21k | host_type = IPV4; |
14492 | 1.21k | is_valid = true; |
14493 | 1.21k | ada_log("parse_host fast path decimal ipv4"); |
14494 | 1.21k | ADA_ASSERT_TRUE(validate()); |
14495 | 1.21k | return true; |
14496 | 1.21k | } |
14497 | 26.6k | uint8_t is_forbidden_or_upper = |
14498 | 26.6k | unicode::contains_forbidden_domain_code_point_or_upper(input.data(), |
14499 | 26.6k | input.size()); |
14500 | 26.6k | static constexpr std::string_view xn_dash{"xn-", 3}; |
14501 | 26.6k | if ((is_forbidden_or_upper & 1) == 0) { |
14502 | 16.1k | if ((is_forbidden_or_upper & 2) != 0) { |
14503 | 2.80k | std::string lowered(input); |
14504 | 2.80k | unicode::to_lower_ascii(lowered.data(), lowered.size()); |
14505 | 2.80k | if (lowered.find('-') == std::string_view::npos || |
14506 | 2.60k | lowered.find(xn_dash) == std::string_view::npos) { |
14507 | | // Check IPv4 before mutating so failures leave the buffer untouched. |
14508 | | // This also avoids a double buffer rewrite for hex/octal IPv4. |
14509 | 2.60k | if (checkers::is_ipv4(lowered)) { |
14510 | 452 | ada_log("parse_host fast path ipv4"); |
14511 | 452 | return parse_ipv4(lowered, false); |
14512 | 452 | } |
14513 | 2.14k | update_base_hostname(lowered); |
14514 | 2.14k | ada_log("parse_host fast path ", get_hostname()); |
14515 | 2.14k | is_valid = true; |
14516 | 2.14k | return true; |
14517 | 2.60k | } |
14518 | 13.3k | } else if (input.find('-') == std::string_view::npos || |
14519 | 9.85k | input.find(xn_dash) == std::string_view::npos) { |
14520 | | // Check IPv4 before mutating so failures leave the buffer untouched. |
14521 | 9.85k | if (checkers::is_ipv4(input)) { |
14522 | 2.32k | ada_log("parse_host fast path ipv4"); |
14523 | 2.32k | return parse_ipv4(input, false); |
14524 | 2.32k | } |
14525 | 7.53k | update_base_hostname(input); |
14526 | 7.53k | ada_log("parse_host fast path ", get_hostname()); |
14527 | 7.53k | is_valid = true; |
14528 | 7.53k | return true; |
14529 | 9.85k | } |
14530 | 16.1k | } else if (const size_t first_percent = input.find('%'); |
14531 | 10.4k | first_percent != std::string_view::npos) { |
14532 | 1.94k | std::string decoded = unicode::percent_decode(input, first_percent); |
14533 | 1.94k | const uint8_t decoded_flags = |
14534 | 1.94k | unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(), |
14535 | 1.94k | decoded.size()); |
14536 | 1.94k | if ((decoded_flags & 1) == 0) { |
14537 | 1.28k | if ((decoded_flags & 2) != 0) { |
14538 | 582 | unicode::to_lower_ascii(decoded.data(), decoded.size()); |
14539 | 582 | } |
14540 | 1.28k | if (decoded.find('-') == std::string_view::npos || |
14541 | 1.19k | decoded.find(xn_dash) == std::string_view::npos) { |
14542 | | // Check IPv4 before mutating so failures leave the buffer untouched. |
14543 | 1.19k | if (checkers::is_ipv4(decoded)) { |
14544 | 510 | return parse_ipv4(decoded, false); |
14545 | 510 | } |
14546 | 684 | update_base_hostname(decoded); |
14547 | 684 | is_valid = true; |
14548 | 684 | return true; |
14549 | 1.19k | } |
14550 | 1.28k | } |
14551 | 1.94k | } |
14552 | | // We have encountered at least one forbidden code point or the input contains |
14553 | | // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full |
14554 | | // conversion. |
14555 | | |
14556 | 12.9k | ada_log("parse_host calling to_ascii"); |
14557 | 12.9k | std::optional<std::string> host = std::string(get_hostname()); |
14558 | 12.9k | is_valid = ada::unicode::to_ascii(host, input, input.find('%')); |
14559 | 12.9k | if (!is_valid) { |
14560 | 3.85k | ada_log("parse_host to_ascii returns false"); |
14561 | 3.85k | return is_valid = false; |
14562 | 3.85k | } |
14563 | 9.12k | ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), |
14564 | 9.12k | " bytes]"); |
14565 | | |
14566 | 9.12k | if (std::ranges::any_of(host.value(), |
14567 | 9.12k | ada::unicode::is_forbidden_domain_code_point)) { |
14568 | 0 | return is_valid = false; |
14569 | 0 | } |
14570 | | |
14571 | | // If asciiDomain ends in a number, then return the result of IPv4 parsing |
14572 | | // asciiDomain. |
14573 | 9.12k | if (checkers::is_ipv4(host.value())) { |
14574 | 402 | ada_log("parse_host got ipv4 ", *host); |
14575 | 402 | return parse_ipv4(host.value(), false); |
14576 | 402 | } |
14577 | | |
14578 | 8.72k | update_base_hostname(host.value()); |
14579 | 8.72k | ADA_ASSERT_TRUE(validate()); |
14580 | 8.72k | return true; |
14581 | 9.12k | } |
14582 | | |
14583 | | template <bool override_hostname> |
14584 | 0 | bool url_aggregator::set_host_or_hostname(const std::string_view input) { |
14585 | 0 | ada_log("url_aggregator::set_host_or_hostname ", input); |
14586 | 0 | ADA_ASSERT_TRUE(validate()); |
14587 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14588 | 0 | if (has_opaque_path) { |
14589 | 0 | return false; |
14590 | 0 | } |
14591 | | |
14592 | | // parse_host no longer mutates the buffer on failure (IPv4 is checked |
14593 | | // before update_base_hostname), so the only rollback needed is for the |
14594 | | // length limit. Snapshot only when the bound can be reached, like the |
14595 | | // other setters do via needs_rollback_snapshot. |
14596 | 0 | const bool was_valid = is_valid; |
14597 | 0 | std::optional<url_aggregator> saved_url; |
14598 | 0 | if (needs_rollback_snapshot(input.size())) { |
14599 | 0 | saved_url = *this; |
14600 | 0 | } |
14601 | |
|
14602 | 0 | auto restore_on_failure = [&]() { |
14603 | 0 | if (saved_url) { |
14604 | 0 | *this = std::move(*saved_url); |
14605 | 0 | } else { |
14606 | | // Buffer is untouched on parse failure; just restore the is_valid flag |
14607 | | // that parse_host may have cleared. |
14608 | 0 | is_valid = was_valid; |
14609 | 0 | } |
14610 | 0 | }; Unexecuted instantiation: ada::url_aggregator::set_host_or_hostname<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#1}::operator()() constUnexecuted instantiation: ada::url_aggregator::set_host_or_hostname<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#1}::operator()() const |
14611 | |
|
14612 | 0 | size_t host_end_pos = input.find('#'); |
14613 | 0 | std::string_view host_input( |
14614 | 0 | input.data(), |
14615 | 0 | host_end_pos != std::string_view::npos ? host_end_pos : input.size()); |
14616 | | // Fast path: no tabs/newlines (the common case) avoids the std::string |
14617 | | // allocation by viewing the input prefix directly. |
14618 | 0 | std::string _host_buf; |
14619 | 0 | std::string_view new_host; |
14620 | 0 | if (unicode::has_tabs_or_newline(host_input)) { |
14621 | 0 | _host_buf = host_input; |
14622 | 0 | helpers::remove_ascii_tab_or_newline(_host_buf); |
14623 | 0 | new_host = _host_buf; |
14624 | 0 | } else { |
14625 | 0 | new_host = host_input; |
14626 | 0 | } |
14627 | |
|
14628 | 0 | auto check_url_size = [&]() -> bool { |
14629 | 0 | if (saved_url && buffer.size() > ada::get_max_input_length()) { |
14630 | 0 | *this = std::move(*saved_url); |
14631 | 0 | return false; |
14632 | 0 | } |
14633 | 0 | return true; |
14634 | 0 | }; Unexecuted instantiation: ada::url_aggregator::set_host_or_hostname<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#2}::operator()() constUnexecuted instantiation: ada::url_aggregator::set_host_or_hostname<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda()#2}::operator()() const |
14635 | | |
14636 | | // If url's scheme is "file", then set state to file host state, instead of |
14637 | | // host state. |
14638 | 0 | if (type != ada::scheme::type::FILE) { |
14639 | 0 | std::string_view host_view = new_host; |
14640 | 0 | auto [location, found_colon] = |
14641 | 0 | helpers::get_host_delimiter_location(is_special(), host_view); |
14642 | | |
14643 | | // Otherwise, if c is U+003A (:) and insideBrackets is false, then: |
14644 | | // Note: the 'found_colon' value is true if and only if a colon was |
14645 | | // encountered while not inside brackets. |
14646 | 0 | if (found_colon) { |
14647 | | // If buffer is the empty string, host-missing validation error, return |
14648 | | // failure. |
14649 | 0 | std::string_view host_buffer = host_view.substr(0, location); |
14650 | 0 | if (host_buffer.empty()) { |
14651 | 0 | return false; |
14652 | 0 | } |
14653 | | |
14654 | | // If state override is given and state override is hostname state, then |
14655 | | // return failure. |
14656 | 0 | if constexpr (override_hostname) { |
14657 | 0 | return false; |
14658 | 0 | } |
14659 | | |
14660 | | // Let host be the result of host parsing buffer with url is not special. |
14661 | 0 | bool succeeded = parse_host(host_buffer); |
14662 | 0 | if (!succeeded) { |
14663 | 0 | restore_on_failure(); |
14664 | 0 | return false; |
14665 | 0 | } else if (has_dash_dot()) { |
14666 | | // The url now has a non-null host, so the "/." that guarded a |
14667 | | // leading "//" path is no longer needed. Drop it before the port is |
14668 | | // inserted at host_end, otherwise it stays wedged in the path. |
14669 | 0 | delete_dash_dot(); |
14670 | 0 | } |
14671 | | |
14672 | | // Set url's host to host, buffer to the empty string, and state to port |
14673 | | // state. |
14674 | 0 | std::string_view port_buffer = new_host.substr(location + 1); |
14675 | 0 | if (!port_buffer.empty()) { |
14676 | 0 | set_port(port_buffer); |
14677 | 0 | } |
14678 | 0 | return check_url_size(); |
14679 | 0 | } |
14680 | | // Otherwise, if one of the following is true: |
14681 | | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
14682 | | // - url is special and c is U+005C (\) |
14683 | 0 | else { |
14684 | | // If url is special and host_view is the empty string, host-missing |
14685 | | // validation error, return failure. |
14686 | 0 | if (host_view.empty() && is_special()) { |
14687 | 0 | return false; |
14688 | 0 | } |
14689 | | |
14690 | | // Otherwise, if state override is given, host_view is the empty string, |
14691 | | // and either url includes credentials or url's port is non-null, then |
14692 | | // return failure. |
14693 | 0 | if (host_view.empty() && (has_credentials() || has_port())) { |
14694 | 0 | return false; |
14695 | 0 | } |
14696 | | |
14697 | | // Let host be the result of host parsing host_view with url is not |
14698 | | // special. |
14699 | 0 | if (host_view.empty() && !is_special()) { |
14700 | 0 | if (has_hostname()) { |
14701 | 0 | clear_hostname(); // easy! |
14702 | 0 | } else if (has_dash_dot()) { |
14703 | 0 | add_authority_slashes_if_needed(); |
14704 | 0 | delete_dash_dot(); |
14705 | 0 | } else { |
14706 | | // The url has no authority yet (e.g. "foo:/bar"); setting an empty |
14707 | | // host must still give it an (empty) authority, matching ada::url. |
14708 | 0 | add_authority_slashes_if_needed(); |
14709 | 0 | } |
14710 | 0 | return check_url_size(); |
14711 | 0 | } |
14712 | | |
14713 | 0 | bool succeeded = parse_host(host_view); |
14714 | 0 | if (!succeeded) { |
14715 | 0 | restore_on_failure(); |
14716 | 0 | return false; |
14717 | 0 | } else if (has_dash_dot()) { |
14718 | | // Should remove dash_dot from pathname |
14719 | 0 | delete_dash_dot(); |
14720 | 0 | } |
14721 | 0 | return check_url_size(); |
14722 | 0 | } |
14723 | 0 | } |
14724 | | |
14725 | 0 | size_t location = new_host.find_first_of("/\\?"); |
14726 | 0 | if (location != std::string_view::npos) { |
14727 | 0 | new_host.remove_suffix(new_host.length() - location); |
14728 | 0 | } |
14729 | |
|
14730 | 0 | if (new_host.empty()) { |
14731 | | // Set url's host to the empty string. |
14732 | 0 | clear_hostname(); |
14733 | 0 | } else { |
14734 | | // Let host be the result of host parsing buffer with url is not special. |
14735 | 0 | if (!parse_host(new_host)) { |
14736 | 0 | restore_on_failure(); |
14737 | 0 | return false; |
14738 | 0 | } |
14739 | | |
14740 | | // If host is "localhost", then set host to the empty string. |
14741 | 0 | if (helpers::substring(buffer, components.host_start, |
14742 | 0 | components.host_end) == "localhost") { |
14743 | 0 | clear_hostname(); |
14744 | 0 | } |
14745 | 0 | } |
14746 | 0 | ADA_ASSERT_TRUE(validate()); |
14747 | 0 | return check_url_size(); |
14748 | 0 | } Unexecuted instantiation: bool ada::url_aggregator::set_host_or_hostname<false>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: bool ada::url_aggregator::set_host_or_hostname<true>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
14749 | | |
14750 | 0 | bool url_aggregator::set_host(const std::string_view input) { |
14751 | 0 | ada_log("url_aggregator::set_host '", input, "'"); |
14752 | 0 | ADA_ASSERT_TRUE(validate()); |
14753 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14754 | 0 | return set_host_or_hostname<false>(input); |
14755 | 0 | } |
14756 | | |
14757 | 0 | bool url_aggregator::set_hostname(const std::string_view input) { |
14758 | 0 | ada_log("url_aggregator::set_hostname '", input, "'"); |
14759 | 0 | ADA_ASSERT_TRUE(validate()); |
14760 | 0 | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
14761 | 0 | return set_host_or_hostname<true>(input); |
14762 | 0 | } |
14763 | | |
14764 | 0 | [[nodiscard]] std::string url_aggregator::get_origin() const { |
14765 | 0 | ada_log("url_aggregator::get_origin"); |
14766 | 0 | if (is_special()) { |
14767 | | // Return a new opaque origin. |
14768 | 0 | if (type == scheme::FILE) { |
14769 | 0 | return "null"; |
14770 | 0 | } |
14771 | | |
14772 | 0 | return helpers::concat(get_protocol(), "//", get_host()); |
14773 | 0 | } |
14774 | | |
14775 | 0 | if (get_protocol() == "blob:") { |
14776 | 0 | std::string_view path = get_pathname(); |
14777 | 0 | if (!path.empty()) { |
14778 | 0 | auto out = ada::parse<ada::url_aggregator>(path); |
14779 | 0 | if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) { |
14780 | | // If pathURL's scheme is not "http" and not "https", then return a |
14781 | | // new opaque origin. |
14782 | 0 | return helpers::concat(out->get_protocol(), "//", out->get_host()); |
14783 | 0 | } |
14784 | 0 | } |
14785 | 0 | } |
14786 | | |
14787 | | // Return a new opaque origin. |
14788 | 0 | return "null"; |
14789 | 0 | } |
14790 | | |
14791 | | [[nodiscard]] std::string_view url_aggregator::get_username() const |
14792 | 0 | ada_lifetime_bound { |
14793 | 0 | ada_log("url_aggregator::get_username"); |
14794 | 0 | if (has_non_empty_username()) { |
14795 | 0 | return helpers::substring(buffer, components.protocol_end + 2, |
14796 | 0 | components.username_end); |
14797 | 0 | } |
14798 | 0 | return ""; |
14799 | 0 | } |
14800 | | |
14801 | | [[nodiscard]] std::string_view url_aggregator::get_password() const |
14802 | 0 | ada_lifetime_bound { |
14803 | 0 | ada_log("url_aggregator::get_password"); |
14804 | 0 | if (has_non_empty_password()) { |
14805 | 0 | return helpers::substring(buffer, components.username_end + 1, |
14806 | 0 | components.host_start); |
14807 | 0 | } |
14808 | 0 | return ""; |
14809 | 0 | } |
14810 | | |
14811 | | [[nodiscard]] std::string_view url_aggregator::get_port() const |
14812 | 0 | ada_lifetime_bound { |
14813 | 0 | ada_log("url_aggregator::get_port"); |
14814 | 0 | if (components.port == url_components::omitted) { |
14815 | 0 | return ""; |
14816 | 0 | } |
14817 | 0 | return helpers::substring(buffer, components.host_end + 1, |
14818 | 0 | components.pathname_start); |
14819 | 0 | } |
14820 | | |
14821 | | [[nodiscard]] std::string_view url_aggregator::get_hash() const |
14822 | 0 | ada_lifetime_bound { |
14823 | 0 | ada_log("url_aggregator::get_hash"); |
14824 | | // If this's URL's fragment is either null or the empty string, then return |
14825 | | // the empty string. Return U+0023 (#), followed by this's URL's fragment. |
14826 | 0 | if (components.hash_start == url_components::omitted) { |
14827 | 0 | return ""; |
14828 | 0 | } |
14829 | 0 | if (buffer.size() - components.hash_start <= 1) { |
14830 | 0 | return ""; |
14831 | 0 | } |
14832 | 0 | return helpers::substring(buffer, components.hash_start); |
14833 | 0 | } |
14834 | | |
14835 | | [[nodiscard]] std::string_view url_aggregator::get_host() const |
14836 | 172 | ada_lifetime_bound { |
14837 | 172 | ada_log("url_aggregator::get_host"); |
14838 | | // Technically, we should check if there is a hostname, but |
14839 | | // the code below works even if there isn't. |
14840 | | // if(!has_hostname()) { return ""; } |
14841 | 172 | size_t start = components.host_start; |
14842 | 172 | if (components.host_end > components.host_start && |
14843 | 42 | buffer[components.host_start] == '@') { |
14844 | 0 | start++; |
14845 | 0 | } |
14846 | | // if we have an empty host, then the space between components.host_end and |
14847 | | // components.pathname_start may be occupied by /. |
14848 | 172 | if (start == components.host_end) { |
14849 | 130 | return {}; |
14850 | 130 | } |
14851 | 42 | return helpers::substring(buffer, start, components.pathname_start); |
14852 | 172 | } |
14853 | | |
14854 | | [[nodiscard]] std::string_view url_aggregator::get_hostname() const |
14855 | 19.0k | ada_lifetime_bound { |
14856 | 19.0k | ada_log("url_aggregator::get_hostname"); |
14857 | | // Technically, we should check if there is a hostname, but |
14858 | | // the code below works even if there isn't. |
14859 | | // if(!has_hostname()) { return ""; } |
14860 | 19.0k | size_t start = components.host_start; |
14861 | | // So host_start is not where the host begins. |
14862 | 19.0k | if (components.host_end > components.host_start && |
14863 | 5.06k | buffer[components.host_start] == '@') { |
14864 | 206 | start++; |
14865 | 206 | } |
14866 | 19.0k | return helpers::substring(buffer, start, components.host_end); |
14867 | 19.0k | } |
14868 | | |
14869 | | [[nodiscard]] std::string_view url_aggregator::get_search() const |
14870 | 149 | ada_lifetime_bound { |
14871 | 149 | ada_log("url_aggregator::get_search"); |
14872 | | // If this's URL's query is either null or the empty string, then return the |
14873 | | // empty string. Return U+003F (?), followed by this's URL's query. |
14874 | 149 | if (components.search_start == url_components::omitted) { |
14875 | 0 | return ""; |
14876 | 0 | } |
14877 | 149 | auto ending_index = uint32_t(buffer.size()); |
14878 | 149 | if (components.hash_start != url_components::omitted) { |
14879 | 27 | ending_index = components.hash_start; |
14880 | 27 | } |
14881 | 149 | if (ending_index - components.search_start <= 1) { |
14882 | 67 | return ""; |
14883 | 67 | } |
14884 | 82 | return helpers::substring(buffer, components.search_start, ending_index); |
14885 | 149 | } |
14886 | | |
14887 | | [[nodiscard]] std::string_view url_aggregator::get_protocol() const |
14888 | 1.98k | ada_lifetime_bound { |
14889 | 1.98k | ada_log("url_aggregator::get_protocol"); |
14890 | 1.98k | return helpers::substring(buffer, 0, components.protocol_end); |
14891 | 1.98k | } |
14892 | | |
14893 | 0 | [[nodiscard]] std::string ada::url_aggregator::to_string() const { |
14894 | 0 | ada_log("url_aggregator::to_string buffer:", buffer, " [", buffer.size(), |
14895 | 0 | " bytes]"); |
14896 | 0 | if (!is_valid) { |
14897 | 0 | return "null"; |
14898 | 0 | } |
14899 | | |
14900 | 0 | std::string answer; |
14901 | 0 | auto back = std::back_insert_iterator(answer); |
14902 | 0 | answer.append("{\n"); |
14903 | |
|
14904 | 0 | answer.append("\t\"buffer\":\""); |
14905 | 0 | helpers::encode_json(buffer, back); |
14906 | 0 | answer.append("\",\n"); |
14907 | |
|
14908 | 0 | answer.append("\t\"protocol\":\""); |
14909 | 0 | helpers::encode_json(get_protocol(), back); |
14910 | 0 | answer.append("\",\n"); |
14911 | |
|
14912 | 0 | if (has_credentials()) { |
14913 | 0 | answer.append("\t\"username\":\""); |
14914 | 0 | helpers::encode_json(get_username(), back); |
14915 | 0 | answer.append("\",\n"); |
14916 | 0 | answer.append("\t\"password\":\""); |
14917 | 0 | helpers::encode_json(get_password(), back); |
14918 | 0 | answer.append("\",\n"); |
14919 | 0 | } |
14920 | |
|
14921 | 0 | answer.append("\t\"host\":\""); |
14922 | 0 | helpers::encode_json(get_host(), back); |
14923 | 0 | answer.append("\",\n"); |
14924 | |
|
14925 | 0 | answer.append("\t\"path\":\""); |
14926 | 0 | helpers::encode_json(get_pathname(), back); |
14927 | 0 | answer.append("\",\n"); |
14928 | 0 | answer.append("\t\"opaque path\":"); |
14929 | 0 | answer.append((has_opaque_path ? "true" : "false")); |
14930 | 0 | answer.append(",\n"); |
14931 | |
|
14932 | 0 | if (components.search_start != url_components::omitted) { |
14933 | 0 | answer.append("\t\"query\":\""); |
14934 | 0 | helpers::encode_json(get_search(), back); |
14935 | 0 | answer.append("\",\n"); |
14936 | 0 | } |
14937 | 0 | if (components.hash_start != url_components::omitted) { |
14938 | 0 | answer.append("\t\"fragment\":\""); |
14939 | 0 | helpers::encode_json(get_hash(), back); |
14940 | 0 | answer.append("\",\n"); |
14941 | 0 | } |
14942 | |
|
14943 | 0 | auto convert_offset_to_string = [](uint32_t offset) -> std::string { |
14944 | 0 | if (offset == url_components::omitted) { |
14945 | 0 | return "null"; |
14946 | 0 | } else { |
14947 | 0 | return std::to_string(offset); |
14948 | 0 | } |
14949 | 0 | }; |
14950 | |
|
14951 | 0 | answer.append("\t\"protocol_end\":"); |
14952 | 0 | answer.append(convert_offset_to_string(components.protocol_end)); |
14953 | 0 | answer.append(",\n"); |
14954 | |
|
14955 | 0 | answer.append("\t\"username_end\":"); |
14956 | 0 | answer.append(convert_offset_to_string(components.username_end)); |
14957 | 0 | answer.append(",\n"); |
14958 | |
|
14959 | 0 | answer.append("\t\"host_start\":"); |
14960 | 0 | answer.append(convert_offset_to_string(components.host_start)); |
14961 | 0 | answer.append(",\n"); |
14962 | |
|
14963 | 0 | answer.append("\t\"host_end\":"); |
14964 | 0 | answer.append(convert_offset_to_string(components.host_end)); |
14965 | 0 | answer.append(",\n"); |
14966 | |
|
14967 | 0 | answer.append("\t\"port\":"); |
14968 | 0 | answer.append(convert_offset_to_string(components.port)); |
14969 | 0 | answer.append(",\n"); |
14970 | |
|
14971 | 0 | answer.append("\t\"pathname_start\":"); |
14972 | 0 | answer.append(convert_offset_to_string(components.pathname_start)); |
14973 | 0 | answer.append(",\n"); |
14974 | |
|
14975 | 0 | answer.append("\t\"search_start\":"); |
14976 | 0 | answer.append(convert_offset_to_string(components.search_start)); |
14977 | 0 | answer.append(",\n"); |
14978 | |
|
14979 | 0 | answer.append("\t\"hash_start\":"); |
14980 | 0 | answer.append(convert_offset_to_string(components.hash_start)); |
14981 | 0 | answer.append("\n}"); |
14982 | |
|
14983 | 0 | return answer; |
14984 | 0 | } |
14985 | | |
14986 | 0 | [[nodiscard]] bool url_aggregator::has_valid_domain() const noexcept { |
14987 | 0 | if (components.host_start == components.host_end) { |
14988 | 0 | return false; |
14989 | 0 | } |
14990 | | // Avoid allocation: construct a string_view directly into the buffer. |
14991 | 0 | size_t start = components.host_start; |
14992 | 0 | if (components.host_end > components.host_start && |
14993 | 0 | buffer[components.host_start] == '@') { |
14994 | 0 | start++; |
14995 | 0 | } |
14996 | 0 | return checkers::verify_dns_length( |
14997 | 0 | std::string_view(buffer.data() + start, components.host_end - start)); |
14998 | 0 | } |
14999 | | |
15000 | 3.68k | bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) { |
15001 | 3.68k | ada_log("parse_ipv4 ", input, " [", input.size(), |
15002 | 3.68k | " bytes], overlaps with buffer: ", |
15003 | 3.68k | helpers::overlaps(input, buffer) ? "yes" : "no"); |
15004 | 3.68k | ADA_ASSERT_TRUE(validate()); |
15005 | 3.68k | if (input.empty()) { |
15006 | 0 | return is_valid = false; |
15007 | 0 | } |
15008 | 3.68k | const bool trailing_dot = (input.back() == '.'); |
15009 | 3.68k | if (trailing_dot) { |
15010 | 120 | input.remove_suffix(1); |
15011 | 120 | if (input.empty()) { |
15012 | 0 | return is_valid = false; |
15013 | 0 | } |
15014 | 120 | } |
15015 | | |
15016 | 3.68k | const uint64_t fast = checkers::try_parse_ipv4_fast(input); |
15017 | 3.68k | if (fast < checkers::ipv4_fast_fail) [[likely]] { |
15018 | | // Pure decimal: keep the buffer when it already holds the address. |
15019 | | // Otherwise write the (trailing-dot-stripped) input. |
15020 | 40 | if (!(in_place && !trailing_dot)) { |
15021 | 40 | if (helpers::overlaps(input, buffer)) { |
15022 | 0 | update_base_hostname(std::string(input)); |
15023 | 40 | } else { |
15024 | 40 | update_base_hostname(input); |
15025 | 40 | } |
15026 | 40 | } |
15027 | 40 | host_type = IPV4; |
15028 | 40 | ADA_ASSERT_TRUE(validate()); |
15029 | 40 | return true; |
15030 | 40 | } |
15031 | | |
15032 | 3.64k | const char* p = input.data(); |
15033 | 3.64k | const char* end = p + input.size(); |
15034 | 3.64k | uint64_t ipv4 = 0; |
15035 | 3.64k | int digit_count = 0; |
15036 | 3.64k | int pure_decimal_count = 0; |
15037 | | |
15038 | 4.54k | for (; digit_count < 4 && p < end; ++digit_count) { |
15039 | 4.52k | uint64_t segment = 0; |
15040 | 4.52k | bool pure = false; |
15041 | 4.52k | if (!detail::parse_ipv4_number(p, end, segment, pure)) { |
15042 | 650 | return is_valid = false; |
15043 | 650 | } |
15044 | 3.87k | if (pure) { |
15045 | 2.85k | ++pure_decimal_count; |
15046 | 2.85k | } |
15047 | 3.87k | if (p >= end) { |
15048 | 2.92k | const unsigned shift = static_cast<unsigned>(32 - digit_count * 8); |
15049 | 2.92k | if (segment >= (uint64_t{1} << shift)) { |
15050 | 52 | return is_valid = false; |
15051 | 52 | } |
15052 | 2.87k | ipv4 = (ipv4 << shift) | segment; |
15053 | 2.87k | goto ipv4_done; |
15054 | 2.92k | } |
15055 | 956 | if (segment > 255 || *p != '.') { |
15056 | 58 | return is_valid = false; |
15057 | 58 | } |
15058 | 898 | ipv4 = (ipv4 << 8) | segment; |
15059 | 898 | ++p; |
15060 | 898 | } |
15061 | 18 | if (digit_count != 4 || p != end) { |
15062 | 18 | return is_valid = false; |
15063 | 18 | } |
15064 | 2.87k | ipv4_done: |
15065 | 2.87k | ada_log("url_aggregator::parse_ipv4 completed ", get_href(), |
15066 | 2.87k | " host: ", get_host()); |
15067 | 2.87k | if (in_place && pure_decimal_count == 4 && !trailing_dot) { |
15068 | 0 | ada_log( |
15069 | 0 | "url_aggregator::parse_ipv4 completed and was already correct in the " |
15070 | 0 | "buffer"); |
15071 | 2.87k | } else { |
15072 | 2.87k | update_base_hostname(ada::serializers::ipv4(ipv4)); |
15073 | 2.87k | } |
15074 | 2.87k | host_type = IPV4; |
15075 | 2.87k | ADA_ASSERT_TRUE(validate()); |
15076 | 2.87k | return true; |
15077 | 18 | } |
15078 | | |
15079 | 1.03k | bool url_aggregator::parse_ipv6(std::string_view input) { |
15080 | 1.03k | ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); |
15081 | 1.03k | ADA_ASSERT_TRUE(validate()); |
15082 | 1.03k | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
15083 | 1.03k | if (input.empty() || input.size() > 45) [[unlikely]] { |
15084 | 62 | return is_valid = false; |
15085 | 62 | } |
15086 | 974 | std::array<uint16_t, 8> address{}; |
15087 | | #if defined(ADA_AVX512_IPV6) |
15088 | | if (bool simd_valid; detail::try_parse_ipv6_avx512(input.data(), input.size(), |
15089 | | address, simd_valid)) { |
15090 | | if (!simd_valid) [[unlikely]] { |
15091 | | return is_valid = false; |
15092 | | } |
15093 | | const std::string serialized = ada::serializers::ipv6(address); |
15094 | | if (get_hostname() != serialized) { |
15095 | | update_base_hostname(serialized); |
15096 | | } |
15097 | | host_type = IPV6; |
15098 | | return true; |
15099 | | } |
15100 | | address = {}; |
15101 | | #endif |
15102 | 974 | const char* pointer = input.data(); |
15103 | 974 | const char* const end = pointer + input.size(); |
15104 | 974 | int piece_index = 0; |
15105 | 974 | int compress = -1; |
15106 | | |
15107 | 974 | if (*pointer == ':') { |
15108 | 374 | if (input.size() == 1 || pointer[1] != ':') [[unlikely]] { |
15109 | 14 | return is_valid = false; |
15110 | 14 | } |
15111 | 360 | pointer += 2; |
15112 | 360 | compress = ++piece_index; |
15113 | 360 | } |
15114 | | |
15115 | 2.88k | while (pointer != end) { |
15116 | 2.22k | if (piece_index == 8) [[unlikely]] { |
15117 | 6 | return is_valid = false; |
15118 | 6 | } |
15119 | 2.21k | if (*pointer == ':') { |
15120 | 278 | if (compress != -1) [[unlikely]] { |
15121 | 6 | return is_valid = false; |
15122 | 6 | } |
15123 | 272 | ++pointer; |
15124 | 272 | compress = ++piece_index; |
15125 | 272 | continue; |
15126 | 278 | } |
15127 | | |
15128 | 1.93k | uint16_t value = 0; |
15129 | 1.93k | const int length = detail::parse_hex_piece(pointer, end, value); |
15130 | | |
15131 | 1.93k | if (pointer != end && *pointer == '.') { |
15132 | 182 | if (length == 0) [[unlikely]] { |
15133 | 8 | return is_valid = false; |
15134 | 8 | } |
15135 | 174 | pointer -= length; |
15136 | 174 | if (piece_index > 6) [[unlikely]] { |
15137 | 6 | return is_valid = false; |
15138 | 6 | } |
15139 | | |
15140 | 168 | int numbers_seen = 0; |
15141 | 498 | while (pointer != end) { |
15142 | 438 | int ipv4_piece = -1; |
15143 | 438 | if (numbers_seen > 0) { |
15144 | 270 | if (*pointer == '.' && numbers_seen < 4) { |
15145 | 230 | ++pointer; |
15146 | 230 | } else { |
15147 | 40 | return is_valid = false; |
15148 | 40 | } |
15149 | 270 | } |
15150 | 398 | if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] { |
15151 | 50 | return is_valid = false; |
15152 | 50 | } |
15153 | 348 | ipv4_piece = *pointer - '0'; |
15154 | 348 | ++pointer; |
15155 | 348 | if (pointer != end && *pointer >= '0' && *pointer <= '9') { |
15156 | 116 | if (ipv4_piece == 0) [[unlikely]] { |
15157 | 8 | return is_valid = false; |
15158 | 8 | } |
15159 | 108 | ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); |
15160 | 108 | ++pointer; |
15161 | 108 | if (pointer != end && *pointer >= '0' && *pointer <= '9') { |
15162 | 48 | ipv4_piece = ipv4_piece * 10 + (*pointer - '0'); |
15163 | 48 | ++pointer; |
15164 | 48 | if (ipv4_piece > 255) [[unlikely]] { |
15165 | 10 | return is_valid = false; |
15166 | 10 | } |
15167 | 48 | } |
15168 | 108 | } |
15169 | 330 | address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>( |
15170 | 330 | address[static_cast<size_t>(piece_index)] * 0x100 + |
15171 | 330 | static_cast<uint16_t>(ipv4_piece)); |
15172 | 330 | ++numbers_seen; |
15173 | 330 | if (numbers_seen == 2 || numbers_seen == 4) { |
15174 | 138 | ++piece_index; |
15175 | 138 | } |
15176 | 330 | } |
15177 | 60 | if (numbers_seen != 4) [[unlikely]] { |
15178 | 36 | return is_valid = false; |
15179 | 36 | } |
15180 | 24 | break; |
15181 | 60 | } |
15182 | | |
15183 | 1.75k | if (length == 0) [[unlikely]] { |
15184 | 76 | return is_valid = false; |
15185 | 76 | } |
15186 | | |
15187 | 1.68k | if (pointer != end && *pointer == ':') { |
15188 | 1.29k | ++pointer; |
15189 | 1.29k | if (pointer == end) [[unlikely]] { |
15190 | 6 | return is_valid = false; |
15191 | 6 | } |
15192 | 1.29k | } else if (pointer != end) [[unlikely]] { |
15193 | 18 | return is_valid = false; |
15194 | 18 | } |
15195 | | |
15196 | 1.65k | address[static_cast<size_t>(piece_index)] = value; |
15197 | 1.65k | ++piece_index; |
15198 | 1.65k | } |
15199 | | |
15200 | 690 | if (compress != -1) { |
15201 | 614 | const int right = piece_index - compress; |
15202 | 614 | if (right > 0) { |
15203 | 318 | const size_t dest = static_cast<size_t>(8 - right); |
15204 | 318 | const size_t src = static_cast<size_t>(compress); |
15205 | 318 | if (dest != src) { |
15206 | 774 | for (size_t i = static_cast<size_t>(right); i-- > 0;) { |
15207 | 496 | address[dest + i] = address[src + i]; |
15208 | 496 | address[src + i] = 0; |
15209 | 496 | } |
15210 | 278 | } |
15211 | 318 | } |
15212 | 614 | } else if (piece_index != 8) [[unlikely]] { |
15213 | 38 | return is_valid = false; |
15214 | 38 | } |
15215 | | |
15216 | | // Serialize once; skip rewrite when hostname is already canonical. |
15217 | 652 | const std::string serialized = ada::serializers::ipv6(address); |
15218 | 652 | const std::string_view current = get_hostname(); |
15219 | 652 | if (current.size() == serialized.size() && |
15220 | 0 | std::memcmp(current.data(), serialized.data(), serialized.size()) == 0) { |
15221 | 0 | ada_log("parse_ipv6 in-place canonical match"); |
15222 | 652 | } else { |
15223 | 652 | update_base_hostname(serialized); |
15224 | 652 | } |
15225 | 652 | ada_log("parse_ipv6 ", get_hostname()); |
15226 | 652 | ADA_ASSERT_TRUE(validate()); |
15227 | 652 | host_type = IPV6; |
15228 | 652 | return true; |
15229 | 690 | } |
15230 | | |
15231 | 1.19k | bool url_aggregator::parse_opaque_host(std::string_view input) { |
15232 | 1.19k | ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); |
15233 | 1.19k | ADA_ASSERT_TRUE(validate()); |
15234 | 1.19k | ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); |
15235 | 1.19k | if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) { |
15236 | 26 | return is_valid = false; |
15237 | 26 | } |
15238 | | |
15239 | | // Return the result of running UTF-8 percent-encode on input using the C0 |
15240 | | // control percent-encode set. |
15241 | 1.17k | size_t idx = ada::unicode::percent_encode_index( |
15242 | 1.17k | input, character_sets::C0_CONTROL_PERCENT_ENCODE); |
15243 | 1.17k | if (idx == input.size()) { |
15244 | 690 | update_base_hostname(input); |
15245 | 690 | } else { |
15246 | | // We only create a temporary string if we need to. |
15247 | 480 | update_base_hostname(ada::unicode::percent_encode( |
15248 | 480 | input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx)); |
15249 | 480 | } |
15250 | 1.17k | ADA_ASSERT_TRUE(validate()); |
15251 | 1.17k | return true; |
15252 | 1.19k | } |
15253 | | |
15254 | 0 | [[nodiscard]] std::string url_aggregator::to_diagram() const { |
15255 | 0 | if (!is_valid) { |
15256 | 0 | return "invalid"; |
15257 | 0 | } |
15258 | 0 | std::string answer; |
15259 | 0 | answer.append(buffer); |
15260 | 0 | answer.append(" ["); |
15261 | 0 | answer.append(std::to_string(buffer.size())); |
15262 | 0 | answer.append(" bytes]"); |
15263 | 0 | answer.append("\n"); |
15264 | | // first line |
15265 | 0 | std::string line1; |
15266 | 0 | line1.resize(buffer.size(), ' '); |
15267 | 0 | if (components.hash_start != url_components::omitted) { |
15268 | 0 | line1[components.hash_start] = '|'; |
15269 | 0 | } |
15270 | 0 | if (components.search_start != url_components::omitted) { |
15271 | 0 | line1[components.search_start] = '|'; |
15272 | 0 | } |
15273 | 0 | if (components.pathname_start != buffer.size()) { |
15274 | 0 | line1[components.pathname_start] = '|'; |
15275 | 0 | } |
15276 | 0 | if (components.host_end != buffer.size()) { |
15277 | 0 | line1[components.host_end] = '|'; |
15278 | 0 | } |
15279 | 0 | if (components.host_start != buffer.size()) { |
15280 | 0 | line1[components.host_start] = '|'; |
15281 | 0 | } |
15282 | 0 | if (components.username_end != buffer.size()) { |
15283 | 0 | line1[components.username_end] = '|'; |
15284 | 0 | } |
15285 | 0 | if (components.protocol_end != buffer.size()) { |
15286 | 0 | line1[components.protocol_end] = '|'; |
15287 | 0 | } |
15288 | 0 | answer.append(line1); |
15289 | 0 | answer.append("\n"); |
15290 | |
|
15291 | 0 | std::string line2 = line1; |
15292 | 0 | if (components.hash_start != url_components::omitted) { |
15293 | 0 | line2[components.hash_start] = '`'; |
15294 | 0 | line1[components.hash_start] = ' '; |
15295 | |
|
15296 | 0 | for (size_t i = components.hash_start + 1; i < line2.size(); i++) { |
15297 | 0 | line2[i] = '-'; |
15298 | 0 | } |
15299 | 0 | line2.append(" hash_start"); |
15300 | 0 | answer.append(line2); |
15301 | 0 | answer.append("\n"); |
15302 | 0 | } |
15303 | |
|
15304 | 0 | std::string line3 = line1; |
15305 | 0 | if (components.search_start != url_components::omitted) { |
15306 | 0 | line3[components.search_start] = '`'; |
15307 | 0 | line1[components.search_start] = ' '; |
15308 | |
|
15309 | 0 | for (size_t i = components.search_start + 1; i < line3.size(); i++) { |
15310 | 0 | line3[i] = '-'; |
15311 | 0 | } |
15312 | 0 | line3.append(" search_start "); |
15313 | 0 | line3.append(std::to_string(components.search_start)); |
15314 | 0 | answer.append(line3); |
15315 | 0 | answer.append("\n"); |
15316 | 0 | } |
15317 | |
|
15318 | 0 | std::string line4 = line1; |
15319 | 0 | if (components.pathname_start != buffer.size()) { |
15320 | 0 | line4[components.pathname_start] = '`'; |
15321 | 0 | line1[components.pathname_start] = ' '; |
15322 | 0 | for (size_t i = components.pathname_start + 1; i < line4.size(); i++) { |
15323 | 0 | line4[i] = '-'; |
15324 | 0 | } |
15325 | 0 | line4.append(" pathname_start "); |
15326 | 0 | line4.append(std::to_string(components.pathname_start)); |
15327 | 0 | answer.append(line4); |
15328 | 0 | answer.append("\n"); |
15329 | 0 | } |
15330 | |
|
15331 | 0 | std::string line5 = line1; |
15332 | 0 | if (components.host_end != buffer.size()) { |
15333 | 0 | line5[components.host_end] = '`'; |
15334 | 0 | line1[components.host_end] = ' '; |
15335 | |
|
15336 | 0 | for (size_t i = components.host_end + 1; i < line5.size(); i++) { |
15337 | 0 | line5[i] = '-'; |
15338 | 0 | } |
15339 | 0 | line5.append(" host_end "); |
15340 | 0 | line5.append(std::to_string(components.host_end)); |
15341 | 0 | answer.append(line5); |
15342 | 0 | answer.append("\n"); |
15343 | 0 | } |
15344 | |
|
15345 | 0 | std::string line6 = line1; |
15346 | 0 | if (components.host_start != buffer.size()) { |
15347 | 0 | line6[components.host_start] = '`'; |
15348 | 0 | line1[components.host_start] = ' '; |
15349 | |
|
15350 | 0 | for (size_t i = components.host_start + 1; i < line6.size(); i++) { |
15351 | 0 | line6[i] = '-'; |
15352 | 0 | } |
15353 | 0 | line6.append(" host_start "); |
15354 | 0 | line6.append(std::to_string(components.host_start)); |
15355 | 0 | answer.append(line6); |
15356 | 0 | answer.append("\n"); |
15357 | 0 | } |
15358 | |
|
15359 | 0 | std::string line7 = line1; |
15360 | 0 | if (components.username_end != buffer.size()) { |
15361 | 0 | line7[components.username_end] = '`'; |
15362 | 0 | line1[components.username_end] = ' '; |
15363 | |
|
15364 | 0 | for (size_t i = components.username_end + 1; i < line7.size(); i++) { |
15365 | 0 | line7[i] = '-'; |
15366 | 0 | } |
15367 | 0 | line7.append(" username_end "); |
15368 | 0 | line7.append(std::to_string(components.username_end)); |
15369 | 0 | answer.append(line7); |
15370 | 0 | answer.append("\n"); |
15371 | 0 | } |
15372 | |
|
15373 | 0 | std::string line8 = line1; |
15374 | 0 | if (components.protocol_end != buffer.size()) { |
15375 | 0 | line8[components.protocol_end] = '`'; |
15376 | 0 | line1[components.protocol_end] = ' '; |
15377 | |
|
15378 | 0 | for (size_t i = components.protocol_end + 1; i < line8.size(); i++) { |
15379 | 0 | line8[i] = '-'; |
15380 | 0 | } |
15381 | 0 | line8.append(" protocol_end "); |
15382 | 0 | line8.append(std::to_string(components.protocol_end)); |
15383 | 0 | answer.append(line8); |
15384 | 0 | answer.append("\n"); |
15385 | 0 | } |
15386 | |
|
15387 | 0 | if (components.hash_start == url_components::omitted) { |
15388 | 0 | answer.append("note: hash omitted\n"); |
15389 | 0 | } |
15390 | 0 | if (components.search_start == url_components::omitted) { |
15391 | 0 | answer.append("note: search omitted\n"); |
15392 | 0 | } |
15393 | 0 | if (components.protocol_end > buffer.size()) { |
15394 | 0 | answer.append("warning: protocol_end overflows\n"); |
15395 | 0 | } |
15396 | 0 | if (components.username_end > buffer.size()) { |
15397 | 0 | answer.append("warning: username_end overflows\n"); |
15398 | 0 | } |
15399 | 0 | if (components.host_start > buffer.size()) { |
15400 | 0 | answer.append("warning: host_start overflows\n"); |
15401 | 0 | } |
15402 | 0 | if (components.host_end > buffer.size()) { |
15403 | 0 | answer.append("warning: host_end overflows\n"); |
15404 | 0 | } |
15405 | 0 | if (components.pathname_start > buffer.size()) { |
15406 | 0 | answer.append("warning: pathname_start overflows\n"); |
15407 | 0 | } |
15408 | 0 | return answer; |
15409 | 0 | } |
15410 | | |
15411 | 5 | void url_aggregator::delete_dash_dot() { |
15412 | 5 | ada_log("url_aggregator::delete_dash_dot"); |
15413 | 5 | ADA_ASSERT_TRUE(validate()); |
15414 | 5 | ADA_ASSERT_TRUE(has_dash_dot()); |
15415 | 5 | buffer.erase(components.host_end, 2); |
15416 | 5 | components.pathname_start -= 2; |
15417 | 5 | if (components.search_start != url_components::omitted) { |
15418 | 0 | components.search_start -= 2; |
15419 | 0 | } |
15420 | 5 | if (components.hash_start != url_components::omitted) { |
15421 | 0 | components.hash_start -= 2; |
15422 | 0 | } |
15423 | 5 | ADA_ASSERT_TRUE(validate()); |
15424 | 5 | ADA_ASSERT_TRUE(!has_dash_dot()); |
15425 | 5 | } |
15426 | | |
15427 | 10.3k | inline void url_aggregator::consume_prepared_path(std::string_view input) { |
15428 | 10.3k | ada_log("url_aggregator::consume_prepared_path ", input); |
15429 | | /*** |
15430 | | * This is largely duplicated code from helpers::parse_prepared_path, which is |
15431 | | * unfortunate. This particular function is nearly identical, except that it |
15432 | | * is a method on url_aggregator. The idea is that the trivial path (which is |
15433 | | * very common) merely appends to the buffer. This is the same trivial path as |
15434 | | * with helpers::parse_prepared_path, except that we have the additional check |
15435 | | * for is_at_path(). Otherwise, we grab a copy of the current path and we |
15436 | | * modify it, and then insert it back into the buffer. |
15437 | | */ |
15438 | 10.3k | uint8_t accumulator = checkers::path_signature(input); |
15439 | | // Let us first detect a trivial case. |
15440 | | // If it is special, we check that we have no dot, no %, no \ and no |
15441 | | // character needing percent encoding. Otherwise, we check that we have no %, |
15442 | | // no dot, and no character needing percent encoding. |
15443 | 10.3k | constexpr uint8_t need_encoding = 1; |
15444 | 10.3k | constexpr uint8_t backslash_char = 2; |
15445 | 10.3k | constexpr uint8_t dot_char = 4; |
15446 | 10.3k | constexpr uint8_t percent_char = 8; |
15447 | 10.3k | bool special = type != ada::scheme::NOT_SPECIAL; |
15448 | 10.3k | bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && |
15449 | 1.53k | checkers::is_windows_drive_letter(input)); |
15450 | 10.3k | bool trivial_path = |
15451 | 10.3k | (special ? (accumulator == 0) |
15452 | 10.3k | : ((accumulator & (need_encoding | dot_char | percent_char)) == |
15453 | 1.51k | 0)) && |
15454 | 4.77k | (!may_need_slow_file_handling); |
15455 | 10.3k | if (accumulator == dot_char && !may_need_slow_file_handling) { |
15456 | | // '4' means that we have at least one dot, but nothing that requires |
15457 | | // percent encoding or decoding. The only part that is not trivial is |
15458 | | // that we may have single dots and double dots path segments. |
15459 | | // If we have such segments, then we either have a path that begins |
15460 | | // with '.' (easy to check), or we have the sequence './'. |
15461 | | // Note: input cannot be empty, it must at least contain one character ('.') |
15462 | | // Note: we know that '\' is not present. |
15463 | 1.46k | if (input[0] != '.') { |
15464 | 777 | size_t slashdot = 0; |
15465 | 777 | bool dot_is_file = true; |
15466 | 5.23k | for (;;) { |
15467 | 5.23k | slashdot = input.find("/.", slashdot); |
15468 | 5.23k | if (slashdot == std::string_view::npos) { // common case |
15469 | 777 | break; |
15470 | 4.45k | } else { // uncommon |
15471 | | // only three cases matter: /./, /.. or a final / |
15472 | 4.45k | slashdot += 2; |
15473 | 4.45k | dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' || |
15474 | 1.73k | input[slashdot] == '/'); |
15475 | 4.45k | } |
15476 | 5.23k | } |
15477 | 777 | trivial_path = dot_is_file; |
15478 | 777 | } |
15479 | 1.46k | } |
15480 | 10.3k | if (trivial_path && is_at_path()) { |
15481 | 4.81k | ada_log("parse_path trivial"); |
15482 | 4.81k | buffer += '/'; |
15483 | 4.81k | buffer += input; |
15484 | 4.81k | return; |
15485 | 4.81k | } |
15486 | 5.50k | std::string path = std::string(get_pathname()); |
15487 | | // We are going to need to look a bit at the path, but let us see if we can |
15488 | | // ignore percent encoding *and* backslashes *and* percent characters. |
15489 | | // Except for the trivial case, this is likely to capture 99% of paths out |
15490 | | // there. |
15491 | 5.50k | bool fast_path = |
15492 | 5.50k | (special && |
15493 | 4.36k | (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && |
15494 | 1.26k | (type != ada::scheme::type::FILE); |
15495 | 5.50k | if (fast_path) { |
15496 | 1.08k | ada_log("parse_prepared_path fast"); |
15497 | | // Here we don't need to worry about \ or percent encoding. |
15498 | | // We also do not have a file protocol. We might have dots, however, |
15499 | | // but dots must as appear as '.', and they cannot be encoded because |
15500 | | // the symbol '%' is not present. |
15501 | 1.08k | size_t previous_location = 0; // We start at 0. |
15502 | 13.9k | do { |
15503 | 13.9k | size_t new_location = input.find('/', previous_location); |
15504 | | // std::string_view path_view = input; |
15505 | | // We process the last segment separately: |
15506 | 13.9k | if (new_location == std::string_view::npos) { |
15507 | 1.08k | std::string_view path_view = input.substr(previous_location); |
15508 | 1.08k | if (path_view == "..") { // The path ends with .. |
15509 | | // e.g., if you receive ".." with an empty path, you go to "/". |
15510 | 126 | if (path.empty()) { |
15511 | 49 | path = '/'; |
15512 | 49 | update_base_pathname(path); |
15513 | 49 | return; |
15514 | 49 | } |
15515 | | // Fast case where we have nothing to do: |
15516 | 77 | if (path.back() == '/') { |
15517 | 26 | update_base_pathname(path); |
15518 | 26 | return; |
15519 | 26 | } |
15520 | | // If you have the path "/joe/myfriend", |
15521 | | // then you delete 'myfriend'. |
15522 | 51 | path.resize(path.rfind('/') + 1); |
15523 | 51 | update_base_pathname(path); |
15524 | 51 | return; |
15525 | 77 | } |
15526 | 961 | path += '/'; |
15527 | 961 | if (path_view != ".") { |
15528 | 745 | path.append(path_view); |
15529 | 745 | } |
15530 | 961 | update_base_pathname(path); |
15531 | 961 | return; |
15532 | 12.9k | } else { |
15533 | | // This is a non-final segment. |
15534 | 12.9k | std::string_view path_view = |
15535 | 12.9k | input.substr(previous_location, new_location - previous_location); |
15536 | 12.9k | previous_location = new_location + 1; |
15537 | 12.9k | if (path_view == "..") { |
15538 | 2.75k | size_t last_delimiter = path.rfind('/'); |
15539 | 2.75k | if (last_delimiter != std::string::npos) { |
15540 | 1.11k | path.erase(last_delimiter); |
15541 | 1.11k | } |
15542 | 10.1k | } else if (path_view != ".") { |
15543 | 8.40k | path += '/'; |
15544 | 8.40k | path.append(path_view); |
15545 | 8.40k | } |
15546 | 12.9k | } |
15547 | 13.9k | } while (true); |
15548 | 4.41k | } else { |
15549 | 4.41k | ada_log("parse_path slow"); |
15550 | | // we have reached the general case |
15551 | 4.41k | bool needs_percent_encoding = (accumulator & 1); |
15552 | 29.8k | do { |
15553 | 29.8k | size_t location = (special && (accumulator & 2)) |
15554 | 29.8k | ? input.find_first_of("/\\") |
15555 | 29.8k | : input.find('/'); |
15556 | 29.8k | std::string_view path_view = input; |
15557 | 29.8k | if (location != std::string_view::npos) { |
15558 | 25.4k | path_view.remove_suffix(path_view.size() - location); |
15559 | 25.4k | input.remove_prefix(location + 1); |
15560 | 25.4k | } |
15561 | | // Path encoding preserves dots and percent signs, so normalize first. |
15562 | 29.8k | if (unicode::is_double_dot_path_segment(path_view)) { |
15563 | 4.38k | helpers::shorten_path(path, type); |
15564 | 4.38k | if (location == std::string_view::npos) { |
15565 | 253 | path += '/'; |
15566 | 253 | } |
15567 | 25.5k | } else if (unicode::is_single_dot_path_segment(path_view) && |
15568 | 1.33k | (location == std::string_view::npos)) { |
15569 | 115 | path += '/'; |
15570 | 115 | } |
15571 | | // Otherwise, if path_view is not a single-dot path segment, then: |
15572 | 25.3k | else if (!unicode::is_single_dot_path_segment(path_view)) { |
15573 | | // If url's scheme is "file", url's path is empty, and path_view is a |
15574 | | // Windows drive letter, then replace the second code point in |
15575 | | // path_view with U+003A (:). |
15576 | 24.1k | if (type == ada::scheme::type::FILE && path.empty() && |
15577 | 818 | path_view.size() == 2 && |
15578 | 341 | checkers::is_windows_drive_letter(path_view)) { |
15579 | 137 | path += '/'; |
15580 | 137 | path += path_view[0]; |
15581 | 137 | path += ':'; |
15582 | 137 | path_view.remove_prefix(2); |
15583 | 137 | path.append(path_view); |
15584 | 24.0k | } else { |
15585 | | // Append encoded bytes directly to the pathname. |
15586 | 24.0k | path += '/'; |
15587 | 24.0k | if (!needs_percent_encoding || |
15588 | 12.2k | !ada::unicode::percent_encode<true>( |
15589 | 19.2k | path_view, character_sets::PATH_PERCENT_ENCODE, path)) { |
15590 | 19.2k | path.append(path_view); |
15591 | 19.2k | } |
15592 | 24.0k | } |
15593 | 24.1k | } |
15594 | 29.8k | if (location == std::string_view::npos) { |
15595 | 4.41k | update_base_pathname(path); |
15596 | 4.41k | return; |
15597 | 4.41k | } |
15598 | 29.8k | } while (true); |
15599 | 4.41k | } |
15600 | 5.50k | } |
15601 | | } // namespace ada |
15602 | | /* end file src/url_aggregator.cpp */ |
15603 | | |
15604 | | #if ADA_INCLUDE_URL_PATTERN |
15605 | | /* begin file src/url_pattern.cpp */ |
15606 | | #if ADA_INCLUDE_URL_PATTERN |
15607 | | |
15608 | | |
15609 | | #include <algorithm> |
15610 | | #include <optional> |
15611 | | #include <string> |
15612 | | #include <string_view> |
15613 | | #include <utility> |
15614 | | |
15615 | | namespace ada { |
15616 | | |
15617 | | tl::expected<url_pattern_init, errors> url_pattern_init::process( |
15618 | | const url_pattern_init& init, url_pattern_init::process_type type, |
15619 | | std::optional<std::string_view> protocol, |
15620 | | std::optional<std::string_view> username, |
15621 | | std::optional<std::string_view> password, |
15622 | | std::optional<std::string_view> hostname, |
15623 | | std::optional<std::string_view> port, |
15624 | | std::optional<std::string_view> pathname, |
15625 | | std::optional<std::string_view> search, |
15626 | 0 | std::optional<std::string_view> hash) { |
15627 | | // Let result be the result of creating a new URLPatternInit. |
15628 | 0 | auto result = url_pattern_init{}; |
15629 | | |
15630 | | // If protocol is not null, set result["protocol"] to protocol. |
15631 | 0 | if (protocol.has_value()) result.protocol = *protocol; |
15632 | | |
15633 | | // If username is not null, set result["username"] to username. |
15634 | 0 | if (username.has_value()) result.username = *username; |
15635 | | |
15636 | | // If password is not null, set result["password"] to password. |
15637 | 0 | if (password.has_value()) result.password = *password; |
15638 | | |
15639 | | // If hostname is not null, set result["hostname"] to hostname. |
15640 | 0 | if (hostname.has_value()) result.hostname = *hostname; |
15641 | | |
15642 | | // If port is not null, set result["port"] to port. |
15643 | 0 | if (port.has_value()) result.port = *port; |
15644 | | |
15645 | | // If pathname is not null, set result["pathname"] to pathname. |
15646 | 0 | if (pathname.has_value()) result.pathname = *pathname; |
15647 | | |
15648 | | // If search is not null, set result["search"] to search. |
15649 | 0 | if (search.has_value()) result.search = *search; |
15650 | | |
15651 | | // If hash is not null, set result["hash"] to hash. |
15652 | 0 | if (hash.has_value()) result.hash = *hash; |
15653 | | |
15654 | | // Let baseURL be null. |
15655 | 0 | std::optional<url_aggregator> base_url{}; |
15656 | | |
15657 | | // If init["baseURL"] exists: |
15658 | 0 | if (init.base_url.has_value()) { |
15659 | | // Set baseURL to the result of parsing init["baseURL"]. |
15660 | 0 | auto parsing_result = ada::parse<url_aggregator>(*init.base_url); |
15661 | | // If baseURL is failure, then throw a TypeError. |
15662 | 0 | if (!parsing_result) { |
15663 | 0 | return tl::unexpected(errors::type_error); |
15664 | 0 | } |
15665 | 0 | base_url = std::move(*parsing_result); |
15666 | | |
15667 | | // If init["protocol"] does not exist, then set result["protocol"] to the |
15668 | | // result of processing a base URL string given baseURL's scheme and type. |
15669 | 0 | if (!init.protocol.has_value()) { |
15670 | 0 | ADA_ASSERT_TRUE(base_url.has_value()); |
15671 | 0 | std::string_view base_url_protocol = base_url->get_protocol(); |
15672 | 0 | if (base_url_protocol.ends_with(":")) base_url_protocol.remove_suffix(1); |
15673 | 0 | result.protocol = |
15674 | 0 | url_pattern_helpers::process_base_url_string(base_url_protocol, type); |
15675 | 0 | } |
15676 | | |
15677 | | // If type is not "pattern" and init contains none of "protocol", |
15678 | | // "hostname", "port" and "username", then set result["username"] to the |
15679 | | // result of processing a base URL string given baseURL's username and type. |
15680 | 0 | if (type != process_type::pattern && !init.protocol && !init.hostname && |
15681 | 0 | !init.port && !init.username) { |
15682 | 0 | result.username = url_pattern_helpers::process_base_url_string( |
15683 | 0 | base_url->get_username(), type); |
15684 | 0 | } |
15685 | | |
15686 | | // TODO: Optimization opportunity: Merge this with the previous check. |
15687 | | // If type is not "pattern" and init contains none of "protocol", |
15688 | | // "hostname", "port", "username" and "password", then set |
15689 | | // result["password"] to the result of processing a base URL string given |
15690 | | // baseURL's password and type. |
15691 | 0 | if (type != process_type::pattern && !init.protocol && !init.hostname && |
15692 | 0 | !init.port && !init.username && !init.password) { |
15693 | 0 | result.password = url_pattern_helpers::process_base_url_string( |
15694 | 0 | base_url->get_password(), type); |
15695 | 0 | } |
15696 | | |
15697 | | // If init contains neither "protocol" nor "hostname", then: |
15698 | 0 | if (!init.protocol && !init.hostname) { |
15699 | | // Let baseHost be baseURL's host. |
15700 | | // If baseHost is null, then set baseHost to the empty string. |
15701 | 0 | auto base_host = base_url->get_hostname(); |
15702 | | // Set result["hostname"] to the result of processing a base URL string |
15703 | | // given baseHost and type. |
15704 | 0 | result.hostname = |
15705 | 0 | url_pattern_helpers::process_base_url_string(base_host, type); |
15706 | 0 | } |
15707 | | |
15708 | | // If init contains none of "protocol", "hostname", and "port", then: |
15709 | 0 | if (!init.protocol && !init.hostname && !init.port) { |
15710 | | // If baseURL's port is null, then set result["port"] to the empty string. |
15711 | | // Otherwise, set result["port"] to baseURL's port, serialized. |
15712 | 0 | result.port = base_url->get_port(); |
15713 | 0 | } |
15714 | | |
15715 | | // If init contains none of "protocol", "hostname", "port", and "pathname", |
15716 | | // then set result["pathname"] to the result of processing a base URL string |
15717 | | // given the result of URL path serializing baseURL and type. |
15718 | 0 | if (!init.protocol && !init.hostname && !init.port && !init.pathname) { |
15719 | 0 | result.pathname = url_pattern_helpers::process_base_url_string( |
15720 | 0 | base_url->get_pathname(), type); |
15721 | 0 | } |
15722 | | |
15723 | | // If init contains none of "protocol", "hostname", "port", "pathname", and |
15724 | | // "search", then: |
15725 | 0 | if (!init.protocol && !init.hostname && !init.port && !init.pathname && |
15726 | 0 | !init.search) { |
15727 | | // Let baseQuery be baseURL's query. get_search() carries the leading "?" |
15728 | | // delimiter, but the spec inherits the query itself, so drop it. |
15729 | 0 | std::string_view base_query = base_url->get_search(); |
15730 | 0 | if (base_query.starts_with("?")) base_query.remove_prefix(1); |
15731 | | // Set result["search"] to the result of processing a base URL string |
15732 | | // given baseQuery and type. |
15733 | 0 | result.search = |
15734 | 0 | url_pattern_helpers::process_base_url_string(base_query, type); |
15735 | 0 | } |
15736 | | |
15737 | | // If init contains none of "protocol", "hostname", "port", "pathname", |
15738 | | // "search", and "hash", then: |
15739 | 0 | if (!init.protocol && !init.hostname && !init.port && !init.pathname && |
15740 | 0 | !init.search && !init.hash) { |
15741 | | // Let baseFragment be baseURL's fragment. get_hash() carries the leading |
15742 | | // "#" delimiter, but the spec inherits the fragment itself, so drop it. |
15743 | 0 | std::string_view base_fragment = base_url->get_hash(); |
15744 | 0 | if (base_fragment.starts_with("#")) base_fragment.remove_prefix(1); |
15745 | | // Set result["hash"] to the result of processing a base URL string given |
15746 | | // baseFragment and type. |
15747 | 0 | result.hash = |
15748 | 0 | url_pattern_helpers::process_base_url_string(base_fragment, type); |
15749 | 0 | } |
15750 | 0 | } |
15751 | | |
15752 | | // If init["protocol"] exists, then set result["protocol"] to the result of |
15753 | | // process protocol for init given init["protocol"] and type. |
15754 | 0 | if (init.protocol) { |
15755 | 0 | auto process_result = process_protocol(*init.protocol, type); |
15756 | 0 | if (!process_result) { |
15757 | 0 | return tl::unexpected(process_result.error()); |
15758 | 0 | } |
15759 | 0 | result.protocol = std::move(*process_result); |
15760 | 0 | } |
15761 | | |
15762 | | // If init["username"] exists, then set result["username"] to the result of |
15763 | | // process username for init given init["username"] and type. |
15764 | 0 | if (init.username.has_value()) { |
15765 | 0 | auto process_result = process_username(*init.username, type); |
15766 | 0 | if (!process_result) { |
15767 | 0 | return tl::unexpected(process_result.error()); |
15768 | 0 | } |
15769 | 0 | result.username = std::move(*process_result); |
15770 | 0 | } |
15771 | | |
15772 | | // If init["password"] exists, then set result["password"] to the result of |
15773 | | // process password for init given init["password"] and type. |
15774 | 0 | if (init.password.has_value()) { |
15775 | 0 | auto process_result = process_password(*init.password, type); |
15776 | 0 | if (!process_result) { |
15777 | 0 | return tl::unexpected(process_result.error()); |
15778 | 0 | } |
15779 | 0 | result.password = std::move(*process_result); |
15780 | 0 | } |
15781 | | |
15782 | | // If init["hostname"] exists, then set result["hostname"] to the result of |
15783 | | // process hostname for init given init["hostname"] and type. |
15784 | 0 | if (init.hostname.has_value()) { |
15785 | 0 | auto process_result = process_hostname(*init.hostname, type); |
15786 | 0 | if (!process_result) { |
15787 | 0 | return tl::unexpected(process_result.error()); |
15788 | 0 | } |
15789 | 0 | result.hostname = std::move(*process_result); |
15790 | 0 | } |
15791 | | |
15792 | | // If init["port"] exists, then set result["port"] to the result of process |
15793 | | // port for init given init["port"], result["protocol"], and type. |
15794 | 0 | if (init.port) { |
15795 | 0 | auto process_result = |
15796 | 0 | process_port(*init.port, result.protocol.value_or("fake"), type); |
15797 | 0 | if (!process_result) { |
15798 | 0 | return tl::unexpected(process_result.error()); |
15799 | 0 | } |
15800 | 0 | result.port = std::move(*process_result); |
15801 | 0 | } |
15802 | | |
15803 | | // If init["pathname"] exists: |
15804 | 0 | if (init.pathname.has_value()) { |
15805 | | // Set result["pathname"] to init["pathname"]. |
15806 | 0 | result.pathname = init.pathname; |
15807 | | |
15808 | | // If the following are all true: |
15809 | | // - baseURL is not null; |
15810 | | // - baseURL has an opaque path; and |
15811 | | // - the result of running is an absolute pathname given result["pathname"] |
15812 | | // and type is false, |
15813 | 0 | if (base_url && !base_url->has_opaque_path && |
15814 | 0 | !url_pattern_helpers::is_absolute_pathname(*result.pathname, type)) { |
15815 | | // Let baseURLPath be the result of running process a base URL string |
15816 | | // given the result of URL path serializing baseURL and type. |
15817 | | // TODO: Optimization opportunity: Avoid returning a string if no slash |
15818 | | // exist. |
15819 | 0 | std::string base_url_path = url_pattern_helpers::process_base_url_string( |
15820 | 0 | base_url->get_pathname(), type); |
15821 | | |
15822 | | // Let slash index be the index of the last U+002F (/) code point found in |
15823 | | // baseURLPath, interpreted as a sequence of code points, or null if there |
15824 | | // are no instances of the code point. |
15825 | 0 | auto slash_index = base_url_path.find_last_of('/'); |
15826 | | |
15827 | | // If slash index is not null: |
15828 | 0 | if (slash_index != std::string::npos) { |
15829 | | // Let new pathname be the code point substring from 0 to slash index + |
15830 | | // 1 within baseURLPath. |
15831 | 0 | base_url_path.resize(slash_index + 1); |
15832 | | // Append result["pathname"] to the end of new pathname. |
15833 | 0 | ADA_ASSERT_TRUE(result.pathname.has_value()); |
15834 | 0 | base_url_path.append(std::move(*result.pathname)); |
15835 | | // Set result["pathname"] to new pathname. |
15836 | 0 | result.pathname = std::move(base_url_path); |
15837 | 0 | } |
15838 | 0 | } |
15839 | | |
15840 | | // Set result["pathname"] to the result of process pathname for init given |
15841 | | // result["pathname"], result["protocol"], and type. |
15842 | 0 | auto pathname_processing_result = |
15843 | 0 | process_pathname(*result.pathname, result.protocol.value_or(""), type); |
15844 | 0 | if (!pathname_processing_result) { |
15845 | 0 | return tl::unexpected(pathname_processing_result.error()); |
15846 | 0 | } |
15847 | 0 | result.pathname = std::move(*pathname_processing_result); |
15848 | 0 | } |
15849 | | |
15850 | | // If init["search"] exists then set result["search"] to the result of process |
15851 | | // search for init given init["search"] and type. |
15852 | 0 | if (init.search) { |
15853 | 0 | auto process_result = process_search(*init.search, type); |
15854 | 0 | if (!process_result) { |
15855 | 0 | return tl::unexpected(process_result.error()); |
15856 | 0 | } |
15857 | 0 | result.search = std::move(*process_result); |
15858 | 0 | } |
15859 | | |
15860 | | // If init["hash"] exists then set result["hash"] to the result of process |
15861 | | // hash for init given init["hash"] and type. |
15862 | 0 | if (init.hash) { |
15863 | 0 | auto process_result = process_hash(*init.hash, type); |
15864 | 0 | if (!process_result) { |
15865 | 0 | return tl::unexpected(process_result.error()); |
15866 | 0 | } |
15867 | 0 | result.hash = std::move(*process_result); |
15868 | 0 | } |
15869 | | // Return result. |
15870 | 0 | return result; |
15871 | 0 | } |
15872 | | |
15873 | | tl::expected<std::string, errors> url_pattern_init::process_protocol( |
15874 | 0 | std::string_view value, process_type type) { |
15875 | 0 | ada_log("process_protocol=", value, " [", type, "]"); |
15876 | | // Let strippedValue be the given value with a single trailing U+003A (:) |
15877 | | // removed, if any. |
15878 | 0 | if (value.ends_with(":")) { |
15879 | 0 | value.remove_suffix(1); |
15880 | 0 | } |
15881 | | // If type is "pattern" then return strippedValue. |
15882 | 0 | if (type == process_type::pattern) { |
15883 | 0 | return std::string(value); |
15884 | 0 | } |
15885 | | // Return the result of running canonicalize a protocol given strippedValue. |
15886 | 0 | return url_pattern_helpers::canonicalize_protocol(value); |
15887 | 0 | } |
15888 | | |
15889 | | tl::expected<std::string, errors> url_pattern_init::process_username( |
15890 | 0 | std::string_view value, process_type type) { |
15891 | | // If type is "pattern" then return value. |
15892 | 0 | if (type == process_type::pattern) { |
15893 | 0 | return std::string(value); |
15894 | 0 | } |
15895 | | // Return the result of running canonicalize a username given value. |
15896 | 0 | return url_pattern_helpers::canonicalize_username(value); |
15897 | 0 | } |
15898 | | |
15899 | | tl::expected<std::string, errors> url_pattern_init::process_password( |
15900 | 0 | std::string_view value, process_type type) { |
15901 | | // If type is "pattern" then return value. |
15902 | 0 | if (type == process_type::pattern) { |
15903 | 0 | return std::string(value); |
15904 | 0 | } |
15905 | | // Return the result of running canonicalize a password given value. |
15906 | 0 | return url_pattern_helpers::canonicalize_password(value); |
15907 | 0 | } |
15908 | | |
15909 | | tl::expected<std::string, errors> url_pattern_init::process_hostname( |
15910 | 0 | std::string_view value, process_type type) { |
15911 | 0 | ada_log("process_hostname value=", value, " type=", type); |
15912 | | // If type is "pattern" then return value. |
15913 | 0 | if (type == process_type::pattern) { |
15914 | 0 | return std::string(value); |
15915 | 0 | } |
15916 | | // Return the result of running canonicalize a hostname given value. |
15917 | 0 | return url_pattern_helpers::canonicalize_hostname(value); |
15918 | 0 | } |
15919 | | |
15920 | | tl::expected<std::string, errors> url_pattern_init::process_port( |
15921 | 0 | std::string_view port, std::string_view protocol, process_type type) { |
15922 | | // If type is "pattern" then return portValue. |
15923 | 0 | if (type == process_type::pattern) { |
15924 | 0 | return std::string(port); |
15925 | 0 | } |
15926 | | // Return the result of running canonicalize a port given portValue and |
15927 | | // protocolValue. |
15928 | 0 | return url_pattern_helpers::canonicalize_port_with_protocol(port, protocol); |
15929 | 0 | } |
15930 | | |
15931 | | tl::expected<std::string, errors> url_pattern_init::process_pathname( |
15932 | 0 | std::string_view value, std::string_view protocol, process_type type) { |
15933 | | // If type is "pattern" then return pathnameValue. |
15934 | 0 | if (type == process_type::pattern) { |
15935 | 0 | return std::string(value); |
15936 | 0 | } |
15937 | | |
15938 | | // If protocolValue is a special scheme or the empty string, then return the |
15939 | | // result of running canonicalize a pathname given pathnameValue. |
15940 | 0 | if (protocol.empty() || scheme::is_special(protocol)) { |
15941 | 0 | return url_pattern_helpers::canonicalize_pathname(value); |
15942 | 0 | } |
15943 | | |
15944 | | // Return the result of running canonicalize an opaque pathname given |
15945 | | // pathnameValue. |
15946 | 0 | return url_pattern_helpers::canonicalize_opaque_pathname(value); |
15947 | 0 | } |
15948 | | |
15949 | | tl::expected<std::string, errors> url_pattern_init::process_search( |
15950 | 0 | std::string_view value, process_type type) { |
15951 | | // Let strippedValue be the given value with a single leading U+003F (?) |
15952 | | // removed, if any. |
15953 | 0 | if (value.starts_with("?")) { |
15954 | 0 | value.remove_prefix(1); |
15955 | 0 | } |
15956 | | // We cannot assert that the value is no longer starting with a single |
15957 | | // question mark because technically it can start. The question is whether or |
15958 | | // not we should remove the first question mark. Ref: |
15959 | | // https://github.com/ada-url/ada/pull/992 The spec is not clear on this. |
15960 | | |
15961 | | // If type is "pattern" then return strippedValue. |
15962 | 0 | if (type == process_type::pattern) { |
15963 | 0 | return std::string(value); |
15964 | 0 | } |
15965 | | // Return the result of running canonicalize a search given strippedValue. |
15966 | 0 | return url_pattern_helpers::canonicalize_search(value); |
15967 | 0 | } |
15968 | | |
15969 | | tl::expected<std::string, errors> url_pattern_init::process_hash( |
15970 | 0 | std::string_view value, process_type type) { |
15971 | | // Let strippedValue be the given value with a single leading U+0023 (#) |
15972 | | // removed, if any. |
15973 | 0 | if (value.starts_with("#")) { |
15974 | 0 | value.remove_prefix(1); |
15975 | 0 | } |
15976 | 0 | ADA_ASSERT_TRUE(!value.starts_with("#")); |
15977 | | // If type is "pattern" then return strippedValue. |
15978 | 0 | if (type == process_type::pattern) { |
15979 | 0 | return std::string(value); |
15980 | 0 | } |
15981 | | // Return the result of running canonicalize a hash given strippedValue. |
15982 | 0 | return url_pattern_helpers::canonicalize_hash(value); |
15983 | 0 | } |
15984 | | |
15985 | | } // namespace ada |
15986 | | |
15987 | | #endif // ADA_INCLUDE_URL_PATTERN |
15988 | | /* end file src/url_pattern.cpp */ |
15989 | | /* begin file src/url_pattern_helpers.cpp */ |
15990 | | #if ADA_INCLUDE_URL_PATTERN |
15991 | | |
15992 | | #include <algorithm> |
15993 | | #include <array> |
15994 | | #include <charconv> |
15995 | | #include <cstddef> |
15996 | | #include <cstdint> |
15997 | | #include <optional> |
15998 | | #include <ranges> |
15999 | | #include <string> |
16000 | | #include <string_view> |
16001 | | #include <system_error> |
16002 | | #include <tuple> |
16003 | | #include <utility> |
16004 | | #include <vector> |
16005 | | |
16006 | | |
16007 | | namespace ada::url_pattern_helpers { |
16008 | | |
16009 | | std::tuple<std::string, std::vector<std::string>> |
16010 | | generate_regular_expression_and_name_list( |
16011 | | const std::vector<url_pattern_part>& part_list, |
16012 | 0 | url_pattern_compile_component_options options) { |
16013 | | // Let result be "^" |
16014 | 0 | std::string result = "^"; |
16015 | | // Reserve capacity to reduce reallocations |
16016 | 0 | result.reserve(part_list.size() * 16); |
16017 | | |
16018 | | // Let name list be a new list |
16019 | 0 | std::vector<std::string> name_list{}; |
16020 | 0 | name_list.reserve(part_list.size()); |
16021 | | |
16022 | | // Pre-generate segment wildcard regexp if needed (avoids repeated generation) |
16023 | 0 | std::string segment_wildcard_regexp; |
16024 | | |
16025 | | // For each part of part list: |
16026 | 0 | for (const url_pattern_part& part : part_list) { |
16027 | | // If part's type is "fixed-text": |
16028 | 0 | if (part.type == url_pattern_part_type::FIXED_TEXT) { |
16029 | | // If part's modifier is "none" |
16030 | 0 | if (part.modifier == url_pattern_part_modifier::none) { |
16031 | 0 | result.append(escape_regexp_string(part.value)); |
16032 | 0 | } else { |
16033 | | // (?:<fixed text>)<modifier> |
16034 | 0 | result.append("(?:"); |
16035 | 0 | result.append(escape_regexp_string(part.value)); |
16036 | 0 | result.push_back(')'); |
16037 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
16038 | 0 | } |
16039 | 0 | continue; |
16040 | 0 | } |
16041 | | |
16042 | | // Assert: part's name is not the empty string |
16043 | 0 | ADA_ASSERT_TRUE(!part.name.empty()); |
16044 | 0 | name_list.push_back(part.name); |
16045 | | |
16046 | | // Use string_view to avoid copies where possible |
16047 | 0 | std::string_view regexp_value = part.value; |
16048 | |
|
16049 | 0 | if (part.type == url_pattern_part_type::SEGMENT_WILDCARD) { |
16050 | | // Lazy generate segment wildcard regexp |
16051 | 0 | if (segment_wildcard_regexp.empty()) { |
16052 | 0 | segment_wildcard_regexp = generate_segment_wildcard_regexp(options); |
16053 | 0 | } |
16054 | 0 | regexp_value = segment_wildcard_regexp; |
16055 | 0 | } else if (part.type == url_pattern_part_type::FULL_WILDCARD) { |
16056 | 0 | regexp_value = ".*"; |
16057 | 0 | } |
16058 | | |
16059 | | // If part's prefix is the empty string and part's suffix is the empty |
16060 | | // string |
16061 | 0 | if (part.prefix.empty() && part.suffix.empty()) { |
16062 | | // If part's modifier is "none" or "optional" |
16063 | 0 | if (part.modifier == url_pattern_part_modifier::none || |
16064 | 0 | part.modifier == url_pattern_part_modifier::optional) { |
16065 | | // (<regexp value>)<modifier> |
16066 | 0 | result.push_back('('); |
16067 | 0 | result.append(regexp_value); |
16068 | 0 | result.push_back(')'); |
16069 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
16070 | 0 | } else { |
16071 | | // ((?:<regexp value>)<modifier>) |
16072 | 0 | result.append("((?:"); |
16073 | 0 | result.append(regexp_value); |
16074 | 0 | result.push_back(')'); |
16075 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
16076 | 0 | result.push_back(')'); |
16077 | 0 | } |
16078 | 0 | continue; |
16079 | 0 | } |
16080 | | |
16081 | | // If part's modifier is "none" or "optional" |
16082 | 0 | if (part.modifier == url_pattern_part_modifier::none || |
16083 | 0 | part.modifier == url_pattern_part_modifier::optional) { |
16084 | | // (?:<prefix>(<regexp value>)<suffix>)<modifier> |
16085 | 0 | result.append("(?:"); |
16086 | 0 | result.append(escape_regexp_string(part.prefix)); |
16087 | 0 | result.push_back('('); |
16088 | 0 | result.append(regexp_value); |
16089 | 0 | result.push_back(')'); |
16090 | 0 | result.append(escape_regexp_string(part.suffix)); |
16091 | 0 | result.push_back(')'); |
16092 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
16093 | 0 | continue; |
16094 | 0 | } |
16095 | | |
16096 | | // Assert: part's modifier is "zero-or-more" or "one-or-more" |
16097 | 0 | ADA_ASSERT_TRUE(part.modifier == url_pattern_part_modifier::zero_or_more || |
16098 | 0 | part.modifier == url_pattern_part_modifier::one_or_more); |
16099 | | |
16100 | | // Assert: part's prefix is not the empty string or part's suffix is not the |
16101 | | // empty string |
16102 | 0 | ADA_ASSERT_TRUE(!part.prefix.empty() || !part.suffix.empty()); |
16103 | | |
16104 | | // (?:<prefix>((?:<regexp value>)(?:<suffix><prefix>(?:<regexp |
16105 | | // value>))*)<suffix>)? |
16106 | | // Append "(?:" to the end of result. |
16107 | 0 | result.append("(?:"); |
16108 | | // Append the result of running escape a regexp string given part's prefix |
16109 | | // to the end of result. |
16110 | 0 | result.append(escape_regexp_string(part.prefix)); |
16111 | | // Append "((?:" to the end of result. |
16112 | 0 | result.append("((?:"); |
16113 | | // Append regexp value to the end of result. |
16114 | 0 | result.append(regexp_value); |
16115 | | // Append ")(?:" to the end of result. |
16116 | 0 | result.append(")(?:"); |
16117 | | // Append the result of running escape a regexp string given part's suffix |
16118 | | // to the end of result. |
16119 | 0 | result.append(escape_regexp_string(part.suffix)); |
16120 | | // Append the result of running escape a regexp string given part's prefix |
16121 | | // to the end of result. |
16122 | 0 | result.append(escape_regexp_string(part.prefix)); |
16123 | | // Append "(?:" to the end of result. |
16124 | 0 | result.append("(?:"); |
16125 | | // Append regexp value to the end of result. |
16126 | 0 | result.append(regexp_value); |
16127 | | // Append "))*)" to the end of result. |
16128 | 0 | result.append("))*)"); |
16129 | | // Append the result of running escape a regexp string given part's suffix |
16130 | | // to the end of result. |
16131 | 0 | result.append(escape_regexp_string(part.suffix)); |
16132 | | // Append ")" to the end of result. |
16133 | 0 | result.append(")"); |
16134 | | |
16135 | | // If part's modifier is "zero-or-more" then append "?" to the end of result |
16136 | 0 | if (part.modifier == url_pattern_part_modifier::zero_or_more) { |
16137 | 0 | result += "?"; |
16138 | 0 | } |
16139 | 0 | } |
16140 | | |
16141 | | // Append "$" to the end of result |
16142 | 0 | result += "$"; |
16143 | | |
16144 | | // Return (result, name list) |
16145 | 0 | return {std::move(result), std::move(name_list)}; |
16146 | 0 | } |
16147 | | |
16148 | 0 | bool is_ipv6_address(std::string_view input) noexcept { |
16149 | | // If input's code point length is less than 2, then return false. |
16150 | 0 | if (input.size() < 2) return false; |
16151 | | |
16152 | | // Let input code points be input interpreted as a list of code points. |
16153 | | // If input code points[0] is U+005B ([), then return true. |
16154 | 0 | if (input.front() == '[') return true; |
16155 | | // If input code points[0] is U+007B ({) and input code points[1] is U+005B |
16156 | | // ([), then return true. |
16157 | 0 | if (input.starts_with("{[")) return true; |
16158 | | // If input code points[0] is U+005C (\) and input code points[1] is U+005B |
16159 | | // ([), then return true. |
16160 | 0 | return input.starts_with("\\["); |
16161 | 0 | } |
16162 | | |
16163 | | std::string_view convert_modifier_to_string( |
16164 | 0 | url_pattern_part_modifier modifier) { |
16165 | 0 | switch (modifier) { |
16166 | | // If modifier is "zero-or-more", then return "*". |
16167 | 0 | case url_pattern_part_modifier::zero_or_more: |
16168 | 0 | return "*"; |
16169 | | // If modifier is "optional", then return "?". |
16170 | 0 | case url_pattern_part_modifier::optional: |
16171 | 0 | return "?"; |
16172 | | // If modifier is "one-or-more", then return "+". |
16173 | 0 | case url_pattern_part_modifier::one_or_more: |
16174 | 0 | return "+"; |
16175 | | // Return the empty string. |
16176 | 0 | default: |
16177 | 0 | return ""; |
16178 | 0 | } |
16179 | 0 | } |
16180 | | |
16181 | | std::string generate_segment_wildcard_regexp( |
16182 | 0 | url_pattern_compile_component_options options) { |
16183 | | // Let result be "[^". |
16184 | 0 | std::string result = "[^"; |
16185 | | // Append the result of running escape a regexp string given options's |
16186 | | // delimiter code point to the end of result. |
16187 | 0 | result.append(escape_regexp_string(options.get_delimiter())); |
16188 | | // Append "]+?" to the end of result. |
16189 | 0 | result.append("]+?"); |
16190 | | // Return result. |
16191 | 0 | ada_log("generate_segment_wildcard_regexp result: ", result); |
16192 | 0 | return result; |
16193 | 0 | } |
16194 | | |
16195 | | namespace { |
16196 | | // Unified lookup table for URL pattern character classification |
16197 | | // Bit flags for different character types |
16198 | | constexpr uint8_t CHAR_SCHEME = 1; // valid in scheme (a-z, A-Z, 0-9, +, -, .) |
16199 | | constexpr uint8_t CHAR_UPPER = 2; // uppercase letter (needs lowercasing) |
16200 | | constexpr uint8_t CHAR_SIMPLE_HOSTNAME = 4; // simple hostname (a-z, 0-9, -, .) |
16201 | | constexpr uint8_t CHAR_SIMPLE_PATHNAME = |
16202 | | 8; // simple pathname (a-z, A-Z, 0-9, /, -, _, ~) |
16203 | | |
16204 | | constexpr std::array<uint8_t, 256> char_class_table = []() consteval { |
16205 | | std::array<uint8_t, 256> table{}; |
16206 | | for (int c = 'a'; c <= 'z'; c++) |
16207 | | table[c] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; |
16208 | | for (int c = 'A'; c <= 'Z'; c++) |
16209 | | table[c] = CHAR_SCHEME | CHAR_UPPER | CHAR_SIMPLE_PATHNAME; |
16210 | | for (int c = '0'; c <= '9'; c++) |
16211 | | table[c] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; |
16212 | | table['+'] = CHAR_SCHEME; |
16213 | | table['-'] = CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME | CHAR_SIMPLE_PATHNAME; |
16214 | | table['.'] = |
16215 | | CHAR_SCHEME | CHAR_SIMPLE_HOSTNAME; // not pathname (needs normalization) |
16216 | | table['/'] = CHAR_SIMPLE_PATHNAME; |
16217 | | table['_'] = CHAR_SIMPLE_PATHNAME; |
16218 | | table['~'] = CHAR_SIMPLE_PATHNAME; |
16219 | | return table; |
16220 | | }(); |
16221 | | } // namespace |
16222 | | |
16223 | | tl::expected<std::string, errors> canonicalize_protocol( |
16224 | 0 | std::string_view input) { |
16225 | 0 | ada_log("canonicalize_protocol called with input=", input); |
16226 | 0 | if (input.empty()) [[unlikely]] { |
16227 | 0 | return ""; |
16228 | 0 | } |
16229 | | |
16230 | 0 | if (input.ends_with(":")) { |
16231 | 0 | input.remove_suffix(1); |
16232 | 0 | } |
16233 | | |
16234 | | // Fast path: special schemes are already canonical |
16235 | 0 | if (scheme::is_special(input)) { |
16236 | 0 | return std::string(input); |
16237 | 0 | } |
16238 | | |
16239 | | // Fast path: validate scheme chars and check for uppercase |
16240 | | // First char must be alpha (not +, -, ., or digit) |
16241 | 0 | uint8_t first_flags = char_class_table[static_cast<uint8_t>(input[0])]; |
16242 | 0 | if (!(first_flags & CHAR_SCHEME) || input[0] == '+' || input[0] == '-' || |
16243 | 0 | input[0] == '.' || unicode::is_ascii_digit(input[0])) { |
16244 | 0 | return tl::unexpected(errors::type_error); |
16245 | 0 | } |
16246 | | |
16247 | 0 | uint8_t needs_lowercase = first_flags & CHAR_UPPER; |
16248 | 0 | for (size_t i = 1; i < input.size(); i++) { |
16249 | 0 | uint8_t flags = char_class_table[static_cast<uint8_t>(input[i])]; |
16250 | 0 | if (!(flags & CHAR_SCHEME)) { |
16251 | 0 | return tl::unexpected(errors::type_error); |
16252 | 0 | } |
16253 | 0 | needs_lowercase |= flags & CHAR_UPPER; |
16254 | 0 | } |
16255 | | |
16256 | 0 | if (needs_lowercase == 0) { |
16257 | 0 | return std::string(input); |
16258 | 0 | } |
16259 | | |
16260 | 0 | std::string result(input); |
16261 | 0 | unicode::to_lower_ascii(result.data(), result.size()); |
16262 | 0 | return result; |
16263 | 0 | } |
16264 | | |
16265 | | tl::expected<std::string, errors> canonicalize_username( |
16266 | 0 | std::string_view input) { |
16267 | | // If value is the empty string, return value. |
16268 | 0 | if (input.empty()) [[unlikely]] { |
16269 | 0 | return ""; |
16270 | 0 | } |
16271 | | // Percent-encode the input using the userinfo percent-encode set. |
16272 | 0 | size_t idx = ada::unicode::percent_encode_index( |
16273 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
16274 | 0 | if (idx == input.size()) { |
16275 | | // No encoding needed, return input as-is |
16276 | 0 | return std::string(input); |
16277 | 0 | } |
16278 | | // Percent-encode from the first character that needs encoding |
16279 | 0 | return ada::unicode::percent_encode( |
16280 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE, idx); |
16281 | 0 | } |
16282 | | |
16283 | | tl::expected<std::string, errors> canonicalize_password( |
16284 | 0 | std::string_view input) { |
16285 | | // If value is the empty string, return value. |
16286 | 0 | if (input.empty()) [[unlikely]] { |
16287 | 0 | return ""; |
16288 | 0 | } |
16289 | | // Percent-encode the input using the userinfo percent-encode set. |
16290 | 0 | size_t idx = ada::unicode::percent_encode_index( |
16291 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE); |
16292 | 0 | if (idx == input.size()) { |
16293 | | // No encoding needed, return input as-is |
16294 | 0 | return std::string(input); |
16295 | 0 | } |
16296 | | // Percent-encode from the first character that needs encoding |
16297 | 0 | return ada::unicode::percent_encode( |
16298 | 0 | input, character_sets::USERINFO_PERCENT_ENCODE, idx); |
16299 | 0 | } |
16300 | | |
16301 | | tl::expected<std::string, errors> canonicalize_hostname( |
16302 | 0 | std::string_view input) { |
16303 | 0 | ada_log("canonicalize_hostname input=", input); |
16304 | 0 | if (input.empty()) [[unlikely]] { |
16305 | 0 | return ""; |
16306 | 0 | } |
16307 | | |
16308 | | // Fast path: simple hostnames (lowercase ASCII, digits, -, .) need no IDNA. |
16309 | | // The simple character set also covers IPv4-shaped hosts, which the slow |
16310 | | // path rewrites ("0" -> "0.0.0.0", "0x7f.1" -> "127.0.0.1"). Exclude those |
16311 | | // so the fast path can't return a non-canonical hostname. |
16312 | | // |
16313 | | // Pure-ASCII "xn--" labels are intentionally left on the fast path: with |
16314 | | // beStrict=false, domain-to-ASCII returns the lowercased ASCII input even |
16315 | | // when Unicode ToASCII would fail (e.g. invalid ACE "xn--a"). See |
16316 | | // https://url.spec.whatwg.org/#concept-domain-to-ascii |
16317 | 0 | bool needs_processing = false; |
16318 | 0 | for (char c : input) { |
16319 | 0 | needs_processing |= |
16320 | 0 | !(char_class_table[static_cast<uint8_t>(c)] & CHAR_SIMPLE_HOSTNAME); |
16321 | 0 | } |
16322 | 0 | if (!needs_processing && !checkers::is_ipv4(input)) { |
16323 | 0 | return std::string(input); |
16324 | 0 | } |
16325 | | |
16326 | | // Let dummyURL be a new URL record. |
16327 | | // Let parseResult be the result of running the basic URL parser given value |
16328 | | // with dummyURL as url and hostname state as state override. |
16329 | | |
16330 | | // IMPORTANT: The protocol needs to be a special protocol, otherwise the |
16331 | | // hostname will not be converted using IDNA. |
16332 | 0 | auto url = ada::parse<url_aggregator>("https://dummy.test", nullptr); |
16333 | 0 | ADA_ASSERT_TRUE(url); |
16334 | | // if (!isValidHostnameInput(hostname)) return kj::none; |
16335 | 0 | if (!url->set_hostname(input)) { |
16336 | | // If parseResult is failure, then throw a TypeError. |
16337 | 0 | return tl::unexpected(errors::type_error); |
16338 | 0 | } |
16339 | | // Return dummyURL's host, serialized, or empty string if it is null. |
16340 | 0 | return std::string(url->get_hostname()); |
16341 | 0 | } |
16342 | | |
16343 | | tl::expected<std::string, errors> canonicalize_ipv6_hostname( |
16344 | 0 | std::string_view input) { |
16345 | 0 | ada_log("canonicalize_ipv6_hostname input=", input); |
16346 | | // TODO: Optimization opportunity: Use lookup table to speed up checking |
16347 | 0 | if (std::ranges::any_of(input, [](char c) { |
16348 | 0 | return c != '[' && c != ']' && c != ':' && |
16349 | 0 | !unicode::is_ascii_hex_digit(c); |
16350 | 0 | })) { |
16351 | 0 | return tl::unexpected(errors::type_error); |
16352 | 0 | } |
16353 | | // Append the result of running ASCII lowercase given code point to the end of |
16354 | | // result. |
16355 | 0 | auto hostname = std::string(input); |
16356 | 0 | unicode::to_lower_ascii(hostname.data(), hostname.size()); |
16357 | 0 | return hostname; |
16358 | 0 | } |
16359 | | |
16360 | | tl::expected<std::string, errors> canonicalize_port( |
16361 | 0 | std::string_view port_value) { |
16362 | | // If portValue is the empty string, return portValue. |
16363 | 0 | if (port_value.empty()) [[unlikely]] { |
16364 | 0 | return ""; |
16365 | 0 | } |
16366 | | |
16367 | | // Remove ASCII tab or newline characters |
16368 | 0 | std::string trimmed(port_value); |
16369 | 0 | helpers::remove_ascii_tab_or_newline(trimmed); |
16370 | |
|
16371 | 0 | if (trimmed.empty()) { |
16372 | 0 | return ""; |
16373 | 0 | } |
16374 | | |
16375 | | // Input should start with a digit character |
16376 | 0 | if (!unicode::is_ascii_digit(trimmed.front())) { |
16377 | 0 | return tl::unexpected(errors::type_error); |
16378 | 0 | } |
16379 | | |
16380 | | // Find the first non-digit character |
16381 | 0 | auto first_non_digit = |
16382 | 0 | std::ranges::find_if_not(trimmed, unicode::is_ascii_digit); |
16383 | 0 | std::string_view digits_to_parse = |
16384 | 0 | std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); |
16385 | | |
16386 | | // Here we have a range of ASCII digit characters identified by |
16387 | | // digits_to_parse. It is non-empty. The port state of the URL parser reads |
16388 | | // it as an integer, so leading zeros are part of the number: "0080" is 80 |
16389 | | // and "065535" is 65535, not a six-digit overflow. Only the significant |
16390 | | // digits count toward the 5-digit maximum, matching the fast path in |
16391 | | // implementation.cpp. |
16392 | 0 | size_t first_significant = digits_to_parse.find_first_not_of('0'); |
16393 | 0 | if (first_significant == std::string_view::npos) { |
16394 | | // The value is all zeros, i.e. port 0. |
16395 | 0 | return "0"; |
16396 | 0 | } |
16397 | 0 | digits_to_parse.remove_prefix(first_significant); |
16398 | | // We want to determine whether it is a valid port number (0-65535). |
16399 | | // Clearly, if the length is greater than 5, it is invalid. |
16400 | | // If the length is 5, we need to compare lexicographically to "65535". |
16401 | | // Otherwise it is valid. |
16402 | 0 | if (digits_to_parse.size() == 5) { |
16403 | 0 | if (digits_to_parse > "65535") { |
16404 | 0 | return tl::unexpected(errors::type_error); |
16405 | 0 | } |
16406 | 0 | } else if (digits_to_parse.size() > 5) { |
16407 | 0 | return tl::unexpected(errors::type_error); |
16408 | 0 | } |
16409 | | // It is valid! Most times, we do not need to parse it into an integer. |
16410 | 0 | return std::string(digits_to_parse); |
16411 | 0 | } |
16412 | | |
16413 | | tl::expected<std::string, errors> canonicalize_port_with_protocol( |
16414 | 0 | std::string_view port_value, std::string_view protocol) { |
16415 | | // If portValue is the empty string, return portValue. |
16416 | 0 | if (port_value.empty()) [[unlikely]] { |
16417 | 0 | return ""; |
16418 | 0 | } |
16419 | | |
16420 | | // Handle empty or trailing colon in protocol |
16421 | 0 | if (protocol.empty()) { |
16422 | 0 | protocol = "fake"; |
16423 | 0 | } else if (protocol.ends_with(":")) { |
16424 | 0 | protocol.remove_suffix(1); |
16425 | 0 | } |
16426 | | |
16427 | | // Remove ASCII tab or newline characters |
16428 | 0 | std::string trimmed(port_value); |
16429 | 0 | helpers::remove_ascii_tab_or_newline(trimmed); |
16430 | |
|
16431 | 0 | if (trimmed.empty()) { |
16432 | 0 | return ""; |
16433 | 0 | } |
16434 | | |
16435 | | // Input should start with a digit character |
16436 | 0 | if (!unicode::is_ascii_digit(trimmed.front())) { |
16437 | 0 | return tl::unexpected(errors::type_error); |
16438 | 0 | } |
16439 | | |
16440 | | // Find the first non-digit character |
16441 | 0 | auto first_non_digit = |
16442 | 0 | std::ranges::find_if_not(trimmed, unicode::is_ascii_digit); |
16443 | 0 | std::string_view digits_to_parse = |
16444 | 0 | std::string_view(trimmed.data(), first_non_digit - trimmed.begin()); |
16445 | | |
16446 | | // Parse the port number |
16447 | 0 | uint16_t parsed_port{}; |
16448 | | // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage) |
16449 | 0 | auto result = std::from_chars(digits_to_parse.data(), |
16450 | 0 | digits_to_parse.data() + digits_to_parse.size(), |
16451 | 0 | parsed_port); |
16452 | |
|
16453 | 0 | if (result.ec == std::errc::result_out_of_range) { |
16454 | 0 | return tl::unexpected(errors::type_error); |
16455 | 0 | } |
16456 | | |
16457 | 0 | if (result.ec == std::errc()) { |
16458 | | // Check if this is the default port for the scheme |
16459 | 0 | uint16_t default_port = scheme::get_special_port(protocol); |
16460 | | |
16461 | | // If it's the default port for a special scheme, return empty string |
16462 | 0 | if (default_port != 0 && default_port == parsed_port) { |
16463 | 0 | return ""; |
16464 | 0 | } |
16465 | | |
16466 | | // Successfully parsed, return as string |
16467 | 0 | return std::to_string(parsed_port); |
16468 | 0 | } |
16469 | | |
16470 | 0 | return tl::unexpected(errors::type_error); |
16471 | 0 | } |
16472 | | |
16473 | | tl::expected<std::string, errors> canonicalize_pathname( |
16474 | 0 | std::string_view input) { |
16475 | 0 | if (input.empty()) [[unlikely]] { |
16476 | 0 | return ""; |
16477 | 0 | } |
16478 | | |
16479 | | // Fast path: simple pathnames (no . which needs normalization) can be |
16480 | | // returned as-is |
16481 | 0 | bool needs_processing = false; |
16482 | 0 | for (char c : input) { |
16483 | 0 | needs_processing |= |
16484 | 0 | !(char_class_table[static_cast<uint8_t>(c)] & CHAR_SIMPLE_PATHNAME); |
16485 | 0 | } |
16486 | 0 | if (!needs_processing) { |
16487 | 0 | return std::string(input); |
16488 | 0 | } |
16489 | | |
16490 | | // Let leading slash be true if the first code point in value is U+002F (/) |
16491 | | // and otherwise false. |
16492 | 0 | const bool leading_slash = input.starts_with("/"); |
16493 | | // Let modified value be "/-" if leading slash is false and otherwise the |
16494 | | // empty string. |
16495 | 0 | const auto modified_value = |
16496 | 0 | (leading_slash ? std::string() : std::string("/-")) + std::string(input); |
16497 | | // The spec runs the basic URL parser with the path in state override, where |
16498 | | // '?' and '#' are ordinary path code points (percent-encoded) and leading or |
16499 | | // trailing C0 control or space is kept. Building a full URL string and |
16500 | | // parsing it (no state override) instead let '?' and '#' start the |
16501 | | // query/fragment, so the pathname was silently truncated at the first literal |
16502 | | // '?' or '#'. set_pathname runs the parser in path state override, matching |
16503 | | // how canonicalize_hostname uses set_hostname. |
16504 | | // The spec's "create a dummy URL" is "https://dummy.invalid/": a special |
16505 | | // URL, so the path parser turns "\\" into "/" as it does in a special URL. |
16506 | | // A non-special dummy kept a literal backslash, so a pattern such as |
16507 | | // "/a\\b" never matched "https://h/a/b". |
16508 | 0 | auto url = ada::parse<url_aggregator>("https://dummy.invalid/", nullptr); |
16509 | 0 | ADA_ASSERT_TRUE(url); |
16510 | 0 | if (!url->set_pathname(modified_value)) { |
16511 | | // If parseResult is failure, then throw a TypeError. |
16512 | 0 | return tl::unexpected(errors::type_error); |
16513 | 0 | } |
16514 | 0 | const auto pathname = url->get_pathname(); |
16515 | | // If leading slash is false, then set result to the code point substring |
16516 | | // from 2 to the end of the string within result. |
16517 | 0 | if (!leading_slash) { |
16518 | | // pathname should start with "/-" but path traversal (e.g. "../../") |
16519 | | // can reduce it to just "/" which is shorter than 2 characters. |
16520 | 0 | if (pathname.size() < 2) { |
16521 | 0 | return tl::unexpected(errors::type_error); |
16522 | 0 | } |
16523 | 0 | return std::string(pathname.substr(2)); |
16524 | 0 | } |
16525 | 0 | return std::string(pathname); |
16526 | 0 | } |
16527 | | |
16528 | | tl::expected<std::string, errors> canonicalize_opaque_pathname( |
16529 | 0 | std::string_view input) { |
16530 | | // If value is the empty string, return value. |
16531 | 0 | if (input.empty()) [[unlikely]] { |
16532 | 0 | return ""; |
16533 | 0 | } |
16534 | | // Let dummyURL be a new URL record. |
16535 | | // Set dummyURL's path to the empty string. |
16536 | | // Let parseResult be the result of running URL parsing given value with |
16537 | | // dummyURL as url and opaque path state as state override. |
16538 | 0 | if (auto url = |
16539 | 0 | ada::parse<url_aggregator>("fake:" + std::string(input), nullptr)) { |
16540 | | // Return the result of URL path serializing dummyURL. |
16541 | 0 | return std::string(url->get_pathname()); |
16542 | 0 | } |
16543 | | // If parseResult is failure, then throw a TypeError. |
16544 | 0 | return tl::unexpected(errors::type_error); |
16545 | 0 | } |
16546 | | |
16547 | 0 | tl::expected<std::string, errors> canonicalize_search(std::string_view input) { |
16548 | | // If value is the empty string, return value. |
16549 | 0 | if (input.empty()) [[unlikely]] { |
16550 | 0 | return ""; |
16551 | 0 | } |
16552 | | // A leading '?' is a valid query code point here: it is the caller (process a |
16553 | | // search) that removes a single delimiter, not this step, which mirrors the |
16554 | | // basic URL parser's query state. |
16555 | 0 | std::string new_value(input); |
16556 | | // Remove ASCII tab or newline characters |
16557 | 0 | helpers::remove_ascii_tab_or_newline(new_value); |
16558 | |
|
16559 | 0 | if (new_value.empty()) { |
16560 | 0 | return ""; |
16561 | 0 | } |
16562 | | |
16563 | | // Percent-encode using QUERY_PERCENT_ENCODE (for non-special URLs) |
16564 | | // Note: "fake://dummy.test" is not a special URL, so we use |
16565 | | // QUERY_PERCENT_ENCODE |
16566 | 0 | size_t idx = ada::unicode::percent_encode_index( |
16567 | 0 | new_value, character_sets::QUERY_PERCENT_ENCODE); |
16568 | 0 | if (idx == new_value.size()) { |
16569 | | // No encoding needed |
16570 | 0 | return new_value; |
16571 | 0 | } |
16572 | | // Percent-encode from the first character that needs encoding |
16573 | 0 | return ada::unicode::percent_encode( |
16574 | 0 | new_value, character_sets::QUERY_PERCENT_ENCODE, idx); |
16575 | 0 | } |
16576 | | |
16577 | 0 | tl::expected<std::string, errors> canonicalize_hash(std::string_view input) { |
16578 | | // If value is the empty string, return value. |
16579 | 0 | if (input.empty()) [[unlikely]] { |
16580 | 0 | return ""; |
16581 | 0 | } |
16582 | | // A leading '#' is a valid fragment code point here: it is the caller |
16583 | | // (process a hash) that removes a single delimiter, not this step, which |
16584 | | // mirrors the basic URL parser's fragment state. |
16585 | 0 | std::string new_value(input); |
16586 | | // Remove ASCII tab or newline characters |
16587 | 0 | helpers::remove_ascii_tab_or_newline(new_value); |
16588 | |
|
16589 | 0 | if (new_value.empty()) { |
16590 | 0 | return ""; |
16591 | 0 | } |
16592 | | |
16593 | | // Percent-encode using FRAGMENT_PERCENT_ENCODE |
16594 | 0 | size_t idx = ada::unicode::percent_encode_index( |
16595 | 0 | new_value, character_sets::FRAGMENT_PERCENT_ENCODE); |
16596 | 0 | if (idx == new_value.size()) { |
16597 | | // No encoding needed |
16598 | 0 | return new_value; |
16599 | 0 | } |
16600 | | // Percent-encode from the first character that needs encoding |
16601 | 0 | return ada::unicode::percent_encode( |
16602 | 0 | new_value, character_sets::FRAGMENT_PERCENT_ENCODE, idx); |
16603 | 0 | } |
16604 | | |
16605 | | tl::expected<std::vector<token>, errors> tokenize(std::string_view input, |
16606 | 0 | token_policy policy) { |
16607 | 0 | ada_log("tokenize input: ", input); |
16608 | | // Let tokenizer be a new tokenizer. |
16609 | | // Set tokenizer's input to input. |
16610 | | // Set tokenizer's policy to policy. |
16611 | 0 | auto tokenizer = Tokenizer(input, policy); |
16612 | | // While tokenizer's index is less than tokenizer's input's code point length: |
16613 | 0 | while (tokenizer.index < tokenizer.input.size()) { |
16614 | | // Run seek and get the next code point given tokenizer and tokenizer's |
16615 | | // index. |
16616 | 0 | tokenizer.seek_and_get_next_code_point(tokenizer.index); |
16617 | | |
16618 | | // Malformed UTF-8 must not stall tokenization: report an invalid-char |
16619 | | // token (lenient) or fail fast (strict), while always making progress. |
16620 | 0 | if (tokenizer.had_invalid_code_point()) { |
16621 | 0 | if (auto error = tokenizer.process_tokenizing_error(tokenizer.next_index, |
16622 | 0 | tokenizer.index)) { |
16623 | 0 | return tl::unexpected(*error); |
16624 | 0 | } |
16625 | 0 | continue; |
16626 | 0 | } |
16627 | | |
16628 | | // If tokenizer's code point is U+002A (*): |
16629 | 0 | if (tokenizer.code_point == '*') { |
16630 | | // Run add a token with default position and length given tokenizer and |
16631 | | // "asterisk". |
16632 | 0 | tokenizer.add_token_with_defaults(token_type::ASTERISK); |
16633 | 0 | ada_log("add ASTERISK token"); |
16634 | | // Continue. |
16635 | 0 | continue; |
16636 | 0 | } |
16637 | | |
16638 | | // If tokenizer's code point is U+002B (+) or U+003F (?): |
16639 | 0 | if (tokenizer.code_point == '+' || tokenizer.code_point == '?') { |
16640 | | // Run add a token with default position and length given tokenizer and |
16641 | | // "other-modifier". |
16642 | 0 | tokenizer.add_token_with_defaults(token_type::OTHER_MODIFIER); |
16643 | | // Continue. |
16644 | 0 | continue; |
16645 | 0 | } |
16646 | | |
16647 | | // If tokenizer's code point is U+005C (\): |
16648 | 0 | if (tokenizer.code_point == '\\') { |
16649 | | // If tokenizer's index is equal to tokenizer's input's code point length |
16650 | | // - 1: |
16651 | 0 | if (tokenizer.index == tokenizer.input.size() - 1) { |
16652 | | // Run process a tokenizing error given tokenizer, tokenizer's next |
16653 | | // index, and tokenizer's index. |
16654 | 0 | if (auto error = tokenizer.process_tokenizing_error( |
16655 | 0 | tokenizer.next_index, tokenizer.index)) { |
16656 | 0 | ada_log("process_tokenizing_error failed"); |
16657 | 0 | return tl::unexpected(*error); |
16658 | 0 | } |
16659 | 0 | continue; |
16660 | 0 | } |
16661 | | |
16662 | | // Let escaped index be tokenizer's next index. |
16663 | 0 | auto escaped_index = tokenizer.next_index; |
16664 | | // Run get the next code point given tokenizer. |
16665 | 0 | tokenizer.get_next_code_point(); |
16666 | 0 | if (tokenizer.had_invalid_code_point()) { |
16667 | 0 | if (auto error = tokenizer.process_tokenizing_error( |
16668 | 0 | tokenizer.next_index, escaped_index)) { |
16669 | 0 | return tl::unexpected(*error); |
16670 | 0 | } |
16671 | 0 | continue; |
16672 | 0 | } |
16673 | | // Run add a token with default length given tokenizer, "escaped-char", |
16674 | | // tokenizer's next index, and escaped index. |
16675 | 0 | tokenizer.add_token_with_default_length( |
16676 | 0 | token_type::ESCAPED_CHAR, tokenizer.next_index, escaped_index); |
16677 | 0 | ada_log("add ESCAPED_CHAR token on next_index ", tokenizer.next_index, |
16678 | 0 | " with escaped index ", escaped_index); |
16679 | | // Continue. |
16680 | 0 | continue; |
16681 | 0 | } |
16682 | | |
16683 | | // If tokenizer's code point is U+007B ({): |
16684 | 0 | if (tokenizer.code_point == '{') { |
16685 | | // Run add a token with default position and length given tokenizer and |
16686 | | // "open". |
16687 | 0 | tokenizer.add_token_with_defaults(token_type::OPEN); |
16688 | 0 | ada_log("add OPEN token"); |
16689 | 0 | continue; |
16690 | 0 | } |
16691 | | |
16692 | | // If tokenizer's code point is U+007D (}): |
16693 | 0 | if (tokenizer.code_point == '}') { |
16694 | | // Run add a token with default position and length given tokenizer and |
16695 | | // "close". |
16696 | 0 | tokenizer.add_token_with_defaults(token_type::CLOSE); |
16697 | 0 | ada_log("add CLOSE token"); |
16698 | 0 | continue; |
16699 | 0 | } |
16700 | | |
16701 | | // If tokenizer's code point is U+003A (:): |
16702 | 0 | if (tokenizer.code_point == ':') { |
16703 | | // Let name position be tokenizer's next index. |
16704 | 0 | auto name_position = tokenizer.next_index; |
16705 | | // Let name start be name position. |
16706 | 0 | auto name_start = name_position; |
16707 | 0 | bool invalid_name = false; |
16708 | | // While name position is less than tokenizer's input's code point length: |
16709 | 0 | while (name_position < tokenizer.input.size()) { |
16710 | | // Run seek and get the next code point given tokenizer and name |
16711 | | // position. |
16712 | 0 | tokenizer.seek_and_get_next_code_point(name_position); |
16713 | 0 | if (tokenizer.had_invalid_code_point()) { |
16714 | 0 | if (auto error = tokenizer.process_tokenizing_error( |
16715 | 0 | tokenizer.next_index, name_position)) { |
16716 | 0 | return tl::unexpected(*error); |
16717 | 0 | } |
16718 | 0 | invalid_name = true; |
16719 | 0 | break; |
16720 | 0 | } |
16721 | | // Let first code point be true if name position equals name start and |
16722 | | // false otherwise. |
16723 | 0 | bool first_code_point = name_position == name_start; |
16724 | | // Let valid code point be the result of running is a valid name code |
16725 | | // point given tokenizer's code point and first code point. |
16726 | 0 | auto valid_code_point = |
16727 | 0 | idna::valid_name_code_point(tokenizer.code_point, first_code_point); |
16728 | 0 | ada_log("tokenizer.code_point=", uint32_t(tokenizer.code_point), |
16729 | 0 | " first_code_point=", first_code_point, |
16730 | 0 | " valid_code_point=", valid_code_point); |
16731 | | // If valid code point is false break. |
16732 | 0 | if (!valid_code_point) break; |
16733 | | // Set name position to tokenizer's next index. |
16734 | 0 | name_position = tokenizer.next_index; |
16735 | 0 | } |
16736 | | |
16737 | 0 | if (invalid_name) { |
16738 | 0 | continue; |
16739 | 0 | } |
16740 | | |
16741 | | // If name position is less than or equal to name start: |
16742 | 0 | if (name_position <= name_start) { |
16743 | | // Run process a tokenizing error given tokenizer, name start, and |
16744 | | // tokenizer's index. |
16745 | 0 | if (auto error = tokenizer.process_tokenizing_error(name_start, |
16746 | 0 | tokenizer.index)) { |
16747 | 0 | ada_log("process_tokenizing_error failed"); |
16748 | 0 | return tl::unexpected(*error); |
16749 | 0 | } |
16750 | | // Continue |
16751 | 0 | continue; |
16752 | 0 | } |
16753 | | |
16754 | | // Run add a token with default length given tokenizer, "name", name |
16755 | | // position, and name start. |
16756 | 0 | tokenizer.add_token_with_default_length(token_type::NAME, name_position, |
16757 | 0 | name_start); |
16758 | 0 | continue; |
16759 | 0 | } |
16760 | | |
16761 | | // If tokenizer's code point is U+0028 ((): |
16762 | 0 | if (tokenizer.code_point == '(') { |
16763 | | // Let depth be 1. |
16764 | 0 | size_t depth = 1; |
16765 | | // Let regexp position be tokenizer's next index. |
16766 | 0 | auto regexp_position = tokenizer.next_index; |
16767 | | // Let regexp start be regexp position. |
16768 | 0 | auto regexp_start = regexp_position; |
16769 | | // Let error be false. |
16770 | 0 | bool error = false; |
16771 | | |
16772 | | // While regexp position is less than tokenizer's input's code point |
16773 | | // length: |
16774 | 0 | while (regexp_position < tokenizer.input.size()) { |
16775 | | // Run seek and get the next code point given tokenizer and regexp |
16776 | | // position. |
16777 | 0 | tokenizer.seek_and_get_next_code_point(regexp_position); |
16778 | 0 | if (tokenizer.had_invalid_code_point()) { |
16779 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16780 | 0 | tokenizer.next_index, regexp_position)) { |
16781 | 0 | return tl::unexpected(*process_error); |
16782 | 0 | } |
16783 | 0 | error = true; |
16784 | 0 | break; |
16785 | 0 | } |
16786 | | |
16787 | | // TODO: Optimization opportunity: The next 2 if statements can be |
16788 | | // merged. If the result of running is ASCII given tokenizer's code |
16789 | | // point is false: |
16790 | 0 | if (!unicode::is_ascii(tokenizer.code_point)) { |
16791 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16792 | | // tokenizer's index. |
16793 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16794 | 0 | regexp_start, tokenizer.index)) { |
16795 | 0 | return tl::unexpected(*process_error); |
16796 | 0 | } |
16797 | | // Set error to true. |
16798 | 0 | error = true; |
16799 | 0 | break; |
16800 | 0 | } |
16801 | | |
16802 | | // If regexp position equals regexp start and tokenizer's code point is |
16803 | | // U+003F (?): |
16804 | 0 | if (regexp_position == regexp_start && tokenizer.code_point == '?') { |
16805 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16806 | | // tokenizer's index. |
16807 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16808 | 0 | regexp_start, tokenizer.index)) { |
16809 | 0 | return tl::unexpected(*process_error); |
16810 | 0 | } |
16811 | | // Set error to true; |
16812 | 0 | error = true; |
16813 | 0 | break; |
16814 | 0 | } |
16815 | | |
16816 | | // If tokenizer's code point is U+005C (\): |
16817 | 0 | if (tokenizer.code_point == '\\') { |
16818 | | // If regexp position equals tokenizer's input's code point length - 1 |
16819 | 0 | if (regexp_position == tokenizer.input.size() - 1) { |
16820 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16821 | | // tokenizer's index. |
16822 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16823 | 0 | regexp_start, tokenizer.index)) { |
16824 | 0 | return tl::unexpected(*process_error); |
16825 | 0 | } |
16826 | | // Set error to true. |
16827 | 0 | error = true; |
16828 | 0 | break; |
16829 | 0 | } |
16830 | | // Run get the next code point given tokenizer. |
16831 | 0 | auto escaped_index = tokenizer.next_index; |
16832 | 0 | tokenizer.get_next_code_point(); |
16833 | 0 | if (tokenizer.had_invalid_code_point()) { |
16834 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16835 | 0 | tokenizer.next_index, escaped_index)) { |
16836 | 0 | return tl::unexpected(*process_error); |
16837 | 0 | } |
16838 | 0 | error = true; |
16839 | 0 | break; |
16840 | 0 | } |
16841 | | // If the result of running is ASCII given tokenizer's code point is |
16842 | | // false: |
16843 | 0 | if (!unicode::is_ascii(tokenizer.code_point)) { |
16844 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16845 | | // tokenizer's index. |
16846 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16847 | 0 | regexp_start, tokenizer.index); |
16848 | 0 | process_error.has_value()) { |
16849 | 0 | return tl::unexpected(*process_error); |
16850 | 0 | } |
16851 | | // Set error to true. |
16852 | 0 | error = true; |
16853 | 0 | break; |
16854 | 0 | } |
16855 | | // Set regexp position to tokenizer's next index. |
16856 | 0 | regexp_position = tokenizer.next_index; |
16857 | 0 | continue; |
16858 | 0 | } |
16859 | | |
16860 | | // If tokenizer's code point is U+0029 ()): |
16861 | 0 | if (tokenizer.code_point == ')') { |
16862 | | // Decrement depth by 1. |
16863 | 0 | depth--; |
16864 | | // If depth is 0: |
16865 | 0 | if (depth == 0) { |
16866 | | // Set regexp position to tokenizer's next index. |
16867 | 0 | regexp_position = tokenizer.next_index; |
16868 | | // Break. |
16869 | 0 | break; |
16870 | 0 | } |
16871 | 0 | } else if (tokenizer.code_point == '(') { |
16872 | | // Otherwise if tokenizer's code point is U+0028 ((): |
16873 | | // Increment depth by 1. |
16874 | 0 | depth++; |
16875 | | // If regexp position equals tokenizer's input's code point length - |
16876 | | // 1: |
16877 | 0 | if (regexp_position == tokenizer.input.size() - 1) { |
16878 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16879 | | // tokenizer's index. |
16880 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16881 | 0 | regexp_start, tokenizer.index)) { |
16882 | 0 | return tl::unexpected(*process_error); |
16883 | 0 | } |
16884 | | // Set error to true. |
16885 | 0 | error = true; |
16886 | 0 | break; |
16887 | 0 | } |
16888 | | // Let temporary position be tokenizer's next index. |
16889 | 0 | auto temporary_position = tokenizer.next_index; |
16890 | | // Run get the next code point given tokenizer. |
16891 | 0 | tokenizer.get_next_code_point(); |
16892 | 0 | if (tokenizer.had_invalid_code_point()) { |
16893 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16894 | 0 | tokenizer.next_index, temporary_position)) { |
16895 | 0 | return tl::unexpected(*process_error); |
16896 | 0 | } |
16897 | 0 | error = true; |
16898 | 0 | break; |
16899 | 0 | } |
16900 | | // If tokenizer's code point is not U+003F (?): |
16901 | 0 | if (tokenizer.code_point != '?') { |
16902 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16903 | | // tokenizer's index. |
16904 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16905 | 0 | regexp_start, tokenizer.index)) { |
16906 | 0 | return tl::unexpected(*process_error); |
16907 | 0 | } |
16908 | | // Set error to true. |
16909 | 0 | error = true; |
16910 | 0 | break; |
16911 | 0 | } |
16912 | | // Set tokenizer's next index to temporary position. |
16913 | 0 | tokenizer.next_index = temporary_position; |
16914 | 0 | } |
16915 | | // Set regexp position to tokenizer's next index. |
16916 | 0 | regexp_position = tokenizer.next_index; |
16917 | 0 | } |
16918 | | |
16919 | | // If error is true continue. |
16920 | 0 | if (error) continue; |
16921 | | // If depth is not zero: |
16922 | 0 | if (depth != 0) { |
16923 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16924 | | // tokenizer's index. |
16925 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16926 | 0 | regexp_start, tokenizer.index)) { |
16927 | 0 | return tl::unexpected(*process_error); |
16928 | 0 | } |
16929 | 0 | continue; |
16930 | 0 | } |
16931 | | // Let regexp length be regexp position - regexp start - 1. |
16932 | 0 | auto regexp_length = regexp_position - regexp_start - 1; |
16933 | | // If regexp length is zero: |
16934 | 0 | if (regexp_length == 0) { |
16935 | | // Run process a tokenizing error given tokenizer, regexp start, and |
16936 | | // tokenizer's index. |
16937 | 0 | if (auto process_error = tokenizer.process_tokenizing_error( |
16938 | 0 | regexp_start, tokenizer.index)) { |
16939 | 0 | ada_log("process_tokenizing_error failed"); |
16940 | 0 | return tl::unexpected(*process_error); |
16941 | 0 | } |
16942 | 0 | continue; |
16943 | 0 | } |
16944 | | // Run add a token given tokenizer, "regexp", regexp position, regexp |
16945 | | // start, and regexp length. |
16946 | 0 | tokenizer.add_token(token_type::REGEXP, regexp_position, regexp_start, |
16947 | 0 | regexp_length); |
16948 | 0 | continue; |
16949 | 0 | } |
16950 | | // Run add a token with default position and length given tokenizer and |
16951 | | // "char". |
16952 | 0 | tokenizer.add_token_with_defaults(token_type::CHAR); |
16953 | 0 | } |
16954 | | // Run add a token with default length given tokenizer, "end", tokenizer's |
16955 | | // index, and tokenizer's index. |
16956 | 0 | tokenizer.add_token_with_default_length(token_type::END, tokenizer.index, |
16957 | 0 | tokenizer.index); |
16958 | |
|
16959 | 0 | ada_log("tokenizer.token_list size is: ", tokenizer.token_list.size()); |
16960 | | // Return tokenizer's token list. |
16961 | 0 | return tokenizer.token_list; |
16962 | 0 | } |
16963 | | |
16964 | | namespace { |
16965 | | constexpr std::array<uint8_t, 256> escape_pattern_table = []() consteval { |
16966 | | std::array<uint8_t, 256> out{}; |
16967 | | for (auto& c : {'+', '*', '?', ':', '{', '}', '(', ')', '\\'}) { |
16968 | | out[c] = 1; |
16969 | | } |
16970 | | return out; |
16971 | | }(); |
16972 | | |
16973 | 0 | constexpr bool should_escape_pattern_char(char c) { |
16974 | 0 | return escape_pattern_table[static_cast<uint8_t>(c)]; |
16975 | 0 | } |
16976 | | } // namespace |
16977 | | |
16978 | 0 | std::string escape_pattern_string(std::string_view input) { |
16979 | 0 | ada_log("escape_pattern_string called with input=", input); |
16980 | 0 | if (input.empty()) [[unlikely]] { |
16981 | 0 | return ""; |
16982 | 0 | } |
16983 | | // Assert: input is an ASCII string. |
16984 | 0 | ADA_ASSERT_TRUE(ada::idna::is_ascii(input)); |
16985 | | // Let result be the empty string. |
16986 | 0 | std::string result{}; |
16987 | | // Reserve extra space for potential escapes |
16988 | 0 | result.reserve(input.size() * 2); |
16989 | | |
16990 | | // While index is less than input's length: |
16991 | 0 | for (const char c : input) { |
16992 | 0 | if (should_escape_pattern_char(c)) { |
16993 | | // Append U+005C (\) to the end of result. |
16994 | 0 | result.push_back('\\'); |
16995 | 0 | } |
16996 | | // Append c to the end of result. |
16997 | 0 | result.push_back(c); |
16998 | 0 | } |
16999 | | // Return result. |
17000 | 0 | return result; |
17001 | 0 | } |
17002 | | |
17003 | | namespace { |
17004 | | constexpr std::array<uint8_t, 256> escape_regexp_table = []() consteval { |
17005 | | std::array<uint8_t, 256> out{}; |
17006 | | for (auto& c : {'.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '[', ']', |
17007 | | '|', '/', '\\'}) { |
17008 | | out[c] = 1; |
17009 | | } |
17010 | | return out; |
17011 | | }(); |
17012 | | |
17013 | 0 | constexpr bool should_escape_regexp_char(char c) { |
17014 | 0 | return escape_regexp_table[(uint8_t)c]; |
17015 | 0 | } |
17016 | | } // namespace |
17017 | | |
17018 | 0 | std::string escape_regexp_string(std::string_view input) { |
17019 | | // Assert: input is an ASCII string. |
17020 | 0 | ADA_ASSERT_TRUE(idna::is_ascii(input)); |
17021 | | // Let result be the empty string. |
17022 | 0 | std::string result{}; |
17023 | | // Reserve extra space for potential escapes (worst case: all chars escaped) |
17024 | 0 | result.reserve(input.size() * 2); |
17025 | 0 | for (const char c : input) { |
17026 | 0 | if (should_escape_regexp_char(c)) { |
17027 | | // Avoid temporary string allocation - directly append characters |
17028 | 0 | result.push_back('\\'); |
17029 | 0 | result.push_back(c); |
17030 | 0 | } else { |
17031 | 0 | result.push_back(c); |
17032 | 0 | } |
17033 | 0 | } |
17034 | 0 | return result; |
17035 | 0 | } |
17036 | | |
17037 | | std::string process_base_url_string(std::string_view input, |
17038 | 0 | url_pattern_init::process_type type) { |
17039 | | // If type is not "pattern" return input. |
17040 | 0 | if (type != url_pattern_init::process_type::pattern) { |
17041 | 0 | return std::string(input); |
17042 | 0 | } |
17043 | | // Return the result of escaping a pattern string given input. |
17044 | 0 | return escape_pattern_string(input); |
17045 | 0 | } |
17046 | | |
17047 | | constexpr bool is_absolute_pathname( |
17048 | 0 | std::string_view input, url_pattern_init::process_type type) noexcept { |
17049 | | // If input is the empty string, then return false. |
17050 | 0 | if (input.empty()) [[unlikely]] { |
17051 | 0 | return false; |
17052 | 0 | } |
17053 | | // If input[0] is U+002F (/), then return true. |
17054 | 0 | if (input.starts_with("/")) return true; |
17055 | | // If type is "url", then return false. |
17056 | 0 | if (type == url_pattern_init::process_type::url) return false; |
17057 | | // If input's code point length is less than 2, then return false. |
17058 | 0 | if (input.size() < 2) return false; |
17059 | | // If input[0] is U+005C (\) and input[1] is U+002F (/), then return true. |
17060 | | // If input[0] is U+007B ({) and input[1] is U+002F (/), then return true. |
17061 | | // Return false. |
17062 | 0 | return input[1] == '/' && (input[0] == '\\' || input[0] == '{'); |
17063 | 0 | } |
17064 | | |
17065 | | std::string generate_pattern_string( |
17066 | | std::vector<url_pattern_part>& part_list, |
17067 | 0 | url_pattern_compile_component_options& options) { |
17068 | | // Let result be the empty string. |
17069 | 0 | std::string result{}; |
17070 | | // Let index list be the result of getting the indices for part list. |
17071 | | // For each index of index list: |
17072 | 0 | for (size_t index = 0; index < part_list.size(); index++) { |
17073 | | // Let part be part list[index]. |
17074 | | // Use reference to avoid copy |
17075 | 0 | const auto& part = part_list[index]; |
17076 | | // Let previous part be part list[index - 1] if index is greater than 0, |
17077 | | // otherwise let it be null. |
17078 | | // Use pointer to avoid copy |
17079 | 0 | const url_pattern_part* previous_part = |
17080 | 0 | index == 0 ? nullptr : &part_list[index - 1]; |
17081 | | // Let next part be part list[index + 1] if index is less than index list's |
17082 | | // size - 1, otherwise let it be null. |
17083 | 0 | const url_pattern_part* next_part = |
17084 | 0 | index < part_list.size() - 1 ? &part_list[index + 1] : nullptr; |
17085 | | // If part's type is "fixed-text" then: |
17086 | 0 | if (part.type == url_pattern_part_type::FIXED_TEXT) { |
17087 | | // If part's modifier is "none" then: |
17088 | 0 | if (part.modifier == url_pattern_part_modifier::none) { |
17089 | | // Append the result of running escape a pattern string given part's |
17090 | | // value to the end of result. |
17091 | 0 | result.append(escape_pattern_string(part.value)); |
17092 | 0 | continue; |
17093 | 0 | } |
17094 | | // Append "{" to the end of result. |
17095 | 0 | result += "{"; |
17096 | | // Append the result of running escape a pattern string given part's value |
17097 | | // to the end of result. |
17098 | 0 | result.append(escape_pattern_string(part.value)); |
17099 | | // Append "}" to the end of result. |
17100 | 0 | result += "}"; |
17101 | | // Append the result of running convert a modifier to a string given |
17102 | | // part's modifier to the end of result. |
17103 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
17104 | 0 | continue; |
17105 | 0 | } |
17106 | | // Let custom name be true if part's name[0] is not an ASCII digit; |
17107 | | // otherwise false. |
17108 | 0 | bool custom_name = !unicode::is_ascii_digit(part.name[0]); |
17109 | | // Let needs grouping be true if at least one of the following are true, |
17110 | | // otherwise let it be false: |
17111 | | // - part's suffix is not the empty string. |
17112 | | // - part's prefix is not the empty string and is not options's prefix code |
17113 | | // point. |
17114 | | // This compares the whole prefix: a prefix such as "/9" starts with the |
17115 | | // prefix code point but is not it, and still needs grouping. |
17116 | 0 | bool needs_grouping = |
17117 | 0 | !part.suffix.empty() || |
17118 | 0 | (!part.prefix.empty() && part.prefix != options.get_prefix()); |
17119 | | |
17120 | | // If all of the following are true: |
17121 | | // - needs grouping is false; and |
17122 | | // - custom name is true; and |
17123 | | // - part's type is "segment-wildcard"; and |
17124 | | // - part's modifier is "none"; and |
17125 | | // - next part is not null; and |
17126 | | // - next part's prefix is the empty string; and |
17127 | | // - next part's suffix is the empty string |
17128 | 0 | if (!needs_grouping && custom_name && |
17129 | 0 | part.type == url_pattern_part_type::SEGMENT_WILDCARD && |
17130 | 0 | part.modifier == url_pattern_part_modifier::none && next_part && |
17131 | 0 | next_part->prefix.empty() && next_part->suffix.empty()) { |
17132 | | // If next part's type is "fixed-text": |
17133 | 0 | if (next_part->type == url_pattern_part_type::FIXED_TEXT) { |
17134 | | // Set needs grouping to true if the result of running is a valid name |
17135 | | // code point given next part's value's first code point and the boolean |
17136 | | // false is true. |
17137 | 0 | if (idna::valid_name_code_point(next_part->value[0], false)) { |
17138 | 0 | needs_grouping = true; |
17139 | 0 | } |
17140 | 0 | } else { |
17141 | | // Set needs grouping to true if next part's name[0] is an ASCII digit. |
17142 | 0 | needs_grouping = !next_part->name.empty() && |
17143 | 0 | unicode::is_ascii_digit(next_part->name[0]); |
17144 | 0 | } |
17145 | 0 | } |
17146 | | |
17147 | | // If all of the following are true: |
17148 | | // - needs grouping is false; and |
17149 | | // - part's prefix is the empty string; and |
17150 | | // - previous part is not null; and |
17151 | | // - previous part's type is "fixed-text"; and |
17152 | | // - previous part's value's last code point is options's prefix code point. |
17153 | | // then set needs grouping to true. |
17154 | 0 | if (!needs_grouping && part.prefix.empty() && previous_part && |
17155 | 0 | previous_part->type == url_pattern_part_type::FIXED_TEXT && |
17156 | 0 | !previous_part->value.empty() && !options.get_prefix().empty() && |
17157 | 0 | previous_part->value.back() == options.get_prefix()[0]) { |
17158 | 0 | needs_grouping = true; |
17159 | 0 | } |
17160 | | |
17161 | | // Assert: part's name is not the empty string or null. |
17162 | 0 | ADA_ASSERT_TRUE(!part.name.empty()); |
17163 | | |
17164 | | // If needs grouping is true, then append "{" to the end of result. |
17165 | 0 | if (needs_grouping) { |
17166 | 0 | result.append("{"); |
17167 | 0 | } |
17168 | | |
17169 | | // Append the result of running escape a pattern string given part's prefix |
17170 | | // to the end of result. |
17171 | 0 | result.append(escape_pattern_string(part.prefix)); |
17172 | | |
17173 | | // If custom name is true: |
17174 | 0 | if (custom_name) { |
17175 | | // Append ":" to the end of result. |
17176 | 0 | result.append(":"); |
17177 | | // Append part's name to the end of result. |
17178 | 0 | result.append(part.name); |
17179 | 0 | } |
17180 | | |
17181 | | // If part's type is "regexp" then: |
17182 | 0 | if (part.type == url_pattern_part_type::REGEXP) { |
17183 | | // Append "(" to the end of result. |
17184 | 0 | result.append("("); |
17185 | | // Append part's value to the end of result. |
17186 | 0 | result.append(part.value); |
17187 | | // Append ")" to the end of result. |
17188 | 0 | result.append(")"); |
17189 | 0 | } else if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && |
17190 | 0 | !custom_name) { |
17191 | | // Otherwise if part's type is "segment-wildcard" and custom name is |
17192 | | // false: Append "(" to the end of result. |
17193 | 0 | result.append("("); |
17194 | | // Append the result of running generate a segment wildcard regexp given |
17195 | | // options to the end of result. |
17196 | 0 | result.append(generate_segment_wildcard_regexp(options)); |
17197 | | // Append ")" to the end of result. |
17198 | 0 | result.append(")"); |
17199 | 0 | } else if (part.type == url_pattern_part_type::FULL_WILDCARD) { |
17200 | | // Otherwise if part's type is "full-wildcard": |
17201 | | // If custom name is false and one of the following is true: |
17202 | | // - previous part is null; or |
17203 | | // - previous part's type is "fixed-text"; or |
17204 | | // - previous part's modifier is not "none"; or |
17205 | | // - needs grouping is true; or |
17206 | | // - part's prefix is not the empty string |
17207 | | // - then append "*" to the end of result. |
17208 | 0 | if (!custom_name && |
17209 | 0 | (!previous_part || |
17210 | 0 | previous_part->type == url_pattern_part_type::FIXED_TEXT || |
17211 | 0 | previous_part->modifier != url_pattern_part_modifier::none || |
17212 | 0 | needs_grouping || !part.prefix.empty())) { |
17213 | 0 | result.append("*"); |
17214 | 0 | } else { |
17215 | | // Append "(" to the end of result. |
17216 | | // Append full wildcard regexp value to the end of result. |
17217 | | // Append ")" to the end of result. |
17218 | 0 | result.append("(.*)"); |
17219 | 0 | } |
17220 | 0 | } |
17221 | | |
17222 | | // If all of the following are true: |
17223 | | // - part's type is "segment-wildcard"; and |
17224 | | // - custom name is true; and |
17225 | | // - part's suffix is not the empty string; and |
17226 | | // - The result of running is a valid name code point given part's suffix's |
17227 | | // first code point and the boolean false is true then append U+005C (\) to |
17228 | | // the end of result. |
17229 | 0 | if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && custom_name && |
17230 | 0 | !part.suffix.empty() && |
17231 | 0 | idna::valid_name_code_point(part.suffix[0], false)) { |
17232 | 0 | result.append("\\"); |
17233 | 0 | } |
17234 | | |
17235 | | // Append the result of running escape a pattern string given part's suffix |
17236 | | // to the end of result. |
17237 | 0 | result.append(escape_pattern_string(part.suffix)); |
17238 | | // If needs grouping is true, then append "}" to the end of result. |
17239 | 0 | if (needs_grouping) result.append("}"); |
17240 | | // Append the result of running convert a modifier to a string given part's |
17241 | | // modifier to the end of result. |
17242 | 0 | result.append(convert_modifier_to_string(part.modifier)); |
17243 | 0 | } |
17244 | | // Return result. |
17245 | 0 | return result; |
17246 | 0 | } |
17247 | | } // namespace ada::url_pattern_helpers |
17248 | | |
17249 | | #endif // ADA_INCLUDE_URL_PATTERN |
17250 | | /* end file src/url_pattern_helpers.cpp */ |
17251 | | /* begin file src/url_pattern_regex.cpp */ |
17252 | | #if ADA_INCLUDE_URL_PATTERN |
17253 | | |
17254 | | |
17255 | | #ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER |
17256 | | #include <cstddef> |
17257 | | #include <optional> |
17258 | | #include <regex> |
17259 | | #include <string> |
17260 | | #include <string_view> |
17261 | | #include <vector> |
17262 | | #endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER |
17263 | | |
17264 | | namespace ada::url_pattern_regex { |
17265 | | |
17266 | | #ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER |
17267 | | std::optional<std::regex> std_regex_provider::create_instance( |
17268 | | std::string_view pattern, bool ignore_case) { |
17269 | | // Let flags be an empty string. |
17270 | | // If options's ignore case is true then set flags to "vi". |
17271 | | // Otherwise set flags to "v" |
17272 | | auto flags = ignore_case |
17273 | | ? std::regex::icase | std::regex_constants::ECMAScript |
17274 | | : std::regex_constants::ECMAScript; |
17275 | | try { |
17276 | | return std::regex(pattern.data(), pattern.size(), flags); |
17277 | | } catch (const std::regex_error& e) { |
17278 | | (void)e; |
17279 | | ada_log("std_regex_provider::create_instance failed:", e.what()); |
17280 | | return std::nullopt; |
17281 | | } |
17282 | | } |
17283 | | |
17284 | | std::optional<std::vector<std::optional<std::string>>> |
17285 | | std_regex_provider::regex_search(std::string_view input, |
17286 | | const std::regex& pattern) { |
17287 | | // Use iterator-based regex_search to avoid string allocation |
17288 | | std::match_results<std::string_view::const_iterator> match_result; |
17289 | | try { |
17290 | | if (!std::regex_search(input.begin(), input.end(), match_result, pattern, |
17291 | | std::regex_constants::match_any)) { |
17292 | | return std::nullopt; |
17293 | | } |
17294 | | } catch (const std::regex_error& e) { |
17295 | | (void)e; |
17296 | | ada_log("std_regex_provider::regex_search failed:", e.what()); |
17297 | | return std::nullopt; |
17298 | | } |
17299 | | std::vector<std::optional<std::string>> matches; |
17300 | | // An empty input can still match with capture groups (e.g. "(x*)" or an |
17301 | | // optional ":a?" against ""), so the group values must be extracted here |
17302 | | // just like for a non-empty input. A successful regex_search always leaves |
17303 | | // the full match at index 0, so match_result is never empty at this point. |
17304 | | if (match_result.empty()) { |
17305 | | return matches; |
17306 | | } |
17307 | | matches.reserve(match_result.size()); |
17308 | | for (size_t i = 1; i < match_result.size(); ++i) { |
17309 | | if (auto entry = match_result[i]; entry.matched) { |
17310 | | matches.emplace_back(entry.str()); |
17311 | | } else { |
17312 | | // A capture group that did not participate in the match is undefined, |
17313 | | // not absent. Emitting nullopt keeps the result aligned by position with |
17314 | | // the component's group name list; dropping it shifts every later group |
17315 | | // onto the wrong name. |
17316 | | matches.emplace_back(std::nullopt); |
17317 | | } |
17318 | | } |
17319 | | return matches; |
17320 | | } |
17321 | | |
17322 | | bool std_regex_provider::regex_match(std::string_view input, |
17323 | | const std::regex& pattern) { |
17324 | | try { |
17325 | | return std::regex_match(input.begin(), input.end(), pattern); |
17326 | | } catch (const std::regex_error& e) { |
17327 | | (void)e; |
17328 | | ada_log("std_regex_provider::regex_match failed:", e.what()); |
17329 | | return false; |
17330 | | } |
17331 | | } |
17332 | | |
17333 | | #endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER |
17334 | | |
17335 | | } // namespace ada::url_pattern_regex |
17336 | | |
17337 | | #endif // ADA_INCLUDE_URL_PATTERN |
17338 | | /* end file src/url_pattern_regex.cpp */ |
17339 | | #if !defined(ADA_URL_PATTERN_LIST_SEPARATE_TU) |
17340 | | /* begin file src/url_pattern_list.cpp */ |
17341 | | /** |
17342 | | * @file url_pattern_list.cpp |
17343 | | * @brief Route-set compiler backing ada::url_pattern_list. |
17344 | | * |
17345 | | * The provider-independent build side: classification of URLPattern part |
17346 | | * lists into pattern segments, the compiler (segment trie, per-node dispatch, |
17347 | | * auxiliary-route pruning), the arena packing, and the sequential reference |
17348 | | * matcher used beyond the fast-path limits. The matcher itself is inline in |
17349 | | * url_pattern_list-inl.h. |
17350 | | * |
17351 | | * Every dispatch decision is made at build time so that the per-request |
17352 | | * residual is a segment scan and a trie walk with bounded backtracking. |
17353 | | * Offline searches (witness plans, perfect multipliers) that fail demote the |
17354 | | * affected node to a linear scan: slower, never incorrect. |
17355 | | */ |
17356 | | /* begin file src/url_pattern_list_compiler.h */ |
17357 | | /** |
17358 | | * @file url_pattern_list_compiler.h |
17359 | | * @brief The url_pattern_list route-set compiler: pattern classification and |
17360 | | * the build-time table construction behind ada::parse_url_pattern_list. |
17361 | | * |
17362 | | * This header is NOT part of the public API and is not included from ada.h: |
17363 | | * only src/url_pattern_list.cpp (and, through the amalgamated ada.cpp, the |
17364 | | * url_pattern_list fuzzer) include it. The matcher-visible table layout it |
17365 | | * produces is declared in include/ada/url_pattern_list.h. |
17366 | | */ |
17367 | | #ifndef ADA_URL_PATTERN_LIST_COMPILER_H |
17368 | | #define ADA_URL_PATTERN_LIST_COMPILER_H |
17369 | | |
17370 | | |
17371 | | #include <cstddef> |
17372 | | #include <cstdint> |
17373 | | #include <string> |
17374 | | #include <vector> |
17375 | | |
17376 | | #if ADA_INCLUDE_URL_PATTERN |
17377 | | namespace ada::url_pattern_list_compiler { |
17378 | | |
17379 | | /** |
17380 | | * Maximum number of entries a perfect-hash dispatch table may index (slot |
17381 | | * ordinals are 8-bit, with 0xFF reserved for "empty"). Nodes with a larger |
17382 | | * static fanout are demoted to a linear scan: slower, never incorrect. |
17383 | | */ |
17384 | | inline constexpr uint32_t max_dispatch_table_entries = 254; |
17385 | | |
17386 | | /** |
17387 | | * Static fanout up to which a node compares its children directly, in |
17388 | | * turn; wider nodes dispatch through a projection table. Measured on a |
17389 | | * synthetic node hit uniformly: direct compares beat the projection by |
17390 | | * about 1 ns for keys of varied length up to about 12 children, while for |
17391 | | * keys of one length (which the length gate cannot reject) the projection |
17392 | | * wins by 4-5 ns at every fanout and by more on misses, because the direct |
17393 | | * loop's exit is unpredictable. Eight keeps the first case and bounds the |
17394 | | * second. |
17395 | | */ |
17396 | | inline constexpr uint32_t max_direct_children = 8; |
17397 | | |
17398 | | /** |
17399 | | * The kind of one compiled pattern segment. The numeric values define match |
17400 | | * priority: at the first differing segment, a literal beats a ":param" and a |
17401 | | * ":param" beats a "*" (find-my-way / Express-compatible specificity order). |
17402 | | */ |
17403 | | enum class segment_kind : uint8_t { |
17404 | | literal = 0, |
17405 | | param = 1, |
17406 | | wildcard = 2, |
17407 | | }; |
17408 | | |
17409 | | /** |
17410 | | * One '/'-separated segment of a compiled pattern: a literal text (already |
17411 | | * canonicalized by the URLPattern pattern parser), a ":param" (text = group |
17412 | | * name), or a trailing "*" wildcard. |
17413 | | */ |
17414 | | struct route_segment { |
17415 | | segment_kind kind = segment_kind::literal; |
17416 | | std::string text{}; |
17417 | | }; |
17418 | | |
17419 | | /** |
17420 | | * Everything the compiler knows about one route. `kind_sequence` packs the |
17421 | | * per-segment kinds two bits per segment, most significant first, so that |
17422 | | * comparing (kind_sequence, kind_length, route index) as a tuple is exactly |
17423 | | * the documented specificity order. For regexp-mode routes, `segments` |
17424 | | * holds only the anchored literal prefix (the leading segments that are |
17425 | | * whole fixed text, closed by a '/'), which the auxiliary-route pruning |
17426 | | * uses to rule out routes that can never match the same input. |
17427 | | */ |
17428 | | struct route_info { |
17429 | | std::vector<route_segment> segments{}; |
17430 | | // Capture group names, in capture order (params left to right, then the |
17431 | | // wildcard group). Regexp-mode routes: filled from the compiled component. |
17432 | | std::vector<std::string> group_names{}; |
17433 | | uint64_t kind_sequence = 0; |
17434 | | uint8_t kind_length = 0; |
17435 | | url_pattern_list_detail::route_mode mode = |
17436 | | url_pattern_list_detail::route_mode::sequential; |
17437 | | bool has_wildcard = false; |
17438 | | bool all_literal = false; |
17439 | | }; |
17440 | | |
17441 | | /** |
17442 | | * Classifies a URLPattern part list into '/'-separated pattern segments. |
17443 | | * Returns true when the pattern is expressible in the static/":param"/"*" |
17444 | | * subset (every segment wholly a literal, a param, or a final wildcard); |
17445 | | * `segments` and `group_names` are only valid on success. |
17446 | | */ |
17447 | | bool classify_parts(const std::vector<url_pattern_part>& parts, |
17448 | | std::vector<route_segment>& segments, |
17449 | | std::vector<std::string>& group_names); |
17450 | | |
17451 | | /** |
17452 | | * Computes kind sequence and flags from route.segments and decides the |
17453 | | * route's mode: trie when every fast-path build limit is met, sequential |
17454 | | * otherwise (the empty pattern, more than max_trie_pattern_segments |
17455 | | * segments, or more than max_captures_per_route capture groups). |
17456 | | */ |
17457 | | void finalize_route(route_info& route) noexcept; |
17458 | | |
17459 | | /** |
17460 | | * Best-effort kind sequence for a route that needs regexp matching, so it can |
17461 | | * participate in the specificity order: custom "(...)" groups count as params, |
17462 | | * full wildcards and modified ("?", "+", "*") groups terminate the sequence as |
17463 | | * a wildcard tail. This mapping is an approximation and is called out as an |
17464 | | * open question in the class documentation. Also records the route's |
17465 | | * anchored literal prefix in route.segments and sets mode = regexp. |
17466 | | */ |
17467 | | void approximate_kind_sequence(const std::vector<url_pattern_part>& parts, |
17468 | | route_info& route); |
17469 | | |
17470 | | /** |
17471 | | * True when route `a` (at insertion index `a_index`) outranks route `b`. |
17472 | | */ |
17473 | | constexpr bool route_outranks(const route_info& a, size_t a_index, |
17474 | 0 | const route_info& b, size_t b_index) noexcept { |
17475 | 0 | return url_pattern_list_detail::outranks(a.kind_sequence, a.kind_length, |
17476 | 0 | a_index, b.kind_sequence, |
17477 | 0 | b.kind_length, b_index); |
17478 | 0 | } |
17479 | | |
17480 | | /** |
17481 | | * Compiles the route set: builds the trie and its dispatch plans over the |
17482 | | * trie-mode routes, the segment table, the auxiliary-route table with its |
17483 | | * per-route challenger ranges, and packs everything into one arena. Never |
17484 | | * fails: any node whose offline search fails is demoted to a slower but |
17485 | | * correct plan. |
17486 | | * Literal texts are used as given (the caller has already case-folded them |
17487 | | * when ignore_case is set). |
17488 | | */ |
17489 | | url_pattern_list_detail::compiled_routes compile_route_set( |
17490 | | std::vector<route_info>& routes); |
17491 | | |
17492 | | } // namespace ada::url_pattern_list_compiler |
17493 | | #endif // ADA_INCLUDE_URL_PATTERN |
17494 | | #endif // ADA_URL_PATTERN_LIST_COMPILER_H |
17495 | | /* end file src/url_pattern_list_compiler.h */ |
17496 | | |
17497 | | #include <algorithm> |
17498 | | #include <array> |
17499 | | #include <bit> |
17500 | | #include <cstdint> |
17501 | | #include <cstring> |
17502 | | #include <limits> |
17503 | | #include <span> |
17504 | | #include <string_view> |
17505 | | #include <utility> |
17506 | | #include <vector> |
17507 | | |
17508 | | #if ADA_INCLUDE_URL_PATTERN |
17509 | | |
17510 | | namespace ada::url_pattern_list_compiler { |
17511 | | |
17512 | | namespace { |
17513 | | |
17514 | | using url_pattern_list_detail::compiled_routes; |
17515 | | using url_pattern_list_detail::edge_record; |
17516 | | using url_pattern_list_detail::hash_record; |
17517 | | using url_pattern_list_detail::node_record; |
17518 | | using url_pattern_list_detail::route_mode; |
17519 | | using url_pattern_list_detail::route_record; |
17520 | | using url_pattern_list_detail::segment_record; |
17521 | | using url_pattern_list_limits::max_captures_per_route; |
17522 | | using url_pattern_list_limits::max_trie_pattern_segments; |
17523 | | |
17524 | | // The tables under construction, one vector per section; packed into the |
17525 | | // single arena of compiled_routes at the end of the build. |
17526 | | struct builder_tables { |
17527 | | std::vector<node_record> nodes{}; |
17528 | | std::vector<hash_record> hashes{}; |
17529 | | std::vector<edge_record> edges{}; |
17530 | | std::vector<uint8_t> slots{}; |
17531 | | std::vector<char> blob{}; |
17532 | | std::vector<route_record> routes{}; |
17533 | | std::vector<segment_record> segments{}; |
17534 | | std::vector<uint32_t> aux{}; |
17535 | | std::vector<uint16_t> root_index{}; |
17536 | | uint32_t n_aux_all = 0; |
17537 | | }; |
17538 | | |
17539 | | // Witness plan for single-string tables: nibbles 0..2 hold witness ids |
17540 | | // (distinct ids first, remaining slots duplicating id 0 so the runtime |
17541 | | // gather is fixed-shape and branch-free); bits 12..14 are metadata. |
17542 | | constexpr uint16_t pack_witness_plan(const uint8_t* ids, uint32_t n_ids, |
17543 | 0 | bool use_len) noexcept { |
17544 | 0 | uint16_t w = 0; |
17545 | 0 | for (uint32_t j = 0; j < 3; j++) { |
17546 | 0 | w = static_cast<uint16_t>( |
17547 | 0 | w | static_cast<uint16_t>((j < n_ids ? ids[j] : ids[0]) & 15u) |
17548 | 0 | << (4 * j)); |
17549 | 0 | } |
17550 | 0 | w = static_cast<uint16_t>(w | static_cast<uint16_t>(n_ids << 12)); |
17551 | 0 | if (use_len) { |
17552 | 0 | w = static_cast<uint16_t>(w | static_cast<uint16_t>(1) << 14); |
17553 | 0 | } |
17554 | 0 | return w; |
17555 | 0 | } |
17556 | | |
17557 | | // Bytes [from, min(from + 8, len)) of a key, packed little-endian and |
17558 | | // zero-padded; the build-time twin of the matcher's window load. |
17559 | | constexpr uint64_t pack_window_le(const char* p, uint32_t len, |
17560 | 0 | uint32_t from) noexcept { |
17561 | 0 | uint64_t x = 0; |
17562 | 0 | for (uint32_t j = 0; j < 8 && from + j < len; j++) { |
17563 | 0 | x |= static_cast<uint64_t>(static_cast<uint8_t>(p[from + j])) << (8 * j); |
17564 | 0 | } |
17565 | 0 | return x; |
17566 | 0 | } |
17567 | | |
17568 | | // Deterministic RNG for the multiplier search (splitmix64). |
17569 | | struct splitmix64 { |
17570 | | uint64_t state; |
17571 | 0 | constexpr explicit splitmix64(uint64_t seed) noexcept : state(seed) {} |
17572 | 0 | constexpr uint64_t next() noexcept { |
17573 | 0 | uint64_t z = (state += 0x9E3779B97F4A7C15ull); |
17574 | 0 | z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; |
17575 | 0 | z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; |
17576 | 0 | return z ^ (z >> 31); |
17577 | 0 | } |
17578 | | }; |
17579 | | |
17580 | | struct transient_node { // build-time trie (views into route segment storage) |
17581 | | std::vector<std::pair<std::string_view, int32_t>> kids{}; |
17582 | | int32_t param = -1; |
17583 | | int32_t wild_route = -1; |
17584 | | int32_t terminal = -1; |
17585 | | }; |
17586 | | |
17587 | 0 | constexpr unsigned ceil_log2(size_t n) noexcept { |
17588 | 0 | unsigned b = 0; |
17589 | 0 | while ((size_t{1} << b) < n) { |
17590 | 0 | b++; |
17591 | 0 | } |
17592 | 0 | return b; |
17593 | 0 | } |
17594 | | |
17595 | | // Starting table size for n keys: load factor <= ~1/4, loosened as n grows |
17596 | | // so the multiplier search still lands inside the budget. |
17597 | 0 | constexpr unsigned initial_slot_bits(size_t n) noexcept { |
17598 | 0 | unsigned headroom = 1; |
17599 | 0 | if (n > 64) { |
17600 | 0 | headroom = 3; |
17601 | 0 | } else if (n > 8) { |
17602 | 0 | headroom = 2; |
17603 | 0 | } |
17604 | 0 | return ceil_log2(n) + headroom; |
17605 | 0 | } |
17606 | | |
17607 | | bool find_multiplier(const std::vector<uint64_t>& proj, unsigned b0, |
17608 | 0 | uint64_t& multiplier_out, uint8_t& bits_out) { |
17609 | 0 | const size_t n = proj.size(); |
17610 | 0 | for (unsigned b = b0; b <= 12; b++) { |
17611 | 0 | std::vector<uint32_t> stamp(size_t{1} << b, 0); |
17612 | 0 | splitmix64 rng(0x14C0FFEEull + b); |
17613 | 0 | for (uint32_t t = 1; t <= 4000; t++) { |
17614 | 0 | const uint64_t m = rng.next() | 1; |
17615 | 0 | bool ok = true; |
17616 | 0 | for (size_t i = 0; i < n; i++) { |
17617 | 0 | const uint64_t s = (proj[i] * m) >> (64 - b); |
17618 | 0 | if (stamp[s] == t) { |
17619 | 0 | ok = false; |
17620 | 0 | break; |
17621 | 0 | } |
17622 | 0 | stamp[s] = t; |
17623 | 0 | } |
17624 | 0 | if (ok) { |
17625 | 0 | multiplier_out = m; |
17626 | 0 | bits_out = static_cast<uint8_t>(b); |
17627 | 0 | return true; |
17628 | 0 | } |
17629 | 0 | } |
17630 | 0 | } |
17631 | 0 | return false; |
17632 | 0 | } |
17633 | | |
17634 | | // Emits a perfect-hash slot table for `proj` at the end of `slots`. Returns |
17635 | | // false if the search failed, in which case nothing was appended and the |
17636 | | // caller demotes that table to a linear scan. |
17637 | | bool emit_slot_table(const std::vector<uint64_t>& proj, |
17638 | | std::vector<uint8_t>& slots, uint64_t& multiplier_out, |
17639 | 0 | uint8_t& bits_out, uint32_t& base_out) { |
17640 | 0 | if (!find_multiplier(proj, initial_slot_bits(proj.size()), multiplier_out, |
17641 | 0 | bits_out)) { |
17642 | 0 | return false; |
17643 | 0 | } |
17644 | 0 | base_out = static_cast<uint32_t>(slots.size()); |
17645 | 0 | slots.resize(slots.size() + (size_t{1} << bits_out), 0xFF); |
17646 | 0 | for (size_t i = 0; i < proj.size(); i++) { |
17647 | 0 | slots[base_out + |
17648 | 0 | url_pattern_list_detail::slot_of(proj[i], multiplier_out, bits_out)] = |
17649 | 0 | static_cast<uint8_t>(i); |
17650 | 0 | } |
17651 | 0 | return true; |
17652 | 0 | } |
17653 | | |
17654 | | // Advances `c` to the next k-combination of {0..n-1} in lexicographic |
17655 | | // order; false once the last one has been visited. |
17656 | | template <size_t N> |
17657 | | constexpr bool next_combination(std::array<uint32_t, N>& c, uint32_t k, |
17658 | 0 | uint32_t n) noexcept { |
17659 | 0 | int32_t j = static_cast<int32_t>(k) - 1; |
17660 | 0 | while (j >= 0 && |
17661 | 0 | c[static_cast<uint32_t>(j)] == n - k + static_cast<uint32_t>(j)) { |
17662 | 0 | j--; |
17663 | 0 | } |
17664 | 0 | if (j < 0) { |
17665 | 0 | return false; |
17666 | 0 | } |
17667 | 0 | c[static_cast<uint32_t>(j)]++; |
17668 | 0 | for (uint32_t t = static_cast<uint32_t>(j) + 1; t < k; t++) { |
17669 | 0 | c[t] = c[t - 1] + 1; |
17670 | 0 | } |
17671 | 0 | return true; |
17672 | 0 | } |
17673 | | |
17674 | | // Witness-subset search over the given id alphabet, cost-ordered: fewest |
17675 | | // distinct witness ids first (the length is always packed -- it is free). |
17676 | | // The first injective subset wins. |
17677 | | bool find_witness_plan( |
17678 | | const std::vector<std::pair<std::string_view, int32_t>>& kids, |
17679 | | const uint8_t* alphabet, uint32_t n_alpha, uint32_t max_reads, |
17680 | 0 | uint16_t& plan_out) { |
17681 | 0 | const size_t n = kids.size(); |
17682 | 0 | auto injective = [&](uint16_t wp) { // sort + adjacent compare |
17683 | 0 | std::vector<uint64_t> proj(n); |
17684 | 0 | for (size_t i = 0; i < n; i++) { |
17685 | 0 | proj[i] = url_pattern_list_detail::project( |
17686 | 0 | kids[i].first.data(), static_cast<uint32_t>(kids[i].first.size()), |
17687 | 0 | wp); |
17688 | 0 | } |
17689 | 0 | std::sort(proj.begin(), proj.end()); |
17690 | 0 | for (size_t i = 1; i < n; i++) { |
17691 | 0 | if (proj[i] == proj[i - 1]) { |
17692 | 0 | return false; |
17693 | 0 | } |
17694 | 0 | } |
17695 | 0 | return true; |
17696 | 0 | }; |
17697 | 0 | for (uint32_t k = 1; k <= max_reads && k <= n_alpha; k++) { |
17698 | 0 | std::array<uint32_t, 3> c{0, 1, 2}; |
17699 | 0 | do { |
17700 | 0 | uint8_t ids[3] = {0, 0, 0}; |
17701 | 0 | for (uint32_t j = 0; j < k; j++) { |
17702 | 0 | ids[j] = alphabet[c[j]]; |
17703 | 0 | } |
17704 | 0 | const uint16_t wp = pack_witness_plan(ids, k, true); |
17705 | 0 | if (injective(wp)) { |
17706 | 0 | plan_out = wp; |
17707 | 0 | return true; |
17708 | 0 | } |
17709 | 0 | } while (next_combination(c, k, n_alpha)); |
17710 | 0 | } |
17711 | 0 | return false; |
17712 | 0 | } |
17713 | | |
17714 | | // ---- build stages ---------------------------------------------------------- |
17715 | | |
17716 | | // Segment trie over the trie-mode routes. Priority is resolved here, at |
17717 | | // build, into each node's fixed decision order (static children -> param -> |
17718 | | // wildcard); a DFS in that order returns the match with the |
17719 | | // lexicographically minimal kind sequence. Duplicate patterns collapse onto |
17720 | | // one slot: an occupied slot is never overwritten, so the smallest route |
17721 | | // index survives. |
17722 | 0 | std::vector<transient_node> build_trie(const std::vector<route_info>& routes) { |
17723 | 0 | std::vector<transient_node> t(1); |
17724 | 0 | for (size_t i = 0; i < routes.size(); i++) { |
17725 | 0 | const route_info& rt = routes[i]; |
17726 | 0 | if (rt.mode != route_mode::trie) { |
17727 | 0 | continue; |
17728 | 0 | } |
17729 | 0 | int32_t cur = 0; |
17730 | 0 | for (const route_segment& ps : rt.segments) { |
17731 | 0 | if (ps.kind == segment_kind::literal) { |
17732 | 0 | int32_t nxt = -1; |
17733 | 0 | for (auto& kv : t[static_cast<size_t>(cur)].kids) { |
17734 | 0 | if (kv.first == ps.text) { |
17735 | 0 | nxt = kv.second; |
17736 | 0 | break; |
17737 | 0 | } |
17738 | 0 | } |
17739 | 0 | if (nxt < 0) { |
17740 | 0 | nxt = static_cast<int32_t>(t.size()); |
17741 | 0 | t[static_cast<size_t>(cur)].kids.emplace_back(ps.text, nxt); |
17742 | 0 | t.emplace_back(); |
17743 | 0 | } |
17744 | 0 | cur = nxt; |
17745 | 0 | } else if (ps.kind == segment_kind::param) { |
17746 | 0 | if (t[static_cast<size_t>(cur)].param < 0) { |
17747 | 0 | t[static_cast<size_t>(cur)].param = static_cast<int32_t>(t.size()); |
17748 | 0 | t.emplace_back(); |
17749 | 0 | } |
17750 | 0 | cur = t[static_cast<size_t>(cur)].param; |
17751 | 0 | } else { // wildcard (classification guarantees final) |
17752 | 0 | if (t[static_cast<size_t>(cur)].wild_route < 0) { |
17753 | 0 | t[static_cast<size_t>(cur)].wild_route = static_cast<int32_t>(i); |
17754 | 0 | } |
17755 | 0 | cur = -1; |
17756 | 0 | break; |
17757 | 0 | } |
17758 | 0 | } |
17759 | 0 | if (cur >= 0 && t[static_cast<size_t>(cur)].terminal < 0) { |
17760 | 0 | t[static_cast<size_t>(cur)].terminal = static_cast<int32_t>(i); |
17761 | 0 | } |
17762 | 0 | } |
17763 | | // The root's children are sorted by first byte so that the first-byte |
17764 | | // index can address each run of same-byte children as one contiguous |
17765 | | // block of edges. |
17766 | 0 | std::stable_sort( |
17767 | 0 | t[0].kids.begin(), t[0].kids.end(), [](const auto& a, const auto& b) { |
17768 | 0 | const int ka = a.first.empty() ? -1 : static_cast<uint8_t>(a.first[0]); |
17769 | 0 | const int kb = b.first.empty() ? -1 : static_cast<uint8_t>(b.first[0]); |
17770 | 0 | return ka < kb; |
17771 | 0 | }); |
17772 | 0 | return t; |
17773 | 0 | } |
17774 | | |
17775 | | // Per-route records: priority data, capture positions (so extracting params |
17776 | | // at match time is a fixed walk over param_positions), regexp ordinals. |
17777 | | void compile_route_records(builder_tables& r, |
17778 | 0 | const std::vector<route_info>& routes) { |
17779 | 0 | r.routes.resize(routes.size()); |
17780 | 0 | int32_t n_regexp = 0; |
17781 | 0 | for (size_t i = 0; i < routes.size(); i++) { |
17782 | 0 | const route_info& rt = routes[i]; |
17783 | 0 | route_record& rm = r.routes[i]; |
17784 | 0 | rm.kind_sequence = rt.kind_sequence; |
17785 | 0 | rm.kind_length = rt.kind_length; |
17786 | 0 | rm.mode = rt.mode; |
17787 | 0 | rm.wild = rt.has_wildcard ? 1 : 0; |
17788 | 0 | if (rt.mode == route_mode::regexp) { |
17789 | 0 | rm.regexp_component = n_regexp++; |
17790 | 0 | continue; |
17791 | 0 | } |
17792 | 0 | if (rt.mode != route_mode::trie) { |
17793 | 0 | continue; // capture positions are only read for trie-answered routes |
17794 | 0 | } |
17795 | 0 | for (size_t s = 0; s < rt.segments.size(); s++) { |
17796 | 0 | if (rt.segments[s].kind == segment_kind::param) { |
17797 | | // Classification guarantees n_params <= max_captures_per_route for |
17798 | | // trie-mode routes. |
17799 | 0 | rm.param_positions[rm.n_params++] = static_cast<uint8_t>(s); |
17800 | 0 | } |
17801 | 0 | } |
17802 | 0 | } |
17803 | 0 | } |
17804 | | |
17805 | | // BFS layout: assign final node ids breadth-first so each node's static |
17806 | | // children occupy a contiguous block of edges[]. Returns the transient-node |
17807 | | // id per final id. |
17808 | | std::vector<int32_t> layout_nodes(builder_tables& r, |
17809 | 0 | const std::vector<transient_node>& t) { |
17810 | 0 | std::vector<int32_t> order; // transient id per final id |
17811 | 0 | order.push_back(0); |
17812 | 0 | r.nodes.resize(1); |
17813 | 0 | for (size_t head = 0; head < order.size(); head++) { |
17814 | 0 | const transient_node& tn = t[static_cast<size_t>(order[head])]; |
17815 | 0 | node_record nd{}; |
17816 | 0 | nd.wild_route = tn.wild_route; |
17817 | 0 | nd.terminal_route = tn.terminal; |
17818 | 0 | nd.first_child = static_cast<int32_t>(r.edges.size()); |
17819 | 0 | nd.n_static = static_cast<uint16_t>(tn.kids.size()); |
17820 | 0 | const size_t id_base = order.size(); // children take the next BFS ids |
17821 | 0 | for (size_t ci = 0; ci < tn.kids.size(); ci++) { |
17822 | 0 | const std::string_view k = tn.kids[ci].first; |
17823 | 0 | edge_record e{}; |
17824 | 0 | e.key_length = static_cast<uint16_t>(k.size()); |
17825 | 0 | e.key_offset = static_cast<uint32_t>(r.blob.size()); |
17826 | 0 | r.blob.insert(r.blob.end(), k.begin(), k.end()); |
17827 | 0 | e.prefix = pack_window_le(k.data(), static_cast<uint32_t>(k.size()), 0); |
17828 | 0 | e.suffix = pack_window_le( |
17829 | 0 | k.data(), static_cast<uint32_t>(k.size()), |
17830 | 0 | k.size() >= 8 ? static_cast<uint32_t>(k.size()) - 8 : 0); |
17831 | 0 | e.node = static_cast<int32_t>(id_base + ci); |
17832 | 0 | r.edges.push_back(e); |
17833 | 0 | } |
17834 | 0 | for (size_t ci = 0; ci < tn.kids.size(); ci++) { |
17835 | 0 | order.push_back(tn.kids[ci].second); |
17836 | 0 | } |
17837 | 0 | if (tn.param >= 0) { |
17838 | 0 | nd.param_child = static_cast<int32_t>(order.size()); |
17839 | 0 | order.push_back(tn.param); |
17840 | 0 | } |
17841 | 0 | nd.has_alternative = (nd.param_child >= 0 || nd.wild_route >= 0) ? 1 : 0; |
17842 | 0 | r.nodes.resize(order.size()); |
17843 | 0 | r.nodes[head] = nd; |
17844 | 0 | } |
17845 | 0 | return order; |
17846 | 0 | } |
17847 | | |
17848 | | // Root first-byte index: a 256-entry table from the first byte of the |
17849 | | // input's first segment to the first root child starting with it (the |
17850 | | // children are sorted by first byte). Built for a root with at least three |
17851 | | // children; a run of same-byte children longer than max_direct_children, or |
17852 | | // an empty key, falls back to the regular ladder. Returns true when the |
17853 | | // index was emitted. |
17854 | 0 | bool build_root_index(builder_tables& r, const transient_node& root) { |
17855 | 0 | const size_t nk = root.kids.size(); |
17856 | 0 | if (nk < 3) { |
17857 | 0 | return false; |
17858 | 0 | } |
17859 | 0 | std::array<uint16_t, 256> index{}; |
17860 | 0 | index.fill(0xFFFF); |
17861 | 0 | std::array<uint32_t, 256> run{}; |
17862 | 0 | for (size_t ci = 0; ci < nk; ci++) { |
17863 | 0 | if (root.kids[ci].first.empty()) { |
17864 | 0 | return false; // an empty key has no first byte: regular ladder |
17865 | 0 | } |
17866 | 0 | const uint8_t b = static_cast<uint8_t>(root.kids[ci].first[0]); |
17867 | 0 | if (index[b] == 0xFFFF) { |
17868 | 0 | index[b] = static_cast<uint16_t>(ci); |
17869 | 0 | } |
17870 | 0 | if (++run[b] > max_direct_children) { |
17871 | 0 | return false; |
17872 | 0 | } |
17873 | 0 | } |
17874 | 0 | r.root_index.assign(index.begin(), index.end()); |
17875 | 0 | return true; |
17876 | 0 | } |
17877 | | |
17878 | | // Per-node dispatch ladder, chosen by static child count: 0 none, up to |
17879 | | // max_direct_children direct compares, then projection over a restricted |
17880 | | // alphabet (escalating to the full alphabet); linear demotion when a search |
17881 | | // fails or when the fanout exceeds max_dispatch_table_entries. The root |
17882 | | // gets the first-byte index when its fanout allows. Never incorrect, only |
17883 | | // slower. |
17884 | | void compile_dispatch(builder_tables& r, const std::vector<transient_node>& t, |
17885 | 0 | const std::vector<int32_t>& order) { |
17886 | 0 | for (size_t ni = 0; ni < r.nodes.size(); ni++) { |
17887 | 0 | node_record& nd = r.nodes[ni]; |
17888 | 0 | const transient_node& tn = t[static_cast<size_t>(order[ni])]; |
17889 | 0 | const size_t nk = tn.kids.size(); |
17890 | 0 | if (nk == 0) { |
17891 | 0 | nd.dispatch = 0; |
17892 | 0 | continue; |
17893 | 0 | } |
17894 | 0 | if (ni == 0 && build_root_index(r, tn)) { |
17895 | 0 | nd.dispatch = 4; |
17896 | 0 | continue; |
17897 | 0 | } |
17898 | 0 | if (nk <= max_direct_children) { |
17899 | 0 | nd.dispatch = 1; |
17900 | 0 | continue; |
17901 | 0 | } |
17902 | 0 | if (nk > max_dispatch_table_entries) { |
17903 | 0 | nd.dispatch = 3; // slot ordinals are 8-bit; linear scan stays correct |
17904 | 0 | continue; |
17905 | 0 | } |
17906 | 0 | uint16_t wp = 0; |
17907 | 0 | bool found = false; |
17908 | 0 | if (nk <= 16) { |
17909 | 0 | constexpr uint8_t alpha_small[2] = {0, 8}; // s[0], s[len - 1] |
17910 | 0 | found = find_witness_plan(tn.kids, alpha_small, 2, 2, wp); |
17911 | 0 | } |
17912 | 0 | if (!found) { // full alphabet (also the escalation path for <= 16) |
17913 | 0 | uint8_t alpha_full[16] = {0, 1, 2, 3, 4, 5, 6, 7, |
17914 | 0 | 8, 9, 10, 11, 12, 13, 14, 15}; |
17915 | 0 | found = find_witness_plan(tn.kids, alpha_full, 16, 3, wp); |
17916 | 0 | } |
17917 | 0 | hash_record h{}; |
17918 | 0 | if (found) { |
17919 | 0 | std::vector<uint64_t> proj(nk); |
17920 | 0 | for (size_t i = 0; i < nk; i++) { |
17921 | 0 | proj[i] = url_pattern_list_detail::project( |
17922 | 0 | tn.kids[i].first.data(), |
17923 | 0 | static_cast<uint32_t>(tn.kids[i].first.size()), wp); |
17924 | 0 | } |
17925 | 0 | found = emit_slot_table(proj, r.slots, h.multiplier, h.slot_bits, |
17926 | 0 | h.slot_base); |
17927 | 0 | } |
17928 | 0 | if (!found) { |
17929 | 0 | nd.dispatch = 3; // demoted: correct, slower |
17930 | 0 | continue; |
17931 | 0 | } |
17932 | 0 | nd.dispatch = 2; |
17933 | 0 | h.witness_plan = wp; |
17934 | 0 | nd.hash_index = static_cast<uint32_t>(r.hashes.size()); |
17935 | 0 | r.hashes.push_back(h); |
17936 | 0 | } |
17937 | 0 | } |
17938 | | |
17939 | | // Pure-leaf edge encoding, last: a child that is a pure leaf (terminal |
17940 | | // route only) is encoded as -2 - route directly in the edge, so the walk |
17941 | | // finishes or dead-ends there without loading the leaf node. -1 keeps |
17942 | | // meaning "absent" for param_child. |
17943 | 0 | void encode_leaf_shortcuts(builder_tables& r) { |
17944 | 0 | auto pure_leaf = [&](int32_t ni) { |
17945 | 0 | const node_record& nd = r.nodes[static_cast<size_t>(ni)]; |
17946 | 0 | return nd.n_static == 0 && nd.param_child < 0 && nd.wild_route < 0 && |
17947 | 0 | nd.terminal_route >= 0; |
17948 | 0 | }; |
17949 | 0 | for (auto& e : r.edges) { |
17950 | 0 | if (pure_leaf(e.node)) { |
17951 | 0 | e.node = -2 - r.nodes[static_cast<size_t>(e.node)].terminal_route; |
17952 | 0 | } |
17953 | 0 | } |
17954 | 0 | for (auto& nd : r.nodes) { |
17955 | 0 | if (nd.param_child >= 0 && pure_leaf(nd.param_child)) { |
17956 | 0 | nd.param_child = |
17957 | 0 | -2 - r.nodes[static_cast<size_t>(nd.param_child)].terminal_route; |
17958 | 0 | } |
17959 | 0 | } |
17960 | 0 | } |
17961 | | |
17962 | | // Segment table: every non-regexp route's segments (kind plus literal text |
17963 | | // in the blob), so the sequential fallback beyond the fast-path limits can |
17964 | | // match any route without the compiler's types; for regexp routes, the |
17965 | | // anchored literal prefix the matcher checks before running the provider. |
17966 | | void build_segment_table(builder_tables& r, |
17967 | 0 | const std::vector<route_info>& routes) { |
17968 | 0 | for (size_t i = 0; i < routes.size(); i++) { |
17969 | 0 | const route_info& rt = routes[i]; |
17970 | 0 | route_record& rm = r.routes[i]; |
17971 | 0 | rm.segment_first = static_cast<uint32_t>(r.segments.size()); |
17972 | 0 | rm.segment_count = static_cast<uint32_t>(rt.segments.size()); |
17973 | 0 | for (const route_segment& s : rt.segments) { |
17974 | 0 | segment_record sr{}; |
17975 | 0 | sr.kind = static_cast<uint8_t>(s.kind); |
17976 | 0 | if (s.kind == segment_kind::literal) { |
17977 | 0 | sr.text_offset = static_cast<uint32_t>(r.blob.size()); |
17978 | 0 | sr.text_length = static_cast<uint32_t>(s.text.size()); |
17979 | 0 | r.blob.insert(r.blob.end(), s.text.begin(), s.text.end()); |
17980 | 0 | } |
17981 | 0 | r.segments.push_back(sr); |
17982 | 0 | } |
17983 | 0 | } |
17984 | 0 | } |
17985 | | |
17986 | | // Could some pathname match both a fast-path route `w` (full segment |
17987 | | // information) and route `c`? Conservative: true unless a literal conflict |
17988 | | // or a segment-count conflict proves otherwise. For a regexp-mode `c`, |
17989 | | // segments are what approximate_kind_sequence could certify (see there); |
17990 | | // has_wildcard means the input needs at least segments.size() segments |
17991 | | // rather than exactly that many. |
17992 | 0 | bool co_matchable(const route_info& w, const route_info& c) noexcept { |
17993 | 0 | const bool c_regexp = c.mode == route_mode::regexp; |
17994 | 0 | const size_t wn = w.segments.size(); |
17995 | 0 | const size_t cn = c.segments.size(); |
17996 | 0 | constexpr size_t unbounded = ~size_t{0}; |
17997 | | // Segment counts each route accepts: [min, max]. |
17998 | 0 | const size_t w_max = w.has_wildcard ? unbounded : wn; |
17999 | 0 | const size_t c_max = c.has_wildcard ? unbounded : cn; |
18000 | 0 | if ((wn > cn ? wn : cn) > (w_max < c_max ? w_max : c_max)) { |
18001 | 0 | return false; |
18002 | 0 | } |
18003 | | // Positions both routes constrain (a safe wildcard segment constrains |
18004 | | // nothing; a regexp route's segments are all constraining). |
18005 | 0 | const size_t w_fixed = w.has_wildcard ? wn - 1 : wn; |
18006 | 0 | const size_t c_fixed = (!c_regexp && c.has_wildcard) ? cn - 1 : cn; |
18007 | 0 | const size_t upto = w_fixed < c_fixed ? w_fixed : c_fixed; |
18008 | 0 | for (size_t j = 0; j < upto; j++) { |
18009 | 0 | const route_segment& ws = w.segments[j]; |
18010 | 0 | const route_segment& cs = c.segments[j]; |
18011 | 0 | if (ws.kind == segment_kind::literal && cs.kind == segment_kind::literal) { |
18012 | 0 | if (ws.text != cs.text) { |
18013 | 0 | return false; |
18014 | 0 | } |
18015 | 0 | } else if (ws.kind == segment_kind::literal && |
18016 | 0 | cs.kind == segment_kind::param) { |
18017 | 0 | if (ws.text.empty()) { |
18018 | 0 | return false; // params never bind an empty segment |
18019 | 0 | } |
18020 | 0 | } else if (ws.kind == segment_kind::param && |
18021 | 0 | cs.kind == segment_kind::literal) { |
18022 | 0 | if (cs.text.empty()) { |
18023 | 0 | return false; |
18024 | 0 | } |
18025 | 0 | } |
18026 | 0 | } |
18027 | 0 | return true; |
18028 | 0 | } |
18029 | | |
18030 | | // Auxiliary routes: those the trie cannot answer for (regexp mode and |
18031 | | // sequential mode), in insertion order, followed by one challenger range per |
18032 | | // trie route: the auxiliary routes that outrank it AND could match the same |
18033 | | // input. After a fast-path hit only the winner's challengers are tested |
18034 | | // (usually none). |
18035 | 0 | void build_aux_table(builder_tables& r, const std::vector<route_info>& routes) { |
18036 | 0 | std::vector<uint32_t> aux_all; |
18037 | 0 | for (size_t i = 0; i < routes.size(); i++) { |
18038 | 0 | if (routes[i].mode != route_mode::trie) { |
18039 | 0 | aux_all.push_back(static_cast<uint32_t>(i)); |
18040 | 0 | } |
18041 | 0 | } |
18042 | 0 | r.aux = aux_all; |
18043 | 0 | r.n_aux_all = static_cast<uint32_t>(aux_all.size()); |
18044 | 0 | for (size_t w = 0; w < routes.size(); w++) { |
18045 | 0 | const route_info& winner = routes[w]; |
18046 | 0 | if (winner.mode != route_mode::trie) { |
18047 | 0 | continue; // never a fast-path winner |
18048 | 0 | } |
18049 | 0 | route_record& rm = r.routes[w]; |
18050 | 0 | rm.challenger_first = static_cast<uint32_t>(r.aux.size()); |
18051 | 0 | for (const uint32_t c : aux_all) { |
18052 | 0 | if (route_outranks(routes[c], c, winner, w) && |
18053 | 0 | co_matchable(winner, routes[c])) { |
18054 | 0 | r.aux.push_back(c); |
18055 | 0 | } |
18056 | 0 | } |
18057 | 0 | rm.challenger_count = |
18058 | 0 | static_cast<uint32_t>(r.aux.size()) - rm.challenger_first; |
18059 | 0 | } |
18060 | 0 | } |
18061 | | |
18062 | | // Packs every table into one arena, each section 8-byte aligned, and |
18063 | | // records the section offsets. The blob gets 8 bytes of zero padding so |
18064 | | // short key windows can always be loaded whole. |
18065 | 0 | compiled_routes pack_arena(builder_tables& r) { |
18066 | 0 | compiled_routes out{}; |
18067 | 0 | r.blob.insert(r.blob.end(), 8, '\0'); |
18068 | 0 | size_t total = 0; |
18069 | 0 | const auto reserve = [&](size_t bytes) { |
18070 | 0 | const size_t offset = total; |
18071 | 0 | total += (bytes + 7) & ~size_t{7}; |
18072 | 0 | return static_cast<uint32_t>(offset); |
18073 | 0 | }; |
18074 | 0 | const auto bytes_of = [](const auto& v) { return v.size() * sizeof(v[0]); };Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<ada::url_pattern_list_detail::node_record, std::__1::allocator<ada::url_pattern_list_detail::node_record> > >(std::__1::vector<ada::url_pattern_list_detail::node_record, std::__1::allocator<ada::url_pattern_list_detail::node_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<ada::url_pattern_list_detail::hash_record, std::__1::allocator<ada::url_pattern_list_detail::hash_record> > >(std::__1::vector<ada::url_pattern_list_detail::hash_record, std::__1::allocator<ada::url_pattern_list_detail::hash_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<ada::url_pattern_list_detail::edge_record, std::__1::allocator<ada::url_pattern_list_detail::edge_record> > >(std::__1::vector<ada::url_pattern_list_detail::edge_record, std::__1::allocator<ada::url_pattern_list_detail::edge_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<char, std::__1::allocator<char> > >(std::__1::vector<char, std::__1::allocator<char> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<ada::url_pattern_list_detail::route_record, std::__1::allocator<ada::url_pattern_list_detail::route_record> > >(std::__1::vector<ada::url_pattern_list_detail::route_record, std::__1::allocator<ada::url_pattern_list_detail::route_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<ada::url_pattern_list_detail::segment_record, std::__1::allocator<ada::url_pattern_list_detail::segment_record> > >(std::__1::vector<ada::url_pattern_list_detail::segment_record, std::__1::allocator<ada::url_pattern_list_detail::segment_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > >(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_0::operator()<std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > >(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) const |
18075 | 0 | out.nodes_offset = reserve(bytes_of(r.nodes)); |
18076 | 0 | out.hashes_offset = reserve(bytes_of(r.hashes)); |
18077 | 0 | out.edges_offset = reserve(bytes_of(r.edges)); |
18078 | 0 | out.slots_offset = reserve(bytes_of(r.slots)); |
18079 | 0 | out.blob_offset = reserve(bytes_of(r.blob)); |
18080 | 0 | out.routes_offset = reserve(bytes_of(r.routes)); |
18081 | 0 | out.segments_offset = reserve(bytes_of(r.segments)); |
18082 | 0 | out.aux_offset = reserve(bytes_of(r.aux)); |
18083 | 0 | out.root_index_offset = reserve(bytes_of(r.root_index)); |
18084 | 0 | out.arena.assign(total, 0); |
18085 | 0 | const auto place = [&](uint32_t offset, const auto& v) { |
18086 | 0 | if (!v.empty()) { |
18087 | 0 | std::memcpy(out.arena.data() + offset, v.data(), v.size() * sizeof(v[0])); |
18088 | 0 | } |
18089 | 0 | }; Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<ada::url_pattern_list_detail::node_record, std::__1::allocator<ada::url_pattern_list_detail::node_record> > >(unsigned int, std::__1::vector<ada::url_pattern_list_detail::node_record, std::__1::allocator<ada::url_pattern_list_detail::node_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<ada::url_pattern_list_detail::hash_record, std::__1::allocator<ada::url_pattern_list_detail::hash_record> > >(unsigned int, std::__1::vector<ada::url_pattern_list_detail::hash_record, std::__1::allocator<ada::url_pattern_list_detail::hash_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<ada::url_pattern_list_detail::edge_record, std::__1::allocator<ada::url_pattern_list_detail::edge_record> > >(unsigned int, std::__1::vector<ada::url_pattern_list_detail::edge_record, std::__1::allocator<ada::url_pattern_list_detail::edge_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >(unsigned int, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<char, std::__1::allocator<char> > >(unsigned int, std::__1::vector<char, std::__1::allocator<char> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<ada::url_pattern_list_detail::route_record, std::__1::allocator<ada::url_pattern_list_detail::route_record> > >(unsigned int, std::__1::vector<ada::url_pattern_list_detail::route_record, std::__1::allocator<ada::url_pattern_list_detail::route_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<ada::url_pattern_list_detail::segment_record, std::__1::allocator<ada::url_pattern_list_detail::segment_record> > >(unsigned int, std::__1::vector<ada::url_pattern_list_detail::segment_record, std::__1::allocator<ada::url_pattern_list_detail::segment_record> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > >(unsigned int, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&) const Unexecuted instantiation: can_parse.cc:auto ada::url_pattern_list_compiler::(anonymous namespace)::pack_arena(ada::url_pattern_list_compiler::(anonymous namespace)::builder_tables&)::$_1::operator()<std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > >(unsigned int, std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) const |
18090 | 0 | place(out.nodes_offset, r.nodes); |
18091 | 0 | place(out.hashes_offset, r.hashes); |
18092 | 0 | place(out.edges_offset, r.edges); |
18093 | 0 | place(out.slots_offset, r.slots); |
18094 | 0 | place(out.blob_offset, r.blob); |
18095 | 0 | place(out.routes_offset, r.routes); |
18096 | 0 | place(out.segments_offset, r.segments); |
18097 | 0 | place(out.aux_offset, r.aux); |
18098 | 0 | place(out.root_index_offset, r.root_index); |
18099 | 0 | out.n_routes = static_cast<uint32_t>(r.routes.size()); |
18100 | 0 | out.n_aux_all = r.n_aux_all; |
18101 | 0 | return out; |
18102 | 0 | } |
18103 | | |
18104 | | // Fills route.kind_sequence / kind_length from route.segments. |
18105 | 0 | void compute_kind_sequence(route_info& route) noexcept { |
18106 | 0 | uint64_t seq = 0; |
18107 | 0 | const size_t n = route.segments.size(); |
18108 | 0 | for (size_t j = 0; j < n && j < 32; j++) { |
18109 | 0 | seq |= static_cast<uint64_t>(route.segments[j].kind) << (62 - 2 * j); |
18110 | 0 | } |
18111 | 0 | route.kind_sequence = seq; |
18112 | 0 | route.kind_length = static_cast<uint8_t>(n < 255 ? n : 255); |
18113 | 0 | } |
18114 | | |
18115 | | } // namespace |
18116 | | |
18117 | | // ---- compiler entry points ------------------------------------------------- |
18118 | | |
18119 | | bool classify_parts(const std::vector<url_pattern_part>& parts, |
18120 | | std::vector<route_segment>& segments, |
18121 | 0 | std::vector<std::string>& group_names) { |
18122 | 0 | segments.clear(); |
18123 | 0 | group_names.clear(); |
18124 | 0 | bool started = false; // leading '/' consumed |
18125 | 0 | bool group_open = false; // the open segment slot is a group |
18126 | 0 | bool wildcard_seen = false; // a "*" segment was consumed (must stay last) |
18127 | 0 | std::string literal; |
18128 | 0 | const auto close_segment = [&]() { |
18129 | 0 | if (!group_open) { |
18130 | 0 | segments.push_back(route_segment{segment_kind::literal, literal}); |
18131 | 0 | } |
18132 | 0 | literal.clear(); |
18133 | 0 | group_open = false; |
18134 | 0 | }; |
18135 | 0 | const auto process_text = [&](std::string_view text) { |
18136 | 0 | for (const char c : text) { |
18137 | 0 | if (wildcard_seen) { |
18138 | 0 | return false; // nothing may follow a "*" segment |
18139 | 0 | } |
18140 | 0 | if (c == '/') { |
18141 | 0 | if (!started) { |
18142 | 0 | started = true; |
18143 | 0 | } else { |
18144 | 0 | close_segment(); |
18145 | 0 | } |
18146 | 0 | } else { |
18147 | 0 | if (!started || group_open) { |
18148 | 0 | return false; // text before '/', or suffix text after a group |
18149 | 0 | } |
18150 | 0 | literal += c; |
18151 | 0 | } |
18152 | 0 | } |
18153 | 0 | return true; |
18154 | 0 | }; |
18155 | 0 | for (const url_pattern_part& part : parts) { |
18156 | 0 | if (part.type == url_pattern_part_type::FIXED_TEXT && |
18157 | 0 | part.modifier == url_pattern_part_modifier::none) { |
18158 | 0 | if (!process_text(part.prefix) || !process_text(part.value) || |
18159 | 0 | !process_text(part.suffix)) { |
18160 | 0 | return false; |
18161 | 0 | } |
18162 | 0 | } else if ((part.type == url_pattern_part_type::SEGMENT_WILDCARD || |
18163 | 0 | part.type == url_pattern_part_type::FULL_WILDCARD) && |
18164 | 0 | part.modifier == url_pattern_part_modifier::none && |
18165 | 0 | part.suffix.empty()) { |
18166 | 0 | if (wildcard_seen) { |
18167 | 0 | return false; |
18168 | 0 | } |
18169 | 0 | if (part.prefix == "/") { |
18170 | 0 | if (!started) { |
18171 | 0 | started = true; |
18172 | 0 | } else { |
18173 | 0 | close_segment(); |
18174 | 0 | } |
18175 | 0 | } else if (part.prefix.empty()) { |
18176 | | // The group must occupy a whole, freshly opened segment slot. |
18177 | 0 | if (!started || group_open || !literal.empty()) { |
18178 | 0 | return false; |
18179 | 0 | } |
18180 | 0 | } else { |
18181 | 0 | return false; // group not aligned on a '/' boundary |
18182 | 0 | } |
18183 | 0 | const bool is_wildcard = |
18184 | 0 | part.type == url_pattern_part_type::FULL_WILDCARD; |
18185 | 0 | segments.push_back(route_segment{ |
18186 | 0 | is_wildcard ? segment_kind::wildcard : segment_kind::param, |
18187 | 0 | part.name}); |
18188 | 0 | group_names.push_back(part.name); |
18189 | 0 | group_open = true; |
18190 | 0 | wildcard_seen = is_wildcard; |
18191 | 0 | } else { |
18192 | 0 | return false; // regexp group or a "?" / "+" / "*" modifier |
18193 | 0 | } |
18194 | 0 | } |
18195 | 0 | if (!started) { |
18196 | | // Only the empty pattern (zero parts) is representable without a leading |
18197 | | // '/': it matches exactly the empty pathname. |
18198 | 0 | return parts.empty(); |
18199 | 0 | } |
18200 | 0 | close_segment(); |
18201 | 0 | return true; |
18202 | 0 | } |
18203 | | |
18204 | 0 | void finalize_route(route_info& route) noexcept { |
18205 | 0 | compute_kind_sequence(route); |
18206 | 0 | route.all_literal = true; |
18207 | 0 | route.has_wildcard = false; |
18208 | 0 | size_t n_params = 0; |
18209 | | // A trie edge keeps its literal segment length in edge_record::key_length, a |
18210 | | // uint16_t. A literal longer than that wraps around, so the trie would match |
18211 | | // a shorter, truncated length (e.g. a 65536-byte segment becomes length 0 and |
18212 | | // matches an empty segment). Keep such a route out of the trie and let the |
18213 | | // sequential matcher, which compares the whole segment, answer it. |
18214 | 0 | bool literal_fits_edge = true; |
18215 | 0 | for (const route_segment& s : route.segments) { |
18216 | 0 | if (s.kind != segment_kind::literal) { |
18217 | 0 | route.all_literal = false; |
18218 | 0 | if (s.kind == segment_kind::param) { |
18219 | 0 | n_params++; |
18220 | 0 | } else { |
18221 | 0 | route.has_wildcard = true; |
18222 | 0 | } |
18223 | 0 | } else if (s.text.size() > std::numeric_limits<uint16_t>::max()) { |
18224 | 0 | literal_fits_edge = false; |
18225 | 0 | } |
18226 | 0 | } |
18227 | 0 | const size_t n_captures = n_params + (route.has_wildcard ? 1 : 0); |
18228 | 0 | const bool trie_safe = !route.segments.empty() && |
18229 | 0 | route.segments.size() <= max_trie_pattern_segments && |
18230 | 0 | n_captures <= max_captures_per_route && |
18231 | 0 | literal_fits_edge; |
18232 | 0 | route.mode = trie_safe ? route_mode::trie : route_mode::sequential; |
18233 | 0 | } |
18234 | | |
18235 | | void approximate_kind_sequence(const std::vector<url_pattern_part>& parts, |
18236 | 0 | route_info& route) { |
18237 | 0 | std::vector<uint8_t> kinds; |
18238 | | // The route's segment shape, as far as it is known: literal segments carry |
18239 | | // their text, opaque ones (a ":name" group, alone or mixed with text) are |
18240 | | // params. Exact while every group is a ":name" segment wildcard, which |
18241 | | // cannot match '/': then the segment count and every literal position are |
18242 | | // certain. A custom "(...)" group, a "*" or a modifier can span segments, |
18243 | | // so from there on nothing is known and only the anchored literal prefix |
18244 | | // before it is kept. |
18245 | 0 | std::vector<route_segment> shape; |
18246 | 0 | std::string literal; |
18247 | 0 | bool started = false; |
18248 | 0 | bool open = false; |
18249 | 0 | bool leading_slash = false; // the pattern is anchored at a '/' |
18250 | 0 | bool exact = true; // no part can span a segment boundary |
18251 | 0 | bool tail_known = true; // segments after the last closed one are known |
18252 | 0 | uint8_t current = 0; |
18253 | | // Closes the open segment; `complete` is true only when a '/' of fixed |
18254 | | // text closed it, i.e. the segment is exactly what was accumulated. |
18255 | 0 | const auto close = [&](bool complete) { |
18256 | 0 | if (open) { |
18257 | 0 | kinds.push_back(current); |
18258 | 0 | if (complete || exact) { |
18259 | 0 | shape.push_back(current == 0 |
18260 | 0 | ? route_segment{segment_kind::literal, literal} |
18261 | 0 | : route_segment{segment_kind::param, {}}); |
18262 | 0 | } else { |
18263 | 0 | tail_known = false; |
18264 | 0 | } |
18265 | 0 | open = false; |
18266 | 0 | current = 0; |
18267 | 0 | } |
18268 | 0 | literal.clear(); |
18269 | 0 | }; |
18270 | 0 | const auto process_text = [&](std::string_view text) { |
18271 | 0 | for (const char c : text) { |
18272 | 0 | if (c == '/') { |
18273 | 0 | if (started) { |
18274 | 0 | close(true); |
18275 | 0 | } else { |
18276 | 0 | leading_slash = true; |
18277 | 0 | } |
18278 | 0 | started = true; |
18279 | 0 | open = true; |
18280 | 0 | current = 0; |
18281 | 0 | } else { |
18282 | 0 | if (!started) { |
18283 | 0 | started = true; |
18284 | 0 | } |
18285 | 0 | if (!open) { |
18286 | 0 | open = true; |
18287 | 0 | current = 0; |
18288 | 0 | } |
18289 | 0 | literal += c; |
18290 | 0 | } |
18291 | 0 | } |
18292 | 0 | }; |
18293 | 0 | const auto add_group = [&](uint8_t kind) { |
18294 | 0 | if (!open) { |
18295 | 0 | started = true; |
18296 | 0 | open = true; |
18297 | 0 | current = 0; |
18298 | 0 | } |
18299 | 0 | current = current < kind ? kind : current; |
18300 | 0 | }; |
18301 | 0 | for (const url_pattern_part& part : parts) { |
18302 | 0 | if (part.type == url_pattern_part_type::FULL_WILDCARD || |
18303 | 0 | part.modifier != url_pattern_part_modifier::none) { |
18304 | | // A greedy or modified group can span segments: treat the rest of the |
18305 | | // route as a wildcard tail and stop. A "/" prefix closes the previous |
18306 | | // segment only when this part must occur. An optional ("?") or |
18307 | | // zero-or-more ("*") part, prefix included, may be absent, so the text |
18308 | | // after it stays in the same segment ("/reports{/:id}?.json" matches |
18309 | | // "/reports.json"). Treating that "/" as a definite boundary certified |
18310 | | // a segment the input does not have, and the shape check rejected the |
18311 | | // match before the provider ran. |
18312 | 0 | exact = false; |
18313 | 0 | const bool must_occur = |
18314 | 0 | part.modifier != url_pattern_part_modifier::optional && |
18315 | 0 | part.modifier != url_pattern_part_modifier::zero_or_more; |
18316 | 0 | close(must_occur && part.prefix == "/"); |
18317 | 0 | tail_known = false; |
18318 | 0 | kinds.push_back(2); |
18319 | 0 | break; |
18320 | 0 | } |
18321 | 0 | if (part.type == url_pattern_part_type::FIXED_TEXT) { |
18322 | 0 | process_text(part.value); |
18323 | 0 | } else { // SEGMENT_WILDCARD or REGEXP, modifier none |
18324 | 0 | if (part.type == url_pattern_part_type::REGEXP) { |
18325 | 0 | exact = false; // a custom group may match '/' |
18326 | 0 | } |
18327 | 0 | process_text(part.prefix); |
18328 | 0 | add_group(1); |
18329 | 0 | process_text(part.suffix); |
18330 | 0 | } |
18331 | 0 | } |
18332 | 0 | close(exact); |
18333 | 0 | uint64_t seq = 0; |
18334 | 0 | for (size_t j = 0; j < kinds.size() && j < 32; j++) { |
18335 | 0 | seq |= static_cast<uint64_t>(kinds[j]) << (62 - 2 * j); |
18336 | 0 | } |
18337 | 0 | route.kind_sequence = seq; |
18338 | 0 | route.kind_length = |
18339 | 0 | static_cast<uint8_t>(kinds.size() < 255 ? kinds.size() : 255); |
18340 | 0 | route.mode = route_mode::regexp; |
18341 | 0 | route.all_literal = false; |
18342 | 0 | route.segments.clear(); |
18343 | 0 | if (!leading_slash) { |
18344 | | // Not anchored at '/': nothing about the segments is known. |
18345 | 0 | route.has_wildcard = true; |
18346 | 0 | return; |
18347 | 0 | } |
18348 | | // has_wildcard here means "the tail is unconstrained": the input needs at |
18349 | | // least segments.size() segments; otherwise exactly that many. |
18350 | 0 | route.has_wildcard = !(exact && tail_known); |
18351 | 0 | if (route.has_wildcard) { |
18352 | | // Keep only the anchored literal prefix. |
18353 | 0 | size_t n_prefix = 0; |
18354 | 0 | while (n_prefix < shape.size() && |
18355 | 0 | shape[n_prefix].kind == segment_kind::literal) { |
18356 | 0 | n_prefix++; |
18357 | 0 | } |
18358 | 0 | shape.resize(n_prefix); |
18359 | 0 | } |
18360 | 0 | route.segments = std::move(shape); |
18361 | 0 | } |
18362 | | |
18363 | 0 | compiled_routes compile_route_set(std::vector<route_info>& routes) { |
18364 | 0 | builder_tables r{}; |
18365 | 0 | const std::vector<transient_node> t = build_trie(routes); |
18366 | 0 | compile_route_records(r, routes); |
18367 | 0 | const std::vector<int32_t> order = layout_nodes(r, t); |
18368 | 0 | compile_dispatch(r, t, order); |
18369 | 0 | encode_leaf_shortcuts(r); // last: must not confuse the stages above |
18370 | 0 | build_segment_table(r, routes); |
18371 | 0 | build_aux_table(r, routes); |
18372 | 0 | compiled_routes out = pack_arena(r); |
18373 | 0 | out.group_names.resize(routes.size()); |
18374 | 0 | for (size_t i = 0; i < routes.size(); i++) { |
18375 | 0 | if (routes[i].mode != route_mode::regexp) { |
18376 | 0 | out.group_names[i] = routes[i].group_names; |
18377 | 0 | } |
18378 | 0 | } |
18379 | 0 | return out; |
18380 | 0 | } |
18381 | | |
18382 | | } // namespace ada::url_pattern_list_compiler |
18383 | | |
18384 | | namespace ada::url_pattern_list_detail { |
18385 | | |
18386 | | tl::expected<compiled_routes, errors> compile_pathname_patterns( |
18387 | 0 | std::span<const std::string> patterns, bool ignore_case) { |
18388 | 0 | namespace compiler = url_pattern_list_compiler; |
18389 | 0 | std::vector<compiler::route_info> routes; |
18390 | 0 | routes.reserve(patterns.size()); |
18391 | 0 | for (const std::string& pattern : patterns) { |
18392 | | // The pattern side goes through ada's own URLPattern machinery: the |
18393 | | // pattern parser tokenizes and canonicalizes exactly as a URLPattern |
18394 | | // pathname component would. |
18395 | 0 | auto options = url_pattern_compile_component_options::PATHNAME; |
18396 | 0 | auto part_list = url_pattern_helpers::parse_pattern_string( |
18397 | 0 | pattern, options, url_pattern_helpers::canonicalize_pathname); |
18398 | 0 | if (!part_list) { |
18399 | 0 | return tl::unexpected(part_list.error()); |
18400 | 0 | } |
18401 | 0 | compiler::route_info route{}; |
18402 | 0 | if (compiler::classify_parts(*part_list, route.segments, |
18403 | 0 | route.group_names)) { |
18404 | 0 | compiler::finalize_route(route); |
18405 | 0 | } else { |
18406 | | // The pattern needs URLPattern regexp semantics: the caller compiles |
18407 | | // it as a pathname component through the provider; it participates |
18408 | | // in the priority order via its approximated kind sequence. |
18409 | 0 | compiler::approximate_kind_sequence(*part_list, route); |
18410 | 0 | } |
18411 | 0 | if (ignore_case) { |
18412 | | // The compiled literals are ASCII-folded; the matcher folds the input |
18413 | | // the same way. |
18414 | 0 | for (compiler::route_segment& s : route.segments) { |
18415 | 0 | if (s.kind == compiler::segment_kind::literal) { |
18416 | 0 | ascii_fold(s.text.data(), static_cast<uint32_t>(s.text.size()), |
18417 | 0 | s.text.data()); |
18418 | 0 | } |
18419 | 0 | } |
18420 | 0 | } |
18421 | 0 | routes.push_back(std::move(route)); |
18422 | 0 | } |
18423 | 0 | compiled_routes compiled = compiler::compile_route_set(routes); |
18424 | 0 | compiled.ignore_case = ignore_case ? 1 : 0; |
18425 | 0 | return compiled; |
18426 | 0 | } |
18427 | | |
18428 | | namespace { |
18429 | | |
18430 | | // Literal-segment compare against the blob, folding the input on request |
18431 | | // (the blob text is already folded). |
18432 | | bool literal_equals(std::string_view s, const char* text, uint32_t length, |
18433 | 0 | bool fold_input) noexcept { |
18434 | 0 | if (s.size() != length) { |
18435 | 0 | return false; |
18436 | 0 | } |
18437 | 0 | if (!fold_input) { |
18438 | 0 | return s.size() == 0 || std::memcmp(s.data(), text, s.size()) == 0; |
18439 | 0 | } |
18440 | 0 | for (size_t i = 0; i < s.size(); i++) { |
18441 | 0 | const uint8_t c = static_cast<uint8_t>(s[i]); |
18442 | 0 | const char folded = |
18443 | 0 | static_cast<char>(c | ((c >= 'A' && c <= 'Z') ? 0x20u : 0u)); |
18444 | 0 | if (folded != text[i]) { |
18445 | 0 | return false; |
18446 | 0 | } |
18447 | 0 | } |
18448 | 0 | return true; |
18449 | 0 | } |
18450 | | |
18451 | | } // namespace |
18452 | | |
18453 | | // Kept out of line on purpose: inlined into the walk, this loop cost the |
18454 | | // static and ":param" paths, which never run it, about 5 ns through register |
18455 | | // allocation; as a call it costs only wildcard hits. It lives in this |
18456 | | // translation unit rather than the header because MSVC's ada_never_inline |
18457 | | // expands to __declspec(noinline) with no inline linkage, so a definition in |
18458 | | // the header is emitted in every translation unit and the link fails. |
18459 | | // |
18460 | | // On AArch64 whole 16-byte blocks go through NEON (a running byte minimum); |
18461 | | // the rest is SWAR, 8 bytes per step: "some byte is below 0x20" ("hasless" |
18462 | | // of Bit Twiddling Hacks) is exact as a yes/no answer, because a borrow can |
18463 | | // only leave a lane that itself qualifies. Only a tail holding a control |
18464 | | // byte gets the exact byte check. |
18465 | 0 | bool wildcard_tail_ok(const char* p, uint32_t n) noexcept { |
18466 | 0 | constexpr uint64_t spaces = 0x2020202020202020ull; |
18467 | 0 | constexpr uint64_t highs = 0x8080808080808080ull; |
18468 | 0 | const auto below_space = [](uint64_t x) noexcept { |
18469 | 0 | return (x - spaces) & ~x & highs; |
18470 | 0 | }; |
18471 | 0 | uint64_t control = 0; |
18472 | 0 | uint32_t i = 0; |
18473 | | #if ADA_NEON |
18474 | | if (n >= 16) { |
18475 | | uint8x16_t lowest = vdupq_n_u8(0xFF); |
18476 | | for (; i + 16 <= n; i += 16) { |
18477 | | lowest = |
18478 | | vminq_u8(lowest, vld1q_u8(reinterpret_cast<const uint8_t*>(p + i))); |
18479 | | } |
18480 | | control = vminvq_u8(lowest) < 0x20 ? 1 : 0; |
18481 | | } |
18482 | | #endif |
18483 | 0 | for (; i + 8 <= n; i += 8) { |
18484 | 0 | control |= below_space(load8_le(p + i)); |
18485 | 0 | } |
18486 | 0 | if (i < n) { // 1..7 bytes, padded with spaces |
18487 | 0 | control |= below_space(gather_le(p + i, n - i) | |
18488 | 0 | (spaces & ~low_bytes_mask(n - i))); |
18489 | 0 | } |
18490 | 0 | if (control == 0) { |
18491 | 0 | return true; |
18492 | 0 | } |
18493 | 0 | for (uint32_t j = 0; j < n; j++) { |
18494 | 0 | if (p[j] == '\n' || p[j] == '\r') { |
18495 | 0 | return false; |
18496 | 0 | } |
18497 | 0 | } |
18498 | 0 | return true; |
18499 | 0 | } |
18500 | | |
18501 | | bool match_regexp_shape(const compiled_routes& r, uint32_t route, |
18502 | 0 | std::string_view pathname, bool fold_input) noexcept { |
18503 | 0 | const route_record& rt = r.section<route_record>(r.routes_offset)[route]; |
18504 | 0 | const segment_record* segs = |
18505 | 0 | r.section<segment_record>(r.segments_offset) + rt.segment_first; |
18506 | 0 | const char* blob = r.section<char>(r.blob_offset); |
18507 | 0 | if (rt.segment_count == 0 && rt.wild != 0) { |
18508 | 0 | return true; // nothing is known about the route's shape |
18509 | 0 | } |
18510 | 0 | if (pathname.empty() || pathname[0] != '/') { |
18511 | 0 | return false; // a known shape always starts with '/' |
18512 | 0 | } |
18513 | 0 | size_t seg_start = 1; |
18514 | 0 | for (uint32_t si = 0; si < rt.segment_count; si++) { |
18515 | 0 | if (seg_start > pathname.size()) { |
18516 | 0 | return false; // fewer segments than the shape |
18517 | 0 | } |
18518 | 0 | const size_t slash = pathname.find('/', seg_start); |
18519 | 0 | const size_t seg_end = |
18520 | 0 | slash == std::string_view::npos ? pathname.size() : slash; |
18521 | 0 | const std::string_view s(pathname.data() + seg_start, seg_end - seg_start); |
18522 | 0 | if (segs[si].kind == 0) { // literal |
18523 | 0 | if (!literal_equals(s, blob + segs[si].text_offset, segs[si].text_length, |
18524 | 0 | fold_input)) { |
18525 | 0 | return false; |
18526 | 0 | } |
18527 | 0 | } else if (s.empty()) { |
18528 | 0 | return false; // a ":name" group, mixed or not, never binds "" |
18529 | 0 | } |
18530 | 0 | seg_start = seg_end + 1; |
18531 | 0 | } |
18532 | | // An exact shape admits no further segments. |
18533 | 0 | return rt.wild != 0 || seg_start == pathname.size() + 1; |
18534 | 0 | } |
18535 | | |
18536 | | bool match_route_sequential(const compiled_routes& r, uint32_t route, |
18537 | | std::string_view pathname, bool fold_input, |
18538 | 0 | engine_result& result) noexcept { |
18539 | 0 | using url_pattern_list_limits::max_captures_per_route; |
18540 | 0 | result.capture_count = 0; |
18541 | 0 | result.captures_truncated = false; |
18542 | 0 | const route_record& rt = r.section<route_record>(r.routes_offset)[route]; |
18543 | 0 | const segment_record* segs = |
18544 | 0 | r.section<segment_record>(r.segments_offset) + rt.segment_first; |
18545 | 0 | const char* blob = r.section<char>(r.blob_offset); |
18546 | 0 | const size_t n_pattern = rt.segment_count; |
18547 | 0 | if (n_pattern == 0) { |
18548 | 0 | return pathname.empty(); // the empty pattern matches only "" |
18549 | 0 | } |
18550 | 0 | if (pathname.empty() || pathname[0] != '/') { |
18551 | 0 | return false; |
18552 | 0 | } |
18553 | 0 | const bool wild = rt.wild != 0; // wildcard is always the last segment |
18554 | 0 | const size_t n_fixed = wild ? n_pattern - 1 : n_pattern; |
18555 | 0 | uint32_t total_captures = 0; |
18556 | 0 | const auto add_capture = [&](size_t offset, size_t length) { |
18557 | 0 | if (total_captures < max_captures_per_route) { |
18558 | 0 | result.captures[total_captures] = {static_cast<uint32_t>(offset), |
18559 | 0 | static_cast<uint32_t>(length)}; |
18560 | 0 | } else { |
18561 | 0 | result.captures_truncated = true; |
18562 | 0 | } |
18563 | 0 | total_captures++; |
18564 | 0 | }; |
18565 | 0 | size_t seg_start = 1; |
18566 | 0 | for (size_t si = 0; si < n_fixed; si++) { |
18567 | 0 | if (seg_start > pathname.size()) { |
18568 | 0 | return false; // the input has fewer segments than the pattern |
18569 | 0 | } |
18570 | 0 | const size_t slash = pathname.find('/', seg_start); |
18571 | 0 | const size_t seg_end = |
18572 | 0 | slash == std::string_view::npos ? pathname.size() : slash; |
18573 | | // seg_start <= pathname.size() was checked above, so this is in range |
18574 | | // (spelled without substr to keep the function provably non-throwing). |
18575 | 0 | const std::string_view s(pathname.data() + seg_start, seg_end - seg_start); |
18576 | 0 | if (segs[si].kind == 0) { // literal |
18577 | 0 | if (!literal_equals(s, blob + segs[si].text_offset, segs[si].text_length, |
18578 | 0 | fold_input)) { |
18579 | 0 | return false; |
18580 | 0 | } |
18581 | 0 | } else { // param: binds one non-empty segment |
18582 | 0 | if (s.empty()) { |
18583 | 0 | return false; |
18584 | 0 | } |
18585 | 0 | add_capture(seg_start, s.size()); |
18586 | 0 | } |
18587 | 0 | seg_start = seg_end + 1; |
18588 | 0 | } |
18589 | 0 | if (wild) { |
18590 | 0 | if (seg_start > pathname.size()) { |
18591 | 0 | return false; // the wildcard still needs its (possibly empty) segment |
18592 | 0 | } |
18593 | | // "(.*)" does not match a line terminator (see wildcard_tail_ok). |
18594 | 0 | if (pathname.find_first_of("\n\r", seg_start) != std::string_view::npos) { |
18595 | 0 | return false; |
18596 | 0 | } |
18597 | 0 | add_capture(seg_start, pathname.size() - seg_start); |
18598 | 0 | } else if (seg_start != pathname.size() + 1) { |
18599 | 0 | return false; // the input has more segments than the pattern |
18600 | 0 | } |
18601 | 0 | result.capture_count = total_captures < max_captures_per_route |
18602 | 0 | ? total_captures |
18603 | 0 | : max_captures_per_route; |
18604 | 0 | return true; |
18605 | 0 | } |
18606 | | |
18607 | | } // namespace ada::url_pattern_list_detail |
18608 | | #endif // ADA_INCLUDE_URL_PATTERN |
18609 | | /* end file src/url_pattern_list.cpp */ |
18610 | | #endif |
18611 | | #endif // ADA_INCLUDE_URL_PATTERN |
18612 | | |
18613 | | /* begin file src/ada_c.cpp */ |
18614 | | // NOLINTBEGIN(bugprone-exception-escape, |
18615 | | // bugprone-suspicious-stringview-data-usage) |
18616 | | |
18617 | 0 | ada::result<ada::url_aggregator>& get_instance(void* result) noexcept { |
18618 | 0 | return *(ada::result<ada::url_aggregator>*)result; |
18619 | 0 | } |
18620 | | |
18621 | | extern "C" { |
18622 | | typedef void* ada_url; |
18623 | | typedef void* ada_url_search_params; |
18624 | | typedef void* ada_strings; |
18625 | | typedef void* ada_url_search_params_keys_iter; |
18626 | | typedef void* ada_url_search_params_values_iter; |
18627 | | typedef void* ada_url_search_params_entries_iter; |
18628 | | |
18629 | | struct ada_string { |
18630 | | const char* data; |
18631 | | size_t length; |
18632 | | }; |
18633 | | |
18634 | | struct ada_owned_string { |
18635 | | const char* data; |
18636 | | size_t length; |
18637 | | }; |
18638 | | |
18639 | | struct ada_string_pair { |
18640 | | ada_string key; |
18641 | | ada_string value; |
18642 | | }; |
18643 | | |
18644 | 0 | ada_string ada_string_create(const char* data, size_t length) { |
18645 | 0 | ada_string out{}; |
18646 | 0 | out.data = data; |
18647 | 0 | out.length = length; |
18648 | 0 | return out; |
18649 | 0 | } |
18650 | | |
18651 | | struct ada_url_components { |
18652 | | /* |
18653 | | * By using 32-bit integers, we implicitly assume that the URL string |
18654 | | * cannot exceed 4 GB. |
18655 | | * |
18656 | | * https://user:pass@example.com:1234/foo/bar?baz#quux |
18657 | | * | | | | ^^^^| | | |
18658 | | * | | | | | | | `----- hash_start |
18659 | | * | | | | | | `--------- search_start |
18660 | | * | | | | | `----------------- pathname_start |
18661 | | * | | | | `--------------------- port |
18662 | | * | | | `----------------------- host_end |
18663 | | * | | `---------------------------------- host_start |
18664 | | * | `--------------------------------------- username_end |
18665 | | * `--------------------------------------------- protocol_end |
18666 | | */ |
18667 | | uint32_t protocol_end; |
18668 | | /** |
18669 | | * Username end is not `omitted` by default (-1) to make username and password |
18670 | | * getters less costly to implement. |
18671 | | */ |
18672 | | uint32_t username_end; |
18673 | | uint32_t host_start; |
18674 | | uint32_t host_end; |
18675 | | uint32_t port; |
18676 | | uint32_t pathname_start; |
18677 | | uint32_t search_start; |
18678 | | uint32_t hash_start; |
18679 | | }; |
18680 | | |
18681 | 0 | ada_url ada_parse(const char* input, size_t length) noexcept { |
18682 | 0 | return new ada::result<ada::url_aggregator>( |
18683 | 0 | ada::parse<ada::url_aggregator>(std::string_view(input, length))); |
18684 | 0 | } |
18685 | | |
18686 | | ada_url ada_parse_with_base(const char* input, size_t input_length, |
18687 | 0 | const char* base, size_t base_length) noexcept { |
18688 | 0 | auto base_out = |
18689 | 0 | ada::parse<ada::url_aggregator>(std::string_view(base, base_length)); |
18690 | |
|
18691 | 0 | if (!base_out) { |
18692 | 0 | return new ada::result<ada::url_aggregator>(base_out); |
18693 | 0 | } |
18694 | | |
18695 | 0 | return new ada::result<ada::url_aggregator>(ada::parse<ada::url_aggregator>( |
18696 | 0 | std::string_view(input, input_length), &base_out.value())); |
18697 | 0 | } |
18698 | | |
18699 | 0 | bool ada_can_parse(const char* input, size_t length) noexcept { |
18700 | 0 | return ada::can_parse(std::string_view(input, length)); |
18701 | 0 | } |
18702 | | |
18703 | | bool ada_can_parse_with_base(const char* input, size_t input_length, |
18704 | 0 | const char* base, size_t base_length) noexcept { |
18705 | 0 | std::string_view base_view(base, base_length); |
18706 | 0 | return ada::can_parse(std::string_view(input, input_length), &base_view); |
18707 | 0 | } |
18708 | | |
18709 | 0 | void ada_free(ada_url result) noexcept { |
18710 | 0 | auto* r = (ada::result<ada::url_aggregator>*)result; |
18711 | 0 | delete r; |
18712 | 0 | } |
18713 | | |
18714 | 0 | ada_url ada_copy(ada_url input) noexcept { |
18715 | 0 | ada::result<ada::url_aggregator>& r = get_instance(input); |
18716 | 0 | return new ada::result<ada::url_aggregator>(r); |
18717 | 0 | } |
18718 | | |
18719 | 0 | bool ada_is_valid(ada_url result) noexcept { |
18720 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18721 | 0 | return r.has_value(); |
18722 | 0 | } |
18723 | | |
18724 | | // caller must free the result with ada_free_owned_string |
18725 | 0 | ada_owned_string ada_get_origin(ada_url result) noexcept { |
18726 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18727 | 0 | ada_owned_string owned{}; |
18728 | 0 | if (!r) { |
18729 | 0 | owned.data = nullptr; |
18730 | 0 | owned.length = 0; |
18731 | 0 | return owned; |
18732 | 0 | } |
18733 | 0 | std::string out = r->get_origin(); |
18734 | 0 | owned.length = out.size(); |
18735 | 0 | owned.data = new char[owned.length]; |
18736 | 0 | memcpy((void*)owned.data, out.data(), owned.length); |
18737 | 0 | return owned; |
18738 | 0 | } |
18739 | | |
18740 | 0 | void ada_free_owned_string(ada_owned_string owned) noexcept { |
18741 | 0 | delete[] owned.data; |
18742 | 0 | } |
18743 | | |
18744 | 0 | ada_string ada_get_href(ada_url result) noexcept { |
18745 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18746 | 0 | if (!r) { |
18747 | 0 | return ada_string_create(nullptr, 0); |
18748 | 0 | } |
18749 | 0 | std::string_view out = r->get_href(); |
18750 | 0 | return ada_string_create(out.data(), out.length()); |
18751 | 0 | } |
18752 | | |
18753 | 0 | ada_string ada_get_username(ada_url result) noexcept { |
18754 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18755 | 0 | if (!r) { |
18756 | 0 | return ada_string_create(nullptr, 0); |
18757 | 0 | } |
18758 | 0 | std::string_view out = r->get_username(); |
18759 | 0 | return ada_string_create(out.data(), out.length()); |
18760 | 0 | } |
18761 | | |
18762 | 0 | ada_string ada_get_password(ada_url result) noexcept { |
18763 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18764 | 0 | if (!r) { |
18765 | 0 | return ada_string_create(nullptr, 0); |
18766 | 0 | } |
18767 | 0 | std::string_view out = r->get_password(); |
18768 | 0 | return ada_string_create(out.data(), out.length()); |
18769 | 0 | } |
18770 | | |
18771 | 0 | ada_string ada_get_port(ada_url result) noexcept { |
18772 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18773 | 0 | if (!r) { |
18774 | 0 | return ada_string_create(nullptr, 0); |
18775 | 0 | } |
18776 | 0 | std::string_view out = r->get_port(); |
18777 | 0 | return ada_string_create(out.data(), out.length()); |
18778 | 0 | } |
18779 | | |
18780 | 0 | ada_string ada_get_hash(ada_url result) noexcept { |
18781 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18782 | 0 | if (!r) { |
18783 | 0 | return ada_string_create(nullptr, 0); |
18784 | 0 | } |
18785 | 0 | std::string_view out = r->get_hash(); |
18786 | 0 | return ada_string_create(out.data(), out.length()); |
18787 | 0 | } |
18788 | | |
18789 | 0 | ada_string ada_get_host(ada_url result) noexcept { |
18790 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18791 | 0 | if (!r) { |
18792 | 0 | return ada_string_create(nullptr, 0); |
18793 | 0 | } |
18794 | 0 | std::string_view out = r->get_host(); |
18795 | 0 | return ada_string_create(out.data(), out.length()); |
18796 | 0 | } |
18797 | | |
18798 | 0 | ada_string ada_get_hostname(ada_url result) noexcept { |
18799 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18800 | 0 | if (!r) { |
18801 | 0 | return ada_string_create(nullptr, 0); |
18802 | 0 | } |
18803 | 0 | std::string_view out = r->get_hostname(); |
18804 | 0 | return ada_string_create(out.data(), out.length()); |
18805 | 0 | } |
18806 | | |
18807 | 0 | ada_string ada_get_pathname(ada_url result) noexcept { |
18808 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18809 | 0 | if (!r) { |
18810 | 0 | return ada_string_create(nullptr, 0); |
18811 | 0 | } |
18812 | 0 | std::string_view out = r->get_pathname(); |
18813 | 0 | return ada_string_create(out.data(), out.length()); |
18814 | 0 | } |
18815 | | |
18816 | 0 | ada_string ada_get_search(ada_url result) noexcept { |
18817 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18818 | 0 | if (!r) { |
18819 | 0 | return ada_string_create(nullptr, 0); |
18820 | 0 | } |
18821 | 0 | std::string_view out = r->get_search(); |
18822 | 0 | return ada_string_create(out.data(), out.length()); |
18823 | 0 | } |
18824 | | |
18825 | 0 | ada_string ada_get_protocol(ada_url result) noexcept { |
18826 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18827 | 0 | if (!r) { |
18828 | 0 | return ada_string_create(nullptr, 0); |
18829 | 0 | } |
18830 | 0 | std::string_view out = r->get_protocol(); |
18831 | 0 | return ada_string_create(out.data(), out.length()); |
18832 | 0 | } |
18833 | | |
18834 | 0 | uint8_t ada_get_host_type(ada_url result) noexcept { |
18835 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18836 | 0 | if (!r) { |
18837 | 0 | return 0; |
18838 | 0 | } |
18839 | 0 | return r->host_type; |
18840 | 0 | } |
18841 | | |
18842 | 0 | uint8_t ada_get_scheme_type(ada_url result) noexcept { |
18843 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18844 | 0 | if (!r) { |
18845 | 0 | return 0; |
18846 | 0 | } |
18847 | 0 | return r->type; |
18848 | 0 | } |
18849 | | |
18850 | 0 | bool ada_set_href(ada_url result, const char* input, size_t length) noexcept { |
18851 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18852 | 0 | if (!r) { |
18853 | 0 | return false; |
18854 | 0 | } |
18855 | 0 | return r->set_href(std::string_view(input, length)); |
18856 | 0 | } |
18857 | | |
18858 | 0 | bool ada_set_host(ada_url result, const char* input, size_t length) noexcept { |
18859 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18860 | 0 | if (!r) { |
18861 | 0 | return false; |
18862 | 0 | } |
18863 | 0 | return r->set_host(std::string_view(input, length)); |
18864 | 0 | } |
18865 | | |
18866 | | bool ada_set_hostname(ada_url result, const char* input, |
18867 | 0 | size_t length) noexcept { |
18868 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18869 | 0 | if (!r) { |
18870 | 0 | return false; |
18871 | 0 | } |
18872 | 0 | return r->set_hostname(std::string_view(input, length)); |
18873 | 0 | } |
18874 | | |
18875 | | bool ada_set_protocol(ada_url result, const char* input, |
18876 | 0 | size_t length) noexcept { |
18877 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18878 | 0 | if (!r) { |
18879 | 0 | return false; |
18880 | 0 | } |
18881 | 0 | return r->set_protocol(std::string_view(input, length)); |
18882 | 0 | } |
18883 | | |
18884 | | bool ada_set_username(ada_url result, const char* input, |
18885 | 0 | size_t length) noexcept { |
18886 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18887 | 0 | if (!r) { |
18888 | 0 | return false; |
18889 | 0 | } |
18890 | 0 | return r->set_username(std::string_view(input, length)); |
18891 | 0 | } |
18892 | | |
18893 | | bool ada_set_password(ada_url result, const char* input, |
18894 | 0 | size_t length) noexcept { |
18895 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18896 | 0 | if (!r) { |
18897 | 0 | return false; |
18898 | 0 | } |
18899 | 0 | return r->set_password(std::string_view(input, length)); |
18900 | 0 | } |
18901 | | |
18902 | 0 | bool ada_set_port(ada_url result, const char* input, size_t length) noexcept { |
18903 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18904 | 0 | if (!r) { |
18905 | 0 | return false; |
18906 | 0 | } |
18907 | 0 | return r->set_port(std::string_view(input, length)); |
18908 | 0 | } |
18909 | | |
18910 | | bool ada_set_pathname(ada_url result, const char* input, |
18911 | 0 | size_t length) noexcept { |
18912 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18913 | 0 | if (!r) { |
18914 | 0 | return false; |
18915 | 0 | } |
18916 | 0 | return r->set_pathname(std::string_view(input, length)); |
18917 | 0 | } |
18918 | | |
18919 | | /** |
18920 | | * Update the search/query of the URL. |
18921 | | * |
18922 | | * If a URL has `?` as the search value, passing empty string to this function |
18923 | | * does not remove the attribute. If you need to remove it, please use |
18924 | | * `ada_clear_search` method. |
18925 | | */ |
18926 | 0 | void ada_set_search(ada_url result, const char* input, size_t length) noexcept { |
18927 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18928 | 0 | if (r) { |
18929 | 0 | r->set_search(std::string_view(input, length)); |
18930 | 0 | } |
18931 | 0 | } |
18932 | | |
18933 | | /** |
18934 | | * Update the hash/fragment of the URL. |
18935 | | * |
18936 | | * If a URL has `#` as the hash value, passing empty string to this function |
18937 | | * does not remove the attribute. If you need to remove it, please use |
18938 | | * `ada_clear_hash` method. |
18939 | | */ |
18940 | 0 | void ada_set_hash(ada_url result, const char* input, size_t length) noexcept { |
18941 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18942 | 0 | if (r) { |
18943 | 0 | r->set_hash(std::string_view(input, length)); |
18944 | 0 | } |
18945 | 0 | } |
18946 | | |
18947 | 0 | void ada_clear_port(ada_url result) noexcept { |
18948 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18949 | 0 | if (r) { |
18950 | 0 | r->clear_port(); |
18951 | 0 | } |
18952 | 0 | } |
18953 | | |
18954 | | /** |
18955 | | * Removes the hash of the URL. |
18956 | | * |
18957 | | * Despite `ada_set_hash` method, this function allows the complete |
18958 | | * removal of the hash attribute, even if it has a value of `#`. |
18959 | | */ |
18960 | 0 | void ada_clear_hash(ada_url result) noexcept { |
18961 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18962 | 0 | if (r) { |
18963 | 0 | r->clear_hash(); |
18964 | 0 | } |
18965 | 0 | } |
18966 | | |
18967 | | /** |
18968 | | * Removes the search of the URL. |
18969 | | * |
18970 | | * Despite `ada_set_search` method, this function allows the complete |
18971 | | * removal of the search attribute, even if it has a value of `?`. |
18972 | | */ |
18973 | 0 | void ada_clear_search(ada_url result) noexcept { |
18974 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18975 | 0 | if (r) { |
18976 | 0 | r->clear_search(); |
18977 | 0 | } |
18978 | 0 | } |
18979 | | |
18980 | 0 | bool ada_has_credentials(ada_url result) noexcept { |
18981 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18982 | 0 | if (!r) { |
18983 | 0 | return false; |
18984 | 0 | } |
18985 | 0 | return r->has_credentials(); |
18986 | 0 | } |
18987 | | |
18988 | 0 | bool ada_has_empty_hostname(ada_url result) noexcept { |
18989 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18990 | 0 | if (!r) { |
18991 | 0 | return false; |
18992 | 0 | } |
18993 | 0 | return r->has_empty_hostname(); |
18994 | 0 | } |
18995 | | |
18996 | 0 | bool ada_has_hostname(ada_url result) noexcept { |
18997 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
18998 | 0 | if (!r) { |
18999 | 0 | return false; |
19000 | 0 | } |
19001 | 0 | return r->has_hostname(); |
19002 | 0 | } |
19003 | | |
19004 | 0 | bool ada_has_non_empty_username(ada_url result) noexcept { |
19005 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19006 | 0 | if (!r) { |
19007 | 0 | return false; |
19008 | 0 | } |
19009 | 0 | return r->has_non_empty_username(); |
19010 | 0 | } |
19011 | | |
19012 | 0 | bool ada_has_non_empty_password(ada_url result) noexcept { |
19013 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19014 | 0 | if (!r) { |
19015 | 0 | return false; |
19016 | 0 | } |
19017 | 0 | return r->has_non_empty_password(); |
19018 | 0 | } |
19019 | | |
19020 | 0 | bool ada_has_port(ada_url result) noexcept { |
19021 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19022 | 0 | if (!r) { |
19023 | 0 | return false; |
19024 | 0 | } |
19025 | 0 | return r->has_port(); |
19026 | 0 | } |
19027 | | |
19028 | 0 | bool ada_has_password(ada_url result) noexcept { |
19029 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19030 | 0 | if (!r) { |
19031 | 0 | return false; |
19032 | 0 | } |
19033 | 0 | return r->has_password(); |
19034 | 0 | } |
19035 | | |
19036 | 0 | bool ada_has_hash(ada_url result) noexcept { |
19037 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19038 | 0 | if (!r) { |
19039 | 0 | return false; |
19040 | 0 | } |
19041 | 0 | return r->has_hash(); |
19042 | 0 | } |
19043 | | |
19044 | 0 | bool ada_has_search(ada_url result) noexcept { |
19045 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19046 | 0 | if (!r) { |
19047 | 0 | return false; |
19048 | 0 | } |
19049 | 0 | return r->has_search(); |
19050 | 0 | } |
19051 | | |
19052 | | // returns a pointer to the internal url_aggregator::url_components |
19053 | 0 | const ada_url_components* ada_get_components(ada_url result) noexcept { |
19054 | 0 | static_assert(sizeof(ada_url_components) == sizeof(ada::url_components)); |
19055 | 0 | ada::result<ada::url_aggregator>& r = get_instance(result); |
19056 | 0 | if (!r) { |
19057 | 0 | return nullptr; |
19058 | 0 | } |
19059 | 0 | return reinterpret_cast<const ada_url_components*>(&r->get_components()); |
19060 | 0 | } |
19061 | | |
19062 | 0 | ada_owned_string ada_idna_to_unicode(const char* input, size_t length) { |
19063 | 0 | std::string out = ada::idna::to_unicode(std::string_view(input, length)); |
19064 | 0 | ada_owned_string owned{}; |
19065 | 0 | owned.length = out.length(); |
19066 | 0 | owned.data = new char[owned.length]; |
19067 | 0 | memcpy((void*)owned.data, out.data(), owned.length); |
19068 | 0 | return owned; |
19069 | 0 | } |
19070 | | |
19071 | 0 | ada_owned_string ada_idna_to_ascii(const char* input, size_t length) { |
19072 | 0 | std::string out = ada::idna::to_ascii(std::string_view(input, length)); |
19073 | 0 | ada_owned_string owned{}; |
19074 | 0 | owned.length = out.size(); |
19075 | 0 | owned.data = new char[owned.length]; |
19076 | 0 | memcpy((void*)owned.data, out.data(), owned.length); |
19077 | 0 | return owned; |
19078 | 0 | } |
19079 | | |
19080 | | ada_url_search_params ada_parse_search_params(const char* input, |
19081 | 0 | size_t length) { |
19082 | 0 | return new ada::result<ada::url_search_params>( |
19083 | 0 | ada::url_search_params(std::string_view(input, length))); |
19084 | 0 | } |
19085 | | |
19086 | 0 | void ada_free_search_params(ada_url_search_params result) { |
19087 | 0 | auto* r = (ada::result<ada::url_search_params>*)result; |
19088 | 0 | delete r; |
19089 | 0 | } |
19090 | | |
19091 | 0 | ada_owned_string ada_search_params_to_string(ada_url_search_params result) { |
19092 | 0 | ada::result<ada::url_search_params>& r = |
19093 | 0 | *(ada::result<ada::url_search_params>*)result; |
19094 | 0 | if (!r) return ada_owned_string{nullptr, 0}; |
19095 | 0 | std::string out = r->to_string(); |
19096 | 0 | ada_owned_string owned{}; |
19097 | 0 | owned.length = out.size(); |
19098 | 0 | owned.data = new char[owned.length]; |
19099 | 0 | memcpy((void*)owned.data, out.data(), owned.length); |
19100 | 0 | return owned; |
19101 | 0 | } |
19102 | | |
19103 | 0 | size_t ada_search_params_size(ada_url_search_params result) { |
19104 | 0 | ada::result<ada::url_search_params>& r = |
19105 | 0 | *(ada::result<ada::url_search_params>*)result; |
19106 | 0 | if (!r) { |
19107 | 0 | return 0; |
19108 | 0 | } |
19109 | 0 | return r->size(); |
19110 | 0 | } |
19111 | | |
19112 | 0 | void ada_search_params_sort(ada_url_search_params result) { |
19113 | 0 | ada::result<ada::url_search_params>& r = |
19114 | 0 | *(ada::result<ada::url_search_params>*)result; |
19115 | 0 | if (r) { |
19116 | 0 | r->sort(); |
19117 | 0 | } |
19118 | 0 | } |
19119 | | |
19120 | | void ada_search_params_reset(ada_url_search_params result, const char* input, |
19121 | 0 | size_t length) { |
19122 | 0 | ada::result<ada::url_search_params>& r = |
19123 | 0 | *(ada::result<ada::url_search_params>*)result; |
19124 | 0 | if (r) { |
19125 | 0 | r->reset(std::string_view(input, length)); |
19126 | 0 | } |
19127 | 0 | } |
19128 | | |
19129 | | void ada_search_params_append(ada_url_search_params result, const char* key, |
19130 | | size_t key_length, const char* value, |
19131 | 0 | size_t value_length) { |
19132 | 0 | ada::result<ada::url_search_params>& r = |
19133 | 0 | *(ada::result<ada::url_search_params>*)result; |
19134 | 0 | if (r) { |
19135 | 0 | r->append(std::string_view(key, key_length), |
19136 | 0 | std::string_view(value, value_length)); |
19137 | 0 | } |
19138 | 0 | } |
19139 | | |
19140 | | void ada_search_params_set(ada_url_search_params result, const char* key, |
19141 | | size_t key_length, const char* value, |
19142 | 0 | size_t value_length) { |
19143 | 0 | ada::result<ada::url_search_params>& r = |
19144 | 0 | *(ada::result<ada::url_search_params>*)result; |
19145 | 0 | if (r) { |
19146 | 0 | r->set(std::string_view(key, key_length), |
19147 | 0 | std::string_view(value, value_length)); |
19148 | 0 | } |
19149 | 0 | } |
19150 | | |
19151 | | void ada_search_params_remove(ada_url_search_params result, const char* key, |
19152 | 0 | size_t key_length) { |
19153 | 0 | ada::result<ada::url_search_params>& r = |
19154 | 0 | *(ada::result<ada::url_search_params>*)result; |
19155 | 0 | if (r) { |
19156 | 0 | r->remove(std::string_view(key, key_length)); |
19157 | 0 | } |
19158 | 0 | } |
19159 | | |
19160 | | void ada_search_params_remove_value(ada_url_search_params result, |
19161 | | const char* key, size_t key_length, |
19162 | 0 | const char* value, size_t value_length) { |
19163 | 0 | ada::result<ada::url_search_params>& r = |
19164 | 0 | *(ada::result<ada::url_search_params>*)result; |
19165 | 0 | if (r) { |
19166 | 0 | r->remove(std::string_view(key, key_length), |
19167 | 0 | std::string_view(value, value_length)); |
19168 | 0 | } |
19169 | 0 | } |
19170 | | |
19171 | | bool ada_search_params_has(ada_url_search_params result, const char* key, |
19172 | 0 | size_t key_length) { |
19173 | 0 | ada::result<ada::url_search_params>& r = |
19174 | 0 | *(ada::result<ada::url_search_params>*)result; |
19175 | 0 | if (!r) { |
19176 | 0 | return false; |
19177 | 0 | } |
19178 | 0 | return r->has(std::string_view(key, key_length)); |
19179 | 0 | } |
19180 | | |
19181 | | bool ada_search_params_has_value(ada_url_search_params result, const char* key, |
19182 | | size_t key_length, const char* value, |
19183 | 0 | size_t value_length) { |
19184 | 0 | ada::result<ada::url_search_params>& r = |
19185 | 0 | *(ada::result<ada::url_search_params>*)result; |
19186 | 0 | if (!r) { |
19187 | 0 | return false; |
19188 | 0 | } |
19189 | 0 | return r->has(std::string_view(key, key_length), |
19190 | 0 | std::string_view(value, value_length)); |
19191 | 0 | } |
19192 | | |
19193 | | ada_string ada_search_params_get(ada_url_search_params result, const char* key, |
19194 | 0 | size_t key_length) { |
19195 | 0 | ada::result<ada::url_search_params>& r = |
19196 | 0 | *(ada::result<ada::url_search_params>*)result; |
19197 | 0 | if (!r) { |
19198 | 0 | return ada_string_create(nullptr, 0); |
19199 | 0 | } |
19200 | 0 | auto found = r->get(std::string_view(key, key_length)); |
19201 | 0 | if (!found.has_value()) { |
19202 | 0 | return ada_string_create(nullptr, 0); |
19203 | 0 | } |
19204 | 0 | return ada_string_create(found->data(), found->length()); |
19205 | 0 | } |
19206 | | |
19207 | | ada_strings ada_search_params_get_all(ada_url_search_params result, |
19208 | 0 | const char* key, size_t key_length) { |
19209 | 0 | ada::result<ada::url_search_params>& r = |
19210 | 0 | *(ada::result<ada::url_search_params>*)result; |
19211 | 0 | if (!r) { |
19212 | 0 | return new ada::result<std::vector<std::string>>( |
19213 | 0 | std::vector<std::string>()); |
19214 | 0 | } |
19215 | 0 | return new ada::result<std::vector<std::string>>( |
19216 | 0 | r->get_all(std::string_view(key, key_length))); |
19217 | 0 | } |
19218 | | |
19219 | | ada_url_search_params_keys_iter ada_search_params_get_keys( |
19220 | 0 | ada_url_search_params result) { |
19221 | 0 | ada::result<ada::url_search_params>& r = |
19222 | 0 | *(ada::result<ada::url_search_params>*)result; |
19223 | 0 | if (!r) { |
19224 | 0 | return new ada::result<ada::url_search_params_keys_iter>( |
19225 | 0 | ada::url_search_params_keys_iter()); |
19226 | 0 | } |
19227 | 0 | return new ada::result<ada::url_search_params_keys_iter>(r->get_keys()); |
19228 | 0 | } |
19229 | | |
19230 | | ada_url_search_params_values_iter ada_search_params_get_values( |
19231 | 0 | ada_url_search_params result) { |
19232 | 0 | ada::result<ada::url_search_params>& r = |
19233 | 0 | *(ada::result<ada::url_search_params>*)result; |
19234 | 0 | if (!r) { |
19235 | 0 | return new ada::result<ada::url_search_params_values_iter>( |
19236 | 0 | ada::url_search_params_values_iter()); |
19237 | 0 | } |
19238 | 0 | return new ada::result<ada::url_search_params_values_iter>(r->get_values()); |
19239 | 0 | } |
19240 | | |
19241 | | ada_url_search_params_entries_iter ada_search_params_get_entries( |
19242 | 0 | ada_url_search_params result) { |
19243 | 0 | ada::result<ada::url_search_params>& r = |
19244 | 0 | *(ada::result<ada::url_search_params>*)result; |
19245 | 0 | if (!r) { |
19246 | 0 | return new ada::result<ada::url_search_params_entries_iter>( |
19247 | 0 | ada::url_search_params_entries_iter()); |
19248 | 0 | } |
19249 | 0 | return new ada::result<ada::url_search_params_entries_iter>(r->get_entries()); |
19250 | 0 | } |
19251 | | |
19252 | 0 | void ada_free_strings(ada_strings result) { |
19253 | 0 | auto* r = (ada::result<std::vector<std::string>>*)result; |
19254 | 0 | delete r; |
19255 | 0 | } |
19256 | | |
19257 | 0 | size_t ada_strings_size(ada_strings result) { |
19258 | 0 | auto* r = (ada::result<std::vector<std::string>>*)result; |
19259 | 0 | if (!r) { |
19260 | 0 | return 0; |
19261 | 0 | } |
19262 | 0 | return (*r)->size(); |
19263 | 0 | } |
19264 | | |
19265 | 0 | ada_string ada_strings_get(ada_strings result, size_t index) { |
19266 | 0 | auto* r = (ada::result<std::vector<std::string>>*)result; |
19267 | 0 | if (!r || index >= (*r)->size()) { |
19268 | 0 | return ada_string_create(nullptr, 0); |
19269 | 0 | } |
19270 | 0 | std::string_view view = (*r)->at(index); |
19271 | 0 | return ada_string_create(view.data(), view.length()); |
19272 | 0 | } |
19273 | | |
19274 | 0 | void ada_free_search_params_keys_iter(ada_url_search_params_keys_iter result) { |
19275 | 0 | auto* r = (ada::result<ada::url_search_params_keys_iter>*)result; |
19276 | 0 | delete r; |
19277 | 0 | } |
19278 | | |
19279 | | ada_string ada_search_params_keys_iter_next( |
19280 | 0 | ada_url_search_params_keys_iter result) { |
19281 | 0 | auto* r = (ada::result<ada::url_search_params_keys_iter>*)result; |
19282 | 0 | if (!r) { |
19283 | 0 | return ada_string_create(nullptr, 0); |
19284 | 0 | } |
19285 | 0 | auto next = (*r)->next(); |
19286 | 0 | if (!next.has_value()) { |
19287 | 0 | return ada_string_create(nullptr, 0); |
19288 | 0 | } |
19289 | 0 | return ada_string_create(next->data(), next->length()); |
19290 | 0 | } |
19291 | | |
19292 | | bool ada_search_params_keys_iter_has_next( |
19293 | 0 | ada_url_search_params_keys_iter result) { |
19294 | 0 | auto* r = (ada::result<ada::url_search_params_keys_iter>*)result; |
19295 | 0 | if (!r) { |
19296 | 0 | return false; |
19297 | 0 | } |
19298 | 0 | return (*r)->has_next(); |
19299 | 0 | } |
19300 | | |
19301 | | void ada_free_search_params_values_iter( |
19302 | 0 | ada_url_search_params_values_iter result) { |
19303 | 0 | auto* r = (ada::result<ada::url_search_params_values_iter>*)result; |
19304 | 0 | delete r; |
19305 | 0 | } |
19306 | | |
19307 | | ada_string ada_search_params_values_iter_next( |
19308 | 0 | ada_url_search_params_values_iter result) { |
19309 | 0 | auto* r = (ada::result<ada::url_search_params_values_iter>*)result; |
19310 | 0 | if (!r) { |
19311 | 0 | return ada_string_create(nullptr, 0); |
19312 | 0 | } |
19313 | 0 | auto next = (*r)->next(); |
19314 | 0 | if (!next.has_value()) { |
19315 | 0 | return ada_string_create(nullptr, 0); |
19316 | 0 | } |
19317 | 0 | return ada_string_create(next->data(), next->length()); |
19318 | 0 | } |
19319 | | |
19320 | | bool ada_search_params_values_iter_has_next( |
19321 | 0 | ada_url_search_params_values_iter result) { |
19322 | 0 | auto* r = (ada::result<ada::url_search_params_values_iter>*)result; |
19323 | 0 | if (!r) { |
19324 | 0 | return false; |
19325 | 0 | } |
19326 | 0 | return (*r)->has_next(); |
19327 | 0 | } |
19328 | | |
19329 | | void ada_free_search_params_entries_iter( |
19330 | 0 | ada_url_search_params_entries_iter result) { |
19331 | 0 | auto* r = (ada::result<ada::url_search_params_entries_iter>*)result; |
19332 | 0 | delete r; |
19333 | 0 | } |
19334 | | |
19335 | | ada_string_pair ada_search_params_entries_iter_next( |
19336 | 0 | ada_url_search_params_entries_iter result) { |
19337 | 0 | auto* r = (ada::result<ada::url_search_params_entries_iter>*)result; |
19338 | 0 | if (!r) return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; |
19339 | 0 | auto next = (*r)->next(); |
19340 | 0 | if (!next.has_value()) { |
19341 | 0 | return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; |
19342 | 0 | } |
19343 | 0 | return ada_string_pair{ |
19344 | 0 | ada_string_create(next->first.data(), next->first.length()), |
19345 | 0 | ada_string_create(next->second.data(), next->second.length())}; |
19346 | 0 | } |
19347 | | |
19348 | | bool ada_search_params_entries_iter_has_next( |
19349 | 0 | ada_url_search_params_entries_iter result) { |
19350 | 0 | auto* r = (ada::result<ada::url_search_params_entries_iter>*)result; |
19351 | 0 | if (!r) { |
19352 | 0 | return false; |
19353 | 0 | } |
19354 | 0 | return (*r)->has_next(); |
19355 | 0 | } |
19356 | | |
19357 | 0 | void ada_set_max_input_length(uint32_t length) noexcept { |
19358 | 0 | ada::set_max_input_length(length); |
19359 | 0 | } |
19360 | | |
19361 | 0 | uint32_t ada_get_max_input_length() noexcept { |
19362 | 0 | return ada::get_max_input_length(); |
19363 | 0 | } |
19364 | | |
19365 | | typedef struct { |
19366 | | int major; |
19367 | | int minor; |
19368 | | int revision; |
19369 | | } ada_version_components; |
19370 | | |
19371 | 0 | const char* ada_get_version() { return ADA_VERSION; } |
19372 | | |
19373 | 0 | ada_version_components ada_get_version_components() { |
19374 | 0 | return ada_version_components{ |
19375 | 0 | .major = ada::ADA_VERSION_MAJOR, |
19376 | 0 | .minor = ada::ADA_VERSION_MINOR, |
19377 | 0 | .revision = ada::ADA_VERSION_REVISION, |
19378 | 0 | }; |
19379 | 0 | } |
19380 | | |
19381 | | } // extern "C" |
19382 | | // NOLINTEND(bugprone-exception-escape, |
19383 | | // bugprone-suspicious-stringview-data-usage) |
19384 | | /* end file src/ada_c.cpp */ |
19385 | | /* end file src/ada.cpp */ |