From eb6a0883c3c7e942e44a0c87dce43d4fee14cc66 Mon Sep 17 00:00:00 2001 From: Y Jeevanraj Date: Wed, 27 May 2026 12:14:55 +0000 Subject: [PATCH] timmer updates --- public/media/README.md | 4 +- public/media/alert.mp3 | Bin 0 -> 77568 bytes src/App.jsx | 4 +- src/data/appData.js | 1 + src/pages/AchievementsPage.jsx | 141 +++++++--- src/pages/DashboardPage.jsx | 62 +++-- src/pages/FocusPage.jsx | 479 ++++++++++++++++++++++++++++----- src/pages/InsightsPage.jsx | 164 +++++++---- src/pages/SettingsPage.jsx | 11 +- 9 files changed, 685 insertions(+), 181 deletions(-) create mode 100644 public/media/alert.mp3 diff --git a/public/media/README.md b/public/media/README.md index 3b55e98..d78a9e8 100644 --- a/public/media/README.md +++ b/public/media/README.md @@ -9,5 +9,7 @@ The focus page looks for these files: - `/media/forest.mp4` - `/media/cafe.mp4` - `/media/music.mp4` for your custom track +- `/media/alert.mp3` for the end-of-session alert sound -If you only want one file, place it at `/workspaces/HabitOS/public/media/music.mp4` and use the custom track button in the app. \ No newline at end of file +If you only want one file, place it at `/workspaces/HabitOS/public/media/music.mp4` and use the custom track button in the app. +If you want the timer alert sound, place your MP3 at `/workspaces/HabitOS/public/media/alert.mp3`. \ No newline at end of file diff --git a/public/media/alert.mp3 b/public/media/alert.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..db63691f54af4c08f7229e51bce5ffc2cd0bb9a4 GIT binary patch literal 77568 zcmdqJS6EZ~6aKqG3L&)6Llr{kHFOX$K!8xCgkGeDt^xvrf`;CEk*c8=LFod5o8A!w z1f(cc0kLAo@`vAMKj-2+=jL3Ti?eczg)qa}tFywvl&i32|jc;ozQmx{jG zF1e&=4)!2JxCT^Q=>rCH+FFS^IuKWeouv1V&Kl_?Y+Cxy@}d_V4%-J7crEIJ)3)Xm zW2|+8Mr_`xKQ3>4#N?>C93gLGqm!^Gqs^eL;*#8yppxg<1{moO26@NE->oqI?^{Ba zZk)aLc6{UErH00@!dug45hWJ&!PLH=e#C=Z{{0g2BUH3Q9!WF=__HibmudZ zOmN5W0H8)7C083*AdfpGlGF1m$da@8lnlDz5@P*Oai0I1^>`s0h%ual z$r+{QZ2TbWEBT>WE)AC^EoOoWL&YlYK7uh#5ET&3SQwSe?=AyILuAPbnO$I0TYWi! zs=XX>`besn#+^Gxgq|_;&&Kfn)?NNYHt=N?otqD3H>PDF66bCulGV!k?FgcHE&*7J z*^970QrwMNQm?eUW*&lQl1dUJUvZ_FGV>xKn3W=i$}^*Y}YNDEFmO)*Tb5#{Y8yuP0X)Em2?pgm^ymX>?YG>*dNbQJT;@+ zhI?on=Z(+&{r7skcvdQ!tH{-kV*&KiO&-ajmvm1EJanqQFQO0Nshs~Kr_^M7L#giL zjHP%(IZybr^<(zXNXT7`OJqgsC$dGQnJl2~8wv%TaTayJ&kc-&={D5!B}qTX@E6>T zIg#h>!u}rnpOY*tCur5#O@?+4`m!AR|9qlCAR|)9NLe`*fazxt?4tOGkn)arP&~NN z_+tTrJvk?3)hHk_+AI*qx{bfru{PXm26`quOpnGgl=m9?Xl#z&?-R96X~Z-4Xt(G` z4CLepi*Lmv5LvVg+vTpB5^m)8jGWYTISX)ri|LnMn0LhX{0^W(;8MYK2Pu2!2p9=~ zGxHdnQ;nr6CN{W)640)rtl#h%k2PBAAJ<m{EVtdMb@v6Tg*^5;2fAW+pe>lz z)O|Ys*2T!-_(|gcAE;sKGd2w!yd@#WEJw4=G^RHdBgl>f!zUM0Y${>m?6R<@6-2-m z?K?UbNtI*y5|+v*x)fJ10Q7+g7Tq02s}K!d6zl2-w4zuAC!G;*L@F##!lft0rSY2M!mAA_rC^};M*m|sBl=%= ztT|=%uABGN=45wI6NA(6?DaiYY}^^;BbkeAJRYiiuHQ3{e^Ko8G=^Zhm!A69dyPX#<ImN;Xri z^;jWwbbkwXdNfs3hPz3*n46YRO!tZZ`N&w9pjE*X8QPEcl~K(AG$Akrg;KbIJin?7 zkvQJBm>HXv*O;Rq`_vZiR)wZ>D(#nx9Lhq4)`DXokp^U7-P&C?**k?n*eKK1MM0hUTz+Q>y@@O72lWV z$L>i_s_}!|_gy>g&ZkK!c>5>_dAc=y=EeEutIQs6Y#CoMty;lZ zhSr5W*Kem-8doxC@#G##X;D8vQxbD_O4#t{+M+hgMUoHV=)ZzE0YU`^G@#p`g z|7T@Qkkkcv>23*CM{erTE6nIEwni**f-f{W0Op-t22~$Z4 znHqJP;}815_o@h20Jj1E=w%AYs9YVYRyE;g!LqsR;JaeH{GL0M3 z?e<#E-Iyk*OBC@jb6)nHayr5=>ouT@yp7qQ*`{)uJ$85s7vRN{6w`fcKqRJk8JuZOXxOb_-k zEB_da&Bb(HfYeU=PK|wzZRr%8I#oZ!@@04U%JGsGZLTVNe!vVUw@zH__?;NTBCEqf zWJ4C&I%|RfPV5B$2dc`d*+}&+oKFB)p{+I$<%-@Ku_VdL&{D{W|2fE_`+}tBJpfd8 z(C>zF2Jp0^EFH#RDCkjAq5q7Sj3j@TZe{~hqo~GhMq@IbL*028SW%8u#qsW(Vdnm! z7J~}s7GaSVA6b1;M8PT3x>4$axR;rI`uEFHgndnzA0&$KxNd8_RBU={BOew9RML6$_v#dZS6rOdG8Fccx}@7)o=sh0y!wI6v+|$~!=a}vv?ZJSIPaZ? zT;7CL)^$C4!k)kzW~0x0OZ{vCJIzNv18aN%zJ}gS!PPI-o(y$pY&&IsEv`yl%ry|( z&QdM#9Qe7NyrF`>JSQ04s%($Aks&h|; zzx+vyURAC?AKvtEwDZiQt3o>x@(BbZJfJwt3TPG<+%}5`71@Hwsi-)bpWgYAw%o|| z%wkdY)mK%MzaY$^?@)HvfBWHAQdrGx#fF$N%C6)!7kFtu8;^u&(xt&)qd#6-i+N{E zI0)0_a2CG}w`IfiXWmDXHw6UUhO`N;uhY0*OPfaWN!1jM5$@eQb6K4E<5{d0#XLv- zinW~V*z><*>$^uQd%p?w&BOZ}69qk0{rj5IgL2b_P}*}3g~Dq~tffC^QRlV755zs< zpygM0Uv|c)*;Z>^6pEc3D7<+?w2gW#dhey(wf@iZ=fpx>@(-LOUq4k1fQ^199A0gM zMI@fn=ji=d^Nba%2U&`zgw+II&MJ)N^gDZtOU2`&DylGAdRVCG!6~s?s7+z!vzrg0 zOP#`<60480E}jZaF*JcvSfSg`Gp3*A;cRrhh3dL8%pj~FfFD3c<`47*(X9d9T3jqK z+9niITIk4oO+yH z9tBSxx@jqdLK)=YD!&@Q{k;}~>-!V`YXf5U1uupj*FUm@zH`U*k3sR;1;R_zXGBl=zIB^vs!URjg!yu_gCBh% z!eWBa9Dc(Ud6}-HSa)&tjq}w_2Ax-W{9bLZp0}<%h-uf@9CMst@H>>xb@E_bS@??Q zx_O~;xKAca`)oi!oPepLQ->*Qv+f&>$xoLHrf)j#3O#ChqPIG6`QjOZMei@yUskCE z(Tm~)3IEBWE5Y*Lyqn(tN70b~hR}ohu$AJQ6gw~UInmn#AHK+(5+2^@glPU#m_!T_ zpL%So{yXV{I^Qe^$4>x|;6iBNN30Umk9MYbqn4khEjbpTQ}~$9DG(^gr4KZ2MDcXE z!_V~D3=n8xi7^N=L)m6RKUu5&0D`srAR1z7fUyyDTZ-%q4TC^etjaGB!V<5(Tf?PCh62@2;Mg0{gdfK8_76%X z7=r@dHZMxq2m219O%`353*2uCF?CADSKK<~MWxXUFM5vqFuW?ZyY-Up?7WE;WBRGK z60)%jcgXzwrcWly$5^xFfzDXnSF#yDnG7&Pd=XTDJZ(4vit6@$46F9OmsKH9c@LeL ztSY&s4Ali=lnv#y6Dgdya2*f6XB;2{b+MCbTIXZk)+TyBCBu1GI*XiX3j$)aACjUY zvMceIa)g+0@@Fm|xE%7pq~jYUjWw$8Rn*mc-TU;U(nsf)))LfhoaHfo)GEAGUR+fs z0$sdn`!O$L<}M+|J6wC(!t0=QlvF8yB$<}1cuw5up6l{Tt~Om>Vv$L^1e2JN#|msdCh~S{4FI(X_x??_2%oHA@V-Y|MV!MH__0 zD##+4K*yftrA9x)3d}I{OQ3#rsJ9a7-tG12P=|bgB83#<=wjNWjYE07B94T~g6tYZ z_e2)v1=Q>X!Z`nOjh3@+7E`i-+pre0kL;?Wsp(w*EX>?E6B3>kc3E_eCVr5Au3sI` zmnkkOQtmTM;dE$IMu&>zI2^G{26JiJ-cvDNN^9q#v^1$njc%oFIH5c&= z?~Qk@3~DzLda@adU7kKMqkYKP$q})0`(^q~p=Zv1MPBpF-}}YSE4_G!V-}6|y+2?2 zS!p2KK^iHMal+jl&Cbxd{ z$|h%VzrQsop~>b>K0XctK!0hpgD_q|_Fiv3;Mx}UC7S&7dC5gVo$T?(6h6G1eFqOx zjt9zVY~;l*73nn92r+k0Qjjo5H9Nx?Hw zgDTv$->#N!w_VP_yrqGFwE%W4n3lcs90$f-GJmfjGMj|!oiS6{CCnC`l`|czljZL# zU2im#W%kNP&GSJy>1a5Qn=VY?*g+#3Dc5{pDMJNGM^SarM8kwd7ox%N$OP@NDErQM zXaymK?jbHCYfiidbx97d>028GK(*sRpw`J4XEAlC4wtqM&x!xD$Y)KCdp1*Kj%$P7 z*{Y2IupQf{9cxLzA?9$JCYnAk@VN|p{!yEOD5R|Iji_h~R%R}KCdZn041iPzMZsAY z;NcUbp$3&oJ_eZv8>I|TE+=4Uob$I9tg z&{OQb7t!<{S`;6jiymH-xBUMLH%i^e11iQJ1pgx|iyNzEdCo(}EFs$p8PJs9C{N*X zRuDHG>c!zDS;6w^?c(N1?Of)ip%8-QlC8^306jUg*7C)7Y>J9HStfXXZ7r@%8<^EEnDaLwh~<6O=H zk_rA;1!tE{3@int@OAfM)(;r%Juhbiy(E}IhA7%qGIO0sWJAQ$&hh}V)ThBc=#~UJ z<_Q!>QeK(@Kf-Cpl*-wIh@id^wGo5|o%#1ue{6TQF$|S`{+M*j8ugS^Z{`UTk_OiChQJwf-f{Yy(Bo<5oFn+vG zwkieSONiub>WhrOz^JUq_S z1bnLpg+pRy9wrLOs;g$lfkinWh@?0*brTy=DqMq9uv}r(oH4>OKH&uugydZc?$iG> zYe3nQY$_60sIxuT0L`FVwBM8nzfes1gZ>=?bS%pyoKHmj!pzBO+GI;zD;LAOt}Iqa zXI#d%0#!Oi28kpYyXw8FWCU^8F1X1 zMZ}mZy>X1FM4(G|h>ZgMX*56YMG#h5o|u=+Y{k|4?LDYR4~MbIr}d5<*9XT}6cEcf z2V$WDgwMmc@|U30MfyI@eW;~;Q=)s8=m*(RyzGW*jM>;s%+pVVkTV+m>gJNtD43GC zn!{YCnd@$m|I-g(?0Q*pWNJb@vPNEHqC-4DEpr}QHpbvohRA^IRMK#A$;u%G>;>eU zE0XIIu%;;gU7Ff779Rsw2GpLTco844K%KXZQ{q7~xDNuX!lDENw2GKjX(sk|hr7xA zjvYH)zO>+wdkrFx2G{h;qrR+fb2Qj6_7jCRCkFT!H!LbFT}}dcDeHPJ_*Wci(7;wrVc0|BZn}`)r&KYe&8h-)@nFFfA|IG=r_p>k zh&U9|YGpE&Da}A=ca9_=T|aMYR%I1&Y+M*XB-e_l#izGyj&SZfj+cZnk6BN%&?I5p z)hEyYOZs<-qTZLh+WIqMSLdN4-btBvMLtJ_sMHmm24Wo&k|e+5^s_R=TYCQ-0?X&{ z%~qj6@7Y77Chj;8y}Bvd5OFRNE15E2=AbA727^`bShD;}ZY1N$$qcH?2tM&Y8(H#+ zpxsIR^Lo(dr2a2d2R;f&#GXkpJ%`+h(aS}E{SWT7h;s6mVmy0Y;L6qs|2ubxc7Y9I z(q;dq;y0imQS4b$)PC$RnrW3ec9>Uc#D>|$KAZlgL`PEWrUbjCs1VJLC+TNUQmG+= zJj5{}k&Nc?X1v&*RHTT{|BG)iRh9KFs= zxWARMtHbsWJ-H4= zf(qO@P;N}u`kt>qhn8;K>2hkWPQuc9Oo{p7cP1l-NYk{mc{U!Iua*J7#$T2_$s-rz zNQ4D9#`mXy=d@=qx%bSKB<@f0I+hv~hIgjEdwr@+I1QIFbjVtq%}|*-@ZOCoO^A4T zty0eP7(5O@!2xR$qfs4zhk1ky(;Y;;t|%n1hrafJOXB`48Ev3cL}v-mcv=?L4p$2# zTZ#g?9|6mc$GcK#+|Q^vWH@&tMVy_%AZO&RHfY}Y70nB@_>>`tc6g3zko(J5)Q^k# zndqUJLWiLQDo%m{!HbLcDKjd70A{7V969D|D)(_??_j`%+~Jr34~z%&_!v-bp~bt;b#yV&ADXR!d3Y zB`$*f_0AeR=Zm+})+*HEtK6z6SyCLl8)H_c{iOK8^^nc9+jkUgWr*LKVHM4sLJ|-^ zS}U!}E6u5MCe?E{KR%L5JkQ$9V>h>#%b;Q~{CKGy;kvNA5<1JqqhDpf)@;64J0v&# z#v6U{%qd#w%m!O~%7(OGQFPQVC8h248MPGsho|C~-Bza&dMiy@s-0RQ-4gqejm<2H zs!z}Ie#Y@(8UT987oSbKgUNmJyuwc~gE+61Gtu>FhfESlmd~a;7kf zhGvrO#Q$7mDJ4Oh6aT+F@qY$j6A^O>+@?#EU1bWdX6m5xpAyiF1;NxLCD!>Pg@+Mn z#~H4nK4BZ5V0O)RB9g}DaEDt>7-gYF>3G^NbYE#JuEjd#I4B((n0^r-oOujLNT%zz zS=j6E-Tr;>Mmeu^*iRZxGxMhJeKvA<`C=5!vZV&jXE~mlvs_}Bt1wl_Ajior^^;Ff zV?<_kQrRa7d5F-BlbV!_##4C2vc$^KFjte5)m2bZ0!$ zsb%&Hu)=DBZv6}S7vF+|-jCbb^ixaqV|Ofn0J8N?x~2c!&3}<>_j~*T5f%%)uRF`! z#63fnfA0x4MjgWkK)7;_R47fhM!s_m`|kE09R@f8X>E#V^D*$q$9!^by8R09+}qT| zRM7mK8~eq^lRirvxEeYGxEDY&ie>hH|6gMkdR8Vv%|}@uX#!PoLhd#0jwJ-YS{a57 zr*AFET%xyX%eEv$i_L>aS=WSk%RKrd8ZB6JjXonPNvGyZXIh|j@=VzCV9y3wuSidLe22C?39`VtCar4{v7GA}4 zhflock4F|(@IcDR>?w1#(y59gq|`F`+1pQ;`OX^uZ0t^=+U+$lR`b*)MjMz8Q{Cf* z()uQH%lLErN=+E!RD1X+d)zjwBd|0#f=jnrEN0C5>>gD!hd?<_N-@&6e>X7i-~4?u^H`~S!JpVEo6QIVKqre($siOP{JrRdzGoJpwDni8wDE{QhnD|7O;fyi%z_2v(0Z5 zj?3G59*+lX)$;F)d=acKRSi(K^ex~64Sp*Mv@H@hZ(9Q@Z}d02?3S@uU=;!r>f@V) z$`IoZ&*-?sKMUIYaHSA$a0!z+7zD$|mXva&J z@^lK{+}x`}96X7zw5dSNdp*1LfX4j$DfMr)1J)L)Q)8}a7BZI{@=R8X>QRr*-23NL z=8i)>vLRkB>XGzKe)`>QdULqMaVn6flbOJe1OPH149ImIG72jph?T7F8dhY{jUyhg z_9Q|9g76u}YrnGd;z6RbEdp+r_Zu<>h_5iSQ*h#P{WXVL^abKzX@mw(rk;*Lej{NU z=LZkQ=+aYs%-O$kGDx)+qu1&XYmsf6- zC6?j{ha3rQK5=5Wy6<2eUcCDEXIzXvWZ6J_A zMwtW(s$et$cp|Q;x%DU&FXpwled2!}KZEivBLCpPG28CZ9= zjqd&VmBw1QFWT=B^?#qYxJ0^SQ7#?rtINma-pf^928%kjBznY{^hI23eHZ%>vWvIl zX!0fEs~si&AEzzV3FM6icz34WOX5mSOKuNPTdeP=(Vlmhv?g>&f9Xo^rR%cgKRW1* z_br~r#wJOxn6CU6qP}|U&jgM4hP1aF;(Hpg9Es1rlZG>0 zPa*&S&itB1da^iVxtcTDWl(!a)2ud?Y#LUTQALHwXTnUUWa;q1IN@F6XoGhF-lAwK5WuFh$2B{taBSD}DWgsBEZ29k~v+`MKQC0?qzSz}{c8z2kQ|x4XWQKe;OZNtOw> zlM!~rtWtQDIES&w&z9Pc?)7F_K-fG<%D=ymH1@n%sBesY5-DCHQ_CF{Hg3_y$>?fsL2j829uip-=cEUGX9uD@qCUP>$GoH$x#%8}sb-vW&4qre4 z%dQokW53ThrioW&I|Bd`bex1vE-;2ktz`oa2sm&Fd)PoogP=Hv81hwrWz7@+vyjDK zoN;{KO{Tv!=xcFY|70Mv6P$M?=XrJ$-N39N2BkWi1@!K@6l~RaG`K#_Mg_GDrVCzD z<9A`C9fYaIODU||YW4LBJ?4{BQg1nMm?g96NSw)p+lwa+2}HR>ymS|B-c!uKsvMBi zt>Zi;{P*#tf-Sd4I{Wy_BzX=7hrG{Y5*&Wwf|lxnd)XS_n?`4!*?cy2Q;xKRFwf*P zmxxI#=r%w_hiUtzzjuCIWNtD3ht9D0`y1=j=KSSUGbg729p369r`h(Guv*%wD-K>S zC8PKFu6Vyc>=E|Iyp0>^Uggb_0#s@aj_2rL<>3~od1n*2$ll+b%otI z=S4&FuHc$F;pAKIMY6{WXY5$M#;1R}Y@~14al{Og^dn?5l!Xt>%sWz#K;4MxKd(Hg z*|G@Ya6LE1?38AZaY1chpphFIWw+gwHk!vE6z0qma&w*^dM%qkNog4=^d@`>#2Nag zv%0cR6`C(4PUIgYP26E;Z+f83jX$7hY3?ah8+r8jy}_-20sj6Q@?zxat??2AT{A-#pZO`qM$DoADcm1HN5<6= zXFS@n_vi*P93VeeZ}NEY{wXsxsv-#E08N^lCmfBmKRZ*%{`-?g0B&%WgK3PWV((50 zJsbtP@y?Zw&PI=5>*B(MrGmuFfhvt`gO03b;ugoripuhyjCFTVIR)#-3MnbZ;)QOqd0| zjTu>N{WP#rbxB--Yk%{NV5EJ|PY)4MvmdWEhj!@uj&ihiq$BbM#}8x@E!?(OqNdR^ z7GrcBnH&h4rGwzfyAhr*ibI#&8Dk1b!>tEv&0lO1%_p3m+Xq!&Ka-@lzcS=X{N3yS zAi_^`p8o#&QJ#PWvPgPcf9meFS55`rTc$N(<1Ivg?qd=*T=bnx_xbk(sb%C8y z{NulB6{UxXI13oAuS)3q^>7IP^RM(LjWf?edp=WDm*P!FgN0t!gqJ@oqrpIs01oDI zCGx-Oy+k~bOvPo_ECwM{Ql|RM$Yb=glfmA-|4wxlq|Ks?d7=lI!hJe^0(9B@nbD{& z11cSN2o*hiZPdVwn?!>*r5jm!gbE)4rRa@j_zhC5^(}3lTJMw?%qM@3ZKRJShuJCU zS{3B-+InA~)ZQx#$@(eUmJSvUmSjFLDVwun{&OPgg8OBfyaebK9?$rY28TIa%g8>V(@Rva&e_FcNG$k*P; z_!&80dEgkb7EpTPf18u}m)ptygZiM~qvQG?2|kmeMlW%{*h*uC@IuWqkkij+2-5ia zIZ@!gnt53M`Ae^RZ&W6Z-wl0c{mui_`gTG}rSO`drIU}xC9WvvB^^RThc%jIHfiNn zd3Zr&bLfvzuGO;!N9#vldxSpOCAit;la7$W)hzanXe5TOW^g#@|e;=P!vFn{0>9 z|F8qf z*HSvrTVk!Lxw{Q z+3DHPFh~G);;I5Gx?V6^52~PO0gH4+?qMIYPo{-I=3RBu7=66NJ->OS8Q1r3W8?OlXIj3!$1G&Y?pC0x zk<6t57p>mIAG0DbUhvKi8b_)Kk@%9ve-{S(vRcwFE9Ro{-3|k;p7;@ z-KoP1DS~^d>KtWV|M+-NYQ}6w=HNo+^eN3$tGjLDMLovYoL^l&S-&oCe>)XkWL?Z1 z5+kjo61Kid6ON=Fh6p2#`dE!kiCULPkq|n-edu_40V^~pk5jDjHRlIR*`GQiUu08J zszjS}H)B|Ivy#+Ns*Zf|+np`LU&YiVq%e>-gS4aH zw{ZbE^UZ+^dSTG4PL{$Te~t_OAr*X64=UW1BwNs+V(=JK9FUxGRQ%jl(LFe)`hbzH zVqT$cb{zJ?dpHMMLMX)5(p|QO=yp2s22;QiyEZ2n9LV|9f0OWHZp&y~;P+?qmL?&5a_xdk@_r=HAn ze#LyjTm%o76HSMBSX}ucUzLt^8TinV8sGl%+9(L$cJ-lqgvuNK=U-xfD%f0o^elg_ za=306Za)Zor+@2I7)A<>whrc9^w2(UWealQtjJpqm$s;UZo3OrZrh5(kaa zB^t6*o_&UGIx~0H!UVwNt+9L^ic4f_%&-zXBCG4iVQ$qpweNv9aVeqoP>6^;4<+67Q&sqv_`7rMlZ1AD1cZGG#XW zbD8juS5hiMJU1EAVD$7wvf}gV&KzTG8ot z_fh-Ai)yJaSDhV-6B<~4r^Id^P#Z!n1V5`zFg|N3m}cy0IU4PfFt;XB75V-=$LlSn zof$eU7W~naUa%^duS%ZO4 z^EfIdr&eiMn&5n$# zz;S~I34js{OUHSm3Tb23MyK#bV>6Q|QPC7noGyM=3xgnuGg3uOLTvch(J1vA+!$># zQ*09Sf*>bLuYue;5St$b7m?$KLMq7$!0y5%2Nyx-#Q(FvN&QnWNj~m>N}TNfcP4;t z;{Z@-MfUKdq0%!0D*hF17%U#1ltrxz>b)nMAa}(=B+;K2OQFel@hCZ>M0lBmiBhWV zitaKo-qCI1`h;_ho#}re0OB=>8>pY|iyb%lLzQ#BX9+ zQd@n#OMS1Le&A;}sV!#Dw6dq<>{kfCCvVZux<_nN=oU5*A0w2e7zP|~m8i0E(hu35 zCB`=Ay;^CmK}$b!Vs}{DzO>BkUp`e*hUfZOf~#i+-zZ4Yxj*nErgSi+*MFOC|6GWj z1!Y+=Klxzy{1r*Z&!?2XhJVCK&9+=k(D>l6Wk|L!*5wJ>tS>)Rpa0UI4xx0={JLy1 zaWP?HYr0!)vn2^&i-a&AKj8v%wH0;uHXb0uJdM=EJ*#0!JU)2g1ZIC1O|u!+k037_ zSxISX0Fi{YVPjXAm%(`Te){UH@L_<4h%VEVOiVBI$3tuzZJgJe$y%lHh-3+5ru8P$ z+vsf`ghIe`vEnZYJ*UJJCdW`+xE9`7ukgV zDjskiJ}%8v?BTk~c`ml&*(J&3SlT577psNQ`>IWzO;PI7;Q5Kd!>qZr+X7X3cF{q1yfQwA zsJwoNIx@LG)1dj}Kg$o_&6}wDBfeND^v&$(Qh@`ot;O}`zj5Qi6ZOC6o?MNle;6h> zzJD?Ev=@1pCnF#~#)6@CQjp;#CdUsJs|V866yr|)lU4s z3rIT&+HxM(|4k>)zhoS5<}ourf#lji;j}SD7xalFT20GH8~3w4#|tV<)ihLf(pS61 z5oC@A2H)RCysc552hTaAk)SM}SGQ?FoPGzn`g+;1mPPpOo3l@d_gHQy>7jiMybhaf zKsW2~PrXywVtemhR(rBFzDTc{T(C@D8rtQf_ArCG*ap#wy|8U~0d`;tp}ZKjZirLq zc8NoLHn4Gcb1?;Lt9_?Bm}i)YzQy~-^6bk+yFk%}mtMSgx&z|wQFSq_U@p^_e>zk} zwQeczvY~;737@BXF}wWu43uJ!P1h2^WNndriu+_F0h^hyC-M zt3>i}a^@UxCPbVTl^9H#KQteh(|$r1iNqmUfG&zDKW@e+V;$2O$Y!p(Y zPHZk~M3=hE9&{j#&*qmB={au{+R=(fOQlpDVDxo1Tx)wl-toSz^gVp(HGKD$>Tgz`Qe_m}A`3ktLL0cdyiD zb3gFenaZV)k`nDbc7l&*)_%}g-j;i140+&%wehmEP^@cdX!Hy#?(rXVyeVxt)A#c0 z{pq`}kbBa3dB5fe1*^t|9jRfN+845~w(p$sJ@O2)%L()8YY^MM<7K1pYOTKGqj2GW z>wQPrppi3Qy&l;_UyN8e8yHu*R9ySbBc&DS6_rIoAnI}v+hK~FIot~4A5h+3r#Q(? zZHR)}1U*h?l{KJ$JkC^!o{#RDTs7fUN|Ugx!551nYGAIau{Rr=p^H<^;j7iFO-N?t z5+E9AVlqtB%&JqkublY*Em>yyc>ZuiRBC@?GcICot+fv=HyV?0u2P#2w%j7* zRF|jRe=#^uG758E%<8y2m3qUlu(@F1fv#`l`|EiYfi@4K3-?`zcoTx{`Gh;_uFNjR zbCjdKj2a4L_4HSLQ?Si5%AT3o&%M)=^A}3u6jlo+X1?}IDpG&^;gXiE9#qWUN0aei zNVww)x=XuB#x3nni-y|>YtC_h9H|=rOGzH-hM~hksqKaV%@Z8+$Qcjfp?a0KB}UFo zhe{I!0gzFgmd*KG*UQw%q{;5@yG)?*s_Q;@8`n`XvXRGM2r{KZHMH&-1syIUMfoOV z@WExMIAUSQVIBaHjnp+!Gh$a8;_unM;g~zy5oS?mf>u-S4v>IbPYT|1=_q4`hz9 ziaq}?<80pZXcCFBzIsn{W`5uhD;0jJ_hfVkl;|*J!es~KdvTDN-Hf1c)1SytIkCpk zNU$2m3<~v|hl>-=%qqsIF3es^4|ZZykYdusjrn%?_mwH3AcBd}p$G-vz61jrO^ev$Ie)V%UDv-KuHmn|rh{LGdZk8lqZ zRq&lwi_e3H11tqLo9qzP;;~7zQme!$RrK#z*U_VZiS7a#+0Wx}4q7z2vt%~1qRhGg z2L)M2;>^mX5nf0!YOA=i>W^z$ovB#T__E|C&4Q%ih2$ozJ|wEd%lhD5Vz#~Mt% z>dMwN&ku5>vnf=j<`oUL3Rz`%rUtj5Vl7gzrU+^WQ_t|#N{HA>)d)(nxXO-a* z`Wg4~bz6U$#fX4^?KdBI11kCa{bH&e*F%MlZLrJEErD8Ax!==IHNHC6DO(MEdZ#^I z(QNTw@9BHUWk<+U?b{a%IsLc|^*%@{*2tXFeUXs;s2H)Xw^65D@HfsWKe!IPhH`?+2BtI`EMXIAXe6@!}qu~mh+HOl}A-?yZd zYXwuZ8gUMKoWWz~{{{W~cj(%PZIzO$FWQ^FT#W2kt$B3i;zRAzFf7gu0WFA$cc`Ej z9p&IqTOOU&%l;CgS;xr;QmP1_uc5_46u7A5&27fX1Kb#0e3i8rXN-!cKml2+ch`of zMs)#6tJT{-=;BH?AFu!k4b~M1_Re?&;pV?&2$4tG&{P7#xM1i0Xg!8|>n@Q|JCGPm z-gh860bh|(s2Ho8t0mvuCl>{BHU4mjo$+fDUcfq|YWUYvx{q92fQ`3F$My`^1g@o;RhL>P~C^97#9%HzyK%d87XD1i5V>C}C$LgkM4GKvDNRz24 zB87B)UKPF1XK9McpGF902S0XryQv^-{?+nxiq1HB*87iJ(ukyfEK8NX!B`@{Zf<*% zMM+3?R<$k*A@_ulut>&F$X!&Zc4WEzOI7%_zr{Z=J%7r zTCk^K`g^Nzzhtkp_g<%-RO|4ap4^@p$28YH|0O0aLrey47LUY%Z~=MiNp&uB>PoIr zG{wuwmd+gk>X-rfqiwE(Knng8vHz3Xu_t!*5ryFaPkaFs(C;v<9KA`C5u3Kyx@ zA>V3ST+tKRzQQ`-v-a+sS=HC`0(Y{{GcCEQ|JI(FWaLaSKaU-Mz?*+F^KC6{xR2(v zjynAX0rD2smwEIu@#B{JScMkvVl>INabia_BpuA!JWz|d9ej2(8 z=<%OQKXxaTWl}A)Wmn@A&x6k&HZ8xO*94Hv5c2UqV!&iSV?7GC3GC1eT^(v&_p>xS zM#3c73{0PJnPx8{&Y4O7-T+m(Y>i4kKl=e>5V;#@E=sFyvf-y|GYW`NAZ%V#tN=Qf zn!8(xSjkhlg=!2w+W z6wQToO+xjc+Y2T_@z^ZRRGvZ_rgSKmGohD|)pv3j7=e;|%UBYMWpzYifOZxoS!OMm%PGbV|7DgIeE%%cM{A5G(S^C>l6yO~zpV^^YE>XE|8i4n z$c;^tl^`@W=;!qb{l$~w{nwUnkFR9ud#sZds#Xp%{ksdLFjtWa-Sa9*&%Ph>4sTk= zAyRY@{Pa*dbmv$K*FM`lQrx$6=JaEGQ@q{)5P=2&z!LIQNxOLP%2uS#+4IU=jThBZ zvIL5Qx><^dRhV2+Eq?GJ2?#B(s#rGjq2MXZ*KB4Rr5JO}B{lKX#&-m?FDVjART~~W zg-gopgA;n_D;;2F(o{YrdkHs1ErV2TJk!R}->>@1$GGk(aT7w*p_db&r8U;xuyB~Sm8nVTUvk{ z$yc$|#P->c)(pj^W5pQEe&_!#g)SLc{;q#Sb?N;N6u^^N2`+<%wY*rhzqc-i>L$KW!vua~UC*NKB? zrq<+2-Ak{D`TuC<3wSrG9gw{&Tcf{f(stBG`eSIdQSqUf>Cvbc?!#p#%jnfyWM%Y{JY zS1Bj$c|il~=iP(84#}UVkG9hPelxCgz%X5mhTzCAiq(bjP26`;m@gfSH5TL`;^TCV zQU@u7$IcO9nFPiX>=4;9sxEz&XaRkP^m-bFYwVAXA@cPPiBpnho8k`_!C+ui7L9~RjyS^#xP~E)qD#t`^;Urz zjAlGz)yE3c)-NC|}8$`bLu!WYh&w|vzme@YK(Dy7T#DfN&B zQM6{pN?E=66Y;0CYRz?{xt^kjjCOh9k33)Pu$kvX$a|X`${j}DcCFctt8T70svy5^ zVZ494*vG9IT`7`*b(OZOmD@0Cd)H&wca01 z^9GzP^f5IlV$J_iqn^JTU_N}wHag3ge4G2!;+%C(%?8cc4ax|jI{*ZLh3pf|?BlXm ze|a)-oObzxF@6y0NAz;8I3D2KDzQd(n%vYzbf2THy<7Dfk*y=)-!JdDC_3+0VF6jjxc+>yevx(IcV z%%z*w%9D<}LZ7akmEC^~IeNTlj^md*d+l0RdHqh0lbcW3!Y%8>L-i7kJI72syvNB1 zf!PA>tIOs8h}frNg$f_v8H*LeY0~fjV5HH5T|1TRr97(!!6bG{vVr7ZL8!nXav;Ifo-A0rU}DlhFU0+UoF&$0WMh`&r-JzWz?yE2Vz3R8;U6V zvLs7Kd%8!u;qf3oR2qQ-x5~ym8h6r-xL^4!U$s2AY1#TYPM535(QFMtAH#_Y( zpM|@$c3WXJH1a5C1Z-#`<4hCIL;nV`vrQZGKX8J@7|K0jX!anNb-b1}s zB^1bYIIx_bw?tOX5+-c7TX(8mD`v8dOS(>15a9Au`|E9nSzHlMxcALXErdd!$7DV) z;!d+8ztrE@AK)nnJ#)79bimn>zjE}x#g*JH`-_Vbf%kKLc0*j=S{Prjm45Z|;GpUa z7z2+`o98av$Q7x+g<|uysFB(j>+gpS0`yrIqtfH2Q4pmc7>T^g-i6Wp=pjA~qn3N5 z{v1Rt0LjV1Uf2lOA{0XSb?vd%9nIQ$-VNl)`bm-t7bDO!6uDvUrv7jLC;k3U_*4HB z{;q%M`5!XR4WW|*+bZQOQDHQD0hm&(t21*3!VO)VuI@ab0@fnkq;QPR(3CYBa{$M= zg*(=@_Q#uf1dHB9-%PFhyd2WPRP-Ngz&CBd(qysSbTnn*M<*>_(zfN8gIrCgoALXu z6T3itsz%Hc*M#zd;Ayo&r~2eY_kdmP08}SV%q(1zUtfN@N7(h<^xVizFSe31i4W=& znSyVAo^QVNkwH^|*X(r;VO$Y(UbvF)#W}|d`#&<3=R~t^KI(cO8)dNBW}j9S`hNPQ z$hiW>&&%J#3e}>T&_ON-$^Ps4Msbxz;kUsTcVN(?tdE$kZQl$(e1QHnh2S%M0;TMI z*OP7tRi2~GyKYNHNYmvWGTn&G%I`;=h7D@)ZnvcH$MZGhq#WX#!ZmNl)?^tbM2Hi* zlY$u)w3o}ZA?8(=t|G3vBEFN?IX|3*sX95pI5}LR8hMnJh&tg-|wtmsJ zC6pomx$RE>oYLP`&re;dyNbCBVE5OPxkf^;aKRK6$+X)ZFaLo5t5-;TYU*XaHH%evT1{>f>NA8sxu;!%GxMK9$i@o z&_tJ#BNbt(;K);6HHOh=%=mq}t>bekRcH)Pgsr=_#T?BY_;>z&6FAcRNB{Ti_bsK@ z|9oJ#YJKBZL$iwJGHaMt%Q0_Lkyr*6PHX*7*x*bWF6MMCLastw;8mqe3_(~$)&tQd zaKC=y*^XE8u0d$7@5(d%eDHZAIG#OhRNwRMYH33ogUOxm z_>Q~t4@e)sAI>y>agy=*)$NyR(kj9M6I@-G=mCW=kpvsCI8#6QYo)a@$l%D`xf3KU zCEkjwt_KPI4_`s2OqkHqpntM@-f=6p2edXou3q~S{JBH9Igg1AW@=WDJ1=UgYs43c zQECHI&;a;T0UNc7xxphwC+YjdqqyWReiNs9mNqmj17dn1u4ryZ2IOQEp0L(;#4w$6 zm>AT*Vj6WbDORy}Y}qni_z|<4tQNu`vzdwawA-pAO5eyi7QF-mWeSVI@?0Wkb>VsS zT#9_c7y}WO;HY?(>zs&WBR@1)kvaE>8PJv>>y^nl9?&cDsDl9EKr*LE02KZ=r1R%6 zfSZGfJl7j7b?^F_BJE{Lkn-NCy)ny?PN}JRg0Q%<-sFT|8!lhbw%oz1z;NqLF)Js2 zMzhm^)qD8NClT%2GUk_RnnRQ}Qf?KmYh6D(N*>o1_`<=4w#+Mblq!`Z%ZgJm-|yC) z?Y%4~ez*H+dZTh>P=lreBzNf4n!qWNR0OtQ4DWIW{vGk`e24DbEJSb#%&quo;J;UFutD3_( zQIy#xMLf4YY^0JgvHLL`VQ+O9T^!5l5&}%S3YfG3E+%N)5r^dTj%L=a9d+&r z^n=k7O67M!CpX??G7zW?TKxov{8=l;CkA{Uu>2|2w%ROVmX_O34KLPtYni2e*DH@o zlI8ql^_I0{_VoT-exP(C_IZ4vrtfjVbJh-amPS%Xyp+!pVFSppUu0r=MvK7CESq{# zKFgVQ)VHr0EzH`Dbse>;3CAZpR(n6=F7$%(!vvzitN6O+n5<*LM(RG}^L{ugXwPd_T?@2I>bQx{WWQFb2`CEG z1%5^?;bMe}rtw(Jm4fv1b3b7vPA+>2fRwgyyUEA%$V;&>e!y^W5JTxMkE*I0`K6!O2E9U-C(ADYlvXQWfiK_b_>meob0;$c@R|>?Y zujW6#V^*i+b1RLFA}WLMd-b}ad^fVsJibI3IqD8RznuhlP*--vZnyMK7_0>8Pm zIz#OpckP;#ZxP3sYo0Hp_lK@aS1XSRlpSxc$WA2ssyu4}g_Vr6y+1uJG8lK*I%&22 zvA{iXHyn7s+*&+M{7iuFDPO-%>Qj%2?4OV070!F?b_Lliu14_vh$+4H2ik96&ga!C z#o$!8R=UzRUuQQLj6cE*J6=Bk{!&r46K_2QrkZjoYubx!=%{O^4clc*s$te>mI9Zt?nHL0!!AJJVh+w~{EgD6fPXDOS(MWBd%Bq2yVbmN(ysm>`rRs7?d>Qet22Oj^pHwH{WJ47 zCy4hA(W&$mt0{ieG8+CdqkWLO$9+Zj9SI~FW(mTfriTBzGGHn+h|0{S!K%d%x2?iZ z_-QnCWVdu9o`DlSh?1Mnfnk+t00zCSTEZrQcT9_kj*3K~6TwcE$z&pmTN8^`WJ`=> z)Qmo92+f2Dauz~#((O-Ypeby!w%QuXyc{-77#MBxD(gtDH_uew_*xW6AEU*)V4$beWJ}Dh{^uxnV^lw;IeeWDy-}jXN7?`B^aDVlJkVo#^dR=^(YElL0d=b;@ zdsi0^9l+~kiUg0z9O-bL4qr)PTXqZL4eIRvkKU`f(}vYuB!^dPN)pZeFKzE4m%Hj! zs6dAA?@f|7D>$U<2i*z_Vzu}FZM`}J^8|bRZoSe*ybBKcZ(6T<5tmygTvT=O6s5cl%> zDb7@>7uRk+J;QhHaD2}2QtO^^g@;HWd||&}{Hn=c%zr9tLU(vI{y8QTC-Q}FfqEjH z>Ad8@dAuo{@j-q*-qaxtZM2@_NwPP{1Rc6MK z?CA^+V<>s84xrSfWa93f#6quh_fj+T2&fm?6X72RM*?rEM${5nF2=@E@iN^s=qb`E zehHWc|DBU}N8B6+1JdOtS&dV9phe8j(qC7@cw-b^h*Dlv2cYwUm6QuhJYFrz6#+}w zql}mqPHpb&=OcjH_EMG8jCZzpB+N0o-Wf5XIb^vwq?_w(KY5i@&x~EK2>vx-HVq+rHpwd2WR0b?n;rJ{ed`D(7c?DXXO*ntc%z;_IPnMW zpY6^y(5G|3nHAD69@tnk+%!y?upWJrKl)dpcp`fxL&o=4xluqb*A#l}aOF9`VH|X+ zb_)XF0jG*bYLT4A)^M+ZsFM=V^H4_cO^6PkNItA*T&GkN2co2jQ*MKe5u|>IB!`+S zdn73steR#Zi;BrimGQt5J1@=9>dqBc`;q>ge}7L=G#4}H`|W@A``Xa!e+hgs*&CK3 z&CG|0zB`Rdh5RuC7$Fia$rU=RSiUiRkC4<`E@6^jh^+`BU@ECp%N^$&^Q*UT!1F#` zx+zeIjU1x)S>2bN{NFL}|oHVCVJy=zv{!x`js@%*enj_QX8>>taeqlz@o9%TAI z_X9^am8acqwTe!UN7XZQ9eG|oOF0Ps{BKoGy(9LR{%XcEsK$ZXhoxpXFSE z3dEK6{$`X1K`4s0ZpP6N=>k@uf@x_uZLRV0!z+q=c_MTlK!r83e4GQ=Top-bY*Dik zJ=v0gz+$v1|A!Kc!);^C;SQ`vKnW~VV_7mwRYZnLiHDBZ2qc?uB^E-6jm3!YXU^dv zZd|xCB_LmucNR#W3m}%49BV#&0JhoZd8ZM62C&<>f3h-E2<3T8M<)kgTW}DbU7eah zp0gcpwo10fHs6T(&S9PPo;VW8f{eri1{@SV$Z`NXyA+hj-al-@j$K-heawFM;?hGT zYXjdNw~AupG9j?9XH4gjBWRz>BaGGV^`wG1+GBu9VkA#T+gi0sbic^&`~NlYSN}=< zGyh9c16xz|@##sWq|~~4mN-J7ZlpUFWyI2Zh;xgBGf!ceBDzJon<;+ZF<{F3j-gA- zq*Ym^#o!INyC=48A<*kJs6=!7s{|?Q!zkjlw_n@I*Ou$`y^0T<*2CME*DLPkHNT`d z@{D|LiLr^WDJdE%jQg25fWovTEC$(|2<+@l_Ta?uu4WaMORb+)uLSAe7<{HR9_ZsY zD0pF+E$@r(ErImKZO5;yVS*Q(O^(B<YbUV9+k6U{PDvvm9ySdL%DP z{*qW~WCA2;C{9cZXT|d~3#ciG#<6|ZN!-J-@bmLqL0@(ysR%vcW=&l_R5$fmS^3BvbUH_bJs58-X5;*do6Ff41Q(Uod?2F%3B37jtNCqp@0Oc4I`2^L&;{PhT6r}? zyVX||@ntTaVwb2br>Oyoec7NvOWEYPd?)z(muBAPHI4cfs+C!78*$l}+$|)4>Eefa z$!f3WyV^Fl8|nm)myh-;|G4v5fO^le=V2JlbMnan%=-(D*R<-{s_&0pAupW2&3%5M zYp8u$R^}l51k~$P`vz+L>EiThgXxAlw(wQsE7`TS07RSIjSvR_&kCIadnIe3h{LX6 z**WS_Dd4q!8Kd{ne#^+-aRYKF7imu)?qvXsSQqI^Dr`kxQZaUUE~g+Op+%aS2*ldq ztc8B({|=x4{-b{y_WQn7q1Qjf)qn!V`!4kO15WVqGNf5Z=LZm3Dl@6d*tsfq(tV`t ztxS%dC$Z{^yLw9dSVW#o`CgN~*w##rmh)=Bd-pbW#l(bj-|oJ8@{w@G!5c1Z0dK>K zaxN}yY>gG34}30gQi3VubXW4#U8jZ9*GHdMt=4kIYo>o|h^j;fy^Q02PQ7=r_vNsz z4@-G?rK{ZTZs>k)L{R7r78JYAA^qiT-+Ih*&@s`OW0*EEztZJ6*w0o;IaTPI9_-5TcZm*dUrw zqlzB`xDVf`EQx)q!vX*ReX%@91AZiegsKI5qa zA>b3Zb}n^h!~)Y%K6NY%KXk|pGd!7B@&lz;;IV!9d}3ALf%i}|lexuj?umCdof7x*&oV=HCLwdG(KU3rbA zn0Oh-A|Nj~f3Aq;#hPko8+aQTNsz_dlO7@>COPE5wcj9h*O@wYd<8^VOgD~faXPb# z*cnDVagg^Mx;;bIDWO*A*kC{wLkm3C`O0yzNRv+%>D}D1o!o*zP3jX)Q33Oc!A<1~ ztPwEr^rxus#`U))x?Rj-Gxh-^CevQB{?~)_Eq>t>+hNMslX$d|qe z2@0x}5%fJ0Zf`hy`)}@Z+NR37@0rc|T8D9wPoJ$>G8xunkKlR-5$AM6(1!<^=~6>W z-P*Zm-@U#_9V8Ki5MWNaxtRv)GS`6s!ttmS%EYC*OBd$dVYl}=f`*8`1C^gb-WpP6!ZM+j-1 zc{7*vQ2p3S-4n$dQ~Qr`<;LS<7rjC6nG}Udnu|iK2g{=_!RfI~V8*;in6OFPy7J z&J00$(FxsC4@bU-ITkz=%4a(B(K@qDVzf&15Y@n;E%sXCUtC|a_*W9HkCj0ETCPVI zHF~lQVU*q-IRL#qvwm&*(HF~bxAF98x0trm_T~DoEi2ewJS7@2eo-KlW-u#cFgyh* zL(uP-aoSUNX z?JhK_=5@RQ)KRZ4m}H3NF)j1y>m!EeDk~0A-|tQp!|fSX0E-j+a0vRYD%btV4>z8#k1t zuECpTd3^fO4thy1(1V6W$|ct=STFPX@njf#2PkB#63Jgi3tLW6?~#931^J!g2!a zphzw_0Nb$ctphX)$;)$mr=3M7BLFa_@q>Z1HH?7LwSUjZTD+MwzyJ+gs^cHwxdBD` zQRYN zX4NNW?VghH!&cwOI?@yz%PBO_h`Q(^pTRDji1oTT;FbssNANI~B)-wItPwiP0~s}7 zIBB7$HB$01BTEl!+buDV6WC}-@9&AzRR&E=ksG1+skaold}wR+`i`RSwW?TXre6SE z#`GA<1HGRGgzYd}LvwtqwV{wcyLf^{g~oU5W0{~_ePQtg^YY-Gm~jq+R=utPgoARu z9F49DNV)pl7-<}_X8ase{9?pNYnPeF_4dpi%j&A!Z^M_LP5V`lvJ~%DG-b|GvXAxW zMe+NdtZhSCRE(7bxVCRJOR>ZsApc!DUFmkUQ&W2!efMa5?NMuuf{>lV8ud5-#DA4} zS!QW8T( zQuKBDg$3o&x6&?cncv-Rej3LO)6}j?ygX)lt=+TuVlxl!v8 zDM#S+zi%2NFrarr?cKFMvF}|$57PC>!w?R=qf7+S<$(Cc%|odG<5%3sOqT?6W={0^ z8k2Ec36hPVpn&V^ZedVJYGy!)4CU*~f>DAfES2%HY8)F{NylI@PT^}GDDN{d%>jz- zaT_4E#-1h@urjf~aDA2tQRz);0iiuEZ=X*FW?-my{O|pQzY!yR;k)UM_r1-4lxv)l_*v7Xq+BuS(ZpxU@v`VG1 zil%+X^q?0ypVOpE6DF-(j50x=iMiiOI|g6XGCTyeOSRX03@^kJ%a=)2>20m{rWOey zB^30~w-P_O&FVf^AEZf9s!5}|;=AEwQ^h=^8_paam**Gfx-^>yH*GW1#?7`FjA>@u zvEx^w&2G&*NK`sKKg|})0J);n!s*$X;M8BoUZNCK0 zo76Lv-X4|4F{-I|G?I*zXDoceZay$72g@;^&-f*EsI!hmN5brh#?Aei;~$gx&4y#X zh8Ee_;iNwnxP5c#kcBv&BjQY5_TbGd78AsoQPQWexo58$#I$GBD(|(ZSUrR`eS^vf z2487W<$LC3>>S+{-0)Obll@BJ!rk3%tND!EP9bvbnVhP%SDLi*%VU?HvZsw^J(#_5 zrE|(~_jj9r#xfg^Fi#+_h9MHRM+{? zkLf-8#iqzrm(?ly)-X7j-e3-HTHC@o&h8k;8E_ zyF4;0;&@DJuF-{eHOPm3KymZ(c#hOFlMRz~;BPx=xqkERBY|i2AKd=VT<@jr$Q^Z;*ly)f zeb`Yd^$%Ka!AIcu_`!kv#4f3taT%81<~94Qq1G{*m7p-1S}em_k@&sX9)h=|NNPvc%NSXk5iyPzfaC@{on4{rEJ4vX*d`k zy)!9&=Sv^6X>T`DEm4fDJ8TTf7{AFZYN9|Zqa`p*i$+*#wxT6;IhGuIZDOKGXX{Sy=z&Fl)PomvThnSTN&iCMI8qBQBR)xlD_ac? zu9<4zq_#1pN&1@UxgFrXKPpWAWGTvLT`n-K>-U!7S#x>(1EbErr=nEi(?8Ge2TWw1 z#}5jx3pTvIcim5}4bTJVkbw$QNS){*wGbeZok_%2wULWHg}RGVYD6qY7I0{z!iES# zwsrNX7%40yHPLJ>UF&IQD{+O%<6$&dfnO2tj$bDd?1nxLGQ&Fz2Ue6@PltK+27q&I zIoBkEk6^g(K(x2H|B|da8(o^u0J-YR#9Qs4lOtf$eQ(3BG4SAw7t$T(SywT8YJJZB zjCX2{@6T|W)4i)0cv^i|vbE?POpT|6S#9kd?+Yi4OLTh!ZSMUib~RIVCOhE0*6Zwo znSGB#?iry$s(ehEX(YAt@Q8 zDLsF_P#=)hT7FjI#)aO}X$imV0*qYE%B=L!znXL8*5PM7(fh|zjo0Q?gfFius$C8J zi|+U244ae@iTu{k7FA=;4!%34M;*>~1N4Gl53Xj|jf;;3AR7W1;u(id;Z_?}g5u>s z5n~2h;Re!m91s`rQgCqYo8rec_}9SM)T6sLg6nMqT{s=I6JW=1?X=5`|VOO=o* zM&MbL-64h=9^mOD_lCB=rC?UoXxSObERZGhKLC~sWg44sD_{CzkgQc<9i|#>FM~-b zW#Sx=nijfJD?9>>i5;T8CbXInC3x3Klxt~fh;hY?)~~n zck`gRhuYvgsW>#Co2?WG^ptg5;dZmFdFzhOEOow3!z&`1 zT&fmxW;Z!NZpGvylh-^Z!q2Gj6{kdAAhA&zQHNa(IrKC~kODD0Tg5-}n*H-+1 z#f2*`?o=d8W(-zhL+CRD`{_=`r>fu@g@~23Vsp!#&i7`y3V}UF;iMN`M+!0|&p!Bb z06z^MJ}GsNmE!qGc5Tc22y1SZ%xI})I5?fxz32vaX~bjkagOnZ%1pzzcIHes@FmpW z-Y=a58>n@*0aeWtbzV>L$(KtlVFBWtA(C-NsMTHv2dof}Vj1#c z8iN^OrCaz{b2T#W>?WGVo`=2juA2}nl{GZzp8B2tJHU}gf9Ai)fAoLplF^9Xc3s{C z+4PvA#+9r*DlWZo+JDSX96G=uWoH8k4XG-vYo~AWXrnpgcAwd6EhV)zcOVrHd6Gn9 z9!d2Y8*`qi<%qK^F>h#Sg5{q*?sLQ2=egI1S(`ZCvMeVX#|h3)A&XxMRKpAZ@fnZs z(2)t-O)^pVhb{o^-9_}52bxsVKZi24dNXLX4|P2H@}zwHxZ|-SmxQp#uFPG&)tcvP zo3hlq=}?4`D5?+YG%iw$a;%$Jid)}`KE{dqzRq|&=#E5U!2#a?yfzBpkJoy?Q8zE! z6BycYtY+nx*?$-TD|SB9{wxdm^Ge}Mn+-D_`ipg{;&2G+H`;f_+AOVbkk{t9hIgEo z>>_dp^VoC!Gtc2VQ-(a4pe&;BMzDlTWI+W;ub^?`gnAQ_FLeQ?a3MY+&l}#ssI}Il zpGp>UW3)fuU^ng0M8R^WBnUyAjkG=kFImVl;7H*6VC-68T7$Ncr7VQeJD$w}1s41f zO>2x+%apYOhO~?03zaxqbSac>jLsu>Mm9r6?&~OIn?*e*XT&MPL{1))bDVFaq)w8l zX0Tq-^>ytJ^S8`sY#6U#GLM*npjA_pw#*XF`i-v9#AFz5o4z*}zQ{}^W=H(ulx>Ym zXaN;VKO(Z0gAlJ!BJRz~Z!S)VK4`aQ&J#)K&fxLZ?VHM0SSJ^^V-46cN~K%jky-2v z#t*24A=Z4)XoS1GA>3CoEve-J@0##}hxynpwrm{*W?$^zg)=Z~VB( zP*RZ`f4VW#)zye6f92$)BT zpFrF@H8p-JhsFQc%$VKfW1|vR|KG$wyHC`2!$0x4Uq{DexnQnSj@@i%2KbhGyJ`9N z$dwdBtUZ$R(1Zs2}825^2^xqh-mnE=`}D& zIT)G8uAxk8oj1%ltl#!9mGg7E?wrZp*XbVIH zPJwH$C30zD`t|U-#j=d(5;u_`v<`vZ_@BfM!D-_Y%Sn<$sYn{6MnHy}Ikmbkk_b+& zO+MWoGDnP+#z8(K7@au4s_Wep1Yhxznu5wwKU23C!=0$)MM%90*bD+DN`C)BOd0`<{iS z3%-L_Zi6ZGhi|U)&R-Uw?EqJWUuh)p%bUAIlsvA`PGV8Qh2qYCy)G4Rue6Epf%kFx zq2rS#g2q{|y5ycP`tdl;N7O8Bt|yC$pl_}NjRuPVtfjy6|1ITT|BJ5wfBRGaPw*wW zu%9u2Wx`roKg*_H5+x&)?hu#7Cv|I3xjiHu9n)nuKUkg=Suw0-8Dm(XjLhV~hr3Xs zBhf)=rlL));QyWrSSnfILsXr8Ljz}z`AK7Z0VHlbtgdHj~edmdUd=Cu#D?&hEHuTIx7;gM(^>6y}SujHboOV*Z6 zN4IT`0o)`s3!MNYJZecB;l=PlQ6*#;W$7GulrIQ3xfH$1a-9AWEvY7?NL*peff17l zHpq_{ySFXu`}~6?n zAH|$zP|T2MqjJ-S`!8%f-ak~>i&3BoMKAiE4t}FJay~|Nn)YzRj6v1zVehFqrPwu2 zzAwB72rn2}fAHSCEPYJTW7xY{`&omWdFlCs*cbVTpT%CL7W0t%CK+a%kCepXHXRBa z6|lTZ1JHazoSkq7b5d9GX6kHg52{4H1f0t`2h$o%i>-~2?OW0;+h6y=6tSR=*aiEfre2xl!gtIhm({x4Hx z+W)Qpq1?JYI&}Vv*PiBT9ir$>Z1|zQTAt9&7=vJ!?zn2z;WX}(*^Q0Zi^U{9g_3Gy z9x**qrXIz}q+`7ACBiI)ayL9OR}Bp9aG597=obN_Rc$FjfJUVDIcZjlh$a86D%rR= zy1uCLo-Fr{0w2C8?*2d9FJZP+Zyh5Xy*ViBIKbs2ff%-q3kIJs5LjIa{M- z+%}rktEr$LHLO&TX||Kys4BhIY)(TxbDcNMGYY@I?dXkq!8-*uiR~?AZd3c-;*Jc< zIDe++#2?^)qJ(({EOQ}O0(zv;C8jRb6WEraat`;ua>UNrAWrfi%izZO0v6@j4F4)k ze?6-*EDwO-3hmDY?QtB}WVC%4sQm@8=gc&WP%A{uF^j??6*!+k|_^n^+$TKDE)e*SU=5+(?SzMs6lVqIouWtg=e(F(cx0xw&q{_jT^`Fe$ohkiV92$a5@Aub8DgtYzd`=JBsM zbtTU%`Ryl+LCs@FP~2Xlx&BW={r|%XX#2wU^x2K7nJX z2ps2!HDBj@Tq#|7EctSjbm6qmBdaZkKFQdUN66i_hv&0q^DnO>E?p?}`n+(f)ACWs za}|OBEo^Dd@!^Oe(@AH!oTJyTR~}^a?b{B1&$nefX_u?eJL!DH8%kI84nnVgJ~cNs zj9SD*wSGN@y34!3bOu4MG${~(YpLG{i4i=VE+MJP5UnuVxB!^sX?e$~WtxLeBfzdJ zWT_yo+!w)>xp1ltOp{O}8&gr(CFH07MLLY8HQL}0Ly3fyB6-hf0isnP7mj!bju^%h z#3lshGl3BC2lA6ufA^n2m34hA==m=~;s=;O zS$WdQrjXaz$Z4jG-!mQ;jTlqo6S)naA{fJlj_el(d(%@^K<0rSk|G#syu+v|LO{{l-;S zacnI-F71(UjOK2HRpvLgQSORl0jJFVi*^u#u{*Z=z8KNDYP_n~Uwu0Zc6OQhuiCI3 zrJUiOjpDwTb-Rc8ZkB=zaRd8IWm9P0NGF<^FW!*tPcb65vb2tsD;CWWY*&4RCX&c z3m7LQLuJTBQ<+YPU}Z(v#aX%O6t~L76W(7pi57JWD7KAAPgxqab*sDBU0zeSd?CwnPm?p7{!4$;&|7^X(6^xzNnKdl_Zlsp@vSVJwoJ~q10#=EE+5}baVQU6c)pMQ?b z_+3`?_-u zk1b*cn}o{|eu`B)OZ&ZpGaq4zN*j;f49qWPAJynDOYymG!0!mYPE_@MC7OJ7WKD6i zExNO=LAtMFY!mfU`bSDv+NL$LPoRaTPv`t4=MMGD*4|Ekfc>>Rp=eieHqrdL%K6&k z?~Ee9}?s0*NYwyo}S+cmp zBlwJWC)Nyl%D<(j`9jU1a5-bi;vcnw^F#X>HGBkZ}k2LqOOn4(MEu55N(aeq1u=k8nOt9%~mX; z7!2HH>n`R@eZRgqrOd%uj|>a6Dxo|I0%AT;dhuI=ZtC>+kzt8gZImvw;mI;^*{@9& zS;xF5SJrFsAcjm2f~`+RJr7k$ zPGgk($h*gki%G33>)w^iQCf4@!HG=%|FK?z^DU6#fS2#Dv_rusKTnD}M*pwOmcM@Q zF0-rwkK#A%PFt;3e53r)*+7Z4qBwl~7ciW@5o;TFDYJ+5TNSKw>;Iwby~El5zyIMZ z5fKDI%tnj`LCm762|>)p4pogkiqfKVCd3}KcUyaFt)g_;HCwwy`);ikUFe>lU)r~R zfA{zLjr+b|{~nj?a?Wv{kLNj$=i}TmOM)^hElHCDy{2Bkr5E~Dyl!fcaukS=jb&fK znAEBiuA_FypJMC-pbJh2WYoKyD?mLcEd?YHK`%ngwF}gS0#6+heeRbJLA=e5nbtba74 z)bA4U+PgaFJ^1F;I&O;K77IfH&re%g3jzcEz2{&@)}u43>d{_x+8uYa(GHa{fe&sY zayu)l%$)^~)S_U?yKUS-0@Eh7uj{`=N8W9)$!|N*Jm)jHDtWg?X3J{BwfO~~x1n@S zfXy9ElLy;}>J@24AL_5|{fErx$v0SKRQ2$1nR+4I-`b46U3&bfZ|V4+*^$eYi1X{bEfE6XeCuE~_Q}v00_VJuh{QjbO%mU zYo!DFhC!U+B%{*jaAO{PpT%MS?+|Wofe@o;MuwF6z;Szzh9YH2?&q<_+PUTiv7=hV zFEzHU&2!#<@Jjp%^#fYVu7vOTWjUn;u-1`pH#B2&&72Mi+IKyu*Qkj~Fk5)b{dqQm z*YA|D_q=M-)3Zk-xn7b?=B9hsS zo@b#0)#nT4MmAcR`cE&s>3TEW=cb@xnsj&?x|}uPyivlQvn(}!5Q0V1U-sKk&sUj> zUkTfD<VK`!hU?k0t#!K!n{Jt zin17@+lo;<*aAHbsu(BQ_`18C8N|Kc1mKb@eG2J+N-f$n5fGat*fv1q4~M)E5QHXT z^%Ot!8VNQb;S_*NUk`P=l#0mrtHV+gk_SCG7@734p2Udbq07@X0a3!>l?q_StbC=Y zy~$M*2VN63qEBEF57&`2h9D;*UX7GKLZI^BNCtHD0Yo#m&1a1(g$w4C=RkJ1K>&v> z6i0ZnowjRj6pgIOQq;R6QwbwU1OOAZZDSbm8;Vt1N zcc3$o;K|{6`k+;;Sing8tYmvx-871O&*vW}plrI8S?Vb%fNFF3(IVAo)*XvD%%rREg9q+bFaUr)B!=M(G1{4hjGj-|(V)vAi@+dOFs5Or zJub@Ki0P1w8jMkASR##($6Ezk?e0vZQ0-5G+w1@|1*@uO&!&0=61H7ds_Kj{lPkSa6!Um za&KycVw)UZJkZdw1H-ujOKvxN7C57NyEbXw?oH;UCCz?$#`2e<^B)iWTDThjz=pFU zYUuKXuJ1XPFRktd34DJgeNpd;-r96WcKSJw;^5q+Jc+wH_74teTneAfoTh&^!@My# zVxr3NsrOO*o+np?_7yf3!fry$+P@m0P70xZtoHs*{5M0t%!FcOk;bSek{qO+F8Tgq z1BRat0MO%~GU7#``8CP6>Iok5f{W(G@I8xXI-!FnpLV|c02nEyEp0C{do593M)g zso01bk2QbU0gO8HDGufUlXdpz6Y>EYIuz%Nn1iGj-kzEB@MrV6bUj#8C2~&=LjSGoN;<84?4ph&q&bp=v^;{6a6E8hS+$UEFbW_LJgq0F&Kl<8@stWrme>-TD@V7Jc@&7bC=m9|>>?6Qe zI^gra;9muL5>y518prEf77L7?0FXyl_RxRgT|hoy3#bjOC2R^vOi8YjFnHmLSb4q4 z7>Q56>;ET)W}OW6790N;4xEr-<9`YYH>!}ACgzj&03fFpLJBAW$vMyew<|zzMYc{! z0;EAsf@-$n5r7i77R!tK_VGNN!*~#`2zZqlFQmxC9UXacHISpU;o#_G<;Xw*50|8u z|M+`_h6_$!#b?rgu9?@Yv^mf+D*+c~JR{~Qvs43!(+6sBR7%S-OB^bzSd0XAnZoJC2I-l%(P5VrQ%7fRHCfn27aeqX zFt)_gJGRnlzGwW*%gmh6IM3GXuD|L0IohTAjQi&NB{mUD0Z9R&39-<0K%Emvzb}k# zgfrz&06^r}!aiBOaHhzRA_4tFZ~i2?h*T|G8uKLr!QPY&nTWcGj-+C362Oh7qRV`|% z=bZm0J62MEwvpRMQ027an2qa>L)`7A)5&Q^gS>khvEFgLTS{}Ks*W&)hc>juUe%A$ z6<#(kE+G!?2#0Ild)v674(+T~cI2}ezODYb=GVggJ-0S4D5=D_$0ec`i`$(h%C#f- z^?y)`PwrW-X4h_vJ`J8QF{oBOYFFj)Y82U48V9}!!=%fy`$T}_g3be`jNrurQId2= zNYW@4eHu=8;*~oCv;q27hSke*2hfT=9Z+4+wF^AhG|N2mlGVUkH5 zGwz2u<5ae6x??#@dSwF1c$lB9J^>nr&)DV9b&ZK;CFz2tJxZzXvI9%X6?w4)y?vr$ z^I7Qxi^sA$WT93Ck7q)FukyquN)Jo@x+28yNYmsO9UI3{-#DA15+m`#f+tZU+I*V{zCcF8@5P2N`E!>CXi`S^T$OvIW6Fr5M* z0-$I`jxLp*tVgA|2i(?i`Vu-}_@2q~7XTst0}JV)!wPMYh<>|#jOLeT8DgQY%W=kq z>1o2>?h#8zqt}c-A}ZdYLz2-o#6R^Ppb`9={|4YFANZsH26Hg5fssRLYkuhtfXwSO z*#hMKnkaob4i-6DoA>n|2WPw~STB;Fx1OTMCA{!Wgm#e*!TS480ZN4ic?0;v3bL~x zA3DOFmd@cUYQAjfIbJNa-?R!sN>rDI8f^~cx8X(Cf|KTdX|ks8UVWprYEgYBYUW`2 zn5QF7F5Y0Yl*ie@=OLi^YYu71H2i1S6M5)5+3_}L+*hTXfyw!4*>t8s-Ctb!lH-*))8NAhGc@bgQli25yzJZYcHJ+3 z)qvI?zUBiqo4=E6H+*3xwWxjgO?4Qv z5-#?OFo23UbTEMl)$-1l)%S+@=P#}f*m>jvOFaX)K_yxIwN4|2oH2c^;+JDU(dk~+ z;h7drg?G;8r8rns@)}CyyjM2lT-bMob#Ox7;@i_lMuNxD z>T++JPBb>Q3_4vZ$~v4~o6W(Cf3Zp8cQY&N`lr(4%+&l6^hmqch|6Nq&~lv0ypVX+ zI}5Ru4;Rtzzcg1nopy~s{I8>bEsc&;Gy*prXb}orsm-)3jWaIxHqZVw{^!$N-u|Vn zo5!?J3AI@nkTwx%Z<>EY#`!zTI0!cY$d?32F!Sh&30exT#y^cIw7U#xKIVKGebxW+Cr<_P9@{%-=<`akUb?+lK7 z@`+Y9|DSbVd3=(Z)Re}9!nIER0LhUgY%pHZy+ir_v9gwMES~g2kyBoHDwff~0xDG{ z(&X&KI2KdBy7l@`DO6w}|5>vX*8Z;@<5Ms6zc)U5Gm?vqpoFK@bf2^=oHmg}#h_L| z_IRO+rjCrqC)!2CGUEj2RfZ}~g4v5EN9(n?x#Qf&U#qvTsjSMSwM4KlFc^H(3|P06;)M0FsAbJB$RV`{lwwD9g4C0MHsMr3g>83?(XM9m<5dw3fL8CMg1Xx^%!%Kn}h4#4*g-YrJ zeDqN^Az76lB!1Gyb#0@^1|$}W(e7rmX{D*clvAGy3A8(YA=Zy`3}5ogxEPK-W@UtD zKo!Bfl0aB|r)>12@6nq6IUFXM_e*Hv199Uej6fZX#7F`FXGx`4aYts_f%^+|=<3W6 zVoi-_`M`QKgEMJ_idqw3dX7&xpM*uLw@osiSNz9cjv6XVo5&G!z<&y1Z16jme(OU9 zmw(ZRBc$M4C5p^1W>sF%&GIhqOl-{_TIl#o?Q8Q4Oq73sM9qj!oAsX$GA_iz{=;4t9>=YM0%Wh>v2 zLGh7w-TBv3MNjD#4)jK|GOhvhwoQZ-azXtHG@CGJ4wr<#*oXs8?I0Ds6+49Ge(qO;vR6s*HO&{M<0xR*t8X**alSHkb}jG89jPaRyARR)+ zY`C@TeggYJcu=|Z_A$;|SM{TW{d@Gwb6g&+Iwym&+$DSa@%A z!4u}tNzWr>A%xM}?{^gTy!-j*(z$)c|4|HA5H-eI)!S(r^khx+4FfRjoCfyHSdaeQ zdVMju0{HSln!C}EuY@Hkke9Ji?t~M@spGQi(M`>eu-IH7AAT}2jWfrN>Tf4}%%G29 zjaJl9EWQ(?M4}3uCx%UA6OjxHBWHKP%-2Jgg-tMj^siO{N{ccsZ2c=Jmi_*bjsFpl zk~kbt;8VJ?10zGlzdSmLyR~OXs|u|%)n-VedFV?E^p-H!XQ40+b9Qq=xpY;Q(CuDn9DoTJQE78$~Q#dI- zKaaOntHPJLIYtDLxU1wG&JYq={pZpuID z3YRVDK7B%2R6(HmiIx8cv5TU%W(_y5MBDc#34G)R7TDx}u(3Hn-eKApN+nk{1XXBO zs<%yxS|m&@WSN!tC)XD3x&B*|f<^xH40Gd%V?>U1tG<1p8mVM0uBPGM-VYd51qy9@ zyb(25tu8-qvp|LnJ-7dnsc&BGE-fPN%%*0(>#W)2HSZD1B0!`+5|a!RII z$nNHK@AokUJvgXdQ1jrVR$iw4woSkKsNdPl{kT~kX{J1;aabC4Y0q=!A6JcFg)vR3 zl#(>Z`1kQ&PwyGt_MaB^P)n4fHMlr&_ShzFJVm)6e%J56AEHlH5S~xb0|sK7GY>XNq^muRs!nC};rWhq?ijXNU7wv^4rETDM{a<4!EXuequ=Bs3 z9B`0b|KB1$JwO<8K1Wk%T(C+9@4z-s{=Tnz1%QCI$#`5ct$;S@dLE)X!NKuK`iM0D4bgoRX;J?~3QDPxiIb(-J9BsWzu zePpE7Zn9L%6A;39X+M5JAC8Zgl}$H)*%>cpEwl2?d~?&E4>>5q6HMeXEmgS0bR$i8 z4RT~jB1|G%&V`TfI$4!D!?A6q{<)cpKTJua*HZ`Eb8Q)GULa@A7-48Ko~wLC`hzfv zvXdd@>n*NKy6U1mH>bzo#F?>o@Z&1205ct%5L#r-;l04*!iZx_-H1Srwi6>4+j2T7 zO6rzq4uyXrME^!ky|Cfq3w^9(>CUNdm0+(UXdA-$DUg_{d6heeABY4Xe-l{%U?KFu z#Eie2xqEhEq|>$}GZYTUdcXU(UJdSq0 z>HYa^e~`h-kh8d2<>l_n-+NEpylBwepByQd>`=zO2o$EH9 zqnQPWBlftql+@RZGwxR)#Jo&^g?h&B^)aB^mWTvyRr_W#^j1tM;TX0@6z&d%o)-|E z4UDCWr*GS9*=FZCCufj+`BR6DGVglV5Wma3Z;Fqq^;nIoH0Rf$LIJMAPXv&viUVdM zv0DGkB28zE!|#|6yen^PM_daW$-H?}=y-6rB7VFU;nMHqiNBz z*S}#`m9W^d_WgomeN|b8koqZ1ZuAppSB ze7=Bk7n%5Mzy?gOlYiIkW>zTJe5VLFGo?vD%~l;!aiG0-vg7gO-PkQK_0=kG}q8v&XO;K$-TKc_*xN3KzD z_fNiV-Ve;t_-9cV!0(D8*fem&F~D;_6(``;l+lz9K-M-2`apS7uf{^-oE0u}AfAVE zpvG0IOnU+R9|th;&tkJs=EJoyIVH#-V`a$rRCwknY#P(l zgZy3pR{(hRfBA2Y0|9pI`k#>4h5iXLOYjFYVb;nxLGVBP&I7k|y&n!=f@7WrqN;g8d3c2HhB$%Z~7?Y3eRX~*Sqi|^R zE;cyy>>{y7TbhD_jm-q%7PiF5>EiljW>?4Uz}VGs(#Sg1&$1NhCc71k+ihx)JAPvY zb25|f2E+{yI{IOaT$M=lc&ji@D0r&+q%B0SV!?5hiyUQl5^iJvEiBg(77dH?y7X@x zzP+`p{+Lk3{gOYxuW)7o>!DoX7Cq0OTXkSBPCc+w7tyvhcWZdB#~-k1!m*+(w;KJ` zTkFo1kcbTSbpQZ!f+iN^0$}tF@=)+d;k8m|=a zcEPYt;%?g84OO~fcCb{Uy-b2zMhur z+Z%7cOB?5zHS`yBr#P%AK?A7qenMkr`^`jZ1#)rYuDYj=&d4?#YpO}LC&s-~ewjln zfAwFNDuG=u8h0$v-&ssh=TjGh2>R=R8ew3COKfnJu=m6S7h-2;*YsW-3sFl@+4V$p~ z8d{Qj>3?@&dbj7n8KWt4;R(veV9~6gyH%l^g$5t@EFYTU)g{B|RUMd%S822SQrX5& zKX2Kwb*=yq0Fc4ph@gHLErAeyeA$}~hgHs+RWN1(x?Q6C6wWfA(76>P(76Y}=&{9j@yNwM>v z{r>Ugzx6+efG6EM?tVGvYoY-D7+2*ujUk=Qs)%EjKINB=M={ih?HdxgH^Hh>Qdh^d z(cG~MfOuR8B=i*k6qdkYl;Rh8qKku*ubU!@#Byu1;_+b;atDRZQ7jGT?m{qY+q6la z;KU8a^~HXXQ#Qda*)ui6y>nI}2Oy{08Z$P+y)+dnq_^Dk%$~-$ntd@AlhxlG{ahW4 z+l*Ru$ozOD853Y3ooU--(sR>G(eXR(spi&&1MkFJ9%t=XNDnp|6i`=L4JY0t)2oz& z8aq;@Z3YUxN{`B^6c*dzf3;`I{arV^yD2u8)5RD!3;(Gd@i`gB<@wss?Fr!yPa!5mGgXbt96YE@-?b{zfv}FP1RJ(rK zM7{iSJERxZr0#ba`i)D}#sI!NUnzGRyyMj{Nxxmz;Ce9xJE>)PCdg zG-RM(J9y}r&wv{uIRbm$sy~botABHZ-<2l~cDqXC%Fsi^b$p(3yVS~v#OGSZaWB5_ z#0p^j=K;GR2wNU^0Uzvdb7OgwHFx$5v0Kxl9?DdpVr^$&07tvi9I;CAzpFK?B3 zD*8q&{@j#FkN(rwVKC!oO93sO3apqC;oiE(P(H8(MSzF9@QpPbC5pUjDI#jF=DPj`# zPyh2JLs?sf#?F7J=D+$s+G__w0}`9`{3508r2)bbKn>`&RJk?oOpA3mk(rZLS5%U$HY?9nLW|{lD#rc93;j2#gWNdI#?AwxlzZS=L9Cb zk8xbCW^mG&6VJjZCgdeRR9+yHt#!6Lj7=YfnF%b~a*6A(5U?LGKn0j058akenXybZ z$&bk_U;h?}E1pgO9<<^yI7W{3R~6LFE4SCnLvV=-Cq*8BczSSr%ExAVq6q-}7$$YY?lJi{>_1flP)x+aKJtmDh!7%Ah*NxvZ?4nDYnn}(5^|7hxj|1c z4gVebTQB0z#`iQ#tmhx8Rg~B~+O<+`QCw*LIne*5b*-OE7;IZb$9>Ya{uOkqC*bQl zpMVp}4o=4!?uOFEvA21IFHdj9a`gn8I%BTI@Ts?{f_2!lU5e9|w3XN*}vgl{hip zbcnPt-`t)3Iaw8Xc+bOTJe~6xo$%MGhePn*j}nQRyyUL`IuS;tBHiyL4mB91RW!fN z)^#ebIpwVI2l@aBz??_0-8P^p-{a?EQgoXVjNMstse_uDJ#V)@pp^=op{fVVeL$S7CpUbCgp4&Mh+LNkcUR2L!DV}5-1y5s6Yvk@W@M|YfB0A z2miC*zg+wm|Hza7^nYqI;sj(7EFGO09zsQ>q5A9R=>k&>nocQySv^|!+$$wj1zN>n zVdZ>WE9)4!(85Ijc|KA3e2t-(J%A4FbMG-FOAC9RQWDh$0(tiL3!8oH-=|!A(uJ|n zfSRRw>=mh01a{%MjgAX~zm)_Ahb z3@yj%J5JtiFATO*KYl9vMcB1L*@v>}qxCWYMR&{^R?~p(*E8RED?3IMC@I%km_?75 z8|Q{p&xX6aHy;bG`xO1SeEMqBYuN74Tp*<7>AW#W_tIWmMri8CIu-k-r>3!a6QRq_ z4a)~=(TcOqhyS(zhp&-yVw>8L>Nz7<{%I%=rCGHrd--;q&@%uL!-hM(EFP_a|GEHh zis{Sn9>99MFL-YjVo6&zOw7z;3<}%cj#FESRTle^p&mF)7Tbkco_aDNJrKB`W@CIc z{<(lX|DZ4%`h)0Y*kS!a(nzvjUrz@M#K#8zQm?Pb`3B`AE9-NW!y&a zyFE?U+)C*^AD%Vr#Cr0-zX8;(wc%bV6$bK)TbX^0RGy7kl(_Iuw&wX~ zrVrqOv#CC`$rAaaE|Ph+?bF&fEJr14?H&qWC_Cl*4Nw)^J&972IkkZ~x#z)jZSw<9 z+furhLav@kBN5&&p7H+h*Sm5N(whmvdQVqX*Y-hl)o{M+s?r04N9|+IFfu zPRzf(3g<0B*0&cD%YV$lS?CX^V`~2nSKRZtmmz9>E9;Ym1{4xaeL-fHq<%?E%~1XaZg6D!LN<~o9s({<18{I92?!*l!5wP6EWO|2L?G~_I6Zx9 z8V(TIkOQ45J-S_#_WKOyampSg5bMJ3Rs?gsRIuI%?RV4;do<7Qsh?DEpMGgCIC}AyTUYLj zZXFxF5+yL=^iYs1N!Ck$d@nvfuV|Tm%&l$Mr*L|f5A}P3Q4xEfKc_^kYBUDi5J%HN zFM<)_kM%I_eB1+2-FRh9_C%$(NA9kay0(7nYu9Opkg?Lf4A@b{q(SLu_Y2Rwa4nl! z`KJ$rCfzosPsso0ZcxFhXSeYdxiU#Zgx59q!-$edprVX}zRYHp!I$RY={ed5s^3b%5eO`+oO-c1r&?eg6aA4Rd5f*{Q^@6-k(6KxOLOI_REWW~!OJmziY?YOtUXlQ8 z&Ua5q2x;A}Gct48fanA2U@dh?2PkNKOUi5eqoWiq;W=tIgI_s4?8K9giDJ&{*Fv2Z z!L(7b5v%v;GW9x&Ma71fe#5H*dLlAf;3sNAoF|bP;>NRHWK09@w5y+AN)8!NRP@7= z$HL~TS2`2TMSeKUu$Xci%~oE^wxWy%sIfB6QH7smUeyv(o&JwcpjPVP1{<7cfM0XP zk<+MKlv@_=*K`nftmbC^vfo}GI^Aqs!V1oujpJWYe=^;tnRVt-`FO#;y&&-sH&%IC zppd-z08U9pTt0=nJqfY3qL}S) z1@pMhqXXp${QPk?2?+-yXa^Sb!ujext^JyIrRlWwDZ3_@zUF2#@7KY3qXm`5-N*EB z4#(DgKd)OzQLpUE8@8?^n9t&*LvyRW%T><76~z306oohq=zr8s8?%gav3DZkC+jMW?M?QF79_kvBawt}*%)C!8!Y|<(qo-zbEzy*pi3~SH!dZc!R6E@~^-;-2af% zuZta>%S=c9rvLPF5IcUN@EZrYXd!O4f^l&7khEOz;pBB<>b``7hBbe;0aQndb)x zA?6Vug5&t*NxFw+iAs{zYzs*?tbuvjl!B*KBuBim`o;l%_eV(oVB%_@dnUF}2s&b? zd~pC0L-HtFR|+ga1=hjOlliY`43u5G&&-q8tDFFyml02|i$;1F5*Ilz`Dr~z$jy6MavihS>_j4Jz z$#<&{tp(rT3&3FEtBad;@YfG6IM6E4vwm}zZgAOt*)x8w?RT*vr`Rn&9#0~ z)PU~ZSKmGhlm-w19R2ji%}C5pLn|acr6g5D+%+;O(6&btA4H=|j zZquo@h{RcMydSwKF9E|Cip!SfGV$WXD<&1t^mYl&)AIsxabmyg|0Y84xo2Qf*u5 ze;X21j9fa}wc&AM6-vG{&l7&LomThm{VCtw9Cb$NVDVENR%t}j>F8{O^*6mG`pBp8 z0;Quiv?qkY#lG^er<M2Xx8J;90Bx>>gOOCl}}IhUs+AJ)cZM;!rcrz5$mbnPevEqjmAA1sJuBfI8y@;&~Bg zI5Q>%=#5ux(tF(|lpdl(rK4@h38 zPby-+CBsuhLWg|INmBeJCx@R`JhCwn)T)9c2WKD;?5^G&%pbjACDTxOm>%gZUs_?9 zWGeC_D$j^(iIQ@826j47X{iNz#m32azN>gr-eJGPh1l(@ns_*2XxT=)e~=NkNd5`- zOsIWII|V(-{)>OmXHt`{$vGw2s%~)kOA= zR9#cLaBcX)cGQZ>OWKvOhY|VLd4|ki8_gh}gm(`eA2xuU@}NE(Jzo2_*D%4}=5uRuj;LM6Xm7=2rOZ1aK8=@-RG z$s**XxXYPR2SB0}wPxgs5Y+4I84hdF5^m7lY?3XYxUE!1#sq2zQSy?vM7D9_&22l- zAZ5#tB3nCT$bIuo`^VeRCjAb%`Qx^-brR`~g!F83h;5@0)>AcP_)6_4n@&q`H8V3} z#XKc@n|EydKQCBPgvW!B!P&qPaGM0AH6&Kgq}^PT#HyGHJ!?~0o56i9y|ELsmXqa^0DZlH|bq8e2M@F!p-AAn<%G*$0MVLRGEFV*U!v z7g0Y5HC>q}3Oscahd)=nwz0}Oma*UHOoZr+{Uzss!rtAyLqykz{94i7OQw%JlWOn% z>+4?tQ@?Tphj(>OKACUJC(HTQABJa{WnbEh#M9w2*F)xJok|DOel$Efw(Osn!>f>- zK5%Ie)yDxKCIA5C@=>?p2rZ$0AOQZR7>n)^eV3ZR$$%#X!&9UWCkIc9&kSmv-0 zzegJ^9U+sv^Exr2_jsTntAbh*?ugPs)tSm@Rn<>v6AD6Z1;!rl%!{8Mp*%x>fZr+K za=J-PRZYrPvR!O(4df|=+l}$r!p?ahgArGXO&&dYML)g5Yy83#<9GALLfg^}R=dH< z$gwfr!1o$CZa#cV^Pk9K7mrj9^{QqX9SjYPlcpYX>!hMuOkNp`?*65YG&0S!!UDIk_7RQA@=aOI-Z0hj4lQ z+aFc;Y(vYpAf$VRN%j$n6L+2Uer}Qlk3xO{Ft^4?UjBvm7E~S{QWmGK?}KI1HNXh9KB0K^P#FajkP}EF z4#IZb*F1YY1gL6XAZo`s()&}~oG{%lOgOj+O|6oGilBopRMe}WcmV)7I8Fy~r7n_; zwv>7rgP;}nCM0wx$kS0UORfHi3a5Y>*)gppBh7)?n422fAad?xLP7#_q$Hj6?4k$`-K?rj( z$7-gK{&D!-53g?r<}UbedK$ONfh~tXdLkTdR`ZDQ?5U$DISbUGL#V2P0EJVZ8MG6p z^3-MJCL1b0y{=S$L#rE3s28eLY)as|(OQ}geepAIb2)O-z=)4BQ{$f$^?35T{(k~!#>qG=u=THm4h5X+C;?1A z=-0}(Gv_CJ9a*z}t!p`0FsWB)aP#G^59*_#DGBYNRQaFSJ8o0YZ2@Itirv{r{mQ|! zq?r53depk<0*fgxq<`P3&l;SL9+NHd5zCr48g5-Pff>nKbR!2pjO0v7>qjDPzF&G) zWx)^SIC-@;P{@3HND_&`MctSlTJI=+nUdf76ZAvFvagDZY)ltr%WhTCKO>K24!S#B z(|IqKE%Iq>%6q3}%4>X(M_K3N@kC2*a4X9ELWv7)9v|SxkQ?UXvUe-+9ZOHskWMzT zaU6JY(>R&8S5zwMum=ae*D!h`&%C`VwPX;J%Brv01g=_BnrhXc0QToX=S z2F5kg{Ny+iGA;-kM}She1;@ii#y{{O;6R%61v?iyMdT>dtqBTeBy7LLuEFOmTIiS_ zUuj_^4@2@G3}2bM4!jC2@su?*pY8yoIiHM9XiPru zyaHM9A;k|qn3M4+>2H)fBE)6GO5q#gFi){H`z2v3Wi_2Wm$B49#xE#pR7_-x8A?X6 zJZ+}mALA&chMAk>&T@0ej@Co&{uKFC7VU_(I-bLao9eEd6Vsg|P-1}TvI1#}g9nc! z>KL~O@_erYeN6)_3Y%?7-Nml}zULlWKzRik=*t9&0vWD>`9 zCod21ulKOGXqIdF{mFmEj=~#q+B>bm(nGcUSN*=^px@70!a}0%(tlNbCs7v81~=^R zOP^^{RMRuN(To-$+U|JwY4OG$#oZuu@xw8w`d8%u9Dd zc8@)8)2|Wh?4K$L$_aHlA}&kXH>2WBt#Xw!sh-^|zT*?t_N~Z`b$enm0ol`(z&kp* z)iQ_XmXVaTY+>TP74BOejf9~~t7X@RdY&Ef=xyONZkkZNksu^8$7Qc}ZgtFLrF}}y zPGX>8JWBtq(rpf~>3xCz0KLz5P9!DdPausB)w;&ozs?0Zn{5;7!umc1>5T~vr;C#A zS4KPdX7@#Jg4S{%kWK}A(kAbIF@ljorfq>jgZ2E}RyYHOk=~FMA`tlqC_W_ctql$< z%!5$6ipW6>GTVeqKgeEhlkXgos$v2{YCv;^OQg_Q2FgiIGZ+j26S+72tJLKpW#sx3 z>@z0D0UQ2*(u4_ez&2WarCkF$yud^DxQ_POtGBRyr zM!EFm-a>5V-7$;kh;2MmFmASySR+%V<+6GFp}3oS+Hgq5)Q2Z+4^EsAO;EAHN|kAp z`yb<}&H7TH5aLF{m2&ft`)ZTlZis>uT2a9dvoN8_M^rf6k&by&(Vbl9-ENA=w``rC zrHVzDD(%<~q@D=KHM!ch8cXiM)z-c8S2=rSFuKnyCBswc7cjuqK_c+c=MZ*T=j4x$ zelG)!W!5bx7+T^%dI3LPdCTxX48dkw$E)gGWv{8ppHCoS!A2vU_w#y@=OrZh=z_4! zJJWXix5Hq~P!|lgRUZKw%9L6NdFm<20~hoD%n5WULw0dwQ2Y7n@}%u~Q@HNF_?`dn z0q-Q=P|{xMLeYo(GA4ZUYZnN_dqb6+mFZ1TRQIva9)Ec?28TCYs4(gv0S+lrdu`I! z?af{|z#G>?$}7m9ZypA9C;qrU8yV>`r5`JnWNCZ-1tY$n$l=UrBxniO#GJ~2-2$++ zIkpU&IuaODKvrAKerYY3;bE@tI_+eJzR8dAM2U?njuk}}W=RCF_hT#30sTBU<}+g2 z1QAw}Xhxi8ni;(C!OauJuU@+`x=55*7@lKMV-Kb{SSJ>XO7PCyz3h+-uu7@h%E97l zSEQueEDwW)($F{f0P*rAbv)rId6^?sZ|sj;Ja*HcF*-->IopI4@GfWcdm#=ET+YHh zrM8F)gKDOy(t&HnRa+~LjH{Mg=vP4EBi|w_JiLL2T0v=oE9; z=YG+2*q4$L64E)MHT%cx854JPfBM&`E@8?|?oMaQk?ssS?F5-XlYA*uQvE`$CE5#vILH3gF2-L!t?2_YBGGHC zNac@+XFMO4HY;0Q;GGd1f*M8z2@nybRSvedG) z35a{-&RIBfXRgc^&Yb1WtnOS5SDD%F?)%v9;VXtySc7l` zX@iKjcP%LBo6K#zR=M)alBf{RGKgByzE1yzDCxI8t)zyqEC3}0YQRs&(pyZqGeP7r_~^3N19GE+ZFTSL=ZWQ>N)%1Hj2GkA9UNX27a%Hjr35%G^+A zB68AO^*Evb76EAdp#YZ*qB)^Z9ao-%4$3~o&+3D{6$Z4wZ4?kka}{qCyp2MlkdWZn zshayU6P)gMAW2b(L|u5o;mUh4#yKdOJpmR_L83Zu7@P*v@Epy(c};gO?|}q#|DXO> zfe${LRvGIDq^lqN-}`SdfUMa5(%eJ?iR*r;DHgl8pGS^=s5fqQ;KT6iXl}98?t+b& z{Lfj*;X}DbLU97M(qd`LVOQtG+)H_CKW=LP(6do^o|Ue);K`3$3u znM7b=nr4;V{XTTlwZ4scF)1m-zOu1B_gl>pxt+772QBWnXF!(dP%*AAYOqt2_ikOBQY z&_i0rF~aG!t!H%$$z*R)9py_PecJzA2tc+!Wl)gJb&t(+R{@rKp@^)`I+%Y)^|UHO zvv1^oV#7V?vd)GzSllJYlCR}Yiu5w>uT^edEBKz{vf7Vy^9rD#W6~mC9(dmlx>eMJ zN9!ga9Fhfxbz;u4MOHkeYb{IOnC?v6V6ap0nemL9g{5DvhM#GT9I{Szxp^$! z=>-NZBI3DRx%_sk$rx}iV0+xB#)4oJpLji}igCD;teo{kJfnZ1$>99Hd%r*y%`Cizz1O!lf?1wKh*jo*3sunipB zc)7?23QS}wPEEw|`qw_n;#P1=nEE5BBo$FMN0i6)hA*@k?(s$*;!g@P$wVt}8;?s= zVv-ER99q^9y3J;%9EnN^@+mi*skvJy4<)P#EqJe`j(sWG_nQG=1(K`(2)JrWQcggGS`< zjpo%dS}ca~p^fLeoLr&OI_N{U-XO6PvKNiTJkz8tb@9?g%5EAN#rsW4*=Ri82XD&S ziqJsEb5u@AfT?9eNoR-Rd$Q2J3Lxc0ve+d0QoL;Lb)4~g1I6lw4(`AJhqBlDLwUS1 zUwpX3>1KJ8$lj~F(_Br3yZRq*z9fyp5sm$nULa5+(48i?Cg15Bq3^1}X1*0ANumJ- z@^BztPKf!mCqRuAKWG>DFkX9@v_X?zf-a$gALcbVca{61QNMeS2l)d>Edy`3(UV!i z%Dc&uGK~LzXu+cBM?hH*Y=zp!+sMRY%3Q6y_{PV{M+Z`kHf7^eY!1rhxO$5veWHK5 zCysQy`;74L5>iMPLl*a;hzxfPKMWmObJDi8M^36dM@iyzS0o6r`-X_|X1=uAbkG6P z3mFe>9~PK_PK0PAO#YhEC}CgpZZ7o1_2!^`4yww+^Nw_rB&vL(5-z5HWhZJAb~lMR z{gjaAY=KH-W#Z1&+@v@SqIu;IUaBCsB9RmK1O%1@Uy{;L;TR)ARG1+b*Ih2&2JqMv~jlPPH{~{&R%zyKK5Z_u@HvpE<2zlj3f>_A6uGsEAONAnb|znvC&3d zvr_SKSJ(L5rO~3M(vCCyV_+;H_SE-m7OvTcV6iIOeixEm29_4qbOz|Mymx}6XWs*@ zI%lw-|6$svwVzFByp{=Zd^lHMfh}6gW1|5n5MSWl!w=ApQy_x9{z>WAmC+31N` zVW2K~{FUs1j?y&#zwe`D^^nFQ|5;8@>X;)PSH?};Wke2pg;MHO@Nvy~PkW3<=I%)V z6LOx#nNw$c_rp0xlE+HvgcU?j%hk#$3zLytv z@sKl<981}Ib`eU{DH{v51R0CNZs%@inqAWw6leiphI<=k*x6ezxv+>K3M*(|My!y-mQPe zf^co`yRb=ko`2Ao$&Q2ddn*{r9_FO-N%ha%bBHI^9<12y=q3j9(41EyB1poGl3hK%%|H8JPcgRIt-m7pJXdZWhUmw zZBGnv(QLV2(E&0_!O|e%Y5i#8C*NUOhyK*P!i&p8lMpL<$!82GSQ~URV1h(x?iJR=9(j@2S ziGnjZVzPc{%_alH63M;p>8Rz=5$c;JhVOdv@F|t_^a&Vp<*Jj0i*c-DVV$k6?aNmH z0+50&mrcYI5H)gG5N`gR1gzR}R!u6^N({XA@{ut6CX@~o88knU6=Ie<{;H>`t0izw z+Y7)f23{j*sb04u<$vJe$n84 z(zW||>K2?D&lQ4ctjsRY>}Q#vuCC;NIsY@5t5_xl^0!m79u&IuiSEH8pR!C!PK zjP{PufB(SV-9XP3{eGt`x8@^V@9Xq!=QbmiUrl-0Q)t2hA&IwB(`SQS$TpnFx|ePw zHJZPaY9O28Oa?(4qIuR)PYO>nv?9jD`N#U8zB2fX>K|1X@6u)p=ceEhY8wI;jspT@;w!2wARk=s7PPXRr4 z_G;hr+(UoNBw7lRKm0sTY54C{b5+wv?wHA{rq4)R3fnWYJ7P3**wEb_X{EJh+1hZm0+ASSsF|?7_=$Nks4WkWBew|Dm@e)Q8yP1Pyq|dHls_#zpsv>fAJEl~H zn{AOyU+!K^GF58x5gVS+2dduoy&Vu3f4iJbKaB`5tNq#Tr&9iA-^+&He6ZM!<~l9D)1+F(il ztMRMZ(}JVJjNZ0E>6;E2R;%w1+-Bo|L%jq9;?U*(xFGsnUvlQ~uyOz5nczb@NtxLC znV50Zx?H9S3K}eO+2v&T#Z({=3LVHm5CwA-nMi{-RqP{u&TPdlL2_z~%>x)^l3|`C z3Rt`TS-+Xv8MCiSuGRM|L5Q9g6yKqTe^Vz%ua^`frhcJ=JdD{j2Mph6LPF>|w=?fh zH0E%+8kU_)&}GVkkw0tXi39?2`KkAhZJ&VbkT}sbltbm_be?5Lu#*e84A%DTli)u0 zO)njr0^n8dU4;o=;0*~4T9O9cv}1%tqYPhOP6Zz;Wh5h^Mq-eEE93!dXGfD@u~YQQ z#6~QB=Cyl70r0qteqbcBuI{VUag*J%u5y zXOFgUm`4vA9`ShrfzU(ZX;c4Bzc|hKFZJak;x6YL2^JKP+;zIiL;y$xTH#QLzfQKKf+`aZJjD{r`@{_m%pgs&HPp8d$n_-Ik8t~CGu{6ByH zo&W6CKZgDPdr*`0DkwOQUy)VC?1rgYnKgeOfZFd#Lkf$4BOHD+3t1bnEtQk4l@cV1 z-4A|^Y*o_DeSI-8$rLR+6l4AjC2w~h|v+*X0i+8fqPwJB%6J$;A% z0~L2{ zV8yC%YH8nufVa~lvTRF685#FB&}%KTvVHf$Ir$t0+xD6u7(0GUigm@NBc~{7iYve% zXaLh=@x_Ff3IMBiZ_gYKzc^9ZQPdNZ?WuD4LW#=(Sc{7!AqT}ts?pERk$|@6T#c!Y z#Y05SAHlSgQPRxj?Q`$9g?*ACM_^Dj4f&sl?Be(TusR*i2&QSdZqDsv1phL4@BrUA zEmMp!;d(yf+M?dm@1{Nfw z$gy_s4!f2gYN2>PJR2&c20_V6jQ%MypXo8p0#1VMXXM~FELeSb z1oOemK_9b1#I9L0<$MUgL<=Sk6Wdl;Lqqp3-=)-E@a_4m{tA@Dv833$*pHa^5!R39 zs>_x294_mwQuED|;RaC4CJEpV|M&g_A8v12Kl!LTpzv4!Yc-|#C{=6*MjJfqhly$E3cORw>w%b9)vhVLdDYQ@gS$*CzR zqvQ@*sbIE+Rf)PAZPD*1r2d>+Fp|uysTK(HMv&|mUt`J~#>pe!PYCs6y37f_ZT;}M zh-cs3o9%?fyLa>bsJY3u^G7~OlZtQ(Uof3)5s-gaNP955%pid^MwF#u?e+u)_#cbf z$7sRlyZ&yz|Gvjn$u07pvUj62Vcds=@Hu@<1Ja*vv6~IG$DZ&z(^Ac1=6YEp^5oCi z-EDxRG_?$fI$DaGLke;tkSHUWq$%hY`EJ^^!ZQOSTmLJGc*rvM0F;b66eN#;=H#YGCqhD zcNO2G0-L7C&o^b6GSDE{i+S43SMe*nMDHGDxsF1#LHP0aF`7PLmn##KnwqX_#$8PJ zxl&FZs%pPaFgn!nF8$pPhx1j@vwkOufm)ZC^1oJtPTbc)?7j14E_CC+vgYbNqQJYj zDeUConb4#*J>2<;z|>1er>fRZ+Jya?%ek7|ee*_%%Kxe&c+9tTu&6p`L`x(d6i29l*Lscuin`R6-pP^ITVz4bnmB2dkp?Z zlm(M?qYr&PdKXhnb%&NCiXt8K=Y2<>U}JHT4==5G>{N^$hE4V#d>4F8epRb%0}8af z=@S#`W9i}nwt$XhjmHFfmju68qJoT*z3XgEy}#6is%weDC2u!qe%bUnXb*vi?gRCJ z#@TY@{%aT`HN-}wtZ|Zxdw76BP~m$^b1a@IOE(U=*eo`Gw8g@N=hg=n0qeYleyl7Q zH0e(LtN#sPqkEm65w_n7{-9>@)!Q1?*=g?o+*Dph%#MFEbtRdtk2WO$H|^C)CbFls zzj1Q+58CG7s8e*i{nC@}R$^uf6pwm?*xkI-XD94y_)*rwmt6zfzBWX^B

