[PATCHv4 00/10] promoted index for reading partial partitions

101 views
Skip to first unread message

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:19 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
The goal of this patch series is to support reading and writing of a
"promoted index" - the Cassandra 2.* SSTable feature which allows reading
only a part of the partition without needing to read an entire partition
when it is very long. To make a long story short, a "promoted index" is
a sample of each partition's column names, written to the SSTable Index
file with that partition's entry. See a longer explanation of the index
file format, and the promoted index, here:

https://github.com/scylladb/scylla/wiki/SSTables-Index-File

There are two main features in this series - first enabling reading of
parts of partitions (using the promoted index stored in an sstable),
and then enable writing promoted indexes to new sstables. These two
features are broken up into smaller stand-alone pieces to facilitate the
review.

Three features are still missing from this series and are planned to be
developed later:

1. When we fail to parse a partition's promoted index, we silently fall back
to reading the entire partition. We should log (with rate limiting) and
count these errors, to help in debugging sstable problems.

2. The current code only uses the promoted index when looking for a single
contiguous clustering-key range. If the ck range is non-contiguous, we
fall back to reading the entire partition. We should use the promoted
index in that case too.

3. The current code only uses the promoted index when reading a single
partition, via sstable::read_row(). When scanning through all or a
range of partitions (read_rows() or read_range_rows()), we do not yet
use the promoted index; We read contiguously from data file (we do not
even read from the index file, so unsurprisingly we can't use it).

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:24 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
In a later patch adding "promoted index" read support, we would like to
parse only part of an sstable row. In that case, the parser should start
not at the usual ROW_START state, but rather at the ATOM_START state.

But there's a problem: The sstable parser consumer currently assumes that
the parser stops after the start of the row, before reading any atoms.
So in the partial row case too, we must stop parsing before reading the
first atom.

For this, this patch adds the new "STOP_THEN_ATOM_START" parser state.
When starting in this state, the parser stops immediately (with
row_consumer::proceed::no), and when restarted again it will be in the
ATOM_START case.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/row.cc | 5 +++++
1 file changed, 5 insertions(+)

--- .before/sstables/row.cc 2016-08-07 14:46:38.886288988 +0300
+++ .after/sstables/row.cc 2016-08-07 14:46:38.887288996 +0300
@@ -51,6 +51,7 @@ private:
RANGE_TOMBSTONE_3,
RANGE_TOMBSTONE_4,
RANGE_TOMBSTONE_5,
+ STOP_THEN_ATOM_START,
} _state = state::ROW_START;

row_consumer& _consumer;
@@ -69,6 +70,7 @@ public:
|| (_state == state::CELL_VALUE_BYTES_2)
|| (_state == state::ATOM_START_2)
|| (_state == state::ATOM_MASK_2)
+ || (_state == state::STOP_THEN_ATOM_START)
|| (_state == state::EXPIRING_CELL_3)) && (_prestate == prestate::NONE));
}

@@ -319,6 +321,9 @@ public:
}
break;
}
+ case state::STOP_THEN_ATOM_START:
+ _state = state::ATOM_START;
+ return row_consumer::proceed::no;
default:
throw malformed_sstable_exception("unknown state");
}

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:25 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
Currently, the main sstable data parsing entry point data_consume_rows()
takes a contiguous range of bytes to read from disk and parse. This range
is supposed to be an entire partition or contiguous group of partitions.
and is self contained (can be parsed without extra information about the
identity of these partitions).

For the promoted index feature (which we will add in a following patch)
we will want the range to span only a part of a partition, and will need
the caller to provide some information not available to the parser (such
as the partition's key). In the future, we will also want to support a
vector of byte ranges, instead of just one.

So in preparation for this, this patch simply replaces the start/end pair
by a new class disk_read_range, which can be easily extended in later
patches. No new functionality is introduced in this patch.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/partition.cc | 22 +++++++++++-----------
sstables/row.cc | 7 ++++---
sstables/sstables.hh | 12 +++++++++++-
tests/sstable_test.cc | 4 ++--
4 files changed, 28 insertions(+), 17 deletions(-)

--- .before/sstables/sstables.hh 2016-08-07 14:46:38.960289608 +0300
+++ .after/sstables/sstables.hh 2016-08-07 14:46:38.961289616 +0300
@@ -155,6 +155,16 @@ public:
// object lives until then (e.g., using the do_with() idiom).
future<> data_consume_rows_at_once(row_consumer& consumer, uint64_t pos, uint64_t end);

+ struct disk_read_range {
+ uint64_t start;
+ uint64_t end;
+ disk_read_range() : start(0), end(0) {}
+ disk_read_range(uint64_t start, uint64_t end) :
+ start(start), end(end) { }
+ explicit operator bool() const {
+ return start != end;
+ }
+ };

// data_consume_rows() iterates over rows in the data file from
// a particular range, feeding them into the consumer. The iteration is
@@ -172,7 +182,7 @@ public:
// The caller must ensure (e.g., using do_with()) that the context object,
// as well as the sstable, remains alive as long as a read() is in
// progress (i.e., returned a future which hasn't completed yet).
- data_consume_context data_consume_rows(row_consumer& consumer, uint64_t start, uint64_t end);
+ data_consume_context data_consume_rows(row_consumer& consumer, disk_read_range toread);

// Like data_consume_rows() with bounds, but iterates over whole range
data_consume_context data_consume_rows(row_consumer& consumer);
--- .before/sstables/row.cc 2016-08-07 14:46:38.969289683 +0300
+++ .after/sstables/row.cc 2016-08-07 14:46:38.970289691 +0300
@@ -383,18 +383,19 @@ future<> data_consume_context::read() {
}

data_consume_context sstable::data_consume_rows(
- row_consumer& consumer, uint64_t start, uint64_t end) {
+ row_consumer& consumer, sstable::disk_read_range toread) {
// TODO: The second "end - start" below is redundant: The first one tells
// data_stream() to stop at the "end" byte, which allows optimal read-
// ahead and avoiding over-read at the end. The second one tells the
// consumer to stop at exactly the same place, and forces the consumer
// to maintain its own byte count.
return std::make_unique<data_consume_context::impl>(shared_from_this(),
- consumer, data_stream(start, end - start, consumer.io_priority()), end - start);
+ consumer, data_stream(toread.start, toread.end - toread.start,
+ consumer.io_priority()), toread.end - toread.start);
}

data_consume_context sstable::data_consume_rows(row_consumer& consumer) {
- return data_consume_rows(consumer, 0, data_size());
+ return data_consume_rows(consumer, {0, data_size()});
}

future<> sstable::data_consume_rows_at_once(row_consumer& consumer,
--- .before/sstables/partition.cc 2016-08-07 14:46:38.971289700 +0300
+++ .after/sstables/partition.cc 2016-08-07 14:46:38.973289716 +0300
@@ -590,17 +590,17 @@ struct sstable_data_source {
, _context(_sst->data_consume_rows(_consumer))
{ }

- sstable_data_source(shared_sstable sst, mp_row_consumer&& consumer, uint64_t start, uint64_t end)
+ sstable_data_source(shared_sstable sst, mp_row_consumer&& consumer, sstable::disk_read_range toread)
: _sst(std::move(sst))
, _consumer(std::move(consumer))
- , _context(_sst->data_consume_rows(_consumer, start, end))
+ , _context(_sst->data_consume_rows(_consumer, std::move(toread)))
{ }

sstable_data_source(schema_ptr s, shared_sstable sst, const sstables::key& k, const io_priority_class& pc,
- query::clustering_key_filtering_context ck_filtering, uint64_t start, uint64_t end)
+ query::clustering_key_filtering_context ck_filtering, sstable::disk_read_range toread)
: _sst(std::move(sst))
, _consumer(k, s, ck_filtering, pc)
- , _context(_sst->data_consume_rows(_consumer, start, end))
+ , _context(_sst->data_consume_rows(_consumer, std::move(toread)))
{ }
};

@@ -680,9 +680,9 @@ public:

static future<streamed_mutation> create(schema_ptr s, shared_sstable sst, const sstables::key& k,
query::clustering_key_filtering_context ck_filtering,
- const io_priority_class& pc, uint64_t start, uint64_t end)
+ const io_priority_class& pc, sstable::disk_read_range toread)
{
- auto ds = make_lw_shared<sstable_data_source>(s, sst, k, pc, ck_filtering, start, end);
+ auto ds = make_lw_shared<sstable_data_source>(s, sst, k, pc, ck_filtering, std::move(toread));
return ds->_context.read().then([s, ds] {
auto mut = ds->_consumer.get_mutation();
assert(mut);
@@ -763,7 +763,7 @@ sstables::sstable::read_row(schema_ptr s

auto position = index_list[index_idx].position();
return this->data_end_position(summary_idx, index_idx, index_list, pc).then([&key, schema, ck_filtering, this, position, &pc] (uint64_t end) {
- return sstable_streamed_mutation::create(schema, this->shared_from_this(), key, ck_filtering, pc, position, end).then([] (auto sm) {
+ return sstable_streamed_mutation::create(schema, this->shared_from_this(), key, ck_filtering, pc, {position, end}).then([] (auto sm) {
return streamed_mutation_opt(std::move(sm));
});
});
@@ -781,12 +781,12 @@ private:
mp_row_consumer _consumer;
std::function<future<lw_shared_ptr<sstable_data_source>> ()> _get_data_source;
public:
- impl(shared_sstable sst, schema_ptr schema, uint64_t start, uint64_t end,
+ impl(shared_sstable sst, schema_ptr schema, sstable::disk_read_range toread,
const io_priority_class &pc)
: _schema(schema)
, _consumer(schema, query::no_clustering_key_filtering, pc)
- , _get_data_source([this, sst = std::move(sst), start, end] {
- auto ds = make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer), start, end);
+ , _get_data_source([this, sst = std::move(sst), toread] {
+ auto ds = make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer), std::move(toread));
return make_ready_future<lw_shared_ptr<sstable_data_source>>(std::move(ds));
}) { }
impl(shared_sstable sst, schema_ptr schema,
@@ -808,7 +808,7 @@ public:
, _get_data_source([this, sst = std::move(sst), start = std::move(start), end = std::move(end)] () mutable {
return start().then([this, sst = std::move(sst), end = std::move(end)] (uint64_t start) mutable {
return end().then([this, sst = std::move(sst), start] (uint64_t end) mutable {
- return make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer), start, end);
+ return make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer), sstable::disk_read_range{start, end});
});
});
}) { }
--- .before/tests/sstable_test.cc 2016-08-07 14:46:38.975289733 +0300
+++ .after/tests/sstable_test.cc 2016-08-07 14:46:38.976289742 +0300
@@ -448,7 +448,7 @@ SEASTAR_TEST_CASE(compressed_row_read_at
SEASTAR_TEST_CASE(uncompressed_rows_read_one) {
return reusable_sst("tests/sstables/uncompressed", 1).then([] (auto sstp) {
return do_with(test_row_consumer(1418656871665302), [sstp] (auto& c) {
- auto context = sstp->data_consume_rows(c, 0, 95);
+ auto context = sstp->data_consume_rows(c, {0, 95});
auto fut = context.read();
return fut.then([sstp, &c, context = std::move(context)] {
BOOST_REQUIRE(c.count_row_start == 1);
@@ -465,7 +465,7 @@ SEASTAR_TEST_CASE(uncompressed_rows_read
SEASTAR_TEST_CASE(compressed_rows_read_one) {
return reusable_sst("tests/sstables/compressed", 1).then([] (auto sstp) {
return do_with(test_row_consumer(1418654707438005), [sstp] (auto& c) {
- auto context = sstp->data_consume_rows(c, 0, 95);
+ auto context = sstp->data_consume_rows(c, {0, 95});
auto fut = context.read();
return fut.then([sstp, &c, context = std::move(context)] {
BOOST_REQUIRE(c.count_row_start == 1);

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:26 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
The "struct column" code in partition.cc is generally useful code for
parsing serialized column names from the sstable. It is currently private
inside the "mp_row_consumer" class. But in a next patch we'll also want
to use it in the "sstable" class, for the promoted-index parsing code,
which among other things also needs to deserialize column names.

The trivial fix, in this patch, is to make this code "public". However,
for now it is still available only in partition.cc.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/partition.cc | 2 ++
1 file changed, 2 insertions(+)

--- .before/sstables/partition.cc 2016-08-07 14:46:39.055290403 +0300
+++ .after/sstables/partition.cc 2016-08-07 14:46:39.057290420 +0300
@@ -125,6 +125,7 @@ private:
stdx::optional<new_mutation> _mutation;
bool _is_mutation_end;

+public:
struct column {
bool is_static;
bytes_view col_name;
@@ -200,6 +201,7 @@ private:
}
};

+private:
// Notes for collection mutation:
//
// While we could in theory generate the mutation for the elements as they

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:27 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
Our index_entry type, holding one partition's entry that we read from the
index file, already contained the "_promoted_index" which we read from
disk - as an unparsed byte buffer. But there wasn't any API to access
this buffer after it was read. This patch adds a trivial getter, to get
a read-only view of this buffer.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/types.hh | 4 ++++
1 file changed, 4 insertions(+)

--- .before/sstables/types.hh 2016-08-07 14:46:39.124290981 +0300
+++ .after/sstables/types.hh 2016-08-07 14:46:39.124290981 +0300
@@ -82,6 +82,10 @@ public:
return _position;
}

+ bytes_view get_promoted_index_bytes() const {
+ return to_bytes_view(_promoted_index);
+ }
+
index_entry(temporary_buffer<char>&& key, uint64_t position, temporary_buffer<char>&& promoted_index)
: _key(std::move(key)), _position(position), _promoted_index(std::move(promoted_index)) {}

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:28 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
This patch adds a test that takes an sstable with one partition of 13,520
clustering rows (spanning 700 KB in the data file), and attempts to read
various slices CQL rows, counting that we got back the expected number
of rows.

The sstable included here was generated by Cassandra, and includes a
promoted index. Promoted index reading is not supported yet (we will
add it in the next patch), so for now the code will always read the
entire partition from disk; But still the clustering-key filtering is
already functional, and will drop some of the rows as requested,
so this test will pass.

Later, when we add promoted index support, we should check that this test
still passes - promoted index will make the reads in this test more
efficient (which the test cannot verify), but the important thing to check
is that it doesn't break any of these tests.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
tests/sstable_test.cc | 219 ++++++++++
tests/sstables/large_partition/try1-data-ka-3-Digest.sha1 | 1
tests/sstables/large_partition/try1-data-ka-3-TOC.txt | 8
3 files changed, 228 insertions(+)

--- .before/tests/sstable_test.cc 2016-08-07 14:46:38.778288083 +0300
+++ .after/tests/sstable_test.cc 2016-08-07 14:46:38.779288092 +0300
@@ -37,6 +37,7 @@
#include <memory>
#include "sstable_test.hh"
#include "tmpdir.hh"
+#include "partition_slice_builder.hh"

#include "disk-error-handler.hh"

@@ -947,3 +948,221 @@ SEASTAR_TEST_CASE(statistics_rewrite) {
});
}, "tests/sstables/generation");
}
+
+// Tests for reading a large partition for which the index contains a
+// "promoted index", i.e., a sample of the column names inside the partition,
+// with which we can avoid reading the entire partition when we look only
+// for a specific subset of columns. The test sstable for the read test was
+// generated in Cassandra.
+
+static schema_ptr large_partition_schema() {
+ static thread_local auto s = [] {
+ schema_builder builder(make_lw_shared(schema(
+ generate_legacy_id("try1", "data"), "try1", "data",
+ // partition key
+ {{"t1", utf8_type}},
+ // clustering key
+ {{"t2", utf8_type}},
+ // regular columns
+ {{"t3", utf8_type}},
+ // static columns
+ {},
+ // regular column name type
+ utf8_type,
+ // comment
+ ""
+ )));
+ return builder.build(schema_builder::compact_storage::no);
+ }();
+ return s;
+}
+
+static future<lw_shared_ptr<sstable>> load_large_partition_sst() {
+ auto sst = make_lw_shared<sstable>(
+ "try1", "data", "tests/sstables/large_partition", 3,
+ sstables::sstable::version_types::ka, big);
+ auto fut = sst->load();
+ return std::move(fut).then([sst = std::move(sst)] {
+ return std::move(sst);
+ });
+}
+
+// This is a rudimentary test that reads an sstable exported from Cassandra
+// which contains a promoted index. It just checks that the promoted index
+// is read from disk, as an unparsed array, and doesn't actually use it to
+// search for anything.
+SEASTAR_TEST_CASE(promoted_index_read) {
+ return load_large_partition_sst().then([] (auto sstp) {
+ schema_ptr s = large_partition_schema();
+ return sstables::test(sstp).read_indexes(0).then([sstp] (index_list vec) {
+ BOOST_REQUIRE(vec.size() == 1);
+ index_entry &e = vec[0];
+ BOOST_REQUIRE(e.get_promoted_index_bytes().size() == 468);
+ });
+ });
+}
+
+// Use an empty string for ck1, ck2, or both, for unbounded ranges.
+static query::partition_slice make_partition_slice(const schema& s, sstring ck1, sstring ck2) {
+ std::experimental::optional<query::clustering_range::bound> b1;
+ if (!ck1.empty()) {
+ b1.emplace(clustering_key_prefix::from_single_value(
+ s, utf8_type->decompose(ck1)));
+ }
+ std::experimental::optional<query::clustering_range::bound> b2;
+ if (!ck2.empty()) {
+ b2.emplace(clustering_key_prefix::from_single_value(
+ s, utf8_type->decompose(ck2)));
+ }
+ return partition_slice_builder(s).
+ with_range(query::clustering_range(b1, b2)).build();
+}
+
+// Count the number of CQL rows in one partition between clustering key
+// prefix ck1 to ck2.
+static future<int> count_rows(sstable_ptr sstp, schema_ptr s, sstring key, sstring ck1, sstring ck2) {
+ return seastar::async([sstp, s, key, ck1, ck2] () mutable {
+ auto ps = make_partition_slice(*s, ck1, ck2);
+ auto row = sstp->read_row(s, sstables::key(key.c_str()),
+ query::clustering_key_filtering_context::create(s, ps)).get0();
+ if (!row) {
+ return 0;
+ }
+ int nrows = 0;
+ auto mfopt = (*row)().get0();
+ while (mfopt) {
+ if (mfopt->is_clustering_row()) {
+ nrows++;
+ }
+ mfopt = (*row)().get0();
+ }
+ return nrows;
+ });
+}
+
+// Count the number of CQL rows in one partition
+static future<int> count_rows(sstable_ptr sstp, schema_ptr s, sstring key) {
+ return seastar::async([sstp, s, key] () mutable {
+ auto row = sstp->read_row(s, sstables::key(key.c_str())).get0();
+ if (!row) {
+ return 0;
+ }
+ int nrows = 0;
+ auto mfopt = (*row)().get0();
+ while (mfopt) {
+ if (mfopt->is_clustering_row()) {
+ nrows++;
+ }
+ mfopt = (*row)().get0();
+ }
+ return nrows;
+ });
+}
+
+// Count the number of CQL rows between clustering key prefix ck1 to ck2
+// in all partitions in the sstable (using sstable::read_range_rows).
+static future<int> count_rows(sstable_ptr sstp, schema_ptr s, sstring ck1, sstring ck2) {
+ return seastar::async([sstp, s, ck1, ck2] () mutable {
+ auto ps = make_partition_slice(*s, ck1, ck2);
+ auto reader = sstp->read_range_rows(s, query::full_partition_range,
+ query::clustering_key_filtering_context::create(s, ps));
+ int nrows = 0;
+ auto smopt = reader.read().get0();
+ while (smopt) {
+ auto mfopt = (*smopt)().get0();
+ while (mfopt) {
+ if (mfopt->is_clustering_row()) {
+ nrows++;
+ }
+ mfopt = (*smopt)().get0();
+ }
+ smopt = reader.read().get0();
+ }
+ return nrows;
+ });
+}
+
+// This test reads, using sstable::read_row(), a slice (a range of clustering
+// rows) from one large partition in an sstable written in Cassandra.
+// This large partition includes 13520 clustering rows, and spans about
+// 700 KB on disk. When we ask to read only a part of it, the promoted index
+// (included in this sstable) may be used to allow reading only a part of the
+// partition from disk. This test doesn't directly verify that the promoted
+// index is actually used - and can work even without a promoted index
+// support - but can be used to check that adding promoted index read supports
+// did not break anything.
+// To verify that the promoted index was actually used to reduce the size
+// of read from disk, add printouts to the row reading code.
+SEASTAR_TEST_CASE(sub_partition_read) {
+ schema_ptr s = large_partition_schema();
+ return load_large_partition_sst().then([s] (auto sstp) {
+ return count_rows(sstp, s, "v1", "18wX", "18xB").then([] (int nrows) {
+ // there should be 5 rows (out of 13520 = 20*26*26) in this range:
+ // 18wX, 18wY, 18wZ, 18xA, 18xB.
+ BOOST_REQUIRE(nrows == 5);
+ }).then([sstp, s] () {
+ return count_rows(sstp, s, "v1", "13aB", "15aA").then([] (int nrows) {
+ // There should be 26*26*2 rows in this range. It spans two
+ // promoted-index blocks, so we get to test that case.
+ BOOST_REQUIRE(nrows == 2*26*26);
+ });
+ }).then([sstp, s] () {
+ return count_rows(sstp, s, "v1", "10aB", "19aA").then([] (int nrows) {
+ // There should be 26*26*9 rows in this range. It spans many
+ // promoted-index blocks.
+ BOOST_REQUIRE(nrows == 9*26*26);
+ });
+ }).then([sstp, s] () {
+ return count_rows(sstp, s, "v1", "0", "z").then([] (int nrows) {
+ // All rows, 20*26*26 of them, are in this range. It spans all
+ // the promoted-index blocks, but the range is still bounded
+ // on both sides
+ BOOST_REQUIRE(nrows == 20*26*26);
+ });
+ }).then([sstp, s] () {
+ // range that is outside (after) the actual range of the data.
+ // No rows should match.
+ return count_rows(sstp, s, "v1", "y", "z").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 0);
+ });
+ }).then([sstp, s] () {
+ // range that is outside (before) the actual range of the data.
+ // No rows should match.
+ return count_rows(sstp, s, "v1", "_a", "_b").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 0);
+ });
+ }).then([sstp, s] () {
+ // half-infinite range
+ return count_rows(sstp, s, "v1", "", "10aA").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == (1*26*26 + 1));
+ });
+ }).then([sstp, s] () {
+ // half-infinite range
+ return count_rows(sstp, s, "v1", "10aA", "").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 19*26*26);
+ });
+ }).then([sstp, s] () {
+ // count all rows, but giving an explicit all-encompasing filter
+ return count_rows(sstp, s, "v1", "", "").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 20*26*26);
+ });
+ }).then([sstp, s] () {
+ // count all rows, without a filter
+ return count_rows(sstp, s, "v1").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 20*26*26);
+ });
+ });
+ });
+}
+
+// Same as previous test, just using read_range_rows instead of read_row
+// to read parts of potentially more than one partition (in this particular
+// sstable, there is actually just one partition).
+SEASTAR_TEST_CASE(sub_partitions_read) {
+ schema_ptr s = large_partition_schema();
+ return load_large_partition_sst().then([s] (auto sstp) {
+ return count_rows(sstp, s, "18wX", "18xB").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 5);
+ });
+ });
+}
diff --git a/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db b/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db
new file mode 100644
index 0000000000000000000000000000000000000000..8cb58ac8e573b8a0428b128cc3aec143de3e532b
GIT binary patch
literal 123
zcmZSJ^@%cZ&d)6<N-ZwVFJb@zMli|1!1Z1U$l`|bpj3hdgt6}#m}ZpS0HJHPLFilm
Zz%-L37lfX54MP7_2Gh*(RS^2%d;m+e5o!Pc

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-Data.db b/tests/sstables/large_partition/try1-data-ka-3-Data.db
new file mode 100644
index 0000000000000000000000000000000000000000..34297464d7303c6bfbe3767773451251f19a91c4
GIT binary patch
literal 269525
zcmZTxcU%<57vI~v1LQyf5e`Jf1#eGOgcEn+IPMNO?i4#VVu`&YHdMqOHI^tbu^TiN
z?7i36qQ+<}iAJ$&tnp{;QDcn$-t6A)&a8isPyEiCH*aR%d-JBeJ&Mv$%PD$T;@FQL
zKaPWcbS+0|6S|}aQiJqd-xRlQc_3BMV5Cy$f_jmZg)ZunL<MKClqQKvY!p2#5dDua
zBZ;CTDLs^AiY3i<YQ&OExx^)uFs;n#LKT-(5S9g;ayPUU>ERz<PHv#@O(k~t>pQW;
zEth!2Ho8o>B$jyOk_KW)&((v)k_K`~L$Rda*G93Vp<I$JmJAG?E0$!-C5^<Af<JX)
zNh7(Wu~<^nb*)&^ST1QImW(OeD3&ylOPY!$6T(`GB~9g$W@5?Y!K=iQW^ze$v1EG0
z8L_0fT+%`;nK`>eENLN^<cKA6taHSY9I1qUg9e^k@LPYFv6d1V+)AWhJfJqv_oj@k
z<dW7x3A6lIEghQV)>1)O8<?@x315r+;UD6R(cfvIKDWUf2E=V8G&on}zhz4ek$<jS
z@|jS=?wl2%HGU?cVeOJAX78y8#LEc(54?3rRCw10`ox1hE2UFZ5=9v)p9Xp;NTiDZ
zM`hfPlRGC-<pdPekoMJU&QaA*_}8Q8-U{psOn%8bUmuNwOba0QYx(jd68-yFn~#>P
zns8-`9{8OjtKJ;^FIm-e=i_#t2#`q}6<}|A*yWm5LFl@)W{HM*{CX&*$<q*WJU?bp
zv41n+dy+l(?~|$+0t4Z;Qm*MRM9s=*tzd)#ru+T#B+9RW9)rqd4p&2gm+Pvb(58zp
z2&o5kLBm@k7A9+OcInotj!j_7el(6+tT8Dtbr=Id81`7--YQ{gXWvv)CCuKZhU#aB
zOAu&5ShoiHENjZ*VnGM=LgzpS07WHkYudy25;Z7+&~nBVMh!J+?yH8H>{+aaauRl8
z5Sp`6+SF!jb6+Dgg$-(lfn%|*(dTu@2D*erVwD9!dUUI<hWh;cw;IZy_C^gAY)Di?
zh1afN5K`dL?WST%fspaP+en1{QsdMT+BU80AEbtJ#k=~El}xj8ruaobk7Z?M<~@Aw
zM}_JMkShs#R6^JVyQH^Dw^#UHR<*XKPdwQgvvKWhjYj9S31s%&8|dqA3+URLuz3Jc
z0k>;%WwJiEzuj*t<Z$h?B*Gl~bqh`DG!ei-?v&}|k%Axs;m+2!V?7E+D@&+8@qE`R
z;Ki^4WZst}j`|aond^_CA7pP$cj!@ig39!8r>z2kaE~ACka`aajHdDV*i)qZ+}}SP
zAraHNa>?ZtK6Edw=7NU%_+TC;06mWe$H}GY+1dsp^jub8F4aHeP&oo}r<R|vr-U@u
z)R4<xVk(C;I@K6ZriP-rcTq#tdu>xgCTlkm;!@*!xq`hyz_f?-5c*(>KWg*=XD=Ii
z4={B2<5Dfxj1|!;AT1goPgW|Qw&fgUgmSra?$p$?tI4J;sm`DO(orrQL1;<MvfQI_
zw?((7G|3vSVaEh=BrK^-9*w49ZgH>YPR(g{Mh&%TIgV`Fo!V~C1~t^_%Z_TOd-ul}
z6pZ4AJWXQn_j^I}NFU6l_CLAbkLZazb?}~RuyQspqebl&rfT@49vDly8x5-?H>$%7
zl_HIAUsfRk22in!Nf(231j0@0lZ2^1eG0K+i-)MxcGlOSnD!w>o<HL!vNdke%9Sc)
zS-18Qf{eds13k0y^gWs?rO{-EBDuib1B{AH>pJfC#gzbBslREVsf3DvQl$&q8&QD-
z!tGf$ffUYkuwIgi=4dlcMe}oJXCukybk{#sG{1iLup&uw(S3rX;jTRFBy|!+DliuX
zTJGl10T_s!%AL|z<w#Z!`B;*b>G8r=ek9Fv%}kPpeVtQE6JGz{s%DJD2Q1k}1qER0
zAwW87ZxXWD{B~E@Yg{^6@o9(*{Ajl=(A<I4ea;q~f31oUW<jw;TcsBUlFDt1bn#Lf
zXmRfaMr^Bkx{kQGhoZ_b+km1Hi;elEiIz&%;4>~rYA!8MGp>_WUt;Wy18j*W)~O+G
zL>dWkwp8REp*2}<i_Q686`jiLEVitI4I12A2!dpDKb#}n0%vP_w2W5x(f?{R0a~tA
zxd^quxvRmIDFa&zEgoEl3*9j=*t<*UV!!^0A8^}xblHv33gYy6*pq~KTmGOtB8GF@
z25*kSWbp;P8{VdOWCRR>VnCxDg~0^Ejhpry^8u*Vq@dn`1dVCx_p5_Qq`2IBBZ<ta
zcEaFAkk{`G8;F5){rS7T&<WEl8GLUrc=+Q=PQ8X6MOPAM2b$%U){iF5hFh6^j6_W9
zT0X8G0o9cbZMv~Nnn1Yi6DE-z;&v}*Nj}{E*MF&yLk~BTi0Rmu;4bmDn3K7%Wm!*x
z+*w^OvN_ZFi?a<xMXs!O3TCEgjIUST?Mu)wf6S>w%i$7eI-+`D@T)*jnI7+?SOVdm
zcOIqk*MFb6sOrkQLUTA#%k(iN7c^HINYF7ZO?&T`03$$(y`=d~0QFo#s##jVKfyXL
zge<)e*mGKNhZZ_Y2<-F%1F&_#QCU`6rK0^}$cHWPTw3IUx8X)8ms{h~s=fn9LqaiS
zjVme;Y<j82K3tmlM0XR0)<b&~Q=N_PYbc=5BTN5;02Rc?c8^d&sh4K@E0DO`G&#o?
zXcZ9IV4Caw7;=Bar8PYEFq)v^(wgopP<JBdDa1o~zuakUb6}<QBYNNAV*)7|pVp-{
z*`PbE$L(Lp5Qa<Z+hIOg&z+Wk?;z#~grOL6V1Ff*4227CV^m1pMn~V(M}VNBb<wGM
zO&M+aqEc;x0wS_0LFZU60t!&QZ~BkI;m-6ePXj5cfgWGp`+~K@pK0dC=IZ60o8x||
zGKvMK_cIYdu2}ctE>kKI2)8^Vgfus1)pXdoCKG#a)4HD?$CLH8tS=(#nRYsJ!$_LF
zGmn!JaR(O{lBUEQt=a-DA>}YBxf36rsp_4MUqII5ep`HwM8Yo(j8d9M=Q#yh)76j9
zR3mU}Ye0}fhKB#1Eg+6Sm_J8N(t(-cGMSzXUt%VxxR-Tak-Iq4n~}Df3Jnd@n5Qwl
zuYNRK0YQ0qyQZSF_#lJt2L^A~zZvgc!1dDN4mc{yvitv1LG<~!!P_e&+Grz`%LebZ
zSA1QDX`s-Q5w@PPU4Si8c^b}M<=VMGRaGXh6eEPH7Q3kooE5nyTI{uEtF{6^X~6PK
zb?+1e5ga*tQpcI$Dk!CDvYCL~cE^apWZ3SuyIQW7hDQugID3P|<LW3CgPRNc4^xvb
zS8L7v@L)dOo>NZ?+Dp1v&fexWULP5-z5QRd3JObr-1g2tRKvyq1)n+%*M0wwYH9kg
z6Mc!QoW1|u3zb#SVB>oO0lDqN){Muz6w<wsV+K};fJp=k1yu;o187|BYg*jo0Tb|v
z%Vt~f_ztSqpUVAxjxy)T=g5FDGj5JXn}P_ar`Y|h#OVnnGVgWw01_!F2K$w3(VaAK
zsKYD`$U+lLn8J$W_ZEc^+T_-ZT%j_BjTK?dmYJchZav}*B9UFODiOGSQ;Ny9m_q^A
zkrEQ^AMFOw6T$oEVmMWl5w!2}qfKX;s>qn%9yLTeGMpKAsdF0XeN5LXor_eMq3+!p
zJ6q+C?j8svy^rZnI|Kl-2vCcCa*u4v^s+ugk0J@0?EWw)Z}yf|z$Y89kp5Z-2WZoO
zJ-64v=NoCQgZ2eG10vbzS%+_J2Z3-7!^hpe1eE0n&bV_yLtvaE>}Zfqf#{DkY#=yC
zWv8pEf(ngRd$pfYL9t^BF)F&B4vu}enw>{VfsEI19d&lXVFE5M=ct$5SuHSs5>8og
zD%O#jSD8TE4ku?Nxko#)()8MBn~E;GT?}ckZb#E?FG$GZXjupcU8D3wUCxm^{+YU`
z9a}=ggv-V`x<<@4s-RvCjaC(uclVciDrnG}sCX}g9DhDIcgL^_cbA}mUccG}lL~Pj
zps0j%6g3qcf#mg(5smF~OBVs9ie*n2Grb&vaFb7+CKZpHvF|9Rt#I6>Db$(1?Uh`a
ztT=D!H>8@gC92qfTXJa$oS$Sb(I^6}m>61{;A2`lu^^5_HvRTCoJ6+whIpOm$nK91
zqe<k4M~4zf<Vc&6ND?`IRY&&1bZU49vMugh^@)DOHs5q1Q&o$*Y|khA&Ru^w85=Y-
z_;;?_GRfBeJaH?SK$xdjA#fk(;{}nK4}hAlYUGx~%^Wa<*MGa?3AwVPX8wEV3XXtM
zafp!xI_XtQDjNY3%^rpAw{)D-cftvaf}$nN8Cc-}w!#QdaNIwn^1GdtUdRE6*HE36
zUqT!&w*VC_&gdV8qB9HvbvtX6mctfFp@q1C-;pg?oOMsHK_|g-<RLIj8Xo+~!GO~m
z|B$5Poc3jfI-*t1nK@>AMHSSbd@Du;HO{$}tb$r-3TvsL*6YTpd9@3Gm>=)G+u7;H
zRx*mPIC~u0gFG|dDYvuljT>al#W@GGNG|W?1_}@|@M{X}jTy3JgoY}ikf}=%-as&Q
z_~V=-W_9pa`+Db?f#9E^Se$gwjQSI5+u>{;AjSG7f8W_aB44e8O$R~q^~r<?1wpqk
z5SGsV%0^=#k8Ux!1>e@h_P+G@0=PKjFlh+fvaLf@$g2OHBoWhw;w9x3{vbWK^-{XZ
z#CDBYPS)b~kB7S^e0??@uJG8G;A1*gr-7=2Cz~YKS7_+7TC{$iWll6!KoEdEf6Yd?
z0j_MdQ?>SAj}OWsDw%HggY6nVob0`y*6RonAL-%jMkGP=JqY|O4DgeXSi<H9jcXM?
z2+aFMx7kK~u0b;9HC%U6oAnV;u1xK}<Hpq?k&jm)V3KLTrnq!naEDkUKypC9rTg`a
zO;bUEbSs+*3SKiYR0V~FZnqLpR(j?C?T7nkl7IAx3uXdxr`HI)t}=r3nlEx=2r4c;
z{=)nK6;zL3QeOq}uQpdxLAC>*$eJGgO5I6!z~gvT#YRD&wAlRap)eIy>s<pYsGxR(
zMv+2T(mPMsp#?i8tUtZy#$Baehk&Mj@Od3<*tzt6YghBQp$~4LuRb^fb}jHWU|_rh
zw)KJ|z^`cB=|dmfBi$&MUes??iV-Tyv+GVDGxt6=)JS>0cm#Ll*osfjLf3@cm+yAS
z=9a7hLep0hF4T_zZi<S1{cK!C5}6Y-F_c6WR@z^QL>4!O%Q}M3vO8ds1hQ&oftEm+
zb<bd9c7cfG*)223GX!R5Pgo*kvBg`yef77KcFP?4Rk&rsjgUKbaUogHbke`Gg%H7X
zrY%HIgqY`}FJur1cWGY?T$JS&>XcEs7P33kJXn5&fyVsy7`Vffwk0t0;X`12@7r8i
z$g-uQS-=op|IzOq&mq4rPdDQ5v^|`C!gUM~h%F(%yk2K|d1Iol0-|Yq%NMjDk@t5;
zg(wJYcYqO>L3evt#|Z2cWy$b4e2d&&a~X!>gmx;bpcb1jl|pVMBXsjaABBpB)j_8*
zMO=e*8E=5gsAlLLs6gnfuQz3i*}l4p0t)=tKPFaJLA84yN>CtlF<U}0i7jEfSw=3g
z8THrHB9~$|!x~*lsVlVLIJaHhdsof_RcMjXF#1FdRmCRPriZDZoB^tl<TBcv0;fv$
zy?wSH=Y>E6wEt$HRi{&-ABS6h0c_|BU|8TlwR;8eEKiE(L2M?Yk3*|*er^OZaoU1i
zaG(NXIKY`(PC<np4!H??DVb1!3Wq@iC_|tuiKAVw)=-pF8v&@S!OZw=dK7u#24kAS
zm#`$&^d}IsVMav5MidsZZ+ypD2|{kp=WDPq0h(nOoFgsUv^W>G!?+AwX%L(+5fZGv
z`p}1@+3*b<Z4)$G{|DFiI3H%$U^o#_wYKkwij(Qk&JK2>p6U4b#?d5lsu~>p;k?<i
zA($UUws-y;2&QlnQ&}2#6%m114;wnupUb!&bvFe!{Gnj@@W<TV7@>vtK`PTX-G2l(
zJ5VmqPssl&<Y>UB;+W}KpT-qQ<ke0%Nt9_&bOvGNKmFmXlAMkDA4bN3_mwF@Rot2M
zn;ojvCDXSB6=?)2QS;!qk~&94XBxUR(~+lsTxNxHn`>i~@ZJYhG_(g?FUZxAK4uzE
z<%TH`Iu-!BDnr4SkaSEwZ1{1=ooTv4ldj5=Su6K4t+A2LAhYh<YAR=ynY0l+3C@kn
zObMB7As|a;+HhFE$;}a$nK5LXS~gES1PC}cKC{t|04=`mbD7Pa?GE)4AuSjNJNeAk
z`DSq^FNODjq7p8%-H68O7a8u%PSr199YKqBfY#J)=ag<ns3ZGuF0*&#2Gvwh-Zv`9
zojLILA!Og8Gl!OQYuD?Ps-VwI(Q1f2;BXL{khRY=HWi-e;0QZmmntrvI<l-IL1HRy
zI<pap%+7%b7H4Bx&;%~`2xQS8V1xv+tjqdZB(ln`;=`?9KAMaGOk49_C6KjtE-VQo
zk^S{|hmy!)9h|n}tux1_f>H#KFTZ|%I7rp|vs0E-_SQpd{cz+M?%0r@m)Cm05FS*v
zRHqHnsV)BcFgT=vVr9&4Pj2N$z4Y<v?R_5#lf&Kn>p#pxB8}Lr=N`3~qH^3%<IVmA
zGwv0$8grZIo(bZCw?Fx-D*iX4v&B3-JK1}9gWQ5k>-P@RLS)1)-<5FU1;Q#i=n9w{
z?MFavS8(C?<l@S^!qnI7uFB^ok=!k=YS${!)HSWbEjXt=dPK>&Vo%Smp}-(Yx~t}y
zUm<8DS#YlS7KOnCA?LCzeH*KS_!78mAiI%z3zka~a@K`6LL}rWgyT*UY8Vt1>V=TG
z7ouTmx_xF3m}mWZ9Sjtl+X09QEUuPyH)vE|Ul`Y19W(_L*tm9x1%V1@`eRV%0yu&s
zsd_}*t)@UUT+f21=rbv*H8qy^(J8aZx%yv7sHadut68qW*}prr1jf0B2PZ`;5L)L(
zCi~TlfL3J%<;GtA0#imrGjTNRJ_(wsVXC)6LB*#twXk2usZ6t~+;x-4yk}sm1Wn1D
zYe6Kk)HJZ8f}rQq@Wgawd3ZuZR9xFLnjsKwQ@;^XU=D{{Nbnu}p=^SN*?Se<trU{G
z_=C%y`H@sd?~G73BgpVa0JD>y?~X_29fURrFztW|_}Le)x~t5-{)N)Md722I5Qmk9
zrz;R5US4aCRX`-*4L5i^nG6u-PP*`(hX73v9uK6ABP4ABGVXEGZgS~2J$rPwHd*U$
zALtj(-1N_RXFn48utb-kAV^!Yw7I$2MyRH!W|rUA-Rr5Kz&^br6$sw&Py=aqR`AtR
zWWdg4h1G_I7H8+qikw;%vut!~Q$m@lMHR#mbX-<!e>l9rt6H*ZF8NCbMu4x$?yPuM
zb!-VlZxrET(qaXp!z=Sy+^!&E7tdv-UVN3HB69v9c{gP6MQB8_{A}p1Mn1g*P%OxP
z(5fLm^~mnBn*DeyPh$icc>vv6t&--eVz8{-etG3pR2}wK!o~%dS+crBgF3+E<LtPs
z9<QNqB-A%QC|CvM{{_CAq#BZWp$`GMvkE7_#lkP7l%uHzArVkdb_u5O9cTKJ$fVNu
z1`?V2prDF^phsOnI#aQ~OQ(Rqoc$J#I`BB3nKv8u9s`NvIn#Hq?sg`sF-z9Ka*Zu@
zNX`{M)^-q7rZqR=2@@gt#`wGr1j1|`07nR9u+Qy0_qxn00lWv!_NR1-EvAMvoe>rq
z5JBm~^xDc4WuHiMlusjldP<|Ahx$?Q55ErGp}>cu==mCIC~Zk;PF1Rf@TRB&;6Bat
zmXuaSlYJ1_TmoAFnEN`5Ltu^swgj+a{9_FQTS;JR0K1%S5sbh#64(~Np05suATU<~
zKLfDe^De#!Y$t*3^`4Z069;Y9_;rw=jzBlG-kgeb9_9DB1a<<jXv4k=sB&j7NZ+M3
zQ8Y7_N%u!^SBbV8&`#*HD-eO*C9ns8leg6n81$4F9MEZ&QOxw7`;riCZ;7@K(9XP(
z)&PNhC9ofWbEbFW5tt`|{Q+E9agETYd<h%?;Nq+61aP1P4g#>W{G9Tr`d|qh0^sT|
zS|%c}zzfn-wVEOgzoGBT1GL{TiE=nlZlz*k(V!Gc;0OSBUMm-esuxM%NPTk3zVIou
z-zbFWIg08(m7*zXK{0c1<Bp1&Jc^2-d`9VM(3imzgZvlh%T1mdQubXh;8IS2K`VSm
z=@U-0Odd{YNs#$vM+KdVkpH#$UwK4T=J($;T96cH$6UGaa~oAn=H`y?64cn;jHQiK
znE7F8nZk_juhG1snZJ^s1gP71;S-K#ooM&X=_+OwR`GqUPB;Xk!CR@Xb$-UK!k{6u
z7^SyZ_2J)DLj#V1G1hW_&xE=%MlaV;MH-8>eAG)p;V@c@HT2YiAe=b3RTV8v026WN
z>o0IzXszmmrGgb<9MY{ZBcF^A>=;8WR&$lnNIApXmg>A#jKr<IXr5XGk2T@Kvt^33
z(2&Pke^$QK0Z@;SZY`0*F)24Hg@84Ha_EJ&AYZWCD9Fxv>u<5zd!?c=lshd9SZ0+R
z+6W|=1PvBdsGu4!i?zwWx0|afyRA8cKDsoj+HL-+(F$rCJuVF>r!)y2j<?j~)#;j)
zX0wLr(&=<V92SPK$Fh-vB@;sRHKbcql)N?nY-g>i`GUvwLsh~jTSrvI<{zwr8U5X!
zNT9-1jQygj6*6rw+hM-U=#TstPQ^@H{M{^&1IO6nck_M8nzNSupi$K{&#!^0KN6xO
z=K-T4;+L$sG*?S7U(u|%Jjr~`_TM>r86g6*@lj?~SuEr(en;+NAY_nQw>6z;py=uT
zio>`v5l(`_yMqY3e$9gOH^G;{;v!5JNXG8}Zf9Twlq<;Lf_ISOf+5WDpzCI}6sH2)
zSC^#_9T0PNOl!1)$bF)Djm8ZZW$SMQ5DeMNT?hJ+$c^}RAtZ9AEewV%27OSgDWjN&
zug<2@<u!5(Xl(zgd0C6MihA|@P)P-I_oh>5xm(O@zmA2fDPZ0;+!TvfMLL;E)ye$C
zfK&DT*D*ke8&q<tf9oO*j(AebpJ8d83?Wx@U&E(XtXkXG2wjm4k54r=xDlX&qP{=k
zPe7K`>TCCf(JrD5OR8zYY4#IQ;x<QN3rM+Xpb;A1X(1m!OB3f@??$at<tKqUPzF>?
zfhVcgwK2U_kF-Tn3FIhJ`N>yw2GcZ+Y}2W>;I{Fg0dmg-vUL5kO8#-v6w^=5>Q`+t
zj4@7TNo}}j4y}^clG@aAw)-bw&Nufet3W=r&7$q)j6JZyv!u3rces|S8E0yzpKG$T
zRvHDbGfM5g^184DOZ9`BcA_-2F0qg8YT&1{obTU|@H}*i9)^z}{Qg_4Q%L8AAHUZ~
zrA+LolGi>FAgHWz5##TZn)+q+EFEq~^aEN`Uc*jX{6{EJktyDOk5aK`W|e)ikhAm8
zf{ox!GK=mnGUGLo36|F|%eHn?!Ug0r(gYQ7>l0R0SPL#APK%VlEyNfZf{r-6I>M}5
zv?}UTzrk!ezZ_Ye-&=oCtI;A42D*Jw<(2^B2FmWa39h@RM2O7u;F!%CLuapo0g!NX
z^Z5vk)<p~#`}2e=x`>|GfHJ3-)$F1&fA-gFJ^_?(s?TQc8ic0j;?(}#iBY%=hhG}@
zYTW7os$#ZJp5p(Qn>%}0aZ;#mzVm=|G5o`#E}IG2n8)`j#^O_nsy%lcpyiI!^K=@Q
zhJQWd2hx4>|Mr@OjSuoTHYyud%reDnV8x`CQ5KtS@a4`bd+^x&-hM?IqQw^2rAG$z
z0XMrCTX6f&RCO)3u(&NK7{m!Zw#Z3=Qrn;zVZEMJ;%(J@5-Om;B2J6E#xSH2VZ921
z+_o6qJ8})7PodSFHQ$_4#n?--GND&>z6j3&-BY0!O^ezp5iB-t=g67}lyn5@N83_&
zw$hE#8|Gqu$d+!eI6>7@-j=nojlZgu?BUHiB07vAZ)^H~YqVi8&aRc~$DB{da&JRi
ziFbv!bqw4bML-r?m*Gtc)E?2+W7*&U6<yz$1<5LjJ+}NUf8==GwdkmL+u-LHDk@b$
zo!H?sAWs(Lko^fes<4$0fiUBKdeci~5X_|P9d%(aWlaQL=BZamEo6%uM@AU-Di+Aj
z>R^rW@<#q)1v3Ax5L4LZzy2#8EL-spYmqki9h}B2(u0?RS<9;|x&Ua1Svsg@nyPVT
z<)l;U4Fa=n&U257j@?{&aDe{_?|OnpVEf@9y|K46hk%6au3LeQhwL3}RG1%XgI86>
zTZgOPX|H0>96QJp9t*W_a>dC=!v$;@&bl@l3HAvW!WaEa<E{z0RGlANwlW`5jW9vj
z>uub6!!?ZAA7>_3B1s-(!o3_(>GAWmL54q+O3d?xooJd|IM~+}ZID(ZwMA#qDE@!9
ze^xqZ7BSBshhPA>AS#ctr0JqpWvNuqlIFL6OC2<M(&&Q8@o9n1`MySI2j&x$Kzq&w
z`wKRBL2h~E3j~<DA*>Epk$RwzGp*9LKVkiNMI-&df{2*3$fYHqHip;Ut_l3BS+2zx
z`(R$elNMViM&-`ZY6g6qk4%dYt<E!AXZWBnv!q!zonMJ}i-xTl>@)aYqE-^E*qDg&
zL>T2sbME~>dO|)ei-QQP57BIPrPn@$#C%%QcblUO0bj|{kteMsTS4-m-nb*J?W{%)
z8lppjS;v&ckS>J@mYmjQZfC6@hFH>i#x$9(>b)ne@7xqpem-r0*)ND-#-|l%!h-#y
zzLEnnKCSTDbjZ4r_=Cptqd$8?+KTy$=J`5YiI^#kyR`$^MGQHEz^_oe=+-mSANN_K
z0YHuwLcT;RL*IfROWMqbb$j9p1&t-lnXr901resPuQU$G=ob1>mHlgb#YF35sg7S<
z@-wEnNYLd)L8KF7SDhW`M{r`+SL`$j;$uSkE%${rj=**neS)!j@A%b<=quS2lI!4Y
zXI%yHE^J5J=2Rg;j$(gK&aFvE!k-?vN@cUZT^bdwR7CtQE%L8xaC;R80OlJ1T^3CS
z7VNG6y+|@-D@5$Q0;`{)u>$aa?q5fCnSZhkCPh{?)YQvfTUCv}*%72Sv{Klx?>{?K
z-O$DhfOUH8npRgNHAaCzKL`ZuK6R`5$i@#R4E=7^qB4;>ptZqn2=3MxPV`i^Z?RYC
zd%FeF1xfLMz0)3=kS8ibKS>#avmnr!tF_o8YW&?5H)Wu=*sF&7?ocsFw==6=d~&?P
z+u4w#HI4nS)*!R!?4Ow`mb^V7c48&}JjFmP_N2K}Td2s)_LL4`DsGPLuy&9UR<hkS
zPqm2K8~gzQ%P?h3d3%#H@sPHINygiA29)ZI@)#h$Xm88V01;FjxQiAQRp+;BYY~ve
z-u>fC4QLQP&>nlAuG`}Xr{b~aN6f>f11%u5jvw4I08<-b%!fUK!wgUYX@-!Nj@<3p
z2=k!0gP~q`z>e#2K$v@R-%#|W=B+<9TqxuyX5!WM-o2;1E+B4G2lZF)))R{39)o6#
z()-W$P7M(9vj)P`C)|qJ`H8vZ{pTwrY{{vIdc#6Rr<tW0t9GcuA$~>CP14~pYqr6L
z6blZK!E9`@nUBbmya77WeMR%z^bfJHiLO9{nX$WiSSl)%s7w0}Yg?-V5cZJ!iq4$Z
z>;QHEarC<w6s5~u5|1?4pU;OtrjOJzlI6_IGroq+O1IeaF#}@=66Vr^UAgKeuQfg5
zZ`g@dyLB+%N>;o3w*R;It_5vCi!|mx$C3_(d0MT@cwAH@)yu-<YF=(=O;{r-!JGGP
z;RHccf{kcFpw@Ynfc<at6t#EY9W+E4hU1u(IDDUQke?$d9Wn_=Kq^Y7!Av6A5j+ah
zOr)-kaGxqUu;%-pQB0b5RQ`H<EK$?qh_3tRF_rmR9I=PS9##1li=*a(3Q;PMchq?r
z8$xj89reZ^pbb~>J|yd0QU2F(L2S|ML;Y_k2;*@6T^){x2v$x<*46>_wQy{Y8?nWa
zJqJ#qQ~`ve=@ST0@Iishqut;SNzcSPa(@I>c%(>Yadg}^8J$w%ZSan+ts&gQ+3}8E
zQ}$LeJX31&j{fY2F#i`yFOnUD{wVdHaiL`*zaWTr3~M&M23jVBQzlp@0IZ&$kwsIj
ze0WFEx6LE)B?4*F*ah7U#(ZhUkrhqYzo`)B((vBfIKrm*eneL-vdJK9#_N&jbQ;Il
zZ?`V1Y@nx$AsJ#n@4C(}A|ErV#FEwnVFWO9M!c39xAg&D#%%2HfL(FuL>N(*S$lbf
zPHhgG0~!Yt9WZZS0{1^skLbU(ngcYu$88Jn51FoP;SR($i1iQk0^;!!dt`<QYmnCJ
z!OieLh4xeh6sPt^`x_#aPBQ1(4ezQ7AD9cHe-NUuf*^TM#$F!#*i3YYy^&<K69|7d
z^f{a}O46ete589{hwR|9nvz7w0R&HnD4-Wa0ghK4AC*J%D|&#i$*>HB4*(AT(BkqS
zZ3__B57je_{_)=aBSUx6PfM#A61?3K5Z{BK8^A#90Wx%FVAGp@G;n)?qr5Y?t1ZJg
z;8`V%Ff2p3$ins9>5Srs?9<Q<%K2NBhCR;ckF!Xl^Ehif?n^=zXWZHcXm^P-^f(g&
zZ>em_nY1+@vWz65={Xd2MHlU~8tdp`T&3B7zIdGWtNqAj*W=9GvzTm`cQ$Yb)H5_z
zhQ;G-JbNd$Xwf5uv%?mSY1Nfx1^#XPyQ+n2*8)ywWZ{Gn?HmK!Bvt(4?D3%$$&GjR
zi(F|Zs`AbOvrg9cLP!y^kRoU@r-xknp^bP@;5}^4o{ZK44=RSkW_HB6g$CRWfEc`U
z%!Z^UhOUZI2TgbuqKnfS2TDVRlxFfBxRDr$Su^|9?V~jbBxGhC104j3JUG?tUn83t
z@)YLmf>W)0j015kU)<u4Y@!ms?44HH`#|7=nqQrHybeLbZa8<&WEh4q-WIl1)%LD~
z1+~aZ`w!ZK2!uJ@U{5c)GjRvR9P0)8hUo{|AHf~U$;kylhA*%d&wl<8YZ3Gf&S;qn
zaV^w7jxBpMKaFUXz242m69{vAb>&a$-S?eRg`|3vHm{xR2GPuq5T+KSdy*|27m6ML
z-2b40AZny{-a}r*U7_=J_{^h0eUtEIgc0ZzH}&t{xK<H^r1?YIkxoTbZEFNbHgG;&
z*WMozjR?qZ&CWmqa;68S4sC|clVy*FEF(Sm(QB2NrH3`muVyIqjw>>Z^r-j;8gMoK
zD-~bCr&srz?@L|c^-(k?N{wy<{ixYh<nR`%C#T0H!73n$N7vF($vQs0ZiSg4{u^<I
z^#;94Hf&bf^`s})tw;v)e7fxeENk1nM06J&SQnfA*|h40ok~SM-Q93|Im2!oY1E=`
zxM8n?SkhZW-^^E8drW$pdzX-=Nx}-fZ?|qh;U{3{1H#n<PRXbD{OeT}@2DeP*dTa;
zb<;y0REAU*;fUZB3VuNw27?#aBzb{>h2JLPx*!bNuo$%*MVn61=oCZ}4ynwTvkOfT
zz)W0C(S-x7uoG%_$3VebSl}K;CPT<q`=?YfT=0$u0%mggtx1wOUHXO_2V<VWys$ak
zC1C)&c+xA{a1G<Kyhd?N{~O*}MQm4{Y7lF<g;A`JI}t|B81I8^0}{4eo&1re;X+Vu
zjow0o!m&HQFR4HX#qay-N6h0x3;f|q-C?9~t2tiTSV>`pq&V4leW-$<y&hZuo%sf?
z7=BS)4Z4&EpM1WzDa`N!llao>f-Zy*=4&lWiQ^&m_FgzC7RMJ&{B6kz+#eGyTs#Yx
zt}yLGVA}6^r=9s<^iQYZJ_MinAoQIHkm2c^FC!v=SP7C|8R3i<N0_&R@AXp!Z|r|n
zn^yAI%@C_0<;|d1LCmaL`!am~{g7xJB26UFIWr9B{?|-H!<HM`knK4+BWSX^Zs_wf
zxdf3XBeGg3sHHRmz|NCVtue9~JPgT*c?=GfjNUyN=GeQ?09MtKQM>f(i7JUb8Hrz=
zCIzu%)PM98ZOCME5V~tEhFFI*96rP8ztYb?S{W5S!&UrS9MOsBjE31Y^q89xdeM~K
z4ZN^%;xlr#%#JjeXUHd=d`8=VyY>9z6z-mk_Fp(9Gez1^X@)l{%;>cJKoyv7Z!8cw
zMf0o@6^=?#EYLl>u?N=$kbuwVbNfbs!Gbq8;EOBOj0MspLC8bZ_H||y80T%E=u(|O
z=M@CS(Qx8WxOZPAa0$i&sT0T=Mvq}?8mwNX2pIoQwmAZLdc6pE)nybvWymtsA;AoE
zRYqd$H|f`63>gY9e$Lzz<c@+}7<Cj9jAZU`IR?hJcmZrZNM3wti+f~MeoeTJ+}1D~
z&cf-AifUWzNbC#&I%M9p?v--w2tdfbb=g`t0K!M%(DUj3hBjWwgWHIAcE^7WiZ&Ot
zN!H1h$DC>fl9Go3?Ah$ODdd=*KNpp3_*@wWb6H`IR|KR34TV{Tu;6;`A9c|z3mXIQ
z2t(m~sF7C%nA;Cp>S1tjEkI7GNW(rzg4MF8cW$9W36I0<a6S}8M+}t)7Eu0K>2geA
z0byS~)%h9nymFx(7_687tX#%LK*QeYhJzhYzYhlzDk#j5@?~lh;BXE2%l?4R^!;k3
zpP|6ZP9QQY{Tx!9q=6NnApfJ~RrNx@XVg%HeoDTIs>;r5ehLKAQkyk=CbJyQ3rR6p
zbkI*iwHCCgp@I?;d@=~glbQ6Vi983iWTrHL%OyC1z`EecOxx0jbS<9DjLpB2j>VJd
z8GMO^Ad%@Q><xxu4vo)jZl<kXF+dfn4@-x@6xO!ZI|NOT&j*H$(wl~5z)ZCJu{MLN
zfH0<=K7+-07{Rx@Z`JBXs3lKNdS>sIQ#MiP^!dLjKFho}`cU1InRnq4rWgXpL1FMo
zI=nicIdu7v8irCuiTR>GcVV`MZj<h7*s;S#MH^NtRP2Q3A?+f7lWa5W)T65dNThhd
ze8#X5t2F!TVwYjF0x%1v!TJzIm@T`w%7JA6?OwHqoA2ga-^^tTZ`QayjDnvEh|Yum
zJcFkWy2ONGEhq|pB7macmJZQWrdrTN!zlkMR8Wo?jYPt#FNYh@Q&3}$wD}Hh3C7ie
zN?d;jzC91ChOwnw(n^R061Oh>O)P08m$Vj3c3#LAOIph%ZN!rO0~U%UZRC=+V#(oj
z_+CG1r>$I)E0!EP5-XPE$|awPB`2%<i6x)OCGEtLvxhH>CGCU~q*}w%#i9$9x4?(R
z!0mveiSkCA!=vcx!!v|(bJ;o&0#r?$u&_*yO1!@F18{?fi|`K-4t4=?9+i0eP!q8o
zms|pO6u>?4KKqSWk|me8#ga#h%ZVj!xx^!uJnfS#mU!fn24cypuJDCnG&&9Bl7?c*
zKNVBNl7@0gwpjAt(O<-pY`LTn+@Ek%x=Y*Y3!x~y5!~7eueO34i<NvItrsgbmMYQk
z76#6j0<LU>=9@@pa8r>!_~=BShoNaImoyVg!d@4MoSMlc&Bc-^|Jh<mbGf92SP~u8
zO(>D$mf#$*poafUvH%&bE3V>H(#3dO@zY>?C07@yELX~_A^vxGQ$teOB7Y>IWS6ry
zxxw<dT)X2*&u4Kp%z>L8i4OEEtZ)?MwKaX_6!tXYB{(c)fTEHFSIa&>_-e@~F(9SW
zm7CMQK1HALH5bZChCGq0Lx;JLKZQ9mkE`>ZC!`b}SC5>zr1XidJ_qVkTJj(&-IX6&
z%A@x;1V`RA_$w>qh7pYnZ|%Su5pRIZBL|X49sIbE|H$ZqpSa^IGAiMxwirnwZ1D<s
zP7BQ`K5<sN>HY-5&yNekyenG2ORj!L^5K^bTcko(x;LnhwToA%kWD+m!inSH9Yf$s
z1(%24XBw^Q*TJjfRJD$o;LKR81@j(0Vw9dcx%h=RwNeBFAS&R`acf|Hq*WAp!(6yK
zg3`c?5Ga+0fxmpGhN{^c6W}5a7nZp*0it+pXo5ZPLa|iGK8!DdWG{?c;^Y4Jg#8U(
zoqrxbf@H}5?K!JL-UU7-5%Y&z(ors$7t+ft?Y9tkKy&f}>&fyvGeHXNMJi8L;L2X4
zUV5@ZDsNRoVLc(6RW?Tyw&&2vS&>InTaK)1ou*?tiHtidcI9!bssPpeqmCMiAJ;(*
zSw?|7mD?05a!-$`AzRRCHIz<OmLQn+kRoB-=d#id3QLM?@I_$o@aM^D<S<C|(x^0h
zTSh{BR;&KD03*<2!<oCGx4O3--oGO&da}BF_B#nBXZ1`{Peb2L`$<-O)_|H2bm9$K
zvWASRqSsXQA<*Qk!XsE!8gy+6&5w5epxT~{pC3r73_t1SJ{2;p+Se+iIQwT6GAp60
z3YmAhB8jjibp{7Sfar?dEV<X8v>SHC+xL(@hSRK#h#_hCjXgK2IB#9^TLrS#uE0l9
zE!b_D61$AjXQjAXjp8Vc^u!6WFaZ^cJSmMvz9Of?lhRzTp0t!!V-KsTa^EMap^o+5
zkPw&B<$Q5@XxIl&ph)TYFJ#qUflqT0FRDB#{oX8ADMHG?Z{LzEJt;#|=8zENVQmAy
zQAQaXmtkRY%2@LSOcRjBq)ZsFo2<*FOx~SP0ZCG%q<DBzrspM*Rg+U@-X))2ds60n
zYbS|3DGMV8ll(m?i*J9chDt-1s-e|WhN+<q1DBBym$KF8Q8^^*eO%U^e?*dEa4Gw0
z<W)v=d1yG0uZJum=HPbNkBaZ0g)jydd4NN@LWs4}&z<t)jlRo-7*mRI!0DS#d^X<~
zpC+`d{j&G5q+#G60AYV^1D+gsDf<0;85}j?ZrpU`N>mlZNtz*g0DS*n!`|F?MQ7}a
ztuy@H20vko1#0l&+UuCwqqC4@l<6<KIBgO?MED{wfNYh2^V=P)D$tnTC;0>*Ij{{C
zXQk#aNK0X)6nAFT*QiBmqs3ZoD(q^=_iV}5@(dZYc&wqnX|bBYu>F863C<ev=gvUX
zba`d=;D?W<o)UBy_w1ZCX8ijQL@G?6*9%+CF$v^Ed#tsWqvKL(_&~)uYr>Vj;i?Wo
zg4F^D{zW?IWEf-yxveR8R*9Pmp%KsqKv4;2wdc{*5DQ5Ykm*=6V@^sepg`D9MA3;2
zmJfl=$$c_$%42Ox4^`=|HD|am#<Btk!nXN1D*BU_I{b1D8$O^*wsz@3z7FK9JywhJ
zkIf@*?Hl0}V1)cIaTd{q0=(SLzqlGeY^CC@1uqZz5Rk_@qV^T+HU(+*=p_&J#%|Ik
z9U))D9P%O3mrP%JM6H&b2T(E7)`OCeCsxeYl<=sFu!vc!e-j*!)B{v^el6kU4o=6H
zw4DUuy3{Eo$CBM}0RTOc?Tua0x@QFvS+fTgMtLZpmTBX&Y1PqK3$7SB1xVQ8wzc{k
zJE8(501y?hyDqj74!b2C01o{AB|9+t5>((9t?BT{yGF!U(p8{LJYKaV6CGVB`Aw+)
zsfyh&ZAHl0iJbwFPL=^-&u@JTzkek4O-vv$UGCjZFbBzUfY5X!No*Dqkh$|YY`VzP
zJ^tZ49hU4MUNZ52)vd1b3(t=qt%-Vp`IG3^<v**XBjX14T{Bp575TJ!stkS#iK_Ru
z2GrIsQyd8VK2m`I;${TDkkq~_gW8eA2K9EPmcI}lsL`y9Q5ASnE5`n#vZGXEvjc)7
zm4+J_@TpNN;5)}4mF&K_)asj$Ad%#05$H@)-;ya<d}`dz2Jn+jf_fp>0LeD))Vlir
ziB}ndZh}?-ib_1G^-`)~69zmzsr(GsN)zrY)fVj*%vw@yq3v|Ttso-L$&;Ej$V6JY
zC$-_SXKHRulS>76Bux!)<5F|xGQxae;|Qr#%Vvfcdq^gWmY8InsXZl*I5uFG)J|vT
z&>DER3!Re3%#+%EeI;-L5`^}Uu+sF&7*-bzB-R-&H9x4kNi|!R)FFmX(p-Q6JN%d9
zm{g#<=26SAs}rQm<CllkM(m_60>*!7x&~CZZA>fO9c=E=TIvW8vBi7ftz{3)IWV(s
z)THId&7fw8YX0xV<q0Z&(c^)*RlqYjI16018!q`_M7%*mPZ;M_l{SkTMBxDuXaa!Y
z@W-!P&Z;bEQ(1>ZT;Wi|+e_hSx2H5A2-$NF@(+N4;=2w`grpA~F&*8NOiVb`V}736
z30)$RX;!CKx%DLbU;n3Oc5&Wx!49yYWv?b4@mHFpA>9}*T5s-4R%K(|`3sh2`E|<y
z8sy*~jyr?Bf<nmS$6z<O$7Y|q^C~OsfyVTDmR~J2HrP7B{@edaup+z<n39cZK1CHv
z*mQ+QNqd0bPWlM>AkqmAawJu>R21#81@<ab#Rs<FEqln?$+ob%`APz(&}!tgKc#xe
z1M~t9V5=5TPuw2f*MNP%yaO82OUSh|#rW4&yD;8nzE@Jg*h^AGfp48Dhe+$@Z5H2O
zv`P|?K*jyAT528oB0#CbgF$M7S9(?&*%8Q!+76QsV#)T)+p<SbfuBespk|OQY=q1%
zjH*>b@OUy6iYMU!Klj1F7zGr>=vXls^9BOcW%QS%7#>@XRjO+PkF9Ubt0YyjEq@n;
zjYN+IzwyWV?F&jW{98*rQj%Y^vT>M3jaf+e8K7gvozZCF;SrH2#ZPKppIoU-Q*XVt
zA$F4Af~stB&fZEyJ!V!{cqS#)L{UL+u=@G$+lvWNlK%$~6|jp8Gehv(3?%l_;dvZt
zNAko7TlrOA3yuY6!HwK6+QfAW&qBBeu{JQ1JIQXYKFx<fnC(B22SMmD7~Ep+zO_xY
zH~1m(d(!xr!*$_>w~Ff6(T`Z*f(GK`I&gJ_5NES5R3s4oLXG<*AGT~mDVY+*U+)O%
z__*=&e_ZH8N@RM_LR>(E=OQpn&_4h8jYU=O`I1{uPrAoLgZMhaE;tQo0?|t;c(ncQ
zNGMsA`8Wb1PAoMORFzND)qohcH?DGNeuv+a2I)x)bn}v`BHQnSY6dTkH^C&syFStM
z0SxJLP)oTq?zBpK=6`Y)>`9BfRui~jZSiT<c*y@IQ;lMiqG%;o2iaX2#n%iOP0D0R
ztMj^r24Y8r6q#O{Wk(cdF930Ae1CCZC9f*<+h$fJG(jfRVWYZ@EE^~oxu@XMvZEj!
z4|=QkinL}FBxmDLa$3vU<S`$g)^>h!H5E}u;xHOEB2#F#O9`ZL;zQy|>uJ7-IdY*>
zeZOlZm~D>tWxdd;0r9=#jeT%0mR8^wS5?($;cd)cAuS)>sd4QHkX|-5{)^95PvO}q
zIh&)rG@t<?ec|_+VY52@MTj`h!q|fUheV=q_+w|nce+&`fSofH-YwyoM$E$U_mI64
zplR{4!g^|lw0!IVnxtCwdwe>g!lRt^5$aT?Esy6jM1m5#b6gOX5rniWistveh#@Z_
zO$Q%@W+L|3R)RU&5f)VJyciAL&-ND)gkbFHVF5-G`R)3B_z5L^crTUyL2f_TYiW@C
zF4LgY%FP<nt>@w#ONt8(GWUu$5%1xV5Pu#CiB&2C!av!w28-JOF~1x-g}i2cvky)Z
z<rWc}_q|}hC?hCq5<cf+*R&4}Gy)3Rj!Yl2b08b4KK$|rnEqz3=>sSh7{bdc<I|3`
z(q5quE@tqo9=AP|>w#k^0SerGVnpp!@cR(Hk!e9ytK5$w7<lZ=#wuXuxGS-<#@Ues
z6>qO~5%w{7%aHn1GpC9QN-8O>rh-z&WW!H65$qj%A!!lk#o1j;Ha0~{B7I&18K%9#
z!$X2$O6wee9($7uE$(AG2Iwsqdd|?dH3*I#dt38((tCOA9n!Qar)lr}Ur+dvCCmYN
z>^*d^$%@JLKE25!DBhl5)eb)=h1KKjgL5I{1cyBKVb6lF=n^T$$OGGBBY+6}16uka
zNyjv<Uu*-p>tOeQA)K9fyCe=*091YIu=^S!|AvJh)2>V+v*0NKfpGKr@^D;;Cj>Di
zzk<hy=e{^-TH5?XV<d@mbc|YDF&>@};#AC<JyrCo<(}P`vlf2vNU}?G1(2^}wi#fN
zBo|J0SHCZU6++a&z7vH;W1gfRfbfSJFM%1x5ccR&2v=nGsMgO{nn#exnYr6lNl)i%
zE+*5e_)Fh+ByE|!)&U#}&e?S9m@^v<0v0>4cmJEu5LEo1lNL!KoETp)Piw&IE;4%I
zUykvW`j0$)fAI8iTK28BwlA7k!6CwgL%K{j{IUP-I*PKQ<**LYMX5Z>?V#O9mQh4f
zjmP2p^0^d606p>zjsPbd3X-We!C!2LUow)k)cf2wJir{OfXL7smFGQb2YnXf50Rh8
z5nX=(xm<f3u|M5bw_5Z2plE^{<Tm}?IfZ~cj(U?hG9KU^$>j#x2`Y=jW`c*l@L>;G
zVnI0P#O@u?gh&ZBLT9sf`vjQ#x4=DvBm28Cq`<tR>C1Blf*tQ@c>q4VK(>(kbD`jT
zq!mhNw&Na?U<_Cj$&Rk=$>&cVN3Y_ZSO_4<*1x{01>P~}fiA||DDwP}Mg$2?t=kEa
zy`%;JiUmbWNzae;ee7b$*ORl4f?cqxUD2@<4)2BEACk-t(M>52t2>S`GyZ$2(ahD7
z;J3Slcb?_&s`Ku`mnI;~N{q!2vyu+O>MHe+`nWXarB%rb{=^l>&B9wmV<YL31l3)8
z3vwE9LD<c~C*h}&uolhRSE@pQJxvPh5hUz^nzQSZDMLqQsf_HWh!2=VXx{<{E2j<}
zvXPw5bzVs(D6toc;Wz+K7-KI_vNTkN0Htg~ynMrYLgh5>M%HFX=8p`2U?T<n=bzPm
zBgu&zJ!HzTuli*NBKwwZ{sBX{=^w+ZmPo-RO@r#p2bR~Oa1P4FP!crD?WF(i2X}6O
z$?>ws>3a+=QT;H8cLuh)7*0?@UQ=(glwjla7tXNe@S+3f#XF<YrX;fi8Wy2gL?q*!
z)%CI6kZ%wI6t8b^)_5_4)OwFIZqox&4#;V$I39!Ga1S!Gd1un@Vwb92Yk#|&fFPym
zb|=zfBs((?lIya^*`P5V^urKAO4Gs}SewWmoh`Bgj0AVy*(TVkPC;sy3;PaoI6B8Q
zhaX+ShSuZkssCQ(W1Rh>FE$~lAf0JpZcX!mcAe3&0<w2VA>y4wu1BHQ%RX}v3T_`j
zRA6zAxCp;WCuY1#Dj>}Em~H=qZ`}ZiVv!RDe+VNoX!ywwRUcktzj^?V>7kaWH?&3r
ziP`MTpvQp<h%{_=8LU^T(0ReH5Xj0^kr^+}9T!NZH!Y`NEtF}{Ck^0xQ>(M#o<;_t
zqG`iLVM+0kHdP4QRwJydO3_WbPABzNVdnkER0emrDMaNsd;VB|2HSokNl(rI-+|Mx
zXM2nz`^;WQJkXM)DSHM<+C;7Ez15jvw>PR<XYU8blH+84lzGLQ(txZTl8M+S&0eF=
z9EcGuOgCT%=UyzmL4Mu<3IB%kf!|G%<_sbK9)d4b$q3Tpbcz8R21qteOS-NLyjO)S
zG>-D=ew#wd5s)Q4F#VIS4e;r~&tNlvS4~b2gO{3wGf9t10^7uiAa$ucgcT%Iqc41G
zXpj`M3F5|C;i4IbEa`PC!56-;gLt6xq}Ln%$15ejNq~}tkIrH}<<rx2@Oz7Lo5+{E
z_TkghKZnhQj0(-Vo4<f8Fs!a8y;0k`SQsu)wJ^O8A*lHDHojjbDG++o2#VcqO9=dW
z6~+yIX6Yy#cabj>Aa&_gw7-`Q89d~&@ag?tN1`O<Xu9BPeIF@p34Ucs_^cT_aLj!k
z>4#+U^lA7>B#IeUvnCCzjuAM>^US9g?f4L;KuABv{2m&pWYvVZ;a&QKx|=l$goq|5
zFODaXuZ}cNB9WOkfA~EmT=nMk1Pj2C#D#6DKxFo+3W4&AzgkJ2yRpk_ftSH+@~h7M
zDn-E1QzX;+1jxj}Y1l1y;ANkTpl=wwg4CrIa!Qc5;=Wn%@hXK3t`PDl_HfiNQhNS)
z^}jH$7L48-LmK1B9EefKgNej5^Wxx0itGY^K7YFkx%B>X6>=^2A&Ho7AG+HId9fgA
zV+UzK?EQ%!l)N<X0Dy(VANM~~Kl0s2a3%=3S(EtmyCT@L!&VKbMDL9T>{ZqMNhI=i
zc&q9J!v7aLNs2aLw2+2p&>I&Th#Vb0!&l>uCLm9S;o?qmndLKrX0(IfDZ<q+BlPVN
z_)#JPimb6YM+H@DF}IZhq4a|s+LICU{5-j0Le^5;UX_>0sJ#|~0<wj~Z>GU7JYkKR
zGwQ>Q2afO=*4c3BPD0M`i9J=2YxeH0DyZR*uJCh77<WFSX`QmlDkx|7Cxh5FWSm(=
z)qXNW&SE|oGJeR_;WIkzjTFvxq|X-sC>C^YzBUNAdzdUPqtAn){`e{w?1DFgowbPr
zralIZfLl|juDFAYf~xPksi49`uUaY)=nXS^BD{dWv;yhU_>W2O+d#N>O&PI1ltgAE
zz(GAu!++y}Ycyi7FsEc|8-j*i$iNL8QETz{c=AIqdh-ppKBa93cQh9?lg@dNP;06f
z6Nswj4Zp*YRtx+*a$6jD7My+Jt}QmWM^T-`?bpCt0i29K^cGIHaM{hr%aY0L!&9F@
z<bYRV&*tV=BM|2N#ZR)Bn6j~O5F$AOwCqDh4ST(_U6@|M6M)eJ7BUphL*Tme_T%_;
zeCAQ#AEdx#nVkNErtNVQ+%=U^N-h!ldIQ{PKU;eaev=8Gx>tYSszo5oKkFgWo1Ajy
z!%@=7fxcNXwH$N@vqAK6f$|zlrtdeO=Kp0HR-H&B@_^i#K|$By%{iGt6j~Y<tb!s8
zMNtG~$*i&;(uFXGfc9%H4a2Mf7!wG&uuL}I*+Z$0vai77*INB5Spk90lbOKHf}jGo
zkj$hfkKp&42q>k==gk!ewOdA+({_>j7(O#&7i^x$nw~;CnaJhIZ1i^`S<#Z&JRZ)p
zrMLk30XT<qXSUuC@j1-8n5U#m{)$N)1|5Nic<oNb*1^?5=t`$fgRo5w${2!=#dZ(e
zgbj_DZNc{b3=U-F{3CSC4JjCTR}SOV;Yc15q6R?%p+YH)?9er^*^w(FwJUlG#{_V=
z2%xg`j2(5n8;MMK15p4$GxZci3pm0Te?N|N7tHKAkb13(=@)zhAunE!T^s{ZHGwQ!
z4beG)teOMorv$S8Pk17aBOzN?v05wyfZmyRULl<TyMO3RRa=KWFZvRE%*TGhKBgV~
z87RyzTK1&rP<4e29TC6?pZy6wej>^M6CW}hvabQXQ2mQwG{M4tUzamAB5{6k*p`x!
zxT8lt;QD?zW*Lr;`|aa&H3DJo*MW!EIWz&Xk4lT86a<~Rf+am2Abh<CcX{lqK2?1b
zLe%Cz5%B3Hyv@Y_PL2i>#GD6G6qmN$U851`l*Py8`wWblgaU3otE7U0PbE|!Adf5T
zJshMEX6lN9M?C};?~1Mtr-vl_8bQ-+1O$0K5k+NGc+0uyW3pnz1BpFft1?_XF3U~0
ztj3$PxcIBWvVnuV%NEVlR9Xnm1$PKX6)tB!oDh++xDM=ZMnK7~hPiXS-$sMUr^XgT
zLb7Ibaro;KjTO7knHrQRlt6M7+p=&<OO@qYT)DYhbP)R)<`*l;(XI|%;Y)oIf))bE
zW$k>(ol0clSX@1zE=--=C$uZiqZ0c3xFAA9f0DP8AE`bfaSi^)7NE2Pwb3K0_V5~0
z&iFw}Gjdqt(L@pqJI)BZR6H$)owyH_8Atf3ZAX&U$QG|FijrGHjAwP(-4zFz`E_^9
zgpW(eN{lYz;X|Ayw}mg6$S|tAbj-QoWP>Xk2V)JQ@0h?3e5@_~bZOjlEDik@2+oe#
zF#^;B!^G<BzS`OFgHX7Q9=si&P9n!@SFP?vWJQ2aTqc|>ooArvWZ`=yqA!?VjC?`3
z?O`;o2GASk!XvnsfnP-!A#J5m7cW1AZ$lEujcGg0L?#b==Noe*i9AdSiNyz%eLMs<
zP<Z-J^m9&Y*1<Z4H}-cEc$I-uvF|Fvhx7^L!~G=|1woD?OFQ2ZPbB;BS$-EFB*pW8
z%vpgxg-S<+dLh*zoR<40Kw)`%;m3|JpJU02JOObDcJz*JRP%MoS=D+-3$AzDlNGx@
zSw~dnvuZws6AYXmpB4Wle9%pX;F~HC3nW;^KYdASr4Nxw47tDI1WYCs1hj=sY@~wH
z^^lw+QlX{42)<yJmF4N%MDYOPoQGt=_MSZd5m+|+@NHuys|E!p@HyUAL*R8IzMew}
z4eld%TU;xJR;b>Q_Rm&9T{<18Vl0woR-o#c312%U6MFjY_`V_@js<7K+6C9g1L7fL
zL>-W24H<ttL{=$*W#LcoBur+Bly$Tl6cJCWVaG3qj~(F%GwB}uzJe+qm{#LPAwk6!
zH;3g-u7}<X!rSs$T!%0PL=DdSZG8_CDX9mC0&+z}v*dr>;b)*Q^JP|iARleQ4=bSa
zp0!o`S_ndRV;)#FUX|Ut32qt*WLIc3{O**%9#ViJEc1(NwCg@s3k$tB?1RY%kRAUL
zR-@WO<TZ;+X<o5Rc*-U1b%I@;D0nNtrL>wfEEEqEV6?fE&ooEjbU-;X62Oir=ZFVu
z0@&rU&^#!y7|jV_FHLPCw*)}=Ii~+Q(bNH2#Wp=<;QSZx<tIq!m2-my@}Um$lh@+3
zn2UCk;jkxVY~7mJiX^l@VQ8|Df`s3*rA$8VRCg4zfd(&ASDyK3Bk|~6;5cV~yg?;7
zqy$wfudclK!7bromo&^!*^^QlxfVArczYa0n^qUw3K2()l1tezrofFiBgW;Xt$|zB
zxfIDMJ0D<7g?9GU`caB|<aMDZq}it&+*1&Q*b2|hAV3VVNFhSPkB_?;D2<pnBh4Ww
zGJoRpyP!gnRRd!B<>w_$aDkD!|JtFv#@savt7!WD#wTxuO;>J;$xS%j&BIaZ%P7;`
zW@L5>YWCrl20~&KR+s<F6-|D6*z}^}>`0YxrZ;7~J@{ZEZttxxB5(|io0VE_g=1T(
zuL7ix+fT-G$<}i7un&^}5oaxLX5hUer7y!$1FWH!UM1r#1h<0Q^->+=2tEC_7hWK+
zs5)=0Ff&r`0OYMPQ{bds&YS`$-D*y_0|)TvN24$?;a8Z}z<vjtCxK_et+`cEL(;Qo
z0j$6Ht-stlS~(#7g|nvoDW=*8%`1u_{2-5g#2bhv;6q3%KVZ#_`(z9`YlAhrgJu5W
zlEzt^`i&FPqOjh1tU04Uhht|qfwk5B3B8c6goQ!qa30RO<QyG<EY>dlD(KKlBOHZv
zp^dkMA(V_AeUb`d>b~q-@+_XS=HD;MK{8?{=dl+21L^VP<d3lI#H2xbK6>T2KzThv
zU+)4B{zXlAkB+D6n7(X0?sLRnk_2k<)3*EuVn{thD)_Zes2P_6FlN?H__8p3(GaJb
zpLlYqny#cH#NXr&)3oHkcJ!t~?iKJeuV_ybM^C0T2gRfYsp}|k2Pd@g^%X0sD@=y$
zGa!~UZEKeyyy#PD2J9+KyRO~m<w{T$b!z|0k}MoU9~>^DOozYdEBFj)vVk<=cx<l?
z6b+}TVrGiSfH@T*#4Aev4dQxsn)pOodL|1Pdww^(I+C+=5OO&mQs!}lxnYGJrfS&l
z^el=(5=vG9HTj1h?L``+{CNq)?60IVz63MV^HZWj!-Qa7hmO>txB`3A%f4$3UlNeT
zKt`8Jr7VtzHu2mcK2<-$Qc;!A<KOip;l1E4mFleJQp;a)2{KE=hYTaNVlDW3Yj;Ug
z(6R_8H^w&b-4J<OCNv(kPILp3+yEx0RzHBH2%yykb}Xi^A?AhJ5=((FZa=(U6%bi1
zkXJ~pYj_M^p;Xvo2tx^8gR%6e#sDW%Jx53^t_8pel89zSfPrDmxm26EbReRWv{8^Z
zJ!pD+Rb?(UYi!pcDv(cYxEi!a&WsT%H?`Z?PdMh37Q0lHJ*jP0&&JO1#8(`AdwntK
zMfucDzr&3mo<qc?cHg4=4DpjxD7dMx<umnZAinO$rU}xB!o=4^7|5p%35HV+nJMTS
zGyFIBX|rFn<{tPdv}x3;`@+OabB8o@{F--=>4PN=C4O0ZpzzI1*?S?fX=@q>6Thp(
z7a!b)xeRoGcVA<gbytiBF<)hxf2FJiK3>3%U-Y5^c2t8JSa$HS*B8o~L4mEViYc#%
zj1Hk74h>sfRme+}#sI1tH#Mz9B+#(i*TKi6dOnO6gH<3g?fKtD!E0c>PdGSrD;zOQ
z^O3zUB0PFv;U^D@fBw2bIh=?;y<rbTY0|QZs{Q(GZvyHk#-F{o2p%c+!~%EIRlcX-
z(j+B?n&CI!4pR+~>CVef-Wu=^zr0Uwc1@3;KN2hhV`h5ZI!WyuO|KWUtD|ax{kH(V
zF(8Wu>JHgNZM9OQ2mTWv-liJ^ckDnV$NaploL^U86%?2U57m20N+eVa-VGUK@=sg=
z1c^lTRbSV&Mb7*-%u9rV2l$~SNF)m3i_kaF^g<$$5<Q@h(-sp{s;n%cjGWE<zsJH0
zZAl-XF^jEEF+3=Tk9qeZWVZyqCw72N8~5WMcThY+r2KHU)KSx&Xv8F=6#A6j7>=Fs
z)F955wKqUm(4-j<I+{I!4E%Uovmp3rmUIv%@M_g8Sw|wde|0zDh{x8^_zK)5Hmu3E
zE)%4mMU{HrW5eF@NK)x(xWK({-II~3<f{B1AXUtmg9+-f4gN0%9F#OdLf&~B|8(2%
zC26pGR(*zd)I`|L<0nhP%``jiclbpg7-ad>-88ASts^cFXgELhem(NNsj2w0=KBzp
zBo8_wgV$=adJmVpisA>{`tSvBzmchR^NW?O2D>PzEAhQFXwI~B^lD)jBxwX-?8<N9
z31V+dP<GuCxE<{+4KJeEY&vHmXqfG%Ptou~+t^!LX%PF}_h~^3F)zpd!0nGvvS)zG
ze7HV#jEA@%J6W3{NZ6BG#*`yivuB$>36_-rDkWT~U4It(I4U6)TedBp6x4LR+Zka=
zlb)GEUH*?N@IeCnc+m8qt*gI0j@}sQ@qci`hFwIWNEfnTpRdjn+_p49s0XjBm5(9>
zF}*u+Vv&j=|8Z<ZI09@d4L&F&m!_+A9K90P=V6<gG{2v22%3UX!Y?j0h7(_yC-6A3
z2EciA*z%xMxgkOWm`Vpz4Y2sAb`*SC<ZXDhis!&s(yFDw;}>#+%csSrzV(;KJji_!
zrMIy)jRXD6ecZVHr`7p4-Xs$W-LmWzx+On3N5+@N4{2J7NVIXL*%GRNmx0XNK9aEs
zl+K^vw2y?cG9clRgtD2)2xA}VH^qdC&EUVdBz#&+3#2aK^|-XQi%VOhA(K=>sM#@V
zqfw!QtQRT>MDDU|jIz7|9hcTKe&%*mSz65mu<x30)sKqdXP1&7mq2dW`x_nwK_o-?
z;iadL;~<kEZ5rLZBu?%G0L&NNA!LL|60<dSO51Z@uL#-@(ig4-%WF*2-&&6$;RK(j
zED<PRnE8@SBt#9(Q7zsH3qx1H=QA+}jHni`hAdCwXPK5y>a4{DWLI4s6-|<?ubL2N
zgkO7-!;J7PhX%`{i5AB0oa9!#KZ*^bXm%eJR$EE2f%Z)Y{}S_<q!9;<KiVx`^~U(;
z%>5CBOs7XatAqp0Z+GCkTXPA)O_$bF!Z{u8v94vlCgYx4Z;~b;(Q%8vH};IL(!b!=
zaLfpac7H-Pw45FUa)v+Id>L03)SZ__fAm0@WZZzUZ;s?t!DVIN_s4`sDrVPo8Px`=
ziJKb~6hO8Kq#31RPmYuc*T5}Am4aGo%ePk;1HlKLv}3V{+9spl+?HDp%36Y+m#`7_
zFyjXaoc5|Q<I^b`en$seuOZE7JA*BiKnTCFR0V!R0MD3#G^1<q=@7Evgt~CAj>T<4
z)ugp>M}Sx5>?sqk3EKeSi;d#q&f6V_F*}C~GzxyC$nIJNi+evw=YXHb-r&i<5GhE}
zC<?~m(O8o!uwp~YQV{I@!gbE5$7Z~5@MBBy@a1{<aVsUrvv<g}#;DrpqFqNuhspLH
z{^a(MxA)11S5Go4^yUHXbn|23e1Uv73He5!k5TS-gh3hhH~M8LsS`+FMjqW*PZU*N
z3eYLSxPjshEDk+IR<r?55txY&9_YYB;2MFHaq6f~l+je2cAzD$py;X$Qtf7qI`IV#
zqw4c*9SFY%7*lcyoR#VlU}+o3_`}n2*cFpai3Gx|IS6S*<g(0e{HzsWitM(aWt=fj
znqp`!XxHkYI?`VGeW&5uRORr9=1@)~nO4Lf-E=~Vr@YSS=iBfpR!OyiGkd0lw#oqV
zPOoV5`MPBEXTG$8e0|7X>#B>9YXKYn)~R1q@y<Q%=aK&Ni{;3W{qw6Q!REYNEM1*_
zS_{5AjE|V<<-`xdfu`^gW_;S&w|?i8pUZ%0H(C1Ms>R#?gWr?I=Noj1bI^@<&PHwo
z`#=-t@O@`#h)*qghC79JIs)8#VRc47BqWVEGAc*#Wb`c+%q%!Zc*w?yh=b&#k={Bg
zFM`ZvJS7KyUMaP|7T&}YDDQ|p10PGq33*4&6{?WJQRm$ULDwW#4NX`a^=82D4PZx4
zLc7V~@HJ*>CIR6bw%Yl^icg5=oc0LIq5?XPBkN!YY{iJ4WiNeJg7*v^wY{R5rvJcm
z4DcaR*n&<e(G!4UYlDcMcpSNB_o;S0j*chbEfU^ei=%57xVKW%^_mUo&^R6Z#!_mA
z5$~JFG3c*F;C_TCNY)DE|JzyO(d-M!JA^M_i&pinh${wC_OYb_3SR_FIM=zV+z<k$
zggvQEWXG6_12TmCDk&BOD$}<Ix(~-y31Radi3d5@if1b6n$THA$1aTpE5$R3*cHF*
zPf`+hkQ8elU<(jBje{hJ&EfgVmNBU5mo!A}3ES7-gp)JakrSCfds-$`z<b3Xs5=+)
z1L!FR#JET1e@><}u|HLVY(^r9>eO*;wE)SOb3Nfm6@Cp}QamK>g}G#N?B%Z@x0>kU
z4X5h&r`WsEb5n3G{G;GsRf&_&>fgxlvVl1d8Q=(p=p*RW=M!||?<fhL1ltV2e(9gk
z0vHeS*H_Wxe5n1&JqhpB>SF829tzo%)AtmF-(=2AU^^43u+h%oD;hm0Bjzo5XILBT
zRfxbV%7qOb%prW!&Eu>d0M0`;CxNcUTOXDk(1^%TircXUJ~=F(Aq#W~5zUi~1Elp)
zfRYaMj+e&}5R21V0N>HV^aMc8X@4N>hv63vlqKGoc^u{%?<)MnQVV#gL_&?1!1G<a
z(PU=}_-djYYXJZ1kdNexzrzp&Y4<s-kJy>0AV}xLxK_v<@WTpc&roMwq6zqoB@_In
z4JpWg)hC;aU6sur9UVJ|+?fRvF6JKz7AmX^@M}qsnRE?qx5%H^5TqEhH&nP$!3>q1
zFg&-sJd#MKCqL2IiPReYtG@zO>;25Ii3xHgv~&jP+1WRSg%Us3#4NZ3J`_emQWvC-
zi+gTeg%1R3ak(%2&?#<KtD8|AAp*PM+H0GFpl=qyOU!MxAcvLs4X0h_-@*P>^6$W#
z*?$URK`aDAu^>dhhg+&1*&G{kF<fZ?Np*5oXTnU`vqN&pUz*}CB)^SQen<s1SN0Ze
z5Xo?Wxt<T%GuU}J(3x*<$3_&TkiZj(`ytbvgb4p<>pH-rs+#tu0HG5~2oNAFuy^Un
z0(+CqCfQB0S$YXoiWKP}U7CUjNGGC^A|gtWCQU$)BJBgD7Xc~KMMR{7G!g!H&dt3$
z=jQ*O$L|TVbILtuW=@-T#(ulL9zh9HAGAFZ(WRApt%`^@L;**`loxYU$WLGNXxXg<
zlhL<5b1y$=Hp2hzM;_ooSF0Hc;q_YVo*N=`v;mlbuPUOoA;nTp+|vZ8u%1{0!+wCj
zJqHN+y#@V)gmQmFe<2t>U{g)M=~#}U)qiTqhd}j?LG|(XAjqvZ{AqdtOYs7wEb$0j
zU&c}!yoi#R9oamh-TT6SCE&dfj>zU{)gI-7U1+FFZUihuY=sinz|74>cw=!n7h8E`
zq*hI1y?`FoylOoy4tdU~=C#WBwK7eOGTBkhYmXVN{gNZ9d7N*j_KSgN*29`7=KG)a
ziyU?zz4rFoto_o$Xh#dXZ%uEld2Sd{_aj<?zhTFG8bAJ_Z7IVk<UT^wH?RIk`=zz<
zOLoZp)&)ChzZjQM;abRjYrD+|o&oQWwtA6>w{Uvsd<fALLB-!%6A|sua*vn8v|8{F
zkRgK=22-g0MV8pUuVMjk(4u0B#Rx9*gO7v&B_(DncHo3*TG14}Mgf)~pj0hvgwRx~
z{zF6>ni{qBH;o_v$o@zQhyi&Yb769@eXvg_6Pg+P<Lhb(egY5QbpHZR>PbnpP`O`c
z56_OWKkdM;s2`$YMA?THsxy7v!CYTwCdHi9Pj-b+=XG$i4Fr{1@aY?N{Llg~s*B?h
zPTDw=kY^e?v+UPNj7Viy)&0Xn`Tq6>6J^uNb0*5RFZ(bG?TQKosk<xQWkjlczjBXJ
z$g1?S*blWab^qA>TPDh>p|e;ys_9(tMHA)X+op)h>b3p-bsk6tA*8G~k;?)bHZnuv
zbjHC`)jyTPAsOJQg?2GB#@L~K>yt`CN;yq^K6;9&-~Uyeq4z+$H}IzfZzNv>ebY|s
zaY~*%+UqqVsww#|Vs+;*B7aJe&t}UT6n{zyOMAICBz>x8jyIlCzRf^0SH)-D%p`lv
zPi9i}bv?|a*g2oeBqV%#iX)JG-QZ7g&C4s_=K51SW%tTO{V8el_AnAu2iGW$l=>6|
z3p*KoK<M2X2DV9U`Gv)ilCc9o8P*J)f$%uqCh`(54fl13dixm>dQ*^wqC*8L(%ESz
zPLdD@Bijq$I@xfl)*0q>!2XopcgL~jFnj)#0W%Nj_3CpxwBl<sX~h0GMj{CwJ+%On
z4Wf+8^`(h2d2CUcVxOVP7ZmEJjZVozXPvd^C%R9QU`F<NcGE4vf~5$o!m&x}lD8|%
zFG2Pd6<O?CvTL0~)YZRjVeMrvCd!6d@KfZq#ctko9gi0>TtnTSXMp@Y>aN!aH^Q~Z
zy8jBa&GeCn-~NI%N@I2WZNwJk<?N?^lXo@hxsMUwOk*MS2lB>wsmE$<MbIN9fJi^6
z*B&9#8{Y;he<lM(f}b>7Pquq<u=S1=PnYY00(9!igLS629QDb+2)oZar@r|9f{F6_
z&`?GpNlFb#_?O9uAmy1;SSG2d`B(8=OyE*ei$vgI27NVlO#am3D;LYQA}+O5xO_?I
zPc6GAOqOQkbXtS3t8!IJodq(NKegKG6LPm4sWEPB4VWXf=zg6is<~)<i&Cs8;<{Rn
zgdnZcPf?62J}TuWV9j|?)Kvc%+~IN(;8HIU4I^ME#8aic83JCGY$pJcn0bOrsj030
z*OE~4xx^^J?1QM`sM?*po8y+sn%e2R;xK6eB$Mb;w_*n(B$7Y1*W24z`{JYfU7aU?
zi$8Uc^<$ZYlum0gjp&3nXOJUh)DsilNcnIad=xbFPxckz`2UcXl~dFyC#Uj_I+pbv
z!Pd-g;jSbry!!c<9d&ikDpS9hi>OtSm@cUDy@|4DO)*BHm=ACOUG}BC1+lNX&(by0
zx2#`PFR#>3Wz$uJwU&Cm{rz&R=cGxy8_!{lQ9b*PdWuV>tcR*&ZD4PrRPOk3gl>s!
zXJDiOtg)U}fNRngbY0m&E{Xq~=QfR(S9$_C0YQ3c4<5|Hps74neC_aM)0o|KT#>t|
z-d+LEQ9g>+`|rW>nT*ksfk=wQxzrcs-~uU8{yR~ZQAn23LOLIj1;?M3=jli@slcBV
z7>N!N07!e&!hiV_rc^%Yt7#=eel$amq9TB~#D@p$M_RNpR+eiut#U*TcvjW&$PH=~
zBp<`HAhqVKs&Y}FrT%!Abr4?$wA3{mds)E5>|?LHGQ6;i8U?3kXpRUI$cFSkleeco
zt$xSjdLyLuz|^FtH4QBzFYlnzFKSwg59KRJG^M7seH(rN_?Znvhu-t$uTj%F|BUn{
z1{WRmZw9H|JHC)jog=OHK|E|Bbe6#?rnG-_CS$}!H%=?+;5qN;eb3%Rqz&)<J0p=a
zzCYnZCLg38W6K$7fU<RZ!mgVpIh*q6fLuz={61W!C|NxR>gj~C>zP}3iCm8||Icqq
zO0Xn#;lyuc9(8H+FXWmltXzrAQhN*8N3;qKq;6E!9sv{x!(wQf^@k6UK2m<!h~4Ih
zSu8=O=#zKeycZrQO3zsE{oPl)y5197>H(Kg4y_y!N!xr~`9TwDl1`+ol9iuE_Vk0v
za=)$T@8k3cXF?P+I;mcsX+&MqhDrH-4!k`$Pla2qzT~qZ5v_Mdibn#j?XeHtTi-Q*
zo%Np<IgS;|%TfsW$lFj}--)gqppaDgLcTr**ka?1>}y28M=gji>kIoWtXcq2q&*R+
z1=r&t*;q40@uEr+6E@NXU&J7U6S!GES5=0D^p!q(P%f(a%J+dbpnHbSsJ=?;5hb0I
z{Jtu8_nXwnS93Zdpl~kL=a{s#qC|4|oc{t)E{AbZeeN<(D@c5PpErLAeS1UN56ld3
zQjKqkn<zci9*Fcqy02lwnX(XwL1-5G4;usuIgglnEl0u$ABEWGwcYY0SR(m-9m6=R
zgbub)>Mq@JYUSgs`g+vIbrrA8;p?*v_-Ht}bE@Arpw2Jm@ftD-kJ_9|^^G_RpLv4>
zNw$t|gd0tH8?Sz}__m4i@!uFDE{)cy)#Omiq*zhG_RKc&y}z2}-euaG&pG#vT$eIG
z-T*CStI0PHZbeJLCi_yPhvOYkR#t)^Ha^ABHtU+fc$=0t8tVFu=h?zaAZeK1&82a0
z)hY{xyLxRcPf{<ZmM2MU1GPL!*4kY}<U?nC!%2%Q{N54s56D!79DpH5e9P&J%OG5G
z4(7M=$mw)Qg5o<SU)6;WUoI-`a^*lQ71muh=p=zfvS*%8WJU7F_X|Pqxwtsv2QJW1
zNcyXx7O}zho^PlC9qHFXqU}*T6<K0{l&V`&uF(-c{(amvn9l0)la3UVJL8O>K4NNa
z>Nb1p^vBP<|5)a8#LxQbRAGKp7vDUu(i4%_Lhp8XOFZDi2YJEWq7t-6FfXw$C}tX6
zZ~XGl3ko@whhz1GM&W!c#dohSMtBaUpw9SBcPj~}T7Ap~-?rGLIv=eO$Z=%bxg(!I
zhzUNN2|yF{|Gkv)QFQ-+(0>QI^_LSI*^Zpha^C0-K?9v9yADEdH3POoYu1??*x93U
zL$+-f{^%y)W%>xwB6Q_IS6Q{JH(CL?jj)SS(OW-$BP9i*2JY6!K8!bMdsM0|L6rhx
zC-5KYv&&UXd+t{rzVu<F;#`&$vec-qTrqfiGwP?|bmjeOqbzQKN7WR_EgtOC=_-D?
zlF0X>%PPqNaEK09sefSDVfT!?WK@eBN?(!BBid(=X~>~8dyfD!>BA+uX?NnKTw<%f
z_JkN!eL6%(V{RgvzRXv5Rf7N`hgJ)bDk=V1iogMio<bTx%+8_o;l^Z>gr>Vv<GzE_
zE_jTE!SAZK_6d5fKPI7dhpS0pEdV-aw7N111_f;`L3Qdc*WrGs$d2IHHu=_z%SK*H
zoT~$@o+RR~E`zibGi*eFjM}i$Y!{raJ~a^26D{czfNlX9bvLFeCu;6Mw)cW2h+av&
zBjZK{#wFXJkEZh-z9}Hl<7(L@NDIW$Ixz#AI(7^V&%kaMImV}M7S9OAq=47<Nr4;)
z2y51MY@76roz`;fT(wt@Es|}1-<-IiZ}z6=lDqhAmwI9zb@8A(@KHgw75lU-Jo-nI
zLalk#Qct-A`6${=+$$;@I$aP~$GW`$_=gfK**0I7!%0&O+W{93po2hh?w))aVNeXf
z5PkIisvapH4QSTG<#B3&UU0OO?f55M6KTGTu4Cmx;O|pA>d4Ee?fg&;fuS=}jhE{|
zrJw`s)lvO@SaGPYu00w~UHvO}B__Yr!MiR^%ycm&+QXAtr`dR^PfJ^6+oim0hx;>p
zgC-%Qi3t|}S=|C_t0S;cW8svBA<>j5yoH8QPRKW~3CST|@(t}$6AE2L(jkKvHF^_@
z#n!|!A!8T(36UN8vd;h`k}7>q7%IITkQ@mW_TteKW1y?6rUI&MRw5f1a5@vJ{x3=(
zJjK&EnF|1VoC&qU8SWG20z~@3kx<)*`&TXJhCW27COtu&dmk19EbN=ywGi5fll%$Z
z2+FXl&kRZ;x6;HS_#nL?h3Ua#Z2e6LA;LjXYC@AV_{kcz(ZRHz#g?(6h`<uFhkbye
z)-+)^<Y+`qXrCYcq()&u>U42wn2FSF=O&<}j4{Ki0%T<GCYVKoh@wD4mDMnVdc<!*
z91<Ct#H|iV)9`cqa{ypISdEw%=t{u4e6%)B`1R{zja}3vJooiUnCRdJ1{JDP*X+}G
zgPO^(XYP|DdfKvXYd{<>)pM_Ea6x^_P?i0wXDm_(5f)K4J25p71InGGEUVIAm;_;m
zAqAij-S*v@9Jn6a+8d4hrq5S4u17Ru6bO9kmWQ1Mnpgi+v}@h@34A9_*^rdI`w)ec
z7gY{^-Z>;dA+JdsV2*AeBoEVl<>XUSb|mMoi_h?qXwvpuq6W3n#fE5C4j!|bKEU?-
z3(bF-jhpS(^c*Nq<<2uWUl^z()TTacKNx#?-9k|PPrr7jQ2qL%23pB~ox(j@uRb>l
zx-A`n3c{BM6v-Vrp)Ej7jO1|V4L?)Nl;Kfz7aUA@D5hObcleGvl;B1(HtvW79JY9U
zaqiNy^?fthfS!<Yclk&SW2DbMi1dTQT`>X=1v&g%9B%tVImiJ%$LX%|c{w+Iwm##6
z=qP5d%g0&}od*l$Sj*iB;|`fQ)7{?o3AockU)UJ=cHu@_CN-Ff!#gKA+)X18LW5n*
zp<%zfWvj2{O_amk_A%@yvsC1=IW@QH?pO{-T%JA3>FzS6wSa6fxC4?cZFo;MK@NAH
zx^PUAiAcBfKeo-w4yG|A1Q+o=yV<ml%LADhzO;nA5~?3ejc0a%j3#_g#$HU1HesUL
zr;}H^0mUG+6RhTxzvYoe8@9|&1BD;BE{mWkS^W{D3<C)LC6mw#^Z7-d?2LP2K4B9;
zq#x9;B0AzR-|#meuOt}Hh2s(S7(W{pz`FDcgy`M@WRotY^nu?koz503YI<FDM4FX&
zHlFIjCWLr?yo0#QymI9yH<Gq-ify-Rw($JoLDu)3fR`ZWQV#8$URkCbZ;ezjoX2+B
zp$(dDSLt$da<J{(R#`yNG3%w?@-=>Vb9lAFnd15tTZB}p{ZCV7h1k0xJ+bJ^+YS4}
zO|p$wo>tyeP^w6IdGv(M-V6C{jgeN~Oo*vk3PY$-AnC}p6k9I0(yJ{)L#c^jXELh<
zMw%2Nv0%m!{bHT0L2oJ=zFef_%{7@W;V|zY(httW5_`j>C?BXHJ+btkFY#!B-vb(&
zSU$xTVIoyZ0boMrs#5-5brY#3h4PfS9J}G-%SlMGH1fGXT<b%CemE1|stlT@NBFo<
zHPLf)uGKOs6l<t4I?hC&f4<~2iy9n>4XVJgF$Y|#X?{FP@)SuxLdB&;NpLBDVw)wM
z<rGZL#EuOG&V*k*00y-jQJVSJsEIx5P$DI1{Q9hol<{4_K)DcVUFI4ZY2xxHj`-&j
zeLA&GgEG3$U`5Keq>Sr>=ONT&h>vY@$1&nSAvA~7AIKZ$^w$d8{6P#rq#x9oFMhx-
zj_dTSStbV=WnLL1MdA3J$OUi&<^<c~X^}n1VCgqAq)p4N<DvkII%iZ?RWjk2l<%L9
z3%B>F&z4tZ(=-6o4U`nU;Gn15@|5S873?E%t+w;=TyX@^cXVW4_V(@&D>r(u{?#Hf
z<>*HU5h!)+ms_|Fktk<3KzumB%XYDzCIq~-tFI2k+WQzzY3P9Z$H#+AD6GGZnVM7Y
z?cX7vA(h8tVFRTOJUa--Z;A412y(m_6w>*mpq{1mMUZqJAffc6++L&vr*~yNxgx0a
zi!&*I#RU?ifs`$&@OUjH4^t{Nsdx%5!VSm~<<}!Gn50rJZGq(yo>Z<1f=L)i9Mq{M
zS+|-HOTa%>9K&i9T-B~eR1Y*FIuipQZjvNs4&svPtYb-#z~)GbpN7X|XotS(7iE(V
z6cNj&E=#n&;)*P7b-SWcE8e7fPwv2<4r>?t4o6bstFZt4P=l9c1eC}aH@7WyNnb%k
z*W1*-BPV)7!ln9`<$Z!9sY_nO;ggAgK^2kjWBp0JhumO&p*=GEbo*D?TSe-&KWT8c
z_vOPXk}m!G73(p?&-VTywsevK0A5BJJ1k#udU+Ca4E+a9OS^P8y0Ssntc-KYxV1PF
zN=b?`(^s*53u#%_I0WeBNE~HuO1l~oMV)`ChP)yw3)>_7x>V}h82|@zifzT-6C$31
zzA+=mJv<w&=~U6Qnc5IB*VL)a!|{wPb$r{Yi6%YU)fT%g-k`Gg*yp8X%E4QM6{#NO
z*dkNM)l+qUmv1etXTQVqoGBZXda>s@QwOe|M-)lk0qY-mbL5y(|N3+U8#{6aK$!UZ
zv505Siz<(&5=CqlXsUsVQJxplz|DH*4bZfNOaCh(1z;pSN)FCgOjrLBoW_|PW)bLc
z4!=gmrAELJa@b9Ja`+4cXpv}Ya>-JyE1O7V7B6v`NYP$|+vJr2?sOWVML49&nOx;N
z4S}T_19Gt55v(THv;e^(m#&=!pfV@<ljF)xFdZ3^-LdPKwulk%%!DP7m;1P6-#*#k
zsL2hMA>{$DAL*9f0HSP==xGi&AT169n`02kR3x`OgKYvQIg>jcTP4zN>G?vyhjdFl
z^|KrlQIzaC51HwBNg$oPGi#VggB}}WNlO55H0jC1I!~D_JO#yy421_ZJKxf3YZa5m
zD<7^zSab=0GyYcuw3RSIlgr+S4DgUrA`@L^QN%%)3Vya1DNH5Gocl||B#Jt}w@rRR
zvoEYBYqI+7F95Vi`;wLSKahEpb!D+F=S`^_*MBK1n{`V&+<W29m9yD*)HSWodlsyc
z6B=26uAEaP4<9YdG(KA;PxQl<jMuK5{u<#zCCd3vuh)_WQ@xztM>b~44I9rsMHcpU
zWIv}=kNUtJs@nuob^u<KC&Ma<v|74H0cb>bzKF__ACsxZ*A9f3#IMHQ8IY!YfE|Kl
z?Dvsk>EtN37?B)$3U>OXaDWT<T%?7b@S(@70cv<XEL-p~kLa)$X0UUJGN7JF@T$qO
z(-YN598`0$bW5tILeb9U0#%5%D!)b;7TzP(Q*~Rn{3cRNxlvK}0gd^R?5VRCdM1~2
zjY8y8nUr)F$wg#R>QMyakV*C0AiJ$hYP7U}c@wF5Mvg2>t;=EKBNuGf%~XAyr*oVs
z@T#Xr8AO5L<@}z$)w}DVma`3lX8@A(WOI?KBb86OXUJdhiXn~G5e1;qFMiL+>&WF{
z;JGone$SX)m?LA?LqairbXXAyKch@~f-HeNOOS2aqkjEN+k0hZ86@oDT*~J+OxcC3
zUtB_5DI5Yh+DKjSu0!^~RTdY*GrLsP@>WaAOBCDc>!-W%eIdGT+YqyKDADwdD*@S`
z=2kYJN2nsHy6q>&rb-ms?zf!ci}bA`jl{kYZ~&6Z9a@MuQJi8sK2nQT!^@raOl&G~
zspnqrGkF7E8nRrrUiNESWzQnzW+afLyfORjrg|Anc7;J+9E4zV@3p%p0<DWh5l|+j
zHlRkzqcw+0o6Y*O6r@bRkH+Cp`S(b(rU42h0x+f;Z*VP$SR)2tiPX>=+7Fs3!<E9e
z0vvA0j^HZT7~#w1g5j^;mh(0_y%C)^jl?|hq-v@+%CoD2sc3~LAfx5lDu0M*A-o%^
zw`x=D6J%1Y=t?!Df=+Mk39H7EZ0Kh-(cQR~p5jtbzc;bSU-DCp>h%u3&`PRJ^`>{A
zv{U*q8Fj^Z8+JXC9S2=gPQSN#?G$;d@AtMYR*0#aDA(>McBlshDV9#a%_S~W9@(B2
zxcF#efyvk6toI}!SifLx`o-1(U{-7G!D^6YeJ-bW;MCVrC<0XO^bV_gXd>4U5RqVM
zm!-LsV97e>Dja^`T4rP%5~jfo6_+TJ8Xbt0DbtQ2*bwK5nc2v-Ey(0aW1Tfv#4_hA
zx_w?(UA!@ZXir@*7k<lmb$QKpfL)v%8Dm*v$*l*vppGrO2%E(lRaYgLGq->Lq92A{
zpEB}r0fc$ex|S8Bg37i<NDaWNQg&BG%w>tPzow}<<xt0N-T)7|`~X^XY;j5E2Soim
zH457!sj72%&6Qv5hCC1w&$T1-^vaE?N35Edo1eS@boEFGskzA4O8E8KdJtXZ@7gQ@
z6GpU1Y8`S~u-;#WgnPlE*(rOpp|(A#@~cQhr(f@*x7O$50cVr<Pxk*}7=dIbC3q`d
zp$!ZW1&N#-jATm%u`M;If-(Q~>6Hz9s-P5^gQq~5sYKon5=^AhvA9i;xypA$5?3wd
zkfv;ol#2ghgJ#;Kr`VkrT!Eq_K<k2Hs&ATfFgQd;0jMdlU*YM8w*tt}D;e@c7&Tna
zyS~OYpL41yo{E50%cQh#V1hUah@lU29R87ZDIVUuoX?+<@xR;boRWR|Z&SXwoOmfN
zrTx70T$+(E#DX#}>>FGF5|QgdDE4rYM8tIKFdG7+odfhWQcOhe$Jj;y8Ds4F)RX~p
zuu~eUtBc?oTIEPf6W53%a2+-Zk_!@!JfmkKdpgJ2DC6?uf>5GNo(T6uqk7Vf8HpDw
zN<8YP8KX@5@>$DSq6R87uO<%fykd31s^QFLfJa@@ttYc9;e<xTCD4j0uw}et?CNWO
z3+%f@RW{UJ)!mR<YI5^-WGCST)$IkInws353!c)3;i6Le|ETGeN-2lmL4a7Pp5xua
z<a(4-*O2+y;0bRB0Y>bnbJJ#*%cdF=kGM9<C4er;7Kpt+R)Wad2)ce9NtDg|fIoeQ
z>Pqk+`yD$|YwGWVP1rL5#S+*m{1bFL*)nXraqC4~FE+m|R}}fWK<_{?NR1~o#Jh7_
zQ1H{-5++7X%`<;q2Z<Dynt#1%xlAn*wG2lOE`+JY*VU^emGh^TiXJKNL!7B)f4)3|
zb{OKqQ!^2O4Q(8y8dHhB#ic4P`JnGit+rvzd$c_2`#G=yHq-!ufipEn^{A<JULeDx
zOp0%h6NgMn{2va^GAZSMo?5&gj#U2y5e!IL@lzXFUe%CF`cs?5@7B?UnE49B03*gq
z58TipXBnDgJ&K8~_OJ&f)YNuobAX1_)J}a^QWetc)NZBlMrWXW1gTfIj203pF16oH
zwtRxgn>xr|8-8Oj0CL&)HVy3(Ad#4idWjRa0jr@WMJV8hlW}2a5W!}h5Q5|*@-bMQ
za`q@YV-r{AcetN1N$cke`!ts7Qor~LfGI<As1plnAu--CU6zQlXanx~j2@6D3XIpX
zg%^_|hw0bI#J1{bW|aUNQP#sz$CyAOZ2H3#1!nu$5l!SWyIVZ>$j$FN<yLqt_Cv9z
z=fUG=j#;y7F%+GGR-~S;z8{9XUfzJVODq4mZFm)fIOsN>E@ucjbf9G$-k@^rB%&vA
zEK$tOxP_}NroEbSd+p7j0Gk$RQ@Q^>($?{^%9G(8dP)@aMWuI5)A`?-N6avisHKJU
zSXEpC)7aDUOsybM)U*Qs;JuzBZq&5!3s{C_Qpvoy7m!I&Q7rs~XfL`t{4xxt@QlSl
zz##!R6tyG}l!nARt!m{YsQs=$WGzv==9hrP4cEm8BuAR#Z$ztLw^Jbc)6_rVY{nJZ
zpXRRik-YhjPV=OElq)#YkW<k@+QFgefes2%eXJGPBnU#pi0Ap#w5COc>qd5p4TQ6*
zEyyh<7K-9?FUq&=Rw$5i2$b}+4g-^M%gaGOfD9dr3WV1a<+{J~GR?%)`}pl-Lx>2g
z(K*E0--ZzQ@CA^o8~jyGn?&-b4e#*-^AUySSl^!t?@M{riyVu`F^;=YC+tVcP`;en
zro1RJoy@eJNRc{%lrfo`a{vpJtanFb2Z4h=kh0EAz?PfWugt&OXteQ7U{M#&=!|~q
zlT3w{cKRSeF0^tj6BuGydjXdNyk7N(kITvOuWVC4i<Nkkop-JW76Yng9}=2mvlvQG
z2fegIYhOpu%<c%rqAYFfloR!ezs)C|>N)+ohc9v@bE%3s|4%N2t=tm`R!VG_XZI)^
z$UsDt-{+sM8367O<yJDnbs1TTK(XGzRu*RnneAZ;ZjB`j&_8db^bSyHC%Yun`m#Jc
zJ>~gSUO!3;2q*<AMEpTtNactS(~jO3cKvm%F;yg^zJfo7hFQwZ<iUv?zM?e{H4(3B
zx*Z3n-xo1_w!GY{zS5`RPdJis0V*``b%fkPr7e04(d?asugVjMwlN@D@N%W*XDl6q
zXwWgE9TRs!QiHgcBuEaQy8>Pr@twN3(J)cem?BH{U5z0J2v`=~;s{K?7NAN<f3A!v
z+HC;kR%_VYQ;Q1%8c==B@?i^N0B{7UB_dqPAK7+i5h-M)>g!l&Wi?Z=E`3cYlsvv3
zO=Fq{g~(SJs;|%PZ%SHP7c^dNX>rBQb$|;u#Jnd?-;f!>OG%UUgQpmh5vN+@f<ZBQ
zn2oy}oq@Y`4!==9T5%F)tcku`gJ`NBKR65rCft-6TUXoE*oh)oH1kGKGCR(bb0XQY
zQlBp8Jt4`Tb9qheKpH8EE`Stt^OKl_5Z5<P-!5(RmHMzWd=5rLpHO01S!GY)@Joa>
zBhnM(Z&|<9d}XmYdbqw?0(DcW&fLtR{m+M3s*2P~T6}Zd_tfd~Q6bAZBu#2KLqiPc
zpN^r7i*KgLYYuWNeKt9me<#?GTd82_Qbc5Bo$(!;X#W3<=!@_2$IVe@q>&@OXCd5K
zF)1J)IJm9%3)39t+3W%^v}AoQQ(KPs_ZkYTU<?|`LHwwF$UuVrGX-_Vf9Oi;LdEq-
z2d6)N{Mdh3>*A9po!nD7$9GO2Gp~cGZ9s<pSuU^DfDA20%WMr0-I?bA*vmYe3!Y>O
z5DR;Hh>KsM;-+4of5buzMg;0FURL4VAvYFytgN28(F`|I;@3A3!4%oJ126P1%Zftt
zgc~e4BVa{|Fg}Pj2VEbOaK`W4J9&yh#adyl(^a^x+4fp~B|lPQo*|0114F_jL<VTq
zBWK~>2M2%Drd<kvSmb2zyCJOw#zmh`Dt_j6hd>WdG0`sk%@X@)H0zaP7*f-Ec%yw3
z({ix`x82&I0h{#sMSaTMrYxQz2<oHqr{zZj`!hl!>qAa`c$F^v^Nj;5`F<7(a=I*Q
zXNp+jJhrDRSKXYbFIV2h9i$6X3TlZVFH}cVV2mMTqk^k={)kX^aa^RO-4e97km@S+
zF9LygZK)3!$&stv5<pAjrO4r`IA4x$2F^H_-Q78aOTX%>z7bnNj&gFkV*YlPp*huG
z#Zl7fs=Ho;p$Qq{3rNZTG-q(}18pPf=r@M8q>p8nXi-tB|4=h7G2#pAZ9<x6JoOuh
zA#$zR5ggN`#I@BHWTB=4?2}bj#$??0@Dxd^t4$Gj`f`%f)!}L#2{tA=&}H}m5z&=t
zgWuJC_d$7i2ZpG&3}O_8`#(M>#)cJky57t4V|CLfIb9=@mMfe{a1$gW8of2Lgha;a
z6>2-Kj;#?VlfX@Eqv25Wwum-$d$T$wKJ}BLKjYBMUBpUe^$<uWeaNWf+{7MY7<p~;
z2R>+Ms?GMz!HJUPrn2AmlqV82b;YTNuxGj@C9bu>FLA@4JyC{;&`r{Y?kpZYWW-hn
zAQ`7?^DP-Bhf0*~-wzJtP9?(bIV^l6HM76gIDsf&`fNK~IR~7{c6?S24_w=+y;|Bk
zHVDf3Q4pnWdOUk-;c}C8QO1X4TbtiU1EGXlCnF~j7-Rm*zqw;D-9<^brMsTXV&-`V
zAD-QAo;Rc~=o}K+jTuDS%g%#ENqycRa%zI5F`kNzW=RSYa!s_6iRAt>&V+o!<?K}8
zj7unV6Jo7fF;TXds`ZYw;Yf(=ij|1DoP$$Ih?;BVqX3$kP~i};JI2?F3T<EJmO71v
z$TBxiTtd}@a5oWO7m$V7Q*E_MYUxo#`$84~dI5l_A+~5TctG2w#i$D&;F!T8$P;J@
zD&tnI(gKLi07w+|A9lHVh;h+n-?S6?CCrc`q5e<!T=T#*sjrz~w(vR=GS>b-S&v$8
zyfBbPMwcR5da;jdU#e132|46X=yZF#yp2#3y6tCy{==K#3Knkwy<1{SZKORyw;c)n
zE8$*>-P?<?9#UT9+A>}pNkN8Rx?Dg44k;gOXb?!`MgslO51$D<Hj_wYqB^mZRLnMY
zqfIPNx@1tv%)|EW{8OpHtOo^<--&5{?A&_`&{@;v`d6=T$}_N9RN104eZ-@X7-8C5
z0HLEMEUWoEpK->Z=(*Vo$a(;ZHfq_u^ns>I);`LKr`ot>Y8&25x}cgJ60_y$nbj0J
zKL8J+3U;p679jSS%HAW>^T}KX=iRQvrJqV3-Lh^mZ-!_mUo9zbrv3WeDuHlh-M0Uh
zD&ITWt{h(?p}VNE-`}JUGF7JD$|}Rqq~NmN`4123N2H7j>ccL0JLgv#_NU+C_M2HX
z<=>Bhm+qlY8;O(K()Gk@w8z2Aes}1UK`5!4CBc`s)KUQg(T7YB3y#(7gZ`BuI^5xV
zb4ab~j__P9Vw`70+0yg1#9TrkNfLVE63Jb@Tu){J0(%L%u5ee3(q1N6bE@0^4DLle
znYts>(w72-6p8Fjf#)Z;Bl3E23G<`6oyUh3kuW=|J7F@O{?Qdy(AyO!`kwkYiq8A?
zWdxv+FaqMk8_fKn0B!JDt4?>*C{sd0BwBu&+v#rEK6eVAXVjp&+rGf-rO^_JFrXnF
zE8(4h1B+C5mroWHGj+22mi5t*Jz4Zv)!irITp4@M=K2v;biDt;neR}u%xA&r9+FpH
zHb@SKugaXo`v;ox!AxLFFgAf>@Yrh_o?4d*D*162El;C9OGKOU&?c-8qbZp^8im_?
zzNM4s5*X3Lvxe>{lPmbPp4AG1p@EAE_0l5P32}j3(9t!bjJ8(lRZvR{r<|^D?)TD#
zZ3{`57~6NN*gi#D-fim~!L7_CH=bWAr)W}teAG`qCD?xQE^1EYm}Rx?_T0=c)n(iF
z>o{qPNWDF@Z;eRS#lAp2-u^GyPS{V!%f5`ZbGtPRE^AV~GysuPxcV#C|Bx@{Y=3su
zvKz5t%H6zhneU}<52#NMx4%40edlxfw3@sIf=_*UY6BB?D*0yW4H1@JFA0hBCx$vr
zxL)9jep@LS1Eg4Li*>V?&^lwMK+h71;j3TbZfZS+v&kjW&yqVzo!$v~Ew>0@bhv>O
zHk(8|vGl#0llj<_W+j%dhfE&5b+sm}0Uf(4)z{Fvtix(zmC98E@%KgHnt4VAapUDp
zbo|^KfxM>&?mY#c`XSx{<g`fcB;YPN8pxUGIjx<#nF{(7eT{#E#buTm@S+$*0l*GL
z?=+fF5}Rtviavv)*%m$){9aJntUw?l<7+{3Bz9~LGy|H@XBtFjVwcrgRx-ZdN$ioJ
zrEk+^k}kr5r|t8@jX<6P(aHcXl1CWdMltdLARJmw!xgd~Iub|xiz|6qSd`HNtyPRc
zh4k3R4ZIL|wjgnu+<m=R3iZ80_MIe#VMgfbKpq7c1EmfSE4G<$v}{3o$5DrM*8D;F
z$@$!X`cTF5D#VG+n?CJCTd?t}xB}vZ7k>(G4P4{s(?S(4yCss&8RJMhRG6(*RX_Y#
zJV|pjkNW-VXZmfMW@MC2pH`JtZQHg&yTralmj>#~&gUA)g!M()+dndpREfNS(t>OU
z+sM%osO-^6&H8ZZ2Tl3q-qMPEsFkz3XV#Di7n{K1_R$wEDswG(e^Db50SM|J)2ici
zps#}Dmw`YGf1Sb=2{$_Gy(5q1OB3bsL`3u9LFAvA5?t6`ja(}5@w)#NqzkB{cU4_n
z4U<3_7n5@P1#DP5`LN9*?yB=w=~39&M{3KmnpAiSl)-=*k=!R0ucvJmbpgmuy%bZ*
zI}X+cZ}3LGAi-WP=EQJr5lQ-!th<nTi&yJUQmU+wFa3~y>DGf15|=Y6#&sl~YGX?0
zPpY$NB#N?Kj6W&<)4^;c(WWCQ`8b?iaTMf0D1TDgh97a@(S;O@$iDRQXOz|FQ<QCd
z6M~C2bOQjvMY?W(QpV(;<cCIQQk(eVsnkOQ9wV|h**Y}0FXW;nhM`NL3GxT3N!?4p
z?}?8Lk}!=NR?9@{Uvqijtr}H1lLq&R7I0~{VNsKY2O%)4@x2hl%I_clEVfx}oxbfX
z6Y{^4Ns;Uy7P25>J)+x_c)Wl7xQKJ#SA@5()6WYAOBqY-*bla9(d{7@*uWsVJ)HN#
zQ=q=hEwK|GokRE;j#AE!iXJ;<a+dZ>s;-UUX($6P^vtHcwO`VVUnnv<e#x2~q5a}B
zeo5DUnOhG49%?7u_{FdNGXHmv_KV;6B|Ad;!Y=P>ztl5+sV~Yzf17nU2)FowIO#<i
z*ey7N#jH4VH@^ir2~5HI5t)8X_i(MUhDK$Lv<_^Dq6j>wt&#By#q7uDY#vSVH1SJg
z;}?Y5q+hmOsHpwY#Q3GD_RFrfr)s|#uO`Av3el|hp2i(;Go3#I@%dv9KK&8Q=q~=D
z?JY%oWpwx0a(Mbv(;3DuEkpy>Q^=l1KNxpj5eTScJ^Q`5@eBl45`p?JzT01`rIk?&
z1?oq%{Hs^`YQN+N)c;4}V%jflj51oF{@B0fbk}|{BK3#ArG4~$^^Nw6v8fGjr~UGH
zW`g#M5wM@|QqJeaXK1@xv8M)v21NQn{qGQT->|EMNm^v_CkMB+LaW(+z>yr58x{dj
zIvK%JAOmSX-t~zMlV%2yJ1WbBx$q~KjE<4(^Cy>CQQb_6_LpWPdYOdbuXJGnBa+QY
zuJS#CU>d!n8ybWpubF!iBMQFSUm%>P!6!&@70a7RZWRwzoGUKbV|r^v)~LfH^aoA-
zGaIa_DVOsnH<jWWiUwQ!g7~Psc4UkC?Yx=P@eG7q=IZ+1|74Py+;bruxB2)xlHc_s
zmIO;cF4`RQ;vIc;z=D>Ip~8wLV6<XV0~jiQ@~DjnFKDzatkLX{*bmpO2J+>cMF#DR
zzgU1t3oX`@t8X(=G9%w(6naa8ukvSy_T;no_p`l+I_IB-@-2cof5079l4@TVd)h?#
z_S`)aW#v;uQ!^x(O0Bd0XQFKU(Ir!?TRLOMWx_S=NVqQd$hv1q4liQ$=c*56F7@!K
zWpeH6i9s(+l+$b9H&M>dz9dtummA?eL-x8>Z&dGRYVCIUL2^0uLCPGRf=Sk(R3F4i
zIT!%O5%d?;L<9wGWy1esxSX#&(-v6*P%3P=EEhuko{%EHFu5TAVeEVIoSm9m8Q@zK
zNM-By6zq<GuZ93Y0v(?4aavF|83Pp2^^DA@dZJojJ1BEiDEU<8@_THQeVMo5_f*}D
zsCov8E-=;wsWFwzfx$g>4h>{{=$z_tO@TiaZ`0vPdW<uR?5^SWq@FIMtC6Pj4o|&~
z@X;~%uF<MeGRfg--WJ}{j7Uco^sjZLCyYqC>S@=TcCospCHD!~vd*4Qu;8>27$~jj
zI8P6&NzFZd9VQ5i-!ow2eZ4kFLeYVE27>Ypxxau8F-8Uk;BqPqOu=O^CUoR2mRL}0
z%j+4lZ#lfj@XiBH;{{b2KjFu43DcuYdbyyOeITU4xTmpBdyaL{bUiS$0)i-WFp&EB
z-!<f$2kRH)hh{3bU<hu3q;iXk$ICqG@(#On+1JEbU45&QOtEfIu_UtgwD&$`Gal>$
z)l=k8tn1s)ikJZ0o>+Hx5;27&+P)9r^(wcc9$L0t)?VfKSj5?qzTmVUq0x<+DBpBi
zko`PDBN;TPq;hElB2P)>uI+lxzMQ^bk;Q(qoP0xMzuiiIqsH_DWF^E&xz}0DzY(b!
zNSvaB#PnMqZ9Gq5X!%hF?Z-Z=Um1eVK2JMytN;G8gb_)byq4Oy+2lAUzc+NS$*0-x
z4ci5HyCLQz`QCyp#>ynsTa?m78+BpnKwMbAH=;)clh$~nd=JfKD_9X2!6+-bR(WDd
zWPn7NW++3|R(ONve12~&+g~^U>Y|RK4sY#g@aT|Vx&7X_cAe#psNTegN2N@)c}ILC
zbNRjL?_dYV8}NG@4)T~u&0RJ#sdeNlMxv*ms9?3-o~w)~zO?hNJIYGki1YTuHKEod
zL?Hs0oOEx$u!6#;+Asv5YU!HJS*!y;g&$;2c!hUZ0s>fp(YU7edPnV_BAY>4bjSQ*
zx`D8cPr-7=gq;L?QU>0SB!JMg)2^@pMe~KU&&-e&LY*}tk4#bK^@9JeRMUd5f!3BN
zi+$&0$P(hXK)u-=XEs1(l^1TCQqlDmGq!2dCPb&<JnFU;$*d|Ggx#?SK*crLy1x$W
zglrY8hu)C`Y|`q5C%t1U)<*{#AQgu_IyF`#;Nf+u=L*+lgF(n3tQi-3|7&Xc+Arc9
zt`()_U<i%~{VdL#vo>n53LR$+1P|qIQvQzDyt4Ik2u;}i)yQIl9}NqyJgN0MLZYb8
zC%@Ls4s39C)UE$i#N9Irl9Z+d@5KEGNQNl+Q}PtOsEet#`1n)u-x?>2H}W!lHNZ?N
zQS_0SR9gMkOe){?n3+^5_@zuzQ^--p)UWE>CzzBtC3f*5RuB=$ffe(oID_*sDn1j5
znZCVcCV8qLdlxqVaVcp_M+KEc%zk4q)Rg)kBcKx>A0VufFIF^>G7k2VA!YuQHkEtG
z*SG$Z_6v*ZEt38Nhoh!+IwDd<8tM-s{g9s0tt&#Y@HIe8SML`<tKfH|hmMp13l0Y(
zOrk_pQ-;<;CplwW%7|Z>MTHz$N6*HNh^=5GTjPrEst`a3k^W4cQH8B&q?|`W)EQ~2
zEZOR(ZS5w?tkp+MlzDYbAr{mH>rHt?)FpjO$fcAOG2Lu|F46LgBk1Z|#bq<5Zb;}#
zR|TCZ33v9kWAmPFa$V~7GS_5^vOE7%`Gf8I?=VfKF*)2js%)SGG$zOUe#NwlD5w4m
zkt?>JLuNHY&ne%Ma%u2|@-(Bmj)O*Y>-F52LFPoI^<Me2Vao~u>=Sk5PR;!_B#QIF
zj-_z9K_!8Y{wGhQ+!OW1Pq8vZd3_f7B#cs!EPHAQLSlhp2o?}ki*80qBu8rgA7Q@O
zo}8```-dVIlNBgxxpeVONSwk+z*X6PX3h{ak??#dd-O;-i4VA{Er`&-i>j%L2QCLP
zsoECAU*#l!YD}|elg_2qc{5DcIn9`<sqtMRW2Ay=YT`)*TjF)8sVN7G%OroQe`+nJ
zL8OnVjdCNZ8ZQV;Rq{C9Op%rY4+K2b$q}{rZXZPLhjy3d<}oRGdTOVETM;A=JZv($
zmCKohsn2b_p=>*y+V9Sv=C2)86K-|9E`REK+ZVHfBv|iT5N8!kh7>6uW_B~9sqzBB
zjp#!X+my@Zf|=hVkP+umKVP;}UToDb7XK{^q`IK)moi0JwAGwUY1uMUTk5L+-Zq)9
z^_!mO3$z~I3hVH$+_9Vfo{!Up>_wq$pM+=(Qb%{cwMJLjY!%!`FTfJdA$5$*qaOb)
zQ|~(Fn{q8FryZ?@M~klLpcNf1f>%4w?KUM`B;#@EC~lwlcEWxQNIOnYZYJ4cB`}or
z_75UtwnS9!j{}GT%^4GEeKH!pp>mg%7geiUB`)>9-zG9657Bm{g}f_HjeLbv)53!1
zCQ4W$e_DZ82pS`Eg<k^(*?>f$Hh)^l!h4v^k?y2LS<A_=EPq<G15ssoUH-JnRtg}<
zbit8UwHj`Km}eB-kRqR2TFq~6m`ghzhRLM?q`GU$`r=4)$D%@$YNvU|!l%Oc2)fZk
z+|sn;unGoId|Cb8H}#^V?*Qx|15+gOaBzhOwde?({E;A~#SGjPg`IN-lsm00f-FkN
zCN-_YFdUswig9&5Gq#|K)V=rgd;yY{^Hk}58Zj_=(YUn!)#WMjrwv}5m)T-`NL<?R
zevFCg!pZFYPnwmI@I}_KRT1#0YKTNsCmbnaS`VkZamXUAWbQ*)GIYxjO(kn6(y4Qb
zb*@*yY$VB_|F~*7iA!1d`DZfVN?qE0hsngO+;Pg({@Sab*A3J|H`$1F^20O}49mVP
zNwyQ#osV!bkk1s#zGPsnwVspC1EZuI`e9`{S#t4#xXT4i&`&g(Edna=4g8r<L|!t0
zP2_lwqsE1hN2LP9a36fb@j7yO{%qX&VvRT0$zc4x=ws8@-SPpr&UutO9~UnuQy$iv
z9WPV<dAp@sro5~Sizn6d`Z*4R28A@&7xDwb;DHnnPG8uqab{A%9SsU9Bb)Lh@4liA
zJm~R~4qwD*>_T-EvbK=L`buAz6de4jp2QmMD_^HLhTAX(*oy+Y;_y}4i3@ioyQG%B
zDlf}2W1wZ-Rcg*fj(OfZvM*)9eV3E`J~j7#xi;13wm}^^m+JFIEU1}HBE1KU2)UQu
zT2I-&jomzmMMvSb9nlsWw$U(Fx*UjsY*zRepM+mZ_qCjG5FQI0)1>;^?wgliA|dxu
z@fPg!#20rNREG_YsJ}-myu8YF_4)aEJ`-tx2NCaOt|3`PlTD-%=ix?ca6t-7jg|w&
zD<7=|(hwYmhN~Yx-C)w3sVeRrC7#T8R?5qhJ*z&8TtwT%*&)_BH{jI=)VEZ0e%jZj
zW%8T<@->iomX_=zSFf(D^_fX|){F*poY$<Z-v#I)r>L849=$ERy4va@-;yIfedweh
zK&9|5o@-PFv_Z?bBz^>ZYL!(0dDx8m;+xf&_5UPcYWa=kLd{qKp(-}8qUpsQ$(C9c
zlV#Hx-{sDP7~<3Y88GwC_?{(-7tB$(U&Li|;ejiL6*m<IcIqu$z00uzo$;eiJrcM8
z)(ny@dD`oXU-lj}ethN?CWdhABS(YyNoR3&8PHtZy*n+@(?8B?6)Nx8o$)jObqbF<
z<_O@7pY?r?v2e!Ei;EWEA$`<njXr0IS@3VUvz8z&)sX%ZDM<X1#Hy?hVwjeHtqqg(
zQLDdLC+n6oetmSN+1K0|zd1<rc#|60miUuC#<Vnuj7tYwx{Wc$(vY2T$-0-GZ*!~;
zMGjmo7>av-1Cv7r|Hx$wui?D`itS{74IIKQ`t4^P$bxOV@M2g4qh-`UtKO4f+m(wK
zCCNg4)*D@Mv}1cfa&3Y~*R6eH?YsuCmb^PJKaup$rv5#u{5y^rjTp)H?4gEZ(}$KC
zdDTex-5cvWO^eI&!#;h)G#PTba;0`4kI`KGP0N*cMKw%|;lTow0YHkbLMinmKW&;;
zSMkRd38f=)ap7x9=hYHK>HQSU<@T%+D!_<9Pc4Fn0rr@BbAr>}KpqT1tiH8bQ$8Gm
z81t~W7&cZXAXIy_#Abp>YX;CxPM0fK^AQ$QNC$}78JMPBP0vwrYGV!bz$$jQ>TSo-
zjH9Q}2i4Ui3R1-JP+nI?W+HaFvT*xdZA#$%mb(zCt`2`<W68@pU0pt?F5n>gd$IV=
z?ms_}&`g5ZC;qjBWdhOf>i^=Ttm$#C_X@K41e3!xG7T?Id}ohM5bhU7@7ki<UPuT8
z$u`cVfdF(PL9~eo;>5=bG-c`@cwide0gC;TNQ70>-KD5l)^QDxr7Kdld)?gB2Eq+W
zA84=^ncuEz=onK9sBexRlTb2L<+uH0=oiseT$?WZn^=9ewRtp*fuKPkigpukPs)bA
z!Q!P@&><4Y;X^5xoSW|*V*c^jL$Q5xKS|cnn7aF`&GMpW+h4b}1YV^s9j+cNXuM0u
zztpnCFq(SmAl_mOou!iJ$4(HqF{azf<(5d7#?egH-zUJn!Jp2+E>Y3HN@*w?eYlBs
zH$6SUG;_9x7d3b*@5s~20Od*@dD%nGA_4<v=^PT5U}=fvi|H<sE=|YjNlu28Z?r6J
zB)kcQ?!*zEL-RM*?2(#KED;+p<1++bWG{I@K}5!-pRfy-`6`^y@U;3+fzO{{`{t;Q
zjnbL`TI#rtrX$M$NK|@4t+GqCD_}8JkONS)G)%SMYKtR5zyymPsY?n8)S5nGg6K|i
z3vd=AIug9rYUObH34n8GlLaqd-=|2sU?6rx`TGAGA$-*J=@P^yO>-`M2^l|>fadC&
z1wJ*Q^%g|9N2iT*f-|9gIn8Tds;|@Y9M;m2(CrBBY?uWOZz3M-mELb5W&rP`H=%#E
z!gv~#&6=7pq%!4p(%m3Q&W8W41zKlTL-_#Lh!PCS`q4HVNK67hG4ZxYdZ2fkYMZ)c
zlVs!RY8(y)nZMM;$y%2^V$6D~1!LAlfM|1{l+NL)yC4`KBn+3af3`3BP2UOAUZMvK
z+Oj&2O3^V>7YWd`)Jt17na!1L?eiSiZ0p8dI8MR`&&UQuo!Rp0k?0KTpmXPjwNb$m
zBud$P3V<#HK!k$I!LP$WVc)7A-Emkp)#@+7W#nCn_1E<{QOjeb{8k^4u8g|rT^O7G
zD`&7LVTO$MBzS+jkxPWp=Y~MJH5V^n7z|_Vl)J%=!X=9BVJ{80qX&7RFL?T$2_9zu
zcM?0YkQloyy<j?eF!x-iJ2dkS%{{jg$h}kn@ut}7g~D;}g5(0Hj}RzGy>wWU8(o$}
z8xiRUW7~tPio5h8ErF1j6*3AvsWas(Wfmd<5DE>O0HXFoMe7IA#t+$s%WePfNm+&|
z8juUtQFYf?h{rV)H1yKpc9g3^QM61@Bj>N>a!ZU(cfyRZ0(GJ55cz`RqR88a5+LbS
zl4}ASS$v0a+Bb;e;~UJLF4i3O@yNbph2s~@pI#iC4tL8gIMvJhb>v@q14WmK>F$nI
zbL0Jsw*!#WEG+yosryb$BPYeV`*;zyQ8!r>jRSGS`kz27NY19ZhZIKsH-kj(b3kSd
zU;j(t03M3oi}A%D%vn?>vZr2S9vuJ2Zpa&qcN~;9MAQCp&n2N;dTmplY3LvkbrW-k
zf@<c_$LxGf!;JgKtWkFg+IzOsMS{>#$`{2)i7<V-NdS%Lwy!G4TSZjrT=>Za_z&V&
zqch5~#>fJ~De8CY^E0JGF=bucuO%fO+r}$ej0ar|z-9aKxrQ>;*BYYzl)h5h#DZqs
zosNK^*cbHD)q<MXcM-8zjBZeT7li#hboiLO;48<wAk3n{Mg>oMEM)=|lDtJ0>$w9W
z03IJ?_0oISOjiB+-zfsJq`SIPb$|BSYl4g2EnHeax0!XcKioY#gjcRSb?nL==mjdW
zy*#g3UtQ8cQ{T*tW8VWY2SUnCZZjOZml$@fn=Km;rRlLVvEbXnbZPd6c8a~<55`-!
zGckNa%K-8f=Abvs0sc!*EOGvGmXSxR$B|h235FhUcd!`B?@uh>_=RclOsv!t87erJ
zBe6<#EXeXn&5>BMpzxarC=tdVmzj>E08$$0AbhBrsD2ET7biIq-9DT~<QkEJ=>qaQ
z@Rrp?UkkU~8E0aH<T!!XV+jt_#HJ+?ewi2bC$?z#J&U3tM!d~hx`3AkpktdVAnD==
zE})|}Odm#DEM33_v4^*xxSP-=TzpucZAj6{TSfk*dPq?&lZIB#S4;YQHF0DRV%i#9
zbmNYw_M?Y2iIEa6DdUD=i2|FUvg+i1zv=OvXkP&MlXFJCHJUTIkYxx0h#~>gr@2<)
z(@uD`=_bLPwdg?)`Z8Uf>24Gkl=Bo^uc4IDjIv-0!ucB%T9a{vUOY$J`ZKY%ExWg<
zAK#8rE30Cj4mQ!0^|=ty%&3qQV$+-{Y_%oIwi38L%FDa4%Yt-nyp*zcC_KD4*2;FU
zV~3v9ntnK?9vq#K0}N&T<q2{|K~tsb&YrlPSEAT1w$yUEv5!=)g&|#zfg~fpFC<L)
zW2PyElI^ea2gKo*7rl4tQ5~rP_3`vQ%+WcVzy(-DpZ$s@g?BCX)tD?Scnnxi5|<P-
z1h>)P!<^E-0B9REDR<*N^ya8RxhbqdT|v%YOZb;S|FwBV`Shg1pNs-(z`)gj=1(f#
zWH8f;aDZ8mu-cncs_9wr{vhFZoJr;CzAb{dNH8Yre!OjREkaJFS_3PZ8me}`q-<>b
zNim)%*0%V>I(wm197g0!il3u})Ys=&bUXRiA+iAhB5KQGS((+O`WBoS`1h(wjql({
z#~V<SGBQWhHj&ySmo63AS6|OX&pNaL&XX66OX^Zw&ZFQ@>Rx6c+u(|Fy~iSfol!2l
z4W6ctAk<+U95!SNr6vs?h|RFUiqejx;dzA*tYNn3umKF~`)88G@+vkCkcGT+GfR$Z
zSHsu`5<Idl68hLCJlD{Ix*U*#OvyYZlACc_X4|3W^;*fAf!8i6E705~0JinhhXr-T
z&i^YB8_0D*0X}k;!*OU~&q^kJ{`L!;xTNY<oG+3fQPeekd&<WMWrGzjuRQgVvUx)8
z0``85Sq4YjwyQsOB{QI73DGm_u5JhuB^w!K?|I~7k-Bj375thx#eQs!{G_OyLY_j2
zMLoN@B2!H?X1_Ru?b$$3uKt0f3%p+CkK#zg!YS6jzQVbIRYYN-W{24BC&l>aWAr7C
z>VG_|e`wx7Hm2wKl;@@03Qf1L<^V*NstXY~sUZ#Yi6!|<4t^VtcJHz^E<HJ{Ko^8e
z;xvD9fwm@CkeVF+1pomY<Kj#%X%ojyo<0`vp|z!CT~w2!8{tgBiy{rvRfM6CNmVw(
z36YZ=$u$cgAQUz#oT?_*{sy}enG|O)q)ML<m+VfI-!1?i`qJDn-!G=jN6zF1n|g`h
z0s44j)BqpKH-~8_y=LG(GP%XMffX(5-!hg^!P@rP5!tXgk~{u}TV%O2{^YI`q8T5#
zW}dUydM>M;BL`gayNydD*ONYF;q8R$xOLDQ=B)so*O1YKj!hocSG&Cvix0&~AYs^Z
z!DZM3?Q9YA;igdtsngXeA#=xH>m%nCQYY62I7C{DGt0rhM#??(*@-(+tQlp_zj$Sq
zSmqDIyP!l_7&kCUqFBGZ0;l(kV2P-#{15A<RB)X=x^jR*TP9>~+xXKfu041K!bxmP
zkFI$FoTQ37yfcf+lszkZ6qYFVpJRBOJq;&y_(K2k5|?sfxGh%7x1^lj*{i0^bACSD
zmwDgS%NcoCH_;>YhGQmMsi=>)E7z2V%J!h1U97Z4Xk%u~HqtdHPsX_^Fu%666BN3x
z9(XP0h2uV;%<{@l)xS>f8~~t`Rq%wAydWnXa(MDw8YwcHaySkUMSc6qFMUo=_~ft;
zV4%1WP(2a7aAm-Y0#MX$wiHvr@2ODsiCmfLvE|40F)!!vRQ(y2TlP{>Juy``*(E-w
zr_PDsfn+FIyt+7#D^vC<@OzS843O^_04MrQF>O3N^|~VU8}EnH)9CxILO0n_K=m|#
z8;K=2pTpC-wib9*KU%<!Tgv5*_Oz=vBbO=til=kE2j(<RJ*qg(>81L{N0pTtQ9T2;
z(fA6RU`PYS$MFpL=RpY)2XO#^I25ak$G)^6>&Sapn6(=MeLc`{HOiR74GKmMWUF}0
z_-PkcQ@|w2E=+o3%AQnV+UvdqFy@xQHdEOo-3vk7Vn2Vl>0OJ-(_a1JA-O5&Mh$G%
z1*2A%<kx&eTU;8RK&Fku@^?&mqm<S6;2Xp-Im(74WG&|Dpp?z`Y=QW@bjPzJSlNCl
zlI2~ZS5a7u-QBO(3RI?D=-BstEZ-TZhgL6UPYa|}$0rRAVA+Xqx(UuryjS+~1*%Hd
z1=dSr03l!}04jFv=cl;?#Rx)xgY?Zx<to?*zNN#?i0^j$Z*+_lBmjsa?LO)rBI?lm
z$A!XBVE(Oj2f?uj-}Pv#*dgTF)y6mjD$klCaSRYQfy3Uv=RCDaAp?<dOaP21;dC(x
z!Q%9Wj&M#Qm1p2$)f;wfX~oDvdT<Ds6|cA8Ta$%%qEy`BEgGg}g4Z>K)=h6jzbR}z
zB&+0&YUrph74>^7*iFuTs<-m=xbhMgayNB&yO|-pqN-Xoa7E2CD*;IKDcl=OcEual
z1)+pF2FdA7EE_e2?23M0Eb8-qNST`S51<&Ja6R;<_nyz5DzdLX8xD_Z5nx4Wr?<JM
zPA{sGotso|>vFgZGpZD=v^#)%M48n2A`9pvn0glM5RuI!nF4RWf}s^j6okRTUBKY0
z)r^qNF$3qe$J!7b2)U-+4XNH?-eJY%u^V*+Ibr~>G33TN<_=DS@c!eN8)bYwcz+LO
z8m&xf3;%M7XW9i5$jCbLEwPQ^Mnsu4CM8lXH}Bm=Cb-aoZ*jF}Ivgx+xV52NZrLr2
zDesegmEYvnzdnyG5c-=GYtwe*Z{WRFxBW=*Qu&wdj@ud|@mTk}@JPYV7xYMh$`18L
z-dU-#V{0B^(bFrVy$f!UPfd(qBSo7*XzaP-ljEea%EbXV!1B+rUOOiO3Twk>Og{zN
zy!oXD8PmOwfnJFok|J_7#r&Q043qx>MN~4b1O&XiP*Cjs4V5st@H{sXA<>{bshhzf
z>S}jD&odYNKvK-_IR5j^uPRATO7Ol)fjBcHuqk;W&pA!Vnf&(vXfg0Lv|=LBRZ5Y?
zSE~i6qHKvMcpe*!AlXw&@9iW})RgkQoaP29g)L8!xST2W)LYZZh(%G#`fTY>slIze
zlfajYCSz9sX2+Y1OL695rvbs_`VLCYnUKAy7NTl#k|QN;HJ+N~d~U!N%~+Zw@x`Sy
zNs|%9YD&iO2Z7K(qQy4V(xatfYD)X1Fc(^jhA2?#reC%;q?r~5OxhtT-Fmq@av=~k
z_kIJV;h-T;%7Ab0;G}>UbVhC^!8x>Uf0smZq>MQCumrs<8jK`8qvxOS1}OB*jMx<8
zA|dl=##nr;ld}L`H0kt=21u&Txs*>kBLAaAnYCeg0huz-h2-oK&w?%2i_4THgX$#*
zI)!dpS0s%N<IYc@*;n6VN=@Ig!TX?uT+!wO@Dh|7+io2vf10wpG;j<O&;Ca-Rb|TI
z{&2CCc#aPOc$AN%=hWR^h-JgC3D76oxw+Rx7DD}W5b+)&YNlKoIla9xxoqC?5!dsd
zu5bJV*{2Wtv-xs4<nEn1OIjJaOdJpPvUCbW_@}`BdI10t?Ui77UhDy~8ekY>UX|CE
zq61OtNpMm_8rSqnfEnP7mS0VmNWdBWG`s;hC~#yAP)7Efs)<y58xo3eE>CKy>btXo
zL*(<mKeg<sKTJFQRO^oCQV2I^s*>JM>~5-t7>2=-T5Ts}({x%%jcH}V{ivyRL&qdb
zT>;XlC*C7?@0_WLXUokX+hZ?nG!dJca$;?eIWtA7e<qU8@WMbF73fpam=`ge&3t%a
zeNU_@P<+A^IZ|7lgWHW3Z&_>r0s??^4@G~+Jt9Uze-IG0bQ%Vyf~0QzI>VFNt<pwl
z{wRQl^d(DN3Kz*0o!ZM1iPnszOw`fuF)nP;zV=zPrN-(us1E$C4I=meKHBpG=0>lQ
zWa<6fqXM})Ku|x-y1)(>bdLxu^n}8g2GjX@%8d?;k&0$+`pI-?_<XeqHKcs8!o@&6
zbQZ$H>Vky1*1(riw-z1vH89vjShkwwxFEvn(5HhXbda)sd(HgD1QE-ohfm@p7VGvI
zKwx7LVIyGQ-HE*lQn7tk+STLrSPv!QB1s-M_4u{9dVVLv=+pXtIxbBm6&E%kF!>gz
zCFb1z+gSdKNXtL9cj?q}C2}}B398pFnQ%_Z&9t;Y97HN~d)x992}PvbpCX6qR-cUb
zu;UXAb#SQqq87QS>L(4<Wc}|NlEmZk2f&)Z@gpr{2yR&ntPN}o!XN>Gls8z)tE8qC
z4A~<mZt|yv-#Q>W8>(p~ORUQX)CN&>q(xQ5IY7P=P}8F0a0)kuf>ta9gQ#q0W3QpW
zm8!A%<UCW(w3<uTi;cyRZ2O@_XiywaKZ}r>1_<fVec4gOndVkEt>v34(yBDi#C576
z2!fJ!hNT7*l==gaJVqNQvH@B$r*fJHp*Uyg7lBz9-{PiU6mB~xEM0D(!{~DsPEpc2
zTW96ySoh&bR?R_1YFh6L<xIJ)`o|)wwahelxe1)4rVSs}BqqQ`lJ)*9WM}5UAlulO
zev7CN`V|jxO*o0SH_oL@&2=$Mreq$T5Mz7{70Mb_uM#I%=lT&=WqmHGm~;Ni(WYcf
z3+J)TELF6$FJZQr$|x)MPp>RhqptmPJ`;Z`^~0ykf)im|BRpmDY7qZ%;>Yx<A}v$)
z3cb&lyFhl;hN^2hoc<S9gyvMg{SVv$+D^0@xRUD8FMX)BGx=B;br5V9@@9x5uKpHG
zOqUn2b086ZN0!V00*ENL8Uht>q&XtWooTJxOFXuRO`2?`_Vrsc;`*oCs=yJG2rm))
zh);*|`c3sb27x5h7qX2_g`kApi;6RWaSHCm3ql})5`aOs^CD|g9O7rB2X3=O>4@=d
z3rVHpe5G%}3g`w|FqKEFra*myRB2y_SgD-qtMX=z3@3{5)%-doG?dvCEqF$Z<BMW-
zEx|ns%b%teI8;}vGS26&jyR~gRH0pm&l`pFuKtEV3O)+i+I+rF)-+6fE@5h5<crlU
zQ<v7Uh8+>^kj=X2db8r&OUW&_oO&xdaujO^Afv-aq+41fY$}aBjsU?JI~CQ}Wq8%8
z63OA~(H?>O*9DdaI{)J0s?QPAb%k$0`h<po+(+WuhJ1l2x7@Vi{0mI@h%4|~8^t^~
zmC+rKB?iip<b1SgV3_euMELj>fczY?qfB+*%4Hwbj5$@=Gy5=fAI%LMAF`SO%On+?
z^Ov&>uiHAmfw<X~?kX0BY|P7Jq$*3xZn6jJ32%e5GA3kYT}USXme@7p=ip6WHVoGF
z`*Zj-+BR3)b(u6sTgU-AasqVZj87jWvQt15Ffp+0R%aLFZAK=V_=fANir}KU%F`If
zH>+JG*mBOoO#$dg+qCpaa1P>Iky<V%Rs+&Dz16Np4$dx*WVdtF>5K1K=KZLgmG+Bz
zF8P^@<_B)>9Ac_8I{rN*1R5A-A_IDK!BH#+@x%0?)p8KWe?B!gC(;VMBiJ_SqLxC2
zeU?9d`t(xrCczp1X<m<nmk~XkwK+mOD(i*mv~$i<a-KXWbhC^p`Z`F?P9SPnlJcr3
z@0B1fUs@zO2XXb+lgs8HuCG-uZw}(-+;VCJQRlWs8T}1TW2K;{!T6oW8dW!b0#2=K
zhu9)c{lUn#x4?D@!~%t~9r&=nNKl}EH_?vVaLhAm(H1A$$q%-hU72lXp5{n4WBtuC
zO9U$6z$V+3>jLRx96iv8^+qoNSvMlsQp2~7^eIUVvxUlb_nqpQ=FU8-77=cyJ$oZh
z71j4D<8%&@a#^;C%rcs0;p;G_4p*-Fawakm6<1y@wT#{y&^)d}^?LLT36j4XKlok6
zpZ|f=l5T9nTf(&l3g{|bM8nSLmC%hKF8|6MM2z3AIyWltx+*Tug~N|&jdIzM!zzFh
z1EbSbeOGa@hh*2w4p+=GT)HzOD>&;O%<N>0ry(h{r*OH#Hi|^BV%}k2n3yDeI=dww
zUCL>+F36VJ@7M91ELy0y$J5<J^thT>Kg0tQQhUDB&896Y;S?MfHa{Z^E3Sdm5jC`_
zs6l4*YeoV}<51b*F55GJG0xRx98+Xm$rD%iqtpr;MkI7f)}T6UbW~UWH+b)p`Q9tu
zy1g+rniwFRQ~h2w`R9-jjo#06Dq9=Id6wkRnu%SX1k_UFvravLXE}D1q53{4r#VOK
z5<#@AGqTGeXv*CBNNE6^m~qi!oB#eOm3Ns+esf04Ysd6g`F2Qyf|f=n(T70U6%Xp<
zNa41&pyuBt_zdyD>C(1gP`h`GaiG&>z=&*q(zc56Q}$<W-zScCk=^w9M$ck)Fa8Tx
z3&`BT;X=0k37S6W(@kG`*s&wH6i_=xZ>`4{!dIN%qr(~($yM@HkMF5zR@QcYV&q4r
z?$|E3+aoPSG)})y>+lul(=Hrrf0ftP0yb3kyA9DY+n3lL-Y!>x%CZ?#pH}-F=X=Jb
zz8s3cn8t}0BI{4Ev|j?7pfi!UC*=A};CJ}j8j?DVmz}r;XQ4-OiY^d=QA%ZZ4-_yo
zD%hD2*<Vvwy?>&3)E+I7o&IH_c!gi#<YUYSNI)qq{gypyiK11{ED>(EVw?@RpamwO
zRz-``7)Hr#D7D|t@!aH0P*-Yk##t|%32q;gE{G5s^(1)hdtfxyOZ#|df^SYuFCTi*
zzxs#d)Pv#m;4?Eh*xsZStS3WoI1)0p0s{pD%8^9Qgw{JXAhs??qSE%2<fLIBIubg)
zfzy_3RpS!6Aq$7$q8HHwukXDnP9>f<S=+!XIcDU5G58aPR4)&a(6`%=OzZH!3KFb|
zZ#&fwb|6TN5s9DV_oLlI=g>efFLv9+)IGw4>4QsrQ+H}<{TNNjJV!&ITS;)KS+BOj
zm@<lO?#sbhRKGqZWMBc#SrCS_4)PVbZP9fN#~{Sb5D&VPS{5%SZ3vhR<-48B1AZ);
z*@#*D-+C`yR7v0>W#j(&ffE!ut8Ark{RV1?K62-lNP$e$Z9IL_-s=>%Nk89Fs+pTe
zpYUx)3obrX-O;`9{qMo7jq*z#WHXi;`1MCE9e_R>)aY+biwX=f8(H<rZ<S5{gExvD
zkReL8TMIPgzFrqWPmwbIZWv4HL2lRBS3VpzIE8n2U<Tsc<9{bcH2#vJ;EyF0eER(u
z{Q1;Uz!Dnk>;VofFn$?J^WafEEcwb>inKt8_%fE5e`j<@h<F}AUF=GlTfA<|fWi<u
zc$FifdiDz43M({1k%WHURs0eu2U5o`dF{uwUvdOeFF0d{_DdUmY=o~f%7mXM;YJs7
z1X7P^35**3@|IC1JCJ(m<+0i??Zht-unIlBTIb4FxrxV1E$EKOWJ}Pfn?V(Nrf9!c
zRQ}M4rWlo`YQIzo8KwP_YW$KN<G;qzf3;uIj9;>2{5vYX)_(CBzi2W3t<H<ssiE)b
z`VSF)Al4GHpevx_Z*3)usD~l&4qU9&f`4e_aEk4Z$n?IG542zE8^1KrdfVWu810t^
z#xD)EUz*xGXup_)`xk2oONGV_bbbUv`NzJMtEt8=$Mr|p{f@OJYriznn;>5lr$y~D
z?-x{Kj_DuUecv(gBY=N1oj<&})}=n_|7kTfH-5>`e(8U9iulDacd)5`_mBu4xRF$M
z_>Vp1`+W6-1?^3gvG=Sd%E#}PV-yY0txoxGAtO@dneQVK6gRHXSs#_j6RO)Zh!^3g
zV!kN#J??I*i#Tn<HbAsMr{C1C6nM?^D%6Fu5DC_x(3N*ukh-kJZAK(h^WBe=gC)F>
zbzM>!3eF%A)s25dv1d^-UC89UCHDcjHua}Qm>;82`nKJT!cCNY*Urim<<QBwdF1Af
z_xw&?Zs5y=r%8ONu>n)h9dpY(>ZK2UmTOk8KQINJRsZa73c8}+Eiv9y>fz7RWQy`M
z4v#ld>o2dAH?{s|)+1Jm<R~#T<r-T_DM5o}c8DV}>`$C4gG0mgB^JEi#Dd*|*;<S_
zFWMU?d4yyQ{}BOB>55ITW6pbP&?+^t#1%PchiJ3(%Q%x4Q)2lRh^vEA#{HQ;u~O@*
zGM7KGN^KZo-Y0)z&0^7JlH=4}GfABmFOvYMYJ|&dxOB^ndaf>z8+9c5-V(@KqglGN
z1KzGd`VN`XpV+i=mfQ+3Rm~^KBsH<k4}gElt#<5K!dzFEEkjsAIy^!*dib&C8yyj2
z*=M)SOd8N6%uE_u?ME|dWbQv133^~3{jvPCrjGldzbrt?<iYa`XXC3#<$<el&M1OV
zvviHB`_O=>p{ersMFaX)f)s7m@_|hJh%&FnZzjruou>GH>f-sAO+3q<td%LsDtO)m
z&_INU1Uzhg{-t37A~m<^tD($9fMVTNR*RLykwnU_Jg_YiW$!3BPjHHQuv@5nEvX*O
z`r6d1UtS<ql2q#Kub-Gk^kP@2E$6XbD<sEwMmOz$%$6Op)W5EbGc|wjLW119`uMZo
zWs36bV)Z;yW9q93Jy?ezQ9w+M1RNMWf+}K;2{DzPl)J@zG0BF4gIcsNVhIL^I+F6&
zH6GFRwTnbEsqm~}vQ(={#XBH+xq;RR_hGTb5?-p+4_M*YaX|E=TmpwRkv&J4XzP)q
ztj=t2RHY6=Nf@<?wyXW~G2;U%4hRwU)&Pnlsm>w5re$JWQv6peXsf6z`O<9JrvbRB
zojaNG2(J3MKaxqnO+7*)O}Sqgvx><5@+Y<N0rYPuH6f-mg4GTkZ!n_hZI{yUi<0~1
zNa|ie?4gX};6xIsiExLI+wC6@Ftf}xco<AB=ZZ@jUYLQiAa~09zu~zLJXq35-vPyO
zj-C9s2A0+J9Yp%UI^i{7D6;c3Y1ov{#qK39TNjng&WPT?aXm^_*7JP!eo`uixh=&z
zzEP0gm!AY%=ikRL$a1YN?6*NSUCOs#&km7VP*+^3!6Y3$Q`Zds)>O|1`=>I+zIiHt
z1i_OFo@=(<te(f-uL%QF71`AwU+9fUsX=A$m1y}R)kDF^AZC0IjqkCI*fJOck?mh`
zsvhFL1&H`;Ty>t^zO_VvNM$dM07BGYqYt`z`?SeS{84(W{6WfJi}}!Np*pSiDVER?
z$?aNw{N=B@t)!_3lF0cyx|0T+)u$drEeq4xFCne^L73bR&QTVocMw;S%UoP?SW%Po
zCl}~3+Dr=n8hdA64hfiQ5a^g~57gu`n=;Bu_$GgHbc^0{T|iLXgkK^@K{=AE>;SG6
z4pRn|1nXvywPsNbp3PeEC)ZwPiev0gj;pzk^@YH#@U?KK++jr0!er0F=amDEkc~+8
zotq<f(4X93XC8CGrbXcAY4lDMY;pOqxnSE{CCvppUh7;=DySxR{R{|9UKi3Zt<C`q
zd$+|s;N7GTADpYBeo>6+&rZTbNgwz&511YLMNJ-cAP0a({ct;?vU6!y$KNU~OQSm3
zb<sr0taQ#q`Rr@~nWD@MLZ$=*FGTyXxKMTe=w+tn7ABoA75w%OoFt5b;f=KA=ey9E
zI1l4t)A)syX<bbtRxvhRMA^7ERIX3m@@`%eWk<d0Cd!_*2-q(T!_Q8KOi>PBom^IG
zT{$rtdl%jx>*@X2hBBuv`s}D+>-j}MN66J#FSixYfyg%f3EzO;YdIE_8*%XF;*~15
ztG}!wQPc-bReq=gYRCCxGNPpO9Uh2UHYQ}VA-cZmlT~`%s8CQK850SwC#38brnTLZ
z=XWR|M+C)r3J%ic4fTm~;hFbYIf4%$dx$5Z|En5OQNJgu%Tkkecq&wUA!`S+FokcD
zNvfyn(a<odE?}l&f@P4G-&5!8YSs_YHP`3M&2=TciLPv_EA<*;MDefmd+PNXA=jmP
z8vO|W0?q}%R5xTKkV&n*z_D`@axV>=F0bi+Pv>T^(2||>^oT*ccDZ2R<gM~}0V=f{
zPV*WUsXGuks%OZ*m5P$Kr_)vthdL0oA4WcrBk*HL(mi8N76(usJlYYC6lVNqiLzv>
zlXJZ<Q|!}2<Rwd)Sp#`WP>pelwtvo32ccf;7tfGW*qoDT!Pu|lnyibXaaxsag0j5t
zWksr8UH$lwzRqcSu59o<h>>|V|AX**T!)qI*AW?k_fpx7APX{OUlz6m63?NHNkt@z
zdOY)r+-v1@s|Cemp7TYw$gQiF#?LYh<23|HlR9{_3i8VsjSD<%y}ZipF4&W3R9e)5
znz7#Nhvl%dh`X#W>mbulv5$7`)^?Zr+Y3$VvsP#1wv~Uc0ObPyY+Hk1lZAr(UQ6nF
zCS(*i1G|{eG4l(XusUI<;ZKRu#>rpx7VNaOghT=wst^z`42MKVJVb$r0ES%R^n0V4
z?~=Fls<%QdfNta_Du0H=1~RGYJMhz&NwsQ!<B&*k-r8TwI;VQ$2IMXvF(Iu|MH4{E
z;q^|$)41-Mq**xCn?9gwyi_#K+wcP!`r!9AuUCx$Dd^>UN3gYZC75`*Cw_0cV}sd{
zLn~Ep=WEFPz(302?O6<ysv99vb|7z5Z@*&Ki}R%&MD2%x3vzl%d58It=?W~yq&d8!
ze!(IN3t&)bH5l`_vkZWW9B;2H!F8OII$>1{km$uEBiK6aDh|Q&30IlfDXx5gk*c3H
z0o!LZm@RpD^TzA=ydlV{U=YD(U+|q=lXY=(T=SarZrMFkLMH2~#)!ab(!BMBlKC18
zml?RcZaQpIzHK|_*#cdlEh1jocP9al&HH8D?}2}_+zs{6fI>0_XN25}RPO)Sy7Ks#
z&aXe2B*dNxA|Z$ob4L)#h<lUCWHOV?Wb72RE3vP!@B30kHPxa;)xOtOlqzlULlw2R
zLhXC)du`?YKKJI{dCtxIM?S6ZoM*k~oaa2tIY&4(8}1%jO?kV9+_KFp`9U^2=Z72!
zqsWzub5pGY+o&E8ENhZ@b4g_-P^K#V0F`t~-YAk-&6ELi39qys{&=XiKQoeY=OR3_
zW7$VZO=}A;XT#Va$ba<_i(W$*d!`!?FSir_9Cv!b3R&{ut{-NR1em8&k>_xGMtOzl
z*wZ3tl+e}Z^^QTMW2hw|rI*bZtoM<sm<?xctunbYF~t#KoI=*R2sKBc>c2IwL?B;!
z!p0<SUoNNQ#nqHpY;rsybf?=l7r~OmNi*8@rMnVe(nT9SP+K6QI$2JyJ9|?UsnD0+
zsNMxtlJj&*decAQ#L0IV`IQnL>+5Q}zDZ&p6;lClsIjGYIExcenHRJrAGnfxsY~|s
z0=%h*j%TL#3LXG~2aWPY<b2Oa6wq%y0>NmgJhg*U+SDNse4sAL%&!?M;MjyQOSj5<
zFn%SICRQj(7aVEoJbiAY&prsFG{P6X;USDp_!)A}j-bjEneT$f0ijvAn|FXRHHLgQ
zH6|<{cMxY7s#&a93DO$RINGGN{@DQ?vc>l~hcH3KmBjWxZgU`pE$tFs=#V|pNQ$A&
z0%LXTF%P_a%YjV74-bNeB^ki6Va0WRU#Ffz>NJ|Xbu)LNmZpi>0dSoWE{t!I$iA?u
z27obKylPsWFOaTqs|Ac5{OX_Gdnq`_B*>$~&&m@-dLFicDq`W)!KONzch?b6TpKxK
zo{T`2WEEBW7n_WN8*${A9YjzmqsaeY4QPa>2CzhMP@fSR7v~m+G~iqqlQK%}p;Bne
zh^z(Cq${eFQT}XhIe(4pxG~p|VBXgU%ZE;)GK2;?pC-6N?Z=u=>5zD-EfVo)TrUr>
zc422Ve=9PS-1nlOgHkU*WVO+O%9fG-7j9{E$}YqA)y1NO4$e?vO`8!YDWgd}bpn|D
z!|w>0moCXsF*V@_$bK+qw5eFd_^yFY{B0Q>MkBommcOCeZLr++F13D&Cyq=~Mvq|&
zVhNO)(dXquJUZk3ourHb$#Bi2(2#?1Mf?yGmQh9FV4^Vyd*_xEB#fH}(*Py?{5ZLE
zw^)K$r`_Ss2$>wfR>;})qmNKYv$s6ct-td&8o9bnP2@uZVWE4u-CvU3&)}kX>Cx?A
zqG!|+U$x~<nxB%1?fN32G&hua^B!D!>xKpMcH6&kZc<d*HEW8ldwaUVf1C_`|Mk#l
zf=Gul;<(CL7mnQ;TrH1=DFC>{h^L+5^dbkKoT4fBNXH8N$7f&R!r9rJm@?$bwXb#B
z>1Msj@qRxgMssJ6&IwI;_<8>jLSue54Y`+b|AN;2U-MP%xFQt!@8*<9KZ1K}L~BJN
zrV$VbDqcQMNQusLN8s}mE3}s`xsu29u!~#gc~qv{E}isxqT=V%f=I;V>`NiZQzh=)
zhq}6Ar9^#Qao@ey7pxV8*ZhiqQr>#*kzPg@)<KTcJ23?Ed0d~Kp}H%{<6(ghIjx!G
zsXO$UQ9+o@!yU-xX&i&Cw7mP%#2&buf9b10vDv(x`2u4~o>s&1r(l|hfR!kiXPQA8
zAY2`<;8alqnQriO9W%5Pfoz_hm-7X*l|0!}XbVCoc?NE1R9^=T8;|1~tpQVgct65N
zVbnKU3t5NP=Z@#C<7?~KfAS@GBcr6B!=@Jwi=jx)i3MJY%$f>IoRpf|5C?Yz`PP6N
zQXWZIvRJ?}Km(XaD+lO|8uQvCPyw7wu_(4pjl#wU8yb=Nq#wSn!i^>`ThGp>2%*3?
zEByLj@un2nU%!<n4`DKo6g|SB-*3wfj_RThOv%L5wwFyO^1`2?`Xou`N(`jVPU6MY
zS2qP1b{Enfz%i-6wn2Xadi#U5I$d$^i_>+9Pn7j>b8eKVMtI(9YBNG2yiQmU>qpqz
z6-2mtAKZ)6kc{iRfqPz8CB8#8Z^*O%!tkV+pgwQ0!}qE3ki22ey)GS9__Vow3}rr;
z%7sMmmVI!jEFqJ;6(_DMMW6(4%#kGqBmA6ccBI%~EPFg;^Tw@!P*AVOB(H4|4S3-8
zN@agJtG7gaUPr<^onG;}&9EJmCYb2Mg9mO=T_3TC2f@o(4p$uS0aSjd-&sBifC5s)
zL!QGXWpR)I63qycyv=9UDWrp1ov7gO`yR;!+egC#jW3w#%^Lj*88~<hu2ETtq=n}g
zJZkm!LL5jQk-YsH!YNXN*xTJqWUv~vs0LMkKJW1BEK`TtVK9(+OlMs8a=gKKbHc76
zoXjycn_`3^iv~2+AWcs{OlhQ?{#G6T&T4_pJzq-r`XQpY@QAda36iw<Ef-w$;yimv
zq0PFgR+_O-;R_0D?Z`z;kPXwmsz8y=M<76iW_toOnu6fo!XhaSQR9Cqjkl4Cvd>Gw
zr2JC<m*ElY)g<@T#pEVQ$4UMgd{KBq{eQ`tT30kvcP8w13{8!;<o4a?81YOXU)5PJ
zsi%otb@xh5<oMB~6Mf80^E*oQ|5=F+#8LW^hxCo1E4?jw<W*P%6htbf29@YyEGAEy
zUqF5|sy>EAcaoAnxk`;|F?q(9uW``ff5a~L`il|`h$D>*&e^3@$aT<`JU@dv$S6_y
zEQ><I<dg~g)AQuzbrcs2t^zT6^}6$|byMj}UcX{7Jy}E&CUK(NB~s(|qI1pp3h(^j
zxvKNns(^$`=3h^jXKspY0g%f>IppPG3fosXEMRp}z7lq~gi!DYr{F}8xGNpGJG(YN
zRS+)AiHS7D2D6(Hn)T1O3rg^HGSa^bQ1>8)UAnzh|9IGPJ-d(pEj_rG(cM0wj9#5O
zwo51;V7}iA);T?@vplg?mjk=16UB<ZEKrYRs{kgxZB-T_Hnjn=Pi!~rk-Ht-C-3zy
z;~9G}p0aDNo@BB@TQAGrcWM(dSiDhwmo|H;cZWz?9#eDVXt^2SwwEnq!wCfJIrTY}
zTt|gtujSMxT*b)7v;lsi;BG=`ZK3$BaFp<XI-um*QfCQu`t0%lbpg+l!nKdTEUbM<
zwtOhLn2HarseLnWNM0_cOuO?dM6KYB2j)A9SL7K3f63>sXRmXR=GBqM)yQg=g^cT%
zWN*3zn|tbf)UxWAawKaqs&>y@`V>_@d)CzVxIEAvC}8u4cN|?$;h79yqh#;pMIIE4
z#J|ef`xV%Wv`Az^hLlx&M^$%ibXu~HXw00W)S`@y#vC~yyE3ZXW7tIB$fnw?<#Fqj
z9=UyVm^A%pD!#VbVU(0UkHMoi?ZdFTX8o;XnNpv`0~6*pc~QU+AEs$>Mz>&s>;y}&
z#phPH*R^R`G5nm~9ZOpCBA!0Yw`?rQIbJc10hc55mSG)?0o(~8_yI8cN%&D0LW}is
z*WrD|Bf6+_%8)&4V2o)lH9*7zt`kV^$U~OH$!3|~RUOR+cWfnHwitHmPbD6`%0CP{
z`x#|+hF$DP#f@RtzIYU`n;7Ar7+ekTo>i9nAB-gmo0WY0Xf1KF1tz>m0P|=`j+jZm
zyMXk1<W@vJR)cylj!!XkmOmxz1C8_G<TO{w|Dz5=rYt<|dM&<xjQ3KCze1o(Z9ZkX
zl6B?WOq#cq3`PvTozIUpCF<Y-z00yMrPBE*n4jvspIq3oE>}*TrLwcBO$USQI2HRh
zr<Iw0KwchOO3kWp+T)_9fhB<F<z(v8QSW>WC#Q}1G@_K^sE<sVD5p(}l;Vy<h!7rv
zf77>zdb3GUB|)B)y2lZarz;m~QA}ynR*?jC2;p_Hay8uz?>gSK3CWoDBklnY*;3lZ
z;)xViS(Rz!COQV|x`I?pxd=f3^{Y-@c%$M0mY!V||0^yWyDcT#EnhEbCaPTHARFS0
zYJ+13zld%<?BTwV{P4h8=F$7GL%_nV_9yR>X~HqQ_tARJ*m6o8CBL6KH>~jVeej@1
zVRdpCtL9wlQpDP|g*r8iY<A$aQv6uhL#g5c)_Hg#?l)uQFnpGU#gznns!C)nFTJgJ
zILZ9WG(|Twv&y;8pOXi!Z-N9g;k*4|csy8KHaS#wXFb>ysDxlrN6E0Qf54)nHnaJs
zLWuB3G0U(2-js8EsoH``9~^M^-JaZy7a-Qt-`8?I&C|+%95TyZzg%~Olf@8Q1pU?a
z2A02epY*cY)M;Z5k+`e+yZK{kX9$<BoGxkY)=;Hm1GyfF2acSUXR*wYkLC7qT#RsI
z$@7-KUrezlxfzxoj|stIt@_KMPT|FN8a2fFW)`>S0E_t?h9Mm}z5#?3P4ko-lEniQ
zIWx6@Xyd)PqfpIv;Uv|P+fnSB5wN1Ty(zQdaJ^}|w7MuEl^o%1@n%Ky2t!MfqwI#0
za1xXGj%kYSto4dDl?)QHbbuuyrMWo;e;mVqB)M$WLN}xQsfA>y#=0XF{16kDkpUK4
zRmEFU<#?G=yowh`-Bqb%?;g?TlzB)V&|PIN&}BN@!`8vh=&rip0`ob%XZCSRuME{&
zrhC^fIvU3*tiTDm&(XYZE!|GT(YlC|T1#aGxqIzv!#fYNq3Jo%k+tNWoTiMU6CGU-
zQ$K#WaIXdi41+5yIkGRnGoBwAJci0$=N?diS)^gVnK?cKVi~<lQOq2Zna4jzcv|E;
zK?4fkn_9wAv}0hx#{<{of7&}e5a+TQDe4q*CiE&p5c8~0xYKU1ff8_)In+DmRdmWh
zdU#$aQzPF6lx4{`h5gp2BC*1%)`*DOL+vG+j{olGr`HU|>6J+OBx#c;Qa9|aca%+l
zsw!BwcNEPIBDGn6{(!qc0Eu;v4zTRMwNLiy=IXH=I`dOLgW_1<DUqa4meU{7kIk-{
zjs#kAPu<j;i_(S3wXqJVrXf4^0w-U6ftUUK*h6oLje^yfXL%~^ez|Db)0OL<_3<CN
zlgSr#dO$s>)nk~J*Ef`;PO3aH?EN?KqjUl)rUuoKbK~KQYHSQoqWegrgcTN@)6k^U
zVm;OK8twb{$M;V){rnZ8t}PE@`v<u_<~A>>u{YvN-?%C}V}|_LNvljsEoXq~-BT4~
z#4$1aVw6%Vw!R&$MW%tA*ivKK;c5X!WlydvVrtc7#g<cfo{3ayT*Soc{wn3twsYLO
z8O*2*N?*uNE%`;<m+ENxAEzJX`dl}^3XJHfsvkgNs<(q;$#MEZO0Cxr>E`(UAyZQ|
z+~;YdlUr@p5^q7V%~ZdV;*w-(`IA-NajV}~Zl-;w7Y^N*@}*||>eBbHTSMe>)0$z=
zaBu<D>o<o!Ia9yptUKHcN~wcw{QS$UjwtGqBU-3~1J6ifX1(LK#%$TZN;z@jPgEGK
zQ-`Y=-*8G5jx0h_>Sy7~X@oqmycHtM)He_>q4<p^8WHAffT_g$(+Klx!Ec+-fFvy3
zkC<s14ZD`dZgAOBnCd*4xZ3#pCS6_YQgGR(m1Kk3Y&uI12hH1-VFOMd3kW-7T&4Ww
z*g}tsirvN6)zlc2^?l#Cqh>!9Lw+CFqa;QCnCGlU5b5OmMbPUS_hYk-X+3lPJ8sEh
zRh{pVQ=AsO5;cr=-Ew1rM-Gj_g;2NrbK@^L3^!*7Ne?bx<E#o+`_s8tZ?ue0KrH`W
zoh*lx;IxMDb~<hZwdn(+z}sk?8L6UVc47trd`(1Wf!6XWr0j;UZ|HqHI=pwEa_}@t
z!8Y@V{8mxzj$BEJZ*Z-|yRu|DOLfY{8MB7T@i?CuMQ3DN>XR;)uaJ(5B#l;v%qQW^
z&O@S8uosZ`%<70hCpxRWsW)3EUN&cZeVjCN0v28$pF1%ZZy)&@C1>)o9wj4sb6P=i
zrd@~k6;CBPJ^Pilfm2X!XWgRx<Tq@Z<}o$FgK)f@Yxq(&A2pnry>P2;x=c<I;D>Si
zjOSA=>*1*--<;%Z*98xpD3nzZ35EEaP@=P|rTQQ?ZZ*mvCL_t&a|U-q!Im&Q7t2nA
za^R~IodZYrce1i%B8P?N$eSGX!!oWKb;Vp<kr40(b274w&rxDV$wra9eE=$a9JEOe
z<H?tuHXmX8dG{D0r`MB2UfwLT=A}2{`@!r-YzXJJK{i*uq-DW#Ih4O<<)d#2O9o~m
z4GXk7Nwl<L`NZmc8^W3!g=q>SVZ(^sl}Po%mbf2viI29=gr4EMAnd${`xnyG?*2g`
z);^87P!{HWH?aBCsh&e2a9t!-9sLOpb9lsZs<DzjNsZpm=KjoHn%hD;KX%hEe!GK-
z_~l1Rc0BbvvSK%)_f{d53;(RisY<5gVLd#U<%eQ@x&&*0nySff4LV<1f<l;rmpMOA
z?}uNcSu&ZlrWt!ews;2?DJ>)dXChicAepLYAH+rPt1g;=Txq72;gJExgW;qwayHe9
zYX{CC=~~jt{mey;Vf>yJ-I`m3<tAe84X&mQRz|As3nkH5d}(nJFlaSFl!<C>K*mG9
z|4C^{iIm8f=BTq2mKneDrny%2@kig2Yw}*iTOz(DDXrdqyuRTfq-qK;1N%!|GvtEJ
zZX(MHov&68N@b9O$kKEhr#eveJfWD@Y2N4=OprPTYBz?ywC-D`VspwXx3s>kThJKS
zX#<Pkz*Xs+W(cy4K-$ouw^P`sSC@Rh5h#p2wxO1O*&nyJP8xA!5hmRiMT$&KA6kka
z@j2BxV}GFY{IPs_Lpd8&^(|xdxdpGv(e8K+vtTk_*75E%mL(09;8p6DjS0kxyKs5U
zR;L;&#^5OGOZ%>flb)-ZHznc(1Wt>5g~Ha~=NF;KjzI&{2_pT{s0;TkS(AHz2&qPB
zgx?%Ut;W}EIeb$NomvZFPv!(@=NZ!RNz>^QJ<I7o&kttbmK&4h?CK~vAPhGfmWv-L
z$s9RMxb8$6IIUThu>lEX?$oMIlW9F_5fPt9rSSlZgY)dOcJiaM{45av%GF=nCU6Z(
z@0u>;tVzb#uE5IYRnHd1XqQ|C|3P+R-X%tI6&s3k2@08J&nO(xkLO=k_~0ZGP#LaA
zJ#JDlm0Xo#k%6@zr)7|^DFV-9_}WER?5Xi1n1<nACHh?P;wW`nr1mxO;*&&wQBz|a
z%pfhb%RV3b1inVMD=oM@-tSf@pat5Lho5n4mw(ZdkviE(Rl^q*Tn${`uusgb<?uo3
zIlLCH$&j<jr@Yuzd0DQl&1k&fR&p#UT^3y(TN*!P)ydyY9Y;6mNHSlY<m&B(ox#tO
z=<4^|u8&zsc|p;5fo%+3g9F;*i*sIvSPslm|A%3WrAEA=ak}N6js5FRn${u{i%D~@
z*Ydl>FsYteMA@Zq3z&IEA=sFRCgAs-@hOJP%vun44MlP5?Dx>eDub{V=KY5|f1V^^
z;go}T(aebyvoWx-T4wptL@0&T188zM%lcOjwy??I7I<MxgK!fW)AlzAZ^yT2*>!tC
zM{N!<`{<XnXFw3QMPNPMKOZIsUrso*Gu9u|*3=wFJTQfheYLHa(7*Zl{mO1zu_cAm
z?c!-{sk4!IhfHd_Fcl)!pPL)=mD4!%!TU3ndsr`S)|}!Gw#$G!-CKE-@!{)-BTtg#
zdN437jcI#1)gVp-*y&)I14@V)PV^K0ZFlG?GdTSTj97(lZqOLXqT5h^x|~&jyK0f#
zL6g7q=eJ?p;|@6&R!Ey^87bD4i>M_dVWp7shj*@#+~Ffz&_oIDsFr)><jCqyST0#f
z6h&HlmAP<k;Bzk_K~pa-L_B-pm=xr5*Gz`*GBE<&wN~KxZvdxolH5r{xT8L_=yRu5
z-J&xd-0s;Uqap^V-w0GTcji#sDsV9X<f8Q_{(++EcLRjnOpRmvF(%{lKe}5~eMZkZ
z;gNJ29>cV^9dFr@0gJ26=k6ZK{FdYa5TSSXiTodg{-vCMNwERv=2#@;_L1EEmv4&V
zjR15DX_*?XZcnFm<Qbj7jD7W&En=WLS&T&{eVE>e<O>o$=?a68&mbgydb1lRKuiqq
z=y+zg#Wt-qR@0p62vE+K6XuUtS(%V5{65|rF;Jaz6q1&;tVG`=39Fvr4u^DcUE5L_
z#FNLoxm5e^%nMrc0%GlNJHaPN0%F~HKv(x3?`o2O&3qseS3#V9V)Yyv3=bbt^U<GR
z#PB1tociV$IU2g^V$90rR{Etp8SVK|RHsQ-u79JRNorr3<!8LPGD%LnsV?<`1P>PB
zZiC|%{u_s8^kT2wgonQruE)1i=GoSnj2k%<CI01nmXZTcxloa2-dO(o;GO=(0GyCc
zaIr-hAEg(JLE=Q-hsKs(<P8kpSoj}toQvd38!r0O!N^5RS6^2%Vvx#TGE}x+JAYO^
zAing9gIEeQ-jYv`DRnx|-z4sQ47&^X(yfi|QIWExSO0@PAwq>o=?N@R2v?skT?~6d
zp`>*Cj~ox9n3#^tkB2dF!Oys-jOm^o_2}S{eQEyN&i>BHgKE^oR#G<^P5-`%p{w)5
z7CQK+w{$5{OH^1c+;&T;yhNxP7ciqgy~CyR@_tV?M6keHBsi|P(z^`ag$Re|<U?Uq
z<;(T-DzY|9V+4~&@lWgba~FSN5t(eTOBdKaefW)S86;<rdCY2wT@U&}_GSnR^~CB(
zs;0TmFfO0E2(Qx#@>vILV)zV13119I!`&VyR_y8&wawXm$G@tu%I0ToBPn6c3lHMP
zQ+K$w{9|}G@GVMf>W$F}_WC!?EBR^I@hu{1ZfS_4NUj&G#qFmM(uJ=~*i{3!5q$Th
zJ(f|ldh>zzSiQNL^6ohg5C5JXAqvOFhWbz4*~=fu>#5gH|E5@06w7<%X-@6?Gc9mo
zN;fZ)clk9kmU=;gyG#7lGCT40xt9crQ6t=H2bXo^a8gVYR_#4EJWq!3m)eg`G@>~z
zo=1!=M4Xa@SAW2V6zynA!u;+o4t5YILIW8SWdyeV#i;R`j1>F<Imvj39A8F}-)GWC
z_hLq9;)cmg##BQe7xe}_Q_d*$8*ciQbVPZEb4FxxH~CUU)njPImQnt)&hr@ucX(WH
z{{4l6G;Yffnkp~9I6WX`R6C4>lYA$ojQA|LK2oT5iAE%IT69Ko4|s`^_-|51>NPz0
zr3KT^Bf**mvF{BT^8Hkw&Qyak(`mYsj3!NPHjNmfF8Sd@Vd-Uj_+TA#K~}PPK>G8x
z{7f@sw0W@2$}a`%;Uo?hJ51E&e97pNTp-==FeHDc9%G=lhw>^pqtCmwp|pzw(ppv3
zl^b#t8D%whBrup|lu7=U+C~Xj{J2H0b_O8iA@R5oCYRIYK$-TKxj^yUnzQ#8qjhLQ
zb(e&?tg~5M231osj-L0!wvR}~=7m1IljhVJsLV_M%$E>BShWL=HN0DpdA$kSH=VR@
zJ^-f*Eol|%lD55lfcx(c`Ax^JdCn|Sm9VF`p&UV^{dYECxl!ksRdnbBJ4`<gF(12+
z>tgi^)i3xg4U=c6{N?3)2U+hAgN>Jwds1;oQguF?kqeiQ$P~Z&rT)r45NYBqbhAl?
zN(3?A`3;9FxcTD?S|85Q9l<=C8CZ~?A-06=E)f4J<ruy&opa&8dq%sz4JN6cz;Rfa
zIZK%>;!6!SPe^I31=I{q@)QeI{qG?C><S9O%}mc%>E0WA%9wYrX4>NyZiV(liFiZP
zt2ZmCC1vzPd*DT&xeh6*(uFFCUE1+{p5%#5)txYS;=aez1FayF7*DOj8_3>Y@<{LC
zkH`}t2~)<QDa`8PPYpb-FOb56r}KF{SMZ`jGfvn-xGBI|ceH8%X^hYba_(syi%ndt
ze8Z#Kg8q{~OS45!<nsY_;B1Y?i<wqqF!9t*l05CEm9lC>5A`l)F%N`}w{8Y#AcpGl
zbe%L*wk>!R`I%VQD7e%3FPS~rsV8G~(7>%xbV=|Gn{vIDp9uUKF)Fqn^}-pCuy%gL
z)DS8&%9t?u1`C0wdowiM6q=&-i!pyrE|=ej0kd+ZI|#+xW*?RH*UlaXKudmGU>`k!
zU$PR{io{!J<<O{XKcdX5u=XUJT96}4lQr|kXNWe$1wcR_q#ssH;oilu=io~X)}5`A
zg0wectf#vJbIbV~V95Rt5a>ne1b859#DGF<T|0D4i7lhp0NNq|^C13sR`37!(C^RE
ze4Ins3mp}mEA8;_1zCF+H*M-m=IYuHVQu`0ix|o6R!Hm&HyO<qu-yAP>;PkOb@$Gw
z9=E}IGJ-cVo)5rv4PVauT0#O3F82b;S>G4ou4b5=c>@n*`;$k?NXY9c^tjGj>|{)s
zFrx9uyr)?*Rai!o#t|db#YBd}KhN<HCnC4E?6Z=%4#FeIrt0~YOj+@h*=4nP0AlmT
zoK)T{a{Qj;jYV%Ysg(=HeYe{|nvlG<6*|u<pI3^0$eoB{oi=0#NnVF!nW!u4w#MgW
z!Nuoio=2HpZ|{Bb({WfH;JM(Y)54K=N%Ge3iI`yc2&&l2y=hW$`apgdK5z4{?jj?v
zhqIoLsp-trB#nwGMcnka7cf<5&oA8Gtck;G5eN=R-QfiBjLNsSSMFuMCCgYH{`~!#
zt>6YM_ifOMU6DFBsNr|P0V5mm>*|=E@a#l}D!+J5*o&uisEk`Rg()F6>ewSquQP)#
zT-KbScu>r-tuU+I!n)e9!F$rz&p+c<CdS1JKE(YfaTr=s0^1CNthAoY`$U*~R%os3
zk>9ifVBYXKOb?yf+RT#8@%5OuOS0*qm^READM@ign&M$EG!<tgEc=m3b92J?PnWYq
zaNinkNSXHhnU0!o$(I#LOl}?XR{xk8Ntya?4rW43>dboArAR)oyVXUWmEmiO$$hM{
zCkp!Aq!<2CINH%Ii^Y+D%!0}rM`jrcBZhoZRy{xiu!be~KO9=rP^xI8AsLq|@&awj
zi#tAK;1&7BT!cREc*3XvLHR|CJZ@@;`+WG6k84_2`Gp1_$1jr>?@@lyf{&XTD`h^p
zofrAMu{vb=bpXoDm>Z^)$rph9i*Ql-C0_vYIeWiTerc-J)=X(<ex2`?Uz%yZAY%`E
zZm_7hZ1Y4QGQOfr!x0JJx*WbS{*d_L2!Wrldh=FPfr#k%heBy;i7F5kcKy1tO64uJ
zUs@^6ZuaDbly9Z|g1FUevbIP5qLgW^{gM|Ce`m|<$}er?U!Za-b;^r}|LeJ;YCQY`
zU$GlZJUQufB(PGabY(32BJr97(cIJ3I>Qn0AmQMQiAsf9^aFY2K~VT3Pev%ec+>*y
z^$F|ViK%(v;=S50N-X?@zXGc$Wiqv2d`g+Wi+-#8;?sVqqx^E|;Y;P0I_fVhNG^iU
zUmuJ(%Mn^Ud=^p`=<PF)fNHVunO3;pe;apQ#*imTD>#HblSSZ>m&Gb@AR~MGQ3(!V
zI?rx6z#PCht?IJ}H;1DvzlQkig?>U*MG6&f{zMOz4j#%ua=wL;%nPbYUksQYfBWne
z{=CEyqc1*t<*mQ!A#3NG6q4-KkKol0?QudN;xp6k)xLxnj|#-rDR}r~+U=2uY>E{r
zSRO9e1t|MPvO5<j$wbvJB6lZa_ziunb&k$fYlT{psT##S)I&{I?Wd5<-m)f=1hI5Y
zWTxA_u1#Ao+q23U11ToiyPnm#H~H+nn(OmF+xr#GqOD5yA<-~-Xp<v8<b${~rWkVy
zL(!HYc0#l~NSfGC?<zZ`FQQ+dF3rd?Pd|-Y2c1><dF+q$6ik|Rr5#s2YjAFh@;YR}
zCr%x*_%cG%YMo-GR*Xe>cpeefyhSiUzDLr=$p6%xGCn%<V-mNFsiu7MoZ?up@y+ub
zoTMK^5D19hwM)B>zo0Ehdp5;VL^#kGkBoSqBI&RT!C|$2u{(yZ0;OZ?Lv#gCT}M!H
zQt<4TI{)P8i`_bh1|A6{WY%kQsnrnwPwar+24jT+giN~MaxZOBdi<gjMT8ep0~0Ov
zdO~5Y^NgQU488wH*~pg?yzrbJD*X8&JyfD#S3Oj+(GChpDG?(O=L+-Sx8hQwj^Sx4
zg(_V|_Eid5HbV$_$d?j(<qvh^&14+@H<>9l<8D(K2g-i&rPS(Gns&yPBK?3%V^oXZ
zwf^{093QNt66i~DC%&d-eJS2$2<Aw1PD<S~x@$9EN~0{;z?7=#e#E!cAQQ5l7%CKS
zr?fcqH?*Yg{x79%{6`$I{DC?anW2ZeTts9of0d1}&>-MZ&)$PkBRx0prDXe%KU|}g
zYaEn3oP(IK4SV(%$2*LvVKI+Bv6KTD*@Qnorid`5F^*+1otl=ArvJW}V=-1L=Y}qf
zgn4!$oSsunBFrm*OhtT6!org9=Of6{`_l{LAxz%8LEcw29HRIm$$fyl1C%|OzB`#j
zZX#GuHWezU>)X~-yXlCepGqv?5T+h+4E*bVH8_w}weR71ikN@@9!Gw7k$?_pvmyL(
zTr5YClO^%IiKmhN`VG%XG>wAFg}>V({wJZibaS<?=hrLpZ)jMTZm$ieT@vn>d{mm&
z^LWxoT|F;;&eoNBGauVzt@Q$sC5K_ur&L5FN6@0`1&Je(&rwJ$LaBU?VoQ5+tcJQI
zhv~-D@}wX<kh0*QhZZ%Vga^`AM3hn>ChOg?0d`cZjVuuI!maE@@U?-n-y}!nS`LzO
zOKz%a38)qP%+*_CGos${P^QCH^E;e|YZ!}&z{V`z{)~3r=SW$!j6ybtdu%=_mK@#-
z&~RFX=!(x#Z_NaH(dTnCPMoi=t@$AN84541Hb-j{E_EoS&(Yq#Nnc;qs#SWbt|yl0
zp<d1SJO*;#vaffiR7s9Om0|<6UKGRx4?FS$WgKDj-tonV!;mokO+;xw!mL~@jUNvm
zL@fkidLe6BKN+h$=aWcUxp~%SpF|?5rXm$g)_XuK=2f9#aDXvf{MPoAy0Wu6mn`{*
z<7;-rHWFEjI`rT`M)uwR;55bypR}nSwvYtb`Y3@zSSU^05$*^>C?B-0$a-Gj+@D+E
zWswH5`uDWNi94xn|9$wR5#-Q?%M>vm8w6c~Jdu1=!s)ii1<xbq+_SLA=*&qMrhl!|
zCRbS+X}+9rYs6eLMebLs6GIT`@u|wR9_dBnH?*75>-*z%$onOeIfQXnYEUDVV1^Sy
zUuwwH;uM0XQ9tz@i-~(rEbXbLy?-j%Ow`EMKr8jcZVz!v+^MDSzQT5pdX_MuPc2sv
z!2m(32t8ZNaJN~pBcl9kpvjAOQ`qRmbXo`LrE(;tR!u|70*zL#Gfp^JLI>F{BltH@
zWlNR5mT!~kSRJhq=tzUu6#_gqUH6jd1W2jgu26V<eeg1Bj%?*Tgxp05zv;W%to`O_
z9aYPN>vf7awSA9W`WCbHe*{+|b)w{N)veh<eZgKw5cx*yzf9Gy%}fd<r4CM}7phX~
zh%kgf)oN#=FlPQRDhlR_({Llu(eI_qsHTqHqH;8od-$9PpG7IUT@8N)EUXvyya;{v
zMHzek%cnV8@f=t4UqPk9eEVNzD6;VIFXahhUbY$@a5}FfX?2MHY0f(L?PyX^+8hz3
z_82=W*4(x=kT0zREMqqkSM02YQ$u=RFYGQ=G{R5FithUuHoI1oA-@kts4^ar{#f({
z-6Ke+f{$`y$L<B-$#UkZZW^TX*?7TKNYz=W+<L{#m1C{lST;}~tqK3!)p;aYAKaqf
zQFw~r)3ngPxAC@_@3ioCCLT0s2$L#jz{mY7Q>P-yS)jwYifqfS$~;_Bn70v}irhHp
z&6lMt(^+E4_qYkwJXdhq%iIc`rFzWe{8{7_M)0GF%$iSA?zo*5>eR+}p;oixM8bx0
z{z~QE3NEB`*4mMw>H&Cxra>%NC9ZMeKX6vF_O7QMA)D&s^F!ApUS#<JIaR<!$(g*S
z4;3Y!GwrTE-k{TS7_WG=c2LmftQ!W=p}qDw8@@}_X$NQ1HE`VGi%QOxP4MWGhkVX<
zy}qIaea@^nUE-1?XV>bwLmg+&Sx~OLa*&+a9w;rocAInHM4UcT{eUD!QQW%)aGrV8
zEnHfu?8!tQzAwV~*-GYaRrG;{^}&HYME~PL&+|DPOVgHA)iHF=Aebq<8;vk)5$>IN
zM4H=?54_352j6kQ8|Vz4%)Dec>`(X_@}RI{Emlq*k=ERKtXnxZOn9d2)s{r;0{BwG
z_OFn-kVmAQPkyIzX5BqZy_Z)MjdkB08pYIl2n#DO;L_3E(OhR(kOG8$KJ}q4Cy{XG
zAan)ax^RASu1FB`<rnZxqwPsIs@&44w0|~Q5=c4WVG{%~<?A*-T_uObS31f*HC#)C
zm(?eiX4gmRrv?_*7jL?uI{&+eeLL0jO#af0{US>HJzucY8*n|J7E&R|=|@4BnO1aQ
z3QT<7xyF`eT8Cg1RDz_mGIoTr<LP{9<@Ob#vLU5KcR<1cN)_|u2qy{bVHd8jsvcsV
zOxy}9rNvdimV}3pyy%Csv;lY(Ax=9lR!M0NB(l;F=12?<b*+P6n^qUIbfDtAHxPzd
z1DTRZt9N)Otxig7Tn_0*c&endX7}j*m@lo>(|5FEzO?oawo`p&OY5`<9**=eGO`!#
zfHlL{FQxVEfDI#s28PAd$b*>G2N#sgw4tLr%NzROToD!=ws=7EvKRd|o;)sM%hkBw
zZc2XF6^2ZD3JKMmSr{_4UIXe?BjhCDB$20)zPwk0E~&!YVu*Q7Xcl~0NmWmI>->^t
z`h-9$o?ySvmlD1+A)F^cHre&9Z$0j!QY7sd*`5lr@JsUw4qDINo$nGT@>@M;rXOJ&
zu-k|}ey;#^MG}sG5mv}g#&qxLzncXk=e!?e9ERKZvm5XVg73U^v1>Q(dK_h?>t20c
z);snHUFRRQJ5VF99wzQ^YZ0E!DjUg*J1`|%k?&+I!_}jCG$Fogg%mm@T@f6HV#RXA
zKL!p%50S`^cbW0Iij7`MSy*zJ=HvY<r3xPv!wD}_Ev~43c)-L{*<6+4@%9u4>^zEm
zMHNo#TZlc2I~JY_`HCEkN)rhAimor91${32Vr)h=DVO_^R^-bBUBQg|clEuk1CJ*{
zg?vT(vgrWeE7T7XsPzjviUs9#wP>J=Ni4bAOvE9nMkx2AV|)1B^N`Qg&3ls$0M0`7
z(<2BKQWpJz5DiK}CgX5F$#e}an5sM=P^~<mO3tE@#!hlpV)g6GZI3;V)Jq^yc64Bf
zh)L(2#F0gsYO-<597u#2#qsiscXp9xCN0v*@0?(rBakpZ$RN^E3uio_tFW}J`WPL1
zuO5$gsC--I_3!bp1ZVa<C~ax_mR2SF7^usSB<y-{+(JrO_YBpYl<r@=L7%W_&&?=O
zNI3Q_!V2?^3#WUpq;qCHTai9TFki^Q0~6gVfh*@OSECi(tc@_IeAVVV*?7^ajtn0;
zYyh5p?k*ra82(jrUc}*p!x9z=PmV0k7q<A{&UmhkAGM=X^P77}FaojHK*kGhLvy6V
z1mr)`a|eA2HvkR7<5t8(%5;ZZVzKHpST0<wceu$9v3Dl07sAR`q~et14xd2J<t2Ai
zdu%6YWtBYGOHioF;&%zcfQC)|uK<(WvHjJ94X8Bq0=_|M)#*x$bVWFUBy#Ug8nwHU
zuJ+WL*CTY0djYoav=5o15v+iReD3;FksE@q-sb+G1)_7&6h@M}MNK3^<BLk}Hs?B-
z{SY%Bk+HYq{a$7KpggnPD<-K~nV6KrD+RfVD$2IIwv_`|X<#}Y(qUogzgBre&da%b
zXtRADe_|rk>voU4Z~-S_u-#Bt6MtcxA=^$pUnaH1(_Y>eM*5_8gvye6tM#YP^oe$6
z_T>`*F|9FYCQjb@dd&03$q&1EquRW1JGOFE2UwT2*D04(ulcM;s9ai?mBFo@EV9Zo
zqp&$jmwQRr_SfvPqz}T*)39LpUI}{|;81`d2O18Kpva+-=XA4lbayA+ES*|9o$C_o
zWUheAA#JowMs5a3=O-j_Ae*Qwcg|PNYmTkx@WL_QTnEQi<x!|=!vj{56g4ZA!7u9U
zU3jiRe7J9GuE9D;dz!&2ewJCPn01gxWeh;(my6+?Le;zUUn`0Gyo?9ajk&OCd3PXR
zdcmsKsBBB=MFXPB8|?02{-s`e=oTYQa3rOdPORWCJWJ8Mm2m8f7_UfD)MOiNMM|$Y
z0uSzK!!eORQIV6<t<7;*z*E6V=oHRxxmUOHFcNm+p|3{A9^&FGM~pxK5Dk>+?7wue
z=pdI{msChf_x$=xc^y^VMLM@BDZNn(zD-o`OK*DRM;fg-DZOPTzX!o-2hu0C-BB3c
zM6z%)!H36+l-}XS!jkN3%W(!^!2`@oPc-s$U7ii(ar82+Y)z65Wv2Jr*AXv}P)rf|
zybvXWGp8o`LAjH|@73hKFJqrE8{#a~Z)Rex;!zZtx&kLg#FOT;uB#}2311Ao-Ga~v
zbM|kIq4msfP&Sbw3(w%OEb-b|KBHa+L8LWJ#_F~j8w$0l;ioY*#rX!jrMEQ0%FEZ4
zu>D+=>^e?RX;-Zubh5dpI*t<flEQDn?;23#@R*QHiX8iRMiq*jHXs}lUynI=3pVcR
z83dDi_>>42W{fSwFY~};{A&5B&G@g)KF_UA*bRX|Tjqs(KI9DH5%Z%nIA%d)VICBo
zS7?$*kyoe8#VPXc3Ep68r5JN%1a?3W6F{1|kdRSuSBF4kv((l@W(OOCke2A!gHD9h
zoe^rc^wkIMhfB~ONI}BaDP=^a74E8o%HKr#4UNjw1li@VWj7z2;qs&CBK(0`DgOFg
zC*cotd~GP9b7#bNyNk;~j@{(})-HYTBSI);BoD)>h}N=9mHH3N7amH=NWZ$A_zn3o
zd`nJp(;}B^P##ek_;R+4CM^&TRW*;m0%1e3%|r%_51+|N#kJKQPAx1gku9UmGXy5g
ze|VG8;S(ew(EN6k1kFMhSGxv&5PitZ=rQRq9!G10a=-c(g%Z{v<^Y2CZv(t1=<N71
zhWyE2oH7O+1s^Bk6C;dUsdK>*CRc*xj@mUQHBb8&7Ou`R&N;YLBviue-H;%@oG@=^
zFB?S`Hbi<3LbLSmm@ta0`jyWo#Jsg|X1Bf!-bavvn-Ak@u!iKt%G_?u{?HF%#L})s
zd+4E^uxCJl_Jqc|{}H#CvS~WhvU)2*A{={)EFwy4Oz`16BAl+LyrNTAdtgc?qBH6F
zBEMX?0gnd|XmcuDdH5vJP~5I9uxM7i+2S0sO!8#Xoj-K1$ApL9AP@;pBRu;W8Ab^5
zD*avtL8Sklq;V=9Tm(;`kC9UqF%MBv(+}_iDhDysZNojqDqz>i(;*Yl+u;#@i1`a5
zy|t%|b#SO3Wz6b{a=-_WmW{4IQ}2IM#lBUy2k^wE!(yNX<9@~QA%$v%#>W!K=Sd2h
zsyo>9IO@WWkrs4)o!Emwa00rOt=rOj>Q2J)tQ2GmJUl@pPviL9a?tF-=kjur095i6
zHCusPV@j4<)qs<ypw%Qefr3h#=1fn!obx#63vz4UUncDM0Jc6)X!CTPhFz(CI6dzU
z98Tzbp6rZ192L8ehx7lypZ2yTbdqP-44futO~^W7BLeyW@$=?*H#|%TGWjmN>v+UE
zy$lV>Ddb#i6i-NmS+hGPQ)F&ykK{-4tm|)!mDK5$CF}5#LTioLKiH_Q9Nk;D#aNrW
zPfZo1>~YK+Uqd_78&&fU-^tOLBU&2s@{F@F@BApSp}z%&>@I|yul_c%ULk4R{+8$R
z9E6zA!*@nJ^ru5s^aakb+F;!QRFV;OU)V*z-2Yk5+Jt)CoGW*j9gRnf;GHKf?w(QD
zPsZL{!Q{QRbK3|%$a;ADBS$(#?tKfphWF?Z9(Tm%i6GC1-6=$o*QrgDDDplG*Ogi+
z#);m*BZc)DfC?FyM-j)xlDAmyh6o)LR`*2#KLq<7`Bfxu_#9-}qGijzLZD<GO7d3x
zY^t$Lv#$a*Igz|Ex$hbfD#;rg1}{IppyZAF9t$FcY-^W_1WNKsak@>3*OA(s>#RI*
zcO2wHsfr0aJVcO$Xn?aC6L|H!4q#pqqW)$N|Iy_dn#5G7MBH?cgy`Gqtq7FqZFT-J
z+D1*>VB6P#Lm!2*rZV>%jw;F9tuH6&a*Mq#BI^fFgbYNjzp9{v27QNX8%j0&3Fb|M
z7?X|3#>xRiQwHV<2f?zisCiJBQVa(LJR(hRG=-k02|1%*7bi5rtj^6_QsnD5IUOjn
zpe+vi`I?0#;q%=TSs8~INj!~pt&eUh%p2y6%4f1{J_F(4i%HuZ4^`EJS5M~TEU@d`
zf?{&!jPoq^qw>L-t8cRG3RM5FlAuIY?(AtpAA_YygZcTLbeiv=DIf5mY{{*wl@B(I
z4A6P>ApOulQ#8NmDo$IqI|a{Fh&gXDF}Zu(Iyq{s+6&YS_n#W|KFU{Z{}VXoqRb*D
z4;g;6Afx2!^d*lfSeP2WV)D3-%BVOxBp_NjL(Z~7+WzFhMM2j#au6+SBj*+2C~e7K
zM8UXFt!L#xP)we4aH20?hvv8FqNiI_s(_r+hwD&M@^U!!XnPsVgfDsZjzx447n9fj
z6eoWm&co1`yt)2GYA=h)+bbTZqw9&7ytDnu658mX5|qe~hL>Mhe!aZGpNxtHeM+92
z6J2q-+YrE|n#fz34$gWW3_I4Jn}?l$oeQ!YdDU(r-y~$vaw6xW-dc-FdCOmgsB;<U
zq`$+qAd-~kal@cX{}#i1aNc^M*Jl*OVGj>kZeO@6C!gV*`Yrc|4Gz_}`NTQ9tR8z=
zvZx%5RQ;^X(1<cx-gc&v!FbYcI4$QI!JKJ2PP7NN+0~1$RHiJn`>!%O&}T2+_FEjd
zsAB=0&0e}FF0DKIpJtkxD=7f%WvgM;p?Qxg{GDBq)v1nBZm9B3TS;9*Zo9ST2CyaM
zglh|lhfXR?!?Byso=|8Wn1;~RzR^RjQl``RBVbHUc=U0L))tEtk*r1tH#?UG7r}m*
zUpiR0WtM+vT=RiiAw@!L_ByAPRKBXwAP=Qc?LHqcO0It{d(-th5i1f43(W=8GO=5%
zj@D*xkCYoa?I78+7U-OBM0?juO5QI{dPIA#*4yN`|0*A#OG);AVOU_f$?@5TSe#%!
zuHQcUh|a6QqAJ9gcFb8!8;@8gHq!-hoiZ>-PPW8*I8Q%^oh$DUBYYl@blL=&bqmj5
zc*HWd-FPdT3Y9I;0b#)m_*iK(2E@GhCKxT2KFwS4*&dD`L1kTQ<ow53rWq#D8?B1;
z%b~z9u&^%U3gcyhWy{3toVGw*z~nA?N{gpaKNe5LA-|3raMge^yZ%bA#d8B1wd~n8
zlPFf!-2)#gK^;_QYesk2mrMAAF&Nw$j%|JlO|O0=R`}Fij8(S*K06l|3UEKs%mB;9
zK3!yP=H|_EZQ)yeS1kX;53Z)`vUI=wS-Lz6kKZ6QH>v+csv<2am$4zd{v>V~Ul-&1
z6vJRSiHoLHFfN#wNJO+ef8My1!gG*(j9(wbloG|1{7jtO_)<zX?+m$CnNn^iV%(HS
z*0@Tiyo)kN{fRR`?sYh5rIbpykpPH#>sYow(yhEHvA2|@RPq!OO_8W1fsuuYxfo+1
zDbtVo=;ehKvq(FwL@CSdJ6bwJ{Rwpd*;3pYxIe^hl6UrzQoL($_N!&yk;hs0#_2dV
zPW8jG$2(1p@r}A4L(F019-|dBJ&a9&2AS%C=kdO{#c^a2?W%HLI2?y9ZEGtz0M%;I
zmOG`R=~uiq<d!43_g${zbl+cRBh-m|k)8vf131Iios!+~2})yeSGiXn=pYx=7+v%%
z!(OkH!@=_EV)PkA*w=>6*lWVyW93AB>K8UOhdt*BuuS<-Nra^8Hby)B*hyJ~@>tGY
z?z82s)3Zy^{7@(>%q!ZdAn)fcER5_Qq5<qy(G!rc^v#zr)^O*brk%;NGtl;`W(8#X
zN}fvD8twM7uq)-e+<y@iB%hm)u&Ma#;t}1{kAV)Dx1PgE5AKq?aRP1rskA(A+FchL
z<!)q9=Xn8`wC}|>PGPWv%1r^%??0O9sk`NmKUd4CDLMHSPDXBuBICr>=U+#0Le!1R
z24wj=>#v5aQLd!r(!Dxq4CAI-xL$>K%wb)-z44uT8m~;ha6eKP%kS~@FbFmm219!B
zzqY!rzgc`#&N!)Z3)l)iKNEh|X#_{mit}sHDL#`Tk`JX!G?DZ{NseNxxd@_+!yTr(
zC;hQVfryUq?n-odRXo52*k0QlWq$$}sPXBEj!5~bKARDlS!E{Z4l#FBwtHD(Bi@og
z{Vqq<(xVVra5D+&EjeoZINl$~4Rkh#tu`(fsl6;Y#0Q9m&*$Y49Vsi6oTqBIX?7@s
zJXP+=Q=9SMNgl2Dnw7-vkR0_kB5o+Hu(5q^Dl4geb(BORq7jq0C06cW>oQ7~0#4>7
zM|)Rju+GCMYyC$3FuGm}s;q0ZS8HWaR6jMlUqpV}>^mK3VbL*2c$c8fH{(Mkfz+^*
z#K}i-S|5GzD2l7A2RPF_!H5%c`f$ba@mPbL162LwptDRbGjR+*f53#C8A!g|ovY0<
zYu37YT3<A#V8Q6-RpVTLSQZ-1#uUCylAn@mBBX>pi(j(po*bx-WcHC(b!9%0>KwCP
ze0K<OHhORh!?LMy>~z)(zW-aF(+oRoOgkc0%83&=*_D27R~$-&8<Vi7J;H$U^$Yu-
zF0V*>B^<hjxWPP)`PhUK%&kgODy+TJofg|zztnHadY^j<wjp2Aa^VXL`JRmGnlUVf
zws>p&$r7ZTa9_Z4@gAx+Ws~?-pz!$Y)l!74%!`*U)(2HQSnaRh!1g44c)!XfFSY7|
z!x%g@s5vtB;1*nMf{9RS$V*(@p{#%7lv-@a!Y*h+$v2`g0rnYX4%#bg@=x{|@ui>C
zr17Z14RZbEig7WTWTav@TS;wN<&MSlls!WHUMxU`)T-g~W?f|hxolkAHh&Z=AY!WR
zW{<jTKDd!esnWOitp3_q2BeOGNvVz=bfYh&x}JnmmmatW^+tZIo@74iwYA7=l{)2e
zpBpE^LZB){Ol{U#(Y2&AE&sw(XDySEJdE}TfKM8cQnL=z5PY`OZf)}2SBj~<PWJzt
z|NQbC^y{c_oGJ&*`3W~!gVS(v!VkrlIwE2>R6ZvimN9GQf5|FTwIle+I`MPeiTl*a
z3rj}yl#78M!h7A0&P@Hxyfjx{4djxXM!>iGBC1;njZyLz%sD?5570h4<J$SIIx#$8
zS$JZvoR5p^im+_M@`^l>u(~+QOQf<e>WN?HtK2xi$nx!|D7&Zp#c1AK0r{=)=tpyg
z0kyPk<5k_^{>}u1#pP*)-Q}J{`Vr=C0zbrkpK>1vHCcWit0cI)>CYEn{$nM!N8Hww
z(VZ%y<dIdG0+?{-F&;$mZJN&y#xWvvJEs{fSFHQ+#+rN^>Bi~@TzD~7*FTS!mgA>L
zdT{>$H$--Hh;x&tD@G4sb*bWnlG48qW`R)6yb8qp_AB(CvvlO7rU=^S44A<s_R@3$
zi$&=y(DfNhI~APE4qu2?Fc<N`mx$U7Y;{A5>k_L%Td?kEEDKXyG{l$6J_2KcYK&-S
zq_Y^B)TV~<yt6_h<#<SC79~cTWWLlB#uP8UP9d|NK5?MrtX^<02}~|I<6CgS*V)zt
zTiC?wGwIeU$(g(nLeJHY6h%*P=SH&@c}{GO);<Z7cxT-R7^A$mj^u0<<cacU5mJ1~
zq^27S(`_W&h&n{mEFsQzBM>v3&p%{yW+i@FNcYar=j>|hitejYA@`%_JS=^*AKCT3
zB=MM$kZ5XH8}@NJ`tz4a&S7TWH;OUdsQdMbMWQZj-8GJ2i7Lj=SFWWM#lRm&2_KiB
zA*@+7(^g@l*GKIo<HDR#cmU4D5(E}MYsLKa%*-SXF2dZdcsJ39GrEOu3q#_0Cm3PL
zSem&<Sg~nsHIi^gTJz`*xAQ=A)(z9B>2BU)$5TZ5giqMMpn^Y+D;vtrS9pEiM^&$k
zi9&JTHwGD1NRReC!gFYX916$HD34f<?w{G2{|2aDI@QiaEj{7P(Tf5pC!C*-C)<2Y
z!sR#Tf(RnrsJ0n=p>`8BTmJb$ktWr$F|~#~Mj3^NE$60^vX-ao7kF8}WNn7e9@h7t
z0_<wyWrDIW$pVelz>?hecC_UD4`H|Ym4Go}nsEph7+pp}V&F^MSN)EF+-XIJkB0ij
z(_-q%V%m&!9TY0#x*V#5${oTd=2IK_(xSWdqq1yEi+P2-f%x#MIKvqO8JwlGs>gfy
zEfnU44tJlp7>7SnyxiwnyYN(jPy8dLCAo1+$#>3{=4cMZ$+dx^zBJe7Gdfcw&3hLw
zhxnq_w0fZ_WDM{osx;J}B2Vr_vp3Kye6ggoR<E%sREH!JwSSJ(Ej*Ew)@cO-74r}h
z6#cpk4<l5rko(!U+f?XXwJyfbh|w`H;wM!ZYhn-MFnVHHSb)(iIYHiS7Qacbj6C0F
z9<T73xQzP)SzEMRKn$7mYI-G2aWcl7`awI{_EOb6Fmp~4%*C$)t=XCC>cNVB`2@ZJ
zybFymH;ju{$Ve7^vCT?Jmb7tZYVEO=vZ>L!;uUAsv0~pv+({$djNjxc+TIvQjU@Bd
zzp#SqG{lYxPU_bq{L+Stu8-O+d-q)L$tH$NHYWYnq!j0;#QKF7poib$=#QT*%ki(3
z!zXTXgwt0Lpq-xv>Fm}7?m-Tkv|jAZohAb?U$39vA>mG4O9N6-nMVURu#U<)0$)BH
zX>O#nXY&rqS&0<6XBU_<{HoDSl8*wdlzDfw70&^THC=)6F?C439C#N!XD&Rd9R#XO
zSFwrxqm0Dg#pg0D=7XYv%;pN8fJo(xkSh!iBLsBzm&H>M<m*OSBC&#>)8wvLs^~m#
zkd^3C^cU!I@J%k-s4L#>ku;u>OD5jI_Mi9JK|-RHEvon-7IF^J2+~Y7IMzZ@(UtLZ
zVkb5!+}^_Hsxx9cHDcgpbf{A*->A>^!BBX^6Pw7@qG{#~R+(z!$(?I64bBF9=WMQy
zUGUUice3p2)*zxjp@WxEQ=PhT^*i-4&lb@{zZ+~o*WhB-DXe9gH{>%TIIc*pk)}KH
zi&a%l<qnO7ySz3O@P#mG1!s#fU}_mS5b&NamKmj#^or`p7}L&l!u1DH!+65@IYnoF
z9ALyl6dpCtFLEnLb9v6&k1YJMNn%8QRo$_N^4UR_Wj5z%{&N`R_!YwHDcSyAh^Zmu
z5i7!m;F&eF<Wj8LTe1*&n{U_hW8vm3xsLWh7}c(4*Zsky8L($GTtBpq07=-tYJlv>
z&7YW>5B;t@ms5G06+O1BfPYb9L)a7$dfG4<;juNw0Gah{72T!Cg;_cuCE?0towJc}
z(>~cB10S_m?hGz4oDD`!a-)5Ib~f~2>^;BN0oefvPfqq>FW59YpY{6Rp6C2&!&uF4
zo~)A-ZmByY#wKn<yMY36ei7Y4U(Vc$9`MJac!_@_71sw`IC8mku>m?iBAYwR3hjUe
zhj+ZOxx=SIYjca7Tso>VZW;KbJT`Zw`Z#B!=d_Z$%Br#c{1tM^*kPN4{VlMQhom5z
zyQUXL0Jpizi(*r26VBhXW|X*;=A?-@hSZ6_JGC~KYmprd;VQ(v^fC?F@6Md`WdlvJ
z&>hiTKSw!9i}hRb@JVWi7N|)ApQPH`GWfDcR&?n-=WVR0Frnj9Zl;+*072+pMNQnR
zaRpNf?mks=IxvP&lmc%J2>mxDmf_h#p1Yx~d-$XDvi5QfmXX(*$RW;E)?n;1uAqxN
zOJUfgtfTu_TdJmEeD=uzNI0LR$NcGQgj0u^Kpc8z4j$-FTEoiCS;S>g0AQX!C4Ul<
zg}V?Wh}5&JOSFsRG7?rBo;0R3>$+>+Jb7wpbCv$BwRvZ)Z@Zwcc<0{@XqK}*%__7s
z%q^^BhG0X+L%xoI)&p(vy;Oz9sya0OIMKA`qX*;@Kwhs1r&c3BA3sY%ZVf~&(1w;5
zH2wUPA5CO*@mC(5D;FFHn_72|gdO0`&ASrW=apk~5QSj5+onIe+TcG_{KG@5a8kU~
zK<43D1D*Bua>a&5k;tc`-4sjzeRL2)rS2RV52YI~a*K<M6s(DDHt*5nOD|e*BqxlZ
zN=gsip}Q+gFP%Ewp(|ImMGVTR<}k`3b<sFDh47G+9#av!bG|{iB(>$zOrab+lFs6>
zK9rG`9|)+Jp0HbfqZ1tKf0&5WMHP^JM*FUylhW<`?A)~;;;12}c)H8SEu$b4(mlpc
z*;K2Grd+h{ir5Oe-Zg6XwuTOBdJ7S|`7!v?TQ*=1EV#i->1}`QWLCbJCipBlVS0zV
zov{^AauBM*pO8El5v8y|C3G2|g@961Nvd*m&6nP*j2m;QUfAV@4;K0zni-}shCGD9
z4UYKF<z-~}6W)!9vHqAX7$)y}WSyAIo79ME1TT@P>$&4(6tjHRr^!w>Wol3vR@E1y
z3(&~<a}Fb}8t<+n%x_B9N@3weq$MRJ%fCd<Xud<jniiX=zf{78(6P89gJH(6@mpG5
zkI=@?`m_CVOdSI3O5RtMR=uYdm#vSL`K^fFU+VCuM=BVeNSY2YwZf_r8wkG{dIHEw
zpDxg*25B*O$LQ$17PT)AL%?$3%jNwwj^mDm@#67njO=C1D}7WQf2;o$i2m(hzdI3Y
z@Lt0RVtWXWF5sn+mK}(ZJdZilgzuB}l`iqT@a`p*2RJEp<#J#!#>ptS*IL_OFCa0a
z$X}uCpp@AB8KEv@ROkJ3tQn=!{htK|eHoFNrKyXdHKY7FyVge>@EMK-N*U(UT+DpA
z6T(N6>yyfT8P)ze4aKUmfn0rjpOugf?ubOns9kP6xeb9!(wNnPKjo8Ld+MXi6o2jP
z4FCeBr2m5#y4rlobiP&j(jYace3c$IWHf2lCM>TqeE6`TNK%n&Sp4Ce1Qz?<P}J}$
zb3{0c1^=jcP(m^?i5L*_9X~)RWGF<&kwXz5zPzDQI;afg3<+%m)0F7&+KOPxfS&lk
zkkH|?#<KTsgyyy?s|37b>XJD|`9<?yRU?Y`m^MZE#j6?uCMBY{xo;R=wjtnmrusuT
zo--y4sDDeL*WNaoSTu1&Eg$lCVda-PY5`MS{DLy0%IC#1udDrnShMVxaqF%rWwfZ`
zd6DkTlLaiiXk80*ACAEG=4tP6hXhm$av$Chwd5Sli;9nbC~KXG1)fC+_}K?cO8t%0
zUzlS9Vwum|^E;}^7u|kgGc)KBOumUqZ~8##>C!7Tm74U??aiz9EAylUw-3j=*M#-u
zzfkCDWP8lh<`aR+FIs4O(}zkM+e11izkH~*-a`3h*NQ)tUs`CtupswnXV0*G$}jnX
z-0y#}Qu(EoRwggV{h{`MD8J+ja)0dQ3+0zKav5-JrD1tN?oT&9tp&N~+^WKc!O0F2
zntS0}OlZ2=6cmnh;jWb)2}@U=BZ53{OG!7|t<oWPPTtfZ50~g7&PdM|4$^3lJqVX~
zh@knZZe<Nrvey3h?-~xltrUVV`8<K2_NNAj&l6JV7x<7gP&2GC>Gl+h!3CM-mc$~~
zz>zP^IG=7be4a9KU+b%jO5dr6qCZH~Lsi@efzO)<K2L0&4HS|*ar+TfLhA<8Yo1!+
zx~TXzPf}rQf7Pcc&<iphUY_YY>ss)bHUP(}`}$~Vp1RXiwG0Me?o*kb#$vpDD-|r8
zGw`he%6{>Antd0kud>zj2tCwp_EkO9@!1JI)b(>jIj2+7^YLLllwCJV4-MSCP7e*6
zHGqTI0yydiL^Rjjh!}^C_x0lL{TMR&@pF!47&5*5_Y@Iw9>6b{)HCZFk*kNT7!?W#
zb35Rcl#qQ}@)Spg%FRo*!fhIt4Lq53<wTuV<l2jfio}yhn*zqu6H4<B-($B;F==O)
z%d|adcZnW!Fw*|^|5FisY{if2Z$xWmW`}%H<@ckKj`!`Z(t^j><osFbI}TynY`BM?
ztAy|paMRJY9m2(<n0X$NuI){x&swG1o%ukKtnz!ys&kby<Z;)nI^_B2cRJ*C#vF>6
z-$&pLZ!FgVCLP|ulMktM*t~@b;I%CU;YW3;TM6Q<<nx9#Mz~O(O>N%rZ*X45flS%p
z<lkHNJ@0ZQH(YTRG>KN4otNQgBIeSaLc)mVa@rzAe&I}221(y}&ncfbZu@AitX!RK
z({+x|m6ya;sWv^Wuz4LB2$4tKIDKAsA|ePWU15?A{~M%G8kS4L)&tG+s2Zv~Ur=>C
znwPvys^ZluNVL~5NTalDyIL!T!d|0|3^2F4hR1N&b5PRuwW8^K`@C5>`lznnZUg`0
zhA5A^*EK%p2U`KKIqBCC*IHTwtYIungTB8_n@I8wf2ry>g^kT)hQNfU7ZK8gqlg5>
zuT{d7k`O~wukp1sy?G}pU_#D>US%lFte!gGNNH|B7s{d1f~?OeA}oo5Pc><4W#U?v
z<R*#vHs(p++J=Q_F=@j$5=Df~7m%rquSnRQj>u^WVh{~23K;?uvPK2FlQY9+EHRWU
z5@87T1P7L7{*zgWh5{pkGn4DbjY>3xJSz+|7|<|4jd$(_G?WoCXb2prnu}`;0Sj<T
zng<%U1sZAwWhS@U{HBK?WS~kq0Hp1n&J7Fz*k1+v0nC~<)fj+EvsJJ!+Ud3-237V^
zq27Rcue%GXUMkcRQ2(;s0QFFz?tlhASOTb<3UviEvi}M|T~w$u+8ldvL_k1NKu9MQ
z%mO&6+=n5oBOUWV<8J{0Ax80&VNcPOk5tO`sBwmH1a$3Gs4bwG^J@cYqe88NrQ|uT
zpn#B8D$)`}^Kt_*`W7nmAsSsc_~!`LljeD#5uSZX0pha5Mo>0YDL(+^YG<*EZ1S3@
zU}J#mYt$`;K1Z}19%NKLNkgFDZ`%>fM$#aU)YSTahJfP+^R{^(m>6D9t)ec7e>(9+
zaR%05U{InVtka?(w3F~_@1a8shD3uQ!cd@2FltXgcB4AMW$-8d?=yV;LNbc~DOe}i
za<Ihtz)1Y0^a6-@WaOtk2#t86<d0k_HqxK~^PiJTl*WJg%EWUy9cfYF(r^lh*MrMb
z#C*GZ_XrG<RCMocijL~>p{FG<I-bh>@3bXsS_t;$X~DughAFVw4fT!{(x!^>KLdl#
zO)8@UGwp@y*1$)Vr&OgYcCiF&nFllNrJ9f9AX9U}V8}JP?U9T7!RY3GK}(tT3JsU3
z-$|{sa$4P@`RIg0@AXBiHyKWgX4>QD57a}on^aLDFhY1|HoWBJ2}KM+0pNmQc{tz#
z;L2~Q52bRtp?mG=m;PN~hyYEVj$oD4X(3hCb<<{V`0E9OuC&eGRGb!;4{Wh3AEjt-
zH}rB4X(kh?ix%l;y=#wZm6>)T-RXJkQfXZyqCI=&zQUwFn|<(>?<(oKooOF_wJ+pa
zt&ef~m>wTd?hz-PJ4O-nl!8^Gb=+y5-s68vcnRO-{5*k8DZys7UQ|VgiC;gcs1uq6
z;mdX97Wb`D1!E_5ttbX<P3gon*}v+jHf-!y5(8ICGM&(+cTm9A0wuT9j@4;|F3<@0
zGjE?!u{>X|5e0e}%)2_)Wy+m&VUMkRB^_3K|6iAq0wPh7Uw<6>?KLfEIhGJph|ri%
zb^kd`KdWae4v5xOFJ5?3j%o(;wNR`8>IflC>^t7x6{bV(-JePOAU^(hGDR%U|1cCI
zy%Jv+KdGzd{r&Y^DdT&ip=h8jCAh|pG68-3yu{Q=O5up|LFm55U;rzp6!*pPm=PL!
zfx!}X=|?0aQaKTXVoF5V){+FWr9}1mxTanLQY!V`L0U0Z3&1>DEUr)!DV~`U+c)%d
zUKbf7bp4#^C3D>G2^9<r*xI0Jg|5&F`17XNuG)LZt45+BZ%u;oN|73%xHc-|u|V|6
zobo5SL8VhnaUDAke<m_4Z<4jJA2Om3C|tMGmg@NmH+(oX#81i8W=hi!9XhR$(xUYb
zmGTvB^V_B{QdCUoFk=%Ol(?>BrgZ6*bKE};QzHR(e1N&9aXp(rZG33hoznOCCO95*
zqn5if@YmTC5>tjvZ-Nw1YBOv(9i6qWOe7FZ94r$$-YZ2A@#FK$C{tUeXSXX%Xv{ey
zmeoN2i2Ti({Yg!|fXtmWi`EtW?YcI#VXg2b<CpgMp_aj@>I!_%GTqSEm8XUWF(aW=
zo{<2I;pXo;?JsYjoWO>*anYvWNc^r1t@hRrULJ=h6bFer)+F!(^G#sD>Ok?=<Q*J{
zy3G5Ue{0hj50>BS-Y!5YGyl<}bp@TQTTU!FUY1Z<{%Y{75JAl69!y|ds!f5ZVF%nN
z2beF7l=K?La&4`y)r8xQpN245(TbzP!o5}fjXWSeF1U-5h%Z|8p`*0Csm%AR0C?JA
zDE$w&#KTfGEDp$Y1i4C4*2;8*{1QhYo1<9VnW_PciQ36@m<CVcDnuJLN9liC#-RT^
zPiH#H);+F5`2OMDp>!M-PL>L0nxGV0@?jqUWIuQv<`Z}5_eZ^=!@Bl*#R&Ya*$1Md
zMuSpe1j=+I9Q~Lo2Ae}1x594dgTzRrY)Xx1g$R`Ca0ia1WiuV#5x>!S5FPa#xkg>V
zM!#QFN2gd=qN8~Um>F7&riN_|U`0!-^^Pb%ieb4O?amc}w9|Q&99f<aBR_+pqigq~
zp`>W0qvrz)?XT#_9y+tIj%wf!KXaWch^ZXb_A?!;jP~xX9Esj)!etph^T$dAF@GHX
zeQdyKq7y9BRtz^0Dlw-FR&btG&9kate5yDw;qOr=xc1y#XOvH@N<TpMgJr>qw?&v%
zP!|E#-zD~Al-bQIn{26RfbgS))@AX#RtI!s8?Vnx)`^m3>$IZfNjdY6tKGG9ROVf8
zA;Y>!+WjCjh?KPKpHZ~DwMYHa0a_<4hd#Ppk`f&&jD?<b^wjx-x_Qj)TRno(T&PrA
zH<+v6jAHVq%`Mw!HYgz8G6|GWytnhduIG=tMir#hKR?}>ma@Da`v`tk+<aQzrzLV7
zXZj;G@a{a0<BSDyL>`ct8Zs?JCnTvw-|sR<pf+W17~T_#A=T8=9VZ_cr~(g^{o+k6
zJ${;O6lh;vZmjI0Z}inxct1QS0!1_(keOQf(o&ASnWjj!9!29km6%#%>s$+gq*U7=
zT07Dn#f~xRB+-_da-pZFTa3k2*C+jrq&hLxYkZ_{wC<r+g>+Pnc108*kS(?8^VVK0
zMj>QWEnBX25CxE#+CEs&cQ~uf!{mU$fwXAXTfOuX(yLQ+2x(PF&0eRU$U#S@^4}KQ
z?8`yo@Ws=)Mj?!rF_v8+k(gYK<;98RE>m7IPc41er?Dy%`CceEV|yRA9n{u)U@|^)
zYe)&5#MhqF;5wum6k02md8f{Y5=30s?ICSfT;}UZIbU4$Wl4%yzB^JKIhDAY#qT#)
zrS%BgGL!srhC!Qu`U+<n4kIaN{&l%*rWNAqvh0gl9!01uzXx@!LJ;#GiEvd_6{50-
zFrQrBxPeaJgr0d^C2%&fD)IH74{C?}PaGm#-tG$IyCB|3chSnle<l{xO~QjQunPHV
z%uj38NYhz-;=dD$(V8r8Ewj1FW5VVPh&Ue`fvWN(y*I;x-+C(WD?7lj-d`IHP*={v
zCyK`MpIfe^gy=y^B2EIl&XRAZBn1#mbVfY#RMSD_uXKzcP^Qy7a0ti9OqDn-7q)P0
zY&-==>i|o&`O#)w(VG8+a<T*chIK(q>@<ffEcZ9L#?;cJsOU@^*Cb8{d0MxN(Lr^V
zN9zkVoDpA?P-QxsCVfS>9-_0wtq5dJ;$}#6wtc!7shtSaaqn9?8=|wz-UR}olAJwj
zP<10Y`~E{mh*U=v)(7Cl2`QQB9J;Y6XQ{BYdDP?|RNi8O-Uos{-ZnUp7j$4UK6!PI
zV*Hn9+GLuex-Aj}emVc_#^T}>nU&N(iXvaX-G@{~T&da%X50E8pAiR{mzYX7HG~)`
zxFU5-Bb}U?*G%vR=rD0Z#45V65jP*apbk`#Sz&uDw;Hp#*qM_|6^Xdp^olEF#D1hf
z0n5IgiDgNz#NTJPqXo@Jn+Xjy4XU(fIr(TtAyUqArW<w-{Gcu8%kD$cB5oQimp?8Q
zMv?3Pn^~A5|9Glbp~!<fKO(IYU(eH&1!}MHp#zV_1~`nh|J}Vh#K?c^zWCPo6aVYY
z?B=O8wS`(tGZx)dGXlRUkTEa_2LYLB1vlU0B#sGJTG8Np@YGQWnf#`i>dewpg&)Fp
zpQo~=mCLMaG`J`#rd5315jl=Xbup7C&`r0PR<+v<WE<kBY-u%iU16K^G7TI?Z5Wwp
zwVa>mv`d<F{7aqqq@^f(Kz?Nw(_ASFkgJGmBQwoA;H|#4dL8xVMp~mCx8ak;6%^B&
zja^sG+PC@QJkwL2xK^L^7j<Oq+xFm^#0gTs`9QH##Y&t4V0L7pLG0dmqka&5?$m9C
zs|-4b0UHplUFi$>AUu0!VKHrJ>D$rZf?&Ca*vVzXu*092HnLgs(!9tUy9dJ5sXeYc
zoKz!0;TQW!lNM7%{Nx0-2xMjZY|ms)nwa|dG8>A3)bsVKKE)}rAo4V=*|PXT(LhSG
zVtSp5)@)+PubqA#X_NRaZp^)o#6mo>weLDFMRo)?FHMo3AC0#YMA+NbK{oTkfh$GH
z5^gy>THn%f!I42~5l`1SM@yN{W>l(cSQkXdEEitYp`8}4T^=69Ppjphqb~SRapMvn
zUVf@>;+RtJhnapBt9(gyzXnXkU+%hIo&Uo4Dz*Q6khB0<j?@|%Z@P@@BT5SWJUtAW
zD2c9u(<UQ356{-FV&T}o@=&JB6#pp|)=XFFmr;~gGhOB06sM5rir%}}s;jHYy0$t!
z;))%bn5d(wdGfrTDsl9^I6@`5?1`QV1hToDt4#rhP$V!SW6GG^j*iLZs#6N*eq0--
zX4L`=Q$s{ogI2jwy5b)cTuvdk>%;F4;*3bAI9zQ^hxAj>;reLgP9nYOx_@>Wfihja
zu4mJ_L|4C-*E92|zyX!|yK#Q8IKVP!<)&mN=;{uxKLj0rHrI%G|F*_nkmm$^cDHNn
zFc*5tb&E;uqy!krDCU>`PgcB)p~$D-J4#UG^J9|>Qe^gQIR27)=FJ7SYY1C!PX|~Q
zMnoXbkJ_A3Vkg+*(j9_s^<MR+gigDxpS`%8zaU%TH=qBT>Lknd$sx$Iq*l&oc75X1
z(d;QbGl9^U_t)AH#J0i(T!Gpo2#1>K${n*74fU5}$JZf7%c-l-OMHWt-1XKn1TkNz
zb%R}!5-GnjU>))waUC_^_#={Cs}rg_MP{VtQL*nnz+IEwD<?cCv$&Wc?@(4g?SPUW
z01bdY%ab1WO7Y*Fec=~xaa4jIwZU25ObInn<o)H2Mf?a;67HZfL5(9&%&#NdA$<nN
z5-8JMtl)m`_QTlOh(k=#ZQ9rz34YYFM)W(;U<oh#5($1(5N%|-%e^-1nB5(HG^iY*
zvbn32#C1x4y7alLzMN5+(24H2b8rvl8xY;K90sH^;@Y&irB@yL>5lnrZpXg+@?FZz
zyoVC(F6A@^Vli<hwh?lNab$)y`A}D9{nEd+)2RT_-Q+Hod)oGg`#1LDRgFB+ZH7HU
z@+q#5qPycX-BgM0Zd*%L%%cJ`gb&0~jl1`z$i?!luBrlnA{i2{GZqIV^sluSY$D(K
z@<%zMd&vEej0jM2A9myb*fbOxyC5ds4>3NP_{bF-2_lV;%%2!O4$`ysr_-V;5h~07
zv32e7HP>(a?1EvkY1Y9o$Ikc6eLHr(yPUJ_Y&++e`(juk)G!+6mSJw0TpB54YH0}(
zxh0pZP*X@Ksws*PYPn=Wl;8XLeE0pH&*!_}AHA~YJfG|Ld7jVhc|Xr9cQX2klof4v
zW_l^UaBP5Oc%xZ4k|gofukLe=b|`{Qtoa=YM0qaxz1N=+@8hLSe`knYkhd@UUeqml
z*YgKC0~6ebJpoDk>@f`@C-hMbfiK<)VhpAOKVX3nA7G?ImtFosKcu4#*CKfm*MI5w
zU?g=GD5oO*Z6f7|gV;0)JZFsy07&BNxlmXbQca;9z(jnD-%@j$lAfzO0MHoy_n%G*
z$GTSVQ8bJveA<m+?E?*T1Ouz~1*O}Ua3B#V_YybwiIj)e$~t)|B(kZ#Ih%uxDCQNR
z)Y^xyX6i`wmlYv55yusq8Z>}gXt5+1@FbKPvI{o}JfED}<kxIKa=4<N)Rw`C;`Y~?
z+WKQ03UpU<sg|oHTpO&r?Z;+`9Rc_#3zwIC19GZuOI$M@DIsf6cO5DDyGclW#Pv*0
zb!9D$(2=@!92Bi1_53x^r6cv3+yhu7t}bh8|8L+XAr47SeL4f6ZiSC@e-ak?)FCr*
zzGBz*+6Dl0`puo19rF8Hb`n%C?%6Di+I$m%S=82oU9e_n{iJaoJV0wyIupbgq9<N{
zAJ=K(PEStFFMxN2#!4n(Mz@E_O+e8E$~0%M_})fb3ldMJ2wYN8RZ*xwF}>OV*S+Ee
zmuW>d^q<pG)MZ-reT}yOdG#|b#4CKu+E7ki>7eECl{Q@1S=-xYwJrZ(WkGu{kvhBM
z*6hc<6tV!gb=p1UhG>W6eTQG<dZu_vNC);A`6k#|PWobg_;cP0sfn-5>5W9n31b;D
zJgM_YUR7`nIQ9DBr@TZIlq=G9sdu4d2qvShb0$UMRYL$8(QOw#{6~DYqlSOGf$a)@
z)jpT}#|536gLHH3fkc5vsw(U8xJbD_Audv+{5RVlX_M5NN!-$W|HWzyl4c{UX>|r%
z@WG)-pdv-m^Qv<K?p9dQhTk2iD=^7vA<y?1CXhU7#*>#hgAm*sepgOEIj#Bh3}js5
z+LhBx6QS%PN%{r1@FJ<*Gq{2jNuB<^+CfK(*%=ZqkgRF(MmTzjI-8P~IKvm-Dcok8
zjVyI)UYf3SmzWFV^?QP}?)$d26!_${-gj`rsB{k>ztIcO)I48Pze$&UtDQL1O~4B<
z1Ncu)8#t@5Bfl9$58P=(EGzN+ir=;GBBwo9R@hHR%4rqQMj%<!a#zCIa(5M|&Xksy
z*21S!EbK{}JgzCnN0K}3gDOs4Krziq!M0eu)-%ohgiRU0;F}iCVLLO8hAk$>EidW2
zmn*Djv%EZOir9*@D)SQ3AgOXmI`G!j7)#^}85O>o5=d)CZU_>Y-gDu8O(?c`<MO9O
z%8v2rExi<9J7RzNNV`g-B#wx_V#8RLkQK@inTa(WtdH@FcMtNRC3gda+X(5%bu9gS
zM=U3ns6!+ZFa<Mt>T2Docz@-$10dIJz9@A1fo}Zwr{SNQzQ^7KKP#gr7oJ=n+l9sB
z;kl(ziSP35@WvwL_W@O*0>yMA218H{QuV!PRb*j5FBg3*e;?`IF`V6m>i>PMIM7Rh
zBq49oV}H!jEjb=noz3rX8*ow~SK!(Mt?SiZqzr&jf@g;38Bx6^(N<UJr|h~=xGi%v
z`+hlcD{*|XtL5)ut#qV_Q(1{#5}jz^K<sLB8ty$}*^UDiAOn+7o%KB!E|C<wCPGiL
z{}$rWaXD?y<^sv%a?Mz~Rygy-y1IsLsD59>w>Nyd(BNx$7JEBaua6%rG33#Tuk8i$
zApzGGhT8J!?T6q0TU}Z8u&nB~NUlL`hSoQtkT!?1Yv?ricxWWr8Lah{hPT9(ibiD9
zKk8-JG?6ss$ILu|<aABQ$lc`QgMEy~No(s#gFNMlw>c|GvNt^`tWN#!7y2+~Xb?=Z
ze!*@;T;k=zxs7pjRL^TvY++bfzb2?%k&NKp*x&g3L@ybi4C^fJEaYXaF(sNwp~5Tw
zHrB3pbfMQMl)M>-#6@atV6nW@f!kDoAg>Qu&DkKT<^AVzb;1{twvNA-BvL*~#NsLN
ze0;%R5h#}Z8^m`+sr=g7Hq|Wj=~vUIr?3;QquJ?Wc+H=hUMt|Eg;6K&y^&1YJO1NS
zmruX%s~h;4t;K=$wp9;2*o{eZ`bj_c@VC|9;{5{A7d<zDZ=D1n4mTsxm0KC(L`r1>
zT*w8Un{eh6D5g7sY;UPeKiv$)`AC2?M>d(dw4V19{I|Znv0iC)*C1*hx8LAO?zRCW
zt2^LzT%3qIRgb&DxM`w*d)&bnUgpG%6%Dnry{aZeB+c%oOO7?Ezr1?rtkITjKhj-N
zxFaT(cdx(H%OtzotaCK1x5V35+1;_*^7=+hg{Dzfx7CS@4Bca*TP`yuc=>Qw0`GCz
zZ9fa+qLo&j1tjO^VfJbwNx^860-v0Pp^pu<YP#?5C=8tz-q`8x_IE>wKstGKY5Gss
z8rWI(KGGxHIF0L??9NQUBkD9&o!Gdu#&6;@j7`p<!zYp0NGLc=3X0Q_hX0E<BaMq5
zZt;0XPnzAqOJuc;y<OG1UY>W(tnP_jue^le3w$1T{^EJ~>T2Ie&t}wu4-Hz-WJR9y
z+;H)PFU@;@XYG0;s%xi03o9R*g+kJjhA}w;#q!!8*o*Qlty~olCa_3v-VYn+ohhog
zbW3*UdIPzZ)*a61C>GjyxnQVB*%E_0RelK4j!8GW3KV(Q_Yc&o4L|H7ti!?^+u}XO
zz#t#h()&3IqpibIpEelI`q|>U$5dqCC+%}%maXx<kKmF<6n$HKrt4%3aprj4dsE`G
z_Dq6fxlVE72i?2Pm8Q!Ye;@O(*Nb~n`4Vq=0Dj6I7Yp0spWjh6K-Z2fJ})xdr0b?F
ze$vCt#x;o3fDh0SJ@GRuTXVZhjL{Z9x9x&Xx@KbI=g)vyP`@Q(E9zL*U&m&PU;1`r
zJzX2N_!YhGMbsd!`gu>C8pPGpB3joVzI!sHy^iRK-{4v<9&~K+AH<X*)sXNRZ1LO6
z3mVlZyzA|7(Fg(b^Fw1~arRgCIAjmv$Q}&Gst~_FPpOxE9>_=&YsSLHuRZL+R}0CF
zI@~;PqQOuuj30FKvDr(7;S=qfCS}4`BieV1u4d}$lz&|Q2{-S=^~=l!tfVSzM7z{z
zb30v0^VQrqHXG`#1@Zk^??7EW->s8H!juR1gjt(i+kAIr&0asaKl^dMJjp?VA)_z^
zL~L0V<Lukn4`(RAfX*XP8Q!d)<)tQ}ZZ8*{U&N1;(BRVSu{G)qdA6)8Pi&lt&2>VP
zEsi!km35&-W|c55Mr`dacIr6g1j|WSQ?W<w$11v_PADrJRhrX4SJ;+d>z9?S5j7d1
zxHSp!8{eyMfLociK0r<+>vK!%*%FdE-4jH@ccm}(e&*E6xudkol(V`mA$`!!gc`)2
zhw|MzqMXpj4krQBuPunSg#Mo`HxeH=5KqFO!ttEBXJZ@IDhP*Gfe#6k#sX0ATzF%y
zzER)Z)Y}1D!r0Xgy;bxiOxpVnj0o2mIU)awp@H$aiiS#kBz!Z*J{&>Ks#Xp()1340
z#lgcCz){}S=cUFL$UI+k(b%)k=!!~9KF8@mXkgip!@~H{fV8qIq*ml}{dgrP3ERnp
zSe+(fE1h__zR(Htx<*Ca_(`G>Y@Ad>C8RAMVPm3v2S`L{c11&5!iP_UwA9LK2BShI
z8sC$$;YLB7sEvbhITjtCbm%Ou3Q@B*m$su{pTt8yj}9`Qhz)1vSe;(QCC7Yf%r=j%
zKJ%G~v$1;Gxw|#`B42!B6h5me6Esg(55mbao1>U2Z#VIyr+J|-w-)UolTiC)^@2tN
zyYp>(_I1<=2+p`mFDs^h=)qV#QAm$&X9q@RKdF8pNNtL}mQ_IyX#D|Iw%2R1+27Db
zu65G;`fjs7_KIj+N$Ty5E*op8mfhIod<%Xi!0EAv<#ptiMA}1^`XGJMgw6h9+md@v
zo%$KxeJh|r6Fybf6%q!(Rb+d|6NT&%(VzTTm{k}Kt6;ZY%_z{dY_rEcSumys(f;G0
zCv-%&-T9p#)^ZIY!{)-B80aVVr)y3w_7JMzkVFLdntR?k-Hhr}KMtFnJ_8RwrEA1y
z@Bd78=NiO;U!ND&8diMBt38CJ3q-3uJ8!SQ0p5>VFN1sGkQ(O`Ix4a|Rm*)|n|;jp
zgBVd24|)>@tZKp`+={4ks#r;@eag~iYxqqViC4kM)2URcD*m8F&l!6$m^mY;mWf1o
z-medhk;609#;NS0iJSZA%1TRSW&$?FNxEg(8{%QlT)ax$wxKHdt?l38NWv8}uNiy5
zYe=+3gEkiS_2*03mtbRtXqc=c*nOO|DJSkRZ6(2|soz`I9j>o^UF!ADtmVv}awD<q
z-70F5X@7E0Kf_vI;|P8V%AbX!@CeT2nve7fe~xBAl?kf<>oLpCL{q;AXr^!0kFnu=
zXza!jqrUI+^y6@;4i<X%V^v9xZca_V%&zgAAz$437e22lqG&_Dnwp6%a!yml+W9^}
zFh^gh@&h<T@LiT}HHZonDDvOW48iERGq3qUn~Z+ciQH;mGT*xf-0j&MhGxsHpkrpW
z<u2CY??$s~N9c^0V~_&Magl>&H8$DNpmSMc9VvL43+a{A8HVh89F6~Ntvg#gn)dFr
z6AQnxOp<vR2?sMri;A7K=~J^VLI#4YY~xAS5f0N2$C~hBfSRq2$ZhP7TAOSTosJGq
z{yLFvD3D1gg6nJa>GQz?W=3|%h49H8$&JY4uy>9XHO%HnsXOUOnz%U53D4o4Rg9us
z12#vultMPastlqtHb<`$l^v<DDkE${G8^xMQB|iGB-xSm;pP^)t_=F+Ab04Y3(vED
z=3(8=x~M)?I9cK0xtRg{9LSDQRWyEXWH!gxf@92psYZd7oUm_aZ6oGhnI}k`G-Vj!
zuQ-aSpgSJWHVCe3^6b}#iGDTad0|zF)G=n-tJQSjrt*4Pzfie(N%OO9iAkLz&`itP
zedK+M*KC3zq?T0tSsZgUV%%PF0LEA<`Jq6#exRPe<HU_?j`~Tcx%K@s#_5`qHsMWQ
z1i)<l0|)UO&H_a3eC5rCK0cRfX?^!y=0h)<d$s@%lA~!Oi0H~EJ_X3T#1%ImxLwBf
zimJd+R}Q^aEG!>HJDQu9M%`0og9dS;p$;MhPauG=g!(Hc7LTNI>X)Q)=PYm^%i%to
z`Pb4OU37ytUkU9oOxL2h@?aLT$y_hwThGgDh35j(ogW+fV*L_2V*01()lV@6#{OJS
z<VUVuK==<(t0OT>^t)Bi$lE)RY>5F&ZaUDFT5&#J9ZhUd%hAS*C#s91<v0i1De6Rk
zEJ9-Am;8l=0o6Jao32}dyD1%fNKR~7D=4^LhWA1!HnH_p?(QMj^NIl*H(-iRm6^1!
z&idJ5?_qYhRplDQj6`exFBErAhYqqO#&#<0&CfaOlKs~+BN0B%tME7!(%XfzsH!gC
z7QjUTt`;Jt>&b0iDMW2@Vy~kSp#sRqme}W?QX93Z${XwVfZ<MNwS@05xL$s+ag-`0
z;PWI78+r=wAe=3-B@X{HB%bP1zbg2`6Gwkg$6x0ul{og+=5|6~<iv^J;%#;mZ+H^(
z*FRiL)u|?n#C1md$`Ea&qzf;$iiqN8j%W*-WqS{;nq^?$zUY(4C$!Z-Fbz>l_io4O
zb3=^_>J@!))1_SvQzurPfm_CCb?8J{or{wM515hO?U@&59Ieh6@w~SZkWZo1rf+$;
z40z=2dxCMW@2W1fRBTs|9!QVGnF;yhH~)lv-`3J=d-uOT$xp1hyzN6_qaz)uC+>XY
zuj3!$fXHpK<Zs`nU^9G|e;5S^BED_&*?L**_DuChLJy7S@dU(A#^o+qt%XwZwWXaz
zX9el{ixoN`)b04V$Ak&9+<gi6r~FRjVSB|atJ6bro#fNP8Kg*r_ND1EA*r@+0Y0Y!
zA!csH!q=AS{g6>d69g<ftgeO*oz^6U_!dQJ`XA(egK+AS@y^+{nh>&r&94}1ixgA7
z4gwULBwgfAL?~uUYFDZp$%O%R`ul8iFRmu2yX@l|=Oe}BWFhAeryp`sd}lZgi=^av
zJHy3(xQ1-@7b)rQ4>gLEp0B~Hn6Jp1)F%m#E7>CO2q>dJ@eIZt)~rcS|I>;<P|A%T
zrqLHJ57~jSNkfmE6>x{vr0l~rV$ax;Ms<#xOWM1(`t6%d=9ue&+ysCGxKTt6hh{nH
zg`EWVQdd<-V$}3SMNjzohSXBTQIiMk3Cy!&l`9wZ1X;aB#GW9ka0_D5U=X}GkmfB+
zJzFhV7#MR-f`9GeKkyi%P62T(O9~4y=JHxo?3*2^$qZP`C99P6T3rgL*gH>@b>i!>
ztV_fGk*{XsOIJGx7#s7J7Gclo45E3*@x#ePQ_VHiy}Q$f=Ehu3wWIefJBei&_lUWi
zqRI!JDCHEMUPbbJpC}&`!S~C2<c&;rCBk?9_*2*=@>NOS-dQR_uH+w{Kh5bpIU``{
zIvdU{RD`p`KIr@+(WFb4j${Y&U68MJdt3LadHrTkJ7I22w^QJ#p*~IUU*2^0i*F*T
z!^;GanE7Qaq|4{pHEv6RL26XttF=tBm|SO1W@F<Rb<#j`CI{AE@RI?XJROuKxEGEI
zJg1x-dO}}av+lSc9HV|^)<U?UDp8XbP-2rK7KxYgp5!*qe}V(CP^`m29Ig49tjV2S
z9ZZ-4O&3}9vEO4`&SQf-$@bgVVfi^z5}S-P4%KHW#S{X0H04#OHP@sqx!dsKNf5PK
zPCsSkfvX1XeUf|aFYYWfVNLEk56_C?*)29XtEfU~L{1)@ozs+`Z)@_iX1pM9ionJ&
zvLEadKL%TJ?#+tTB=)N1q-R9L&=|iHM-KHIrb&U1yfCzx;(n;?2QwCW)!#hrsjF<i
z%WKfA+%oUM2r6Zoy9j<_z#Q{9m`3x{;_#X&(9Da!H1yKxsPx)o-D14*19-jiRY@h`
z<w@F1puwopiw!p+`<Ccxyl!b&h)~Y_{?d?X)SSA7qb=fEUwP}#jkr4u^4^1@?VK3c
zoNvRlw|-AQox_jilfOmSko4Iw93zCje(~GcSR;U4-u=f{FRpFF*DRgvVC<q1$WJ5J
z$8x$?g>W>G&vcy&LFder<=lTFi}~VjrEGo3t6m@IBIBgNeC@QjM<t_o<Hk^9bw9Na
zPlmrL>fv#kA>B!U4ukhTKOLzv`ceN@)n;xATJK2$oxUHQ_7PAqR%e}8;L8q+%EM=D
z&IZldMxMV)m7T%zrFi2wb)cxw>TLX9%>~UF<_ou#ah$OMNa?Vl0pAsm)BI68(f`Qi
zY+Fz<g%<+W<xUlm(L(2}&X^bBxF#ABWJ*d<^@WyiJljt4lbuN)z?+&M88Rg;4EL%8
zYazYqwnmZT`lzA@n#b8=@XzR-DjOi#oKFVsoKC&tu!vS?zuf@UiUz{!9QXvZmpfgt
zR)+lU6gFEP=kTu%V<RQBG5U8!4b(-7^<~^3#EDVtoF)-u3N}@;ogWj3DBo#$hoACV
z18M5p6>WH#Kuu2P%o$GRxM0lVcinSi3+>vsp#?6`&pdzAVc~s7S>sGE@7hS7?#4Xz
z<3eJec%>puK-`#@mjvoxXyjFIm2v)Tq{#@VwYs@zo}@JgfZ65IJMsqKWSpjZ@MotF
zR+Tl@`b#Ra<5&1fYo!3Wr6qdzLagK(k=V+L+8Yh~6SNOVw1dr-dbbI|eH15-L-8Bh
z3Pq!jK9va18u3a%I?*Xg5@rJag3tz?vqZ&*IVnPA=5ukP&8L1`n35@Oqb`37O?`@e
zTgWr9{2ru%z90sT#=qN$upQT%hcu$^%q9q10#yW1;4cKf;6;GqqTw3zt`D3w0E*Gx
z*rW$Vc^OT{b0-w((Qo0MycCk(6#wS!d+4w<0pr)U(UBT7$jdOID({^}O7PAIJ)9`C
z<xSz1K~4#SiPKdTe!9I;M=~4tbkx<}=HJSGnlP}Ac09k-d+Ej~ol^-0By=kF5n`5%
zSEU$SwiL(F4f)V-@3!ESKY2Z;q_jKVPS+2Qaa()7QEN)~W`IQE3@L(*GH%uwdcUvk
zMF<VcDFbJ00Jw_lo;79YE3hEq<_0*Wk1MP7ls5y7cMY9QW{Kg|AOKO;38_{Ce9@%5
z__6^0`(u>Ol*zYm!vyGOXxbFuQGtxnKASaV=9)kK4LHPWRFc6L|K_f2$Tb+Z@$+ky
zMvADKmtV<h-5BLEaDGjBIVo;L66JEZ<wGlt!FSpO1ET9%Cv;WuGp{^Y7|25G#v{uE
z^Gpox2G9_|5-XyRJOTgkJ~0G$SAKaT{Bz}(?&@|YxQFt~>H(LOUwUZ2^i+OXbL*b+
zOHb_=icg1j-YaRO{L)MN1wQZe%ccj9lwW#lzho%CY+v=0@=J#H%ah74yT&770rmPx
z?H2+;p|*Xgfyys^v|suvzZ^K{QGV&G{eozxROZkh!<Ap~5TdATa6jdjqs^x)zi2Po
z!TptAjz9Z@@=JfM%mC$=Q_=CtFWUWNaF+7R4`2MQ{F0@Wc}n@^Z1azmU!Kx_8L0en
zVNplrmx1gTh-IsZDeNcHZ|P77c+NmFHxT#}NXm)0L7te3A^m>-E2S9zs2)-pO2IbW
z7#ZjnIWbKohq}Oh``Sm~&M_GAM>V&baYx@v+o9CsR(~OP3ZPye-aw=RqerC%cfn~M
z<W%2r0lt=rUDTJJ&~#K^`*>?qf;9$zDAhwxJgN0pJ&h{53bdd>FNv$VCpF}gAU&zc
z)uwt<%g}E*Qgu|s=+^sxM$4kpq9@gIoo=r<RrI8`pQMXh5}O+R3<uC)9k%V{<DY>f
zrzSju<1G(@@}wsJv{c<oU|C@WUC(Uf8YJ8>aHd@yD>)+L>v?sjp44Yrg`U*^dx}FX
zbpPpontv!HM8Q!FDa2(YghPv^0EiC#;z`YJikx3!1*3NSB9fv~$Mq<v>x*40ifA^=
znL6>0S2`OIDM}z)Q}bWM3kz2RESWqb<9%_Vmgju>m+pRaL0V>j2ooy$XN0cQtBoFt
zrQ{W({?$=d{q!kEp|=!Z^Hx8HKotCSth}~aB}A?_kDu6Z1tBXn^b+;^gSU3;da&c~
zJGzQ?&p<e1q3V6d6GV!1;2^@a2{nIFbWT_ES8a8%7UdHy5PpEK*>tJ|F7Ic>$FYj8
z%hj6j!5L`kTqFWikuhNV4j2Q#ZRiL2!d^sC=WCRHt2)`h3wWYc=Z`BHbp(ohbJ9fq
zTnJABL>;X93@=-#Q_*57cpuK-0!9Asr5Rj7lIt`-KMN-tAOTG^7`IFgUjZiMNvl78
zj!t*d8vcZsn}V>Wg^YhfPcnYLM^9=#`)@tTlz&kq$!XH%*+^H#iMS`NU3Re82{|pw
z4~sX?Wlf9Ohg&3_g-DBU{uXycVq;HyalY85CoOf>i+WO*gn4>W_X7yNrwyFE{DS;r
z(|SKptr;mgz%_DOziA}|o7MCjMEb#<Hn8xw8o}`7v>_cT8VcYjPug<_Pw7XTBjJ$+
zwP>pENy{w(Do^VW8(iLb1d1?r;m=ZOlP6v0`b{!2?L#O6>hem>tS)#h;3@Ll&qFz>
zp;8OyhX;6h6fZv0lBcld!AoB#yZo6&Vp)0Bz-FSzo8G$4PSLy?$ZK-HP?bnI09fAZ
z&Yhsp33>C@A4L{<$CUPB)s|iBgM=_Ba+!0rSjcoR`2T>gmoI%n9LJHWFx@y#Ec;Sz
zjMN<99NVeu*@~L0ph*zv2f1Pn2BDpGsq^O+Zcs}r<C8DE_MeV&`F@Fx^826%I?9a%
zn09UEX!&ya%T*nhaYSnF-nW}Yiu7+W;y$8p-bLT#7qUPnM6NnJ#&QBfa^(tqpNG}p
zWQ=XH#}!<-pJOEVD&X5g%i;C3!B4;+#k!iE6)#2smb!t!)aZ*M&`JbnIpR#Xcm(jc
z+Wb_&HA1$^)p2kQ?4ZYG{h*~dkXTpjdrsjcLw4CKalq0VWkYi&oYa{Jmuqf2eUn|o
z;P=jJI?Sx>>b0L;O=_ABVkrBeZ^9*ZMCJBUZdX=NE4U8f_v#_T`5oB9L7nD`jR7k)
zyVS?a$A&!IJdYhsw9>5aqh6KueIN77VX-=oYeN6#9Ep7H<9tk0ngbfn&9#EnmZrN9
z1sRQSrs1+NT%;5(h<i++m=>C#%;G)2ykttWPIs5J!4XXpTawU~5A7mFDtTvHOQCN0
zotV=)<z3$t7tOl5-yi?H$kk};zQ#U?vB-}l{G+rrCO=W7qdva=H9}a6g)RHHh|o#7
z{Q4P{g%lrH8tLe$h)`PIRlNs|=(ZF8t*iMUb$TnVfAOm}ukx9X-cV~)jDhrXpNLQ|
z523)J))#xM*Rfr>o7>FGM$=fCd_~7|^Ulr2ULLwx#?{lEU<94v`(U~M3x|WF`!1l<
z|J&S&`;rhd+3ojSpr2)GPd-?hJD?<6R5#$HCKqvXMq=v@zA{<KBvZi!T62fSUKPs%
zD773fmgt*zd2_dnIv{d++!0epiY)*twF$vl`GUYo^}ZS|kUVZ{uK-a|WVifTehVF!
z{a35LMdy)2YKyeK17hQLyF(zy^yM9NwT+D(sPv1+-R<Ff;O4GatnS{&KdMa*i1=L_
z8vs&HTr-HItSL1}gTBUdGSB644{LW<e2JFbBmD4W$aBf=(NhtnUL=jZ??g%@t`i>j
z#9l`@1His?{<5KFFBi$yjQT@4*&@ro4H7YDRCW^qT_nxhiXaTAUlVX?;a_LbqI$<e
zbuDS^&xsZ&(rY*2)+m%(`F2rjFC{n=Zm@Aa(wmPEvzq6NF5USit|xUaYU_?0MSCJ|
z{9OkXm$$^9(DCe;wnj(Ub@rA@!I@3!JS@GIE8f$hMT~)N%h)7lAS;rgZW!(E0hLO~
zX-XGToVmBf_dXujyaq9|+vZ>$(Hfui#s2|S4f^jYbB<T<Ls>(^N<=SpMjY|krCNNQ
zu<*zx0l3s21rNaW${L^72@eUP2zlZs`_<)k&UDFDVlYpeu6XBiE<v{VnYTnQc60!F
zlH!>8=eMG^`1x~7*qm_vx5gL6)WC!RGX>9H>OaQ`%+w$SrNDJQBYxGz*KvcUy%NH1
zvI$tdpoD={gbLpM`Tu;A4c%@Eup<=Di2oopmTKj6At*~S_~!YVw;wHRrR$k9e%IQA
z$(Z0Ee#%)lK0e2xi)fWV_9OHD7yKX7IAJTQ6DFBIFAfjT=*j|MK5SasP)D;Jd#S#^
zj~B5+O7jg+(?Vt?>APawoNK5a@R)ym!w^GNagPY{FGV*oMqVK=8E?Q|@sz6*%&O#9
zck0g|1qr0qM9Ty)rMJG1fvr@F(mgwFo9@0fOsvoJ;L#jELi%cnpfFRO1VeulSC}R*
z!T-;t<mF$>-|HJ_OQ@SUNk7e=ga*HlhAmfHW`#p$7chjJDgeQmcnr(+LE5C9&nov#
zDtq-sqPfMuAf|_E306((ZYKrMQ?(Pc<vRp3!~it=os!UgQX2>|H=Ar&QS08}hR>?B
zJslaXeFs`Wfb?-E#BYt_wg`}l>I6!1LXsR&mzEYz?B#^iN}yOZs1Iu@eb_N^L9-?F
zJgT4!d3{aj)3qp+7bz5$6Z(INGd5qJHDS=A85Ej8NOy$vNu3~kf?6jGpBT;@T~%>l
zy&3gW6Y+am6UMF;_m^xoChecZOrp@m{69-0`7V<9&X{<KeNc58K$GYE)|PuaB(9g5
z8UzzVT#F`M;MObRT5?zc<EWn+G}E%-cs>`sndO!LAhxBpc++!TNG(f=iF4vaNvU)y
zeEI~q*1GV6;+E39ac;ImBT}DNsTW)J#dvW|WE=n(vVGXRn7a^w9DqnaNV|(&!aEjf
zkjtK*%#Dnm({X8eu!}>duZMokWF}6XV=8*|)F$rxfMPn~X1EA1Y>Bp;c%DBsO+nLg
zrKK}%k!^&>H%UL&f=_9-s#7$)i!CcdXvkbS^VKi53D8sGtGv%mgJNN%TTAhZ#MfrJ
zQ-K8$pND&&Gyl_Mb^_l5Cctpo$7(nDBB2yU$Gy?p?6u;;$OXTa8kCd{J-BPH*BYKT
z8jy@c(*D?TMbcF105R6y=ntLP+l?(}hg0hun`{r83@{}oMl%c^d#l;o)u<X69V(OU
zQuiLnz@$zVYqag0DyEf8iO4DpC&rH7&1O&tCiD;n5S1US*8>IDR@7m&#|~&!i@cG+
zrL+(KJ$QuJ>{rjjh5qR}d{=FD=Z}LTsQ;=$Q5dTngV~)H7|WAc@4AlNLzAcRg6OgL
z{O7o6?rioxL+_Ev<{Ogj{c{ngQ0o)x>A+LCY!O`xkVt7IY!HxO+T7Xf*^`wGhiY1a
zd*N*wu?I&rP=apohRA9ka}FvDbE^&?P098NM<JM6tq?eA%Ik<uiT-H&Qn_GEBsUTg
z$~luB8fhS$zDo11;y}XJWL`8i%E=EGC0i{iJYn!D3=tTkmzB=45wuS@>K4CUhf`G2
zUWc#z*6z+6k-D;GlH&i&Zt%!Vi~w={Z{g%OuY3>)255}FX^gnTq#GEV^R{k6z7Ozd
zLzZ?94y)q@=ukU*KPqSI5~r`ye)mIwebi3^E?ard1l&aMB>6~Yp4esS>xmg5BF{IQ
z;eaNL{`)N45c3q%kN*Jq3eRi4pXOiYRkfyps{SVEgLLsD+*t`+SGy=)U#cz=SLKHY
zIVy17dR*MQ5!c_@Kx*<_(u0oKKvAi7rZ&dxFtnOYPGz-9yx=I=;orS1z&l9rA(7J2
zZ^STN9!G=tF``7qI)Z2G?w}l@z6g(rPIx8X(KNF?0~{~`BzrIt!t7}Aa|{d1sM-S%
zl^;y!#JH^J4w5MCLg+oPR2u_CLo7hTr49p@<%;={kVxqa;@xWiGd5;<k%E#{RgV$v
zapeLeku{Uj5L->H8IX`kY2FGbl-e>Qb?Y)-oCu(zzB6{9Z!0vB*-XT^vnI0kB6QkF
z)j1d>t7FjRTLCzD3Ju#F!+K{jy-<aiu@0XAyMXn8>yOPb>i$mFxGFNNov|;%A%Y)@
z?3i!>Dxi_-KvAZQfH_6C)iyx06l93EPv+SrOPMyQ)f3Y^lX!(BE!>__Cvs#K$0IE<
zMb`5sSt6s5?{8WbjRD{|#!yXU0&*a^#b1^%SzvYnCIB=gsnWT^5PrXimY;YB_w@MP
ztN!Z;Wz`iZwoTcR4%j1Yy@hleIh^*JcdlS?9Rc38=R*YF;wv|QQil)z0nNoI;B0;1
zK5o-_M(I#7jF8a4(P`V*E{~gA^NGf#49BW2R2YzS>e{hDv95}#$jq0cUbGO;x%N3+
zN+bFJzpe+^kYkarguN!ZGs%@-mWyUdx|O%|387;7&UvF~%%p!_dx(@ys?9)C@}q8p
zIUWd?Ez$38n4PQ$cWEXk1}q1V9h2f!{lo_KnYB?CQBwU;s4p>iQik`l;&X$j{Lr|l
zhJ%YOvFWB5cGy$r3>|PMwyd`cnva57V{&5aTlfS#$(k5>W~z??OEFJHQl<Te&Bjsc
z<dL={T4$cL=(u8Sa5dziMRKD3YD@zim-98GW8<sONOU)NlTO^YPZyf#`u$aOL={0c
zjlE8mF%@T5ZOV=+BeAa`@&8-{Bo26933#Du80+@nAh>Pwt;>nSMj$i;PjV&>|7)|d
zkn?0YarBszO$AOlaqL|<G>cplD*)yYN%@;_+oq97L}pk&<W4W-f1Md1C%$OeQ%6X-
zWM0rpi7LbV-AVg_;gO0yzZaotIm7`pCBf2u1w5;Mcr;{Nk#!jt1_FF()h|$X0SmNx
z;<mmzt0ukMC&nUh$?vU)6JlM?l9)DCz!?(HeSBr|_D^*2kfmLHkiA6U`FP_IPD6l0
zhG(H^|27~{@Fdbha|LIPH0JV7=`3agzYRDNbRbk5)z`^LSH(AC{&s7`0R5<b$Salv
zF4Nhd6cRmtT=MzPlf?a+bh#(OE%UWY*H$3#B2O`2Um$|;$m-lq5-p1PZqWh;!ce6W
zOy-AHMXJ^B21&Ih`9#2F1KVV#5@ZPg>yeXc2RO*7RXNGv(}Sq|Q19GXeYPccQp3~+
zIK=aKAX`#Mod_=gA1Xv)*(g$SlJNnemOjs^o1E1APi$uS;&PH{Ca!Tc5_xiz7%Y;`
zJ4a4xw{BZ|FB|D@Qm2QCkg3~h(#NEjF~=l<4`8TxTyJPCFs|g6b0dYWg(tacweUkC
z7m+W0D@>P2>ba6qGpTlkkTIuyOnqDcjl)SsWbOYKaBCuIkl|Qof#gXVdIFdA0lXbe
z%BG8Xz98UG@jDq5L3MX$pL9$Wd=kXM07SKAL5KMpETmuh>;uj`Kt`nLOA$;PZD1KE
zGk}ae((J_Z!DI&1O#o<0`lS!kh1W(Us;O;Z`Xs;}_*6gU#WyP${FoC)d71lHPBlq9
zi|Z_B!7x-Vx(CDEK*`&CXi3w~h1AP;!ZybVO~~ugKNF3Hw6O^B`+1m^X-kCL2ah5`
zLGzB&O86($d4a0mZPTTLlJ>2_ivd3-(*flrQ`2V(LwedrE}!(K7-3O5^7b)FEP8wh
zF2lvk8|m8zIB#eT&|Nr=R6mSIkY$Y++z<9E#$Y)s>2&@4QU%e)j5kz`hH&Y4NK0=~
zP@=D8ynxF?(E^#S{|!;mRd>5f71Lbxnt<{zneQIsqGZ7!fJSub-xtoe)7A)OrL-mc
z8i&%s0)KjU0m*efMZi7{?nLRD0(`B>fx&<cVynx8b>!sWOoS5Uu}bdb(C-%D2*A@k
z$<3aeDem{><nUT}Y8NYucm-J&G*WPP_O=t<X8crkM{De^+IzAd$sNAjHk71|Ir%E%
zk&`<km9Mu3G8M_OKlwkVBiZjGtf<xw<8pSvzJw<MCN;ytsiqRVR_^wExqcwM4#8KM
zFNzdRMR0QFNuK1aH*gEcTM19{;E83Zi@%pjezsjYTX(tbj3;^I)B4mk$+>?!+X@ZH
z$>aAr(yC{j76-t3kew+!#zNnm2?%5X#Omx!LquVK*qLTcXwDonH29B#8kFWPEl(0r
zLi5kz4NkxfEk1@=<O1cjLZl`UC@VkYGZYc33;Cc*EE|zrQQ#}RdRolmWLoz+l78#f
z-}hGly*E}h<D^JiFCMmfYa)jcf1jY82YdQeH1v|eDDMr95EV)O<RJt|GZ5f0e>P%4
zSCXzkZ<ZGMi^?UUAvArp0QN!bnE9kNGK)&8hZeFBfUlj-#3h$l+<c~2&SYX$?I?}n
zXa9nD0fA+@Sjm8IeD_S(eni+GvCHy}J2Ta;(1HMnkFCmvBy{|W0HTt+>F5FzZw#pA
zfA1T+2&tQ_PT#$_L&R=Tg9{M`7y*i%bynm)=B3hF=4{Zq23(k~RD<on&}!vL*PNmL
zr&9%z#~D_yBX&028tQR|A5Z2qjg~CfS@S+V^HMeVt?e9SaMzkp+>Fef&PDaa+zRI_
zXUu${Gc-=tnS^AVK15Q|hlQ<lq_kHMM0p&)6>_Gx#D<eEXmj>>E}fYqZbRd7KH2Cv
z4(meEexKx6grc%@U>L57`35}BAvZ3H7DILp{|2^<Z&P-TzHuy2M;iAm5=JUqWC;NH
zk)0E_mnYE&XC@Su07T`7sp}N<B)8R+oipcVb~S=USri}~wz-aN$g&8M_ts$kcBByy
zC@=3rTz-M_%8xqmlC=C?y!P=t@~U^Yh*(H@b!*)wSz7aDxJf7_Z3sYsaK0YP2XBjS
z7}Aa_aD?Gm<lV2#7n_pGUfbM4<T)6w^Cp%KCHY4RJkrr2aJI}-zbPrt37ace;E_-L
zc}us?sn`oAN})gJk`hFdAYGV|-dEs}E>}3jG*i;=p=&d$dGLLasR@r4;Q`UtO@9DP
zQpBDIRi7hZZzxlf>90wO2f^W|v`;GCtphtNf}UOri5Dr4Dq+_(9&#M;_wl6on=Xj&
zAD)zeDbqM@g=QgH)8jEPL+QER2U|HM_~VRLIzUjU`DBWY6jmESiqWcfPm&V;W2sFb
zAyHEc7#!|~mEJe-;?>sgCbw*}o^-tYjo3M)YDy1`73zykiNj>_CP+?koCp*%PyzWA
zeXNO4PEPT(06LuSZEQ;SRw7p0lalfG?;<2pPU-gza#i!?0DGE?J4~MBNg29gsLl$c
zj5t`KV$4Xtfht0Brn1KD#kdxmHNQ*qqdT+IOaLS0B^3wqww}yh%H;dF_Rw%lj5MtP
z@zO=o%=fU9(?}%eFFr&rW>7dYP#=oOQ=(s9z8Kqgea51tNPud1E>wecQ*A5ckXk}n
z=?&?yQKYOMT&l}rwB{aStMDyK@4a(APN2w}ecsXS?zg|ar=!4Q*)>JSvac&5Df1P}
z2QE5wN_^-R&KEq7bhI@RuksZ6cuuK!Xt11$7x4hn56709g+kKV*4Qxd)kqhXKCEwO
z=cql2_8|DuO2}P`fRgfC&wGe#5gDz0SBiYlIb&hyZx5{+4SSm4H0(YKfS}Ihf-_*|
zqi^4M7u)%Ke{ZTK`X2YXx>|^ohvX;-yo~a_At$y}-^tE-w6b!Z7@pMHr{TIKXisYW
zx3|R`C#pu0L@YIE7}68)=o_SC`W&Hic#<`>$@Rf?=%Rx+0I4m*3Wf@Na%$^Cy0k|?
z3f;b>Q?u0e)8I$UHvpv2bBI<T)NcFODCS1;q$Xsq)sHCo0z#_tRe4ff*~s53*3~r?
zkZ_T!=k<J%%bMC}HmnzCC1_`r?=PqJKZnagzI1Hr(@*2cn9ZXm1cY^7c!0T=2KnRL
zAOH@1{>I@|<7q?5E#}VDQG32b>^m5iN$R%<cEMC4Tfw*|fr-PJj>m0!QYYR5E=3$t
z{(Qt+{4hv+n;}`5(H~bUT9rhZQx4m}<7cD=T^D$P<zTTaMiME0BP+dX#4UzUX2rNc
zSt4cCwa93ZvU-%Ok4RbD3W>zDdV({M1TYU-m@2a+ZE)1Z58g$h5si%~J09kx2^7=r
zxlj57@6C79vhS2=222OO#Bp3VmM`Aa^~&;9C+>}hE;aF5eWLYToCHMsAfI{%M?t<t
zsiHUX-zhyMBR{#Kp`3cI<I>@z-7faY6^(DSA2+T_J{I+>)3C1iPKwn+j}YOHKaInL
zskk|9L#zM<vQ>R~I@c=;ROtRpWXa><L-Kz`A>61*snh%dkfUs}DqD<H=UE(ydH9W-
zR)2~!R!3@hL6@EgiI-kLo@A{c-GWn+CF5DZ+B7O_q4`Tyt#u^ROvIuT`yo|6v}%J!
zx$v}h*Ao5U;~`cS70})rQHxa{a}f6kB2&DnMh>UM1vrg}T&eS5B1BRb=YmdN5_!TQ
zKUnuKkV{$Q%P=6Um_nj24#W(gLbF*?B_+`cLD@UA=$Dj-C2ioMa|Yn6d2`SDKExX4
zjibgW&;63_F}|Rll|izm<+R`Kji!Qyg7M|9!481ulhg991FC_pXj?I7+T>{~(|mjo
z)mbBxs7%|d&wVtjr=BwR@XhB01dVCoV(6M~6<+cTha{(}muDlxA`c*vRt?cp-m1dU
zL*pS;1Nv>vgu_PT3#w!)Kv?O$CkyRfPO5+NuB-uGHlpk(Kw3$yHlpm>wDWP1Qs%+E
z0?%VP$onvmzf_!$bm)z%-l$zv(UJRD_=RF8R;jA5nRkkGdFr;4IrXruJnXxv^OQ|>
za0WJ2yadk(<u^{_P3K-=R|49L85)baP`vs*ihStB^nhx*{0R66PK&8qzmHzfN#K%h
zB;!$7!vYacRg5uHq};2h3=t^uzi<7=U0jl=x%`^K(@)%z%dR?maBSs)Hc_s?ZM&NK
zaYr~3NmuZqf?8fa%8#_x*Xas9`W(V1a(jQq+w213A@OwrM06)e43XxF_yw2EB2$|S
zFghBE?hpKZEFGWaJ)QxOz<sWD$0QwIDE0%sDC>p&R(>CEZ6MiPPG{lkv}4Nm*VIUM
zxfYymCh&P&T}=V%m>>$R@(DK%8R~VYB8;@0-6+8bNSy&%kzIYAhwJN=-<8!E8Si)y
zkn9>{Lr6oBH1wrh8*dk7*YLJ#AO#qMYS|t2I<V4W!7-Q1qjjVSPj847NGYx<ts5ew
z5~5dVg-Lv-cbnZofZNEke&44P!@?z;C8k0PBlY=<mdpVD7ZrO?Aj>-Dipi6tVqd)F
z<g1F0dMqXDCkZRM^p0y=Euk8DeYn4Re}*}rLhnxz{Q;z{FCFlP=cMj^l&*s#Ngr2b
zq#N^9TT8X<|4>&;dDSFWb<>*0Q(Oqw(N|;q_OJjps?t~6dm#0rPWr!&Ex!`qhSPiL
z^iCvg<54@NGyAYGzy+KqN<U|Xb<{pNb^T(WLZtWM=198oZ&j2~NUn6x=Cqkg-TWut
z8;+C+cb+&VZn5rP4r(FPBK^1HQeQ8Hl*H{f$|dThJ77&=E6dbgd0rfl>~1jKAqx;3
z*&STz7_B3PCPrrINKM~>=Z*;aX(<;C(2*i$AyT!-)n<D^U&AZ*T4$@{prNxKcgKE*
z#pq_h3-#4MaJuC$v1Q<Ev%2k95nf%*nWE^GA)>Cw?L6^{dZyO|zz2u7COaP|g;u=0
z9EAahT++SX4HlkAujuaHr_$rK@5$yg)9q*|QnCsVZE>0^i;QW|DdctJVLq~ZSajes
zI?{-GVbx((l&yisJ$lwNI9RFD!m1kk2$zu>eut4JW@b8cRpqbZb|WM(GlF7zc{@dv
zIpYqr);bP?Jny4bI<Z@LuTYfUB~8z_697NbYk%vaH?CZ_!5dwQK(ImnQb{eq=6Rfu
zT)OXZtWD~`ShSEFL-e{+IXD^Ny@KbpY`iHZN;7RqX7Tg+jk~;Kwq4xZOS>*253^Dc
z&_YdOa87F--k25ymPC^*ddx87#fb0jj9~GyRrSW4y5f7EhC8b6P=}OCI3Cm>W*z%K
zsFT5dVGN_fRcebLwq_}Nq~M6w_z{P(C&bZDoeVS&kkA)Ob{6%Gf)VpPVRdS>J~`k(
zR1M;^ISTZKYX~`&?oQ(tSJdc<pPSTC-}3y0O88&(A%*c3C5#fc2vYpguyNF^(7_eM
z(goLYe13dQTl}hPF%4?;admOP6rM;MMfg6ydoh=VQ0BTG8^57<P<0L@MKh39DShYG
z8trfY#;FIUSmSqncqjysIQXMA@+w`#W(=78fvo?UIiMYW{Qg3KdX)zpW$j1!`xtfr
z0M-2YTRX$~ZbNg-ha>Zc@U$S;2m`RI=3_6XFX!px?~YU#-*h-1%#*2#@79a?vWWKM
zMseCei~8lYn?D&03NlNbBI3Q&LQG~ww5zj%n3E*OC;!>_7L1@OYv7V^{X|ApHCIHr
zyG93XH$U`0%O;lh5=}4+%4>*W;EO2xD~i1UPxl1>+uP>z!z0;EsQawqi>da75gXjg
z^=6u=ws{F5FI|UeQ2P^1!H3}G&}6TYH;R|Hgcd`^31XGD&dBLiqj}3uHCnPIw4WLl
zqT`ekqBh|u$-|0}U}>0={!5e<EFFz^a!QWFf>%sTNr||O6(i%Lcg}>=zuIGELHZFs
zsgWlkedHv31ocrmn8FG<kQ3!(E<>qtx|ovCr*{i@O5u`Bogy~s{>N+TW5S@N|7U)N
z*%WvV_a%^LX)2a(9(!a<7<FC&<q0!BcB9j!n=)I%q(cQPN;y}fEg}Db;+L-yAy}3f
zQxR@J?KTnSRB=l@2&R|9@#>0rCr_$F22olx4R>DJe1T$Ka$LbraZV}nve6e%8CSbp
zY(T6TjY3b~ll;sjk=gV@sXY`^b)~b?$MB<~o~)B#mPM42yz$iz;)RrX%YhJP@mP0Z
zMjB=RQ4i-B(}%6EQMxg0|A457*&AG{e4xqQtHmTX)Qz${77kXsM+7bEV9#;5M#SZ}
zhV)S)7Mc&;*qKRvRzDAzrK4wng3=gi6es%PsT}I0N*3i~rL^O-9SyyR8+t1Tp7u;E
z7ucGr`#BIdi&}Nn_W5FDZf|N=eQgD!eD(BnTpV*o#a#Jc2~$G8ceh^WVLsHro!^il
zSZe?j^FJ1UW)alSPqJ+{1TbG_&Cq}-+iP{9+PEu{SbM!Ta4lAQ0Vb>cu{VH10+C}w
z%B5S1=N)g%>_&5*%!>euBjwWcr8pU?bI1D9>Ln#LlR7Zg7b%0wuEE&a&ad=BR3R7D
zP$EQ0(L@6FLW)5uA0%CRu$<h1wC~Pph#eHg&}ypwFrxjsxcD%l^ZZFY%-L;scQxS=
ziAVg{>|G~boz9C4E8Q!g{RqBsK#&aQ{Q)ByQ8S~Oz5j%fy4!jCzzT@ca8>P4B|t=P
zi5Z_{d-n93jlE34y|4}<!Q`k$_l8r`surU#07RDnP36-wv0hF%srYoN(@xSe<xMyY
z3s|6n3F5~giJCL5NZ8$h7CJ8<KG@#*CbmU0^OxyqOI}q#mFg#;MwhL}yPF1FA{RUa
zax319<Ay4D#PwDgP#=8Pq&0Kl<E<oa5_TK*^_6%LVtJjFdBDEZ5;G#bR?w#CG{4At
znz%svQL|<1c5KAd*`}s;j?mp6@BJ9=lOy=Bs{8xu@HM9L1<(s_15Onk83rd)9#kZK
zo!`S7gP&Nw*@3rf^i8`2Fn>Q-iMOx1gMrKZlOgjt-BilIygWh7gKoaKPqD+?7nQH}
z`%b)>Fjwv~vfUQPWxmx^+=Nq`e~(u9xKCwzAmeHd0nAlM0Ew5wV8PX=xaS3o=t-wH
zj<ccwvLoP|V}X_t{karw$g-4l?+F1UWOW43hu<it6m$t%Vvs`vp652(3J_arIuLp4
zFn`!DkxfuCEnUo|+$ptA(}O*;2_s?i9Hw9M`|y*9&I3$TmKEy7!7x&X!9Zz_R0V?k
zb)Z<$zueqTg*hvV6iZ8imqy*yn>8hqlsySPc^Z+`m=X#nBc5b)xL+=hp!#@=>FCx|
zK}V@mj>3Qw{U`!SS&f;kDBqLXN5+@+siOMocV&Eo{y^p&k#AVP0KqdBe6fz<Q*>6@
zG3t?$i<PSmX_n?6&_B!B9233}m-^sL98r<?a!Rg}{Y@QB9lX{S^j`qo#LeDFbqN5~
zJo_ERSx{{YG-;k?TO%)Gh`1K+_Gj>Ej?1znvJ{bYxfaaJV*Pj1#4;|31c8Ul#a|D#
zYM<V3+x+TX1D#DAB^SH;0z$8|3Zd^P$!@r+rS;GH`-teAO`|7y6Y){6x85D}1b+h{
z?JU8wAiALGw`tE_md%<!YDaw%_~sNJALPEtakf>236;qQ9uc;TH-d-W5}zTZqqC9D
zlCR!;qFIoehN^nz(jG0y-+b!k+BVt@D2C5mF|#OJN0ZK3@ld8!NZ{ELgX!1J*g}f?
zOzDbgX}!ptKB_)Ye=EP<4<@d^=36f)!5P%$h(6<;-!5&@xB5>pGOgsOR)x48_1+Lm
zT<XUr5l{5{cLUuO@Vl1S#DF(AQ$a$X*q{;Kh*6tj6BK6yx|Nz5){4F|>oPM7K;X!U
zjbHtLnU=OM#vT!h%!720X(?!1OYQSw*GM_X6I<Uu>os+xO^K0LxbMcg)Zq}-rCJJ*
ztcljbC;j26uT>Y^6<-R+ve>lBbQ-w|6=CJ=*WpmimzNWr#azICFr_5AAJ0=_HK^^7
z;Y5vHe=1L+8aZ2oR7>9zHc0(gC?A{H7uXAJA!N-C7_Wm-*%AkbX0gi=t}<)luv~^T
z2~ZnGVPsmmXB4*6tc}qVxsxa;p2V^L0%)m84QqDdxx$XR(dKWj^k#K|fJigqfM3&q
zTcB88?7+o%0zqCt$!ruo(>4frXOxN#r?(_QU@n9Z1WOFSF4EF+XOPYaNGqN}kT4zz
zBdx-vuz=37tR{ak&YDT@W)-#)3%$1)dDn$%Hl4%yOMotI{~UoH1<I}ggS@e>Nhdzu
zt>h`^b_UY^U6o?hQROz%bYGv0I>ymlr_4thA9IonaQbTg+I`q-6&0Hxef!b*U~gB+
zaoSj0{^5ncp<}A7(CnWL#r}sMk@@`LN$eP_$_0IZ%YDv@H;D4JH(RT3gw+jRU$Qh>
zs7bo*!fMIqpbEX4lS6&yt;oaJW0Q!c+GmouB%d}cuZ3bCv`<bswUTN#*vt?mjGtXp
z0&yZI)w|e(-Bfec$Vm;mWQA&KiHfaBAq|lG7W+>P2@~W#Zt$f$6rb~0fV|U6;+xd`
zc78j)JfKB$vCGg3GbZWA0e!BdcAJX4*T-OrO^QMr+Pqh1S+c}Tgqo_GQN|YU<Tgg2
z*piZ8b+NrS2Q;uIxt_=F4V>zSq=dIPmn5ZsqHNwdTkA~f`PN5bnn2d;KHVz3Ni-Ox
z|Go4^{9tWKgX)~0N^_!00%IF``d+j!1D>SpQ_Do>OF3y&GIn$PJlT@Q+%H>HqqYfA
zJvs=eDI{7tOlT-=XxO#EIbr(iVI2+AeHE$K1Ohf7YIa&@JVH5qHI0WIQ123OC0V$)
zd;%|CkY>}uUf3uEBBzkr2<hbFza7GEij-qn4?xp+E>m%X$t;)?S2C((-Ion1YZku|
zkltw(6sOH5HM$OsVhPs18P&h>Rox+COB-$-A&wnC;;CFi@ql99ouD8FdE2q??VK3C
zG3h{SB&!lqCY4XalPf<I`N+COya-`~0EFG~;qY_j`)E4lqhPx^8zlWOrNApH=#=Gb
zd(}QG#=w03^#f;U+WB5yI=$IDCA1-l^O3IguV^ETPrClFvXwwF-R{|hQo1M$n)lno
zA>r;fc@62iGkYR@_o#mhDj*hONE(X2;_rjROD%xl)UYrV9SS!*bw1~&9+D1t(Gz%Z
z@fYDmw&dWaPSYKakaHzD^d~H@T8*S9$<2nAIRwZN@J02{i%*Qn5i9b!DS?Mru8+CR
zl=PuAb*hnMwRQNqu$9n&C%JR)UAPSF$?3W$IrhRo+~;E@?T@lMYqG&8&K_bCY$@42
z=nA!{UR!}HHo4n)(cjUU-0Leyg3e7bx$kQyy`skoW|fKsZOMbDD|k|FL>bA?M%$}H
zm~n?6IeFx>>0$;cWM6tv`WAIhUGdl;#_xwbD>JT%1h$5aq)%E_`<}6hVG9H>Idbx}
z?AgKsL7;y)<jk7FJq8B3Sjs)~+?7G>5=5O_O1A>w$oz{s7?8C1+tSCh$t8V#ttc-{
zAgtW$bP0r#j)#*4Lh1Dg;RWBct^}KOsHQqEr1kH=soWW=%K){t6)^_*ni}og*U5+b
zw8XPF6nS|x_!QOjsZSL{9IHm1xIW8uwv8P7q`Gzz>5IRxeGouUUoAFv5GbaTad4wi
zPZQgK<uV{;M9kQJhCU@-9h6KW2>+3DaPsM=eyeXdVyLhDY+xBA5RMQ9!VGFUgfp2l
z0jk5hQ;l>8Ki7Rz`DK9GLp2@3#lJ$7U$V4cs?#A{J0GF^qMa#&tJ5Le^s7#xFp!mj
z^t2kMq(g|VvLjVN_45`}2EbCr#rd=vmx?zBWFffs&C^PysakWC5&^&b`>4P2OPclz
zJX%pziqm($Kl|wkm--mQo-k0T&KqAVh1^;p53A19ppEi_NBtqR3;2Umnkr=cp&Ubl
z)4`9&;m~>o$}j2KFI|<6g$3_Xe(9?HQk}LV{M0Gs7cDcmnzqCI`4Z)q8fiP)&VOF{
zrH58qb=r<j7iTEH=+kysViqIhQ!kZ26e&7P32ufwGveRMI6{%0BRXksb)E__S4W8<
zI&Jw)rE*O~gOywzrgSsT;E)+DRYz!Fct!OX1<QzkR9Bvf%Aagf7gZoX1^%d>J4(=j
z%KLrxsZzO?po4&w2n{%}T{Mg-cM<{s>W-Eq0Sg_S$Ps>a_z$!7e53E|)sx1JJg<@<
za)fkpJ16ei#@<pDh=dmd<#A5kv{B_oL$G)r=gfsc90@uq&rQ|EB9`ax{+`>Fli33N
z<mCg8cp{5=Ex&SJm;b=D{C!+51K}*dfmUrq%v^qBBd?A`ymo=I=DQ0z%7({sMT+Tz
z53u_Y_XzTiKUeAM-n}ADEGL&0Z{aA)m9l(L8qN_h6Q)A|%j>GQ9L*NfyU8c)W#S>m
zbm}%%G?6A%e2N1RKL^seG~A@{6w`&dxYyK`yL=9~B%Vw9JxrtEixcQcx*l1|?x)x_
z623QRjmBdqgs0)ZrruS4Q{|Js@ZAOo>#a>T-C#oA9<02?6S0m#SRdUg=ZFv(Yl?p)
zo>_6I(a<}XJ~+Dr88xF04j!Cf%P9?v?dy9PN#0U|_pcGTJSm~=R&XN7%*9EAC9J*(
za7alBzc8i7HG(I_-1<MRG;5=6JxDj-6HiLVKR(ivI`@|Kq_}!#MUpke@f`qVxRc<<
z<w;42#l@3I@<h<3j=<Gj`h_ErCjug!Wjs8>5m|Tp{nA)Z8o1ymJ!$Bhu^fpKoxw$R
z#Ftnr)r}Du0N`rml;=NVe)5Xf4dekt1w57KGIKAaiU|Nj>JdySc$Aw()}?7L7KsCt
zQ)YgEz+V~{GZcPKou<tXLS_q1u-GzE>SKEO4JI)H<|le-oiKb%j+<&+;n0OGHoegv
z1Jt#$`nh>J%9{Ts>S}uLy*WC{<~l=ll<n)PM2fVl;OgT-H>G_~BH|K8tr&MQ3J0zs
z>51q+DIdCv02A7{X(UJ6Sh>2%&lFdI$H%Vch{Sd(wULhU!?%zRp{lcy$2bZ-C!aLP
z7git#hr&iy05}@kZ+$l_E;K4862wLmAt%^l{$45i&oj6bjwd%TG%xB2J(6zUDXJ?_
zqVM&dHksbb1giY-K})p*kRuEb`(sb4@3cjnkdi2+);>dr2Tr==)cR`?2b_og05CNY
zvEX<T(kmV5q&g2OlIlrqQq@7M%ahu&)kQt2^-;a9r&{hW)^oL={e?)9Q=>=W%~b4!
z?Z85vBBUmaMrcKmEBQCPqVZz{UTSnRv3gHx*Yp-5NlxuqRini|^D4!<<kbGZA_Rcg
z;?qOlQMpL%fuFIa4tWJ05c&Q%x@wvax{`A#Tbji^gsby8>eIKm9x=4kX8-7M1IA(N
zqM!STf4|D{;?v5h`L6@zh9<mE5;F$F2}_gSYFV9gv_2;)B=!q>HxVh);@Vi%6ci9T
z2OiU_Ef5PqhnQF~d2_J9C9k@>jMF@dg%IZ>uO9n}uKKkS-jMm~r44`Sav(_`Y;-gf
zcuXJq!j(hpg1mcSGPmI%KaMybY2O)u2l?vd17A<&CW6NN#XFH=rz~H^h_^f8C)zl|
z{Y0AS)O$F#iG7Hw=$8mofLa^rKhQMNxfsPwUR8h4So)<4hXTY;PilUpE;8bR!)w?6
zxUFOd=85vnS)0TSiCp#d5Vc|DLs{+@auY%${qK!exUrL@r1?EYkR?@8$S$PS$w4j}
zL1)tH&j=Pp%#+se%3B<Xo>b2IdD21(-sGsP1>>*qU=UkqUNl{7AvVo4SKL%s)1<#3
zW}?4}oYrnE9`wb^q8{78y(5vJAsukcmt1w#i9_Ne0r=p{%4vy<bto}UTI$QYxa!!1
zbn)yL2W3s`ehhB6>hfN#v}qZ&H6$jfJ|H&kw0`ptznoWmP!(X+z~ZXb+9jr1#gMqi
z#hF2-rOTtl);(!C(I@q!+zsD~Bmk$XkYobQX}bq&+T_`Yp$%UcjY?86?bBa%qBN`T
zhoUG+bC2V>5~Vb$lol>4v51r<*?2zTdF17zmvT0M+FCWdTvzj3|KN#5D79wF2b`3W
zPQ2G2;S6~mX>%F&0~&=~t8qQJV@`1sFOiztwY@dh0rD2hF<8oQnAI#HxJ(C|<MmC1
zTbd4)BGj3V@5m!u2J2`i-Uf(PrQxeLnu1d%65XD<pT)kes`CK%P|78#;$`mYTG3P6
zx#f3CeMAt`h1KoVN~@LmH~e4gHN`kXBfsZO3KGlRaDOg-OH)+>UMuz0-}|{#oMQRk
zcXPP<NpW3%E%$`z;6Zgh<+s;(rNsNY><ZkKX|hb=ldk|ZRg8xd4bg=9VqKvpad*Ut
zqwH#S1z|#XCXcJ-KUc-K1&=G@@?Sd9cD1>3sgbuJd6YosJLc#V*Ja&f(k+&**bf_W
zmC;==98~Og4|7D)d6&~;7D-l@YYEP@qVu%u>T20pySgW&^FRf;UA?}V!Z!2TVh?I{
z(k1tS8anUFYE~@jywx=*0XfTX6|JF{Sf7R#Ju5N-G!<3)n2u{yNuHi-%wIU|@pZ|r
z3B&MKr;&oY!E7Sj;gmKwS9517QoiZEqnZdXrRZ5V$3PKu0#vx{E8NRK2ow`R_x*^L
zv#{fAU23K!F9QFJhP{?#nGLR$JVh?9bAnS_>O{%ryfz}wJAJN+J+Q1d>mnSyUtq9!
z3(;x1)JNL7<dP0`^${hR(Nv2J!pHx>F$&&NYA?yYz?)+KUWQK4$Y8aUV-Kwm@cEUb
zOOusIn5yOjki(KLovinUzu>H*Jo3w@KOUx5p{Tla<{$#aqL?;C^3Tuk(Oc23d~v{i
zU8$>nz=sN@D!V-pr%1kKn5rvv$DC;rN=f(sD2ee>Xx2{q$p7tmj<YKyjc&hj<3$be
zxC1u4B$5E2niJmGGPU<w9#j?lS9!h2soJd{t1UDQ$@~QC;BH!q2(LVx$>VP6SfP_`
zcSIo&!y;FkU6=J-9iPV0K;*JMRU&eE-165G#QuBS_Uo|je7~%2=Xc0M2~4O`9cev~
zHORTtGEj+s!XPy`+=EKL$nNgJ8yJpOz3IV#Wq0q2!}WDQrOfU-!v&Jno%JG~E@22z
zkG70^+=I@Tbw<)XEH**xC$cUD5ju)1h^$M6m-Jbe#?^vT7tdvNPaIg|X2t5xe;Yd<
zu8H8D?Z~M=#XTc5hTW&~Y9Y;;42&^qtu_X@VZm8<-acn6M`VardEvkNILRViUlLyC
z@UoGxzxLmYq998v--i}^>sO3TNj=11(TG%4=|R{oo+7WS_!5tS{aMJ0YIWQA_t~}r
zleEQ!kW73rX~(=MNuZc^U4so&VU++?Nj9Wlvc-GaET>FCis^@^JBZc4boVGB{5dH=
z2BsfF;HV*bL&RtH+l)`HBW8W0IME5k2M0R{c2Zj<63A$+FThnBf@;<<;`sl;W<7tb
z1_A;ZnEEO4KRMYk#ZSK2$iO*rWAY%!w)koDm4qp37Z`Eo!v%yc)B44Tb6pj_I$~`6
z{FS2GyW)$SYn9HcuW_vK(!DiMT*$yQQirjEBPVhqt-9Xhaa}{!_|>Jb>7uuVC;r`Q
zFK~*)UZ(Iuu%X`qNVI4ifU@ePAc)k5G<s0XF_^Yj;7*z2C9976*<A+-Tf|Kua8}o_
ze^5DTwE(ilynj&)b697!!f1d-bld0eMu``K5NGq@4ppuBfq`Z^_9`p{M4Hd7WcsGF
zqO6?Tg8bd)Le3|Js{3(wfrqN&M|9f9{7Z3_fTANsx)cF7IKBz<)p<%`^(#?d{%nRh
z*11yOx&RcmQ1b4E*&V1^^?es5<%jj2!D&kEF1a1&`dAYTqp=;~Hg(l=>woVMrcq@k
z@kppUlKDLIuk=X6^xt@nPjQKqLyDHeim8PeqzcbPP4-X5C+B2=)!JgjJ-z>3Y(ne)
zV!8xRg5~^9d~3BzR<ix9xMutq88K?xvCjPGqisc;kHt1Z-Bdy-8a;;v7k(`9dzEwt
zY<eLV)#;b42}x-Ph$y}sP}nh;*VMc4!QpXBu?gv8IE#%w#3uCoPNdip`eZWbnkEHc
zvnKREjl(ylLw%EG{U5Yq&=b^u^^=1rCk#ut8Q{&yq#VCZ!)LJv6MjzI38Q`+K}n)G
zo$w@#-Fi^ppGn6QrRKZ`Yzb3+xEy7Q-8RpdSuCJJNRH<G(^TBc$uF6IL<{OTh-cAk
zB$v=uD|%ys&@VZy#Jg5?0gUElc?tkWHEl#IuAO1$zah~|Y!!kPCR%AxjYMhYb?s`>
zHol%0rmIid@<sdl)d`%)OaRzp`!E`=HFR5`$^(e>gS`9Q(-_{(uG&qXxoqZH!2y?g
zbFl9*2K3@ba_Ek$g|21u(O-%MzThsfW);5X6In|3GQRw&`KOtPb2RBpBCZM0Ep6v&
z{yA95#;3{*dSkj6g==db#zkGcdPYer!!erw^sn)Sqi?;r6>*O^eWSv6{-^<su>8}3
zi+n_)YBxLvU>|zt-AUPN^?Z@DFC^vmdYz(3OL<d*987Q5$Y0>GH@a6B{ZK^<g*|p-
zJ49gN#olTUn**b$bCk8WD!NoFGCNC^HrBAz-`Si#2ru~dwnYJ6EEerGfw!^QJDz{&
zMM=RrfY@j_PU9|rx4m;+1P#_*EXnrRXZf^4Y&z^!$cm!@b66Lgzin_)7gW>C_}snV
zJ13%=x=zLYvRJfNs1mnZElNjgTn_ZfCDcAQ=T>|Fe3sZtSAO8n3Pw^b&-yduT~Y2p
z^w_iKw81x1ldlB#Vizvaql`(g;Nr*h*vI@4&uKp^KH+=hBhz{W>5->wY|9x0P=X4E
zMfxFGsD^DKt~s;raaGak4^NSKw>ukrszSZf1J3A0b3e1uEu>~+Kr}5`>8AZNPm`Bz
zI<DK-7Vj`VE;K8>^%*5^;=J+XHH)sP;!oyb1O#IJt)G<_CKfCh0s$iZAZ^MQBec*!
zw(hp+THQGoPfK9e)K=Pi;A8{i2vxMH)c&Xb6Zh%n@+JN(4~i<U#C2rkTr9b&k1HtV
zuV*TTmDlTUc8lq|z$bnG9D-NykSp^~wc-YmFmfeLzpVO*C2Qn6Yrc43d9seta`kC-
zZ;sW1-emLr&6S^>Z>QsvZiQ!xnW#*E=Y7`<OCSHCEDw^n+ko1baEGD&Lvq2^tORc4
za89#2{0Cs+#OL889`LCj5FQv^)(nr$(ZHoZ@l<iAg%dYX!HY+Wy9=8mv_WJ9-)l5)
zbu=A{s|a<wLS|tkj-ZYf*S0I0MmA*-15oJ~K&Y-NVc%6_jY>R@$j@{!0cA%AEYCW?
zQ}pFyY?)Pi%7!n$uH-f1>XRLIWXUiB$fXTacBF)z76DYU!~H7aoQquDo<;;@o&@mJ
zc?Aul3KwfN(-J3S-XVvaKtCy~90}bpOs!pyW6;e9z(sLgu{wr54SyF{GLdokjE}iJ
zB3h9hqiaP43S1V)SRFD9*r{We*xp$Md(=V6DdT^I{ZShQMJgDCoL^|rt5~z&iwYDe
z^Ex1alQwwTj==wU;U_va^O8<V))m!h6V+RmCE{siAo~Vn33AY4@wYb{^ZNwQ7?7&u
z+DQvZk@~@?cklGoVUSGgbMVxJlxHZVbvbC$;?90}ImzJ$CU5;0Z~%U&^3F9QMe8Q*
z`4nT|Ymz<*UeH*i9P~$q6oKc^ySSnd+B*8udysV1-lOB@6XB7=X)x+#BhAIBzd41c
z(Nz@YScIz0=i(Hzqe?Py{kk1?Ug*FT3*xv5l*&`f&0?2s6+Ff{8qoXFW`EP2stbgw
z=M9JS&+5Zwv9d?~5RY1`o&+w@-w#`8kTm&48m6}q<TppPzl^JaadV4mE>ieWR5Ey0
z0872XQaC~1L8KpSiH%o^2oY98)7@~B!_Qhfw#1g9%Ar=Zv5YUm2Z;rFJ~=V+x(j)f
zxS~kFbTqw@j$~bkJl{N*Eitw$vy=R$1}T_s>(Uzm6!q5HhTfu>Q6Q{riS8yngp8W#
zUTk95Yn+y`4);2XlMmmnHL-7f06%olEje+(3s_`$?3A21I7|o7awiU(5QK=Ze0_4_
z@P832O(cz;imaJD$&)zF_l(Z=Cr-S$r<IN?e|K}(9Cb2D3TGtk3>T6tNiSLvml%~R
zY6!pwxv4B@|Gv5gLj?SuwqQdc6&+W?r>jdpz&(_C$-MMvu3#*wofX*|f<(;Dsy_&`
z!>P8kdUl}5V}5sV4TO;Sy&YHCm*MP*ZPUdHJT&p(B5C`Ps3t=7=3Rp`7)p*)LiyuQ
z4yfZ&&UW(tvd2aHVlGc87m^xaIP#HZx@Ro&*WCv(E>)hvW&U>G0+yhQ>#Fp_jKH>H
zPtP_hGYJ&Sc}#3w^$So%m$Q0|C9|XM+G$3wmEvK7AF_OX`8v)vP&aRPgW2V4lJBm3
zAX21<iO%NUdPu61d^#1hG@@##D=9o6GVY|>kH4-wEwPy9(0E{Os*^2Us}W(vlhm;1
z7EaPwts#%&R$W8tuuMw;iX}CvgSA^DgEJ+m`F(ix8Q@!{fpb^|riHk07fDhT;>7TU
ztx4^+v%EE$l%pt6Q32fLkm8}?zba9?6T`P>EyR0}gHEh2d8KkArwS^o&NZHUsshED
zlwOY4SZ+P1n-RQ|_FQ{5R@db|83@A2w;?C>|Brx3s#>z13~E@ZPc}95N9<_$;aiik
z&)_Op><Y3ixw07ITD@sTeZWLL3K-0<!mN=Aw#tq|ySAhkj@P(clcv9kD0}E0ECMa|
z0126Ar(b0Psc!c`Q?f1XS7PvU5^r9ZsbEPtnrZPvWY#<FBfxK@Wqslv6DW;}2h{aJ
z@&g{0WGmV9gD%UF^bVdv1tw`--vTkQkhF0n7G=I7c}u5F;*E{8<AQ%PFAtoWUoa35
zaJTbPqsZKzDm<DLa^KpFe!6{tbf67z+k6XB`7C(U2$Un6kbhF39DhE$iI+lW*Ek>3
zsoIAkbbbNy4+Ui+SXDY3jWm*cW%Btq7w|F&?{d6^Uiz`5sQ}25u05SAPPBZ(=Yo2&
zQ|zGScHi^<ishhh4*ZLB_lH3&jmBDfXoUd)O-ZiwqLN-i{k|kx$-WT?Tg>M{l9THk
z2?`dFMRIarbAJ_Eqo`nPa_|uKaG_9;Q|bI+_!je+C*)Kb8O9x@S&QMpYh{7UnjG;a
zf<Yo0CSO)gZd0I3iiCVh-&T-z)C%Ap3zIt!z>+N%jlGiHL^mpjKYSHLE@z*LhB}ga
zDej_0u5ME@JLyQhzS$;1lB~&naqQGR9>gYRtryq&*yO=;#KW64`PtYSW)PUCoMOq_
zChQ>c#@dp{_$W~q*oUn)g~{W~;a;HhnAQLQbZp5lw2OI>q@HQLpL3qcHkPHlGff+f
z!?F0r3@tIunt^?(Zn>GeT9+HiHvifXIKpcPAaaa_)Gn^bY3e1?V)oi=*LAlCEBBXm
z5_qJN7#ym-RiSr4+?G~NdWO2qLz>pD!PA?@i0Y;H-^F!@0ASjBBOrsyaT^9{XQ44%
zEVs8gUi$c&OrO@l!;EeP|7`s11ymQmf`4%rS1x=>>8oXUN7N{^yGORzlSw$KXhiDj
z=^+RMD^Si1Y;P7Qrk|gHPqKIuBwxJyrS6n)?J{&y8?<t@WV%_8-6Uw*@6ElCT$R!Q
zV8_!GD@6$x0W4$_8_;kSh|4Ux6e{-$=KpGKc#;OLS_e3Q8e$9{r*HW;q7WmoQmL_v
zE}c(<PB|$8$>R+6ysa-78r0q_aLLXvBR0}}wxC#N_!;h@hfIdkd~8x%9aG!Ix^0WI
z(^Z@{`0PZoGv+m%=K0D!&V+6cM5jF2ne^#Uu~#-{+MDP5U@~e|aCXL--WIt~_}XM=
zk8ucxu93*+3ZdYiZ26aH8a>W_7oO3XLFd5eo1MHx*)WGZ0D@7g4WwA-@N@dAMn6ar
zuP|-Sabq%`rBBD8wJ-u+IdD!a8w)w$9LNd&XhT*Y**SH4sZD<g?40>ZX{4AmXl@tW
z{P8FjdHyHMb?foVU)0E{^xMf^LMdta_6%>tcQO;Jwmj5Tv$`V|U7@KpKfR$dB^$#0
zAB)Tb3R^k$kd}S$VW3MWX4!FD44)+Jeq(vEz#^5chD#COmUOUvehXusdZ4C?4|RpN
zpulr<bg7s;N<NXYP`BEjx{q8id?`~!IbJgmsGKLt=h6?0CmQL(Lf{p69_jMMG82#I
zlzwlO*;pZHpBadE)Af$HFIUVu^C`kd4zj5+IHkX4vEV4RdaO{6^)$4*jSzboFd%If
z%@5w<c8XYBz-4-L7k7x<M<OXr@$dLQwyr!r#;f~hLl7isL=eQtJQD=T$UIqQlFTGC
zBi7m}@rst%VvnUtDOzh&72447#vX)HDOy^zw5S%P6|MC}OHtIWmf!c@C(kqYJo)*2
z{E;)~F3-K^o_p`P=X=haR$8Yx#eW7IMm0=PV1~>L-*!ihh6^EkrJkTzV754d4(=Jv
zmX?s2#q0=;6^xZ=910HC3fU1JR3Vd5#5LUHwZ?e+#@Nxd2+87TR%Z@tg%}kaE$_k=
zPAnSlXx&}sKkP^dL@E}IiG}gY@s@1ARZOyEdu9~)a2|x?sJj_ed2UDh=-K)fy7<7D
zLs~$L!5&v|V$q2BtawMCJbh(ZMLNTV<j7WHsq&1iZ2upN5P6Q_hm<&DT$g)<fuW(h
zA`?diUn7fSLZuvTNmsQ$AJ@rqI=2iPD_p36B-#!`s)!_#W>&=^N@HTOH9Hj9ibdQ_
z%={t)vN2>-(!>UA^1^^`=mlP0k_J?lcnhwxthfQGDR9O0807E~d8E~Tw$6k}TE98a
zMY?1vsX>u{(zX)hLKXWc?U;dF$%L}IPee}-C8!(FJCpqC>_Y-&!gla^OlwLx(h6ox
zk;nK`ZXl1Fan_TmG4^EJ{{bK6EI+(M=sAQLchS>jaMRO@mj^>TE9(YTy7Wnm6o%<m
zF8_+oM?8DOAFpvR08{PUG|n~tH~`)qe<5?asPO~SdEnic+mlMMP+=(65+Si^y!UT$
zpf+L53cxNrk9**0l}<qHbFUQ?4#tEh&1X9HUJ>{rr&YcHQ_nc{p^9@=-#&>3Ku8PB
z$#v?=g`B`s6RoQ5lV@Q%QX><N?jn~Vtx2z{`UDJVrk6;sD6+ZJqTl<Ry8Qr7G%71h
z`*>z+T;mg;X8DdTWlLJp=*WRgndN#yvB#&S-cr3aFsb}2ouiP*Ol(t5YugbI8rpb+
z%beE92TD*V%HA##yp3JwPZ^<CWobRH&1$UmkGIh`+bgcT4W<W>^hi$YzxY6JHsSnW
zj1!<_0nkNG8yKBQA|>+jLk}R40)Ey^zjE5BOvLZgvL}Jdl{W5~glVO0lM0KxwZ5>G
zJ@xg)x?TI7vhF&N&72;!#TzixEK(u8U;Qx&v1a%%60YfGJ_Mg5Etw3@ei5-FEqx9b
zRgn_7BG$(j@Hmkst%;t~Q|l*l6oO|>F<xwmHrc!txq`KCX6s;k6=Y}>D?*0G#yFL!
zdJ#Ov-50{RnWfmXzNLL9@suH!lfGLI^M^>0e@IH8i%B}xva|(hUp`r~Ul=LYqq4p*
ztSI$p#{d@ZF6~?rvg0aQSNN+Frd&7&T>2p@Qe6J1D(26y76`E1og~0A-gxqO0h2hv
zL@M2Rx2zul9ZC03vK&R~C@^8o^_8B?McO+cXtZ;M{G#Z6;i;5~TDort_7xFkV@a<v
zvLKHwqy$eQMt6GknZCLmFum5TMf4zTP7j%ZTab{Xj5iVXr;tek6nA=q4{x9{t-Bw1
z!K@{x8|G9%3z@u@)2oF$y?O52v{gAhCIori#BVUC$NdPGI=C{ZZSZCjTYN&l0g$46
z03XDna(WuV{^&?;I$Z3pBenk-OI$4IPVZd(u6jXWs~&lTkdJ9TfAUdM@{!#?bopaX
zHokJ@l-{2`5o!sD&}n=68#h|<Fv^5%P9G8vYcC#%fU427ggZTF%U^W7fGc{6hbWOt
zP9Ogs6*6h^f%{bn6i1r&+RetE%uY<uXP$~6k}1tCx|u-=1?G(j_M-=I)8f&>!>$7S
zF)bZV*STr=OM2&)R!x0oCRI!85wTs<7wC>$^35%Z@RL59{WzAe?AV!1Ri9~37s1Jh
zeboLYnX#lH`QX|+x~squKcs-rz)P&uu{Akq<rGXb2MV2hImyM=vvTBT+I?bKEmwNk
zhanYHt({v2+XQel%DQB+-|#AaX*Hl18j-c~N41#2gd+d-_8vh)1+{^>9H-UW?XM&f
zKIy(4+v-GB^jTexk=Ks!n4T94!v{fgIDK1u1<T)baz$`Es~r78x7?foyGvXiI1kDK
zKlI-Kr;Zf*D~$0XS_lB5Tj7m$qzEqrP8GQ<&d8fnRx<T-$Dj$e>}+~V5LvdEoh?U3
z=u8t%^H<m-#mZ!7{4N|sD9QT#ac>>T-oZwDfox0pcsHR1+qQ^`R0NDIZ$MyVXQvap
zLfEwP+rCG`v#2`GZtaKRBuC>Q^TF!f6dA5HFb^kX+NXE|Uh>b&T9it4mDxE+#v>{8
z11&mq72cghlG{1raS|;H0MX#0C~a}@CMUK+Vi&C(6Oy-jWY!^>h@@!`N6Q{a4tPwn
zmI|&lAjorD-xCChRg*VoNDZwi5DfWN97%<R$Kv62t|B`NY8;hF?NZ@(;iSjvTG<=V
zH)38UX<hR>{$9hgD~r4P#tI;%PnX<}5&Iy0-W`}ke66+@O1r&)h$NJ~Ut^IF%7K?<
z!^)dy3mp&=>Bx+n`fSFPJ>7G+$4|!tLxOdCx^!yabPDs4&U}ZbERsg){J>c)JrExD
z*_ZplR*BX;y}jmt)^h=1EH^vbd<aYM-8PkQ!KYO}XzrIu#^K3b*gVCW4KKciR3VI=
zMr6|A@*R&ie~>&&(B;1cr(}%;wS}ODW><~b)V~v@&90!wFy>;wI*T?tS7?Tp$x{Is
z?XG(3{M!5az}-^3h`1W1U3`-;x?Pd;7|K~yX(;P<HQn<8)l6nr%K?Z*Cq7!@As&G<
z%>B7DpZK~dyX2EwgGnQ@%X$ytJUw3spTR;eqy6`@i<mmP$a1l<g%6~O#pQ~;`4u~s
z@jJSoZB{6<Cb?Yg>x`ulj`>)=dTx!ZO#-KM?-Js<e{)LjIfb4@!zq~;h9K>cIs?q5
z0Je_-HaI(JDU_5*NK$raoQc*yY~GY;N*Pt%-?M-6`p0GE=o33lT4N9NG|8lFY7?Yo
zAkdn3-V(y$GM0DuEjDUxF~U6GqXLSDIrE+JmhxJ{DoHBJuZ-m8g!1v$08joUR#RbM
z+;~!T(V?O=LRfo#h=W$L;hC3bAW?~7OFQnqOp1LrAJ}Ko_Kv>+tXBq>p@U=qfy{~S
zR$utNQXO-zq+P<U&gjm>_8l%~RKx+jdTAl|w^z+Ju;t^XYDnx}Wg=plYQmx%^(=|K
zPZvd1Aoi;>rBMaqfGz$$IwEo}ox<C>aKKgG&W*!=4(Y~t)$0PL+LAc>4X+xy3M`4^
zL#}X6wY!{i^7{p!=s4Yp(|q2=Ax@P<@R<{5Vo=3}#tYA0uEgb2pME%Tfjgt(7cJa7
zD@4}};6Wp(j|z&%Coa8Dy@xD`E7s={hk4%0>f1C25qlCwX!PPflY(^ZxDz*bdn82G
z<i)q0R~)p-sO|V(`5bkCg8IPe6E9<5-k#!_d?*CP+A|1Se&XJOqK#U6>^LB+hF{~i
z#TCN*8xNTeg=y@N3y7=n=tp<_^|TX-6;KDEzX(>v@}j?eH6>VI^umgpMD*CQy3$Or
z^MDX@ZGP@1Z*N3OeqB|=tS7f3uC-v*snf~E6mYG(f8J!dDYdsLu$mt2pguIlXSI~1
zMdE-ad5z-PKG0jwu9D>U0{LP!z!7G{om6#1iXhmWRMT%7biJVdElDByN`@izaWJSm
zUS^BDElG6`QrHzLa3nR%`48?(*dAY39~IcdCp8%u&G3I@xg?oh*fxn@$T_3mRr2<z
z(!hx^I|5jsbZsm^bSGJI-%%|Rnsl%OVN&AWoj4HYa&Rdh7%Cwt8Hx)EX(0`cY`PZg
zNg28Cjq~y;^a^tdymC^<-w_T-OE$zi*tKt5Ushb5Lr(1Z+nrXrI_0FyPq4ecK}L80
z@(?pVVG_+rgWd(!9cCvH7=(;VHv{=X6Id-tBN5|T*N!<U_h+D0>FLy*^kx+W!KgM5
znKDeB1^gW*T@=Z8UY2kWj5_Bm7Fda&>AmLko@bo*-e~T)qjm@NNqN8FM5BEm6Y%`E
zl{63{S3v;GLije%$*a%`G`@z@Vh+DBRTV8lRyU!y#<j5u8bs|GtA9fw&4UA)yyfJV
zlRPdWnxWXZJzh!J!utZbs4I7#8?j*!>_Hd(^k>RFvmnO<RS(<pSCRd%!BJJi^01pW
zU}*=RD)OmLKkL<zs|sjD6&*%9h78K$Oo1kyd>{EvwF(*KO#5q|%ONA2uLI{}kwv~7
zzezaEfyZ#|!WS%)Uf4ik9!<A`=^fj6ccp^eQvI{pJGj4({NOGku!$zY;HPaS`{4ON
zO<};~+3FR-zp_%HN3Xc8mAZ#R%G4?1eAO&o-|FNUP@&B<Qw})et-&v-aap#8#o{_B
zf{`rN@b~tGvg*{qMM<-@@gf|DVE|KS2Sm43$_#))QwM<aHCu#bpqgqlHNiF!Ys;$%
zJdGe1C5VC~15aYNwywDY(x9Z<QRj}=9`6ZV3Dt@vf#qqjTAwQ3)2eWT)nc{Z%rc7e
z%!#h<3prvzs8qJLeLK<<n>{E)NpR39d^-0c73y?YyT17pniY?ZgH#*|YL%@$-=+sz
zi?z>X1(Zd`tN(_fb#&^$VjcM26mp0O>ckDi#-R<eI#lTXh`YP2I-+bH`#Zv*0S}~X
zH0+#Q=w+I?MYtM3He;tu{S>c0^!jRe=Uvc*&4vm3dsv0lI?vUVf??iVC@iXU<h<q0
zsjy1<U+Qux847mc+@zEJ<=+qFhz;Qx-MDIzk`9W`3B)5f8<=^2AIrK&`GUs~gu^6f
zW3)HDcMv_kn6G>;dMtnXRW-rL#<Uh9Vw6sR$58@#A25FLT|fgie4^so+rKnI98$K9
z4=h1YSga^@lG(5v9<ex#fPkbQXChn(dZdk%eB!HLgw33l`gJJgMuQG9KMh1d{k{5X
zI-JG}|5Xl5s!CvAb@`_gSTpJl&YYfbLAy4<rdRgz&BF-(CMpiYT?tWx1S15hGd>(Y
zkQutQ6%3l`-!{VQBwHUgFY^!wxRA6%JGNMCewjLO@JT;lpxrkA^RYVDQd^C7i^s86
zgjFNkg7R_I#6Xn`D5Acy%uBC~!KVJ2z-Y168>FO+;;ROdzyLyKTf^IMGVmu+^(7g<
z06KIlnjxLUBMGuE9l{G8e%3y~Wot3?svqD#>R94SWn1hG#Mja?2Jw%VKk@S@Bd8b7
zXYCs0c^cwuj>ermN#j&D*GEEvUC!1nOVK~-7c$=|94R|p&C1sG*<$M+P0>TBz-;S%
z1kQ0#uWGm1gDgZK^I_(?3PU_#!0~$8t&cZ9XnyxKIyQ@KSU`oOo3d?Weh9J00YP*^
z83?uOkQL*^iAstmRda$SPZ{tJo(<J~hjC3WDdU(>p``q7>*<0ygK^FMM%k)Gt~^T|
zm0~GBJ;J|y(jW^ADr6`q!-1@fivpJs&!Lhf<ggXqzUWEFftf*D(#qGuUeQK|In3F8
zrFA2zf!(<2?ZP2!uvB%;I=R)CrW$0l(qihZz-YS;&~q_phOg=%I)GrY1x?ytjmAhf
z9xOh3R^RB61x}Kp76oIDNu%5Nc<WL=$tRzGrc>Ny^X#6?Kdi-bDNxBn#Oe9p&OK9E
zlPYwLasAn%w<kjg2*#Udx|5?YXr{aG;A`fzDqq2f1CZ-$dhk@x9?Bt1db-BTW1e9J
zU-lIo3Yl0Z`&Iq1Djoqeu>ldFqP5N-ZI(D&jYeadRy;I#%X4eb%3$ZWN=4<F*o1p$
z?d3E(7%H+S*ZaB&&Jx1V@CF;z2jH5*Z6d1%`gslRtqB46+{sb*=U^jHznm9sQHDHe
zT9zPAG8X_vDUyILdUY1xs@1&)e3oSElgzPf{MALoo3O85f;*JD$~m8_k)m<c1;QI?
zdlw$lLj}c#giHT}ODZLG3j{1;sBk2+B=?$90{>{ww#QrTXRtwelU4^zypqWHgjVB|
zvwbo10-KyXY#Oo(iH!nW<bR0z2D+2SUH=a9DHJp(PdbRzi{r6YmWkig^u->B2S%8Y
z5K~tZ1xA=-hJy^sV4r1s0uVu#<OQeJ@DwS^TSVu%26<TZ%6QLlB`-Yo1I3uLDwYhp
z7D4J<dIygD1RJyBJqspU?Jp~|`i+w2lxO{}D5|53o31Mn4Fu?;wC$&&`lPWPuTS!e
z8rDu7R#x|yKfn!HY+u^DACN7QUg?0{i|xf^u^w)GfMzx_{n%M}<wn)=&-?xqApNYd
z(=+!~^)$v-s@>OcwlRNTAsxMV$}h^p$ckS5&y{FOxxOxom_UtxFUxGty2+=aT<P9>
z^$z_!<D=!HFNm^*%8k#`on0ACSPkYBZ)9X<s*}q(=3BWoV%-PV#pMcrtEUt8z^s{^
zq-wXL>WFto_U?jE<|(zh6%nWzyKLdI7!r2>o~~&CjcNo^pP-ZmFLOLeHLz@^rx-qX
z!wdhsQxYe!v=Vn}u}l*3@HSpv$RvRuunm>-006~uN;J*@n-}m9($jSTtnIK2^?QR@
zVuVg!vCVf@280N|wAFqoPmB;#qg45&o%Tz6l!@~)#7)ED8b#WxKZGK5WNc!`2?{^{
zP>!WREGYugGNdjKR(|QI{lcOXpp0|k2g)y6VuYYqm0vQBj8=Zpk|P9lR(|QYah39m
z7AY;Li}Fj?o*R{4x@hev`4M7!1vF58>8kzGO(~Pvu!{1FmM1}teUo+Z3*{G@DgnJ7
zc>a>|OAoEKo=R;)+bvXn>8btFOZjD_-z4Ri3duXhT6ZeH^w!FhC-0bW^0@NLYuYbL
z@($BmE8&r#A)KWg2YNNV(_&=pP~6-(x(X<moIt<EIV@`jW?|NWXG(1qvUbev<D>kN
zuC;@#9c+H`d_t99oZ2re?>K(R?>$WU#ijkCB<+YT2>V|7#jX9q9?(&y@U!~-m#X5u
zWo7hp@dCwNO69eE5HEzVZCH-y0z%nh!6AfDKKtW_j<VCWT1VNvaWW*glYq96_qB?o
zOc4j(4XENv9V}uFZ#$2e7VuCIF-?Y_#^A6;{jTMc0o$pjmQT-!qAkd0<LB!r7mKdx
zC|52v)lsewKsa&o$+xSV(NXRV&;aMqU<x+s+_lO~Kk;GrV52P07k)=k5p1hZ^=S%U
zV+{?2K!<n=k58?FkR0OEggZ5$Nf<UQ@ko#wG>GA<1X6rz=pVYxIko<Xv9z2!HKNX^
z*sq0h?$pSlo0McuZOVfF!Cy~oz?|BmjKg?n>DF1b^lil7veOFPskW*w^(1@$yLyuA
zqd}A;r?#5{8?M+5cWS3!_t628Q@i~azG9TC_olOYu70xt>=(I!j!K44Bz*~Trw$%9
zQvXRKs>BLCV}ZOT`N?CB>`{rBe+G?mrA|mh_-VFzsWBKqWxpUD)TDv{vUTB-0#}!5
zGvKErVtC}4YvQRn#W0&)jR9;XZ111@pHB7{Eqzlbp&uXIMk$6uYi;6kub5ipq9^xt
zm8~s)OILK`CT`{?i{jG<Iy<#oI<K!#j@^cl0PPFoA(03ZHv-gsUBf64*_q~>iTVTw
z-#thCFtJ7Hhox|SCIfLi{eZ6Trv^#1lzgT?oWaF<<ns-x>nN9>mk1Oe1c$^U@AVr9
zD^Hrc6F5<Aj;(s&X)O2Mv-qSdu2NX`AhI9i#}^Dxfpix*?iKr@+G*?`xxRJ5qwL@8
ztZw%?azvFU9I!a4%DR(!QVq-d0*QG{A^4ud9@K&5GNKy5Y!3~Ed<*Qn((s1I=+bc8
zBQ69`E`Xv=V&$QOnt{b_Z<ZfI3&z`9{Y_mX-S)VGpD7bSQJp`gwY%*p2VU2c(pN5^
zq<DKq46PlAsN6ZVb-n6h@)wpX6X-G@Q;%zORm=812|#g(-xF`o(oUf2cn|vD3p#{u
z`*80F+AY~WY8?E)l&aXm2c`y@mG=Lj1YhMN1{naA{esL&JHMtCnC)*bQQV&JyE42?
z`e$|=q6!we!zi=AO%f!MQRe?3W>I035AIuaJd1b!q@ye?U7@3_XgxzmS#?PVj*yBC
z@U=w`J%-QCyZ#V*$ox0X`pTa@-b|}9>@0%NQJ*T)o;B1aE$@#lrdm!u_$s_$#WiX;
zG8(S8)BtTdhE!xClXUV$VGU0=8Kxh$*Rr2Yw4C8wC#v|^*j@TytMEOHa`jrSuKK@B
z$dap!0$c8Y&`5u`p2Y1>>Lw3b@EC|)g16<LcX7QGwLGizQP?J0sr>J1vySre8NwoJ
z-^G@x!!J&^a%G4A!UdrO#e+Obk+@Kbz#iEVbW+4ip)LTR;(4kq9b<SMIHQYY-HwRA
z8w<u>C_!AWkVq+EE)`+7qgjJxlw@|ad<3UB)m^xJMLAmcVd0HbIY(z?M?z?U9*bnV
z2vd>Dq&!F(9BBw!r(2B<cg*LMBs<!h5&MCDMHhdh0n+N@Bhce7cuxyOnS;Kcx2ex!
z-Lse@YaIYbw7Tq*=hTvHy#qUAb`1Xsi46YVTuQQIbnh~rB~(3?qXRC-gz8ga2}fB?
zp~{ZQc{$!X(%ZW*c^VhQN19m+>rlh%Fv{%keH0{Qn7<A$Jk;aZv@lq=<d$Syq%6|1
zcpwnPs*xY%hHgo$uKr&^GI_8&yKn6J?X|Jp2o12*2JkW}30@OUYur}4h}J0Wm~+<G
z!@~;Vp<wqL?@=~+-vcod8@}7{oiA;Zjl~hmt`JXUK|Q%cOYBdR*MgN+XgJvgHwfWd
zSn<>6N7wQc2Sq+>vr)xly0l7FW=sPBXCwX5e<6oDs1epd<MbO|PGXr3O2<(LK5n<)
z_Vf1SNMesXxZB_N#vwaLptJrw?h9}hs?(IN^t|$+Fb@Ty6qDxjp43bST>$#&D!g4Z
z5D>dezyOq1{fnD}y}WxjF^y}>1GXs35=oWDbcpb9qgEtUDr-d-jht5ZB_a!Ib#kso
z(YN$mO@3k6E<v#4)1nYUL0o_FY0(RG3oR`+7eQ9UV(v7{4@U+4!H(H@F;AL6^1L9$
zAml9d-o=Kx!p`yc^gV0a{dhecSEoQ08bj!;JFV-7y6h@)TF+aE`5^X9PU|~7vPn6K
zDFNVP0D$@gNuq_rK8WQxmCU!PlRO{0p+`~$oyl`50oOljU{;t8@{|itFG4b>O@b)~
zQ5rl{NK5S0Au^r-sYuK3oWD;g(wsgzjFaj8AZkvOK5TlR4#f^FnLZprokb+HVVNIy
zk<+#*Ca^2s3~59PN^6oLs}hQ#_yv4e>7tT0??Aj05v(L_ub~4p$vYQ6)hVpqR}s%e
zEG6$d^EF-Ortfx8g8W13+mvED7KdYbZw_iLKWd%)EQs>RWmyN+VZ?j~kH=}J#7{bB
zpTncusVg6F86}g_aiCQ68~>jT)~i)0%}6(1=0p+vlHtyLxEjFc1QjW3p5@R4O7nhM
zRIG={6w{Lr#^}y8FV<o9g>i+D0sU0B&_qx?a(b0qxY%mI9yq;0HJH<@&*i1XwIHY0
zx)&AcVdWKu%!UiCR+<TNdf2VqcmWp{k(}OuUBN{zfS>XZwN50(r<-cQXf2cj_Gxmm
zy0<F2$(<fk4^}wJ75DQaJt@(AT~A70hM5uz#;2!!?DP{U?({ZY{}B`b!<Ci!NbSoI
z{7vjCpie=&R6e%eftEoor9}t|CN6kT%X2BM&N7PA&quC*I{e}_oDxIDU}E36i=c2G
zqOxrcu??x`A@agGrFhNJ_&90wON0>6NXkR8G=4sU=xRhJD3gz@q`r%WY5lkP0J}>e
zKQqrfu0|+^x$AL?&@F?!iBG81NsA|hREnC=NnAZk$1J493@a+(ET}8EY9@{?=&821
znbyBSJ1UnPF4YzKYyrZXiG`#cUj@Wd%AQ_x3?2$Q*#UjDzbOEkVnNfvO*(CIq?)cK
z`Pjz(Di0=|!JsUs{EpJgJ&27bGD|Nev+SeN7UHxsjd-r;N+SYHioLV}W_*S-MN#eJ
zr9T4gzJwzGH46zrMC~fy?vf*D5O#1#fNIDnj;945|1(cl@cEYULP54@oxZJ4(bXY4
ztDKyYNDx70XTUem)pU^p3$+#zQ#Ire!%48LOQC1|Yk8==jr#vQ6E<*8im0p)(d3N$
z2X;@bIwsoArvHQp`ILCUmg6=H_j-`bPV=`o#H+7Hin;(E>gzcMU2Qhs0|IJ_T~uMp
zv3Eg46tPt#R9cFgs!shl+qMQwRM8o1;R8Kmc6K_A`;&6NR}Fihv)^3KZk-=f)z3eu
zcdLa!9to;Wc4oTl@r2}dW)(D{--v`tR)jhg3%Z>{i>s-sNd4#$&u>}@7w}Ly7(%Te
zyF>x<Jkf%XavG6|=UaUc=@FFj-3IqoMDCyVZ(KbOk+IGC@1*9GGB<HwGNH(MdHaR+
z%U&E2uqodGcT=r?rjH6<K~_3Ztfj&)rz8>{Y2|-(DVU^nF^JY8)+244Grfg}64aA>
z(8YdQxC2LhA<hA7@^g6R(I$7-EYyAB-UA4{DmEY=tb~vlN=Mo12W&<<GAAL8EpT<e
z2aVH@hju2h4$!FO)WLCuULMd9NQN^<AvdtxqL^plpC5*-P$EUX{KhD?VdbD8U#rzX
z_W?J1;+<M7CEcxF6h$cyVy?BJlqU~6=)hVp4)|F-JP;EYA_0z?9AWd|gdoB3F8@;9
ziQQG>{fjQb<aPx;|BWgOw=1+0Hpx0&0z5GbWLLdS&#LQ6Hp(cVLJdUJ!W5l`ay9*?
zLkm(+cC{Rw5v?Pc2V!YsY_zL2GAWf^r3)Kas3(98Q!e}UK(!NWtph(JyIjp?v8mN8
z_#l>NQEG6C<K%>EJ+dfW2AmHpTGO(td(V9_I#Tbv3Ym~HuloDwxCW#lSQV`+I~=i@
zDQVaTFrQG;s36#dC~4fFQ&Bq7q>Ts+qj5nzrKxO>1jQqp?@TYS6N=^C@9W}tN|@&P
zLpKmgUYrgKWyr6ISOHkUgze)U)7wx=Vd#P;lv4B)vVW0MYcB(ENGKb<MW7Ws!_BH9
zZFv=u9SPfKANsvYDLd}t)}ip=kyDBX_6Zr2EZnJ|WK3ee02S4@#+r&arC0x~ketYp
z*nLQJs_6NEB?Lg!xj-K8U62@aV!sB8+o>Qk?!*Dxuh5Otl9>HlfG?|2^;Tm$VB+vH
z9MR~O0Wj21#obwTJ>hMSuQ$4>==;D{dKoe^P0lY17wKRI9?Cyj-Sd<k#*#R*^BzNm
z51PFyi-SwZ2QBCTLmj;jxDyv1V6lXRZv-0ZEd>W8d{BJiG9S910}ZuBNuH#B4Li>v
zKg#L{TL~11e`Il%65Ltn571DrO&31KhdZJgw_R0IpQyF+&)#u#kGlNT&;Ig(;%v(K
z*e-xvNYdWr@EOBY@Md7!*K#CnL69x&2Ss%o581irn&$6<g=RcjSP&o%Iy=ebcpFco
zDw%K8?lab3c6sUJq#J+xW)g9s0iS$f^*{JZ!R=4J5|c^y4EfrJRiRJ?9^);kJI7+F
z{%WknySEgii`a`tyN3{b9pih}U?BMjHiSuD<MaHy>%etHQ-GGFN`7H&@U_IfIH~H`
zS=^siZH1SvS?wJNv)Vy6rAZ+xBddyX$3akV|4*uWWcn-O7=jxhsIm2Me@1i*5pM+$
z)G(UM1-#~@C_g1OuPT%bUx<9^(etP1`w;W(<7%uaK~l|0mKg#pnC%w8)W}JRKPmxH
zxV%6#Kx99-l2UrUUcm%pNlLG-K>f%lWX#Bd7^+Tb=qrFvm*CW?L3B8&YZg9JL;G-2
z&kMLqiX?YZ=E?!Ob(b`tqk<$<z1MirK_B8V939oB&7Cy#=`ak0&<)_7b}LvdVIV9?
zxn&1pbrXU7NHr>e0i~();%X4&kzqz9Jbb}(LF+S<tM_8V_{6G>fEGGW(P-*0F}Q=%
z&zN^%4bffTl=DBVi4%z0YgS)D@LBHvuP$}QRp@9a3^6E%q5`h9#B-@>t*mn}*|6$c
zK{i<BTh1sw<G!_!g5ZI;T@-m6w<iyY(*^}{0ANk<Kxi)PGCMz2L`3}<R3q(~2Q&Xb
zq1TrE{r`oLScD!Kzw=ViR>Hs-kKCZC<=Dp^8<;?kkEWBrRES?@Jkv!%;D}Y7ZxBK>
zD*L?4_DGHZ68n1X3eF88*h#(>HW0c;=)LjoI+~+{edB{idMwq`ge5{pA%{RZ)#JEX
z5$R;HR_c?fmoT@rTG9h5p0c%ODNaWe!t{!t;$yFVC~qVzz5?XXZ4F<rRku>CjSI^7
zo~cR>3IpmiU?tro+}36vA5irwQv^Wen5`{uAoN`r_x|B+Lk2)serp{9*9nwJcvV|&
zNQg8Z_-qZ(!~1D{xuA(o@3^e?fBpchLCbZ-&`@EOEmqfSb1Ll5*0u}0`f5^GzNJ|^
zH4Y?swu0K?RRXRjU8iMM^W+Ue2LN%J6^T?rf<AUw`&|DDR$nYJf$FyQ|FjCeM^GQK
zb>I@1r?u}1>V%hASV)F8VQHU4M`i1XM>amnDhviK$6Lo<7fujN5+|1Sj$xmo&IO}Q
znW^N@5v0@j&io3B$M{|?<?JHz&C5G#7l(#PXx?gEOSI1gB{u(?L=MN$77w$s`TH0P
zzE=FaRj~rEY59+WFth4b6(Q;$MgYfYhy_o7wC;HT2gj-+k&XK!{u?(fc*c*5LJy@+
zzX_{MkVaDJdwMj|7f0dbiwd+8yK(Oz#W7dd(WL{00LN%}By`Pkc<d$kF^VM9j~`MU
zA)WX(D~!}F{W{VfNGOKigJ8+RvKG4_Us&@wt;%%yl<+jjhUVH}gs2mnmu{YzPQO;Z
z8~qU$q$(;XWqkOSk_}F<H5&iz7|GX&I&zgEw>GbYL&67x1US>{9V#3`Z2niM5P;Kc
ztI-*-T<R`ju>~zvpv$WGfivC~TK6KcCdb?A4Ob~l5e#MxH+-P%5bBhJ$bOJ*hI<tb
z1ZG>*Pl!;I0N9eamTWCXBW@Ta#omEGJ|)SkB5LcvP1dZ;6ei^=^n(wDBWgMu3hhJ+
zBC;SABFK(bAA1zoRmEj%mz@v4KaI>eJKfk9>LIaLxglP1ck>#m6=hrR;|MvV73B&5
zrlrhhd(cVY>nyeb+2Ji&e*^^}+Xj6&s|w*m9;6_c!o;HSwvh#81c@r!#+GH^JA}O`
zcH$J4=}Z8mRDl3a84NS|U{ScHZ&#pBYA+bqyNQ4tqeaj1ntOP02i8|r4%o@v=3~rD
zTEh`~suZ%q`E3zkS1HVv{}7N0&M9UhUK%?BXpC+ty#FK3po#MG%KjU4=l6Bvu2PC|
z)67|X=mb3^Z}ry)L@(U}Ow|xoVY9yNIx;1gP~@+|m+I8l{y><~(L3$qrGs1WXh0}O
z7QtPSP>wafughO_$`3ErB9F1`gB%_hM8t!hb5fKtdTIFIR~$M*3QK>s#uL3*opkfU
z9-75TzB@aVp4_B|UU-)jOPQW-g6IfxBEQVqD~teJDan4d&a&tS3hGGNKY?1>)V;Q6
z?AVe>uF(QZ0<~j1XX}0_4*bbMbD_T2Wl&xCpejj{YOmTABHj{t74;6_*%vI@iNKuP
zs4=o(;N@4O%E^&|MKuYA$&wuPbU`~Nl&a3>eQ$9-jsr<lkp$74Y+ivok8sSvoreXg
zN{;UVqd9HIRz-(0GAG+NOl8g){%S9oi5J*Jm$8Jy*F+_g-1f1OPflpwlHBQ<0<RW`
z@yXpn1-K*cWv>}{io`yvN-Y1Lex^Mfpr(pCi0<S8Q{NXtn1UoHXEQA!eu_JJ*sSYR
zIa!iN)yy*MhD=T#cYAt-rzpE*AoJOzA7%;plGx&z+7`#mp(;$6IjkV<@{AOiaj56I
zX-<N@Jo^??0090N7yPy_nKjGrUQhs_F}k$y7ki*65@^P<Wb}tfg+ky$OCMqb7AeLR
z^GmoXKphp<ztuxAb0me*`mfMqks@!peS+@M(zahpTadb?9Yf%lBeo`ed7`WqrR@EF
zIsi=SM6uHmo=*?BkvCo=qD%5&Q!{FvF#Xt5SZu7<KYxdJGOaacrorpM>AAXWP{y;8
z0_{<=QlO~u;%^lJnpfXYuKcQ~F}~}YXuKQH41X8#=nbBhSzqq;u<5?@(P}XX6~hzZ
zlJ_hlfCuUk)*YZs>Bz94E-|JJkRnG;soXFl8WXJ8Kv>9wcuubN@FsaTU=o~C>$Rh;
zN&X!<C8QyshFU71AQwUeCwMzj>b`=+;CQ_!`F|`a4J+BwMd3zr1ty|~C0JIvg^*(M
z9+=B`)eVjJp!uFFjXce9Qp_u`KxjSSq_|l)R*ED`N@92WB(Y`iSyED0_2xpaP6a1A
zr^a<+oB~l!$vBQgZ(@z{DIK>7#yeiJYd;0ftcpA*_6m-iU!l6pNE`#j)JSql)*rah
zh$MH)z$;skB}Lr{P@6ktXy>82>rBeXssRm1*DNVx9SR&#G^C_VID;T8S_4d&-dc|w
zXZWb{YXDFz()8{ZxdD-X0;HjCeCN5LM|KfWU`6Nle;nz7y|C3)0;`9=a!^rcj4|f_
z2Z07fe2i4k2&wOK)P>1-3U_(cpgb$hcykbWENioxtnr~t8&(}{O(@1KRweD2a8hdg
z*@I8KyzUPar+~G&vm3lm#1^F8TM=4Eq{QyC#4Y#ox>h+V=T&t|S<wUYkO@NkB;(<I
zcSw|da2bD^7~s@5dNSBa^DCK7&sLxD%Z;*UlaKac#l!|LuEQ}xY*4y#6&?yA#dJLz
zD_a;;<Lw$-C$oxF6@Wg;_XamoPajP017adQ0yu-|cRptfzaG!SX0b5JDbH6pSio;l
z{X+=tsXnb{0>Z4zQv^H^d$w1*z|*BospLovh}wr|PhoFH6>@6O@PT#>>&YphH<9#1
z1ii?q^>f3mgk(vLXb{Jc@s&g$!PLlgb7*EFOKQ_OSNPYfqR5+QaSmBZMhNRkPHjCB
zv1Mqh@&81p>PWU)$c#d{>?3!zBqVpLtB|1pNcHVz%&I~^v(s4}w#Sm%ZLI<mR}rhc
zuf4YcnN0Ih^~)=3N-KLk9lNL4FH7p+@qv8XRi~X-HX^_;O;_2N<97_@MIj0bs+CQ8
z>V#C>^Ck&O0Jv5~CV+M|PJWw5WYm-+q$+0GoNR~#&1xXc+&CnT;86^-A0WY#&S~cT
z%LvEnN#_Gg%+^ZMq9TOX6rn8A$44RVA_ZpBgLK=Lie8QmCp^;HEw~|$ROf@O+>ND&
zQYp`;PoV<Enx)bY0)>=Dtkf5Ar=kdt@$2Ag-PzhI^JHH!d@~h}M5_O-vY4gseZyV}
z8!6o7q#ynp-jdX1I^I@THE6ERsc4~(K|SI304Jd{BjJPU87S_U8++bx32ov|-b+w;
zrYp?jR$YduP`-Zmck0$4-wC~-Ue~nAhuc-m{SHZplBVncJY#J64p955l3!Zg64|J{
z2o&NpFe$V9oIw6g5x8QpSJ}L95L>Q7cqog#hBah18$Go)UO1>rLKG?Nwuc&J!PLgN
z!Xv|J6S6(x7S4HMt7g0Lx5kz5gs80*c9#h7mF>+6U`G^LE%sLTY@JzO)B)tJ#H~1x
zLil8RQcpPBYekud9L|6#M_6yvq2@)?*W(VP@qy&FXUMInk1@bOGjc3i?|8W`E&OF&
zxgLK{(rHb5pOigqJzPP(uwLM_omJ&Pq=$;?9QHxic0w|AZV~q3Rp59db`A)kH`P#4
znjiq%9{PQB7}NS(zSUE}SCOH*oj|s~{mGhi?L(MU%<Q`$#shL;l-Y;jUxY+U%JmTx
z!~7F?TY=A@NHl)%B%>Rf2=%JQiZ1>diAF_Wk74PT6&-X}IHD>1M_TnKbgWprRNNHL
z>0(XN=C9-GQJ&9UAQG?0W8ArxZ#I<$WU#cS1m_uzi+OAX`kD5}3!z8Q^O%D@>Q3|Z
zMyPR(lYP&T3Detn+GJ%B8S7Zb0GbH-RKPRc_mrJRT1K&^I_Hp+P9&HvEzy~gu0D*a
zMp)#(S{U$x%_l;eYa~sQ{!Ua-Lfm%Aq8Mn}UixR=;_Bj@vyXVxa9?uR7&V|8qx@S8
z6VZ(#a!_}8`5?rvh)zMmq_obBbtM0fghUr?AvkI@6BaHgW=GH&zz>jXomLi_e6xy<
z6y8ACgHY7qi0E4l(?i(I4r7}xdbp0+(X0s&T)LCBqviAHu&^<z=<@Eh&O)3PttTwZ
zY>6L$Lg7MAFXje-$28j?a5~gDd0|HzxXn<KTP}{*k=n;kBC%&=N0*vnDkff4k2}~n
zwW^q@Gr?Qxv&@;`A%f5B$SQ#zpeAFxBm1|K8-57or<hALVPFgY)MJ)1vr-8QxC|@6
zSbMYbIEnb8(b;F?MQPv-Ob9|;v*TWx65zd?TzK4}Q6M6Qx4*{l(oHC4W@zm1Z1)lw
zrP&6XCswi&iBOuqsWgeCF_IUCVMnPd7yyk+UhOc4sSkCjve0IDIa-#C3#*uvNnVlr
z87(TU4n|HE5nCj!-z7qIn248z(YWf;wmk^WEEbY?<fRFQAy#O2jtC!Olzq=KqDd*^
zcU2egtBGK6l#V1FsxA(S@u%sJNr){}C7<l|rtosXJc|%>_w<#{TiGb6r(Q6c&ZY@`
ztP_`tVK7j-u1!5Qf9a2b7aOwaRj+=69=L&76=$ARb9>f(Pn1GNxL*ZEe&kou6n)I&
ztcUBpykVIIK*eLLeI8&7*FKMlOPbGOme)vCDV$XKudo&(lRK^YULBw=J}q#fs?f?U
zplKoJJNMARVd_=t+*perh`LQ_jTWa89!px2-!m6r+$xP0(j2Bm1;Z(xW+sYW1bjQJ
z{}gZ&J9$Abv9IPd%L%;AQG14*mNW&I2wF1ri4Y<leRHQdr#R^y!kpH&FYZsm<qmwv
zkrWDZsi3de5r++B*CL=B#7?`@dfxL_jXoGA26RV)w!UM|mg5*91C4VXI7wiI_g}dn
znawjdVR<ft$d?wHP}o<L0N#nA$MKSk<7ciq>CBfGX4g?8vZjk-2xd7gx61t{9#9Y`
zO)Ac8uMHeT$T)RG!UR@Oy!^g%6=n-95fO`+hR51D1N=S5J0^VZ*MVQ3h_{hGY=yfv
zp)7fKQi7)@lrk)<hFJMDFrl<!+NA!3D`t)T&rf|=m=Ccw!v;TWBUF_bHt&Jw4L!~q
zw!gw@qP8;aTqc|sg1TeFfH`;fUw)oAP34=&z6-dFXw5Rj4QA=PJ-H18A|@1pRDN(C
z<)&$|9qCvSf&ys8**Klt30#jxQIHv?vTXGTLKMO|_d=c?i${*}NCU2c(xqR!b99k<
zglB{KXA|V8O7JFFAnB&xoZ8yzV;#8jp^eVm{qr#Jk5?BzV|lV9pg~<ER8mw18;K(C
zm=~MwAax!TD!?zw4@?BpeH-x`kapjJX&mnFKoU(Z>8gnqvzMdO)jxp!UBu1+Mf3#k
zPm~n$zL0AYZN#UC-P4`J(;KXvQb||LkRRgK8bmR7x~cZGQ{L3QIKBBaXb;+6Oe1(#
zh@|-RxUynjF=VYJJuzX=Hm0D?3ckwe$wkQIOiQM%pnE+~M7@vDOO!jk{kdC$=HQ>$
zxsK`_4GAdEo>Uamnyq+lL-ZUASv2kRKE=;)PZV4Y%k^)1|F$-2qDX(^p{=PWnGqV3
z(}$$N2rnjDlGAf`JA*vfprAIG^GSZvm`Wu<Q4`vzR|0nH!ZeQm5XS)#M`WCQ{Lnb2
zHq=WT6QXH@U{2B+VU(E{1_o#|#0YaYBlo8Wypi(WhV~Q-nHEpcsfVQ#a|1~s!;0!K
zm>?>&SkAa=?tO0cRnH@=z4b#UH6%r2OOA)~cPp}JKU<_bYwY+&7*tl#o_;V9kdE(f
z6=9>4gWGWX5P9SyfwkyKAoy5)tB;U0U5kh<ovP-=wLL$Tc;=q1{IX9*r;8f_>(9Bh
zIrJ2F>C?qw1o$KU5em~n=egeXydWwl6Z6-+H~8s~u*tW3{YN!SD13(dui|_eKm$oW
zer#)67de)MGsX63p+P2PPTwSWA!>=3@EQ(hBmjxdO!q|I<9q>!;JPBBZGa*wx!Kq>
z5x_C+$rBi&%X>U2xY+3u4w>~IuUD6ivH;?p5eU|zDI?VHc1Aufq9*~1v+3jMZ?V-Z
zW=nLod{Y;M(rG?C$uA74tb|^~AIMD6b=FojE>0U+{zdj)2_)Z;+v!~KLymXYYr=DY
z+1b`U*We93qrMG$0^6O#uC5@-xb#xZ->qkKsyP3=#om^S37+gloRr!AelqP=*7A#8
zJ^6$<(;$bfGi4gO88<y(U4(BQ>3g7>wuPXW-8pv5KNG#Zuh29u&WY(^o~eb18Q#jm
zr9-!Tr+a5)X_bLVp0(yzpocqhYZoSwT{$lLNpn-LbtjM;DR1#WyQlX|>hs&2^6b})
zP*4{UI0#Os@bI^~x6G9TaeJmomE>HSd1d4K`#i@<R_~{)b86ChKhL@$+%*)>FT?JT
zwzZhaN4>AIuiJa1AH8+S2Vc>AH^^pxBrmQLn^!f7nj!wp3ymS<F~`Ff!Mb~vJBJC|
zy>#lx(T>{Ov2LC@@hqDV&X1nek`OKr&B-J=l1$f-qKzoOo0$Oezp2VRtM+c)EHkO)
zfqbBvNRXdA+e4qX4KI#x7^B9;gw5qUUC84KireM?<xsk_$Gd9i!)&;MeIK{?bQ<N%
zuF&qlHedn-F}1krZQFH(Eo!^4MY|ex!p&Vo^2n~pC0_MNeX^_R@tDD4Un5*C_uKuD
z<v?g4-en%9i!tPq&)aJ0YPY`3N)@Y;UG~3m<WRbR2@jrpx)LsX01w5Soy6vwKRWOv
zN^FeUH?jXmx4K=fSFhobO03lE>YfRl?i$ZQjt@)k#Wa%yAN9-|aAyLLMO)Bj*MJNj
zz@2_wwt>E;%C2F{BWzl$ECI?XZ^NiM3KU!w5Z=VN;V{#PO~|fETZJgD%o7T>fT^v7
z=M#2QiSshO^B#SElivMtPfrgLhXv_@XV|=&39ov30)ssE!MsFdU?d=({DxF6rH^-a
zZ>1H3D4Pnyb<$phXpSO>wDy{yHJS8ptfGe|ZRsIADS^fC*~b_YVeeqYcKkc1JU==^
z4<#t*p)@D+u2s-OQ0jFPI?t^=V2=$n(G+h<eD%Ri?z*L}b__CLLnBKoSK#dZzXK%g
z66fsKgeF&ldV(jtGjYHdUxewaa3^M8_>CS$Es4X=7u01<sa6cs>P{Rzsyf|9-HGEH
zjnNmKymVF-R#d$}@(xX_Ij44ouFvezTmLL?PMlp_!3t<eT+lTTcU;mPOX9*KJfDs>
zaBSbO`N&JAU&BVLMHJ;dUseTSt~9O8d$i)G93BOhbaRal^%rGo9fyqKY?e4xRqDL>
z=Kj-HRp`;Sdo~{GoXpyepDVziEQz~)g(N-NCZHryTCJdNcqQ!Mm*7dFRH~%wQR|18
z84tNT^Whd~F-JE%N6u6{rN1t`dl^r-Dkci}<?AY#QuWJNeZL(_s4spPqg~h#k|oX_
zqg|1ss_AI*wT~v#)g|AGen)qhyn7FKcG!$m4=GmHqy2I9SY7IaDQJdgO`cR?_8YZt
zY}AvyW^!StV4+IY{FaM7!EF_>F)c||C*3FT1SSbdHG^KEcQJs7iWNU!Rn{4Z2+GP-
z_qg!9iNbPH!-+S^Q?fa!$!PeyQ&1YPL%~Yw9@6#b5BI#mda2%|`1iydF4-)0of9o{
zl+-1BM%jMx20U~C089K?00?#ldWgjmu3T2jl9ZC!TmPkUQhE@B0I34NYtH!aIQRNf
zzmyX@-nJ2(3@3KYF78sHV?A$8BG>?MI+8Ni|9O?gRrbJiKz1h$==LL4oI1%M$w`Ag
zjzo$jVH*leO3C&bN*oiI6&-e%k>6m$6j=czx}c;45f0D*5(O*H!J_a_{b27gFJL@H
zrEZ*2jRPPm#r>shf=t5RLkeNozBO+F(ByfG=2Lr;G4JXSE}N>JV7p+Ew<-T))q795
zBuNEf0KUATelU~jLbn3WQ%iy-6)pF#<<;v`O=qz-*V?kt3&Hwg+)%u06dQeYp1@_;
zaslfGR~^nrG)B_)bR|ayXJ=OhO=B2#eqP&0iA5kb8MEhuLpV?huRN^3`?K$JPb{@n
zX7#~bd{-GSwj!cOI`RZbWe2L#%|7ecPzZp?V?0@&(MVX*#xuQg8;C;18a>~n#HFWQ
z#;IOMldk<0N49C>tp>%sGPSp?vb&`r(fWc9o+IFt2A*Q}3!9JODf7pq&f!28MU;+2
zY3-q$1+*LD)!16;MX)d3_w3ecZOyH{d~}{+)|y||*X@SZSMajIx}=T+TV2*Lo09TI
z6<fAEtl^6gct;ymPHMaYj@Tk(Nw!L(;J&GiG`P&xX3HVR>hrcH888^vzN2Jq;3@|@
z2|H~>7`I{OPkHN3m~LzQTU&Koq}5hQ0SKu>jMm&%`x6Tt44{kpPv@=}0-wd&cF~na
z;#@GFO}nq$$;5Djs_dXfi?!>!0|zrswRliF<;d6b!`@Z3MGQ{Bi*C;WfD@vo!Eit}
zSo@nIeP~KU0F0JxtrRt=qdM$Cop3ln^1`7pir=%Sg{>oAL}!a#MWslgbQ{y5A(WVO
zP5kolcCnvK@Tbhd*-%08l<R?a7S7R8-m8tElOj*-yv5!yNDEy?Ri?aR;njf=@(<Ik
z(^&9rVI1p#YGYG`SziA0Lb~f3SFJnhaof}+0*@2M^}dRWF_%1ugp`n7R!g>ST10~o
zvd{hWkm4t*3Mu>CQaDtHWeciG`r_wYVi+>+9Ty0{0?+Xe#bOSut^>od(-TP_M8n}p
zcvBYcFQA!zWS}1PVgZ7D;&4ldi$F2{n(O2WL!Ciz8GjEw^qM$<tmK7_BI1gNA`I{~
zU1ld;q5sBfBPQ|c1SK7Nvn-nL>f)_fzH4S7sD++L58uJFTDEEmXZ`rMZ^TvB4^`@z
zAlbZ9qUv~39dVN1U_i-GQoE2Lang;d!fh7YAX19CZ8dsAs>Dm0+ZOa+#7rg&$QIhL
zY$BRPBpR(k*;a21qDUwpDo8*m(i*vJ4WC|BAn1IlVW*H124e-<3{SkcV5w7$PFieH
zr<7Ex0?}-1F%d4s!oI;dV;^?sHyCvRbE3SF0)K<r;C&Pk?5u-e-_;;EoYm2aqW3@q
z<Y?7dk6>|1yPOW5v^}7hZJqAoSq{fJL7kXw-4hycHv)kOxY4h0N5QuW1Jut4nKwmJ
zylp@ZY&Yr@^EL;4G_WpVLc*jvF?Ke|s;eM-_hm<x6}<)E6AC+QW6w>6X*tKcsGF7w
z;@Q54=7!r|UUy-_XTKvogwN!`URAw(69#ujR){f-K5<6V056t!HxUUWxV1K@2jJ&;
zVVW|cKfW08=qjW*nEpju<(CR64&F_9r2JAL#lhTT&6Hm%q&Ud4|4;b^!POKCZ;+DW
zAU6Ni3(7Bj_%9Hx#zP#ub5g+#MYy<nV)&&ZZ)phPS;rPWbwg@s+@qj$6hiugm4m)f
z>Py#JDo=8-?oAe}2jA+{eko6KuxaiH<rkOw3vjOBl(*JI(t<FzN@ek`*{GG4-UR;;
zuP}rIF8`Vg<(FN@zE*0|5^%7P(5UIF##rqYlW*(~jZ<o>kbL7{DMALLNPD#jo_ym-
z0fKikatD>HCf_&~`yb_(j@mEf$u~|_D^GBtPrhL&`v^xsRHo(L2t}@q*mLd9D>c!?
z8*u6W-?w}vgmqDy2*s^9_Roa<3cq$m4q{0+U}L#?^`c+Y5G~_|^8RVMyI{0WSa-Dw
zsJYmOmB&Lr(sQ!(bgKyeVv7QST3==(wyvf|u_)ZhezlRAkEpa{|7{_9QjOMss3eG3
z@K7AZj(Y(%mA8w=)Elb6rp(E;i}3<fG5L6My(8F-z@;sGcXA`?OKNg-Cr5@Mf)edi
zQ!ic6adUEuD;Q5fOY`qBuc=DUL+<4GJ}>mO*=m2NC)q!Zr=<8~S99TR%7$>XkKE3`
zhQ9tzx9iZ7a&ou&2<S>bv)Ak^`hxvhd`k<OlLyQMAVv3JnVek*K``lX44a=wi^eC9
z3K8NkGi{kX?g3)8iM@zVo^)LNB#wuarglPVRj?^*k>O7e;dX`-gG()e@*I1T`dkJn
zU|1;2f{T$f!XAk12YKP|<FGWKZnPIEdC7#U^aLd@eI~}zW+R;7EwA`c7YapMJrW(%
z&_)n>dHuH^2!hNgn;!hEt9;vU-%*ORW26ovW%%;+C2z0MKD6?^zt*FR$#9?pH_uj8
z$A~p}IQq7(3qNKqq7BMFA5GR#PUk(<QO-u^>nIm5BGjzdR^ZiN{QO`<>t5{Z8O`h4
zA_OjGyhXydzt;tpr}I^gzw*7lQ)n*@k2b(xRE0b!T&8E8)OiJgEu$3gwy&s*5>w4!
zQLdEAk;9eM&X+HC6i|bQb99qCrP{NxR3P0cwf?hAPYQ|LEs%oP27*MOb?d^12;V1y
zi5w{ns|VsDC9w0389o`HCz&dXkN3=n6gI-<-xO0mIVGkp5Hw;NF)4BLvS0C~Dnw36
zd>vO*k<XrzTD*9$myfV?(3kiW=PdP_hhbx0L`cP)@vCmBrgYrZTpdbvbi2MWh<47M
z(yPu2Jt?!9KBQVo)=l`li(Qjb2HwE!UnBt$)e|vAh`vY}S*yZGj%_nn-{OP|{sM_f
z`CFSCt5U|6Jn%J^>8~Mm3cIiJ)c`R7k^LaeI$o^DMM`sV(ITiEIj@e+q$A}cAPMCu
zFv1Kft^m1k??-AsFo>*YE8{QfC~LEGb(9UoMoN*kICjz8MDk}(x9Qs2`PwR4O5VK#
zA5Z$T&l*4}(t(AzR*Lu|>F{^(!WJp=PgAbxG|R~__~j#*g2o1~HSZ3U<<swP*7fRa
zn(qE7T`Wzg=_!aYk*?f8&N{6sM!B8~-wcr=-+o1RJ(cg}e6M~Bn`3}y43Dn4yy1_|
zW?7A%2r~Q0@_Y>vFX+t`sXi72J0&8QTIIKzlw?i~XbDTK;CaVZbZXG(e|1YHHT0j8
zw5U6^{>-|RB&S9+L4H_t$#a%SjVwVP4%&^Tc`>x0JGI5-EIp}p?paETO^ttoOjcNK
zVhiR}TWy3f6_!0dK~A-g!*iR+C#SmBz)UBS9I5T*Y(GJ)tGsNd{~?is#>j4(Y*4yw
z5+f}7Ku6)xs`pO#SZS<$@cJ!hv609ayx!J_ehRW8y`{?>C8v(42mc&e*O*`NGOpCc
zbUq+J$cf|xf(^5+MN|Z}JSWmDdc0$6a#~(XDz(zgt#@h@aE~<m-`={UN$+1zrK>_(
zw03JFQcC{##0y%psW3zEBVgcmK!R4nJBpTDTRK@+_r`BJH>NyWy-H}^Qt6Us)uTp=
zVUndUl7ObxP*FjhVZTc7j{Q39GhC%`Odr`<y=}8q_stBfI*pl)%=iA-7l;P=Ve?XT
z)hQaybo^DiEz74y8+3)v<c85g()p$bs*$D)SE^!z7h=1jdDHbrs#BBFmUO3qy+L^~
zw&sC=vE1+SKuPAUu6PiYOh`B3A0b+43@<`q#zw>|a3}{7Cdqc6(*PoiSQ@vz%JzM9
zCz9<o9A!R)OST8~f=PxJ42=#K3Sv)3N;9`Tyt&Sx3#`+<n-u=!wi_=_Qso$5%a)0~
z*@~ldP002bA6Rb1MrC{48dxPn64D>_JudWve`d-t9V|<>r*FnVn-<Kl{v;G+8L5yC
zp~IZN_1);w8kh*NXuQ401KkC{-p6@NsEmJ6R_)*QRSo+4jy}KA@EY&yhho$;oJl>a
z9FQ3#Ksx#tJ=uZE5+KR;H@~Iv&v@H!uS9lqP3b_s3^TJ%)bN^8DQdJ+Tn4j`g}o9r
z+9lipr1`&IY)CLT(g!ayBPnI^0R-0;p*+&keaHn%C@b99`$URi)h#$K(+i7K+-gcN
z;gU8VL|8kqoV4BdSs114+=M8|glEroT`75gvPtk)W^4XnA1B31Nk`s7OenD)`B>M7
zf;M6&#;uj)Qz4;rP0MBH#FT4HeVprkpYlkTK7n_)Sh;ldS*9M|WY&VDV39W-!wf?S
z-qPQx$_B2kb6{q8Zlr$}DtWub`Fa!yjS2?s-XZ<F1sP~H3gp4z@Ctkfw|yO|2uYAK
zf>cRU)}ie1FT`P0!|1T(<fzdK`amSP9YGgHQ*oCaq3Q5l6}e<bxS=3GM~Zlg=)EEr
zpiQ0N3PN9mWk<89un58@J6idcG$$mtqjh!~J@Lzq1Op82Vgqi6?FP<6+G60J<miY5
z&mvd6!=0>Ri^^4!qrJN}{YbZ?OUMK|U~Wf`2OsN6eg3OcB7ih~h8T4^S13pJ#RGLr
zWBOcVxFxoq1K;9u4FByqw+d?eIjF&7k#J@TrebuC;@_+aK)D%jLY-*(g>J{>Rm+8L
zG4X%<0Jc>T{Ugl`M-(5CBF{E$62za$_55w~baK5gYDf)FDdzA2IOmcc3u8S**4(mm
zq%RgLH>{WpuUN!G5Q*~Yu<61nffZc87Xgk4Pf5dU-7dTBz#Ftz@{atMlp^gOcQ&5X
zBklJ+Ro_El{;)8we^+a3u!qP#`G`G_J`c%1z59$-E}!gYqZGsGzYrFSLa9w>+tA4A
z(xol1lPKTDHgy1Nq(8>eJsmVgH{1w7aB~{cEGQlJ7sT4XJujv;g(uywfiO`hr73~f
z$Js2fpl&js2R9OW%~nF1&$0*rhJ@oOavj|%kaVQ#2aB8ONP$y;mDCEtx`Eq>oECC5
zT8|g1S3R79kIZR}>@f4|mV8>1i%5y6RmeLRRTlteN{TMXjMb51ry(+$#>GzJ$e&>O
zb**l>r6tY489?LX4Wz!b$%GW2=A5A~*LDDsz=`GDX`RBG>TD8eUDxeXGZ>XCkhGqU
zKcUMqKCSOW)ngFzADoL|N0`t4>yMkn6Fi_UN(Q8XDHO4SKD*L}{@Mi2zu@uQs?tV{
zdsA5L{L^x4AdrB_C8tf=9F^iBF;Sm7ZVVL>>7AR8X{sV=4qn1M=o_{|-)~@#r<4yZ
zfFo)M9mca{epDo($jbtk2sSLnvtkw^os&{)+`VH6#jv5;W^b=6l?c(a`5QrJ1a*bm
zMXs;3z3!|K!Y1u3f^RdafA<}vXAmi|`>x)`_9IlsI`-YSB?5v86#0j?NJAms4y0qL
z;kxEd9z0Z?R4$k0{HYEvTke3pSk86Wr`TrHy&XjML&T-C32xZ0#CtpI%AZl0bv*DP
zM!8uHaWGLrTkCc1*wP6>x_<?E2?)y*MBdW~if4iJVq15chscB`-Pd>}n4oh2N}7(P
zkD{8i$?4UXAWbMG)q07DN+QXg9+E%9iZBqgusJ>K38K(JG(~14INDSJ=44n3;4$Sg
z)j#Xhk(%eh<3r>^h9l!xb&-{yYSQD*_l_Z4a(ZI&KuJeRUaR|hb9&mEsXpvsv67Q*
z(rR^WvXLr?HroF3=lVuFH$dbTg^TU(z_rNfJ=QBu>HNVPmN^iW<VStBz|BLPd_Euj
zJ0Yk8c(k_N>2Ew6tWzrKL)uV_4WLQ;5nn<qC#R38o?{^-bNcv?-}Ph8AsQnt>Fk)1
zKKa+8niPjKZFnpAleSZlK}wW1Y39{a0-tgiG0ZLHX<x`<$wPiRQlYeX22vrQVNHsq
zrBg$qDP=`aW(uXO%G;GeDeK<^Fj%a|Q1UBo*Sc%QXCEV2lgMS?acCW0kMW2{`nd<8
zvk9NH-*U)IP*T#t9RbZeJnZ>%jgNGsb|8gGnT`SZtJKYwKCn75rvit@dwWOtvsqSG
zKj`c?scfYZ$yPnsv4wta6B@#g$`CQDIg&kJD!rtt6i6du`y(9wGa4Hx@?Q&eIh&>1
z{Seqj<dN?8031uC$d6x~(bfF?3&f(;c$h#seKQ^lxqm=%JFA?3M32ew&H(1hC`c{P
zNu}`mM^&021Dtdn#t2HP{{lCDN{R?t(2kG*PI~dNZmBt&zC>UJv7p=8^6hhUoybn}
zPl!Z9x#AC>pj>7rV%7PwT!56(-cRS!COe%a*zrX!+1b{Ou#*ajEqUN-WM`+#Q+TX8
zU1}rQ*)8*sS-;|)y=_n}6ibxZ1yPkKDQiufgOFU#L2c}KxTS1EKf}>WBQYBdgOiP{
z3M+(0<<mNLA~YW*O>7I78;!&S?X5w$SAwD~S;O=yKvY0RM4~)vqYj@S&vgwHj-9B=
zkhcuULaDUL`JG<Tt;T|eFd>k-3y;H-SzNL5%3+1HZqquej<7Lb7iQ$s4G1MG)+>Du
z7cENJT@SY$jfbuBT;Jfmvkl&eP@<99s2r?|q=^azQy%>08!UdMbR>TY4?du-b6{DN
z%tk<rh;z<rICUJMBEg`It90h{^dv$FJRe)j7jH0x>+;A#n(0WoW`L!H@Z5YI7Xw1M
z8}T@WQXbf##R<<-pMn5Nc>$k%4+Sz4@A7?5XJmKz??Wh8RHQ9(x2wjoAN5?p{yFt^
zT%mn7>Q<qv-cE=XjD2Etva3<|n<1t*y9pRXV3R(<UMI4dT}^+*7Nk>3u9o9yvO?Kq
z9<6J@?2@nWSUp5}xonj>w9&O-zYhUc`^=U)P&L3OS!l*m5ZMoASNmpg!>sTqgZxIf
zkn;%~+K3^)(d#AsJtPPoTeGg-OG_xD*_FwBxpW)9Yd|MtnA9p{Vha#ab`&l?8ZoFX
z982+5F>Ezbu4+_Fso6EE0lr>e<+#ysXVLhO`j%BWX@{7YiAnL)IHVE;n<mAEcNXxZ
z(Bg8H-aUykvdAUP3xN?rq!{v2@nKXsNcoW${Ro%z@%}&;p~My%7>qzD$hJ&euZqs#
z%}s1UT6+sNPLU#StPv{|WGZS)U$|GOTez~-8a`W&y8_iN(oSz!9+kQPTQVdLK>j}D
zDo=E0@VqaI87IbPGT=;7BF8kf9~}O==zNKx2Y%^kMkSG`_yfgt&;4(Xw@7F6l-T<k
z<XhNcS&W4tUdDb=N-$T|!pkcj@O@TTg$lC&24+ZDAWG<AdHCgP^jd3396dkO>u3P0
zKy~<Js39~qzC{#|g|41hcw>{-_vWFK32|D;m0(>D+=(;$B5Sj_%q)qsH=hk;d_wo#
zi3@rmWwyr0J`_**3y%wBnUEvM-;(zNcxknpyg$oo9MWf0LJFi)ewn)dSQ6LxFC?F%
z0GW)%xnBCP&z8i^gZ>|Y(zd6&2&{;=zvJ}4*1D$LiMy-bQ*|OVM;)X)GVI*|FBj!z
zz`q_h11$^E&!tpxKsb$uI_@K3`h%SC059^6J^JZ-zIHSRPcX|T+QVl+T!r#4-yVeY
zsQ#Xe=eM8WIU-Vw7e2i<fOTDU8xCrVCj7jOS8P`j#ZO{u<=S%Cb8sdTYBbz3!`iQ_
z^X_8>wxrGx%1V#EhrwCPFBIAdO+1S#valuuL2x8_%`Jno36zuC2nJY6s<f5)%!}|Q
zcT&~2MTdI?Ux8<^C8=f|3V&eplN7Q!frn04<u$0gBHVS)JtK>TJp@3;8cxmO9aGs+
zhn&;|8CyLcz^jc4Q&Iw`AE0DmkB$C#CNQ{wqzIp2Ns2k9WZ6=gc@38L74QykiR~}I
z_E?e<%eH#p8jukXl^;?D+-WOL3a=x*4vpCiqAMxm<59TCiAW)HQpX24@xr@Dq*{`?
z<|yv$>SUp~JE`ZrBZAuCq|BYuglXn24|q)hWC=wrNrRThbkz0HoiwZx9IUnFjly!$
z$isM-7n3sq%JfGWhY1Sxxs%?kTOCE!p@b+Ir!G-oFzQG${a@@W%?KP)!vnTrjPKbL
zaHYx!nrU7EYExaA8B^Z9=@Ft7f+pt|7D3EKu7ZYZNKzYCvao|6kt#+jT3y^s{Cdz#
zYaMHR#C2)hutmw@CG^X<<*Je*L6w9$fVW87GZ4!JD})mv2%s^#ap$*tM(bKJ?pfkb
z;A&`D+CLJOF%-}?YvXs-sq$r9KU9G`mIkn4UvX@7X$#$$7*DP%<ajT2QGm~Krk?~b
zr3NBmm7R}5juKMY<yRj^vdYw1Wn9;8!$2-}Oup4*rLgE3&)qL^Ef9H(4}A)_npI&0
z;4(gSD&eHnZZX-idYKTHN$UiYRcocer`T>Fst}8{+N(JPPz6r2wdSGgzFzRfN7LGQ
z&0>8e%r;CM65dW&n)tE2o$#gMjdgq$YvVO%^{7E0mc}orN)Su&)@GZqV{ox!cZ@;(
zy%EsMVr}{GERWXA2M|&KPcD`b$zp9C?WfmM7Hj-F6}B>$)mFVd-pf!(`yv3AUdp-!
zZFLP)@-M1W#Xqtwj4A|JWU+Q?5n<DPq-^avp8=4BCXfl~V?Zr65_4$9OH7{!2n;L&
zm1JxGZ${Vh@S#<=bzsqK;pKqCRB#?0Dznr|q>Yh&urdx(*D9Zbu@Cq0z;&t_3vv=W
zao-(;4k_^?fFt9SyaT<(4*{qA&PSVY6jAY^pcvk(k29j~+&FKk668$fWA0)IZlAYB
z(M_U==ATePud5=;8YwvZ70xz-R+E=sgkQC$CfK<U&XcQ3rm94ChRDXUSYMTz7D4mv
z)&WN~%chTisc?jlKK&7H4cQ|6vUG_8vJ<qA^u-y(7e!5)qLBB#3AB#bLFvE-WGxYS
zf)CdZ@kYQ1Af*(sVjuQn;T$?r(urd?t3+kDQ}L-_l75}hIfPUt{T>dBoLISZVJj}D
zgmU>JVvUFt<F#C615zWTpl;*M^Aw)L+Pj;G>oF<$aCTIzZsLvq4v6G9Pj#LuV~yFo
zoIF%IZU)-YL0Y67C98(O38d292||PuUbseICB=w3)F7H|L2GeI#ElgF(W*4tLL<jF
z5YPHxMPj50swX)+8w_UsY2>A(*5m@lkV=Vz7ghsO39&WU_Xs_bZBa;0Pe3}rDNRKn
zG(TiYQbmt<DfSt?Xn-i&<gLh8jyAPU$~Nn8xCn?Om(3xc#=TLaF^qX>WuTOb5jjkw
z@<!T?#pzKv(DOz*JrvU-aZ-2q2a}>eDg6%jKe0C1)~^b*5+w~7d$s}jFyuojJcMqj
zxHeSpwhe25h%DMsgxxA|cO1DICJm9#VjFv7tDB8zuE*6|nm8Nj0kom30%@Bvwlqm6
zM~3P907ns?h#4Fa$K7|G%5gyz26kEmqGs-?i`0rO=e2>~pr#4Xij<EC&z_`6!9(y8
z24z@qcR^KlI#5L+Fi{DJuxFmJ@MZD4qByWhRt|@Q+7Mxl8`e!jsvIQN7KzfP58(78
zQew8&{^)lvW)Kspa_MgLp7e6pFTH6JBhyzVdb5`H*T;cGtj2Wk3tEfm$bYHxo#9wK
zKTVUSP6gqCPpn5O`!7xlgmSJk9xFwP@qdRDn16sUrGKUzuSd8HH<5#o-Esu2X1JS=
z`0%u&#)knMU8sQ?SwI$~*L=Ez=ItmC@b@z3ev_yn8q|zQda_@=lA!VgNYF2w<i7(M
zr_pK8qD!ukn1QTQoCGbPg~AHWk2YfVEBP^SBNTx;`!M;`hWmkbY*cHmcRV*xL=DTy
zjiPaS87j18PL7nS%Iv8~q*{`jR#sq;>ZXRC0`&72ma}kY2hpBv-mnvZR#?@w3RrM6
zpmmbtvvfclIoVbpIk+`Ol(!_?KM!;<xm9nYAOigpL+=jm<aV`cP(^|yN%wpAVkL#6
zizT^R<1mI?*R&${7KIy2ulN1xM-A0*VZ7;nt<UnbH0tu?!~t^-=@HPD<m?7Y8Us<+
zCJ$S9pib1#?kbHfZmjuH^`bkl4v<R6{hP2*>=jy)lPCQO^QJZ!Sg)q3-6@1bn$Zra
z>cOII($X9^-n$fvCK`yKWLWSA+(MNQh<qd&#yt@j_e+C-ai^gX(UM`wR7gCgQr#1n
zwpfN3W(18Rt@sG*Nd*4{u1@aer#mF9KRiWOti<neHB!vD?V@rMR^i&LxgEJ3JTY|{
z;mdPa8)7!3I(w0>Tx?!C&=m?zq!<sI7xQ3?s`#*qetaES0L6+-KmRQF0WgP9gmXN-
z1c`cv2}@o&YesNLv7B`Ak7q_gF<u?1<f|3VHlf$MlPfyw!rvwSs7kE--T;6CN!K5J
zs@!8#`9(STS+}3gdg8CMSVgD2<rME%5swmOvFx=;XW_A%9<Ral0Z(Uu2@k`B8>{;i
z@DKv3STa#dsWlK$??s>rG9@)bI6sXP==#aa2RQ`lHo8`ssEm|`LHH7lk1dfD!^*AP
zP^6AIi1rjyz$fdyys_d%UOA=tp}>ZoG(Ws}Ov5XDn^nJ?_b_fDB8bzXiDRHuC@FPI
zmRUz~z7Ln+;p#}EE_X`C*$=7npe3c_UL}Z&I&GY<>(DV&o5?A?8icnb4Y*S>V`fn<
zcS_bjt>`@p$&sEgM2~vt=ASe)6R&$>|IH~QL-6*2knNN@wxe>fP!}V+SRexSgezil
zDJE5KeTG8;%0eAzasbGJG`)Wadx)&8B*{Q1gT$O6_3SCLemVdDEq>$N;o&@{iYg*Z
z@bV&#()Twhe^^OFl7Prq&^+f=QQ@+3g$GwtTa965GHg!%G&z#IHV2rBs;VMmM=&IV
z+_2eiD63E1WKf@BOB;YN>2<=e-HW4iwc?C#XMdg=Sfok2cNgfAJMFVWH;E7&>A(^w
zT`jE=b8LW1+2J1}1*d%lg&F+Qr_qRNqBX!wPS|KqBCHyz(Rez)h>wa8GhIHLF^V38
z<cnX{qK66T%0G6`?u<_gy#8alpU#i!c3mB)NWM3AkUEeMfzS~{>X}m>Jw$3Y#ebM9
zSR4&ZiNKdg&o_36(47igsXkU~p_eE94vhZT{w=9huJPSew3f)J0daU{7Lh7Ql{6ut
ze$)uJu)Voc>v(O#rXU<EkSu8~LJf)~&8ZPhF^$3vAB)728u_IXiAz|RNSBl!wNBhF
z+2a6i+AXdtcPmwH*(ytIJsG=(*pQqW|DwzjwVyND>K%6wrifJgyX}38NmvDQstW;l
zbUk#Zw#z$3*MEF!r)!iVr*_*01xxcI_5SLbXMf|p=vRUe?zF3~cS3+kT5j+=adCvp
zojM}orB0!xjybEu{@^)LG-bdxg?1r{+MKhnCW!#U*i$FZ-ws`%WK~ti4?-tR%eOZp
z7#4Zv=XddSsxD${ZH_n27G=65Nblc<Xo@%+Y0;)xjkUc4<>Ze~zYtado5T`7sjw45
zev9RdE304Z%4S=&-7qIM#Drh_B`jk?H>8b+;dHJg9bye^tvpfK*I8FfKS4AZ!440a
z^o4zT8?j%~*9~)>q$25?IsP)~l=OW~I1h{6lz-U%mu__)?;hCP!=vC#q*LSJup;(S
zIx`uD4zVifd@CIe%Xp<`_!Kq<LJBA8`U{-CNVz*rLV}eq(Po@Qvbo<&vA^>T6^ox8
z{A%B)#{f1EFT#cN7EB`TK7U>eA_y3}y~-EA;pzutg$RrRbf^trb{dJrH6QIG*@Jk1
zeC0w?e(SJ@w#H7baiSTsJv<fxPyy@}sggb7ILn<zj_-EkANED!%13d@-s~DrrlE>0
z?|Dp>eKFdkf?~19Z92{qB?_7eiIQ;YA~})V_LN`NP>c^SMBDvpij~FNGaPimx$PbD
z4%0h{Z10k&i*9P~@vkoTk!<hN9{!W!hs*Y?a3q)zNpAa~hd&C&LH>oqUjdRq<U)F+
zS=f?C@w1L504z(IecaF3bBlRUTrF8bxoH4<)|*EjM`|iTou;?f<8(r@63xuMX(h0h
znAzvDai#-`n1Eg8pUo98LM#Xz7T&^2xGvKxw7mF-zQRsk9=&ww!Bd`a&`c^<bfEFX
z4Xf^ru!zrrZ0CjTqc}M*h<14M4=`7WpJ3WvRXCS1eX#Qjq`nZ85Tot+0ucr1W^CM_
z7BZR1onR-B4-QDxg=;?YPC^tJ3)8XQ*w92Jb*c&OEM&OKuD~aWP|p1)Af8e#ttvEW
z0?6VC!13@8?;?v98#<^DFb$Z>zY?HJl*%*-VA)dsb`A_+Q>=zamlDU6)iT@v`3Ml_
z(Qq{JT!`7>5~KO3x$gG$Z)r($f-RCAUZL=L)37w`xfO9t9DY53Ue%}&RlCD~buPC7
zXrI6qq@#v~r)eXxm>fY@BWxszk=qfPaT6=c-ppeFafC<B3K1)l9gV&B7)YzK!`K}H
zA$A1dqL$%STCP=9_}Pj~z!v3HgP;nh6^kPwYRGst{c0d1^xy2T-GwWK-Iv5qwKyEz
zG6ykMQO!8q>9{#+tuQ}|0AFMK_NSIt;OtWGcs&m%Tj-7+|3>sAB)6l_+8+eD;=Re*
z1xbcdQiY8Zv;PDX1R_tbhS^XFj^USVeBSxN3QtI5vr>iJNn^e0i9!*WZuWu&Qku{J
zuna9h5%1mP4VZ2KTa?*h3-;~9NE#@@c%+$z!g|`UgC%Bmi^14L5IbF~i!HqQI{{UL
zE2Bu17RDU+1dM0ZFX_85Qmo9h49>~gXETl!(;^HahrGJspLA<BtUrjeCT3Y3Efh1A
zL<)+4Wo~i$N!v~yH_>m|v2<7Cu(7KBm^HWitt<*#lJ-|$NMe3V-_^z%Cqr_?jccj+
zp~j!)KPzS8!1I?t3$rerd>uz|%|fWe)09r%x!Bz6Uz;XjtPf{9+GN_mrO!(eltCbh
z;Eze8Yq6PC&jNyt@J77?`~NfPF}FXsf%F-ZJR#{=gz5xu>HaI><UA)m&hc+but<jI
zVem6A_N|K)KZ=R!|Ju6tpeU;-z5yyF+A0igX0j}>OX@JdxE~@?@I5viObxNfXi}rX
ze4#1rkdBy8z>t%VMlpsc-;YF5lgVww8BJ3sm=PNtwRCXI2UF%FACuPaeBXZeyLa<H
z=5Sx%-gD1A=iGD7k61<yYjPB@{n05s@5ICji8da&cci7G!wf@Yl_c9g=FnL5jxpD#
zB=JM}<bnO-IsHy=6z2nwAWP#RJrnO}371!gDCu%?+=wE6Fi9TP*kCaq#`4N(Rl57H
zM-*2#UG`oAx;C2t?b79u)rd$FOQd<_oCpK?gZFI6YBfN=_|8sw%tIMZn2b5~j~Ew^
zL~Op9B<F9d5S%gT@~e+v9gD)tC%>_fpr~|CXRJVmz>YlywB4pj$Z<lk)|&DdPH;~@
z%i$;5Rb3{e&MEhTJy89Cp&se$o!_4W3LuktbGXO9+muBHf4dj?;p|}jsG=<*XqVhn
zhq7%T=B}O<2$lyox=EiU4i{Ak_wuYJOGBeRUo3|Ni<XQFFF4!U*tTpTO(&_bc0y?N
z*y#0}Z72XPEMSYhGR0aZ4gc*=a9gp36J__{3l<I@5%z6Z|0X|*YyaP<d&X&T)Tr$`
zkRJK8B=?WUx>H2T@$soqBBfpX{3#2@ipDv4{9c~WMmjxjtLdF!yH1+G`TPqJw6~AZ
z120}|&EmJ62L3&TGlGfGZ9kO8e^%;^#x5v<3oUpHw32RL4K4X}zbPbK+x=)?vL(nV
z$V|^b2_JI1n2k?16Rw?JRilG;4R(^aOX>aP&S8!PrdRKYPw=ybNs7J4iOCK?F)>Xc
zU5TlO1QN?5A`|IfJ(^QEV9IklZPq1)NpcidW8GO>7-tLw-9aALK#q^~^$cCv;Spw*
zl+>YcPx6cLDZ{&{IJ$XPqN7jAly8b-WhmL(Oq>(*Yi0OpgsdY;d1)4u0zMJRtK?lx
zuEzyppdp%FC%Ew3$x@Nx%W@G#fQXAp%@KWRt92~}UH~bxOvVpAc~9veo&&JNT;;8T
zY&=gRs;A7n_4H3J4jVMd%8vobtCYN4IG3(4UcM<aj~o?5G!l~fMTiMWK4n2eH@48+
zPvW!kt`XviUOcxh+nSG}G_mDNuh()W1aV$X0BLs2D@P+OTM?x)jv~UU>cl6lJRYLd
zFYUA-6F~4Z4lpss4B3(N%_;+*T!$SsXr4_K<_R+h()M#l#fRGgErk{{(?s9>3?N26
z9Z3pIKPi5J`(T#S!tS9?hXW@>D5zu4w#~JE3To26KWavBTz1;?q2?)_6C+XJoA%UD
z{e@S-(;MpqkX($EdVW{Ji?%S+hiH75`{MUSX;wZEO?WxpW?3X4NY_>eLL9w+z71zK
z$}Au&hP_X@ZWkeN#@wLrK&>Ye|Ca7YAoZPj$1$Ai;Q`!a+$z9d>1y~my{e;dg4AA@
z4u%{mHL4S(SQs}Ua0bB@$V3Vp5;K^PiFBhafw2Y^aYT6YporFWbc{|1@stdAuiF`0
zlFORX0Z@}7>?1<5fQIzAXMz6&WAIZd5rfZ=ozT;#rgzSU%F4-s3^k)2{LE1#byQ5E
zwKjdioN2{T!blma+7jAr%-F|5Bwtl^sc*gjaF_kWX+|14?><or$Euq6wMDNXPZQZL
zOt$8zQ(FFj<cE~=n;}p7GT#|nDhVwmb$V;HrIG86W<MP%La(Xws_;AU6G-ZZ<F9Ze
zu!a4jwEy|QEBeF;caOWWIV5?=Rg-6=5)0`&%f7<)`OOy@;^~zINcZN^j$CUJ;R*nE
z@q(%0)D@?Y2qb-7x;MlE*_iuJlF%l0>#(&X8P8d92A<|-QCPV5&caigpPS3I--%No
zwvrB<YUhj@at2iNbRTx2QkAiEcK+$MKUTj+xBGP~4|3kx_tcK$D(G$7b+$0~o(^*7
zFVQ$W<|RtM%bD|~3S$O34uG`$bzygml@>%USp=?h&EFFu%dRB*MP07DWM*I6u51IR
zFDN$u@+5|IyCZWKK9-R5AacGQy<*-hw5&&G#Csi>Np*0E@d-ha7I|cJoIvtweVRrs
zrvu($#cxSk|Go}Um)2sZEKn(3nT^*kAEgcuxS$OT06&b8!Opo_-0Pi)Q5Ovgua?+!
z=~LQu?jbZod;T2C446MJodqqWya_;4+|fdUQke)>@6)7fAps8Q+Nj=mju5qd04P0x
z7u*<(aRRh`XVwqc?HD}>#L)OB)I?{_&`24`OLatt-1<mRx|JxDlt+Hjdr=vT4fKT<
zZsP0#P<&d^UA{KA-e~GXu5!6fc{gSAE8;-!Z&3$}lsO3<!yRypGjZe7J}6rZVJDFM
z0lb<Cr*qLrpce88KCUGz;8j4XB2RQzov~Yho5c0C&$OCGQt-}OroqE6bXqyYVW9$2
zwF%T7SbYQu(?Y8TPf4HTa=sp@yXm*&7ue?!>u$JJV97%wY>h?<4EDL8cy>(X;>Bo%
fE$fOz+%RchFW6I1b#~$py*hTe%~rYS?&bdgsNCZ*

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1 b/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
new file mode 100644
index 0000000..94824cf
--- /dev/null
+++ b/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
@@ -0,0 +1 @@
+2833048369
\ No newline at end of file
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Filter.db b/tests/sstables/large_partition/try1-data-ka-3-Filter.db
new file mode 100644
index 0000000000000000000000000000000000000000..208dd70cff3590bad33428f74e4e480d3c5117d8
GIT binary patch
literal 176
hcmZQzU|?lnU=Rgj@&FT2+K5wy-KYiz29S1$5dazf0HXi^

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-Index.db b/tests/sstables/large_partition/try1-data-ka-3-Index.db
new file mode 100644
index 0000000000000000000000000000000000000000..9e915de05b67d53e3886cb62bb29f5291667cd9f
GIT binary patch
literal 484
zcmY+AI|{-;5QhJa??)lx2|PiJAta@b#z*4=6$>Ga7K)%q5F4$;16X<h59B$#LYz$2
zWi!?MnQy<%4ve4yRpN6E!|<juN+=*@`YrxaM!I1JBfvN{|44-!fhvkT9V^m0^fXeS
zF3B2`)}gORdq;ldG~gsid)HQ^vz};V3b8{Vb~@{+B3*x=k!h?FPS+nQ(hE8onZYqZ
zdO?>nt-(5yQdSms?gR|lQ9R-oP_XxNO_;+&lI3WZ_I|;UT4x*oew6cgN-7`uc=Y$V
co0;Y-;3Y}+xf{BSiVk^~rN$NU<^jIv9}QwFdjJ3c

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-Statistics.db b/tests/sstables/large_partition/try1-data-ka-3-Statistics.db
new file mode 100644
index 0000000000000000000000000000000000000000..53c7af52832a98d83d6be4e2a08ca2c237e786a6
GIT binary patch
literal 4452
zcmeI$`%6<%902h9noe`8O|7()vdprWqL~Tl)MjcFndYMxd2^B)YHX{_3dIaU!mKnC
zeDnYbm87SSqJF5fhowoRMTNn#Flre+)&tkQxZ(GE`U|2RxZLyE_uT6}_k7RxMT(+W
zYP`)9PPA~W6%Ix?a;b&+x@{_c2cMCZsmkE>dOlC9<5k)$gKG6oUG7d@a00J0WE-;c
z^D=en(!$rV=iT;NFBWek-o(XXv5d()X!=m)afRS&;Sie`hmEv&Eo`=jw0*|eI@Ys<
zumfR7!cxM{gk1>B35#=q%?(26Pbcg}cn)EI!a;<W5so9ALU<eDeT1tBUm`q!O%v-u
zFCpRv!Z)y)X@pC#S>pa|Esk@^*pgsuhj461V!qN}IPTny?P9{7d=OiC3VZ4XY|nn|
zSpnGd8n9Jq*r9dU(busP+_BR=u=V1m1+9z+5W0;-{&s6{+~kc+dyitLt;4Rv`AM6e
zqBxU;_cL=Jn@xL!#&aCbf9`P)ic9X6BRhO*LY5|3ke$Xdtseiolg3<8T&~6WsL;Ga
zakq}C$kShWB6|%aBG2i?>+NsG>m6Ki6O9iadV{<&3P0a^Pa}%wd{816uW3cD`LPta
z{Wg9-FWb@kq@AaHh2v>;>|x|0pL56$ZUsU!er@Rcl{q1Q0^_V_0m=`yW3v;Ca|KQj
z(2`99Xub~l*#$7}*lzp=?WBqM0zJvQ6YVEinz9eZr?Bx|(5|7rD4(avf1HHz8O=vW
zpl2_Ry9n(!n7Rx)pfBq@bXfZSdT7n_z*OkOhTIV74BxAf(7S%hhM~*vG{r(UC)M~s
zKddf20{!hue+)1^U$(UaI%D~Axc}*<gf_VUX-lOX?tdoJ`05(Co*8P1C<JB=wDA})
zH@8<A4{bK@gX<&tUQq>qKO7gh4o89U(&`I^mw}zvobJ*AyKE`{2<I<<rWk?qS3Hip
zqy*#L`LZ4G_rT+vx>E(>-uH%;aJ}Y!j*Tw^@kPldUsw->1i$Z+gSdL&ZRc*_Rkf`x
z@Od_x!a`s^=Ot<yE5P{Dt?k`I!1XU)UT*}xapr6*d|u-%|NhX4IITR;^E(<iKIiMN
zk_l6KYaf3H|6PMI;2N=OuetCGvDaMaef+mImvtZ6Yc7-y6E)ZP$M%}bUUPv2`L}8=
zI=MDzdp$Kj@-`(|k`uOqJ1d@J+M-8`gnwwL2Nio#%<jd)^t51#wk}PvfxKAI2%WIP
G4b&g}U`qV}

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-Summary.db b/tests/sstables/large_partition/try1-data-ka-3-Summary.db
new file mode 100644
index 0000000000000000000000000000000000000000..56c5b4b1152b0c5c585a9c8e0309591b99a70e72
GIT binary patch
literal 74
wcmZQzU}#`qU|<Ad5a0vi1|Vi+0TN|~KmrDsz&sGilAD`Y02GGlVStDL0IpsJZ2$lO

literal 0
HcmV?d00001

diff --git a/tests/sstables/large_partition/try1-data-ka-3-TOC.txt b/tests/sstables/large_partition/try1-data-ka-3-TOC.txt
new file mode 100644
index 0000000..4d01074
--- /dev/null
+++ b/tests/sstables/large_partition/try1-data-ka-3-TOC.txt
@@ -0,0 +1,8 @@
+Data.db
+CompressionInfo.db
+Index.db
+Summary.db
+Statistics.db
+Digest.sha1
+TOC.txt
+Filter.db

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:29 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
Our sstable reading code is currently hard-coded to read entire partitions,
even if we know that only a subset of the columns are requested.
This patch introduces find_disk_ranges(), a function to find the ranges of
bytes we need to read from the sstable data file to guarantee that the
desired columns from the desired partition are read.

The returned range may be the entire byte range of the given partition -
as found using the summary and index files - but if the index contains a
"promoted index" (basically a sample of column positions for each key)
we may return a smaller range. The "disk_read_range" type introduced in
the previous patch is extended here to support reading a partial partition -
by including additional information which would be missed when reading only
part of a partition (viz., the partition key and the partition's tombstone).

This function isn't used in this patch - we will wire its use in the next
patch, which will complete the read-side support for the promoted index.


Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/partition.cc | 162 ++++++++++++++++++++++++++++++++++++++++
sstables/sstables.hh | 38 +++++++++
2 files changed, 200 insertions(+)

--- .before/sstables/sstables.hh 2016-08-07 14:46:39.189291526 +0300
+++ .after/sstables/sstables.hh 2016-08-07 14:46:39.190291534 +0300
@@ -155,15 +155,40 @@ public:
// object lives until then (e.g., using the do_with() idiom).
future<> data_consume_rows_at_once(row_consumer& consumer, uint64_t pos, uint64_t end);

+ // disk_read_range describes a byte ranges covering part of an sstable
+ // row that we need to read from disk. Usually this is the whole byte
+ // range covering a single sstable row, but in very large rows we might
+ // want to only read a subset of the atoms which we know contains the
+ // columns we are looking for. When the range to be read does NOT include
+ // the entire row, the caller needs to supply the optional "row_info"
+ // containing information about the entire row (key and deletion time)
+ // which is normally read from the beginning of the row.
struct disk_read_range {
+ // TODO: this should become a vector of ranges
uint64_t start;
uint64_t end;
+ // When the range above does not cover the beginning of the sstable
+ // row, we need to supply information which is only available at the
+ // beginning of the row - the row's key and its tombstone if any.
+ struct row_info {
+ key k;
+ deletion_time deltime;
+ };
+ std::experimental::optional<row_info> ri;
disk_read_range() : start(0), end(0) {}
disk_read_range(uint64_t start, uint64_t end) :
start(start), end(end) { }
+ disk_read_range(uint64_t start, uint64_t end, const key& key, const deletion_time& deltime) :
+ start(start), end(end), ri(row_info{key, deltime}) { }
explicit operator bool() const {
return start != end;
}
+ // found_row() is true if the row was found. This is not the same as
+ // operator bool(): It is possible that found_row() but the promoted
+ // index ruled out anything to read (in this case "ri" was set).
+ bool found_row() const {
+ return start != end || ri;
+ }
};

// data_consume_rows() iterates over rows in the data file from
@@ -481,6 +506,19 @@ private:
// The ring_position doesn't have to survive deferring.
future<uint64_t> upper_bound(schema_ptr, const dht::ring_position&, const io_priority_class& pc);

+ // find_disk_ranges finds the ranges of bytes we need to read from the
+ // sstable to read the desired columns out of the given key. This range
+ // may be the entire byte range of the given partition - as found using
+ // the summary and index files - but if the index contains a "promoted
+ // index" (a sample of column positions for each key) it may be a smaller
+ // range. The returned range may contain columns beyond those requested
+ // in ck_filtering, so it is the reader's duty to use ck_filtering again
+ // when parsing the data read from the returned range.
+ future<disk_read_range> find_disk_ranges(schema_ptr schema,
+ const sstables::key& key,
+ query::clustering_key_filtering_context ck_filtering,
+ const io_priority_class& pc);
+
future<summary_entry&> read_summary_entry(size_t i);

// FIXME: pending on Bloom filter implementation
--- .before/sstables/partition.cc 2016-08-07 14:46:39.196291584 +0300
+++ .after/sstables/partition.cc 2016-08-07 14:46:39.197291593 +0300
@@ -28,6 +28,7 @@
#include "unimplemented.hh"
#include "utils/move.hh"
#include "dht/i_partitioner.hh"
+#include <seastar/core/byteorder.hh>

namespace sstables {

@@ -771,6 +772,167 @@ sstables::sstable::read_row(schema_ptr s
});
});
}
+
+template <typename T>
+static inline T read_be(const signed char* p) {
+ return ::read_be<T>(reinterpret_cast<const char*>(p));
+}
+
+template<typename T>
+static inline T consume_be(bytes_view& p) {
+ T i = read_be<T>(p.data());
+ p.remove_prefix(sizeof(T));
+ return i;
+}
+
+static inline bytes_view consume_bytes(bytes_view& p, size_t len) {
+ auto ret = bytes_view(p.data(), len);
+ p.remove_prefix(len);
+ return ret;
+}
+
+static inline clustering_key_prefix get_clustering_key(
+ const schema& schema, bytes_view col_name) {
+ mp_row_consumer::column col(schema, std::move(col_name), api::max_timestamp);
+ return std::move(col.clustering);
+}
+
+future<sstable::disk_read_range>
+sstables::sstable::find_disk_ranges(
+ schema_ptr schema, const sstables::key& key,
+ query::clustering_key_filtering_context ck_filtering,
+ const io_priority_class& pc) {
+ auto& partitioner = dht::global_partitioner();
+ auto token = partitioner.get_token(key_view(key));
+
+ if (token < partitioner.get_token(key_view(_summary.first_key.value))
+ || token > partitioner.get_token(key_view(_summary.last_key.value))) {
+ return make_ready_future<disk_read_range>();
+ }
+ auto summary_idx = adjust_binary_search_index(binary_search(_summary.entries, key, token));
+ if (summary_idx < 0) {
+ return make_ready_future<disk_read_range>();
+ }
+
+ return read_indexes(summary_idx, pc).then([this, schema, ck_filtering, &key, token, summary_idx, &pc] (auto index_list) {
+ auto index_idx = this->binary_search(index_list, key, token);
+ if (index_idx < 0) {
+ return make_ready_future<disk_read_range>();
+ }
+ index_entry& ie = index_list[index_idx];
+ if (ie.get_promoted_index_bytes().size() >= 16) {
+ auto& ck_ranges = ck_filtering.get_ranges(
+ partition_key::from_exploded(*schema, key.explode(*schema)));
+ if (ck_ranges.size() == 1 && ck_ranges[0].is_full()) {
+ // When no clustering filter is given to sstable::read_row(),
+ // we get here one range unbounded on both sides. This is fine
+ // (the code below will work with an unbounded range), but
+ // let's drop this range to revert to the classic behavior of
+ // reading entire sstable row without using the promoted index
+ } else if (ck_ranges.size() == 1) {
+ auto data = ie.get_promoted_index_bytes();
+ // note we already verified above that data.size >= 16
+ sstables::deletion_time deltime;
+ deltime.local_deletion_time = consume_be<uint32_t>(data);
+ deltime.marked_for_delete_at = consume_be<uint64_t>(data);
+ uint32_t num_blocks = consume_be<uint32_t>(data);
+ // We do a linear search on the promoted index. If we were to
+ // look in the same promoted index several times it might have
+ // made sense to build an array of key starts so we can do a
+ // binary search. We could do this once we have a key cache.
+ bool has_range_start = bool(ck_ranges[0].start());
+ auto range_start = ck_ranges[0].start()->value();
+ bool found_range_start = false;
+ uint64_t range_start_pos;
+ bool has_range_end = bool(ck_ranges[0].end());
+ auto range_end = ck_ranges[0].end()->value();
+
+ auto cmp = clustering_key_prefix::tri_compare(*schema);
+ while (num_blocks--) {
+ if (data.size() < 2) {
+ // When we break out of this loop, we give up on
+ // using the promoted index, and fall back to
+ // reading the entire partition.
+ // FIXME: this and all other "break" cases below,
+ // are errors. Log them (with rate limit) and count.
+ break;
+ }
+ uint16_t len = consume_be<uint16_t>(data);
+ if (data.size() < len) {
+ break;
+ }
+ // The promoted index contains ranges of full column
+ // names, which may include a clustering key and column.
+ // But we only need to match the clustering key, because
+ // we got a clustering key range to search for.
+ auto start_ck = get_clustering_key(*schema,
+ consume_bytes(data, len));
+ if (data.size() < 2) {
+ break;
+ }
+ len = consume_be<uint16_t>(data);
+ if (data.size() < len) {
+ break;
+ }
+ auto end_ck = get_clustering_key(*schema,
+ consume_bytes(data, len));
+ if (data.size() < 16) {
+ break;
+ }
+ uint64_t offset = consume_be<uint64_t>(data);
+ uint64_t width = consume_be<uint64_t>(data);
+ if (!found_range_start) {
+ if (!has_range_start || cmp(range_start, end_ck) <= 0) {
+ range_start_pos = ie.position() + offset;
+ found_range_start = true;
+ }
+ }
+ bool found_range_end = false;
+ uint64_t range_end_pos;
+ if (has_range_end) {
+ if (cmp(range_end, start_ck) < 0) {
+ // this block is already past the range_end
+ found_range_end = true;
+ range_end_pos = ie.position() + offset;
+ } else if (cmp(range_end, end_ck) < 0 || num_blocks == 0) {
+ // range_end is in the middle of this block.
+ // Note the strict inequality above is important:
+ // if range_end==end_ck the next block may contain
+ // still more items matching range_end.
+ found_range_end = true;
+ range_end_pos = ie.position() + offset + width;
+ }
+ } else if (num_blocks == 0) {
+ // When !has_range_end, read until the last block.
+ // In this case we could have also found the end of
+ // the partition using the index.
+ found_range_end = true;
+ range_end_pos = ie.position() + offset + width;
+ }
+ if (found_range_end) {
+ if (!found_range_start) {
+ // return empty range
+ range_start_pos = range_end_pos = 0;
+ }
+ return make_ready_future<disk_read_range>(
+ disk_read_range(range_start_pos, range_end_pos,
+ key, deltime));
+ }
+ }
+ }
+ // Else, if more than one clustering-key range needs to be read,
+ // fall back to reading the entire partition.
+ // FIXME: support multiple ranges, and do not fall back to reading
+ // the entire partition.
+ }
+ // If we're still here there is no promoted index, or we had problems
+ // using it, so just just find the entire partition's range.
+ auto start = ie.position();
+ return this->data_end_position(summary_idx, index_idx, index_list, pc).then([start] (uint64_t end) {
+ return disk_read_range(start, end);
+ });
+ });
+}

class mutation_reader::impl {
private:

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:30 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
This patch adds support more efficiently reading small parts of a large
partition, without reading the entire partition as we had to do so far.
This is done using the "promoted index".

The "promoted index" is stored in the sstable index file, and provides
for each large sstable row ("partition" in CQL nomenclature) a sample of
the column names at (for example) 64KB intervals. This means that when we
read a slice of columns (e.g., cql rows), or page through a large partition,
we do not have to read the entire partition from disk.

This patch only implements the read side of promoted index - a later patch
will add the write-side support (i.e., writing the promoted index to the
index file while saving the sstable). Nevertheless this patch can already
be tested by reading existing sstables from Cassandra which include a
promoted index - such as the one included in the test in the previous patch.

The use of the promoted index currently has two limitations:

1. It is only used when reading a single partition with sstable::read_row(),
not when scanning through many partitions with sstable::read_range_rows()
or sstable::read_rows().

2. It is only used when filtering a single clustering-key range, rather
than a list of disjoint ranges. A single range is the common case.

These two issues will be improved later. In the meantime, in those
unsupported cases we simply continue to read entire partitions, so we're not
worse-off than before.

Also note that this patch only helps when sstable::read_row() is used with
a clustering-key prefix (i.e., a slice). Our higher-level request handling
code may decide to read an entire partition into the cache, and not use
a clustering-key prefix at all when reading. We will need to indepdently
improve the high-level code to use read_row()'s slicing capabilities
when paging through large partitions, for example.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/partition.cc | 33 +++++-------------------------
sstables/row.cc | 44 ++++++++++++++++++++++++++++++++++------
2 files changed, 44 insertions(+), 33 deletions(-)

--- .before/sstables/row.cc 2016-08-07 14:46:39.268292187 +0300
+++ .after/sstables/row.cc 2016-08-07 14:46:39.268292187 +0300
@@ -63,6 +63,7 @@ private:
bool _deleted;
uint32_t _ttl, _expiration;

+ bool _read_partial_row = false;

public:
bool non_consuming() const {
@@ -332,12 +333,42 @@ public:
}

data_consume_rows_context(row_consumer& consumer,
- input_stream<char> && input, uint64_t maxlen) :
- continuous_data_consumer(std::move(input), maxlen)
- , _consumer(consumer) {
+ input_stream<char> && input, uint64_t maxlen,
+ std::experimental::optional<sstable::disk_read_range::row_info> ri = {})
+ : continuous_data_consumer(std::move(input), maxlen)
+ , _consumer(consumer) {
+ // If the "ri" option is given, we are reading a partition from the
+ // middle (in the beginning of an atom), as would happen when we use
+ // the "promoted index" to skip closer to where a particular column
+ // starts. When we start in the middle of the partition, we will not
+ // read the key nor the tombstone from the disk, so the caller needs
+ // to provide them (the tombstone is provided in the promoted index
+ // exactly for that reason).
+ if (ri) {
+ _read_partial_row = true;
+ auto ret = _consumer.consume_row_start(ri->k, ri->deltime);
+ if (ret == row_consumer::proceed::yes) {
+ _state = state::ATOM_START;
+ } else {
+ // If we were asked to stop parsing after consuming the row
+ // start, we can't go to ATOM_START, need to use a new state
+ // which stops parsing, and continues at ATOM_START later.
+ _state = state::STOP_THEN_ATOM_START;
+ }
+ }
}

void verify_end_state() {
+ if (_read_partial_row) {
+ // If reading a partial row (i.e., when we have a clustering row
+ // filter and using a promoted index), we may be in ATOM_START
+ // state instead of ROW_START. In that case we did not read the
+ // end-of-row marker and consume_row_end() was never called.
+ if (_state == state::ATOM_START) {
+ _consumer.consume_row_end();
+ return;
+ }
+ }
if (_state != state::ROW_START || _prestate != prestate::NONE) {
throw malformed_sstable_exception("end of input, but not end of row");
}
@@ -354,9 +385,10 @@ private:
shared_sstable _sst;
std::unique_ptr<data_consume_rows_context> _ctx;
public:
- impl(shared_sstable sst, row_consumer& consumer, input_stream<char>&& input, uint64_t maxlen)
+ impl(shared_sstable sst, row_consumer& consumer, input_stream<char>&& input, uint64_t maxlen,
+ std::experimental::optional<sstable::disk_read_range::row_info> ri)
: _sst(std::move(sst))
- , _ctx(new data_consume_rows_context(consumer, std::move(input), maxlen))
+ , _ctx(new data_consume_rows_context(consumer, std::move(input), maxlen, ri))
{ }
~impl() {
if (_ctx) {
@@ -391,7 +423,7 @@ data_consume_context sstable::data_consu
// to maintain its own byte count.
return std::make_unique<data_consume_context::impl>(shared_from_this(),
consumer, data_stream(toread.start, toread.end - toread.start,
- consumer.io_priority()), toread.end - toread.start);
+ consumer.io_priority()), toread.end - toread.start, toread.ri);
}

data_consume_context sstable::data_consume_rows(row_consumer& consumer) {
--- .before/sstables/partition.cc 2016-08-07 14:46:39.269292196 +0300
+++ .after/sstables/partition.cc 2016-08-07 14:46:39.271292213 +0300
@@ -738,37 +738,16 @@ sstables::sstable::read_row(schema_ptr s
if (!filter_has_key(key)) {
return make_ready_future<streamed_mutation_opt>();
}
-
- auto& partitioner = dht::global_partitioner();
- auto token = partitioner.get_token(key_view(key));
-
- auto& summary = _summary;
-
- if (token < partitioner.get_token(key_view(summary.first_key.value))
- || token > partitioner.get_token(key_view(summary.last_key.value))) {
- _filter_tracker.add_false_positive();
- return make_ready_future<streamed_mutation_opt>();
- }
-
- auto summary_idx = adjust_binary_search_index(binary_search(summary.entries, key, token));
- if (summary_idx < 0) {
- _filter_tracker.add_false_positive();
- return make_ready_future<streamed_mutation_opt>();
- }
-
- return read_indexes(summary_idx, pc).then([this, schema, ck_filtering, &key, token, summary_idx, &pc] (auto index_list) {
- auto index_idx = this->binary_search(index_list, key, token);
- if (index_idx < 0) {
+ return find_disk_ranges(schema, key, ck_filtering, pc).then([this, &key, ck_filtering, &pc, schema] (disk_read_range toread) {
+ if (!toread.found_row()) {
_filter_tracker.add_false_positive();
+ }
+ if (!toread) {
return make_ready_future<streamed_mutation_opt>();
}
_filter_tracker.add_true_positive();
-
- auto position = index_list[index_idx].position();
- return this->data_end_position(summary_idx, index_idx, index_list, pc).then([&key, schema, ck_filtering, this, position, &pc] (uint64_t end) {
- return sstable_streamed_mutation::create(schema, this->shared_from_this(), key, ck_filtering, pc, {position, end}).then([] (auto sm) {
- return streamed_mutation_opt(std::move(sm));
- });
+ return sstable_streamed_mutation::create(schema, this->shared_from_this(), key, ck_filtering, pc, std::move(toread)).then([] (auto sm) {
+ return streamed_mutation_opt(std::move(sm));
});
});
}

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:31 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
Add to the range_tombstone_accumulator a range_tombstones_for_row(ck)
method.

Just like the existing tombstone_for_row(ck), this function drops from
the accumulator tombstones that end before ck. But while the existing
function returned just a single tombstone affecting the given row (the
most recent tombstone), the new function range_tombstones_for_row(ck)
returns all the accumulated range tombstones which cover ck.

This function will be useful for the promoted-index writing code later,
which divides a partition into blocks which may be read independently,
so each block needs to start with a repeat of the earlier tombstones
which still cover the first row in the new block.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
range_tombstone.hh | 5 +++++
1 file changed, 5 insertions(+)

--- .before/range_tombstone.hh 2016-08-07 14:46:39.333292732 +0300
+++ .after/range_tombstone.hh 2016-08-07 14:46:39.333292732 +0300
@@ -294,6 +294,11 @@ public:
return _current_tombstone;
}

+ const std::deque<range_tombstone>& range_tombstones_for_row(const clustering_key_prefix& ck) {
+ drop_unneeded_tombstones(ck);
+ return _range_tombstones;
+ }
+
void apply(const range_tombstone& rt);

void clear();

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:33 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
This patch adds writing of promoted index to sstables.

The promoted index is basically a sample of columns and their positions
for large partitions: The promoted index appears in the sstable's index
file for partitions which are larger than 64 KB, and divides the partition
to 64 KB blocks (as in Cassandra, this interval is configurable through
the column_index_size_in_kb config parameter). Beyond modifying the index
file, having a promoted index may also modify the data file: Since each
of blocks may be read independently, we need to add in the beginning of
each block the list of range tombstones that are still open at that
position.

See also https://github.com/scylladb/scylla/wiki/SSTables-Index-File

Fixes #959

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
sstables/sstables.cc | 191 +++++++++++++++++++++++++++++++++++++++--
sstables/sstables.hh | 21 ++++
2 files changed, 207 insertions(+), 5 deletions(-)

--- .before/sstables/sstables.hh 2016-08-07 14:46:39.412293393 +0300
+++ .after/sstables/sstables.hh 2016-08-07 14:46:39.413293402 +0300
@@ -407,6 +407,27 @@ private:
uint64_t _filter_file_size = 0;
uint64_t _bytes_on_disk = 0;

+ // _pi_write is used temporarily for building the promoted
+ // index (column sample) of one partition when writing a new sstable.
+ struct {
+ // Unfortunately we cannot output the promoted index directly to the
+ // index file because it needs to be prepended by its size.
+ bytes_ostream data;
+ uint32_t numblocks;
+ deletion_time deltime;
+ uint64_t block_start_offset;
+ uint64_t block_next_start_offset;
+ bytes block_first_colname;
+ bytes block_last_colname;
+ std::experimental::optional<range_tombstone_accumulator> tombstone_accumulator;
+ const schema* schemap;
+ size_t desired_block_size;
+ } _pi_write;
+
+ void maybe_flush_pi_block(file_writer& out,
+ const composite& clustering_key,
+ const std::vector<bytes_view>& column_names);
+
sstring _ks;
sstring _cf;
sstring _dir;
--- .before/sstables/sstables.cc 2016-08-07 14:46:39.418293444 +0300
+++ .after/sstables/sstables.cc 2016-08-07 14:46:39.421293469 +0300
@@ -31,6 +31,7 @@
#include "core/do_with.hh"
#include "core/thread.hh"
#include <seastar/core/shared_future.hh>
+#include <seastar/core/byteorder.hh>
#include <iterator>

#include "types.hh"
@@ -56,6 +57,7 @@

#include "checked-file-impl.hh"
#include "disk-error-handler.hh"
+#include "service/storage_service.hh"

thread_local disk_error_signal_type sstable_read_error;
thread_local disk_error_signal_type sstable_write_error;
@@ -296,6 +298,12 @@ inline void write(file_writer& out, byte
out.write(reinterpret_cast<const char*>(s.data()), s.size()).get();
}

+inline void write(file_writer& out, bytes_ostream s) {
+ for (bytes_view fragment : s) {
+ write(out, fragment);
+ }
+}
+
// All composite parsers must come after this
template<typename First, typename... Rest>
future<> parse(random_access_reader& in, First& first, Rest&&... rest) {
@@ -1066,6 +1074,108 @@ future<> sstable::load() {
});
}

+static void output_promoted_index_entry(bytes_ostream& promoted_index,
+ const bytes& first_col,
+ const bytes& last_col,
+ uint64_t offset, uint64_t width) {
+ char s[2];
+ write_be(s, uint16_t(first_col.size()));
+ promoted_index.write(s, 2);
+ promoted_index.write(first_col);
+ write_be(s, uint16_t(last_col.size()));
+ promoted_index.write(s, 2);
+ promoted_index.write(last_col);
+ char q[8];
+ write_be(q, uint64_t(offset));
+ promoted_index.write(q, 8);
+ write_be(q, uint64_t(width));
+ promoted_index.write(q, 8);
+}
+
+// FIXME: use this in write_column_name() instead of repeating the code
+static bytes serialize_colname(const composite& clustering_key,
+ const std::vector<bytes_view>& column_names, composite::eoc marker) {
+ auto c = composite::from_exploded(column_names, marker);
+ auto ck_bview = bytes_view(clustering_key);
+ // The marker is not a component, so if the last component is empty (IOW,
+ // only serializes to the marker), then we just replace the key's last byte
+ // with the marker. If the component however it is not empty, then the
+ // marker should be in the end of it, and we just join them together as we
+ // do for any normal component
+ if (c.size() == 1) {
+ ck_bview.remove_suffix(1);
+ }
+ size_t sz = ck_bview.size() + c.size();
+ if (sz > std::numeric_limits<uint16_t>::max()) {
+ throw std::runtime_error(sprint("Column name too large (%d > %d)", sz, std::numeric_limits<uint16_t>::max()));
+ }
+ bytes colname(bytes::initialized_later(), sz);
+ std::copy(ck_bview.begin(), ck_bview.end(), colname.begin());
+ std::copy(c.get_bytes().begin(), c.get_bytes().end(), colname.begin() + ck_bview.size());
+ return colname;
+}
+
+// Call maybe_flush_pi_block() before writing the given sstable atom to the
+// output. This may start a new promoted-index block depending on how much
+// data we've already written since the start of the current block. Starting
+// a new block involves both outputting the range of the old block to the
+// index file, and outputting again the currently-open range tombstones to
+// the data file.
+// TODO: currently, maybe_flush_pi_block serializes the column name on every
+// call, saving it in _pi_write.block_last_colname which we need for closing
+// each block, as well as for closing the last block. We could instead save
+// just the unprocessed arguments, and serialize them only when needed at the
+// end of the block. For this we would need this function to take rvalue
+// references (so data is moved in), and need not to use vector of byte_view
+// (which might be gone later).
+void sstable::maybe_flush_pi_block(file_writer& out,
+ const composite& clustering_key,
+ const std::vector<bytes_view>& column_names) {
+ bytes colname = serialize_colname(clustering_key, column_names, composite::eoc::none);
+ if (_pi_write.block_first_colname.empty()) {
+ // This is the first column in the partition, or first column since we
+ // closed a promoted-index block. Remember its name and position -
+ // we'll need to write it to the promoted index.
+ _pi_write.block_start_offset = out.offset();
+ _pi_write.block_next_start_offset = out.offset() + _pi_write.desired_block_size;
+ _pi_write.block_first_colname = colname;
+ _pi_write.block_last_colname = std::move(colname);
+ } else if (out.offset() >= _pi_write.block_next_start_offset) {
+ // If we wrote enough bytes to the partition since we output a sample
+ // to the promoted index, output one now and start a new one.
+ output_promoted_index_entry(_pi_write.data,
+ _pi_write.block_first_colname,
+ _pi_write.block_last_colname,
+ _pi_write.block_start_offset - _c_stats.start_offset,
+ out.offset() - _pi_write.block_start_offset);
+ _pi_write.numblocks++;
+ _pi_write.block_start_offset = out.offset();
+ // Because the new block can be read without the previous blocks, we
+ // need to repeat the range tombstones which are still open.
+ // Note that block_start_offset is before outputting those (so the new
+ // block includes them), but we set block_next_start_offset after - so
+ // even if we wrote a lot of open tombstones, we still get a full
+ // block size of new data.
+ if (!clustering_key.empty()) {
+ auto& rts = _pi_write.tombstone_accumulator->range_tombstones_for_row(
+ clustering_key_prefix(clustering_key.values()));
+ for (const auto& rt : rts) {
+ auto start = composite::from_clustering_element(*_pi_write.schemap, rt.start);
+ auto end = composite::from_clustering_element(*_pi_write.schemap, rt.end);
+ write_range_tombstone(out,
+ start, rt.start_kind, end, rt.end_kind, {}, rt.tomb);
+ }
+ }
+ _pi_write.block_next_start_offset = out.offset() + _pi_write.desired_block_size;
+ _pi_write.block_first_colname = colname;
+ _pi_write.block_last_colname = std::move(colname);
+ } else {
+ // Keep track of the last column in the partition - we'll need it to close
+ // the last block in the promoted index, unfortunately.
+ _pi_write.block_last_colname = std::move(colname);
+ }
+}
+
// @clustering_key: it's expected that clustering key is already in its composite form.
// NOTE: empty clustering key means that there is no clustering key.
void sstable::write_column_name(file_writer& out, const composite& clustering_key, const std::vector<bytes_view>& column_names, composite::eoc marker) {
@@ -1223,6 +1333,7 @@ void sstable::write_collection(file_writ
const bytes& column_name = cdef.name();
write_range_tombstone(out, clustering_key, clustering_key, { bytes_view(column_name) }, mview.tomb);
for (auto& cp: mview.cells) {
+ maybe_flush_pi_block(out, clustering_key, { column_name, cp.first });
write_column_name(out, clustering_key, { column_name, cp.first });
write_cell(out, cp.second);
}
@@ -1234,11 +1345,22 @@ void sstable::write_clustered_row(file_w
auto clustering_key = composite::from_clustering_element(schema, clustered_row.key());

if (schema.is_compound() && !schema.is_dense()) {
+ maybe_flush_pi_block(out, clustering_key, { bytes_view() });
write_row_marker(out, clustered_row.marker(), clustering_key);
}
// Before writing cells, range tombstone must be written if the row has any (deletable_row::t).
if (clustered_row.tomb()) {
+ maybe_flush_pi_block(out, clustering_key, {});
write_range_tombstone(out, clustering_key, clustering_key, {}, clustered_row.tomb());
+ // Because we currently may break a partition to promoted-index blocks
+ // in the middle of a clustered row, we also need to track the current
+ // row's tombstone - not just range tombstones - which may effect the
+ // beginning of a new block.
+ // TODO: consider starting a new block only between rows, so the
+ // following code can be dropped:
+ _pi_write.tombstone_accumulator->apply(range_tombstone(
+ clustered_row.key(), bound_kind::incl_start,
+ clustered_row.key(), bound_kind::incl_end, clustered_row.tomb()));
}

// Write all cells of a partition's row.
@@ -1256,14 +1378,18 @@ void sstable::write_clustered_row(file_w

if (schema.is_compound()) {
if (schema.is_dense()) {
+ maybe_flush_pi_block(out, composite(), { bytes_view(clustering_key) });
write_column_name(out, bytes_view(clustering_key));
} else {
+ maybe_flush_pi_block(out, clustering_key, { bytes_view(column_name) });
write_column_name(out, clustering_key, { bytes_view(column_name) });
}
} else {
if (schema.is_dense()) {
+ maybe_flush_pi_block(out, composite(), { bytes_view(clustered_row.key().get_component(schema, 0)) });
write_column_name(out, bytes_view(clustered_row.key().get_component(schema, 0)));
} else {
+ maybe_flush_pi_block(out, composite(), { bytes_view(column_name) });
write_column_name(out, bytes_view(column_name));
}
}
@@ -1282,16 +1408,25 @@ void sstable::write_static_row(file_writ
assert(column_definition.is_static());
atomic_cell_view cell = c.as_atomic_cell();
auto sp = composite::static_prefix(schema);
+ maybe_flush_pi_block(out, sp, { bytes_view(column_definition.name()) });
write_column_name(out, sp, { bytes_view(column_definition.name()) });
write_cell(out, cell);
});
}

-static void write_index_entry(file_writer& out, disk_string_view<uint16_t>& key, uint64_t pos) {
- // FIXME: support promoted indexes.
- uint32_t promoted_index_size = 0;
+static void write_index_header(file_writer& out, disk_string_view<uint16_t>& key, uint64_t pos) {
+ write(out, key, pos);
+}

- write(out, key, pos, promoted_index_size);
+static void write_index_promoted(file_writer& out, bytes_ostream& promoted_index,
+ deletion_time deltime, uint32_t numblocks) {
+ uint32_t promoted_index_size = promoted_index.size();
+ if (promoted_index_size) {
+ promoted_index_size += 16 /* deltime + numblocks */;
+ write(out, promoted_index_size, deltime, numblocks, promoted_index);
+ } else {
+ write(out, promoted_index_size);
+ }
}

static void prepare_summary(summary& s, uint64_t expected_partition_count, uint32_t min_index_interval) {
@@ -1405,6 +1540,17 @@ file_writer components_writer::index_fil
return file_writer(sst._index_file, std::move(options));
}

+// Get the currently loaded configuration, or the default configuration in
+// case none has been loaded (this happens, for example, in unit tests).
+static const db::config& get_config() {
+ if (service::get_storage_service().local_is_initialized()) {
+ return service::get_local_storage_service().db().local().get_config();
+ } else {
+ static db::config default_config;
+ return default_config;
+ }
+}
+
components_writer::components_writer(sstable& sst, const schema& s, file_writer& out,
uint64_t estimated_partitions, uint64_t max_sstable_size,
const io_priority_class& pc)
@@ -1415,6 +1561,7 @@ components_writer::components_writer(sst
, _max_sstable_size(max_sstable_size)
{
_sst._filter = utils::i_filter::get_filter(estimated_partitions, _schema.bloom_filter_fp_chance());
+ _sst._pi_write.desired_block_size = get_config().column_index_size_in_kb() * 1024;

prepare_summary(_sst._summary, estimated_partitions, _schema.min_index_interval());

@@ -1435,7 +1582,17 @@ void components_writer::consume_new_part
p_key.value = bytes_view(*_partition_key);

// Write index file entry from partition key into index file.
- write_index_entry(_index, p_key, _out.offset());
+ // Write an index entry minus the "promoted index" (sample of columns)
+ // part. We can only write that after processing the entire partition
+ // and collecting the sample of columns.
+ write_index_header(_index, p_key, _out.offset());
+ _sst._pi_write.data = {};
+ _sst._pi_write.numblocks = 0;
+ _sst._pi_write.deltime.local_deletion_time = std::numeric_limits<int32_t>::max();
+ _sst._pi_write.deltime.marked_for_delete_at = std::numeric_limits<int64_t>::min();
+ _sst._pi_write.block_start_offset = _out.offset();
+ _sst._pi_write.tombstone_accumulator = range_tombstone_accumulator(_schema, false);
+ _sst._pi_write.schemap = &_schema; // sadly we need this

// Write partition key into data file.
write(_out, p_key);
@@ -1461,6 +1618,8 @@ void components_writer::consume(tombston
}
write(_out, d);
_tombstone_written = true;
+ // TODO: need to verify we don't do this twice?
+ _sst._pi_write.deltime = d;
}

stop_iteration components_writer::consume(static_row&& sr) {
@@ -1477,13 +1636,35 @@ stop_iteration components_writer::consum

stop_iteration components_writer::consume(range_tombstone&& rt) {
ensure_tombstone_is_written();
+ // Remember the range tombstone so when we need to open a new promoted
+ // index block, we can figure out which ranges are still open and need
+ // to be repeated in the data file. Note that apply() also drops ranges
+ // already closed by rt.start, so the accumulator doesn't grow boundless.
+ _sst._pi_write.tombstone_accumulator->apply(rt);
auto start = composite::from_clustering_element(_schema, std::move(rt.start));
auto end = composite::from_clustering_element(_schema, std::move(rt.end));
+ _sst.maybe_flush_pi_block(_out, start, {});
_sst.write_range_tombstone(_out, std::move(start), rt.start_kind, std::move(end), rt.end_kind, {}, rt.tomb);
return stop_iteration::no;
}

stop_iteration components_writer::consume_end_of_partition() {
+ // If there is an incomplete block in the promoted index, write it too.
+ // However, if the _promoted_index is still empty, don't add a single
+ // chunk - better not output a promoted index at all in this case.
+ if (!_sst._pi_write.data.empty() && !_sst._pi_write.block_first_colname.empty()) {
+ output_promoted_index_entry(_sst._pi_write.data,
+ _sst._pi_write.block_first_colname,
+ _sst._pi_write.block_last_colname,
+ _sst._pi_write.block_start_offset - _sst._c_stats.start_offset,
+ _out.offset() - _sst._pi_write.block_start_offset);
+ _sst._pi_write.numblocks++;
+ _sst._pi_write.block_first_colname = {};
+ }
+ write_index_promoted(_index, _sst._pi_write.data, _sst._pi_write.deltime,
+ _sst._pi_write.numblocks);
+ _sst._pi_write.data = {};
+
ensure_tombstone_is_written();
int16_t end_of_row = 0;
write(_out, end_of_row);

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 7:49:35 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
In this unit test, we create using Scylla C++ code, the same large
partition with 13520 CQL rows as we previously imported from Cassandra
for the large partition test. We then verify that the sstable index file
we just wrote is byte-for-byte identical to the one previously created by
Cassandra. They should indeed be identical, because the data file has the
same layout (even if timestamps are different) and our default promoted-
index block size is the same (64K) so the sample of columns should be
identical.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
---
tests/sstable_test.cc | 54 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)

--- .before/tests/sstable_test.cc 2016-08-07 14:46:39.498294114 +0300
+++ .after/tests/sstable_test.cc 2016-08-07 14:46:39.499294122 +0300
@@ -38,6 +38,7 @@
#include "sstable_test.hh"
#include "tmpdir.hh"
#include "partition_slice_builder.hh"
+#include "tests/test_services.hh"

#include "disk-error-handler.hh"

@@ -1166,3 +1167,56 @@ SEASTAR_TEST_CASE(sub_partitions_read) {
});
});
}
+
+// A silly, inefficient but effective, way to compare two files by reading
+// them entirely into memory.
+static future<> compare_files(sstring file1, sstring file2) {
+ return read_file(file1).then([file2] (auto in1) {
+ return read_file(file2).then([in1 = std::move(in1)] (auto in2) {
+ // assert that both files have the same size.
+ BOOST_REQUIRE(in1.second == in2.second);
+ // assert that both files have the same content.
+ BOOST_REQUIRE(::memcmp(in1.first.get(), in2.first.get(), in1.second) == 0);
+ });
+ });
+
+}
+
+// This test creates the same data as we previously created with Cassandra
+// in the tests/sstables/large_partition directory (which we read in the
+// promoted_index_read test above). The index file in both sstables - which
+// includes the promoted index - should be bit-for-bit identical, otherwise
+// we have a problem in our promoted index writing code (or in the data
+// writing code, because the promoted index points to offsets in the data).
+SEASTAR_TEST_CASE(promoted_index_write) {
+ return test_setup::do_with_test_directory([] {
+ auto s = large_partition_schema();
+ auto mtp = make_lw_shared<memtable>(s);
+ auto key = partition_key::from_exploded(*s, {to_bytes("v1")});
+ mutation m(key, s);
+ auto col = s->get_column_definition("t3");
+ BOOST_REQUIRE(col && !col->is_static());
+ for (char i = 'a'; i <= 'z'; i++) {
+ for (char j = 'A'; j <= 'Z'; j++) {
+ for (int k = 0; k < 20; k++) {
+ auto& row = m.partition().clustered_row(
+ clustering_key::from_exploded(
+ *s, {to_bytes(sprint("%d%c%c", k, i, j))}));
+ row.cells().apply(*col,
+ atomic_cell::make_live(2345,
+ col->type->decompose(sstring(sprint("z%c",i)))));
+ row.apply(row_marker(1234));
+ }
+ }
+ }
+ mtp->apply(std::move(m));
+ auto sst = make_lw_shared<sstable>("try1", "data",
+ "tests/sstables/tests-temporary", 100,
+ sstables::sstable::version_types::ka, big);
+ return sst->write_components(*mtp).then([s] {
+ return compare_files(
+ "tests/sstables/large_partition/try1-data-ka-3-Index.db",
+ "tests/sstables/tests-temporary/try1-data-ka-100-Index.db");
+ }).then([sst, mtp] {});
+ });
+}

Avi Kivity

<avi@scylladb.com>
unread,
Aug 7, 2016, 9:16:49 AM8/7/16
to Nadav Har'El, scylladb-dev@googlegroups.com
Can you summarize the changes relative to the previous version, to guide
review?

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 9:28:58 AM8/7/16
to Avi Kivity, scylladb-dev
On Sun, Aug 7, 2016 at 4:16 PM, Avi Kivity <a...@scylladb.com> wrote:
Can you summarize the changes relative to the previous version, to guide review?

Not much, basically:

1. Rebase to current master (there were a bunch of changes, unfortunately, like using shared_sstable instead of sstable& in a bunch of places).

2. Fix the FIXME that bothered you. I'm not 100% sure I did this correctly in every case because I didn't know how to test all these cases in practice.

3. Maybe a couple of other tiny fixes I don't remember.

Avi Kivity

<avi@scylladb.com>
unread,
Aug 7, 2016, 10:14:07 AM8/7/16
to Nadav Har'El, scylladb-dev@googlegroups.com
Please post a git url I can pull this from.


On 08/07/2016 02:49 PM, Nadav Har'El wrote:

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 7, 2016, 10:49:40 AM8/7/16
to Avi Kivity, scylladb-dev
g...@github.com:nyh/scylla.git
branch "promoted-index-v4"



--
Nadav Har'El
n...@scylladb.com

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:05 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

tests: add test for reading parts of a large partition

This patch adds a test that takes an sstable with one partition of 13,520
clustering rows (spanning 700 KB in the data file), and attempts to read
various slices CQL rows, counting that we got back the expected number
of rows.

The sstable included here was generated by Cassandra, and includes a
promoted index. Promoted index reading is not supported yet (we will
add it in the next patch), so for now the code will always read the
entire partition from disk; But still the clustering-key filtering is
already functional, and will drop some of the rows as requested,
so this test will pass.

Later, when we add promoted index support, we should check that this test
still passes - promoted index will make the reads in this test more
efficient (which the test cannot verify), but the important thing to check
is that it doesn't break any of these tests.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/tests/sstable_test.cc b/tests/sstable_test.cc
--- a/tests/sstable_test.cc
+++ b/tests/sstable_test.cc
+ auto sst = make_lw_shared<sstable>(
+ "try1", "data", "tests/sstables/large_partition", 3,
+ sstables::sstable::version_types::ka, big);
+ auto fut = sst->load();
+ return std::move(fut).then([sst = std::move(sst)] {
+ return std::move(sst);
+ });
+}
+
+// This is a rudimentary test that reads an sstable exported from Cassandra
+// which contains a promoted index. It just checks that the promoted index
+// is read from disk, as an unparsed array, and doesn't actually use it to
+// search for anything.
+SEASTAR_TEST_CASE(promoted_index_read) {
+ return load_large_partition_sst().then([] (auto sstp) {
+ schema_ptr s = large_partition_schema();
+ return sstables::test(sstp).read_indexes(0).then([sstp]
(index_list vec) {
+ BOOST_REQUIRE(vec.size() == 1);
+ index_entry &e = vec[0];
+ BOOST_REQUIRE(e.get_promoted_index_bytes().size() == 468);
+ });
+ });
+}
+
+// Use an empty string for ck1, ck2, or both, for unbounded ranges.
+static query::partition_slice make_partition_slice(const schema& s,
sstring ck1, sstring ck2) {
+ std::experimental::optional<query::clustering_range::bound> b1;
+ if (!ck1.empty()) {
+ b1.emplace(clustering_key_prefix::from_single_value(
+ s, utf8_type->decompose(ck1)));
+ }
+}
+
+// This test reads, using sstable::read_row(), a slice (a range of
clustering
+// rows) from one large partition in an sstable written in Cassandra.
+// This large partition includes 13520 clustering rows, and spans about
+// 700 KB on disk. When we ask to read only a part of it, the promoted
index
+// (included in this sstable) may be used to allow reading only a part of
the
+ BOOST_REQUIRE(nrows == 0);
+ });
+ }).then([sstp, s] () {
+ // range that is outside (before) the actual range of the data.
+ // No rows should match.
+ return count_rows(sstp, s, "v1", "_a", "_b").then([] (int
nrows) {
+ BOOST_REQUIRE(nrows == 0);
+ });
+ }).then([sstp, s] () {
+ // half-infinite range
+ return count_rows(sstp, s, "v1", "", "10aA").then([] (int
nrows) {
+ BOOST_REQUIRE(nrows == (1*26*26 + 1));
+ });
+ }).then([sstp, s] () {
+ // half-infinite range
+ return count_rows(sstp, s, "v1", "10aA", "").then([] (int
nrows) {
+ BOOST_REQUIRE(nrows == 19*26*26);
+ });
+ }).then([sstp, s] () {
+ // count all rows, but giving an explicit all-encompasing
filter
+ return count_rows(sstp, s, "v1", "", "").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 20*26*26);
+ });
+ }).then([sstp, s] () {
+ // count all rows, without a filter
+ return count_rows(sstp, s, "v1").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 20*26*26);
+ });
+ });
+ });
+}
+
+// Same as previous test, just using read_range_rows instead of read_row
+// to read parts of potentially more than one partition (in this particular
+// sstable, there is actually just one partition).
+SEASTAR_TEST_CASE(sub_partitions_read) {
+ schema_ptr s = large_partition_schema();
+ return load_large_partition_sst().then([s] (auto sstp) {
+ return count_rows(sstp, s, "18wX", "18xB").then([] (int nrows) {
+ BOOST_REQUIRE(nrows == 5);
+ });
+ });
+}
diff --git
a/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db
b/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db
--- a/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-CompressionInfo.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Data.db
b/tests/sstables/large_partition/try1-data-ka-3-Data.db
--- a/tests/sstables/large_partition/try1-data-ka-3-Data.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-Data.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
b/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
--- a/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
+++ b/tests/sstables/large_partition/try1-data-ka-3-Digest.sha1
@@ -0,0 +1 @@
+2833048369
\ No newline at end of file
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Filter.db
b/tests/sstables/large_partition/try1-data-ka-3-Filter.db
--- a/tests/sstables/large_partition/try1-data-ka-3-Filter.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-Filter.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Index.db
b/tests/sstables/large_partition/try1-data-ka-3-Index.db
--- a/tests/sstables/large_partition/try1-data-ka-3-Index.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-Index.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Statistics.db
b/tests/sstables/large_partition/try1-data-ka-3-Statistics.db
--- a/tests/sstables/large_partition/try1-data-ka-3-Statistics.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-Statistics.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-Summary.db
b/tests/sstables/large_partition/try1-data-ka-3-Summary.db
--- a/tests/sstables/large_partition/try1-data-ka-3-Summary.db
+++ b/tests/sstables/large_partition/try1-data-ka-3-Summary.db
null
diff --git a/tests/sstables/large_partition/try1-data-ka-3-TOC.txt
b/tests/sstables/large_partition/try1-data-ka-3-TOC.txt
--- a/tests/sstables/large_partition/try1-data-ka-3-TOC.txt

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:06 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: STOP_THEN_ATOM_START parser state

In a later patch adding "promoted index" read support, we would like to
parse only part of an sstable row. In that case, the parser should start
not at the usual ROW_START state, but rather at the ATOM_START state.

But there's a problem: The sstable parser consumer currently assumes that
the parser stops after the start of the row, before reading any atoms.
So in the partial row case too, we must stop parsing before reading the
first atom.

For this, this patch adds the new "STOP_THEN_ATOM_START" parser state.
When starting in this state, the parser stops immediately (with
row_consumer::proceed::no), and when restarted again it will be in the
ATOM_START case.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/row.cc b/sstables/row.cc
--- a/sstables/row.cc
+++ b/sstables/row.cc
@@ -51,6 +51,7 @@ class data_consume_rows_context : public
data_consumer::continuous_data_consumer
RANGE_TOMBSTONE_3,
RANGE_TOMBSTONE_4,
RANGE_TOMBSTONE_5,
+ STOP_THEN_ATOM_START,
} _state = state::ROW_START;

row_consumer& _consumer;
@@ -69,6 +70,7 @@ class data_consume_rows_context : public
data_consumer::continuous_data_consumer
|| (_state == state::CELL_VALUE_BYTES_2)
|| (_state == state::ATOM_START_2)
|| (_state == state::ATOM_MASK_2)
+ || (_state == state::STOP_THEN_ATOM_START)
|| (_state == state::EXPIRING_CELL_3)) && (_prestate ==
prestate::NONE));
}

@@ -319,6 +321,9 @@ class data_consume_rows_context : public
data_consumer::continuous_data_consumer
}
break;
}
+ case state::STOP_THEN_ATOM_START:
+ _state = state::ATOM_START;

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:07 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: disk_read_range

Currently, the main sstable data parsing entry point data_consume_rows()
takes a contiguous range of bytes to read from disk and parse. This range
is supposed to be an entire partition or contiguous group of partitions.
and is self contained (can be parsed without extra information about the
identity of these partitions).

For the promoted index feature (which we will add in a following patch)
we will want the range to span only a part of a partition, and will need
the caller to provide some information not available to the parser (such
as the partition's key). In the future, we will also want to support a
vector of byte ranges, instead of just one.

So in preparation for this, this patch simply replaces the start/end pair
by a new class disk_read_range, which can be easily extended in later
patches. No new functionality is introduced in this patch.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/partition.cc b/sstables/partition.cc
--- a/sstables/partition.cc
+++ b/sstables/partition.cc
@@ -590,17 +590,17 @@ struct sstable_data_source {
, _context(_sst->data_consume_rows(_consumer))
{ }

- sstable_data_source(shared_sstable sst, mp_row_consumer&& consumer,
uint64_t start, uint64_t end)
+ sstable_data_source(shared_sstable sst, mp_row_consumer&& consumer,
sstable::disk_read_range toread)
: _sst(std::move(sst))
, _consumer(std::move(consumer))
- , _context(_sst->data_consume_rows(_consumer, start, end))
+ , _context(_sst->data_consume_rows(_consumer, std::move(toread)))
{ }

sstable_data_source(schema_ptr s, shared_sstable sst, const
sstables::key& k, const io_priority_class& pc,
- query::clustering_key_filtering_context ck_filtering, uint64_t
start, uint64_t end)
+ query::clustering_key_filtering_context ck_filtering,
sstable::disk_read_range toread)
: _sst(std::move(sst))
, _consumer(k, s, ck_filtering, pc)
- , _context(_sst->data_consume_rows(_consumer, start, end))
+ , _context(_sst->data_consume_rows(_consumer, std::move(toread)))
{ }
};

@@ -680,9 +680,9 @@ class sstable_streamed_mutation : public
streamed_mutation::impl {

static future<streamed_mutation> create(schema_ptr s, shared_sstable
sst, const sstables::key& k,

query::clustering_key_filtering_context ck_filtering,
- const io_priority_class& pc,
uint64_t start, uint64_t end)
+ const io_priority_class& pc,
sstable::disk_read_range toread)
{
- auto ds = make_lw_shared<sstable_data_source>(s, sst, k, pc,
ck_filtering, start, end);
+ auto ds = make_lw_shared<sstable_data_source>(s, sst, k, pc,
ck_filtering, std::move(toread));
return ds->_context.read().then([s, ds] {
auto mut = ds->_consumer.get_mutation();
assert(mut);
@@ -763,7 +763,7 @@ sstables::sstable::read_row(schema_ptr schema,

auto position = index_list[index_idx].position();
return this->data_end_position(summary_idx, index_idx, index_list,
pc).then([&key, schema, ck_filtering, this, position, &pc] (uint64_t end) {
- return sstable_streamed_mutation::create(schema,
this->shared_from_this(), key, ck_filtering, pc, position, end).then([]
(auto sm) {
+ return sstable_streamed_mutation::create(schema,
this->shared_from_this(), key, ck_filtering, pc, {position, end}).then([]
(auto sm) {
return streamed_mutation_opt(std::move(sm));
});
});
@@ -781,12 +781,12 @@ class mutation_reader::impl {
mp_row_consumer _consumer;
std::function<future<lw_shared_ptr<sstable_data_source>> ()>
_get_data_source;
public:
- impl(shared_sstable sst, schema_ptr schema, uint64_t start, uint64_t
end,
+ impl(shared_sstable sst, schema_ptr schema, sstable::disk_read_range
toread,
const io_priority_class &pc)
: _schema(schema)
, _consumer(schema, query::no_clustering_key_filtering, pc)
- , _get_data_source([this, sst = std::move(sst), start, end] {
- auto ds = make_lw_shared<sstable_data_source>(std::move(sst),
std::move(_consumer), start, end);
+ , _get_data_source([this, sst = std::move(sst), toread] {
+ auto ds = make_lw_shared<sstable_data_source>(std::move(sst),
std::move(_consumer), std::move(toread));
return
make_ready_future<lw_shared_ptr<sstable_data_source>>(std::move(ds));
}) { }
impl(shared_sstable sst, schema_ptr schema,
@@ -808,7 +808,7 @@ class mutation_reader::impl {
, _get_data_source([this, sst = std::move(sst), start =
std::move(start), end = std::move(end)] () mutable {
return start().then([this, sst = std::move(sst), end =
std::move(end)] (uint64_t start) mutable {
return end().then([this, sst = std::move(sst), start]
(uint64_t end) mutable {
- return
make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer),
start, end);
+ return
make_lw_shared<sstable_data_source>(std::move(sst), std::move(_consumer),
sstable::disk_read_range{start, end});
});
});
}) { }
diff --git a/sstables/row.cc b/sstables/row.cc
--- a/sstables/row.cc
+++ b/sstables/row.cc
@@ -383,18 +383,19 @@ future<> data_consume_context::read() {
}

data_consume_context sstable::data_consume_rows(
- row_consumer& consumer, uint64_t start, uint64_t end) {
+ row_consumer& consumer, sstable::disk_read_range toread) {
// TODO: The second "end - start" below is redundant: The first one
tells
// data_stream() to stop at the "end" byte, which allows optimal read-
// ahead and avoiding over-read at the end. The second one tells the
// consumer to stop at exactly the same place, and forces the consumer
// to maintain its own byte count.
return std::make_unique<data_consume_context::impl>(shared_from_this(),
- consumer, data_stream(start, end - start,
consumer.io_priority()), end - start);
+ consumer, data_stream(toread.start, toread.end - toread.start,
+ consumer.io_priority()), toread.end - toread.start);
}

data_consume_context sstable::data_consume_rows(row_consumer& consumer) {
- return data_consume_rows(consumer, 0, data_size());
+ return data_consume_rows(consumer, {0, data_size()});
}

future<> sstable::data_consume_rows_at_once(row_consumer& consumer,
diff --git a/sstables/sstables.hh b/sstables/sstables.hh
--- a/sstables/sstables.hh
+++ b/sstables/sstables.hh
@@ -155,6 +155,16 @@ public:
// object lives until then (e.g., using the do_with() idiom).
future<> data_consume_rows_at_once(row_consumer& consumer, uint64_t
pos, uint64_t end);

+ struct disk_read_range {
+ uint64_t start;
+ uint64_t end;
+ disk_read_range() : start(0), end(0) {}
+ disk_read_range(uint64_t start, uint64_t end) :
+ start(start), end(end) { }
+ explicit operator bool() const {
+ return start != end;
+ }
+ };

// data_consume_rows() iterates over rows in the data file from
// a particular range, feeding them into the consumer. The iteration is
@@ -172,7 +182,7 @@ public:
// The caller must ensure (e.g., using do_with()) that the context
object,
// as well as the sstable, remains alive as long as a read() is in
// progress (i.e., returned a future which hasn't completed yet).
- data_consume_context data_consume_rows(row_consumer& consumer,
uint64_t start, uint64_t end);
+ data_consume_context data_consume_rows(row_consumer& consumer,
disk_read_range toread);

// Like data_consume_rows() with bounds, but iterates over whole range
data_consume_context data_consume_rows(row_consumer& consumer);
diff --git a/tests/sstable_test.cc b/tests/sstable_test.cc
--- a/tests/sstable_test.cc
+++ b/tests/sstable_test.cc
@@ -448,7 +448,7 @@ SEASTAR_TEST_CASE(compressed_row_read_at_once) {
SEASTAR_TEST_CASE(uncompressed_rows_read_one) {
return reusable_sst("tests/sstables/uncompressed", 1).then([] (auto
sstp) {
return do_with(test_row_consumer(1418656871665302), [sstp] (auto&
c) {
- auto context = sstp->data_consume_rows(c, 0, 95);
+ auto context = sstp->data_consume_rows(c, {0, 95});
auto fut = context.read();
return fut.then([sstp, &c, context = std::move(context)] {
BOOST_REQUIRE(c.count_row_start == 1);
@@ -465,7 +465,7 @@ SEASTAR_TEST_CASE(uncompressed_rows_read_one) {

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:09 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

make column-name parsing code public

The "struct column" code in partition.cc is generally useful code for
parsing serialized column names from the sstable. It is currently private
inside the "mp_row_consumer" class. But in a next patch we'll also want
to use it in the "sstable" class, for the promoted-index parsing code,
which among other things also needs to deserialize column names.

The trivial fix, in this patch, is to make this code "public". However,
for now it is still available only in partition.cc.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/partition.cc b/sstables/partition.cc
--- a/sstables/partition.cc
+++ b/sstables/partition.cc
@@ -125,6 +125,7 @@ class mp_row_consumer : public row_consumer {
stdx::optional<new_mutation> _mutation;
bool _is_mutation_end;

+public:
struct column {
bool is_static;
bytes_view col_name;
@@ -200,6 +201,7 @@ class mp_row_consumer : public row_consumer {

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:11 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: expose promoted index in index entry

Our index_entry type, holding one partition's entry that we read from the
index file, already contained the "_promoted_index" which we read from
disk - as an unparsed byte buffer. But there wasn't any API to access
this buffer after it was read. This patch adds a trivial getter, to get
a read-only view of this buffer.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/types.hh b/sstables/types.hh
--- a/sstables/types.hh
+++ b/sstables/types.hh

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:13 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: promoted index read support
Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/partition.cc b/sstables/partition.cc
--- a/sstables/partition.cc
+++ b/sstables/partition.cc
@@ -738,37 +738,16 @@ sstables::sstable::read_row(schema_ptr schema,
- auto position = index_list[index_idx].position();
- return this->data_end_position(summary_idx, index_idx, index_list,
pc).then([&key, schema, ck_filtering, this, position, &pc] (uint64_t end) {
- return sstable_streamed_mutation::create(schema,
this->shared_from_this(), key, ck_filtering, pc, {position, end}).then([]
(auto sm) {
- return streamed_mutation_opt(std::move(sm));
- });
+ return sstable_streamed_mutation::create(schema,
this->shared_from_this(), key, ck_filtering, pc, std::move(toread)).then([]
(auto sm) {
+ return streamed_mutation_opt(std::move(sm));
});
});
}
diff --git a/sstables/row.cc b/sstables/row.cc
--- a/sstables/row.cc
+++ b/sstables/row.cc
@@ -63,6 +63,7 @@ class data_consume_rows_context : public
data_consumer::continuous_data_consumer
bool _deleted;
uint32_t _ttl, _expiration;

+ bool _read_partial_row = false;

public:
bool non_consuming() const {
@@ -332,12 +333,42 @@ class data_consume_rows_context : public
data_consumer::continuous_data_consumer
}

data_consume_rows_context(row_consumer& consumer,
- input_stream<char> && input, uint64_t maxlen) :
- continuous_data_consumer(std::move(input), maxlen)
- , _consumer(consumer) {
+ input_stream<char> && input, uint64_t maxlen,
+
std::experimental::optional<sstable::disk_read_range::row_info> ri = {})
+ : continuous_data_consumer(std::move(input), maxlen)
+ , _consumer(consumer) {
+ // If the "ri" option is given, we are reading a partition from the
+ // middle (in the beginning of an atom), as would happen when we
use
+ // the "promoted index" to skip closer to where a particular column
+ // starts. When we start in the middle of the partition, we will
not
+ // read the key nor the tombstone from the disk, so the caller
needs
+ // to provide them (the tombstone is provided in the promoted index
+ // exactly for that reason).
+ if (ri) {
+ _read_partial_row = true;
+ auto ret = _consumer.consume_row_start(ri->k, ri->deltime);
+ if (ret == row_consumer::proceed::yes) {
+ _state = state::ATOM_START;
+ } else {
+ // If we were asked to stop parsing after consuming the row
+ // start, we can't go to ATOM_START, need to use a new
state
+ // which stops parsing, and continues at ATOM_START later.
+ _state = state::STOP_THEN_ATOM_START;
+ }
+ }
}

void verify_end_state() {
+ if (_read_partial_row) {
+ // If reading a partial row (i.e., when we have a clustering
row
+ // filter and using a promoted index), we may be in ATOM_START
+ // state instead of ROW_START. In that case we did not read the
+ // end-of-row marker and consume_row_end() was never called.
+ if (_state == state::ATOM_START) {
+ _consumer.consume_row_end();
+ return;
+ }
+ }
if (_state != state::ROW_START || _prestate != prestate::NONE) {
throw malformed_sstable_exception("end of input, but not end
of row");
}
@@ -354,9 +385,10 @@ class data_consume_context::impl {
shared_sstable _sst;
std::unique_ptr<data_consume_rows_context> _ctx;
public:
- impl(shared_sstable sst, row_consumer& consumer, input_stream<char>&&
input, uint64_t maxlen)
+ impl(shared_sstable sst, row_consumer& consumer, input_stream<char>&&
input, uint64_t maxlen,
+
std::experimental::optional<sstable::disk_read_range::row_info> ri)
: _sst(std::move(sst))
- , _ctx(new data_consume_rows_context(consumer, std::move(input),
maxlen))
+ , _ctx(new data_consume_rows_context(consumer, std::move(input),
maxlen, ri))
{ }
~impl() {
if (_ctx) {
@@ -391,7 +423,7 @@ data_consume_context sstable::data_consume_rows(
// to maintain its own byte count.
return std::make_unique<data_consume_context::impl>(shared_from_this(),
consumer, data_stream(toread.start, toread.end - toread.start,

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:13 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: introduce find_disk_ranges()

Our sstable reading code is currently hard-coded to read entire partitions,
even if we know that only a subset of the columns are requested.
This patch introduces find_disk_ranges(), a function to find the ranges of
bytes we need to read from the sstable data file to guarantee that the
desired columns from the desired partition are read.

The returned range may be the entire byte range of the given partition -
as found using the summary and index files - but if the index contains a
"promoted index" (basically a sample of column positions for each key)
we may return a smaller range. The "disk_read_range" type introduced in
the previous patch is extended here to support reading a partial partition -
by including additional information which would be missed when reading only
part of a partition (viz., the partition key and the partition's tombstone).

This function isn't used in this patch - we will wire its use in the next
patch, which will complete the read-side support for the promoted index.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/partition.cc b/sstables/partition.cc
--- a/sstables/partition.cc
+++ b/sstables/partition.cc
@@ -28,6 +28,7 @@
#include "unimplemented.hh"
#include "utils/move.hh"
#include "dht/i_partitioner.hh"
+#include <seastar/core/byteorder.hh>

namespace sstables {

@@ -772,6 +773,167 @@ sstables::sstable::read_row(schema_ptr schema,
});
+ return read_indexes(summary_idx, pc).then([this, schema, ck_filtering,
&key, token, summary_idx, &pc] (auto index_list) {
+ });
+ });
+}
+
class mutation_reader::impl {
private:
schema_ptr _schema;
diff --git a/sstables/sstables.hh b/sstables/sstables.hh
--- a/sstables/sstables.hh
+++ b/sstables/sstables.hh
@@ -155,15 +155,40 @@ public:
// object lives until then (e.g., using the do_with() idiom).
future<> data_consume_rows_at_once(row_consumer& consumer, uint64_t
pos, uint64_t end);

+ // disk_read_range describes a byte ranges covering part of an sstable
+ // row that we need to read from disk. Usually this is the whole byte
+ // range covering a single sstable row, but in very large rows we might
+ // want to only read a subset of the atoms which we know contains the
+ // columns we are looking for. When the range to be read does NOT
include
+ // the entire row, the caller needs to supply the optional "row_info"
+ // containing information about the entire row (key and deletion time)
+ // which is normally read from the beginning of the row.
struct disk_read_range {
+ // TODO: this should become a vector of ranges
uint64_t start;
uint64_t end;
+ // When the range above does not cover the beginning of the sstable
+ // row, we need to supply information which is only available at
the
+ // beginning of the row - the row's key and its tombstone if any.
+ struct row_info {
+ key k;
+ deletion_time deltime;
+ };
+ std::experimental::optional<row_info> ri;
disk_read_range() : start(0), end(0) {}
disk_read_range(uint64_t start, uint64_t end) :
start(start), end(end) { }
+ disk_read_range(uint64_t start, uint64_t end, const key& key,
const deletion_time& deltime) :
+ start(start), end(end), ri(row_info{key, deltime}) { }
explicit operator bool() const {
return start != end;
}
+ // found_row() is true if the row was found. This is not the same
as
+ // operator bool(): It is possible that found_row() but the
promoted
+ // index ruled out anything to read (in this case "ri" was set).
+ bool found_row() const {
+ return start != end || ri;
+ }
};

// data_consume_rows() iterates over rows in the data file from

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:14 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

range tombstone accumulator: add method

Add to the range_tombstone_accumulator a range_tombstones_for_row(ck)
method.

Just like the existing tombstone_for_row(ck), this function drops from
the accumulator tombstones that end before ck. But while the existing
function returned just a single tombstone affecting the given row (the
most recent tombstone), the new function range_tombstones_for_row(ck)
returns all the accumulated range tombstones which cover ck.

This function will be useful for the promoted-index writing code later,
which divides a partition into blocks which may be read independently,
so each block needs to start with a repeat of the earlier tombstones
which still cover the first row in the new block.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/range_tombstone.hh b/range_tombstone.hh
--- a/range_tombstone.hh
+++ b/range_tombstone.hh

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:16 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: promoted index write support

This patch adds writing of promoted index to sstables.

The promoted index is basically a sample of columns and their positions
for large partitions: The promoted index appears in the sstable's index
file for partitions which are larger than 64 KB, and divides the partition
to 64 KB blocks (as in Cassandra, this interval is configurable through
the column_index_size_in_kb config parameter). Beyond modifying the index
file, having a promoted index may also modify the data file: Since each
of blocks may be read independently, we need to add in the beginning of
each block the list of range tombstones that are still open at that
position.

See also https://github.com/scylladb/scylla/wiki/SSTables-Index-File

Fixes #959

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/sstables/sstables.cc b/sstables/sstables.cc
--- a/sstables/sstables.cc
+++ b/sstables/sstables.cc
@@ -31,6 +31,7 @@
#include "core/do_with.hh"
#include "core/thread.hh"
#include <seastar/core/shared_future.hh>
+#include <seastar/core/byteorder.hh>
#include <iterator>

#include "types.hh"
@@ -56,6 +57,7 @@

#include "checked-file-impl.hh"
#include "disk-error-handler.hh"
+#include "service/storage_service.hh"

thread_local disk_error_signal_type sstable_read_error;
thread_local disk_error_signal_type sstable_write_error;
@@ -296,6 +298,12 @@ inline void write(file_writer& out, bytes_view s) {
@@ -1223,6 +1333,7 @@ void sstable::write_collection(file_writer& out,
const composite& clustering_key
const bytes& column_name = cdef.name();
write_range_tombstone(out, clustering_key, clustering_key, {
bytes_view(column_name) }, mview.tomb);
for (auto& cp: mview.cells) {
+ maybe_flush_pi_block(out, clustering_key, { column_name, cp.first
});
write_column_name(out, clustering_key, { column_name, cp.first });
write_cell(out, cp.second);
}
@@ -1234,11 +1345,22 @@ void sstable::write_clustered_row(file_writer& out,
const schema& schema, const
auto clustering_key = composite::from_clustering_element(schema,
clustered_row.key());

if (schema.is_compound() && !schema.is_dense()) {
+ maybe_flush_pi_block(out, clustering_key, { bytes_view() });
write_row_marker(out, clustered_row.marker(), clustering_key);
}
// Before writing cells, range tombstone must be written if the row
has any (deletable_row::t).
if (clustered_row.tomb()) {
+ maybe_flush_pi_block(out, clustering_key, {});
write_range_tombstone(out, clustering_key, clustering_key, {},
clustered_row.tomb());
+ // Because we currently may break a partition to promoted-index
blocks
+ // in the middle of a clustered row, we also need to track the
current
+ // row's tombstone - not just range tombstones - which may effect
the
+ // beginning of a new block.
+ // TODO: consider starting a new block only between rows, so the
+ // following code can be dropped:
+ _pi_write.tombstone_accumulator->apply(range_tombstone(
+ clustered_row.key(), bound_kind::incl_start,
+ clustered_row.key(), bound_kind::incl_end,
clustered_row.tomb()));
}

// Write all cells of a partition's row.
@@ -1256,14 +1378,18 @@ void sstable::write_clustered_row(file_writer& out,
const schema& schema, const

if (schema.is_compound()) {
if (schema.is_dense()) {
+ maybe_flush_pi_block(out, composite(), {
bytes_view(clustering_key) });
write_column_name(out, bytes_view(clustering_key));
} else {
+ maybe_flush_pi_block(out, clustering_key, {
bytes_view(column_name) });
write_column_name(out, clustering_key, {
bytes_view(column_name) });
}
} else {
if (schema.is_dense()) {
+ maybe_flush_pi_block(out, composite(), {
bytes_view(clustered_row.key().get_component(schema, 0)) });
write_column_name(out,
bytes_view(clustered_row.key().get_component(schema, 0)));
} else {
+ maybe_flush_pi_block(out, composite(), {
bytes_view(column_name) });
write_column_name(out, bytes_view(column_name));
}
}
@@ -1282,16 +1408,25 @@ void sstable::write_static_row(file_writer& out,
const schema& schema, const row
components_writer::index_file_writer(sstable& sst, const io_priority
return file_writer(sst._index_file, std::move(options));
}

+// Get the currently loaded configuration, or the default configuration in
+// case none has been loaded (this happens, for example, in unit tests).
+static const db::config& get_config() {
+ if (service::get_storage_service().local_is_initialized()) {
+ return
service::get_local_storage_service().db().local().get_config();
+ } else {
+ static db::config default_config;
+ return default_config;
+ }
+}
+
components_writer::components_writer(sstable& sst, const schema& s,
file_writer& out,
uint64_t estimated_partitions,
uint64_t max_sstable_size,
const io_priority_class& pc)
@@ -1415,6 +1561,7 @@ components_writer::components_writer(sstable& sst,
const schema& s, file_writer&
, _max_sstable_size(max_sstable_size)
{
_sst._filter = utils::i_filter::get_filter(estimated_partitions,
_schema.bloom_filter_fp_chance());
+ _sst._pi_write.desired_block_size =
get_config().column_index_size_in_kb() * 1024;

prepare_summary(_sst._summary, estimated_partitions,
_schema.min_index_interval());

@@ -1435,7 +1582,17 @@ void components_writer::consume_new_partition(const
dht::decorated_key& dk) {
p_key.value = bytes_view(*_partition_key);

// Write index file entry from partition key into index file.
- write_index_entry(_index, p_key, _out.offset());
+ // Write an index entry minus the "promoted index" (sample of columns)
+ // part. We can only write that after processing the entire partition
+ // and collecting the sample of columns.
+ write_index_header(_index, p_key, _out.offset());
+ _sst._pi_write.data = {};
+ _sst._pi_write.numblocks = 0;
+ _sst._pi_write.deltime.local_deletion_time =
std::numeric_limits<int32_t>::max();
+ _sst._pi_write.deltime.marked_for_delete_at =
std::numeric_limits<int64_t>::min();
+ _sst._pi_write.block_start_offset = _out.offset();
+ _sst._pi_write.tombstone_accumulator =
range_tombstone_accumulator(_schema, false);
+ _sst._pi_write.schemap = &_schema; // sadly we need this

// Write partition key into data file.
write(_out, p_key);
@@ -1461,6 +1618,8 @@ void components_writer::consume(tombstone t) {
}
write(_out, d);
_tombstone_written = true;
+ // TODO: need to verify we don't do this twice?
+ _sst._pi_write.deltime = d;
}

stop_iteration components_writer::consume(static_row&& sr) {
@@ -1477,13 +1636,35 @@ stop_iteration
components_writer::consume(clustering_row&& cr) {
diff --git a/sstables/sstables.hh b/sstables/sstables.hh
--- a/sstables/sstables.hh
+++ b/sstables/sstables.hh
@@ -407,6 +407,27 @@ private:
uint64_t _filter_file_size = 0;
uint64_t _bytes_on_disk = 0;

+ // _pi_write is used temporarily for building the promoted
+ // index (column sample) of one partition when writing a new sstable.
+ struct {

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 7, 2016, 10:54:17 AM8/7/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

tests: add test for promoted index writing

In this unit test, we create using Scylla C++ code, the same large
partition with 13520 CQL rows as we previously imported from Cassandra
for the large partition test. We then verify that the sstable index file
we just wrote is byte-for-byte identical to the one previously created by
Cassandra. They should indeed be identical, because the data file has the
same layout (even if timestamps are different) and our default promoted-
index block size is the same (64K) so the sample of columns should be
identical.

Signed-off-by: Nadav Har'El <n...@scylladb.com>

---
diff --git a/tests/sstable_test.cc b/tests/sstable_test.cc
--- a/tests/sstable_test.cc
+++ b/tests/sstable_test.cc
@@ -38,6 +38,7 @@
#include "sstable_test.hh"
#include "tmpdir.hh"
#include "partition_slice_builder.hh"
+#include "tests/test_services.hh"

#include "disk-error-handler.hh"

@@ -1166,3 +1167,56 @@ SEASTAR_TEST_CASE(sub_partitions_read) {
});
});
}
+
+// A silly, inefficient but effective, way to compare two files by reading
+// them entirely into memory.
+static future<> compare_files(sstring file1, sstring file2) {
+ return read_file(file1).then([file2] (auto in1) {
+ return read_file(file2).then([in1 = std::move(in1)] (auto in2) {
+ // assert that both files have the same size.
+ BOOST_REQUIRE(in1.second == in2.second);
+ // assert that both files have the same content.
+ BOOST_REQUIRE(::memcmp(in1.first.get(), in2.first.get(),
in1.second) == 0);
+ });
+ });
+
+}
+ auto sst = make_lw_shared<sstable>("try1", "data",
+ "tests/sstables/tests-temporary", 100,
+ sstables::sstable::version_types::ka, big);

Commit Bot

<bot@cloudius-systems.com>
unread,
Aug 9, 2016, 9:58:36 AM8/9/16
to scylladb-dev@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Avi Kivity <a...@scylladb.com>
Branch: branch-1.3

sstables: promoted index write support

This patch adds writing of promoted index to sstables.

The promoted index is basically a sample of columns and their positions
for large partitions: The promoted index appears in the sstable's index
file for partitions which are larger than 64 KB, and divides the partition
to 64 KB blocks (as in Cassandra, this interval is configurable through
the column_index_size_in_kb config parameter). Beyond modifying the index
file, having a promoted index may also modify the data file: Since each
of blocks may be read independently, we need to add in the beginning of
each block the list of range tombstones that are still open at that
position.

See also https://github.com/scylladb/scylla/wiki/SSTables-Index-File

Fixes #959

Signed-off-by: Nadav Har'El <n...@scylladb.com>
(cherry picked from commit 0d8463aba580cb3c84cb9cafa825e0e2eb16ebc1)
@@ -372,6 +372,27 @@ private:

Tomasz Grabiec

<tgrabiec@scylladb.com>
unread,
Aug 10, 2016, 8:06:50 AM8/10/16
to Nadav Har'El, scylladb-dev
Paging queries will use a slice with start bound set but no end bound. I think we already have bounds for the whole partition from the index, we could set found_range_end right away if end bound is not set so that the scanning of promoted index stops as soon as we find the start bound.
 


--
You received this message because you are subscribed to the Google Groups "ScyllaDB development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scylladb-dev+unsubscribe@googlegroups.com.
To post to this group, send email to scylla...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scylladb-dev/94eb2c060008f7869105397c7863%40google.com.
For more options, visit https://groups.google.com/d/optout.

Tomasz Grabiec

<tgrabiec@scylladb.com>
unread,
Aug 10, 2016, 9:33:50 AM8/10/16
to Nadav Har'El, scylladb-dev
On Sun, Aug 7, 2016 at 4:54 PM, Commit Bot <b...@cloudius-systems.com> wrote:
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

sstables: promoted index read support

This patch adds support more efficiently reading small parts of a large
partition, without reading the entire partition as we had to do so far.
This is done using the "promoted index".

The "promoted index" is stored in the sstable index file, and provides
for each large sstable row ("partition" in CQL nomenclature) a sample of
the column names at (for example) 64KB intervals. This means that when we
read a slice of columns (e.g., cql rows), or page through a large partition,
we do not have to read the entire partition from disk.

This patch only implements the read side of promoted index - a later patch
will add the write-side support (i.e., writing the promoted index to the
index file while saving the sstable). Nevertheless this patch can already
be tested by reading existing sstables from Cassandra which include a
promoted index - such as the one included in the test in the previous patch.

The use of the promoted index currently has two limitations:

1. It is only used when reading a single partition with sstable::read_row(),
not when scanning through many partitions with sstable::read_range_rows()
or sstable::read_rows().

2. It is only used when filtering a single clustering-key range, rather
than a list of disjoint ranges. A single range is the common case.

This will affect performance of CQL statements with "IN" restriction on clustering columns. We should open a github issue about this so that we don't forget it.
We should still read the static row. 

 
--
You received this message because you are subscribed to the Google Groups "ScyllaDB development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scylladb-dev+unsubscribe@googlegroups.com.
To post to this group, send email to scylla...@googlegroups.com.

Tomasz Grabiec

<tgrabiec@scylladb.com>
unread,
Aug 10, 2016, 12:20:28 PM8/10/16
to Nadav Har'El, scylladb-dev
On Sun, Aug 7, 2016 at 4:54 PM, Commit Bot <b...@cloudius-systems.com> wrote:
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master


<snip>
 

diff --git a/sstables/sstables.hh b/sstables/sstables.hh
--- a/sstables/sstables.hh
+++ b/sstables/sstables.hh
@@ -407,6 +407,27 @@ private:
     uint64_t _filter_file_size = 0;
     uint64_t _bytes_on_disk = 0;

+    // _pi_write is used temporarily for building the promoted
+    // index (column sample) of one partition when writing a new sstable.
+    struct {
+        // Unfortunately we cannot output the promoted index directly to the
+        // index file because it needs to be prepended by its size.

Does it mean that sstable compaction memory footprint is proportional to partition size? This may be a problem with large partitions.
 

Nadav Har'El

<nyh@scylladb.com>
unread,
Aug 10, 2016, 12:51:36 PM8/10/16
to Tomasz Grabiec, scylladb-dev

On Wed, Aug 10, 2016 at 7:20 PM, Tomasz Grabiec <tgra...@scylladb.com> wrote:
+    // _pi_write is used temporarily for building the promoted
+    // index (column sample) of one partition when writing a new sstable.
+    struct {
+        // Unfortunately we cannot output the promoted index directly to the
+        // index file because it needs to be prepended by its size.

Does it mean that sstable compaction memory footprint is proportional to partition size? This may be a problem with large partitions.
 

Yes, but not just compaction - also read of the resulting sstable - because reading the index entry (to find the partition) always reads the entire "promoted index" saved in this index entry - it was like that even before my patch.

I think the idea is that for large but not super-super-huge partitions, the divisor (64K) is supposed to be so high you won't care about the proportionality. Of course, we know how sucky this is in theory as the partitions grow towards infinity.

Avi Kivity

<avi@scylladb.com>
unread,
Aug 11, 2016, 4:00:29 AM8/11/16
to Nadav Har'El, Tomasz Grabiec, scylladb-dev
Or in practice.  Let's say each promoted index entry is 100 bytes.  Then we have a 640:1 ratio between partition size and index size.   A 64MB translates to a 100kB index entry, so you're limited to ~100MB partitions if you want reasonable performance.

If we could guess the partition size up front, we could make the block size sqrt((partition size in bytes) / (estimated promoted index entry size in bytes)).  This would make the block size and the index entry size equal, minimizing bandwidth.  But it's better to spend that effort on a proper O(log N) index.

Pekka Enberg

<penberg@scylladb.com>
unread,
Aug 24, 2016, 5:45:00 AM8/24/16
to Tomasz Grabiec, Nadav Har'El, scylladb-dev
So did anyone open an issue about it?

Tomasz Grabiec

<tgrabiec@scylladb.com>
unread,
Aug 29, 2016, 11:18:02 AM8/29/16
to Pekka Enberg, Nadav Har'El, scylladb-dev
Reply all
Reply to author
Forward
0 new messages