From 3401b84076fcb711fad9c5542e6391977d650ab1 Mon Sep 17 00:00:00 2001
From: Isaac Corley <22203655+isaaccorley@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:08:58 -0600
Subject: [PATCH] Overhaul 2.1 Remove Dependencies / Add Full Timm Support (#3)
* remove dependencies and add full timm support
* update readme
* add unet head upsampling param
* fix flake8
* update readme
* make output_stride optional, not all timm models support an output stride arg
---
README.md | 490 +--
assets/pretrained_weights.webp | Bin 0 -> 107262 bytes
pyproject.toml | 8 +-
requirements/required.txt | 7 +-
requirements/tests.txt | 4 +-
scripts/list_compatible_encoders.py | 40 +
tests/test_models.py | 236 +-
torchseg/__init__.py | 7 +-
torchseg/base/heads.py | 13 +-
torchseg/base/modules.py | 53 -
torchseg/decoders/deeplabv3/model.py | 19 +-
torchseg/decoders/fpn/model.py | 12 +-
torchseg/decoders/linknet/model.py | 12 +-
torchseg/decoders/manet/model.py | 12 +-
torchseg/decoders/pan/model.py | 13 +-
torchseg/decoders/pspnet/model.py | 12 +-
torchseg/decoders/unet/model.py | 17 +-
torchseg/decoders/unetplusplus/model.py | 12 +-
torchseg/encoders/__init__.py | 153 +-
torchseg/encoders/_base.py | 59 -
torchseg/encoders/_utils.py | 57 -
torchseg/encoders/densenet.py | 130 -
torchseg/encoders/dpn.py | 146 -
torchseg/encoders/efficientnet.py | 152 -
torchseg/encoders/inceptionresnetv2.py | 68 -
torchseg/encoders/inceptionv4.py | 68 -
torchseg/encoders/mix_transformer.py | 25 +-
torchseg/encoders/mobilenet.py | 55 -
torchseg/encoders/mobileone.py | 558 ---
torchseg/encoders/resnet.py | 211 -
torchseg/encoders/senet.py | 149 -
torchseg/encoders/supported.py | 5025 +++++++++++++++++++++++
torchseg/encoders/timm.py | 147 +
torchseg/encoders/timm_efficientnet.py | 459 ---
torchseg/encoders/timm_gernet.py | 124 -
torchseg/encoders/timm_mobilenetv3.py | 150 -
torchseg/encoders/timm_regnet.py | 349 --
torchseg/encoders/timm_res2net.py | 164 -
torchseg/encoders/timm_resnest.py | 209 -
torchseg/encoders/timm_sknet.py | 104 -
torchseg/encoders/timm_universal.py | 38 -
torchseg/encoders/vgg.py | 133 -
torchseg/encoders/xception.py | 75 -
43 files changed, 5699 insertions(+), 4076 deletions(-)
create mode 100644 assets/pretrained_weights.webp
create mode 100644 scripts/list_compatible_encoders.py
delete mode 100644 torchseg/encoders/_base.py
delete mode 100644 torchseg/encoders/_utils.py
delete mode 100644 torchseg/encoders/densenet.py
delete mode 100644 torchseg/encoders/dpn.py
delete mode 100644 torchseg/encoders/efficientnet.py
delete mode 100644 torchseg/encoders/inceptionresnetv2.py
delete mode 100644 torchseg/encoders/inceptionv4.py
delete mode 100644 torchseg/encoders/mobilenet.py
delete mode 100644 torchseg/encoders/mobileone.py
delete mode 100644 torchseg/encoders/resnet.py
delete mode 100644 torchseg/encoders/senet.py
create mode 100644 torchseg/encoders/supported.py
create mode 100644 torchseg/encoders/timm.py
delete mode 100644 torchseg/encoders/timm_efficientnet.py
delete mode 100644 torchseg/encoders/timm_gernet.py
delete mode 100644 torchseg/encoders/timm_mobilenetv3.py
delete mode 100644 torchseg/encoders/timm_regnet.py
delete mode 100644 torchseg/encoders/timm_res2net.py
delete mode 100644 torchseg/encoders/timm_resnest.py
delete mode 100644 torchseg/encoders/timm_sknet.py
delete mode 100644 torchseg/encoders/timm_universal.py
delete mode 100644 torchseg/encoders/vgg.py
delete mode 100644 torchseg/encoders/xception.py
diff --git a/README.md b/README.md
index 89d0f68a..ace89c81 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,129 @@
## TorchSeg
-TorchSeg is an actively maintained and up-to-date fork of the Segmentation Models PyTorch (torchseg).
+TorchSeg is an actively maintained and up-to-date fork of the [Segmentation Models PyTorch (smp) library](https://github.com/qubvel/segmentation_models.pytorch).
+
+#### Updates
+
+The goal of this fork is to 1) provide maintenance support for the original library and 2) add features relevant to modern semantic segmentation. Since the fork, this library has added some features which can be summarized below:
+
+- Improved [PyTorch Image Models (timm)](https://github.com/huggingface/pytorch-image-models) for models with feature extraction functionality (852/1017=84% of timm models). This includes the typical CNN models such as `ResNet`, `EfficientNet`, etc., but now extends to include modern architectures like `ConvNext`, `Swin`, `PoolFormer`, `MaxViT` and more!
+- Support for pretrained Vision Transformer (ViT) encoders. Currently timm ViTs do not support feature extraction out of the box. However we have added support for extracting intermediate transformer encoder layer feature maps to obtain this functionality. We support 100+ ViT based models including `ViT`, `DeiT`, `FlexiViT`!
+
+
+Additionally we have performed the following for improved software standards:
+
+- More thorough testing and CI
+- Formatting using `black`, `isort`, `flake8`, `mypy`
+- Reduction of dependence on unmaintained libraries (now depends only on `torch`, `timm`, and `einops`)
+- Reduce lines of code to maintain (removed custom utils, metrics, encoders) in favor of newer libraries such as `torchmetrics` and `timm`
+
#### Features
The main features of this library are:
- High level API (just two lines to create a neural network)
- - 9 models architectures for binary and multi class segmentation (including legendary Unet)
- - 124 available encoders (and 500+ encoders from [timm](https://github.com/rwightman/pytorch-image-models))
+ - 9 segmentation architectures for binary and multi class segmentation (including U-Net, DeepLabV3)
+ - Support for 852/1017 (~84%) of available encoders from [timm](https://github.com/rwightman/pytorch-image-models)
- All encoders have pre-trained weights for faster and better convergence
- - Popular losses for training routines
+ - Popular segmentation loss functions
#### Example Usage
-Segmentation model is just a PyTorch nn.Module, which can be created as easy as:
+TorchSeg models at their base are just torch nn.Modules. They can be created as follows:
```python
import torchseg
model = torchseg.Unet(
- encoder_name="resnet34", # choose encoder, e.g. mobilenet_v2 or efficientnet-b7
- encoder_weights="imagenet", # use `imagenet` pre-trained weights for encoder initialization
- in_channels=1, # model input channels (1 for gray-scale images, 3 for RGB, etc.)
- classes=3, # model output channels (number of classes in your dataset)
+ encoder_name="resnet50",
+ encoder_weights=True,
+ in_channels=3
+ classes=3,
+)
+```
+
+TorchSeg has an `encoder_params` feature which passes additional parameters to `timm.create_model()` when defining an encoder backbone. One can specify different activitions, normalization layers, and more like below.
+
+You can also define a `functools.partial` callable as an activation/normalization layer. See the timm docs for more information on available [activations](https://github.com/huggingface/pytorch-image-models/blob/main/timm/layers/create_act.py) and [normalization](https://github.com/huggingface/pytorch-image-models/blob/main/timm/layers/create_norm.py) layers. You can even used pretrained weights while changing the activations/normalizations!
+
+```python
+model = torchseg.Unet(
+ encoder_name="resnet50",
+ encoder_weights=True,
+ in_channels=3
+ classes=3,
+ encoder_params={
+ "act_layer": "prelu",
+ "norm_layer": "layernorm"
+ }
+)
+```
+
+Some models like `Swin` and `ConvNext` perform a downsampling of scale=4 in the first block (stem) and then downsample by 2 afterwards with only `depth=4` blocks. This results in an output size of half after the decoder. To get the same output size as the input you can pass `head_upsampling=2` which will upsample once more prior to the segmentation head.
+
+```python
+model = torchseg.Unet(
+ "convnextv2_tiny",
+ in_channels=3,
+ classes=2,
+ encoder_weights=True,
+ encoder_depth=4,
+ decoder_channels=(256, 128, 64, 32),
+ head_upsampling=2
+)
+
+model = torchseg.Unet(
+ "swin_tiny_patch4_window7_224",
+ in_channels=3,
+ classes=2,
+ encoder_weights=True,
+ encoder_depth=4,
+ decoder_channels=(256, 128, 64, 32),
+ head_upsampling=2,
+ encoder_params={"img_size": 256} # need to define img size since swin is a ViT hybrid
+)
+
+model = torchseg.Unet(
+ "maxvit_small_tf_224",
+ in_channels=3,
+ classes=2,
+ encoder_weights=True,
+ encoder_depth=5,
+ decoder_channels=(256, 128, 64, 32, 16),
+ encoder_params={"img_size": 256}
)
```
- - see [table](#architectures) with available model architectures
- - see [table](#encoders) with available encoders and their corresponding weights
+TorchSeg supports pretrained ViT encoders from timm by extracting intermediate transformer block features specified by the `encoder_indices` and `encoder_depth` arguments.
+
+You will also need to define `scale_factors` for upsampling the feature layers to the resolutions expected by the decoders. For U-Net `depth=5` this would be `scales=(8, 4, 2, 1, 0.5)`. For `depth=4` this would be `scales=(4, 2, 1, 0.5)`, for `depth=3` this would be `scales=(2, 1, 0.5)` and so on.
+
+Another benefit of using timm is that by passing in a new `img_size`, timm automatically interpolates the ViT positional embeddings to work with your new image size which creates a different number of patch tokens.
+
+```python
+import torch
+import torchseg
+
+model = torchseg.Unet(
+ "vit_small_patch16_224",
+ in_channels=8,
+ classes=2,
+ encoder_depth=5,
+ encoder_indices=(2, 4, 6, 8, 10), # which intermediate blocks to extract features from
+ encoder_weights=True,
+ decoder_channels=(256, 128, 64, 32, 16),
+ encoder_params={ # additional params passed to timm.create_model and the vit encoder
+ "scale_factors": (8, 4, 2, 1, 0.5), # resize scale_factors for patch size 16 and 5 layers
+ "img_size": 256, # timm automatically interpolates the positional embeddings to your new image size
+ },
+)
+
+```
### Models
-#### Architectures
+#### Architectures (Decoders)
- Unet [[paper](https://arxiv.org/abs/1505.04597)]
- Unet++ [[paper](https://arxiv.org/pdf/1807.10165.pdf)]
@@ -46,339 +137,66 @@ model = torchseg.Unet(
#### Encoders
-The following is a list of supported encoders in TorchSeg. Select the appropriate family of encoders and click to expand the table and select a specific encoder and its pre-trained weights (`encoder_name` and `encoder_weights` parameters).
-
-ResNet
-ResNeXt
-ResNeSt
-Res2Ne(X)t
-RegNet(x/y)
-GERNet
-SE-Net
-SK-ResNe(X)t
-DenseNet
-Inception
-EfficientNet
-MobileNet
-DPN
-VGG
-Mix Vision Transformer
-MobileOne
-
+
+
ZQ;m7^uqtPxFA{t4Rk|MspgO z@tnacfNN^@NoB?{X2QNE$q*AmrgWJB9-p2C5G0MxIa+wOCu)x?lB%;isV#vkO|&a= z5EU`*LIg@!|1twiQNZ}|dakubM!a~|m!HpgeZ6zJ0a}0R9*jTS@4tRefBVz#@ozqV zcbpCQr8odlgRHMzYc!w%-Wa+QSgw`Wffh?aK$y}k)lsC{OKFfaP=R+j z$L^zmrpbDB#B~$4Tfd0{n&!WhRuEonTd03ve0}HDb3F^k<9B~Pehpc@Y>GZ(x9h4IFrJ zJoy^5!^j%Y(;i_H>$orE>0aOgPj`4pXxmx^?wVm?jWrg71!E0ZV++O_u*QPHf+<*x zHP%>TF%~e`5(CzNHP(PN)>y!JSLU4uoOgH!c);PE2ZJ?Oj0Fr93|NfC6r4WUaBMiR z9UE|-_6Rb>u#f8$VCe }CsVKsWZKlD{gSyFV zY)%;6v236zVdLHD^L!VQ_lNpA>McRB%6)AWLV}Qmr@2+=N_ZN3=cws-oKny) u+`Fxlv@W^}tA0s+d3;MjB*0WmO>*f?Wxk7vBSg zCl@dea;q3)H?6&ST>rnGsqv}cthL}8=Pu#A$##97Osvgow|6i3ImDu}RJO|)KzE4X zjQ8u)HOGlyQ*3=>a3x{aZB9;X+nU(6GqE+XZF5fSWP*upb7I@JZBI1u&3oT_|9tgT zSJ#8R_n)rXUHz=yYwh9%qjUp}k$$=P*2;JiR~S`Y8CaZ5`qq&_$i(wd6Prp p+n#p4)TE@wy8pvDWynGTx7!&7aA`xxNVG?n$rF zQfi)PV?$+-sedcY8M~djNBBd3b=h@883K&JW;ktiRdJ-8`jcZ=*aMqDp mgf9DP%i&A99>oecji7o;f@yQS Rw~IhnXlj17j){C*2s;$&vGL6q $VaX`sD&TmmpNcmbBmAu$=tE ^?;hMxz#l!Ph1_r{;7cg5 zS(nwm`OY=WJKlpY3~^Wdk}(mrNR4yt{Lc_F1Vy3ts4?Ik!lPsye *TM-#9+ z?Cf^8i4QuJbqfb7vq4=HzkB}?<+O_?Wb@q!jpeb|Y9&h(*fdcYYd2|wbG^sNW20O~ z {I8!ZTTN_rMPy6J$qs2F#fk?5-Bi9NMsrpVr(3H;lb2 zJyI+haE_-`8o`|pa2Pe?57ox}j;IDlFd@K-?!EF}f05+t`;(*H_olX YbQoOCvDM?!-~2%I$KCC42Da$Axk0+pq}eV&3Z`xG zQVjK5s%)&|KMu+Gvk{853pSc->RMrwDruWU*d;}l^#+0+Kn-7ciOu37OcWIKq0e3{ z)%5Q9>Hes2uK^R)yPl%cxXv oMOKnycL+JwA3S@CEhOO}U>gd(2>z*1L zr0XjoH=_0KkeF*B@G^mwI$j-8)D9k_m<*MGGyVmAvex@Jkr{IL-JGCXPL0NGAmQqu zL%swfZ%LD854ZD%pM@mIkWW^tR(87&V+vqj?<#yR(#OcBlV&e=U0mgeBzyfctE)_< zz8SjTp_t;Tnhir;#)(Xhu^2Rr>wcHPXe?CNX99G>Cgy15`3?gCvBAjK&cQ6MIf;GI z$7Ob2Zy7 bJ9-vvN)I}y3^xK-$(PMBI8Nj z!I55&ND3FxPelg_2*Cv5z4_z@D$?Xhldd_cURC({CSB6avi6Cdla7qQsi;zMNkWkW z8)ys-4RJyNHmQIpL&Lz|(|5)l)ZK?KRkbjoB@28OAWgX*h?-EaqBL+SPx4eLNap8x zL#+c=qL!1@o{>d?a1mFcw(q}xWgdayT_@*mLDn#hiv>L$U#4P2@E_SJusQ6+Ob!Ub zb|sJIU4;vY2AeTD7kc(0TnDj2GK4GkGxuk>%;G_rGY -J=5Ultpp7MLnT* zXtCwk%Iv&y9Iu0o5x0{C-t3{2AK~8(^3(9*koo@8kAj@1PG0dN!o;*#z@0QwQ8Bz8 zGkho`r3xJ+b)r&5?}$THbZa>4t4Krsi6NMA |&q3ZEy~-J5r3 zWxpDnTIT;lz$?#(A_4~WN3L=Ul92=t<;_82JggluXuYUfO0NlJKlPLqkx_jwyqoIu z;vmibAP1}RI5OcW&Ew4O!~ e}5NaHF=#|&8;y0VE$9$gZsoXA&*5- zs^Xg7p4ob$CorKhROrUdwaszXp~|9*bTiyc^kwsLl$vhp#hX*S%nP-KDumAedEHy% z1&`q;vIKk=kkTXeQO}X_g;amM M^N|uM5#=xjD}}lHUY+5MkY(Ydho5NkbJrgfPc?QwkJ%LzzfSV!5lR zVW->&5kxwj+UJ9MwQ E^#RLZ2X_JJDlR78nwW!W{SB+lL%P0zIWv`s)Oq plG;rBB#w2(FR{RgDOR{}7%XP 8usA!SJ&JCEsj3A2vWuT>pAjBerWBD; z-yY$dc^oGwFdAOxRlX jgkWaM>dMnr>cPuGc2Lsx{9;YQ$t#4ZO`->fA_@ay(YJRL&_Dk+{TKG7}>tl zP7k5Ym-pV*%!uMiYj%+`Os4PHnaBB=V`75?R}&?SE>Sj&eqx|Z?N1q &0x^jua-97i{v7k8@u*S3euFE#K8#y}t1Sl6OBe5{$-q3lDV~!Ga35Nz z5nU`h`-d=8W%5V7Sp2|*#y{?WH%fm5d^ZOaDO o*jlYPszj$jlWVQ5dyo|C zT^8*~(N8lBUk=hR1*yp@tnWo?Rv?R?tlW}Pfof+)Ox(a;_;u_1+}>Z=!LjFao?vF3 zk1glyK~@dHzd$TO+J4$UAH$wE2x5teaO%(Z7#v}-k7wNDa>D1rXlUz9>UFXM0YG}r z@xzN-NZ(J+5ShvYA{RbMukB(=cKx*Ye{C2|3^>}eyIt5X>A-EPpwl06GK;C@f#;bw z#Y;96u)2J{vyo4bqMduK9;rb?2w?DDd1sml+X4wq4f=++`RS}hPqP?v96@3vOkOdt zV%O_!OFJtX#861V8N`RUt-SUll47!<0_Kya=ZIT>&?qxmCYV!*rS^&1@Z_&r gtS@wpCo!3BVM)a2gN|Z6^E|w9#fcUewFfg*@V?p&<%azl-5)rW@OJCEukM6* zKJS=A_vbxA5lU_g6cFxh=9^tr{;24pcgg=UmETQL=&u1EO_NlIk^ML3fs}Ai!25|J zbCZ)z8k{^_0+d$n;=M8cv-HbHg6_mQOEvM)1hIseCO^~t-tor^p+Ga*$@zEuE817# zVx!|{E9#&AU?CTTCOEM@U}cyQqnF#oqb9UYtJN%18n671SydLW{Q(36nCdZ?huPvm z#2p4Yi9_uBhyM fZV&0ad}T3%DpaIAr k0)Sfm!t7V_oAS1@6I3C`VJ)$ z%h_)CcKSi5zvkY|*=fKz60eO`sOH;|`ctd}Bd|$knvxw6);LST3B&IkSHjh?+DCsU zf_g&ZxV`13Sm%X;iS0Mq<6)FU7sFi;9oBd(Ms=8UYDxOshwWLmU0Wj-bE+=E&4AQ& z23~94g33#sgQY@>uncXNHxKHcK7XGzyX<~djv3QR!j^FsGt3Ln7l5}$Gta2Y&>(_& zFe2lzk-8o-v4*#EbzJQ8BenG+)bwB5Tqo*a`EhwLT1q^b6S3v>x4LIm@Z10O*r<+( zZ!2i7p={)JL1nwUv=EkzugK)8C=X9}!Qu|TnwUFX?fYl!2s?E1p&b ~qi2JY;QjOR#y3Pw1)5aPZbVRCdkg`S4a#Xbgy(F7SdPiSJ(gUgAq){qeN|N%- zP|!O7+*EHd<4pojPR&R%Mdmp?f~^S8u2@fWbK|k#H{2C_(wi>lShpCZtMuF=9(d}0 zk^i~sGdQjoJ5NvG{m)qwfEv=U?Navu3OWX7i3xYA@}R51RF*2Kl0xP=>VxK(xEuqi z`;%wqm$ry~&&Qa_ !4YMyipNMEG4 zwSy_nyZ=mM<|3VE^sh3JT#PJ@hDPRg93aZbY>B>XSbE{#yB!-xB(6Vl3)8L@LH3`R z45@^!oPLOsH(g-GcOQ;Ql}g(4!zO6E1=Db>I7-W +5h^^_=gD%_cw;1EvQ~}LC>q^K8to?%8{-Z$eYdpZecKtN zdnaq4N1dm-NK*QEvKyeJS6p5$)A{3}nZXD~kVIdz8fUdiO!>QQ=uYGscxvI&LA}7) zRHiU1J7`W7zx{5kp<&BdnHBq%3N|qv#DmI*R#R9_-P<8aYi^9yqJ`UNE0`MbJUm&- zVm1rMc%bPmdu8PWj_D?8RK}aG_lV2fubKFxaH &J&8As#f$Z0{Y9_2zb?#6 2>mY?E7-^r{fRRk#NQV&?-98;UN54y b5m U%B7MczrHz({h^oY!;FCETG%TFM&M>T*F&YNQXnn}I@)*;>GCEJg1 zQ%E=w6P6Z8iN*8RVd<$nm9o@~#bGNvVnJ5e_n|N56NSlm>pM$-6xYf;PzScyx-2b1 z^HWQP1>BG%+Wh 7ep#`oGF9m9=pi%_W= zLCPL_DEOt yANUV~%yCXX=wTw1TOr%#fHX zk 88{huU~ValXgQfEiZxbV6CBA=&g)XQaW|=tZRf$(-Q^;iLTrf~ z-6R{!0|`LnyAA|kl38g1k6l!O9|lys2tb%1>=M(q)~86ZFH-J!0czlKwn%>}N*tXe zgq?>5oMvuCBgBa+16A1O659ynbWof+JULYp_8T4 eS_1?K5Nbu;{kw-HrqOZ-dQ_)1sC;9~CO9L|1ReO(#Ea6FPpHJ%pzYnwBP^{?RwK zxaqy!Ta(L54-xoyW3Q-Utq` {I|vcqW5P!&S@)2`jEx;}oUj zC7w?-Leesbqc^aqq@~Y_x9ex5pV^0;2*KzoH98`LM;&Xww@)%RuV*-`5(cISb(~(D zg;jW?b+=HVaK$@Mh5>ak%>57r?uh4VGX1pObl`QjWDuPLH+NHmI@Qh?{UeTe_+aR` zCjiHX*PZZ)0pDbvviwc`!5pkUE-{&})ncl}p*?TYA@1U;Ocbs%5tsDk49{nRe+_ z$ka~uJ7mF@DxXd(6xPlKoEjX9UW$S-u6-B~4hn7bGBSeQwS6nJ)gc|EKB~tQuSG!n z;VVPvwk7d1gVVvF%`b_ { `4u+|_F^39QSPIt(QEV* z_VWbWGqfd<&H{%*AJ1;xe0K($(!$~O0h;Nzq7G$h%ojplMdmVG$^Z7?Nbrbn$dY&a zB0=FHt+lfrA||`(keN#UVtS5Dkzm+za&jH RtX_2 zs+g^Z>Aw&fd5@ZW>XMq`cUe)Qp`zSsIdMo<5l0A>;Jr#UWe9(OUSA|MLKWd_eW5fJ z7a)a*$s{HjeT-cBBS&Rvr>p(UiY^2fweRn%Ap7k3nISzSo|Iz*)m(abe(AZFfDn`C zVD8Z(P}OJJ&qPy-xmocLgGWd`y%Na}UAzJC{X*E~@VUExFtU zan?O2OV(uV*Mv&Hbzw6RUA0LAw?d$Gp-}^HjGgcAU4%_FiC~J3Y(Ydt0h|Bwl-Bm+ zesVzQ4p?>KD?o&afi3eu{8>bYcHJ4ChyXv?bQm-b{O)+=2viRKxL4YgLz+Wl;Mcw9 zZFk+RsGFZ;Yyl&IkU2!$czc8f>&9`wzw8kWYVSV3bpDnkbc5Erf#LqJ&0o_6dpnTW zjDW}U(EgwnxuS#^gxm=gelgb!X711LsnEOMXD SI+#jYbfkZNF4#XFE7+?^3VG ze8hG#X~{NLaJXe`R@k?1cSeQ+*9~UG5pJOS2`-`!^jKq3^c}wPD+39$AO+~)Ikx|m zWFoY<3u*l(J%?Cdf&BR+8i3OPzio$DOLdR1b&=fw0*I!ZQB>u0w`RJcQ`HIir|)r8 z+}T<1aJcRE+H=9 qn`z1b$Le6eD}P=Pc6dD zpJzo#zhgH}uP&U|y`}7^61iYIPPu&saZ82)00PiOHn8$G$;WZ~QA~XKVyrn)Zh^J; zPLhA5s |?Gbdc>AArwDhqZ2Se!%%#nW5&Zq@@!R)_hu26Kt- z(>*L=+U)1?d;Q#l90vKXd;XrtaW)B&5m#rg2p6cMJ@=nFi|eMzHNOIWvkwxuAs8(T ziV>KvR_KqFDyG_LAn%R3>&033j nVbXOV;OzaN*Y;|>P+^?S|Qi9Ik zi0GZh^*ozhnlC2dCk)ekG$5RW8+;fIX}3}%!QRJ~u*%7a@zL`_7q57hJ@Cga-vxzz z 273M8u6VLpU$$`02-~f4P1)O> zFme#oBkiMN&8~S+V;L6F36iF;Zy{Tc$p#>X;1>?$$~t(k&~jUX&0)z2bHIduA0+4V z_3ilfw)oFhf=Op@@Cz2msuXR}gIg}Ue$#sIy}{bHqqpzkS-3Jy1uFzltH=qLdB`3D z?gxs3#W=4Ej3vCKmk|F1p;7HpeLaMD=Log0lz_jQO?>`m0)`*@nMc3s=uqg7}sl_UsGMn24W{MddhF9v}R Jnm0)Et=^BM3ht0wE0m4B0 zGJ$Q}N%88}lHVGZL~(*`MHl=teYN+>&??MCV3i3nqwC6q%og-Bm9<|uXD|^^vnW80 zh8r55$&q>6z`|!(F2PhVTALjfBdCyLK7l(dqJAii)gg-=-FL1SzHnfnXnV{BY$nbX zoPfZ!vwc|Hkvm`d9}1^melr1EHim!b48{+^Kjum0-L!ot;spcJD~9z-mRz4gqvm(d zXzVSL3|-(*5$-zOYJ|Ul)ZWNK>?RHB6Kdy`_Pi~ UGd}Em^YT0x*AcY8yG({Cx{@^K_Jl|0*;2zPRIANw z#a*SC`j-)x>`S6^Z{WWDWD4c@xTvWH!cm~%L)_XbSl#r(jF%K(D}2*7k ~4IGwIL=5=@M_ZMVd z)ZdK^OFa+hgmvOskqf7U%90pc>HMoU8L3qHdx oU2-qy4ODCLjPfq`R;R#N$B~j z-SSfK?<%Rm>(K1>oFyzZSkayU`5^EfJQ^m @(H^4?f$5O)Oi<+51mXzs!1&wSs%UfjW_?(_`|xl!!K;gbjT=It zp?GU9t-Pi>rG3W$Gg_1T-5YAm&Ks9)O8cXBn7V^XWAesr;_$~g)07v2DRW&bcQ}J~ zdiAtE_|AlznJ8mT!07%slGW|;w$M`h_8IG~#Bir#&Ig@AiIZ=;4tmkey>d=6b%@lJ zGuK2+LY?t>2$R9XtR_?YaGcv%hCt+W^2+Dbe%G=5nqP&4w7om`Db@VNoZ}cxFDf%M zF7X>JSR0hRpaNX5GUm`E%GPQ?8)o{ z FS;oYX=r zo{G`~IU@sWht7k>hns8ui$h2EEN?VR0iG+aPoNBQ!4GGd0z>ofdAKrYIBhYc5an}@ zNWVZs>|=Pp+vCbhUDey^Q*isVKYTqFDv*5IZ|cu)E?D1sU7kPXZdGP(TuLB{_MFTu z`lM%^MnXARlxer9P_pa)FehFa#8~}S<*iB6dpwraI}YP_;2EGCHbe59CES-t{}gti z`V9W|y>5bCWKmj1G6+TW0?J0^v_(*oM;!%a)Gl3{IkDtjg6O1$djnrz%bPi6r8DPd z7kYu@w4wP>fAX-WC$%u>e2vb0#1OsiK67wWWH7i%-IX|t$$xU=7~ZjP*?^&8I_l!- zZp%|db)d@Aa*@u3Od5tXF;tztXgD9d=(w@b#zjHAH`CzAK<5=nXfKS2zNwoRdD`M* zUItOgt9)}5-l5BXP=3eM$VxI<%`H~ldaAy~@li`wGV7Mf1d2HBExtlwf6;7U_<6K~ z-KjcZveyXpJs#3XfXI*~N8w$G&R*htNyNp9lW&(B2A#%yU7=_ahc!aJ5zEftU~7G9 zn^$0Onb<9Re=o?tucmwA8)td&jMYJLDnGnRjRlvusuLX&Ns=2ul68$E3emnqYKdD8 z2afvPXXT;kc-CTT_3I9d0q>(_&G^+m`On)%cTSp=jWpsv#y?5}qrlL9L7y>zg%2o| z3qX+hnBXw? z`Xj7S^wcXWUV)M%5a(K)DjRh^NV6fFU?UN_<%u}?WmqxgT<7m8^PLg)u>Y}9c{r=6 zJS9~xo{{kH> 1}0C$ej%&H`Pot44;;#H?5kNBeTyZRKCahW0&>zf89iI zKkmYwfhJ_4R>8QUc^H1B#&F7xEEGF1X0e{IwoDw!*nX9dP51VSVFsgFeqH$6g6lV2 zVn2sB#u(LXtQkZoaD(UWV-p+GVEG(!$aTff4>Fp2#2xN*U9Wf;>q@Zje)^_C|CAGV z67J%k#1I^9c}#*^jb)UV(lEFNQ$Z=FFcCbs+h9BCF-o?Zbt}hWY;88VRT1*}9Zrsj z;bNM*J7B0t>Ha+>8(tQ|1Jd|u-aK@2V$ZDCqU)B&j%T6{Uvpa>vfnotJ;fx`6=i3n zUAxc{&L$chjCDZSduyJ nKoDbL9QqENfviYvOG4}V++Ov#5 zkleq7`O`&dygB9$Q^$p|ZBH?lw`PH<1v5q2Ty{fuU9+;6oA!!_L-j3nu|bBz0E!cm z0G0c#Qt0P8w?KnpC&A^-5g*S><{(+36-zFK&!G!mK8MF{qh}eXZ^l4!DK{vjoq%}P zvLGYr@_PT_zDVfY m+x|5gZWE z1_4F!H|LEk p?e2kr6)4X2c$|N-nHB!v z|4<&N{M+KH)*MWLCRy~`wQ7cZ? Dsw&j@HCa%sQhXPDn3rklGL`-c zvYG{fpk@oigH8gW= ;c?6s)yK`*@ak|8{r-bAT zFM2FVGcL{bTNx9!C9_p0iy%>qfF+s#p(H;qq9126GnT=)Lz_#RH7w>}&%OQIf-Ib) zb|OX$5}biP0nR|b6iO2R_m(J+gNPWgU7VTm3%j9?m+_Vfn9dU8-1YdVRe7*GHj1Fh zX;a2-r8_m6Dzl5I;@J*X{A@G1c1BAVws+_`XVs`G!I0tjF>xQ!1={|h8r*?h#F-HE z0}moGxQ`{CK+A|pJ@n6wMf{?%WpHT;qwc0#lRJZp&rC6AhV$;RbD5|`do6ZvWA7YK zt5@j-JF6K5i%cz*u~q1v*#3cNt?IR_Ub`5Ia*`N$C+jLf51bEpRC!m0$&)CCs5!J- zyS;u35915T8+wY}@X>G1<*k&{XeJ(C6`8m3=g0&acM=$F5>r(4BHaFLwIGva(GsDB zK&MP1axRsmTb;Jar1=3Fa)R{$#DBEMPFr4%p3qynS;JnL(-8He6H^rUtg53^6JOWY ztl?{80_wlR6h+3wh1|%0Ordfebhq5d)kxR;+&4q%frDDiAP&%=7Q)gFSd;2Rs0lC@ zv8S#8J&*#|m8 *Vi9@4<&Z1xIXQNt9|a=0 z`ZZVkVPH1GRiI3*y>vkzdbwzf0gJ@6th6jx)5J7+bIvqjcXR7i)8gbT*j3X6d8$=m zDpQMuFZ-9#oodz8+`?Rp>dRGz^VgSyxdr%Y+Sls;S<^VoEX==F((YeD=80d!um48M z|Hm~U3pP?+DlssCIOU!pj6}4b2vxD|z j@E9P<~^$v(a||A5eJDd7;7Qn?D~y(OFQrspi=M$8-W&P0mM*S#rTY^ zWFvf0M{8^dN_Vm1f@YHrb{blUQ3TVDDTXBY4u^m&tWt{>)I2+~Yo)~adPet4?fRC9 zD^~=O&mTy5>$<+|T$m1{IL=%r?nm%%KU<5}6?v+!hJwi;0#G?BjmIVl!!lQY4RL(p z{r01OXO}UOQ6o$9fuhQ9SL0oX3Hz08*S=ni;H+c?74u4iYZXosftLHOszR=@gGdRX zQe#ve+yfcLEez3blRDtZY(zSOi&+E_#_EkKVLq_UAq=N%Hia%`DD#I(eG<;4I|3)^ zp5gm~ouBCNFf)%X@qi~w2Wkj0tPl*i=8m?;Mo0s>F*t!+H?1)%QXm0xdG%=g8cH4h zIsI@el_EDLQ>I5-q6%WwSQgr$N+~@8V|KKU2Xy$}J-v>ZKMlTN;>}Jap)-BOmQDcl z>rng}L{KW 7)ojlRRKfdV7mnLAe$gQ`fE}K>y8rz6v4 ^7R!g7Y=(8htPfH-g{m7fYMY#7g+U!_!3*{SpU z-v;X0Vt62}Q@K#FP|y{{Pd&}8VQ{F-6P~wOwZX#R6ku{&*;;d6eYy3yJJPZOc)Za0 z6=d!ZZX^Gx_otlLTw*Njze>SDd19cWvn@JM!N(1UK!>V<0k0RuZw;gg osPB8}L0kwO-%@ulW7QxAIwJN^MJA?ch#;Bt57xPPl>-f_M#Y_ Cd{MEo0 ^zZ-Owp)>kPuA5Y-seD+il_J z8AbDl5Uz;_Yh^~za1_d* $eBIc1=FXRNN;P*nG5kaJZ2x*M= zRd3zTGM3$SUa<>tr(UUu>7&atbs-S4xfpSVro1nQ!Fad~xuS5N)iXwDXDZS3L^RmU z!IWUy_n};3G2_+YUK=IY@Q!7V;m$W53=!ot7ZXL_a292@L7V$@-M|eY@bPzqNJoHU zvA)XLbY4hYE7OF>IIFkqz1bf+;<7}RHvAhw{=TaB2yx8K(5qUYFSyS)^rF`0XSsY{ zre2bgBlXVW-5_k~F4X2v0@|NUTnwD(t7ZLcd5h@L)F1qK{B*6^Ewu(wlb_56(+ GzaCTt&kT&~+=ZeHvNUGr0u(57GiBIJO+4X(}xp)%1@I*i)Eoe|uhu-2sdV$DyD z6CYTpL?GvkL96&~>wDelml{s)ziq$8F7M0Z{DWTkvl5>Bcin%vV1sjG`BM5#T@>SJ zrxVTntn-AqMjzpUxQEjH8PAzk@j)Sx@!L0w=|wT@tU) QoUC(_w{)DK`> z_y$=VpSB)3F=} @X3tY-1S_$PF?6N! zkM3ElM{v309;cxS=CLf#c2km|(__;LPhIU#gkm7&u&iF`@XLk1=9nzp(~iRUzudd4 zk@=1I5Fyt@hBa?Df5_ro=Ia`x^DTq7Z0^Y`r)rVK^Vk~MJu*j2MQra4JpJEM`qmSh z4p6P=%*BgRwP@E9SQP@;?Ueb8InhuMU5NM5oq@{%bZo}RT`p@^>C6)FX$WVT0j!;) zh(s?v9eu0V)^mTbYx>q29D8o%+Ze*>xT`OF5qIqG%Vlwi!ubapf|?&{4R-afLNpPf z1^G)$CmPMtb?L(J?Oe8!Z918n`5fMOmh81g9SkQ5oKJ_GpGxewU)J~x%G c z(*1H~tT)d!wY*}imf{h>wyXc!G$FdEwa07X?sby?9jBGJUr>l2P%-I0(6kjeOo3R# z(_G*+8b67vDzDa_%#X@L2sL#_Y_GHgalfrMX?m!Ed8Y|MA z?r!F-Bq)H$z4x-M&mf}KHIlLKL$uSs4Ug<21R|Sg9cQT;VbBc%5^p^HPVJgkNMhrR z5;kBI*JxF||J>{#PQi?lR$$w#j3%fxUWneJcg^WnxX_=o%_B>UuPU`%aCC*QF)UiN zP4qgQGb$b=L$cjkg%ta)%I&&ED#j&Xy`_#MR3;K=D&0=0Vc=8q{5VOA+^_BFSLC#x z;VYc=xZbv#XLe5@$R3sdI|A@{u+9sUC>%%pBR}8qx%KA9kA4UzqbwWN+_6Th=~;cc z_2xkFl*e|vPgT!1 8{(Qfqwa-Ssn(%y=oqjp zFyF&nEQZz?q<-i8b6q-OPOqIL#42<;d_>^!p2+p@FB_|p@pnU9uds&>78_-WO5f;g z>mzTjxeLriflH#Ez4gEJLE!mG86sb x!X=Gsw;yuj%VG zm-wUP+zvT-Mr+s;jq?}E>7m8>^36=lM>hJ)e2BLIT-&98g{l}*;0_0eYO%$*ks?4D zVM^m$iQnxepTpKVI_1l2a%)OqX-DGu&&v?r3EK2QFHE`~pp^G}6OwZ6`5)q`Hwk6i zqQ!}xFuF~ xK?=lJqp-Bn7YYyDZ@3jB@{;EV2;FGd!H-C& z$$js?&&5qW-TMNF_tPLYYPT|*`$O99)XK%|o1x`AwhLmXA0p88t|k_=xnkSt_Z>Yk zcH82gr>ro@DftBnndWgjOpR&tt`gK7tL O1`rd`gx~cAw-hW z<>7NO1Yg}WcKH{U3Mzm2m9&+va z77CyA$BN$nkwY)lEn6c*tPKOhz(SzLaJBA>QF9XFH0*URN5#?tB0aTmJTwYQ^XQfW z;A2tdKFkhxVGToJdm{$U%r 5vLQL9`p)O?dalEN2r}*-;F6GmRqJTp}~C`NmemwoyMk@;Z^y zy Wzu~yrnBmHIuwMp2!N(LSKllwt*yM^R(NNkZ=UjsS^ti81hiP-y zo+7l;FAOVbzH{@>w)QYT#cw4`9j>F}Su8u@H|!i9oeP&M7cTsbdh8usVT-eLoO{C8 z5y|-E;EkzGyIzk#`%!>cvBh(?f_#U!e1Aw?{~8yO+*w$)YXBts=M`P-EN~2(04-+K z@F6ry6G=aDkWK%!>8%GRcqX|9MB>yXhVlK^{AU8!j|PS^Z=%=l8dL6Rlqn7xeK7ny z@a%{FT>aZ-I M06Hcs#k z0fICAI9~neh=N0L#@S4&d C{zU$u+T0|PcSfx7-KWmd=!_Lxf(uNwC z5@}u3pSc6D+o|w1)B@9foa-!_<&dGvRt{MOavX_C;J6J4tRwsUD@gu6Ah_z;PPb0l z9dS<7Jp698X*wF^a1k_$)Qo>y3JK?;*KYObr%WV>9g2*|)P{r2U89Nt ^pNPm_Eyz!H)Sv&8xbItKdLbP*ZA+{`TQ_w{xpl+7D@~PO0_E z$Tsyb11-d0s9P{LaavlO0|~i~WX)MQ*}D!B5Xr0&U!#LWA0>3sVN^_)1#WnHVMgB2 zB6Ll|UjFtSJ7lGApZ${$wXuqxhv0O9kK;_&u*RNWZT|XV)x;Q$^@1OJzml*WO6m$I zgR$-77q?bim`4WK_4#Cn#8e}Z>tBzA(q+&>pk}V&zXY8l##?s0Z73sf!$pK5^FeVD zlnE3_Qs3$JH*;eBf(ehz01{5asJl&=A#R6OARf|yz<&EaBB$k4EStl(FDU{r98rv* z2q|V_F^sQbKB__@k77g$BZ?j`g;EP^!C&_FFx&4vMWq^_KPGgqU=x+q4i+lYZ^MgC zN@UfHjmfkGQKWnn8)h)Cr7?iUB>GjK?8|G2JCX7TW=~RR#|kJN$~xF(Ti{cW${ofa z7*(b3s!0p7{g{;Eu3bT;J!!0{_#6L%Es?FeZt9q`-MY>X4ABORaQ__LCGc#nwB)&6aV!4#msh_3< 9Z4iCIKSkeZjq&>#Nksgu zzjWgf6gsacsbDNz6Z36gAsDBpLRvhU)I5;8oMw7Jt`iT&6P~Ip{5566o3kUK36LHO zH5v@ruT(2&j G**#34@&92lP|o5c&Z9tB=Yu9;gK b;d_iRYH znd{>^{g}{7l0aCS16ch52z0hV6ofBG;FnUmh4o(Gj~lq&h3{O=hTx&$H2#XrkSx6z z2qcgBp` Yf`V>|GWbBt|elBw$ob z7!>cD1J;*TAxspABCG@^GB*tYfPhdE27`c9f>1(9S_q*jC5Z%qz+pJ(EYzV#e1`-7 zN55S~5B66bDCTc_pHDw!!BzqDPD11Vj+ r2Q%(W-!v1o_IB7l(u@QIUtY?l zZ@w|#3o<2)BdCv`gtaX)InKmr7{ws`Y{|nw85uu0t_1;#aNjY&`?k??Bl AxV)N&ap^swp=R 7cHu z3ZiodlT(#7$PFd6*h$(;`MC=QznI LSSJIlV`nU_hJTr UW% zqsc1Ap=bkF67o0A4gq)ro(SAJ`S4gMas5I4eC%V8^b#=~fx|{phC?6;6SHVPYK+S( z8e!lyPEhldighE{31xN_CqFxuEpCTN$NvFyK#afhbl5T`XtpR1cUx&R@XkZC4hi$Q zWW!UH8nD;}9k8%$-HnYk+OnjWxA7q?&~^YOTyD=XV0wmKQwAnzF K6g0l-8SYRwL!N&q)06}N%03C9$1P6Er4tg92yQg!m;!(^^n-q;K%x3Q@ zAvvUrL!c+J#fOZx0N$Iz0xc7yxYqPtgD@=n^u|0mKZuroNT)Ocke_gL(dbU3!iE zxJ`(n-#)=cOb!mi!X`wsKn$+1ut`IOg9SJPQ;h)RfLr*4(t!tqGx&v@_8J61%Py() z+U{A+!*$*}&9-S?ynA&{g*ONWu*p>;R7muI(Vqkpg~|{Y*u8lxXv9YZbaHWkchX|4 z+_TA|kroiPU9_M<(4vttExUIt3p#AukOppHHe_U`34FU$0Z0(n@wkWpEeIeQK>!43 z0ije7G#~)&oGrEhHLNQ!8JO1Thc!tZWk(gAWwdCqTXA5wX2I2NCmg_rV>`uc$976Z zkW&}40jF3h6_-p2X0wUEA#Z`EaFvH&xZD$;`^!hIs`n+5g*k??CVi1nymV)2GF+(H z#8oB^Ll-5+G>uUWEvY?@F@9#13~?iSo8<6v{7n4D( AqjS~ZzXKkxz282XZ&I3UcFWwc889XbjdfrocwJ1A?eRI`Mmee zUP*_iapM*D^z4aB}v_*(^D|ID6&z#Qo$eJQ=!S7@CX389F6t zWcW;sF}~Rze&IOA7+*e&FUP~!o}C@XtH<&9EM9HX1M%#OF@7 BLbX_P_5~|i~^n`d!*5+R862%Y?+)yKklPZW Mf@~l^@k5*WA5o6(Ir3 zN43K;?WziDY?T>4Wx-_DU@PmsUe&hi9$vj})^6siOMo*5=bW3l&bY&wGsd}V%p5 eNfpacpQ7#s~LxP;x-=zm`TksSe7p+r{!E?^T6kj0=AO=4z|sLEOt3(%U5fk?PLp`5oMZ)cC@93pPn{P zHO2dx_w^56=RTP^JqF(IH)rpgu~L4DUrJ9;Zga85xZ13ZrRvypYtz-P&a|!#l{1-` zx~ixaxGn)Zk+5S>&H%#XNc-A^#f`m*9T_>2A$>SI4E;?6(&&I=HoHH7mm4b@*`+yP z;@mWUcnjj${@(b)<9+rmz6_>JUZII*V0AzYXQYH2)&E`%5hS1hH~ba=T$EJ3Rryek z_G(eYohlGaVQdv4TdRp|wq sGiQ!oTLnPXnh}b1N%*kMn!-JHh+C zx&O#RbLFeS`+PIMmBHTUu6X)PHrFS9sXQ#LSrPyaP!9(`m5)F2_|$A9=JZbAha@MN z$+xG5CySJ+3{R+1qL8lYtg}?tP3 Z5+Rux$c*&7(`!YX# z;~ZbFR$UL7EIp_0<~s3oq&MtyA9fcMDQ*C2K$E5c0=y>xx{fh89KT^C0-Ku%F+@FY zRsos_5Zq}U!4ZD5NF>gmztOjT{Ks#FK)7}5)-CmrKZg0Oa2lR}LcV4iew^o
%Hfn&i#|etNyXN>}74%-CX>9Zyqvx Zd-0=euf?Q~$tMr+W(L_Gms)>uT=j ztMKjv=2ZYi)i_lf?~bYerK#I|H0fPhT%WabiX#!%hRqP$3d~^~8d`)YkfPH$)njma zVNRYQ(8P~#!&&f3oC-*gAO_Wg2w)BnOk~IDUrz!8sCLVCL;!$tY!@!z!bQ0he>ohj zML@KEipaDr6n9h*6%m7o59KROLpZ~a4(I#+Mf=`2O-ApD>ph*8M|;)ntVf=EO6Qfi zrbuSQ4Ix=}ezd}dq0OBY1H_;u=)gsqi;QcBGGIM!;jjbN@1;_APxL$S!ec#l0P9gr zL(u^-fc`E`O+¬{tlt_iN_}_iIgbw{&cXE~pEdNF7++2hAMkm`6@eZ{1pke@zId zI>Ychxyh~T*Gv_r`-Mab0ZCQO^*<5rcm0j;7plQ}pXh!yp&w#+s)*sU48;D+`tcPG zW6|f(WiQM&%($;*2}gUZYr{nO(03w$D2YfA8B!G$)6l=Z0Fv$veQ+<}*S0K>M5Ju{ z?aRu_?izG#S|-Sa$U?9sEe~_i_YQc(TRX5E0&OHzGU|mb-bB%!IQ@4nFZIjbdf6+Y zap*B|yRVmQN4n~Ih84RB1uOavtSwv%K#>zot)ZC#JP?Pt+P#-Sq8f2r(L}`Y5{gtB zPBg_lJbVCPDMqb&@2{9b(!S-@?pq-5Om(1}w~ekf`Z)E`1gjd`5b8JU)z3&k>)O5P z0)dqpMAuF;hX(YWUq=&Yh|D3hZ8j1%0aRnO2AHbH16~M h){nS5vaHZe14yzso>g+srbKt9W_=~=n zVa;Ahp=Fgt;9GFe(g29A0jKVo4nQp9I_f%^%vUf+1&Xy(F1h2N9wQc sI@$}(4uVaS_f7?qXBs7ZLqn)VpTi ^At>j9t-o<^5$h+ l_s{nf*~>^p^+%?7weMZIZl zBV*QGA74)Y)BBgY=HVRc?ghurT_>L(;&q2ZUGiD(qVkc0w3~UCVG-a2t^l+}T|)$t zu1VAb3?6L5{tZ$J&pNPES}L*NYH&huIXfPfIBL*OyfrhJvc55!f&i)yAbO|(LxNv_ z7us6KSl7BnZwzPx{v-z0H(nx+IXK52*JBef$)3~%0yP`cz>0dD;+vV8%Av@Nse$Do zG|uz9#!oXv@WME@mZs}751(5&zW08@gqA6n-163$fAoW;pHZ86FB!e9)8NPZIRC-H zPhYP1I0~@8Pi{vZfoj(g033zkwVqP_+f^f?6kJ!8?f9nu#uo(s;yr+c0QCD)e(=A3 zijV(Cvn;#_q6{b|eNRy8qTOC~=|_&I{RZd1>(Q+1UhXwCJI{W0r1va`y5I}3kTNsH zJ8pvqnSLSY0A{HHU|*r4tMuo`2$n>KJ!8GmsZ(juaDrcU9=9Gm;u(O!D`GW+2e&kS zsl5zfmSa2A6dR`&$fH?C#4C4f6Xt%7D%4OTEy#U!X|%LJB^SmT)yc0ATO?=2C^c@G z@BA!r6>AyGdPzG^Hgnoao0!r)w9$4lcJxon&`fl-nIy%o9flDyv=!s|MGC`In$`kO zeEX%p@!i1a8!Z++4C=Yd==%qK{VPYm{C+NwpRPGHlA*H*G7!(0L?}2QLIg^ofBWnh z6a=84zQNzlANMaF`Ca^sjt=Ain;L*}!JXk407b5#htK-lD_@*>;c6;5!)}zA>#}CQ z(fqgGfAJrWB_DWYhSd*>_D?@wANj4h?{l8gBFLN#8|I)`f*BQ#H+hx^5ZXB_8bVwJ z0C56=+66c!5Ce_6P`3nbuc$Q=YDXZ3nih!l6$s6WKn#Q?-D;_M52UW+`Fy@n-vg k9X@N(13sKmbg;Sp% z^V8ov;7c&m5_EbFzV7*jatVe~DQjB7A|ydXbO~S%=>F}x30xJnTn=0f_@BPVeE|mW z1^%I*5cm-2ccICN9^>$0vL!Z)v-|>=`txDAO)s`z`lx8|*4OnoSpQ%jS1PCfc~N#P zMO?V10n23a#;9kAs@X}P<7iNEXoftdiRGY8iyhj7R}SJZw+x5FoCAho=#(4|3`r90 z&^Cz~t}X}KVHm2|4DHF)<<%Q+E#virR}SXGFbs?KAaPz9_Fp+BN=$}h#|A_q(h?+B zLaUYttf-? B&EKhH1( aj9#nK z5C&7rZI3RyUOd-LKfK~UzSX+#qQ!zy*xuR9(?|Z^*Y m6`LYNp5XDJ{- zgj}Q`^-9wKWx>+@*?|kSeYN^O{HT9#zt%fl8TkJHSid9zM3QbKxuW54ofu$QL^O%7 zv<8z#kU%KeGEchTuTLlX;LRNKe<1bBm>s_C!-B@&6yhhn@Xr!WphsK*JZPvNA>pk? zA>l9xb4Yh+JDVBXb)D<#TsjWvxY2RgSvtDTI Q!@>NZeZnvd zgFP7-hAPsSVR+?$p-r(}RP$~amZ?@UU{8jjYO6s~lNqR;Ok?xrt7RIAJe_f5ZqhtW zntWV7Ip3L~3Azf#7d!8L@uJtg-tp;QXw`QmvE`3Gn|bADkMxDN<~jj^9uyc_ -;Dsf+kdq5ciw?|r!8S&9Ioqe-)XN!l)qin#)s zUz?AZ03}GqxjEoGFZBHA!Ff+_c>Mzag{SJ_b(>G~<<3UE^HZ<)JpMqT$?NO=so99H z|Hu_nlad5;sZCvBERNb$rmjrIqN2*gRNW%CwaM&_`Vy(@$~>ve4Crp)thLUXMb*(+ z%MIJnVQw32*IA2$&UTKj!&-}CW{M=1 DtYI^g$!2qQ+zof_@{5iDB+k^(lQkrV6I zdoTXv&-c7P|NT>a>epN0tGVF^hW{Xl%;$d;@h3U>@Fy04b9fC{eYPT*V_{s S1fK%(h&f1 es3sCs&E)wJvENHt)^&6jnEwCMTTjP=}df* zw|$u(|Na@j`s;10SN`ll=b7WIhkx^^mw#vG6+LLz3} Z(=};fZo;cYMn}?8 z-J7YdvbOg=9QjN>@WyAw9eD3~>U+O9!21l3t~}K~%%9|KxaVQI=l$G2_Wp^V<9&7D zJsI)d_{Tgi$=2h27Tz~afH|jkG0cr(fBpj0#m-^b!yQ=Cs|Wa{fW`a>TQmx(DlpVI z3ze~o+*nt!*f1zK+rEYK79WTZ0?W7oS&18mVb3M=yba5tb6$Av%b)wYpDnR>JkHnu z?4U3F1GAd}bQUQkOoeq_Az(Rco3{cyrNF?LMI<+2JN?xum;f&VJPD8k%m8!*@IQVi zVEbg!Rpnvl)*+y73Q`^DbD(dwx8ei4o` z!TW k^_u?=6W?Sd_dCzBm{h_b?QQM_g`6!vUdVmpuG@$CCTnVCCVenZygu#h^+SG|8 z2uFp%uKse0Tud1_SSJo#uow?!u-fb;bvQpz;b6}XFfb0{mgB^joIBtLx~x62MEKQh zu0XI??NK|2sRanpIyAYkc913-IKrMcsFCu{!;zil$@Bt-#(Jkp?dtn?l*v!sBft6b z?o6%5t}{g4diUQLW0@2yKgxSnQ_UUzl8bMyGyicT-~C-lwT}xLhc?;Ti(1>B=Fc8$ zDXY>@44z;)5eNP4SC3YE;z<4ko)Op^vB GyKy9}45ni~es8695a) z4r~j0R}amAMl=-zDIGKNXa!bfzJx&|tbn6yGoWf%0%(D;#b5 M_$B+XQ9laX!<^gaI9Q#w zMqcNqExIlr|7Qn(b;OO3TQK(&LIGqLVE4B-?xiqJs{wo~InM&@7bpU*2K;TG4)~VK zsv}8k|2EO7`1=Tvy&Ji3$8a<{AuL_DuIjb%*{Q$%Yv=#-pUt!WbvD&HkBt4k{5yw# z*>`jLx@q$s+XwTABNax8=}d}|5*9Ry8tPe2!5SD&g0bXcySl3Yl~B!4Wc~hrfh{J0 zHA{3gfUfK^NE^&NnKUc#a{tXaW(5Nf3?kI3rH-$|5v%!J3mO@^MNOrL*9`%PtSYp5 z|8NXT#%(YV%opEJpZx5#rG((lpts~M67MLz7>S5~pPZ_9H52oQa-uGBLtXTm(Ymtd z^wx3**b;S&_isyV*?Oa7g{CYfFNMAatmn$kbdZd3 %}1KbO^rITPRL=^c_Vq)D1J{O>!e&f3}kyZ2{Az~;sH3G&ajjD#_SS%IG zF*FA&1N9(&pf>yCrmbT@ppKBweLsCCxfz&TGZM0H8y;X)N|Yeosx3y3J$df`>{q^R zYdb&vnL7@(c0GqD_)FW<{BhE+-R1W5_Y#QB$eVEav$3Z143W2urNbpsHrv0Rm_f _+`JcF*Vew=km)=|ZJ?rA(-*=ez m)qPxi4F-TLt1fdi*B1I9?gYz z*W3ra@=NKuzYhDBA0PDGUz8mYpt>n#TG }C+W3V>KuEO0~~ zk--n#&s#kJLXZJXP3d{ hH`E DrBv%s(Tgw!22qkKRx)S zr}jRln-t|{)69 Z_-#hfgX$_Eo5Y@!tDYh4+>B9$!~pZ)%>b7tCr}`E|D4 zl{;j@tx0gIyDO(IzOya;w{A|&4t@NwblUgialY{Ipf8EmOV}$SHw a&= zHK;;DO(3I^DO7w%H{Rc!fEUG6(1YYR!gxGBkPHIwIm_L?XsE=HFm4?hO)fHBZaYr) zRPWvL4EgL`SI%*l2YJ&k@9C7c0yP%cWRNsT7bM_Hl G_| zBJI5@bYFkz7hU`KL*Fk#h4 U8U`Gv3AJ5PLPo={a`QR#1Hv)8@PtgpmwT3=PZ z-5gH5AF3& A;(5>SRFO>I)i5E<8| zvDm{SZU0*j%ua2pTd-pm?CVeRgE#hj)*|LD1(Jl>TF;|6=%e=Qle6o6qEe;oDO(Yb zOf-vBe|REh)u2relD&CCG@MSlQ0U8Ydusy2Q3%PcxE)S2l4rh??Wdwe4zu90N1)5< z%suR$oQHf24ncU-tm;mmEMXgP(=gqxg|u6KQ^9o8ZbfZ=jEZiYrJs11!F4LCO=bLb z%;xDI^?1UQsj>gg{ZCy-iBbMf<$oZc=KxyN& W6viqh1H9qu*j@F zT+4X+h0EN5wixTK5>&({f_9vG0Cv2;J8Iwsp#mu6@t{6j6-m0uK7^62984+585emL z7Q3N&@|sV4`{M)eeZ9@N@)vmNv)V#eu3Ziq3-_LdJvExc2&<4Tq;ZNthMNMXOu@i9 z2SAb_M3X}VKxBYJfPO{8?L2%o$p*Ii&CO{N`G>(8$QlD5eVNa$8lJpF3v1Q@N>rf? zTJ=KE6tz&Q(Vz>W)uKfUpaDdy2aSNtL4dis00?uTxLj%hK~rphRHuL8xu=2`ku7Fe zZ=KUFfxFo|#XDlz;QS1^b8XRerzMWPonuEk|37f@>yAe|3%%+GGnDXRt@@J&MMZ%D zF)K`55}9pqhorA739l9@ClLMJT2-~DZ>nba#ymbyuNZKZs}%Yi#*|8jQX`|NpeUc6 z=I AP696H7|8u@1)H4^uD9WCH4|d4>x2(6TO{~MS@>QoWpMTl?sP$!_dXS zUVW__G#l9Yp-Y-KhoKt=EyM71kZ!PXI8o|`bi%M4PP){Sm^ci{gheuT!%3Pfe}@gy z4M}o+NF>c%ABNWlx4~R;y6$ALyngA-a*>iQVG_#Xdtiej(FlPY%m*j`LyvlXoN7ld zJ~_<(?6w+hhjPxrw#-$>Gk+xyvtEJ0MPT|kbA1;+-@k;6fK{gmlmv+&z&Huwl28s* zF`z%20&*aUNcVIN6P#lr#)GHK69Fh93IJ3|RUoQrX9z*Tz^fg6e(v*cPkzGfy!(6W zjgfQnX}^;Xe1|YF0MRMgAsLkRk*YHp1{rEb$`B&$WEinNqnn%K&6_8{Nz6&i%`uQ6 z4a*^($Ah$Ua57vUNaKlneK=dD>!14I{A@Vs9u33!)xmBw3qK5xV)fIpd-P}+()ugr zUpVyLVM?4oTyzWR4*g;S{9$*vSS-4fk*<5V=(=3#02FI*7O=QntfRJo=_;JXU~A}r z%Hg24wWC m+%e3i3 a$e2dfG&=CePxbm=m` z YA7$I77(n) zhgZPN3^Pm105dy_P!ZQvuIu7vH^7efMF-%%P;e4No&s+JB3v6-mlWhVP&!9?(rc&* z?`R^=2RzB`+vT;-yU47Gh4%2NF3YESvu1}JpoV(CRtU9e%zl}@Q7|+$Sjuh3){QAx ztSd1TEhC))iv>$zZNO1#jlJ 0LC^!Uwa>C1aBQ@eS z2`Y&AmW~G!hnm7(5!BET{kg`D$GLmi!y%rtcP@P(XVHFwlX#?V&>r{|q~I( kX)IWU@pp3_t7E zcxShA-^ =+WKqjs z%&%saXJ_Mn?uYTa`8XuUp>GtA1t3qFO*RXj4|uwbc>ZT<-|PK1T;Lfz+G4+pGkp})fKLkt z90fq5#zn@nZNRA+07qMAP#Kr;n4DW3{9H6R4GVS~8S~|k0tmHPz4}#ynIedI6I75X zAcEOhO0}EB?G^>F>Grtqec`U??&vB_hE%kUTuwQMxv_>9aHPfN5;H 0rd5WwLOR|6IRNC#kL#sC6LGZ_8b8WhUsv-8Hyzlc}mbMG=|06^7MJE=_|l9>YD ztM}?u%p!-?P+EY A0N0C%_<-ouVSMbbq?nGAvA%+P&OaRz`?V+De&n02d& zs`~246F%Rb?-9>?Fh(sn$fH!p)1SiwBl7@X+nY<}FADvbo2}GM-O!Y5YYjNIy9S&Y zk1Ac3jkbj?21XjY9mW*1``~~Gs71Y3Nm>-9L~SLh2ucV*kOSaLnI7*Ro~h|Q9RxmC zSK7|!yn^re2>tJUk#Cd80I&dnm~iV;fL()F|2CKezO@*iFXMGs{6}ODs(3sB)#yWQ z_FA2Q65~WsLo^OXURvH6wQ4n=86c@#++ZO9cjyWLNw^A;aMG>jEGf1XK~>l)LQ$qh z?YQ-W+F7Vepq}S(KHvX5=W=G3*vn(j!}FY@J!AOMm<1#1K(a4Tg^HPiu#L8)cGQmA zp+`u~wz}F;Gt%i%f)>DR$?D56fGLz(Dbgm!>} z0; kN7@ro&g*7S>N5TsAUrOt(R+}raqhFRvZFnWn0KGETNx`X*G`$0;I z2#~0Lv=Ye?C{fS?j7`CeP-vBw L--v*dV#enFKakIsLA}`ACQgf0 1J zShxtBoFwcHbP3cH8#Dr@3?{%s4CN1Cz~If2VmB5v;>!{;xr~)C(g1Y2AUTW}YH$WG zSa3`*h#3KwVe_>Zz{n_(AmS#`Ja3qlEoUTBR8U?f+!21JEq;NmY}vQ8sJP>3?#sv7 zFYzM+xuAjk28L}gOc@L^L{iFyfd1?2x;qJjFIWIO1wbyS$<%;sEDevh%6J9ZQo_&Y zdLPP37< rR#HumXHuHyw;4P!1tVXWcJB^zUg}o2_$dCMJsBTE!m-0lvH_7Ze8s17 zo5p5oxT*|rafb(BcZL7`*9q5ED05M=;c02p%~{i_)Q!w~e6vMeOMXRXo;W@B^|NKa zjBM>Sbyf8Ax1V+Gm!9O%XSvfGtD6lfMf(661P#(k#U&AqKr1Chp;QWL01!X`X$1ig zio#{Kl+Vl5p+r+Ew7|S&qzI+vhJo5?6dF7aJMfx5HCS^hh%597NotB10BUM95VO+^ zMUdykKsu)|_GogNxdiI!;B!3SQ;f3hBDT!3)4qJ@0Y3i)JUr|JKkfVD7+D*U1p1PZ z82~#jVL$?CvDFkz==)>Xp?|w2!$_|AR7CO}X6oV4W-yA&tvMm(@&ur4bhUjx=$ G? z2F+lBd%p2(SN(^y7|R^@@g)y?Z>gjHq~#i1yT^FWwB@BkZ2i_=_rC1k)O_Ri)pnx* z3qeI^S$tUrB@bqjMloOizn&%=Oo~ZDf{!*xN;dHDM}PG2@N7fU;tmhp|Ky#+ME+b! zINn&!-Z@U~Myli|K9i=m+dso`I{kG%^XtT4Cv8{p?bxpFv<`7d$?8Xc6c9& { zXq%RXRuDC0V}5i*Xq_PNv~8i~`=KTx0KC6gc5R0c(>KdUKR*u7@+eO+$5|ID&~&F= z`GkkyIga5&fXNU>lhqU=TZt4b0F@kt4AMH|!L4bu8e41(^}fXkZHErfz+D&i xSzcsHJu-a5A4%kwof!wl=V|22*` zxy%(GdOixt%^BSGB`9Yyc0BPz_(TdhlvANCc|jiV35*Ty_Lpb$b{~j3#z2c9_g>GZ zmQ(`XF^RAFgJ7*ZH$MIAKmoueZdpl{+)A1y%#^Gps$ (OyZ36#}9G6_=s`qA46D$YCeS!28>LGj~U zJo!|ml_#PTqIUV_ z)<=)tesuEaJHw-mW2%pi z(~l<8>({??eHdQ3e)SXAuP4LC^yK>0PrP!lk-T#9nV(40n5$@n(_}cy@DRaCeaOwL zH)BMc5Y+%Q!qc2eqY;hJ0EYF#l`ElGZ@v(i7lNMX){Di$=d&(th2zzAPd)8P^Ej(> zZ`gC;TGOaOP=r7XfQ8~Uu&p$1;@V}1xoEK!O+h7^<@KrPMd1>+L@WdosM>ZwvH`Gg zli82qqSx4F$7f?w_(n2u6-Y>y=ks~YH6B__kcRtQ@AIJ{d=6Wd5j$Vd=3PK&%+Lzj zFbbyq6 _NqG2cDke&JXDJ4HvuqDw!T|M0gje)_NFEV=wU86{gZ*V*PC`S)G+z|+nP z-;=rqvMvg8Drshx+=``66e6P(Go7mt)bR~d(_lKOy;G`jO=gkCG|Rk;W4UxjW1w29 zlPtaiHZDx10jpNT>pYlDXXaC8oFxa#@wu-UKQ?!KRcm*D_4M5MH>mugT0KyYp(bme zj5}FWo9OFj*<1VZ=k _5mJo#wN;3L=H*|&c0M=u@zcF)D Yp>@yb8? zXOg*>KHtgN4fE5NPSP`vVw0Y{cIoA#AN|FDtdGP6lm1kbGMt_H3MPFMo75YUT=LVs z_b-bF$Z8`ddA902EnYu8<;H_=+3j45wPbyYAwAm* NgCPDbDBAM*Ttf%6x_j-JMC0Jn+Sh4jza}3c>YSuHUuVO0(Mv$o| z)oT9E>#H90@nw&GJBSvvBbWB; z3VP;X2#^_>3L>*f r=@{s4(nWohbA(?Z+Maqk zHz+o