From 62c2defb1d7ed09823d33868c9df03c6ebe922aa Mon Sep 17 00:00:00 2001 From: Junhui Chen Date: Tue, 19 Aug 2025 20:53:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A2=E9=98=85=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserInterfaceState.xcuserstate | Bin 57109 -> 76293 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 24 ++ wake/Theme.swift | 26 +- wake/Typography.swift | 6 +- wake/View/Credits/CreditsDetailView.swift | 288 +++++++++++++++ wake/View/Credits/CreditsInfoCard.swift | 107 ++++++ .../Subscribe/Components/PlanCompare.swift | 165 +++++++++ .../Subscribe/Components/PlanSelector.swift | 135 +++++++ .../Components/SubscribeButton.swift | 69 ++++ .../Components/SubscribePolicy.swift | 0 .../Components/SubscriptionStatusBar.swift | 20 +- wake/View/Subscribe/SubscribeView.swift | 328 +++++------------- 12 files changed, 911 insertions(+), 257 deletions(-) create mode 100644 wake.xcodeproj/xcuserdata/fairclip.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 wake/View/Credits/CreditsDetailView.swift create mode 100644 wake/View/Credits/CreditsInfoCard.swift create mode 100644 wake/View/Subscribe/Components/PlanCompare.swift create mode 100644 wake/View/Subscribe/Components/PlanSelector.swift create mode 100644 wake/View/Subscribe/Components/SubscribeButton.swift create mode 100644 wake/View/Subscribe/Components/SubscribePolicy.swift diff --git a/wake.xcodeproj/project.xcworkspace/xcuserdata/fairclip.xcuserdatad/UserInterfaceState.xcuserstate b/wake.xcodeproj/project.xcworkspace/xcuserdata/fairclip.xcuserdatad/UserInterfaceState.xcuserstate index 6e6e72499448001a99e3761746a5dee7d7cabe07..8717dea82a31eb1e9dd5050b8e85794f536020a7 100644 GIT binary patch literal 76293 zcmeFa2VfM{_CG%NPM_J?nJu9S2!sx4^dcn{LJ1{=4sl7AWF^Ul>;{N{%*BqNC?F^* zBtfbQ2o?}gQ4~;7Kt;q3qJjlbM8WbucS|T6(Vya%_uk*<+YLK&=hpN2+;h%7cka02 z0*}uhAO9AE7|gH?$MB56h>SA4@g#SN&*Lo`(b!dzlkb6FLmKn@%!uy zx@Bp$p=V_Fb(gtw6GMsiFcKqYW%^xyw~5x;ggK1LSeTkjEv7cpmAQuL#&l zCW%RAQkYaGjp@boX408H%rIsQGnUC^@)-|P$P_UpjE|YjOkt)m(;33dWNu+@W$s{R zGjo}{nfc5z=3!zIwq6U=kW^UMp(HfB4si`mV*!R%$;X5L}mV?JgM zGoLZvGRK({%t_`4=2zx7#2^XDNI@#HARDry8mKO6fEuC}s3mHJ5>OkIgpyGTN=0d? z7wU}$qCsdd8i_`s(WnS{Q8Ai`N{|ovQ7M{)u15sTM7N>a(L6LCEkO68`_Y4_995uY z=n?cNdJL^a>(F|%32jEtpx4oE^agqp?Lm9dKJ*rP7kz|2Mn}-+=ma{6zC+)mAJNa4 z!#ozSf>o?z8+PJaxHhhb>*Llq9w*@TxHIm8yW<`>8K>aUcnltkv+=dqg~#C>oQvIf zJiZQ3#3k5={dgLlj&H!X;9K!+_;x%G&&Lb!z4(6o5MF|p;+1$6egSX8FXET*cKkAa z1@FK+@ha3Vf5K<*uPkO+mSZif#x`M_vd!4$ zYzwv}+lpKXyV-l#d)WushuP)q3U)pFIJ<$}$Ue<(VP9gmvoEu+uy3$$ zvR|-YvPaot>{sm9>^JPU>~Z!4dy@Tu{e}IN{f%QdiIX{nvvUs4$<^ns<{EGfxh7l- zt|ixsYsnaW8YPaIbQ&ac^>axVO1?xc9h&+(+EU++prB?n~|{_YLt-Q_~yp6Z>4&KSv;;-hL@y+=bd|SR9-=6Qlcj3G9X?!ofH$R*o!H?ue z@uT@M{8&Dl&*SrX4}Tp$fuG2i@IHPrKZ7^<`}xKE1N?*hL;MncDPPW4@Rj^BekH$_ zU&pWKH}RYKXZY>>%ls?+4*oU%P5xc}0RJ9;kUz$M#edCz!+*;k=TGn_`7``k0SQ=O z1y!&JO@(GcbD@RMQfMW#7Gi{0Ax?-F+6i5SYlLn>s*oo15(WqZg+an7VYDzt7%Pku z#tV~#$-)$&Ot@Z{Dohh@5^fgm5M~Q=gayLA!a8BS@VKx+*eE<9JSjXSJS}VzHVa#Y z?ZV5#Zs85#P2oM^pzyx%f$)j&neesnjqt5-Tx3KfVv!X&krxF~6m`)MYlt<)T4DpS zq1ajMB6bz85xa@q#U5f$F;Pqslf_Z(JhV_^TY|FSDY+P5zEBu z#hK!b;)CKt;u3MGST0tGmEtn-VR5;*LR=$0E^ZJvid)2I#jWDY;w$0~aj&>fd`o;= zJRp7`ekgt;ek&dqPlzYQ@5JxLQ{pe;uM#Kmk|0?nU1}yZms&_IrB+gFDMpHw;-q*f zL255uBc({GQks+@4Uh&(Bc)N&Xlab(lH5|ER3zOd-7d|N?vQ3nbEG?^yQI0&-O@eM zJZYiykhEM{A+40wN$aJ@r7hC4(pKp?=|$-kX}|QYbU=DfIw-v_eIR`(9g#klzLvg` zevnSfx@^cc*)BU|ryM2MkZa1dr_5ItDEBJ&E9FXsQmL#_9#I}uo=~1to>E>=wka#J9*4b+BeBQ;uWtTs`b zs?F5qYHPKv+D>h+c2m2nJ=9)mZ?&)5PaUcbQ-`Y~)G?|{ov4I~IX zXQ_9nv(-83o$5X6Jaw`9fVxqALVZ$wN_|@0q;6K9QMahis$11<>P~f!x>wz&exQD+ zex!b^9#+3lkE1)!&1{y%Tn7?$8wdWuBD!(zU695w56q`jis%nou#{_ zhoz?_(UNLOw+yljwq#mzEV&l9WxOTNl5g=?CR$1?(=5|1H&|v^ZnfNIsjyU9mRTOQ zEVrz%thB7MthTJNJYrdAdCKy%<$22smTi_@mRBvWS>Cbix4dgPVEMrEiRDwvNy~SZ z?=7b+KUhv%e$*HZX{u(?G|j5j&}wRNTD+E^wb9yY?X>n<2d$&lN$ae2(^9llt-qF` z4bX;Z!?h7wj+U#rwei|@T9M|}CTml)x!T>@J=#2NzP3QSS6iqp((cpl*B;Uy)|P9J zX=}B0+Ggz;ZHxA-_JX!udtKYDy`k;b-qlWO-)Y}#r?elm)7p>PPudyntoE~&v5HpR zYFKU7tE_dc^{n-+jjTmche>u~D`tIImh zI?X!WdV_U_)wB}pOzVx-o2)lmZ?Vp@-fg|ldcSqC^k8{i>m$~6)~BtTtedU7 ztgl*Mv%YTKZGFS~rge|?fb~7=$JS4*Us{jqSZ8%k=XF6BbxD_XMOSr;Zs;}jtMvwY zL%oIGQg5ZV*E{GP^-lUVdQZK#p02y}ae9uPtGo5_dY+!Id-Ut{3A$IGq~D;=&`td| z{dRqpK3`v;->Waw7wb#(75Ym3F@3GRPT#0+*0<_A^qu-H{Z)OR{+9l(eo+5VKcXMi zztKYn`D!1y3MdTZBe#{wnnySTVq=jTPs^@Tf8m7 z*3s70c8#r{t-me9Ho!K}Hpn*EHrzJCmSfAcxozWZc{Z=jZ<}nJYMW*=ZNzrB?H=1a z+kD#s+r74hwuf!YZ7XamZL4gnZEJ1oY#VJ)+g`G5x4mZDYujhrZ#!sv-}bTXu^?6vH*?RD%|+3VWt*&Em!+8f)O*kkOm z_BeYRds};Fdl!3>J=vaOA8XIHUu$>S$Jul2xpudGygkpJZ}-?s?UU@2?NjV!_M7du z*l)GpX20Ejmwm2%fqjX6slD7@VXw3=vp;5EYk$%Hl6|}VW&11k9rm5}UG`V)ui0O> z@3!x?e`-HuKWzWZe#HK{{R{h-_7nD#_V4UJIb?_7usLcvu5#3M)N?d+G;y?Wv~bT8u zyJME)PRBit3P+`5nd4!{a>okCO2<0KddD-4Eskd$TOH3iUUBSj>~y^Dc*pU9y6bGCDibAj_- z=R)UF=L+Xq=LY9S=hMzD&gY#kId?dBI(IpDJNG&dIzM$Db$;VK>HNWY#`$X$j;b3~ zFRFgj)lm(i8b&pWijHa=)g-EERI{j7QEj5SM0Jh2CMqQ=HEKZAz^Fk{gQJE&RAE$6lsBq4YD!dD)QwR$Mco{AOVq7VcSX&Onjf_w>Vc?bQ7fY!iCP!6G3x24 zEm7N|UX0oiwKr;C)LT&>Mtv0Zan#|cFQUH6YFt!WP_U2D7%QVQ2IF9A49m!jo!~C> zjfB4;J8Nj;oC256SHajAyNOMVoG96`=s~|?Gq9^#>c0&371@lX~}e1Yv{~X zOkJiPQ=hq-X}~mO8ZpsKW2OnylxfB^XIhxNDVU-unX;*vs%bGb(`xFbVcJZ)>7b9d zVp=mXOe_<}#4`!-Y0I=@+QaXTOedzZ=`>prZmn5i`pt=idz^l4Alws#+iq46Za?AP zHE%L|W*fBzyK|roskt7%w;lNf z8EnUewaqqaUfjG4SD`!5Fg?><0PS$+R@EfFpUdY@_7)ZwxZ(0ZYSjDuP;#)Vl3YHp z-D%%Jg9p2dy(J($&LpVygkrC!$nOi>17kjSZ$L`>GDBB0{h0nt1~Y&e$P8izGnvc~ zCd-U6YngS-x@LW|f!WAxY&JEUn=SV-!$Gn~Fe8~!%xEgxWd2vr7v!>Yl1t*;|=~JZm7pSIWDtw zoG+)uGtPbPU-WvcZ?b2+e=n2GT+6taaU+93DuS*W9{i`PvD} zGdi;ZRcMxN!>6XiOv&-)x?>8xxupT*W>TzWr6+q!+&w_H@=9HK?ry_rn%GQlDX?fV z{Ig%^Mr*s6ICjLLAa-qJyNFv9vhIgklt}VIo}n)LW{pU zbtRX$LDBKWh5k}aAlX%t8-#yw>bi%S2U9228Okb{dzhTC+O~jsfa$WFxtCeUEMo3s z?q?R8t<4xS){Hab&4lI5gUmzB5@sn=&QzFf%tUjDxssp^f<{m+t6315pgs2W_+u|r zwqgg;HG$x@Y@=f^W#GGQSfMH{rkcXV&s~rPIQ&v&gh`>uU*avG8my-%FWFmMmYh#j zBVTyp&o;VTDwl!oJeRN3m*Fi+0|g?p3^bdo~W=FGACG!lkg?ZNOY<4kw(7~(^t;`$j*q3N0FN&Qj>LpC&zp!WA7GjyrhGWhS8nVl8PE6fhF ztJ&S`7QFT z>|APgg8`d5HNJI&n1nWMr?+k}wN0B&9a}d@Xxpa!^y$HD_A~E-a$S{CiU(9zZxKun zmCSzT0FyI1BlFy~a2FnAKA>avzL`|cd}yXzIA(_eW0st4B>u%Qi=9GexneLi!sQ)d zj?y9focV(J(o8ke%wCnuG3G1gYqPgG*vzCu);b`3VLSyTGpxFYWxt;{Ct#g`9Z+5J zfhF!q9&f2{NPy{rStL_aG23WbP43yjYv-p9cKvtE&~oN`Gu>?Y7IT{Uk@*Q!_A|^` z=4a-Y5x#&mL019&oazj=oD9&a-v#;659CSH4FFNs+7LSbo?XF&-UPK6S zOqU9T5o`80Gb#{|1ap8n(Cj%h*w&%JrequT$d(PERzg5xkcO;a4_?qA7k6+a(viXB z{82Ixyp*9sE`GS$^22R#AScsh=~60j0V^NXM72Q_Q7tp89Mv(0T_B3+>VPN?%{GRH z)hl04VGPVqlo4a{f>tD0N!i&{T>`?)0m8gkBMH~98j~qpiAJai?b&G5*c@(-s6b6o zGjpW5g36^M-wPa?8|>jKyR{wALyEh=?~09N>R{5?+!EJ#YGxLC{QccNALvct(psZf z+T<8>R5^+>N7GVl7vxX%(s1Ios0&PLs2ysLI-riI6Y6Y^F~^$O=C!8F9Jd^GMc1Hi zOf2ewdYU=r60;l}3d_vpG}D^yfXg7@7Dy^PXYgkmS9_|gf8T)dsZ;X7!1w#oi)g_? zi?>ct(4pbMo9CVeG)22FzBtU|&rkD|_`p#2fjI{%Shi8OY{2;OKDYmON^s_Q3kqDt zU~Qk5cevH*s2@|K0`)BibG&&Ab@0T)s5gjdK;=2^JdHhQGy38NyTNBs zbiM@%6We)@T%_|?S<3W!*v1G-W+oa+>o5dmnR#Y@1saBin;!FKS_d6~?{}Z$RS*+! zQn-s~c)+>Vgc~ykxtSU(&{&j>u0<|14&|U+^Ez{aSzs2LMW)v*UctnpJotFvGXY#f z6U`F%l)}dZ9}pDS@Z7u`5-(rAcQUmglD!a!0Kx^nl*lw;vVswhya^ek7fqthodP!u zYGe@wt}<__KQ-JiNK?1kToOzD`QDOhZ_|k&&0CNQ(5$Y4lfks>=K&K#3NSC449ttB zn7+`Iil#C{mx1>z@E^Fzg8#KNm~hYDh;C+Tl%t!>N#*Dkb29Cz24KjS<&}6#i*i90 z!8hjXcVRQa&(1=3GBqmE9cVV1V@@&4%{Jz zA9sm_L%d}v9v^*>`m#W`1J4&IAQ4aa0F&du$eirS_2=(J3mF|PLifS+9a~!J$sJeb zcl!ny#*A%O4Zhx)cHbRee%ZNW4NrS>T9DKiqX&k9>n1Bbr2;Jm9RfWB&o7C5{^Ktm zT&|r>TsY^~X(YRT`wDYfbkE$S4E2S!#)c=qe(s_?f4)uKAZHsXfypHnI5ODE3&<@*D6t_;^;|#1gzkh$He7+n z(G#=+8_-7cR`a$B^d!LW_P+wdE$Af*!)MV}^c;E~y@0l%7tLAb9p-Fvj(MkfmpOL@ z+74dYc(emPy8woF0{|zQ^WpPA5Qdk8SR{ZVG5Q}4!ypRZrYL;JyeEvp1As#G9ur4D z<~%?l{j@Z=@Cbc^4p9_-YAz^8hs}HcpHTP(`ii3POLP<+GZ&hR%=;?Q*XSES;r-^~ zE04lcfTABFQPih--{{=!eZ2EK<{VtIaz`ydAp$KCorz4ku_Ap7cWcW2S;G(YExW64 zia9OZZNFe9h^*fLSq}oTFa~5jWX`x4QweJWCm31sqDgxR7}P zt0&k}m3R;QGR(>Vys;fSfG09wnWX~TL$(HvqG@ZG51TEcd*<{Ekpa!54wZyHFa@_9 z7^*eC8iT6zFm8Yw;zl?cH#S$9Ys^Q?$INvP;%PLpwZ#D zfJV1E+s1AQt8`T!v#fM#dS|7lgUi2UJS^Y*dB0hp{V~*D=@tiOR)HsECQwp1E@# zvbbQQs$6<;y#o#^A6&0$W^8`QMN^gPKg@siujB78dQAU+;rI(V!OwI1;7$RQKME*+ z`FBxHxe8VsVVSBJl&Jr0s9)IDfARizRv|)|`q$Ba!P?CKoueOj3xIoVwlO`7?Ocx! zyln2maRp`Ii~-v?XF_&hE(27T7Ukq;g8u_7~5RTwq4tf@#phRQlLufVIA&7xK34C zMQ9!F&l3z?xBGVu?yoEm{tL~RE3pO_a980}Jdo+K8mHl2xHnG6eQ;mg5BJ9zc!0UV z+-N>wK50H>K5cF?H=ECxTUO&iOlNBB;w(HA4}-rWz~Frr%v@^nZZqF7--N$=;5RrD zFKPBx?-T0pDe@G$imP)g{Zm$P^f^~T*hiK_-7NwCXRJ5ii>$Uj=cOtDXVgFF<_g+z zdDPs>H@AlDYdit$Yg~W};o~)*GoOdg3t(R#fZ){Vu-R3Lr+~4DC*jHFi{?uexC~!! zZZ~&QTN{GFz!4p6@(u=!a9{t$m;9x=bXe4ssy zKc@wJ2B7_%g7yml?HAR6*3Q%}9TBe8H~1ul>bLkfK4Bg;kC|Up;_vYH0M)O}Z>~I4 z&jS8_j>O;A{%IxCzf5;6bZe9?CXg;@L)k)n9{HC9s0~20=Q6{37FDxL$s^ zvhe^{Ho^QY1Xs2lz?E&!c7RVOf*68eb1Hmem}ZZ`?vFZQq3F&gf>5wM*q#J&1o0JY z5}QnrK#+XdP|Nma`_e+vF(F6<*s}eYX9$w2!L6-vmvGGnv#=Uj$!4-c*erq+f>eSm zmFzHfIJ%o4jUek4hc259c)T_ek2jrZ*K*jdp3mN;C#`>cLh5jUE}H{Mb0d?c_EPIs z?oLeF@)bY*qsLy~Z%#7~g?k{Moe%`0m`dB|( z%1&Y@vs2hI_Ih?IK@NhP1Vs^4gP@uO)gq`iL3IeailDly+36wh5_Tqy-e+%SprCqT z^j=L+D_8;n^tS#Nz5f7u=TY>|C#ZfHz6$}qk?X+WVSb1$r+8YzE+wb|K@BU|3bvA< zMg%qgQ)^L|RH4I#tYjad_*=!UX4eoDO;BTknpConvX4>xH6;)+a;4Xd*(U&0Pey`j zs`vSq6{(kFZkC15+meK8=h3+2qeG1*Z>^}A_ z_HFhZc0ce##yK=zd0_ z+c^x~?gaHA5LE)$?e{Ns{{igM;5qhtg1UsUdzwzYKe9i;=PW^83A!fm-3_$mkDi9z zmam3{ghLz$Lc(E=C8!5MJu5h#gNZkhpp?rt_i`#{g+eglH1idLl0XtUgGyp@ge2OT z_<2jib&KL^1NyldTulyUid2Hq2a&R)}8Yo1oU%FA!)P7q<249`E%ofeh1gH56);GcikgYajqLuoIhG0?u*u3TmZ~m zECqA_OLSrQiS}G42(RNhaDdPO1P!X-I&)nJ$|UH*ct5TO_2UvWFx$xdi?OE={}o;g z4}>}UTt&ICOJPc^-#`95k1>}LENSrH2vQefFVuByD4B#4X&78r2NalN=cwEexg zbb^KultsHNpt=mD-nH7l8|FGDd}km8ctO}OEXi|&0AEZT4ZsNZZWcE@BKMJ0riYt7 zgU^hKc*ey|p*tLFaO1cfE|+t2pu0u8eT=F90QRJJkt zuZmV6bnv462`O&B%TsWE@L<&jKW#_Yu1TIa`W1{I2*)a(EAGKy zaoJaJLljpLtb^-sz^b}lzHk@F`8Zw?ED%DK|A{?j+#|v4!6!WCG7RDG$Ecp)r1ilv zAz<<^i_N*1O$d7_@RpqW9Vs?X28;7#8|i<&iGk3X>QV4aF#idEqd7s5IB%n9zT54G zeNe7~$mTpBEUxhXey=9%+YZcLuygsJ+f&Ky3KlZ)vhN7x-U#Llal9k`svragYQW?o z*pe6+o>0tH^@8zMu)NZ2W60ks?>vq?KkWN_NF4|kH96ZDcDafg0s-IYMa8B5ND=%n zSQ>0^{|7cnSGzCn{I&+R?+`RK+sOJ`Z4C}1yeR$ENWx;~iUmnAAG#J<>f9_{^41?<0aqefP%Np(kcar;#`<^?+{lJ~( ze&l}Q&TwGCfX+LUpc@IgiJ+Sax`m)y3A&A-+Xd^IUxEfGkJyuK8B!s z2%1OG{7OEKkEaDKAn4vJZf)`%8J+JGX+jphbl;2quX`?;yYQn`ub!IN8mvveD?wkwBtuJ<@*9(e7-N1H+s*9Phu1M)HiS99h*|JX6olw|8va4v4%SWXi_T5~3 z^Sqa=1XI+$IK=?i&{G1NK_Kg^E-ZPVr>F?tSVFfsx+h2XxX{VQU(4rE(RA@(nt}Us zSp}cVy9s)jpylR_p~3CnqajoaA}$NzH7`Z}tOD3iSumskUK$YY!~(tuLizbZf>xIE zUV>JcGcI^!gsar=Erd;&IpHV#d?`}{HuQxf0r)BW)PQ?{zn;1W9=XKeg|i_19N=4i zCVwM;6Mr**3x6wjn!lZ&#oxitCg?GO))KUip!EbjPSAz`-)_2--~0Gr@0IaLX`ig-8Bzp6>18H}Ei?&l0q?f`5{KilFBR+J5=ibPErj>q`Dv zek%_dKTpsL1Z}J2U*NY5%elSuMzY*LAwchV>y2qP!WL+DA+7X*D- zAtVXO1RW*l>&vz}BJ>t$WCA8aA4(O+Kputulq$ZehALWzYc^P*kqJVkFhs~A=o^B* zCFppiFiZ$UCY&JX4+Nbi=tqKn3Mih! zL_SOKRVkil0u1@{e;q@H$9=kB28dCZ5g^91e@KkNEy8U;jKZx1{Zc(Kb`9r!r*LJUS#ssqja|H7Q3j~Xl7_mgK zOt3<*x<*(QR3e3y!YX04um*_nQ6NTa2@xaK3BHQpx&$`|X2dQ2WyXJi8K0rdxP@RX z%#6=bW_%vMMLz^v%})bgz>A6DQGZ3)MOkr&u#;eeU|WUos_+`Yc7khNHU(1HBfL!s zZm+OUfND4hb`l&_DZC@>2L%$>Ah_n0C%6xRwLXf}3YXWL_RStHb^DULle^TP(OIGd z_bDVj6q)pMzq3`Bjfu}Z{%Ptx4R0NF?QHz2qn!Ht#+KLO&-3O@(zavV)D z)|lX?|DAUER~u(H7}_;GB%`7vssWx970Q#i$sh8hXcOVhx8)*8akJ`qGB%udZLw~E zC&jBMPqw5yc@!pW7@XgUi4z-%F%VcIMvINbCSp^unb=%xA+{7-iLD8S|Hlv) z@dPIj+=k$`1h*r&{c15bNReV2u`Ts#iXA9Hb_f$>7lP9QE=}C)Uvj+s9If|(S zcMOrE*c-@^?IiYrPd|ucCAd@IyED+EY}mpAGDsW(0wN9;GYRfW@HG`;mN=B)ZUjTb z%b(aD@@Hb>#8F~45TrO-93ze;xI4i;2<}-aUMspNK_(KMbj1l$%x84b6Uln=3r)73 z>6%ja-p`I59dmlC0R$-)K+?j9D z1yCrKQWT~}pwOo7jSkWy6Ml(}I90qMh~eoJ!@V!@ba+s266b=hBi=0DBHk+ACf+X2 z;!caR#W~`gBE(1ZA-FHW{Rr+)a0bBx0=mvXf(H>inBdGc;@u%2FA(n)7mAAj%J)+! z4+%qgIKjCDy9tJ^U<8-^3+I0T&MPULR}q{QhVvr;XYo<-G5R4GAUZ7g4RB5}`i4jT z3GrzP=O;x7f*C>Z$O>_jxS8Nl1dqLJR-pKtxGgBoFHmtFO$G8LD$Zjf#o2G+LvV5R`i>rwGD(z_09Q&fN`?nN|H0eBnicb z^qo2X66ED4NU04Fqy)OB86rrj0}$lz?g5axNj*U@r0x=^9y1BPu|i6ek_f(u;9D;n zF-pCpJ^^Bs(kU_C4ALjjFis5bCA|2ZP3)Mk01lF}fEcC0Ql>P7;M)kko#0uO(oks_ zCB{1lo_)oMQ5wtWQg$TUt;~3Lru_DR-gj?0Hu;_GX14<|O5-4DPGr)%KYsiD*_D0v zEZl8v{Kk{td{(6#N#i9?5VH9cvUgsh)51OGm8ODvBNa;%r4q>}`K3~6k~CSGB9%!1 z(YXXezuiOdJc8#Fynx_)30_F>B7*ND`2IE0v=DAhv8@!?y(7`xJ9u#zxeo$z30@U6 zR-X9Z1Mh!T{Dm~1;v5F?fiTV&T@vR@qza1jrBXS;4-veiLaLOO5xkVZmg~#47hYN= z!Cs#VX*G3tl!L=VdXzdmDynmMG}#)K+6~fE6z3bIC!{9{hB`e=@bXIOX=xM1`3izp zUU{5958!E_u=asCn{-5!~=RoByNZf(`)>g9(Me0yw% zVT(Yx{X3*LK<|-uO1q?2rPrj_rQHOBLbHb8M+knDV9;vUE|=b9;-$T)8J{J+P4GIZ z_pCQp1T>!wG#37{$6s7(sSiT$FA;n3N6U!OJwCm0WtSUQhJDu3N7APtHM~oLr8dxe z9{)qVNBTlKO7)&E3Eo((-V^THZzb5V4e#KTPEZPcl2YiSbl$0mn0LZY{3x?j>-kAK zBb}9gmVS|bm41^M8Oh)$c$(l%1cTK8G7a9=X9?a)@N)z|Pw)$?WiH5`vJ}*MWDDia zZDHg4^M8*xuY4SZOkcPtUq$eXAvTojUy2RoCUSES47sTcM#Of4U#^f_$Sny5 z<>d9t=G~Fw8E=01DN4+T$E5u2PM_kvEwL{6hx z-)=ykoKDgAMg;n7;`R^#x2$Wyj)0;8+tnk z!4S3qQzop=env@`zKGy|?8QF+RcensjRGC)%TlVET$9J_pgpC>P*fS)ffkU_ORLh$DVe^DtflJBE{ zhuP}rl?VJ%Kyi5_iqqTmY;!QJ@2Q0g+Lo}j&fY))zYLN-9GP@j;nHT)J0#Y8;ACo- zA&stgoCEwyc})=Tt0~~WqSy^gw-9J?v6*M@6Nc~O@+MG!4Fx zPVfnWPZInc!QTg>0OT$5vs3{JhM(e71fLFQK>vvP^G8a|r9(_Fr67gdy+fv3yLp$q zE1>oK@P}HDyhoF9^MY0}MNNYMYvr)-EZgb6P5#@|fH%Ato`tLt0FSgrvl_sU6xTrNy@! z8a(}IXfWe&6F!j-2f6wX{A}zcTR(16<9jAuWrw(qIF&4q=-B zSF=t3_qh7XYg&pG2w2exYYAyuiX8}8aiI6;hp?JCFYpDs)KTrwuq$_G!K{T(elE4PZ)%Q{t5b z!bTCc24QPfDs7c^K-p|9!q&dxl&!!v0HvC30FRU^HN_KYFKQUeNmbI6UP^Bzov;8Q7^ixKtxs4O zr3L}^Rr)I#=Ys#)hJ=m&ZwxXBkNXH^bbx)8QIvhzMt{h@$~Yw#Y)&PIu#Ky=IgNec zysuLV1GK0V04=i3E+L5FCw$5bphd;6lq!>y$;uR^OdhLDRi-J^l^Y1#g0L+K+lsKQ z2^&M$SgOLZafFR0EXZt|HHsOeMdc>tX5|*;R-nb(DJ`}Q(_%*g?_y$82s?<<;^2R2 z@$$Rf6?oH5xw43`?ZULUn9||{xKMdOSwh(M=JW7H*bbnU<{S0G1HVjJL5cBUWjTTO zYq6axl$FXV!ge8Sx64P2k16Ye#JG+UV^=DV8z?be6G@D<-w4<2X=Mu~#!bp*`D5s#Jf_{2|GFqLodj3``gFT0QmBhUnr|)UP6jPPpF(~0IRCJ zDyX6=sj{l5s%lX+)vAILl112|gdIlM;e;JQ*pY-CMcC1V9Yff$gw0-~+JdaAMhUCb znrba3UWH8nguOP*s<{DW6A0C$tV;g(SoOckF`%{p0#;$3bcG05jR68yW5qsdteQYr za0LOujw5UiFmN{`Dl8-&)XpGQYDX3Bx(PeJLhYhV9iR>*Yyn{l30qXD4puWM9eW8| z9Mn_)-w)LK(`R-4(aBrtNJdvjMbhyj{Wf*@X>0P#RU1D!)ql{LWkAO&tedLUteYPC zvJRU*x$ox3r*6Y%hm&(>{;1*dr>JyOs9MIm2wMh3T*13}czw`v z*q(aP4%6@xM1`Z>D%F|ljp|JVUf9S^Bkc4_^_GB_fW6_L^b&-taF;qaxV6>L!k6Z& z;2Hz=R_~?kJ@Zls2tV?mx)PRR)Q8k1>Qc2_txzk~W$MG~aur4tT6QyGZz1fhguRWh zw-a_2VecU9Y{Jf2t*#0&_oKn37>wrO$)mkR^^||BP4yN?^86-Ut zne@XM4Now1=|N8y>g934&v6LiES-94VAapDRNhZkqb-WpmskM2tZ+9`WL*H-;A|1 z0PtEG5_WY6yq3n70`^TEea)?D|Se7fV+P-p2{M;fm`%mLx{EBu650-NcPkKA6|%H?ru_v9-K}*?`7m84DVd*WwCkOk1hOG=s3u zUjdEj_w}Jaej!M>-Pc*D_le!CR6$HTS_gUM!rDUZG?T1YE19S zFj;`c^b06WRGcH%Rn9k6FR*LFwJ|L>1~}9*lXB?xOO0Llk=rc`fJ7~`EO%IDTjp5q zwA=+Gdbi~s%RCEATp$5E2)mQ8y9oO#VPVn)v-Net?j|hEns2VL+#4d%`z?zt4+tHB zM3+z!r6?P26&hML&=0&MfUx_5 z-(ZWj3Xl6H3wYcrESoI=&bJBsPKD)J%T~gI2)=jOEK$pgmX~QEFF}MJ`z}Q2Szb}W zFMI&#B$7+&EDBfcb;}-#klmIyEN>F_AYtDp><5*Wy_S8Hfj=bdM^~PKVdH_NnvDnh zR*v~?|J(hPnVTkk+}=@U}P~MLfFrPr22J$RF8*9^@|Xx9{n#R)t@Xs zQ?WTi&CoCZj2Wt7O#qS6SdG(o!X6{+SA_lgZq^+4 zLsY7D2P)Ni;6k<&6GzxzU|j`aun1Zj;nij>O-l#y(0Xa$o&Sw+Ooi4*>q|I9IPS6$ zsWwo{ghDXU27^+@VK9!gEU>6JHbMk#%4cCI9I1_^pcti%*2WNyC-9nfPOQ|jwQGS# zIf-!c6*oh*JVw{@Bh}OOj!DH)xA$y*=i0twZaliACh({>0g@I(CY|!^$!qe)^i#Hc zx2aLT6jh)++VTP()rvK`@e?iAN&vx}05Df81YizgMuXlUuGzo% zz5J?>2Fsx3+5?2E9memH0DiS{t%p_)_$6GO;5Q)H86NBv+G>j6mD(!8)g@fL3T=({ z2;u4zuJL6vE4B3+yhE*0dtBR~Z6w^)glj;!hLzfr+EWyajR+Tg<-xcW5cXUo!bZ<+ zvF60MUZq>QZ+rht<};}jjN2gTi;+ohdN)HzSlv69Jk~ZhwYIjS%B<90)^^fPeg#xP zt_i4u+Ai3v!8NUJvj(>zJTh;BM>hc6y%f03DR6gD+G`p?d*LSzXrF;OqrImc)ZW)V z&_2{Y;!bOyXrF3_w8MmJNw`*oYfZQq!o?CUj)r`3@q|ktTpPl*U85Zdq4%hEO#4dv z8YbXxDSq39@!NrLNrX!#+yFWU5BwLy{{V)6p%?~Dr+o;+R&*(+kX5qM_jXuit3u%5 z3a(Ry)nbJM24K{BTsHJt?baHAUaQ0Ev;xz2AzW9&T~leTX{|-k+l_GDuQ+FVS(InxdcO6TurssGwU4c@La()% zwIy^iCRR98h;Tgth}PB=h=~zEv^AX_-LugJ^RKmywKLc;*0$Dm*7nv8){fRrgi9e@ zD&f)y*Nbqy375Xy+J%X?Uc+ZuyTe{IIIp=33p>@zy+RzSYB>wob4XSPQL1go7f75H5>wLkTyGaKi%}If8H_2{(#x zqt{rAgB)q~voo!esNdXLMmcg!m?N|4i?g{20lzsn`Cp2>{1j=u6)4hr8{x)=De{g> zQsh0>1(YJ^S?3e(TEe+1toK?M5^fyf@-H7nK44u+De^(5eB(_H1Sj=rpJJ zt3|b@v^f_uU|nzB7^KJzlp;M8hfh+9j10Q4*|vnC_>6TMWyUSmXRTYU&sm?hzCgGF z!W9w@kmw~`G2tdIx4sA%+irb15D?3iP-gTIuJpe#AU3+kiPuNJ{rc#4!X2>J3cCy_ zGrkpIM*koB&#ecoa9VG<^?kxks+JkUIe%*XEXa$8DKAdB#CU|CIA(?I0;{cGS--Y^ zWBt~8+4dw1a5D&J5)Sg6Nw^zVTSGeqtY?GgP+EVZ zgm_b!5N`oO46@-p|FYrbXG2{BHq^l?zd6K)y6sYIsMpf30>RL0>vafsE8%Xd(Cg~; z2zNW-W?wdkjowIaLJNte=FTiIcl4&z+_|F~bI0fxl0Ut*9uEwv$LO(o9O32=I9-do zt5Q$U+fW9bOSrqQID_h)8C~xZNsI43)!mr3u6O;l-`6QS^=R+@z@U0JNZLIzX~(Q1 zyYZcUu6l0X&ue#2STV9n$Z|Dm5SRXwL5Ucmq`|17l z41It;P#>fZ)-!d`U=|SWUc$jNw}^1}5$=A%EhZee1|B5bL#y?nK_x~X8APl;mLhgZ z7_sG5h<)^5#Qp<_Eue^nNe-e80}+UN@g)&ES-+lwX^LJ(xC+8mR_If8pyFkOTXFdi zOZ1zd5KQzN>HPgLmA+f3^uehN7jGxTNnruJL%)kccD6o82e7Ur9Jr8HSL$>1yD4PX z5blvH57|Y4!}}s}D7i}dGU?s5d@;THB~Ray`1SH1 z?DZF&gX~hhG6>lU3fadl(P`lxTcyLU&2k;=x^?9`c-hvQGseJ4G#Rc!cc#At&M+D> z*)_o(lnPkKENAQ{TXl${{)GM%(d!DcgDJa(%XvU4NNyn+Ug+aNDT#)Q8dsmlg%iz?$M8?9Oo)`F)u=`R+ouudf?U zhiYG4f_^TaKg;LNg(uHDDkP~a_+a3^!>v!GGqOoLU(lHD=iybb>=Lv+?KseHgm0h zK!0y&MrMl3@2=1fFgd{|-q-ijl-rN~T6r8&h70{j|MbE_59#10dya4~(4N)x&-E|# zFGoO8zQEWJ?)hw^YkYjCc8MK3rp2VC#V5wJOYD>!)45YZd`v?7wjGn(rL}DvpVBVd zQ=IQDa{D}mr3Eg(wvs9WK0wI(naKZUyXSn8Qy&g(lI8-dU?!(wQL)zA&Yu$eaz zj=stRRDTePy@cCGxVH%RHsRheXN>gtQVTqJ9_Y$!!x=n5CMB>ZcOdlrcy9?Dj#K0O z%jrIl_M8&8AJSiRV;IO-f!ha%+8DtnGE@2vb(MJF9GZ*r?gyvR_&wetcpFSGW#W0e zen(V2Ty;BGqcm5crvN||b$)&52|ESJfrEJTi{-|MywW{)l0UdLIOd|%UH*({hISWc z8;*;fPUsZdeyC?4mD`cQKM5UMCj_X-Xu|AVYKFTA>lqE+{aYTY5*G~=J-96JpQu5?qY9=e+WH6E!(ISabu{v z#24t;$Xf%7X_v$3#78_u&(|w()7zP)g@tg0R}e;-?z}?EXjw_6o`T#V2_4cp7}o{c z)Roy;X?#Sch0)^Dse@$-C#xwQ6xV>(*=1v~^roWAPUtY`P%IlcCDFNxz6OP}ie{}Fion}IhM&8@3 zd5e}KgOw|S2Zsm$>82UcG!-pcLEZxb-2iE0Vxa{o9uRSF5lCM}Oe?q;p8)tjuVJ~t zfvafKs@m&}#MqcROk<`6(}wBDq%-}PK};qymdRx%Fn(q#a~m^@na$kEEMk^0E11Wb zjm(qG)68aO3-coL8ncgipE<;Q#eB=0V7@~ZWJ7gP6Vw{Tp-!k9>Vx{D!6*-17i>O8 z!M{w~(BIG>1h)N`fqBXpYh;h9nx$YubydQpYndGA0QxI5uNdPDx?2RGl54n)6eG{b z4*=#E;l2XQ5bkTjeY4!S&X`~n7=`dXfpFgv4(7EJggY7d$8n0JMwb@(A!WtD7Jrb4 z&idI#vrFeh6J`3#DEa(B$|0a&1X4!#l!D!3pnyJMObJYSEgqTv$#}55x4>w&iEqrv@&6gEsM9+Q*0cXPR*{(`BVG-MGP+VVDLnW*RpdFrj@X9$l7j|tBbo+CU@cmcM(7!MoEjTOd9W0kQQM(q(88(t**RKiaq zyh(UM_#0vL_*>|B8PF_xCSL}ejhz=Hd3vepXJUyPy59zuvixucrQhTB4fEvs^Mg;O z7x{{TZoMVvl2tt!NH&_D^_SuvSDKecJJ`|RUFa<->s8_^&OdiGT!*R>sOb?r4v^*> z7TBi^@XD?-HW{0ZXN)bzv&L5AIpcZb1;R^&mkF;BUM0MR@EYN*gx3iVJ@BIOlCj-* z*?7g+VeB+^8LtxFM)#TtP=0=I$C57{k(a;@ObPu-lyu; zyT$?IJ>wwZ?Syv_-bwhVWqg+Lq45!YP0wlq=Y#S!saG6&*O}%i@ViR_2bd<6Q3W$# zli8@fl*2cegwRLr!Y|MF+R}fbAbEO;fil894rYWG>{4cjBr~p3Y&ghG3ULd zODkkcg`!ry_dfdh#zD%j(5%rtCkFo=-E#pK_?KjB9D7aQAz4F5jCL1Iygqmrg{M?K z_`B-+#^8MVy>SW@#?&draMn3(4E}!=w9? z@hcU`GsaotXX6*b*CTv=!e34J1|X0&#)d)y*^tl!X#W!g(x%ufAdoiTt>|(a@KzwS z=~4n|vl+*2jz1R2CIf89eUU^))%m*;IX1m~nW!0#y^^e0h7`N}`6GaE+*5jciu~p3 zaOxw9@pyd(vlm%)%m3Hjdq7o{Y-^(g*ERz?i69_Bz>FeUayBEGEkVL2=M0h-K@dq2 z1VoT5L4tr}Y!Ji%0szdF6kK%T$m+em3 z1xnL1q;1FSRzu*e108kh9+p%l=HIM{y{vy(5z*1)d5&P$eH2G2L@CZts8VPF)M`j! zMPWnXO5sl74KQmg#chCE9{{vkPw|-IIYkRaC&g=ucL1{vQhWi3b%|Wf1}K|62)LjY$Zq;8SB@P9 zc;%SqVb&|Wg1m=WkDoX$=;^s$FE5(!&wBY`=-9@swrC+Vh%_PB@^5v|dUaxGSpeVB z;%Eu9Bw7kBjh2C-6EMUFL!fQ}7!rgbp-cb(DuHsZpsS;MNK*O$1^}%N@Bkfv0Z6Oa zey{6D3iarkKIGph^N$*xTpm%7U^HcHY)Pt`bK|+6^eDM3_+(Coj!yRAgYNrR<^BW~ z|1dP<>JY{IkD8lY1kwHLqo;xfE|?UwDhz=?)nVu)G8PPWPDFb*C1A{30g}lcp_|sA z@A_i|v@WpK(U;KLXdM_5g&{E*5>G?xp)aHLVMqdoBws&q)N26A|SS|k&2;>Es;Pn+kZ}fy*t0&rv%w%tLl~n6b&_8f_y+`@ID0hU$C}x zJ7o<<3RqpFsSW;)kc#vmpR_zw?GX_U(nvBKd|P^1X@w1tg-jukM}};O-de8{FzVKz zK51}EwuQqlf{Rqr5pYWgJqBKl=m?VdS)Yh;=p+h}40JsD7CHfa8=VM)3&|lR7`g~U z$}psofd>28K;Kf)X)uIby#sot0YgNjXUK;lwfrZ6s7J@So-Snxj0z(+q@~vKHumR< zE=u}N0H2XMs7H4klvC7qCX(m1rKQ_?Ju*saqw7!jd+VR z0*3TR@6=Q^MJ5~T@wHq^6q4(sM9N%$qL2K9!CEVKiy9#YGphr6im(Dr&WcO|ajf?b z@;~Hee?|}M(IMya{4|Vz_TgtUB^5n_bm6~TUR%&uU;h}dkdXmV{}^B+f6@Lz$M`)x z>DI3>LVrQeBJgJtJ%ye|&%lrw44K1_1q@lHZ?{3uqZhz&EMQA9WCcUkYe%vC4_kxi z9~k8391NJ7HYpguqS*dBYY>B?o5BFI?%!F1b{Ei_y8Z^feXst11K&>{L_zNg==e6% zVex=--pj_xedx$>UOoX4Q3)wodBsy_&MGOZscRCnb@dI1CT8ZA*0y#IPA+a&Jbe(j zPWv~wo&h!#@1!BQbqRop1kjuU= zbvp-vL=w6nWE&k7D8jW~!NE>YWdA`>!2vadEOMaRgw${t(4Skj9z|Ngb4&~Hha_Ic zfow03UIDUC98TSiw1$7ZGR8@eDkuyp6C%jD0xgCpAz)sBGAGx|Fuew4#Ke&n(`^PB zlIt0)M?r@4Vem#~88v{-%&bAK+*&S5wFl%XAXW2_lEJUjq%qpL{`1@gka=DW83hMA zaHj+M;(E>dkv^*ILuyu4yWnC?v|oQl1F7Qt0q|36z3_oDQ25eeqzQZo2ufxMC#`DwNOO7^cH z-GQJ31IUNT`MJ+^_oeuO68?utj|KqKaib5&ARcvaF*9~d4Gc~Vy7n8( z@H&Wox0WOsY#fr2_sAyP&z9kJiU^7rU1ErQmRoBD0L}~D2*vCD6J^%DP1T*h&E*i zab6fm9(>H>hq>B~WEh z%W};@N=B7SI%}*^t zElsUJtwgO%twF6r?Lh5J?MCfOeVsatI+i><8y0UU`S<#t)X8fg4YM7C1|SWy1G5uD zgQ3L$lgj~yfTneVA!itJ$v}48VQ?5cW*6zy0mv1G++fHZ0ci*x0?TFtN0I|P$o47; zhmm+egpdDgDUzKd?MBMO64xzfBOthdnE?zMvLoiNPyEGP{Zh{ z?ZK5P0Pun7y}_K5`m`Z`PRW8!u>Dk02G~|6fHePW8FDj@tuLuV2|+S${RUr#sK2R*+7o#jgrG$1iKqB@)!k-BIXq4H0BKEEan{MJmvxh0Np?s z0yfMw7z&1=>o61oL!mGf21DU66ahmwaxuyjJQ!7s8b%$XfziZhVF;K@7;PAeL?BZk z4BdyJA{Z)$QLZq`2S#0kQNb`O1Zg)GOd(mKvA&a~BMG3B9Tf-3{0O4=Koo_8jWx-D z0g*%YYr{kKK9J2C+O=5<)C0-uM)+$c>)H=czZv4K1)ge0;9W;N{b%*vY@C28g(nw5 z-b~6~H>5ah$>r9w!RhSIAav;`avAso$TkPjp7bp8*#Hf&)*~gv2@c%D)_hmJDFp^E|heP1;!F%g|UXAC>V-{p%@stnU1l= z*wI;Fz#5N*ArP`T1w&v9kmgyUu_L)zh~>4>%8k(`kjDWTOD$zH6H`**_1C#$z@f+K zm@60$j3>qmhT>o-9)@ngP(nJGeLNIZU;^6#%XNJklY(A=!2n!*L>JP;Q`UDO6ITG1 z{hYhTuah_fFd#o=k{$=q9w15#=s{cHd;w#&>!%{5+7bF-y{*BR5M*6}`I(r40rN8n znO|r?Yj5LmDdPTvGjFHT0pjZeTK>09`dM9RQq|L$!d zmtz>V5IE@er_~$47vF#gb;xAn#T(BitpRxvCZa~QcR&GrqAuCqZhO`#R zleHBP2ADP&D*1Dsc3`>y$Asy`yu!T3yurN1yn~?!Fa%hIG8h6gp#p{~GcoTm-Ix#H z&t8gSFjNIY)i6pL`3uSge0Is71SOg*h{*1Hk_ZICnVhBwWEfCzAQ5myI^;A&TpT}f z=n}G|&X`#nk#s&YSd&hcM##!k0D_NJ zOPFQM3TBmp7V{nR151IW#8P3Yv74|E7Db_i1tubc(Hgt*lW~rGPoUq80hNNpH6Rmc zEr#>&VxJaFauEEm5x4_XxHZW|zs8pQy*&D-T;x5M)?1*ad=@;t{_9T|v4NXl=rIhn z!Vq9BfHQp=hL(JQ->mH??g+aLyB)g&U5BLsCvHH`V5lC3nn|S2BOjpS{`7PI)L$}v zb94g@Y%C+v;9|k85ouT~7Kg>dPy-A-fuW}xWDXco282feO=|??%_UVN^p_0t>9%jM zDRdSHn?lk>Iva_9rC2DwQP5H>V!5!~6a*Loyit=6SP3%77ZBm$;Xzcs1CKGFcnmGg zYj4CXPA$m@@;vuUZ=BM9H}yDY#&V|lR0 zu*V6A2Mvq~AQWM!1%_Ve(TV)0O*-ldT+;wE*nsdszz<^iu>6-mbJp3qG^_wtkizh< zNx<8q1Xdc+2x0T&fC~Un-&k8G14}bQ^7tMh8_*z1XM?Fj9313@x!%vCN<Q{M z%%f!YI>2mzw)-^`NRV@8)&Qp2g5~(zY$Whi#sYIQiyZ5(cP648l6orI<_Fqa^ zlJMWgdIM!RekntC`;)}sQ5$1p2O?NY|ErGN#$E=y0kFV1)U&o}1ZxCn+TY%Ju!f_s z7FcVrI{|Bn1ytZi80t&K+F)&As2_$tAp{(wEYT9EVAB2;vclRJLV)5x?6jK+h=#ES zK-mF+Zil}WS$~NW)|Iqx1nUC!jX(py6#J+94%VOW!ukTNg!RVyU||>;M}Mibnie^w-M{*83lYy#+KrHX0j)y@`#* z#$n@OXbgsc3Y~zVFEBI-LsO(<&9I5c4F}j{5WI^xmZpJA8wvB7Md0xNqAN((`<;!w z2WASSkIhB)x}x{x7Z4BN+fbtB=q%fcO3lf z!mVFUk^C>-!L{D#S}fQ{1I|vuJ_0*@pl|cl?BHi1Aa06fV{ z>@O%N72Axctl#GS3VB)pA*D~#F!L!kT1FpA#?MA`ifM7+Vi z-2f4&Z7}rxFCc;p33@2hGqJtckJvtJKXw5735I^aC`uSb4Wl3!1>UmtPlV8dXn*9r zh$#x(I~X7wtjRDAIe`pe1lKSDcAVs5L4iZUK*_)G-Rt?&lwC+wo500Ykj|g<=z8`7 z_A8Q&f>E16KAF7Uyn#3Viy#EIi3CDW+t)yd(f?Zzf*7wn8}uj7pX@!)Zw7#3Cj|`! zEp96g50o-)8*V#p2W}^h21kpd!=Z5)92SRzQ9EH24UD3NQFJg04WlqH3Jaq^Ivz&t zf>HFjxLstWjAMi@;+T*NGI4u>Qbw(xpoL;YBKc9A$J zg3L9Ef)mDx0*QhX!JULrdtek(DozY14x^Z16bGV}|E=Qvmx_D+B{Db#AUSceI60g= zjADUNdtnr78cq>+3g}oA8;oNAAJ?%sC9qm9{;D{Cb2%nX6%MsdL?ZWy&6Mje1r2VvA9 zl2*o9AX*t`P1ee&!(^?DI{Lp;E8|>n$mU{5ABS9c0i%xmTdj=q!GWE^X*d|?i}Qm~ zVDcY>QOAK+#(^`O5v_~@_b>maHxK=1S{WCHyFt>*xCo$?QG7rv|I^*4ss=VjZolYM zTpX5)f`CiFLby1Jv$#7jN(AUs5IlhrB&k#pA0UvWezMDPDY(=>RjLGx68gJJ#br^b zXW+7NIk;ThJzO4)0&*LyaZwm02BX9`v?(r*tW8DMwdwC1Z0q{)Cv~}=__LDykG11t zvUZeQ(~gAyL)vjePa;~A3<~~J!E+C%K5jS821YIngp9RJ~50s2czWHVAHSPxEuH3&u@GdMgcQ=gL@%2ZUFhlpKyb? zA>3!&FpN@wQHn6?6pT6zqt5)(H(vj6|LtFMO_<@S@w5Ph;5XqRJPN-VzXiV)zYV_~ zzXQJ$58%gn7et!V^`UE+F z7XShj&xhxSQQ9y{ClxP<7lKi`FzWLEF=_xWhL;2{p@Q)efEqyQ0V%!Xi4Qo>`5zCC z#>?YR1J#08z$@axlG2A!1~AGn4SxoI7J)5BFpBs;4qNal6tsBNU$Mxq=b5+TH9%3# zUyJ^FO8WX|xr8?WAOx?C*TL)J_3)SRUbu5(vQ)@y35%e~7Yz zQ8pwT^4|hN{{7Wj|N3gKe?Dn&z2A0tM-m9ZJCHz#^}huncz3)PGE=VLJ@B3|$`(f1 z!6l*4~3HGmJoUnhYOd@uq+oc_i1CK1N?8~8|a(Ckkt3>Yhh7OD6s zgb+ady1!;3n+DdLGkWCQpMVMeCO-C0rR5Ey-2Se#@QFZa;gj%p@X7cTd@77`hf!Bx zln0CgL+ADX8>Ll){{y&v@eg4XoPw`~QNGAz{s*@&z5%#>@sIJ1FbZJMs~he#{4+eb z;OZB*FTRCB7~ck?koaX(fRDG<#z2E8CDp%ra`CV5?|xT77pR~cMg<}j1R)|4*~qaT zF@ShiIV5!?f2ybt56%`r_F{D42k}E-hnq7cjQT&N)40)Gq4A=DY5Zxf(p;knp$Vgjpvk3qO7n_l9vmMgORG+6 zNqdbpk+y`kh4v#I790$5f=-d{G~HRc^K?pd%5U5fP1UhZ7gWQ770c?bZ!6xVc zx_-Jbu+i-Y8Uh=%uxM5^J9;0Q3mt(@MBhQDpwlp0F}pCkF^m`{j2|WfxcQ@jU%wkO z0z8frm`ULAIETG}y@*x8CSh~2dDsH%eHlRlrm zn7)?&1$`_1OZpD_SM+b_-_Z}z57Up*kJEplpQfLqU)asMo3J~1_lMoz7!EK9FbFf8 zWDsYNWRPaKz;Ka4g+Yzs7QKQ&ULX7(vk2CTz@-d1r zN;Aqb$}=i5USw2dRAt0qiRt{Ev)-$Y{tR}2x ztQM?RtTwE6tPZSBtp2Q5S%X-ESwmRESR+^?S)*CYSzob!W!u9h!luRM%;v)8!{)~p zz!u0B!4}V!z?R5%hb@IIjV*(%i0uJe8CxY=HQPhBKDIC5Znm#%-`JMfsn|EMqu95w zZ(~2fPGrBz9?pK7y@35bdnJ1vdn0=*dpG+e`!xF!2Q|kQ4m<}V2NMSi2L}fy2RFw7 z4jvA14k-?4j%yq@ITAP$Iqq<5=KWG~smQyu#_p>CFjq25|;+hH!>)MsQYej&bea!gH~6@pB1s zNphXzy3A$3Wy9sj<;>;E<;msE1#|gvMRLV(C2^&2rEz6&J>qKOYT;_*YUg^x^^U8b zYlQ0y*H^A3t`)BD+?%=SxUt-LZhG$B+??FUxOutxxCOX{xJ9_-xD~ihai8Hn&wY_w zh5ItM0k;vi@gc55Cl2u+5KFLTDjIA!ebyLTo|@g-!_Z3keDd3!M}a6Ot5?7LpaZD5Nf=DMS#` z6Vewl6e0@w3S|ft36%*|2vrHy3Oy2P5NZ^9CDbMKS?G(?hih?$6`h_#5Fh=YieNTkSpkyj#LPwqJ> zb&`0}|76<9+LO;tHlJ)c*>>{X$^MgrCx=gto&0ig>g3GHxswZ`)S_ENw~NwLThc>LKbS8Y&tgnkbqsdRH_@G*7fdv`n;8v|99`=w~qo zF%dBtF(olWF`}5Y*cGubu?Vq9u{&bvVwqyuV)eR)ip_}4 zi!F*Ri+vZT6yGGyAkHMtBF-w#F3u^wU;Lo>VR0Vu5x-B}F7fCB-F8B;zG3CF>>IBnKo1CBH~6OVLQtNij>YOL0nZOC6TtkvcAQ zLP}anR_dG-K}t_bU&=_zOv*yaTFO?+TPj2ZY!u~ey4g;cfFA5xuC zZ=~Kyy_fnR^-*d-YDj8WYD{WEYEpWK^dadB(st4@(pA#E(%)s6Wkh6TWaMQ|$()f< zmC=#8EMq8REMq2PA!99LD`PL?E#of}C=)CbE)yveBNHoABJ)P(lgxiy&PL8o&P&cm&Q~r#?!DZw+^F2R z+@$%jZ@@4YX@_)!bl7AxqOukvZMgEO^ zmwdN;kNlVdqXM%6s{)4tm%;&s!wNhKybAmZLJB7p#1$kJWEA8S6ckP?oKsLzP*G4< z&{7CexULYUa6=(lAy(m*LZU*lLYhLRLbk#^g#v{lg$D}d3RMaZ73vfk6rLzNS7=sv zr|@3kgThBe3B|LD=M|L{RTT3Ts}yS#|4@8%iuaVnDXCL3r{qtiohm$4bgJZ3*=efN zw5QRhv8Q*Pc0TQQI^cBR>EP3Yr)N&jonAQo?Tp+RYU9v`*Y9Ey*~H$T-Uh| z=LOHpo|iwbc>c`!2j?H1Z#dt0{@De#3r8;;yTE&a|3c`6TNiF$NV<@6VOeR5(q1KY zB~GRNN{5t=DjiqiQxa4XQ4&*Gj zqPAa+Urj(wP)%4(UhRz9IW;9UH8l-2f||CPg_^5cxLTxIj9Q#pf?ASVidwqbU9}vw zJhei#Cu+~tn$=p=+SEGKUaP%R>sISg>r)$08&s!KXH%C`H&MT?eqa5S`kV$<4HXS_4J{3A4LuEg4MPp0hP{T1hP#HRhOb6|Mvz9ZMxMrVjW-%S8hsj{ zG(Ky5(U{hl(^$}0)MV3C(R9@G)C|^4)V!marTIYfspfOdH=5m=J(_)*Lz=^yW1171 zE1EyFwrJtC*tIyd_G=x|I;wSCi%&~ROIAx>>y*}6tqWQgwN$iBwF0%$wQ9Bc2^55_ zgk6L^1Qr4tfs1f}aF}qEaFU=%I72v3xJXbXs1pncM1noRh2Tc;AixAa!c{^LA(oI% zs3JTh)Dap8PYBNmF9>af4#I1~J3=>MmasrrBrFkD2tO`SUfOhN^QEnqc3h&lM0e@P zrL&i8FGXG|z0|Eup}kjIT>Fx?k+zApxwfUYleU*OtnIHIs2!{wq8+9kp`ECms-2;o zrJbi;s9mi6K)YRgUWZC&v(8qX9Xe#C4=}WOWpD&g)#%QPok` z(bR!;igh}5KIn|D|`5qnDyrs8^%csrN>&OYei;N4){PA-xg3alJ{s8NK<-J1)~+MqkEW z#$VojdCz5*%WRi9E^}SpfBE2Lh0Dg5gD>B^+;(|EpHW{}UsK;n-%B6X_t(FwAFdy# zpP-+ppRAv%pRS*&U#wrQU#0(0zh1vl|CxT1{uhJo2D=UR8n7F18tgaVG2k`eHxM)s zHZU-VHh5t0(4fhn$Ka#Eh{1y4R>SRvyA7EQSq<3@xeX5*9yUB`C}t>Wc*;=S(9qD> z(9F=%(8kc-(8FxoKN@TuXT(PkqKBPpZPMjA%iMtVjDMkYq) zMpi~PMjl4jj6#gUjUtU=jAD(_jWUgjjmnKGjcSY@88sL^F?we7)@aaZ$!L{GL8K<4 zh+By}h_plu5l`GrJVHE1eXWVVvYy8Rhv+=0$xCyPvVH05! zNfQ|pd6QEnN+v2M>L!{d1QS1#2PUsgdQHYnewb34ZZoAfJ!pE^RM=G9RMJ$&RMGUb z={eI2rn;v3rsk$DrXHqVrm*Q%(;(C9rlF>{O|wmFP3uh?O`n-Io3@&^o4zuAYx>@_ z$F$FM(RA5#)%1rMrP(I4&1T!ocAC+eVa#x5yUb3QDT5;k@|ESZ71rvwm57ys z)mf_xR?1cyRs<^@D?KYqD>o|-D{m`bs{pG&t7xm6R%upQRykIARz+4NR%KQdR!^;7 zS&dpvSWQ{YS}j<8vs$tGVNGQXS#Pmswq~_vx87&XWqrWvW7a3E`K<-5RjnPY zW34N!KiE*)aNEe+5N&*IuG@s!+^~tVxowkSbJr%@Cf6pZFOuf+Zx&$+gjP$+B(=e*}B*!+qT=z z+OF7bwPUhlvE#Pmvs17;Wv6a;$xg@avK`UR#LnE#((Z~~klh`-RJ#njEW2F0e7pO0 zC3aY!5M^xUvcnv2z3Z|xZx1x5aST*knWJ}aL=K@p~Rugq0*t+;hn>Z<5ou+ zN3akt|hM`p*pjz=AjJBmBXIVw7yaXjy+1`a&9G~EmUUKeKJ9$LS=m|5S;N`L+0NO~*~Qu2+0)tEIm9{MImtQMIn6oCImbEAxxo3M zbCdH&=K<#-=Mm>|=Sk-o=XvKv=Vj;bE?AdcF1uYAU6@?Uf7d|QYp#*539gB*cU)6k(_AxLi(JcGD_v_`AGtnu zed_w$b;50%8@(Hg8=KocH*UA1ZpYpD+yvZ&-1Oa|+)CVP+@8CAaO-s&cAIzK;=awD z-kr&v#huNa%YDE5A@?KhqV5vzXWcKltGKJXUvk%RzwB<{Zs+dh9^)S8p5UJ3p5mVF ze%C$6J}bBiafC&m-+x!ZHEC%Y%7C%5MTPi0Sk&kWCe&nnLr&o<9@oaJG}RM^LvYUi+M|W%Xuq$pYcBDP4G7Hw)VF3cJy}f_VR|k{k;RduX*40&h{?# z{^0$|d(3;$d)4~~IP-EdIQ4Re4~-AA&p{t4A6Xv-pVL0)z#euLA9WusA8j8!9|Iq7 zQ7Z6(`1ttx1o#B`T=xm{iSUW?iSdc`De>v>`3f_@Vz40`2xr2N;eL1w{sK?Kv+#;9 z)X%lClqVc+Ave7=Id!oKRhZoXH2ult7jM)=0~#`@m!z3rRp zo9|oY`^fjP?^E9<-*(?uzHfcIe7pT1KS4iDKYc%IKiJRDFT^k2@19@2UzOiezb3yH zzn6ZUesBD`{671Q`i=Wd`px*w`+fEM=1=2)#Q(IvrGJorrhl=2xqp@aL;rgJM*nC2 zP5y8F2mOcr$NazePy5dXPy|o~&<5ZFb_Fm5umrFMa0GA$@C8T(Xa-yg&<)TJFbXgU zFb}W_unlksa1L+_hzN)ZhzW=dh!40Oa3>%&AS2*zKu*BDfc$`_fYGZoSC3s)z3P57 z>1xf@?yKJdsRE(EErHttv4Kp1djr`5_XTnX9tb=XcqC9HP$Ez|P%iLv;JHAhK;=N2 zz{tQmf$4#nf!TrifrWv^fe!*30-pqS2EGsM3G55}6gU?6C2%@$HgG>TVCd?h$II5s#x_kB9%>b88|o119_ktD6Y3l4A6gpP8%7bfHEdVdfv`hi zd|^^ys$uG3hGDj04q?t=Zebo_-eJCB;bD|vn+c~2=M6s} zekuHNxM8?)xJ9^ixLvqIxKDU!cyxGd_^t57@bvJz;W^=X;RWH3!dt_;Bd8m7Mq(myk<5`? zk^3VLMjnnl8hI>IEK)jBE>bb_T%=N@N~Bt(Yh+AhYGiigy~u*dqR5KK>c~GL>mutT z$D>%HB%&0f)S^tI%%dEle4?VFVxm%`?nY%t-HW;(RUB0sRUY*u>Uq?gsP3qqsJ^J7 zsNtxwsEMeR=&jML(HzlS(FdXrNApDUM)OAtMW2iokCuwojJ_1D6Rj7mA8izE5^WxB z8EqYH7wr)36df6TKl)Yl*O)yqQZd9B|CqFx+L&iC%`vSpFJro524V(dKF5s2jKxgE zEXDk|Np%ytx$Wl8n{+oZH~DWW-_*NleADcv2tH_=KGr~u}~}~ zmNS++_E@Y~tWvCUtX`~9tZ}SataYqitYfTmY(Q*KY)ouwY({KWY;J6R?ETo1*t*z; z*v8mru}!fpu`gpgVu#~4$L))gj?<0vi3^R3jEjkji%X14j!TQnh%1WwBd#&-SzL2m zYuxL&cX8cuy>WeUbKqQmn)p5Otnuveobd3$c#u$;P?J!b@F?MBLT5r>!f?V^!k2{UgvEsAgzvX0Zd2XnyRCEE>vrJn=-YR1 zXWuTm{m1S0+nu*R+#bFC_4d;3)kKO!>O@rH*2G9;JJNTI?*!escc=Z%LNY#?FZp6JAz3H+a9X6 zQsq+>Q#DeJQr%KLQoU1sQv*_iQm?0mrQS%5PK`~yms*f|KeagZL27wwRccM@AE}R0 z8&Vrn2hyn0xY88UEYl*>O4DAY&84H$8Pl25S<~6m52f>^3#N;ti=|7ZOQ*}GUrbj| z*Gkt;*H1S}H%T{34@u8XFHNsWuT8H{Z%luY-j?2x{wn=V21N#MhDwHZhFOM3hF3;l zMs&vAjO>ikjH-->8MPUYGoEHV&uGqgpV5;smNAtvlQEyMl(CZWBa%9(1JmYFu0c9{;DPMNNmS2Dda;Y`2GtC>NW!I^h68#71m z?znsGuKHc~yYY9+@4mX*bGPsAr@KRUC+{xaUAnt+_j?va7F8B)7A}iEi!p0&7JC+F z7I)U^ER!t9tSebwS#Xwr*7dBgtQ%QTSut4;v!=4q*^JrT*&^AZ*>c&+*~Dy?_$`*?!pp*+JRC+40%8voo@bvj50_l>IpSX?9a~OZLm`p6tHtf$X8|k?is8FWFN$ zP|m&_sT`dg@0`S(%$(w!@|>!ihdK2*jXBS9nsVOe4CV~yjOBdEna-KbrO2hqrOn0V z?#gAzWyxjD<;dmC<;#`I)y%z=tDCEzYm{q}Yo2SBYn$tk>zwPB8<8888v`b@A2GIx#xB-@m}@4_xBd_DDyVuZO+@8hsoQM$DFq} zk1dZQk28-qPcTm;Pb^P5PcBa}?{uD3UT|J)UQ%94UV7f$y!^cTc_n$JdF6S1`Ph8E ze6jq~`8xS}`KI|!`9b-?`LX%8^ON#Z@-y?Z@^ka^@~iXz$ZyVnm*1V=o8O;5m_M99 zmcN+4oWEK?Q9xaQD%eu6tzd6~c)_It&w}`ZvVz)z7X|GFuL|B4d?@%>Fi=3Qrb_6`n2BDzq-ND|9S$DReLNEc7Y#E4*5G ztuUl8r7*oPvoNbLr!cRuu&}7Gq_C{8qOhv)ZQDvB%0D9S0yD=H`|DJmw~2StEE(>Q0bP^ZKd3$r%N?TwM%tN^-GOQO-n6Gtx7#gy-Pz%qe^d< z#+TkMO)JeT%`VL?%`1Ifwx#Sq8E=_HnR1zGnNFE`nP-`ISxDK9vZ%6~WeH`8Wyxi! zW%tV-merLtlszeXUe;XJRn}WJTsBrVQ8rn&Qud>qvV2qd=JKuOm~wnMeK|upSNW0h zW928x1X<;xYz&B{~CpO?QW?=J5x?<*fFA1NO%|5CnKL0Pf20#kvnV5#7& zI9PF_LbO7n;%vpm3e^hric1x`75Wv16_ypw6>b$}6}1)Z74ItgE5<6mR35Grt`x15 zsFbdht5m2As0^!&t-Muvx3aqOkIF}tk1L;6HdVG%zO3x5d{fy~IaxVfIaj$*xmdYe z`Mrv=YE#wbs%=#}s_3hZRw-0nu5zdfuDVl|UG=c)b=7dyQuWDd>1xety=wDnhib=a z=W4&|km~U2$m*EtxaySZ^y<6SIn{a91=UZh2dcl<9Ip|q5v>ugQK&gzbFoIXMx#cn z#<<3+#*0Zi#~z+|DDY7D;mL>6 z56?VQsnxF4t2M24uJx?-uf0*5RGU(pUVFDTr#7#)u(qbQwzj^uvG!SQb8Tzw%i4vy zJ#}(*Hg&Fb?sa~3A$8$(>2>$(9@Rards^32*HZVguCwkk0>7Pe#HGqOfnPp(g^&#cd`&#lj|FRZVxe_cOXzuJIqU}@lMP-swVFlcaUaBaBK;MD*(_%{SL z1UG~>L^Px|WHw|s+-oRkC~A1nP~K40@UWq_q5m=MW2wh#k4+v2JWhZ79vT0k>&L+AhY}2l$y-n;*`dgsHgz@4HB&ZkYTn$ut$AlNZ8K9db2CdbYqLzV zQnOC; zZjEh?Z@t}`)SBFy)|%Ox)%vuxzjdXJzKyF*s_lH6R-1O4UYkK1vCXv2q0PC?wavZF zv(2Z?x9wKjqqc>Y^e@F;%D+7G^4v?MmntuHUK+o2cpbWe*gCUR5zx3Z?{0VaJOi;M7MOeT(@HPneOx57rRxvHM*_4 z?YbShox9z-J-WTSeY*p?gSxMGhjmAEXLfgV4|Y#|z=;Y82m8&VeG?~57QrJKdkiNdiM4l=n?3V=#lP`>rw1E)1%s>-lN$==+W-c z?eXY|@2T#2)zjZI*fZQS*7K!js&`ZG&R$F}zIS&oV=s5_(ca^|e7%Cb;=NM6GQIM> zioNQ+hP}?c-n~J+F}=5Y@ARhjX7t|cE$F@9Thd$FTig4hx2LzS_fzlZ-qGHP-l^W% z-i42wKW_cF{o~G$v>(wQu^;gt=|3`jRQTxfG5ur5$M1bd`!4r|_ucBd-FLsQvahDE zw(n72YhQO?Z(o1kVBc`xSl^ev<-YIzl>M9fH}`Mr-_cLg&(MFQU#9_F8_V@P>_J1DOGO%wzaey%3IuJ4tH&8lIF;G45 z$H1e3#{*9Xo)5ej7#bKE7$2A%m>HNK`1?O4;2r+8T$5_`LoPt>(7y&?|*LlJn?zq^S93{pT7@p9;O?{4&#S+ z5APXf9zHnCGt4{8KP)mVHY_*&kTp3$+j@onwq+++!kR`eW8(4r5MZu4A5K-ebOF{$o*NNn>}%9*)(Ib&V~L zeIKVB-!#5?eB1cWaoTar_@VKmDPs&dcCw(WcPliq2n2egdJ()3? zHJLk^KY4$$c(Qi#@#NFVrpdO+j>*@PZzq?hc299m9iHNu;+^835}lHmlAe;ClAp4f zN||~z)im{XYHVs^YGImsde`*sY0l|`(?_Oxrun7?r-i3aPM@CEm^PX=nKqxcnzo&G zn0B7_o4z_7G<|(KbUI=>YC2{*XZqRn(9EV8)*0!U3p1)S8Z(3$y%~cU;*80R;|x3# zG;@6>Z05#H+)Tnu(oD)s+Dze0{Y=};*V#?8TW7b=(#&FK@w2;U8D|g79-X}~t30bV zt1(NM)tS9KYcNZk^_qoe{bvJbgJ(l$!)N1W(`GYgvuE$k7R(mSmdw`8Hq1VmeLnkf zc4BsFc4l^dj%p5?+cLL(ZucDH9P=FO+>tq+x#M$ub5e7%a|&~(<}&AA&-Kpr&kfFf zo|~HAK2I}`p68wCpBI`xIWImhH7`3aKYwc8V4gT{I&U#=J#RPfFz+!RI3GM8Iv+6~ zHGgwHZa!l^Yd&{Af4*w|;e73U{e0Ve$NcO0ck@H@!}DYFU*?zRSLc5$P%Y3dU>5KT z^b7kIPA-TqNG-@NC@h>_IJcm*pt7L8ptYdA;IQDl;JV-^@ivx>8izAEUi?fRhi{BQP z7gxV=ebfBr_RaTO__x$=>EH6cRepQ%t@T^?w~=q--zLA!e4GEa_-%P<%hL9xolA5} z*d_eZ?j^=0o~83k7E7T^xl2!$I+xxpbuaZUeOmgwG`cjt^lcfnymOgu8N0k|nR%IY znPZu2dH*v1vh=drvd8kZ<*?<5<*4PjIY+zMeuXXWyW;fn2w!-~_2>q@{%(8~3du$6?B#FgZg zw3Wh@qLq@BvXzFFCo9ianpfVfbg%TT^sfxAd|p{z-L$%Ob;m00DteV=m2-9f>Y>%6 ztNg1%t0Jpns}ifHR+U%vR*hH9RxMX;R-ISfR2kDf+)@0F59dT*oKtP)MfA%gx5x<|;|Cew_c6WAm=KZ{%GSAHHlv8;AZZx|$jUUhHbKN|i znn1ltO{LzVrcrNGGpRY$d};x;n5w1fsFlIU@-^&9no`jh&LHqaE!&^#^E3f+`$PPd{RX(!s1cB2F6 z5ITa6q;u$8I*-mb(*<-#x{xlSi|G=&6Wx_Aqx;Z(>3;NJdI&v~9z&0%$I;_yGd+oZ zhn`N)pl8yv=-Kpp^g{YW`XhQX{W1Lsy@lRNe@btox6?c5J@i-f5&9^7j6O@BqtDY9 z=qvPf`WN~R{VRQ!eoQ|>O;A(R3^hkBP)lTPh3t?$azKvA1$iSMh>^+4sQ0=u3s^hTcaXqL0uPv=!|@JJDYB z8QO=wLI==6bQB#!r_i_PS9BNML-)~d=mC0&9--gS<2>{PJw<8+Y z|6&Xb#qf;4h)fHnCDV$rW1JXQ#+UJ9l9?1Hl}TgLnG7bA$zrmZ9443P$aH49FkP8G zOkbuSGnA<`GsBqS%t&S|Lzs!oBxW)*kD1TB%Pe5tV-_-tn8i#TvyxfItYHapnYbk~zhE%baGuW4>q3Fc+8~nCr|9<__~KbC-F{JYk+1v5_$vjjT~Lszw*1 ztI^HqZuBsE8oi9(#$aQJG0ND+*w$$7U`#M}Hg+*~HFh(0H})|0H1;y~HkKLt82cNC z7)KgM8Altt+-BTv++o~l+-2Nt++*Bp{LHw| zc*uCl_^t7@@v`xX@v8Bf@uu-7<8Q_X#)rl~jDNCrtUc?%I`HbOThFd$*RX5Zb?ka}1N%O^k^P9>#%^bKushi=*?sI+>=E`TdyGBHo@39m z7uYN8b=LfleZ>CGK4zb=PuXYea}IM1Cvp&7s`ck;amh4$whH(xVBsj zm&7G=DO@U-%jI$TTq)O?>%#Tr`f=r4f9^GIC^w25&CTLwb91=4oQ0dm&F9|b7I5!z z3%RA-N^TYRKDUwE#BJq1<+ho*FSswcecV^v0qzKQl>3hRp1aTe#y#L3a*w#*xyRfS z?kV?-d(InpmRETb--LJMo%q(gGw;rO^TB)wAIc~2iF^{D%%||Fd>Wt5=ko=8C%%;L z#rNjN@#Fak{OkN1yqVW{!cXKU@ss%}{4{k+`8s|jzmea>f53mpf5LC$ z_wxt%gZv@>Fn@$U${*vu=g;t$_{;nc{LlO^0xNI=F9?DtNP;XVf-0DVCPE9rNoXxN z3*Lf{;46d+5kjO8CA1gfgj69-NEb4M&O#TVtI$p8F7yz33cZ8@!a%byRHzh&31ft@ z!W?0)U=ijC^M!YX1;Ts6LSd1xSXeI93#)}q!Uw{K!VY1luuIr2d@g(?91)HR$As^N zGr~RLzVMsyKzJxT5`GsR3r~cn!ZYD7(I_gSDw;$)(Oz^AJw-3kTl5hF#1OHq*iMWW zJBSIQIYrD8^Tf_#7qP3@P3$Z769l@(spULv`5+}?U&34q_fgF>AZA7x+qGBMDfmwb}UMMe;7t3|> z8hO3EN&Z0oSpG!bBJY;>$b024x&clojW zM1Cqilb_3f$bTwWVH81WuC!2EDy~0d8GWVJXW5oNEKB{mDN_NoocT- zsLrap>aPZ<5o)B`PK{Ml&1#NXqIOYxsAX!oTA>b6hpX?X)72U3Om&tzTb-lMRW0f~ zb-wzpx=5{2*Q)E(_3CEzV|BN>N8PJ_rtVYst7p`+>N)kidO^LYUQ#csx6~iiU)8(n zWA%ypRQ*%^%VadEre>yACP$Nt$;0Gh3NW=bwKKIhwT(8#n9@xdrc6_oDcjW1RA?$S zm6`gO`kIEAhMFo(lT4FMQ%rA~rkdU|O*6f1ddD=~G}|=KGC_{VXoWW3vRnSZ6?N0< zG_$4=)KmZJMNk<*!?iksCJ{7QBb#R`PbkagWt3d0Yr$(dEiE&f3Jtf-%m@$-?#c~jbyVY{!H6FbXV z#BXy>zyV}g+NwZWODKU*EwqGQCLhbO>#aApw0p=z(0L?m&P)m`khcnfm8ej;8-}clXL#Q@f zo1p1GM4JfT<1NFJye*bTtu5cVMp}AzYiil<+SGFQP2Q5!!OdbRXldCyhqXUxkPV7K zrAAR>3@vM@(b|X_YOGcTci*e@cc)&bh@oX2^#*08G_6`2sg0_mCQ_5A$=Yabj5ZF6 z)!cQn%=YTm)FYwa3WNT0f_ew)n@-KJwD5Lw8GFLe%g~#eMa}M%S5#7xnNmy5GW0z` z&4n@+D3jprX10|voT1*WHJpKq)&{+2=u|^3)Lz&8ZO2OtomNsy4I%nRdjm+JfBa3@ zWZ?M5POPTZ8Cup-YpAu_ByDmnwVv9bP0`-e#+UT39Ne#}XTQq6BZrg^t zt=T~J~ z>Pu=L^%eECHeH*c&D3UTv$Z+e+|`Cq>VToWE*0tsbrj@a0eR>@?`rP>TyqNS0QY3e zy+>^tWYXFa?b+0_x3|gM*o`yPd0RKmK{w{<-M9$dn6HihR|lGin{9o#repPkwxAKK zn}C%e#P$m)*?#>StG`3t)kXcQwy=h}r!CUS=2|egY^>#RrH4E9kb0s^{1Np#^;lc1 zEzy?NQBOhU&$VSB^X1Tm*ppshPIY$`85)-4ghbH*)acTDnC81!z0Hti4vR`FkYv zO|X&6T4QUyzu8*3=3mgzDcYU(HbmFa9<-;SL|dn=*L>?}AKI7p)85yPXt%Y5lLp-o zxY{g%W>roP+d1ngI^23{gT*goVh^iI&{1@PA$lF%hHgu@qubNbbPOF!$IueVy9E-G&wy~Gx^gv(+-Jc$y?bi0x(iQY; z+FtD|tG0SrdKG%Q)0K1;$d4XI52r_HpJ|_KUx3EaBk55fy)U(We`~Dy1U&&n@H#c4 zdtOoS$dMKO`i!kEugW)>ZVsCG{Kl%(6(1ej(kJ<;>3a?2szFimYSBO4DnFiDnsH>^ zYipnH+BF)AHa2xKJymb&6#7l=Ywa5#F+B}Pyk8sNZE(fV^30+AQp?Ab|63)S8tg}Q z@knTHm9?Qsix;)cq32mug0_H49R5dbmYQBIJJXBkRl2Aa(@W^3^fG!my@IZxYw0?A zrFK+1rXAN#XeYH(+PB(i?K|!Jb##4$sMgWzK}$mEjUcKs4Wc@y-2{!%v|A0L%Aj}Z zqS~dMZ4}ks|D|5^*Yp9sxfpVBUAm$fT( z^lAD#YNB>ky9RR7b?kMHz6h9K0$utd!KzwU;qV$9-brwCe*w%5`bYg~H|Z(bb?xg~ z`nF+*c0+3qRYWAZInej$2R7V(1KfVBHSC~o!^InL8F1@HKShj=+cWw({RjOg{TDJI z3egB5to@|@to@?h(SFtLYWKAJ+Hcx}b;xML4GBm@k|7i+fZM|c+@2E3NGKNE55-xb zE28q806ElJd(?m&as}j&8*+z_r}n${7(P$Hi2r12X>w>F4)RAq&}0;V0<~w_^I8;) zLbN{!Wq>w+5Si|PB2ioYdKC2dPv|jfN3GZX0&0!7yb(F{a!EL34sv^`(LTw||HA4MKXnR7Z5PB$~rxSWD zp^p*z2|=C&CAEZ6{rNnM$mc@%bJS+HX4v5n(2rY-fqgcH+?y+er^gO+HA; z#8_JAc}eJ`?W|Yh{d!zz&NrE@&IFxCR}InY(Rb*3bOxP8=g@g{0bN9w&}DRmP(Fn6 zC6phb{0S96s6avm5h|EaA%qGgRM>iStwHf_qFd-kbQ@IfX9I{c+@^bkYD1_bLM0Qb zSl7Q2I1OQ@Ls8|(5tiuquPwcPf4>Ah)0Oc#p&}Z!@h{LuY`~QMAyg!xqHN!wkx8cP z1}z?z*crPJDvnU`gz8X--LN|~kx&VQN_=7Uu%AK2{-A-^2I&fkgWxb24wb=f zMWB#@HrLSDxNzLw5M7TWa3qexZE#!Mj!-FtN+nbpq0$MJL8#1n9Bl~2v6K&v#~lcj zr6ZKBtsztap*mWQFW6-E=!d}n&2Q^lkiF5QmXW?u@T#1L_;dlhD z!qs>rp*j<)3!&f{-3SHG=s~ESgz818-h?V!hez9Jgva9vy5GZQokV>aNz{)}!*th2 zsNoI1FBi`M(qPcdz73?obN-j}!|&n6I&cf|B0`lDs(&qBf|n9%0HKBe7w%PBgA^ZJ zi|chh)ZvwQ6`=+as)A6j)#256jn0Qbgc|%eA2tC2J^%t_Sgd^542K`XVU@+LPoo#a zTk&=q0k`P{9I8XMQ=3Al%2#7%#n;0|A%me2@Xzr+8{l8+fRFg+-MX9Xj}PM0I^c)! zVSEH1#mDe*d;*`ur|`FgswNb`K8jG_T*eS;ETP5`YCNGP5bE`H_`3$c&ouykNeBFm zM!*5-2EeDk0Q?sn@H>P8Yi_mF_}>2n{4su}1O5a*B@`jl#9I6ugSUi!z_3SmnB5tg zVXWXVSO-TR7BQ?24!F#J4=7NN222=kv;kuNV)^O+yhtG$(c{WOkabrBKI5QqP&NKem5FKYTjR&M5%e$PZ z&|&S*3}AruHH4}qR2_sT%pe9RPpFlIS_Q@R@WckKkNE^M0>G?#HTEulztx0wty7|Q z@4DwXc>i>F2-BHSP;~UGMZbA>(m4OWQofj4{l&(`i~XT!W3$IGuj|boPXi%VLpa5} zL4j9ZqsLP=a`b#LUTzXH*drnQCHu=vVWxxqW!_|_GH)@{n75gCh<^VDLcLF@jfC1n zs1NFy86b*Ty8UH9bRX*Af7D=qKi2JU@W1UZvxHd=t-{$1Ael?3&9yiW!~YLC!pS)~M8w|54zOjq%GauM!w@Ihnr#kK4(4f0(bf9(GZDBswX}6X6 zl-b5?XLc|L8(xK=-Wre~;0}0L*<|#D{bdKh#BZ_-_&a zEn)R&W4+IqzjUHLXZ~RRB-Bwt9V66nAgYlv(mGL35bC6kpDm6ypD=O;)yTifywBX* z-#*RfY?^V^v!6LLtq+jYC_z#A)uL&8zq-*x%$c`lS+^NgZ5@Bp8cAw28CwC%j7^M9 zjm?bBjV+8V2?eJ2G@-sD)c1rs<4UNr^+r2GsL_G)F*@ORLY>pWKCjd4B6xbBS(W9t z!R{9GCWlw(X7n-o142e$-Q8dKx4XB}%@}G72f7)<2zBYd={BMPIb%CxjFoQ2Xq|3X zb-F#&0Q$pLy0z+;Xv_g;VoWk78&iy_#x!HPF~gW?%re5me<0L#Lfs(LO+wuw6v*^8 zp?)G1Nc5L=##|fGj2&&GR%3}yvpbD6yK5V_63Eopatyh~zQ8FXc=cZ!IAt90zkG>t zsByRsL#1&Tq3#jteywqY5hC;72=&OuB`4z;<9H}SPce?ueaQppobh$Na}S}wkS+E; z#)-x^fj7oU#>qxF{X3x^6Y7c1o41V9bl!lQdZq(m<4xoV<18S<>{rRam3Qm2>1Oi2 zWuwKRv%B~GOy`XSip~S4(qrr2PQ|#uxX1?gLLKfuUTRTIuU6$NjO%r{YmBwVI^#;? zDr3EIwQ-Gctr7gdUxYRgnj$n!XhdjCXok>6LbHVC))_Z6!2N;EcN;$jxM{utZdz>g z-E^xLcz>?r{RN?gM!diJpLicO9@FtYVmwM{iO_Pb@wo8>p%p?m2Z$PjCF6I-b2_Bo z8_yWe5?Up+iO@~zjOPK=i-c|ps6rm?Uuikx4}jHmz-rf6-5(oo!Qqc^cx&uGp!?bQ zt4)}9K$vt39lCoUOu8l17BtS@$@s_!xj@LL8Xp6;wB1Vu09*54tO$maHLw&*vxvnk zgD$Wv%dtEw5ZZyzj)Zn1bZbI86B+{lAVRwm+Ktfeg!Wj^N;ZI56WfGs$~H5EvMqFo zJsTnRC3GaAqX?Y{x=bhi+i;d|PKZyYIY#19(Xej4j%SN*BumD1bHNdY9@bZpk;{km(hK*(82pvdh=tM9O znoVF~&_d`CLWe@}7lx2cH>hmJtAxJSwYO=~&-r&&dv_`rz-QM0p;^d1u#kKBcmA!s zaL=y?YE!O%P}cK_!LGcQ)@TUXe74XkF}9;Fv2YLwTdYeg;y=8#_f(IB(3iY5+m(gn zL_OP$?auaKd$PUQ-h^&L=(dDzM`%Dkn$R)zY#$IrKgx&g4`!5()uE3AGfKnI>ECAb z-r?@w9`1g+5zygmHM9WlXdPT z|Ff%Bug$*0F3`z0ot?qXWM{Fn**QQy3p)iX8 z{RBQ+3Eh#a;e$84F ziBs79y0AOz2prOd-KA03fBWrLI~waf&g!W}_5^#9Jw@nlgzir09(C+#7P5l>1vyfk8A;0)<`bAIQIp^8Z9Luz!6CX}-TA8jh6>^U(^OVQfpg@XxYnFA=fb%Xx{}bqi{XSGLFg(%R}*?9p+^xK zOu?9SoV$%xoVU$qaQ-@{#x`>5jTb)S?FOGw%C!RqaZqSn1B19&U=SC_#lt6o(4Z+3 ztluyZX5vh|$-Y6-TpE`Nz2MS0V7QskS}m8w0T_hPlN%Vs6>vpRgr33`>I|9)9py@N z22FaELE?tSdb@Hkkg4OkaoxEd1Y$<|O+rtt<9bmOIS}Amy3Lyg4h+H6XHT-p<8#0`R?gI_I*mbTllWP0-YJv(puxwR0MzMv6T z$&IjyYPc?{cV6v*Wpyu;CpU(hqzh~;H;x<6P2gVV-r&rf#t{xUKZDRS2|dfQe0YoC zb=>3z0lmdd!;~SEo30CJL8E{c5xO4IU^)+1H%O=>w@8=JVnV;yD4}J#gc7(F$kPDU z|8+tygeI5))RUuq4k+2WFL6ArDf5|g&$GDR=oKNUDulZ+dbd{*&&T!Yk+Hz;PbKH6E0(X(S zgf4JbxU1YX?gv7zBQ$hx1EJq1^hQF%s4s}nU=}|l^hbo=yq>$!0Q+rvJ@>P2ZMk1{ z;6H8zev5XK(4X6k?UBZKiu*%H{!c=G(ttcq0rGIS^%n}iJh91hyq>A#c^-lfFutGG z@)9o-dK;nl0P2nL6yKC@2_W*#_~v{ILT@MZ4npq)kIvii_By)(+1*gS!K3phco&1p zy8?7^8+9ak4>^jCz2yS}OCVd9vNp?vr_-5&1Od3Zp#hlgIZhcEkHK7-HJ z`<|)W!-M~65BZKfSc4iK9Ma*J>>=No?`9P~-&Gg>(U;n;50LpXeh3Jk@5A@y`|;&` ze|`Wzkgwoh;|KAB34NTsCG=@Re@E!=34MmpX9<07JwMbYe0~I;z*p{5& zlk50;el-trxK8LBguYqFujAM28h4A(Kfcg7{v#m9W+287)mENtfy1qEsE%~YYK-9c z?fhpt4R-K5`Ca^Oehgy=4|FCx zvUKcHV#zOdx7>ZB9gJkJPFfQ^X-!Onf#8qxr=UMLn?Gp{!G3!s1Z&QpBEE5CRF32$Bg>>V#k+1murY zf=pKVH|9ZwHU?E_3qoJhS?7Qd4Tmvs_ zY9N>Y%&G~!g}!>1%fLn;=l`-1X+niC2*@G4Mv!YGIbNFXFtusKZ@8cb`_vkt3dn&x zUg`vpqrWgtm;ydo7%xl^UKidF%z`EmVWKcem`sotLEZ%U5adgcA3^>E1rP-I0zrb; z32)kXA-ru1qJ)_`D?%Ds5#AU?q4)+zQ6#|Ppc-K*L7|NtSYdV1LM@jdfQx*cpfKAv zaG-f(57r3lbvV`v>j;VAv@H5%2J8Wm?*)-hU1ep!7jXC`9Clyz4+eZK=%Kyv4VWDi3uZ?+2q`%fr>EpB zhgR7;3C9Ipj{)72I=UTnbPwtjiGu=wZniFP%1%b1f>&{K~N?^S?h!bS1f=l)@`wHM@Kii5#8K|EE4L{=!J#nI=Fuj zl+ysNX!u`NS7b#2nl5r8XjL9T`L&`bg5Cfvi=gpfb-Rg8#O8XDrh4~bBwH)C0IQ1% zb*uZY*vFL9AT7~RbOAAlPGW1(nV@2VN(kyyC%TGmx)@3c>iohGi@pX`^aISzn{^S0 zfp8cEhwC=~EdnuAjIbgshU*A-1>+{R0OJO&up-=CY%f9{uSSd}sC$hVOHdD8He2ob ziHU%Rp{a&mOt*`vV!9#PdagzUoO?G+vWwY<{kD>EjlIYh!3Wog1!70Bkf1&U)&`({ zbz-qtB7zc^69k$!6dsiE=`^$0UF-$3_+k$VY*>G-pjPZH!t%!f1XXAWT@nYE4XNy3 zF{1p0SPuQ`FAgY$WjxgtL&`l8zxH=^eERG?f?$mstiBT~#MfYTRZ3ZPd97FhtE;Sc z3>F9ICEb_*IH49wHny-*9ASH?U*l7&#A<>D5m=l6YX?+uv^Yi_+XbFgRXw6&D70p< z<<7SFwzemY7bo;Gsd+`YBdg2$3@$IS7O4}*i?18{cFrrZ9XHkj7E8Z3wYfM^oD2Yp zAc)Eu5lAsiOVBGd+gduUp`|MVjd1NnOQ(wq3@z7*GsKzVEOE9tN1Q8K#ChU;@m&Hd zB~TSX(C(20jUs3?L1PFSOVBui#;-H97Z>U#MqDB;6_<(2#T8xFQ33`X1>6Z6*zMCN)H0-Yv4~d7xBLvMLXf8nu{;u)3_$@4A6HkaI#Zv^$ zBxn{vv+Iy3ekbnMSJ$99P@x_jd0VdRa<;75H7HTMBwqWEd&D2a>*5W9ECkIXXug)< z(c!Kw;_qv4^`Z@~C&ZsXmOqQXY|h@@ls2PxZSwn7yxZf2^nfsBb>gq$Jwsm`eaae1 z@|y^bzaAR;P<$kw5+93Ctjz_+Erb>mw1}X^_2M(}x%h|pCwxCAXbC}JpqCM}-1^5- zy&LYCDXEElt1CuX&hK4r)>$d>R$2RPc>PL$1!UdJ)U-=^RdxA@er01_%c@<&L!+ZY z8(JaBQcFYh8cC5<$s{$Ano7;2=28oSY6t>G*AcXmpj8Cb6SSJ3HERr^lAX=7NRVfg zoOM~RZM1u9Gz_9%xB1V{+^HsEZC!)fgtv1Iiwq5Q4GU`($d zDM$*ILZnbBObVC4cYyKUKoB^OjRb8X=mUa2B1N@PS&%__61lz|I(eZmC^PwiH&#yp1RmCI9%Nvp0A?>uBI_Tpf z?Ug?N`>rntI{#w1i1d~8wZ-93Xo_@DIswWi9g+@9N2H_DF$p?wiJ;2_T_NZyLDvZS zp&n?G4Fu>2!~v=RH-IW2d7uZhXqRQ?p{I$`73r2<(N*c1^n-L=x*^>p2y6s=-y-No zf^HM^Q$2|9HpB((rC+2wy7+#EVHqJ96U_-q7Eol9p1pNiBTn?0B zsgWFP2$4g(X7+>JYDNEw@)0GlQneg>$5Ra)!ZXX#6LwgRkRvS@PPm|2Im&YGgnL@U zt!?#N3HrlYvUBmk5#?q5T*DeFri}Vkt-yM*@nH$pJFvl4ck)R;ET_romSHCYX*t8P z>}2;)Iae+OD$03szFZ)8B$y?bBbX;x042njMlK^* zY0v_>Tv{v-(6zt;v;eF5P4IVph7GQ$styf3MbQW|M)M@giv98C5b4h;Yd4ufS*2-9 zJ11v%PanUaknqShZKGool2Xz#vT}0sI~J96?%K0=zy1SX8&WyEYUJp#<6l3)@q%1D ztgL!qmkJ%YjEbSvbrAm*>vAscR8cMnP>^R;*Szx4u4%9npnL?B_OO=rzMB4MJCycnvIyqY>0hdD^YsIjxX(P&p zl#i|)F-X5Z!gl|YP#+ZvL6L3snKsOHaDEjWc7PH={=W9OL8g)R1Ag7U949D=g~UO-FiS( z-AhWUD+X7YFkJ2xsEbJl_B>oJ>kF6rl<1fXiE_i9MUe6oW3qh@xjy4z7=+{V-dh4}` z;4vE-GOW6RvLmaK%0>iNjjrflT|0Sd?UXlPEGzR!C`qu!TD5OY^GFzGvi|LnF#EhM z0OJfz44#HyL#!d&P;8iLm~NP3SZr8sSZP>mSa0~iu*dL?!F<4Q6qcu5G+Z`ZH{3D& zW_WD)lQK{YrBKZ%JIaF!rXr|VDv?U3@~L8~2i1ofKnNu z$m3;L_0H9xj z6~adNw#wUKbSHl*ZzI^B-~br*$~$4$ivulo=SqC#&#WPsN5XI$@Qt_alfTxn_=?~V zm?hPSW&SxI2lR`B8kf)fc&A~>1ge1eY>{5`=B2!2TL?^;67+_EvS28bdIXiN z59==lCw76DFtuMrb>#@K3Df^69mPR${;yhGpcY_Nu3n42{!RO%d7tikt#?{OBE=g* zBE^T`g1;N&uY^IYrvxa0N{|w)geai|cOZO@2 zzh7%>Rt6cMi-VOR%21_J8Kw*;xQyVw1cQDJAh?3y*IvYZ@Mt}Fg9qth-v2iD4bhu2 z)^n;BXGa9a&l{bLFP-lOgvFO>~uB@?wN$e;3^??Ky37}`z=&0cmWfY(5(V}&z z{OrZae}<5TC$OFEu`*kkV*rs1CK&dP^fC?UUop5mIwT~dq{_0pSzp@-N13m@YcXAK ziE5Pv7UjBQD`lawNLk!f57TTJ8G?rqTxm(Tp438FrY!H4(y2HNDk^{ib;=5*#7GEhtw*oEua15V17lwYn5)wdSwF$c&#B<0U3+| z;Sy{nuwY%6?ikJP73qGYZ2nuiuM<4#AJVlEYa7J!%64UkvQybb@Mwa^5*BEVD)H%08QL#@U4Pk5Kak+W&t=aKa`6@GDjk{Bsv_t3lS?AIf(M zn8J0+_sSXNta45{uUt?rDwmYY$`t~$9gumz6A7L~@MMCg5d0>=QwavgGi{yHu<=8= zY0HHxKS8z@!|DOu%o04kF&B zNbn4TXV$8m3d4(81jB~Y7g=ysQJaEkQdQNYHX(R6!E*?nTc?u6PN9vQ91SnfV>GULSrAO26Pqjpde zl%8smZgoKQt)yH<@DeL254~z~)HF5yZ&I!#u(RQBlVfW|E|?rOPt8{g)Q)PQ3bxj~ zjNs)2uOPUF;97#~{-)LheaouV&>c2(cfDf?j~WjE`qp)sU0FY5$80I@_^{4srcx1+iMn5(`=@J9{I zRTl$u|9c5^V{2>GRXTg?RFDQF)jp|J>s4sr7J@$oBI#4S>IQX_jcFTorft=U^iXG- zZ9Q&FAN3OzwtUyAThy)Urvz^!css#6>eTJ(4xQRN3EtI6ZL|705bKLq7qI-tDrfa8 zDEjrQMgPxL&gud6IJj)}pn6C>tR7L1s>cZ4L-1aLKO^{ag1;ax_{)0r1fYA0|C;hq zzav=Buwhs|@CcGo_#2oT9&VXY>|`;`a(`u&vwB7S0f4~S>NS0C7=Qih+^~9E{TTvf z^(TV&H%|ZQOQy`~J@tW28(|+Q!3X~d;=i;J;($J7eFqH~Q8{vGzvRlnl_RWvLw%+` z?`3N7Z@&Q%THisn>K}%_|JOx5iDtR`Of~;A*8^c2^|vMh4gl2)=Wo?S6APMXT`(oU z25QM96MUTD69k_m_!NPSJNWefnO znmU`h|3`>w>S1Va>P7GkJw&~!jqjXO-oIKO@_QtZ75@xzP5n%;gZ-62*;E1dLk#z$ ze*bN4d}WuyiU9)~Ync5~4Z}=hA?t4%ZW>{#GF6*KnnsyMn;@e2nc!at?3}{C5`357 zdj#Jn_&3PRx&miYu+{ zIBA+;nhBE=ELCTkW!d(JuNgnGvf4DqG`Cw`ku}`agQZ%N#nAVkCmQUOX};-QL-dLj zT7rQy*c;ppfd&w+p@X5Lp_8Gzp{Gy??=UJChQRBJ%)(^hP2nwJhA<0WTQpBtFPsoA zi3X7tF}!$)69rKc6*IhjsHxaoYzglma)3EeXL#pOqL?hEi5c+Pp&T(E<`;{_Qh4;N?U8;gv(n;PpZW;YC3XFoBT-Z~Uo}-iB277U@UX0I%V3hSaG$yn@FYlB50* zBn8W%@G722IT2pKQzDnb%XhlL`*Kdf`0bW#z5}nyd9Lst(*Bb3v3qLEVS8-W{a9F zX|}A{ie^7Gd)(}4v**qJZ1qj6pLPa2+78<_v1?}6!mgE_ zz1hym&c)8nF57O3-9dZK-qXI=zRbR#eSiB3`$6_Y?8n(puz$l|v)^Zb!v2i?Ir|It zm+WuY-?G1L|Fiua2h}0ep~#`TLl1{u4g(#AI8-_ecc^lh;9zzj4wD>aIxKLgcX;1n zi^EojZ4Tc$Ty%Kg@XV2OY~g6<=-}Ae(Z$it(H!g;>KN`A={Ux5isN+0nU1p^=Q=KQ zTo;9dtV8bi(PB z(;268P8XamIo)vjr8V7}ZEb2D+PZD)($+&-Pi#G__3YMjT3cGLXkFKORqHja*R|fz zdRyxqt#`HFV|KQ4_Hy=j4s;H7j&P20ZtL9MIp6tBXN&W@&hI%dc3$ed+~PuTvd861 zm#mgqHD5ihHI8-wJSBG)CZ%UoBu zZgTz5b+hXyu3KHVx$bb?<+{i9nw!DR-7U?nuiHeo8n=yZAG&RJ+v4`A+jh4LZnxd; zx&7w$(Cv4(Kiv)Pv^#b;y8E~nxKDI{$9 z80j&}V~odmkIy}hdYtk&?eV?G1&>P}S3ItHJoFSj?L2)v{X7FagFHh#!#pEAqdZeQ z(>yagvpjP=^E?YY3q6ZHt32m=Zt^_t`OvGWR~xTnuMDp&uN<$AUPWH!60cIP{$3Sc zBfLg>jrJPrHPP!GuNhvmyykdWyykn=dad$W?X}KpgV#o{<6alNu6y0|`qAqrulrsP zydHTy_Im2=;ho|=%G>Nc-FvxrjrTh5t=I| zG@o~T-t$@Hv&3haud{D}Z-Q@pR}}bzigZ65k!Zm;5L{FTZTRO23(Y@B1C_JLz}Y?|Z+qe%Jhd_PgU}zUz12 z?}6VVzbAgr{QmG4{8j%Z{>}XD{2lzA{GI(1{d@Wk@*m+}?LW$YjKA5R_)qem;y=}Y zjsNig6d(oI2LuKL2eb`H2`CNd63{JA1}zR+8B`y%CTLyI zhMJA(EGeIE2>(Egx2IIT7-0 z$af)ULLP;-2yGwQEz}&kDs+G7tuQvsGc3p)78({F78w>7mKK%~mKBy0mKRnKRv1=KL{5sF5;-?=LFA&yrIEFfDvt}ZMw8s*Jf** zZEbe6+1<89Tlcn}ZN1z2wIyw5ww>K}Zrk~7ue80>_HNtzZ6CJFZ`ZwD&vw1r^=-GK z-8bznwY%Exdb?Zg%s;ie)9zlo2km}u_q5#~Fx}azy+eDa_Rj5H+k3S4ZtvGVuzhg* zu=Ww{quLj?AKrd``>pNIMN`p%(FM_!(KDmhM}Hi>HF|sW&ggy7N1~5MpNjr2`fT+1 z=!?;pqkoCMAN?@;ar7TCh8PsX#JI<##uUbs#&n749#a<6H>Q8gz?jkIm~k;vV`j$8 ziJ2F(AZA%iP0Y%e`j|B_$74~fXKYYxbZl;Her)I1^4Kx4<6FgyCSwOwmx=k z?1tD)u{&e;#C{h0W$ah6`(qEq9*MmcN5{Fu#l>}r8y`10Zcg00aSP*?#MQ*Dj9VSI zHf~GYuDH+RzKQ!b?sVLDacAOg#F>AL`#J8{xchMr;$c}#yd3Wk?-K78?-}nG9}piL z9~$2wJ}15`zF+)+_}Aix#1D(FiXRm}Hhx09IeuRJg7}5;i{qEZuZXXUUlqSPeqH>A z_>J)g<8OCRI)rv8?l7*yvJSgCobT`?flgo&UQ}ur*;@!qvp)iBXC1iP?!g6MH9C zB#ug)miSKMdx=XEmnYUHu1;K=xFK<4;;zKKiTe{zC!R~Zka#)qdg9H*+lfCXK1wto+*7(%2NiWyp}RHWkSldl-Vhkly_4WrmRS*OQ}y;ld>-5 zd@7UbZB7kIjZMu@?U>p%bwKL4)CsB6QfH>lPPL@Im%1o*Y3lOSjj20QPo#dE`hDuT z)QhQCQh!LjnR+|*m(;tdzoiLja+;dfB&}Im%QX8mr!6nE zJCgPw-7dXtdZ+ZN^a<(a^oi+{(`Tf=o4zo8N&52i+H~{E^!oHQ>7S%;Pv4ckH+^6F zH|Yn{52xSFkTV=I+%h~fd@}qq!ZIQ<+GMoPh{@=lF*9Rp#@>v>8J9DzX8e@#I8)4& zGaWKrGTk#hGyO6HGlMfjGdpA^WoBn~&MeOym^mnOXy)+D>deuZlQXAgPRpF0IWu!k z=Df^zGuLMx$h>LJVzS(_lCyHMx@7gtD$DAZRgpC~t1@eN)*D&xWX;T)lQl1ELDs^o z`m8lspJZ*%+L^T{>&vXKvi4^k%sQKOGwaW6DjW8xWeeGIwkf+=cFS!0Y^Q9O>^9l$ zvtzR3vO8oaWv6CmWM^mRW*1}^W*27<&z_zAarWu#r#Y@UDLLl8ITLf1=d8(DpR+ON zgPd(SpXcn$`6lOJ&XJsBIVW;Xz$c6`|JamQzchC){AXg=-7f7alSfJ}mMn3N4B& zDkv%}>Q*$cXnfJ@MQ<0)Dw;-Y0mD~dK1?JPQ8bgJmPqO(O8iY^yjE4oqi zW6{q=zZTIGo5a9deZ4xDOW0&s-;a!Tb0_EI+Z$? z29<`E#+4?Orj(|a=9K1@b}TI_?NeG=`ey00(&?qMO6Qi&|Nm;Z@BgF@wvXdRZLA|T z)w-)qjr&fkb+1}S9MNjs1UO+6AdC=B7y-h85U3CmlCW`vupx|a2!xS1>!_=0+>Nu^ zYHe+`+Bl*A0Y=Jry^$|=OE`J7a~_6*CRI~HzT(pcOnasXk-zx z1X+sYAh}2(vJxppRv}%;!^oeImyy?y-N;+WUy%=xkC2a%f1^G|Ek-d=TvQdxfHI*V z8!Cu8h&qh=33U;58FdYH6LlN)3+g`V8L9`}2c3l;iyn{8LFb~Upr@nr(2LMZ(aX>) z(5ujE&;{rXXdD_s??I=~-RKuU2JjIu92g0V0VV*S1CxL$z#L#XunJfM6ae1>n*cOW z1e5@!Kp9XDQ~)AC0!RTZ1ndE#KpaQ{9l!zLFmMz&0h|KP0_TB?z$4%>@Hg-jcn0(U zuYfneyP}Mu{zaKZ9~Mn6$}gf8sf$8I7mHqCMq%b-wqXDa7DK?0FiZ>&Q-Kj9O#jVF}#BIhE z;cz$tj*O$=N^neEDXtplz#YWh#P`8}il2<1jbDIYjQ<+H62BV14!<6cz?1M4dQzz4R{^ih~JIhi?`wJ_y~SKz6*aDe+}P_zlFbxzmI=_e}sRGe?rJ43?vLD zWD$lEh7m>(MiIskJ|#>bOhfc$j#Uc$|2TG=TI8X$)x`X#y#iG?_GwG=sE=w3Jjp z+DzI;+DSr^a3ms$OrnxXNP9?~q+dyYk$TBP$sd!)lBbdvlb4bU$eYNU$=k?diz25cvrC82JSGB>6N%{)v2ne2IL8e4X4)zDa&v zJhpgQF|N3}*k63M_)p3Z%5=(X$~?+K%3{hY%D0s7C|fDpDLW~J6cmL*VNgmb915Qz zq*PKM${xxA%4y1ZN*CoaR{?e)Q_p7spF^OQK63bj#>Q-7phpx&ZBr9Pv+p$($Fk5g!$(8kcl(I(JxXftU`Y1?Q!X-FDC!_o*e zGL1^3(^#}JS~;zTR!6I+HPZAn6U{=~L)%BQ(Ht}v%|rWv_DjitlIbNIOTZFSNxbAz z$dx^>AUIs z=*@I5-A@nFTj?;pi{8ullCgl1&p4WEz+eCX`|xXP##M#Js?~ z!o1GB!Mw%%gZYx#%Y4V`%ld#dfb|LMbJi5rG}eDuvsklP^H>X5YgpS@B`hY3%>r3G zRs~DUf>>271#1_phGl2DSRR&-)xrv~BCIx6oRwguS)Hr{tZvrp($7j)l#)wpO5>&1 zOJA}_v*)pwLF^UmeD)glckDtoiVd(aY#f`wE@hXq`D`H@Vpp*h?C;r5_Hp(__BD1l z`zHGr_OI**?BCfh*}Y{0%d*RcmyIkNQXSa3X;15N~If=j_~z?I-?a2>cFM1Ula3>Je_kP8YyF$jUxpb}JpHJ}yr zfcwEi;1A$&@FaK!JO_4xm%(dbH+T#D7kml62H$}1%KMgoQ2t^0;PR~UY^Z!#`6uOH zm2WODFE^H_%5QV~b91>XxmYfhOXsqb#r~(05`&I zd8c`2c~^M%cs;zA{7n8} zeilEQKY~AsKb8-D%Ks1lOa20WK7R{;J0HPE@r(F4K9SGngM2Puz!&l>`BHur-^7pe zyZBE8S%R5@g@V z;W=TK@Url#@U>{PXtF3zG*dKNG*7ft^o?kxC||TjBoH-=4vS8Su8JOs{uKQyhWd#| zibsnli)VxI=tEd{KNwd`)hnC2J)GlC2W7q)38=BzOr?LY8nOe2Gv}DXEeuB)cSPiAQo$az)ZDxh1(H`Bm~z z@<{Thq*wA58Vn7CMnI#XanM9)GBgdE0p&qEpzk3s6oK|b=b>_>F3f}(yyhEKAGw%TCG8$+~2hWY=XkWVdB^WshXfWiP7cSAA2prK+$BUsY1YtZJ!BKvn6g z{Z)smeyBPo?=R1ikCcy*PmwQ?FO#p3=gZg1*ULA`H_Nxlcgm4+mYgjIqK=rNaJJnXz4pkwfLa88?Q*~DLLY<-R zryimnp&qUNLcLhMLA^=6MZH~(P@~jEYMh#=E?4u^6>5>XQVprA)YabE! z{kmpS&6*lQjicsV&5fGBYyPSEx8`L{Z_PVRU(E-a4>f}|6Er!RT+I~CbWNUSre?Ng zu4aK|k>*NIuQy2d&~ovqGM z=c@D8`Rjsp;kt`;e`_OlB5kpjqNQm$S`gB5wN=_0ZJoA3tJj*eHmyVJ*7~#o zZAg1mdrkYaKC6CO{k-~x^-JoP)vu^uRgbBs)K}MkU$1WXr=hoTa${cOj>c5u@y2tF zU5%F;uQhfz-fw)+_j)eY25(#_Ekbfr3uj;j;sM7m0yR<}pDSGP}R)1`FK zaotJX8QnQum+q48uI?AzJ>9SRf%=j9T>TXNbbX$Frhc}5o_?i%wSJv`gMO2Ki+;O) zr(URs_16s(zx2V&bYz2$+*P`7_pEMZzLLvjWi?OC^xnkZ<+d-rkG}$=9=c47MYfs)|kFC z0Vbk}X5yH*CV@$4(wW?*nCXn^wyD?j)|_GPXU;SaG!HQ^Hy4<au#R ze(O=|S?eR~W9yTq(@oc!?l#?TdeHQ!>2Xs})2pU8wm!CgwhwHd+Gg1bY$O|G)7Z4O zMw~?X~uL`(C@<-eM2gBleWN(|*E!-u}@3*pca&;F#)I z=h*0AIY5Wlp>otY8XS6u#j)G5&jHySCmoL+J&qTSSI&OUZ0B(2Naq;mIOllh66ZSS zM(1YdHfNy||(pBU3*-IT~}SN-4om^+^gKH-J2ozRyWp7aFg9s zH{H#2%iL1ye2dC>A#%j-Z^AUCir00h8* zAfOGj2BLv@AQ|Wg90(i^{17-ExE=T<@N3{<;E%vxfhU1i!G6KaAT%&IBsetqad1NL z^I&dpN^n_lLvT}YOK^J-8)O7o!Lnd^P!^O26~SFWL(m-D9o!py5&9rBHZ(qz6Uq%u z2~7{>g=U6khvtPAhBk&ahqi{chjxaLAs~ba;X=d^IYbFnha92fp@-qD@SHFr%nKXB za5x>_A3g+ykAzQ$FNLp!uZ4dO-w59d{}Fx?eirTt_lDoK_HFIoI<+;wbxUhuE4mfa zif^U1(py=r>{d?e?$$G{k6U{p{Uf6yV^-HqLk{T6!|9~RG#ljE$oC|(z@k6YsIcru=jpNL8MJO-xJ7NPLl)otT?gkXV#h2PIGmVnURVCd>(c;z;6H;>X14#7~I} ziHnIFiQf}{CjL(RllV9BGSQoOn;e|{D4Crcp3F(+CMPGSCFdmiOdq`Fi0Q@^MF zO#PjDntGScOb<*CNe@krOpi&AOHWAWq^GB6r@u+BNf)HQO@Ei(nMS73X-pcIE=hxF zX}Te;Pn*)#^xm{B?MS;ZXC?CG|2EtFzy1H)dG!AP#BM!( diff --git a/wake.xcodeproj/xcuserdata/fairclip.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/wake.xcodeproj/xcuserdata/fairclip.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..0ff5029 --- /dev/null +++ b/wake.xcodeproj/xcuserdata/fairclip.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/wake/Theme.swift b/wake/Theme.swift index 7a3f307..dfcc994 100644 --- a/wake/Theme.swift +++ b/wake/Theme.swift @@ -23,7 +23,7 @@ struct Theme { static let accent = Color(hex: "FF6B6B") // 强调红色 // MARK: - 中性色 - static let background = Color(hex: "F8F9FA") // 背景色 + static let background = Color(hex: "FAFAFA") // 背景色 static let surface = Color.white // 表面色 static let surfaceSecondary = Color(hex: "F5F5F5") // 次级表面色 @@ -40,14 +40,18 @@ struct Theme { static let info = Color(hex: "3B82F6") // 信息色 // MARK: - 边框色 - static let border = Color(hex: "E5E7EB") // 边框色 + static let border = Color(hex: "D9D9D9") // 边框色 static let borderLight = Color(hex: "F3F4F6") // 浅边框色 - static let borderDark = Color(hex: "D1D5DB") // 深边框色 + static let borderBlack = Color.black // 黑色边框色 + static let borderDark = borderBlack // 深边框色 // MARK: - 订阅相关色 static let freeBackground = primaryLight // Free版背景 static let pioneerBackground = primary // Pioneer版背景 static let subscribeButton = primary // 订阅按钮色 + + // MARK: - 卡片相关色 + static let cardBackground = Color.white // 卡片背景 } // MARK: - 渐变色 @@ -59,9 +63,13 @@ struct Theme { ) static let backgroundGradient = LinearGradient( - colors: [Colors.background, Colors.surface], - startPoint: .top, - endPoint: .bottom + gradient: Gradient(colors: [ + Color(hex: "FBC063"), + Color(hex: "FEE9BE"), + Color(hex: "FAB851") + ]), + startPoint: .topLeading, + endPoint: .bottomTrailing ) static let accentGradient = LinearGradient( @@ -69,6 +77,12 @@ struct Theme { startPoint: .leading, endPoint: .trailing ) + + // static let creditsInfoTooltip = LinearGradient( + // colors: [Colors(hex: "FFD38F"), Colors(hex: "FFF8DE"), Colors(hex: "FECE83")], + // startPoint: .topLeading, + // endPoint: .bottomTrailing + // ) } // MARK: - 阴影 diff --git a/wake/Typography.swift b/wake/Typography.swift index 27f7b98..91ba2d3 100644 --- a/wake/Typography.swift +++ b/wake/Typography.swift @@ -60,21 +60,21 @@ struct Typography { /// - style: 文本样式 /// - family: 字体库,默认为 nil 使用默认字体库 /// - Returns: 配置好的 Font 对象 - static func font(for style: TypographyStyle, family: FontFamily? = nil) -> Font { + static func font(for style: TypographyStyle, family: FontFamily? = nil, size: CGFloat? = nil) -> Font { let fontFamily = family ?? defaultFontFamily guard let config = styleConfig[style] else { return .body } // 尝试加载自定义字体 - if let customFont = UIFont(name: fontFamily.name, size: config.size) { + if let customFont = UIFont(name: fontFamily.name, size: size ?? config.size) { let metrics = UIFontMetrics(forTextStyle: config.textStyle) let scaledFont = metrics.scaledFont(for: customFont) return Font(scaledFont) } // 如果自定义字体加载失败,回退到系统字体 - let systemFont = UIFont.systemFont(ofSize: config.size, weight: config.weight) + let systemFont = UIFont.systemFont(ofSize: size ?? config.size, weight: config.weight) let metrics = UIFontMetrics(forTextStyle: config.textStyle) let scaledFont = metrics.scaledFont(for: systemFont) return Font(scaledFont) diff --git a/wake/View/Credits/CreditsDetailView.swift b/wake/View/Credits/CreditsDetailView.swift new file mode 100644 index 0000000..8d6c496 --- /dev/null +++ b/wake/View/Credits/CreditsDetailView.swift @@ -0,0 +1,288 @@ +// +// CreditsDetailView.swift +// wake +// +// Created by fairclip on 2025/8/19. +// + +import SwiftUI + +// MARK: - 积分交易类型 +enum CreditTransactionType: String, CaseIterable { + case photoUnderstanding = "Photo Understanding" + case videoUnderstanding = "Video Understanding" + case mysteryBoxPurchase = "Mystery Box Purchase" + case dailyBonus = "Daily Bonus" + case subscriptionBonus = "Subscription Bonus" + + var creditChange: Int { + switch self { + case .photoUnderstanding: + return -1 + case .videoUnderstanding: + return -32 + case .mysteryBoxPurchase: + return -100 + case .dailyBonus: + return 200 + case .subscriptionBonus: + return 500 + } + } + + var icon: String { + switch self { + case .photoUnderstanding: + return "photo" + case .videoUnderstanding: + return "video" + case .mysteryBoxPurchase: + return "gift" + case .dailyBonus: + return "calendar" + case .subscriptionBonus: + return "star.fill" + } + } +} + +// MARK: - 积分交易记录 +struct CreditTransaction { + let id = UUID() + let type: CreditTransactionType + let date: Date + let creditChange: Int + + init(type: CreditTransactionType, date: Date, creditChange: Int? = nil) { + self.type = type + self.date = date + self.creditChange = creditChange ?? type.creditChange + } +} + +// MARK: - 积分详情页面 +struct CreditsDetailView: View { + @Environment(\.presentationMode) var presentationMode + @State private var showRules = false + + // 示例数据 + private let totalCredits = 3290 + private let expiringToday = 200 + private let transactions: [CreditTransaction] = [ + CreditTransaction(type: .photoUnderstanding, date: Calendar.current.date(byAdding: .hour, value: -2, to: Date()) ?? Date()), + CreditTransaction(type: .videoUnderstanding, date: Calendar.current.date(byAdding: .hour, value: -4, to: Date()) ?? Date()), + CreditTransaction(type: .mysteryBoxPurchase, date: Calendar.current.date(byAdding: .day, value: -1, to: Date()) ?? Date()), + CreditTransaction(type: .dailyBonus, date: Calendar.current.date(byAdding: .day, value: -1, to: Date()) ?? Date()), + CreditTransaction(type: .subscriptionBonus, date: Calendar.current.date(byAdding: .day, value: -2, to: Date()) ?? Date()) + ] + + var body: some View { + NavigationView { + ScrollView { + VStack(spacing: 0) { + // 导航栏 + navigationHeader + + // 主积分卡片 + mainCreditsCard + + // 积分历史 + creditsHistorySection + + Spacer(minLength: 100) + } + } + .background(Color(.systemGroupedBackground)) + .navigationBarHidden(true) + } + } + + // MARK: - 导航栏 + private var navigationHeader: some View { + NaviHeader(title: "Credits") { + presentationMode.wrappedValue.dismiss() + } + } + + // MARK: - 主积分卡片 + private var mainCreditsCard: some View { + VStack(spacing: 0) { + // 主要积分显示区域 + HStack { + // 左侧三角形图标 + Circle() + .fill(Color.black) + .frame(width: 80, height: 80) + .overlay( + Image(systemName: "triangle.fill") + .foregroundColor(.white) + .font(.system(size: 24, weight: .bold)) + ) + + Spacer() + + // 右侧积分信息 + VStack(alignment: .trailing, spacing: 8) { + HStack(spacing: 8) { + Circle() + .fill(Color.black) + .frame(width: 24, height: 24) + .overlay( + Image(systemName: "triangle.fill") + .foregroundColor(.white) + .font(.system(size: 8)) + ) + + Text("\(totalCredits)") + .font(Typography.font(for: .headline, family: .quicksandBold, size: 36)) + .foregroundColor(.black) + } + + Text("Expiring Today : \(expiringToday)") + .font(Typography.font(for: .body, family: .quicksand)) + .foregroundColor(.black.opacity(0.8)) + } + } + .padding(Theme.Spacing.xl) + + // 虚线分隔 + DashedLine() + .stroke(Color.black.opacity(0.3), style: StrokeStyle(lineWidth: 1, dash: [5, 5])) + .frame(height: 1) + .padding(.horizontal, Theme.Spacing.xl) + + // 积分规则展开区域 + creditsRulesSection + } + .background( + LinearGradient( + colors: [ + Color(hex: "FFB645"), + Color(hex: "FFA726") + ], + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + .cornerRadius(Theme.CornerRadius.large) + .padding(.horizontal, Theme.Spacing.xl) + .padding(.top, Theme.Spacing.xl) + } + + // MARK: - 积分规则区域 + private var creditsRulesSection: some View { + VStack(spacing: 0) { + // 规则标题按钮 + Button(action: { + withAnimation(.easeInOut(duration: 0.3)) { + showRules.toggle() + } + }) { + HStack { + Text("Credits Rules") + .font(Typography.font(for: .body, family: .quicksandBold)) + .foregroundColor(.black) + + Spacer() + + Image(systemName: showRules ? "chevron.up" : "chevron.down") + .foregroundColor(.black) + .font(.system(size: 14, weight: .medium)) + } + .padding(.horizontal, Theme.Spacing.xl) + .padding(.vertical, Theme.Spacing.lg) + } + + // 规则内容 + if showRules { + VStack(alignment: .leading, spacing: Theme.Spacing.sm) { + Text("Credits can be used for material indexing (1 credit per photo or per second of video) and for buying blind boxes (100 credits each).") + .font(Typography.font(for: .subtitle, family: .quicksand)) + .foregroundColor(.black.opacity(0.8)) + .multilineTextAlignment(.leading) + } + .padding(.horizontal, Theme.Spacing.xl) + .padding(.bottom, Theme.Spacing.lg) + } + } + } + + // MARK: - 积分历史区域 + private var creditsHistorySection: some View { + VStack(alignment: .leading, spacing: Theme.Spacing.lg) { + Text("Points History") + .font(Typography.font(for: .title, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.horizontal, Theme.Spacing.xl) + + LazyVStack(spacing: 0) { + ForEach(Array(transactions.enumerated()), id: \.element.id) { index, transaction in + CreditTransactionRow( + transaction: transaction, + isLast: index == transactions.count - 1 + ) + } + } + .background(Color(.systemBackground)) + .cornerRadius(Theme.CornerRadius.medium) + .padding(.horizontal, Theme.Spacing.xl) + } + .padding(.top, Theme.Spacing.xl) + } +} + +// MARK: - 积分交易行组件 +struct CreditTransactionRow: View { + let transaction: CreditTransaction + let isLast: Bool + + var body: some View { + VStack(spacing: 0) { + HStack(spacing: Theme.Spacing.lg) { + VStack(alignment: .leading, spacing: 4) { + Text(transaction.type.rawValue) + .font(Typography.font(for: .body, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + + Text(formatDate(transaction.date)) + .font(Typography.font(for: .caption, family: .quicksand)) + .foregroundColor(Theme.Colors.textSecondary) + } + + Spacer() + + Text("\(transaction.creditChange > 0 ? "+" : "")\(transaction.creditChange)") + .font(Typography.font(for: .body, family: .quicksandBold)) + .foregroundColor(transaction.creditChange > 0 ? Theme.Colors.success : Theme.Colors.textPrimary) + } + .padding(.horizontal, Theme.Spacing.lg) + .padding(.vertical, Theme.Spacing.lg) + + if !isLast { + Divider() + .background(Theme.Colors.borderLight) + } + } + } + + private func formatDate(_ date: Date) -> String { + let formatter = DateFormatter() + formatter.dateFormat = "MM-dd-yyyy" + return formatter.string(from: date) + } +} + +// MARK: - 虚线组件 +struct DashedLine: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + path.move(to: CGPoint(x: 0, y: 0)) + path.addLine(to: CGPoint(x: rect.width, y: 0)) + return path + } +} + +// MARK: - 预览 +#Preview { + CreditsDetailView() +} diff --git a/wake/View/Credits/CreditsInfoCard.swift b/wake/View/Credits/CreditsInfoCard.swift new file mode 100644 index 0000000..b374a4c --- /dev/null +++ b/wake/View/Credits/CreditsInfoCard.swift @@ -0,0 +1,107 @@ + // +// CreditsInfoCard.swift +// wake +// +// Created by fairclip on 2025/8/19. +// + +import SwiftUI + +// MARK: - 积分信息卡片组件 +struct CreditsInfoCard: View { + let totalCredits: Int + let onInfoTap: (() -> Void)? + let onDetailTap: (() -> Void)? + + @State private var showInfoPopover = false + + init( + totalCredits: Int, + onInfoTap: (() -> Void)? = nil, + onDetailTap: (() -> Void)? = nil + ) { + self.totalCredits = totalCredits + self.onInfoTap = onInfoTap + self.onDetailTap = onDetailTap + } + + var body: some View { + Button(action: { + onDetailTap?() + }) { + mainCreditsSection + } + .buttonStyle(PlainButtonStyle()) + .background(Theme.Colors.primaryLight) + .cornerRadius(Theme.CornerRadius.extraLarge) + .shadow(color: Theme.Shadows.small, radius: Theme.Shadows.cardShadow.radius, x: Theme.Shadows.cardShadow.x, y: Theme.Shadows.cardShadow.y) + } + + // MARK: - 主要积分显示区域 + private var mainCreditsSection: some View { + HStack(spacing: Theme.Spacing.md) { + // 积分图标和数量 + HStack(spacing: Theme.Spacing.sm) { + Text("Credits:") + .font(Typography.font(for: .subtitle, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + + Text("\(totalCredits)") + .font(Typography.font(for: .subtitle, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + } + + + // 操作按钮区域 + HStack(spacing: Theme.Spacing.sm) { + // 信息按钮 + Button(action: { + showInfoPopover = true + onInfoTap?() + }) { + Image(systemName: "questionmark.circle") + .foregroundColor(Theme.Colors.textSecondary) + .font(.system(size: 16)) + } + .popover(isPresented: $showInfoPopover, attachmentAnchor: .point(.bottom), arrowEdge: .top) { + Text("Credits can be used for material indexing (1 credit per photo or per second of video) and for buying blind boxes (100 crediteach)") + .font(Typography.font(for: .caption, family: .quicksandRegular)) + .multilineTextAlignment(.center) + .presentationBackground(Theme.Gradients.backgroundGradient) + .frame(minWidth: 240, maxWidth: UIScreen.main.bounds.width * 0.6) + .presentationCompactAdaptation(.popover) + .padding(.horizontal, Theme.Spacing.md) + .padding(.vertical, Theme.Spacing.sm) + } + + Spacer() + + // 详情按钮 + Image(systemName: "chevron.right") + .foregroundColor(Theme.Colors.textPrimary) + .font(.system(size: 14, weight: .medium)) + } + } + .padding(Theme.Spacing.lg) + } + + +} + + +// MARK: - 预览 +#Preview("Credits Info Card") { + VStack(spacing: 20) { + CreditsInfoCard( + totalCredits: 3290, + onInfoTap: { + print("Info tapped") + }, + onDetailTap: { + print("Detail tapped") + } + ) + } + .padding() + .background(Color(.systemGroupedBackground)) +} diff --git a/wake/View/Subscribe/Components/PlanCompare.swift b/wake/View/Subscribe/Components/PlanCompare.swift new file mode 100644 index 0000000..77fc88c --- /dev/null +++ b/wake/View/Subscribe/Components/PlanCompare.swift @@ -0,0 +1,165 @@ +// +// PlanCompare.swift +// wake +// +// Created by fairclip on 2025/8/20. +// + +import SwiftUI + +// MARK: - 计划对比功能数据模型 +struct PlanFeature { + let title: String + let subtitle: String? + let freeValue: String + let pioneerValue: String + let icon: String? +} + +// MARK: - 计划对比组件 +struct PlanCompare: View { + + // MARK: - 功能对比数据 + private let features: [PlanFeature] = [ + PlanFeature( + title: "Mystery Box Purchase:", + subtitle: nil, + freeValue: "3 /week", + pioneerValue: "Free", + icon: nil + ), + PlanFeature( + title: "Material Upload:", + subtitle: nil, + freeValue: "50 images and\n5 videos/day", + pioneerValue: "Unlimited", + icon: nil + ), + PlanFeature( + title: "Free Credits:", + subtitle: "Expires the next day", + freeValue: "200 /day", + pioneerValue: "500 /day", + icon: nil + ) + ] + + var body: some View { + HStack(spacing: 0) { + // 功能名称列 + featureNamesColumn + .frame(minWidth: 163) + + // Free 计划列(更宽,优先占据剩余空间) + planColumn(title: "Free", isPioneer: false) + .layoutPriority(1) + + // Pioneer 计划列(固定较窄宽度) + planColumn(title: "Pioneer", isPioneer: true) + .frame(width: 88) + } + .background(Theme.Colors.cardBackground) + .cornerRadius(Theme.CornerRadius.medium) + .shadow( + color: Theme.Shadows.small, + radius: Theme.Shadows.cardShadow.radius, + x: Theme.Shadows.cardShadow.x, + y: Theme.Shadows.cardShadow.y + ) + } + + // MARK: - 功能名称列 + private var featureNamesColumn: some View { + VStack(spacing: 0) { + // 表头 + Text("") + .font(Typography.font(for: .title, family: .quicksandBold, size: 14)) + .padding(.vertical, Theme.Spacing.sm) + .frame(maxWidth: .infinity, minHeight: 30) + + // 功能名称 + ForEach(Array(features.enumerated()), id: \.offset) { index, feature in + VStack(alignment: .leading, spacing: Theme.Spacing.xs) { + Text(feature.title) + .font(Typography.font(for: .body, family: .quicksandBold, size: 12)) + .foregroundColor(Theme.Colors.textPrimary) + .multilineTextAlignment(.leading) + + if let subtitle = feature.subtitle { + Text(subtitle) + .font(Typography.font(for: .caption, family: .quicksandRegular)) + .foregroundColor(Theme.Colors.textSecondary) + .multilineTextAlignment(.leading) + } + } + .frame(maxWidth: .infinity, minHeight: 30, alignment: .leading) + .padding(.horizontal, Theme.Spacing.sm) + .padding(.vertical, Theme.Spacing.sm) + } + } + .padding(Theme.Spacing.sm) + } + + // MARK: - 计划列 + private func planColumn(title: String, isPioneer: Bool) -> some View { + VStack(spacing: 0) { + // 表头 + VStack(spacing: Theme.Spacing.xs) { + Text(title) + .font(Typography.font(for: .title, family: .quicksandBold, size: 14)) + .foregroundColor(Color.black) + } + .frame(maxWidth: .infinity) + .padding(.vertical, Theme.Spacing.sm) + + // 功能值 + ForEach(Array(features.enumerated()), id: \.offset) { index, feature in + let value = isPioneer ? feature.pioneerValue : feature.freeValue + + Text(value) + .font(Typography.font(for: .body, family: .quicksandRegular, size: 12)) + .foregroundColor(isPioneer ? Color.black : Theme.Colors.textSecondary) + .fontWeight(isPioneer ? .semibold : .regular) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity, minHeight: 30) + .padding(.vertical, Theme.Spacing.sm) + + } + } + .frame(maxWidth: .infinity) + .background(isPioneer ? Theme.Colors.primaryLight : Color.white) + .cornerRadius(Theme.CornerRadius.medium) + .overlay( + RoundedRectangle(cornerRadius: Theme.CornerRadius.medium) + .stroke( + isPioneer ? Theme.Colors.primary : Theme.Colors.border, + lineWidth: isPioneer ? 1 : 0 + ) + ) + .padding(Theme.Spacing.sm) + + } +} + + +// MARK: - 预览 +#Preview("PlanCompare") { + ScrollView { + VStack(spacing: Theme.Spacing.xl) { + PlanCompare() + } + .padding() + } + .background(Theme.Colors.background) +} + +#Preview("PlanCompare Dark") { + ScrollView { + VStack(spacing: Theme.Spacing.xl) { + PlanCompare() + } + .padding() + } + .background(Color.black) + .preferredColorScheme(.dark) +} \ No newline at end of file diff --git a/wake/View/Subscribe/Components/PlanSelector.swift b/wake/View/Subscribe/Components/PlanSelector.swift new file mode 100644 index 0000000..d37fe54 --- /dev/null +++ b/wake/View/Subscribe/Components/PlanSelector.swift @@ -0,0 +1,135 @@ +// +// PlanSelector.swift +// wake +// +// Created by fairclip on 2025/8/19. +// + +import SwiftUI + +// MARK: - 计划选择器组件 +struct PlanSelector: View { + @Binding var selectedPlan: SubscriptionPlan? + let onPlanSelected: (SubscriptionPlan) -> Void + + private let plans: [SubscriptionPlan] = [.free, .pioneer] + + init( + selectedPlan: Binding, + onPlanSelected: @escaping (SubscriptionPlan) -> Void = { _ in } + ) { + self._selectedPlan = selectedPlan + self.onPlanSelected = onPlanSelected + } + + var body: some View { + HStack(spacing: Theme.Spacing.md) { + ForEach(plans, id: \.self) { plan in + PlanCard( + plan: plan, + isSelected: selectedPlan == plan, + onTap: { + selectedPlan = plan + onPlanSelected(plan) + } + ) + } + } + } +} + +// MARK: - 单个计划卡片 +struct PlanCard: View { + let plan: SubscriptionPlan + let isSelected: Bool + let onTap: () -> Void + + var body: some View { + Button(action: onTap) { + ZStack { + // 主卡片内容 + VStack(spacing: Theme.Spacing.sm) { + // Popular 标签 + if plan.isPopular { + VStack { + HStack { + Spacer() + Text("Popular") + .font(Typography.font(for: .caption, family: .quicksandRegular)) + .foregroundColor(Color.white) + .padding(.horizontal, Theme.Spacing.sm) + .padding(.vertical, Theme.Spacing.xs) + .background(Color.black) + .cornerRadius(Theme.CornerRadius.round, corners: [.bottomLeft]) + } + Spacer() + + VStack { + // 计划名称 + Text(plan.displayName) + .font(Typography.font(for: .title, family: .quicksandBold, size: 18)) + .foregroundColor(plan == .pioneer ? Theme.Colors.textPrimary: Theme.Colors.textTertiary ) + + // 价格 + if plan == .pioneer { + Text(plan.price) + .font(Typography.font(for: .body, family: .quicksandBold, size: 20)) + .foregroundColor(Theme.Colors.textPrimary) + } + } + Spacer() + Spacer() + } + } + else { + // 计划名称 + Text(plan.displayName) + .font(Typography.font(for: .title, family: .quicksandBold, size: 18)) + .foregroundColor(plan == .pioneer ? Theme.Colors.textPrimary: Theme.Colors.textTertiary ) + + // 价格 + if plan == .pioneer { + Text(plan.price) + .font(Typography.font(for: .body, family: .quicksandBold, size: 20)) + .foregroundColor(Theme.Colors.textPrimary) + } + } + } + .frame(maxWidth: .infinity) + .frame(height: 120) + .background( + plan == .pioneer ? + Theme.Colors.primary : + Theme.Colors.surface + ) + .overlay( + RoundedRectangle(cornerRadius: Theme.CornerRadius.medium) + .stroke( + isSelected ? Theme.Colors.borderDark : Theme.Colors.border, + lineWidth: 2 + ) + ) + .cornerRadius(Theme.CornerRadius.medium) + } + } + .buttonStyle(PlainButtonStyle()) + } +} + + +// MARK: - 预览 +#Preview("Plan Selector") { + @State var selectedPlan: SubscriptionPlan? = .pioneer + + VStack(spacing: 20) { + PlanSelector( + selectedPlan: $selectedPlan, + onPlanSelected: { plan in + print("Selected plan: \(plan.displayName)") + } + ) + + } + .padding() + .background(Color(.systemGroupedBackground)) +} diff --git a/wake/View/Subscribe/Components/SubscribeButton.swift b/wake/View/Subscribe/Components/SubscribeButton.swift new file mode 100644 index 0000000..307cdad --- /dev/null +++ b/wake/View/Subscribe/Components/SubscribeButton.swift @@ -0,0 +1,69 @@ +import SwiftUI + +// MARK: - Subscribe Button +struct SubscribeButton: View { + let title: String + let isLoading: Bool + let action: () -> Void + + init( + title: String = "Subscribe", + isLoading: Bool, + action: @escaping () -> Void + ) { + self.title = title + self.isLoading = isLoading + self.action = action + } + + var body: some View { + VStack(spacing: Theme.Spacing.xs) { + Button(action: { + guard !isLoading else { return } + action() + }) { + HStack(spacing: Theme.Spacing.sm) { + if isLoading { + ProgressView() + .progressViewStyle(CircularProgressViewStyle(tint: Theme.Colors.textInverse)) + } + + VStack { + Spacer() + Spacer() + Text(title) + .font(Typography.font(for: .body, family: .quicksandBold)) + Spacer() + // Fixed subtitle text as requested + Text("And get 5,000 Permanent Credits") + .font(Typography.font(for: .caption, family: .quicksandRegular)) + .foregroundColor(Theme.Colors.textPrimary) + Spacer() + Spacer() + } + } + .frame(height: 56) + .frame(maxWidth: .infinity) + .background(Theme.Colors.primary) // primary color background + .clipShape(Capsule()) + .shadow( + color: Theme.Shadows.buttonShadow.color, + radius: Theme.Shadows.buttonShadow.radius, + x: Theme.Shadows.buttonShadow.x, + y: Theme.Shadows.buttonShadow.y + ) + } + .buttonStyle(.plain) + .disabled(isLoading) + } + } +} + +#Preview("SubscribeButton") { + VStack(spacing: Theme.Spacing.xl) { + SubscribeButton(isLoading: false) {} + SubscribeButton(isLoading: true) {} + } + .padding() + .background(Theme.Colors.background) +} \ No newline at end of file diff --git a/wake/View/Subscribe/Components/SubscribePolicy.swift b/wake/View/Subscribe/Components/SubscribePolicy.swift new file mode 100644 index 0000000..e69de29 diff --git a/wake/View/Subscribe/Components/SubscriptionStatusBar.swift b/wake/View/Subscribe/Components/SubscriptionStatusBar.swift index 1a92267..48231b7 100644 --- a/wake/View/Subscribe/Components/SubscriptionStatusBar.swift +++ b/wake/View/Subscribe/Components/SubscriptionStatusBar.swift @@ -61,21 +61,21 @@ struct SubscriptionStatusBar: View { var body: some View { HStack(spacing: 16) { - VStack(alignment: .leading, spacing: 8) { + VStack(alignment: .leading, spacing: 20) { // 订阅类型标题 Text(status.title) - .font(.system(size: 28, weight: .bold, design: .rounded)) + .font(Typography.font(for: .headline, family: .quicksandBold, size: 32)) .foregroundColor(status.textColor) // 过期时间或订阅按钮 if case .pioneer(let expiryDate) = status { VStack(alignment: .leading, spacing: 4) { Text("Expires on :") - .font(.system(size: 14, weight: .medium)) - .foregroundColor(status.textColor.opacity(0.8)) + .font(Typography.font(for: .body, family: .quicksandRegular)) + .foregroundColor(status.textColor.opacity(0.7)) Text(formatDate(expiryDate)) - .font(.system(size: 16, weight: .semibold)) + .font(Typography.font(for: .body, family: .quicksandRegular)) .foregroundColor(status.textColor) } } else { @@ -83,12 +83,12 @@ struct SubscriptionStatusBar: View { onSubscribeTap?() }) { Text("Subscribe") - .font(.system(size: 14, weight: .semibold)) + .font(Typography.font(for: .title, family: .quicksandRegular, size: 16)) .foregroundColor(Theme.Colors.textPrimary) - .padding(.horizontal, 20) - .padding(.vertical, 8) - .background(Theme.Colors.subscribeButton) - .cornerRadius(Theme.CornerRadius.large) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .background(Theme.Gradients.backgroundGradient) + .cornerRadius(Theme.CornerRadius.extraLarge) } } } diff --git a/wake/View/Subscribe/SubscribeView.swift b/wake/View/Subscribe/SubscribeView.swift index ab3eb10..d90c682 100644 --- a/wake/View/Subscribe/SubscribeView.swift +++ b/wake/View/Subscribe/SubscribeView.swift @@ -38,7 +38,7 @@ struct SubscriptionFeature { } struct SubscribeView: View { - @State private var selectedPlan: SubscriptionPlan = .free + @State private var selectedPlan: SubscriptionPlan? = .pioneer @State private var isLoading = false @Environment(\.presentationMode) var presentationMode @@ -57,16 +57,23 @@ struct SubscribeView: View { navigationHeader // 当前订阅状态卡片 - currentSubscriptionCard + currentSubscriptionCard // 积分信息 creditsSection - // 订阅计划选择 - subscriptionPlansSection - - // 特别优惠提示 - specialOfferBanner + VStack { + // 订阅计划选择 + subscriptionPlansSection + + // 特别优惠提示 + specialOfferBanner + } + .background(Theme.Colors.cardBackground) + .cornerRadius(Theme.CornerRadius.medium) + .padding(.horizontal, Theme.Spacing.lg) + .padding(.vertical, Theme.Spacing.lg) + // 功能对比表 featureComparisonTable @@ -80,7 +87,7 @@ struct SubscribeView: View { Spacer(minLength: 100) } } - .background(Color(.systemGroupedBackground)) + .background(Theme.Colors.background) .navigationBarHidden(true) } } @@ -94,197 +101,127 @@ struct SubscribeView: View { // MARK: - 当前订阅状态卡片 private var currentSubscriptionCard: some View { - VStack(spacing: 0) { - HStack { - VStack(alignment: .leading, spacing: 8) { - Text("Free") - .font(Typography.font(for: .headline, family: .quicksand)) - .fontWeight(.bold) - - Button(action: { - // 订阅操作 - }) { - Text("Subscribe") - .font(Typography.font(for: .subtitle, family: .quicksand)) - .fontWeight(.medium) - .foregroundColor(.black) - .padding(.horizontal, 16) - .padding(.vertical, 8) - .background(Color.orange) - .cornerRadius(20) - } - } - - Spacer() - - // 播放按钮图标 - Circle() - .fill(Color.black) - .frame(width: 60, height: 60) - .overlay( - Image(systemName: "play.fill") - .foregroundColor(.white) - .font(.title2) - ) + SubscriptionStatusBar( + status: .pioneer(expiryDate: Date()) , + onSubscribeTap: { + // 订阅操作 + handleSubscribe() } - .padding(20) - .background(Color.orange.opacity(0.2)) - .cornerRadius(16) - .padding(.horizontal, 20) - } + ) + .padding(.horizontal, Theme.Spacing.xl) } // MARK: - 积分信息 private var creditsSection: some View { - HStack { - Text("Credits: 3290") - .font(Typography.font(for: .body, family: .quicksand)) - .fontWeight(.medium) + VStack(spacing: 16) { + CreditsInfoCard( + totalCredits: 3290, + onInfoTap: { + // 显示积分信息说明 + }, + onDetailTap: { + // 跳转到积分详情页面 + } + ) - Button(action: { - // 积分信息操作 - }) { - Image(systemName: "info.circle") - .foregroundColor(.gray) - } - - Spacer() - - Image(systemName: "chevron.right") - .foregroundColor(.gray) - .font(.caption) } - .padding(.horizontal, 20) - .padding(.vertical, 16) - .background(Color(.systemBackground)) - .cornerRadius(12) - .padding(.horizontal, 20) - .padding(.top, 20) + .padding(.horizontal, Theme.Spacing.xl) + .padding(.top, Theme.Spacing.xl) } // MARK: - 订阅计划选择 private var subscriptionPlansSection: some View { - HStack(spacing: 16) { - // Free 计划 - SubscriptionPlanCard( - plan: .free, - isSelected: selectedPlan == .free, - onTap: { selectedPlan = .free } - ) - - // Pioneer 计划 - SubscriptionPlanCard( - plan: .pioneer, - isSelected: selectedPlan == .pioneer, - onTap: { selectedPlan = .pioneer } - ) - } - .padding(.horizontal, 20) - .padding(.top, 20) + PlanSelector( + selectedPlan: $selectedPlan, + onPlanSelected: { plan in + print("Selected plan: \(plan.displayName)") + } + ) + .padding(.horizontal, Theme.Spacing.xl) + .padding(.top, Theme.Spacing.xl) } // MARK: - 特别优惠横幅 private var specialOfferBanner: some View { - Text("First 100 users get a special deal: just $1 for your first month!") - .font(Typography.font(for: .caption, family: .quicksand)) - .multilineTextAlignment(.center) - .padding(.horizontal, 20) - .padding(.top, 12) - .foregroundColor(.secondary) + HStack(spacing: 0) { + Text("First") + .font(Typography.font(for: .footnote, family: .quicksandRegular)) + .foregroundColor(Theme.Colors.textPrimary) + + Text(" 100") + .font(Typography.font(for: .footnote, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + + Text(" users get a special deal: justs") + .font(Typography.font(for: .footnote, family: .quicksandRegular)) + .foregroundColor(Theme.Colors.textPrimary) + + Text(" $1") + .font(Typography.font(for: .footnote, family: .quicksandBold)) + .foregroundColor(Theme.Colors.textPrimary) + + Text(" for your first month!") + .font(Typography.font(for: .footnote, family: .quicksandRegular)) + .foregroundColor(Theme.Colors.textPrimary) + } + .multilineTextAlignment(.center) + .padding(.horizontal, Theme.Spacing.lg) + .padding(.top, Theme.Spacing.sm) + .padding(.bottom, Theme.Spacing.lg) } // MARK: - 功能对比表 private var featureComparisonTable: some View { - VStack(spacing: 0) { - // 表头 - HStack { - Spacer() - Text("Free") - .font(Typography.font(for: .subtitle, family: .quicksand)) - .fontWeight(.medium) - .frame(maxWidth: .infinity) - .foregroundColor(.gray) - Text("Pro") - .font(Typography.font(for: .subtitle, family: .quicksand)) - .fontWeight(.medium) - .frame(maxWidth: .infinity) - .foregroundColor(.gray) - } - .padding(.vertical, 16) - .background(Color(.systemGray6)) - - // 功能行 - ForEach(Array(features.enumerated()), id: \.offset) { index, feature in - FeatureRow(feature: feature, isLast: index == features.count - 1) - } - } - .background(Color(.systemBackground)) - .cornerRadius(12) - .padding(.horizontal, 20) - .padding(.top, 20) - .shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1) + PlanCompare() + .padding(.horizontal, Theme.Spacing.lg) } // MARK: - 订阅按钮 private var subscribeButton: some View { VStack(spacing: 12) { - Button(action: { - handleSubscribe() - }) { - if isLoading { - HStack { - ProgressView() - .progressViewStyle(CircularProgressViewStyle(tint: .white)) - .scaleEffect(0.8) - Text("Subscribe") - .font(Typography.font(for: .body, family: .quicksand)) - .fontWeight(.semibold) - } - } else { - Text("Subscribe") - .font(Typography.font(for: .body, family: .quicksand)) - .fontWeight(.semibold) - } - } - .foregroundColor(.white) - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background(Color.blue) - .cornerRadius(25) - .disabled(isLoading) - - Text("Get 5,000 Permanent Credits") - .font(Typography.font(for: .caption, family: .quicksand)) - .foregroundColor(.secondary) + SubscribeButton( + title: "Subscribe", + isLoading: isLoading, + action: handleSubscribe + ) } - .padding(.horizontal, 20) - .padding(.top, 30) + .padding(.horizontal, Theme.Spacing.xl) + .padding(.top, Theme.Spacing.lg) } // MARK: - 法律链接 private var legalLinks: some View { HStack(spacing: 8) { - Button("Terms of Service") { + Button(action: { // 打开服务条款 + }) { + Text("Terms of Service") + .underline() } Text("|") .foregroundColor(.secondary) - Button("Privacy Policy") { + Button(action: { // 打开隐私政策 + }) { + Text("Privacy Policy") + .underline() } Text("|") .foregroundColor(.secondary) - Button("Restore Purchase") { + Button(action: { // 恢复购买 + }) { + Text("Restore Purchase") + .underline() } } - .font(Typography.font(for: .caption, family: .quicksand)) + .font(Typography.font(for: .caption, family: .quicksandRegular)) .foregroundColor(.secondary) - .padding(.top, 16) + .padding(.top, Theme.Spacing.sm) } // MARK: - 订阅处理 @@ -299,91 +236,6 @@ struct SubscribeView: View { } } -// MARK: - 订阅计划卡片 -struct SubscriptionPlanCard: View { - let plan: SubscriptionPlan - let isSelected: Bool - let onTap: () -> Void - - var body: some View { - Button(action: onTap) { - VStack(spacing: 12) { - if plan.isPopular { - HStack { - Spacer() - Text("Popular") - .font(Typography.font(for: .caption, family: .quicksand)) - .fontWeight(.medium) - .foregroundColor(.white) - .padding(.horizontal, 12) - .padding(.vertical, 4) - .background(Color.black) - .cornerRadius(12) - } - .padding(.top, -8) - } - - Text(plan.displayName) - .font(Typography.font(for: .title, family: .quicksand)) - .fontWeight(.bold) - .foregroundColor(plan == .pioneer ? .white : .gray) - - Text(plan.price) - .font(Typography.font(for: .body, family: .quicksand)) - .fontWeight(.medium) - .foregroundColor(plan == .pioneer ? .white : .gray) - - Spacer() - } - .frame(maxWidth: .infinity, minHeight: 120) - .padding(16) - .background(plan == .pioneer ? Color.orange : Color.white) - .cornerRadius(16) - .overlay( - RoundedRectangle(cornerRadius: 16) - .stroke(isSelected ? Color.blue : (plan == .free ? Color.blue : Color.clear), lineWidth: 2) - ) - .shadow(color: Color.black.opacity(0.1), radius: 4, x: 0, y: 2) - } - } -} - -// MARK: - 功能对比行 -struct FeatureRow: View { - let feature: SubscriptionFeature - let isLast: Bool - - var body: some View { - HStack { - Text(feature.name) - .font(Typography.font(for: .subtitle, family: .quicksand)) - .fontWeight(.medium) - .frame(maxWidth: .infinity, alignment: .leading) - .foregroundColor(.primary) - - Text(feature.freeValue) - .font(Typography.font(for: .caption, family: .quicksand)) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .foregroundColor(.gray) - - Text(feature.proValue) - .font(Typography.font(for: .caption, family: .quicksand)) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .foregroundColor(.gray) - } - .padding(.vertical, 12) - .padding(.horizontal, 16) - .background(Color(.systemBackground)) - - if !isLast { - Divider() - .padding(.leading, 16) - } - } -} - #Preview { SubscribeView() }