From 518aa49205d15094b70dc6f56649e27fafbe2331 Mon Sep 17 00:00:00 2001 From: biffgaut <78155736+biffgaut@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:02:52 -0400 Subject: [PATCH 01/14] Implement new construct --- .../aws-route53-alb/.eslintignore | 4 + .../aws-route53-alb/.gitignore | 15 + .../aws-route53-alb/.npmignore | 21 + .../aws-route53-alb/README.md | 99 ++ .../aws-route53-alb/architecture.png | Bin 0 -> 55118 bytes .../aws-route53-alb/lib/index.ts | 175 ++++ .../aws-route53-alb/package.json | 109 ++ .../test/integ.deployPrivateApi.expected.json | 551 +++++++++++ .../test/integ.deployPrivateApi.ts | 37 + ...deployPrivateApiExistingZone.expected.json | 930 ++++++++++++++++++ .../integ.deployPrivateApiExistingZone.ts | 52 + ...g.deployPublicApiExistingAlb.expected.json | 779 +++++++++++++++ .../test/integ.deployPublicApiExistingAlb.ts | 58 ++ .../integ.deployPublicApiNewAlb.expected.json | 926 +++++++++++++++++ .../test/integ.deployPublicApiNewAlb.ts | 54 + .../integ.deployWithoutLogging.expected.json | 407 ++++++++ .../test/integ.deployWithoutLogging.ts | 38 + .../aws-route53-alb/test/route53-alb.test.ts | 384 ++++++++ .../@aws-solutions-constructs/core/index.ts | 2 + .../core/lib/alb-defaults.ts | 21 + .../core/lib/alb-helper.ts | 152 +++ .../core/lib/s3-bucket-defaults.ts | 9 + .../core/lib/s3-bucket-helper.ts | 22 + .../core/package.json | 2 + .../core/test/alb-helper.test.ts | 390 ++++++++ .../core/test/s3-bucket.test.ts | 12 + 26 files changed, 5249 insertions(+) create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/.eslintignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/.gitignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/.npmignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/architecture.png create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/lib/index.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/package.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPrivateApi.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPrivateApi.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPrivateApiExistingZone.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPrivateApiExistingZone.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPublicApiExistingAlb.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPublicApiExistingAlb.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPublicApiNewAlb.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployPublicApiNewAlb.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployWithoutLogging.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/integ.deployWithoutLogging.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-route53-alb/test/route53-alb.test.ts create mode 100644 source/patterns/@aws-solutions-constructs/core/lib/alb-defaults.ts create mode 100644 source/patterns/@aws-solutions-constructs/core/lib/alb-helper.ts create mode 100644 source/patterns/@aws-solutions-constructs/core/test/alb-helper.test.ts diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/.eslintignore b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.eslintignore new file mode 100644 index 000000000..e6f7801ea --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.eslintignore @@ -0,0 +1,4 @@ +lib/*.js +test/*.js +*.d.ts +coverage diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/.gitignore b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.gitignore new file mode 100644 index 000000000..6773cabd2 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.gitignore @@ -0,0 +1,15 @@ +lib/*.js +test/*.js +*.js.map +*.d.ts +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/.npmignore b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.npmignore new file mode 100644 index 000000000..f66791629 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/.npmignore @@ -0,0 +1,21 @@ +# Exclude typescript source and config +*.ts +tsconfig.json +coverage +.nyc_output +*.tgz +*.snk +*.tsbuildinfo + +# Include javascript files and typescript declarations +!*.js +!*.d.ts + +# Exclude jsii outdir +dist + +# Include .jsii +!.jsii + +# Include .jsii +!.jsii \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md b/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md new file mode 100644 index 000000000..295318507 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md @@ -0,0 +1,99 @@ +# aws-route53-alb module + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> All classes are under active development and subject to non-backward compatible changes or removal in any +> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +| **Reference Documentation**:| https://docs.aws.amazon.com/solutions/latest/constructs/| +|:-------------|:-------------| +
+ +| **Language** | **Package** | +|:-------------|-----------------| +|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_route53_alb`| +|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-route53-alb`| +|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.route53alb`| + +This AWS Solutions Construct implements an Amazon Route53 Hosted Zone routing to an Application Load Balancer + +Here is a minimal deployable pattern definition in Typescript: + +``` typescript +import { Route53ToAlb } from '@aws-solutions-constructs/aws-route53-alb'; + +new Route53ToAlb(this, 'Route53ToAlbPattern', { + privateHostedZoneProps: { + zoneName: 'www.example.com', + } + publicApi: false, +}); + +``` + +## Initializer + +``` text +new Route53ToAlb(scope: Construct, id: string, props: Route53ToAlbProps); +``` + +_Parameters_ + +* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html) +* id `string` +* props [`Route53ToAlbProps`](#pattern-construct-props) + +## Pattern Construct Props + // If no existingHostedZone, must send hostedZoneProps with at least zoneName + // Public APIs require an existing Hosted Zone to be passed in as the amount of + // DNS configuration required can't use any defaults and require a complex + // Construct hierarchy to define - at that point the client should just instantiate it. + // Private APIs can accept props and create a new Private Hosted Zone. + + + // drives multiple settings in construct, including + // alb.internetFacing and hostedZone creation + // This is a construct level attribute, define it here and not + // at lower level service props + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +| privateHostedZoneProps? | [route53.PrivateHostedZoneProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-route53.PrivateHostedZoneProps.html) | Optional custom properties for a new Private Hosted Zone. Cannot be specified for a public API. Cannot specify a VPC, it will use the VPC in existingVpc or the VPC created by the construct. Providing both this and existingHostedZoneInterfaceis an error. | +| existingHostedZoneInterface? | [route53.IHostedZone](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-route53.IHostedZone.html) | Existing Public or Private Hosted Zone (type must match publicApi setting). Specifying both this and privateHostedZoneProps is an error. If this is a Private Hosted Zone, the associated VPC must be provided as the existingVpc property | +| loadBalancerProps? | [elasticloadbalancingv2.ApplicationLoadBalancerProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancerProps.html) | Optional custom properties for a new loadBalancer. Providing both this and existingLoadBalancer is an error. This cannot specify a VPC, it will use the VPC in existingVpc or the VPC created by the construct. | +| existingLoadBalancerObj? | [elasticloadbalancingv2.ApplicationLoadBalancer](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html) | Existing Application Load Balancer to incorporate into the construct architecture. Providing both this and loadBalancerProps is an error. The VPC containing this loadBalancer must match the VPC provided in existingVpc. | +| vpcProps? | [ec2.VpcProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html) | Optional custom properties for a VPC the construct will create. This VPC will be used by the new ALB and any Private Hosted Zone the construct creates (that's why loadBalancerProps and privateHostedZoneProps can't include a VPC). Providing both this and existingVpc is an error. | +| existingVpc? | [ec2.IVpc](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | An existing VPC in which to deploy the construct. Providing both this and vpcProps is an error. If the client provides an existing load balancer and/or existing Private Hosted Zone, those constructs must exist in this VPC. | +| publicApi | boolean | Whether the construct is deploying a private or public API. This has implications for the Hosted Zone, VPC and ALB. | + + +## Pattern Properties + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +| hostedZone | [route53.IHostedZone](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-route53.IHostedZone.html) | The hosted zone used by the construct (whether created by the construct or providedb by the client) | +| vpc | [ec2.IVpc](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | The VPC used by the construct (whether created by the construct or providedb by the client) | +| loadBalancer | [elasticloadbalancingv2.ApplicationLoadBalancer](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html) | The Load Balancer used by the construct (whether created by the construct or providedb by the client) | + +## Default settings + +Out of the box implementation of the Construct without any override will set the following defaults: + +### Amazon Route53 +* Adds an ALIAS record to the new or provided Hosted Zone that routes to the construct's ALB + +### Application Load Balancer +* Creates an Application Load Balancer with no Listener or target. The consruct can incorporate an existing, fully configured ALB if provided. + +## Architecture +![Architecture Diagram](architecture.png) + +*** +© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/architecture.png b/source/patterns/@aws-solutions-constructs/aws-route53-alb/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2858f5d019bf39903639de92e86eb24baafcc9 GIT binary patch literal 55118 zcmeFZg;yJ0*FFpsm*P^~wYa-m@#1d9in~K`cb7te0;R>>EkFvz9RdU`8l2$p!TOEU(h0Iy!SQJ%icNUY3|pgLykWeSQnaA2I6dH$45Ph~aF=(ovs~y_=57g|B9W zDMbE3YIA`_yTr#b@awmXyNV$sGhK3^umyZ&|KeN=`Fh#jwo75`J%1!oQeR0`m2h;Q zVFYQau0dtlKq9OCkH5kfP2VHaete?431I2?av!nv#=1j8=DmX;!Wp0(nz)gV^pGWl z_Hv1~5GMlAy}1{G{3fg20Vcty@6cW=Nmg!I_gf=K$s!X}0>wI}ta7?-#`z?yY(D4h zQ>^Ew5=s_CEFp8bM}*xVcV-cj7EvgR(mg?4Zkv^#mHI^}+(50~Bs5^(DI)HEr=sJ} ztiT;YOQVf}UT6ZY-VS}2xtfW5&7RC$G+0uI31aCnt0Lcd+1CPW-f|`fsR^HLvoB&m zHJT3$_5c*F|TuQ@Qr}@hikMsn!{mP z!iS#UgYPB%w|^tjKmNn`Nll+4_L!+O4-S}1+Camw%gf!PAk}2ja<&Co-h6>a*kiNT zaiRTjb&{V$zjS3ij-E$H*lSH*;sa5~z RElieUy9ZlP*bqYyQ>dNx(z5v`%Xs z7j)NSjmf9NUc}3xz4ftH@49mn`9aEj&%|~`P#6w*U580_&@1vY*g>)kEnq)nF>xM9 zsb_LnjsfBXtG!Xiv&3i_01DQnw4wiF2N6(5^nuOgPn=X_R9_h30p{-30J?GSg|GXZ zo=4H%#BN)TkQ(K~BMwuki97cu@ePDfaJRX{d6u*eInQ0-feIzIj L|v& z5ZC<1^Ksn*juJ6hK9-Up91SJSO%!+-yW8s5-g>{gxciQd`r@-)-Jg>j zni(G#o 4|O0Pa0#}m)0B>I(GyBKwAo1u!Ohk zR=vFFO&kt~hZiQJ0dd>A_ZFMAMyq)gn&wle+#6tXWB4yeK7&=`G&`Hh51Rc#zTbyi z@9rRcfevQ7rd~0My~16nvA|a%X4wo~CQDJ2UFDE!-Y7ybR*Dr~qzQ=*JY%?*9>P~n zzO!3)vU#)%VCJdH}H=p<=`Vhe1dP?as)-)1b=i~!P!=aRU`ZZuYjyn80Gw4&($tWLu zT!roGq4622unKcK>$XYm M*I zV>$aN5KEBbDR8K}^}xfDYP^^3F`={ipA2t~xJJO*MO(<~gA*zgdb+j(5>|wZ qf` 0M8t^WvwQE&CbDFow`=6d}&DU^(hQiEdh!jaq>whCNQ=lIT-)$ z{o2jqro#1vtahMM%Ub7~?P0lXJEz~RfklP;VCxeyas^6Kq<)uVPp%slbCtYyXn93` zIN6LH$g3UD&N!Lxt$@BnY&2=~AF =!z5B;cJ3S#M^?^& zFB&(0BFpmdn6zG|&7s}*^q8IHqJ12I#lm%LoJ_XcTYFe$Sra`Q>UlfGppGN+8pogy zJ9g3FsUCu(lcR5MZ~mE1P6?M}H=Kw!GP1WnHtnGGJVOMu24j;37JKLJw>R%i&FRuh z1*j%7Q|_fYs7e`qm0u)C&kL=Syq7aV`h0r9ee>y#J4|^Z$gff~cK!aps|5sDUh#6W zj#m=+M5(BwYa#5tTd&qjK8(_Wt@&CA0`~QZ6*cRcaIJsrwpAu|#!XhQE}Mf^k6G{( zk8~`&_Z7(vFuW*#%jqs^8u2efI_( Rc}atT+R#p$xEakYv1 z(}TZAQSg=}1S6o(Rt`s^uafvTbUEN6-3U-SH7np4sI_9V>RCEgfORSmMIY>Oww`H< zh;SRq{owV~+-EZu^Rn4kA+mH%)12)%y>A%P$z1p7$j`c8A5?}+u^@1*Z>%?8w)J|~ z?-2w#4(@9*v}?hoAGa>es$G(aqo+=666&*^t$WE&qillvCI@SZRzRhAZxdLi_UdiW z235?U -pnfGW`i@H1&m&28WhDHiatAD{?)-m|7A1 2xfl=->--%c|PaatCzsoTMbY3k%|CZ(u9@;C|x_s}2htH>cI1EPE+((Uc zVpRWBy9Pg%#zB`<3&dsD! QvRZGEq6GO%G2TuM R5kQ>;QM!l(` z=9so<6wXnfOM}8lWm?nt(vv%=v^nx(TEeeS6@vK4{SJ&sTkmUTWMq4=2gE=ZiDPrY zjP^z5_#=l;&<*HogHfZQ?3C;&mbj4>v!c%5PI0ZwMT|tnv0Lb89vV)l((I4N)FP`2 zf#2&X{OV$1K|BClTwzEbx+zq2YoF`E<3yD@^s}3)$KQ%1rI+|lBi@9;)wF`%A%4^> z=|MYVM9QMX&Y$2`X`NxD{7ain`Ef)+m{_-oCFIbny?k6kJ>0 lB zYP}tz_7wh1l_m0h#**rA&phfBSHTXB?zJ-v3;_&!=O`V+klOehX76m3d}IeD^_!o# z28{AzuG1s7b-TyDQQe&1s<1-m>Er@9+mSwsVuJ}Vg7?u+(Jvn3ke+ WWZEQHjc?{CHJCt;q2VQM=hkb =eJ!P`3pcmnJV$sZ*3j#{`J7) z&RKvNg2SS6eBfQSFNDpy9FG;uD-zKxq)PaVCXTei{*;fX!Q<7RL>o7Znx78#`Q}Qm zGn}q1gf8edZE|jQ-F2U%fF8TT^~4QKHq6Cd3 VJxWBA QL$cK_wswc}i4#ca^-h^AvkMCK@c4qwLy94` zm$;36I?y2IQK7-w#%1r=!Q(e0$PWh!9QEX0DdM3sm38ip>RLzc+Bh7#L5@0y`tAU7 z=(ga32~5r~`V`5l=Sx2V=}G_|=LZ*@?~&%IlIl^#_l)6iWXGR*sI}#kvxnIY;NFWV z8Q~LwiCoW_F6;w4^ENY&za47)9IX~J(u)Vj8bHWr4(L)-Y?>5B9>vy3;_$M~Skpwf zmn|elODNFbmxWrgi`uA!XUN;&quU=Zkf>hxW4#|=#zZIgn!+LD{2N+&gZX7T$#$V) zns7|#aArMm(SwNg*ioHQ$I9<^pCIk2`vVO7fXO9RqdXz~zH )T#r#(*B)VDqE#98cu6x*LhsyUp?vJB+V{ zVy{+@kNi-n-DYpG8k;s~;@xF1;=dU9ZP)3YceTGbP3Vypdp?n||0`*}bXLR``_WW? z4j^G#xZQwf-RT* EfSssw&ANFVlli3Xl{Kgrrj;AAb+U-*+IR6XE zGkGop^`1I_gW--C?B0Aqvlpt}#4Iy{84Zpt6}ZQ%em>%ymw)&@RUS<9VDGk}r~!W? z+I^o(zc;fbgChvITUj>bC93I|8Rs7F`a`>G!`$oJ$G@Dji<@TYqC|KNLYX$Fn0? zBHnTK;$UfB!8gt;h{xjFd_J4H@{wC3Me-L?Qn%DS%QZbyHSx}($}P|JNA7QPmrO(6 zG*`9PTU`n^j|-(>zNe&(*|u$iF&({rwAEJQgG~k7QoeBadb4f%w3FQ-BHPg!(%H@W zvdH_S)Y7YHldn%|L_l?b{*iUVH>AphLG%=UZ=RWLEdy)es|h-P2@wD6G|G(p>J78Y zpC_iLO&^uNB2S=P%V$g}r&s _OjMVFMtI#f(|jD@@BPKF%4XOrUqsN~Jj_ik6*b^)%t| z+?Lr~j;4);Oql9l+u`^2S{peQJ)5i~1~~sz(YP3rvR8+{-F|KJZayvv|HIl&4`qW% ztBR>}$9lkDwt^?aViiy8^3Q*F^RC) $qQ#E!{%meN=wXyY+Sk& z3i+*708BAv?y?o7&Swc^Zu0)ew==%q{3VQ*?TWu2AopCgF7BA6Aw}93v_I!^%hbvT zP$Ib{zfeDSBPKzWq*{r2;7)s@%jDE!Lk~|l*Az(`>3ZBDVMx9!KxVt 8E}EoW4jXDV_=@`f%A)Pzb7AD8#G`E(AJi8)ZplX;s?F6XAAW z5PTWq-|_sR1BGgr_y#u5@0~%8F405hf_{1Dh^^Yo&A{?k>KDq|tg_gynLIm)GtG yxD)Pm~>TCKhD)<>lBj4(IbWY{P zFjo)W*5*lHO!1(Wl(O@IefX3Yt!2MBWj`i1-4fJ)zYsGm_D$or$J7a`DPaE)fgAmG z3eHw4w$S1@ c>Im+e6QY`S6So6e1oDm$})5__z;(DKH zJ8;{i7)mV9$t(%*PGEiWDWbRbrxQ6nZc~;L0XSZFi`caTB0=R>AJ^9nGDY6rPnirI z4{|8iMY2=cGi34)zs1-$>dW}p9V22}G2-E!2Xurvfy@r945peo3NUS|FrVBM;e>Z~ zDk&Z)?iYW^A_Cq|IfY98I-o1vus!W!jNqBfHQ`_Z1fgPSQ%=t(kzZW~7rzd1xhQmB zwjDO|36Ldq&s7n1$)c_Ix+4S~&HQ$QmJ`m$e`HVe77Uf2D8P8-wm&m43NJS5pz1aw z3WlB-9MfCXQfDH2!QWfPQs9~5jj2p|4zNt|)o=-Y8`bha*?IlypV|;iZ+BR2cWY4@ zf_|xK2)80{Y`lKXU$9>BjKbWXunrwOn%R5-@75Tr#n @GX8k@ncxb^yOu< ziO~TYF^~!5CP8ki&aQWEGLs8#>^d XebVYsqJt^uk`wD)vx|&cfX7#)7 z_iE~N+R;KLki^WY+ksN=T#Ip&9;0R*xek(LU;J zWRlro|swdXMFy(ZUU(m=sWM8~L>MGFJt6b(oH6>@syn{h$y^xxrj8 za7IR8+P~%YismS86aIJbdN=`-@3^D(iBHvdpix%UG=xJ^m@kh#Rh+!s!9wgBzEz6a zCf6T={SPX{nR|m2BdYfnJ8>Z)G%*BzN}p-wJ49)|;K?D{{TAayb*{M3C)oN+5h(WF zB<()OuvOSi(bg=R1fBHVBx`iGx-Ti$0&c;r{49$>&O3GYGtAwb_53<#_0^fu=E*}2 zQf{?~6QijSp=JsPQX`#>!(6*Yw|o_;sUb<=$J^nkKzMTldE@JkxbI%s;#)i vZfyNzupXXv}P(I@<4bN rS2g=+;};tB4W1 zY*3Dh^P-`1ere?Zc9{dZAX$LNxfZ6r?_V3%zBf`nq!}Pv#FX#axPB9!T$jvERhP;U zj7GLfajHv7&HYfQBGMIh3|H{%i%aJjjQ>bxI|yO1J$PMgJE~4*lNU=EY!wu%JBoDX z+&dJq@Ufhdv{Qp^-uULpGKDRr;7zHMT$CA&lKv`fYUim&FEE &Py;8~ zW5a>W9qygBBaL5ougF!psdeHr8R$NIg_{YsYihnJW8@oBe}t7eUx7 d@sfAEpd$;Mu2BUj9AuJX0*WtLA#@z_No^_$0NhhJOx%9lzG%bK0@B9k>9CtgIX zEJqW~Ng=p@1)2!x^g%MIE*b#gs!$5hJ(bW#!V{m1iwdF*{>!V;@-mwa5dNFZ4%4Ak z2Lieeuf3k?Duz5nvv1YS^}3FEE+WzWIm6!F&sJjl{k27o2($8Hh4X!j<6>2z8TLxU z5d$r`-RjFP37gIpBeUA8Fl1b5`n{z<3?bu)QA=@DDX(_LWxi^?ce4Erne-MSqm ze2VVgBQg`D^xKbH878u1uxmR2`rd_!GK?Spwrxe?ZumfGorEA4HzCJSnc208;!G~^ z)hnXls|K$`f%a!_&~=kJnGD{aYV(pRq4Lak#)aj-$bfb~D149B+W9?BU;1MqfYiZ@ zu&=}7H+ePYYMM6c$>1bO*#v4;q^aNjb{5gGaMF)W_i*(tU&R8*_b *1Ga&m+!&Qc7_3T0y`wyOl9O|dneOHwdF{BpwDiju*F-Jsv z?T12tietrHYbQc4>vB|XqVHC` p O-8l|SZ9HA zHp+FX2WHJo>05vi^y(JPadT LHA{Yk0t*WnS#U-mJ=1-w@e z5(+PBdO+3Coz~dpw($ZW`;D-PNGjpqXe);My?D(vs&Q2$97PJLs))P2(OnvnbzD9E zngELkeywG}>eC~gWK!u=7w607RKb99?=2Dd)(@h&ZuJoDXR+m@E0|DcFXjBI@8vdw z&Hlrch!+hFas)u+BHi_3Wn;#(&L-xL)o~LWd!=#?+?;LZ19z`S6*+h5?V&l2ij)p^ zRjm3}(B`b~`6uHs; v;kUr u Qq1+eQW0G{}$YJ=)ZuiVXRfu ojUueRM~K!wz+Q22 zS^uow _h-t6^2h#F zIIXMv3Haiv+ VEw~S5h#@655|(|as%6Cv=#rGiG&`dZTO~`Bdu+uJ %z&_*(|U1!M=XHOOZ8e(#_ z3R|*qCh A%t8k~e9^v@ zfBB@%Gb?tcf%BYSO^&e}W9rRxPvFVA*U }ZVKe{EtxO$A0 zUTC1XzfXXab#xzetG}H$_jO7II>A3Q?}S#{fXQO!HfY32D@lQ^vE{{r{V_o9#f)Y2 zg$>U#9mupy{LH-GEPGWSOy7v?fz7}i_V zvVak;Z?T5Fu|nfUtrXwks{ zIMAmAwR@CVp6E4y&*8eWUEz &AgT|J7zaXv-9~ffeQMz#p#0-Sh_|n-7=QV z`LK5Af#-^WE4Puo(&R>Sg+hTg|DZ&>a=;ffonSjzOtCoA3$1@q)gQd^SU*;qqJE%G zvCLPRaTZ@GLSZjk#Jq~L$BB4(SQ1*LQ5$4*%TJe7W#t~a^-F}}!ix4W-O}}917WO6 zvhftw1l^l&Cbm)@_l9EON)EMpr}u%!?GpD5)WQ1Kqp_4GyKQ#qWMRqHDk3$ktm%5Y zIcn?DC-ZwD+Wj9B3AryhSDQP#u67OqM0z)?tpX@n>SGiD){AJTKzwaKmnC%M#h^|2 z;%k1kx;~iJx-{L}dAVJzS}=f~h%eez!CPgeZSthevT!7=cE&0TcCqNfc@kGU!7@3y z =!|xTE+k#gg^;27$ zJylon-iuxZkL2(03;LlR6};kcMv?!OBr#WhW`;-a9@V# tEy+mj;+roIR$%nAR--ge3Z01OUErw&T0Oa9KgS=7f<8oNiC zEcHva9aGdX-EH+Qq1Ysw!MY(^pF@2-8lePRC@eX2nY5Z&9?%R0;)ecK;J-@a7x#pI zivoK}j~c_g_G0qt46onr{~SkUe5O*;9nMvzuIU%O6k&7W1LWw8y$&F`d}&8+9HuiV zwAIk+7Gy8YvWe@I>fAcTwg&WkX3kuxpW1CMzj@i5+#DgBkjtF+TB7hIC3$xpkgZ&+ z#nXdPrI})Z_U7W{zeu7v;ZqWO#?cyT;L*k`rP1os80ezv8!Pnk?2gav;e`;a3ZZw8 z#O*EDr;Um1k(zzodbtP;+d*WH*VG^+nBa-5WJ#bjJY9vhUJT5aLJ6BFcAo2!dpahv zVIGo7!*&^{=&4Zs(7Od^3w|o}x%ymUw=DDqDg5a!(Si3Ee%r{k#JHNk0%Cr!PTO#&_Av z6i%P{i6UfSw^=Nd#*W0MFZ1KDvY>SXrhBA^#B$V4V>!Uu+<>n)k$n!wO>GvSIP{>I zHp{M8!*v^q%Q(hRLUaCcnba~~0oF_Fup?SMx?|8dDicMRrkIeqLAD9-I{HyjS%Sf< z=#IaGy;Rc;aD9y%xodwZ{E$dl7491A*<<% nxiB530M_c7cww@@d{T@@eZcmwdJkSVnP-L%{d%GUk?%CJ6Rxfs H1>C
>gD(s1zj+kh?(SOz&(f0}-|4yjQt5%`#cC${;CO*HEwxItLCFpv% zGLOlR!R;tJV_xfPJ#+cnZHSlK_Imi;Q#RL3ZZnL{wV_YwQOZQTS^e=gD7%_ zRHv9>ABwKmR4mXRu=aRD_&he+g*d|_2x9SGr*1MkVpw7%amrEq247!aNmnttRHRXg zJ`Jz4TfKc->`pCzP0ix8&?N^VV{=}o#owp~>)Jvo4UC2oZ7^P`WXR(w%hSIkXoc`B zC&)w}+T#1XUUm$ 53%RT zwMK^csAmy46)ZZsa?0NqGC@w_uX#9gx-+J28@sY=?GDsCBGT4iZ^fvtD2E#1htA#7 zynUO4`HvPJE84(l)AKV*K-Pu!rP{EPPk?kC7MQa=njWKG Vo z|F2Wpg@P-|QO*|`xX72Bz8h?g!+c; DOS6#H72_NpF#jN~AM_C83-8gv8OxH{6cFi&@?cN#ET{p6mZ z1nTE6y|TA0YW4~yt335d+z3-El4YizVY?VPAR0R#Bc`heZxaLHJ-m0MpkGf7hR^!x z`_%+E{;SSbkfH27*62t0JVM>)4eY#o6InHh (p!vl}TP41g3!&))T6nP ;6e4V>!XYiPTm5^s &zzZ zkluA!pwFNl&)nyS;9ARLgQtpd zK+`na-CbC`Vxg6nn0clNzzMy?g@BN$G1FNg^QDn)VXlU0k58(T1a<_)uPOBqUL~%i zb6%w$7cG*W2xpA{PUhhD_733jZ~KpeN0~0Gr5BI-0P_!fQVZD6haIQl$HPf6)=Aqf z%WCUD&9MB1)vMk4>rECw3 &N}5*T<$wDm-W1Vul*{hC!AZ_$w+GZQnP(u2eBH zX5+}3(1_s@NbqRlZ}gUbqfw&H g=x3+W4%D7JC>Yn4%aB_FPBw zG~-{FuKp=As&28V=-C<8v~GisDuQmy=tPFg-{lsvS1M*$FRSxs=DQ#52OgWk1m>ih z3!OhIp?*%~W#L;iDAW4xZqPPIc-O@A(Y7jWmjHW---MuQR2cG}2|O9R>Fpv1C~fTZ z;F1EbU{5+4gLhLxC9~+CIaVB^S{?qYtTfaTJ;(qe>!8m1$-YR**P$}0j2|&I_Uu~O z6+`-+2y%@gbQloG4562yQK)}(Ow_x8G6ZH}*nZAjk~E-n-8Z1X#W1lz17f{uMj*fc ze<*Wr)Sn!{3z{AcvDimwvhS&Zw?oCMJhfg8v7Rh;@ OOl=jhcGymrK~~c?)oC(BBkF$)QIcL+R>4)&<9}XN-HvyIP<{0 zgRJ*fL`fp>7D^ED)lSp+#AQ`rtn?7*aj2Gg!VrkbEI6&P-RIP$DyZ1%*}^kPpfD_Y zacT?(%RLx?xo$pNoMQQM2@?_qR+*TlPkztQLCJp+{I3`a3TppQFX&!iPY+*w&ago! zIioVEw5eF4ZWS5NMW}AqZ#J2kQfJDSZR&M}hRU9=ct8i?rglKStDz6) 3 zVC2v%eb824&iEj%p}hXK?|F=sgU^AsNJlYebcuzNaFDqXGo*IlOkj-Fhgm6V(aK7j zaOh&{KHGtQ8h<*#5AJA`s@>l&Is=!kuh->XJZW>yq5v&$3SISd9iQUA)$&^<+YhP^ zoyTRstV;9!*mu%oXGF|I%9Wp_B >jdr< zl{?Gp5&(am(UhwYaHiOgGAEOtA6Vrw)lqxztXsttoOM&TjF)wP9f_gKb30TV_+myq z)*{W!9Wm1#^6wUdGY3KXzO XTCbu)s7C^TIb@-$MoEy7US7A z*AmVMO-IBSHWpR61V0ZftW*|Q!}4(50;FRf%t|J53IJM`Dk2q~Z>HKSR+ys18<}Q8 z?G3DMR$J!44er6E+I38c#SdSKKPw9ikS5eut*o%>LwX7$ {zdA*k^dWs#1zIznVlT=uHU;;gK$NShsh1-Bm7HakPARGism|?*4rKz z%RKp^ERsGN1CwleC`QO9IpaAb(574LEc!RhIqfoCXGX`K|G}jWxI-haKzI+pYw}|m z>s%I`;!D6+h l!vNsa0ewKWn9=4y+~KVtS;a2!$Qd+%a)d*sJG ))K@9KFiS=C`tGdvwZ`<6zkx(YKv_ zv?_W$@&ljVq^dH8i;-&`SeiFbN3}ifLIYfv{#jN>> 82#!iZceSVJZ ze?OyoJqH$+Xd ML7ZLrirY7nDVI|L;yZxO5DYg6VPNKyMPI9D|5$BW(lx+4b)AbYUMw0;l2G9m%T+ zO?mYvE+5AEi)bdO7KBiXY31X7e%j!a?pZ-WSyiT=N$QBVO CJV!t%7%3 zev>Jf(eHrn-6G}gy(f6342MIKWrmgl?yhN&i*R29>XXa**@p6QPAmf~(8C`D>ev%V z--o73o&b_V;bM+T>fgH<{#*2xuMT3HZm)@mAUm97oE6P_&uRO7SCw>UW+%TFo31{l zouA^tI|h+$&$}Xz(<6Hq#X>RXpwqr9+hblWo}Mwo i$4c6}+s{cOZdMtT>=`Kv1Rp)h^oDA8OrE9XV(F0YhftIU%SY-P6`+z-X2 zPgVww0~K8eGgK|;!T$U;x^1C~#8gf9*3>9IeRP#G2e3Ov$W>CaI-&D6q#aC!*y+H3 zT1695LV#6$m&U&~sATx2vR+V*49G~H-(pHob9vS|Fse|7NS|}7X!Tcn9IaRqNNv3D zVa^{$J1r*w_gLLVFigs3T;WbjD;ABh+6gdDu_2k#e50 j<^o9jCS3)h)99U} z WClb~tXX*NrYB~ a^VB!b`%b8GiV@n~^rn}!cnX*OH1+TO&^t$~+R5;*qwR;p zObwa4zmODB#)9M8Y}J1n FuCSKb8uRLMWc^kb2%B3L|Hw$5^?io)c&gqFSa0dCl!4Ho%$UC0og|sF!}H?; zv!OHm<7zW1C!Ia)$>(}uLC>Qb`$FdFc8ij-{ZJiRbuk{GNKUJo@NjN^?X}RPk**)- z6fOr%`5+r05xPIuwfRgf+&wrn{CexSjLWXS15y=73=mOo(aa>)A7jZ=;6+*YOc|sy zOAQT$x+Jz%>sD8I5JG#W9BWv%2|CHnnR>5&+_nk3YW|fF7$}+=Xm#2|J#QEL?;$9! zEo6$4M2QWjAHeZS{bqQy)!pq#JDS7KLb0p3M=8wq_S6US91L zl3N@CO(Of_0ugTL_#w)>YUJCsr0^gd>e!!s7}%%OUf$_rlxvZeCT 7gMm`>a0Zjb=t?|JUAkMK#s6-C9t< z0!R@R5fJH0lOnxICj Fvvyl+J@c7!u4idn0CKt!A>mn_&nsuQd_9->6BgRGU3-frUZ=|c z2N+XQ89agp6W4RO+?$HB4o%+}!;YIuO;@Tn+Z}h!LFgwO6y@|L;uz6ZMuxrH6O$<8 z?+$4|-SFEr`2B}Xi=za$j@Q~2a7w4}CE`W5a(d)8l{cP&W9 o6if0-I zc{LutWOr(ql4)0zJ619C6{PGB*W#4U=3!P+&pEn(oGjni1WRI%r=TCOympyu#V*2G zpjNDx>Y2*Tho9|sZ}yaG3w{qz In ?AsOQKF|N!n(vaBJL)2E@@Iykbp^N;{BSr zvDgatp?OGd0czMAF9dAgT2N%O!7E~YBr9 bZeYhs$=bVT| z=Oyp$&=zy}(5Z!Iav4?8pxm4U*PAZv$1(Ix_Ec{^_f84<2nf;74f4uFL2M5B4{V-t z{J52wYj(CbjcA9`G>WA$eH9S29b 8g$SiAy#RyC@&|)Cq61Adv!=H?+ ziID0QYuNL%=8@SDTG#r!PYy;Asby2%w1Q@i+vYy>TZkRD$`RvAju8o@2L+9c2zfp` z;ZtLjxrCq1p+%MUG+Ky=smtJ;z~S$-eG)o9U6Eg=GPGjj{eI;?!utkCU-|f1k VD-qkx_2?SN10NmWrImp3m~Ec)YE>+Ez1HqtkoG9&os9 zy6MC7vo1^CCfTzFz*8N5 X}~5!G0wzQGDMiD>#~|?c5(AO$_TPDVoQi809@o@V7Wakz3t?B zw<*I>b*0Enp)$m$to7lx2YrB#6y;SzwlbWiPNiW|{kVa)ntVg>-Va~_^|F7yHN!BZ z!cE%co?Pa&dmqxRcoQlJi~5Vt mQfNvq+lzaOnK(4Z)VnV>H;7CvvbZ-3D8QL= z !lyv`*r@DH`iGbv?-x!b!|w^UmmB?RxK73Z^2G7jVk@l#=<$FQcAjaB!^Y_ zc&^oTo0 ST^PcP5 z_j;IVV?1BKYgTqfJ3q|({ES;$K&tR@xV9Azci+M|we5F2o =g?Q2Br>R6LLr%rWb|y*Lc9^}F2JrG zGOUY~{K~%ssM${sB0ZikpqqT#O+7$Jq{wAI=BGzfQcQkZwoh(1$Ef865hnO_NL0JC zKd0Xk7ygjR$@!vT9Hz$qy2m^slljIrA^Q$BZKoL>CHyTDPa&+4GxYA#qax6I1{aDg zqY$CFsh_ryCA=kSAhm)o7cxtC*FH#o!zd*xo~1>qE5${yH(w5@V2K-4`%kV#NkSp+ z@FryRO0g^NjRk+ZNHE&?dB_B!?>fquA+rtg4A~-5<+*{1zxQo$dX$t_CYh3yJl#>+ zs<=ie2gYg=Y!rNBa^#DYXC>nddV@mzm2AxRKCF}Z0m uo6hq`@=oTaFToy*O`{7H2w8+b)+Qm z&DBc2qKk1EI-Rrh7Om)2gMyCnn=^Cx=JPFDVT~T{w q_ZDg!sUhKWCA4;yJ zdR6M*uR#tg8xDYsD7Ou}`B$}XD0Xa 4%(0R^Kv{yR_cskKmR@CcXC8UY?iiZIB*v9Br=` zfqe!e7|_@e4jj4tH`uohaqpufN7-|ve#8#|UhpLdd)OEYvQSyczP8?vw|`yMJG^Px zwheOaqg`*ai%=X2*1k(ax^-_q{2N*9JSBmvV)xDE3ru!u(r$7rhTkj=lTyA`Ki5hU z7{9NlmmI;)!#{k#8I_@*>yYI8Jwneu?q20=ClE_s54YA z`Cb0+(Y)P1^~-ZNZhLyvG;KyP}z0)@-Si%T;X zBLRcz8Wg$c_!9j3KHsHF$f`gaIPfQJ^M~oz2i5r2EaIsZWtLM_{tGX!AQEzCUFz9% zqie6S*BDpayL8*oB2YhV=e|p7Cz(I{7onV4Ef}!#<#>C>`S zWGV;kop-Ejd3M6leH3@K%wYX;H^V?~WCs==uSY4dhNZ&(5zoYXniLGKfXxLQKVCyB zT#=dxl0Dgb8w0TzyU`oqUlUk~Hxzgr`oh#OgTcZoARSinBc{|lDk^y)mB4*skZe%W zqw_^vv!0-rB#{3)U(( lq5 zV>?TtqkjK&1+aRWcHd^Bk=0Y;oosg<=Z#q!rm4%6+xWLW4SX%!?}NK%!IwG&x#x#t zq$#)F9zEhi_VeZ09dNgzs72C4oTcD$LUhywb8i0m^y0e!&@8>uzg? -{n*zr5*&G4(Z<{`sv{n3TGP17-dNm{yFgXFGFl^ zp69MZ!Cn8|#u~8P20}{J@cTUfv?1#TJb>K8akR_tICtv7|7{zR0AkSi*~k3<`)tfw zCIGZqKHe+4{Xg#yIP)k45VPIST>C@r|I@r~G+;pZzrEx`DZk{SS&qH1=-PWn#B~qk z_{
7U@oCZo1FHgyqdKw+5CX`q^O; F^f=V~w_6ux!2H PsHI=4vO4JAAha~$T~CV?^MgD fan>s`g)kBNf>vv=#KHnIB&OP91M|dCbT+LA_b?f+@z!kT116iTq3lJ=C5inB zR}dv>2N8Hf MJ!YM!|^){@fg^oQ`1!uIANFHOAv~YTp2DfR+upH-0oAL{E0vk z*Gvo_w@Z*G3s|&{l5-^Vl>i%W2F@NseRksC8ic*^ZeqYZFY>|VtsNh306QWsNbGe# z?0qL1aLa9ZC{I5r@cij8VN_+t1xK5D*;SgU%fff!u~&Q<4SRM_>N;EQ`>$$C#5X{0 zTzRa=RDkt?N~0$JfR__Yx#oK`!=%uYOc>14@QuqVAl=`s@TI3U&bd!1v0A*@ht2Ij z**GC0`4gwon26aAOsWTkxN)iUb=gk`;bVN{nWtC3$9J;L2dPk;76^WQJc%VH!nZz| zUD@KRUQA`?HanW8kI&?qfbF2%w_4~CvGjhYgV8 Cr2-|E_+wcBf~2{z8ap0+;4OPa-HyZ~44XSRqWP z(Wm*EvJid$_A?@Gy5$q3@0*-^pByQK#%67-{CAC$aIo~vMz9R=6@!?|tjLxSP@vwd z#hb8{)%5vo+86Ooc2HbIuk>iKxdNG4`OBv&MK)x0uhH#c+Y_cHLd3%l97)BBpRWI$ z3Sx3>WAcTm80TwD4`is*OU%buXjm-=#CG *KG#ym6 W+?nleW?qDt2_E!S+LA&~|X;JL#(B@hy+dB?v z>BQ7MnUfuvlxHUAr6=#ru3gq-7~o3sVIY2afpD5?4BT8xd~Y9eM@n9d_gw|O)H9yy zJ2mcWM)r=MmggC@+E-Ya@a^t9ch8;D5s56DGfXFsCTw6PHYnv%`)cH}!G0%CVP&dS zRP_kY(Z fY#_pwQQFo>Rlcm}?iL;8uUIbG)jMpeQb3&ACxN(JpAu6j8 zLequ~9G1p+fGcXHwLM#)W^IuREGgW6t5K0JyQ2B{l*Z=`65*vfw}{fYSx6#;V*WHp z%LY-Y5K&?a3E>M1X(v;dnKZd7vn^)w%vUnF(Adq*Lw#SIe$}YghBr2zLlypIdPS}Z znBj$)o)*D@>8c1Hm##JZ=Ir^GU@4q#Qsxl6K2oK>sVby3Nb*&0RLpkHRC#}zGO0}D z5~~%98ICQdXSr#zSd&WHqU{Tc=$3DDj>#_ 2k zs+ODG^+@TD^aCqt?TY)}b&@r+Vd^g(6LRO%Y&{cwj(3t5?8d}LpEQ)E;hz4?O&;TL zo=vkB7A4Ro8S3sg4`(44hID0CO2P6mgabr9u0YsCW;%I#g`pvWbv%obO51S3hsk z=Wq=#({1cn#a5=oD!;^(*Q`;>gK2*?vx5_v%KX~wH?XW!#1MgbvDBK)U|wyvm>G{L zS#1Xy;j}nhrUK|ij_^VSPOf0LVbs&Rs*cJ~ua*k8W{|jmo&7u2G%3X=+bd=#;)5nk zUJOxVZ00N1KfHv(W*A)0W@u_b55w$-fP#g3{v8D}L$EPr(?E=msSke6yjdOEr5#j2 zA&Z=mA);l52F|}-&ZsVH!_!6u3Vwt>!6~6f$Q?u(f*Vb|*UE*Z-efyS890EQAfh^V zPq}bgxgS|+bLSRFWe()-D5S|QB|WR%&m>c9NWaEB=@E`zeG?%vx$p`8g`j~-P|>6u z^xD*moB1Na>xqB~46CJA3M7BkgO^!5+{=36mApsSc+YG1oVvgAoXTe*tp2AoMlWj> zO?hp*IAwzIkRmZ?dT$BM!IYzhKZwhs%G|v7=HoM1oDqm`GEB#S+Dw{F!V`h7OY^r= zURlw(v9prlNozmX8Hw+*_^>%^dO{cpazEUy**qtJw-?&^^_H?HmN|wx7JkUkPzF8m znF `n61qVTbbYDjLo~622fBN#{tj4 zfVca|6QU<(=|Qx=$8M&+gR$~NdiZk}R#M>);nT^P7}akFwez*>j)D>=jIcr&$Y13? z&RrYL5RN8G%2eUhfQqA4eto&bKF5)g;8XhIrfPmpDd>fGWYJPI7bq?>w9yEzZkuti zWbDtuxN?}d0kg?VZvfBHDGTBPg+SyFK#zat*NOMOU3)bd{VI9ejnk92{tH*~o#Ewx zC)65VvLj^hQg!sM5P?~L)io}wo$Hy-H#A%j6yWHV3}w^S6kkgJs+XpQ(tIfUMRL1+ zv*d}JmbV!$SAXc*z6Kk%5uh zzRD!%o R}LN}?0mUGM$*`Iv`q4L?Fm zs!XIvUkw@|r1 jYnQ%B^fOt1>1H^YwQR?YxzQ(4qnsPY}Vm<6-d&!0SB=E{dA78=j# zz`Tt=_X_+DJ#61{`s}!kybLpr?-B8UQ^)7twQoKJi($_P2EXg^*1dO0yUbEKx=`jt zp6>nZRw!5pWjwhM{-#e|Uaao1`dvlV9f@h7^N;x?hT3d{ORb&L4~ve%?2Ddr_gMDF zCF*JN(L4=g2qtS# Z<5#{(14jsZ%Rf{Y5K^g=j6{!3 zG?&rQd?=*-^896H4K&Gut+!|qK7{Y{C?=#44*QDnAVKKI5LnEoo8<KWtfM+z %~`a*F$7zkc_7f0iE14b5QoCIIF454&9w~x_SIIzhSrC z9IW#jaYp9Yf@~WBzdAg!UISET0=)#6x(eJ7nFt?Bn@{Yd+i#`;J7|U(S3O~HZ|-;z zmQQH6D`GYLtRCOraV|8UwsRZY-;o-c;2tw#-H6hR=jcqY*w!KTN*}Jyb4tK@R}?$W zg@HNveOD?$rX9D!e2Uh@Vq=GdGexfN?}t6*+~|JG#<}HW!StX2V}}eW@+Gd!>*#g| z>&EopY7Tdw>`=hGTWBbNl=Isp$ ?nGAamD$;@^C5b^=Jwhx0(1AthE2vWOZg? ziOHjQXtRWO_#W2<_R!fhMsx5TNUhN;30E{vCe)2){AYaGWBE`7GDj%3>lm|NPv4!_ znSKCZpOfpKdL?4@a4Oe`4{Z5OmebyJ !8vv_ zrm;}S9IW1Ja}U2UWweVZoQK|fi}wb;T_HdsnS4&+dM6p}#*meB7}E6D;#{!l4?2?_ z&r9K+4pn-54V`z6$JN5OAuBaiy%0M6eI2t;5u|MBNv|!g@X;1}6VG(_JG1~k%TuTJ z=q&MMl4mlvw^3!Jf!HjspxNGvIVIQM;GRnJHb=_U(GGTLtRW0)3kOQy-CePA=E+)M zn>bc@zHi!cNQscbP}ji+Oexo#r76dKfFvUZtT4)6jmec{LX?WynKfD5GJm2xy;86$ zio}EJl^^H!_Dt+*8^Jd^ 2%j!B1n0i-N$|hie@X&vKC@=CSIDpB;M?M{;L| zq;E^iz&aDz8V0!Ql&&ThsY6ZB+2ecLJ9d0>{9H+UI{;M?a$^brFy3T~N%_Z*HRV;{ zx;z}d$x4iS_Xk>MQ2z3V%VjQ0eq$r64m7LizQ!blmNRQJY0?ITPvc%pOn;AOrM#;N z_gfyQHLNrh&w+cHXVk62F2Pj_gS^dT(8bZ=*06i}BIB$92*R-RyN;X<#~})Q7oK*P zpN6dkOM{irF~hpBt{P_?Yr$)*b!iXhUV+$r;u`KgDZna^H20+_FvR8B#P96|T_qR$ zX-_^FM6)->t^Hk(WFVfRuA^T@ZBjD+ `K0||(fMo1Sc;!)oQ z+xLQCCY*7(iyh$;LkU@fm%aCVtc_7#PQ=F_@d!QIEg(ft;yVk`jW>N z<4!PyVZ{7?iXJhoNOWx8PoJ{Ej&(vWHN`W^Z!FAOb8*U;Z)j{~w-NM^YPPK3u@v1+ zA)0AXpV=v7tUyF2Y(NH?qh>wOAkihBN?I^S4w8#O_#;>MJ eYzkg*yR># z4DASXPbDV#^2zL=D!-tM-_xY}D;zsFDtresbfsmPC0gBuqFIWxnh~044ywxsR3^ z L|us#M&TKD7si6?A7qK+eN4>hUCF1cv&yxRgrOpT52FRP zi;g9t2lQEbnPp3m#GbB9LPjO*l%uod^Lr&TtjkS|tOEFsfN0rEC&UfkWN?b+R(XXk z>y+0PXO?&7`bJ#!+(oig;UZ7a$2ed6t2SF1VbHicnan)?rs8Xhw)N194BNv*;d1pm z%QBNO3S{WPnrVVQ>NTf$!8PJ9QkfX 6E5?wR#oU&3_iji6BprdRAmJ}XhqeLNb- zXZ+BTnoZZcD=0SCwC^MPBZ$WN@Wxrgsx5WCqw+DEoYC7SZOLsAtBb<1q+mNsMb5c3 zXhxXFaREG*cAc`e;r^?S#uM$}P`dR*g`{Y#mVecnC1X1@UwCbemE#kn;Fy+O9nP(w z7YG}aH*M%R2NJX^tgUUje5}|diGt{m7+UN2jAa)|@fvo7&!ty9%l)(+Rpl(kB-gd? z_*Ib&NxoocyRc&!wi}_N*+GOi*!6T{XXl<-TD4=f=FRP9jM(lUw|>mRYVnpob#s}y zU8N|#)~hQtv#xVZ{-{FQQWcC}1aCzKC4@)^NR`hPVO8RPcH-O3OwBgBU3~+V2)Hle zvurEgzvVziIazP!j6+=>onDkx_KC)p)sQZ5Vd}@#;FUX>b?&nZe604>z3c$!qb)pE z@#e#m>DCuC8`>mBZkS}h%3+GgS)Pq6nC-xtWeXdy;I0M7<(FktFD2!{>FJ6V`93)c zhOE8dZhnePB&<)jE-xc=ObNsF@-79-snR1?Z_jNJ1FS)Md)hLY?)0K=4_ubs*FQ4s z;2A~?Igepp00=x)2pXScGANSFc5N?5SFFT64~lE*(5Oo?9)RZXZ-xH!%-E-o_4G05 zxEwtsed1@h1>fY@MKDe=rGjnjE6JmUTd*Yo2V+i}) $>n7dNzv8RR&_s z*&mu ^a9Zqgg_>8INEW#}F=2=1JGC2`N^+O@FqNO;)E5d6v2A|Wa?a`i) z2VtgR`0gM{Z=7iTbq+9V3WvTPeI4iF4^rtqEqW#tdHf>bRkNfS PV0!Pt>HN2{pKG_U`RY6$=Em5|KqZm^86T-12sc)AldIQ(ruTWe9Zkw{ zX+@sb8|^^2$)3Zh;J6Mo{Z#{ioVKW-f~$zJPL<<3eh+~(=@@?{{gefo>~0R$^cKr@ z<*9fIJ>GSHlBR{yWFQx98;R$Eyvyt7oI@YA=6YHf1aEdM`N={x*_=Mkt#|-s7o4%# z^Ik&9D`%Utm}f_Vw$bIOa3P@=!<|b7lX9etgIX1ZSUt*X1p_m`eX1VRD*j7DMLuqv z!O?Ft06 rnP9G_~$ zp)SI`?#)x!kRn7En|bUB^^nju6A1r-ZZ|PbFfKPdbg~0yemR;nj(m$vV(C+DA-n|^ zne~2pvqua)d(oGQ@_O&bVXGwl)_`UonoEb0Irj~-Rd }X7yuD z>}JbX;m3ww)pzp7)n-J!(06XcnPIu>=Y6`)1l*tRNI2>_R>H`|bw}BsEgQD0x?!JZ z)bR0Zr{1k{6Z>JIw%fmN70UVz_sA%G+MmlHdeW3wX5DIbDZrLDM&odM3SicVA+piL zBGocmFjb$zYvas3iBwJL+m0oTQTM;QJx;25NJ;)lHJrV?M#Zp4eRyXqygh5>0*mf- z{ZDUk`>@2v&O4c{kh!Hat%fn3l7m6LXN~{rLO(D{XLvll$NA*p|9 _a;!>Zwp z0?R4>^ZjTzNsr9QQ8Alx9z4ouNS&d)S}uSe_gdMSq^$F@4B#x@U;|u1b^C}E>wkou zKSsPe>^~xErH;;PN&c5aRJ>0O=%IDUtHQs<=YN%|J$^tVx^sM%^Ui-uN8W(^w1>e4 z#{G7v{6~EP{Esnb^tSglDP_0*Ijip5A3Ua8my7|bQY3gt`t8`OXTx}2fcIt`TXBr< z77Xcyue-VfVB=>1y{RqJ(J#`j)G5ldWMyxGmd4J0;QXf{* v7)+cMmpC~h0g|mY$wQ;?*Nrn&Kf$u&+3pH4L5o7=SZqoOJxOb|V z#0Xfd&W3|2uv|Vnh++Fl=QhTagtrvp?V5jBeoNOfr+UZ9YOP_`5Xl!(Uc1FJAu`f~ zIrbxkSGN|rV=Z3ryRVM^@lkgOg+8S_U6H2M1^=EW8|4i=4o8_T{ds^uLeemnXFW zKzO!K0aBY|yDEAQkU+|d;HV_;^{PPro58OEqSF3U=O_S(`m5$Bj<~&jKT6n-B+vQS zd1i^-K7}T)tcN|1Sl^-IMSC?Rx0;z#3+wibyzyOTnBt4-b3UsUOr>D>vQFmAY? x5M_O zD}~j|+`nZw vRAZ#s;wM)kLh1kwK$xlENUqp zdz7gf)2^C8J85rrXoR-?`0j&}nUK-Wpbq#a1TkrSOMpNaLEcgF!{B>7u7?ZX#(Hnm z;f0V5Z%Koed=-Ky%2$ez80+37Mx{i|W}xWk=bH~3v$fS~?a-Oe>%j7BVd}i(sjE@O zj^F3HqQ`Ay4u5JDl7vmnqv92A`T~q itJH4^+0R7d2jKQQk}I6Qo8dm;+&1T{eB1dkDl0O8KfrgICfPRo0~ncC z#ZNXR9fzixSGxPsk@@bsL=TLoXUygNUkiHME;95A4NyR05~i1^LQ+WY#P+`9kMuoU zLj>_N1#}W88qH7_G?J9en}R4Qr=)}V_dQr>k6`I}?mH;ag=5}|m#6fA!su5Pg_pef zFQrp;bxd^Ut)flzTvH<2_T8QdC$ryZoRC#oKWP=M7dYTT0WW7hZfpa6+5W}5w?7K+ zYB9;+c>Ysw;dc)$wkNl}6+66~E>oav1jtvWw!KMG44EYb2H)?--1K;2ZfD7^I7~>4 zu3NR5DvMFR#OGt*IhkjQ<38MuM&8cfq-( b6>LALGFpg87^X7uTFRKxUHKS> z#(-S}KlyxNK&WW4%9$NB(yz9&hFnRL6LfH%i_{N%!d+lU0H_C>mmV&+BE0||lt~j> zITgrHh-};~5IPlZ8*PVJf^NSEV)A({5Mx31it}vdtQ)7M;Q!3T5Sp*%q#u%JPi0+d zM!{^Sg+z})H*urnv?X_=__QStg1V-^{aBgZ6xgmzPeoJd)|ktwT($EYlo&7OYTa(J zJ=-y#rsipo2P=!p`N^h06GzRNg;R@D;)rh6ebgbXDX}J`W7q+R@xr%X`f`JQ+PhDO zC5-VjL??V{xk&0aDF-+fBsg_0{u?#g$r4;TxrSdBgn~IPUA%TGaa>e?WrU7Uim-em z$0{U4TmnP3rduRXz%x9`fCIDXcR+IC%ZI;&Dv{oK{Y&Ht`u*4C2U($l1s-AHbaiWD z1r1?3-k7}#MEOk o~rG_^