From c71e0bf602737e5f1f67f13885a3b7a0a8cdb87e Mon Sep 17 00:00:00 2001 From: stephen Date: Mon, 12 Jan 2026 00:41:54 +1100 Subject: [PATCH] Functionality of creating folder and uploading files works --- .env | 5 +- .env.local | 5 +- docs/notes.md | 13 +- docs/notes.pdf | Bin 369397 -> 373858 bytes prisma/schema.prisma | 16 ++- src/app/dashboard/actions.ts | 123 ++++++++++++++--- src/app/dashboard/dashboard-view.tsx | 188 ++++++++++++++++++++++--- src/app/dashboard/page.tsx | 39 +++++- src/app/dashboard/sync-actions.ts | 113 ++++++++++----- src/app/layout.tsx | 17 ++- src/app/settings/actions.ts | 68 ++++++++++ src/app/settings/page.tsx | 123 +++++++++++++++++ src/app/settings/user-row.tsx | 113 +++++++++++++++ src/app/upload/_actions.ts | 60 +++++--- src/app/upload/page.tsx | 12 +- src/app/upload/upload-view.tsx | 196 +++++++++++++++++---------- src/auth.ts | 14 +- src/components/layout/Navbar.tsx | 29 +++- 18 files changed, 963 insertions(+), 171 deletions(-) create mode 100644 src/app/settings/actions.ts create mode 100644 src/app/settings/page.tsx create mode 100644 src/app/settings/user-row.tsx diff --git a/.env b/.env index 667e6ce..ca0d499 100644 --- a/.env +++ b/.env @@ -14,4 +14,7 @@ AUTH_MICROSOFT_ENTRA_ID_ID="b549931a-f491-436b-b7bc-d37d8ca3c17e" AUTH_MICROSOFT_ENTRA_ID_SECRET="O3p8Q~oMph-0kSLwkvzEJzJdx_iHGOjJjrr5Pa1A" # Required to tell Auth.js to trust your localhost/proxy URL -AUTH_TRUST_HOST=true \ No newline at end of file +AUTH_TRUST_HOST=true + +# added initial admin user +INITIAL_ADMIN_EMAIL="slohning@live.com.au" \ No newline at end of file diff --git a/.env.local b/.env.local index 667e6ce..ca0d499 100644 --- a/.env.local +++ b/.env.local @@ -14,4 +14,7 @@ AUTH_MICROSOFT_ENTRA_ID_ID="b549931a-f491-436b-b7bc-d37d8ca3c17e" AUTH_MICROSOFT_ENTRA_ID_SECRET="O3p8Q~oMph-0kSLwkvzEJzJdx_iHGOjJjrr5Pa1A" # Required to tell Auth.js to trust your localhost/proxy URL -AUTH_TRUST_HOST=true \ No newline at end of file +AUTH_TRUST_HOST=true + +# added initial admin user +INITIAL_ADMIN_EMAIL="slohning@live.com.au" \ No newline at end of file diff --git a/docs/notes.md b/docs/notes.md index 8409b5c..f75b471 100644 --- a/docs/notes.md +++ b/docs/notes.md @@ -24,6 +24,7 @@ - [7. Run this whenever you change your schema.prisma file](#7-run-this-whenever-you-change-your-schemaprisma-file) - [7.1. Pro-Tip: Update your package.json](#71-pro-tip-update-your-packagejson) - [8. Where we are up to 8/1/2026](#8-where-we-are-up-to-812026) +- [9. Testing Creating And Uploading Folders and Files](#9-testing-creating-and-uploading-folders-and-files) # 1. Reference @@ -340,4 +341,14 @@ I can see a few problems, 3. We would have to create the UUID ourselves, so that we can create a folder with that specific UUID and store the file in the folder. -4. The Upload file Page needs to be able to create folder as well select a parent , add a description of either the file \ No newline at end of file +4. The Upload file Page needs to be able to create folder as well select a parent , add a description of either the file + +# 9. Testing Creating And Uploading Folders and Files + +The functionality works may not the best user interface + +Projects ID 0371fdfe-a2d1-4f25-b229-804f299bc064 +Project-1 ID c8eebe0e-6e90-4cfb-8e44-c05f7064f3b1 parentID 0371fdfe-a2d1-4f25-b229-804f299bc064 +AS-NZS3000-2018.pdf parentID c8eebe0e-6e90-4cfb-8e44-c05f7064f3b1 + +Now we will go now and add metadata diff --git a/docs/notes.pdf b/docs/notes.pdf index 3b6ec2c3bbc6410d4132b680d4331429bc1d05ab..fb9012d7bab2684466da3cd403d4c298a1f5ec45 100644 GIT binary patch delta 58284 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Ν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

