From 38d549ae1c55a91c9261a3d1ede0bddb07cdd5a1 Mon Sep 17 00:00:00 2001 From: Jakub Zika Date: Thu, 3 Feb 2022 16:14:06 +0100 Subject: [PATCH] Initial commit! --- CHANGELOG.md | 7 + LICENSE | 280 ++++++++++++++++++++++++++++++++ dev/user.clj | 29 ++++ example/pokemon_integration.edn | 12 ++ example_run.sh | 5 + install.sh | 8 + project.clj | 26 +++ readme.org | 127 +++++++++++++++ resources/images/bq2pg.jpg | Bin 0 -> 43714 bytes resources/images/intro.png | Bin 0 -> 90425 bytes src/bq2pg/bq.clj | 178 ++++++++++++++++++++ src/bq2pg/config.clj | 167 +++++++++++++++++++ src/bq2pg/core.clj | 15 ++ src/bq2pg/db.clj | 161 ++++++++++++++++++ src/bq2pg/gcs.clj | 107 ++++++++++++ src/bq2pg/integration.clj | 127 +++++++++++++++ src/bq2pg/proxy.clj | 17 ++ src/bq2pg/utils.clj | 37 +++++ test/bq2pg/bq_test.clj | 19 +++ test/bq2pg/config_test.clj | 48 ++++++ test/bq2pg/core_test.clj | 8 + test/bq2pg/proxy_test.clj | 12 ++ test/bq2pg/utils_test.clj | 39 +++++ 23 files changed, 1429 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 dev/user.clj create mode 100644 example/pokemon_integration.edn create mode 100755 example_run.sh create mode 100755 install.sh create mode 100644 project.clj create mode 100644 readme.org create mode 100644 resources/images/bq2pg.jpg create mode 100644 resources/images/intro.png create mode 100644 src/bq2pg/bq.clj create mode 100644 src/bq2pg/config.clj create mode 100644 src/bq2pg/core.clj create mode 100644 src/bq2pg/db.clj create mode 100644 src/bq2pg/gcs.clj create mode 100644 src/bq2pg/integration.clj create mode 100644 src/bq2pg/proxy.clj create mode 100644 src/bq2pg/utils.clj create mode 100644 test/bq2pg/bq_test.clj create mode 100644 test/bq2pg/config_test.clj create mode 100644 test/bq2pg/core_test.clj create mode 100644 test/bq2pg/proxy_test.clj create mode 100644 test/bq2pg/utils_test.clj diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8fff04d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Change Log +All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). + +## [Unreleased] + +## [1.0.0] - 2022-02-03 +- Initial project release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2315126 --- /dev/null +++ b/LICENSE @@ -0,0 +1,280 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public +License as published by the Free Software Foundation, either version 2 +of the License, or (at your option) any later version, with the GNU +Classpath Exception which is available at +https://www.gnu.org/software/classpath/license.html." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. diff --git a/dev/user.clj b/dev/user.clj new file mode 100644 index 0000000..17f8830 --- /dev/null +++ b/dev/user.clj @@ -0,0 +1,29 @@ +(ns user + (:require [bq2pg.config :refer [load-config-repl! CONFIG]] + [bq2pg.integration :refer [integrate!]] + [bq2pg.bq :refer [create-bq-client]] + [bq2pg.gcs :refer [create-gcs-client]] + [malli.clj-kondo :as mc] + [malli.dev :as md])) + +(-> (mc/collect *ns*) (mc/linter-config)) +(md/start!) + +(load-config-repl! {:filepath "./example/pokemon_integration.edn" + :extra {:export? true + :import? true + :gcs-name "unknown" + :gcs-folder "bq2pg" + :sa-path "/users/akiz/.config/gcp-batch-runner-dev-sa.json" + :db {:dbtype "postgres" + :dbname "postgres" + :user "postgres" + :host "localhost" + :port 5432 + :password "my_password"}}}) + +(def gcs-client (create-gcs-client CONFIG)) +(def bq-client (create-bq-client CONFIG)) + +(defn integrate-dev! [] + (integrate! gcs-client bq-client CONFIG)) diff --git a/example/pokemon_integration.edn b/example/pokemon_integration.edn new file mode 100644 index 0000000..6f00acd --- /dev/null +++ b/example/pokemon_integration.edn @@ -0,0 +1,12 @@ +{ :integrations + [ + { + :name "test" + :query "SELECT * FROM `project.test.pokemons` LIMIT 1000" + :location "EU" + :target-pg-table "public.pokemons" + :method "replace" + :timeout 120 + } + ] + } diff --git a/example_run.sh b/example_run.sh new file mode 100755 index 0000000..9aa4991 --- /dev/null +++ b/example_run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +CONFIG=$1 + +BQEXPORT=true PGIMPORT=true PGHOST=localhost PGDATABASE=postgres PGPORT=5432 PGUSER=postgres PGPASSWORD=my_password GCSNAME=some-bucket GCSFOLDER=bq2pg lein run $CONFIG diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..a57a759 --- /dev/null +++ b/install.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd "$(dirname "$0")" +lein uberjar +cp ./target/bq2pg-1.0.0-standalone.jar ~/bin/bq2pg.jar +echo "#!/bin/bash" > ~/bin/bq2pg +echo "java -jar ~/bin/bq2pg.jar \$1" >> ~/bin/bq2pg +chmod 755 ~/bin/bq2pg diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..7debaab --- /dev/null +++ b/project.clj @@ -0,0 +1,26 @@ +(defproject bq2pg "1.0.0" + :description "Integrate BQ data to your Postgresql tables." + :url "http://github.com/akiz/bq2pg" + :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" + :url "https://www.eclipse.org/legal/epl-2.0/"} + :dependencies [[org.clojure/clojure "1.10.1"] + [com.taoensso/timbre "5.1.2"] + [cprop "0.1.18"] + [expound "0.8.9"] + [com.stuartsierra/component "1.0.0"] + [com.github.seancorfield/next.jdbc "1.2.674"] + [org.postgresql/postgresql "42.2.22"] + [com.oscaro/clj-gcloud-storage "0.71-1.2"] + [babashka/fs "0.0.5"] + [com.google.cloud/google-cloud-bigquery "1.137.1"] + [org.immutant/scheduling "2.1.10"] + [clj-time "0.15.2"] + [com.taoensso/timbre "5.1.2"] + [authenticator "0.1.1"] + [metosin/malli "0.8.0"] + [org.clojure/data.csv "1.0.0"]] + :repl-options {:init-ns user} + :plugins [[lein-cljfmt "0.8.0"]] + :main ^:skip-aot bq2pg.core + :target-path "target/%s" + :profiles {:uberjar {:aot :all}}) diff --git a/readme.org b/readme.org new file mode 100644 index 0000000..2879189 --- /dev/null +++ b/readme.org @@ -0,0 +1,127 @@ +* BQ2PG +- Querying Bigquery can get really expensive and you can not run it locally. +- So I created BQ2PG because "No such thing as a high-priced question." + +** Main Points +[[./resources/images/intro.png]] +- Migrate data from Bigquery to Postgresql easily. +- Migrate data to already existing tables or create new ones automatically. +- Append rows or replace whole table. +- Run export and import individually. + + If there is no new export, no import will run. + + Data are loaded from small GZIP files, keep your disk's space free! + + +** How it works +[[./resources/images/bq2pg.jpg]] + +*** Config +- This is the main configuration file. +- The only mandatory part is =:integrations=, everything else can via provided by environment variables. +- check *example_run.sh* or [[Environment variables]]. + + +*** GCS and BQ clients +- both clients will be initialized with /$BQ2PGSA/ environment variable if provided +- you can also set the path inside the main configuration file under /:sa-path/ key. +- if you do not provide service account key it will try to use /gcloud tools/ login. + +*** Integrations +- Integrations must be created under *:integration* key in the main config file. +- Take a look at example integration in [[./example/pokemon_integration.edn]] +- These are mandatory keys: + + *:name* - transfer name, also used for bucket folder name - must be unique in all configurations! + + *:query* - SQL query definition for data extraction + + *:location* - location of BigQuery dataset + + *:target-pg-table* - target postgre table in format schema_name.table_name + + *:method* - postgre update mode - append (default) or replace (truncate target table before) + + *:timeout* - timeout in seconds, checks on bucket for new export from BQ (if new export does not exist after timeout exceeded, then continue) + +- Bigquery fields are converted to text: + - if your /:target-pg-table/ already exists, it will try to convert value to its column type + - If that table doesn't exist it will be created and every field will be imported as text + +*** Export? +- You can set /:export?/ key to false if you don't want bq2pg to export your data from Bigqeury to Google cloud storage. +- This value can be configured in main config file under /:export?/ key or as /BQEXPORT/ env variable. + +*** Import? +- You can set /:import?/ key to false if you don't want bq2pg to import your data into Postgresql database. +- *Keep in mind:* bq2pg creates record for every last integration in .last_import.edn so if you have already imported some existing export it won't be imported twice. + - it means that it won't be imported until export to the target folder finishes. +- This value can be configured in main config file under /:import?/ key or as /PGIMPORT/ env variable. + +*** Stream GZIP files +- Bigquery data are exported to a batch of GZIP files which are loaded one by one and save space on your disk. + + +** Examples +*** Example 1 - easy and quick +1. Download bq2pg-1.jar from releases +2. create your /integration.edn/ like this: + #+BEGIN_SRC clojure + {:export? true + :import? true + :gcs-name "my-bucket" + :gcs-folder "bq2pg" + :db {:dbtype "postgres" + :dbname "postgres" + :user "postgres" + :host "somehost" + :port 5432 + :password "my_password"} + :integrations [{:name "test" + :query "SELECT * FROM `project.test.pokemons` LIMIT 1000" + :location "EU" + :target-pg-table "public.pokemons" + :method "replace" + :timeout 120}]} + #+END_SRC + +3. run =java -jar bq2pg.jar integration.edn= + +*** Example 2 - clojure developer, installation +1. run ./install.sh +2. bq2pg will be compiled and you can run it by =~/bin/bq2pg= + + or add =$HOME/bin= to your PATH. + +*** Example 3 - clojure developer, interactive use +1. run repl and switch to =user= namespace +2. you can see example configuration + integration you must update before you run *integrate-dev!*. + +*** Example 4 - real use-case +1. Place /bq2pg.jar/ or personalized /example_run.sh/ somewhere in your /PATH/ (see [[Example 2 - clojure developer, installation]]) +2. Configure every environment variable so your config file will contain only integrations. +3. Schedule bq2pg with same env vars but different configs and synchronize Bigquery and Postgresql on daily basis. + +** Environment variables +- if you are into 12factor ;) + +- *$PGHOST* = Name / address of the Postgresql database server you will connect to. +- *$PGDATABASE* = Database name +- *$PGPORT* = Database port +- *$PGUSER* = Database user +- *$PGPASSWORD* = Database password + - this is *OPTIONAL* - i would recommend you to use .pgpass which should be parsed. +- *$BQEXPORT* = true [default] / false + + Disable this only if you want to export once but import multiple times. +- *$PGIMPORT* = true / false + + Disable this only if you only want to export data from the environment. +- *$GCSNAME* = bucket name +- *$GCSFOLDER* = directory name on bucket - for bq2pg purposes +- *$BQ2PGSA* = path to service account JSON key + + This is an !optional! parameter, you can also login via =gcloud auth login=... +- If you happen to use a proxy, don't forget to set one up as well: + + *$PROXYHOST* = Adress of proxy server + + *$PROXYUSER* = Proxy user + + *$PROXYPASSWORD* = Proxy password + +** Caveats +1. Your Bigquery dataset and Google Cloud Storage must exist in the same location or you get error. +2. you must have a =bigquery.job.create= rights so you can export data. + - + r/w rights on configured GCS + + +** Development +- There is Malli function schema for every fn, lintering is prepared in *user* namespace - this makes debugging experience much better. + diff --git a/resources/images/bq2pg.jpg b/resources/images/bq2pg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..938453d5e93e2642cb850b88d59a594658f4ada3 GIT binary patch literal 43714 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 literal 0 HcmV?d00001 diff --git a/resources/images/intro.png b/resources/images/intro.png new file mode 100644 index 0000000000000000000000000000000000000000..5eac44c3aced49712d918f7bf0b16b4377639c51 GIT binary patch literal 90425 zcmZ^KWk6NI);1u*p%0*RgQRpwcZVP)DJ5`-LrRBqcXxx*-67rGjdUm=AYI=^@4fGR z?|VOfu;!@$6x$w-SU!@$6g1L;Q)0`Q+Dkl`f^4DzCx zn3$4`m>8LoowbRXr7;YQbZ~qkqN>UQPQX~}et3*9t+ME`G>umrSZi-mL{$_^nwFIs z{^h%O_(UC*Srl-CLFgg0+&IF$J{lD{^A#BVSy^Ge&k5=6y`_?p>sQ@=9M--at#`aw zFg>;()BW)cM#-lEO9rO|PPmR+is0qmkhHYC;r9$!P`mK+2H2#bSQ(Az=xmtE!t3LU z2PUlWdB)TeoyUjA&z$snWSg)suPD<76Hlrzt;Bl4iWDQTFb*&$gp7mHVP|N5GkMb9 zphvFJ{n$I(G!+^=g^Zx!U_;7b7#PJJyZn8as8UQJ%EZKoE%L}qeVU!nZqP2}&mL^M zYfz@}JTISH2R8mn`5YajPjq%`g-yZeb$`VNG9H~G5sru4(EhsgGPfEBP880BP^Yx$GuE1$PlXT zy!YZuFdTOXKTlc`9ZvsU?iYLnv0OuN4qrF-yAY*!eNs@jV&b1ws^o;Pk zm+CI8yO$6M0h0`Y%E!eE(T|K!x`QGLL*0i$369IBGz(7EcSWC+8-(s_Vgr{3i`)Lv z=GihVh6u(UB6A0eGlnENs8i%c5Q3S=O%&3{=RCsl{V1n_qS>^xn6loJsy&H4;#8zdWRKy#273tu7brDoq@Ag!tm~+q%W$becV6%( z2t9DBQ*)i)7L%Ka3Guz(QUsqDUwCuyk3Ns?*k3o!i0&|gNX)(Eor&w0n~Lk!8=0F@ zNc8a7K78ap?KH2+Ey;e8*I<=l-yr3RtL5NN#Nvq!la)~=U=s%I21f>2%TUFT4}^21 zQc=8&8k7l?#+7N!Q~XH35Hn0o6T7{2zSX+Lb?R}djqGnIdy-A{&W`p6okLu898FxL zEXOPDR}olxX8y|g%CVCQ`R@nejj@drPWiX_x7oHS2j}7gRYCLx^p-En2JPZy<2UJ7 z=qZah)ZAu3GnO+BMYn3qh3HDQswzc7@rsOjM+F)A7ZXYxlmw~0xupe%+38=-iw$Om zr@77X&0m=#&hX9z%oHBHJ+M6pone?!EV>+j_eq5}FhgQZSV;bx++#_0amOSWQZfS> zZzwzwu@5MSED)~NsD5`Av17^@knl~tV3xYnq_l4l0+l;lSPZRkGS8eNNy+BwGD5JH zJPGS!C)sP~P2hdUE9c<&LuUqmVrB|$I)2Y;PN0}CPipRLVrYCR$4S;&DYM`>pLudE z=d;%1bFuUe!;h?k_`7&r2)qa)2zI`@28;XlGjlfd#x)S|IaYGP_q`4Ra|g}EfIRP-dX6x-p`;e!#9WR>C85!{ryq_w(s zEfz*LMn{e13O~klM*oEPgt=0E23&^d8T4W%i?G_%+WDs5rlkPOuBw6B!utK%{H1`! zvMOku2j`Tt$>gvCJD-VXwSC=C)soTWc!oKt<+s7MnTK%S{AXj?lk0VqJ*@4v{zjpj z7Bmbr-cxVCxQ%k`vg~q>9**ki>geV%p)vWE^_J07ERR&Y!crv!Btc9ubpPp|Npbq&MP>4MEMm2{AKynMcVD)WH!hu-=lRXYorK$f6B z_c)J@nZ7odnwAQpqVz^8v1@bMHo#ZcH}QEU3VEP-psF7~S}kgPKwUtGL5D$V7m0tW zUuahZ9DGo+g&)*Mwm#l59goY%&DSd-R zOPg_S#d4KvRjv)=Gs1`e@i zNs~s))dAMfD~m+_F_ivWGdfo~Ycsbtk%z&%RpS!l<^-`JmBjjT7Oi&;Ip4@C^w(rJ z28ZM4)E7$Wbx zJ+=CASDHAOHds`TSwB#J9v7HUZ~11m&Gt4C*`Oy~c5SeiKE0?`jnwg%)AI6ub#=B@ zeN*1eS!53B@gef^jH;2AN*!S{pVMWvfUO&^r{RO@`(j;fge_eawlSFc5S(ms4Ww_T&z`4Ta9l9?IFbmMcY{4ld&@uNP z%o94S+Ks#aOgId~i>yyNP}SDVG&@S0V!A*IN%@FKhm&3n)ZM41I=LI|CE7&5d@wvFmPFL|IC3O&wBRH zG|c1E%dC}4MW9H%nX1Mo4F!2#BWoy=!AEODVvbf|w#DQM| z6p&A!Y8pA4KCt?ViPR`Sn!#EtEZ z?96OFnOR$rJ=JSqXzlPxfP&(wp@04T?dK;mlmBVS%Kjh20tU$Z^oE(0iG}&Ui5WYa z{eQ%s-uxB&Gp@hQ@jq3@D`pL~u`{-}2f8K5%KxW<|CRSY-TPZ!+1TFN(&1?oYF1{S z1lj%}@*mm%DWzyp ztLtgpyh>)y#+Dl5W>90RzoTSh2P*lmul}p3=KqMYadQ5<)qm~i zPcC3cg2?>L|1wHJ4XNh=nWFj%fo=1p6NkG8DKmfy=ZSvnfdePID?XH8r+59s7Jw=N|V6o}F|RHij*L0=sCsXtrpPI4I^-H}45HmP}ZPe=)+dn|9-?zu9LG(Q_%hz~h69@S+4W zf~mZJ9oDZ6HtuGmR%zMxyfiK@t&5pa*H$3>7AHZxLS#S8I+-JZ()is6MH%e`D9Uu) zdYPf)c3A81g5h&1B?}*%N`ZWIZls{AV`%@!${w6z^)W2sm;JwhAtXwXxQPE4Ich%s zkfkIc8BXx(y`G1Ip>sN~LyX780?kBORDdG?iC@9t+ULi3Cf%lfbiSWt3Mm|PTMWtu zy3XtVrz3CH@-n(o8Oj<&cha3!$7vmejC#YSh1ragZ0!5V13?V6%xzbOKG2actA=%i z>x1I*toM(P9_^ zs%u7=l*f2F)rR5SnIpPobGw8C6*)?@VqGTnituc{an?Wx@GB%NrgaZnsk`$|kr|ET~Por+P4H-@sc&b$rioeJ-M0q{dBs zv(oI8_$om|G=lel_IfWj5*a-*KQfqkzj{}>giY}3yRU4V`{Vs3uhP=z$9o5s55L48 zaI??|y0|7MQ}@$>Y1bQAQl##|5csWB3kfIYQ$Gv3>YMu2iNXxZ+huD0nFFuR8Ts5* zKSmC}alat7$R9M(1Uw6dH^%5f*&4DRvrBSe9R}&X^dk^jX2ot=zPtTBr8u*qX_}rN zyJvYc)bjustGe<{7lu&Wa~us}85rpt4ko63MUx{XopS@9J2n7vw%NIj1$~4nMolvYs5HM&S-9ytDFP!ISRIyal zAAyabCF{C<>%O83UFFgL%Bd5Hrk`uck`jff;k#vr=AFj=lH(FIU$@z@h|^{XT3^@; zqvhDJ0Cb(R40Yais?mOT`hZLuRU_S4duCSKn(;?z{i@}$?K3GdY&eBfE`{jlPOC0o zTFyrK>{eZN2V@ya^R^>JKF^iusu7|=y)Y>yLB+d@0_SlFD%9+HpYLmbR`!u-3A*4e z5#z<>-q-G=SPZ`9JIp(0p(C04qKNDH3=v)R(1+?xEvvS}jGD^6ky`4E1Eo}k`>D(f za@Ht&JAt5kgL#FLX{P6m*$j>wV9gE=RoeAdE;G#?zKBDjD2!BoUG1o-$?#$XIATEE z9B2uQ&UulS<8LWY@iJX@@YA!vG#pvu(!Ly`Ne$l-(RdbdDpI&@bLto&a^T0NsETx< z^Jx`-Hlzp${R?HX2y*@ogqW?WA*Ly$9l$V3LOH>%Z`Rza7sa@i*zb{2(xSYlpMw}` zaK37Tv>a>J_{AQwWpI(NeP)Tzv)-3~V7pwl51e&bVHc5#jo^59H1RrDK1)q@O-ewr z*|<-1!|qXoZKcdnqCA^&G=umwb|Jly*rn z!ZxzeEPfN`&9q1HGl{Sa#6w_Lix9TO{7wmXvZig_s`ireliGwhw=phs>1&8O-8oMR ze4z&i&)1MT+dYrG5Z#w%Ui%&#*M(Iq5ds$)=hgQYOYbF~#j84>IL&S)J7JM-;6ZuD zSsG8}xhK37kKZgpa*H5Yxt9~&#qUbYGAag7^-g5EzW6P3D-pE*w zDS0z1qaOqrUSc0$8#AZ8u;8iUwcF26Jg~1RRXC)ae69Aj(EchrOfvSo2=ZOyr9#Tg z>y+1fGk2z4{x%fh$vN@sLGV+~TKqXknZ3-55BbM=Bof$%MTjKM!Xv?v`OGN|UsF?N zn~|`oRV89yo}&m(F9cE1X%R3&qq!mq$SG2lk9qg=VyA}}i6-SdCGsLtVrL<+IrJ1n zFK9CO9Djaw#Kio%F8=Yens{1XXU*ldeKGS?J>0@-xVWN(8mDRgfq0-5!X(c10 zTn{LHQF-2ue1*^uoWYum&43Gj3h&y(-Q*kDW@By*Qar{AGj~R&dF^yVcj5x(wOi+f zYMV&|KLIH5Nu9HuqIODI$p(!I!CvCV`oss*1KeE3)54aJy6l1*xYd`?TlMB3R7Q|w zK(JnQWGiJ=^}+q++8n77#US109K>6?k7!~e;Q~K80rJwp$5y&#MQbF4uljtP_{oK( zWr7RV=01!sIUsUcwr#4y=8VBo5TB+e7(WQXTVyTCt7hw7cvX@^UNT%+6lG!3d1UdtwMD2 z+vm@^Xi`In^-#(gH+4hc6DLaEPR~=^puW>^RJUYBr|_CXdz{N)>G?JX#j;;HN%o2l zH3k6_B9V>PDlYw7f7HMkcfUHAaEiLctaxLe1SBYEw@RsABe~41Rjg~8gJ?WM)YreX zC_e%C9LSWloXQHs2G?ORqE8Ot>y%_rLUzUjs$wFk2^aAo4S<7CRYa~4#;szdv0YD! z*W=%S<#g(8pFf`P-LhO1Mf>NQRcE7MX|b8I4g7To%nka%vy}HIri0H@SRjJq5xEn1 z(bh#~qUj>Edf(rAc>R~1bR5N$a)R1tGAwoelH4_m9o;jtWq&2@M<$gFS zt|InA1Wg%!AQFFyDi~PC6uhUi0~|YxhO}2wJPany`X}4N6Bma|#l5;53p391LN_u~ zMUpQ zO{2vCc}TFn(si8>%q5xJ!OEG?$2 z2BLyYjrzW}j%+B5{VPvQ@}fn^MHmjjqAAFPKiAvjq99&EUtaq`dO8&BMVpaTVk}A}&V@B$_#ThKjYXLv|APb>$Y&2M3AHVdsg|lR@Cby>p zym=@Lwj}jp9Akf`z~wUgODbO*1Zs6_Jbt!uDKc-mJ}|N+iZPs)RaHMl=$<+T!ir_I zNRnle#>%qY5aSHUhh@zb5%v?{8Xe#W_n#}HQ1Ka>Rd%>zB@4H)HTd0a=@2cdP$&0* zao%vFjCjf?ZHitSHDl^Mw(RAE{&r`ke6?wH<`DoY_^E6{_v5v+lGVO;6_RascmS0F zVVpwKe2k1x*M*49N2Sq?r*m8^^5hK(bzcuwT@-~SY_(mxy6Pl>8KjVSSE1*Xw&re@ z`{c)a)w~mOz}qZ;i$jTq@v6$EOMS_(4y8_5a`7$yiTH}4#N*h78un={hLa_5XcN^+ zrkxWfvyCztNilPi{)X-%rkD11{=i?D1IJucJ*1|03OgawaL4GbRUSfqx`5M%s5DPa zaQH&$ZUm~ZxF>H+3KtZqDEx`Vq=q%I^$XXWw459_FMKve{+&pLeFjNPX~u%O!v=g| z50y|VX&pmnYbqw-k@FQ(7K^m&eLdJ34kZb1}$6oTk~SPtrN;cga2=suCFgb~N^D;XHhdn!Ge>_vmt= zna0s7rgR`oH;0~hP5FRGdpAucm=J{hiE?mM@YZq$q0*+bWzoJ-X98^CgL2(L#$U)} zcZ6h!jdf(9d_3;?Tr3D16wm~|y)miDSJkt|CZU$L^{z0q3+#n0K8Y$wLsUWaj;cVS zSf}w2hg*j1hSH^}1==K_3t`s~igpeScQM?flLlrHiEw2#21w#}UZ+4Pl7;&<-NNy; zq9E~E@eo^wTMc0XJX16p-c3+35DA@DvJ;cD}a_eTBpz%qO3 z`69(CENidkr>&P-kec__ZPzAAM6ISBs4;m39bx7R1z7E?9~@5ji{r(}4AY%h}+3mTSwC07yD^`r#`*pwOQN;mx`@HV~I z!mD>*B%*u^CBhDPAL|+I59OGAD|r1e-6E^;SXm36tT&7(cZ?G&Tmoaq#6+sOo&Eh! zvI(+joj*Iv*N^aa<~>RxQrvfGy<@7g6TC*DsIfSNTRDu+TxPknqD@}n`*^8|p!3zu z1d77-3S%hLD~<2zD`Tb`MDe!sy_NMliap|KcqyVl{0$6Kw~?^5Izr^_4$jJ`@DJqm zNkH`rMACXK{{Ub@I-G`v`UGz+UBsUuqH%DPTe4Vq4sDyC)0XK<-AUtWPxqlyJ2 z-Rk@xjuogmfgp0L;<5SbDg1DQo)`{McEhF+bq{c~LNG9Y&Wm=}kuK8s!M@t}1JgOU zbHcs4k>bgJJtdVTVJw6rcvXSmdoWw7{euD&OH1WmCl<_VT3lcjFT#5|0fVDRMmZtr z+nuAw7Cf3iB^YvJNEN;?vlCK>9$0Swl`AkwOgQHnvJFE4&xRILXuZ}pBQ4-&tuVy< zFb@~jONTGY(IE2HtIAHQ)UV29^V!8BMJOwHAV~qqvC#Eb#KI$v(@6xCob*_1= z@Cutizikn;oX_sbvHZYkg1xLxIiyC5XevI_a67m4O-sxNX$|RjZS-Zd>*=iLaQRFpdlEOtIzatN;rWxwo zrZTc&!_;x4uwH1>x<%Dp=*ygkh7wC&?(>Nc7{M z5~JetjUP3~;lSQNrK>B@$B)>@j4X|Iwq9B(poD8QA!wPM4X*6~#{z#T{ZV<5$zSB3 zT+{lx)n6kt%VQ;1RGANmV~)U#x{Kua-kzH?h(hwnA(=1aG)j$qkj(-rpaCyGBhXng zw5J6p2BRG@dYD+fAI|Oab9fo+{VbMBoq-X$Gg=-YtN@mNzdAlCdNpZ6>#obi`&$oj z9x`qdfkgl(4<-v9xADfyN@G9ycq?^Pt#-&V{K*!y^5Qh3)L|B9o@}M_3rW?v&p>rL zZfx0Vwm)t`xSM)UxV*?S|MJ8|=4t8L%a^C-&>;VTk8v_!0#-b=eqZtq~f}%hoL|7BQ|If{)e2QR}x*FFKTJG==jMa11)fUS}6aGp)}Sk<^>w zO7S9x8@=EBmvGNqs&$i%~ zT%c?t&5Tz2gG~$C{9UGX^OL0ZmT>#zs5kSU4n_CoI*a$??a*LFzah6l7)9!Yol})a z7h=Lp&`#hIojtaP=4{zB!l{fZM+OnZ;jRZ~-*zGoi6v2U43n?Y5;_W|_0VNnWKSaF zN5!f4f27jA9(YCC^?Nr~@=Ru$&Yy7qy@FnQuF~+5ak;f@_j_z zaw>`4Ne3l<&LAmHptt6N(kgjUjtE~)iIiMY-j1%gA^eMXTgF2~I%C+>h=Rhc1dbwj z(PIdM^VjEBA~3^d<&C0I(PIYJUc%L+j?3DD>tj8CfL~cjee^btSZg?Lr!f0*r7=b+ zkz!vFU8r9KtOD0kj#_HPayey`AB?tHQWRT99+QL~Sfwg###Q>jY^q>HJpw;WIAx)m z=uioLE*zy>LKis?oFZu{R4dkzEG&{C49AA_1ufX(OYaY2gLxjt1d=K4ie0-#w)H^i zAVs2$Lu2yAFLpBaQNf~;)@A?r?x8K7M>)l->to%H+dO^gkSr6BYZo>fy7X+re4NA?j?rfW0@^~jfu?E@N> zCHT59(r|vz6ms@pxz1u~-tW_BrUOobx-gZuLieA7+oFn1pT#D)57HmY5X^x;l-*PK zF^5K^HKHc(0^b108utOl44me1{oUwc8SRZ;P+JVh+RecZPzs^njIUU)9O?0U7L zd^9hXr}KZsm!>-|%G4iaWyezOA3$1GD`iK$_~KGBs$bkN?sz0Iue$;B+f)Qa3At_T zDB2D%ivv*Tp?RvhbadVYk;1i3-qQp=$h$<9r4OoFO~v0=gi-b6)|n)Cj=fm>bUZSn zSa3muT^ARfXBWdH*u$kL%e=&R4T3ku4L7KJduG5G`!s9oiB$W8+IzD>ZZ+!Z{3y|M zD+1kgC}<#Yd@B4y>dQE!jK)PnpM|rZ8-E~@e9EY0Up3bv{)Y%*f3kKi`MUGUnJ&Kp zRzGZQ6}y+xt9F#G$>O#!Jf``6zB+Zf(QUs<(k=H(io4>gdxj2)y#vBvmcGt=;w0Kx zMsC=a?AwdUS^)Z2IQeuL?+p|Bp1I|hkClwckh}ARfo{GR``DEi9(;=23c0>kykr6< zc5|RSicEEss+?5Dtgh_c$R9j(8r541x?ZwSyj=SSp#GByAUaQ2=@YP%PXR;TD;0G$ z$^8*uD2SC~_$U4w$HOLZzL#A0#yL(pEdlW zqQ4JgZy4afoW>r+&M_*_5N>*FFgn(~JYTK%=REzD13pc-xQ6KLiuYd~_?Ng6B1kw$ zBuXU5e+%ytlC&@;&5}O1U3+j}QU?b3&V{Igg za8hzWN@H~~@5Sdo-BhK8dz+;O>2<03(~tknP|?1EgCyYNBgmMfKy=8b!uToQCatg5 zTP3gs-suA3O7cLj8K|2`>i)|Fp2Nd}*gT^kk_pL@1SZQ%IEs`@qC)5J2#NtfX$~bo z)FKQ2c);=hl44oZAUw?g(xs{afsgp&$!2LM#&1EjzXH=k|FjbyCY&o9(bBi_vG6K(u0?)cecFcRTif7WQ-#bQDq40jZep_KUpN!7-hHqlP|ldaap|LH_lZz6aX+mj zW;Y3Q^(A62Wk*3|ryOBn7Y)C)8KN2c2XIdS*M_QO#Nd0|4pMv!z{&QgGAVA%~!GD&Hq6M1p}@{duycn(W59s*a4 zcQ$5gT=xm93}S)88}C^;Slwt*`p->&;I^M94= z&5sGHH?q4}2*YPrPBFou62}+U-s5U{;{+VR0Yk`|d=j3t8{Yi!U)m+6fRPEP!|%qs zEYQWlGG1SR0Ca(3V__HMw)pQFdS%l9u6n_iA_pL9WPV5%yd5uZUHc%Du9jJ7f!VKLCU2~GX`M)WSboi;fHrJ+>TV0ejAPPpM^!yq*_)5mo)CA&^61pUf&*nGX_XXt%$lc zPdBrfA~kxt_yniIpf8Qr0MEMx@HDYc6j*@Xj(OH7xiS+Z9WlbT+l`7-O+U8440ik6Fn=8^K59Lg*?9Y z6Op}W^$yXTQqS``Kh5=^@DyM_`!^$nm;ee&ck%nE(4%|DJ+aer^lZ2`hb2730@!&M znYx46j!GE|P>rm#AoIy?N4kFxb<*%T0VOH?0DGvW+w`e0grKEJ;9@>EMVF3*!tV8^ z#RrdbweY2;A7$DvF-=`b6&~1bScjf?lY^htV|9H#y1BuhXADCb)z6=()z|VEU)jL@ z>K}5E$`ZnZSPDa^kF`DkB-iesw9bnm%l%@gXoly_e$kxXXIOi#`AqToznPY%a zE=Cu;(jPHe98(f}xY{hb-bpQ|PkHg4vGw<)tB~vOy|~yXx_Lxh*I|bKRsh&{=x(nR zpc`fe034`CK)OMIDQ}{qhHER++7j>vz#?-uS~ny3)Jtn7Wkc4t24XqmAl?$0W~uwk z(z^hAn|Ole-_E&-Vs3_y`8p*6jcY!OUTb;M?M6ISc91XBzNvVd@t*%Y;O-XK=4M>P zMc+ePPI}E}3sq=ZNdRJh-$(h(ZgdHVIuM(Z)~r35lc7nElN|#LsLZT}{|j?6uY>uZ zpr^{5St$loj%Z3*FcP3#`-I1>U<}BWNI%2>6T*^1sg-SY6WGu z+z(W=fHFlDoP z$zyRL{UL^lNN@RJKorUAwME!HA-+ zUT|W*cavX0ybJ_4#a5BGFOrlwl&R^f*8Q(8j4HsSQ>#OoKR7NJ6YK)f5L!>s3g#z5 z$1P`66t?iCs2n5XN%(9Zr3cX#&1zcXP;MQ5&a)cpg%Q@E=D;3Vip)vqn1qU>Bh-|B zNq0*juLJ7o= zH63aWM zzOiNklUYuD9GU?(Xqt(ltQ2+;F}&|s1wHFPT*@3H&e!F7fP&w|rIDDIBio|^7)_|iaG(nj&$BOrDd^L(q8p>|5kB% z+a#2HTHt`J3W!1&lPpNSm2HZ#qHZJvqERd-B5HotD17G!OOw##)g+I*O zNw?u@&r>@B6yKoQdtJ_@Vp-zE1&XL#kMu9?`Xpx8NL28mdKJJDFw-9K z%3!RW7;K1{ILLx~j5d9tcmQ>fVm1q^kvX4W+GRxeLXH3(!tn?ROB)QSCdOQ$YQl3j9 z0Vp`xJkbPPQM|P(8{jKTN{owb(o|`8=keO|5TL=IJSK~DqZa65KsD@?I5+Pm65|Eo(jhWshJ#oAvd0}t@}Ezq;Ao?y0swA zHu-Rylf^46tPWaq!Lqg8c6(I3MX99;!WR0ekOV{V8!euGh^e`R>B=SobCJ#$0Zln) zU{Zz7#q>nM$+#0ESl={+?Rs~an)(!^^&K*ps)R#^%~~#QVEZwU*il*{{lUl6r-xS# zo4}d626MJIMUzM8ha8|b4U+@8(_ljAIuQL-o)YFrZ2@SE{|*TB5GLEvT&_GRVSKpK zcoU)CImY)=4LZFjnfI!#V zo!*-+;_yi_tn8;<14no>v3S@HMxYD3cP5*0NDKk$q=M`D!K(=uwL;&P3GjNw;T|fb zfs!{168bCNTQS5NqSK*{8HjjAZER^S6B;%wLW$+dM>zxnmMF=%ddp6-muRRAzTmoT z>O5aH2!}_~Z{@YGM)HtCl&F~k2dU-4M0wZ zw^B)aa0gXN75D+1Z+R)s{@TpVm|VXR@YWobcnJh;=^S)6j>mTKhszpw2wc8CBI*cKU}ud&VT)Gmux0VcDPxm!qg3qbdTp}MOU6tU&MhwKkC_R zXZBe6CxcXappujKQOcPZ5DcSb3SkwU7v(y6t~uH;KyCT?^<_E2qPhYH1-Opr9j+J}5+z4ThH@mn zxc{OVd2#|;qHK*+D)o(5aKf`7lEp7|&?R$aJPlD3k*Z3C7N_IY#kybT9ik{&m5>e5 z?;?9S#-U2H^C2Gw8(z>u-F0Inus9r&UWgWuyXUh^a~Z)R7FwQ8xl*TFoYZp=!$N=^g16P?aV7`Pc1cI=^G^S@KHYo_K5QHs2-y_f?JJxzht$7a)9jF!?z8< z@4OrEoM+wH3`uTO3w#*+b9zD+f0|cxA&H+QtVauMUgo?@RGNh*zg%WDP3a~O%)Dnc zcn##>&3}F^SQ;B0liBSXPA;kR_hFwGtz?9hkZ33AST`TmjVG_YQG!qUtwhZuPa$y&E7_HKa*4K2B?7jL9mBHi>!)$48kn5&_j*PZ;4&Rv+CTd1IvyW7`7BTX>sR4&%6I05 z2>Zw5IU!eB zUor)q`#a35L2kVXjy{(+P+AuY(ldil8bea5i9qDrKFt_NS#Dv-Y-O;AM$Zi#b!J+j zhLu^VA~e)MPp_O4pTQm;ne-?}h?LdPk4d>&dfjN{MvK=@4p$uC=#6LCW2fmN?UXG0 z#_JlzNs`gS(xbsYGkq$oKl_ky8l>2(Axv9RJF8Wc-GPHx_fb?nJGwVnP@Z;gnnyMH zP!V!xLmh_sLVo$3kSRqZpZd%^{Y{9t6;U3H=~S29z`+kc{!;`6GaR!fB_ zK874;4X6|~Xb_#Y=EQf4K0gnImZwdL-EZ8{`T=nTHDc9CT|3s_?j2XK6dFrZ$upng z*j@=I*JKS0=3rjtzn02xk7QpR@84K{wTO9uA<7498#IoQJA#B6#=REAxKuph43_kV%Qc zEmAT{w1Nv zJNZ4(rw;tgRT@S;nEY6j5p(&>$Y+>~aMa&W4hNf$y6|b&2L%HGw{Po>ayY#&FsK;p zrr$}?Wy|qw4+{*IBEci;eeiYmhw%!cr>Q&}>trAO`X03e^MFp9muD$7SmQNGMflhkeG9Aa-d=>^OEX+s>~DnxyxPWrx^mDC z*n`meYp(j@2I&M0bm%LgNSk_@M~uu>;qfxnnB?xzjH-n)T|TH3{!mpv;2PhkvYpDI z7<<`?5lW?99Pwix_8jvS=N!4PW8rQUQk!{ssk#xtI+vJ~n% zwVqVWa~$|}Y_=|rB4hhSqUDuH!#FM#+VI2&QMqJ^a7$%mo$4NPT(>%=$;X9j4O^l3 zIH!|_xh;HD2;U)Uue>M2D{JTSCIj$JTuTudpvVDK7wV(coyw3o3)VcC8gF*<;S#wdGwm?C`tfB<>M_mbuh zsx?U99kSSoPmyf3;YCRBlj;uKM=v3tksicP0J^yw?wE)_e9c*6Q zLh&AzH0;b1t<%4aU^bf6afBJ+v}fs*rY!S#0nl#QUmazEGfoOrmrC^ zJ7Q!LSL6-rt2hnA;aWFBfBH)g_6~V9E*s9Ny*H1%wE>Dlh8?vwwBvTavRN7JBR>XE z6}!R@$H#v>v46X6fQ88dWe0J3{^a%|^L@=8gJy`fZZ58EsBg9R7Y`--4zCq~-xG*% z)yNH(FYfg${~AdAZ{*G)9HtxpBR-s_$)c%b+6k(60AHEOSoJ?3*$80?5Am$Yj*F{5 z2k<{o-@kxAr2)`U@S1=dL=pvE*K7>os-@JlmqlbXOkxc?(33b0lyo!x3B6KV z^(+E}$1(&gcGiXF;%$;{p8%xyi_5Wpp;I8z^9qQVKXdKyf_-L!20BIV5cs>qoIu>( z>Q3{wsef=pT0VHPTC)19N;^w7kDE`gTF9oz+QF0yKNp5)b?g;1fs^@6c(l>gW=1Bk zjph`J0jM+;Srju*5;%_VKOy{DQT^GUU)4JrO#kAr-Zx$_S|;D_FH)bdh9@xaRm)<% zH8XG{0*fOd4D5T?$@rd~onoXc$^>k!V>|TnG|a6`GHX544gTBw|557G_Wky$_ir25 zZT~v(5tvB;tbt0xuTgIbxN%k<57)bFjz2Z_XG>FG*NlsrBMkVrHg@Pr``H3FDNtt& zH&;RI%c=SS#D;mA5bJ-a=3l!13;OB;i23x_cMimX3#&q&cUKF;%Rms}`+vgaiN&%q z)|DIAz|rGJvI%+g^8rriB1cD=#ax-Jqk+j1TSwGk1|-`5p+YJ&oMGpR)$J&pqwCv3 z-${4 zk)3ea#(6jhU~S-9$V4%;!%x+hgZ=b1)%dR=b}G$OF6i$;_KyVbJ2wOM%KXeOuN?kc zgK6MjjA`3(gd~5j`5fTEO0&W%GcZ{WaIo5;`h>Z4A2kw)m|R|=4X_^_66?4~rtz!b z-DUnCP(BVH0HNbG1Drqo#U|z8$*M)M7+T(Rq9_mdvrW-gb8oJ4Ob@qWnl^Nh*e}nw z>Q?qeROp%qv;%M~v->?qTY&-)uS_FEuxyQF%w$fQ?ndBqYPnDzh7nLzXb z?a#KeEyw=B%!Rq&$!g@ghL;KOO~%0b1)L@(j-2*o4eV8~Q4@bTBQ9}8D}|19o>&}# zs4yYf)*#j?CR8BA+d6|{CMz3KAiYzC6WRPkzJ;iIIsc=7xVzW?JIABEI}{qNM=CWOT$no`C!#T06& z7H4m>90^D`B7cgWlGN?;NHHTfp6%+42ddroEibvHlN4z?GBZ(;wyE27%yp_SCf-Ltz2W(*YXJaE8(v zWzAPVfKc_gr|9=H{VudOabtqF^2bl!^fe&z2QgFNS`gm>0IsSKCk4u`Ky4fy8xgt} z58rTChM1TWH+rIof! zE6d5mQY+Y7st9K~b+=!t*} za3?CZB*f}sl<&A-MNuH1v|Hcq9^fnX=Zp_~xK>*4Jw$0z7 z)Y*Fm?^em0MK>-^`bg)hQpbj9-llzZ!0BvI-NHXdVmkxWsU8!HF`=|88HShrF(sce z@zXoKE?$UdY#G?`>E6uj1Q4*^PiWmj{zN;(6w4gR8B6Mc5dQLN+;H)sUKUwuR;w<< ze|K(VxF{pZDAw;%Ne%iqG~L6*vHbQ%@2P7fOAN;D>-TaO98Lm8{>M?YyZ1&vJ)RTXDV7!CkXzM2XWZl}9t7 zH1S@4#}}R?ey>Qiz$v4$3k>(OYP+8d_yM~3IUu`e(%?f(G=XvgX=?uX^&d$vqt}2Pd^wvN8oFn7uo;Z?HaB~jx*C4g?6cDG$R;b zV0a`I8xfuZB^@EQW2+#8zD+S|-t{Jj=<}vgzAb!%uY7$iP z0x~v?6KRhE9<(%{@XuCmW)EbmPc!a!Km_vUSJbf$#DMz8%+q%N3&#*k>9ukdLVDR5 zYZ>imHXTPd1FMWTytd#z+bxY2*KQ!bQ2`dDs;>mxFH{A=qmUfm!aHnoT!G(~xDI_C z)t%CM&n3g>>fZ=(|GTJN1~~o=y$q2oHM*!V0$;R66orL{_0V!G8K6QDQ{X}t+dXV1 z8RlYEC;3+)Tz5e8to+@t@5+*!6saTI8Q~bt^INtCf@L_9taFnthu=OPq8w9%-`3OP zV$pAhWv)N>+q_^5HpeO6Y=$l0ZuQ<4r3@2@Oi)97hUH0}=;GK~vhSON4#wceP-x5% zmhc)EB)4q!NB!cL;e=00Bo~R)oZ*J7Di8-}uX=9;ylEWWrsU{9sAJGLL_7`dk?YBJ zeNHe{QBI3HwFn?PXTTOK3t!hrb6m(d?OY8J<4Lo11XzSN-i|+%DW&n|JNh;|)g%vp z!yd74-BU0wH_`-GcWGyiBGw_OoG%}R>N0D}5*q-Cq85z!8Z@8$ZGf7|IQ^p!g=1YW za%}x>)z>ItS>IIvyq;97O>ZP%GbmHk-d4KfgqIm3a6-6~ArV;joPR|CU3oReY$@#g z6Pp^@j%TC_a+U9`%@JMu?}j%~a+fAqv1qow*m;uh>(8cb#OyE1>|r*-Z;*%1Y7=lO zpJyv5xIh5wmtW|S{E`-#<>9C?>GE)aB_B_qRspr{O~_{?)HDQe3g)e`HBHYZv=;^x z8miJPT9mllKK$}fKA)rnzjh?mHw}5=DM@LM&begGJ-nHV=D8I46$o;LQ&2a?V*}=v zA;r1=C(A>gK<`oaVhm;ujCnP998MG3&}tV%<**?X*_=f6Lr4f)P}e%1-uOD2@t+(k z2qepYvHd1!ph_R!jHcTX+BP0~SYyz<%YU4vTmBq`vTTu0asKlmY!5S*3Q>Oz- z=vi1BJ{h$zj{be57<3X4@*3wUvuf1ges}+>-SKw$ z{M#`0uRr(4{0Vd4)d`#yhD!41`MOkD=tf!Lz=>`bZ4w?1y7%TQJm8r}2$hQ9ezX#k z1b7>y1$mr(9cHBO)V$y+f}i##8XlFbMMo1^XchH19{8MBDO_!`D@}V1eu8KKiNn<^ zF7wmy9#avbG`%5~c$44QTYNx1m&5b*9O#R9v4c;W2HUvK5rUqJjiN5-p>XbD+z>LE z$s&7>7_mC?OCU6!X_E@AzjB3*q^uwZqn*Nxn0doyKnB1|!4(D19G01+Azb3^F4S|T zAiOQu2~0*znc}rVu`NS3!tuK#DKwZ$HCfBixV*M6KjX!Uooi%U$Ovs1&DiJ9RMWamhF&L++Urm~Nb zyHT&Vl_wRSY!c$~8UN7t@ru}_J5J{b_tf%Mj6#zogAv?nic<|Sx+Ke`W1QojV>&_3 zU4g`QQIM1UIfb#wWzn!6J>?9zX216j_m8WL^BK5+V@(#+R1i~~W2LJ-&^_?@xRL&D zj9!{J1hbM|=0u7vO^{CRgEzb=5PVc@Fhu6_D2jrl6NRHa{X6Ii7e@%_MonDMHs!3*wL(5mAKEa`Pq z4TF!ce^P}HrHNWtC@mG7TviPsUhul$G6+~u^lr%_DZ}riUEzAoL!Axzx%#;Vtc8c) z$6lPoN)>T!6_LxOy}(71vOqydh$%`nN+HH;dv$QN!Q;#|Odbf0&d&CG%x;fxnI^do z3Wt7G*ucpTAvpLV$GVa?=UBsfq<`5LRC+NVn8*9pIdO_hq{>6WZn-JL=rC&I=X)R@@c#Bek3-ohS^Ux zd|l>rog63ZW-P<+rAFV$QStCNA1!+_hWFPWC2uQrb0@ez@>AF9cZM2SaF1TAjUknx zzU$@HAMplvg4keU0YYU+NW^=$Rt?xnePvnRTwHvq<3DV4QRAK0zcAt409%g_lq2MQ z5L{l@nUX#%SsW|M)QA{1ODb3^PH%BgAFcBMR4|1fH3ovPEVa(yKf)3&thxeP5dohL zAaaNM&F3Kwx6IyR;3AqqWb`g+K{{?m+*_zPXi%rC%p1Kw!+H0k_?hX~{ld+O-FqqU={mv98wvA>}&ctq@bTEXA@Fa!Z_P|?k4lmW7(uC)GwHzQnBgp%AN~TcRgF>5 zpDXvD#ZmSv*^rk2(J&=?0ci)O%T4R1B_n`^q4NIvIG1K7J2=m0JH~y8*yfek9fTLO zjY~OF3a?m@B9SgL&N8m>sEJ&^ANw`KxF+4EW^b{tPplid^;*u5dw6oK0u4%#V$J*) z$6>nb>9c+1B=5xI-w$kR8TpHAhUCrm{N0|EGx}Y3S1P{O^TSrq2%Tgengm|UuxoPI zx|_=wPvJ{d99xOMXQiHB?J)E|Pa3!n7PPAD$g9G_Ts8=%6i9t~H1z$u%B_|obkes9 zMJo)XY) z8(MKvFh}57Jg#jJ1lm5r?K?)N?=gC1^;5I9D%bs1pF-J|ub&xb7Q)kWk0v=JxO1jIi zAQx)9V+AKl9f3MO5Y6G&0(?ZIVr~!7(dDDY`PX}2un!DbFP|gbmiRM0~aUy{AB_rL$8as?6aBP96{5?5GC$lY1&9=mOY!jVcK{Y$W;|qq4}Rh z9VDM>d#O$7n5#ZwYB0swQoK7}c~ieRwh3i>1JPR|fd3f6`MVU8JDQEb37rP9$#9_v116X=}X@S*wr^Nv(4!r^-uVxc&bZAsm(zwBOL=Ht*xP;)c^pxak)OC#tTlL>AD=L@2l3(0nM0`;c z3r`P)D`ss-$l*uRB1XV!K;X_5+@jRNrin!3IEXZoR!mDs>hm5rMT-&!nS9{!2H|kX zu5R_9tWkZkm9SI5`ORB@TsnY*xzlFZmvTQySNIgs8sHcdyL?n>ES6fx$78TlOC=IWC<7->SEv za+>pwQ|S!yucT`#@cJ+|5<2|r6sqDxu~*-(1oa_Y2v%e|)28%@8~@OZlnxn@X1qZS zL`&j!k-p>3t7~POw@qrm&$=PeM7py#w44l@%kYQe7~{I?32$8RLGeiN`I34L*P5;{ zFK_v>C&>-vD!<;3Nc>%F;N%$gF4QgKYnC9jsnao10Oz}WZ!3H4pBK{S@xoGK$g2>m zxEmb)Q)g1U%rF1RGhVYJG`??Q#KHv67H~?DVkwa<<>Y>8qj2qkznA0E=>zGc=o|N~ zA&H=(ATwcN0`JV+LI8`|jA-GCwLBD_g{YTuvflB__a&x*AmvYBmb2i>CMv9oj0>{y zTmj}bSqAlTr@)h$1pnXP?!avQ z7kpQ`7%i}la9WOl*b0rPh5JTTz(M6LVYkxR*(W%ijxXirj1uxf0ZfCNOIb2tIb3*t=0`uv8-J-N`A_37_u*~iAm zoK?@odc1Bm{e*{83h8*Bk)b~d^3X7spa(E_As@BNtmWGUjgDUlPu!Pb4-3m$DJHN{ z3;8j_fT07I*BfZ(6KAJYzN$~VxKW;4&9=g|Mop_&=kHHzVc-8mjSO@%$Xc$r9pqK= zwYtj&E-ms;PKcgi#yITRDlUC(N2}Gb9#t7j`SbIF3dtu+_54f$+F&z=9xhCx^9YLe z8j~P7y|p=44pLt3aZ!x?5Vc9URa`8;Y`(4fwe)k-%?q^*GOC(zbrLH4C1&M9$JJLK zF$RFvZYv1g7S_nAu#qS-gm7D2ZMf1NYG|ZLDp<^gJv#M3q?__~dwd&piN~6XZHcyw z)C>pI7dI+KhkRB#3F)K9ODv1BK#WGj3qXZCB(unQ1|I99Jh@aEe@u$l=5o;{n!>|N ztq~(iHA#J#dAmhGGZOuRRx0(J`XlCy!VG0{kSQ9xG*L^oia*4M@Xl!f&sVBoxnsnz zV;K7y7P6~eAzI%+&M;1a6fRH$;Ia@>DzcsjGNjvYXWlFhP3xNr8Xr*)3{bXZ5Esl zhmz*pwj`6Q>uOPekk8OBGHx^ps9a^vF+JwSx5=H*k8!Qyyh7aN4Sp-E2v#QXqikmj zBfI5%R;9)~guBJlJtUx1rB>(8VB3E2qb#ds;GZfQ5WBeJe5eQ^0EfNAm5%jz@7O@N zvbZZ|lUGbXbVmviK5g51Nk7o{#s#?=Q<*568!n>BlktAdMP69=a+$*4P#*> zqE4N6bVXv?yHd7Ox+^Ht!;J%Ir$5&UKYV=6Z{=FB%5q@>OYLb~(w3(9KUcmA|DvofQ`Q544qoIReMYRSz$LCxU#GCol>l!pZ`MIfktP z6mA1JAMrgebfZ~NBxLsHty8=^_n)m*P89@{xtz-n(X^pLZu`q8lh}J}7HY(s_GKJ< z*>*%fZRMWWFeg|cEgmh7Moz{Gf65-b*Dnas%5>wvY`fdQl!X6+jp>-sNPLB${qvg0 zIe+`fU0j4y#&i-zg&_;}FV48^qqaV;hMV_aORy3AY4W(f^9%PoX7D?Vg|ZQ(h|ext zll_#ix|eXD+F=-5QE?*5_w$nbVoR5^j~gYMl(KcFewmqK@itS%>lbBt?bkZ7cWSGL zIaAu9LcY)Cv;d>|qqd#I`4>#Iv)k9VXoDlpEsqh>`juiuE)kAgy0NuwKQ z>TE(c_-QD!VLacd3T)?>GN z(AkzFyGUWeZFm`88Pb)=rAr%K27F757BZDCBO=g;f0Ol10k<}pcME!r$TQ^JWLJ?e zB%)7O6htiS`5};vN4p@oklN15t%c=+5`m4qu2?Hs;2x-SO1 ze>Q4@)R@8-fSp~*a79bIk8xH1T5KeJxa6luXkk9a>f7rR(P`~CxkOl8AmbX!um$4i zQ^w`(W~61Mkrt#Li1;EK6g4m}w;Zz%ulJkXut+OuR$?W#><*0*ulNL{j`u@mxngQo z0ncU*#aFT2=B=cE3d9NBHz7z-YK(a|hCl2}{zpemN=B0bMDPDjJ~HBZs)>!0Be`Zj zVeO-G*0mf*g}lq(m`ia-6dM0(N zd3tS%($$DIxkrm+!WqK`c|q!}#|}Xy^t$)hne}_I2na^W!u$HXgj;AC>3f$}+UlE;vkOM^WYgio>{n$UyP)EPq_m87Cy7Xhye;p*qx>wV ztPJ9=$&X^k>SiMQ&3+qf348W*x$LV-_eZYvYxiRdbAJZ|8-91jjeT4-W+cztFbJ#X zJ#$^TCX}PZAYvO{TQsJK5tp0^>h5(PDjgnqE8tS@ETC_VA=IK>`1kQm65wl`p#O{e z7isiW)W+WeK^{@nOUN{iax9*@SV?VQ;Nu^^hGEtGZ|)ItIx)O+&UpuQ$bUz}G;&#E z$ShcBa`yd45YW~czQ&I7b$jAEWAv*&%7`UHw$3opDZ99pveOw1zxBCfu^YEpzCz`^ zUvJx>Q*Tmnv?$9rr%@FvheRS!JlfW}%8;TI%jZWBSt6`8+Dy-=4Ee1HDw0JL(sKWX zgA$@sl58pz%<5<;P?N?W66uTetK+gmT`l{j%xTIH5Tva8d{B>klk8rYE!JBoc$Db& znQ}#WZb}SbIsMhJ-Qh7ye~m2IRLCD{qKDk)+AcsdKd~w=iz|W0`y>-mU52S8Uj3tT z9B(8g*&m~StKiH?>&y8d#d#DLe|D;M9OY?fI@*hgQJLTM4aw}M(m`uG1#L2q*^)op zT8OP^CcKZR)9>ha`F4W`36H1}SlJ1jAIC&)&z#qy3=)BAblhX?K0K`6X&AG=^-RWg zNK7x3(yr01EyH(c57n*YxM(_35`$hlSNc6u)r3ImN}i_`hLhGv?^M1>RPDLnf6xhZ zSyO(5gb>mdI?R)$A-$SDsu(sm{xeI{D1)|`&jvECT$_`0o=3pOt>}(KhZshg6&VL-5CfUgyOJgP#;vJ>tMfRk$Y^8c z9`ij4t0X}qj5jQLcnWM_JzN%oZ-u0lD+P4lGd$k&3?_U@s9;`sX=@)I<_`90k^?&u zOZCKj=Ew0OKE~!b6Xw4$&A%&qP@9T&EO8vY#_7w#?tGn{)qs^yDJSTxk@IjO0gbA*%wHHXq zR^5hndLqE7R>{|Km$R_W;gE1U#{^vbS>Cpms;4?(9LA7OZY8RwRpx=Ai2}7UP~&q# z;Wjg)lYU%>Db$>WA+d%7t2Sp1*3`lFi>EVJhg61xzJ%O;U>N-kP?ZV0Pl~K~wKznk zVx2XO^+>bzb5M)JBRTXOw-tJ{V+Cygj(K<$ zjUQMOn1e`&1oG?3Zr)^|ie$iSP(Bcq=x8xonD7)Rn4#jXsaC!+2 zcPupBjbiB=$nY2?s@~3u5k1l1u_@^#Mxm|`83O6m9V0mL<@z_|r`b$7QXf6HOmxTe za1_!KT$c;vmY!k#j5GKCxgBjIBqC9_CuGDA&lQ~Un9t_giA%8)P;P&!o)!WeTAeE< zL;q-m)Cec9T`?`p|jL`AQFWnEI(B3u>?}Hn}2w9iV2ip~aP^x}Al%MT5$qA!YiOk(i#ZMtu zNtDXn1yG-^XHHp$Mc|=w1VRvQaTEq7l#-xkiKHVO9p={8*`y)XH%r9&)~8$o#pGKs z8rwVo6__!}6U8{@UY9Y5fa!xC|F=msKP|!8|2y6BXGdbg4YY zgY+A%WVJ*o;^oiCUI5@mfVUL zTa_nw_G3mFpc)o*8EO)X!CT36Opp|G%=$8@AVgK|=3?_os%ZJn26ScHV>ypHD>;5i zY1!d4U;YO*!Yf>~EMV8c4As{cXlVWvOY=Z&er{Ye+jGIh>A(wSAy2b9QU%3Z(UGi% zgNfqzwpjT<2Yqye8#4j6O(C)!2X#W}Cp!jkBUH|{-}eCL zO>deO&bw?^_r{=kd_E!so(*VM>}g&G{C}NI^Z*FjEbpJjZ-hb*Uk`fH$EbgaKp7d+ zL|YnOk0do{85#aXnT(VJo>-qODVw;y#cn=q6^gkggF3J=-I(7R8K8wSVVT+(Muo85 zH<02~(p5sHP;p*}@#gKUR$LY~Z!4ofx_S$7(N=gQ%pyrlhkMgLSA0xdf;L@+;7ruy z_3EXyA6t%H6P}V2YT$hHn=@Ao9Q7&JklVQ7-2puH*SMH8@r5yBr3>R?2b(sslx4(D zj8O%p`gWEiQLl%mLk99ACcoYdvg+baZtv>;yVn1YR=9GABp+6jR%adi4;+R8)|YMx zgkYD0wVc9R%lV1rr}Ptl9B`DI`@rMf0uEeA*?DivCQzSMZC$M&#ABmxYG+nre0Vgn zrU~{^s%W%mXqJc=NO=+Ac}#p7vVa2H_}Vl(h) zpl9@N$Mkh>Oh+L;Em)i7wpvMC`a+EC%yX}g5H(4yN&va z6n=z_wt=ech!~h;CRE{=4h$Zhh522Ck(Uu0`Xw-8)XL{u#J$K=j`|XF5DWvVOF&j5G!UW^cSxj(ow{gxIxw z>N0-n#3RvYqzUchM3V6Ne@C1DFXNd`{fxVrRrsX;i@UJ^=w!Sg?Mslw7SDd6nKd9h zxSsG*ooDRlpo5~BZAP&;&lvSnng`Zl{K+=y{=Z}ii>S8*Q(vawgS!8L>#V{h6|HgD z3aDGCI@(ICBB9GtIcNCh(akgDCn#7XWhWE0%cO3RR<_nRhfG^00RFjf2{dz6>(~-z z%d_4xlRD37f>j?s@^W0Z3L?l!7rpr8q93>1yQB zzu-28RcYSleiRpC@77m6-kC$2Q}_DsHv_l1Y>y8BxM}#E!)%W%Tf`G7HeND-qxMQH z;A~ry>442zR9*OhE`pw}y=@=G?R$r}%hy6t--cAXJU8ob5{f8*tjZVh{?3W~l8g~x zd~#O|i7Fzjr;TtX`dzY021kbhs2B>qFX@3_*`u6j9zRc zny-Lla~2nre`-kE0e6vOTEmG%jV(^;~1yL}SH3snF#w zm^VxHY-yA?w{i}XbeQvNIr;yJEdJMxPWUW{$jbZe^Uw560~uA)^-PAUkE$8MxxYM7 zC%}!_*d}JZwCZa^P!Q3}6L^HaWxcg5^5_2&2MAI9!;tQRlI-1xBm(`LZGv2p#)w1i z-@g6jcfV~_r8Q?*?L$)hf_*DfnRbM#%@uEDwGq0^qx%RI(#1g0nmn2ODt!6>a~mc+ zm#Q0Lb-1RlnX1CyTOPhZxcb`p{pNBI!whgaWS_~BVupM}Kc$|Zn26?D&9o!2ln;;4 zZR}@*kxHC6`7!9OEn#<4yAe*)2K`@33wF@&TG#I{4xiNiS)s;W!P9m}Q{2c0yYV@3 zpCoAT2*?LVIJYUxPpl2|O~s2gdgJKaK5<8kl^O!9 z)-+0`+HMNc_i5qE40q9S62j=O=xc#1t?2e!^4|y91Xa?U_@mqy)!5N;i>VsGLp0CD zi}GOctnKjAjZScs5$~aHWk=>Xo$*Smk>5V^?H?lHDzTlr&$JdMj>U|K~Hu;k%1u;5HT&^)DnY zM`J3hi<=UWACqE1O>KQ+G}#S>f^$-Aimyq`wqK%c6eDBZZj93wWR|b6)2g(Zw2+{m ze!cqAl-*j++PclWF!87Oi8eTpQFi$y7cQGx0lnR)1^k%n1znR-K){fhEd=c0>Z&_V zSU9b7Q6}Bt;P#X$;htJJTj^B~upK(n9;{&HLsAmH9-y-naUjt6% zd-$eYiN43pi$A8w>-I!pz9Q`9{X%@P{c%m>621;(502ZG|5C&-3@h2GkMlm;qaecC+T+!_RZZ@5kI(s%a_2PvD~`?EQT0FD>`O{vF(l;=h4T+P!Pvzvl1thj=Gw zHX43u&e%(^aWYmHnsC)Nxd@??vAjN9P+_14IO48n38*`;M?I7c1oD9C;ISheEH-t< zZs6u>!6X;vt&FIA7JUG2h|T4YadWMhw$w7(BvGv?!5z#HLCjr1pq-ha`&R$idOeMFt1!ep1aanH&d@TQ2 zCR~wXLxNL`+|J|GRt8#(Ry=$nIQuzdiB95K`{VsEvi#PveFLbcd$y-P@(e`t^dnzR z#IwMN5w@)N>_LwY&TB;NMbmB}F&q4rNCeIcviDMna_26x&QPOy3vws})kqF+4$mjU z86zHglXJ|Cw8}>o`Mf`bdG-(4#JVFqNPUwNlWa(%z+ksZ;sluEOnz&`aoB5F(rv2C zzGMT)*Eyii+G*0NR~1cl`s3{%T{)+`QDc;*G~e6_5(5Dz-lz$Dm`oRpcx$oJpR<#Z zus;$j?YUn9Fz6J%z+W)n`ep(*$x0r~-^teZ9Ki9%0UWtFZ9h+Htlx}&+aS%-8PKPO zg1;$H2GBiwtlnddmKgPavdp7$i^L=@Q6d-hac!oXw|>4i7AAfKJ~-V0Ja83sVONIU zVx!f?gC!Oj@AH}Tv(u)7!|iN4xDsi9%s6`&dgl3*;SIAG9-;u(G`2uZ@X%e zt5HsyN6o|(V;Oq?DFe{AQ?*FSg)M)g_+t3aiDd$F$UbyUey)XyDJhL)G`qoO2 z*~q5kI0Wm7XWX*DGHT=ai)RMPDLK{jOTTZSpS;Nb9_tBNcC$C=Jm@rRF~^NT8OXtT zs!^DJNASxY!>X{y=-~dqDy+<`l-h2(uSr6ZIxefy!qw|K6hS`UO??M`4_hUX^Xqg_ z7`LWsQg&(|8$W4KpibN-3FflQU2{WuK1I2q{W4r*U*(Y{I`=HHvJT{Y{z+^CcXV51 ztLukI&H*D%MfJ(oo3{twKBheaGHZKp;J}A*fNU+xp|(vcqBrjgNTLvX9cBsK_-~wW z8&$qETy4YB)H9zGoF#5;(t7`FS_4kbGk;r#c9;x$?FULpmFUl2BY@kbB1gg&ZIAYf zNnKF_whiQawX2}kRc8_3?HGnv1T_j|Zs9*<6gOP^vEE~!wE?~brbNKtP`m~ZX!dVc zgRZa^J$>o|0G-CoYiYLpT*zKVEZzX$F&k_dAf?l2hJmM0&=;1XkiJxr{{(=&@8FRV zcv}!p0VEV1@ zVM5Cma^H#Y_SU1ce1w&uUnSBG#+{PY|ZV5hgtPa^PupU z5&fBxPz9bf7h*w}zEJmu>iGzw_h@potISg@vR+;mziz2K_s?0v@^$X<@uv>2RO`w8 zln08SH~hYPd~+k?t8?_c63BW#8OrVvm9Aajyp;p`Ro04p#7c#um@sI zu`xLkxg2$WL8^@;6e1jJT|b*7ly1Vnh-7>nJ?fQ;H3)+p!H?%NR`AdOFUroaN_XHN z&rnH9Wzz8?%3`+qjQi(^88BD4=EIfc=50kaCc5gPLeIMONrIt$ap~|^{qT2zqCLM` ztG-sHUi8lO+<6aE_*ILI0gDp5?du}^^rUZpMEMY9#LDaDPvmdsG-m(h!vUVm(J7k@=UyM^6Ho#qc*gTCeXJH_&CS>lp4 zM*yPAxdtd#y|f@e?()p6MI0~W)h=`e_|aPdU8+wP&$}6;bt!)?hCNZC2`XnOCDrqR zKx9Dv-sklPxWA0hxCz9z4V)Ym_Q>;MtPLOeg312AVZJ_t)o1tI`F{%ve>$z{I7xjT zlT622{Nlgr^u5@N)r})yyS%&qRXe@HP_jOhX?3r9uU!DBKePg{0~oD4<9vw&*jBxH z{(CDAW~v^-w-o|Z<~b1JPX;0bM-d#+g0x@LywZFy*OL6(_=43^1^rT)p z>z|E*Uv&X{BOMWvwZ2a>xFzDyq@FqLS!yL6{XuMxDU|;Elc>aSZe#~li||+RYWEr^v&BE)9rK*aIY(lbjt~}`P(|criz+O>Qht3Ps`NUR( z!|VlsV{ydh;UF`?roUdKDIj5CAaib+wVE2t^9Z^RCQsq0zFbj9R&2UJ#nVFCW}%zl z45RCxXc~$K0o;ex-cZewTaw{}7DJUy8DB1Ew3S=Q9NoIkghNM7wNlJ#kkA$fUlJ(G ziomfTdrkY{I&IN}g1VA2D0xlP)|O8|_Xn>>^1ZsOJbS~^cEj%yC)j+F4O^g_m%(Wx z$AbTA$8hoawnu;2jeeFqoq@-4?IO;nb^fzOv`?RhP%y3!+_EEs`VI(35O3DlPZRy$ zw5&N-+MixVMTSWFvs9G7-#l@;3Dwyv%r?jHpb$?j3 zFk}UK@m;}HoIn-<12g&ebERlA5Ku3rx6FPLl0{7GR$iV;#m^g&BD1;B-Z&58FO0dS zjv~`K_c+6xH>xck!MnHPg$Pz+Zxy`Y7!w>QO~58nnBkyhl$_aUV2qHT;afB+wQiqC z;SCmk(zP|xPqwTfL@$$yMzL{~B6H=Zy_pDsa%48X!ev;|oSPt4k6-@cb^OW4RgG@v z4k&i0PpYbs|n3G8~O^JSy;ErDwWDC)?I# zYtnq89f^~nmvD4%lhLYeX9OcsFKcFgoU%}c046lr!R?DHN>tM^ig)quc7}_JOjgm{ z=3&$mdSaI4A^4O>{SC1J#u!!dI+d*KTj+%gaXw#R#Hj`MA>nqF@U8b2X71&0wQN4* z>a@x{eEGug7IH2aj(?0i*GCl`NibKqAcWirinOf&D14pwKfuk1lUE$eF}v?@MgtM9y|wd+TbQZy9VAC+gh-%i)Kjr6 z7heEXL8o8X^Jh_%Cjn`kc|_8+eja1v{%<4ZA3;NSg_R{Ziv~P#6)BNZ_LH>MR^Q1an$Dh-;Nw_ z-H&z}Th<4f%ejjquQBm-n&jU4?&2HknHrK9z6Pxz`yY#KJ=uyxqcJt0vj(nhOuO z;O*g$wunPMC@S8^i~t;L`f0L%wl1zPLHfPs8Dp=r-Qd{$-{*a42P90kL^_3sBzWR? zla&d6*GG3j*Heg)SaXN|VFw)~dPR`gsL)4PURX&4#6(iAS8iWZIrU2Jeka3~TE zoia!RBnzTPV+=*Ymx{mXepobA!TQ?R$kW)t)6vNDuE3_Eqv}&tRaZ^T$^BuT_7}!W zRsYTcK{shiZ5v)}>O4-}?VSlbYgx+ixFf*caNqSSE%Xv_LDB_$en!;bnPtmx#Pb+M zq$yvFT19iTSZ|c=7o2a?=Y7VR0y@spozx52^<^AZ{0T{X_fFP}M1sXJeHX!p5^3Zg zH8Ih?*S>d78Z4aQjKuWWhicVt@AGru{95``q(O1U(aT|?@t0KCcvRS7+bk^CI%n{Fx5{iD0lwEF{2#FmL)+NjrIfC*2MTCB8>O1| zkp(U~NNg?>Pq)R!p>L$!qb;1^YO_2}1-^o>LBuCFA*U`sVnBtq?z!H{D2)Ed5%Xfj z0lC-C%u|h~D_?>CLnmHg=GE38w3J?Ng(A8<*LTB62|8ebyDf8CCYZkcK+GxUK(=ei zR=6PB3(+ex@Daxqc_=YI-a)(*)x>WP>me3fd9#eIS6zRpm*b1>6vQEP3_4o0*9C{@ z1R(ueQ42@-pkSu*3-V#VseDmdj(GvPz5J0SBoED+em|mm&t)g}K_kz5e>Sjs z19@0;B)ULwmz)Bb#(ENU}6-8DAXtt}cX85^*$Z=DW{J)m)W{^PR35oM<0m zf)RV*umt!%pO4%aipD-q8v8>>X@wn5k*lTg&MUiW$HLs<^yf)QJF zNhk;}nj=iPYEz0+iALo5sIR_UzaNiG(jCd_@IJH+tCW6YcHLTS(rD!6yhbp?xrX~S;S>Nc32+v?i9y%zGKc7J6ACb!v=Ta!gtz)BrP$aHao z{&s|UVF;HcvT5tlUC8+z8_6c7fbV>!81OBFS}t$0)2ME3-Nv%HESiuJ|G=lQU+RO- zF7YlczWUvK&k?xYG=q!uotY_?$=64+`g@)GL|e-@&SbnHc5o&Bft_o1dw`GZ6mf+C zM9@ijr^X$a;)Cr&LUoV8op*wU7wi9vQ^yn`@rDCo3w|n1(Rd z2F>MYlQwTmf-l34$)m??rtkL{1^tK%oL5L1fm`ndTWz|5Ww?Sd&_$c{y2AW7YMbxY zL#`V`S0L3EyT+4L9EZ(R-pXO363vjx9_cD9V!_mWBj%DY`NZ~13O1hMP?m@E znCaNIQ|`(M{&D^d-VG`i?+;E9UD}wu+hM1L{(>QY%z0W%OB_n zz3+e#r9Bpi$T*N}9!Ii(+E)B`QK=O&p4xhTm}j1E30oLH*8Vvn>6E|<{uHk#u0LFn zQW%)@Fc}uro>lAMTNRg}VvJgsgSnz)t9^#B-CG)Phs&Ez<))g8k-lSLvZ!h+N-nbE zwzu#6R#IUCW7c-X>@8gVk&;iKkD5Ddq}ZgXlMV#I@XaJ*JagxyOcv%2f65N%FUu1y zv9j{_Ih*a75T>J|MEh2lgd8n!&oMy)McwotkstBDA?}cTlLlowLAjHGoS%gqiX)_0 ziT7aP41M<}tCyRP4@_b^P~8~L#P(@rMMXfxw3XO#45+}X=UE+A_wMmf+ zZIWCN;oGyQwFD@1nqx}KjkYG{Iy^jlzo-(b6bz!gMUSfNxRNJcE^G5|`s0^G ze<1AL%DvIaU*F5stpU>Q@OU+poyXZbF#JiI=yh>^f)Z#z7_Sl*f=zyJaL;Z1>x^gg z0sq(_C|p!DW3bReHK)V*>szn{l=jENjQ^DPnEyqa5v2TzB#$LmbJ@$xhW}!;Qg$r;Q#a3gAtS z=B>leHQ*^nJh-swvX5vCWWyI<2V+00ZRKX5sYP=RQTzM-{%YNI%5|}`yxUR8#aUxS zMRdM9UfKOlXCJ9Iduuu(k{t8iNZl>5H^I|dqWDzS1FJ<3{>&+{R&GRns74P&-8EK(NB^6H zZ=K~{E4`d5z>TB#7ADM>9g|o)m8~#ak$pPhU*AOgNU+fidGaE?NA+>2O)p5&e9Pz=iJFrPs_S&Lm1q+B zR(3#y1Hqf^+AfXZPjq2ye0>M}Qr-zG#=>w-u1X(o=`LZ230~N4(fn{_xYJA+E;B+r zs}Pg~eeg8PK*PgDzau^m*MPVdEpS2U^~3OU}V-mTsfJf@xjv zYX6S)M3@Ze+g&6DJ*nS!<8=hN-GsF`Er^Q2q5Bl$rclQnaUS#tWa`5Oi-Vb&l^y6W zeryVge}4S~`;r3^JQpR!KfrJ~+3A4Dl=XC9=oz>l{?=(8dYTdR#6bQ-dSrIBFhjA}Cg2f~ zf9kW2G=`%Ncr)I}cz*Z*9O6gTM+X=F^=uY7WT2WPoH!?pUA`7pHt8x zK;=c{o=~y7IDtWVI65c^;T2~kQ*2-b)D~c1nTimilR0VIMJ8UXw#;iV+Y>6^{Zr%W zeLjJYgCGJ4oHHrOHy!c5F`o?@P$)>r^k#w)OaBeiG4PjAERj@MF?^z(&s7*4CD6`j zH8Anpp!dQF5d;7&DzcL>yiC_Nh6?dBCIV2>ceGP&T7MhlIME%Ft?;T|R-#qcz8Dul z24Cd2{@z6A6J&n0(~4{?4^K(n;a$c(GP$n#S!jX52uGKX_Z@I)aOv-$MH2gc9&^1idyA!Y72)B|A& zdl)LsC5gjf@yNuK+Mozq%OdMoW_s9*96n5EKx@7$`-ZX+@wGwkt9f2twV6vvEB={9 z<=61XN~580JnY$fy@#bKiXD7aA361UkRqG* zf<@E+$JSd%#nEl)!wC>1I3zfs@!)O=?w;W8?iPYJ(73z16Fg`j!QI{62@Z|>SG@Pm ze0P2`f3j9Dx~uA(Q+q%AkpV2)WM{*U0k-9QDQv(yVT{)|CG!bRfO5&|j^gg)F~?{t zrX;8G3X4F88rjn+h9?1@K&W}yx&SJP31lXkdE0#XcO4`7Q5f#)r@-)Mj$=$P1&K`H zyG>pZcg!7%;kh7Y@|DB5z;;G0_-bn@5j-g1%wn1T^>Ov5f!|;+jN90%BN%EZc=W(M zNxdi#<|76|gR!uUJf|s|{5jXwM;$72$Ie0k;~xF2ag!)^4{h|iKZTR>x^tVKn??5Mx=SPJ>%y;wI~Oi` z`KR@F;mSDo`q>14(b8sf=p|>bb{zgk_-m967Pc*Nikt$iALp_mv<;M z7(>_a`Hqwdj{cUM4psPjpgF>O6O~p*oA%t7}hja@?$1Hq8M7F-~vIOH> z8!H5p+5gLOyP+vq9i}_UU|JV!AT!)hc*b~D)prDcTqs0-iBvrwiCF+;m1p>XKC6(%AVoNxv& ztQ~teAJU_kV64b&sh!bEUbskh6(#ukZuyQE1KI($ic zKb!K2N)!LsPot|sMiQdrrp4QP54i^@v$@k9E88wsui)qpF18QhdG4Ybx^^?4U5O zrxLf<4Xwu+MQND=;h^$|^p8&RKz=Y$HAZjA8;(uZ@dh}6m5WHHo1{PkAz7dyu4R=v z(z*CkHck;aYG9DvN+RZyc&fgGoj1H}g@aV+ah1!O|L-pV zeh}oVP#czcjw7`-4?WBW3_+0~Jxd(+UiOz&(!kL} z5*7Ov5B~Wz5Df9QXzjw_z^{I5zPxM%Ci#9u z$jz>-HdMoa|MFtY;HH50hD?2`1uO7)t5otc_8{ue6B+tli;!1^2be@ET)b zRwq*Sp!$ZppwjMsfpp)P0YefLWxqHx>6KDfTuelH74R+r;_h5arJ<5K9E_h}!>?KU z$}A5$Nrp>QQ=a>ay*vXJ|CDhewnZU7cniZrpu*FHWspgv*K``n*Q+s&U^gEVEJ_jZ zZs9%a!ggPcwjN>F#p{Rw`x{L(ggIeC@^+1CSC%Fzde7o`2FWlYp*G|xw7A)Yx_fOhrE(0l3AbbOw;P zo&Zd4-nKlebNkiid<^8hf0)b4QRmg73iHuJjPG|U)!VZs`;VphvM{U={dW+zHE$0y z|NR^(*kF1tCag)j!tsQ|nTOa>-FjH=yUy7t2(-KqwSubv7l{7D`I-XPvyF;xfGth(2ASfoUVUreysW5JAfW0$Jb|C5INzq!Jxsv_rzT3On4W0kK+q;0 zi5Z4*AT#+84Uso61M@wpnJ!h60cvfXae9n#z#yxc%&bzk8BS^9+ulUu#!=+|x$LA~ zmR;=MMJuhBO#s0VX~WPDl-x`Pi{$5+h~stOOdPIyKRaVuQ4wp!MS}a-pz}3mQN|>A>{{FCa+Yrs`07Rshzi1fB@5Z!)nJzQv!0^GtlX*7Q4ZjGq* zwPO3F?{6^S8n@L9=gYLlC_X${ZJ9(fS=D?AK&01rsDE(ScIi(%(ruLI+vRcGiCuC# z|C70=tWK$A946R?vBuY6b1oh-kRg%lxIKOgWn6r`{XYN8EGd69S!#dATm4wl!v^c` zjf=$gAMzl>1k&XUmws3ix~{i12xP0oeDu9h#4*BRVKVg|$J5d34;6LcH3AulI-dm+ z=t`m(74~1#s5i{j0Re>fCrKugzo()134@A7E1j`IbrN(Cp*F&+`UrUVO~Gx)n=zsJ z+dZ7iWycKV3RM|L@$QRhs%NFutmsRU%2*s#)l4BenaV#C|dTlDnfc-S&MUo+?T}hh3aN3Y}_i^wWTSrtnKv#VEC%6I!Zm2i38zAd~n_O*jp~BJ6!yu<$gg-mhtC$@}&KV?^EAh9mxO~ zJw6UQl->h8;hNIwnqb_@RW!2s7;tW~zUV{&4h*m0MW)&4#4=~(z8Kk-X_Y!C`hXc6 z8na0y6IZ0UXCJ1ABA;bD|8e%QmB2XSO~*?8xTpx>DRvU0E=VNnpyF;e)DdXSpc}{{CJX5S ziaCzX;PPp@Bx$DUsB>*kZ)ij6+$gP#n%(rktEYE6fw^K~cX5pK6L3z>jmD+^&0o7f z|9&njU;q7Fe1rs3vPj#5jaD%%-~~D~WPQp>+qsj#PLVtnnsp^V?^ZXu!wNKNOh2t? z2i3Bf4t*u@;*yCW6O+C2vUzTB6zf4dAV=OEo!XoAbpHz7qWe4B2$5zt+K`-Ye#CZj z+QXqy%&i@{dVIrX(lPcyv0hP*Mzy4DRtD_-5Ul<5$W>_(i{-YfgKymP$0{y1fR9TU zL(nK^*2e(a6~}PF)@pD>ySLENXubMd%5oa~QTXf6=~~1t@wKiq;IuVxrqODtUMj6+ zjj*1tl~?s{P{uaJ81{a;4Py6h%9M4xeUrjWvy*Xg9^f?5Wa6<`o=Hb{Mt-{A#gcl{ zc>LSLkh1!wyG5-Vz>q5UjdCyj(en$zsbUv@j zn(xhZD;NXoX{8~>3)AxRmks;b9Q@so6jNkuMKio~kuCU=OEzsMYM_ZrcNT8p#8T1z z;^)&uqn5zlxLxqW_cOI(oyPp3OwN8W(RVkqS(SyIRYhcO+(j6K(8Dv&SIdBy9`?EmYesf7+X?$_pppknV{f zOaiG`PW>dD`M5_m`VoCr+E%0GubjnlV=K^x-F;y{0Y!1zP?Ci^xlUhZG@Ala+e zBHx4rt47fwC~W>INFtpmEWL-=rjhfG9|St&+*KD|ObfRGPxLq-W<{J;5$Q_jf4|gO>#T0Y4mh$=OfQbiu7a!>-OE^(kI_2?K!Od*1 zccHbfDRI@@I(nX+^wcY7oTl~ffrle(0a6D^jmD!NSCZWMii2I zoJ#JL#l0S4;fyVm7mmVi{jW(HlWe2 zVbN6xIfYZA^(QTMU$t`e+{biGd+iAPYU9BVgAyiBFagdDt=m7t5O4l-CFC`}dA+^F z)s;*-1M0q6h6iMf>ThT`6me1rZPERmXV!Qj*2$e*fa+?mb z8?N_@rE$W+=gQR+mPb`zm=s7Kb2I73**u+7>ajSMq_*N0D0T>twVG=v7|J@UCi?98 z^_WRbta<1}8D+~kmd-AGZ|^QDQTi&qar>-j;o$JoH8CmON*c8uxJu;1M?JY9XA*8z z+FA4LYlpkYZ~GjwB{PwvpWq|ibTrxNsm;82i)%>?`Kct&mt*`o3=xoL4;A>`Sf#Fr z8n@%>2J3LNFMmfxcS-w`|1_Ou<#FHADp)>^n$W$`EtxK(_NK`_Ox5}}`pV|!M&yX; zNTZT;gJ~U=s%8$N)C;1x6>UG>Q