{7@TN3 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 J_`mT6{sW2lnIixI literal 0 HcmV?d00001 diff --git a/src/App.jsx b/src/App.jsx index 095a079..8c5e965 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -139,8 +139,8 @@ export default function App() { {activePage === 'tasks' ? : null} {activePage === 'insights' ? : null} {activePage === 'social' ? : null} - {activePage === 'achievements' ? : null} - {activePage === 'settings' ? : null} + {activePage === 'achievements' ? : null} + {activePage === 'settings' ? : null} ); } diff --git a/src/data/appData.js b/src/data/appData.js index c64afde..d087b3c 100644 --- a/src/data/appData.js +++ b/src/data/appData.js @@ -85,5 +85,6 @@ export const defaultProfile = (user) => ({ isDemo: Boolean(user?.isDemo), focusMinutes: 0, focusDuration: 25, + focusDurationSeconds: 25 * 60, breakDuration: 5, }); \ No newline at end of file diff --git a/src/pages/AchievementsPage.jsx b/src/pages/AchievementsPage.jsx index 8cdae39..7bead2b 100644 --- a/src/pages/AchievementsPage.jsx +++ b/src/pages/AchievementsPage.jsx @@ -1,10 +1,13 @@ import { MONTHS, TOKENS, badges } from '../data/appData'; import { Card, ProgressBar, SectionTitle, StatCard, Tag } from '../components/ui'; +import { calculateXp } from '../lib/accountMetrics'; -export default function AchievementsPage() { - const level = 8; - const currentXp = 2450; - const levelGoal = 3000; +// FIX: accept real habits/tasks/profile instead of hardcoded values +export default function AchievementsPage({ habits = [], tasks = [], profile }) { + const xp = calculateXp(habits, tasks); + const XP_PER_LEVEL = 500; + // Earned badges: only the ones that are actually unlocked based on real data + const earnedBadges = resolveBadges(habits, tasks, profile); return (

@@ -13,52 +16,122 @@ export default function AchievementsPage() {
-
Level {level} · Legend
-
{currentXp.toLocaleString()} XP · {levelGoal - currentXp} to Level {level + 1}
+
+ Level {xp.level} · {getLevelTitle(xp.level)} +
+
+ {xp.total.toLocaleString()} XP · {xp.progressToNextLevel} to Level {xp.level + 1} +
-
🌟
+
{getLevelEmoji(xp.level)}
- Level {level} - Level {level + 1} + Level {xp.level} + Level {xp.level + 1} +
+ +
+ {Math.round(xp.percentToNextLevel)}% complete
- -
{Math.round((currentXp / levelGoal) * 100)}% complete
- badge.earned).length}`} color={TOKENS.warn} /> - - + + = 1000 ? `${(xp.total / 1000).toFixed(1)}k` : String(xp.total)} color={TOKENS.accent} /> +
Badges
-
- {badges.map((badge) => ( -
-
{badge.icon}
-
{badge.name}
-
{badge.desc}
- {badge.earned ?
Earned ✓
: null} -
- ))} -
+ {badges.length === 0 ? ( +
Complete habits and tasks to unlock badges.
+ ) : ( +
+ {badges.map((badge) => { + const unlocked = isBadgeUnlocked(badge, habits, tasks, profile); + return ( +
+
{badge.icon}
+
{badge.name}
+
{badge.desc}
+ {unlocked ?
Earned ✓
: null} +
+ ); + })} +
+ )}
-
XP History - Last 7 Days
-
- {[180, 240, 120, 300, 210, 280, 190].map((value, index) => ( -
-
-
{MONTHS[index % 12]}
-
- ))} -
+
XP Breakdown
+ {xp.total === 0 ? ( +
Complete habits and tasks to earn XP.
+ ) : ( +
+ {[0, 1, 2, 3, 4, 5, 6].map((_, index) => { + const value = index === 6 ? xp.total : 0; + const height = xp.total > 0 ? Math.max(8, (value / Math.max(xp.total, 1)) * 82) : 8; + return ( +
+
+
{MONTHS[index % 12]}
+
+ ); + })} +
+ )}
); -} \ No newline at end of file +} + +// Determine which badges are actually earned based on real data +function isBadgeUnlocked(badge, habits, tasks, profile) { + const completedHabits = habits.filter((h) => h.done === true || (typeof h.done === 'number' && h.done >= h.target)); + const maxStreak = habits.reduce((max, h) => Math.max(max, h.streak ?? 0), 0); + const focusMinutes = profile?.focusMinutes ?? 0; + + switch (badge.name) { + case '14-Day Streak': return maxStreak >= 14; + case '100 Sessions': return focusMinutes >= 100 * 25; // 100 focus sessions of 25 min + case 'Night Owl': return focusMinutes >= 60; // simplified + case 'Hydration Hero': return completedHabits.some((h) => h.name?.toLowerCase().includes('water') && (h.streak ?? 0) >= 30); + case 'Bookworm': return completedHabits.filter((h) => h.category === 'Learning').length >= 20; + case 'Top 1%': return false; // server-side only + case 'Speed Runner': return focusMinutes >= 600; + case 'Global Legend': return false; // server-side only + default: return badge.earned === true; + } +} + +function resolveBadges(habits, tasks, profile) { + return badges.filter((b) => isBadgeUnlocked(b, habits, tasks, profile)).length; +} + +function getLevelTitle(level) { + if (level >= 20) return 'Legend'; + if (level >= 10) return 'Expert'; + if (level >= 5) return 'Adept'; + if (level >= 2) return 'Apprentice'; + return 'Beginner'; +} + +function getLevelEmoji(level) { + if (level >= 20) return '🌟'; + if (level >= 10) return '⚡'; + if (level >= 5) return '🔥'; + if (level >= 2) return '✨'; + return '🌱'; +} diff --git a/src/pages/DashboardPage.jsx b/src/pages/DashboardPage.jsx index 2272ed5..6b1c5f5 100644 --- a/src/pages/DashboardPage.jsx +++ b/src/pages/DashboardPage.jsx @@ -10,29 +10,38 @@ export default function DashboardPage({ habits, tasks, setPage, user, profile }) const displayName = user?.name || 'there'; const xp = calculateXp(habits, tasks); const focusHours = formatFocusHours(profile?.focusMinutes ?? 0); + const focusDurationSeconds = profile?.focusDurationSeconds ?? ((profile?.focusDuration ?? 25) * 60); + + // FIX: compute real max streak from actual habits, don't hardcode "14" + const maxStreak = habits.reduce((max, h) => Math.max(max, h.streak ?? 0), 0); + + const hour = new Date().getHours(); + const greeting = hour < 12 ? 'Good morning' : hour < 18 ? 'Good afternoon' : 'Good evening'; return (
- 🔥 14 streak + {/* FIX: only show streak tag if there is actually a streak */} + {maxStreak > 0 && 🔥 {maxStreak} streak}
)} />
- + 0 ? `+${xp.total}` : '0'} color={TOKENS.energy} - sub={`Level ${xp.level} · ${Math.round(xp.percentToNextLevel)}% to next`} + sub={xp.total > 0 ? `Level ${xp.level} · ${Math.round(xp.percentToNextLevel)}% to next` : 'Complete habits to earn XP'} />
@@ -44,7 +53,9 @@ export default function DashboardPage({ habits, tasks, setPage, user, profile })
- {habits.length === 0 ?
No habits yet. Add one to start tracking your streaks.
: null} + {habits.length === 0 ? ( +
No habits yet. Add one to start tracking your streaks.
+ ) : null} {habits.slice(0, 4).map((habit) => { const completed = habit.done === true || (typeof habit.done === 'number' && habit.done >= habit.target); const progress = habit.done === true ? habit.target : habit.done || 0; @@ -70,11 +81,13 @@ export default function DashboardPage({ habits, tasks, setPage, user, profile })
-
25:00
-
Pomodoro · Deep Work
+
+ {formatClock(focusDurationSeconds)} +
+
Focus Session · Deep Work
{[1, 2, 3, 4].map((index) => ( -
+
))}
@@ -86,16 +99,27 @@ export default function DashboardPage({ habits, tasks, setPage, user, profile })
Focus Hours
This week
-
- {[2.5, 4.1, 1.8, 5.0, 3.2, 4.5, 3.2].map((value, index) => ( -
-
{value}h
-
-
{DAYS[index]}
-
- ))} -
+ {(profile?.focusMinutes ?? 0) === 0 ? ( +
No focus sessions yet. Start a Focus Session to log time here.
+ ) : ( +
+ {[2.5, 4.1, 1.8, 5.0, 3.2, 4.5, 3.2].map((value, index) => ( +
+
{value}h
+
+
{DAYS[index]}
+
+ ))} +
+ )}
); -} \ No newline at end of file +} + +function formatClock(totalSeconds) { + const safeSeconds = Math.max(0, Math.floor(totalSeconds)); + const minutes = Math.floor(safeSeconds / 60); + const seconds = safeSeconds % 60; + return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; +} diff --git a/src/pages/FocusPage.jsx b/src/pages/FocusPage.jsx index 716e12c..94435de 100644 --- a/src/pages/FocusPage.jsx +++ b/src/pages/FocusPage.jsx @@ -3,29 +3,43 @@ import { TOKENS } from '../data/appData'; import { Button, Card, ProgressBar, SectionTitle, Tag } from '../components/ui'; const MODES = [ - { label: 'Pomodoro', duration: 'focus', color: TOKENS.accent }, + { label: 'Focus Session', duration: 'focus', color: TOKENS.accent }, { label: 'Short Break', duration: 5 * 60, color: TOKENS.success }, { label: 'Long Break', duration: 15 * 60, color: TOKENS.warn }, ]; -const fmt = (seconds) => `${String(Math.floor(seconds / 60)).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`; +const fmt = (seconds) => + `${String(Math.floor(seconds / 60)).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`; + +function getModeDurationSeconds(index, focusDurationSeconds, shortBreakDurationSeconds, longBreakDurationSeconds) { + if (index === 0) return focusDurationSeconds; + if (index === 1) return shortBreakDurationSeconds; + return longBreakDurationSeconds; +} export default function FocusPage({ tasks, profile, setProfile }) { const [modeIndex, setModeIndex] = useState(0); - const focusDuration = profile?.focusDuration ?? 25; - const breakDuration = profile?.breakDuration ?? 5; + const focusDurationSeconds = profile?.focusDurationSeconds ?? ((profile?.focusDuration ?? 25) * 60); + const shortBreakDurationSeconds = profile?.shortBreakDurationSeconds ?? ((profile?.breakDuration ?? 5) * 60); + const longBreakDurationSeconds = profile?.longBreakDurationSeconds ?? (15 * 60); + const [focusInput, setFocusInput] = useState(formatDurationInput(focusDurationSeconds)); + const [shortBreakInput, setShortBreakInput] = useState(formatDurationInput(shortBreakDurationSeconds)); + const [longBreakInput, setLongBreakInput] = useState(formatDurationInput(longBreakDurationSeconds)); + const alertAudioRef = useRef(null); + const nextModeIndexRef = useRef(null); + const getModeDuration = (index) => { - if (index === 0) return focusDuration * 60; - if (index === 1) return breakDuration * 60; - return breakDuration * 3 * 60; + return getModeDurationSeconds(index, focusDurationSeconds, shortBreakDurationSeconds, longBreakDurationSeconds); }; const [seconds, setSeconds] = useState(getModeDuration(0)); const [running, setRunning] = useState(false); - const [sessions, setSessions] = useState(2); + // FIX: sessions starts at 0, not 2 + const [sessions, setSessions] = useState(0); const [selectedTask, setSelectedTask] = useState(tasks.find((task) => !task.done)?.id ?? tasks[0]?.id ?? 0); const [soundOn, setSoundOn] = useState(false); const [selectedTrack, setSelectedTrack] = useState('rain'); + const [justFinished, setJustFinished] = useState(false); const timerRef = useRef(null); const audioRef = useRef(null); @@ -46,6 +60,120 @@ export default function FocusPage({ tasks, profile, setProfile }) { }); }; + const updateFocusDuration = (value) => { + const nextDuration = Number.isFinite(value) ? Math.max(1, Math.min(12 * 60 * 60, value)) : 1; + if (!setProfile) return; + + setProfile((current) => ({ + ...(current ?? {}), + focusDuration: Math.max(1, Math.round(nextDuration / 60)), + focusDurationSeconds: nextDuration, + })); + + if (modeIndex === 0 && !running) { + setSeconds(nextDuration); + } + }; + + const updateShortBreakDuration = (value) => { + const nextDuration = Number.isFinite(value) ? Math.max(1, Math.min(12 * 60 * 60, value)) : 1; + if (!setProfile) return; + + setProfile((current) => ({ + ...(current ?? {}), + breakDuration: Math.max(1, Math.round(nextDuration / 60)), + shortBreakDurationSeconds: nextDuration, + })); + + if (modeIndex === 1 && !running) { + setSeconds(nextDuration); + } + }; + + const updateLongBreakDuration = (value) => { + const nextDuration = Number.isFinite(value) ? Math.max(1, Math.min(12 * 60 * 60, value)) : 1; + if (!setProfile) return; + + setProfile((current) => ({ + ...(current ?? {}), + longBreakDurationSeconds: nextDuration, + })); + + if (modeIndex === 2 && !running) { + setSeconds(nextDuration); + } + }; + + const commitFocusInput = (value) => { + const parsedSeconds = parseDurationInput(value); + if (parsedSeconds === null) { + setFocusInput(formatDurationInput(focusDurationSeconds)); + return; + } + + updateFocusDuration(parsedSeconds); + setFocusInput(formatDurationInput(parsedSeconds)); + }; + + useEffect(() => { + setFocusInput(formatDurationInput(focusDurationSeconds)); + }, [focusDurationSeconds]); + + useEffect(() => { + setShortBreakInput(formatDurationInput(shortBreakDurationSeconds)); + }, [shortBreakDurationSeconds]); + + useEffect(() => { + setLongBreakInput(formatDurationInput(longBreakDurationSeconds)); + }, [longBreakDurationSeconds]); + + const playAlertAndQueueNext = (nextModeIndex) => { + nextModeIndexRef.current = nextModeIndex; + const audio = alertAudioRef.current; + + if (!audio) { + handleAlertEnded(); + return; + } + + audio.currentTime = 0; + const playback = audio.play(); + if (playback && typeof playback.catch === 'function') { + playback.catch(() => handleAlertEnded()); + } + }; + + const handleAlertEnded = () => { + const nextModeIndex = nextModeIndexRef.current; + if (nextModeIndex === null) return; + + nextModeIndexRef.current = null; + setModeIndex(nextModeIndex); + setSeconds(getModeDurationSeconds(nextModeIndex, focusDurationSeconds, shortBreakDurationSeconds, longBreakDurationSeconds)); + setJustFinished(false); + setRunning(true); + }; + + const stopAlert = () => { + const audio = alertAudioRef.current; + if (audio) { + audio.pause(); + audio.currentTime = 0; + } + nextModeIndexRef.current = null; + }; + + // Keep audio in sync with soundOn and selectedTrack + useEffect(() => { + const audio = audioRef.current; + if (!audio) return; + if (soundOn) { + audio.play().catch(() => {}); + } else { + audio.pause(); + } + }, [soundOn, selectedTrack]); + useEffect(() => { if (!running) { window.clearInterval(timerRef.current); @@ -57,51 +185,79 @@ export default function FocusPage({ tasks, profile, setProfile }) { if (current <= 1) { window.clearInterval(timerRef.current); setRunning(false); + setJustFinished(true); + if (modeIndex === 0) { - setSessions((value) => value + 1); - recordFocusTime(focusDuration); + recordFocusTime(focusDurationSeconds / 60); + const nextSessionCount = sessions + 1; + const nextModeIndex = nextSessionCount % 4 === 0 ? 2 : 1; + setSessions(nextSessionCount); + if (Notification.permission === 'granted') { + new Notification('HabitOS', { + body: nextModeIndex === 1 ? '✅ Focus session complete! Short break starts now.' : '✅ Focus session complete! Long break starts now.', + icon: '/favicon.ico', + }); + } + playAlertAndQueueNext(nextModeIndex); + } else if (modeIndex === 1) { + if (Notification.permission === 'granted') { + new Notification('HabitOS', { + body: '🎯 Short break over. Focus session starts now.', + icon: '/favicon.ico', + }); + } + playAlertAndQueueNext(0); + } else { + if (Notification.permission === 'granted') { + new Notification('HabitOS', { + body: '🛌 Long break over. Back to focus session.', + icon: '/favicon.ico', + }); + } + playAlertAndQueueNext(0); } - return totalDuration; + return getModeDuration(modeIndex); } return current - 1; }); }, 1000); return () => window.clearInterval(timerRef.current); - }, [running, totalDuration]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [running, totalDuration, modeIndex, focusDurationSeconds, shortBreakDurationSeconds, longBreakDurationSeconds, sessions]); + + // Request notification permission on first start + const handleStart = () => { + if (Notification.permission === 'default') { + Notification.requestPermission(); + } + stopAlert(); + setJustFinished(false); + setRunning((value) => !value); + }; const changeMode = (index) => { + stopAlert(); setModeIndex(index); setSeconds(getModeDuration(index)); setRunning(false); + setJustFinished(false); }; const reset = () => { + stopAlert(); setRunning(false); + setJustFinished(false); setSeconds(getModeDuration(modeIndex)); }; const toggleSound = () => { - const next = !soundOn; - setSoundOn(next); - const audio = audioRef.current; - if (!audio) return; - - if (next) { - audio.play().catch(() => {}); - } else { - audio.pause(); - } + setSoundOn((prev) => !prev); }; const selectTrack = (trackId) => { setSelectedTrack(trackId); setSoundOn(true); - const audio = audioRef.current; - if (!audio) return; - - audio.load(); - audio.play().catch(() => {}); }; const tracks = [ @@ -114,21 +270,31 @@ export default function FocusPage({ tasks, profile, setProfile }) { const activeTrack = tracks.find((track) => track.id === selectedTrack) ?? tracks[0]; - useEffect(() => { - const audio = audioRef.current; - if (!audio) return; - - if (soundOn) { - audio.play().catch(() => {}); - } else { - audio.pause(); - } - }, [soundOn, selectedTrack]); - return (
+ {/* Timer finished banner */} + {justFinished && ( +
+ + {modeIndex === 0 + ? `Focus session complete! +${fmt(focusDurationSeconds)} logged. Take a break.` + : 'Break over — ready to focus again?'} +
+ )} +
{MODES.map((item, index) => ( @@ -169,8 +335,124 @@ export default function FocusPage({ tasks, profile, setProfile }) {
-
{fmt(seconds)}
-
{modeIndex === 0 ? `${mode.label} · ${focusDuration} min` : `${mode.label} · ${modeIndex === 1 ? breakDuration : breakDuration * 3} min`}
+
+ {fmt(seconds)} +
+
+ {mode.label} · duration + {modeIndex === 0 ? ( + + ) : null} + {modeIndex === 1 ? ( + + ) : null} + {modeIndex === 2 ? ( + + ) : null} +
{[1, 2, 3, 4].map((dot) => (
@@ -182,10 +464,10 @@ export default function FocusPage({ tasks, profile, setProfile }) {
- - +
@@ -197,37 +479,41 @@ export default function FocusPage({ tasks, profile, setProfile }) {
Focus on task
-
- {tasks.filter((task) => !task.done).map((task) => { - const active = selectedTask === task.id; - return ( - - ); - })} -
+ + ); + })} +
+ )}
@@ -253,7 +539,9 @@ export default function FocusPage({ tasks, profile, setProfile }) {
Put your MP4 file in public/media/music.mp4. The app will stream it in the focus player.
-
); @@ -266,4 +554,47 @@ const soundChipStyle = { border: `1px solid ${TOKENS.border}`, color: TOKENS.text, cursor: 'pointer', -}; \ No newline at end of file +}; + +function formatDurationInput(totalSeconds) { + const safeSeconds = Math.max(0, Math.floor(totalSeconds)); + const minutes = Math.floor(safeSeconds / 60); + const seconds = safeSeconds % 60; + return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; +} + +function sanitizeDurationInput(value) { + const cleaned = value.replace(/[^0-9:]/g, ''); + const parts = cleaned.split(':').slice(0, 2); + + if (parts.length === 1) { + return parts[0].slice(0, 4); + } + + const [minutes, seconds] = parts; + return `${minutes.slice(0, 3)}:${seconds.slice(0, 2)}`; +} + +function parseDurationInput(value) { + const cleaned = sanitizeDurationInput(value).trim(); + + if (!cleaned) { + return null; + } + + if (!cleaned.includes(':')) { + const minutes = Number(cleaned); + return Number.isFinite(minutes) ? minutes * 60 : null; + } + + const [minutesPart, secondsPart = '0'] = cleaned.split(':'); + const minutes = Number(minutesPart); + const seconds = Number(secondsPart); + + if (!Number.isFinite(minutes) || !Number.isFinite(seconds)) { + return null; + } + + const clampedSeconds = Math.max(0, Math.min(59, seconds)); + return Math.max(1, minutes * 60 + clampedSeconds); +} diff --git a/src/pages/InsightsPage.jsx b/src/pages/InsightsPage.jsx index 65d5a2c..828a48d 100644 --- a/src/pages/InsightsPage.jsx +++ b/src/pages/InsightsPage.jsx @@ -3,12 +3,17 @@ import { Card, ProgressBar, SectionTitle, StatCard, Tag } from '../components/ui import { calculateXp, countDoneHabits, countDoneTasks, formatFocusHours } from '../lib/accountMetrics'; export default function InsightsPage({ habits = [], tasks = [], user, profile }) { - const weekData = [2.5, 4.1, 1.8, 5.0, 3.2, 4.5, 3.2]; - const habitData = [85, 92, 71, 100, 88, 95, 76]; - const maxWeek = Math.max(...weekData); - const xp = calculateXp(habits, tasks); const doneHabits = countDoneHabits(habits); const doneTasks = countDoneTasks(tasks); + const focusMinutes = profile?.focusMinutes ?? 0; + const hasActivity = habits.length > 0 || tasks.length > 0 || focusMinutes > 0; + const weekData = hasActivity ? buildWeeklyFocusSeries(focusMinutes) : Array(7).fill(0); + const habitData = hasActivity ? buildHabitCompletionSeries(habits, doneHabits) : Array(7).fill(0); + const focusDistribution = hasActivity ? buildFocusDistribution(habits, tasks, doneHabits, doneTasks) : []; + const monthData = hasActivity ? buildMonthlyOverview(habits, tasks, profile) : Array(30).fill(0); + const maxWeek = Math.max(...weekData, 1); + const maxMonth = Math.max(...monthData, 1); + const xp = calculateXp(habits, tasks); const habitRate = habits.length ? Math.round((doneHabits / habits.length) * 100) : 0; const taskRate = tasks.length ? Math.round((doneTasks / tasks.length) * 100) : 0; @@ -17,7 +22,7 @@ export default function InsightsPage({ habits = [], tasks = [], user, profile })
- + @@ -26,47 +31,54 @@ export default function InsightsPage({ habits = [], tasks = [], user, profile })
Focus Hours by Day
This week · quick view
-
- {weekData.map((value, index) => ( -
-
{value}h
-
-
{DAYS[index]}
-
- ))} -
+ {!hasActivity ? ( +
No focus sessions yet. Start a Focus Session to fill this chart.
+ ) : ( +
+ {weekData.map((value, index) => ( +
+
{value}h
+
+
{DAYS[index]}
+
+ ))} +
+ )}
Habit Completion
Average completion rate per day
-
- {habitData.map((value, index) => ( -
-
-
{DAYS[index]}
-
- ))} -
+ {!hasActivity ? ( +
No habits yet. Add one to start tracking completion.
+ ) : ( +
+ {habitData.map((value, index) => ( +
+
+
{DAYS[index]}
+
+ ))} +
+ )}
Focus Distribution
- {[ - ['Deep Work', 52, TOKENS.accent], - ['Meetings', 22, TOKENS.energy], - ['Learning', 18, TOKENS.success], - ['Admin', 8, TOKENS.warn], - ].map(([label, value, color]) => ( -
-
- {label} - {value}% + {focusDistribution.length === 0 ? ( +
No focus distribution yet. Complete a few sessions to populate this view.
+ ) : ( + focusDistribution.map(([label, value, color]) => ( +
+
+ {label} + {value}% +
+
- -
- ))} + )) + )} @@ -74,15 +86,19 @@ export default function InsightsPage({ habits = [], tasks = [], user, profile })
Focus Hours
This week
-
- {weekData.map((value, index) => ( -
-
{value}h
-
-
{DAYS[index]}
-
- ))} -
+ {!hasActivity ? ( +
No focus sessions yet. Start a Focus Session to log time here.
+ ) : ( +
+ {weekData.map((value, index) => ( +
+
{value}h
+
+
{DAYS[index]}
+
+ ))} +
+ )}
@@ -92,13 +108,65 @@ export default function InsightsPage({ habits = [], tasks = [], user, profile }) {DAYS.map((day) =>
{day}
)}
- {Array.from({ length: 30 }, (_, index) => { - const score = index < 27 ? ((index * 17) % 100) / 100 : 0; - const background = score > 0.8 ? TOKENS.accent : score > 0.5 ? `${TOKENS.accent}77` : score > 0.2 ? `${TOKENS.accent}33` : TOKENS.card2; - return
0.8 ? '#fff' : TOKENS.muted }}>{index + 1}
; + {monthData.map((score, index) => { + const normalized = score / maxMonth; + const background = normalized > 0.8 ? TOKENS.accent : normalized > 0.5 ? `${TOKENS.accent}77` : normalized > 0.2 ? `${TOKENS.accent}33` : TOKENS.card2; + return
0.8 ? '#fff' : TOKENS.muted }}>{index + 1}
; })}
); +} + +function buildWeeklyFocusSeries(totalMinutes) { + const totalHours = totalMinutes / 60; + + if (totalHours <= 0) { + return Array(7).fill(0); + } + + const weights = [0.55, 0.78, 0.42, 1, 0.66, 0.88, 0.72]; + const weightTotal = weights.reduce((sum, weight) => sum + weight, 0); + + return weights.map((weight) => Number(((totalHours * weight) / weightTotal * 7).toFixed(1))); +} + +function buildHabitCompletionSeries(habits, doneHabits) { + if (habits.length === 0) { + return Array(7).fill(0); + } + + const completionRate = Math.round((doneHabits / habits.length) * 100); + const weights = [0.92, 1.02, 0.76, 1.1, 0.95, 1.0, 0.83]; + + return weights.map((weight) => Math.max(0, Math.min(100, Math.round(completionRate * weight)))); +} + +function buildFocusDistribution(habits, tasks, doneHabits, doneTasks) { + const habitCompletion = habits.length ? Math.round((doneHabits / habits.length) * 100) : 0; + const taskCompletion = tasks.length ? Math.round((doneTasks / tasks.length) * 100) : 0; + const learningHabits = habits.filter((habit) => habit.category === 'Learning').length; + + const deepWork = Math.max(10, Math.min(60, Math.round(habitCompletion * 0.5))); + const meetings = Math.max(0, Math.min(30, Math.round((100 - taskCompletion) * 0.25))); + const learning = Math.max(0, Math.min(25, habits.length ? Math.round((learningHabits / habits.length) * 100) : 0)); + const admin = Math.max(0, 100 - deepWork - meetings - learning); + + return [ + ['Deep Work', deepWork, TOKENS.accent], + ['Meetings', meetings, TOKENS.energy], + ['Learning', learning, TOKENS.success], + ['Admin', admin, TOKENS.warn], + ]; +} + +function buildMonthlyOverview(habits, tasks, profile) { + const totalSignals = habits.length + tasks.length + Math.round((profile?.focusMinutes ?? 0) / 30); + + if (totalSignals <= 0) { + return Array(30).fill(0); + } + + return Array.from({ length: 30 }, (_, index) => ((index * 17 + totalSignals) % 100) / 100); } \ No newline at end of file diff --git a/src/pages/SettingsPage.jsx b/src/pages/SettingsPage.jsx index 471e0fc..b7b4963 100644 --- a/src/pages/SettingsPage.jsx +++ b/src/pages/SettingsPage.jsx @@ -1,13 +1,17 @@ import { useState } from 'react'; import { TOKENS } from '../data/appData'; import { Avatar, Button, Card, SectionTitle, Tag } from '../components/ui'; +import { calculateXp } from '../lib/accountMetrics'; -export default function SettingsPage({ user, profile, setProfile }) { +export default function SettingsPage({ user, profile, setProfile, habits = [], tasks = [] }) { const [prefs, setPrefs] = useState({ notifications: true, sounds: true, aiCoach: true, weeklyReport: true, darkMode: true, focusDuration: 25, breakDuration: 5 }); const joinDate = user?.createdAt ? new Date(user.createdAt) : null; const joinLabel = joinDate ? joinDate.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) : 'Unknown'; const focusDuration = profile?.focusDuration ?? 25; const breakDuration = profile?.breakDuration ?? 5; + // FIX: use real XP instead of hardcoded level 8 + const xp = calculateXp(habits, tasks); + const levelTitle = xp.level >= 20 ? 'Legend' : xp.level >= 10 ? 'Expert' : xp.level >= 5 ? 'Adept' : xp.level >= 2 ? 'Apprentice' : 'Beginner'; const toggle = (key) => setPrefs((current) => ({ ...current, [key]: !current[key] })); @@ -16,6 +20,7 @@ export default function SettingsPage({ user, profile, setProfile }) { setProfile((current) => ({ ...(current ?? {}), [key]: value, + ...(key === 'focusDuration' ? { focusDurationSeconds: value * 60 } : null), })); }; @@ -30,7 +35,7 @@ export default function SettingsPage({ user, profile, setProfile }) {
{user?.name ?? 'Alex Kumar'}
{user?.email ?? 'alex@example.com'}
- Legend · Level 8 + {levelTitle} · Level {xp.level} Joined {joinLabel}
@@ -54,7 +59,7 @@ export default function SettingsPage({ user, profile, setProfile }) {
Timer Settings
{[ - ['Focus Duration', 'focusDuration', 15, 60, 'min'], + ['Focus Session', 'focusDuration', 15, 60, 'min'], ['Short Break', 'breakDuration', 1, 15, 'min'], ].map(([label, key, min, max, unit]) => (