From db39eeea556d331aca4877a91b3eed621f81936f Mon Sep 17 00:00:00 2001 From: Stefan Dresselhaus Date: Tue, 10 Jan 2023 23:55:38 +0100 Subject: [PATCH] defined & added repeat-patterns. --- README.md | 12 ++-- img/2023-01-10_repeat_patterns.png | Bin 0 -> 45293 bytes lib/addReminder.dart | 3 +- lib/homescreen.dart | 10 +-- lib/parser/todotxt.dart | 8 ++- lib/repeating_task.dart | 17 +++-- lib/types/repeat.dart | 97 +++++++++++++++++++++++++++++ lib/types/tasks.dart | 42 +++++++++++++ pubspec.lock | 2 +- pubspec.yaml | 1 + 10 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 img/2023-01-10_repeat_patterns.png create mode 100644 lib/types/repeat.dart diff --git a/README.md b/README.md index ed45bca..5a9b7ed 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ A Reminder based on todo.txt synced via nextcloud ## Current todos: -- [ ] make repeat-datatype (like: daily, weekly on mo/th/fr, bi-monthly, etc.) - - [ ] define isomorphism for 'repeat:'-meta-tag +- [x] make repeat-datatype (like: daily, weekly on mo/th/fr, bi-monthly, etc.) + - [x] define isomorphism for 'repeat:'-meta-tag - [ ] add interface for repeat-datatype in addReminder.dart - [x] save/load data to/from disk - [x] adding/removing tasks -- [ ] respect ordering that was used when starting the app when saving. +- [x] respect ordering that was used when starting the app when saving. - [ ] add Nextcloud-login for getting a Token - [ ] use webdav for synchronizing with Nextcloud using that token - [ ] sorting by "next up", "priority" @@ -28,6 +28,10 @@ A Reminder based on todo.txt synced via nextcloud ### Adding Tasks ![](img/2023-01-08_addTask.png) +(still missing repeat-options, currently defaults to daily.) ### Details/Removing tasks -![](img/2023-01-10_Task_details.png) \ No newline at end of file +![](img/2023-01-10_Task_details.png) + +### Complex repeat patterns +![](img/2023-01-10_repeat_patterns.png) \ No newline at end of file diff --git a/img/2023-01-10_repeat_patterns.png b/img/2023-01-10_repeat_patterns.png new file mode 100644 index 0000000000000000000000000000000000000000..e54d7c399f974891e92f3903f826d41b1bdc1c8d GIT binary patch literal 45293 zcmeFZXIN8PyETlsqkDshZV^xfY$z?Df}jWlML?v3w9o~lgN1;!fS_2AB2_@?ReA{} zp^AclfDi~ZfI?`Y89JnVbK&0SI?r>;^?q+T@A>im@WQODwdP!N&3WJB9%IbB)YepC zV>!;k#Kgp=dh4bx6VqM<`1kDhec;H=-%Pc^pFNLsRcsi2r?J1|Fnqtn=pT&|UL9wA4^%b1^_pCG`{dm_)FW&!n3Y3czRW+J^1Dv@^-#gzI$R}Br92Jz z^YY6d{8EQ5GqgR+e2$zvyGX46h+QFX#BWR5b>1;do-2%>jrW$De!yquuk~I=-^?so zKHD2h-%4gwUlSUCc}BH#YDwkXbEhIA<}!woGZ8sy#vteTK)nyplsxShn$}>qFvdS^ z&h~^II+l7;X0xPWdijlO|Iislf#t0^!}Gik9Rb=uHKkHHlDPkDGifqPOVgbCgUhb4 zh-9(d6L)T+CET+>X>6NNIpSNgc9TRgF{C~~@t08?d0oyF2`H0?9u__REHWbLk4wm+ z{^Y!7;B(p z;keDxXsxSk#=~TfAqUs1eb3j;IMj0solTIP_DQiAuMZ+VoVQyPw+?SY{jO?bLu=;1 zF0nGEyC*l1-zI|b4R#&kDra#A!)Ipq#Z_#7^&47>edqdD^|HAV9@^Z($+| zlOUM8)`S!)uVLOxEH+WoxU~{(afan?Z`%)Xi3dMEZA%@$>OK>}dQ&}p;kolwC;bwd z?#W3vy#l$rq|!CzaJ~hkXQ|+e5)wws;JKFkmd(Sdcss0BH~mu~{R~dbf+JWwRzqCZ^IZAI5U01ct<74C7;E*B462#a6D>X%GvQLI&2?RWU9ygZ z|MGtSh=UmA#%J{ww`odnjnJIFR`DQ|^l#9;a5=7SEZ)%snweqgmO>osW3)*KieAXc z)FDep+-CLVIBCRH6@hgYx=_04mX_%2^z#rZs>~o()NxST>3RL@ifm3!okKP&)WZ8L zzSM`tTxCYa!wcfVc^2~ZBQ5;?zD=&~pq+;MT(qy@?+_K&jwMP3%p6NmVXTi%D)tkT zWFKx?_?)XyEjWa|Ug>Iln}wTWGiN7m%49>DRg>d_!&TyP9`0@6852YHjpx0T2OC7s z{y3e=3*^O2tHfzfHP-e%7P+noH^ZG?{?&I;Sk@trUb)Vk#oo1!DIsXM^xy0_xf%2A zgrBXRx6@Kxthdv8I6j(up0O5vxD~IpnLb&up{{oB^>(_u5ICJ_M)X+_|5giQW7vk! z;&IlW@mMP){L?mlp?jZSG@S3(+eDgHV>mviEBU27BM*7Fe)hV z!dz}ELBJnb&Gb7sL1EhI>L%2YfYgj{?7P=AXe%x61xHf;{2dMcFx_Ep+zmmuPwt+m z{l{-08Z$8oKN;T-{wN5z%S}j7lXs&>6F>YPzdJ;QPR;o(aQEvNh5uhS{y%YX@Xh6w z+G_u3DrJEIAG}ZJ&(hP*vK6QK8CDiu^|O)5lwIoWA$EsAMrpXQYprN=Z~r9;4ij7ROW%cB$7<%-qxfsThnuo0<&8>_s%+XVDfJ^{zvtfOV5|ea=PZodH8be7lMW0ELm8>^nsEm$)g-w^q1GIPa}ibC zds{D3Li5BMs(%YxhxgmHenzb93f5nB6f=S7f#yNOvSOt)G_*0_)?Rl}A9>1{zQ9(` zUVZZoK`8b48SIa0nlo6BWjr!{IG1yHjS%B6-}8R{+NMS8n!nH4t;I9-kMOVgs{Cmg zZ(3Db!f%D;+4^mc;i889*OFV+&aak>5ozr8YEz@@OS3(nS2l9<%nd?fTolc|M`za~ z(p=Gw3o^Rx+wigNjY+k#QrwQ8YuB4eYs8hvu(d2P54ZO{_>M(36S~}1UL5^;GHqw_ zHR6`JQJ%%Hc;Dx-5&v?-B##4knnMxS5~!aY>f>Zr>cj8b;+DQGMb>XN*W+Z6+te{n zxZd4%bcKPuHR`+DSl7-_@`(psdxhM#NN#kI>ZzUj1-*K7y#78^_Rerny_%Rz`n2(B zjM&!42^W(2&V+S~SXLnzq5y7qB~{iOcdS3OMCV)T&%KPHm5~>&ScE){eT1#tH5j#0 zm{DkzkmZGJw%<(P+8D_&8BaGPUI|A#j-AZ3r=N<^Yv*ChqYjC0eXLa>=DC(Hc%39| zL?Ta~^IvJu@eC?Nl`knz+-9r}yWcp%qWySoi&V z4_bZI!@SI9_5*$_4R_)k8+GcC=A>Rqo5|WC7Bci)f@xz(TP3ar!|1K#TIM}$AP2ik zI5}@EQHe|5@FL4kZmAcQR@|OpEe1QPP2*LNnPKOXrcQ$#ozVfo$E$^<|Wa%P(0;gHuOs+g%YRdVAE0Zf@D-|x02cDrIRL0S5?*1(R^ZS>6{uv&@c`bkBAksYn&fssPJ?f^K zWG4O`=35-B!Z-^SQ-UHrp4AuMGo!AWzM(z(ww(M_ej?n*lcvj6rkwvwSklYgltit6 zx9AhwQpF(XB|T5NLSVi}->UR$m%7O2Y$}2*4maqU`^fd9e+D%DEe!n!I$!BzY<&$z zcTy<9{~G-}W3A2$@%D&)bR%;`GJ^C!nB4b zv?~gg^m$-;&&i{ z*rqTzbPzr7b%G}RRtwIRwtto8>UdmUoXu!{>mX*`NPb#=V#6E8V3iGdq@E|Jv1nH3`4s{EGQcx%MTYLG#wBMb$Z5@{SPRV==9F)h}2p-ETTC)Ko8ydYAnjIJpHwL|A zvUS`M(__r{ppnK;LUb&DCcS5TPa4zSkm%6s39Uto86({0^_&9G%>&H5Gz6F2m!f2! zPVd+Zdpbea1}-ucg_x`D@Xz}!?dVrE`88==iAbF9pImj^+9Zxinju;X9tzrbhjV_S zCnswY(7C28J$GU|X4x;eC$Nuf@fZ3EXEW=f^m`u+Q0{wh$)TL^KMB?8GI;q9qmqSK z2#vK7K&r{G7=*^O;es;bG}P<=1}Po8SUsJzI7VNuRQ2@ql=%bdR&a75R0Ax~yBJh0 zE~+~Ul^F%09LvYE-s4a9WBoU9W0~pDnHOYHG~yV|tPnE6Wwbu4;A5&%`sVgYx<|JO^dguH>TK>rN+*wsg#?v|zfY zU-mr^SvyhY!o-wt>}SJX_Otjb4YdmA!AN_f*{4S|Z`tkTzV-f3K~zuZy~lfr{Lzdb zpF@bDJJa$T)$ViS$6r|p=GM49ZsM6s7NAeRoZ3p3IC4&X=B+qLwtd$DxQ+4LT(;V1 z<3cRxjN=6@hpQiDC%TE%uJ+h`esy$~8xTV2R?F#byahft2+~E{&7D)Wem>c5VYIca zV0QY}p(HIw+b=SPe5w={7kSm ze&O7u{2*oNIAf|eTmMS?Y?mP!pKn|iX@>Kto<-M6$!K;+UeiR^8Q6KSz2T}Ehts$QDYPKh{)lPmT-d(e6OA0mDYd-yoXf%TAH>>SD z1KTH4e|Ac?+%4_0#q`ge(TzHHS9T42O(|C9*)VlR1u@5*5E0|m_d$ORTlM3W$Vkd^B%yJJA7u5@`$%pJ`0a`VO~j;z*9M4w;3 zGU$tX-Xn89*|(I3%cUhu=WTKu$LJUJOf6{U=JbU4`m-PiuQbMDTvwfIt--nj^Q;%EK%p+wfU(UE*A^YMro)L4% z!QF^(_oPAT2Bj{=4lc%&1i874_q){EhX={^McMB?khNl^Gr{URHnxUn&J(284~G6m z)CaKRJ%Txo9`7h%Rt;4wBnxU^dAw{XLoj?hmS?^u?1@KK+-p%KR=j5B6)7u>8bZ9s zH3y^SIlhI=AyIQnJ~$5br&|sQE*8^Tqds4X+LuR;_z#M*p@ zmilvVdoNV_^~=wu6(5TYNPoVKed)E@t%AQ=i>sIk&i>++lXwi_=F-o|x+-dTEP<4p zXe|=%nvhs4UfxBQpV=po$Eqzz_M69dBqSF}ZgY-qwm)wX(kh#n^px(o=oDKt*Ad&_ zanIk>B!M@3d0&59zI8g;mJ>!_7l;TvNmPhaEx4DO??B&*GK>pdPd^O%o%2>m=Nq4; z+DdantNR5mmt~~yR=AK1C|xZzz8VI#lYL6*8>#CWEqB_Tuzsq)GtH>SH)?I365rNt z#pSZrA7yjvbl2;fzjvT7W94I=P(_BAWm@7N#NL6`<>6uN$9&twd!k#?c6%G$K7W(` zf{wq7R9xV>huA7$DWURc`8_I3yiCk7PU@KC%}%3EWGt%P^$LdD8dD#d2dDHD>~FKQk{9c0*W4=H71Q1Nn39PH=1#B- zZlyEbk}O>L_UYYo>|uwPP9L9{>hAl3BU!G2t867YCo}B+`081|Lv)|vW;Aa-6Zf?$ zvXk`vz@C?=ZBV<7%H&aHH0$kfP{@~-uDqN}?`E?oo5)DimGiMGWo85K^Q(Axp|uBm z<$2=EtD2!RZ)auK$h}3;hi5%sQU(5%S=-rib{CZPl2@BtZb&ZeAq zbL-YCAMHHdALU|uWm&n8^Pa~Yb8|m4Hh)D(%goxjj^F)---Ek*vgM|&+C?s7|8UhW zn}}9vQE%xSJD*IvwIjV^>|T>!r{D6yg4fLl0R~1H$Lod4rF}z5j=gkR=tWdv9d9>Ud{`G-Ue=4V1Xr-~LUWiAk~jZ_4g^{qd_0ZDas|54dzf&RdfA zhR)jf^TayP|Ceu@cv`rc z_P`O`4`ap5=FAQAjlP?QIC}c6ivR0VDj$8L;AN2i{$RwgqVIJi#5j*sUE~!ROI3Ux zSy)(T?l9f?e%2H!3xYDWm&@*d|2SEQqm4af6N}cO?aF9SZ-PT+##IWq zSUE*+tuG8uW5Z_8ZByFCi#!*4+=&rR+gTckb9gRs^LOeAlC2&6+X+&B+pCiOcR6H@ z>eOOIXOEn9*ak0-s6h?my*AfA$L~0M50OElia8GPmo$9La^n9;V_z7py>@lwtAtrV zsa4ZHX${+p)-7QL3~Ofwv5#&ha@gSvh9w22})sqxCo^liC$3T{u zHPZDDYe7m;nVjgMvfBF%gV6+S=vTakKch9ssmil0{L-`T&SO=g@(qxZ7GF@j!K77JEhYW z$jrsNX)Yh0-Ln0CP@@hmLM9ZDk36=4+ksa!6&Mpy&p0KAPhZF(DHHoRHeV7-tepCE zjC-GTaG5NMvQ+W;t?Ed>tF)Lqms4uIAq^e}G}mxnM{u({w2E)akn1whhP=g5?-P@x zrDJ(_BEilKGoNLOFLV7GiY*el-!qvrpH=1S1WS9aOCatC!mFvbv!?c z6jr5~8w`)t{52DAG={r=LY;9V4m*!Tx~?CM*u+y6nz0q1N50vWD4hPPIC08Evo&cy z%QIX3Z+D>v8w5re5wUv3cGsV0<`?=4N0FAmq>rXP%#%f%ZBNkA_E((h%kw+9V*1uA z2hk9F&~&~3%^4Nb$qNrBZ%L=>3BCBn=6$VKIL#p4W2JE%iFJ37=}kH+VvwOYbN0m8 z_t1%JH4mUTMH(6zh3OB(`fNqP4}4T6n$_f&H?xPp(YE`mGu`gL zEA<8OyXry#u2W?hFO#$dUGZ;Zr2oPU)7{wh@fm9rh~e_H-%=G_NBuU4abkn=q~Wh0 z^z$N(%kE`b*SdgUFC6YMKT?f%QQR@lqKiR-i?%+vIN`EW#6vA73> zF}%ROQ9^-<*`Ys&${qA%di@QG%-^4oef+IY?ONNx6VNl;kbe!EGDvXeB-1UeyOQKu zL0OC!l9OIuneNg$r;!k?=@5=Ya2Szv+QXqbqn7y)?9br}7Z5OwdnCg>K1E+tHuAJ3 zU3&**#>J{i>wn3Lpos&#D&c$@&$aJ3bWu-Sx!*vn5;3+sJ(q9~PZPU)yrR(hyG&h; zmtK~-Dirduqwy#*L16m5r@0J4anBnUl~y-+>4U`c2KVY~a|G1zeeboN zd}fm#8E-ynWQ$V8%lf>RunS{#?2Sx$AQ02at~u5Do}Bf3CzUe~#>#niXMN$(noYiJ zLZQr`u+yiGl1eu2M8@doqw!?0(Zdpv;Tq{7lvuDz;L5xKz85WvwbFsG}BHKM!Po z@0i>-fEN&eGC_-X+vHMSh2hf}mFw@4oc@H}WI0qIhUrRx3>YUh9U8SbVe*O6ZiSTw zf(E%`L zrHMLkwWhmTdW$tB<+i5V`S!-Z^PZ8uN_5TRGc^m&C75$!4(0Z>=6p@yR9riP$7UD^ zk(nVPGo=d6hVEstHp7TjPe$H=Bhu{du9o%D!}r+eY+NAubzYs$&A)9 zH7Ue3F!S~uL7<3O^wK)?+)VES{t}1(^HqIAWglXjaha7%OugmDtpC`pJTjR-b(^80 zvWu-orjSH2aJK+@|HZ~|m{^d~^)UM3xyGRVQDFIb57l@*Ds}Ap@Jkt2)Ni3i>A?^z zQa9m(Ai=2-@{K2&t&RDV`VB+61ma91od-)l!>&V^2hSyHG)~c8mauJ$w%J~tb@e_| z5XqvqRAD(Dq`fxDAKWWBD_=F`sdUg{HH?Yaf0hBgUKU zI^PY}x{cLs7i(~ZJ};jSgt7LNB-MmYIrxG&RNGv(iFX<3G9i`w9`7y{E{YunGgoHK zsQPjj1@G(9vaU5DB`#VywY6s3^rMJtDt9(kMcoX*xD=Ur`ujVwN6}MuKYx5))F(DL zO0Tp+xNH+l^~k;Z4_3v76_`|Fr|t4FHzo+ocMEtR@Hr9M%N*b>U8Wj!uKIz~+Omm3 zg3i^xgd_O76hNN~Of-i+Y7$=Bg+`lj7{)TQZtT(2S5-ox89Df~_=d6F`?V}Jrt zPr5dLPLQ{x(iLvD&l;bAu^T@LV&;LlviRovBw|0tuaWz4CqEosa1*&paJmx*ZprjY zNN%%)XGIxtxPVEy!ew~MJk*s!Yq(i(TB@*Sl^RNNDUb-Qc%y{4krMl%)@LJ2FRWWa zjwOskFgLRq8O^~lSj@2ApD5*W`?)tVwRf)Xb*#=I+tt@vWorq20-%9_$Fv^Gqb4@# zs=|8&{dV*LtM&Q8H8ImuFy@48%NxCZ>h%p-wlQ%O4w!IkC8lTcC+>?-@y{UcbXOFM zd+(*pld1(GbFo=sXb`T^%C;EUzW4BV$x7`;mYL-~8;dz>$A7hRS7s`^@Y<6kR+eNX zU8gtv89ASoId;>`-q2*Mt66#$JLEvI{R5axND6<3gr%zAfV!Nb-6Cr;RB>Y(;sTim4AD_({U2Gd0 z%YJ{&GwV@XD%GF>854Fnn*z$bZZ@ana<}gnKz{;$qy_QAPR3cFy?Thmg&q)n)Yv)p zMXswfc2Y>~J_~s3aJg8qi&r4-`)j-eVAH`>+Oad^(+yAdLN2kMlC#I;yxlK>>c`!A z#<;@SxD?D`o1P5S+2|y{)63v=rr>N)OI`mMDWEoIR(fM@$kwcd>T2%D+cu}0AZmuzj^9K1w zbo}i#&%(qC&n0uNlQ}!_IVMCffW-Ux%3jZ@4T`pS`GtX!Gw*vmlY4nx7ltsdRbOh9 zLO3%)Wi0prV;`JJ*SKdCeP z&*uDxY-kAHbbsnBW2LJx#XrH3;jiKVvhwV^#&nqyil}MTh4({mV_Wm=pw126{sX%RKfw+A+Sv5Bx>LE zrZeuIq2-8ImSGu`jdDF)`y7Yvy zF0+AK=cIjX498^6>@$P^X_w@c#Up*((6cI^$qr=O!e@%o>-VUeKMO_PcVp${imZDJ z+8Iv*j94T&9&dGxKNZcq(N1;dPW>nb++! z*N61-T)k{;>7+}GCjbwtbDD8$))0rwL7-`SQDPR7yJ$vJNvv#G;oK_Pm72?LTOI5(!MS%rI zU<*OG&GqJr*_SHZ1GUDYK8FoNYVxW@?iQu0rIwA%m3{@4D6+xE$QumR{+-xk=+5e3 zc(K*S8x?Xs>t{h}o5N#}_ch)wX*Rg*>$|HGyu!`cK9bHTVa~cWPz1U_kb^oC&xg8h z0%GAM>*fRfA0I-c2hL;RVH2Qx=Z@ZY9x4~&o!g43a=>S0S`Rv#F$^aFXA!3kQax{b zECzb@Oq(n)#2hvYY!-NpDTJt7+IC_vZP78!vIUzeq@eq)_cf)o;kK&TkB`1(Gh3(p zS3TpV`mqyZwe4ajS%1NV{P-C7t+-o>1$e3Z|6A@~d4e zkbo||V1#7ZrQR)b9CC+wz>$E)>y?#+ZVD7%|3fG88o%t7#j1&s-MRBV&x4V4Fg3?} zdGG3ev=ShoQcS5sCgjarCvXqT-%tH-gq4sp0MJL?*rmFio~tw`pai)3=%-=j-Dk9A z2m^p!+CP5`~Xg~WoB9Yiy=eHBt8g)KfFQmHz>pEnu0aBF95!KQM6Uw{A z2?zdRWhJPm1OTO;(g(%#hKO(L5{TVti}tM2&oiiYNHbvZ#|8>uxC_AC($I^mhya+O z(85aX4W(qO&BE-{r`VNglm3exWeyd-UzP~dZdwx+{ISXK?8zm!0kaPN{!+rTuHaA$ zc?2T4?Ski`Xc?Mr~blistUiKmv zJn`c7REl?8Ey#FP4yQCKeU%!6wD2qI(#??YAoC#z3K$L_&cmJ>$jA7DD&9584MbPh zZApTEZlM#r)THv^x zs`;`ahy7_dYBg^4i|zr-4#byCMLCW;#>Sm8WKpiSUjRlo9bDNgxWtm?%OZQ$&EHy( zi39e8b9|nNlQyn?Xj@wsy|If-U+*qixt*felcZd#i$8~{kUcc{K71hY%WAhtSbh9$ z;{%gw;}h2gYb2lhL{UwDfyp$X#IniGY~hvmw^ZMlY^3WA7GEj1QPVML*kPpsdW9oM zRkPY&9NL3)!OM<6e?8TL9XcQL(I2h!Bm{Z?HS#Klq;Y#tAQvjWz3g7canF@P&I8GT zzmeSXO-w{#dm@kCF=k5l0tv>Uq8>o?{5azRLt|q9jSuW{E!NSV>1#l$=+Dlxh?VG) zEgOX$1btTcqcJ>3>AG28en?+$uAUidm}`wo0`{HphA8VvNh15{n+1v$Vc7gFV*4j- z^5CTs_&LXg64bq}Bs1}#ZVwJodpg9b3{&v-{z?U=Qd-w_)Hg1}o_mM2Q1tril*z{0 z=_Cp>&q8vNTB+-++a+BB(3Eb{*(K5SzCZ%s(^TaG5td86y3imV@cb1WdL!7;y=m#O zC!7v{T=rbR^b`EQr0LK7csytumuU@7RNUXFMZP_|E*0^SVU}+3;LLJvtjAt{Ap1dg zfh*RL_V<;!&+2Yq?|x?4K;FTTK@>S~4v9uePySN)QjY%9CWcj~WoyQ?3PShW>)7@* z6qlIk+b~Raw^Un(Me+oH2=q?gXIljE)6zQ@7hN~BWT8i~ywJS>fe{4(4i$oDEu$L1Ln%;A;tbw<-jE=gmdV$^yB-TQdu!$FVZE@#A(2fT#OfExsK z-l-x104Y}}G7JTY-BrM{Z&!CQa{$SsmiafG<%`zMuOSK1H6BPmXMvcdF}?n!%>-gp zVk^BMP6i*79SqkJaA{%>yNU0EX_Z#IiPL)HWxTT+d?h#zqB+IQ=grqngcD~(Qj9=G ztA#;1&^5sg5PlGsO}_qRbrv55giEYdR7|C)QE>xYJR$o5jNd8=2ynrZpght5i4!c! zS?%zAmr0VIjX43>kw6J`AX9Dyf=J%&FCt;b>Ol3C4O|r0Je*~E`*%^``XtGErETOq zIGKr-9X+l>tfjg-8gu05D1FH>F?Hs;i1N|nlIZr{*;w){fJ3;>=|QPinv1>nVXv*p z4kx>0=+XoEx`F(tjRYwdWbJUG?&e4+Ha-{kw!^TpYC!Dn+>}SFKwQ<@YE1`}*|S8L zddjYWk;|RVdr%*Od|l&9nZlH5K{wiG08K^gZFjRHrLgZ7rVSBP;sjI(}v7| z&(rb(?=Rgvh?6>Fm&)%o`NpOr;qolU$uOAs!f9wnh~i;rLhdvMaTDa!9RODTP2RqB z7wZyY-auSzaP0MkU1l_e8=8eFzqZL-F#0D`Z9T<(jScdI=5DK zXCpMk+y`&7p%3!POa_L4K!jtArMoYWH|~O&IPMcH&36up;A=NV6L;$Y?W39d5D=sR z;%pqq<3jHv&w~0-6T&57YtRtR%eyEu>=w6=yl z*1GOwYrY>k|F~5oT!)X#^!|0fYG7!?x$HhX5&#pz+$ArH4OfKyfSVUkNOV{u0-u5G zl%eN65PnLKeGC-NJ*j+X*6_hHJFQat?lgB%)v1oeI8gQg;1~sXOhUg7ohAA;7HhnG z_xc-2VbBoBA34(iCLt@~(10karGgUu65)25rBV}wR9EKX6O@72{v?>j9Z0di+1Ltr zN8-cVbtTpvK-omZrettJOB>uRmpIxhoX#0t<7&lO z<2+o^Q7Z*7=#`B*hI$3_>3XLjsPafXyQ^|*A8|FAKpRTK?4UxdB_YlZs7bXIAbv4f z+B*tu>cmy#Td3=Wyg+IL59gKaU$TU*lyRoMrQ~4L%*LE)HMY>8x)(yAtqN_sOA-YCiTRNuaLa5Ed=nu2 z7cqBxVO{FmD%o}WDD;|{?C;%zA?RIpBC}p6=vL5XqyTP3>@H^0zU=PfM2uMcr2&-u z)8zhp``G^#(DuKy1MTU|xE-JiRSgXdlig>&ostHqZ&58yR(YjdoltYB0EuafNsaoN zaJfB3B%}>lUeg8vLb0v2q6Hg=JLi$+ElMq)x}Z3~y_go13=AD-Avg$J50StFfVIj5 zC@WiSHPZ`uZ^jg}vP3ljml6_#h6 z>DFxAWm$Guoeylz2gHF{~DM}U{y!U?80%?QdprRgg?4| z|J8-k2B0onUBnzCE*F_piU}99>91jz}a3PFOE&*Wk zo}{g-_s11#S!2eC?Mu3uCtG7%9UZ>;YE;^O6f>i5(`DpxP;}VZw{VUv=|2I6t+Fa07ZuGWxHVOnnj2F|k{uRe?I2;# z4If$vst=nQravoxSCP7gd1vqEGS*dToOFC+!=&A*P5_WM)Y9!8;o}6XJiJIY-}hAg zJNktHil}kvr%VG3j;@e5L^oh-;o|1@U}y>_-FDhCuJiShi9U--wCVqI@*1$f@Ki`` zQi1;Gy0J)fH7ei)^5dhXG%?H2r1uU6oF#TKy?6gqBX)4YkpK{=P2^p$wP0<}rUC&S%`)W3?J$1H|YDO;|6BdUP$= zF@BOn{ALGa(RVu~dy<)1X+!aWuOom2E~ad&Lk`u^PTlHYP5`m}Jc!v}oa0;D_4Y&& zTnq=iGkj@;50FFDFv8(UoWJNtEO-#6;DkM_Xs{ESlT!f3>{Ty$uU)9Bq!5WTXTLrq zi+V1y9b!jV(a_xuwYa6v`d# zNrtYe$g1N057Pd_Ls`sf!&w$_!Xa~tct0yMs6|DM@5$IjEpNJV!I=e*mE#9FEX%i} z2=ZXJA6a*^hCQIO_#codd-;b2x4!$nPo6YtnN_+r;A&5W1;zk0tHTEw`Iwk~ZN7aq zlQXV@s8x^Kjlr}h{{bV@@*84X^&Z{-0Jt!KuIsp5_IGWWf{)(T(u6MqWEbWG5A<*T zBjwe6vP^|j4lN4r@l)%5=Q_PZXxSciLg|`Ib+tuEvor0(|BZTD6mow}XoYO2T$0M37Jy5Jv!AK# z2_A5V@c=sFL**320LMe3!%~;t$xA?kh8z{HvTkz8Z6yFVY%rdbyTHr=;i3+0LT?6! zIHEg5QCx@yUOg;Ow1HNg*9z!RGF+DBPN`A*tFcfQ$gwr^`?SzWP`G9CbeeP-v4*vM z2Wn_gyBdceR5Y`xjY4h(rY4KjaY*xoEO|hYk>^ske+;7O?8p_uJGloxZf+cJC+I<< zBgOkFWp@qCiMT=S2Yk=&weaBq;yncjCs->d+n@e*NVDG6^nD50v0OgpDg|;-z;5y) z#{-Cf?T2_}!!kg+xaVZYID(8mYefI63u=vB8LCm+vi@fvxXXHXem|^NSQ3=7(uEn* z9{GUPcj5P3-@8(})x-^?`o*o28tg(TB`A-DArkU~`rnU}i$KY}{m5^!OzMD^ zaqyq$T;5s-yp0#s3fXho_RE3h(&8PtZIE zz&lG3^h>Y_B)?yxV3jIlW0T&+%-(SOD?Mw5% zvP;k)?o@)p>~_m`i-I#WI5Qm2Owb4UWZ$}bdg3G@olY1WWpbDLrIhA8tq9^r?ZH80 zPs!Oq0F-M*VuA}oMgY%4l0QrKZ&$R+NW>;L}nFOp$`KXdB zs2KfR6E4$w)WkKw9Es6Xjf6ZmvVKEh6if|N17?wxsX$H1(HaBdpozh-F-V|(+rY3h zLSbPB=};$`{^d;gDvLH11&l{OD7p#2^;3%*18hzt0MS`aCnOwtGHe)h+N{x!byd<~ z*l7{NLU%7S^cHE&1!w|AeCo3(U`<-{8nPGzQ6!4TwW_fr5ojN^Vi+y7;Z2gbH)ghi z;Wf++v{657WJR`v@CLx>_)PEhki{@C{M@gGyr)#8Td;=>Qchx9`$Ma(Kpit-j>#vKaIz93o=f*5m8r2uyF)j@2+a)};XDceRpn92EckN;f;n;uZ~ldD z4V(nZtQZ2uWU#LQ0sIBhCqONkz;cC{x_F^1P;U}$gsZ}uN4 zZUe=s=KElgju@TMwl4NtmkVcwL$Y=fTofDMkgV@4b|gyUtQHa%xIo`8^hQ&@h6nB? za+A+l?0NRn#5g+t^SKOEd12r_V!53T`B^MJv>Frpg8#M9QI{BPwObP4_fWK+Q-rj& z$20w|lJm<}!!i?FgFR4inT zVMAK6DDp_DS92II8Cmd}&^5Pyu7ZC~GusNr@_`HE+zJ?H<0Vb5o=a9-HTO!_g>0U@ zt{8OYf&3jsR_HmT{o2Uw07%(%53B&YwmG?pGh{EWdbMbzCC9sg(%S?KJcO_obUxX2 z1kUag?^jaY=6f%VF4SSo@m;*yVae36+u3u@0?g?pKh- z{zt;TU8mgvPS_qtFTo)fw!Mmt(PK&wOBD2%Wqj`KxC;Crz3kk~34)9*0&*#Sn1*ny z+0Jn4=*2iQ4`Z2N1K^V{jJ87$rSdqzh6xV8P312Ls?S4?S8_`3%BE52Ga07l8?Apx;9&#}E{-;TxAz1JB# zIr9rb^)-xKh_tzL7>?LOJE9H#%hbf)7;Xo4U$sI-?#10Bs-RLeBdq#cL{kfq$H%H4 z+4&^}hk||a?l3Md=c@t**}fmetP<>qQy)o6M8drPelx$dzS>x>m`3sBlC>_te{LM_ z@vRqaYoTvt+h1#L%dpvcMW~#mW0l(-lVZAJ_1orzb1rSR+mv9nDdaJWqQM7HO%WUf z%oQM903W1l+^71IF;G$@Le?CcwYfgm1lNJ{T1oF9_hU!mCEMGjK--WO&uD0i)x!ei zBx)9)eIC#ZMPr*Hf<}N}z2v<*^OY2eEp!;tH#8%~j^RArWX`KX>5amc`wmzZG+VY4 zBpo6}LUiPDo=YB0ANISb9FI}k(+uM>)lM!%(E^%_L}Iks$^7+0l%eT}Hm8-oyGQrk zY13n*^v0IZ^p4SL*4SH01EF!VyduOw72GT)1Og|0mY&Z*C?@bX*83dpM#ZPGxye@_ zW$~=fo--puu{No``LZ9RI{_Aj_z+0anoyNJLi)Uf%_3ova;Rq1==u79bj(+u%Il4Und>oX*EsHU`3G-}(L(69h|Z;ImUSXnhxOdEg7jZy$&Amy$4bZADaH z7BP+&IekjkpPFATB)o}WK7qLp>pAF1!1rA3_Hg1!a`QFdKD-3-fjRt7mXzK< z|12F>SW!%X6f&E^Qrp7ew;ECTq%!+jD5QM90K}oYd!9xj12_hR?0p@Kf72r5qxVL!uHYPn9_tj7Jp0;A0fa=Q=qXwK2z60)=5zHJI+1zK!t-$R~TEf{63x~kd$AvRa_D$u**l$rtu2>jS zN(*jeMF*`n+{dFPzZ~8m!+udBA}H&2#||*(6(0Sg$QpL_m%=K1m^vUH-w`j-QVWuF z3iqzYikAlh>rwA1J3-w_F*$a{aqxb>VK1RiyyQ3fXql(J3&AX}q>!>vO@OWj?J_<6 zN6X~Xu;0AJh4 z79T(m?SqoF2|zbmYugo*DL3~cSR_}&bFny_SpwvIJwFC1FBD*0R0D?Pg)AX)aEEqs zw+cTBZwtiJwb|QHDULTNG>wPk5Hn$DSspdpwRyfci0+hK`D)V|DNrbo_2P2~7p@=D zuK+iVYGQc-D$&VcTOj4mYJ(Efs6G5DU<@L6(Ksr+3I5l=f8*pp#$dZ0=`=7)(%sHep5uPwF~_$%RZHa8W9a z9UzlI28DXGpG>dyNY#VI%Lj_Zs>TDiONXSOi$4jkeho({B?7l`?X_VLMI!;FUNuWE zyXM8A@RF2m`6b6Ek<#xDGm@8^NH6qc352dnd9h28)%~K#WZt7ST%jrfG978d|I#zR zySfFbA}Si#d7&%pKSwxh=}1?BTB~Ocy!e3I>EJyp7XBj1Y=1)(@aPgpp)*tT|9zzW zbeo;;gy+ZuS4emW=+wvgYXMWY+~%I`z4fPozO5~WUMN6Od!fxF7oHya@4k%-bU4hZ zs8$M4=PErVgnuE3E;8MU{L7LA6|~!`xF_M!fG|%1+YNz>AnG5f_=e^G#B}s;!2Vu{ zvTFq^s;Hq-`NJFAuGF%T3_efpQF=tYC@}u+@}; zI?>%V5>n~orQMRqS?iE550{qv`JAuvExb6i`5lN0v(aY<>-=!-Wxo#xW9vYyzaRw| zE1RZZHZg}J%z*;)T5KH^I0=u-^Ft8A^05Oso*%|B7nXJM28TPK?z=U1)3xi9$iP1} zBv>?Wwmb4V$>}cl&XwH+CbUjSLeQLb0+Df6I}(zBFuy@LpPPQ$YswCI{R;I};0n-w zh3s<>i8=QqvIpA5aJANfw;+$n9;$Dl{e?_|T0)IoUeoX6oJVU0Q5K0HfhS7YwsG`- z77ZqJV_5>C4fA@RX~5N|-#rTB;Rmb_*?Tt>y2!0qBe+w>Z9#p}3ap02svL3x@`1Cl z0OR@L8_0h4q`N{|?H0Dc7i2-(O4`*l*TU?4K$`)M|9X?f0Zy7sBGPdm#ee@Erf;vv{q}{41unaW)f9$A|5*yYc|gs|{|-a{oyFV#tr!1) zZ`uFH|w>poEAPz5eoyaJL1{imG|K`f*-NqYeho+uL%W!E-c zc#cP~9Pn?&eIUto<4wuXmS@qWt}Lm9E|bh`Ovl?vmlb8ba?mDzR1@v&W>UW8*-j<# z+V0Ie_0#g;(&rw0_Xc%FZ3*ROoN_D*Bdl&O_lG3JDKsd$3#5RIv?77u$lum(t_aDr zRdWVyd>4(gVd#w<&H>;*T#&K(u&Da`pT`n2WV5R6MY^b1t0&4E-&SOj_{6k?!F zsO+vW{5ukftovfNrFQug8G*e}So@7uh*CGeEVydRgz6I>1{E z?|PcDqLFDYpWpxHxA%n3Z4Psf#t#B-)YyrpMi)5p;Rvi#uuP&@vy++0=iZrmPXUrQ z+~r3Y?lk^{lSdFq^&D*Sp*c5M7hw%Z7&02d*8TenuW~t0trB*C9-fJy)hivN-fhsz zitL;s!URpl0ywC1fs=N3^b>}Ubd%E~)0D0+gIuYovxR*{B&w|^h z+CX-mtD{ZUgmsTV4qNv_PqlFZVo7XU?!zO^JCln_rSGE98&eWeL);=&^R6Vqc)+}E z%FbWp^(A1uj=`R{N7&t?!(_9eTHOjTDXKiEIsXoT9~(O=XUvvL)Tq(p%Q2~Tc9XTs zH^5p@Njq-lZBa^|w^?a}a96mNbxo(XTcB-pWYmx4eeJ5uE;~T~@Mw$=khtqrIUTRR%H0yw$BS((hYRuQn z3TB;Z92()4xYa?|rf>`c)C!xq=IS}mV0Hrztn;otFqm%_3AALWUMk{-_=M8eyAT6y z-qh&Q+Wr!PQ^xw$0E#M6?irdpwDDy$6#KSc0Ven(9O#%j+j!-MdJ(OZRVw!=eKlD& zTS6}w6tn|X0IsX0V7Mls!>zK@6~lX*+?YSOwUOg`X4v0V`*sLr@Nv5*wKpt!& zd41*BuP-kB{^l7*Wo5m(p<;b>dVIC}Dj?DuYv0C)rU6W(9W2U&J6?zdtRfHf4KiGv zOB;Te&nMmY5bD)#pNRFzJZo0#ON9}<&4Bec=8o-h!(VbKGNFR2F-4H6(j_`$JO1I1 z_R$*E1E~5bTf6g%Z=)8*F?}c&} z^GWAf+;u8m8oahSKX54%$LG$htGRiMhP9>K=_27Dfa9bg z7ge12AM^bv^C!T$4F-~E=y;axe0GoxzdCQFIUWQMA>38$HSJ%nkKFlNl_T;FdrM^e zanz4;T2M*m>On;#J&6vsMn(}5Rh_VDns{)qJ<$%5J{~0616D6$`k0P8YVW^--^MD$ z?``LRq~CzsJMvEVXh6v)(s?iC zJ;Kf0e7XpbsoAGq9SxXfr9^FdUCZ$R6L)u)nJm@(zgYlO{B)+5y~n-hkGa&5?kqiO z-l`|02qzvo5)M`lG8qXmr-OU#J$IeP$sRKa4v|1ty(GXF9iB7(7bvr4F^>`4tXx!k zT>tJsz8p2`gjz-wdQ2@){N9L&d^EMvCJPE)SpesTOrL6-bW8At)1>|tJyFtCplhdQ zE7;75;lF?GK%bVPTm%@+BPO~q8_Vr>QKoxD1gwxbqnSZY>NaYX0NzM+%Zm&!qDfou zt(>8gc0;({?a>%Vig|dgq;oIy@ZO5?dZi}Kkx0?(o$HIFyuv?q!;wl8biBI&@i)!?e(cz*V-cI zE+50J&LH~BybTsNJ+#{*9qenTZ8PZ=H^p^AyEwF-Jg$Q2wdw{QyB3)F> zX1|8MI5tu)$lxfS!jds?UCk>424+^XxmFWqoH?Q|)D(YV=_EwM26Ywdv%I<1TxC5Z8VUx9HMkVGQn|wj=Uhz!7?jucPel=OpKVt{u za_=zOAh=MZp)PZ$hB&->T!xvI*%Ee_PRGlZI3(|m#G#(E!dg>I@7n|S8@*;D0_%>) z-mRUVwF#7}(#6k0H+@xu(LoZP5DJwf453#lCJ;DTYi9(UfP~eQifmSO+cRl?!r>1L z9e5Wz_h!8jN7~H~yVI>26Dm=HI0(xQ>CER7v7{(LNBlsW9aLff?gA0zEI4U??nD(@ zsGH?g_Px4(Rl2oD;=gZ!mfXF-b?3K8!e&1B0_09IlRpOva*JjhRSfel85Ha`COL-Q zFhXkeI%yvXZJXyFU$P?{YuCjDVYzRiSPuY{As$j2W-ixbGg1ERbKp{^SpPaZcERA% z@>H|=kHbK@aPD6o;gaQUjuK=kZ~k6Fr>U$bfkJOGnCCb?NIC`;f9Bk2ucx!0b#>UG zv?3-~3HjdWQ~}3>4&3J^Ya3HDgGBM>9Wfc+5|!xG@MApGS|C2@!o^LF)d_~0Y{?%v zui9lBpy@G}PZ2T~^36)Qo*OD)Ej`Mi#jz+| zSZ2eT1(kZL?IfOQwp2Us9AC_s>0Vj_9Jv}6wU-_s@9W4u^-qd;Pe2+=9;o|GVQB1S zM8p(;dxU5ae*WoWSm9&lXy-6(X~J{W)+ z^8*VF+^c^DaaqwFzr|tb+V>}?;&CELg&$eiB7b3!ePXo)4X!m)ElRGB?YIBw1D|k?skm58c ztz4RvWI+Tc<3H|pDLi;=uqt_?#g^)S@kaP!{zu5-Di~E2#b}FXxX7c%_0N^U4LQ2| z5|iS&>x5Gvo9ZA&p)cuO9>j*d!8UZY^w=3No{&-~r-ROqF6;{)b+RGK1vKVQpeQ!H zpf34pwNme^?3U2*`#04Y%C?Htx8zyl292Wz$vq(5w>NRFTWEJ9weJN{d4AM^u6|Jb z)geO%Vu#&4B2eH;gd3Cw-!tl>6}2`qfG+SDs7;$KduZzwFei0_JMhu78AXaKx%~T^ z%@2jac>nY8CjX#CQd{Th-4pcD$SCeAUh+Gj%>==C?K1-1hn~Q5@7)?_`;YPd^UljD z+Tn#iYs>PjCf@>jC-Cq-4aiY76Carr#`8t*;)P1uIWmX(h*0ev7|qr;r_!r9{$uYF zC*nrMYJx72o)&jJ(1kR-fAK264-T@LM757?q7$JbU2=m0fGU(GfR>1Klz(u?DMGHd zS$T>PZ(x#=mIg9?UCfx=$hS(EfQo~-eN94Vh!ilke&@$kbbPAG zp*OsgTR122NNu}QgZFPLe7DEP?q3&8nbrIA#GRqVhAti&w=NCF(>wCKL;A0_RONC0 z@@o{gg3r}E9z9O#9(Y^@TnNhOA1^papuMhCEAl{wdcS@;yi_vbIu@ruuVveUQ5!27 z<3%y*XN`?kzFy}@{v0@+Ow$Kqz?meTkW}55gFG7Q$(4W>g6E_73)dig0eigREDl*0 zCHWSes-cVdY(O)#T}>u0=dmXm>^mz?(rXqGEI|#7w9C<6J$jGYwKmrfuf^8u6VJ#| z{BYLQrkdjfd{CWLFpa+yMucw&XPZh9R*!BGRc|V6=W&Z*($U5Gci1v$D1f#F1FAdW@-m-I_ummg25rBI? zGrqP96Z(WCeMUT{8!0tN-9O{Zb$jv^54?WU)xg@t+0br1bl@SgB1htbpN4km$Znf~ zNaDZwi4hSS+^yPX`=!Y|)r8bcNjYR*2`YPPjn`Q?KiPpq+-Q%NE_L zH7i12ETCX(KPn~+k}XuUk5*Z`;0n~5rtQu{)F}DPhW+1aC6R#WDR-!{c$(_4K&F}p zPTU50u-yYjH<<7u0=dT=||wi8cN@vt(j(S_1vth?7nq$Qn)UdznyTuaWSJ^b#g-(sTm(Z z8Jo-mw7m*!+Hp`#Ie%N9pW#F93-1Zv&V6==IUz^y4vhX1RuB6!z`hP=uk7jjZDP=)Ob`+VWt&<`R@2V!(mhdqW7rKo49u%`oSrvla7lu~h z+S6MLKLJ=mGyDlV+@dpAiw2G~X z*$=0GsU}?>1JHP!q~_^8_s>Dtj$N&XZCGb(AHK`edBgG(_$--5@rra8<~`GeKa|Kb zDd|Q9@E%!tOsW`b`H~8aJL>STDKzk+T{0?9Kp~&u$} z1&3CifxE4`n{KD5)=Dezc90wO7e!(PycK6sGBHyMnw(F-DVzbzy0qJ`?!&v_32Wnp zJvKV&;abo25t;my8M(VqBCWil8$Ul=;#xL}EL&v)z)h6}_C?kOtu76#^j7UJc1|@r zF28*U&5>`vEc3GnmME374e2<->y}q3b+@}_8-=<$p`Tr@gJ3RWL|6Oo2qpz4yhhBh zz5bC02ryWbxmHh)U1&YZ^R3!lQS==tL#Ybe%o1-U?}{Ac9!wGK;EO-v;@7P%W+JcO z?8m?(sH&4cwt}%E`H#{siwd@UgTbbyA#h`jFROp#=rOOED-7v|xcTk8c_dJj=LnWX zoRdohiN1BrG%mq@xQ?!U2!hU`WCv1d^*29Q5w@Bu6cxcUalzQ>*)C4w{fJX$;j9p$ zX~hX4>HK2l=J=gM??aVxVUSN-gc}-8bu@khd)N*U?X`)gxBNn+odxO=z^BiBuXy)X z{po7S$q`-ckt?}STVo`aSI7t4V}H1sH}cIDa3}##+8`L_)1+ z`@TbSM+Zr3FG7ov9XT;5JV_cl7yZ0ns~k$Is* zsA~i;H|U3v0}ikCu&sXlTZ@uMf@ye%e1alOvKJgTc@ye@M~9U!u;TL_wwo)m+B(K@8xr~;K>ZJQ#Xqg z(`v3K_?uGcO4DP!(H;v7@Hf$aEqcn0Q9+{m2M3c)frOfRDr>O{F~NFln8#Bkr`gKA zr3$>5dw#o|^0EEP{*4%Qw3qR@GogC|YJos7>xQtxgwcDbg>4PX7P?o| zYh*tGk_N7;9a|Icc&a9HV+wYnN0g{k7uu{e#NSyEx+494YbpG5N=jc*tK?OrHRLp* zsdJOoncSEKA5&`JibG$V*JJEeqXKopYGk+O>z#b|D>f}JB)Twyub0>d!8XoK>9W_`ut;PotKuz{Z_o{Ip2{N^8S|aej}4J@wqCj zex9sf^%QlqYH|4Op6x2*HJA`l0NT}Wt@E`R_*i7z72i&vM>t~=brtQ-ewzlr1dcyv z*G`Y?Gj_FQa8ng><`eC3bFP(ZqdE-g^T0Vt@STb8(Ud!jsZBBKdTiCKG~tW(%N@md zA6w%>f_!Xa)irQyIGy(-v{*N5A7AzZ6MnRW*5GK#pt54aQu@4Yt#Rv>vNv&s7`tHj zve^Tfr2UjlVD|uvTS)*>G;*hl;9|vBhek`QmMEI>-LVaSRTW4_b)$T)v&p{FQ1q@w;iC-aAA%iSOi^Uz6McxBHO8KIy zEcdGvm8Uft*Az2E`JtOLliHGB*y606cCJ)%^2dS_M0eFa;>Yq71TR;mU^OL96ZTbp zj6XQni!k-k#N!dSCSY9 zoNU^68X$u)5h{ZS&-4I1kL4iou|eb`B0?qS!xZ`q)U5Cw`-Z$b%YF&R+t*vR3}x4M zi||iKJ*mqf_S0SD+@DwXE~eHoMn&Z09)cr<`ZCcj-I*d%+GObbjkgayU-jv<-Z4El z;}`aL-stx{^LQu@wIUDu5HA}sYMUI;qqqyZtB*Tj=3dSy5U~zuvhCXPb{HdKkuCk* zND@P3Q%*hgc(=BAAz%te3o|U(Hj$Z$m3DeEdTa7k71&>$fv!a5EWZ$%gwV9kJJE3%;{p^bi~#8Um$t1cHbBOQqc9MvbT&?slO zjAPU~Cw1$~QXSW=*e6fPbTLvZ-U`%&KTNV1b5d#oyNmOMsK#*dcT392+a$p?VOSp) zKf2ZsknB4oz@~_KHZUTBxjfY-3Z)H*Sh_F~lM`8R(8MatER^=Qyw5t&&xdWAM2@@{ zHo$49%CK5?R6?DxxL1^D zMJ;+MRXL?45R>?U_a-a3I6l%k!i#lzFxwZS<}Z?x$JQDoFAL4JiCen!3lFRCSIdxN zh33=+@rzRxgYn(B+$`biJ%eeeN@CrKF;t!sxqyE+Z}a)#*Y1l@e8)XyM>0-Z9(NYv zC>{~w>dO`SMNd7L^tDu3p(+@=^46*T;12&6@p~QA)q0jCMc1)6I?K*14rO<&Vr5G? zfw;+6o52B`kQ_fr5q`PaXnc&Vav6^^ynXM?u2xhV3EJp4D-GtdZ=oi%#0AuRFDC&1pJi-EWy&+`Ruv{Nx5p&b%+#mAR$D7U0bz=UTWx# zS}K6tRFbYE$v(J>08d?s@j%(P59W>d@vc7Yw!pa1kO<*Cf#6-}>JsW*zMS={e`n)7 zP44pOX@`^fdw3s9I~Hi^DLuRQj1`#62Yz*3)B4D3I((hxKw6$nzWkGqqvT$l zonQl593)4vm=k8+ioVZyln@yOiHV0nt$Hbu{L4S#Pp1f6~R*w6J^H*D|BgZ zp37wHIsV`-*B-9Du-_>Xvv?`u>+IPiMi$i1XyB1+)6{k+u%E?1O~&MfPNOkk z*4(=R*>@#UFhnwM7Xnf_xB)ya6$Tv|xv0uaS7_{GfB87^%#H~Q3N>VsUxH5y5R8rx z%TInE=pxH0Ut?4GaTBkd8w-$znuks$!lL_&_jF04qg;I@87F;1%_4_xtwT`8x6wY=bi*##O;>WK3~zl%w&hGtfdkPo`a zBiK8CFlb5_RjTwge;z#dWo8G#f|7U(um5`N50Q#&)NR>PZMX4n0Il|H#;!Zk6F*bE zy+zm?O$_}h$y4;CBiApg-3pfZPsO8JA0|pSEIrJ6oS$;?IO%~hrA>Cu;fwsxG)sR& zpvsEaxC)$z_vX#Zv~wA|;k0YwL!XjKxDs(JAEK)KE#Nm`Mua#01etpaE$U>oUP0Up;guJuOj@%n z^-X)T8{qrrn*`d31*+Gtm=KtWS${T)<(R*(aAezTR}JE$pWx155AfvFVG4klP}f(T ztx|pa%D@)}^{G8Q@KAu}{l|`ylS>T%{%IRt)q$Jw69~lth4tP!tCzuC7Hf7asI40U z7F!A`R~r%^*EXn%*wFg!MyG`a0DBuw(6m5Z{P?oCrfz&a8MXl0*Ot;&8MRlvK%!q) zWnercOwIz6jbx1#D@AM(>Jz)wSo1>nm}7cq#Z0P;=$*0lA3%Zv(-Z)oiAlui5a;+0 zWA-MYa?CTWW{SyS2w)Y8%LON^&_PLL?ARV6J!w|bW#p}O8Xr?6uc{CV8XSnsvwO! zhwEy(Osxg!?E5D&4KQB;>CTIi&MBsC1*+p$H=O?NnX1=z;b$kzo;02+SV4S)L754{ z3;`i3yxyrSL%7fOJkTWB|1@xzsjKM(BWcz0R2#9s9S4HeYY!xH2~k(sRa9DI43KkU z;i$7fO{2?3SG~$^N?7u(2>-yd#?0e3xuJ}2-hpqDzS1dZm?IH4+4ESKC|KfEiecC3 zDYA|7fs5!(7+Yf;krVy7C#$c%3FXrEhX~7vhJ1J3hOYYrmC5y3m1BC%!6T!A53did z`9s#6(A_m~>{xc#fLIj85vz?cB zdZLMISk(6Q=NPcIC}_Ul#D?+FM8YYmu>u zLa4$}t?|GOZTsLQ?M9z2jW<^$i9#MebL+N?bkF&WU(q@JyGjT=3F7mXwO+-a|Aro& zC|v6*s52}AKRW)-p;7jdU+38PQEvYQncwiD!l7#egWom5m{YYI@4@?pM|_cHx8HeW z^bLN1&YA5EqoCK*9jL#(t9@kb6n$F0gJ*ga`LErk|LK_ckHYxBozHcYBN?$v=s|HD z0%!cO6?%O&$Jf>en+gBnz_nIf|mP%+7c*9T1&)@xVE>Ku*qT@2= zaO7S2oMA2?xF13!Gw3Jb0pSJqTk^bF)Q1}Xa&&@)z{@#8-5P#wKQJQE#dt@v4bdO5 zO^=dfv$QP=AHB41bJPYc5aD;#FKk+=V)wJ{q=S&PUa7FFAkZ3&A@Sb*p35EXEV?T>MEDYE`)U|+PN2Gw)@22dT7OMuHcF3$a}p9YYhS$lYfy%(1*s4k=9 z+e`69ZXPYXr|rq04SVC`LCpkQp>! zx2HN5U~dWDXaSi0PX?J}m;MNLaIg`JJAFhx-l-zQJk)xXyK_FD9Yt@XXcq-yEbcc+ z_Rvn}XBan1XWF1P%(b6;^zxQ7X$st_=I9AihMwQRNpSJJv7OiaGY9tk+w2fZ6%z*b z>hSg|RgJix)xb_OFyUB~B7rQ2mt(d$?Zgh@(s85+O45t< zetF+&X`31pFSqZ*>I)4UK$X>C2cCGCSY0wH(&_3}NYG?cXq?`Yk{-s;czx^trRnDVN;z(im; zw=6A=mzVJ-gDj*4I)fKg5SIjN;b7~3?_OV5+6yCat_uV*ku<@LbsLL>SdP{I=-|U~ zCR0Wyri^sM4qy5yd9Jngei`FU8rxF&tr{_nA6)DM%sDF=UOn?{eFDngzk6e;S-*O) zb2!M`<48fz!JI{<+C75Lv7}t*3wyU)jE2i7&mPe8Mr!v)K@?|byXR5co?P=MR&CeXM&fGwpV9+TBONC24CDr4z zvoEy6``ZO{)VU)3@a8$@m{vj~==mw6l4gL#5m>(|cxumBW-~hlF{Q$x~UUd0`8tpb8?oNN2}XGuo5M9+qhk0$N1l{?ZEGmYD3TaxIOJQ z*Iha^Rd%wx#8WhIp;Ny~?YJ4$ac0Cx?u=0G()Cm$(uo)3o0|+$NOe|(`u1_5??G4F z>FdmpPd%4Aj5i;8%5IE0rhuvZ!l_aC2cH$S{3tqd!jv^j>g&o4JjVO;wFV;Ht*Ojt zRh4Z?9|wC+oE%-Wed7eJ8*xlWtMH$w@+yXEWRIq+#m@u#=|Ll7)G}PaQ{G{RO}0tG9W8oeMalq5I_us0xrHw$cEZX}serwwAut;Ykl3gUs zgZ@|qu`tAgRn}$Dv$xDtr)kWYcbK8|N4}>P zs3nm@JIcGT6AMiX4n2CjeTnhD)tH4b>H~T?`Ia`@`D9J|uG!Eh({!<_YR|5%Np^>{ z6e`m~a&Gzg-kgL(zaRcD);B0&kwC;A`FM*r0Su2Qn@N4x#2Sqwuar@`_P7F1XQt=) ztjW-xt94DG%|joG{Yw(CUDwYfRWIpv7~^+vH&>f)xx&F+ynU~~tAX4Yz?^mb{2HTd z1=iit8$%wr{>uz3eBkB#BjyWM+e=Sv>2)y{rh|?=3)ETb3VMSWMFT~Mki@M=QlvJQ zhF|_`%N(jweB0T+`XG{-wpvG{iDugFAbZ1x<@qEByReII`Zfzb)vKS2&<#E# zw*v72ZU6)Dq>5XtGVvE{`xTxKvLNH5ou}wU=!P9 zPa)8IEkE_rH*pz&=H~6a0rc47x>cM3J4_9f%vrKt@;%byc>g*G_)%Pw&KULB5)L~I zmGwqT=kI1t`qxLOqrPX~87R0uKdk2p6I7}c_<|1H6MRnP-po4Ey@MEuya?Hi;gzxAcsO3QjblHYCpOKR}`9y2@Ff zO3^I6RT9vmb+k^I6miXkzROoln-DCZJo8YtHOeFSM>no3)t6N#A)kPB5=k(rer%kB zwdCu}Q2<+16-~3THR-?|sfeEF{2JN!s>im9j=5|+l)-J^HQ;sl;lf|?I4@T{$#h=Q zAmfB-syX~{xQ+k1XWRh?oX<^cY+S4^YU!To&Cv9Z7=u8zv;QMCjlpznqNLJPOW{QF zWyTO#>WF(lf0<&kv2Y_5KJJgqrN9 zgyW31WYa1~Gw8>$Z*L5h|JmVYNxc;}`t&2DBy8_Og*M}jp_w&FK7(RMbXoOw@RSUn z6Z=k`Gc4wwb8GFnjC>b_1$hHO6l4V$X~j7vaPOr6+)=;uoH6#kDu&BGZQY?^s$-GR z)L1Mjuj4a)-*&@PX+eGZ(v_X@zAkNz-=d6`GUI`1hIa&_h&y=?nvx7SG+#~1-@F{b zx%;BK$h>)sX9|~frEmn5mj>r1bma4r<87#A_d-3vqqxE7Cj8r3e9;F*tSKAy(x~la ziqQ%9V&bAduwQ{D#q!4&Gg4OhEp|YSm4`=~E{IntStJie5#vk1#;W(aRbgL5_I@{9 zLoTwS!>hgfX3<9 zsOG#D?iy1B8@xxP4-n6@$MVY?xL;Ni*-()nv^W~zWbTRn4FA_6fxhe4*&O4a-OhV$ z?v;b1#90Hd0w}gtq z>wt~b|4dcYp2kz?B92F6-Qy(m_}Hx(v`SG}NFRIb);>6{L~9!&x7H$CRFl=ga` zR`-1X7L){)Y&)}TYz#Q7ovMHCRt{tI??@%?3$!e@t|x~Oq72WervNQ%Z5T#t)6d`z zje%l}*Xq2k@Z;c)mQBQOtBk6PpzgT)P^%+X^#c02Kb`kWd7sTHfV`$-{MLhT3R zeqjD~DTiWF^@fnF&u;Z(#v}}XoLFwl^d?)AYP3ZI&=B zpNDW6WjYZhpF0c|;krm-Yij@*^8IF9xW_t2D4l!KF&x~5!Bn|O0J2qBk3qo$tR&5N z=^7!=yK7{}O~N_IwELGUV&xT$RjK-#yT8U0j zfZB(%M}VCBhT#PF&@M4L{??59ATe)5Nlke1kv_oH9O~-U^9@7C9Y~DNa#|lRdffdH zSu)6XdMG*N-vlg4^RF_;Fu4)$wpe6yB-YS>MKdyRIJgSu%Q&pbcHMFN0em}jz3ZA| z_;HEr&?^}COK36kMAh{~V&JioqAN!uC|Xn67F*#5 z2oL?Al5G^~X$37-V7IVL-a8TtvU@`XN%74sp7xw+%na{NW7eCY2dBtw&&`}9{DiGXCVGYJuQ+dbl94448A8x;dlTb3vP1d; z-!%vN{<f z$8S547jKk<>xIp%4CM@+Se+wvui0PV09;d|Hoyl^M8tu?;)R}S#EX{zRC7c;umM6R z_#Gw!a5=FAeF`h9&P61mKHQaib`A!*^QT$cW`3WaCG3;3o83UWtF)7?M9I9v7XW&Z z9>@~=euX+E=k|rjceIhUwXf0huhnSFd@R8)KIAM9Yo6Z?wO&m^j=uu3^lm}AfEb@B+`FbZEq9x^(UR1sBoiJf+G9(A4DlzDo3yqD|Rql?fKB$1YY zLCUkbzrDUiS&@zd*k9c9+bcN|St`QD;I-e0z%S+t4!1&3b3bzXU3 z|A?(yyk(Qzqp(F1{l6qS|MIh>lq|`du>sS+EiEz+EeQL9%Do5U%DES1{d)ZoDSQy` zI!+o1+s)&@ml%iPX)3}Edb@28JE&!lM}$e@r{-q>=dL|%WUJ5xkP1)!dk5#Xqa9jND19# zJotbd7o;8r0n*XkoLbQi9y>d54H~hi(SQ8e2{{N&tG+|B&kx9#b0!g6dOrXouPn13 zdKnKmck08-hPF1oCju3*31fBC^3)8V8lO)h3#Xk?vktW5fF~@c8ey`7>)z7)rS{RI zcm6&pik>_SA5J~6RIi_vP;(pk4^VrS4~^)qm`HUOtxu-fULA*=KC{l$VM>;wrc=BJk%-JUh(UqDpOSluF!4IM%J?uvHn)yF1p0@ghPOysv(#t12%D zOTLlvz$E3%^iZ+s55(CbsdzeXf1tS+5M~{5X#od3@&`k-S^)@)16ZWE(BiU>oi0pg zYqi#yeIbDcCW?xtVV@Q=xE=c(aEIUxJAT@&001(NEp`3~@jrm9l{5OZ003liU;bx6 zW>F2<%uD`vM3(!14Uzrc&aL8}#6N&)lj=)~8w@#i6#*NRzsGK>vBWE>ed6Namdu`r z!f#bcDp_}@)`}USD8nvj_f+lmO4Hbc6vcQ8=bmd_lLS}Dc>EcBvG+T%*wk?RKD{}B z(WvWnW3m=d4U`nYxsw#VLg*&fm#sZb!>3#?Ur7rwFB}0dE3hl1a_f3#+Kn2U<3-`J zhd#%X+lUT%A3Lw9>f z)~@FHaizRD@`>@5YYRO_!34YHJ_dBi5XS<&pJS+M= zywoFP!EN0JJUKH-&;M52w@~rUCBmy}utUED=S@;w_N1Lx9a_^OW$=aiRdGo?NNl^t z?D%stMUolX(OKe$|KjhsfMJ|kHT(Hp1riuht9rJ6*rjg89~QJ4`iNf`f%@o@9)@Px z^8N0cYOQvg#7p$!W!WPq@%9zM7hQzisoJP$&3HQRGQ48T@o~QX-_VEOv0KiK@|T^5 zcND3AAO(Z#3hz0&j0xN0v7<$r-;gw{vC+e2`>7rMlu5oNvx3+sGFX3@oZVNo-QkVD zM}5brqYLxTlxR@oaN`Hl*f^)0kesZZ$H386SZjuQRQP8OfAm-?CNI)9LRU)#!Z&|u zEjHMpBQ{SLnBy+jHmWOkvd-tJ*ScoU1v2p1m&WbEgq96dn}wC}6J?9m#cmTok*Fu;QX%eZt-Zu$Jz;C7(Cv4znSOa#|GnhLI#CA#5m>e2FFK3WHoN- z+qvW4#vI?kx3dmYk?WZuFkBp5a~geGZ}Ux;;G%aGf8Cl;zV3g7{$$H`r_IW5-O~xB zOHd8*W-&vJUHc+nKnvi!+Y$j)yrpr9Ho!xXF-7$cpV8}vtFKzPoPF3gyKL_%nR{QP zFEZf3Vt5zd1<4+(U>x!|dzaiF_!ht zMRhyeaf?Wbjw?c+iS~eaCEvoOtpWgM<#e#5-C+j3H)kRwXTjeCS6+2%DB|RYs3y~? zpm-y2$FCItsonu;<2v)TWRk<%J>iXZ-dupL_3Ac9@7-5r*+ZT))ETZ=R2m^R^l%=b z6t@DS#6QRD{9c!~G4bcZ<9C=(L&;aKisi|6N~RvK16=Z!-zQebxb9nP+BLAY&_k=( zRbmhIk&$ji@N!BoasF6HcA5qhH5c<AAj-6$_ z6>_^iiQ%3P)>qF$i@m#@6yu{hYpg5|JUv3_Fx5M*UyHm zUx6_h-R1^gYJYl{_&-mE`|sQX4rR-3qb7Lxu%qA!ls8d!KW1`!Jtj1B!I_j(j57A< zlMIv_m#%}Fq8|e!OSU!bFF2_2gc=)U5jTG!>F!C*NQEt^h$USK{r7q$dq1A(v}Dij zhP}cGNp%xLEpWz=Nd6|-BTII2Uu^ADi6U-<3fp8Nf#V!c-RsN{LBCA(yCM;IDEw z7ru(RFq=yp4?VyBNbhw6i!MQUQ~N1xMutAK$UN+gau%1eQ7S*j~{u%fRRin zHb{zBdU5j@k9`)JV{59X=BMS8UOu3s&dIO`AWaziGTmLx^x;W0N?Y07;cWu-!vz6q z81c%TQHm$)8Bh2MFZ-fUJq<|up(7ZP8lbPGobJJ!GDiYo{KZCH0NWs54*E^J)Q?Y{ zT#DGvHU0YOxenHt4qy|E*Ub1flqXc;?a4ay*&RIQHbf3Oj8cnub(jALizbf(({LSclIJr`e<~rak z8E?)Imz}RTL#Oo5p^r>1T_DU+58sT+Fi4JX&{?6raN$~!w zj_OcD;}eU4l!V22*p8IS#gDrqm{)VAKS=tGX6+nmU!_cR}67Q$$Qb{Nnce*-7w6(aeDmwu^Wwsr>hxw!=8kytZ+c}%vp2zI`VQ4EPXtZ63|%p0JXu22b!E#MgV42=ugR^ zd0}sCQqTJwiFu;#vihLz6_L6pTk8 z;~BzIfSju0^6x4I#ck0i>v-+worh#O2d@~$>p6h8P|$-NqEP^7e^)xaK<+t5yeu9r z$@}oEm^DM?`=~`Y+DO&o&4ZUv8Ty;~qFi1CgS>IaCK-j3cOG&``q$a-Kx@B(_i!K6 z|KE^SnUM(aTq(x>v3}rpAQNmd z;(I0YY-$=HH0)Sn*DrM+Aed4+nEbU>Lx1Fb^AdeOHgF8RmJ;6zUv5o@yw{dJN294^ z0~vN`EuMC6e z(wtGtuA-~Px4Ns~`THksFbrY`n}^0&S62*8&9Fx#Sy?nCvVi@&pW(oFV%L0XMny1t}- z^8^SgKCA!v-a8Ez^&>yaB)+n;E?Alr0$r&hb*^lT_^`)GLXaLK@$b_po@A##KDEX}e5#Ntx zxyB5s%|*bo?l|D<4tWaNQ!GxCZX_NWL1|9~oOlq))Ni(werdp#akdsf^*PQA0V@fd zzAqs`yF}*Eo}4FA!Iy#-^dIR;ZI{P;8(Ti}AATk4Oi28}+w9T|`w}Snc=zSNn=e~E z;oU6i&vlMF{op!zIhy;iwKQxre4}4_AP#J1#!Hy;fK+WV@)7B_#qK{Trv|-ga4*%X zYFCP1`sQF7Me!U>l@AHb&Znr%$x(7@x>&xG}oboKGoKBHf)NEzn z@hxg3%xE48lW|XLU_bv!-;+y= z96n|nyP-3jiGR@q3;~${{y392Xo&U_=T~2pXn!)}HZa3K7~+^ZCxXy+h$X+dUDJZTa$M+Eso*YSE@XbE@lQ$XK6%@V6LfRDEu z{m9*05_rh7Md%NKtikW{N8)`AR-S{|4&?BIa%XQgS4?(J$*7!da`M^}u*3WU>vb9I z7uRPVJ8J@M?z;JDlUEyiP^j9KCDRWztftjVP?vf%9;3WxvKn6KwCn!>nRr)s(uvBV z@w3078Py0uwyP6Y2&kG!n=b%n1QT!gu&&v{)Hs!~TVSImGhXi3M`#~i{CwI-xe%Evc+CgMV5J$9in*=7eS zxE?sgxEyyDM4x(lv9bmu6nXQ0>DF|pTR7zI7~39#Aa3su_B7dVas;M3rdN6~gp?{e z=c6_}zlk>DPUEzS(rZG_|HLCNF?)2L;}U}~8DC~vh88c29-Ub%u#Wv^V(*|hBmXpD zmFkn3S|ph{BVla9^Mf||$_OZ(!ziEF`jy%qjuTz2OxCek%r#mW%>F4wjo;%-7Z+ z75Gtt$qZj-`f{t09;`zvL$-Kl&Wm9Rg_;s)Y z)zH*Of4tX#GSZn-@0goGaw-b!KGQ|W4)Ex7=N{YtrmyZ!M?y!SzF14CFP_2epk%r6 zyE94NBXHtXFS-#M`>>H;L;cFByAu+hhH*J_40o_by8?E$4VNH*Mfg*SM#DkpF~vcD zg!1BWe~m9qWngI~aJ1$JYB0yO$+6C)uUhsu_3fqGF?8qQun;(3m0pbjVC><%2&nP7 zi9pwNY%dn7RBDvWna%O&l+Y1+B=vAKsXjF=KrIFy7&p+yh$HBZLkG?^X`DRYL#a4B zApUr>od4SCN0cEA{=>;=iPyvK3&Op$KjOh=p#N&&ujxiT9*=`d!VSBb)3Z;U%fY9ct3S0-4=Txb~DRW;tzhvdq zE_vIFlcN|{Yp;J5g0o=NG29rN`n!9|8<R8R}3rpI&khgZ!^|?_`h^U${UPXuOSpl@#Qu z;S0wDBTpSdKJhPM5Cn>mfS4224!FcFR~gF)N0Dy`yrD`plO` zU(b4-jo_uK7*Ui00Kb-B(Y?)_tl|P2)&o=Xswa0>O%d{IX<{>*9wl@Ey48>ZpD71+5*wA0|UxeM`AO!>;&4$!acdXRcb1jgvu3+cVr3t)-Pmy2t zHFa>ABrjDmgYxmc1d1P$TgxBlT{!(Y;nMVqe1qZSLFJ;qx zAN2CLWGrFU8cF8vHZ9s`Wd4;oMrIMWgJ!zdAy+zmog1p zQJT4wX?oLINnfKtMdbX~9CV}2!oM+Yz=bljet^9?{h$_os|M%ao9cag`ql*6a}N^h zZ&KB)#T!IMt~+p&-FzG3+wf^J(a(>9+gO-xllyS3(y8mEO3~Y67;=?vT(`Ypci9BYMbM*VQKyCptlv zL2sKB1hd(^4yLAO^a?6l^-N}(x9nL`rK12(Pu{&BNbXf*^l6`ZhPge6J(tnN#Hy>! z>Bt*u2mN-@I8IqWlDzc6aw)HU`odH|YUPxp{c_eo>DtS}leNg4_6O%!260JTsFu-2 z$pSeY%A0^Z$Nc!6xHG;JZxuJL#6I-R&2WmVR}>}>M9KW$kN8?z|3j+PEyY4GVf{!QSEQ^u>xzgU9NML>;2Z~;oxs=D8yn&5B2}H*N;7!`?J{_$sAmSGh5eFV zW8RAh=24(UY81VV%@sX@x)#W8%zV*Me6d-6H1qD3`1Gj_zH4i=iIo3crb!t63p2~Z z!LG@ilnf4O;B=G_FuSa!8r8Q8FSjCLiXcqye(A76ZT#=2fuqH~IC?8*=&!xpM}|+% zls=&~>}sZU%ol&Y7vviMjRL%*BFq?UJdbiUJH5ZB=BA~&|IyI|by%P9;PNZTHoBX` z{abSN7k!6Samo;*t@6k*Rp^es!*{ZrOtF>Hy?kB8|I~-Jc=+xTJqeIFMN)*d!(>P` z?*#c>x|=D5qF@E(yn6q9&1u&6fr;?w_4IXeCf(rlIG3-nBtbrjE`{?t_@?2sB4e&5 z7JYboNo}$*8nf-`CIwUe$Jr%LZF1ror2WfbO(BDCOZB^;xH#Vo%w6w<*p=26b@5<$ z&YlEi5FN5k&H^42PfrQ0Q~sKZJY+bOmWy5Vy&IJ^;M+ca5mnX zE`mn0e8rS9tU<;(#T*f^uPO~{0L#~JpMEA5pgN~Qn@Hi{U%itFw8X_A_0q`hAH|38sM=E@w)(6l()(AMo>uI z_2PsG$X;}uquNBizYW3YG%f*{t$v<$)$wB`xjSRp;|7{~+#2={86d_(0Ob{rW-R7P zruY&4w~+%)w26w=1C6>648r$l>(_mHksWb~0Jbx$@eIPW2MG5&67sYM%uk?vP%9bk zwuzaMe?g0UKCIvwGn0e^5}?9!hgHMpIAlk5V`@o-Y6G-PQa_yL@;By7%xzg-d~5_i zGTxsN(t+I`>e_K2tPZ&htleNrn!d~lUvr5n8NXtrozXhh`#0DdQKoKo(&2%RIs0&)BwAH`qB<@%I7cdET@=zzdW`+Yx2#sa}+X zeK18_wyAB6*a8~izp1?1btsvHkTuiD{xeFQ*DOigD$9_7bFjEg(F8;kwz zYo|K%;>_!Q&dNx)sS};sGE-0ih^C2Vm)qR=q;o|00#UuCvbHD9fCjd2xF3AEn_Va6 zW3hwYpF8o1Z@L%448{R*`r+9tf8?+*-;`NVGhf|h%AXb|YwcU>EOLQ8yDZ$A=gg@0 z&gmxIQ&ViV99Ym!rTqSOMg66e_N!^6~!d}>JSL3wX#2<0FSftVB1O9kIxIj zF8EL7xif!g5Gche>SUP*2M2$g@Qqn1_5NFA%lp-zI%PR!2Dbl*%%XM$ooD`u$tJg# zja%p*Ds%?~D#eV96P{SaCAW>L+vP8Rimec;w#E1f0+&_~ydd?snfkcTULH)_y)80` z)bXhWPFN3y=Vb0&9%`(_Q*NA=0($2K+)=0b*B@G{b|fw&cGmUSk!#0wBdCL6QOY0g zux+`XLiZu#${CbZ0pNGuosl_-!rE-pOjv1BW0g^3I`@D8v`Urun~(hTy&n%KOEj5) zd#&4bfbh5`58iT3DQp83MvnA~TBrox8#JY9C-bh9Q*bA0^@{Iteg3PPn>}eJ#w*Bn zk&`1#pRWh*i{G}`VZ0wDZco&6V2p6HBNV|TPJlZ?RTeGF(8Z<7q5E1Gr`aJ63D-xG2Kp6{LGotC?J6AaC7gKMA zqLz`1Ap~b3F7Ky2xU_I^v793dyC7$~!HaCuPNt~n%y`_8hG-Y(b=khMWN>mDR%Lxo zAGF_i=pn+re$$XF^*{YeUZldPx8HCHPINg2M4&a~+R08M#AKW}5>2vXul( zKVR}Ikf7m$XN#b)+)F{RoLdXyr@QR9b5rgIleM+_h~&SX%OBVly+J+8uY%;j5h7lM~B-Z3toppbiCIUndv7 zKL}*7THJaE=3)G?3kAX!|9c)pF7CYx<`3+$l#S{6@iWMvx7!SYek^XuhWq~f`v2oc d*9}I=n|AII!M?6ulqCk)+c;TQ9lvnve*j!F0q+0+ literal 0 HcmV?d00001 diff --git a/lib/addReminder.dart b/lib/addReminder.dart index e873043..4adee6a 100644 --- a/lib/addReminder.dart +++ b/lib/addReminder.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:nextcloud_reminder/repeating_task.dart'; +import 'package:nextcloud_reminder/types/repeat.dart'; import 'package:nextcloud_reminder/types/tasks.dart'; class AddTaskWidget extends StatefulWidget { @@ -124,7 +125,7 @@ class _AddTaskWidgetState extends State with RestorationMixin { const SnackBar(content: Text('Task added.')), ); widget.onSave(RepeatingTask( - task: Task(title: _titleController.text, begin: _beginDate.value), repeat: _repeat,)); + task: TaskExtra(title: _titleController.text, begin: _beginDate.value, repeat: [RepeatInterval(interval: DateInterval.daily)],))); Navigator.pop(context); } }, diff --git a/lib/homescreen.dart b/lib/homescreen.dart index e4d81af..2f3926f 100644 --- a/lib/homescreen.dart +++ b/lib/homescreen.dart @@ -8,6 +8,7 @@ import 'package:nextcloud_reminder/repeating_task.dart'; import 'package:nextcloud_reminder/table.dart'; import 'package:nextcloud_reminder/types/tasks.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:tuple/tuple.dart'; class HomeWidget extends StatefulWidget { const HomeWidget({super.key, required this.title}); @@ -30,10 +31,9 @@ class HomeWidget extends StatefulWidget { class _HomeWidgetState extends State with WidgetsBindingObserver { late final ScrollTable _checkboxes; - int _counter = 1; late final Directory appDocDirectory; late final File todotxt = File('${appDocDirectory.path}/todo.txt'); - final List tasks = []; + final List tasks = []; void _loadTodos() { for (var element in tasks) { @@ -81,7 +81,9 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { } void saveData() async { //TODO: better update lines instead of blindly overwriting. - String data = tasks.map((t) => t.toString()).join("\n"); + List tmp = tasks; + tmp.sort((a, b) => a.lineNumber != null && b.lineNumber != null ? a.lineNumber! - b.lineNumber! : -1,); + String data = tmp.map((t) => t.formatAsTask()).join("\n"); debugPrint("Saving:\n$data"); await todotxt.writeAsString(data); } @@ -90,7 +92,7 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { if (t != null) { setState(() { _checkboxes.addTask(t!); - tasks.add(t.task); + tasks.add(TaskExtra.fromTask(t.task)); }); } } diff --git a/lib/parser/todotxt.dart b/lib/parser/todotxt.dart index caf59fe..2534797 100644 --- a/lib/parser/todotxt.dart +++ b/lib/parser/todotxt.dart @@ -9,16 +9,18 @@ abstract class TodoParser { static final _todoParser = _definition.build(); - static List parse(List input) { - final List ret = []; + static List parse(List input) { + final List ret = []; + var line=1; for (var element in input) { var parsed = _todoParser.parse(element); if (parsed.isSuccess) { - ret.add(parsed.value); + ret.add(TaskExtra.fromTask(parsed.value, lineNumber: line)); } else { debugPrint(parsed.message); debugPrint(element); } + line++; } return ret; } diff --git a/lib/repeating_task.dart b/lib/repeating_task.dart index ddb2070..cd6776a 100644 --- a/lib/repeating_task.dart +++ b/lib/repeating_task.dart @@ -3,10 +3,9 @@ import 'package:nextcloud_reminder/task_item.dart'; import 'package:nextcloud_reminder/types/tasks.dart'; class RepeatingTask extends StatefulWidget { - const RepeatingTask({super.key, required this.task, this.repeat=1}); + const RepeatingTask({super.key, required this.task}); - final Task task; - final int repeat; + final TaskExtra task; @override State createState() => _RepeatingTaskState(); @@ -18,7 +17,17 @@ class _RepeatingTaskState extends State { @override void initState() { super.initState(); - _occurrences = List.generate(10, (index) => TaskItem(done: index % widget.repeat == 0 ? false : null)); + _occurrences = List.generate(10, (index) { + var start = widget.task.begin ?? DateTime.now(); + var comparator = DateTime.now().add(Duration(days: index)); + for (var r in widget.task.repeat) { + if (r.repeatHit(start, comparator)) return TaskItem(done: widget.task.done,); + } + if (widget.task.repeat.isEmpty && start.day == comparator.day && start.month == comparator.month && start.year == comparator.year) { + return TaskItem(done: widget.task.done,); + } + return const TaskItem(done: null); + }); } @override diff --git a/lib/types/repeat.dart b/lib/types/repeat.dart new file mode 100644 index 0000000..bebacb2 --- /dev/null +++ b/lib/types/repeat.dart @@ -0,0 +1,97 @@ +class RepeatInterval { + int every; + DateInterval interval; + + RepeatInterval({required this.interval, this.every=1}); + + static RepeatInterval? fromString(String input) { + RegExpMatch? m = RegExp(r'(\d*)(\D+)').firstMatch(input); + if (m != null) { + DateInterval? di = _stringToInterval(m!.group(2)!); + if (di != null) { + return RepeatInterval(interval: di, every: m?.group(1) == "" ? 1 : int.parse(m!.group(1)!)); + } + } + return null; + } + + /// Does the RepeatInterval referencing from a hit b? + bool repeatHit(DateTime a, DateTime b) { + var daydiff = a.difference(b).inDays; + var weeks = (daydiff / 7).floor(); + switch (interval) { + case DateInterval.daily: return daydiff % every == 0; + case DateInterval.weekly: return daydiff % (every*7) == 0; + case DateInterval.monthly: return a.day == b.day; + case DateInterval.monday: return weeks % every == 0 && b.weekday == DateTime.monday; + case DateInterval.tuesday: return weeks % every == 0 && b.weekday == DateTime.tuesday; + case DateInterval.wednesday: return weeks % every == 0 && b.weekday == DateTime.wednesday; + case DateInterval.thursday: return weeks % every == 0 && b.weekday == DateTime.thursday; + case DateInterval.friday: return weeks % every == 0 && b.weekday == DateTime.friday; + case DateInterval.saturday: return weeks % every == 0 && b.weekday == DateTime.saturday; + case DateInterval.sunday: return weeks % every == 0 && b.weekday == DateTime.sunday; + case DateInterval.dayOfMonth: return b.day == every; + case DateInterval.dayOfYear: return DateTime.now().difference(b).inDays == every; + } + } + + @override + toString() { + return "$every${_intervalToString(interval)}"; + } + + static DateInterval? _stringToInterval(String input) { + switch (input) { + case "daily": + case "day": return DateInterval.daily; + case "weekly": + case "week": return DateInterval.weekly; + case "monthly": + case "month": return DateInterval.monthly; + case "mon": return DateInterval.monday; + case "tue": return DateInterval.tuesday; + case "wed": return DateInterval.wednesday; + case "thu": return DateInterval.thursday; + case "fri": return DateInterval.friday; + case "sat": return DateInterval.saturday; + case "sun": return DateInterval.sunday; + case "ofMonth": return DateInterval.dayOfMonth; + case "ofYear": return DateInterval.dayOfYear; + } + return null; + } + + static String _intervalToString(DateInterval di) { + switch (di) { + case DateInterval.daily: return "day"; + case DateInterval.weekly: return "week"; + case DateInterval.monthly: return "month"; + case DateInterval.monday: return "mon"; + case DateInterval.tuesday: return "tue"; + case DateInterval.wednesday: return "wed"; + case DateInterval.thursday: return "thu"; + case DateInterval.friday: return "fri"; + case DateInterval.saturday: return "sat"; + case DateInterval.sunday: return "sun"; + case DateInterval.dayOfMonth: return "ofMonth"; + case DateInterval.dayOfYear: return "ofYear"; + } + } + +} + +enum DateInterval { + daily, + weekly, + monthly, + monday, + tuesday, + wednesday, + thursday, + friday, + saturday, + sunday, + dayOfMonth, + dayOfYear, +} + diff --git a/lib/types/tasks.dart b/lib/types/tasks.dart index f4fa9d6..376e8f8 100644 --- a/lib/types/tasks.dart +++ b/lib/types/tasks.dart @@ -1,3 +1,45 @@ + +import 'package:collection/collection.dart'; +import 'package:nextcloud_reminder/types/repeat.dart'; + +class TaskExtra extends Task { + TaskExtra({required super.title, + super.done = false, + super.contexts = const [], + super.projects = const [], + super.meta = const {}, + super.priority, + super.begin, + super.end, + this.lineNumber, + this.repeat = const [], + }); + + TaskExtra.fromTask(Task t, {this.lineNumber}) + : repeat = t.meta["repeat"]?.split("/").map(RepeatInterval.fromString).whereNotNull().toList() ?? [] + , super(title: t.title, + done: t.done, + contexts: t.contexts, + projects: t.projects, + meta: t.meta, + priority: t.priority, + begin: t.begin, + end: t.end, + ); + + final int? lineNumber; + final List repeat; + + formatAsTask() { + return super.toString(); + } + + @override + String toString() { + return "$lineNumber: ${super.toString()}"; + } +} + class Task { final bool done; final DateTime? begin; diff --git a/pubspec.lock b/pubspec.lock index 82d7417..0a7bb28 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -30,7 +30,7 @@ packages: source: hosted version: "1.1.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index f97f81f..f0e3fed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: petitparser: ^5.1.0 tuple: ^2.0.1 flutter_window_close: ^0.2.2 + collection: ^1.16.0 dev_dependencies: flutter_test: