From dc7f369be9a6d557fc1ad7a7c559f53e1f887736 Mon Sep 17 00:00:00 2001 From: Crzyrndm Date: Sat, 4 Aug 2018 14:55:17 +1200 Subject: [PATCH 1/6] Add relative urls to the valid hyperlink url set --- source/cell/cell.cpp | 2 +- tests/cell/cell_test_suite.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 667212d8..1e26f7c8 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -360,7 +360,7 @@ hyperlink cell::hyperlink() const void cell::hyperlink(const std::string &url, const std::string &display) { - if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end()) + if (url.empty()) { throw invalid_parameter(); } diff --git a/tests/cell/cell_test_suite.cpp b/tests/cell/cell_test_suite.cpp index 510786b3..0f76e2af 100644 --- a/tests/cell/cell_test_suite.cpp +++ b/tests/cell/cell_test_suite.cpp @@ -687,7 +687,6 @@ private: xlnt_assert(!cell.has_hyperlink()); xlnt_assert_throws(cell.hyperlink(), xlnt::invalid_attribute); - xlnt_assert_throws(cell.hyperlink("notaurl"), xlnt::invalid_parameter); xlnt_assert_throws(cell.hyperlink(""), xlnt::invalid_parameter); // link without optional display const std::string link1("http://example.com"); @@ -707,6 +706,13 @@ private: xlnt_assert_equals(cell.hyperlink().url(), link2); xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link2); xlnt_assert_equals(cell.hyperlink().display(), display_txt); + // relative (local) url + const std::string local("../test_local"); + cell.hyperlink(local); + xlnt_assert(cell.has_hyperlink()); + xlnt_assert(cell.hyperlink().external()); + xlnt_assert_equals(cell.hyperlink().url(), local); + xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), local); // value int cell_test_val = 123; cell.value(cell_test_val); From c804b4c569a591b7db7c215e07929845a81f8fc6 Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Thu, 30 Aug 2018 14:46:58 +0100 Subject: [PATCH 2/6] Added new feature to insert and delete rows and columns --- include/xlnt/cell/index_types.hpp | 6 + include/xlnt/worksheet/worksheet.hpp | 26 +++ source/worksheet/worksheet.cpp | 144 ++++++++++++++ tests/worksheet/worksheet_test_suite.cpp | 241 +++++++++++++++++++++++ 4 files changed, 417 insertions(+) diff --git a/include/xlnt/cell/index_types.hpp b/include/xlnt/cell/index_types.hpp index 129a5ee5..b7f47a5d 100644 --- a/include/xlnt/cell/index_types.hpp +++ b/include/xlnt/cell/index_types.hpp @@ -283,6 +283,12 @@ public: index_t index; }; +enum class row_or_col_t : int +{ + row, + column +}; + /// /// Functor for hashing a column. /// Allows for use of std::unordered_set and similar. diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp index ed460992..69b998e7 100644 --- a/include/xlnt/worksheet/worksheet.hpp +++ b/include/xlnt/worksheet/worksheet.hpp @@ -270,6 +270,26 @@ public: /// void clear_row(row_t row); + /// + /// Insert empty rows before the given row index + /// + void insert_rows(row_t row, std::uint32_t amount); + + /// + /// Insert empty columns before the given column index + /// + void insert_columns(column_t column, std::uint32_t amount); + + /// + /// Delete rows before the given row index + /// + void delete_rows(row_t row, std::uint32_t amount); + + /// + /// Delete columns before the given column index + /// + void delete_columns(column_t column, std::uint32_t amount); + // properties /// @@ -778,6 +798,12 @@ private: /// void parent(class workbook &wb); + /// + /// Move cells after index down or right by a given amount. The direction is decided by row_or_col. + /// If reverse is true, the cells will be moved up or left, depending on row_or_col. + /// + void move_cells(std::uint32_t index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse = false); + /// /// The pointer to this sheet's implementation. /// diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index 33386f84..b51b68e6 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -42,7 +42,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -736,6 +739,147 @@ void worksheet::clear_row(row_t row) // TODO: garbage collect newly unreferenced resources such as styles? } +void worksheet::insert_rows(row_t row, std::uint32_t amount) +{ + move_cells(row, amount, row_or_col_t::row); +} + +void worksheet::insert_columns(column_t column, std::uint32_t amount) +{ + move_cells(column.index, amount, row_or_col_t::column); +} + +void worksheet::delete_rows(row_t row, std::uint32_t amount) +{ + move_cells(row + amount, amount, row_or_col_t::row, true); +} + +void worksheet::delete_columns(column_t column, std::uint32_t amount) +{ + move_cells(column.index + amount, amount, row_or_col_t::column, true); +} + +void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse) +{ + if (reverse && amount > min_index) + { + throw xlnt::invalid_parameter(); + } + + if ((!reverse && row_or_col == row_or_col_t::row && min_index > constants::max_row() - amount) || + (!reverse && row_or_col == row_or_col_t::column && min_index > constants::max_column() - amount)) + { + throw xlnt::exception("Cannot move cells as they would be outside the maximum bounds of the spreadsheet"); + } + + std::vector cells_to_move; + + auto cell_iter = d_->cell_map_.cbegin(); + while (cell_iter != d_->cell_map_.cend()) + { + std::uint32_t current_index; + switch (row_or_col) + { + case row_or_col_t::row: + current_index = cell_iter->first.row(); + break; + case row_or_col_t::column: + current_index = cell_iter->first.column().index; + break; + default: + throw xlnt::unhandled_switch_case(); + } + + if (current_index >= min_index) // extract cells to be moved + { + auto cell = cell_iter->second; + if (row_or_col == row_or_col_t::row) + { + cell.row_ = reverse ? cell.row_ - amount : cell.row_ + amount; + } + else if (row_or_col == row_or_col_t::column) + { + cell.column_ = reverse ? cell.column_.index - amount: cell.column_.index + amount; + } + + cells_to_move.push_back(cell); + cell_iter = d_->cell_map_.erase(cell_iter); + } + else if (reverse && current_index >= min_index - amount) // delete destination cells + { + cell_iter = d_->cell_map_.erase(cell_iter); + } + else // skip other cells + { + ++cell_iter; + } + } + + for (auto &cell : cells_to_move) + { + d_->cell_map_[cell_reference(cell.column_, cell.row_)] = cell; + } + + if (row_or_col == row_or_col_t::row) + { + std::vector> properties_to_move; + + auto row_prop_iter = d_->row_properties_.cbegin(); + while (row_prop_iter != d_->row_properties_.cend()) + { + auto current_row = row_prop_iter->first; + if (current_row >= min_index) // extract properties that need to be moved + { + auto tmp_row = reverse ? current_row - amount : current_row + amount; + properties_to_move.push_back({tmp_row, row_prop_iter->second}); + row_prop_iter = d_->row_properties_.erase(row_prop_iter); + } + else if (reverse && current_row >= min_index - amount) // clear properties of destination when in reverse + { + row_prop_iter = d_->row_properties_.erase(row_prop_iter); + } + else // skip the rest + { + ++row_prop_iter; + } + } + + for (const auto &prop : properties_to_move) + { + add_row_properties(prop.first, prop.second); + } + } + else if (row_or_col == row_or_col_t::column) + { + std::vector> properties_to_move; + + auto col_prop_iter = d_->column_properties_.cbegin(); + while (col_prop_iter != d_->column_properties_.cend()) + { + auto current_col = col_prop_iter->first.index; + if (current_col >= min_index) // extract properties that need to be moved + { + auto tmp_column = column_t(reverse ? current_col - amount : current_col + amount); + properties_to_move.push_back({tmp_column, col_prop_iter->second}); + col_prop_iter = d_->column_properties_.erase(col_prop_iter); + } + else if (reverse && current_col >= min_index - amount) // clear properties of destination when in reverse + { + col_prop_iter = d_->column_properties_.erase(col_prop_iter); + } + else // skip the rest + { + ++col_prop_iter; + } + } + + for (auto &prop : properties_to_move) + { + add_column_properties(prop.first, prop.second); + } + } +} + bool worksheet::operator==(const worksheet &other) const { return compare(other, true); diff --git a/tests/worksheet/worksheet_test_suite.cpp b/tests/worksheet/worksheet_test_suite.cpp index f324eb4e..8b67d676 100644 --- a/tests/worksheet/worksheet_test_suite.cpp +++ b/tests/worksheet/worksheet_test_suite.cpp @@ -104,6 +104,11 @@ public: register_test(test_clear_cell); register_test(test_clear_row); register_test(test_set_title); + register_test(test_insert_rows); + register_test(test_insert_columns); + register_test(test_delete_rows); + register_test(test_delete_columns); + register_test(test_insert_too_many); } void test_new_worksheet() @@ -1259,5 +1264,241 @@ public: xlnt_assert(ws1_title == ws1.title()); xlnt_assert(ws2_title == ws2.title()); } + + void test_insert_rows() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + + // set up a 2x2 grid + ws.cell("A1").value("A1"); + ws.cell("A2").value("A2"); + ws.cell("B1").value("B1"); + ws.cell("B2").value("B2"); + + xlnt::row_properties row_prop; + row_prop.height = 1; + ws.add_row_properties(1, row_prop); + row_prop.height = 2; + ws.add_row_properties(2, row_prop); + + xlnt::column_properties col_prop; + col_prop.width = 1; + ws.add_column_properties(1, col_prop); + col_prop.width = 2; + ws.add_column_properties(2, col_prop); + + // insert + ws.insert_rows(2, 2); + + // first row should be unchanged + xlnt_assert(ws.cell("A1").has_value()); + xlnt_assert(ws.cell("B1").has_value()); + xlnt_assert_equals(ws.cell("A1").value(), "A1"); + xlnt_assert_equals(ws.cell("B1").value(), "B1"); + xlnt_assert_equals(ws.row_properties(1).height, 1); + + // second and third rows should be empty + xlnt_assert(!ws.cell("A2").has_value()); + xlnt_assert(!ws.cell("B2").has_value()); + xlnt_assert(!ws.has_row_properties(2)); + xlnt_assert(!ws.cell("A3").has_value()); + xlnt_assert(!ws.cell("B3").has_value()); + xlnt_assert(!ws.has_row_properties(3)); + + // fourth row should have the contents and properties of the second + xlnt_assert(ws.cell("A4").has_value()); + xlnt_assert(ws.cell("B4").has_value()); + xlnt_assert_equals(ws.cell("A4").value(), "A2"); + xlnt_assert_equals(ws.cell("B4").value(), "B2"); + xlnt_assert_equals(ws.row_properties(4).height, 2); + + // column properties should remain unchanged + xlnt_assert(ws.has_column_properties(1)); + xlnt_assert(ws.has_column_properties(2)); + } + + void test_insert_columns() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + + // set up a 2x2 grid + ws.cell("A1").value("A1"); + ws.cell("A2").value("A2"); + ws.cell("B1").value("B1"); + ws.cell("B2").value("B2"); + + xlnt::row_properties row_prop; + row_prop.height = 1; + ws.add_row_properties(1, row_prop); + row_prop.height = 2; + ws.add_row_properties(2, row_prop); + + xlnt::column_properties col_prop; + col_prop.width = 1; + ws.add_column_properties(1, col_prop); + col_prop.width = 2; + ws.add_column_properties(2, col_prop); + + // insert + ws.insert_columns(2, 2); + + // first column should be unchanged + xlnt_assert(ws.cell("A1").has_value()); + xlnt_assert(ws.cell("A2").has_value()); + xlnt_assert_equals(ws.cell("A1").value(), "A1"); + xlnt_assert_equals(ws.cell("A2").value(), "A2"); + xlnt_assert_equals(ws.column_properties(1).width, 1); + + // second and third columns should be empty + xlnt_assert(!ws.cell("B1").has_value()); + xlnt_assert(!ws.cell("B2").has_value()); + xlnt_assert(!ws.has_column_properties(2)); + xlnt_assert(!ws.cell("C1").has_value()); + xlnt_assert(!ws.cell("C2").has_value()); + xlnt_assert(!ws.has_column_properties(3)); + + // fourth column should have the contents and properties of the second + xlnt_assert(ws.cell("D1").has_value()); + xlnt_assert(ws.cell("D2").has_value()); + xlnt_assert_equals(ws.cell("D1").value(), "B1"); + xlnt_assert_equals(ws.cell("D2").value(), "B2"); + xlnt_assert_equals(ws.column_properties(4).width, 2); + + // row properties should remain unchanged + xlnt_assert_equals(ws.row_properties(1).height, 1); + xlnt_assert_equals(ws.row_properties(2).height, 2); + } + + void test_delete_rows() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + + // set up a 4x4 grid + for (int i = 1; i <= 4; ++i) + { + for (int j = 1; j <= 4; ++j) + { + ws.cell(xlnt::cell_reference(i, j)).value(xlnt::cell_reference(i, j).to_string()); + } + + xlnt::row_properties row_prop; + row_prop.height = i; + ws.add_row_properties(i, row_prop); + + xlnt::column_properties col_prop; + col_prop.width = i; + ws.add_column_properties(i, col_prop); + } + + // delete + ws.delete_rows(2, 2); + + // first row should remain unchanged + xlnt_assert_equals(ws.cell("A1").value(), "A1"); + xlnt_assert_equals(ws.cell("B1").value(), "B1"); + xlnt_assert_equals(ws.cell("C1").value(), "C1"); + xlnt_assert_equals(ws.cell("D1").value(), "D1"); + xlnt_assert(ws.has_row_properties(1)); + xlnt_assert_equals(ws.row_properties(1).height, 1); + + // second row should have the contents and properties of the fourth + xlnt_assert_equals(ws.cell("A2").value(), "A4"); + xlnt_assert_equals(ws.cell("B2").value(), "B4"); + xlnt_assert_equals(ws.cell("C2").value(), "C4"); + xlnt_assert_equals(ws.cell("D2").value(), "D4"); + xlnt_assert(ws.has_row_properties(2)); + xlnt_assert_equals(ws.row_properties(2).height, 4); + + // third and fourth rows should be empty + auto empty_range = ws.range("A3:D4"); + for (auto empty_row : empty_range) + { + for (auto empty_cell : empty_row) + { + xlnt_assert(!empty_cell.has_value()); + } + } + xlnt_assert(!ws.has_row_properties(3)); + xlnt_assert(!ws.has_row_properties(4)); + + // column properties should remain unchanged + for (int i = 1; i <= 4; ++i) + { + xlnt_assert(ws.has_column_properties(i)); + xlnt_assert_equals(ws.column_properties(i).width, i); + } + } + + void test_delete_columns() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + + // set up a 4x4 grid + for (int i = 1; i <= 4; ++i) + { + for (int j = 1; j <= 4; ++j) + { + ws.cell(xlnt::cell_reference(i, j)).value(xlnt::cell_reference(i, j).to_string()); + } + + xlnt::row_properties row_prop; + row_prop.height = i; + ws.add_row_properties(i, row_prop); + + xlnt::column_properties col_prop; + col_prop.width = i; + ws.add_column_properties(i, col_prop); + } + + // delete + ws.delete_columns(2, 2); + + // first column should remain unchanged + xlnt_assert_equals(ws.cell("A1").value(), "A1"); + xlnt_assert_equals(ws.cell("A2").value(), "A2"); + xlnt_assert_equals(ws.cell("A3").value(), "A3"); + xlnt_assert_equals(ws.cell("A4").value(), "A4"); + xlnt_assert(ws.has_column_properties("A")); + xlnt_assert_equals(ws.column_properties("A").width.get(), 1); + + // second column should have the contents and properties of the fourth + xlnt_assert_equals(ws.cell("B1").value(), "D1"); + xlnt_assert_equals(ws.cell("B2").value(), "D2"); + xlnt_assert_equals(ws.cell("B3").value(), "D3"); + xlnt_assert_equals(ws.cell("B4").value(), "D4"); + xlnt_assert(ws.has_column_properties("B")); + xlnt_assert_equals(ws.column_properties("B").width.get(), 4); + + // third and fourth columns should be empty + auto empty_range = ws.range("C1:D4"); + for (auto empty_row : empty_range) + { + for (auto empty_cell : empty_row) + { + xlnt_assert(!empty_cell.has_value()); + } + } + xlnt_assert(!ws.has_column_properties("C")); + xlnt_assert(!ws.has_column_properties("D")); + + // row properties should remain unchanged + for (int i = 1; i <= 4; ++i) + { + xlnt_assert(ws.has_row_properties(i)); + xlnt_assert_equals(ws.row_properties(i).height, i); + } + } + + void test_insert_too_many() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + xlnt_assert_throws(ws.insert_rows(10, 4294967290), + xlnt::exception); + } }; static worksheet_test_suite x; \ No newline at end of file From 03198f7e40c03955bfb32ef2c832a7d55500d774 Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Sun, 28 Oct 2018 18:46:09 +0000 Subject: [PATCH 3/6] Corrected the calculation and formatting of weekdays and relevant unit tests --- .../detail/number_format/number_formatter.cpp | 4 +- source/utils/date.cpp | 14 ++---- tests/styles/number_format_test_suite.cpp | 46 +++++++++++++++++-- tests/utils/datetime_test_suite.cpp | 8 ++++ 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/source/detail/number_format/number_formatter.cpp b/source/detail/number_format/number_formatter.cpp index 5b0d5d49..284412d1 100644 --- a/source/detail/number_format/number_formatter.cpp +++ b/source/detail/number_format/number_formatter.cpp @@ -1673,13 +1673,13 @@ std::string number_formatter::format_number(const format_code &format, double nu case template_part::template_type::day_abbreviation: { - result.append(day_names->at(static_cast(dt.weekday()) - 1).substr(0, 3)); + result.append(day_names->at(static_cast(dt.weekday())).substr(0, 3)); break; } case template_part::template_type::day_name: { - result.append(day_names->at(static_cast(dt.weekday()) - 1)); + result.append(day_names->at(static_cast(dt.weekday()))); break; } } diff --git a/source/utils/date.cpp b/source/utils/date.cpp index df98a35d..6b6302f8 100644 --- a/source/utils/date.cpp +++ b/source/utils/date.cpp @@ -126,18 +126,10 @@ date date::today() int date::weekday() const { - auto year_temp = (month == 1 || month == 2) ? year - 1 : year; - auto month_temp = month == 1 ? 13 : month == 2 ? 14 : month; - auto day_temp = day + 1; + std::tm tm {0, 0, 0, day, month - 1, year - 1900}; + std::time_t time = std::mktime(&tm); - auto days = day_temp + static_cast(13 * (month_temp + 1) / 5.0) + (year_temp % 100) - + static_cast((year_temp % 100) / 4.0); - auto gregorian = days + static_cast(year_temp / 400.0) - 2 * year_temp / 100; - auto julian = days + 5 - year_temp / 100; - - int weekday = (year_temp > 1582 ? gregorian : julian) % 7; - - return weekday == 0 ? 7 : weekday; + return safe_localtime(time).tm_wday; } } // namespace xlnt diff --git a/tests/styles/number_format_test_suite.cpp b/tests/styles/number_format_test_suite.cpp index 0b7e291e..c510e594 100644 --- a/tests/styles/number_format_test_suite.cpp +++ b/tests/styles/number_format_test_suite.cpp @@ -37,12 +37,12 @@ public: { register_test(test_basic); register_test(test_simple_format); + register_test(test_bad_date_format); register_test(test_simple_date); register_test(test_short_month); register_test(test_month_abbreviation); register_test(test_month_name); register_test(test_basic); - register_test(test_simple_format); register_test(test_upper_case_date); register_test(test_simple_date); register_test(test_short_day); @@ -155,6 +155,46 @@ public: xlnt_assert_equals(formatted, "zero0"); } + void test_bad_date_format() + { + auto date = xlnt::date(2016, 6, 18); + auto date_number = date.to_number(xlnt::calendar::windows_1900); + + xlnt::number_format nf; + + nf.format_string("[x]"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("mmmmmm"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("ddddd"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("yyy"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("hhh"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("sss"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("AA"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + + nf.format_string("q"); + xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900), + std::runtime_error); + } + void test_upper_case_date() { auto date = xlnt::date(2016, 6, 18); @@ -259,7 +299,7 @@ public: nf.format_string("dddd"); auto formatted = nf.format(date_number, xlnt::calendar::windows_1900); - xlnt_assert_equals(formatted, "Sunday"); + xlnt_assert_equals(formatted, "Saturday"); } void test_day_abbreviation() @@ -271,7 +311,7 @@ public: nf.format_string("ddd"); auto formatted = nf.format(date_number, xlnt::calendar::windows_1900); - xlnt_assert_equals(formatted, "Sun"); + xlnt_assert_equals(formatted, "Sat"); } void test_month_letter() diff --git a/tests/utils/datetime_test_suite.cpp b/tests/utils/datetime_test_suite.cpp index 85e5f186..22e8266c 100644 --- a/tests/utils/datetime_test_suite.cpp +++ b/tests/utils/datetime_test_suite.cpp @@ -40,6 +40,7 @@ public: register_test(test_early_date); register_test(test_mac_calendar); register_test(test_operators); + register_test(test_weekday); } void test_from_string() @@ -113,5 +114,12 @@ public: xlnt_assert_equals(d1, d2); xlnt_assert_differs(d1, d3); } + + void test_weekday() + { + xlnt_assert_equals(xlnt::date(2000, 1, 1).weekday(), 6); + xlnt_assert_equals(xlnt::date(2016, 7, 15).weekday(), 5); + xlnt_assert_equals(xlnt::date(2018, 10, 29).weekday(), 1); + } }; static datetime_test_suite x; \ No newline at end of file From 5a444332916ec15a2fb3fa9c14ca9c0dc628eaa9 Mon Sep 17 00:00:00 2001 From: przemekmirek Date: Thu, 8 Nov 2018 20:47:58 +0100 Subject: [PATCH 4/6] Fix relationship sorting --- source/workbook/workbook.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index fcea0b12..dae61446 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -1617,9 +1617,9 @@ struct rel_id_sorter bool operator()(const xlnt::relationship &lhs, const xlnt::relationship &rhs) { // format is rTd - if (lhs.id().size() < rhs.id().size()) // a number with more digits will be larger + if (lhs.id().size() != rhs.id().size()) // a number with more digits will be larger { - return true; + return lhs.id().size() < rhs.id().size(); } return lhs.id() < rhs.id(); } From 36d6b9823dee772702bcb4c50b4ccde58da0dbfc Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Sun, 2 Dec 2018 02:38:58 +0000 Subject: [PATCH 5/6] Adjust merged cells when moving cells --- source/worksheet/worksheet.cpp | 35 ++++++++++++++++++ tests/worksheet/worksheet_test_suite.cpp | 45 ++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index b51b68e6..23c9ea7c 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -878,6 +878,41 @@ void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or add_column_properties(prop.first, prop.second); } } + + // adjust merged cells + auto shift_reference = [min_index, amount, row_or_col, reverse](cell_reference &ref) + { + auto index = row_or_col == row_or_col_t::row ? + ref.row() : + ref.column_index(); + if (index >= min_index) + { + auto new_index = reverse ? index - amount : index + amount; + if (row_or_col == row_or_col_t::row) + { + ref.row(new_index); + } + else if (row_or_col == row_or_col_t::column) + { + ref.column_index(new_index); + } + } + }; + + for (auto merged_cell = d_->merged_cells_.begin(); merged_cell != d_->merged_cells_.end(); ++merged_cell) + { + cell_reference new_top_left = merged_cell->top_left(); + shift_reference(new_top_left); + + cell_reference new_bottom_right = merged_cell->bottom_right(); + shift_reference(new_bottom_right); + + range_reference new_range {new_top_left, new_bottom_right}; + if (*merged_cell != new_range) + { + *merged_cell = new_range; + } + } } bool worksheet::operator==(const worksheet &other) const diff --git a/tests/worksheet/worksheet_test_suite.cpp b/tests/worksheet/worksheet_test_suite.cpp index 8b67d676..1d9ee5d1 100644 --- a/tests/worksheet/worksheet_test_suite.cpp +++ b/tests/worksheet/worksheet_test_suite.cpp @@ -109,6 +109,7 @@ public: register_test(test_delete_rows); register_test(test_delete_columns); register_test(test_insert_too_many); + register_test(test_insert_delete_moves_merges); } void test_new_worksheet() @@ -1500,5 +1501,49 @@ public: xlnt_assert_throws(ws.insert_rows(10, 4294967290), xlnt::exception); } + + void test_insert_delete_moves_merges() + { + xlnt::workbook wb; + auto ws = wb.active_sheet(); + ws.merge_cells("A1:A2"); + ws.merge_cells("B2:B3"); + ws.merge_cells("C3:C4"); + ws.merge_cells("A5:B5"); + ws.merge_cells("B6:C6"); + ws.merge_cells("C7:D7"); + + { + ws.insert_rows(3, 3); + ws.insert_columns(3, 3); + auto merged = ws.merged_ranges(); + std::vector expected = + { + xlnt::range_reference { "A1:A2" }, // stays + xlnt::range_reference { "B2:B6" }, // expands + xlnt::range_reference { "F6:F7" }, // shifts + xlnt::range_reference { "A8:B8" }, // stays (shifted down) + xlnt::range_reference { "B9:F9" }, // expands (shifted down) + xlnt::range_reference { "F10:G10" }, // shifts (shifted down) + }; + xlnt_assert_equals(merged, expected); + } + + { + ws.delete_rows(4, 2); + ws.delete_columns(4, 2); + auto merged = ws.merged_ranges(); + std::vector expected = + { + xlnt::range_reference { "A1:A2" }, // stays + xlnt::range_reference { "B2:B4" }, // expands + xlnt::range_reference { "D4:D5" }, // shifts + xlnt::range_reference { "A6:B6" }, // stays (shifted down) + xlnt::range_reference { "B7:D7" }, // expands (shifted down) + xlnt::range_reference { "D8:E8" }, // shifts (shifted down) + }; + xlnt_assert_equals(merged, expected); + } + } }; static worksheet_test_suite x; \ No newline at end of file From 38afc61219b3053da486c96a3d52759523cc057c Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Wed, 6 Mar 2019 09:45:08 +0000 Subject: [PATCH 6/6] Update the format elements when setting the cell style. --- source/cell/cell.cpp | 6 ++++++ source/detail/implementations/stylesheet.hpp | 7 +------ source/detail/serialization/xlsx_consumer.cpp | 8 ++++---- .../data/10_comments_hyperlinks_formulae.xlsx | Bin 33351 -> 16965 bytes 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 5fcf6030..8dfe3c6c 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -846,6 +846,12 @@ void cell::clear_style() void cell::style(const class style &new_style) { auto new_format = has_format() ? format() : workbook().create_format(); + + new_format.border(new_style.border()); + new_format.fill(new_style.fill()); + new_format.font(new_style.font()); + new_format.number_format(new_style.number_format()); + format(new_format.style(new_style)); } diff --git a/source/detail/implementations/stylesheet.hpp b/source/detail/implementations/stylesheet.hpp index 0ec45161..67ffa063 100644 --- a/source/detail/implementations/stylesheet.hpp +++ b/source/detail/implementations/stylesheet.hpp @@ -51,12 +51,7 @@ struct stylesheet impl.parent = this; impl.id = format_impls.size() - 1; - - impl.border_id = 0; - impl.fill_id = 0; - impl.font_id = 0; - impl.number_format_id = 0; - + impl.references = default_format ? 1 : 0; return xlnt::format(&impl); diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 3ac9eb0b..9a05603f 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -2339,7 +2339,7 @@ void xlsx_consumer::read_stylesheet() } record.first.border_id = parser().attribute_present("borderId") ? parser().attribute("borderId") - : 0; + : optional(); if (parser().attribute_present("applyFill")) { @@ -2347,7 +2347,7 @@ void xlsx_consumer::read_stylesheet() } record.first.fill_id = parser().attribute_present("fillId") ? parser().attribute("fillId") - : 0; + : optional(); if (parser().attribute_present("applyFont")) { @@ -2355,7 +2355,7 @@ void xlsx_consumer::read_stylesheet() } record.first.font_id = parser().attribute_present("fontId") ? parser().attribute("fontId") - : 0; + : optional(); if (parser().attribute_present("applyNumberFormat")) { @@ -2363,7 +2363,7 @@ void xlsx_consumer::read_stylesheet() } record.first.number_format_id = parser().attribute_present("numFmtId") ? parser().attribute("numFmtId") - : 0; + : optional(); auto apply_alignment_present = parser().attribute_present("applyAlignment"); if (apply_alignment_present) diff --git a/tests/data/10_comments_hyperlinks_formulae.xlsx b/tests/data/10_comments_hyperlinks_formulae.xlsx index c989dc5feaad03f2ea2d4050ea5af5087301e021..142d3d0b8916fc8545168641b98bc3fb618ad5ec 100644 GIT binary patch literal 16965 zcmdtJV|1nKwl$ihqKa+Xw#|xd+cqkyif!9AE4FRhHf~n!bI#hU&i?M#?%z9SoBA<& zoA1E;^dVWvFTh9u007{hF93kO>!*DqKmY)IFaQ9=&)*t?Hr9?t){Z)gZnj1aS~RX! zmVHW+*4=b)YY#|r4aoFHQ^FvYSt}^T?Yy1I&E2|8{%S(F$o4asFq6k{ z$rXlJ=P0S&y4Y`cNxXxFW5W2QT-++g;i4XaOFp^0oNETXsYVef50O$Z%J1@~lXX~` zy*2OZESm#Sj^xP_0#%R5y-&SFI{pkWig!%i^F zvNU;9ebl_d(r(SlBkJ&rZ7?$*Qw!U*bJgZIg3iJYYAn|kY~59}&Wyc>ytD1-7Qp+7 z7erIj7Ezw(#z9sZDomsr1_MMJ8;9pCE>jL0OtTAp=};s-YYS>{CBV|{F1-pCd7Q+^P;Q*b zFL4#A!`l2Nl2>aEDTuv0d6H$1E z$m2d!S@Mq(KIXJJwbcrT4vkA9Q#rW2jYlUw)^km&)Q4W;x^g9*=oUz6nFl9^v_pIp z5Q%NFOu83I&E%OI?gf!p*(yU?4ZW}rd1frlL;HKke`?^QcYep=(=Q#q006*!YQWIO zK-S*I)`3>f*7h%_OphJ;%PBwAAROm)!iNiKNT4KJ9GXMGf3)mG(o0ZHJ>i?Bqr+*| zT`H#Ja-aO;VlM1y6df`GNw=<4B0RSVuST$67De`J+nwGSVY6L4o{tly@wKLS5?XUH zA0j5v5TQTz_i?<|YOS88BevCPpHyQJP_HJ<)AEbN`<$P=Y8n*eV(978@s6NU(o>3J z`9r$!+!sV~Y1oB<3>&U6_B%*tGXb?b7T^>4WO}C?5)N_%w$1?fuRsI}?#zh8dH^_9 zW=$aC{lY~Zx=66whYEPW`MIu?X$UFieOk^v>a(5G1kJZSP0T0&0clQE)X=+S_vV~V znJ~vdK27QyQR*I65$UZvkix{98a#**@4Jo4p4$yqbg%`_zmhn{OqpT0N8VN^ytE#i9PXY4- z^~8ML^WL<)+4wl2<@oYGuEVbeI=;Zk64BiP@ye1;>$n^OsP)yvSMRNA#1 z&gP+gj`o=ROPj}se7?l7m=R_7CIa}YHm-pc*N-;fZ6G{k9x!4U*IqeOJ0$t9bhg$! zv#$q@fq+P`DTy}lzkE0K@!2+m(Kh+Br?}cod3eqZWKFg{04v!t147<|gkv~iu1hoG z7{DV&kYraLEtaO!$Do{g1PcX#Q6)zPhlgkvCTG>Fr%l7Fhtw4qOQq&htt{;{oX?yc z?bmBvHns@QMI+r@-JhPHJ`ngIxV(6nsJOPf`vxB=RVs;zv}GhZ+$bquoX68!AFgpx zxyY&9pUaxsa%xIi_LZ!#%k%H7G(1F2P}_Yrdp0KrwxVT5hl-DA8Fkb)jGNuFYx4$HLgQAJ)xKM?jL3lU;pN z+W?Skh=zh3!i(Rfk*#_~kdoG=mxM;7?{7m9G&8DHL>s{haT1Fen`z$1lG3w*rQbsG zfdcKKcSpaDAPV#846^`3i2+JH*>iX+w*ZIw!gX^1Yc59!`10wa8M)$q0mSO^`x?=n)j4B5#-&cEj<9?#(W>y;ap+cQ|EnNVK=j^xoR#%mwMW|glK=TI0Lu3-Fp0h zpgrFaN7$yAQ(8|r|OtNz5c+Zv{S291~5b|TQJH$EzUsI`R?Ku&+x;i?D^Sx%Ac$-BY%;o2W$c8W<*|X8}t$hqO5U`Fe99$s? zifT}VKFIwZ^)bGlRc1ULLXQ_tNopTSxsL-+>lB$$_=qhe`>zwbtpl;9J;37sE)CGeC$)8fVd3+rxPK^D`Oxp zG)PT2%L+Ms8;od13ne%PBifnyI1d!~JR75Bl&i*!$IEm4D=J3vMOu4ip=kHadX|U| z5oEbp`Sd*o!|O$0f}Am%Zh6G4&<8lI)+(hq3U?iZTZh@8X=XumQ28Krs%1cu<)?{E z_yr#;ZL&2yU5R{=JPR8$8y4at-%jwK)_e+Ls9a8lwC8q_B_n$mom(i_wV}bJUct}6 z02Q@rLTW|)?q&(U6JqQ1M1M=fB0WvB55X!;PZr~?x2bIJR2Favuzp!iL?>{AE+Ya~ z&AY8ZX< zb0!-_!^+V+8RB%QQ@)a_yr_%GigR4WaMEQPguoJPHpp&46X1Izfds5c3Gn?WW-*eQ zwwUV8*^~-Z@|~9#NNKEJo+fK#42#2YD8x#vHbfh7@GV0)Bm6fS+gC;vlL4}T7(>h&2-vndN?aY?% zHri!dJVB%=!3HwROP{7bhG9R%N1?MSEJ-8Kci~z4dUS+^vB~!YIm5_#$3|PZg3X)g zF=S7^1_r2?+)=H6KpIFbgwJai^@YuBTXHVE=HjTAzd7KpppmFz!V{97hrpfvWIP8i zHYTtdY6()k;EKyFGlNF0;ZiklX`!N`q4~|Ef`5c7(_PClF?O$t<#@M`(0fWvOJc!R zge-3ltU_l*`KS;)67IQG>x^P7PT_6z?S(LGr8OhKXlk$U>yJRnSs;Y>9S3RpCbx{nCKs~z%YT=WK;~VXn@e0wGN-2b6x{?WMTq6|>F?Hj|@;X5flE8W0^Sph8J7#gK$GzV*LU>=EwO8i|QgrSglaEGU5rlpo)dTnoF|rr3 zsF94rYj`wAB9iVK!VVi&XZE$(*)bE*tna`Q3J`mm-s8UTB~)Xk@kDz{X|B`=o+HbH zx^=D}#T4l??@w%fO{h}db~Tc3FoS3C9^^P*-BFj7gGVt;DK~gZzBNLU7ZS*ch^Pe( zQ8wsJ)vh>;C^)NKSmY_Ikk@a{-Yk^YMK5SSq}jY==z?#n`@nJ73~v8elgT^kefVVt z**m>J-}sH_p{&!jElNpjZN??ZcR~I6PJcGiehA5vS z;_*wpWm9xN+;&a^KNqCn)LJY9^(#0atyOi|1HcVzBV~#r+_wfTa!xB%k4dewVXcP@ zmZP32>r>*ZY*v7xvo98mLOk#6!ta6TlPYM_S8~;gAn&Z;sXMN`_qWx<=?5;f?4h4TreSKD?_Zw-BE5(vyn$ zk}fJC*Aa{7Ye{fg!~hArx3p;c12{THq3hDoiO)}1#Z1S^Q4sIPU&f~jX8Y9M<#bUS zm}A8+^!7AFq)Ktk`Nm%8PYsaUJN8_Pn>y>mANF_cgEDWkgDp#hR-`U;N$ zI4LKzW38XxQi4f&mKF^5^`jAz|B6<%iJP2Q)e^BlZE~1OQY< z10T;>uG)}b6w(|vo(==YFj&jQN*1HCfP9Kul@l3#a}qzB%OBA^&vD3c7%81^lUU5n z`Dj{+S<-6l$iFVti{ibX;DzLNhH=(TuCBVO!s)B>Xv{UPl9-%kcI0k2PE>`tf{8ke`y54{j8-+-`mD&bV_qCIE7Y$Zi>bZymj^ zp&t7=D5{=$0vjsPcZFlt-F^W7cZWZVs)fS%U+?4cAIL z8PdV|Blx?XV^Z`WJg=5NK&R(3lGvI$usSzAYT}qyUqHEb~*TI#S4^DVTSVxL3lHc_hmNmTqO`riI< z*&q&)!_6`tG6S{}E}K57WUi+{Ms@L;F1TAj-yqEan_tYHI?Z{jqjoa!rW1{!UmaFg zQhl1H+QnF4A9H!qR%MpWh`JgPB0cm9bA1P5P8m}x^qsdp_iwX$a~lEa3~det(coh)ME5T z20CGQ2JWY9p9Im@TUB_}AKo7R$U8F7L<)UjA>ULVr?eZoe;SE()+Vzq)wfDqH~ zUvzjTqLRmA3miR9CSEF9VZXhGV+st=V=Z>M#nIy`(*d1(w-p6?KeEn?3B_cLcbFC| zbU*@9D{b)m;x0zi?0%6iQn3`%>I+WLGpSP*0=BeT2{->Z)3JNY+2|xQ63L3^z}^9| ze+Jr71;|3dn*ws-r}^JdaTVNtvTdy)QK!f%%wpM&2zagJP1CuFk`?j ztvP}6h$f8QaU`tA9;LhP-;R~PTKCIEnUX!7aEUO~mmetXCz?DwsXQTAL3ibrsadN3g5RHjIpjn%z&9}%!L66!vSY%8^BQAo|WYaUCO#@m?duy zUYM!0qQzfnj4lAwih_ybh6D~-ex-iv4d8L;*oZApP?EtKTvH{rLeajU4@X`@VSQJg zxKc@9Vsu)&2qPFrn<=q8J{Qlv@ww;sahwy}k3r8%?G?@&TSqdY-5GJdHO0};8VV1q zR=3H9FEq{9=iI3)rjBIjbK1^am@2o#1kL@9n|1?h*@e3z^)TfyJnDthH(`-{n7&|m zs=oI;_Si#f6MU_?C0A)DICMO%uDy^Cq`Bjtc{w{+fl4a+9d`oa_H!W7&WI=l?>r0aQ23ZGDbTx-yz;Lu#`?n})sU=N|Eq&jbDj~&Nm!Is-Rn8S1 zbL3m#P4}}ef$Ab zfE>YF2281#Mb$ZKt<`!T~@QS5D zYM0dseQ1+rjo;aj`KylIwy^uIwtFl*IdiNY!kes;3j5t-zMxr74%_;^E5D|3o7KFx zL#9f^!c<(KBc&&^BPDLlw-2nZ9Ln$B2spSTGF!w`%a1^B=csJNJ{aY?j;)q4kP*BN zSF%49dyrR}UQYCaU*RKPaODVmdVBfHBre9+!V;Hs<}yjy^(F7mVAE&B7$THgT+TrH zsa(jm%dSRCT{L*fXr|P0Kwiniz?+VwHbBWN`TIqI(Y^^rcJjf@92+o=eoH|c; zf>gQGVuJRYO*|rqBj-jFr_h0?v*Pz_yor*6pS%P@8UNrxFZph$kn!l+yHw~1&G-zj z9Wv{$Hpi$-{=OJE=Lb8EpQ6}{n*YK~nb$jFeb4S*FJOK*M+Y#HHwSE~I{1y^N8(NvqE+82~G5Q5{h3NPr^+6vGm$*l(vb>2YEvi@xTk5 z=n_XhVoSet*>#KnMebdtz%|Z*7i1qW^pYKEsXUi^AM%=bJT{i2T<&j|EvxOPgy>zl z2yA7Ro*r+W7@B=8Y;mO!X~XNiU%I;ElH<*8^#yyz--zVL7*Mfj`Wd9gMM@+2T+y_m zp7DNYkYD+6SK>dfshfAVDQjlZbCFk_lKUeQuz1`z^A!LOK@PO;cy@HSzp7gV&LX8J zLbOAg(}XgIt=drl_mHw#BqDLELLl^7p67&TRjGs1qhKTXeOVD z`1dC7Tq&sdYRDM1JMGC#DS5W+YKgdxm8cnU(>)Q1dZCA(H$$r4)2ZKmLoI<=f?Yi- zn-gK5RM%TiY62Stu_Ib1%CoVX8h@GRH!P*=bb<#6e6T^*kx%WmX4RnYKAq{IOttrf z$KY(21+eEq3CIhv)2uQYcg3umIU#UiY%=y&K{lJ+;oiy-bq^UHb00}yT!<;pk$?#^ z9PFQlpPT|o@euEiA*Zhyw~gM0CND`5V@0X%uPqd)gaO1*$n6LBdX9-&ie`zW+_Ca8(gsa_M zo$7Tk6AjTKw1_*f9p9C-U?~-=XoYtclK@gG?~6rM-nP!88hOl8R&Lo3QtJQNq>F1c zDpj=`*ynKrvp^~$O4x{yOQ;lqwRnA*M-1g3sEYq<3qX5*ys=WHg%jIda=?3=lf+@-hBxUG(cm{wyb!A^@0 zFJ>!*#fY+YDPb%vv zRXTXoy^yJhDbIBuV;dh?2)T2HQoxY5P!VqUoK+nE9^r56*dWaz8tUt_*pwY|Cl{sK zhL`H3Uvf0#y;NC#fJ7Hh0;48xHznJ234OvJ9-Wd%%zR5KDoa(YVV{#SuXN^s*Gl6g zPn%2_O)&PJoW?Hu=B5JoQdS%L(%;<=G~9Rrmp*)JJ7vZdwi6g_D_4PhjxN-kIhV=E zIam$3<3(}o>E+W3lBQuv+}oN9G8Ui zATk%gHHaKddW>w~oK?ulYEv32E*|leoX#9Cbs>r-o!z8W7IpHYnqT&nMs1UUr%{B^ z9jVEYi65{+vd|iw3oDOE#j0X5of;j$&^!COo7J2|l{iN|CMUohhwkm@+RyUs07f2k zy~@mkWzm6*jr^SjmGQ0#U%%k|9MeEvh)kcOQVJ{%!MI*oCdTU3(`n5h?}0ZS;lpub zAHBcIQyuRMhExQtjvT&9^U2?rAU0b5ZV4?jN`A=}b&@?RdjsvJq;`SZbk)GSI@Y4Z zO{aGvcWibf0lsU|U7?f7W z3w0l(4(8>eQ3~JPEY+6_N09)H^n|^sgqXFsE8>5*51cl2&Cc|fAphc%(X(JLy4F4Fo{Y-kH z1MUf$WzXH*Z5Z2FqQhS3C=L^Ziu2Hwd(oa;treHhSgH_wLD#QiR13}Y`X=;9=R%XF zh%L>Ng}0QwRFt?MyD@cxUhgbx2hiyR(Fwgu{rz;g%F&5rztymkEx)octh>PKU;!5| z#7!m|sx(FWp*f?V9Pi{{?y$jmFThyXIe8MN*Pc7rlJYXR!n`T7)dg=U2 z4lfbm2Vu#6WD`EP>r0Vjn@n}cf%A+tw~w@R_3a@JL$z8wEK5ANg zYcShrE*ZKstI4&*eZEkrTp@N(ZB^%ze0`}ycB6!)-h_j%Us4I|V&buO1V|BM0jt~d zL|%8gRkLRrd$m}os>3``x*6}6oY0_`Iy2p1cr{i4p*>)6pgim-_fpZn!AP53_Okh- zj;KRKLXo_6iI53<8 zALIT?f8Y;dhG`v9ngDaee+a>KnXHgjkijivt2_Dnwqbl)XtiIo&?Vp-} z0hd3DGJCK4s(NCz$C|AZ6HV4U+tL9o*D;MR-~n%+OoV$3yxPceql~1 zTIh1h#UesHo}9-8eQGC-U6wO%g&JYxCTF};6o6{ryj+Vi%wr&+6kY_lZ|zi#GS$vJ6>Z{h?)jnjM!~p!M+#lq_FGQ(^5 zE%4;92kXgEI^oL;I?&?qr0Dx$V_%`cz`|IV#^}65uYUaiB2buQu;tx>rTO>xmX)b~ z`i}L1gZ@m?_neR0MTt1E*;VC`)`8Oop+n;FqYVXX7e`=$l|HZ*5XUfFiWGu_@S$V{ z=o1ex((wW$X{?7KxcQf%H9EQtx*vkRkw4U61E_!=rH5mWOgUTG!5W^~A-DvoC($XA z^a~@+qDh%Hz9k=^pP)Z89b+bd>P1UmegOQlG3wc1LV@tvxhDAR-NXNTW7NRL-srE^ zb$E=FWG@|D(8U{a{sYS!pPFDJ7_tlshzgPoe)2hJDhUzc+S^0H(wezkmqF5j*FN#L zG3dSJ?%X+0Dhb;w?K}V6)v{RZoa_L$jxT+h`@vnXoL0z!A9Wh~Xg($yct#mI2q1&N zf+8e(=Ees0@(?_fV?WOP`D}r>$V2e`s99h{@ZSl z6L_;=TbeyVo!JONVhLEE@7@S zMFZTbKe~WTc8(hc5}rQK*7rr;#c-WtGyDR;FNSKO#*dta2^(4Y90z))At#7c;Q_)C zO&CiICt#`raen45EUE?>!FiKQ`D^2SEM?K5nmj=>>_s^Eq+%VPIcO7k(|X6P0KrhG z@clQnnA95UwL!x5uV|izDsQTU2kn#L=oBe(*Nj^OKub}B+DzGkZ+i@_vpjrQt+G>3 z1X@t9m&k-lw_h*9GEV#JzFDNbBI0x8zec!9iIruUq-lY2oKs1;)R0 z`>)xOf7kHuIg|Do{=Wt+Kqk2ht2_ZfrxS$ZtISv}SG09^zv+keHgGA_uXdmm5s770 z{Zv)Eq4wcbvwz~p4uQ-l4=wY48F$Dp7xM(sH7FL<4ie+JV8Xv6bNfau#N=W5HDu2G zi`i;+BV_)tUHS4{ymYI3`P>5jH1}P$Sz7jkZimOU{T|BWSF?!(F?;fYguLm4pIc33 ziOotqQZiS%GW1(+DKmsmRL}`Kt`LP8dv4O8BiV#FScPr^mkgzy`Z>=EF*j#u3=yPU zsqEaKoHxc(PhIvA@7Tneo+D@5u>Vv^+qWPrF;D=2ccOnyKz+KKqp6XV(ZAm5|8luA z^|6Q*7PyWBa_|l85Aho8UO>ws>E%-re&kuTrkbHrJy#ThM&uard_qta2?cSJJwY(a^iuyhb}Z6n^Un(%u9j4w44glfg3LBtoQDRVe&YQBPD)$U96=egw7|MFEWhx|QIf$#ZI(*4q zp?s(JkL2sEp|)~Tb0qnJ2f@%+Mr4dyey8w^MQe~Me27rX58a=6RqAl9ISbcQ?Hj>g zp8P(C!7eI@4+ueWFNbnSa+E2df+xmoS?V~YpK^m9WTx6v!@`a?C-Mc?Wng}hB2qiR zU;!jD0g6ICDffMlUMU2DtZ>R~+c90bG{jgVb=*27oBX5H)LvHF;Itt5+iAHt&3AhY z1y;_r1}nv>-K@0!WvLk}80=gP;aGowZF&sNQxdZjHfuxEj!d)K3=j2XBn2`LJ59oBu@m`qtU79b8TII#QwEyrIhJU_4 zu=#ktvba5{L(Tpfda88SJ7W9*n2)F_Kmf4O_2XyG{#}Yf?!9Xc*eye0@`G z1Nzr2qf0@gPCcQ!;4IDidmx@^{ew*+S0PTS29mjh!*v;E2QxVq2YLz0L~EI@BD`P z%8l|AcZ2F(Fq{*~=^Jz3bNXvo9;D;{$hStGvCN8H$&<7-{u! z1e(XtE3$**bVnllAcJ5@(aB+t)7R>>c{>_fU|`W4lD6dS8&6(GiG&(jA?+=eIm@Mz zoH!Zq?Wv9#9bxq2%;zJmUC^9Hnltp0Jh(UICY(-;RX57^K?yf6ZJY@IQ)I1a%(fYc(suRB}6eFlwQve6U5Uq9esmwZpAB5rx{T;lqYn zLu(24P8b)1VzuztBLUDOFb;_}#GUyvlzSwlmmd48nAYc*$%qigU6V||wUqK?eUApw zWsRnnxxkmr^7VS_Z3yeBr0gc)mJ7H>tTsZf{#eDXDD1BXo8jy9r<)}RiY>Jo8_|O# zOI3IGp;W*#CQIN(EiFSZ~N>mTiX8eh9}guLR)s9w{a9%=KhN@Z5G;Ow)DZuLeYh)_2e7Y%IO^` zt;Hb&GD{HlN>zV*%UsP_iym`6a=UlCMcs;EF6U`@_}0kXYk69IMsU5)wOX^oj?F(0 zo?uTTiiuC2vjPkNfc7`faWFM9a&(~m{lW0p=@YLw7O_kR*Kwhs%A-s{0$5Kh5v9zp z)U3o^XR`AR0g_YNN-&}EqBj6w*cpVh%A_L`eS+vLY^@ceGnTa+BXMf^g+*^P7=y`$ zaYn#DdRldi8^@|o)8acSU>Oki4IPajru9>v`Yap+#*F`nXT;2%W@`ud6GHtMo-#<+|}5j*ILfy&Iwyo+M#ly-zp8!FUaf+e~M(piHl z$j#uPNRhv<&&iQ_M^&vy7;CSimNrD4)YQ|13(D{Di0p?_-CR3(+gcK(lRwr%V z=<1_*n0Q(5%1XR~47%g}Pzw~xh@~O=5x6ibDAeAck(DCtgBOl&&jO!=W6+mlWvE`K zBVPs+z25bsf-z;E-v;aHIt!#>d>rvS>>@d&xNur5KdXJU-!0!Y;Zm{mIWGa`9BGfU z_@r8X)I;z3O+5Dd=bi0WM{!zJax+>kai6m7*t_6Jz0Zrl(2iPlQ0qjJRK!0+;#@c4 z_5M=}SD)JWYwGutiy7EhS$)o1}?49#Aq_}Oa*GEH|5`v&^c4==N{S@{AT7kW)T+H0pSv++x+ONKw zv2KN!9T~m&!&`eHB)!<=P5sD{AqR4X5W>n}h2>PPK)lrARq5=<3VS$s3ByGmXE zOw_U*!9XxJ>0Zt5HX||i!;W}CdlW?4H3ZcTCYbxdUi{Xb@=|d^ph@O_JT4Rt1&a2A z#AA$+xZi<%iPe!BhE7JoFvL>LZHb(;Rh;sBrv!08ok|>%#0eJDELq+n5@a~iJx$50)h|>g zn_=9P&A!}#EA@Ii*ILxoHC|5x743&nAe51KILMY+*uz#>-vS}DdQ)VY@53&*!ny;^ zK}~fD1gxkb+p|vgpxSendF*XWm+E2My!x(4d0Ajxdn$_#I3M*82v0GYt|PDa>Svel zIC6JT3g49mP*W3SD`&onA0Wnj6GQoR6Z*Bw#=Sa?+aN+LXz>&$PF`0PIY=A?}HkyiCYb@4OJ%>_YRQZ#j@||2k7exW)<53Xr9S3fFnlO+aI}R zP9Rc5&!>Z4f1YuFEu4G?vxBLgy^*1Uqy1mr`a7AAl7#X5tc5&e6c2_bRg7JpW4G%|wV^)UE3aaS`$+1fIu63#L5i64~4Ki$+?Rgt!GX z^v4E3rw*agfFz9HD|2qo4>@2rX;*r{iOA&dZ-nfZP&5buv69(w?%>+Z&uSzgxk6PS zN;*HnH#M>;7R)6M%TPa1hb~=4kIu?Pm9ow~6*Qka)r;zv(cnCtP$?>w?{DRsmfsHh zW_sXL5sID}JX$v4DM+txsq@e1Y|H;@s`VM22cH=w^nYEnqnoAC@2jm>(y~eYjK_=0 zs@IGZ!=V(R$sa_*rL#)0(?8lV=z@`b@C-N>>ppn=yGR7*D6BkMGY>Kxs-;wqgQ9nm z;h@dOh0wcd=lf8y8MqN6Ml{sm^cb2Iu`G5<5Gf#qZIv6O(z1o&JcY0n0I9nZ3NHY+ zRJBU<6C|{Cr4WaUtU1a63o>Z0kb-9vhvfI4=N$=>515D*1TgFP*#dnFR|aCEAV|Z6 zsssZbSOEf>ky?O@%K{=cyTdFMRzjmTgjNd(*e)Pm3)vf%kjoFX(fFb89~9>7 znSztleAS>>1Z9DaCWGJl`!@#ltMJli0iFEw(l)Eo^Jn_Jd6~V-B(#BF%|2J#%b9%n zrocX2r{^p`ez?+WfVJLPK7B7UPMtfa)1ZE6?ZICM4%Pjr{eU=YOrvciW*jV8Shrw* zRs|LvSMUH_Q@|u3?5c2uLm~JuY5nyC@=rh9U}T6;|MWxI&r{<6KrVlmHsY1WB2s^o zOIhji+5V@sIRXT7g7Or>Mx{pci3s%0kgi$hn6VWXOQ6)aDu^Fsu3Q@vVPkMOdCSL8 zovyUaWVfpmVdP%~m`3ml-SH&JY)PXj3PBSoh+7o-48Vp#&|!Z(5EZsvQU>v@b>qhd zFsh0-jAYXx2Ltg#CkBqY7F#r=tqCM5)UU;7CXGtwE!uXCO-0W$(dLp{G47?27aQq= z{^W8qPka!=`D)aWSgV_kB0m-G+kAoc)|Y+|NIyWp#PNVc`6p)wsPu#3Rwt#~ksBFFQ(5rnBAehPCCq4lB*^u}fxHm1G>Uyk&Y$Rs9g! z7Uvy`zor?ZW#mJ!Mc~&*kdE0t@j`lR7)o*0R;dUuu&x}u*WS^)n{3=Coybq_xRr$h zLD~cu7Y+&1gn~<^bhDPoYn#gOZF88~&7nC=h$NhU^|HyMXQ)&`kMQh-fdz9#2#zbz zR+I;lAC90DhHVqmNoV_oZ`P3=+UoO9e~d~XF8}zvA4Yx_9{*o??r*RBuL@-QUlqvC ztMtO3*8nWpxL+hp!8qs~i=Tm14z`;Xc}93lpYNFkiufstO2|^rV&5M$G=F7*u z2vC5Uc$p7pu#e_{D-i_~m*vYO#TEujtCSl7Fo(w2v*c(`v|A-Zjm;?S!TO^?LldFaz@|kaZN9UW42d-z+ZV=an%m?q}danKaHUhwq}(O zE$T5Kw!aA5-H(akNz7sPev?`?Z~+`_uKm-r@?NButL z`Y<5^*3U2&zTwAwMhLUnz5X1)*#T%GWCDd{6 zx)h}8v2{UIDIsxh_y3(4PZOmoOxy8h8ZJW?cam3jGITg+xoB%+YTLx8n>Syb+G{^` zZD#9lIaLPGswEJ)(&R5EWaMA%xs{YfQA<{0?#-&3?ZK8Q3W#|~4T+d(`37MGTF$2i zsscl2)A%bv47qVAQ`1%9AC7WFv$Gj{odYnL1 z56) zyWogy2{3bN$YDABhQmf4#G3sOSE zs<5ogDjni3RG8c+P_U`R@tMq*vdCI4HNOXx&Fe78C@<45pJ~yhjZNov8fH|6*_TN( zy8BO#2ndAqn*{&ot?SPle1gQzSMuB{Ks0-pMZZBVEzV-p!p5>k8;eP(tnmF{+6zx{Vn}}DpdRl^k?e$H;@Ly zZ=nB`NdAfNXCC%9g6!wQ@?WXw|72x|}L#)-`n+qT`YlX>gA_+~EV2kd?G)T-Kh zt)(mn0f`9)1_lcz8s#cq0Fgly2Mz{i2LlF%0Y(6(_shxA-NMn`NZrTT!p(rm+reH# z9S#g)e4$pi7YnHC;f(+W4*B@s#Q!WA(il@5WI^pFzeUNYD|eXyCtaNVg&-qMR6-eD6J%4%?GTetR*P0}uH67#2r`bShiJj?qJu3D~H z$iQL7CtIejuM~Z1`7+568F9wY5SW1nPL<`Ckwsa}3=XQC|6&Zr%Zm3$B<1 zhC-WcwdY7$9ZV+tMj`e_XvK?7DR{O(PsY`AdD7xZ4ZNGN{2GPdZpX^`mv|3eZvk`q zX%A1x%Krp!q&V?~*H|6%He00Tq)53IS9nX;>svm3LCv-AH_ZTtUI%~R`l++acM zMmZIR?cjE8@WA=8F_h%FYBKbL!eORTeniYd233cAZAGaCuQg=D7B1>_@hYpyzFCN?JZfrzUu01BFXTI)^cn!P;kdc_zb5q<~~!h;v$NzBC;s!^mHO zMa3Z+9|k&dVM(#r#-rbmYr-eG=fM!@z=RA!8rP75FN}PT{AKuDMU4qAyjZh>Vw8lo&{)pDA*zz-%W@+`gShUFbLA zldwCrow3PMFYcg;Et@e@RW>ZX^z=IYixR;o%+L8JG^fvH1DVhRWu<$@QaBoECwO>@WTuqaIMfvU=k1e^ z=bd-|@9h(QzfIQbHf|P4P0MZ09j|Gx3@gj2W@};_1hCBHo&ur1J}|JA(;zS;7=hWa zckds;(QqUvV101AG-0sLae?B*KTg@AzD|HbVGMmQnFr)xs5cM5{P&yEn*hoSIHg%2|onqe6X0)dlqL1sWx1kc3f*5F!7UsxIN~&UPeS? zo&oQNRhLqXNrvhNa7O(;G-%0Taw*(I!go%jUlgByyEMRT$ex%_>u4~F^JZB+ZstvOUr3XZ z1>0IQyzDX`{QHL*p2#jllAtQjYL5s^8nnP&uLy+dB(8N|^rrS<40$rNa&``P1s!%a zO_{-~O&_~32NH=~qE|8y?DX5}@moccWF6K6g;WYc(Q9Zf*a@+O!?-!%IAj=JFhR%| z-2B_mNqPM=Xe!>tL@jq;OuTR^CCQ$!+S{2R-7i#RIN8`cK}yAHbf@AJzA?~JmHUa7+8ULu7|LTFvaKRY76d+QSlBF0QAG9%g=>r_O|l#N|V?4d-;xKZ{t)j)a8)p0yQm=w0bf zEuny>3+Gk%yyf~#B`x5@0E#TAo&FzZj-uV*OM!8`sR{$}g!iMH{PLudx(@B3!v zX6Or?t}VUt{z&`d@t*W-=)GwK1DMQ9XQmh%AFI!Rmg)Y#?~D-^aLI$iG)%6o1OQ*b?rx+-pT(1_M8vR(-oM-_H8< zchTGpj6{|lT_aLij9v^k^mVQp9|gzadGm&SfK#Ku;zUOGH8R--H631LT0Plx>2|a# z2-Ph+?8F$QN;4DQ!dF;^CwrTYdg6bH_K3Ba{y*NuACf^Kt0b zYOi7zrk?yu9SxFuEzUbQlak5o2j!?S0aBDiIYu8z7Rr4r?+aL|0r%ES(VtwPBt-5) z1|gs9WoHVRCd5D-#zn@Unk(Z{eV9VR^~~ok{t$T@WR2vA2t1w7Aj3X+|%zF zVT|eo!=LrvP_-_?9MTGo1%X9fhdTFl5+Jg)A?K9+5D0a&j!@;%{9x`*2 z)HN^R8VW>g8Zk-TL{db5Kx5ct&dw~@XP3w~3zSMQd(3p)t;1LX=4KW&OE36b@JK`7 zckpo5uSIW2G(^2}v$y>pz4Q0Ke*Mx4mVPB2m6OCfie$#d;j-dMJHgqoHhT2-y@8R0a!sOc?Hq$!CGX#+-ioV614Y?9b!{TOQymKc34T06oM2v zz8tRySWc+D!F9!a8RDQhcwT0~NYBr7j8gAs7T?jWMXGwSW$a7s`G|fXe|?60W1sVD zO|M9UqrRSBZE#Cd;&?*&J19UIaFVHSrN8^0;RNA!`9ig1V-i;#qYPZy3=&;0<1ENv zR+x^ZT<3m}|AU{XwV_aC+v-TCNOd;5D@=iCHagUXN7}7>bb7i#CSBU&B}$FEmBqoE zwXZM0EYO!JHxWDW8!BIVIg>(+-wYb#s?$tH`7@#KXsw= z4*J)#72Yh;l3+sDnHX}HbVd;h=yAAb*T2bLsCFWvO_GQbkl#$R+Nop&4k_8y>mZsK zjBPtcHXNzdaZ)TZUcw2TUYkVxp4#bgYb3MZ9goVJJ8}wyD~d){tJk6+@?#JX=>PM~oU;X-6*;i>L-!dNdHUzC*=o+<_6l>y8uU1! z{|$9%JZb+rFJL=i_w)^aoUWLreHdkh7Br4#nAQ^r-FZEij z03W-ajH=lq@LEH)!pW2U*s8wZ(MUTF8a{MJv~dajz;+tz=@`T28q`*zEGlW*x_y) zk+`Y#t)uM3N5ZAjrVRP*yUSF8MqF9VG>yLc2rI4Z<%rCCznKzyugI$87lQK@Yf)s{ zC_x^0%BG&-$VYF+9L96RN&f~Azc)!kE9~7jO4butKJH271D>r#iq;^u+o&V~S&0p<9brI{@1GX2ODJR^^w{r#dHt z+w!Jfqz6N|Kbg--u<5qfy?nY&nkW^YC*8d5U@(_zo259_`BUZo8LqyHCwE)z&FpEO zmYWr2OlZ?6;i!WFoEWAz6pqNIMU z854@Z*QWY*&JM^Hgb7KPpJ5}g$$W=Sv6dua{ewG=1d`lCYN)rf|9qS4`BzN!yh;^j z#(cM*gQ*q{t0=j7lBB)utega~f)<#QAo)<6H)=)yt}D94**)(jOorrLL1hEl zhIAiT`tQg$hDu=Wobk_X@Meob@f}?$CZ^|u@gJo3OZa*d=3|6r^KP^>x`+#RUd)+q zqRwT+tJRaZ%|I}&L`buYrB(~qO-y*R!Vn@67;-II*v6Oz9=_qVKI1Plk|yzN%#m zI+#wVbybj=XD&y1ws3I~u4gex5Vvtvy+}zoogOo&6FC62TII;~;QVS!5EFbpKk~XD z!7m7HJ|9|u!2v&&aqikiof_lQ+0FoLjw!6iJk^o8R--#z0R>>3ADXp46D0F5)qJ*| z{LuSzaG+z|0^KUbm#;TJ{f5Jh*B^JGb~{rj0BQ9IGi^4j^QmX9Jg z+2=wUC6i{{S(Xe(;J2BMh~` zCqARyRWyzv+*nf_kGMP34y`>S*zt;wS3wnU)qR*f$L0YOyHqHnI~Ns4zd zj!$jA2cTGFqbYdxJHL(Qm;z$GE--6X0>*{?!C(bvq#LB!(mK-TtZ{5l^MI7Zs^+Uk zPZ!^x%F-q#zcco7Etc?Di@x$`4LS_fCa~BVDDiq`ZAmfnK(~p{0JWxbM#@d zkM7U!lC#nVTL%$?x=0~gbNrNn zs*)h6$P;(Hb&xEXVM=W>lpO9aOi%*OljMiD@SsTIDUr}9;gc`kzbCx34=Atz*Kk6% z?Fe)qo(eqd>?eCSo4z3(#ql|7yd=H>=PU!so!xtDygug?XjC!q!|%YiJeuX(*`qmy zy*vn98GGQg#0YJOT1xR*`23<=Ln%fD*XHxlkx>_x@A#biUy(XTz}tvgqJCjyHdgSu zuq1@0_}1y~O($tpelQ37>viETw037`aX9b3*BWT~fERReOUpv=LM7bqYy07=%=+vR z6@ScC*mPn*Y-}+&T!-nsc~!SFyq!?wG{YYw(od(dp7F+I7<%*Vk%=cRnE!sLM2`kF#w5f=){1Fk>ymry1Qm?# zzFkYK@?&D*aL@+!vH5Lt2&iSbP@AK|(!b_Ux!DEmJj!&6+>8AFByTRPN=#EEI(ky& z9cOfjKI0C{D`Qa6Kd@B;rK~DV!TbP#Zs3Ta18@YkCaioAEs$pXr&u^YIvzyuKY}#h zh1WP3+2Qg%joPf8L;}qtxHjS41g|UvWmR8UH>uv|(Dv-4+OKoHSNsq~=Bd8>Vt}wE ze&y=aaYc&$s*&bUlUicQ9O^22SK7G*q1D;d5!PWy-vkh2Ms@^IeJnBZ-p56OjN(`u>gHP#=7NMgAoT09TG8U;r$-0?Y5weY#Wr6Qn^WM2KbP&6%O}DU z?h!g~vG4BiPcBt5{MIkYn~i(xiD<(7`ITWyIEC}Nx$^Xn3j5a!X2}(TM|#H|kK0$Y zI6|dUPvIQ(RpX#7b@8qB!BL^;oz6;9J@Hc+zrOpNBa2(@R_N>9r&(hmpGEI@mC?J# zLqN{7T4C2Mjzel?vGxuNHd6A~8zcRFwHVO2V8eGLKl3fHOIT&z;;;(y%qo-1o)dg9 zY_{NlU$Lqn3?S^K-Iy~xU``o6KH|k}o)XT~F41rVp9JkcFkSxS_`Dd!(TiI9pV#bN z>J?`Grph;gqE%6DW;IlEV~2Y&Ve#2+%P^s!*el zXa;WfiroDQL8bV#_Ih0e0@@2aiQncci7_TJ!L|R1!`S8<+zP@c6%WQjav!oPc_SG+ z`^(WO-!((oJ*sj`J)MgTXJQNr+aOA5R#0X+IpzismNeO6$HAh)2eNfA59K=-VaKH4 zfKi&iWs57S(l*fV)jI3S*Il@nZfOzkMp2lSMCAWw=@(u_9wbuFy}k_KVL5tm&!0R>EP@;czvLBf$-6k8SBRo?LT>+;n8 zRjE!y!9#LjU}4{O1qc3V#@nz(oF6kE{QcGQIoOch7Y@sg_K!T~qKS)8nz<(&Sj)U; zL7Jk`I2aQrSvT_tG>hRhEMe_DM~p&xhY?)f$6>8(@CGYU_*5wY_F!iwjD=&!m-0hS z>^3eh5VASKU5*qDrHDCyxyW(#sQbS+~XKSRe5=5_o?l+O{gAA2B_JA^tO_0@YO1Yd~J&zQSyC*8Sk(;Il%J zGNSN94bt|KAFL*RREodRzu6y7m(zY%+&5VB-40qZXZL8tOqC^mniq^8r&cWIgBOL| zocq&y1cOH)k7TejN{8PK4`zgu(tKXAU$J;?s>nQqkgHioFrt#q;%oSn?~#bzl1?KJXw!C<%cXq(M$sIFa zKQsNi(FpqfF@?jf-s@NUcAiI(MhuDnU#rt%h z_ENN}d<7ei`9~RAlzA{ELr?2lxy!^PF%wNahT6S2GeY@<+2h54UA4kOj{n9k0VSnrG24cRfW}VpdCd@?&{@gUOn7DZg-q* z=I^t&T+e#-O2l(So}S%|}vh1rf32yFTU&Kb&=;cWP@m!Zq7 z(u3dF!nl{cn%qKKseZAhN#T#^d~=;@JK+tfSAbfUV}ex)P0{L$-*;CB7%@=uX=X^7 z;kSBuCn~@fI>TJkw3$78QF>>aw_U=P`@*~K8!OwACAv(&Lsen!-Q^Q?sB&TE#0#?> zmEdh2i2%=`6Q6iMKK`H0qYwAsopRo+ZXQ8SEJ_b;f)@ufHF4R4>Vqy^n^le=J4v4Q zo7I!-(KJoRSJ4Wx#fw@3e-=&>j0H+y?9M z(%+!hTBJVRl3hP^uiI!rH%A-i=*O09-IyH`4eSBXGWZMJ`s8R^t-E9#9$5Qx8; z!hX299}~}kIbonaZKG_w52DZtfjF08mrz4wL!()zgIGMv*cZv}<|sm=i)X1*I7Xh^ zGUk@7m`5J@lsNPykI;FzX9f*#v;0@rW_)ocx+F>?jv<5$`R&ZkVl41`l5{G-*Pi@j zfazT6p0E9p_hkrhRk6ZueT6Lr6ebCM_5rm=iyMMR!|PnCVIMmHu0WFVzg(EYPP&$3 z4vzzT3}I&5qsmZ|L}FT9BOP3=XS>PfmMBA8WcR8Es#xU@X;0XFue~VXUuR%qm{A`^ zezKu{lf;Pas(TN(7{fk_tAph3dRs3TPO~Gso=6ZtMp8JPVM$-mj6TZ-wn`QM-^p(} z)=}h+-df5uyt&}o{@%U~VODYaPnvzQxspRPiFs11Axx6Z7cKKu5?_V=>IbJD}sx4R+#`$>NLK0g7}`SeY9EPi>A zpB0G3G6aednmvj>Nv0OM?j8&&C7ae)l>d1ksM|E&ay$BAyd1e2Sde|`wnA#97rGP% zfIS;D!>|iiFq3U1um+m}b)t?=;1v4)@=lA}PlETkDw6sj(($|{*XV+oLa3$6C7jyZ z!=t!09iBDQ_VQ6ccnR28v>QxOSE+w}@fy=dj6&Nx(eQn!w|6`n@koL89ej}5ZOx}p zpZU1`qgaj4;c~L&`nOLv&A!U^?qbc1+{9Oge7}AI?aV&`?VjREb|Y)v+TX;iMxDCR z2R9Bl+rFGV{UFl|JD!F zIyZqvCC8)1S+RKkI!;dTDzZ_zB2c3Je8l?%QFKg@Ea|qQ({i-fh$B_`pOF5oT_|!9Juf6TPW_hGPvpV2N()G~H@=_n)-X*< zTOR3I)=yF$?g`f%OM!-S8qmV_v*D-uz0C%BM$;zA!%f-&@@=J|?Po4rslY`7*FBJUwxvpc$KRtKu+GO&9LM_m(&}&PY$00B#vf z5KPX0#y-w=)p~VnNzXkFn@*d@OIz2|5(9rr*S5GEx}`_(qui^8O3UVPdf!-90NZkD zST+%1VxAbTqj9#ANHfaBSa)%$s=xl6@{8RHbfjA3?kC)1pZev0IRNCeOt-%#-e>*e zz{b8wk^7}65Ox?ca!bI=wQlw0egdB|{Hp(gcp8Zm6q#T7bqr~Vmj%~pxD*Y9vM2mC z%qs9)eowem!WHj!q;Z(s3)Ww6)FDT)6|oR5>TS9P)>lXZ-_F=rZL(NT(bjEmBP-n; zvORCh4PwlDxsj~XeK0eoV}|P7V@McM9-I1UQ4@EQ9=tpMI_}@;jfgZ&VA+>l7u{G3 ze4Fdat&J0gA6Z+2B4|1^I_YijijWi?f37DZu=8rFRgqhwzE|Q<)UIB$l$BXW>wLK9 zT)PW~=~}Lb(bUcIr@3A<*MY{{I*K{E#V2thoar2mS@AAzft-{XNYHcDWwK0x@_PtW zk5xT=Qz0T}I`}#mv|jM|3k;W_d*5HJgw-s^)@BYIj#Kfg+L@L+1%4qlfn8KwG!R7H zt+ENA0JPg@{UC&+TMmFmN)vU5`a2`6PjWfX0~xjvjx(q+7WX2+>)BGwice$`_E+>| z+2OE=qIc;~IA7Y5pVP7Lm$HHLZzWzUB^Xg2Rt52w5@0h8=sj$c7X*0XXu{nBXG$xTDK)MH%6;f$iHG-7l^OTIB|`{ zjD5ttEIzaXits0?*EU6@0Cu~C?rT<$akez)<}&1NCKOa{JI@;GU2uTLViQscM$y98 zm;$x#Sg3ZMvgPF?KLQo+LUH}*TbK&M;|CHbx~2h@Ro1>s8lmro2L5kTS?}TNe;bG| zhNrOdJxK>s18hNzZEjXR#+$pELb*ev!O?m%YSz#2PD0?kuQgz7r`^`bUQOlZy!`H- zsbg_=L$!*?Dl>_WLPf}EoamdnOw&kY^Q0)4Js#CyfnB?c>}#dzHSt&YH{QkDmMZ*o}4+E?1b=vTV#DtaJ%oM?FjO z#T)MTHksVOL7S1pDR{CVPeFiL>J8J)a&fucz&yhqs8EMzA}gGEtpHq>4lT%0(>rch9vr!)j zrRSPYoPzO7@DGr@3zdu92xjlmRWFZj6;Z|Zhvd9xN&q?jF9@dWNA>58O!f6WUXb6v zNW%2HkJ`PTpOo*P=0ya&b`Ld|* zHs(MvNikyEQ$ z-5@Y7kv*`lDd?b0)T)>cp!=0#nSYvX;_`kK+8VtbGAHFr5*x>(r*Rts7BY&CM;lYt z*cJEt;LTT-ol(_YpC8BS`zGF%0GbC+L?+6#6dVcK`mo39KrP{^H*hFp`nUhcp*Y0( z#+4W?t_Cl2Uz60JEAG#JSuD>pV1Wbxpu8 zhFqOrr{esI%KCGsna}(&ue$4ehCOFEtrYfsd5gD%SaGi}Eu;7;D1N0o=wjMJL%anW znhbs}pnOWdf=9E#N2R-@ZD{J2K^JC$h?T~fls78VW`+rU#z0wVWNY7wC*P*6Z4&Qd zV@bcQ=}IV@Aqh!rUb(IB=v*d+D0W3LGi?15flyY@097Dxj~igat!`U&=;}uRrUG&Q zfr^XLm5<9Ukq;U3YjgZYZWC7RRF)3Sb)}YRFMz9d(?sV+s?nNBs zQcpyG#({Ae=_ZM((6fQ`nBw0U${j+_^@)(2HBCR7lvcHKErH5btJwJ@&Vku^P>e>4 zoq>_!YLI%V#oXsO^mUO{coskO(P=O;+LCndBLkd=^ri@!;+p0^Nd9XF+mi9U6@{f% zGe&zMRB@i)+>YvdL2opMj~XZUx4+S+lJZ@dx#FEJ2inFUpbym4LV{m-^DnBUzI*`V4SIdbqiP9WUD(E1)sMzJ zFqq}`xcAI>kOR|()O+;=#xDtEpQ>!B=vK}dr(>slO0%S33pH)W#%*%XR%vAqQE5{0 z&f9f*Qz_F0|Jc$+a>ENw-p&KGrwNs8Y{7j>v`USAcb{M!(qA6OC%~N^NNA>&DE+n_ zB7S8TgNG6kC4eR<-0uRom}2olIAagAlJziK7YDQn!kM#Ds)~$VHtUNFKW(& zZpJq!6U7>La36@jj4Q@5KOHx~+*));hZ%aSd{_STr@D}Ejvfv7fc-&?XaB9!EbTJU zUNigM5&tw&`OMA*AGV+|;p!kF+*+njJ} zi>H~AEGX3GKE0HgcXE)1SuY2Z8ND+dE%(4aQ=d=d9JqAt1>QvZ4sAjLej|6@ykTd^ zi-;+eBU*nhXv#J?)>cm+szl5zjwwYC^070+^)qa`Plo={@e&%DtQp6#6$?&?~w?55oVMRE)B%vdRKd>H1 z_&d|%W;;!FxAi8c!wP-igB(q>{6t!)(ta6Jym#9vahIcAdA^L4Ma|G7#yrCtq!sq! zgG~R~aej{#l_#n8z3HOtM56Usoa-Uc1G7&qc2~1;!c~&hn&6H;29sCX!7vyEhi8Fbz3O9WOqoGvBL3!RP-UhQH zv4-;rAm0)Yot+-F&HT-TIYnFrXaCfCcv#4jwOW90LZ!5F99>ta&Zkl`sKGKg-mIS- z?26aN*dW|wFGy=(%z67M30!9C>`~e+6$jC4Df!FHTLn!JoMlA_{I;T9E*Z1NQ-0Ms z98wsYz@1^b?^TxnuewZ)b`Z!bDLWuNWdQOWfbnw?6skSIoJf5y5(IqaZKm>)8N8>i zmbc@id9>VkW-o~D#%aub0_}HzX{xUoY_C6Q+cRUc`#E+`XHDk3Ci}K{x3m;1*nG(i z70;p#{Exb}RmjNJ5B=Vh5aGH7gc77i(Xb65r$S5brldSWw-VS4oi=TSC3fYN-_L$z zTN#@!XrUgmVD;HJZrPU~kO}&*(L3m6BHlO;$oKQv$~?6rLo{NL3aWgFdn}0L+k4gR z(dPo&@ir-zC?DbnU&b1Df&$Cgjki3Ym1+%7W%8@bdbnR!9Z*HFsL{xK`h`5u*l83O z3zTA|nfcm2WQVUqu=cdZg8PZ$?2W2-x}Amoown9M<2jSzf)sgB>65-?A<)Nti%P9f zAWEJB8Lp=4w#;Ijkv72`#0jzj*h{S7ge$sU{qb0e>bIL|t%~A7u~0``SE3HkJLbJH zlUu|il1L}DqQYCBvU#8D9VZgWF1g>xpBYYpJbdQ{^Tw!K1s-K2yM>fA5XXyqONzC!)V|{Q%&oosdz6wpi!K z@V7^2mGj>28lLzUzkD$6iSA=~no2C-s2Ru=$n*^3XD>Z}`0*o3LFZiq;gSA?TY<(` zdu~l#p3XRxYGtZ{`-rY1jn@PN@~Et301gQRU!m_Ry)OM;5@ z(#|Iva0Ru+y9`0O()@WYrv38X=shup9W|&4A_gw5sq$R`kKKdS_56ID7In~Z=s!4$ zyw3dU-d-%rn)0hmPgcbuEJxnsXPq)8kx2ph}OuC)SCZx zDw~KX0`w<3c)t#^dpH#>7o^v$+o9Kre&_FGPB9nUO~ZYjtH5)6Ba@Z(>s83iV{woi zOA$P1$ze$}Xh$>2no=V5o$byCd2r7;*zn@E-*qyl*h71L%jGW#vp|SZWJ!_y#G6Bv z;e;Cv{~ptC8lBs*EH-n=XRtCKwiRazKYqDj5cKS1I3w|3?mT%v=mJMGP8W*Cq5YRM z1B!!YacUrKH5A&Vz!y2ikxE>Naoj<(o~^T_qI<3fL&E9i6NQKx0tw;$-TkccB8S{) zHY-3b8FerJC>cB(#FT*f_HQ~er26vC{-eZO4Tmv47RaV&Jn71@BCf_yRQ|w|US;89 zids+AGOSi@zE7fSM_2JjUUBRm5RM+>u%b7)g2) zaJi)Od-vft4nIS=$zQD{KmCc;!(&p^Mnw~c5Xo|}B93HFIP->5iRi*>m>2i2vc6Yr z*WA#~DZW4i4%^t@ym+oI2bJY=HUxk3 zj=}^y76d|MT$H?$iZBC(X<(szrdIyerW_5GURb1IA!4sl+VbtJdkWD-s&URgxY(I4 zq?=E>sj2W!inRw&U59%a0wR3Lp!^L)K~vsC(`JYJw{{1x?NAt+apd%C9yVZCm6E10 zVW&y^b31hrt6IpNET=!ebtXAG|T(aP=eUFFcaw;U-?5PyC0-_;%r+S(E1MsqcLT~*k z9jV$qQhK6csa|(9L0;%nri-5+I&%pNKtf&8kkFmvH&l%UPP$P-)=3c(zkJZo1c2#%sr-(X-l9pdUKYvzjo~JO`fISm5w_*q0n~9i% ziOTM4q`})V<4w3<4FHV0aA*bTRZgEsW>f;j5^#C#NI#ZgMwiC8^bS3`$a(NAY)Ed578&h)E) z_Cw&!C>sfk^c;V+upY$56&qJfQMv%Q=S0}y&D9*0R5H6eDe$&2_A0pK=}95sBtW^j zsYk0To%L12Fc^OZWe$-nW~pw$&GfR`p{&O&B*1gFXBIv_#|+Hyb_GQ5te_ftyzz(& zRjJ?KWw}2QspmfmDaPNb&97ZTcP3Mi^ zNWE^hyT>0t+B9#s7jHaYZWxIF9R7CuQ1z_@ko1XhAJ$5zr!%BnQXcwU0&pA2BCsO! zjs#wEFjrogt=u|Bv~=@oSQt$)u+{uB#C74$F}hqbdXwkJb1^#-A~&M-B3kv8urpV1qs=EaOsQDApXyh-!iiV^hO*tV+dD}G| zK;0Qk0Z`!b4Op30s@h>gwdk6@{Ze?!%&Zf>DP>oYUoTr4;FEzyAq_;RSk901>Av}| z7*)J8I`h=r;X#|BbPG_URYj22Z}vUFsC~L# zwX&h<_s4=P-MaCgE=-n-xdAMMJPVq^3$dkBJd{z`dV$(vrV zJ`7~j_f$uG`5iz3JhG0-_QPHKYc*_E2lkD&*)_J8S9FVi3hO^D@9Xg4D`%&77isQJ zXau~s_A}n!d|lHT&`DR~o&Ofq=sU1S8gxT5&JbGTAk0Y*KFcN?kv=W-{VE~8pP9#TlQ9_MhoT%A z&2z(^e8FTNW6`dLy`%BBKiBrAsa%r{aONR;Zr~K%ZQJuYE5^t^i91r_?lyiK)KmR; z1}E(jgLFIhb?0Gv5k{Ca`c9`6PJd?c_+@!cB|#$vV!%U_5r6u}SNl}hNvYoKCTo^SX^=W|pjz)8)7`tVD`>JpKm4TkI)jG39^SLr1D@hCzW?_rz5EnV7ibC5i)@&Nr) zrKT3+(UyN{{*OfXfS!6GcbEl(BeyfGA7j|n)h?A(r5wJymu07aV2ITvxP0>Ek>$q` zfD&hduypUsFExIZ!^?Y(b%1D}ICK9%>Arhs5Rajy+0*tw!QI27r>T0ia3B|MZYAMk z$EK7PwVi{}-%y@l@MzC}9V`8LdF#F*W)3~Ruc!5Oe(9i#jpUj1W z3|N%R|KLtT&Tjx69}D_z!K|=OPL3mmpAS)ogP`UWF8>R?6EhA0eXhLT(jkh z)$xHGXDl<%DkZtJx4mI(ioA=CkTou@DxPefSQb`QW!4*5F7LUyehuZRZJlcRE)fLm zw3Pzm;faWSQ0aCWf7|vfaqVRZgCV%ui!v_h-G6@@uv*RDwyoGkS~BPT<+KD2_v56D zaviB)u}SD&GwNlN^2G#IFzr@#I;8}z6#}gXDqp-;@ANfcjZG7%YL8a+IV*!XUr`<91bQgthYCD z29Y#ctn{A(^|Jd(0~(*JLi;}2 zKN*w0yg5NjqN@1f#FO@(T?{pMx1)O8g_dIxd#0HeeoJW{qO5je2^y4oPRs36bRU%- zC?+1PgALEKGU^~(V~4>U=&rQ0BLP_<;l}7ZD?4z67e2)@RYX9F;L5w@(|j~QaZK9N zwJ$gT`_`EUe6I%;XC<%;D&Kdg>jh8DC!iqV_TaCVc6=q4AC_1qNF`!@;8&9~@$ihs zA6k?NrqPbAGgPqH#&kC7{VTsq;dlNjdS4L={k!g6!toKc-@bcBt)yy8J;@1-@;mBk zptZiYzYnP6cFu@rWp7vY8*kUNf(R2nFTU{VwTZMHWCd(3IEdpqn6AshS_j6(v~Jo- z>;R;img@HJF%6+hA?Z+Pccbc%dQFmQLoZaM{jy~jkBV~-2I2rq*9GpS?F(7Hq#}{% zD~p{S2FwTay6YW4^oODNrfv_9CKu3$KN5P^;6O%ed-_G5AvqbVr{kpeiCj_ZSgHFS zmsnkfz9;iw88m-45a!g)*Q>uKnmhFMru_vITGcVLI9qYJj-8=FZ<>`pdOBdNyu2{XE!-2f#hzek2i1owdRe9AH=Ilp?vXO}2% z;MA3Yz{P<$+h3qejWmDHW+Jmo#=0?>XQ>@xeP_uW;+gE*TMWXHPH_!?J9H4c0m4fM zMCK(pPta5NCP&ra)SHbgC4JSBrMYN@a6a%r8sa1E)+UP%9c>7OGl?v;jz&0ul_98%f|=xz12hx= zc23ovl6IN%s(=UO1d@fY5;}%Uhh2L*78>VempP*R~Io0RvuFh|?y?f!yjF5W?FH<6Q7( zZb7U|>_qf&&0~ZOWVo|)S7NCxR5>^<2E0>(;8(X5lB}{M${ek_O1C@@1a$wWv#*S< zBip$&J9f;>j+vR6nVFfHnVBJGitWS{Gc(1^%$%5+8Rw?^o9@g@zn(R-yzaf_KU=jV zm5$EVDJk_dPKL75d2}~*qHypIH%b)KUTZmNI4$s6JCD@DpKHk|KuLcca(I1o2p+#b zFsEXt2gzk_(Cr(H@#Gwidcu>)w0BJfG52Iz{(?quP{iB~$`U5>%M?`~9-m^jBAxSI z3OpC9>_x`MCqx+R65QJFHNl@D*tMu85lX5icgf1wOGD=tHnWyXP7_W)d0IUpQR2%c z?_aYA+_9+&%K4}#+g;gQ)o7){pIUl$&LQrWS)s1%Q843bIf)?TdDt+}@pn6ZMNSqo zZ=o4?)jAbTR1USVIQ7#0ggVGF&^MjY8#3iOKE%}|B0I3Emld1mACb8hONT9Zjy;*} zZ6@ly7?f%)geyD#&LH9@k z7p-I;WNLk#=YA$$jr%c@@i0PXXr19^?RBy|iPk04Nm^F3!1Qpf{kAoZ{*(~`@jCzI zW&E|Jm=KMDg&h__x*vv#@6b+rMMsv-OC5UIywV}DTJh*=AE%=Vy<)Fw@mBIV96{~GmC|F9UZi@*oo<>)}I1qXY+g4d!@sLpp!p6Nk zcu%}pI5Zo)VCX87PoA!5l^=vAX*mRgmc!EBI}Z`pOTTq|?$!$_ZJGK`Z*gAL*4@qX z?txR(;6ifR^+y09&y{*U=Jtm6Q^|T$CEBwB!{I%4H9qvL#Pz-YTtW&(_|ejibzdo^ zoNemfUBhFYdn z5Hf?T&lxma8XsHhK^h8u!5GdK{?!xS3sM2we5aNT$k0~9`g!?rnbTsjHvj? zzDxkPsTa=7C(^L+QhRB;AnifzSv%D=F$*fnkio zbyvW9)2&aQJQW{i5qzMHoksvud7zV^Xu(_8rk=j|elsyA=yGao$;H#2R&Vs4enuL6 z<$=tfnHuK(mZl zyAsoMSK-8H*V1DSF+!_SLvGsMMHdQRz1%rO!U-a>BLz0ZlqS39z z2Nc*4S@llZ&r-Q>Bg!sO!{ZMsqx?*KQsjJLCPEj{9z4`U^E-C3zQ6@foI$Mehkn~7 zOiMvCSW(tJ^FQn_SE)teSh2r1ZLcC9RHQqa8MZVp&THF9X}I2PQPP0s zHQ{9a+L!Wj)GMjdqAy!N=EF2~*MBUF`RvPDZ4z}N51m8Pm9npp>YO+jj5p{Za=j>B zs(}-wcvSYS;8B?<4V|BmgrOynSmUzYzv>5OL{IFb>w>hQ)V@{YyNK&^Nn`%A$qv7T zBVj{-gfE@X;X-ET3=OY1*h`uAaxAEhxq7eDa+N;Lnrzd4ldu(^I?NU#FR%{XmHaXN z8jc7LunJ(hLswwGE8=R~I3s@A!5iIm7a%JP<_QDh@+@>~6%h2@T*u$d$&WoL{#475 zfZ?L$s;TCo1I<`y#>)5gJhCE5TtYAm!XdXPO2xv=>GnDq{ip(6JYKeVNb~DJRXBWd zWwE>Md=d^O>3U6iZru!twCv-QlU@;Fb07BS?`VovXN-FwomX3j#M_+AuS!7oi;cCn zIgJ7&h2;*Q_zrF*aS%&AL3=pI{0$`{jeG8tV`&7BvQs7p7)JrQ2Jz+bTjrRVooRSQ zW~pgh7e=XmjuSLB>Tvj3mXC^x^$Y5ga~k&%J1ZB|&43NQB9$+qOk@<(6I8e71_RL( zajBr;?a~@*)8RV%(1#l>^O$4;%+OlwJ@aqij@|etAE=jgmr8>~^7_9nhk3k<(Z^|t z9<|WnThoqc3TA@1sFVpS+u>>y>r?ZsehaS%Skil)>e!}iv#;o+ks#j*13R3AN}A?D z8z;LP_U2a-&5n1}Dsa+;<(UgY|IV$I7^QU*bCcblF~G@s8?AyI-Pb}NnSCl+-O;_L z!3Ut>z#husxXY>K<-`^6){KSNJ~2ZM;2anq!{UQj0$!3J63h3P8}6Vyy4(45U>8L! zAa+Sb_ztpv^vb?QmDm}KmY?ItMa9(GL$MHQ6EL!#B|Hy&6trEo>=W-+Z_Cp0_ak%0 z*_+1W{WbJ3u z&6zo9eeF+6!Tg`4Ow5zqP$rUAn!KKRi^I*>dUluQ3&G9(EAL=oRjcb^J}X6m zc@jq1vCM`iTY8&&hoL7r&KX}N84Fz;&<_?|z39A;-DSNhx=Gpq?VRzxU<+UYzrWplwu@QepnU83!#Q*rX;ewXZ%cc^%E7nt;ThGjaBU62@yuln3->*#xUmZL-;+TVKFP{-Zo-M8Tf zjOBKVB;}m>g~L^V4%MD6$s}otfq@|eDIudKhEtn<>5|mRfH6d>ErjGpsQV7xSf$#4 zoraa9sM>8wITBZ87Jbt^(eZHCCuX(`q`DHY87*2msW(WPu7;rpzoJz$g-_Lff}K(9 zmY57L@e9DhsIZiuxyzlozURVOwD#_9HzWGxPMleUCD-SpF}f0Q*g9}<>W(iF_3yb} zVf#4hEHy~y{vbH+)bM0OnlvA;66t~;B)hVfCh8>~}F=@?co1alq z-?5Ud)(+n!XQ4!LQ1w{VBKG3YN`!E4?n2qAdR)b&)76s2+&VGLnSM42(Rxce8j*yvasHqD<=dOJP4*Tf;5hJMX2Snzp7lSGNOn#hOz09t1yLIUeft?ps! z(Q0(?Tk$yFhg{^a7y{$uku5UBty<1zIu?z=t+UvQ-D+ z!JA_p%-SiuTlUSeD&yzk^iOO*GC+3~7_0NnR8a%o@?%u&Fpt@QY8Y?1Q4(#aRCjTp z08-p~4uz;%!r7k;K+Ms{(S9%d<;Z}B7&J02#5%;z6wULZ=3kNi4N z$LNSZ6XIEgLFla*qsy;i%uLyMl8^kFTKI+^#K9N~xZj5T)t##AEa}kKfm*tbxfiVj78#gSn9ESp$U;W5@R!Cd>AIj*j-W05^Y*%l-c1$&OQ?d06aThD(d)2F(R> zw-0IiMf6ykv6JN?0;>WKjKjxx<^!v!Zr6Q_MrCue5uEvaPCN7t$_<28&sy2Xk+V5E znrONa#Lv{>oWZMo?*T&tcs~C(kv5ZD# zQDixILr8m5+x+pK>507~%o;}x-DjaIyfu?){>evzC$WR%m?C>2sl$}1AE{o2w$q3k z&68Ao(H^0Wmo5;ezK4J4?$P`k+J&8=@>>}8N(}#+6rOqNz-x!ATwuWB{gT>B-3LYN zcK>LtJJLQm(*aT zllrvp*Fmm4rFZW#nvZ(i7hiin6G~zGy{!Gp0ScQ!>!?=4k!WJ!QAM$Yxm;0}Zshjs zsztg)^<%GuWeoU}lJG^2sTY^Z@(BT@%R*5hi!g@f%CVa~s@W&G4|R*fA#`tTiSpUb z90gjEZ?o4yu>1JD)On4d(eP?s8$UKzD1;el(2r-51sd*GQ3p}QZ8ijmb1c@LPLZ;l zwADbVm9CX>L_e;J#&VO+D%|rDHk#tuC&;AiyV5K{5{=BwuoZy=A-;z=uw)fKBGhc2 z@(0!fikuyJ4oKH?=2`T_t6r!ltkP1qM{2Xf9(PnDXP%Cn3tiXYD672q)23+2!<>*zCf4?FC=7i(t)-#GZ`6@Rz+ zw>%Kpl9|e)B1X5-v#fy18GoZafuz(<+LBPWa&00RB@J64zsI+h>8DPpd=7j$m2u3o zDOL-j{vt5_wo!Qak@wvBoY1Z@Met^NDMhQW_xCdpF^2A3K&v4yPzG%I$-@zC6MCpk*{}Vd9Y5lK7LNClJdWa% z$WhO0q##g!W>(L9!EybpukUT-P4Budg2}6tWM4Zh5MFd0eSCrc2C?!m_hoM6D!nYg zr+Jm9=uuH#(ETwzG`B%)ehqO~e)j5QnTeJ(N0xNs<-qV_Xze!X1yrM-&%0ZcS;4+j z7Ur0iwl3CP`nBuUujybcu>V*n52 zPB5S|g#+e{+!^I9trok5ObRX^c%i5av+(V9&WL+YP9L|~&G3sA*%9Ay@}4uU&@o2|G0s_-ET>?E3lI)?RT%pw*nakSO*ykEMO{cV_n} ztsWEwKN@G^0y%f|r0l8sIV$sCQ!L=8f?=s=VD5+4hUNG^o|`fzEJ|b)k(E-nIJ~Zi z!+_eG#|_^2BrdUCNjx{J>y)PVWcXZ-L%doO6=82A>;P&>AV>v7ioJ@ znGJoWj`|qeZiwRR0z3M4h!sxktl;x{i81L%7Q>K^6RVVh zU@h^DSmOTG(b>E^c1WfjE+OP@JW~oeG?2i;NBA$}nEg)8vaX0<6bu$M{hOLh6|pzO>-vd@tZ^z&QewVD>* zyMN2__Y!`K&>@+4O?GArIe4Jz6JvEmJOe=SLn`!Q*K5{Xn}|m z!uvG|be_n;5sMFv9-McRjV7+@LvSt6EzRz{Q#@(18-=V7OHU5D_gUU~VN1g>P0#uq zyLQQ3=BW_f{(N$Tz-b!6wK+fY<>ChG(?+v)sBZA7^9c0ztP}N2&)QO)hSis0Hd1m% z?-by~?`^3jN;+Z-*horR3?7a7%(4d?-!Td=)20{}zrsnx56dFvqdO>G1LXkA6_MJK zIwOLjzxL3)u6Cz?dw-zqE6msw_P$-;@vYSw^1c}OE!apT+G{#tSsk|X@_-p6^yn%b zK_h#{)LZrPhP&OOyXMVR<iQ7d5vci`ONBmSp+KDm&skWj%NCnuTPVs+qa7bSg-jc&|uR*Q+@g{(+3 zah60<8bb*)@OFBEdIbxOabUU zmq2jX`xa3)3^DfbNB<}Y>c#0j_qX>?EXbe3zENPEH-vTsrFT~8l}&&+;^(Td!Q&pd zghq2DLc^hK3{CN>wl1=Iatg(P$&?St;u0HyeNirAOOo{3)z!C-@YFT~vE_F6Au!sb z`*xR8TYyb9!rnf=0=$37F%9x1V;VNNGq3}l3MOmTs6$>7aqSRw6yv~U77-!D1mr>K z3H`nRI4em>Jge#YPNto>Q+UQqY5@eKR@13e|1m_-eJLGGS0y0y-wqI6$f=2V6STq6ZP&?q=TI5q z5x_xqHsIOi+w|p0$_b4?VL_;6L_7Kc?`!4A&?i-($EP5Co;^gv=N^dR%D`<{&Nek) z5d^b*M@ZW=ifc5fWa|%RQmY-*eN%{A%PO88@`CWbovWvQw+}ScRzYwfvhqf2IYeH*F*#0y6ks2n{Si`)HS zZO4eN;=E76<~(%R!1bVnHQI3)wHaOh`>E*Ov{4fV@7a0+Ghfr3il0>!BaG;7$I|;W zpP9*5{_-QgCPW|NaoFablp@~;tZRgAiBDK-a|&zzNceAAcbws)8Hd8Ac>RuO)S+&k zCUgd=&t|FlXEF3syf1oxcg{@$G)T7lSjR31XpkHS0tAHkYv)`eJ4chhIwYIV{$t`obB5-#j#ZtC zEL-KEjxG-i=aAYYL$C~Nf}4`=kv?inqixWcKo(JN0YacK!YGt(@#Sob75TQQrzd( z=~Wzn2O^vE2f$?;TZsBD0m(i@LHTTlD>GWtXbZ!41+2Ss_}i=$+N|eQzecxBfDn2{+5!4w-9#&f!L%CPXgZVO2Dp%ZtxpF7L}{&~-Mv`V=H#mXT0(A`X+!U=*M_)gWDef&GZMdEBK5A$ZV;Zhq z_abFhT+cyN5txFS!tH<&#(K)YgU=!?rAOGw9Zbfbp{oZ_-ron@$Ip7#>6!pNdIIza5748#HJzKCqm`kZoz-71orCy~x{OhfvFipj{gzwy3wOk) znN!8E46CDy8411x-ivQyCX^{5*7>n9VF8S45%y_wZ*k&mX~|oU;u3UTBF~8vuP@1e zS5&-x?BH(UXe)+c;~wVfo*0HbIm64#X?`}e8Kqq#QSVfo{gcCX*^`$GUB?5 zprFWj;-~uA?mCV>7d+Vuo5-&x-!!51Hp35?dH2@&ZKdMa(wsxGZFmFAv(^p994wtV zSdUUXQYHz$a8>3I;BB3BxAJpgtfcpTqwT#Pyi=27+?Rmh8Pe#{H}6m1l#=S6ffXq4 zLS)Neo8OGcJ|`<9U^bhwka*_{{I`h&6`ZAso2pa^0Vb0ApT_I}6B*gr*Z_L&J2C!c zBW|>6O6@FVn}1)kB5uGwY;p)BQx%OjwGpMY8?O4L^Q4UcP<$epnk zT4Z`&?qA%EvDGr+Q|)nC=}QIFyMfD+VS+RdFD#e8*Y2RRHGPMZT$+3l3;j&o@8RJ? zLS;wOJQxqbPFoe@;6w(dMx)V(+)0p183V7{7i>V|jx0X6iX>tsoNdzBO?g5u0~&uw z)WB;G37Rs|0-f!H{G-6aS)|GsTJd_WLLti)Z{Bkn2R_de3WNoGT@KL~3-1Vo=~!k6 z%>o@#5=T})u5wQ>LDjJA9Njuug2U8Zp|tG+xUSSf?BHPOdKw9h_hd=NU0$>@5YHnY zqmsbrp+Sy0>{Xg#yaGYYs{}_b>C4?)w&LrA((oI~4FAg=miya7$1l3RPjHkzqcRkE z0O*4YcDkEGyO6Mx0d~*T< z50dIAa~=nI^lRUQWToN9_SpTR;7@1sbVS4%opr9b=y56n1K07$wfq6$t_ZO?G)cM2 z0wYk_TW1x}uQfy@Tn@J)OSzVMSD&4ZGl`^5Ki3_mmI(&U1okKjjImLAH?~%OP?Py) zeocFurt$>t9xxCLA~vMwL*xEk40inVUA7O(;w8I8BJ~SoU$YbGAPRJ8)Ij7>QE8mn1&Bh9Xpd(>9v8PoKq6p6Ixb+sZR@S(clk91D;fgHk#9F$+($8h$ii>$f%d@ z3tZj+Gk!laM_12V`y0r=A6q*>WYzN*Jog7g)jq(WjQ`?F41YboKmIwyeo~RK`(v)c zqTjjmvOmkPn`)1(0y|YoPm94xLoMM<1H#fJF^k3Pi#dmE&8$T&PGC67!#WX(QrC?V zZ99oMkuqX}Zjlr>c~hjw$I$J)o|8VZP0W$VGzk@c@p=8ho4FOXF3E$CA)vCbcOg&` zrZxvkmhKQ7Ot>n70bCK&9JS_$Ng0ZuQ96pW7M&}&Gg%RVv+p{1!G%a7zSFBbGlX@| zf50NH{kmcNg&9_JTrOZFU6(rrU3-T_a5MzP^@JZgt!O=-M{F2;VfbsWE4@?Rfrm%x zbpoSoTh>!;oqWa^iR&Z*lJ)03@ak`rCG%cb3Gu7f&*p;W?R);dQ0kawXI|VRyLTS~ zw8AeY!_{#6wTngSIfT?wtsP6K(bXO3pS1+R6hn!-sjmjAHxpP=#VH+!g zHtN~TAP7nPq83fb!RP?*y?G_whH3f$e>6pFSD`D-cyZ?e@3~l%*DrdL`=n&5kta}^ zT%@B>XgoJ|_z*;d&`Rl%>=?w+WaR3*s-f!w+OjI5=o=q$b2dPxHr3d=zx(3~_jO(D zC2s1w5Pu??zyFt6(76{T|N>9U^xj zD_zc!yRwH~-ubsjrvQRun`rV8DIhpb02U&m--6?x8Q32o@(;iMI~U{n=Q!D(I3@|o zfFgPqc!p5pHeJjoZc!FR>HI_V5VUuDT-rJTJE2Z?V_i$K8k~l3PUq5Rdo{5SSI+Zn z5n8bUgSfI3*bIRg3tMwYZ#NFTF>B{bpaLAIct_|cncJS(mYIFYWZvph8m59^N*fhP zZ17+UXr*HaA_xmCX(hCd64jUK_j7?5a1d;SCrs=Lm|Wj$(m!&KNsldgD$Y`s z;&_JFesY}Fl7wzYM*!{gV|c`E1x_`7R1iu2Ht63b$OV{SuS`1k1~7}q91vLk)dYX6 zQh%F3>Yq(ep76H`0IhjA1H+}4Wl&q}iEe-e9nDCY{fMjov;Zh2ZHrV#T$UGYzLv~- zHP5c0QGC^RSb7*vENlpr2I-A$LLtKF4AGaNRik!lEKd zXkylLy0Q~a)2l+kv7JvczGlVDeCtt?7R1TnYIw^<{_x8@6c#{s6)s&N^Ix*7zr!;L zAhRO-zh+m{|Bu<#ZX!&8_KwxbJUHzJIvW#M?C{*MyBN4H(pFnrM?!LAing&hC=U8! ze^WDZU};L(X2eFkRB}ILsbO~&S{qcprESC)7Q>AHkL+si9Up9*O919=p>b4Q6etNC zS=GRT6M+O3gX;bJhT(i1K#gBz{T^s}t}gHTn!2+tI7H6N6&WvSsx(&&kD}jdP`%>> zdF(TvQe-Vv?^HJB0CK_pOJ@=D%N~WyKWA4b^3Ku~R(*Na0MEsG2Ly!uX8Ya+g}#j;?o&4o6%fsL(ckF+(6 zqp?qvo5rX*e_L9xZy+~@>oGH~v(x9#>|qGL)s*Z7ES4)pu_1D3~i{y@lvLX1hzdTxpkiVe4t4< z8#D@sBulcA@g53-E990U4?}Qo9%GP!eBAs*ZQz=;Ig6N0W|YLCB{$#9k8{X%Qc;6U zL9^$+U!z{AX})b;l1WYeL#wtjJJzHswe_8%{?Ii0?Ge&;gK&y-=3X;1h-Qj5+w@S3 zG7@}QlAwQcVSc>ij_T6#dkWS*Me3kX`HU%O5Oz7z7w z8XB!s?=LSk$A8Z3xOA$BzrbCN@Fd7Y#Qus$*ccj;GI>LJxgN3o<9KSi1{-zyX|pK6 zdxQJ&10R>n26Z>F@JPopgs&8}9X|!S43C@dJKbAvRu79K7e=BXL(xr4iB>ZQ2BKF9 zTGc5;CXX2(eb(Gjqlp3?;f`_R5#->tI()^;oPxFxwn9^5E3vCT_dF+!gi z>HIgd&5iVkou_f(%UGr#Yn)*Bzl7flfCFPpyItA*Umck7F9$9FIPgCWP*VCUt^4V~ zez`-OEO7MB`!?8B6)V;9)Euf*5uttTvVJebe#Wx$C_L8<;IT9x&pyU|0W{VjeYL~2 zVr(g;aq^&mb#uzQ#KJ*gpXjRUH|PBRodgFZWO(Ns6Z3=$qh@S}A>`su2mbLumuJUy zs8hcG_`)Tq`b~R?s`vreRUB)gKU(s06~KW>VE(rQTg-|@$aY^h6teyJoFE(#z1~>; zwq}G?l(Y?0Z+|H9_+f}K)@&^k3BTx4f>XM$dh~0ASvB7CMBA1sUh-qKdQToPd~R7! z(Ct)=pawi6mw32j0}HyO<}pgQktjp{c$a3nk$l$Fa%Jp}j3oz!t!A3kR+L=Q^)Woz z9GoVlJv6F%KO5XN+)nb38`Y)e6!4n3C}=TI!M<+SO0X2_7^6uti)74?`r^%c7AU8BpooM+aGQ2Tf%OAKEvCN)yw zLVgyN199nd^*!g&Q#G;tJWgc;r;E5NSS7ysA~!BcL>cq}8>J%pKs%GqQR?v`@Jk+1|`G@;eq=;1Y`6r&9FbMZ*!|da@Q%Xu@RH1Wx<0(8XnX&1G5%Xhw;IJ7L8N`?#w3 zJ}G`;mOB|9%DS@REe`b6dap9jQCn}x96||Q3>%jn*$;{PC7a-0lIF6z!Dtvmh7R=# z%ahvv`#gjYbMI)V%Ckg5Y?Guez${&>``V{Bl;=ZoBVJ_u7FND5o$Uuehs)7J6@{QJ ze}E*`NW~ICNiLgc$_?BL9q5Xbq+RCq4sKjHx*~>z60(;dV&hs8o}J4bW15? zUlnjmHokQH&KO>m+hC63K&OmIU4@9(%wSf!HQ&OIx+9Ns)u%FfTM0u@B7L9ObP^`_tG$>XI?DlxpqN0T(OoSW)SXxu<8fW@W7hqXez*CcU=2hXFW0Hr>WZ zGprd!Y}S#j>%f#H5MswnP!kDM4rx>8FXW{LfRS(7jkZ>Y00O!v`EwQ}fEjZ(H?cAK z^ZW1g?eU+d7M^IX*{-mnbl_LHeQ-Y0Ot>*Zzk$|jSgDuLVzy}1oo2MD{wy4npNJt6 zz|-XqyjGP7+`7_d3vE3yYjA{Tn3TnyPpxFDMy#QRO;4P#F>ux61V?c+e=?KgZ`8|P zsIlN^yNJfGAx*}f=~7M>mM6LbqW#Sp1ZqrvL6gvS?RE2N!nP}uP=EpiDd!@y$_lV$ zwqwoYP8o~e$aP8@>Yy;8K)FmA%Rq*ZBes*wsIY+?L)jb!!IUOB={Z0dc!#r_l#&nm z-8+!rBVYP=5u+&_WLE@qr&9GJYkme}$L%t^D2R@2M1$`b2^AzJX_JXU&Xm;rAJA*^ ztd{x)EOo1xU9cnsg=tE=*(rHRM3cY7&(JW`EV;`Zcyyp&vl=_Pq)Wr}*kiy1!D2E) zU<^!mn2af-b#5HMKO;$DHkdLFGrfbPDM~07EKCU~-rL)dESx7zG}Fh5`64rsYG6gW zv0phE(?cW`73s6QeSyN}W@_S6bPoZ*-zjhL>~i@8d@ z?&?)GDYnbY6MQ{S;xe+`AKiiEHg%_MndjjsDuD5A0CM{(ZtqQ+2<3%t%7prKn|k*8 zdVqbtV8_?#bK`@XP&x=aY^rCJcEVaL|Jlyh{bk^+a^v~_B&V~35yT57R^>Z^EFvWQ zB$T_fk_FgSzWL}nx>p*1nSlWzgXo|Hq03cy*kM@{?#v*F@5U&qf1!c4Nu z^t9y|kj^q|vInWP+v%^e!I>cGzIf_tBv1$+27BnNQOA4C^)7KKk14iaS2pPCIu^8L zVJ#Uok#Z$b8S!iqRfK^y4dM}C9_I}IC~~|n#<86_;Y{jzImJzMdve0!wNjgHl;QpA}qBv$**E^0utqGjBNkyFy1U6ov zAFGmW-0u=FKc+9+T(+uOY}aax4XWl9B+?>BR_YL|qS;2geeO@z#0eY{MNB&QzyMZ+y@p z>Lbl+ee7y2ooctzB|!JufE*@ThUiAE9-27Y@=rp?_z>Q{%Mk~){w$ydJO zm1;iEvkKc%G~NtZ1?m#?&S|x5pE(l59f?u~HGzf$^p<#1E^$&aeQC5~h9ucrAu_jD zFsEu=DCE&3z%PhopQjY%{Oj&=LQT}i_)%o{20j*>S=C@v38(V${^63EE>^FUWvLM( zZfu>?i0w6THlH$UUdqPgonbUpX(&!QxY}4-JBF!Mts#|e2xQi49&F`w+50C8 z_r~^>=`lWaYE)I|mExIv*~Fv9IMt-H?%Wfpz-Kvb;Inq8nXs*U(Jh_2dP!lr#`T(X z)1! zSuV?G?yT9a(1U%w5+jRpjUDs>8Zu8{yOAp|6^)%1!mC|%8@$Jr$o|XMAKXr`S!`W@Cc^e}7xm@rgbyWWMDdYP=)wT^;I0WS{@{l`{H8&kgWRH{ zNbX4Y$s~4%A`5qPEdh@Jj>fN1VOx2EVwJ8$e^TiIjpwXq));F7syqc{dhyUKD28Vw zdWu|eFzRG`8~bm)1^^cS()?iRGXNDP1;}Pm{wI?)H*hpDR&sXy$te7l&D z&q>s6fJxN-ZimE>!6o^?1Q(#+Ae)8~FphP$)|5{+wkER?pgB&AOkG)&8VA150V8pB zi>77@Qhkf{3=_)R(9N+st2eA()RKD_!wY=m>gJ=u6g8~5EgDDYU5u7A zgi^N602^uqvU2tALsw=A`KfdjT>YWB;Ed>jld@5U< ziOqI&#`|Zoa?Qe+qIW}F&(C|S$Fa5T0p{mb2jpoc0n{(X-0ufR(H{NJZa15kfXmHrph-^UjJiTd+KPXfLHo~yr5|8s~j z0Q~0=<9`AF{ba|lxBRI23;5sXJOHpi&w2a{?C)n3euWLw2KqlwEC2w1o>=%7z~77Y zzXDF^0R3LN2Y~)8-Tw>d@8#uRK^^t}0R4|*GXV8xvH4$6e=nr|in^}<*RB3TSrvf( zv#k0r=)c$2enqD+`bYHt*$V*Be^%Q51^xFr$FJy5CjW{4U#cDeK|iY=|03vjHvd;a zzGnX-=vQtZAm}Hz|1W}mC%JzWG->{ap#N>-zxDK!^8Odp-|5_6QMm!b#Q~eK|4!}# zZu=*>`!521r`vuN@M8Vn1pE*A1`zO*eESyxzq28~3h1=^L%^@x2mtaYH}Wr#zwb$Z zg^YIm1M>GBDggNB4)tGvf6pU+1!nO01NgsY6#)F7S;fEL|Gu97iXY+mr!Ib9T>;2H ZSJ&T=!2z3cARr{bpB3P$-|Odp{|mL|h&uoP