diff --git a/src/iceberg/CMakeLists.txt b/src/iceberg/CMakeLists.txt index 4cde4fb23f..b2dac4dfb5 100644 --- a/src/iceberg/CMakeLists.txt +++ b/src/iceberg/CMakeLists.txt @@ -158,6 +158,7 @@ set(ICEBERG_SOURCES util/decimal.cc util/gzip_internal.cc util/location_util.cc + util/mumbling_bitmap_internal.cc util/murmurhash3_internal.cc util/property_util.cc util/retry_util.cc diff --git a/src/iceberg/benchmark/CMakeLists.txt b/src/iceberg/benchmark/CMakeLists.txt index 5d3c19d0f5..0bf98ce5b4 100644 --- a/src/iceberg/benchmark/CMakeLists.txt +++ b/src/iceberg/benchmark/CMakeLists.txt @@ -22,3 +22,9 @@ target_link_libraries(benchmark_smoke PRIVATE "$,iceberg_static,iceberg_shared>" "$,benchmark::benchmark,benchmark>" ) + +add_executable(mumbling_bitmap_benchmark mumbling_bitmap_benchmark.cc) +target_link_libraries(mumbling_bitmap_benchmark + PRIVATE "$,iceberg_static,iceberg_shared>" + "$,benchmark::benchmark,benchmark>" +) diff --git a/src/iceberg/benchmark/mumbling_bitmap_benchmark.cc b/src/iceberg/benchmark/mumbling_bitmap_benchmark.cc new file mode 100644 index 0000000000..a33c96eb51 --- /dev/null +++ b/src/iceberg/benchmark/mumbling_bitmap_benchmark.cc @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Microbenchmarks for the Mumbling bitmap reader. +// +// Build with -DICEBERG_BUILD_BENCHMARKS=ON and run, for example: +// ./build/src/iceberg/benchmark/mumbling_bitmap_benchmark --benchmark_filter=Pfor +// +// The inputs are serialized with the test encoder in +// iceberg/test/mumbling_bitmap_test_util.h, which picks PFOR bit widths the way +// the Java encoder does (checked against Java-generated fixtures in +// mumbling_bitmap_internal_test.cc). + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iceberg/test/mumbling_bitmap_test_util.h" +#include "iceberg/util/mumbling_bitmap_internal.h" + +namespace iceberg { +namespace { + +using mumbling_test::BuildBitmapFromPositions; +using mumbling_test::Bytes; +using mumbling_test::EncodePfor; +using mumbling_test::kBestWidth; + +constexpr int64_t kMaxPositions = MumblingBitmapView::kMaxCardinality; +constexpr uint32_t kSeed = 42; + +// --------------------------------------------------------------------------- +// PFOR descriptor decoding +// --------------------------------------------------------------------------- + +// Value distributions for PFOR inputs, modeled on Java's PFORRandomData. +enum class PforData { + kConstant, // every value is the same (one bit width of 0) + kSmall, // uniform 0-3 + kExceptions1Pct, // 0-3 with 1% exceptions in 0-255 + kExceptions10Pct, // 0-3 with 10% exceptions in 0-255 + kUniform, // uniform 0-255 (stored as raw bytes) +}; + +std::vector MakePforValues(PforData data, size_t count) { + std::mt19937 rng(kSeed); + std::uniform_int_distribution small(0, 3); + std::uniform_int_distribution any(0, 255); + std::uniform_real_distribution unit(0.0, 1.0); + std::vector values(count); + for (auto& value : values) { + switch (data) { + case PforData::kConstant: + value = 5; + break; + case PforData::kSmall: + value = static_cast(small(rng)); + break; + case PforData::kExceptions1Pct: + value = static_cast(unit(rng) < 0.01 ? any(rng) : small(rng)); + break; + case PforData::kExceptions10Pct: + value = static_cast(unit(rng) < 0.10 ? any(rng) : small(rng)); + break; + case PforData::kUniform: + value = static_cast(any(rng)); + break; + } + } + return values; +} + +// Arg: number of values. +void BM_PforDecode(benchmark::State& state, PforData data) { + const auto count = static_cast(state.range(0)); + const Bytes encoded = EncodePfor(MakePforValues(data, count), kBestWidth); + std::vector out(count); + while (state.KeepRunning()) { + auto result = DecodePforBytes(encoded, out); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out.data()); + benchmark::ClobberMemory(); + } + state.SetItemsProcessed(state.iterations() * static_cast(count)); + state.SetBytesProcessed(state.iterations() * static_cast(encoded.size())); + state.counters["encoded_bytes"] = static_cast(encoded.size()); +} + +void PforArgs(benchmark::internal::Benchmark* b) { + b->ArgName("count")->Arg(256)->Arg(8192); +} + +BENCHMARK_CAPTURE(BM_PforDecode, constant, PforData::kConstant)->Apply(PforArgs); +BENCHMARK_CAPTURE(BM_PforDecode, small, PforData::kSmall)->Apply(PforArgs); +BENCHMARK_CAPTURE(BM_PforDecode, exceptions_1pct, PforData::kExceptions1Pct) + ->Apply(PforArgs); +BENCHMARK_CAPTURE(BM_PforDecode, exceptions_10pct, PforData::kExceptions10Pct) + ->Apply(PforArgs); +BENCHMARK_CAPTURE(BM_PforDecode, uniform, PforData::kUniform)->Apply(PforArgs); + +// --------------------------------------------------------------------------- +// Bitmaps +// --------------------------------------------------------------------------- + +// Position layouts for bitmap inputs. +enum class Layout { + kRandom, // positions spread uniformly over the full range (mostly sparse) + kRuns, // runs of 64 consecutive positions (dense containers between gaps) + kPrefix, // the first N positions (all dense containers) +}; + +std::vector MakePositions(Layout layout, int64_t cardinality) { + std::vector positions; + positions.reserve(cardinality); + switch (layout) { + case Layout::kRandom: { + std::mt19937_64 rng(kSeed); + std::uniform_int_distribution dist(0, kMaxPositions - 1); + std::set unique; + while (std::cmp_less(unique.size(), cardinality)) { + unique.insert(dist(rng)); + } + positions.assign(unique.begin(), unique.end()); + break; + } + case Layout::kRuns: { + // Spread the runs so that they cover the whole range when possible. + const int64_t runs = (cardinality + 63) / 64; + const int64_t stride = std::max(64, (kMaxPositions / runs) / 64 * 64); + for (int64_t run = 0; std::cmp_less(positions.size(), cardinality); ++run) { + for (int64_t i = 0; i < 64 && std::cmp_less(positions.size(), cardinality); ++i) { + positions.push_back(run * stride + i); + } + } + break; + } + case Layout::kPrefix: + for (int64_t i = 0; i < cardinality; ++i) { + positions.push_back(i); + } + break; + } + return positions; +} + +Bytes MakeBitmapBytes(const benchmark::State& state, Layout layout) { + return BuildBitmapFromPositions(MakePositions(layout, state.range(0))); +} + +MumblingBitmapView MakeView(const Bytes& bytes) { + auto bitmap = MumblingBitmapView::Make(bytes); + if (!bitmap.has_value()) { + std::abort(); + } + return std::move(bitmap).value(); +} + +void BitmapArgs(benchmark::internal::Benchmark* b) { + b->ArgName("cardinality")->Arg(1'000)->Arg(100'000); +} + +// The largest bitmap: every position set. +void MaxBitmapArgs(benchmark::internal::Benchmark* b) { + b->ArgName("cardinality")->Arg(kMaxPositions); +} + +#define MUMBLING_BITMAP_BENCHMARK(fn) \ + BENCHMARK_CAPTURE(fn, random, Layout::kRandom)->Apply(BitmapArgs); \ + BENCHMARK_CAPTURE(fn, runs, Layout::kRuns)->Apply(BitmapArgs); \ + BENCHMARK_CAPTURE(fn, prefix, Layout::kPrefix)->Apply(BitmapArgs); \ + BENCHMARK_CAPTURE(fn, full, Layout::kPrefix)->Apply(MaxBitmapArgs) + +// Arg: cardinality. Creating a view: header checks, descriptor decoding and +// the container offset table. +void BM_Make(benchmark::State& state, Layout layout) { + const Bytes bytes = MakeBitmapBytes(state, layout); + while (state.KeepRunning()) { + auto bitmap = MumblingBitmapView::Make(bytes); + benchmark::DoNotOptimize(bitmap); + } + state.SetBytesProcessed(state.iterations() * static_cast(bytes.size())); + state.counters["serialized_bytes"] = static_cast(bytes.size()); +} + +MUMBLING_BITMAP_BENCHMARK(BM_Make); + +// Arg: cardinality. Probes random positions over the full range. +void BM_Contains(benchmark::State& state, Layout layout) { + const Bytes bytes = MakeBitmapBytes(state, layout); + const MumblingBitmapView bitmap = MakeView(bytes); + constexpr size_t kProbeCount = 4096; + std::mt19937_64 rng(kSeed + 1); + std::uniform_int_distribution dist(0, kMaxPositions - 1); + std::vector probes(kProbeCount); + for (auto& probe : probes) { + probe = dist(rng); + } + + while (state.KeepRunning()) { + int64_t hits = 0; + for (int64_t probe : probes) { + hits += bitmap.Contains(probe) ? 1 : 0; + } + benchmark::DoNotOptimize(hits); + } + state.SetItemsProcessed(state.iterations() * static_cast(kProbeCount)); +} + +MUMBLING_BITMAP_BENCHMARK(BM_Contains); + +} // namespace +} // namespace iceberg + +int main(int argc, char** argv) { + benchmark::Initialize(&argc, argv); + if (benchmark::ReportUnrecognizedArguments(argc, argv)) { + return 1; + } + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/src/iceberg/test/CMakeLists.txt b/src/iceberg/test/CMakeLists.txt index 1874fc25e8..505d04bfda 100644 --- a/src/iceberg/test/CMakeLists.txt +++ b/src/iceberg/test/CMakeLists.txt @@ -155,6 +155,7 @@ add_iceberg_test(util_test lazy_test.cc location_util_test.cc math_util_internal_test.cc + mumbling_bitmap_internal_test.cc executor_util_test.cc roaring_position_bitmap_test.cc position_delete_index_test.cc diff --git a/src/iceberg/test/mumbling_bitmap_internal_test.cc b/src/iceberg/test/mumbling_bitmap_internal_test.cc new file mode 100644 index 0000000000..5ea2f6d835 --- /dev/null +++ b/src/iceberg/test/mumbling_bitmap_internal_test.cc @@ -0,0 +1,563 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "iceberg/util/mumbling_bitmap_internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iceberg/test/matchers.h" +#include "iceberg/test/mumbling_bitmap_test_util.h" +#include "iceberg/test/test_resource.h" + +namespace iceberg { + +namespace { + +using mumbling_test::BuildBitmap; +using mumbling_test::Bytes; +using mumbling_test::Dense; +using mumbling_test::DenseRange; +using mumbling_test::EncodePfor; +using mumbling_test::Header; +using mumbling_test::kBestWidth; + +std::vector Range(int64_t start, int64_t end, int64_t step = 1) { + std::vector result; + for (int64_t i = start; i < end; i += step) { + result.push_back(i); + } + return result; +} + +// Checks Contains() for every position up to one container past the last +// expected one, and for the ends of the position range. +void ExpectPositions(const MumblingBitmapView& bitmap, + const std::vector& expected) { + EXPECT_EQ(bitmap.Cardinality(), static_cast(expected.size())); + std::set expected_set(expected.begin(), expected.end()); + const int64_t limit = expected.empty() ? 512 : (expected.back() / 256 + 2) * 256; + for (int64_t pos = -1; pos < limit; ++pos) { + ASSERT_EQ(bitmap.Contains(pos), expected_set.contains(pos)) << "pos=" << pos; + } + for (int64_t pos : {int64_t{MumblingBitmapView::kMaxCardinality} - 1, + int64_t{MumblingBitmapView::kMaxCardinality}, + std::numeric_limits::max()}) { + ASSERT_EQ(bitmap.Contains(pos), expected_set.contains(pos)) << "pos=" << pos; + } +} + +Result> DecodePfor(const Bytes& data, size_t count, + size_t expected_bytes_read) { + std::vector out(count); + ICEBERG_ASSIGN_OR_RAISE(auto bytes_read, DecodePforBytes(data, out)); + EXPECT_EQ(bytes_read, expected_bytes_read); + return out; +} + +// One line of a fixture file: a hex string and a comma-separated list of +// integers, separated by a tab. +struct Fixture { + int line; + Bytes bytes; + std::vector values; +}; + +Bytes ParseHex(std::string_view hex) { + Bytes out; + for (size_t i = 0; i + 1 < hex.size(); i += 2) { + out.push_back( + static_cast(std::stoi(std::string(hex.substr(i, 2)), nullptr, 16))); + } + return out; +} + +std::vector ParseValues(std::string_view text) { + std::vector values; + size_t start = 0; + while (start < text.size()) { + size_t end = text.find(',', start); + if (end == std::string_view::npos) { + end = text.size(); + } + values.push_back(std::stoll(std::string(text.substr(start, end - start)))); + start = end + 1; + } + return values; +} + +// Reads `file_name` from the test resources. `hex_column` is the column (0 or 1) +// that holds the encoded bytes; the other column holds the values. +std::vector ReadFixtures(const std::string& file_name, int hex_column) { + std::ifstream file(GetResourcePath(file_name)); + EXPECT_TRUE(file.is_open()) << "Cannot open " << file_name; + std::vector fixtures; + std::string line; + for (int line_number = 1; std::getline(file, line); ++line_number) { + if (line.empty() || line.starts_with('#')) { + continue; + } + const size_t tab = line.find('\t'); + EXPECT_NE(tab, std::string::npos) << file_name << ":" << line_number; + if (tab == std::string::npos) { + continue; + } + std::array columns = {std::string_view(line).substr(0, tab), + std::string_view(line).substr(tab + 1)}; + fixtures.push_back({.line = line_number, + .bytes = ParseHex(columns[hex_column]), + .values = ParseValues(columns[1 - hex_column])}); + } + return fixtures; +} + +} // namespace + +// Examples from "Appendix A: PFOR encoding for unsigned bytes" of the Mumbling +// spec: https://github.com/apache/iceberg/blob/main/format/mumbling-spec.md#examples +TEST(PforDecodeTest, SpecExamples) { + ICEBERG_UNWRAP_OR_FAIL(auto all_zero, DecodePfor({0x00, 0x00, 0x00}, 256, 3)); + EXPECT_EQ(all_zero, std::vector(256, 0)); + + ICEBERG_UNWRAP_OR_FAIL(auto all_five, DecodePfor({0x00, 0x00, 0x05}, 51, 3)); + EXPECT_EQ(all_five, std::vector(51, 5)); + + ICEBERG_UNWRAP_OR_FAIL(auto exceptions_only, + DecodePfor({0x80, 0x02, 0x00, 0x04, 0x07, 0xFF, 0xFE}, 8, 7)); + EXPECT_EQ(exceptions_only, (std::vector{0, 0, 0, 0, 0xFF, 0, 0, 0xFE})); + + ICEBERG_UNWRAP_OR_FAIL(auto two_bits, DecodePfor({0x02, 0x00, 0x06, 0x18}, 3, 4)); + EXPECT_EQ(two_bits, (std::vector{6, 7, 8})); + + ICEBERG_UNWRAP_OR_FAIL(auto with_exception, + DecodePfor({0x32, 0x01, 0x06, 0x09, 0x01, 0xE0}, 4, 6)); + EXPECT_EQ(with_exception, (std::vector{6, 34, 8, 7})); +} + +// The Java encoder's choice for spec example 5 (b1 = 5, no exceptions), from +// TestPFOREncoding#testExample5 in apache/iceberg. +TEST(PforDecodeTest, JavaEncodingOfExample5) { + ICEBERG_UNWRAP_OR_FAIL(auto values, + DecodePfor({0x05, 0x00, 0x06, 0x07, 0x04, 0x10}, 4, 6)); + EXPECT_EQ(values, (std::vector{6, 34, 8, 7})); +} + +TEST(PforDecodeTest, HandPackedWidths) { + ICEBERG_UNWRAP_OR_FAIL(auto one_bit, DecodePfor({0x01, 0x00, 0x00, 0xB0, 0x80}, 9, 5)); + EXPECT_EQ(one_bit, (std::vector{1, 0, 1, 1, 0, 0, 0, 0, 1})); + + ICEBERG_UNWRAP_OR_FAIL(auto three_bits, + DecodePfor({0x03, 0x00, 0x00, 0xE2, 0xA0}, 4, 5)); + EXPECT_EQ(three_bits, (std::vector{7, 0, 5, 2})); + + ICEBERG_UNWRAP_OR_FAIL(auto four_bits, + DecodePfor({0x04, 0x00, 0x01, 0xA5, 0xF0}, 3, 5)); + EXPECT_EQ(four_bits, (std::vector{0xB, 0x6, 0x10})); + + ICEBERG_UNWRAP_OR_FAIL(auto six_bits, + DecodePfor({0x06, 0x00, 0x00, 0xFC, 0x18, 0x00}, 3, 6)); + EXPECT_EQ(six_bits, (std::vector{63, 1, 32})); + + ICEBERG_UNWRAP_OR_FAIL(auto seven_bits, + DecodePfor({0x07, 0x00, 0x00, 0xFE, 0x04}, 2, 5)); + EXPECT_EQ(seven_bits, (std::vector{0x7F, 0x01})); + + ICEBERG_UNWRAP_OR_FAIL(auto eight_bits, + DecodePfor({0x08, 0x00, 0x00, 0x20, 0x00, 0x1F}, 3, 6)); + EXPECT_EQ(eight_bits, (std::vector{0x20, 0x00, 0x1F})); +} + +TEST(PforDecodeTest, EmptyInput) { + ICEBERG_UNWRAP_OR_FAIL(auto values, DecodePfor({}, 0, 0)); + EXPECT_TRUE(values.empty()); +} + +TEST(PforDecodeTest, MultipleChunks) { + // 256 values of 7, then 44 raw values. + Bytes data = {0x00, 0x00, 0x07, 0x08, 0x00, 0x00}; + std::vector expected(256, 7); + for (int i = 0; i < 44; ++i) { + data.push_back(static_cast(i)); + expected.push_back(static_cast(i)); + } + // Trailing bytes after the encoded values are not consumed. + data.push_back(0xAB); + ICEBERG_UNWRAP_OR_FAIL(auto values, DecodePfor(data, 300, data.size() - 1)); + EXPECT_EQ(values, expected); +} + +TEST(PforDecodeTest, AllWidthsRoundTrip) { + std::mt19937 rng(42); + for (int b1 = 0; b1 <= 8; ++b1) { + for (size_t count : {1, 7, 255, 256, 257, 600}) { + std::vector values(count); + for (auto& value : values) { + // Mostly small values with a few larger ones to produce exceptions. + value = static_cast(rng() % 16 == 0 ? 3 + rng() % 253 : 3 + rng() % 4); + } + auto encoded = EncodePfor(values, b1); + ICEBERG_UNWRAP_OR_FAIL(auto decoded, DecodePfor(encoded, count, encoded.size())); + EXPECT_EQ(decoded, values) << "b1=" << b1 << " count=" << count; + } + } +} + +TEST(PforDecodeTest, Malformed) { + std::vector out(4); + auto decode = [&](const Bytes& data) { return DecodePforBytes(data, out); }; + + EXPECT_THAT(decode({0x00, 0x00}), HasErrorMessage("Truncated PFOR chunk header")); + EXPECT_THAT(decode({0x09, 0x00, 0x00, 0, 0, 0, 0, 0}), + HasErrorMessage("Invalid PFOR primary bit width: 9")); + EXPECT_THAT(decode({0x72, 0x00, 0x00, 0, 0, 0, 0}), + HasErrorMessage("Invalid PFOR exception bit width: 7")); + EXPECT_THAT(decode({0x18, 0x00, 0x00, 0, 0, 0, 0, 0}), + HasErrorMessage("Invalid PFOR exception bit width: 1")); + EXPECT_THAT(decode({0x08, 0x01, 0x00, 0, 0, 0, 0, 0}), + HasErrorMessage("exceptions with 8-bit primary values")); + EXPECT_THAT(decode({0x80, 0x05, 0x00, 0, 1, 2, 3, 4, 1, 1, 1, 1, 1}), + HasErrorMessage("5 exceptions for 4 values")); + EXPECT_THAT(decode({0x02, 0x00, 0x00}), HasErrorMessage("Truncated PFOR chunk:")); + EXPECT_THAT(decode({0x80, 0x01, 0x00, 0x00}), HasErrorMessage("Truncated PFOR chunk:")); + EXPECT_THAT(decode({0x80, 0x01, 0x00, 0x04, 0x01}), + HasErrorMessage("Invalid PFOR exception offset: 4")); + EXPECT_THAT(decode({0x01, 0x00, 0xFF, 0x80}), + HasErrorMessage("Invalid PFOR value at index 0: 256")); + EXPECT_THAT(decode({0x08, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x00}), + HasErrorMessage("Invalid PFOR value at index 2: 256")); + + // The second chunk is missing. + std::vector two_chunks(257); + EXPECT_THAT(DecodePforBytes(Bytes{0x00, 0x00, 0x00}, two_chunks), + HasErrorMessage("Truncated PFOR chunk header")); +} + +TEST(MumblingBitmapTest, EmptyBitmap) { + const Bytes bitmap_bytes = Bytes{0x01, 0, 0, 0, 0, 0}; + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + ExpectPositions(bitmap, {}); +} + +TEST(MumblingBitmapTest, EmptySparseContainers) { + const Bytes bitmap_bytes = BuildBitmap({{}, {}, {}}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + ExpectPositions(bitmap, {}); +} + +// Sparse container examples from the spec. +TEST(MumblingBitmapTest, SparseSpecExamples) { + // Hand-encoded: header, PFOR chunk {b1=0, e=0, m=3}, container `00 22 FF`. + Bytes bytes = {0x01, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x22, 0xFF}; + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bytes)); + ExpectPositions(bitmap, {0, 34, 255}); + + Bytes full; + for (uint8_t i = 0; i < 31; ++i) { + full.push_back(i); + } + const Bytes full_bitmap_bytes = BuildBitmap({full}); + ICEBERG_UNWRAP_OR_FAIL(auto full_bitmap, MumblingBitmapView::Make(full_bitmap_bytes)); + ExpectPositions(full_bitmap, Range(0, 31)); +} + +// Dense container examples from the spec. +TEST(MumblingBitmapTest, DenseSpecExamples) { + Bytes first_32(32, 0); + std::fill_n(first_32.begin(), 4, 0xFF); + const Bytes bitmap1_bytes = BuildBitmap({first_32}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap1, MumblingBitmapView::Make(bitmap1_bytes)); + ExpectPositions(bitmap1, Range(0, 32)); + + Bytes first_33 = first_32; + first_33[4] = 0x80; + const Bytes bitmap2_bytes = BuildBitmap({first_33}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap2, MumblingBitmapView::Make(bitmap2_bytes)); + ExpectPositions(bitmap2, Range(0, 33)); + + Bytes ends(32, 0); + ends[0] = ends[1] = ends[30] = ends[31] = 0xFF; + const Bytes bitmap3_bytes = BuildBitmap({ends}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap3, MumblingBitmapView::Make(bitmap3_bytes)); + auto expected = Range(0, 16); + auto tail = Range(240, 256); + expected.insert(expected.end(), tail.begin(), tail.end()); + ExpectPositions(bitmap3, expected); + + Bytes even(32, 0xAA); + const Bytes bitmap4_bytes = BuildBitmap({even}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap4, MumblingBitmapView::Make(bitmap4_bytes)); + ExpectPositions(bitmap4, Range(0, 256, 2)); + + Bytes all(32, 0xFF); + const Bytes bitmap5_bytes = BuildBitmap({all}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap5, MumblingBitmapView::Make(bitmap5_bytes)); + ExpectPositions(bitmap5, Range(0, 256)); +} + +TEST(MumblingBitmapTest, MixedContainers) { + // Same layout as SPARSE_DENSE_SPARSE in Java's TestMumblingBitmap: every + // other byte of the first 8 bytes of the dense container is 0xFF. + Bytes dense(32, 0); + dense[1] = dense[3] = dense[5] = dense[7] = 0xFF; + const Bytes bitmap_bytes = BuildBitmap({{0}, dense, {}, {0x01, 0xFF}, {}}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + + std::vector expected = {0}; + for (int64_t byte : {1, 3, 5, 7}) { + auto range = Range(256 + byte * 8, 256 + byte * 8 + 8); + expected.insert(expected.end(), range.begin(), range.end()); + } + expected.push_back(3 * 256 + 1); + expected.push_back(3 * 256 + 255); + ExpectPositions(bitmap, expected); +} + +TEST(MumblingBitmapTest, PforEncodedDescriptors) { + // Descriptors {0, 0, 5, 0, 32, 0, 1}, encoded with every primary bit width. + std::vector dense_positions; + for (int i = 0; i < 40; ++i) { + dense_positions.push_back(i * 6); + } + std::vector containers = {{}, {}, {1, 2, 3, 4, 200}, {}, Dense(dense_positions), + {}, {9}}; + std::vector expected = {512 + 1, 512 + 2, 512 + 3, 512 + 4, 512 + 200}; + for (int64_t i = 0; i < 40; ++i) { + expected.push_back(1024 + i * 6); + } + expected.push_back(6 * 256 + 9); + for (int b1 = 0; b1 <= 8; ++b1) { + const Bytes bitmap_bytes = BuildBitmap(containers, b1); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + ExpectPositions(bitmap, expected); + } +} + +// The spec says readers must ignore the low bits of a dense descriptor. Note: +// the Java reader currently rejects such descriptors. +TEST(MumblingBitmapTest, DenseDescriptorIgnoresLowBits) { + Bytes bytes = Header(256, 1); + bytes.insert(bytes.end(), {0x08, 0x00, 0x00, 0x21}); + bytes.insert(bytes.end(), 32, 0xFF); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bytes)); + ExpectPositions(bitmap, Range(0, 256)); +} + +TEST(MumblingBitmapTest, MaximumSize) { + // 8192 dense containers with every bit set. Descriptors are 32 PFOR chunks of + // 256 values, each encoded as `00 00 20`. + Bytes bytes = + Header(MumblingBitmapView::kMaxCardinality, MumblingBitmapView::kMaxContainerCount); + for (int chunk = 0; chunk < 32; ++chunk) { + bytes.insert(bytes.end(), {0x00, 0x00, 0x20}); + } + bytes.insert(bytes.end(), size_t{MumblingBitmapView::kMaxContainerCount} * 32, 0xFF); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bytes)); + EXPECT_EQ(bitmap.Cardinality(), 2'097'152); + EXPECT_TRUE(bitmap.Contains(0)); + EXPECT_TRUE(bitmap.Contains(2'097'151)); + EXPECT_FALSE(bitmap.Contains(2'097'152)); + int64_t set = 0; + for (int64_t pos = 0; pos < MumblingBitmapView::kMaxCardinality; ++pos) { + set += bitmap.Contains(pos) ? 1 : 0; + } + EXPECT_EQ(set, MumblingBitmapView::kMaxCardinality); +} + +TEST(MumblingBitmapTest, OutOfRangePositions) { + const Bytes bitmap_bytes = BuildBitmap({{0, 255}}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + EXPECT_FALSE(bitmap.Contains(-1)); + EXPECT_FALSE(bitmap.Contains(std::numeric_limits::min())); + EXPECT_FALSE(bitmap.Contains(256)); + EXPECT_FALSE(bitmap.Contains(std::numeric_limits::max())); + EXPECT_TRUE(bitmap.Contains(255)); +} + +TEST(MumblingBitmapTest, RandomRoundTrip) { + std::mt19937 rng(7); + for (int iteration = 0; iteration < 20; ++iteration) { + const int container_count = 1 + static_cast(rng() % 40); + std::set positions; + std::vector containers; + for (int c = 0; c < container_count; ++c) { + // Pick a density: empty, sparse, borderline or dense. + const int target = std::vector{0, 3, 31, 32, 100, 256}[rng() % 6]; + std::set in_container; + while (std::cmp_less(in_container.size(), target)) { + in_container.insert(static_cast(rng() % 256)); + } + for (int pos : in_container) { + positions.insert(int64_t{c} * 256 + pos); + } + std::vector sorted(in_container.begin(), in_container.end()); + if (sorted.size() < 32) { + containers.emplace_back(sorted.begin(), sorted.end()); + } else { + containers.push_back(Dense(sorted)); + } + } + const int b1 = static_cast(rng() % 9); + const Bytes bitmap_bytes = BuildBitmap(containers, b1); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bitmap_bytes)); + ExpectPositions(bitmap, std::vector(positions.begin(), positions.end())); + } +} + +TEST(MumblingBitmapTest, InvalidHeader) { + EXPECT_THAT(MumblingBitmapView::Make(Bytes{}), + HasErrorMessage("Truncated Mumbling bitmap header")); + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x01, 0, 0, 0, 0}), + HasErrorMessage("Truncated Mumbling bitmap header")); + + // Versions 0 and 2, as in Java's TestMumblingBitmap#testInvalidVersion. + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x00, 0, 0, 0, 0, 0}), + IsError(ErrorKind::kNotSupported)); + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x02, 0, 0, 0, 0, 0}), + HasErrorMessage("Unsupported Mumbling bitmap version: 2")); + + // From Java's TestMumblingBitmap#testInvalidCardinality. + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x01, 0x01, 0x00, 0x20, 0x00, 0x00}), + HasErrorMessage("cardinality: 2097153")); + + EXPECT_THAT(MumblingBitmapView::Make(Header(0, 8193)), + HasErrorMessage("container count: 8193")); + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x01, 0, 0, 0, 0xFF, 0xFF}), + HasErrorMessage("container count: 65535")); +} + +TEST(MumblingBitmapTest, InvalidDescriptors) { + // Reserved descriptor bits, as in Java's TestMumblingBitmap#testInvalidDescriptor. + for (uint8_t descriptor : {0x40, 0x80, 0xC0, 0x5F}) { + Bytes bytes = Header(1, 1); + bytes.insert(bytes.end(), {0x08, 0x00, 0x00, descriptor}); + EXPECT_THAT(MumblingBitmapView::Make(bytes), HasErrorMessage("not sparse or dense")); + } + + // The descriptor array is truncated. + Bytes truncated = Header(0, 2); + truncated.insert(truncated.end(), {0x08, 0x00, 0x00, 0x00}); + EXPECT_THAT(MumblingBitmapView::Make(truncated), + HasErrorMessage("Truncated PFOR chunk")); + + // From Java's TestMumblingBitmap#testMaximumCardinalityAndContainers: the + // header is valid but no descriptors follow. + EXPECT_THAT(MumblingBitmapView::Make(Bytes{0x01, 0xFF, 0xFF, 0x1F, 0xFF, 0x1F}), + HasErrorMessage("Truncated PFOR chunk header")); +} + +TEST(MumblingBitmapTest, InvalidContainers) { + auto truncated = BuildBitmap({{1, 2, 3}, DenseRange(0, 64)}); + truncated.pop_back(); + EXPECT_THAT(MumblingBitmapView::Make(truncated), + HasErrorMessage("Truncated Mumbling bitmap containers: 34 bytes available, " + "35 required")); + + auto trailing = BuildBitmap({{1, 2, 3}}); + trailing.push_back(0x00); + EXPECT_THAT(MumblingBitmapView::Make(trailing), + HasErrorMessage("1 unexpected trailing bytes")); +} + +// Make() checks only what memory safety needs, like the Java reader. Input +// that breaks the spec's content rules is accepted and still gives defined +// answers. +TEST(MumblingBitmapTest, ContentRulesAreNotChecked) { + // The header cardinality is reported as stored. + const Bytes wrong_cardinality = BuildBitmap({{1, 2, 3}}, 8, 4); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap1, MumblingBitmapView::Make(wrong_cardinality)); + EXPECT_EQ(bitmap1.Cardinality(), 4); + EXPECT_TRUE(bitmap1.Contains(1)); + EXPECT_TRUE(bitmap1.Contains(3)); + EXPECT_FALSE(bitmap1.Contains(4)); + + // Unsorted and duplicate sparse positions: Contains() finds every stored + // position, including in a non-final container, which uses the SSE2 path + // on x86-64. + Bytes unsorted; + for (uint8_t i = 0; i < 31; ++i) { + unsorted.push_back(static_cast(250 - i * 8)); + } + const Bytes unsorted_bytes = BuildBitmap({unsorted, {5, 3, 3}}, 8, 34); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap2, MumblingBitmapView::Make(unsorted_bytes)); + for (uint8_t value : unsorted) { + EXPECT_TRUE(bitmap2.Contains(value)) << int{value}; + } + EXPECT_FALSE(bitmap2.Contains(251)); + EXPECT_TRUE(bitmap2.Contains(256 + 3)); + EXPECT_TRUE(bitmap2.Contains(256 + 5)); + EXPECT_FALSE(bitmap2.Contains(256 + 4)); + + // A dense container with fewer than 32 positions. + const Bytes sparse_dense = BuildBitmap({DenseRange(0, 3)}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap3, MumblingBitmapView::Make(sparse_dense)); + ExpectPositions(bitmap3, {0, 1, 2}); +} + +// The view reads the caller's buffer instead of copying it. +TEST(MumblingBitmapTest, ViewDoesNotCopy) { + Bytes bytes = BuildBitmap({{1, 2, 3}}); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(bytes)); + EXPECT_FALSE(bitmap.Contains(4)); + bytes.back() = 4; // the container {1, 2, 3} becomes {1, 2, 4} + EXPECT_TRUE(bitmap.Contains(4)); + EXPECT_FALSE(bitmap.Contains(3)); +} + +// The fixtures in resources/mumbling were produced by the Java implementation +// (org.apache.iceberg.mumbling) and are copied from apache/iceberg-go#1750 +// (mumbling/testdata at e305815). +TEST(PforDecodeTest, JavaFixtures) { + auto fixtures = ReadFixtures("mumbling/pfor-java-fixtures.tsv", /*hex_column=*/1); + ASSERT_EQ(fixtures.size(), 130); + for (const auto& fixture : fixtures) { + SCOPED_TRACE("line " + std::to_string(fixture.line)); + std::vector expected(fixture.values.begin(), fixture.values.end()); + ICEBERG_UNWRAP_OR_FAIL( + auto decoded, DecodePfor(fixture.bytes, expected.size(), fixture.bytes.size())); + EXPECT_EQ(decoded, expected); + // The test encoder chooses bit widths like the Java encoder, so the + // benchmark inputs match what Java writes. + EXPECT_EQ(EncodePfor(expected, kBestWidth), fixture.bytes); + } +} + +TEST(MumblingBitmapTest, JavaFixtures) { + auto fixtures = ReadFixtures("mumbling/bitmap-java-fixtures.tsv", /*hex_column=*/0); + ASSERT_EQ(fixtures.size(), 6); + for (const auto& fixture : fixtures) { + SCOPED_TRACE("line " + std::to_string(fixture.line)); + ICEBERG_UNWRAP_OR_FAIL(auto bitmap, MumblingBitmapView::Make(fixture.bytes)); + ExpectPositions(bitmap, fixture.values); + } +} + +} // namespace iceberg diff --git a/src/iceberg/test/mumbling_bitmap_test_util.h b/src/iceberg/test/mumbling_bitmap_test_util.h new file mode 100644 index 0000000000..6637b9e760 --- /dev/null +++ b/src/iceberg/test/mumbling_bitmap_test_util.h @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#pragma once + +/// \file iceberg/test/mumbling_bitmap_test_util.h +/// Helpers that serialize Mumbling bitmaps for tests and benchmarks. The +/// library only has a reader, so these follow the spec directly. + +#include +#include +#include +#include +#include +#include +#include + +#include "iceberg/util/mumbling_bitmap_internal.h" + +namespace iceberg::mumbling_test { + +using Bytes = std::vector; + +// Packs `width`-bit values most significant bit first, padded to a byte. +inline Bytes PackBits(const std::vector& values, int width) { + Bytes out((values.size() * width + 7) / 8, 0); + size_t bit_pos = 0; + for (uint8_t value : values) { + for (int bit = width - 1; bit >= 0; --bit, ++bit_pos) { + if ((value >> bit) & 1) { + out[bit_pos / 8] |= static_cast(0x80 >> (bit_pos % 8)); + } + } + } + return out; +} + +// Encodes one PFOR chunk with the given primary bit width `b1` and base `m`, +// following Appendix A of the spec +// (https://github.com/apache/iceberg/blob/main/format/mumbling-spec.md#appendix-a-pfor-encoding-for-unsigned-bytes). +// Exceptions are the values that do not fit in `b1` bits after subtracting `m`. +inline Bytes EncodePforChunk(const std::vector& values, int b1, uint8_t m) { + std::vector primary; + std::vector offsets; + std::vector exceptions; + int max_width = 0; + for (uint8_t value : values) { + max_width = std::max( + max_width, static_cast(std::bit_width(static_cast(value - m)))); + } + const int b2 = std::max(0, max_width - b1); + for (size_t i = 0; i < values.size(); ++i) { + const auto normalized = static_cast(values[i] - m); + primary.push_back(b1 == 8 ? normalized + : static_cast(normalized & ((1 << b1) - 1))); + if (b1 < 8 && (normalized >> b1) != 0) { + offsets.push_back(static_cast(i)); + exceptions.push_back(static_cast(normalized >> b1)); + } + } + Bytes out = {static_cast((b2 << 4) | b1), static_cast(offsets.size()), + m}; + auto packed = PackBits(primary, b1); + out.insert(out.end(), packed.begin(), packed.end()); + out.insert(out.end(), offsets.begin(), offsets.end()); + packed = PackBits(exceptions, b2); + out.insert(out.end(), packed.begin(), packed.end()); + return out; +} + +// Passed as `b1` to choose the primary bit width the way the spec recommends. +constexpr int kBestWidth = -1; + +// Returns the primary bit width that minimizes the encoded size of a chunk, as +// recommended by the spec. Ties go to the larger width, as in the Java encoder. +inline int ChooseBitWidth(const std::vector& chunk, uint8_t m) { + int max_width = 0; + for (uint8_t value : chunk) { + max_width = std::max( + max_width, static_cast(std::bit_width(static_cast(value - m)))); + } + int best_width = 0; + size_t best_size = std::numeric_limits::max(); + for (int width = 0; width <= max_width; ++width) { + size_t exceptions = 0; + for (uint8_t value : chunk) { + exceptions += (static_cast(value - m) >> width) != 0 ? 1 : 0; + } + const size_t b2 = max_width - width; + const size_t size = + (chunk.size() * width + 7) / 8 + exceptions + (exceptions * b2 + 7) / 8; + if (size <= best_size) { + best_size = size; + best_width = width; + } + } + return best_width; +} + +// Encodes a whole value array as PFOR chunks of 256 values each, using primary +// bit width `b1` (0-8) or kBestWidth. +inline Bytes EncodePfor(const std::vector& values, int b1 = 8) { + Bytes out; + for (size_t start = 0; start < values.size(); start += 256) { + std::vector chunk( + values.begin() + start, + values.begin() + std::min(values.size(), start + size_t{256})); + const uint8_t min = *std::ranges::min_element(chunk); + const int width = b1 == kBestWidth ? ChooseBitWidth(chunk, min) : b1; + // With 8-bit values the spec recommends storing the original values (m = 0). + auto encoded = EncodePforChunk(chunk, width, width == 8 ? 0 : min); + out.insert(out.end(), encoded.begin(), encoded.end()); + } + return out; +} + +inline Bytes Header(int64_t cardinality, int32_t container_count) { + return {MumblingBitmapView::kVersion, + static_cast(cardinality & 0xFF), + static_cast((cardinality >> 8) & 0xFF), + static_cast((cardinality >> 16) & 0xFF), + static_cast(container_count & 0xFF), + static_cast((container_count >> 8) & 0xFF)}; +} + +inline int64_t ContainerCardinality(const Bytes& container) { + if (container.size() < 32) { + return static_cast(container.size()); + } + int64_t count = 0; + for (uint8_t b : container) { + count += std::popcount(b); + } + return count; +} + +// Serializes a bitmap from containers: containers with fewer than 32 bytes are +// sparse and 32-byte containers are dense. +inline Bytes BuildBitmap(const std::vector& containers, int b1 = 8, + std::optional cardinality = std::nullopt) { + std::vector descriptors; + int64_t actual_cardinality = 0; + for (const auto& container : containers) { + descriptors.push_back(static_cast(container.size())); + actual_cardinality += ContainerCardinality(container); + } + Bytes out = Header(cardinality.value_or(actual_cardinality), + static_cast(containers.size())); + auto encoded = EncodePfor(descriptors, b1); + out.insert(out.end(), encoded.begin(), encoded.end()); + for (const auto& container : containers) { + out.insert(out.end(), container.begin(), container.end()); + } + return out; +} + +// Builds a dense container with the given positions set. +inline Bytes Dense(const std::vector& positions) { + Bytes container(32, 0); + for (int pos : positions) { + container[pos / 8] |= static_cast(0x80 >> (pos % 8)); + } + return container; +} + +// Builds a dense container with positions [start, end) set. +inline Bytes DenseRange(int start, int end) { + std::vector positions; + for (int i = start; i < end; ++i) { + positions.push_back(i); + } + return Dense(positions); +} + +// Serializes a bitmap from sorted, unique positions in [0, 2,097,152), with +// descriptors encoded using `b1` (0-8 or kBestWidth). +inline Bytes BuildBitmapFromPositions(const std::vector& positions, + int b1 = kBestWidth) { + std::vector containers; + if (!positions.empty()) { + containers.resize(static_cast(positions.back() / 256) + 1); + } + for (int64_t pos : positions) { + containers[pos / 256].push_back(static_cast(pos % 256)); + } + for (auto& container : containers) { + if (container.size() >= 32) { + std::vector in_container(container.begin(), container.end()); + container = Dense(in_container); + } + } + return BuildBitmap(containers, b1); +} + +} // namespace iceberg::mumbling_test diff --git a/src/iceberg/test/resources/mumbling/bitmap-java-fixtures.tsv b/src/iceberg/test/resources/mumbling/bitmap-java-fixtures.tsv new file mode 100644 index 0000000000..5af4471939 --- /dev/null +++ b/src/iceberg/test/resources/mumbling/bitmap-java-fixtures.tsv @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +0103000001000000030022ff 0,34,255 +012000000100000020ffffffff00000000000000000000000000000000000000000000000000000000 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 +010200000300010000a0050a 5,522 +012200000200050002f000ffffffff0000000000000000000000000000000000000000000000000000000064c8 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,356,456 +010001000100000020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +014000004000000001000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f 0,257,514,771,1028,1285,1542,1799,2056,2313,2570,2827,3084,3341,3598,3855,4112,4369,4626,4883,5140,5397,5654,5911,6168,6425,6682,6939,7196,7453,7710,7967,8224,8481,8738,8995,9252,9509,9766,10023,10280,10537,10794,11051,11308,11565,11822,12079,12336,12593,12850,13107,13364,13621,13878,14135,14392,14649,14906,15163,15420,15677,15934,16191 diff --git a/src/iceberg/test/resources/mumbling/pfor-java-fixtures.tsv b/src/iceberg/test/resources/mumbling/pfor-java-fixtures.tsv new file mode 100644 index 0000000000..d38aa98658 --- /dev/null +++ b/src/iceberg/test/resources/mumbling/pfor-java-fixtures.tsv @@ -0,0 +1,146 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +0 000000 +0 000000 +2 000002 +1 000001 +6 000006 +56 000038 +232 0000e8 +0 000000 +3 000003 +1 000001 +0,0,0 000000 +1,0,1 010000a0 +1,1,0 010000c0 +0,6,5 0300001a80 +4,15,11 0400040b70 +26,43,3 0600035e8000 +188,227,203 0600bc0273c0 +2,2,2 000002 +2,2,2 000002 +2,2,3 01000220 +0,0,0,0 000000 +0,0,0,1 01000010 +0,2,0,1 02000021 +3,4,0,7 0300007070 +12,9,2,9 040002a707 +1,59,38,4 06000103a943 +122,70,167,129 07004668030bb0 +0,2,0,2 02000022 +1,0,2,1 02000049 +247,2,3,1 6201019800f4 +0,0,0,0,0,0,0 000000 +0,0,0,1,1,0,1 0100001a +2,0,1,0,1,2,2 0200008468 +2,0,7,5,6,4,5 03000043dd28 +14,2,2,0,12,10,4 040000e220ca40 +43,39,14,2,13,31,46 060002a653002ddb00 +255,96,35,30,246,138,111 080000ff60231ef68a6f +3,3,1,1,2,1,2 020001a044 +1,1,0,3,1,32,2 42010053480580 +3,3,216,2,167,1,209 0800000303d802a701d1 +0,0,0,0,0,0,0,0 000000 +1,0,1,1,0,0,0,1 010000b1 +3,2,1,2,1,2,1,2 0200019111 +0,6,1,2,5,5,7,5 03000018ab7d +5,8,12,8,6,11,14,10 04000503731695 +33,11,11,11,37,36,4,48 0600047471c786002c +184,217,92,22,93,40,177,74 080000b8d95c165d28b14a +0,2,1,1,2,3,1,1 02000025b5 +0,2,1,0,3,2,1,1 02000024e5 +13,3,2,2,2,22,145,2 35010258400051e00680 +0,0,0,0,0,0,0,0,0 000000 +0,1,1,1,1,1,1,1,1 0100007f80 +3,1,0,3,2,0,2,0,3 020000d388c0 +6,4,7,3,4,2,1,2,3 030001af264140 +3,3,10,9,13,13,14,1,13 0400012298ccd0c0 +47,16,34,3,32,14,14,54,28 060003b0d7c074b2f364 +83,252,142,51,162,173,201,86,85 08000053fc8e33a2adc95655 +2,2,3,3,2,0,2,1,225 620100af894008e0 +2,2,0,2,3,3,3,3,1 020000a2ff40 +39,3,3,3,118,3,2,0,0 430200edbcd00000044e +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000 +1,0,0,1,0,0,0,1,0,1,1,0,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1,0,0,1 010000916c4e36ff1520 +2,0,1,0,1,2,3,3,3,1,2,1,1,3,2,1,3,0,2,0,1,1,1,3,1,1,0,2,3,1,0,3,0,3,0,1,3,1,1,1,3,3,1,0,0,2,3,1,1,1,0 020000846fd979c85752d331d5f42d50 +0,2,5,1,5,4,4,4,3,3,0,6,5,5,1,3,6,2,5,4,4,2,3,2,7,2,1,4,5,4,2,6,6,4,0,3,6,7,5,1,2,3,7,7,3,4,2,4,5,6,2 0300000a9b246c6b4bcac89ae8cb16d03de94ff714b900 +15,10,14,13,8,6,13,12,3,14,10,7,1,14,13,4,8,4,15,9,15,6,0,0,2,8,14,2,11,14,11,4,4,3,2,0,14,9,4,15,6,15,0,7,13,12,9,6,3,6,3 040000faed86dc3ea71ed484f9f60028e2beb44320e94f6f07dc963630 +61,19,10,24,6,5,21,40,14,38,7,60,63,4,49,53,59,13,38,58,4,12,58,22,53,45,12,52,44,27,7,25,63,23,45,13,50,17,23,6,24,11,40,4,0,48,52,53,17,59,11 060000f532981855683a61fcfc4c75ecd9ba10ce96d6d334b1b1d9fd7b4dc915c660ba04030d3547b2c0 +106,202,74,117,151,161,54,252,70,104,177,73,11,173,214,104,45,195,90,193,255,21,194,173,52,50,50,107,121,151,50,10,109,209,5,174,148,31,176,126,119,33,53,139,166,217,233,148,91,86,163 0800006aca4a7597a136fc4668b1490badd6682dc35ac1ff15c2ad3432326b7997320a6dd105ae941fb07e7721358ba6d9e9945b56a3 +3,0,2,2,0,1,2,0,209,2,2,3,1,1,2,1,0,0,2,1,2,1,0,0,1,1,0,2,1,1,3,2,2,3,3,3,2,2,1,0,1,1,3,1,3,2,3,1,0,0,40 620200ca186b590990525ebfa45ded000832d0a0 +2,3,3,3,1,3,0,3,0,1,1,0,3,0,0,3,205,2,2,2,1,0,1,2,3,0,1,2,1,0,0,2,3,3,3,1,0,2,3,231,1,2,2,3,3,1,0,3,2,1,1 620200bf7314c36a46c642fd2f6bd3941027cf90 +0,179,27,1,1,0,3,2,142,29,2,3,12,1,3,2,159,2,3,245,2,1,1,3,3,238,122,3,176,0,1,81,2,134,3,2,3,3,2,1,217,3,0,79,1,24,2,1,2,2,1 620f003d4e9b1eed97eb05aef97349a4010208090c1013191a1c1f21282b2db068c70e7f7b7ac521d93180 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000 +0,1,0,0,0,0,1,0,1,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,0,1,0,0,1,0,0,0,1,0,1,1,0,1,1,0,1,0,0,1,0,1,1,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,0,1,0,1,1,0,1,1,1,1 01000042b2a52d7b2f922da5cad596f0 +2,2,0,2,3,3,2,3,2,3,2,2,1,1,1,2,1,1,2,1,2,2,0,2,0,0,3,0,1,0,1,2,3,3,1,3,2,1,1,2,1,2,1,2,2,1,0,3,0,0,1,2,2,1,0,3,1,3,2,3,2,1,2,3,2,3,3,2,3,1,2,3,3,1,3,0,0,2,0,2,1,0,1,1,2,3,0,1,1,2,1,0,1,3,0,3,2,1,0,3 020000a2fbba5659a20c46f796669306937b9bbedbdc2245b1647393 +6,2,1,0,7,7,5,5,5,4,6,4,6,7,1,6,6,0,0,5,7,6,3,0,7,7,7,6,5,3,6,0,1,0,0,6,4,2,3,4,5,4,0,1,2,2,0,1,5,6,6,3,2,0,3,1,1,3,4,3,6,1,7,2,5,2,6,2,4,4,3,2,6,2,6,4,7,4,3,7,0,0,5,6,5,6,1,6,5,7,7,4,0,7,5,2,4,4,1,3 030000c88fedb34dcec05f98ffeaf020689cb01481bb34192e3c7aab291acb4f1f02eb8ebfc1ea90b0 +12,11,4,7,2,13,10,7,9,5,0,11,10,15,7,2,3,8,3,2,12,15,15,1,0,12,1,12,15,4,3,13,2,8,13,1,1,15,0,1,15,9,13,13,6,1,8,4,3,4,4,3,3,11,15,13,0,15,7,0,9,15,10,4,0,10,0,13,15,5,7,1,7,8,6,8,6,14,12,13,8,8,7,1,1,2,12,9,0,11,5,3,14,5,15,8,2,10,8,1 040000cb472da7950baf723832cff10c1cf43d28d11f01f9dd618434433bfd0f709fa40a0df57178686ecd887112c90b53e5f82a81 +45,34,50,39,14,48,58,6,14,15,31,43,1,18,52,19,39,61,54,48,27,35,60,36,42,51,8,31,12,36,13,42,27,48,10,3,24,13,18,24,40,18,0,28,18,5,53,5,34,16,7,0,52,24,26,20,5,28,34,48,10,26,26,35,6,23,38,6,32,3,48,39,34,25,22,46,59,10,34,12,37,3,20,39,14,12,27,38,42,49,62,3,12,31,23,31,56,46,62,14 060000b62ca73b0e8638f7eb052d139fddb06e3f24ab321f32436a6f028360d498a1201c485d458901c0d1869415c8b029a6a3197986803c278995aeeca88c94352738c6e6ab1f8331f5dfe2ef8e +51,0,25,64,149,21,32,29,36,212,134,253,135,152,93,216,203,187,234,119,116,159,100,53,94,123,182,9,59,63,48,210,145,228,218,142,196,32,11,142,199,225,233,43,178,23,137,86,32,182,236,228,114,57,46,144,253,156,56,153,194,125,79,140,64,7,252,225,206,65,64,116,241,46,249,148,18,164,189,7,63,233,58,194,220,20,224,122,187,123,91,191,227,151,41,90,140,199,131,208 080000330019409515201d24d486fd87985dd8cbbbea77749f64355e7bb6093b3f30d291e4da8ec4200b8ec7e1e92bb217895620b6ece472392e90fd9c3899c27d4f8c4007fce1ce414074f12ef99412a4bd073fe93ac2dc14e07abb7b5bbfe397295a8cc783d0 +3,0,0,2,3,3,3,3,0,1,3,1,2,2,3,3,1,1,0,1,3,2,1,1,3,0,2,3,3,3,0,2,1,2,3,3,0,0,2,0,1,2,1,1,2,0,0,1,2,0,2,1,0,0,3,2,3,2,0,1,1,0,0,3,0,0,0,2,0,0,2,0,1,3,0,1,1,2,0,0,1,2,1,0,0,0,0,2,1,2,0,1,0,0,0,3,2,3,1,1 020000c2ff1daf51e5cbf26f086581890ee1430208716064026103b5 +1,2,2,1,3,1,2,0,1,1,2,77,3,3,3,1,0,2,3,0,0,3,1,3,1,1,1,1,0,2,2,3,2,2,1,0,3,0,2,0,2,0,1,247,0,76,1,0,3,2,3,3,0,1,2,3,1,1,2,3,2,0,2,28,0,0,2,1,0,0,2,0,2,0,2,0,2,3,2,2,0,0,3,2,3,0,1,1,0,3,0,1,0,1,0,1,0,2,3,2 62040069d859fd2c37552ba4c88704ef1b5b88090888ba0ec531112e0b2b2d3f4fd4c7 +2,0,3,0,1,0,2,1,1,1,91,3,1,0,2,1,2,127,3,2,1,2,3,65,2,0,3,0,1,131,140,3,0,1,1,1,2,0,0,1,3,0,0,1,203,4,86,0,48,3,152,3,109,0,95,0,3,0,3,2,2,3,1,1,1,1,0,2,2,2,0,2,181,0,2,3,0,113,2,0,3,0,3,37,2,3,1,0,122,3,1,2,191,0,3,2,3,0,1,2 6211008c495f49be6d8c731581c1c8334cceb552a24b18cdb4b6cec60a11171d1e2c2d2e30323436484d53585c59f4208f20553266d7b5c25ebc +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000 +0,0,0,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,1,0,1,1,1,0,0,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,0,0,0,1,0,0,1,1,1,0,1,1,1,1,0,0,0,0,1,0,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,1,1,0,1,1,0,1,1,1,0,0,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,1 0100001b7d6f67d5b5f5fb61225c003408c6e5d7256277849abfe0e5076e2ce50ac02a +0,3,3,1,0,2,1,1,0,3,3,2,0,1,0,3,2,3,2,1,3,1,2,0,2,0,0,1,0,3,2,0,2,3,2,3,0,2,2,3,0,2,3,1,2,3,0,1,0,2,2,1,1,3,0,0,2,0,2,2,0,1,0,0,1,3,2,2,0,2,2,3,0,1,3,2,3,1,2,0,1,3,0,3,1,3,2,3,3,3,1,2,0,2,2,1,2,3,2,2,0,2,1,1,2,1,2,0,0,0,0,0,2,0,3,1,2,3,1,1,1,3,1,1,2,2,3,1,3,0,2,0,3,2,2,2,0,3,0,1,1,1,1,1,1,1,0,0,3,3,1,0,1,1,3,3,0,3,1,3,2,0,2,3,2,1,3,3,2,1,1,2,2,1,1,2,3,1,3,2,1,1,0,1,3,3,2,2,0,3,1,0,3,1,0,2,3,1,2,0,1,0,2,2,1,2,3,3,2,0,2,3,0,2,1,0,2,3,2,2,2,0,3,0,2,0,2,1,2,3,1,2,1,3,1,1,0,1,1,2,1,2,3,3,1,2,3,0,3,3,0,3,2,3,3 0200003d253e13b9d88138bb2b2db129708a107a2b1ed8737bf629ba2598008db575adc8ea315550f45f378b9f9696de51fa34d2d84a6f8b24ba8c89b675166f6cf3bc +2,0,7,3,5,3,1,7,3,5,0,6,4,6,4,2,5,3,5,7,6,4,3,6,6,2,2,5,2,2,0,6,0,3,3,2,1,1,7,3,6,4,3,4,5,5,6,7,7,5,7,3,6,7,5,3,5,2,3,5,5,6,5,6,3,3,6,6,5,4,1,1,4,0,4,6,0,6,6,4,7,2,3,7,2,4,6,7,1,6,7,0,2,6,5,7,7,4,0,1,5,1,5,5,0,6,5,4,7,3,5,3,1,3,1,6,6,1,4,0,1,1,7,4,4,4,4,0,2,0,3,6,3,3,3,0,5,0,2,2,5,7,7,5,0,5,5,5,0,4,0,0,1,7,0,5,5,7,0,2,3,6,0,1,7,7,4,1,0,4,7,4,0,0,3,5,5,4,6,6,3,2,7,3,1,6,0,0,6,1,7,4,1,2,3,5,5,4,3,3,4,1,1,0,3,1,1,6,4,1,5,6,6,3,1,6,0,0,5,6,7,3,1,3,6,5,7,0,3,6,4,7,6,3,7,0,7,4,5,5,5,7,6,6,4,0,7,4,5,0,2,1,3,5,5 03000043bacf7469a2aefd1ec954860da27bd1cb77f7bdeba9dbae6f6b098261b4e9f5373b85aff01a6d1aceeb2cec6027c92041e6d8a12bfd16d1003c5bc2781fe113c01db366bb380c7c29db1b84864e86ecce02eecbd787a7cf8f2dbf683ca11768 +6,10,6,7,2,6,11,11,15,1,12,6,11,10,9,1,10,10,5,10,5,12,1,5,5,12,10,10,12,3,14,0,0,2,11,2,14,15,5,13,0,1,8,6,0,15,15,7,4,13,10,14,7,15,5,3,1,10,1,2,11,3,4,15,3,1,14,15,1,6,15,15,0,1,4,14,4,10,1,7,2,7,12,12,10,0,10,13,1,9,4,8,10,8,0,9,3,13,3,6,3,6,8,0,10,11,9,1,10,9,13,5,9,14,14,8,14,12,14,1,6,1,6,8,3,10,7,9,2,14,11,12,1,8,14,10,13,6,1,7,1,7,8,6,9,0,7,11,13,15,1,2,12,6,10,4,13,14,11,4,2,1,13,7,3,0,2,15,0,10,10,1,3,3,4,10,15,13,8,8,5,5,5,9,12,9,11,7,9,12,3,5,8,9,6,11,14,6,1,4,2,9,15,13,14,5,13,1,2,11,6,9,2,13,15,8,9,8,10,3,13,7,4,5,6,1,3,6,11,14,0,15,7,11,0,10,1,12,2,6,13,11,8,5,5,6,3,2,2,0,2,7,9,4,9 0400006a6726bbf1c6ba91aa5a5c155caac3e002b2ef5d01860ff74dae7f531a12b34f31ef16ff014e4a1727cca0ad1948a8093d363680ab91a9d59ee8ece161683a792ebc18ead6171786907bdf12c6a4deb421d7302f0aa1334afd885559c9b79c35896be61429fde5d12b692df898a3d7456136be0f7b0a1c26db85563220279490 +33,53,31,14,7,48,19,54,41,14,49,12,22,30,52,46,56,3,57,2,38,53,53,17,33,19,51,31,5,25,25,2,54,6,46,34,35,26,46,42,19,8,30,17,57,10,62,0,50,28,35,16,36,1,48,32,21,62,3,51,14,62,6,14,15,28,17,52,61,54,48,17,34,50,11,54,14,51,1,23,42,26,9,56,23,9,3,33,60,26,27,52,19,21,61,19,36,12,35,4,10,33,44,29,4,30,46,53,19,24,39,46,60,11,41,15,50,4,59,22,59,39,34,3,33,31,63,35,24,19,22,42,55,11,61,33,24,32,1,19,30,55,4,21,15,51,38,11,31,37,0,1,13,36,20,41,59,10,59,21,40,45,52,10,15,52,49,58,59,32,59,30,61,51,27,61,13,11,50,1,45,12,20,50,14,56,54,27,53,35,35,50,5,17,41,32,30,11,50,6,45,29,47,63,57,45,58,13,5,55,31,5,8,29,18,27,22,10,22,45,3,16,2,47,41,35,56,4,35,17,12,37,30,39,5,19,18,34,36,14,34,1,25,24,29,47,30,20,35,49,27,15,20,31,24 0600008757ce1f04f6a4ec4c59ed2ee03e429b5d51853cdf159642d86ba28dabaa4c8791e4af80c9c8d0901c2057e0f33be18e3dc474f76c118b22f63b3057a9a2785c90e1f1a6f44d5f5390c8c42a1b1d11ebb54d89eef0ba4fc84ed6ee788385ffe36135aadcbf616200537b71153f398b7e5001364529ecaed5a2dd0a3f4c7aee0edef736fd34bc81b4c5323b8d9bd638f2151a6078bc86b5dbffe6de8d1777c521d49b58a5ad0d00afa63e048d13257a71534a290e88165876f7948f16cf51f600 +137,124,15,177,14,46,87,192,2,26,29,101,108,133,169,80,164,119,34,2,217,15,160,120,146,55,85,128,7,124,26,218,11,6,119,241,182,220,234,37,137,192,148,190,204,246,51,52,231,8,199,235,183,63,156,134,226,31,151,162,58,18,17,136,125,171,58,200,247,4,66,107,66,50,90,87,117,254,198,23,171,152,60,88,112,209,143,65,137,211,23,90,209,129,213,211,147,140,46,215,209,120,240,184,236,224,189,80,79,29,132,113,196,231,51,161,192,27,103,23,9,248,43,244,137,166,9,44,97,215,139,151,34,199,203,3,160,31,217,47,207,134,163,165,47,51,55,15,78,61,152,229,242,22,188,214,119,25,22,154,137,53,227,66,73,5,253,52,227,29,127,161,161,197,44,106,145,151,74,137,110,14,208,61,93,86,110,72,233,200,41,147,52,201,139,231,32,114,135,59,166,16,171,239,211,225,84,178,199,72,53,167,113,31,114,221,140,180,133,58,238,68,10,158,86,69,239,21,206,130,200,131,173,15,11,187,234,133,244,173,249,38,8,151,29,109,73,207,56,46,48,144,39,102,90 080000897c0fb10e2e57c0021a1d656c85a950a4772202d90fa07892375580077c1ada0b0677f1b6dcea2589c094beccf63334e708c7ebb73f9c86e21f97a23a1211887dab3ac8f704426b42325a5775fec617ab983c5870d18f4189d3175ad181d5d3938c2ed7d178f0b8ece0bd504f1d8471c4e733a1c01b671709f82bf489a6092c61d78b9722c7cb03a01fd92fcf86a3a52f33370f4e3d98e5f216bcd67719169a8935e3424905fd34e31d7fa1a1c52c6a91974a896e0ed03d5d566e48e9c8299334c98be72072873ba610abefd3e154b2c74835a7711f72dd8cb4853aee440a9e5645ef15ce82c883ad0f0bbbea85f4adf92608971d6d49cf382e309027665a +2,1,3,2,3,0,1,2,2,1,2,0,0,2,1,2,0,3,2,3,0,1,3,0,2,1,3,3,2,0,3,0,0,3,0,0,1,3,2,2,1,2,0,1,0,0,2,1,0,0,3,0,3,1,3,3,3,2,2,2,1,1,0,0,3,2,1,2,2,0,3,2,1,0,1,0,2,2,3,0,1,1,3,3,3,1,0,2,0,3,1,1,3,1,1,2,1,0,0,0,3,3,1,0,3,0,0,2,1,3,1,0,1,2,1,2,3,0,0,2,1,1,3,0,0,2,0,3,0,0,2,1,2,2,0,2,94,3,0,1,0,2,3,1,3,3,2,2,3,2,2,2,2,1,3,2,1,2,3,2,0,3,1,1,3,2,0,0,3,3,3,1,0,0,0,0,0,1,0,1,3,2,0,151,2,3,2,2,3,1,1,0,1,3,2,2,2,2,3,3,2,3,1,2,1,1,1,0,3,3,3,0,1,1,0,3,0,2,0,2,1,3,2,0,0,3,3,0,1,0,3,3,2,0,3,0,1,3,3,2,2,2,3,2,2,1,1,2,2,0,1,2,0,1,3 6202009ec698263b1c9f8c307a61090cdfea50e68e44ac5fd235d640f4c27466c25c2309a2b12dfaea9e6e35e0fd0011e3bad47aafb654fc5322783c4f8c7eae96861c88b75e50 +2,2,63,0,1,3,1,1,2,3,2,1,3,3,0,0,2,1,1,1,3,0,1,2,3,3,3,2,0,239,2,2,3,3,1,1,3,2,1,0,2,0,3,3,1,1,2,3,1,0,0,2,3,1,0,0,2,3,3,1,3,3,1,2,2,3,3,1,3,3,0,6,2,0,0,0,2,1,3,2,1,1,94,1,3,211,3,3,0,0,0,2,0,18,0,0,3,149,2,3,1,1,3,0,0,2,0,0,0,3,0,3,2,1,1,1,3,2,0,3,2,1,1,3,1,2,3,3,2,1,1,1,3,2,2,1,3,3,1,0,0,0,1,0,0,1,221,2,2,2,0,2,0,0,1,2,1,0,1,2,0,1,1,0,0,3,0,2,1,3,2,2,0,2,1,3,0,1,0,3,1,0,3,1,2,1,2,2,2,0,2,1,0,86,3,0,3,1,2,0,1,2,1,1,0,3,0,0,3,1,1,1,3,3,0,0,3,3,3,1,3,0,3,1,0,3,0,0,2,3,1,3,186,1,204,2,2,3,3,1,1,3,1,3,0,3,0,0,2,1,1,0,3,2,1 620b00ac75b9f095c6fe3af5e48f5b42d0bdf6bdf2809e59ff0220db5c203395e3976f95e9f40416a2064614327a27134d9a892cd86530d5f0fdcd30b792bd773094e4021d4752555d6192c1e8ea3fb057d0497756ecc0 +3,2,38,214,202,55,136,3,2,1,75,3,0,197,2,1,0,0,1,1,95,1,32,2,1,60,3,0,224,129,2,210,2,1,2,111,1,165,2,2,2,1,3,2,1,198,1,0,206,0,2,2,0,1,0,110,2,1,2,2,3,2,0,58,0,0,161,0,0,2,2,2,196,1,1,1,2,0,3,0,2,3,1,40,3,3,2,2,3,3,2,53,77,3,3,2,1,1,2,2,1,3,0,0,2,26,1,0,2,0,1,3,2,0,3,2,0,3,2,143,1,2,233,1,0,2,3,180,1,1,142,3,56,1,2,128,3,0,3,116,0,0,0,1,3,245,2,0,3,176,1,15,3,1,159,107,0,1,3,2,1,3,0,1,0,57,0,2,102,0,0,225,1,2,2,0,2,1,1,1,3,0,1,2,121,0,3,1,3,3,97,3,1,0,3,1,68,1,2,0,168,1,0,0,0,2,0,0,1,0,176,1,0,1,1,0,3,1,3,1,0,88,0,1,1,0,0,1,2,104,1,3,14,0,108,1,0,0,49,2,0,1,2,3,2,1,2,1,0,0,2,3,3,2,2 623200eab39f1905d24c1a9b5a9e648a129ae2042a158cb4faf97e5a70a4878e3b652c5b18cc01d8c7df1e7112816895c64df74d1810204114dd01418781061b990be802030405060a0d1416191c1d1f23252d30373f4248535b5c69777a7f8284878b9195979a9ba5a8abb8bec4c8d2dde5e8eaee275c8d892c5720fe20d1ba71cdb3a8c4a3531a3ead8ce81df6c0e768e67879846ab166836cc0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000 +1,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,1,1,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1 010000a032a0ce605f1740e2cb2aae0482fd63fe2e76a626041637310bcdd9a6f745c3 +2,0,1,3,3,0,0,2,2,0,0,2,1,0,0,3,0,1,1,2,2,1,1,3,1,0,1,0,3,3,2,2,2,2,2,1,3,0,0,1,3,2,2,2,0,3,0,0,3,0,3,0,1,3,1,0,2,2,2,2,0,2,2,3,3,0,3,0,2,0,1,0,1,0,3,3,1,1,2,3,0,1,3,1,0,2,2,2,1,3,2,2,0,2,1,2,0,0,0,2,0,1,2,0,0,0,1,0,0,0,1,0,0,0,2,3,2,2,0,1,2,0,1,3,2,0,0,1,3,2,1,2,3,3,2,0,0,1,0,3,0,0,0,1,0,0,2,3,1,3,2,1,3,2,3,0,3,3,2,0,3,1,2,0,1,1,3,0,1,3,2,1,1,3,1,3,3,2,2,3,2,1,0,1,2,1,1,1,0,0,1,0,1,0,0,1,2,1,2,3,3,2,1,2,1,3,1,0,3,3,1,3,0,0,3,2,1,3,1,2,3,1,1,0,0,2,3,2,0,0,0,1,3,0,0,0,3,2,1,0,1,0,3,2,3,1,1,1,3,1,0,1,2,0,2,1 02000087c28243169744faa9c1ea30cc74aa2bcc844f5b1d2a7a26021804040ba18781e6f813010b79ecf8d85c7977eb919504419be674f70e76d42e01c0e44ed5d189 +3,7,6,0,7,5,4,1,1,2,5,0,6,7,5,3,3,0,1,4,2,5,2,7,6,4,4,4,2,0,2,7,4,2,6,4,0,1,7,3,7,4,0,7,3,0,5,0,0,6,3,3,0,1,2,3,3,7,0,2,3,7,1,7,4,1,0,2,7,1,3,1,4,4,2,5,6,2,0,3,6,5,4,0,1,5,4,6,2,5,7,6,3,1,1,0,7,3,6,2,1,0,3,4,5,5,4,1,1,4,7,6,1,0,1,6,4,5,7,5,1,5,2,1,7,2,4,2,4,7,5,2,5,6,6,4,4,4,5,4,1,4,3,3,0,1,3,3,4,2,6,1,1,5,3,6,5,4,1,1,6,3,5,7,6,2,4,5,1,1,4,0,1,0,3,4,2,0,5,1,1,4,3,0,4,0,2,6,1,5,4,6,4,3,5,3,0,4,7,0,4,2,0,7,0,4,6,2,3,3,0,4,6,7,6,1,2,4,3,0,7,6,2,7,0,0,3,0,3,2,1,4,1,0,2,4,5,6,6,7,2,1,0,0,5,6,6,3,1,7,3,6,2,5,0,7 0300007f0f612a8deb60c557d244178b407bf0762819b0537c27cf842e59915c83d6036657e648ef221cb6133e20e97d351ea29eabb492c31b05b8b135eb09cefca526021c4293188163668eb1388871326c4df1518f9701868c214bb7440bb33de547 +5,12,12,15,2,11,15,3,2,1,7,11,8,2,2,15,8,7,10,15,11,11,12,9,10,9,0,5,15,5,2,2,3,11,3,12,15,6,14,13,5,14,4,1,0,12,14,7,9,7,1,2,14,1,4,14,6,3,2,3,14,15,10,8,2,6,2,2,3,10,10,7,15,9,6,14,5,14,0,15,0,0,2,9,13,7,12,9,0,7,12,5,14,15,1,5,3,4,8,0,11,11,0,5,7,14,13,3,8,3,15,12,0,2,10,9,4,10,15,10,3,12,2,6,14,12,5,13,5,8,6,2,5,1,13,12,5,8,0,5,7,10,8,2,6,6,13,7,7,12,3,3,14,11,11,0,7,13,9,11,9,12,10,2,9,8,5,9,6,4,0,14,11,4,11,5,7,15,2,10,4,6,10,0,5,6,11,4,11,7,0,14,15,14,4,3,4,2,4,3,5,14,1,7,5,11,1,10,6,7,11,8,6,0,6,0,0,7,0,7,1,0,14,15,12,15,13,15,5,13,0,15,15,2,14,2,2,6,14,0,9,0,14,15,2,1,5,12,12,12,6,3,10,6,1,3 0400005ccf2bf3217b822f87afbbc9a905f5223b3cf6ed5e410ce79712e14e6323efa826223aa7f96e5e0f0029d7c907c5ef153480bb057ed383fc02a94afa3c26ec5d586251dc58057a8266d77c33ebb07d9b9ca29859640eb4b57f2a46a056b4b70efe4342435e175b1a67b86060070710efcfdf5d0ff2e226e090ef215ccc63a613 +10,14,0,7,16,42,6,4,49,6,51,5,16,40,43,16,43,20,60,42,42,26,50,17,27,3,38,8,29,28,60,8,57,8,20,23,13,24,14,20,26,8,28,12,59,21,56,3,47,38,20,13,34,41,40,8,25,29,14,31,13,34,36,54,5,30,21,55,21,23,1,3,53,41,10,10,47,19,56,40,22,19,27,48,42,41,3,3,54,19,34,35,9,47,40,22,33,31,8,13,60,12,12,53,6,12,9,13,55,2,47,55,34,37,4,40,15,45,3,17,37,14,42,1,19,45,36,34,54,8,33,43,56,52,12,35,35,48,36,14,20,0,47,23,61,38,53,25,16,39,46,58,4,62,15,0,31,37,5,28,12,23,16,21,47,31,40,7,5,11,26,54,35,12,26,59,45,49,49,55,58,40,31,54,42,27,4,13,6,3,24,4,55,39,46,9,18,11,2,47,5,53,30,49,5,59,32,55,19,41,43,40,46,22,58,41,49,17,63,38,6,13,24,25,21,1,33,62,45,45,19,35,21,30,51,58,19,46,16,55,31,46,47,39,34,29,32,0,12,55,44,13,29,40,52,3 06000028e00742a184c46cc5428ad0ad4f2aa9ac916c398875cf08e4851735839468870ced5e03be650d8a9a0865d39f36293615e577557043d6928abd3e285936f0aa90c3d938a326fa1685f20df0c33518c24ddc2bf78a51283ed0d194ea814ed922d8886be343238f090e500bd7f66d59427bba13e3c07e515c317415bdfa0714b6b68cc6bbb71c77ea87f6a9b10d183604de7b8948b0af1757b117b8374e9ae8b96ea9c51fe618d61954187eb6d4e355ecfa4ee4377eebe789d800337b0d768d03 +92,49,171,186,7,119,138,17,139,74,121,7,95,219,198,147,40,12,210,242,20,80,62,70,132,206,221,148,239,53,111,38,110,129,190,64,116,204,185,219,7,12,193,16,100,152,174,208,5,166,12,240,136,112,234,120,149,187,49,66,112,74,193,202,54,249,120,110,214,242,149,5,218,161,143,236,142,55,203,126,120,179,30,129,165,223,50,91,5,182,196,228,117,129,54,179,121,201,88,11,253,194,87,251,37,134,109,9,158,233,43,23,36,174,210,135,214,128,178,4,248,238,80,109,65,223,211,139,240,51,192,200,65,212,185,7,249,193,159,84,77,48,24,243,178,27,89,183,217,13,143,133,170,3,202,240,30,173,23,102,156,63,3,17,210,124,204,41,69,186,225,249,22,79,128,9,79,88,201,109,97,60,36,19,101,136,222,126,75,148,141,230,10,199,3,4,91,50,24,185,96,142,60,142,233,56,81,148,96,253,100,249,73,129,53,62,63,68,196,170,16,121,138,130,17,75,184,49,87,205,133,74,170,81,120,7,59,124,55,37,224,73,20,228,194,243,53,172,48,143,240,31,118,161,150,126 0800005c31abba07778a118b4a79075fdbc693280cd2f214503e4684cedd94ef356f266e81be4074ccb9db070cc1106498aed005a60cf08870ea7895bb3142704ac1ca36f9786ed6f29505daa18fec8e37cb7e78b31e81a5df325b05b6c4e4758136b379c9580bfdc257fb25866d099ee92b1724aed287d680b204f8ee506d41dfd38bf033c0c841d4b907f9c19f544d3018f3b21b59b7d90d8f85aa03caf01ead17669c3f0311d27ccc2945bae1f9164f80094f58c96d613c24136588de7e4b948de60ac703045b3218b9608e3c8ee938519460fd64f94981353e3f44c4aa10798a82114bb83157cd854aaa5178073b7c3725e04914e4c2f335ac308ff01f76a1967e +0,2,0,1,2,0,186,2,0,2,3,3,117,3,2,0,1,0,3,1,3,0,0,1,0,2,0,2,3,1,0,3,0,2,1,2,3,1,0,1,2,2,3,3,0,145,2,2,2,3,0,3,2,2,2,0,1,3,2,2,3,0,1,0,1,1,2,2,2,3,2,2,3,3,2,2,2,0,1,2,2,0,2,0,2,1,1,2,1,1,2,2,2,0,3,0,3,3,3,0,1,3,3,3,1,0,2,3,1,0,2,3,0,0,0,3,3,0,3,3,2,0,0,0,3,194,2,0,3,3,24,0,2,1,2,1,0,1,3,1,1,2,1,0,2,3,2,1,3,3,3,1,0,3,3,0,0,0,0,2,2,3,1,2,3,3,7,1,2,1,1,2,0,2,2,2,2,1,0,1,2,2,3,2,2,3,0,1,2,1,2,0,3,1,2,2,3,3,0,1,0,3,1,2,1,0,2,2,1,2,3,0,1,3,3,1,2,2,2,1,2,2,2,3,1,0,2,0,0,1,3,2,2,3,0,3,3,0,1,2,3,3,196,3,3,2,0,2,1,1,2,2,2,1,2,1 620700218a2f784dc122d326d1af1ab3a87ac45abafa8688965a8cfc7f4b4b03cf80e8f0991d64b9fd3c02b6fd962a91aeb198daf1364a6c7da9ab481eb3c6f3e25a99060c2d7d82a6f2b9d930181c40 +2,1,2,2,3,1,1,3,1,0,2,0,3,2,3,0,3,0,1,1,3,0,2,0,0,2,2,0,3,1,3,1,3,3,1,2,1,1,0,3,2,1,3,0,238,1,1,0,2,0,0,3,0,0,1,0,0,0,3,3,1,2,3,2,0,2,2,0,2,3,3,2,2,0,1,3,0,2,2,0,1,3,0,1,0,2,0,2,129,2,0,2,55,1,3,3,3,0,1,0,2,1,2,1,3,1,1,0,2,3,248,2,3,2,3,2,1,3,0,3,0,2,3,0,0,3,3,0,0,2,2,1,3,1,2,2,2,2,2,1,2,2,219,3,1,3,3,0,1,1,2,2,1,0,0,1,3,3,0,0,2,1,1,1,2,1,2,3,3,0,1,3,1,1,80,3,2,195,0,2,0,1,0,2,3,0,0,3,2,1,1,1,2,0,1,0,2,1,1,0,0,2,0,3,3,1,1,2,0,2,0,1,2,3,2,1,0,3,0,0,2,1,3,2,3,0,1,0,1,1,1,2,1,0,3,2,0,0,3,1,3,0,3,1,0,232,1,2,2,3,2,3,0,2,1,3 6208009ad748ecc5c828ddf6539c9483040f6e28be8728712262dfc499d4b2ee732c3c29daa9af7c5a41f0959bc753b212c395849423d621b9309ec4564e0dcd06bb272c585c6e8eaeb1f5ee037ed94c3a +2,1,3,3,2,110,3,2,0,0,1,0,1,1,133,3,2,3,3,1,2,3,0,1,3,1,2,0,2,1,42,3,146,2,2,1,0,196,1,2,2,0,2,0,3,1,3,2,85,0,1,0,0,1,2,115,0,0,3,2,0,0,3,53,1,0,0,223,3,1,1,196,0,129,38,3,2,0,2,1,3,0,3,98,1,0,0,3,1,146,2,1,254,182,2,1,236,0,3,0,3,1,1,102,1,1,2,1,2,2,247,3,3,2,2,2,3,82,250,2,47,1,1,112,2,53,3,1,2,247,0,2,1,154,3,2,1,3,3,50,3,1,255,2,1,2,162,2,1,189,0,1,0,1,94,2,3,170,1,2,0,0,238,64,138,2,100,122,166,3,1,2,91,0,2,1,148,0,0,3,3,1,3,98,1,3,3,3,205,0,1,3,217,118,3,0,0,3,0,3,0,2,1,0,2,42,0,1,1,86,0,222,3,1,36,1,1,1,1,2,81,2,3,2,2,2,142,14,49,1,64,123,3,0,2,3,0,1,0,3,2,2,0,2,1,0,20,0,3,240,3,171,226,0,4,1 623b009fae0457bdb1d89ba90688de441b0e0d43d41b89ce4369a90cd659afeaead49db26e7ede6a511ae608a2b6c903de7f476c3324a162d1566eaa53cb13a240cf81050e1e202530373f4347494a53595c5d60676e7576787b7d81858b8e92959a9da2a3a4a6a7a8acb0b7bcc0c1cdd1d3d6dce2e3e4e6e7f6f9fbfcfe6e12a4c5570ddf1809624feded9f54f8b70df6633fa2f5eaed08997a95a5633d9d295dc95230cc41e17cab8040 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000000000 +0,0,1,1,1,1,0,1,0,0,1,0,1,1,0,1,0,1,0,1,1,1,0,0,1,0,0,0,0,1,1,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,0,0,1,0,0,0,0,0,1,1,1,0,1,1,0,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0,0,1,1,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,1,0,1,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0 0100003d2d5c864d433a3ff3c90986d10765ad5a1d398a9a32bad2db0ebed314d5403d000000 +2,0,1,2,3,1,1,2,3,2,0,3,3,1,1,0,2,1,3,1,2,2,3,0,3,1,1,1,2,0,0,0,0,2,0,2,2,3,1,2,3,1,1,3,1,3,2,3,1,1,0,3,3,1,0,2,3,3,3,0,1,1,2,1,3,2,2,1,2,2,0,3,1,0,3,2,2,2,3,0,1,3,0,2,2,2,0,2,3,0,1,3,1,0,1,3,3,3,3,3,0,1,1,2,0,3,0,3,1,0,2,0,0,0,0,0,1,2,3,3,3,2,2,2,0,2,3,3,0,2,0,2,3,2,2,0,0,1,0,2,3,1,2,2,1,1,0,0,2,0,2,0,1,0,0,0,1,1,2,2,0,1,0,3,2,0,3,3,1,0,1,1,1,0,1,2,1,3,1,1,0,3,0,0,3,0,2,3,2,1,1,1,1,0,0,2,3,1,3,2,1,0,3,0,3,0,3,1,0,1,0,1,0,0,1,2,2,2,3,2,2,2,0,1,2,3,1,3,2,1,3,0,3,3,0,1,0,0,2,3,0,0,3,3,2,0,1,0,2,0,3,3,0,1,2,0,0 02000086d6e3d49dacd58022b6d77b53d2fc59e9a34eac72a2c747ff163348006fea2f22e812da5088405a138f45467530cb9542de4ccd1106aea1b79cf10b0f848f18000000 +6,4,3,7,5,6,0,2,5,5,7,6,7,1,6,7,6,4,2,1,2,7,0,5,0,7,4,3,7,5,7,5,0,2,4,4,4,3,5,7,5,2,6,6,4,7,1,7,2,5,0,1,5,1,3,5,4,3,7,3,5,4,0,4,4,3,1,6,3,3,4,4,2,7,1,0,0,3,5,6,4,6,4,1,5,2,5,6,2,3,3,5,6,3,7,0,0,2,7,7,1,7,3,5,5,7,1,3,5,3,5,4,2,1,3,1,6,6,1,4,1,5,1,2,3,3,3,2,3,3,6,3,1,4,7,2,4,6,6,5,0,3,3,2,5,2,2,7,1,7,4,1,4,0,2,0,6,2,1,1,4,1,5,1,1,7,4,0,5,3,2,6,2,2,1,3,3,7,3,1,7,5,2,0,5,7,0,7,1,1,7,3,5,6,5,1,2,2,5,0,7,7,1,7,0,1,5,3,0,4,3,4,5,7,0,0,6,2,3,4,0,1,6,1,4,4,5,5,1,6,1,2,6,1,4,3,5,5,4,3,6,5,3,6,3,1,5,5,7,7,0,3,6,1,4,4,5 030000d1fb82b7ee77d115c51e3f7d0a48efab69cf541a5d8fbb048ce6e45c80ee9a1aae4ddcf80bf3ddbcbaec459d8c34a6da6f333a9b50daa973e1810c898693e0ad648b7d9f50bc727bba94a8fcf06b11cbc0c9c07192d38ac63b63d5e66dfc3c64000005 +1,15,14,11,6,12,3,6,12,5,6,10,14,9,5,13,7,7,1,1,10,13,9,1,11,13,15,11,0,13,8,5,12,2,9,8,2,13,3,14,14,4,3,7,7,2,0,10,14,15,12,8,14,11,9,7,12,5,9,9,12,0,14,3,10,15,3,9,7,4,11,9,8,9,1,11,5,4,15,5,9,15,10,14,7,3,14,12,1,10,6,6,1,9,2,6,15,2,3,6,13,13,5,10,3,11,5,11,14,7,8,7,9,15,11,1,13,6,2,9,8,5,4,11,4,11,10,9,12,1,8,2,8,15,13,13,11,14,0,13,11,8,4,5,12,5,1,9,6,12,6,3,10,3,3,5,12,13,5,7,13,13,10,2,5,1,15,13,15,13,11,6,7,15,8,13,2,9,5,14,6,11,3,8,10,15,6,7,9,12,9,9,14,3,10,0,8,5,0,14,13,4,4,7,10,7,7,13,14,12,0,6,1,3,8,14,0,6,5,0,7,1,9,4,14,2,2,6,9,4,10,9,13,15,5,12,5,13,13,5,3,7,7,12,15,7,8,6,14,15,14,14,8,4,7,8,3 0400001feb6c36c56ae95d7711ad91bdfb0d85c2982d3ee437720aefc8eb97c599c0e3af3974b9891b54f59fae73ec1a661926f236dd5a3b5be7879fb1d629854b4ba9c1828fddbe0db845c5196c63a335cd57dda251fdfdb67f8d295e6b38af679c99e3a0850ed447a77dec06138e06507194e22694a9df5c5dd5377cf786efee8478000003 +47,14,46,45,27,53,30,58,36,2,9,55,17,49,59,44,42,1,22,46,47,25,43,42,51,16,61,50,34,5,9,60,10,61,33,18,0,41,9,14,37,1,42,37,53,36,44,52,62,26,50,10,25,21,48,21,21,41,61,32,58,54,10,8,57,4,8,59,39,5,13,29,24,47,11,22,17,45,25,60,61,39,31,5,50,55,33,49,29,17,41,56,15,60,8,3,50,39,53,41,11,6,14,4,43,27,4,10,29,20,63,17,2,52,31,10,17,55,20,47,3,61,26,54,27,25,32,40,38,54,52,39,14,37,4,35,16,61,3,45,26,20,61,25,55,57,35,20,59,4,6,1,13,53,6,13,36,4,53,41,26,62,25,0,10,58,8,9,51,11,7,48,39,51,30,50,50,59,42,36,30,28,47,18,45,52,34,56,15,3,5,11,19,4,1,21,60,48,46,21,12,4,45,47,45,12,7,55,63,18,41,39,50,53,57,3,17,13,14,26,54,10,52,58,4,61,32,2,41,20,35,55,50,27,5,0,16,38,28,5,48,54,16,55,49,40,60,8,3,0,41,37,6,50,26,38,10 060000bcebad6f57ba902277471eeca815aebd9aeacd0f7288527c2bd85202924e941aa5d64b34f9ac8a655c15569f60eb6288e4423b9c535d62f2d646d67cf677c5cb7871751a783fc203ca7d692c6384adb10a754fd10b47ca47752f0fd6b66d98289b6d273a512343d0ed694f59df98d4ec418137518d904d696be6402ba209ccb1f09f37b2cbbaa479cbd2b748b83c314b4c4055f30b95304b6fb4c1f7fd2a67cb5e4344d39ad8ad3a13d802a548f7c9b140426705c36437c68f080c0a651b26a600000a +63,49,112,166,200,81,146,73,105,173,84,54,239,52,122,107,143,81,49,200,151,141,146,237,99,194,121,81,230,47,102,169,74,57,3,135,109,84,157,135,138,221,14,78,65,87,85,72,68,118,19,78,183,100,219,240,200,30,88,48,97,161,95,126,87,186,9,145,187,103,161,202,158,157,137,20,217,157,67,89,255,205,145,82,100,89,138,158,71,59,43,51,116,103,222,153,153,62,110,33,47,149,68,34,19,145,57,245,142,33,97,17,67,53,154,216,101,230,94,115,142,128,249,111,145,137,22,118,122,233,47,128,45,65,153,60,60,7,246,231,215,84,246,192,0,151,25,43,77,14,154,46,22,90,181,53,59,97,114,137,186,255,202,166,127,20,248,53,4,93,7,31,20,254,34,25,121,191,110,78,187,115,254,79,251,8,13,254,106,192,60,0,219,37,90,116,243,75,177,241,140,77,86,87,157,175,21,99,204,51,185,23,245,242,217,98,254,140,171,43,219,206,254,118,76,250,177,217,155,214,43,116,59,167,100,41,3,47,70,188,118,155,120,130,100,109,209,134,60,72,114,20,234,42,50,250,247 0800003f3170a6c851924969ad5436ef347a6b8f5131c8978d92ed63c27951e62f66a94a3903876d549d878add0e4e415755484476134eb764dbf0c81e583061a15f7e57ba0991bb67a1ca9e9d8914d99d4359ffcd915264598a9e473b2b337467de99993e6e212f954422139139f58e21611143359ad865e65e738e80f96f918916767ae92f802d41993c3c07f6e7d754f6c00097192b4d0e9a2e165ab5353b617289baffcaa67f14f835045d071f14fe221979bf6e4ebb73fe4ffb080dfe6ac03c00db255a74f34bb1f18c4d56579daf1563cc33b917f5f2d962fe8cab2bdbcefe764cfab1d99bd62b743ba76429032f46bc769b7882646dd1863c487214ea2a32fa0000f7 +0,0,3,2,1,0,0,1,3,1,2,0,0,1,2,2,0,3,3,0,0,0,0,1,0,0,65,2,0,3,1,0,0,1,3,3,3,0,2,0,1,0,1,1,0,3,0,1,0,0,1,0,2,1,0,2,2,0,3,3,0,3,0,2,0,1,1,2,1,1,3,2,1,2,3,1,2,0,2,1,2,3,1,2,0,3,2,175,0,3,2,1,3,0,3,3,3,2,2,0,3,1,0,3,0,2,0,3,1,1,0,1,1,2,3,3,1,1,1,1,1,1,0,0,0,1,1,0,0,1,3,1,0,0,1,2,3,3,0,2,2,3,1,0,0,3,1,1,2,2,3,1,1,0,2,3,3,0,0,0,2,1,0,3,3,0,0,2,2,3,0,1,1,2,1,1,3,3,0,0,3,1,2,3,0,1,1,2,1,0,3,3,3,2,0,2,0,0,3,0,0,3,1,2,0,1,1,2,3,2,3,2,3,2,0,1,2,3,3,2,1,249,243,1,3,2,2,2,3,3,1,2,0,2,1,3,0,3,1,3,0,0,1,2,0,3,2,3,0,2,3,1,3,0,3,1,0 6204000e41d81a3c0106341fc8453104928f32165e6d89b63b39cfe8d323516f5550141d06f2b435ad4bc093c2b165f0db164fe20c3616eee1be5deaf62737063b2dcd1a57ddde42bfbc000000 +2,0,2,0,1,3,2,3,2,0,1,0,3,0,1,3,1,1,3,2,0,2,2,0,3,1,2,0,0,2,2,0,3,2,2,2,253,0,0,3,1,1,0,99,0,221,1,3,1,2,3,0,3,1,0,3,2,0,208,233,2,3,0,3,3,2,3,0,0,0,1,1,3,3,1,88,3,2,1,0,1,1,2,1,0,2,3,2,1,0,3,2,1,2,1,3,3,1,3,1,3,1,3,2,3,1,0,2,2,0,3,1,3,0,0,2,2,2,0,3,2,0,2,3,1,1,3,1,0,1,1,0,0,2,2,2,1,2,0,0,0,0,3,3,2,0,2,2,1,3,0,3,3,0,3,2,0,0,1,3,3,3,2,1,1,1,1,2,1,2,2,2,1,3,3,2,0,0,3,0,0,3,3,0,1,3,3,0,2,2,3,2,0,1,3,0,3,3,2,2,0,3,2,2,2,2,3,3,2,2,1,3,0,2,3,0,2,0,0,3,0,2,1,1,1,0,2,1,3,2,2,2,1,2,3,2,3,2,1,3,2,1,2,0,0,2,0,2,3,0,3,0,1,3,2,0,3 620600887b84c75e28d828ea4353176cd381b3ec05f4e4592e4e67ddded28dc2a38b5d142a600f8a73ce07f9566a7e0c3c7cae1cfa3aafa72c832549ea6ee79822cc78242b2d3a3b4bfd8df4e960000003 +1,241,2,0,3,1,3,90,2,1,3,0,1,0,86,0,3,3,53,2,0,1,3,3,1,0,0,84,3,2,1,2,3,237,3,0,3,124,0,2,1,2,3,3,0,3,3,1,2,2,1,1,3,3,3,1,1,120,1,3,0,0,3,1,0,2,0,143,225,2,2,3,1,0,0,1,219,1,1,20,2,0,2,58,3,108,2,0,3,138,0,3,2,199,92,0,235,3,1,1,0,74,0,3,164,3,131,1,0,3,2,2,1,3,190,101,1,0,1,1,3,0,3,0,15,1,2,0,3,0,0,0,1,1,87,2,0,96,0,162,3,1,3,1,2,2,2,2,92,0,1,95,59,239,0,2,57,0,2,2,3,3,2,0,169,1,2,3,2,139,0,2,0,0,32,3,3,1,0,1,2,0,3,2,0,0,0,97,51,3,2,2,3,230,1,3,0,0,0,1,0,73,3,0,231,1,3,2,0,1,3,2,0,195,3,2,3,2,0,1,3,1,2,0,15,0,0,3,248,0,1,1,0,1,2,245,1,2,3,3,1,248,213,151,1,2,0,0,3,9,2,1,216,2,249,219,0 62330058de9c48f61f40e6dcc26f3da5fd470d236b41d48ac8e3b0f5233d3a7945ccd8c05e02ddaa07f24af85bb203d18e01fae7011cde1e3ee1d8c305196f4760d92701070e121b21253943444c4f5355595d5e6065686a72737c86898b949798999ca4a9aebbbcc1c9ccd5e0e4ebf1f2f3f9fcfefff1654d57b7de8f8d8539b8b15fa4a982f643558a175ceeceaa22183394b9c03fbdfb5942dbed80000000 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000000000 +0,0,0,0,1,0,0,0,1,1,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,1,1,1,0,1,0,1,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,1,1,1,0,0,0,0,0,1,0,1,1,1,1,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,0,0,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,1,1,1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,0,1,0,1,0,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,1,0,0,1,0,0,1,0,1,0,0,0,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,1,0,1,0,1,0,1 01000008de037f2db8d9fdfff845ffeb93975a66770f8a32ce0bda451cc72d30b35d23010000ff1fc4a977b2b6b2b26f994622a7b56dbd28a6af87cd10eabc2ec947ceb58ad5 +1,0,1,2,3,1,2,3,2,1,2,3,3,2,0,3,1,2,2,1,1,3,2,2,3,3,1,3,1,2,3,1,3,1,2,3,3,0,3,1,3,2,1,1,2,1,3,3,1,0,3,0,3,1,3,1,2,0,0,1,1,1,2,1,0,2,3,0,0,3,3,2,0,3,1,3,2,3,3,2,1,0,2,3,1,1,2,1,3,3,3,1,2,0,0,1,0,1,1,0,3,1,1,0,3,3,0,2,3,2,2,0,0,3,1,1,1,3,1,1,1,0,0,0,2,2,0,3,3,3,3,1,0,2,1,0,1,0,0,2,1,2,2,0,1,1,3,3,0,0,1,0,1,3,2,0,0,2,3,2,3,3,0,3,3,3,2,0,2,0,2,1,3,1,1,2,1,1,3,1,1,3,3,3,0,0,0,1,3,1,0,0,2,0,3,2,2,3,3,1,0,1,3,3,1,3,0,2,1,2,1,2,1,0,3,3,2,0,1,2,0,0,0,1,2,2,2,0,1,2,1,2,2,0,3,2,0,3,0,3,3,0,0,1,2,1,1,3,3,1,1,3,1,2,1,1,1,1,3,1,3,3,3,0,0,0,1,0,1,0,1,3,2,3,2,1,0,0,0,0,3,2,2,1,2,0,3,3,2,2,1,3,1,3,0,0,0,0,0,0,1,3,2,1,0,3,0,1,2,0,3,3,1,0,0,0,1,2,0,0,2,2,1,1,1,3,0,0,1,2,0,1,3,0,0,2,0,0,1,0,1,0,1,1,1,1,2,2,1,2,3,3,0,0,3,1,2,0,2,0,2,0,0,3,0,0,2,0,2,1,3,0,3,2,0,0,0,1,3,1,0,1,2,0,3,0,2,1,2,0,3,2,0,0,0,3,1,2,3,0,2,3,1,1,2,2,1,2,3,3,0,1,0,2,1,2,3,2,1,3,1,1,2,0,2,3,0,2,3,0,0,0,0,3,0,0,3,2,2,3,1,0,2,2,0,0,2,2,0,1,2,2,3,1,0,2,2,3,3,1,2,3,2,3,2,2,3,3,3,1,1,2,3,1,1,2,1,1,0,2,1,0,2,1,0,0,0,3,2,1,0,2,3,1,1,0,1,2,2,3,0,2,3,2,0,2,2,0,1,2,0,3 02000046db9be3697af76ddbcde59f4cdd81592c3e37be4b59fd8114d4f2e8357540a3fd2442685f04782ef3f889d65d7f01d08ebd1f72664f8601a8668e33c197d7650200005dfc0447b900e98fa7700079318f4060a57061c204455a6f0d8883089ce01d18c98e036cb5a6f126e758b2c030eb4a0a1ad2bdbbafd6d652490392d46b2e2863 +6,5,3,1,3,6,7,5,1,6,2,1,5,5,7,5,4,7,3,7,2,7,2,4,6,7,2,3,1,7,6,6,1,4,7,4,6,3,5,1,4,1,5,0,6,1,6,6,0,2,7,6,1,7,5,4,1,1,1,3,0,1,7,2,7,4,2,0,4,0,0,4,3,3,6,7,7,0,7,4,1,3,3,6,1,0,7,4,6,4,1,5,6,6,1,5,2,1,6,3,0,7,3,2,4,5,0,7,2,5,6,5,4,4,7,1,0,0,3,2,0,4,6,0,3,5,0,4,4,3,2,5,4,2,5,2,6,6,6,2,4,2,7,1,6,5,6,4,4,6,2,6,6,3,5,7,7,0,1,6,3,0,5,1,2,5,5,3,3,1,4,3,6,5,2,3,1,0,0,3,1,7,6,7,1,2,6,5,1,4,3,5,6,5,3,6,7,6,0,4,6,6,7,5,2,3,1,7,0,4,4,0,7,4,6,3,3,4,2,3,0,2,6,4,3,7,6,1,0,1,2,2,0,0,2,3,6,5,5,5,6,7,3,7,0,2,0,5,5,6,0,1,4,0,4,3,7,4,7,2,3,1,1,3,6,6,1,1,2,3,1,5,2,0,3,7,0,5,6,0,4,5,2,2,0,1,0,1,5,4,4,1,1,1,6,5,6,2,3,7,3,7,6,1,4,2,7,2,5,2,5,1,7,2,3,2,7,7,6,0,0,0,3,0,4,1,6,2,0,7,7,0,0,5,2,1,3,6,2,7,6,7,4,4,2,1,6,0,0,3,5,5,1,1,6,1,0,0,6,1,0,0,7,1,1,3,2,3,2,0,6,6,6,5,7,1,2,3,3,0,3,7,1,6,4,3,4,4,7,4,3,5,2,6,4,0,6,3,6,4,6,0,6,5,4,2,7,4,4,0,2,2,3,4,5,3,7,2,3,1,7,3,1,6,6,6,5,4,0,2,6,6,0,4,7,0,7,4,6,7,7,2,3,6,7,6,7,0,2,2,4,2,6,2,5,0,3,1,5,0,5,6,1,0,3,4,7,5,4,5,2,4,0,2,4,2,4,0,4,6,7,3,6,4,6,7,5,4,4,5,3,1,2,0,7,4,3,4,7,2,7,4,3,5,1,3,2,5,5,2,6,0 030000d597bd391b7d9df5d4dd33f633cce9868c760be3ec24b07af108046f7e3c2de23cd0dd8d4731da94757593901a1307448d58aadb28b9d74996cefe0e62956b663d532033f72b531dd5ef84dbd4cf120f337130b47f1052013d6dddf085b81823030000f3a64bd894cd41f170952041b21275c9f7f18baaa9e9aff00188721f8151797de44700ed2710310392d3436d794d87ce8e4f1d5a0cf4c358bc81272be99ecedac0b6138f37e9efb84a2ca8668b8873d9540a2826ef4dec95943c73af1d2d5ab0 +15,13,4,10,7,12,11,6,4,11,2,8,10,2,5,7,2,14,9,11,15,8,7,3,0,1,14,9,11,3,13,5,3,9,11,11,8,4,4,12,9,3,8,7,15,9,1,1,3,0,3,7,10,6,10,8,15,8,3,9,1,1,4,11,15,8,14,4,9,1,15,9,9,11,7,4,9,14,7,3,1,7,0,8,7,0,3,2,7,1,1,1,13,6,9,7,8,10,4,7,6,5,9,13,8,15,13,14,5,7,6,4,6,13,3,15,14,3,12,13,2,10,12,3,9,15,2,3,9,8,0,1,2,0,2,7,2,0,9,4,15,2,4,1,9,5,14,2,9,1,13,2,10,11,6,11,14,5,9,13,12,0,12,5,10,3,5,12,14,3,5,5,3,7,6,4,14,9,13,1,7,13,8,7,13,14,11,1,12,11,1,9,1,1,14,0,13,5,13,8,8,7,15,6,1,11,10,9,15,12,14,10,5,14,8,11,0,9,8,7,11,2,0,10,14,12,12,7,0,5,5,14,14,7,6,6,1,15,11,0,4,3,3,9,1,3,10,6,7,14,12,4,2,1,5,5,5,8,5,1,13,1,5,7,6,4,7,5,5,9,6,1,3,13,5,3,5,13,6,5,9,9,14,13,15,4,6,15,5,8,7,7,15,4,8,0,5,1,11,14,8,6,11,10,13,4,9,8,10,9,11,14,0,11,13,8,12,2,8,6,13,1,4,1,15,3,2,11,2,9,14,13,14,9,5,0,15,0,13,9,10,3,10,10,2,14,11,3,5,5,6,1,4,8,5,13,9,4,10,3,13,3,9,15,3,14,0,8,11,13,4,1,2,7,14,7,1,3,11,3,2,12,2,2,1,15,9,2,2,12,7,3,8,0,3,7,10,13,8,6,14,5,13,13,6,12,3,6,9,15,14,0,13,0,7,7,0,9,15,2,7,9,7,6,13,11,15,1,9,4,10,2,3,9,8,1,6,15,4,0,6,6,5,1,7,4,13,0,14,8,3,9,14,12,14,7,7,4,8,15,4,7,14,5,0,3,13,2,5,14,12,15,8,8,10,6,9,15,7,8,8,13,3,2,0,6,2,5,13,15,14,8,8,4,0,9,6,15,15,6,15,5,5,6,6,0,6,11,4,12,3,14 040000fd4a7cb64b28a2572e9bf87301e9b3d539bb844c9387f9113037a6a8f839114bf8e491f99b749e73170870327111d6978a47659d8fde57646d3fe3cd2ac39f23980120272094f24195e291d2ab6be59dc0c5a35ce3553764e9d17d87deb1cb1911e0d5d887f61ba9fcea5e8b0987b20aecc7055ee7661fb0433913a67ec421550400005851d157647559613d535d6599edf46f5877f48051be86bad498a9be0bd8c286d141f32b29ede950f0d9a3aa2eb35561485d94a3d39f3e08bd4127e713b32c221f922c738037ad86e5dd6c369fe0d07709f27976dbf194a239816f40665174d0e839ece7748f47e503d25ecf88a69f788d320625dfe884096ff6f556606b4c3e +1,23,4,19,8,58,26,58,44,9,8,41,40,13,60,17,54,1,53,7,62,42,30,52,51,11,50,51,63,58,21,13,13,17,40,21,45,61,58,1,34,55,2,53,29,59,27,11,19,56,25,55,56,6,32,17,18,54,56,31,7,61,52,22,24,27,59,11,27,59,48,25,58,61,37,26,22,38,52,1,1,46,26,0,26,23,38,27,4,31,42,30,31,53,19,23,11,55,3,35,18,41,50,19,39,22,57,58,26,26,42,5,39,18,22,15,18,61,20,48,62,20,6,63,12,9,30,28,0,55,57,26,17,51,54,1,44,55,28,25,59,22,53,18,50,59,14,38,0,26,54,33,30,20,24,21,22,8,19,30,23,40,24,10,7,46,4,7,32,6,33,2,48,56,1,44,29,24,15,30,45,9,29,10,58,37,62,14,24,41,38,23,43,49,33,1,40,50,38,16,26,46,63,41,31,57,34,24,32,43,27,62,62,7,36,17,50,24,1,62,15,55,29,51,15,16,57,8,1,6,19,13,38,5,26,21,52,45,27,48,55,51,9,22,60,9,17,62,17,41,27,28,59,63,1,63,34,18,5,52,56,57,60,8,33,3,17,13,37,13,4,10,23,25,33,49,14,4,19,1,45,6,19,1,11,37,4,38,41,43,29,37,13,17,23,5,34,11,44,19,61,0,55,2,46,16,48,12,8,32,31,9,26,53,9,5,26,7,63,52,7,61,62,25,58,33,4,58,3,16,20,21,25,57,42,18,30,61,26,34,43,34,43,11,26,39,22,46,47,2,40,40,53,11,15,31,34,50,55,13,58,63,31,52,50,14,4,13,59,11,33,61,63,60,8,32,32,30,32,57,16,61,23,7,31,21,37,38,25,28,59,54,20,13,47,1,8,34,32,42,6,11,47,28,31,18,28,15,20,9,56,49,32,30,14,0,54,34,35,43,60,44,52,25,0,6,37,12,44,12,23,54,46,57,10,32,24,45,50,38,35,50,54,33,9,7,7,18,49,52,14,2,31,59,2,14,59,63,32,47,37,16,44,10,11,26,27,12,59,32,53,15,15,33,29,22,47,58,8,8,3,34,0,1,14,21,32,31,4,18,24,38,40,19,63,53,29,53,18,10,6,16,62,39,28,12,58,2,58,63,3,39 06000005711323a6bab09229a0df11d81d47faa7b4ccbcb3ffa54d351a15b7de818b70b577b6cb4f8677e068114b6e1f1fdd1661becb6fbc19ebd95a5a6d0106e68069799b11fa9e7f54d72f70e34a9c939d6e7a69aa859d258f4bd530f941bf30979c037e5a473d81b37719ed6d52cbb3a601ada17946155884de5e860a1ee107806842c3806c7583deb4974aea5f8e629997af1841a329906aefe97f989882b6fef87911c9807e3f77733d0e480464cd985695d2d6f0df3256f0947e4696dceff07f060000892174e39f0884344d94d10a5d98713844c1b464c12e5126a6b7653515c588bb13f40dc2b90c0c2207c96b5245687ff41fdf99ea113a0d0515679a927bd6a2ae2acb6a75aebc2a28d4b3df8b2dcdebf7f4c8e10decb87dffc22081e83943d5c77d596665cef650dbc122282a18bbdc7d270f509e3181e380da28ebf2cd1900694cb0c5f6bb92a062dca68f2da12471d2c743827fb08eeff82f950b0a2da6ccee0d4f3e1756bfa2080e200139581f112626a13ff577548a190fa770ce82ebf0e7 +217,186,90,3,155,51,127,185,6,206,246,132,12,145,163,146,36,136,130,43,19,11,33,90,151,14,46,130,97,229,187,15,15,177,216,3,248,122,159,95,140,73,248,173,17,245,99,240,100,10,87,126,233,1,235,173,124,166,146,16,153,247,218,14,73,187,45,148,146,26,55,240,208,92,23,29,125,113,127,214,225,7,43,224,45,249,120,197,248,141,113,172,43,81,134,253,185,44,156,94,208,137,178,16,204,161,158,120,69,73,234,165,222,14,213,90,212,142,121,79,17,99,202,213,204,250,56,117,150,93,76,234,243,8,118,49,66,72,20,155,227,169,19,130,16,114,22,154,239,64,246,206,0,167,19,133,40,150,143,7,138,22,1,30,233,43,176,53,229,191,100,133,215,29,205,65,191,222,191,49,174,254,83,53,143,218,218,185,49,67,113,244,160,232,200,239,168,27,160,157,23,233,23,28,226,99,208,120,164,14,248,87,58,191,1,72,93,104,175,12,95,6,7,62,52,236,2,200,166,18,230,188,203,97,15,69,111,37,74,56,6,62,57,151,223,134,118,59,130,229,212,237,99,99,20,159,96,124,96,35,208,154,58,110,14,76,75,206,170,255,26,229,158,191,99,245,2,119,217,37,22,19,60,226,198,131,31,237,115,73,67,220,166,4,35,209,169,51,63,180,204,114,15,189,186,62,135,13,113,85,223,164,20,54,75,102,253,132,250,91,221,108,5,182,214,158,45,136,105,115,36,52,23,42,213,121,25,50,212,156,122,13,113,88,33,52,231,219,112,97,35,34,39,220,177,148,248,41,15,4,133,175,223,60,2,36,232,154,22,2,51,12,90,179,123,153,184,8,77,17,235,240,124,15,99,211,154,232,206,5,80,74,167,218,233,167,22,50,48,219,136,72,4,104,124,131,129,243,44,244,46,219,6,142,218,117,165,164,100,218,155,157,222,195,25,66,196,213,254,93,171,69,235,209,135,80,6,92,99,236,25,18,154,70,253,211,243,5,247,115,242,159,13,151,39,152,136,52,121,24,70,158,180,102,67,189,118,88,56,56,221,135,171,163,48,220,116,247,31,13,81,104,189,135,51,53,39,2,247,168,155,109,74,123,100,55,71,87,55,100,32,34,72,19,75,182,27,125,183,66,115,148 080000d9ba5a039b337fb906cef6840c91a3922488822b130b215a970e2e8261e5bb0f0fb1d803f87a9f5f8c49f8ad11f563f0640a577ee901ebad7ca6921099f7da0e49bb2d94921a37f0d05c171d7d717fd6e1072be02df978c5f88d71ac2b5186fdb92c9c5ed089b210cca19e784549eaa5de0ed55ad48e794f1163cad5ccfa3875965d4ceaf30876314248149be3a913821072169aef40f6ce00a7138528968f078a16011ee92bb035e5bf6485d71dcd41bfdebf31aefe53358fdadab9314371f4a0e8c8efa81ba09d17e9171ce263d078a40ef8573abf01485d68af0c5f06073e34ec02c8a612e6bccb610f456f254a38063e3997df86763b82e5d4ed6363149f080000607c6023d09a3a6e0e4c4bceaaff1ae59ebf63f50277d92516133ce2c6831fed734943dca60423d1a9333fb4cc720fbdba3e870d7155dfa414364b66fd84fa5bdd6c05b6d69e2d8869732434172ad5791932d49c7a0d71582134e7db7061232227dcb194f8290f0485afdf3c0224e89a1602330c5ab37b99b8084d11ebf07c0f63d39ae8ce05504aa7dae9a7163230db884804687c8381f32cf42edb068eda75a5a464da9b9ddec31942c4d5fe5dab45ebd18750065c63ec19129a46fdd3f305f773f29f0d97279888347918469eb46643bd76583838dd87aba330dc74f71f0d5168bd8733352702f7a89b6d4a7b643747573764202248134bb61b7db7427394 +3,1,1,0,1,0,3,0,0,1,0,2,2,1,0,3,1,3,2,0,2,2,2,2,0,1,3,1,1,0,2,0,1,3,3,0,3,0,0,3,2,1,1,1,0,160,1,1,2,1,1,1,2,0,3,3,3,0,0,2,2,1,2,3,2,1,3,0,1,3,3,3,1,1,2,3,0,0,0,0,0,0,0,2,0,3,2,3,0,1,0,3,1,1,3,2,3,2,0,1,1,2,3,1,0,2,3,3,3,3,1,2,3,2,2,3,3,1,2,0,2,1,2,3,1,0,0,3,0,1,3,0,1,0,3,2,0,2,3,1,1,2,2,0,0,0,23,3,3,2,2,2,2,1,0,0,1,3,1,1,2,0,2,3,3,1,0,1,3,1,2,0,1,0,1,3,2,0,2,0,1,3,2,0,2,2,0,3,2,3,1,2,0,3,2,0,1,1,3,2,3,0,3,1,2,2,0,2,3,2,3,2,2,0,1,0,0,3,0,0,2,2,0,2,0,3,1,2,2,3,1,0,0,2,2,3,0,2,1,0,2,2,0,2,0,0,1,0,0,1,2,1,1,3,0,2,3,0,1,1,3,1,1,3,2,0,0,2,2,3,3,0,2,2,2,2,3,0,2,1,2,81,3,0,3,0,0,3,2,0,1,0,3,0,0,2,2,3,2,3,3,1,1,0,0,0,2,0,2,2,2,2,1,1,0,3,3,0,0,0,1,1,2,1,2,1,0,3,3,204,2,1,2,3,3,2,190,0,0,2,2,0,3,0,2,0,1,3,1,2,2,0,0,1,3,2,1,3,3,3,1,3,2,3,1,3,2,3,1,2,3,0,3,2,0,1,3,85,0,0,199,1,1,2,0,0,3,3,0,1,3,1,2,1,2,2,2,0,3,2,2,0,201,0,1,3,3,3,0,1,2,2,2,1,3,2,0,2,1,1,3,1,1,1,0,2,3,2,0,0,0,0,0,0,1,0,1,0,3,3,3,0,1,0,3,1,0,3,1,113,3,1,0,1,1,1,3,0,2,3,2,2,2,1,1,0,2,1,1,1,2,1,3,2,3,3,0,3,1,3,1,0,1,1,1,3,0,0,3,3,0,0,1,2,3,1,3,0,1,0,0,3,2,0,2,0,153,2,2,1,3,2 620200d44c129378aa1d487cc39505958fc29b9c7f5b00023b135ee16d2ff6ebd89b431c4e2d680fea90758bd1d8478878a3b6385ecda2ee8430a236b42b24a20419722d92a050620800c5d782bcaac99cc384c2bbd408aa53c05993c9be828c87681e7f7b7b6ce1d0d60f1d9a8e847f1a9e25d52e00044fc4d35d15cba94959ef374570f06dc438869e194950797c92c1fa533bd5c72726 +2,0,3,2,1,2,0,139,0,0,3,3,168,204,2,1,1,2,3,2,3,3,3,1,2,1,0,3,3,2,198,1,2,2,3,3,0,0,2,3,3,0,0,1,3,0,0,1,10,1,2,0,3,1,1,145,2,2,1,210,1,0,3,3,3,3,114,0,2,0,131,3,0,0,2,2,237,0,0,2,2,3,0,2,1,2,237,1,1,1,3,1,1,3,0,1,1,80,3,0,1,3,3,1,3,2,1,0,2,1,0,0,1,3,2,0,2,0,0,1,2,2,2,1,3,0,0,0,3,1,0,3,3,1,0,0,1,3,0,1,3,3,0,2,1,3,0,2,2,0,2,2,1,1,0,239,2,0,1,0,3,2,1,2,3,1,1,3,1,0,3,0,3,1,0,1,1,2,3,1,3,0,1,2,3,1,3,3,2,0,0,0,0,2,1,1,3,3,1,0,3,142,2,1,3,1,3,1,0,2,197,0,2,2,2,0,3,3,0,0,3,1,60,0,1,0,2,1,3,0,1,3,2,1,1,2,1,2,238,1,1,3,0,0,0,0,1,0,3,3,1,2,2,2,2,0,1,2,3,1,3,0,2,2,0,103,2,1,2,0,3,1,0,1,0,0,253,3,1,3,0,1,1,0,2,0,1,2,1,0,1,1,2,1,3,3,0,3,249,1,2,2,3,3,1,1,85,1,1,2,3,2,1,3,2,0,1,3,241,1,1,149,3,2,2,2,2,2,0,2,2,3,3,2,0,3,3,1,3,99,0,3,2,2,2,1,1,3,2,3,2,2,0,3,2,0,0,2,2,0,1,0,2,0,0,2,3,1,1,95,0,3,3,2,164,2,2,0,3,3,0,20,3,3,1,1,3,2,2,3,2,0,0,1,0,1,1,1,2,2,1,2,2,3,2,0,0,1,3,1,3,3,2,3,1,1,2,2,2,3,3,1,3,1,3,3,3,1,2,3,3,0,213,2,1,2,2,2,2,0,1,3,2,1,99,0,3,0,2,3,1,3,0,0,2,3,0,3,2,2,3,0,2,1,2,1,3,0,3,1,250,1,0,3,49,1,0,3,1,1,2,0,3,0,2,2,1,3,0,3,0,1,2,2,2,2,1,3,0,1,2,3,1,2,2,17,1,2,1,0,2,3 6211008e630f096efd93e9af0bc1c198d5a64ff88f0a42b2655d714c7de4907881a9c0d3d071f2728a5384e6d74cd16dc6df8025f4e9dd24a8f0d049c796697004f6a8070c0d1e30373b42464c56619bc9d2deee8aacf10a4d1c83bed4ee3c4fec620f006dca398d10771486459f35af556e78755eaa2be3df3a97ba3828482d73e28f0f5eb8115a6b81dfb5abddfdbc66a879ccb70b3ac99cd935358ca731aa71b6964b09142a323e415371767db0bcd6daf967ff95f25617a45d58f8c100 +3,1,1,149,3,3,1,0,0,0,0,2,0,1,61,3,0,3,253,2,220,210,211,3,0,3,101,2,2,2,3,1,2,2,1,3,1,1,1,239,2,175,3,1,2,3,3,1,2,1,3,0,44,3,3,2,3,0,3,0,0,0,3,1,0,1,0,97,2,3,0,223,0,2,3,1,2,3,2,1,0,3,3,3,1,3,1,1,2,119,147,2,3,1,2,1,1,57,244,0,0,0,0,0,3,1,1,0,0,109,3,1,232,3,198,1,2,1,56,59,3,0,0,1,15,3,2,3,0,57,0,0,2,242,1,0,3,100,47,1,0,2,3,2,2,0,3,0,1,2,1,2,200,0,3,1,3,3,3,2,0,174,2,162,2,2,1,2,86,0,2,3,2,0,1,51,1,0,131,34,3,1,1,0,1,1,71,1,2,3,1,2,1,0,193,0,3,1,67,2,0,0,2,2,105,0,3,0,43,2,2,1,218,3,66,2,2,2,0,3,1,2,145,213,184,0,2,0,172,100,1,0,2,167,3,61,3,217,221,2,1,1,3,2,1,0,139,0,208,0,0,0,177,3,2,18,0,2,1,2,3,2,0,3,1,3,0,203,3,2,0,1,246,208,2,3,107,2,70,1,1,2,0,2,3,2,0,1,140,3,3,0,3,2,0,22,3,1,2,2,2,1,0,0,0,2,0,2,1,0,0,1,1,0,2,0,254,1,2,1,1,1,3,128,1,112,2,2,0,0,2,0,142,133,2,1,3,0,1,0,155,0,1,0,9,3,0,90,0,169,1,141,0,0,3,0,2,131,110,0,2,0,0,2,2,1,107,0,2,1,1,3,247,2,0,1,2,1,202,231,1,66,3,1,2,3,122,0,2,3,0,1,127,0,3,0,99,1,1,76,2,3,3,163,2,0,0,3,232,0,1,0,2,2,3,1,10,2,2,1,154,3,0,2,0,2,0,2,2,0,171,1,1,188,2,1,1,144,3,1,2,3,11,1,3,59,3,0,0,3,0,0,0,3,2,2,3,2,2,3,2,3,0,97,0,1,2,2,251,3,3,2,2,1,3,0,2,1,1,1,108,1,1,3,95,3,2,0,2,3,3,2,1,1,42,2,2,1,2,95,3,2,19,2,2,22,2,1,0,1,2,217 623500d5f40217362f36ada757bdbd9c3ecc0d11b32db93f75bed95000d41d3993c1fb10a4cd2e8c660dfe2aa68b874ed45db644de0a4ce9baa3650804bdd65e4c007a030e121415161a2729344347595a61626d707276777c8185898a98a1a3a8afb2b3bac2c6ccd0d4d6dedfe0e4e5e9ebedeef6f8fcff94fff7d3467bacb6377643bd6fac4e3833bc64bcaba15320211c1068ad90935bab6693f6de2d2c10622e0026e373e18be962e13ce2da90224148995c4a0899c4c472150cb8829c97e19b6db8b1ccd4bf8304ada9b2228d494dbdfc303aebb11afe9c9517f8be5a9beea9190b1011141620273c43454c4d54585b5d5f65666e747a7b7d82888c8f9398a0a4aeb1b5babdcfd4e0e4eef3f6f9ffcbdd1a46317f81c8e19825aa8e06daf72e5079f613a3a0a6aaf902398f9b5ca5c41760 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 000000000000000000000000 +0,1,0,0,1,1,0,0,1,0,0,0,0,1,1,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,0,0,1,1,0,1,1,1,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,1,1,1,1,0,1,1,1,1,0,0,0,0,1,0,1,1,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,1,0,1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,0,1,1,0,0,1,1,0,0,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,0,0,1,0,1,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,1,1,1,0,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,1,1,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1,1,0,0,1,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,1,0,1,1,0,0,0,1,0,0,1,1,0,0,1,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,1,1,0,1,0,0,0,1,0,1,1,0,1,0,0,1,1,1,0,0,1,0,0,1,0,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,0,1 0100004c87417dacdcaf6eb2426d621f8546f785a22f69b15d3ef249dcfd0fe96e80580100000b354d81610ce6c9615d2667559f154fd0ce6e71df94af6be71b6c64cdd5716d0100001139a2bb200a50a7a37ec9b77fedd25dfd030c209162c079e6987a499a9f90fe0100002b0ff942e313ce603c040ac86dfbddfc92b132f36e5f158b45a7245f11 +3,3,3,3,2,1,0,3,0,3,2,0,0,3,2,1,2,3,2,0,1,3,0,2,0,3,2,2,1,0,2,1,2,0,0,2,0,1,0,0,3,3,3,0,1,2,3,0,2,1,2,1,3,2,3,1,1,2,2,0,1,1,2,0,0,0,3,0,2,1,0,2,2,1,3,2,0,0,1,2,2,3,1,0,3,1,0,0,1,3,1,2,1,2,2,1,0,2,0,2,3,3,0,2,2,1,0,2,3,1,0,1,2,2,2,1,1,2,2,0,2,0,3,1,0,3,3,2,0,3,0,2,0,2,1,0,0,3,1,1,0,3,1,0,0,2,0,1,0,3,3,3,3,1,2,1,2,0,1,3,0,0,1,3,1,0,0,0,3,0,0,2,1,2,3,2,1,3,0,0,1,3,0,0,2,0,1,2,3,2,2,1,1,3,1,0,1,0,1,1,2,1,3,2,2,2,0,2,3,2,0,3,2,2,2,1,3,3,2,0,2,1,2,3,1,3,1,2,0,3,2,3,1,1,3,2,2,2,2,2,1,0,1,1,2,0,3,3,2,3,0,0,1,2,2,2,1,2,0,1,0,2,0,2,2,2,2,3,0,3,2,2,2,0,1,0,1,0,1,1,2,3,2,1,2,1,1,3,3,2,3,3,2,3,1,0,0,3,3,3,3,1,2,2,2,1,3,1,3,3,1,0,3,0,0,1,2,0,3,1,1,0,1,1,3,2,2,0,0,1,1,2,3,1,3,2,0,2,0,0,2,1,1,2,0,3,3,3,3,0,0,0,0,3,2,0,0,1,0,3,3,0,3,3,2,3,0,1,0,3,0,0,1,2,1,0,1,3,0,0,3,1,2,0,1,1,1,2,3,1,1,2,3,0,3,2,2,2,1,0,3,2,3,2,3,0,2,0,3,3,2,0,2,3,2,3,3,1,1,2,0,3,1,1,1,0,0,0,2,0,0,1,1,1,0,0,0,3,2,1,3,2,0,2,2,0,1,1,0,0,2,3,3,2,0,0,0,3,2,2,3,2,2,0,0,0,0,0,1,3,2,2,3,3,0,1,3,2,3,1,3,1,2,2,0,2,2,3,0,0,0,0,1,0,0,0,1,1,1,3,0,3,2,0,1,1,3,1,1,0,0,3,1,1,1,1,1,0,1,1,0,3,2,3,0,0,1,1,3,3,1,2,3,0,2,0,3,1,2,3,2,1,1,3,2,0,1,2,0,3,2,1,0,1,3,1,2,0,0,2,1,2,0,3,2,1,0,0,2,0,0,2,1,0,0,0,2,0,0,2,0,1,0,0,3,0,3,3,2,2,3,2,1,3,3,3,0,0,3,1,3,0,0,1,0,2,2,0,3,3,1,3,3,1,1,3,3,2,2,0,0,2,2,1,1,0,0,1,0,0,2,1,2,2,1,2,0,0,2,1,0,2,1,0,3,2,3,1,2,3,1,2,0,2,1,1,1,0,1,3,1,0,3,0,1,2,2,2,0,3,1,1,0,2,3,0,3,0,2,0,0,2,2,2,3,3,3,0,1,0,1,1,0,1,0,1,0,0,3,1,0,2,1,0,2,0,0,3,2,0,0,0,2,1,1,3,3,3,0,3,1,2,0,2,1,1,0,3,3,0,0,2,0,1,0,0,3,2,3,1,0,1,1,1,2,2,2,1,3,2,3,0,0,1,1,0,1,1,2,1,1,2,1,3,1,3,2,0,0,2,2,3,1,2,2,1,0,3,3,0,0,0,0,1,3,2,3,0,0,2,1,0,3,0,1,2,0,2,1,0,2,0,3,2,0,0,3,2,3,1,1,2,0,2,3,3,1,1,0,2,2,2,1,1,3,1,3,1,0,1,1,0,0,0,1,1,2,2,3,0,3,1,2,2,0,3,2,2,0,1,0,1,3,1,2,1,2,0,2,1,2,1,1,2,3,1,0,2,3,0,0,0,3,1,0,0,3,3,0,2,0,0,0,2,0,2,0,1,0,2,1,0,0,0,3,0,2,1,2,0,3,2,2,0,2,3,1,3,3,3,1,2,0,3,1,2,3,2,1,3,3,1,1,1,3,1,3,2,1,0,1,3,2,2,2,1,0,3,2,1,1,3,0,0,1,2,3,2,0,3,1,1,2,1,3,3,1,0,1,2,0,2,3,2,2,0,0,0,1,2,1,0,2,1,0,0,0,0,1,1,0,3,1,3,3,1,0,2,1,1,3,1,1,0,3,1,3,1,3,0 020000ff933839b8723a498210fc6c99ed68580c929e06b4d0766922f292d1a9688d3e32243534213fd9870740c26e707086e974459ea2e3a9f89b763b5eaa458fb06a0200006122ab3a8445b997efb43fda9df4c18d45e816de20963fc03813cfb1306470d856d6cea4eec8f8bbd63540815039e2850be03ae8007af1edda2b004057385d4302000055453b05f6c8db9786391d82639082408210cfae7f0dc128f7d7e8294109a60924edb625474c6a352cc82afc45110d24838097f36253c210ed15a9ec145967780200002b693c01ec24c6248e0ed62f52a5dd1405acda3a11d98996d2c0d0f20221240c98e8b7f636e7d5de47a939706e359f462e8064900537d25d4ddc +3,7,4,6,6,3,1,6,2,3,5,3,3,5,7,4,1,6,1,4,1,5,1,2,4,6,5,1,7,6,2,3,5,2,1,2,1,3,5,5,0,2,6,1,6,4,6,5,1,7,0,4,2,5,4,7,6,0,1,1,3,0,7,2,6,0,5,3,5,3,1,1,5,7,7,5,3,5,6,2,0,4,7,6,0,7,6,2,7,7,1,6,1,3,0,0,4,6,4,0,0,3,5,3,4,4,1,3,5,6,0,5,1,7,2,4,4,2,3,3,6,2,4,4,4,6,5,4,0,3,7,3,1,0,1,5,6,4,3,3,6,4,1,4,5,0,4,1,2,7,5,7,7,1,1,4,7,3,5,0,5,4,3,0,1,2,7,2,2,5,1,5,4,5,7,7,1,2,4,3,7,7,4,5,2,4,5,6,5,0,2,4,7,5,0,4,3,7,3,6,6,1,0,0,4,7,2,3,2,3,0,2,2,5,4,5,7,1,6,3,1,0,4,6,7,5,2,3,0,3,2,0,7,0,7,6,4,3,5,0,5,2,5,7,3,0,0,1,1,6,4,2,5,1,7,7,0,6,1,5,0,3,4,7,2,3,6,4,6,5,3,6,3,7,6,5,6,3,7,0,6,5,6,1,4,5,5,1,5,6,1,7,5,4,7,2,0,3,5,2,7,5,4,2,1,0,3,0,1,2,7,3,7,4,6,1,6,1,5,1,7,5,5,0,2,0,2,3,1,3,6,5,3,6,4,0,6,0,3,4,0,2,2,7,2,1,2,5,4,1,0,7,5,7,0,0,3,7,5,7,4,2,5,6,5,5,6,1,4,2,1,4,1,5,4,7,6,2,6,2,0,1,4,7,4,5,5,4,3,1,2,4,1,1,2,1,2,7,5,3,7,5,4,5,7,2,5,3,5,0,6,6,5,3,3,2,2,1,3,1,1,2,7,4,3,6,3,5,5,3,3,6,2,6,3,7,5,3,5,2,6,5,6,4,6,0,5,2,7,1,4,7,4,4,5,3,4,3,3,3,3,5,6,5,6,5,4,6,1,3,7,7,0,3,0,6,3,2,6,4,3,1,3,6,5,2,0,1,7,3,6,6,7,1,7,5,4,0,2,5,5,0,6,1,6,6,2,1,6,2,7,5,1,2,7,1,2,5,4,4,1,7,6,7,1,7,7,2,2,6,0,6,1,0,7,0,0,4,4,4,4,6,4,0,4,1,1,1,4,5,6,1,7,2,7,4,1,3,3,5,4,1,1,4,6,1,4,6,5,0,1,3,2,1,5,0,2,7,6,1,0,2,6,2,3,4,7,6,2,2,6,1,4,2,2,4,0,6,4,2,2,3,6,4,5,6,5,6,0,6,4,5,7,0,3,1,6,1,7,4,6,5,5,2,0,5,3,1,0,3,3,3,7,6,6,7,1,5,7,6,2,6,5,6,6,3,7,0,2,2,1,3,5,0,6,2,2,5,1,7,2,2,0,7,7,3,6,1,4,6,0,6,4,2,4,5,5,2,0,4,7,7,7,2,4,0,1,1,2,6,3,7,2,6,0,0,6,3,7,3,5,7,2,3,2,6,7,6,5,7,3,0,1,3,6,5,1,3,2,3,2,6,2,4,2,0,7,3,2,5,6,4,0,1,3,4,0,0,0,3,1,4,1,2,3,0,6,0,3,4,2,0,6,6,7,1,6,0,2,7,7,3,7,1,5,3,6,3,6,2,6,4,0,1,1,3,6,3,0,6,5,3,6,3,1,6,6,5,4,4,1,2,0,0,6,3,6,6,5,0,0,1,4,3,5,7,7,1,0,6,3,1,7,1,1,5,6,0,7,5,6,2,3,3,5,3,3,4,7,1,0,6,2,6,6,6,2,2,2,0,3,3,4,6,5,0,7,3,6,7,2,7,4,3,4,1,3,1,6,4,6,6,3,6,2,0,2,3,1,3,1,2,1,1,6,7,1,5,6,4,6,2,7,7,3,0,3,6,2,0,1,6,3,2,1,0,5,7,6,3,5,2,5,6,5,0,6,0,3,5,2,3,6,1,4,4,6,2,2,3,5,5,7,5,7,5,4,0,6,3,3,1,0,0,6,1,4,5,6,3,4,1,1,4,1,5,3,4,3,3,6,1,7,4,2,6,3,7,1,6,7,6,5,5,6,3,1,7,3,2,3,7,4,4,4,6,3,3,4,3,5,2,5,5,6,2,5,2,1,5,1,0,5,4,7,2,7,1,5,4 0300007e6cce4eb77c38c34a9a9f93a8a2ed0b1d353c4567c0963ac2bac9bfd77213e1f2fce2c09a00eb90bb853d489bca49ac0fb20dd1bd0ca215efe4cee8b182ba54d97f2a3fe552ea14f447dec409d34c2565e73226f530d0e3e8e8aaf6013a2a7f03000018d0e74f4d5e7f5cf8d71969b8fb3a0eaf622182bbf31c69f684132f57a0c1c097455847bc07ef8aeb7188c367cb206796c6542515ebf65eaba36ada4592bc79dade59faead74c2ae6792b8db775d662ff0c66b465ea81ef6e7d815a31d91cbd0300002b95643f73fa5862381249a0849971ebc2dd84cc66a0b4685f10b273e4b18941a24f4bae1a5e19c7cd6a1590dbfb737e5aecf848ba3254f487ef19868a5a84ffa80959f580cfbbd35bebd82f52d359443b57405c00330a630710db9c17ef9af3030000cb404bcc6af33b590a033da8063bf9199e4dc3dc9badce465b64906e6a3bdd78e1674d9e4132ca277374cbf61e40e688bf3aaea30753c64c93b7df60cd903197384c35c6f1f167cefadccf69f9266e3aadcaa348b3ae6c +10,0,2,1,7,5,10,12,8,14,6,0,3,12,6,10,14,12,1,0,2,15,2,4,12,1,5,8,15,6,15,15,8,11,5,11,2,6,10,3,3,5,9,15,7,8,6,6,11,6,6,3,5,11,10,15,14,0,5,4,0,14,3,0,15,12,9,7,11,5,12,12,5,4,1,1,12,13,13,3,10,9,14,5,12,9,9,1,6,2,14,10,6,13,2,0,14,7,9,10,14,3,4,9,9,6,5,15,11,1,3,11,11,9,2,9,13,14,7,13,12,6,10,7,8,2,14,6,9,15,13,4,4,1,8,1,9,15,9,10,13,8,8,13,9,2,15,5,15,10,3,2,2,12,11,2,1,2,1,15,8,15,15,12,6,12,14,1,15,1,11,6,14,9,7,0,6,3,11,5,1,3,2,6,8,7,13,9,0,10,14,12,4,3,13,5,2,4,11,9,7,2,14,8,12,6,9,1,14,5,14,0,9,11,12,10,1,15,8,13,14,7,6,4,13,6,15,1,2,11,5,13,15,6,14,2,6,7,14,2,2,2,2,6,12,4,13,0,0,2,7,10,1,1,15,11,14,15,15,8,8,3,9,14,12,13,9,7,7,8,12,2,7,13,9,5,1,10,9,9,15,5,1,10,9,13,8,12,15,8,7,14,5,7,7,10,0,10,12,7,7,6,8,0,7,3,15,10,9,4,4,7,15,12,6,14,10,7,4,1,14,13,14,1,14,3,11,3,10,11,1,10,15,15,8,6,15,5,9,10,5,3,6,8,5,12,15,6,3,0,5,15,10,11,6,0,10,14,4,12,12,7,4,7,12,6,1,14,14,3,3,0,1,6,11,1,15,0,2,5,4,0,4,7,4,4,2,12,5,0,2,14,7,1,3,7,4,2,10,12,4,4,3,8,9,10,12,7,1,2,11,9,6,0,4,5,0,5,11,10,6,14,3,5,9,15,5,14,0,9,9,7,0,1,9,3,12,0,9,15,4,14,14,3,3,11,12,6,6,13,9,2,11,0,13,1,9,9,3,0,0,4,8,10,4,8,10,11,14,3,7,9,1,14,14,13,13,2,10,13,1,8,11,14,13,7,10,14,2,6,10,14,11,11,2,3,11,5,9,14,13,10,8,14,9,1,6,12,10,8,4,9,12,1,6,15,1,9,2,11,6,6,14,11,9,12,8,1,5,5,9,7,7,4,1,9,2,3,14,2,7,3,13,3,13,13,8,4,12,7,9,12,11,11,5,13,3,12,13,3,9,10,15,1,5,15,12,13,1,10,6,8,12,1,9,9,4,5,3,13,9,3,15,8,5,10,0,5,15,2,15,0,1,11,9,5,11,14,4,7,0,14,11,10,8,7,4,11,3,5,11,7,7,9,11,4,1,13,1,2,9,11,2,2,15,11,13,2,8,11,11,8,9,8,5,3,7,0,11,1,1,0,5,8,0,5,10,13,0,15,15,12,0,9,6,13,3,0,3,7,15,14,6,10,1,14,11,10,9,9,5,13,15,1,10,11,10,10,10,6,5,9,4,11,10,8,9,6,9,10,11,0,14,11,12,6,5,15,2,13,10,14,15,13,13,2,9,10,10,9,9,12,2,6,7,15,4,8,9,5,9,9,5,1,0,14,9,11,14,3,5,10,0,10,9,9,13,10,2,14,0,9,8,3,5,8,10,2,4,12,4,10,5,1,7,1,7,2,8,7,11,9,2,1,9,8,5,13,14,2,15,14,3,10,9,11,7,7,5,15,15,13,2,12,11,14,3,10,11,7,2,14,1,8,7,14,2,8,4,0,3,14,13,4,9,13,13,7,14,5,1,0,3,14,2,8,4,3,5,4,9,12,12,1,4,0,12,12,9,1,15,13,14,6,15,13,13,11,0,14,6,13,15,4,5,13,14,0,5,14,8,3,5,0,8,6,9,11,1,2,9,1,2,10,9,3,13,6,13,8,0,7,14,4,8,7,13,2,4,8,13,4,6,10,12,2,8,3,14,14,12,13,3,3,4,5,12,1,12,13,0,12,13,7,15,7,14,11,15,14,4,9,6,4,4,9,3,10,6,4,3,15,8,8,0,6,1,5,11,14,14,15,10,4,6,15,0,0,6,7,5,14,3,4,7,15,14,8,15,0,7,7,12,8,4,1,1,6,13,5,8,2,2,8,13,11,1,8,0,14,1,15,11,0,12,0,2,9,9,0,8,0,10,3,15,11,15,11,7,3,15,13,9,7,10,9,9,15,1,11 040000a02175ac8e603c6aec102f24c158f6ff8b5b26a3359f7866b6635bafe0540e30fc97b5cc5411cdd3a9e5c99162ea6d20e79ae349965fb13bb929de7dc6a782e69fd441819f9ad88d92f5fa322cb2121f8ffc6ce1f1b6e97063b5132687d90aec43d524b972e8c691e5e09bca1f8de764d6f12b5df6e267e22226c4d0027a11fb040000eff8839ecd9778c27d951a99f51a9d8cf87e577a0ac7768073fa9447fc6ea741ede1e3b3ab1aff86f59a53685cf6305fab60ae4cc747c61ee33016b1f0254047442c502e713742ac44389ac712b9604505ba6e359f5e09970193c09f4ee33bc66d92b0d19930048a48abe3791eedd2ad18bed7ae26aebb23b59eda8e916ca849040000c16f192b66eb9c815597741923e273d3dd84c79cbb5d3cd39af15fcd1a68c199453d93f85a05f2f01b95be470eba874b35b779b41d129b22fbd28bb8985370b1105805ad0ffc096d3037fe6a1eba995df1abaaa6594ba8969ab0ebc65f2daefdd29aa99c267f489599510e9be35a0a99da2e098358a24c4a51717287b921985d040000e2fe3a9b775ffd2cbe3ab72e187e28403ed49dd7e5103e2843549cc140cc91fde6fddb0e6df45de05e8350869b12912a93d6d807e487d248d46ac283eecd3345c1cd0cd7f7ebfe4964493a643f880615beefa46f00675e347fe8f077c84116d58228db180e1fb0c0299080a3fbfb73fd97a99f1b +11,25,0,35,4,35,10,8,21,54,25,40,58,16,10,14,45,36,55,63,39,27,55,62,61,22,62,56,24,11,21,52,21,14,28,7,36,49,15,7,38,2,51,48,8,0,13,7,25,30,18,30,7,63,35,39,18,56,53,61,49,13,10,35,42,6,28,36,18,30,35,39,25,63,19,11,45,35,32,0,37,32,57,48,36,43,44,28,58,61,39,25,37,62,46,3,38,28,56,41,14,45,49,29,0,63,35,21,13,7,59,15,27,6,41,21,53,32,31,3,16,24,33,62,25,32,23,60,26,39,31,29,55,44,45,38,33,50,53,8,55,57,7,2,24,25,5,41,5,52,50,35,19,21,15,42,5,28,6,9,53,10,29,23,5,41,17,50,0,16,3,42,23,27,0,18,1,7,18,29,32,30,20,61,36,57,37,50,4,2,42,19,28,39,3,48,35,62,15,27,23,14,63,32,28,2,18,10,58,61,22,36,51,43,52,2,7,58,25,62,31,38,23,15,1,27,48,8,35,23,0,60,37,3,10,53,59,46,2,0,49,34,24,60,12,56,39,62,0,47,32,9,5,35,37,55,41,21,33,62,19,10,56,28,39,16,56,5,27,6,1,62,33,60,61,59,23,24,59,29,51,33,61,26,59,48,7,12,59,55,31,2,36,43,41,58,36,62,56,34,30,49,16,58,51,47,19,13,50,54,35,50,35,21,19,63,1,38,2,51,47,24,46,25,59,51,33,40,40,29,18,22,25,45,22,8,12,41,50,39,6,47,28,8,53,47,12,1,43,18,35,19,17,6,35,54,19,35,24,11,16,20,0,37,38,4,59,17,1,41,7,47,50,37,37,58,9,22,54,23,40,58,19,29,33,48,54,8,0,59,31,40,7,61,31,39,31,7,59,5,55,48,62,27,60,61,45,30,33,43,9,20,11,44,40,8,3,19,63,34,13,39,22,22,18,37,3,40,61,35,2,23,33,13,16,0,23,43,27,37,33,5,21,27,55,3,22,60,22,5,45,18,60,9,9,61,12,35,20,28,31,52,55,52,58,25,48,34,41,28,10,32,12,62,21,63,18,55,28,50,14,9,36,17,20,53,19,61,52,16,29,21,40,56,21,63,14,5,33,42,45,42,23,52,37,4,63,57,21,28,19,62,60,6,25,38,28,2,40,29,41,13,29,22,20,8,52,6,3,30,36,30,16,62,46,41,24,62,34,60,45,47,54,22,30,58,22,32,40,29,35,36,58,55,4,35,34,40,29,9,55,35,19,2,40,46,39,57,48,52,10,40,51,26,14,57,18,28,60,5,6,39,61,62,31,38,1,45,42,22,17,47,21,14,22,1,47,9,26,47,34,12,59,28,49,62,23,30,26,54,40,21,0,18,8,5,13,18,48,62,20,1,25,10,8,48,1,50,18,46,12,2,43,3,34,29,7,47,8,60,61,42,26,7,14,18,17,26,45,8,24,60,55,55,10,19,30,1,12,43,1,63,13,18,52,6,34,41,23,4,21,27,60,53,2,15,6,5,11,27,50,13,22,51,22,50,15,50,9,5,56,53,24,36,52,14,19,63,36,20,18,16,19,59,36,27,9,42,7,54,26,55,17,2,12,54,9,44,44,58,24,31,9,9,6,52,8,3,12,3,50,22,12,44,20,13,52,14,1,53,39,17,44,18,21,63,59,59,2,11,6,52,5,60,51,42,21,36,10,25,59,59,23,37,51,51,44,60,33,3,22,54,19,55,47,8,28,51,47,25,63,15,27,28,63,49,21,15,35,28,40,49,47,33,24,59,14,9,43,1,38,0,31,6,54,60,24,13,37,45,10,5,22,29,17,49,8,40,44,41,0,21,21,55,52,6,35,45,20,24,53,27,0,20,53,39,17,13,8,26,19,54,33,36,50,16,38,52,19,6,19,55,9,33,12,15,17,36,30,40,28,16,33,60,43,12,41,49,28,0,56,2,56,20,0,34,38,29,52,57,45,33,55,53,25,50,43,61,51,53,41,3,26,39,46,35,14,21,2,53,21,62,19,18,29,25,61,35,50,5,42,42,45,41,35,27,59,16,10,35,10,36,1,60,53,24,55,52,44,24,16,58,24,43,10,25,9,24,44,49,32,26,7,27,51,37,51,55,52,21,39,58,20,52,27,63,48,27,11,45,59,60,21,34,44,29,24,58,11,44,38,8,16,9,12,13,34,36,32,22,16,13,60,39,27,11,25,30,37,44,61,33,10,46,61,55,15,14,10,38 0600002d9023123288576668e9028eb64dff9dbdfef56fb860b57454e7079313c7982cf020034765e49e1ff8e74b8d7dc4d2a3a8672449e8e767f4cbb63800960e7092bb1cebd9d997eb8399ce293adc5d03f8d5347ecf6c6a55d607c341887e6605fc6a77dddecb66872d48df91c2619169174ca34d53ea15c189d4a7571694720100ea5db01204749d81e53d939972102a937270f08fe3db5cefe070248aebd5a4cebd021fa67e7e65cf05bc088d703c9432b5eee080c6263c3389fe02f809163977060000a5587e4cae1c9d0e056c607e87cf7b5d8eddce1f5aef01ccef77c292ba7a93ee227b143acef4cdcb68f28d54ff0660b3bd8b99ef3868a1d49666d588329ca71af708d6f301ad28d34468f64e360b414025984ed10691efca597a256d97a3a4dd870d8803b7e81fd7e77c7ec5df0f9bf3db5e86b2542eca080d3fe23675964a50e8f6309784d4005eb6e584555bdc35bc585b52f0927d32351c7f4df4e99c22a5c2a033e57f4b77323899115354fdd10755a3857f38586ab6a5f4944ff955c4fe060000f06666702a1da4d756508d060de91e43eba963e8bcb6fd967ba5a0a1d8e4eb71238a8749de34c2a2e9f9c342a8cda3b949cf051a7f7e7e606da9646f54e581bc96af88cedcc7e5de6b6a15012205352c3e50164a2300724ae302ac389d1ef23cf6a68739245ab4863cdf729378132b07f352d068a95c455bf3508f1852dbc8d5b35b23f2245e35624d0e4ff9144904fb91b26a1f66b744233626cb3a61f2491b4203303c9632c50dd0e0759d1b1257fefb08b1b417ccea564299efb5e5cf3b3c0600008435b64f7bc8733bd9fcf6dcff154f8dca31be163b389ac19807c6dbc60d96d28559d471228b29015577d068ed518d5b014d6744d21a4f6864c909b44c64f726130f4647a871087cacca71700e02e1402299dd39b61df5672afdcf5a436a7ba33950b557e4d2759f63c85aaab698dbed02a32a407cd58df4b1843a62b299258b3181a1dbce5cf7d159fa5346ffc1b2edefc562b1d63a2ec98840930d8a481640df276cb65e96cf612aef773ce2a6 +6,168,224,139,120,27,231,23,196,1,15,41,26,132,8,8,140,188,214,75,110,235,82,81,33,35,150,103,233,147,168,131,142,92,90,105,221,185,236,91,215,85,126,237,99,139,68,248,19,146,70,203,148,198,247,85,90,2,252,88,178,213,203,177,58,74,22,63,31,68,126,215,35,42,148,104,75,172,175,24,242,29,214,178,138,151,88,243,20,211,222,137,134,96,172,12,31,23,9,171,100,220,17,27,120,69,32,102,18,81,209,207,169,235,195,199,29,105,221,168,84,8,7,223,88,228,14,211,64,4,106,97,26,31,42,218,230,208,21,58,96,7,242,2,233,109,193,200,19,193,136,146,138,220,137,129,227,241,125,64,144,141,60,149,155,175,236,33,98,106,236,71,142,54,39,59,43,22,199,1,227,159,145,237,104,65,111,94,158,110,119,213,62,184,117,98,28,76,235,198,223,133,210,39,100,240,204,180,197,113,193,23,1,56,132,34,70,72,131,144,90,108,64,200,195,139,91,158,116,219,173,171,50,140,30,230,195,100,193,202,16,161,170,140,57,248,80,208,186,170,149,14,28,208,190,21,39,55,127,170,48,238,105,58,104,92,141,206,194,104,16,78,249,206,148,117,160,51,209,98,197,208,206,51,159,99,251,185,20,105,234,178,119,81,127,169,249,135,200,72,188,166,103,68,166,0,18,233,140,31,85,165,36,237,140,156,13,182,185,143,33,76,239,231,67,5,39,139,82,224,187,89,210,223,230,131,145,230,145,161,42,130,150,233,66,163,74,222,101,105,161,77,224,182,35,35,105,72,220,25,80,221,37,44,86,208,205,180,165,11,21,77,28,165,181,28,78,186,6,137,21,77,138,50,47,2,1,149,241,13,251,200,15,62,3,52,176,52,131,68,229,244,229,32,166,251,162,119,238,95,192,7,67,228,93,209,71,28,188,204,61,121,34,165,161,133,53,100,48,96,109,172,6,179,152,18,249,14,138,41,20,113,116,205,69,188,11,126,17,48,175,203,138,219,192,243,36,186,244,252,78,255,43,168,148,96,19,83,252,36,177,133,117,91,40,99,209,39,33,232,54,143,0,131,55,157,102,138,184,252,145,103,225,104,163,207,24,254,238,121,59,32,83,59,32,253,120,188,86,214,119,84,114,63,229,72,100,185,75,133,215,96,250,180,196,20,107,17,183,88,185,219,83,37,239,18,182,33,51,108,13,196,112,250,171,180,25,192,92,40,137,173,143,154,138,34,105,177,9,151,219,61,186,166,127,111,154,167,199,250,131,40,52,15,91,15,71,57,242,186,91,201,156,43,28,246,157,58,228,74,145,146,86,177,136,43,170,241,189,179,198,52,17,37,254,32,106,237,63,136,165,138,24,76,139,2,95,30,122,13,225,30,21,94,142,137,17,214,157,42,216,87,43,17,197,197,185,182,191,225,123,11,52,76,167,152,88,199,194,42,244,247,12,126,113,155,33,246,140,104,178,184,181,229,43,15,124,28,150,78,26,31,231,76,130,164,43,46,32,40,236,131,98,128,110,87,244,161,143,122,213,221,166,42,154,187,152,160,84,203,181,101,148,96,208,19,15,114,218,5,122,173,229,8,92,210,55,215,89,220,102,201,170,134,234,141,239,152,92,104,253,172,209,28,1,155,252,174,225,245,210,106,134,72,19,16,191,65,119,169,165,142,106,32,90,225,28,59,228,248,30,147,144,218,43,183,95,104,9,234,22,240,55,89,69,34,154,167,120,105,81,82,82,112,68,121,92,158,248,92,133,255,126,174,118,133,28,113,228,143,134,50,151,53,49,207,151,53,156,170,161,94,19,44,89,195,48,62,70,88,110,176,212,87,120,142,208,32,218,63,37,43,81,104,128,45,47,165,127,32,221,29,95,124,200,126,153,62,40,219,184,141,64,16,84,164,101,205,237,104,244,220,212,6,186,218,169,215,255,90,29,205,68,99,10,59,186,43,12,95,19,195,171,63,177,42,140,242,33,71,71,182,247,191,153,138,222,243,216,182,55,98,221,80,192,175,30,168,96,137,96,168,122,100,171,208,198,3,7,176,205,47,141,49,201,107,129,223,200,16,33,55,111,114,103,149,13,80,124,231,63,200,98,62,52,129,115,149,155,169,77,167,184,43,47,74,52,152,136,173,214,6,234,13,204,72,190,74,217,66,104,83,65,130,198,108,156,129,124,155,66,174,84,129,224,253,248,23,34,193,190,1,219,209,28,1,90,108,32,153 08000006a8e08b781be717c4010f291a8408088cbcd64b6eeb525121239667e993a8838e5c5a69ddb9ec5bd7557eed638b44f8139246cb94c6f7555a02fc58b2d5cbb13a4a163f1f447ed7232a94684bacaf18f21dd6b28a9758f314d3de898660ac0c1f1709ab64dc111b784520661251d1cfa9ebc3c71d69dda8540807df58e40ed340046a611a1f2adae6d0153a6007f202e96dc1c813c188928adc8981e3f17d40908d3c959bafec21626aec478e36273b2b16c701e39f91ed68416f5e9e6e77d53eb875621c4cebc6df85d22764f0ccb4c571c11701388422464883905a6c40c8c38b5b9e74dbadab328c1ee6c364c1ca10a1aa8c39f850d0baaa950e1cd0be1508000027377faa30ee693a685c8dcec268104ef9ce9475a033d162c5d0ce339f63fbb91469eab277517fa9f987c848bca66744a60012e98c1f55a524ed8c9c0db6b98f214cefe74305278b52e0bb59d2dfe68391e691a12a8296e942a34ade6569a14de0b623236948dc1950dd252c56d0cdb4a50b154d1ca5b51c4eba0689154d8a322f020195f10dfbc80f3e0334b0348344e5f4e520a6fba277ee5fc00743e45dd1471cbccc3d7922a5a185356430606dac06b39812f90e8a29147174cd45bc0b7e1130afcb8adbc0f324baf4fc4eff2ba894601353fc24b185755b2863d12721e8368f0083379d668ab8fc9167e168a3cf18feee793b20533b20fd78bc56d67754080000723fe54864b94b85d760fab4c4146b11b758b9db5325ef12b621336c0dc470faabb419c05c2889ad8f9a8a2269b10997db3dbaa67f6f9aa7c7fa8328340f5b0f4739f2ba5bc99c2b1cf69d3ae44a919256b1882baaf1bdb3c6341125fe206aed3f88a58a184c8b025f1e7a0de11e155e8e8911d69d2ad8572b11c5c5b9b6bfe17b0b344ca79858c7c22af4f70c7e719b21f68c68b2b8b5e52b0f7c1c964e1a1fe74c82a42b2e2028ec8362806e57f4a18f7ad5dda62a9abb98a054cbb5659460d0130f72da057aade5085cd237d759dc66c9aa86ea8def985c68fdacd11c019bfcaee1f5d26a86481310bf4177a9a58e6a205ae11c3be4f81e9390da2bb75f6808000009ea16f0375945229aa778695152527044795c9ef85c85ff7eae76851c71e48f8632973531cf97359caaa15e132c59c3303e46586eb0d457788ed020da3f252b5168802d2fa57f20dd1d5f7cc87e993e28dbb88d401054a465cded68f4dcd406badaa9d7ff5a1dcd44630a3bba2b0c5f13c3ab3fb12a8cf2214747b6f7bf998adef3d8b63762dd50c0af1ea8608960a87a64abd0c60307b0cd2f8d31c96b81dfc81021376f7267950d507ce73fc8623e348173959ba94da7b82b2f4a349888add606ea0dcc48be4ad94268534182c66c9c817c9b42ae5481e0fdf81722c1be01dbd11c015a6c2099 +2,2,3,2,0,0,3,1,0,3,2,3,3,2,1,0,0,3,3,3,0,0,2,1,2,0,1,3,0,3,1,2,2,3,0,2,1,1,2,0,0,136,2,2,0,1,2,3,2,0,0,0,3,2,1,3,2,0,1,0,1,1,2,0,0,0,185,1,3,2,3,0,0,2,0,3,2,0,1,0,167,1,1,3,2,1,2,3,0,1,0,89,0,1,3,3,0,1,1,0,232,3,1,2,0,2,3,3,0,2,2,192,0,1,2,1,0,2,2,3,3,1,2,0,3,2,3,1,240,2,0,3,1,0,3,1,2,88,3,2,3,0,1,1,2,2,1,3,1,1,2,103,2,1,3,1,2,2,3,1,2,3,1,1,0,3,2,0,3,1,0,2,0,2,1,0,3,1,1,3,2,3,3,3,0,2,1,2,2,0,2,2,0,3,1,1,3,0,1,1,1,3,3,1,0,2,2,2,2,0,2,1,1,3,1,2,0,3,2,1,2,1,3,3,3,2,0,3,3,3,3,2,0,2,1,1,1,1,200,2,2,3,3,0,1,2,0,2,1,3,3,2,2,2,2,3,0,0,2,150,3,0,0,3,3,3,1,0,0,2,2,1,3,1,2,2,0,2,1,1,0,1,2,1,3,3,2,1,3,1,3,0,1,0,3,3,0,0,3,1,2,2,1,3,1,1,1,1,2,0,2,1,2,0,0,0,3,3,1,0,3,0,2,1,0,2,2,0,3,0,3,1,2,1,3,1,0,3,1,3,2,1,2,0,2,0,3,2,0,0,3,1,1,1,3,1,1,1,0,2,3,0,0,0,2,0,2,0,2,1,0,2,2,3,1,0,0,3,2,1,3,3,3,2,0,3,1,3,0,0,1,3,3,2,2,2,3,1,0,0,0,2,3,3,3,0,3,0,3,1,3,3,0,2,1,3,2,1,3,2,2,2,0,0,2,3,3,2,0,3,1,1,3,1,0,2,0,1,43,2,0,2,1,2,1,3,1,3,0,3,1,1,2,2,0,1,1,3,1,3,0,0,244,3,3,2,3,2,1,3,2,0,0,3,1,3,3,3,1,2,0,1,1,3,0,1,3,0,0,2,0,0,0,2,0,3,177,3,2,0,3,2,2,2,1,2,3,1,1,0,2,0,2,0,0,0,2,2,0,3,2,1,2,3,3,0,2,0,1,0,0,2,0,3,1,0,0,1,1,1,2,1,1,0,3,0,1,3,0,0,1,2,0,2,2,0,0,2,2,0,0,0,2,1,0,3,2,1,1,0,0,0,0,1,3,1,1,1,0,3,1,0,2,0,2,0,2,0,0,0,3,3,0,0,3,2,0,1,2,1,1,0,0,3,3,3,0,0,3,2,3,3,2,0,0,0,3,1,1,2,3,3,1,2,2,1,1,3,1,109,2,3,3,2,0,2,0,2,3,1,0,1,1,2,3,1,1,2,3,1,0,0,3,1,3,1,3,3,1,1,3,3,3,0,0,1,3,2,2,3,0,0,0,1,1,1,1,0,2,0,2,1,1,2,0,1,2,0,1,2,1,0,3,3,1,2,0,1,2,2,2,1,3,0,0,0,1,0,1,1,1,1,0,1,0,1,3,2,3,3,1,0,0,1,1,2,3,2,199,3,0,2,3,3,3,3,3,2,1,2,3,0,3,1,2,0,1,0,2,1,3,0,2,2,2,3,2,2,2,3,1,0,1,2,1,1,3,1,3,3,2,1,2,1,2,1,1,3,2,93,0,1,14,1,2,2,2,1,0,0,3,3,0,1,0,2,2,3,1,3,1,3,1,2,3,2,0,2,1,0,0,2,0,0,1,1,1,0,1,0,3,1,3,1,2,3,2,2,0,2,0,3,3,89,0,3,1,3,1,1,0,0,1,1,3,3,3,3,2,1,0,3,0,0,0,0,0,2,0,1,1,3,1,3,1,0,1,0,2,2,2,1,79,3,0,1,1,3,0,0,0,1,3,172,2,12,3,3,0,2,2,2,0,1,3,1,0,0,0,3,0,0,3,3,3,1,0,2,2,0,2,3,2,1,2,1,2,1,0,0,0,3,0,1,1,0,0,1,0,1,2,2,3,0,3,2,2,0,3,0,2,0,2,1,3,0,3,0,3,1,0,0,0,0,3,2,3,1,3,0,0,3,2,3,0,0,3,2,1,1,0,0,2,3,2,0,1,2,0,3,0,3,3,2,3,1,3,0,3,0,3,2,2,3,2,2,2,3,3,3 620a00ae0d3be43f098736b2580a1b80e7845805ec2384d79b111f14362f28192bd8ed234d8ec5a75b9dadb538d224d7bf268a35c57d2a8976399fe3fe2552bc627eab2942505b646f808997ee8aea56eb0f1667206204000ac3f429da2519f9dc4f0da7558980f4c928cd9d37988e0d5d52c08892b439fe3707ead02fccdf279ea0be35d21e267735a17703ee7837f6171c202378ea6d4803b6cef094af6c62020080a39bc842341594c70628280939401d5348880f0e1943f0ef80d6f6975be22d16d6d0ddf5fc1eb01548961864f61a9c045511ef416ef2ffe6cd849cabab465d75d86f10620600f9997919a90f12b776e2420544ddba23d37505ff9300217744a9f1701c8f2a1d030fd28b999031411ace8c89ccd00edc3b0e50b8633edccebabf0b0e416873755c3593ac30 +3,1,3,3,2,1,0,2,3,3,0,1,3,0,1,0,3,2,3,1,3,0,2,1,1,55,3,0,2,0,0,2,3,0,0,3,3,3,1,1,0,3,1,1,1,2,2,1,0,3,3,2,2,3,1,2,0,0,3,0,3,40,0,2,1,0,1,3,84,1,2,1,0,2,1,3,2,1,3,1,3,0,0,0,0,3,3,0,3,2,2,3,3,0,1,1,0,2,1,3,3,164,2,2,0,2,3,0,1,1,3,0,1,0,3,2,1,3,3,1,2,3,3,3,191,0,0,3,0,0,0,3,3,1,3,3,3,3,0,1,0,3,0,3,0,3,2,2,0,0,1,0,1,2,3,2,2,3,2,2,0,1,1,3,179,1,1,0,211,0,2,1,1,3,2,1,0,0,1,2,2,1,1,1,0,0,1,0,1,0,0,3,2,2,1,3,3,3,1,0,2,0,233,2,2,1,1,3,2,1,3,0,1,3,0,0,0,3,3,3,0,2,1,3,3,3,0,0,1,3,1,1,3,3,2,2,2,1,0,3,3,3,3,0,1,3,2,1,0,2,2,3,2,0,2,2,3,2,1,3,2,1,3,1,212,2,3,3,3,1,3,2,102,0,0,2,3,0,1,2,0,3,2,3,0,3,2,2,4,0,10,2,0,1,0,3,2,0,3,3,3,3,1,0,3,3,3,3,2,3,3,3,3,2,2,3,3,0,50,140,3,3,3,3,3,0,3,1,3,123,2,0,1,2,3,1,0,1,0,3,0,1,2,1,2,2,3,1,1,2,3,2,3,0,0,3,3,94,3,3,1,2,3,2,27,2,1,3,2,0,1,0,3,0,2,0,1,1,3,82,3,2,3,2,0,1,2,3,2,3,3,3,2,0,3,1,1,0,1,3,2,1,0,3,0,2,95,1,228,0,0,2,1,0,3,0,2,3,2,3,0,2,3,1,0,0,0,2,3,3,0,0,3,3,3,0,0,0,2,2,0,1,1,0,3,3,3,1,3,0,3,0,3,2,0,2,1,1,1,1,3,1,3,3,3,0,1,3,0,2,2,3,2,2,3,1,1,0,118,0,0,2,0,143,1,120,3,3,0,2,143,0,3,1,3,3,90,3,0,1,3,3,2,3,1,0,3,3,2,1,3,2,1,2,3,0,0,1,122,0,3,3,2,17,3,2,3,0,0,3,2,1,2,0,2,183,1,1,1,1,3,2,3,0,0,3,1,2,2,3,0,0,1,1,2,0,0,2,2,245,2,2,2,0,0,3,2,3,0,1,2,2,0,2,3,0,1,2,0,0,0,0,2,0,0,1,2,1,2,3,1,0,2,1,1,0,0,2,2,3,3,0,3,1,3,3,1,2,2,2,0,0,2,3,1,2,3,0,1,144,0,2,3,0,1,3,0,149,3,3,0,2,3,2,2,0,1,2,3,0,0,1,0,0,3,1,3,2,2,2,1,1,3,3,3,0,2,3,3,0,3,2,155,147,0,92,2,0,0,2,2,2,1,1,0,0,0,3,1,3,1,1,2,141,2,1,0,2,2,0,1,1,1,0,1,105,0,1,3,0,3,1,0,0,1,2,2,2,2,0,3,98,3,2,0,0,0,0,0,0,1,0,3,3,2,0,3,3,2,0,2,0,3,0,1,3,3,0,0,2,0,1,3,2,3,2,3,2,0,2,1,3,2,2,0,0,3,1,3,0,2,1,0,2,2,1,1,1,0,3,2,0,1,2,2,1,1,2,0,2,0,1,2,198,3,2,1,3,0,1,2,0,3,3,3,3,2,0,3,3,0,1,2,1,2,78,3,1,1,1,0,3,2,0,3,0,1,2,3,0,1,2,2,1,2,0,3,2,1,3,2,2,3,3,3,3,2,0,0,3,3,0,3,2,3,0,3,0,1,0,0,2,0,1,1,3,3,1,3,1,2,0,1,3,1,3,1,0,3,2,0,0,3,0,3,0,1,1,3,2,0,1,3,3,166,2,0,1,1,3,1,0,0,0,3,2,0,2,2,0,1,3,3,3,3,3,3,1,2,1,1,3,3,0,0,1,3,2,2,1,3,1,0,112,1,2,3,0,1,3,1,3,2,1,3,0,2,1,3,1,3,2,0,2,2,3,1,1,0,3,3,0,1,2,3,2,2,0,1,3,1,2,2,2,1,3,3,202,3,3,2,0,3,0,1,2,3,0,0,2,0,0,3,2,0,3,0,3,3,0,1,2,1,0,0,3,1,107,3,3 620800df92f1c4edc97c82c3f535693eb60cc24719279dc03cebc527ca2c5c4e7dbfc303dff1333a046eba17d4c97906950443a7f486979c703f27f075fa93fc792b8a193d44657ca4a8ca34a569becd3a621100e79d2fde82c63b3a0a138ff4ffbfebc8ffcdf86d1319ad6ec3ef6ee784c85eee1bbf8d47932d024cbb2d02f0fc0a14fdcce255dfc72bad48234f2cdfb1fb4f9e081020223e3f49656c7b9698dee3e5eaf0d590423237971945f97637a358620c006c18f9ec398b55ec36b05829a83b1a2c600819b4942bcdf6a0b6c42c71f2e86c10dea5fcbcef082a5037599285451cd06a8ee0004f8f88c7c21eee27a0dc9295060b172f6b73969799abb7c7784b7d9259a45e36986206003869621ae718ff8f19ad538c6c698e7aff83cecc4217dd8774e0cc5e1fa1740e287ffd97c1e9d06c779c9de2b53c6e876a7ef8c6c20e33c6437f0f25749bc7e5c53a5cc9a0 +2,0,0,2,2,1,208,34,1,0,0,154,1,229,1,2,1,181,3,2,39,0,2,60,2,0,0,1,3,1,3,0,1,3,1,0,2,1,2,63,1,0,2,3,170,0,1,0,1,1,0,1,223,3,2,61,3,0,3,2,1,2,2,0,2,3,0,0,29,0,1,1,59,2,2,1,2,3,1,3,2,3,0,164,2,0,0,209,1,136,1,2,0,0,0,1,3,1,1,1,3,3,9,0,3,0,0,1,3,3,142,3,2,2,0,223,0,3,1,34,160,1,3,1,2,128,200,0,0,1,3,0,65,1,3,0,2,3,2,3,1,3,2,0,3,2,3,158,1,215,1,0,0,0,1,3,2,6,190,0,0,3,80,3,2,0,1,1,43,1,2,252,2,1,2,3,0,2,3,0,0,2,3,233,1,2,245,2,3,1,3,0,3,3,93,3,1,235,3,0,1,3,0,0,1,185,1,2,3,0,0,1,0,1,199,2,156,3,0,3,3,2,2,1,1,183,3,157,1,1,1,16,0,0,3,95,1,73,2,128,1,48,3,1,3,0,3,0,0,43,3,3,0,2,1,113,230,2,199,194,45,3,199,1,3,2,1,0,1,1,1,1,1,1,77,2,1,0,3,3,2,251,0,3,0,2,1,0,0,1,1,2,2,0,1,0,80,101,2,144,230,3,0,248,57,0,1,16,1,0,0,1,68,1,0,3,89,14,3,156,183,3,3,26,8,3,128,2,2,2,255,2,3,3,2,0,0,151,1,161,2,0,2,119,245,125,1,1,60,2,0,3,167,0,3,230,1,244,0,0,1,3,0,215,1,0,2,203,0,0,3,3,0,0,3,3,48,3,2,1,3,3,1,1,0,1,22,1,0,0,0,104,3,1,142,0,3,0,1,3,3,3,0,3,3,30,0,1,2,2,1,2,123,32,3,0,0,3,220,2,2,1,3,2,67,0,2,2,3,0,2,121,0,3,0,3,3,2,3,0,1,2,2,2,2,1,2,0,3,166,0,0,76,190,3,1,2,169,3,1,7,3,3,227,2,1,1,0,0,0,2,0,2,0,89,2,0,161,3,3,1,1,3,2,94,0,216,1,0,1,3,2,3,1,3,109,3,146,2,199,37,1,1,121,3,2,1,0,0,0,3,3,3,3,1,1,3,1,1,1,188,2,0,3,69,2,0,3,3,194,2,3,1,1,3,0,2,2,0,0,0,48,1,2,3,1,219,120,3,2,69,2,3,112,0,0,0,0,0,231,3,1,2,3,1,3,0,3,53,3,32,1,2,2,3,0,0,3,243,3,0,1,0,3,2,3,0,0,1,1,2,0,1,2,0,3,2,3,0,2,2,0,3,19,3,1,3,88,2,3,1,1,0,2,0,1,2,0,200,2,125,252,0,3,1,178,58,2,1,0,251,129,2,3,1,2,2,0,203,2,0,3,3,0,30,106,3,0,0,1,3,3,1,1,37,2,0,78,0,3,2,1,2,119,0,217,34,1,41,1,3,1,0,3,0,2,1,3,3,111,3,3,3,1,0,0,67,3,2,3,1,46,2,1,3,2,0,248,0,77,63,157,221,2,2,3,0,81,3,1,2,0,2,8,0,1,238,0,1,152,1,0,252,3,1,1,190,0,2,1,3,2,0,1,0,3,0,148,3,0,0,229,3,251,3,1,181,1,33,178,2,101,3,2,235,2,1,1,1,2,3,2,1,0,90,10,81,1,22,121,0,2,135,0,0,0,2,0,1,36,0,2,2,3,2,1,3,3,1,1,3,1,0,2,2,3,1,3,3,2,2,0,3,179,2,0,3,1,3,1,2,0,3,1,2,181,168,126,0,2,99,1,3,0,118,0,3,0,1,3,2,1,0,0,0,228,10,3,0,3,3,2,3,148,1,1,150,0,0,21,3,198,3,117,177,0,22,0,0,1,91,2,2,185,0,3,3,1,1,3,1,2,215,0,2,185,2,0,3,3,1,2,2,0,0,205,2,4,1,1,1,114,0,3,3,0,1,87,0,0,1,1,0,0,0,106,1,0,2,1,3,1,208,0,77,248,97,1,3,85,153,3,0,2,98,0,1,0,8,2,2,1,2,2,3,1,2,2,1,2,172,3,2,66,0,1,1,2,3,3,0,1,2,115,0,3,0,0,3,3,3,73,228,0,2,122,45,77,3,1,1,3,2,21,3,1,1,245,3,3,1,2,1,75,0,2,0,0,1,1,2,3,3,199,1,156,3,1,3,0 622f00829242565ec881dc749b4b8451f9ce68b045e9b7b0814601d5f4c1fba3361d801c5cbb78ee7407a83385d89b2c2d66dcf77c7056c11e33e97d540f584dcc3f2506070b0d111417272c34374448535759666e7377787d7e8493959d9ea2a8abb7bac2c5cdd6d8e1e3e7ebedeff1f9ffd089b9b493cfab73c73a9d220a3dc8a20c909f506f50affaf57eaec67b671174a030a700623b00ae7de455564fb324168418b04441136cfe32aef8358b5523ce40734b0f0f39f51900d8c7f3e1a6cc329ecac933ec6a98e02d9dff9408861f5e811eddeb55e40f0002030406121928292b2c2f3033383c3d3f404344464a51535758595c6063656b6f7882878a959c9da2a8afc1c4c5c9cccfdadde4e6eff1f3f4f7e71c0bc53f94664e7e3844560e7b460a0fe5a1df5f3e9e7dd723056a31de23741ea53bea0785a85f66e4c49780623700f5d52363eb5ca006dce6c003db7371ac3f13b05863b28fdcb52182436a4db68e3cac1f56239b195d327ffd0fb69e01d6b1d8818443589e130c1fd569ee56e4a5080c111d222326292f383a425b5f6a6c6d717276777e84858e9197999a9ca7aeb3b9bbbcbdbec3c9cccfd2d6e1e5e7eaecedeff2fcfdfebd1c0cd9e45ce4d23c116c9ffec3be8321da25377620a6d02fe4cf9f7502ee6fef979fad22c67a58250062310092c0842b9f5d2b7e8f8dd8d922dc8c7900b3ec581ed481e93d76c98f6818563c7050249d045d728429ada63a16f1b30fd0a5d79d5f67205bf4dc0001040b232f3031343843444b4e51535556585c5f686b75777b81899092939497989ca0acafb9c1c2c5c6c7cdd1d7e1e315e849b2da9f61de4296517176c156bb5bb305c55ad13f98566602ad0712e5e2d317d4b19c diff --git a/src/iceberg/util/mumbling_bitmap_internal.cc b/src/iceberg/util/mumbling_bitmap_internal.cc new file mode 100644 index 0000000000..a8971c8d67 --- /dev/null +++ b/src/iceberg/util/mumbling_bitmap_internal.cc @@ -0,0 +1,350 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "iceberg/util/mumbling_bitmap_internal.h" + +#include +#include +#include + +#include "iceberg/util/endian.h" +#include "iceberg/util/macros.h" + +// SSE2 is part of the x86-64 baseline, so it needs no extra compiler flags. +// Define ICEBERG_MUMBLING_SSE2=0 to force the portable scalar code. +#if !defined(ICEBERG_MUMBLING_SSE2) && (defined(__SSE2__) || defined(_M_X64)) && \ + !defined(_M_ARM64EC) +# define ICEBERG_MUMBLING_SSE2 1 +# include +#elif !defined(ICEBERG_MUMBLING_SSE2) +# define ICEBERG_MUMBLING_SSE2 0 +#endif + +namespace iceberg { + +namespace { + +constexpr size_t kHeaderSize = 6; +constexpr size_t kPforChunkSize = 256; +constexpr size_t kPforHeaderSize = 3; + +// The 3 most significant bits of a descriptor select the container type: +// 000 is sparse, 001 is dense, and the other patterns are reserved. +constexpr uint8_t kDenseTypeBit = 0b0010'0000; +constexpr uint8_t kReservedTypeBits = 0b1100'0000; + +constexpr size_t BytesForBits(size_t bits) { return (bits + 7) / 8; } + +// Returns true if `value` is one of the `length` (<= 31) bytes at `container`. +// Scans all of them, so the result doesn't depend on them being sorted. +bool ContainsByte(const uint8_t* container, uint8_t length, uint8_t value) { + for (uint8_t i = 0; i < length; ++i) { + if (container[i] == value) { + return true; + } + } + return false; +} + +// Portable SWAR (SIMD within a register) version of ContainsByte: compares 8 +// bytes per 64-bit word. Reads 32 bytes at `container`, so the caller must +// make sure they are inside the buffer. +bool ContainsByte32(const uint8_t* container, uint8_t length, uint8_t value) { + constexpr uint64_t kLow7 = 0x7F7F7F7F7F7F7F7FULL; + const uint64_t pattern = 0x0101010101010101ULL * value; + uint64_t found = 0; + for (int w = 0; w < 4; ++w) { + // Little-endian load, so byte i of the word is bits [8i, 8i + 8). + const uint64_t x = ReadLittleEndian(container + w * 8) ^ pattern; + // 0x80 in each byte of x that is zero. Exact per byte, unlike the common + // `(x - 0x01..) & ~x & 0x80..` trick, so bytes can be masked by position. + const uint64_t zero = ~(((x & kLow7) + kLow7) | x | kLow7); + const int valid_bytes = std::clamp(static_cast(length) - w * 8, 0, 8); + const uint64_t valid = + valid_bytes == 8 ? ~uint64_t{0} : (uint64_t{1} << (valid_bytes * 8)) - 1; + found |= zero & valid; + } + return found != 0; +} + +#if ICEBERG_MUMBLING_SSE2 +// SSE2 version of ContainsByte32. Reads 32 bytes at `container`, so the caller +// must make sure they are inside the buffer. +bool ContainsByte32Sse2(const uint8_t* container, uint8_t length, uint8_t value) { + const uint32_t valid = (uint32_t{1} << length) - 1; + const __m128i needle = _mm_set1_epi8(static_cast(value)); + const __m128i lo = _mm_loadu_si128(reinterpret_cast(container)); + const __m128i hi = _mm_loadu_si128(reinterpret_cast(container + 16)); + const auto mask = + static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(lo, needle))) | + (static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(hi, needle))) << 16); + return (mask & valid) != 0; +} +#endif + +// Reads the `index`-th `width`-bit value from `packed`, where values are packed +// most significant bit first. `width` must be at most 8 and `packed` must hold +// at least BytesForBits((index + 1) * width) bytes. +uint8_t UnpackValue(std::span packed, size_t index, uint8_t width) { + size_t bit_pos = index * width; + size_t byte_pos = bit_pos / 8; + uint32_t window = static_cast(packed[byte_pos]) << 8; + if (byte_pos + 1 < packed.size()) { + window |= packed[byte_pos + 1]; + } + uint32_t shift = 16 - static_cast(bit_pos % 8) - width; + return static_cast((window >> shift) & ((1U << width) - 1)); +} + +// Unpacks groups of 8 `Width`-bit values. Each group is exactly `Width` bytes, +// so it is read as one big-endian word and split with constant shifts; the +// compiler fully unrolls both inner loops. +template +void UnpackGroups(const uint8_t* in, uint8_t* out, size_t groups) { + constexpr uint64_t kMask = (uint64_t{1} << Width) - 1; + for (size_t group = 0; group < groups; ++group, in += Width, out += 8) { + uint64_t word = 0; + for (int i = 0; i < Width; ++i) { + word = (word << 8) | in[i]; + } + for (int i = 0; i < 8; ++i) { + out[i] = static_cast((word >> (Width * (7 - i))) & kMask); + } + } +} + +// Unpacks `out.size()` `width`-bit values from `packed`, which must hold at +// least BytesForBits(out.size() * width) bytes. +void UnpackBits(std::span packed, uint8_t width, std::span out) { + const size_t count = out.size(); + if (width == 0) { + std::ranges::fill(out, 0); + return; + } + if (width == 8) { + std::memcpy(out.data(), packed.data(), count); + return; + } + + const size_t groups = count / 8; + size_t unpacked = groups * 8; + switch (width) { + case 1: + UnpackGroups<1>(packed.data(), out.data(), groups); + break; + case 2: + UnpackGroups<2>(packed.data(), out.data(), groups); + break; + case 3: + UnpackGroups<3>(packed.data(), out.data(), groups); + break; + case 4: + UnpackGroups<4>(packed.data(), out.data(), groups); + break; + case 5: + UnpackGroups<5>(packed.data(), out.data(), groups); + break; + case 6: + UnpackGroups<6>(packed.data(), out.data(), groups); + break; + case 7: + UnpackGroups<7>(packed.data(), out.data(), groups); + break; + default: + unpacked = 0; + break; + } + for (size_t i = unpacked; i < count; ++i) { + out[i] = UnpackValue(packed, i, width); + } +} + +// Decodes one PFOR chunk of `out.size()` values from `data`, returning the +// number of bytes read. +Result DecodePforChunk(std::span data, std::span out) { + const size_t count = out.size(); + ICEBERG_PRECHECK(data.size() >= kPforHeaderSize, + "Truncated PFOR chunk header: {} bytes available, {} required", + data.size(), kPforHeaderSize); + + const uint8_t b1 = data[0] & 0x0F; + const uint8_t b2 = data[0] >> 4; + const uint8_t exception_count = data[1]; + const uint8_t base = data[2]; + + ICEBERG_PRECHECK(b1 <= 8, "Invalid PFOR primary bit width: {} (must be <= 8)", b1); + ICEBERG_PRECHECK(b2 <= 8 - b1, + "Invalid PFOR exception bit width: {} (must be <= {} when b1 is {})", + b2, 8 - b1, b1); + ICEBERG_PRECHECK(b1 != 8 || exception_count == 0, + "Invalid PFOR chunk: {} exceptions with 8-bit primary values", + exception_count); + ICEBERG_PRECHECK(exception_count <= count, + "Invalid PFOR chunk: {} exceptions for {} values", exception_count, + count); + + const size_t primary_size = BytesForBits(count * b1); + const size_t exception_values_size = BytesForBits(size_t{exception_count} * b2); + const size_t chunk_size = + kPforHeaderSize + primary_size + exception_count + exception_values_size; + ICEBERG_PRECHECK(data.size() >= chunk_size, + "Truncated PFOR chunk: {} bytes available, {} required", data.size(), + chunk_size); + + UnpackBits(data.subspan(kPforHeaderSize, primary_size), b1, out); + + if (exception_count > 0) { + auto exception_offsets = + data.subspan(kPforHeaderSize + primary_size, exception_count); + std::array exception_values; + UnpackBits(data.subspan(kPforHeaderSize + primary_size + exception_count, + exception_values_size), + b2, std::span(exception_values).first(exception_count)); + for (size_t i = 0; i < exception_count; ++i) { + const uint8_t offset = exception_offsets[i]; + ICEBERG_PRECHECK(offset < count, + "Invalid PFOR exception offset: {} (chunk has {} values)", offset, + count); + // b1 + b2 <= 8, so the patched value still fits in a byte. + out[offset] |= static_cast(exception_values[i] << b1); + } + } + + if (base != 0) { + // Check for overflow once with a max reduction, then add the base; both + // loops vectorize. + uint8_t max_value = 0; + for (uint8_t value : out) { + max_value = std::max(max_value, value); + } + if (max_value > 0xFF - base) [[unlikely]] { + const auto it = + std::ranges::find_if(out, [&](uint8_t v) { return v > 0xFF - base; }); + return InvalidArgument("Invalid PFOR value at index {}: {} exceeds 255", + it - out.begin(), uint32_t{*it} + base); + } + for (uint8_t& value : out) { + value = static_cast(value + base); + } + } + + return chunk_size; +} + +} // namespace + +Result DecodePforBytes(std::span data, std::span out) { + size_t bytes_read = 0; + for (size_t values_read = 0; values_read < out.size(); values_read += kPforChunkSize) { + const size_t chunk_length = std::min(kPforChunkSize, out.size() - values_read); + ICEBERG_ASSIGN_OR_RAISE(auto chunk_size, + DecodePforChunk(data.subspan(bytes_read), + out.subspan(values_read, chunk_length))); + bytes_read += chunk_size; + } + return bytes_read; +} + +Result MumblingBitmapView::Make(std::span bytes) { + ICEBERG_PRECHECK(bytes.size() >= kHeaderSize, + "Truncated Mumbling bitmap header: {} bytes available, {} required", + bytes.size(), kHeaderSize); + if (bytes[0] != kVersion) { + return NotSupported("Unsupported Mumbling bitmap version: {}", bytes[0]); + } + + const int64_t cardinality = static_cast(bytes[1]) | + (static_cast(bytes[2]) << 8) | + (static_cast(bytes[3]) << 16); + const int32_t container_count = + static_cast(bytes[4]) | (static_cast(bytes[5]) << 8); + ICEBERG_PRECHECK(container_count <= kMaxContainerCount, + "Invalid Mumbling bitmap container count: {} (must be <= {})", + container_count, kMaxContainerCount); + ICEBERG_PRECHECK(cardinality <= kMaxCardinality, + "Invalid Mumbling bitmap cardinality: {} (must be <= {})", cardinality, + kMaxCardinality); + + MumblingBitmapView bitmap; + bitmap.cardinality_ = cardinality; + bitmap.containers_.resize(container_count); + + // Decode into a stack buffer; only the offset table is kept. + std::array descriptors; + ICEBERG_ASSIGN_OR_RAISE(auto descriptors_size, + DecodePforBytes(bytes.subspan(kHeaderSize), + std::span(descriptors).first(container_count))); + + // Branch-free: a dense descriptor (type 001) is 32 bytes and a sparse one + // (type 000) is its own value. Reserved types are checked once at the end. + uint32_t offset = 0; + uint8_t reserved_bits = 0; + for (int32_t i = 0; i < container_count; ++i) { + const uint8_t descriptor = descriptors[i]; + reserved_bits |= descriptor; + const uint8_t length = (descriptor & kDenseTypeBit) != 0 ? kDenseLength : descriptor; + bitmap.containers_[i] = (offset << kOffsetShift) | length; + offset += length; + } + if ((reserved_bits & kReservedTypeBits) != 0) [[unlikely]] { + const auto* it = + std::find_if(descriptors.data(), descriptors.data() + container_count, + [](uint8_t d) { return (d & kReservedTypeBits) != 0; }); + return InvalidArgument( + "Invalid Mumbling bitmap descriptor for container {}: {:#04x} (not sparse " + "or dense)", + it - descriptors.data(), *it); + } + + // Every container must be inside the buffer; this is what makes the + // accessors memory-safe. + const size_t containers_start = kHeaderSize + descriptors_size; + const size_t available = bytes.size() - containers_start; + ICEBERG_PRECHECK(available >= offset, + "Truncated Mumbling bitmap containers: {} bytes available, {} " + "required", + available, offset); + ICEBERG_PRECHECK(available == offset, + "Invalid Mumbling bitmap: {} unexpected trailing bytes", + available - offset); + + bitmap.containers_data_ = bytes.subspan(containers_start, offset); + return bitmap; +} + +bool MumblingBitmapView::SparseContains(uint32_t ref, uint8_t pos_in_container) const { + const uint32_t offset = ref >> kOffsetShift; + const uint8_t* container = containers_data_.data() + offset; + const auto length = static_cast(ref & kLengthMask); + // Compare 32 bytes at once when they are all inside the buffer (every + // container except those in the last 31 bytes of the bitmap). + if (containers_data_.size() - offset >= kDenseLength) { +#if ICEBERG_MUMBLING_SSE2 + return ContainsByte32Sse2(container, length, pos_in_container); +#else + // A plain loop is faster than SWAR for short containers. + if (length >= 8) { + return ContainsByte32(container, length, pos_in_container); + } +#endif + } + return ContainsByte(container, length, pos_in_container); +} + +} // namespace iceberg diff --git a/src/iceberg/util/mumbling_bitmap_internal.h b/src/iceberg/util/mumbling_bitmap_internal.h new file mode 100644 index 0000000000..7bc256a157 --- /dev/null +++ b/src/iceberg/util/mumbling_bitmap_internal.h @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#pragma once + +/// \file iceberg/util/mumbling_bitmap_internal.h +/// A read-only Mumbling bitmap, the compressed bitmap format used by v4 +/// manifest deletion vectors. +/// +/// Spec: https://github.com/apache/iceberg/blob/main/format/mumbling-spec.md +/// The spec is still a draft, so this header is internal and not installed. + +#include +#include +#include +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/result.h" + +namespace iceberg { + +/// \brief Decodes a PFOR-encoded array of unsigned bytes. +/// +/// Implements "Appendix A: PFOR encoding for unsigned bytes" of the Mumbling +/// bitmap spec +/// (https://github.com/apache/iceberg/blob/main/format/mumbling-spec.md#appendix-a-pfor-encoding-for-unsigned-bytes), +/// which encodes the descriptor array. Values are encoded in +/// chunks of 256 values (the last chunk holds the remainder), each with a +/// 3-byte header, a bit-packed primary array, exception offsets and +/// bit-packed exception values. +/// +/// \param data the encoded bytes; may extend past the encoded values. +/// \param out receives the decoded values; its size is the number of values. +/// \return the number of bytes read from `data`, or an error if the input is +/// malformed or truncated. +ICEBERG_EXPORT Result DecodePforBytes(std::span data, + std::span out); + +/// \brief A read-only view of a serialized Mumbling bitmap (format version 1). +/// +/// Positions are split into a container index (the most significant bits) and +/// an 8-bit position within a 256-bit container. Each container is either +/// sparse (0-31 sorted one-byte positions) or dense (a 32-byte bit set). +/// +/// The view does not copy the bitmap: the serialized bytes must outlive it, +/// like the characters of a `std::string_view`. In v4 scan planning these are +/// the bytes of `manifest_info.dv` owned by the root manifest entry. +/// +/// Make() checks everything that memory safety depends on (header limits, +/// the PFOR descriptor array, descriptor types and the container sizes against +/// the buffer), so the accessors cannot fail and never read out of bounds. +/// Like the Java reader, it does not check container contents: for input that +/// breaks the spec's content rules (unsorted sparse positions, dense +/// containers with fewer than 32 positions, a wrong header cardinality), +/// Contains() still reports whether the position is stored, and Cardinality() +/// returns the header value. +class ICEBERG_EXPORT MumblingBitmapView { + public: + /// \brief The only supported format version. + static constexpr uint8_t kVersion = 1; + /// \brief Maximum number of containers in a bitmap. + static constexpr int32_t kMaxContainerCount = 8192; + /// \brief Number of positions covered by one container. + static constexpr int32_t kContainerSize = 256; + /// \brief Maximum number of set positions (8192 containers of 256 bits). + static constexpr int32_t kMaxCardinality = kMaxContainerCount * kContainerSize; + + /// \brief Creates a view of a serialized bitmap. `bytes` must outlive the + /// view and must hold exactly one bitmap. + static Result Make(std::span bytes); + + /// \brief Returns true if `pos` is set. Positions that are negative or past + /// the last container are never set. + /// + /// Inline so the common cases (out of range, empty or dense container) cost + /// a few instructions in the caller's loop; only sparse containers are + /// searched out of line. + bool Contains(int64_t pos) const { + if (pos < 0 || pos >= static_cast(containers_.size()) * kContainerSize) { + return false; + } + const uint32_t ref = containers_[static_cast(pos / kContainerSize)]; + const auto length = static_cast(ref & kLengthMask); + if (length == 0) { + return false; + } + const auto pos_in_container = static_cast(pos % kContainerSize); + if (length == kDenseLength) { + const uint8_t byte = containers_data_[(ref >> kOffsetShift) + pos_in_container / 8]; + return ((byte >> (7 - pos_in_container % 8)) & 1) != 0; + } + return SparseContains(ref, pos_in_container); + } + + /// \brief Returns the number of set positions, as stored in the header. + int64_t Cardinality() const { return cardinality_; } + + private: + // Each entry of `containers_` packs a container's byte offset in + // `containers_data_` (upper bits) with its length in bytes (low 8 bits): + // 0-31 for a sparse container, or kDenseLength for a dense one. + static constexpr uint32_t kOffsetShift = 8; + static constexpr uint32_t kLengthMask = 0xFF; + static constexpr uint8_t kDenseLength = 32; + + MumblingBitmapView() = default; + + // Searches the sparse container described by `ref`. + bool SparseContains(uint32_t ref, uint8_t pos_in_container) const; + + std::vector containers_; + // The container section of the caller's buffer (not owned). + std::span containers_data_; + int64_t cardinality_ = 0; +}; + +} // namespace iceberg