From 1b13e119a9dc6042c254362e8fb8931e3e147b82 Mon Sep 17 00:00:00 2001 From: Cristiano Hoshikawa Date: Fri, 8 May 2026 08:29:08 -0300 Subject: [PATCH] clean-up e persistencia na nuvem --- README.md | 383 +++++++++++++++++++++++++++--- src/langfuse-k8s-cleanup.zip | Bin 0 -> 53323 bytes src/langfuse_dist_cloud.yaml | 442 +++++++++++++++++++++++++++++++++++ 3 files changed, 788 insertions(+), 37 deletions(-) create mode 100644 src/langfuse-k8s-cleanup.zip create mode 100644 src/langfuse_dist_cloud.yaml diff --git a/README.md b/README.md index a416cb5..8366340 100644 --- a/README.md +++ b/README.md @@ -89,8 +89,8 @@ O mesmo ocorre para: Existem 2 arquivos de deployment neste material: -- langfuse_dist.yaml -- final.yaml +- **langfuse_dist.yaml** (ou **langfuse_dist_cloud.yaml** para utilização de storage externo ao clustes Kubernetes) +- **final.yaml** Ambos os arquivos contém: - StorageClass @@ -102,8 +102,15 @@ Ambos os arquivos contém: Para ambientes produtivos, use o arquivo **langfuse_dist.yaml**. As variáveis de ambiente já estão preparadas para cada componente do langfuse. + Se deseja validar de forma ilustrada e passar por todos os componentes deste material, use as ferramentas mirror_images.sh, create_secrets.sh, update_secret.sh e set_var.sh para montar um arquivo YAML de deployment como tudo ajustado sem necessidade de criar um pipeline DEVOPS para isto. +## Persistência fora do Cluster Kubernetes + +O arquivo **langfuse_dist_cloud.yaml** permite que se utilize o PostgreSQL e Redis fora do cluster Kubernetes. Isto permite que se faça a governança destes recursos de forma mais tradicional, além de maior economia na escalabilidade e melhoras em troubleshooting em geral. + +Caso use a opção de utilizar os recursos de PostgreSQL e Redis dentro do cluster Kubernetes, existe um pacote adicional neste tutorial chamado **langfuse-k8s-cleanup.zip** onde há mecanismos para o clean-up de forma agendada dentro do próprio cluster Kubernetes. + ## PostgreSQL Responsável por: @@ -1102,70 +1109,369 @@ Define se ClickHouse opera em cluster distribuído. --- -## LANGFUSE_S3_EVENT_UPLOAD_BUCKET +# Configuração OCI Object Storage para Upload de Eventos no Langfuse -```bash id="vars44" -export LANGFUSE_S3_EVENT_UPLOAD_BUCKET="langfuse-events" -``` +## Objetivo -### Objetivo +Estas variáveis configuram o Langfuse para armazenar eventos, traces e arquivos no OCI Object Storage utilizando a API compatível com Amazon S3. -Bucket de eventos. +O Langfuse utiliza esse storage para: + +- Persistência de eventos +- Upload de traces grandes +- Armazenamento de payloads +- Redução de carga no PostgreSQL +- Redução de crescimento do ClickHouse +- Armazenamento distribuído e durável --- +# Variáveis de Ambiente + +## LANGFUSE_S3_EVENT_UPLOAD_BUCKET + +```yaml +- name: LANGFUSE_S3_EVENT_UPLOAD_BUCKET + value: "langfuse-events" +``` + +Objetivo + +Define o bucket do OCI Object Storage onde os eventos serão armazenados. + +Observações + +-O bucket deve existir previamente. +-O bucket precisa estar na mesma região configurada. +-Pode ser Standard ou Archive (recomendado Standard). + + oci os bucket create \ + --name langfuse-events \ + --compartment-id + +## LANGFUSE_S3_EVENT_UPLOAD_PREFIX + +```yaml +- name: LANGFUSE_S3_EVENT_UPLOAD_PREFIX + value: "events/" +``` + +Objetivo + +Define o prefixo (pasta lógica) dentro do bucket. + +Resultado + +Os objetos serão gravados em: + + langfuse-events/events/ + +Exemplo de objeto + + events/traces/abc123.json + +Benefícios + +Permite: + +- Separar ambientes +- Organizar dados +- Facilitar lifecycle policies +- Facilitar limpeza automática + +Exemplos úteis + +Produção: + + value: "prod/events/" + +Homologação: + + value: "hml/events/" + +Multi-Tenant: + + value: "tenant-a/events/" + ## LANGFUSE_S3_EVENT_UPLOAD_REGION -```bash id="vars45" -export LANGFUSE_S3_EVENT_UPLOAD_REGION="${OCI_REGION}" -``` + - name: LANGFUSE_S3_EVENT_UPLOAD_REGION + value: "${OCI_REGION}" -### Objetivo +Objetivo -Região do bucket. +Define a região OCI do Object Storage. ---- +Exemplos + + sa-saopaulo-1 + us-chicago-1 + eu-frankfurt-1 + +Importância + +A região precisa coincidir com: + +* bucket criado +* endpoint S3 +* credenciais utilizadas + +Exemplo + + value: "sa-saopaulo-1" ## LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + + - name: LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT + value: "https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" -```bash id="vars46" -export LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT="https://${OCI_NAMESPACE}.compat.objectstorage.${OCI_REGION}.oraclecloud.com" -``` +Objetivo -### Objetivo +Define o endpoint S3 compatível da OCI. -Endpoint S3-compatible OCI. +O OCI Object Storage possui uma API compatível com Amazon S3. ---- +O Langfuse usa esse endpoint como se fosse AWS S3. -## LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE +⸻ -```bash id="vars47" -export LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE="true" -``` +Estrutura do endpoint -### Objetivo + https://.compat.objectstorage..oraclecloud.com -Ativa integração OCI nativa. +Exemplo real ---- + https://mycompany.compat.objectstorage.sa-saopaulo-1.oraclecloud.com -## LANGFUSE_OCI_AUTH_TYPE -```bash id="vars48" -export LANGFUSE_OCI_AUTH_TYPE="instance_principal" -``` +O que é OCI_NAMESPACE -### Objetivo +O namespace é um identificador único global do tenancy OCI. -Utiliza Instance Principal em vez de Access Key. +Exemplo -### Benefício + xkthfgahad -Não precisamos: +Como descobrir o namespace -* access key -* secret key +OCI CLI + + oci os ns get + +Console OCI + +Object Storage → Namespace + +⸻ + +## LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID + + - name: LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID + value: "${S3_ACCESS_KEY}" + +Objetivo + +Define o Access Key utilizado para autenticação S3. + +Funciona similar ao AWS Access Key ID. + +>**Nota:** O par de keys de Custom Keys não pode ser gerado automaticamente pois não é fornecido o Secret. Isso só é possível via Console OCi + + Identity & Security + + → Users + + → Seu usuário + + → Customer Secret Keys + + → Generate Secret Key + +## LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY + + - name: LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY + value: "${S3_SECRET_KEY}" + +Objetivo + +Define o segredo associado ao Access Key. + +É equivalente ao AWS Secret Access Key. + +⸻ + +Observações importantes + +* A secret é exibida apenas UMA vez na criação. +* Deve ser armazenada com segurança. +* Idealmente usar OCI Vault. + +⸻ + +Recomendação + +Nunca colocar diretamente no YAML. + +Preferir: + + valueFrom: + secretKeyRef: + name: object-storage-secret + key: S3_SECRET_KEY + +## LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + + - name: LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE + value: "true" + +Objetivo + +Força o cliente S3 a usar Path Style ao invés de Virtual Host Style. + +⸻ + +Diferença entre estilos + +Virtual Host Style (AWS padrão) + + https://bucket.endpoint/object + +Exemplo: + + https://langfuse-events.s3.amazonaws.com/file.json + +Path Style + + https://endpoint/bucket/object + +Exemplo: + + https://compat.objectstorage.sa-saopaulo-1.oraclecloud.com/langfuse-events/file.json + + +Por que OCI precisa disso + +O endpoint compatível S3 da OCI funciona melhor com: + + LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true + + +Sem isso podem ocorrer: + +- erro de assinatura +- erro de hostname +- erro 403 +- bucket não encontrado + +### Fluxo de Funcionamento + + Langfuse + ↓ + S3 Compatible Client + ↓ + OCI Object Storage Endpoint + ↓ + Bucket OCI + ↓ + Persistência de Eventos + +Benefícios dessa Arquitetura + +Redução de Crescimento do PostgreSQL + +Payloads grandes não ficam somente no banco. + +⸻ + +Melhor Escalabilidade + +Object Storage escala automaticamente. + +⸻ + +Alta Durabilidade + +OCI Object Storage possui alta redundância. + +⸻ + +Menor Custo + +Storage é mais barato que expandir PostgreSQL. + +⸻ + +Facilidade de Backup + +Object Storage já possui durabilidade nativa. + +⸻ + +Recomendações Enterprise + +Usar OCI Vault + +Evitar secrets hardcoded. + +⸻ + +Usar Instance Principal + +Evitar Access Key fixa. + +⸻ + +Criar Lifecycle Policies + +Exemplo: + + Apagar eventos após 30 dias + Mover para Archive após 7 dias + +### Exemplo de Lifecycle Policy + + Object Storage + → Bucket + → Lifecycle Policy + +### Segurança Recomendada + +Bucket privado + +Nunca público. + +⸻ + +Network privada + +Preferencialmente: + +* OKE privado +* Object Storage via Service Gateway + +⸻ + +Policies mínimas + +Exemplo: + + Allow dynamic-group oke-cluster to manage objects in compartment observability + + + +⸻ + +Importante + +No OCI, esse Access Key pertence a um usuário OCI. + +Não é o OCID do usuário. + +⸻ + +Como gerar + +OCI Console --- @@ -1405,6 +1711,9 @@ Ao final: # Referências - [Langfuse - OCI Object Storage (Native)](https://langfuse.com/self-hosting/deployment/infrastructure/blobstorage#oci-object-storage) +- [OCI Object Storage](https://docs.oracle.com/en-us/iaas/Content/Object/Concepts/objectstorageoverview.htm) +- [OCI S3 Compatibility API](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) +- [Langfuse Self Hosting](https://langfuse.com/self-hosting) # Acknowledgments diff --git a/src/langfuse-k8s-cleanup.zip b/src/langfuse-k8s-cleanup.zip new file mode 100644 index 0000000000000000000000000000000000000000..3fb8dbd71bba66a0cb14bc962948b7bd5d8760ee GIT binary patch literal 53323 zcmd441yok;wl++6NuzX^bV;XlhcwdN9ny``-Q5k+jf8Y}N_Po}2>gJ@{l2oTeZDjH z|2|{fKA^*O^IU7rYhE+%g_I~T2r|Ik>j`MC>irl0^9Kq5E`W)qnZBN_weC}67VD?l zCc2ttwieX34$uIAAg6!;0Qdh>UJe!jTu|l8@NOY>Ul~f>UlIZU;@>Wbb9+e*4RIbm zNm)f|Dvcjq{Z|)9zrDEjOB8MWms&3m#l;j3;T8O)+<`*Tfk_aa03I3Pf*l>uA%J4? z@p`6;g$84B7Y1f~Ly`~lx8TMnrWC{|N`*$`zmSU5h>nkmjY))(u}1gLLPz)JJ|+{m z02RJKaS9+J66nAceh%i_LAMCAi*v2LiueH$VSfDca`$pNByzVDI5{uz=~{IVLdHs)5kKl;?GT~~(R)}D&739>wLlYZS> z`YPb+wf=IOw>(dtmKI4VV~?OIlD^_r`RuK0r=O{jcS-L{yI0e^_@5AXUU;Y z;45DK0bEip-2U+|y&ivA_A($G=K9ngi{40oZZ6DleJB{UT)T8UxfsN3XEB8Z%5G(I)AqH`egP~J835oA( zJ!FL!OOcBpK_gyU+izEY!~gSpbqwKZF2$I!u#o zK!gJ|;7Q${H?KZV_tDxycnrzf+J>nyPO0xKR)_G6tw{PH$4)6FK{%@dzKX3W%WM4! zmF$eo?C3*G8+iiaE48{j<#ttpW{>Ais+MeB<_9Sh5DNIIxxo!2kWHWtodHWJmqC}^XIhsykmD%(# zty8=r4`eg@9m2XDe;!u4S7u9RZ2NFeHEOHU%8Ilx(NOzC_1|09`P!(2pet{b7PA6# z1Y(Vg$urxZgbA#x43|PtiO}2xzp=23+c$)u7%$Jcs_iDb+>(#F+RhnfR_8RSx~T3<0n>c4dd!u&BWm z?>Epu&}&O_?E8elGiJj?paU5bM927Hhmad1qcRs%VKk77ypm|((ShFeiiZ+wfh}|a zG{_r6qa7YVyi^AkSq;kgVjWFKpeI)+`)U-u=(Uni0nwufiqwcz%Wkyu&D@KrI78H% z_Tl@WQVvU9}D|y=r1& z-&XH@7-n1cXCDr0b+)}OG1JfPIyY(C zra4RP(;MHv zfg^tVZ$+3*8`HpfRwN&{QBLD58!gFIm}`XU?9Kj$t1%kkES#P-`x;A! zpF7Z%n}q!H(493tZqA#H6F1HqK{vp=kW`Y_9%+9RXK%yrA4Q*E z$K0|f2wtC1xcdNPmvLL%fmwXLL3rX&Xw)|Eel~CjX#W-##@o>7@LhNm&dB*rXb}D^ zJjw|0@QVv*$O!NY%Tk%@{3uAq<6Ie@-UiB#w@Xb{+^&i@W7@(WX`Hpy7g%1nG$cQJ8mSqLVuKea{(lLsc6xGAP+--q?q` z;P%f&2{KfR6&t_VOCf*XNH(>~Sfog6b!AVn>HD%>{07+@foh29z|9C4pdp++4bmM& ziOe8mZe9&<%4wF1_&u3XAuQ)nEUi$69^Mi#2KgSolnM^^3x9qoPL}TSfVii)Y6{rf z3gM(MT6z^*S&F?rA`qC?7`g!z0=n0Nag#--mR-grCCJbUPm3e4y8@brPReQau?7d= z%_SBO0@T1QYb(7)Dd1#y2_mnaZ<)~1j&AIedZSUSr>?ZGFOD|sKORwF8R+GXVj?i* zg8z&`p7h!!%yuzM6rHx4Fr}Nk3y>i!VZI@z!Gjn_?giOS*}Lfq(j=d2aA0xFR$B^9 zmnxIQC~uCYQ7CN>sha{sIuC33E|rW|cj&s%g}Vc6jbp^x@H#h=8!8Y$iSy z(Cp``Z^0KBfkSHm&7q#0EVY+cUh`1zwX{ICyy{9?aJY1Oy&gGP`m$mvox39!4GMR# zGAGH2r_!u#lcksQbWx8uTuqwBtQyQK!ze%)2Zjy6v8baC&*_yDr-|@S6{;NVHii=|}KZ3DQ5*+Y~jrVig z=?bZAl)|DnuFBZ8eJ6do-!X?RisD*k;hD0gJ$jHHj zT{*9rk@!g}qb=Ok-n}~ zVE^wV9*Q8v3p=lRA?^{a0t9-Hc-$e1`5=XR{4+$U%(XRt2&vF*4!3g4rFZXtLHh8z zcZ~h7Jnm=F<#vl7Vft-{e*~t$Ag&TOuOeaZF&$@8hW|d9yTjD*ftCIgQyp{dADe0R zt(ksXe_{IYx_^S{-4;K>^xM_{5tu51!X2bIM192+D#)Mydra@@0wC$%d;U)o*)T$F5t;iVDnU?GHOldb2-F()%^2BqdZr8fNMtSG)miWJ0T zy1vqFkx0Hqz&c8(^H*3J@DH)Caj zBrsx*jBz#&FF2ssuAshBUg~jQr;A}~N>CXjz+N~fg-?~xL=LoV1PFsZw$XYpThJrM znuN2+pJ1GGI8Sgt#re`x^wrfk3(epsfYACIuOAX=MPnvF2HfNYyU)i1xAlBkuE`ai4j;deo4wJU)6^yA5ms&lAt1u(js#KsIIIRIE^_)K9AtDW#jqMJfv=& zJSfScg$RO*iYl?jt~HvR|Ge65Ve#5yQSbeiBmHBp^XlrX8W2`$X<=3!7VThapQmP( zeT?}Hy{d4uqG>Rx>^yKn^(+BgD5PAP=&wsP0ugAstYazjUwid2iOVxfDUW@Wu@FR( zZ1V|;!j6qv0$aq@M@G>!YjKURPV9wwqsN}lxUk6)@pd?xXeMbqqzbsW^-az>kJJW8 zz|H5l_y8xmi5$~7-u9_T%SUF4_$kuliV>xivI-_K<^7l11&|UXd2@!GPa(7m*sy|u zRJW%GLfI*zlTof^GCXOx&E|kJ5(mj(U zP7Y&J=676NmjU_NwtY>L&AgsX4c8Bnud(;epA)bnaNaORJQgEMTsFPhAm0NqTdREkZC8Y zLN1Xrpb1z`V?_ksK1X2Q`u0HVV^ooYu-FQ*y68>A^CGJ^l?|7J9xsp!(AnZXg0%6b z;#2bQ(DZ0j>7Z&)1byl64D>MN(XRv{$x@FD;zyVpdITI`X7D=cIZDWcxCOA_^#KCT zdrd>W3a_FbYR};JM8%48ju-Li=+N$yh{i0y6@eTb@F{+eqc0Ix4#%0_@M)UnUA|gD z$J5HFy^JAfoEwLaDingN7m+j3y?jT-(S4c^j5}oQs+d|GxwHUm@!q4wDJ}#Gm8tgN z1@r0v_HId!SF21_OG1LaNtqq{)ag6hK$*iS#~?NN{hn?d=-5S>ZEirO8Mne$qC~Mu z+*cnAzF4xl-t0&^)N}|Onkw!}H#wYgR@?d$Q9GcFs5t03q+R4IHa+Pbwa0t)lFrw! z0LIvV5k3MHUU?i|-ET}FH9c5+AX5PM2KX)q19{=miwX(=01Wd@d;N%k|0G}hEg9d1 zpWlR_|As;>cfE{&OsCFAPqCxRq+-&xk_)t{jVh|*3Sf$wYHU^h0TxS|2GwR_x@M>e<)K){yp<)& ztK4=U&^d3mc=a<0a@G{kql?XkoTa@)77(sW*8^# zd}72vOB+bcN%|P)okLLUC-)Daj0T>tMu)AWv|;?(o=2_kHsd(--DhVzBoMF2aM!~vI%wwgA=Se%9v|n9~ zB(vmoj~KqqQJberQj6b{3XX__OKOYG)U}(6M>~*Eeom~*YAKT}_gbe@O0{U1CjB!{ z|Caojz0sxG!IY@jOthwrV(|W3^c~9_sMC+E(R)lAGjEW>Ei02An<@+%J({T*%@|#1 z=ZEIN3=QbwItG@hV;XJ9)xnWnN>Q_U7!J1}DGwq*eBwDp!* z?TSjRqQlDI5t}$s)|)}{65JECZYxRRw1eKweLzH1@40CK`SP)n5p|WPuS%G z+s>XTC?z}K9i!z=V#t{ky^0NtPFz2=ANpJiAOF08lPRyxc$$4G3L0^~Z+q;KO-&!V zC$8_4{J7ONM-aUuIb7%630de~qT{2q$rgxv6UDMb5EGZ*+9gZ03YA=sfpq~o~6eXiLX0I1tU59v@o zCmb?idf6|%VgbZy6SP3&^cb~>?ztji;o|8u?V$68_Mwwd3WI1Cfa+pqKkv!W=QN`X zE{J)P0}gF2+??K~$Yhk@s|$yFcBRaX+Jg@}-JN;_+)dV$vguEe1MZ?)YI{*Hlas-)XUSFf&{4YxOLZomJ80}K>qkO`^gg6ja;usFl_@hx+T zJJk&?Km`|!{E79&)1~nfnwG_z%gdV`mzx{rJDp~;=>V^JtJ6S8|E|*>68h8MMzecn z|No`7e;3vtRyBSZfXwZ5txPl>f2^9m)iiRxQ%w)APx*&cjE;# z-;Eb|{&u{82;)B-F8~2iaBv|x1$FLreHA!&5Ici?ubh5bJh`(3Elq3P z9~Sy%)vgS`t-r+6!)ufNA-s3n{0Q1_JNyRP|BfoH0S#uq`sDdlm7<%bmj1hbdieCCI*PS;A_HVw%?s8mL&_D6_yVlY}Jy|eLX!d@e(`oe9sgrq^9I$g`NoYeI zT&1N18_P0L&*d#~*Tx6%4!WcS1b0NDi#$+RPt^9Xnls29~dplloF8P;p36~ zNrCpRIqQvdbzl6pm2EXcriE$TpeUTjUJ3<9Bq4``P?XEFL6B2L&}t0O@0<}s4Bs7z zsyQO^2ma7U(igJaXEW>BqnoMEb=f$TOvDg|7|hj$1Go^rRybw_c|c~_3x)*4@VXf( zLuTjH$*cB7UU{V@j6PaHHX<+USfPyaj$4o6V7A5K&C@|p(d2>z@$AYRk`eu4f=feD zKhh_V#EHU<(-+ zQigS43_--UPf*F!wlINn9~kd4j+@ZImkR* z1PXZVaqn9@Nxdh)m*K6DhBLX83t$M4DYaur1$Hn{Xi%`UnMaqH#?#9#QD`gG>!dV{ zr~$8&T)1}y1VN2=VnO`ny08L$9y^_AMUfD&H8sI#`MD?|=|0gzd=R*GoH(~)*r{tpb`Wl^0GO3RK-Hjf$HlF>` zjU@SmH6(dO1o-4MWaT7fcmxGB#Dt#<@G0?$3H-#V?z$eix0>iq7nz2)1|snw_#Rv# zbFJ0|bP5bNK9!bIRMb3bV&sS_n;00InnyzHo^?QgPj>Nkq%F`7F9d`K7MMIoJH26~ zpDW>9ZgSE}ISOTzX|IW3yljMj9gM#mJfk;HVz)1<<-L&&cH~?cn18;=k|8Na!3yUz zA%@gY^~@+00_U0Iv_%36V+NFR7KPUtPoBg}sV@t?3ZrGE9)`L?e!Td z0$l0I>5?TLgLRV$d$jN+VO%uh|jD{Xx$fDqcTV(1L$+KJLjk+h7I(;b&lfOnSj3p)kAaO|5NAqUs}dL##J0Z zIg4+aW52qJ1W&~e#MVP>?kaUZY$o6H#cyKGH@CPG^RMJ)&5&pjUY);qJrnbMJA2M2 z&;h~_Au1d!oFP}WGHzF*%B+^6_(pTjhAL#X|l3$^t=~!M` zU$%1_rItY0DnXPr!-v$<2olLwhCZo!)+1u*t7<^R zdja-mTx`A^=AtvuPIv>|&+;wcT3Kr7M8Oq9pLdCDJYBa?OFyHe$fLfn&>=E@x~A7o zsQSX6G>}|RvW|w<<3$`eVRsyTeqv=#U?<{ymST*kNQ37)M5p{OO%U#+%1RN<5{1Ks ztTMS3@>`_ju>yMU1%%Z+doG$Ma^aK+wpF+kw4ZwjC!Hlyl19|7xH*EJx-GPM^~F!w zx>pfO)(@RnwKE!CSkH*~^N@4Q&nBXfPuk_YAazt5;h-!d9fRdJR&2HrG)d!X=Ul;9 z<}A`_3*(@x=rszC&PBqG@;Hm;e&V39L32d|0%SZw99gfR#flF1nVz(K>iq#ST69D6 zvzN32A$VF@TtXtowG3=~JUOF|@(~zm45~Q6&4fPt<_2bAL|L>sd`;I+x}JoP>!E!d z*<^hzO1Ec|%Iq_PS@~g4haCz4(t7F47C0KdL~B3d&9f$alFo>TR*(hN7OyD_y4bUh zLmL}bFOraWF$oCSL)}&yc>T1MNHuM{A|fK@F%eZD9CI47UKbLrE%BlmqDQfdgO{jZ z)Wb~=Qv9x@c#glAxIGgR4%^_=LA7;a_Hrz7bLI40P%?KoG8}4wVPcOfH83$B^lJx| z!nPAtp1ABTbMT1|>KYm+InSgR#Y65qZaHp^&Z2YK03=K`r;Bj01U+DA$2X5=3tACC z`y3Nl7-fU)Fe`=oiiFU)P5%>=IgOI_S%T43R`xKH+lKjRAvW8Br&EWU#|wGwSgGEa z=CHNTIa7)YgO{3yZ9Tb#+8MxT(kb+AEpLSqZ#{Jpem;a>qjgK$R00w;XhGTTA#k57GQF5B*x=-MQUAhI3dz zuCeON-M^~bA*#%r@5A$5^8B!VaF^izkaNB@bhJ$jwQol>Z_hydFpd6JJNR{#g6_9y zf7|Xh+4$FnKgu4z?e~w6L!UtRn>g&^z9!VH{v1D$Ll3)L#J|J)mraRpO|HB5y_hnI z+uYfA5KkzZ5(9&yLcW1Jx2<~&joUOI`K=+o$T`eBMkqQ08$AIug?Y=4yV?ziA8Wc; z(Gn-wh41BjJzRh`K4PQ53{jxJP`K?B9yQ|RV?YzspeSO7Y)@2%oUof}bl+*bzKYp2 zJn=1=#iR}Uc-zZ%d}`C(rLw0nXu@={sK9D5=gcJ4_U0uyd($>6CeQ3H6KHLzCdcC> z)QvR^2T6?wFd8b?=ANbCBrYtN)LBl@=VZ!EZm>pejrp(lV`OAeuMC_w6*@avZ9T7D zSM8ZQdl4l!cx8(3I9FI#k;pa9@i^e4pLY&dg$e|PW6eD6?T^IMcgfRAtEvP&2FzkJ z!C&gBT~m(Q4Qc@)%HoNF*&fBHt_Zb7O%OFi3 z&U0^Jt}W?TxQgw&Z$&iFQlPtU@Z1Zh14A|`3YO4|3orQGHLE(n@92cUN@7wQ@U|?8 z{&zZgcw1@z0|Wn~JN#?={*T9wf8_dibAi8feJfoZ!(Z1X@4WFZj(x~2zpvH)<@NV_ z{o@_J288NuLu1R=vrm~DAk~K8Je2>2pI3%+VI`-yIrqB zd5nQ*5qu7OuKj2n=CgU>vrLeAd_<~2ht+k3pFio-ixwW)ZZ@x~pGcUDJLq>l>DkJ& z{P5(N;xSYwd2+TkSGwD{NvuCsNI466vK*b+Ox>FId zva^XoIH5F{<6OH^wj~>h1LgO2faxH1nnO(~S!Y;RJ!MQ}$sd`+RxN4q4xXWKiA#Cl+nKTVtC3d@XL&V`c zxnZ846V9bU8ZRMewfVjyMavblBp!etKpvY_kwQYUzluL^ssv?V_+Wz3*Wo7w^<0~5 zO(}_Cx-5Db`vapmi`1zF(;(CoMLS-!zL;nAD>wHf##Idbc|DPanRrK5SFJ{2S6W&J z64g8d{1OFi-ia1KR@H7VxM1!$A+L{ISsg_?3RPH64N_m!hj6u_tT7=>(1&;tdEA>x zBHeRfRZBj-87FRn*0{4FjK>ajMYlEt`kf6u#OL>s;+qXo{Sj3E2s`ltg)^_6?EM-k zux!=Q|J_a)9!y*PH0}BN@$Jp6jIAv+wRNc+eoRn|wux@(NWs+n!*hh|WR2y| zvJ~S?2Odbv-Y~**2tuV1`5Z|@AF$dz_ukq~5^mbuG-^Ldgcd}UAV&=6NOsg)pLU$y z-`F4>W5Oj|Ir33wq^JWc8zc)tL;LJyZ&-Oc*jQnP{|U?$jVWIna>u>}LnX(CWv;OToO#qI z!NzG(MCzCCGV6$FmE5P;prtdVA%q_1L#qWKzoH3r^+L6IDFKU{R5xtEJsMlhCZ92% z2|Hq>u=CD*v!o@fIBgQ*mHK9VE?k6V35nYvn1mZcEjc};5a}}PmGQ>5lee3>o@8eX zLD$*bNHN4IaK(`h`_2Y?|L)H9CnFXs)dRxGjHaFbY(9HBr^CeeHIn=XtgzvmN;#_dR1R`6%#BV)Zv6QSD0*i zj@Q`iIA?tU)<)n(@o?Z9i`58|+&B+5LU|w8Cccm{{#rqy^_5vmsl+@5D^&t~z9tB%!wSuVf zUpS&Zx>Aaj7=|kV7e2LeGm>wNBvJ}DC z@@eDCbiCN*nSp`hK#}c*WRb4V)F=;mt73K5qcuK)9n+P7yevF-x>~`IXQ0+Z;_={c zV`71_G(5hP*JQEGPm=74BwpnrSuHSl zK0Dorg8GD&`=p!98&5?OC4=wvd}OU#CZGEESImI=6%yp4QUesFO1tr3c8LK4(^HBw6B zdIR_CQHXQVXJ2|S3s<%sC=svpP7~jpR~Lv9Ox#hVC2;6L*mz4CNWi16v#=_zhFT+NpcL(mc~vzDk!u+uccf3Ty`~d z>+a19Zg;$luN-{x`1Xh#HPqi@`$ImW|Kr&H$JF$Xpyn%3CnvL#wXYSDViCEDf2Zb$ zGUulW(^qOXHP^8RQV7W?on8)l>1 z)QkAx?~KP;J|C*-HmD1J7t|jj_WR<)x1j!q;Qb>^hYz&rs@~%D*L*}&N&E*<{UH!P zt!Vs@=@?pT|B2m*he*S>(jY%yB)V?ze=|w;fk$VpRR{);esIKOlCI7!&u)3KKht`l#dR(rgU)`I0;b;;AW)vzMix0s@`yZ5>qX%#q;W<`ohT_3(Nu{0B!Ge@Z!b6J*~e=cvt% z|6fYrzgOPhZAPVWyWNjc<9}2EJQJkq>2yuZSLJPa?i=#&^zQgzT94t@;=U^ke0!?W zzozxH&CT=-^-VP`zCCb>%2D&jDtzL0hHvh6-A&nL$$fqJ!N!Z%Jt$Hl^4wu8H3MgS zEI4nI6xOuF_k`=l>W%FtrNfTRSq}L=ccDAOil;G4gxRk*#yOf3Pjyq2OFZWA*jwII z-!=j&8#buxwIAZN8wMz$C0Yi04cbd9syu;435ntAr8+<7{6$IKy`;^ejjb~m~g5TWJQMDjD z{luv&SVlU&PTons9)rC^T6)?3JSW}(cYLhVl4IP6Su@CyXU>?WdUpkt4aBW>WNLrB ztYz7!N^G*AN>%4ViM*TxZ$utnF#tRrALM(1dRBu z--4gi<~DV?>yQOqQOAuDuiqv5nIS`a3q|KC!ayf-{+lGy@@qqY(#cZX&o!_3VlZu^mY-#sVcp<8hMmWco5AGa;C|JXx*!^|SL zqrK+z-;MUZ{{3k0fBNJweh{W>XpnneF3HO(^uLWxv$yN7ir2$QDwf}J#eEg=>Hkz& zpK4o~n;DsF{gf~6=JEV)=ke~U=}|J`#&a}x4@>dKw1OZVAf^P>02W0m-;xoL^r4IH z+%Y`$;Y5YGI*QUFsZl>j%Sc#gU^Y(%32w@O*AZ`5_D?U7OxR||m@XAG@2@bWc=L#m z-+;Um#=s;N$a+_XdtX{+Y36a@grtQ9?mEX~7) zZjz^e2d_dxUu577u4rXs7eZ^7y`)AT6}%{Rfs*7Iwue}-^?=T6$+D-T@n~C^GVOB+ zmtT7h498tylj6ZXprYsIhsUwp0a|K=2T00(`#?lVP zB#7XX4zx6*L<`l35k6y`CaVT5YCi=CNLRqEKQQcCx=& z1AdNDZ{0BVp&rWTW%vq#<+D5?Fl6kNo9#D+Sqty;GcC;{0yO)tNtxD4=_JtB0ksxg zG8u7bdo(^7?d0QlB+b@VPJ`MbvI&vz7xfj^OU{~}-VYZIaL|?I0|EdDf9FIG?S=0@ zaiag+bncw!H;(k*nUN<1(c{=T1ikkp@7mgl?`P!i>Y@n`>Y_iL!uuDiSnFzA>Dv4& zL$?8J-Ha`q zzQCJQHhOEpwJk$uBXG-cLSlhO(GP6_?{V_O6XKcCXE{!n`IXalS}? z=g`{$udbdM^q#XmNDS$i()v-XVNwZYo#9MTWQnRyn0=EF5+XxESO2zVzt?4!x*86drSUI@1u_@#W z*j-|#OC^GLaLZkXw>J3~e?3I~_rq@gf}cv`e|ZCbW03!ylLhZU>keF>wL;!oWPwcn zlYiHN4~N};+B^CeB!3NpJT=ucG_%n)(=^l8{VmDgP2}X=68txkpS^z~77XO7RA|yv ztYmEGdmxdKd_S6e44N zPn`(vL47#6g$@^e4(jqgT$7~q%>YCYspl~n)%DtmcI4pPxxQ+7m$-$V5w1EGy_{zR$Qgg{w0QEX)c=z=*FX+^zE9b_jYMR;!lX2mr3X>3nL^$5m< zuX;ukP+tk}jP$>)Esl*C)0!~cA*|S6ES{{mpTFJ%+N|uo^|;{gqQFDT`hB15UnchV zX`}zx$o?Q4{CB*M5Y%ZV$3++X-ur4RJ!Ajf`}iMZVRzZ+ud^`Y`?EcUPMS7`=4L+) z1D3a$m)-5My<6dfW?nQfod=GA4FEii;zDfZBb9qJhA(tvfHB?$e2{wU{23I==UU0E z%emUTww91R$D&dH-~h67DQ=j{UBZ08!j!kzrq9aq*>XHv z-rQ!g&V#n%B`H3jVZ+839{q{10IE3>;C)ywiJ%jzgC&hn8g8J8x6sqTjHgpB7@@W_ zoL0Q6+kL(j+(W4Xfk-k5*SjkYou#+BIR>DgrS>8pH%yc0LYoNGW|ZpBUIFDLnbKL+zR8~iQy z{}?j$1|?SG_!9T^Ark@B%*y{xrVj(o-5K0po1U4bsqWW)^3O_Hf44u_?lM?+8W@n4 z1z86`C}nsa;TwEOWDjv~;FI0+8!`p=Y+M?nX6r$`4pJOPo$KTUq*AG;Ek z2D-s)GW2vHS8a9R#(SjN z9wS9l00jAp3>nN43nDIbjDZF68u2Dv`TJw9A?pokiTau-3rJcaIDroqKj#iDgq0ks zb+_#IB4x|3(EHraF^3{)!R*4!9yZW}38XZQlc-Qmt+~OQwe1m=m5H8EIBoeQSIa8x zCjGSt5&LliPgY)2qN(HAto-78hc^LWx60oMGoSb3L%g21d8e6^SBkao2Ps5f8>Y|w z`%^q{3?7G^kWp(NbNB&hvl|fhDBcEzj(>$_DyVytvUy1_PeTGuR1F_@H&-pf29stLA%ccI&7bstB zGxOz*@U~|8G=DnM6fN5I;~mVgnR9y7=@lxLipobhi@A0o*KzT^7g7~&uUy0v{hwzOe=GE;9Nt4ilK^4MC@p&zCXIJ?+I+}M*fPvc@IT0mp8&c@obgks&u zh-RnKp7B=tn^zY!-;r6ZbDGF|KmY)*UrPVy{|TA>uZ-&-!)@Lm%2jh*{a-~tBS$05 z@8i_n!PH;JDGNL8KQ5;JJ!09)s0Gc^Ah?{DAWT+!4!#f}{ZxeMUBxhI5!r;jGtR1z z0Z&i_b8)VwX7z%^aur;=zi+>SQyi+ zNN~ZT@+JFM5^^C(6I2fEc*!jcKm!l8%ZB85z(=NFJQ@vfW#DOmQ z`LPP*8M96E`!}eufwW|H<%)1Acrlwh%pLD>UkSiWpNw7@T!WV&_3?)x@~u{5Hh)ou zSr?)Ye5XsJK0$YoE%)m2&BfS87t0n|5Cf&y=&rS3chyr`L~6_G=^18<#mk%)m7^EY zwgVkYgdt|s#X(uw^i9I;h~YHxVX_3S8dl+E)a4p;iyCF`C3n#0WE|rJ%a&QK&D8CI7v2`XgL^=r!Mjz+ZJL>c76!_*=<}%EIwS;rs6n^yYSkaGMGFc7{;X z5l4t2df#ls#wQY9Nm$;7OwOZtd%q}Mm8R(J%Z-_Vr&ue^2bgS-khrE{sZ*S;1J=nW z;m4+AQFt=Wb5}CEDjk)>$<=yK+TPh~tg0{(mi831@zawj(i}suFP@}p5qkD6L(}VL zdoX@TmFm1x}-5IK?6aqB}$Svv#&tKacKx(G1h+ zU1O-&@CShFI-e~h|az68cxiG#UTjv97_1cXd|mC6Ae=EE?M2?m^?igDH1Um)q0iiPW^ts^M$!jG)AVnL<)4k8TEs@YG=geL!QG6w4l*}>N@~to28hfCuKz&LUUR}=j zD`Y|Wzv9z)Lnip*g>#_?PY#&bM$j5A%j*HS{f#Xv8bYrS9M=mJnBrWYUWyYahigN! zR+7D_;lsk2{gsXnmdU|tYD|x|WT4(;4Of~eikP~ja=gRut7e_a$iJ9W&Da$0$2O@u z=?253D+@PXAMG)5{p>#wrthu6=Lt(rfpm3dy{K=X!s4aeojN0yb=B1KCQg%WWvmKv za4HyBeDU^I;?!HIuqs$=gQyUWt~x;yK}V$9SwsvR_`6Q}n(_su@13ofh7)H(qR@a{ zGEMQQK^>Wh4P|j~(B%$3N#Vw_0$_^iCD^oGqE&SU*Xsk{Zku0M{X`Rq0n+u}cmrB%=3=C)3h3ol%h^WV(~zfghD{UM zv&n;M_E*x&uO*#6PP0K8@iqG+Q|<^O)OvGkvVspct?Uh92n{!dxZt949ZHaVaBNJ1 zY4h#+FuK~L$76)5^Au0hU+chrydwuIO^{YRY|C7r+Rn5?JVsa~6(&a*cs_Z)zbhhv z1ZbMDQSp6<4xN{=+dB)3$2%;p_}T`6x+5P_o9*yK4HU1L>-qIun-k~6uf;yQboc9^ zN>XQdgr7p6hFkUbGPO+_31REXx3D>PDMV>zAa%^WQO*(-RQqs4WVgpj)%yYKMiT(C zy)=P9-(sTq&E*n|(S8F#to)i=>nZ7EEaL*2<(r9W15*+}9a=Ps=S->=SKFV*fgS1D zJj(lmgDLq&DKjKYnRyz%{w9lA>mbUbTTae_{CgAOA^-foocRMH`g>vX52@%6DEhxs z&ddZw#Z;T^`PxkAe+4uB@5<(3K@|PTa-|VBl|MT{M>HV+q`UxxF^@zD|)3>|! zL6VGG$mqSSDg6@39pJ>eg%I_{eGFfs@OA?Kz)Iocfwq??WI@UEaQ=y588YL&NY)vd~ zSI@JMNNasZI4lAmYOPgivczpVio6#2VX&tlX!Dn3Ngb*EnWH>Vkn?h(S%p2>h<(&6R zY4i|tuEc}X>n9t;2AjITf#w4KZfr_c@tFPYSQazZ@2Ro)0eqhC+qIj zjN3EGiOrC3XnlGYl!H_bK3E!$ZFDcOUbiep7ciGCvj;LVZ?u9fB5vNW+Jd_dZ=Qc5 zbB=u#BuG^tz|x@4qpl|V4whjCe!)N*^6xv#{$b;ow2AlW0JN zM>W^cXJF4p6!|dq=yYzzH8!vW3F3&1LRyt`)x#YEoYP?XO@QYMl9DIPiVc#5#PRRE zHHUV$*A{8%u3lupztUZ8UzO8OI~;!f*t%WlF21i@D)m8Z*biEM4|T*(M?k(2*tdGfZ5DGMAT_@I z#ZNr<@A*sri&?W3rn@K3AdsVmDZl78n~h0z?e3iEG|c|kT%O&00=%&J@LUHx2 zT#{5rPOc2)`tE&Br}lfi=e+M*p5N2+`^F>u^M2N6?X}lld+)W^iuui4e(Zs1ixz>} zGMaKRQc(>l(={AI7Kr9%9y=+fDm3VMv{4$%yKI&GipsR{I#(*4*e@&@^R^}P z@uXC_8Si5**Ds#Z89h`y^xOwlU_@}TdV2nZa`!`R*Vg_XcPGE4wKbAfzIaJmqn34A z`t9(e(H}3=AG2%pKXpHHMQqv9w26DAb(KuL6FomW?(wV8S6aF-apQR}n?Xw$=hk?d zJXrBa?NDCnVF}YIZo8}EU7Oo1^Y7mnrop15xf|0}s}xH;O>V0#&&vCd@=EdMq*pShC2wpPxgylr{j8qZ!{j6HbDBJCCdaa- zXkU@o`yr2YVOre;*B4T<9kq!HPS;*X?;3jbR*e0QuTNNSd;)6e@1NFe8W+7?>a6Bt zGl?|C_ixw(s2($vLm0R8j)fGIF$*6&`W?xaCxXR({wFd1;~HmsnFjz3@~nS(x~a_2_F} zuAF|#{-`%*CFkPP=g=MZ{OCoRzK9>hG|_b;3n`F`2)F#`8S0{{bq}`fP>|q`Lu|ocwn!KOLt3@Ni zMz39_lRddAWsLgmTNB6pmey{haX%u*e%pr*>vbzjq_3`KC6~Rj68_=Dm1WDWo-0~# z*I@W$^U*goW-SRhR#YA;F*4b3>XHcarsB-R3(tmR=`v$CUK{_?^Mz%V$}EE!2F2sj ze>I45dT%hoTJ>H|ncYyO(5IuG{I=n9>B;5y?!VLvZ;1%6@?wf5ZS_}bJ?a@_o#7OC zyER=;>SA_~Md7KSa)v=e#*K~(YfGJ@L+{C^G`HKm_0RcD!9_t$edn#Op#^c77q*wa z@vqbki%mJOzfkg&+V5@_x($JA9$YxD@b**skH)RBXTH>L-ksENbzSt>`Qx|5%NF@} zII%<| z+*KUOa(^>S+kTjA)1w@dy}p{6JA%U|vfQq=mlr$B%S5|r8_SESf@`+jN)e9o+58uD%w@x#gQL0p66|#Kk@-Gf48BeSpKGKuSxZ2J+ zcB|STdsGG#A=)k@XnRMTBleAdhMPOm9=hLb>xx7h-fU*kId26No{Y2pHq7K*vSt%) z>w3y7=zN~X**gwG{>y9{rj0#poy7TT-xCA zr>0C1+gDMX>g>3&D;MRN3y`yZ%jxaF;z3vq#h*LDIx9p^*gVAvzZ!-O65_yVcwCfs|a1vvZY{%l9jqpw)fl2h3$4%rCg<#ls zzAL|SMm%jeNcj?N-MV95v~1QCm&V+%ADk|WOp8mjWHu|?t$2F(eoNaqX^l&V2W2!= z4*xRP?Cw%$jhf^~#gFwDzZ`O~LG9U>)f<_UqE$CsG-V0J4wBnDSMPVBWTzMH3c3Em zQS09BJ90h#VbXq;JQ)8UNZo4T4{q(Z3ruMsmj;fZuH!DE?M=X$a^BktN?hTZ!^Qj4pgHXLd+wRbiU(BZ|GKzp!`%5{ z9!{|q$&-g9=bHsLT50~A-)X$3y-=fioVd7_zMeKlu|IzCJAL`2%!z{`D;vK`#4G!ZEjpaA#HT4EK>FUB&Fs6dcae;O6To`1fm7+p z(BPdj#17>feF1kuL1X>LhD29q7`~s*c`aF)U}%Z8A)qOtDLg4M@VPPWVQY8V1~+2q zxemiEw*-$_VYUqXyJswT;V9%fa&ghqZ@egg3k*lW!&TnH+tuCmt+kc?TWR}Pn`n^) z#X*x~l!gC~s@$ZDrjB*qbd+=a_Hst+J>n4{PB`Ogf^#S-NC$$IPh89Tn?dh70TqPV zFZ4b^bV=6Inm@(a-t$1G+a6-Q!)C_hET4OH(g(YT=QSkn9!HH@B?iyvNiIZGMU!0r-lH zcUiO~ZU2bp@A)Umi%1i&9KfL&$cY%pi5SR<7|4mhaYT01*Tx<F}!6ns*@@Y>hJ z?vHW&oFv8B^Cbi~e(SY)ufvQ;du>j%NcIAo>!$~@B>v~KBoCWSTi zAhg?2Q%b4mH=*cyv4#tuwjSYJ05)B?ODA5$;N2*>BkZ1|ObWRb+*NEKx8naxZp9Mn zvkI{sDoGaoW?FfO>b%!&a^>8}T^-el+{g)wj2JWmUWy7S^Hf-q7Xl5Ux_&Wf@E^F- z?3-%=F(KiFpx=beV$P@G_7Q&inYOGKcQ%hjKTTf_KHYsU#MA4eD=&-;h~$E^PS@w( zw~!DAy{%>n35`KO7<5ZvKJxQ#UImEMgUei$2*i+zEtok2h#U_7XkajMB@iOG%F=P6 z1P8a>*DPlL=?jvD3_ynXL=2qIU_O+VnbAzG%{bk7@p{ezVsNvK5`##tZAw4>3`ofX zRq0}o%%q5kQ3M4zLcBf4Mj@a~+Qy-L=)ntGJcEEep zcpIK!nJ7r}VZv_biuZj^->Du)0KYF8AFIc81Xv~k;QK^F0-?wt!M(2NO8VWAAYXM5 z7;3CH@BkhQ!(J#@qr1S_m~J{WQQ4JX#!T zTu35B$Sjg44-EAYOxoG;0+_LD8R22T%I&BPLJY|Q(Q+3-9m@FxQT_~_?xwj07{HmpEeN(?HnI*UZlj6~*CMoG{VWW&xrQLJR6ElH z>Uc{b+7sRs18=8ElKOX&1nroOI(-Ixqn1EL2xyJXhcw!hdMbu=jV@WzeuZ%W=o{n&2(icx7;>d+XQxwSH!e9sORIHBRGU#^G30MkT zRPmx7bXPYGgQcZUo+D{kyn)2*PiW5oEN=Y6)hM4#SYW4kV~FCiRg3W;W=CClSHr&DcYeFyUhGLN1$Q^v?2xMVaHaKJcL40t)g--Ikj%D~XF(57^#qhip* z76_y%sQVlrD@OaiVb_^+resO>0v2tahORRV`V}+56!~>Y1_isnGg(GK z4}FvbZgkPM8Q6$q4Y*9ggdJTMNV;(Dai)X6kB8s7fRIgIqN$oeD^Y^i`YTR^=NSg`Gh6hq>@Fwg_+kAWHnL`C} z!SD|)Y>C|%X8I8*hI2^9{>iN|g!lXa0OLh|XzfU2%mfkJKvoqT2}nE(;UfcDArMPm zIe-HBu45kxV%DW*M^f- zLAM;_GBWu{f|d=Mjj_a-%>;_*Iq)Ns_Q(ext;}PF!9O2KRuhOIq_XJvh=P{P!EOdi zw(wB}X5$UJo|6kT@nU|oDh+lsnEfM>BEAuWRFNJ&YC!A0U@hX&R*A) zx%lWZNhAOsZ*)h%q#chT%bT-25h21W2uK;NDuPC7OuFc{UQlL(6Jg`AMbi_RG`a0$ z*>*c)B2X@2w2%k705R!N0F?3=bMcAb@i=2GJ7EV|&WPJ3g5|PCi)Uah`zwH@%(_Pc zG6KMb7Y&6iG0TnIF0#D8XH4vayi2#k$deRLSs{pE=&b(^!LboWw9-9fRmE`v?4P}e zlF=u_3o#OC?x(CAjws(JT*j)yGNCu>=(1f3aWne%5~~i@!9J>knlQWpv> V2A)j_3HgHGLqKwkRx148e*w-@ZLR