PRH+|Q_&J#qpZddVZnv%JLzm_C zfnGYLlF!yipBkazVXS0#3>D%h2noyRtk814vz%JjDbz`qY=e+k| z*}n`m420pf<%s$T(<1$A#zFy|f@W+%vt9ph2oC!FWw7o9 zv?Ujl##wX02ib(OK4SlAv-E{0!=mC8F+Hcq@HO6%j$Yw|Q$#vFm@-N!#l|B}2euUN z!UcJDV+Uatzq|n1AaeMuSxhzf-Ve;0g|S#D`}<%1(e7R-ef*9o7_jhR z)tG$YsxjI8D;8z&4{h+zkl+WIQe*QuH8DYA#inmBl|w#HONq-!T;pj+mZpfKP;)JDV>FH5Pwl4-*qXMH;H_#hgeinl1;; z>cc`wbdD|)<@RCjWGb7k%gpGP z*xVsLj{m}FL*>q2@L0)T{;YpvvxdqkczGCqY%x8~>`32;$bew~+1}y4Ui^Yru+Qu@ zp{ql@d~mW~$Z8+o@QB$s)h}SRFNmJS??TRnM*I6kbINe}(_!)P6*Dr@b6ywftEOk+ z73sA)#9vI$(aRs252}Hfo+XS6SA1O=wtNhp`X9`Ki7c5!Ii#mfmPcs};xTEyE)A>3 zLee~vJaT6eClHvt)lA|v0$R->YVvq2;x2+RUpryXJBKU^4)6}~@l|8<6$P}9VnC!I zM`hA6#4sXi@jMNP4Fq)0h^UD?JBgv_h6xb+JBf7!^uP>?pG}Bu7_zj0uI*ijwgi-K z1=K(bqA7+%;dk|U&-#c=BFeQP&P27<#9WSCM0iE)JqO&*Ag@6|O!B{uLiITilA7V5CiLQhO zael-U0@|5Q)aFrF61_=iQV>xF9bXL`#o?vdK}09ihL=K*ki=1T5YY++21A0SCy2NP zw10IlaVuIuCu<^=5MmU8gZ6|Fxu`9asD+Ar$WkbHIcXmvg~P~to}_-1gO^~wU?Iba ze#jw`I37uukX3lVS26*e!LQvSiOvYEfqB(O60hPPuGivSSwq|hf{ugRlXxUCTn&uT zixnhW^ldHi9D#`nFA)_8EM8SK@dKI5!L5y$o9;jw;C18ST4p#y$s1|S~V1sG}R{}m5mT)Ctgn{1^Z~{LHqfZgA0^W(MPZ2P~ zq{B@CGfbA6zP^ANu+jSZ0%n*TxDqhK1V;4*%rJpbeE~BpycYp8AO-k+gCVhSpe7f@ z{#Sk+n3KMM88dyj5-?*%RnrHN{;g>Sj8X;6n8Tbv!hi3X18YIQ#}g$`Vmy(Bq7y(d)5S=8QCfSBHAe4Zda&UVf*d7Y#fGo)y?O0Eg;00t8d&u0O<)MKfhZYBx zUY|C!HZ)i$+R)O_V7Y-XxH7c4a51znbWkVS(7NDyM;p=+TDgux|A37QAfW-lA zr44bwfwiO!v4ATCeTW4!P%HWn3+7C?7-GR36qP>2f&~LEhFGw|+YGT_1zUzb#DW#D zO&?-GaxUl-@D2=_z(2&vBkB*TP2~yVOx~19q(vAS$OmD9$mKAkRY24_o~=T{kXIoP z9SVpOF?9PZED5*(DV}30iGm?w3Ea|~N|GjIltF1$39$h~E<9MLmOUgL0$NfI3K7c# zv;F)$5zLzwX$b)xxB$e9`$!1WXYzkJgm>)%v7JDm3YO1|d>UyUB*mfHgCvQv%S1CW zmoX$FDjnv_7?Kf{4RT=&35m*v88e2YLC|{$&g;7S#&Wf}uCGT-3Qx6-?3Kx>Dx?GfX}+xKM|n7|g5A3?#*OwyM{M_Q-}K zut!{KKv3_GkfboQw-$dq4;#t zOrD+*NrHfU9|5)FH0ch84nBrr>LY*xNVWl_u6UMY2mYf01Wd7kO?sdhT=Mcpq7Kq3 zA#FwCPvAyV2`LFJdI}ABes$X`oSZW^F*78TS?p@ z;lh~%%zQ|=G<{fxK}Zb3rGbIdXATLMhMRcU8h^JEEP?(YYQ}4VnBj+g1^1wrK`4#i zV}el~g#Gvx3pNdlx^$>28`hR3V8#r;5-?*1TEH6G5j1lc0#NEFWr1y@fg}6^)iLbr| z^ZEE4+)!2kMBw|57{Y&EnfLP@@c{ua#6RPtg0@~IDe;usi605e*h9*Mdp`X^bPp5O zr-0aoAfvxN6{bH38S#5yv-H_R^VO$;*w{n!#kapcn?GOvKG**=G$&RktT~{*dH{G( z#8F>3y3+;I1Jw5jruPksfcjox$fgIX{{DvJv64QZ!j_+dp$P*(1=PnTBKUlW_CM6O zSC=HgJ8eUZChk2)(jLToM12ltuRbXey~IcoX!SYLWC2pjM6RMFEmS}tP2nmpDo&rO zJWVq8#JMS+9h(-iB;25VaPtEeoM)E%ESuPU1Mw3d{V=yd3Yw||NE32`~RXnkC>YyFRM zkL~?8q)QVI?wM}gQSoRzt8jy5?cvqjm)1G1!ObyuUv9f!ul7Ju;p8NJn}ZSxE6=N@ z7a8fr*RQd0yv;rDy)d$(Jj{0Sf_}7aW36pkp{RoDoCay9&MMt^NriPGPO2MY%XZQC z9Hny{3lGx;Lx`4%1NY`1av-zD8r*%A&L-C z;W*NOz^&mRP#<>1pk^}wf9MaxgrN1qKp||bVWm}sDvA>&sq0|yt5f#aKC3ND+q$`VB<-G%yG$TsvRBPONljX=`{v7@Mx*0p5 z8DOx%bD-HKa-LLCzX8jcRZ=>KeYhvRsF;*uT=DJMGhUQs3%9DQVEXsH%gbK(J1te% zmcGeg#}(I>@8Nlbi_%)NT)N-3+oS;W!it$aE8FAy!WHk_PT+k0Wyp&>YoCq{SGTGXsiQ zDkLI?c56Zr;EN1~GPFR+hTw}nhLmQ4+EAvFWFShUK`p>9k1>o&#gEmscr(k0GYN=I zhc*CVo}*AE)CLISMnFX@&@2eJrMdTm6Di_1I@gI!xoAN?cTPvfdogl7MCz|CWq^<>8ng&X*{rIRJNX4sTC|=zzwzZRpfVe|y;87-cEKe0o-X4~jD0^|tU;M7_xI*{K8c4KnPH8Ak%@<7P=zi$Bc2r8u)o z4@Fxwc6T-u(REK!#S0hQcsT9rhNywpoEi7@vh}WAzvo)Rx}SFK&C~83eVm?y6I^5F zU%p#>r9ChFz{RFF+w@;Yx_A23W$qU1oHIUG^ON)E0c>k}{0tPo8Uld;9nv|BO5-aS zsx%`P@BqmL6L|Kzq+E=bI+whUz#UvUJo3cR990l<;rNXz2)S_lMiqoyIDVrFA}$=i zQ3Vkfj^C()hzrMWR6)dr<2R}x;=d*iHA0uD_{Y9A5rsxN4oRcSwayo+FcB- zv4Xm3kBETWR?LSYU^H;6`t~Fy4$r*NEqjs{%CR7&qU(;Jg8<6Z3Fy8Pw9m34b>hI` z-(FSW0ThD-0;QQaj^|)QT0-OsLPQ*qQ3pdr94`SPqf!O12LwQ+3SbW)GAab@{}35f z5E0QB(C%MI1Q?7uEGDvqt0AyW17|~}3Bn>8U@)p6E}{VjqY45e8lW!fU}VI100xUl z{MaK8opOcA^V3hF?jRcgB9MMMj28!iNboW+`KQB)Dm(`l;yic>l+H)iyud{yNJFuf zgOmo-P-8twe9Rk)w7j4-B#4e+XzL1S9kYz&hByJF@wn@70cWZoO`eIqSd%62tW74e zSp_UW*5(Hq7YN-g@FE!yFvdS`tjoK3sn%+G4w%*g0POE4{{R3b$IH9DhTWtpr%woWXFJ@gDME^7?7%<(pg4B?j9g5 zbuhStwP)b|mM&lhB24OF_%uS}8G;xk4`a~Lx_F`~dKCsz1TUO{;=&;fHc&*GjJsmU z7`zS#-3$&QLB=3F0um1VjKTL{QV`OOggcNTaKlhjB#3e-JK&Eo^#?Z+A2vVI z9&a#88nI?5>;Z%u;Oz3y#hoA!aCWX3D&GS|aCR7m#515c=@r{n*$swb&{S@dnA4l>{{I%0CAu#dM7`jjh#X%F_Sp;(j z6aSWg{E9(xVB*y=^an2vn)s3us5@xlJ@Ke#(8Ql8g(Ba?gL2|Oiz*1jy;00%kRe$5 z9Z2E|lpqjKMiG_JOA6oSyH$hm`CG28l+;atZ0|7T=3D-DFgQax#y9tZh>&mY1rZ@0 zfKvq#As&EJ2O~nQyztGvAc)|b zdqEI^hul;_5WzS8gF(bdU51l`L0tw(@spSkZwH{=Qe-gSZA2pix+)FD{gtG00+B|c zjF1K%Kp&buGz&a(rV4@&JaWeM3)~xj;kU|=C-DNSNekvdH~;LqJo+F(E}cjl%v1kM z-hf~QM=VnO7SANf=TVnDFmp+Y+)7ZvMGu{iIAx&?LSIO%r7Dp1@lf{!Vk(kl@#sbZ zmB^5%q5XLuGFcl{Dv+blr77gU3c5&AZA z;S!wSWK^X{_JzYaesalPiJXS)XOgveWMwi$=c2Qr&%nv#g+#Pp4~nm+keN7o7>X*> zQMV~M6zNSRTMiy1$PsD!aIOcrQr?lNWb3h90bW<53E(9r+S7k=_A1eR>xWS|SgQ1X`r2T`T0B!MYIf%J%^`r?B|G4?12@?Of z`J)L?9d7<;0#t{aKbip5;pUG#t@NH>to`GsT!0;0M@vDb+# zNkluALN~Kr$$*Aae1ICTm>dj;Z@y%H#2$%0<0Z)bOQC!>@@BNd4=y3&BgI?kPKF~( zTYp%dY%7um@5xfU=eU*RV6>4(l0vJOkr{{@Kvn|X1?5!XJy}Nn4vEL1G#S48X#X%N z;9S~2ObQYn21&v2(f&bFFnqLskQ59bO^~d|4IfRAt;Y=?O^~g}4IhoBIpkJw!$%Wf zJKWUK1lSHt9S;j6OA=7LFHFZI1O$0S0nSpU`H@#4MkrkJC34M=yanwIBO9P(fASAF ztc1#+SCXwzYy_Eq){aj*AOLhxOMnJ(8%GnMK|CKw6QDuJ2cpT*7&L)~ zBhYXs-iHXXI0>DOCyUT=FiR68<8h=(6C~pqfHY}?$@t-xo`$?az}?}=aE!)4UX5V( zwbqdz@%Q2Jsq4vbfL#lZYru)8H%gBo&mA;RaL$R3eu_6?1DQhL-HIi*64eDzj&21j zJ&5H-jzuUN^eV^TS%I(!7#H^{__+9I<~quVn|w2C-WWHlz{6~o=n|8@&WpP&#Eh-)6w#_XzDC3ZWX-Rf zbGT7uhT>_OwEq>$9S_=8s+^MaJZ;Z%*=T&SlAU>RjXk?G_{-@tgg(vr?^E?-v)ZBYsZ%<0{^ zOI;Ot%T^pselzQso35|Q3q6GmwPyx468vf5$M`9sNOg4S;#8^S&*+XC{T zaBv7Tydi}Gr_ulzg=iq5Q8We)35Dvh;Q24z6!Hu%o@g0)4-yTaE>Gf>=L3DH=%yAz^uhNQ|JQcen-b>f+#;T2(E4j!ovr%@ooiyssWr-9F;;6cbp z8k>TLeIsbVpU^&s6f*<#Lug>I9cuvPu9NbBc9GJmJLqaqTp5hrvW3uu5s}Sw~^v7b48UySvOIZAn z{2nEKNP*MvAbi9iFb_NvAVgybTRljT>kC^66=`K77 zn~6U+Fk%o0$A#?zWb&z_28MVX&qfQi9pOv(>ko;4%1E~e_zPlDJbyW|F{DC-8H5OJ z)a)Qm8?|(}lNi;O&gDOFGjb66C;$S74@_bA2{iU7Wu?(Mc#tx(KL-CHEFl^{J;9g1 zK>Xl|M$Z_`_bBl*S;8obN@MXK#~L{ZizDn0;N*agr{o0naQOpqH2kH*Q)$BDqQkMj z@O}s1Bn;Q!&|$Q)(rKd{7S!W#g^>!JQLylwgn&angAB?jt49Yt64nnogN5gVgxYdO zA#ggIpL~RR|L`B2anMKEYC0Rdj&O$@{b2@V(0%}{5XJ^@E&`Zds4auS7^&zWe=2<3 zYSb13of%~p;Lt|c15z1q&LFHG3@QiDOpK5M1Cnc_m;nKfPzGoLNRKXz;ef`%Gw&lh zL}w3?Wx4q1qbJGaC*np_XD~;r2?H#P@Cq`RoKZu;qK?{B4DecXVeicV<0tGyVNc;F zF(a7)_a>|+3=R!HK^R#NHnZ^RGr@`o1U}@w0WOX*173CF!sLWi0{2Fvm|^iBHXYd?L=&K5eCsW+ zUrZKF2whX))M*ri1f}CYZalI>aCyQy%VdK#2v39!kXu0e>%Bo|MxilaaFi)v0q7WR z{D1>0faXzBU_shVSPC$=Q9GQ)1*IOMqvA(SLNq3R z!Z(t}=J1^@E`NdeA+j80MpzvFG1bV%95#NOJA%fB@JpB(Hh2Z$iNMMYk9YX%54s9) zUARMVkHXptDTz^A5umkj)CX{TRAvEav{6QvP2>I_4jHh@!ps1=8^s{LXNBwGL5nbr zMH}Um*{r`YEzDmael~k_=)mUiA1fItYA`gy#uTzN!to9`D1hcd%y20D!!|*G==^@N zGNhP<^@9U19tckuL?9eRf}fxW2k}7TzfvF=0}4RnpTG#w*n{AIxDX&z9c5WLbifG0 z69I=VY?Z;-;s+HY2LUH9yqXX&j@S^m5>hz~<|rQlQRFCuzyUKlN-|8==z&?I{UwLR z#t$%uGYDxu+Ncy35JzQ$;3#kuY5*Eb*aX0K;Gda}90Zg>NP>W{hHM!+evmA|6-IC@Ai@R~789E`D#ro>7PiKaf#W~1 zGII7{c!f3sXe0kEhkx}z34q8J25@jz$bTa6Uq!qg*ejtO2sG9(zrqJ~K;sB|VSH~0 z?@FN2^?ii28PEw`*fRr-IVvRu?@b6t7I0R{e~x@4(_q7pdJbT&5y}sBAQd-yj$n&~ zT_V)u2>WNSs*nZ|S}dRm`(3CvlvNqF(ll6o;gzPb=)$H9&yfi`1E8^lvn4?LYf}E1 zRXo=^QjYja(;z4v#We?TqVP;OqcW=yk&X&pfd*M{p|*5Lstb8A8U!&kuJFKM-bSq; z9Rdeoji5vJeKc*9QHD^HIck#vq#Kf;AY)3SkBnjHf?iSXOY@A?7=t8h6BoZkP-+v`=e@f;4 z-w0lT|DKXNZKeR~3)ozg0K5h^!3efw2eM!m5JLVEn;6aH`-Y*dXvO zoC-Ju&H`KtuL|aZ_X5izd;w2lAcODW)xq-!D&S-U2`~Ur3j7@b8BB>N0aizs`agQr zC(aY;zj#q30Wb`*D!30x68z&6Y9Nb&iBVL+>&T+uqEGk@MHtMBstUeFkplOl{#SnJ zCsag}0>h(y`IN5$PD2y?pKKH`89Fz3_47Pnba`+rhANm5!vc~IJcFhJUcrz7&tOV{ z0hlgeSFHbPLWZRYhQ(F^cVWqb>#>=DTzmpzVifKkZdL$CB%kcFK*Oosrua?&k7z#= zGo}S&C^+OI;k5%_Yp7Fn0rx%#n~;pRkDjC^mZSnLuhwIwS^69bd4A)C@FE}lz~-uo zkAHZN59H^k)yrA_oW;AVrXTl5-QrvBCpT{H0LJEzr)IT}1K`>_d(YdN^dmj65<058 z$9_NJ)i+JyW#PM=*tc8AhK}9=v>S{&6#jPKk_cYl=0l8O&2eFWc!1>3#nV9 zI+Oi{`2*(T{ej+MoAe0lZDP~f5rWHLDFCD!m3$r_HQ?GT?paMbI|nrfI<>w94b2Q0 z!jN&TItR2ayP!9B2VOsQT^mbFc+sT?d`XX?T*->_{u$W}2k>RAt>6HXn;XoYRX=)- z^Fd=mW)`qoy;qxuIH82fh+N@r`&ed-wa*+q0HbE5&2F`KH;`1Hj|%hgc)5+_KmqK z?jOtrL<5)IdJ9@ZJ3Db96~Zz$JPVEG_2AI(i#?z$W+fFXO!ZkQ{V#*W8jSd;LGvJyYjH|s&ev=kGSj9$HkJI`QySZh+wv zZYCzwN)dmBCZj{XNrARaIWt+uYg%l1IkxLR-b0d;lu}N+xay1zye}WVC=TOZyMBJ? zx;?KZc2Ham~Xy9VWvA%lYOtQJFOt(XcqZL&EIEK^ERcz?Wj4W`Bw*IPk; zMTME|__lloGdlxO?giCs1!=$vJNrCxnhLcH4`JviLLI9gye&M!ZGmUz=}@N(p`-gJ zZrSqwE-5jr#?iDKh?rc#VZA(OEm^CcSxLLUs?60?VclH2$B(S$(6AheLOWq?Sz^CX zEa6uFg;4NcutN|vQ?oVX*JkCy{toAieQ3QkuFrn7;jg`+A{G5$RAv3(1#hNxh@YR0 zvj}Ty=$>Rs@rUyucJQ~Y3%LoF~)eV~a*i5rGzVWW0lHA=!- zSPA9KS0c9#`$C2pFa0tJw|(T{ZP9BPw$YmnhaLFV7fq^P+W==Z6;wGG&PbBg)a(^p zjB=^sY}BFVm{3`Tw7;VIZgxcP;eCQ1v(*5GyB$W7(rWQokrE~+@tgIjc*febog;Ayn^p~k9v<0wmcvu1dSmyRq=b0=fan9i+1p0owa0LETBJ) zPVi}TmQSMxJJiN$f7)D=8wTS78(46d?2{hS=fo^E2zA7ULZr-qb+Lp zZNO|hi{)Wg)`%gFP}Q%-GhcC4pAQ$ax%N#sEr1DEIFHHDD-Gb*>cRfZ&WDjq`10w% zLntq>bv!;&Gr;KiOzwRjJ-OQ#!}{pq=v;M|@?#gpWmA`MM`#F%k}1n7cJYV>2JKoO zK?jl5BGjuIL*TL+qk@D52DlBQWDUm+<;uy3h>!fI#f3a0p%E$rY^982f(Kl$@E6l? zhu*EoYVS!~%tq=;+y@S;@au+Cmpt*1q)fae+B)ZA(I*mP&gq)Fry*0ed<5)3>l@dH z_ejp*g<9o~Z3>o&;jY#bTD4)Ybh3dMnvp|13IE+l)wp#+w15{8z;&c#!18=Ox^4l% z>tLti#5)=O@$^?b@$vYHxR{_NSD14OZg<;=rdUbw#?dv1m)O`n6B|+@R?kf_+}jAh zv}XN-(U;XZwh=eh+e)onxpsoOH2Td1{%%um``iX<^oimrA-HxCxj8&+HprW<(Vq5f zbV18hc75&`f%$IJ$>%yb;1wVxjosRDKh?z8wR>^|HZ;VSh;wOiU-%n-+w^KU8_KB^ zzUMG$h`oefW;k0}db_K_-&1M_OPsd((9ELDHLukuX4kX`x_l*}(=Mp1Uz(Nod~8bK zAENa2VR6!Q(dmsVT#l}mmo+LsTxs}}BXG7N##wtQ^{q)(E&Dlpfi0MbfwZ+XaK_V^ zK0C*O*;I6QU)-mk)=4~^%+Q4RqyJF1aKjsSMrgrQtxf+QvOusiaY4ZygPh~s1={`V zc%M)FLVwE~>bPXB%HZuM*Lk|d@8JZdXFsmU4l~+AsGx&&JP+(TCQJ22Z`^=&ze#|re3@<-2A`PD zJ%=)~!mpP~5CUpzmxW`y1(Pt4w%$cpil~K@@_3XS22Bx&@voJX66Ie!Mud|bLgy-G z6LULh6R>ak3?b~K52B(U^&0BxIrvJBpoP?&Y|yiTZZHq9=@sS3)rAh-Y%xS4tl+AJ z)IX9a2V#z^scs{^+O{%}+*j2kyNiIRDZKe^`8RL&PJqw!sS5Pu*QK?mFtqK^a@un! zj*@kM5?Fw-b+IWlGaY|P0SwkSTH&L#OzEg_1drS?QP@j|aX5rf zw((KAX!_4D5AOOQC*Ji)E;0GZEYg9hT1^)k5dr0Hzs`jb3}~xuS3uLeXXBZCl^k{} zmJ2+TjURvn!z>CuWqSr1I)}QZCdnv_| z0G%ZGOiM@G`6yw$N%a@$z)ixTA!_MOs~~j`M=6GdZo1Q#p5NN>Mn1V5j6sK=I(W8L*kkuFiRv=PCkoRpw0!SWtmvbsBrDv*U~kgKp1VH7 z^v9+;B*5r8>~I;M9ibxHg{)Mh-Wvc;sw_!3*b;U;jqZ7;j`+6qpBMsNOQ+_bjJS2B(hc;(43CEto^ zFq+=go9+#p+6gk6KY=iD>VvJ}KM5rY58f$X`|bf(RscS`|I3Vp9i3d?SKw-^5FoMh z&Gy^;P<)dF>BXb9p}j~ilIJw_sd{xM>Xfm4cN~S362@9UahdH|^Lz|aN8?5v18oRL zB@M<3^Y^;7Vh$sP>>?H%44DV;wMQDTW4xG^sgBB zj`T7hlxxHmup$`wXVkeAHA<#PP&lOJ;hahy(tTrO0@bKcX+j_ZfbDfZ^{}P*8P#S= zaGUJHc=fC*E269t3|nGQ=cp{qds#yV7yfQLIJ^}xKB^kt#%~o3JQAE62)M}AVR8=V zkferF5H1H4GbKn+S=MVjaWq9Uisd^(#j#K5%nUV~mC;V{+hgstKSogu^DtnJ|d0&gTHc9ST76if#UVbQ%Aq69R(el@t=xG;D~uQ&*>yz6;C_w`yBk#m`igGv`E|r0t`oxb!!4fW z0NOGawSejK?;DEk1?kS^P)f6+S3xQH8J=Vhjb+NG^Qh)}2xp(=*g_9sZXHp||Dyl7 z^RDH>FTsB%Aln3JmAwPU$?|#S(Nzh6?`NFnPElsRe{RL(;790t)e)gy2kR6kUYEIJ zrGBsSy=eSi&zY-RRyTM)p)e+NKN19D7!%s}t4goLxap~j7n*UlD3#01V62U0IngUi zHuF+5!an-W4 zCE&MZDwgVSK%7wLRH8B-r+Oc1$v(4sIDiz)S79+9;Te0zah)RLs5kW00zIHQUxraY zCzPkcqJ$GYev^Z%Vkb4N`Cm;uZ?SWs@=-N90e6Eg;i>}|=9}J}8v!+(mEKJ!=lZ94 zZ7A&eGJ!iOq~#^3_61tsKmmViRKZ&B7JvuqzUOeFvHCyz3Y1I2cIN2L2UBHmRmm=5 zX@@!CcI!)c*VlnnL$%G+d&w_o-3aQVr7Q-5DXc?`-8vy(MeZW(f7e;7IPThXIvi=! zH)<|p)xPra^tKW4z?{hnfaL~k_q1Zas>*mhS^*OjsAf56gr7j#{Y_ShIKTdaJN92_ zMpOwXQ6Bg6{KiR8VK&Ot}@0|d8o2-Q(o)p?n};ooB%Yqot#hjk!}#aXdIe}ow*A~+L8l?)cP_XpsT;rp3{EJL z+oc~LOpYj&nMpzSituJB=`ju-En*Z-KXt!5KhpFA8c4SLn=H-syZFt4PQ6gVFfp@& zP}Qeqyhyu{#fsFsF+xKb`fksRX@?V~r(bg1?=qJx@>gPJ+1oNg`v+rqCDrg5hfIt! ziruXy*Lj7L-mBDjsEZy1vTsIrB$gzeg{zCZkqw^P)qfG@2a2Eoa)v@E&Ri+95P|rh zOK+~3aWZgEK0u!53b7mrV?RbkDOXPKdMN8_9f65e0}{j`!E5@R$+COS z*E-$Qmjq#s3|=bb)Vs0y$I@wPOv<7W#wT$Vt6hP@M+MUPErx)x$$Bw3&z~O;g^SQf-1%@4HhO zeaIAol+=&j`uc_q@exzD1unF0D5K zUyaj8DnVkJ*D9u&!gsuhK4@V$AsKd#vG`Qg8E%6V*-_m)?XL8K zkEPXndhtr$QiQ-ZZQ%a0j(VBo{0N!`@F!dbd8NzuspR7~RB?JicWT4TC_KhF>4f>h zNKM^m=6!^t>hu?@DH+XH%3d$@FeGfum9&FrnGH_4bharOThrW_nko@|$u<%E{4BA; z&8H1dT;|}+|Lbu6%Le8Imy2AK3UQLQAV8FJ$xS=plTa7t6F!L=DWak%^<9!69V9Mn{SE={o5@U8l{b z>ug6vKgD5TDx%{UQ(gEJC|f=&|5WfPoW)8Eci6d_;{C1vL5y15K{)4jrdnXDIv^-(1Muq&pZo=0nqtpVR$QIw)tmr8BU=4kYe0H zP*Yll(|tNj_+o|=Cm=_*S*fLGHY4Zo8ZVXMjoo?kxiaVhrx*8Bmcr63ei#;_4*#jK zgFfpAWx5!$e$kzg0{BF?!v7#xm_89&;V8)D!2Wp_9Xzq9(#%Yj01Pk!xwLP4n&_`f zNYpP|&|;L~=(gW*#DB8>kl)O5yn^mU8bC+z#}SWm#Sy27Zh_njpk+xQrzpBmhc`*K z69?72{kSfE5)0Za)VzWQ9X&!ysV6-W%jK?;dPP{vRf$qZed5X2RMma|cn9|A^_D&Y zL()OD8K2lDhrt#n3~{p(Gr2$Ik0Cv*!X|M@z7mzQQNFxEKdcEi9|niJKj6wXeCI!g zXD0%Ya4AP;CxpVIYeI^%>YF^=XHuQWioar(v8+{SmLL%8wdw!IytJr!Ks`k|SJr13DMy=XUTM31a zUJjs*GlY-Y{(x^_ic79GXtPR{3S_w4AS)CwT|h)oeZ?M;YvfYX0ZyoO;Xd8u*1|wS z7+Dt01D~M)4*6T)~ z*VJW>b@&3~y81)ZX&-_37a^N@??e~i#7_3pi*cv*t7ZWPTxL-?BHFFXTxs~T;{UfX zZ2cDXql-v{MPECN+F{D0K8003BLXl(3WxDap zsX&h+##;kOC`*wv9il-yO!U`}mGnXMLFYjA;*+LX%>#mGD9~-Si5N|JP{T6*Vv(dr zhzp?@{gr0Nk1)-By5e7YZvmt~taeB4kN84+FU@%1nMOh{3@l>K4lRbwO}t_LD!;)% znq>mo;F+RN{zY;`(xe)9$^#Vo&_TUi3iURPB1iwAQjT22j6UY5yL?6p1HR(LqN?8C z+awtBq@m7jcbWI%QCch6Ct5baYVbK!`#WTA6@}Ljo*UHo57i-5al5rZ{^#uny^0!! zKX9k8VgR8l>L^vxkxWWb$#OxMd#MtQ>XIPPpe)^tpjKvJ0drw-pHg{f0dr+&A*>RN z$4Ln!8e9s|himkWMbgJE=g}}hsf6b*hf(-j&B>Jxn zb=CIQ1JQL3jsm~bn_$itZ7uTOJ?ILL4o4VR@$uZwD+jDbGp4*PwnsR^_PgA$n-n+) zMW`p>f$kAIF+$N+K>umODK~Q@2$kTmA`pQbLfMQA0p)iszE6^PRkcGnbO>!OD$060 zXp)V#`2*liTv<{B0x<>_ERW^P9*%H>C_E<#Zc_y&Dn7}y%J83K3mAM+OEBfs!2k3q zmGOzGJ?dwP_7{X|X^~;FB)QP@nar`rRh9Icn#9b;Kgaje#CET^5fC@=a!2rnnOj7_ zd%;x1FS(4@Srm^g5d0^cP>z|!!EESnYyPgY0oD2}BjrV}b~x8SOvUPpkevoHE&)fb z!&>{3MsM7AmQTz6U^+T*1EMjr2M)JXQmN>0eph(KG&cYu5FcTL;A)Bnk@3d{i{hT^ ztH23ziTA-YI=8#~VLiYv%6&OTmcT54(oz7f!2qD# zvRyB~(e0_v?Gb|UD1bQ6R&sEo?GX%!B_$9?`bum3I#Qxd#91v{a?Qm_ z?ga^FP1O#1iZ}+6dFI2f{_|VMy)8?7ZfeS$f=vm21x&l0yTqStAU!??PI_FAsD+Th zq4;MNa>7=&D9wjYBnVkf>ik-Q|I92`)^Car3YzuO@GTN4MR9OLD83`ZlnEm9b0!XT(;%b7d_7%MGc-M>JnlsS2=ms*^!>|&v< z)BfmRbf1Bo4hQv^wUnyu>3fE4BFNn$ixC< zW}CVz0`nv9R65~uKX_(W5rQdockVuG6NwA`kw|>te#JTi#c-BG=vj+bYa{~JX!$j# zq#nlkh#eByIO7rZuj*|APRLLyR>_>^94EUm?q6}y->}Kb^@JLK-)p`ZRTMJK=oS9c zGEkDkt;In>`1`%iAiCB6^CP#mpJ=B0v7cD7KhN^hui>&2X5Dbr%_Jcd#M?1kKISkT zgh^*E;4i>aI_USZF_xxVR}aNg`WN#Ra}}iDO9tE8Zazy&Vx*ZlY-oa9{Q7gl!Q0U7 zoZj~^ziR_-Vub!iQCwUh^N1qtz=TJVq}q_s(aJgzRZcFeNv|Z8AjaZHt9$ljU(t-I z>KG!gK$2|sv_(j%6Fm1+M|GM)W^!*~$p#HL1E&>Oc*^yD6#(0VOvE!Ia@{S(+7_NT zOe_Dji}`fmJzXDOvDo^2rMTaX!>P7Ni`mJm5;MFb|HHk@Zr~acIS@EnV4f< z7SIjdiD5jDU*aF_25JXGmcm!I_Dnb~pIEPVmvvQPX9v>Jgw;|AFup*6a9g8FcZ9&~ ztkSvWJ8WiAj+O>q=_Q*HwaZgQ)bxj?x~3loXQi>CkF>&80SZeX1ws^R>_(o~lk5Uz z=2Y;i{iMb@dfuO2&>@Sl@YtCdLVJ^S5b%oI!YAn&1H0#oGTYLXz(i{~?Z@L4kHq2d z2m5$c0$-|EKom=Cr1JPcWZ}Tr1QD+P=~70OvAI^GmQ{_5{|o9R??VU^kM`0sOfwcU2hbL8|}wDcPpeZhSQB*45? zM(k&(m||i3OAfsmc6H$?f~>d&*hN-#pD79ncfsr2wdUN-w-6D`TtZh=4ze2U1CC}0 zmoJd~RBj~1n5wLp@s84_bqT@`B;sM@~cCh(Thh&o?%Wi0Pa-ELuSz+ZYeJ zh3Az7sJSpA4|VusYhh{~%JyQ=0MKxyeK=QyFct#$njTGdT+^+^1G( z^w2dp={_T4c@1C9e@-e`ABCj2`sOvFmqPEHsB#*5Dx_QGz1ejxknHL8_w@K8Od0N5 z97hNK-wmeU;++z5EY!kY<8&k!S3le}f#i^&m(f>v$WZc-mJ1pT@219uIUsbmUIx-_ zy;=6qWXh8QK;VtW-{6 zFNW{KMt5ZWYbs*$mssQ&aH7mENPw`AvF{I0Tgh$@0W6;a1>SgotwS|r&~p-+l=75x z2-TVLuD^|-1zt&pl?bE%hYV~;Q>;xjFZnnZb5+!+%}LG=n+}L0j(ss%S}G^EKzgik z_(oLny2hR7A7Lo9l`|P$6~YhpVApFuJ%Ap&5LYo;zv0Xs_M+}+ z?8}V2`R<>ZhX4Jg9QGj+|7~M|Vf&|RUkA^&M*AOpzFW8QiLnPZv@BH~>S*JHADCl> zysxu23gqeq0{!h7uX|a9i~f#X@lP>}9PAr2f~Gqj8KmgHAAv1Y&E(pjfdQscc=gMm zyz_JE#*Mse$XpcvlyX3I+^KMaL(-DoZqD}IZ~i<~|C|wCay-r)m*W_Y-fuz1`wfHh z=4d&OI#vopVy2|+)meT+Z;_?VDl=&}hw6Wt403m8yyBHsyk9F%`@IL#|CKRVUt&Y@ zlg;%^ZQM_O$p#9d5B;gbPO(~Ke^t&=Ra%tSf|N3y_EFy7H=-p^eSIA$XC{$`{Jwyi zT__h}YprW*?fElxC00ZqUeQzZ0)ct*SfcXc)j-=v3XqUc=Inxz&We`%N9z ztE~KZ!2kbB-y>O$r)fS5>?+8GcF=!-B!K+o|NAZ5G9;jf&I{v|sOIKF zLOum8THEgL?Kqu8UA>bUzoASbj@tK3?avjB2l*jZv1`HM7RNPM6Y&0gyNVrDt&9=V zM8($q@pe=V)C+=b(Ju}o&%^K_-{fosZgz`*G&nd1ee4}Y=G|V8bz||7-%%B7M4cYM zUPof|LF()@s}ROp#)oY$6sI_^gh=yj8rp7Y^|Z@|2PXAwHgd zv;;gK%#HoFu+&-69@#|XLrhS}0m}J&e_j6Zkk+oJ9aWAf8%Yb11AF!+S71U7^q1aL zMgndG;>eznr7T_#=WT8{t7)|1E)HbKP}Pt2axs~$|Dkqdyo(N%=~xxMUV>+hmGApq zUMAt`FkPq}UJaPo*_KGz<+F_=!25_P%)$c3an)>45V;O)My+^+0(#)u zyus?;AZvb1Mi!X2|Ekyt3EBOX;)TcNGpEir5i?I$KJU(#WxCQe=Lh!A7r27deeb+H zquaec{MQ;gRu$6k5H{iQIOI@;GB>CDUYr%9jArT6-zCboBHcg|7aiWBz#FzfZ3J3W zTpTE?uOUb{00U`!|1IhzTN_;C5*QFIuZIF=I)0!(i+x`jJr@at0)ZW66ea>xVk%aM z1O`IvzZ%C|AxCwxAj$wrlzvJfLJExal^@~hdwUIrGrmjV@^~S^>x^wk2rwGTCR26h z2yk`Udc$pW6t+H4PUKgdz~ZqNb~S0!725)RRQ4GuMd+C&S!d0&L4sN+CXh9Uib;Q6 znb~*DSy~FX)zp}DFTOrl@6P=cP0oW~NbX^R1nKpMnyLM=FPXN6Mz z%DNxsRwZ1BOnY{f_Y8lWc*f7J|5=B>A|;9D$?d{mUWWLEC;y>bin%spklsmNLHvA2 zW^ERfd|wD&Qi(9d$-{P&*$UC)qnDigjlOzocK(C=W7OsTq8;1PkD69VZHB4kX#tPo!u2Xj5`Po9RV5L0Gk6?2dF+5B|j-i^NGx(N55i`ng9*Yb}2PRwQ2e%zEJfI5AL2fwVsBNSHK6)a^ zE^WD>6l+);#$`;~;sAN+pVWt?CYmmOlkQ6*VaV^bj8^jWrc6e7GZ55B!~>V#+A1u6#0(MnDAJ9V)v54` zlJiGZTfwO%C1n!TGts+Y33bdydz2x=q^|E`6lo1GcOp%Vv00zmI#sZHSu8n_clgVM zSR$gek|n75NA)-Tg~ENTd=Wac%4Wyk@%r+z)HLi1u0U$HGf8_1KTl~~f5}Q+d4f)q zd>ce8;bCU0I|S`ESni@BGLq0#8%!Hv*B`GG%n?)YkdVVHRKxl(Gz**Vq5ohdO>NX= z8H{JN@iz`nWs;9}=Zyu-zvh-m5*wXX=5rqE7V?0YM?AZJZgN#LghM*=1~L%zK-=k4 zJKSUWr2zR#=$;q>+O|#<4c0N{H9owq6w%?lx`sp9{D*%Dlx(X?-XPo?>tscfX+WK2 z$DLg%*^*U|bIHfLb&J7ClLX&D?Fq$g+NL(>o9l+^oW}LBA>z6zf3&R*aRcnw|E9hT zr`pfkGWbmhOb_QqWwKzD4=NgUOL4bsN$jto4g-%zQrr{+WXC=4Nc*{rZ?kEF(Ig$$ z<#WsIJY6Y~hQ{cbEFq8d-1jw!1*Z~;U3f12c=;K)BmWXg`7H!h-GtGK{z!1=EDOYY zt5HX(5EfQt_&c+qsKYcJem)^i55u6UW#E~2R{y%^vAOAU=JN%*E-{jiry*QK3un1B zdjMFXt%s0VOa2CI&F5qfL$qI!N--(g_foh?oriC(rZsKVzj9kvsnYqbao44L@Wj`f z6PmBXEV}F#nW??zNFRDR;6+syd?wLj_uE6SQtwj!{57JNIGSn**Rk2+wgVel_q=Zc zD$H>Aud6AW%%JtE>cKz)DUSFA!&?tSy$$d<))%d z!-cnnDKd=@Uo9%)Mqe^5a>kyA{)lT%9;J|+v1wQRS{E=6|B_fv8r8VcN-W*~VPdDr z`Y+-3k)rWpd1^mS&P*$=+;>$HPqVU}le8wOqCtD-m+~A;QS(`$G}McUmu#h_oq|5l zDw!unllae)301MvD=&Ky7hhU?pwLL$UnC?a$Z;I1pCyYkT8kOHLKP;{8r=g<#$^4u z1d->z(@^s2PN$c&k(@LA8d)rvg>~{3h&J24PaO&&>y1^#viO%-8r?q^d){Gi-(sT~RqdR30$TDfH)_b98(> zqubpc1x@fwsuefIEOwlVO#OQ~O|cGrZpd%T+M*j8u}hsw#dPN$ai_Z0$~ zoGoAZcQS(mJFfv&5+n^L*SrKHs&CS= zkSNm{L^#tbVKdJ;7K=|_K0wU8y z4ib{#8dML;eY&lE_so!rl;#U1Xi>h2*u!}P&sc`xpq|WG05m}WDIf6SFJVtaA{B?h%geU(_avtJ>}JyX@6qp-YP!In@zxqKUsDU^dGeA96)rzykhFt~K} zI)Z{=M}Jjlkyau#uxf85m!sUqecbxM=_myH+9g0^m=`OzY3@U&58xPJCqe9Q8P)^F z`=L2PNmL5xZ_><4!%7f=ko`GD8Ux7?60*3|zGYEa6xGOIN=uaFhl>r=msac*)eCMa zSIhD2mfs@-wU*eHzZjrvjdp#Fd_F}E5HC7ye0uk_Z{zo}PvA#0fivOvG3IY+TqP)N z>vu{pfO=_FrO>Q-e}I%ROZevVh=9AdmuXTOPF4*~gY=IO=_d^@a5XMC;+h6_lbsKV zjeT|esj(1YFO0aLiSM!dYOiUdZ1}AyaDmS>7U69#>UJD9$jV@x`-P1!KtR^`#(VKQ z!A~Q7MwE?ZCM$L-2-7gtvBa^^Ym`s8WdabfzE#!JQAd%dU7MXDgX#w9B&UT^3l0YK)_D;}hbS|O zlLrf14jvS~EI`ltt$qJtN+oSYgnKbQXE)_Hm?~=DL2)xPLB1673Np0@DAbGVj%f(P z+$EcnEw_sUlpM$&Tx;SK%5t5pM8T$A`=S4@_Q-^*^VC4KuNS*@HZZD04^7rt098KW{8k$hqL0&>Sz5z(?8bzX$;) zb~(69GLr~DBIOaKh(ou06<){GY1?X@ZtbR&EcbC?_1SM#v`G>1kE$r-;hb_jH1_L^ z7X_89K(<;p$@F)+=AEPak*m@Y7X zdf>#ioQ4l6n)n!xyreSX^G7B74*%V**v>GK+!ATAnW?IHf830K=F1bTfqEPQ$h0(} zYD;+LTW_+vY>&z=W{nGbmVf0_Nde7lGP=B31KxvPu9A-^3=4LH!o-D%vsPuG~opwX3k z`-{?utHmf+%Q+SfZOYN&i~(FXa9@W9Lf(fR{b&SFobqlbV~GQdmJ;y>Ag6Y659Pw2 zfct|l>fZ4&$_#i@Y4@T^MmS-}Xl?iUevI4iy8$%I$l^3;CX(FWu^#mga$K0!5SItcV02K{7#&6vzcvU%zT>c~uHVK-aFD!LNX3&!#{n~cT1B>CVNUZ*1QL{L4 z2ST_k;hY+aOxjc#snu>Ab@>HkmE+EpQ-2UvPXv16Rjt4C$*a)NG()`q`}ZXc1vo&; z<8ggzyE|#4YF)K3bfbd$8qm8afATwhjVJRlw|;#YzxdR{NpVg8qJw(JM;kumc4Exi zlmN$-JvH(s(&8Sj?jZ07$!g)24UUL)OlBadGkqXFJaPZe1f82I>GO>BO6Du|DdCpn zKT7cnF$9I!uL-@=iqa4G?P|JI;Xu{grtY`ry9QcsgOR{$1x1Qe=EQFc;!`ov_=kv@ zLPL^t-ewaHw7&)S3n@$bGaLGJ7p*tBO?MQ?V|~Z%*HNWNUfUkMVl8l_$;JiuTR&J% zJ1s0RDFs{Sicl9U@u&_E|Dp6HH`oFDC$gh`WXa@2`rZWPmFDbk!d7*?Oo458?cNtl z-Qt~JI6C>S&P2|BejP75;=MoL)3cH*OmKAG4TJwH53KR)2qWtd*FhhkhWil@nfRgq z{YZ>|!zp_`CY{dj!CvB7SLd0cWi^dTreRy3z_hgN-s|VR9niSsri-0@XW8Bh4{k-E zGsN&CK(*6!>?2@u-bvgo?f~c=0r$t+z;fe$(dgyhjgEzhkapPsY&c!7`B})1R zRQp*LHAW#f%qu*R6bz z|0OfOqf-d`>r$xyWq@3ucj4j_)CGUexufY?%i1Mrd8zcTW?y?1nj9d#t{`i|${TFe z+7@cU@*No);;|tIK`|^E5|rN~qp$X0;rCs>5!`cSB#gby;A%FTs zK6UOl$UlwOGi~NfarIJOUBX%|hC?V!)sl~EwBZ+?SX}GeOM9ATg>2e?!K2rnDHm%y z6P!Tm4PNGkOt}HCQXsVM6esWhKO~gaa|K0|_G1i^BFss>*-0Ie(JAf9`!lq|CCK;x z3GM7QT?KYYO+o66y+EKqyWc(v{(%_rCn4t8gzVAE{>02bfy}jwywG}&7P%OqX6R%`8U-o;0Z4&Dg4G84b%w7+I zl3)&Un+>{`WD;f+?Ras3Nphdt`nw;Y=mL zm+A9I8wfy|XNR(lJhc2W3>)lNG))K*Y(4K+dEmUebVAe~P2;QoBg5%2S<2K?qIlnw zGrC5b?^X;q*odv1rAGbF9;rxOt;Q5G0Ka8%qim?FN0q;iXiN(>$s+7mI#Xv>avJiw zm#@z|f-GbJ-AUzM8OW1R5_qbsUCoOd?OM z`LgEjiKu1Um|#c+@hQUNa>2ZWQlt~^O8OCQoJ}6#5qLkWaOTsFzBvS-Av{2kNf79M zRci4z@{uu2NIWn2|-&kHUrN9S-h<7e1?VQBt1Zcv+HI`fUw)iU{ms zC#+#5kUOiGr86DzuEVLQjJhN8dZY|-L2{qRA_??3ynjS6NrkIkHg?jBE~bdbt48Rj z!ch!m9*;Dt67D65t!#MYj0xqQ88-1QZ67VSQxuG(2#vFr&-+JmMpb65wXH{d9c#5V zzW8E=0J_6sV@%_M5&*=fA^%8aR|A&)ZgbSK`v)f^rK_(hB34K(QG@^IBF>VcpE*Nc zIEEmHp+fomrz|QISrmlu{?`)PDhri*NB~OeRPZI@qIv8U4T&k&z!C)g2*h`{!4N8v z3)PyFv8LZOX;#hyZS6&m+a0ghm?F-Bg}Hyuu`VDBZQCtRPR zf+cTzF`IJ?8>zwiMEmcB4U>#DJ~Rq6J8()ZkwZ%}xtGg0XQnj*fP;XFWS>?7NTrOX zbcXfq3>I3;f=R7JBSZr}0MMEL70`Q*2(UR)7{Rk4vT}RrKI~iq@`Ykna_Zzj4h`}V1 z=U)myAD_=jffS&y0jX3V%3;9YQ7ZAco>El%NHW)d05L&ec($NR8-J5Icfxl1sza1M zHK4;2C#8m_46EO!B0zwe65 zL3{GK(+Nt$!H@yO2rz8JIndm3q=u-{cO0wS@B9N2XVdEV*m6dN-65!^_mO}1ot>kn zJxw7-exQk;Uo_Rr74Pjb_l3gLtZDUA&9pOca>Qn&#+Es78bwS&RDOnB# zi>JaCjBKMZqTJY9~YiB28KP&_=RDscw04YXS16%dN5l*R#2;wYteK9KEIax{D z4*T(4BsQVh%Hn8$It&-q4MgU{de6V05<__&Bj?sMCzzDZ783%KkyrqaVaF-yhr8l+6wj4p{9> z?l*X{QBOh*BShVgpaw_%q7|0V3JQ(BkJVJhi7b`~0nfyLmO@1pOU;oNmux{BG?mD1 zu4$VpZ0GQX9c@sRCsICNv*`nIMB{aA3;@wKpqV`4)4UM-mZ6ZoE=9L`g2f=s*W;=B z<4N6t;RYrZJ!dHGuAwB!AupY%%Bc0u{30dnECgQIIr$~{a;&wqTvA4YFiQK&?6ptZ zD%>l<#`A1{VoHqkQD|^3fk5L&mO%=q+W0x%5D}uWPiSr~vkjIh zql|K?UE8Or;sS0E<1P~$5RYc+XN@B6-W^ZGo&VMb8<%H1aS(g|7ZTVn$FX_Mw-upp z=fzoBTaUiCl`z6HQNnt^fu-~iM*v;0%gim1@eZzku(>$~r*DXCC?j|npkdp%zj~Na zjE3!gmoQW=wQn77GxUdv0!|MIw=h0dNajbJPacg~vGLyteMDGI)-Y-WPqL>?9aG7!G*|Y~>lATk6TN$&- zdm!Y!1gdR6D+Q_s?2@DEBYi)1wJu(K_G3S=AG>c@D54VyJMrBWA{eB0@5hK#u0RwT z0wYsb(?Q)YnGW1dGagYDzdwfx%lo&fG(q&`g5Xvq&n{)g6foH*t#e}qX7}!i3MTu1 z0-5sq7rB{$c8t_u<-iVt$kEsr%jitPb`Z`-L?WE*Qi3qpvA}qa=B~AlwtOMxWwuGl zX#1}iAADVmd&vwt#8nE08^&$Y_Kb(!JKPon?LH7D9+}dciWd^s9k31`r*mwxmGrJx#*p5JATVdjh?mN+&E?TaJGPOC zYeQUzVzlSL2zXTcbmW7evwf}mib+IQgzj_j^xv15QTaZgP;BEUAh+yFMA0OFL6+X= zs!WmY1x~^VI5!|yw!9P6s-Sc5l!8i-YU6<3s@)BTyL31NyB64CeVc5U*?RB77FA^} zl|ExFXYY-Zs_UJ~khcghPvFt==_%575MP6NFUw`9ZiBsiO$J!fM)nnCxUP|q@u7FV z#n}Z2+=~Y-fk1%_zDIx&cU|f{O@h{i@Q|;7nL)u2tcxJc^>wW6nT|M8Ug62t$m zHif5VP3dE3@-uw>aYw1@ab1+?C{C71SVjhuSI}f!O5P)3vESiS((H>Bn)XPk>Z&qe z9cg%JRpHN^E7~bwB|1FRTMeV7KcT@K=oTIu=8LBLh90vo=7+{D5Hg;%9?Vkj6ad8lRp^b+jYx+;$?v&Nxmsk9y=bVc8 zBm$IwB-|$5AO}ba;dT5kgl3p1>PO z1KB0hL73!BrxQmQeB_>Nouy#NQp3i=v$;jM;Ks1hs6uagHXV?OP0`qkb~VC z<8Qd&jEB#!cL`_2hZ7D8eI~4y44yD$M04cbIGcpYlX;KQ5DAnBO(bL@U7q4}XdL7) zu1zAZaScb={&x3o)C#5>{zGLDK094wQPwOMJTkedTPNORIbynzjQw`=FBY$ zYwG^s!S{pB2c0qBnew*l@ON*Q2Y3P<0cMvacmg7ShX925(o+qqsRYd^0elCK2rZ|i zK=(j0!G1*L4kV;CNJ7~C0`)p!DO0`BdXNqGV{e?+KAfhvije497~Y{v->1rpJx zz$yk9QAS>-Px-9#Cn6t?BMQdBerTSxeVEVMnxu#QvzGZZKyxw$yK|<}@bgJVHbl<#t-ENxfAcwoGIjqEjFZhK`F?5fVv!4jCrVC=xE#8$99}o&8fjg&s@v5# zf4`hFs}ySY3Puu6rK3v1C~Q-OQ?O5JTW!U<*v#hZR5*jMMWKS+`58+N+=zb4AqdWtPOOs(T)D zb(-(O?`yA^ip4cVH}>x~TRhgqI8g97f5Kx^hXbT)(cvhVhE=!9KajKR^}48|Z$Sl< zdhB6Z@UiT#Nlq%E$8mf{T$CpzPjM)28OhpRU1szP6i9TzP7LIkMY{`jn(#Pw?XjhuA>*XZqHf8+Zz z0|n2ho|4&bs#UcrneQZ7a;@2xyFlKks4-Sz-1%q`9a%u<-UidAvAVST{f-(2I8y~P zFoyQni0eaP{53)8<@G$e;Q^5R#4~xfb}(2^^$7;1pEqeV~I>V1)%L2?B`Pi z7#8FTPAA9$kYb!pr_)M-!~9+A0P}Quox*?;TDlIyCC{J7csfzv&VZAWS+^MluZ`T%JhC*fODb93fep1eatT1JcQQ$GOdUe+8?6kc$}c z1?D)Y8n`HdsR8yng@G(6>WYda)<#%d7%WwjV6X!aym1f-&oqL)CA$skNCP!Eo&Qhb;O znU|DJaA!jSl$^}c19c>ae`_6JCX#4uY@`A1HM&biF$!7E@Dw4V7$9zk4g=~&0oxGA zRB?tzq3k=BjHDP~4x5o^0SM@f#2s75MHmMemn*?$T-XuqlvBd=X516_s=Y=GOf}XG zKd`tBOH-$iu^8U@eTeDQ?-N+s2#Prr`A^)$<;NA#=~)L5efcn)e-97}KFi_UgAn5x z2t28P&${yv4+9)w?ioIOqY4o(({^}v0zbR62eg73!^0pWZsSzWa_C?})x}^0uI!>W ztwTkfBGE(v%P4My!LDb(ZkCL;QM9wQREEpUpf)|%B7HjSu^4O|Gpl13(njM^XemwX zZw&U3xZ?u)it;R*e`KJcwT8^QHifQZ&XuFtH2PI9IZhycRKeavXEt#}%Jh^HGuC!B zPb{BJwAy0Vyw~m&&cx&bmz^bLkz>M>jb;BWJpT{1Aqk|=3X$dI$A^~P9FTx=W@ z$(3+JIT{3{D0hGELbO@@H;_88mF->NqUx77dw#NDrz#Wde^f9IMwimlH>awy%TL?3 z)kxMM$73tS+ap&;7D1ipZk<*o_#Vo(-Y!vdV)lNW^yR?C*-NI*7TGH}nUSk>fve6E zm$(qy-7>_VJwtq8`PTIX{60$fxe_cZOe9CYW(!q{57(_#ZVJ}w%X(vHt(F>}YOSig zcW11Ydau`We^!O#5`o{=9R18T*4fCm*Q|jb>Ilt~9$8IA%}A(~K2{~B$f}J7bxy13 zcaIngArrHty^iGiHu-m(q&hO=eX87Ez_wbKzpVwi`BZm$7CXwe3sut9#i>?hSEqEC z`_qt2D>3PQPpNb+hFWI!A!WT(Zl74U1Y<2(DJ#nJS?61IJHMW|wN>pdU1>>6v9H~Q zPgm?Vzw0BN#nPw!$8Bp-rOl-a@r;d>7HylId!k3ESW)Wy3iz??SL~-#D{D`}T@xlh zu-Kzof9bQiOl>`k)acf>7P#Kd`<)iH*&oc4(Lb2%(ACoF!-8@j^N9DcQJ>FO`}jWG z%8MV0EF5S!@Id0$T+?13Y{zvXOzCtdX=cHaV%q8xADD%@hU(99Iy=|PxaTsO-1_wV z;@Q*;+9u3Dj2*UA)eECx-w8MD=zP~v(6MDUf8Os?4QtL8cdB0s9#(70tAVT~AFaUV zF*!7nglU^@9;R%E(K;)Os4XkSJd_^i84K<*;<;m2Wv$apvX2 znH%RjqSU&N72{O0plB9!D0e&&X}NKGyMpl5=6!SBZpypc%Ekvy$Ycj7KN2c2<+kib-}yZ!cjed=`V~Y(DtsbCrYT9Xm=bZ#<*3 zXnCLCjjkjpi}g%+yu%1mD29sa-NMvVRy1DLpdydJie4$ zNlkaEf-)(*17mj30CiRxG2Hqte}?^z?$(h@N~ZA*3@59I{r=tg-=tG?r*gvsui?VC z>SZc@=48~u#D^*53ta!0;xOg4nv+&hWw`=tFQtDs&g2D(1-9lluVF{J;sSu%eH-s1 zO;IeV{Dj`>VFyx6=2j_~)qGvRX7l*Kpwu?+tMQP>w$#rK|LOhu>pQsNe{820_t!1F zOsgptqkk5DEFW0hX1~;LT`reMSXsCM^FF=}nM4)KjnJb+U9)#|fm`*i!kzx;7b{(` z46Rt{SE{%4-eK+&-sf?^TyC!6FvrnVmisf%)q}K`t{>T2>e@Q;$w7njTYYbJfTFS; z7wpZPN#Cp%<@!8`&*R>Hf4I{~7cIPQEUukh=jSX(TY7W!neV%6e1GrbT%Rspe^7m| z_M#8mV7zX2Z))_Z*!$bdd`5((Wj-I2>jNF3EHLe|j3w3?kV_HrfvRBQA~af?l4jBn1a7*XX9VBrWki?0Dw!r=x4W z&*pNMYl_PsTgtikis+NQ%UT`D_JjKycZVtuZVht9h_Ojc$^8X0r(Gj{*bB)E-hA%E zA9iOz!)|=$yEG2G$!oKoYCphULbA2ie|y&L8j6vNXXNVXf91IoH%)@IANDDVSaYiG zt&W@Cf)BUg!!7u*Pg&J3PP&B!ieZ7`wJ^>D(S;PyEh2D>2wW;6P(8^vs|~x>V8FHA zUwOc-c2(*WiZ=G21^F;9JB(THsbSe_{a)D3-BGu2{sY2O23Wghb49;4Z#CK5q8h6W zjz1xE!X0r(B=daL$8Fv3PQKrCcYyNhJigmouU5sQsgwzR{tRFL2a7%;E|;Nn0uz^k zhy*ADF*P!mNrnR5e~D3}linyaqul>%;fMI&Me_M+vsY&9B#hwZVql)WTeIE7^2ruW z2#&f%OsGI!QvG(iKOHcA{P6dKPAn6qD&b* z$v#mTaE>&5ChBB0^ppM{n$wV{AXp=|iznkv_wm^4=$pR^WuXa)&|APS7n822#vV6id9Z|Alg+bDcc zbKo;R!wgjxunD7aAo>hb#=6D~=Owj&66T9|$N39wJPf(cfBNk~S-t%76@QsHry@Lw z03`{xNp}dde-d|FIlKQNv7vLj-YR zmCdk?P{EaC30)iv=qD2TALbf;GGfE8_h_r^B^nI+)+FmJZZaOqc1Mwx`Y{nFtq z<4RLwJoxF+x6{jf$VAL+0Tl!>p=ZH390g0yPqY1|L3~n>g{ovI>D$5iX23*LyyOKP z)?|RpD$MP(sTNHoh3PLySD%X^U=B?4e`M~ez)CqpV2C(Gj-Rj!-B`sZ?pJT|9Oa_K zTBHYTH>PC8in=kfozV)Xq%{e)11qLTF^q7UBSlRp7EEB_?n1g92Nu%}7PGYC6a`8G zqxQ5paJpby6TLFE4)?dQZJt-Ly~6xC8U2#Vg*>r(TQQ}jE_*Kf>kc@+RM}YSf6Bg_ zaa@Vu&K&e4;hbC%z;S8}^b%slC>6pv)si)R9(*e1P*U^_pl2Bw4p>FkMm8;JrMwJh zf`F(I`KCybl5Y>Y>>5zQlg-q{HmSvDK600!qtYtnnOuZ-CA2il&IL70kOkX8S6Ze9 zrc`oXb|*&5_Mqt*LyQdE+(qBfTPZZi{q$0yj1vNqgtjl5aFaTv`^LW40*g7L5@tTOH(mr0BQ zO@EgXt=P_)MV4=JTq2}VSQ-MR?Y4S8Dtpr{nM>j03jS_!J7|)mQ_ELBDtH?Jq?AQKdsJlMMIN{$jB8zB1glKqR0vyuS?n}bj2ptZ4he7(S)XH zSlp;`Rq~aoJI*EfIMzBEQyikyof`TFbY{%`pKPg$)AEdxGN+=ODi~tr=Ut#5mTDkcv+j>?v1M30|v(H>(#G!!}xvP`0l?hSWJo3vTN9b+k5c9HD>>EA%D<7 zHmF-D&Xw{FGC(k9*Y#%hX}d8xgqw{66+5SO)6)S)NxS#Ywm^-U6eBcho8Ozw-@1oX ztmwf`N?NL|E_{a4E!WkzIF=H8r}{#mucQ^2?R-^6J!1nx!3Yk2iSAMr>qf zd86;~+tVfsn4$*^2N8)w<;+90C4aP)E!nJ`MWy4JN#Z?0;G)AmvX(ISaapY~0*`-!}u}(J%<9156*72KiyTm5iDAuPxd!zOw8_8`pUQsUGMGMr-cvQudk-Z~hVHikL_ z%wQC{hlx2T8lZ4A84T}6s9?tMX@E%rMy-2Nfc4HW5FEp;G=^Ct3_knTgmdn$MgS@? za$9KZ1tX6gOksdGz+gO0_zW|1C^$f=1n$x^6lQ!8$}NB@55mxLfVojI3|*kx$OxT% zFDHYc=Q8O=PSUq>j{<=Sf3##phO8(Wu8gQn+t9yt-4_9Gpt%XdxviEdqr9S&nD|6c zvt2e`z)wgz4I{$AETq#n%f3}qSq&KUj4di_NINx5Ck1|rz*y+V|0Ci$!5%S_7ypkqjI~VQlr#la(IprzH0pOp{NKn9eyas@?w)?PE1xk_hw^K-!<^D_w^rqXbAxELWE5BgjgnEHwi~0z zt=ah6l2NPK9?jm*uG6-eUN=CkwX4^G+~L>DHQQZy|8seve_c9Zwrk&C?XT#f;)Ju| zFuHXE-J`EG9Xtjbx$0Nc=jbl*?3A=0Sn=;vcHflAis=1i{F;rgmC36&x&7W>&oAE^ z`JH8-mB-p0HhA}%<;{gWbZ@P9A8}h{6dQPKVBxekhF+aad{k9Gtt)~~*~Xq>Vq)F3%* z&>y@4+dda%BW~HV+V;8FYJASQ*zNtpu6l2F)iy8ce?~|Y?{JIb#a82Uc(L328@{=G z#r(96+x`5)#CNFNvp1itr>3-&wCy*F4wfMap%kq`=kc)kEByTfc0Qb}_(xno4ZbiY z$%Qj2C%o4G^PdlYzx?Nc8U~Z1z_UzpF`**xEdf$%U>cXN0VEJ4C#~TFfGnZLfdtM4 z(1yuDe+>R0j8DW6OfaI*f(wSBYu11`QUpF>#uddJB?p5UQB405epCnf?SU~13}&eg zu&)SHm}U^40|@Z9B{JzBV0L1#*|M2{IZr0RX*y?s(aGgIg{5U6?Q(}AC?M)<4pbBM z-T5H^25mLh$z%X#U_pY-i}TZFQV=*Tgu2AVe>s?9!dxN}JWM*AF4zh{q|$=a*g7IV zjuOd~&LGC{GFIaF*7tn&OuMbIE z31_!e++LC~Bn8ZAuF}~^*yu3JnWw_Mfr}=?1#(|lo}_>|TwTC|hd|4SE)RpbM650? z1L|Y2zZ`;f*&^jglEm%UOf5FbbgLM&c6%jhvEnSbg z-{rIa-9#AtH@EeD2hL!=z4l`Zf6qC5{+$5DIQ4UQnxAve7(X9?k>~C*$uviKr>h-7 zj+uR7zj&7al(4#IeYYjF|E&BLc%Hw}We;*@zI@t2uqyPLASr_5Lk3~IecX`pJLq}YUp^mAOP`5}Ld}e9Se^XRizclGl zBt1GzM4j;HaK9($6bm{Q)GgmH5`cK=kf6PU!H&Qo6+Yl(>_5q&vPe}hdP5|~O%)~QOE zZl0#j%nz=h6eV5IApWl|XXU4JA;4987nUlhj z4n~_Q>nwC#W}Stbf1`};`uSktF32)wP$wB>96w+)L&`C0fL{680)%jJ|<+(8D?&!<&2N zy6D>FcWrN1C;WEr*Y{LJ;C62X+|HwFbJX$jF^9eFM_;SFe>WZEExsYGk*V@N-UdAy zDzJ5MOVWDHATOi7?4;RB!fqoOt@0J0P)=z4%?(54EyqvG8zoj%JFs*ggZ-B$Wsjn0 zBMcN$_!=Qa_&6c04#R>V31Lyc76wopSZ+ z?0KNZU?V|vf1G_gFJWmUq_)epHB_j*nZ?~#J(Q(ZRzWeykP0Z^=;>V z9)GQJIpa||@&>J#!R)|wxvCo}cwKz#y$~2JyU~#gt$A0;2qk~tEav^4MX=ti>fC`# zrjN9N^RKVkTgBFAJmV}WuDSgZ(DO@>yovYby|>rcc@Ome12D=#S_)-uWOHzMM}!b?zXdgswayn zkrBaQoFrou(ocT|27iAUlV6?Uqvzhc;kVyk{`rF63+31#HS@#2{`~Ua|2F&s+SSMn z{IOF9*)MhL6r4;L*3QFTdW@ z;D@h&fsQ8l_#o|Q9T$2Ka`^iD%O4oi9DW4+SjGT8rVV2p+Zgmv2XKFeZvFl%UXGr;!f+&k|KEKTo+@7D z@5?Ly0e}Db!nql7UW^(zA}cgZqX6U$ys}QE9Feft@BArw?H8^+n_HXHDu8#ilk>EW z-oiWSzwlbw2wey^>H*$!!|&m7*hx; zzU+Uv7eae9%f@GƊzv*h zMw2k>bDME~8d(5bUfb{_z>5z8^vb%>gj^Rs{q|zKU4Hq7zl;)qh)-gJ(M`P+X> z!Wi-4gn#BfwN5!LjLv5^U3fCWxw39VC*kn~@pUmo3MFeMQZiXx3CWXn7$+xLu5l9A zrTyE>-%u#HVg3(g!SZ>MA|9p4QxZHS!BZ0aKad3fwPE!IOJcHhzywjboy5Rqg8{+J z`DJ8QbFU?r@ZHxx4S)C|CacE)HH3eaO6ASJ-c0C?J|LF|YVA{#iNMpHkq50#Dj0YU)g$0nq1NsYr zSdUE3wi|w}=CAFjgoI_lL$l{48n7+|_Y_`Rf%iiNc)4~0M$9|5xNef>NH%{{AzMKI z*BfWy2}%iOim5^NSH|ZMtvFHGvoNYVoZ@+{v~X8-03 zoQ(jF#)@8?g(5xJ(HWHgcbl*pDPAoZS&lPgvUe#3*a0-JpgqpgI~f@imEl_>yV^9G zKy9IzNESaYXyq-lP3Bf#3PgYM)fQQI<*R(;NK9KHW^_809PfMoQtFc7WlxfZYr&G)M=o|y_q4ww2=TY8mU&P66U*rcc zgbs|HQ|#@npgB_<9LH|14>T_*9gJ~mg5QykPV1OnHC|`cw~tM0tRmHeUZtaGx|nm% zt_ehi!l7F#)taj1=AvRqEtA@c>2@%6l!m#%5}CJYOdN3;wH1E}loiXf*V?{dL;S#U zw%1-y=QgL`F+Ojibls?FD*b(fzA%Ja!I4VTp0;1M?xz#p` zQ$wTKU_UCAm|#tD;b<&{D&C4lzaBH}HFG+gaIUlbO&R23XwFja{(>U>ek!<$TyLbB zQo9)%yrW`1&5TW+X=2|rVQyc@QnaIF43=DUTDl{k4ePt&I(7uU4#uo6b8BtJd)?Qn z&AuCPtlNJo{VTi%`F?tc5>QhUrpPLGQVKkBuM!*L`jWYo44<=W#lMM|=5W5zEGDR0 zokfG%ff1TtFS^)w$ve}{(L+sEOV-^3L}?>2UqPtiIbIij4{)9CC`vZnkHr*^8LZ3{ z7k1keZwmE_De-B^!)I#ajBRr<<@#w{OA%@BLb-n!*4-D*g*?4Zpmtbhf0I!~I3EtW z_AcZO5vMC6?lnInFzt^kB@M`>Nz!nuWHP)6Ga%4^^UCVHQw0t!P}N7dG*btN39^pc zGHJt27#&ur1_`5WK4S{pKx-WJJK;sQfUQs(8fInAJ1{1=rp_`=Nz3i>DhDr`tNHxK z?6Ky>!JEvIsZDEJ%ypsE`EHZ&MY;U`1m6A7mXspM{ zPr9swkC+EedUI6!BFeh&C8DbA+!=qgs~bbLEtvfop-uEw2Yw+V)Iq7gZtb=`_BU0g`;s9ZNJf6Cme;&b0@D0bnsHu^QmU6@&z3+d(WrcRSo zO!?7S&enrxeafW11pD_b)F@=*RX_FEv|?=A!1i@-`O8xpy=yt(s(T0VGXMY8>}*NmXXLxsVchE}gjaUUUFQM%VtsmB;cumyOP zHH$!6%iI<}MYb^T1a29zIWdxjBt~r}*2yuXcts^!)1i`j`&6mlE!Tf^-4LpJiZu;V znTFmy_UFChYW}1ntcVxuJbm_FXXx~O9+tA7!3!SK1SefOAmt~$*&Vt2soeDHVPLM* z2m^wSt+VFSWq-Qt`*!ZrWq-Qte|oy?PnTUQUCBv2UG}HT{&d-&E_)}^PnZ4avOm%} z?mqKR&n3sbGx;uwCWC)B-HX;~vDyxg{*%-{gJ-*YixpONczUc)kM-%XK0Vf_$NKbG zPkF4GRW|xQJ=Ukk`t(?z9_!O%eR`}vqsQu2_RjpjM;|#bc?r4gbLtxA`rJA7nLK@u zx6i4=6FxqXpU93}8c$?{7E}s2y--E#Npf=7J5Uo=h|-*u_sf4q@bKt5SQ}+JIyvl} zgV%8^eiJ@rrCAkuII=xqhV_670Br@pTXBkBja*m*S}(`FzqsGXu!p6I*KEjHq;E%aUAUMGKI9c7)f6rOc@SIAdBSTWq- zBCO(s3?^78{Rv+M*84qa+8@6y@Sa*tm6oYCAEZ< z2}oGTYs6FcbC&^nXjMQ^HDMG`oZ6;xTq`A@ZGt6IYia;EB0ZD07P=>$#~I4Nh?AKB zobtzlSjjUBI~}M+if0>#`5!Dwh7|?#7FttGQ15>gq=YssD<>=G^08Qg6&zcp-Q149 ztEJ3ru8zxY0maeI7ID%&-AJ?zjSz<(S3Eo}0+3U+TC8A;z+!FO*BNL9ZOXt8e6Mcs z^FFsBlK4HogK})Da?3+MeE$6q^1^a3izn10aDBKKMsPvGPh-B#HGYpxf&gZ7^BlyU z`v8Bj{?Oyz&5wKYF~cYc+(<|DWv)*g=g1Q}tNA+y?_eRniScxpBQZ1PG=( z9vn+x>qEtIyVMa5Ye3xQ;ZxS(UjnF&9~ID_e&qZfmNmv7wbAeNyqL)}kqw_WfhDJ( z1`5)sWy)7f`VgOY?j?xFIkfW{ngG)??OT5Y*h74p@At4qdBO{CB|k*O4-*0_FRnQC zkw9xY_d)i7%$>xAURZG{vAuk6L+R~67S5CJn&M*eqNgd-`VhQU9eUgcIs9st84hfQ z>^Gri1DXi_YnX-UrzL5$Tu|_bggvk-g(*nmX-Obi-_x!}Ev+1|B$@pD1I+mflt?|r&s*06bb#=#pS z&Q{9VFR6L#p3(gfkLU7Sh)07H!AXBKAFt>G*&&R`pT2Svp{?CS7(!fl6QL5Im`H|> z26+NW`BYk1YDJhTzY7q2TCHf9hr-B<=nqf}c*b*2VxdLMryaRzV7C*^TIb^En3by- zYm|!-)SB)h0=fFbbckM ze*FUN&#!_|E&C-t$k4Q;$*CHb^)yvf2)d#WUKf7N?~+?n>B#gz2Pv2G=kqU%X|=sN z-1oa>w0Yg(YPIAj-|ZUG;*w&@j}D_+DeR346VI~gxfJ=~8%)oZp6(s5Zhzgm*6|xn zOoD3gSsnLdmjm_6i{c8Ra$kR5UUsKR+PG!ViL4q=_f4k_yE|LJ`K8|1FUsu|@W-cb zpMmSURgNjPR+*HVZN70ATkd$By;)I}x1r_y)Y>z%dBs`NRB06Y?Y#d{#yldMR7}u9 zENY-l_royZ&bc2_b1P#eROt9P2FHB<^l|rN-O!UHcD2DRP7N!&nM;38?j#4Mw{cB( zSkocbt-uf#g84E9zG6w9*v4|Le3m#_uz(FKchg-+PS>*MkMN&TzAId*!pEfC(Vad| zumn0Vr<^G^_E+}^#2u9@sBGk(NoI*DuvfmsFr#+MmlVZ;w?h`3%7tQY-`%cpuk32+ z*g?NpE48_msd5eGg^Pbe&lHq6YbR^Yx9(D?UCVm*p7MUZU)@?nohJ;(>(qX!-0XVh zc+Ms#?8O8OuiamDqajzi?YtL03RSH-_eRt)uVjAJPN)=nUzs((U8A?~Os9cWS>>O; zdAK89efN6bpIx1(^Nh~*8VUWhe=^s>WXS*Bf^ZKnbb7bj?Js{AG1u>=?k@oI(C9Sr_|BrthJ-V!fPunwROS(tZ%Z>Fb z)84I|c<;^D*Uy`W!_su|&|2S%$C-N^%Nc6waY*Xs*l}73G1uMNkat=Vo)zxbWpL|K zozr&URi$}Gv7Nmh{agm%Gabm@;C;0y_UT~4_jBWV_xVtR=`MEE25WZPRl2Wr`8~g~@;=RT*b$Af!e*xdG*=m;|l?4-*@pl9# z1T;4`Gnb*a0^EOQbc&)jjmNa*&x~Ki-<`OAc(YcM^5&AW>5?EPS9|~VBiU|wc|=i5 zhCbhX6s2~L>c{rTAMo#=cUp&y>=N8XQ)i8b84Wrg@W?Qw-AJ)iZ@m(aeW$b5X~V;Z zRyA-PpKP`2mLn>X|Hor{5LFnp`Ae`SUw-6kQHKf=h$GWWX|xR3c27>p@!odV;RFmriV4|hWc!vX95+B7Jg0dAHczX*0oOCqyL7Tl|Qw5EetEE79kW^QM&1PH2ZPolFusB*>~9@}zA-oekay zyA%xObHjWDv3ct=Z1>kYQ5XO;ptyosDPh6U-O)T@+55m%RXOn>bfDu!bcZl+O_Uuc z43~k`#wvp1Hwpk3p-RF~x0XsLjHIZ>Yvv&o@?L+02@8~Su~_|9eABk;*E``Ey|D10 zR;O?^Zd_MCZBE(69KPFoBb;3HdyIyzATemFA`zm+@TwXQx<1?nVz-SLuib`YZ2xfg zcZv$>Qvai1(5_1u$rMIDL&0Y#_zVUA38COmS7;w|3DAgOGfWN2slSd)P+wXEao)`l z#Cf-fx&jgb0^V(xoVx<)e{t{2pD({NuDo=KTM9HlHN!qJjE-1(O;h2A`VQ&)m%xog z=vXTa9#jkPYoG65A{T%gTWBw}8r%~XNWBJUEIhHboF1o>h4t7(P4T z4ZeR|S`KAtaHZwpX32XOdI1$m0lOJTW2?ER)jRLYQN>{;Hsfl%LnCl|=U=N{{&A;i z#gjF99X#R^iv1`sf2S(;+A#+#QcP2j0$5f$5f(NyK`+dc+qA(CFh}bq9}(Vk@(9~d zA5cr{X@i24@%N~lpz=C5VX|?x*@_Tf$Qb?^E3$^sw2;H*bsXh@K!;iRQ9Yo%8Ljdp zhoQI8h|E%AV47lE6g`tz)j)Zcv8Jh4i3LnCN?{HfZG?aoe`d6p-i9 zl8U(+7gUhme;nB6L+n2xv;VN~L=cFiTrF*)!>CtNeI^EsD{>s!u!)FFUK=T*iJAK1 zWmg!Bz02iU#==lTe-_bf%fVt0k2ZqEP0U9@NP`Iygaz(cYh<|txMxDaQj&WXz$l|5 zzBqbcup&%X5JQlqYfwDd6fGL)7MVopwi7}NU+A6NfB8rAob&rS!0gPW{*O2pEtqCx zP^L0@Qk0ozPe1TnAhOGx)T=UYGkyl`T8^9_4V)KjE6n z&?oKed9HPt$GSI%z8hc5)SW)uo~^rqbfSGaz#r=`VdZ%$_fq93?Nj|+r+ui;DAetI zeTL*Kf6oJlM<{E!-sd4R?bK1Bev%9%i{sr$^htQB?~$)9?{!@XTuj~jZ|2@Xsg#mJ zDQUCR?28udg-S|`h^UbERSPDSic(0OcKER|tNeTk*Xu1BHKw!yK>L?Rr&_@!1W1r5R(@swaN@ z`YNFG{8ta2-s7h-P51d-&y`KQ+RTJ!IXhOU`o!jb?EG|vU$c{M5fSG3JZsj_%U9(T zLR6^45d2rJuEX22J&5oCCAH0X98RK(5FB-AD zA-8YNvdR^go8;_n>BuNY4gK}dQSa-ZP4yaS8cnv#E~$R{W@_>F6u(3N(|)hMiDq5q zLv9Xovv07A*s!8-QCjWbHN&F&j)K4GlfRtqnX>Du!VB&V`yuMi-AGA5;= zA+mjoY-;Au8EIu0+kN}}uuCnUI!ss1(bL{IcU;X<{gtm2tmf}MUbN80By5Czyxj+z z!h#QDw+udi({IdpHwOhI_#W`4HJZ0nFW0N@pJVRyD+B<2A}!Uo`;Nn z)Z^@!XS^~)0^p!x@sOP!vBx}@x@_$tJ8ZuSrg?Sm-*R zBs**BP?ijS>-~h|BzcRzda7Xz|H-JjZNm zvpvvK-Errhy}H+eLnk!sI!YNHF=H}z-tq%wJLmip-O|aaClzDYjv9nV?i#Ph=bcZi zOTKZ5io3Gq`zC9ocSQ%PNBNJlI5czIl9ne&7hYMaR_mOnLv~s0%hbusFm%$_y*bG` zd{62YhOGxg$HXPdB;ijIw^=6l3Im;NZOdIyarIL-$^2_4e$ty~oFqtX0lgrpK zmfj<$cvG!IU-n;wk2=CR8f2;Ta@)bBie;@#?b%kDcA+-Ofi1~xn?mnf;9e(nI7q#T zY{uu*|EgKEeMwfNe6Xr__7I9{mCVo}iXF)vcYG@tJFNQ1wPo)ro)2Hu+f~}I^Fp}C z=b|L_z@WYl&pcOs``mota?Q=VJ{p~iQum+qf7q&Edb9HLvE?YqOK#QJWn9wo5u@%m zYs~i5s(ryqzG)NPTKkq$=6}p|bR}lc8kD1a^)BD?=iTfjUV7sVr@b!Ra>KI3nx+$d zS=s5(4d#Z&w%Pc``hcx_zWkTX_iH#hOD+oB6;e^ z9^nTor94Sj`ehfZ^7NtXQnwQ|B~F$H=<6F=!gvd|`@1AHf2_%lr|vC^YgG3u-28Oi zmc-1H{!M&c^+}_*Tn%2+u}&`p{nlSFUc3nY>MPn%Vqu zpZBE{U08dDl^y!@zTCC!XzLbF!-)?ZyjJK^!s$!hWTz*kp8oIk!)GDvdGEl4r2@11!lJbqK^h_|Pn z$t^Een)l{fP3OtzVK4F{8%<58n;x1IGAcj#q)s!#Tjv4)`)$}1A5-=FxwELKqVW_5XocCqU@myWY%G=pqL-@T~r9yFT9Nq>@m z^l(b#RnybOr)i87mA$ma8&AG?F^*8ysp&8*Uw*sOG;6S5$f^0?*Yr5$_nmssmN+7Q zeM!}cZD04aj61q|aBrT;?|7L5n)|XxpWp_1KJx#aS|gL^;dgS%YSm=zQA+E2C=0dD zu1dR_-=2V>+}q@N`Ubj&H#?Fj(Zvh>ZWqu~uz7{~JD!rQWdhu9g+;IPHl6H8uTL*P z%6G_W{Ei3Kujue2Oc(c4OP}}_&U*UVpfWbla1Yd&*1&Ii;MvS(?V zjj~$n+BUX+ugjB5V`SsX6m(wj5yRMnOSkG#!qy3I~29u}dT<6|MId=Z|&o#T5p83I! zMiWB=wU2q(Qa8=N!I&0hnwr)be9-K%(M;CnujtdyKe_OI@AQ_@rem0IL+0gLdEb0C=llH2buL{aYAT&l@cC!SCud$?s#$ z{K!SJ_sLHDsaqzljY*ytb0qTW=V|Mf8wcFdc(HEDe#+$3#fNWBF_eL?b(ywG%kk+0 z`YbPN(vTxJLyc5x>kSu54^bMpN3!R|%-? zK6xbnL;HWTJu|At9zBw?vi#6xdTecpOS4nlg`8PQt6uASeSdH-!|Qz~zC7V18<)}b zuI#&v?VOhW%(AN|;L9?n?azV^Gc-SUszsX>#1`s>dvI5NXV#4U=>590WX$gvhdBE$ zaRvA9U|8JDpRE&`BESE5{kcW{o#J_Oo7mg(&1>iJ<0}0Q#)})lhu%|@2(3* zAwSRTDVXZIzSEOyc`%z^ui2UzztPTo&N_BfS!GXr;HO(QS?<3*hlSkJeRE}Ysnflk zn<`^i7OxA-qqV+9R?RsWXg+q{#PY*4U#Yh>BGd_ zf!fd0KTXN|vcIUxbk_K#@)vqoSuOv~OZO`B-uSJxa)Mnle>}g(m`q8d(dnWS2j;cu&PwO)9`6}$K#HkE=s{m507W&t+m1X^e)ENTDHo!w$Hsm zQg<3rT3b{UKk4JsLkpcJbjvW>BWOk!!pqL6?er@jGjoUYCj*-Rdygyd>*(c&viH6E z9M!WhKc3nZ8uT-0Vn(i_=I!JBq`u{G_Y3DfLdoa!HM-1aJT=TI>1m9(NSWvPj`nSW zM@RhU@mFX&E*+~np|>bp|6JH{A6{)CO>WiId)|yq$Q!Vw1|g?&*!&<1^zX2PMxn9(Ap6n(ML0<@HL{{Id-9 zGlTng*K*e{h?JeZTXC@Ne0vjovo87Fr#)XxzV4~2VfN})(~K{6scaecxw{4{Pn@>t z)p$L-j{;XOd3&o0KTQ>Fo;p))7O&*Wd35A<^5lyb$KwhMW2!^_uN4%&B0nz4HCD6E zQr_K`ovpb^;1_gLhj(i?LnFdcZN@hKhFHav@T0qT=47q7aB-1ha|!Rxnl(D7+uACO z2G2GPNtoiMxx-uWA)~o?P3`NdH9CVV`p#9p9#w60M(>@`^!<-q})y=CUgr(+&DwCHus?Os-zsJ`}|MZDkORj-4s4tO>Tb6i+sWLS^S-;ddqr4oZ^i3~pXV;sjxaE}*<;cYG;@Jj)c0{u@6`LACPf{r zyud5_biM6OFULNt`62g4`?Gt;R-BH0UiZ_XR>1d4HT_n4)_S*I&KrSVRc@a%%DK9J z#IvOJrH_I?U2Z)=f1LSPIWVrMw%d1jxS*;dU0}VEocjVFj#?*BPd$F}IzH?;I^8mF z<(Hr8HV%HDUJt(cZgtGW`3|0*Z}&dPQLC77?J{pv+?RNVwu#jJ9w*utPnGSsV=kLt z{(MK;83X?Ache5$I$1l%F?Oi?$8g)<-v9J$lhcwCZ-=(UF;x`P?|QTDIb4iRuWp-j zW$qZx=*QbPzxSJLW7tLA_ifL+`m0?PIYnE&E359>AEC1J0-_hx9&OwHu*#h|=lSuu z$_onX%gY;$Z^X?Ao!?a-)8f2&&X$kgeQ5hV%L>1A*w3B9kL^Y{!5BbaY+&vO;x_asD6B^UK7TjBWCG+P&!{SA>)RZ-v+DFeXSTW?= z%UKt`$UMDs%wpyD=aa9ew!JueXUVCMU$<;qy8{yv)1%WKzB+X{@S8%=XNqobR^FXd zqxFiu+m*+yd=h!*8R_E1j9oKAuO_*xN3FE`_OeRRzc|YN0?p}^uW!=m?flzkzh%D~ zd36K-^?#}9iz17^M-IF7i(5Lir@im?^1(4hIp5d3Fj&!;TkNH%a<5Bn=tjn=_og0o zvn<+wSbyB|>bjL$1$FOXQ|ASCAH2gy-!H!8ho2a`eBO^uuZGTVjCgT|$FQz@?SmFNq;m{gEUzYiPwmv1Pl^1wLFT7RUGvn>ObWmFVei{-8hfuMX~uhve;4~C z$@dGRr6#wy;q_{}wf4iCc6b?(h8-Ab(Y7cdG5qU;7N5cKTCtu+uY!xC7xcXw+P1R2 zh40(vVqfw|k$sk5#d>eR2+Xf`o3kw;=49T{$643Y-;ew6an?QGg9f9rf2=E4?JP~^ zG%i}Oaaz^vEu~HEE_wB-sz2YV-oLn}q1W6iCb20nI46GMtL=~bcD>sEDyj9vsEo5~ zqZR#LE_>fqblK5_r|{GM;=SIguFqTdu1+2G^vEF1_`1n?oRMWsuD0e|cl=7$y^~lo z%H7xa%WraIlR1$M(?V}=VPp7o8l5)aHEPY4uom{G#|w6Mk^&Q|WiBS)U;F*6PK||M z@KE`e$#K7jWp6q-beiVI;d*ng-_p*UoR{(Zblb~u^-evd=f8AfqpF&>Y1?GqY~I;6 zbE?bd&dtH|Xsew+_cXl9U2vHHHaaJ>{P%3ECdvQ6#>2n9{^UnDpX>YD^{JateC}t9 zrF*(ZnyU}?{h?Xy=Nn(vXeO>QUwQUp{p`{OlXorV?^`5i9ir@i z%;dkLRlht|?m5HLoRt}2tR9)W)5mA7-yKq3j>p3$O|7Z(^WRM!8E=-dQISuM);(w^ zv-jb-a0fF1b<&G+s#C1WPFv2#<(*2Ieiw~sVVUuY3xoHSo!tCPSxJucD)&aIidMVR zUR}R^@*K}=o|Ed51N)+5{BoEVL)4@8VsB+&8&6ADH6m?CymQF0JcYHi`aQf}IXB9t& zyD=gLzqmEIenkGy)w|kf#~;q{-rccrGyRd{tHEjc+AKNmO#No(y^fAE156b+gr!;E z%I2`I92s46#B91fW2o3rvimYaKmOq`%1lPxEv!Zs#)axBU2J zGS`k498Y%~G{s)0Zr`p+o75DZ)N2NHCz^DbHO#Tjbv>naLgmdgXT4b)$;#Wy8LEC(QZIxMiM!#;(*kL%Db7PTONO_qL+R=AMW3 z%b)D4gO~rGp0!Eb=Qhbh)l)es-6`mL?U$}Z``kg#vnugE3)%KtPw&&WhFo(sE?%TT z`m)ij#IC2ghv)Fg?XG}_4 zr^E@;vA$sROpBA#Zd)G5X)@V;$ZTH1wO0`%7A`gAoBM{PojQ0iy<_@;=+kE$cP)uB zQ7W@7l*eU8Pjx(dU{4-<{(_W7`;+=Di>xnesutb7Z|`X~zAD+##N2GH(#*J_4~GYg zn)xYV)$v`7yy%Y7)Dr8L!<#Gzr=-oea%=bUyttt=>UKAukMZNby){(6PFGImUAw|0=6BKiHsPN=C*FFUpo9KaaL8Gl-k9Dk+OS>I#$eaG3h`QdO_cL*W}r zugv^v{cxCLFDbV{q1ESfL(?jQjR{zyUeWX+?is7sm^~c&Uve7%==~$(ZO+X;7C1GE zD@)ORrhnv?<=T*=Gq$~#vy!8>J@}+tuyev$-PFoVoq*v7Z+VPaAXCJtDdm>P82o(k z%&uGDil%svW4^l>Gw8(Y2U;&l=hq3eP7d`$C9J(+vd1I7s~0t0R+!tfe*WsmneXGDIr`GFaCN*ou+DoAZsC7j-_Q|Xy#HQ9hcUIr zw4>EkF5-B^lNr+z{7kHQJ?>XdUy`|UKf$xbJ^OUWv+nCZtv`nCevqyZ#jm`#Hp4w_ zgnx~;-m~ioL*1@BI)p`%Uq88cI_sHT;Na^mVTDoVlUj!vp4`)>bnFZN6 z9$7v@>$FVy$-206XDdBMCL~OMy`R#2%QG%TIse(4iLPfkp%bDm3bco}OkTcqG57cI z`hb+}(YwN5y*nK5pmJ)#2>$P=hPjjY*YZ1&+^STCttShy)r9a=YtNm1v6L`?uy56h--0cZ$0m( zfAxOnuDvoZAD(V4+|*t1AtL(bkX;iuu0fdm9_#G7HQO#!Ew+pr(=;<|c<+tp>xcI~ z;kSluIK?k?G-|W?+#vVWt8DrSh4&9WrFJY0E7^PgO=@uXkZWz6!SA9LZ?+iuW$lYB zMV#Ba$jfR+)Gz&Ds~sO@Xg$L_?|QZ6{urShZvCd}p3;e|o0nfZBw5DF9ISa{GAwgk ze$dsO)v5USfYnaTg^Ir>^fFpcaN;S0wg%_8%JBKs1+l*m*Cw_9I2JO(o7?25@BNH9 zx~xfGrRHkOcooYJ%F|iH*X6jLNIJ!uKu_QLb=J9(*Y6U?-_q*LJe;k5DQ$~`-Roi{ z&o_M)8oy`XRh_UUEG{VW``gB_u7fhpoF8P=JNv$K>iK6|uU0*@Znzj{r5Nz|^UD4mAW7vnI;T5aj9nBZW9zA1PZs!{r zJAK*Ft<&nSMjfsGF!bB5*6wTeW7I!{EnuH6KNdb^yUy-)FUox$Od<(RwJh5EpK&;~ z^U1H#DZgdjo_TZx;xg{&ZI zTL+_SvyoLd*`&XHwy=H1|KC1`X#Xtw@R@8TYUAJWafNd|`bB!KY@YZ@6LjqzSr%3G zlBcQ&$N#UoI5eV((X9V>2pmCK7kLbcn1(F;6gX(c_`66m=*U;;o;gfnb;gs34&{f) znb;G*Ez3eT-;s^`9~Dj-Ie(XaluIQBt%_EDCun91Kf-&y zsI;4`LFRCX#eIr%wK?2>I^)6g#-h{RvDo#`hOh5l+H% zNgOl_$Ht-QBut46i%3*Q5hTn|d{Of6#aj}lP27QJMj%}>riPCFBCDa9WK0|B5T!L_ zYz$Evfli7`on*{j)TcFuF+}Bc7-kD)VO!5JY@$d$9>*s2k4szrA8j#EGmdGGr4ef( zXJQ)|4ZDvkT$z6=F$Jm=%!W;3p=0v6D)L(iLrgKniUteU&cXt@m||LJl_o`*%w-7{ zn1MD>KvddzXFbN zL#JUhGU7~w2bz9iYz%Fm(cg+9G9%-Q(03PXf}m<9HWx#iXF{c^?${&@jdX`fn?11@ z6zT~=6EExz2@Uar;)FR^HyL4bpxED)#yreOaMBlZB%@qkkm~tidolED0cL>S`(uyM z6@L)+1YkvEbS(gi)l0C2BviNr#_AY^dBP41!i-Q=JfeknBq8Sz zcwl@O7Ko#tq1aHgMix&%8Bv%jni7i7LJHAP+8K(^L{UWPRWufd?nPrNC@KbvM+;)$ zi67g*PRur8ifC*swiLZ4WSe5KSkz9#4UtJ4b_flLgQ5P8!@i^YL`f$eX8mnBbbK}* z%OH^$$Tkt1k7});etjZVi}obKz2iyP781%zg61maaXA4PfEfv_LHQ{*lEf}3plBl3 z!}uh@uT|JC3ZL6=OG{WZjy6}g*X2y$f~U;!)7;;7U9UmMvU~$H5}*i3h@_!j*U=Y=$3I+=L{ZrE#=0q0{#u|nO>i%=jhPVm~B zZ4F%wL*<*XOtfk<)c4QFmLRiyD0Sy!`KUf0s+1I9=_tJb8lHK>FV<{0#-^uWRAkdVtcSktf7*cNoF8lFF0gS{rfmk5a0O;Z5AY#0e87vl`gquUTy zBAwA~KXA`d`%qZ)T2p^XngvkZo@*6QybhF@dW!$`gap)qC`*p zl;GD>Y#q)QX_W!487B8fI}94=zaL?O|7U>Xq5*pE*BpazJ!cbXOy8MnVlxM04I?(TM&A>h`?B za?v%SBvhy1EvPf)EoO+Ey0DdKd>1J8Ll<^~L}LH7@@Rq62dsoNA3Q|==!lp`>!(IA zD;gCP#}yehjSdRvM}@>aa8@*~XvQ=KD2^+dF|qGyT;Ys`)>z&3#~P8}M;JapySpT0 z(gR}yJBdJ(K7$aT-E9)O{27J`&67v(omU#3$TH2wVB*3JzB zv(JalI(zYo!qu~3tf_8p6C}_uAfR_>ww`Ps!l%lbUAu z#rh7v^KrquLRDXrut&o^Xa5S^G4|uFXTj&!T+WTXa3`s(f!7}VsbzDWFN`o^G{2H1d53{e2$2q8cI9SR%6}$kY zs=%ou;B0wxV-seBE~tQA0UDr@P^v0!NJM{I5<0I2MTq|2$Y}mZs7k;NKApw-_w2-X zL&LH&&XK6nO@*!Wkv7Z)yb8u`A=_E6bQZYUtu)X@dqnuHUPGtJ&<@0~s zKUZ!)_{rGTdPOYzp&=OzFMl&UBCK)g91qfmnf1oC zrDX|jaW$rw+N${0rH%N1J;(N*s^s>jGPcU3G_wrH9J&?!zV(~NYJ--O9-Hqie7vc1 zW_QJuH2Oum9riwJvfk)@YjwIZL1)>)t@{@*y;J?jCQg3uk9X!q%lE17QDqgcyVgtT zex}p2y6@Ar__3@5`q9%K1vIWg-{wucl+!&y;PL!o(!+7vjn|JItZ;8o_`TS>c3vy0 zgQF7Au|`}4ebvIt$y6aK8u7=bMxxfScqrQCN=ZXsbMVDPDH**j!ej*(bnpoz!4o&i z5a55C@T&))NGdoC(d)V%Ztp2_M+|Mc7^(x3qKlC_I5WB!r~^Ksi*Y(Y61o_s10tdK zgLI*fIt7bM_}l$xlm@IS;1EwTS~Cik9l!_R!2_C51Rpe&Os3O>A0Hw>hYAVJGr$c9 z(9ujr4~^hS038!a2%Cf(5uoESnrcim$H9F_=l~Tr;q z?HiSbr;I!H(x#|~v_XB;q4BeZ4E=R3eb=Eoc69owH_USDUVN;lI*~ z>pi>w)Q%%RYe^LunMFp9Zx7xM_HWxtT3vd4rJhmgkFy4i3ohOZfe)mP$p}r`$bD$P zD>x>1(%L<$n~pnaEcp!yj<0_J>_p0;A zDhKH7uqpTnBHjTE6B&vShye)q3!|u^EyZ}b;ENf)i;R*FVTOX5sdzYvFQ!ujB%_Pz z6am8MVmd{@E;!fx;~)swMHka40(Q~Gbc%pobTOSGU>BVxiq{0{qW7~Yu`5B3Y51gm z(`jXb7uafzdm{!LtO9_R5+ouxU;qHLMv~BJE))T1y&w_f+JFFBW65Z}HAJeTiP#td zVkwbOw>8uPh;@yO4DIjJ;_K1p8Bhm+ zl@1BLb^&2%Fhy68FdJ_mk>~@J3V`Yb&KGk(0!-1x+>ZcLbTRiMz!Y7~{Rl8c7jr)X zOws$fAAy2c#B*Y#1MrDX7io?G@QF?r!!C#h(26KP5b%lqmkI%VqW|SW0GR0gWJtJC z)m=p!wO|&`Mq_<(e`MkY^X^X$J#&M7+MgVnG#iS5Ae@Md27GI~!M_;d@MOiIxE%^u3{3%^IDl${;7Q1%d__LX z;33%vdW|a^t%lwqPTP^tgcPXNAE!G~Kw6)L|0a=` ze|Cg$O@#3%S&)!}-=y$?Wd8x{FmEw5h8-fNd!T;0nC$^Ur;EuRJWCgIJ)jwMG1UVm z0odSA%S4b86Fnf_bTQAfW;?@`XavB#>0*`#%$wd%@?f(Ok&P`1hD2mzi<}z~+4_l* zaKo%i6>XTxH8A=9$flA3_SzrW_?b{Vw-w%lM|-lM!k-|=5wZ><$PFi6>}59wl(K~P?LKgk%-9gi(gxrHyB4vqbF?`mlG7)pgIy*~;453}HL zi4dTMk~JyAgimbJq?|?<8gU~*j25Mxq)G3mBLhxC2pb2t1KAs$CfKnMV1}VkE@cZD zcnYLWwNS7QWqiLMJ*h(hbQ+{dfo%VB$mlS}Q{WVVfD~v(7d+OkM+qZQ(QYF5ay^Ek zh}P&+g3t^d_~5&c(0E{7yAB0rEnmVw$PO_61A_#H3ai$ z6o)~4aT-M%&fi4tl>-+duLWL|Fv@<%3tp5V#_*8VVTdt2SSdq{;lXh-#EEurl?-v7 z9b6?tj0?dbj$riT!haW)A;j@U$d5}ofC>yL1_EOqWfK{Fp8zv|X-WwqqZnf-CRk9$ zlVM7P9}rx$q|7EGHW%bpHk3tVG>8Yq20Mx|EC8fw1lkT1EeyF?K*k0#(8B~V(3lJOU-LfVn>7pnr|W&FjeU{4Hj=AZDH3~}b4@R?%$Mds5f^2o=V;)V9lfVn;JrntZ%ofDYX4NZKQVE$an zXcC&`0=IV0qfCM%k15;|=ui{|*aC_J8O`(tOKT8dT7u|>lo2F!+#8ftx`?8PA;Y=w zR7W5oO`Hc(oh4x7=-PZ}01gEd(Z!{d#c0|>xD1V@D5HQN${Lih2rePjGfbepi~`4z zX9Fol0szHRNT_%wB@F%YfOCQIp%fOG!TqaoWcd^uEZ7)I`2^WUQNSi_lkpeL0zzi| zMYEtShB&QHI84T0Fbg4{@fXYjLT3EU?1RH(h*SH7!(@na`-H=UD^YYJ5Hdpy2niR- z5CcNOMKbyUp>Rz;EFQ2Xxl2I_TVgSJWE(^AN0WjGON^n!qt`?Ul!cI8Fz9wt97P^D zY6$3M|8j~Q@(HD=6FXQPeRvQ07#B~8AQ_6WC6Os)h_NM+8)S&FCFBML6Qe1LB*B$L z%47`fkAV?ruA(#{yIAN*l~3UULyn`EqKst9H^f~IUAjiWQv6y?VWZc}DH{F#g5{eD zcBfF}aRZSa2q?@DpD_?Pl_5T40Gx`>Bv7WJ+-vw=v?GyXgxWGFchHxW6oUf~GbxZ> z{7P0vziZ)abJ{xi^ya_$e&XyhM{r{uY(_y!Hl-ayN75;>8caJ_+J4wKz;*NkT490~ z%}9oxApN=?y-cSVVZeaU<4nqE{^IGc?8$-kmTEtD2aT1@BWB+6ec;rn3)_m|e~ z@z)P@PH1`@?O?HbMWh!FLbIYyLfP_Lqj4?+4^r(a5gM=oBXn&XoTatodT7*rKRa>&V@(09m=@8_3_N1 z9{QEd$0kOHxm_+DQU7emhc7m?3)cCcvA&+rKH&%EMa~{%Mo{2=nkTo;8Z4$js_P}#?OYsOYlX+ zKkYDWIpQzSNTHV-AY-t(gwGlvV=_6!J{%xp0S00rKD5kd(+S8k;4T}26U3l_GB%Ic zh67|Ah7i3Eka4Nf?QuCQsS)s)FgIwA2TzNp1l@9o&Gc`B5WlEIa2p^av_VI6w@^$W zkB_zx`k@lQ|KCbfDje#9-;$6qBxeitSOmWDflW?aJ4YCN-D;8z~o44n#rRP$@GB@vZw@E`d0>- zbKy$~|H>euPzl`quMAe2NuVYP8JhrH5;Bfx>G&e`LnkaEE)A#%`Bup#frunT82{E| zFquNQHb4fa14JYpD1(Xv_b(rM;82M(y?-mhYY)Ps=m9bwoC^$m7`6aMcyu+O9vj?> z#B#!E152+L%%gLO{NaEG!HfuwDj{PKY;=H(2a1uHF&z7`h!l%Ny}$Os z|6~0O77vapBr0+t10>bB^mSS5bh+S9mtqcTNa{|q~n5m93s&) zaDYr9krC=&tbQOFlKvag^TIUkz=v6E;-qAtjLjrYNCwKd;4>vTd=Dw789YVW0}@P+U34d@?6B&BgcE5v(|1M4vWH%Q62lHmx>3TQ+&Z{V}c zKOqVXNvudFn@2N)=WS3@Ojn+31WNtzQxOCTCj4|9mK7KsL7{Uv2^wkFlF zG+u!-2G)QXL&G5B{DH22fiwuE&4dMhPSP*2z_Uno47M$~#w?cf24bB#?$P6kw1N4YC1WNUEO=?`le} zCmVvE~(Cd`IYpg+ql2GStpN}@J88{(VP!%Qi%1ofnYDBx5PS{EBDn?;of zM|>C!tf%A}vw{3ct}&a9R7HTU zlG~00@BTDW?nm zND8}h*gz--4v;u@VM%#$4u>lqp(wGz;Yx8;IHZAp0~>@qgYf8Y;6woaOLPqNU@uAn zX%0_ngurYh_AFR1l#sQrG?U2$Imv~yT9*`FCphZ9$%t*?obHQ^-Zac6J;?#9u z$8dTr=|#EHbd%0yGo=Q@=dz{o3YRU#L1A->au0ufKLAMSLG!3m+nD=5oDY`=7(tt= zKX4|XX~~)J2)c^giz#|=94e^}9=s$j*5x0F&V%=?CHF3{bg6AcKnm&hxKjHRHVbj& zJP`B{MkZ+hJV?4obqpD8$@Kzblwx7vilwkAkIfk{VPUN1aTroCkH_Ij83m6^yzem3 zP!{&Ay+akLyAiH?%BYH;YE6h{Rd|ToPM?b1rs3S zN#-XDvIxC0_yETw88oaCRm!!(#*qXBkXDmACIH#LIVE9A31ooqBnQZ4 z5)MhIfAMGln@EOK*d;tk*vw#qlajOrAQX~N2{I4^&Mac076yd`M#;ga*WH5>1Bufw dSveE8@NoEeIs@^_DP!dz@5YhS)3cjt|9>aPS&{$% diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b55b756..383c356 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -6,10 +6,17 @@ generator client { provider = "prisma-client-js" } +// 1. Define the possible roles +enum Role { + USER + ADMIN +} + model User { id String @id @default(uuid()) - name String? // Renamed from displayName for NextAuth compatibility + name String? email String @unique + role Role @default(USER) // 2. Add this line (Defaults to USER) emailVerified DateTime? image String? azureAdUserId String? @unique @@ -50,9 +57,9 @@ model Session { } model FileNode { - id String @id // Removed @default(uuid()) to allow manual assignment + id String @id name String - size BigInt? + size BigInt? // Preserved your BigInt size column isFolder Boolean @default(false) oneDriveId String? @unique path String @@ -64,7 +71,8 @@ model FileNode { owner User @relation(fields: [ownerId], references: [id]) parentId String? - parent FileNode? @relation("TreeHierarchy", fields: [parentId], references: [id]) + // Added onDelete: Cascade here to allow deleting folders and their children automatically + parent FileNode? @relation("TreeHierarchy", fields: [parentId], references: [id], onDelete: Cascade) children FileNode[] @relation("TreeHierarchy") createdAt DateTime @default(now()) diff --git a/src/app/dashboard/actions.ts b/src/app/dashboard/actions.ts index def547a..9edb37e 100644 --- a/src/app/dashboard/actions.ts +++ b/src/app/dashboard/actions.ts @@ -1,25 +1,116 @@ 'use server'; -import { prisma } from "@/lib/prisma"; + import { auth } from "@/auth"; +import { prisma } from "@/lib/prisma"; +import { revalidatePath } from "next/cache"; +import { getFreshAccessToken } from "@/lib/auth-utils"; +/** + * 1. FETCH: Get all file nodes + */ export async function getFileNodes() { - const session = await auth(); - - if (!session?.user?.id) { - return []; // Return empty if not logged in + try { + const nodes = await prisma.fileNode.findMany({ + orderBy: { + updatedAt: 'desc', + }, + }); + return nodes; + } catch (error) { + console.error("Error fetching file nodes:", error); + return []; } +} - const nodes = await prisma.fileNode.findMany({ - where: { - ownerId: session.user.id, // Only get THIS user's files - }, - orderBy: { - orderIndex: 'asc', - }, +/** + * 2. DELETE: Remove from OneDrive and Database + * Improved to ensure DB removal even if OneDrive API returns errors. + */ +export async function deleteFileAction(fileId: string) { + const session = await auth(); + if (!session?.user?.id) throw new Error("Unauthorized"); + + // 1. Find the node to check permissions + const node = await prisma.fileNode.findUnique({ + where: { id: fileId }, }); - return nodes.map(node => ({ - ...node, - size: node.size ? Number(node.size) : null, - })); + if (!node) { + // If not in DB, trigger a refresh anyway to clear the UI + revalidatePath("/dashboard"); + return { success: true, message: "Item already removed from database" }; + } + + // @ts-ignore - role added via auth callbacks + const isAdmin = session.user.role === "ADMIN"; + const isOwner = node.ownerId === session.user.id; + + if (!isAdmin && !isOwner) { + throw new Error("Permission Denied: You do not have authority to delete this item."); + } + + if (node.isFolder && !isAdmin) { + throw new Error("Security Restriction: Only Administrators can delete folders."); + } + + // 2. OneDrive Deletion Attempt + try { + const accessToken = await getFreshAccessToken(session.user.id); + + if (accessToken) { + const rootFolder = "WebCalibre"; + // We target the folder on OneDrive by the ID stored in our DB + const onedrivePath = `https://graph.microsoft.com/v1.0/me/drive/root:/${rootFolder}/${node.id}`; + + const onedriveRes = await fetch(onedrivePath, { + method: "DELETE", + headers: { Authorization: `Bearer ${accessToken}` }, + }); + + if (!onedriveRes.ok && onedriveRes.status !== 404) { + const errData = await onedriveRes.json().catch(() => ({})); + console.warn("OneDrive Deletion Warning (Cloud record might still exist):", errData); + } + } + } catch (cloudError) { + // We catch cloud errors but DO NOT throw them, so we can proceed to delete the DB record + console.error("Cloud communication failed, proceeding with DB cleanup:", cloudError); + } + + // 3. Database Deletion (The Source of Truth for your UI) + try { + await prisma.fileNode.delete({ + where: { id: fileId } + }); + + revalidatePath("/dashboard"); + revalidatePath("/upload"); + + return { success: true }; + } catch (dbError: any) { + console.error("Database deletion failed:", dbError); + throw new Error("Failed to remove the record from the database."); + } +} + +/** + * 3. MOVE: Assign file to folder or folder to another folder + */ +export async function moveNodeAction(nodeId: string, newParentId: string | null) { + const session = await auth(); + if (!session?.user?.id) throw new Error("Unauthorized"); + + if (nodeId === newParentId) throw new Error("Cannot move to self."); + + try { + await prisma.fileNode.update({ + where: { id: nodeId }, + data: { parentId: newParentId } + }); + + revalidatePath("/dashboard"); + return { success: true }; + } catch (error) { + throw new Error("Move failed."); + } } \ No newline at end of file diff --git a/src/app/dashboard/dashboard-view.tsx b/src/app/dashboard/dashboard-view.tsx index 915bee1..62f0c09 100644 --- a/src/app/dashboard/dashboard-view.tsx +++ b/src/app/dashboard/dashboard-view.tsx @@ -1,26 +1,52 @@ "use client"; import { useState } from "react"; -import { Button, CircularProgress } from "@mui/material"; +import { + Button, CircularProgress, Box, Chip, IconButton, Tooltip, Typography +} from "@mui/material"; import SyncIcon from "@mui/icons-material/Sync"; +import RefreshIcon from "@mui/icons-material/Refresh"; +import FolderIcon from "@mui/icons-material/Folder"; +import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; +import DeleteIcon from "@mui/icons-material/Delete"; import { DataGrid, GridColDef } from "@mui/x-data-grid"; import { syncOneDrive } from "./sync-actions"; +import { deleteFileAction } from "./actions"; // Un-commented and assumed active import { useRouter } from "next/navigation"; interface DashboardViewProps { initialFiles: any[]; + user?: { + id?: string; + role?: string; + }; } -export default function DashboardView({ initialFiles }: DashboardViewProps) { +export default function DashboardView({ initialFiles, user }: DashboardViewProps) { const [loading, setLoading] = useState(false); + const [isRefreshing, setIsRefreshing] = useState(false); const router = useRouter(); + const isAdmin = user?.role === "ADMIN"; + + /** + * Recursive function to build the virtual path for the "Location" column. + * Ensures we see "Projects / Project-1" instead of UUIDs or "ROOT". + */ + const getVirtualPath = (parentId: string | null): string => { + if (!parentId) return "WebCalibre"; + const parent = initialFiles.find((f) => f.id === parentId); + if (!parent) return "WebCalibre"; + + // Recursive lookup for breadcrumbs + const prefix = parent.parentId ? `${getVirtualPath(parent.parentId)} / ` : ""; + return `${prefix}${parent.name}`; + }; + const handleSync = async () => { setLoading(true); try { await syncOneDrive(); - // This tells Next.js to re-run the Server Component (page.tsx) - // and fetch the fresh data from Postgres router.refresh(); } catch (error) { console.error("Sync failed:", error); @@ -30,26 +56,133 @@ export default function DashboardView({ initialFiles }: DashboardViewProps) { } }; + const handleRefresh = () => { + setIsRefreshing(true); + router.refresh(); + // Visual feedback for the refresh action + setTimeout(() => setIsRefreshing(false), 800); + }; + + const handleDelete = async (id: string, name: string) => { + if (!confirm(`Are you sure you want to delete "${name}"?`)) return; + + try { + await deleteFileAction(id); + router.refresh(); + } catch (error: any) { + alert(error.message || "Failed to delete file"); + } + }; + const columns: GridColDef[] = [ - { field: "name", headerName: "File Name", width: 300 }, { - field: "metadata", + field: "name", + headerName: "Name", + flex: 1.5, + minWidth: 250, + renderCell: (params) => ( + + {params.row.isFolder ? ( + // Folder yellow + ) : ( + + )} + + {params.value} + + + ) + }, + { + field: "parentId", + headerName: "Location (Project)", + flex: 1, + minWidth: 200, + renderCell: (params) => { + const path = getVirtualPath(params.value); + return ( + + + + ); + } + }, + { + field: "type", headerName: "Type", - width: 120, - valueGetter: (params) => params?.type || "Unknown" + width: 100, + valueGetter: (value, row) => { + // Priority: Metadata -> isFolder check -> fallback + const type = row.metadata?.type || (row.isFolder ? "FOLDER" : "FILE"); + // Ensure we don't display a UUID here if the sync was messy + return type.length > 10 && row.isFolder ? "FOLDER" : type; + }, + renderCell: (params) => ( + + {params.value} + + ) }, { field: "size", - headerName: "Size (MB)", + headerName: "Size", width: 120, - valueGetter: (value) => value ? (Number(value) / 1024 / 1024).toFixed(2) : "0" + valueGetter: (value, row) => { + if (row.isFolder) return null; + return value; + }, + renderCell: (params) => { + if (params.value === null) return "--"; + const mb = (Number(params.value) / 1024 / 1024).toFixed(2); + return `${mb} MB`; + } }, - { field: "updatedAt", headerName: "Last Synced", width: 200 }, + { + field: "actions", + headerName: "Actions", + width: 100, + sortable: false, + align: 'right', + headerAlign: 'right', + renderCell: (params) => { + const isOwner = params.row.ownerId === user?.id; + if (isAdmin || isOwner) { + return ( + { + e.stopPropagation(); + handleDelete(params.row.id, params.row.name); + }} + > + + + ); + } + return null; + } + } ]; return ( -