mZ?6m{Z>o{^YrXO~m#hqF;K?TRsDXl>tXq&}jwc5l~+!|C{gL!11&gmeRIw-hnUe=RoD*cxshEA4K><(o}1V(ykz+WHa zs{JgmwQFtFv=Ysx@ec>zIv1-H`x8A~SutG$b8%9X~YP_ZWg4+Xa5kXIc z`OM?Yzt5Vn@lXDrE5kaOg`j}KGSXL;`@@f+#D@U4Ap z^0idyRckc}|8&}*YD{L)VAd`vpO_JgiCk>$M>gYBB(~j@ z2U%Ck`9e9DBx4nd*Hj6|tX}3Ww}1WKRNG8SR9lY|rEpt?So7VK((7Iqcqp3C5&BVM zZqv@rm}U^RK1dCnoEv%5It}8rqB?wuMB>?IM*ale_eT@$9HP128OlRXvg4s3yviIG zfO_3`j;8k?wulLm`@qBQSgjKC^i@tPkW_ z;NKc4-&bg4y$+Y1j`+~(C69S$sc4;j9%V3Iiknea-!<99t_zaS(@rdQlvYZj8 z^n%$r?G|tXiH+xX&*ADY!yvO?{{}hMgxfGosoJ8=t#8+Yh>Vai;bVGcq(U9|dx2Om zA=5~tO;7COC2B?vX|-(^>-i2IR*wN>=;YqXrCrC*%<7AbdBvZ9!BB7R$QEhwr;@&) zexuAVmEmv~vjjUdPa5h-;)yxsGF`pzHmejQP4|J(Ugy6Pp!xy43;t{~A+`u?y7;7e zCySJ;Bm%TdXeTt+;@jhe*(1icZ*h|T)R-n!iTtMREupR})C!`u>bJrU)MOXXf^u&tBzzNFk6D@dxK zq*y@Xh$hUznQUtXnd%!!pvC`5ScLcngau$?g_KIyX%>Ll z2q;jsx%9i&k+B{Hw?9`7T+`9nLv@_>_V8LAhP9ldQ!3@Az~|T0EpfQLC<(t&KaA5k zQ5_%8)d&Lh$`w9(`FB=_2gK&F@$B`@x`PlA>B%G#Md%Z&VuLvnKCl$WTtyTqvG6a=NeuC8Ikg~_@*in69@C~2 zV(S$JbJWgGU0x&#UM(9d^?KTp=6I;z=k)CRUHQ_x8dVRa^J?OYdzR1#ejzvy3iE&o_+P!Jc)I(jP^0`ODtDm9jmCaSDRjy8)OI``eX+kd0;1ATOa zgW_;oQa7w>r8eywspPJgHaQK1I3;Pd+R~67JtyW)PenrpM2H_1exVhobqH7o@ilpa*uzW((hN za6(SiDwO<)IDF6O0gmtlZ9m{@eVGnI%y~)dbUeh_#O>j`FOW%+ZufmtV87n+>Fs2; zSQw5J&}vX970P}(1Y{LSh;~Ai%YmT@lNClTsh+q9ji&pPQz+`@4SF>i%R*sEykwUXN6K@AOwJ+DtAm!#>31V zcczN0@F@jcsV2mQPH(`(k8QWF*5V6yN_7NK{BcV?)TQ*Z`8|ccRlLZZM z*1{M!DhzM3sD_Dum#3Y#EY--2?g*zF$ospQWeiYG$DS=Gh|Al>4cS(bMN`^*i#_ps z!}b%A;wp3P&q4mg9e_7+&9JT0FQ=52PXERhA7Nkrou#gw;VKH_^|S^jCFsEhmxoP$ z<^AWT^r3uX+_82;00z>=kG1gQIT)U)K;U{{cKQpA(ph-Q@eGhFA$<@Yr3QQSBFq7x zK$-b!lS}2NHM z)6QR|jFwhV39V|`kAAVcSg*%;ou`ouM%ILuh!#4JD=W@BeF73l;#jqt^fN%6|J(2L zB9^c_GcX-MX*6OV8frXtVz`KiX3XsJ&jX8ps+S&?jT0a7oabtplq`yE=wthGdxu@W z*@o{O`-Ts7!St-(=2uY&leE#6d}hoIW1XU@u)jyP+U3P&{^I-Bh5$^A2WOvt$mn+d zJ{lYF#jp^BJ2pH?YITIn1rx-motLJF_F>3;S7 z&t2piZdU%E$r@H^&pn%l=YJ3+h36{Sy?FYM(Rd*#(k`Flgp>i({AFRKCyWRb_Rrzj z?*q#;YI@-M0U1?E9f|g9%iV|D^9o1~Tl(Y82A+2A_IlI5+Ec3;r3s?1fc^$$J|ngDRtp^vRz)|j%OmMnk9oOl4K9` zJ_Z28Wg>}q*yYoEpM2jSf75n+&JhZv(r9$t-q3aj#3#Qi1sC5EwFN&7_5m>%byxFy zlSOq@SxD$JI7iDb(I7ygfT0cyl#w3-=Xbba*2ga5g}*Tyt=E;tKBZBlw5yWkC22YQ ziHalMVy8ghIVP1Y%CctI5^x^eNzJ|al}elW$T%q9t@e)a13JvJg4Z^!a`~oa$>&UC zPGB2+gF9tWtT0run7W~H%eH=V1jqXqw+{DzOx-Yy;WhxWY0Ma)_dhB%8%$&nYVqu- zmhgjZS1ti&2fpZ(vTdi+;_AS$R2L`>Oc>sjGxs6XdXFhfdVpV-*Xvo^oTAc z;@~Dfk7RJ#q|OjPl@%Y(v;jdu3*a~)D5j{|8{wF{Y(9i`(Px99F)86kUH3i8INoe6D#C`D)Ade{ z#=Rk;2yOr0+(>L4pngO@JT_4R{}d?+K3Req%1H2p-gVZ23HYAZxZvE?_}HboNyQe- ze;du@HNp9PsI*hENQ&dT@YhpPlkR^HIR9f)1QWp-Vw$5kW`eIY_!>$8G})g3@;#09 zOYzqn-|XRb!A~y7ON#lDm~w&ZWqbhNQB#T9`{`j}Dh|RC*>uMD#sYGS>!+Gd+k+d# zW(Pe2eC2K5Bpb1ObipMuHwt};CfE5#T!?d8ri`Q|2azDO1bjAA^I@7k;mmQs5@!I=(p6-!A(nqENa=BU z69XUe*On}j>cc3_E)c6FqK*P5#}I6fcnbW>en9zHSsM7AV08CIX&QA#D2@j+&*{9c z4A#-(pSwWnzX4e^}QlyMikQ4jkSup=HmbuOFPer087AELQHhVhv9(Np!n6*+o5}4KbgX5N5 zOXUqVn4B_gdX(Ub0rpDpZX`@$s?BC}|v2?rDTO5U|RpBLteKmUQxo(a-SeH;w8 zGY3onA7S= zV?d;tv?g4zwiysNRU3A{&9doA-#kftLU%-q5THU1@29efc*1@FqO6%RGU6oj!ioMM z8z+r(8m%^wOQO@5cDYrA{E<%~B#4dt#qg$x!Q1xe+UO|SSV-qvSl8Uy3zwYvXv+^imsw?JZUhreoO+AUQp1{xP$7ePLk zP1j>PWs`3po&HFk%73FG99~H?#9L!Bh;uN~3?ydV%_$M>$jJ*2@c?XiLrEA<=Jj6# zp<-<$aDY2N9$2S}mfRNyD?gRGShxB2PXgN?$ovR=w{N?wFbt^DvsvD#C}xI8%@MY_C4f-*V1@*9|8a7_4DhEj&4|2?3^;C?wClKFW85;mEo zj72Ss9U%7G zy?GHt+Hyr(CchyZX0N5O2;;DtiN~S@b`p(};(K3=MP5Jpfp#`Y0pUkpi|n)X7iR)i zvk@YQYo{l6Y~U_RHIlbJuMq}61|Jagb0MQd6aUIc*l>FwVL>zw>6NSortB!7DAp-& zpDk9RE`NPE^%K>Y7({_eBh^CxTln5LzUlF5@sbS1{1KlOWg`qM;_eVh`ezQyu8*;P ziS32Eoaw#nT@lw~mo5yQ78HQX}O0-t~J3opJ;gWAX=tH{zJB9fY^LuXhAE!>6#CO!%p=>%PUI|B+!* zGn~YfrK=MMDJ$ZBP%_{Q!ujwN6wVolPZ8UQ585aVhGs)xLxQls!RM*c!^p#dB+Ols zKjdBp??jP${{f_XVDIsn1t86(&TptO`J>2{a39XcuY%b2RE!+fXP1|NLqcOFTd%v%E$0Rw-d4Dyp?3r4!MNr%$WjgbuU*_tMnIl!Sws zr5W~Zh_u0qQOK4z*ye{{fxLtIYqLGMrMvaw29bbjX_y<&Da~1Vyeb4F#JC>)*_vBQ}B8!NK1PG2f}KMhdf z&5|_k;tn}p9WBl}^Bm(=BGzMAMH?sgi{v^~GP_9_VUQAo=`{nBi(=uk?2Kd zo{2uEMA!(Mq5BLVXpfgJJvX4=mvakqz;{$U_>1aRJyr`q6(jL2WCq&;b>GGLC>gb^ z@ZElACvN%L^w1(0aYe;uWCi2Y`HTH$h=6G(LfM;SPnWl<2sd$5O#l<5N}JUa@J+c} z97$Si#4MykD^wyC+6QEjrZ+kM+g0Ye;2Z|9KgReJLY-kBs2ytASuQcW;>& z^I(l|p4pZ3>z7A2&q`)o{z|DjRr=X`=DHvc@~w?9C(B>AB?53k@52NYG3=>F`;hg( z$pY1^jHQaX1+@VEBww4Vd*o7C;7b7HZ{(K;(wfcBTy_4vvm}&ex1=4Q!Eh>qSWCvs^IP529pG(iWv+GM;}yWiGMl_zGL=RK|85aEs_;=!#jw6TQ0} z3l=|3>64%htIx(9-XFV4qn^-`FrM{3UTT~G_$vSu5~^z+(Jx2E>A(d!&A0-L5-e@p zJ=0nHyK?zV4WrG%x`)!^jy(@3ukUH6j>+gszhv?2Xd$Ik8#Edqvg-|E!I-pmV=@gf`VsMZ|<~|$CFhO&WPZkrq3ZA{uNDw*LD3^$UvbF%x z3~nieJ(x%&U%@UI;Iw^Y-9x1cRAz(wS}T43w`r61j+QhZTFP@CyfO4{+@FlS-BJWk zR8#nkl7;H$Zr(cpd|(AqaW#JGLq1$kvsZQ%2EA(ewii3oA#y%~=ttSd=KTg$Bv{Zz z77&;f)*w>6e=R%I8;+l+gFJ?o#H7as&9sXKm})K(!5_bi-pVM`8{_Cr9*1~Qw(?cq(QHf zM0@U5F5kIf6mAse#j= zCmxL?U7XoQ%;+d5=)=Tpdlbk&2(#kNErjYLmDpMrn9aAC!7Wc?s=>j?Cev!;aE7ey z99hcewuvRHkS~Q3S@;F*Yx#t#nd~!B=t^a-WUhFg}BZ;FvOw-LcI3H9z!=&?a+65Piq%lt3ha419E9$b&+m zuJ3<}jLZ1<8{iW#iL5M0kUQ^#qYD5({t4hl9Ddh6SggnZdehO&qlv(|7Vw`LRzuQE z;B{`ErIs9}6=DsC_i=49>Iwz{6n*DtV=*Q;dcP5V zg=jIz=0hS#2Q1?7S8*ttJrPc~PyQ$`?c=dg@obJr&_(Xc!f;ZFL&EC7%%t;2LSI2J zcdxdO{%nwsEj9-fU^uwyx@*<2Tqrk>VxH>+G+!y}9>w0ux0e+C;2;0Fo0E)*-v`ut2`4_*+3480>F~rT@s{SA& zr_7bcJ2R+#;BC$5pyS`MoQixDOHkgaRN_)cXd}R_OM2;tYKUbkNt^MEXyO`*^6Wd zq45RKRMFjEpUgh;q^2gjiC6oef{`f*PCl`#vV@ti4&YXJ!iuI+6h4ZP$wRDhS6)s@ z*pP2)Q0PTE+=i|O41@i3-;VJ=EJQ^U^AZc%r*iJ?P6297?G zxJ)qi$x^l5!;h4UKz2vn*;Vj>{}r+*NzDTdX>zIa;he&KTRRPFS7-C}$^q?Lf1Hlc zbn(*!zfR*XFc1hlA^$SqI)Z_xZ`Eb7G5pv*6!)6o3Hxl=w2y59msVL)eHew+KLxzo z*!715+mx~z!~RY%Z|4S-OZ>}jRhNlk4HXqpQv@dMo5BFme5e>m8)L1xTNECfw5(!i zg9Wh*&p1knIVVWeugOQ2-*GG0YFeJ^i~2nJ?pBO^cFyZzj{*7$pB*}6IziUEj_D8= zibLx9M===A_OiTxtuV5zhNevqc^HSvG9-f5$US#AcXX^V2b3&B$5E?=i#BMkVz!08woFN zd(%D3A&lno{nWNH?06z4$p^72N5+-`&{Vpw6yYVW!-l_ZRh-IantOoSl+mwUSdpwd zlFA{YTA^M1xchVA#~(Z;T_vV_(w_KCmp z%?2PHO>$HU&<_@3&W;XZageVD9IV_|xN<33o^o}#jyDjXPO;ESBjmCT=iuq+dILv5 zkS5L?M@EI+I;~(PSR6T(Tre{<-x*3_MCIE@V?><0=}@5#&u;CiZ$N*r`k2q0R1k{yaB=;n`*Dr0IIP3 z??($&j7qtpNOJl)1%ddKqOg&LXF7r2#I-#bIHG_h5JYAYUHg>WMAga3^lfqfD>w#H z(__;42FA!G8ra#6XZ&l^mpH^Mg5B9twJ&K-@_^%7T2$_Kz11w^tk0+$>K_sw#5Ln2 z&aNm3EXAwA4iPkRa~9#h8(%X5n038wO>ntw7VD>NVy?nzsKea3I)lMT7FmGyFBuCZu|Lo57k_gG%W7M4-}mp{H5SS2 zv&?l-hl+-)mX`0Co77{M2iKa5(Kp1>F=Uz-3>QTu;G5M#xp2xQyUaP%gH^lKYR_97 zWgDR6@5?=RMd>z#Nw5otcrIHeyvE#U^z6n54F2?_Ko!uo{f3=&wtHzcZ+RwnKkg2V zf8o1Su4P4b?xvf}F~1bbIa8t=5aY6*WBv_{)hb;7U}qwpK6Fzbg9Vk9fe%JRsv_(C zRhrT#)wBrs%b6!TnX6TAjXzvt>+dQCFF{Afqlwx6X{DaVPyVp{*FDDP0zPR*xQ##5 zq3V&>%jS2=VlZN*A;_~eIi7Cav{wMspSKsZH#ps;cmaUOAIgIp)GazLLHydqm8>Qa zs>iU}HziUH=0Djtkk#TCiR#bR-vwXcq5(B0+L^&92e@ur(yQLj?aRjC=N6CcQK#4` z59f?jo}8L$!+%cI7dVhFER%>?UpV;tyB*!+!1bmNayXZ{7e65N#{F18P;vs}0+1p| zR2p1nS`2?v)iLyXhaJd>jpLDpCcf|ZXp{{nM^bxkPjTrEjHnLk3v_m%>z*7e{~d0Y$v^}ykh0HC{^cj%Bz=3`OdRM*y}9A}1kF27J5 z1K_8Y<%Bqe`Y|XA?+J>5(a`%^(ef^F5XLp>_sFY{#fWelnfkd=OhTKJgBnyrSZClK z59R`GRPMnz?fa)SOV!cucc{*Zql6VB--_K6rV?X7T}R zvVL~NDx+7lihM|vpi?2zl~*=Wtzi7DRQ4M(fiwwYQ1n#P=*?Hd_SZOlZRqbtS*UDp zm^A@ig7I)FN6RD`C$IW7so`r>!R{kIq*uWos(&`Pzv>o=?(T>E*#FMB>I+pitbIy+ zlbSI~as2O}sR3YQs-@!JM;DF)z?0yi}%sc>$YaNtIP&+ ztYjlV;l-_){?JK-S4@A^F37>{R=CxC_r<=%*y-P201(LrK=#K=JSkjune3KRlA$;Z zw6O3f(ZJG`2H|7`3fBCO8}u)6k?04QM8U8o4_hnif3_YO{Oi72t`%325AJ_SX;jOS zQ9kghx7=)m1sAuL|M>4`{@;K-2Hwl4B=eKAG^gDP5#2Q~@{#^n26cXVaMSqny?lnY z;i!J`8~*dnCb~wwb;?$MoWwvP17YdXh+m#Wlym~E%GUX)KoXz^`J4xkoj~S@)^k6F zyzcg>GoArUMWzDjgjkq2Z{d#I`!mh}Pr%KI{g+V43${cWC92lYDvxVh$kNOEOm9y~ zgv>LpT)j$|)wmDzg3bZ6j%gKZ)p+e+wiypk_a_TwKaKliD;j|JOdpWwa?o&~Y6oCl(!R65dl`<}3?eo)hD-;Ok?gJp37pAUL z!tCS-Ky@ocIIsqaj96qylAf1F%L7z~2I%C{`8-sCadjn!0SMeFJ~9=gXA73U<0G|}YF#)*&dSU92mpMle<=hb|cyRaX;gY&R`5%(pG<(-U&5Tt6+xH%@`MSfo^jfx-A3U@hyN1%)5(;{>VujiM=`nJgpbax?`Re2RpnQSKa(x~vYENA0LV_UOx{9j4`(Nl z1LNdD+P#NMZnHXyzhwi|4PsnR0msBaw17pxEu1m{88^<7;~?0{AaB*Xm7Z|6Tmd^K zslfIzh*G2{JO(kYbfh=(1I~hGOm6qIi^PzBsf`|^D@@BKdcAYy*{2)%WaX!aD9(hsA@9K*ggDEBCOJUA|-U z>PzbLed{xJtuOH0pZCxfxKnqMT{mPu!6&^;tMh?7JR&%mbrA3=vEH*?B->%Lht&;g z41UcHq62h9A?!o_Ac%$84lIPTzr`Xf9RSt@tUB;enKncs{^D_3C%?$ZetThv0cTJG z;6#YLl@kNBu9CmM?QQiC+OZ2Q#7CO-(g3&#&i zuuLNALwSGATuzLOC?OE=r3cKdx7UM65{ok3r2$AFNuN3MU{WOuJAp2Ws?@8+UUwkA z6tMYXQXM@#;y<^#R3_g$wMH-gTAV6>zn!_vYI|`GJ&uji2K$f7@>1ZjW*7Yk5?gTI z-yxlW*MQp~i=L_{;*ubY#e=)MJfwIoYQdgZikWeC2k6o4kgH2b<<`~Wv@`~Pm#5y1 zq-oxxsQzN2+(ZEwxj*qy_mVGGH4tr|f$t72mT~!hpGej7H1pzUT;VM)4dZj;lK^yL z4wLn&V0LS~H*4xFY!xiC0=A0GS4-U&e_LD&^g%4`=lbRUC}>jS)1UT5iT9-KVALCT?(~;&#yRbAs0?>9{1vH)d;ZQ8QzHHhb=ISnqom!FqEQnzxXPze}3G`cJ-OMh|IJ4}@}P@kUzss!6A@A>Ql<#VurYok8Fsfitj$ zlF38?CCoP>n?^vX{4)4dW5K0Y2LV&_B= zzjUNbV>JoIJ1_b7L_S})**!JdD9Z}(Y}cKt9ME_I*q=~{x^5o0WDtvAYyPd=6^vMZv~X{ZiiL9>NNK=e^f0|ma-yq8U-ae?hN5Wk67flJ>m3q!%RV!fqw&U9sn_LU;KB+A?Wb# zXjWX2R$W{~me<~$Tn5kTy%;&@`_hlyOD?RF5w{b@IF}VY%7a-iiqHJZxmE(-r}X=O zu+s?4pCy#dU!+V3T787Q|1JZ)XQ>nZytiGIDmj$OQIGs~vBlR#qS*lXH81q`30g)r zkp#X7u~r8j=(vdaYi~R|<8O)3h07z(J>(_m0hm-H0@EjGqH* z_1t13&M53VJ{Wb2&sU%Zpgnwz0~3j0d>Y;$g~4P$$GF3}qr6)RAE3ywTTM=}CdOYA zxD%-mBYE4n#|VhirsFP8i0loAHIax)knF?xLq#ZbYnV*ubA5actVby)_nhdW%_~f9#~ZE3bR%73 zV(u6Ce}&1-lx=NFZuO?4yzYlz-)=_H4U};fo=_i+cw}W4pn;kd)2++m%O-Fk#sL@&bSc z95?`cQn|Mjm8*bvOMw?di8RqGtQ|jo;28Q{~mK&g!su6jZhX?_u?AK_vuKU%+OZ_WriA4u`<+fLtQ7VdC<5S<9+? zeTa~H;t3J3ukOkg>(u|S%CmJadil`5T8Lx^2hu#7?0uCk#ADj_V#7WvEdmmn%RTc` zH3tx7aAq79QXm>JEruyToSlKg@JBWckEZ3N#u(wXV$iG|^T!em`;#3K6vaIPsl5d% zR*v!DD|F-_!Q}NI%yY-gZot%iRxG^t+Vi&_d1E9E+oL(aZM}elo82a#_q=ehmi-pd z$erqT@e8Bi!p=N!d=yTExx9N6k-+KLP}Y(L*Mz+{e=`}vE+88s_mHtqo+BE9rD=p( z-T`oE2Z4>c1=s|Sb*%$9IXzR$P44k$3&LdjA}S%7=quGCdE(he_Efmz%Qj=|EU^a= zhWj^L^7)hDVsKqFfCYb+n>?WO=lOuo#!LIp3-WmluONqW>AZWhbPRM4#j~zTnY(b_KB;!vF8vasUr?(PMOyGwD3yGwDWxE3$&?hXqp?(XhzX7{(x zy(c-j$^Ak2L6atPjyc9V9vzQ`LE)!~6wn~!&UYN<9Wgmg(Kn(%>_PuStQH{vcM5au zbiW(vOTU&|rlvDv_P+5NtbF9p(xSQ|E9D&2VLXYQO}nm}QZLwtfLS(j(d`ZG#3U8j zK#zCa@p>vwTTjtHJIp9fE}YvPv47qj5=CC&C|&J7QDVbUo0I0>Depy8MujpFX>ECn~0~T%Yl{+$`ZtV&V?)dif$9E$e2fQv5?lN)?o`_sR!HvfHb7x{M8v_Pnv)bZtSeK-<^ZDY51m%1Q9*xL@wJq>V89KsCZ zfWp%Srt}WJ*PEHji^MhI$YB4}={?K!j&=rgLTaBNoE+91)+OSJE1#Qb$)_nqgG`6F zlk2zuCgQt&kGCDmnIKMxIu#(hBLJHPk@8uAo<qjVX8=UIUZA5T9ymXUMFQ3x9-M*(n6pZhTDF_ zkHM_}`IGdv8GYULnWvLjKh2X>;iiMCr2{Y)uUj!)1gchjQ$*YImEmb-RpZ(J_;+ty zUC6fS4d(SD%%tt*ilQnRWMl9bXKyuXMLGux#7 zTqwbH^?Lttx~Q*TY*8J5wHR&VqdP+p5&6MP_~j=e-ctbJKJ6zsI^C8}AH6D!WZT=H z%$#!*t3lTi@$Bwmr4?D3k`Oj(4V}rZ@lG{eIOH zccv-!a>*#DAB#PRoT4J=RrNIQx#Q2mEGCg$zF3Dc+Of)83Lo2j)Ve2lwN!v}+PPl! zX zn~zH|Bbv3I5OM4CJ?fNSF9WS7YL^R0Hp)N(uJw~rGQQ}MLV=$}enElD0mDGcjm0M} zcFK6Q!mf;QE6WG2UUzOSZi^14-x6dtKn>5*yD}hns>k{is8nqK0)&)XBcaLl;B;;M zAuuA#-I}~bPcN1St-%5Fr^Is$kK08~B~{1xmbK?Yrbq(IEcCjb8QMp4O-*rh7Q}0@ zx<1q_?kss%|5PDfXFxplpSUGJKJ^c(RCxNApe9EQh{y|j4#n7~>&2G^xno|L z=5+jcn)(Dk$ACYpQ+X5mk<>3*c1(WPtecSjT|CYYqgc&@*wA!$!3ob#5A4t z+r~AIUsv?$de7TC9jke2w>#}7&m8(VL=ldPZ@;r4O$^x%jv3D~( z-V+c%7$t^JaH|eoc?9D0vajNIMl#j+FVEuVM)JOt&1;Yuy!4eU@x4uP>dSWbICRDs z>2k@Tu$YBiqUfA=OBPr~;iyBB4JstYB)PETtwvQcblKmXC_>!9*+NZah>h|p2f1F- zGIkI%%B7Zf{IUhlLwQB!CXK|{Q3Lb!0$!V;EH7X2QnAW|giN+T;Frma9P*itMxVcJ z3-RFWK9)@rzupZL8@Ly=O}hht;KP6`Q~LZele0P{mL|JtK_Dmw7id$52ZIuQ+32u4 zf~kJVj3NpNv%eykEDA{s5DF<*X|6f%~M&NePRXdfXUb|0Wm^V9$2`Y6z=tAOe%FEqnY z*upr~N`s~bLD-WIvW)Eo!<=%EBp$?%qT`=qF$tPOo%Sc@Kl7i+w10ccz6JSht) zUn}3;&Hva*v5Th0A?Kcjg>ycab07%Ibw+9O?dGlBtlo@&jj->-ro2zPLoJ06uvliZ zdx>Q$SJC`s_6~q1EfJ##HvO_I#cW{Y!#~GKA-H=95)36VzOKvKt zj|S81>2iwrDidM>f3Ac#j+@9)^=L?Qz%bTSYqTk8g~=ty4YFPt;}4%S9>T9Pb@lF8 zO>&tDsju{I&Bt<8J}<8(3x%T)f(sJAHea$DKO)Swoj-qjeZG@Xtf!%jMD+S&mB3P4 zMhsv{%2zu;Jk%+p4wJey>LKFnI)EpYyN*ADgCxOsM5bx}2GJ*W!CLD6mmMdk96uc6C}P_ZcfDbUa>+Ia}VkS(x2jH;CM~NO8v+BgO!tt69Q^ zxBlb&Z(T*poG5HH_*YGOFMn1yfY?|#&xMaG}0c!!#4j?fgmR4z1vvn^lOi0r#VZ@6Ii4% zul)R^U_*~)1^NpXXC=^SRU|yPBtd^RK@5e;{Ju?enu}qljOtA4ZN=U9B`|!dW4LTX11l`@Ys(>k|$C6o`kdRy=_x}suWeFnlImBX3TGV zT2{VK0-|7K56%V04g|j@pq$ft$yN>FXP__YY>NWJ>6klkPXo+{_@@3Kb)0h6CUFdM zZs;heS`l5Ns!!KpcM+8Au6FJ;r5a6 zpQi4kB2f~Iw*LA8i;*TYk79lu!W3CGhN_gxe8s%W5UU!rZB4I%{`+Y_UEm3UKqN4j za`VaJ^zkS#KvUsGigbl`h(Qm{EZd$9fn@aJejo=Y+qGaD)^cDA`{8w)z$ccD0;To~ z2z(E~>(&UYmWGwWcw1W-OK=#(7SGisfR8$K5 z)=%dXeV(;k-GUcaz)Ic^`S}xC`p~G^bhb(T#vl+*@vv<-5_jKkZE_@}zU=mdQ($R; zx;7tdYD58Hq&r4bfCt4=^p*DG;C4Hy-Q8dB&t@u^wCXdTq#tIIEsx98ymB(~K`EtH zAKKI^a*9=@oweoJKYURUZeI;`EWDD<{y5n>){`kN@+sKUpBp3EZKJj=&i?NeH_^fk@38E@^p+>?U6B;(28!5c%ubd>OQMcUp3Q96UlZ&)m9_XapZdofG zuhPBFCEBj$p=@gQY)glCLh5|=jnyUvDjMnkv7;v^0Mj(?-yi95JNoskSluS&07Fo(T?I3} zilRMR7-~qr!nr*^+%&pmEwQ9Wl#494zF#k$pk}+X(dJ*Sj)O`|G9--i(Kw#e0CNv8>=XcjG#J z4os+ek}!I{3Jw>%d^0%zq&?*HGUmb3cwdaj5#=tWk$`rhAZ{t>Jn z;5Odj#|hxz#~v?GzBSoze%Se5`v>(GX5XuX1yjnwIN}!)fesvpy_V#Y$_gC-E}FTz3vCcK$8LI z2Y>>k(2TGxc?WJ*wQq0glwior+bBty<Gh@fWV4_VkNyk| zCG>xw74SQP#i_vur{t| zNu=3w#Cgf!AC)_50D7H7OFIghPJ2Q4@$<0i2HI=(mA!rG72P_awR*%DCH={uH zdCo&@IHB#b`gcAE_nlA6Qd)mWW1C=j7=3|okUL5>Nct()(LL<1a8N23RGWBmufK zrr&58sq~rXo**1T4zB?Id$${Q8w7=i#HKF1>Ow`CZV5Q$W+*0iKr+fl9bhm}2D@No zoU6*AojfGmwQypi9GhcjK;qA8?vv>0BtZ?Ty|;YllOAT(nMCUI{@ZRH`jYq5JR;*n zSE5z2PQ;fZH5nK$(TqX$_3AC`irI8YgZM0bc+|Fv#K56FB)E}3GJ(@M0N=bCg`vZL zjQ`6yps4z^lUe7k`Jd!I)o8zIE>?2vITA#Yu~;i0hBCsfXOVIR)yyI@&AtaU0eczv zo<;ze@5TrhfU_~MW&oa>v28-&SkCLkK_2U9gVW_iqn+wwq`Sesa!>C_AtAIbsAjLi(vRaaW>|s{|Bx7869{7s)u3$5|3e$FMT)w; zLSfs4^k3P7Kb%Ats&0rBt2QLO39eumGuvdCYY}rnIy`4lMyz&_!y2G$V;}x;wIiJd zI0(TRP2T`=w%j{E?U?+>=nt!f$_jNJe&A*b)CUU#PQs1?GyK?VP5E-svZ8+t*R(UM6u1OGW!q&ar-#>=R?H)f)A;%MZzf1%|ZDTX^M5LD| zs@GY3JzS{D=6kv5Wf7sI!PWS#DGW?%vx(rZEX8s{`Fl<_wB;1}=UN=at1tjixSfXyY%44zSug~`jJBvUw70Exn?VUf2v{}ab zb{EKKtbjA!!c4Y_dpEt_ zo6@jECXEtD!(+GFF{f8nuK}v>tZPtxT`i#Z0FwR3H)1)NX8@Fv1}N8_0*;bKJRqBM zt-Th==Dh#^$mWDM|39)hWuP+punUr>netisgcH%C@6yof#^rdx_HuYW1fm1n{RDub zO9>Dg)BiY{orZM3I+!a<(fh$6a5a{uNPJgqy9DFGS>d z!tB1`54!^>vlOgcNL+mY=QcDtj;}MFjN$*i0`O47_)DdczBHKD{a2@wLt-Gs7{++* zq&J3Y3MfJHkvYV03)0Yx8xG0Ah?ZvHT0)==onj2&-lzfjLMz46L>7P9Fxgguw&U(d z;b@)jyH6UkaY!PqIzw|L>ahpiZ>1_dew#hOls&KEP;&c0M{}%u2+;Iau_KRH|KC}& zBAEWivqB_~lGM2oA^-J&h1o*^p$GCQk6)nD(cqYT{^_rVYGqRxEa~g$G;8|6OuYm( zK=A4l8(1_bt%76`F+AjOEt0W=3b>TU1Dv*1!W57MAkJbsLJkz8#1e2jrj8CS!GMEU z)dq-=fqFAq`6BO&ZdmG$0CS*|#T2+WYq5@teiaosc(~kFZgX>xPv-dqsOB^mo1KbT zht4P=A*e0iViD(L*;D@9lib)QwNrLCQ(~#V+t+hFhN>_rYn}x9TiIX94SW88>`)Vt z4mez43u8^lGNxP{_z-LCWD7{%>Lu`lP&WTXgA5`{0T#k!i=9V5J|J>n-em+ZO6OfW zWDSM#Kw&~H0srT}hUFU9b3OBTlVwSK+x`elFi_Km3sg!EM068CVTv?^3*akuG5>Y$ z2tNGy$p3;wz@>x{2&jx|LpAUdSKxpLE}@Se;HRl4S5~H0K?D561A7O5b0kLf0_(j$ z$~z$580wFFpIl4p(q^yseQ|&HWkoX`Ni0!H|IMZtAvF-B6#khSvyhY~ot;cnI*>d~ z1y2m`_gI<=OX0_~-Pg|Z$Ex#|teK8t&q?RW<{9^_XKvT?_M-NCyNdQZz0O;{$t4CL zC*aZ>_0^Is7sMgW4*>|8Z%hQma4~QJR{r|DtE{qR1ZCi#QL-&i18xt1Et7yp^AwrN zW*IM+!8L8Ias2HYkh=oM2ECn4|0+LIB>#HfB?=T?FX*~v#w@n{C<6*UfbwgT_t$%D zIHRMDx*3H?s$4e^gHF>_LTyurUrzgG2>y%fhf~yQm*kG8nBeyM=^Mjri(xr8*OR}~ ztwO?we&?d zH#M2%+81B~pVNxTBf`>xYuu+9fW73IDl&}(3BD@}8iyEvnrXU4rnlruhkOaDy3T-U zk&x3?Cu`Cax&Y=QTMABCE_99M426H4X_6KUD#c@{-+V7%3ugc}intP$;t@bk^)l#N zUbf*Lal6t_)4NqmCd3bz6C8<~JeVp!;lwh>Ra;DxRtbLtgv^KQoxV*Uqz(X!__X2~ zQ+F>4D3)Rot?7D#mtQ!<#Y4#+)P3zYKLn6;2i}ExKwWh3(<*k`o9gLI5zfPQ*$*H$ z1<<~s3RVx^V;h~)eUm!ZQlLAjh&qeV6b`;PYaM;mED{9lEKy9=-F=)rT)Du>@%B2D z3JHNU-XlgQ_fv@WcY6Ib9z=*Ai4q)|Ul@EmGpb>?@k=)JF!S9lP88f6!}dI}yDAl= zNE9|Up0Y({5`*rN^_N`t5My`tWv<7a1a|G7Wx%~66OR7ns-PR|TpGyop+d|6N>g>4 zw<2h_#*@L$zAu-dK#l}|&mB-EIM%>ZniXa*B~u4Z^)_}0ctIC9A|ZGO0QuD79f7GD zW@;U{3$I#bh9&P_IyikB06`L9=9 z$G#i-3Q!$Bb3I|Q=^m(;=(9Pr{y0v~r*4>38hg+EI7Ive)F@08?aF!^NT_%Ec*lIW z{TK~=1)n+vNjQktP`~iL_`iN4>uOE(3GO#@&LxfV0tV~0kd_u#188&bztxsbPS#Ma z8ok$yuvF5f|HIVT+B`z;sImG_BS*T&SOWDWa4$-st!h(VYOp!3y+-QIGq6A*YeL%8 zhUvlBZ2#vD&VAd$B%9h29|7b3dsVR?;e`Ayjg|Uiuu*!FjRjs7Necqm0;!D44%xF% zbdku~t%|FwHh21UFy0{%H%JB3rSYqn$an#{S+@=o<8Gg)fc#(=dZ4;h`$XS|Ai zOisuH7B>N`R)-rBjK|_z|PHeEUZ>-S}q3g;fe57G-$S?p^?+i1K7zrt4 z%lnG>JgLXr7#JCAUy}GFXR_gW*WV%e2c04Rhkpc86-tS|)AQ60) zubsT*nT1vCV!dli7EktybtWrv7e2gOVPsxv6ag2tqg;@}wM0k@IWZ$Diu`k-&rl98 ztRM>qKND%hk3eqt5II!h%2w7KVgl2bg+w{BpC2K2a1R3x$?l~^1xC8K-KRcwOyXSH z0f*rm88a!@f@oONFT0M#NiOCYRn#5>tXfq$r;E)1%`G4#;p$d-mJJTXH`cLPi=aYg zwt!mK#x!nhzX0seb$a+qA0Oak#JW({IUd$ns5PMe&5a=Mn>f4Pv6Tjk>7J^@(eE~F z{sqDqutqQ?Y8C1C(3tcw{kuOu1hRNFPx;owq!D``0DbgZ@XRlQNO){R<}l_26r#4` zcmA;`H`B3JH}W@CG=LKJO6!|Uv_iJPDu(kvQ@lP`fU`wS?qP_5i&SR-M}{;O1h4~k z42IE@qf&&>QTgTkh*I+9LIb*u=_z7-&rE+WpgWcD3*#nJ=DyR^D!2iM&# z?#IEDaIN{W)gu>zf*6s{gP|Z7om93UqE@r5n%1_l6~K3_^#yfPQm8&sd+l6)9Y@3u zG_QLOh_@YwJ;R=nXQzeF;$0Fr-JRFAlb1>o&~nF0A%L)$&Efy8aPs&kNT@fLb4Qx3 z`vs-8GbiWKBAx&OmAQ0R78D4B1I4;yR?y5l7$i9YY&PfS3(VHtE0JjrKsMRJ0tOT^ zZFwmWr55sO*TT)784KoQhj}sl!%|u#HsjsfZ+kWQ*FPSt=iIkR1Et{>V!w+}Z{1cL z2Ho}5QhCj5HhkfF2%~7im?^Rzur~O6c*UMkU^bG`*&(fu_~_xp&UYQPFyYqOS+8E9?NFcC-oa#n6*5WeOe1{cdg4m95P-wq!FFOR6@9ybc8=W)xbL=(@3VC$xuJBiZCpUP$No*`B(ZQ9Kj@f6B8 zAiOd`ZW9wa%X&Z77l-t$W5@Xm~#pny^nl>7o6+C2N>WAE{&mtwj zr3$ht5%VcejrEr&3quOv2c|2fIvT@_IDNA8N1nUMl)s@rY~&`c!Rgu^VI)8_w)?P7-VRz`nJNh9t%I z%49lmes3u}k4e#$Iy4iF^HO_&ysgxcJH^!qjH*lF{~cB3hJoAX?YRWSpG(4#ph|@! zu==%+u~8Z@vr@exddsbB2`JTu;~xaA!1@eXVm@ShD%JKEKX);=HD~pBUp!lv0>{L`hj^Cy#2~K583njzl+{>#uF#c8 z>KzzF63%N}$2}~P#)znO9th^0uwSwGQlV~D2h29TabW_{OhL{Q&Xey___8aK##9eZ zCdNZ07Us{FE6u{jLvizqV3_MKwdZ=3Ul}JKi2`roxog<8TLAneh@g3|x62y1l#>+C zZO_CD2>RMy5Xjtms@Tmx#=uQas5l6!6f4Xb+5Ccma*K9K7 z3tIVJQDts^h3fcrCt|zXZST<6+HE^z$sN2B5iGFwIEFB|JfQ%UHy1dggT$R3%!?s; z!d+1mJ41YZy8#!9dQO7bh+r~=mijjJD1*QaG9%$ML~{&0jlIsqa$E`$i1t}da|y{X z_5>-e011ZP1h?|q_MfmUs!1eYf(Q<=1Q?=ur;o(WQ|x#o;|~pokY+^`%Eq>L<@QAt zMmY%vkD=CB-sy$iRrK5kIBgL*YN->6O5y|)pp{Jb zTj3*7a+aX+0E(?wCpq3cJD14zp!4-5O`M1Vm#YA8iu&n-E_sKdm7@{)4wt&uSA+ZaWg0_FBIEN?eSD=>JAc6ayIaO-C zp&DUv@z_y5M@0|4p;njUa_K362Wq*}@sF3Pj9G0&LK~LtA^f&5swvRI81pj#UjR$) z2{fu^Ex=!F6UhiMy+rFeKH{1x+~r4RF~WpD`BT6Qrw-Fbu`jv_rVsyO6YN(ENrOIqVlGYWLYJ$ZZym_Y>cBl8oo}xvXxE*EtC~=CS9iJR{)=| zh@GrT0A5C5gpRU>D`Ktg4f91WU^gt}Ls3%qx8He%bAY%dSD+ZD&=*FA)Hq}9%jnjS?+aUPM|JE8NGF!N^qdQm5Gha@}3I$5gU z?!9YgRwt89LIuWJxP^&PKe`u1z%TNi zBy}c6P#pRgVgd0X+L$77HpwKeJu}=s8E8|y@A{vefZ9KRoBU0?E8OekI%B_4XlsVE z?s+idR|kBJ?lJBaC?3%fg@E`iFuLh$|Devt>vU%fYU6>Qm-{_+5hzR*DE)|zR1ai2 z;S59cJ~BSk+!A)4${YB|~vTs(76T?AKGbh(Y zIOWKRGdUdl871(hTkzQ^sGW!}S2U?qo95KtdOjEc!EYrr6C=`)5L^|}HfRRQ$$+|?;5P6Q@Ib+n~_c7G;R8Q7UcgN*7+Hx zvgF~9!WX88O@okM-87H~KzroF*7VsXBvL2j-|6kh5N~oVf{tG}8#OnakZT!cCYnDW zTRqJ~wnuAy|Ggz4Qs&<#9BXOL9)i#o#Qo??Uj$13f*Hudqct8skrF{z0LbCnV&H=a z2E06RvGSQZGCqI=pX-xWMeTn^4}Ssj9^!$B6ec;Qddr!CXEn%AFb9d4&VJDi)H|dC z1AuW2^9+S_GH${chREWF!{ooaM6~^(qUI%{;YHY93PKR+eg2P;dfsa)#Sd4)1zHB_ z0!i9WA`^o_A3#rtE>2oskwj#r=_jgyA}O{L;_1I4Zo-MxNbyE8@o@|q^ZM_LCGEH8 z@1x+R0P zBMwltJlLG%T`@v~%uw~{WFrn>d5c7k9ukG?ufOe$)8G<|MfSeLC+Xt^_5R%!Vpq=S zq%bt4W`mJK^cO?z5+(r}k^6++n3{x6d6IK-p-6&~u};yQT6?H0CWO>#Mey+qQj506 z2=hYrQH?&ZtUY#KE*aDDp;BASZ~A5Pp?*c(;1Uz(O%#CZ8GAInOs}>m9?#&Osp1ji z=DQ9OmJx0c7O`IoKnhoeuWeslRQmB__^i319^is#8>&y zKa+9pAOgfnj(>1EQZtGvtfLI)fWHDS016o*+?%_C#8y&Gg=*>RpL zGp;wZ6kAR^w38nhE@SPbE(ipO1K)(RjFhDbFWV%o?g}svCg3-tL@!O2i14EL8cVRo zT7c`vgetc6ZXxc+I>$$t{Hoqt3B!df1y%yJw*Nfo|2*)|7*I867NwRUG5B?V9uB%s z!Y~C968`+;>{yyQ5q5$eN7{$_w&wfpU8U(iPat>(S<6sIo7XS=nMcy`tKC=FpsyI3 z1thVM5Ehx!ddzcTwBg@sGn`Hcl+93jpkTlae?INtP7-U;#a;kh!fjFV14970$ggkE z=yIj@)-VP`Z`k)H{HAzIzUt0g8g!Aujt8WvIm57gIP z%NwBKg?RmRL|Nq>{FxjTp7@7hzD7ucUgrT{Q+D!baI8=-QVm9@n8j7;BJBc18YX#l zz;hqTP3TJ^7gB*TVL5c-m}LEtNDds9prS)0KYJh0NVR^ z50<=~DAbJfG$|=^3+*bWIg3GfhCn}`;=gP3fBzB^CjFy*v4gmVs(QM5MCp_5Pu0*C z{B26jP-v)&kd>Oib?+vZkRBPLt6~7PL!9s?81nldsuUW;-|>9rLYvP4@Pew`()kim zeHCk|Dyq2%ffftmPyyHjtb?`T&BXUVry31tu&DWbZFeQlRM# z*n>={=mJnU>qe(~azTZY1^WJCqQo)(Oo;FKzTH9CMwtE^p~QZF{63J=?~rsl!*Kzq z=@>?Gq9Vu_AYz_XN~kHxQ>{`D*~RW6V@*ogi!7bXHosG6dn(7%e;xtrsMN@L7dr@u zg>%r;7Sk7Xy&#DEOH-}FO#|&qkRdslvGG_6^5H*{SPbR;h-!rz`d(M-gprZrdN4)O zc#s%0Gp~`lQ&OBIBkis>qyRN_#ZK)8RZfJ^flOM}bwrLHH%owDdAVu9)gP+Dql|lZ zD8$ZhilwS+N;dVNA?Xx3cTJpkARbb@4?p0a0UhEfjx04XPTt?`ObLApdAXcV-M6h%J7qC5WW z)pHXEBvJ(Ujg^}nP3`bfORYy@9Nn^r;ijR235+gcn%O9R#s$n{?pdXxi?nS*B5Xlt zbMvjI)?fZKj*c=zHWQWsizR^8155Qrjpa?t&%_d^L zM*u~PUQNK|=#bz|^T48yYK({iT zkHfmMt;V9`CyrN&*V`hcC9nD)138vy1e>X*62vC+0s?ncwP(1Z<`Qd^DhFId*+BuH zx-4(Y@Y#xWD#CtqleEHB(&NX~WLES898Q~CRLC5Num&D!l!Fj!uO>W&%gw}S)evtU zC3(d(XifD+Ij&~@mzxa?So6mR{hp6>WmK3H!rQ@fnZ$U&4T-`6iWu=PNvA!}PZxy1 z6Cfmf<(WPbYj7kK=zg;UOqNd08|8sg{UmPXkit>56(p!)KzHn2#32cubSlqWrS38% z5X=;L4@e%Fr1ZnAG2uR|^|s%DWxZR2{AgtYu&_E{r+JJE1+&!av~Xg}4r;G~+F4H< zb~gP(J7T0HsUX$f6r8=dBWs(Nhf6K72AhlKF|4>f$R{~CRxe2-Jn2r+RdC~P`*T$P zI%u{}Kg8A8{xnI-c}};GfwTk_0W2>b(5sC{qiH9Qf`!Zf3%8s}uP^x9jz z+UnV5aqHva-kIvXLMmF&)1)$IFQvwy{F&_g{=B|1a9|C4^u z>Hl*k{&&B54C?A!$r*4jSp23G-kSke5%%&~t$MU}7f^SRWpC z=P9ZTDy~(O>3?<1q~plj$yw9p)1Ih`{3Iru9dX>(iK*q2!AMmO0na^f3#*S3bZOiT z*<+cV`jpE&#Jqzqh8HQ2vnruA#5yNIwq~8e4gNk}QT)iKMe&$u0R%)RP(;AsiJ1z+ zr!O6MEb1v0qh#L$86&a7C_rjFkMePh;8l!{;AYKWNhj<^C(NA_8;4#N#(U%2SnL~c!opFXy*vuUWs=n?qd*2YZsd<5Z0R9& zE%C7xHWFLAI2M}JzRzT`ws+Fq|+s$u7I;TtlY($o8d4(RYs4`J3m^kzl^E{(IAPpVlxHl)A+IADo*B>c77tU?3K~ zaxkN08_L+ASRg;j#ZJ2j=fgS)5FBPZj!>sLT)U(|hkP)>&fC$n$9Ml4s~c+=Yb5hK zF2s0*MBy4^55CrSE8ud6+xVvSO5&a-c%+eVAt{W``$u(#y%9IHlh}L!-;VC>fMchO zGu^r_iXfBP-HNqcbBp(&m;yB{$niHK=tuUbYvzi#IS63=O+_9Pb=l>9$)o@)52+E3$zh(9DeI69&JfKWmuPawih{V3S*LQ^S#b%$OOuD^`I&3=5bX= zV(|6;2s1;QULeIH#s0d+W6R6aDB~hHMX)4*z*}zdyJ4EwMSshr$t!lYY;Z(U&-o0} z@d7*smoW7q1!393kYhMHBIDWf^ip5Rapq(=ngutBtzn1| ziLf6u!$TSl#AC1@W%J4~aZ^vhg5aPIf+|=w}ZJKN8nz#I^V9GsK)je zh{rW~@CyI;pXbNn9*%o#Y1}q71Up_^r5QT8$^&Q?)xdLSv>_~6AFv9n&U&5Ik4s9$ zhdA_6_$f4s^{wZ_pbB%>9wOurBdL??#UHqP(f%R2@5jTClb(DtS-R_=8MS<;H4jd>{ z0)`D8Hpp5I2E3Cvc<)=ip0)F3?)nCn=r7Ge? zj(7v9D`d+JwsD%1V<`y5Y6{bsm{mptK!ZZ_3Du?=ydddvl+BMO-NiGl1;*7hdcGOt zyn4Yuf9{exu+S=y2Ch$v&qvC4q@cjB89PUi^j9J$e^LLlh2%Vt1E!65zK~yZudS=Tdb7OG?Mk#fS?K-jU7+Q{7e0qgIVCK+kTx z+*kLB+Pgs4LfOHxLgRf~@Ll?G?`|%pi|+Eg@@_$Xfmss9?%lHO-CpJ<)ceUsYNvb| zmOxg{1mV)q%^(pxWv}zWn1?1;`;J<7+s%tv!2IGNW=s;+_|b@y;$-{;=WVQbRp*y+ z?F`U_dWK7u!;&}1_d(d9rBK9^@dp0(i1W_OVtF-yQ>uswZecNTvupE?&`KGzHSoM$$gJSz&0{K&Mu8iZ}? zPpE7vZKv~auM~VcZPZ`g;`M#{mN?h%AM?kT$UjEFOW&-?b#=9OaLBf@9d>unMmu9P zpnR_QF>6RHeD1B>yRh+_nDxJpi~V?2jL#?Uy~S;pes!W!Ycf%ey9oa7N?WZr*HTEJbR~2s$RrzRay&mip?a`y z-$H16t3tT(w#hcO=3|}oat31-GvTIXwO~o?dfVFn`1f(~S@L=PeN~=@OC@hRUK(yqpmBwKpUXyy&4x+P zYb8zZ^E^5Jdh#yKeES5{(&z~zZXG%r3qXgU& z$Y!#f9z(gKCf^jwq6DnF+pxXY2^AW0f=5`@X2F{%cNOo`)UDs}ru{O{0 z^|;m5W&Hjl!DLj=vtRKuAUu_*Y`fvJBgLo7Z#o~e@}2JhFGJ+jcWX@gcvOwappeFb zCd1S0VbB`A0qUCxiiO}~82p#I&j?@I;X*IKY$vQ;TN?M$kZ}WQ@GM}|5DQH$7>bOc zErz6m;h=k6h(?6{isI)#VsE+s$#}yBpe4|Ud7wxE*d@sTeU^MdDqnHC?~0WE02b$v zDHh!Uqt%#T#}tn9X6LaIj7avk|D6RO`M|tg`A=0g)KC9QYR+nI)!_Dx$qX-h*=4f* zE}r+CXj6IwVplNH0S$F~bDM=lhF*Za# z9kXzhfn|Yb(vq|C`2^#<3Lfc~gn8C!y*YAh{MU2C+?j@MeXW#Vo{!EC`<_m_HNV~I zSj?e_yZ87Wo6bKmje8shn|td=no$Sg{57Hp`-9@%Z15JTd|P+4h|p*G>ido#5Ayj- z^W&I3zBo(&b9DA|&x~V28ST?2li7#R0=4?9t6@oN!b_h#lw%)ReeQ}UTp!=HmHic` z`yNlkG56XF3a7fAt*y?7S#$G^-`B`tTfPkjIx3Zb1I$p*13?*Bm=L(_8};mf zHx+~+P^R(iv0)h&rq*=jZFU%Cgd=pa!rPH!njAT*gPJwlVI7_{5cV#ijFDGAx!i5R z*UkjbfV*DMTK~`ndV0yA++6U1K6S0E4jc$qaLmmNgq@B24?FBfvVo?Q_lXp7x{N3`|lg8|-`Ikt>N)4Olmh$2yJv@Pnv-<)<9J$+j1v@!X`MYP$b06r7N{ivjP zr!YnDYQbe%96K1kH3(r;)aZ}K(;n>F&*DkJ=)d(%*je5(c=M%nNuwa@eV*%vD1F;l zLS7e(I_>&X@x>;?b^_0raEAnQ6NYa`28vnLlR_te@FZR^vj`z?zue<$+V*y&nkdCM zhL=QJ_c2KP29!<^hZiG$qlPeNy6tH_G<3;wp2P{vz^*2@u*bWUk{5TUbL@LRY@g1w zx%vK})8md1xI2#ly*K7i8k+a;#Uytlc`1c8tk@ZkvpSo&diRUPjxXW6wWd7XgrXi2 zBfIJi_Z>K%YqMWVGrSU=zq_V+HT$%4k^t|)>UT{IBc5tD>tK*b#;fsk3FgRvfzAl4b=Y8~8F?<6u zZQHoNZ{d!mNI%ozFnRRxgIm{y8vphXy|u#)SO{NsX`8 z_IWX+5Z*m!Z@e=M7oe#LM35a-kA%Z*+k$u5}RR;O*cXdbikIbYvx6FQCCsYta_ zN3&G5gmil_Cgop=k-*adnL@T5i^YKj_4ZKUR}3PwmjwQ&i`Tc6RNXZfS?tb$wbpDe zdh2=H3x(o)KrePtPv|YDiOYQ_jJpkkUPYG|xTCbgCI|9sRfMmYVnGN3I3=|iBhzeY9qq?=+U?2bY@w#O<~1e%)&pNd_qW(} zy;>SMC7-8ZNn4VzVz%b>vuaoY;o4UIp=4r6WP4G+5WRbb1)1P&lv}~2oe!bcQ46|X z+D5ZdnftAOQxj~29NdS5nD=n}=Y4tCgUXNwJnm*(P1PK2;R>#~7i|EcV{>L>S5GI< z7XiWBnE4k~>a+jWnqK7dtN6U@*XDI+UCKVJyr7hLBfN>h(s=U%GQD2nLDVZ!kMifB zYd|fQ1MP9tTSpOyf30lZ!{dHBpp#GGzx&&Z{Z$FH@Z*^CisHM4 zRHjy8scN~#7g_v?&FA~*&dh;s*{gwwh1~<=Xry&3`u)z6fJp68N$d3#BHhXaZbpVX zv7><)H-rYe^M5S*jGa0O> zQGC*}oN{2-dFLyIzSmotkP?f%fgi8=9ik=phQK$#!lq`Co>5GA}ZtXYA2LpsE!(icinj({u4sE&Re?kk>fSPhbTM_DYf?I|3%naMpgMm z(Yt`8G)Rhsq;yJmw}K+wjda(cySqavmG17A25F>2kZw4{-T3?Gy&vx2gJY-zIOpuW z-?i78^O;@PP|P9Oq7UaZn~zsM8tH0Bu&M!`da(bodktKxwVFl2go^dI6Mp<|B+ zDr$vDktBQ_{7q!S_TipyAJD8sL_e#Qs)>)ob(PP@VsC79V=gDmD=VDg(yyvbS|Cm7 z9W)<7Z0!B4?#{RdOH;kJH8jRP78)+jmC`pmeY`xOi`dYfzvOE?53lpjfV+(Y@NgNa zXdpxea>-9*?S#(`-X>6KLaRY3os3nCetJNBFt5Clq%p`#5qr2}Tn`kF+fK`HsL(;) zcS0cc40Zp`#Za6a8$R6Alj-n^Kx0;N3o_-N6&ILh8Sa-fOX!$x7Knh<6Kf#n1@7R~ zWjtz=3MXp*j50mgMJDD=ZuOpxF@FJY$oo9POnzWUp?k5G-o5Q9%w;!)l*I2^gZmx12Lzk;v zAHTZY1f8a9yg80T>W7jMxCL@_8pHZ6BB7nk4$+r4*2)eL;A5sj?>I&WuMm&&to$e= zPi)QO3E?^+6zparn$9MxvF{yL=Hhf!k(Q9q+CEv%TK`EvJgc*rQd_oz{Ml>9<3cgZ z<#t#K5YkzBxN4A;t3yRa%0+;06mq{MQP#Zce?{3@HHS$Gg(o`2)QiWZHD+qFQ!R3t zKfKMm&}xxd39ZC!rNM)2vVOOn{ZgIjxf~?KglZW{$npMge{rfjT<&q@d>`K-gF|Q7 zcunV{=}}g?m%g8EW4w)k+qkgMR^RgDH>W+jMy<|UcuYKXCHK3uV}4HDsdEk6E(jzn^bN?{p>o#Cr+{Y+mbC`d9~SCHpK1) zugv5IuoOYvygr{WsM1(*u}{-wfXR5K<0$V#Ub4UsYy2KQnV*&A?y_W6}&q>ME@pFQmaV;c-uon`o zM}V?EDm{D{W_%XG+vBKI6M5KB>ZzXh`b)wKJ44eD0%o0rk<1^yEZ@g-+Rh=b7a>E7 zCfmPgG!WvG_&v{?#N`@y5F85avwk>O7nLdT|L|N^Qb%(HQ*iZGf+~t+k=Tj;?fg>N zl^UadJzai!HQru9Av|Y)6hO@naXXurX>nt*QEwl$y50If5VspKWKVB5jrT2}u(}t4 ztTm=(J@Na2{K?SJThe`_+D`K^h;G@)si`!1cGJ&nO6Yst?1atC5o6)@SN|lo`p7Rh z;9u{kC5jjwBlvYkgs@Jsok{U@u?eq#Y?kXL|M>w~oU=T+_bm}GsA5cjLEvj)sWgeb z1bc73Af~44V62(8dey@GNp|&u1=nVyd-+W-q7-`j;;hjEtn35|D@Tj#ACX4aCGj`( z6X9VlC;9k=SC908KM}A?p&S=l+FlunXV5Y5tM_i09<$0;)^i*Fy zsmJ-(wxd%+7O{B~htOHjA8U+OHAfHI7iA^jE>rFvx`7}mpe4gqw`nHtF(R)?b;`rQ z`S2Krv|@%%0IMYG9}sU9YRCv{lPePdBh;^pk}>WC5Um^CjLZ=hlbKqreK6n=^s zZAp32Zx{gV^^C^vJ6}kW(f=N(28)Q2>%(h`=GyFVK6O=cu_$3+gGKB_T@b>UK|6a5 zi#he7qP!=qaEC{x?u~olR&jEAp_!FR1#*dY+lN9yO{dxhM9h8K7-6n@ebJg~PrY}w zdv95({zpslf4)Sjx?dWVP0r0k|1KwJewkPzsAv<`v2*@d;>ZCos;7}gmtmjc73<|v zfdt^~>5sa!?GuE>b~y1>027T{7PMikI4fH3DPC4*M%8-@$AqV@N%TJ_ZU4=N=doGQ zYxdpd;{Gd^qC}`H5O)hC2s&0DBaNv0LwEYwh)uDKNho8D&A(Bkhj=TBw~!{}aCQm^ zv4{9{hhP#w5GbyGyXLGm)bRYwYK0ECu0V7)ZLK#~9~@+dOi@_s-fh|nguSFIv*tyi zd(Ig#E$-KqvoTnzToJJIU7+^iXUu+62zLO zffgkB^X-rKN34~FyK`dM@1v7pWeacS;t{(d-5@;-YumWnr{zGb)>TdpzkcZZ41+FI zwdf-A2@N)!%0^kbGf>{85$6n$_YPBv+*`A6A~xM24>vo8^T`pKChCGO+K8+9WR=$+#m=%Y?XI|Abkb|K72-XEFq@Zk3eHz|6^Qe zt>VM}aE`EElgj~p4oC)!?j1?vkXGW`rFx15d~zRE+5F}M$ck`A-4=B|r$6Mt?N#un zHog!bhMN=5fG1@Tm~kjmv>n3s8+Wpsdy4o(%B6>xKF=Z8|FUAl&|2sLy89zrgs)#f z5Ufg@*NKMvE>MkL!J}|D%<6jH?3{qmkm%yQnG%hS%p}`5aAMMyolCv}8CBj?V3-|U z1AYMouQu2&ZzQ2sTd*AZ9>d!$6>JWH%k_efGv@xa9Xc<4pc)I7@fbaH%#!dFP z*fU|koE~PP713x6=q*q>4 zVMx%!HsQ%IybGk_y6#|c|9)Alnvi6-S!(zUPyCFP zQ;V>JgB4Y-hDWHuanjTXW?(gz9fV8o)~>!DLeHjbhzUlLSOG2*QVa-q6Ye^=NU-Ka zUtyDp$IW(f*?EVMdVJ${pA`LON{vzdRef98z0(Gys=@(+nIF=gMfYN6#WSnnYC<&I zg_^-xBI3XkLjvZO(4!j5X}P}WSAUNT0pc?orcg(u?8jxaA)GGnG}8erdb!)3_!hUe z>#}>%Z2o48xn8zi7mBVp(&;;d__RyeMKxgN)l>IW>?ZGN9Mf;oCxKGSC61Hl=&{{^ zU19?4UNJXlfgD8^A)=mCu)-iKb_EH<=lCHGhSFHAw0Ylu%*~pqHdAf{my#)`kNgq$ zfT~si+By!4*7dSa!s(kvj<-W4DvOk3tipn(#eoFi@pDs%!I{YN%uvn z;Sj03_i`!*riZD0o$l!_`O>CAG#cDU*4;c^l>hGo`6g22*GC@Uf_Puf=GXY%;02;~ z$SW81w^OuU4Y`e9+JV6UnTEtypD>Q>GcDYFzsr19(#Rmeiu? z1}aIwDcG>4ly{-xo=7893JesmBg)n(J6W#Twn%F|L3Tv|{0sLzYUY&~G>~qS_ct&O zctZm@CCKeYg&)1zF+0QS@HZKITr2J$LDJ>J4b@XL?`P}rAGcw&jGwFZ&nBjq!eCyxi^!QTMOe(-3s@hoI9hkITnaD z7X2ze$Z<>AMbX0<34xz5x(tvYT-yxLk3joWmBXotaT8HBJ}bT;0Iux1881h~5BgQT z^=h~{zc?oB`*McZjLQ_+P~xZ7H% zM~Cv-tX_Zn0Fn?)+Bh4qE3QDGrB~IVmptj`aZiA?=QH#`opMV2r_*hz`#2i;K^H(b z_2VOd7mZ1YKV*9zo~+1tIesIw2@jO1xs;@*$+NFyw_oo$cC$9KS(HbBYiL;~de|#2 zufj8%GYiOjN3!|hlly_P1NAs7N7oo?56ZK`E~@L78@<2EbohmR`({!6T`*~~omx1} zLCMh{E{+=r%bae2^^%u2R0zeM6DRTyCx!2@o}NTK<|`Wv-2 z|Hu#+O%NvKb4lJdDtM*+&+$V$AOhpC3%Z$ygW4 zl)z`~Nv!hp&qAzWK3-l^4}>+j2R~+$B;L!KG;XI`dHF2T zvMfxgxpS+^5M=iiZOH&FFlH6VM6{1_qcAmSUVcQYXQVQ$Wm!J!f90Bae)xM)`OnGy zU|@#q9+tiWW`9TE1Nh%0%ySi(;_uB}9EyuuE@>Na%)uoL-^+u|jp;L79Ku>bwGf|- zp|7tg0t*8o0h)GdW%oX-CW%E^!}@b!}^_8K^85UdO>3@VHf!p|}-6mbDvI7S&2jVXy8s|H%HPTf`Uk69hG%eN4#) zm!Ji=mTc_EYUt>UO@>Pr&9CcMGH&zfdXnZ}KNP}ct7`(uq4Xi2!*Rbkykgrz9bz;j3sqLBU^ocZSc zz)cHkV_0%*Mm{p{iVcM{dGHb(5rwqPZ4Tv<7oq)rb7#=XUK{0<*zLyVJ}!ZLW}h|P z=??NjY)0zwtYju-saW(XDld*zN==+QF0TvAr8di$cTF&fAAYoJ0wqQLPlo|Thilfu zvA6;XX}XZiLHhv<(h!-vb^H?)P*N~#B4U4`QA`h93Jj47BAF+0z-6Z}gClWB;H4(K2h|R!Sv*I&?MB5=78SrZ$^Kip9 zieVQsP4zu-P3#^%>ALp{`w*|n+{9Aud3!qJ`cQDgZbI>*>JOCQalRutG|CpnQkr|g zj)Etmc92`$H~}? z4)jLZ=Gcs$Q~QN_p7?>;az{KI2Q};`kB5-5{Zg13tx_@9CQWH~J^HrI*RFP?tiqTh z)mLobozZ+F6xk$}ITRL4$$c+$)Ta<{-q0l53ka27s^p{frH{e-!U=Xm=tXV|Db-(} zH->4FpRLmzc|$imN2uPyH5!!jW_<*oodpJOwbdij&Ts=4z42Vgmw}Y5mR}!rp$Xbt z<0^v>8XEtjvXMmf%XK08bhsR>yAfGR+1O>8W^;`9cE~u#3t20Af*v)wxAOUxxrgat zz%Hj^i&jl*>TZ8O$-%3Y&HBAT#ho(73-egSSnn{YzHdn|r8p1&rSc`L3gkO^) zUEnynkqej2GuLBqOKYn}bI57NQ`Ns(he;7>DP%T|fzXIxThz>ng?t5ROE+s|?ql@w z=dYChxO@|y%uCCX^&gX*)*Q))DqZRt)tb~uEcIJ8xMlM$ko)%`AEaMK24kQOt@ep1 zhIXfYrZs@?Ao_#^es;s^20>(H9gG3F0{f(hr$FNv3>TuZbSa6Din3hd;!XZ-8G zo6$S1Q6Gvb0&^MhTPE6q?#$`)rlnS-d@{a2Id?tev2Q)Rasg#z1nRW)J760V=lo+4 z)I5XYhe1$tFep67X7!plNAFQ0I)qEi$6xm+AsteWONgsx*Oh4g3eM>HtarYsZUY+G zY}$WQanF7S_4>&!W36T+xxP%cR3C)zt-$>H{uny37hXJMS88R%&NgR3u}!9X zLEP?}8ekaxL+Cs+Ifh%q)Sej8C=R1b1567jIuV?_I)oq9H%06*g9)y@5x+h4Z3{p2 z-s`G5`%El2)HsSv{wmkgBR9pm(>IJZ0p7`TlZJ=fc4M+B#oJFy?joUU3owSHux7W& z1En0JJd}%rgde7q#eb|dBXQHwU!(Lez7K=kIg5_3(F8$WbVkW$@j2fKZ3j1`b})$- zJ~w8)=Vpj8>MIDaxV2p7)faDl_enowbp!PasXLi|p^RQ+7_a-WWco04j6k#J(b{f1 z7#UX_*qKr7O*+MR8>%`FqSk00w8%A~>srVL?|Jc%WroqYl)9}mc;LK*CotF+qhIvS zR>VjY>PP2I<9$k;eK0Pf7wKHe$(sJ}z|6&>=s@y5rW9%@??DZKgP;vu$4O09nrtIY zoTEL+#F+De;^St1)+mS7&j;%x^1>$`Bhwk;_;5)zrx{_t^?0T5OW1q@)W+QVZ3Xdr z%=XXb!j*0T9IfX8u!!(`c~SGOW^KFoNttfzVO`2dWqZXKiU@c2-z%=g^S@n+8#jGMSl4r_Xzu*>^w|< zmjsve&GnWTWikS?I$cDP+iu>U6mpxIb_%iwiId)!jI?uCB7`RCh*nhDHMaP-{xW%F z(&Fm1_vEn}?_afli@kipcm!fO2Un02z*7a%!qWv}!{Z1|vwuAQjlec+sHNX)XkR1l zJZaNlQX6f4AP?23`S8(AZ34e9rcU-0`8caDA1mUEs2scOPi_Wpx`n1-@6)+LKC_ah zbuUmDM~cWhmuk5GJBwb}!;?2&v%af}SbXmO%94dWa(Qpd}h^&dve(_`?@GHSi4RBNJ%7(>qxRO zF4SO=)R&hhMrntMm3#Df_dvh5TPDe{@~?yNI@mW}JC>PV&f_Ewm7wmE{d~oog7wb+_ScgZc}8HS#0WpkJsw*GOOb4ULVx-8yhuvk z@1w;;Y=BpXQxRyWk<#8}fmGl*%rf$yncWuU_I)8Dpl)o{Bdn3R))#+9O^fSqekHAw zhWX+|6aD6U5@D&*b4TrxIy55R87gB~Hvr&yik()b(zo0v8Aa7H{iCQ70ppD*L4A+5 zEnaet7AEeNUqMW3T5Dc7o}+Jx{5_cU#J7>cH0zw@`bu;IO*kI#OFGVR&~w2py))xa zo=K!B!x4KZd#Fk1AZYY>zQ(~hNVh6GF|EcLLTlRH864yHZChqKT!p&sQL7@n#?f=Q z-ZJX-xFu7gMWWo^XpeqlHou5dZiT1DQLL84(^2Om#g?5oCb$Q)#sE` zv$;d~KF54NfvgI3!p#S3M_8zhB87G3iHqM`>acrX#LCmz=>kCkGG)8>NRKAJOZXr` z$6Nl9#9Tiye;kYUDA1%kc)8h+fu!ow1!}au27*jFquXaUzN@p}KswjM@_0k{XXGdx zi7?sUw;dupLdNkFG_{%QH9-Rg*ufwv_eIg7+)ZnbgGCZ4vZ3Nf@ z$~B|vJifistV}(kLIG&earzqjNHO02XgB@dMsg7`9LpRvyH#a5W+w=DeH0vKqvsL) zB*0_%(27{uClPLV*@LSbs)fL{kClA|^DrLoeuYOnH?a_~+FOEW5QpIPki??5O!m@7 z12?L2fxw2C+{Ss`|FUT1IjIaZ|B>JsI`n6zhtStYb*TWIfs4|k+^m%^TW zeB5+Emi)o#7>_6h1-lUL1f!0JfC>qtQ_=bi-#mGA94x zA57iD+A~TKLb5&rOM$}bJ!DMg6|TJb7Vko&T_guv{!jgGhM4;F!t-z)EYB6T6Tj=S_ zKtCAP^VH@!Ez2|RZ}8R|kYUQXD<_0E$<+x1O-;*ePSO+PC|IOY)EARONOS%);M+uu zdL3F@B4GfhDtlxNaoH|K-`p&xZ;#L#v6L5UPI3-iE*kO)%Uh5KDy-jco2o1Q)ue!5 z&{*7NlW0dR$A(u&S|DIkzpZ)cD}q!u0`}lS2p!~Xgd5fR<@`lBsu^%RStJe^{rrnBhqEj395w9YI7cmzLSTD zOAOAXDo!z@+H&(1!no8$drNHAebopvK6!cYlHi!KY7I?ZKH2Hs^xCvR@MUQsjU7sxUOc&dE%uOd6d)JqAV$pM7jN9@1%4>#!uS!fBdcS9n}l+FAyQ z>nHqr?JGt6;L5sT>_VW*T|>@>!pZjEed#|vDIH}+#>-)e`lL5MUCm}~z#B>A=Sykf zV&claKC0@I@SHj@IbJt2$msWvM|NZuJVj+v^iLz~f`$95LjC!lqBwt!vog)r4N`Pi zW|-gkmdcJI>qke%@KL%r^wF|>DLG8dc|baIC{3RIpZBz&?~z89Z8(k+mwhgb{JW1$(!b|0q({sAlWZJ=G$8SEvC1w05LrObic zT1?(>Pyq1R%WhNw*T`-=Wlw8qMZnYKgVm`L3*Od#Y<}qHLR$`lvS_4 z%YKGO1Zba6!$TjcSGtyyjb`;vWDG9eUGGioQ3*O5HuQxQue~5s+LbYxD|$A4o~ZH8 z*#utGV{b~1>)+%~=5;QW`tf=aRsh;YQBMkvZjZRXMML2PyNon3_52*If-D#Mr%9!= zt-1q1GCXEL_G?(Y)Dq3)ZF5w?q&$2@>B;A#%D?nnn`Q!A|6+z82_p_R;3z7)g0L^y zC4vcmyG|R8V(cWjgw!FhK;&7e(&V%DHDa=|U{x=k0?H(V9E=ZBs-~hdN#N=FU6tWq zDd_h)%-1qN)Zsf;Fx^Rk1$ifVE6KoTCH?> zxRYKDPVKk}w6C0JdDYqnc->E@oKB~_+?20>91(^t)<1qQKcZ-7*$*R9-Q2S(OW9DS zOIazZJNrM!F5pwAfCoG+u_Tie%YPdfLXiuff@ASH>295veDoS2j7?F#1;>y$SdF+R zm9!eOGx#0G+Gj*FJz$7Yc+y-cMtc!H~Z z!2Q@ww!2I7YmV3LIiXZi0`urTac{W&v|| z+keZeIA_Q81GF8rYUbN+Ec5OjJSpl7qFT~;Vp13(8fwg*ik8#XSY{aVrcbZ>zriT@ zBh~_$&@b77%jU}J-@EYwK9N(kOJ0@@Jp^m27ltm_4LyRY^E}l_F7bUC&gaCz%H)x@ zLQ3WL3BaP^x;c5IvK>l!@BPYqxN?~>7AjX;;{B-8XuFT>u0I(`5}{kON}a}cL*Z_` zmjFx#o-+L|DT5>Rmr1JhAAZ(7?)H=Y1PyGas4)S4ZHx=8%ejraqv>AM{HJ03=JTT9 z4WGHX5p2u9f|ZEh>n5;2>phBBSpTl#%`E$NfM&00J~rw(J*#uPaMX0K#tW1{n|(I* zKNoFFk^!k)D+zS4Z`d|3g9RVd#BD+a+G1RWWQ8opV-zgm%bD^7=NvOVjiyaMB)JRXS`G{bnnqn8 z=SmXKr7)GthK;-X_R3S|n~M~^DueeA`Oh8B*-W|(%u`u1g+E2xA69;oqnqi zz04?o8nQ+YtC&X%I|S63?Fdi+A^ht_E(<8FT?Qqxp3eau8QIcU@)tsqP4M9%+7%q& z*N{fP@hrK!-iWdBy{oQisYn9)9k$OxIg5h<2XE^+@v{Zsen~D4v0!;AE&~tAlhcJ| z|HjO8i0OCPRRZ4QS^Fa;We8d<1tskO0zv)d$&*-Z$?hP@;nzgJF~56~neM1LT$Jl} zquETH9%Pw0sW_Vkw?8Jn>EdM&ZCG|DucE0^1|w4ARnyNw8!@^mWX|Qh-!=_W%if+* zPDjqoOLG_anElp*O$}FnG3JMu$nz(^%g3<#y}b%D%h%euRH;3PwP9C`#cgZ1vz1WbCZ-!UKS(jmqd#0pT)eDN)eMg+5-6)X=f;aO2 zT<;=?h&bkMm#JxUFwz zGW@H)`QcdUHEP&%&O?^l1li@=$X572$8y@*`|Y=039UJ<@S3~139Gt1SJfJQG3?kh z27Fx>u=C!3N3sOIdoLrTY$j5ZB!?Zm^*Xz$;MiWK=pw&4?v6puiE>>(Xthl)UT{t1 zM?||=%adNB3_vcWrOj9j?r>Pht%ZBD-!z9ad~E~111 z%r;A_19ha)P8&Ll-<0s&|M*oJz$pz?T7QOj@VFf0GJYrg=AdR;PrYJT`K{~0FQwZh zhXjGgQ+)X4urP4&WTujXb%7N&CCCM4-#;9vqQG#*arN)HJ0-qlmsgywWn{rIu%qA5^`NW zY182;@hFU1sVOgeUNJ?Tn*1t$|DNz$<-yXIC`K>$GHo}TJiByrexz3)V<8bgXZ@&S4wvgjFEr(n=Yb&ImTOE zXIrjQX3KC7J-4G0Yq#@QlqG?sVPbCCWVgkCm`UgMh83t6P!(`Ie}%f;ip9(`XESlv z(jUiT_JN7^qY~fGD{M;}#dgmBw}XejJ{DQ*Q6h)kzRO&%os0ez%QNT|b20?0yQ8-< zpl%Os_Th+BNXiA({MhUCM6*-kZ0}NIq3y+Vow!+%;B^44KhJWVbp(l*%uGJ~{a1kC zi|y9YS&1R~tLO9Zrbw-f-b!eWyy&BFH|_O=U4kBDo|*gil02!Kant_BfI8kV0^n^b z8&t{DGI2#8cpkM-FZ$fRFZ=71fGLz~EZeyLLjy_~{{0!02&9-8f@VGJ`j} zGN&W-@aNghXyYL3pzy!d*C<9gjw3oW`LA3BY)aN#mG_G5h!e5;UW66sg%jSBvASpP zf-O@3>Ss`yIEpeSJh`BM@H5a&?A2~8)Z6ALT;`wYt2O?*puuT zo!|eJHa2*{z04S+K%)GXWp(gp+L^AG8X_9$n^q`#yzt|7cLu&iy7}UhJEt*0DXu6x z6<_J{d_V1B;UzaeEeZYsG10M8!;hr$+1+a0V~*cfQLl&|?7ZgD_jA&@#1C6M0~N9^ zGHu1{uNrx^-||ym3X9NZYxc&OUU<2QoAG&A_cJ?~EMhn$o^3chNT&SU+;z-<>@aZ1 zrM$3#qNIpJ z#codLSs%+Rw82`5{}ywHAwf1c;b(Gk^~>pViPo6mai7%ADjsyxPqjaiQo?CTnMX2y zIhckQci%&2n6!-3IC6wr*DGxt@*=g}ciop?uqBWee<(=To;vB%u}OOygw_hh;N5Bv z&o9i#ZLVHnT1y&D^W|T9u2(W8zS!p{Qe#Gj-m#KdsMmN}6e!O(VX<-M z4F!hVZiBi6$bZX}onuV_o=N_{dK8fyrZI@lq7UDY!L5XfD3G}NPY*Uw#W|2rEs_r> z3gmeSN!5^yNW1B7Dsy*`aF|9q9V~ogMH;mA>(SidtUQ)HJpegllslO@X=~5&^M^g| z*v$MLvOWkh4Y9nePH1g%P4?^;q&nLcV(8~#|8rW*cP)Q755-73KrXFUD^KjkV4!@- zT|yB0y?aQX`GYE9WM!zxJDX;scW!LHS1XI(zu+q*EIuTC()&BY%eOo}GD{sOol(p` zKx-2Rn`A!gmdk-)l6;YtqKoG>_AzNM`&Tnil;+$ooiV?Fq<*nr}4lPT5T@@d(wZLSKjSOQ&1A*Rx)S<&O zB;*0X%O&}?dyl-S68X%Ac>rVP7_C<_){(Fpin9plHy2)qmPbq_ijYgLXg4yZ_FQgA zz~FoyO^AUGA|jfzv>ulnab(o@_Z6?)WhtZLu2KcY9985I9= z&OcTiV|m^`=DlW7KJ75W%j7-x?F7>uXConI=BGVv=AZ7Sl}YXr6wWb=!nQrNQpuOh zxF&m>NUiwurQR-F)B^j*>}9rAboEZHx=kw!V;2RF8#GE)HJ^N-7oRW*h|M$F$4)cU z%DfQVZ@>2!n9W8*x?Wc;vm>kk^6DSkq_8h*d50-^uXaZbnX<~QDIEz)?M6?Pk5lt_ zxlFb>l(Mvpk2@d^7bZJH@pwnKu4;w)NmJers|zo>0)P9@&I}agKoF6V zGPoOMix^$e({oVhz||>Lp*BWMP}+VG$Z_jG-z=}#j7yW@BSVws^y(gPKP?^8Szh7( z<(1upfL{Cmu{v{&@wMO`6cFIhUPrPbvr>=onC7@aNdBswRew~8;*prLXP%asa-^=# z5^%4gJpl~56opHHEtFe^ujF^p+Ou`F=Lgf%Y1+fb#0DEu=t*x9fV54YCX6*zb6?H6 z3m%8#NA7Cq;}uZ(kTqy*YN+j_&?aNjoI!uwSIA3{z%sE|Qgsg))^ zvd^#H{{A_wbd|1;_5808^h0#aAEZA7DR!IHBpW>_}t4Iis^FUkWab6 z&GWTHn`fvqgk+EFr)XwB zgk?zG?fhN;M6Y~@_D7vlVWm2|ME|~7V?gnP(P=V{W3g8w!<@$Z_eG{^16!Tj!SRHj_)Fn)NocvI&Eh2-aW3`1XMSCXr2oE70qS6FPd zX&GB!{17YadM(NjgN`tkxC!0yC8)3N)yLW(N4XS{izx88ZulfHJ_-KPq7DkOU=>Z%Q8K}2-1?6T1X>ZVU!AIm{9nJ*Q$?GbLsCShkG>8>^D~&go!ck%b-0z3Pe*$@hfJ?U`&yLAwkb{Q_4R^iH+hqTXXVykdJM zz8AGCg~#$*q&%tKc*|3zZ|%4z@(skf$buj4!%_a?>_it-5s@|~aG_lWoP|s~G554p#MX_&91;yLDN>|Gc9^@P z$HVQ~v=@Z zg^c`?<6|_>9-YtMrw+hNcrVpJZL+8^o+Gs3o21A&qZmPN&HLzqWVUV$U<076=R04o zm|>~M6j~^Z7Ou?9__nyIXq>dJiKuZa$uE; z##DGm0*pOD>+?*&=Y zWB#n$K(#(mES_AV1&{mutRwweGTJb>Mpn@7FW~uJ63s>w62hY!<2-Z~D!Qw04`)+w zSxsNmPc`h$v)lY)RSvzcu+DJ(5uNAE+Ick}Zc;voJ5}WN6^)~TuPA4qvu@cb{Ucth zlwo*LkxnUJ2s*_)_Dn3IO)xOX}KD!&1Z4b4E%aiQa0@erseL^8uX7hMTd|5 zX`J47Ye?)jU!a`yv!#Y8UxGFq6eO(prbKGc)o;pjv<{;Egwxqmbbe_EW3~;Y;Gyr_ zMvb0t2mV5T7A}h!eMO9B{=25_YiXvpjXXDl-U5qh?BJ$GNnK>&6oZl#PSxrV`rlX4 zxLp?m^fjrhd2Bo#rFVUAX_?yX5Eo^i`$?6Jso!ruUm45Q@t?o=xmDhX$Cq)SvP@Tm z-OEumpXP9KM-omGqs2yGFH>uF_afr zk0d!gLw^5W@m9?wn|T{`q>xOngWTf*Zky#6|9c&gKf`+G5TO;c^d58)xt_G_#QzI< z-bU_MxMiUkosguL<&%bjOCwXR+uHT4+jvOsEm_+rseK@taA4YUb$b1I1ft#2(P-!B z$*oJf3N^7wss@^~DczDQ(+=`oS+lf9yD8Q?^F#exN6iaHAB$Aqbr$plykTZ$OXr|r zy9Gn!2E_UYa;)qrdnNbOd*N0oCS}M6p4uu?R9hpRjR7`X1RuFr2q2Iga4p!hHYSX% z6fBlb4wf#d*WbSJC(9@_s~vDgU~R377_(YGV{hpCU_Bl?k!?<8cN)p-U{$X~in(Aw z$z9R<5L_aO@^x)kq|UV+mVE~O?KtuGb%k|eeqm?&O#Z4@dl%Q7kGP?jhgPt?#xIMR zT-&~f(Aui+Ce?W)zohc2Jmm1X!g|hAn*&U1N|crX-0!tk)o2}mQ1!xR-8Dyjwq{wc z!8%KAtW-y`CVH~0%|cgSTd>;xeQTX%y2bweNbMI@X6N~UJ?1SA^s>GGN}iEKq&<*@ z3;(Zg&2t#)E5_~Q!xnf$w{3w! z&ewmCx>7}7ct70GPTu-g-)&+qv@@2ev`QU(-ZEW))%4U_%I`xMd3meVU%q`Ern=d% zQGItD)%y7U3ZqfmQjNE>|Lh_2^qQmjd^XKL!}Iw)*%c~2u4+SQpo~r~_e@OB|t{Q(R|$$F3n*`Iv4CiicVmz&EjBN%+w=}%S@r&{wS+70gc zlnZyxBNLEHt?vrNkkj_VMXKhI(Rn8~pp`bk%3-FCdd zRcl1Y;j!S%w6G0A82Su@R~eAGcNXZdwUt%>35vi*2=8+{7_vNz5uuWrkL2gJ=)f7W zrr^I{ml0?7{Tsz{k~xAT?rm8nen40^{=DFO=Tv^sz~UIi_*zm5>ed2k&HvY~(@sXhGkHSj~3L;B4FT~%$`T~PIEM>R_; zy=~((CFp3XMe`MweE9KUBmOw_7Xo(P{~A~RuVD~E zlrOe9g3dD+2v{$4@yIQ=d&Lf?gS7I%xBis#^kgNI1qiC}NV2jekxya_gyryr23Xp1 zUf(rn)kdI}_m2ggS!FwIOGD%rNbn_0 z1ksu`9&{uZSS`!lCtKwXM8t)WH_+>KQT6<+b3GZ=L zxGaAi_dhvf3l%edb|R56KBZ%ns8_yLm^^q@X*dZ~>@30$*LipQYB+ZQlO1>pqH+EV zt*wB*@%C7d;}!T39z`vi^DXYxWA(su7F3>fu1N|-mPoTqu}5nx=(qGAq|e0CmCHup z8kQ+GRz4va&s^RsM-F29V(&?#`5ba$+T8&7MqiPe!fN->xfzKs8DOqN)-ByIC3$jc}D~ zMn=Ht&pRSshy1Y+{KZ_+059Uunx_<#5M_``2xi$ER{@XYD|{~dbmm>&_ZPDeK+L=m z8U!T9e4y1_?n%66C~N2nN!aOoX?s3fYt$dDZ~t}6{vN2v+jGrH4CJEUP!#qzQKR2{ z)I#@r>+2EKC67UyxY6-v&Kox0+!rKjCuRR`B@&vg-yjc^z9^=7F)~Ur3au<&%f-4(x$! zyMXf_8r6mSfZtu^b>r~;Q+c-2;gSY(+qI#x+jrcD)!GCIfYS^80ief}-UxyrU}ax?KM_>$x~#~H?fS*V2`qUUVbLSl$9n_0lA0T zDD+I2h78|irG%&(=A<27pH~@HdF51M+T)-5;WMV3@*vSMefRZMEau=>*qOX|Ir`o^1rWCJ6lRgJ|h6zvF zF}OqUNnN^^Hy`rl0IY2ESz#Ioeyr3V4a=#0v^^Tt^}b!^@jVjuRS1fdrc^9>9zn5uT*dB#%9OUOQ?T`BxIwc zNGPW^glqqPzc#0J21Z7l79Of|+!^h)>E-O;ASW0{ zMW`?lW*qJcAFg!J-7;F?H8BztN0z*$%nKapM7;_^-Ar zZPvT^r?sXSR2YfSDp%*#4!_=53h})y5mVK_4k8Nj1~7C~>TIfW#<$)ixw&6gPi-o0 zNjc5OT?x*Bpu^Z=xzTaQ5E!@+P*2DW@Olp4B-jTWK|G6GkCv%})_2Bo5+vJf&0}3V zQoktxJ({A?kJHL_cdZsJ?{bRwk--Wb&0vAN0A4J5utwj5>wl}kWs4pq(vOSIJDb^o zIX!JakT&Z*+Zl_P$dfKQY25xHIAocU2wP)G@^gm+i5-0Xu=9;5^!o|)C*eR(mJfSz zcXOsnQX}Mj`=UrWhZ$G|5=%-q@j7zw7CHlva0z=ap5O$%tDOO=@=I@v0K-jN%+Cx_ z9B~PsfNlyna#SO^I;Oy;LY=W55QFEoU1o&w`nkW-E?kPG$-FpMcUwZgKnU9fN62A; zJg%TCqM4TIsz_J&(%*>2f9+PI&NQK2txD!u8?lJyhtB+buCPT$_B6Oyhof5k9+2bt z_o$YuoVGrR_Z6CpIgFuE&ci*ls8^8=wm0&3g@L$-3)o+ZMun$5<^Ujn@LUAaO1kcwvmIPz^fs-8<2mVh_*pR=F#eG{+16Gr9QLd0@%uAWQ|D^|(~-sR8jtru zt0|@qQc5$l84||v_ob#I^J8{Da0M*f9@Gy0jj=sFSgfDo&e<9R!HtuxZlA#EkdkPc zJ(WPK9RB|V!UjG02@@uK2YUD(U%h%Y#U&M+)Nj$EMQxH7EqT$KH*ZcB{Ve(K-Mg2@ zOcw2-Y(w}av_NzOKcK7k_vE`WGw5sZ*z>YhSZwO&aUHeEBlqn%%7-&iT+zYTv>K87SQlOc0 ze)0mz9G4H3LAR(^-Z&n|qMS0y*FqLkV1Z`=239hA_wFsMVEW<1hgzy@b{SwKE5xBg zhZgtm-%pbORt7%eTx?nM0NRi^c(m>&5Yp+>r&rAX?c28$?~YrLekDH_-b|STzk&na zXV$D-(BHp*pPJC;%CZE&!*xA~3#bK4tUNq(=FH?$zIyfQIGxiba)7%(g~)_|zAHh( z0FZYPCSc*hg~`%{0)gBSo71Y!Ce`Ev>*l3Pmlos(60_6uB!|c&iiVKI7Q3MU^1YyZ z;ij1BUk->TI&a>*6qnRd?*_i(H{!yNm*INod&d%*RWy>4_hfe{n$n5MF=aQ6pRI}sep84Q zTVtf{N^#Q~D`UWqOae>}VqztY?I;KAib+6#V$LZS?wL`>u{fsakqFJCj;u+W^<14<^jC?v?UeMU`8qm0xM< zfoBcfI)2wZ=XU=N4j5eCxN#%7g6p?)=FBMu3>c7H)!m^!$3;0vUyn%|Fpbp%;7tEC z5$4hsfKQakX=M(02HZ}7T@8uFb67RAb~TX(>`)+>C;;opKC;H-K`c$r5iMW7JjrL) zE94Q2DbI;J;@r7&)3XyZhE+7BORY+chS&Tz>;oOiS_(6S$6|}JDo2!1+_<FIf7K&VIxN!C>4j{eLQ7624uC^F~Pty^g!Bx4>5GhlFgB{G)` zShsFnQdH<$+|@>m7*Wp>;~--z?{lW+bD&Zm%K1KOdX|x= zQkr9+RpL%QmpPC*kU8*&a)8@N+2W(Qml^f3WJ3mBWdO~79FO>A<%w0~S0;{!Wm)V4 zw94D|<@cde-Y<@&#(v_Db&E*}Z7lcI6aU1iVIe36U2Bm6ly=>>ZLU}DiEFJ`Qm)7K z0UoTl8WZ5SK9+(Oqd+ENKgw^AjE^SHCb{CiWy&0AX$}B%S<#Bu#KK13G->mGRU*JH z*Y&WfWl_tuJ=4!|fQuR`$HtmAZCbrG69o%bP6Xft!~}_%h5$Uko?g9rB}){?$PXZ! zAmd_e`XK?_$tPC3ECH^oVNCm=h}?A5DR$vUz;@x?o`2Z&~z;F~YDtibxAIBQS*V_Aa_p@`!?jLI?M zC{W3XIM<%|^DFMPQXkCk_OIZ0?R8QNc_t0V*->MqXW0~ak^!{fWKJ^&G6ymT+7JiC zM{7xn`nW#^7zU&XP%GLBuuJNEd}yR56jDFu4DNtQ(sDh{Iqn#WJmoUcUQ<(Us~tOb zERG#JmQvu-f&~kjTD-;b-MxD^0fO#{YY(dr6DsbStT|YS(5Qz?Pr2cUQ|DNv{7aTB zNh=DmIN{>L`eFC(-Svx5lY{8L+FL3TL5@hDDlhD{vVI$z8lX5m(}! zJ9ie|&)`SMSp6(y2LK(23$V@9d=6CVgZbTVK7U)P1~P*Jk0mP***B9c7RG>Vp+Kti dESn-v{s)}krn~u;KN load-sa [:=> + [:cat string?] + [:or nil? Service-account]]) + +(defn create-bq-client + "Creates a reusable bigquery client. + It uses service account on `sa-path` if provided. + Otherwise uses Application Default Credentials." + [{:keys [sa-path]}] + (if-not sa-path + (-> (BigQueryOptions/getDefaultInstance) .getService) + (let [credentials (load-sa sa-path)] + (-> (BigQueryOptions/newBuilder) + (.setCredentials credentials) + .build + .getService)))) + +(def Bq-client + [:fn #(= (type %) com.google.cloud.bigquery.BigQueryImpl)]) + +(m/=> create-bq-client [:=> + [:cat Config] + Bq-client]) + +(defn job->destination-table + "Returns destination table found in bigquery `job`." + [^com.google.cloud.bigquery.Job job] + (let [{:keys [project dataset table]} + (-> (.getConfiguration job) + bean + :destinationTable + bean)] + (format "`%s.%s.%s`" project dataset table))) + +(def Bq-job [:fn #(= (type %) com.google.cloud.bigquery.Job)]) + +(def Destination-table [:re #"\`.*?\..*?\..*\`"]) + +(m/=> job->destination-table [:=> + [:cat Bq-job] + Destination-table]) + +(defn job->results-map + "Takes bigquery `job` and returns its 'destination table'." + [^com.google.cloud.bigquery.Job job] + (-> (.getConfiguration job) + bean + :destinationTable + bean)) + +(def Result-map [:map + [:project string?] + [:dataset string?] + [:table string?]]) + + +(m/=> job->results-map [:=> + [:cat Bq-job] + Result-map]) + +(defn create-query-conf + "Creates bigquery configuration that will be used in a job." + [query-sql query-name] + (-> (QueryJobConfiguration/newBuilder query-sql) + (.setLabels (ImmutableMap/of "query-name" query-name)) + .build)) + +(def Query-conf [:fn #(= (type %) com.google.cloud.bigquery.QueryJobConfiguration)]) + +(m/=> create-query-conf [:=> + [:cat string? string?] + Query-conf]) + +(defn create-job-id + "Create bigquery job-id that will be used in a job." + [job-name dataset-location] + (-> (JobId/newBuilder) + (.setLocation dataset-location) + (.setJob job-name) + .build)) + +(def Job-id [:fn #(= (type %) com.google.cloud.bigquery.AutoValue_JobId)]) + +(m/=> create-job-id [:=> + [:cat string? string?] + Job-id]) + +(defn query->table + "Sends `query-sql` via `bq-client` and sets `query-name` so it can be identified in bigquery history." + [^com.google.cloud.bigquery.BigQueryImpl bq-client query-name query-sql location] + (let [query-config (create-query-conf query-sql query-name) + job-name (format "jobId_%s" (rand-str 12)) + job-id (create-job-id job-name location) + job-info (JobInfo/of job-id query-config)] + (.create bq-client job-info (into-array BigQuery$JobOption [])))) + +(m/=> query->table [:=> + [:cat Bq-client string? string? string?] + Bq-job]) + +(defn job-result->gcs + "Takes `job-result-map` and extracts result via `bq-client` to `gcs-uri`." + [^com.google.cloud.bigquery.BigQueryImpl bq-client job-result-map gcs-uri] + (let [{:keys [project dataset table]} job-result-map + destination-uri (str gcs-uri "/" table "*.gz") + table-id (TableId/of project dataset table) + extract-config (-> (ExtractJobConfiguration/newBuilder table-id destination-uri) + (.setCompression "gzip") + (.setFormat "CSV") + .build) + job-info (JobInfo/of extract-config)] + (.create bq-client job-info (into-array BigQuery$JobOption [])))) + +(m/=> job-result->gcs [:=> + [:cat Bq-client Result-map string?] + Bq-job]) + +(defn run-and-wait! + "Runs provided `bq-job` and waits for its results." + [^com.google.cloud.bigquery.Job bq-job] + (.waitFor bq-job (into-array RetryOption []))) + +(m/=> run-and-wait! [:=> + [:cat Bq-job] + Bq-job]) + +(defn bq-run-query! + "Runs provided `query` as 'bq-job' via `bq-client` as `job-name`." + [^com.google.cloud.bigquery.BigQueryImpl bq-client job-name query location] + (-> (query->table bq-client job-name query location) + run-and-wait! + job->results-map)) + +(m/=> bq-run-query! [:=> + [:cat Bq-client string? string? string?] + Result-map]) + +(defn bq-query->gcs! + "Runs and extracts `query` as gzipped csv to `gcs-uri` via `bq-client` as `job-name`." + [^com.google.cloud.bigquery.BigQueryImpl bq-client job-name query location gcs-uri] + (try (let [job-result (bq-run-query! bq-client job-name query location)] + (-> (job-result->gcs bq-client job-result gcs-uri) + run-and-wait!)) + (catch com.google.cloud.bigquery.BigQueryException e + (timbre/error (-> (bean e) :message))))) + +(m/=> bq-query->gcs! [:=> + [:cat Bq-client string? string? string? string?] + [:or Bq-job nil?]]) diff --git a/src/bq2pg/config.clj b/src/bq2pg/config.clj new file mode 100644 index 0000000..e80777e --- /dev/null +++ b/src/bq2pg/config.clj @@ -0,0 +1,167 @@ +(ns bq2pg.config + (:require + [bq2pg.utils :as utils] + [clojure.string :as string] + [cprop.core :refer [load-config]] + [babashka.fs :as fs] + [malli.core :as m] + [malli.error :as me] + [taoensso.timbre :as timbre])) + + +(def Ne-string + [:and string? [:fn not-empty]]) + +(def Db-conf + [:map + [:dbtype Ne-string] + [:dbname Ne-string] + [:user Ne-string] + [:host Ne-string] + [:port [:or int? string?]]]) + +(def Method + [:enum "append" "replace"]) + +(def Table-name + [:re #".*\..*"]) + +(def Location + [:enum "us-central1" "us-west4" "us-west2" "northamerica-northeast1" "us-east4" "us-west1" "us-west3" "southamerica-east1" "southamerica-west1" "us-east1" "northamerica-northeast2" + "europe-west1" "europe-north1" "europe-west3" "europe-west2" "europe-west4" "europe-central2" "europe-west6" "asia-south2" "asia-east2" "asia-southeast2" "australia-southeast2" + "asia-south1" "asia-northeast2" "asia-northeast3" "asia-southeast1" "australia-southeast1" "asia-east1" "asia-northeast1" "EU" "US"]) + +(def Integration + [:map + [:name Ne-string] + [:query Ne-string] + [:location Location] + [:target-pg-table Table-name] + [:method Method] + [:timeout int?]]) + +(def Config + [:map + [:gcs-name Ne-string] + [:gcs-folder Ne-string] + [:db Db-conf] + [:export? boolean?] + [:import? boolean?] + [:integrations [:vector Integration]] + [:sa-path {:optional true} Ne-string]]) + +;; todo - simplify config - no nested maps +(def CONFIG nil) + +(defn- set-config! + "Alters global variable CONFIG by provided `config`." + [config] + (alter-var-root + (var CONFIG) + (constantly config))) + + +(defn- exit + "Exits with provided `code`,`template` and `& args`." + [code template & args] + (let [out (if (zero? code) *out* *err*)] + (binding [*out* out] + (println (apply format template args)))) + (System/exit code)) + + +(defn coerce-config + "Checks and returns provided `config`." + [config] + (cond + (m/validate Config config) + config + :else (let [report (m/explain Config config)] + (exit 1 "%s" (me/humanize report))))) + + +(m/=> coerce-config [:=> + [:cat Config] + Config]) + + +(defn parse-pgpass-pwd + "Retuns pgpass password if there exist same host, port, db and user config. " + [s host port db user] + (let [[chost cport cdb cuser cpwd] (string/split s #":")] + (when (and (= host chost) (= port cport) (= db cdb) (= user cuser)) + cpwd))) + +(defn load-db-pwd [host port db user] + (if-let [dbpwd (System/getenv "PGPASSWORD")] + dbpwd + (if-let [pgpass (slurp + (fs/file + (System/getProperty "user.home") + ".pgpass"))] + (let [creds (string/split pgpass #"\n")] + (some #(parse-pgpass-pwd % host port db user) creds)) + (timbre/warn "DB pwd not found in ~/.pgpass or $PGPASSWORD env var.")))) + +(defn load-env + "Loads various environment variables and removes any nil values. " + [] + (utils/remove-empty-vals + {:proxy-host (System/getenv "PROXYHOST") + :proxy-user (System/getenv "PROXYUSER") + :proxy-password (System/getenv "PROXYPASSWORD") + :export? (Boolean/valueOf (if-let [export? (System/getenv "BQEXPORT")] + export? "true")) + :import? (Boolean/valueOf (if-let [import? (System/getenv "PGIMPORT")] + import? "true")) + :gcs-name (System/getenv "GCSNAME") + :gcs-folder (System/getenv "GCSFOLDER") + :db {:dbtype "postgres" + :host (System/getenv "PGHOST") + :dbname (System/getenv "PGDATABASE") + :port (System/getenv "PGPORT") + :user (System/getenv "PGUSER") + :password (load-db-pwd (System/getenv "PGHOST") + (System/getenv "PGPORT") + (System/getenv "PGDATABASE") + (System/getenv "PGUSER"))} + :sa-path (System/getenv "BQ2PGSA")})) + + +(defn- fake-exit + "Like exit.. but without exiting REPL." + [_ template & args] + (let [message (apply format template args)] + (throw (new Exception ^String message)))) + +(defn load-config! + "Validates and loads CONFIG on `filepath`." + [{filepath :filepath extra :extra}] + (try + (-> (load-config :file filepath :merge [(load-env) extra]) + (coerce-config) + (set-config!)) + (catch Exception e + (timbre/debug e) + (timbre/error "Wrong configuration file provided!")))) + +(m/=> load-config! [:=> + [:cat + [:map + [:filepath string?] + [:extra {:optional true} + [:map + [:export? {:optional true} boolean?] + [:import? {:optional true} boolean?] + [:gcs-name {:optional true} string?] + [:gcs-folder {:optional true} string?] + [:db {:optional true} Db-conf] + [:intregations {:optional true} [:vector Integration]] + [:sa-path {:optional true} Ne-string]]]]] + [:or Config nil?]]) + +(defn load-config-repl! + "Validates and loads CONFIG on `filepath` - uses fake exit." + [config-map] + (with-redefs [exit fake-exit] + (load-config! config-map))) diff --git a/src/bq2pg/core.clj b/src/bq2pg/core.clj new file mode 100644 index 0000000..3271fe9 --- /dev/null +++ b/src/bq2pg/core.clj @@ -0,0 +1,15 @@ +(ns bq2pg.core + (:require + [bq2pg.bq :refer [create-bq-client]] + [bq2pg.config :refer [CONFIG load-config!]] + [bq2pg.gcs :refer [create-gcs-client]] + [bq2pg.integration :refer [integrate!]] + [bq2pg.proxy :refer [set-proxy!]]) + (:gen-class)) + +(defn -main [& args] + (load-config! {:filepath (first args)}) + (let [gcs-client (create-gcs-client CONFIG) + bq-client (create-bq-client CONFIG)] + (set-proxy! CONFIG) + (integrate! gcs-client bq-client CONFIG))) diff --git a/src/bq2pg/db.clj b/src/bq2pg/db.clj new file mode 100644 index 0000000..f26d87c --- /dev/null +++ b/src/bq2pg/db.clj @@ -0,0 +1,161 @@ +(ns bq2pg.db + (:require + [clojure.string :as str] + [clojure.java.io :as io] + [next.jdbc :as jdbc] + [next.jdbc.date-time] + [clojure.data.csv :as csv] + [bq2pg.config :refer [Table-name]] + [malli.core :as m] + [taoensso.timbre :as timbre] + [next.jdbc.types + :as types])) + +(defn connectable? + "Returns true if `conn` can be used by JDBC to initialize connection + otherwise returns false. + `Conn` can be map or 'org.postgresql.jdbc.PgConnection'" + [conn] + (or (map? conn) + (= (type conn) + org.postgresql.jdbc.PgConnection))) + +(def Connectable [:fn connectable?]) + +(defn- get-type + "Gets Postgresql type for selected `column-name` in `table` with jdbc based on `connectable`." + [connectable table-name column-name] + (let [query "SELECT data_type FROM information_schema.columns where table_schema = '%s'and table_name = '%s' and upper(column_name) = '%s'" + [schema table] (str/split (name table-name) #"\.") + col-name (str/upper-case column-name)] + (:columns/data_type (jdbc/execute-one! + connectable + [(format query schema table col-name)])))) + +(m/=> get-type [:=> + [:cat Connectable Table-name string?] + [:enum "bool" "bit" "int8" "bigserial" "oid" "bytea" "char" "bpchar" "numeric" "int4" "serial" "int2" "smallserial" + "float4" "float8" "money" "name" "text" "character varying" "varchar" "date" "time" "timetz" "timestamp" "timestampz"]]) + +(defn convert-type + "Convert Postgresql `type` to conversion function" + [type] + (case type + ("bool" "bit") #(types/as-bit %) + ("int8" "bigserial" "oid") #(types/as-bigint %) + "bytea" #(types/as-binary %) + ("char" "bpchar") #(types/as-char %) + "numeric" #(types/as-numeric %) + ("int4" "serial") #(types/as-integer %) + ("int2" "smallserial") #(types/as-smallint %) + "float4" #(types/as-real %) + ("float8" "money") #(types/as-double) + ("name", "text", "character varying", "varchar") #(types/as-varchar %) + "date" #(try (.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") %) + (catch Exception _ nil)) + ("time", "timetz") #(try (types/as-time %) + (catch Exception _ nil)) + ("timestamp", "timestampz") #(try (types/as-timestamp %) + (catch Exception _ nil)) + #(types/as-other %))) + +(m/=> convert-type [:=> + [:cat [:enum "bool" "bit" "int8" "bigserial" "oid" "bytea" "char" "bpchar" "numeric" "int4" "serial" "int2" "smallserial" + "float4" "float8" "money" "name" "text" "character varying" "varchar" "date" "time" "timetz" "timestamp" "timestampz"]] + fn?]) + +(def Header [:vector string?]) + +(defn- get-conv-fns + "Takes `header` and maps every column in `table` to matched conversion functions." + [connectable table-name header] + (mapv #(convert-type (get-type connectable table-name %)) header)) + +(m/=> get-conv-fns [:=> + [:cat Connectable Table-name Header] + vector?]) + +(defn- build-query + "Takes `table` and `header` and build sql query template for next.jdbc" + [table header] + (let [cols (str/join "," (map #(format "\"%s\"" %) header)) + placeholders (str/join "," (for [_ header] "?")) + query (format "insert into %s (%s) values (%s)" (name table) cols placeholders)] + query)) + +(m/=> build-query [:=> + [:cat Table-name Header] + string?]) + +(defn- get-header + "Takes first row from `coll` as a header + which is splitted on a `delimiter`. " + [coll delimiter] + (->> (str/split (first coll) + (re-pattern delimiter)) + (mapv str))) + +(m/=> get-header [:=> + [:cat [:sequential string?] string?] + Header]) + +(defn truncate-table! + "Tries to reuse or create jdbc connection based on `connectable` and truncate `table`. + `Connectable` can be map or `org.postgresql.jdbc.PgConnection. + `Table` is a string in 'schema.table' form." + [connectable table-name] + (try + (jdbc/execute! connectable [(format "truncate table %s;" (name table-name))]) + (timbre/info (format "Table: %s truncated!" table-name)) + (catch Exception _ + (timbre/warn (format "Table: %s can't be truncated!" table-name)) + ))) + +(m/=> truncate-table! [:=> + [:cat Connectable Table-name] + any?]) + +(defn table-exists? + "Checks if `table` exists in db with jdbc based on `connectable`." + [connectable table-name] + (let [[schema table] (str/split table-name #"\.") + query (format "select tablename from pg_tables where schemaname='%s' and tablename='%s';" schema table)] + (-> (jdbc/execute! connectable [query]) + seq))) + +(m/=> table-exists? [:=> + [:cat Connectable Table-name] + [:or seq? nil?]]) + +(defn create-table! [con table-name table-header] + (let [header (str/join " text," (map #(format "\"%s\"" %) table-header)) + + query (format "CREATE TABLE %s (%s text);" table-name header)] + (timbre/info query ) + (jdbc/execute! con [query]))) + +(defn insert-csv-from-stdin! + "Inserts csv from `stdin` parsed with `delimiter` to `table` via next.jdbc `con`." + [stdin con table-name delimiter] + (with-open [reader (io/reader stdin)] + (let [lines (line-seq reader) + table-header (get-header lines delimiter)] + (when-not (table-exists? con table-name) + (create-table! con table-name table-header)) + (doall + (let [query (build-query table-name table-header) + conv-fns (get-conv-fns con table-name table-header)] + (doseq [batch (partition-all 100000 (rest lines))] + (try + (jdbc/execute-batch! con query + (->> batch + (mapcat csv/read-csv) + (mapv (fn [row] (map #(%1 %2) conv-fns row)))) + {:reWriteBatchedInserts true}) + (catch Exception e + (timbre/debug e)) + ))))))) + +(m/=> insert-csv-from-stdin! [:=> + [:cat any? Connectable Table-name string?] + [:or seq? nil?]]) diff --git a/src/bq2pg/gcs.clj b/src/bq2pg/gcs.clj new file mode 100644 index 0000000..47a9b8a --- /dev/null +++ b/src/bq2pg/gcs.clj @@ -0,0 +1,107 @@ +(ns bq2pg.gcs + (:require + [taoensso.timbre :as timbre] + ;; [bq2pg.config :refer ] + [clojure.string :as str] + [clj-gcloud.storage :as st] + [clj-gcloud.coerce :as cr] + [clj-time.coerce :as tc] + [babashka.fs :as fs] + [malli.core :as m])) + +(def Gcs-client + [:fn #(= (type %) com.google.cloud.storage.StorageImpl)]) + +(def Gcs-uri + [:re #"gs:\/\/.*"]) + +(def Gzip-uri + [:re #"gs:\/\/.*\.gz"]) + +(def Gzip-uris + [:and + [:not empty?] + [:sequential Gzip-uri]]) + +(defn create-gcs-client + "Creates a reusable google cloud storage client. + It uses GOOGLE_APPLICATION_CREDENTIALS if no SA provided. + You can set this by running 'gcloud auth application-default login'" + [{:keys [sa-path]}] + (if-not sa-path + (st/init {}) + (st/init {:credentials sa-path}))) + +(m/=> create-gcs-client [:=> + [:cat [:or map? nil?]] + Gcs-client]) + +(defn list-gzip-uris + "Returns coll of GCS blobs in gs-uri" + [storage-client gcs-uri] + (->> (st/ls storage-client gcs-uri {}) + (filter #(str/ends-with? (.getName %) ".gz")) + (map #(format "gs://%s/%s" + (.getBucket %) + (.getName %))))) + +(m/=> list-gzip-uris [:=> + [:cat Gcs-client Gcs-uri] + Gzip-uris]) + +(defn- gcs-uri->temp-uri + "Returns temporary path for file on `gcs-uri`." + [gcs-uri] + (->> (fs/file-name gcs-uri) + (fs/file (fs/temp-dir)) + .toString)) + +(m/=> gcs-uri->temp-uri [:=> + [:cat Gcs-uri] + string?]) + +(defn download-blob! + [storage-client gcs-uri] + (let [target-path (gcs-uri->temp-uri gcs-uri)] + (st/download-file-from-storage storage-client + gcs-uri + target-path) + target-path)) + +(m/=> download-blob! [:=> + [:cat Gcs-client Gcs-uri] + string?]) +;; todo - move this try catch otusdie as download-blob etc. should be also checked and +(defn delete-folder! + [storage-client gcs-uri] + (doseq [blob (st/ls storage-client gcs-uri)] + (let [{:keys [blob-id]} (cr/->clj blob) + path (format "gs://%s/%s" (:bucket blob-id) (:name blob-id))] + (timbre/info (format "Deleting blob on: %s" path)) + (st/delete-blob storage-client (st/->blob-id path))))) + +(m/=> delete-folder! [:=> + [:cat Gcs-client Gcs-uri] + any?]) + +(defn create-empty-blob [storage-client gcs-uri] + (st/create-blob storage-client (st/blob-info (st/->blob-id gcs-uri) {}))) + +(m/=> create-empty-blob [:=> + [:cat Gcs-client Gcs-uri] + any?]) + +(defn get-blob-moddate [storage-client blob-uri] + (try (->> (st/->blob-id blob-uri) + (st/get-blob storage-client) + .getCreateTime + tc/from-long) + (catch Exception e + (timbre/error e) + nil))) + + (m/=> get-blob-moddate [:=> + [:cat Gcs-client Gcs-uri] + [:or + [:fn #(= (type %) org.joda.time.DateTime)] + nil?]]) diff --git a/src/bq2pg/integration.clj b/src/bq2pg/integration.clj new file mode 100644 index 0000000..7abf0b2 --- /dev/null +++ b/src/bq2pg/integration.clj @@ -0,0 +1,127 @@ +(ns bq2pg.integration + (:require + [bq2pg.db :as db :refer [Connectable]] + [bq2pg.gcs :as gcs :refer [Gcs-uri Gzip-uris Gcs-client]] + [bq2pg.config :refer [Method Config Integration]] + [bq2pg.bq :as bq :refer [Bq-client]] + [clj-time.coerce :as tc] + [bq2pg.utils :refer [gcs-directory + update-local-state + read-last-state + before? + interval>]] + [babashka.fs :as fs] + [malli.core :as m] + [taoensso.timbre :as timbre] + [clojure.java.io :as io] + [next.jdbc :as jdbc])) + +(defn stream-gzip-to-db! + "Streams content of GZIPPED csv into table in CONNECTABLE." + [gzip-path delimiter con table-name] + (with-open [in (-> gzip-path + io/input-stream + java.util.zip.GZIPInputStream. + java.io.InputStreamReader. + java.io.BufferedReader.)] + (timbre/info (format "Streaming %s to %s" gzip-path table-name)) + (db/insert-csv-from-stdin! in con table-name delimiter))) + +(m/=> stream-gzip-to-db! [:=> + [:cat string? string? Connectable string?] + any?]) + +(defn stream-gcs-uri-to-db! + "Downloads and streams all GZIPPED files in GCS-FOLDER into table in CONNECTABLE. + It can truncate table or append data - based on selected method which is 'append' or 'replace'." + [gcs-client connectable gcs-folder-uri target-pg-table method] + (let [gzip-uris (gcs/list-gzip-uris gcs-client gcs-folder-uri) + table-exists? (db/table-exists? connectable target-pg-table)] + (if (m/validate Gzip-uris gzip-uris) + (try (jdbc/with-transaction [con (jdbc/get-connection connectable)] + (when (and table-exists? (= method "replace")) + (db/truncate-table! con target-pg-table)) + (doseq [uri gzip-uris] + (timbre/info (format "Downloading file from: %s" uri)) + (let [blob (gcs/download-blob! gcs-client uri)] + (stream-gzip-to-db! blob "," con target-pg-table) + (timbre/info "Gzip has been loaded into DB") + (fs/delete-if-exists blob))) + (timbre/info "Job finished!")) + (catch org.postgresql.util.PSQLException e + (prn e))) + (timbre/warn (format "No files in %s - nothing to integrate!" gcs-folder-uri))))) + +(m/=> stream-gcs-uri-to-db! [:=> + [:cat Gcs-client Connectable Gcs-uri string? Method] + any?]) + +(defn export! + "Exports compressed Bigquery data defined in integration to GCS defined in CONFIG." + [gcs-client bq-client gcs-name gcs-folder integration] + (let [{:keys [name query location]} integration + gcs-uri (gcs-directory gcs-name gcs-folder name) + gcs-state-uri (gcs-directory gcs-name gcs-folder name "EXPORTED")] + (try + (gcs/delete-folder! gcs-client gcs-uri) + (timbre/info (format "Exporting BQ result of following query: %s" query)) + (if (bq/bq-query->gcs! bq-client name query location gcs-uri) + (do (gcs/create-empty-blob gcs-client gcs-state-uri) + {:status 1}) + {:status 0}) + (catch com.google.cloud.storage.StorageException e + (timbre/fatal e) + (System/exit 0))))) + +(def Status [:map [:status [:enum 0 1]]]) + +(m/=> export! [:=> + [:cat Gcs-client Bq-client string? string? Integration] + Status]) + +(defn import! + "Imports compressed CSV files from GCS to database." + ([gcs-client connectable gcs-name gcs-folder integration] + (import! gcs-client connectable gcs-name gcs-folder integration false)) + ([gcs-client connectable gcs-name gcs-folder integration force?] + (let [{:keys [name target-pg-table timeout method]} integration + gcs-uri (gcs-directory gcs-name gcs-folder name) + gcs-state-uri (gcs-directory gcs-name gcs-folder name "EXPORTED")] + (loop [start-time (.getTime (new java.util.Date)) + cur-time start-time] + (if-let [last-update (gcs/get-blob-moddate gcs-client gcs-state-uri)] + (let [last-import (read-last-state name)] + (if (or force? ;not implemented yet! + (before? last-import last-update)) + (do (timbre/info (format "Finding and importing gzipped files from: %s to: postgresql table %s" gcs-uri target-pg-table)) + (stream-gcs-uri-to-db! gcs-client connectable gcs-uri target-pg-table method) + (update-local-state name (tc/from-long last-update))) + (timbre/info (format "No new update for: %s since %s" name (tc/from-long last-update))))) + (if (interval> start-time cur-time timeout) + (timbre/info (format "Timeout for %s has reached its limit: %s secs." name timeout)) + (do (timbre/info "Waiting for 15 seconds before checking GCS again.") + (Thread/sleep 15000) + (recur start-time + (.getTime (new java.util.Date)))))))))) + +(m/=> import! + [:function + [:=> [:cat Gcs-client Connectable string? string? Integration] any?] + [:=> [:cat Gcs-client Connectable string? string? Integration boolean?] any?]]) + +(defn integrate! + "Runs Export, Import or both - based on provided CONFIG." + [gcs-client bq-client config] + (let [{:keys [db gcs-name gcs-folder integrations import? export?]} config + status (atom {:status 1})] + (doseq [x integrations] + (timbre/info (format "Starting integration of: %s." (:name x))) + (when export? + (->> (export! gcs-client bq-client gcs-name gcs-folder x) + (reset! status))) + (when (and (= 1 (:status @status)) import?) + (import! gcs-client db gcs-name gcs-folder x))))) + +(m/=> integrate! [:=> + [:cat Gcs-client Bq-client Config] + nil?]) diff --git a/src/bq2pg/proxy.clj b/src/bq2pg/proxy.clj new file mode 100644 index 0000000..a76d081 --- /dev/null +++ b/src/bq2pg/proxy.clj @@ -0,0 +1,17 @@ +(ns bq2pg.proxy + (:require + [authenticator.core :as auth])) + +(defn get-credentials + "Returns a proxy user and proxy password in your config file." + [proxy-cfg options] + (let [{:keys [proxy-host + proxy-user + proxy-password]} proxy-cfg] + (when (= (:host options) proxy-host) + [proxy-user proxy-password]))) + +(defn set-proxy! + "Sets a HTTP proxy and only if there is a proxy configuration inside your config file." + [config] + (auth/set-default-authenticator (partial get-credentials config))) diff --git a/src/bq2pg/utils.clj b/src/bq2pg/utils.clj new file mode 100644 index 0000000..d8affa8 --- /dev/null +++ b/src/bq2pg/utils.clj @@ -0,0 +1,37 @@ +(ns bq2pg.utils + (:require [babashka.fs :as fs] + [clj-time.core :as t])) + +(defn gcs-directory [bucket-name & opts] + (format "gs://%s/%s" bucket-name (.toString (apply fs/file opts)))) + +(defn load-local-state [] + (try + (read-string + (slurp ".last_import.edn")) + (catch Exception _ {}))) + +(defn update-local-state [kw value] + (let [state (load-local-state)] + (->> (assoc state kw value) + (spit ".last_import.edn")))) + +(defn remove-empty-vals [m] + (into {} (remove (comp nil? second) m))) + +(defn read-last-state [kw] + (let [state (load-local-state)] + (get state kw nil))) + +(defn rand-str [len] + (apply str (take len (repeatedly #(char (+ (rand 26) 65)))))) + +(defn before? [last-import-ts last-update-ts] + (if (nil? last-import-ts) + true + (not (or (t/after? last-import-ts last-update-ts) + (t/equal? last-import-ts last-update-ts))))) + +(defn interval> [start-ms end-ms timeout-s] + (> (- end-ms start-ms) (* 1000 timeout-s))) + diff --git a/test/bq2pg/bq_test.clj b/test/bq2pg/bq_test.clj new file mode 100644 index 0000000..d4a6f47 --- /dev/null +++ b/test/bq2pg/bq_test.clj @@ -0,0 +1,19 @@ +(ns bq2pg.bq-test + (:require [clojure.test :refer [deftest testing is]] + [bq2pg.bq :refer [load-sa create-query-conf create-job-id]])) + +(deftest load-sa-test + (testing "loading wrong service account" + (is (= nil (load-sa "no.file"))))) + +(deftest create-query-conf-test + (testing "creating query job configuration" + (is (= com.google.cloud.bigquery.QueryJobConfiguration + (type + (create-query-conf "testing-query" "testing-name")))))) + +(deftest create-job-id-test + (testing "creating job" + (is (= com.google.cloud.bigquery.AutoValue_JobId + (type + (create-job-id "testing-name" "EU")))))) diff --git a/test/bq2pg/config_test.clj b/test/bq2pg/config_test.clj new file mode 100644 index 0000000..cf8a31d --- /dev/null +++ b/test/bq2pg/config_test.clj @@ -0,0 +1,48 @@ +(ns bq2pg.config-test + (:require [clojure.test :refer [deftest testing is]] + [bq2pg.config :refer [coerce-config]])) + +(def testing-config + {:gcs-name "testing-bucket" + :gcs-folder "testing-folder" + :db {:dbtype "postgres" + :dbname "testing-database" + :user "testing-user" + :host "testing-host" + :port 5432} + :export? false + :import? false + :integrations [{:name "testing-integration" + :location "EU" + :query "select * from testing-dataset.testing-table" + :target-pg-table "testing.table" + :timeout 10 + :method "replace"}]}) + +(deftest coerce-config-test + (testing "Testing coerce config" + (is (= (coerce-config testing-config) + testing-config)))) + +(def testing-config-with-sa + {:gcs-name "testing-bucket" + :gcs-folder "testing-folder" + :db {:dbtype "postgres" + :dbname "testing-database" + :user "testing-user" + :host "testing-host" + :port 5432} + :export? false + :import? false + :integrations [{:name "testing-integration" + :location "EU" + :query "select * from testing-dataset.testing-table" + :target-pg-table "testing.table" + :timeout 10 + :method "replace"}] + :sa-path "/home/nonexistingsa.json"}) + +(deftest coerce-config-test-with-sa + (testing "Testing coerce config" + (is (= (coerce-config testing-config-with-sa) + testing-config-with-sa)))) diff --git a/test/bq2pg/core_test.clj b/test/bq2pg/core_test.clj new file mode 100644 index 0000000..6a799bb --- /dev/null +++ b/test/bq2pg/core_test.clj @@ -0,0 +1,8 @@ +(ns bq2pg.core-test + (:require [clojure.test :refer :all] + [bq2pg.core :refer :all])) + +(deftest a-test + (testing "FIXME, I fail." + (is (= 1 1)))) + diff --git a/test/bq2pg/proxy_test.clj b/test/bq2pg/proxy_test.clj new file mode 100644 index 0000000..1a7eee7 --- /dev/null +++ b/test/bq2pg/proxy_test.clj @@ -0,0 +1,12 @@ +(ns bq2pg.proxy-test + (:require [clojure.test :refer [deftest testing is]] + [bq2pg.proxy :refer [get-credentials]])) + +(deftest get-credentials-test + (testing "get username and password for proxy" + (let [proxy-cfg {:proxy-host "host" + :proxy-user "user" + :proxy-password "password"} + options {:host "host"}] + (is (= (get-credentials proxy-cfg options) + ["user" "password"]))))) diff --git a/test/bq2pg/utils_test.clj b/test/bq2pg/utils_test.clj new file mode 100644 index 0000000..48875a8 --- /dev/null +++ b/test/bq2pg/utils_test.clj @@ -0,0 +1,39 @@ +(ns bq2pg.utils-test + (:require [clojure.test :refer [deftest testing is]] + [bq2pg.utils :refer [gcs-directory load-local-state + read-last-state + rand-str + before? + interval>]] + [clj-time.core :as t])) + +(deftest gcs-directory-test + (testing "creating gcs-directory path" + (is + (= "gs://testing-bucket/path/to/file" + (gcs-directory "testing-bucket" "path" "to" "file"))))) + +(deftest load-local-state-test + (testing "loading local state file" + (is (= clojure.lang.PersistentArrayMap + (type (load-local-state)))))) + +(deftest read-local-state-test + (testing "reading a value from local state file" + (is (nil? (read-last-state :non-existing-key))))) + +(deftest rand-str-test + (testing "generating random string of len 12" + (let [random-string (rand-str 12)] + (is (and (string? random-string) + (= 12 (count random-string))))))) + +(deftest before-test + (testing "date before" + (let [date (t/now)] + (is (= false (before? date date)))))) + +(deftest interval>-test + (testing "bigger interval" + (is (true? (interval> 1000 2100 1)) + (false? (interval> 1000 2000 1)))))