From 78fa2835abe7ff49995ad82bd28dbb956375b875 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 7 May 2021 20:03:24 +0200 Subject: [PATCH] :art: [Route] templates refactor --- .vscode/launch.json | 5 +- package-lock.json | Bin 361439 -> 775279 bytes src/routes/guilds/#guild_id/templates.ts | 133 ++++++++--------------- src/routes/guilds/templates/index.ts | 23 ++-- src/schema/Template.ts | 10 +- src/util/Base64.ts | 47 ++++++++ src/util/String.ts | 5 + 7 files changed, 113 insertions(+), 110 deletions(-) create mode 100644 src/util/Base64.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 557fb6d7..221931ee 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,9 +9,10 @@ "type": "node", "request": "launch", "name": "Launch Server", - "program": "${workspaceFolder}/dist/index.js", + "program": "${workspaceFolder}/dist/start.js", "preLaunchTask": "tsc: build - tsconfig.json", - "outFiles": ["${workspaceFolder}/dist/**/*.js"] + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "envFile": "${workspaceFolder}/.env" }, { "name": "Debug current file", diff --git a/package-lock.json b/package-lock.json index 78bc463620a6c24dc99aed6f1d1e4e2ee07355cc..41954a61a4f1881f28bdce09567eaaf25c3676ff 100644 GIT binary patch delta 97715 zcmc#+2YeLO*8k1S-GmTGAtaj+LJBREO(BIE2)#o9=@Qr^n`B9{8+H?lsDK@j<|xO8 zfXY)W6r--9v}b)jgM#TCXf_NSF?LqbyUBl^D~DHdau z3I8J{ztn2C7h7#5>BeevN?&owpPl=b8|~vQ_8Mbl<&0vRxw^(Z9{#Y>Tx_z~*>A_s z7?~m-pVoPndl0+Hw$x-Z)Yh0Q>F9--Y50FBNC}-Yzh*_X$)3L0WT!)>6!yza%Sh|j z&-HOpv26vLETu39KgfVnp}ZdMS|x;sl~`*`mZj`R1Je4z=2b%9oTbJ}bBVFWYGZ%S zO&gfjIFdPYfW@?2nj~{z+JLki*Bp>s%z@SA$^Nfpq z+%+aknc33#aOjJ15qa z`gkrKHkyS9=w~D;;+9C)BK2^9=)%Ol9onpN5>jNg;OR3a6_Ub+pqHW2T$Em1X-->g zZ~8XWh;Hfm=-6cv_a((Z#72?@4gVr-#djvO2g^nhEjCOjgx>dY9oa?dp}0uR4?5j$ zs#*%CMshLGWs49B@tycoaZg+#99=6!!s_n44jM#$f%wOU$hoow)89#q0{_fLG1(dy z-LlJ;4(G1tl3>G)TnNN&$4i!Y99Ps3lK=-^;v&T)eK#?-XJnqr9%iIvA{$oQ$hx-C zA=2BcN{SH&#|+9=rLoLpG1(}~mc0t!2p!@Nq2f_}O5JVx1c}!6<3hxPvA0Bfq!qu~ zHB$E0d_T*4f6ub6q*GrPFAEd*##bwNSyJc0&h1X-8~N1iyo zXBRQ2%R$E2s*-xPYq}(HQ({8hxWp*e(KY)tM(ms1wyrKI&P~j=#IU+Qk_$M+v@3h| zf(>W!K5ZO5L_FN}BWb<_#fX{RUS~4sTtl@Hzl`rH zZfYMX9_^VZev}p=Uv}O1X`$||*)StKlU z^57WqtJN?}4>xw;I@ZMwP4O}o?C8Ly)jcz;cjM>EA(G&)4qRK%&n9$*)9HT&i+hH@ z;C-2Oheq^s?U;uR6$gyE06m9tvEuO2edHTjS2?W8oWAkqO&`09l2q4zTr$_+Bj0mfSoT}IeR3AvQnjKmP-=x|a(oigOVS<+eyQL9v=PFh@gvVIil^JI8Blf2)NEt5(U?_W zu~m#3KW}n%`r;|o^Xz@HivLJaUmjRomb2`{Q16kminUW3;%Wu-50-O+8p+ZY;Kxjd4 zfVFZd+F~}C2B?i@>>xzkJ1ZC-ibIWX`yHeW9KDrvg>yB0G_<)5Z39$E2dI#xx56K+1$Rrq`HU93*BYV#I_0Xft1%DQBvx`zmBXjW*@7s7u zp4ueP*@MLTs$@7>gcKzH8!4Fgtz^3OY19H$)`I>oLusXvn$hB>+e5{S^QllUo+sj> zU5V05sc*xvRn5E#2W+nd?s-lR4ZFB3v0z&Qn^C;Hs1W*?xX2k-VMcNL(im~wkTBTW zMi&BuH{y+|20k5z8PW0`wv6!vcDujV>Dt4haG|Z3_gHYN-?#X7(eF$eFIeBB?vLXB z!hDrAwdD0Gye;YU>B8nZ(n-$t#J!K{V0XDLMLNrC|3I#X?{}^W6+S&yPt&)SbEvtW zT18Be%~%X;#&Mm*0(&szN1;Dr(LITf_@)pINriZuT~4PH1BJM2wclr}i134V&Cw>w zH{PW@rK`cXx_e|?&1UwQYb7`1TFu64o5Xj4!!MxY>d-~LCv2R8oG*VUIunuiLRk^f z!>xbtoqbTtTXnF$bIjR+er0BKC)ZXLF=v~&-9p53)xof>uP#+gTGCy5;fG$JQZXU2 zv&!5VcYoH=$77qeOXz}ffk5?AT{_(5!0l$w=}LWrBKeREs2 z=kVoP%Go;dS-$u z@EdaSCA?srllXR2x@Fz_ijWSgcaUgUwZDnRb^Am<489zN61(uG;Bjh)qVDLGv?Ywe znQc}}6=c4G3QAHvmn|l)3lev%*v;g*@w%GPnyxBe1iEOvuA{i|=}7k!c`KzU{#yA$ zV5X>h<$9-)(fc^x8y4|gEWFuA=rDm<2?1F}UFMC!%#Nv>uqs|qQB2C_C)w1B< zzBRG1bTt>2Y5U6pDbC0sl5}>}7s++2E(q*C^4&oUTo(&AMAwCE;3dCU!p5xy0pWR)oIt0o z#SW)>qnoc$NF;4~lG%_|Px0NJ-Mp7GsqDND^rttOsnlw#3LNkA(+*^7Z%$E*>@TA> zxAQ@X@(Y&RSPV&K%g;*q)f~AO_4t_O|OVP%u-vQwh}LaHD#1&iw;Ufv$(@tZQkRH z^6r5kRgpnyX<@{nhith{6{GoyXvG`mdW)M%jJ)}PzA@10DFHuG%_mGZF)(ibx}i_$ zIO>Xw7w0|QMG>K0{fvz(1Y=KZ-IIG7aXV4s2YWjx z2Ka8T6UHPBkS>0_H%$H&=o`+()mff(YQt3tQR2OI%3&U_cK+ok@u`BY}mwi#IPTM_LFqMaNs{A6@T-xd_iLUkpyx1At~r1am-%w zk;0F}!lZ|A($#(WbTQ(HWa>y?Z7{ZteD0Wt? ze(e%Na5jO4RJ?wk4MQiZeIr9Yl(_SaU)iV6yg5it@r1V$;D*-)z1Zok)6Q?S6Kmhr zD}H~ZAW5A2ugfamxa)1{Q#$|pmx9G7|E*l;!GE8Zk6O3qowlwOI?wp)cT=J~+&tKK zPSDq-9Cad~-OH}aJr=CQyoh=A7ufDZxb<7<{zCG6^eitp{)2M!>R*b1{3l39(fZyG z&NU*E{C&kP*6n!T3H@^uAnyC%9X6U94fy4U@i0u#b%cx_2vXSd;qS`X9zSu8O+vS7 z&qqp-$FYxeN^s%_A77I1oLKO=Ui|KpOA^BB!l#MyLtXY+LS4pZPBeMJ=V|gEZ(i~p zoxaY@UE){Ca6l3ozPPHS(U-1iOk+-hx{8spTyD}*1QyLKkkU8AiNiyEg?RfAI>ST^ zHHAP)OO>(0WGFF1BnWX(PmoXiuInm+At=VDUyu}by4^q$psT<|sX3mVP#%v?ige|~ zKHJFW9O0X0E86fviIHPn`w$qtl#`f ziB!jcYs@TKzWtF6Z~pFX`S5j@zT=r@k|M_c5H><{k*bC&)z%s4KrHy-&PkeMX=Ci& z>OY3>V@2}gQFb*c(r6-0%W2F-(VR>5sfle*A7R(CUE}jHT2?^hb3#0X->l0NJN@)H zn|SmBu7mjPPdz7S&X=UVQPtHZONpV>Y^sFg285sGn@N^fex^izIO02JzLx(5&i^Jv z!G{8gg4oeqrWkbganP6J)*LxIJX|IOjW(7FvzKs0OgMK;DNoLvlZ4iH4GP4+(PlG1 zB1*!$I0?V&DHILBTRET@3mKCI)6qL#@Tk)JrIsjEJFMf0;Ql z00WEH{P%78D{=_L9)CTj%}jiFU-lK2;tDhD=!0pad)6Xn=y$nN`Q{(K{DCJVHzp;qlujzp z>A(A~$R%ZKX>!J8c7xqqX6fhD-o$lRcG44#Y-Y`ihhB+QT;FB(Y^opV@4bfmfUPC0 zkv+3i5m*?75vYf^BV6w~j(eK!wD{M`U>L@8zb$Gu0p*TVtPjoe#UmxBBX?npB6wi2AU_4>)5TZ>SdqX*=CY+a@3_rBvcI0WwMYYX@ zhW0q>uJ)YMeyvKNNo-;8RTyU`~Z%GbIFdC;hZy_4BcrkIg$%=V3wK4%f-B7 zMidu?IyFVYt?00+$?3v9 zAg6@tTMY^+4u=xC^U~#dHHo{dmS%zWuR4|1k`>N$OSytX{VlL>7ZP^)A{Qbqe-Cp2 zy7LKeX+Md9)!~@DePUWHTnNW&aNTOItvqs2Rf$KRxoIlr=EEyM zxHzUV$=(_?JcUa)&*mbwB%-=;V=VrIDvNM9mhVPi0Q{7vi-6ELzMT(}wUsn1O2IpI z{VIHAVM8%nY}*1M6;{RZ1~|M9-(sb}Cydv8557!oMF@*zmaguLpy~m=xW()eM!UtP z&AJTrYF52NT=K0R428N3IMfHz?JxJ@{=weod%d|lc%e5MlI14MNKNj;4S)=R3ldPz zgw6AGQ4o>N1$U=fXH)N?M*{&4_Tlu7<$bvJlH=Cxr7e;uf%F;_bhX!z^@^3i059FkzS$JhL zes{(oZeb_ct#&WTV6(&KGbl|?_TV$6Z3!F9JxwR?0v`rDy=Z15m1r-UFoAH8; z$->GGAC{30@bXkN(k7qcg4LqENvbYDbqbT$lVm6=#U1He!1sb}^ATcPS-=;<{$0*; z7;aP7@m)UM67>7(fsEifD|FVz(^YK3s^xqqE(eUId_TA{mJ5P+veCq5GyR!OQ&SQ! zg@I}kx8%^j=Wu$xmpnd4(g=>Q&5{ZBvoKST2}vl6j{4&DlHS%*ci`F&20e!?v1J&N1LIL2qAI7I;) zxIBvcz!#Se*4P=SHXUqUCM3Y`qq*1QZvnUrpe$DR4j0whi>xc;*Tamj@UX&0EjJ;jf5svt z^!D=NJPZP^hZY8giRknhFeSC|sda$`?{X31)ZJK_{9#Y5isc?7_Dmb67#b3awq%!7j7kypS4 zDaBJU780|Yo2^Wo#yv_EOf_JYe(1j1)2<|Mi@DZrfJuIHXMa|Z@leuZVDHj|d{g32t>aE6|=%!#fFZ6vz!y|LJ9gHTovrBUG zobQIz6wc*XSr7&^g8X^h4DFDOYUl&Uwn=%SY)8JDglSzr&qIYs!~D^>KM&657Q`A;!5$<@VHc(5|nDR`5 zj|f$NlTJNP9zbYlSDD`EdAe4>5Y@aQ8sZXZSZ1M7cs*7+10BJCXq#|BWp1-Ew4!PS4AhBcz=VH>mXlf$=Y7 zeFfiRc45IfE&?{bfdoCEC#kTvhR=XK|HJ}&Smh)N>Msk7DhQ3$wS@(@@lk3%Z~q92 zmHSgF%otF$mWoF{h=KGkNG9xA%q7D{0c*}Ryp9MSYNKzN#K&IUjXLrpMrIGKxKmi-{gb!n1wJ3^8b37bC|oppF~I)L?O z63*(1BoThDwifCO5$0Ni4PA#Ne)1zw%8se#b}+N&Vl_9z;8~qV1FhC9HwhXs7BZJ; zs+YnJ6I7(Gx;Se#Gwi(y1D%U+!n;k&bHIl-Zn%_VZm>&+>cqfJmJXQ~T}LtQd>FiV z5KRZPAA(?mMc19a=x7*P!xh5B27KFCqDl{M)Nt|ebq&``j3`SEC>1TvydJK7U)A^B zDn_1WfwiBCjWq^XVndfYb2Y5L3H_oc*Kl*?z*^~x zu;U1q0N38cz1IYjKc8ynQlVgU|1>%~7l5$_4`CHS=AO9=FPZ>I#-Y?hScsxmil%&x)pv$c>E_ul$t-C)aZ8 zeYyl{)2GAIJGocoF_mI#^$JNqyJHI**KtN)oNsR1&9fAPi|aUt;vDzh#a)s7#|TLx z@a}r9Yr5xO7u!t68Z^j@OUf1Rucc@th}`JX_^CfUcN15upz5hj?k_wg|IAT#H+_n< zn0A!gTVTTq@&KQ3ccIEditTn<6i!hrj!qcQXQhdm`_th8Kr`W^ z`?0X$*$z5q)#pF&=N7;pQK&!AO>DxNuX}*|gmHJ%gXr3ya*Fd4c?TOFY7H2Lbh^GGJ4!0CHzW>*d-q}8)?c3F zqUCY`XSAckk}?}u{R1H|>mSaU0cQ?_$&Yil$#Z<@FVJ&UTw~rc8b#Euqqqq@p5UHk zbB8ur3N(yHH#Xbx9=n`Nb>9HT(Or$S{rDu;MJ{!4k{WXrL<(5;uWds=nEe#@6q~^9 zwWD95dG}@~A?EK>Zqj(5LdpQhG#@(gxXPEw+^C`M72K@OPx1X_w&#%RbKYNB^kt13kb+8KSqL!GN zvlY%f&s}6=_Fag6ZQ|fY4fDcP-Fkw?kkcGY;f;Z|G>51Ei(I_ZVnhWJm2ziAf9%*{ zqSX{qyFwG|f4GduSR_oHO#G|@So+v+~0Y)??1 zQwO*gm8{ids)qb2m=E*9LGFbA%Wp(UeM9dR14BJ~nCl7FcSz6(jjO626f7~7B3h!} zfR~@Wk&GiwEJl+z^1u-UfZ-92RGmp9L!<=Rc$u+=7JBUjhmT-1e*ZtY`O1rDSyBt< zEAZkaokf+k=v8jLHo8vhY)kMgSPn$QYut_6@OZ7H9vlueGFbB-(Ys2r9%rw8;1a$w z9DE&hvMIL+K_lfall=%QNl^=$J+ub~fmaBRow|`biRXUn0tIh! z$|T#uH@PPiqSI7E4QXud0n>_6jxb%Iek^Jl;r~M8YvEhmbWb7tlE$AEyJ&6lC*Psl z+NV-uf`e~ym$hDps;0#cJUtA@8#vX zQA*`w1S+oI+e=)ZZH{6})v&%tARnd@eM9e%dj1+Vq*9gHmydD(3ruM#$EA9zYr3*w znCTe`ec$5-!q72%NH4j@WiG`WEkn7fva-sk&<)B zNglmMe}?C~;n@5E9hg3;rAB1VuYAZws$E$1Cu^-TEiX2)y7IEahb4u&D2OSfNy@TH z>iH+Q{*ohj!wE@?Rf9FCP7duq;yxX!sg0?R(eM%Xvh;F~eayu~%MY}+x)MYCrLbfq zx&!%7&{k(2pG4r2{*7SnC#A0R*jO`{TJUwb8Z)P#TV9{;lA)p zBWn=kQhrS6e8Y|{GWwj|5u4EG`it-MG0;q`H}oPb`57+?9=uwHfV##F$Io(|9qZ0= zPT#lNTY^BK-R~#3i;6(QIRr@JWcjKJzLpo(RO572J=?%t?}IGWNS-$>MZY*pp*%bS zE9Y-pj3~cb&U0HSq3W_eJ8ij|tatSO1qC#|T0M;Zuabwt>i=@TDy%uva#L{=@bW+Z z=Zvd9nMlIm<_p{(OyM7{vUwU@3&*D}Uf@RK!`v2wmd}Y_xeCTtX8gu=i;zhe3LIlu zn4fP%-0(kt0iHdM+;S!Lv?%g0Zq%RjmRb` zK&rx2qd=duF#AJZHBNQpMmxEkLfQ6?Yw@8Rq@T-eL2Ab$?clC|#P|WU@eiA+c5IZW zR)TG={)V*xaB~%RsP&*5A8J$jccoejy!jg*o_0P{nWib==jQkd09tgl329MsT!xPS zg^C}{cJBg?_pzPsq9FcZwfdsIq?jTPK#!E%N^looX?X{zNh%^rU4!>P$kj+IPgV%- z=F8VAcIc_*1-#sr|CXMP2)Bl&2tpY#6|MY$}I-Rzax2P zLH}!4Vj}L@4t%$+nin={0P~j1lQ;1WVB0kR6aslBr^gY!-S$`}V3h+<1O}$b#<|+} z995caEIG4R6h9iKK8<}rZtlpBX4=`O9r?UK#FLYv`LEf4(J}l5^&}sS^GwIq>}8eK zBKa$G>qRZdvc4L0_@3qJLtRr}ShJ_i&=w1mH7~bMbK9$JW=l<}n0zJ%juKSsM|R@N z6jq%a*Mv5aQ?Xv)#T8fAiFY>CbZ3txcjn_ApT+ah%9uPfbmpbHXpxN()>5Or#$Y#= zV&8B+8O|i|=askpi!MBa&gkJ>A|Eej1vKAaH+5-pY#t+B)Wz*ahLjm=@j~i^7%=AW zx3YctJ%|5IasSTc@|WmkRm0ijx~ngGe6cWX03YWF9l$qBq;hl~i2Fdt_nw~6;v7mx z??Jd)I%sD#yTcPgWbk1AdHO^D{HtZA8X9znmm=L0hVV~GFwi!6h&iW)FVuX+s@JRx z3ZEoNuyqnf9BT6TnZCpYwDeG(IoecI5*L8r{2~JDWI)R_c9`R@u=AvzM&~;%fs*#azY?vIxe%^RdIn9W`*d< z{4TaWR>tLU9%5DBo})BN^O9w*au@#Bl~F6Ur^>15Yr!38PMdZ` z8MmmWV=#!BnDGRGqni*KHgFoh)4h+Z98TNmd|x?C578=BCO9%chmBaL^9Qv(L75qz zq+;9*UMjTq-3-23p&!h;hVLmZc`qHFzJ~9C$eHBzT+%hm$B!CbG;or=DtDB1>V*Ew z$MwnSGbejR=A@bF+2hPP8IuN%%(0KRFPoS(;kucVW@HyFtH>O)baBauvZZsUXBS;} zO?FM~%xUJ4nK@%d_bbgAS2StqTu8nTbBz>H`lF9vF{qU@d1ti^Hx$ybW)`0ySrU6^ z^NHGuvwGmq@$qb`uPJ8#Vh+y`vue5#eWq$LPI!1Oe~wv`a9=yLPoAI0uTbkdsipIl z*VI%SOg5WU*$A^~soRJQba7y*+pg3SiiCIPdoI1URIvu7v%6b{Vl7)PV zqt8OVYqP_fvWS-o5*HZxLGm;MbLIexX*nDhu+ZB-jQqdoI}>T0$2*GnWcm0>tVc)@ zf2FP4<`(l0bfV2eSQ&Ttri9N`yqQiW{w#aDSgbiE5H)|zCX=auPBtW`@?$|P<)s7? z_iKQ`WlrlPubfYoQ{yNs=dtcPt5#(<<3>{jRo>XaTt!=}8Y-=bd%;TO%V}8@s$Mz& z)t=sh>QNeYl)0+bhW`&QnEB`EX{#fd(E?Jf^@KhPlcffxe#gaQMH#}Hxxkx?dAn2) zZb}7B*FhCa%`>kpXTegzKf%s3wUW>ewl; zat--6@5yyt`_EGgVs>wl3q93AAwia{i25hd>gG&A?Rs=T`8W*;dTH&iQZ#I1iNiD?(D( zSDkRIMtqg$E9+Qx9ktP^r*HF0zO$UEx+3{3vMH6xp!+^4ko!(ET)P4*a)i|jE zcvdzPu<}H4KzOp)(ZmAWCui0QZX5k3g`c;m5T6Ds z1(!QqvM1pw5UF2!3A88?|}14^ILeypU|dE5?eBKE8%$ z71Go!Y)vNJSh7MYl{V;Rq@1RY`N#Pki*9zhuhd?ls*w(sTloL7cVNF2Gs`2AbV2?Z z%y^qDwN*v*-o-GBSxj0I1ApG?G+!Hw&iH3rI%iP^DqJ86tN{b6>(aaUd$nEJnvVnlLWX5_ zsbDpGdLMr;L_pE4TndQmc>`Uqnlnn(M0cgRu$5x{$_~(LL$ip>k`4SL;ci759T)hs zRk!22*lt7L*tW~)_Pj6x(+-wyA2NO*Qp&hMBL3|t^3VyKE6cA-)rz zD(;C(WF5(1b$3jdZ4j|wH&*e_lgS_YJ4yIZjZFG4HSsMTJ`^L?9vTa5i>!x&;In)9 zC)q=UdwG+ZJJ$Oi;h=gs%pRQ{hSEwSO?=0ek)dM7d8|E-{y1^bu0$!xq`nO%nPB6E z*3T%{xc}w`2#$*T&}HI|BtLaOKdVT^spx(4*h8r?T8e5bX&PaZIyD~fJFJqx_WoFE zW5mnII|>ewcH+lawv9G_6E73Cqj;El@itv}nKqwx!63W@wXwdi4|GY9=#7~AjRoP` zitkKl50;H2T5On52)*xXUSWC2Lx`c%8`!u5^MZ~%%=h<{dqDeyI5pjL`tObJMN_r%1%F3JG+;eWgj!&0Fh}?{r>@LU zeq*=u1|LBCsApwnyQ<%KR>I+i?Yz{E6xZv(^_n=j;s1B6vQk#nEYzOv572N%YoCv_ z<8oTiuTgHStboi*SZ-qP&R_}hFm;fSz^cLJ|BCnluU&O!X}=s*Ta?`@13FgZJpO8c zALTh>o_E4`_+yVoMaA<-zO!|;+(^|I?RnzAo4e0@(h0?MptSGD``Z{@T9nmNYA%ys z34h*;8X(MvE%rbSO(db!yF0lcnyJ{8BM}nc#KiWbLMbVfG42xsg}4RUkEC@}`0;Rk zfHV5?a6N3z)p)yd%&ylv;`{SWQ9NHy>p)~-7dZR^O6x-x`JS+G3Zkj3eRZj5Wp|gf(nBv$xsVX420o#6 z8GSvvX}g3jtY>=lQY;U3mjid4y{5yT;5?}PO8&s=8no4^3xUx9zRtpRLY5 z_kNd8zJyEdoP^D9F#9~~-d7OXw|WQm<5;y{+7QNGFnk^cUyc&miiI}?`%zq)kwLql zVuQ%h!a!K}GJh|d;CmiZ0LQ<=n-;2EGM|;b5-cy!8n#aHi?jzW6imZboJaF?!D<~c zwGX~I9onpv($K7{;B0Ny?gJZbPL3)QrIcV@&@gdoVQ7jr0pjpyJ9d+~8`x=km{g;m z;M{D_3bvQwd}Ck*YW0m;bCQ}5m~LNSdiyz^c$E*9Oj~&MHLSKngNkDU@lZ^dy8ND? z-|{&+0vhg2hbc$V^E~Wz{xN2^(JZKWL0I_08pL;psc-Ou1M)ge*f^v$uM?#J;}wB? zq0MR0exY8il)${w<|L`U(pI+q^zc$WOsw%z-Dz4q<%&-8p?rI#R06Bvmb4#g^O-dt zYJeMYPJ0^Rxgke+XGxOY$N4>QGEry)pB>|)1LJCNTs+1nN*)^={<**m3f~{+&j)5G z$Eo-Dwv0Zks4BEwjn`^uZn3IS;PaEskUv?KF@1lx{xN115?c3o z)sQtl+(9gdU@SAij(16%o7sr&bJwYs!Ej1Q;6 zg-&8#SsRGo#z#_UP&VKk!EiQQVEAE*!x2|)41(%JAsHV3lJ8iBqTGif2tG_M0Y9)5 zg0*s~qR@&z>bHM)-6J`E2-yfIfA!FqQRh+ll!vXmoX74Q*uO3(8yG-*h z=I3#8bv~|EaY~zydz`R!EL^RYs}F?KS}Zh_Ps2%Azb8^)smX}`>)|NuAPfl%X2*t; zC~@-sykxab!@ez9NsS*5IWTA$Pg`^~-mwSBg~zFV){=WEp0S6c_Wc$62bJ)&kk-8^ zwb+O11$&{hKqQATz98uG1>eoFC_%WuHwTp(kXr2I)mWEXVyV*K0uQB4bWImHL)uSq zDy>vbjvucuK;qOBRafH~dJ?A|=l1y>D#fX%(R_c1eu`61lV4SF>S@Bi`RO|xsX}|{ z?f>;cBoutWqqf{jh%X2n9^P&-R%4p%@Cr=7VrqY7Z{Zndcq+;EKZ--^K8Wp0}F(9=h zUsc_MY7k94^O3oNR369a6KN~4q|3QNML-Z?wKe8Sx%l>nLHHNmY)(sy-0?oJ1I?ZH z5EAf%K?Met)_hy826OU&O7k$W&x|Rl@%=EB*uzl1x!VJhS1 zyYozsAI#GScJ6~v_e|E+V4xnfJ1>*_%tRI1o#)|vXJ!6LXV0^@?p?RqGvnwr#pRkw z*w_uWcMx*n{;5KZTDrNe@*^{4m?iYy2s>S=zx}qyHGP8HF-LS$~RoPgh zLHf@|-?A6vm9u|q*ic<4Y+E4Qr7Xw89mQ&PqY4Gq=G)PCq0mN9>usbVXzeA|Dmm8_ zkDZL;2Eeq*TtD&fH##xtR0up#B!pwZffzVeBrKo>2g+m%H5OZKja@pW|L`pqty$+8 zCKn6e)1p5`vI!U4u@|U&U+I7NHlbR5AlP0abaBip5#psnondY}$ZoaJdfT00i%ED? zaUhO?r9y)A3wM*1ePvkFzM@Q!YL|{J7n0=Vk}$X%Ayr-CC>AO^ods*+hSA=|+2&&}c8<}t*56QJukA-<0<+gDR=v(}cC!@f$a4zbsSCB9xggxTEhcF+aG`Y2s{*ftIe6QQ#+ z67IA~n<=&PP8v_*A#XfM)O#TvhS&vGKGKn2BlP0tdAW%cJ4qk!&^%AA*0Fq!y3J18 zMv2EaM#ITxup`dHGf65OsufIK-6%Ktfj4OyB_5yFnbuVfhtW%g;&3^LbD4Pjj2@2d z!{X>{&|j7c>!mdRyO#-e<(J`j1lCGS|AJ(~)aAl@cGPE=3j^hKJS&VglL?89fhk#h zKd4zDY*D6s)a*I!@_&_9 zV+r=KM|n#{k6bfhy|w9wbb+EFG87I*kX~^37NG|WGh+G0i?=u*D7GBa!`NGe7$0!n ze$r$vg(V}gO4nW;vhZQK$kX1s6{912??di;`c{b^wT@i=O%IE%kOZj<$lfa$l#F^p zNP_2Xlcr_&pSxX%2~4TWwA+O%(v8Z$L-3({iYniNMRy>j$>aHS*mDQ!O56)1c~!rP zQKL;c{VPqy*VI-TM~$zYa!tXCtm!MV%O;JTkUKAPYSz-xnH9FOIrFC2?9=*88gtFq zakG}sT3kG*z@FKEQhCw5Sz}El!zU~qFlSz7&CAqz{%TRB!*OR%Rw zn%PoZSzAI=C1B24VUL1M1m7vVs`%5}&HuE1op4z3t;u%@#}t3+yuR7DK3^}qt9(+s zHVBGVO|W32^OX(UB;>O~25RtCU#`?L%&vlh8CX(e`zEJK+pbaHt+ds`sx&NlxoETS zIlDzu?iLc%`cJ4^891Jy80!}(-ZLaE*Tpw#m6qk$;^f=A@$HVoG;LFwCH{`ZI{Vx!u>NpjVO$7&a<358 zY8QZWc$=Ixxg(`obuZ;6VoU2@VwFWk0CbtHi-%MYr0UsjWt)B~efUf?=?8P}6Dp;0 zNFUuN#LGnvCVJCT?gCNw3%6(s2<=-1+wT|lXjP=u9){BOj)3*B4MuDWZvQ+TZhugCl+7^YAz^N`OoUgNO3X$qk_)G1Q}t#I zmU;gkzvNSycU39v7{66$D;bSV&d!7db!pk+s)vQUDMgORZ9*ESRv^uX-NZrVceQC7 z#faCi9}adJFnNgT*HvLA7o5dTf~% z`e+j)X4a!ZA_zsKOHdY8x9r;%wmvE(z>V{Cf!~_Dib*0I?vJO01oeV*WkM7bK8E(; z{X{2OR9j0(yEd6=8R#HDN)A1SuY^)E(QN=U%K-G{kZfhhMbWWhGgsG$k*D<%5#f~Q z7VH$t<%)fk3BL|U?%%<)NwDEYv_@jL<<=57Ux047sa;Wj`Rxf|n*SUDFxV?~WO@BFVSr=plR`fZ&gpeQ)SS}AyrT?R~HA*ny^H$ZMU$tqS4JmT~d^W zkd!JXg11HOU(~#S>2yRxiMZo(G$ig3UJJmtea^V%zRPkApe4xHm!@}))#RR^1s8{mxMEn@7%s$ z$YBlFhxzw}Dz=nkFUGyMp>OEx{Q~VfDLG}uz8%`QOe>kIu&ScOY^$bD9qJ}5t}4;+ z4>~@68PnX@zPoGeS6NGHD=80#HTPk$LH>YnQaXhm>BtH*4+^`b?l#|LauIOupzt&e zKvc@e@p6)Ghm?j-K(xM|LcL|LNpwAMSh$ZVXqhV8E$jZ#Sg{C_t+>Sa zBSKQs9#*^FNP&4r1gZDcGjDcqjQyw3lT)i{nax_qH63H>Td{D%>%w1(JM!Q^h0c#} zc|%a%oh@$)zsqY8S6MA(R;yiMx_B=ZK9}yQ2W!*wIM}NW8xIzh@|n=LfbRv{=3^1b z$^w3FjOS5c!&|~dc2V3hgQ{v{O*up!z&pA#6uqnO|4UdWH9<>JI|#N_3NgN<7JXIB zow51{bSB^Ww(w8sZ0G%3xLJGSyUUelI@$`k44_@aS@Cz)h;jQ%cy-0e*xO;*J812l zm=+5c!cphEZZ+37S#vCJt;3@{>^}W2(=hAb6%I7LADiAzhNq6QM;!yJjtL*rSEQP| zsjW%CqI%(vh^9bPi_wBktBY8Ja6O*%lgEW6GMp-OdJj*P^;CLjo-P)KzAqHZ6ISQ| z=vXT*r%VMCS13ba&lmgLxjr%!Tk$GLZPA?ns=;>}e=0vD1|t>hX!b;G!(O}Zb;d~G z-p4vY&kxWz#~T_6<39+5W6R6*5>DcLD*7f44MI(2<6JHbzNK@2Wx=_FKWyUNqBTE* zQ?R}nRyc$0k8s^#(}$?HKky;iD}DY#huHIT@ZXjiNTgaqh4ztpA=Md#ZYO!*ssa09 ztvrE*RzHf~zpW=ELe*V08ctU_ad}OZ)DQ*xjD1Qan*$r1E#&%mW)aR`$f3b-URoZu<;Wi1mX^$B7JU}uD`h8<7kNZ6knjLNFxg7aPgh+P*@y9+RB>~)8QfV zIUx=fm0~-O)1ONG*@0T?AP%hW5I_4FL7OjxaaVk&6LQWGqyL7OMv zg54VyeBF+Wv4`oIkvV#v5!!LGTc7!}!~h}TtdKgw<9yYPJy9&EUTO$Hm~s{oJR0FPe66bP zZP<5C&^xA|Lx&zSJ1h;tJx!^8;k>}J8W#RteF*(UIL9Vv_g^7Praw4_{ud!AvOmGR z|4G4TD7+w4$v$$teE|uQTzp^sitaR87+KAhR1f4_`BgZ{$U6UATEstTqFegDP&pMd3q*0&F$bQU!PjdKX6iff^j1XJoVasC^nouU;dgvKB2i z71tPycDuQZg-rJnwD8{9fYJYqKhgKI>XI-kAa3z5FA4kD4(<3;Sg4kipuH1Lnv1Q~ z3dI_d^yr~}`ViMnOqxs}|1b%L&mQJ_!KUv>25kH{I(OeK=Tay~ySG1y*m8ulyH;Bu zww@q)AJYif_y!X6fF98a*jY3K_WToBtf9Xy3hFPTW0msR#;$<=`MbUC5V$&ec7&s5 zET*#l3gVC7eG~U3>@-nOFsIq=p%;g$-n7HCR`*D66wpR;*zq$FwpAfggY5ju-^%md;F~i+_P_q20-Lm4RU2rX zdy2=xwQb||Vp?Qd3L$!*Y7DJcfF6h>&(jgqyhf^5sTyBjl^HTQG^kcB()ELXbRat= z{j4yGbkuCIt$P1qWfb{U8tj&iB*v*UtH=^nZc*(tOB>-=z2SUEaz9)cKl$fs^e!iBR+ z1o=tWHk9g-&nIDN-1;Qa2_C%%W%xG_B8H&;9ug)}9Phb%NRSVDZ??M3^g<~m6i%j+ z&f?)Mp>XImRF)9S&=H;>50Y-zc=x6Z!(w4yk{8Mq&D7mu^g$rx3jFcE4|29;yw`?UT^VQa^ z&EHj~MEB_CHC!A*y_OtIhxl%!lh`gk8YXpf-iRaJNNk}m#*RiGSrrnXz6c}L6jB7M z>(PMBFVX2>Xm`ASw52Unb$62TpYC`cs55D>%uTYa+$_2FX^2kx50!i1Xy1c`H4EJ$ zh~}byf-E7G><@^+i*JAhsMU054K7+!Zor%o?1_6P`VJW)D7`n?#SH%@-1Ot#u1;Qrwms%({_g5Xq4wA|J@SS33qefc0z}D#`L7pG(d2oAm zrMZS>k+_}9i@w0Fc$2e``!f%-Ju+(T+Msb}}x4GgR{7dvAv z(K+MN{Fd<^mjV z8%RE84+&9uVPei>;r&%8S7U*YG#EGF@F4PHKsfT6!Q@4HG-|O(9~h<0RD)6BzaHT_ zH#Wa39Epy-hlh{{>9SdKaC07+qn7c2N&TvPgH2*6wc4=vg8Tu~z%*>GL)8wuZW3|t ztYCO3j!VVhv<`Nc>ry1-__cqK!Ubx|hT6WTV|WAC=yiGnhQ%=$iFXOGe|;##cjD>% zz2N9tAySN(FM09g&Gwok-!+3`ww4yvw0)`ux3CALg2j2?1g-kQUXd%qN01}*3aVu` zY1usxI?`#~W8j~_wvx^lGpJw8@7{#=a-NV;U)$-J1junocGk zB%rC0xnA-My-)9!MbI!Cy=hDiy*>uzP{dNiGXFS+q(H9Euz2JIa#7)Y7&4Ja z5&7YhNaiqahHzsXL0zQ4%1J~5F|L?Qvb22?NVW!7wM!6^y$w|BnM{r;RB6YyDWnZY zF-Qy$OyJ%1=Dg$foW_vWA`C#f-dcpw%b2yJGd$4p<2{=dUB$T%1}h7Xa0(Qp?0g(7I? zn%Zrzv*}k|BiZZGu=5(!*bo$>AV!{WR9$OXQA`ox73eN?CCuK#_BTihHj2aR<6*)q z@`5jpPE}QdLF!NrN3zbIVkz-iwa4VCy0WL6|QKCSNCj{ zVx<9$PMeW^#lVF^a#XRICd`wyS}IpG$ymS)5gjBhA~jNi`mv9>7{!iaddshpp7ufr zd}$hdnQ$Pz;}>d&>+3JJP8TbBsWHsIT?&q7~Hp@}5HaZ-PlNnZO{=s!XTn~Ly8>5gm4l>wUZX`878GG9ST&`Eb6oBy<# z3}!%iHM3IN&Ju@>juFR?iiDYq$+wF245}bMQZCvP(mzLlW zgKQ*^SG%pMItc8zjzl{~T}Of>SktvDNo*jF%yGj?lEhIK6$|}v3V7psGF=T@o^khQ z9S6w7zs-bl&|YIee^8a#ZZcSmHD+a_8kbaNo{2-NFc)@JlCCRkd=HuQ4PA6htY53b zKGbE34+OyRW$3*aq!Zdh**T#f+<7DE1D0}J@H;n3j6{lKtxdo}PYYLJX`CKoFdZf& zN!MOI!BW*^bZ(7;uPyA$CorBP{&N^6-1p^UgnnsRa7x64y&r3k8dpE`#Rk3~mkV1B zeAhxvRzsCeRTrQ~VthH634R_-ljT$0i^~yDU7rDcmZ972XgbJa3sKMAUcN zmwV7;IvN6M{lTkcrEB0gJnnUEtr^aLh^wBof`o|i`%+=m3KB2wIT{W7R**sntrJ42 z;x|whjlf?qcPllh*}toJT4CcFa#?!J18+sOdGAf6uYw=nzlyv|C-IN1IjpNG+d%v; zX%YZ9UXQNZ-)&(AE@J=PlxSyV1#V-Eodq@&a5mJ@5PvKdRA^frd6J!{5S2)^A`+>)ws&Xo;lTp;2hRaZ#ok={nA zGc6$9XjviUkVO21QQJ;Gb%fb>BlEzt85GWUOK$9Q?P2r+L>;cVm5-Kt zBHUxUhV~ID;1YP6XaOGz!E2xen$u`nZYpNwwN~GRM>O+ZEa7v~hBZ&t-b)pOq)2vP zPbQKu=&}X>k+y|&7E;XiEt$x{f__CD!OAV@C0V-#d0$N~p8{`hK}~}u{ZDSK+-y!` z8D@>_ID!FDL`8?fSA!7DFkuL0gUtsg@^cMH=Oi(UHhJh+q(E}DT9m4?v^fdribV<% zXwqCZ{IM1%xc5HlnW6O(sC(mhKi8n^@w@I7lTsWt?kaAn)V1e>;%@ycE?kNB{g|$N4Vi}11=%w zQF4TN^0pizL5_&W$S_VVkVpN4>M#==S)n7+Y-rfG3w5o_7r78|`Fp8Q&>bzcOZyS- zxH_C)fWWOLDbf98nw00^%H&$8w;bv23=So)ht_;RXV!EUH2e!;W7{7`In3Xw0*@h%Jd|N!%EV|6s_z!?C;sv->Ge7XhJhd^;bS zAZWYPypgde1=WS?SMlv6{3q6lM$;~iH^AX_C@d-kJ|Q5+z=3DTCB-u?H%jHR-rMa& zI$-t79A|(^{_x6;RNs~?1r5#Hj+Mk~5h)Zcp>n>Oq)Ugfdx?qiC2`|-aq!VzVvvV` z*iWk9#@jJphM^7T>~m&X#6PPvK^-V%u#Gg;>`{oILg81!8w!dmRQYdp@pgN;sj||r zq}D2OZ^giYxd=G><~g#L*|u&RKKm9{KF3lt7{GLu15br-pC_-fueuB6*kRfQd>n^g zAg{~KU(9T?7%L5?_TVDMa*8X}(&xcFE+QWLD<*w13J_w0Len8CtKNkn@ z5~-OxOUc`PltdW=wZP_meSFRDTI36WS5x0_+-mtQw@?tvL(7eK%_1MveRO|sN~TwO z{%+ajd9(e<4E0l_d#5K>9?|#pP6kHAdm*a@`KniEUyy)~t=ku$!1k?utF6qU^&#t{ zC9GQU)V1}oB28tu_0zlVt5%}!{HsWVH%p_BCriWgl}9ADMwQ2*YOqf2{gcLju@5@k zoCPE!pkF;%7l7!*8}&r$I}V>8CtKp>mYTKJh6P=)uC2jdTP-d*()M zJ{cxg$>7uX$tC%p93Ot*A?@Sq56OF|rRm|V6GYLB!*S*W!O9a*EJd>@u!iq*?g`B3H{9H^o+sYc$@;is?2KKbUtLnnz;{bTDX@^ikw4_Vy#eh+9r z342@|_zxy2vV8KLUz1*H0Z0u`ObzA)vL38<1#g@>4}%edPooWiCO|HX`GyRTJpK26 zBYBY3vUgOYUiKOc{38x=d5z?>83*Oxl440OKld%kn4@w6+T5b)=nBV8D^$C{$iyZK zmXqX%R^?yTlJ{MrB(+kpy4su70^RDW?M~~}D`P-RA+J}dwRK8LuQFM_YB}1FQQzKv zEo7d-GIvR5$t~J$aV-=oJad-39RNLJ^*NNWF4@x#_B4=Og`oJh0rSTg6#A|6WQ5|w zw!e@olFHHfzoZskeo6@GA(x4)!a*-~bx zL;+S)E|;giCqYrLs#?fGL$-RQ0B*QUx`-!FWdZh_34-)XBw5V=Pqf%j%Rnq_`Iw)h zgQFJ_XtQuB*KU|LYfvQyGA+7}Vy`n1z+A(JCvicr!GhY@`aj8NHs3dYlA=J=>%pb5 z4w~RzK;AgMJ*&atr&|qM_57D|fL4Qi?!8vW3XS+jhocjxLl&apz*cv^)?ilv16F>J zaKy|9%dWzDURS}6qphHevr0;;JSgD$rOCqT^fiUS`>oTi`LMS;lY`N7m!K;Sh&ZS% zGTI<{2BvaZf8So@I3ur6}ixr1hi%$4nhsAto$U!X^R4q~u|JU2q2S-(1 z@p-#@h@ttykYGqsk{}dVH=891Br1@Ed}kqF8wf-on`F)Rve~a}7)u(hRomLgyvlK^ zj*iMWVzC93hgu?zPN(03R&5>Z(DAD?wGB+w5vS6gci(Py-;&%HNX9>R_wBpy-goc0 z=iGCCzn^^pESAz2Krq6j8^&XMA}KKtyRDITSKgwM@0y}M-zo>$cEA$wm)Aio z-ZD<{8WHK58Dv`AG#oZ5p>8h}H#`+{&5KC-TPzU!p*q(gonJ^_vYAWNx{Jih`s>vr zL%~hY$X+MDx{xx%B}a%omn00{ib}&!!Au)f`ZY9>>C26WQ|x|U$HNQS;aWj1ml{QS zIRS$E3bRY^Cc>?nv_QOJqzBV9Bh2RQz;25m8M6k@E44 z6zGb2X7P+Q1*=oxWi6x4Tf1hATLLe!nJ`6g*gmJQ)VtRdB+HZeDAc||$VJv7%d6Dh zkF|YdV$2{c_P50bPYjkM>sCGZD`MVmN`rAF08czeRZRX%RJQlSOH@73uoTkfB`1CU zMN0c+Wa;AMGA(K|3qM&3iW6{89VLTzq{I9qzem&IQ|*0`yb zi>qWLKn8x00pb(@ppl1{=WfMbS-g~(-}m6Zo`as1az6QeH1@=-;93<(Cq);jTC(_)~gjO2+2aVtUOILu6d$x z&td8hVKRw8%7AfqP$K`c74W2N_ik0WZ=tK1rg^0AHbX)6<12w-{&}<$voJIs6UC^a zP?dsre+LwPjlHYj(a~ufOfS2Z)irlfeS(=DU#>l2SH|W9e>EwxR&s4h=%V0P(_G75 zjf;3_7~C@QKg8A}PYwAu_5WtPJyER^YQNL&b%Z5hG&fsI9+T=&a~Xzu(&g|YlS+6r zKt5CVYB(bAHPXs8ur7+ZE#er4aE1Qq{(R6RGUE;r5_b4=*?93XF#IWj z`wQVC8nz|qUkB@EMcByQYGhikEXB!5bAaL5j3*Jp|E~1`lPH4m~17 z9Wdd^BKUZEyT@SVv|!9MBg6KN$WHwZS*(KLb-bS7=h-c65+9$=hmH$#s1tVs;i{_f zVlmNc(1_oxTCu*tDIA&hW+5H88G?e^q1~8p2e&{VURmD3JL599j&(+(q!8P01tno- z-vHjZv99}^y+o5dT{)#Cjh-l|5rgCR zP;K7nGCJXStWUQZzbK=bGc#RXpSP}IlJXKx1m)YTrSWJ>DahESW+y+ z$o%-h;m)YjEyl!h+Wi<)ettP*&IgL#=OPZhp#1dtdnuprLOHnDW)r4`@exV$*bS69 zrsI@+bXUNW5mAOM){v@ppy_f_hF3cmvk4xqIRc^v1F{Cr4QSg!{_?RZu&K|r(Dflb zJtH2vs|qaGTn)P;y6~rJSd}}y+w60z#hc8bju6948uoue%@LM;F^<%bO4FXtlkw3S znoX-F^{J7vBY3_B&d!VV5iZi9*Ju?LZoFHoct%Kt4{_PbT4Qr{`i|g>Ryd`uNR|sg z!wLIfy*FcF{LL0{vpJAG8e4vc`H1tJqYBf5Su*@7J~oY3YVBD&?b2&4Xv8koDf(#6i8?yrlkw@prosqe|g{O zG+fgNO*|V)rE*%;a{eM>Ff~!cV|RA=)YE4!QK}kk$!R25yOq=ovEpwxO$qcS;jU&n ztj^3J)Wn_5unUb%0s~X=g7z%l)`Md<$doc{kgA;5mbZX4YT-T50v~B-`{CFOOMltotu$xY>Ie%F z59fE9dfa%Sf*_JCE%vh=a70P&G8Mt69uZR2mCDLLOkPsBRar`$Fp{YX7>WCpK`CA_ z3VC=_8<~9uOKoZ+%eCeq`Zem*{A`=ek=gRxFsWdD5#KO-tL+Q&){sImZBii9%#`8f&MTtH;a++Q`#^6u z3KbN$FfB%K03-TTFd?rwAWc1lc+LSV$;msA(za&9Zaa=$CeN>@nY@El-S7+>F3No* zVEY1H;=vx+c+Ht@y1C0FXVFz_fH3K^B^QaF1geRZ6koYu9uMX6yn5Ndu=9x#VU>K1<)7enwr+Qg)z2K0O2b=js@@Rn0t^#HF$C15gMo3f&uzMu zLNN)%3t6^6O?hcYvDGuUu6%EO?fO8qvC!CBFk-Q`muYK3-E1kWtXO+{VReVqzXP)$5;CQ(7Tw$Fc;s20aWr;3L`p1y&m9LKPKet7Yo*vNuH662SD8uxNdx_{@IAO@%wzj{#!cn+> zz|m>*4cNM%F+I2fE_4)n^OTW9jb>~*Mr_pGwv{hAa3vBD_Y;EvZ z)?0fzc5bV3bd}cni&}SDy#BtzN`G_r23&N%K3S^2Pk*QYCyMAW>L#4l)B_ z5E0TIzS2uXNzsc+55FL)8TA&VMDz#Bdg#RnskeM8^7-@f*?nNzZs?XgI%bJFoxqK#xQvn4(asZMOop^) z@gEn!D&a?Axuw!Un}nYNhe6SacnM!S@L!N_9Vuol z)fUVQYW9a@p)w`bkUgL#af?L<*depz6dcFq> zj|c@CeoFlFZ|?~TiduyNoTQ??8R<17!ujm9cPf|9hXUg~7q^Y)tOYL>8}Xz?G36?x z?2}WKY|LK@u?(9pm!xRWl1*od>5L#+3bdaem85AZ78R1=F>lE_6%-t0-^|E4xbvAf zjJ7`#EA;+qQA@soGgt9;bft}4Z=uUu { - const guild_id = req.params.id; +const TemplateGuildProjection = { + name: true, + description: true, + region: true, + verification_level: true, + default_message_notifications: true, + explicit_content_filter: true, + preferred_locale: true, + afk_timeout: true, + roles: true, + channels: true, + afk_channel_id: true, + system_channel_id: true, + system_channel_flags: true, + icon_hash: true, +}; - const guild = await GuildModel.exists({ id: guild_id }); - if (!guild) throw new HTTPError("Guild not found", 404); +router.get("/", async (req: Request, res: Response) => { + const { guild_id } = req.params; var templates = await TemplateModel.find({ source_guild_id: guild_id }).exec(); return res.json(toObject(templates)); }); router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response) => { + const guild_id = req.params.guild_id; - const guild_id = req.params.guild_id; - const { name } = req.body; - - const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); + const guild = await GuildModel.findOne({ id: guild_id }, TemplateGuildProjection).exec(); if (!guild) throw new HTTPError("Guild not found", 404); - if (!name) throw new HTTPError("Unknown name", 404); - - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); const perms = await getPermission(req.user_id, guild_id); + perms.hasThrow("MANAGE_GUILD"); - if (!perms.has("MANAGE_GUILD")) - throw new HTTPError("You missing the MANAGE_GUILD permission", 401); - - const template_id = Snowflake.generate(); - - var template = { + const template = await new TemplateModel({ ...req.body, - id: template_id, + code: generateCode(), creator_id: req.user_id, - creator: user, created_at: new Date(), updated_at: new Date(), source_guild_id: guild_id, - serialized_source_guild: guild - } + serialized_source_guild: guild, + }).save(); - const templatenew = await new TemplateModel(template).save(); - - res.json(toObject(templatenew)).send(); + res.json(toObject(template)).send(); }); -router.delete("/:template_id", async (req: Request, res: Response) => { - - const guild_id = req.params.guild_id; - const { template_id } = req.params; - - const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - if (!template_id) throw new HTTPError("Unknown template_id", 404); - - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); +router.delete("/:code", async (req: Request, res: Response) => { + const guild_id = req.params.guild_id; + const { code } = req.params; const perms = await getPermission(req.user_id, guild_id); + perms.hasThrow("MANAGE_GUILD"); - if (!perms.has("MANAGE_GUILD")) - throw new HTTPError("You missing the MANAGE_GUILD permission", 401); - - await TemplateModel.findOneAndDelete({ - id: template_id, - source_guild_id: guild_id + const template = await TemplateModel.findOneAndDelete({ + code, }).exec(); - res.send("Deleted"); + res.send(toObject(template)); }); -router.put("/:template_id", async (req: Request, res: Response) => { +router.put("/:code", async (req: Request, res: Response) => { + const guild_id = req.params.guild_id; + const { code } = req.params; - const guild_id = req.params.guild_id; - const { template_id } = req.params; - - const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); + const guild = await GuildModel.findOne({ id: guild_id }, TemplateGuildProjection).exec(); if (!guild) throw new HTTPError("Guild not found", 404); - if (!template_id) throw new HTTPError("Unknown template_id", 404); - - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); - - const template = await TemplateModel.findOneAndDelete({ id: template_id }).exec(); - if (!template) throw new HTTPError("template not found", 404); const perms = await getPermission(req.user_id, guild_id); + perms.hasThrow("MANAGE_GUILD"); - if (!perms.has("MANAGE_GUILD")) - throw new HTTPError("You missing the MANAGE_GUILD permission", 401); + const template = await TemplateModel.findOneAndUpdate({ code }, { serialized_source_guild: guild }).exec(); - var templateobj = await TemplateModel.findOneAndUpdate({ - id: template_id, - serialized_source_guild: guild - }).exec(); - - res.json(toObject(templateobj)).send(); + res.json(toObject(template)).send(); }); -router.patch("/:template_id", check(TemplateModifySchema), async (req: Request, res: Response) => { - const guild_id = req.params.guild_id; - const { template_id } = req.params; - - const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - if (!template_id) throw new HTTPError("Unknown template_id", 404); - - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); - - const template = await TemplateModel.findOne({ id: template_id }).exec(); - if (!template) throw new HTTPError("template not found", 404); +router.patch("/:code", check(TemplateModifySchema), async (req: Request, res: Response) => { + const { guild_id } = req.params; + const { code } = req.params; const perms = await getPermission(req.user_id, guild_id); + perms.hasThrow("MANAGE_GUILD"); - if (!perms.has("MANAGE_GUILD")) - throw new HTTPError("You missing the MANAGE_GUILD permission", 401); + const template = await TemplateModel.findOneAndUpdate({ code }, { name: req.body.name, description: req.body.description }).exec(); - var templateobj = await TemplateModel.findOneAndUpdate({ - id: template_id - }, {name: req.body.name, - description: req.body.description || "No description"}).exec(); - - res.json(toObject(templateobj)).send(); + res.json(toObject(template)).send(); }); export default router; diff --git a/src/routes/guilds/templates/index.ts b/src/routes/guilds/templates/index.ts index 80dbe5f8..2d8cdf0e 100644 --- a/src/routes/guilds/templates/index.ts +++ b/src/routes/guilds/templates/index.ts @@ -8,23 +8,17 @@ import { check } from "../../../util/instanceOf"; import Config from "../../../util/Config"; import { addMember } from "../../../util/Member"; -router.get("/:template_id", async (req: Request, res: Response) => { +router.get("/:code", async (req: Request, res: Response) => { + const { code } = req.params; - const guild_id = req.params.guild_id; - const { template_id } = req.params; - - const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - if (!template_id) throw new HTTPError("Unknown template_id", 404); - - const template = await TemplateModel.findOne({ id: template_id }).exec(); + const template = await TemplateModel.findOne({ id: code }).exec(); if (!template) throw new HTTPError("template not found", 404); res.json(toObject(template)).send(); }); -router.post("/:template_id", check(GuildTemplateCreateSchema), async (req: Request, res: Response) => { - const { template_id } = req.params; +router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res: Response) => { + const { code } = req.params; const body = req.body as GuildTemplateCreateSchema; const { maxGuilds } = Config.get().limits.user; @@ -34,9 +28,7 @@ router.post("/:template_id", check(GuildTemplateCreateSchema), async (req: Reque throw new HTTPError(`Maximum number of guilds reached ${maxGuilds}`, 403); } - if (!template_id) throw new HTTPError("Unknown template_id", 404); - - const template = await TemplateModel.findOne({ id: template_id }).exec(); + const template = await TemplateModel.findOne({ code: code }).exec(); if (!template) throw new HTTPError("template not found", 404); const guild_id = Snowflake.generate(); @@ -45,7 +37,7 @@ router.post("/:template_id", check(GuildTemplateCreateSchema), async (req: Reque ...body, ...template.serialized_source_guild, id: guild_id, - owner_id: req.user_id + owner_id: req.user_id, }; await Promise.all([ @@ -68,5 +60,4 @@ router.post("/:template_id", check(GuildTemplateCreateSchema), async (req: Reque res.status(201).json({ id: guild.id }); }); - export default router; diff --git a/src/schema/Template.ts b/src/schema/Template.ts index 64ca2165..88e36c53 100644 --- a/src/schema/Template.ts +++ b/src/schema/Template.ts @@ -1,21 +1,19 @@ export const TemplateCreateSchema = { name: String, $description: String, - }; export interface TemplateCreateSchema { - name: string, - description?: string, + name: string; + description?: string; } export const TemplateModifySchema = { name: String, $description: String, - }; export interface TemplateModifySchema { - name: string, - description?: string, + name: string; + description?: string; } diff --git a/src/util/Base64.ts b/src/util/Base64.ts new file mode 100644 index 00000000..46cff77a --- /dev/null +++ b/src/util/Base64.ts @@ -0,0 +1,47 @@ +const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+"; + +// binary to string lookup table +const b2s = alphabet.split(""); + +// string to binary lookup table +// 123 == 'z'.charCodeAt(0) + 1 +const s2b = new Array(123); +for (let i = 0; i < alphabet.length; i++) { + s2b[alphabet.charCodeAt(i)] = i; +} + +// number to base64 +export const ntob = (n: number): string => { + if (n < 0) return `-${ntob(-n)}`; + + let lo = n >>> 0; + let hi = (n / 4294967296) >>> 0; + + let right = ""; + while (hi > 0) { + right = b2s[0x3f & lo] + right; + lo >>>= 6; + lo |= (0x3f & hi) << 26; + hi >>>= 6; + } + + let left = ""; + do { + left = b2s[0x3f & lo] + left; + lo >>>= 6; + } while (lo > 0); + + return left + right; +}; + +// base64 to number +export const bton = (base64: string) => { + let number = 0; + const sign = base64.charAt(0) === "-" ? 1 : 0; + + for (let i = sign; i < base64.length; i++) { + number = number * 64 + s2b[base64.charCodeAt(i)]; + } + + return sign ? -number : number; +}; diff --git a/src/util/String.ts b/src/util/String.ts index 3a8e35a8..49fba237 100644 --- a/src/util/String.ts +++ b/src/util/String.ts @@ -1,4 +1,5 @@ import { Request } from "express"; +import { ntob } from "./Base64"; import { FieldErrors } from "./instanceOf"; export function checkLength(str: string, min: number, max: number, key: string, req: Request) { @@ -11,3 +12,7 @@ export function checkLength(str: string, min: number, max: number, key: string, }); } } + +export function generateCode() { + return ntob(Date.now() + Math.randomIntBetween(0, 10000)); +}