-
+ + + + -
+ -
+ -
-
+ + ); } \ No newline at end of file diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index d2f58cd..b45a344 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,7 +1,9 @@ import { auth } from "@/auth"; import { redirect } from "next/navigation"; import { getFileNodes } from "./actions"; -import DashboardView from "./dashboard-view" +import DashboardView from "./dashboard-view"; +import { Box, Typography, Chip } from "@mui/material"; +import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; export default async function DashboardPage() { const session = await auth(); @@ -14,12 +16,41 @@ export default async function DashboardPage() { // Fetch initial files from PostgreSQL const initialFiles = await getFileNodes(); + // Determine admin status for the header display + // @ts-ignore + const isAdmin = session.user.role === "ADMIN"; + return (
-

My OneDrive Library

+ + + + My OneDrive Library + + + Manage your synchronized files and project folders. + + + + {isAdmin && ( + } + label="Admin Access" + color="primary" + variant="outlined" + sx={{ fontWeight: 600 }} + /> + )} + - {/* Pass the data to the interactive Client Component */} - + {/* Pass both initialFiles AND the user object. + The DashboardView will use user.role and user.id to + decide who can see the 'Delete' button. + */} +
); } \ No newline at end of file diff --git a/src/app/dashboard/sync-actions.ts b/src/app/dashboard/sync-actions.ts index 18ab0ab..9a4e2e2 100644 --- a/src/app/dashboard/sync-actions.ts +++ b/src/app/dashboard/sync-actions.ts @@ -3,50 +3,93 @@ import { auth } from "@/auth"; import { prisma } from "@/lib/prisma"; import { revalidatePath } from "next/cache"; +import { getFreshAccessToken } from "@/lib/auth-utils"; export async function syncOneDrive() { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); - // 1. Get the OAuth token from your PostgreSQL 'Account' table - const account = await prisma.account.findFirst({ - where: { userId: session.user.id }, - }); + try { + const accessToken = await getFreshAccessToken(session.user.id); - if (!account?.access_token) throw new Error("Microsoft account not linked properly"); + if (!accessToken) { + throw new Error("Microsoft account not linked properly or session expired."); + } - // 2. Fetch the files from Microsoft Graph - const response = await fetch("https://graph.microsoft.com/v1.0/me/drive/root/children", { - headers: { Authorization: `Bearer ${account.access_token}` }, - }); - - const data = await response.json(); - - // 3. The "Sync Loop": Map OneDrive items to your Postgres FileNode table - for (const item of data.value) { - const extension = item.name.split('.').pop()?.toUpperCase() || (item.folder ? 'FOLDER' : 'UNKNOWN'); - - await prisma.fileNode.upsert({ - where: { oneDriveId: item.id }, - update: { - name: item.name, - size: item.size, - metadata: { type: extension }, // Store the "Type" in your JSONB field + const response = await fetch("https://graph.microsoft.com/v1.0/me/drive/root:/WebCalibre:/children", { + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json" }, - create: { - oneDriveId: item.id, - name: item.name, - size: item.size, - isFolder: !!item.folder, - path: item.parentReference.path + '/' + item.name, - ownerId: session.user.id, - metadata: { type: extension }, - } }); + + if (!response.ok) { + const errorData = await response.json(); + if (response.status === 404) { + return { success: true, count: 0 }; + } + throw new Error(errorData.error?.message || "Failed to fetch data from OneDrive"); + } + + const data = await response.json(); + let syncedCount = 0; + + // Regular expression to identify if a string is a UUID + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + + for (const item of data.value) { + const isFolder = !!item.folder; + + /** + * FILTER: If the item is a folder and the name is a UUID, skip it. + * These are storage containers created by the upload action, not user-facing folders. + */ + if (isFolder && uuidRegex.test(item.name)) { + continue; + } + + const extension = isFolder + ? 'FOLDER' + : (item.name.split('.').pop()?.toUpperCase() || 'UNKNOWN'); + + const fileSize = item.size ? BigInt(item.size) : BigInt(0); + + await prisma.fileNode.upsert({ + where: { oneDriveId: item.id }, + update: { + name: item.name, + size: fileSize, + isFolder: isFolder, + metadata: { + type: extension, + mimeType: item.file?.mimeType || null + }, + path: item.parentReference?.path + '/' + item.name, + updatedAt: new Date(), + }, + create: { + id: crypto.randomUUID(), + oneDriveId: item.id, + name: item.name, + size: fileSize, + isFolder: isFolder, + path: item.parentReference?.path + '/' + item.name, + ownerId: session.user.id, + metadata: { + type: extension, + mimeType: item.file?.mimeType || null + }, + } + }); + syncedCount++; + } + + revalidatePath('/dashboard'); + return { success: true, count: syncedCount }; + + } catch (error: any) { + console.error("Sync Process Failure:", error.message); + throw new Error(error.message || "An unexpected error occurred during sync."); } - - // Refresh the dashboard UI to show new data - revalidatePath('/dashboard'); - return { success: true, count: data.value.length }; } \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 62560da..6c6275a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -12,6 +12,17 @@ export default async function RootLayout({ children }: { children: React.ReactNo // Fetch the session server-side to prevent UI flickering const session = await auth(); + /** + * We enhance the user object before passing it to the Navbar. + * This ensures the Navbar knows if the current user is the "Bootstrap Admin" + * defined in our environment variables. + */ + const navbarUser = session?.user ? { + ...session.user, + // Add the bootstrap flag for administrative UI access + isBootstrap: session.user.email === process.env.INITIAL_ADMIN_EMAIL + } : undefined; + return ( @@ -19,8 +30,10 @@ export default async function RootLayout({ children }: { children: React.ReactNo {/* ThemeRegistry handles the MUI Theme and Cache Provider */} - {/* We pass the user object to the Navbar so it can show the profile pic */} - + {/* We pass navbarUser (which includes role and isBootstrap) + so the Drawer knows whether to show the Settings link. + */} +
{children} diff --git a/src/app/settings/actions.ts b/src/app/settings/actions.ts new file mode 100644 index 0000000..cfc6115 --- /dev/null +++ b/src/app/settings/actions.ts @@ -0,0 +1,68 @@ +'use server'; + +import { auth } from "@/auth"; +import { prisma } from "@/lib/prisma"; +import { revalidatePath } from "next/cache"; + +/** + * Toggles a user's role between 'ADMIN' and 'USER'. + * * Security Logic: + * 1. Checks if the caller is the Bootstrap Admin (via .env). + * 2. Checks if the caller has the 'ADMIN' role in the database. + * 3. Prevents the Bootstrap Admin from being demoted to 'USER'. + */ +export async function toggleUserRoleAction(targetUserId: string) { + const session = await auth(); + const callerEmail = session?.user?.email; + + if (!callerEmail) { + throw new Error("Unauthorized: No session found."); + } + + // 1. Authorization: Who is trying to change the role? + const isBootstrap = callerEmail === process.env.INITIAL_ADMIN_EMAIL; + + const callerDbRecord = await prisma.user.findUnique({ + where: { email: callerEmail }, + select: { role: true } + }); + + const isAdmin = isBootstrap || callerDbRecord?.role === "ADMIN"; + + if (!isAdmin) { + throw new Error("Forbidden: You do not have permission to manage roles."); + } + + // 2. Fetch the target user to be modified + const targetUser = await prisma.user.findUnique({ + where: { id: targetUserId }, + select: { id: true, email: true, role: true } + }); + + if (!targetUser) { + throw new Error("User not found."); + } + + // 3. Protection: Prevent demoting the primary bootstrap admin + // This ensures you don't accidentally lock yourself out of the settings page. + if (targetUser.email === process.env.INITIAL_ADMIN_EMAIL && targetUser.role === "ADMIN") { + throw new Error("Security Restriction: The primary Bootstrap Admin role cannot be removed."); + } + + // 4. Determine new role + const newRole = targetUser.role === "ADMIN" ? "USER" : "ADMIN"; + + // 5. Execute Update + await prisma.user.update({ + where: { id: targetUserId }, + data: { role: newRole } + }); + + // 6. Refresh the data on the Settings page + revalidatePath("/settings"); + + return { + success: true, + message: `User ${targetUser.email} is now a ${newRole}` + }; +} \ No newline at end of file diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx new file mode 100644 index 0000000..060c61d --- /dev/null +++ b/src/app/settings/page.tsx @@ -0,0 +1,123 @@ +import { auth } from "@/auth"; +import { prisma } from "@/lib/prisma"; +import { redirect } from "next/navigation"; +import { + Container, + Typography, + Paper, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Box, + Alert, + Breadcrumbs +} from "@mui/material"; +import Link from "next/link"; +import UserRow from "./user-row"; +import SettingsIcon from '@mui/icons-material/Settings'; +import NavigateNextIcon from '@mui/icons-material/NavigateNext'; + +export default async function SettingsPage() { + const session = await auth(); + const userEmail = session?.user?.email || ""; + + /** + * 1. Access Control + * Check if the logged-in user is the Bootstrap Admin from .env + * or has the ADMIN role assigned in the database. + */ + const isBootstrap = userEmail === process.env.INITIAL_ADMIN_EMAIL; + const dbUser = await prisma.user.findUnique({ + where: { email: userEmail }, + select: { id: true, role: true } + }); + + const isAdmin = isBootstrap || dbUser?.role === "ADMIN"; + + if (!isAdmin) { + redirect("/dashboard"); // Unauthorized users are sent back to Dashboard + } + + /** + * 2. Data Fetching + * Get all users to display in the management table. + */ + const allUsers = await prisma.user.findMany({ + orderBy: { email: 'asc' } + }); + + return ( + + {/* Breadcrumbs for easier navigation */} + } + aria-label="breadcrumb" + sx={{ mb: 3 }} + > + + Dashboard + + Settings + + + + + + + User Management + + + Assign Administrative privileges and manage user access. + + + + + {/* 3. Bootstrap Warning Box */} + {isBootstrap && ( + + You are authenticated via INITIAL_ADMIN_EMAIL. + This provides permanent access to this page regardless of database settings. + + )} + + {/* 4. User Management Table */} + + + + + User Identity + Current Role + Actions + + + + {allUsers.length > 0 ? ( + allUsers.map((user) => ( + + )) + ) : ( + + + No users found in database. + + + )} + +
+
+ + + + Note: Users must log out and log back in for role changes to take effect in their active session. + + +
+ ); +} \ No newline at end of file diff --git a/src/app/settings/user-row.tsx b/src/app/settings/user-row.tsx new file mode 100644 index 0000000..ef03e78 --- /dev/null +++ b/src/app/settings/user-row.tsx @@ -0,0 +1,113 @@ +'use client'; + +import { useState } from "react"; +import { + TableRow, + TableCell, + Chip, + Button, + CircularProgress, + Typography, + Tooltip +} from "@mui/material"; +import { toggleUserRoleAction } from "./actions"; +import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; +import PersonIcon from '@mui/icons-material/Person'; +import SecurityIcon from '@mui/icons-material/Security'; + +interface UserRowProps { + user: { + id: string; + email: string; + role: string; + name?: string | null; + }; + currentUserId: string; + isBootstrapAdmin: boolean; +} + +export default function UserRow({ user, currentUserId, isBootstrapAdmin }: UserRowProps) { + const [loading, setLoading] = useState(false); + + const handleToggle = async () => { + const confirmMsg = `Are you sure you want to change ${user.email} to a ${user.role === 'ADMIN' ? 'USER' : 'ADMIN'}?`; + if (!confirm(confirmMsg)) return; + + setLoading(true); + try { + await toggleUserRoleAction(user.id); + } catch (err: any) { + alert(err.message || "An error occurred while updating the role."); + } finally { + setLoading(false); + } + }; + + const isSelf = user.id === currentUserId; + const isAdmin = user.role === "ADMIN"; + + /** + * REVISED LOGIC: + * We only "Lock" the button if: + * 1. You are the Bootstrap Admin AND + * 2. You are already an ADMIN in the database. + * This allows you to promote yourself from USER to ADMIN, but prevents demotion. + */ + const cannotDemote = isBootstrapAdmin && isSelf && isAdmin; + + return ( + + + + {user.email} + + {isSelf && ( + + Current Session + + )} + + + + : } + label={isAdmin ? "ADMIN" : "USER"} + color={isAdmin ? "primary" : "default"} + variant={isAdmin ? "filled" : "outlined"} + size="small" + sx={{ fontWeight: 600, px: 1 }} + /> + + + + {cannotDemote ? ( + + + + + + ) : ( + + )} + + + ); +} \ No newline at end of file diff --git a/src/app/upload/_actions.ts b/src/app/upload/_actions.ts index 9210685..7fd4013 100644 --- a/src/app/upload/_actions.ts +++ b/src/app/upload/_actions.ts @@ -7,12 +7,14 @@ import { revalidatePath } from "next/cache"; /** * Creates a virtual folder in the database. - * No physical folder is created on OneDrive to keep storage flat and fast. + * We explicitly set the metadata type to "FOLDER" so the Dashboard icon + * and Location logic work immediately. */ export async function createFolderAction(name: string, parentId: string | null = null) { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); + // We generate a manual UUID because the schema requires 'id' but has no default generator const internalId = crypto.randomUUID(); await prisma.fileNode.create({ @@ -23,6 +25,10 @@ export async function createFolderAction(name: string, parentId: string | null = path: `/virtual/${name}`, ownerId: session.user.id, parentId: parentId || null, + metadata: { + type: "FOLDER", + mimeType: "inode/directory" + } } }); @@ -32,8 +38,8 @@ export async function createFolderAction(name: string, parentId: string | null = } /** - * Uploads a file to a unique UUID folder on OneDrive - * and links it to a virtual parent in the DB. + * Uploads a file to OneDrive into a unique UUID folder + * and links it to a virtual parent (Project/Folder) in the DB. */ export async function uploadFileAction(formData: FormData) { const session = await auth(); @@ -45,46 +51,66 @@ export async function uploadFileAction(formData: FormData) { if (!file) throw new Error("No file selected"); + // Use the utility to ensure we have a valid JWT (fixing the "no dots" error) const accessToken = await getFreshAccessToken(session.user.id); const rootFolder = "WebCalibre"; const internalId = crypto.randomUUID(); - // 1. Ensure WebCalibre exists (Simplified for brevity) - // ... (Keep the root folder check logic from your previous version) - - // 2. Create the unique UUID folder on OneDrive + // 1. Create the unique UUID folder on OneDrive inside WebCalibre const createSubFolderRes = await fetch(`https://graph.microsoft.com/v1.0/me/drive/root:/${rootFolder}:/children`, { method: "POST", - headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" }, - body: JSON.stringify({ name: internalId, folder: {}, "@microsoft.graph.conflictBehavior": "fail" }) + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + name: internalId, + folder: {}, + "@microsoft.graph.conflictBehavior": "fail" + }) }); - if (!createSubFolderRes.ok) throw new Error("Storage directory creation failed"); + if (!createSubFolderRes.ok) { + const err = await createSubFolderRes.json(); + console.error("OneDrive Folder Creation Error:", err); + throw new Error("Storage directory creation failed"); + } + const subFolderData = await createSubFolderRes.json(); - // 3. Create Upload Session & Upload + // 2. Create Upload Session for the file const sessionUrl = `https://graph.microsoft.com/v1.0/me/drive/items/${subFolderData.id}:/${encodeURIComponent(file.name)}:/createUploadSession`; const sessionRes = await fetch(sessionUrl, { method: "POST", - headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" }, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json" + }, body: JSON.stringify({ item: { "@microsoft.graph.conflictBehavior": "replace" } }) }); const { uploadUrl } = await sessionRes.json(); const buffer = Buffer.from(await file.arrayBuffer()); + + // 3. Perform the actual upload const uploadRes = await fetch(uploadUrl, { method: "PUT", - headers: { "Content-Length": `${file.size}`, "Content-Range": `bytes 0-${file.size - 1}/${file.size}` }, + headers: { + "Content-Length": `${file.size}`, + "Content-Range": `bytes 0-${file.size - 1}/${file.size}` + }, body: buffer }); if (!uploadRes.ok) throw new Error("OneDrive stream failed"); const driveItem = await uploadRes.json(); - // 4. Record in DB + // 4. Record in Database with full metadata and virtual hierarchy + const extension = file.name.split('.').pop()?.toUpperCase() || "UNKNOWN"; + await prisma.fileNode.create({ data: { - id: internalId, + id: internalId, // Matches the folder name on OneDrive oneDriveId: driveItem.id, name: file.name, description: description, @@ -92,9 +118,9 @@ export async function uploadFileAction(formData: FormData) { isFolder: false, path: `/${rootFolder}/${internalId}/${file.name}`, ownerId: session.user.id, - parentId: parentId || null, // VIRTUAL HIERARCHY + parentId: parentId || null, // Virtual link to the Project folder metadata: { - type: file.name.split('.').pop()?.toUpperCase() || "UNKNOWN", + type: extension, mimeType: file.type } } diff --git a/src/app/upload/page.tsx b/src/app/upload/page.tsx index 120865d..fdb7096 100644 --- a/src/app/upload/page.tsx +++ b/src/app/upload/page.tsx @@ -2,16 +2,24 @@ import { auth } from "@/auth"; import { redirect } from "next/navigation"; import UploadView from "./upload-view"; import { Container } from "@mui/material"; +import { prisma } from "@/lib/prisma"; export default async function UploadPage() { const session = await auth(); - // Guard: Must be logged in to upload if (!session) redirect("/"); + // Fetch only folders so the user can select a destination + const folders = await prisma.fileNode.findMany({ + where: { isFolder: true }, + orderBy: { name: 'asc' }, + select: { id: true, name: true, parentId: true } + }); + return ( - + {/* Pass folders to the view */} + ); } \ No newline at end of file diff --git a/src/app/upload/upload-view.tsx b/src/app/upload/upload-view.tsx index 3c1dbc2..66c6c8f 100644 --- a/src/app/upload/upload-view.tsx +++ b/src/app/upload/upload-view.tsx @@ -3,10 +3,14 @@ import { useState } from "react"; import { Box, Button, Typography, Paper, LinearProgress, Stack, - TextField, MenuItem, IconButton, Tooltip, Divider + TextField, MenuItem, IconButton, Tooltip, Divider, + InputAdornment } from "@mui/material"; import CloudUploadIcon from "@mui/icons-material/CloudUpload"; import CreateNewFolderIcon from "@mui/icons-material/CreateNewFolder"; +import FolderIcon from "@mui/icons-material/Folder"; +import AssignmentIcon from '@mui/icons-material/Assignment'; +import { useRouter } from "next/navigation"; import { uploadFileAction, createFolderAction } from "./_actions"; /** @@ -20,7 +24,21 @@ const formatFileSize = (bytes: number) => { return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; -export default function UploadView({ user, folders = [] }: { user: any, folders?: any[] }) { +interface Folder { + id: string; + name: string; + parentId: string | null; +} + +interface UploadViewProps { + user: any; + folders?: Folder[]; +} + +export default function UploadView({ user, folders = [] }: UploadViewProps) { + const router = useRouter(); + + // Form State const [file, setFile] = useState(null); const [description, setDescription] = useState(""); const [parentId, setParentId] = useState(""); @@ -29,81 +47,90 @@ export default function UploadView({ user, folders = [] }: { user: any, folders? // Folder Creation State const [showFolderInput, setShowFolderInput] = useState(false); const [newFolderName, setNewFolderName] = useState(""); + const [isCreatingFolder, setIsCreatingFolder] = useState(false); - // --- RESTORED FILE SIZE LIMITS --- - const MAX_FILE_SIZE = 150 * 1024 * 1024; // 150MiB Limit + const MAX_FILE_SIZE = 150 * 1024 * 1024; // 150MB Limit const handleCreateFolder = async () => { if (!newFolderName.trim()) return; + setIsCreatingFolder(true); try { - await createFolderAction(newFolderName); + // Creates folder nested under current selection if parentId exists + await createFolderAction(newFolderName, parentId || null); setNewFolderName(""); setShowFolderInput(false); + router.refresh(); } catch (err) { alert("Error creating folder"); + } finally { + setIsCreatingFolder(false); } }; const handleUpload = async () => { if (!file) return; - - // RESTORED: Client-side size validation if (file.size > MAX_FILE_SIZE) { - alert(`File is too large! Maximum size allowed is ${formatFileSize(MAX_FILE_SIZE)}.`); + alert(`File is too large! Max allowed: ${formatFileSize(MAX_FILE_SIZE)}.`); return; } setStatus('uploading'); - const formData = new FormData(); formData.append("file", file); formData.append("description", description); formData.append("parentId", parentId); try { - await uploadFileAction(formData); - setStatus('success'); - setFile(null); - setDescription(""); + const result = await uploadFileAction(formData); + if (result.success) { + setStatus('success'); + setFile(null); + setDescription(""); + router.refresh(); + } } catch (err) { console.error(err); - alert("Upload failed. Ensure file size is within limits and check server logs."); + alert("Upload failed. Check server logs."); setStatus('idle'); } }; return ( - + Add to Library - {/* Section 1: Folder Selection */} + {/* Section 1: Destination Folder */} - - 1. Select Target Project / Folder + + 1. Destination + setParentId(e.target.value)} disabled={status === 'uploading'} + helperText="Files will be virtually organized into this folder." > - None (Root) + -- Root (Main Library) -- {folders.map((f) => ( - {f.name} + + {f.parentId ? `↳ ${f.name}` : f.name} + ))} - + setShowFolderInput(!showFolderInput)} - sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 1 }} + sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 1, width: 56, height: 56 }} > @@ -111,7 +138,7 @@ export default function UploadView({ user, folders = [] }: { user: any, folders? {showFolderInput && ( - + setNewFolderName(e.target.value)} autoFocus + disabled={isCreatingFolder} /> - + )} - {/* Section 2: File Selection */} + {/* Section 2: File Upload Area */} - - 2. Upload File + + 2. Upload File - + + { setFile(e.target.files?.[0] || null); setStatus('idle'); }} /> + {file && ( - - Selected: {file.name} + + {file.name} - MAX_FILE_SIZE ? 'error.main' : 'text.disabled' }}> - Size: {formatFileSize(file.size)} {file.size > MAX_FILE_SIZE && "(Too Large)"} + + {formatFileSize(file.size)} )} - {/* Section 3: Description */} - setDescription(e.target.value)} - disabled={status === 'uploading'} - /> - - {/* Status & Action */} - {status === 'uploading' && ( - - - - Streaming to OneDrive storage... - - - )} - - - - {status === 'success' && ( - - ✅ Successfully Added! + {/* Section 3: Notes */} + + + 3. Metadata - )} + setDescription(e.target.value)} + disabled={status === 'uploading'} + /> + + + {/* Progress & Actions */} + + {status === 'uploading' && ( + + + + Transferring to OneDrive and updating Library... + + + )} + + + + {status === 'success' && ( + + ✅ File processed and assigned to project! + + )} + ); diff --git a/src/auth.ts b/src/auth.ts index 8e547bf..4538d2c 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -9,25 +9,35 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ ...authConfig, callbacks: { async jwt({ token, account, user }) { - // On the first sign in, 'account' contains the refresh_token + // 1. Handle OAuth tokens (from first sign-in) if (account) { token.accessToken = account.access_token; token.refreshToken = account.refresh_token; token.expiresAt = account.expires_at; } + + // 2. Attach User ID and Role to the token + // When 'user' exists, it's the first time we've fetched this user from the DB during login if (user) { token.sub = user.id; + // @ts-ignore - 'role' exists on our custom User model + token.role = user.role; } + return token; }, + async session({ session, token }) { + // 3. Pass values from the JWT Token into the Client-facing Session if (session?.user && token.sub) { session.user.id = token.sub; + // @ts-ignore - Attaching the role so the Navbar and Settings page can see it + session.user.role = token.role; } return session; }, }, - // Adding events can help debug if the account is actually linking + events: { async linkAccount({ account, user }) { console.log("🔗 Account linked successfully for user:", user.id); diff --git a/src/components/layout/Navbar.tsx b/src/components/layout/Navbar.tsx index d8038e3..bb6c80a 100644 --- a/src/components/layout/Navbar.tsx +++ b/src/components/layout/Navbar.tsx @@ -10,14 +10,18 @@ import MenuIcon from '@mui/icons-material/Menu'; import LibraryBooksIcon from '@mui/icons-material/LibraryBooks'; import CloudUploadIcon from '@mui/icons-material/CloudUpload'; import DashboardIcon from '@mui/icons-material/Dashboard'; +import SettingsIcon from '@mui/icons-material/Settings'; import Link from 'next/link'; import { signIn, signOut } from "next-auth/react"; +// Updated Interface to include Role and Bootstrap status interface NavbarProps { user?: { name?: string | null; email?: string | null; image?: string | null; + role?: string; // Added + isBootstrap?: boolean; // Added }; } @@ -25,6 +29,9 @@ export default function Navbar({ user }: NavbarProps) { const [isDrawerOpen, setIsDrawerOpen] = useState(false); const isLoggedIn = !!user; + // Logic: Is this user an Admin? + const isAdmin = user?.role === 'ADMIN' || user?.isBootstrap === true; + const toggleDrawer = (open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => { if (event.type === 'keydown' && ((event as React.KeyboardEvent).key === 'Tab' || (event as React.KeyboardEvent).key === 'Shift')) { return; @@ -32,12 +39,18 @@ export default function Navbar({ user }: NavbarProps) { setIsDrawerOpen(open); }; + // Build the list dynamically based on permissions const navItems = [ { text: 'Dashboard', icon: , href: '/dashboard' }, { text: 'Library', icon: , href: '/library' }, { text: 'Upload File', icon: , href: '/upload' }, ]; + // Only push Settings if the user has Admin rights + if (isAdmin) { + navItems.push({ text: 'Settings', icon: , href: '/settings' }); + } + return ( <> @@ -67,7 +80,9 @@ export default function Navbar({ user }: NavbarProps) { <> {user.name} - {user.email} + + {user.email} {isAdmin && "(Admin)"} + {user.name?.charAt(0)} @@ -104,6 +119,18 @@ export default function Navbar({ user }: NavbarProps) { ))} + {/* Visual indicator for non-admins if you want it greyed out instead of hidden */} + {!isAdmin && isLoggedIn && ( + <> + + + + + + + + + )}