From c2cee455ccc42060aaa34cc140284c3527967769 Mon Sep 17 00:00:00 2001 From: erdrix Date: Mon, 2 Mar 2020 11:39:36 +0100 Subject: [PATCH] add documentation --- Makefile | 6 + README.md | 187 ++++++++++++++++++ cmd/manager/main.go | 1 + .../nifi.orange.com_v1alpha1_nificluster.yaml | 46 +++-- config/samples/simplenificluster.yaml | 54 +++++ docs/img/nifi_logo.png | Bin 0 -> 25418 bytes 6 files changed, 276 insertions(+), 18 deletions(-) create mode 100644 README.md create mode 100644 config/samples/simplenificluster.yaml create mode 100644 docs/img/nifi_logo.png diff --git a/Makefile b/Makefile index e47dc39746..9e9ef9e2b1 100644 --- a/Makefile +++ b/Makefile @@ -153,6 +153,12 @@ endif release: tag image publish +# Install CRDS and Deploy controller in +# the configured Kubernetes cluster in ~/.kube/config +deploy: generate + kubectl apply -f deploy/crds/nifi.orange.com_nificlusters_crd.yaml + kubectl apply -f deploy/. + # golint is not fully supported by modules yet - https://github.com/golang/lint/issues/409 go-lint: $(GO_LINT_CMD) diff --git a/README.md b/README.md new file mode 100644 index 0000000000..97fa694a5e --- /dev/null +++ b/README.md @@ -0,0 +1,187 @@ +

+ +

+ + Docker Automated build + + + + CircleCI + + + + Go Report Card + + + + license + +

