From c6be398e5af43b417a4b65ab153672e7e45beb4d Mon Sep 17 00:00:00 2001 From: Alexandre Date: Fri, 16 Jan 2026 11:28:26 +0100 Subject: [PATCH] Update version --- .DS_Store | Bin 10244 -> 10244 bytes PortfolioJournal.xcodeproj/project.pbxproj | 8 +- .../UserInterfaceState.xcuserstate | Bin 113417 -> 113649 bytes .../xcschemes/PortfolioJournal.xcscheme | 3 + PortfolioJournal/App/ContentView.swift | 66 ++- .../App/PortfolioJournalApp.swift | 1 + PortfolioJournal/Configuration.storekit | 90 ++++ PortfolioJournal/Models/CoreDataStack.swift | 7 +- .../PortfolioJournal.entitlements | 2 +- .../Repositories/CategoryRepository.swift | 9 +- .../Repositories/GoalRepository.swift | 9 +- .../InvestmentSourceRepository.swift | 9 +- .../Resources/GoogleService-Info.plist | 4 +- PortfolioJournal/Resources/Info.plist | 263 +++++++++++ .../Resources/en.lproj/Localizable.strings | 1 + .../Resources/es-ES.lproj/Localizable.strings | 2 + PortfolioJournal/Services/ImportService.swift | 26 +- .../Utilities/Constants/AppConstants.swift | 1 - .../ViewModels/SourceDetailViewModel.swift | 10 + .../Views/Accounts/AccountEditorView.swift | 72 +-- .../Views/Accounts/AccountsView.swift | 27 ++ .../Views/Components/LoadingView.swift | 29 ++ .../Views/Dashboard/DashboardView.swift | 2 +- .../Views/Onboarding/OnboardingView.swift | 2 +- .../Views/Premium/PaywallView.swift | 15 +- .../Views/Settings/ImportDataView.swift | 139 +++++- .../Views/Settings/SettingsView.swift | 12 +- PortfolioJournalWidget/InvestmentWidget.swift | 445 +++++++++++++----- 28 files changed, 1061 insertions(+), 193 deletions(-) create mode 100644 PortfolioJournal/Configuration.storekit diff --git a/.DS_Store b/.DS_Store index 18741fe52db028119653064f4920cacafb750350..fca6afbcbcfade75251b7f40e5d169b5615ee72d 100644 GIT binary patch delta 54 zcmZn(XbITxRh%hUck+61i^=*DJZxpcPeSB-Cp${GO}3VB*nC_JPZsB OQVanM`3yx2B@6&mTM>i+ diff --git a/PortfolioJournal.xcodeproj/project.pbxproj b/PortfolioJournal.xcodeproj/project.pbxproj index 0d15600..785356e 100644 --- a/PortfolioJournal.xcodeproj/project.pbxproj +++ b/PortfolioJournal.xcodeproj/project.pbxproj @@ -306,6 +306,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -343,6 +344,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -412,7 +414,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 26.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -469,7 +471,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 26.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -493,6 +495,7 @@ INFOPLIST_FILE = PortfolioJournalWidget/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Portfolio Journal Widget"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -525,6 +528,7 @@ INFOPLIST_FILE = PortfolioJournalWidget/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Portfolio Journal Widget"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/PortfolioJournal.xcodeproj/project.xcworkspace/xcuserdata/alexandrev.xcuserdatad/UserInterfaceState.xcuserstate b/PortfolioJournal.xcodeproj/project.xcworkspace/xcuserdata/alexandrev.xcuserdatad/UserInterfaceState.xcuserstate index 117fd35331cc19cd4f562c0404b94fa6a8e1208e..ed293571b8cc56aaf0dca6c146940d1d4fd6d1e9 100644 GIT binary patch literal 113649 zcmeEvcVHA%*Z15zGuz8-vYTzmCXmocC3M7e2pvLiAtajuX=D>1iaM8K2gMGGLPD=n zM5&^pq9O{|z={p*0wM}1-?=k8o4^M2)jaR>{qc&s*`2xlciKJY+}X*Mr6s=VgoJk( z#9)SHIEH6bjGEDnj+ySQ@|9GSkBP~v$}cW~Z^L7%D=J6FR7{@Y&9C-_FzEKBxq^96 zPJeH$w;M9Cvz8b zH**j30JD@?#?&$O%yMQ0vzl4YY+{~f_AxIoFETGN`Va-V{m}q45Dh|u(FimWjY6Z*M3jdnqhd4_m7NC^asXRh1FP(4cLfnI1Jmd3y0$<+yb}6J#bIl3*Ufy;~Q}bPQ__B9cSQdJP;4U zgYh^#9v9##cq*>IK3t7!a4o(G--`R-+wdGb7vGKV!S~?@@k4kKUV@k5&3Fsminrls z@OJzxeh%-zFX8?8W&8?$9e;$sz~AAY@L7BwU&NPLhUHitt7lEDnHAW!Y&*6++kx%K z#U>|^XAb}{=n`vkj$UB#|u*RUJd9qdka7rUF?!@kD8&c4AO zWZz^@u%EMEuwSxYv0t+%*;DK{>`&~^>^b%_$8d<#a|X`HnK&zF<03c@7s=hg_2zEm zQn*wujZ5b;xJ)jK>%;ZsvblcTC~h1#o}0wwabB*Fo5D@yD!59nnycYzxtq9Kx!bro z++41XtLK(;E4Y>1DsDBmhFi<6lbq3Wr+QI(>~P-UvJ zRsB?hRD)GHs^O~9sxhhws)?$}s(e+Es#sO3DpO5URjH<{W~gpf%~FXfqME0=U3ItW z9@TxS`&AFA9#$<X7O!)!VAWsw1kS zs&`cHs*b5XQ=L+Mqxx2LMs-&8i|S9+Wi_KlYF@2X>(n9YP<01&M|G?^PMxIguI{1k zsZLjCs58}r)j8@>>Rk0Cb)LFJJw-iRJx4uPJx_hR`VRG->bul;tM5_YtG-|TsQNMW zBK0zLow{DVLA_DEN&U2XoBBERKJ^Rg7u7GR_p1-8-&B94{zm-O?OQXO;1fP%?+B~nj1AKnp91iCQCC=Ge|R7GfFdBGe(oIDbRQ| zg_$F?7+qBPU_h|QOpVz*oeN%f_ zdqjIw`=RzD?JwHjw3l^iokpkCh3f1&w=P;2qidy$)y3(ubp3Qgbz^j6b>nniU5Tzt zSEHM*o1wc+C+Z&4J)x`Dt<$a7ZO}cd+ogM6_p0uI?ls+E-4Wflx*v7tbbsjn)LquA z^%}iaAF8+O-TG*KjJ}sXMc+q1SU*HRR6kCitIyX@)tBna^fmhF`UUz2^o#V%^mY1r z{RaJJ{WJPK`n~$+^{?s==s(kcssB#@z5WONIsLEt^ZLsM#()fZgV_*ja2vu6$%bx* z8x1LjR719*pP|2Dgkg+fg28JjG!z+%4V8vzhPw>&4G$R}HY_nbX?V)8#<0P#*|5W~ z)3D3%l3~B$Bg1EglZKxRKO0UPE*dTyS)<-)FdB_EW0*0{7;j84CK{8Bos7xG&c-gr zuEuW0UdD7|hB4DP&^X9A*f_>G);P{M-Z;rvU@SG38Ox2+jWdk*86Pw*Hr5&IjmwQ2 zja!V{jeCvH8}}Ix7+*7zcc=1{MC5g_?w9_Arm$k zOh%K*WHyDG?50Rll&OWOrK!ECgDKsVVahaRnfjRenzBv(O#Mv*Oao0rO`}bdOnIis zrYWYWrW(_9(+ty0(=3x{y3=%*X_;w-X}xKi=^4{@(>~LF(*e`lro*NqrsJj$O=nHN zn9iAgHJvy8X8PT9!F17d$@GUAnKfpuS!WJ0hnlVCaC3y&V{U71XKruqV2(F;GWRt1 zG7mS8Hs_j)%*Eysv(G%ke6x9ud9Hb$dA@mpd8K)+d9!(kd8c`o`6csy^ULP9%ty`d zn?E&wX8z55Nniy|FbGD$Bshd{AxdZ~v=iD3NkS)KpfE@nCX5lr3X_F=p+G1V%7k)Z zrZ7toh5Lnt!UMvC!b8Ht!Xv_?!c)RhVVO`T)C+5bwZb}KtFTQtD7-DaFMKL|CY%ty z5xy0^6V3_03x5cIT2vObCDIaYX>aLZ>1au|bhdP{^tRk+NwM^^46+QfXvcj^`vdXgB^0Z~MEQBg7LD8PX=CZAeN;YDij0dPqh{W=K{@pOC&G*&+Qx28E0W z85uGvBsXMINM1-u$dr(&AvGb>LuQ1`44D-ohLDiELhcT!3t1VmA>^5m?IF*Gyb$to z$ZH{oLym+T5BV_UY{)Mm=R$rBIUn*{$nPN+LN10}3i%@xg=#{DP)le?Xn1Hus3$Zs zG&;0RXnbfwXkuvh&>o?~LPv&92%Q*O7+Mrs99kJVEwn0hR;U;{H*{X;{LlrVt3%g^ zZVlZQx;u1F=-$u+p$9|X4*ekXSm^Q4Z$r<7o(=sa^g`&x&`Va%%3FWYb8Yi%x7+Tr&9^;jd(5`Tw%GQ#?Frjb+j84#+eX_a+b-K~+aB9q+w-

;_^^bq#IWvReZu;NWry_(8x%GyY-HHDu<>CN!X}61hZTff zvNLvM=j|%H&aStc?SkEEx7nR`m)&EJv`5=x>}~Ds?6LMZdy>7Ay{o;Oy_fw4d#XLn zo@MW2?{6PqA7USBA7LM9A8Q|H&$Umo7udb_68jW;xxK>fvsc?^+H38%*l)GZw$HKO zVZYOUuYJCKq5T2-Blbt_kK3QHFSReTuduJQueGnUZ?Zpa-)4WtzQexLzSsV|{U!T; z`vLoF_BZW^>__ZJ?eE(^uzzI#*nYzPx&3SVN&9#9@9jU^PutJgf3;t*U$kF#Fb>Ya zJG2g+!{jhKLLF9z!{Ky9I6RJ)j%Y_4M_WfnN30{!k>u#&=<4X{=;cUpq&hMkS&n{= z{*J+pA&%jW5sopAv5tw3Tt~j6z)|cdag;gA9aWC$j+-2}I%Yd=ciin*;CR6Ch~o*z z5=Xsbm1CV_lVhvnS;sEN^NyDsuQ}dy9Cp0xIOh1+al-MH;~U2hjYZk1sMGFrJ0qRZ&Nj{t&Uj}hXIE!WXR0&Pne80t9O@k59OIne%yW93CC)PEG-r*o z)_IGQIOjRne0jaZPnqxN2OruA5x9y6$z| z?^@`3*!75OvFmZyQ?8}1<*pU3O|GY1n_XL6TV2n(cDnYvUUt3WdewEnbzM1f z>qFN^uFqUwxW07#==#a^v+K0$oa;B&?{3!3xp}wBt#j+$W_O4?)a`ahx})43-LdXC zcf32no#;+-cX9V}-{9`;&T{v0_jPBx`?&|ZbKG8cp}WXk>@IOnaZh!Zy35?t+%@j$ z?wj1Vy63p(y63s)yBE0cbKmb?=ziE;?_T9z?OyNR;NI-s;@<9l*1gNU+x?FF1NW!y zlkQXQZ`^0y=iL{>*>EnL4>yLJ!dr*84^Is59^NCoXLx#eMtElU;P9OAQQ^7alfq|) z&kCOtJ~w<``26q%;rE3v3SSbwEPPG)+VFMZTf?`79}Isx{QdAx!#@i@5&m8HPvK|7 zFNR-=;3D{lh=>*uZ6gvQ5+jl#dPMY$=oOI_(Jx|9#Ndcg5u+mtB8nqQBFZAlBdQ{N z5i=rYM$C#3Bj!fj8L=SZfrtkq9*=k;VoAi45i26rM{JGQ8Sz5ITMbcYEf09`!utS>##ldD2to zS>ajjdCs%Lv(vN7v)i-Bv)A*2XTRrF&+DEyJ#Txy_MG&b@_gg@*7Kd`d(RJ^A3Z;L ze)gR9objCX{1VATqDUOcMsksSq$*M!X^gZ-IwGBsu1I%ecx3CyHj(Wkdqnn(>=k)K zWbeq-$g~kL)Y#;%X{oVk8CmJES(#lDx+W*3cIw_GHCM1^ zXJn45sG91l%**#?ROHu`dCRMno?T2d({VN9X2O{W#=}H1QA`V_rO1maQ7vjjt*8_A zqG2@?!?a>r!+R9dj{X&mqDeHvyG|6Oza4W08||m0yr5!6wl51Nmy=)R^_EWzT+OP= zEA!?Gv2dYpo^N1DQ5ASY3P$FY)_8qcRTX7}a)x<*)fH8FlS{plrz9hjlBRMT0HaWFxMr`-YE?Kcj-BJ^}r6y-}N$u1nS8z6rrJ|yA za$Z%oGL~Gy(Qr>1XW*6whL)6&9F^FuYgA(A#H6ThU6P^_;9p|*BzQ|m?jEI8;ONez zGac73J(!+MFXjfOH*+JC!lW{3qD2f5Lq)4-6T?Ki=n$Q20ESE^i|NDkWwM!m@NED9 z;SyJgtHn*?(*$LTW`g>N0E_@5%PFpyF(_|(Nl_lGuzV@-HMPnM>uiBiBdSYEOR7t} zzELFw)x~nL>~dcvc(y948j1yKHY%1`P@^gpAiFZbZcXCZp5nXp>0D>@#Y#bC5k@m!rsH~M3^SG)$BbttFcX85^ie1GaVxCwg&JsoOE^&dl zSe!_grqk&BiUMyOOg+22+FM#$Qsgbq_of%;RmTM;8JAvB092Oh^MOw=ue>@}a0hDj zFKJwGKt+)+R|vnxU1^%&8thY5QB#@YErmq|MTWl+~ zt7GOe^ThUI2MVD*pQ4o~F+R+g`e*a#!sZGg(j5?>)!F5hHPyqtGXcApu3a-z)6)_% zW3##?C&wlycIg(Invs+ko8GBgMtVjrPbalNwP|%LcKF9^U4dZYPaQ8b^Wpyny6N)9+7m` zN@mqkF*}aSi`Ji7J^QbzRFcLNL4^n+WX>?U>>dx$;7Ug8ZanH|hdW*5l2J)nkq zi#LjcK<*8O^@6pcG8jggKQ+Cgtg^}r99vN?DHtFVxFvDm@T$CWUkR*-G#yw;dq!HH zz%o*vfqRqz{LO*j99&*nJFKR>9Hc;6X+{22A606N7A9ASpdI^5Qb_`RS3_xkYXVm0 zc7S=4>A0MEjd`7UgE=Ush^b@$gTL|5P^pe0$gi?L;rhBu?L7wN8mewk*qz@S(%Ue3U;*!z= zs3WaJuHaF6ypj!p%Cl+LGKL>8pRQz%F~^w?nU9!{nNP$_F-z+$}+#-S-lO3e1%>nw&^!v{OO@jh<#MF&)=3XPC3h zFU&dSSLQtP8}mDJfw?FS6^DsA;&5?VuKW`KK}rUk0R-*JtkYOc`YdL{kZ<{A=QZcWx#t*+NhPIXmH zesxV1a6|V%xxcR~%LQDKMN zhPPluwj_iCx0La;L+zQcrAx&knVIiLv2|3-%Ch;2UUER@RD&K?Y9^p0CTtms5{s9i zPT~~Wf*Ex|T~W7O!397pNtX znh(|&=wjHLc*m50Sd@l6!6%t>ph~HroaoD^JB}e0K9Ic?<(*Prz3cLZvW4$1U0SC# z)amrmjQ_vreNpnKI-@B%MO-a?iB7rwZRvx?5);>}|L_qb$Bg%uPrFGjiIDskHjP*Q zH%D3^)D!iBEfWa)Qh6gaxTd)B{r0kRxStjB;`d7mQAh#Ukb{kgqVub zP&&#G%f$+@Qk=FNWuZQ(FUl6H#2RtBSo^<5h(pjYN=`#X-!haVR@41AwKke0!NC?> zel-F8^V9*2c6e1qMYV|5=nZyvi$Z%}~EBWT|Ro5K1Hq%HLZ~NuwaGrnQGy;0T!RA5g715aH8sn z!{~H1@=+`m*(2c*p2(&wWySof^F#$qVW{6Sda1}mrBIq;^;s7ntttAc3PRY{myb(nbz!Tk~NDTEol+!+s-}cZVV6;$29$IL3Se_Q$u( z_Y4>jh==3~fl6JFuq_~&f~HXPMkzq`8K@A_CGLd;i7n`m%p_8;PK*&26;FMMBYpw+0U;g*;fBb=FN{@eWJB_>1vH&b%sZ_h(4m#>CM9{^Qw!- zz-G@ovoCB7>kURz6NVeu(*wZ{FD|W3FZSk7%`T_ni)xb6INywtLeSn52IiHNN5Q7A zqAIq;S5ZnmNl`v3!Skakt0)&#*G9GR73WoX3))2G=aom5S5!w$_C{4HR&qg9A^4o4 z^58~!poM&D{m-lxFbvib3Zo0j75ey1=#rbfRZ)c%RZ&m~d>tUz!M2?YQvvxERaWDx zjw%LwJ8E#H|5i1yU`MIjHX}x4XS5MmXw>GYH-y>22>{*%Z?!LOW;AkphcIv&JZRb_!QxW z0efI=(!t)3s;-DCYhsN`sYUsG!X9Ys0n z3`Y3d(y`0{e_~)xMo(Sqc6DvqHlf2k7i$qPh35S%LHG~XVh*~KuEkt5 z58aOL5Q#WjoFmSajoEwrYccPC(U^S@JxrJSA@TNQ=n?Ub>)H^CwfZ=qaOZyjg=24> z{QPgDu=L-c@Fc2l(vn*amfT9TT)Z1BxqIL}K#^4@*#d{k_^ch&3 z`GYMibCv2!>+|naSIoziUtioLIMk54V0VRkqM~Ekw(Ag^kd)k|TaRA7Q;uk~I^$Kk ztWIyBPIPcU`l@M!1^i6;Q>pjc9&`=d=0#qrWf0hJ6TQ^GLp@cJxdFQc5EtieSqaiz zqYbsy>-E-=lJ4_?l&2Novcp#IbXuFxoKV1Rk(yXz@4OUBM%e1~dbk=XUxkLBg{v(r z&}_?`)XGZf7F=o72ClRoGtBFgT*p4pR#3?XciOjszFNb#j!MI6dbk{CSq>wMADv!N z<)widD3BQF<9R61$+8^A7!TJwD-~~e1g>|rEOWxe?#jj1^Wb7n%Q8C38v-pHfQvWU z>YTJ_s!}w**RpiDo{_bJwwwuO!qqMxP^bkkm@;ZB6bP!izWwX6`!%7I1`Lc&nYmA* z>T4;b3P`oB1-J92Z1*%51kn(y5B)mS17Ne)oYDjh6gtnnQ=tZ<2(p-&>`^=DkN!9$<+3xN~2SX9zjQ$ zj^G@i-qIkKawB>nINto5#gPVv*9q$LJHe1?9pC^aay#8Twp&d>Q&ue1bOZoL1wl zsvVL?!R*98pv%okHI;9qZ9IfZccE67fm#se1GS`VsvkE)|!FD`_L))OnDZ z=c^rFA={JH-l4SFbhr-IUx?I44g}g@QS&87#5m~^4QSF>2K5G~e=xwzseRQVHK#tbu$ z`EfY4c}K(4%ILOHtQR{-z68u-?y8QZPHF3Pn5T||D@GN#dDZp6XysNlSS!1l1JjWz zUNQGNtfS3ShxBzy4KIYXh)$_Yk@&z51~y>}go>~k3*s7aZ5B^|Gr{jqrEqoz;L+lWlIgI$D1vBZ<1&)J7(1|YskmPDO|8T3IvVqk z??f=GmSK;$Q3OwRgO`qaEd%{3&Bg&!c>_kWGLL8+2QFqD1J-V9+y=MB?ZE2ofIH$? zakIEZ+$wGppAol<&x+59JH(x9aXhmNCxWc#1ZHt(+y!^V-NaoG9N8o86`vR1Bgjoq z8-m&rltI@bO5weRz-YbZ`bh7{Yug-V+Z_r$lv7sMmtyW&1^P_7UkaE;4i-yZ;y z8*K1C2SNif!B4=>6?h`f#glLzo-Dp7zAPRPUl-pL*B`}RTnMu(0tzh|+tBL>X*}Xf zK&1O&t%u~*&VZdOg;U<<%Zply%RqbrbPfJX=$SeVWlAlns>9_}T3ok`GKNY#4VQ?o zh_8zKM}Z_LE2$|H)XL52(#_ZC%@K4MKIO*Ecox)pLp(?a8Wd+zN{MuS;vsoDO_Z7k zYj8Wh1K)`*j4SZx;fxqIU`%yM8Q6?@WtHOF;$abDPo;$bV~_awc*<+O_`Fi@OmGHN zd8fxyODldzRfTlcC_c!r1cNUAYLh5lnh8{rCL4c^RlXO`2L=HznnD~3!PVgfba9)y z1zQw+KVFC*7)!l6GAQCZ;?Z1TaI=gYj5!cE;Le#MQ^Ldek#Vx0PonX9{3w157_8AH zFcpSStGj^mKqjc^TDj(8{CKX=7HH@Sf^HzFD@8>eeu7T*3!imv}HnCF&;3)Y!BsxLblqBA$ zDdm&D`$agt;%_WhE-rwTD`lnOofwSCdb|to#(TsQ;^*QQ_4s+b55FLONsxme7u6#n z&>Wa$eL?1ehV(m=ZHjV%n+^O9A)_HB<>0@%;;I~1#;;=MGJHV%N?d;ozkv_pH}N6- z77*Cm_%J?#i|{-6UHl$&{sBIQkK+$Pnkg)F1*U_f9J3abfhey~gC@==iHj>ShIs?a zRX57tfaH{NDM89F?yfE$>XkB_t{6M4@fCGw?~Pd-+Ehl_U^@h|I6(595q}ZCmKM`V zkX`&qJbR@w_!xhpCx3{t6{Y?xp8uy&kO1>uF4DkT1e9a zQ}nd>^M6C!u?E%%2>>8`>sW&%-YRP*mzLzqdM8%i14F7}KoL^AO=b^8KE@647UlVB zd`k4VK-s{s7B-v-Tg!&9p{$j)v0<#8b+As>#k$3F;;-U)@i*~z@q&0!yd?f1{<)To zfXolrnXxU{mTWZqg+xp7vXoS5B#0#_grHCnK3d@#Y=&G7J<21BlY@`aHX%ItCWw%M z;OH&Os|2&Q$=i_M21XtvPJ#0oLM}~~0aYU>T~gyXs6?q`;RQ$>%0vg1k%OX=7>cVX zECeTaQ!Ops3EW>MUd%N4pyxX>{6d>`32SphL+(ita{VMoEDjb_I{l1*GqO-aGz+G?+FupoTToSU>qoff$$SG}8ARma}L-b;{&pqPM(!rsR|ND1tIb|L!!L6HPS z5!9ldeTZqzK0;7SnnD~c7EORw8`SuC`mG`FS%9z9#2lDc1mUEb0`Hi>45CwJ%WJHR z`ANuNZ=$<;=xzl;t!Q_x6^D=AdxAO;1Q)ll&)`|?vjoKwlq4P`sHfO*G~I#GVULkEVf52jnF;0XEcI*z7Ba9~ zRJz~GzC?R_p54d3z`jUO96|8}B@mRj97Opp90DTT2%2&oh-^T`JrefMG`bF}=AA)} zI^VFo8L~$UG8m6&huABz=bY zbfAl)B!(4$uz(1xm*O;_WO5a3`28+FzsX4x{+ld4T-oU=B(w|hZ@Ur(N18f+#Cq>3;J*sFn5gdr;X z&cG0@4KWO#RGMarNIH@0kDY7rac&?th#Sle;f8Xc|TNr}I<_aU5(`D1(_-Nc&uH4!9TmfPP&F3GIgOQDVN%94G zE7Z9E0=fT*xx%B(*?&A$xTU^$C6E~8z`7!)cip>r(i3geq~EU8x}l_^?n9`_*CYPWNDaCdTdad&g~aQAZaxdq&P-2L1_ z4h;WNg31UgC#Zs;N`j^lR7H@FplX6@2%1jN41#8E;2z>0<{sf5_i>+){#S3EEA#Q-ohmRC9^yPNI5|s9qteUx~UUQP&XlY@%L3HQQh?lde8LAem0( zaK@>)0%Atq=|H}+c8jYlttkROC-r*MkFh1?;}R#tdzDz-xK0!Pr(T+?4_I8OV&g`q zQ@5c6Xs(brn)(vx>A)uZKXMqi^ve3VLbv>ivbelTP+D;XaFDLVmoI6*K6y28><*6N zWdeT|)k3$@16Vshn$*9s%Ectgk4c4SLh+vYSls&TE=Z9XcnX^H8KRA zlR5h4Tp@dA>`Y2Eu|7XR$9gNNIaZZd8e1vTHbizZ(~=XDlaiBS(~>%Oj!o_izJhMu zI%map?Ut0D-nDa5r*7#=7=hcx?V(-oCg_%B++KoirEC;hTmf5<0vRs9>7|VIMQ%T> z@Df3{E#qD$NR+k+R}`fpS}Fb-_cnwnxYxNixP#oA+#&8Qf(SgIji5OMfqP*dLAS5u z4s%Cv2=@;6F7>b6LC|*U7lA$X4%p6NWEm+ZiV*~m8=YJ+hY?Y;UUJ@%bdQbiAL_$nb6m*!Z7*AA9kioT|MXz~oD zGXGDx&%x`%ea4+2=uU#}s^h-kz9i^wf>u&r#MJbp)byl;Zi%sJojSoO`;5+svE358 zbOpfDvJ$#>$xKa!6XRvnh>6XYPuIpmmTm;vx9xiw5R5BLGuQ1 zLGv)_NBk~mUH}&~Y#yb5uuqi#t@p1mZ|7YA7w_Pm1U*L3qB`EqhZD4zpe53pUE8hv zH{8-nCoT9G+DS|5Sbdy2R{2(x@tAG9r;*3j-V$AdWxW>^?U-K zNd48z2&((<`>XkGjG6Bq>~7xt!-?^IzRGxWb=s(mCC8ao)L+f_g0eRRmu+`u)1DDM z1|&au@WZ)nvQmdZS!D@QcquM0jZc$&$jiZp%(tSl@`)gibaNX+-6kl5=*JJF==G-@ zy^3-)KZtVl>T7VcQZ0vvBO-r`clq&@cllg+UBlGS$%DdYr?@C*2-b*RFkf5~+ zWtUu+vMYJ&f9I$1RRpakXhR)e&4c~9k)X|#vYREQ!r#Q-+7yl6#*36jHxcx-M59Oe zxq$t=VC+-AZ?nDK(E*R`AR~s%IX-8RL??Gb*}H51LGT$?{VYM} z2s$r0b$%!4B0=Ehyi716n5E;y>m;;Xma+<4^FP^Iz~^@?Y^^^C$UJ z{5Sl!{CE8K{15z({7?MP{AvCSf0qA+Kga*dpXYz$f9Ego7x_#49|ZFRw;(u~;2eS{ z6MP%NPZGSI;GG1&PVff=e@*Z&gvEpv2>$F9Cu}WY?;z|7!ah&fHwpVK zVSgi>if}f3O!sKzh@-HbMcpO(b>cG~|pBlUjZn^sdxk7dG;vg@> z|G?v=ijs%&dam%)HHYF4S;c2~r+Z83!9h9u5x!SJiV8jFo!7`W>Oa&G>z(E;uPQGs zFPVPR%&Enbr<7Gxc&AS-om@~0NqX{zb_lEvBvkm~!5g1H6%t^5@r5N-UYZ0GTT
z!O-`!&b)zX`c? z)Hk+LW~11$ymH{Cs@S563V7ff?6)TaZ^Y&m_?l*--tuJL`;Vip#A^R)b<^bmeUK}7 zuerMah723P4yL%ia^J^uh1>okeJcd7BpFjLP>t`eR%D<&s*nCd`m!NJ6Zq7$z8ofx zFNc6_(D=DW{=DnIii@a5$=!eUFT;Al@+n}qq!tXUn0!sMWxU+~=l}Hpl`2mj z$(Qh)k$*#`K|uVa=~yUt{B^Ey%fIP37y?Dxf{v1S8%Cm-aeu`fQ{^$8$`z(J@0bEg z-v=7(IuBWBtV1j1!N6lC{?*Zh-~|fMsG`oVNv1XO5WfGH@w?z5(Di5>&{YJwlsEtn zGc6C6r#H!C`SD*$t{_6adMJMpTUOmBj{{Pu|5a@HT5IArwIL(KfB0xf34JtX6H#u} zTzMpCnw?r{j0_&51m1M8q@_pq&GGj>reezK7C?1nXaiO_4 z=6^SFMYTj8z@=QF^54)ylkDmT;|dc)x)!_+^yn@4qW)}lf@pGk0vCgauu2*Nh9hQG z|7Il`NYB3?_S-svRrsr{7}a`tAoyQO^XozKx0Tywc`RJBbBQd@Wp4narxX;(9~+4a z`Jk0*o9cNu>Z^K2wO#eB>N(X8)lSte)o#@u)n0;C1giHs+7;oviUGB=b7A#ehj<{9EhIj!)z@wBF+T>p1=ghmwQ;CbAY zXGc`;L3l&;KEW1$ctdskdf^S#3DuY2yjOj$`hwt4f~|F`uT?po*r;)!{^V@fQ(uNW!1rD+l|zhof?oacg0}a z9kUKScLvG^9>VBf3$b&Slw>b8`D;UI*}!0iGIoFp^wU+`#iow|}@N9uSWZ*>B}t^MS! zhO<)3)yeA4^hIzRg4@dP;(Ea>*p$WSrM?l?Pkn>BH^J=*?og*rQKu5zk>L1di{h!X z)cu->;;H+q2T+2IB^ct*a5CzMdI%80&|pGnFFMZmz1+8U)u|5q4++mgYA+DYa40(> zxa@+I#jg*1ZlHF>xR-JA2Zt!pD03aHhKOmMdJKfgaRLpKtH)ERo7hyCTy;UIHCYXh zAA=~KxoAQE7X!iZcnH-IL;p`lNI6V# z&6(Vxo==%*0l_H>6D_1n^nm(7`XU$@BTaq>Ci+aUD0nYcFQJ6>xcUi#GYHPCQ$MMG zir_4Q2Q(iOEmyAwCQ`3ZuT-xhxDUa73C^xpuTih1Ow^Cy{{J6H{msCXTY{N#?AolE ziHirU-=6Sl*6i^sAY2R#{0x-c9$dETs=-|cw&?fC3iW&MMJ?_N*{%Tw-l5)2*Lf#p z;DHhY@1YD#k8WLkfY35xN_0x1910g+QGj|`eL&`Ah*N{M7)E({59Q@SK@BKX4ylj* zLtZ}a=jBiQ+TwG{%fl639u?3QlPD|8Li}q=eR!azo#!rf{&Enf&T2u z2+yd`(N#IC{)OPt1dpjx|EfMu@K}N;G@GTOzNEfPSI(>cQ?gXX!OCe6UAgf=D`#nQ z)IT(hN~3FnW;J?^fzs?mg5ksl75wnLTC>IyObef_*32DwFk{Eww5q(!(+MS%ZZuXX zYYQ&B@AgZ>`b4Hj>^cAZ?5^WCLau>AHyVe=Ey1pFNwDW#XYk6%TWC50?3$LEXibc! zm8P|(ji#-pou<8}1Ht(O7Z40ISV(XY!NmlZ5Ilw8sRWm<)x^rMYZ7JHHJvH!WeV)m z0q9L!w9X=RD zhnDGoDnol&^BQIQS2V9`4iNk>!H*F9Xualj%^Q^MA0rsD693!Jh0ws`p)^N>Svm2B zl#qFM_y1sbT<`uLO&d2;V*B@??EArG-%V?$>-==eeLG&-e&_Z>E5<|F=#&J%2{uky zjgK^+%DnuE#LG*rvxZ8QuQWdcFaLuLyXLf?m(Tfi@$ZzEpHg^vSwI)BrK~KOV46QD z{ryR>^rS#|#E2FF{mI$g41Gf1mHFLTjaCoS(Q36ig6jybhaZj5f^1k$@Tz8`J8g*8 zMmq_mQga2Bn%XcbHCHwzH4~Lxi8fpt1$1|Hez&%Twk4&z)da7RjW2C$m}Q$_Jd++8 zaOT_oX~VZox=>m8z-h3Z^hdPqp=^iXvc1M_nZBn_-$(AdoH_KC5fuj-M7}montH0Dmq3xOOlA zt{p<~M!&$(=3E!>vDyg~i*efV1V2si<~r>}Z7#uE2!5vd058xM(N4S+a5%pNfEQE1 zw>1U$q?yXHm1{w{1_>IiPg_j^2Wbc=fT*>toe3b;27@@>UifRt?E~9woY3vTgR@3t zN`TLTvbO}6eK=;}l;`>mPTr$m^2d9ZPb4-1T-45y0iP`azJmf@Oab3^O~CKcK12ck zpIh77hy8#r(k|9M&ctY!P{4O7fbSvr6@p)-+WJ5P;>#%Fz^uC!#8+Gw@%7qG6pRhp zjRb>_|M@!Y)7s4h?<4r7=0kkDb_ea`S&BGpj{)(W6!90ELVPY!5Z|ZW--Jb}eOdbo zMSMTOFZ&UH9Z-BD7{wb;=Df7x)0F*l??x|bcdBle5I+QE-wH0<>BaT!pR3J2H#;h9 z+4+aQgJ;ixc-Q#F`zU2Z?`Yqb!H3*%;P%%j_&X{1FJ2S;kF}@%nRwTJ;|Ko-KevOp zC-@Bo{5J#K{$2z2=P35S5`0j>{`c!)uVZv9Oh<=wnBYSMzg4H>bUeXt6MU3n-zAxDFd#%Q3hNG;-27R3g90G0RJ)oxDNJz%XEDSKJEux z2Tzi?wm#Pl(~Y2j=jetL{1L$)*Xc&;z*X}J!6%vz@bS7yO#z;#n@j=!lwddkLIt(1 z5I`&n2JyAAAO3iHb6@Y$FIubrob@M^2EeC4*{Q*0KYo0^?$}dOg5FHs%`)IONq~QKomxs2qPzDW0zTgl_(DJ6Anpl1 zsQ~^>0Pr&nfG?te!yfIF0{D{a0=`_giUPhux02v*3I485w_3M`VDPs6)O>(%)NN@B z@U6OS6!0Gi{?QNka{%IwU=V+PqzgOehXJ--x9zKXr(gmj0lpi`?g=h?$0OeG+b3mx zQ6Jau(x~U3hR}-Q2h;7-y+r5w0#!0UQzfI@PnFE+CX|eDOabq89X#S4;vc$$65eMi z-utOoI2}YKN|mEJcu@O4G1zsV`tkn4kM~K6_c;Y`@M_8-a+Ybp`#Xv^!1b$w_fOZw z`&S(VPwRB&b-xh||Nma6yP&&B@CAbZXf|!GXY^EUuwFfuIO`&;nVzR>b}4AhEIQ?B zNqU{WDLtS!>m@w^dy>mCmFPha=$p_3A1_@0$f>U~M=d$~V~-zVCU&7zq6a;oZ$b~K zc0Jy$4VL3nG`qb+IuJ5bw4_N54_5BE|BCNVjKR`c_uo}YZ zn~lNs!}KGYU~v5?{b*otR!dlT{3Dg<`tbnAgkYvcEe8qn2BrP5iK`zl{LfEK5_FTG zY+i8L@`Nwn@0>I^>%q8HrJwBW%{79qKu`A#db)354V1z4bl<=ln_zH@Zk>W&xn9x( z)AXPR0B|z}oEq#FmDuFD+m7O8A^N;IJ?7>J})wHMs1~u@~;1eQTy;%lnUydUfLbx<-I+ z*VAnS2pUMFfCGvy3f(RWojV9Ri}pDM@O^r!2iR%)7bUv@GPb_3u_yOTFrNuVO)%Y`>ZXAWF!zvbu9j8EY>t^SAsf@X#$ zf@Zsa`(ep*C(?g=*kqgk$DlUUZ=(#uYOqVd8^R>uV=3^LD7mx^A{V7fgrO|}{}0mL z4DDp#4Y6!XLp&2>08vlacm?=Q^jXPlFG>S91dum$2ILK02%F$X-q0P8H}o*{q%XoI z5;jSG2jo+PUdkZT44E)5L%Jb@z~h10&UJ4@yzC5mzjNw=)J1)5F#i*$rW{mE;V1+7rO6{CN z>PuDTI?<3v=bB3ium>eT!(>W;J)0uHu)~7#WEw+>p;X3xs)T)Sz}_&KV&C(c*jE{D z`DaqzaH}8t*)r1`Zl~C%DA+?Di=XM~52(wISHs;D`g;hQszAR0pvTh;_tTg7Dq+*) zxAlTbS&Byti|A53YIuyWfP7}1VX@(H!e$XRyZK;WYFOTcq&KWEtfa65mG$+*z80Wd z7Yt=dt?#}s@6Yb@=!uU*54AqNLt{|@a z(7A4-wI4>Cj;3Eh-(hvA00P&At!0&kK#n5SUvaEXs9d4PHyeN_aZe$p< z5e1hmPZ7Sfqz>G++)@;^?}eKi0dC}sYM85$r+|ZbF4P${6!0-k0bVoI54h1}v`By( z1qpDPr(x7kz{gw*aHHMW5&$>CF9jQ2Mz=BC7-94nBaKl;(6bW=JCU%tgq=j#Ji<;U zY(8NN2pv=5T4S^fxUmh}(%6oPF?OJU7b$>)oPqI9p%Q)uMf@+G5cC(>lK*=T5NfWx z%%&c9-<;WMM$nDRj6Dcj>}MV$?2MKhdmG!)7hy|a@#S|=mhFWIg+#K9*_5#Q82b{o zl(1!W#(u{Bge@nm^h4Rr;?pz^F%AbNG7dEkGv*Msg0Pi@omOugVH`=BsEV*YiHZKJ z55qT30H&N6%#@46b``CCu`jV=y=$S&7sik zrqIm|g3hAptpNUl5n?zLaCm|a?7nZmPA#R%>&ADf#D2qg(DdqjsKcRp>paA{|VIeHm zmP%~;Ot=4&*z|;4Gd?`d_&sGFFjyW`nCE9Iu}>S%&=+AJBJ9KRJ4oy#p{;`V@5W1% zi7pr~682HTK2~S^!}up*7ZLWUW@91~YXW*9Zg+w3d>$;M#s|dTAuxkjrmas64^@QC(*o}nU zwAR#3=44YZwk7=`B2x6J>6eJuJ^#na&7Y=b8U&nd8cf*Deoi(G15R%G zmxvUs$C$qU#u0WaVYk(pCYZpueul8mQZByEFAV*SK(o?GzDfFx9k0nNk?{69 z`~q79zy2ouEKbwuHl|WjCFT4wQ@IHYwdV-CgRnd6*`cN?6SdL^yNj^9=@9?o*MWCr(PO9uU8CTECb2p;I?D zlG?AC4$`^4PVMa1sGV(kliJy@H)Uss#wmy&HN7Vz4o@cpv+E!g)^Ac-|9X(DSE_tu zI!T4~$EHtApPD{1oiKfF`oi?3=_}LMggr#qw+Q<-VGk4b2w{&B7HqM13H){s`~F(f zDL>%f8$YD3P}9#8@DCKgKcZ%r>!gBe8N$AtZ)&TKY=S@0=gKW{dHZMK;mln%XSyCkqb13EOj zC>=t+$yM^&Vpozd%#r43U_En`xrG@*Azu*oOTvCtZ;mmyqO1q>2zwZa-u+j%*XE9l z*&G|p%HO;=X6WX9{kV+@y+8bQ{-TYP?ac{LHZi#D{DQ2(Dm*x9Ww(j9t=rMw+Q9ba zWOG-Efz1%-1_u7-It!-&dV{$yFz`Q!Wtg*N1~w0rCAN7eW#I1=28ILGr<7T29z!MewH_30o@CCa#Fl3UAKQ2f^H_1Z6cerU)M$L z+ASa4ai!`_yey#~#6uN3+dRvBn@sb!N;Llqg^o~~KNn2%?GGvF-EO{12K-J5@blNH zrBu1kychug2ODMc<9@)O@&jH^0smbA91=!kz&Wk~@KqFWFxM|AfUg6<)!!RW(-*-& z3J=Ne0X1#jVx~@g^H%dV!d@cmA9d#K=4T1}C*e@@NtoSc8Urxzq52UrNQ64`KG2UG z)0BRUJE1JyE9Td!QFzsM(ENt^Adm`&3CH?LkZNmQWOy=3udQ-JJ86Ni=Ae9fyAIhK~r=W8@1)UzbfZ<;)9+i=w zFvE|o{gY&3^ACQ|Py0bX2cUCmKj<7}`1?T*Z2 zO?n5_(!xJNffqC|DM2Nu38yEVp-#{WI>H$VCo~(c!y*4r0PyP5W`b3)Q2YC>|{fhP=$tvnCUrI1+dAdY%T8GK@ZPb} z=U#Z_NwN1IqR@4I#^~f;SKE76kG=Kz(+#7py~6NI;it*ajXND^>|yM!InK+M(mxW+Tl9;i#Jl#TwRfR-1aT zVx}jPIb;>ba;er{ruwM3t&cpfWV2RdWCQp%OJI!k z#s)ROdI(+5<^W^pX57ut?aK}QZo2ZLv^X*|lf-nc>NdJA12p~HRsgpMNEf1B|b9D1B| zR9><1M4{V{8BX2)jr%vUJGV!5q-lnF3QV&T>juuMsae6>o7{^fOa!XC0map0g4Lt_ zT5fONZzfS*y}G(;_ zC*xVhbJYkr+sG#41BA}qWIWG!zR(R6I(G1wqncGi}9Z3Li&L57~?~D^bxg)hO$L8f@g&;raCv?QbQY` zP)psDLKn`Kx*dD!hZ$costu0uW#cPC7Ztj}O~%)ZuM6D}p&S116}Y#J?`Z|@-AsWS zsv7MBwZIK)Ti^<_A1NC@HGa9f0{4~iYqh|Q5W11g1@3za(GP8F=`OCmz72E7+dfbnPU{iW@_xApn$f$wflrPhz@b@_3>K1v_Ev$12=fqxX_XMA3em+^UG z57}>iq@ZJg`R_H#1s2Wc1%>+U1$L=-L6Pe7RMzLC)q@XoQ&gXqwD`QBJ3cR<21+;k zyr4HeFX&UyS4HSX3EctOpR~&JjfL4vx(ht$RWPt%kkE}0y0J|K-U6S{jT5?w|C;X$ z!UcmfzAuPoe6KFaC>W~xzU>|q1xj|4hk{rEE1cT2<^}13QL680R3>Y_FBmIzEg09< zpU)g+e}CDfW0IHpEkj?reBkG5Wm_BIz`uwyW!gRzbI?)9<6>dV4Rq> zQE9<+&G)Q=puCsvA^X`!<`yi$_kUxOyI^Uv?^hI57u4YURjTi&Wqm(W=oScFh3fl- zJAL1v`hK<0P0#v%o$C7o^AA=Lx*41)t^PqP+hIjEhoV58{wp}V;0U3cC3Lf!3XUpR zFLZN+uIyjykQE$Pz#$@=_o-o;bp;cwnQ7LWHy4~#aI)$`+ILoesB44^PRA{0v~|mb z-$vY@Jbd($(<%&<@+b15s;r9O=Jh<=iy#LJhs0+?7 zxJZk?3p4RIpQ+9QmXz9suDosKbNZNGBMY_mrl7<8thp{NxLk{Y%Q7)gxu+zu&sLRZrq51-=W&)WL9{@z;(9=&7Yi6V9CgzZz;UcbMls(7q*IrZwr1N$q}__HOQeHE7+hwH%0|ZLDbOYBG@#lhITlbd=vU|7Axe`?$^IpzC5H zj@RwB>yo{%yNRhYIxHr-r&M4EsTJ6dYW-W=Cj7IH^fv{lz)bs@_BRbMxlIF2gG?Ti z*W@$#h3*icJ5=Zn6S_vB6GC^m&{2mRDRf5(-TLjOpcb~KXosGrAyRMCFg0j5WGk@a z)VFlHGu4PaOO4q7yF%*Uecx{4Tfa>vn(w2V+X53quq~!ZrpYQocZ|>-tNlsgzt3pO z`g?|Hwi<~uO|%8a3*8A#ra30+XGRVu|7-mK(*l#aubinuEq5E$a%Wnkmb;U7SMG*y z%x101q`s>&tuR%aY6Pdj>P{89(>9w{nQGNa<8+}rBU5SoAD#F$G2k=pX26%;aMv4y zIwqeH-wtbf_l8?ORVyqL13uGk27HFM2flKQYs_!g|MKhy-!|OJbarRsm02SkZaPXU z!bfI`@Yxh$(;~G9pY*3i_&C!Ue{alTIg^jmuYVE$?^ZH5unU z$h{A>z1Mg1@wbnxO+0i<;gR>AcyO{S8x|@XV zj(@H6n9XKBoY`!)n5||-=x!FeTZHb`&E`V0O)Wi4-rfFxzS=c+m%5sJv@MNK?sd!f z9SswIy!qH=fArtFH{Jfu&zO62Z=bgJ#-4cL*2U40R~`Fp_l=2zgYlgu*SxQJf7Qh3fam{?zXq&FB7u5u*9LX6Ijo^P9|@asO7;{m*9I|3b$7ZwTFcY6QH$GXgk5 zbCa3&;JIuBT%kt5m4;7MgzkCurCsJvbz=UYY+&DDzFGCpjbQ(-`wQJWjf+}FhUQPq zpR2b1)cl#?+;836O~&($=P|#{EcY(+(>e3q*^GQ=W`w)R{JqeGakt#LyF8>T>noOI?#*VvR?;jnSyR!lf|RmvSx76m$FveP98JnGIhC<`j)Gax zP~UuD0m~=%_*^CrQz}kp}qol5u@swjt=MVLciDls|#kY*h3pW zx?;loo1Q_JQp;4!G+tZg>N2Ukeu>a`68b#N3^QohEHi~ZzooNmnPX9R9QX%xR&>MulW8>nI<(2D7tIJnZ&a9{^udAED-)7+2rS%-_G`rQg zXfqPY@tJa)IicE8Wm&O{d7CWN(#gAA)9zhqS;Z?>Re@~T-?boZvD8}XEcMdKe{o-# z(VDTtuFsbl&BfYPjd zE6`Fhc2^2^)?)G6nl*KmwYi1k7|V&$fGw6|Eyr1ox11pK1wwBUdb7}5wpcb=PO_YA zIYsELLchPz4;A`hs=R26yqpww3TmlU>PpKOR8_Vv^+W&a*(sG(nOe4P$vuLym&Cd>Jj3xvK< z={m6RJx_0w^Z~ywb zt>@=VD49}Ty%@zCc$?1k%Id{x`Lk*9eTn5#Zq7*M=&>ftcIo6+|IX@mx#e1Ez*fr@ zmMbk+S+2HRBlHfTFA{pE(7S}bc&p_)%k`EUEH_$i68i2!-$Uqo34I@--&fV#R8dpa zu%dc&vaYO-^DM_!uA}WK%)OZ8EWl^-JosO5`rJ zE}ch3(HPJ!+^1f+U+8-_21;h8O059nmp? zCX!>%)TXbzwsNrc&=bG!+Z`{$kZ*6#Ry zr>!#=tohQ#o2?zJI;&pjgF+t?`mpMTu2V|8w=U50_;;(tB(wOZ+Ec8p(`;<*tR}O! zwTpEhp^pmvV4)w9F?6KG(B9C_zlNLtYCbHtEw);%g}WNxYR?#dcuOb1>a_O4;8vHl z*xFq)_z0mNDfF>sgIjxB`&j#0`&suD`nb?1ggzYiJlt((Io*79(ub9sHUg=6Y-aVy%47Wy$5*XL=8V!zMV zY|-YRv>sqBp$l#uZ5?ABYaM4DZ=GPBXq{x8Y@H(X^(9?gODD;zrezMSWu|()g zg?{RGE6d5O)2!32GpsYMv#hiE*Ic2Wrgpcd3;isipDpx@g`T=uC=by($=b?gDEQ3Lxg@#tDd*D z(JHKmTL@FSoU|mwB3|H&A*%~6884uN;Qq4f}V;h;VJx@$k%dUU2sJzvvL-K55P zoY0rIbg8W;T2G-%ZQW=+$$GNTFA(|)pJ zeudCi3w@2yuiRq2(R!2hX6r3Nze?zj68h7H{tQ*#|L^*y*1N6u(b!qO{|H;1TZu&9S$F0w(&FT}@C#_FepSJE0`qe_eM(EcH{W_sPaI5uM z>vPuUtuI(#6#9dN{$Qa$ROlOp{%|$3{~O&&>l?eaw(qDl#=Am)NUQFo^+WaIM?!yC zJGztB&(zlSbG17u+IA`ASDj zu5?gzie5AM2BD|UIHuX;N+)G6rL(fP(naWx6?*E9GLVwl^#k@p+8aRHwyhpf1~TD?5ifzU)fJ#pn8hXpDOgH{f(}p;!}dV z8e9oy41VTLgAZ0%=f71Mq6}4rX$C(_=+74VbFv1HDRCvCB$brVGh#eX=+77W3xs~t zzi;rdyBd7rt_CmJ)!@^KKxKw9Q|K=g`iuVSuA?$feXdNIFZ4}9zj>FgV@ofxxdBls zm8+!zR~g4Bi$tHPdQ(?K)F!4NZF(`DVvoo%2s8Yap9P|AEj`eS9MHp9%dJLjRS}e_a?jht} zLhd8venRdqdKMOf3S zJXgr`gj^=%`9dxi@&X}O2zjB9D}}sB$cu%%M952pyiCZ;g#Bz@?k=56tWQV;X*!w%Atc^>e@lh z`?*6$<&VsJ7X7v|mIv``pp6Cx(=ePxVY+SETT28S-!Y(P&DbGJotld6jI~M6Lv>p9twX5Z-l&I zwJ5dLBcw^V{lAwG3CJxdnp}0YRN=0?T*F6 zL3b+d@kT<4c*q;eDJLmS%DwHALamaDL}OvMH|V84iATcjSkS}Y0_kuhjoH9Q~ zlX8Fiq$K^Gm@hyTpUhPI3ABn5ZSHg+7)__W(SSD@Z*8%Onv@6IC&lZFL=)+#-|dg8 z8l*hb{k~|_jh6!HfIsbzMRWX8s!4gceNxilSQ6Kuizga)2fXPJ7Kw~?t$f1)V$APHmxMpz_6LLhkS7@pCnGuDpQlNAynRxV1Z%`Y z4V*}mcEA&&9rIK7`+bR2D(nlUQ|TOCDl{oi{`Vy^6!s>lyCQC1GDeB?QY@py zh~fzKafI3|?u`Zmp@ct`PNrIWf4wH?BRfo9&a5@TKTD z;_j%&ul6UCw8ZHs3I%9CX`KTYv9-lc*QC7t-Y`XI7V^<)2}W|t{T5BihwYP+OeMUbL@ezNB?4-DPqiQM z&W&f zwoghd9t#H3jD>uOC>Bd4=ofnvA$QV8M<5oA`n{f<-uHEyl+W8ICEyE(VqVg`$a^w&i9`%9rhv;!iSQB+T4lj~dD87_Ce?9CG{P(NrXyh*LM` z^o#G%qNIV(|gnW@eGN;zRSCjH>JEf!p;dn?b zFHt(J0gne==-#`-X@4^AiAOxiq_=gse@K(^efy*^yb2SoG?AJ9u_wh?FO4qocq|$4 zCp{jYC&w?3Yf^q}pA@=`(KKCDw?B}k?-HUuj)o$PyyKKjRMd0_7;D-#O4DUd#Y zJVfu%{}=Je!Xxkw7>SWnApV^Xil$en}=0t!LZ{J7`k&X`hs6 z#LGmB&#w+4h_3{*VzC&JmI%^@d6U5?#iy0$3p;93*fOX+77Kggapnn$-MCu#qeNQF zPZbjnM-zc~nkp>SI=%|KXi`k=lR}n541vS$G~F1rm&CXw8l!8L@P!lM0P~gU)@7y8 zq)D-~Pl`X8h=xPHxI4%+D^ie$8npR-pV}1*`Ov1d#ky%yl=ewMMmUDl$ZW7-9LJ-UavbvtsIS}{K=$0$1goJ zDfaeBp`HRg?%+CMeUQ42vIsBjJ&)Nb;>;% zV|vo-qeB*8=ueHG@_KT-zrQBM)jlZ!kD3rIN-`KhN)Q3Gn~Yk0u?S<0h(8@{-Lok4 zXi~bjPf98j^7tdn9!1iqfkZ}nJ|-=~O!K7EeqY!d%kh3tlhU(&QlfrF+01n_jmy+X zfC?C6(f#+vgG{!2{bB0l){#6|lhV7LQm75%e&#?E91}jQu?+}iZ7V*`kC>jfKW;T$%vm$1#=`!DSOhP7*p_poO&#&N!ho3QkeZnhU4@r zgQ+mxz7*|bG|l*xS0Mg$%oB<*L~5wuk8Psc&?`34b`i zjGUidOlv6?D<@KTdU%hkQ<>3iNvqSa zQHl`nF1$H@nX5_hwNFZz`i0H~^Dk;OL(@#<5{dB7Fhkb>g+J=avDgAlN}zpGXxACF z;0>lMDKE^1@n(-+83ULgo@Y`fl2gMh)}(~mC&eF4(P#yj8Sznt1$<18(5BEeqYd)~ zQq(=^)+5)#DoskHeNv)~_2N+`^AibrF0^8l$~ZF$%*J>kkua~wy#D3|28A_+D|6PL z71kBj=U!M-xHk8~L4^nBUO0?bb*;Y)Dm7)e)U;qG}bjNUd&fil?$7{S<0$)LE%Na+?@SoOX1es zbT28qH21>gg;(TWxVrF~+zZzivZAiFIyV>Il6&Fy!aH&=++BE2?uGjcAN-RXK3e!# z?yXN2K9zgn88$l0k^e&Bi@6tGDSS2e!hZ_i$i47(;XAn(-Y;aUh1N=aT=+@uh0hDW z{F5wyTlih>tv?q2lzZXVLY82)O5G;e@^UZeZ2H^_9c_G%+4_;aZC!FN7;Oc)7c4ew z?u9~|E%!o^&6#_lyRAp=h2FM4xfk}e_0PR9z~;`q;IVmgF9d9?e`=leh%K6XVW@5R z?rmv{+Y-6Arfs8gFO0E`&Al+eHZk|Y6dNnfTg#tjo1S}NmTh+Kg?YBJ+zShA6}cA{ z*%s$sSY}(Ed!gD^lY61oR+oEWwJrB!E!%;%+>fN!@%-jp-*v`$paDnZ@+zU-?`aNKiZL^S%+GN`*URqPfQkB}um3-ebqN=>1x?)L5WnCQ~E>5Xj zG^~6DbYpC;tfg?xsP&%DI;ob7qr3$_<+FWFwUy<&S+$h2c;3;7%&pDX0^gnYh`Hwn2( zZPdEeHGhyiy1sJ7=!NR%nv3|Fw{CV_O+#%(rFxZbz>Etk>&ur`?fgKFFUD5ZRxV=y z*~*1GzZcGY0XDa;qH1Zy((1)-zS$~Qo6Ss0?kYYgZobr&&qM3eEUK!jTo~h~xix%H zw3^T7GQVfmnA+Z#-ngi7toHYhGJh{KI!DJxClY-5Syi)G-TYR4WM`gwjjXy`QvZ{U z>(6apawr|x^^^K4(*kt=o$QP;>=vujUWjWt{FU(jVseQm^`^on6MMAzP^HrYo zk?q$e=_B=%QU~9LX1?(&tyx}KJz;6pwDPKk%JJp3%PVWMV*jv9Ib!V{?0dJzefBQ) zee7LrFWL+2CcD{g5%LxxZxiw*8TVZ({}h~z741dpeNG`?{HOQ*m4%x%wD+|4%GI#1ecu+t+WQOnvTWW4 z*nZw*XSL(y*mCl~d0Hr_pO&j`&nD-y`*V{E*+*b7d)W54J!&6pA7USBA7*Fm;nkUV zzedQ{3i&!AQ#aip|^aSWEUr|fAvixF=U@-0HXEn~3Tg?xvQ?-uesdy4n} z6ESX|ta@aMkZ=A|k7%BorryVz$y@*QzW>&9bL?|-O+DYf0MFT3a(U+_J4-I_`qLs| zU);)jsUgsaafAS)x{<6_xJY=i+QF7mt@2XZ({~v{9X{M0Th21)8`g%Z#)@ zRh2k@&{RHsuNzceRk@Z5y0&ulpd@wwAU?oe#@ESpZMP($=4*RV>p`T}vde_p0~(mw zk)Wzl-F&02wb3_g@>#A^{!irZ!RW2@)*5#EHv4uuTK0?Wm)NP-Y0;k*@^hQ>P4>&} zS2SKG7- zAD5cKUD_>e(@4#j6ysy_Y#N0J9po9%-R<@I4;j$?Am#?61G@9V_K-ugO6Yn%O0ZMk zzS#UpxBX`6Vm?L4R^qqW?^0E{-F}DtP9eW6W9rkDJxZ_PBza`|iRZU*7zo=^Rj*#E` zuQd5fi~pt9G|RuP=J!8Bem9%nw=(&q50;~5E01NJ@}B)8Rh9ScAJ{(>@&`iZ&yQ49 zKCyqQs`9arKmA`-MLjGLH zUkLfj&GtVWk|R&ZUkRC1zx&_R#bMy9PDe)}f8BUFTkwvGC6nxfv5q=ud}VoELv5yp z8O?_T87DgSMsr6OA%EMfxx?73d2XzRqJidEZC2c2adhMJCf#_4BJySm`G+P)p~EKR zpM;@vPE+M@X%!f252pW<3am|i&8Uk3=1OYaY?gXB`tp&dqo<>nqqn1vkbf5PFGBuR z$iHoI^mFX%=N5x|a*7_uWnEW!kmYi8DOPxlygaHL-m6*!FhK(S9{70>Y5j zc=>aVu(pkmBjSiU20Mn#)J9wC4nhWZu{jZ-5f01wUVWas~Hw&18Dz0zq7eOv<|m+mWSSdp7>v-`afB0vT<1L zsLAzPt)qGF4u9{)TG{8;IGSG%XhrQHwWu8|47S!q?J!59LpX*ALy<5zgu$LEVEqDe8WYzw^WVm9ml98Y=h%yVQ>nAtI2V!<2Yd`7KZL^OW5vIW#_UsHE>q_QyjT7 zi;goK=P}4}oas2rakk?e$GO7LOBnhHLqB2YFAV!{b)4_Gz;U7DBF83Sa0>%Q87&Mm zg<(-{%dsufau|5)yCypfpfmoF8|%NEtLqt|Zc6Dt-)e8FhM(>HTl zTD|Ll^13C%_=dqB;=3Y#i|}G7=m~~e-IAG#T<8fd^p*!&ucdKZrsamW!)yOWZXydk zzVc9I+uZPi&=dCXB|tF5+x&2lH*o%4vct0#yc)~R&ed9Wc#Zsbj8oxX4Rm)xk2dKZKl-S(Q$*88(ug6E#p+M#nPgMf7>{L@=!%i zc5c4ldv;D%L(md^pSR^M|~xZc!sgHI6?}(K3ncxWn-< z``&aZ>|*O;@8alE)WzAw)up&g_bxp|hqsRy;2V!=UEPUmY*A`Rkva(&>29 z@eVtuINox+Eeu{^@HIK!b-X7GeqjjxYrDQWK6bF(>E;R zjxX8u)j)?NsO|dd_*Uxb_^$0vt{eTGmQ3rIKH=hr%KF}=JSD5UzB+#7-k;jud(AiF z{8#o#K6AXzG~ukur&}GY=J?g|2fB8sba0WjHq2hAMR|-h43W0GzUKFDuGxy@qE6~l ztBN|RJE$54@8PNJBVCK^IJ{%ej=ehe?%1be-;Vt{?%T0{$Nf6)FY+ry{z8#oDe@PI z{KX=FiOA=~mSrM;xyY~DUgXdmUR2!W)vkX?y^DIO4j-Cz_;B@HWnCw>`!$Se@pw@` zJYKY~Fbr$7uGy;_$A3DYMd06a_`i(_ih;5Y3(rY*#2kTUUTGEb5CE%z1eKcC{j<$z~i$r z9zQ_!_((NQ5^drn`$&0Fm0H9f>+*P)C%Qb@<*6=DciGY9nJ&+E;n3`(MTcWVhhs&D z<3xw!MTZkahZ9AIjiSRzqQlACi&ivyd{viMi}LVzgX-}yS&vUpJx+Y$@##A~&H+%H ziVhTpv00BFg2#&vEjmm^7{&?1cMW^A!UC&u9I=$!&)rnJtp`_V~=ir!g+d9TS*EZ$!31ja)BJp@HVXj@2 zapDEsdtuvq*PJ@9(@TTL{dVz7@A^k{$bX}i6Pt>*s=97gBXDXa0=KCVIBj@4g%4+ASw z5C1EAQW$1uUBAb}|B7BJQqO%Vdb#KoVVEln^O}lYD|%fR%7kITzvuC{i_~+U+7#Ol ziqvzT4D*GdyxHTN`&6`>bDu8J4;(SI*O-Av&D&=G#`^S(jK?|msc1LnKAk$h@u$k= z6YO`o4K=ndx2Z?DWqtQ;5xZhH6{+Vw87lT%=VTxG&8h8PNq4$%x04=v_OLH!&pp-c&i>8; zn83N8bAMr2CJf7)oNnhpVW<*@nt!csclw?WbIomnMNjX|A3~Pmf8u;KX&NAnGXSs8MFdQljRKAVEAaaHX3FO zwICRddRX(BHS#*=fjJ{@=ONBRb1w+z;kg%%a<0$4aEy~BFq@pm3d0eboW~2pQMs-- zSyp_nhVqxWihQ)66b-lVUWzeoGP@JbZSs~NpJl%PQFsv7b4NcCooM#IIE$A_g z14<9%VBHzDHT9WIhI?gR@$*M!3cz_GMb&wcbCa{lxmg&<5=|{xI-$Adc5dT$<1r-1 ze+9?zsA;PI%l@vO+Tc7(yF>jYdrS8B>odP=cQikoxh4DiZOy-{cQpT=Nu_0{Kj*zp z1}0mb_c`x(KHz-N`H(Pd6o!+9;Z$KbT^P>X>U_lcsPi%BgW*#Cs}%Rv$fu!BT26ek%L zw6ZHotHH7JeJ!E0+9c%nB$5GdBJO6LIty-ne8a^Dd_H%Q&!B@Wf=>iuzHABk$oYvH z-5(3XIh*oL^kf*^{`t23*{8mAe%%`9T=YZ@m0@scZgv=g;{^ zIe&5fn)kC5biSBBh=m8*0+iC)@@n;<<(2g_m#W7QWcFn@@K&^=Fr3nOTV`U_mGA0M zW>k3DH?C%Jn;BJ?&ZSppRR84nJx-;%46aTs3b^(XhKrgNaCJce7jvhZcBjB=E=Frw z9#0d7rf2h0u5Rp;{Gh8a{{WWOG;d|Cs-nKS6^6}?w?E@@NL^h;F6Z?(HkkWQX9p+x;xv$b8lTzz(CmIi)XHnaWJ%u>oP z-d$$ja(T0vrJlKDXJ-BR2MEKZ*{p?J&Uhc1oh?~uQP&WpxdscvWt&_>h2io&heW1g za*b4T!g%kB-R0zc7Xmf2oh1xcHs{1O#x*wo03&Y&uFB?Rg3Fo6lX!{Jl9|aa8rDrN zy7<>@a+M0hwT+AC5)bNT`z0I{?F8!nMS;)U`|)ZW4x@h2fUXt}53GSG6$QDh&4u!=q~NM}6lx zrJ-6~l~uX6eoAG9`kK9@VhL}<>eyvw9aZ#hYCXuGOwJ!f=}~+%61vY<8`49q2kp8158?yM^H%)sLCotn2F4LJjNsr7J3#8s6~XfRDB?7kif$+()_AYjIrJZ zRM%-Pnvw^F;bCETf%gN`>I>ON0<+G^Z)ASHtgS(it`Ogs^tMKvsuGm>SAZaZLaOE%UqYc zu5exHx=I)x6NblyfkvBw;#0!#^fuQuu4`S_xvqEJ;JQ&5b_l~W!tksxJSPm#3qxiZ z$3IfxA6dQ3*sQZp)!FOg`%<=o2(kA=8=cFH{WbIa^{tgH_x`mhx%a;|yH*J9(n?0J zO&w3=hyz2$mi>{YkFS}k5hL?olWnthiuL{F! z!oXPnKf>^aFuZxG)YtX8)Z6vC>rK~NuD4z9NWB}o3d39Kfb%V3VEXqRVR%;QP0YRnJo`<3QB7UnGLZMyr^#@nF_t4wz9r*Mz)xh z8U25wK+bERYqMx+b>%_|SjCb#+0=ZYfxcOz)aC0e9iCW{b-{P8pBWOmzIXlL`qA~1 zFnk~k9}2@q!tn7H*DtPLUB9`07luy+2d)`D6Nb;#s!#3wWX=}hY@sQc74W4?>s1RE zw)tTitIK#5zq_9%u2heW!p@#HPpPL-R8^`!mo%(cQC_=FtE@^Y7iX4~O^r7!ty(zM z%T9wnW&o{@4oFo6H-JDehI=J2RI0UKoC898e*3?~^Ze&vgBY_jNfZ7U()J z$SiyGc%IA4@1WDmhP`I=R*#jyt}}b9vBCKtwWYo5YgW$aU9%vw;LjxGt=F0j8hUl* zxOUTyj-5(tIRUIO?<%9M^WJ7lk+c7Pp20(g_8Jx&J!b5<@g>t|%qg4NySkyO>e(*) zbTt;3TAG+?y(`r9CY;LBa)d}7J*2|M4l_#{Dk>@~Sr`7SRoSPT&7rpI%Q-BC^H>Hp zXJ}Jlqi&PEQQv5$T~E{HdBIiOy+_Y|diCzpx8J^8D_MGAC9)Q!tI8LvLg?INdiXW9 zq{5r7%z}CDQ+sc{M)uXrTX3|ok@XmIV>hCCAnS=(sJV{M&Q?qvt;&eg+&#O`{sY_t z89Q{-#!iiUHFn<2>)OV>shq5hW`+w| z5~>m{57S|qP?9KBGm@?>S1S|Fsi~*iS=Z{8!t5BH0K62BD#(f$s zs_b~m(UeFs5oc^lk7_JvG^tV@q@GP#J)NzlcIRgaDBSXE=DfC+4;GA)QGRB^#7UE9 zX&zONp_-xnwK8M*rJ3_=D6UPDrr?r^nULa%(y8-W1{|^4+VXXqOQ%i2*O|Z5N6~au zjh<13CuYu~`rXyKO|z%$<|=p3o!1;2O>?L4&-r{2VQLj^3$^mqw1CHVb6x5v6-aie zx71(qNnvTUG)|f|Cs!<^3TiPl7D0VZTU~;@5p~Q|D*gb^S{aeu|t;*MlG)M^O~!Vist`s z{=W`=b`Ecf_b>L*)1o$X7Y{5hDE1V4Gj$?$|Ibv5!a$Yy>$XnkO!epS|@eq&wBp!^54PW?>|iBtobDl6$(xnDS?>pADiY+u zUSI_m1OQpe0WcZn!BSWbE1(8eK^+_ljc_;|3G3l#I2N$IatEM?@{=TWBkgYZzT3XA zANU~-qX9YH(5>5Sm<#C9jWoM$gp&aucRL;MaksMp-MXPmH+1QSox5S@ZrHgScJ78< zy4?sn;1fwI)I)b5&I%_2vI^0ua511)A$k>}S0Q@weYsS4ARG+nR)}tejFr0*}L!fFGUD!t?MS_yw?)6ZtND?YaZr zhtDLbn1C)m2#yBQEhgP!;-(m#iqD27K=0yha0w7U#l%nXeefcDDM{TsLm{9;cXa4Z z>~!x5y#YV;yavcy&zAu|_9Ra|u~kp}*^~0x^K&4bp4h0*OTe{0AHv5#9{YR&U%}6S z-~0S7Nqw&a;;S!u_k9eoao?u^-TS@*$mxrmzHh?Y@Gg)>U*fUv_wW;7m%iAgpA7h= zAAad~7m(L}*sdS?^&`*yUWL~IoAo1K{m56pPl0^*Bj5WP0NwWu05P%e94LcwSO|+? z2^;~(!-;?&`xBS_iTVDsVJ`4Yf1c@I0aZ{9D}h+-Pn`897W@)y74M5KU=s5sA z-FdJ-l)wTYA8rBU!Mz@if#cu=xDYM}WV)|}tKnh5mTvs&#xHK{=zas<0_^9;w{C3c z#`o?&Bxzti=m47z>;#>mA7I;oLtq$;fEXMAV_+OifJsmT){@F5YThbqkvrp zVOL(mqe5B*UuRi?h`xYp3z8~Rdz}EhO5QaD; zfi(U2(~m#>_|rcDC>Q=kfDAt}{40U7;9n0L;Yzp;o&j|8qnrO7cn>~oATp9Drg3`(IKR=^rq2M56+@F{#JNx{xwguZ}%g4iZF6o{GN zNpLo7h0Eb)AU=ZlBuIWj9RRr@Y!KqP5YL5pE`(h}Ghi0Xfq5_=7QjMS1;k0H0mxT~ ze1*tYhQy;JXOEi;(X~J&@-JX+=mYavGcgXTdpe z9$Wy#eS|oQTn{(G&2TH+4#^I8GIAG06$C8kRlifjA>YFvk~9?EhvNI8`#=F$KmqJ96gv#v7u?_hKSW>%3FM$IQbZk zZ-&>yI-sl$KO4|zI59XJTMoY*&|~7Z0M__{yU7#xvYa{l9VK53N0r?oQ5U|IHWv~Ls*N8Ph-bNe@hXQ#VK^{kJgNxx3 z*bd}t#NB{xMmz|Qz~k^d;DZsb!s~#&Mo>ORd;;Wkqy&Y~2L^%{0uYA5kbo4B&yk~H zER2Wca5P*7_rne#-I4FXhd}xxvB$`-;9K|sewL(IXTT0I>=45zF? zv9WLvpkM4oNs8wKWiyVA;-|tzuoW%o8ScTl8}LXC9p>Vdn5+HAV6*+2t#26#2^W2z;}t6FdLS@a;Sz?PzMb_ zeiP(3u@%rKaT#0<#8l#XAifh%!k6%yBqfob#12Up^nl*b4~Uth8$95L5JZ7|CCOKE z77$0t`A`9suo#G^WEIpvEs&?=TEM=^L*OtV=94$U{qTt-rObd0QbS+{@OrM_XV?euZ`uO*Hf@I@=nwk?dZf`KeGHrdX90OgpD#(HI)MV% zVHD4easqi9Mczg|2*@Axm?Ry5&IgQx2`~vt;1PHMUV>NPbx9h108EAHfUic+frsEZ z;NH>PJNi{g8pHEru-%viun@4_803w47Cr}Jc?_{U<_Gv0(0!}~9Y6;1J$7#(hQ^w} z3g|f24VDIjlSNn|WKjGYXnKt9Kk&#{*Q`5K2^$MNjAdbkkCGeuAu zKN!{k_l=^An@=7I6JZMA|H(68Hq3)^z{iv8U^S5Tml$Ag=n5vl zrzLiv{FGqZ5;tJSl3|d9QGiWL#sl$FG96~YTquL1f%Hp=rIL5yD@iKV0dh)>fW1md zuN0e=Vzbf|902H8Itj2}DfTNR-O@!seoG&KN8t&08lH!j02!sP!x!+YBu&L1Q;CbI z#Klw#pvzQrnTpJ*#OKsO;DZ1Vn^TF+sY75mke8`(ARkjFz+@-^%J0-lSPV;HIjn#h zI2Z)ryQv%Cc-RQ1z-e$3JO^*Vhwuq}4%lSskMIi+Q`7Q*xSEC^rr7|WPb06>B7l9S z&4AfJ3`|4zw3R?CO?I4h8Hm9Xm|N4%3f?6W}B`70!UO;XJqy zh|TF+;S#tE$lvs9;CjGj(}|zycfeh6FFXJb!(;Fy>;UXK{Y4<((}{uUZ^Aq9K2Ub1 ze=12c@a+tIJ0k{37zM=cjPWoD@b8RiFca|ej51gNm4K~hEQe}X1@*87u=fn?J);qh z0Ltu)W8iqe_cQSQjML#PI2Z86j7_iwE{5%J1zZKU!<}$9+$Tvh2LgGXISfWX9I(+$ zd^Qui%)AA7W>$Y7erH8sFmV4Y>^F*jE{CfmX>lL$K>$J!g=>M>UwjW>kHrs4(vk?I0Gllt4ddW8z?Vy~1g8EGuT?#r;CR>wr@-leO{&nn>H^pVTi{|KmaEXS3O%dPvx?ZL zLZ2$idDRm@o~xdL=YTv{eIrRLOn{wMkna@-Lla=174Jz>HNL6t0sDa)Jm7;Nkc2cG z0Am3ARb!{>*+AS>R{;7|Q|7Cyf%vJegOlJoxEsh{HTkP1f7MR|d8>XNh|%iz;UoAS zi1!)^I)DsazzAkgpb%m}`ZdH&&G|q~)Z78csd)s@w}$j;J_YQ%G9L`E7m(gc?6A@T z-M|L>LJ-hx<#?C`B`^(U!W<|Ae7Uj`mcSv<2#3RwupW*9{I~K%K=+lW0zO=MCfo?G zNfM@!R&|2Cp({`xR@tE!^o9N~00w~<{6OAT#ew);MIKj?$5m5cD&Wgi#NaCOv+5im zHdb8;*TD5~6Wj^J$*TL|A$SC^|Ef3OYxoX+m!#Ux-~!^Hb|4_THUyNb+TnoRYZH)y zQkV`4VJTDrj;pPQ)vyi@f@1;wYcGeZ;99r=Zid@{yw#GoTJly)-fABO@>TmbybHue z?T7FQd=6j1H}F0D2tP|wT{j?~b=aYfxURbh9)yo2sUBO`4un&X*do^H}hEsvOHe3fc!d>tU_`v>8`dyA>gmo z#LsFE1R(;H+tni>4(Psm6rl6!3P88j_-6H?AmB(q&(-8<^$9@it|o7*&w$I|O1K*E z-RkS%Cb$)D2mH4h|E<0c9)Krd2RsKa0J^Nkf2;A|>dyiHtwyKS-@}iRv_=nm0p)Uy z5zuK3I<0Yl69&UvSO&z`np$Xp0|8&JISkNY4S8Nep4VW{H5bEnxB|%c8uGh_{I0nJ z?go6e<}r8)$k!V3wFVon#jb0+fgSq602l;52m|F{?NFdBtfdUDodx7+EqPi?p4MX5 zwb*qnc3n%J)?(MS*mW&-U5j1UHo;aPfB#QQ_Z{42xvmTN3nhduy|)m0@1TOB%dXf^ z?AS%Ii%5qM0)Y@(2oO3*lb%o#AoLbO@4XY6fPhp1IhW_0HFNF#$6EZ}`?;UzV`k0X zGj{p|-FDJ#rzG4!r$wY9YbV`yI>?lDn}bumjYXV=xN!#CU2?{?kKAw*iqO2-nq}eLC`HP zC9$J!cGRsAX6*JD`s&t_|M46zVrSjt>h=X+;XCZsp6~gI4s@h5_SmgEqmi@QQG9>h zeP`Wu*Zn&NG7Fiz@5Ie_m%aNzPVpyKxQ3hWE`N9VyWitM5cJ4JehN|qv-BuKdBS-D zd3(6A9ch1=@kHhRn>nMLTg$4b^efCUc8E&Ab@4ctr>uL6$8JM}}SmtFO8 zr@h>1FL&Cj1huJ$`|M?Ry_)bS%`tl~`|D+Yy`JTHUZ*u}khzy`df8tuyXYl*ub=pZ zU+GOh1`x+E^wi5-z3jAC3WqqyCH~?%xA_M**2^4`a!1M?X)loxRG~VxXo$>_GDpfB zDRZQpk#Ers*&^*N(yk(hGZKA9`t~F3Dbk)I7vfupT!L;Rbs4!InIdJ1lqvEichGI5 zOucp6TerP++grE2%VD3r;r9ZLEU^53e$_Y+$oW*kjZbP#XRA(QhC9_Obsy)sVH1{rAynAN%j~IM2|E*LZ{0yv;kv-{%{?<41m_ z6MF5_9kcXVP6pfA#a<3!hCatR$yNRi{Qo{;|IxW{qtUWQ%N$*jGL%Q=XgQ;s@)EK| zx4~|sf1?Zb8STfShcOa4qQ^0rDd;rXy+)_99(khWiPmYfPNQ`itf4#IEMWs%*}-o1A%9=_`^w)}{=ROt?={?LzXHhGPlx@g)0`)H1#kCz zi+A{twtR{{`~5;k^x4mS_KRf@@gy(`-S*REzr}238#~#=Qk)7zpwpOY)aNnG67vKtd75W1Q%oD)!%Q*eiTQ$d zd_x>FNnr)6S;t1?kC8t{{uudV4sr^2&_4^Z_RmKtYEzFEc)S0zyg)1Lwf~#ww!bd> ze?d%vc*-xe&e3udGs0g9=?&dkNE<3 z8utyljnidZ3^K*Z6em;MH2y%haWci}Hcq#3x{cFq+z#wHPQJMP9OMZ4jXTL{&LV5v zMchK1TZsEF>%AZtl#RUP$KL^i^g5^r#n9)VYSg3-Ze>st+{&QGX-hZyGlY0Xkcj+) zA@UEAf5=#- z;tqzaN7f-bag#%?aU%$ZhT!d?Imtr->~&~SbURd+L#xvSdmQS!ANmx}@d7WS+o8G~ z`VBqlO*ApYqT8Xe4V7)EY(r%ms@tJ*4P8VEOIU{QXsCXNu0`gdG7rsQ3wt?$PKO@l zEPrtwoesUjJs$8d2!@$$SU$`%%sj(NP?icrP?@Lsl3(aVS9%adU(7H}x5EhLNB7Q?}YvgM7D%sOlKyu(QSfm6YM_0?h|BA&~1Wl6Lg!fnhdtG1KlPZ#w-bE z(QU$?T;VGEO)%34GmS9Qh+O2SAVny~qqO03+Ved>VTKW1aTg=p#fU!0KSJ&i?sUXF zlF{i1-_Qs-MjXTYBfLH0Z*Fmqe}iCTKo$y6m5kFp1x>_mMN0#T;ZFDf7sM=y#+}N4nRM{vH^)5uJ`ah*?G+ zDRQALTYixrtG3bksy- z9cBNceCwmOu$?1#d(;`uaf!dUhHevenV6k|*khtQO)Nt=5mZ69iMmXDhWGf8kNJ!* z(QTq^iLxcimMB}IZWHB79KtY$GlE3)o2cJJ{U%Of8v0GtU!t6&^)R|Rt>}P~MyIe3 znMdE}VGxXweM~m;Qj`*urX2E*k$;Ta7*mx-xY04qc@ndX(es#>c!eL4cg$$y8Y9=3 z>G-C`Bw^QMWEiuQG%|x=tiHzTWo%1i9s3EN^BrCAdt=Q%b{vzLiaE#5VLr+D-LY%g zz-|uUZpQis#-8TCcg}N>yFoB6lv0$X0%ja%N8|K0t`>E1|Kl3d47tX=&YQTYacy`H zI~?b>#>qTR=5b%rj-Sx^xZmhZZ(=daxWNo1o&?M^PDkT(G|o)p%rkBgspx6kQT_>n z@j1vx0ScqH@$!$Cf4uzTvp^@ z$EUE4P51`J`v%7E!R?Gch;GO0a{TQen2?A36r>2n(d`7;Cdf8Hwh6LL(Cq}dCOpOe zcow%a!R<`Y?*#o$(C>t|c?bPY(BA|(C+K0qksuH=m{^$?@x4rpLFS2bNkaCCi&;rJ zo7u)rF*%0)?jiWic*f6_`S*IpZqGVX@fZ@x5W)j{v5wM`Byq&Uy}zB&j{>m zvVBcf#AN%LZ1%}!p1c~fO}3lKdYXKkQ)F_UKe@s+ZUn*aImtsl9>MN@x4Yl%?svQU zy$t0E$NqkA$;b3z8W~&-f+>Y*fLojL12RwPid&n~i~bBFfl-V>{wWi2>r;|hL@LW! z#ah-Q|J3ZrHnkWfk!z|~!xx?{d+=9^}|Y37?|zG;(~!gOY0)@k!G z*EDxIO@Gt2uno64Z4dT0?Er^4iXBd~yJ>be&F-dMrf9fO#cbHnI26Hu?#}~>GDsPf4cnB?PvNQEM^n3PTz~2OuxyUAedn{GrT=R ze>3zqqX@;Zrx~TGL2Vx6NuK6eUg8yA;|+8<<9nj$OMeD37~Rg0ZH8_(?E4{(SJT*8iL z1!TpJXXQk{vkFlZd!AK_|Kay%`Fm%Uea)J~D!enxzGfZ7@6Gy)`#~@}1a~t#2YJXx z0sQXlaO&VUXFtb_m~plp&3==&c^CITyDguh!`WTvhMSt*izw`Hb_@fEV=zM*jm~Gw zI(ssPoV^g;%uZz~X{Z}NjLdUop4*Gw#4-q-&W&d* zQ<;HI=guXG1+2n1F*hBZ&eiGM-RN|#yPIo{dBt(}^Quz|oz9bgp8WIlI`45_q7{0a z_bFc>_q_J}%&&Ap)_L7=1M_5?H;q3?Mz`~Jv6oYv<03kpr_*^ixXs-lm>)(FWSTG2 ze3|AqpfSymY5o&D#WOt5hkT5D^FQZHzUEuL=SO})*7>@fuh04Jb-t|gW6`e{zMZxXR!y`1747jX;8dQ85_9sUV|1;ucO3-q<%WnSeC+VCzPAm;*^ z7TECu_qU)A{TM(T!x@SFF0kJP6VUAfeJ)5xt_6G0;es374uXZ*C_rIkSXh!Wlt-5f z>te498==32GA^{+h3;~p4i~=7uMA^8Tds5J6hyk z7Wu73|KoL9(}wr>khXk_?iWQ7Lo9=ELyHm^#c2LuG3H#P|3y35!+s8NloOohEEo7U z2o{HsmF(mo7kPPvf)qjS#U%*G-y@5wQXSna*2iKuwfIS%!YqrQvd zU(+75ES^Ow%UQ)*>}qiaTiMPr>};`K7vJO#_mDkB=9DmUlMk6wkdGh|EgcSnj_ zO8J6ze8X>aqbI#_M=AXoh;CEHF_V?7VLfuC=r%>SDY{M3ZHjJFbep2vl1w%A9(UYurHY)PI6tiM&hXU6O-bxZfpiU`aTQ zXi7_3@d=+}uS{yVSidm33)xN>Y)U)S(^?(d|+*EPagUd4<<_lXrNZkN6lfES<<4 zbh`P@|D*IB|m%7!Z2gu|O_kv)V9+wp$f+~1_Su^Z)*%SPa=XjBq@%A!r zFZ+sb_>FG#q&NK-KpcY^&n(uk9yhwoewVq?Wjoo!ehy*Z%T92bf6(Ewhe42L-)UKK zpJ_Twv+uP0$emUgcbZn53Ya6!9BI|4j}FsX&=RwxnI-K7UP6~?AEL*!&uB+`zUN2c znU5~h*0B*?rs*_gw&002)j;>dn3xbvQzOp)cTWK#V^|5j(2e}gjtK?o)7G1B3 zpfYu6%4697D*In0|0?-cJ2%dy?xWk)S;&cwSLa8^s|(W{zrWgkS0^%!C3t7GZ)Ei@{NC#GT;w)>bG6@G z<2Tpj!0)c{yKC}M2K}sgf~R-}Gp@0tHLZA^)|hvVovrzhpZS&F=uB675Q*Dc6HN>Q z(8HPpMlptQ$h<~3Ym!*NB2qBNnhk7b8#-FEkAocHSP-lY!M@hkpgxVTtF?BuR{pi} zua$qT{A*v~Z9bzTvaapTU?ww_WW2rBO{`tc8tiJVU9H{30W#6$+RI$!Cb#(q-LA_` zacWVQ1~jG_kE7dlvaOSCoowr5Tj%eMb#kryg0J|RZ?W5T`d!xn{jQUFoqpHpZ=Ia$ z4)Y)g)>q&;+N0<7f1tbd+u6ll_T#%hn4M(zzC zAlnAt&W2ym;|7^F^un$;^rb(sEaYquY|OzUltCXG^|4V88(+ZhZETBKH~xeoe``LJvzq!R-?(;AR(zB4AFyu-vPdE`& zrW!S=Lp>T|hv{xBy(Rxc-|1#Ze}nh=2zyMo$8>v4|BA2CQM#R_`zF%Oldhxm{tU$5 zYw5Fa-|2RlZa?X#(OdeTT)_QMzD+vb zq~lHP_>~x9iDNVq(CenD=ylU<=8?oIwsMAZ=yj7`H_5a~ubcF`Nw1sqx=F7Ydd<*l zMrq0+TSi4HA!CM&88T+bm?2|^PBV0x@hDI8EHY=jL~A}orx`lU_>!+_&-dswqZd)= zG{a08gBVIYi`k7%Gi1+@Jwx^k*)!aGhVM1Qx3f7w?#;Q;>*gBBxVZ`TytxhUVV|4b z>E<8!ncr~xo4aARo8uV5IP|!A4)a-nESufu<}^03g>CFa#?AXUz#(Mae2KrX_sz0y zmUZ)gS#`W64<)EfHEL3a`nc0AEs=Z6>%7goe84B@af=?exP>k9Z|OsS1~Qo8jAS%p z`GZ-QWs6z1zJe~c>R_u5wz{XSov@3oI@lVC-`v`d0qA6_+uG{3woXScTm9D7|9(p^ zTlKP4FI$(ff>rz-1lvkthHV|t>9%xqu-%N?KV<~JGX=lB-EVJSh~L_-3gEcUYFP7v(O%Oez`H12(8I1#w- zolSX+7TC$o=Xr@%*v-y2X@lMDw3D4W-Px5s=xwL|cTPfAJI%H804M+ZCz&AYE*W?E z{aueE>#iqwnOE?}uGjdGk7&y$e9uqlb(j6`>Owc{VwdiBZ9-SOw&S5){x036w_X3e zdxmpdd*s+7#~yF&IgB0bxqu9N>|)P#ytU_c5bVuE6pR`6kG<#c{$B6z_5R))JPd+;?rC2!O5+~(xrcpK zsE+yf)uAc&w$DB6a|8Q)qx;_F1MF#^``-5*Kk^G5>5M(?lXYJ_b4h0>d)UuGPGJxG z&SMw*{^k~Uv4{QH$W1;9P?)0F<^Co-h2HkR!CUBWzn$%ONBi3$&wd&9>udjT5*f<` z>~H^cW-^;4=x+Z;GT6!vcB8}nCpp78WZi!meIAhUfbI@7L!JZA@H{W_Ci*(?E^;0C zoUizXZ?V?{c6y*Yz39zIrZ9(O7Lm$Q)+5t_quAqto7_QH2mTF$gCWRsFbBEF%Og}m zX9ufOi@G$RF>)V#oEEgi-ya7%G7eoFyd4CG3ZdsiavqZBkewYaL1n7ow-5X6!*+7m zZykODT^xRn7kPzO`2;f`Hs|3e`p}ob3?l*aAD+Q1+|A)676!qQRv1~jG_a-8t?iP!lE zyFBqFU!$iJdOD$l6CKgf3A;RD{uAauVg3_xo^YEd+{g(xa$+t?EF^^`Y~w-@oYc+9 zJmjY!g(*XMDk9&>+SH>VGM;q1C*?c&0xx5qCtpX-lWy&#{hjPf9C|w$&j?2GJMx^A z;iS7dxt%@i=MWZl@)W+Gljpd>!yq`Nzf;)>LyxEOQG(KxBOF;zRmDzE$$08LIv~#} z_jD?XXa=FLQ^S$#)C49o75hD9zo!;qx2Kk|oLwB}JeRr3-`os>({AjvOsDPh^gNRB z=TH0dr~UcUD{v#H-NRD?BxK5 zImSuOaE^;y<|==4i@V(CVGx|nLN*Fe2)jLNw`afMH#%dkv*tRxgQFbB8)v<7PM_zV zMu+E~<3-GN?hnj!ZVvN<;JkOvyPxykIq#kGMQMlb&U@#)cg}ZX8|FCgo%7x~e<}zr zG^8cox!|1(c6DJi)A7y)?_AKEQG<(l@yTrA9|*we+I_=S$FV<)@O-9_E~S)C>{ z<1t!bXMc{vp8lM~6!do~E7{3GEB9 zAjaUG%ig&>nHxcHB?RwW@y?Yn-sUsD;48i%4YzP*Gh4Brzrv|QJsQxM7!nvsB4fG2 zJs$8d2(D(KHJ{*}tKPZV4)=F;Bi^~{ovZe9tvt2x&Nc5`v!82yiN`zFymQTdu3h3T z-nr(T>-KZK74P#QZTXaitY$6iNe_a*OHzeu)Sx!Kh+{BA8O~Y$<|eoKCkSr5%)5B! zhIej!OfoC+&JFL}@EzTB=Qk_iotxgdSrd1DGZydM^v=y;xbvIW@Xk%|+`JP6w_c<#^|ocW$|}+eN8}cW!&7u7$qpp_jIK@J?YIJPI8(|&Ich`9_2Z_lf^q(S}~D1cqfZ@vMdZjvW8L! z?_~8(){=ZnXS(36tlr8xfLI1Hh%t<1921z0-_AOh`7CDzD_PApwzGp>9OndbXO%na zRjzTJ8$n365VDY!?Dz-kWRo*nVTw|b%2cB!wW-U~yvCcn&AYtMhkQeO%$MzZ%$BVi z=F6tbY-YJ~xxuXQk+WIX=oMfHMB8JXo`CdbH|MIn>OdYuJvNL(Lqzn-iEh)Xbr0 zxQ1CnZ}SiL`8Np3ksCYCVaGZ0QyM$YQI_)5!j5y)p&l);;~Y=&6t7~(IbO$I=lB>q z&haUq^AmQQ!;W+ON^k5qhaKnWOFYA|;~XQIf*t3WhCSz4#9~rd!Ui^yP6qoqz(Edk zo(o*$5_d6g4mX{{O^4;e%wc8@%SS299A@UQa@54kVP+1iOLNQ|X6CS#w8G3`W)6FU zwwO80%weDLBW4aWb65u=F>{!i!=f36nZwK+HiF+VYuF#mW*$kbU=?dvAB5!0$|Dq@ zAcd(wRcat_&U(1VoR1-MPI+@ajjTCk&DokZEJt@ax3G%U*Lm#WUDN zt|Vm0B||Qq=h}=vlk2}fvj_d>I>et`;Tku%jox$VJa>TnxwE6=-16r3R&L)%?yu;= zKt`jF+}_Qtlia$Bu;1KnIrqaLBu^H+ktYWw2&W>IsY65b zkjKvQ*jXMs%kvp_mdBp*xXC>I7(g6Du&X@wlqZpy%t59+3victmXO9u^ps~ETiL;G z_9ADVo7}-2=Fv&s!pM`?j`BXm)95^}e0kr(-yeD3=Objz>+g@e-|_=L(}5^t%sZ4} z3}+I__-^v1vWyk1Mz*}ZoxFCRSC@H@agsBfL#KH!bCti5IbVMCn9p~R?Z|5&a5sFiinlz#*kI{lx zc#rq_02%VP=X-ua7x{mqGku9cuKaT4H*fwu>}4MZ$i$5K&6xidcabf>T#w`;FON`& zqLiQ%zO_fHBjY1=7{WLvp!Y|n1R(|d=L@*G0+pzO|9pXH?5BYJ6c|Bb5K=HZW-nM6 zf2N=}3U){Cg7#U^f41OAd=mxzcER7#Z$W=g6r9Bt{t7}0$yvzvRHz|Mc$CL^hG%)6 zx6oUmwtUJLe2e}H>90@+I^w-TOF7I<{tZG3hmeg>?5nW%3d>!%9F?htJ__rjaAWMP zu)P(wx5EA|Df|h&naW&}Sjb{lvWhhvaM8nit4TCOL(W~H~fN* zih8eTSNaf*Z=mQT%vN*(<|?{`6|80*8`zDvih8T)p&+D~eHClTi+H2hYrM(Zw8fr^ zeL*|g^Br!jnC!*w1tG;F&~b5prnub}_h*XxGsQpWSM=eZ%M?;v#^N#Pr1%*wqu1gO zgOCzg$WAWuVz(viwuBx^l&2AG@b^!NUYNDSbe5CBX5=Zc4L4KbB7VQbRsQA{ce#)E zO6H>gg(*f!%HXY%zL}DhcnjG}&f!Q9Qp)a2)#rW8Rmx1IqUb|k;u%f?Bk|`-EoB*L z*h8s}$XjYF_Fn1)r#Z_7E(IZ_pXF6_S^5+7So$lz2g#fCge|cS22q7O8khMZB^ibgyUgJZ&UEvGb@g4SB z!CouaYXvt|p)c;K!YFiKVLZPxl^M*$zAJ3NZY$Vr1-q?qhI8n)f@~FJs~}qi*(&HZ zT&{3?4KG9y+Z&cvAElcsmN4OriwCE+{ZzVAXCLtWOANAgOG@TtjHIU zgPi2ScN0+%-%W&WBT67^ggc1PX+(8u(ufwc|!tSSC+f-Pa^3hy}@n%LFQ_5Rx5}-SCg$; zJ$yISUZ*wQuJ$>;5C7b{kZM05OSO)4rYi%Gt=dF>XBskAld;+&eEZd8tG0sG=(ySr z^jd8X`-70`x~g7^GU%zg+pGRAZm7B&s{Re%VgBk#xc};YySm@5ZXeanQvCsTP{ZBS z$cx{sk)HyT#qZWAkKe9Q2i?~&Z;b{#$zxS|fwq?BgIuIF8-axQH97af`c{p~k}?q-F@YC`3_8P#XDbR-igE*KABP z9_I;K@*;2YHt+HQZTW=n=}b3z(i`*Cj3J&8Br=u>n5(9~YwEk^0`y(eTs3_IHQi6m z`{=utytQPhrN3Iw;D&3-QOg^(1~P~tc%xQ2d$IFc2RRai)V816_EXzzwIirPHEQ6u zYP-YQZFmp6sQoc^QM)~6s{IqcV2;{ju#4JuQF|t{n9F>Y;O1(3xAyfQq)r$`D305! zBSRe->QtmAZlq3q8saAExQRNgc$GJJ3pwie9_su?XLMR;0CAYPP9oEhp^pCQtYJNR zsI!@E>_DbEx~OxUlicDi_t0~lhe1f)Eaaykg(-u3_Rk;;saux@*hAfBJWdOAR`)Y} zM|HnOXLWlKh27WfOMmRCuB>(SS9d%U`GYy=uI_SHv6c;NLjJmP*S*9|?%*!!%3Cid zdB}(T)|0nhQOXgHJ=d#@%=I3nIZyI5Zl~TWyvCd8xn4(fSkK+mJHww`;Tkv4Q@wwK zkos=1el|j>h92tso%-+c3E%J?ey@Ia?5ln(!x@RW>zlj&Y?ff=`ev?g=K5x?zk}WE z!|e4B|_si)#R@r zq-icH@ecZIs!RVo!;q#jHud{WJJXGx*jv*YDMf)zfGCitGGV z1}$7!Xf}<=ALeWDm1G1Pz0If@&6xbUqB@_59Z2hf9P1KNxpM?26?^a6Sj?ME-6m(eTeE%Y{e7k!96MW3Os z(AVe(bQ=ALenLN^KQP7uR$(31V*|G1NbJCF9ED?Wd)xu{#h2rLxIZ3%2jX;`firOy z&c;J<9v*>5;z@Wio`EayAY6%O<9a*?Ux}~6S7Q+qd;?yH7vWp*9e6Rm7vG1Mddz(?_y_$&N9{sEuHKjJg2 zhBdP;HkxhEc4E7-acmNs%=TjYvgvFFo6Y91x$IQ7ke$XBvD4XNwuJSuGuTqLjICj3 zv$d?Boy%UuUdt|EZ(tX)H?y~~_ptY}_p!^_``Hz2BfE~>%x+`Uyc?3?Vz>?iD}>}Tu|_H*_t_FMKi`yKl|`!o9sdxrg;{ewNv37n0ybCH~b^Kk9B zj$Bu+8`qud!6kDkTq@U->%|S=hI4t`2yP^o&yC|IanraWZaP=Wm2u_VOsSN$w1Hmiv|agJ*e;*YgJ6$oJsm_;@~nPvn#MWIlyY<$LnI z_%yyZ--plThw{Vtk^CsWfFHw8;3x7^`9i*!FX7Aha=wzU;%j+7zl2}P-^t&_FXQj# z@8R#|@8g&A_wx_%5AqN3tNHc(2L2KLQGN%%li$z3#J|kH!oSMD#=p+L%OB$3<3Hs; zs)TvM)q*J8B-|`45|#>g3ik@jg$IRz&?u}Hz88KHeinWe z&I#v*KUJ)XQ>j%Nl|f}xSyd4#hsvpnQbnuUt2(GUtGcMVt9qysRY|Izs$QzTs>@Xa zRq3j1RgP+iYN%?2YNRS(RiGNLnxLAZnyQ+vDpr-M%2XAqO4V#tt!j>HuIeh))hba% zR5z#=surnkQQe_hth!6JOm&}Xx#}U+3RRPbE@CeteR6tsiW0ibvt!ObvJc)bq{r_ zx~ICAI$fQu9;_avzCt}(JyAVL?N`^S>(z7AbJg?I4eBe^SE;X7&sP)mP3oJ~i_}Zi zcdGAFKcrrvUa4NCUZdWi-l~2~{kVFYdb@hJ`Wf{h^#|%B>d)2Rs*kHrsDD!bto}vA zXgG~pW7b$ST{Yb_-8DTlahiBdf+kUuq)FDKXwozTGy^s1n!%bOnxUEk%^1yC%{a{@ zO`)b#Q>H1`%+}Ou7HMwL+^V@vbGzma&0@_G%~H*sn!7ajYF21gYF24BXf|pd);zA+ zrrEC9qj^^IoMx})Ma?UkS2eF`-qF0PIjQ+Ub5_e}krr#UTAfy}jnuleUTtS>7wtf8 zmUgIiv^HN`pq;FpqMfQO(^hC}wDYtL+9ld$+6T0&wQIC%wOh20Xdl%+rF}-bSG!O9 zy!JKi>)J21-)O(rp4I-UJ*VSzYMowZ)7f>AIkyDH%vENH&!=MH&r)7 zSE?)1)#zsHZr0tVyG!?g?m^u{y7jtEx<_?S=$_O)rQ569r~6R%sqQP?DcyIv?{#N& zzv|BEIlWr1*W2`VeVjf?-&>!q&(LS;hwDe_3-puqQ}k2yGxVkUYxURb7wMPk@6_L= ze@GwDuhnnSKcatB|AhWY{oDF?^&ja!)_R~nEreH5Bk&k-wlj`Gw2NlLnlL5 zL!u$ckZkB{xZKdskZTxf7-1M|7-tx7m|&P_m~JRGTxGb{u+VU$;SR%M!xF>&h82cJ z!^4J6hRufUh8>1C3y<8Wi1afETSajbEwvCufpSY|9Y65|cVTa9-a zml^Lit~9PTt~Wkv+-iKx_>^&%@u2Y?58{@ae z)5af-KN-&(|1>csWa3R4lf`5;MVM@+C{whlr>U1I&D7h}$JEz!xv8J2ziEJJpef5V z)HKXA+*Dv1V;XCkYAQ5MGtD&3GF6x=O|wn)run98Om~}>n^u`Nm^PXoHf=XOY1(ai z!SteOzv)fWTc%^C6Q&x0)B5?=jzNUTI!s4wyHYA2n|?KW*M^e#ZQwdB6FH`E&DE=9A`A z=3mTb%x5i(1zE5~Z!ueJmRL(COJ_?L%Vn0XmTs2rmJ~~>rKhErCC$>`GQcv>GRQL6 zGR;zAnPu@?>MZq^`Ic)e*II72+-6x~S!!8sx!>}*WvAsC%O1p$Yo2wCb*y!qb&7SW zb%wRndaYHo66#Yl{H&_>1Z?xWIz1e!3^)Bl&>)qCetShW5t?R8DtQ)P{tlOBGMvy zNA!v48*zC=zlijRK@lS(Mnzl^F)3nl#FU7s5z`}PL{vpoN7O{ji)e^g60t1efrtkq z)J$Yto>K}Is0$+-|c@yqDVech}1^vBF&MO$jC@Xq%$%mGCndPGBGkKvS(zU$o`R8 zk=cBl99hM2?Ic6*)d~Mr3JZS!8)+W#sJ0`p7FIuZp}nl0;q?dA%dT;cz$| zQI2Rwdq)RHXGa%DcSjFLq9e)C)6vV(*KxUHpd;Op?Z|NqaSU~gaEx^1I|>}*9TOZ= z98(?B9mS4PN13C-QR$fNsCCS7%ynGlxY{8)h~oywLdPPs+?-4-f3`JoK|O~)8X_uqnt6$ z_Rdbu&dzSm?#={fqBGUm)7i(_*EzsB(3$1Tb`Ew9appNkI7d74o#UM2os*qYoJG#* z&Kb^9=PYN1v&K2wS?_Fc&UX^$4bGdLw>g(MmpSiqu5hk&u61s7ZgD>5+~Iu6`HXX~ z^F`-t&bOTJI1f8Na(?DK>OAH=O|DyAi(PlQmb)Hu zt#CEEHoLaE9&_z*?R4#OJ?(nS^|tGP>!9l$*SoGmuJ>GrT_3tWaeeCg%yrcDt?Rh! zlW z&ppCD+CAPq!9B%2)ji!^=B{v8x@WtubzkpZ;J(Ryv->vp?e3-SJKguV?{x>xPr9FS?{e>P?{&ZCe%<|s`%U*j_aXOt?j!Ec-Cwwmx{tY!yHB`( zai4LYb^q%A!+qX^J-kQo7(G@`gr}V+#?#)@!PC(b>*?g_>Phe*o>QJ*JZC&-qnIcZ<%)`q zijC?K6&DpB)hjA3s&`aoRBqJJsL@gRQM00|qvk|i6LoEr7_}(s_Nb*%%cJg(YK&SP z^>oy;QTwA_ih4Qf?WhA$2ctfYIui9|)XAt*QQt+Ki8>o?jVYy;pkYdqwXe?=9Y2y|;Onc$aza_1^E@;N9qb*t^NQ*}KKN)w|8R)BBWn zxA&m;9q+r|L*DnihrRE6Kk$C&{mA>V_Y?1@-p{;8yeGY7_DS5zEi42+R6F=i%$i5xc~ zKYo_4!9NlH4Mr5k#uir;`TYUL!dOKtvH`}%*kQkgmWri?=Ge5%6KAvwhhV78CP99%U@Ge?8~k$uCMe})hQ#pnT|}4 z^^Av!Vxk!@(~gN@+A|$QUKB)?s1`M%R@905^-L_&iRlbKW0c zt1Cz3kM{ZNs%wj;SNNo8Np?|PQK7kW=m7;q(=&@|#})aHyH`qfa-X>D)Xc=V)Qq(3 zxIQ_(a^sSFXC(H{NX_k)k}r}zb#=w`qS_(KTnf$3rhC#nL$}m0wdBOqn55om zF-bj>l4E-JN{&f{ucSW7@FOv`PmD%^qYsnC^w_}kWiDs>G5whV%s?ic$zU=?i)a-i zM4M``hA>0n({KR7Ev^&Si;swp5_FqrBIphgfHA|&^2@5{ zjwqT_URnecmM?`qX4LwC&K77jrmnoAysq5mA6H&dS0*2tB^g9Fga%tgdYsR9jS2rZiNDFrM)-JvK2Dn2F3J zW->E{naUJ0)0iS=I#bM)h#oOYj269OJ26IVFLn?+im_rRvGXQo22;wEG3CrmW)@Sy zR5DdeHB-aP7Q2XXVwyNgED|flt3^?~S-f3bE>5MSNf}>UUE+&}r4Om9^Ho%om-?!T zeOYBib@8D^#%EQR0GDO>{SX%{s;VnAdqTa2l{arVyt>q1XpXwbU1^yR9voC#U0;*$ zs{o=xFcCVmyGV!3>grjQMYXdE%^gE6MpW087yJCuxYDnoX%?Ehg<9oT*Vn=_WY!-u zr1@IPimFO|FldKRPB6B^{Bft>mI`J~GYk*n6+#q%nyHf}q#T2a~N$_FCG)7xQ z30r8kN_Rkk)(xqusjn;W%>(RW)6#M>vN98M;&OYZrpBcv_39m$k)50rmzB~xJ1aXe zJEdnv)~Ex_t;}uA?aUn$Wer>fs%yObD?A1TF#m37?7+{g4-!`#IzWA0||VeS><#RM@?OcImVFv~%`KEON($~6TPYfrHk z{Dk${ia~o7)%blSLrOq#m(M7N70Rjz_$@>!iK{XjAo2{;^UbR%sw%mlM+e~Y<~@R1 zbTsgxq;93I9WQ7EcVW=n@`^fNtsE@XGNCpw8>fayl2Kb*1k~8TJj^Ts znB{KalPmFh`Fj~N=lEIw8Z53^A#FxWu9PqtYsc!9%r^O+nF8A zPO-PxN9-$JF7^}quVtQOo?>=^zS|9y8Xyi7M}XcNDbtGTV3=j`tgPzFnpz)7Y;~1n zV1P~FmL!1%wMA9_a#)nK9H68lJ9AKoj8tae9u)vtrBlT@vZ|tCbbVD7Xo1X%>f%{` zYSfyMuh1M#2M)HRngqtKgVw>PnX$6AmzdX?9;=y`nOB%snb*X0F+2FmJ+& z-WIb(s>Smt?$n%06V6esva#vhs=&=p#|0(Ck%4Y$=Aot<9}lvfW0B~(>Z5!0ztOj4mavbF0eaHG`@ zsbDlN>~N81B=@<g)21o3_aPci2gZBlt81^Q<3FV*`rD;#`OYR&P zT&gIi`itp~V^p;tbZ>Q4O2+=1|J+=;9QA`O6Da!%c_THlzOJIY z%18ZiIUh}z9VB)m>W>CcTK~VLZc}=T_O5cp?tB9?!T$G(JBj$wBV`>8R+kq52!T-wbj*iBHEzSJ3Q@U zyL9g%M-SdL7)@r2HNs|(32eo<{^AOgXO!U3nj7LK4h!Q3=e;Wwaiqa!d^i+t zqG%3Wulf}7B`fwVkym=!n?C1+v z)|32?bl$C<6XO4Tbgjy0wMDuPs5M$cK}}Iz*#y|>`Q{CVePKYSZ`I2)!A{#(=Z~LP z452Uh#f%Oh;Pa_I>IYMgUV;U*>Mb*;Ev`s0Gw|>T%PJkTvRi_e=On{Lhb5qMf^VJ& zK7Cn5Lspruc-D|AstT!9s)+Z`EuT>bz1&K#x%%}{-u4|kb?qJx-J=aKL-@CyrBUYu z_L-6eesoM-bxdVZc~uN-IIC;p%Kg<9G>R2dF8kT#SNdvWy3h}o71N!>yt=+!yTHwu zq8NVz`0BOQRn_(Wn5yckP|sjH7^nkXgjy3zrw#vhz6{3g0^{bjGM=AWtKyiNS}O5% z4KZE(Wkt2Vk}fgDMOEn1B7^<6rE)jm|0c+LA6`GR^ z%6u{9l|`k#7=R$ALndsRO7b8U(IKX+$R7h^)K>vI<)u}ycBqA_D4`TfNP@>C7MceI zcO4QnW>nY4z#1Vu1kk~DU^*}WsQj49dVd`}Y>qExWKHl^9cZl{((Jp888aliiz#jz2T!5DQgK7N~4;p=dN8YLgbAnpq&?pWuKN}iJw(uuNe74vNuD#vPt%4g6v(@=I#cFUIOa&7w*P|)ce15 zHaXxhzl@1N)s*qoHwRlYvEkvNjwQWudaJ`(y!+$}Gkn45B_Y#DE zlNQ&bn%{BD1+w#eOOO^f{0}sImBCKlZe#JLSjrS1Y#nKk&InaaxT{jcc!h}o$!S?vyYR7{7?mv!qApO~E5t9Rdi z0|sV*Zq*tuFrTY+I=z90?IGmpucJ8~h-?+l^3{%&teby)R&}k9rcl5@BD2L9Za+ay z3|{pfJUhbJsMFcCEPU>+3=&D_8E0JW za_J3lJwd*nGVS?+a6QRLt-m=X^n5E^?AayYa>3O!u7|E+(-l) zUD(yaehCdh`A~H`5lx1QTOXQ<{7`R8E!r(mYr7QPgI1z7Xg$=~?m)ZH9`rnV9XzXd z(Fagn`vp1%wY5K@v*p4>Xto+1ziqJfPo`KLddJ;Va zPk$Qi7Vi)ji%Z0%;+<>I9`KH1(O$GqybA)g2Js&8K564dLzzl+o9>(oAY%v-Fu2?l z=nCzyWdD9-6|i?XjeCuS3LEoa|;)CKt;)+Ie z5}iWdi7Ulb;#&HUC>poODe^ZIRLg!@o$m_z*etjX0WGUEMn2^DfT+b%3}ljYiRMyi z8ifX;GmGkq%V-FWCQ+o`@1S46J30$7m0!_0^c(tpg4C(NS6exeW=l%)i@`OWC|#6B z5(6S5t`^rEgf8dNpO^u+>{J1Dk;lW*D(Q|@Y!tgoVGPV-?t+1(LFv;2n5Qv|7PAW7 zyx@9hw(?WeSR+TdL(7pmwpe=rYw6=@Ec_C!3T6N;I;Pj8OL7nd0~@ggvQ*fF&Ef`e zV*p!mg!r(ynS#)z-tVg&C3)oFriXH>Qiw5U9;6)T#%4%1;L*NC%PiPkltQAkc^fHI zjh)!FQrskm#U93<08O{ZccPhftFTwxB0?0sDL_aArlE0_$Hs$D`9c~=Sw}}457BKL zi#vfD=z=f9U2!+u9rwU-;#To7@o{mRxLw>K?i8O8pA?_kh!dDyI0+}?6r75C;$Aon z_ZD|SUS_xWjJQYqlAvO!`6uXlf^Ma>h*3nbDQBDy;Wo(9!On0L>=7ZAndyUl17t8O zYl>=Nt3-v~S2zY}7)-m!UFp@Sc}4TeD`BfqBJB$&Hr;{M*VMu$2B;TIPD`gYN?Hc| zfMt~1z9MNJ(sKZb2;hNi-;ARAiaIHpE+@caf&;+S@*1dApfevO4>P=|p}HPo%N9Aq z0vR)UlWsU+(ZMH;qGw3_G{@9(8vcVg2j?;-Jcv1k!JV*-$PdwDxUZ^IO2;?5CMhK| z5}%e?dng_@soC8C9?mRje!&biCWr7Sd<7m2W8~ukJO+=&vjEFrHbsi1DD9SeSb?8a=!%fX;YLWsua)$EErhDQ+@j3B`cvO5=e7?|}5DLM| zIzE_ak{{R<4qr-&UJ>}kYboJsJ zbg@B?P`PuXbmuL4rxn*uX?3gg>;v)=!jf_Cz*cxEz7wc?7hVQi;(Mq`&CZi08&uhZ zy7EeJON%ONCY1zBj>e20E*=u!72gp*D>UCT130K}LP7$SX@5ddg>N227;1fU5~$0X zFsim%I#QJo=1+o?ns6aK6Q~}j@Fyr9Z&-sC-q|JZcFfp+<2Rc}Oxp?jA$&i606z#8 zvgOh!-;1A$@5$`A0=rh>mEvJwJGqz(H{x|nWFuaU*Wk6{`{D=UhmCkW-helXABi7} zpNOUTvwRH&)J9GyrY3jiOTyRZp zyAwYlb19{y^bAE172#fupTtk$T?#i}w4H2Cv-2+O52_L3truRU6x)rT!Fwjw0EJ}X z5x)>WFEo#A6O;i&fEglQGv#&e#rr17VP8oVHR9*-3!wCxT>|%Q6x|Y)P{?w?b!w1% z?#C|`nlA%XTj-r8!EdRV1Ndc1ssFgW%ondxBmA29m6)pV#hdsL)HUF@@Z0zRK8WAJ z?}}fG$HZ^MZ^h%{iM32DK8)XouMZhoUUyPF1z+FEbq&!_TTow7LMseLL1o=&AGlTi zImX&d<=hszZJh1e-KYM;uH8JJ|+H0&@_UkQ`>HZ$APOn7)%^^Ey3J^ zT`~A@vq>F8260q*6$B7lT$RfV@K02%einZcH@%O~;$QJO{2Trq80-&x9{-7JS;S(N z#V1)FZ(vod8jOyjW?EoMWeZ#?s%$8iQztXtFRAsG7{j_jS=BWw=Yd+KDyd#BXq7H( zAK{aHiWYMR8n@^}M{lnF;F-!SoBX*@QIEKvAeJCr{8=Jrk@zt|3_)BAv(0K*oou$5 zUE+E1m!LHrAu%0m!LGHem5pF+teuTy9pV}BtoW;VPW(;$y~!>%Gfs-KZ)SazOU-PH za;cd~Q7$#JCBaKf2V_--~8oda9&rwD;qD7IqLSV+vardI-NA1Z&X z-8#r#&Y0MK=o~wM9Z2hErx*Es;P%AV`XDS1m7pRJ5EF#{-!(Y$;xpMSC`bVd8DKN% zVj)3Y8DCTb{-vz-;w!0zi!T8lzOX_>7E?tT$AjTe)P7KK*+DF%E;q7+*&*yub{IRH z&0|NfBiT{x6$A+csR&XNq#;O4kd7cdK?Z`11erE6yVwGD3_F$`$Bt(wuoL0)WN`#R zW`b-4*$Ijys69a)2*tl@%Y870BYqd!>NB(GgF!WiAPq98a2iQ2i@CnpP`cQ5G{83I&Vc z40^)_q))o!2w*15>l)}vsA-X(s4!AFTfsyI*qQ7sf-D4C18gN*Nl*m*FU3lVN=oGJ zauONTAzT4hPD)Y9*CPH5{-->%j;(JINMYx(4e|w9rCkknl$}qILre|%oUF(a_BwnI zL2iOv1Udh|+vUgGs zl0Z4jU%HSAWglQ4Y)RRb?5dU*Re2)c}*t^{>k&2DFRushi&2)?P2#q+=zXaeU6|W1WKIPeeClD#S@fB3DP9sO;2i?j4bXndPFy> zQi)n0_+>i zl4hTk`M<@2XS;@dn?1lDWZz-mB`ArYWP(x%N+qc08umT*F#A6H0sA3Ay$DJps1HGx z6Er~b7@@wozEX;P`Jr?ad|1%B&XyOm%b{Y0YIwNiXn9Lses!&XLg@Nr`8Vlsg6vMR zUr;Tw7-Wf7EW?Q#_G^0K7(uJfCCV(R3Kf|wA8j)M=>>d8&d(x$(%=Li}| zP`a2pF)2AQK2iFw*{=#!|K#w6T)}Y?S7e65&YX%f0O>h3r{T0R>9YvRCMYLJdd|q1 zI5TJAtOVr}G>D+V1PvibDlxW(NLKidNH499b6!AWE~<&fa*LQI`pOq#nRSg^C$2LG zYGEir!w4EqNpBim5Yt>xr^4rK*zlBBNoIZ`e57%KTE9$JE{;AXo=e~o2?9T4BtfGj z;`R;^H>p?CuW7+wBd%>}inuhcZy3P=QxL=aCV~&-pe}6Pqb?+P!G#1Le<8sq0|#Wv)xP`{8sScPDojw~V`+yNA1%yN_E=P!&Pd1l15Uo1j{P`~-o@ zucxQ{=og&tlfPgc^oySJlfPg+-2s(QM79LX5L7_hN`E+nM8-h8vV0?id_G`6u zff62U*}mJw+K(ENT>$swgkJFBJucQb&sSGOZD7mhG=S6kT!3ONn_hI<`SsKN4G_Jr zY}r2HVvhy`OzVYdAfRQBi_Tri%rtMVz`2Ec6x=iJ5rXEf;#oZ zjBKYOyMx3KhX81_iF|Vi;D&6W!d?AVIm|pi;^OP9(G6yNu@X_9Y(cU6Rq@xkBv`G*< zre7=dhZ7jqU^<0LYeBUnstO?vafc}(-XmziD(-!PZnzX7KBk2DgafA=r1j<|LVV7B z)!Nj)hN*o+pnM0Wb`wkupp~^y$MoyusVTEK#hq^L0YAb6AcV7sKHwH5hpc3TsHAjE zpWTv3=eXZm_~G1no}ugelc3vIfjW^Di6q_hC{i$1M-h$v@1w_YL-`)%;U+$s>9LtN^A_I9NANb@ z&PVbN-pRXoH}B!22)dJ?y9ioF(A@;xL(shh-A53poBIiRfS?BndWfJEn|Uwaj*o#O zT(Nvd`0m7a=DYBh@o=t~pp^tYPE^}KeHw^rC;jmRQ9VUe?-SKAqDC?$obsVG85L#A z4zUx^hwfmOO};1T34d;NExkEe_Tux4%X~B@7z+own)wt`@V5?}OgQQy(U%^Cg`;$x zAPrgU%dCeAM|e&~MMd+5{vk6)_zAar24f2Pd+&(Cq&gCL)arxh^`m zR1gB$SDF_0%?+Q*_~2C57n;ldg{cgxE`qF^^t1Kxrv%5}*w*9c`)cRVbI=LFbXh*Q zLlD`g1>Mb|m>wK|Q=z%O&DSplIsK4(yhL?*^U0J3C$pu{Jh@FLlhLwXzWJCH!7(2# zG}pB0m=y0I0YZ`yx)u(^?BF~eD>N6i={!Q^gODknQ5`Rx+ENTw9e*7)SoQoIel9g1YQ!vp`Ik@DS~zp^fW=>8$CnN9)h0T%wNwh z;BVj;@;CA~@i+5}_*?i}`P=y0`8x=Dj$k$6wS?bBgqw(PD-m8K!Yf2LM^v4Os)48$ z64g@bos0xO;=*&2lG|7XXS>U)p@hUY2WToAE?7r>X?Yd(VH4=DaphH$lBOj1ltQ6N zDN`UUG+udk0WIxmX$|8?`AUoY^?v1SBi+`tJXm@``(|l_LUYoko*b<0Z`r@l+`B1b zQ35XzDEAjjhHX$$J-luJUO|upN~*L$`Y0PD#b82a^-{x0%neR)QAIVBqAQ zg-avIFPCT<;gU-qMGpbW%PBOc$pc6~Q^0$tRS5a@HPnJ$Na7Z43eA1xo&a+zvkJm7 zLONOH%a^tg&9Mnm{IAwU4{rynDd3F8r3RFq6v_ZJb-E-a;5@L>Qjwt*Jj9Gw@!*&3 zUBw3odLAMn%}o5dpj_`OG!K~wklP8`3%an>_5q;QzM+`~m(TK?evrO}8zxvXV2hk`sF; z#bu_X!0UywdnU#8PU@8gfMw<;ruE9n$beVnRMNy`T(SIGkvKRIR85Pf;wa#>q%kf# zJ2AC)ugv7QjFi+&2nhAcj?3uTvsYZ7>@0XHAC1c5Br?|mWf=)f59K+zvRE-zvhqeu#G%K z5bRP969l_d80ABPK3c~gr`t0A6nuYAH$5NI9U4KO(jTW_ivzTGHz^01edA?T0g6Io zI{YStm9hYctZImg!l5l-zE;~n)Kq?T67W~}Q!1qL#ZYAew25lhT{+A%_rBh3S%2zJPoJ3Dn2eU2~++BHsM`#CO0U=6= z7Q6&~O%S9RzG)O`i`LQp-@_|fmQ_~myUr~hm`m)Aaq-MPrauoQyC~^(y63V z4e%q?074ek06$$s11Q}F3#0x+Sr@LLvMv^90{7+s>5 zjKE#k72x0E-vm1d)==E^Hca$Bf;pM}?-w2b_8$SYcLCx4V4c125Ofh%2rCH|2v&)k zI;O|U0m6>ySII|HmD#KjUSWDXVvZHo3hRXR!UkcZ@UXB+*eq-j9uXcDwhE64j|-){sa#s zID_CUf^!HSMDP%ThY_4d@JKrCSB2Mv*M&EPH-)!^w}k`3LE#mmaqb0BMBQz*kr<{6Lth)ClhuiVXq|Yt%SXwup0>bB4OVl>}kT82p3Jb?u6?@ zxWR-gBivlV-9)&D2=_GMUMAd8!u{03PZfTY{Zy>|?*t-*v%&H8h34Xavi}V$hfbjN z(C`hm4|aTY;V}^5kKoY8Li5bF9Xb?*83M&jwRORdVVi#y4$i>*4KbaKLIKe z=*zbJ3GzI$VY5hYgik~joQU-wazXe+f}s$l03CJ%#k0c4*9XV96`JeX77CdV{}-V_ zl_fZr$U^gqi_RsO(@V(q&GA*xGOh$^&k3Jvp&Wv~1g9vxLO;$o+gDXvRZ&$w=gN7r z%BIh(tgiOWnN=~pqyftNWyge;WrLsUPk?BA@hmtr<4>3YH6FBlGp@YaALlQbl`uLd zBRelAzOtm*hEo+8oHo4Ifxc4cZyzBDhmev`fl-RBhAxBy=?TulU1)y%qOuwoP5 z;at}zIC$qm^R@rV;0o8n*(P6QdA;=FuzLSr(PThyT9^GxwlfsGZ%S~rZacGr6Y2I3 zZRaTP6q>&tGMHZbt5lL|aBzGGxxqQ*wp9EfHzuPbuX_4Ly_me<1mgeeX+72G;8fsM zJJbIOEyA$)D`!$QE;w>>p?Us48TqfR1x!Wp>;6hcCI=@4)ogRxc2Xf1;6G3EsfvQL zf!Brqqnu+niRf&aC!!U-DrNEEwd+;kT5U#fGH|q}qHReNk{ZR+xTxUF3eKVLKU861 z+z(Iu| z6mqxXd@cyiA-l~<5qkN3LN2_4gn9r_1X^A~-_{sTikpMefLG15?WSFR9ZxfFUA_=L zgWH2M82sO@98ldEoX5~MXNp#LEpRcM7WW3{Fuc%Q`)|lclN0t=D(u1FOh)`eTF{~j1Sd19&1EI1HslvWCBWH0Icm^MZOCVmRclmG5xY^fR<%yGUbR8BQT4ED zlWMbSi|P@AM-!Y+Z~?(%2p&uDID*F$Jb~be1W($i+A5bhtG26l&{9OzlMtQ9lOZBc zb8&bo!84^IM0kaQRDF5Lgj{$Y3@SS2=D}+qD~oDc%e2wk|3<#9V|dy}dKIyhosO@T zGR3XVr&%kS)cUtGf2#eE?@+x&@RVS_L-p#V@*S!Js&^rpuR5rDhu}hjrv+4pRPPa7 zL~u!)W&TtjsXmnw4XRIQq5)5bl!599BpPsWc%nh`M=-Rn`bq_9-$vEfs$;5e2=);? zgW%Fe)p6Ac$dcePg3JH=**?{ej7jxVc-G~`qg;BIEqNyz@BCr-`= z+3>bq$LcDN4bNV%W~BYbtKWFyG)?S18zbjC6k7bQ`cq1}sLo4Cmx@bJFxW-S!+V8$ zY~;UCt9U7IuGXpbO}TRn2Njg`Ij$zSCX__qsJ6%gthUPntaecWo~;OQeMo?>kp=iK zWVEd$M@lBCV}QNYkbbERvbQ=G*jwF6-I;z9>?gQR{wZ#PKj3Irh!Lkw1p2At)sUo_ zL-5>yI!T>O@H~RAYO}PSI!%3fD``D-KXre~unh!XDW~<+8H`Dt8O{jZMCX~oe-3U~ zcdYyKZO9D^-YG(vYBH^H|Ne7pP;gy=J~ zMZx60Z&gEs#RM-2sP9n2ze@>*m-4kyZd|=geIE#s`fl|->U#;kli<4uUe>5y zuD+iN(cOfeP5*D#c&Gy)l#Ss+IdNm|yrkvBH|`5QN5Yc`C%%+klP0V-a-Xl>ZJB zyh`D}4=Mk3R)0*tB@G^se**tGltq1^hC@XG^-=Yg1g|D|O+fv%`WV4$3Et3Vo{IXU z`g=+_s~W0jz*AXADR-JuZhaW#EL{#NQ#+&ntu>zgUHu2;*^LB4O$Dvz&>+U7!Qs5{ z*?RSYv9D!6`AlYQQO*yE;MW{Kpy8pd5Z?CLg};v;)GjM}_nAG{rA^)fWp9e&*Jw0) z33iQ6f_?KPCLf%+#;SpnM;kQ}8k@$hiPShWPK`_B)_62g1V2LXqXcgy_%VVXCwLpd z+X>!5@J@oC*r@T!uxmQVuxmO~*q>Bj-yMSe<^R>-ZLh&KsUSfbs55ygC_$RuAVHcw zn!fa#;9UeiE&l`wiZFLj;Lgxw1BYlbHBgQ648eN>njB3o!Os%>Vw-7j%`nYKkOs|g zO`c{1!Os!Am*9Pkno*i7s5CrJ@C*Na4Xzmv(lsGmx`uyTSkkyH&%AoBc;>)V`ceRp z#L3WhN_g9Di?2*wm7e?X)|ExwV(0ek*Gv+pX^JVGi>LAkyAb8S$5uh%Tl+`zy!Tuc-@m?0*IL zUl8DBRDi*oc~24G`=|gf*W6FP2?pc%zWfse_!_fU!8@Q?Lm8`40~YW@fgu;KPf&VUAAg=jU^E>6cbDG}>K1J|% z0nHzp^8|lS@Q-cAcUo2}z#v+VYE7t9JsQxesMZAkE1d6=lwFC|ptS(sU04*ZwQ3_M z-~B}J&$9ESbucEaGaS$4yM~|sc35V?wrS^TW-R@|O|jQ{plwum+kTTCo3ne+;Jfem zGv|u=W2#?jQu*3;+71%n+V&FQX8>@miV6*!__(0xItaM-GHuG=Q{LKC8E|cH8E|bs z3iz)I;DC`FVr97y;M#NmT$@4gxgg-$>`MWz9i|;Yu^6t+BlvfM{|IPDYDW=#p0KFx z03V|rPX`%G0f!U$0Qdv|oMl=AeA+yPY=v4du3?HsTcY&=;4CIA8w9)@K%5y4;$+8+ zU&r~vK|m;;Y$4CUVu8yN<^|+m7k#pn4yt%;*K}OEUQ2-2wP^3jV_seB(vI ze?$BJ-&60}4}#!-5|nmO_XOTRDkoG}S4i4BG-3Z0#r|u;Iu-1{y(IQOXn&%xoYwwG zST|uk0qxJ)UkDpT*miBUFVOy`g&202qSi4wL{W?;ES%|~yJQ{ge08nteD5Ch6E|bY z$UirYdHclS6^p<^96zAbKwE7%iaW3CSN_4vBX*Gc0wsR10UB62KuFKNp!g6%kx*Wn@M%bnu{J{-iCCw_S9hpmHsE5GQhI)C+fIG6^2PlC3S!`ps* z|83g$SB%VA`}!+;7Lwszn*m;^n=S)hBmo{zp`+U>HX$5v%V-6?avgmmr_fV3O9DLU z61|izwYvF#6Yy(-fL|8`9MnBwQxw2qpC1H#Koj8f{g%302%D+^e)}Z>U#7d40)Dsd z9>Vq_Y+68fpKdu}dlUBZwgY^HuCX=1SL@bLz=1pa1_9pyAZ`o?@%y`bvDcp*Zr^q7 zv$gM(OkpIzH$&Sk;caic+ZVNPTJ9H(@k4(fx93rKm0U=|x9YahwLV6T4D8B}26Wr0 zk?G%xkukrofVWErFK?oF!|Mq^qYtEbZ>L<+Ka5M1F3;=U{F`{c6~z0UAl`>5-Wdws z5S$6(P5)%M?6B)TqIiEy*h~fQ&n}7g*E&d^26V@C-w-yNusH$Uaoq{R<`Q;DoB40L zA9U1gfGULpexOPRQJVciX*M{FW)`jTDka@-y4LJ~p3zHoU?^dS$y}lbJD_jH4t%_1 z)7{6u%o+FKkEi;cjGYQc9giQ-gB{SfVh2ddUv- z)Po%W!1FFK`5@r>NPYXi2e`h247k3t47k1<1$?9eIGo)I0zNSWxIP{L*C!BmR1k1| z@}&UR_tEzQEcAW#mlJk0VeM+85!-&k2k8q8{3(kLPl%Tr;+KvuyTa|e9y`ISOnkN+Ww(6-J z5PIq#mjExnL@%YwQ~DPG@V^mH)xQ`7{FNZ!@E$(G(h?_H^~6?(0H4@tV2bA#;i2e82Ta2BYJ zKDy+}jyZYD9rM4B$o>=xRE{4oK+??6O497fWMZoHxc$` z$^-D)!k{rXbOz)NT?l)15P3s4K;F>Z(1U&xcqu!3jr)Io+BSeywUlCCnXtP32j$}w>{VAeBi{X;WIZ+p8f2k67|$(_^&p=-+Brd z)=>PRq_4-gjKNJ--|hEo9Ici|x3xMFX_?CW!FyGOj;Av5*9b`s#Hq3w_1 zZL8AFM=cq7+g4jjW1fBPs^)2(8#P870B+P8bw<6>U^E&{Mzhgkv>GD_yOF>jXJ9uGb~9nO5cUzmK1$fF zgnf*#k8d>EWx$OtLp!5~i8V%3z_%%YKOw35omAC7PZ4kJH9gJVHS`x{li@EB`u}@r zv#~n}j}gq{_Mq?>6F_*3iAE3oChQKv?v#Im&g^E6R#>FB5y~jSx_4G-esIjSy0Mny|YG`%I&8kZ~{-qCJFtRuZEB>Z^&2BN>x% zRJc$skK9$daqnP$O>xw$MXtk8rF#5;F(29%gtwi0=lPtDGc!NiJ@lbO?o=AQze%y! z#&O1pl+NR+0Pm#&Y@9>|cwcJ*tolYlr^r|$3vjU{z%PIR8z)f#-gi*}o@snJ4K1iAEb;7Ln(=itcxXllyb<?tc!~Z6ZR{@o@hHE`q>EnMx*f;;~C>w!a}a>7-7F@G@dj5Muq5G!XE$cYitu{OeQv5 zD96sdaxHgyaLl7AJ0fOmC@G)3xxU-V&rBkb=RO%O4qJ1kSY@pZb* zHYHO@{v#;K9HNpeZL>MU|4MS(OR|ZUkC-wDdp;=1CR#pX$}#2A@BhQzd%#Ckt&O`o zVPZV~K!mCEnotEo2%$(wFoj~xvWs2RV^>16*JJP4yJGLX_ulnB zdrHWV$T1%N-*wVu<_bQ^>pF$&Leo~T?I&03}6N)C|B1IF6CJ9ZU z&~$4pno=}Xu&z?0s3n<81^()+yuY!ZASYx-k=pT)4Mnq5H`b^tF^cBk#u~Y!8yDw3 z@D)`R)lmM678F$%EfkvWLeoQNcH2<2sAw_eU(-`)C=?8P{#Sc!MRkW5=*3FHB963n%s29G-W?6}RqVYFGYO7Olw?U>3Z6 zDKx!zqPU!{k0@IE&-z|PCuR%qshPf4(K-sSMwctVtN_Z)h->U>`AsiUEBcq}bms_- zKIe4jt9`FqdkK{mzHXeF`H?%vw5YX6T^?Dqp=hJf7=^~vTC}-ni_n;brev2j97R_a zUE4|TtLVC->s80G2o2StI$kci34`3+(I69UQ@(uRkddF9yL(};2OoRzowV_8Bkb)R z!(Q<1y!p|l@k4GqXzYDs3qBgr&Ukkf-K*yHZo1nV7A3sbTC|n!w#L?3ciT8PXTOJw z9?O`VB@vjsR5kflwXE1Wl$G2o&lJ6e$^XIBXwmCglfRuc`TMHLojH^DX*2o2?I!kR&ft`LLoI3ud- zrqief?GN|9ItE=-a|1A)&a9el?+&KZ@AG8VdODlVkv6!lG;Q#G zcJfy4mA<;c|E#;M8&x=KK3_*$*j4Z4Mxzow)4cZ)oE!oQy#{mCUW z?y5H~|MH`>t1Kbx(vD#_mtXF_zceY`d}+_#O^W~bcCJ#ZtIrs{E^YL%YV-=#ReT*> zC71GMT?7m^d|PmrSM$c1*%2P)15Cg`wPv8R^5d<4kjHbH1Sfe-H<9drK0SDzOB;GyHw2E2~2*LO7F%5k?nf0i=p`m2;* zOFl~kZ)#`28+Es+1~lkyPM7tBYQWo61138dP_J~$Y3Od<){NQjO`Ba^kMUP;oyOP@pVh+$3eEKNfe)HR zssnH-Mcch!oY%H8dp2aWc{TS!skhvvJFn?u71Esm-MgxuXNIT(0AAOP#vs7XxM+P))4w$QjxxQN2mGfxB)j`{c&RR zMYqo`J^Y6Ym_+$>n_f>?L&vbQOuhE}{;|a6*A0H|C1w8eoE?xG`svO3Qf_F_TlB^H z61`P#)7yn+hS1Cunpr|KTWAgtnmL>G4ym8MOy5U3rl3q{<}y#h{g#^QmVH|msfIMn zR1c-k8nJQk?E3oU9B+~Tu$+C%>fs_W^?Z2Fy|=Xm&z`;?uc}*F)umSb9THVx~CN|yC{4ozOT zUO!A|Sb&lD)~u@LruyaFuv(paW28QwE~$E|6S`rGcj7y_SH|co{#nmkKP^*8^|SO2 z{Q+2Xu3AKw=8EVtEGsnXB$%eTt%lZDQR?&ygyz6(sngf&tRJSY)vFDTe!0F*XljLK zd8>Yf{ve^@ZwKwN0;gZ8PY+iNdWI_$xO$YPKSV8XD>@dqlH8t0eT$w`&O0n&(I2Bf zRxNN1Lc^41y1=ca5S`eu5cP8Q_Z~NQ>>bw@#rJyc+$++{j`gPy_SBAHZ{O?p2fn`} znLKuU-z!i2?NN1Uny!1!fa~;pSYe>@^If~{`^Sb&MQ9Ed-1eIONvk|x zSCUKQz54rA+i%t1Cp3o%&Ec*32lNjL%@IO#|GfU?PFi#QEBaSe+aDz~*|iM%H?iki9qqa87~2O2UN$yyna{M}OIHs5 zB3;?OOW5~1hJCzOj~z))!DX3!KRrG5rQb%7IdE^w02oFz18GijrGf%?@tGw3$-#0w0&3(eZB z7Z{500)wu{P!*v$QQcac{)rcypG~Zx*q|fWq$C^q8wRM>JWXg$&y-}tzEY84P)7?jZM{|h=$(^JIsK5KJzwlz$;CXMZZixa zY$vyEOnzj^SpSldzua1KvHSFmx3J7D*K`_u26YvV!LN=C*5QqaGIAi9&OEuJEh73Jj+jPE!#YjDBV2Cx!n$ zogruMe;LkGJ@FjFxk7Wb&|K4MINxxA&|E7tH|(+|z_8x1Q58ZXAk-_GDR-OHa(8`a z{p+(Ie%E}P`b}4NbxsNQ z8q_9Q4jArBH$S(lMR=21gs=b0BK)Y~`G3~kG`x^)d0xrP2N=>L!aH+C`0lp(0QI|j zw$0(Q;CjQmLUUKn?byGzv2ZqbzC+9XjP6u&)4Yby4PU9A@P&b<^d6zPx7F~q;TxgZ zDl`x5y4L1LgLf72NZ#d8ySn-Z(*U z*}I1G9sb5=x1D~r%lY6`<8(@ovD{c;oF+7{2+gZP^V$aE4C73-^t>)KZ~X69yT(dN z65$NI^mh-Nk84P_P{>}Zrc6gbjhtI?81&=qffkW+v3Q`Yu0|(=hXP20fzIr zexh-)@jzA2OVsv?y^HU)8kec<6$f8-sC4!F49F?&AY)Ue@G>l=@V-moH7--D>bE<* zm3!r2qq?p9AAF!OX1A3a*Y+wivaQ^xZY$TkpDVm9h@iLiwc6YIrme0vs@uwq>xAZm zoX4r#%8mb$ZdVbS57qfNe$YY4-34d7$hcnB#KlHBejf|XC#}X-BVE5wg@%O&J9VeO z;f^^iTxz^R6>^!XZdyvzeWj{y*8O)-oZgVzT5i1F$ZDhx-*${Q8*fql6a##ft>tNU zjh!^Ruhbjw(tbX%{Dx}+yZy2LYxM)&Hsd{ny|<&Uta|CCOL|MOt8eac(eZMh#Ad?k zatm3F4;V8$%8ltA<(h9*yQ^DV$iR*R++2>IG`{j*j1Y~lW^3*@G5*`ecQF5Zs`#ChUOzNk)9UE;^H&gmk-ETs}R}yuy$Hb>PQzxJ5 z_OO0#Y0$+!ylvTWM}2a@^7L9}6QAl#oqVc${?n5`8#;Hwr5BifE&AolITN-QeUr|V z`BZ1he5(5sW17@Yb=r<+L+D4`oYj!YW@39`Ze(a@PS)CPPIgXuPIh*BPS(_~piDZ( zG$1o4t1V+(f2nKhp>#$pO>;YIUXUv6GzUVo#bzOM_ZXscwqU(y5VJO=C=B zg%%&H%DY<5G%0fmws!YQ-FdtAaPaJT+-(=fY(Ku9bN#EA)iexVUCsINRm+){u3gyf zO!rQHoy*o#(_Cs{Q@N?aG|e>KG{ZF0G|M#Gbbx7&(DoMEBB9j@tzKviLTeOSlhB%l z)*`gUmz(BEx0~jhs!R(^)ux4}8veFeXiKO^wN{}m6sC{j z&c)RF`rH-UZO^!`bkWkq%?->r*Vkp{*(-JZ+J2q=#FD)sS)HA)ShFH?-70sP?+}b5 z!eh-%P4#t+@#cnxn!2X!wXEEd-WIa6G^A>ps+Xk0<`Q5n&q~bQgq@pV=d(ayr*XyW zxdxA`7iywSTrRMnxv3@>=a8MgmrldfnuD5awqHZOb4i&~zQ=QIxvG}-_r7k=ZNB>2 zZUWyykDi^TELqpIv}uhRKN@Y!#F%rWCKJn>FS%rUX#GSQm5w$cZzYVT+^D&vs~OqnvTlEo&L6FI#$}U-gKPMI$QkD z6`o#rM&UZDy0xYgO(${8s&)^d?IW~hEpPq5y8QKxK6Kp2S52IM^ERod@chCHOlP#b zDYScLGRWPd>rH0~ZQr);ujw2UpOH6oJGI+s?4c@fhytf5DBI9&o#`S@>MS6`{aW5= zS$sgdTXJ&B+hE$5Z29GNBD7JV zohr2Ds=P?&F>V*sR;(H;sut98*L7V}Lw#+ndJFn~|LNVSHMQw#rg6#A6&+vSxAWJd zT%5A9ot$(%QK=i*dFbs4O&4hOgJ0UWxrb$k^yVz}py?5{iFwHMu+X}N*3)Ww)byCp zdWF`fDr9?E-X7ETOlPVoYR(~I4nGrcUdexar1<=YW|2yHUGYI@D| zy6FuQP8}B7h|mrd+Wmxfe>Ee9>iXK|<#l5cjg^hu{xz;<4RvWr{=)?K6{hd0;aA1^ zzsls43&-bVo^xYK(~`^$;-(L%8oHfE>1gq1iqa?Q0~Vx&a}T~yD-YWIVJ%z_wMXUZ zh1J|KIi{|$rjDu_^GYUN$kP%|_W%eT^&R?~N^_03`b&F{?kbWbT%4YO}_y72254#+hB}_J~xZ8e+S` z&AXX77k`tvr+IgCuZ+SILYoxYR94|;z1d(knoVZf=TSmCT4=`zE&Y>;yHerloSN-B z=-6DggO1I8x9d3b$^dE02J_zLf#!XLcAU_T7upG``irJk^l4ub=kfP;AJ1p=SGAAR z&{&g+#;r!$?0Xr(Z5^prmH&+QQ{kXZRt_`Wleex@!HFJ2x+Jl8ltGOsRqv1vBdyCCWgtk&> z=c8P&yUmMzUT;>TIYllvucq^8t~1x0SC|hnH<%mEP3C6vO7kkAT_Cj8Lc36CYlL=@ z(9$;~(xpOspwKS6+`LA*-F%4oQ1fBt!_7ySTlm|NLR+hL6qgI_3ZXqnXo+LB(5_LR z9jxl~|8^eLTf8cD{~zo;nol*Kme&I@uQQ)b=h1wonO;zx(ANL+&ZGH4^F^7sGakO4 zqGE0p+J<(WNAo80=EAep&SR6%Hnu$1^45;sGxL>d_pCV+#np7r%-0C*%C_#A`FgWD zAyc@qa8u#tmX}*zX?b-+;iZL_6<*%*TFdKd&n#DD?l9k(pVNEH_vSyi-^^hi?RsP8 zhs_*vzux?a&>phhOn=}|wKV)Uy)pAsW|q%wG(T;A#=On^tk51Nw1*4r5klLt(fqvm z1@nvMmxNXbEy~{{w3}6V|G(>vncp#PItsrhTQJ^IZ2x%mt8m*%g8_E@215OloIo*=YqH<`aNe{25E{Jr@Hp*>M(PZHWw zg!VL{Jwr|GuIh2kYU_!0?0cF2*rA!S6!O5rM9#@A{_9o&htY1qR_r9w66;7 z>q7gc&{E63E41$m?T149vCw`hw4V#@mqPos&{FKb7up|%_Gh8}RcL<~+CPO{AmnaB z)(Tk>at|T*6ml;i7YSJ}WTTMHLM|4vRmgTBJA_;&%bS+BEN@%hvAk<}&+@+I1Ive&k1QWsKCygi`ONaU3As|p^Mza`m7V<(N*9du$kQWPi ziIA5H`9L8r6LPJPmkYU0$n`>AA>@OE+#uveAvX!RS;#Aeyh_Ncg}g?{2MhTSAs;H_ z!-RaekdF{@i;#toj}-DzLOxo^#|Ta`mXD**cN@l(!+r(7blbn!lASZZsZuv-wTpWa zo0eA9x)_{puVzeM*EDpb<5fw3`rzo@nk6Bb@~0Ngv%fF_*~(*C+_kl zW8S#W6No3h{`O+*SuwYCO^nYS2*v$@q$}$8CtdzTD(nioy&ji8oJuCVLBBiZkGB`o zCoAT*u8E0}lThg#DAy>rhO}YH;l+Tk0hJCR_s=b(fvSRM)nwUV$>xn0$0hiw!=SR$!a7D0) zD-;hzeGy+W>`o@yiy4v?b5GaAgkq6|KOBgnG%vXc$K$SOJmztQBA!Sj74;;N!BBfK z{;Zg-T@!;@{K-%(;EE*!L6qhRxnjY1#1)ArypdRdG@vNAKyCx{Gnz(tl+FLQ@n;i#KxAc#eRo{(Ck+UI0KR>b3fUqm1j z2*&~ew3GBlT>fO#gR)XyS1c8eQz7^$O?j2f)U1dnyQZvY!sm&H<6+`WQlSMs2?WMc zE>AS>@dYEnR5b2xpOYC`F;90*OgQF?1U)GarNm2>8Be5K(O4+pO2*uta4;SVdZKyd zWlmPiwyuexf=PxW(U8j%@KCkH!XZ~Q;O0;MR4ANulY~TG>95L)d9G_>5!-#~ zq+5YF`HJ9ku9QCzNu@jyzb6rEue3#3F)wsYjK>>}#8VNU%NJ4ekaW`&cq0)Pmhz|k zzLYN-$+J!NhI{QxT@#ZEMH85Z+_)n#m*0~LqO@4T<%_4{G&JsDA|7p@o9zAd+E=tXi@SV*fG_AyL_&#ho(p8}rq{mKH8BZ%HteQ8j;Dy+?+((i z`DhA!-gq(@@&;1LR9BCWYpc z0qQauM?ZFnxn1FaFXBr0{lQ4c7k39kd1A76!fW5_ni#h~5%u^2DOW(Pi~SLl77hh` zuB6u!iBhu#V!pgKCVTO__Jgj83HainP>|#Y;t6aMiqOV{LlmK4#78E*$#61HO!i)P z?MGb`6HU0o-nc(Z(M*K#vM|+Vm?|gci3I$?xG$MXB-`62dv&|^lP-$!MMEjK+fR#0 zaq$PKXu_$8+vSZWqQM}2nP4n0H`#mHwV!oOOx&BK6NWJ&ZlBsWOVFI9A}LqcPa8xN z=O=^hbCbPsUHiq~FEdH<;ZMc9{+i|O%4U9q^E&RNP6h$bRoU(}b^Vs6Pg^H*KV zNz~`%KiV&^J3(hQNK+8@C#iF&pQ&f!VQ(xiCs$_0eA6{CUSHft>zs5^)-k^?7I#IW zs+pqEXwXaJ9|-4FGS_9reAhKGiDcXpj7L+hVBD{^n$(+NH{BU*6{9taC8DXk5x`AZ zF+X%oOe{fPIfXM5A;XJM94|}I)kIfeuP2^}d4hRLyFDxBr>=>K#-f2his6Mf9zkiz zIK50yJm^YzX-=boh|lBB>&)Jh74u8i#Q43TVAO-n8E#OYsa=h5GO0Gsbfu$7Z!i+i ztDPUniutW;VtfgPVK|#Bi^{XuWopUA77pUQ}lr7ns|`9rawT5clr0R3(^xuLu43Z;CB zm^&7BCla3aHNbOOF@;?d!;mF}(^8eCdz_aiN&G`zc1l-d);}qc{wXa(={=4 zzalC6doG_pMIRs-O3{Xf8Pd{mi-agg!B}2br+QK{y4RD)E`TF@^bS{R!r}%i3tV6!BoPZa#2mHeKb#mk#jWWa)&(F zC=&Gs6L~G?k6AICKGKywS}dLj#G{lOCu8oHz)E5`Kq8|WC5OGj2e-elC*eoRx+ zGb^T~Yhr@*&SHLbD$C1!gFh6GFy8cFes$gs+a%)g_LEvAoaZ763WaRznwUt~!!(B1 zr}oM5vN-cj(J1~F574N25`hTCsGa#sSaOgSQ`$8#A$KgsWE?IWQ>%dp{ucF7+r&bV zxIdPnI!m_qvJzWXjI(QENOX{)WyqDHbE9^iVlD>LblKwGP(0*kRxs7R%#@U6#q{Z# zn0SO~#S~S)C!luG{b~)6NKkEh{Ry`>5O({+?HhrTepxYlc1;WgGZG`ku3*wbrPKr)%4!%o+#y_iv1G48I3@dlC}AJe`R6iSOf5%$pqU}k_>Rd*^F zWg^<2SJ{luit%<$Ou+3zt zu;YxWB8h0ymp8O6IUp-0+%+))Dw53VX`?Mrw2fLL%E4DSZA)o9S(>1l;iPbKXaEflyDY9yH!vnD@#`8KRCGL zko*USmmHD*;K-8fwt-xv$CezIA7X9EiTMvsDLFO&!5Jm%@*kXC@~`{{=apQ*@~o2c zg*<+})L-3iR;kl9HZNYx_Kli_+07EU6s#}VutVV7Z?=@=ugWjEq9lJ+e#tc@*XB#U zq2%BB4{k2GCI7+gC3oaMxVz+@{0H}y+@Js8p%NCM=Vd3C!Y4|e%n$lZ$+r9l&zHQA z|KQ~kmWj8w;_D@Eh}OFsRJ1btcZResQKOTNp0@MFnO`44_A z`7Qs!pH?aFfwh}elm9@mcF%v%)4F^9gCeUg|AEnJ%70L7Ey;gix3d1IUAC=d);{?U z`da(tKNw)$JO9DH)#-02aQ@|`45uTRQ`i8*0K2y zCRiutKbT^jn*U&$b$b4TS=QP459V6uktvNq&D zXtu7*f3U`SaQ=hCtcT}65Y{8}9~@&nHvhp1*0uQ$PPU$s|KN1%8Tk*+vQn9>x1KHJ z6V_YL5%P(7%Ob4VS!8)_rEb`2*J}0LIv3lc7P)HbY8n==aV@QHWKl#z%?fr=jHs<@ zuB%>BUenmfCXlH$i-uP%s1EsSykU2?09!AyuFn_0(Mp}O!Me%1*}6r@Cky#hA)mg% zdYScd>lH#?CuE-9ke{S$vsM2omAdL(y1S8G9E)q3hC~}1YnmF_$XJ#BL%aTs^~S8| z(<*gycd6)|3B4^V^o&Z~oc~7XWK6WEzIJK-*!t#%x~kd^GBbN%t#?`ytvh zK*$#g`63}-EaXdsyk5wgguGd8l!`Og_|z;M(^Rv3%tBVwEM2se%@qeUlBDVy^(mWe zbPH>ms+QJn-&n-foD~fXS--^ z{bKbzMD>;JY3e(&_8v+7C+FI4Ti?ld?f0!8swL|KA-Ar#ek9}#ss@T`R#q3Sxw!$mx0f3W`974z97TY;_6`lwA~)7oU4BIHYje7TUXOq=g2Azv-z>x6uL_QV<6 zZql3UZ9Rp2S5#uCE(hwPM9m{!h_KYtdGuhSLf8ioXo^pER7!q0MZw zm%fA(dCrE^D?fW?nzb6o{MfTTmSs%2HLzR%(jp9 zZrdQ6%Qo0H#OAhng#7Qczuze2n}mF`kZ%$4twO%-Qk&1_w*^pG$QHImY(s^7yO8e` z^4)2L-6Q0Cg?zt|AK00{|8MxXEumT@Ddao;(jpnljZwp~qVKN14EJ{}H_0|RU)ANd zX;{w2n!v5=ZPSH(-(MC9+w69>{0mD~+UDm+Uu~;Vqh|@>L+foUA$%mS;jm@bM98cm z3gxwB%WIa`H>}xNJ62QUuCDR8bM2U|&c=m@?K)4k2HR@Z4ci)RO}1v+N*jw29~1Hu zLVilf&j|V1O|~_*gKdY{4z;l;@p&P?CggX8{E3ji&QIcz*}DGmO5MEwrmpX>FF)J1 zjj3ByKX`>&Iks!oY{zA#K3S=&|8JyrXkn(-WXfRUkWuyZi)(Aj)mpT=#?^T;PRb_Z z=}O(q|0Wq7GS4{#on`y> zEKiP4#w*55npin5Ig0~kIs}+LrhH6nd~zzGGC?}Vk(@a>I$TaS!U_@_2lQ z4eE0Uvv83?efXAn*kPHfXbTJ6ZL~+PX1C7Tu8_8{g&VP zustZ`_k{eukUvm!@`&wGH76em`QyKplmDpk|7f+0=ATy6OU?CBF1^pC(@Re*FPrTw zmNUvrw%63Gyli{L_NtIS74m07{#?z<8@4yqtb8Hlul`4~^1hlCdSPGYvhwjxvch++ z!w$=3<#QVwo;KLNuzhL!O32>``CB1>x54&}?OWS-LjGRJKMMKh|Ixhs!oEM-uR`Vo zA&!3<6-{stP}LeLp$Rorjm-_|DrO98*E2@^lbqWnA^()kxxHI9=lQ-GjQF#@n$5Uf zvG2xK8SQ@d9-@Hm`>(C`p7z~^{JT(?TWVK>+4b2Pj0F=j{+k-CLzT_&i=pNU>fKzL zOm;4s-e@=5E%su2iID#g@}EMHgi^54ZnN9%rFMr<3Wd^5C>o*kR?Xs?sYc?<*4~-p zAkrtD*EcujJ&ZF%VBj%mC*doq8WogCHDzmwQ2Gtb&b&S~tKhq30RwF}E@ znwl8hWKTND9Ubp$|3ccv68paPL3WpY@T|62@-G!nE zMHWi0O5ODT#$-D-I@>MA&efCp`(JQx&6&Y ziQ5x-y+8XX`y^@57W-)X82ecJIQw|}1p7px=!Bvdia{twp_qhX7K&wyeX@OueX70O zUSXeRpDvVQp_B;4DioVg>_RCO%3lA(a|h&QI-}97ZyX(Zp>`Q^ zp}SZj`u%m}|0&j8QE-a$#BZ0Fvs;xteGm`1>+EL=#UqpvLYW|x*+MxmzwtOX(|9O+mtK_{k8x*&I_DiD?4-MHrN>4TC$}C#=kJIC?3RdUo=hAF?_#*yK%vJ4Mb6;J`?YqCmii|bqucMu93^SLCv)Vp{eBLTRJ_@PBo%+| z$Y*7E+aZ$nht=BW5uy09$B5b==MYJ55K8~c@u8W2b4NbgpS8chF&6gc?9U4&Ae3OM z{YCprLZSH`y30MOO6Ek!ZT3$I`&q}Z*L^$QclBP0Z6|3A6VIu6y4~G8_Al+~?M1S|{x!## z3S}5)D%!te%%SYp;V4jj;lNz=_Om^G9Z|r}bwpnZW&fSLm3^hOu(THj{|9$|mG;gU zywuS93EeuWU#Uek_{f~WW9n_Jn*BI7R2kQ1@lvK|*O$^ch-NKb>fD*dOZO_>8!eRf zFQrnB3nkH7Ic)#-*atL`U0y(L5mb=Of91w_RMn z?Z`_L90&I4w$f3A9o;ePapQWd9_|@8@SHp9kN$e@St|&eOUAg;iK?FjN;!HIi;u_R zrQA=aCjT#vj4iDw$jMb%Ugfc}aQ(H?9DLqsuorxNzGj$zl$Z~3`q*+ko2E~Vbu>vr`@n4Im_m8!?` zl%AugjYI#@kYw44vPYGp#P-=Fa-JdIcNv+#=xbD03<RA)VZ9OXfcwb>`Sd_N=JA{3=W7t*e=Jj}K==k5ay!4)LM7P2>+u8kt(vQ`= zeyG}=II#OCYK617vkK?Ay*veyM8uPt=mW_%BQP&kj~!{1ekVv>DSo zdh~w6(NpT@=%t!|StVb=Ct9O$AT;j(&rZBnWnBbV`nBsZojuy%>dE*$z>}*f;5YEKP4II*IB&t_5@9d*e+v14ry;?_Q zHm<|E7+3WopD+D^s$ED>Idh7xbu7=DI&rLU z9F+f{$;1 zJsIHORR4{Rb&fL~XF1Lm3Pa&jg>sruPS2I+bNRjAL3I49-sz#nss5My{Uz%ACuTyZ zzsUv3{eDaO_n8pcm(xLVzvm=4-dF$CGyj>5oLJfphI8ELV05y{ag*a_$1RRq9k&T( zolwpa%D;qiu29b3gIEsq^O4%E}1T znM!*6agR6YVxtX?xecw zfYsBHu-ETOu>XJ+#|ie+w_gkH$nJ1c&gl>nE6Ck}7&{76sU%yAeBJde8=^Z?HHyKumrPE{FtU#KS^W&g5t}E_G!0sVNt9 zh{@-UC;Xmx%*7IMmeP9J>BL?)uPeb${s0Tmq5C`eW8Iyj#+@e zJ_kJa*1L}P+um|~Ae2k8D({Z40A9ltnO9GT6w<9DHK%x1tTkpX9cP&Rdzfv23LE|bP{gtGbB!lZLI zj<0>t*|TsoOK$kyn9GX#HCHHGTJG59>@5{Ji=4U{6UzsyrzgkuU@G>~bpD(Mr*ZDY z@(ImNRUGQ9zOsQwCh7F)6U)`VWwq_JI9XDeO{|kC+{<%`EmadsX}qGd#6IWjmrLw< zLb-B#V*3}47Rpt*qz!cHVtdgHU7C|N$T=8kPM1)wS??SolxuhH66xB>=~GkU7s_>= zrQ~Jjuv|(m5X$x0lsJbw_b(i+>n4;Na%qV=b@2j;Pc3bUNjPa@*E<tA zES`%$Ok@hKoRjA3I9*-0*x>~Ddb<@-QcWsE_c#<+bWd%g_2$gimXa^R!uHsxj?eLV2uGH#EQ=p-_l(q@r&2L$XVNO#__k#E}T>Qi&%LA#W;C zxpc*n`nsCNrOTT+Z=KU?s~VOEIhmW4cFr@L>(bRjwxnk~cLR^lluqZ!@yy>j9X~Cd z<`S8EtH)`FnbCFee?KRsaOhJq#-@&BR#1IoPD182%J}xzyy|NnFZ&KTH6X|_0Uch; zDft3tD~-1ELgz)!i=CG^*9(P#9aeZoDBFbc>?Y?1=SJry=Vs>?p*$xPCih+t%8NpI zNmcxRp_sND{^z7t>IP<%@t=coMRhjpe^wk}|Gtvb&U;PTPmjOe_4(G7ZO(groAXZf zwLQEs{qVT=j89Lb#>=|-Et%KP3->cppJgB3o_=^@!!vtcd?62WX1UABWkZ)a?{?nf zyw|zad7txs=L60MofLvsgz~CTUK7geLU}_dZwlotp}Z}WcP^9qJ0F$$IUjXC;e68h zl=EqIhlWtzRR@Ca3gtbaye|~m>JJ$dE}p%#FVoTpZruVDHSOldBeb0)s+1wZG$JDeXq*yUzEV?>o`e z$3meq^Qlli+vxnr`LXj8Cx8B2C|?NWOQEEfm#E#3^lb@T7cw=yJiS6)gT(@t4!@Yr zk}tlEclN7EE7Y4{$e6psTk7%rwKeLm%bS-kuWDG6sV>TE7N^&FO-p~ipXTAPIj`=M zOxyQ82bns5aQ^80Nhn_nLU41~Of#+jr*yV|-gHui=V;bhW4(xbx5%8R-SceMhFp zKaw=1Pu4(XyOs6sB=LGjnXXKq9@3CwR?1XMefBDp`lLHwWoD;tl3vquL3%l&+x=WY zVKkO%KJKBz_Uk)5I%e#+@e|5t%$!p>tzTVpZSAwYdKc;RhPFz6 zdcSIQ3CNs@YY3Vkryt%r%riK;U&zdd0i>-FGWnIR75nN9(IGdpLB`uou zwia!Rk(M<@r{e`@S)V=j?A^EDUi}B`&9m~Q2iG8LQL46Tu_}b_MY@k&-#{#Ub)vCv zT0%Ir|I~M6|BQO|$Lm^@?k#dlF(q#>YkXKgxrPm0%cqS|WyI=h7e3p2-$Aay^xlgz za<|9Z=D4;Uf73357DG$H(VCX-YR)_X`v$&hwe)D&t)=G%KA*Pi&Xwop79$<@OcZJ+ z+Fqu0pI9ERP!p1>sZuMD+)9;pK}vE#rj41_$XR)9zuIQ$z5mGdBU*a5m{i%Zq`fts zp#Iafrbe~sTMVjHJF(|tuBDEuZ`i(JfDE_&Hhl$C+g1Xdq?5NzoHTjL?2JY0(CEy} zA8XQ@Uz)zsgW}pcc`7EEly)iJsF*gdt;-*6XsBAVpjGZy z+*I&#!FL5e7yMfAd%>TDa$%3co`t;%b%lmPQ=z5MUpTRFa^cj%8HEc9mlduqJf!gG z!V?P5DZGF~=x-{#z3|DxXA0jd{J8L|!fy+I>ej29F5}mQ3?L6{a?4ewhu7M zO3KQ((#`o>nXSz3{G-fK=1kX#zY66yszssvE|fnu?{;G0?6N(}`WDVEoGrQ;TIfyx zDY{E7_wz3m<(@mQ(NxFzkAWEP5oo~9V^RZ^H?2`ym;Vs5f-ZSFWV(l4HYn3c=^vl) z&FSUCymmQ*7(N=^K1kQPc+(i*7`Kb!dJ;oqU)>oY`}EKNu^DP`P8!h%>d*d5qN zDD4S@zym{J1WbYHFbC#Il5P>y!Ws~860C!B;5@hh*24za441-F@Bw@)NqP;)fK2^v zusiey46HYR3HE{kFc9_y7YqT?rT0MqLNEzPll~OA8D5qogAIZ}x(!pI37X+ZI1By- z=fe4LAzTck*Fbs=n_vsv26w<+a1U&S`{6-&1RjGY;c0jmevl+1c`-VGG#V3teB(km z7>H@6$X5yZDj{F&@0Lmqg~Oo*$Xf|{ zDoa2zY>atpOlE>}Hj$!(ccdhkc(CyD}v!X}6L_>!a{2yam|T z`Z@e4QI|sjbOY>RbHF};9c)pELlQ>87#IiW%{B?90Qs^lfdioykZZ$FYz;tpv8{yF zfbZJKqm4Y;@Cn=FfR60NKpb|$*wL|lE4(jBrKF=2S*65VihWD3fM?(bNpg@@$L`P@ zbYK7z@DAUlB*z}m7xsbyus=)%^zJ|>j&*P*oCVm|L3wg)f_vZzcpA3B^Y9|P4DZ07 zlH^2JPUJgpfqUT-_*#<6P-NK=a1s!28S$2(`!e!Wb|GvA@?Ca0TnYG38U9oD5WEWC zNm8F8C1a6J70zJ@=%%?)eQ6&z|V0|9F@M zb6_4+K{eC>HtN3u8YF1|`WfJd;V=TCfUE&Ymr-3_RK=`a(BW55!?HUseE0rhYY zVB-PUcmOuu+Xo{7pV=Eb?v2mvjnC|j&+I)LNY~z^Yw!8602aa_a4Mjuz3&6^y7#ky z9rk_+UV+!(M~VIi6oLkBg$Lm&z(-h7BMs!8f!J;!dK!qH2EGR$z(;`12C8xV1V6*C zlC)2E=n1_*2L>7HgS&wikUw}g*d3g(FAM?~41xUs`wYfDgAkjND<&8L&6XP>^KA; z7=jIlV8bEUaL9aE4h?_}ha3h+0CI<10-NAYz$Qc9fIlV4josXP!9L)Fk&uK@Fb2@8 z8@;;Gs~g{QlP7m8Tme_Y)o?SA5BCG`Fgyy6!#99UJ>9_pWq|!WeF2#s^5Yo@=-7jP zJ?Pit0d(pa4P#+EkOmKF@Q?-%diIcS&jCQ5J>=Pgem&R1-GFS*SCZsKrq>DB$;&(5 z)o=`)3#8jiy1l&P#b>>w+sk|27vLqpzrFZ{PX;rPHXnNNp=Td5eaQ4JfQ7IKmcV(i z0j`IC!%c7tU}GP;@!bXYz*fMnK4kdbf_DHv^nCzd!!MHLw*qPR4+nJMM+bg%;GYcj za3~xOEpQ~X!bZ3b@GJj~fKB|!^FIN|^FIU60&@Ky!pHC_d@e}=33@>h=)nm6Ap|Kv zZh*W8$a`QuECBKz_(PI{3g`fP2C-)ldj`Egq(R;fMu0ei6JQcdfpVA)#2F;cAaMqX zGq?zrK{JrQ;IVKjoC8|`y9IBD`{7;qOp-!90e=c1ClmwZgpd&8OG7_|kAXZ6{TzOQ-{22PB018qUO>Kwk?&#n z)v!LWC-j5<;DZ2=?_t<*SPCfn!?4M)@lXl1PzNiZ0m#=d(mw2LAnn6$g?r%%cnV18 zu;(Rdzj{~==wLtczuzVBC}5NQK7%je8$gHq{RF=P=^kDH8bGhZcY`w614#35Y&Lu! zaDf|0|L`D$fea6)%nn}&=yy128veB;?T-%jPr_kv4ZO)P3|)*s7bCFSh`j+H7(sj^ zh;Ib(jUc`e=wQS=SPV_j3@d>=jW`Cd=ZNC~n~pdG&VqB`Jh%d|>4@t9dycqCl15I3 zSwLAENg78I??`kyvJr@PB=L?U-jOH4sX&|~iF4!ya51b0%GAhBa2XK)$XkGXj(ifH zf~Nufk0g&H--5T{UHA&n#Ypr$@;gb2763YqDu9lo=qOqQ*gskh)D6)}Ag$3FppK0m z1n42U3JwPJ89f4S2mCIE9%IXZe8l)&tOc-p?07g4uu1GRxCg#~A0;VH8selOt^+$@ zlQ_1BhanE6Cq4$o!z7prb74MI!y;G;wNMAhi(drjCB7BVN&F>v72bfi;A6o5;$H$f ziQ|9qKO`xEP7JKwsDk+(4Q}EdXpc>PR>a zE`lv^DO?UW1Ns<+K1LyT)FbdXAa@kD8ilP!y$;A9^$s9=)c2A!S_0&bM%L)T-~m5` zU?{{P38Mg=j2;Kra5QNdeLP$NL+i3DOn)pXkc1Gj3qbbLue+0_jn4ZuJ z$nO|E7{Lt1fX|Gv13DNp4h{kGH|9l28e0h1Y3xG47sg%!8(=eB23Nw>uoWJIrvZN$ z`vQ>vv7~D(Wohh}@C}gnvA+R6GOhqLAcG0^0CX^JIHaH)u=}{VFdwSnKv)j-&;U(v zIAEJ`7XWD*N1Dc61J}cia5Ip$anHfa@EW`cZv(m-N1Dd{1i!)`k~Cfm-2vYnkIu#y z0XiDLCk%lgL|{J{0i<<2HX4ua#!m#w+4u#p3|7M$I2aCv6W}B`70!S&;cWOf+zSuF zBk(w2+wtgf{PTb<#(ybE6R_O`Cm??U@+TmFLJaVg38R5DOdt&tra%SE0CYG39Zo=p z6R_697Fn~I#NPr}piEW98|ak_RS||^fG#ScKprc|V+DDvAe|NHr2@TFke7-rfWD^{0Pjv) z0p|nxnugrzL1+ZRO@B?2X2@U!3s|8P%3u!|3~ulN@69+8PK7hzEI0>(LB3~_@0sL#Ci$L8zGsr}nRajja%c91{xA^s1s9Ot znM>hV!2UBI1LB=YyfeRpAK@1u{#nF7i}+_L&>! z0ePKGT{C+;OoFK}4Y2L(0|493t^#yA8y(Ij?%Av0U^o{ z(NF_*a1b=XO5nW%j)%2y5}X330eU{*V%P}S>wwGQ8n_;Agqz_xAn$WD&;xddA}~QQ zVADD1cFsP44d+B41^CUJ$xsf{f%;(1e5i&+umnzr``|smkLRG@xxGLK#5=bS>;;2i z7)*pIfO6+9hFYkH20%}9*8qB&dpH~o>)?I(2FSx)HU8iE#DV?hVZV9UWgfblR|@EF z9_3&ja^_JE=0za^_{F@jKz`=Ufl9ze^T@|M@-dHm%v%P_fwat94Tk_}nAZX)0D7Kx zCY%lDz1Tn1Oeb?|Sv74Cq$;a)&5l?Bin%uoX8y3z^grE+h;e=E^Xr5n(FCAzPi z1*EmI2GC9AF>pMb1<06~8%{lEoY2tXKyLL9~e>72h2NW*;6F#jsJ7H)u>0Da6y zAM?@2{H^c+JPf37{*&+w;Ggqfgjawx&L@rY--Qq0WB3fd1bkrr_wW<^3V%pa6}qj` z0BNtn52|_rzE^bs%meIPwGbA=fq;#xRzM@Hgf(y|905lHdagpxRVTtJa5`Z3s(-`;XdRNW5`!6Sezs$K%@QT2u-Ef@pSVJ48~ z1*CZa;TNEn1=wx@;TOCtN!9p7bvaA}!d4Tu`YCt~h^P8(cu$fRP6GU9A@M9E?+X_K zvKD>>pTOtvl_b@i0T;u1*a%xBX;BI61p{CoZ~=B$MEFJMei6D~^phklZU%I<_-Hr| z)=JV6{CkNV9MA{)0%=?FF?m*S60f0rc8Bppcn2c8P( z|3LJAAo^d{6G-DS8z5&Ha+YDIW#<64S#}{@B1yIQaIFgBUxnACvi0_d!%6wrCoMSw1w zHUK(lMo-QA0zT2~1|MvK>)|1I6rKR|(TqNt(MR*kfDbgk3GcxBfQ_4f2lB9zJgn>n zGW39+Kw4Ll)|CbzT`N5>8Jgg1xDC+bD)PRnFT|h{(B&$0xeA@FS^?-}6+W~IA608|!NZV>7n4upG z06z?a{UHho7zYz!3RJ*!I0A@&^)|pKR(}N8X*F`zV23s2cMb8a*$2??nvsA{tr-pf zPfPb5-DTOW3HS|!5b3=LN+=<8LJbz|*z1R)fW0e%s95MkKnN|=&`D?^(g~2zLI_n# zK%|3oVkjcLN}0=-<(-%=B(qr&U)zlKix2 zag`g$)>XD{vUQWKTR3uci=YZ_qg!=qQiu99pfOEp#v91lO%L7Nb+$&>@4hBJw0C{`VLarWi z^@!m?+;ESlkfF!(yvXs}d{p_k0PWbUQUUOAlP40899x0k%V{^gGU*$g|2y@xW$ z6)RV)j$`#2`v!0E318Blj(m^rAhrv>g;?KU>=p-&--;O6^$ z!2m`eYagBTNkbQXw&1-!$1rc7%Ur{peeMQ9-#qwc`+B!;Y042vEqn)kqp_pDey8t) zJj@Hcg&p;^qrTr^#=f1=SKpreOketAXMN@BJC*794*UMfZ03>5BGR$PzRTH*oWE3{ zIUk_AUuLn1Q$f&A=6*$S^ZjJ+SC$BBQiuAu`F`^ElfT~sJjAoS#H+N#EdAQ@F7MMF zdHcDsezNsj%o5yuKb`hl&02P_8@JWZZS*_Kc`l*fez$|b_(6Yr>z|K$c)!07p}&3g zAI(hsPJjFAzXtF1-^Vdd;6D3b~Z!N_cML?g?NTD3Yp_{6K8*Mb`d9g+&mVrkX5YX zH#YM-dWthwoSnv934#ITh@=*EiKYq7aAO0^F+lDCau2YV0Uz=SpVN+Sk$Hg317sc` z^8h&qj361=2H4vGyBhEZyU^!=T*K$!;0G_Vm((d|H) z2I_X8ZU^dipl%1ggMAK^Z{Wv#$`|N&Ux5i$>wd63M5WF92v zAbTHV&x2$eG?n?RVLdyr$3X`;#Bp*siEan!a&QDDSG+4KTbvszM zgLOODo(I2%e1qTMP1>N}!TKGn-@*1j_%mc3Z2yCGI@taPccC|f7{XA7Gm-@4ADqH0 z=CY79^g4JsW*Pi%5DW>YFvTcIIm|HRJ}Oa<20ViO4|x_hI^<=6q@j8vS_jnoOKj0(u8sC9$=!DGiJ?YN?WRD-hQ1lv~ z$TVg!6W@M(D&~q$XFu11U}z`>DME2dA^%YMhsr-x{-JJlXnox1&{vRks1ApIPFH#` z5WhWi1PP31BEFTO`W(7|Md)*=`y9HFEo^58yV31XT@Jk*1jFv35Jf3LX>>bGwqddj zlWmx6!*n}Lu3^5NVUP19_CCzshv|3NOUOJ-=3%eXiuZ7l!SKhBb@+?4<}1FY z8-9CuANnx}dmTOu-455~@ad#tkHeRd!D`mB0o@MQBN3`G>UZo{E9q|?)@Fiv$;Z{d<s)f2`T6{L6-^Zktso@1ep>}kc(~;WJ=I&f^HM8qTA6$u;1 zt&Hx%M3%9Et!!r}dys#${G;U`E&u3KTtuH^N+9c)`>D+%JkHDb?J=!r&AWVn9>;t_ zCw`<4_Bh5jGA5ppBrq1;j?v|qbhfaKKiI`ybUQ}2F|v)3ZH#PVbUQ|_v3Uq3jBpB~ z-?7Dzd92K1%Tk^yM55ENwP?h{m}RV69jn)|Pw_Nn8v7P)G1FM{jQx}^XvYv{v4l)k zvyR`8f2{mt*G9gNG1tmBH}CdbvMA&=s>$34UIyn?-sdmY`5)8)9&`5t>5 z=er-*i@x+@0JqBLwsE>0_g}6{T;UowxP^YlhamHK zna77yfRdC!r{gP7jk-jm)A3DtfQM*~*~Y(!dB&S({F}VZdwj^p#4?Qqq_LD0WU&@A zjMwe>J?L}18yNo&7r2bvj^JlrxQM)1K;rjo#}yI zC-g?Q6Wr;9$;dQ8rU^1l$i%)U*!KjPCTwOa+u6w}{zkqDx}9(l-A=g9zuXS|&!LeA zStk~z7Vb>qPk{#-Q7YPh*aWFQeCqt!Ry2Cz@?yER%4f6H{5t z5|$(TMA;|GK2i3G+3e;xSGf@clVqFZMkiGv68%l`+mjx|PA5G<3!dRQ-l8oZ^C>!= z^b=jt=_Gwl>Pvsz>ZGwGBhRFjWMR*fHn0hqCjHJ1WSg`PeNM9PNte*)Bs-sU6Mas) z8w80V=rb{laEeokvXsXxiM6SRP7`&SsMADqB|d;o6Lp%X(?p#n>NK%6I!)ARqD~Wa znyAx6ohIruQKyM!NL-Ch6Lp%X(?t0b%I?`kk!P$-bw_g(!kfCr4nG$+N#<8(BmZRiC(A!s{>g4*vYVLfyPBMftdlPV!4%)ml#-O8Dt>!P zZR*j8rZhvhQ*=4yMOtHzQ$E0*PWgg%bU?RLbU9@ZlbOa0W-LBHI+* zPLXTM9`Q}jDUzf;a|7X41u-&8rL>S5|PjAA*5xf2A_?nCBjPx3UfPkVva zd58D;h)H zywpKo)AcgFKeA3wVHS(X!h6%rKm7!!_#1Ohzsxmm;N9c`6y{zk;ck*6sfFK3u1^CV z<0U@i6F$d`$##^iujEeri2G0OPA}w29>X}?RPrPyV~5FZD_Q1bnUm)*k0t0lc_pjZ z$RC&`c{h96&!3nnSx3n_N;Xrnd6I8&Hwb3vX+||3=VjjDE!v{D8S>ANe}?=s7=rb-`IuUp5cyW93cmHKf~S6(CrLe&bSiGRvX^oQ@+D{v&=s$ zf$>bjoU@W~L$hY#-B~Nh#J*xYnHhMDS|%d)~j8Fm|^~Be1(4I>u0{dXY;$zot{j= zuI6uH2fMMS`SvvbIDcV3^WE3{f4CL|3qmQ2oC~TF&67Nh-(TRj7r2K7@A46!VowXc zq%+;n<$@s$VjJ$lu&V|0SiyF7vWNW~uAV+tGoJj9@+) ztYrh6$VUED`BUXjl|R+}r=H|W5G)Kw)`g|0Ok-kr3ctPZMPA``TG1NaF4X11_H@A> z7ye9N1~7S`~2o{B)-$h}_ zyh!Fng(*roDxlLv5!A%rnMF;|>7s{tgvWS^|M3PoU8K`R@1xU2pJ0wf(@7x#RYH!i)CBfh^9P>ZWq7DhkQ*Zenh8> zb-Fl~KK#NcrXbT|nHI~mcol0{k4%fVu#G?1#c9qW-{K2g;wm@zm)k**79eYyZqxLc z=3dieO)HH))7)rUE$R}D{Ao>y!HuN3ku-Cpy~69fNgLkA3~3Yi6}OqT5I>l<6xq{c zPm?`O_B1z>5ltMAB#-sGNsFuE>rpnGFgpXr@Pg3xzgQgx?4@R>-00|G+n3ZI!%`~{lBa? zajWTWb%|SDk{A15BJ+|5c$i0doabqYyi4AqE${FiAM!Pw_z}0TM2|~;rZ4@NhC5uM zuO<8Vlf#_gFHRxn5}B6R@lyAl8uq)?ewWrkw@dZ8^bO=%`T;sz8cQFB zF^S2@uyh79nS(BuW?-*N^|w@iOZB&O6Yg@U4woJef@OKA#N)h&oh=kjV-sk<>$G?RjvoY3bU+eMhl+jC0@m@R=i0Y-liRPwnDEfex@(|k$r{C zD@HMf@yNVF&J_z;k8CUa?O1V`i(KJa5M+dM4}~a-JIW|Sd32jmix^(y75;}@8M@8T zZH8_$beo~u4BckvHlru0vRB;y2bB*T4VoWpDxmxEwsaT@bDPxBmRSos<)X@wb9%DhtM zl|RyhSma*W4|!M0yK*F>alb3wz{+{7W*u8Oz&~8TUNZyo5l%shQG(Kxr8rA`O zwChZnGG)qaja_HH$A^5v=d?qonRcEjTV@;skug)oOc^s}%#<;60+UEWrnIdcKa z&}pVlGj*D|1$}02X9sRIGl!F$!L4TgH`7(F2f->gv8ov@(C4aGa1*QC#45R0$-PSM zRdTP=?W&G+XDB0(ZIw)`R-mX=et(tUUbT}w{K;YLcGYq0bCp|Nbtee2beUBS8M5xD zGS!H}oo2=GAP@5>Pw*7>pY<#DA><{DdvJT}3sZ~|=wbbRL{ODTWL~eE^$+k6 z&3P1atbdu7v_ePg-{k{7=2POZuk{OAMh14Z-mccmzh3_J@~@YF{Voo1hC4y9LDmfg zC`&Es@*sYDgPYjUg6FZT4R*ERHQuK^y4>(RKhd3@{ETilj39}{EMYk-$zmZ(``Vbu6s95f#uLc4(YLelU-Y<1rcL44 z^`;^erz8*40XMd34AaraCVgzu!=~+cZ&NO2-E;$UZn_%;n?uQu8`|vM&G&L2_O!V^ z4QaxI_?^v<@;I+z*3I^_*?u#m=^bVV*5I+EScS_`9~H5$=17U2d_TE$z_T zmhbohGi z3Q_1ayDoaoZcGdh@GNie6tT*zpIhDO)@$74ZV+s9 z``bdX+im*XR*p#YxUC7zcnDdxxzBA+@fxqwiq^=u&CPCmpAV6BTPJ?R-nYrRP1bF) zZqxC$kxXVT3s{6Z-L?#Ox@{wJZ`;Qqj&g!i=y97Kx4DIF^8a3l;*_E+6{$oOs?mT( zH01$ybDZn^%bg(Du7mA5*q)yP6vmBhw~y^*s7*bh@z!>4ZTHsphk2AI(98B`c#dwk z?d{pP*FVamvp;&X95d{YaYr5M;_V&Y-q9Ry?P$TXyu_=tkhr{SQ-R7Tk#%lY3G-;=Lb3?@6H|!WH{d2>Ajua+c|~lq%f1&EMXn% z*?@iR+|3^LvY%W|VrM(eyYo8#qVHY$-lgwdZf=*EcRi08cgeV`HE$#9E?IZAqXXa2 z37L1Lav=zI>u~pnxVPQ@wcS7B-gfuoXWZNFe&}F#4p)Of zV;;pW_O#$xUf^ZyW6vk_VjMG=&qC7B&7LgQqMJRs+4Bdx(9Is*?9svA{J7n{MJYik zDpQO4G^7bJ$g$Tg>}`Wy_L_OG412%C9`|%j`md~5`()U+i9P(uVUCf@Y0h$vTS2g2fBOqim|~Qq3_9FjjVNj%>;7o; zxnIWpy4&9kdG_~bAcILjU;8H@*ZvvIWDfJN*Zmo+Vh!uC%l)~W=L*+xAEY4|c&@2Y*Hv2L~{ip$umlW#K*w$s?Dw#p9`Uao$%ow@DNHd+V!k6S_>OM)=Z?s5WHjTLND}^g!jWVau!wY) zk%4_3Sfmp}(S|gpIr1HS62E)&IsS*9j=n`3de9F!j_Ts5E{^Kr z=wxQ%rjMqw7&(sm?W5V)>CwX+BL_Vl)zeWO9KDE+jupWC$IO4s{Kw=xR-S4^QH#1n z(}*TK&nM{SSbqlMPLB;`EE7mXzGE|)!+c~swjBA6t>ZWB^H?@=9&>xg?C*FU+}m-z z9WP1=N>K@Uj>~Y|jU9i1S7}Kr+VU` z(+T^`@z3W}rzYOXsZT@9o70Skc!bA!if4G9m(W9w9&+@M)0($=j}Nh{9N$<@J38QZ zb2{-OUFc3Pdh-i$3?iQ4=qg87Ipfh)&SZ3zGlQAfZ_a!clEzY2kcnOA*maIw=h$`5 zR<^Sf-$#xc%{j;sj`J6%_?vTF_U@Q|zWD3(sVHR^)z#@Db ze=Wl|`qwJfu%3-^}e5S$7jFJat6Tinno@1OGi zsgA5hXQ#Y>%KNA6^R!t`H^uv>y?j#|&wNJ~W;pXZJJ=lre^;XcX8GH1{rvy~8G~8=_FI1^;dcJEle1$lG4r!}8q zma~5AYzN%J*=)>m*8b1h|36VQ#{2(x|DT5$!g##@kN5wX%9S8EXXod+8I}&fCWYGhDEb z3;MdCuM75Z!3-Dd1I=bflYu>;1XAoSkhmNj$|GM|D zKglR`blv;cy?=csw}Rk?9o+E#4e#G5&PUk64e#IZ{*9m5gdN=Q{tfTnI2;5w8(;@F zy?@jDH=kxCX1F<(WPat}Ao$k|{}!My#rP02{QC`^_>qm6;orR+;7}0UipC7L9_0yI zFd8%5^8PLF-OY+upzJ{o5t^1T)H zAE7zeNvPREuW^&x+zmqVg;0c|6r%){h@di6iKYP!Y0Tq1!IPLb-~VXI>$Kt{KIRiX zqZ8lr18yf@U-~l;Gv_mJzTucRpLz35W-8{*XWo3NEFuf@=3B!${=mHXc4FRq$1!id z9L$^VGFQ0D^&liHA7R*M*gce?EcO|8FHzWOSWWCTtQqb&>_HypIiANohrL7_>^JOf z-lZLO9A?L1U*mqm>^RJh!+PO>8zhPz$GjrG!=3(YAGlwl?6=n`IbJ$w8 zW7e=e?B`DoafZJ+%Q z*up-{oBsd@IgOd~n>qhK{EM0Mn>qj8ASApHW)3%Vcrot7%;9DZuS`A69B$_DhCGUy z!_6H2B(GxTa5IO$&Igz^{4>6!JzrzL;XR1O%;EMFzK!46&JK={i_GEn6Mmj++(h1c z0`gFl;*_E+-5J0j;u+3G%vT_UQ1YYy0{SoD_Y3sHKT}{ZLm7eI3+TMS1m-ZGg`}bH z0xQTw_5!}C0vkArto~bANWlvD9tu9p%e>7e_}zk^^9|o({{=@fk(tb5HgmDlf-A{l zEqnAZVEk(@37E|yu$x*lZD=*Eno39G8J-< zg?^$d_EabqJr()|ofaC7+brZR3&~l?9Tr+f20AIU8+i)nC6s*Vys&(Q?Wpj*+(!hm z7OsukD%^m^G^GVH7H-MwwBjQ=@grTZ>%zV0jckSEu=m2cES$ttlKB;#7M@2ci;=nT zcJx@-Z4@btJVhGv7`iH=t0KB8@)~wl_zOV$X2{v zWG8#r&!7CmHEwb{2q_v+l#1NP{m4+XF3~hX7eyc7A)e)VUgA~UY|+t-!L1e@PYUj| zXd3Rc=nCX2>Q0Mh^E*4(%|7HRdI*0Pik{^>mx7RDIxqGCIxqGqUvL2TR_rwXy~X@{ zi@$&yD&B^7c%LnJySRUUac>tt8ibUv&l2`oqBU>x9v|Y}67A@KeoK7ENYdGhEG2GX zM*+(hAUurXc zzm$6^WiO@tUg^>_<8hwi8JerfL)cftFmsa>?qc9HV7$q5BC#AE$ULA$9Nw3%Dsv{%C%x1 zOIXJyviY4|*lRhrSnePvI1~84l2Zj)%D;ea%YTcVm6xM@0(vYzmSh&={qoCMNfxq} z-+^oLhhY`z2B>=3e_=J1v6E68NF9{jdyvE z_xTY2T!p^qzk;1tu!9Q2k+;Ga?7YG(=CXiAqz54ti*ql!tXKyt>BbCfvX*x1glA)3em1L+SLnRq1 zZDAXKunT!AoyATnUBow6=_-D^lHaa$CkTlM$V)!*Qw;YU;kP6Fc0^@rQHOd&qtgiY z9N{~Pc$(*U5xb0doi}MsH^!pFh&jw>A!*1TA%BGY5%Nd;#&!;I0a+t%2O*UUa32xW z#cx+`LNl6UpOv5BDSRW9Tk#Q}(~b^&$M^h%t}E-gasqCsvKy+rfJLOE+sd+4UWIIx zWvi^)%5qgc%5ieY#V#xBx3YdK>$mb1?6$IgtK>naRl+et6`fY8h&@(`pbFKfP9w}y zRR%JKi6k+V6wFXXw^iI`m6iBjt8B&otL(+!gDSFDk-5rA&hQU1 zSCO-780C?zY9#ut+Ja|!gEqXw`+S0XuKFck(UtzlR8^*`GF46HS7swq)l?RtyU|C{MBmVPO3%Igl6cq zT64@$tvdr4#z;mpj>$}81~ZYrn%vb^BWpEXR@m{!5%~(Q<3=M}(-vJu{>UKW8O|uiFrG=s7Aae#Y>~1>W+GSQTGsO$o3Z!E z?dUghH!?@=$IV9mg-#=N8mZIB+d)Y6fV_lp4+YU}b=_9K4>wv}r`63;U8mJ`THUQy z*K75+_@1AML;mXWSC_x~SSFCj6lAaNMyoF)o8Phb>M~WofxSlg{V2a3rPC-ojVg~$ zqwXhy`ZUD%9;MT$XLuf+M!kk!qx2f(Mx(x^9|IW7P)3k|Y*DgB$rdGB)O6&E%0RDC zS*$^?Q5)HUUZeCHrPnC85aoM{I?4&m5Ot30+~mJm?gSwa}JHhxwa- zxWMHgq*iU3@gU844BtR4GuJY6Ei>10Pqpl!mRqT%`&xgn6TR0mS1mVPD~F3*;=gyV z1|hZGbL~*_k)KlNzV^Mi>Dm$KzqWg--GIi#VAk4Zt^E~WRJ#k^v6I^J)pk#{ z-BImC%vXCBb6LP5(#YgDHnSD^Ywu(?`lx-9Gw7uD1upYn_Paqyop1_LgyNK<43(%s zZR*j0#x&(gUgkAk=S|F0=N&$$9Ub_FPME8XJ=W26o&F4D2>Pz0?>f4!<9_Pw4MOS` zMt5~9B12u>)%AYekNK1@&{^Hd%w;|cN#hJ|ukOG2ChEDtdiLXgpI}HmcUZ3;=BQ_m zdNDkRTddcDXL*5__>k}E$tWWWB4ZPxs7`6zn%>BWT&|UOs#xap3rXqi|+|ldVhI@$KiM-Lr`HPd-Z?wG8=efZx z?AiZQOGpEm8HQV{`Dp?JjRo}$Q!)H2YiWaO@6>P)8uE|XcM>D#BQ6UFpIh9y@||C z(piS=O@7DDo9MpD9`1PI8(nK}b_GHI1Yhui!gr+5w$3^-VPOdrkfGP5rY? z&*N5N^bw|G4jP+;4;^^8H6+oA(Z?SK=x)$_y`>}8^btepr2;?Y3BEu>8F|dY?j4ZHn0(0 zHS-NWtdED!a6JfVo{w+}QiS4^qAccXZocMr-Q2F5*QWvQxVaq7+hAwSe`N>$HZ;${ i`;X}9k^89>{NMiw&GY~MYo&(&@4x>4|1;!~%KrzvJTn~t diff --git a/PortfolioJournal.xcodeproj/xcshareddata/xcschemes/PortfolioJournal.xcscheme b/PortfolioJournal.xcodeproj/xcshareddata/xcschemes/PortfolioJournal.xcscheme index ae4f789..734e45b 100644 --- a/PortfolioJournal.xcodeproj/xcshareddata/xcschemes/PortfolioJournal.xcscheme +++ b/PortfolioJournal.xcodeproj/xcshareddata/xcschemes/PortfolioJournal.xcscheme @@ -50,6 +50,9 @@ ReferencedContainer = "container:PortfolioJournal.xcodeproj"> + + Bool { + let context = coreDataStack.viewContext + + let sourceRequest: NSFetchRequest = InvestmentSource.fetchRequest() + sourceRequest.fetchLimit = 1 + sourceRequest.resultType = .countResultType + if (try? context.count(for: sourceRequest)) ?? 0 > 0 { + return true + } + + let snapshotRequest: NSFetchRequest = Snapshot.fetchRequest() + snapshotRequest.fetchLimit = 1 + snapshotRequest.resultType = .countResultType + if (try? context.count(for: snapshotRequest)) ?? 0 > 0 { + return true + } + + let accountRequest: NSFetchRequest = Account.fetchRequest() + accountRequest.fetchLimit = 1 + accountRequest.resultType = .countResultType + return ((try? context.count(for: accountRequest)) ?? 0) > 0 } private var mainContent: some View { @@ -84,7 +145,7 @@ struct ContentView: View { } .tag(3) - SettingsView() + SettingsView(iapService: iapService) .tabItem { Label("Settings", systemImage: "gearshape.fill") } @@ -105,6 +166,7 @@ struct ContentView: View { #Preview { ContentView() + .environmentObject(CoreDataStack.shared) .environmentObject(IAPService()) .environmentObject(AdMobService()) .environmentObject(AccountStore(iapService: IAPService())) diff --git a/PortfolioJournal/App/PortfolioJournalApp.swift b/PortfolioJournal/App/PortfolioJournalApp.swift index eddd04b..68db5c6 100644 --- a/PortfolioJournal/App/PortfolioJournalApp.swift +++ b/PortfolioJournal/App/PortfolioJournalApp.swift @@ -22,6 +22,7 @@ struct PortfolioJournalApp: App { WindowGroup { ContentView() .environment(\.managedObjectContext, coreDataStack.viewContext) + .environmentObject(coreDataStack) .environmentObject(iapService) .environmentObject(adMobService) .environmentObject(accountStore) diff --git a/PortfolioJournal/Configuration.storekit b/PortfolioJournal/Configuration.storekit new file mode 100644 index 0000000..d6401a7 --- /dev/null +++ b/PortfolioJournal/Configuration.storekit @@ -0,0 +1,90 @@ +{ + "identifier" : "A1B2C3D4-E5F6-7890-ABCD-EF1234567890", + "nonRenewingSubscriptions" : [ + + ], + "products" : [ + { + "displayPrice" : "4.69", + "familyShareable" : true, + "internalID" : "premium_001", + "localizations" : [ + { + "description" : "Unlock all premium features forever", + "displayName" : "Portfolio Journal Premium", + "locale" : "en_US" + }, + { + "description" : "Desbloquea todas las funciones premium para siempre", + "displayName" : "Portfolio Journal Premium", + "locale" : "es_ES" + } + ], + "productID" : "com.portfoliojournal.premium", + "referenceName" : "Premium Lifetime", + "type" : "NonConsumable" + } + ], + "settings" : { + "_applicationInternalID" : "1234567890", + "_developerTeamID" : "XXXXXXXXXX", + "_failTransactionsEnabled" : false, + "_lastSynchronizedDate" : 758307388.12345, + "_locale" : "en_US", + "_storefront" : "USA", + "_storeKitErrors" : [ + { + "current" : null, + "enabled" : false, + "name" : "Load Products" + }, + { + "current" : null, + "enabled" : false, + "name" : "Purchase" + }, + { + "current" : null, + "enabled" : false, + "name" : "Verification" + }, + { + "current" : null, + "enabled" : false, + "name" : "App Store Sync" + }, + { + "current" : null, + "enabled" : false, + "name" : "Subscription Status" + }, + { + "current" : null, + "enabled" : false, + "name" : "App Transaction" + }, + { + "current" : null, + "enabled" : false, + "name" : "Manage Subscriptions Sheet" + }, + { + "current" : null, + "enabled" : false, + "name" : "Refund Request Sheet" + }, + { + "current" : null, + "enabled" : false, + "name" : "Offer Code Redeem Sheet" + } + ] + }, + "subscriptionGroups" : [ + + ], + "version" : { + "major" : 3, + "minor" : 0 + } +} diff --git a/PortfolioJournal/Models/CoreDataStack.swift b/PortfolioJournal/Models/CoreDataStack.swift index 010ca65..d77cd84 100644 --- a/PortfolioJournal/Models/CoreDataStack.swift +++ b/PortfolioJournal/Models/CoreDataStack.swift @@ -114,6 +114,8 @@ class CoreDataStack: ObservableObject { return appGroupURL } + @Published private(set) var isLoaded = false + lazy var persistentContainer: NSPersistentContainer = { let container: NSPersistentContainer if Self.cloudKitEnabled { @@ -139,13 +141,16 @@ class CoreDataStack: ObservableObject { container.persistentStoreDescriptions = [description] - container.loadPersistentStores { description, error in + container.loadPersistentStores { [weak self] description, error in if let error = error as NSError? { // In production, handle this error appropriately print("Core Data failed to load: \(error), \(error.userInfo)") } else { print("Core Data loaded successfully at: \(description.url?.path ?? "unknown")") } + DispatchQueue.main.async { + self?.isLoaded = true + } } // Merge policy - remote changes win diff --git a/PortfolioJournal/PortfolioJournal.entitlements b/PortfolioJournal/PortfolioJournal.entitlements index 72e48d1..a1a2b88 100644 --- a/PortfolioJournal/PortfolioJournal.entitlements +++ b/PortfolioJournal/PortfolioJournal.entitlements @@ -3,7 +3,7 @@ aps-environment - development + production com.apple.developer.icloud-container-identifiers iCloud.com.alexandrevazquez.portfoliojournal diff --git a/PortfolioJournal/Repositories/CategoryRepository.swift b/PortfolioJournal/Repositories/CategoryRepository.swift index 8af6679..a0554ef 100644 --- a/PortfolioJournal/Repositories/CategoryRepository.swift +++ b/PortfolioJournal/Repositories/CategoryRepository.swift @@ -39,10 +39,15 @@ class CategoryRepository: ObservableObject { ] do { - self.categories = try self.context.fetch(request) + let fetched = try self.context.fetch(request) + DispatchQueue.main.async { + self.categories = fetched + } } catch { print("Failed to fetch categories: \(error)") - self.categories = [] + DispatchQueue.main.async { + self.categories = [] + } } } } diff --git a/PortfolioJournal/Repositories/GoalRepository.swift b/PortfolioJournal/Repositories/GoalRepository.swift index 3493cb7..a6da414 100644 --- a/PortfolioJournal/Repositories/GoalRepository.swift +++ b/PortfolioJournal/Repositories/GoalRepository.swift @@ -40,10 +40,15 @@ class GoalRepository: ObservableObject { ] do { - self.goals = try self.context.fetch(request) + let fetched = try self.context.fetch(request) + DispatchQueue.main.async { + self.goals = fetched + } } catch { print("Failed to fetch goals: \(error)") - self.goals = [] + DispatchQueue.main.async { + self.goals = [] + } } } } diff --git a/PortfolioJournal/Repositories/InvestmentSourceRepository.swift b/PortfolioJournal/Repositories/InvestmentSourceRepository.swift index e79ea59..7a1eef1 100644 --- a/PortfolioJournal/Repositories/InvestmentSourceRepository.swift +++ b/PortfolioJournal/Repositories/InvestmentSourceRepository.swift @@ -41,10 +41,15 @@ class InvestmentSourceRepository: ObservableObject { ] do { - self.sources = try self.context.fetch(request) + let fetched = try self.context.fetch(request) + DispatchQueue.main.async { + self.sources = fetched + } } catch { print("Failed to fetch sources: \(error)") - self.sources = [] + DispatchQueue.main.async { + self.sources = [] + } } } } diff --git a/PortfolioJournal/Resources/GoogleService-Info.plist b/PortfolioJournal/Resources/GoogleService-Info.plist index 127b24a..45950bc 100644 --- a/PortfolioJournal/Resources/GoogleService-Info.plist +++ b/PortfolioJournal/Resources/GoogleService-Info.plist @@ -9,7 +9,7 @@ PLIST_VERSION 1 BUNDLE_ID - com.alexandrevazquez.portfoliojournal + com.alexandrevazquez.PortfolioJournal PROJECT_ID portfoliojournal-ef2d7 STORAGE_BUCKET @@ -25,6 +25,6 @@ IS_SIGNIN_ENABLED GOOGLE_APP_ID - 1:334225114072:ios:81bad412ffe1c6df3d28ad + 1:334225114072:ios:a0a50b5835ac042e3d28ad \ No newline at end of file diff --git a/PortfolioJournal/Resources/Info.plist b/PortfolioJournal/Resources/Info.plist index 74c86e0..7a0d636 100644 --- a/PortfolioJournal/Resources/Info.plist +++ b/PortfolioJournal/Resources/Info.plist @@ -35,6 +35,269 @@ ca-app-pub-1549720748100858~9632507420 GADDelayAppMeasurementInit + SKAdNetworkItems + + + SKAdNetworkIdentifier + cstr6suwn9.skadnetwork + + + SKAdNetworkIdentifier + 4fzdc2evr5.skadnetwork + + + SKAdNetworkIdentifier + 4pfyvq9l8r.skadnetwork + + + SKAdNetworkIdentifier + 2fnua5tdw4.skadnetwork + + + SKAdNetworkIdentifier + ydx93a7ass.skadnetwork + + + SKAdNetworkIdentifier + 5a6flpkh64.skadnetwork + + + SKAdNetworkIdentifier + p78axxw29g.skadnetwork + + + SKAdNetworkIdentifier + v72qych5uu.skadnetwork + + + SKAdNetworkIdentifier + ludvb6z3bs.skadnetwork + + + SKAdNetworkIdentifier + cp8zw746q7.skadnetwork + + + SKAdNetworkIdentifier + 3sh42y64q3.skadnetwork + + + SKAdNetworkIdentifier + c6k4g5qg8m.skadnetwork + + + SKAdNetworkIdentifier + s39g8k73mm.skadnetwork + + + SKAdNetworkIdentifier + 3qy4746246.skadnetwork + + + SKAdNetworkIdentifier + f38h382jlk.skadnetwork + + + SKAdNetworkIdentifier + hs6bdukanm.skadnetwork + + + SKAdNetworkIdentifier + v4nxqhlyqp.skadnetwork + + + SKAdNetworkIdentifier + wzmmz9fp6w.skadnetwork + + + SKAdNetworkIdentifier + yclnxrl5pm.skadnetwork + + + SKAdNetworkIdentifier + t38b2kh725.skadnetwork + + + SKAdNetworkIdentifier + 7ug5zh24hu.skadnetwork + + + SKAdNetworkIdentifier + gta9lk7p23.skadnetwork + + + SKAdNetworkIdentifier + vutu7akeur.skadnetwork + + + SKAdNetworkIdentifier + y5ghdn5j9k.skadnetwork + + + SKAdNetworkIdentifier + n6fk4nfna4.skadnetwork + + + SKAdNetworkIdentifier + v9wttpbfk9.skadnetwork + + + SKAdNetworkIdentifier + n38lu8286q.skadnetwork + + + SKAdNetworkIdentifier + 47vhws6wlr.skadnetwork + + + SKAdNetworkIdentifier + kbd757ber7.skadnetwork + + + SKAdNetworkIdentifier + 9t245vhmpl.skadnetwork + + + SKAdNetworkIdentifier + eh6m2bh4zr.skadnetwork + + + SKAdNetworkIdentifier + a2p9lx4jpn.skadnetwork + + + SKAdNetworkIdentifier + 22mmun2rn5.skadnetwork + + + SKAdNetworkIdentifier + 4468km3ulz.skadnetwork + + + SKAdNetworkIdentifier + 2u9pt9hc89.skadnetwork + + + SKAdNetworkIdentifier + 8s468mfl3y.skadnetwork + + + SKAdNetworkIdentifier + klf5c3l5u5.skadnetwork + + + SKAdNetworkIdentifier + ppxm28t8ap.skadnetwork + + + SKAdNetworkIdentifier + ecpz2srf59.skadnetwork + + + SKAdNetworkIdentifier + uw77j35x4d.skadnetwork + + + SKAdNetworkIdentifier + pwa73g5rt2.skadnetwork + + + SKAdNetworkIdentifier + mlmmfzh3r3.skadnetwork + + + SKAdNetworkIdentifier + 578prtvx9j.skadnetwork + + + SKAdNetworkIdentifier + 4dzt52r2t5.skadnetwork + + + SKAdNetworkIdentifier + e5fvkxwrpn.skadnetwork + + + SKAdNetworkIdentifier + 8c4e2ghe7u.skadnetwork + + + SKAdNetworkIdentifier + zq492l623r.skadnetwork + + + SKAdNetworkIdentifier + 3rd42ekr43.skadnetwork + + + SKAdNetworkIdentifier + 3qcr597p9d.skadnetwork + + + SKAdNetworkIdentifier + su67r6k2v3.skadnetwork + + + SKAdNetworkIdentifier + kbd757ywx3.skadnetwork + + + SKAdNetworkIdentifier + 44n7hlldy6.skadnetwork + + + SKAdNetworkIdentifier + k674qkevps.skadnetwork + + + SKAdNetworkIdentifier + 2rq3zucswp.skadnetwork + + + SKAdNetworkIdentifier + 5tjdwbrq8w.skadnetwork + + + SKAdNetworkIdentifier + 97r2b46745.skadnetwork + + + SKAdNetworkIdentifier + b9bk5wbcq9.skadnetwork + + + SKAdNetworkIdentifier + 44jx6755aq.skadnetwork + + + SKAdNetworkIdentifier + kbmxgpxpgc.skadnetwork + + + SKAdNetworkIdentifier + tl55sbb4fm.skadnetwork + + + SKAdNetworkIdentifier + 9g2aggbj52.skadnetwork + + + SKAdNetworkIdentifier + g2y4y55b64.skadnetwork + + + SKAdNetworkIdentifier + c3frkrj4fj.skadnetwork + + + SKAdNetworkIdentifier + r26jy69rpl.skadnetwork + + + SKAdNetworkIdentifier + 275upjj5gd.skadnetwork + + LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/PortfolioJournal/Resources/en.lproj/Localizable.strings b/PortfolioJournal/Resources/en.lproj/Localizable.strings index 31a85b6..8dbac06 100644 --- a/PortfolioJournal/Resources/en.lproj/Localizable.strings +++ b/PortfolioJournal/Resources/en.lproj/Localizable.strings @@ -20,6 +20,7 @@ "error" = "Error"; "success" = "Success"; "loading" = "Loading..."; +"loading_data" = "Loading your data..."; // MARK: - Tab Bar "tab_dashboard" = "Home"; diff --git a/PortfolioJournal/Resources/es-ES.lproj/Localizable.strings b/PortfolioJournal/Resources/es-ES.lproj/Localizable.strings index 5209cc2..f685faa 100644 --- a/PortfolioJournal/Resources/es-ES.lproj/Localizable.strings +++ b/PortfolioJournal/Resources/es-ES.lproj/Localizable.strings @@ -24,6 +24,8 @@ "Open Full Note" = "Ver nota completa"; "Duplicate Previous" = "Duplicar anterior"; "Save" = "Guardar"; +"loading" = "Cargando..."; +"loading_data" = "Cargando tus datos..."; // MARK: - Monthly Check-in "Monthly Check-in" = "Chequeo mensual"; diff --git a/PortfolioJournal/Services/ImportService.swift b/PortfolioJournal/Services/ImportService.swift index 28b458c..075e77d 100644 --- a/PortfolioJournal/Services/ImportService.swift +++ b/PortfolioJournal/Services/ImportService.swift @@ -73,7 +73,11 @@ class ImportService { ) return applyImport(parsed, context: CoreDataStack.shared.viewContext) case .json: - let parsed = parseJSON(content, allowMultipleAccounts: allowMultipleAccounts) + let parsed = parseJSON( + content, + allowMultipleAccounts: allowMultipleAccounts, + defaultAccountName: defaultAccountName + ) return applyImport(parsed, context: CoreDataStack.shared.viewContext) } } @@ -96,7 +100,11 @@ class ImportService { defaultAccountName: defaultAccountName ) case .json: - parsed = self.parseJSON(content, allowMultipleAccounts: allowMultipleAccounts) + parsed = self.parseJSON( + content, + allowMultipleAccounts: allowMultipleAccounts, + defaultAccountName: defaultAccountName + ) } let totalSnapshots = parsed.reduce(0) { total, account in @@ -189,7 +197,7 @@ Personal,Real Estate,Rental Property,2024-01-01,82000,80000,Estimated value let normalizedAccount = (providedAccount ?? "") .trimmingCharacters(in: .whitespacesAndNewlines) let rawAccountName = normalizedAccount.isEmpty ? fallbackAccount : normalizedAccount - let accountName = allowMultipleAccounts ? rawAccountName : "Personal" + let accountName = allowMultipleAccounts ? rawAccountName : fallbackAccount guard let categoryName = indexOfCategory.flatMap({ row.safeValue(at: $0) }), !categoryName.isEmpty, let sourceName = indexOfSource.flatMap({ row.safeValue(at: $0) }), !sourceName.isEmpty, @@ -237,7 +245,11 @@ Personal,Real Estate,Rental Property,2024-01-01,82000,80000,Estimated value } } - private func parseJSON(_ content: String, allowMultipleAccounts: Bool) -> [ImportedAccount] { + private func parseJSON( + _ content: String, + allowMultipleAccounts: Bool, + defaultAccountName: String? + ) -> [ImportedAccount] { guard let data = content.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return [] @@ -246,7 +258,8 @@ Personal,Real Estate,Rental Property,2024-01-01,82000,80000,Estimated value if let accountsArray = json["accounts"] as? [[String: Any]] { return accountsArray.compactMap { accountDict in let rawName = accountDict["name"] as? String ?? "Personal" - let name = allowMultipleAccounts ? rawName : "Personal" + let fallbackName = defaultAccountName ?? "Personal" + let name = allowMultipleAccounts ? rawName : fallbackName let currency = accountDict["currency"] as? String let inputMode = InputMode(rawValue: accountDict["inputMode"] as? String ?? "") ?? .simple @@ -341,9 +354,10 @@ Personal,Real Estate,Rental Property,2024-01-01,82000,80000,Estimated value ) } + let fallbackName = allowMultipleAccounts ? "Personal" : (defaultAccountName ?? "Personal") return [ ImportedAccount( - name: "Personal", + name: fallbackName, currency: json["currency"] as? String, inputMode: .simple, notificationFrequency: .monthly, diff --git a/PortfolioJournal/Utilities/Constants/AppConstants.swift b/PortfolioJournal/Utilities/Constants/AppConstants.swift index 14d6c05..7eb1478 100644 --- a/PortfolioJournal/Utilities/Constants/AppConstants.swift +++ b/PortfolioJournal/Utilities/Constants/AppConstants.swift @@ -16,7 +16,6 @@ enum AppConstants { // MARK: - StoreKit static let premiumProductID = "com.portfoliojournal.premium" - static let premiumPrice = "€4.69" // MARK: - AdMob diff --git a/PortfolioJournal/ViewModels/SourceDetailViewModel.swift b/PortfolioJournal/ViewModels/SourceDetailViewModel.swift index 3a9e6f8..61adac6 100644 --- a/PortfolioJournal/ViewModels/SourceDetailViewModel.swift +++ b/PortfolioJournal/ViewModels/SourceDetailViewModel.swift @@ -32,6 +32,7 @@ class SourceDetailViewModel: ObservableObject { private let calculationService: CalculationService private let predictionEngine: PredictionEngine private let freemiumValidator: FreemiumValidator + private let iapService: IAPService private var cancellables = Set() private var isRefreshing = false private var refreshQueued = false @@ -54,6 +55,7 @@ class SourceDetailViewModel: ObservableObject { self.calculationService = calculationService ?? .shared self.predictionEngine = predictionEngine ?? .shared self.freemiumValidator = FreemiumValidator(iapService: iapService) + self.iapService = iapService loadData() setupObservers() @@ -70,6 +72,14 @@ class SourceDetailViewModel: ObservableObject { self.refreshData() } .store(in: &cancellables) + + iapService.$isPremium + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + self?.refreshData() + } + .store(in: &cancellables) } // MARK: - Data Loading diff --git a/PortfolioJournal/Views/Accounts/AccountEditorView.swift b/PortfolioJournal/Views/Accounts/AccountEditorView.swift index 5c5de48..f7b1298 100644 --- a/PortfolioJournal/Views/Accounts/AccountEditorView.swift +++ b/PortfolioJournal/Views/Accounts/AccountEditorView.swift @@ -10,6 +10,7 @@ struct AccountEditorView: View { @State private var inputMode: InputMode = .simple @State private var notificationFrequency: NotificationFrequency = .monthly @State private var customFrequencyMonths = 1 + @State private var errorMessage: String? private let accountRepository = AccountRepository() @@ -25,6 +26,11 @@ struct AccountEditorView: View { } } header: { Text("Account") + } footer: { + if let errorMessage { + Text(errorMessage) + .foregroundColor(.negativeRed) + } } Section { @@ -39,25 +45,6 @@ struct AccountEditorView: View { Text(inputMode.description) } - Section { - Picker("Reminder Frequency", selection: $notificationFrequency) { - ForEach(NotificationFrequency.allCases) { frequency in - Text(frequency.displayName).tag(frequency) - } - } - - if notificationFrequency == .custom { - Stepper( - "Every \(customFrequencyMonths) month\(customFrequencyMonths > 1 ? "s" : "")", - value: $customFrequencyMonths, - in: 1...24 - ) - } - } header: { - Text("Account Reminders") - } footer: { - Text("Reminders apply to the whole account.") - } } .navigationTitle(account == nil ? "New Account" : "Edit Account") .navigationBarTitleDisplayMode(.inline) @@ -73,12 +60,35 @@ struct AccountEditorView: View { .onAppear { loadAccount() } + .onChange(of: name) { _, _ in + validateName() + } } .presentationDetents([.large]) } private var isValid: Bool { - !name.trimmingCharacters(in: .whitespaces).isEmpty + let trimmed = name.trimmingCharacters(in: .whitespaces) + return !trimmed.isEmpty && !isDuplicateName(trimmed) + } + + private func validateName() { + let trimmed = name.trimmingCharacters(in: .whitespaces) + if trimmed.isEmpty { + errorMessage = nil + return + } + errorMessage = isDuplicateName(trimmed) ? "An account with this name already exists." : nil + } + + private func isDuplicateName(_ trimmed: String) -> Bool { + let normalized = trimmed.lowercased() + return accountRepository.accounts.contains { existing in + if let account, existing.id == account.id { + return false + } + return (existing.name).trimmingCharacters(in: .whitespaces).lowercased() == normalized + } } private func loadAccount() { @@ -86,27 +96,33 @@ struct AccountEditorView: View { name = account.name currencyCode = account.currencyCode ?? currencyCode inputMode = InputMode(rawValue: account.inputMode) ?? .simple - notificationFrequency = account.frequency - customFrequencyMonths = Int(account.customFrequencyMonths) + notificationFrequency = .monthly + customFrequencyMonths = 1 + validateName() } private func saveAccount() { + validateName() + guard errorMessage == nil else { return } + let trimmedName = name.trimmingCharacters(in: .whitespaces) + let enforcedFrequency: NotificationFrequency = .monthly + let enforcedCustomMonths = 1 if let account { accountRepository.updateAccount( account, - name: name.trimmingCharacters(in: .whitespaces), + name: trimmedName, currency: currencyCode, inputMode: inputMode, - notificationFrequency: notificationFrequency, - customFrequencyMonths: customFrequencyMonths + notificationFrequency: enforcedFrequency, + customFrequencyMonths: enforcedCustomMonths ) } else { _ = accountRepository.createAccount( - name: name.trimmingCharacters(in: .whitespaces), + name: trimmedName, currency: currencyCode, inputMode: inputMode, - notificationFrequency: notificationFrequency, - customFrequencyMonths: customFrequencyMonths + notificationFrequency: enforcedFrequency, + customFrequencyMonths: enforcedCustomMonths ) } diff --git a/PortfolioJournal/Views/Accounts/AccountsView.swift b/PortfolioJournal/Views/Accounts/AccountsView.swift index ec0a3cc..3efbcb5 100644 --- a/PortfolioJournal/Views/Accounts/AccountsView.swift +++ b/PortfolioJournal/Views/Accounts/AccountsView.swift @@ -7,6 +7,7 @@ struct AccountsView: View { @State private var showingAddAccount = false @State private var selectedAccount: Account? @State private var showingPaywall = false + @State private var accountToDelete: Account? var body: some View { ZStack { @@ -33,6 +34,13 @@ struct AccountsView: View { } } } + .swipeActions(edge: .trailing) { + Button(role: .destructive) { + accountToDelete = account + } label: { + Label("Delete", systemImage: "trash") + } + } } } header: { Text("Accounts") @@ -43,6 +51,25 @@ struct AccountsView: View { .scrollContentBackground(.hidden) } .navigationTitle("Accounts") + .confirmationDialog( + "Delete Account", + isPresented: Binding( + get: { accountToDelete != nil }, + set: { if !$0 { accountToDelete = nil } } + ), + titleVisibility: .visible + ) { + Button("Delete", role: .destructive) { + guard let accountToDelete else { return } + if accountStore.selectedAccount?.id == accountToDelete.id { + accountStore.selectAllAccounts() + } + accountRepository.deleteAccount(accountToDelete) + self.accountToDelete = nil + } + } message: { + Text("This will remove the account and unlink its sources.") + } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button { diff --git a/PortfolioJournal/Views/Components/LoadingView.swift b/PortfolioJournal/Views/Components/LoadingView.swift index b1a7cfc..54a581a 100644 --- a/PortfolioJournal/Views/Components/LoadingView.swift +++ b/PortfolioJournal/Views/Components/LoadingView.swift @@ -17,6 +17,35 @@ struct LoadingView: View { } } +struct AppLaunchLoadingView: View { + var messageKey: LocalizedStringKey = "loading" + + var body: some View { + VStack(spacing: 20) { + Spacer() + + Image("BrandMark") + .resizable() + .scaledToFit() + .frame(width: 140, height: 140) + .padding(16) + .background(Color.appPrimary.opacity(0.08)) + .cornerRadius(28) + + ProgressView() + .scaleEffect(1.2) + + Text(messageKey) + .font(.subheadline) + .foregroundColor(.secondary) + + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(AppBackground()) + } +} + // MARK: - Skeleton Loading struct SkeletonView: View { diff --git a/PortfolioJournal/Views/Dashboard/DashboardView.swift b/PortfolioJournal/Views/Dashboard/DashboardView.swift index e6a25eb..92918cb 100644 --- a/PortfolioJournal/Views/Dashboard/DashboardView.swift +++ b/PortfolioJournal/Views/Dashboard/DashboardView.swift @@ -43,7 +43,7 @@ struct DashboardView: View { viewModel.refreshData() } .overlay { - if viewModel.isLoading { + if viewModel.isLoading && !viewModel.hasData { ProgressView() } } diff --git a/PortfolioJournal/Views/Onboarding/OnboardingView.swift b/PortfolioJournal/Views/Onboarding/OnboardingView.swift index efb8420..5535013 100644 --- a/PortfolioJournal/Views/Onboarding/OnboardingView.swift +++ b/PortfolioJournal/Views/Onboarding/OnboardingView.swift @@ -117,7 +117,7 @@ struct OnboardingView: View { selectedCurrency = AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency } .sheet(isPresented: $showingImportSheet) { - ImportDataView() + ImportDataView(importContext: .onboarding) } .sheet(isPresented: $showingAddSource) { AddSourceView() diff --git a/PortfolioJournal/Views/Premium/PaywallView.swift b/PortfolioJournal/Views/Premium/PaywallView.swift index c2d1e91..83bf699 100644 --- a/PortfolioJournal/Views/Premium/PaywallView.swift +++ b/PortfolioJournal/Views/Premium/PaywallView.swift @@ -120,15 +120,9 @@ struct PaywallView: View { private var priceCard: some View { VStack(spacing: 8) { - HStack(alignment: .top, spacing: 4) { - Text("€") - .font(.title2.weight(.semibold)) - .foregroundColor(.appPrimary) - - Text("4.69") - .font(.system(size: 48, weight: .bold, design: .rounded)) - .foregroundColor(.appPrimary) - } + Text(iapService.formattedPrice) + .font(.system(size: 48, weight: .bold, design: .rounded)) + .foregroundColor(.appPrimary) Text("One-time purchase") .font(.subheadline) @@ -283,6 +277,7 @@ struct FeatureRow: View { // MARK: - Compact Paywall (for inline use) struct CompactPaywallBanner: View { + @EnvironmentObject var iapService: IAPService @Binding var showingPaywall: Bool var body: some View { @@ -311,7 +306,7 @@ struct CompactPaywallBanner: View { Button { showingPaywall = true } label: { - Text("€4.69") + Text(iapService.formattedPrice) .font(.caption.weight(.semibold)) .padding(.horizontal, 12) .padding(.vertical, 6) diff --git a/PortfolioJournal/Views/Settings/ImportDataView.swift b/PortfolioJournal/Views/Settings/ImportDataView.swift index b9cd1da..e8b094f 100644 --- a/PortfolioJournal/Views/Settings/ImportDataView.swift +++ b/PortfolioJournal/Views/Settings/ImportDataView.swift @@ -3,6 +3,20 @@ import UniformTypeIdentifiers import UIKit struct ImportDataView: View { + enum ImportContext { + case settings + case onboarding + } + + enum AccountSelection: String, CaseIterable, Identifiable { + case existing + case new + + var id: String { rawValue } + } + + let importContext: ImportContext + @EnvironmentObject private var iapService: IAPService @EnvironmentObject private var accountStore: AccountStore @EnvironmentObject private var tabSelection: TabSelectionStore @@ -15,10 +29,24 @@ struct ImportDataView: View { @State private var isImporting = false @State private var importProgress: Double = 0 @State private var importStatus = "Preparing import" + @State private var accountSelection: AccountSelection = .existing + @State private var selectedAccountId: UUID? + @State private var newAccountName = "" + @State private var accountErrorMessage: String? + + private let accountRepository = AccountRepository() + + init(importContext: ImportContext = .settings) { + self.importContext = importContext + } var body: some View { NavigationStack { List { + if shouldShowAccountSelection { + accountSection + } + Section { Picker("Format", selection: $selectedFormat) { Text("CSV").tag(ImportService.ImportFormat.csv) @@ -65,7 +93,7 @@ struct ImportDataView: View { } header: { Text("Format Guide") } footer: { - Text(iapService.isPremium ? "Accounts are imported as provided." : "Free users import into the Personal account.") + Text(importFooterText) } Section { @@ -117,6 +145,18 @@ struct ImportDataView: View { } message: { Text(errorMessage ?? "") } + .onAppear { + if selectedAccountId == nil { + selectedAccountId = accountStore.selectedAccount?.id ?? accountStore.accounts.first?.id + } + } + .onChange(of: accountSelection) { _, _ in + accountErrorMessage = nil + } + .onChange(of: newAccountName) { _, _ in + guard accountSelection == .new else { return } + accountErrorMessage = validateNewAccountName() + } } .presentationDetents([.large]) } @@ -178,6 +218,78 @@ Personal,Stocks,Index Fund,2024-01-01,15000,12000,Long-term } } + private var shouldShowAccountSelection: Bool { + importContext == .onboarding + } + + private var importFooterText: String { + if importContext == .onboarding { + return iapService.isPremium + ? "Import will be added to the selected account." + : "Free users import into the existing account." + } + return iapService.isPremium + ? "Accounts are imported as provided." + : "Free users import into the selected account." + } + + private var accountSection: some View { + Section { + if iapService.isPremium { + Picker("Account", selection: $accountSelection) { + Text("Existing").tag(AccountSelection.existing) + Text("New").tag(AccountSelection.new) + } + .pickerStyle(.segmented) + .disabled(isImporting) + + if accountSelection == .existing { + Picker("Import into", selection: $selectedAccountId) { + ForEach(accountStore.accounts) { account in + Text(account.name).tag(Optional(account.id)) + } + } + .disabled(isImporting) + } else { + TextField("New account name", text: $newAccountName) + .disabled(isImporting) + } + } else { + HStack { + Text("Account") + Spacer() + Text(selectedAccountName ?? "Personal") + .foregroundColor(.secondary) + } + } + } header: { + Text("Account") + } footer: { + if let accountErrorMessage { + Text(accountErrorMessage) + .foregroundColor(.negativeRed) + } + } + } + + private var selectedAccountName: String? { + accountStore.accounts.first { $0.id == selectedAccountId }?.name + ?? accountStore.selectedAccount?.name + ?? accountStore.accounts.first?.name + } + + private func validateNewAccountName() -> String? { + let trimmed = newAccountName.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmed.isEmpty else { + return "Enter a name for the new account." + } + let normalized = trimmed.lowercased() + let exists = accountStore.accounts.contains { + $0.name.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == normalized + } + return exists ? "An account with this name already exists." : nil + } + private func handleImport(_ result: Result<[URL], Error>) { do { let urls = try result.get() @@ -243,9 +355,30 @@ Personal,Stocks,Index Fund,2024-01-01,15000,12000,Long-term } private func handleImportContent(_ content: String) { - let allowMultipleAccounts = iapService.isPremium - let defaultAccountName = accountStore.selectedAccount?.name + let shouldForceSingleAccount = importContext == .onboarding + let allowMultipleAccounts = iapService.isPremium && !shouldForceSingleAccount + var defaultAccountName = accountStore.selectedAccount?.name ?? accountStore.accounts.first?.name + + if shouldForceSingleAccount && iapService.isPremium { + if accountSelection == .new { + accountErrorMessage = validateNewAccountName() + guard accountErrorMessage == nil else { return } + let trimmed = newAccountName.trimmingCharacters(in: .whitespacesAndNewlines) + let currency = AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency + let account = accountRepository.createAccount( + name: trimmed, + currency: currency, + inputMode: .simple, + notificationFrequency: .monthly, + customFrequencyMonths: 1 + ) + defaultAccountName = account.name + } else { + defaultAccountName = selectedAccountName + } + } + isImporting = true importProgress = 0 importStatus = "Parsing file" diff --git a/PortfolioJournal/Views/Settings/SettingsView.swift b/PortfolioJournal/Views/Settings/SettingsView.swift index d82117b..48c5bf1 100644 --- a/PortfolioJournal/Views/Settings/SettingsView.swift +++ b/PortfolioJournal/Views/Settings/SettingsView.swift @@ -2,7 +2,7 @@ import SwiftUI import StoreKit struct SettingsView: View { - @EnvironmentObject var iapService: IAPService + private let iapService: IAPService @StateObject private var viewModel: SettingsViewModel @AppStorage("calmModeEnabled") private var calmModeEnabled = true @AppStorage("cloudSyncEnabled") private var cloudSyncEnabled = false @@ -19,8 +19,9 @@ struct SettingsView: View { @State private var showingRestartAlert = false @State private var didLoadCloudSync = false - init() { - _viewModel = StateObject(wrappedValue: SettingsViewModel(iapService: IAPService())) + init(iapService: IAPService) { + self.iapService = iapService + _viewModel = StateObject(wrappedValue: SettingsViewModel(iapService: iapService)) } var body: some View { @@ -221,7 +222,7 @@ struct SettingsView: View { .font(.headline) .foregroundColor(.primary) - Text("Unlock all features for €4.69") + Text("Unlock all features for \(iapService.formattedPrice)") .font(.caption) .foregroundColor(.secondary) } @@ -705,7 +706,6 @@ struct PinSetupView: View { } #Preview { - SettingsView() - .environmentObject(IAPService()) + SettingsView(iapService: IAPService()) .environmentObject(AccountStore(iapService: IAPService())) } diff --git a/PortfolioJournalWidget/InvestmentWidget.swift b/PortfolioJournalWidget/InvestmentWidget.swift index bfc38cc..1902daa 100644 --- a/PortfolioJournalWidget/InvestmentWidget.swift +++ b/PortfolioJournalWidget/InvestmentWidget.swift @@ -5,6 +5,8 @@ import CoreData private let appGroupIdentifier = "group.com.alexandrevazquez.portfoliojournal" private let storeFileName = "PortfolioJournal.sqlite" private let sharedPremiumKey = "premiumUnlocked" +private let widgetPrimaryColor = Color(hex: "#3B82F6") ?? .blue +private let widgetSecondaryColor = Color(hex: "#10B981") ?? .green private func sharedStoreURL() -> URL? { return FileManager.default @@ -53,9 +55,11 @@ struct InvestmentWidgetEntry: TimelineEntry { let dayChange: Decimal let dayChangePercentage: Double let topSources: [(name: String, value: Decimal, color: String)] - let sparklineData: [Decimal] + let trendPoints: [Decimal] + let trendLabels: [String] let categoryEvolution: [CategorySeries] let categoryTotals: [(name: String, value: Decimal, color: String)] + let goals: [GoalSummary] } struct CategorySeries: Identifiable { @@ -66,6 +70,13 @@ struct CategorySeries: Identifiable { let latestValue: Decimal } +struct GoalSummary: Identifiable { + let id = UUID() + let name: String + let targetAmount: Decimal + let targetDate: Date? +} + // MARK: - Widget Provider struct InvestmentWidgetProvider: TimelineProvider { @@ -81,7 +92,8 @@ struct InvestmentWidgetProvider: TimelineProvider { ("Bonds", 15000, "#3B82F6"), ("Real Estate", 5000, "#F59E0B") ], - sparklineData: [45000, 46000, 47000, 48000, 49000, 50000], + trendPoints: [45000, 46000, 47000, 48000, 49000, 50000], + trendLabels: ["Aug", "Sep", "Oct", "Nov", "Dec", "Jan"], categoryEvolution: [ CategorySeries( id: "stocks", @@ -109,6 +121,9 @@ struct InvestmentWidgetProvider: TimelineProvider { ("Stocks", 26000, "#10B981"), ("Bonds", 14500, "#3B82F6"), ("Real Estate", 6800, "#F59E0B") + ], + goals: [ + GoalSummary(name: "Target", targetAmount: 75000, targetDate: nil) ] ) } @@ -139,9 +154,11 @@ struct InvestmentWidgetProvider: TimelineProvider { dayChange: 0, dayChangePercentage: 0, topSources: [], - sparklineData: [], + trendPoints: [], + trendLabels: [], categoryEvolution: [], - categoryTotals: [] + categoryTotals: [], + goals: [] ) } @@ -166,15 +183,18 @@ struct InvestmentWidgetProvider: TimelineProvider { let snapshots = (try? context.fetch(snapshotRequest)) ?? [] var dailyTotals: [Date: Decimal] = [:] + var monthlyTotals: [Date: Decimal] = [:] var latestBySource: [NSManagedObjectID: (date: Date, value: Decimal, source: NSManagedObject)] = [:] - var categoryDailyTotals: [String: [Date: Decimal]] = [:] + var categoryMonthlyTotals: [String: [Date: Decimal]] = [:] var categoryMeta: [String: (name: String, color: String)] = [:] let calendar = Calendar.current for snapshot in snapshots { guard let rawDate = snapshot.value(forKey: "date") as? Date else { continue } let day = calendar.startOfDay(for: rawDate) + let month = calendar.date(from: calendar.dateComponents([.year, .month], from: rawDate)) ?? day let value = decimalValue(from: snapshot, key: "value") dailyTotals[day, default: .zero] += value + monthlyTotals[month, default: .zero] += value if let source = snapshot.value(forKey: "source") as? NSManagedObject { let sourceId = source.objectID @@ -198,9 +218,9 @@ struct InvestmentWidgetProvider: TimelineProvider { } categoryMeta[categoryId] = (categoryName, categoryColor) - var dayTotals = categoryDailyTotals[categoryId, default: [:]] - dayTotals[day, default: .zero] += value - categoryDailyTotals[categoryId] = dayTotals + var monthTotals = categoryMonthlyTotals[categoryId, default: [:]] + monthTotals[month, default: .zero] += value + categoryMonthlyTotals[categoryId] = monthTotals } } @@ -208,7 +228,27 @@ struct InvestmentWidgetProvider: TimelineProvider { .map { ($0.key, $0.value) } .sorted { $0.0 < $1.0 } - let sparklineData = Array(sortedTotals.suffix(7).map { $0.1 }) + let sortedMonths = monthlyTotals + .map { ($0.key, $0.value) } + .sorted { $0.0 < $1.0 } + let months: [Date] + let trendPoints: [Decimal] + let trendLabels: [String] + if sortedMonths.isEmpty { + months = [] + trendPoints = [] + trendLabels = [] + } else { + let latestMonth = sortedMonths.last?.0 ?? + (calendar.date(from: calendar.dateComponents([.year, .month], from: Date())) ?? Date()) + months = (0..<6).reversed().compactMap { offset in + calendar.date(byAdding: .month, value: -offset, to: latestMonth) + } + let monthFormatter = DateFormatter() + monthFormatter.dateFormat = "MMM" + trendPoints = months.map { monthlyTotals[$0] ?? .zero } + trendLabels = months.map { monthFormatter.string(from: $0) } + } let totalValue = latestBySource.values.reduce(Decimal.zero) { $0 + $1.value } @@ -247,10 +287,9 @@ struct InvestmentWidgetProvider: TimelineProvider { } .sorted { $0.value > $1.value } - let evolutionDays = Array(sortedTotals.suffix(7).map { $0.0 }) let categoryEvolution: [CategorySeries] = categoryTotalsData.prefix(4).map { category in - let dayMap = categoryDailyTotals[category.id] ?? [:] - let points = evolutionDays.map { dayMap[$0] ?? .zero } + let monthMap = categoryMonthlyTotals[category.id] ?? [:] + let points = months.map { monthMap[$0] ?? .zero } return CategorySeries( id: category.id, name: category.name, @@ -271,6 +310,29 @@ struct InvestmentWidgetProvider: TimelineProvider { } } + let goalsRequest = NSFetchRequest(entityName: "Goal") + goalsRequest.predicate = NSPredicate(format: "isActive == YES") + let goalObjects = (try? context.fetch(goalsRequest)) ?? [] + let goalSummaries = goalObjects.compactMap { goal -> GoalSummary? in + let amount = decimalValue(from: goal, key: "targetAmount") + guard amount > 0 else { return nil } + let name = (goal.value(forKey: "name") as? String)?.trimmingCharacters(in: .whitespacesAndNewlines) + let targetDate = goal.value(forKey: "targetDate") as? Date + return GoalSummary(name: (name?.isEmpty == false ? name! : "Goal"), targetAmount: amount, targetDate: targetDate) + } + let goals = goalSummaries.sorted { lhs, rhs in + switch (lhs.targetDate, rhs.targetDate) { + case let (lDate?, rDate?): + return lDate < rDate + case (_?, nil): + return true + case (nil, _?): + return false + default: + return lhs.targetAmount < rhs.targetAmount + } + } + return InvestmentWidgetEntry( date: Date(), isPremium: isPremium, @@ -278,9 +340,11 @@ struct InvestmentWidgetProvider: TimelineProvider { dayChange: dayChange, dayChangePercentage: dayChangePercentage, topSources: Array(topSources), - sparklineData: sparklineData, + trendPoints: trendPoints, + trendLabels: trendLabels, categoryEvolution: categoryEvolution, - categoryTotals: categoryTotalsData.map { (name: $0.name, value: $0.value, color: $0.color) } + categoryTotals: categoryTotalsData.map { (name: $0.name, value: $0.value, color: $0.color) }, + goals: goals ) } } @@ -357,9 +421,13 @@ struct MediumWidgetView: View { VStack(alignment: .trailing, spacing: 8) { if entry.isPremium { - if entry.sparklineData.count >= 2 { - SparklineView(data: entry.sparklineData, isPositive: entry.dayChange >= 0) - .frame(height: 48) + if entry.trendPoints.count >= 2 { + TrendLineChartView( + points: entry.trendPoints, + labels: entry.trendLabels, + goal: entry.goals.first + ) + .frame(height: 70) } else { VStack(alignment: .trailing, spacing: 4) { Text("Add snapshots") @@ -450,8 +518,12 @@ struct LargeWidgetView: View { if entry.isPremium { if hasCategoryTrend { - CategoryEvolutionView(series: entry.categoryEvolution) - .frame(height: 86) + CombinedCategoryChartView( + series: entry.categoryEvolution, + labels: entry.trendLabels, + goal: entry.goals.first + ) + .frame(height: 98) VStack(alignment: .leading, spacing: 8) { ForEach(entry.categoryTotals.prefix(4), id: \.name) { category in @@ -545,83 +617,202 @@ struct AccessoryRectangularView: View { } } -// MARK: - Sparkline +// MARK: - Trend Line Chart -struct SparklineView: View { - let data: [Decimal] - let isPositive: Bool +struct TrendLineChartView: View { + let points: [Decimal] + let labels: [String] + let goal: GoalSummary? - private var points: [CGFloat] { - let doubles = data.map { NSDecimalNumber(decimal: $0).doubleValue } - guard let minV = doubles.min(), let maxV = doubles.max(), minV != maxV else { - return doubles.map { _ in 0.5 } - } - return doubles.map { CGFloat(($0 - minV) / (maxV - minV)) } + private var values: [Double] { + points.map { NSDecimalNumber(decimal: $0).doubleValue } + } + + private var minValue: Double { + values.min() ?? 0 + } + + private var maxValue: Double { + values.max() ?? 0 + } + + private func normalized(_ value: Double) -> CGFloat { + let minV = minValue + let maxV = maxValue + if minV == maxV { return 0.5 } + return CGFloat((value - minV) / (maxV - minV)) } var body: some View { - GeometryReader { geo in - let width = geo.size.width - let height = geo.size.height - let step = data.count > 1 ? width / CGFloat(data.count - 1) : width + HStack(alignment: .center, spacing: 6) { + VStack(alignment: .leading, spacing: 2) { + Text(Decimal(maxValue).shortCurrencyString) + .font(.caption2) + .foregroundColor(.secondary) + Spacer() + Text(Decimal(minValue).shortCurrencyString) + .font(.caption2) + .foregroundColor(.secondary) + } - Path { path in - guard !points.isEmpty else { return } - for (index, value) in points.enumerated() { - let x = CGFloat(index) * step - let y = height - (CGFloat(value) * height) - if index == 0 { - path.move(to: CGPoint(x: x, y: y)) - } else { - path.addLine(to: CGPoint(x: x, y: y)) + VStack(spacing: 4) { + GeometryReader { geo in + let width = geo.size.width + let height = geo.size.height + let step = points.count > 1 ? width / CGFloat(points.count - 1) : width + + Path { path in + guard !values.isEmpty else { return } + for (index, value) in values.enumerated() { + let x = CGFloat(index) * step + let y = height - (normalized(value) * height) + if index == 0 { + path.move(to: CGPoint(x: x, y: y)) + } else { + path.addLine(to: CGPoint(x: x, y: y)) + } + } + } + .stroke( + LinearGradient( + colors: [ + widgetPrimaryColor.opacity(0.9), + widgetPrimaryColor.opacity(0.6) + ], + startPoint: .leading, + endPoint: .trailing + ), + style: StrokeStyle(lineWidth: 2, lineJoin: .round) + ) + + if let goal, maxValue > 0 { + let goalValue = NSDecimalNumber(decimal: goal.targetAmount).doubleValue + let goalY = height - (normalized(goalValue) * height) + Path { path in + path.move(to: CGPoint(x: 0, y: goalY)) + path.addLine(to: CGPoint(x: width, y: goalY)) + } + .stroke(widgetSecondaryColor.opacity(0.6), style: StrokeStyle(lineWidth: 1, dash: [4, 3])) + } + } + + HStack(spacing: 4) { + ForEach(labels.indices, id: \.self) { index in + Text(labels[index]) + .font(.caption2) + .foregroundColor(.secondary) + .frame(maxWidth: .infinity) } } } - .stroke( - LinearGradient( - colors: [ - (isPositive ? Color.green : Color.red).opacity(0.9), - (isPositive ? Color.green : Color.red).opacity(0.6) - ], - startPoint: .leading, - endPoint: .trailing - ), - style: StrokeStyle(lineWidth: 2, lineJoin: .round) - ) - .shadow(color: Color.black.opacity(0.08), radius: 2, y: 1) } } } -// MARK: - Category Evolution Chart +// MARK: - Combined Category Chart -struct CategoryEvolutionView: View { +struct CombinedCategoryChartView: View { let series: [CategorySeries] + let labels: [String] + let goal: GoalSummary? private var pointsCount: Int { series.first?.points.count ?? 0 } - var body: some View { - GeometryReader { geo in - let height = geo.size.height - let width = geo.size.width - let columnWidth = pointsCount > 0 ? (width / CGFloat(pointsCount)) : width + private var totals: [Decimal] { + guard pointsCount > 0 else { return [] } + return (0.. CGFloat { + let maxV = maxValue + if maxV == 0 { return 0 } + return CGFloat(value / maxV) + } + + var body: some View { + HStack(alignment: .center, spacing: 6) { + VStack(alignment: .leading, spacing: 2) { + Text(Decimal(maxValue).shortCurrencyString) + .font(.caption2) + .foregroundColor(.secondary) + Spacer() + Text(Decimal(0).shortCurrencyString) + .font(.caption2) + .foregroundColor(.secondary) + } + + VStack(spacing: 4) { + GeometryReader { geo in + let height = geo.size.height + let width = geo.size.width + let columnWidth = pointsCount > 0 ? (width / CGFloat(pointsCount)) : width + + ZStack { + HStack(alignment: .bottom, spacing: 4) { + ForEach(0.. 1 else { return } + let step = pointsCount > 1 ? width / CGFloat(pointsCount - 1) : width + for (index, total) in totals.enumerated() { + let value = NSDecimalNumber(decimal: total).doubleValue + let x = CGFloat(index) * step + let y = height - (normalized(value) * height) + if index == 0 { + path.move(to: CGPoint(x: x, y: y)) + } else { + path.addLine(to: CGPoint(x: x, y: y)) + } + } + } + .stroke(widgetPrimaryColor.opacity(0.85), style: StrokeStyle(lineWidth: 1.6)) + + if let goal, maxValue > 0 { + let goalValue = NSDecimalNumber(decimal: goal.targetAmount).doubleValue + let goalY = height - (normalized(goalValue) * height) + Path { path in + path.move(to: CGPoint(x: 0, y: goalY)) + path.addLine(to: CGPoint(x: width, y: goalY)) + } + .stroke(widgetSecondaryColor.opacity(0.6), style: StrokeStyle(lineWidth: 1, dash: [4, 3])) } } - .frame(width: columnWidth, height: height, alignment: .bottom) + } + + HStack(spacing: 4) { + ForEach(labels.indices, id: \.self) { index in + Text(labels[index]) + .font(.caption2) + .foregroundColor(.secondary) + .frame(maxWidth: .infinity) + } } } } @@ -687,59 +878,64 @@ struct PortfolioJournalWidgetBundle: WidgetBundle { #Preview("Small", as: .systemSmall) { InvestmentWidget() } timeline: { - InvestmentWidgetEntry( - date: Date(), - isPremium: true, - totalValue: 50000, - dayChange: 250, - dayChangePercentage: 0.5, - topSources: [], - sparklineData: [], - categoryEvolution: [], - categoryTotals: [] - ) + InvestmentWidgetEntry( + date: Date(), + isPremium: true, + totalValue: 50000, + dayChange: 250, + dayChangePercentage: 0.5, + topSources: [], + trendPoints: [45000, 46000, 47000, 48000, 49000, 50000], + trendLabels: ["Aug", "Sep", "Oct", "Nov", "Dec", "Jan"], + categoryEvolution: [], + categoryTotals: [], + goals: [] + ) } #Preview("Medium", as: .systemMedium) { InvestmentWidget() } timeline: { - InvestmentWidgetEntry( - date: Date(), - isPremium: true, - totalValue: 50000, - dayChange: 250, - dayChangePercentage: 0.5, - topSources: [ - ("Stocks", 30000, "#10B981"), - ("Bonds", 15000, "#3B82F6"), - ("Real Estate", 5000, "#F59E0B") - ], - sparklineData: [], - categoryEvolution: [], - categoryTotals: [] - ) + InvestmentWidgetEntry( + date: Date(), + isPremium: true, + totalValue: 50000, + dayChange: 250, + dayChangePercentage: 0.5, + topSources: [ + ("Stocks", 30000, "#10B981"), + ("Bonds", 15000, "#3B82F6"), + ("Real Estate", 5000, "#F59E0B") + ], + trendPoints: [45000, 46000, 47000, 48000, 49000, 50000], + trendLabels: ["Aug", "Sep", "Oct", "Nov", "Dec", "Jan"], + categoryEvolution: [], + categoryTotals: [], + goals: [] + ) } #Preview("Large", as: .systemLarge) { InvestmentWidget() } timeline: { - InvestmentWidgetEntry( - date: Date(), - isPremium: true, - totalValue: 95000, - dayChange: 850, - dayChangePercentage: 0.9, - topSources: [ - ("Vanguard", 42000, "#10B981"), - ("Bonds", 26000, "#3B82F6"), - ("Real Estate", 18000, "#F59E0B") - ], - sparklineData: [88000, 89000, 90000, 91500, 93000, 94000, 95000], - categoryEvolution: [ - CategorySeries( - id: "stocks", - name: "Stocks", - color: "#10B981", + InvestmentWidgetEntry( + date: Date(), + isPremium: true, + totalValue: 95000, + dayChange: 850, + dayChangePercentage: 0.9, + topSources: [ + ("Vanguard", 42000, "#10B981"), + ("Bonds", 26000, "#3B82F6"), + ("Real Estate", 18000, "#F59E0B") + ], + trendPoints: [88000, 89000, 90000, 91500, 93000, 94000, 95000], + trendLabels: ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"], + categoryEvolution: [ + CategorySeries( + id: "stocks", + name: "Stocks", + color: "#10B981", points: [30000, 31000, 32000, 33000, 34000, 35000, 36000], latestValue: 36000 ), @@ -757,13 +953,16 @@ struct PortfolioJournalWidgetBundle: WidgetBundle { points: [15000, 15500, 16000, 16500, 17000, 17500, 18000], latestValue: 18000 ) - ], - categoryTotals: [ - ("Stocks", 36000, "#10B981"), - ("Bonds", 26000, "#3B82F6"), - ("Real Estate", 18000, "#F59E0B") - ] - ) + ], + categoryTotals: [ + ("Stocks", 36000, "#10B981"), + ("Bonds", 26000, "#3B82F6"), + ("Real Estate", 18000, "#F59E0B") + ], + goals: [ + GoalSummary(name: "Target", targetAmount: 120000, targetDate: nil) + ] + ) } extension Decimal { var compactCurrencyString: String {