From 167e7b58a1b08571291b4f9a63c40d71cf08b3c4 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Thu, 27 May 2021 00:19:05 -0700 Subject: [PATCH] Drop counter HLD imported from community --- system/drop_counters/drop_counters_HLD.md | 397 ++++++++++++++++++ .../drop_counters_general_flow.png | Bin 0 -> 24762 bytes 2 files changed, 397 insertions(+) create mode 100644 system/drop_counters/drop_counters_HLD.md create mode 100644 system/drop_counters/drop_counters_general_flow.png diff --git a/system/drop_counters/drop_counters_HLD.md b/system/drop_counters/drop_counters_HLD.md new file mode 100644 index 000000000000..bd0cae6127fa --- /dev/null +++ b/system/drop_counters/drop_counters_HLD.md @@ -0,0 +1,397 @@ +# Configurable Drop Counters in SONiC + +# High Level Design Document +#### Rev 1.0 + +# Table of Contents +* [List of Tables](#list-of-tables) +* [List of Figures](#list-of-figures) +* [Revision](#revision) +* [About this Manual](#about-this-manual) +* [Scope](#scope) +* [Defintions/Abbreviation](#definitionsabbreviation) +* [1 Overview](#1-overview) + - [1.1 Use Cases](#11-use-cases) + - [1.1.1 A flexible "drop filter"](#111-a-flexible-"drop-filter") + - [1.1.2 A helpful debugging tool](#112-a-helpful-debugging-tool) + - [1.1.3 More sophisticated monitoring schemes](#113-more-sophisticated-monitoring-schemes) +* [2 Requirements](#2-requirements) + - [2.1 Functional Requirements](#21-functional-requirements) + - [2.2 Configuration and Management Requirements](#22-configuration-and-management-requirements) + - [2.3 Scalability Requirements](#23-scalability-requirements) + - [2.4 Supported Debug Counters](#24-supported-debug-counters) +* [3 Design](#3-design) + - [3.1 CLI (and usage example)](#31-cli-and-usage-example) + - [3.1.1 Displaying available counter capabilities](#311-displaying-available-counter-capabilities) + - [3.1.2 Displaying current counter configuration](#312-displaying-current-counter-configuration) + - [3.1.3 Displaying the current counts](#313-displaying-the-current-counts) + - [3.1.4 Clearing the counts](#314-clearing-the-counts) + - [3.1.5 Configuring counters from the CLI](#315-configuring-counters-from-the-CLI) + - [3.2 Config DB](#32-config-db) + - [3.2.1 DEBUG_COUNTER Table](#321-debug_counter-table) + - [3.2.2 PACKET_DROP_COUNTER_REASON Table](#322-packet_drop_counter_reason-table) + - [3.3 State DB](#33-state-db) + - [3.3.1 DEBUG_COUNTER_CAPABILITIES Table](#331-debug-counter-capabilities-table) + - [3.3.2 SAI APIs](#332-sai-apis) + - [3.4 Counters DB](#34-counters-db) + - [3.5 SWSS](#35-swss) + - [3.5.1 SAI APIs](#351-sai-apis) + - [3.6 syncd](#34-syncd) +* [4 Flows](#4-flows) + - [4.1 General Flow](#41-general-flow) +* [5 Warm Reboot Support](#5-warm-reboot-support) +* [6 Unit Tests](#6-unit-tests) +* [7 Platform Support](#7-platform-support) + - [7.1 Known Limitations](#7.1-known-limitations) +* [8 Open Questions](#8-open-questions) +* [9 Acknowledgements](#9-acknowledgements) +* [10 References](#10-references) + +# List of Tables +* [Table 1: Abbreviations](#definitionsabbreviation) + +# List of Figures +* [Figure 1: General Flow](#41-general-flow) + +# Revision +| Rev | Date | Author | Change Description | +|:---:|:--------:|:-----------:|---------------------------| +| 0.1 | 07/30/19 | Danny Allen | Initial version | +| 0.2 | 09/03/19 | Danny Allen | Review updates | +| 0.3 | 09/19/19 | Danny Allen | Community meeting updates | +| 1.0 | 11/19/19 | Danny Allen | Code review updates | + +# About this Manual +This document provides an overview of the implementation of configurable packet drop counters in SONiC. + +# Scope +This document describes the high level design of the configurable drop counter feature. + +# Definitions/Abbreviation +| Abbreviation | Description | +|--------------|-----------------| +| RX | Receive/ingress | +| TX | Transmit/egress | + +# 1 Overview +The main goal of this feature is to provide better packet drop visibility in SONiC by providing a mechanism to count and classify packet drops that occur due to different reasons. + +The other goal of this feature is for users to be able to track the types of drop reasons that are important for their scenario. Because different users have different priorities, and because priorities change over time, it is important for this feature to be easily configurable. + +We will accomplish both goals by adding support for SAI debug counters to SONiC. +* Support for creating and configuring port-level and switch-level debug counters will be added to orchagent and syncd. +* A CLI tool will be provided for users to manage and configure their own drop counters + +## 1.1 Use Cases +There are a couple of potential use cases for these drop counters. + +### 1.1.1 A flexible "drop filter" +One potential use case is to use the drop counters to create a filter of sorts for the standard STAT_IF_IN/OUT_DISCARDS counters. Say, for example: +- Packets X, Y, and Z exist in our system +- Our switches should drop X, Y, and Z when they receive them + +We can configure a drop counter (call it "EXPECTED_DROPS", for example) that counts X, Y, and Z. If STAT_IF_IN_DISCARDS = EXPECTED_DROPS, then we know our switch is healthy and that everything is working as intended. If the counts don't match up, then there may be a problem. + +### 1.1.2 A helpful debugging tool +Another potential use case is to configure the counters on the fly in order to help debug packet loss issues. For example, if we're consistently experiencing packet loss in your system, we might try: +- Creating a counter that tracks L2_ANY and a counter that tracks L3_ANY +- L2_ANY is incrementing, so we delete these two counters and create MAC_COUNTER that tracks MAC-related reasons (SMAC_EQUALS_DMAC, DMAC_RESERVED, etc.), VLAN_COUNTER that tracks VLAN related reasons, (INGRESS_VLAN_FILTER, VLAN_TAG_NOT_ALLOWED), and OTHER_COUNTER that tracks everything else (EXCEEDS_L2_MTU, FDB_UC_DISCARD, etc.) +- OTHER_COUNTER is incrementing, so we delete the previous counters and create a counter that tracks the individual reasons from OTHER_COUNTER +- We discover that the EXCEEDS_L2_MTU counter is increasing. There might be an MTU mismatch somewhere in our system! + +### 1.1.3 More sophisticated monitoring schemes +Some have suggested other deployment schemes to try to sample the specific types of packet drops that are occurring in their system. Some of these ideas include: +- Periodically (e.g. every 30s) cycling through different sets of drop counters on a given device +- "Striping" drop counters across different devices in the system (e.g. these 3 switches are tracking VLAN drops, these 3 switches are tracking ACL drops, etc.) +- An automatic version of [1.1.2](#112-a-helpful-debugging-tool) that adapts the drop counter configuration based on which counters are incrementing + +# 2 Requirements + +## 2.1 Functional Requirements +1. CONFIG_DB can be configured to create debug counters +2. STATE_DB can be queried for debug counter capabilities +3. Users can access drop counter information via a CLI tool + 1. Users can see what capabilities are available to them + 1. Types of counters (i.e. port-level and/or switch-level) + 2. Number of counters + 3. Supported drop reasons + 2. Users can see what types of drops each configured counter contains + 3. Users can add and remove drop reasons from each counter + 4. Users can read the current value of each counter + 5. Users can assign aliases to counters + 6. Users can clear counters + +## 2.2 Configuration and Management Requirements +Configuration of the drop counters can be done via: +* config_db.json +* CLI + +## 2.3 Scalability Requirements +Users must be able to use all debug counters and drop reasons provided by the underlying hardware. + +Interacting with debug counters will not interfere with existing hardware counters (e.g. portstat). Likewise, interacting with existing hardware counters will not interfere with debug counter behavior. + +## 2.4 Supported Debug Counters +* PORT_INGRESS_DROPS: port-level ingress drop counters +* PORT_EGRESS_DROPS: port-level egress drop counters +* SWITCH_INGRESS_DROPS: switch-level ingress drop counters +* SWITCH_EGRESS_DROPS: switch-level egress drop counters + +# 3 Design + +## 3.1 CLI (and usage example) +The CLI tool will provide the following functionality: +* See available drop counter capabilities: `show dropcounters capabilities` +* See drop counter config: `show dropcounters configuration` +* Show drop counts: `show dropcounters counts` +* Clear drop counters: `sonic-clear dropcounters` +* Initialize a new drop counter: `config dropcounters install` +* Add drop reasons to a drop counter: `config dropcounters add_reasons` +* Remove drop reasons from a drop counter: `config dropcounters remove_reasons` +* Delete a drop counter: `config dropcounters delete` + +### 3.1.1 Displaying available counter capabilities +``` +admin@sonic:~$ show dropcounters capabilities +Counter Type Total +-------------------- ------- +PORT_INGRESS_DROPS 3 +SWITCH_EGRESS_DROPS 2 + +PORT_INGRESS_DROPS: + L2_ANY + SMAC_MULTICAST + SMAC_EQUALS_DMAC + INGRESS_VLAN_FILTER + EXCEEDS_L2_MTU + SIP_CLASS_E + SIP_LINK_LOCAL + DIP_LINK_LOCAL + UNRESOLVED_NEXT_HOP + DECAP_ERROR + +SWITCH_EGRESS_DROPS: + L2_ANY + L3_ANY + A_CUSTOM_REASON +``` + +### 3.1.2 Displaying current counter configuration +``` +admin@sonic:~$ show dropcounters configuration +Counter Alias Group Type Reasons Description +-------- -------- ----- ------------------ ------------------- -------------- +DEBUG_0 RX_LEGIT LEGIT PORT_INGRESS_DROPS SMAC_EQUALS_DMAC Legitimate port-level RX pipeline drops + INGRESS_VLAN_FILTER +DEBUG_1 TX_LEGIT None SWITCH_EGRESS_DROPS EGRESS_VLAN_FILTER Legitimate switch-level TX pipeline drops + +admin@sonic:~$ show dropcounters configuration -g LEGIT +Counter Alias Group Type Reasons Description +-------- -------- ----- ------------------ ------------------- -------------- +DEBUG_0 RX_LEGIT LEGIT PORT_INGRESS_DROPS SMAC_EQUALS_DMAC Legitimate port-level RX pipeline drops + INGRESS_VLAN_FILTER +``` + +### 3.1.3 Displaying the current counts + +``` +admin@sonic:~$ show dropcounters counts + IFACE STATE RX_ERR RX_DROPS TX_ERR TX_DROPS RX_LEGIT +--------- ------- -------- ---------- -------- ---------- --------- +Ethernet0 U 10 100 0 0 20 +Ethernet4 U 0 1000 0 0 100 +Ethernet8 U 100 10 0 0 0 + +DEVICE TX_LEGIT +------ -------- +sonic 1000 + +admin@sonic:~$ show dropcounters counts -g LEGIT + IFACE STATE RX_ERR RX_DROPS TX_ERR TX_DROPS RX_LEGIT +--------- ------- -------- ---------- -------- ---------- --------- +Ethernet0 U 10 100 0 0 20 +Ethernet4 U 0 1000 0 0 100 +Ethernet8 U 100 10 0 0 0 + +admin@sonic:~$ show dropcounters counts -t SWITCH_EGRESS_DROPS +DEVICE TX_LEGIT +------ -------- +sonic 1000 +``` + +### 3.1.4 Clearing the counts +``` +admin@sonic:~$ sonic-clear dropcounters +Cleared drop counters +``` + +### 3.1.5 Configuring counters from the CLI +``` +admin@sonic:~$ sudo config dropcounters install DEBUG_2 PORT_INGRESS_DROPS [EXCEEDS_L2_MTU,DECAP_ERROR] -d "More port ingress drops" -g BAD -a BAD_DROPS +admin@sonic:~$ sudo config dropcounters add_reasons DEBUG_2 [SIP_CLASS_E] +admin@sonic:~$ sudo config dropcounters remove_reasons DEBUG_2 [SIP_CLASS_E] +admin@sonic:~$ sudo config dropcounters delete DEBUG_2 +``` + +## 3.2 Config DB +Two new tables will be added to Config DB: +* DEBUG_COUNTER to store general debug counter metadata +* DEBUG_COUNTER_DROP_REASON to store drop reasons for debug counters that have been configured to track packet drops + +### 3.2.1 DEBUG_COUNTER Table +Example: +``` +{ + "DEBUG_COUNTER": { + "DEBUG_0": { + "alias": "PORT_RX_LEGIT", + "type": "PORT_INGRESS_DROPS", + "desc": "Legitimate port-level RX pipeline drops", + "group": "LEGIT" + }, + "DEBUG_1": { + "alias": "PORT_TX_LEGIT", + "type": "PORT_EGRESS_DROPS", + "desc": "Legitimate port-level TX pipeline drops" + "group": "LEGIT" + }, + "DEBUG_2": { + "alias": "SWITCH_RX_LEGIT", + "type": "SWITCH_INGRESS_DROPS", + "desc": "Legitimate switch-level RX pipeline drops" + "group": "LEGIT" + } + } +} +``` + +### 3.2.2 DEBUG_COUNTER_DROP_REASON Table +Example: +``` +{ + "DEBUG_COUNTER_DROP_REASON": { + "DEBUG_0|SMAC_EQUALS_DMAC": {}, + "DEBUG_0|INGRESS_VLAN_FILTER": {}, + "DEBUG_1|EGRESS_VLAN_FILTER": {}, + "DEBUG_2|TTL": {}, + } +} +``` + +## 3.3 State DB +State DB will store information about: +* What types of drop counters are available on this device +* How many drop counters are available on this device +* What drop reasons are supported by this device + +### 3.3.1 DEBUG_COUNTER_CAPABILITIES Table +Example: +``` +{ + "DEBUG_COUNTER_CAPABILITIES": { + "SWITCH_INGRESS_DROPS": { + "count": "3", + "reasons": "[L2_ANY, L3_ANY, SMAC_EQUALS_DMAC]" + }, + "SWITCH_EGRESS_DROPS": { + "count": "3", + "reasons": "[L2_ANY, L3_ANY]" + } + } +} +``` + +This information will be populated by the orchestrator (described later) on startup. + +### 3.3.2 SAI APIs +We will use the following SAI APIs to get this information: +* `sai_query_attribute_enum_values_capability` to query support for different types of counters +* `sai_object_type_get_availability` to query the amount of available debug counters + +## 3.4 Counters DB +The contents of the drop counters will be added to Counters DB by flex counters. + +Additionally, we will add a mapping from debug counter names to the appropriate port or switch stat index called COUNTERS_DEBUG_NAME_PORT_STAT_MAP and COUNTERS_DEBUG_NAME_SWITCH_STAT_MAP respectively. + +## 3.5 SWSS +A new orchestrator will be created to handle debug counter creation and configuration. Specifically, this orchestrator will support: +* Creating a new counter +* Deleting existing counters +* Adding drop reasons to an existing counter +* Removing a drop reason from a counter + +### 3.5.1 SAI APIs +This orchestrator will interact with the following SAI Debug Counter APIs: +* `sai_create_debug_counter_fn` to create/configure new drop counters. +* `sai_remove_debug_counter_fn` to delete/free up drop counters that are no longer being used. +* `sai_get_debug_counter_attribute_fn` to gather information about counters that have been configured (e.g. index, drop reasons, etc.). +* `sai_set_debug_counter_attribute_fn` to re-configure drop reasons for counters that have already been created. + +## 3.6 syncd +Flex counter will be extended to support switch-level SAI counters. + +# 4 Flows +## 4.1 General Flow +![alt text](./drop_counters_general_flow.png) +The overall workflow is shown above in figure 1. + +(1) Users configure drop counters using the CLI. Configurations are stored in the DEBUG_COUNTER Config DB table. + +(2) The debug counts orchagent subscribes to the Config DB table. Once the configuration changes, the orchagent uses the debug SAI API to configure the drop counters. + +(3) The debug counts orchagent publishes counter configurations to Flex Counter DB. + +(4) Syncd subscribes to Flex Counter DB and sets up flex counters. Flex counters periodically query ASIC counters and publishes data to Counters DB. + +(5) CLI uses counters DB to satisfy CLI requests. + +(6) (not shown) CLI uses State DB to display hardware capabilities (e.g. how many counters are available, supported drop reasons, etc.) + +# 5 Warm Reboot Support +On resource-constrained platforms, debug counters can be deleted prior to warm reboot and re-installed when orchagent starts back up. This is intended to conserve hardware resources during the warm reboot. This behavior has not been added to SONiC at this time, but can be if the need arises. + +# 6 Unit Tests +This feature comes with a full set of virtual switch tests in SWSS. +``` +=============================================================================================== test session starts =============================================================================================== +platform linux2 -- Python 2.7.15+, pytest-3.3.0, py-1.8.0, pluggy-0.6.0 -- /usr/bin/python2 +cachedir: .cache +rootdir: /home/daall/dev/sonic-swss/tests, inifile: +collected 14 items + +test_drop_counters.py::TestDropCounters::test_deviceCapabilitiesTablePopulated remove extra link dummy +PASSED [ 7%] +test_drop_counters.py::TestDropCounters::test_flexCounterGroupInitialized PASSED [ 14%] +test_drop_counters.py::TestDropCounters::test_createAndRemoveDropCounterBasic PASSED [ 21%] +test_drop_counters.py::TestDropCounters::test_createAndRemoveDropCounterReversed PASSED [ 28%] +test_drop_counters.py::TestDropCounters::test_createCounterWithInvalidCounterType PASSED [ 35%] +test_drop_counters.py::TestDropCounters::test_createCounterWithInvalidDropReason PASSED [ 42%] +test_drop_counters.py::TestDropCounters::test_addReasonToInitializedCounter PASSED [ 50%] +test_drop_counters.py::TestDropCounters::test_removeReasonFromInitializedCounter PASSED [ 57%] +test_drop_counters.py::TestDropCounters::test_addDropReasonMultipleTimes PASSED [ 64%] +test_drop_counters.py::TestDropCounters::test_addInvalidDropReason PASSED [ 71%] +test_drop_counters.py::TestDropCounters::test_removeDropReasonMultipleTimes PASSED [ 78%] +test_drop_counters.py::TestDropCounters::test_removeNonexistentDropReason PASSED [ 85%] +test_drop_counters.py::TestDropCounters::test_removeInvalidDropReason PASSED [ 92%] +test_drop_counters.py::TestDropCounters::test_createAndDeleteMultipleCounters PASSED [100%] + +=========================================================================================== 14 passed in 113.65 seconds =========================================================================================== +``` + +A separate test plan will be uploaded and review by the community. This will consist of system tests written in pytest that will send traffic to the device and verify that the drop counters are updated correctly. + +# 7 Platform Support +In order to make this feature platform independent, we rely on SAI query APIs (described above) to check for what counter types and drop reasons are supported on a given device. As a result, drop counters are only available on platforms that support both the SAI drop counter API as well as the query APIs, in order to preserve safety. + +# 7.1 Known Limitations +* BRCM SAI: + - ACL_ANY, DIP_LINK_LOCAL, SIP_LINK_LOCAL, and L3_EGRESS_LINK_OWN are all based on the same underlying counter in hardware, so enabling any one of these reasons on a drop counter will (implicitly) enable all of them. + +# 8 Open Questions +- How common of an operation is configuring a drop counter? Is this something that will usually only be done on startup, or something people will be updating frequently? + +# 9 Acknowledgements +I'd like to thank the community for all their help designing and reviewing this new feature! Special thanks to Wenda, Ying, Prince, Guohan, Joe, Qi, Renuka, and the team at Microsoft, Madhu and the team at Aviz, Ben, Vissu, Salil, and the team at Broadcom, Itai, Matty, Liat, Marian, and the team at Mellanox, and finally Ravi, Tony, and the team at Innovium. + +# 10 References +[1] [SAI Debug Counter Proposal](https://github.com/itaibaz/SAI/blob/a612dd21257cccca02cfc6dab90745a56d0993be/doc/SAI-Proposal-Debug-Counters.md) diff --git a/system/drop_counters/drop_counters_general_flow.png b/system/drop_counters/drop_counters_general_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..c6620803601018ac823d25072790e361468a34c1 GIT binary patch literal 24762 zcmdqJXIN8t_cpo#(Gf*P1wo38ItmB~3Ic)@m7*XW0qKhL-jSB5qu2mZI#QG-U3w?6 z017C*caYwDPtMv2&dl>Z@AW_J!?~{WVRTG(es$G*-D^KpQIeyjVWvS4g!cM1X*C3) zhX19k|BVvmw@t&wCAK|UO5RKKc$+>xny8E$pIu*3 zoTY-zP;=s8y&4ZF_rpI<{r~zO^r;Bn+C)>#+A8s?bo@C7udn{}2*Q7=;tbxwe^X3f zS6Z6+aFy@WHMm~&cgXW=7vCXN2)`oDhbKWNY4{PODgOWC4{P*B6jI&n#>HGLoG)!t zG5Odz*WtrW`X&@~F|*1(9wSr34O#P^ge|kYq~`PUn&YMDh2D5g$>S7~WOylPyT1=Z z9Q*b>FjsFfm*zvW9K~+LD1zQ7JknXRCB|n=x!nGPk9S+a#s-}qC%%!1nhC*Ls9{YG zyehWZ`hwfurYcfgR>dYr?3_jo>!11raUm~^4_hnO+s`Gq1vP*NOs(y+EyPDn|3+2Cv%| z2FIpfu$fFSnapM}X>nZnq%HawLGZg^>C>F}^Lbz9kJH%On*6z8FN%fFzrg1Y-RVBu zIBxNqv+*8-5}&!wd64$gZxL9s=#8zy@07f4!5Y}B8B~0_ZH&a1nydS*JH1a3#N)jY zBsLHZ?4{(!tS6tJ0q>a^DxT>iP3+ZlDn9S2Wp@!+s>5W~Owz`zLHTr`*{ani1QAR? zYP$dQdr*F!P{Uy;qKzZKMGfVy{l%#WPvI9W!)V`P8mZb~Sl# zRZNz(4-bM^qIa-0Bb;Ae>cqME5l196yk6EE4o(<+1Yk`Si9d9?Anb;-Q>cb552X# zN?d4daOwyk>NNBS*q_!X_%+kmD|sw_pw!C~Jksy_1^1HII|)wV3ohJbazn^kqBBK+ z3aOu`H#*2Am#B%IlsOE?Xs_xv`|5(H;B5p;qlT4ob=IKNeKNhE*JpEjv@WJj zQ*q=QM@;E>Vx)(MM|Ks0$dI(p@g$ACqDCJGF8u|OYJ0%}?>%zav@Jr9gd#;3KRw!) z^Usr4_t}3Rc)Jfy_g1!P-Mg9IyvaSQ2co|TY1Fm1w?ClXXIs8La+pIY{z7uM?5Q8$ z^iRx8OhgFV_4>1kp%XrOi)!|HG3vsRwYdb^$N<^H28E8B6VdnKRI+J<9s2S2b#03h z2s*au2xjAR`C0{^si)pzr&VT!L{CpohcSZvq(VB7VM;v#vV_1nzS}FgFhx)-QGVg? zXVxXEGqg4;ZE7mF+cFap`y1)b zo~dK4WUDHLrzHX-=CWP9SqhG^96S0wKUmL$%HEdA=?osXVuf=hUNBs**7DgJVi#r` zee+n^lZ78q5hR&BY99P@{!)}qkH81};gy7dvhv%D4MU$pvuTHePG?u^PbpH1w6;YG z+ZhZ6_a-XuLBgEKzvIJSDBDhI%V5`Q?kTzZJ=*+}ukYErEb<9AAF{D*wiwMCZVfVW zYo=Xe6IpdN1iQd_nj|gR^!*WK56#}~?c1FDu_I587X}0$7i|}8j;v^4DX@1)QpcrF zk#W>(w7YnePWrI_mn)ZQh3K_6X@#c4Jqtd7C!+_8cVhV3J+f3NZmgQ6}4HFRrPJKD2{30^1o*Yz9=g1CJZv-)*^B1kYM~S2}zu~}zf0>go+YEYR{z;*As^i1@7@SMTW0p7v z`la~BH8Wu;%3r%SH<|4Z2R&tUS(QCJb8q-7C~(K)qroE&$}`*+mEMB+sb!`P8&t#I zR@*$_pXN!xm(k7Ym0Gqn@f~CK8r93EK(M>XtJ{3HA$!=Lnbkz(2x^;TNuPeEXFXOt zxAffi-Cn+l8GW!`FrhUSA~no~p4h*9%!QPzckD*6DQZ}*v(!wc z(w3iKr@VSa-Y#`gf&<`ItyvJMVA6^27qB8<822&E;>>W@v3st>#2yZqIaZBysE=8G zPCd#Z>vX_rR!k*&DHMqFS<-d}WLel)&>Mz}hBJkW|9mp8LkPk8$06!^H2k#@&3}Oe z@xa_2#pULos(krOx)4P45hZ%S{2ZW@&rX-VFLC=8Ai z53sC#KAY={qd7NU-&^>`VOKn!7#$rwb*{d)_oIMS8(re*EjX0}boyU~5G3d|44Zcg zn^bSAZe~zue|v=~tiE4tv{f9_-|Opk)*x^4DdU04&*;G=!}hhrsNJottv^1X7Vh&} ze0rE8`zHGnMbPFaw%xg7t}ZU$!6H=ovvnB9(yDsLA#$|-=UIc@`#uJuBOE1YwKk{k*26GeaFfDkIExotehry&$UV7wqfXdIG&am^ty1C`2RL|XTO4YDE`T*FTq7JrcZM6H^NVD~9 z$!xiK{`h&jCe*OvgJcf(7B07gecY#I8*sW5yy(tVpM#aQ#Z!y8^i&EXbo=+mKiW%U zKQ=L8S?aO>M$_C^bHRasLIAnL5}vntz~AyGfdE)FQoiX$E`8)5dAiS@nQPhxZ~stw z);rma^TNQIK*)vLh>*Nm2@XJCe~|Zmr)3vKv5WSPhcZ?G6%u!Gc1`IE=xFGtT@I-11pCwrtaY z)BBOy10Z*f)J!QxpaABdRwYWEz#f8G9Gk0u1h;~}p-vL|GbVFUPLt7+FC*-EzMvP5 z->-`0%DBGo!>!o2CuNqsH!7~GK8)Khceoc^K8Pg0IC)xI7xw;$r~5u^B3D1M9V@P1 ztPcG9-c%0nMiNmwcbXS(Y;3&m2v69K-@Vzk^}TQF`*xexN=}U5vrQ{-NaF)3H&e64 zbtD-%W5Lxx98$cL)dmqyd9j(1LSHhvsAUz>qU^7I4x7vzOf+TTW@(`diFRHSRFMKr z0!OEtpTQR~_b)pNhj<>A+M+}ey&$bQ{eZxI-?nVq%jIkuEB(KBs)$q`D%z3MOtHbegr>i5P+4$*98^i2 zBFjN-5ID(yspmK&oy8|aMUiCms03``5|j7J-8p{Dlm)^xI4rPdg$|(Z?r?w4wWh&% zxNi4@DFAyH>$EfG1M^Q{OF&@I=*j#O$>AYVRdE0C>o7&IK@b4uXV`%U_(!>-u8{nf zk<$Kv7Z7vuM9lTn6o~&T;z6+I$)XjeYsUAYtXZsiTLUAADuJ;gNH*tj>aaWG(~@P@ z`iAoK{hirv!xT=O9uyY1*qAM44+F2nUs+|gt0QEZH& zPp-bXW}^P+Dyvi=Ll%PDuFm1Ztos*)*434nKDpN7_!H-~)xw8a7$we`yE>2kcEI7p ztHwZI5$pqQJ&I!&MVXQwbFe#$OG{^46DHWIRtd(gFE}syiX8lw@cMuQQlV8yx%GND z#^JWK^n{aj1&7bpFvewl%d_M5yIR&k=|4l2M88nb8)nhW1=>iq7cZ@J?|b;<>r4W! zXcm+H&7VGD_;-#IicLphMm0`N3c@IEyQwYIhi5hAj}zxVObHikbzmUT|6d*x5>b(k z7-@f|TsoH!U?%sh(ecUQz{K$vuuU$&2{6R+fCv^@c*Jwn>rV&>L$1Dgk}JQ5br6w% zt4%H9Pbg}mIv5yqKt#+LeyFL6r7-nHW6me=2OBFjlaVVY{)C!8{L%RF|NfV1L2o=~ z-WnQ|yD#^BTnpaEM|4TMxY&*p+wPl5>yt}ig>YF^goYnKrGibk_rq&(F>X`H#7|Ik z{Oh+GyJi1N%L(1K0>P`T-UAb(%((L_D;YHpCChRr*K_*DpVe*FWHq?4Zx<9rb=8hb z5|{YuqLd6V--8D}hk6j-W@!oct^e#AHC(Idjy|si`FT|BLRMjDlDZs+(#DHXOm1TSX@>s!rr8_oC+uC%hsrPGte@&#%qMpC4QVlk zb9CM_=bzRk-u%WYOA&HiV6!SCf1y69(toL9z~txbv9ET;AOAInMDo4I-9-(a%7oi* zKKI1F{@Q@?IVUkx8*QBMx@ha^?A4g!!r|~G#x$a{qMO8O_tmT}XZgZfBgmvhoE)bt zxt;W}Y`YZ>lJ8>S?OiRzbep(omWdcD6yMOm$hSFjOXd!^s7HAj6Gs8|2r{ z1rki9>;nCpV0))^!L!FU-i?wSw~BK9Hvq1twm`RMPV1UJ5< z@&v=}I}%J5tfwxn&UAMsJ$aO?>qRmCB*=4c_`Z!F#?ANRAsLF@VQe%Xyg0}8c$M-U zCt1|FGsb)FDE6HR32rZNtBBF6tFyF|Of5Nde!-1+u{8kaDX3XxVa^j!zHa%Z(xfh3 zj3PZMBcZ2Jz0uc3RIcXBs7(>hqA9AWFUz7Nq$7Zm=kQ(A0R6U`SPqFVGKzl7T5fCo z0tSTj5uLsts)u5O5~bupJAEZ{&;w3QHYm#;Nhufl>7O`=#7#Un3Glq z4u4F%K5F0)t%2$Iv+QOX;U`yAaYePry_Bf%3*u4oqqh~SoqBA?pW;M6Mp5C1=Gb%o&%u^Y#{ahG$czas? zr>m9Ijl9oBPXU>Os78CDapn45V?&$b@^9n%&x64ur*3+!{lynmmbYP<_9d1I-HxUlZGeB!n2Rkr37wmVovQ^>LpZTpISMPqw)hULCr+sq5ACKOgakezwXFs#w<$+U2(9^mtM@*BZ zSW-@Hw-&e4A!_Z@Uu%z*nC2kD5ZU=RD?e~?8A+$B8w&o9!J?>@9N#q+-y0E~s6Eo3 zd)hTMW>@O?z1!8h%zP}=w+-L6{1|_oFX|oC@nYw$bF{FL-shGrHn=97MzSz&7PG|i zjk?qhU&p^SyvFyHlJlV1xq0(~%5skj?0WU@)9qHLK15M&ef%~!{4pjmlRw01b>BCW z2LiZCClfQD3RIGQ%CeR?`X*NfuYYdN6TAqgT>KpuMwc|6WPU?5@q!QMKN9`(^^b3Z zdefh3F#0$`t+1q|tFs}qN$A;tFY78pH&WCuidn}YW_6-YrP~4@5;>gGGeQI<7dMS$ zTd&tim>hYB)O-p5XsjjrM>G4W!H0VK0#3e#*HYhBjJ8T@Z!YL~KkMw{Oc<{U5ZNEX zxnn4g(|Ml}6D}U9o*THf5<6qfCD!&L=bbZS^^#^TU5wIqBMSd7-|nOpZQPRh-LQSQ zz+XeX#>Adu-W(lFpz)I__EGlzI0*17s@#Hg zE#o)+r|W$9+mxc2Q%8zMkICD8Da)@4u4FUKN0Ph;FQvJfhIp?$ZYm7w3^yzjF}y_l zWT<2xq0L8VJsgl7f?nHC=E*6+p9xab#_lu0HrL#|G%)|Ftju?=bXhmHUjo9cHg9`}4_@ zH(qo3vwf=#Q`b~=AR1{DjBg;@?3#;vdvX;B{xgb;@KZK3Y&e>s1;t+{V8 zye{{or5DCM``g?wn*li|Wh^d!d3vqMx$^jdSo&u-v3%uVr4xu75JLPkV3LlnzPR3R z6Is5XYj&VKoQ+Gq=D3nHbJMw^%*u_)J`xm(NVX73q|hS8F7DiOYTN%QZ1mo+EXlv(5F#m2`&Z9>)0C z48JQlwk7E_nee%>1Li!zZBB83u}?f}vkQYpVe7r(?17f172EoNg+-MvEQ`5a+Sv1% zswC&+l`4lPud9d{w+hv>3+$nUy064-{61V$-l%C*6sp(<5t`IOYNkOReqG8j zX-E?+6AD5g_P!fQfelZDjLG3d7%zqMd&s#ayX@{l%nPW8Q6if4y!p*k0b#R*92ns1 zR>ppa^dSK{cC7g2GzC)2O2SR{OI<>1ahd!BoZ#8!sRzzV6a_32GAfgGcBTyCV@2kQYWv*Q5aQ|fS=vw zCeGHEIy2ukAolv?Pr{lZi?8FBJCfPS@RS;Tl#-mN<=O!zg5qD0+z!qQ!?MoJi#?-= zg?bF&a=Qx+irzLfJj0M0ayer`_Z>8|2JUNX7LZU!(vw&m>yC8 zT3O;=lcMnQ($d`kit0EY^Cc)>IclVOw!@+fnGP!Z^YPr9I`|o)a0WDw5md%1MVw_#ua>*Cq0LuT!kkuZ%_?YfSoDR^`57cWF0gB0%_;Ag?V6wbKPS+->eg{t=}5 z1}v(R51-tvBual#|CDWBSNy~9rY5KDqVLMIDr(DD<6?Z~UxF+IMW7&nA=W7_R5v^p zNm4v)_|+y)c?QY=Y~SFRMB$3j@4J#SkJCEZcD`q^{S%OE#*o?-+Uc;1j3s8XT&Z!-|ku5 zbHru!ER?$d#C*qO#)8DU!-=JCQ@+`KTv_EZ9lL}Vz>Jj=ihaplKO)^XH#eK2UNUp% zQttnK!dG^6CFVyfrBom)WH>Amn^R}f6%V30M21VdJ4{99|NXfb_ zq+eun;d+ZpOIu=S1bi!tiWdqzxA;)lUf8!3KP`O2W3$i0;)8R>WCS&{5hdUg?0~ug z);^>RLxt(?JS_U6C~BoEEXC>I$FgV@5A2I_ zsr?)o|EfI!3$er@!es%f6A1%Nv}k!J(ff3vyRPR3WBJ@85GqNRaTQP7#)%{Hh#*6Y zFpWJkGh1*w+?^>2KZW96O7?Q-Z7bS*)#9IG4sL$wndKW3W|Es7Qx}DMoJXV39L1?) zgf6%E@qYZ5{eHWRR^T$*Tp0SfYNdmVCj~h&ayP6J zz;Y=+keeGZAU9x&enL45*DRI`7$mvYM(ek`zZjN*KFAGN5n2g^f*%T*05C%fC=N)_ z1(Fq~2x|uDDerAVq^q*`9So8p1=GU@l=t zfYZ+Ur1aH~MR0Ws^eN8XS9(XXbx2dtW7$mit?wl8^FX=N*)Elv>gGAg0(^Rf{GR(& zOhH5%yD%PrsRwc5^MDaSvT&Ou+UGiO!pQ?rrWbl z!WcR*#(7bp^7kdeDR$m>6w~TfphEtBp?-{N&w*~o8s7Ab;qsMEtK{v+dK5~L#U&+B zq)bRa)I|VX`_9m>{n~~K8~&1onJrzUtG?kh6H%{3#0zYo;EVu@U_;^R#=y_BlqFmH z@P4mBR1NaD5A9>SBq(~bTk~YNRZn4RYHAjuyrqXd1kl{O4H5#yzYj&Jz`lWhgOY?3 zz{pXnn9T7rwoSrFn_<6=4)$v5GBOMYwS!slM-IwxblS-s@KdrwY(Z&!{8Ke$g!NCX z2pPpr(Hqg6(ck5|&WOEu?$Y_r+gIb7q&58njD}4sEpK9V#o1!@;1SeWg9HKs#$NzB z5AvYV%b1u*n?GN9jfTIz1A-(*ujO&&txe+bSB_nygfj)QDQ`q1?#j_%Z-qXVb(3s? zYBf|>j{3?bovSU{-Q|usNzF87P2ywdMs8e_j+Y>lG@Q(!-U8wP;AQdZKopdDFG_fE zb*Z@f(dLimYNNA}YM$WERlqT7WxQ?hqZLXIm&6dZU1kc0{I&0a0#-V1D+a(L0z1%* z)VW|2bLSzRdJC1MU9f{lYUZ*1J7f=)yJYLFLg6c`Y|q~Bk^We!K!;A{?62=>EX>|qGxWdRhO1J-?b^eJ6>ujkzRFZVL1ffu ze^A5R*D)~EH0K39eih&9DSqv$85~&H;@bv`KNsTxlx}WmG1(HRKl`s=Vc$@xzoZ?P~({Zn0|580X8IUew3z>|%j*4bEPfJt^6 zgX$GPrNY=>Pvk=xe8k>dP)g?4*)hB+wc%;U6A)%#Y=#h}6<;GLJqr_n-0%8`3 zrGZ^GmXKVDq7F&nY8)D%!D(|Ch%jaT0N6SMz&2bp)B&q~4$a~)OFt{Ft@LlNV#w@> z=q{p%dL!i)nP)N;JZ~tm_OrbEboh5jQ;w(D(HnuwNCXgyCwW`;yXV5Ahs%@f+cQ$d ze{99ERZX@j9|z0^Rw`8nI6M?&FrZgpiE@=GLQ>buB-h8ob3%vY=B8)azuG(l<_voz z6xwIk7h{Hn^tAv^QUaJv7UZW*9D|3WdCG-%yfD5nn>FxUvFc*dZYHtj35S$y$xeq$ zM|ve(CBzFf1JLQG^J#(PQMu1)<3k=LE4w{l!MUHGy765&QUk^CGGK=2-#akx*juQ) zy(d}A@PpR&HZGozPx@iH_bIMCoQ%h)Qz!50GVoZ=r)Rb;;r9NNMe{Bx8}lXLY=A8{ zmw^pjzhL*^@{i=>ZN(-j{=}_T&*V7So^*Y7CH6C&rq(?T7}4pM%*Gy?8iQ*Bu20hK z*u+C!GiKk=No4Vfa~ss?POF#Pjas?xE#_To=QEq0t8Am zF<`Mt_;ILrDxXa-q^A4p{ox!T9cWBzP$VWX#X_uX;dsB`oZ>$Fv~T)?N)Hp1OFff) zJ~%snZDz8ndlsPXsX22}Zt&sMQ4w{+^DL{^tt|b@9D*D-^p*_`re0Uyn-N`!H&h^jEd>VVp{5+ko6yu?i2TrsCp_OW#mL_K{Vm8#6V>sKc zsXL^5Pb3;%pBc(sU*^P9!wCG;sLuio0iR_7QVytUI^~;^vz_hNPQE@;kyt1HFq~!I z97NFs%g?%E8_II7GnfKGj@;?9_&l5{bFQAkhDcsr%Sc-s!U!Qb-We3KH+NGy|48f| zdZVHU=Q8I9tH`KpSgfcL|1IauM^23$>8FoT>T}~2x$vj_UJdAY8*cW14>uD^usUeIz4;b8$X5XIB)!x zXI1)^@U+3sYV!5k11Di+`Sc6%w;L^Xr>RV4O*8g)hSIZ-rpJv64xrM&zYnaPUAtE^ z%<`ENzwkC~V-xfALFo3SUJPcftU)jJhQ&?n$%gy5&51xAF~0y6mN(r#16~upd#u=x zPfR{ko_g**5ffHD4XP(|Qt`S=8KKePXT$7)=C-vp71TJXc6Ack4&S>ssj^3hagK6*P?VO?j6#cspokE#!X>kMjcO4U4yee| zdw&TuX*WRtlZlaU% z{Q5*1QZ!G4i`niiXJL>lC|-jOQf*F7ZJX-HAb$YMGxE#Vs2G5l1G#~TnYNbU*ChNeKRR=rHrAhJF1I0rO=7em;SAbzLc*-7v z%}3k?Rr_v3L0$W3b<4iF!5ITr$g^I{ni!HNUB70(S-R#qP2(Y9awE*$e8ne{ktLHD5wk=htZV$o=H zO}=+*YN{3RB*a{&z8<5pkAg_ziPk#gKl6@u=7RhtXyTND2)h8MGN>2g6=@2<5Pr|} zSA9BkQd-=9Si1wN`R%u%sN8Y5e}hfL{*Pz2+j-s7T?I)Ko)A^_Vu;&rJuX@)A5k9M zv9?kOfBm>A!XCJ%V}5pQTbMgTCSuJi<++n_b3;*7dKN$lbLV~(XfY9yu#V6_&}P>)j0m3qli_`up#9|JaX%utpm4blqjA}A}jA2+bd z;ZQjRp>;-wkUVwa{2ey3xfeUl9`>pH+;<*>cSSC>4J1} zrPYsr)9{jK#2=b5(cGLhhc8Mq3qU(aJ7Oc zfD;c`nCwxdCfkbVwmenOZPNnSKt{erOMOdtn#Me9>O4PKVNw&)16KiJ>(4gwJ#uv{ zF2J;FBG*F{5&i^06-w)PEGu_vC8k*lO_-?p@agdu1%r7)H1@^b^H8@h@^;u`-eS}g zJkYK|#sVltz5puD*+k1ICWCUi0K-OAx0Jh15GE#N!*NbvE!!QEYb zeK9kCHLq#jhML=f7RX*EX8aiMG~JUjL17DDhW^Bfq#pSKK7YoMwdYk={?sh?c5uk; zFw!lf)u!0ZNqIHy?I4OW(7*w1SQJB>e^Q#&6pvhuj>T$*j3VMtiXQJ!TQiEBB zNI7kHA}~zeEww6_@cBH=qzp4J~5Wt14NT_^us4$ z}@*JQ492-i?Qv- zy%VWR(ssyh&M5Z*&%s9z0Yng>^%L6uGboDmJDJ}TgnP=}0sVQmAGUMGb8}GeRnh!0 z-0O*niSvY`vCV@m_AYf&%*HS0wIZkoEi1U^cJK z!AjNo*Yc!XB$f)&g(G|zNSc66`B?VqI0-D!69v_9-W)Xl1b>UjJQ*JQmX%FqYxw4$ zEJej0vIWTdAh?s4Mv;L2A1@PoQgGf5Z_a+9Yny&fF^0f+z%U2!p}V6oSC?hd){xbV zZhWPJB%HfrdB~B+v(OKMg2gBMcI}EHLBIW$&l)2WQF%1THdWqIxV9s1=a5G(UTbQl z8UTqv)(-ye8EPKrjVwWWEla%}(q4QyU~9Nv>hhOVHRc_cufj?a27zQy{EDNp5w6^B zaCWFjQStj)UX2^d1DubOl7xVSM~HMiY1EaR*4!q^YjCmmImGD)eE%Ey`&$kR2NMc> zI@3F+pQCO&ZK@x}QTcuTN=~ua9|qXQdUGPfz8n;Oq&G5^11+NOCrkej>#0^ZJRAyV z5Qsdu@x-?cBOkE0$izY?PPkkE2UG#kCh1`c>ts(k6V^hM45ovo^Q_fr7B+wq0y7i~ z>LhF}!AxB!MBa!Z&@kg6cN@H8F4zt91CW086RI9f)6XH(`J>uC!nFpbE^vQ2F)QccjGooYZhdAO^Mu0yYs%an*MRkAJKJ zr%X0)6?SqwU&2+=ZlEURoD>64mf&z;gr<7)F!IIRri9Jp>ZXGLCiXbW(PI74DNzC! z7v8??-Ha@1`tsnor+)tyjYx&V765dIO!mMmKNsohZYS;s;OWOROHkawRdk7D8RSfc zcpS*oVD z=dr9h>Lr0vECc=rL=13T%&$kg%^^B~3oitAD;R7RW<>@vs>lF>l+sf!qV!|%Lq8ml z@PoGv8h?>yl!_zEK5BVc&obK?T6gkdCxcm-r!h?9mq=4lO{d1Va`%+40aAcx zzbt?l?N9RSP$ngM>ZuRH>+xj%SMP;G(r2V7y$^iLR z=x@R80c7+JX;Ur%$>}Dc|pxxCV>i{z0E}3cCPS&VL2W z-m}-AHYiygxR}N+sd^8^GFBA;lEcKT7>K&+H>XV%>Yw`mZwP4P&07tj?CEwmu2sx> zR?_UIhOKh)m2ym<+)x3*Z+5E!NLq!C>uRndW54Yy-&o=xY!iQ9*TNB-iCI7Q5H}6X4r~o>Tcxbs>g{FsY>5gXFQm!%*vj9 zQicKztGDv+D%4-@^%?F6#d%eA)r^iRJx@?yEHaVY_-yC3+9A2Vp-V@IDN(VL6U*qb(ZiZz zQZV5KLvB;lbp(EQXl1`A}lZ@ZzkA@6$%Kjo~J}k+}kCWe5GO zH$S!}6pa4xmXUVl+y3rNv{H19=j4S9Nk@j_asC%Oh5TJ?12M!EWkbV_tnR0oPrl-_ z`??p*h-kY4nq8&8L$2x$7M#+3;BT~*^F;7F%;-L#z+MO3w*;ucr*h)!L)L7*g~Xop zLfLHu`G2w7{`2?0a}*Y-8ypOzhv`w8S?(zx-Rx6izmfMwCb)GT!tr(-a^6K=;gP@t z{(o=!0eLi1+5gwlFOyG^RO|n>Oths1Rz+gS?HsS13fAn*Z2IOWK0ZTMu|kdlgZNTN zDkDaAP{gXod}krVD7Y?9PtElA5(>Y+AuK8r7rMu%N;F49jpJq|HtdXjJ9zMB*2j3V zM$Gq}Wn#<-M9+O&y}Cu-BY)D^n@R6nhv3`)IYX?4DE51^=*`^kWBR!2dOQzf|Gvob zC?D73-n14)niZp`>AWqcuJvsWX~`01?r$ZAUt8H`Cv)|P*{2+b+X+jI0l`3%n7rb z_c5NWJ@z?G1>1FFLgR2yEx-z9xTatq`=aXA-q#qW?VO=~_JmC$&_`_Vo%X&u5oyyD z1$7CPDIuSYs7mh2#xpb@YHy>>d0V?S50q-@E&^`b=k6&@5fc7O-jnmPva+c69qIO3 z{LZ2D=Bs8IkudPtH}tH&M-6X*^tl6zqji{>qS0&{b|BLK-F{^c;kZrWZ`2|sA8ysw zggL2UGf(Ls%CyT@bcDw zy2gB$XKyJgfAg+&_A9UmREq2@eSB|uv32)eL(e_dkaH?Zs&2fRkd)DJvS?cz_p2I@ z^NYD?VCXDIT(8J2H}F=7>5u$9+54IHwUP?PmzxsGbKA<1gSYbP-XnDy@)}sQkptR@ zAd8!t-$UQOV2ZXy9^N9gMRJXA*blXCEGH*cE`(~%W^8wf%+Dn3iRsoN1_jCC#8fuz zf(BO68n`BRK|>`9SgomKjaRSn8TMYx-RiRA#IyarqX%kMenT;F9ldUS-gc$)vL0b) z4^~MOrG7zkW{8@)O@Wq_vpVTBXWHC8FcDYm5uRc^ed{nLB-e?)qI;vVxtHUOgk6&x z-aw1OKfr1EIXiA4Rk*KJf6C8CceBgHu4Egf1V%4K&b?JW7}+b{xyDwQF?$1;grN;f zm?QBwt8ZePj@o4G=Ee^zLMzhz;TNCQf9~7k6nR21^JC&<<$REaLz4uGIM17(bf$?J1?+$}elBb8XnQF|c<0jDu|f$f-Amy7)4`z(^I1V|BYw4O8QfLawLXw&-p(}Et6!7+K zuQ)GRTHC4OtYn`T&J(qH1++<&Z(5t9yVhCYw8wF%o0sH3N|ct<*F*J zbaA;JZV^!m6lVeRAX|9e_|(E8g%ZDrBmMO)EiEE~%(kqkd5Ex7N_S2;qSd!IGQXp; z$C4_tj%e?)y{9&5nzB1ZX0+8%i{i)4rqkTI^!={od&h65I!2xkrtJQk*7zFb>MV0S zPpAQyi1>397p}`SEKlE15Mc6oP>nXj#xgB?T+Jr^kZ_rNcj5WfG`$G_FSZ+j3C_P< zTHecu>G;oKOl~zj z^Ic%`A*-RkGVOj_@^w?_^ZT~X-m~v7pgo3i(eDr?B^0KF#)*Gi;~g%e^jcl80RV#k z()kInpz)Ks-g(S=lkdhQuIE|h6!`{fs86yu{yD8VnNg(LRFvD9g1E{4b9AO+<2^4L zgL^CAb&WLL2AIsobdd50fVh#>4Ek%S1hj%;w^qu74w(Y|THcFj=C zL&{nnb!=Dd7iylyQbf4qP-LC2?%=LA4)upo@whxfsgo?J#{JbN| z8?-1)L%;-%6z{WtUVsxyY*pYWlL(inh-c4PAKi{MZEH;m2-$S@<7Ocm1iJox)O*W` zenh@lvYqkVR31&SdxyBGG4HdV-k4_J8g6--?C6&pMagP0DvmD#Sp9F`)%@uTt&n0M zgIKOdXy(pF>1pg!uXx&SKRn4^TlXgQ?&|}NN@CJ=Y2PKH97iH!*u{$ZyxW)V4H>se zDE#@IvZwvfB)65<%Tz0gQr!~jLYX!jVkG|~O0OM8seeEWckg$MHhZmv_&mp}jiC2P z!8;^Wuz{bBPJeA=wKpXlHRX!>f?8rtg=29XnS@cJrsNdp5*k1GQ(_95cQRwBi+!v% zKKLmIHvS5Nnm_HL73!RYjQ0K%4re&5B3Bj-J+D>C=ZYfw7p6Sw- zU%WS_erveo7vU3(a-?ZY^$b<_;DU7;u2`2u*xcep37f&~zX+SS=0E%Xn&iUIr>)U6 z^@&Eml297zOI@)^i}B)~mh>5MPmPHcgxX<|eEQwTV4c-*wCS=Zl|NWO(^uuiq=0&N z_Wq6ZyiFv=eYLTx>IXO8Bw!~rN`9o7BURAk^YB(|xC!cpbSV5$qW`>GfN9^%Jhv*P zTr|PaMm?=Y{8Y@ObQn?7m45H$xJ>E$-h%$dc3x~{^{Eti&(pA(k~ zZoOv3IVP{Nlh~f$^S3EklYh90aOwUaKu9^XeFaJ)uK!nYM`F|D~>M z<@wTehW>21ogk?BO4BA%(BboN6A^%Z(t{R&>B|Q`?fb$F@xqQ@K0-#S`R#g3*~DD$ zrb@ie+o9N)isiYV?N-?dD=U<3j-`1<^i*BD``~ZuuR!YYYNfG{+xXa+{#g05UmQ7V zRNIQ@N^=}~Bhv{rA5yfPoX4enH#mBX7GI0D6GPk_@_?g^vA|)2JJ9u4IAqD|clSpb zZ6TY!zJ8_T-)sIS%uU#P!T&+D1~YML_qE#d{}tU@TmkOPq=)b;6hG5f#mID{a=?Pv-=T;423&#(%uu!$j_;LaT6 zU7^@&Tm&zr(7=N6t%`=$LxAa9Q)Z#Y2O(RCHxK6-5^_U%ThH|uTi9R z1=>v37SOVc)q#=O7!9p)CUw@QT@~u|=hq?|d~@QL}zrlx(m*lx6aS zs%I2vgv?_}eYL8vr0SAzJly^Fj(O`TMC5EQ!ms)DQ zk%0DcT^>2$di)_IBj(pbDk5BrgKDGWK&T@blS1BSzYlHDw^CP5hpNZ>Jd25Bz>kwc zB86%Ti2= zeioc%v7xR^p-u)95fx52sf3w`j8+NYVv?42jYke<1>og*k8ORkIzEUDjUctk=r=X12WnWspA9a?MMBHXUYcc1p(qbaU=_FDo!~OMLmorQ1#n1Nx9^JLE+9@rUj2Yjsnw*% zcvzwZHvx*yovk~E!Rf&QlZO*^bS0NH{t4Ec|yX=&ERDN6ceKrxS}|<#!C{YhrG-o$;?J_ z(uw(JM{j}j^1y~fq08FyG^nynB0{Bd8P)=?ERjyP5nXOZOTf`^Vqq`H130GuD@4uB z?-Z-7ce6^3h6NMn|4mr%E2KoYaU1p}016D1%!4PJZltA^Z|9vB4O09yJi9QZNbJu`;i)>vIrK)4E+))17A@G^1*R zmLt+^t(?;e&I4P1q5o$xtwBby#%2JzBHt(Uk^BS;OP z$WKr$Lf`?5Qc~-$1KKd{=J)WnWl?e~bmIG+{0VNM>2ogE%2RQOfWJoXMSv9Yi^0hd z2onKcXsI1k0kyl$j-U&OI>7YO%Z&H+3DlzB&@!X`B%Ejb=N@1p-MI*Y3!pQIJk|nK z@4YjrVcFRdjtmNaDN{fVd7qbepBDrUm_0DmyjdMU|0k%LBGg)AlwMx5k~6xv zm6&5&W$ar?0p7FG0Z*H80?S0>)_;)0C?<;kOAWPimf-M{LeQ7gxQBs3gXRsmX%*T>-1w7nd*ZgEz3NXH9{iTQp6bTh zw;9lJ?tx{EqWChn?zmRennPrq6`7obU_Ia$&|7`9%||9)qDs?iu*#6264?|1I<=o$T`Y;4(g45BulsBrx5HoN^1Gl@9Z|n{qKI~pue409@#7CfWb+DXrFvbZ5X zJXrC(0Nxie4etwqRt)QwyU|_?-y&^`larD-Joh6x@3g7g*US!DL_icd|0z@=nvIJy z>>mpNW>p~^e<8i>4$5ZtKQ8^TF`!l#%&#e4{m8idYqBB*60Aw9MlENxOk{V zSO`Lh6CDD{*#8ANY`Om5>}%-$$fB`-(?6ngPexjezMln5w+0|hs#d6vhZo>XSxj)f z`X7kcD9}h^1__)1+m$e@@k=>TIwEKWj3K|>%W$>mN@CnL7%XwMklzz9ykv1B^FtZKuNdof>a;C)yzyIDA(w;;T7H(Z8F-rb;%V zI0moY>A3(ahT^ZK4H)qECG-4bcam$iawCj)oEER>d#bJBhXV7`vXqA2t4@+p4HWqc(Hv4;J6I))!|povPT}zEnfUkwD0#od=u; z`Z}fX3NL%rg7KFldTKZQ#ZiPfQCSt68Uin)=q-WZpy66ltK`sla!Fz;DmiEoJcOkN zwZIUS-6=5d>=3vw>X##xbh!a#IoTY6?vijyo}7qgQ@&{ri2{ijtD6^tyU-r~q!%$h zqiE&A2f%*IWIjBU37ht-1p?hJJC7DjN|uvl5jbBDsJLc*YgXsKaJYLcAmUG7n~=O>bUJ=-jMeIG)YPNL|SRfpFO zIszP}^>}wqjK}Ae{$}gRs!K_GvmE1MVVL3BnGzcarYk8~TZA_YcGW)mmHi`V`ai-m zE57avC?m#2*bhUfU+y){G2_DDRA8nQhyD$C%@1c;9%U)KTPBmhLOF7c`P-%OE-VZA zT~>HN{!IK|KNfCVZ5LE+1-UjXQ=Qv${bmt?aGl1!8nPo3?!xB@`cX8UlYZq4*dW-q=F0QYvGZGfGxY;)}nCIRo+P4h)%W);Mw2_{E z4iDo6;U#~b$?UzCBper@yE*p_3-L|lbWuom-W`w*AY>w8a3-b~cFJKs%V+!MxuK1> zWx}>*zK;D*{j*A9ocNo+#v-#PN$-tB-)KRe;Q!T!45$buD9}T$hwnzLVox44^K4sJ#nsG`NWNN?od9HJ-@*+ zQ%)S|pIcG(@Y#}cTN0m}wBw735o0+5uTH672w25z3ma@NaBN2ZANy(iR-B3tEnoWw*J69PP z(x9C<-~m#Q{i?v=a~w4cSC}o`{{IVb3`#Sw0VNuMTZwA|%Yh34e;t_x-mC^Zs}|*W zBVdwP2@KykcR)>gSXzK|7l3g9>`)3`1#cw-#+C^1$RRIqM*=9*1x#6xw08VyJTOw1 z0Z+X7->!Q9-;w?Q<&`wS<7U}QPIW$ZhUc=r;yd+wUaARBJO*AK4NPjlJ#-Wm3DBk( z@QkRn&vI)8ud zpFck*&b5w?J?d+_ZJ+f2oPU45Z_AszgJJ*1g2Z3bixZA^-8yyRp7r~h{NH7)I}XE6 z9X{h0w7=KP`pV_WVz0JeTgSg$N>(;g=fKwPW5PDxR=~xt;1h{Y^ZLKq4s23nZxiR2 zxdGgQ`1SXaq?$J;)nA8STfUKD`>%jYD`7Q2UPVx_@8Q|OlEB7T#Qi4L-rq-l-AQ;B z1#G7-nHy=PgD}$M>aSz7+nmkCu0K9+Gx?w75^zfr zVV4)4{tMhj{jS&il6~8qs|l