+ +# NiFiKop + +The Orange NiFi operator is a Kubernetes operator to automate provisioning, management, autoscaling and operations of [Apache NiFi](https://nifi.apache.org/) clusters deployed to K8s. + +## Overview + +Apache NiFi is an open-source solution that support powerful and scalable directed graphs of data routing, transformation, and system mediation logic. +Some of the high-level capabilities and objectives of Apache NiFi include, and some of the main features of the **NiFiKop** are: + +- **Fine grained** node configuration support +- Graceful rolling upgrade +- graceful NiFi cluster **scaling** + +Some of the roadmap features : + +- Monitoring via **Prometheus** +- Automatic reaction and self healing based on alerts (plugin system, with meaningful default alert plugins) +- Encrypted communication using SSL +- graceful NiFi cluster **scaling and rebalancing** +- Advanced Dataflow and user management via CRD +- the provisioning of secure NiFi clusters + +## Motivation + +At [Orange](https://opensource.orange.com/fr/accueil/) we are building some [Kubernetes operator](https://github.com/Orange-OpenSource?utf8=%E2%9C%93&q=operator&type=&language=), that operate NiFi and Cassandra clusters (among other types) for our business cases. + +There are already some approaches to operating NiFi on Kubernetes, however, we did not find them appropriate for use in a highly dynamic environment, nor capable of meeting our needs. + +- [Helm chart](https://github.com/cetic/helm-nifi) +- [Cloudera Nifi Operator](https://blog.cloudera.com/cloudera-flow-management-goes-cloud-native-with-apache-nifi-on-red-hat-openshift-kubernetes-platform/) + +Finally, our motivation is to build an open source solution and a community which drives the innovation and features of this operator. + + +## Installation + +The operator installs the 1.11.2 version of Apache NiFi, and can run on Minikube v0.33.1+ and Kubernetes 1.12.0+. + +> The operator supports NiFi 1.11.0+ + +As a pre-requisite it needs a Kubernetes cluster. Also, NiFi requires Zookeeper so you need to first have a Zookeeper cluster if you don't already have one. + +> We believe in the `separation of concerns` principle, thus the NiFi operator does not install nor manage Zookeeper. + +### Install Zookeeper + +To install Zookeeper we recommend using the [Pravega's Zookeeper Operator](https://github.com/pravega/zookeeper-operator). +You can deploy Zookeeper by using the Helm chart. + +```bash +helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com/ +# Using helm3 +# You have to create the namespace before executing following command +helm install zookeeper-operator --namespace=zookeeper banzaicloud-stable/zookeeper-operator +# Using previous versions of helm +helm install --name zookeeper-operator --namespace=zookeeper banzaicloud-stable/zookeeper-operator +kubectl create --namespace zookeeper -f - < Remember to set your NiFiCluster CR properly to use the newly created StorageClass. + +1. Set `KUBECONFIG` pointing towards your cluster +2. Run `make deploy` (deploys the operator in the current namespace into the cluster) +3. Set your NiFi configurations in a Kubernetes custom resource (sample: `config/samples/simplenificluster.yaml`) and run this command to deploy the NiFi components: + +```bash +# Add your zookeeper svc name to the configuration +kubectl create -n nifi -f config/samples/simplenificluster.yaml +``` + +### Easy way: installing with Helm + +Alternatively, if you are using Helm, you can deploy the operator using a Helm chart [Helm chart](https://github.com/orangeopensource/nifikop/tree/master/helm): + +> To install the an other version of the operator use `helm install --name=nifikop --namespace=nifi --set operator.image.tag=x.y.z orange-incubator/nifikop` + +```bash +helm repo add orange-incubator https://orange-kubernetes-charts-incubator.storage.googleapis.com/ + +# Using helm3 +# You have to create the namespace before executing following command +helm install nifikop --namespace=nifi orange-incubator/nifikop +# Using previous versions of helm +helm install --name=nifikop --namespace=nifi orange-incubator/nifikop + +# Add your zookeeper svc name to the configuration +kubectl create -n nifi -f config/samples/simplenificluster.yaml +``` + +## Test Your Deployment + +## Development + +Checkout out the [developer docs](docs/developer.md) + +## Features + +Check out the [supported features](docs/features.md) + +## Issues, feature requests and roadmap + +Please note that the NiFi operator is constantly under development and new releases might introduce breaking changes. We are striving to keep backward compatibility as much as possible while adding new features at a fast pace. Issues, new features or bugs are tracked on the projects [GitHub page](https://github.com/orangeopensource/nifikop/issues) - please feel free to add yours! + +To track some of the significant features and future items from the roadmap please visit the [roadmap doc](docs/roadmap.md). + +## Contributing + +If you find this project useful here's how you can help: + +- Send a pull request with your new features and bug fixes +- Help new users with issues they may encounter +- Support the development of this project and star this repo! + +## Community + +If you have any questions about the NiFi operator, and would like to talk to us and the other members of the community, please join our [Slack](https://slack.nifikop.io/). + +If you find this project useful, help us: + +- Support the development of this project and star this repo! :star: +- If you use the Nifi operator in a production environment, add yourself to the list of production [adopters](https://github.com/orangeopensource/nifikop/blob/master/ADOPTERS.md). :metal:
+- Help new users with issues they may encounter :muscle: +- Send a pull request with your new features and bug fixes :rocket: + +## Credits + +- Operator implementation based on [banzaicloud/kafka-operator](https://github.com/banzaicloud/kafka-operator) +- NiFi kubernetes setup configuration inspired from [cetic/helm-nifi](https://github.com/cetic/helm-nifi) + +## License + +Copyright (c) 2019 [Orange, Inc.](https://opensource.orange.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 397af39b89..3b29ff84a6 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -49,6 +49,7 @@ func printVersion() { } func main() { + // Add the zap logger flag set to the CLI. The flag set must // be added before calling pflag.Parse(). pflag.CommandLine.AddFlagSet(zap.FlagSet()) diff --git a/config/samples/nifi.orange.com_v1alpha1_nificluster.yaml b/config/samples/nifi.orange.com_v1alpha1_nificluster.yaml index ead0575e41..847b998d7a 100644 --- a/config/samples/nifi.orange.com_v1alpha1_nificluster.yaml +++ b/config/samples/nifi.orange.com_v1alpha1_nificluster.yaml @@ -30,12 +30,12 @@ spec: # A comma separated list of allowed HTTP Host header values to consider when NiFi # is running securely and will be receiving requests to a different host[:port] than it is bound to. # https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#web-properties -# webProxyHost: + # webProxyHost: # Nifi security client auth needClientAuth: false # Indicates which of the configured authorizers in the authorizers.xml file to use # https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#authorizer-configuration -# authorizer: + # authorizer: # ZookeeperProperties configuration that will be applied to the node. zookeeperProperties: # Additionnals zookeeper.properties configuration that will override the one produced based @@ -70,13 +70,13 @@ spec: isNode: true # Docker image used by the operator to create the node associated # https://hub.docker.com/r/apache/nifi/ -# image: "apache/nifi:1.11.2" + # image: "apache/nifi:1.11.2" # nodeAffinity can be specified, operator populates this value if new pvc added later to node # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity -# nodeAffinity: + # nodeAffinity: # storageConfigs specifies the node log related configs storageConfigs: - # Name of the storage config, used to name PV to reuse into sidecars for example. + # Name of the storage config, used to name PV to reuse into sidecars for example. - name: provenance-repository # Path where the volume will be mount into the main nifi container inside the pod. mountPath: "/opt/nifi/provenance_repository" @@ -103,22 +103,28 @@ spec: # resourceRequirements works exactly like Container resources, the user can specify the limit and the requests # through this property # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ -# resourcesRequirements: + resourcesRequirements: + limits: + cpu: "2" + memory: 3Gi + requests: + cpu: "1" + memory: 1Gi # imagePullSecrets specifies the secret to use when using private registry # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#localobjectreference-v1-core -# imagePullSecrets: + # imagePullSecrets: # nodeSelector can be specified, which set the pod to fit on a node # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector -# nodeSelector: + # nodeSelector: # tolerations can be specified, which set the pod's tolerations # https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/#concepts -# tolerations: + # tolerations: # Additionnal annotation to attach to the pod associated # https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set -# nodeAnnotations: + # nodeAnnotations: # all node requires an image, unique id, and storageConfigs settings nodes: - # Unique Node id + # Unique Node id - id: 0 # nodeConfigGroup can be used to ease the node configuration, if set no only the id is required nodeConfigGroup: "default_group" @@ -129,7 +135,7 @@ spec: overrideConfigs: | nifi.ui.banner.text=NiFiKop by Orange - Node 0 # node configuration -# nodeConfig: + # nodeConfig: - id: 2 # readOnlyConfig can be used to pass Nifi node config # which has type read-only these config changes will trigger rolling upgrade @@ -138,6 +144,13 @@ spec: nifi.ui.banner.text=NiFiKop by Orange - Node 2 # node configuration nodeConfig: + resourcesRequirements: + limits: + cpu: "2" + memory: 3Gi + requests: + cpu: "1" + memory: 1Gi storageConfigs: # Name of the storage config, used to name PV to reuse into sidecars for example. - name: provenance-repository @@ -152,9 +165,6 @@ spec: resources: requests: storage: 8Gi - - id: 12 - # nodeConfigGroup can be used to ease the node configuration, if set no only the id is required - nodeConfigGroup: "default_group" # rollingUpgradeConfig specifies the rolling upgrade config for the cluster rollingUpgradeConfig: # failureThreshold states that how many errors can the cluster tolerate during rolling upgrade @@ -170,12 +180,12 @@ spec: # If set to true, we will enable ldap usage into nifi.properties configuration. enabled: false # Space-separated list of URLs of the LDAP servers (i.e. ldap://:). -# url: + # url: # Base DN for searching for users (i.e. CN=Users,DC=example,DC=com). -# searchBase: + # searchBase: # Filter for searching for users against the 'User Search Base'. # (i.e. sAMAccountName={0}). The user specified name is inserted into '{0}'. -# searchFilter: + # searchFilter: # NifiClusterTaskSpec specifies the configuration of the nifi cluster Tasks nifiClusterTaskSpec: # retryDurationMinutes describes the amount of time the Operator waits for the task diff --git a/config/samples/simplenificluster.yaml b/config/samples/simplenificluster.yaml new file mode 100644 index 0000000000..fdd420e805 --- /dev/null +++ b/config/samples/simplenificluster.yaml @@ -0,0 +1,54 @@ +apiVersion: nifi.orange.com/v1alpha1 +kind: NifiCluster +metadata: + name: simplenifi +spec: + headlessServiceEnabled: true + zkAddresse: "zookeepercluster-client.zookeeper:2181" + zkPath: "/simplenifi" + clusterImage: "apache/nifi:1.11.2" + oneNifiNodePerNode: false + nodeConfigGroups: + default_group: + isNode: true + storageConfigs: + - mountPath: "/opt/nifi/nifi-current/logs" + name: logs + pvcSpec: + accessModes: + - ReadWriteOnce + storageClassName: "standard" + resources: + requests: + storage: 10Gi + serviceAccountName: "default" + resourcesRequirements: + limits: + cpu: "2" + memory: 3Gi + requests: + cpu: "1" + memory: 1Gi + nodes: + - id: 0 + nodeConfigGroup: "default_group" + - id: 1 + nodeConfigGroup: "default_group" + - id: 2 + nodeConfigGroup: "default_group" + rollingUpgradeConfig: + failureThreshold: 10 + propagateLabels: true + nifiClusterTaskSpec: + retryDurationMinutes: 10 + listenersConfig: + internalListeners: + - type: "http" + name: "http" + containerPort: 8080 + - type: "cluster" + name: "cluster" + containerPort: 6007 + - type: "s2s" + name: "s2s" + containerPort: 10000 \ No newline at end of file diff --git a/docs/img/nifi_logo.png b/docs/img/nifi_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..08f4a550e0ac97a6d3056ef63567f57cd80a4dcb GIT binary patch literal 25418 zcmYIwbzGC*`}YlqD2Nz@f`mv(3P`7cFh+++jHz@>H^W3iVn|B}qe~h_%%Xdg>8EeSgh=*CRPXICvgk zdy}MX^?9Zt(n9gAne!59G#KyLXiyvFz{#38)Le~IleGhzbB_Za3Jg6T?4Kb02GUJZLE(`V;I4sds|)q z6eirx<_b~oCazs0AwJ#>A8Ay-Ifqw=+~cT~G+e!`Lqgmz04#dmdq4<5Au;%>lbE5g zQhU;0fu!e8c5e>x8#7u;jtl93q+4_c_SEAN-Ci+t z^6yTW{I{4$?i;~R z$IRgxu4T6?potSupR{wLfOoq4z@~ z`OtwYY?1pOv>`k!17ZK&T4I>QK?$7w&7)wsRopc>PPzKqcLT8~KyO`L3u&^(D3rXg z4KbmDus?pj4MXw(X*l$H6I~4CBfMq3^<7rwRoNek*g}r0L_yr0OGAujMALC8@C^BW z?RQHEb2=bNd%!W1E2JVWvLfShvinFa@%`c(n*z5nFoghOvTJr2jAEaip3O2PyEeFw60%w*O>> zx$%z{F7o6^ggy?m0=qpz2*PBmWyw&&NA5(M$Xaq_UdL&m@3po+g(^taP^3J&@FoSI68yJqn%=HxC1V^@lNHdYFbGvh=Z@SX{V8WBZo(Lk z5leP>e2{7)y+ci7KApC4w07M4C`v@UyXgtEt$di@&rc;v?txiTSeF`wfA`r+HaYg& zZYAZQiQjs8>V8`qp&Y*dBs=9y2Cn~(G2gR482u`aYV7zkP zK(KRty^DYKTQcJM(X}{SUk1A(f3?bZo!r-2krYE^n*jlldWF#MUqo#5D~n8lK(*SF z^=#<#aYBy(^6anLAC(Khn}>0QCbxHfHhech@8zH12KvPs-cLMwP6=>r>}Q?|CM9P} z#h`bi;j)`QbJp$c2j8bdXtw1OeFqB&X(k5yk1ch7Ulo`WxX3niX4!eq%D z`K@382)FoMNoJtx@w|&UeknFTR#4!3P-HLZ&*cFc8W$U*Dk|W+plUV6(d`(TV9zGB zx3~Jg_rHUZ@kwG4VV!?Pt9{o-c%%2G3sqO|9gJZD7@b6cn&lLnf{Tw%t{5^a`XVst zML+I$aw*QAQ<-MtLwXnXApjTMjVdvsueKVL=k}sU*3oo*9 zUnCsJo%$S1#vyqjWWY70_Mh|JdA?P<>o?broAxC5XBmHwm;l;2ap5d1SK0wVZF^gw7}dWZjL4XL`b{u5>(VE>|Nyt=2J zG_W>l7FPHaNAKixRu)uJ0i&@L^>sQ46EiY`ZuO&JqUk2~ z>$~zsSy`EF<&Pt*pYIqAm3FHi3~bNOz*qY_jx6z=W z?cHnX!xL5A-|%D5h~a^e%VZScsUjK1n(h9of3vzlI5gjo6Op7-ExcTFK(sE?YZudm z3eZkxF@pXdH~>H!ReD~gfoPHhTvHa0FwlZf&lVQb4=E!~`pEAe!P_>RfE-*FYB zrW(1|G-$DvUjAo-f9WukIk8Yw6ybb|+v~sV?#c{Ab3L z*+s*P#@}RhEJHxd8$LZd#Wcqlz0v)L7H{l+wq~}ZjnW4mL_8pz&XK(cEzN4)^;yrZdq`9mlPtloj%4@iq|Mz9RAauhQW3`gFP72M!mAuNADZVSfi!_q$ zOVqF+v}1ZG8m(N zQ`*Y=w+Y%P`{-Pc2}i(37xW|xbBP)^fWVx2A>-$?m4?xoRWE!rTx~Q!e7rF@)J2ez z3lpRQ)|B)Y67>ce+ih1?6N+*BaRkQ6WSWXRl&(&%v+3vT@%sH<=MAquLt|H-2x~rz z#BkpZjA@mlHE(7a+DFLaLn9*jfKYi`G!e8Rn_p47;brR1J+ZQy*u3(Tn2&!rSI`MZ zZ{1k-lb!r#G$5{COe8I07}J9mNUq+pD+dXn(j55Y*8)fK@J34f@OHP~SyDD`bC~a- zubmb^dlf!Kub$HJ5xT!g?QG_WF|kC46FQ-hsxY>t+L~*By9bMf41(&PL-N?>kjPxfwiymbFykTN|bt)8BHQ%^kkZs7m?M4kbQ1~mu z%=6$Cuf9-jJW=Qbz@SmTsC&OJTLN8=TD%CMTC|}AU{@%`WPbnKs@NG)UqPdHw=<_7 zYtRBAGH#i(Ptw0+yN?+&KQj`2gdgc3HRe8u@GN5CMb}Rng?WIW2L&wR8lFjlM6!Sn$JUz8Fo4z%b^i1M8<(22P1ZLlT=q^y;r! zZ0`OX!kvuwi>=3YrkMYbt9#o)g+Ycp*{uVe+c0734^-lV1ud%gdt^Y&_dk>GI73 z`3B8&?$>Wp8RpO^ni^NkM`5B@_dr4TY}?!UC3-G}C(LRkT6H88|It*)1g1{%+2#HT zYq&@7c4nEStoz0p&05^ULoeeXp@~s^_ptAmQH4UIvR5ZKd>`q~n;!|u)m2a8RF=kZ zeQH%Ko^IOhV zTd_c7Hz}3E#$N#VEc^To6;mQ3r#@|)uK2JR_czZ3jkBf^JLHL|)`&H7unLB#TvU`(3$JEx~!iGj^LY4cIim znAUorP<^#`Zm?Pip1={=Jns!_Co|joU133LaozF489V zl@Bx2q$tyGP0zb6l@eXMl1hxRom0DuH{b*x2u!HQ^PAI=KtEcA;;WkJ*DZ!8{8zl8 zK#TIhsmGah4L+QxPziMYy4bYe)QYLFe?ROQi!V?DLiH@{Fv`B;pHfx|&IRzMncNB_ z`dj$zMA+9qx7}65H?W3%8>`#iJfC-Eb*4(F04EuzCQHa@Z2;z3tzIs_MY49PHLp#R zF{z?y%Adb`&hGWr0sw$SC8C=m+Uk3#nzs~xZ9iqdzCibgM9~HIZ=gv~F7koQd{q-e zvTK(qq}$Vb+EPkpV_ulbVUSZayYMsiUj}uXXT9rSxjIZ%XUL8_9z?mGHE6=GHa+Ft z?3JVKc^v;z!b3dsRN>X#lN&!NS^yAs5M2eG^<{{Pi@MWo$^D%R+LGbYlP7y*&dMRP3Fh@T0?-#zDW?I>DVc zgggS!X_C()Kd@Q@6x;TGH zu%>Xm*UDv4b4QrmZI1w`*7EyAY8ND9eFJ zRW2c&5Ba|`3SO|Pte7k>CnZd$33#WV^!+0rwT-7%{A77EBu%qB>UJ>>p*`$kokgqX zmTdSz3h%f=JN4SHs$U642UvE*_tw~UUNrcycV|{ukkD$K`FjInKDaA$iL^yfcawxc zf0^y6Dk@H$(9(5{m!$jwytFLK_@?UKgrsrveoa4uE)vp< z`^_Mf+U-U16LsL7)>%AaU?samadoK$k5SmD8&q56j#Nr&nuIZ^haXN+KnwXf?+-SX zB?;I#f2e1P(i@!n{_%MSC>{;YM<*&IK+oPJA^iS)ZgKQq?PS~Md-{-yr`j*c17r9M zn$pMGG;~B#!h~QI^WOz8?!R*WDwN8JFcwdFc`Z~fpjWCG!F!_p4A#<7 zGK>M(jji1XK+iI7NS4%xHjnTPR|}R={w^2#i1zIK#Hw7o_Z{cGRB+ob4QR>H2XiB) zkb0svG)EJSyyjUgiUj4{adZD;C?g}Hvf5{YaQztx9gx?go+7A}c=Kl5Y3U`hnH;jk zvUU90lRvnvSex1%fxopwMTI&!DpewGOUZ3xnR#>Khd*nOXrJiysE2}&S+77&Tpu&i zZ|#u+2?_>~Mx2cao(5Qa44tc9;Y5f+?igG{k9!YbYrD{U%QRKjloi%yhfaUKYd~|R zHin%3_PZiX-z3y8oTY1yAV=^__JAV>`E2%A=a>?;`Ub~mQXZhdv>vU8t?~DGSX4D<_IV=i zBh?Vo^Wp%n9%tMimO|hqHr~d2+h<>MkF$w5iwL|xsXLv7?@GdbY7vh%BIZde+q(RvugjKPH zr`KC`Y}V}pQPH(`?xO|Oswpm)JzynOGs6?2kyo>hK83c^S#)7@F@`%W|As~3m^Eum z-D0Pcm*YSp^(ft|a7^=QGICH^y5Xl_nAbre_rkXT9}18;38l+#DVq3lr$CS8Rgs9! zYUdzaf|&mW68wdtUP$pp#s4|-L+}Feai%<>E=N^swTELieI5LTOhUMw(Y*`-$I)6p zx4s{S2gM3d?4KHziE%qtY4z{QMv~o+Yd5ENvK%xQw#LWT>j_hGNSdWQhwR_O$OhMM zCI&StH(?uk2<|05nAk}p8BLgu&PK@Yn7W;JK1oZC-s&Fc+`QI6z2BnLX`eNZdL){d zpNQdK+Ibp9c!#0J{6_B7feRVplxY2n~J0KZp@L$mDdufakyrKXX^D4^f+;u0Xzn?#>UO> z6lavL_T@%59h#C3%hdRp47)L?QI8LQs9tg;mJ(Il{Fl zXrXkNel56o?U%-2tDDV-WRux-kAmrrp7hNjUm5!(R0&L8@0#DvLd$AT*Kj6+Cv6~3wiOlq*Bd94B6cPyUmA$1!@LvyJ0t@H#@Q4y z?kGW`hJx<%2@dY+YHBGN=5j3k{Pje7Y(gWl`PSVJMH_z0OgQ(@QXHk#ARXd=C~Z=vaJWAU7=-pOgbW=^k69J0|o;H}=>bsLNO^ z!zl=@<~qLn5;teJz6dNWT7TV@PjA^FRUD(;)A8826w11~|8mg5;jfc@o5SW?SI#qd z(M3;`*CZ3EH|mig|7t)l3MKbqRQtv!p8;m3a5U@Csu>-?ky|b2;j0`BzjxGfsg`BE zi0M6Bbx8(FwL}Y9!vS5`q@la-Aqu9&5_YGLd1%x*gA1tCN3ON4M+L3uC{2CxY}ooD zQ&y6(w=%>~-@~GH0q7B+Vp_j5n{r$<8|8H5x&5JpQOk6Hh!Eg0s^Olc^I^E+V6a~x z)c`JoiQ?JTWrGx1?-10FcZeYnetn(a{pHV#khR{c9WKWnfx@A(1WbKdX5J_jqv@Mp z!xS8HbZZ5Nhi6{D$gNl(MEETQbZcVgBv@9uK+3TEfT~wtP3y|8l$w31ozF&!FHa}* z;k=eQY~X0O!7#YF-KJ2zSImfvmHOz@T>veXb~zgN)la8?|IfweHm5n)5oa5Jlt(JO z7g*kfwb?_!jA-_?rzs8av2itzN9822?&q$EEo6Z2!)ZRgYzETZ9CFIOKXS=!lTq2Q ze;-$diiM<2Lqo09F;K@Ut25U}`v?K!)Dww`*MJBiu3dxeLztb!Q5A>69$3S%f=S!? z%*afLI7pNLE$#z*Us5BN$h1cpnrEcVmQe;KeaHQ=Ym{;v9gA&pml_ZQ*vx{&_=s%n z`~bpc0`i%K2b)jb+cF$$$rMunzP9<|!fR_{A;bim#4aCk;yVWEWw>52HqO$qxc$C3 z)J#Y*YR!ZLKM)#0Gee@ zk)_y&UD|u-+?)C)r$g>N1Aaf$g;vKk1y34?xSnP2uq(feRuHP5d^g+Zl(?^5XZh_om8tKJXHY!peOG@IDf@)W>~YEy!7;_!_hH_i}L^(|%VyMLFhU-(bp_ z`o0sa%)GIcBT8X<9d9K%dgE2#fghLPQUfu;1$W0C8(R#{Nh}KD0?Jc^luGJL9@NN= zRPU-ZVS+tqJXHtx@SWjxu9n>lVu_+w8n&P%l28%9|JXVG&v<7CJDn(8`p6eok3m?6 zQA|;A`X-?ypu8)kzNlu{u{wW04bEdCjD=1b$sEAOa^R$7V|=HnukIj+5C@5HAK=}c zY_L8nM$mNR`y3Q9o<>FRO%`wbjxz7L*DeUgObo#!iVYx3Pd|()upIHXktVxOb2Prg zjO(>O8R|2xylL63fALjyDY^l#PAw)D6nyXC_Vvku^MYmeAFd`;u3)i?Zq1mgxvjWC z(Bn~^ew*$(w;<90ZA?e15UDi7~t7Sxx z4q?3QB`|@R8h1JS%E3PD-rBK5yAc`e8rrA6ABft{8T}@0Q^ys?h!0717%72j+K;HF z-99;ajVs7cIJu8(@poqbnP2br`mh5^0N94~u05)H=*y4C-xloxD=ch60$?4A?t6HF zn$@O)y;e*U#&$DRjcadAJXXGyBMxpj`om8hws*P_^~{m#GqD_d@!F$fHT)d3OKQa% z2}D-C?|5WUXx5{r{ns68Wh=cqB%Z#rpSGp-1YOMZNV2%yq{o~jh7 z2R~LlUIUTEc`Hmpo=axhqhJox)V*B+BJGBPC3&o~_wb+j@3Xxygu&s@&MV(7UvIFh zM6~1GyOy#&BQFH{l`qa`4JDL6Om^V>>wkM9KaY|MyG0@LKS##cDBMqzDXLqmBzaX! zP_gMaDbCC337%=Hn_uuvGOn;gh<>*``SvUkKKkRds(>Q0?2HUh#8-nMLo-bJ3kSQg zA9yH3H^>70^uQv34A+TD|GrX5e3#q|ZA?tV_G{rdH-Z`B`O4jOy&>p`Nr1+a&eP^# z_NoV9(?VcC2mh&)4iFh(%M=Tb>6(NiHIhZ}V($@Y#GGn+8puJ# zs+xEMcLX}%-jPkj+EJ35K@3?bajm0T7lYg2XK{@|>9Hr{9K`DPR&KaKr1@@dW>>H@K$ zBGNzN21%eFQiX#w8lkxj(XI+^1a$yQ+xTwis>8@t=H5Yu{cHAcdXlkadhv&y?3am! zYqq40RPGDF5vszrBaRc6*d?B=&R9%hkqJ_{nN-Q^=E&05971})3hpX=>ggk5r-ylP z`#zF1&`(=;=;5eEs-{(v@Sh;tj?M4jJ4OB!<=HhKU%LJ|OgCSqAQsW?QJxc$p#!@7 zNM>7!a8ZQt9o0hiHw1elS={DS8^Pd{!!6;&{clXf_cV51=my#OhQ26lTQ;IVJ?Mm2 z7O2D?e@DIgZ&UtQy~fwdtX;Ag|G2BnQje=^nsysOPB?L2Iw$oyjb>mEbtNle@~$JvAICwR&(KD*&9e zq;s}+MJ>&PlK3#~F?R&3@0hrz(?p)Rh|_G1)T~k@A@u)*NAFn6<*d~nTz@0)T8}|DEcIPDmkvNN1V5Y6QJ<=#n(Ttb2?m-hJjiCP-pzbPQ&nV4P{*(b=yb%{U8;}vrsTb!v}T3qc1RpQzkg2=@C$)Nu) zbl~t7cPLYH>nR12on}!rB-DKn5^Vu1_qA>J;EaYmUPo9);IOB+U#FdOkxi51MzEKN zg+k;**=2E1ax~&m(_W|5Ygg~s_wB=cFV|p1&Y)}4O;y*=bq)Z$(<~;dndSmarANQX zzACtAKrIy!!PO?f;}8@{jFuEC#wh07}g3O*Zvga_Q|J zNuF!kP-CXM2Z(#oN>c}hH2-yA1>VuGt+q+;Xb^Ch`a&pfgF@Y!`h#JPJyB{)!vdq1 zYu#rQFhsHCfq21>w%gOD|~m5O8o9skCCf%P<)~FpD$(_vVD-+?0Wqf}$S` z&*4RU*kQ}D&)*qk{H%wl$M+6hjXABBFr;FC>lTB+n&s>C#RSRgY|NpKc#V%CBiUJx zQ+bEKDl)EFKI!z&!Fc5kX+fS?2>CkHkV42fYt$%A_jj&B3Pr?f^M_H-qxWlUY9Ft; z?7-$n?m+3}Ja^nv|3Qe2cr{BS#trVTdFR^u;`fV5<}9Qwu!kxRhKDp<3fUETM|Md1 zsArlk7s6lTOD&YzyJlN_^_kjZxsZgPBC&UhltG2|-ZtFw+MS48agu;$y26Rt zRI=P~_Ymgm3MhtR5^tv`oppq}A?s6=fC`dcd`yZbtKV2|m&!s~*+E)YXDQUF41?E% z^TsW?BQY9Th&OTOS+RK~onr1^>^KYEsRsY*C>;oZ%_U!hK#lVW&RwQ&?fyJr3gYR% zD(?}&9|@anaS;jYCg5R|a}F5TbA+$g!L=iaB_}<19xvB6u~Aeghk9H;>w3ws;1Of= z_=;oxvfYBbniJU>l>va-F-YM9&9(ukITj-Dgf8*uXAwQEH=C7gN3nxhCxk;3z*qzQ=ntcESA=zu$I z__FWE+Y}Z}a2n7%Ua8*Cve4C?|FUGSYovqPx))S0nN~HE8jMCYr{aE3vMTR1kp!*s zA?1~6m!>EK@m=G#%LXRa^Q|W;0{?yGdAC z+J#ViJaVMK4LTrlr{2!0h)u8F=5hZN)J>IHIvr%d`u3+!iARJ8Nq`an5f7Uj*pLWS z3s4tlsYT_e%vo?s|MPf}e19H4Q|-|#^L}V&&h!%{FtEpG8GmB_S{m&Yg+ufW>{QP8 z|HORXDqKhZ&OA_=mQR3T$i%Bprr!#T8n{Tjwf}a9Uja_pgnT;m`YpkE>$i8r99DST z759X2?ZvHGqvz|-x%<3K#k5PYn4~3q-Jzs7jgY+OGhO+)6JpDUy3ulB9TrWm8iWg2 z-%X8tO8AlUeJT0-N%!Bl;1+6vQ+xH>GQ>lxs{`pgX8&gJ!uxODs<{R)Eh3Y}m9Y^n zQ})$hVz`#{$m+>Z&90jCunoF3phrh+9|}sKgkFVXZRlggXE3{M&l^uZM4Js^AZ@v% zfeD147D_b|I>S^|zA*|h@5oT3aA>R6ciji%iiRYH;iV@oy@+nCgYqg`zOtl^s z)0r*o(sDFYC5Cu}HTcYqT@c>ZXOH@9FeKssBkTK;b~K^CaS}tJ5wkQZpbru{EEEGZ z+thzOL2WrmkeZWvmUbx4b~(}V<^}S=fPB!WU_nKRNILaJcCkf;NsXEl4ElNw|0JSi zs{h^sfJx3yeKUeSmLI985pLIs@my2)3}**V`>c)V*@yZC2tv^W9WZBy{ zBzQMhHToEhgCpc`D5XQOT;Ae=z^HU|PRHm80;$Had+QXUoU zu`0Y=QDZMlBjR}p2Z@|t?tu*(z^)YtWi;cKK9yf&An7ZPx~WlUPqqB{EvaI_6+Bbo z#LT0^cr~ZHU%u^Ty|A{+Ux`Zv%dJ3~f-1;@nAHbR&CIEV9^UcfDDtXu^&7XFyHdQ6VP z3%o}{k(yPKZg!Xf2s}zCm@V^oga&fHzkldHW}WQ6tyjOb8%-N3eCH8;&BbP&U!H=- zH6qV$(E=__VpaS}JvuQa_m=*kqCDH=$_cr-#&|)n&kpcLn4(e6sM_(|hYgX860eE) z9l76-GFA@D)l*q)sodeVx69?cNC`-N2OBLRC3>5_kg+^=L`=(Sb44fQ z_cJ5eg*;45jnZ|w!lAwf6h<_*3lsk4;if(|Ck6}xh8|ZTTEL=iMd*g4`rAUVsq^8s zX$b{Bm5M1={T>KC!T2M#ASY%wyoKyCmD^yjE*2ApgK652@p8NDrlj}0-++0}gs4&i zi#LhJibv(_d66)x7yd$j@|RHFiW4i89$ZTCMS{D!Rr?tZJ3NoNY^JBL9lPI9xjvCU zU-{%i_{3adB0nV)*!DUE*6R~3RL`0+zoU9L!jK^Wr_+V5AV*wq`p~%8meWyiJM9Yg zFJrjESfchDkhxl#PU9Mji+piJ4Fnst7sZI3skf^M-$qaO;6#7Td!!E5~q%G_(ErI8=P4a=dG{icIg*7fkRhQV*omR3dut=7za1Yd!wHpO%J`D(=G#pO0w!1)*+#(DqV8|3H6Vn&ANbz6-?tEF_dO zm8rs?pMJ69CRgjbUChuMh^E8Hv&9xMGOzb+=)Yy8s{|V951{9z1+gkhOL*Vypc8)dv)(*!jGY0T+b`j!oVTSh@MI)L&4Rjvre^NkABHRGjrZ zieZ#VKWV=uS8ox7%#ECkVo=*}1S=)zy4To*7>8dKw7@k;`%h;vlj8_Mg%|vF zpFm@v=mcrh#c46d;UjLzYGnjbFYV*^E6Q!V-_pNRHg#Eo5)Hr?u;jLa&ipbni>E^> zexQk=5d@plNTWcZUCCQXnh-cr0445D#L{l-O<$Lk3~q5pPOsUr8#Fq6;LQlk9X?&4 zC9(^JP}h-yu(buLcD&cT20Dk9tQDsh;ytrfAo$M(!GCr2iD$_~rCkIuy7Zf^l@K%d zQi}v>=VcWw*+=_-=C~FEb)9o0N?IwW;hl#nj7$}0M4M{6IO(_{MEA+Za^>nfWz5TM zraY$g_{SuGGEK=DGudz>P%?zg-5p zZ9Ox@2{!zZUBm~vb8%V{Fn{Y-lNk@b3y3%p{oeO-laK%gOkb9omb3PO!I@^}V~4RV z(y0u%@Y3()PjsxAVD-iHx<__xgXXox35t+v7**%_4)&7{d9Hue$w z!wIT3GhMI`5qMjb4tGA#x693EAvnPA$jii@%?DSWtAr?x&!e_x^o&f#GS1{N4%tXZ z!C<45U)w6c+ zssa z$xUqZ8GC%*z-up>;JZP)AkCD0a{eWF>~3NRkI zYID#)<_55lb72IcRAvX_6TzNFrZ&D2H%j6biaNj))tI@25^LrKX@_kui`T>33zcgi zpC+9w%dg&%i6aH~i3_9ml>;R#u;_}UH9YE}u&Dg~J35UA^5Xw{mbY+;V;cEsJ6!V$=dMNm8m$36{r z?7!ic{_UQYN3=ve;c(`spmXFrQ^R(H#cb1C=pks6$sYe@ zvTWj^nNGEhIxa@Ya4+U#nE~{MNA)- z@P;>wly0cYz_mowdM_(J<${_Z{*=D0@$oYuiG)5u90~o7hkLh+?MN&v3pYF@pGpF+ z3T`F6xD^1$KJ*ccX1yi<7W8jF;d(cySKwkr=xp1=$K6OHQ>KzR zJ?c^2bJM?^$rT+X*{YgP3&ty3?xDRs0M=*c$Iy(F;^udX+!`%oHh;kkdrn4Kv<86Q zctS+pS|AU`#-Cp|O@xM??iE~m;F-`Ki!GEBx9;u4{;Wc-M_Ef6s}|F z?EGw>8Ew}W4s#>z5w)ab&;_X!QtNQKx*Xvn$D_hn(WclxZcdu6_DmX}fuJoSc0>%T zYmdgo(b{1bqi&B9_Q!qQLD&@z_^h8MqUR9GBxz|!8Q&Xm4TmEU`?aHs<34)>Ymd?* zpp;7s>!Ly|&(0?TK^1GXn{EF-x7w`?wjW_@sWk*eF3t5dJMhY$Rns^v;4}0Kgf8}w zJ?^W!L)_I~Q+3Ve=+L6|Ur8b=)SRHTrR)O*J4Ef+uYW&g&Vo_S{7ut7Cc8$7f`&Qk zUSNk*eU0syf;PaTC}{jy<)9Egq8hH?y z5Fw!S4_>nqCmC#!TxX%%g-CDix`!1(q>69<-Cns;bU(*x)i!;!HYr*E1_*#ZW?Q^m z?hEmPzKnLmR(DLudClxIa4ZycDT>GMW}aWs0kke9JM1?m6=CYq+H&_Qb_P}PJoTv! zTGQfzAnkZQr&@==vEtB?fc~DlV1%4fa^}gUJ5u7w%1mP3{UKd%*aS>W;8?{Y3ejb3 zsWs$kWQ!X1SO9cZX+OSJFd#s?ZcLJtpm9rqH{%4i{o659XRPIN3-8dv&0rbmePDM* z_y_zXL&{Z${Af%!H+6?{k)C+dFD>xg`D8BVtbraheH+{HTmES;`s0oP-Evv6arxwBNcWDkN<=F$d90<#JNlZ6ID@-m@N6H}1m|E@m)1IS^%&k}3@ z)RlpHtH-YTJ3&0au7dBFallXOLBt>ET{%m7Zlahxku~(GVJ|vmjkjrw@8~+i;e52f z%(L5tp8SQAV?Xw&#c0<6O2BYhNB4<(=hQn^0!1!$9V6C%OOglzD1V-d*{=%i(FkT? zJ&VkQ`p|z(YeGHO6*p+;v&9X*Bs~GsQo-cYqX-BzulOHNu)YQMMDg==aLs3MCF9li zNX-!JAZg!hNy6DaLCZJDW5WrQQ2CeZsWG+Mz#?l3yzb3}+274LgDMuT59Qm_MA|@gZHzcf}742-?(rB~>IGDiVb6)~PK<+<43=#Oh33 z?-@+pzi-sS2Uh;}@jT`nw2pQvB`V^sGPyfAZA62)=BC<5tK6u~5R6fG6lmyvwriXU z90wCxe!bU=nyMkl?62#J&|$AD;=-c^Ul2ncT439FCv9F}<@3}WVsh0R6eGY(8+6;Z zx$4EvafRjSt;$u918fW*SoFXsVBuGhy*hhT+PC9v26sh}2r%iyJ^5v>giNA{^QP$L|8+HB`!BpySmm?Cm;qB0e8k@b=|B%KFjA*JcsbXKt7*^~Z# z!=rt|$8k`-WL~#=t%4ZUoA=UFl1cp=!J2oX$|FE$sQBHLs#xzYIU@h!S34Dbi)RO^ zS3tE0>Jwp$i$9GfI_(frMLdMpaGOo|&Rj&Yy#f&;J$?=rlr1geKp1AD2Qm#;W2F#E zAgRd~Ns--sMF|`&)HDtSlz+Kp+CJ+G0e3@tD21nhF*0UaK%AqVQQ!W$b?;x>G(s^v zJZ`nmMFMP3)G`sES<$FQx?>fTC!Rn~CC~@}X{$Ed$^V zAEPec`SR&nio!-bc7NRE6%4W32gWM=iNmEj&yuN_98;fy>ANNZEf9WW6e~@{=CtXW z{xhRbVEBogHSTc6s4cU9eb~JHs~XLLcNjvwS8syn{ZzH26ZOW8%N>l%0G_9uYiq30 zdN(rHCfi8BZly%w zpJ?I#!SvzX&6aWV&M3)={`)S&n* z8k0&Fi)RXVcmVSP&+2YD@CDP?^hZgxy@oGNHIW{x!K;Z0g&?0%@T|=o4umU{IE(4h{ z1xvg-aSEVC7>sndRiy8!j*?hd;g*)E-h&V zcm6cQigW7TO(xkDP$AZtV=5@3QuR6%9 zD1&bHtC9px{=ffmqKCpHL=WJ(ACg~MCkvhuCWaKyV&lK^+9~Tl0;Mal;^EN`rBp|M z>Bkt>oTWmg-$a6ABsl?JsHepLtK-Y#q3pu`Z(E|GvXnBGB1^VV${vZKvTrr0$4HY< zXk;BrLiQoDE5=e;9&2_bA^Q?B){w0sYu1_fjN9|RpWh$9^Ur)fbKmzl*SW6iT<2Q8 z=MeVZaxpA4bPOBBK8`h^INB?G5Llu3e&(WRR?P*$QtXmhni>6aB=6fT8lM*M>}Pj8 zP$6}g_thSv$}-yTpDAX7*k(WkDhAbU<{Nhx9N)qu;P;%N48!zdgksv6^D7j=S;!Qa z2Q%7EkWr?#>WmLX=-a(3v!9Fy%6CWKoYm|d89>@X3|~<_zVHbG6EPWZ=CZR#y}J(bqo3K=XeR8%m9K;)(O=hjVE_<9u8iqBHZ z!LFsukQj83y($NGoj|9moaGwZzjBK+v>G&)K5)}f`H??USNAIiURPq$8i}-e`X&h_ z)|Xv24kBpSKbj@^vy9GI@G_VRL>JhqeWu@q;xWfSdpc#mOg1d+N@Ic%!lPHTOe?8K;>E z%Q&AQIE$aXp*OIh56|XN!GpM=Sa#d#WlE<7iG*0CgOCQ&Jl9hWz*?@=@$mtJ&)W~b ztE#KjZ}CFUf)ha()R~~KWzeeXW0@gMdHGoy2xoJ@9;THG3&5m;Aowd5Z#SSBI~qr! zdq&`ghdX>;0d+z4Arb%cnMwHgK|mt>|8Hix2+z04xgt;?kvMyB|KCT;Z)b!C8#K%- zXnjBhvTDb@`(8wUKQ5TE2D z<~HSG>iN2BQFmb7(hun4pRb@DOGy^J+9VD|ZX0lJ*ywP!dqfI5vD#5*2OTSS)6Bq{ zpUMW6c&B6}F8j`9aQO&4i^V`WQrDnO7VTJT#`W++glR1pzZ6NS$C=s|N4W!0qG)_} zvT61g*YuVAF&HK)(UV{RW3U$P$iq5CP1~hye---&*Dy}rp zzHtnTp62^;y2RdAG=6FKv;~yL`12a|{cACY*M);hk6PJ^8a>f}aR|E31no9b^YWrx zi&gDIndkL1lo1}nUTEZ6l}c8n1@&}I+ixN)a}+P7(a^*CSk^dz;~@pPhH+rH-D@|8 z5fg^7psqSDZ8P5EXFIaL-6hd1cfxc2^gizirBKr>$F}gAL5y|njw0s9Idui6Xoi&bx z?`7gED?c;LG^XX@@hk8K3OJy9tm?cofwK?mUU=+b`}Hq^s*^DJmI}V!%G#BWP&9h% z)8{PrZASH(82eE0vZf{{I36nx%ng;IG`ZJ-Q9yr_kpzQ#fKUI|xq?vVy@Cr5iS>y1 zsdsPqX{R!H4&xeA3c~y5nHsPo?vq)W^3nvl zoYa;4^&ekanQq2?*>PkxzLm98auJ@Wln{|Phx?EEV{@$f2_*=O=}dezo2og}|E}H< zE(#;(EHmV4N*r$;VM_au5ybMJA{=QztiKkB=q@c0FY1A`b+l*xCK137i1jgT6?yC7I z$o$~$R>6zBtwY8Tp+Tdtu8H?QHoDMH{ngRdzY$B5@g12|+H~&j-(P zK%f9emm8l*HJGXuL#uqS_!14YhfkD{Qs~4%SF2n)81eo8V~wo-?IPsr4=&ha+J1QJ zybLiy8C_$9g1&{wEA+#*$h~f8F|0d}Kq`>OH;0nS3X>GTG1%YDrHBpSJKozAvzI+OpvbH%{yV*j4ox@ct12z@fh8)kk14v6SYJv^*mIa+#&QF}^_u{W+xqV2MbW zD}B!<-$SKU1qx?9xZ7nRDF6P}?0Xz6oTkY?R!irQ_hL$kt|Vhoj`e4$06-DLB}Y&H z$25@jgzL~gZ{EI`(^a1Crf6V@pqQn3fRj#4;-%f5DF2-4(XHLg(M5Q!MNEKWZ-BG} zIc@B{nAk+ug}#r+>fNgvK@^B_bUxoTof?zTh;r|{k@9zVre!U^74(UYg99rKP{_m$x+a+go*g!S9GVx`0kAT^!Kd zxYEA;$q%Qb55`_RwB$BQH5CH875VEOd(+^%i5^+$pCPsw?n{6v>V zRWoQclbQ`5&TzbDU%MGFEZ;pcknRErdoi0ovKbvAF6f`ajNAEgkl_=+=7hRUDQgftk=eoDOxe_Vx~6u+&zX>>l$}BufRw^@NoB&-;O) zeJqbIYKg~+bO#L$ueHXeTcg*S$~kqrWwJvp*YOL9~EqC?6rN3Y?!61))ns%j0 zi(!Yk+9Wf&)0@STU~bX7F3!k`Auf0gs|?8XJdZ*F z)+d@SDrs+nb4h(a#_MI%syuo=fwWIf8`1SVSLQ)pH+~S@7C%*8UiDP+F5@$|^4Ls= zb=;44NZ>Qb$@J4Nk0J{t7}?&;M|9ZtUddM=%zxF?=Z?S(HN6@9XnkV*tYk6E%f{J5dUvu-bdwMXn8Pqqd&(uD5~duCy<(jtPZv5zIn+aA}cCOn^{m_1KD8 zSO!R^s8qXEvXr>G*jWi`Jh{o;fS~bF`?^Oi5dh+?5F3<4?#^-2)7m2S3gJe+|tKAhR&$}Yt-B?pu}6UTN7(yPb|s0 zv;DHsIzjQiz#BTZ&;OV_T8PcT!E;tF28D}KhRkw2KxOMX3}vco4px@bGNoV7&iEKK z=1aT3InAF@U8|zJnyu6)3f0H(cx<@^EMOMTbJEK{89J%P2rtl?LnMucivY5;GCG9S z>aZtv<$8r7l&^u(JDWVL52}upq#j=4eBqo+sT-DfXt2LKf!yBe@-1U&__o$jSh*mj zUOkz=+tS;Z$s8Iasv7XX<6IFkJO;%9qBCIqdKs%chEyW^SjCqBTcF_}%xs@{B~EFiKR zRC6}I`-M;{*h(@>@~_f~%HI1TrN+30Sm6^R|FI(P=X=uUINOMPW!L11+=?z{5iZvH zbG<5{YIC3^c|VkvkXdv+$V!uc~HAAq^Q!Dy(JR6j`Bo-Xc7BoKe$?0|uH)O5(n8OgJcs8xJcWpd1*!dng+ZJn1-zcNJ&_R&F3 zxIdC5CM6D=8%u+*H@w`5pF4l)cDAcXn*v=i0@Lr0^S%v&?lUF4%Guh6Uqb~R^EDD$ zl^+)eP~fGrt2+GF?KEu>@Oufy^p`!av65%GN;Ji2lP)_HzhHR>KG1Z_wvx{6!SG8x3P(bFT}&2vxQC%*l)yg5*BdX`CUgQlcy_5Rgt&T*_w%x@hQZPt`Lo<>ZK5nV6%)Kgz zPX!EbQ>L>@rd4&~?5XgeW@~fyqchH#UQZ8A*Qn(B(d1D5yj{)R&n+jAeXkd=IY!xm zDefkqE;C<9Vwz}t2#UzhkE|jjFVz~|=Z7~!z4*=8C&s2ttGt*9VYPnijz`@91aO%w zAyDn`P2fo02R_F%*5?ayLj{k?{<996dyeajt+y;VI@$8WmsfhWy;u(0Zp?JkVm$CQ~CSG15cAg%L$eedj%F+I5J!1MmN(GS+-7~BV zAa4ImaFQG`-!X>g-d!etE2q>SFrNJ#oi#HqlxjG`@B3Hv=vQSv!ng3v?YBlc(qgx! z7PL0%!f8nrp^A&A!JRNt(To~JKF*F%d$44?X~ z1pr|A3m(5a09198qc)`Rq*GemYwz!15z_4O5OOjAHxEv6KFrLxIqVgB7J+czXtrJZ z(Q~?_w&W&N(PB?v*(8{o$LorPOha++(97-&b&6-@6qotzvFm)ZX$q ze$|ml?P(^hQe1jqSw{u}-zOZpE1T-@omzMUwbl#3fC{#ApvvpAf-$9r6r7Al8Nv zdii=(kkSUtRaA(k6jwjjy;kj&*^de@wRvi&eu)k%ob>Hv9V&c0atN<%R*81=SF3Cw zI3op}AD&Lgn|GmryJ>!HKKm0N&r5f&d19_rv=Xg?R#oCJ`yX=1=+h zw|qMc{}M?DFYQSdU=RRwhR@h30c92C@?5W?!-7|k0p2wti#V;eyGpkP-M}uyUOvh% zf)pJVrMYp2ZvXiTa0i9~;D`eD7om#cBsJB9dK_1XC|tep+4(nP>tz@~`f!?^Oc`HZ z)Ygt-{*PTv^eKb&O%)>lF%5%d@aGFY=NSfRFD%Vma za3Wk#i$S*^AW?$%6dywW&@p8IXTx=s!Qls1am?bgtaxx#H-Mdv`Rm^{dsHfKz&vB_ ztDN%9Q&fZ^Xl@hKYe4cd7PYo+QLnqAYan;o#32(znzas^NI^v*B(QajjOGl%;bPEx5#Wd~LB{UQ;^kTyS2%y+7IQbF=V)PtcRiVyHK2qo$-8~9b51f#O_QI)x<;0 zjafBIq&E$SWSKTuoo=ymT|-A*E~(vjHSQw~78k+6MbF+0nH5)d1gcxld9zx{iz)%} zb7Awzd0mz=+k1Y-jAOnRtmwkRlHvjzMR8;#o{B1e-F_z3fhXlxX3xz8i2;$H5_Ak- z7mvK!LaVQF5Vt0ZV23SjjH)n1L3^B={umW$r`K)i{<2)RR5jW{8JX9NKUck)FH3B+ zahm>2vV3B;V3qT5*xMNZ_O|Dv;Y}FQTx!$xnoG-Alic+Pn|DB6I48yw*nClJO8G{& zl+5Wl2lboEMg{~V2cG?#Xq%!#-fJCWJT~%i`!hZcdfsZA@hRQ)ze3u3rU|MTw=q4! zr-Hatbj@a^Zwo*J#hwf8mD)j0^MSYRz00)@U4BB$vq*R|htL7#Sx)ml#iJJemy9~9 z)$dzA*!}b}mdaqC8z5Vo6EL0#w26F9GrZY?JRCFI3+`V(&-~<%z9CtyT>`un&|NQ#zPu+;$> z?;(Nt7WHTC1gk`1eu#p+w^zMw{!nWDlcyh77ymU{4hhMx{^vwK4@^a*ockuTk2)UU zvwSK?N6pzOq+C;+lPk}cUWpz=4qw%HtR3g0U&e6F5BejQizkcqTLbmJX~%fckz#!& zO6ymb^UUMf(U6~8{fT)gWv?U%dlQ5LL3O)Z1wL(VqL^mjtU6yNEVKzg8R6e3AX1jMh>E3w-4k9e}%T26?~ zD9)uDSw%&3cx9nlUMk?rCO2-=!&8T5gB#Ws!i`>wD&ggw>TUBb>wPRMDmu?z>% literal 0 HcmV?d00001