From 60d19f6610a838060f6d8b0121fc698b4fc887da Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 13 Aug 2026 20:06:08 -0300 Subject: [PATCH] chore: add snapshot tests base configuration The actual tests need to be created. --- .github/workflows/debug.yml | 10 ++++++++++ CONTRIBUTING.md | 15 +++++++++++++++ app/build.gradle | 2 ++ .../landwarderer/futon/ui/PaparazziRules.kt | 13 +++++++++++++ .../futon/ui/view/SourcesSnapshotTest.kt | 14 ++++++++++++++ ....view_SourcesSnapshotTest_dialogDownload.png | Bin 0 -> 22789 bytes gradle/libs.versions.toml | 2 ++ 7 files changed, 56 insertions(+) create mode 100644 app/src/test/kotlin/io/github/landwarderer/futon/ui/PaparazziRules.kt create mode 100644 app/src/test/kotlin/io/github/landwarderer/futon/ui/view/SourcesSnapshotTest.kt create mode 100644 app/src/test/snapshots/images/io.github.landwarderer.futon.ui.view_SourcesSnapshotTest_dialogDownload.png diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 6ea146ff52..1c59cb31e5 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -28,6 +28,16 @@ jobs: - name: Setup Android SDK uses: android-actions/setup-android@v3 + - name: Run Paparazzi Verification + run: ./gradlew verifyPaparazziDebug + + - name: Upload Failure Diffs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: paparazzi-failures + path: "**/build/paparazzi/failures/" + - name: Build debug APK env: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 93f8418f4b..b3fe4e4d08 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,3 +11,18 @@ + Please, **do not modify readme and other information files** (except for typos)(and if you are better at explaining it then thats also accepted) + **Avoid adding new dependencies** unless required. APK size is important. + **please explain your changes** atleast try to cause it just helps us work a lot faster than spending time figuring out what you did🥲. + +### Snapshot Tests + +* Baseline: `app/src/test/snapshots/images` +* Reports: `app/build/reports/paparazzi/debug/index.html` + +To verify: +```shell +gradlew verifyPaparazziDebug +``` + +To update: +```shell +gradlew recordPaparazziDebug +``` diff --git a/app/build.gradle b/app/build.gradle index a5a83ad4f2..6f47c0a077 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,6 +12,7 @@ plugins { // id 'dev.reformator.stacktracedecoroutinator' id 'io.sentry.android.gradle' version '6.1.0' alias(libs.plugins.compose.compiler) + alias(libs.plugins.paparazzi) } android { @@ -241,6 +242,7 @@ dependencies { debugImplementation libs.workinspector debugImplementation libs.compose.ui.tooling debugImplementation libs.compose.ui.test.manifest + testImplementation libs.compose.ui.tooling testImplementation libs.junit testImplementation libs.json diff --git a/app/src/test/kotlin/io/github/landwarderer/futon/ui/PaparazziRules.kt b/app/src/test/kotlin/io/github/landwarderer/futon/ui/PaparazziRules.kt new file mode 100644 index 0000000000..87ffd4d13a --- /dev/null +++ b/app/src/test/kotlin/io/github/landwarderer/futon/ui/PaparazziRules.kt @@ -0,0 +1,13 @@ +package io.github.landwarderer.futon.ui + +import app.cash.paparazzi.DeviceConfig +import app.cash.paparazzi.Paparazzi +import org.junit.Rule + +abstract class PaparazziRules { + @get:Rule + val paparazzi = Paparazzi( + deviceConfig = DeviceConfig.PIXEL_5, + theme = "Theme.Futon", + ) +} diff --git a/app/src/test/kotlin/io/github/landwarderer/futon/ui/view/SourcesSnapshotTest.kt b/app/src/test/kotlin/io/github/landwarderer/futon/ui/view/SourcesSnapshotTest.kt new file mode 100644 index 0000000000..a6bd5b3f96 --- /dev/null +++ b/app/src/test/kotlin/io/github/landwarderer/futon/ui/view/SourcesSnapshotTest.kt @@ -0,0 +1,14 @@ +package io.github.landwarderer.futon.ui.view + +import android.widget.LinearLayout +import io.github.landwarderer.futon.R +import io.github.landwarderer.futon.ui.PaparazziRules +import org.junit.Test + +class SourcesSnapshotTest: PaparazziRules() { + @Test + fun dialogDownload() { + val view = paparazzi.inflate(R.layout.dialog_download) + paparazzi.snapshot(view) + } +} diff --git a/app/src/test/snapshots/images/io.github.landwarderer.futon.ui.view_SourcesSnapshotTest_dialogDownload.png b/app/src/test/snapshots/images/io.github.landwarderer.futon.ui.view_SourcesSnapshotTest_dialogDownload.png new file mode 100644 index 0000000000000000000000000000000000000000..b28a567b9dbbfdeaa4c9cf95efa89dafe89b69cc GIT binary patch literal 22789 zcmb5Vc{JPI_cpA9YAJeGRZ&zYt+6GjxhO3)6R9Co2V#sV=AqT%Rz+JiMNL&9iJ^uV zLa1uZB*vH$6fp!r5Odyiz0dD`*Lv3XyVmpkagwz@EBTyr_Sxs0eeHc+ab_kDxjBV6 z+1S{)4IVwPU}HPh!^U=E;q)oilZN_&ayGUn-3AY|t%AmuNgV!{N2ACL2KkidcU)>> zl@x7kSkxf2p<-^UG)dZKSaKvJS*4}hsaIwGi{JnIA=s_*=E|{8Y}&K;Urp~t2!MN* z^p)8@v7P2&`t{PznuEbe^b$IhI$Yw2>rrHNdVvP=ILXF#+W0@W`;g;o|E;m<@Ui{J zb`H+Q_TSno!b!IO++OIi{oi->cL@I{T}`E3g74Zuji2>P`ANtUudDYcs|Z3z7FZJ) zpv%)sY{I7Mkg7+CyL2UiZY{Tn-h)8n=iORWOlIZqd=FE3GbZEv95OgH9nZ_gwj-~r zpgdDz6R=RXE086d;W(rME{>e|^F-RH8WPWV@=;8+S?f+mBwx##6R+qxjg?xOj{emyv37 z*<6j2=*U)o$MY@@^Pdm)=^nQ?lZ10%lgxTD$k=y7D&hj$4><*Z%Zi~tu%f9nbgU{% zfGTt>I#qHKo>^W;8A&JL zk%Koo(r(Pzz(*^53RP+u3lB}H#=Ulan^Ojr9i?`Zcn=;=UDekGpX;s{@3!c>^e{(OqXZjen`ifaZl!Q{cvZheEfx(1?}b>` zl^m3M?i*z)f#U~}mU7CgRULla(56z4fH7LwlGw^NCX^B@=AJQJQXjTiL_tRSV}-$I3*2j>)@pqg1M={!-SvYb8u4>Ar%Iis)tV(Nmn-({L+VSBo#wDY@L>XUkUqyi^4 zh$X~{h++Jfd%ia}b*A>h75v+u4AdG35Bx~oe0Ww2`e*ewht_00{lk7lcSpQes9Q$W z5gOzH*tN+Mup!El0U9A^y{Y4ccr(AHC+{=2`+w7_eV&C?WZdz>x{|-<+aV&tW9w)> z7HnoqdAkR@QuIkcqK|mZmX(|LPQu8SXOA-?giRaOnk7cqwqn{QI#J*AY%sPO0}a6( z!hmq&IZ0SIXwvGgi>bruLED!6N+3Xq*@+-3jUM0cFo{yLfVld%M*Cm(_vYr67KFm`GZ%a>cJlh9gW ziGfoM5iMfNs@y{NI?sL|x0yMxDyRmh-ZMGNW~dApy1LCPd{JG}chgtjd*^lhVlxkq z;j^*rz#GC_w`RE~BW_}T#!zMrDvi8swGD#kF(O_gn@D=p47Z?qYjpp%OsG9%?q#Fz z4WX>_p?OH}kPD}?f3@Mk z9VT>Zq-jfU_B|S6pw16!=PP~d1{wDc_4woIjC1?a&mblkDvBm!S1~+0J{Os?)hhj^ zW+I`|hg5x4m+rogt5+7SowHiRmdpIJ6zUG*e_K@@XBaM2?J}>;AcfcSWRh{GGD&JY zCtJwE^Rpi-#q(79QxTOX3br)@!nlRC0&Kli_QpOHq=E%RZEG6dgPec&!^HEDsRZ~W zYK}^h?}+-bC*x52iSNX#e(s*yx9aqVuji$P#*>r}x)Zve#o2O%C zUxr;|0OYc9OEHTlX|@*%XR-aCey+C8jo)mJ`EU#3-=D4c-09b@B*6Yk3CZ~}$^a44 z6XQHW@M*U2`1z)=v`W?I;C>E0&78*bb)X%KO2xoMIfNlODKi}Gj0_H*ON)(#q3@4&W$YSMFWsNcLw+jxDL1CNxva8= z)3Ic5ZsDFdLS(tS9SckYnSk3ZMwhfm>|1zDX6-(F2u0+5OCf(JOo;YhF>Kjm|9R)O z=BO2B(lP~BS|+Kk4giK&$5|At2q`^6WvuX|c%8=*Ob!3wFg66uG!1*x~lsF+eQ580Vbrr}v zle?_rx7jKoJG(h17b!I&ZO3_te*;Z-6!<4SvX7$kNMa?!723@lKJ>lwRts2mUrZQ| z6(Cl*su55BcEno3a&3QIRD`nU8>VyW(i-8m;cid(?KoFP%F{Z!+9S&d6V<^rc8$nn z7Y<>;MN!8}$_lt8yPilB;506IW7{bCf@gQNd1)WDy@jx}%|q@YH-$744M$kZZ>t0} zN8jz=9Y}jKgN!b(&KH1VIZ!lY=cuqt%b4feo3ARkdP0*Nu;hpf{w2;@r_W%&eFK#~ zZqRb`SGq1eRAK!(WJVjZMV-)KC#^3=EWB&!$nkg{<^g$!vS`|G#3J1vC%AjuTAmF5 zm9lfe0@OSCuPQX#M3|n2kp{H3WcpESz50Wv1Y5A}J1X6aU2bx0* zbYtJ20c_l!ICqOOs8`eAhQx+-2oYZyFf0|92m8`3I2Z0YB1H3$l)2Fzo3vHG@nzgDHdcrg3-x|^vXl_ zCt~N(;6j5n&D_<@p3KVYBTGu>f&WCfKMpir?jXA#N`_q5(MF;A8QjK1+u_uk`|GRY9Q{049-r`zw~7fSnW{F|AC4O{;@7`tBemKZ|dsO4eY-Pn-P z*cnE!9BfbeOVflE+WcHp$md_~eaq1Zq00#(3Pa%tpQ;I#C&OkI%F{tM4Kw`rZ^t@o z#}h#mXvjr>=e0@Y_`7x{1=u?>i;OaI*Ij1A%K1QcB-MncN{V4+_d&9{Tpabz)Ucr zE>NNRsm)K#q-rwfpQyw$t5~xnYeg#fforgDOSWDDz?0~!7-l#2(kK|dl&w1yvH)dP z_av=lDVtX}wf2~F_>{QAa{Ta#ZzxiVzl0QS%+`rpR;4`ZL3C_(e7ilP^gzFW25?Pn!%8Fd+~=(gC!rlHX|$<@Avn` z0Qab?p?jfR{Y}hj;?M`>Z)^qPhrx)^ruly}H2glg^JkvhuWCoVWV^*6NY|Ra=q^nM z(6|20q(nl($uO&P8v%S&F-0wxBXEKGq%^sHZbZ`hWdIyoWJ4j^8TUskRArJv0ZuUVualVf#otMk%6rTu4uaR zZr%$zdgSDBKDJlhTZJU$CX}D*g4~$HohB?Jo%;ma{aO}~ihWDbf&>j8EZOu+DeEGE-uXNjyn?nig7xb%0w0w(qJzrh=aEV+xS9AkSm z&kFXh{D=1cTi|~z@ju_Y@hPe4PNJj)Iluu6041N>A5=FDYEFE*GFm-Z?1(}Bl*V^$ zsw+I-xJ+N$z7~;lKICHBi<=1bX@*S>mi7_8-1C1Y(hS%1sTLfB1|f}Ul!9@}*sieH z!Qt}f%a%<6e17ZQbMjzXWg9+YU-?;AcxaA#*qC};xHW2^A#mn3a&HEIb8($+TEXku z2y;`CC(2GpR|e0zG|F>Rl@tmSza;GJW<0-(a2^UN2$=pJMD`shZ2Q3(zTBHr*S<+p zyuK4SDf*^+)@Q(QlQi%U4<8#64y)jj(WyKhl6BbnUP!gq-))>E;!Xa(o_{k_G;6q6+*|t{1&@YKG4Xu{#_p9wOtcf z-?r|oazYHD``L*H1#Tj<$!*5UYDz0gDo#LIq8u4OUp|Idx|H%A!_%i@NsUmUpfcQR zqBRFP9tjAG(<{5GpKhO5ZdwVj!R^XqH2tjd?CYrV80(b=f0ti6hV=A)N_494amg69 zoX?~e%3kC&PHC?$9$&4V?!4h{>}5-?pZp=4q)FV)yz82%c5Eljhd$;RP=~K$QunFW z9-OlACX!t9(u!Mdib`O$O#s!}i!%Z={*u|N8-R1kV6RL~XIE?QRbxZ;-I?X> z%OsyW9^m8q_zc2f8-2l{Aw$c(e4Ke|Q`D`xbn>6`r{OUX?kjf6vSi5(#_%T4BHLNc ztV-6FvPS4O2zL#DlIA1w_59N6o^H`vx-J%T+GvSfJG$SmSsAjZ%AmC|_`1*6NB*9S zd?p95hQ~ceV1q-(Wh@{R1kNAG^g0RYcn3CcL@~3 zZpA?JZ-*u`jX|G;)@8H{@#J>e5jOcQ1)ou%Oo}H!yM=n%%~S# zDxhA}XGXee{xrKvo(<>KEUV7Wi3~2|`2dXx9!>urw-lbOr9Xu%JV& z2xADfZ7iJx<-3ull-6`AKY~rz5Bq;8S=3C&7F<2+=T|c+^k2uzj#F!!UO6W*ajF&qr0~@^?5VTHJryoQ^L%g1%8$VvKl+>`ifQ>mw0!mi`4Ho`=x zQzH{=cn7d$2MJfhtWYA{drb2J);H%qpwz)TL2dcfA0yOgBLsthiS~}y-t{je!|i&! zh^x*ixL4-wz@t2bO5mSozX*eXy{*e0s@02>#A69%Fx9{f((k@%ZZ*=jJ;uLev^FH( z)h&{jy^^szL|2}u9)#99@1Cj&vyJ(xW7+nSN)cHB5Hm7ZhrI1}jm5oMwnkqf_{ol( zXceh?Z0?o;B)hWhV=uRD8tnB<$kQCBW?O03p<)~);|x<@~#B@E-Qiee?S|LOaWuGMfMG-#p~pdLrK;0^2@N{*6hs zw=A^2Ch%iAZ+Gz2%b5_FGoI7f^Bx$twN> zcD9ECTedy5rcA!L#x2rB;I?hrtQ5|PL(;*3eFrrU_h}#yHY74%Z+rPA?@5ufM})yM z8e29YcOLlrjy_M5>fdvnAMEH=3&PlA?+_ZQ)IIG20zhHp9qf6acgW1XuBC+c%7Vk0 z7SE(Cj+Kon|AGE_k(IchM7baS(WostD*7EdJKUR|#|2JleFIw9zG8I_*AXlLALAj< zOY$$CoH;DHGQ?lcs4+P@v458POb=4&RurhcW@bXYEW1e*6Jkxx^B&gwSJ}vErX*ef zE~&9gd??|NvWlB@Y%WBveX_<&s$(4Y9-qTLaU1>)YdT+N)&bEJ_KUg&KbC(wqh4}w~aUZYz)F=HL#S# zyDD)agx5#F?W2w*x7CFuGS05YvMrqDI8k&WG@>6QIp!+Y?JxCv915!t(S#VS(XHwu z7nP+Y0T>b5_+eM(yhrFX5$(>L3K(cabKN~Gp}#Uj^a;uB>RM9AD_lbZdDb%8`(G38_FFaE)!Y1FBqxL;b* zquBtfpKDQ@;X0OTZk75ax&edAuctNxE`u|W4-isKDzEuQpE??tI`!3sCp`tGRA(82 zu|i2zUXo`Pr$m%}KS_~x(F>c<6bsmfV~uZqesZhnB=LLB4Hjkv`z*OR45^TJRL?BD zEjAmh?i)g&z8`W7a)mnm0q0#5fZMiOZ=ami`cP$T!8edk9vB=dmwlmw&N3Ol1757o zGtnohG0vRn`Q2y{PbuKrKw#|hV-SV`sy{H$5US?0_9vjPYlcOf#z1f^8DzU0A!hs- zXsPnMO8+dcaky#Mc?)i5U58`mkOA5f?(8Enjol<0NDpg82nwp5Uz{I<;~c8>V6{(t{ve{#acfe`;@<} z7D+WR1{GXMNr(02oAqG!by7*gGMQBhv5d=yMWJvMKXQ8jFD`HmUK+SQR=@wMsNhN@ z1O=-Yo{Y@9iM?;lou~ykY(pmUWd%04S+BH6@MLdb)=X>mt!9eykk3N~3G3o5{^*C} zg|)14F`GDBStaIV<#!p{1tk3h1ZzLUejxA%Up8{ z)Tw-{oP{10d!*J7DKP{rK}o{&Y*O`hYU`6oNu{Y-;;^*<4%#r%bR=JL(aVL-^MP^3 zIO~H|kI&s@%>w3&vhyj1G5Z0Ry(PHWtnLkXh*wiWl^j*)5hLwuG{R6}41X|L|6J}kM(+A4)b;}jqapPo zDG`4(KhE*0ArfZ%x3G;+2B^VK}3ISL#h(hG^}M z6^zpM7GXG*(pVyNu>U*xLQR&{459jE;ZtsH)(AqeEb~sny4T{wF^18)bhkSIMH&_( z6uV6P9gV1-{&jc2aN=CM7<|kWCTp0`f9KKsEUgi>?B;EiuF@d4xAICNAad}YgYlb( z(dQyN>dYVxR{>f(yON|yvp4L}d16WxXfF4S!Rw32y!)=^{O@^gDN3*LYP~Fb0K=5% za~<)02sl^f_E@52JsKLWo^pB!!AAf*FScMt{$iEO?`sUAb)~-gN zhz;H&_2ErYagYc>eC0%l*ao;<;Na9p;p2;LPb6jsoFotj_kXyOfEe^vFmdWSk%Xpa zCrQZy_qXxNd{n7-TRZx(Z1n_+@jBcuICCbN$QL!!#p9q5+?luQGQiLiJ%ah!qt#HfGS;XYedWei9fE1lZ zA}56jIJnK`hno&qLfpg#f=#Ho&-)|C+f5TXtCCRb$xMbBu#BmE74SID)_inai`wrJW{LxX6n@Lf7jm(QRInG&*2nY>a8Iiiq z%HLXaOaUqGpoH;UlYtLtFU8O1x0{6#F!Ova?od(Y&y-@&2#hXdtjB50p1#W7o7G4# zeh8Wk_i%L_O6c3xJGABure$MHHry^0oG*;<>#=*i+N5k<3(y)+thV6)BKynVX&!p| z^TMjK;$8PNsDIOILqpEHht|`;>ajG8X=ux-k>u~PLQrtsesdlY71`q`Vb-H{)NC0z z*!1WNFI`& zuw5pS$z}Ts{j#)?CL+x8vFh?wHEKY5b!1pLn~Mwv3m z7)Pw#&F%CM3cBtJ;IS0oL;+tJ|5sZhlEBXSCR8j$V05l;bX*~q`hk?Wfi{cxBL$y0 zMmtyPd+MZ`--w|kjK@@+w#KA3mZ8BUki}3|pm;7}*)t7oOi%O@gn2uDzhTdmzg#I{ z8vUj^7Id{gWOJdPXbh5&!c?1Z0y2odb7W%<65<;8@@0hpV&SHY^FV$9Psc%8(Jl&B z#r)cv8B7#@y=N zaCsU1J%T>s&@E*ps#hB*a%5jQEO8LL$XK+fDvHsh*`3}aY)Jqn-*|0OIrTu!M+B=y z9iX4(GH_OI&PFsWWSaXmTXc+Dm{qijU*{K7-$wJ6Ybg#uySz^UOtP*$znd$&P=piS z74^=zXYVi%DJ2UOIkI?1E4pMQBT%9$?08c{Ki^JZM&D@f1-K1q{qpx$MTA|OLunN{ z(c}O~z5=*reS23ox&H<$4J#cb01qM9@ZLw?aQY*$1QB9;g}(|oY;bVj{6awUHjEw? zn5P5;Tf3wGX_*h9J9e!^UKC){q!KoZGUYVF!uB9W$dgf`90b3(oRH^jW|J48SUZGP5rnKM^*=Ji6pD*7T57&~052 zu7x3OxL43CBp;iG?w0DlXP#@3uu97Lt-2<->45Z3Z{{;JhvS}MFPwtDHSoTQC&VsF z^uW4Il-$t3!tR@gkO2ZiG3k?a393ybAxBK9Q2-8a(oC}A%YA8nXOX^UfoUwne@)0Q zJsfm>P5rs%^eoR)$kWapw{d)2p+AfjK2Z1@4~|wAa$*|uy@-Q~Jc#@Qo&LLV#oZZkOk=E?+D9?o@vDLK8QRsyf~3x6L1 z7S!hofK3;Q1`Iwn!pk1&IPjFPF8}Z3gS<&gybgH{_Npv9xk@@~c}*!G{DM4Z(^K9% zY0z;zw%)6Ha6cjBwMAMenLWkOcS%qmb9Tw*0qJY76FOdG%jlbDStFPRj%1kpY6(q( zJH62#KfiRZM&=O5r^nU9jjn$C8L-uwbSA$Lo1L*~R}_0ygQwsSD3XpAxCE|xe_3@E zCsxJ5TKXNQXVGs2UTKAae{a6H*{j`J&!UkbC(N7jm##`#$la9Wm&#?$XOJvqE(w4g%e~(R*gQzXTG7eR@@lFU)Rt0B z4?|Hok2NSWTfw%qoV#zS{f`f)QFh8(F!a#_T;Nqn0Kef9!vZ=&P%~$(vG75o&O;K@ zHMFQ~ASyz35@9y9r*WT<0G$D@@aUb2XepAg z_@=774&M)n@Yx46lI58P661f4Ti(b?%5n^XpnjqC70ALjtw@E*6@~&wrvQ@EA(5cB z1ohD6FYf<-vi(V5Rqm1NNm@o$+?SF3CBs14$R7aJKPVAfrC;tCxMH zq7G#EEZL8rgtuzB2CZMHvjrwdNHn0cS=pBg^w%xrPZo;b8Cgl(##_3oJx3R@_@#t0 z(3M3^O6HHr7LJ4fhDVFANgwxh*3MT+(XskES`qQkDs;JHl<7Mu^{U|> z4yf%?xusRjmnKoq2D@Bv{Sdv=#<0X(3pn|cs8}t{#vX#|`-F0VK`oPt7c>xVPQojV zNb>!B26gdw_0rkockLJ<-{ zo`_6Yu-aoFkf$DDO|j3`m!|AyhdOO&@4no9SsKdm)j_h@a|MRmDbGXhBSXqu_pQMb z5ynAZA zXEk|z7OT0+*Q>26z2;g!r0t51`AN_IDt$$`cFO^6A$M-LbmSaNWm7*Ccr5e=A1TSQ z%ZBEs5s=sKRTX%!80t2Mekj@yqbaEvE0=~?|HY^^YT$O#IQ2D=KXokrc%-Z3d5zAy zFAt0uH&4ryF+I<5>M*a}~fk7OE&BYhE@47 ziGkE9XaWjGpe9#klgAhJNE%Rjkq>pap1TcNGl%Va$oEUJ%BP8Jz- zH9n_%)!1X7m<8?SgbuNP(X@PX{m^XAx30;bE3X|vIY_Hx)$x%z{eC5W^+VDY-lCnYFVgPk_R&iPIFUdFE zk*MJr0W9=5M63$Z>jNU1Ca2!-R$9*+CkrxqwiS>!HMTIpx-3GqWK`8>qBEI%ogTS` zbAE$fZdnh%eZOA%odQv8mSvV#rt@nBXX(&A`x0+$!454iAM*PrIcBB68dh=r$E-_} zV!qP#bQUvayYjSA5-N^K{hmoN*AZnE=x>GEEJBUqM|m}E){vY#f2-q;2@S4ea_S=#22Jbjy+8X$N@I*POU%w`_H|>Ww0POkr^-EM6d`b7zLfR@n!D&R{eM~*7pW47c{qbZCg|GF3Q1LVIp zPLh6klai?g^~)O?^X=YBkg|}DvX~^QI68}% z{|El|=9*r7B-|y!GEv4^u`C=kU>tm)?C1C_Phb0*@^z~Tg4OK`aQ*7)>?oReg)dN< z{7v0hkyS6aYbk;EX>lKPdm-=mf}?3B`ePJQI^cu50JLrqRBF-oqJZVkf8TETaCy$A z^T0(!7XEAV!1qj#ovCk+m?F>0sWmO`##QX;;tzQl7jirr4;!&+!44{s*Qzpa3P0f% z#wbl5nzj5TFJIR*Q3`~rpN{E!t?>|idq~WXb9(-aTsJcRt}}DBg+fVDyQwTwRTC?q z^jR^h(8u7Wnj$gv1s)!M7esR5rK!t@23+qT)j zGn0)Wa&8beob2fC3Msh#*O!JV6yh*PE8($!SK5ZO%)MpUwy@u1se9N+MbONWC@N46 z^OSU+6t+b>3{9-v-IY^+$JHaPw)(pg#F@H2sF!@CuJ9+sT{MX%k$#QCWCW(=Tr)ZI zufQ4Gqlb(?Bxt~Jsb4ke6w5rp5H-1KmKzqX*BA#MF^D7`HH{sY6*;(z!7jf7VBow$ zH*bm?HhI3+bDuLshempjxzUs+IzY6SqV5sErFfskyT>$^5BcHkX zG2`y-o>2SmkT22nGy%@aAiIqt$~X$4{U$Y_ArN%mbIcz$lda*?e29D5V!{X{mL7JG z+_mgxF_pP`3xnf%R-^K23F_g}2tq&+xDYvt@r?8q#Jv={_w-wR(R%9uJAokn+*p63 zKJ<97;I8bY$enU)?}k(vwK`7|$Z>wht@Xf8MSz-g#FNsz-IWD9aXM2%2A{cKFoJPF zvZ^B;B&kv3FLzpgkrU%bcIN+b{|QGk&3rV}oN)Jgi_3(8O^%$y_x`XgWB!3$C#k?F z&|;g~UB;^7$SlXtE-vE)G+%JiDhn`#+Gsx=>Hkx4!+m0Y&x4V8La$mDc*dx}NuXCG zG^0c~5UxiD)rOW&=LxzzwgsYwVe}zY+DHY_C`T2~o=Jgq#-y~WMecnPekeZQ<1&Nw zq@fDR1gsvrsN>}w$FG!_qx0&E)?z6v+bDvun~HYIEAm_v8D$`9$gf2}=85?WNGmzw zg(OF+&q1xLmtdhu#tg-BvCvj_Q_&%UA~itrQVws*IMM2li|2 z%<7Tf_jnoMe}&3`=w6oQVw`dM?M%f7Pa@7PQipHn?13k3BOFATI1x7|1jm6iBqyS_ zt*w7^8`H??tFVO2cl$8eK!b-8gDmDg+^>2T$VwWZ{Btx7eP35ViB7@|>^A_>#vxZ; z;aGB%Fb~~a!2wFWPg`P!?F-%9v}%BTy$K(KQLbCaMM@j=1_KtZYEyH)2jtPS=yO1f zOOB>4__poqZ$7Eg_H&Ij{;ZI&s)4Zl^i8K$Qo`#M0$G{GA!aePGlUd{u}<(Z<~|m> zD3c$V2_cD+!#zwyHQcwC)ggt7T?wEX2R}w|fMKZ}Z{(SbnEOBG=g`y2U5bE*o(8vw z1dqFNRo`|emE!IaY4cXggw0rorAh!O%AJILtWC8Ey~;?tmmf`05KcYZX(0f?dzq zHvst-v5G%>LA0Uce0Brc8MysIA;)p6p~@}cDuCno%f5VVY$1wE6qCCZix3LopLky4 zoULwj9q<}&R`c73HU1_MAC_LkPV;pJbFXB#D>09>c-UoU<7rE^nqZNTg6l5 z53Y2xY_D}=`!r4LJOlU-;yeB>H#1aT9zt6Ery zSqxl{bQDl>xa1Zt``g}cx+KQfrg74fxq6LNws&13m!nfPgCt+TpX(dnWXrtCFu?M}(Iac=?wRhn-CnjTHoJctuRjn)EqeA?XnypGbu`sIRtj0*N z(lWrY=OGL0ugIfqN4dh7esE6pGX7%9v_}0%o-Y0=2m8@O#fBdYl;_-3*}f=Jq*UKUVfp$o8d69+$tNo|VLlg4VNhdd~PuuB(gx22|Xb ziE?@3UN>nwux*(8_NLkTVZf7JrBnUktwd<2(wzZ6hs-7_-t5(UI5tf;*SKCLNB%s-d6PGay7C>oH$4g|cU^yWUrhs-nDASNm{?91x?G?+ zL{1sLgC{Z9KYbZYD}BBvs^o38(O*&e1ly|^@$Le7uTiImx$_Xt4T4GLZgDabRc{gk zo$*gD$=jFMDTWPivWq9h{*`+i`3(I5LdE+0(q)$A0~Y(+H25+vUR<)(Oi3JPv9EqU z!M|}6<`o5uY3$ALhA4UqX$8RDCkiBAY77K#{xDFE-1_m075I)^T#a;KMFW39mPXn@ zCjc-nY9zUtn%uMk`<)Fn{>^I~Y4A`+k#+nEjCWek1d9moxTb6FkJRKha7sTm*iRe^ zb9DY(Oub=j3EpAplThC|;%eUS{+7;PZE2L&Zrff}t}HNR>YaRrZ=uhED3NZUM%usu zx-_l3vZ`Y7&343}$3#P=uxxbV^|Za}nQ%DU8hih^7Asz6DB;}3x+nTe3d6J4I}Z|M z%wzCWXed~bB`^Ie`)hk#U0}@qI5-9&#E!AMKqZIU2r+Mr{wP*muik}?gdKhFvtdC^ zw+s(u7KUmxD=c+^PeQ#B6L08Ryf~-x7Mi7~?cM=-H$g(1yR|-Vl7}$2ZOXc9Jx#lF0P%76NKIn?q!)-3upQUmmp={BrV}vh z6o#g@H|p~a?UcO&o%d$O$hS1}Hx?S4B%}7b0|8nJOziwz(ZD_rZ#?R+4ey4PN6zK}L7eN@NeL;fQ(_vF;d4 z2AJ~EyTa`LVWF+4c^nJuH7$FuC!d^;waCxeri;OgH#dS05?F%ZlN#^w3MKQcsi7zG zc-NtO4vO{of()X{TunI3hW89r4!&*I*N5o zQwdlY6u^nFO~rHdglyTRPey=8M;n7p2iKKKCjYry7QQb^d8vOS7xA1Lb(J#99{6!e zEaFeQAbm&~Xf%g{^;AAISWahKyAk8OzfHQ9nCx<*;&ED|qdg>1RI#Ik_TH7Q6H}=E zSfSEIR-S4NRbsK!E1w_V`J;gqfChMtT6(OEv$)pI#8g~PBqV|kR;05aC}nkvBf2#X zci0{-%Ze(5C8>JV29G=M)S07#`R@d0ly$qStx}hjZ?ZHDT(fJ7FHRxyeI^6Lefu4- zH0OfZ2M6mLD*#23a^uT(qh20C5Oet6wTDLDR5e)Vm#M&mocV_~jmw|yYtEutWqj2} zcBxQLIhluE{|wE*LD(#3ecy}P+_^di81}eUrNvWF;?o=HUpIKQ&xF>|b?`?@(ybAz^t2j;g4}5b~v#d9<94G|`R));A z>g471+pt8MJ$-KqyT8RLfS*#yPuC3RBBK7DxULhm2}sMDj74(zD;3|V2XVvK24Xrk zZn*!IFq7l~p2K9L48Zs=t)TOlC5Wd`hDlj!45h-P-|2nVBC*LD+sjnPQh5XI^gvvi#15!IZDRYe?#tPI7ZqH0o=*W zDVqlpp3x6e+_t(|F%Kt;>68asQi8Rhfn`uz%+g;#53iqBhD;TG;4b{I-bzP>fJ#QD zH0%9VvXSQKkHXf}d3{6y_hsXmdKx;@c)PQpR;(C=*Y-M~MHWq`YBPitOJWjiGg-R2 z=JUD7jawp%?Z>UkXD&!XVai6Y(N9@{UiIQ|NfT1=i70!nP8S#I@qB4rFtDueN^J>C zUO{4zsv`GBjTtP7IKM|3kB0r3K0ET={F@vi=Z-IN{Qx=OxErC!ivs(au zB|GI+--7$V=WeRFQ0{;nt6@3iu2q1HY$5hibZ|) zsF~lbRZB9iynm)rFFD}mbaS#V7$MKq^PI!9?n8eQ3qA=o1S)&~I1TDoVd>3BtAhg{ zL2mw*;CSqR)c>(Nr@ot;*7y8r9>KocAKYHcN`=%C_IgjfSk8LbJPm(X>AV7lure)| ze0DMKZABxIL-|Wqa^FZA`i>CMiBP}`p_bSLsnaVTlgVlT{uh`CujN(^794G_9rF?@ zU89#`8wg*NUYfMmUW*Z!(9KeOuB{ExH0F*$$jUc7jIttyQkTGiGg&A2??im;Rg2@8;j>Im|)Z9=WqQ{Bck;D0|i3cI7A& z`ED)DX@=KVh{~bx}jrl-Q zToKxvproWOFdI;C0p&x=eRH?cnUvzF#bz>7NQf?na+GJt*lVmgv>QP(QMcO>b_uy6 z>PBJl`WXSJ(Li^wZ0EEm^s19aRnF;*CVnwFL~g{eqm`vQ@-?*1?M?GVKuK`9qN{og zKRqVLi)H(Tha!N@rRrb&frf=|43%5GSuMjsey4Nr+OmXVoqFlM>9yuj` zkn_GmkfB|nahPwc?nA&v>;5Fq!DU%*_pXk7#Mm?JZQn(SF9?XAQ|^zsb$kVrD5s4_ z&kBbF&)>#Q0dXi+2ju3LqaIfuPwPVhQUVs)OC)*|{BkH#u$fY`}CA={*_aY*b zMXsDF5$}AJInMqxCimeJaFEkjV9t+RSkF9Jl#b!L`WHOJts0ZiOzC_rc|Zab)Ykc1 zpR~$;QI3T|DBx@maUASLAoZA>M6@1uM77)q7?_uG!V=n)8_&op-C0^cUea6mT;zho zOCXs;HYaaFrwL=4#PdWe$C&iEuY$fT_#x3A_`@^@1dv7}IEN_9k&`@C4*ByI<<9Za zMs-)N|2|pn&{f!Y^4wDr24>wLpsdvQi#gmSXkUJ!eUwb)G*zflDD@}X?2KO{axL)F z{>E4r;Lj0c6LC`I9Bu!e5For<_y}me;IiV>f~SC;GSoaj+|>whhs_k}h6(4N@aFmj zT{I~o?(ZjAfqxIkplJ==S5yUS>E$jy7I3DFt&p1?ho~`}3CLe@qq#A{xZp}$mG$a1 zH1k&##N&j`^LQ55kWlg=rWDJ)$b%%j7lSL%>I?F3s}*<7t^3Lfj2=yVT? z4NT>6Q}-ekcNzBSUNFofD@ z41ck?)Okfe2IYKlSwYU0ZzxltA*bC^s3v*gy|wt zyzfmL1g7X?OHWkPG%1x^L8Mky?S)rhUgB?wrl8To4=0me485(kU9zRZ&U~_VLU707 zwx0>Ut+TrG+-hfB znbvlQ(%+RFev8=lcUA~)wX+nCEdgLvm@TV6+Z;~r&Ie={L+yazPTTyhvRi8<1kp$6D!E6&$r!ZziNui|;+@z#@K^?)Yjw*gNWG%ODlMh6INAw3 ziZC(z2---lrAiKBRw;=IR}vWQMeBP4s*ObnT{2;IBF`8EM(NpDoCc)~A3nI+w3vF< zx~j$hCh2_L!9>TKWSYM->IIx_=|0`MU#{OLFwvK+-P*lTzw{|}?`MC80`(KmT55o7 zoui{aV>+b1wt9lDo+q3}&TED*%XIBcMp8V)tW{!z;pX&)OpOrP2hanPl+Fl_Z|<=NJ>t#nYQvJ&mn(&8 zbDT>JSzvivT7$O7itAF^6FfQ^;9|o_`|t0!Lh{+^jvvLLoZuU1sciWZ5wj1t3D5N!Z#?8A*|U?P@9uy z@GY9nS&Vko7h{}#)ZBdat;H%NFmxk-Zd_aU>fH&L;CQUQ_R_GL=B?p5gq4j#jhtf7 zDqgHgsGTB%XYbgQ!kI>oJxX^xhFc|sUogPCl4n)tOGMHw!8CC#Pd_>(jOu#_y*krz zUlb`gkF}H?8y2923uAry78U89DdX~kYDatUjz7oFCB3a1S2S~>+Ma;5SNC)YBay@E zZ(Q-@{{7>d2{Z67y`Dp|r`C%&AAlyQv8wm0m+qEIi{isC&`(`;*$=Z%ZbjR+!4DCn ziTXkAU9LC1d<_2ZulM0?Z}E5qi~Dl#!@c!UQP~RQRQlqORfQM*ggK(&w45&Cr~2&l zn;M29Nz(Rm9RnHh@)~Csz%l}B6;RRC05&g&DyqCUqOACbda-eTD@ab>BvSgN`DYlI zS8p^9PHE*pJ@WJ@DZ-wU6YK~jlugqY(d{W#vuklptDPNolgF^D$(nx-kV z6;~Jrl1f<{^w5Z)_mA zbnP+J>Rqk)^`3H`&7kQ|Nh!tj*o&a~P3`aW1R#=3^aP+hw(E(*Ow