From c9504b0f57ed55e6c20bf34f0bd600d1ff8144c6 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Fri, 5 May 2023 13:54:56 +0700 Subject: [PATCH] feat: add GraphViz and D2 as new outputs (#35) --- README.md | 2 +- dbterd/adapters/targets/constants.py | 2 + dbterd/adapters/targets/d2/__init__.py | 8 + .../targets/d2/d2_test_relationship.py | 58 +++ .../targets/dbml/dbml_test_relationship.py | 2 +- dbterd/adapters/targets/graphviz/__init__.py | 8 + .../graphviz/graphviz_test_relationship.py | 91 +++++ .../mermaid/mermaid_test_relationship.py | 2 +- docs/index.md | 2 +- docs/nav/guide/targets/generate-d2.md | 38 ++ docs/nav/guide/targets/generate-dbml.md | 16 +- docs/nav/guide/targets/generate-graphviz.md | 34 ++ mkdocs.yml | 8 +- samples/dbtresto/d2.svg | 111 ++++++ samples/dbtresto/graphviz.png | Bin 0 -> 107911 bytes .../targets/d2/test_d2_test_relationship.py | 261 ++++++++++++ .../test_graphviz_test_relationship.py | 377 ++++++++++++++++++ tests/unit/cli/test_runner.py | 2 + 18 files changed, 1010 insertions(+), 12 deletions(-) create mode 100644 dbterd/adapters/targets/d2/__init__.py create mode 100644 dbterd/adapters/targets/d2/d2_test_relationship.py create mode 100644 dbterd/adapters/targets/graphviz/__init__.py create mode 100644 dbterd/adapters/targets/graphviz/graphviz_test_relationship.py create mode 100644 docs/nav/guide/targets/generate-d2.md create mode 100644 docs/nav/guide/targets/generate-graphviz.md create mode 100644 samples/dbtresto/d2.svg create mode 100644 samples/dbtresto/graphviz.png create mode 100644 tests/unit/adapters/targets/d2/test_d2_test_relationship.py create mode 100644 tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py diff --git a/README.md b/README.md index 1aeed97..10db7c0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dbterd -CLI to generate Diagram-as-a-code file ([DBML](https://dbdiagram.io/d), [Mermaid](https://mermaid-js.github.io/mermaid-live-editor/), [PlantUML](https://plantuml.com/ie-diagram)) from dbt artifact files (required: `manifest.json`, `catalog.json`) +CLI to generate Diagram-as-a-code file ([DBML](https://dbdiagram.io/d), [Mermaid](https://mermaid-js.github.io/mermaid-live-editor/), [PlantUML](https://plantuml.com/ie-diagram), [GraphViz](https://graphviz.org/), [D2](https://d2lang.com/)) from dbt artifact files (required: `manifest.json`, `catalog.json`) [![PyPI version](https://badge.fury.io/py/dbterd.svg)](https://pypi.org/project/dbterd/) ![python-cli](https://img.shields.io/badge/CLI-Python-FFCE3E?labelColor=14354C&logo=python&logoColor=white) diff --git a/dbterd/adapters/targets/constants.py b/dbterd/adapters/targets/constants.py index ff618f9..9521bc0 100644 --- a/dbterd/adapters/targets/constants.py +++ b/dbterd/adapters/targets/constants.py @@ -2,3 +2,5 @@ class Strategies: DBML_TEST_RELATIONSHIP = "dbml_test_relationship" MERMAID_TEST_RELATIONSHIP = "mermaid_test_relationship" PLANTUML_TEST_RELATIONSHIP = "plantuml_test_relationship" + D2_TEST_RELATIONSHIP = "d2_test_relationship" + GRAPHVIZ_TEST_RELATIONSHIP = "graphviz_test_relationship" diff --git a/dbterd/adapters/targets/d2/__init__.py b/dbterd/adapters/targets/d2/__init__.py new file mode 100644 index 0000000..88dc512 --- /dev/null +++ b/dbterd/adapters/targets/d2/__init__.py @@ -0,0 +1,8 @@ +from dbterd.adapters.targets.constants import Strategies +from dbterd.adapters.targets.d2 import d2_test_relationship +from dbterd.adapters.targets.default import default + +run_operation_default = default +run_operation_dispatcher = { + Strategies.D2_TEST_RELATIONSHIP: d2_test_relationship.run, +} diff --git a/dbterd/adapters/targets/d2/d2_test_relationship.py b/dbterd/adapters/targets/d2/d2_test_relationship.py new file mode 100644 index 0000000..3a7feeb --- /dev/null +++ b/dbterd/adapters/targets/d2/d2_test_relationship.py @@ -0,0 +1,58 @@ +from dbterd.adapters.algos import test_relationship + + +def run(manifest, catalog, **kwargs): + """Parse dbt artifacts and export D2 file + + Args: + manifest (dict): Manifest json + catalog (dict): Catalog json + + Returns: + Tuple(str, str): File name and the D2 content + """ + return ("output.d2", parse(manifest, catalog, **kwargs)) + + +def parse(manifest, catalog, **kwargs): + """Get the D2 content from dbt artifacts + + Args: + manifest (dict): Manifest json + catalog (dict): Catalog json + + Returns: + str: D2 content + """ + tables, relationships = test_relationship.parse( + manifest=manifest, catalog=catalog, **kwargs + ) + + # Build D2 content + # https://play.d2lang.com/?script=qlDQtVOo5AIEAAD__w%3D%3D&, https://github.com/terrastruct/d2 + d2 = "" + for table in tables: + d2 += '"{table}": {{\n shape: sql_table\n{columns}\n}}\n'.format( + table=table.name, + columns="\n".join([f" {x.name}: {x.data_type}" for x in table.columns]), + ) + + for rel in relationships: + key_from = f'"{rel.table_map[1]}"' + key_to = f'"{rel.table_map[0]}"' + connector = f"{rel.column_map[1]} = {rel.column_map[0]}" + d2 += f'{key_from} {get_rel_symbol(rel.type)} {key_to}: "{connector}"\n' + + return d2 + + +def get_rel_symbol(relationship_type: str) -> str: + """Get D2 relationship symbol + + Args: + relationship_type (str): relationship type + + Returns: + str: Relation symbol supported in D2 + """ + return "->" # no supports for rel type diff --git a/dbterd/adapters/targets/dbml/dbml_test_relationship.py b/dbterd/adapters/targets/dbml/dbml_test_relationship.py index ce856e5..34e18af 100644 --- a/dbterd/adapters/targets/dbml/dbml_test_relationship.py +++ b/dbterd/adapters/targets/dbml/dbml_test_relationship.py @@ -32,7 +32,7 @@ def parse(manifest, catalog, **kwargs): dbml = "//Tables (based on the selection criteria)\n" for table in tables: dbml += f"//--configured at schema: {table.database}.{table.schema}\n" - dbml += """Table \"{table}\" {{\n{columns}\n}}\n""".format( + dbml += 'Table "{table}" {{\n{columns}\n}}\n'.format( table=table.name, columns="\n".join( [ diff --git a/dbterd/adapters/targets/graphviz/__init__.py b/dbterd/adapters/targets/graphviz/__init__.py new file mode 100644 index 0000000..fb09012 --- /dev/null +++ b/dbterd/adapters/targets/graphviz/__init__.py @@ -0,0 +1,8 @@ +from dbterd.adapters.targets.constants import Strategies +from dbterd.adapters.targets.default import default +from dbterd.adapters.targets.graphviz import graphviz_test_relationship + +run_operation_default = default +run_operation_dispatcher = { + Strategies.GRAPHVIZ_TEST_RELATIONSHIP: graphviz_test_relationship.run, +} diff --git a/dbterd/adapters/targets/graphviz/graphviz_test_relationship.py b/dbterd/adapters/targets/graphviz/graphviz_test_relationship.py new file mode 100644 index 0000000..d6c6f50 --- /dev/null +++ b/dbterd/adapters/targets/graphviz/graphviz_test_relationship.py @@ -0,0 +1,91 @@ +from dbterd.adapters.algos import test_relationship + + +def run(manifest, catalog, **kwargs): + """Parse dbt artifacts and export GraphViz file + + Args: + manifest (dict): Manifest json + catalog (dict): Catalog json + + Returns: + Tuple(str, str): File name and the GraphViz content + """ + return ("output.graphviz", parse(manifest, catalog, **kwargs)) + + +def parse(manifest, catalog, **kwargs): + """Get the GraphViz content from dbt artifacts + + Args: + manifest (dict): Manifest json + catalog (dict): Catalog json + + Returns: + str: GraphViz content + """ + tables, relationships = test_relationship.parse( + manifest=manifest, catalog=catalog, **kwargs + ) + + # Build GraphViz content + # https://dreampuf.github.io/GraphvizOnline/, https://graphviz.org/ + graphviz = ( + "digraph g {\n" + ' fontname="Helvetica,Arial,sans-serif"\n' + ' node [fontname="Helvetica,Arial,sans-serif"]\n' + ' edge [fontname="Helvetica,Arial,sans-serif"]\n' + ' graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"];\n' + " ratio=auto;\n" + ) + for table in tables: + graphviz += ( + ' "{table}" [\n' + ' style = "filled, bold"\n' + " penwidth = 1\n" + ' fillcolor = "white"\n' + ' fontname = "Courier New"\n' + ' shape = "Mrecord"\n' + " label =<\n" + ' \n' + ' \n{columns}\n' + "
' + '{table}
> ];\n" + ).format( + table=table.name, + columns="\n".join( + [ + f' ({x.data_type}) {x.name}' + for x in table.columns + ] + ), + ) + + for rel in relationships: + key_from = f'"{rel.table_map[1]}"' + key_to = f'"{rel.table_map[0]}"' + connector = f"{rel.column_map[1]} = {rel.column_map[0]}" + graphviz += ( + f" {key_from} {get_rel_symbol(rel.type)} {key_to} [ \n" + " penwidth = 1\n" + " fontsize = 12\n" + ' fontcolor = "black"\n' + f' label = "{connector}"\n' + " ];\n" + ) + + graphviz += "}" + + return graphviz + + +def get_rel_symbol(relationship_type: str) -> str: + """Get GraphViz relationship symbol + + Args: + relationship_type (str): relationship type + + Returns: + str: Relation symbol supported in GraphViz + """ + return "->" # no supports for rel type diff --git a/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py b/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py index aba0691..ef68529 100644 --- a/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py +++ b/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py @@ -32,7 +32,7 @@ def parse(manifest, catalog, **kwargs): # https://mermaid.js.org/syntax/entityRelationshipDiagram.html mermaid = "erDiagram\n" for table in tables: - mermaid += """ \"{table}\" {{\n{columns}\n }}\n""".format( + mermaid += ' "{table}" {{\n{columns}\n }}\n'.format( table=table.name.upper(), columns="\n".join( [ diff --git a/docs/index.md b/docs/index.md index c496e51..f8ce435 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # dbterd -CLI to generate Diagram-as-a-code file ([DBML](https://dbdiagram.io/d), [Mermaid](https://mermaid-js.github.io/mermaid-live-editor/), [PlantUML](https://plantuml.com/ie-diagram)) from dbt artifact files (required: `manifest.json`, `catalog.json`) +CLI to generate Diagram-as-a-code file ([DBML](https://dbdiagram.io/d), [Mermaid](https://mermaid-js.github.io/mermaid-live-editor/), [PlantUML](https://plantuml.com/ie-diagram), [GraphViz](https://graphviz.org/), [D2](https://d2lang.com/)) from dbt artifact files (required: `manifest.json`, `catalog.json`) [![PyPI version](https://badge.fury.io/py/dbterd.svg)](https://pypi.org/project/dbterd/) ![python-cli](https://img.shields.io/badge/CLI-Python-FFCE3E?labelColor=14354C&logo=python&logoColor=white) diff --git a/docs/nav/guide/targets/generate-d2.md b/docs/nav/guide/targets/generate-d2.md new file mode 100644 index 0000000..df74476 --- /dev/null +++ b/docs/nav/guide/targets/generate-d2.md @@ -0,0 +1,38 @@ +# Generate D2 ERD + +## 1. Install D2 CLI + +```bash +# With --dry-run the install script will print the commands it will use +# to install without actually installing so you know what it's going to do. +curl -fsSL https://d2lang.com/install.sh | sh -s -- --dry-run +# If things look good, install for real. +curl -fsSL https://d2lang.com/install.sh | sh -s -- +``` + +> Check [installations](https://github.com/terrastruct/d2/blob/master/docs/INSTALL.md) for more details + +## 2. Generate D2 ERD content + +```bash +dbterd run -t d2 -ad "samples/dbtresto" -o "target" -s schema:dbt.mart +# Expected: ./target/output.d2 +``` + +## 2. Export to SVG + +```bash +d2 -w ./target/output.d2 ./target/output.svg +``` + +### 3. Embeded into Markdown + +```markdown +# Sample D2 ERD + +![d2](./target/output.svg) +``` + +Sample Output: + +![d2](https://github.com/datnguye/dbterd/blob/main/samples/dbtresto/d2.svg) diff --git a/docs/nav/guide/targets/generate-dbml.md b/docs/nav/guide/targets/generate-dbml.md index 4f14a78..e2767e0 100644 --- a/docs/nav/guide/targets/generate-dbml.md +++ b/docs/nav/guide/targets/generate-dbml.md @@ -1,29 +1,35 @@ # Generate DBML -#### 1. Produce your manifest json +## 1. Produce your manifest json In your dbt project (I am using dbt-resto/[integration_tests](https://github.com/datnguye/dbt-resto) for demo purpose), try to build the docs: + ```bash dbt docs generate ``` -#### 2. Generate DBML +## 2. Generate DBML + Copy `manifest.json` and `catalog.json` into a specific folder OR do nothing and let's assume we're using `dbt/target` directory, and run -``` + +```bash dbterd run -ad "/path/to/dbt/target" -o "/path/to/output" # dbterd run -ad "samples/dbtresto" -s model.dbt_resto -ns model.dbt_resto.staging ``` File `./target/output.dbml` will be generated as the result -#### 3. Build database docs site (Optional) +## 3. Build database docs site (Optional) + Assuming you're already familiar with [dbdocs](https://dbdocs.io/docs#installation) -``` + +```bash dbdocs build "/path/to/output/output.dbml" # dbdocs build "./target/output.dbml" ``` Your terminal should provide the info as below: + ```bash √ Parsing file content ? Project name: poc diff --git a/docs/nav/guide/targets/generate-graphviz.md b/docs/nav/guide/targets/generate-graphviz.md new file mode 100644 index 0000000..d7fd3e8 --- /dev/null +++ b/docs/nav/guide/targets/generate-graphviz.md @@ -0,0 +1,34 @@ +# Generate GraphViz ERD + +## 1. Install GraphViz CLI + +```bash +sudo apt install graphviz +``` + +> Check [installations](https://graphviz.org/download/#linux) for more details + +## 2. Generate GraphViz ERD content + +```bash +dbterd run -t graphviz -ad "samples/dbtresto" -o "target" -s schema:dbt.mart +# Expected: ./target/output.graphviz +``` + +## 2. Export to PNG + +```bash +dot -Tpng ./target/output.d2 > ./target/output.png +``` + +### 3. Embeded into Markdown + +```markdown +# Sample GraphViz ERD + +![graphviz](./target/output.png) +``` + +Sample Output: + +![graphviz](https://github.com/datnguye/dbterd/blob/main/samples/dbtresto/graphviz.png) diff --git a/mkdocs.yml b/mkdocs.yml index d8b3f3c..f0d2fc0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -15,9 +15,11 @@ nav: - User Guide: - CLI Reference: nav/guide/cli-references.md - Generate the Targets: - - Generate DBML: nav/guide/targets/generate-dbml.md - - Generate Mermaid: nav/guide/targets/generate-markdown-mermaid-erd.md - - Generate PlantUML: nav/guide/targets/generate-plantuml.md + - DBML: nav/guide/targets/generate-dbml.md + - Mermaid: nav/guide/targets/generate-markdown-mermaid-erd.md + - PlantUML: nav/guide/targets/generate-plantuml.md + - D2: nav/guide/targets/generate-d2.md + - GraphViz: nav/guide/targets/generate-graphviz.md - Metadata: - Ignore Tests: nav/metadata/ignore_in_erd.md - Relationship Types: nav/metadata/relationship_type.md diff --git a/samples/dbtresto/d2.svg b/samples/dbtresto/d2.svg new file mode 100644 index 0000000..a97a120 --- /dev/null +++ b/samples/dbtresto/d2.svg @@ -0,0 +1,111 @@ +model.dbt_resto.dim_boxbox_keyvarcharbox_idvarcharbox_datedatebox_result_numbersnvarcharbox_result_number_1intbox_result_number_2intbox_result_number_3intbox_result_number_4intbox_result_number_5intbox_result_number_6intbox_result_number_7intmodel.dbt_resto.dim_datedate_keydatebox_datedatebox_dayintbox_weekintbox_monthintbox_month_namevarcharbox_yearintmodel.dbt_resto.dim_prizeprize_keyvarcharprize_namenvarcharprize_orderintmodel.dbt_resto.fact_numbernumber_valueintoccurrenceintoccurrence_pos_1intoccurrence_pos_2intoccurrence_pos_3intoccurrence_pos_4intoccurrence_pos_5intoccurrence_pos_6intoccurrence_pos_7intlast_appearancedatelast_appearance_pos_1datelast_appearance_pos_2datelast_appearance_pos_3datelast_appearance_pos_4datelast_appearance_pos_5datelast_appearance_pos_6datelast_appearance_pos_7datemodel.dbt_resto.fact_number_forecastforecast_datedatelast_box_datedateforecast_numbersvarcharlast_box_result_numbersnvarcharforecast_1intlast_box_result_number_1intforecast_2intlast_box_result_number_2intforecast_3intlast_box_result_number_3intforecast_4intlast_box_result_number_4intforecast_5intlast_box_result_number_5intforecast_6intlast_box_result_number_6intmodel.dbt_resto.fact_number_scoringfact_keyvarcharforecast_datedatenumber_valueintscore_1intscore_2intscore_3intscore_4intscore_5intscore_6intrank_pos_1floatrank_pos_2floatrank_pos_3floatrank_pos_4floatrank_pos_5floatrank_pos_6floatmodel.dbt_resto.fact_resultfact_result_keyvarcharbox_keyvarcharprize_keyvarchardate_keydateno_of_wonintprize_valuefloatprize_paidfloatis_prize_takenintmodel.dbt_resto.fact_set_numberbox_result_numbersnvarcharoccurrenceintlast_appearancedate last_appearance = date_keylast_appearance_pos_1 = date_keylast_appearance_pos_2 = date_keylast_appearance_pos_3 = date_keylast_appearance_pos_4 = date_keylast_appearance_pos_5 = date_keylast_appearance_pos_6 = date_keybox_key = box_keyprize_key = prize_keydate_key = date_key + + + + + + + + + + + + diff --git a/samples/dbtresto/graphviz.png b/samples/dbtresto/graphviz.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7ea9fd658bfa54508793b8d63d5452ceb6ca0f GIT binary patch literal 107911 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 z z-;bNNXhMlfpc5;fOXOtfAU$a32pF51O}YFUiWMH>WBh?sYnIp}2k`*^tHDWanrDSt zt5+~lkTZyFR)F(mg{o^d&Lu&pdOscze}h4|@rpk-`&9`#Rk=*A#RfUYNWXoV8~#iWEBH@{#Zkn^#tlZfnlo7H9y#6 zp`wVWUBZqEt}Iyb&7Bkz&YINS#pAoL%#O$HhWw$xhb9^@Jp0*ZXM|ew%s>yiLF5sK z*p*!goV`49v{++B3_O6S94M?czah*-oTb&A8e+-uF+?9eGlT}(nhqEG*@n=mEbnFA z=2pS25q1~1Aq%dtu^8NDdQW+hQ*Ah?j_}(~VD^|foB(3@?i}g8A3q@ho`GY_#pxPC z@oAAs_gSFuyD+PbsnM$XOutM83A_CRB<7f=&xg6+gVfBf#cpNMY*}n7ieZ#M`RWMC zKgmW_P^fy( z(0m4s%g=|3F2wbaE>%Lb#4l;6&Gw&G%}{%FIZDafP$&55C`}a#N}um?hDYhsTA(iF z4Kc*j1dg;244WwK$+Fy$es2!i@8Fi`F;y*EJFeo?=smT9|CO(cx0bOOl3CZuW z(_MnSXRMMOAN&G(w=J@i(JWN7b?TbmQJ{x2cVBi+y(YEYuIlerPcWPYvcxAmLKHuXo3|2Bob6Cy8%lE0O`CIP#iO?hP&7%`b4;IIbUe`>ImYBGoBTG0VrLFKlu z)?QET_E($T1A>uG^p2U%QtVbzncNR*Ig$`=z5qnA$T!*iwjl9R3V2WH)dU_Cp_VcM zKQZsUwA1iC1J#A@yd8~#*dvw%yLtEzVF%MlKn*Bhw$B+RU%({DhBai%b{qep4289pK+d$XtXHV?;_ha&SH-kckV+icvzz;rr1{ zndWc6%)it#)fpDKW_%$whb@e0*qAO1GSHe5t1yC){*CF*K6e z)^LAQU7Csx=Kg_TnIZc zfx0x(H~)?^?P&4C3g=@+NwlJ*5T;yV=6y zMCc^GWEvBG+Ev2m+u<#cz%D~=ix|Wo9%Rb zH+!le148ML+uQWh?NDRTF=eMuBR;rmz;na8u;!eqiU%!!_y^M(1I_RsS1$v)4| zH%_-V(vdTAj-ou)%fTHS|Aon;X$c+({>7IG=Ydo?Fuu#$fbaU)mGo?X8?aR$bRa7U zs&D@%;ga7mBt(6EC=o&L!>q2PKui zQFrn{D6uWklD4d?~=&@&Nih62r~(EdU z(0@j2j~hI5JnYy16n_0S;uWsrA;CWQX3TZk8>11U}>46asX~o$ksZBYlE6Z0wYrG@UK*?~p($?Sg&1Nq@a&q&u9OLL(b!xDd z97`Dx+G;oOgci>V5Av#*{hm1jlN+0FOJ)a{CH*YFyrLn0vfw49_|8)0a@7>I1Eqrq zsVDwjFK0tY5+(>r__E4)a_#Da1d~y7~(<c^?kIviR}f(JVTQCADZBQsdBCH3>U3y7{Ybb+gEm7!D@N?G)%cD5kmuVSec1 zN;6w)_mZ@lqbxV(;MS2-Bd&Oq)ZoE5Xt?~4oAT0qk)fT^ zTo!k2=rj##KQRH0=w3L-l!K}sU8}*)Svt8P66OZQUC`dOp$#)Aj?{Hdr3u=_BymuW z5iJf#_h7)N9sDDuYJJA%In0DBYwrmKds2B+E(H0nW!ka|SsnYRc4gkMqfMaRXT$ii zb7zcO-c5{Q?S`D;jm%*Fo+&i5;Zo^18c1j6qX-?0&tTbeD{74!Y)d&vgkxW}@hf01 zMx+xjb|5%kJhF)_l3$ao5L65ucsiHJ+#4*>HX72%^I^zW(n z2sS!%dz!}T7UW@{7}ZozHL{;D_o5USBAE04NLVcMN3LLU0is?$m?*`K7i$-oj(v5b zW2r=O?T%P3lzg8H5&;!APeC>eQm2W9By*>qMJ!CBc~*PtyO(nQ9e1B-XG>xvwSK<_ z#E3FLa7^62v6K$-WVeNmGz^B!Y4{$}ebLP*HG2q1%7{VFNM36HYM z7K!*D?|t%oaFr5Kk0a*V>6)cJ=pCOu4dc=qa7(s{FxlPCUik=G-xG22SLB%%palU)nPk%{!gTuw)sjFU82P3qU}RMK+o}v7W8_`1SLHaf3+Z zKB=~7rKT@=u07?-%*(Q{rTq(xbNi1$`_-78y?nyf2PxkuLd{H8u++1AbTeMI9l|@~ z`w2U3O@r4EAL$ezs;X?F3@8PxP2C!-Yo5#fFLvMuPX>ZNb3>p(k=cnB_E!I3$y5v`uEu?2;ta*!PdzvE+|IInOMK!x@gKxXnW|6Be7;q*xt z9N<^|KY<7Tj4sGvLC?auW6QCNoj@$8*W~mWH=zKUHTU(yAjkKIMV$k}t5_3uqM@RA zn)zR}tK~$%9beMaL-VCYwykl!8F#K}3C?+t%3H9hH`={+N_ht4I1t@_yxcGKQN0mT z8++%kO_C)?QoX{CyhOpXe%rWx+|^xVv<485F0Z(fi&FH3VzTdOj14_hRots~L=RO` z&K@_5WA+d@kr5jT}qvzX|c3z23c3kRBD4)k!XPe{W-!|-0;I~v^P zEP{XY{H{UU*@fb&Ik?U7@|{E2m`}tAIQOUGEAvFk52ZVg&Ry9hN{5Rss^J`+TQl;y zYtaQfp;Gv6kH*T%qT-&K#WB-2(S$XR2z|Fx#y4QMv<9Yfv!hc=%WAzFX)`8yG-d)@ z9$t1HaQn#AfLtO}eToCpjZE{10t>TwVeHw*yD}Z!nf8okZz%l?1tt>P&@RM)ht3@% zItL#slI4Ilwr4ia|LW}c7E%$1#}_J@W-`ZVwB4FNEk9-K1c(@|y-B?Iu`Z+|r>fIg z{!*S##iQfwW74r9K3f0a+tR7^N)H@3jW5e%9c{%KUB6;&F2UlOc%+w=)g9p3`?9Vo zq`U2wsS@e?vHL8D9{;Y9zrlb_VWH(AlOBKsMp~qPOD5UO2RXj}HLS$VtQZ{1qF*6_{EBe#-0F!J|oL)l-A=G49rkJ(|lGC;lW*Ze=wp1s(C*quD*z zzhTf5Mp-TW(9Rgcb;)>H7-yJez{xE#$>b{&zh3oe9G=4Uv0plKA*z&DRJc`VXZzGg zUm*3U^O4;`2Y<>jl4&4j5K$HZYKSu%R~(k^Zn%Uk^4asf1v=p@1S@`dT-~QQ>W*BX zRghbK_FX8k9w*l-B_G?h!(+xjryVKPS`{|CrLGE6BqNG|dA<8Mg*Hdxl2;wEnrHql z?Lz2_YRAkdLcg)-g0TIEqxbc~JXrqL0u)K)B^n4>NY$Ddl}jo27Oi zgGM`zv)XVco#%Xi3+*ssqGI76`Bcr?>x+Ku+&@0;i zXAznaBI>|cC202EOZti*mmh(O1Bm$f2@TZK3;;g+E?pFush+$-2iho%*_P06e9W?X zs}x4*X9*R(R}CaD-*%yeQB{uiC#_M&4TFMIsCFMrW0cw*?G0r(16u+c7aD)J*7mFy zB!WR%*)}6z(O5Jaxt1G@!xOtNalyp?%Fn-nLU$W^6#O0u8(H3d~Sf*D$f3-sM&!#Xnt_9;rBdmfC!k}XV!WImh8PpFs58g@v?_Tm;K>q08z}PV74{~ zhV<#U@2`V_b70JU0Mrw}to0~N&%R-M0lJCTP;-VeIjO!ogVO-c@V$jTfqWG(B<$cP z8004G4R|94PFC0#r`9W0ugIhpcq3>2aCX3HybfYjJtw~O;U{S7zy{J&Kfx3-erS%I zS<5jPoZK%#r2YqD8r0j%|B5!=js|oV%;b3n`IBY>Z#IFaGx;;R#GB>!PRW7iFEHUt z?5-}1%5A+{B*02~cXT?7*T>qOXlr~8Dk;yCI}9^P*N#ULQGe?v?Rw zrSa)lFy5@s@sP}WsD%ZXVy|-Y08o8&Jas?sx`Cn@6E!&bLqSb>6Vw`m+;Ku;*)i-i zG|v7PL`Rz2!G6-%S55o>jEJpchUl=9;B{f3*=w?#KpIAC-~{!0u=m2@{N3ti>B)ur z_l*Nf@X#9PFwJL>HPvD)Ml>& z5E(Kf6MLE7ZQOC%_<&^mSsajTKU+l__>;WX+NZ zKYlasGi^5rwwYet7#nw+iXB8}jcu$xKpOL|?#)XSU`0JNNb8{1dzxL4TW(ZBnE>N$iNI;U!S7mt$L68UOGp5Z0G7#5@p}Hd#XO*H`51>RwueB0 z21oSBCI8}Hp_bCU8Z`D{r%=%cc%H*|_kh8yMshud{I1h3mlaOAqq?u+m<6_oeaI|l z!_mGTwbD&2D{Uj-3%!cDvvsS}C*?#}w$kAcEpfPol{S$=Vd7r-&cP5xkE;Dwjg~boXJU+O6d$?kt8lh9*hjvd$*9LG#Ncw3g~ig9kyumYpVj>0d$s z{;73vasCk~o9xBmB7jy(W+w?F&fq$3)0Zr-j@)w&bU%>xa${uE@|Zd}sCOGL=Q%ZV zm8nd@?~0nqc~d?8uUSLGZ-XvI-hO@?exHV>FPr=EuFp~Y`}1`{rDNJ}DQwJ4nTME} zt@VY61fwfB&1v?9vnaV&{b3=t zcN0V^*|Vlj+-y@X^GvU#S#{R+JnG6l8DV(%6yzlZ> zkK9BA)@P=6wfX9`M{k_%PCghf=7&gYSlY?g{J%)M1rAh>cal~67O$9lJo>F@e=&99 zoLDx$$7nap8Q)?Dp3~$09!7b|s0`|d6S5oSX=dNZ@^qNTY=u_t&}{ZNTE!)wch|jS zzBc*g(CnkOYZYBZW(ZThiAT2z_rnbzsI89CuUNS;6%f6OW-tXezu!mH8=a1HUat{) zqPxenD={8g$&q*rsuqLIy&aHgS+U)VB8te;Jlr#4+!CB+Eu^Jtzs16wFt)q+eurnC`FipO>G=&zQiBqs!7s!Pdem5?~8l#lX zqbM&>lJoiCgU;#xc{1NRI=M}{YD9yCIT`*`X~2qU$GzkeFH+i*ix)w$jSTr^fVF*y z{M^9VC;mDV%>duTlsJ3H<;gT+1Tb%^?Q@ z5;b|5k!*~kiM$ab|x4>$piJ=={Izn$Xf3a=LJWC0O5s3nQe*$7@vAo+_ezQzO?7o zuTXHPC&hr-lUuC^S3LkKBDwG?LNSF-)ahQiWjFb@EjnXb{^#hgy6D2f zFGoj5?*N;gK2)G%JJsNmAm)+}Uch_MREO$_g@uJWV7*JV1==Hvi+Q?JB#~h1X+=U} zA_;gtc6>POI<;AA$X75fHwS7w)bcV6syD@F&C3BoTgFX%kEPN^t49bJ$ymH!K5 z8V5l-FcTW8DO{tq2r_a5;8jNle1Tmz08Lrm?Qc3946nw4udCA;!#w~Yl*h~C)iu9n zg4b#2VAq{SDNfhQYT>Jvm;;7Z<9m@T_cCa!s#}tLLMBRG=i{OruA1RVMq{HzMg?Z& zR*dG@mCdTW4?8bYrGB{DYg_0`E?$ZpaP*yY&bGMeeLqz~ujXmq*x1+xl*4<_wlZ0d z1gN9;Zs;l4%q*B4+w0PDQRn-$sbBs^?$gJ#v@h+Y9*5ncupd|_Qp2>{^blJZ4r%8P zix%NlLTSCxLw?x&bG4r3jF@2lz!AX{OZLR1PSH#T=lrQTM@`?|m+)$%oy_)Xy=d#` zW);_0c@287NRW4QgI2L5XxF0-I*SFe z56D^@=uTvW)0Yp(4B~$mGMskeBSeKe<#%>g-pWRbG<}a$Av(C#P5CZdDnUMz@xAD> zHU}Vz*8TghiyQZMa^(*B>0T4EiGniCgy$z10wLIH+HI{ZLuGM--C6jUc;N*GYL-=v z!S+Zns8tb~N-Ol_+ehfckzLSDEf<0yo{PzD8BiM<-P5zeH#JAwsW6!e3q5xnQ@I~@ z)ftI2tA1rw4P}tbhYqd*J$d(Xkau>o@1_aG2l8l#wW4-EfO@pqpPjytM& z+o|3@&GW8~G4;bCowx*<7kT!8Mr0qX-jMUg9W*xm7;tXcLg@j@tFE90l`gBlmwF zg7*f~dD6#aq+crS`-E+@YBs?ol2mG0Qw zbcJgi?C;$SZEn22A2{c%`h*wfz@+cEE1>meZF_RV^rPP)G4Eeb1|Pv-cP&M}bw<@2 z77WGYX@}()+3FaL2w*~mf<9SuA`6`AD_&ybUWQ!GG>FE$#|%Wj=0!8Xl} z*V$jB*Ou;-qQsche^AUkrsc|hYiurPAn_W^g)UzYx9L--Vw9-^99p5SJ1cbZ{$# zZ?n3{`@Eg-tz75m5V|W<6+)|Qv9e~agT|q2fs}G? zY|8n3fb9~==Ml89xD22K-MxUhAf`x^uJc6xP$vP=(apj?vvns&xV@6wX}VIP1Vz_=Z6DtDgSvij-WBkv4Brb ztFu=DK86L-{AZ`9H9K~4!S0xKM{+?vAjN$qDEBkWFX`+xVJ@gRkY7z(d%>E2(;Iu` zsdwHzwT9m6D04R4_?XxmDO&X1Wvh5>3Ds=asrE>&#U$rY%kG4WfEfS~rbqciQOj*V z;D#(&5nlv$mGaOo>6_(Cy{}A_?OwnBQyqIRTkS-;OnRwe)X#mvHu4zIw4?Epp6@)o zUf`Y{bS)MgH&_4NgmMag0WWl&Kk9h;-X{0;zg$d_C8KV1B%z4?5$S}qPd{1<9tD}{{vHRhi_CT_R zB3A$zTpW9Pu)J)KjY~crs=a7M(hYy9n)513)6l5+wN~wge7>Db&0QS*3MRF>g)qz* zZrt?;8_LBCBAVjV&okE^r8*@yf_`sRA@2Ijnl_JipihY5;=Z+Q{`E}XWBl!Aq&jQP-|r)S7(Zs$U4?AFKYr{FDHJ* zLUxG$o^o{s=Y^Nl}Zgt?poHcn8uM}?;4+IqKfV9t7@KR=HYK; zIoBLH;m51F=~|?X%+{Ao@kBj54SGD#+fu(A&_-*|ds?3;;XiSuWMb9V^>W!*1D3to|kgAznGVsJi9HaDxgdG0H&$W4-GsDiY}%Y1oLH&2F+2%&95t z=$YTn^#!FD*IzSc!>-dZt9qC1-i#6rtV}GnbXv*O+|JhQNMaBaWy?9Lq`PX_z?v() zrh;WojCFPvn{?PS+KxBW}BD1m!5KGXT#Y!O@6rE>=0 zq!tq=<-E#^O&7Na7q@=FWNvs+pZ29b>3T#6VR+p-V@cIGK^26(QXHMpy%jtE-jCy4aYXi6}7{SIwK~Pe)+*WUp zS|;5u>ce3<4m}LP@-4|8eo1xV8iu*H{Y+ukL9e{PM~>qdfih!)JUjZLUu50yz}DR# z%wt{RV_XLcDa|qsR_t^6eKVvN&bxs>loRhp*__6#ukOg_#f_c3brfK{tR17QBER3$ zlC$)v1$tD>Ga$`1UkiSRD-n0pe7x$Z-nGbjOc0r;+i*{OZ_U;viLs?$TZZ<@WjxfT8VSsz8ZsUqK@M;#>X z3z0bEB=>6i)|CV{S@ujchefZ%dI+F385JS`>UpT6lM_V4hX1|Zt8?RB->=nKA=BoQ zS`Q!Iqhp7CB>v&9e;~3@=fv z$9ARRx{6Uw)eVk>&oZU$LP1onhK>=v-~(q{-)d@UMT?1v4UUfH5pfv8kdE;X=+);8 z&{S@1EwbK|)bFvFoCA+!wf_BU^{R+{5_QnM!So}rGw&pV;)a@%;=_<5O{2i9)XPRrHImV>e0E1w*SwJ8@cxdPBrZZhfeQ3oo@aT5S_W z>yO_$ZV%Tg$b3I=aDqRPsrF1H?b>rR2Y0)<20cB!Bm)7D?_Zs58#s9O`dmUmNcgWn#@40ET=!nYR?9;*_eqZXr>^A+O z`Ab&1j|=+0PEHoP5QeSiJEHMJ1+j$H`FXZR&x5awd+&yekU4D(ULl}n?!rmSl(|6O ztDiC?L1K5DPTW;FQN&?*p*xYZ*2$Z5um{-eyn+HHpPdbL5dVeYo|Z+&#@aRqp06RI zakp)U3nd;+6g9=9$}Ic=cp_*W4MrPjpF3&F8zw*Ne?TG@d{xH#jzy-<>E@ zP+6%(z?NXaJq&?&4yGdl@A?{2wOueLz^L$K81_{}y*CC>~&P$h0bjO^%8JWI9>g+Pw0s~$Z=jZ2ZR$H&RbaG>IYih(8 zbB@DKQnb@tXMICDZ4>uc5ayRC>9x5LcfZVI-LihIgLCKSXG#`$Wo0FJ`8ps(01qoR z1<{XjFjggnToX|N%O=0D5bU4Wg|7JbNQZhYaO|U`OJF=Txxy~(n*}QX=DwiG<>2Hb z&kyqm=6GeBu?p)1akpaXpjWIaNxA!byC*cBfpHDs`cRyuD*h7&n+YSgqd4^diA09! zF&7mTd9JoxcKP1N1ZQM{;|T;Is~$QQY6?UgpX`z2XHE(gr^^N4f$p_FTQ!xzMiS=t znCviRmNLOdmcxZnW0^j?oA8L^XRl`7yOC}#kf&E}$sVta2Ltc>!kOf51XqXCuyMJb zgY}T_{JMZPJOWS*dR|-0(Sw3;ClGMn0{0GWO|hqso8Mgy{X5Rrz_DOIm1>%N3xZF zvkCnNCfcmH$ynF9#G5rX{CcFfkXouGZsgQyGLLk0;oGN|V+}sL?C=P~TGu>aHim|V zu7a2mm1JEd(Wg;`!0{yw_?>)K36BL+lyDsU1{UuND3wPcX z8r>KU9yIB<`Iv0zyI|7Wd7U@JxDnx?{-Ho**RhuNWuT<<$K~Ok>LfWlf6fkqL1Z2y z9T!E&QcXxo)QZ=JpNTvg`9rA8_A>7tlTMcy|DSIx<~Z{TDAV6EP(+XjSX;ty5q@du zAuz-KXRl@7yYclVT)?u67BckoQft>kGG*hG?bV;WnZo~GvP2ynI<7*&o>Nn25L{)% zE8V1MF1puh(aDqx1=r{u#Jv@9&L{3#iW!E4RVX64rX zAOmbG_ycT8keK&%r}!h2e3lQ7w%ZIJdpX~9exdS|t+pCJS&OWexw$ktV0Nh;GDsbq zB_Qu69mPB}Je=RqVD$Fw+XN8@BTr#CV5)A0(gk8}SxvatzilO>z+zj;7N6sKN#qrO z>q$I3VzAK|@FJBMjFMP9Gn_RtK^Ud)8ITB^T>i6z{qyqYE@XeOOo{taDRsQ_Yg+wj zMre8Y9sW8zJZyFeZfjd$IUhJttzdSH6JD%O~g7Uy{(XcA_`5iiPBb4qILwry` z72Ay&x@&5WfkVipl?tD!&{dPt)(b1Y8+;i?75XrO*;%+f8Pu`c_*~Rjlskx*=x#O1*3{ zl6H@a%gFWjr#$dMX}V(i#mMj$z4T;cddq3pm$zCGbMvvr!;|%1EF|R!s3bv=HS(&o zZym(+InLdBsy!vLbm@}In7|Nzb>$$) z2stf47J(bkHfpdHJ&S&sd$Ws7OIrj_T{qp*_s6bxWYNF)7mR>3trduVnN3vUB^rD6 zq8*~QUAzzrjw%DK;~l5PC;7Imc?-;l9Tc;_L97+K*e-EI=EFG#iClmxQX`m0D{W&z zc0tR~ut@#=1NL_cnV0Pm;EC{?9u=fKf66!Ru%Ah|#A^F;n3`q8#|>Wv-mMgmc#VaP zxOUNb&x4#)cR^#CIYy5HFOK@8fFC}=kD8ZB4DbS7V(9$oi?CnL5IC4>*o&gKN862N z0D6>!A5sFWQws3pmc1!OV7){z2P%&r^t6GxzHk5uU!)#=F(ETTjO!|!n0cZ|_3FGs zoU*Aaw9x=fcJutSiz7Q|WJ8q{8hQ?eLwDbTN9b1xy;FF+G*ZgJ%Nr)<4Z>V12%&nJ z&^MdPZa*wMvfTw57B<7vqbOmoGv2?Kt94shes^83(YGFLKat&?gVRR>&-0dd{$g;Y{u_FlruAj7T+*+5)QLqsP-%-dd2kA*02uYYYYuge z9SM-{0n~IZ2PdZxAdrC10R+4Crx(Y-Dg%G;139YTs<&X?*tJmM^-$qXX>gwc@zLL0 z3zWt$=+|viwRX`&B7+3N)?eN`P=xNuYifa`dbU2AnY(%2=D>{xP^$!u`&H2 zEViJuRDFG+Td9}z2e8=9?~cIys(?mr?z-TicPlNXvuX^mW?9P!X41-KBX?OMkr<)E z3J1?0Y`2)nX-mM);inp(k63a?Maw|Q|- zH)(n-jqhJN<*#M|iKlt0WaRwM1l@50g7m_FAkDoqUtShY5oUcY$B#Z{eEIoyAF?*g`h4MfZ5U-p@NO@XOZ{g-wb zhUPF}Ux87N@>`OnC|8Be&47@C?6$?n?MBP)8yXryI2H8um0*d4L&*gaiNp*CQLHRD z>(!Ue>r7qd$AhS0zE1(uibJCw0E^yK1Pm}RI9eVa9$>-2U`PGuD5!2kT!NjF1s>LQ zWpd)CY?<$#Cu*Wb3&81o;A}rU`V84zW;n>hynplNP3~v#+D_6##$FL%RkjTn(VR>L!x6VNV_a{NZ;v2DqZVT`)gG&C9DcGZG#FP>1zE zc9vUJ{2j-Povjr{$2r&<%bVuFSh1I(yp;=d?P)*FO9+d@!!2=1oc_MrXBNXjT>_8+ z!cZubq~*H`G}>k$8v%&j51Cxmru2haoJ9OmuJvvdpTk+@ggROrKPE2(7 z7%}~Yt0sFjQqR8jKDSN2Gg>$cT)-;QZma^nyGe{>K6~}HLeRa8wsRto!vl~DcwE?T z_}Oo7*qxUtDXygfBsap@tOo2ym7FXQ`j()Z+3=7hC-~^dczIxIPXPajW zwuPa+-jn#t#9P$N_WV|iW^RRsqO9|Yt#O|9v97KKSp3M6dGrMFTJ_}cdF^LE2iPXa zv=SI?(x_X$E%>d1Dp@2C8odgL`K|o=?;r}ne(CwTmyl4`yiAq4*-tV)&~$E zPLa?9n;5wGw7%-I;mQv63TIi1j*pMdTbtcvJ3)CF7Jg-FyQJjAjb=HA;OF2&ePxYTgXV6>wmLx?p~NLyjBwAK7hPWRea~S zUsGl8S@6AN;Dqnr`#=)Ui&BZPhwBk%3V;5K&hd-V;NA>K#=0Bhy-*ao39=c%Mm*10@x9;6b zGLzen=ixYG%dG13@Juo{mix<#hi8aaU?P!|%BvG03z zu=@4aUMjGu0DDI-2|kPJAoD1ewuM6w3M;`}mNY1}!WPL4);8E_N-IwUt^1h)nC6}N za_G9gtLB!Vg#*?`=p@Edf;9I3u=W;ERj%Fs=t8!rTO5VpuH_`Rq-iPJfFVh+RXx1w9#mupC-a0bqe^F8nni(t9zZC0Tb$+JqJHkSXnMi=7 z3zym7uWA9C(ua^L{Qs7Qyqq>Rv|CK_DMcyuR@4nNESWWb{U6nzs8_XYcQC9mgP_!Q z(`7|(o1LX$`q_H8Bdz?gnKzVM`!V--RU>sv2MjOIa#*zHROU~f2^n~mAK_GG_$=1Q z{e$+2(!v9qtg8{TLuUy+QvN3_iPF}ob99f_zI}vUhgq*DRK^hD18FpLK-^4W7yXsc zWKZ4bqH2TF^^vIq;!#HHh?`AF_`d&m%+0AuA0`~fJ?nh07H8j)GhR_#$qksDF&O>`1 zx+3$^yG!~fZ+^Yy9Kbc_FIG z@;WIXIC)L7&}@L&-qA6uyj&ycUVsu!umsC!lnfnW(MZ|xFeK+$JO_SO+x_Q~3ygI z;;kmLm$H}~*h{<#xWy1%qLtsMT_wNZF!K4{gPMVcgVqnHZWib(<(iD?7~tW{N z&kld&rT-<0p274pcj#y75SrH84E;N(N6kxyR^IEFXg5;WFdII96dV{#dxS{gkNz>l zFjzD00m1UeNW-8HESs|~OPh48P(y^&Uj_HHoC-rNEG;O-sPHutcGxRKO%h_oNsb^k zMy%PcQ$q$f4dfJ~?&pj}HE&EcFW3m&O#R`?Z+$dR&8v}QgPKHe{^1NH5RAezNPUf! zd{;I(RU3@?t-^?WCoWil=p0nQ)1ONbx*=;IQ}tDvr=riy-hAg3ZH1<0?89$q z^5wCJQ|KuBJY^RX|0Bj^=;RST2K!UlSfPQ-qL}F|6V7k#%>O?)41UpEnWQX5etgW6 zN8Ahn{{P5DiGSoGU!4C%F8U=E7QIK`zB+kV@92^-WX&-qXTQAiqaM2Er9k%SgQ}b) z#okL`_R-=3e@ssJkLWH> zRO>)C!u|UU3>S9Z6_m>P8q>i&sgQf0&)V`tPx&r1ZD1xCEpc7bR^|0tpXX<`SOTDU zTe&oI7O&Jv_VSPJe!V!g-tjc=OdhO9IE#Zty9_NmOi0G9(aaAk*MIDze;4Xeh4Ljl zg~-BEv*Q1Z&==K1$znhYV-C0qZ#3cJ%}Z4dWdJX>X}&!@*W%6z|9c?p}y7GpRFVQ zzrrv552<1Ivr`8ZM7@oWE_SZlu6b+bmU-6xR~S>e2`ufWHryz3;lK>MzwY8;KBB!p zLUjeog(?cOhk8;yyg{cX>@#s+u6>?{-U1SmR2W3`xZ0dJ>@Ge=dD>WTZ#X&iXf(?x!I-i%XR*= zLhqPqg~sJ?KHA!4^|k11Kq`ht*5~!6wJ|P?wt`Eyzc~z-+}>vmC0hyv&9B5;S*g*K zl0<;@*8WlSn0PuRiIpjx-!8PzYqIqS4E+>6t?+pHTPbfT_gkT(Nb$lKWW(B4%yVDO zqXD186>#%!I%hqXAi=%;zl5L2lV$A+C$j{8 z&WBpg8r@Irv$bU9qMV)OGu9|M)f4$RA0ZWZfWnrz*Z#=WSvZakyGXG1=J@|2Sc4At z$DNrgb0WoB&)!Vfp;Zo7F>ABPg|YEtwz6<@1~bb*;#;lOEr~CuIiwM`m_k|k zg~G7Xp<#bWyU}!CC+p|(!pU+0rz%pq*%|w+x%|BcJI)^{7ti~j+y}=>qqRIb^Frrc z%Q=ogg2cdEj@hhCcOs}ny~#UYTD#3Gi+Qx1G0hrvTaubm@fj&|=KGPq7a1}6OW%Bs zuqpKQTcgb-ws5(N5?LFu3nxP&oQiZquVdA#j4X3>Cg}-S2AXc1TT!WrM`<^|j?m;! zsabYFY;%dj_;Li_`S#pjtr<2to=hhff>I-#4tOn_rOP}<+5$CQHTbN^^9Il-pPc)# zN_12@lD-NEV7L&sQAev2`jV=2gCl zcGh~m9A35J+r!O}y1qA0h(71_B$)Tq(}<5bJ)|WTW%7Zx0?s%EjDG@ch-_+56G^1n1*UYEBN0$9r4z zQT*=ZAW#8tJa7LNJ}amLK_Pf?W##r^+FJw6#6#e|O&>q*1lk7i9F*N`Rzp4%+w zQ;>j~9R2O57pIH$KmQFi_N|52$ZXq*Ldz2%asCF*2+>Ah-VJ#V96<5=_mBHB?`st3 zzX)g6MkJ0lOi2O8KZ=~3+^*?b#2gq)v3Fgjq)A57E^NY!=b;{07lUx}FgZ6@4z3ZA zCbaX*rQ@p7($d@sHskI;kPr%ggFxkblO8+J-ps&_3Y2~RtvLeHWnYG130#aZdcM`Y z{r#r>*$<*P&BAHtfh^IeaL56pY+rYGq7RjadP5ME8W3JCM$K>_5bF__A|*X)%z2zr z*OZATMCf~y4ohcFjz24x8up;oB(_1AJ189$j(;Tro&eC3y4&I)EIMC$nKm+K6z3jEcvvYGIP#8jYYzx5>#{F&g8BZ9FC3hB7_Z87&`aIjt6+r`Km2&i-oe2X#NYYI>yBgg z5v0soNDejo^!yZjvjn{gg7Wr1#aQ-FhxI-D(h|WOisMLxn@YW~9#wx!$aUj*6%kVF z_(YoLe}W?_BuH`VOz1@ox&rRDTAQ2W9QU$@jOo~qkA{>DH4L{g7xBzepY0Ud`JX&d zJN_N!w&;NdKN;zoh2E$9(XQEUX_h`@J-6P%;tJ^g{P|+!^6~?>(cFOfoC_I?=22Sg z86&xY`2+mxY^Pgqe7~qV!3H{=@lHg9=G;;Una=;F)8XtQMvLgu5YHa48sb^1Ia2g0 zD^)*qkm|lQ*EN6qv2p9$1iiYKVia6#T<*Svg#-c}=V^w|Srgyurk0WORtgoW8hcf6 z>qOE2BGlpRqNPrxX&mqF5Jc(z)%}Nd&VwSlScL~A=8<5>80@0I_vyp&FBt>^x{T~K z+2!s{I~6mM3Vu0!PxXn6;tBT-41iqv@%a16eU0_V7j(U*)Nd;3a*e&%^_AsQB>oJcFLZv#MSi{U?8!P` z@*47Pkz@l`xixsX3}g(b81-Gm;{hbjdlT|2*xMJU%0zw&yL!@hU8EI^EoFov)Nia9(V)xs-zBh1@fD?$nMV0cl_>q zqLd!V*`)28G`4y?S%u!|b%A4E;~8=JCkWruD^!l2ePs<6F)v|}4O($JDhWAVx9qr} z1>E))pPN+mFX)+pg{Lp2bcdHd5;N&k-mOZKH#L$H5rGy3auVyU-Px@&pdfBL=a^8I zRq_X(Ug(O$YJiPQwIalj|AJi%T}AZW;^6rehFx>xymbw}m2DnR^_V>o{=e)k^|p%K zusy~i3DnLZxIOj0O~Pi84Oe+ne&GlS;K~(_bfuM*J-Dfw-3d|ZtAThtkez617CD=t z1c)4hPqM2|4<2+*ynmG0H<>YTZ@W%*=G`bQUe;uG;C2szjsXFiPQ|2bP>UO*tDZ^4 zf6n15seQkp8>FzKZdn}>oIgR}W5d+uEx}rGo~6vuuDBhm;0!N??giWr-yF$qYzm$b zVsRZUnUHd!gErs2fp)ideBZycY_r8COqHUPf69h5;=lUOj1phi2gok2u}^l)kJiO7 zz0G?dv-WaIQi84K{a>-HTOlU5Ge)kfLft*ZX&ZeY)^vu zi`jax*kEuOBWf|%nZW0;#br158X|9Kb)PYi?%W`#D=yES^Z8-UZ*a1LdH9@;ii*k{ zP$~&w9fUfVhq*v!hK2Q;oCR(Q3WjEi-V?hGHwIkUmQ(NV`EoW2d{I?CHl}|&R%3SC z;e6D5rr2absc*r+y5^W~EZ{I6T)7AN@^-RKb)Q-I7tLx(K7)x1yNqp zwynHELZ|m5{1}WB)Z5tf=uQynLcu@396Z|*&oVz1$luo1W@=*61u}g0Xa5UXV4p#+ z&xXAT4I5do@8QBkb3hrhs@_fg>b5Bx3ymO(KHeCoT^!$4$3G_K@9ITH0U$;^+@)Zb z_fucE{dURo;TI-7VxOIBc+_zV3kw{MD_VTeZR!H=9p38Kw3>%EJ}N_gK-URPvP#}3 z2>U@wMhTBew_0lz;$yEKE>;k>9VjMw=WnWlU;kM5*qFsHLb*g#ggq;DT-AXPcP~QQ zA#!@NmG`=m9Ihu`$%>4T%ky2KH(dMmE!=k^JEl)lHF{ORGT&Jl%YsYehiKvcV=Urp z7d% zdZyKQb$A2F(%1bg#(%X7H}bciE?qY9=Kr1UXvu0ZPM!PWQjI%f_S3K)0^Z#PD!~Gq z;iH%UlLwOmDYz1m{RdtTEkmz@JVhHeE49b}9s{i@9rf4lRn+YBXnX8VAE~uha0DeE zz#3_8ZnlGl){)D~{o2V%(a>-z46nyE7NM-%t+JpQ$gy3qO%frr{Nw`_)7l3qZBmnIpQCl|7vfoMz3$37h*&D@1% zGFoq8mQb_taHVq*y!D!89=dHmK*R4RXlC+C>;tnNTG-&)>fD%a(YAU)2er78Y|NVl zXIw!o2(lSam4e(HOj~uZGXh&sl3pd-VXF*!jX;231LphnJaozRL(6O?qyf}`Q~qnC z1@&I}wa4+f+D(V4Eo=|y4uHmbUs-u_k6blUgfY3l_2Gq6n3MM`EONk!o&v9q7Ka$3 z49z{Nxmw5!mH~D>XkpLcKU@!5Tq^45=N!;VIzi>809u5i&zU!sPznx ze$Rse&uQ_Sn3D>o0ikt1gl1raK%u2;@h#{W4E-#}bwY$b595KFQC?mS+W}Pi;Sbi6 z*Ln8PJHP=Zxa_G?Ic(u1a!?oj>jl`zQ_IuQfXd`v(B+(H%W_F*KmL7mvLHob;g#VG z>ac52ggb;@IBj;L)=n^J>TyiczOWJz#Dec5;5Uw!8;JikP=dUN3NuHmOz8yS<=%4p z#rIFX3rluSeD>!=JUa6G;4xSxijW9enrC03>fg`&t_@nh7M)8Gq!0F{6a#5+~6EG7~VWAu|CVeS7| z9SEf4dGE4q3aMBX&{6r$u$evV+x;=$*Euj0j|zMd^pQM!*>Is14$It+#N(lNQ3ZMz zU3wFaiJ2`A7b9#G=eojGTvCz=SYA7H47jN_bBqoSf`Tvrl0 z|Nkg2OEQ7|D>!0?o}&&Yz7p{j5HVrQWctjE5dwx?iDG--ya`pn40K&NHTlB3Shh!g zF53&|VUuDoRC+*l36h`wLK9!;xaAD_bNj37Y6e)u%I6aOyV;dt4Gqcy?qB`tSXk z-#z=QHF;2>&xOYSqUG6x`*v=rB=lyePF=7cQD9*OaS_PRGCUv~J$j;%k_U*`qqX_F?R|(f7 zgc#!`905rj>>Ar(W!GGp3yq3|DI32U&<0C71NV9gxct|Khr(1_7F?F4I9!xqu2;^M zgZ9GBa3U7gw73>G*`0Nr;c*kA7n&nwVHTgvc$|Dcnq^y;#o}W&ma~i67YdR(Albf$ z#k^I1J&1Qh0-ll5sW4HRkNA8*7?Cuciyt-8HY8Z^rm!0hGv59%Z{T5Y#%4z{lM%k5 z`kj$L{K0P>D}Of0kipMkX0A>aCs*<(-8yh99E2Rt%<*KS`F6-{apC=+IHe6ObNN=54ps+2IE2}3{ zsoB&#QEGZ#z+nWZvgK>n?0?I`^OWvDALJexT!3+23mkJ$82og(F%({X_o3-)R~pbD zFsa1vpOtj5<|EJx@v|>aS3njB2Uzd(_R4ZR%kPhzHFy$nB&?Q2jR8$d0qLKw;9&&i z!Eyb^CkEdH_TR|3$U1oNfODV-w)K<~7~XCiMCR z?R6ooPmOlo^;op1r%ke#&K2`~S-xA5^CU+nboC-xDyyNT@{(Qlz)rDifJwH)y33<( z0-aoIqJ!3qRSf1?UyY|H@M!4?2|{3DzYDP()!sQdOh;f7Hm`DTmRcUV+wbP`?^_c{ zITJf{WCmf{de#EAHfQZ9ga-&_0 zq;v%%I5<2ql0<;x|NA80$m&P9fwODb}$LJ;r4t->$!S7-}KPOCq(B_S%l7|%yxDG z3j98Zdx-?6yyRVXmbxxCoe_ zC*+zm>MMXq_!!(=$T@;XcsctB)YEv;^!N3p9PIxv1EaY{l}j;t=3vS}93jlaE;?GF zBCYRZrcUW!v2_nnsy2F$o9F-&xaZpLjQ4_XAANWc#^8j*6dI$Wg0vGeH80IT%sYJR8_-sC%ebrwh6#rBZ& zP^UgjPjTFWY06y8r;}KM#7G1|PuYvt57BtoH$|1xrW3#!6IG-SCP%05ny zUrvB`c;R?c2ve#kD~E~lE~xbMLR z2d4@S=3^y>O=lr7i@|o&D7B0YXVSa}0|};3REf5#KI(9R3C>*FP_Lq9=&g?@s6;8F zXi-n3VWZBi9dv&X&ZIh+6EB|%k+y?tGJ|4C@#RTsT4;YjZ3%sUf;;5fx&Ol1h_D&aOQ$y)!_~!d9AbB6IqPvk4 z#GeWNgRH75ZB(4t4``>sY8Im;_ws_&l>xvLHb|%6`I}pivgeTl8s^m`2zlepgRijn zA2^(a_R$4q6=Mw#y zyP>)!H{nJ7h{;?Q_eWuQp*w&OI8-492Ygxi+NaY=1Sc@BfXiJ(VGDS(VyNq&1QR93Lpp;Igm=`~ z0Ui|*^vOgqf0QN{2Wk%OdlPUPL;nebguH8BP$s05esz%+fO4JFVwi*T&YeZD&G*9g zf)d4k%znURcVoI$#s4X!Z{6Q8z#tW1>2tW&XFU*P4xnGY6Hb5=_IG3dggz+f)NLj+ zk|jV>%!O-Ob^$i&g9Z&4KJL2Ijq~OMTGVC(xxln%^}_QGxO68oD=Q1idNlh13~z}9 z#fFH-gk9VpaOZ0}Y^uKPpGZvrXL7rUA!aQYKt|c+qW=cyX0BvjhR6kW8y0wVG@7_^ zXUr}XS%UKbYD2MLtysgVV)Ga zp{UH2kLS;A=!oK!MspK3h%RE>>g`57pgC!QUSQW3EYeY{tI?w{A*Znoii!7dQZVIP z#O2p|1EORTLXGg;Wm60yX=(sMm!7 zb($3q=w!jddJMa3Z`sQ8lKo?heloab5P)5s+dSM~H5)6pM?*n+p#cdEGJ&LuszV@4 zGk_jED(knN*#Spl3b=OJ&^y~Kz$*eDKj@0Q8UGWs&do| zgsI%tgnAPizCth7HcaeausWQvLbDZ)ZNnffu@eLojr&1%sC<2jhCDzw^(nMu5l|g0 zFgOx4kk-?Qsn^ohjs>8dB~In8l2^48_0?sOiEn4n0D7Au`%E-75)6u9EM0^PPAXOsgj9&vvW{_d#s`poV2a3pO z9>z>4fcqE0e>748`F_Dc4@pBa8yj;qiNaTpXg;u{Ro84xo9VXw3if8!lQ? z&=A)@VpWra5(;pu-1|#K_9!_)Fjg@$GizF|{Rz!^CcWv3iat0bFZ2(8G4$G^yNF7v z0d6!!YC|6)jz*!OFX~*01$@01DzJMFS@j2UwP7U8JFkCA%aW4YsI){W0|_~R8+B`R z0E{X6T+T!U=KCHwf9_W?kalNz^QFUxMIWTvm+=`X$rbobmQ5#FQ9Hpwxu1L!)LEo; z4moi&DTau={fw6y+WGJv1~YU;07TK)9zfI3vzCx9f~)Wso8#7lGMf}+A%|wgd3YIu zDm3%h?=P2{ZA>+R1UL_sHK3V90zL)g-_Fi{1?TbCx^{MUHsgW(VD`edeZyaoT1ooV zfiGMv&!0aJ?MD$K01=XB3fS@3x>Z18N(6upu_?-b=Pd?alZ@m6wmNbax|0Wc~Y{S^LSpZrO z11PwZ2DBZux#yLnl*Z|m$C;D`XpDY)rnb(q{VurF8c8v`J(%wlaHS##%-%5vW_^}r zjc!$%6na{x^JZsKR-L|2kID>x?b!eH=KheSg}Gy#gL~V1-N>DWyOnq9L^o(@Q>h#r zsAzQp+kRM(>MRy>^G7(v4u4$!xis*$eu30yzWC&x%kDg(hrtuq*nveNu^KTwG8nsb z2mn>H=I3V?6vDy(&7}1~0sOLo5V@}bYnHlAx-zokL9w=qWcQ?zuJpF+v@`8Hr42-WS$HvU_*xoY&b@Kb{uX#&A&(rwj3gDu zare?{m~1$Qa+YPq@@;n*n@B&8N4*NU7iDMQ|0I>5n*hy$LhL7Gfqx0%qIPa+V6ad{ z4V!@zwn|vU?4jm#@KtdYSepR(X0=GAG&?;->VD=1jXobcOmQ>DWtZ3gWKyeZ{;d3W zn@Mxp`LyRM3fr!d3RC;!vuC{{>U}lKQhEo1qv7Lb-#@(=F1OD@8Hmev=7=3wOu%5Z zU=9rv?DY>%5&&>yrASBY40ajMcc%cAxeoBWIqW8<-lxC#e;<14^y_*#>WtiR#bX;t zbSiVVV%hmY*L3cA^FnnggTX1~g2Mua{!QWU={Y%l@HU$_I)o`u&_R$!+b)UV42HIB zbP@1qLjUjiw!bbs#+Xh6u)@jS3cHrUPC zjsZvoM39&}MWCAsfIn(G0a0waCE}lqxB`I%I6tNqH1#v$@bWgWPo~fq=K@m>H{4WH zlE^$+38iC(v5TZ}`jmCfAkI3gnOpIL`DBcw#LfLfn*NqjjY;9n1zVAM6R;mZtEL@X z;XDj1%RrqDa6cEItVUD5N+6^&iwzIXJd-uLqDdLe-ER4MMm4uDh+F8O(}3J+ zp(Zx)4iitrkKBmOA4k(?qKC|FEOiWSLECra7Nx+dKea(gX5BLRzO$~n_URsVe-lP% z4omxBe=Lo#H~qv<2dbAs5tj^yQnxkx9&P)K%nv_5A3ZOePZz_VyyxTbw8{Cn%e)MOIUXxpEge~J zwjDEGX#0Ko*K%Mf4>Jr8ESMtqhDisDr4^Qz?hO$CZ{{7`Zu}v}yc+**&r0hx7=uPG z-P~_`vujn_aBWdc-L@?*dc(%jVIA*$nl_L6XY;dZ@wV&-PxAdZ(@Sp66IyO-ZZ|D~ zV5TcDJCl}&n~J)GQ4xkH0H93}YmN|R0s$?CS_Xs)Bs*M-l?k~!zp~PgAU>3SX0XxI zT2*i`Q@M{r=`)_Hldv;qr`{NnwJnU^o4S3i*{)gdb<^KjE@P=r9>^X)9U{r|wtoJ{ zs7y-<4?ja$uhjs3)tl8~ciGG0922**+OvTBQt05{&-Q@OX9mR=^fPLFc%s*|D)Zf^ ziRB)h0RG*BXXouI>9+44D3Nju6P0m${Q3~*dFY%}6O5KUloWQ*@PCBrz^SxJbOrM! z5avzc!=!2g-2J)Q6AVIm<^@duFBg#tKb`+tICh^*p5!(60x8uf^_n66!v6K z=b%+?rXxO&#be!nZ`SkBcnl`FqN2tQGV(m&$UyGO!NRD5w|q`J>{(qIqgscmLudA? zdN+R;IIdbN_U`|#)ulf9ok^wgTE?gf5fRHtzi>YX#U(Qx?r=r*43p2-nbH}%nx|B5 zWKePzeM%yAAXe;AX|1oEI%9?XTZbSu(fQ2z<2ygZ1@4OSRIpdD??;Zg^HBx4zp03i zb#60uh=~2+F~gpExrp}C{_EbtM=hinPq`57gI-EtuwnEW5zIyO%FAPMb9e8mbhZVn z2;bxW?291t_yU4G9Tyk(#NK{zTq-s^ zh9YTB0ar2ik400fUgV$gIP(c538<*3Wa4-)0{9n)VH25_vQZpDQ18g_5A^i(+`Hb? z@1$T6|6zP79?pT6m$$RZ6?)bxNP`3pKg``Vd=^4@Ry^*Kh=~AEh6R|i7+6>w2Nf?u z=dRejdw7tGvCt1gO+$0+)TvWWK-P}RTl~(w;z=LTZ>DtbfNT3Be zuz`Z2qQB!sf+jBk0s`Utqwg{M_EFlLcD4kD{imXul}@bXj;nz{jQIs7WXX4>dJGX2RS;APxWF>hL2-J6n}9gj5}-eRWMrf|sB3c!x4$ne`2GCpgnyCk zFHj>tf;Z3~W?}vXZ5sq}ZX1$^3zj0`akusTx7Ev;HG5pCLfm}=14${LVkIK9@Cgpp zZe6=}9P~Ls4-bz%+Cov$Ej54_^#GL%pdbE28JC^*SUPYA4?zq@*HZ4V3}#ECcQ9`v z(cqMU`7yJiZ9{sw0cF0DVMd`vTFM<=nbfuXv|TV`fB@6j*hm!f94p~|@!~}% z7z=E^`@^_QBpxt5U^Vi}s;YIs7=D4mqRG+_!9Ic<$_m^{8euK4A=9{U*7|$9Fud->4XtgGn_xy9lRA-5axk!Cj;+&kF z^#B-xB+Ie})RSMJh-mUndigj}Vc}!QS3A$%vP|Y(DwEBuLEX;)vTY<4QigXA3wx3G{}KQ5);2l13x%1 ziB88bK$SCtN$EKRIDK#}Bu)|$pW23UU=pI=7a*7mY^J4pb2QcLXveG_9UDMq3yzNu zf;5IFDJgmK%$d({@5IDyB~o)ulfLv>yvk|mx~Gy)=!?a^pXB&_4t6=CP9<5D>yLZp z=8W>+uh68~Pc;&Yiistpr=NroFg|&Cd2ji95oZlyYS{j<}z#bBL%(vW%l}|uLu|ma2OH2C@An;w!!^$~zQPJCq zs;V!c@TBJECg>w0)Vg!1z8U98Jd z{{E*S8NY;&wZ?FrgOK&CrbYnhCPfX68{C&+(X^#=#h(q1D#LJSIAO_AC(v1tWK0UAfyX8yq7zJp3hu7Jb-S6Pg1>?tMVgX|%5z}APQ<(KT;#T2c;4Hq0#RDij*-Sj zSmT2HmPc*&bDa_~7A^|sk@n$#y#U1f{p(nUxDP|7vOAyZ>Tu!7B^nSB2UD636<&jk z7*t;`nw*^c4yZnCK)`3HRG#PO-|AY&VkH{z@o)(@eC?p8jQ0vW52+_lZn3ekP6p4OT?3k(QR$p^fq+tHJUsK6y#Hj2)ZsGUMN5PFlvSB;~he?UI;jli1P?E>p@UYPq_WM%SFP1nBNaw?(r`?G2DC z<%ySFWOU96Jup~*4woWQ$wo*V%#lI!s*IRY=|pzwutZMB;DOEG_@*;`A>FN}vz$9x z28*|fJ9?SlN#wMIUu-*8#Io_T0`t|G3OwZKa)3e(`Ld->Ca3adI zeOhnX#{3}C%qo6eWA;2>o`3)1g(~-CN>X`P`R0uyBbR_GXaG>vS!65^I}q(Qcu{8P z++)~*X@<=BeEFr7E(W>z?;ibDWp2^Z6OqIVl(1%Ij3Xi@KGm6d|0W6zfJN?sO|rAX z(TW#nR)~jr=m4r&9ttKaB&W(Y^{_@(&fE9oz6)o1_RSfT*`}+9K24INxO8-*j{)6F z3~m(>IXRH3r8*(9;#2Wc0O5I_G63$;d6yeE()l!=C&|a0IQjs0XOcMKFA#x$t~XGj zSO#kmXkI+y_84OL#2m}iWk%H!WtYzEFHh6UPAT>!&uqMBV0&ABHkj!xxwA?v(~roE zQ%{-N-lZKQHu3&^4mLFxj88@AtK5O*bCrx;Qn% z$w`k5@lXg639z_ROpwF=+ThRe(r&O=xxuIsnJA7^kmbGqOTge_ZQm5!65xH*z;(1% zl5N4vEu^G$_V2&{zGd3WfVLGxQT655lTEQe?C z8JCdP3-G~JMn-(Vd>7CovAbu=e?iHoz*)Dkpx|gV8bkHR3NAj1yH7Azu3SM0n~0J! z0ABMTiGpVLDe>66x~EYCcpbJbQMm zs|${YT{?TT+z1*!e?D$)Z9Q0IOjy0QaC2#-ln{o|G(f-nlbP0wC?vt}{{827Tl@OX z*S$Pb2gx`esPq4{l)$}p6Ge04VC|!4*m&wgMa5Nq{>zX>-txKL1{MBAZLJ_J9bMvw z59)TjDAi~mMTth=-dycVK)~M9)4Kx0ub;kph5vJZ|0);PMYUWlV#*-+eu)Tm6bo&H zFJHb)#^=HTDz0C0GHq+T02K}nj)bhNn53ldoD;+~(eep8Zm%3*SoL6}Tw{CtJxfbw zi0(m<%KZbyM3cE7EjhWmUZth|OHok~JrQtM(Q%WWQq9xhLkrH=*Y_uA0BfLGOoD;5 z9tewd5U1XOB`@(R6j8*dX7wRLCW;Jx0L_nBHt_9qUgMljXStt>42Ful}xIuh7WajGa>MLuXL!~2_zvq;G{q$>h6P0Yx zNI?v)j+3zRm{4+1fY|jVhRZhJXz!HFioTb*h0 zRHFCpO@JQd1U%DS+E{EO7Iex9kkdZ3MzXVl6(4@S0qc`!5G<#{k_f}=0>wyZXbQ=K z8XDuc4A-ZCA^r?jx~D*8e22fq5zXJvGIe2i|9-Q9cM_=RG@l!uW2 zCpB8Z5Y#>b#4{X8Or(Lw(sr*2i`}Xl7`OoI*k}YyriZftG>%X9h??NwKY@1Ksl zZFPyG{Rb72H@ZDg@uO@eDt^^QN<-H|+;mEE8pplOdq2v;?D9`F&(ZFNWSd^MxUyLl zD>Yl5o4=Wiol6?C`V(S$Jwi2VLMm9tX^vJL3j!x)0z~4}SX=3&t(qKylIAN}FEy0(xX# zQPM_g<`&?}m7PdYI`PP+R5q(pLn-RPa%DehLN9l$q`y03Y5e=Iw+mxLNaP`=1VF%* z0TY8AtXLm5&?6v5J#3HRN=$kko1t674;T7mq4#j}KJNhgD7YUE)gniCxjn zVVlz%nOj||c7hO>Z#l+Y|M{~opwOw;6B82(N=naQ_8>M;*dZIrPYD?rQHa?52V2Vj z1PN?Vkhq6OHN;_Bh3zi-nVIlg4n0?0Te9xh+>4Re&db?TZ*gaI8EL#*!4gM8N;(0H z1B-C?3&?K8=0j)U==Iv|iL7R<{!-Y6O98&+9H7ZvSKG(l{{V89tk z6eH?xir-c^eT&6lG2gH%P|Kvhr^J^6FFnme!9R&G#k}(!POerN4L2SaHGoQVrl4Ln zwzk#-SSP-C(HHWE9&|9kxd#jP$=3wi)@X&Dc*AMM$#P(7?rt;l>Q<>+%1ElcP7Ya% zMdn*Q=DdQ2Fn;k&s;MRRl=p)TGvOvn;~M6d9(2GpgLH|(+_`h-qhxQ|j-iM~=-%4Z zgWx?ux)v^%-+)mQz>{Q$Z}X6unHdW(8zzPn0JR0U5OEY(Utb|r)o}EjLVJVQY&^0H z3Lx)5Dpz+qaoYAB&AS?oZDanMs;;|4eZz8}qYk7pGKG z1DG^(ZWP8)eCcN~9^%}T&e2u5Hl{^THbQ5-tK^>0$A4RG3IJLdK zYc?cdNpj$S@B=_O5iEXLNL2JMfCLc#u5e!t?wK6FVmfz&lbQIbYqQZB zg+Xn_1Ey4$Ts@J(pk{|7VtejDC6l){SmR!sZt!&b1${696C}Qw$~k;nP<`(H zRz_r9?_`+8lu>aB(YvYQq-)m>9yXZ?pVp}SGF3gBC1AV|wpDNad5qsM)vG@7t9K`;C^*-G zf?Wn9L_OgRHMn5(@Plz=-@!pp3w0h5Z~*V$bNri|yH6RU`AQ!hqMl&=OdeCpLDo(N zr_0BI$dbVt(SEa@)HB`P-LCa?%^>i5PDCzY&KAZ(FA!MM}AeHVOXMaEGh_U2vDeWBb+^CV%sbT}O)LcA+~3 zOm3lGc5FdQRr7<~f-;icC|x1Tug$;j^y#b==2ShCo%U?As0leR%C0KQB4`@AopNz1 zWMAV}sfY3lJ~N%waLf3zA89emS!EVdjM$OpN}6i zKmg7+XdpPM#~TClooGS}c2Bk*RLpF)Qc{qc(Qi|5wG?lKXxYr_ybc{0Gze!NA(xsB zSLjyb9J$%1ZvmGZ#;81RCbMGJ5He7ak{q67xSu&rzpcfUXLW7FsL55S?Z@%pq9=}y z;*cZY4QE~mIe-fS>*ps7EMs9|p(ubU8XBHjgl~wsj{g(ppd=hDd~_N}OIGNlwp-{u z1sfqfJ)MX$7)p0LzaxBO!wp*(u#YzZB{yQiP7)G|ySQ*eAJ3nI#=?4q-;PoJv!#Qh zqy4eilf1w&1KlPHyrAXR%Iik}WBxCHdPB!ovW3^}ukP2o%ZQeco;~{vHU>Y0Cki5-#IP@@1*LrNLkI0L+oIsfmsA@+Wa;tN@fbk@2d zkL5IZef|6p=ZFpnPikUiB@lS+L-$slQRk0G{p}6uI{xKZ%Lc7M?15aq99K zoYVeI?~k=zcau-^TKFK)b>+Y0F;Q!4Rw(g_&zi57A&VMbxp3hE z%6VX7MT>!#kFN`iUiJ0$)HiQRLrHsOO6OwU-sH@%baC-?-w&Bbw+5zgoZo4)Fb@V>^ zD{m;hKPuR>r);b@Pv8Igin3ExS7*Cqrax(B?p#J?Dw`TxX@JdstGcUlM`-l@>jo|N zlc?TI-S1YF#G|=>#Pbkmq}%j10XITSMC1kI#__*@|1KdfFAn}-NRZ{qo3*;DC*FVg z`@9XoMjKOI)b=G!AC=&i;X}^*yhW*0GSgwvA4f|vs#qG!jsUu7GICkMjlzXAJU3Wy z^$_;vD8tT|;L?CC-=l3sa|vp?I)H!HU@GL@XuRqKuiETN zmA#alnmPf_F7$P=!R!&fT zTR0~H)>-nZipdn2l2GRjmK4&z(c;HLMZZc?)4R+lZ?B6^+#P8G4%M*^~PpE&a`(y7yU0ivC5hLz$A= zT9^I^RtAzKUK!P~?88j|gIxiNmlC2=AO3}rP%47Kunt<*5M2!(fG{zVLY^-kYr%WO z>3fr$5qe7=-#kyW^;wl12GWKl(AkdYR>h9;hq?r2NN$B5u#zaEiF1i zgBwgjDo^qJs|OC+C6CbS&k*v5LQ)X62$0;zV9Qp*40XoD*ZPTai?=ul#oB0mdV@q} zJUBvlYF>o9Q$u;Qd-u&&WZ905ZTiQk?dax**|8zj%2#pc=*iT{6T;F29M({ zmn|KzN1f&NW{CZR{+sAICqsJl8=xSzg?CV`U?q}))kxB*a=EQd?@w>^HcP!FM@yB; zQuTmKsgBr8^})2NN#EYpRF1riM{hNZw!hmewd4(bQK^V>e`G50u6L7hzAkFNb+FuY zMc|rq*pz}z4e3SL_>}*!uZrsGSoBOGcD#fX@6SLh4W6X6@!yAPJ@#`45w2CUS7};e zxoq)3Z77=Oe!yG6YH*_8gGq8#6Mr8CX@Fi0s>0 zA@PJSh`oW4=LYbl_pd6dizY-tPa*%ChzJAVrV^9x;)}=LtQ+LOQMyCJ$H2rS=HPG} zJT?YB+l5ZT1a)8er?y|K5u)piY^ITdr3=@Eng{`keDOTor0PBY>f)pI=M*n>_~){M_=Cyq_04mM6(4NB_Qqo0WHBb9>_g?gMT{VymlpK7)1eu*x7-$~8#OdDd$%HrXUxP`7G+F_zJ%YT zKLINtzPZO4@Ms`}4MJVF_2WRgy!cm-;w>xyHirs&zy(2@l#AoNj@T42aQNN=pEH1& zlNare zS;)%M2Qvqv#1NBw(_Xs+#o;fY*4#QYtNgkNM-Em8Bd{oh zr+;W};1rHS+?9})7BMl&m~%>I)z#GnKkQ}DNH_;1DJzU`|Xe5T5khh)z~|C7XQ19*V@mJ77!r2%QYU5fMJn=z?g#lc!Ik za;SkghaemB25_@qK=@<@cORleU^5@pi~-n_P(#!qIu8O{0{r4&nJqoI@osXHVu0DE zZHi0}JC_Y8s|qaToTN+|&%rW{;1~Q$OhttRUKc^jO>R;Tn`yP?H$RZCCj|rqz%heC zw@XUu({QnwqKZoW?h~wpE%3yMp@nxGyo5WS2pm0vMW#Is3_M2_iwTN zj&n<>OHih7L0u*ZAzSN$2>?7WH(*Lf;`Gp_D7QY6sWZ$U1;aP?`@JFwkaxsREhmKj z?c0|iXh?(rA4gspy70g|cUT(4k+BE35dw^Xn$*^2fWG0a>QOsiK??RiRPpnRCzq(= zyZ_STKn>S(=PF=V?F`-aPGJrbkIlEiD~Gg+z^vyoQ($=IK|h91!Dzf7vT{ zb5U_I_rD^w3Vj}8kjt%Hwdxdk+uh)r$lEd?7wh}_m3#kkvf`N_inxS?=vJ*-JcI*>I%S8nGzJEV!qAHn~M$+E*tgGB>i;&Mro6D!NO7X=XoiuEr~AX(CXB2F=Y~ECp~)q8LsV z!N?KT3Gzuff#|pA?Y$gJF_u)vM<*0ai%M(nX8ZRH*QIs0ba^*%`e^S-OL?n3nqe!F zm*M(jU+a6dj@nP6e6t2aIgt~)u$pCK6B86d46a)z?ml>24y_4;K;nHDW==0rU^KWp z+$1;7O?q!~NIhef`qDf-qsux?@^o-^zxu9DV!<&?6{@(U@{*oUte~#*7k>XkzEMowp%hg-{`Kh_O@(!26uHstnFhiV_$TWTLKs3 zYlHDEQhXuM68KG1~Q#aPiAG8bSKN!#3)aghDXPCXy_3X=y z?$k@&Nb}Lh*3onm-`Rc}UHk2IqqLGYt+4~A9=R$+KpSI@+Ba_FwZOo=6<>pxHR=y( zJ*(!DJaVn5NTlzb)5GS=xs5VX5%^Lq25fFVDef_LR`@bTowx9OCku;;P9e-x*VVlN z@Gpit#(k)96;jS6GL?Nj5Xr&OCJto(+<)Uyp`8LWA?^8V2hsK6x*|~lcj9Ie71)6{ zNDR&E`;ufATh|aEE;;bftaB+UZU-Ms2%IH&0a9 zNFrfhLv%<43nHl{ihAT5TgdnP57h~*UIQk$bY|dg_51fn0I(s&xJeQ+beb(GGaQ2d zJsUR@*%Tn9iL`;78gg)BV{6mK!D=CVBTfbeT0JQheh&^+96DpN(_YMt-y}jWtN&J> zp@t}4NnMR*vIDrV2#f+`#<im8C!@)@Y#I5Cq4l9u zVgE)J1<{*t1bSpH#_~2l{Nwe&o%%C;UFKra63M)X4JdC-+ppRjVITVaI^9|1*rlDOCSE}JpSkuE%pJ^ zs;FGaNy8o7b$2fORFgOLdeQVPMRFwLV*K6N^-;4YQ*uL!{)rg~MEvOXP1BbC-5N3cp1PkU!@;a9qiFJpJeqm+bYhY_j6Ukw8TEHLWs>(TF;Sb! zZnPE|GAc?M7p^g{D}}Ump!@VA&a9bz%Jq}m?0LSqDP>3vj6W&jXi;!f7mLs`2 zurO@MopGC}cG!1B*|Jn~XvV#S*~?X=(p*sA04+=CjVb>c6w*8wmfE_T?$Hh9N6&X` zvlltvuJ+=kx_JJ@6l*Y4!f7C)OG5jn{P|cTZa;HK&Z156up71HK7D#9>qpCT+Wt)a zci$cqNomKwcU8Qrkx|$9Eyn12(TnW^3cEv?pVa$!)Xv;JT{BVmEs22 z0g^`l53Oc^9Ez)6Xy!^{Wi*#j*0FWo^?dsMTg{4I#4=JPD(P>X9aCV+GZl&&Xz27f zb98s7y=uduEJX>S{(*t(Xe(a@$qZt^OCn7|6*v6VcoD1k5XS{M@*9AQq#V5oWrF4- zq{u{n3EA#tk|G0`DHv2y#;sv>o$t^S4sn0&f$MLWsOM7swy?0>d!WnkvCF%e_nX`M zM!EbpdU+p5qnt9kfqnbJD7)vA@`%b4BB&}7U&F)w|4-0S8sEHit0m0ikb+d9o@@Xp z#U&FM*!AgCw)v~&$a{NW*Y%-)4Pdpvw@dw%{#8GX+in??>9?Cj>2;zTOi4#LeLDR{BF7*>Nt`oz$~Gsx7RZK93w-`7;ae} z2?@qUnEpF|d&kk>l8RjMdbjVceUs}VVqa9=>2ORAFJZmQd)(1Tz4J*$N4nikqq_Cl zbx(>yBcF2y?`qZZ-NoA|V);{sVI;EF!l8SE&e>p}AJsGL+3qEg3de-wi>jIz*!M;s zx=|!$*q>EoY&02upM*tR9qWjimjny&e7Lq+-0vYhBY+@rz|6I8edjQXuC2T5tQDAZ zHO4;;gk0=dyv&auKZvT^`R|17TMQ-&36 zwwT4d>X>rvRGVC8Uc5VGbcK3nZGCEsLR9C*M^o1rAN_5MT`$?0Ms04I4XKW)_WE3F zn>aCVIrQzC-r2r^YC)BC~v0q-O_`r;v4PHmu#stHWM~^wC!YbM^#Jyv#VQX(`_#7aqZ}?Bt1g)?dj<`I4~@Wa>`t6aO7X!=xY4m zElX5&SFf%l`5w3li5d2yYmX5QxOVKI*(g78dz)5J;ND*BKl~jMTM`m!%*QBFWs8gn z(-)CVnN@1mgu5B?$m}+PwTHr}Y8Jtx0m`3(R7l!uoEID59j_ACQe z`{ui=K16j~hpzwfIZE+3g`RKebHkhAQ@49Rk?XyyZ8F|T=`+^2$M|^S#9EoNlb)N5 zAv?zjzgvp?_NcqYr{ljRdCr@>6Xxe%jjZMk`nW>~CIHO~K$mZ39i`}!GC)&#yNrhK z;{17bdGF1{IP7{*P+-$X#POyqv+YQSnK)L-HBhS$3f`O0n%Jt9>=hK4TH-S+C2CxF z2@qNjkczNXp-`&#pcE-|?OzM=_%-rN5Uv1y4ydZqIevbAw&5>Qo^|M%X-d^yhkPRI zuM=_&Eg)*}e4@o~90C7x{DrU2pFe*d;M({#Hg*sN@E4H7Na0huMEaf}B2gnEu3}Nl z0b3Es3VsJSH!99;!ebJ-(J~sK83#i-<;9?iPpqq{t6M>XnJlkt+Jo4cAA3CA03Hju zOE2VT35kd&eS+UJUYa|31yxJo5ksKMd4Rrv$H(H8wX_%@W}n_pJxw z3@jYB(_BJH2>k{-4A+#gGDxSL=l`Aqx6aJR$0sNxbP%c=WOLVn%0o-Z6204Op>DjZ ztLp>uv{WP1rl|{`p=Wyj{5ia(naL%L@BXCejn#YbNkm3YSYKA0;78nD?PLMpn-pcky%Aso|?JwgXcu634 zFCktd?Mr9QoM~Qj3wz^DRn=p=l>w+ej7=teq{gA#A^J$;Qcs48iV8td(Ml-A@H-W$ z3CE%9B>M}Q){D)7tX4Qv0-#iq?BgC25fmjutN<5uJ7fi+3`0&U?|LHX6E^` zoDoEhhHhU!k+6uUsO2<(!yTgZ&)U89vrNDJkU6EU{Pz)FpYUg)6DO>kCt4#OKNi5I z<=g*HJ)iWvc6kjt23-Jargq{DQwQh?*Z}YkYfQe&pTB=!O`8Y63h!6~<0WGiv4hU+Au@Q~ml(n^11==d$g?9)L z0%^1WMK?68u8`7;b0H`w_{4j|35;5-0^E5EuSEhHffgff2UchQL#npOA~Fz4A3%{g z-dZ0_%FkrjlktUDW)ViXk)0e|^92~s%--=~TReWqSI~*!Bv`;2!DyGRbQcq|dAlWPLdeK|w(u zrLE-!WCak{{4(Vb;A%o+&CSgPEBFHY0^dZ=IjR4En1F0Me*E|)Oa!H&f!;f9tq@Z6 zBS0LHEHt3|$H;N55b^5)wEuF@`lbl1t}Rh}4mPDQar#VX9d$jy$*!j;DCP0g;P<7I z!w23Pe0h07{8iXDdsWr$;n0}j?J2$|4o&)BaGOmuP5Ll zfZ}6ow$O=sWRT*(W5ch7t3ftK#JHO{Iq6Z2*Gs5!1U6d@_oNO~uT06W9PkipZP`NW zt~Rdcr;%DVm=GFwB|0qKP}9opX#B~X&rrBLKdxkJy35qk+w(=x66!={lEqc#@xARb z&a?%hKwE*+c2X>0pS=G3c{>V40x{sNUcY_~?^U*d1&hA*h-zfNL)P~~-UAR#>Xmk) zxrQv;963ax+c$bhokMzhdQw}J`iUvZ^8D9cCWsbjyrzKm(~MUj0UZMK5<7{uVK7I| zBQ3iKIDnJHcsuI*CJ5nMms!9IMrA|DK{-^T@-9Vpp?`1|}7oroe2d9{3q4X*e2Wj#?P=$jZUc^Mnxi8~UVGmgu4RVnWYgBI z0RTow&Guq(L6+$6(0pnM5TosdpCWoJv`kHJWj+5}`%qxbz~!R+^ii|Z(#eOMG$so= z9`nkqTY^Z~4}fUJKm8m1(dkE5kv|lC+(@tqw`XO=3%LYtai0C6GM9i$CnE3+Vmeu~ z54y9+_aM3=I0tvj_MIfkg-aO!ySE6aIk?re|mf-GFP{e|B>$0(u}?O@R3gE;T_& z`ySvj254;G?1SsL5}$VVg=xo{D{B2i3aA+mBCGJaofwAgk>IzuK*$|Z5b~)rQB~cB;=#^6NLXR#mG%`_XQ@QO;+IHcwXL z*=NnqpVBUE#vx<)TDrQqQBjIvdsraTDMa>11OQK-2+F|`g%q5CNuaekT*deICY~}8 z`*#r8R>h$hbf^LiM}ikK0u>67*6|D=z%u!C>MI{;w|Kdf!U+aZ3hi zH6Z;CnrG5iXw&MdbsCh=^VQ`&60@+C)$y@7Yi4k0Xgp%-@)pQxZFHuC45B2_WX9=M zu~U7I^!_c!tQfUev~o1JI9A6rrFSs3mmoDrRZ>NV7Ld>YILm^Q;zmx49%!ub7a{4s z4~R1+=W5ZD)w_%aHox7R?UTtJ)$Ncs?>e2spO^VQ)2h;uFN>Bh zYgLiK4z3F%xWGIQ)aeGaRjj}vCn21uKOvGr*E0n%uK_f6gI3V@`{+W!ZOy>Rc?<41 z^fW}V4vD-4fV8&ab0V+{y@kXS+yDXN#l^+Z7DY>%Sg`Bx*jDm+&P_Zkyuv)nitN<6`IKsEUSXgq916`y>kCeeS97F~@J(T2WY)85hxT>amZ_lG`sb+d zEvH;-FQ;f!N~q^WU!dEWk{>0edt1As#aK@!dgmU=Fp8$4LD)e$nL53{-nUCQxi9FI z8HC-t7xLL}kpoGnGCsVp@NiP8LwY!NlYy!U^Wo)K@U;D(9uEvgz}kzD-O5KEV|V{9 z)1dVAEg@VS@|I2`A3<-`B=?=zVLzDtOXb!Gwg>r~;9_|b8Q~WYh)?vhI1zcSk)C~@ zzY_-y3|Mw^XjlmZhiD233ckeKW&6x}kRAf?QA!AU1ouT706BrEjJAV){bMS??J9w= z81pc|EOz4dL7}{3ds2h0F*U|QOam46Q}|vJmjiMS0Awz9AG(5a8>ANwiFAR~_}ROOuE zmVE}&TzSlZ;z(;7Ity@#5_AfwUN1VGUK79&7g-7W{9(#)nr_+_!2RSh$E;&I8fSDH zkxP%y1vw>W zx?2uOwT5}&&7)u zDMxs@Wf_)oxgEjVB-hfANyKx1dP4y($P>LFR94`|b(ysx)$+$DK&N?>LQ%{1v{;p* zUW>j|JHE(8Ne?eeomF&}bvjjJTHG=p2*3hN&5=0Y%tEPosI9gkgNlc?Z3@xxW#8 zg7;#D(a#y!E4a^$TNBkQ=CV@2ypo1W9>{bM+}?oE7I*5FLvT3Ku)CN-F?5CM9L%RU zdf*6d02j1MSbN++eDB%5_=gr7=+|Iks0CQ?LXXkd25T5YZH0!S3U=v%_%t8p<~CIt z9i;Th{dvYl4VRGIx{fMO$^)`)JJG}q)E?Al1y88l6&zO*7jUvkJ7-PHbDs;jPM4JOqzjv|6{QBMXJx2qhx zmr~yjVS$E7w-pQQ87I7+1(Z@EKiYcc{ErrZD2uk5U1Wf(%u7_%E~NPr#s$*nf3Oo- z5hQ_6os}pa^}ufkWI@6U7WWjQKX5YAs{!+R9nywQB!CO9e^33(5y_2*YIU8)F-qSZ z#Aeq`%{RFQ9K8WtsiqTz3MN!UaL_=SjM2$R@>~}T#=_WiI!yglTB7uLxwTCY^v7T# zNIF{KRUrqAhTQ280j@@IFr(gy>X@K;@b%e>KjRe?XP{bswUxy#Q%7?pL6nG8-OAef zAwrlZ;H)t~zDV@7Nmt`td-O;V)d$jR0I%E5>fmliwnbF_ZO?sVVVr6IyTMaUlP*(% zyG3uL>5Xeh2JHtY#cGp%FN;`eTwI8pX-Eyo8@wNgUYjV{fq{^s07`t)LbydUuzCpQ zpes@AOLaOzN>>O6k>e1{`=9XB_Wt#5#i*i;lA`o$sZBAjspw+m?LxWq6mGg?tG2hd zpTVp!GU|i`DL@AhP%{iEW0gtI3~G|QXN~aCsG5o548&y4!TnW`s7MznFf3alsaNiI z8(2>q9)MI4cn;X3*z?7O3v#fJ_lsGBmWYL1G}gh&LDgfHEGNXcn=uAucE)ZY!6R;cS%Vb zR?W-sGV6cQe~X@4(iJ;$+-)ML4E&nLGe!ZsK_h8i)PYjT$&XWi!w5IDcDd4%+p(|kyBwz$=FFth1$)(N8&ZvQ;i z^plx}tijpSzQ?tt8-!O-4W-8+d)W&TL>!I3OO6{b77)iI>YeyN36%_`4Fgp~SLAM_7_oecbWl!2`@BX>0tZ&D; zJ00;YoD-cNN6JlS5B``FX|d|LaG$dD)zbA~7J}H;OB#|9*ShG-!0QS5b(~uNvTO32 zk5{|I>@SS;)~K=98yYDY7~)aOn&bW^p8UON`%bPrQG1D}my{Bg0KXgkeSJHiIVHkv zD2Ryy@f60x{F<29%yG0Z*37Qn=U}EnY0+Q5NMG^2d8QC;Yexs{ZLVx9?xPpl7x{R= zvc(}F?xO4X-2@x6mTKQP}whQx$1fCZ0dC039b(Y zMs9Uc;RjPQ^w{&Z2k&~{G}|4vekWtN%Fg>w0{zT`s;R8&S0gf<0%(TQexdmyKLRU* zYrDF9*k8$prkT%?)ANc`Kjfsto|SI@qaWLlA>;npQ1yaJn#t(U&Ni@%!d8 z%8B;MjXy)@&t0%-s_K;gv`0Si=VLpy*!u;ar-v+UisQXzN3Du^M)E|)yWUB7ygNPV zhVD_3hI0=D+9`L>m>34F$&<+bnCt6OU~xCF-2RBHRd7d8Y4zTWA@8ghA=wu>9J`A>~gj_-eN9+F$Lg2wRZ_rKS|n(E)a?LjVI4y!r;k{`wEU}yXjP{I%Q zfPO(6#encn0f#%8ha@uem6JyD+CAUCd#oSOU6a$E6v;fImSiex5cxoTZdKb`?_Afr zXPWIFac~;NSXNB&Xut8f*%(yAv`mlv1B2FhQ?d8&vePe6<&c=IxH$7Z8->4nK(C5g z%_Rp%{g8IgxO{f2IGy~5?N%%=j-`hm9TC49buBRLO`mF1PqaeDYP(Mdi+(0Y5n-2DW=mt1v#n~}ld&NJ%ynOql7dZU5ABa>zpm%Vlu;a)I~t^7{PjX~l~07I z#(iGZi3b8xTiwdk=^0C2@~ia+Tx*zWUj3rcNHaM{t!#a;Myug_<=WJWR6S)Ywvpxx zkE4aA>y@8Wr0Et==U-JnKM=9u`*UNyc8?71@fe$CYc3Dxj?=fBXZ_bav%DYJboZ8e zYeYwD$yN1T^tKAVW(=(A(j7CtUoKGNuGBDbC}$pRk!7i=IVmHY-x6KYu-h^1#rM20 z&V-N6EkS2o4~$xwI2Ct$OKIy_IhVBU4_U7wQ2dT!DWjf?JOJIWAgi2_uRBCH%-HIM8?u}LsjIsgWo;g65l;y zbF4UTn8CI#=<}l8L`%lDG6}M#-lKNtz|z||CCAmtIw~J-JKFv##U)6>Rp_|HSsJ-N zeBX|D{+!h8X<}qan9WluvCAH8wtf_RM$RVsP-w%Sx4yn@MVWDGPJUZHT@RWq)a|6~ zGUXXH_;fQmFffNUT!6Aa?pNIdCJV9J;kw}5jxU!*lW(f*-q**l9h=uP!r+1kOp zjOOtA!HYIgA8W&ZTh+Bi8sy*XUU2BoKgKVbH#ChK?Ds z^??!l3=6blPN+)hi45oOS)I2(z0F4X$9^m8bV~c{+WC&ux^r6;-PR#R6WgOf+)(cQq%(IniJ zyVcZl*^8Nar(cz9PK3upF8*ugB7m}hs@`k|);+ct+JquUE|0_^eHHTxTS+ZpEvL5= znm;P{@I4$Spl{GUL^^+?Hh1S>@Urm3GZida0d*`C>}$is~MI zDtPcdhcC`7y}i9GoSc<^{uIs?!n5kpJdMAHhHO_ZUv^cAi;}2yXmsYHLf?RC z(W?g$zXD+_9)L82`F91s6{Ujz1Zdx$N$)RXo;}mE#5D|v{-;HzUg+x*CM?H!>6A4) z-qPRZ@3?-?-=#y>G&enR1y`()h++4Svks@jUJkQZT&On)sbS>)b`neW>zCNy*;(#pYXa)!0x@F<+z8TLd!pMyNfhVb{N^niU`oW}YZD^H0T;XTDP!Y}f z`gOU*zo*S=T^C))9KG44$oQ9cS^mzEzCK=j6nH!FJ$w9TX1wrn6mAB*-`jWZEF2x_ zUzu-Ow{G2<)&8#BXFNSwP?0F@*z^+rieErLf8q+YBUcLIm=g*-aJPQ|T!QFbF z0i}llwAO;!|CMlki1kvbD|3LSZ_MSqTsF^S5BkElhq7A3Ykv zC(gvckfE$`e~qj6*Ycq;BrAJ%?c7N+W|B>NdwV-C%y~^rPba>3vAwLU3_BxgcX&-r z4fR;%$jAtRLAqd#|0FA`3Tl)OA3j{dBqCD}3qp_+@2C$ScF4Vd`*ywZkt6+e_bc(7 za&o~94O*B3{RL^TCyJs5U~kr2xg=tFd9S48DX^eK@#I+4za=*>kNonCy}keEpT~Y{-)_c+1s-|%)-C#a*YNOg z78aJ5upIvC&50DB{spq225gg}BAKGnCbz>v**P}#+wexO`d!=0hJp4~WNv+DV|cFfSTi>awmT~AMMfjJ02UhS2Z4uq@uk`NumWC;_7O~sV{#5R41 z`71vb$uSdEi7*MCu#5E7P@O7#nR!1~uhqVJ{L$Ty1#DCftQMN<@0g1bgODDS&rp0s z%q?OXiqPkK$wfu1m{T`6I7s+ezC|ai@9VjFl2+E?D&K4ts+>py5!T~FYpcLU!LH8E zo1f=@oFDx8v#Po}(D?b&r_P5%nTNdG-1d;cq+0%TADNYpT~B7)lfI=rr?fqXouVv; z&`ycqhvc9Vq<5bwuXdOfKJb^3ro3!Y4hN1Lp(R8-v9ZE~oN;nG0-0cJqQH%B9wiNJ zZGo`-ZkBL!b92=`td_14O$XV{8Z0ph3p3!lWgY?r$>ByzsD4$qh?Pk9x$r<<4bqF! z?tmCVnv`I8<&3(OG}}Q#|FWlN2h9UWCE&SFUK>_OHvnNIBqpxFTvPUaS8~))p^)kT zP-IF}Ol+)@nb~$x(^5eJgTH_OI{*1~Y7UifRZq`@i(bcZV_;_5iEt525B=pSmtrW# zc)QK$pokEcwp4zw_OUf(UK18ijU0B`xdiTvHk9X{WDC*B%4~l6>C8C`Qn^$s`TP50 zKEb{Z*es+09J54TqOIsDoSq<7Cc=N0X$Qb^z`X*PA5K>xk&7-z5DjP86DutW}fgqBUqL>)&5vd$|ZKfIQM+u znX;g>NfzIkc(VC4^=~%ZXxnqHgyCe!=grvD{2H2?wKWVvTCV8Mx%%c5%>fe=4uV3+ z{wQ1#s_<8k{5KBF6fai}dcIi6FL7FgpDW-VLaQNjO(eEGyPW4H03PKKdK>%L)i4jq z@EsYY=%4+*J|oBG*quoWmHwbY6?Q{$p^Egq^|#7Z9gNgI9=6DnSj~T2PE{b>$Nfpv4R$ zR|`JzR~X-HUiTm$>TeD*U-aVqh?)LTMr(-@QETH3(JGJjxV#=!ZV#@3O`l=jYFgSc zVgQCRumT?c*U2O%oDM-@VI_V2t@%!$Z*9ETvw~nH7)yEl#EFO>w}S)^ldGYN}ChZe+`R^Qif+Mh1;%mV6PuizBsVWWdc9Hwaq-KD)c2b!9^w8*sz0uLp`O_z$7=-WR_iEpZnWLqcgrG5LVShh8 zt;{Cr$d!ifbwTHI8*UuSYQ5S_w}x6$#S+qbt7Oz_+=C})8xnL%1oQICG{iX$ExxRP z)FrU96n8KNkw!`4$xAHcj6nt=?x~!ALdmVwJ#nI^cqH=;L}gp|$+Oe<0z+|C>c<}c zlePGFHxXqU7#JJ?-GT7#uflr;nG$F>&K7h7`&E^gTp5SvBgBSXRb? z`zla5@edg`{K+dx-FpGETbao?k+GTgehPdwR=1uVq_p3tVLCYUhf%DN|3%UnNwre` zsGK^o*MP{+4eP(a5aZHIz^osj0wLCWv)$7QM9&3+XBTplj~v1bTD7F%T{Ac^kiw0h ze@0#`*w-8FF%r7_Jo=gK$v{CFWRIJUYW#W=DR|Dp>CF)g_jyc9=Pt zcX#tMXV$<%&>)sufVw-r=KA$VT55E$veB>CD-)6~L^&I(l_=ci%!bUFa2$Nf9Rk)afnzjtJb>-&BG6 zM3p=7P*s%rT(a?Kl#$(}ecmbB#L={n@{EEwHS1>4noajI^X`X4=-$-L2(FfDNi*t; za<2J7t9;~w{*6~ECq*ei>oS5sb+aS1C-1ce#H&N@60! z5@d;~JecOz6TdJN{{g|AP&9T*U-sf&csoNOYf0BBqazT0E zadQej7Yx*@A_7xHK~m+Q-L(<}=dSGb8B!-_6#l9oIrtg0ls#ea_>p5dLqlqLpX!a2 zd(N`E)}=FtYrnPYk7VRfu8n;dd0WCzZ?_)RDA#t9m*M0_8w)X|B*(;A|1+{S(qr>V zVXObvT_nt??-DH0|R` zzS`>K0}&iabuJ{rFV4MREJx;q(ZS9bF3?kFwjj|xcI*5OWcL64`=_*+)n;uVGlfJ4y3o0M5_2jIy$9C-aekXn>p8!F3!QLA;)gyz-ZLVY`?sY zecF0^_0saQwLd8rTw_R>J()A>-#nXH%@I_+A5#laeD+Dhi;_ag6&44aAo63_qIuLr z$1CQlZvWxB8(s8mnfW0R1sB*lW7wbWzusoL$KzBE@j(g<)aKjwX_?jXJhLu{lgJOj zS#dA!>Y*2|vhoTbcJU)YqoR+lK{#3J$2x|f-r0aSrETjpypwWF1f12_af6ge51^hA zbL}Z4#Z|YOaxb6Z2I)WIF%PAV7cseP7oeM7#a+7>8MbwhhAd4@u4hnSoXUu%<6K;_ zyK2?K>7=7+z2S^eF$?$WqWX8_tRwdlWlLkpWI^?=(Z~VyM}wb`idxuj$6_pCp9*GJt| zx2kj9)P9X*KioG3@9izu{OBzo)4kk#^oCr)v*3HbPtF@h00DL9FgQBWr;>J-TIc`v zd#~PECaUM?nE;867fv%!S(j>rlP|wt_ROLEY2(+gyWi`B2#;$}V7q7fpFG1|3T3VJ z4zeOGkt$_2Z4K93#sl;1bGxltuBjwYvN-M=8y(Aitn2WTm#3^Cg3)`Z?YfQk8KKDL zVWDLG7Y)*r!xEiojb~&jnw8|Hqpq5u=Y5u8B5Bj>(&2jBMYH|7P53E|DBkxfUp2F6 zPiSi1a%R*>I-4hz{#;|H6n|bJWjB+~&4ybmEgj|(tRusIdXVb!-!oH&T3?piddw|< z+?p9l8J1)_CLHxfRh3nCD!@Jd!JYquu&Qc2x_4Ei!aC{veZ$ZLX}e`~?wSqlQH>R4 z6w%7ZX~(u*?qQZ0=1`*7U|*LiPWk>dcZHA0G;M=d{VgvG-C4c-l$Ph+e8zSzD!<2) zZpZO{oUYdhj!~go`cNYxG!(_&P5fDAS$CVR&aOgwuSedY2>Kz7IF_Nj$P_wGZib>E zdZ-Hojrcg79}VX$%PV=ntAMP*BxAPFRGxb*P;7s^;YIJPyYfRVsYjA_rA-B#hV2?$+E%BZ+YcLBf`Ti2k9mBav!(eYT3_Nlon#j z!QC{lPy6wi_s=x^vKT6s3O_81|3!>oRYLX(T~!DfJc%KNYUfpolPJm#N{4J?_sUOY zb-V9an5t~#(GALJ>pr0-9$21wPAHi=xkF7vFPYPt+nQ-apjJxbzCpEWj0ZPvXEoY1 zJArLh8w4`k1S-NbQ;atn3Y2K>L1ot8Z(WMPJLF!`GBF7u(-Fz^mh8ep#KXgvcMUmo-OtJCE@k^$hW zLO@}R4xJ%;cV)|rHgc$iYN%2eSzj%)Tow3yW@g#Jh;0|M7#LWe<>uyoZM=0{@ambp z!iw?n@l|i%27jFc$nx-b^*GD-})2ywc(dti7@rzzm_#9+ z{00%Rzpw<~pm3*ttgNaUyZ7@V?dQKO1yA8^d2#U2_Sduuzm@^x>)3LP`?23K5-45y z`H$sXjp+Xty$qW}eqdlgOjhU`|?LGUeEpkMRq8f0X{#1U#V7 zUa>$Soz;Q-e+Pj z&nA?%CC!kPdNy6Zpyk1-gvnv8oBC;vJhT2(pUdcS7HSs*FfPEDRDM08Fwp0y8m~%L z5U<2PxOQ2(hDM-k$tU0)G~N4ML1k$ZP$=NAg!50raEYBpIyS^E%`y5B2FmQiMl>$yIM%N&ROLQ$-bH;^HEh*c$QFJ6P6pv#hWEc;(fO<(Ch1xuv8>;jlp8^J--Bb?+DDbHrNcDc(j&^&=;ywz9wDvb#ry? zaV^>uqD-{0L~BJvsDNas18eZDH!cxZ&L#2!<>nF1(X4>l2@+Xees$PvXb}j43|E+R z=9Q$}+|9l(w&N$T{c!^Hj4w9YbA}#S5RqrBdcPxKf?C-FbBT4`iwo1eD0W_RmX=;TY{5I_S8&&ChSL63#B63QIp2tXNwS-{6LkHLXj80Y_*KtH z-ie6;w;-sjtlW21{hYMEl- z8X5%@rjKP;;)?}<^3HA ztIstTAI;P0PK=m&^yrb8nAjz}8G)w3$E;Yf0z3zGacX*+hn>EvULQvv=d!7(i4=jL zVF2QU#p{DTdGu)YKUPKKZ&Vh^Y$NuA@;x{jm6L7pQ;&OIx40}@Pf01|`H2t3e9k$@ za#J%_!hp8_jx>u zYgLTk=8-KQ@OUYEM!z;lL5yehb&fEv6D(_AfWoM z!h2vN*qN{Q%}PDBI1f>_$tFF2&It$)Fl0I8rG4KTKZE%xG|t?+8~$|+49RTa0?Xq( zhUgg@?3hB7!MX$hCMEa~@N9w&0$%Rx=54%#<_j6Z4gpmM8$&KCa;C zB&mHkZsO{pAg0GvM<_|BLCX9PXPhOA01;7Noh=M(v_Lrl1#W6>?M+R~R5CJR>*(k> zuCE^etP?j(l9%n$7s9RaAGu={fEE1@n!L@#)3^wT@_-o2N}9q?jzD4vhLDkwL5iq` zjt*hPtkhJs-(i5-@j^>9h?wiv1Z?kI0gd2F^%yRMu!4f~hksHDt_@_#z}R>tO+;j5 zP1#{bSkD*U=Q(@!EO5&Iz6e7Za{7dwR9m|18aJc6b8>U9c6Xb`$)4Brjg!Byg|xi@ zlw=5^(9mEz5e+DD`6O;{=old2+J}~w)mg1~2a=zzzTimJG4MIRhi7#E7x|tDX%+SY zRtD>Bs4xRnTD!W~iEIaAn_i52FQ1!}yCfp7LiE;9Zr0H;4k30ovY#9HQnNCKTKHMo zOVQQU!Rns7!)czgh8*z`rG3wL-5Lp&U?6F5lF07eNH&W8Br5*pDcV;9DJ~9R%#RO& zdXoG+)wY!B8ix+2WLYlEPC(qwB8OXBMqC``Z}Z$Z?~Wk8?f${T)xrIAsH$ zHD0XA6}k8Jj7bNVwsOiYs)Y9#@AIg)u7Tyz-}yxKGDXVf4EBw^R0qotMw7J zGS`R>E!i)pU4>;;f0{WOaZ5ncuv8my1XnH9M*d!99*6IDo~(Q~lkO{8d*d8mF@11l zqy}q7ejX!(owdc|l+j)f6A!D_e1YGT@N3z0Qap4j$vzSsooyOnS}EyzImfbmpJfN- zrnF|ZCpqWTSaFvuVY*h!o(WjgaI(jaa%Z`7r|B;}G5453L$lfcT|p%T$7!5|8bvN! z@)>6a$?Rio18SIigTH_FRxOQ-WB)QL*qCp~rZ??=BSdwVXv2L?J8^!dlI~KqEP-e1 z4Xr~el_MPgt0ve4Id>&JPX}!LxUN5AuDF zQ}*7-ugP>&LU>nv0!l-cGE{P}c)jij^>#U}7mM8umsyHp>o7Wa*qOUi) z(W9A7{j3+oVvmkf&X_=py}s-aDCSMm7m@nnd(wz0DuxpDIjeMhEz(6}(XGVnhcsiL z=i<)&`3*h&Oy&W+Q!es6d^ts-yYZKSI z@v$Yo+H&$zliP4sO@wORuk?z5juvj&h$Qj|)qT%@NkJ z{1EpIt#?rZ8hW|jcZfMrX>mkW`SS|pd>;vyl%wx+!*eiyom_^HL6FOkgQEfn8MGHq zpFZ7jBA~8c38GU@uRaDMtJ*$OeWX#MI^8g|&>*PhKwh_|A>FFvzu&jqO=1W-xXUX! zN@HIRCnad&oy4{*YL4OTimHQLk1c>szl|X995qUXms{ZA^?(3z35kR|J6OTXc6G(c z#dnS>gSE$XhOtjsF>*CEMG$)d19^BBg3uZ0c5Cfs31(>MI~99qR-Ey90n zWuWh}U+Px`CEM#Zp9Wj=cNLQHL~S#Ws8sLNsD)*D*0M-MMq;CDiBW)!`C2 zn6$E{t&Ihb)xXGe;W93thsZ_<%$Az^8XR}uA~Y0QIy(N4W?(dFY%!arjt*0oV}ac9 z^a($3)1*xo^x5`Hb^U6-$#?oD=3AlBpzZ-Q$9Jdyar2c~83u+R2o!FrUr`C#G_+VA za6)wK!Xv17NzQ|0Lsyr1czBphbi(DGh|~y55-daH;`_R~XXlENI+@i~!$E~@@%z2c z&mXjWdy7XZNgi@Pq70oozFQ8F70(^}ov5 z`Af3OYvmSC2Q?Ul1jYSAVJT@?(CuC}>5!D(&{-MuHcP+YOp#T7o?)qS=N<_~gfBsK z4zXQ6Km)afYiKA&mom#AP6}`jy1@%;G!%v7$cEYT^75AQ$ExR|N7cXe@6;>$a-EHE z&DjqhZ>S2{@Dxbx@n+kbn9HcGTsK@HETLVfcZ`ub zY0kfzhcYZxtQeRdzMiM-0&p)wwXy>gPHdJN=Yv$gZy;p_k|N^^qj@NFbnqL{6rsIv z?@ph;XWO1~ed5~0kb$K2_Gs|b{hHjV?>$Y06xO26)&IVnN=*C8>bADF8>Txhxh_va zA&kT(Ho6?XglI$FvB4f7m$Ia|X50r-c`YJ?ZG$`9jie(EF)$qop3B5d&j?Hx(0kl%S+46= z?OrihWPVi*@A8EWE0?Ecsb^t=xX{!b4b74Yi)~t8?Gi7)EMxqIvhK}Ubijn)5<2eW zyG+v^-%lw~hW28|K%avGcS&#du(0oXL=W_HH)=MfoL}lGmuX6RD{YY8|}k0MNQ8RdH-0_+Y!~>q&FcMUQ3c%XXs_0Dr0(K+D+Yp^Lf7| z=t^pDMllz0JT*DXCge0NmA~hp`MLGkWj5bmTG3JWsFX=qTsZS&ez&$}()oZU9iHrI z6vJ=O1KaEECOG-4=aUI;>gx3fhSC7e@Y!qO7!i(Enw@AHflP`211YeQMUN|iTPQu; zgr7h!Hqi$#tX~bW9nbX2n0xmknK%uNMWefP5>e-KhSK6E%6sB{4epODu(tN{`1b+- zs_i;e(gj)3&AIeSkksvX3>KbqI|GA|`gfm)O+1IPs;+nBqKKcJzuk71XKE2KzqvJc zVS0AH^el`u8LXLc%jyYbWE%wPl|bOMQ&be-12@QNZ*N0QHF5}ieK{W9{#{SWTkxf57LCEwmHTegVF%V)41`3Ib7p;r@bpd_lJu!g)0kQC7?`1q8? z(TsVQ5s_x=NF>uX;DM+I@u#o@QASfa{89QANg1WG9jEf->*}mhaP+pv?y!VJ>+Kfu zVhB-YSbME+<+Ta@V&21Q1`xsE8LDeG2&G_o`C7%1n}=iBw(X;L^IRfnka>y_Ng*_#$PkG#W=^IE$<$m( ziJK%uW|=aRP%?xh^Kd6+%9ux{BKhs7-uHW-^?u)a*IL{5TYvm)&-QHMcHP%?-Pd`X z$FcAGu^+@K;+JP}*aV%*h3C`DH=6DF?Q%peU2n3Tihue%n6++gNm|ggZFdCi>oqLv`}q+bD49e;T7#NXH0b5+&;yfgRp4DNk4ACF z6=*OHOmtZ%E}_mpeLViWXO0V6e%4gFv`5+Z%+O6k%b$U9XZ*!Z95?4e3Z~Pc zWu2=`W96G&xR4&Y11n=pB|KOiT;1hVH-&PYwObQ4v5>xc@vZqQ#)r?%{()}PME9dV zbk}w|^^wU|L&iUZ*HvAsNNImjB^&Scw-Xrsn)k0%2tLA9WV(Vm3yjzL$er7$9RY1q zITdAsfE%Ib#8A8#DP|@A*4iEMBUHJhg-=6nbKUkWCx#|X z*ZasX=i0ROTy5&V+7LLGDC#KMMXIL!oLK%#3{=|Ql`;A>nGRC;(rgRXQ6OErkEaR< zQ)F!HGU!;&SzF5?_aVYffKq4^6g#S1>C>Sda*$n#bsK*GWJu8bVc-rMaLTYL`R9C>&S5mOoV6%Hz(U-;Gmh!~ixpZd$bED4D zs8vmxsTR>=IEwDlqm8(`$Mj&>ICb!%doc7X!d9`${VOVrOP zu&=ghcw0J)*SoU|!>2dMng3-gwYe%z*bKJpJkEM63adqpSt~s+fsG6*{lP#3`}geO5#isO z5RjuY`OMgZxa}dl&IXz9Y>y=6D0a2-E6}{dYrVY_PeW;-z(rrTi_@kdw{XOU*lGX% zJvz?)|CP7-|TeJMoP0?X4m zIjr~!Yk#a^k~q~>6!MH=Z+7~!tW-OuozY@KH{Xhec=&A#R}+@W97`&DIQ*jOCc`D~ z_V4|50w%rUbQRUp2e79pQ&)ForvB(8q9<(O3BfhVAqV1sR~=NACG zMI$sD5SeiTQ6O&292uit z-10Nb@w>%Z{|3|*Ty-~|v@TgzDEzIpr75*dg%RSH9b(=Sn~&{Ea$d~-x3oWc#kHuR zcY{l;vt6l3c5#{(>TZVXX$j^7X;)8gpat}Z& z-{%mEC)a2r<*3?Z#zSg9uQB|w7>R>MmS)eUe~=W8Tk>sB+Z|YL`B|t?C_0^YLP2J2 zii|{)lB<`hwk~f}<)Un=Q{g~VN1}X{kE4xWO2e_-vvp29+iq+;Keo-L_U$hu9BtOf z3_3bG$P)_<%Qe_l6C?&$C*VXlD#0-<4~F1lZMB}8iLx3HoQlWMqPY>fqhj02i23Ck z*57oxIo9c}5R33Fr}FNMb1oUl@=e!LRuV}H(jH0`&}m+qax<_l!!_OKca=5QR{uPf zcco`<9_vs59q#OPEd1?P_D=0)hkD6N8oLGpt0vF(1mpwh|CgqE6LEGU`akH#|DZ1b zg5@B=w0$waW8LwBk*q&tCfwbH z9*s!T{UT$>Oc@2HZIXmqDxIT-*cgX=Xx%=Vsdq|qfUXGXzqm;R=73051HxoHwgCpG zTt!Ai`gM2g*pUZEiw}Ulq2eM!V%yxpJ8jTFp}q8ZiVfYyI^93LIMpg)bT`zs49#(` zO|ucCAs;*H83yP2-^FQZYAn9lD9CWQ);xPoBBK8}57BH#I@S=M6n4j$H>-Gmsd}-W zQ7x2%_jQK0*fx2%`RZNg5?2Sg)02UW0gB8cz@IT&n0sDW8X1fe(I4!p;KJS>dwBO2 zIcTiWWJ0v|P$W%EPF4of@P9zaiz)6h5n(IyvEs+RY`AjTvj_@&Bs8%Ey?$Hy=s?|< zEW_&T<$E$kRa1JKUo`k0yBzH#5TqDnYLXpgD`j#b>5Y$#c~9yQtunX+v~g})U0L}6 zUAlSmZfJ&3%DKN1CVVWz*S|F%!vsJ$GYq3Hmb*wo|*Hxf%h2Qa_I-s z>PPNn)6*+W#$In0yhari*3q)rkqEVm&mrR@G!dZte-Jx8$E*Xm#6>hTG&pz_pfA6GP#2BV3tc1M9V2Rk%VSZr zSy%k6uo%*IiFRtYkKgW3TSRNh@&E2@XCg)2pjAOfvnm%-E{}PLDgqGsg*WT=oi#RI zjLNrvWF%-l;?biAE3^Vp)s%B<@e2q5y7op{$>@g`>z`NrDyVU>TpXF^78WANMWEIs ztd^;%-0v$ueSjit*}nY^UoAn@5DY3q~kyT%1-l8$yP>74@O4l9X7*R{bA;oqDh7LkrEZUU#sCmZrfblz3KF` zNC_PD(&sOJTpZQ2OIWyil!iyOLORA0y(5H)a(i&|@Y6g=kYI?eAa`zoeIe`a58fhg zV;YbX}gQQWwcrzRv^Rvrkh| zQxj-Dqp7)cp^Prz$mdYGJ10=4ucPCG+6dYI57Ls=hYnz`dSjp{q=u(wRjPbY`qdi) zSdefD$pWWC$Iet9*RfNlg2Hwi9fk-eV;yqqq`>CWyW|qPoD0aAqn+u^xI(nLvWkik z&;WoXI2c6T0`H=u6#uCO_`Q7bA{6LEbqP!OZwHM%f+0uvonnl>A`dz=X=0nxGZ$0|UfS+cCdtiGfJOuI1LPWu#@{ z6<8he9>tJwql*m6ng9kjjh}z;1$M-M!ju@-uYZ&sz&fD8#^d&^oP&EfCMG;EnJVP( z@2UZNw34Ao)cc!cB7}ujm588tK#rQR4C$7zpC|`MG!J zWlnFEdWzTacNFdB2>)vbVq+d`)rdNNFVOu2edq)w)whwW31@j z_yv7_&IR28M(N(7xwLzr`Vh`_&^PVuBzZ6c8!RRvG&S$GaCF!T56)zOa-Zp&7q&f8}9B)kM}b0;6TJz zai(qa)=u<@&Cp8eYzk;yP`Kd(3y6E@?j^nTxVyffCA*|x&iYtUg~82dcv6<$)gLQ= zZ!+D=tMHK1{)LWjWvNijcB$fe#i9_K7|q=FUplkTx77jZ^VYU`@m6worldIA(o+HQ0iUtCw zub%8Wb}M3T*a9@eDR&zL1?Y&LjkBPs>7e;9rQwMm^kzCQoin>dIYrA;JskFq4lSq! zC6;awt4vmIv&-}29VJZ{Ek#p%0aKJww+uAX(vd_!B>bVheKlJluWUMRlS27s5KSr73=I`RVrz0#aXXsZb^YPuaIIRM2r=+r2!V?N~r8`I@yXgA`4Wa3H zqc?X@@nW9L5&7JLrZJza=xmQLbJ)J1A&iMX6!1EnEZutr3}3^%(gfvj>$cE-?~FE< zRa)zELY|G-n0YwAY-uW56Zoy1V;i+TOOxk>Z@JYnDVc&{WBD|y^32Pug%%09&Hn4( z8MAux`kha!_^o8ock^(Peypg@iW;rpy1Nxsy~n1UNE^R@FXO$kW8c}+U-rMOv~|n& z`1s5wYV+NWk(f8cG6`)PHKOob2c+ckmq^DlkYJk^vWo35Ij zqrsTgWZX&B89K<3QDi*Cc*a7(r0KZJwl~{J!4GaZ9L2Z!3`Kq7k)%jl;UL(to%Vp_UI(07#EO-$Yr7y74 zsVSSE)Y->=B^tN{ljug`N^R#kzMVK`E_Cw1 zF{(oF2KYEzTcM&~y~5qRvOg7d=y~Z`Ht5_PLhxxFH)ZS+UMwfqoH^?dWJ=5SG0-*d zR%~+EKT=RTICto#Rz2H}*{D<10uF6~2F&&D1Cpw%mo6si$+6D)xlY2m(yd*dj?pJ% zo+e4V$sqK6YiK(O0Z7pnYS;-QVxoY=C}!badxniE%OTo)^_E)z63#SM)tG&L25VIx z3`?GT@$gK_OM^KMU+dgbt5-o)+jm-VEsr*15EePkytYcY@O(9oLrKu--1^s6aU(-= zNr&Qid-h0p3Y1&fM`;QMGvv&{w0>+jv$iY$>ytMyXkA2cn;L%2RQyApm`9&Ge_kUD z%8k|JHlg?A^N%qVFXOEPlR@96C^gW_P%)UyE~)9xPad(XrD&&Td`;}69#6bRXbC@o^NP;sA5I)vbESVD|rTc;WiX) z#Ly?*X-Lb_$>}NTkPagWgD%goXLF}|<~YB5YRnGPd)Qf(ahCMEyN-q2GZf4*Z3$wW zy%AJx8n;8*)oj>DHvN-k3hzd2;w}TR!GDnpBU9@E;-EeM8o{#Wfnwah^s;*gGQ`79 z9r)OZ&C>?Yziwn1#2qnR>PJic?E3ZqVF`L}iXqUS$+TlB+!FR9PFehurZBb6xwVHlp6*izzyLyEWb%j4#_AkuUQHiiMs zboI-W?=`){J;x#8y*_1iYyW&EcgnZ{VGvsgZ9M?uj^V%rQ`sJDJd zyl{(New7}5jn;qu6efPczs_ZOl9-5IKlS9v9K#K z{z*w`=~B{FMm(@kZ~T}Wz2e9E>+_10ciwKyxzylbi$hs3OS)c3-6Tr0kf}KTI+M5w2xvh41){194Mte+&!!{Bk;<);&En;pfDZYn46>di_PocM$ zD5LD_lX9a0-lnGYY2#YScQg&+jJ`VWIqZ05#Ajba^O9Ht#0Y%Ar1|#?tkE9Eqjw(Z zwXW(j(mz~`Hn5)KS4i_D+Jq2g9i5#?@8X}f+@WW(m2{Ww#-xq@#+NGyg=~j10PAoJ z!{xeR;6?h}qw4r1rKCs)PB-iCFRT}E`=a4T7SM{CdQNNFf2RaXMFv}yHR5C5;IpI) zO{cWWR3acm1<*!VPy+G;_i}*`7@5e1a){6kXh|Itzn5=5<`KIUOigoi4# zS{0@e?J?PB>nEU*&yv+HiP@EU89fkZ0lo*}T7n31r`El14-}jmR@C!wR2dV_cRSt5 z2_g3LzQ50>iNAfU;jXY^r3!D#vJw8;H3tHkc964g>4qPoigA88QEQU(wh)(2|StL=#2;E~Uc{U*ai;^z={nfz!+! z4tW6S0smDh1`t<9m=92{0w5vhN&r9mn!PP#`Vhn@$1awFhJfGAX|}ey`INlz>vd1I zBz{{jq+wtczSZ*0AcLh;Zm54o<-%_&$1Vn=OSXm|g%0(L;Dhx{s1YaZ*j9|C@ z8P1vT5?DbYx&!q2x=a^z-Xrt00XH5-*nJ$$!@&`60%s&~Zq*EQI(juCb^W>iU~Y%A z?nkTf@o_SLwfANfR1@9+!hX%P6e}1SMtn4h#bhDX7(QuqIZAH6=XIgir4MI}5d!7# zW#}y?ULyOMZ&&x0z^#x-Gu($wSl^(_n0(J853{sQ$X<6v?TtGsYUcgcl}M=&=g|=f zQt6zS54x5ilVtxkc1QNtA~o5$EcZ||3OcuZhY~rYNvkY;FAV7AOs}D3_Q{hcdG>zB zR4xj^MG!N{cub;hA)y!=#Ax_r*VHj=RL?>Ati{NA=}!9jT}%RlJW-9LV{*YTV~uUz zm)neKwdmuFkGGI_=p{XM#CZ^9XTCM$tORxWW4BQ@A99xc#rMM2&Q9U!~P{7`f7Gid9$AFwmc+P$q)M*3kzNZDMrI$ zcxm7hCQls!=l)ocU~B);l;(L0x8mpeLllNxS*{QaVCsUsd>5H-Nz6-7fKy&NeNDy` z+RxWkuy_@?Z59ryW*PQ4zQBH>+*<=jd?NS2hksIV4=|={*A|gC$j#OMU0hJGoy@}} z<}(Ox+7^EhoPP?6nwz6wq(VeCU|1o6f}H4!L%v4(BRPAZ4I;4G%Qc*yp6-T`ioZOSFXsyeFg>s$cn)X^;`xhR0ow5S|-jyB=_U<3Ry3RQ6!8? zK54cc7ZdSU@m@agK1?pK3_<>huMdDdM@P+1encu|8ZO2s zaG|&Kw9@;%SkK6ET)s+mdc%r?gaM@3P@#};)=f`uNe$T17Wj&tV|GCg8u3rvy5`ENqIk2jtC^fKE<>+-e;l5JQ^JYzh8xsw=#8X`Fy)=(m7wb?z zRJn^uo&PVIAK+=yhAC%e7W?#a$(IXyqTC{F9CNZT_yJsnBn|O?U|=9mY6EvwO$|Bu zmLd3Rdxz=yKVd>s3jjC-46t$6IuY9dHIg{f}%rAXe&GScI-Gn7*q5b1OIqH zQMwpp;b5Z54|`%n!7W4$4iFh*`NFoKTzW`V0XAvxP0w@aSZRGd{X(nuZ6N{b^2Ep> zHaf-ce9-k~X{IhIEWM*6dORjsYrASkdDe@u?L^aW-96@FU0i4lT}(;Ib@!cX{?hXE zYh~G?W6U6?K=xC-;j17sr-BZL#Y??L7nx*fuklw0#t8?Y2P-Cbu&^j#p<*HR6tFCM zg+qj8aelq4BGVeOUs2oG$D6)t(*nSvu0VCIplFwyuveK^_^~dy%fh=cPxpwxx^JNo z5gR@$Wtd{;gAXVXNHXwleLILsea3e!{rg2_J3|+i4YC4uw3+>d(HzWBWk8DpMpJWF z?#q|E{BpY;@-JYFUw7fChcHsoBF)>!H>VeT_5Rc=SK0hJX0_RpuZF{Dp|;G$77XR3 z9EU#?a&lSEV05$wc7e+%O{I#vAUOy7+2JxX5P!Mt^lcyXbbY$Uw^gfIK5N?_tp*Pd z&tDh?MuvqzF3dy*K_Z-sbQr;(N+|;NuVCw)s`K@P$i(O$m1>^Xfr8Mw9oj4N94lC| zTav%Me%ko3o$@?N#Il32f}i6?>$4hO9a(kp1>W2dLGlZ_?|6$~ssvnjL&VQ_7C@eS z$VBj`cUVeb>0xvJd5v<#lEV(G2e?FQ`nY`ZEvWamL>sB8euQorYXoo7t*!iFa-TRKa7|hnkyXO)TqMxrp%Nj1IbW(#( zO69Gq?D(TJ6~E4=K-ok}buwxlOy^U$fDz9H$jtsK6ZYH)gMK*}06wKx)m>NQGVjJd**4zHrcC>1bLKpq@=zYfHlok+4*tV3S#PvhmE-WkcoRl zS3+h1Vy{7}vi&cl28?&s@6edb7Tey>O_hI<7%DOL;kwf2r_PGP@uuB3s#b5@QY18IyQW(H3^Yh+9?V*@X_;;m-@|RT%io+zVAE#jx;8iWW%zx@ zw#<$fZ;vYOZ$B69 zr@;_L?Ch(n2@R1h8u#~eQa0u0G4TuV^NV4ecL#dZ&fD5H!<=KXpmRR@VFvR{S5)Cfacv0b?5H%H6N&bdCHO6`NIILiei*!pKdX~rs`$wybhpv<7nep;i8$fGookOOf4^gTW3i}r2xnOj z`wqv~%b4WCSC>)QT7Q2ra^1|Y?f$e@?^c;zXs;ACP(a3O3KI!DjcpvB->Y%b`Y^h` z`jWM+@=RM_tMalsrkpvgwGnk}O)V`}aFKDvAgki|`+yHyh|J`E4p zk2peIGKfmgrr$#DO@Orep5ELGrY{Vsx>6sF9Y(6T%DGt6MlaG7QY$Y`)fT$*+&Cvd z9eMm*aCMKa#Va*h-(8U!X}1E;D{6fLVXeazLl*66s5{P825>(6il%vPSD{p9y;iIxZIe?Hxrv{@_vN%y`Jo)$C{6SJ@udYG{I`qFk(K+`Al}T z_4mCthBWa^qXxUgD~~>Q*%;dxWZtX!^`>rQgG%wp=f-_;bHirI1*@Wjt&OWwE(8er zA4^D2R|n+s0wM?GyRk4>(HGE4{(!L{*)C(o*}1t^7#{Fg+ASyb<##20`!dF7X=#3v zPTJ~|P9Mu3wYYaVGna97j(#~jznwK$X2M}u{kMK#2F4%EpM0mu?L7~o0s^{+BIp$l^&2tmCR9M2k zNa!NN5-R#(+;RD9xK6%9tjw>!jug%eCe8HiD^4UD1JKojEoq%+{N!ZZe_Uv^{2FxG zSyWnt_4nDS(wtEqL;5hJ{JbH z15aU1rxGEfkGiYbELcAd$Zx{{?=iW`iDah_+G>n5*7>xemwhJ_y1i%?yZgt^mL#5| zD?7b*&}GlGor4COHcR64t+ovo@5AaaHw-qM4?&LDby$)YD7T+S_$H zoM|>Mz{)s+*^goJUv@PwACJji+mHM8ugp!V$8&ghDIU7zbenU%g{pOH-}W-rhi$WW zAFHg7J@CHk!HtxJ3cK{7j)Gj+kEa1sJstqEAPqxCEa4LFI@M<3G(R_;l#!uy zsbtB(p6(g60A25@kEi<$8P|4di7+R%=-RDLXH7$i9Aok1vI0iUoC3IL{yr=b1-&wm zo<_jYx(}E&Jb%1l9fTKGBVlsp@Ja9NFIx1f6r0+eICRw(5;^1b#$}YE1SX< zvOZt@A_LjlpFWu8zSCwWZY^|q181kP)t&u!-*`-xC1Zxt3)mVoSg>L4eG**6PFXc4 zFWj}ehQAJzI|wASp)3$)-v%=-{&#wZJ`$u@a7EfbYX|qX z=tYyf3+4$$u^2Nl;3JUgCCN>}NbL$S;D{Jtc?^T~Tp9<$xLJw|P2LT#*15~B8Q*-@ z{mO-&s@jqB*Y>Lne%$ObelhN?Gly|zjl1lg!c%X!nypwv`-YCv(e_Fgv9-TeJngZu zEabgIGdYKlJx4G0z4PZnkQ)L(e9SQXJAm;1qp~yp$j74bD8{9!hKSodhPESlI@n5d zn7h2kLi}>;%gqYDw4(9C&g$8h%oY!*7mG!1z2o+sYxP`iJ@ZM;;HSZcq;SB@aTu+j zj=2e8#E|Qhrsg?J8k>P$ED{Qq_J+~m!(`}MHV6!TG>7OEx#wdAFghtws#*c*X2aKh z$NmckK~&x?d+Z#-_vA;9pLftX*ntmZ<)5=b`QSuwTj!z`9i46Qv1!dmToye zC41={S!sQtK2FuI%?m>hL zI-YCX>9M$sO8Ftpu(|ZiF`9tL^{}&Tw$;^JkA`|ImAgMz~IbF@2Vqc@kKmRMI0+%+PLX zZr;30n<`MSWzB1!lc5zmgZUUUb||N6k|9|Sg$+~5RpI+*sj1Btva@HTr&>)OOI=FE zF15Ha_5oVTvaH)g=P-S_84HcXV`*?EgPp}!8WR`sEdh2)LOhvfr}Aj`Aw*NZk&=0D zQ~&wu+1bu{1DGx9_g^^}SRXqT>$uC_q#@Ne=uKv>s*e-AEBh>ev8JVZ`; z^RCm8NvSWCuz#q>Z+%28*JoaD@QlPz@FB=l8{r2QHU3^ocrc3+7zu@8KL%nngAq!# zq2&xT>)JJ8W>++>JKA~wq=xzM=DP#avtT?)b~_BF#Pxbiz+g+>ZHibIzo{r{_>0h&_*Wf_qLuH<9T#(}-n9!af0aa2`Qd3tq z36J#B=iV+u2W!FQ-unKMfIJUPQi>ZNzAC^W<65p0Du5weCD6y-CKKJt+7N#x7cuyy9jjPb@p-Nu!{ zUET#J<5ev|K9H;&5j{1x(^D6ej)sLr{CkP7%=#BzFB>pcGBJtfQG1e%EnweZ*0qd_ zn8S)k!3u*lN$z6cHnJCQIY7>w={WYitu)>qIbyMV-qNxTxjsfzq$e~iI&l+`id-g! z5hr43p?Z9GndoL;`7_>cOt*gF&yf+zarZZbIt){uo?Vyb8Zp3Fs8MW)mtU zT+&Gi&shr|sZ_w`XAoVzM;70*KY^SV^Y!Gyms8|?x>ivr?1|5w)yp&K$J`Zq(VyIc zQHD>1;vg(Ngki{a2%KDsKmjc}zBgcnBj`lXJSj(3Y+z}GXR)WX2yTx}(2Yl{GEz>+@janXPMpO!84PEPb_7#`%XR4S0)v%+Ui>618RTnC z7{L=YHRbFy`bi%jauc+_doAl@Ca&-*KZ?BgUV^uTb5RsYj6n{b1L(1^b*34nsf3E} z3{gJcn4tc6kH!5W*lG5If@{IR$0$`M%863)=5$LyokGS$MVVQj=H%$uAAadm9c(C@ z>g%Jh0}df`qq4a6v*R)nqoNL@dT6}4iUH5u(tE731|V7+kzO<*H(2Sne5Jwpr+tkK zX;^&OXbZ#9(AA(y;sOBiy@+u&k3^2(KpDSYgk)F>3M#K!0cnJwEO6($2mC$RcS zoB&wV0_<)QjH(hw2KsX)V$piss=`gGpO?ji5SCcq)*<{2sLE{5xtWQk(_{g``ZEDo zAGQlswEWG${V)kd<#~vueXS@56Bcf^DJr`sMUxg74>ZtH8zvErBinp>Dd7=Yg{#g+ z2;Cv+cr2h1gQUm>0&-{qOS9Mf-IjYS(mIH3S{VHmCCL?-j>^g1*r*qCCQ-B<$G;lE zNRoID1By5%?QdXW8!eYms@9eZIE{s|~NRlWr@lX#? zreCGC8<_XQ5ngz%$)}F{L%EE4JgKP20Cjiu&v7WkPe4ik0k?=0=OY~j+9dlW+a1ul z^SJZ@d24Rm4F!y)YXNH3^x;D!qRulUOM{SMqdIVOd>`|#iX&#G{(!sLZi`_EZ}u}?baxaUOeg&NTF=nOdfc; zXSl+oOQWA2i&+Mk=p8+J=QkYJ2Ii(aTL|z2P+<^S01FSBwv687mOZ?4`BQBez2j&U ziwURX><9uw4gr&uuVEMOV-{c{-XSR`M+>9}sb0A}+=mq9IKwV6Vr(i=onGP=dF$#Kt49?v8X1VL!>TZh!wE68k<@FE2dKHT4hMHG3Ce7tx9G0u0jsas-_6xRSA zp@9}Z7U^dQxyLnTsy2k$@K6+RonYLkBqbh%njmr^LDOUf9Ic*`BGG_BvS z6=3g9H|y(KkZ7X1iqo#)Kves_6X!xAq{^k~FzDPh0jCyFO1(y*9NbpMuq21!yQ%0; zZ{x#>)z%RXQqF9v+lqtvm>1(I{bIEDxv1v-vK^6uJ^X=xmd1 zho{B#?TECkMCr9o@oJ}LX~UPaDV5d<-Bd+u=a(wUD(iF7+j1Y}cP#IU-|=zgRZN7+ z#pfI43|mY4q=dHH&$}wI6MljM3JsdYH7=8kD~XWt%DC5l>D!l4r95$6L7}cjU)s zG4`4=oA28k*V`A~?6fPYG|h;l%F*0yx>Ss9W?PTXN-~bUv~8Klp>L>FZ#C&qGi>cq z?;l%(zkem0idweqqtc?$uJ$EGve!X?avv8 zGAmsUD`Q`wYvgCR8o`iq@CV zb<%pCbeJD{Ub%1bab@(Ci)F6BqU>|7>m)Sw{J4H@1@EDWTZ*hJ#@aHsVlSppes$;U zi1;qJGGwm*WIS(lkDKzd0b{DTn*ORAii>u>b-o~(8p+hZQ1qzGwu*OZChM*jr`3Ek zFY;)!?mQmGWaRP5x;$;&YHl3t;Fl8zR$U$F_OW3xvi`nD*k0o=?eJFH>bM=EcZH04 zyPez)O@yi>ckT}r8L%iYXs_l8-hKDF(WLy-axVP&)e9GB_ZP(EY{;4_*Mj|^PX5s?|n0%GREFrG-Ovn zrLy^KAT52#t%ozdW>>yhd#aJUvAZIO*DQhguGGPuiagW^zP~TDw@;q$51-rXUE^E1 zcdLV&pYD45&$%@jwHa=fd$xL2FNPlyZ_6EV&Ya%ZwDdiXVZ&6m&BEbyu9OIV z;%V;NOKW|1{ZQ)lK$;D^_`iX;Z}h6YuCK)*>DJrQ#$H<WCOvQet*{;`mqV4~~`IqFsOVbMq@PGpT$fOwtO77+L&O-JyE#tXt^EOxmuM z;y>dI_FSH@OFf%^Mu$IOOwBcHjvigpilv&p!Ln~*zk^~%Sb?vq8!*fS%p zewi>0bXTk1t#4i5mndMgdnennw)LtNj1!B)5e8I}E&p$jlF*tTd&>@2k#jXt|M!(< zkzkW+*04TAKKS|fu@{AGGc`QTc40O6l=X#2%&5m7$zOjy!;!qqnB2Kd%X3GzTzH|$ zitmw~VP)M`8rWsGa|a1;6pB%_%i^V6oips7CL4uj$ZEK{z4^eQGwC60E3zLRr=#7L zpvl~SAzZ>tB`?2zXl$w3txAglfrVO*+&YI+8!7Uu|G(DNe_Ekil(^`%(lG&Vc+cQS z+DML zizOQw<<$wZ##MpWhY#OuICGZT`tFgQ{QBJKyk5E$p0r)F)&;=}tVX`i$u_d}NVJxl z_xaDsq;>D=OwXUZrYIZQcb3zu=(%^zB|U=+O(f);Kv>etQ&Cmsxn!H(mS(1Es=}iX zN2~dCRFgqC)Ln(vl2c=i{qg+Bs$7@Q)1fWaCVSQ_&tI*f+WFN@urpm^@}8xv+twjl zvT#qQE_^sX|F)ln$Na3x{a}^U+GoXJM{h-|FlcW{^!n;l@Y9E%XZHQ%@8=aSB8r|@ zawd#bpIX?EzFg>CWn9yzwc3TLMf{$XLEM&Noa;eLaCryICi=hZZtL4VVY4l#>qAkF zU)6odJI_nWe&%bKDoO6?>bqTv*YZ-PKOYrQiMoF7&f(M+`oAx*%*gVz8o?8ICFR#s zm+PlZM7@kRH~-kH|9mrfo86~(H!rNS_rD)!NLxj?@_Q+I=B&A?P$}3lJZj@mYn#c| z+7s$p(^FTRZ(KN)9=u=okYM9^2lqo+H>lX#WBj_O+DK&od|yD#y(*W@bShdc{E2VC zs7PYmU6u9&PTXsGmc_8qUJvA5H;CNx&NI_{?}!P_eGltN=0@i|xgmCj;4++H?s z!faTNb}$*;S0t~09qDpCqogNuf>D>1Nw)|;IVjPUvxEGKLRmp7Yx2dskfY+83kS!L z^Wp2&B9fbvum6oNBHPxke{5UHT-`s|rnXKxpR5R@SNIfnSuWcy@t|xY3Rit)l{w-@XE2^;oqR<=B|NiR;8Qs3Q%nvC2sgS$0Ej+0OXU@xq6r ztzk3eSrLW4PWzBAsaSu|_GsIbKu*!+jg6GdewAYv?L%KK4?m)3S2GrBhkd)Bt4`c7 z)P;JQCNouEq$+gABt7k^1Iy7?4#kh9NwO47)1MxmU{nw+1@Jwk7%?9WR38-ulw{>=X?jg;F((#W>S z-Lo~f2hwi`*`;S63A1-viG!VRKRv!QUCUQ{8)c`jA$|}kcH)5jmmD_pqGh{P+Ei0D z)Ru`<);eGNz?a|qc&L}CL~{kt?zlViGKXng9;*D+T&nM&>7q5WZv<83fm z>2V&`p?3Vuf-6Et%x(8{7Fp+va=*X(T*gkkyG7GkcSXJp4oHcR`}cJh5uVfWP({jg zvwlfc#n9CC{(YgRi|xft>T8_~vw~HGj5e&`^OgiY)>IEJA^Q=XOzMGE2c6kVEJaQJUoAUrA=CeP*#)mFhV~Cz=$(aX z&1a!no6Uabom{!J(y^dz*6aLY^S{+=DH2~cBQG6)Y-4Tynoavq)xfNKTCbFNe38hA zg|JD73Y~`$L-i^0#2y^`lCy&~j3*{PPsQNId-hbSSnhyF2llbMO(w=Ad$R4wjRr?8Bv$bvP)l2p^4S9WL{KI2b7o8SD^C*_l2@z@6{mTDZ zY9rAZ(eK%J*}r|Qb-KG{;Ni~ID8mil-siDRwm;>V0acMqryvuk-N1O%8LaU72KQ+`K_^t~w#H`O;O5 zlBR`<*~q?Ekz#FoMue1ar+RivbTdy^1_3H5+V=K%XxsCFT)ncyVUh?kTbpFsiB!8s zwAf>R`gf?LIM0kc6Dv0mY=D8DS{bfuJ!KWbaE4m>U|^w$Gp+tx5qFHs_n$JHU0Zti zk4bn$jApx6^!;C?IQfI*N#>J5;c}zlrWjLhrPT+CQm25veVwMFXFf#v*%XP7@ucT? z499we`?wh7hNdMLXN>BNZg5MU9as~3V6`+UqbNWAeXB!Z*87lTE^K-z%=nT84t2TS zQk41E>id7(=zy2-KKB1Yp)8G5lslyPckJY@Lm@j3P5Jb%1^8ddEHZ*a@7&j%eVh@l z7yD$j@&DIqE>hObesT?^KDe>FTEFlbmCXWMnkfGtu5=YJQv z5k956Ov24*&me3q7)*t5f&$USnsHyG-RC-`t!)K~KkniS7#BNE^w%YvTzoa^BIHOz zV->6|7z1(S3yHNSR;64HfGjnV3~MFCGn(0mmH--!6Pw715z-MIzuv^k6*ok95Ewn> z>S@0GF7Ju4hD)H(;z61bYVHaoUs0;7D8_I(SAmi!n~bfR!!WnL0ZIJL!P^15o*b(O z$~*~U)IrcUjZ8&9MD}!L5f!p2*G}cw3~syXJdXH6c4urRLT48;?_Oj9|H_~ z5Uxpe&rT&}p<_Yiv6v!}MiJ2l{!%WSg(AlhqC5z*s20NaZ{$?y_dm)~2i71B0&Ll2 zdy>%goX}9C+1G>cBs4GvvppgtFSINDgx3M9&;%kOp<&6@4}{XdM}7hW9MKl~j66$q zQSv%3UDDAo6s1Zwe6OT>SIzW9@Hj)zc*lS8oV6M0EH(s7_{#N&T_@43Jx;rIVj$u+-$>&@fu68* "model.dbt_resto.table2": "name1 = name2" + "model.dbt_resto.table1" -> "model.dbt_resto.table2": "name-notexist1 = name-notexist2" + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database2--", + schema="--schema2--", + columns=[Column(name="name2", data_type="name2-type2")], + raw_sql="--irrelevant--", + ), + ], + [ + Ref( + name="test.dbt_resto.relationships_table1", + table_map=["model.dbt_resto.table2", "model.dbt_resto.table1"], + column_map=["name2", "name1"], + ) + ], + ["schema:--schema--"], + [], + ["model", "source"], + """ + "model.dbt_resto.table1": { + shape: sql_table + name1: name1-type + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ) + ], + [], + [], + ["model.dbt_resto.table1"], + ["model"], + """ + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database--", + schema="--schema--", + columns=[Column(name="name2", data_type="name2-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["model.dbt_resto"], + ["model.dbt_resto.table2"], + ["model"], + """ + "model.dbt_resto.table1": { + shape: sql_table + name1: name1-type + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["schema:", "wildcard:", ""], + [], + ["model"], + """ + "model.dbt_resto.table1": { + shape: sql_table + name1: name1-type + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database--", + schema="--schema--", + columns=[Column(name="name2", data_type="name2-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["schema:--schema--,wildcard:*dbt_resto.table*"], + ["wildcard:*table2"], + ["model"], + """ + "model.dbt_resto.table1": { + shape: sql_table + name1: name1-type + } + """, + ), + ], + ) + def test_parse( + self, tables, relationships, select, exclude, resource_type, expected + ): + with mock.patch( + "dbterd.adapters.algos.base.get_tables", + return_value=tables, + ) as mock_get_tables: + with mock.patch( + "dbterd.adapters.algos.test_relationship.get_relationships", + return_value=relationships, + ) as mock_get_relationships: + mermaid = engine.parse( + manifest="--manifest--", + catalog="--catalog--", + select=select, + exclude=exclude, + resource_type=resource_type, + ) + print("mermaid ", mermaid.replace(" ", "").replace("\n", "")) + print("expected", expected.replace(" ", "").replace("\n", "")) + assert mermaid.replace(" ", "").replace("\n", "") == str( + expected + ).replace(" ", "").replace("\n", "") + mock_get_tables.assert_called_once() + mock_get_relationships.assert_called_once() + + @pytest.mark.parametrize( + "relationship_type, symbol", + [ + ("0n", "->"), + ("1n", "->"), + ("01", "->"), + ("11", "->"), + ("nn", "->"), + ("n1", "->"), + ("--irrelevant--", "->"), + ], + ) + def test_get_rel_symbol(self, relationship_type, symbol): + assert engine.get_rel_symbol(relationship_type=relationship_type) == symbol diff --git a/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py b/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py new file mode 100644 index 0000000..6991a5b --- /dev/null +++ b/tests/unit/adapters/targets/graphviz/test_graphviz_test_relationship.py @@ -0,0 +1,377 @@ +from unittest import mock + +import pytest + +from dbterd.adapters.algos.meta import Column, Ref, Table +from dbterd.adapters.targets.graphviz import graphviz_test_relationship as engine + + +class TestGraphVizTestRelationship: + @pytest.mark.parametrize( + "tables, relationships, select, exclude, resource_type, expected", + [ + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ) + ], + [], + [], + [], + ["model"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ model.dbt_resto.table1
(name1-type ) name1
> ]; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database2--", + schema="--schema2--", + columns=[Column(name="name2", data_type="name2-type2")], + raw_sql="--irrelevant--", + ), + Table( + name="source.dbt_resto.table3", + database="--database3--", + schema="--schema3--", + columns=[Column(name="name3", data_type="name3-type3")], + raw_sql="--irrelevant--", + ), + ], + [ + Ref( + name="test.dbt_resto.relationships_table1", + table_map=["model.dbt_resto.table2", "model.dbt_resto.table1"], + column_map=["name2", "name1"], + ), + Ref( + name="test.dbt_resto.relationships_table1", + table_map=["model.dbt_resto.table2", "model.dbt_resto.table1"], + column_map=["name-notexist2", "name-notexist1"], + ), + ], + [], + [], + ["model", "source"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + + +
+ model.dbt_resto.table1
(name1-type) name1
(unknown) name-notexist1
> ]; + "model.dbt_resto.table2" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + + +
+ model.dbt_resto.table2
(name2-type2) name2
(unknown) name-notexist2
> ]; + "source.dbt_resto.table3" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ source.dbt_resto.table3
(name3-type3) name3
> ]; + "model.dbt_resto.table1" -> "model.dbt_resto.table2" [ + penwidth = 1 + fontsize = 12 + fontcolor = "black" + label = "name1 = name2" + ]; + "model.dbt_resto.table1" -> "model.dbt_resto.table2" [ + penwidth = 1 + fontsize = 12 + fontcolor = "black" + label = "name-notexist1 = name-notexist2" + ]; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database2--", + schema="--schema2--", + columns=[Column(name="name2", data_type="name2-type2")], + raw_sql="--irrelevant--", + ), + ], + [ + Ref( + name="test.dbt_resto.relationships_table1", + table_map=["model.dbt_resto.table2", "model.dbt_resto.table1"], + column_map=["name2", "name1"], + ) + ], + ["schema:--schema--"], + [], + ["model", "source"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ model.dbt_resto.table1
(name1-type) name1
> ]; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ) + ], + [], + [], + ["model.dbt_resto.table1"], + ["model"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database--", + schema="--schema--", + columns=[Column(name="name2", data_type="name2-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["model.dbt_resto"], + ["model.dbt_resto.table2"], + ["model"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ model.dbt_resto.table1
(name1-type) name1
> ]; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["schema:", "wildcard:", ""], + [], + ["model"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ model.dbt_resto.table1
(name1-type) name1
> ]; + } + """, + ), + ( + [ + Table( + name="model.dbt_resto.table1", + database="--database--", + schema="--schema--", + columns=[Column(name="name1", data_type="name1-type")], + raw_sql="--irrelevant--", + ), + Table( + name="model.dbt_resto.table2", + database="--database--", + schema="--schema--", + columns=[Column(name="name2", data_type="name2-type")], + raw_sql="--irrelevant--", + ), + ], + [], + ["schema:--schema--,wildcard:*dbt_resto.table*"], + ["wildcard:*table2"], + ["model"], + """digraph g { + fontname="Helvetica,Arial,sans-serif" + node [fontname="Helvetica,Arial,sans-serif"] + edge [fontname="Helvetica,Arial,sans-serif"] + graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir="LR"]; + ratio=auto; + "model.dbt_resto.table1" [ + style = "filled, bold" + penwidth = 1 + fillcolor = "white" + fontname = "Courier New" + shape = "Mrecord" + label =< + + + +
+ model.dbt_resto.table1
(name1-type) name1
> ]; + } + """, + ), + ], + ) + def test_parse( + self, tables, relationships, select, exclude, resource_type, expected + ): + with mock.patch( + "dbterd.adapters.algos.base.get_tables", + return_value=tables, + ) as mock_get_tables: + with mock.patch( + "dbterd.adapters.algos.test_relationship.get_relationships", + return_value=relationships, + ) as mock_get_relationships: + graphviz = engine.parse( + manifest="--manifest--", + catalog="--catalog--", + select=select, + exclude=exclude, + resource_type=resource_type, + ) + print("graphviz ", graphviz.replace(" ", "").replace("\n", "")) + print("expected", expected.replace(" ", "").replace("\n", "")) + assert graphviz.replace(" ", "").replace("\n", "") == str( + expected + ).replace(" ", "").replace("\n", "") + mock_get_tables.assert_called_once() + mock_get_relationships.assert_called_once() + + @pytest.mark.parametrize( + "relationship_type, symbol", + [ + ("0n", "->"), + ("1n", "->"), + ("01", "->"), + ("11", "->"), + ("nn", "->"), + ("n1", "->"), + ("--irrelevant--", "->"), + ], + ) + def test_get_rel_symbol(self, relationship_type, symbol): + assert engine.get_rel_symbol(relationship_type=relationship_type) == symbol diff --git a/tests/unit/cli/test_runner.py b/tests/unit/cli/test_runner.py index fab0afc..acc2348 100644 --- a/tests/unit/cli/test_runner.py +++ b/tests/unit/cli/test_runner.py @@ -71,6 +71,8 @@ def test_invoke_run_with_invalid_strategy(self, dbterd: dbterdRunner) -> None: ("dbml", "output.dbml"), ("mermaid", "output.md"), ("plantuml", "output.plantuml"), + ("graphviz", "output.graphviz"), + ("d2", "output.d2"), ], ) def test_invoke_run_ok(self, target, output, dbterd: dbterdRunner) -> None: