From 6852b767c62ff5f08259e15fae667293a5433bc8 Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Fri, 12 Jan 2024 14:29:06 +0100 Subject: [PATCH 1/5] Update README.md --- Documentation/Images/Banner-AllIn.png | Bin 0 -> 122408 bytes README.md | 56 +++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 Documentation/Images/Banner-AllIn.png diff --git a/Documentation/Images/Banner-AllIn.png b/Documentation/Images/Banner-AllIn.png new file mode 100644 index 0000000000000000000000000000000000000000..f64e77f1dbbaf2e7c1917096fc571ac63ca9d431 GIT binary patch literal 122408 zcmb5W1yCGcw>?T+2oQpMaEIVB10+EPpWqG&gF6EZ9+F>z!{9c+kl;3u!F5Q241>G- z;2PZF<<@)u_wK#ly;bi!Roz`@S9NuD)mnYl*?a8{f2Ro|dP@70fPjEVMOi_cfZ&lU z0m0pSk01Vxuo~!X{k=SKQ#SG-ARr|BkK+yjB7^#G@Q#Nz=q*86AN|JP$$i^58gB>) z&@qHpA080gnQc~4c%$ocXS;c$f^X7mz7{rGFXNrVDH@_A@$;eb-G%$AA z<5KV+r*=Ed$HeUSxOoF^)OoRULT#Et4|$GN!Q1fYYo_Q03Tzv7KdS%{mk_PrpJB_3 zjqhu`WhgK#NPq8qHoa|}UMi?=QJz^+y54mGv>F%b*MU!0S6kE7a?GJl8(rh!>F{h2VBW3j@Py~{@lVXUK-BI+(^ptx)}4WxEgHfc9-nWpE%~O z)UyTcV3NH6BByS&4WsRc`4Kk~!v6?HAt+tjil%=4cB_;)yl)V{#8D>mr+zE8Ybp5m z*DLWt>}hmwWP-Z8j%LM3$G+Nh+YD#kuV1w|882xgTHDr0uhg~Lc`>?GP#@~!3a@ow zx&^Gu)z9OFmyt0UTtZ5F($#Egj~eUoiSD$Eb)=`WYWs z;i$-vtV!`9_BccshY8O~t0-f-0r~uS6kHj46?=8s6u9jVsYed)@H7{lsb{O>lH<@> z$akDoYxf^o1Qvs>Qg4zyO0<|HBGNS*hassD0uD#3xmC0vw|egv)~eC>N#oHhHN#La%@?FK*$m3gdWnD7@j*z$)Th#f4>CZ@Qd!Z#Ie@ zG@*-EZD&z74OGn$Mu@ksMb-wW+`Qlw+aWFs@U;T&U^+CjGIs1uey?44&U+^3Cn%fm z#2Ch4vW>zJnt&d0I@3AZF{GQ2o;PDYzvgG5`~sBg^Yu53)a7fBUYtHt^q>@49PVUS zdOh{?n7Aup|6{p2321y#1*<>uMayAG0Z>CnWsQMBi4SD_k%)83AHW`wICb*lXDKps z+qE0cS0lMzB?n@l`s2jBx`SGJ`z4vVT@h{!SSc-DztYsetkde|dqAY;N^HtIyp!Vc zBO5LGD&@3#^m{h#Vsj%i#E&0Czi+bEylY{^?&x3!z;n84%q>uMeUlKtu^s&7&?;%Qd{mc8eu ziu+ofTzTtwcsB~_Nl;X zK5xl9)v=+OkI^Ue-V*30%hbHdG>UBP@$4Ud=->aH*+!v_$;(-d+B~#1CY!ZSg*1mN zWqf<1g1akMNnSm}DLA&94zPnPShp~2*Ou*0bf;=Yo2>kJ3^g9d#D1$(8m@3*v+yu0 zYp0fl`*!?_pr;av#2Cg*$ik7)UYl;0`E|AuZWgC|Q{%F9!BL^b@VKj}m2p73%!|2! z7ur`28dD+1w@S@eAioO_#5~2&TE>jz(p!&tV+WSkY=eALCc^w zDH!q?d&Qh?mUZi_6o^uW|8mnLzGbJejZeJs4~R5u96-%0r~|t&+H}9)R*HYfRrb$f zs1LTed;qa1^k2Z-HUO*f+`RR15?)iQT5_Jo+bcgMQk?W)KzqTQ;q(VInR!B)4S*%bC`Lb|6)Sl1iB^`RHTk9B(BLV4xx4)h6mz4d)-_F^;G(Zo*CC&aD$J;Ox# z?5;7gpluI(#927pX28fg6%}?BUaY}SNmCb`+Z4Y!zw2u`1?aa)7`@d`S5UJ?OMur3 zy|vV0S7gRV9%^tSbAY~HN+WM$1RZH-tNvuEjfYh^Gq=jLr3%S1T{O_wObDnNM&LNK+_2 z>vL@1yM2Z=Y<$`xe(+oLHn}t4-*A&p)-~-L`TGi3T zyES6roJ8XPWQry*5RqDsOq;rr_f2(Io6_mewp69+D~df=mwS)hRX4n}ISQH-(pI)i zmy)eqQ}=|t?WKcm#T(_*`@HXlD}^lWCkkc>IwDls5A8;Vk4Mm#o-h5#k;l;`qVb+a zBBA|I&xB%o$;q1dxQ&FXbreQA}1s*xll^#z& zvu7#i7DE#Aa3@>VwATWZ)W#ti3FbzgCuLqHdM^K*majlm!UYKnKK7IupqJGW_N~HH z&Kay_dLmAEEx#q%`AzN7kCEXZWF$BvrtCqNMQ^GDXkT+t*0kF}%d~;r*e9K8sk)gMt<8AT(~zBE69epKqUz}0qWFR#D1qhA@Tl43`37E5lz-XGijmZ zZ_?+q5hQik!ruXhM_Ps@e3;XilpWSCtA=!D{~gNy8RZbIp->~YlgYT@pGehQE{kx| zC(4{}I6*e!#trke%&WeTuFrdEGS;9Dx4n27z)GhgE7B~R7Wi7L zp9Gt>34b*9H5J)UrNP79^=9|US=SvSEhT9Ufue_rgTF;T@~v$7Y$psesGaL)M{~Z9 z>~(8uw99}-_}G9I`m8?+w#zwJA{w5Gt9!9Z(`jO@`XwJi>bzB`)jn&PgwIoPwBusrp87zSyhgr$_8WR$-ralh-hVi);<49 zxi=aOdcodL_uQ+4pRGmOLRs_Wa|9&b=5>hmP7Edp@Na(j$`sc#i2O|ExUt1@@mUOK zw{YaQIXkisRih!%+3}g?0H>GX$|*O-vag$)YQ%XcM01drZGjp5kP(99HzH$?=nZj? z7M`89s{ael2?)RRn*2-D@Q%T3ZF_wxs~+E{=qtbay$44d<*2o)_+~qA`i11s=x8Gp zYh@?+M}FY#@9B{kF4$9}ig#1eU2h{HPQxnh^O_$x@{W_gOa<+Hw&`B>$A#?I%J$Sr zR?ZJbv4KpbxSw(a(NDx5&m&%WO-695!+o$7(Ybx+us~Fa`ZS5ilyUu6n zWlAy_yr&ocdp$W_PE_x_xc$ZFSAYjXAbP(G9rFacT6#LpVD;Bgj8fv)8)Zeg4_7`# z>gbNoZUlxF&>vcB1K?rS375$+MajC+A)jUqz)ia7Z8sXWvySL7*r-gAwj;lW*Avv_ z3%z3t9t$MIxfy#frJc;lGVdKB%_+m05;WB*FJtlbvX+g>G5u@5{J8RfNyUdDEgcTj zjR6cdPU3I1d0;J==XE_kfv)5y_h0H`Jg9OR##$4fn=`KSoZLnBJpN6qcItN7huoo1 zQKqoSP}<|F&QRkB6+A({wDer~MO8b3tdRzoM!r{5i_T1)sN%#8U3db9yERMjlU{Rb z{iXZ>`*&-x_XTA%R0CG|?Pdgg4Ov~ zMHMZuzdi4A@7F~SGVfEpRkD?aHFho1d7xmp-ZV?p;A2%~h8s58aX!jqEwcU+e;J=BKK+j%ZH6T13C@;ZpsvEc zxMc7|<*!LEEIe1@Ef?)yJ=jSd^KAz4n~P2zVkjZs#eelo4G(q{^$Ah^V(mPVHatmj zIyWYq>SN%fPupj*Eer<@r>qA;qxH6lkgJAzH39>k#?dM=pmtdYddMhY_!0mrp@TFe z##>tUdkvJ#sz&C7t?}Xc;knLUK#>CPV${L<%HvGi=E=hGVR#L#AgG6DY~-Uvr3n`? zH#oeQdXUtvYuwLxN*W^qQn+>J>!S#%c%PUiV$zw)}zsoeqRG4 zqtT1r2mBnpRfda<-tU027QmfVKcgW3rWXQSabvpJGHp(R0F2nEm+=8{J*J83-f!!g@)kEJ8c!_e%p4j*OKq@`MnKztdwInJh&|AuvHMO z`Hufsb8?B6R&V}DJY?0=B%i6XxgVopqY=n$t(qGg)c=@;I}jbCW!*JZK3Jkb#fub@ z-)ON>(CsoE_9Vu*M*FQL4kiW`%{X)^3SV@fQB#9#Q)QQQ2*nUOkyOx1)ZkWH$8(b4 zJrbAFm5FACa~q)8bz3tB^n}aX>cE-PNxCQh9(1phJlarcKW z;lD(A3DRr-CHUiRSx1Wt8Fryf{g)hDJV(e|9O9&j!dI7Js9AT)AHUoO)>a5#0-rO< zr2sig7>7?PUPP#Ut*f4Q!f?8YsaZE>QfM9i>-n=94 ziRWlrxm`+4UexTZ28Cm`#?)H&OIK*-l$VGw*kX`{r+;Q>-ZWG^0U96c#GI zna52#o%dn#mT7yHM??G{IO6=^3ff^zUlj3XgrrWdgH84$G;tCpw8W;?Q>%1aUl)9E zrcKsgcB4=G!rCiiZ|EHjuOXR#mpC%K*dzVzpr#h4ZXylRSxIc6z5-#4k7mH}zqK4{ zqqWc_15W_(C%{TJkM@aI-CRROJg!dxrvC5w!GM#?8#AOR*W!|}<5bj8pXONr>sTeE zeSB=piM&H>C!$T?J!UkDCy3mMT8=G9Mkra#Ib_DgVQJZVf9gp2uYxV144V19PdP<( zPl81@+vd6^i2+Riu5nH;&$%qG!wbq&fg=$NU{L=uPvQ$vq$1Nf=>3x4g!}VXYGl&Z z<~a6R-Fi)Is##ihh!QWxLitKZRuKJYp`lN!a|NR2N{&yO^Mo3a$Z|cPNi?xkJ~Vyq zrc2<(8+APWmjWGgGH2;;FrNa=(|i3aPv5VXuLyJ_0^ErKWB<5TNKvI^*08JPS2v}K zgImPsZ5DvA>~$C9c_70)c|+C50sL*A++o9dzPZ_HN-xvAr|&kL9drV{1O~L|D~Y(M z-m@GOrp*^*-3X|a%{rM}{lhLsO9+zjAf$1<{xOyISI-KM#kuI#M9NWqo7y$)*$>d_ zA1=12%N_k$ScT;6e@&iJlMj$Bdl18jKvUHLe=rhc|NQ?CO`1?CWytj|zO)yYcg*Vvl+!a3%xtjM$@wX#jSh zAZ_!pLNTzjGfjR1BN&|%`G z`IhDHu5ZH*tdhwIE7Ikg$?WJu)D$`@_6ceG>Mt_`?4s9uu{#d_Y)`m%o3J&uH#0np zZ~6)qy@Qe145K;)b66s)H^+#$$ zn*(3>EMcLhh+Fp+M^izu3f9Ty+$y<+bSr9WXnJ%C7frZ61Z6#Ko6bPwcyJqUsDofz zJ=DHYM=?37VhbAvvs*?sO)Gm+iFahwM&)}a+AC?eHfH(jfDo}QjW6;1)o3y;m@32g zvRXlr(I)Td6mltENhZa{wyZ1QR=?)wi}%&^pYr~Vuku1M-M3XYagROr<6yYWoqK!; zrWDu_&r{cDH4t97bJ%`vq`VVRqTQv1Lm^t(m(R1J`;ps&-=YT+5jvL*clSCHk@Gn<}G9t%8A6C3udXH!j@Sie)9 zvaItnWfSZvD&n8#?tHdiGi*baxz|EP7cK9pm99{Gl{3t?--SrqhiH)shgzIn-E`L4E_baCbZ|rrE+tqjUQCF z!*cm+*(xaOu8eq4GS=1t7BUzV=e(Hv$N0hVR)rA?)(*X(?H5D8+XruRRcLV90gSfo zhJHF{`6i}nWx&dK`eFNzXxNMiSfap4`C!G)q6@%K5kHxjK$cH0?;|d!8XhKTBz=*r zYT?;0(mdzj5H#}GPGbb$f8cL&4)~E?RL%!_7FweZCr$V7*InB{V0|8mUQb9%u7EjF zX;-)&66?(?(hK6Hsb?hDHFi3IyfIp+$PU^UIYpXrQ?xj_pe+rwZ|18g-cK#Hn%ioI2-&YTcFO=;L)>qS9)Z?+D=q0 zDboGJWHFFUs=p3qyQ#i!h>3_C%3zKYpLKHcEBc)ISkziy=O))bd#GX8W5>-os)I_S zQ4n{zs&%3zU%XoAY_)pOJ4aZ);S1!wPuq-R_GsYQC~DF8NApRh`sU=~9(4;#L3J6q zou}2C4)eJHc2VBlp%JR+IqipDrC!*%-AvhnYICReR2G;JuHAyXI=h?MfDurtP)0Ncu84H%hndTzq$rV;sz1Z9pfE zfOFb}#?Ea&&so1^h<2p-BFd$qY!_HG8$LDUj{4p#s%fW7HR&iVuH<>38b1rTk3l?U|G;?NTXOf&7vDwXSz7fpKqCgoul# zG~y@8H);T~=mj~l6nlrjwIxf3CD!C*Z_84VOhKzsL2JiS6*9e>SHj46m!xp}mS$gv z({_9dr$BxI!|3vd7go9$AsAZ#EFTM+h6*JuTHAi z3dAHov>MX~x1BLw*FeNu#_-x}fGouvJZ*l#m0W!boUmjq@wL=({dkP;W{f}#IG(b( zTFF;Y%fLgjX#ZeXAah$;giJ#^$;YzR;ULwu*U4F{gc{udv!03XE8~ZkC2M!9Gwdg4IXI~RPaY?C?34Rn$FbN5fdf%1CyA)=H$vX!@rylK?~4$Nt^ z>&FZH-}$dJqT&jPX5Q}bnZ}!atTaGyjrX9_Dq(4qD2#3DZrACz^VbSAz-Zs(4aoS2 z2Y5#=XO&!Nrwi(H;3;sscA#Ml9jUTK9FPwt_ep{GmYnad*@<-ZzKxtQHtMPk^Hje# z&SJ=t)h%7X?TQqxFY{dpH0GA}z*V}q;d(}0zknW9*&KfQH_A79ZT`J76gdCKF>5cs zOLZ<$%-3&uEcPy_9e4{^tnKr!zE8E@B=Zko-0G@g{fDGiU7R!O#JAua2JPb;<;Y6H z94U0-BLykLJV9;l9<)+s&*rr`q^!7;jr!l|tQgohG00kLK~K z-%_W;9!+}U$pzEKFcW@W=Lsf)9WaR#UxWzh>c(E6kQ-szDEwHeBAY*Aqt>fSO(w6~XB?+TqQXtSDpxo$MV z&eNVwtGmlz^w(3>G<_cs!Ek_Dt`R?Bsw2_%_oP7#gT-|%9*s99eVcfJPP z$Y;fvg51T#Qe9RBQuUOc)tW3BJu@Xk-f7dW%Lj;(9O^EI?TT}=9XQ=!o$h*-`{A1v z`4Gz9_TouKnf#QOhu^BT;{L9bglVC?2Opjfh1`)CRA2h^Jvr`u7N^vZaUB*<=V({< z6teuzV$+KEVupv*^WLuZN>0sZx{CesiUd{G$UL#rga}~$O}ALJfU9o@(G2DEg9^&| z-}6)0OYe-PAJMn09j-3g=V-=CCBBxtPgg}#f%!2@mxi>#yg8)RIZd{lv;EYwPeQ6% zjd4`=If4nlgH{o2Ilcq};5>|_nvxt>KD|}D3@OH5c{wHhZAle}lG0Q_u@%&;K-8Bn z52yJZbQHaOVGb>%i=WH%*ac94&kqyt5o;Km)P5jV=t1QY=|(>j`e@iKWDwMq{TpYR z;1qfY&ZcLrGLAi+M6Wdg;Vb%>)dPN6lyBx3x;!vge#?JcZhm+SgY)f~W#38?wE{7E z=*wX2*&Hl@6NmKzUuI-pz>0dttZ}L~R(Drb-fWDtFdI0!Oc~oI9UP&dMy}Q=OOh@lhWdMnzkWWsgrw1_)nf?!Xx*+Fi9TGs<;f_sjr1^9sR#mf$w{e z=K0G7U_uo#AZb0v!a_7m?rg%G5Lu||XLRr! zzI~L4*LE2c9~LS@=UPbb`YKtyhW^HG>8H`-itZ6A_BD?%yVR80kNc+)~ zR~zeuT(6$q_Pm%J?DWltYuT}&QPwY4jP%W(`b#NG>7mNKNZ&fEUC3sWE`HfU6hUUp z`hFr0MFqefd;L6_#iQ@q&!W)p`Jd)d?Ae4>Q}l+`3BxOx^V5}-&^;7d@B}p_8yRB(Jlz{8wX~2@;dQA2dp$Ep6gVEvjpkL{Xpnu^}r2HBAc>6}6#DiQ}41V({;;V;JY45%FGz{7!B$<*^33!T4Tq z7F{GX6&r3H=c1~;PnFNCM74+ddCsd1`b7$sT>4?2yz^{NG;jh2D+MWAg}`L?W&I|- zC|9#mymkn=a7_)4>eh&Lk^50z6xJoW@8l>t5R6P-n6Ua6X=Qk4qUphZkN$6|PXn)S z6#Y_LE1c6b1Lr3}`Ehlh04tmZ1D`kUCeUP zK`E}7e!Xd9ngSK(?Q0xMbZ)XQU`_Wu9LxFZJlU4tW7v+gQOkD1HZRIc5_ElnrQ42K z6s98#vJl&sKnc@!QFkM5LUX(C0FI#V=}7Ud>^a_>5% zts5~*2=dwy9i_k3DgkFPv?u%Yl(1Aj-U>h{?B)L+)r~zVtx8vwBljaGabo!5V5waD zPmGi_kpM~!XdOyd;6LTbt>k26k&Uz+ejPIW-JVQlzeH@`JMU`osy2Qi>_>!t^X8`x zh!1p&Yf@xUeHaov2I-bwtDNWpwP%kgE@!N&sMD>ZTLtB(9{OFS`ftuXBLc=cJ6Wim zb-lkvWhg-)Kb5(ozs^{;9sSmxI{54Q+Ck?iOROQ_lW<=%ZIiORYPI&C&A({xVJU(= zra}x!yq|PC&#l+xwpX(UnjPkMAp+^J7A__WbOPnUQj`iZ=c7C^X8nyd9Q5iPB4XRl~p^k&?l4e1yW&#uj{HRn1yT+BVJBvLT2f`)8v)~6do&;Vxbk5 zrN7TV)W{3DMcPlUw}k48fLx{Q;%@W-r1ljEbmP61jsC*l7NV}eqG|FNEG z=jL?q*%$uX!$^qGp15_A(=1t4c;oztxF%{QCEUI3ml za7ook)uq0L=!#!XJnkQLg+{#cr7m`CmR%~zm;ufiZEFZvGVFHYe2NnrM`tWiTfTN_ zORhcYg^}AQTgS8I_;gbC<7E!26irr!hh2})tHA#dE9KV}MNFmzuqKo~M>saIXr0_c z_!V+r(l*XPr>cvja&?9p8DbNhQlu+dU3_CWR;zOj65u8|vxQQMn$BGxH?nvrp)O(( zKPCsG2qDChwQJe7u#TysrJKIthsdEZoAAuL_F>cm$~{SLF00C4L7&4e7~h{D7wt)m z-3QZakq3s}UtsLg;mff!YXi)6HB||{7b;%{@lN77IwmrQzW~2tTjOHGA!TJh?()|x zw`s6)NE&LQx-g&)SzpHSg~Sg$lcsbK_6BC(9Hxk)Xx+omTT2=<4pU;A^ss;xNC|OiPa$%W^b4Lacflh*r-|$UNjC5kmHIyergqSJ6UbS zN;-5a0znO4+S`@>wE={u+^5mhtjO_Qg(ld6DqLS^;l=t%*kJ9z*vsZSr#(n%4xHV# zp_iR_R?~*XCfBhkuV=C_sl8bepqQOw5gB- zk4Rn{yZ8S!&ef380_Z{+n2vqk!!?!)>&sU`k1L4%_r{&2e=159mwR|Fmym)_j03byh<;gY@UGsZ60p+Ih!sdnKk8-Mm0a2{)YnN^Rm`v6DQgF0%&H2zr4Mz)J4z=bNr-8cQvC;Lg&s){f z!_p~9VyNab%h*lg0e<#v{kkumcpaBAVJU;Aaj~TGyn)ba2|7Ga&FA$iFEr!#PEvJ5H=Vw_3P|0P} z#9}XBnX|X(Z2D~|c?$;s`=?r&au<9u@fuMB`_`6TQT$7z!&(V-|ac>0XJ;C8~^+&jbxm7@@2b~o{i>GZ43^%2d_;~dlXq- zP~f}~$pIQh!>r!e=yXo(oON0nK5CZO z@j4#j8s=&NUjP1!===nw)d(7I<^FB%apc-}0vdx!gO}&fAH3}##<2iUl1u$Aw$1#L z`%wcf6`XI@=vv?aiWD071qK5k7V#tr$@Zhj$x|bCi+_V8|BHw1 zLc8tB;sMQaW!t>6Iq%NB1p5BUvYCXXAGl@RJ?v%tFLz6yWVQ%pcAU3B{ll#%f66Ln z7~T+iRA9MRz+b7Hc;7zP-#3ky`JKvf;uKkzWnCJ(*tmMCK}Gc8tauI{dR!CESsI5X z_xer~QC0endDVV3e9^wVTONU(SeAaOpy{y;N{2Rm5Ur&yVJlc_($x}F*4xerh?sUB zsW6@0(ZPxzj!}Sm%sG<3cW8t2g?UfkXgBF*Mn#py@OSHkvtT4Awc7jm4mrc`%{HqG z-SukY?=9mzNJPrgaR9;kRp}L++Kk=qktS%;X4Kka)7jXiJzq;M2k1!gI9YmfWh>4q zG>W1utES`S>QGo@jy-&_+jO`M%6Hjc!RPKARvmb9MoFP2nk&fMxDzHcE0pXK_hv~l zCGCqVd5B5dpNvYqmvFoy3->vdOk z>C_hpI2V-0#cg-N9MTHoMvkg5+0Pq7R_Qq$!cq~RIOr>EYL-)Y^1RVKAvR|sREQ5O ze^@lymtEtiXlp)C>As1%0AW^Gs@z7Apq1<7r zmbEYQG|@3OSWz2ncj(Fud}1lPYC`VNiU>%HEV}mWt~b=BoBc;0(=Pa>+pkKRrNfgn z{YfCFsHbVa=u)yS0YG})kZMQOXjSs z-zRX}_&0V8Zq|V!awUDI5k9jP?wSUbIuAra+p6At!K_+C88>t11>L``1BO52jln)7 z{B-9v?=~WjsrL-{e2*Yzat`xAQmGzc5U4a%w>JT9KM%96bUoB!dSl=Jy`H##aT=0y zEN@{+@u5s{#MC@gLu7ASc!gUE3*3?oD3W8OzJYC*?E`fCnd0*%eS!G5D@A7+MHOiJPcjA6iJ1x6m8_BKb#3iKBA`>XPn zjD}=X62;E;Zxp6f-Q1&O>}*i+nHodYV)_<9>A=8Upm02~W()^gQFSlZj$2@;66h<# z?ng6YKcpXV^1hm!n7~+8B_|aYll5CvCY(WLoHtCCcg!mxH#QaNf)E=@75$;MG4v?` zt%g$v-^+6SWZRTEl6#zVJ#!--NjwH1c6`E&luWeJD#f%WxFFZMkqu%xEqgHuwaK4x zhygy^D$uAR=f>TF+QjeTbag8%xg0-DSnHl>@dzsO$Ncv4NY7Ha34DZ4=WHpxv*>kA zFw9usJB5cHaJS>6aYy_+Hau`<_W7b*@<~)-uSK*gTqq_RXGq~??6}MG9uZK_ACaaU z?;BNVx@ssL@#0 z_&OiJ{|wXzgq>tsvbqNP20n>SELF~q^MD>Z@p2d*8n`shL1Ov2YaljD>XnY>#> z!_R7(rI6~uzR9svc;;_S99$(ptK$PFz^VzhS(T{78Xm`mRYvZ6wAt15eG`W*i+{dF ze^F93-%0t?V+)LK%21s;7EWi6$qYLuaJ6l4r7cR;?#8uw?`oY7chnZv2hyJBR;IT# zFzPv2v;8~EL>{99Eu$ciZI@{wd{7>eC z00<=3-M0J*mfrym?}}jk{5BOA6=U6pF_6G6RIJ-VT~osPpp*c5q&Sk!@tn_yGh;5UVY%CrS11~#y`zX; zeNd(7AK=F9V|iA_y}PH^0$5~u$)~7m6}42lJ;^9&fQ(9@dB}*JP&Cu?8*L`10A(}L4SF$9&FQ>K@OCA5{^KsHcLiD7> z>rr#Ppdj^2Q?p_hRqb?aJ3n=d&bPFT%`Pj8;gF6jP7wqOa~@t^YfQ9a89JK~W}RG3 zCL|vI+QqvV=v*a8rUP@>4365S20BiyiSjH4QC{BdtT}@f*kzT7|1eVDYnY`6OHIP_ zORa{^Y%M8bre^Gf@JLD$QOoh27nu6sdsRaEw4 z#7jr&qINzqf}aITq4V#0fCj-n5$-mSQjJsR28F-<5dpkjGb+T3;VJLh{nc8>_O|Vo z061qPCx1fM{8YL?gP{gg&I~Jzgp=1=nQw!ayR%dy&zv()y7P2+9?~9&6wGNj1;&Tg zGq3cEj7^b~bjk?MGg6%nNcM#Fk!pZe2OjF%7b)M)U2n@k8(EX4i6#%zB283rtJ9wu z_;m_Ak5!QAoh!T|!YAiO3XT2k@0=DxyWwaJxjuT49NVwz4PkEV#fH7ax0OOVl?PM0 zG~mX)xXD)%DjTbTj8A-F`q=!D&cuC*Zpkc!`-Rf}ePn}awl6Xs_4YMc`q(g`6RI!1 zEIQ22QH{m2Sam;?#ODf3%wWKV_hkgD9}JCWTAFfgEG(>|`NwR5?%k-s-OrEbMPUJ$ zNxYm34M2w#vbkgwFQ1>hv`focWGiUDum>n|2UKU+Y-c+T=cQ(@%pP<-r&`hB5P88k z?*tQFCYbl+b*TQT5amkCvbi#QOWa+xe(i-PHtHZd9T%ynz#EATMlth<2uIMg0quuc z&97ILhMB!udaGvsDRiZQqIyik$1-3k>E*~@p7f+@F9}9;**X7u0{D*=ZGJVrH`_vk zWqoDL7=-wy`_x%^f`B#2s+@f!?!vKNe!!ZwpTjn7G8XBW9~%B08py`^sg!qPt0siN zokP=OTaCYG%uzDcDN|Y53z_}o)g(t|{67DtuOx#PY_?6BFQ zhefP1grCp+mW#>E3-A|3qkh%q=|zVZ_QtR%*RH&tN|F3e*#B`q)H)i=$mVyUlHDJ` zH%M3RvVj+5_w#MBzdVCnUpA=Gmjh!8RsJ7Rxjp$$Y%-Jr%f+o%8;Bnfx;m}v2y$Mm zABNYgT~8cpI%6&Y-rlaKL2{?$|A%LF1hmd`N=?55RIqnE7E-6G^k@_{PPycdpnSh(N8Z*`b7kRw$0nS&eFhj;6w+Rc26pwb`dUkPd* z4XcC3v*%^oD;bz-5B7(m*`P@h_H5N3c2oBx^^1a3qN3W4SZmMsDt#1lD)nf9hi&*! z2}iQ)?E>+mjTqPUr0Wp=JowyhzO((eI+&z%JzeNKd}9IM#?ts{a6H37=5umJNox+HDK4F; znbnxQUc9mOrI{kq0ayX7v2XDRxBK!I*z2k8PAhrNk*^T*S;~ zAzVpTQMlRlc~*@5kau*)qa=pKkG+2rh=q6T4<3d)4u|QqO{oT^DTNVcC*5N2tQGcT zr27a4u? z5#^=Xmhw65Tyvz$OnZU`TlLXY~^9wcd>B=xNKq%`^Ag^XFuzv!_q~AIANR z`1Sv_rTuswBd2`SF7e{}f~tIdG-mFK;}S+ybLJm5b8fpVHdDg?f5>JiMd&=&(ARIR z5cTNLj-&Z~umb&i&o`!Zm)|lkI1`U-@NjhLBhkIT67 z9X))XA$kXtF7t@HH?aT(7l6@oiJ54hS~z+dWO1132C_{!nf@`%r4`|dSw=!lS3eA& zc$BkWWLh+5gPRilq@kyh%cgtyWSD;zpkOZZwvWLqW3S!dOAm(*qhsc>e=faRgd=io zu*+y)H%q5y7tquXY0vrMSk#2SE|SiEl_kEhkm^Fj2rct;6q`Aszg!<>#hJuZGYpaO z=LCK{oQWfK5Eh0#a}30OHb1%Y{aXx(S&Q(UEJGc%&GR+Ksnq~7p^?V=Y7@g_0%8^z z|3F9QcERIy^qgmdYJKUIcTykOm)D9zx;s4q72=PNjkJ)4(SXLsNjF=%PD-Nd12S2y zwWepQ8JTJAre8!tJtk|zStP2xkV?-A9f8C5xVsd|t6dL_4oTG>(^j~l<~jWK`Tnq> ziAvRU(sDvq&5BFtI^Y>Mhy(HFzYXHf2D4eIjSWs|;rWR!Gr4UE1qfzu_GNl{@4+L- zvF}zko82KQCcI9@{bPbDohuC*baEs(Evf(?9p<^TZJ(dTD4DAm?+3*~0ra@PE=w<8 zTPLy@Ve&84n!WXBrnS7+{ebVi3raMWPVa)%dHmP~h{~xBG{zw=O2?ZQrj6?M=RbUs zqJ`YVB2Pm78J)izitqh|nMrsEnvOyW)usHDaaRlUwPT`E>d|VppUxZYJ|x8`Y9-(6 zEp1W^&>{v0a&}OK6G6sx3c>~<>;RWPr8yDD7DAs_rviF6mFl0e<>i4w4pG4jndN*gd1567 zVU=wnjIAOuhIA+FB7VlX{01p`AAMRoV_%ZJK2T_m+q0ukvrXuBw|JU5_zD)$-{9kg zKz3F=&VA`WB zK%8$?(Bq*&?@_etuw(<>NDcNEtvm{=I(~;0TiYe=V0a2jHkOMNri&Xhl`0$yR>BnA z@zpRj1z)bDCK()9`%b;eVh7Cm*(Xg3sdlL$E6O5F_|}gTAsQxnOW`U#AF5lEk{;7Q z|1YZEJDTnO|Nn2RS2wDZ+O>%1P%=VRROw?|)?kQW2Xlmjk zO$0u=GoIJ0$X^3zEW7i2O34PmKuszIsPlZ9{Y9k0$-j|R_xw5PhJRHoj_0*VjGjY< z7))ESC;!Gzen}a0)ne4LZjEZATf_?9BtOAy4HE<>&dH6VzHa|Mz(Q172(0JKke?7=aFuS z-C?x^Rj%&$4`>ObQ)`uWc*XGDW!SQv3Tdco#pm-#p6dkYzqcE_+`hXfsf}hYH+dqZ z;?oO>sE$vZVEqxzT!=n9QvqnACO^YP*jX1TlUx5$02z_A<#1{=;5C zN}lc9V2>drX4~SW17^jkO~OkKL%F+2DK`_rY!}1+rLss@cNBN{U5eR` zVKVn#zpX+Y=iNCL;X?GGBuWb@;dZ5d$g0ed9fIrCx8SNlme`aHr{ME5yf21R(h3=) z#SjOHb$XocifdND(@Yh%n`=F9D6J@vuTwl_7Fr8={mz6nOrOiI#LDQSWm^v&jn4pP z%{irut3%Ubb<3Vn((D1}L9GPrOfR`cplrT#SNNOPr|FfmwY_u}A2QI)ax_ltM}`XY zOC$W(6~I#M>|)Vk)Y}9gW6^}DkXsP4oHqg)q*gZ0Ya$+MHv(^{1}E~Ns@mviLvX~F z1_z?Ym-{4Y@l`x~OEE6Q(J3{PLnnH5cfqGCaSKRPxLfv6v_fZ=%VO#qlH1fU^n&59 zDrLx4rq)m1<$WG1eO79=d|j|D{hj1Fk@mwrN4zt;w4RNTtfFWIeN<|ZU3`0j(=v98P8nF` z1;5{zd$%M{>-B=Yu)p)K$Z~4SW(JJxiPpw$Vt2=0Ecb*wL1SI4Wp(^zpxz;->M^!A zd!0>Adv5aU>#-7t4Kx|m4E56of`}?TWc@yO8abY)!dkvlq*E%|G0J|kLvRsaON#<# ztuYeDiOyymp*#@~$o^e84Smdl8jIO!b$8iR{R?VhGOsdPTN$r%Nb=J<;S3`NdaKbP zRZzvbJ4$DGgsuaG|(&f|Y!z zRrVzLsXGlO{sYI`Z)-#QJlAxRd;OgS?8y}l4o{xz*4w)Gu<6rGDzFp}r^#K2 zEAVUPugCi$-ZKQ7bawL)=%?EydoR`sWp|oY{#j%y0Ro4jH0RTMXTK)ZPtS zeXQX1DEY?IY_pRoo=c6Ojm^;%fAeHKq41v>3=;n%7 zdkv)HsJl^YEDLdAM!JJQjrP<52XDmzr>2Wfx2NpKg*c}-@1@Ieadl~uRDOZWzppra zB#)$F*Q+7<`akfleTDb@y;JO2s?xxKtNab%bt~WR3{+>#3 z+;Kv%&Hi=h^r6>p|K=t9G;VXk=fV-#CWACwx;TeA61(Z|p5I0zy(LtwN}m;N z@ci`Ulx``6*>N-xQMsRk_pErP{=lqcYRY7t{alZfZdF;dI4&&xtT!-kY5f@vVckKz zBGN_%pQrF0h^tewY&tJz$*LBdh=Qzz1#Im1Clq^5rCg{@0q$>M*!+xEiwj$4B7MKh zq?Fj}uxm#;+czLhXDPBhC3ocyN)P(UNz0#BEU1Rg(u2!E3R}th@s?1x;i|6pb^K}Z`5EFoYmO2l{iKmzy|s5?ncv;c=}!-KvjRGreIc8uEfeqv7XcF zY;DWOYQv*+|3?w+asg|c_#IwbjvS5Qf|1I=h48CiAd?|4ZN5qCl^xh_mgv6Q21bor zEpko3nZ<(3w>R$##|o@BTBb9>g&{3eX#QP?j%bhU)N-l>%VD&mN*)wDdWVLGe;)<+ zMN#6We|g)Fxhah7CkAJDA51F_um7mCl||Gh_Pm%N^4rKyWF+HPf-k5VngO|!(yJ|a zs50r*3lc}JArRtL%0Ps@mDh0N{V{9z)#{N#)!-}(=&$vpqOGE(vuL}G-*vJ0gTl1x zDbZQ_;%XTS1Xw`N0f1Y~l?TQM?d)E=w|j);4COcO3JJU~Hi~F*@|m`*OjHYQ*?P2@ zcIQ8yV0p2Nz%3Br_tVSERzEpf8({&`i+=vvZe!lh?D96Myxs_I(FDTEUB|QgPyR2) zKJu^l@;v?%a1CN4wDqk=5&8!J!t87(Zg8k`X7#&e3>d#~;ibCmpDjq})UxOH_Q>23 z2W=qsrG}1!gf3GsfBt{vCg@)>1d;z$6wVEMLz!U91Bnelh0}+r0{#{rqxb`@qvMB1;shsFoRp7vcgkE96$!SAc6{S&;}6<6*mUIqaeQBy_?UsXFW zwyQB2JwzL=_*wcE0;1qif|$Hoq^dZ{K_on*I~55#6!evU4On0RQG1@UFBRX>c-gbg z!iO*`HA;Gkt~<-YkL?4?NZx3wAMQw4lsT>y&WxLjEdKQBf1y0Wp6Ke9Uv9V2D*x@7 zS+!uzkFafJg&_yX)O~T;=4OGQkU$r;t`+Kwx5hhLbbta zGOTKHm4e%jho`aXG^MXB^ETTjnSQC`A)B${=;|)k_*}kLbDqB6KT%*_7wk>T}U#cni%u|Xz?NZ+(JZO60h=72f!HfOq&^HSn3YV(= zKb?}rH7bk~qC2d*YhnEQjk~IqU7CpzB-c4IcQ6Uyhzs_tadlHVRz%I8-brLuV=Tv~ zuk$YrN-M2UdW}m%(U}jBHRJ7Qv4TRJFPC>x^qUIE1};6dmv9fD>t%gz0Uq7wP1>3J z8c^DoPsaboIWD?1xm$3`t*e&RqVID3vJ*$xBW1`fxA_ZlYnFI=kA|!jnNfV@iWnb* zp$Yg2%v`_7xX~fd%GyM$mCiiH4pGfyx?gKcr=6`}ZTpMqNJ9STZ295dC>_M;B@olYR^GSCcmYE&uq;g{Ka4ST2G|FKK_+G zR(tEU44))YqV+rhTd8gf>@Fsgi!WyM>^IG&FhX#N*=XfX!DY^(MHcRYJ!|0h-n;mv zSk2RwSWfc*@Z>_Y9xNGmZI~zT%Zy2i+l@Zp{i}Z;wsC1RpPInYbUa{w`uQamr|bPX znf7#kI)hW})JD5K%)qpmmN#l}VPa~8hy{MfmgYMU5nKEQW|y9vDX%0;9Dr5&41#`b z4OZqvZIFm1B;L8ui|TLn53KnaX-i#1d?|NNValETP5T$4Lzx@7)VzQBi_`6(qYPqX zou`AV@6U*59u_XQS2O7cC5_QT?0!Hp(6#rr+O5+nEN>Xo&bhpx8Puak>dih(uL=du zr8%CMI%}0|OdfdbgKkq?6*OW>tmQ$}KP(f5*3ul`=x|tKGF|le5;zo$;uOklEYZRq zYK^ur3KP(jcT_Gbs?DkV|t}MVU^6=@gENlVcS?2lE`Gq2iJic%W@rgF6 zkjyuyQx80q*Dps#;~8*2oZH84Q%z5p4-u3S=r2PzCf zJ>>nj|MZguW&0jISb6cgZn{j8kN+tLHOBpYnOKm1Aa7+B=0?kcuDX4-*qr~4S%Fmsd2^>? z75_N-4!$-57Vu&5jS1K~w&?@v#wuF1fX${q`l>z5u=KEDPnCY5XR5)P)^nQpuh6)+( z25K30eHyy~^X>z@^d6`mZjzM_^iv2r?057{+@+%z*Kfs17JxVUW@k+vuK#8X;J~nS zE4tJU50wy)W*T5hRI+mAj?WP74KrXmo{-Wk&9%6}#CQ4uLv-|fht4-83|f}jrti3f zpBuqYP)l)PcTX_R5d~aUNgSg4m5sD+@Z$o=G!nadT1HDLZrZAv6;@Rb$h|Ym8tH%Z z=61p$A_RCUyk8-1j%{ zL35_@Xf882??$x^g$d7i--sTYoU)BV#y|&MTmUCd{t*`a4rwr|;zi(U$=;dGLa>>l zz8CQ&sRDZojKePPs}M9;D%Y1&`4XTA)QFVr8xC)46MS;j2X&lDA?yHX0$8#qk`ykfviOFLzO*c)_}cUGI^HJM zAsKd1mGn|GrpogOeOBn#`3c(C!bXkS_pu1plb~3h6lQqW)nzH=ch%5&MC4oM(}>IZ z?OW368X$ypPe$0=FlnW!!UtqDXk<^kV%NudO;Bb)FQ5Q~9bod(LHrIUhaia=i4aUb zUh(T~4i-rb9X^rwt419zW0GbfJ$Cc*0o|+ z$}zjRI1(Yj#cg9o;qs#x!Ir7mmX_reXy1j@*-yeTH| zr}5021b;8{kIO}`&0PCXH0Uy1YR`la`O!UB*jqaC73EG{(5KVXh~C+HO?N`$f!?4w z_Q+2N@=YIId1j3yrL~e1#8XIIB_5C< z^{?4yG%Nby~bq~h}3i%zd-+5U!r=#{Z+mmki>3-ht zlNwYW*0|n27jpfK)YiA1_n?;>fo4vf1zHXJAe$u>fGq-#Q^i2`bvnOVSzzxgkHrVn z_?Uc&BIEvbI1EMnHqw~dlP3YNS~?q(PmO%Me&&=)okHUC-N*4fr^9s-qCpOl>8ELu zZuOr9(*u1ufh|7mH9i}^V;S!A+i-LnAPr?CSS7V04Jx8mEu!`6sMC0n_}6aEh4zjr z03lO${_JwR7|UMb2-aD&Jm96i4On=XXCmHO$V)l?71hdFF7XJa%hE~y+m^trt#ai5 z7#Dj;Vf{QG02u<(8~rk+uP$DtfLJRFYt6dFV@nhDSDWMR7P)5EzWwoCCjkjH5`uOb zl1^!mvrzdYqh2$(NM$AUPKE3Xs`+%>3kt8b-w;;D=})%l=m%yKyLL>TKlg5}YyHg_ zn%lFWx;b^BZB-3wvo+DsnF`*Hf&6QM4RAY8iW~;QBGue#+Xj^)2aQoZ1I&c=uWN`(0RxN0og71q+3}*SLXTUaW@+&GsD*l z>bv~^h<$(p%_kS%5C^@57=BD=eZP*gFSIhNl2KGgVOu)j%~<2xf&tjfX(j-Z%{N;% zm;_p>K6{vjIm=KryZp9d`e#~n!|~34e)9>P$Ol4GYfHZKs%_tFlvclSX~{V}*kzsjW`Z3co3|p`_NX>BvD{j47#1MH;nFjdfYQDNq!) z>3fc@I_{Oi#JAO_zcg8};1Uk|l%ZJl%LoWY!eUzE*90rkq<`;y?O5k3l4jp<8jTLk zU)lwDEk*f1r`ON`6+~Pju_RGhTd_m) zQ7GqrQc|SP?+)Sa1$oyGC=FBSkor{ezJVsB^%?*Xg1}S}wX>lZ)XrgUB zwRwugTnruZ42u32wSLx@hwM4tjuW~0)i2^-N@D?IIu|94-1Jiqm?LTbj5 z1cbio;d248Xy~-MOMwt`%~^&mzr=np`OTR~f`0glxQL6d?@#?Y#&Dda5LOlrEVKTo zFv`Bot?-B{c~&KdS^gwC)qR$4BTn!zr{tpA29{N`KCCYsqqvO!(P;XMH=z89H%-xE zqB;`%CHk_D62z(KJX&%4>RG8?h=V691s=LX8@3|;d0eK+OW>m}K$H~9I_Q!kyRT@a zuOlpSY?=8Ok_f!@JWE*$-}CMLr4QkGJ#hDzR!Gw|hNU0hgFA93>|vzxyfL{pItozQ z7)`03E@rMYc4x;rM&wqp1c~h!GZpZeVRgt}->p@} zjl5<(3ujv$=Vt6D$`O>G=p> zi59I^G@mxQZGtvD_n*vHEALWtr{JAs*TjhKTOSF9mXB!{;2ZhQ9y-T_Cqy$&@%&13e=07 zr+7qWkGffz?n&p9Q4EAV_{G(yvN=uc+v{?p8J}9I}n_xWZbnE%Hc}Pz1T;lM$>+#hHn$( z5jqZU+8c=eokum)1CO0@P%UmXd0;3TxMq3#oBb+uPoQ3tJ8aer^Wj0{txdMR7km@vO~r}kB7wQl_NdVy z!Te)y+mT~Z!a+LXI2ax%`lq=5p#CrAXa2prkMUs*$jL7wXSIKF22xX(*JQpi%S=B# zIOcM-@(E>jZc{)wpyDBM`;*xJxKq*h>yZ#%Oy{lyANAL^9w37KxcVo3zePsDVFB8A zulBs@WPt4#DR`J2MQ$qxTVjr!9#L8~CR9iecLwSIMqaWCLM2kFk?&-iCzLrMi%afC zR;(ByO`WY#yyh03Q5`l+COUiw3?OWr=*n%m#tX?ZA>-z8(-!vdUNhd2{t9?C}3!IB&L;)*4i*o=J=HyuSlvLk}csc>P}Gw)4|i^zo;RZ{5GpF zebIxy5jkkKx2w3m?<$Kn-*%Y~h+RtEdDZun5|{R#ZbnttWTqzUf2UzEVK;UzsGf1% z8~co^u}8he{S|L66L+N&>jHHzN)u1E8g6W|*zK+H$Rx&DBeSpFKiPlig5oW?3W^^l zT6vca*D!879s9-Yxx$y@@;w>moXg>p6>5OZSB9urtFoOr50&4xYDNlOvOHiFhXw(DXOKhXEy6Omj;@#RK*UCWt8 z>O^W8yt(v;j~vw>v_z-YLn~a>8VW$Sc_n90@+EKZrhL~$o)bx%JM;e)MDdLA`O;q_ z-GU1ho~{{>yUtx6EDaFqYJQuAJ$rK^nLTIo@(`$!?1*~HNNt_mp28R#7CY1>*XzIV z5PkJ^@0-bs4gUf7(gfZcOWk)gIKjrW?;NM2~{2YFRgWQ>T6>hx@ ztJ-PIs52~9Xgdx{T|d6+Z~GGH(x3; zE1N?S68?NHrB8^QP2eeUfRF|A+j<6Z@Q|@zpL{{wjL=yeEd*;=J~;>@LlB z@5|-hUwP-RUQZAt+FvsCbb42J_I;@2hl}r;)|#`Io(dKSRiyI% z3RG3Q?>FsN#$NDujl>s348Q;qUH!AeySsEFLAh6pUUf0a3z?T}$*@gguG-TRtI5tC zouT&ii>j&wmr=g}G`70IFowVlW{EJ`sqjCFa;{XK081uu%^r-qRwgkLghmMaD5<;< z#+idD`@Ueo?zr)#gmng7*^9e#0ur9A%Tl}=Bi@mdhdp+??c|i2FV&n<>qqHprXMp8 zKex*K-VE9+>NcjPIDt+{+3pT9OB*FV#f`x1SWF}+NI-iYO;EA2^!g~ELX59PcHI`5 zm3lqo0}Xuzi%Gt}1{O;KqYqDEDvb0DeX&f%A;@YAW9hc@4@*PU(qe$%mmms1UV zqc}FErS%!5Dp_T94`g$T?i_%3h|EBPO9W_yUp$Q)2MPHp9iF|;{hmyXtm^)K>uogk z7hCTUojLRUmDIGGq|f;jlD-Akg-ZI_L)DZ+LV4|xJG(2S^#&p?Nd0^9{6r=YDE+dL z8)?0rE!2QhWXXM8=!xb?(VfuTkiX?+2{8VRsD2@Bf&K)>t&e;^T^L5^ zs&c6VxVBUe^{}PiLTA#s_128;fN5%J>p43L6Uv69-nuT^zx!4daY8)ILt?(=GCrR$ z#kpO=-m~-rOT&@u{LM71fI{DzqZ$9DJ)()uzI3 z{57+GO&yGeTH|uTDJdI%5%xpo0YJ;h&wsxwG4b?Q6e^Dq zI+9-R9kRVpK|0q&*wMHe5e_)ztNiC)&+Ql+^-e@3U|gqLxaC-2Xlful zW6p|Atn%2gZnXAmtbLtOr-`IWi(yx}#xAcEz)^8KOb zF^b134@viY?@#Lj_6c0E-abi4SI+xD|VSY-A@A{9?hSyjd$H#AI_*wB{i z5gBR?x9Y2~z)iPcksY%RJYN)d$6TZE&olpaeFW_<0mR)iH9jP}SW z@?jrwpfT~@bdkM9y?XpQSO*1c1KINe@ERUT>=jT(mYv$rm;wpvk{tjew#S#tzwe{4 z@yHiImw#Pc&gwJXbyf&pHJ_&dY?lonfrHZ!ZCeqZRJ`v0#JlktGVb5U94@J5;zjp% zioe;7SY42c_!okS8D=(o!=#NfIeFgLrbj)&B1=Kq{hP39A@?2eu?j0k1{=SOu4zw? zYhK2jb@N}T<=h?y+{Q_L4kixwwsX-onH%dKgx)8`>m9655~=~H7~yb~RI89iZSfX+ z?j7kSGL42XgITjW>YN^ptneZqDB0k5I$Q8itfPzUtd!j(C26e+7X8-W*pX5D#7ay8 zv25g?lCz~KaQVf5drJ2D2@qV(UGK&F5p*V|_(r;5drhN5{0GPV0cKbGj%RIz-QCn@ zGTJlFZc5}k@c1~nEdg~5^E9=7rc-qrQi{qd^x8!I>Uwq4JBte7K_2X&FWskku4C1X z9=s9t_gJVfZN;^{t2-*xtT&)?Jzw?QMIY(CuFaWSVXD0nz$`H!%M6{tuhU6?C%3E!vvB?UcH*7d4qdls7=zFq>Q&x5zv>N<*QHsf#MwB`9~&wqk#(8pnR|x(RWiDP5{CA z(U&HH-c8-cYrRBOtS-l)0MI7oiXUxvh&16q`uzywC0=IQ9Q$XH6a(bCB2QXX4Kp&5 zn~dc_+s`}N)JiOp`3(>43zdKo5o3`Q6lK*$s&W42{XHDtGPI?w6@WTwd8B-Lwi`bF zY!)+53g}j?%s%b4^Q)J9q?5ZK)?{T5nj}B^^80so4@XB-sb^j29MIS=tH*~kpK(T) zCJCO9A+LNS@(PvYgiQCfjf`p&NfBh8CF0TOQpzy7LdD(oUu(NcO4Zb+z&hh_oiaog zdzQ^ngNDhqT*7+Pm14%QLCx0r!me!P&YSg0Y^NEbmjH?|zK-eTu<$L*U={Qk)TD!x z3m;|M6*8tJy%SZ-j~FkIJzb7Wt;vet!O^frIwZk05~HIw+WZ#d6aA5+8- zuI|bbwlUIqttY*kO`<_}N27l|B`S7aMn)f+wq<{_dO*yJaS|c%S-g;IcL0q4_&qpq z;(vEbSe$*Jkjps=gU4YbR!~Mquo<`Bc(`u~{YDGm#5Z)4jcJ zBu;e{rI63>{g9djB_`8jTLFrxwoJkw^wQ~Gn7+X;Y*quEDF$=|suk&j4aRPEgHzmR zWlMS$s23PC5PrSkc{1eQh~%pE`7Pg0P3UB;#Qk$ImYSAiT=D0*=0jHN6gGu)8SS&b zQqvJH~0%shN`OKn>I<=W@;;s^~5pxYTpk)8Ac@O1{C z+XPRPz!dJSNbWSt95fLyAqVB4!xWzt2h#DEMAL5eIJcA+nA{#KhrcHTm0OpJ19hex zh3~`+(k^G%Hp52^^5q&K*>Jh5+7fX2M(e1a{qDgr4bWOB$HcO1*|I{!y271IH-%-d zOm?5BB}#_0RU+rq{D5jFTvz!?S+3aYR8{BvZn`+9H8Zq`=nF@4=HEb3C(WC zfyd*H@|3KW1}_7 zZxF9jl6896Bz5qtuq5kk5?@XoY7{klSF)$ue< zzEu?^c)IA`I`)ZCZ)HC>60C_7F;q#X3l*DW|D4(u`ecO8pcGkL3@eC`%!==+H!&=( z?DFbC;ty}_*9um!2(LI0u|=6cl@V+O{i)oux9JrmS8CN3lit{5n0_k+?i)$&X+!JyY9NQ#vX79SYMg^*Mj9%V>VCsRc6T2MN z>0+Heuq^pg-O;ao#5ZJB9!PMJ@`F$l>W6U~mWaDA^B2!E9n*STP8ExFe2(!8!b6N# z3o>VXW{85>XkR2(3{!neWTa(T2l^U~W${1#rp3FdVmTp{cHKJJWp8FpLFn|NqcL)* z-C<<1c4a-5A-#x$nLc4JUAOXETBC4ssQarF)2d8BR+@y@%j@^<3mrXoG*e=r*g@Z6 zAJh6ZhjHFl>Z{;beB!I@0VSxkp9Pa2ew5#lfQq7Kt#wloH@3_MvjF1zCS$!6zvYHc zaf@k1w<5PUFL5uwhf z!V-R|kD4g+xP%k%tU|)O*ug~|`}n6`M8o{z49@{u?6z-VU8`HeG@4_%b~_OjZCPMy z3$Exohxl>;GbJEPt=wXsjr4~cKtblWjfZtgi4mt4dP?*LRhDL$sxgI)6v-t1u~~&i z@P~}KCF)adS+6(tAl`{coy*+t(`nJ}c#h64twc^g<#Er%dWSa#nm)s?BPekZBztzprP+O^U58Zvp&``rtsHJ z`e+`}CO4Ow>v#7BUKPx>IR2Z#`U91r4?=&z}LtZq-@lkd0Lu^j3|l z)j-S8cAVDC7cqvh^}UeQBfX%O>$!HxDz~U@d)80iX1(ZQ_-Y1=TC-Q4Nb}5#{mF&U z(1qeSH1*D^m6*7rbpKQfJ9W3Z#rD*&7*uFzsfm4{Y)sUB?Rp0Y?w6<|HQ+?cW!kYP zL$|XAk6Mr2%+I`axKd7UdY+^j==vWR3Khyc3m?Yur0GV`Nh*L~w9b(2v~YPWc)3dO zR|`6_ojBNK`qOs4!Thgg#1-!(a(;h1c;M>*uQOr_))GLpd|?XD$dITO4FXrWqJl8t z{FtC~G~g^(+E)?O0vmL6`%{7QK5?3>`?+6nsM+az(h<<^_TuaFoQMVStXz7BH-xd9 zJLp>xZuXA4(U$RB3f}045gZs(YqnE=?)%+G3RU;5LdBS0EsDWmgC)Fli&qEH5V=!r z%^ir9?J3uj=3lXEYnzXpcbaACR&*8ngj~|8G)l=(CIN7>PCe)fjjh2LNOaY7bg}n) zztJ{g;Li5xrU0c2*O=$FBwf@+VbEUe)tO_O)W!3wPo|KqB6Jyjov+pUov8s;?S)YO zxZ~6XO*SGgW@VHG_Vucuu}X; zhU?j*#&G#(;g9#el$W`|3eJtE#x{POQMrw}YnAD%M0B|K5&mFBUpne76-Z3c8xQTKKBWU|FrB=XvLoc0B5&?RbQ91HhBkAA(^^H3O0 zvX4&#jm)p++HQRqO%}N77s{m{vrx#oQ*96@t(hBQ<)}{*xc$J)h}cR*E($-I?RC&n z+@iRGSn%*R6k+~G?YlYTL&+qJ(?5pFU^FM1AZJoBNo?4qWa(G0j3W>Wm6j#_RZ>ahy9Xq9`2PG%l9;Ji;_? z{nbJZ^F8do;gdKQnzYdB++QQdN&?1(^h)xAcTyIU9ngy4AWr|vD(qoYMvRgG8?lRU;?My-V?0?>GHZiV2`&=)Pv(PIJOK z8Z$kVebp^|d4LOLGy4;MF#`XI<5Rjocx#hilZbBRs8-O3$b^~xG0CL(?v-B};tEE8 znIhd(z<9a4GFa-_{P>S~WB&8M_Qa17t3T}h0-~~SWQ>8XcW=MaJ^h=De>zW0&YKariIV5w93qxEt5E5UHiL7-0{&& zLU`75?G$?5OVRUWYK%JFT%%+&aYo3k@Z|2|zS`!L^Ie&ooj^ZtAj9dVS!)65ob>s~ zVfoyvqkP!isL>O#jUu^S?*wOvf1-Ism~|Wf_HM0iI$3=Ioj&dpJEqr`wJGZfN>Cv` zL6+p%L%&XHIcmGi3(#_fvEjOAhwubyf9@|2N>r&u8O; zKQbNNA9v(j`6`T3^&2rvPq%#5+x2wy-;AWKC1M8~nDZuwUOLc-&X}5nL=#_Sl*?+9d&8v^c zr+}SyK{Mh2ylgHTgkjDyv0tKlsBpay*=@uGTP4hsZFs$AiL9>qup?JtxJjqUOu*K! zKG|!8d*n9;KD|n5KkR-1oJd8d^FrNo;_x%qc=q*glFQvwv-%ROLWc@_ZCG1bdPf+a z2lOg&q96w*DK85b>oOCZ0Q$1#F)m&A{)qoOl%CJ32NetuRX(SqdayS;Fn4j0$bslWHs?MG_xmN?zp#x}Rn9I5XQm_n%W6(-#}-a;?9g$LRI zbYYbMk>Y?WADE5fr5kJc%Cpq70(@?jhPT*oH<*_+SdxLG(weg8i0LmFO7KxL56W0nnLKt}x|HtG=iD26B!{W8}(n!HhgnK(sdROG@7j(hgwjychLi3fFz z<^3uSyWCHuTK)H}Yn+Xu#iMOqge0(sp^iEa&~N>+C?r-S#(ld3je-qC;@{4V1tsr$ zKuk8*&&wdGUHWE5hfkl7xvdC$y5@F`zMSMV9~sgdG=_l;Pk^kV>{w@Qt&cV_I7$I< zT}wPj<%oz4AaBp*VK=O|mmj&`6fFwc@0WF}PQOQ=Zn0obB1W$%Q(8fFw9PKMYk65q zqc=5wM>Zc6$Q32v-6eAs!Xtc9m~VmaZ<<*%aOy8<~XFDD`+t@@mrsdN1i(5$c0L}MU!74 zZES7cpmz~GdM8Z2bHqg%e;ZcUB(#~(HP`ARayMsK#3qsk#Nm=#mfZdAT%1~K@-Q0J z=T+^V5O~{V`>8Jb`8Nl%jw*rm9%aMTyneLSw>B1XGRq{HX;qB4by>!dY@>jKS|O99 zX+z-aJ-L0BFO;a7Ykh|!G~^lJpE&&I56V0LwzvQJ^2e=lHz)US-(UU`cQv*YHhf69 zZBjS=GuhHo#|kgpGT#UjL95&1J03n5*DeI=C@2gAzl>QAsT)S~0b04-^`wTCH(Vf@ z=7RM$4o#FBD$(Y9l$*#67JF-bi)d5;MdP;cA}0uWVPyZU3Y9=FK=lPhNIN5D-(GE5 zg%Zm}_q`f*KPJ-lM`H*}8ezI%TED%lPUKAJe}KXsTO z4P$su9&ln_@V`mze6Z?Hi^9PG;PeEuu!BCEeE3RAyC>BjQny z+StMa-S|RLq$YBDpuJ3zV$6JnAI$v zh%E1;$L~%?Cb^cIXm3Q_scP&>Y}<@SP4h^6_Km}2FSPf zvmwTPv6(hzYoyYm@bMcz%Y1U4qBJa0DHr=0tBkOB0<>+m} z{S!PwGXh7bp7-8?ud5r7l-3DX~BGvMTY?c57WiGi5UX zCs!8&!ABh_Pg+ji=GaPCf44n8Jv$H#xyUt|Kf%IFg6B)Q(vu_`fs}Fg9@)O9!VsV?@+QXTBbS*`l4WT$e6i=O zGee;K8mc@Tq%k$r{(LO2+}3|3jLfhr`*CJ+mF|OrE_<(a zd5+{!^e5(Mr>M1F`1KMTGd&@M{qR!yn7@Mf&b)O|JZIS2_0AH$xr?}qiDu6dC8A>K zq4u044_D8~hy+J#`hUHTkHxp@C69b^3ZZDwl4QO3)$wReh+2!R2C(Hj2UOWx5V`+* z9wK5?VU>SYhejV0_OJYEFm3(!tDrx|y{faYTxtcd5eqA3G@%^5r4JIn(kBwUuRPLQ(Flc1%* z9lx}|YRvp4UPHiCh5MgH$20$Ox%B$XYmTO_-MK4mFqtNoT0T`@eT=usFV1@TL3({KWz0pnU)TG4-BdO=aKv z_slqUih!bY1*I419aO5)1f(~m_eh68U{L80q)Q9ZrS}>VRC@0<6s3ihU`Pm%kmR4| z`Z?cu-krSL=j7UJuY2vaKKFjtsa2}c8sK61rt`5!U4A%#jD`|vSK8v%fPPx*=V&;4 z80GDuFMQWw<#%rK+Ux(f`re<~n?2$kVquh=^^$SpI?wfc(5I z!Ub;*EnZwQMOq>Y2=_3#n+tS+Se28}@EHsf+cJrJDu&CEK+esEV^3mmvg=D6vO#}N z%&E}Zg*$ay5QnHu^ve%Sy^2s{iCxf0h30JF+I{61Cp1TgIb20As9@mx)AVwYAXH{< z?^QbSKzhJlIBr`6^z)`Vz3K|!M|kqC$NJ(_8@xpkp8c;)>1)P#TQhq=$JR2MoC+Tu zFZ|x5-sqRt46$+2U^?NwuHZbH?3f&2if9=zNA%9TtAvT}UZi;%7^lFKME2H5NZIQ+FQ5L8<;Zdl!rVI#cho|TMN%4Jqx|ORP z93xx5zKo>E!aIuVBD}PYx+D0E_dmXEQJcGv?AH$rJDO&jyaGG~4yc*mg>Wh9A?^O8d zjzKTT?|j3`51@9Z%7U3;B)%W4S+_&<4NUtRnuA1KPBcL)O^>|w(yUT>{(>)=Ll62L zB(_}`v-(esfP&mQH=*IOEI>zz?YUI;$1%jF#jBYU^Q$a`%kpoqtyBFW`rGz;v%GB} zhQ_kFotg{?=b8*c9kw!tU_AO>AlwESv$B^_Eu&k3 zZC91ls^Y`%7u6wSKP`Gt5qLCPb5y9CYs*X1tfenxXF_{VQ;5|@1wuT*052|Bz!m67 z$zr>damenK#uw3!)XDWvG$c;*$>1s`lt1594OGYpd>wP>--Q`dE08^GkASXt?+4Tc z)dhH+z}Pa2zt@eoG{II?Qpkw5KwN&Ea*1p=RMC4YlP!?|RPe%P_Q=XiUFTS3AhpCGNCKWZKLFq=9%xs+eXCAWwOIB;nr#S z2cH|_UC8oUialeA%6qRiyk?NgT_?M)KdrLo|C3?PTlH?lm4rBzlclS;hJ`vXTYHMmCx`%YL zt2!c+w#9esnN3T?647Nea#OXn24cdsa;Z<%aSnVG<*SdB;}`o!<}X4nD%9)32=TV0 zl{?C()A(RVGjt9bp7K1u_1Utr2-lk*dZYXE$0!{^)pFbO?v7X80rJhox$cU{1FjGs zzl$SD)wa?jQX5GVEgOhi1z69t{8Xx)(%XtI8Rrt~O5dHM(unpw*nm47z1@2X_!|fJ z@~qJhy+l)07VLA{nk{lWA|e>Ws$V6g$GAYAQ@=-JsX>IZ+WN%~n0z4?h?{8(xL#c8 zcT+F4=i0AzMEQ$KWd-XKBXh_!BSwi+30MQKbrY6fu)JC2Tqflz9iLOx5wFc#;T;M( zDT#d8RQSooJLAaomDZ*L=i(+H0iQI-_VLqN$gB}4CgDrG+&lceMP`)lO}0Ev1B>VK zuOa%r%)mxD`o-fxivaE53++*)1%z+UUmG~w5MQQO2RWx6PZQYBOQUhRe8w+ba@vKP z83M>~8@>EKl>HjGDOX^vUTj@9gU-V;^iZ=Gsr)0Z$A~CMl(5QMxqavT?9StYnCIzk zObH4qw#OFZFSK>dW9kAzJd8DU8uuYd7Mkztz#6l6iM%jD-i|Wz%LKw^p&gu+R_|R{ z3zIZ&(LcvKZ*0yD7bq2OY$stC!IDK{%{+Y~JNw;r$?>jg?3?^r>vci^-_8cF1M)QA zdVA4AHx)Aj5}$JJX?9uuTfg`2a4onnfEkq<%pLxO&S1Ri64{ z=Zy_~{^v6EH}<&7if~w`^ciWpGPxtjA&ajxFUhp(@Q?+8MLt$Tem z2~-rtutB#q9p}%1&ELaR$ho`ig``6*M$&X0VAmxA6Avejaezod3%H)PdB2k5pJU4t z2kaE$pUh@2cch9jB?NGcU*}5&%FIsZCpf*fcIVz6i zy!KOWyC*{RV(kr6kX8h?#sheY(uJ}lYs-1st8|=hM`baA2u)Umv#Q~O=Ps+#ff2H& zr~+AAzX&^6L4X=tS>F}0a^gjhnG6#xbCNg2XFUr)@WS-`^rjduA%7iS1c>m^iZ~ls zz!h^n;1vD8cla^2QwcH2XoBBqO1-{ngqbwzq=<`+n8f+MDZVr6I~P_zH@>fz+iB%) z(|VC)Ww33@i!hy;KZzq z0A;&d&&dixbjrC`NxVPvwI3AUT9}KF*Q@2!!7U@}cK^R{PtR!(gifqDyjQ2c$N}_| z@QMGj#!{Tyb?CXZeY{rqa6HeL!v@)1LCHHTb2yiALDozn#xyEHA>`6AOgFu1dyy>F z)q$F&NyE-pb?H^FRi>Bbz))3JW6WFGfTSc^&>>SU$yq}0osO+{a*HtE`v$kD2`5tq zN#55H+K)@Rf6dK~LPpSD;V%1?a^p@3KSl~J9E+0Sz8VpP@&#O$-4L;BqL}0CenE;Uc}gecNo6 z&ixPW{Rh_-j6T}z`Q*&iSzqXnh}R~$CrE3%b#*BT4(JpUgZ`>K5!~TA@3#|q5ufX#0LcVB~ z;Y%Mnz8)q2^Tc7n*6t!;NB^pH!h5Z#{No&JJ9}P1eCxc4=B4OrwC|5EBhuL3zJ&NC z`8x)Ac{73sIDGYSRGDg8?L^W(z*1Lj`SJQqH(xfcsdYafkN+%i$BjM~qoK**kbiji z*LR*!!k<}*?)b8MK_&g0U>M=9N}xso1!^!k!?l;Fd|ba*SSpmT`mMd0qx*^(lSITs zjh$MR^(yUBHAWx_AV+(y4JsJ#!UmRcfdEv=)ejE;wF6!|7obEt=g0IoZ1O=K5(X34 z2)*U9xT)kvKti@u#rdg{AoPciANDoN{xyMA@ehT*9w|uv^;@b+h+KdZVN-Q&Di^Sy zY!uiMcQXmV-LI~t+>~Uv8K9oARC@eUtqPNUl47N7C$tm4`sw`+4TIZ(fKcfvRBAPg zxG3W$!;z^io2)mHGx(8HsK)+sme1Rs4U<&I1yO2C{%{HTvRUrh7qAKH#?r6(@`^wn zr)e6GdA|%pa4cDKQ)elwtr7v@ZLm-Z{l+q}Bk~_8>1r}H?3{?HXciF8uQtOJ#^%R! zTemUItKAdW&SN>Nn;X&dgZe*FoWe~$xiPga7P8P3h5C+VQn7i@KKwIcv!Z;4+${py zI1z!7HmL`RV|O-@M9m6L>2f<4aA?Jc$3Mi2kPrjh#YmiOFy>d_(F3rT0*4PM&0re~ z-gd$qyN;bJj0x*e|T`o8u+#6f&L843=t|P?145{LYk?I`FA8V)W zp8$gVWc}i#@MTiQ;oc;E*{z$|h@?F%uQ(>O*Bat0nqo7F1fD%(n7GHv z{e}KSy<-s>#W~t|kB;#7t;?}v0mt~^o7cB_PrOV3za+vl#q&pGC+PzYPpFyQ@dz7% zwBB9T9pVRn^6wQ%{cWm-KNjmRfA?q19&tmP-(H<}$eWq(hq$=tw5~XS9)}uq`#L!3 zuY@@ae2R(kNaZ&!PkR=vw0InohUxu)?NhimOn<fY^H7Iu-KVH*P4$er%>wCJH$|8j zV2X3}IbA2;yH0d}dG4vj;dZiHfjrE3J+|ZlVpF0PUwv`t-Xonj@C%=A0kGQHGl=$7 z#vDe&&vKJzZgQ=IN4R9G{~8JJ_%kQ^s0t#+)NPe@1Lh#JbfD4c%$hWj)4%rp&OHTF zbL>6!oEg_Vg#gvf@o2i;Aw`BU#=Y{p5ObBvXwkD1RKYb{?k zIfs{lYxF`hHHCxyb*KCaCWXt!G|rjwrM-ZN5&hL)qh@5O9F!aM6$vAp9&(rCkuoG* zd5~SkQ8|K(F5uKTuvbL%+0iN$xm<&T8=xI?(rLew6WLaXR?eOVBr2n6`^G1QGZ}kqe5|C5P zL56`@z#V4LOPMv*hj%0Sl6F#4{F{ZZiX7LQ;|FJM0e|>Xluec!miQOV##hYuzCTrt!Jin8-Z09|e!0%aiWVB>lCfL9> zBpb!mBOL=Y_#G!C-gH1CtN%rh4daRZB^O?0@ae4sPFmGhK1mJV;PQDD3ivj@1&pj; z_+v7D>kA+k+J9bh-X^AgX*k*|&*7)(^UToX`5B)szV%gA{G~t8M@{1sAa6B#&WD6e z%3JE~sHEwS-<$S_#DB{8vFB-1sR3o$0k?mblbvE4@7rCc(>rg{VK(dqn&!VXuoy{%(hhEUu0`M~$j%Z0-LS?*1Y6&7I-gejvx29!vQx z^n|R_6c^rFzx^Vo^qY0xKjLgyB~B4=j4ejt`{Fxms~)_6UW=&MJNzE&t1c5h&-ISZ zQPJ63A=kAJjBV-#UZg*3?07-B^C)6ttxKXfrL$flC^>Hb?lZ#oKU|aqxo3W)5*FnL z#N5($krcE8ZrFu$QXD7WCa@UVSKnoOi06QR+`0(__)g<41Z5Y7X|2#}t=pUEKLMmS zH08RTOFvOU`BB&Vg@Y^{TyV7WV75FM78@|r?RS$H*s`T%@NKF66}-Jsw-@eY4MXJ~ z^>%hj7OS|hhL3dMI{d|Fejvt?M7v-gweAx{9QowPZYDXxn$NmUiQycIY0bEwUP{o? zn~qLwPOa-M`KQ5tR#J1(La6rmF7E5|H;cA`XMViZ>ggQG;NGxt&c0IZmzJUZ{;5zS z*0&48_Yw>P9zQdXo-h$?p}O~l>)HIAMPhgTiv`mEGEwb6iF$LOr_v!_G_0TC>oxan zZ)(tUaOP^?Ymj$_jRtgYzwO)p~sJruP;B!*bl&;Gq)5|q$CG}GoWwl(BsTqNHw$le+L zx{C`t%e8JUROWSz11V~75f_=L;MMi8JX^wSrY_CpAQMQ{Xh!~vu=_PJGEjZskvg)P z=%7VMKRmh!Ze(kJbp)ata_7U?*vu={uhgBm9fngcsmw|S81;d%k%HW&g={cDw;m4K zO{C5)@r0;6wzE>SDN~@}T`tw#jkVch$5xpHUC)2l9th&{hxMSi)4p4sXM?gOQT+zCT(wgFmY?1$XT+YUx8(whepeIPpHuG z-a#fjW)eN|Y3-C*Bmxd;l*Un)$EAn18%i<;-+>#pQW|Aa1VcPvPPXgTidl8l9o?uBTk*qsUHl%Xc%t*)n6Uq1`|9M~2;y}hW-d3$s;_o_vg}PjQhZYT zN;f2^vB7$gU-rp}T=kr@YlojTdQ1Ft%P2Z__0LhME^#Z{Bf^l^ zx2xod9P#J(r{8|0)xls9j!#W!{JtzW!XyrG^C!beZMs2KfJ+4(MOkh+NlLz``bc7K z1VBfu>z_xzhnT-^`^{0lD4z`tTK=^u?blPg2(&ik7wq}2_q^+tddJ}}{-WpaCA!ge zIT?nEs1xM(>4#NfYv0+MUG@3qhQQW7lB^qG7V$Kx)aPA|=2nOQ2=(RMc0EoE0b0sn zy;}DnH=Fi~hG#SkZ)a)@7;@tqMld1H2gA|=3u_dUq$mI(4P{bPKuj9g?Z}c1It`GO z>gb-xy24pT)by0ai9k04&$8wt1)B16B*i-Ab+v-I9lokYY*w7DT(Zc zil&E-*{l}d_KH)NUy)O3YW)KVR`RRj;-&|X1&HBvmYfm%FoCp{fc+U8_XKrVEInzqVS-~$0 z6&V31@4kxY#J@nW+G%H9+371y8GwfR$;<&*`NGu2^IKl;Vgy97odz9 ztVmp&*)o3*zp+~ZVo0n$?@7zVWlPE(PWu;4 zf1P>wLZYT0EMkum9ZDTjOE9lt*!HuaoYg#5PYV`N3qjDb4s zQoq{g?Pr6D zHjMqczT&du;l*lB<#jo;DlvD4R%20^(OI9y(OIPn4wp8ijSi#^8o{x$bQJC^6CDH2 zM#EcHS9_h-f2i2$T$)hYnz)y;J$4P*nI7e$LZCvq=hxRb4`hC8CTs3b9U{Qfz_w<$~8H)vMnl=PX~IY>O2Is*2k;|S;*(#z|2Q((HY(ZYuPJm{g1 zd{zuv9wA!bFnYIEi8RW_M(DF!{&zIYn%nI6SNbFQ9yQ^Z={~*(!!3`ce+k8Tc1+E! zzSL2Fj})Ut>6c=Tpt<@hhSV)(*&zQsWD79Pi5XDH8oj41|l<|81ONr|mKlIlJd8_)9n?%qG;@j@H;3Iw8QX{QXdqX}Td?n1x`v>QU zg^wiksiJ8nb}%S398H~b>!Duu5*CgSZ(9CM!p7g_w#~cwz5j=~n&rqp{0e1Um6!!^ zrz_Cigh%xvU#!R<`$Fat7}$n%y)?GNIjJs+ThB`cdE=;U+14yE$ybYm_pL3ZE%len z)6k7vDxcjRq#lb>+AKdEo13idU45Lc#{|%-8S*+kYj~9+alWi45YgW0oz{`YmgW9* zHNJI1tZp8NvHIyzTe`E$W$cWXa%P2V?=JUR_Rl0&_-6%Vv3`_t3N?;b|5PKprbKeG z2u`Jr#{6`r(77oUYgbf)<`+%)8B1iUr6hNj?0_U{9bf@|W=^?gT}04c?pcR^XAd&a zg2x-@5DP}SM~XwV9LgYeS4Goy0wZ2z&%1E>cDE;a-*dn5CWr@kaUdu!K+lJ%PkAK| zf{3N(eyZ>|*ohup>}vVUzh6;&mIppm;W>ChAs!nJANy3r5Nn0%T*XRc6QDG_m)bgX zNK)*pPh>Os#!W*=c?B^Px&dBFjU8edadZoGB(i$NyUlxLU;hS6KUY+Ua{@Eara&rK1>{mcn~3_pd>VJ9kN-Q1X8K@_;E8P zT{IY*`N%#;{H_tkivGbRV&Rg4`G-DUkGp1c>?cx!Z;VeTlyt)Lhcyx&Ty`CKw7tYF zl6+(0gZEf-FvQgDc4^k?>rbD1s>-K-9uk!jtR2(i>JKtf{Au<=&Lz!oLldg^R0(*c z$)QWb3K3asfN4Y;GPGl{QkfW)zxKn!^}dWRDX`dg_`bd&a}1b*%25F{XHXgRjs4_Z zkMAdQ=h(|nb1EkpUAj-@02b}1d-NK_`kIKfBXcXP{`b*4#ZTSWi-5!Z_psl zr=y%~9(Ws+p(8f-K8Wd&WsGJrZ;jP?<4$X!2;19biGweqRbD;vna3?rs{%d2NoaA) z3@iE^S~;P$PLVn2(z3%QNzK<7_&&T0>Sd+4d0&T>|9kk+|@mS@pQzTCtt|@%!J8N{mXu+*1>jQ-kTviM+tHGSB&F zrq|uj$U!(u$eJV71;M*m?$mpq0$O`5v@R#QPA9Vd81A&2G&^0ORExwbc80d1%iK%T z5azm32Kh^bdQmo`jygKv6g-~jrh7H z0fiE^5^Xw(Pu6Fl=34)d{n4sFoc67&`Loac#1A)AeYZ*6gvBX zi#A5j-DxBf)(FEB4$)M&Ww#x%x+@a|M)7deIF1xO)Oi@QMI&DaLFYEKab{os`>)tP z7%far@uzC|6~TwM7=n2j4Yiy1P)Fqlh^G_DitjoYzchHn*X*B2fnxmS;XdXOvPj_) z^~ybce#n*PCD7$0^ABCjwb$2~2v4(A-ZjtNN`SM+`z|n~$NXTBT&?g^`G^xYQ{C>Q zae_Jaf}W|Zr6~nXFq|z%A=iAiu15TN2dB^}3*o$Bzso4WzDe-Uwup`1x@E1AtPbSdKEuuV6Dz($oSlhJn3MSd~}lY8S_dQvXdeNVIGCb$92G0%W* z%~}y**>|qG`s-zw5o@FTES!&*5tBRjh2=wC@}JK~nH|5?i!*q&h%#z0hA?y;)|NJk z-eD=x0ks`%HE zMTNrKQeV`--;TX;MV53+av=aeqkyKmiiM5C^RaT>hzl(y(D6{SyR7){KhipZ_~vRm zubr|%LTden`_q~i6S2_-7w&u2`i{*}B8>wphX|X|#Bpv|=?D zSh^3VdW}+wDs0-0Z~`*T{&}k_3?nL9f`F^bv5S(pWxj|Vr}}VMCCRfMbWy?c-a^HXrh6KcH{;AHAzxVr% z-)1$-)XMmFZ8>yLDboUEG0g6VKD`!LG_eOA-Y2QnquJe_g|<|wrRF8zR+5_~>#EO3 z@*lUB>(AkxW6ySpii9DqH9n`bppK8u&%CK!P8NnI6Z*X`fdL1H=D8o<>j9+B?L_F7 z7Ty7q?jrnIHU~^T45cKG=O5ZmfH3|PMlhu zfbTImk=h47_D4?p?UcGaSD)YeLUby6@2PYeU%``9UVtB+P&zeF$X83w&~#ul3Is>` z`QlIvSaT20x#`oD0pR#KN5C33R-xGwyHfm6x%Cb5_fXxBC7;u?5^N}iaAy^EZM*#8 z$mZP`tzK|xuxv?KlE+j->o-AyrajT3fnX}wnxkvsRT5UGz^n7u3(Q&bBJXAQJBGgd znOgw!l*4OH@jp`2Bi?=tClP3;>@JqnBgiiFmH%UBKp5Zt>*E69P$eV9_KLaIL=;ad z=@gAbeIF=+jr^tsF_{Ir9^*>e&@er;uny!+?x5L*Bd0F6jcob1rZD=_CX1?0cc`EU zpKEHH-H`ld-jVI=P>sf)h9i}fvL zgf<6dG=b1r+tr$(YelFRA<}C~3f>fKgd7B*D8KQ$#`d-5(*Hh=1?HIaL^Z^J4b4EV z%IkZtjt395%mxNAw@uK<7- zcnPqeWz`i68xPX^=cf8MQV$pQ->ZWxyq+gmRbHw{8y>enS=v7<6f9vfOB_)1P&zpx1EdRY+U|lH(ctW^X>Yh&UymhZanoWbwH{(rd?c`f`&d!AV-y~=a z{?jz}um*|cI04I3d~}Ce@4kCvqS`Z2%$L+O5}vVc_@*|xfeE;*^GNYXU^I1@{g_Gi z`|AUnz}JfntV{M?*yRS8ca4H*fc}m?|NPyVene5ep4URGvP@L1WEcWbqSVyp!XTlj zV=SFdtN1K{qrERPP#BRO^&@Hgs|{4n&N+W;Q@B_!nqn&fw*$*n$plq2m*%N%qky{M zrGOHE=(O_)JmTcUxHeq*(7FU7UdOQnwupQ4Ty*=Ki_CR2g(e?<91CQ0rc)DDWTMYf z^Iqmon?b!_&NL6n-+MLRIe7kVMSV%(a$TQ6!n>KHyo34u@3<6AE=R6B#M@ZMJ~~}S zeDzZy7kPt?#le~Nb1F%o!&N&0?L#`D9PG88QJtwD1cNW|f@Jn2x{4jR+rWgJstp;x}m z6T44s9kL}HY4&ty6r5e%lpLa$u5d(UXQkCtAgz}mz*b?*r-nI_^DKK&fOlz&hzwem zQ$7_U&lR}l-51NUa!o@P_ex?vvKD{}{5s>GW$Rvs_+23-tM=(_kMRYi~x* z4_*@PnV!?g`FPAawD{;^4J2yr^I_Ze*|ufxMsfz&asqGM;N=qzJF3o+wu1T3T5WvI z%};C?WX>*azr1AGZ0>^T_~vG84^7>NK6%2|%6cYCI^}<~GqGX}Toi{Jk*?P=^2?&H{96GDD&LmICy$#eJ(GgL2A!8C2i9DztdxC^$msHV5 z9`l@IY*VhkJ}L##axWY-l`dTJu04I%Df+EGbl?wbrvyYVFZ+lsqTiooRlK8yRlmd)*q-)ptpCz0uua;-(!<29ZWumouh?U?5z@l zw5;MTWfZhJ!oN4vJT~*s{~q7-v_v=l`Gz6Hc0^~0fop)WJ&{c&b?0-mm1y6ngsaml zbJWVT+WNhuKVQ((UHT#ZE46Pv=+u0|^xR|2ppAoVmMHQj`$(kif$!nZ4webfd~sO- zsUiy^d{yg1wd>V@(Rreio&2_B1}Dr`&nJiB;8x);hxQEnTqodC5pB*nZJY7}>vS8( zGvGLB&3;9AkMqH%>3+y8Oe{_Q^(y>o1wQ;D`%9lz|A{>)^3L~LBf&4TOO5a$6uK{b3?1A(_z_okh`#!GvK9516< zi0^{zm$3eT49Xe4)of|)m}^z}4ajQp(LJZf+ZBZIb@%R!k^St>&& zg;fuEExs7B1F9091`EqGj9MHBD2zF&(e|(N>s6;^94sXn4D&qF`$i>;K_adg3kIPC z#Q1&G#4qou%GC=dj}RJ*erk&q1aN-0htcJ;mtJqo6PPwW_YP!ILAR6Wlfj5KJMq;N zKsATBD5`^LT^al5fy@t@Ul=1B$SAi4Pk$n%iVo!az>q4Bi|Ceo zlEwMro3RqjMfA=Rq2QJg8~L`;nLHb4j>|gM!uxdAUiPhb$LpsGD$UL zyinXvWMa6gIbualpy2*8@tFaIOWL_QzaZpb(jh_PAP=Etumt?L9lgN&JK=#yor+xo z9Tjwae!LM^aY^Qq=8Yg;gndTSt^n_x{>&B8i$?>epBI@}w+Hr0ibG#or4|L0*W1s> z6B0OjrMso+C)xM|@Z;n2JuR-QXv-MG?;kQhq1_P% zTww<|*Uf-?;{~NNqRVmjC{hAQk7akI`-@)g^HtzVdA^q=iH_QSV z-K~T?eAoj!y?!aYZIR=%^60yBP=zi@2O89wfP+kZ2aBBv{HM|*tHm|-MVq(AE5?Px ztD9fBv~~rCgx=dmmog=LL`8BFD-F-4z{&jV$OVWAeOA?tx6ob zAN6klS6>_qQT#!Bav0JR+VqmO$Mnbnn&D@@xy_jWRT+r#+j?fkvDBLQB_#QT$_(Uj z70ntTxXtAk5Vhc!k{O>ZWKY7)*c*LXY>vRCH0~;!Wo>g;n({m=I5xFP9FX_BLXp6@BtlUi(e~IO2 zK}?H2Qf(?P20)u7K&M=5GokBB1vw`EQtnIqa`o@7ZN5vxzD=M>c`_z0Gq7~?x;wMP z(VL++3X0E=VbR~cHDrClb+Y6o#0czXo&<~Ad~ugbWfMM+!3Mdgy@#gG(+^l87Si*# zw8a{CB;?;sXZXZu%OOnKYjIkA| zQqryxPU`$`(rsGF%rBo7yiU}BERBw*_22TX*ZAaH(Zr9%_93Pq#g^r7-Tj03R2?7= z+91hSLQ}D!&=@fHQX)f@zw*fg3_eO^KR+p&Z8$Y;(Wdn}i!v_nr`OOgT*Sn5D(u+4 zX^tg@v4zGpf9*Yc6}yWQL#=|;mb)LDfqc!FpG;5*N!gtQ>MZYe#omZxKh;{z3SD+Q zU}@llDf?YZdVcMArCbC^=oU&cx+XCwJ#j0oQ}Mv|nM}~7em#22j+Sw=X8gRQ%dgo& zCo2QRk2o-(rqylGx95KaikU6U^}U#gGl_uNd~MqS1=YyQn4q}41aOd(>E??NVSl5a ztQk)3b;J4j?G2Jy9$?8Rs*?sYU!cDx*MvpfC4m;7xg&`WD`h1w&hOZrRL>2t>pvt- zb=01z4dy=c9B3TD#Z7v7Y&DO~_m(utZM`8LMPRd-NGB1w5Yx!t+U4v0AOEsvl%B&+ zibH`XV@*(D(51ntfb=d_Gi;^dQbg9b@we!YZz^i#JvsJXtZ$F6ZA1P2g`mmuB?}Hq z(@Tdyl5cea|0&sx&P>lcVP?UqykxP=8u@}V7_0_l(Jl{a^;@YVcAZx#NHkg0)osgO zyTelI5mj5ZpBZ-16i4o+9JhAV{HyW&-XsK}e|w*N-MQGc>$>%zVniDqmRKxO_hBRc zecS|H+s{w7A}(PmV$2lx^gv}^UlB3utykcDaEs0NN6?ZcUjgEI!H!(Opvccg9;o(~ z@3^GN$fSZ!tGQSXHsgc-e12^cdrgvSgtCP5tC%K3c+O#+9TRCNBKUI~;9tz_ng#j* zKqVe1wmXgy>u>mzMrBmBijap&#yYNTNl^u1w*2nK)sNiT9?|?-@{3sm+0e*MgWHiS zEy6ECS#WuUpYjh%D_1{LK5YFVlTS;ChUK)lSO~5@Y3pmjrPgz=Dts%S#I)95yRmfs zK$)jTmudFp(C76VnEh)uE)&2B8_&YFH8nGznV=qjY4qP6N~=*qF@3i_b96S*vp1i4(AKjMHGFLqRQ zj}S0}xBR%b(GB>~-BT4B+)sM+_&)Ohr&vbYD1rycqBR9}>otA4cRxMC;T=!dQrwUW z_PeL=7c^WLzArn^b4bgr;u1OKR2v~1mmgGqG_+%o_4Q*|e7s;)ysjOqzi6O~%DY&q z)5#Z>y}fE1__5_I=ezdtsMfnB4vE`}mNOyFw;-XJ0ilQP@9C5b3ask=99?_E zn#=V8`SbRBW8J0YRpCk~rCBBpz-qwug2JU-1ur*cq2`C>ng-!YLa#U#l{OQdx(}3W z<;B=uddG-=KsW{;g_?FjFxexLb=zqJDgoiHZ*G@)tN@tgtE)q&o0ls~r+(!P2%T8A zCbCXA7Az;Z-cz6LRR1~~M88}F>KGntSE)oLerihUtUGxZ#Ut18f!gS{nJ z4Clm)tUC|yHRq5&ojzM^fByauFb<)kGlJk4!yJSCI5b;!Q1(jvR+i_-*VCT(8zr=$*3rCX(L7 z$SM2s9K3B@_G&6F&$w&g?CHfPd%BU@jJ2ed?*g=UzkB#NYlXk`KNeV5B_&)XoE;fp z9N8OLe7JUPngM#7DKk83!+Qd)Yn^dvn=Bh>mtDU z%`TE^#})}Z63_ZBdDf`Kx3psmhjI=FRmLC&;qp@vq?xP#8ZrIxzv5FIre+;hoVC9A zNTnutVf!Lm2l^t)&$sY4Um#<&(({Y9$}B+zi!8h4lI*>l&6f{sg&`UIVQ`rUJ|7#R zH4nx|vvshp@NLc6>SRH?#vQI=rwCK0sK2q^tD|-yw>~O5CXdg`i;C4v=oj^IJ!8CQ zGHs#hPVe$lXYpIfAck#3w_3Lc>0jN;$71R#CG44^3y33c7;w@dSN~n>TX{eYANEHu zkbXAN@9AgA7quhjUoOvKxnKU=)Sabs;-4;B6EfdSU`r`q46U%oLqup{F zjPT#ibdQVSAJ2x{`V}XH&QFjY$Jj&TB#zCHXy*YpcY~Idn!x+CIo(1SHGjSF?)Nmw z%Q`D65+?_MsjFn7oi6UcE)no&Es|y~9Iwur>|6DkWpc1ST=}!M=Hl_zj=v2Gp!DhH z!QWaWf8|H=j7hGnoGd*1%5vPFT7P{ai*=~WgL@mbI6EYZL^^OX{R`8H+;Y!y4wU7H zBmZ16`4l~OV#Id$0KwtrO}6#ZIo-Z_d;SYNOvs^P9&bfl$@H8GLz{8+_ZL?N-&};x zG=LJtWB$bF23j{JDh){3RgH`G1q}a~q+!)cftN9`rzy$Q;xi(}E}P8^DoG+*&pIno zTrw^HYT(fVsr_vR=LoPGB3gc#tyyPyvaU2$ZttMLN+zWfw1Ifm<4Y7KzyaP6PKets@CUt8? zmvdOfYi^fcodA86}Ty+Yi7-aa*r#Ou$}kS%s{C2 zj;IJ6EBU*nlVWy=8X7D`U?n5;qQJ2rLRZBAKBDmcg6RaA-u1VxAt{=qNo++&@6kEj zx48IOduJ2^>|M#nT7>S3lzg1p1&Eb0)`#Rz#$LqacD!{eyxxj54p5(e2k!7X? z=V(F-DYK}1mSm5MZ`FZm{>sM+l}oXLSnshTvgZ(ip|tk9WV$R1?c=A<&iy|WG?1Jh z8xEPdFIKLpZ^{O9B+H&?As?kz&OJW}&b^up5>GL@{w4bd3vHvAcsBgKsCG z?h{+P@ekf9wd`ysxns{RspbAPrG*{j&)%;SNNmR+tH9kA^v)Q~WWy<*`q-0oae%~E z?G`S6K-867F*p)ej(#|3z;b$sC67qRY|sABOzm+&QU_? zu3tNKV|`cXLv8jEWOIp5LA++h3NC?{#gEHy+b2hVczvv(;kbtC z`EGb>r>zQ`+-8OpZVq77Eh`j}42MuQP8|Mf@ZE^5qOX1{ zG1lrjYt?4k*z*+rl|M2|T2Dkdrufi*S(NE)tHkRR{=1k~(V=imDPlE$)ad|TRXKZz zyR(i?!bN*4zo+=PIZPYO^uAnV76j#eTS&t8y5De^`Nl?V?<*w~Jhkm923m z0Fx#u=JM7ESi9Uy#AObM<-fPs4zYLEdNiP%E+a(r(z&?|xdlzRVlJ{_T|mNt+VHtbM~xoKoZ@mDO0M4%MVqVmQtdnbWh#=9_##5 zfrd=BD{cGwV*g}EzpYmuT6&C`^X*L&#Hifc__Z9Ln-71k^*!hR+PNu_(~^I@4li9% z5I(0b`5nJv9Ohs?c3Tda8jFF=$DeD8yBG~vwol-o77%&i*h)9WPssQUWaUZtc65XU zDgB^j$(xfcF))s zl(<%%W}{C1=O}x)U;fU!9S-YnQ|n}K?2ek#u}ZS{^^{cRLAoi*rds**)ir3x^x-nP z)C_L9`C57yRGa~-m?`YC%$L4Gk=tgFkrXT7^cV*}9&W2>$55>GN*>4D#t2}(mWcLd z`sVIx&l=-(z^V(VjzLl4WiuXEZpjk=?kY$ux=|ZQt*qaX&S_-a%0DoXfkE=FQkw`^V~P;W0r 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≫$wGrSXI&R+n}5=U(GM;dr*8Q)s{wY- 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

