From 2e6c1b4ff232614efbdbdcb66cabc4e33d066eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20H=C3=B6ppner?= <jonas.hoeppner@garz-fricke.com> Date: Wed, 8 Jun 2022 12:28:15 +0200 Subject: [PATCH] Build jobs: Use parent-child jobs to generate needed build jobs * Move all build, deploy and test stubs to the manifest-build.yml * Create a new job to generate and trigger the build jobs dynamically * Add the base jinja2 file for the build jobs. * Add initial docs for the manifest pipeline * Remove unused files --- README.md | 13 +- build-jobs.jinja2 | 162 ++++++++++++ common.yml | 4 + docs/manifest-parent-child.png | Bin 0 -> 48846 bytes docs/manifest-pipeline.md | 63 +++++ gitlab-ci-integration.jinja2 | 56 ---- manifest-build.yml | 173 +++++++++++++ manifest.yml | 449 +++------------------------------ 8 files changed, 444 insertions(+), 476 deletions(-) create mode 100644 build-jobs.jinja2 create mode 100644 docs/manifest-parent-child.png create mode 100644 docs/manifest-pipeline.md delete mode 100644 gitlab-ci-integration.jinja2 diff --git a/README.md b/README.md index 82bcb5b..158955d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ <!-----------------------------------------------------------------------------> -# gitlab-ci +# gitlab-ci Repository <!-----------------------------------------------------------------------------> This repository contains **GitLab CI scripts** for Yocto infrastructure tasks, @@ -53,3 +53,14 @@ repository to all repositories that are using it. â–¶ [gitlab-ci Deployment][7] [7]: docs/gitlab-ci-deployment.md + +<!-----------------------------------------------------------------------------> +# Manifest pipeline +<!-----------------------------------------------------------------------------> + +See this chapter for the pipeline runnning in the manifest repository to build +the images. + +â–¶ [manifest Pipeline][8] + +[8]: docs/manifest-pipeline.md diff --git a/build-jobs.jinja2 b/build-jobs.jinja2 new file mode 100644 index 0000000..3aa26b4 --- /dev/null +++ b/build-jobs.jinja2 @@ -0,0 +1,162 @@ +--- +#====================================================== +# Create build, test and deploy jobs for all machines +#====================================================== + +# As the trigger job is not executed in a environment +# with checked out repository, we need to get the includes +# directly from gitlab +include: + - project: '{{ ci_project_root_namespace }}/yocto/infrastructure/gitlab-ci' + ref: {{ gitlab_ci_current_rev }} + file: 'common.yml' + - project: '{{ ci_project_root_namespace }}/yocto/infrastructure/gitlab-ci' + ref: {{ gitlab_ci_current_rev }} + file: 'manifest-build.yml' + - project: '{{ ci_project_root_namespace }}/yocto/infrastructure/gitlab-ci' + ref: {{ gitlab_ci_current_rev }} + file: 'manifest-package.yml' + +workflow: + rules: + # This rule is needed, as otherwise the workflow:rules from + # the parent job seem to be used and prevent the pipeline generation + - if: $CI_PIPELINE_SOURCE == "parent_pipeline" + +stages: + - infrastructure + - build + - test + - deploy + - uploadftp + +# -------------------------------------------------------------------------------------- +# Stage: infrastructure +# -------------------------------------------------------------------------------------- + +changelog: + extends: .infrastructure + script: .gitlab-ci/scripts/changelog_generator.py + --token=${GITBOT_TOKEN} + --branch {{ master_branch_manifest }} + > changelog.md + artifacts: + expire_in: 4 weeks + paths: + - "changelog.md" + +# -------------------------------------------------------------------------------------- +# Generated build jobs +# -------------------------------------------------------------------------------------- + +{% if distro is not defined %} +{% set distro = "guf-wayland" %} +{% endif %} +{% if distro_fng is not defined %} +{% set distro_fng = "guf-fngsystem" %} +{% endif %} + +{% if optional_arguments is defined %} + +{% for machine in optional_arguments %} + +{% if yocto_image %} + +# Build jobs for the normal yocto image +build-{{ machine }}: + extends: .buildimage + stage: build + variables: + CI_PARAM_MACHINE: {{ machine }} + CI_PARAM_DISTRO: {{ distro }} + CI_PARAM_IMAGE: {{ yocto_image }} + +# Build jobs for the sdk +buildsdk-{{ machine }}: + extends: .buildsdk + stage: build + variables: + CI_PARAM_MACHINE: {{ machine }} + CI_PARAM_DISTRO: {{ distro }} + CI_PARAM_IMAGE: {{ yocto_image }} + +# Deploy jobs for the yocto image +deployimage-{{ machine }}: + extends: .deployimage + stage: deploy + needs: [build-{{ machine }}, changelog] + +# Upload ftp jobs for the yocto image +uploadftp-{{ machine }}: + extends: + - .uploadftp + - .uploadsdkftp + stage: uploadftp + needs: [build-{{ machine }}, buildsdk-{{ machine }}, changelog] + +# Run platform tests for this machine which the yocto image +# This is a little hacky as we need to match the machine name to +# the available platforms +{% if machine == 'imx6guf' %} +{% set platforms = "santaro santoka santino santino-lt" %} +{% elif machine == 'imx6ullguf' %} +{% set platforms = "nallino" %} +{% elif machine == 'imx8mguf' %} +{% set platforms = "tanaro" %} +{% else %} +{% set platforms = '' %} +{% endif %} + +{% if platforms %} +# Run smoketests for this machine which the yocto image +smoketest:{{ machine }}: + extends: .test + stage: test + needs: + - job: build-{{ machine }} + variables: + CI_PARAM_MACHINE: {{ machine }} + CI_PARAM_PLATFORMS: {{ machine }} + CI_PARAM_TEST_SUITE: boot.jinja2 + CI_PARAM_EXTRA: --all-devices + +platformtest:{{ machine }}: + extends: .test + stage: test + needs: + - job: build-{{ machine }} + variables: + CI_PARAM_MACHINE: {{ machine }} + CI_PARAM_PLATFORMS: {{ platforms }} +{% endif %} + +{% endif %} # if yocto_image is defined + +{% if fngsystem_image %} + +# Build jobs for the fng system image +build-{{ machine }}-fngsystem: + extends: .buildfng + stage: build + variables: + CI_PARAM_MACHINE: {{ machine }} + CI_PARAM_DISTRO: {{ distro_fng }} + CI_PARAM_IMAGE: {{ fngsystem_image }} + +# Deploy jobs for the fngsystem image +deployimage-{{ machine }}-fngsystem: + extends: .deployimage + stage: deploy + needs: [build-{{ machine }}-fngsystem, changelog] + +# Upload ftp jobs for the fngsystem image +uploadftp-{{ machine }}-fngsystem: + extends: .uploadftp + stage: uploadftp + needs: [build-{{ machine }}-fngsystem, changelog] + +{% endif %} # if fngsystem_image is defined + +{% endfor %} +{% endif %} + diff --git a/common.yml b/common.yml index ea0ccf6..186a453 100644 --- a/common.yml +++ b/common.yml @@ -45,6 +45,10 @@ variables: yamllint: extends: .infrastructure rules: + # Only run this job in the 'parent' pipeline in the manifest, not again in i + # the child pipeline. + - if: $CI_PIPELINE_SOURCE == "parent_pipeline" + when: never - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" script: - yamllint -c .gitlab-ci/.yamllint.yml .*.yml diff --git a/docs/manifest-parent-child.png b/docs/manifest-parent-child.png new file mode 100644 index 0000000000000000000000000000000000000000..9c3001def9c0e735a0b46091febe213631cbd4fa GIT binary patch literal 48846 zcmeFZWl)yu8wdCz0tyH!9fE>_B7$^>Qc5Z<9RkwbElNm>l#~jHbV;{#3)0<4ch_Fe zIp@DK`(bBxW@o=GXPg5s@bWx&T-UGeC*Xyw#5HVkY!nK0?fElNc@*lh4GM+Ec?A=B zrM!p*zIbmeBJ$$7h{$a#8%slDGXoUrez<$Mz_WT`%0_L4qHo!F4%e;yUnDU4f8aJD z`tagTA9glxjK=XDcH?LA8k87=Z+)l(m9R*RG;e8OJlRBV=xKf4BPMyOE&t}mN}aXP z#JKBN75Y1qaAW0B(l1NJu|drZc7|fOmEX|s*y&#pU@Z)K^<47H{9(CYXs+YS#Qx*4 zB-#|iN0^7AGh~J_oLjtGec#QkCg|}B-)7xRA_)C#_hd#Q=OI;%byo%BW=CGEWY-P9 zfJQfhhcX@5-^KZ#Q@-R#*na=BnPKr!ms)<u^1&Q4uHoMNy_`RkqLetQ?=IiKZW|K5 z!TIgya*FD+UXQHzp0#^YbMh@kXyPHxpT0bCIGgg^tWbZ*#j<`6LtpqLaMleM-COgE zvUU81esg*P>fC5b((+JBN#{6XS5hR960K^qw$WZhVc)C$)|ZRcFqz@VQ}*{7cuqpe zmTf5a65+v&L3MZPG<@L?<&tA4EWg@ki3Njdl@*0$C7#`VCnspk1vWuZGFYlGFPM5# z5~8RJ<i9UfX%X<sRjX&OY*8q@2IL=F<U>3PcoEC)xr`Xr0_HUwTC|^}gNpDHnVp!b zortBmxq*cpO2o!M*UsSeZAW9fH@798%e+wW#v?(YZlj)yK2dZUSsi!Q=vO*#-Xb}v zesH<v+m#u~8Sx)w943Ju)uI%PM`q^akJu<mdhV(>NSpT?54L8Ry;R7IwJXSaY)@z_ z_EPlvofrFOmuiIkDekM(Mb4kO@w@TQO>8)HpC#JXOm-i{ce5m8Ha0eL)}q(02|L!3 z<ca?8BL@>b?DFcRYBa%u;$kLV$2*0#+V`25sPIpze?Kv}PxJ4GjV9$~t^DF*kF@2$ zCSh4?Yil+gyvIrg_x}67JToIkVo7naAWpxZ)B}Io|GiwJ*kqFUR>)=UlqG)IJTln- z-;ZZiyIiKGD~=uK&&(<*<{NJO_mQ59cS*A|Jtjf&3FUt;g&$|4Z+h_%DFg-n@0ZUU zDtLZt&fosuAK9?yddS4Y^!0dE>A#m~<S$4&US5~@?<Q03<gu%e{rBts?6}x-|L5n| z|G)cOLqzD}lr32z^t<I`^_at`x!FYJtM@eW-KV>M<Z#K^{Rg#NuX!CFI{o_fi<JFM zSgU=p#ki!ZDru<T@ek}5qB#swMBZ?r&(^ArmowdVdnEd`M)UP0vIib9Gt;xOe$2{Z zJUu(JwzIp-&3%}0Yo#lJkH_usv3^rfnc@6Szlyf5rDb=mH@ba63kR3;_G^drv8!J1 z-(%$D<XpzUV6mBdcD%Quva&`<NEj9oA!2Cw9a~9s`4)x^GHlCJA$;q%IXR;=D;%c( z{%twjnl-Jmkd?)I_39O>^5Xo2n~zVsUthD_?txKvVwItHJeyJ1bs{3Mi}N$0mhhFf z=4LDs5|WP*5l4H2+Qa$!SeeS%-(=!Ai_|=Se|fUIHcCQ45vR8Cr=vp}gPCUVov(5L z+-%>II8O7@m7EIHo8f|c2jh;^s6wOeh3|0|dK(i}{QE=tV{SX0WA=lZrzevan71E2 z3VxvQowS6_YD$>OX$lQxQL)BJ<#DKc^X5%bHbYzi*Zq`~ly`sszM=9wwYI3*Q$F5b zYmZ^kKiq1j4j$!pKW6`vCTBEN>kU^F{W4iR->{S1#@5#PcquI)FmQHtxbWTk_cw@% z#XUR(wcWNbbaiz_B_wvb_%<Hv)S{x8wY%zku&(0Z=(mL3X<BP;Xt+*HY<OCUa&~sE zJl$@`C1ZUzQRQkosOgBj^UTal48JogrjK`L92WsGagz_e;Fa3GbOq!c#>?%S)}#~p zWApMJS061<pdy+vuHU-VS!zA|_fHzW<AgJPAPF-a7ncfsa?EZEZD^ieBQ~e`$h+KJ z=K1;ghNh;0CAU@hNtg-tve0+$E;ofz%fYZ6t!Q7gE&WMT+N80O`5_Sk<J>|ducg)1 z5J0fCwN=;M9jf0Pvb9>+-J7mJ-`3u~wX-t|3kL=3U}}EeK!Xd`0St3ke0)$<m4LFc zG9d{G0X4PUV2&mW7njk_LT5)jPXveQz|_i$l%gVGPfyRgckiZVXX`C%&cwB}s4y@v zV&YWza|`qHrw7z6vr9J%Pj`APTR+~rd-pDCYHm((rJLJyfU($eG9)5`;1;jlZ9zdQ zQ&Uq`Hn#kd5-bK65xbRvYnGN9ywTHT&Gu8ZXy0WMKETD)`(C5HbH`gw=<L((t{pL> z>X!&vCRJ*=1YR-tyQplnqVjK}o(r)?+;)GjcXf5Cs;g7%EcyFunE$);HJ;q!bC}C6 znYc7H;kq$D*BU{|Yv=Ecj>T%ftXO@vul|MRwme6kyuAF|xHt-_D8{<UNop^Tv*VsL zIqHtiP8L$!xw*MK_Y(&^N^UQh2{JM=6kKcY)@-xBv2j41PHkJ;2MKETPuc1vGgDKw z@jSL&d|eF<qTl6`y4Ff2L$b58^GklcrxfytUmGof-)XHm-(z-jb9+pR`zbnF-@u^p z%M+iW8c!kkcCK|&k@dPYte((<0@n4K3y<~ESv;6BG9eFs^<uNHd3o2>)zuU1Y!Z)l z7TG+{-B56mvFye-6L{^*^+ttUcJKS)-TKwr`!VvN$_&g9-$o_!FZmZqc&4mKCbIW) zzHDw<A@|0`m1fW$g({-L+?|V%>n*o8)%RLl$*nQm{oAv<^v6%D$|c|ZWZz`8VlmMb zrJApY0aZIot*C8?U{SB!VXdttoYvaPs`l5fZ^|ohgOpxgUMRRTuMb*+u!>Z&PP+th zN=vy>6CNk#zWCH#{x@i!$;n~e=HYooAK!QX_HD2A@rv1v4Y^mZ$dcUm$>`-0EA>X@ zBqcB1e*E~iD#@?<`v1$KR<w_iH}_$P%%BqzggXrn4_8%HeQZ9$K2l`bTwu^XRAd@$ z9qaFZW#p%Ez3WC*GrrJiE!>c-o*oU<nVdh>(mY%!B{emd#<o^PtCg`?24-fgsjq%i z-{3y`Cw6vs`>xV+kV9n=@x#N=S?Gv8J*c@b*jw(Wvz_SUSd^c4epM7Q$a$NA#-@z0 z1!-dGej!u>*upUCq&zlvQNzQ-i{oy^rh_43fy7&92a|02O}O8ZlQYK^i3tgH9+PHV zo6QLD@j*w$#>O_?kz!$C>5qa9i4Hp=5thyA=_xFXctLk^At9kzL0cOelQ9PqlZ-7} zN<N1y<@xJ`graV4{AFcjyBm{}hc4pczSb2q-#<l0zI^e*s<EqCvbwq&1wR|~^Cvq$ zKmSmbYYDc7XwKFD>i%serjR1j!AnGi18&=`^rw5do>em^>6B6Sb1gTJde<63&jY=q z$bib_@14(FmLWAYLID8*sGp{TcqnFOX2wU49^AjL(-Fg>s-{-(riUitWCw~&XJ>Fw z5H3=MD=RC9DxGbM3`R;U<)GYi!%RW_xd*eIl5!VXxYOxYbFg<JY|PES$)S4s`t@;^ z)z8yp6ArsQ&+B0?HEh&ebe*4_JYZtVQQ`@r68H=+Bz6m)1VK9;8z1L!-o6_W5>mO< zM8SI}ReYoRgvoRu>yCiHI5(kXtrr?9+Fno@8xN0;n>&V9BIL1Q2Pt$?Xr6i4S}+px z|IV8abgO*ZMcFUkBsxCclgerH;B{C<8ex7>(fn+v(D$D|KmGXe!=xQ{gHHs#T!Hnh zcnGyn*HoQPEQ>zoi=Gvo<J~1ESJ#M`7=Ne(O-)U6=P)|XTa6^ff4*PK&(CjYY-E8w zs`m4Zu0~TwN6?_QXTlv3UmYW(W@sw_v%adASfIx2{>UILue7xEIthtiaxyK-anhZO zRy+va(>KZEIA9=KT_x_r*;5$N?(O;ZrHLv&EPSfDij8VodU`*oR!gr5BcK-}_~8Bf z_fVYkU}7xFm%g_PQfIoXmo5J7ODBM(Ik&jD19kAhQL(=UfgwP~c?L{m5yMCLv7Ep^ z&;ThB<X8S(F8}}M|8K?t0eBkbSFc`WxExNG0;N`FzYsuEL{gI6^XFGnQ&XEfp|SI_ zq{w!3bmRdnI4>+NZtCj7gU(14vi#kjeT!4YoAO2(-P^Zsb5_o0XJ&FvSp3;BVCBfH zvr*t;0+eZOZ?Es@z{SGCicd($&&#Xr?Y)VEgVWL3e^qVydsY^%Pn`}fHz6_c$HYWg zXJ?-M{e5m89$n*fDd&Ef8^#~ZbJRSM>6fbf+uqS}S4b$yu=Dfu^74ns$VhDQoGZ4r zJ0@~(Z{50O?dX^WSgW#<AG&2;Nl9~mzf#>5<URDvb1v~9*xde8LV}E;AszIu=0ATF zFlYvYA|r_akd~I0e~gWNE-!x*z5r;MX{E>|mJ;x@40{s6{e4f=)W{bW7A|9A&MYry zTnb-l>hF)NtrdnY^;}L)Wn6KbFr2P;fguc`9`aJHt*vkm(+dmVe}%c!cXnQrkdTl~ z63i}7FMmKI^QE)@Hv@7@YR_b38r$1(C@3h1d^K2>mX=-{8h(t6GnMYbAvz+1y$a~M zp}(KV(eVJsqPey8>cfW*<rNg-#=>Zj`!f08eUXI6$7fN9mFeMPqCbEB{O-Mb(^FGk zetuZ%>+3@!BYLK$I4{=dXrY4F`{B>7tOVxf=C;Nvn3<cype;fxg({J0@xh<Hmvb-+ zws~bW@gdaNSEW{W{P3wUbq+VD`L`MfcnQSFV*uC52r>1FLha~*mL|Rz+uPe~Wn=TJ zwe`7no<{MfPlNz7tza^gGL@U+`~x2_GR^_gOG!)nlcQOIBlxJRwe=1c*TFZrPfA>3 zqUIL$X12K|q46r(?vV)h7%}B@SpBhgY+1R5$>+GvPDfP!nM)Two7<eO4<ch*_)K)Z zH<X4<i<W}}r-Oq-w0*J@>%++0P|?B%oS(D4Y3!#`Vcl*h<Y3|q!8IO@;Ct&jv+<40 zfxH5mJu55gm21};dwTL^S4KugdUG`SV3iJ+SW-j7qst9Wh>wQ`_u9yaYh*YpM|8YH zPN*(jVCDHlRmjY#biqx1l+_ka<H$rLv8Lbb9|O|;^=!NC4?jAyRm|6w*1~Of|Gtc3 z(rklUwX(B&eR{Yx2F0>S3n<G5J@mHsI3%n(wO*NO*AFH=g@C)vk6PAL8PX5HEw$`@ zq2i&DS^1WpzuWTQ;X~R74+3gyYo*jKUMn-;l(;u6PgZB{yZ9TKqV$EEoiwdxZyWA9 z3!^27FT>CPkGg*Ird~muhdCK8=Kk8KUqZsIwUMF<9rxXXgXWHote27V^8=lyy9AV~ z7mQbha)0cX2WsE<V)>$wZm?l(N69INcI!q_+1~fgs%4Q(PRof7;2%pv`Lxt-n`kJ6 ze&CQW-396ge5TlZ)HgWz8o-cwpfd38L1ng!+Z&!26(hyPX2ZV(4#q?Ri66yqSyI_9 zblibEr}jJzpPPG)U@f?~=HWu4t<6oHp*-Cn3NAb^ph1OpOY#mI6EfD;EE5wGW9|pz zW7f^LM8(Coq1!2s4nmiCE+b>m_v2;IExst(1m3OfcIMforB>)OQj^v0$U@uc7HUQi zG9bvdwl;Wk^u)wOfU!GEX-V7j(b_i4eGfD=G_K&|FQ%s@vX*r-S0BDb+Mc>)RV1KD zJg<WZ*U*v)mp}le5j?gF*Qu#3w@Ysl5WE7a>AJsK2XGpg?oI=N9BJrFQSbQjlO<KE z=06_-o-^EL%D&=t8=vB-``VS=yzh=*e5zlEi<7qSxb8D@a&ktq2XB3+t$FNRf3x7j z_LVKO&UaMxSGUY${EhY~y4};8hoW8LJ=ZmwtNUh4hqyNl8x(M_uBS$%hxZ4@$5WQu zE!l{bR2X$r#mC1>pH~|g8p<mwiWUN|Q*zdl9hZg`ny?`t`uqtUlgHPeWb7C!7cVr< zL^7ktTS-~vnyhv!R9Yp2>e{*@sY2a^19R%_p9cQutXel;x0i7^J>BV^U0sz1Kr~e0 z$V}~Vc<0HJCu1HbYuw!2z>q|Ndsn&a{Td&?1w{x2s3?}z02>P3(C8>|g!h0LD;(Co z0gx&!E6cZEQI2|~?i(FVQZnv9@$%(MAgu&9Z@vu;#jiQrrvP>et5wHBiv_0w77+}$ zsaTz2zz9saW0qFc=Z_z6zV-1jJv&m)(P)JtllSvy3aqr0)YO+y+cVt<n#!6Z<Ko(( ztQ-M^En6!dg&&y%B)#yrC)o|~+tBcEx^iIOyu|J7nCSC}w)~%Zlx7`Q?MfEbnV3)w zcZoNT5~a64w81<X9_z@x<<C-jLlgY2PUp6e(8Wi?Z>ndbj?xpQm%U=$#o3a((dnYE zZQ<T+U<*63q!jHdR$?66zmY8D8N%f!*m%Z;*GtlK1&DrFc(`?=<$cuCr%!{7ub8xT zPAxA>0vZN+2#5gtQMvO>8quoD#T^tcZeU7%o-<u^Htzb*a%W1cK{1=nOrxXu;2U<H zhv;hK{Ic}L{v%^6BMVxC!XZUP97%55SD`soZvMi_(ymDaK45*aR>EexAicjjECREG zs1;n}b`jQ9FnnWUW2yzO1M<@XDk}IU-FB`)_xcnSHM6qP4ghVq%9RV5nEz*F5jL&w zHHxNpR|!mR9Rb2#jF1yV(^(%YLskb0nMfle$DV&CWe;SZt&@$KKNXIabkZ>>#n+P) z<@OIN95=o@ZcJnh(-i%*IeB$nB;X^AZ#v;pyHR<&b7*t9F0olq^0k>08x^jj!gK)p zB_1B0(z5<4K^08vQ%(L?95(CD0#;0~4U>9cM?7!HAVcPcL>+6d!}v0E8z|^iQ|J{# zL#q4h<5Fg3jL-y8m$9%2$jK$GtR8!KcyMU9sH=e}^Hf?IcY1o7V;#D3Fzh3#<*MG8 zWkZAO&DG8iT?F#?E2+3idUc)dJ}Sps^m~s!w0ADjbjm{`Uqg!Pt5#G7OrwdDi-qL| z3h2*BvANV@R|17-oT-NZPC2aoCj6lcrHA^n8WeJZM|Xj8a}rMgQHTZ6rDV(o2jrmF zN89sF!kD#CAJJ<+5Iux8rqiFH)TG5if>3SfZ*L|lowI38p&P{uxDtB-_ZU7rj$9?O zUAG26jJ63Sj?L}R3gN3z5xqZrHK36%x!pCcsiDf+yZBbX92WB{)?UAgr<$r|XN=mb ztr?C<i%{bX8vJkcYq>6^M*kfxVTJ`X?|E^ORBab-3$S~3>P3le1bv}=?Af?F%8h+H zmKVdC;k^@Pf$r{86rH8&uhuL@cd~1$l9JefD(E825_xQW=i8$TU$@?bg8vj$7&2bF z`^aq`9UW!8D)e1U@=Oe-;JS33fS?{4Nv3&yPtOfUM@N0sUkyNcbMx~YOXaai9&f9t z<uJY+M64_mHl)ujQ%ly6O`_-RRQa{Y34JBdNJ)GyDOs))heNcamgsrz41Gx&a3UhD zLHmT-UZ`7-NzAO(0To9&M_U`&G_+|ZQAZ<~N(@S!n3`&8Z9k3ww6wHLCAzNbg8FAR zS{w|_`**3dsOV+$k)P952NSb?)E-kH71Fb?Y*kW=C}=k|`U(&c624GYHas2Gd90Cd z!)i|x@2W9BPqY+*sCd7>iex?-{Vqe%Zx*iRFZGZU)0%EC(;2%iJt<*k;kJYe7Vp%& zSwM0yPsB-uz9DA2$FsD;T+J$S!}-O<=CC^=L7o>N#b#+%L;)0_HZodlPh_wLsO5Hk zv>2W6Og5z&lyIPB9o#7u#os(M#FSrBv7H2c|3iH>m|4u<=r(*oXEMqF-)b!IH;&$O zuD&>TO?2OXHCvx>Y|`^hEam(6ZRn9)pKX_*RKD}|{fzsJQN1__c&;zrElFTc!R^RQ zU8CR(1N0432pzA(xxL7w{{slGWYj^*2Il6$v9V<L?%lH&Orww*=g$-T`0=eY)USrd z+?{(Hll?-U@ak!JN(Dcnuh1@SwR}*^<}&HKFCIi%r+sleC^c~atyK(G4ZJ(T2CLmq zwug<9Vmtb+^Ia~WWZxtrY6N|R!c72Knn874sZ!Cs+3H+pVI0%KvIpzqGSxL^!>q{8 z?oJdagZ>PXTyB1+W})FVi4aQNnT7xki!{NXWedU6I8stlY<LNup*4N|`gIXQ9-y7^ zV9qT-B6`!mKG17|G>B@_;simk2(MOA{77EmVdAH?;li|$6Ced#iKI#q<VoDtGjC7$ z9V=dJ?WS@vP;3LFwWvNaJU-Zv19^FAtc*=iP!K6*d7G2zmt9nMbV`@*8q_2(ydK71 z;@|XmT13T-@5@#HXZU0Exk63imy$O<Z$UTcJ3Ihc?kYAmqUIbP9_r}p+qRAhf?5C^ zjMqBlWm(?@H}%G-w7<~`&O$?aHkmsW0%PH&EG?dEiojd|MgX86I6Q~a@k~;320%;( zi$6LM{#sKog#?UGKu8GZ(Wjw-0b*bky?_45SfsJ+wjpl}fUlvEdG{@kwMizlp3=kj zA2)Z}Oh+E3*)Ddy^YhcrUrRU%TQnJlf{ib*d!1|2jZMI1S7)@?T*dAr5<hLiW#y6J z`Jq0q{c=iET7aaSTytGr-RrmtgLYz=9rbKY_Wp$sfMzi<F)rf^TK&SZ8XEB|ZE;~? zIvr%Tsbv)v6cl?ue%#k`-&3kSoC!2(=imJ;A|3PCn?&0!9Q0chX&T<n_BJ99zI}VC zDTu5dr1EFapO;MuKBNdB(Q@(zRgr*<>{XQxl<z7%q#PhJ5K;>Zy9HhA+#ObjdPpl{ zIZTNo=w$R@wu%`1K+5>@O$;Z5lIIsXK7TFzU^@WHt~}j(#X>O?TNW$E(AlNN4${?t zWSO<k%?3g#6h1s5oC_VHn+vLHEJC+3%eJUEObE3-&o~I^W$!XF27ySjIeBp&4M2Fk z`oscsK<CXmEFO>3ZsP!aO72?NZDfyiP%zB~AoVrr{(y#tsIub~j<y$P2eyA?xLEWW z{7vMhkSz-f3%~X)29DEgFc%`Uf~&!@FUd}d%cxoYN!_CCJqVpF?#FieUSm3sH+!X+ zS-@_X-LC<W9`6?KYq#>DWC?tLhfmGSvSjZXZ%Rr^N^4#DT<~C@1Vy(``f~B?(PVy9 z)~~T0t=uu?`Qp@R3>)cr8`$f(t_SM|e}8}dX+FCDb`+Xh9pF1YK0a)0Y-y&&wKX8i z-&^BCK7Ra2_liqyO$$qSbLt{<>x@7sdur;~sFnX{(dW<H_zHLF`Kyl?ss|d8qr3() zXP-6J?HZuXHeHp^d1p(#t#OTl%i=Br!-tdgictHNfqc*!aQ350301bIKe3;34%XKv zHyt1#yU;M$npDZoj{Tu>*5k5lxbdDcTO&@hA)St|3X>yandB|QKaB~14PIt&X<&R+ zFqg5~49lgZ<r%10btRJ??I77YuN4huhz+~!{;dNVJ6vi_+Z;-5v^iA=svtTFqzDkd zLrO}x;D({C2XbCgNRz$C&mRv8ArO#GAXC9tgCEMovc9i5TeF0ndYytoN>}#|G`Dt) z12Rg=4w!sL5EA`ELO_P=8}j+9M|ta(^GbF}>E3{PYe&Z%wC!oYqPSH2svPPm#389f z(@SR0b#D2IJvzCQ@M-l!qWu%90q&s~+tpCxHq&jGRcpkh@i=pV<<Jc>y%T_`SUyKY zI;<NQC?5HJ2~>pj@)f3mtXK8R{h80DrC-mtMK&F@x3xJz%Run>%0PCq=f!zPqQGbj zZB_;hCyVZ{%e;>3@QSMw2!Gxm?py;FGd=D&IS)XBo|!q+^K_OPm8D)10{T88zHLDl z+=0eKKuY@TWPj~wQRw1oEl?gHY~5m(&qT@J0^#TF=FDGuCdND&#*3H!`KK;RAy<t| zg9KX_&Vt=G?vLWNKoCb4B2~0>VbuQ-5N*2!0KcOVIqwbRXtv*S9D4%Q%K32GFB2n( zjg>V<z?Bn$q|nyq>aeKiK)P=_kO(GkgfdiraW;8zgNh1~Hjy#TDEZnP!s4*1icBy} z))6q!G8p$@o>SC7u6B2V<3y_r*LVXsS75t@wRT5*{)|9?zx|mc?#H{j0GOLlg)CQ! z-FVP3alfeKYIVf2`SoY2Ah$gjxbq_~@AvD1c4!Fbo6$9=^WR2~;2XnGFfe?$BWsAh z+sLS?smZIUjoe*XNEaZgBUW&>cBs0zjx{K8b7w2bJCSy>>Q~)fIOWlLB>7-EWuj8q z+DJ=xw-NLzsI+WmLywUq?Y7a*T*IHMG5~xS95}Y~sy98~a1uu+-4AYoJ_OF+7T9d0 zw)UUp_wLBe?@v0-Uej{h5_36Nmx0n2EOJ5Ry2=7FDjld!hvz3B_@C5Vob$mgPQ&tJ zv6!vL7n<82wM1qaH~}I{K$RiocX|v64pc6cb`qC-tlUo!CipiCz^RW6jo(z{1pFmB zna`JFJh<=4D9Fl&w2pCu69BBrdZX$<d1c<|t4<dT@BRDtAM@}oxRjKsaD1)%^gtno z)u7Ee7j9r2;qU!gK+R7|;a}IuH18nnPW9PpaD63eJkBzzl=lL5L3@f7bT4n!&z8p1 z07^#z+RtM$Z&%pBU9MFo`U*U>QR#0SWlr9GXy}M+jeV#j5CSGnMDslGeppgzpBZhg z>fOZIw5k4?pCv@y&L%5EHK!{gt><lRnE81m^NA0`cOs9ua0%5a7Y^{ISr%TBLM_K3 zW_-*vSzsWgR&4gl{49e@90l;5qidbZdPWpsodE>&CjE`2U%q&O8?n7!u>tl|qs-rw z=Mkg=F6=;@05dCSX@wLPvRPPId`6S|EP6XFhbKwa@ca1<w{-X0M!mj`Zk4$+zSXSV zno5za9}5Fb1_fNFf4w)GtWE&2WM*xxvnN?1SdN~JjcvHnnJu?!pB&UIgyHdDobDhl zcM}fiQx&YRhk>i8RywhOT%lJKIEH~kya`JZ@oo?;1u)#--c%eghk@g5_bJHTAS7%s zN^%!hRwf4MGXwZC*CF|6IWrf)mKYR?Bk<D@Cs^Bkuiu$u5>#IPy*>peC#TI^&$B?V z_OzVmi4xtmpTkfDl$G&7`JRKt^!oht2z-{1N9x6!Z4YyQmsn1^SW{`<-?UliAamJY zeWgEmZmV=AP&y@chG9X;$jC@81EXSJXmj{yey)i}#o)z{yEXd+ly1;1I}-S!p=?9P zt~)&fi)QPq>0nN@J3p9guff<t1V<#cKq=^U_;DRe@N`oIG1igd2afhpv(S0ncbPaR z@Q4C}g5Y)pb%8hSF82pgSd@B$zmX3PgUjABV#BsaJ<?z5O$8xiv*zLq9}G%Fz5tH| zya?nspiEBB%*bbQ&gy}-{5~y>Ug-RA7Q?b7)%ZRG1M9FpGbbmpwzjr@9G}G)_f)sy z!$?mR1IvHhBmdywZ0p07Jqz2;y~sd+MeZnN=^q=Zos1+Ahl?1lKXPw1_Xf%^sgp6H z1=T;zq?59>viiZ9vk!Ygf4MJx%y}^Zq0w$&_!AN-ZEO*c9xkqO4-5<p4Gr}T(Kh#C z=ztb4$G`QCr9|1lrUYCw@es=A!onyJMD9ULh1RtMDid`}`ijCu!|J5We$y)uFMg`= ze*{U%1b4=+{Ek;}vi7gWfqY*bSyRwPYyO@C$~uJQa0n>|5T@O)U}I+tC=BU5e(bt$ z24eo^)|T$-P(CHU)9=G-kjTNMY5-Y{i;D{?4L4NYBKO^u!BEi12rMlvG4ZLSpFQ)p zMm8^ar?IfOdw~W++i{zyuY|hF=Cb<+VkRI8BNY(bdkW^1%#ku%dcf~@Ku`Sg<u>R& zu|l4LU{kU#+&hIV0OD4nW8pOn4o2teHv@H-x9my=aX&)91}c-{Y;gTN2(0YG>s<3x zJV!=1L6xnVX`Y!OkyO@`&W^rl*FOIR#`WgzE_ixx(a<qBj~0`(!}X7V5FwOcwkf#2 zy*&`v`QTyRp&nR~POJINaO2ZR@&wF4@H>#eMrBnM(xpJ@V(Ieb1LBRCT;Rt!O}{58 zJ=-4*c6I|PvN4tovG~JSoL9jMw7``f_}+OvJ@D7BrxD)qpbYJNC(M=UrUcO-qEJC| zgHuHz2=r@ti<e}~XK7J#AKGMUl>YpdQII43)7u;KSohLwb0|Fn12%wo#PkHxl<`Pq zFdnTRZ!a_v1q+(b5;Jq5GY;|V;bOR*Hg6-69e8rL85r8QK^K(fi;ZlX3nmh2r&aFM zssH<)aWX$g`AK{^(1u^&^V+WU_pK`?9M<;qgn#=+1I|HIR1`uOp<xgZ5QsqF1V|qV zE~!Z4YH}n=K2VgO(4N$$X2yo?Ky%@?nY#k~uI9Y5wX2&8?;>LvK<}b?HvmXEIXU=& zzXRD6@JoxGmp~#?oXwIQ6p^XQN?FPnDI{hv{FKdmr)_@VqHQdRqrV2$NTJh~-j{FD z-s$h^(a_NP&mF9+xHp~<C?>r;h&4)_&Z$`cRaf^_jn^MQ8mL<!EGJq!%sh{vV=?Z% z3tF#9zaf}eMN6>?+7G~nk#~-m(Up;wN5i-AuxX1)xukX6y^&%#$X}@WBT2K!06q8j z?kpA_<ri>Kt!JCa2<~YuQL%thr26Vr_@_^=x9P5bfgQ%En&$-wBm!UX&<l`wqmwlR z2fh<LBfkb77L3`zKv8b9M;BM$kZsdsV+0}x&IL=gFtjCaxQ0?pX3AVQ(q6Xa9lvfh z{KO{^!!=Dh_AMCJh$RedV|A=70s!iu3k6i*#e22_jwAis+ctD^iEdh2r1bP@JH?J) z?}kT?W_Jqa(gXa1Jc`VITNz=bT(D{Ra7$+=2TyWDoz4$ixu_<2uC=(5EQRjakv7So zvaD$}j)WQ|A`+58WA(_IW{&>%Uq$?S3ytKwcA_#fnD9SmV46uvNws!&=SC%`*eEAu zoS05j^1z(KbZOX}WlNPk`vY}Szd$7fv5Qg~Nw630($Rs0s6Oj5Sn-dE70yr>Q)>H> zaFIANf7Q?KyL+M;t3Ud0zRhl5ex~dnYC4NHU@a+VXqZX!mP1G-Lg9`U1K@8&9hhkh zJOWeXxvcC06hpQy_Cr8JNRkB{8ZgG@hw}9gPfpN@*f!CSuoWFG?d-Q!ZZYz<PCd;E z(US_7OL;ZEI$fZ?&UAj2Q*zDbd=lSg-v7NM1XN~XVqy|$Dl<t73nuWn!J;4GZkN|Y zZ-NPi>_WL3*AAG_ChcJ8-K3@tO-nN>^5mEgKx}c?=>3M5!PTSZ;OOV(?}u~}gy@vj zH^$tx<dh=H6Ib$^sWSI-IiIWT?Cc<PyKKB|LW!g7)1BwRsTLy@CC9Xz1qaxe)(pi4 z2HGdL$IC>B9@;u6p5u`a6Kidkt-=64;yEf?0iH#0{kpKQaILd|50hV=&J-+kr0fD| zC{@e(?XWfy9uxD1(ia0vh|s`596UU{A`>>I5{(pN$N&gzxTW_Mo2x^-L(;>ex>cvE ztUhadX9v_WR-W)?=tx8mBuKAp-ORg_`y)u-*i&%rNKfv&wTra^-JWf8d)c=;LeQ<W zUXpoJsTdx&gQY`WL4yy`KoBqA0Xx*#>OO~fNrG;@?+p-X0RP6o*s)COfI|bCKGL0o z$T_gV4W8{F14zjaT@#_K5O9HLk3G%vh{{)#H#N3?jw%YqWz@xw;H70C{FAw%wKV`S zTp9yOc0d987#3CwwM?e#hxK|V!~_UV4mPkD5`~p-ohwoRjV!IGD72b>3XQ50T7lEq z-eBe<q@{rTX%z3i0aO7@gYqUybfDL1=A*@68NsY}gVquY_7fzJSm}IgfO;N5TR8+1 z2r@p4nYq=hJY)@f<>`+(IL!NXx<SqZ{qnC^i3(W*HMf;c@W$f8!oW~P`nGR!I;M?V zx#HZ1blxf_r79|IDL=l&8!nScY>F88$3nbgJfTxhIOJYwm1Vb?4>lp89$3**CMFDk zuZV<BH_@SgvSSK##q;P>Zrec%B&T<0F#xG=b+RT2JWv0=K1Il$bwz7?IQQ3tLe$Q$ zw^yFZefK5A%-Z0dgPc7rD!0Tzd1)9cvkeFhH3Gj2$(J;BYs7ITL!m-IB?$Ep#X173 z3%Sc(+Iw`KSTgfjSHbS=>IwmUB}U_7Oh<OU0F0cBX!9H-^LRSFAdIC}p<cKtl+Ji- z$;T&{2l6h{Z}jWh{ua&=Mfa07q{nA7zyd0xko_|<{y7fablt>x{e5h3a4?ItQ9s4E zj8-9_*WHjz$(&@zBhx$W;dONXGI9*u3Y<=~rW)u>x`5rLmxVB+q99>-RQZ+Aiv_LV zK`8(B75L{bd)t^jD?1wuJa(R7<6!Uj;;NXcBlD;Yjdph~Ja)1U>wNnu!wU-2{&vHo zuA(LwWP~8kN2<ht(gSYNPmA%-!27lB1OQ7Tsu1xbwFdAZy03AK)e4<&;Y09eYef6S zdAQU{*<#`><R=@T`9tkR)*pE^8T*^-Q27wZ4GWl%o}M1Si-x|uvaPMHmgkxMw{PE& zIH!Su!7lun5rPZY63`_YK-PZ1!0=7G#simHuySIq#oFF}9{L~&?hI5>D}b@&MxyBq zkY5BL+@}3e$?r<%9r9?fC(@(3Q!?Ofd9O*BNZbEOTd~^rV2z}`aDE?E)tq?X0rs46 zkNu&TcII-6rxuGvMX{F4(mjNkz&mViZ|ectZ6eDA`qB#MUo}q$4fNIe$;qUv1ayx* z&rj9N`2fQp8|-)`cW1;jw+FJj3tb8AKy`CR9B)uiv|~}b)dD{Y1bhcg4T(@1B|7^8 zxSj=O@-VmZ7eW?+>_FK;j94W7T4ce706;(+P!pR#cR^g(lA5#ZrWL9iDk>@wB3~gO zhIksCpE<yQiNo!R=j&JoRUx~?Jm;0Qbv|o;K#NjjSeVr~!4TLP{mY~?y&s%clSS9p zXMUx4c+#EAv~q6l<nzz2Dt`5F*u}GZyx)MPx-Y^DM#fAw*6Ee)ya5ts8F>wjF`~6{ zPXR!a5s8Ufi`_4I2>Lq&lVf`pz1w+x-;WB?fHuC4L)HS?__YE`SQv;T2jr*1a8VRe zqL3smN-Q`r2?PyCDw=6=-V6bNq~Kvd$DkB&`2>=Q4Y1urt`0^>om@aEG#kqE1|@{e zxHpCTKtWZt1-^h_YiR4FE<S#!OQgtOwSmrrjbPg8#Yj6+;^%(4J4`F2csZU?J}b1w z!>)`1RIk2@*LatZ^_C(g1eJhGOve(qC;zD1Z{8p|wCsPCZ4j#WsymfJDQ|=`fT833 zcr4h{yc?whCK(u+TQ<dWU}QE;a4F3bMdpL2Ry`EanBuXHJ>$=A1?&NA5e2YH(*pBi z-6aZ_T9`%6)f>a6675)7ZXGqQ$_dDViOD@W#8$ZR7gIe1?zlFo>}O8DU<H`)mTd_B z1*tQhEBOWZ%iu`yK*E(BqFxU!&Ne)u=`{f?hkl_4BnYyLEG$GKP8MbJ#Nxr^1~x+Q zi`<qb;~91MU+S=|nbIsAD2ZFs5tUHzW>QW)GtYBt<ryu!oY02euJ<AJH2tcaZ#hNC zNrZ%I$VbN{5#<&TE;88Z3TZbfDb39I0Fee?4Tss7*txkgSi(7|2mYhUd(pWJfPUYA zzzyz^b|ng^ujpUd%YJtEs5M90;qKg@y3r6rJdRLXfhgsUzHYgEwy$4C9zP8Kz6={z z#V#swB^BV`_V#vQ*S=z8U^Z>tx`&(drbIRWAv!vGg{@DrdcuB%&>pvlicH#%pYIOD zJ5v1QPB0Y=fmQ!%Yr_V+0hkFw1rYx22-`$ycoN11slR!Jh4moUg4eMHt|$vob%+M8 zh{baA^4k3UjYJo<vg6Jm=N!z120iK<$WTqjla6a6jp4Ksh~o{~Y!J0jBC<%vBml@X zhulj3N2GZ6DI&tBtn3IQf|+Z-+}L2_L!l$zO-DD$ncSo)_t~|f^1er^VUeZL*)Pu? zuo2!AoF@2;;hR}!sblWT?g7a}$Z97JE-3dyq82iR{-9w%_K1?($_oOXkkVS}NydWx zT|LE^vzPi0&MR9c@BN)&vXVkn2$lz>9CK4$Q#>Rc^uy@s(!EN5(twrzX3e5ANL`?x zK;m5!%TH{En?&DJQm$XW{$kNy<zoL<1Q!$9k3Wwy+oly!mU!+Tz(`La$hZOO{xlR! zyN!vnZwfrxZO-MUgG|6cr7?3M%qR=vOfFV1+nyaq@1a(gb3lFRfA29)eeR{q75XRO zk$mXr7&ux_MMNm<<1&Rq{59;aafB%>rRh6UN<E~Z%dh25R{G+{0p;Yf%TSE88DlRY zN0cz0;x1D`etuaBm3Ump>93S)fvrq!^kBCTxCVjivgcf%y`M&fz;~n%K_&yXOCh5k zxyW1BrPn5}_h`7d2DxVkA`9SxVP<9M#yVPBzLb_8mLGh`ma}JbKHznz<iZnqLJV<? z%lPL)kj3bxu!w|t>4;#VJnDY<`d*Wc@#51V+J{UrmtTqYEof!_o2OeQceyPgx~x1% zE_FLCD+}@KE}^3{8=pnIN*6sV{SbO!p0n@LLR}Yco5oPX{2H9V5TG9l^zyWJhnu?C zI5<mv>3<A_?s1ah0>q#O#UrBZHp5CXP!B^x!{7`?<`RpAw4|xp<7YQLv|g>*lhk~O ztIldzR){QF6^Md8neS+sO7IHOSygWk90}oUZ_4oR$t)N)sDi>m7B;qutTa=wi-!qM zaN<HlBa~v=&nIWm{@RJ4n2JNdrEd)@t|F{8rrD!qV~YSN+i#4$mVqR#z~Io*(xOYk z77@!OLIKGUe-)+j?Vro(TepuNDGd3D<g5-ZP0b9FJ#<xZE5~hy_K0Bx12j<a-vB|j z*;tK4CfIyr2y*wJy;H1R%hx#BSppabGS=@5rA#&YwMYL&&r(x+fI;KX*+BxIj+r@k z;;y^$I3YxxRH7glXwwgbvDc2hNf@sds(IP8FU2yuLWutZI41!k54J=;Y-Pyl0Re+d zUa(v+paLX#zpwzt$kQiJ(12AO9v^F2#R$U}#>U3LdAI@!kWk?Fp?^YwDhcp+WF+*j z&7pu|&#bTKP>7d(1A7jvg1hweSUz>a$Z-Mav=CaJnVWl;nQ5AxxC<->QPwO<r+w*^ zd^6%`dizE+q}(HEXa*;K%FSNIvC>nF;VZ0p_Qh06LfpX;uQs>YR&{sn!T!DZ>DQ)p zwRkxl0h`S|O_W}h-&hy2WOUlUO1HJ^wgg*<;_WmKWH@Y~Q$ByBvsIEdbR$X1;j8zS zdsU3HpJnzwbFZSai;K<it}&2p_D>=?q!2=U*n3Nek1q}^X}UiI67~wBpKanYGi`39 zmuPt$8GyUa1N?(x+=wqGUhaf=U+LTuOW4DjY=`TvjnNx6PT8dvA!=N`lPyYOGfDOw zK1=sYCvx-o+u=IO{A0ceTV<7{57GxVn$NUae$40F;akmR(vKF>7vK<JISsm8(8$Ds zX9LOdrW9YAy*ltCAX{qs@d@RBIZ+s5`CLG8`A%Ci;zS(}9z3EKtnx3`a`+TkzxDI! zh?DYVo7L>jVfIvX{QYuo&ctFn%lVd=M6NtqK`gJgA6W-Bc-kxZ&X#62giDk|I;#GJ z$~mUIRF!w=IY84orVEfbc4Dp0CGqGqvnnpCZS4A{d_ofbA<Y@cd(-e^(VS?ICP4VO z&&+JO8xZ_YxN$uRR%*D5X>ZDNSRtIBb!6qmS?UVUCH#0Q9xy(jeZ6im(sfQf{65w0 zb79=`%#i-liD7>9#I6Ap<?{z$Qhvr$p?Nyo!na%#4gVTn{{Vx;y{7bMe70ZVrcJ)# z<_!AJlV*!`Er%HR7F}q?^0`>bTPWw}=jVh(L^t4!40y%>vlvLrmOlgrBE}TJ^iQ8Y zO>Jz178Vv_izAcxA}*5>#?Eqhbd(JaD?paQ40i#NVAot-PcV<1-Nv(c3cgTipKjpt zg)HW6CMvrX&?X4b+rHv1Pzqj&?_yY}*Y;TKKT$^~dP2na(AJExGpKz?Emq&uK-NX} zD)E9LiJK5d#k-ka8^Q6|rcr&LHw$lCdoSW=dhkOE<~Q#24`do&&}<_@_-77NU!c0+ zm%_f#H#GExU>TU+ur2g-b-hzl?=392IMCTEC@cHc>411c2wUgn%W#$lX>c0nk=jo< z?C}&M6^YsAbt)l6w5W-=18pcFOv=a;3$;(T(9=Je-!xx<E$M70MtShw_3@Vk9MnAB z0vRJSbMsio>bH%g&PQld^RDP`hQ~0yVjT~+UfPkLL~Q>ZXxn-V6Tb6GRTXkwA2Kr^ z!eRp(fFh0M(W6KIAPF0pn+*2&;t=*CMaKge2Bk>Hz##S4OC%pW@lPq(n<%S`hujQ| z^iRwKp6?zvyT4Z%Jz#p&-1aM|#hxBMTinrH>d=g<jSekIi;xrZV#xgRsb{01H#?QK z@H|EayLP<w11#4MxbsaDZ0|i!*A{dF-j@wyOqLYpIBmbNJX<7qMj^!(zsA_o!bPgh zR^)l3>@lSFG&Beg3E@(1l)3apzYryl_dVV<Thd17-hIl2Y>W#H6};--{f8H{IOSwM z+_6WgV;9Pd<LW%Do~52e=0Eoe>YI9l5|lpTU%2p-Jj7ueaUIp%J&Woz&oALzj4l<L z>~7(*qU-k3W{V44*G9tmqB+ca$Od2*5}F*MXa>{>iXF#L_st}&XE-XRuu{0~%25}F zoc-Iq@ttf|7wY*=6>4nXGWlxmoyAV^)Q)4)tK+P%O?TN++zcQe{s8h=;;7ZfigFGp zUo@Pa`3Kai_UPS~(hZ~i<c<<j#2yKvgHa)Ht(pDjV#pQD9l!i%9oYJCUlS0LHIqbJ zt9lr6QJe0@d#rfDI2t-{#hvN}`^U|bJ9EVKA(gSnMKMzc)pB#CJw4fuEaSq0A@2I$ zwo1N>RUX^?gQV(CEF4=lI(Jfu{IBs^Ph?MRrC($pFat4yx*Yls$#MIa<Osib@giZc z;^UKe2vtk*V%|u1)ifP0NX34NTo=R35K1VW5L+5}<1z!J2|hHg4w}DF0(}KCRIp7+ z(=PrHdeM-m*qiW!;0PQUX+<L=<u5(7FszZg6BRwTlR@W!Ry8)J0Z8^S8(V!{9h#Am z(X7TA^pBXh%!sg-_i+A3_c3WuT{mnGXgd#Jtxrr)0ncT8L?LmUnU>_Crd|5a6+9yv zoU_OU&;chSp_&^HWRXGa5LD6hT`?x_vNGqQ2`+$;pveHicnV$X!Gi~o0iA_heC-c- zhb!dQZqtwq{1z9`*b|n8fHnl#*exe0K@?87L!%P#e;2riJ4tEnd4sx<p6$!IJe@)H z95VM{hk-=5+;P3kmjRs@TsKIO&qDWnip1yXY(>8JplIYtu9^4MEAhPr`2$=sD_h$? zukP3+KnxW*IEtJ*B!!9T{cB)k6!GcPJII@Yz6|qmAI=F!XW8_LfR_Rl214`U2?_4w zp(`1?Es!(*FPQJXLlb>pKp+7|1HenLrq5RzUNbmY2d7|QSV-2)XQ5leJ*B6olTRS$ zm4l<i(fwQc6_a29wuEJEYzp3T(?qxEJP!NxNfZtkK#zy2Ftxr8C+{8=7Z;=YFY$r- z1vVEcSWIs2?lK{xKZ}YQ$Hx;O6Ae^6`z<lttoS`JR*;hqb8{)bu7_u~{hME0aj~=) zL+1g^!EQPr{e&`HDhwcrh6W|bae%4ENlSU6;Zk4RxUs*tmztLs2CNRzSRrs_#L8-B zY8n_97iY5o^Y$$H8#0*c!3KTxL^yL0fY*mu=c|{SfH~dV?|zoa?|Dr$U%<S_jk=SV zZJlrZ`q^mW*o`p)Pm*i+;Z64-;SKE%KzOkC=aGV<qErZw0YWOUoD>Ar8bVL3!&9WV zm;fF*;v(Viu{-^<Q2vlg2*iL&9j(1C4pa`ziSoIv9{?<0m9Eh$U+ilZ4T|uqqm!cZ zMy}UbUuQe!|Kb(Gjt$2WzJoU#78cf?*xRM^I1m2J>gwv7!JLHFdFa8L|0Ld5Kf5)- zd4-6&R8zRV^>S*TX9{qHNdnlV(sjUnaKr@}&uK*(J^B8Z_;6a2m1lWcBQlu^_6Rfg zGTLnjtO5Qp<z1fsaM=b3W*{sdn0I?E$3NlPF_pSkUx_)tb1F7`8afUCqiZO1dGSVj znFUO?#U#GLd>AbzPP|I8EkcAftbW3DuaAJU&e2SoIe#4vR)>AytJYdEXwqV0Vlabn z!Ck)OEv*lk=mknXT@vBJxHtbPs=vmz<rn2@R!3eTYyEiLB`i}mCB`yHZ6jxIMi4m8 z#Z{9<X0!80&dQ|Q<)dS6GPh7fRs$(Y<Me5Mv16*(;Pjy#nQxWrL!#1W=v8#BKvW=` zWKXsCBHgCX$Iq`BW8)sk?z$7!Z~m7Bxc~5Bg<&!k6JMDAV^UygcW&SQ(zTLvzQ#vq zsd1_HKcz)2o21B`2+k&4u8k8(nmMPyT4IdEq`!CXJy1y`u|6zdZITfUd7TtE&PGRD z4@(`;vA(XZb-$3Q2+rK6==$_5d3hU2iZQ@Zuf0PvF|Zd~_OeXjd~8d<U0E{PHr$oY zS>fH&%5NhpK&4PkUb3kmlJ!^*@nhJDl7}@3E>9Pr^FVcg)3t+TT(Xen1usU4b}?}f zeNhkQf>y5|7b5qn95y*F3(tIDoP;#l>181(3>^C&sB-}GQQ$y=QhJY@n-p>BRv<79 z$R8mS!NDppLD1`?`yz63$mMU-*OUh78{ra?k*}8-7#WBQv*AGdRO*>4@8f{;SaT-j z@ja;4iotxyu-<>r0;#)CoIc;DmZ?8vdcN6PNr_;2oftIz*D?2FB&kni!b1V7BQH2j zvVwEn7&S-}?B3_o2r4fvbIBcZQ27!Pmy<dq4R#lI9xy!8o&6iVOxb|8X=m1?eW_xr zE-`o5X4P}7Kc5<C7q4mR6PT*Hv9Wj%K>H5Q!Ie}kv$+Sx`aL-O1HlPM%y`2oVW`>2 zF>;8(=@}Y|Lqr<F9hLhdrl<4Fo-7v7U_PIox<U0ft^5sZYZ26v!ITqiW#s`5iYEK7 z#TlH<VV@PmmA@_>?#JAl+&OMS&l++06kKuhc{fvvl&ND!XRao7OsA_{&q(|3f#H30 zXqfTl$iaMt!5lF!RngCMfZN2yo9^8s7TEfO?cu&6*oONa(aa9tg<9|7Hx4weR2rCT zR$A@h-?OT{eBZAR{esTAIc<o`(q8K~;JQI~Wf0gC_#B(YPTRC_T%DY(;OGt1066+3 zR5PAebnnrlYgkx*534t9HI=E8XJ+((x8xNRWc+b?DU?H#c|R1g{ePB1-!(<kG_Y-6 z3|DNF(sl27P9+K7zN>rrs)BGW+6QbWJnWDUKNPd?hYSq(L@IY%E7sU6Q3_%3QQ9kK zXJ>}+@+gb_9LZ=_Ue<b{ahoB`>$dmht9QasHA43vgx|euw&_x%<z6MZ&F`2P*}Pb7 zqj?Z4hW;y`_Z+3HE$C(bb!Vw9TMVLQNVpO?%bTs@+W?UcXhp%0l&l)jsBm~>V`GzN zG0q#jF<EMjo~e@C1mTq3<5LhVbsIkr9l|MYwRz`fQc^y-xeI=%SZQDIK%U$u)PoQe zB;)%_r6KeVHSzY%07#trKx~b?9az*f{26GLnOlkJ=?|bX6Jo!wo189|RFlt9;pz8% zfcAIE&}UcUfuN8ZmV>fc(8|gL`>1MGZI|{(mWH&db<YOu_TM4(U$Q8lUb$nw{;HU1 zb|&R4pQOa|@Cqdb*KUIQuP-{%C3$bS_ps|XOfjeT@u}0By6?RE$tan66Z+-m-d_JJ z*?ZToC@SG!@<ySiW@at{N`ScCn`{>y)>w$o`E_MrfxQH$138aF)%LLGT3)kSm1+14 zwBB#2n@+*`tGn^_AcnhK6z`CvD@CIbUQ*pvc8W`CWng5)1;Na8lSK)4es(sQh5LmH z9K�gm9QYMUW^BT3}-@uii1p-FFDFSu7{`om^Z@G<@r);lUo4P*!Ur9C^cL!R>%v zyc_kN+`VZ``OvR^`pb_W{vHAsQi;+RJwd_2q?>sq!Zj9nPEiV1P)_%+>#r>NwRAkZ zG#V5zyy29rt>Stb8x?w?<%~(qCFoJQNlK0BSoiLn>Tp_*wQH<H7{e>y+aiYj2OCOf zVtvIavjSZ&H*MD72@C(|&gKQ(p?5oLUFG=TR)MhZRqYFWtuAF%mMv<v5|)x5l(+7O ziCnppaxJ{|H71tL>u>CLsS<Hee-AwAb?0aFHy5`x+*uxP-((U!nI2dVecaa{-PCa> z<^2up_ftDZynZ>QPFpm3dU~~nh1096L2#H66<L=62jnzLt<WGmZ4!ys9~&3v)4eEi zpU`9#-<F&5wSfVL%SDEk+#&Y+ryENZ8S&4nu~9M8LQPZMC+iDW30qP*v~o={GuDb3 zXlc<wQ@qxz?2e^_edS6moN^o2IavU(1ez}Ak{~-tfate9w7bmA_(%$q$0lXqwrnIc z>&+uK7<f?iO*OmVyui%>(OFl}tX|wFv>VKI`OT)&l6O;#hssED(^a0hyh1s#+hKvR zgRK7+eYCI6!luQL-Ey_bQN!ZVvreYkp7%a1oVC{$*RiekUgGU{UHz3Phcy#jacNB2 zIbBU~--UO;y$>s2YSNb{E<j%;(Z@jV-8}W~TaM`W$v8gtnARxaoF88zBw?I8f0%OA z`V76f|KZ+WPTq3aC-DsYD%y4wn!^L|YSmyIgf<{zET8KR)*PR5mMR)5BVPzkYZfti zF7@7nN1hnFUqDD3d?e|(Ql{$jW7A5=EIL7+(Q2{lR&YBUsMLi6Ygce_8(>i`wfFg= z^OS$Q25PczObjW&U_D5CB1R7!tnmVuN2l&B#t=kX0W#hoAn<`mfvhPXgbFgYq_kD4 zmcKS)+5n)!P25_LZsR}+<D*Mu7&c`$f5hRt?((=m{Bc@ERfXDUQMhC(L@GpebZ-0N zlD!276^Tlja1BBKmj29s6~csduo0~x+*L#|3kg4n!UlptiRJC>eRwz<y0tpYR@5C3 z9NhThW%6%$C<Wm7DTuY1aP5wkSk8jY`V`(8LSASnICak^9!eDqZ3wZAYfiUuP{@xu zK_VIr1(L<)&W;Gwy6n-6PB_p07_wHEFJIOH>BMPs%6qvAA~A#a7t1`(cp(6pee4Qn z8(}!Sn~EPYFl<5*q=D8ASLGj)b4Fc0c#;3|KA~!f#VzRTH?Cjzf(MBFxK)$E+zO`O z4LFJhi69+_vq36TrONYQT@$%k_-%L;&UM4?#A{_56RTXLWg0mgPa(61f%;93ma`56 z;U5_IhpYjOA-M^{W8{<itg!%;k}Imcy+g|?a`YP(jkX%YD@f1fRB$gO431NMIIuKF z)V=FaE{^$P7Ef5(E==T=ztvX06ws;T^iB`B!9-`MYvx74$U`?}EyI%MN01|U&KJh^ zYm$gF%20=#?e}CmTCB4e=7t<-uUDXY-my=|3=8ND^Dv;!(s1iBw^OVt`8xXdzG~Sa z%~_jZi>R?o@dg}FxN_yno4ozc3>4>JMk9|ccn4W0a0saZf?XRqhvS&uKn8Rm;>!)k z^2;4JwDe<v9U`YsAa#!k&fa^NoRT5aQvf4Fa45iict!Z`P4D)36B+h0C>{Whlsrwz zXTN7G>u%4rK70187W_tzVx_9(ClMJLeoczG$MKLQ^pSF7z02c?p}mVg*Ab*1TK}9x z@yXjkrE5{A8KN~lMbO$1tp`q0O<8ddK`M+%qtpvr4-`tP(#e~Q%@CO<NT|W7x=R3S zE(2>lJX93lium}kRxck?37AkY;ISXr+8#&uz-Gom)xt4>txm2<9e6Ot=H_NC7%H2s z^hs0jq?-)ITnKa`W()E#j*Qh*$j@E5des|J2Vmy;LC=NfR!{?XX@t;ZD6ExPNEu|z z=5!aE6u2H(Fltv*0x3ltP{WQG?<CLjS4QNYt05<24W5o0M7AMt)&Pfm^PG1KaVfc9 zY;c0T_ZFTD0SRk7H$iIf#%dvoya^B#Qr*PD2K#Lw2Ek)Y926B5k&|GmKi`Bi+$Sa@ z3xFKKb$F)A6G&pgXuP(<e5L=J$O$x05gnZ`O%&}b%GqkElhGOyc}+t@F_(DyACsbX z{oT#t$x%X~pHodr5-UYJBH0PsB$aX_FNj)=E$iQ>w@&8ooId5L7CO07(XE2{I?`bN z%IfifP9P_7mdRr4m9_#K-Y4&_Kb?4k{r=a~b8^;=#LFnVtFg&jXFrAZpGHOF(bx23 zSlbq?C%zL6yOJ0f+LUiq{;s1gd;CUArR&XvqMzzJWXb2lo7d8rhBtkA;SophV5twz zI}2Z7(2=mkrZriTfU7SoFeLG*7JcK&<rfT*q?~4?s*K8k)lJOW)miqegx}&sX<qIT zaA=|{#c~VJ|0YB!iYQg)z|*W?r3u5yl7ZN_nHf~<*R*xvl)|3hu5a%g+5bV>n}Acj zw|}F{OqrS_BvdM?3?Y(CQKHOALXpal5+xEc7NRYcDPv+SLoy^qBt)6Y6d59AC{d=2 z=kwKmp7(vP^S<X?*E!F%|NHsxo^4rc{l3F}f2Ldh`jH)ZHoXGVzZE|<hidBA8ic6C z3||`FwRS$Q;$xaytGm#aZ$~rYc7#`fonP}VT8;}xUI47}fMHU2!W6E}?!tj8iL<A* zwbc^hb!?-Oy1fhO6I@mAA0GTXFu(?$8zP3I+pNBTY=Dzk6B$RP-+mK@5As{;c0S7E z>}(Zl>kW_&o^Z5~&#yzS41$c9z!t)}%!5wC^h5qwhp`Ue0;Ci%fLDMRcC|Rq(wDdu ze9R0{xRe2>g^HIE{~I}(5YF_$eGVdSf)o7yR;QU|UPM4h(6TGZdb~DU&^Eq$%^EiN z>j>yL+EZTOGQ@+PPFGKlE>fFWG@MN^lm#p`k2G^=rsP?h+L*L)fBhq9bHcP9GP7Li zR2TSAxYv5s8?EfI%Jx9k;ozUACn^g=r&ITq6y+<{#rPf8yj(fDQSHLjD%}{<30a=d z$+Sxsn_p}T7HwOH5-|B;+QF{%zs*kxX|{J)kSdVND(Uw5sh?ij)qiwcdHF-`{Ept4 zX<+ogs3~8`T51j1K;$kE+{1^!2-~{f<5m7FVxH=p931=bl}etfUYRHEqGMj?Z-FA1 zEFxqE5v>Kz0)3rgNkG+*kF%gwDR3TGPU*%z;+3%UGTm4bx_3VCb6G%AYAWjzKYECl zUxN>VIi6lAjtdVV@4{MWUT<P^lj9Jo>4K|&q=+xwsHzoWO2a;DBl6qOJkh7l>Rp6n zpulrM3BrcQ)>Z%T&8*?)r<p1V2~mWFg(+gR^#m4xS}N5X7yt9N!aRq#{O=1mJzi=Y zgF&&}i;h9p)RgK{wDI8GZgf(uFyE3Coy+I?3J#$X#@kaz2L?-F5Y7!%aUO=$ce2ya zH+v&|<pcr*`a7P>!C^Ey`{&~K_NQF<t^Hju_bSbN&(WykK6?)LkZCwr=;f&7MxnG2 zM*WJ5tl-j*s9LG#0OU|hA)`vgZXHdYCU}2aU&-l}U%JCTAUQCBMP%9PV&<+6#k3>b zmE2H7U?bY<9pem0;`yTu3=Hj6<GFKEk?eCblSk%iPG;8^&voTg0N+;LeormU@OqWC zh>XlC0s+4Cd}+#$wu1U{W=!vAf5hFpCt>g)PX=Zp!`m}hyBRY{cE^AkLj1ihwZn{- zcmqjWx<%*g?b*4wxS9ex#y759GMeR?#%0}sBrqswQm>m0wPYPxJJVty4syUQW<6zO zV#1ilWRq<|rSMXKLi$u$s|s<KASGk#k<8aHH($WMo<-!CDkRCJ3sZ8;I!8|>`!PCc z2ajl(KaD=8mrY-x!R|b3XF9Uf(`L}@T43l3PK#?dhclbcKmOW{;#*8i%(Cu7Y{;ov z*-~1M{+D7g{}3krLYqC`?$;|<;&5y;7OJeb^`icIG#woByO0_mrfM8NsX*cZ;8sUy zT1d2<V-Nf_nz&sX(6LQVCP_(=%p3S{_>mb_hFS)091Gr0wPda0|9H`X@7LCTjWcHP z19UCStwSu+1*9IS@7tGvQ;+BgAe7I(^uv_I*8wnU&3E9JJ@<)q`@J9lEG0-;fp`(c zoUhq-O{_)mU?+jwCLm)4+8{Lq7!l9fYIq+_u%FC}ucl2-Y&U<w3okA<z>{XqKd5g$ z4-cCsQ4_?tb1h5hA*2)8vV{$?Z~k#{>qynrGI93pyeFC{!zM-}{BWR(4|6HhYeR1M z_I=ewRGyyekU)}Jo=`g!1dl<D-;a#^j4JRIK3KLxyDUW+-d#9=f?xqFZENF$&x-`m zH59pDzKS|9tjd~1MnKbe6JJU}P3Jn8*>a67P#~0j{CL!8T-O7BZBN=B&5OJGVZ?-5 zP^MPo(<dV?G>5$W{8*E(@OFN>n2G<`X;WKZ`mwkD_V1CZ0gla^x4b&`e4*HNoULa= zpQ763=WUM`G6vOOKIk;rQ<IgLNbkeUp}$Xs#==Q$G)^?o)ANQ5GP%NJ6Hs)%b_TJ^ z%4crlVyFgiigMwyZgjiYl9wUC$%50`ponxf(ClUW=-2wwnExO@KR7rzSFj6}2laiM zxdo?Jt#^X?-ou3xRtWpsb$M8T)K_pA^%9vYB-hbJFRDL%5?FpCSw&MSYr68_2c7-c ziy51ah(&A@DQMCkd8YAZi@4fxRfj{eX1)`b$^)XWF?79W_i<AwEj4x5wVB#$CX7wj zJVD$1&sNJyE30cJb*2pR#sUVx9L|-EHKYCS9|YvB8*eU%S(fDFiBd8wf8`s=v1j{m zsc&7~#oWcSb+yGx*5za7*KqF<ArwVu=gyTV7m4EEhtUaw3{Lp}n=ZzKlmqomikLNx zBtcGWs=nC6{d-&9QsRtdJ49@vM0l{n{Dl`xJw*FIKYIm=9y*cRtjM4_65)mT3K2Aa zp@Mth$qyFmwI;O>JUZt(U)(^nBu=`+<Jz;(GWP6U_;Wb?_+erOK#xH&yjz8gJXWrC zO6s^J>^h2Dau#S}6bebHX@xfsvZwlo2Uox8b25A8#Dv59!?Op31BI)X5jup2rsp8b z!?hiNYJ({SUV>ykW2;xbY}h!j$?3n>jZ09G7e|`I^t{l$w|Nu4eN_{v3rF|GS>6f? z3NqbSGvrbDHQg=sG7bR_=f00>BZC`<zbVor57oYY5Fz)J`cA;ZXV>Jy683@c4A29N z>({SWyz)!ks4m4&>~=)NL(>$<cnEBR;DjUJ+?wH;?LozAyJmgfGmjZr_&d_3|FN;5 zE+ks48Uvf$;(n~7qeF(-`hk)Mm5*IJ&9Dcw1}T^*UT^!Fc~`cEeS8Al&h3BxNtC4- zxw#dJ-M2h@HZ7<4BaTIs75J_U`Hy^q5tizZ-gXaMhLMdS&@=Rh-QT~boBG$-kZ*uj z@+2d?;QlyF;&IK^xP>>!8ttOwz1gFC^x9LWKCKR}%~ES%Nb>LQw#+Eyb9iaq)aRYL zO<MXyNmVs(Bvac@yS=si$>T+l>t9G-^nE(`^YV=GwFS4rys}Pt72CH`yd^KMD}1(4 ziM7qmIdRi%?X2axP3#jFs1x!X5*K}koysSSD<q^7-iwiXVq@w94lW8o_;9oHCp#qQ zvSRh+wJ5ku&-_Wuw|8}zW8Qv`Cd;7Plyh}_c`W`dE2yWtot~M%Mmp${ZNd)h2&ZS- zv;;CKUqkt*2gerlA_!+nn|plJBYMadtp#}!6bjU;B`_2@Pqa{T9zWJ~d1u$I#O#wG zGZR<$EeYWjMAAjp6<JikBM^xhT06cINV=D5LJ6*QBab3#u_a_$5Tnp3Z{szT>2@5y zw)x)MCV8{UXstNQLkF9_c*k5WWbDz>&_Bf-;-BqAWw|)E?Gd$l<jSLimKkw%eNK|F z1|nfp?r~lo)4jLl=-8T=<B>!s&bdx0c*o1x<s^#dzP2bD0!GxKfYOKZ;vkVm*asU# zNRkKz#dY5cXbJI!r-P(LbOo#KW>0Y@v~1s~Ijn?7oN%BiINCdOlF=^O>eA^f6- z1T_{y<iTVKu!S0>hc6o$4Z=vm#CM|%HV&sUby8kX?wkN(KN*3NI}d+ab0pJDMOF2B zC*4Zf=nzC5t>%}t_W~gXB$k{H!ce!sYBMv_b4n`PZQPa=y6{cF)anf}lG*X&<dNV+ zNWy{xE;WTqGeLKA<8{RvIP|1xGV24dHgO!Gq)y8#qBb-Ju&+rR^++?M-esF`3k#r^ z9~2M|4%@NSu}NAfTZi|t^dtL4K=R;mD%~#Gwd~a~4M)6%63qKdw{77szM10fWw-Uz zilB0|?LOL~2K-6Mw#IRTai^`U82nVdff9$zWYsCZ$y-azX+}r&9l`_ptKYYro^d|4 z5Xvh_4^*QPkNd)C&pu-AbrI)C<4dI~<1RiHqT=FUZ*S<)+EN#rurbhqK#WllNYzPq z;azsTRKQy~K5wCw+*NMx<z!@JTot}uR-B=y6hC)S9g<q%&ROm~`gTlk#UpA4HQ$a% z-goWZy<SmK0DU@RXr)2WNf_<~u{&`uGvna$MamI`s*Uk_&G1bj5x}?`T>~#x3-LFj zdK`Fhr8ZKU1yvcZlr^i;R5t@OxiluLsjEuF=mt%)2oCtVxV>2)@=Z-lU>#aQQl4PE z_W}HK6^Sxben-6YV^k8P!G_%*j^_$g-Q%5;@JC&RF=`5aDg@N};|GZCIDY60o_aYt zqfsayg@M9e9{yAc5X;iRA;UBU=44h*PVx%GwnJ1MXwj*YjyUvDj;{xTgXKeVQEX@V z-V3-Y3T{|_qgDus&ywJ_>z`%~+bPJ)uX%Jh4y487=J>;xF6B4J>m4|7LxoGtksd7g zxe3wpkI%%?ZD(0(<(wmzHu;?w1>63E>|c1N*GmQboH)|GF`EuHUWdr@V>`k<A#e&g zT|nhLsdlQ&?pPPX>A;-AsODII`ou&18{|v@wgH4dkN<uvG++R#ajEGRO`sY_aRoHw zRe3oR`J=5mS3Kf|oXoKB4QFikpL#ts_OY1yZ30l8kf<ng=(@cXILmN-Nnta7Mtf4= z)OXX=$UAc!r9vZh2V$u#PoAX5Dd+C)p108X+ET~CTizj?4VXBt4@Rj-Z99o?<8)!C zq}KSV3M=l}gH*AaqvN_+IdwKU!pm>$JoM~g2rXidQokf)K=^h`ommy&;`hFK9bP?m zUCOS9OJvKpHRONHG@kZ2nvtGPNCo(8@%VXWQC3#~0FlYud!}B9oiEwk{PT|=A)v?7 zieyi|W)0?*RJG!dk}`uu!VA<P{*;7pz9fDoAZv|N_73gTErA9R6=}3{6L6Q8Ls?F9 zIfgDpI!~7N^ZD)D%iv`&wbCjBc`@jDLMjr{{kv_-7HzeqfSYVzI9gl#Iu`#)+1F`} z#}2Vlo<=Z2B!j`~8yQYP_)8lNx~?r+1|9ZZK&7P!cwQl@T|afy>6rj-chi?isEAD; z4Y=p{$a_iG@iq&r54>5eo1Utiok+j!0`qyRq-u5n*>JkzXOaaw4OR*JB78eFcXFxE z=0BJBOYJ;eKNjmk|4%Su-r0)h?6C~H>x43-j~|d)Zs;&Hgl?`9uEy?f-vZFCb(4R@ zrERDZI&EDR;OF-lDqaE!5d`&HT^y}utjz>**EaxuX~!z8!aKx;Z&YL64*L~Y`L*Dm z%TNysM`)3xEQovsmHXKBfesO`Kdvd^@T$iM)ySK8?lR<$B60oJtxJjK!l`dbrg_m4 zPtOI7uBUDJS^3{RIRku9f}cQ43ZNCE5I@6qw?l^x6#yjd^jz>jMO;=<!E99#TngLu z30vDGSWJQHBIHVdPf@93rTNe|t%v#{do5?Cr+Z+@3cPWn!BlD7&F0piU_xKO_}5Ig z)FVQbjg8Qgt-`&)e2OOSwpHM?e&$J+S-KY=HtJg4h)_cLQ#Lro@Ywpo<Nk~hg`b*w zddtB28_D=54@BI%_fl`861Ej6Dw<y1CnW9>Yz6Q&iC!fRqtB2doWFF*AI{rd0-TKW z-nM)%NQt2$K*7%#)EG__QX37`il003Wo}_GGnmfv;Z|im%SNTr<#HIrONM>e%6>!h zt4LpqPJg|lQ^;hjn_n8!h1??J<JDQw<N?CvQ2_}k62h5aKO;4P!emp<=cL3$f})_B z>cz#=GV{!7ZhE}+$*H9X8DfXC6=6B-kRaRUUPQuTFtQ0OkvR>r)ceK_Hb9ZSI3CEw z1taQf)DDkro5W!6_j%igY>#EsQK3j}QTY75VA`fn(g*<%&7kz>%Zg707u3er0Jd<Q z8WBcgUurEy+MihjEu@Y1UP*HPXS}r-4dh9zF(d#%4tFr*`@*vI8kTV9-`{m1(bUL4 za~#+aX($ouBeHojD_J-&e5X(q0cZ!nn$v9UEw?7L@`LFT$RV!R*XzE1{W>0up{b8_ z7RyDz1bbqQxSA@%sF_=+g1ityjPtPqd+;egiG;iA`0-k!)xW{X{mlhPHrqFqy~DD+ zr^k7!g_-3ddE9Rpmg?#1`!e+28;C7Ms0OEi7Zi9nl}e$;z~V)+Ho;qKl#&{vHAKTz zM8i)2;U(-ed=;JdJwii61LET1Y6EV=)Qb%bitRJ50E*a$)9@f%N5V?KfSRUQL=VUi za3YQOCpO*QPk<ET%w`kFGx)73&!^!NbeM1u`l1sS71btEZNet(aQN)mE$Sk-ODFFi zd%m84<b@%(G@dr-jkoy+WN#gjkmXxDt>eFNr^s2KFHBve6dvL8IN^Ez{0vNJpB!x3 z3e=VxZMz!KivdPCy@l$oE(^Q3Yly)?e@?>AVb4s@9u&rzj>X^uvmwFKve!N{BUkPT zIG#*rlpyR0nfAF-#2^oZ2f?;78uBfb347~kHmRmNh0N?Cn}(WSuX~L>L-BIdtTo^W z)823Q4@h75yJvsLE!dCn9l`a3Vj~Fvwdq?bzBFcNrA4cJ6O}oI9XXeL;a24{XbOJl z?;Hm1Z<eob>8T5J{+X#WLgh@?)nh_`F@-z$g{@+vj$YnhhNuQ+QWF47u@i88mgmrg zuR0reHc9cUau9)jDC}*Y3{{Z&9Kb%fVqG({;O)l?Q>m-TZdCq)1w^VHJAPba{@_F_ zf@9F_zHl9-$7vH%m{oxzEhzIagNB9%ASC?7d^%_B@y|fP3BiJqG1=`(&wb(yGE0N2 z=o!3XpSj&FnTt7HF!h~NNxn$1a@{=VK^~UpmEx}o&Z#(;|6^Q*P8f%#YJ#rJ`lD*k z+$Xo=QqApDetl9Bq-)--+|GJ{O7-YOZ1!|QDOXd>;roIOdIgu-YE4$*aXqL*Z{A$u zGrd++Ku~;bkx;>vmDl+-yIU{rdY8`bJ|V`vq33Cn%H|{0%OvJl+g#Y=!}SgWi}u5| zMsbbRMJyW#rq3$B!_nk2gBY5Jrq{4a-0Ix4`BFS1Vq)0g%+7eIBPb|{o6{e<RCSSM zf{LybZ)FM)Mi^H~D?%9V={5RkD-Xvh`8|F5wBklEwD~8jtr=ybJ5py%e+CQ0J6&Co zpc{zWr1|Vz@O6Ro;;R%~-l;{My;)8)>OeW|YP}UJPtmH($?gi@Tx;_E1Kz=TKNK68 zWGHrFVcr7}%RsRDqm-0aO-*@KHnNGq0;-(?cW$e(p4A>tW8Obwwd35v$TAAAp^cHz zAtuVgtSi^2Y0df@LdkyBwYC1bo3X4Nqch#kgei0CuDN0@!8<-(zB@^X<@7&UJzx(( z>=rEilBdK!kKLXA?%n92d&)0*Ki;F?m8^5=>W1ZPkQA`<m1HTT8Qz3-6Z%7yp^{_D zeOY~!+*?mNc|laaiFVnWgoT?diSRQVGEG}%b_@+4`1ENl9hNQOu{K(Bx@H#3RA($< zyb)%-K?rC0X6_AMRr#tvx464-Ue{(lD_<v~pJsU4M(6maVh{eSN)~n&2gP}ka&vPJ zP$_)kVGI<Y3jnlr+Eg|qXK>$8cOC0rhLBql#Cy5=F}^l5F;MX}<k=m`XgCos)op5M zn0zs^LfIQ%SbD&wznjW~Mu#1x7#N~49pPb{b?lkprRgP%Y_?gK`{mYjCMBKK7Em?4 zoo_x~AMY(df!Lf0tMkmnCe=aLaPB33+^me2IUmoTKktR$jQiRtVg@+HRMQMq#Uey@ z?>;8uk^td#ZL}e3TD%u%6kET{>?3bLVC5TO-<^K`sf+a9mB|fKKVyAWMOD0omQgJG zdKgx4a{ZWlRbPCBm+3s~+48y#4tawKr3~^EjL%?DiaT5?pgM?CR7K==JYx89?w}x| zP`2M&3hW=^(Gge0q9=A=oa9kS19)f=pHcn$u|>(pjv73AgG$FLoY%3b?PQZ$5~Gt> z^*aId&xP5`-@n5KV7j6HUOaM_5jMwwI`=Q;1oAY~bY&>Q$+8aFg9#1v^2(>ig33=e z+<ED{GaULM=vR0CxxWkLH><FYA9?X<+pR`iA$)J>#B%7cm#3~?i`BTh$(Q$#IL~@u zK@dz6-xCA=ecv$I5b_f`Y0qeae0%U{QGRd-m7|G$oS)AeQ05KMO00(}pDvDja0%G^ zC(fPY6bx<Ius&r4d4XI;Lk?xuvrD!m3?>|)mp8(#rfXsnh^Pa^`$9wV*hE|+QX2&l z0OVJ1-UMc{t2zT~3D8edKYDb{9j%Q39u2p61K$JwCm}1F!my9LEjdmj2AsSH4^rLE zyjMQt0)7GTIP?%rTefZ8s<v+*({W+n{^|Epy!aVoroB2kI;A!_Cr+MJWeFf(grg#r zS;%+iox7&v_4fGw@tUNR5hri9;fNj0Egs+N;#ZcelVnR#4cwlQG3ZS%zxYRsf6HL( zLyqO&pToyoPF4+hW%9SP8y7_(|NirPEnT6-U%L3u$r1m3Y5ep4t)=#vT-Gt!|m zk(pbkL$`nb59;BN)5s8u;;U<Hyu<nL`|!;jS2|&EXm6&W7z$QBLqkSpA3Cfm;PFjn zKaeUfA(gm6Sk)PtVtjdqOnZ?mcJt;<!aH#WFks=~YgW+x&s$=aIUw}t#R~wPXlU3$ z;WOY_;@Dk_XBnoN04@JAtPE6vXablt*vO|+Zld^dcbFc-s$_BcyAtVf`eHp7;uF*3 zmEZvG9(Da6Yv=Dn8f$8!3i8Q>g-1s(m5t^gYgvl*Ec3~1UfeBLmEt&=$*XtX=UlV+ zNL3GJxSh#WK7`C1l%p(o;|eprJCi_(2bQ0NY43fh5c%GsHSl)AD&GHt*WQSo7tR28 z6&901yKgQ9FN`AyfV#5;c_8ma^~nC%lIu$iV6J1s5=<206y6q$Kt;6RV7FCRNFgii zKz=FGayAFz$acmykdTveY%VtPvH1cCEzr~J)oH9}6L5Fn37mbmxN36OEH0UQ`!`%y z7x6X}GvWy3q~P#_a0)-og3^!nvN6Vpi-YIQmGQw<=rIRZG2Mf1;K~l3qn8gS8j^#B zjvOpY4LG?D6}_tOblkb?s$3yGTiW_;lVAw#qiSxFcb8#~cPAhqK;B)077nt_EAiKL zbiN?4@f#sI_rWKkq%vJ1gguBJz!n6p|7LH5F9dY1{jbse{2Rgy%*{FfbJux9Zsy=R zc|>Tg+B~l%!|W=Z@~Zl@_X!q^FElmvlmo&Pv~+a*V6lKOZ7n-l-ML!i^QP%QQ4UcJ z_*QbNFZtA{vHjk9DE;uY!&Rmr?HrXfn4m&0kE*~j+r))$jS{(L+UAz6EME?VMB?xI z!=)F;nd+L3ILIH+px>~D&DCk1AE>wGtFNV=)q)VKCDFpU84he%j`J%XLV$lC<>23= z4!SiQL;Y=eTi?~x3^n>2itU4_8<$K27^{r8GA>PO|1J6eBgnaSfHv=e^o@@4Zz1ZI zF*#zrQ}BT)9cAiUrF(bt-s_qAs_bI`6tK!(fy)28FikngNzwQfF$U-YAe`Cbd{<)t z1P7sH>}C1!aZT^pRZ|1pSe&qBK-Y29R-`TIIdA`|{_?~PzBRk@Zd-5Yo|N&4-+VXz zXZngek!pe7xUE+%*%vD{uy|lZEhS4I<HK}_1`(_zUv39_{!%P@JDWoW#(Nswr!Rm# z-hR)nRpEb9m~n9SP$+dxs~Ohsprf4oG0!Tc$9Fv2m)GmBLXMM>>?~7`hx%-h+QyHB z4z;awzu+>&`&T=~r*`C%&#?v85RYXKXgg4dSoYs^@0S%@a`Plx=DD>#_`=>F5K3lx zi_*kIoP2P;7e4@a3dzZ>7P-B@cScc=3ugz+_#wq{pnX8PU&nk4(%_5>zSf|fi#Oh` z<T8I1FJ2guX+NZ5@9eWq0JTY27&rU_PYagjioLoY6=j-r2~C?nByUCSL}p2*_l(b> zzbC^(+&t%zL&}Y5CYNJuEYUdQ(DPIMcfV$+f;5h;C{Huzkk~N&pi@nOq70!U`;B6j z6|!7}`o<1>kMfF1Un~MW%04s-E_V&s80ir{!iOTf67dBRr)vd}<SYm<%U@ZjzECi{ zN*$kdWNOrEbA(pNTZoyH9zTBEFqvnLlyRHhWQ&h1AZUEf#hW^&CnaIy290f<8LO?9 z2b%=G+H}YXs{#o?ULhem(M7E+9DKeg;dh$2|EqiK-;N8xc=1#>T|w5?ne{7|U?aJ3 z+Fu2ldG$}<y@K<f>A`+-^YR8l5D1bB<5)P!`-QM4FVhh>EEx0z-PZIunj4c76r-IV zE*n+NZoS^I(fU@!<cImzAT(J*Ra5R^+3C+WjY?edYwo{nbS%<MqmsxvTAXlS+?PIm zC|0xJ+>-IN`v(x;9f0^1ABRvVaDWiCCC?}i)*?<`iin-K-;3oo+Y+@~H&Q;v+a{4w zXjOi*y2^a4Dlu!@P)EJ^^w$x$jml~Ql`S{QPri$iSxQ7)phi#>cr=(w0#1{Ylgs$& z*q+Y;ij}DAsw1{$gWN>!C>;<a61@2sqf=nd6G2Od=(^bEOVIr1GCM_42NUq!6A9Dl z7gaAV>$|LP{DQ6g`Goz><(vy^`wz&!WFsO6r)%LAF4S{xj2woZAPzYOxy^{YCY&h} z7ifi&q+BIYATaSF%!4yTt_qYYfnJN;Co9k-BfroywPV9W{VgKv*Du4DPlm9d#5XB) zPHWTIgmq5{Tu{2p1O$SSDoq{i$CLF%d~+8J6RL2V(bLmAn=>AMpje7l52kA`*sMMi zzGo7o-7R!)d3{+HFK?lj9&%AjPfaBOB|(5#AS)D6D4g(oY`&nWmY{11oeA(+4On7Q zfb4083N{tA;#F^8>#*}mP>AvbSu=xk_;@EF%p+eX8fcOl2EMJ(K!ze3{&9m$40b=- zuqIO)9UsYj$GhW8FG{ISTmaQF(xAC60XQ%$8k!i!6jYc3wjux^0GZH)1TjiLS;7v} zts9r$DCu*`6OA%^;kpbGQR+*XSUaFy5Hvu2vj)jhrqUOo=!OI=_g2J*l}F{rqXKB@ z>F>JJUQo}uj^FTqnJKn8Ic!y9;deZ7;oJM`5h{!Ya_~pd|4@LfMhzO`;-@N%FP;cW zfOFEL#mZdviAV>*E|Up7=XVJpscFUP?Pj_h`G)8%VLdHtZ|6r+ojM2~p6zC=cw>ab zr-a?T>yMxnOGLeZ!fE<LD??sL_SHX5h)(<rW`!v0u0dhPTqSZ7nn^@5jgU_B!w2%} zBm{><yB4(*2nrE8*#KyvhmF~Ff&N2^P8q~Lj3_oJ#4EhrqBt0v0RR>~CfmJA+!yp1 zD~qBG*%67#v;X*n30EK*pxdR9mg>^TaUxYdST!Snc&L<io>}WbrL(>=aQ+v6#-M?9 z#~!vDLdz6auM5dBbYYA1A>avG5CyxllP=>m%8qY@ICY<jyQ#(E00YcXjueu5+L0YN zM)_iNnpy!*_(RJ>%B0ol5#jqcQ0M!G03C>}V4<K*XQsgMQ(tfuOZawJm=}&*=YjW3 zIG1GZV#En_0}Z@#C?o8~E;vOguGjnzA-(J`AwAecMor)e0g@)3RKA~xXr?E`AmaQS zbHR!Duy9pi;m>!<MY5l+jVUGX4v-pALVbL4%C<BUK#H0WH<3j_M&Sb+F+sp^2y5g8 z@89t1mETgLwF2N5+m6YPbnDiw!zUpT6R07kkcZ0u<-XwVOYBf>XzJ>6gW)6W1p<9_ zevTj1(mD^%{kyom>kzAR9VLs>+?WA*+~8ttTlDZiK+J)n^TruU#DoYUS4NwF^9fJ` zs$3+`one2#tiEQk#y`8w)JjHq{Msud!IOOq2_{XHpKk1JVwS_J+t`0JDl@ib;@ytS zs-dG}04>V#n%N*{5y;1dkqtx?0(yYlY)T%}guuVI-RRbev0r@$$qt4h$tZ7>7(YOl zBi-;i*h{FAvk7$R>+4nbtqc?h?hy)R8PI{^!*sdSW@r$g%`Jo4F|9>1BSZfrGUupH zxng7?5LVUH^d`<5!W5!-@B^x6y5O6uv?xqk^S=`&@gXjnmJ@dzAd@d+jU+St^ckg5 zDg9P!8n!GPgEq^#IPSp%^YvkR9-Mz52Ecvj{G-iioDaPMD(=Cbka*y{!E{4Ld}7GK zUJ=VgbTrKrap`2};_S@2@H;CJY`dU4H#zcIt;wAzjpklvXG`MicD|MC!1|X>&X{qB zZnH_2gI6N{>)x2iNSRwK6tJqa2wJv@cwR{)#wXx0G1Aka5G7%lK+Og5Fn3|32b17p z4b@q%e8`T*ocaWlIf%RuSt|DxT*Q<XW-oria5I(sP0+%VybvtV^B6xu<a_`Vr3+#q z!CeODAt3istUz+o5YsiNf^wj9<fw-l6-8(XCNAN@SE4Jy3^gx&AIOg3KmZq*Zo-#B z{^$>u1dp#f<7p>33Sc{}7n(6M+9HW0c5-@vHTE_yQ#O>8ktrvFBV6v<ky1>!V#=UD z893N{GvdyjGZ}6B4;}IcIzf#AU(Fd%rUJwkz_<PR$0<OG2aQZmL8^tK&cMK+sO593 zbL!=<!J<specig^kBZ-|orDnEHhG`%VJ_S-6fe_z2x_my$<TOLQcCK5;aZ5(p(MFK z=m-TbinhU`kfyW84j((#^mJ(4V+||-Vtam!_fh%<+BH91_>jMjC_cctkS`6xOV<!p zB(AN4eMTJ0X@-2WZ+S?Sx&I=QlPRS6I9w&2`*kVGh|$5(dEtAjB(gneo$XGuQx{yX zTuG}|M-KxNrY~Y_s^Tx9WG4qcMHyIcHgrm`opj@NVx}yP4<R8HFI?$RIv|DjGh|nw z&KUslA!$5Qj1GgS)Nux*CiR6hA1e_-)Qsd9#xEQys%zT1k(w{JaU&D%&xbpz`L$3! z|5yi%!02V3R@3CZBasmhk_^tZz+a&Tkq_sS+_B)8LiMO!SD(J5-*JNjnOpX6eak*L zJ_-reH8(#u@(q5~ZY&DhtcQ;t(U?pKV|Z6jEaFXdwf<ZOlAT^${j(gjIyz74LT=M< zx`<^~P=YpjHZkl0_GmPdjw<uj$B%0$xKr)emza6D+kux3MzVdz&@q7O`Dt!8x~rfl zKqs5WE<%Cgo(?<3(DUBiyCTxk2IH6i%0&!k=nM}r?L{Ch%I$8nCIuJ2adu=x4R{BV z+r^jn>-gzD@Q6?Ei%*Mz^0D>2_{=PCjTe<UDpM(Nh{*GxrYCeJDjI{L?L0vz92|(# z3Ee#MS;<7hDTvgLJi698WJ|jvq`q$Y?$JE;@!B_%JHtM7?qE;+(j{C~AEWZ&ax>e0 zspXB#JVR2>oZl6Fa+~vwb&NVYcW7rhka1MwLoK6-7c6US<;5Oz%a9{e_Fz~bgE*li zA3?i?kC58&i6~w`JTe2a$A*HAaWBY6qql%?N!pGHW?-R+BQv_Jt*sI7!i&2`c1nP# zn{cKO&Vy4>krmPblt>gWOuPZSM)LaLFTi-%n)uD**!Pdmeh{7d^CtmG`-H^9nOL7? zvA3xCbk0Xtu<Y5;u!Br4#YW#dH?{&Eh{g(@lTwjH4@G`Ccx@CFB@nB^dkT=M66|pU zUI4YhEK*HzquZ(o>R%>^FCePs#BD|lxyg6{QPdT-|7Wp7LbDvTPHBjG{Y+r5mg#Dq zpocPBE77*wbsHYBxrLUb?dKh>ho+|+>~1O<7fCsh4)XzX;hY6s)Ex^MF2S#jTiH8a zB{p4`HOe~6CsXWp?1%fn>Nl99OF=7xZAd&WMNf;6PDiq4&yRGgASF$JTpEZTi_d?D zLyuUGpkmOD*|khj@bEU(T5G9Mu*apCb%wa{3S6N`M4wjZFa$aR^3IP?X<#!|5IR*n zGrYTrBNwkuf{~$x_d`7kSECiC9=bhU2T1}E&=XGp0F*GyKt$EXpBq9#tT6oICdM_g z6X`G3FVqRlK!=*7pmNoO6qhh1xX((#aBS=Qg`$i^C4;>qk15?GTh)r0Thi>W=3ueV zty%NtY)BKu%Z+Ex$mIRC%D+!Hv_$Bq5izPH1|Q>KPUR5)4gt8gve)Vz=BeiH^Rx2l z>FL;uMr*qVXB^%rwHR+{;I53w-41DysnrS$t#bYKh0R(jvU#dxC{iBnu4)1|{?s(f z)4{toB^9Ks24{4Q|Naf{clF)Pj6NH1E&MjfF2RaS<wdf~8-19r(0*n7xslvp8yTsG z$Z*@Nv(<)V2p<}cMsr9lc(M9Zrf2XZY#S^P5doLNA%|E}W^BW>w%zGw&-8oqIrw(6 zLLB*iYv9E{zfMu=k1k9j5W5G@$;jOSCPTi-nejOpDXCXzW$d(dAhc7T+aV#k0?}bq z$)@Kib8F#w3YiQE4jzFiqdqq6Hpt`w@uBtP+dEt19dlQggF<<U=yIGKEGRm_kTQ^e zgl#BciCg2QASLKXz%Z7eqmi_J!>#B!|Kfm+B}otlrY3<=xj2Jy_ZrI#Ie@k!Y${=H zL3jEYijn$A^4hE`CE}wzk;+2`NGi1b5A}VR&tzuk(^Crn4=lUqv{ar7&|e7TyGL!A zO*}k2i0lW)#+g{B+3|M*O?wg@EkfQNe5ema^cjv{xl_S0;GJT9+H8CFDDY|LuM(`# zXxXY@F0}u3S!;DZur0Z_OyOXUAj^tf+Xo?D?AzRp(1RFKKWG`A@*W8Hht~{k?<ZVo z6v|aZT?YQORy_t;M`&wig-l1DB2*;^x(`J?YK3uVxWb8jp}F599<>iq@ra6w0y-!m zT>)BKLet@Lz-TX3%;@446ubqsVJ~V0eU21%3c0s%SfT*-MQ?@4;H>zT+&qevB9?=r zCc+^iK8HlL7rT*+KvlCymc3con^wbkJQh(cu>4<uThgq^&B%_wN%|tu2cqH3D0_?y z0Xud+Ivs=YlFi$;WuzWv0QL$wBGLw#Gw!)eZUEZD0Kh~g=$dpvMXqvKV3#qAik`Si z*U?S6ooD#<f%U;scO6~QD;$lJKf5Z)mcq!ZrVuh98ctte2b)lt5swYLgE0y&RGqpf z8^WuEprAlKh2-VN`w>C8iU5hhaoe6cx42=q8U0HV_o+O+qzMdC$(es`hfos*&3r>b zm-W=)j|VqBWO@cP1bO2=*bW~`UDe7fE8!QguzTtLzjDD*w_do#$^P%@;InHLL5Z*Z z-_gOE1QeSI2&I(7BiNE-C1w84s9?c(XguvMHv^s{JDAlwDvP9pF*3APpxcv6_1UoE z;pdjk7Mp{XN;vQ9VA--AROZz?JMP<W^-bSj?{32KekU0ljUAL!!Oi!j=JwsY%+Jis zt$3ae61g@yFX#i4urtnIxIm{X|M)_a*Bd-$g-s%Evs04jryFftXc%p969-jERaKha zWRvShnVG}K|Dy$Xa;jncY{{E9tRR@Q9=`7mUICoVb$hYvZD&sTNl%rp9VQYw9}zGu zk>iwlq4(Xhg{1@_d=;%(Vtq{5a(Y?8*p;|U6IJ#NxcfmixFoxf!XfN#Ds<`~d6>s{ zYwuDtQE*c^|9dl|+^v%AZzFsjA#H|640pEnvEIMN_(OrYzUqtySan#qR^wtQv6MLf z`>PJ=d7+deAX-1AC;|8^YS;g7Jnhl$|2t1>w(@_)u9I-y#<dL@Z!h-j*wyri{d>Km z6gIfQ%9#Iv*R<NRI~ExXQ$7N>^@HE%K-+<skBl6xrf>5XXC@q+2OAFz`5x9W8m|{3 zY$Bj~tY?(^N508|g|zP6bK{-+ri8Eqh77{To=uhbmZ`bFl*s+LN`nq`pYYzj>j=ks zXz|c^A9u<`{BE<ihD%kU`*OL<n#xDbC}^Q!-(q+`a}05!(W{66@!tQ(Wd#UL%O@H2 z?$w>5Ywm?}>+c1yjdM;x+HSB1%@m}Vd<UssK$kJ>!>wF>tjQAZ4wNdmg-4ts!rL0* zYS0CHDg$Dc99ZucnGV_i6Fn{9`DhD>yqzHOh$cKX_IUJzgd1VasVJx*PlSLb*++#e z1LH;7FAs>cA7~AfQ~!b4%W*kls%gB;3YIg|pi{WMP?RzC4m=9eMb@*z|K&9`|D{yu z39>!*?69KS7%R3PiG|s%A$;#GHiSQ-a!5aUdY{@w!#z8-gjiDFz01zePvPGxT=Tt& zb|h^7hC4SFYbn`)MN$-{_Wvuh%MTSAHkCJFci*Rf1wWWe*z~!R*(N$ttz5#%DStW9 z`oEOu*_>29FYd%0xA!yNP`?hq9ZfE-MLJ4>*>-fCWLfu)jt%aWISt;68EmXQ1%hU! zIEzQO``Cp2p<sRU_N@;F10s@cz-tlOStJbi8`ut012o9j1C#;80DuPM29<t34-{ML zbX*v-p{eN-gaqK-+=survR9@maNzH;NJqZ2DAj|hZfE{cJ`@4qb0rT?B3x9sJ<PTf zgPOMJ3Lv<IW0I0e-0H)<7J<VFhGGz0Fhi~a>c>b+2u-@59}|Qc1Io*=wZDX@{g*L| z+8JgLtD4}YE$Rbthl>_Q*MKKfIl?MjSe(nwjGr+oJ&f)WhE5ETsxKuC-W&c<@(eg0 zJ~ZC5^Vok0O}<6yVv*zfFXwso!{T>(@PDRJ@e2F5syy>u{Dg~t%V1nI(k}KZU@6%C z0%L#w_y1=)RU&%G2kH(Z1B$WEf~Emwx&HG(gI?kXOR12Sk$LDt)(m-FhoZx+cRqw} zjnG1wfv4(SY6+$OE8O=oN1g+O2oBzSAdvg`-!Bgz8QLKb)4<z7pdi7FURyMrbLHQc z^37GzS^kEQtJn|PqH4IoOYkf~C~M+bChKm-E@Z^Y0M{xQs_Csq4pVNzRjEI1HXg6< z_l|+>5}E+a>Sk6H49&y?_JU6b?JKaS|E`_C4~g3&FCS}%gRqX*Yivjk2x##rZxeB7 zPFUjV9{t^;aw%$yB&dJAKKAssu<(coKR7GE8eOkd60X7c9By3n5G?*nouw?E4cWQL zcx^TSN?%Gq9E$S<)yfLHK;J8Ld%sYGmQh+M1@d`Lh!p?_Es7N!u&L2=fB*4gpoB2q z$vTN(#P=JVVFRrx_@=75nn>!HF0iIC0F=PVioZZi10u!3CPSxDOjF`{TCYH&0X832 z2X^FQ#kxfQWhImUB~s-Vg#ubN$BCdL24@3`xq6N}VG3_*Yc<gJ;)nqsVCWs)hAI;? zjG(b7ef##{Y3l-fQ2n$!h*iKt-yf|)cxsQl2pmpJzr1i8Uji}IxYnt6h^naD(sEw( z58o24<o(rGm??;@pxb&^zH^lQb>MdI^LdHCxZmd|r=&oDmjpx)XKa=MKV(D5i3W<i z56-RJ?VEUlAeBFqbCm3<<R+pG*zZ838ZhQy9U;U53D1=Z8F6}HJ~E>$7y9dd+h$EZ zo}^HWlpj^UexSBYzT0ADy|BY8RE>H--hf^-x@+ymwnh34HXJaLv&Xl~$dGy1xW1j~ z7teLEzvnuUn*7hK>b!Qf(beTo>6kX|!-w%6m_I@OOK@UPB_TQH5k92<Psdnw{aR_0 z?1Cv-XTi>a_xCany|;asl9GsT4S|^)ZNq3nEKi(BkdfAeWF<M75o&;>aOK5Y;E^!E zX>$Dq?Q8A`-yCrOy$po{0{7LOG9QC1iQGwk4$iI+&RxP8xmiudG{M2OZwMX&%JBK~ z=cPk}FaSeaMn`#kMtPSA%k06dapTH$B~ep8i+Z~<d>;d18#72g8L&MNpM$YCk_Ozb z3^i|qso|)d^%P2E+)BRKtg(OjXTI?aBFq^Py2SK8>${PAM|JsXiXmOB*xKoRCGO5E znVebA?rU>f<bSdJQ&LixPxl%!T`<e|e!+6~3E^W8RA0Hd(A60mAmj4LowC48&*p0+ zyG(c4q^-B<mV&K3L)T~4|1ey-wkXf7y}i&dqv+-((+mY;N4xB{3ypfuC3sfbXJj}V zEH%>1RxlRdeE)IPKgv9+tmhZvt9TDcoX~sRRrh;J@t=#eJ5C><|5h_o{IYfKt)5;+ z#e5{~ex%ykS_oaC)o-?T-UUT5Qm9nH?Bjl*#KYjix^$@;3{~g@tS=mk(DK7!1)o9G z+=%|>m8ofIXN^V4P^t!>_y5>>U0)h-;atn_)HMB)J)7B!9$aM-JYLq_AoFhQXY#Q~ z-A~o89lK`Ni6uv#KmV(w``Pn`zU;IY6!jmU)<KO^?j3`>2hk2C@DmI=oHJT!^}1`G ze^rxhOw<e=^K9qRO5=M$7bQ-%96Z1Jz)0^4u2$&)g<u?zn^!IgTGoMU33kBs(m9{` z6VPZNSwkhMp&R<<ig*&~M2r!5@Ay}&z-Ec|g4*T4^MK9UaZErVmJ|L*c)Gip;FC?{ zOxV~&dG=_sd$uc%g)$cRgn91K2GhKbrZT(p<Nc<Tl3vfwkm0iBuEK$BqaMxV-S5*( z`7j{F&1%1-hf=b8@37{+Jie{|b>}W|vrw3){VdBzKDvHuy!PUE@3jr(+t1$Hk%F3= z;JPG18?qvdzVP;({~g!=F=rF{TW@@<4WgpIj!&{+@_P_W6*+Hr@^QdjhZaTxECaHd zqmFNa=>Y{Ax+p)CMCf_>GFs5&#_aX%v=^#GObToXFqFu?3;_BPD9HFw|6_XbE`On0 zIY%zDU-_e(#2%9}7FWo8Trm3PI@#cgKQH$>eveaA{}E)KrHMTNgd~c+2X~cKlaHYo z69wOC0&v5M9rZQHi{ZsMgm5D+zz-01I+%}Jw)_(!!^eT6Tc`aKb#uk0dxuZPTX50b zdv>1sGjdw8K8r=^8BPbWo4Y>+Z36>w`}S>F2WhnF{o`)M2D>-=snXrvZ=G#54RDxr zYOt5&K<f<&xCSyF5)%_Kjr0~cs+=Kkx{#{_EH)L;%rO3)$h~ZtUO;`!442N??b|(` zuu>$(JUQD}zLp&6=kve)_9X))rhQy-=fh_&c-4Odqs(~v^m2H{Rur)#&Bq)+f2j&j z&C1e5`a6D!u7yP?hy*~(AA5>cQ2?=)w70jL2#>}OXPK^igYP@rZF;-UjwjdXDdN0} zHDABAUz^|-%cW|B@>fU&cihJIIEhBfILi~q2CPz}$J@NOV2O5Zh=_>z41xdsooAN= zjr#Cq7bLSpCkl?6N~MZte*5{8%TM*hrAX)-fU50Sf}NG;UX#H*HF;YGyDEO+j?8(k zB@Pq6-JLnq7PfF$&CR^wqdf&|T!yU1wnVEg^!&}44x4{Ujm_iK%P*LR_bNayN#m&5 zJU9U>jGg>3?dI5)%Z6Uhq3O4)9BPbv=5B1@4O|D)9>q7Dd6#)FD(dE=2X0I7XRSG> zxw?XX+|d@5K6b;Bz~rD5063h$9s&)$1)5+a=LJ9$L9*G&S>fa)g_#xSF2sQ0JjVXz z)6wzzyX0%j$jEy(F%&d3K=JaHy=%BlyCXPa(`Au~l3yC7F?82TMXlueVC$@a<W*a6 zH}V#MsdL62V!``^zn`xwwQkR(K&HjZbHC`w#P*Z$31Cf=k(#5x=S9#>OWV97JSWK; zCVlS5b-I{8Q3;drO<1;o&hSo7V%%{#d`KJ=GVKod1#Fk)m+e`SnryeFw8bi3Sx$jV z+oSFR@u%S8l|`frUt$IN+3!;5^4i)=%~wKTZ#x+k9TI-oX2&O=SLwqyKHQl%SpHdX zrT+_Q_n&sghb}&uie3)b1df*cKi52AUnX-HiG>eZX<ppgwnwtkaLFa2vn3XJz*TT* z@@GJ{JNh-+k$f`ZfB>EM{#@63$D(l_<TcEP#c=_uKnudNLI>;iJi>!|>%L~@B@7aR z4GZZ<Avr?@j`6d0=&xK5yqc{PmLuUJt@P~Ed7onzT?KMECn{*wgYI$Zcw-ngvLa;r zAaQp0_p`2Ey_$@1An&Aj_SZo)L3w%%AK?Q#iDgPAIw8Q{k4#%ECx1HuOD<uAOvEe5 zC|{en7T`oy5XTS<9n%DFf`aXV7p}i0YaJn-DJ6uh0mtfY<Dfh9!La)wJ~-Bv&0dpt zMTc<Mo%mJPY#9Q`oIxHjL5;#YAMpt-ygETq{(1jM&Gx!IMJz``)BSpyJyQgB6rAV9 zKkO_0+1^<rVO;Fj_chm9;pDNLsh?Pb+hGznk2cQ&K>rzmUZv7?iaszA5+NAqE!XF6 zIvs!zaqJM00mL^ond>985?Y2vF&hugp+`seL=CshtlzU|j%(&myzXYCa9EA<@kw1^ z&)5=Goz4f)3$WJhs3_a-2^XKT93Ma5CGC_P@pPL_@73A2a{a|uM7OX0cAuk%eT1VT z`y>D7?Uy81yc_U-TRvHPea+r$iXZ`kkII^6@PLh$ye6UWm)an*F~C6>z7Z4?BM>eL zr|*qTaaWfk`{+I<ed1^!q98C%Bp3xrL()|}*-a3>5EL1F#Cl*%gcC!D`lo$HIKh~< z&E|`^Sphf15E;`~L8t4c8QR>FTpxf9qj2-<C-*NF_N@6PgFzSPf7bO5-j;bY`(>~9 zgP|__@}~86=jWm`Y@SNqIlZPL-(MpMt8pneVrO9I62j=C0`ZL-AL?1W4i09=v*PtE z-W{}Xj!cqA)(uW8Z#?Qm=)SAwo;@G4g*t)o&OllN0M?xZCRtG>_q8rAbkhS@dJv*h z!_WPdRN!8$z_`u}Amn;^LA#NR6MP6g0|OsS6tsl(22`jw$a$38-SADvCmdIIb=`F{ zXyHSzVO9%qLc+BgWb|z(h!xj&WZ(%38l78b$rx0poj!=YJAwI%^#jh37;zGVJ%K~< zQ`meV4|?%M5;ljzOWWv`Lff3)@p9?v?L?^&c=P5fY>-hn8P#Y_ojKRP-~_G2T|qu4 zhJ&4eiM)Pj9J4LqI#}`;+99}n2mnd(LdPqP2n98NcH&}tjDUmQt_2`tfXiRu8<GH4 ziEob>cM7ij76t7c1j3M=UzQ!i9!;PBq@@{(ZJVg5diTy3R|7nmr{15=O|v|NTM&yO zIEOX*d8J#J5!a<3eXqN4(|WFRUyVBH^{~aQx8?H2EEnvFOAoNEl`)K-r-gWeFg5Wo zg#rd^6q8Gta8j1wOU9re$N0j+Hft39^D6?Sk}r224T7D<bWD|tjZN|oY~oElA-h}@ zzdotP(h2PE#PLF-WA8h>Z6M^LoSJT`hQWz(S%`jQZN}=5nFGE|6e&&h3X^)UydZ>- z=vqi<19DJ=wrr{TdI1;`3k<}h3WEY;sy`_dQ)#Yh$0@BvbZZ6vb;8ID4%$L?Mbreu zxDVkOh-)u&BPfVeMQ(Rv91>bjGQ<)&brNtPf_$L|M3~|94ur_tdppQ8BDqV7zu!p{ z&v#S%ZpbzuG9gbCsZ|86$FD4Ea5G5JE_MG|#1fw%(gQD;?DibPeJ6g*Z$q3DRAGqE z*@XtykKBbPvkR)0{DT6Oq!mDSMEHVv%(*)W6EZL$Vs`}$<pngh7j`+<iI1oCjvWia zTU~?th$Lwd-yM-MK?)&r>-do)0SG=NCn+%qqMHSs6o7Ttjd7Z<F>^i;huLS0q_%5` z<HA$mk)C++<O%e5XVTpsi{2+3Efmj3?N9xRrwQVA1*87-%0#k|oJCHg^zn|lk<#RH ziq}nB8IA95RVhNXeLeiV-Td}VN>I0zPJM-YPR-dlcl6#X%=4i~t4HP;lTQowpzDk~ zim(aQe4b+l8fjLD;K{!4-(rRklk6$sWc@Vp=J26$x9FE2aS@8R>0(7JoNKt#SGs3& zdedY%%KlaFwP`J(@B?G`CL35ARH`S(`Wx^$Eot8&i&;V<ZGg%XmpJTiV2AP#hYt7l z`k=L1kN6yj@08)<l^h}|JftKhK$3|GYy1h(4v>CiMsYb}14F<v^Uq8nXgvwn2@;aF zLY77Bc+m7j7d^GT1qP5rOHE}hOz%KfA*7(dhjm|&l~tKS-8`J<IX*sKe`Y719iqUL z0S*W635uc$rBSJ>$B(at9u_AuQC+dGRcP!{da&115S@3{%XtOlK#}>omY@JItbB)d zb2LsB5^&r^7#otSO43vb&#RzNxNp^_Ngrccp6j}8;Z=M(Th8f7Y}&l}%}Ik^+#dCb z{c0CQbdK+t70P%Kvb9`}Z@lWyhor;wl=+#~=M|OdY&~Xw_DEPe<R8LFOLB?=UG0Ig z29bF=qyBPe))23<vsvluw{K5rt5ai-t9{SN%)IroX7^?_tu%QM6mow)zI{v63r*4R zj6bsz6V58J$HbZK#F_Y_f3x5qTej?D3aD4nz3{j##e7pMS}@)zMz~spS7LPQ+1Uk% z5ba-dU4W&!_57|~tz!o-!19qgNbx$*R|;VRnLxgO!*Xnk(kWn+gn2;%T*%}OtmfAs z5RdgKVYUVrVA`jy?`ra(gCv126fbbqRyaU;S{$f1d(3AxakCQNF($V05wH0JkBOrw z*-AP)JCm;`qYV{ZwE<Ko(K}wfsz`|1Zx7r#Pn@{R5COoy-Zl^R_ViK7*h4M-o!!GX zR{;6K(hIK?XWFSCrFL+snqxxqxeKGZOirQ`w_ZgayT>ne=G|EJGwJ(Q4)PJgWv5U6 z+)SG&g%pBJumV@r-QOQrDd_%gir&S=r5qLL2+k^ab$Zq<OldwZv_y@=Od%Q?#P;}@ zh@X>^Q2r4LKuk5^aqFf^?(Z0e<bUs8%brSUXM>l&8Kw`3MJxe=!sDaJ{)KcanwF`| z01|TD_)lk@lRZ^yLQ{?UnCO%-Jv}YTFEr$=5M3d~c#wTKCeZ_e%D|hp1&0gWi+0OA z8briWQhq)UUr0r==8Y4^al7N{U_eKk$Fphv@%a6pN}kQy2R*aCnG|1@C&R&d_w*Lc zr#M#4hX}|oCvsDAAWwF>bHPUa8jL&e<6x2-2_20qw7&dCVK1<*@5?&y5k3@?E-5$z z$kg#|!*FJ<!z6TvUsD}fKF_l}?2My7?GU;B=A`i<WY3kSl<P2EOxE85J?pkkt37Y1 z0Xz}L@(K#7w5B$mHv`g)l*e<QgoB1=2O2hIdwvx|XUL0=$svRYd9kJUA@OC@Pn?@| zu_?pxQ3?u^s3gfqyB~uZEf81kC>mQ%XuZ}}lTR<MguiUs&5QIh(StN(yz3en`2huB zU-N#<P63;PD1#Q4y9bOX;>;mb8qHzaYVjshVRo{gg9G#V%unxo2QzqIpXGg9`mt=# zVfcY!d3_GUnJKA1!|qhbPid8$?Ckc26HebIAXFkMSa`US-o@X=)lY;N5EUV3)9SrR z0m7I-l~hQHQ^=(bbsxl~!Ez;+1)pxK6hJ@Fb!{f2>SA-u@4=xVJH;cHZIWB7qvoV% zJJz9tLR&=;2{JmBvePgO!Tf8s?tkDmxF!4tU??(H*%G^@_4(zj(Oo~jf7h0J0JX|_ zFh#74^pKFOSvVTik+vT2KabT463*%Pa*jDf!%Fi0#mkWq8cBeNb9NmZ^MRR9FSQ0T z3iJ}_JoDY6Gl#Fa+H{*-b^5bGHb%j#uPjbx-N=B$ab26TG=>7Rs|<DQ0zsL>%`ZQa z!Gn}DJ43pVTSu<l@XFzsiXX$Ghhee+Ex7ZFIOJSCvRLJ!LobmUE!rMsCo&GPP4uiH z#^#a1&N!LQ3q7Jzt53d$l9CU}Vihg*7*xmSu^yf0Vp=DVMi7sr%AGMop=@Mi#M6~z zn>U>>E3^qW4zm+QNa(7VR?aoAp1Xh8ql9;?z20LiTBtY?_du#B?&_*y4~?TS1Jx2n zSCk9JJ<gEeN0PsYWS>gp^#x<-ARVGIFm@4e36YQy?FpzRS(&?-wk0<4vnv#}v?W}c zc!((<*W5R4CmES&{YWSv-VoCFD~a9!C7j}Pe-fhQC`4o;*XhcDEe;B}3<osbPU~+d zVS32eA&eu8*H5#ztyhGu4EaS|(DzBAav|I#>Y(WK4=+7EUtmLGYPuJ~Pf&UKK#jr% zLD9M27cXYb(P*?Xv;&KLH+BF?XtA}m4KCetaMcF9b0oU);rbzx8K_#Aii?XY+;2h$ z4w(@LPTc@yAtHh!*`~<WI?<504`TvfK`l;pOMicVz~Jvv-8P%yrQZQE0mc@Vm;ZS3 zPh&@<d_^7WQj7Gx{n*B*zcjYAv@2>(-&~gSS=6aw_oE5^nf9HP5k33_)hf6VlYR2F zeRMtsA3H**eullDyW=omJdC1s7;{C-i=0D00urE0B$p5r2qUBrMKBqpf4l$;ZtV-= z5yrEJibwL$jWdU^*ODsCnf)8}?cVDyqF1?J4H+0`1>>L1=lwC?L?EkqgO>Y@4(y>F zYcMePM7mdHI@cHbPX)^`KDrboAd&B(WaM+KC3y*G{X2FoeUCvhBe=EO#xD1v<U%yk zb?E0v$f!x4tx>dj5XqS8EaFFnN35EV?IN<*8*K>jP6AECRY`DnqHHJPKG-TG23U|i z>jo8=CHfnZc1oIR?C_@Fmxr1;un%Q91$KF%TCu|7aQzy2TDzI#;^JtN#H$4J%W<L) zA+zF!-`X`r&FzMS6laPgbZIXzoD`XC83!uvJX^9Hb76@Fv0}|#X(_3Z;pYnjJD&gR zDj-9v@e2U<lf+P>p++W<6#VBmkP^{uSkbHp$upqz*WaIDrZx&P0+&Ei7G5qn{O%ow z+G^U{+dt26<L-AZ<f-u!zxNioA(%yR?!zSuvjw&su6d?m5w=@3ooDhbYKyM#3ZK}a z27GhobmkKUpGQxgz*4&Lb!jVwB5?MAx{BdGa$68VHwN&HJ{8%+jc-iV)wLk|ZYyz3 z09Z-P&27B@U=1t{upSUgw9Z7mUYa4vo(2N<E@cjQS--P_m6ap5eBy-mqYnxAiLbxn zFFs!$2H<7-@KGOtF2{1Y00xkzwcg>3B6D3wS<w4iF@SMMS`6kh|JMC(aq84Y(oX|# zk@{2OKSRUbJ@(xK`dMF;*d&MsL1s2IK~g*dT?B9(WO3gv&opNDWllf`a?ce}ydb^I zVcPFX5QDs1ks$1|A%!u=dV4L3C2Mu_PEOeeoie`MetwYBDWA8FLQ3xn<|_5I2jE$R zlXn#2!l!O(l11jBsK=5ZwB~tBJ@=`=8(Z}8M@bZ5F1(QB1ABfvz<j_UDky73S$r0? zB-}2#E4e_`jjd~gze@j?Tle!KE9Q4MDqTfP;uO?<?H$%KH61VU9<6|6kjcp9dHS#& z<eEAp9sM*6Y}6kprlFBh0;;EqL8dfATl+u(e*SjrfsZgcpeNL^agjz-yjfga9hiUH zn8}YL7<G}dkpU`om8=%EtQNVC&)Q?WuL<+^w=itFSiAm5#mkYtapyok5mw4n;e8u6 zvn|Emx%>;SJlC}c-=Xa-(fJa5{DZNj#)96}a{YiWNN&$CUK*)w6BCl2M*_rgIPvUN z27d?gZrdeOa-iFW+S=LaSy(uJ@Cfk9Vfi#Wqv|#xz29?w<$UO^fYy%umqlX9_eSP+ zC+R+F5&2bqxM9nNe^&R>p)GvXH9sL&P*{kdN0OjP0;5MC?VV%80sg&y=E%{bH*kNy zz?l>n8d|wNRPoi)b7gZz=o<l0h~JeR?{8orqh<jsAVA_KvCZKAh9aPhh=$Sdh}J#R zdZ-FDf#8)d%W`r`wnS**tI7NG?)|pfH*|baGF8@6Q1R`wn>n_s-1S@K+|-v}2f`~^ z=FQK!{K-^OAUEf#^)~H|pYEp?72=rAHQmO{&RgH}P5`R`rMt2?kKCFYm_Db0M;IM5 z@egW~)S|NoWR!;o_Uu}i{6<%jBDGabeicP={#!@ClDPNk>#4E$<Vd_xGcjpZLk}V5 zEf6p4w3(Z=9tr9;p%-Y0ycX7TzB@7>C8^S0MYMAm*l~?;_&;xDTH&sF;$)mKdw0Fs zrro>wVNph6kHeGGhYSqGR%Mz!yAGLMw9ap7C`nl;LC2fPsoRzV!zZBjpb(8{{qvtC zYKOJFimCL&Dku8a{uWa#^p_EPN)0n7S8%3h(JJ(Qtg)Y#NnQ>uXMUsJSUjA8mj;Vq z>hcMTALf|$o}#;G5)M7G)6;&9+w={c7vz+{*hiRer$+vav+$f-h27TQS@gVVOBwzJ zTyUGWY*Bf6ZBASxz}w%8W}0!%Y3<^vkp8fV67}9}77+NC*pGI<3fy(ebS(UKe)uwa zPOW$J%^jKVH`E%v6~7yCWx!nS1u;eVv+p<F<a5D($ed=l1bTDQgaRN#7g(XaHbRT3 z$eart7a`q^jD!)O0@s+%wf!hU5<o-(k5g<Q2xUT^hKyIr&eeZbbFN?LInj7#Wono? zJ*9xf?^WqX2D;A%%SKuana>9*qy{`2OlX1^AHf+UIEMLRpedP7hVLF|5DpXDJU$8` zx>qjwJUF-n36iuYc335-O}dAM-mW-^-^NwbrIpSsl<4kpNHN%m%V9Z|p43Hjr+-Sd z#=NkcA(@a^L9jhR1$Zmq$ne>}p{GhnB&Y4kpbD*t=yoRO%xN`n;;W4z8KLaMhwv=H zL>7|ON^5$ui4$kgo?Ku<pL=`DEIF5T7}y=zgGsSvm6%MiPBR)R6aOoXuy14AL^U0K z5NQ7h@&fD_KxvX&Z;@Z@2KH?Bc|hPWzgkSMiqW3jD?%(3l)1=ki#Mhb4=j|Xr40?Y zkHn>}8gN!Pvy%^`Iod{>SNP=(>z2^y0{gF>;WFZy+!$u1d*lcUn0q`9#Ae)3r-v2> z6h7jwpr^(L9F0(M4xPLWips%Z+nC!Pl=UH7ys?Y0b$e&<b^_<az^H-!1`1YVOA)ap zeq;DTe~8TdEM|5ZHZ(9`2+{C?N2yomEM5a|^v@Du+d-YJ+@#^;oplDo3*ZgL09Plx zTt8P<aj_s?gD->`Xb$)&8yU(nnIO=9u&iVG0739l7IGb#^yLx@Q^PaE8ZpMP2IK-j z=1~r1b)CW^O+Kh5aPGC&%uD_IFLB8jGjQt}D3~@eEJELlKe?9iA{*Iy<Ub0m%;XI$ z{^$SS|1W%)4&O8$^gCyTwO|raLFyhmW;c7p!lEu*O&#eJkWI?XU;OuzuU*^zZGO;M z;hNjxPc>jDXN%fHeU%Jj_@$IZZsX)C!=x~@<nR_e&av{QUq**U89h;jP?j;x&oo2B z!($I<4YI5g9?yL#mH5wRZsLf9)JG#pg_MQRULbhs0k6oDqaeH*ZDnvbke~YexnVnf z$zrRF^`Vx48UuR<-e!E&-E6{%#z|O$P#0mxV4~NadXE!AWC!3IdqIrmSZrA2n|uP> zf^pj5{XBg-$<WTi<F}lA9K8TzU0n)X4a^q;Q)@8Kl4P}E>u}kxyMO!d<6CQt91hqJ zF&xEJDlqi`+9k;8fumRW_fyD35-dotCMc^+A{;;;!RxdHbBbrK3H<w>^#Tk5TH-{N z4pdX;85noNh!XsTB@ahQ34R~AXZ%Icrr(X<oSK=bfq4jMoTFnhwEpf{a1<}IDqky; z?TI2`7xKZ+ySNbZ`(fr~kw%7wzTdyw!;_Q*M6sfzrszzbDfBt0tX7g^T}n+8mi&kM z9W4*!|NEBoj~->)z56-O`0Fjy#$N4Pe5ainb&Xm?9;vfXSVu4T2E7qfQ`^AHC!%s% zPWbRHJ(fF=CW3$i>{j}JRd(g^P_BD?N=4;ZDxGYJ3W>;Wq-@c0a@wdwWr$*sCh4HG zs~lS$*+$XaGMQ2mNhvpG>|0c}!YDH6BqR#=`-Jm3%l+ft_mBE0%b53hpXc}cZa*&f z`VMFIRyBtwfzo7$u1inm_Tz2|1cDC@bh|%(#wI+xkda{om#gRQtv3r+X&3wOQ=Y%= zkx;OvXiYmL%Io*zG9nY^RVoThi6}TFMGe_XcZ;5@dVmKe-yRCr_YDv3aQiXCiiEO= zOgX8)YUTKoz|JFa9EdkSI(u2emGVu_t*;&=rKVb(3t#AZI$%M*_30~5g?)ZCa9K=! z``gym-Vj*9-!G7?bK3E%=GilAj!ZgN{}AsSbajC19|*G0x?-*>hg&KKw+5hRNH1@e zg-4!{!y%)jB#^)k1NcA!^QL<<RZ`W`dO8~@$G;TX99i}}``)b_>33hO&&pBms`Gwq z9ZFXb-xPpbGX=JCtkk(~{Ftxbh!NYrU$8e#p&aFS3piew74=PQCVn9cWGoRV$Vj$8 zBEN?*n_sql)JocL;G*NTJpQS{joV&1dD7in+axk9aAIJd6=+tEdn#eju%o4lh>AjO zH-iGZn>j3U5;8IuP~(R*q-<4lL6$CBa(d#Lq>YIXp6rl5mAPl)IXV4jvBd?o{v$2N z=LiJUu0Z|5+L;B+)uW}soUEj(p4YJkb&IK`s}`KGbO}zVn3m=yw#k@eXWX`Ha8ZZ{ z9gik94~PPeN?u|pUKD{IaI}&(gG#OE&qHkkgv<)AGFgpk)SIfRrnutgbL2G*zOU^J zKj<$epUAzjK#bD0K{GfzTdXHC0m=hPuI8XUb1)~o{OZV+;4Whsg@HaF%Rm<uHmCEh zK~AHfJ^XLXx8qC-?~MW=!MU$SVMfq`(JiDTXk^e0Qj2c!ulDtrj6$Rqh)rt-dHG|L z11Sbv^|NUIFSl)>d@0tk4df}@8*y=Q`X+W0_w#l2KHZ2l^ridN@Q`)xj>405KU*ct z%;)<25b?J7DU2&2eU@0QPeyFdUt2eP)c7;H4u}Ra>yN;;7-Q%|i~rCIS;%Qn`Z9Qf z0Bx!hSwEgM;SnmCoFFDoJ&p9&W&)8NpCt69&0hrdKDZHV%khp^Q2L{{kq&}j-|K!D z=DxyMM7&3kzo5a7l}8O=v1k_QsJae9`Nn=B&^Ouj$E)W+;Be%UYf&uoZ2V2>ma@)m zc)IcgHRhKJM4iD2TCGoBh?#!*@GseSI~+!{2~^f2-D7cdNg9&ph<~0qpb>vT67YeO zuKf6_3S4p}QVxk36=N157!G8ZOqnxdDz@0tWtV`O{ltXZ3o#7NFlx*#_$$+D5EK*y zjZb<BWUD&k=OIp4&nwg04rR`uR8}Vs8gz1_{FzxPx+8L*zHUF8b~~wRA7SK(7NhvL zC1{WImaSjA)(pz>q9Hs&I4QJ79>ad6?wDP}|MCw4v*Y=lN9*q(&-OH74<U9Sxz~gR z2MvX7oY;DQUePlJq$lwuA?%{*NhlC);)UQXN5K`0cHH8&9Sb^UtZg`6P9pCbN$H_T z{#HWvt*ON?wIpKhL!(hC(`YvCa*RoUJ_)%-qe=n?NE*DyogCMTbqJF=g+U=iJAll$ z?><eCkJ2Tj@SW~gH`5^uEAg6Bwm&^)LdF82u^{Xw{(39hsfZdxL*Ee53FB1a8Bi~r zlSbf%*`PWwBBSmdVTjeDT%)I-F|T>~GP9#+qCV-~g>=@k>ghj@?i!gxYgM=PGfo)3 zy62=5Z)rwqxu6@JWhe<rER0-8;@RH>_HICzmt<RB0(|K%jXMKyj}Y9BTv)2{e7W=* zg5Es^sS<I})9bVY`>L#CRt2pj&MMN#5_IUNpDcZS^+2+u0o<TNr~+n>Y#CTj;1vL= zN&v~i4o6bOGcq!ucDAs$k6W9YlA0<8E6X#CbRd>8^ehChBldYhrxDK=n%rjyLv(#S zLXzuAwKG@|M1$6W=pJwbJ^Po#n$~#)3H*}SMe#{A-1tCelSQa7HC($;K`Lr#Rc^Q0 zyFm+vIBEF0A(XpZ_in>f57c$ig^-Tna<{RvN!#4S$7aS(+2CDl9w-;du>PGH07~G$ zabnD9*eywPKW+)ht|zMutz7+zFhnE}vK$6_@=%eKT?k(A*pVsCNI$Q@O;c5;tLnuA zxP;Cvn8Yj-yondC;N8{Q3OW+%w$`t|KP`aTLlPkK=-}1S{kpR&aXZL4fzwwBK_35L ztz=%^*)2>VaTR1JK!&>%rT`IS<ngECrGd^86jRO%dr{0>yJxlK!p_;H7~*-awx$*} zjat;;trf0>-@uiz+}2m#E_rT7-50!#I)e{E#?1}zu3e{mNiWXpA%GCxXb=D`GFoXG zLP_xW?37ah!}Qkeyd_OrC?ct<FX6fk8EglLt_S>p6Eq~s4G<&BVrL^GuYeVOgk!%2 zNS<;hIL17ezzO0<v?4k>Iv5yBZeCtqm(Q%a;(Be)=QV{T*58Zl?gYq9aI(wE->$gZ z!;pHT!%*I0cP4aqlm2C=*j6R&vMI$&s*-~JdUcMXJ&30tzg68qmqGSS-`7Fo<b78m z;lfX+Bv$$RX}{_l*ma$b{s8L{l%lf9I*6FgV)B+4tno(Jv`A<MB7<6@w(a^iockIp z-L_P?ePHg;k;>6%zersM!gcvl6|5~<v#z4zBnotHUY~R-D;F8z-?|Q~MHTba{rz*^ zv~`*79FuXNGtX)3OZdp}5D|@;*~U)kjOepia#>D&pY}N+N}m5n``I$B%OQnBJC|5o z+AU;JA(p7vX~}sJrw+0x-M<S?Z|A|thuyCm8&TQ(+T7f16>FveDGUkY&Mzo{riAye zq65H_Nab>Hi#$x0C>Y-Nm&IqApf5(vs{Bsf?`rbpE9(VW`7|Gvhc_AX^$h?p-U8R? z_>$5p9D_wJBoUqa>gn}dXGXE9CwIJ@g{p1(ThY$C2*rzzn>{}rIecCWXCsO=sR6mX z3fpr&!;Zh#X4bpVJ-&U+6DK}V5<LlSj*q7~mmusERJp4W$%ZC$YNDbDZQn<aP&_t# zgnAerXeLqz=zLB9=hJ^WU*Tw<Bn}KR&QIO`z6hp>^Pa4N7Q-BY*~Avbe&LQyo!<0B z9{+gnp;N~Am>%Nngw=s;*f97%DWVc5D82@A526wzgLrX9^W)paF=*rkts)K(I(iQR zq4Pic2{S}H#iX_KyN1TNzX=HrbQ#B4EEd<hQA1khdBob@!PTo-dsj;hl#50h*0+=u zjVOmpf9J(;YVyh63ZE&_As|be$h0UjL+y{TQIY+gWOBm;+>D_i_x-!zbR~{>;K|>= z1X07b9J`E;4EVvHL5>$06C;9d3y2vF+6)pV0y~o=?ktD_MWjbnRaF5g3m$V3Hg&ZF zrXV(C9}pEJTjkD^A$Qh|a_DwQMS^K)p*V*W;b+%;{Bd&AiXaM7FM-u8f258Dg3kib z@2!2;&rM4OXfr+r@1Xt23sc$GKD}XVyKP&;*2(p9lM`&VRg~C_J(RIF$rcz;Q1;GD z)~1p7>ZzKfLf!O=)&4RH70are^3Ky5RrQ)IxL6+sDqm%jWrdFixfG@uu;i8xJER3N zH8qQcZfsQ5^6%Rxw=yuxwuHxaruquzOcS3^_xYTHquU|-&~&(a@mm_$SbKqTihy9C zukR4za%qqVxfWEpXJ85kliSvU@VJjXJ!vVyTNum7TUU8=%-lj~4L#e8ly+x^H?w_x zYX|8YSsjHxx3hitP3v0cv@TN$5ba!o$@7zC{97L%Fr9IpC4abF%-qeOT(&oH_*-uU zIbpCkoicam45y)I13#)C$L+R3+$u?hvbB{$rQpfD?4TAUBdb*K*E(81_C=W~@Nn=E zj@gIyS3B>WsOYCWbPxkn0)u~irf~wxisml4NXeKUD_yA?!_YKZOjW1Gi2M4=zvLa} zX~`C+u=~mJy3jhz64O}-o`dy;@RA>pG2B+9h+Yik7{pbLhNt3;pnZVE5bFrYqflj~ z?qkS+(T3<u^DF%mZvQy|qHsXU7<NYg(+evNwFedsQ-<f8&-u2C^^YBurN~6>(Bp1I z>SzfqP<F3CV$)X=A&ABi231#smtKP2cEl?XH8jR$m8CLTc|U;HxLy`7uQPEstS~YL zk-l6j)&`>l7LPakLDI_?iunbSI?qfhtF3EPEmV>%gS#%e2OisWf;mfmQP|<_`sLBF zhL-ZC5I6rFnWV3ks*G69uI?Z}s{SggiGnzf&Ea4qfCZ?X^i0i^8fR~RBb4s@KV>P# zT-rjb|7LjO>QX+7nx-PQN%$ZvuV};(sglTzC2RraAV93-b#Ih-3V;F6IAL1ZR!}g} z)vH1h4D3Z?sO=GZbGVL?JG0!*%+}G3nUfOyV4;KM;dw8sr=lkpZI<xeh_(hG1X^S7 zOD2rCYnyK#cvmb11hbB&ELIt@M1+!>I*{CVaiViQux|bO7C!%AlNa+G+xeKyx1r8E zSkh)_#58O+95c9W7XnuciL*mi_1pkH<%bh{Gwff#rQQym_!be^APAS$UnVU%+=C@S zAdKsqvB#0j0%B|1sH*EK04#w2!=LapC8eayAn7Y0&F|@Q@Bwg(zd;$>VTl9z?5YL8 z@aF%Fh6Xf+pPG1GmE?7GbQEbXRm#>>Te=iD<A(s{uu0=6T1^Y)Oqnm5^*Z`y(E0b_ z9H4aAp9eBj%3seLtJ1Con}Zkve1X*ku<75k%`I;uGLT4#2*Sr;1SEcaHhz;#bWs7o zB8Zlv8FSvyF@d}OlrIrkHU^~;pb>}=peO(p!cTUSEltR@kYKmC#6!Rx18l$<1F9bQ z4=PiFV>UEkfGYgUVJa8S5x^6S06r0K<JN84WMvh>_T^zp3(&Rhy?*`pmVUEM{dQ5m zSD60uUewf>vZ~P2^Nyt3L1#APKUYOU683{V0GUNUQ4tu3jvO=PyM6o^XDH<pZ=C-c zBSXVn%#c?(d2ar+_HK$?`!5)5`~7ks2%C9`njn%pl`{OxN`j@4tNuENGCv)#;H_zQ zquLR(_5EVMt{1$2zui-q0y~$&q}pc;^ReI7vgQMQ(B$wb<MxJtnWAlDl^|+Cm7SFm z>60iTA9kfwcZ|%;<?N{#!&gA>3BOa5DZaTfyVvZ*L%ksH<KNVe_fX~wONf{jGS*Cd pTjf5A3#FXpbhbz6>42Vo&uE|Pe7}pF;4BKRwX1C`Q_c6B{104v%9H>A literal 0 HcmV?d00001 diff --git a/docs/manifest-pipeline.md b/docs/manifest-pipeline.md new file mode 100644 index 0000000..d4f8ec8 --- /dev/null +++ b/docs/manifest-pipeline.md @@ -0,0 +1,63 @@ +<!-----------------------------------------------------------------------------> +# Manifest pipeline +<!-----------------------------------------------------------------------------> + +The pipeline running in the manifest repository is the one that does the real +work, like building images, generating docs and deploying image to download +servers and triggering tests in the lava test rack. + +<!-----------------------------------------------------------------------------> +## Triggers +<!-----------------------------------------------------------------------------> + +TODO + +<!-----------------------------------------------------------------------------> +## Build jobs +<!-----------------------------------------------------------------------------> + +TODO + +<!-----------------------------------------------------------------------------> +## Deploy and upload jobs +<!-----------------------------------------------------------------------------> + +TODO + +<!-----------------------------------------------------------------------------> +## Test jobs +<!-----------------------------------------------------------------------------> + +TODO + +<!-----------------------------------------------------------------------------> +## Job generation, parent child jobs +<!-----------------------------------------------------------------------------> + +As we support images for multiple machines/architectures we are building a lot +of different image variants, where each needs at least build, deploy and test +job. +To simplify the generation of all these jobs, without a lot of copy and paste +and the possibility to configure the actual build images, we are using gitlab's +dynamic-child-pipeline feature. [See gitlab docs.][1] + +[1]: https://docs.gitlab.com/ee/ci/pipelines/parent_child_pipelines.html#dynamic-child-pipeline-example + +There is a *'generate-build-jobs'* job, that creates a yaml file containing the +pipeline with all needed jobs. +There are the following CI variables controlling the content: + +* `CI_PARAM_MACHINES`: Space separated list of machines to build for, like "santaro santoka" +* `CI_PARAM_IMAGE`: The name of the image to build. If set to an empty string, + related jobs are not created. +* `CI_PARAM_DISTRO`: The name of the distro to build + +* `CI_PARAM_IMAGE_FNG`: The name of the fngsystem image to build. If set to an + empty string, related jobs are not created. +* `CI_PARAM_DISTRO_FNG`: The name of the fngsystem distro to build + +It uses a python script called `generate_job_from_template.py` to convert the +`build-jobs.jinja2` to `build-jobs.yml`. This yml file is then used by the +*'trigger-build-jobs'* job, to setup the pipeline described by it. + + diff --git a/gitlab-ci-integration.jinja2 b/gitlab-ci-integration.jinja2 deleted file mode 100644 index 8fc3d66..0000000 --- a/gitlab-ci-integration.jinja2 +++ /dev/null @@ -1,56 +0,0 @@ ---- -#====================================================== -# Trigger the integration pipeline for all repos using -# the gitlab-ci repository. -#====================================================== - -{% if image is defined %} -image: {{ image }} -{% endif %} - -workflow: - rules: - # This rule is needed, as otherwise the workflow:rules from - # the parent job seem to be used and prevent the pipeline generation - - if: $CI_PIPELINE_SOURCE == "parent_pipeline" - -stages: - - integrate - - build - -default: - tags: - # All jobs should use the infrastructure runner - - infrastructure - -{% set projectneeds = { 'project': "" } %} -{% if optional_arguments is defined %} -{% set prev_project = "" %} -{% for project in optional_arguments %} -{% set projectshort = project.split('/')[-1] %} -{{ projectshort }}: - stage: integrate - needs: [ {{ projectneeds.project }} ] -{% if parent_merge_request is defined %} - variables: - parent_merge_request: {{ parent_merge_request }} -{% endif %} - trigger: - project: {{ project }} - branch: {{ branch }} - strategy: depend - -{% if projectneeds.update({ 'project': projectshort }) %}{% endif %} -{% endfor %} -{% endif %} - -{% if manifest_project is defined %} -{% set manifest_project_short = manifest_project.split('/')[-1] %} -{{ manifest_project_short }}: - stage: build - trigger: - project: {{ manifest_project }} - branch: {{ branch }} - strategy: depend - -{% endif %} diff --git a/manifest-build.yml b/manifest-build.yml index 697dc69..6a4381c 100644 --- a/manifest-build.yml +++ b/manifest-build.yml @@ -129,3 +129,176 @@ variables: .gitlab-ci/scripts/package_release.py \ --images-dir="${BUILDPATH}/${IMAGEPATH}" \ --outputdir-local="${DEPLOYPATH_TEST}" + +# -------------------------------------------------------------------------------------- +# Stage: build +# -------------------------------------------------------------------------------------- +.buildbase: + tags: + - builds + timeout: 8h + interruptible: true + image: + name: "${CI_IMAGE_YOCTO}" + # Override entrypoint so we can pass --id to set the UID and GID for the + # user that is created in the container. This is a feature of the + # crops/poky images. See poky-entry.py for details. + entrypoint: + - "/usr/bin/distro-entry.sh" + - "/usr/bin/dumb-init" + - "--" + - "/usr/bin/poky-entry.py" + - "--id=118:998" + artifacts: + expire_in: 4 weeks + +.buildimage: + extends: + - .buildbase + - .build + rules: + - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" + needs: [] + +.buildfng: + extends: + - .buildimage + variables: + CI_PARAM_IMAGE: ${CI_PARAM_IMAGE_FNG} + CI_PARAM_DISTRO: ${CI_PARAM_DISTRO_FNG} + +build:merge_request: + extends: .infrastructure + stage: build + timeout: 1h + rules: + - if: $CI_COMMIT_REF_NAME == $MASTER_BRANCH_MANIFEST && $CI_PIPELINE_SOURCE != "api" + script: + - cd ${CI_PROJECT_DIR} + # Get pipeline for merge request + - MR_PIPELINE=$(.gitlab-ci/scripts/get_pipelines.py + --gitlab-url=${CI_SERVER_URL} + --token=${GITBOT_TOKEN} + --project=${CI_PROJECT_PATH} + --commit=${CI_COMMIT_SHA} + --ref=^${MASTER_BRANCH_MANIFEST} || true | head -1) + # If pipeline exists, mirror its result + - if [ ! -z "${MR_PIPELINE}" ]; then + .gitlab-ci/scripts/mirror_pipeline_result.py + --gitlab-url=${CI_SERVER_URL} + --token=${GITBOT_TOKEN} + --project=${CI_PROJECT_PATH} + --pipeline=${MR_PIPELINE} + # If no pipeline found, trigger a new one on the master + - else + .gitlab-ci/scripts/trigger_pipeline.py + --gitlab-url=${CI_SERVER_URL} + --token=${GITBOT_TOKEN} + --project=${CI_PROJECT_PATH} + --ref=${MASTER_BRANCH_MANIFEST} + - fi + +.buildsdk: + extends: + - .buildimage + - .package + stage: build + rules: + - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" + when: manual + allow_failure: true + variables: + BITBAKE_TASK: "populate_sdk" + artifacts: + paths: + - "${BUILDPATH}/${SDKPATH}/*.manifest" + - "${BUILDPATH}/${SDKPATH}/*.json" + reports: + dotenv: package.env + +# --------------------------------------------------------------------------------------- +# Stage: test +# --------------------------------------------------------------------------------------- +.test: + extends: + - .infrastructure + - .prepare_test + timeout: 1h + rules: + - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" + when: manual + allow_failure: true + variables: + # Include git submodules + GIT_SUBMODULE_STRATEGY: recursive + CI_PARAM_TEST_SUITE: '{platform}.jinja2' + CI_PARAM_EXTRA: --nop + artifacts: + when: always + paths: + - "results/**" + reports: + junit: results/results-*.xml + after_script: + - rm -r "${DEPLOYPATH_TEST}" + + script: + - |- + # Submit tests to lava server + RELEASE=$(ls ${DEPLOYPATH_TEST}/) + INSTALLSCRIPT_ABS="$DEPLOYPATH_TEST/$RELEASE/$CI_PARAM_MACHINE/fng-install.sh" + FNG_INSTALL_URL="${ARTIFACTS_HOST_URL}/${INSTALLSCRIPT_ABS#/*/}" + .gitlab-ci/scripts/submit_test.py \ + --fng-install "${FNG_INSTALL_URL}" \ + --name \ + "Gitlab build test ${CI_PARAM_MACHINE} ${RELEASE} ${CI_PIPELINE_ID}" \ + --results-path "results" \ + --test-repo ${TESTS_GIT_URL} \ + --test-repo-branch ${MASTER_BRANCH_MANIFEST} \ + --test-plan ${CI_PARAM_TEST_SUITE} \ + ${CI_PARAM_EXTRA} \ + ${CI_PARAM_PLATFORMS} + +# -------------------------------------------------------------------------------------- +# Stage: deploy +# -------------------------------------------------------------------------------------- +.deployimage: + extends: + - .infrastructure + - .package + rules: + - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" + when: manual + allow_failure: true + script: + # Workaround: We need a command in the script section to be able to run the + # after_script section of the package step. + - echo + artifacts: + paths: + - release/**/**/* + reports: + dotenv: package.env + +# -------------------------------------------------------------------------------------- +# Stage: uploadftp +# -------------------------------------------------------------------------------------- +.uploadftp: + variables: + CI_PARAM_PACKAGE_FTP: "true" + extends: + - .infrastructure + - .package + rules: + - if: $CI_COMMIT_TAG + when: manual + allow_failure: true + script: + # Workaround: We need a command in the script section to be able to run the + # after_script section of the package step. + - echo + timeout: 30m + +.uploadsdkftp: + variables: + ARTIFACTS_SDK_PATH: "$LOCALDIR/$BUILD_MACHINE/sdk" diff --git a/manifest.yml b/manifest.yml index 52c32d3..ffeb647 100644 --- a/manifest.yml +++ b/manifest.yml @@ -3,17 +3,11 @@ # Global # -------------------------------------------------------------------------------------- include: - - local: manifest-build.yml - local: common.yml - - local: manifest-package.yml stages: - retrigger - infrastructure - - build - - test - - deploy - - uploadftp variables: # Default image and distro @@ -26,6 +20,13 @@ variables: # distro for the buildfng must be settable from outside of the job. CI_PARAM_IMAGE_FNG: fngsystem-image CI_PARAM_DISTRO_FNG: guf-fngsystem + # List of machines to build images for: + CI_PARAM_MACHINES: imx6guf imx6ullguf imx8mguf imx8mpguf + # The id of the gitlab project used in the rules section + # to not run pipelines in forked projects + # Using variable here, to allow override in other projects + # including this file + MANIFEST_PROJECT_ID: 1725 workflow: rules: @@ -36,7 +37,7 @@ workflow: when: never # Do not run pipelines on forked projects # (use id instead of name because of rename) - - if: $CI_PROJECT_ID != "1725" + - if: $CI_PROJECT_ID != $MANIFEST_PROJECT_ID when: never # Do not run pipelines on integration branches - if: $CI_COMMIT_REF_NAME =~ /^integrate\/.*/ @@ -75,424 +76,34 @@ retrigger: ; done -# -------------------------------------------------------------------------------------- -# Stage: infrastructure -# -------------------------------------------------------------------------------------- - -changelog: +generate-build-jobs: extends: .infrastructure rules: - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" - script: .gitlab-ci/scripts/changelog_generator.py - --token=${GITBOT_TOKEN} - --branch ${MASTER_BRANCH_MANIFEST} - > changelog.md - artifacts: - expire_in: 4 weeks - paths: - - "changelog.md" - -# -------------------------------------------------------------------------------------- -# Stage: build -# -------------------------------------------------------------------------------------- -.buildbase: - tags: - - builds - timeout: 8h - interruptible: true - image: - name: "${CI_IMAGE_YOCTO}" - # Override entrypoint so we can pass --id to set the UID and GID for the - # user that is created in the container. This is a feature of the - # crops/poky images. See poky-entry.py for details. - entrypoint: - - "/usr/bin/distro-entry.sh" - - "/usr/bin/dumb-init" - - "--" - - "/usr/bin/poky-entry.py" - - "--id=118:998" - artifacts: - expire_in: 4 weeks - -.buildimage: - extends: - - .buildbase - - .build - rules: - - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" - needs: [] - -.buildfng: - extends: - - .buildimage - variables: - CI_PARAM_IMAGE: ${CI_PARAM_IMAGE_FNG} - CI_PARAM_DISTRO: ${CI_PARAM_DISTRO_FNG} - -build:merge_request: - extends: .infrastructure - stage: build - timeout: 1h - rules: - - if: $CI_COMMIT_REF_NAME == $MASTER_BRANCH_MANIFEST && $CI_PIPELINE_SOURCE != "api" script: - - cd ${CI_PROJECT_DIR} - # Get pipeline for merge request - - MR_PIPELINE=$(.gitlab-ci/scripts/get_pipelines.py - --gitlab-url=${CI_SERVER_URL} - --token=${GITBOT_TOKEN} - --project=${CI_PROJECT_PATH} - --commit=${CI_COMMIT_SHA} - --ref=^${MASTER_BRANCH_MANIFEST} || true | head -1) - # If pipeline exists, mirror its result - - if [ ! -z "${MR_PIPELINE}" ]; then - .gitlab-ci/scripts/mirror_pipeline_result.py - --gitlab-url=${CI_SERVER_URL} - --token=${GITBOT_TOKEN} - --project=${CI_PROJECT_PATH} - --pipeline=${MR_PIPELINE} - # If no pipeline found, trigger a new one on the master - - else - .gitlab-ci/scripts/trigger_pipeline.py - --gitlab-url=${CI_SERVER_URL} - --token=${GITBOT_TOKEN} - --project=${CI_PROJECT_PATH} - --ref=${MASTER_BRANCH_MANIFEST} - - fi - -.buildsdk: - extends: - - .buildimage - - .package - stage: build - rules: - - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" - when: manual - allow_failure: true - variables: - BITBAKE_TASK: "populate_sdk" + - .gitlab-ci/scripts/generate_job_from_template.py + --template=.gitlab-ci/build-jobs.jinja2 + --distro=$CI_PARAM_DISTRO + --yocto_image=$CI_PARAM_IMAGE + --distro_fng=$CI_PARAM_DISTRO_FNG + --fngsystem_image=$CI_PARAM_IMAGE_FNG + --gitlab_ci_current_rev=$GITLAB_CI_CURRENT_REV + --ci_project_root_namespace=$CI_PROJECT_ROOT_NAMESPACE + --master_branch_manifest=$MASTER_BRANCH_MANIFEST + $CI_PARAM_MACHINES + > build-jobs.yml artifacts: + expire_in: 4 weeks paths: - - "${BUILDPATH}/${SDKPATH}/*.manifest" - - "${BUILDPATH}/${SDKPATH}/*.json" - reports: - dotenv: package.env + - build-jobs.yml -# --------------------------------------------------------------------------------------- -# Stage: test -# --------------------------------------------------------------------------------------- -.test: - extends: - - .infrastructure - - .prepare_test - timeout: 1h +trigger-build-jobs: + stage: infrastructure + needs: ["generate-build-jobs"] rules: - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" - when: manual - allow_failure: true - variables: - # Include git submodules - GIT_SUBMODULE_STRATEGY: recursive - CI_PARAM_TEST_SUITE: '{platform}.jinja2' - CI_PARAM_EXTRA: --nop - artifacts: - when: always - paths: - - "results/**" - reports: - junit: results/results-*.xml - after_script: - - rm -r "${DEPLOYPATH_TEST}" - - script: - - |- - # Submit tests to lava server - RELEASE=$(ls ${DEPLOYPATH_TEST}/) - INSTALLSCRIPT_ABS="$DEPLOYPATH_TEST/$RELEASE/$CI_PARAM_MACHINE/fng-install.sh" - FNG_INSTALL_URL="${ARTIFACTS_HOST_URL}/${INSTALLSCRIPT_ABS#/*/}" - .gitlab-ci/scripts/submit_test.py \ - --fng-install "${FNG_INSTALL_URL}" \ - --name \ - "Gitlab build test ${CI_PARAM_MACHINE} ${RELEASE} ${CI_PIPELINE_ID}" \ - --results-path "results" \ - --test-repo ${TESTS_GIT_URL} \ - --test-repo-branch ${MASTER_BRANCH_MANIFEST} \ - --test-plan ${CI_PARAM_TEST_SUITE} \ - ${CI_PARAM_EXTRA} \ - ${CI_PARAM_PLATFORMS} - -# -------------------------------------------------------------------------------------- -# Stage: deploy -# -------------------------------------------------------------------------------------- -.deployimage: - extends: - - .infrastructure - - .package - rules: - - if: $CI_COMMIT_REF_NAME != $MASTER_BRANCH_MANIFEST || $CI_PIPELINE_SOURCE == "api" - when: manual - allow_failure: true - script: - # Workaround: We need a command in the script section to be able to run the - # after_script section of the package step. - - echo - artifacts: - paths: - - release/**/**/* - reports: - dotenv: package.env - -# -------------------------------------------------------------------------------------- -# Stage: uploadftp -# -------------------------------------------------------------------------------------- -.uploadftp: - variables: - CI_PARAM_PACKAGE_FTP: "true" - extends: - - .infrastructure - - .package - rules: - - if: $CI_COMMIT_TAG - when: manual - allow_failure: true - script: - # Workaround: We need a command in the script section to be able to run the - # after_script section of the package step. - - echo - timeout: 30m - -.uploadsdkftp: - variables: - ARTIFACTS_SDK_PATH: "$LOCALDIR/$BUILD_MACHINE/sdk" - -# --------------------------------------------------------------------------------------- -# Actual jobs -# --------------------------------------------------------------------------------------- - -build:imx6guf: - extends: .buildimage - stage: build - variables: - CI_PARAM_MACHINE: imx6guf - -build:imx6ullguf: - extends: .buildimage - stage: build - variables: - CI_PARAM_MACHINE: imx6ullguf - -build:imx8mguf: - extends: .buildimage - stage: build - variables: - CI_PARAM_MACHINE: imx8mguf - -build:imx8mpguf: - extends: .buildimage - stage: build - variables: - CI_PARAM_MACHINE: imx8mpguf - -build:imx6guf:fngsystem: - extends: .buildfng - stage: build - variables: - CI_PARAM_MACHINE: imx6guf - -build:imx6ullguf:fngsystem: - extends: .buildfng - stage: build - variables: - CI_PARAM_MACHINE: imx6ullguf - -build:imx8mguf:fngsystem: - extends: .buildfng - stage: build - variables: - CI_PARAM_MACHINE: imx8mguf - -build:imx8mpguf:fngsystem: - extends: .buildfng - stage: build - variables: - CI_PARAM_MACHINE: imx8mpguf - -# ------------------------------------------------------------------------------------- - -buildsdk:imx6guf: - extends: .buildsdk - stage: build - variables: - CI_PARAM_MACHINE: imx6guf - -buildsdk:imx6ullguf: - extends: .buildsdk - stage: build - variables: - CI_PARAM_MACHINE: imx6ullguf - -buildsdk:imx8mguf: - extends: .buildsdk - stage: build - variables: - CI_PARAM_MACHINE: imx8mguf - -buildsdk:imx8mpguf: - extends: .buildsdk - stage: build - variables: - CI_PARAM_MACHINE: imx8mpguf - -# ------------------------------------------------------------------------------------- - -deployimage:imx6guf: - extends: .deployimage - stage: deploy - needs: ["build:imx6guf", "changelog"] - -deployimage:imx6ullguf: - extends: .deployimage - stage: deploy - needs: ["build:imx6ullguf", "changelog"] - -deployimage:imx8mguf: - extends: .deployimage - stage: deploy - needs: ["build:imx8mguf", "changelog"] - -deployimage:imx8mpguf: - extends: .deployimage - stage: deploy - needs: ["build:imx8mpguf", "changelog"] - -deployimage:imx6guf:fngsystem: - extends: .deployimage - stage: deploy - needs: ["build:imx6guf:fngsystem", "changelog"] - -deployimage:imx6ullguf:fngsystem: - extends: .deployimage - stage: deploy - needs: ["build:imx6ullguf:fngsystem", "changelog"] - -deployimage:imx8mguf:fngsystem: - extends: .deployimage - stage: deploy - needs: ["build:imx8mguf:fngsystem", "changelog"] - -deployimage:imx8mpguf:fngsystem: - extends: .deployimage - stage: deploy - needs: ["build:imx8mpguf:fngsystem", "changelog"] - -# ------------------------------------------------------------------------------------- - -uploadftp:imx6guf: - extends: - - .uploadftp - - .uploadsdkftp - stage: uploadftp - needs: ["build:imx6guf", "buildsdk:imx6guf", "changelog"] - -uploadftp:imx6ullguf: - extends: - - .uploadftp - - .uploadsdkftp - stage: uploadftp - needs: ["build:imx6ullguf", "buildsdk:imx6ullguf", "changelog"] - -uploadftp:imx8mguf: - extends: - - .uploadftp - - .uploadsdkftp - stage: uploadftp - needs: ["build:imx8mguf", "buildsdk:imx8mguf", "changelog"] - -uploadftp:imx8mpguf: - extends: - - .uploadftp - - .uploadsdkftp - stage: uploadftp - needs: ["build:imx8mpguf", "buildsdk:imx8mpguf", "changelog"] - -uploadftp:imx6guf:fngsystem: - extends: .uploadftp - stage: uploadftp - needs: ["build:imx6guf:fngsystem", "changelog"] - -uploadftp:imx6ullguf:fngsystem: - extends: .uploadftp - stage: uploadftp - needs: ["build:imx6ullguf:fngsystem", "changelog"] - -uploadftp:imx8mguf:fngsystem: - extends: .uploadftp - stage: uploadftp - needs: ["build:imx8mguf:fngsystem", "changelog"] - -uploadftp:imx8mpguf:fngsystem: - extends: .uploadftp - stage: uploadftp - needs: ["build:imx8mpguf:fngsystem", "changelog"] - -# ------------------------------------------------------------------------------------- - -platformtest:imx6guf: - extends: .test - stage: test - needs: - - job: build:imx6guf - variables: - CI_PARAM_MACHINE: imx6guf - CI_PARAM_PLATFORMS: santaro santoka santino santino-lt - -platformtest:imx6ullguf: - extends: .test - stage: test - needs: - - job: build:imx6ullguf - variables: - CI_PARAM_MACHINE: imx6ullguf - CI_PARAM_PLATFORMS: nallino - -platformtest:imx8mguf: - extends: .test - stage: test - needs: - - job: build:imx6ullguf - variables: - CI_PARAM_MACHINE: imx8mguf - CI_PARAM_PLATFORMS: tanaro - -smoketest:imx6guf: - extends: .test - stage: test - needs: - - job: build:imx6guf - variables: - CI_PARAM_MACHINE: imx6guf - CI_PARAM_PLATFORMS: imx6guf - CI_PARAM_TEST_SUITE: boot.jinja2 - CI_PARAM_EXTRA: --all-devices - -smoketest:imx6ullguf: - extends: .test - stage: test - needs: - - job: build:imx6ullguf - variables: - CI_PARAM_MACHINE: imx6ullguf - CI_PARAM_PLATFORMS: imx6ullguf - CI_PARAM_TEST_SUITE: boot.jinja2 - CI_PARAM_EXTRA: --all-devices - -smoketest:imx8mguf: - extends: .test - stage: test - needs: - - job: build:imx8mguf - variables: - CI_PARAM_MACHINE: imx8mguf - CI_PARAM_PLATFORMS: imx8mguf - CI_PARAM_TEST_SUITE: boot.jinja2 - CI_PARAM_EXTRA: --all-devices + trigger: + include: + - artifact: build-jobs.yml + job: generate-build-jobs + strategy: depend -- GitLab