Coverage Report

Created: 2026-11-12 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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) const
Line
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()() const
Unexecuted 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()() const
Line
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()() const
Line
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()() const
Line
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()() const
Line
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()() const
Line
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()() const
Line
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()() const
Line
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()() const
Unexecuted 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()() const
Unexecuted 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 */