*i7F28~-xh76;xs6o{$i5uy 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 -Client IOS \ No newline at end of file + + +--- + +  ![Swift](https://img.shields.io/badge/Swift-F05138.svg?style=for-the-badge&logo=Swift&logoColor=white) +  ![iOS](https://img.shields.io/badge/iOS-000000.svg?style=for-the-badge&logo=Apple&logoColor=white) + +--- + +[Présentation](#apple---all-in) | [Répartition du dépôt](#répartition-du-gitlab) | [Structures](#structures) | [Technologies](#technologies) | [Outils](#outils) | [Wiki](https://codefirst.iut.uca.fr/git/AllDev/Gestion_de_projet/wiki) + + + +### Apple - ALL IN! + +**Contexte** : Application Swift et SwiftUI pour le projet universitaire de troisième année (B.U.T Informatique de Clermont-Ferrand) intitulé *All In*. +
+ +**Description** : Ce dépôt contient l'ensemble du code pour la partie client iOS de l'application *ALL IN*. +
+ +# Répartition du GitLab + +[**Sources**](Sources) : **Code de l'application** + +[**Documentation**](Documentation) : **Documentation de l'application** + + +# Structures + +- MVVM + + + +# Technologies + + + +Pour réaliser l'interface visuelle, nous avons opté pour **SwiftUI** du fait qu'elle permet de réaliser des interfaces utilisateurs complexes de manière élégante. Le framework est récent, mis à jour régulièrement, et facile à prendre en main pour le développement. + +# Outils + +Pour la partie API, nous avons utilisé plusieurs outils : + +- UserDefaults + +Pour stocker le token localement, nous utilisons l'outil fourni par SwiftUI qui est UserDefaults, afin de réaliser une authentification automatique lorsque le client ouvre l'application, en récupérant son token lors de la précédente connexion. + +

+ +© AllDev - Apple + +
\ No newline at end of file From 87eba68e42dd56caa89fe9df655706ec6c05acaa Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Fri, 12 Jan 2024 16:11:15 +0100 Subject: [PATCH 2/5] Retrieving and displaying bets via the API :white_check_mark: --- .../AllInApp/AllIn/Components/BetCard.swift | 25 ++++++--- .../AllIn/Components/RecapBetCard.swift | 3 +- .../AllIn/Components/ReviewCard.swift | 3 +- .../AllIn/Components/TextCapsule.swift | 52 +++++++++++++++---- .../AllInApp/AllIn/Services/AuthService.swift | 2 +- .../AllIn/ViewModels/BetViewModel.swift | 26 +++++----- Sources/AllInApp/AllIn/Views/BetView.swift | 7 +-- Sources/Api/Sources/Api/BetApiManager.swift | 49 +++++++++++++++++ .../Sources/Api/Factory/FactoryApiBet.swift | 11 ++-- Sources/Model/Sources/Model/Bet.swift | 6 ++- .../Model/Sources/Model/BetDataManager.swift | 2 +- Sources/Model/Sources/Model/Manager.swift | 6 +++ .../Sources/StubLib/BetStubManager.swift | 4 +- .../Sources/ViewModel/ManagerVM.swift | 6 ++- 14 files changed, 153 insertions(+), 49 deletions(-) create mode 100644 Sources/Api/Sources/Api/BetApiManager.swift diff --git a/Sources/AllInApp/AllIn/Components/BetCard.swift b/Sources/AllInApp/AllIn/Components/BetCard.swift index b58bb1e..9a37c5f 100644 --- a/Sources/AllInApp/AllIn/Components/BetCard.swift +++ b/Sources/AllInApp/AllIn/Components/BetCard.swift @@ -6,22 +6,25 @@ // import SwiftUI +import Model struct BetCard: View { + + var bet: Bet + var body: some View { VStack(spacing: 0){ VStack(alignment: .leading,spacing: 2){ HStack{ Spacer() - Text("proposé par Lucas").font(.system(size: 10)).foregroundColor(AllInColors.grey800Color) + Text("proposé par " + bet.author.username.capitalized).font(.system(size: 10)).foregroundColor(AllInColors.grey800Color) } - Text("Etudes").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold) + Text(bet.theme).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) + Text(bet.phrase).font(.system(size: 20)).fontWeight(.bold) HStack{ Text("Commence le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - TextCapsule() - TextCapsule() + TextCapsule(date: bet.endRegisterDate) Spacer() } @@ -34,7 +37,7 @@ struct BetCard: View { HStack{ Spacer() UsersPreview() - Text(" 4 joueurs en attente").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color).fontWeight(.medium) + Text(String(bet.registered.count) + " joueurs en attente").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color).fontWeight(.medium) Spacer() @@ -75,7 +78,15 @@ struct BetCard: View { struct BetCard_Previews: PreviewProvider { static var previews: some View { - BetCard() + BetCard(bet: BinaryBet(theme: "Football - Finale de la Ligue des Champions", + phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", + endRegisterDate: Date().addingTimeInterval(86400), + endBetDate: Date().addingTimeInterval(172800), + totalStakes: 100, + isPublic: true, + invited: [], + author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), + registered: [])) .preferredColorScheme(.dark) } } diff --git a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift index 418804a..df1957e 100644 --- a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift +++ b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift @@ -31,8 +31,7 @@ struct RecapBetCard: View { Text("Fini le ") .font(.system(size: 15)) .foregroundColor(AllInColors.grey800Color) - TextCapsule() - TextCapsule() + TextCapsule(date: Date()) Spacer() } } diff --git a/Sources/AllInApp/AllIn/Components/ReviewCard.swift b/Sources/AllInApp/AllIn/Components/ReviewCard.swift index 8ff8846..7b4754b 100644 --- a/Sources/AllInApp/AllIn/Components/ReviewCard.swift +++ b/Sources/AllInApp/AllIn/Components/ReviewCard.swift @@ -23,8 +23,7 @@ struct ReviewCard: View { Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold) HStack{ Text("Fini le").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - TextCapsule() - TextCapsule() + TextCapsule(date: Date()) Spacer() } diff --git a/Sources/AllInApp/AllIn/Components/TextCapsule.swift b/Sources/AllInApp/AllIn/Components/TextCapsule.swift index ad556f8..11ec010 100644 --- a/Sources/AllInApp/AllIn/Components/TextCapsule.swift +++ b/Sources/AllInApp/AllIn/Components/TextCapsule.swift @@ -8,21 +8,53 @@ import SwiftUI struct TextCapsule: View { + var date: Date + + private var formattedDate: String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "dd MMM" + return dateFormatter.string(from: date) + } + + private var formattedTime: String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "HH:mm" + return dateFormatter.string(from: date) + } + var body: some View { - Text("12 sept.").font(.system(size: 15)) - .foregroundColor(AllInColors.lightPurpleColor) - .fontWeight(.bold) - .padding([.leading,.trailing],10) - .padding([.top,.bottom], 5).background(AllInColors.underComponentBackgroundColor) - .clipShape(Capsule()) - .overlay(RoundedRectangle(cornerRadius: 20) - .stroke(AllInColors.delimiterGrey, lineWidth: 1) - ) + HStack { + Text(formattedDate) + .font(.system(size: 15)) + .foregroundColor(AllInColors.lightPurpleColor) + .fontWeight(.bold) + .padding([.leading, .trailing], 10) + .padding([.top, .bottom], 5) + .background(AllInColors.underComponentBackgroundColor) + .clipShape(Capsule()) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(AllInColors.delimiterGrey, lineWidth: 1) + ) + + Text(formattedTime) + .font(.system(size: 15)) + .foregroundColor(AllInColors.lightPurpleColor) + .fontWeight(.bold) + .padding([.leading, .trailing], 10) + .padding([.top, .bottom], 5) + .background(AllInColors.underComponentBackgroundColor) + .clipShape(Capsule()) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(AllInColors.delimiterGrey, lineWidth: 1) + ) + } } } struct TextCapsule_Previews: PreviewProvider { static var previews: some View { - TextCapsule() + TextCapsule(date: Date()) } } diff --git a/Sources/AllInApp/AllIn/Services/AuthService.swift b/Sources/AllInApp/AllIn/Services/AuthService.swift index 1a7ee71..62a99ec 100644 --- a/Sources/AllInApp/AllIn/Services/AuthService.swift +++ b/Sources/AllInApp/AllIn/Services/AuthService.swift @@ -144,7 +144,7 @@ class AuthService: IAuthService { } private func initManagerVM(token: String) { - DependencyInjection.shared.addSingleton(ManagerVM.self, ManagerVM(withModel: Manager(withBetDataManager: BetStubManager(), withUserDataManager: UserApiManager(withUserToken: token)))) + DependencyInjection.shared.addSingleton(ManagerVM.self, ManagerVM(withModel: Manager(withBetDataManager: BetApiManager(), withUserDataManager: UserApiManager(withUserToken: token)))) } } diff --git a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift index 522af33..6a6dd6c 100644 --- a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift @@ -8,28 +8,30 @@ import Foundation import DependencyInjection import ViewModel +import Model +import Combine class BetViewModel: ObservableObject { @Inject var manager: ManagerVM + @Published private var internalBets: [Bet] = [] + + var bets: [Bet] { + return internalBets + } + init() { getItems() } func getItems() { - - } - - func deleteItem(indexSet: IndexSet) { - - } - - func moveltem(from: IndexSet, to: Int) { - + for bet in manager.bets { + print(bet.theme) + } + manager.$bets.assign(to: \.internalBets, on: self).store(in: &cancellables) + manager.getPublicBets() } - func addItem(title: String) { - - } + private var cancellables: Set = [] } diff --git a/Sources/AllInApp/AllIn/Views/BetView.swift b/Sources/AllInApp/AllIn/Views/BetView.swift index 1ef638f..bc21e48 100644 --- a/Sources/AllInApp/AllIn/Views/BetView.swift +++ b/Sources/AllInApp/AllIn/Views/BetView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import Model struct BetView: View { @@ -16,7 +17,6 @@ struct BetView: View { var body: some View { VStack(alignment: .center, spacing: 0) { - TopBar(showMenu: self.$showMenu) ScrollView(showsIndicators: false) { LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [.sectionHeaders]) { @@ -25,8 +25,9 @@ struct BetView: View { Section { VStack(spacing: 20){ - BetCard() - BetCard() + ForEach(viewModel.bets, id: \.id) { (bet: Bet) in + BetCard(bet: bet) + } Button("Show Sheet") { showingSheet.toggle() } diff --git a/Sources/Api/Sources/Api/BetApiManager.swift b/Sources/Api/Sources/Api/BetApiManager.swift new file mode 100644 index 0000000..10225a3 --- /dev/null +++ b/Sources/Api/Sources/Api/BetApiManager.swift @@ -0,0 +1,49 @@ +// +// BetApiManager.swift +// +// +// Created by Emre on 12/01/2024. +// + +import Foundation +import Model + +public struct BetApiManager: BetDataManager { + + public init() { } + + public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + let url = URL(string: allInApi + "bets/gets")! + + var request = URLRequest(url: url) + request.httpMethod = "GET" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + var bets: [Bet] = [] + + URLSession.shared.dataTask(with: request) { data, response, error in + if let data = data { + print ("ALLIN : get bets") + do { + if let httpResponse = response as? HTTPURLResponse, let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] { + for json in jsonArray { + if let bet = FactoryApiBet().toModel(from: json) { + bets.append(bet) + print(bet.theme) + } + } + print(httpResponse.statusCode) + completion(bets) + } + } catch { + print("Error parsing JSON: \(error)") + } + } + }.resume() + } + + public func getUsers(username: String) -> [User] { + return [] + } + +} diff --git a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift index 223f685..8c29b11 100644 --- a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift +++ b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift @@ -30,9 +30,8 @@ public class FactoryApiBet: FactoryBet { let phrase = json["sentenceBet"] as? String, let endRegisterDateString = json["endRegistration"] as? String, let endBetDateString = json["endBet"] as? String, - let isPublicString = json["isPrivate"] as? String, - let createdBy = json["createdBy"] as? User, // Assuming User object can be parsed from JSON - let type = json["type"] as? Int else { + let isPublic = json["isPrivate"] as? Bool, + let createdBy = json["createdBy"] as? String else { return nil } @@ -43,10 +42,8 @@ public class FactoryApiBet: FactoryBet { let endBetDate = dateFormatter.date(from: endBetDateString) else { return nil } - - let isPublic = (isPublicString.lowercased() == "true") - - return toModel(theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: createdBy, type: type) + + return toModel(theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0) } public func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet { diff --git a/Sources/Model/Sources/Model/Bet.swift b/Sources/Model/Sources/Model/Bet.swift index 919ebbd..fca14b5 100644 --- a/Sources/Model/Sources/Model/Bet.swift +++ b/Sources/Model/Sources/Model/Bet.swift @@ -8,7 +8,11 @@ import Foundation /// A class representing a betting entity, including details about the bet theme, participants, and deadlines. -public class Bet: ObservableObject { +public class Bet: ObservableObject, Identifiable { + + /// The id for the bet. + public var id = UUID() + /// The theme or topic of the bet. public private(set) var theme: String diff --git a/Sources/Model/Sources/Model/BetDataManager.swift b/Sources/Model/Sources/Model/BetDataManager.swift index 1a3fef2..24a769c 100644 --- a/Sources/Model/Sources/Model/BetDataManager.swift +++ b/Sources/Model/Sources/Model/BetDataManager.swift @@ -8,6 +8,6 @@ import Foundation public protocol BetDataManager { - func getBets(withIndex index: Int, withCount count: Int) -> [Bet] + func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) func getUsers(username: String) -> [User] } diff --git a/Sources/Model/Sources/Model/Manager.swift b/Sources/Model/Sources/Model/Manager.swift index 7eab799..224e021 100644 --- a/Sources/Model/Sources/Model/Manager.swift +++ b/Sources/Model/Sources/Model/Manager.swift @@ -19,4 +19,10 @@ public struct Manager { public func addBet(bet: Bet) { userDataManager.addBet(bet: bet) } + + public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + betDataManager.getBets(withIndex: index, withCount: count) { bets in + completion(bets) + } + } } diff --git a/Sources/StubLib/Sources/StubLib/BetStubManager.swift b/Sources/StubLib/Sources/StubLib/BetStubManager.swift index c9c8347..bfacf3f 100644 --- a/Sources/StubLib/Sources/StubLib/BetStubManager.swift +++ b/Sources/StubLib/Sources/StubLib/BetStubManager.swift @@ -12,8 +12,8 @@ public struct BetStubManager: BetDataManager { public init() {} - public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] { - return Stub.shared.bets + public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + completion(Stub.shared.bets) } public func getUsers(username: String) -> [User] { diff --git a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift index 2bcb8b0..673750b 100644 --- a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift +++ b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift @@ -11,12 +11,16 @@ import Model public class ManagerVM: ObservableObject { @Published var model: Manager + @Published public var bets: [Bet] = [] + public init(withModel model: Manager) { self.model = model } public func getPublicBets() { - + model.getBets(withIndex: 0, withCount: 20) { bets in + self.bets = bets + } } public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) { From c381fdf0e736ff5d58af61552431b4e759709d61 Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Fri, 19 Jan 2024 11:06:09 +0100 Subject: [PATCH 3/5] Correct AuthService --- .../contents.xcworkspacedata | 3 - .../AllInApp/AllIn/Components/BetCard.swift | 2 +- .../AllIn/Components/RecapBetCard.swift | 2 +- .../AllIn/Components/ReviewCard.swift | 2 +- .../AllInApp/AllIn/Ressources/Config.swift | 2 +- .../AllInApp/AllIn/Services/AuthService.swift | 29 +++--- .../AllIn/ViewModels/DetailsViewModel.swift | 26 ++++++ .../ViewModels/HistoricBetViewModel.swift | 24 +++++ Sources/AllInApp/AllIn/Views/BetView.swift | 3 + .../AllInApp/AllIn/Views/DetailsView.swift | 10 ++ .../AllInApp.xcodeproj/project.pbxproj | 15 +-- Sources/Api/Sources/Api/BetApiManager.swift | 4 + .../Sources/Api/Factory/FactoryApiBet.swift | 23 ++--- Sources/Api/Sources/Api/UserApiManager.swift | 9 +- Sources/Model/Sources/Model/Bet.swift | 29 +++++- .../Model/Sources/Model/BetDataManager.swift | 1 + Sources/Model/Sources/Model/BinaryBet.swift | 17 ++++ .../Sources/Model/Factory/FactoryBet.swift | 2 +- Sources/Model/Sources/Model/Manager.swift | 12 +++ Sources/Model/Sources/Model/MatchBet.swift | 21 +++++ .../Model/Sources/Model/UserDataManager.swift | 1 + Sources/StubLib/Package.swift | 29 ------ Sources/StubLib/README.md | 3 - .../Sources/StubLib/BetStubManager.swift | 26 ------ Sources/StubLib/Sources/StubLib/Stub.swift | 91 ------------------- .../Sources/StubLib/UserStubManager.swift | 38 -------- .../Sources/ViewModel/ManagerVM.swift | 16 +++- 27 files changed, 210 insertions(+), 230 deletions(-) create mode 100644 Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift create mode 100644 Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift delete mode 100644 Sources/StubLib/Package.swift delete mode 100644 Sources/StubLib/README.md delete mode 100644 Sources/StubLib/Sources/StubLib/BetStubManager.swift delete mode 100644 Sources/StubLib/Sources/StubLib/Stub.swift delete mode 100644 Sources/StubLib/Sources/StubLib/UserStubManager.swift diff --git a/Sources/AllIn.xcworkspace/contents.xcworkspacedata b/Sources/AllIn.xcworkspace/contents.xcworkspacedata index 50d956e..a92bbda 100644 --- a/Sources/AllIn.xcworkspace/contents.xcworkspacedata +++ b/Sources/AllIn.xcworkspace/contents.xcworkspacedata @@ -7,9 +7,6 @@ - - diff --git a/Sources/AllInApp/AllIn/Components/BetCard.swift b/Sources/AllInApp/AllIn/Components/BetCard.swift index c75b2b7..cf2888f 100644 --- a/Sources/AllInApp/AllIn/Components/BetCard.swift +++ b/Sources/AllInApp/AllIn/Components/BetCard.swift @@ -88,7 +88,7 @@ struct BetCard: View { }.onTapGesture { showDetails.toggle() }.fullScreenCover(isPresented: $showDetails) { - DetailsView(isModalPresented: $showDetails) + DetailsView(isModalPresented: $showDetails, id: bet.id) } } diff --git a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift index 1a47b77..440275c 100644 --- a/Sources/AllInApp/AllIn/Components/RecapBetCard.swift +++ b/Sources/AllInApp/AllIn/Components/RecapBetCard.swift @@ -107,7 +107,7 @@ struct RecapBetCard: View { .onTapGesture { showDetails.toggle() }.fullScreenCover(isPresented: $showDetails) { - DetailsView(isModalPresented: $showDetails) + DetailsView(isModalPresented: $showDetails, id: "1") } .gesture( LongPressGesture(minimumDuration: 0.5) diff --git a/Sources/AllInApp/AllIn/Components/ReviewCard.swift b/Sources/AllInApp/AllIn/Components/ReviewCard.swift index 001ef16..130e085 100644 --- a/Sources/AllInApp/AllIn/Components/ReviewCard.swift +++ b/Sources/AllInApp/AllIn/Components/ReviewCard.swift @@ -70,7 +70,7 @@ struct ReviewCard: View { .onTapGesture { showDetails.toggle() }.fullScreenCover(isPresented: $showDetails) { - DetailsView(isModalPresented: $showDetails) + DetailsView(isModalPresented: $showDetails, id: "1") } } } diff --git a/Sources/AllInApp/AllIn/Ressources/Config.swift b/Sources/AllInApp/AllIn/Ressources/Config.swift index e235a9a..d734b64 100644 --- a/Sources/AllInApp/AllIn/Ressources/Config.swift +++ b/Sources/AllInApp/AllIn/Ressources/Config.swift @@ -8,5 +8,5 @@ import Foundation struct Config { - static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api" + static let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/" } diff --git a/Sources/AllInApp/AllIn/Services/AuthService.swift b/Sources/AllInApp/AllIn/Services/AuthService.swift index 5c75fe3..ea344c4 100644 --- a/Sources/AllInApp/AllIn/Services/AuthService.swift +++ b/Sources/AllInApp/AllIn/Services/AuthService.swift @@ -10,46 +10,49 @@ import Model import ViewModel import DependencyInjection import Api -import StubLib class AuthService: IAuthService { - public func login(login: String, password: String, completion : @escaping (Int)-> ()) { + public func login(login: String, password: String, completion: @escaping (Int) -> ()) { let url = URL(string: Config.allInApi + "users/login")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") - + let json = [ "login": login.lowercased(), "password": password, ] - - if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []){ + + if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) { URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in - print ("ALLIN : Process LOGIN") + print("ALLIN: Process LOGIN") if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode == 200 { if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let token = json["token"] as? String { - AppStateContainer.shared.authenticationRefresh = token; + AppStateContainer.shared.authenticationRefresh = token self.initializeUser(withToken: token) { status in + print(status) if status != 200 { completion(status) - AppStateContainer.shared.authenticationRefresh = nil; + AppStateContainer.shared.authenticationRefresh = nil } else { self.initManagerVM(token: token) + completion(httpResponse.statusCode) } } } + } else { + completion(httpResponse.statusCode) } - completion(httpResponse.statusCode) } }.resume() } } + func register(username: String, email: String, password: String, completion : @escaping (Int)-> ()) { let url = URL(string: Config.allInApi + "/users/register")! @@ -78,11 +81,13 @@ class AuthService: IAuthService { AppStateContainer.shared.authenticationRefresh = nil; } else { self.initManagerVM(token: token) + completion(httpResponse.statusCode) } } } + } else { + completion(httpResponse.statusCode) } - completion(httpResponse.statusCode) } }.resume() } @@ -118,12 +123,14 @@ class AuthService: IAuthService { } private func initializeUser(withToken token: String, completion: @escaping (Int) -> ()) { + let url = URL(string: Config.allInApi + "users/token")! var request = URLRequest(url: url) + request.httpMethod = "GET" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") - + URLSession.shared.dataTask(with: request) { data, response, error in if let data = data, let httpResponse = response as? HTTPURLResponse { diff --git a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift new file mode 100644 index 0000000..8f63afb --- /dev/null +++ b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift @@ -0,0 +1,26 @@ +// +// DetailsViewModel.swift +// AllIn +// +// Created by Emre on 16/01/2024. +// + +import Foundation +import SwiftUI +import ViewModel +import DependencyInjection + +class DetailsViewModel: ObservableObject { + + @Inject var manager: ManagerVM + var id: String + + init(id: String) { + self.id = id + getItem() + } + + func getItem() { + + } +} diff --git a/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift new file mode 100644 index 0000000..a5643cc --- /dev/null +++ b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift @@ -0,0 +1,24 @@ +// +// HistoricBetViewModel.swift +// AllIn +// +// Created by Emre on 16/01/2024. +// + +import Foundation +import SwiftUI +import ViewModel +import DependencyInjection + +class HistoricBetViewModel: ObservableObject { + + @Inject var manager: ManagerVM + + init() { + getItems() + } + + func getItems() { + + } +} diff --git a/Sources/AllInApp/AllIn/Views/BetView.swift b/Sources/AllInApp/AllIn/Views/BetView.swift index 7a6ef13..9f28940 100644 --- a/Sources/AllInApp/AllIn/Views/BetView.swift +++ b/Sources/AllInApp/AllIn/Views/BetView.swift @@ -54,6 +54,9 @@ struct BetView: View { } } } + .refreshable { + viewModel.getItems() + } .sheet(isPresented: $showingSheet) { WinModal() } diff --git a/Sources/AllInApp/AllIn/Views/DetailsView.swift b/Sources/AllInApp/AllIn/Views/DetailsView.swift index 6bf0660..6c02302 100644 --- a/Sources/AllInApp/AllIn/Views/DetailsView.swift +++ b/Sources/AllInApp/AllIn/Views/DetailsView.swift @@ -1,7 +1,17 @@ import SwiftUI struct DetailsView: View { + @Binding var isModalPresented: Bool + var id: String + @StateObject private var viewModel: DetailsViewModel + + init(isModalPresented: Binding, id: String) { + self._isModalPresented = isModalPresented + self.id = id + self._viewModel = StateObject(wrappedValue: DetailsViewModel(id: id)) + } + var body: some View { GeometryReader { geometry in ZStack(alignment: .bottom) { diff --git a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj index a86ec07..2ba0c3a 100644 --- a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj +++ b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; }; EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; }; EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937D2B25C52E005D81E6 /* TopBar.swift */; }; + EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */; }; + EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */; }; EC3077072B24CB840060E34D /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077062B24CB840060E34D /* SplashView.swift */; }; EC3077092B24CF7F0060E34D /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3077082B24CF7F0060E34D /* Colors.swift */; }; EC30770B2B24D9160060E34D /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770A2B24D9160060E34D /* WelcomeView.swift */; }; @@ -23,7 +25,6 @@ EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2D2B4EC04B00853949 /* ViewModel */; }; - EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2F2B4EC05D00853949 /* StubLib */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; }; EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; }; @@ -111,6 +112,8 @@ EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = ""; }; EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = ""; }; EC01937D2B25C52E005D81E6 /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = ""; }; + EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsViewModel.swift; sourceTree = ""; }; + EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetViewModel.swift; sourceTree = ""; }; EC3077062B24CB840060E34D /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; EC3077082B24CF7F0060E34D /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; EC30770A2B24D9160060E34D /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; @@ -167,7 +170,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EC4F0D302B4EC05D00853949 /* StubLib in Frameworks */, EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */, ECCD244A2B4DE8010071FA9E /* Api in Frameworks */, EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */, @@ -350,6 +352,8 @@ ECB26A162B4073F100FE06B3 /* CreationBetViewModel.swift */, ECB26A182B40744F00FE06B3 /* RankingViewModel.swift */, ECB26A1A2B40746C00FE06B3 /* FriendsViewModel.swift */, + EC01FCC22B56650400BB2390 /* DetailsViewModel.swift */, + EC01FCC42B56791B00BB2390 /* HistoricBetViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -375,7 +379,6 @@ ECB357342B3E13A400045D41 /* Model */, ECCD24492B4DE8010071FA9E /* Api */, EC4F0D2D2B4EC04B00853949 /* ViewModel */, - EC4F0D2F2B4EC05D00853949 /* StubLib */, ); productName = AllIn; productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */; @@ -529,6 +532,7 @@ EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */, ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */, 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */, + EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */, ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */, ECB7BC682B2F1ADF002A6654 /* LoginViewModel.swift in Sources */, 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */, @@ -536,6 +540,7 @@ EC650A562B279D68003AFCAD /* WinModal.swift in Sources */, EC6B96D12B24BAE800FC1C58 /* AuthService.swift in Sources */, 123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */, + EC01FCC52B56791B00BB2390 /* HistoricBetViewModel.swift in Sources */, EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */, EC650A542B279545003AFCAD /* ChoiceCapsule.swift in Sources */, ECB7BC6C2B2F43EE002A6654 /* AppState.swift in Sources */, @@ -873,10 +878,6 @@ isa = XCSwiftPackageProductDependency; productName = ViewModel; }; - EC4F0D2F2B4EC05D00853949 /* StubLib */ = { - isa = XCSwiftPackageProductDependency; - productName = StubLib; - }; ECB357342B3E13A400045D41 /* Model */ = { isa = XCSwiftPackageProductDependency; productName = Model; diff --git a/Sources/Api/Sources/Api/BetApiManager.swift b/Sources/Api/Sources/Api/BetApiManager.swift index 10225a3..6de0b51 100644 --- a/Sources/Api/Sources/Api/BetApiManager.swift +++ b/Sources/Api/Sources/Api/BetApiManager.swift @@ -46,4 +46,8 @@ public struct BetApiManager: BetDataManager { return [] } + public func getBet(withId id: String, completion: @escaping (Bet) -> Void) { + + } + } diff --git a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift index 8c29b11..1adb92c 100644 --- a/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift +++ b/Sources/Api/Sources/Api/Factory/FactoryApiBet.swift @@ -11,13 +11,13 @@ import Model public class FactoryApiBet: FactoryBet { public func toResponse(bet: Bet) -> [String: Any] { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + let json: [String: Any] = [ + "id": "1", "theme": bet.theme, "sentenceBet": bet.phrase, - "endRegistration": dateFormatter.string(from: bet.endRegisterDate), - "endBet": dateFormatter.string(from: bet.endBetDate), + "endRegistration": bet.endRegisterDate.timeIntervalSince1970, + "endBet": bet.endBetDate.timeIntervalSince1970, "isPrivate": String(bet.isPublic), "response": [], ] @@ -26,7 +26,8 @@ public class FactoryApiBet: FactoryBet { } public func toModel(from json: [String: Any]) -> Bet? { - guard let theme = json["theme"] as? String, + guard let id = json["id"] as? String, + let theme = json["theme"] as? String, let phrase = json["sentenceBet"] as? String, let endRegisterDateString = json["endRegistration"] as? String, let endBetDateString = json["endBet"] as? String, @@ -43,19 +44,19 @@ public class FactoryApiBet: FactoryBet { return nil } - return toModel(theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0) + return toModel(id: id, theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: 0) } - public func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet { + public func toModel(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet { switch type { case 0: - return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) + return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) case 1: - return MatchBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "") + return MatchBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "") case 2: - return CustomBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) + return CustomBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) default: - return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) + return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: []) } } diff --git a/Sources/Api/Sources/Api/UserApiManager.swift b/Sources/Api/Sources/Api/UserApiManager.swift index 6330e6e..89873c8 100644 --- a/Sources/Api/Sources/Api/UserApiManager.swift +++ b/Sources/Api/Sources/Api/UserApiManager.swift @@ -8,7 +8,7 @@ import Foundation import Model -let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api" +let allInApi = "https://codefirst.iut.uca.fr/containers/AllDev-api/" public struct UserApiManager: UserDataManager { @@ -37,9 +37,6 @@ public struct UserApiManager: UserDataManager { URLSession.shared.uploadTask(with: request, from: jsonData) { data, response, error in print ("ALLIN : Add BET") if let httpResponse = response as? HTTPURLResponse { - if httpResponse.statusCode == 201 { - - } print(httpResponse.statusCode) } }.resume() @@ -49,4 +46,8 @@ public struct UserApiManager: UserDataManager { public func getFriends() -> [User] { fatalError("Not implemented yet") } + + public func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + fatalError("Not implemented yet") + } } diff --git a/Sources/Model/Sources/Model/Bet.swift b/Sources/Model/Sources/Model/Bet.swift index fca14b5..b99b7c2 100644 --- a/Sources/Model/Sources/Model/Bet.swift +++ b/Sources/Model/Sources/Model/Bet.swift @@ -11,7 +11,7 @@ import Foundation public class Bet: ObservableObject, Identifiable { /// The id for the bet. - public var id = UUID() + public private(set) var id: String /// The theme or topic of the bet. public private(set) var theme: String @@ -43,6 +43,32 @@ public class Bet: ObservableObject, Identifiable { /// Custom Constructor /// /// - Parameters: + /// - id: The id for the bet. + /// - theme: The theme or topic of the bet. + /// - phrase: The specific phrase or question related to the bet. + /// - endRegisterDate: The deadline for users to register for the bet. + /// - endBetDate: The deadline for the actual betting to take place. + /// - totalStakes: The total stakes or amount involved in the bet. + /// - isPublic: Indicates whether the bet is public or private. + /// - invited: List of users who are invited to participate in the bet. + /// - author: The user who created the bet. + /// - registered: List of users who have registered for the bet. + public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) { + self.id = id + self.theme = theme + self.phrase = phrase + self.endRegisterDate = endRegisterDate + self.endBetDate = endBetDate + self.totalStakes = totalStakes + self.isPublic = isPublic + self.invited = invited + self.author = author + self.registered = registered + } + + /// Custom Constructor without Id + /// + /// - Parameters: /// - theme: The theme or topic of the bet. /// - phrase: The specific phrase or question related to the bet. /// - endRegisterDate: The deadline for users to register for the bet. @@ -53,6 +79,7 @@ public class Bet: ObservableObject, Identifiable { /// - author: The user who created the bet. /// - registered: List of users who have registered for the bet. public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) { + self.id = UUID().uuidString self.theme = theme self.phrase = phrase self.endRegisterDate = endRegisterDate diff --git a/Sources/Model/Sources/Model/BetDataManager.swift b/Sources/Model/Sources/Model/BetDataManager.swift index 24a769c..bcc0b25 100644 --- a/Sources/Model/Sources/Model/BetDataManager.swift +++ b/Sources/Model/Sources/Model/BetDataManager.swift @@ -10,4 +10,5 @@ import Foundation public protocol BetDataManager { func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) func getUsers(username: String) -> [User] + func getBet(withId id: String, completion: @escaping (Bet) -> Void) } diff --git a/Sources/Model/Sources/Model/BinaryBet.swift b/Sources/Model/Sources/Model/BinaryBet.swift index 8767849..051ccf6 100644 --- a/Sources/Model/Sources/Model/BinaryBet.swift +++ b/Sources/Model/Sources/Model/BinaryBet.swift @@ -13,6 +13,23 @@ public class BinaryBet: Bet { // Custom Constructor /// /// - Parameters: + /// - id: The id for the bet. + /// - theme: The theme or topic of the binary bet. + /// - phrase: The specific phrase or question related to the binary bet. + /// - endRegisterDate: The deadline for users to register for the binary bet. + /// - endBetDate: The deadline for the actual betting to take place for the binary bet. + /// - totalStakes: The total stakes or amount involved in the binary bet. + /// - isPublic: Indicates whether the binary bet is public or private. + /// - invited: List of users who are invited to participate in the binary bet. + /// - author: The user who created the binary bet. + /// - registered: List of users who have registered for the binary bet. + public override init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User]) { + super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, totalStakes: totalStakes, isPublic: isPublic, invited: invited, author: author, registered: registered) + } + + // Custom Constructor without Id + /// + /// - Parameters: /// - theme: The theme or topic of the binary bet. /// - phrase: The specific phrase or question related to the binary bet. /// - endRegisterDate: The deadline for users to register for the binary bet. diff --git a/Sources/Model/Sources/Model/Factory/FactoryBet.swift b/Sources/Model/Sources/Model/Factory/FactoryBet.swift index c692035..40a7f0a 100644 --- a/Sources/Model/Sources/Model/Factory/FactoryBet.swift +++ b/Sources/Model/Sources/Model/Factory/FactoryBet.swift @@ -10,5 +10,5 @@ import Foundation public protocol FactoryBet { func toResponse(bet: Bet) -> [String: Any] func toModel(from json: [String: Any]) -> Bet? - func toModel(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet + func toModel(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User, type: Int) -> Bet } diff --git a/Sources/Model/Sources/Model/Manager.swift b/Sources/Model/Sources/Model/Manager.swift index 224e021..94e87a6 100644 --- a/Sources/Model/Sources/Model/Manager.swift +++ b/Sources/Model/Sources/Model/Manager.swift @@ -25,4 +25,16 @@ public struct Manager { completion(bets) } } + + public func getBet(withId id: String, completion: @escaping (Bet) -> Void) { + betDataManager.getBet(withId: id) { bet in + completion(bet) + } + } + + public func getHistoricBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + userDataManager.getOldBets(withIndex: index, withCount: count) { bets in + completion(bets) + } + } } diff --git a/Sources/Model/Sources/Model/MatchBet.swift b/Sources/Model/Sources/Model/MatchBet.swift index cddcc4e..e197042 100644 --- a/Sources/Model/Sources/Model/MatchBet.swift +++ b/Sources/Model/Sources/Model/MatchBet.swift @@ -18,6 +18,27 @@ public class MatchBet: Bet { /// Custom Constructor /// /// - Parameters: + /// - id: The id for the bet. + /// - theme: The theme or topic of the match bet. + /// - phrase: The specific phrase or question related to the match bet. + /// - endRegisterDate: The deadline for users to register for the match bet. + /// - endBetDate: The deadline for the actual betting to take place for the match bet. + /// - totalStakes: The total stakes or amount involved in the match bet. + /// - isPublic: Indicates whether the match bet is public or private. + /// - invited: List of users who are invited to participate in the match bet. + /// - author: The user who created the match bet. + /// - registered: List of users who have registered for the match bet. + /// - nameTeam1: The name of the first team involved in the match. + /// - nameTeam2: The name of the second team involved in the match. + public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, totalStakes: Int, isPublic: Bool, invited: [User], author: User, registered: [User], nameTeam1: String, nameTeam2: String) { + self.nameTeam1 = nameTeam1 + self.nameTeam2 = nameTeam2 + super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, totalStakes: totalStakes, isPublic: isPublic, invited: invited, author: author, registered: registered) + } + + /// Custom Constructor without Id + /// + /// - Parameters: /// - theme: The theme or topic of the match bet. /// - phrase: The specific phrase or question related to the match bet. /// - endRegisterDate: The deadline for users to register for the match bet. diff --git a/Sources/Model/Sources/Model/UserDataManager.swift b/Sources/Model/Sources/Model/UserDataManager.swift index 584add7..487cad9 100644 --- a/Sources/Model/Sources/Model/UserDataManager.swift +++ b/Sources/Model/Sources/Model/UserDataManager.swift @@ -11,4 +11,5 @@ public protocol UserDataManager { func getBets(withIndex index: Int, withCount count: Int) -> [Bet] func addBet(bet: Bet) func getFriends() -> [User] + func getOldBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) } diff --git a/Sources/StubLib/Package.swift b/Sources/StubLib/Package.swift deleted file mode 100644 index 813f113..0000000 --- a/Sources/StubLib/Package.swift +++ /dev/null @@ -1,29 +0,0 @@ -// swift-tools-version: 5.8 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "StubLib", - platforms: [ - .iOS(.v13) - ], - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "StubLib", - targets: ["StubLib"]), - ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - .package(name: "Model", path: "../Model") - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( - name: "StubLib", - dependencies: ["Model"]), - ] -) diff --git a/Sources/StubLib/README.md b/Sources/StubLib/README.md deleted file mode 100644 index 9f7060e..0000000 --- a/Sources/StubLib/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# StubLib - -A description of this package. diff --git a/Sources/StubLib/Sources/StubLib/BetStubManager.swift b/Sources/StubLib/Sources/StubLib/BetStubManager.swift deleted file mode 100644 index bfacf3f..0000000 --- a/Sources/StubLib/Sources/StubLib/BetStubManager.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// BetStubManager.swift -// -// -// Created by Emre on 31/12/2023. -// - -import Foundation -import Model - -public struct BetStubManager: BetDataManager { - - public init() {} - - public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { - completion(Stub.shared.bets) - } - - public func getUsers(username: String) -> [User] { - return Stub.shared.users - .filter { user in - user.username.contains(username) - } - } - -} diff --git a/Sources/StubLib/Sources/StubLib/Stub.swift b/Sources/StubLib/Sources/StubLib/Stub.swift deleted file mode 100644 index fe9e225..0000000 --- a/Sources/StubLib/Sources/StubLib/Stub.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// Stub.swift -// -// -// Created by Emre on 01/01/2024. -// - -import Foundation -import Model - -struct Stub { - - static var shared = Stub() - public var bets: [Bet] = [] - public var users: [User] = [] - - public init() { - loadBets() - } - - public mutating func loadBets() { - - var user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100, friends: []) - users.append(user1) - - var user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: [user1]) - users.append(user2) - user1.addFriend(user: user2) - - let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30, friends: [user2]) - users.append(user3) - user2.addFriend(user: user3) - - let bet1 = BinaryBet( - theme: "Football - Finale de la Ligue des Champions", - phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", - endRegisterDate: Date().addingTimeInterval(86400), - endBetDate: Date().addingTimeInterval(172800), - totalStakes: 100, - isPublic: true, - invited: [], - author: user1, - registered: [user2] - ) - self.bets.append(bet1) - - let bet2 = BinaryBet( - theme: "Cuisine - Concours de cuisine en direct", - phrase: "Le plat préféré du jury sera une recette végétarienne.", - endRegisterDate: Date().addingTimeInterval(172800), - endBetDate: Date().addingTimeInterval(259200), - totalStakes: 150, - isPublic: false, - invited: [user3], - author: user1, - registered: [user2] - ) - self.bets.append(bet2) - - let bet3 = BinaryBet( - theme: "Technologie - Lancement d'un nouveau smartphone", - phrase: "Le nombre total de précommandes dépassera-t-il 1 million dans la première semaine ?", - endRegisterDate: Date().addingTimeInterval(259200), - endBetDate: Date().addingTimeInterval(345600), - totalStakes: 75, - isPublic: true, - invited: [], - author: user1, - registered: [user2, user1, user3] - ) - self.bets.append(bet3) - - let bet4 = BinaryBet( - theme: "Cinéma - Oscars 2024", - phrase: "Le film favori des critiques remportera-t-il le prix du meilleur film ?", - endRegisterDate: Date().addingTimeInterval(345600), - endBetDate: Date().addingTimeInterval(432000), - totalStakes: 120, - isPublic: false, - invited: [user1], - author: user2, - registered: [user3] - ) - self.bets.append(bet4) - - } - - public mutating func add(bet: Bet) { - self.bets.append(bet) - } -} diff --git a/Sources/StubLib/Sources/StubLib/UserStubManager.swift b/Sources/StubLib/Sources/StubLib/UserStubManager.swift deleted file mode 100644 index a2f8b07..0000000 --- a/Sources/StubLib/Sources/StubLib/UserStubManager.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// UserStubManager.swift -// -// -// Created by Emre on 31/12/2023. -// - -import Foundation -import Model - -public struct UserStubManager: UserDataManager { - - private var username: String - - public init(username: String) { - self.username = username - } - - public func getBets(withIndex index: Int, withCount count: Int) -> [Bet] { - return Stub.shared.bets.filter { bet in - bet.registered.contains { user in - user.username == self.username - } - } - } - - public func addBet(bet: Bet) { - Stub.shared.add(bet: bet) - } - - public func getFriends() -> [User] { - return Stub.shared.users.filter { user in - user.friends.contains { friend in - friend.username == self.username - } - } - } -} diff --git a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift index 673750b..f6dd67f 100644 --- a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift +++ b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift @@ -9,9 +9,10 @@ import Foundation import Model public class ManagerVM: ObservableObject { - @Published var model: Manager + @Published var model: Manager @Published public var bets: [Bet] = [] + @Published public var bet: Bet? public init(withModel model: Manager) { self.model = model @@ -26,4 +27,17 @@ public class ManagerVM: ObservableObject { public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) { model.addBet(bet: BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])) } + + public func getBet(withId id: String) { + model.getBet(withId: id) { bet in + self.bet = bet + } + } + + public func getHistoricBets() { + model.getHistoricBets(withIndex: 0, withCount: 20) { bets in + self.bets = bets + } + } + } From 6eb3b2e8cd2971f1b07a44fb9291ebc74aeeb2ac Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Fri, 19 Jan 2024 17:54:59 +0100 Subject: [PATCH 4/5] Delete ManagerVM, re add the StubLib and improvement of the model :art: --- .../contents.xcworkspacedata | 6 +- Sources/AllInApp/AllIn/AllInApp.swift | 1 - .../AllInApp/AllIn/Components/BetCard.swift | 49 ++++------ .../AllInApp/AllIn/Services/AuthService.swift | 4 +- .../AllIn/ViewModels/BetViewModel.swift | 15 +-- .../ViewModels/CreationBetViewModel.swift | 4 +- .../AllIn/ViewModels/DetailsViewModel.swift | 14 ++- .../AllIn/ViewModels/FriendsViewModel.swift | 4 +- .../ViewModels/HistoricBetViewModel.swift | 4 +- .../AllIn/ViewModels/RankingViewModel.swift | 4 +- .../AllInApp/AllIn/Views/DetailsView.swift | 2 - .../AllInApp.xcodeproj/project.pbxproj | 12 +-- Sources/Api/Sources/Api/BetApiManager.swift | 2 +- .../Model/Sources/Model/BetAnswerDetail.swift | 43 ++++++++ .../Model/Sources/Model/BetDataManager.swift | 2 +- Sources/Model/Sources/Model/BetDetail.swift | 38 ++++++++ .../Sources/Model/BinaryParticipation.swift | 33 ------- .../Sources/Model/CustomParticipation.swift | 27 ------ Sources/Model/Sources/Model/Manager.swift | 6 +- .../Sources/Model/MatchParticipation.swift | 32 ------ .../Model/Sources/Model/Participation.swift | 32 +++--- Sources/{ViewModel => StubLib}/.gitignore | 0 Sources/{ViewModel => StubLib}/Package.swift | 8 +- Sources/{ViewModel => StubLib}/README.md | 2 +- .../Sources/StubLib/BetStubManager.swift | 32 ++++++ Sources/StubLib/Sources/StubLib/Stub.swift | 97 +++++++++++++++++++ .../Sources/ViewModel/ManagerVM.swift | 43 -------- 27 files changed, 289 insertions(+), 227 deletions(-) create mode 100644 Sources/Model/Sources/Model/BetAnswerDetail.swift create mode 100644 Sources/Model/Sources/Model/BetDetail.swift delete mode 100644 Sources/Model/Sources/Model/BinaryParticipation.swift delete mode 100644 Sources/Model/Sources/Model/CustomParticipation.swift delete mode 100644 Sources/Model/Sources/Model/MatchParticipation.swift rename Sources/{ViewModel => StubLib}/.gitignore (100%) rename Sources/{ViewModel => StubLib}/Package.swift (88%) rename Sources/{ViewModel => StubLib}/README.md (72%) create mode 100644 Sources/StubLib/Sources/StubLib/BetStubManager.swift create mode 100644 Sources/StubLib/Sources/StubLib/Stub.swift delete mode 100644 Sources/ViewModel/Sources/ViewModel/ManagerVM.swift diff --git a/Sources/AllIn.xcworkspace/contents.xcworkspacedata b/Sources/AllIn.xcworkspace/contents.xcworkspacedata index a92bbda..74c136d 100644 --- a/Sources/AllIn.xcworkspace/contents.xcworkspacedata +++ b/Sources/AllIn.xcworkspace/contents.xcworkspacedata @@ -2,13 +2,13 @@ + location = "group:StubLib"> + location = "group:Api"> + location = "group:AllInApp/AllInApp.xcodeproj"> diff --git a/Sources/AllInApp/AllIn/AllInApp.swift b/Sources/AllInApp/AllIn/AllInApp.swift index f79fa97..374a309 100644 --- a/Sources/AllInApp/AllIn/AllInApp.swift +++ b/Sources/AllInApp/AllIn/AllInApp.swift @@ -8,7 +8,6 @@ import SwiftUI import DependencyInjection import Model -import ViewModel @main struct AllInApp: App { diff --git a/Sources/AllInApp/AllIn/Components/BetCard.swift b/Sources/AllInApp/AllIn/Components/BetCard.swift index cf2888f..8f29bcf 100644 --- a/Sources/AllInApp/AllIn/Components/BetCard.swift +++ b/Sources/AllInApp/AllIn/Components/BetCard.swift @@ -12,7 +12,7 @@ struct BetCard: View { var bet: Bet @State var showDetails: Bool = false - + var body: some View { VStack(spacing: 0){ VStack(alignment: .leading,spacing: 2){ @@ -67,44 +67,33 @@ struct BetCard: View { RoundedRectangle(cornerRadius: 12).stroke(AllInColors.delimiterGrey, lineWidth: 1) ).padding([.top],5) - VStack(alignment: .leading,spacing: 2){ - HStack{ - Spacer() - UsersPreview() - Text(" 4 joueurs en attente").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color).fontWeight(.medium) - - Spacer() - - }.padding(0) - ParticipateButton().padding(.top, 5) - - } - .frame(width: .infinity) - .padding(.all,8) - .background(AllInColors.underComponentBackgroundColor) - .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) - .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) } - }.onTapGesture { + .frame(width: .infinity) + .padding(.all,8) + .background(AllInColors.underComponentBackgroundColor) + .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) + .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) + } + .onTapGesture { showDetails.toggle() - }.fullScreenCover(isPresented: $showDetails) { + } + .fullScreenCover(isPresented: $showDetails) { DetailsView(isModalPresented: $showDetails, id: bet.id) } - } } struct BetCard_Previews: PreviewProvider { static var previews: some View { BetCard(bet: BinaryBet(theme: "Football - Finale de la Ligue des Champions", - phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", - endRegisterDate: Date().addingTimeInterval(86400), - endBetDate: Date().addingTimeInterval(172800), - totalStakes: 100, - isPublic: true, - invited: [], - author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), - registered: [])) - .preferredColorScheme(.dark) + phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", + endRegisterDate: Date().addingTimeInterval(86400), + endBetDate: Date().addingTimeInterval(172800), + totalStakes: 100, + isPublic: true, + invited: [], + author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), + registered: [])) + .preferredColorScheme(.dark) } } diff --git a/Sources/AllInApp/AllIn/Services/AuthService.swift b/Sources/AllInApp/AllIn/Services/AuthService.swift index ea344c4..df4b7e6 100644 --- a/Sources/AllInApp/AllIn/Services/AuthService.swift +++ b/Sources/AllInApp/AllIn/Services/AuthService.swift @@ -7,9 +7,9 @@ import Foundation import Model -import ViewModel import DependencyInjection import Api +import StubLib class AuthService: IAuthService { @@ -150,7 +150,7 @@ class AuthService: IAuthService { } private func initManagerVM(token: String) { - DependencyInjection.shared.addSingleton(ManagerVM.self, ManagerVM(withModel: Manager(withBetDataManager: BetApiManager(), withUserDataManager: UserApiManager(withUserToken: token)))) + DependencyInjection.shared.addSingleton(Manager.self, Manager(withBetDataManager: BetStubManager(), withUserDataManager: UserApiManager(withUserToken: token))) } } diff --git a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift index 6a6dd6c..e378534 100644 --- a/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/BetViewModel.swift @@ -7,30 +7,23 @@ import Foundation import DependencyInjection -import ViewModel import Model import Combine class BetViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager - @Published private var internalBets: [Bet] = [] - - var bets: [Bet] { - return internalBets - } + @Published private(set) var bets: [Bet] = [] init() { getItems() } func getItems() { - for bet in manager.bets { - print(bet.theme) + manager.getBets(withIndex: 0, withCount: 20) { bets in + self.bets = bets } - manager.$bets.assign(to: \.internalBets, on: self).store(in: &cancellables) - manager.getPublicBets() } private var cancellables: Set = [] diff --git a/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift index 4adb521..bc7b7b0 100644 --- a/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/CreationBetViewModel.swift @@ -8,11 +8,11 @@ import Foundation import SwiftUI import DependencyInjection -import ViewModel +import Model class CreationBetViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager @Published var theme: String = "" @Published var description: String = "" @Published var isPublic = true diff --git a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift index 8f63afb..d8db75d 100644 --- a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift @@ -7,20 +7,24 @@ import Foundation import SwiftUI -import ViewModel import DependencyInjection +import Model class DetailsViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager var id: String + @Published var bet: BetDetail? + init(id: String) { self.id = id - getItem() + getItem(withId: id) } - func getItem() { - + func getItem(withId id: String) { + manager.getBet(withId: id) { bet in + self.bet = bet + } } } diff --git a/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift index a98dfbf..294ab23 100644 --- a/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/FriendsViewModel.swift @@ -7,11 +7,11 @@ import Foundation import DependencyInjection -import ViewModel +import Model class FriendsViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager init() { getItems() diff --git a/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift index a5643cc..480c7a1 100644 --- a/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/HistoricBetViewModel.swift @@ -7,12 +7,12 @@ import Foundation import SwiftUI -import ViewModel import DependencyInjection +import Model class HistoricBetViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager init() { getItems() diff --git a/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift index d9bfcbd..e321f91 100644 --- a/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/RankingViewModel.swift @@ -7,11 +7,11 @@ import Foundation import DependencyInjection -import ViewModel +import Model class RankingViewModel: ObservableObject { - @Inject var manager: ManagerVM + @Inject var manager: Manager init() { getItems() diff --git a/Sources/AllInApp/AllIn/Views/DetailsView.swift b/Sources/AllInApp/AllIn/Views/DetailsView.swift index 6c02302..f317d0e 100644 --- a/Sources/AllInApp/AllIn/Views/DetailsView.swift +++ b/Sources/AllInApp/AllIn/Views/DetailsView.swift @@ -43,14 +43,12 @@ struct DetailsView: View { HStack{ Text("Commence le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) TextCapsule(date: Date()) - TextCapsule(date: Date()) Spacer() }.padding(.bottom, 10) HStack{ Text("Fini le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) TextCapsule(date: Date()) - TextCapsule(date: Date()) Spacer() } diff --git a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj index 2ba0c3a..3199431 100644 --- a/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj +++ b/Sources/AllInApp/AllInApp.xcodeproj/project.pbxproj @@ -24,7 +24,7 @@ EC30770D2B24DB7A0060E34D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770C2B24DB7A0060E34D /* Extensions.swift */; }; EC30770F2B24FCB00060E34D /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC30770E2B24FCB00060E34D /* RegisterView.swift */; }; EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = ECB357342B3E13A400045D41 /* Model */; }; - EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = EC4F0D2D2B4EC04B00853949 /* ViewModel */; }; + EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */ = {isa = PBXBuildFile; productRef = EC60C5672B5A83FB00FFD6EF /* StubLib */; }; EC650A422B25C817003AFCAD /* Friend.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A412B25C817003AFCAD /* Friend.swift */; }; EC650A442B25CDF3003AFCAD /* ParameterMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A432B25CDF3003AFCAD /* ParameterMenu.swift */; }; EC650A462B25D686003AFCAD /* RankingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC650A452B25D686003AFCAD /* RankingRow.swift */; }; @@ -102,7 +102,6 @@ /* Begin PBXFileReference section */ 122278B72B4BDE1100E632AA /* DependencyInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DependencyInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 122278B92B4BDE9500E632AA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Model/Package.swift; sourceTree = ""; }; - 122278BB2B4BDEC300E632AA /* Sources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Sources; path = ../StubLib/Sources; sourceTree = ""; }; 123590B32B51792000F7AEBD /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = ""; }; 123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = ""; }; 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = ""; }; @@ -170,9 +169,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EC60C5682B5A83FB00FFD6EF /* StubLib in Frameworks */, EC4F0D2C2B4EBF5600853949 /* Model in Frameworks */, ECCD244A2B4DE8010071FA9E /* Api in Frameworks */, - EC4F0D2E2B4EC04B00853949 /* ViewModel in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -334,7 +333,6 @@ ECB3572D2B3CA3BD00045D41 /* Frameworks */ = { isa = PBXGroup; children = ( - 122278BB2B4BDEC300E632AA /* Sources */, 122278B92B4BDE9500E632AA /* Package.swift */, 122278B72B4BDE1100E632AA /* DependencyInjection.framework */, ECB357302B3CA69300045D41 /* DependencyInjection.framework */, @@ -378,7 +376,7 @@ packageProductDependencies = ( ECB357342B3E13A400045D41 /* Model */, ECCD24492B4DE8010071FA9E /* Api */, - EC4F0D2D2B4EC04B00853949 /* ViewModel */, + EC60C5672B5A83FB00FFD6EF /* StubLib */, ); productName = AllIn; productReference = EC6B96982B24B4CC00FC1C58 /* AllIn.app */; @@ -874,9 +872,9 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - EC4F0D2D2B4EC04B00853949 /* ViewModel */ = { + EC60C5672B5A83FB00FFD6EF /* StubLib */ = { isa = XCSwiftPackageProductDependency; - productName = ViewModel; + productName = StubLib; }; ECB357342B3E13A400045D41 /* Model */ = { isa = XCSwiftPackageProductDependency; diff --git a/Sources/Api/Sources/Api/BetApiManager.swift b/Sources/Api/Sources/Api/BetApiManager.swift index 6de0b51..4141547 100644 --- a/Sources/Api/Sources/Api/BetApiManager.swift +++ b/Sources/Api/Sources/Api/BetApiManager.swift @@ -46,7 +46,7 @@ public struct BetApiManager: BetDataManager { return [] } - public func getBet(withId id: String, completion: @escaping (Bet) -> Void) { + public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { } diff --git a/Sources/Model/Sources/Model/BetAnswerDetail.swift b/Sources/Model/Sources/Model/BetAnswerDetail.swift new file mode 100644 index 0000000..77ab2d8 --- /dev/null +++ b/Sources/Model/Sources/Model/BetAnswerDetail.swift @@ -0,0 +1,43 @@ +// +// BetAnswerDetail.swift +// +// +// Created by Emre on 19/01/2024. +// + +import Foundation + +/// A class representing detailed information about a specific answer option for a bet. +public class BetAnswerDetail: ObservableObject { + + /// The response or outcome associated with this answer. + public private(set) var response: String + + /// The total amount of stakes placed on this answer. + public private(set) var totalStakes: Int + + /// The total number of participants who selected this answer. + public private(set) var totalParticipants: Int + + /// The highest stake placed on this answer. + public private(set) var highestStake: Int + + /// The odds associated with this answer. + public private(set) var odds: Float + + /// Custom Constructor + /// + /// - Parameters: + /// - response: The response or outcome associated with this answer. + /// - totalStakes: The total amount of stakes placed on this answer. + /// - totalParticipants: The total number of participants who selected this answer. + /// - highestStake: The highest stake placed on this answer. + /// - odds: The odds associated with this answer. + public init(response: String, totalStakes: Int, totalParticipants: Int, highestStake: Int, odds: Float) { + self.response = response + self.totalStakes = totalStakes + self.totalParticipants = totalParticipants + self.highestStake = highestStake + self.odds = odds + } +} diff --git a/Sources/Model/Sources/Model/BetDataManager.swift b/Sources/Model/Sources/Model/BetDataManager.swift index bcc0b25..6fede4a 100644 --- a/Sources/Model/Sources/Model/BetDataManager.swift +++ b/Sources/Model/Sources/Model/BetDataManager.swift @@ -10,5 +10,5 @@ import Foundation public protocol BetDataManager { func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) func getUsers(username: String) -> [User] - func getBet(withId id: String, completion: @escaping (Bet) -> Void) + func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) } diff --git a/Sources/Model/Sources/Model/BetDetail.swift b/Sources/Model/Sources/Model/BetDetail.swift new file mode 100644 index 0000000..e9d7804 --- /dev/null +++ b/Sources/Model/Sources/Model/BetDetail.swift @@ -0,0 +1,38 @@ +// +// BetDetail.swift +// +// +// Created by Emre on 19/01/2024. +// + +import Foundation + +/// A class representing detailed information about a specific bet, including answers and user participations. +public class BetDetail: ObservableObject { + + /// The main bet information. + public private(set) var bet: Bet + + /// Details about the answers available for the bet. + public private(set) var answers: [BetAnswerDetail] + + /// List of user participations in the bet. + public private(set) var participations: [Participation] + + /// The user's own participation in the bet. + public private(set) var userParticipation: Participation + + /// Custom Constructor + /// + /// - Parameters: + /// - bet: The main bet information. + /// - answers: Details about the answers available for the bet. + /// - participations: List of user participations in the bet. + /// - userParticipation: The user's own participation in the bet. + public init(bet: Bet, answers: [BetAnswerDetail], participations: [Participation], userParticipation: Participation) { + self.bet = bet + self.answers = answers + self.participations = participations + self.userParticipation = userParticipation + } +} diff --git a/Sources/Model/Sources/Model/BinaryParticipation.swift b/Sources/Model/Sources/Model/BinaryParticipation.swift deleted file mode 100644 index 5a02622..0000000 --- a/Sources/Model/Sources/Model/BinaryParticipation.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// BinaryParticipation.swift -// -// -// Created by Emre on 28/12/2023. -// - -import Foundation - -/// Enum to represent the possible answers for a binary participation. -public enum YesNo { - case yes - case no -} - -/// A subclass of Participation that represents a binary participation (yes/no) in a bet. -public class BinaryParticipation: Participation { - /// The answer for the binary participation (yes or no). - public var answer: YesNo - - /// Custom Constructor - /// - /// - Parameters: - /// - coinAmount: The amount of coins involved in the binary participation. - /// - date: The date and time when the binary participation occurred. - /// - user: The user who participated in the binary bet. - /// - bet: The binary bet in which the user participated. - /// - answer: The answer for the binary participation (yes or no). - public init(coinAmount: Int, date: Date, user: User, bet: Bet, answer: YesNo) { - self.answer = answer - super.init(coinAmount: coinAmount, date: date, user: user, bet: bet) - } -} diff --git a/Sources/Model/Sources/Model/CustomParticipation.swift b/Sources/Model/Sources/Model/CustomParticipation.swift deleted file mode 100644 index 9956aa9..0000000 --- a/Sources/Model/Sources/Model/CustomParticipation.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// CustomParticipation.swift -// -// -// Created by Emre on 28/12/2023. -// - -import Foundation - -/// A subclass of Participation that represents a custom participation in a bet. -public class CustomParticipation: Participation { - /// The user's response to the custom bet. - public var answer: CustomBetResponse - - /// Custom Constructor - /// - /// - Parameters: - /// - coinAmount: The amount of coins involved in the custom participation. - /// - date: The date and time when the custom participation occurred. - /// - user: The user who participated in the custom bet. - /// - bet: The custom bet in which the user participated. - /// - answer: The user's response to the custom bet. - public init(coinAmount: Int, date: Date, user: User, bet: Bet, answer: CustomBetResponse) { - self.answer = answer - super.init(coinAmount: coinAmount, date: date, user: user, bet: bet) - } -} diff --git a/Sources/Model/Sources/Model/Manager.swift b/Sources/Model/Sources/Model/Manager.swift index 94e87a6..3ff086a 100644 --- a/Sources/Model/Sources/Model/Manager.swift +++ b/Sources/Model/Sources/Model/Manager.swift @@ -16,8 +16,8 @@ public struct Manager { self.userDataManager = userDataManager } - public func addBet(bet: Bet) { - userDataManager.addBet(bet: bet) + public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) { + userDataManager.addBet(bet: BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])) } public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { @@ -26,7 +26,7 @@ public struct Manager { } } - public func getBet(withId id: String, completion: @escaping (Bet) -> Void) { + public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { betDataManager.getBet(withId: id) { bet in completion(bet) } diff --git a/Sources/Model/Sources/Model/MatchParticipation.swift b/Sources/Model/Sources/Model/MatchParticipation.swift deleted file mode 100644 index 68b47ba..0000000 --- a/Sources/Model/Sources/Model/MatchParticipation.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// MatchParticipation.swift -// -// -// Created by Emre on 28/12/2023. -// - -import Foundation - -/// A subclass of Participation that represents a user's participation in a match bet. -public class MatchParticipation: Participation { - /// The points earned by the user for the first team in the match. - public var pointsTeam1: Int - - /// The points earned by the user for the second team in the match. - public var pointsTeam2: Int - - /// Custom Constructor - /// - /// - Parameters: - /// - coinAmount: The amount of coins involved in the match participation. - /// - date: The date and time when the match participation occurred. - /// - user: The user who participated in the match bet. - /// - bet: The match bet in which the user participated. - /// - pointsTeam1: The points earned by the user for the first team in the match. - /// - pointsTeam2: The points earned by the user for the second team in the match. - public init(coinAmount: Int, date: Date, user: User, bet: Bet, pointsTeam1: Int, pointsTeam2: Int) { - self.pointsTeam1 = pointsTeam1 - self.pointsTeam2 = pointsTeam2 - super.init(coinAmount: coinAmount, date: date, user: user, bet: bet) - } -} diff --git a/Sources/Model/Sources/Model/Participation.swift b/Sources/Model/Sources/Model/Participation.swift index 6ccd9be..4040e22 100644 --- a/Sources/Model/Sources/Model/Participation.swift +++ b/Sources/Model/Sources/Model/Participation.swift @@ -1,37 +1,43 @@ // // Participation.swift -// +// // // Created by Emre on 28/12/2023. // import Foundation -/// A class representing a user's participation in a bet, including the amount of coins, date, user, and the associated bet. +/// A class representing a user's participation in a bet. public class Participation: ObservableObject { - /// The amount of coins involved in the participation. - var coinAmount: Int + + /// The amount of stake in the bet. + public private(set) var stake: Int /// The date and time when the participation occurred. - var date: Date + public private(set) var date: Date + + /// The response or outcome of the participation. + public private(set) var response: String /// The user who participated in the bet. - var user: User + public private(set) var user: User - /// The bet in which the user participated. - var bet: Bet + /// The unique identifier of the bet. + let betId: String /// Custom Constructor /// /// - Parameters: - /// - coinAmount: The amount of coins involved in the participation. + /// - stake: The amount of stake in the bet. /// - date: The date and time when the participation occurred. + /// - response: The response or outcome of the participation. /// - user: The user who participated in the bet. - /// - bet: The bet in which the user participated. - init(coinAmount: Int, date: Date, user: User, bet: Bet) { - self.coinAmount = coinAmount + /// - betId: The unique identifier of the bet. + public init(stake: Int, date: Date, response: String, user: User, betId: String) { + self.stake = stake self.date = date + self.response = response self.user = user - self.bet = bet + self.betId = betId } } diff --git a/Sources/ViewModel/.gitignore b/Sources/StubLib/.gitignore similarity index 100% rename from Sources/ViewModel/.gitignore rename to Sources/StubLib/.gitignore diff --git a/Sources/ViewModel/Package.swift b/Sources/StubLib/Package.swift similarity index 88% rename from Sources/ViewModel/Package.swift rename to Sources/StubLib/Package.swift index 67fd2cf..813f113 100644 --- a/Sources/ViewModel/Package.swift +++ b/Sources/StubLib/Package.swift @@ -4,15 +4,15 @@ import PackageDescription let package = Package( - name: "ViewModel", + name: "StubLib", platforms: [ .iOS(.v13) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( - name: "ViewModel", - targets: ["ViewModel"]), + name: "StubLib", + targets: ["StubLib"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. @@ -23,7 +23,7 @@ let package = Package( // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( - name: "ViewModel", + name: "StubLib", dependencies: ["Model"]), ] ) diff --git a/Sources/ViewModel/README.md b/Sources/StubLib/README.md similarity index 72% rename from Sources/ViewModel/README.md rename to Sources/StubLib/README.md index 74e3704..9f7060e 100644 --- a/Sources/ViewModel/README.md +++ b/Sources/StubLib/README.md @@ -1,3 +1,3 @@ -# ViewModel +# StubLib A description of this package. diff --git a/Sources/StubLib/Sources/StubLib/BetStubManager.swift b/Sources/StubLib/Sources/StubLib/BetStubManager.swift new file mode 100644 index 0000000..7bb801f --- /dev/null +++ b/Sources/StubLib/Sources/StubLib/BetStubManager.swift @@ -0,0 +1,32 @@ +// +// BetStubManager.swift +// +// +// Created by Emre on 31/12/2023. +// + +import Foundation +import Model + +public struct BetStubManager: BetDataManager { + + public init() {} + + public func getBets(withIndex index: Int, withCount count: Int, completion: @escaping ([Bet]) -> Void) { + completion(Stub.shared.bets) + } + + public func getUsers(username: String) -> [User] { + return [] + } + + public func getBet(withId id: String, completion: @escaping (BetDetail) -> Void) { + + if let betDetail = Stub.shared.betsDetail.first(where: { $0.bet.id == id }) { + completion(betDetail) + } else { + print("BetDetail with ID \(id) not found.") + } + } + +} diff --git a/Sources/StubLib/Sources/StubLib/Stub.swift b/Sources/StubLib/Sources/StubLib/Stub.swift new file mode 100644 index 0000000..5e70aa0 --- /dev/null +++ b/Sources/StubLib/Sources/StubLib/Stub.swift @@ -0,0 +1,97 @@ +// +// Stub.swift +// +// +// Created by Emre on 01/01/2024. +// + +import Foundation +import Model + +struct Stub { + + static var shared = Stub() + public var bets: [Bet] = [] + public var betsDetail: [BetDetail] = [] + public var users: [User] = [] + + public init() { + loadBets() + } + + public mutating func loadBets() { + + var user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100, friends: []) + users.append(user1) + + var user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: [user1]) + users.append(user2) + user1.addFriend(user: user2) + + let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30, friends: [user2]) + users.append(user3) + user2.addFriend(user: user3) + + let bet1 = BinaryBet( + theme: "Football - Finale de la Ligue des Champions", + phrase: "Le gagnant de la finale sera l'équipe avec le plus de tirs au but.", + endRegisterDate: Date().addingTimeInterval(86400), + endBetDate: Date().addingTimeInterval(172800), + totalStakes: 100, + isPublic: true, + invited: [], + author: user1, + registered: [user2] + ) + self.bets.append(bet1) + + let bet2 = BinaryBet( + theme: "Cuisine - Concours de cuisine en direct", + phrase: "Le plat préféré du jury sera une recette végétarienne.", + endRegisterDate: Date().addingTimeInterval(172800), + endBetDate: Date().addingTimeInterval(259200), + totalStakes: 150, + isPublic: false, + invited: [user3], + author: user1, + registered: [user2] + ) + self.bets.append(bet2) + + let bet3 = BinaryBet( + theme: "Technologie - Lancement d'un nouveau smartphone", + phrase: "Le nombre total de précommandes dépassera-t-il 1 million dans la première semaine ?", + endRegisterDate: Date().addingTimeInterval(259200), + endBetDate: Date().addingTimeInterval(345600), + totalStakes: 75, + isPublic: true, + invited: [], + author: user1, + registered: [user2, user1, user3] + ) + self.bets.append(bet3) + + let bet4 = BinaryBet( + theme: "Cinéma - Oscars 2024", + phrase: "Le film favori des critiques remportera-t-il le prix du meilleur film ?", + endRegisterDate: Date().addingTimeInterval(345600), + endBetDate: Date().addingTimeInterval(432000), + totalStakes: 120, + isPublic: false, + invited: [user1], + author: user2, + registered: [user3] + ) + self.bets.append(bet4) + + for bet in bets { + let betDetail = BetDetail(bet: bet, answers: [], participations: [], userParticipation: Participation(stake: 0, date: Date(), response: "", user: user1, betId: "")) + self.betsDetail.append(betDetail) + } + } + + public mutating func add(bet: Bet) { + let newBetDetail = BetDetail(bet: bet, answers: [], participations: [], userParticipation: Participation(stake: 0, date: Date(), response: "", user: users[1], betId: "")) + self.betsDetail.append(newBetDetail) + } +} diff --git a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift b/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift deleted file mode 100644 index f6dd67f..0000000 --- a/Sources/ViewModel/Sources/ViewModel/ManagerVM.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ManagerVM.swift -// -// -// Created by Emre on 30/12/2023. -// - -import Foundation -import Model - -public class ManagerVM: ObservableObject { - - @Published var model: Manager - @Published public var bets: [Bet] = [] - @Published public var bet: Bet? - - public init(withModel model: Manager) { - self.model = model - } - - public func getPublicBets() { - model.getBets(withIndex: 0, withCount: 20) { bets in - self.bets = bets - } - } - - public func addBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, creator: User) { - model.addBet(bet: BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, totalStakes: 0, isPublic: isPublic, invited: [], author: creator, registered: [])) - } - - public func getBet(withId id: String) { - model.getBet(withId: id) { bet in - self.bet = bet - } - } - - public func getHistoricBets() { - model.getHistoricBets(withIndex: 0, withCount: 20) { bets in - self.bets = bets - } - } - -} From b4992ba793e66c0716c3fd638067c7ebf053dc14 Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Fri, 19 Jan 2024 19:27:30 +0100 Subject: [PATCH 5/5] start of binding DetailsView --- .../Contents.json | 0 .../Exclude (1).png | Bin .../AllIn/Components/ReviewCard.swift | 4 +- .../AllIn/ViewModels/DetailsViewModel.swift | 4 +- .../AllInApp/AllIn/Views/DetailsView.swift | 49 ++++++++++-------- 5 files changed, 32 insertions(+), 25 deletions(-) rename Sources/AllInApp/AllIn/Assets.xcassets/{CloseiconRounded.imageset => closeIcon.imageset}/Contents.json (100%) rename Sources/AllInApp/AllIn/Assets.xcassets/{CloseiconRounded.imageset => closeIcon.imageset}/Exclude (1).png (100%) diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/CloseiconRounded.imageset/Contents.json b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Contents.json similarity index 100% rename from Sources/AllInApp/AllIn/Assets.xcassets/CloseiconRounded.imageset/Contents.json rename to Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Contents.json diff --git a/Sources/AllInApp/AllIn/Assets.xcassets/CloseiconRounded.imageset/Exclude (1).png b/Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Exclude (1).png similarity index 100% rename from Sources/AllInApp/AllIn/Assets.xcassets/CloseiconRounded.imageset/Exclude (1).png rename to Sources/AllInApp/AllIn/Assets.xcassets/closeIcon.imageset/Exclude (1).png diff --git a/Sources/AllInApp/AllIn/Components/ReviewCard.swift b/Sources/AllInApp/AllIn/Components/ReviewCard.swift index 130e085..2798c36 100644 --- a/Sources/AllInApp/AllIn/Components/ReviewCard.swift +++ b/Sources/AllInApp/AllIn/Components/ReviewCard.swift @@ -37,14 +37,14 @@ struct ReviewCard: View { HStack(){ Spacer() Text(amountBetted.description) - .foregroundColor(AllInColors.whiteColor) + .foregroundColor(.white) .font(.system(size: 25)) .fontWeight(.bold) Image("allcoinWhiteIcon") .resizable() .frame(width: 20, height: 20, alignment: .bottom) Text(isAWin ? "Gagnés!" : "Perdus!") - .foregroundColor(AllInColors.whiteColor) + .foregroundColor(.white) .font(.system(size: 25)) .fontWeight(.bold) Spacer() diff --git a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift index d8db75d..e6980e6 100644 --- a/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift +++ b/Sources/AllInApp/AllIn/ViewModels/DetailsViewModel.swift @@ -15,7 +15,7 @@ class DetailsViewModel: ObservableObject { @Inject var manager: Manager var id: String - @Published var bet: BetDetail? + @Published var betDetail: BetDetail? init(id: String) { self.id = id @@ -24,7 +24,7 @@ class DetailsViewModel: ObservableObject { func getItem(withId id: String) { manager.getBet(withId: id) { bet in - self.bet = bet + self.betDetail = bet } } } diff --git a/Sources/AllInApp/AllIn/Views/DetailsView.swift b/Sources/AllInApp/AllIn/Views/DetailsView.swift index f317d0e..2dd996f 100644 --- a/Sources/AllInApp/AllIn/Views/DetailsView.swift +++ b/Sources/AllInApp/AllIn/Views/DetailsView.swift @@ -18,7 +18,7 @@ struct DetailsView: View { VStack(alignment: .trailing) { HStack{ Spacer() - Image("CloseiconRounded") + Image("closeIcon") .resizable() .padding(8) .frame(maxWidth: 40, maxHeight: 40) @@ -35,34 +35,45 @@ struct DetailsView: View { VStack(alignment: .leading,spacing: 5){ HStack{ Spacer() - Text("proposé par Lucas").font(.system(size: 10)).foregroundColor(AllInColors.grey800Color) + Text("proposé par " + (viewModel.betDetail?.bet.author.username ?? "Unknown").capitalized) + .font(.system(size: 10)) + .foregroundColor(AllInColors.grey800Color) } - Text("Etudes").font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - Text("Emre va réussir son TP de CI/CD mercredi?").font(.system(size: 20)).fontWeight(.bold).padding(.bottom, 10) + Text(viewModel.betDetail?.bet.theme ?? "Not loaded") + .font(.system(size: 15)) + .foregroundColor(AllInColors.grey800Color) + Text(viewModel.betDetail?.bet.phrase ?? "Not loaded") + .font(.system(size: 20)) + .fontWeight(.bold) + .padding(.bottom, 10) HStack{ - Text("Commence le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - TextCapsule(date: Date()) + Text("Commence le") + .frame(maxWidth: 100) + .font(.system(size: 15)) + .foregroundColor(AllInColors.grey800Color) + TextCapsule(date: viewModel.betDetail?.bet.endRegisterDate ?? Date()) Spacer() }.padding(.bottom, 10) HStack{ - Text("Fini le").frame(maxWidth: 100).font(.system(size: 15)).foregroundColor(AllInColors.grey800Color) - TextCapsule(date: Date()) + Text("Fini le") + .frame(maxWidth: 100) + .font(.system(size: 15)) + .foregroundColor(AllInColors.grey800Color) + TextCapsule(date: viewModel.betDetail?.bet.endBetDate ?? Date()) Spacer() } } .frame(width: .infinity) .padding(.all,15).padding(.vertical, 10) - .background(AllInColors.componentBackgroundColor).cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0) + .background(AllInColors.componentBackgroundColor) + .cornerRadius(20, corners: [.topLeft,.topRight]).padding(.bottom,0) ResultBanner() - VStack(alignment: .leading,spacing: 2){ - - - + VStack(alignment: .leading, spacing: 2){ } - .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight : .infinity) + .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) .padding([.bottom,.trailing,.leading],8) .background(AllInColors.underComponentBackgroundColor) .border(width: 1, edges: [.top], color: AllInColors.delimiterGrey) @@ -71,18 +82,14 @@ struct DetailsView: View { } .frame(maxWidth: .infinity, maxHeight: geometry.size.height*0.98) - .background(Color.white) + .background(AllInColors.componentBackgroundColor) .cornerRadius(15) ParticipateButton().padding(10) } .transition(.slideInFromBottom(yOffset: 800)) + .background(Color.white) + .edgesIgnoringSafeArea(.bottom) } } } - -struct DetailsView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -}