From 656946e04792072430cd7a72f02b04597fa391dc Mon Sep 17 00:00:00 2001 From: JonathanHelianthicusDoe Date: Mon, 9 Sep 2019 07:09:32 -0700 Subject: [PATCH] v0.3.0: new -q option, updated logo --- Cargo.toml | 2 +- img/shticker_book_unwritten.svg | 21 ++- img/shticker_book_unwritten_256x256.png | Bin 27064 -> 27098 bytes src/command.rs | 102 ++++++++----- src/config.rs | 9 ++ src/login.rs | 67 +++++--- src/main.rs | 34 +++-- src/update.rs | 193 ++++++++++++++++-------- 8 files changed, 279 insertions(+), 149 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f7d9237..ff0cb12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shticker_book_unwritten" -version = "0.2.0" +version = "0.3.0" authors = ["Dr. Jonathan Helianthicus Doe, IV "] edition = "2018" description = "Minimal CLI launcher for the Toontown Rewritten MMORPG" diff --git a/img/shticker_book_unwritten.svg b/img/shticker_book_unwritten.svg index c30eff0..a850b5c 100644 --- a/img/shticker_book_unwritten.svg +++ b/img/shticker_book_unwritten.svg @@ -29,8 +29,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.70710678" - inkscape:cx="419.71809" - inkscape:cy="577.92742" + inkscape:cx="228.36795" + inkscape:cy="369.35229" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" @@ -49,7 +49,7 @@ image/svg+xml - + @@ -419,6 +419,11 @@ id="path977" d="m 125.80613,280.78875 c -3.2071,-1.42129 -6.40678,-2.85634 -9.66346,-4.16489 -2.01534,-0.85158 -4.05987,-1.63981 -6.03602,-2.58069 -1.72133,-0.86302 -3.4431,-1.72495 -5.1581,-2.60054 -1.38706,-0.77946 -2.77283,-1.55852 -4.17016,-2.31898 -1.086635,-0.54927 -2.127326,-1.18727 -3.177,-1.80397 -0.914325,-0.42854 -1.818012,-0.87459 -2.689613,-1.38765 -0.750234,-0.43318 -1.251575,-1.1794 -1.975533,-1.63927 -0.802352,-0.54549 -1.66637,-1.0031 -2.538031,-1.42852 -1.099429,-0.53452 -2.158979,-1.13825 -3.163234,-1.83569 -0.770779,-0.49097 -1.620968,-0.8423 -2.434463,-1.25683 -1.008833,-0.45111 -1.972035,-0.98819 -2.909168,-1.57223 -0.775452,-0.54613 -1.642306,-0.8408 -2.521244,-1.1595 -1.107442,-0.50748 -2.206905,-1.02316 -3.321388,-1.51394 -1.059879,-0.53082 -2.093905,-1.10897 -3.133202,-1.67791 -0.882028,-0.39956 -1.823071,-0.63 -2.715752,-1.01148 -0.892288,-0.45534 -1.791898,-0.88405 -2.718879,-1.26556 -0.923335,-0.47499 -1.854115,-0.92502 -2.747428,-1.45579 -1.012013,-0.55148 -1.993236,-1.16528 -2.945516,-1.81471 -0.981067,-0.61405 -1.962243,-1.22413 -2.925123,-1.86681 -0.893455,-0.64834 -1.82868,-1.23548 -2.756781,-1.83224 -0.868881,-0.52245 -1.678918,-1.12286 -2.490353,-1.7281 -0.652828,-0.51747 -1.35001,-0.97779 -2.063568,-1.40798 -0.95033,-0.61587 -1.813237,-1.35025 -2.727225,-2.01444 -0.954445,-0.70391 -1.908786,-1.40526 -2.865608,-2.10609 -1.002007,-0.60181 -1.93322,-1.30876 -2.892313,-1.97484 -0.982799,-0.50284 -1.738586,-1.31429 -2.596907,-1.983 -0.996498,-0.51601 -1.855213,-1.24226 -2.764779,-1.88859 -0.977615,-0.6677 -1.818344,-1.50421 -2.71381,-2.27276 -0.839881,-0.78114 -1.606331,-1.62547 -2.454042,-2.40104 -0.86201,-0.66394 -1.781146,-1.25532 -2.710888,-1.82025 -0.879495,-0.6137 -1.849634,-1.07059 -2.765733,-1.62127 -0.879201,-0.46019 -1.751684,-0.9337 -2.609861,-1.43535 -1.051949,-0.48812 -1.978517,-1.17752 -2.935289,-1.81974 -0.451358,-0.27161 -0.874105,-0.58445 -1.296006,-0.89866 -2.418585,-1.8149 0.148072,-5.23529 2.566658,-3.42039 v 0 c 0.363927,0.27613 0.734237,0.54234 1.126491,0.77779 0.877068,0.59732 1.731657,1.22485 2.701738,1.67241 0.886127,0.52201 1.793493,0.99859 2.6968,1.48774 0.882867,0.58439 1.898183,0.96915 2.749727,1.61141 1.157563,0.71394 2.315322,1.44184 3.363518,2.31176 0.814032,0.74528 1.562483,1.54718 2.352931,2.31139 0.799839,0.68725 1.546959,1.43848 2.416461,2.03943 0.970915,0.69856 1.912442,1.43252 2.952348,2.03079 0.768816,0.62684 1.470886,1.34042 2.360103,1.80609 0.988773,0.68683 1.951626,1.40939 2.980045,2.03742 0.95913,0.70279 1.914889,1.4071 2.872863,2.11141 0.811948,0.60258 1.591265,1.24774 2.429857,1.81428 0.822127,0.51035 1.640546,1.03401 2.398837,1.63636 0.725691,0.54996 1.453748,1.08664 2.239179,1.5527 0.944293,0.6127 1.902106,1.20608 2.812801,1.86907 0.975646,0.65397 1.975014,1.26502 2.966392,1.89476 0.877433,0.60613 1.791163,1.16362 2.726931,1.67438 0.709851,0.43225 1.460222,0.77056 2.186101,1.17293 0.962282,0.40157 1.906212,0.83756 2.832402,1.31458 0.958855,0.49242 2.101506,0.57057 3.022198,1.16415 0.930391,0.51304 1.861865,1.02305 2.803646,1.51495 1.026039,0.45571 2.049614,0.91012 3.056634,1.40731 1.157972,0.42471 2.297758,0.85891 3.328712,1.5543 0.831376,0.52568 1.69323,0.98828 2.591154,1.39131 0.983279,0.5107 2.023534,0.92221 2.936341,1.55976 0.818478,0.58273 1.698821,1.05815 2.598846,1.5013 1.072361,0.53268 2.138487,1.09401 3.123308,1.77765 0.59395,0.43746 1.158716,0.92554 1.673683,1.44343 0.869201,0.51551 1.78376,0.92989 2.684394,1.38457 1.007688,0.59456 2.007638,1.20795 3.052858,1.73365 1.36399,0.74336 2.71955,1.49974 4.07067,2.2665 1.68157,0.85999 3.37136,1.70361 5.059,2.55149 1.88886,0.91062 3.85852,1.64363 5.78448,2.47005 3.13557,1.26122 6.23742,2.60128 9.29716,4.03662 2.89628,0.86886 1.66749,4.96482 -1.22879,4.09596 z" inkscape:connector-curvature="0" /> + - + diff --git a/img/shticker_book_unwritten_256x256.png b/img/shticker_book_unwritten_256x256.png index efe563dfe681904f319e387af22799d803e90c34..041542ffe7f6e8ed1f5997c1784f1ec5ef277b30 100644 GIT binary patch literal 27098 zcmZ5{byQUE_w^mRyO9_``a?@dcS^T(hjjPQB_Z7@B_K#E-6cp$H%Li$zt`_tzkgoV zV$HzJn)}Roo_o$dd+!sisw|6%Mur9e0H(a0lsW)Fz^4!Z1qpmGa4ok29}wIm#pHs5&jvz|GvdecbLV3TN2*@Y}P3`dR;dWnz(6jJ=> zejG2j&d=Xc?6#~HcsUL!>~(1nlao+{wl6R#n+>LI- zIjb-$f577dI3twH{P4R7jowiLRCTNmCg6*+r$3pMtNy(hrd`<{k8`eGkdKR_4b^H_ zF8L~m^@@K&V8$&LKf4c8>|?>)A%m*I97Gkv-7rMc_N>cgv`{kg86HNFwa_1}wTVQH zH1zYQ=CDN_CNSc=L_!m;kQU8WCSXEEnq0fOas2(qw{I?Us$<;Bf1#wusC}e4Gcz-D zz|U*PY@JISHpT$5iWq;MMbDm%Z>RUQGv+2J^_s<#d(%@>ydIvO`jM{VE@q)EkSNy% z{UbO4+qXHjEI)1L(=3{+a!%>gU!-+(wrJE=%9)p;%XX^?! zFCQPDw9TT6S=22WwXf-n-4z2c@<0|vK%Cwg-q05UqtHBORr;y_QBzt(sp%+i3C?-# z#sx3hqC&sANtZP(4zLOPL&bm;MGj+>u9*`>Sa&^XN_KS`ysbinzoreNmemWc5J;C~ zQ!A=yMPq9kyx|gn`BY?GUTBi-@W%E};rt#Rj3(WD4`Y-nn_fX&$35X~x1$N`3l%ws;qw8L!QlGavDWENWSEj+{pLoJY6runt!hO)h+EvmVwGf(rN_+f zt&6wBI2-^yci4BeYHfzHvNET=y}jB<2RN6am=*|$6}?IxD{WXC`nvjwCsT1(QQe$c zj<15$arP(Ouwj98sMe=Q`X#n`VZ)AeIY7x;_-~_K<6>TVdUHuhNk6_xIX|b;GJwGz zhI3BlPZ=046{^Vm9NLqDPwVf-mT2?kTA|z`)22bId;bibLt4N7-_bIu;N zxc5LQBVzd3huOtp!a<^3O0cFj0^Uz}bj${Cj=3#ZMv)KRes&j7x~cvC5rKiyHC_w#XLtm zALT{y4VAeUec?p5N-%m2%Csx-laiC?JUl$UNBZWug#251Vq06ACaPMMX$AL6Yk<+D zBuTbQ-r5xb(EDVqt7E62hxBjz>n^|VInN-+KocPui0fvJ`YRv4>28uCa7uvTrbr_2 zxF>e}Js!K4Y1=}`jlp+k`1fiC`RbG}74o2rRFx^Fj!f+l;V7+nuJrMj0g!7a^t0(` z&!zdnC<$#{qESD<5&SLzIy!S5I8LMtJ$(UyWEhyr;JPSQ9d`Duw|eS`#d~hwwBW3NK2%OZkd4W!LLQmG3wCyQ@Az^$ELbh#0ft5>N1o~4-Mq7|ImY#b6bnAgQ(!{I7Wnv^K2FAf~ zMn*fy%2!^V1voT3Vs(WYwaQuL*#0`ov)kZu+77rV4n#ymCbo1xf3fBrlNye+=rhIIGT=@jbdMDVb^7W0GD-Vm7lvRyVZb~Z-Z8$u)- z4Mt!ou*0-v23mkpm&^;b3@-ftR{Ts|c<+sh%2JG~wJTo}#qQ|zg+>*HfO#!s@9I80 zWeU4(sno8fudOFCge(ECD+#`V0RCNZ@bOId0}8Z}lJNbG&GUl;+K?J2Bf0?{{5?_UhzS&r0Prae_EdsN>bOr3>QN-nuN)t z>5APh2;Hvm!7WWiu#XYKHzQb2|)o1vPpk5^XCc-)h0+Zlo=7Pr+~wf-u(cTfBuXm zr)q3>_cKi0H&wsdu|b#hy=3eAS5UB)lT6z1BtSBDS3CoUH8{!{u;*(O(H}kaZrkoR z22zJ8NEhFTEf!Ab!0$(gXQa5H3RU6LA9}9Y$+!Z$6|)EDVBw~ED=4_-YJp4V2=sv1 zAy)#$2hm8m3004HZc~*pz-B z1#coT>!!6!l&DiQ=vU7cuKcGQ1TM}y(T*pJ9k@i?__CeZV)65RA{V^&h0K`Jy7M;` zT0~6y5HS)L1|W_QCh1}E2FHv)0mK>63$f62y27t+xhHmF(kObLwJR0DdaXhfTO!!d z+JE*MTqaDptQEe?a@Ap%NK~La#j6afJTF%4tL`sckJY`;eAE>La<%}Tgg+~)X<}Js zOkKlw{+X-y1#t9R5Q9qfip6Se`=D^_Ed=ppAWY8F(-YduK?NI)Mg~$ok9X%hw*K!+ zJ6t>%-q))+0P*Vz2tT)4x}fihyJ%m-5j`1vNwF^A@`JvjL%ETF%90Z~%ap`o!CqQE9mv zM7q#J2(E-U69m-)kxnWiX=Z^@NdWcAkbLs!8eNJ6aora@>(J!k-Ti1N}K>Qyk4lw=Vb#_v8u7#ZWJ9stAZ?S^u8KxB;+Z_X1lCVsZZR(9^x% z6DiT4&|%cKN+TU4tRB5KE1QSpi9iN@szS|-4Nv5MM59=J8gZdCjzEZPk#?mhT;j@7 zfsW4R-=aZrxfgaPg_e>|$(5I`$;VT8*h%l2Vom5o>W~1+@Or{$1O!j&Q*Vq1OQm0i zncBs=ViqlSC-M^=3oZ^=hB=vb@mll*fBvTESb_r>OH$ahDl{vGhljJl%~T##(8V7XkoGTD-A!O2C|^ra6ICWnTGM!-56h(i6n*#S&( zO5@+%VMYc*0Y_(_@(kUll6&ruQXIsR68i;iPH+4SPyqQlo{yt#>roPC@nUHGt^k8V z$yB8#vla;S;uJq2f`>yYDI?>S1Zv@UVjUspys<}|NOve2J6H(UG>$yaIDAfyCB!w3 z@>WyKF0{ZuWHqvL%>e>@W*{ z189bZhco**FjQ8Wx%_bHt=K7R*S^+66w`FzNuSNAdV4;hNKEUF3oxp>hY3tIuC0+m zG2FkLW#j}fp?oTsY{I8JDD%{ZTPI6Zm^E+I=cD;5j{>e3AvrCr^wY4#=*G^i#&BJ& z_fPvo&giFW?s(*bN0vYeKkQCoN`VRW9@J#!_X4Ks5F9SK_^=fDuJRPpjEqJS$^+O! z)AXELh8Rj_rFJDd2wGb~&}tasRi!3wxN9;S|LRccp8?tw5W@ejY*<*id z417Q0@BwfW`|fo}d_^1?is0*vYBIVmr9xpxy}(+o4S~SA zwGr%mcX88B*xT{G2ZO|l(g{7B0+$R&~DU;(`A2p z-}_E$+k7%(4yo#3+5qlV#^gytg4X@o{pCIKfE#XDmX&gacj6?{iUMvAwWtr-fc3a+ zSv@4u&(5D+4M*b7zfYGbE(CAB?0z!=D-1B=xIMu&+OY1Bsa@4iF2}Hdo1c&a25IjQNeok_k*2uM-=z{U&@YWJGyV+rgB}(g^(zB)}KV7L82&Vq?ZqY*yd?OP1W`G!ug8W+j z9n(|$!UrSD4nbKeusV}eD3?9pcDbJn)W=YEr{s(x|DDf8s%npk4IxLxQQ$nRY;0MN zb1JBIx_uqMsbgJT_~F)~*%bXv5cp?;vb}&u-I$t(+cfjm#DzVd4^rf z4QxcA(Z$pN{$SV`;B+zBw=!xnBSr@UdCI>Ay{D}8QM1_POHq2?h#1s%(ckgQF_QqV zxs`n^-I9dk@1#SWFcT!mch`uAlqUPM%NzE0#b69hys#f`-lUpmHY6m3AYt%=qAetV01uOm{6Pe-B(!Y-rS>RQSJOB9+ZYH5;{Pn3Wy8&%2d4w4M= zz}HL1>>RiK0?HtmqC2Ur_4EB=@!O|%CtqmoPmV`<+^??Zi))YvtMJ|1RH*u^npUjl zcX|ojGQvPAE6ao>LRUpt;tRmB4|dP4Zf+jIY#+5ZkpM9l7Z*6__UqG-fOBWx?x&D@ zsw}v9Ca!gXNBP>GssWHQ3XGa2Fdp*1pnBA<)^#8SRz(AF>$PCi4V|idat}` z2{>@#Z{6c8-+7Agq=&z)AKVfspWe??R#YU{CFE6zA_st#m6aRV#r3s|)rMrEViMBP zp*nzEitVfSvztqHZk4AXkR9&X{~~&ehL^!fSMMboJ|X8lYE>s5zrp;P)++=#oVt!r zIHdHutlibgbL(I||CBldrU9&V?QjXT>RCH>=@h}m1Rp98S!E-vzw>@#11lFpc?w@w z`_mE{4OgRSxG9tJ%eE{4d(Rf$htJPAPMdm}i|{u`J>pkQ4*BVije_P<)ATeAW^G+K zV}?JdmQe(6XT6nXje<94lA%zphDGeI-uqldkZ`z|wY#bSb5c#eS@Z~hi1{Kwf)OF5 zu4^gyqm;e3|C2TjK~9=CqoHSX5JH!fGq{Vo(=`$I@+FIsdY;wX-2s&PWtJ~sxh z2VS1{xr}ad@d?Ri!PHSs8>WqToKy$6a}0z6`H4cFBTaAtkZ>vZWCy|Js<^W683Dj=DHau8&LrbB7}*=*$3fc#n&a&TuK z-zZ1oE1wHN0#~8u?RWgDX?&N-7=TMCjhM|hjbT#A7Q(no>?+#lk=aMa<}-^R&si!d=&j9As*MQUNe4^}}qNH7M~6ntj=N2hkpJfCwz?)|pA zt}kSoe(KbV;Kxe|&{y5Ck1zRgO%!XcM+dD& zevzgINRy+IW&{`&^J9C3A0{?zPTRu(l3tFV>W%usAn&1r=@ngXJ_TrMY7Y7N`gR~B zPA`=vS#M6AdqI;gYmT?Zy760*bZK+jw_=@5ltczTREsCYy`;>flANASHy4%C@CMrqi%x@ulvQ^7M9VeKEX<9DuA)NVgGpB^wtnoao(TuFJyUnPt& z#FJl!QU9hU7~%&Ap3%y)C8!cYihf+NREb=wG`OFT?@he{@+R#X^Bor(m?j3KiooWd zI!vh~#R^{{3v9oX=%>?E|M1my2t&ZLWtL{?1*l#&rIzN!#E!1v2@QO$2kM*g=D#tW z2^2vICY-h~f?)?Tp%P572Te6+l1IhCcBJ0ZDC_?LzcQ6d?_*-neEj?#Jb+^)9L6CV zcIdWg@#HOUNO^+y&!>fht9up3k_$gk2DzCQ+o=S2MDNqR8F+H`KX#A(q`|i&ZhF`p z8{A)i>hYUYkS}G44zOds@MS=q;coMA)a99G(MfzMO5DFKd?0%5?yK}fN{$h6#yaX4 zKG*qPE;S>G>2YW4zXdX<&cK5B?j`))rGOwAB-W*scuu{rWB?}Gb}a$}C( zat`}ljS20M!<`?HO`miUh2_y6xo-IVou9t%DNvZ6jnfRRzjn6#DM|_)sIGnB# zGHo3DSNMma!~E2v$ZwK-+2&YwcaGP)XgMi<TVw zv_e-dGKLWgQdUuGB1J*s;u{>-lW&EvM<({disFsyFDqE#D)!?DG)&Yb%*EGWk4ILdh z)%q>{KRCsX=$z@bgz@ywB&xQ(TC!jIDGs5IT>o?^HNoWPZ%D#txFn0CZp;^)Kz+PJ z4x?`W6w)l>F5-vdbtWQisSzxKoBi6z`^KdQv+0q#O; z!E+b~7$-G4hErvX*Q}#h{9WKDr%VlQH2Q(>5x4x^1Mxkr$Q0ljfBY5bgh>C=Cd_KS z9}tf&%UtzqdeSs%xxJ~;U+Mjio9h7jux`ZHzv$$mPQBv5uDNP??SVI+S2Z8k0l4&i zT1Zhh68{A)q-_uOxxI2v6hCA8!7z5> z1U^#ZPuh=*6se0uxRH1Tl5$FUa=){U!~1>Qwfb?Gl!qTQRLx(@&8UuWc{?bV)f?wF z;o1Wr(m3g|G`MoH>lO}qXx@dZ4jq#3hr|DU)Z(V(h$V{JBkNj9Th<< zaH61ta^+;b5O+V>m&JYbe#u<>8u>MT)D}~A(b3Nejq+h`%$ZT904YoChb#ZphOh-(!s#Nth2eH{7%}?U%hv=7_<~tG2KaSp>70U2qtm33tnTQ5zPDi|{3k~z@qt8z zM^q@*As7jwF7S(78WOqsN|K~qG^{S}VpU(Q{8a-m*{_X97@d4<5nGQ-#Go?VSFFl-edF~M#Rd4bKO?M}cTUT$FvzV@t;av= zqtkHK7w*oeAXA#tAIMp`Amf?WquPiHLiB5^z*dnD<^ev# zwr9+lcTCM>n#ui6p&P1wgF$>clNMj{yJY|ETQ7#L zKFzsFH`X}8rv87>*!Bm>ds1QX0%%@yP_H0wf>MfTR9!)9SKR?J`O7FF6g_KSQqeil zUVFuqQWN<*zm8!+@ozN&uSFKzxOGSTtSQn)cS0$d`r059hgbV4Q$fDXJNBi8bRHlq zNFgO13~c{->u5edpdU0MHJ{w0YVQ|jI!q9#-ca*|>~H))UGt7jzNg=ORVt0^GHT?@ zZ}v0stCRJ@w#6`3m_5h`AqgYJ3^(WSrA#qEF2j#Fq++;ZDe;!qc$C|u6RhIj6Y>Vj z`}+)6n3CJmbt`;_6?CVBWVd>4Z3!#-I9Y*$6iC+5>TtjLEWj_!`>1-u$eXbST)F6| zDZJS5W{VPYDJzi!q1_w_mJ2LxOUe_*34cFxhTPYyudknp#1VKV7QcZvi*886vLNr( zu(ew{BP{%w&FnWoKtx2pbab8GwxmvY7kpm$P~wPYGIz@}u-A(Xlq~hq&UABOthV2U z)P8(31p=lOA@A9Ot5Tgwi!FQCJnd5*P#&t!r+nISet#MOc7{vO!Xz}(Wwh&4z3-UX zdo8$x|Fim=@dog0eL@8S@Gub&c8Ol_xny)xA|w%K-o?)RjfgBdSgiec0p2bHYtN9O zMf8s^C+l;1x&Pf(1i!qBSIEPaYjac00s|O&V2{K?V@4mw%9*Le(jQNitSkn`2~*_k zS))OxfZFHBI_LE-gk@URvJwsqpL-C%i?kTE=%0Us+kz-)qqll`Jc({NzrX*N$Hv(L z4NfaG+362?+d7^egDC^CVY>uq{UpVcjQ1PJX3mHlKIayC=H^?Kr(8x%s7PuHfuLld zi5tCu$$t0nIHDH&=c#0uVj5BGzIczA`kUM7A-G6$MSRg~E3mCc!M(m5*#EXsyfW9l z@$L4xJXf6=I&`UJ_UtuuqQnHh_VC-K_86bQ%%6mQ_480WbVDQJXK>CCEZYXh{Hz1Gmw;^F@YB(bH7oB@)J-L*FZnUJxD)z=oefjs^V_ne7LxIM?bx@ zjv+lCRpOKlIYnw4@nw*k%@8~|2|;$Ihag)?nOLd8O8;wUeksk|`gU}S+ro|pkqAC_ z3j6O#@1R@d%74&U{M`NHn2_;hKy$PIX7=N-)_9T@u|0JJB(2Trk6RmM6&Ei@k7 z*Ic-kHtajO+n~bU@I<~DG1ku0?b@H_bewjWiLYy6Q^!qC-s5j2NPe>T%Qb8zs1qHI z1xlkB^JXe-pq`#WK`5nMHcA`z*xUM_u^SxNtKtgDL_#u2<2mK}PBvTD^ z{C5IGa=h?_#t;eop2Hu%du?`D*j47(F%MSlzoIra7_)}HR#Bhf3$OMu3djVZ|cYy8XR5!FoQRG9!-ksu*4>$7-Pn7 zB~KJIubVNIQf&lMso?Q&JMoP5PW;DsNM@3y)>)ZW4g|MVaNxu553s?sopCWU2?sKwzlGwri~>;8j^5kw_++ z@glc|iTnoIf}GH16Z{ut@|Z7&G@R8L5?09c{^L(NjJa5}*9`%K_JYu%<`<{ZIiGx{ zl1{MwF%BV9qMrN!L=A5FV2b%V!ApMTZ{C(yJ7Ds<2Bf3%e}!Tn_xjayz&A@Q-^- zY)Qz2__2?^rX-pZKF1o@zm_a8?UC@1amlLY7GFQ?iE`<6>*I{`23+Wot? zRJ_Gz(|OJ+Om>ALK@Z>G!!Gq*%)QI;v&q-C8sE(tZM@HRI{mIn^ip|;uX}LzJVj=~ zrRQDw1A&?u6Q*4`CaON$obYN#_vgq%=sKtFKJFk@el6k9^z56BYd@oK8nLlN z>Ny2cToH97qC>ayf@l1DrFqBzP>&-uG73WdG>NW|ACaLx4ABS(t{qy^{ID1*`_((6 z`4@5M@s1P!&EZQH^(K0BApyDZ)6KZ@Im+i4`O@-Nk zs)wG)Na$5N<5<%R>Xv7_QbP$c#b=_MRs^rqtO578D_Vf^jbnCh5W}zn9$UV}obygQ zP4{+w^A>xvaBSc4#K#Me8HxN!ngbz?sv)9U2|}X%^Zj&(y(dYNfMu^4V%xa+;PBxw z!B~2Y^gdfUu3Me&U)3|9T#fmbjpK^hNA(9mT9Xt8YRnS1ul)9AQ;ROjLAF>3SMG`e zWCEU@Zxj>5H|AL>6GKO!2qTX5`jZDSEXJI^UXo``AVK6@72%AP&_&0~A~ zn|vb5>Bp%~=uvMdfI70&4+}uQnmO6*RMB*$^KW!`*F?8c> zH2%m^gr#ks{$g(}L=0*k|&@9Fhcq}$YKjciSVO@Hp1a$b~Saz8^c(BQ<9II-1LebY{aYrW%aI*+!EsQ0$p zW+7&!+W2BodAt=K6>q~S_h>A?V9^=_sL4_)y$Q|MvcYJDBr237bg?WZ;6$*o`pM5E z#c(ZWie3fe$?d&#tUbBu4S~dOWu1nG8qCWnGhr>rS@Zy1k_G<1ux2M?l9VoFQ`@x@ z*O_BU-SeM=@Lo~4Q`m6DItXhokv}4R$R0_f`!iAkzO6rlG}qZ|aI23)SYj?lZNL(P1cXx1~U)~uVHT$k6cRjOrcHWXBL=j6Y45)*!RQp8qW zrp3TXGnAhJ0FX}kjIY?0f3$*wx`@!pjDCMb)PaC8ZFN8I9+L55p>4^Mqz z$p=JgY<2mXrP+ubpeq!;Jh~KB{kNI?fgDr?wQU%bCD{V zSMb?+S20o0jNL=G8GZ;2I%eu~^wef98X@PRJxLpK#rQkZNL=eMy<_aCmTe72X*h`g!X+~b9(HL4*B$8GTik{IA9wlGS zZiqo$=jUEE*ZuDk;)s51ml5Jlvp>y&MTBaK8)V}s2%*#Fy~J<4PG1Gt#;Api{#r1o zzO}iz>ezi+0Zm);zkd@Ey1Gj`0(JHEserd_fJS3_ateZr_2z8ZUHC)9SXSP}u~(?^ zcK@iCF`3rrvzU7&-r0=g+&K+y=uVdGnxt}o8;KR6o`t959Tn>uWgGU9=kw&Fo;0@P z2!@eJQi-E~!-KE8z}=FZ#Lzp?n*#mG+=lV}->stvx%5f;tOQqj=!Ek|=EA0+aiT_m zHS!?K6P^Bv=JCNr@%229MvF|hbDgz6?rN)Ao0126yKGGKis$n6oKCTb$9%0;PD481 zQnqM!8vXO6zvXWUf>IQgob#(-Kh?Q@9m3aPZ6A2Z)-W7pKAFm4{!ch5Nx8YsPYI}C zv~^N|1>mw8aeHo2swL@rmcUVdqRHtUPEXH^IGPSiRk;Z_T@dM>EIN2=a2bA;;Ny`GO$*_(qr4{I2^UAbSj>mz4x982cMW2_#Wf;bm_{HM1Ru z?0d`SR4idJnhdtW1H2m@{Mgq>OI#YK*AB!;D{HTJCEk#v^~VJTaUV#8@2qr{dvsqt zxxN_MG#qU9%Dwbi>a*CXlk5KozA`HPz@PK~LK!vaaHY}yd3fL$#e ziZ|&O1k8(uqCdqEn5})BB1xSw3K+knc0&X*rx7DVF1ij5vN&EaJLj)WOKxSqmgej7 zzUc^c7^6B{R8ZeVQNJrm=`Zth+K3K&wee?QKn7AG9T^Gb1Tr%-nSr+6iI|UW(&NPdqNHL&*V)We})!=-+iDR`9VcgG8z!f{pD2M0OXC7eDFw}TgvDksQ z<0|@EQF&r3WU34i@v-V_5FYZ|z|BTA1!JB}|Avm@kKkq0D=wA2kDf?r`jsS|pA%D1 z*gyaD*_1FWVe^{t>wN%IRNSu`9Ln(nOjD+1*?58yHomU`mn#JXQ9Wp*;g2zKHz#22 z1B28xM!8a?81)K$)JVL@{d7JW^x!>Cb+H&j6!x7IO3po9xJi9MSBv{wLsDp1^G$wE zJwm2@_r6D&G{5-|&L~|k$?BHG4V%pimhmtFcER!v_2x46lJ6hvG5`2ePLdIYCN*bP z{-s57+z;elJc{%_vL<>qOhjmp{BgR_vE&~bfQ2u?_NAf%H5<+2b5uEmk&R6mIHiPj zppl~4aw(5LnZM*BK^viU%3Z&!GT4QS}qTgHL>Wb3bshKF!E#CGw^K9LncbVm%Kr1 z_V4)Rsxa-KQvCBufzrDqrQp;OEbAOjZBFIMHhXWY*JkU9{1^6HCEd+ym~asdkHaj{ z-a%H6K%@9@1rnF^!QQ_zR=10^`YG3-=rj6Y8yaacznBUZTFlGrBdKFr^TR6xoZh4{4NnX`@S%aEv}J4bX-bui*Uxp8ujmdwJ-rbbQZP@Qumkf zOA$_MR$nG})Hj8424cf@XHOj>r^KMC*~j4mjf!4ErL>7JXp{Irk*U4@>sPkYR}!Xt z04XV{ox;BLY0?eIKR-@c7bZo@HZd#^_(!DUTz_N_p;a@$Eks|vjnJXuAiBF8;SM!I z{QT~X&G5aL5 zb78}Incb0oQc@QK)@>qZu6GR&(p3~(^tkAK-FC^k+_?t__e6(PJ7tYhov~A2r+?<>hXl&*9a{U`n{D0gRSsJI{hXPL3t46uap{uf07E3Y9?? z6MOB?n55Q#pnBMcf6~Sg;LXLIsu!!8*;t!Txgj}ABXX&Mk%H6qT-Gm6IG1rXtN(bF zR%Xs6VzQgEjtQG`z4VqLM_S-mD_7}(Gw&cKKI!~!OM39%<5Q0<;*G>>V#@0$``!zi zqYYasRf(Z7l1=@<4SG8G#N=cRWu~3)D)mV+=AaS$$pcmJlMp5V`+*1F(dw+N8o#@_1~oo{9?OzBuFB!UMpl zBR|y<>2Rnq3GCwl@1w(hXYF1IJIw(BIzvigEhCCGPZMU~B{kmwp^uPKEU5La9G;U=Ga8{tUP`a|YAdPLa+0mAGMRz<GI>OD( zr<=x_zTZ}Xy3g)U>S~$g|0FdPa^u%oIIcle(vMfN94s)H-J>*9Jvg+Igj0t9>eDzF z$oxMP2`j1np~idReZA-LGnb8VEhnWx8%et&vA)Qrt|;+GMq8g&m$4!+e|=%FuW9iP zs;nn9o;kg=2Cb02O1LF$6qM*4!p`|l7rda({P8qXimwP07_FnCfo&Dfc2HraQCsRt z(oNAofg9PUP2u#5wq*%bFWt$sRJh6rMNWFw{yV3D*iPdcsrj|U4T(SQ(C=e-?m^8T zHAs_Mgyn28pTd+50GZfwCk3Y1U)L)GvA=1l|G7}qmZocNUix+B@?VE71Js`I!u~i8 z02w)XCp3%|ZsKTV)zqnrT#&8nKvLx%NkQrrr*fex$By+@^;)dxik$s1tY{FT@jTg8 zl$48nHgAb7W6A6yWBy+5K!j~UEtAtDa!Bk6Ab6o;TYVwkst??~ns%RyLX%yaJSS~x z_CHv9+>~>E^ugEs6A9Wy)hjgfaV4yJEBlBMV}E>YoL~D!<~!S0`}zeV;wNN=G6DK& zPnd(ANWbA3f>M|al-^J(j zZCX5?^qOtg;&f?|G_n8e=NZYaz0{u0#UJAyw@zbJ;_XBgz8pI*Nu_ z&gy_r3@ef>ebmDg93cA;BX%u0;ZX#dO*g{A!kS;>$y374Rz>Ui$-jZOp}_}i*Ebr} z(9N_lGbjOv4shJf!W$m$Fg@}KGaJFi6i=gqh>(}2^;Qjm}d zbnwPv|BxA%bv;|SEQ2!w{n=fJ(LEZZ7jm+ToWHT>N2jZ47%9shM4|(l-cr(z1AQ?u zi$gd*ta|GxDE!4by+m6!ObK8YS_=)?1SyE3-fl0HT#ZMS&kXl-pAHkK4k)EV!}Euv zP<*;6lPYK4{H~eWeJ-^t>u93KZy_IhHEh^YXv#4${aE-53w@PT%Em9Sg?st zzVr*61W-+pP*xDs(R#p(eE-9$D;-nC`~w!9?|StV=3IWr=ihXrz1ktlV#`Am?<0MB zU0>oym3Gw8qqA8lP4g*db#|7pepn%@V#)g13Qyq;s`-M1~NB+NCOvUGX3*x=!2bP_v$Gr1dtP4 zj@IZf2n}h!;vlk{%q&GcybacU+zgU@_L4Jn#Bq-4Jy{hpPH{_CHF2ItB(6xCvrNN~Uf| z#UhJZnuv~3qEPOPN43Y|iecM>ZqB>;-;dCP|Huop;_&|#kYYr~qLb_o!N2M*X+TDX z&hxv$@la?J=*&h0cn28bD?eOXZ&Pvg z;*lqa87j5n`sbC{1URHW#WD#f(t#fJ)wND{`K`C}D&JC`T!QxF*H@^aludOf+swczo?FIUfEy{oG zQ?JvnNE2U-IEj%5wy~$S7-QH>9(Q}vpN*+nko^LB+!N*uBS~rOlpSsLBS2THH^?BV zyrb8+wX7;iOvHrgSLdOvFR%V`jjn6w@>4TA$z+lI%qW)^&$)jw0WPpLm#SH@yJ%QD zJTC4fc+7)DU<8d$PQtI3leHO-nqY4zymLC5Ql2}m>zm)~_T-*|TCuC4mad|uT93~= z5(Q2>72!XDZDirC*y5Yl1uW8tt?G}Y<)tejF65r(zjY3sdqbUQor3o69@?=xU+YB^ zAGa5=Gfxm#;F|bg!V#GdcyrR0k5e~& zb}yu_T6giYHs%o%WgMfV%;XmmrFDZAVpo zp5#~dBc!)99;qK;^)Ppv=6ck8(JXKsS?)s#t!vUujp+A-#pr9^LP87zacF%S0& zd;O=FX#IEnZ=mD_jxLa-a>2U}e+nb%5i84rZMk=b%6ttU{z0MqTSp*r(^&X8Eg8vUqXrVwv z+tZe4O#%8-FtDajuOHN2Kf0t^T-jgC?p_X1#JUtH&9COyc7>^YH#dNS*<4%H^w+fP z)4Lg;m(^=R-Q(mPS&$It&2|#QQ1FYC;K%6VxiklSZ5ye&{tVnur!y96#U1)ZkWaU zTvRya45}>=+~X3UQyLxIQ-YdmE_+<%|61Ok3JJc#^!A#=GY(E5s?dB}^y}flTn+>1 zqF4YM@xHWD%RSF#sQ8x<{WMGo6uOTXK3NqRrLAP(fR)YB!Y>V%{Sq*5wjZ(7Hr~+= zWzyNCnu|-J>BudM{RyOQq}-dj8^j2^*bse7-#uPoId7=t=`NJM0qFO22(uq^GbSE>p~To~l%o2;~OaK?}pHgL};E?A6{sr8g5+HQ_1pVy+>S zcr=n=+WQx89*)kLZA;*%2cG;x6e8)B(Cu5ant6Z z!#^;W-ir+QUf6@arUD(6Fr}oZ%RU;Vp&vNX74;@wUPZHkK*tg{TfrVJN%i|r#Z@>I zs#1(PCUkz-#M~3y2+`gt(0RcQl+K^I5h+bY#vASEpCqe(O(9D%0;z^e_I;3t$)r4yGZjouo&+^y&wdtzm;c zUb0u_4}ne+T>tno0lesKD*#FioYpGyfb^iobZa6f+MZS_br`jPcqGWAak5>&fqTK@ zq0@WwU{_Do2i6|Y>d^K}iT^fv$a6=E)o3rt|c${29`9h?=f zRSq)a24e(t!&3kdJ*Amak{^72={B*?bKj4vT5D7Lq33rgc0rOGs;rs39dd&p1jGWf z3CSGG4OV4lv){Q*n1{N{+pknTT$CsJ90ilAgl!mS3g4%aG+rV89?J~dJ?>O!iDE=# z7Ts0wLp8lBWKdnX$EilQ-Fb*ITVrBnY7OC!AI&87X{(*>=coGSmc`K`& zJ>UbDv8l~$`9Qgvm+!yOuut6uc{5(F1t}%w27m5`RPrKZ-V=Uc3*7sX+-T}`*j(QH zL9D4xN%IUD=7wkWYW-Ds8fzDB=7^O)ig>^$%C-M8!pC_q(QaNH;Ll9_zqYP2E~@Y8 zuXIUwx^zhhN_VGp3P^W%cMC{2NTZZAO1E?h0>aWQE7JWxzvuPCOZag2-gD>7H)iH+ zli{bshN2?zcxp@9w1tAAuS#M6l@T5v{(2TG#_c&nJcJ^Q>|0KHg6$uBFrjrn_(_=1 z2``)YbN}upV!ro2tA398J{ioau=vcU7hX599pkkOA7=WUr&Zg!zk zqL@yaM_`HypRNDAwwiHJlf5>GIEAE&;&YsQyPZx2R6cIeOZAlChxS|I`QW{cr(5l_ zXMgj+czyg=GD-@xN0bY{&QOg}B|@59SB^=}KonwYg0)po7VN7STqhj-NM16Kd+()kUN3mt^XtyZx|OMQh{*!qhjX_xIu1SK_*h z{M)@^Dz{hx{xd9~v4?$Tb|1oJ_fqXV{;U1O0+o;F-IB29!HjK%`6;RC(l^kXIOSNd zLt)jW0w&2Q%tR)Sqjad3`AEE4wCm2Cz2r9o zblREE8HBKl+rAL{-X%=`d`&y%)5dwqOz3BiaLG($vtS8|yCI&9Or}>6X6nuX&V)ui z=Zg`8w~g}&x~+xJ8!swL#Gy0mLkd+$m;vl!K4J^mK5}=|kYUjHvBB~VZ!m@%;+J80 zg|NR8QpP5`ku&Q2=_BPu+8=w9*t$ztq-u1bs*Uvf7((;ey&~ZUhqTg(6Sn&v4L(qg z>H8v;)W30R;{9b?pWl4`fixF-e?6M3N~IQv@}5d@B9ydj)BYq&8%^w|SfqAz!Fsci z+ATX6Vk4RF{^rkTyzCd{>=?HPn)xUCtXv$RK2pDb{v}oXEyk^ zTSZ*`96)ekOsxL=v6wfVSxHYAi9GF0vn=1IC%uaG!5Dh1G6&kr3r{-92<7r~%RX0Z z&LeEBTqb#O%0!2gh%D1*j_rASc>F@fal?X+(plB(dD-&jh(vH<`eE|5e?|n58~$@C z;(mJzaNQS{+srCL&;J{m{tnizXfS5u+`~M0*zQ>Po~$8#M_zrKR-$<5*N3xDnhA29 zmUNWVL0zbsuGiG~Wh~R5hpu?s-gnTUztj&6M8rBW*}T;Y1>%jQudGuH=1pPXpGZCN z-}ph(CKbJWME>B3&CNLHAaF4?0|OuYdQ(M*a0A;c!5tFWGyVDF)jWl0Q^@zjVI?&G zWg#5{l!Q#-9iECx7`A2urxa)~aJ)p6+N6NAA>auaipqVVrCA!~hJ^fwzvEq`P7BXc zJt>?yoDO>c!Q(P$m8_yfEmO{G@8(NUTMM*!y?$XRqC*4vk5)%5O)!ee178PK2d6B0 zS#5}MvFc})f0~<1xT>n#j15P)22*#d91bYMj1u`yd@TznTA$O#(4l*feV!?=wi)G^y6*qbG6Y~ zaCpOIvnyTz$qSy(gn-)IBY4xwIPMt$LZY7KW(E^Ac{$Zvnit=zfdgvGzR6aE>>n0t zz-@7WYAcwFEtZzI@Dev1B#XcniK5TrKl~)VW8K#u$jA4xA27|179g}}wV}#drE{hO zpi;Lh@W@=onX6pBh%|LW%20aU0!kQ4US5|gPOXN>h5J2#;Lpq(B?wPwtx2MjfMf@N)g(uu6nuVZquGOfGFo_rDB-U+p}K zm5k`@tjsI|lhOl-9d$m=dP>egbtyZVbRI%MP zoNwdrBp-`b6;k_`zWdc?QYE8?yR5fH~FjeToM^hT@B5X+hscOcQNZ_3E(l^;N(Ly1^ zV;5(sFNLxg*U+o)=8?c-L05K90Di~b%~Y!rlk}ldoKU2j7OlKX+C0etY(fYBh>}ic z`X>bPqOFCcU{&JK{6woK)ivRp_%uh!7}VcRSB4e*GM1zz85}{ngB)GFSw^ zbzY-NiOT0T7zGy`fXwP3G>#8~AsA|Gc4}Kb$%f9~&M7)nA*Htx}*L=S*2uXu@$p}LK^v=WT;ICE(Uu5cm3m3 zRH8W56wO0RG49)(Axk3f#>(^E>d7QF^#XwgjzMn-FCigeK>yK2!OA~H0W&S7clSY0 z6gpKGLr+($O$0$i8^^@F4^lY6g3+N9%@eKB0^{>tn7)3^lO{UCSo&Fj}x6bC-(%Cen9Dqx_? z)AOQa!=(*J?^!9@z;l()?NTaQD>|PR4Y+J-#yPw2Oezy5*Ef{72R%JzSJG=Hr7$Clo*+kg`P%*_*q!4 zY{)!9e(s7#k+j%stPGQz&MY%69SXKtx;l}Ts(<|iz3c3w(7&3e`8 zs!nu=H=TE=^vBPmiy?Z2WvAAaC-w*~h|(N<2YsOtc7}yqK9ZJY&3Fenk6e*s-JsOm zj)|5sGF)1`!BS^X{_IQaOTP7fP%&#q{N+&jHX&qjPuk>1jw(|Q{6S^2hY)#oUpN*+4(|?)z`N_%Y%zVn)lh5 zBihtcO4-eESh-|T-lHj`+%hOEXA~AbH5D^!hUoWS$!$Tgy*rhe7lzO8$8aV4tNZNt zlWu39_I4xWm3O6K(Z?q~lq|nPWlSPg)g-=Iijt(kdc`|}2U5(vKfNJ)Lz(hQh$^gC zW2+yRJ>c+J{Dle?>E8_YYZ+v6RsAKmA`HND{`xGKzBy@4?blxmn4H#fhDE+gWjy@= z_si8-_P$@)y32`dH;!E1D=~jaP^FjQY?P_`!OZGRuOejk+ssc0MviCZ@N|oXHJ@+} z#u~Q390W(u%Kp33~(cH4pgkh-t1tSMHl3 zR&syXhFAANdu>xPVzlE@dv7Kpo zIo~Hfic;XjE`Zpk`0KU6bkfJU^vA!54kC|;Id?4;4((QlN!hvq=C?%^78Q5u*gkJ6 z)|6t}4Gj$&=Sg+QR3~){gSy37$Ns@UX+kLc^T3F&iS=K!n#Wbp?t_v)B>&Bl`sXDP zJuxYBuMB>w7T3$s-Nc1EsARrPh7DA~E%%=k2+>DrrCPPou* z@b^0Uo39n-hz1D-c6V;&dnQA_i#fLroIi2?&TwCRjareQ_A$+OuR5H#<;` zz(S7w9u~V#-{gs{`p{SjKSZ0a|F#jdIm!eLliVUa$-A;xxFP%)L)oOn;yU!G$L?kR z0{5?_m|ObBhoiS+@GF0I;;|~pm|RjFt$CV1mLR2_8xW)~Fl2dP6Q{3*asCct%Ce;U z#!U~^xfM<5bk?*q$&h#EFbeNiQ-}}doAI$b_{RBrXl=3rA2!^=Tg6wvn1Mznc!b}H zRi?qHdJ=*V-(s;i&4Z8m^>KQc@WQHQ+I_EsDRn7pX+7oYY&n*O=iQ14+Npc%%EM+h zmJvg`YjEq2hT~>~nkfuu?XwixU{{7ASD1g^@rr~>?+&RawiSs{G;WT>-ugA4dopeQ z@s&egif+W*_ZW<$fQ+?#cF+r7Q}8?8xM$HYrMkss7;;(4EsyyXOeSm>XO zjg75<@ul6A1J{#3Wm$g1~;8YsJczxQI_rM6Xuj#1=2`yZP4>7P8*5@jUfcSIK7-=Tzrzh zvhP^=7Yss+Q-4A`wGqCHskXP;r|NBIT3F0{)%LEoJ~K~nDjOFC@~OL9j9pa~3Ui=V$$kCH*5VET8X<$;~ioF)X8>NrAJ2owgX>P1#2`jxx)0E}Q#V2wy36 z4lhwr*mL`YFf@^N&SPQn=7_A>DSk-G;Y)X>+Lx3$A*a^6@#>h-7-dpKt_XSsA%{0B zjXkg4&rW+GM-o4Akoy@|jCN7xc74D&LdeKiRpsZH!>gRg-kko7CUf@-z7&Dt*nlcg z=E;2)uRF&9@27FCpoDG06x?Chb{Mt%bSixvTv`jE5{hXQ!>Du#l4OR+v`T#AQw{l7 zh7(V+sqlwwYbft;(Y;e1)+&_iPk&nHuN)}4SZbL^$@McSi_ZJ^v^oE(kY0uW29*I^~ zo=l>O+(=n(mOn&iAM>9@DIv<*80Gw+pO^XMsD2n!6f%;z?{9OW;2}IKi$83Kg8zhF zgvm6U_IgG-e7;gNIjhu$0IKLOS6p*-u#ZK#n}k}c^ttk#aed-Z#lyc3U53t;*)VuJ zt&!$GZcuieA~TZTNmJHCzVDE&7;7E z4Kc?dw`^Uri|bCXRoU62MUK5Wd__3;eC1qDlTH_*7h_M%illlZxl0_JP5e}gm0tLcKof<3 z=?V|TCf6Zln*J_eBa^>3DQqs`;EURx;=!dP>>eD=gJWoAsU#B)dZKF{h``1fQ?2{NU5kv^5;q zoPCW{Vno(SP%4jl*O|-ArK4$A;2FoJs=WOSha%~>l-7;KsOXX_-lFn@iN5unM6rg4 z=0o5?F*{BByV|>Kv{TqwjC&sh3#u?Hnmchx`4vO{GFBtTy%;W)c(-O9w?(V`9f4O; z38XNvH%pC{<+yUnlqX2>N%xBv?u0?2Vy#iq)9|9O%=pH8BPy>z9XCivc@l)|`zh7- zCbJmt``d4a1Eyp3@bWabBVLq~taed*Uru?8x1#E;j7B?5yn2UKf{(JA9=i?_J5ARVjcX&U5wEc}1nfDaFa-10N@EN7ntcRA62AxpM+zpNqalIcG*q5v z;K^vLy1jfZQpfZ9DTT)`W+J_WaWP3Uj4A{fsWh zP$1gC!9Y_o|0?$LespvM6ehk7cT1wrMGe>Z3(w0-Q4Z_26h-6)?c>pb8bcDS$GoJ z)Dtf|LJ1Gv`#q8{{!UrHAQ0P;hB0+^M^3w}9Ls@}dYjg$A+Xe%|8lr1)A%-!mk?uh z8U`!OU2`jxngks_FUA_)rj#-rd$l74gqo5?%=pCIo-FR8&2ul+X2oks4?0#F=YhOus%tQx37`H5M;u2Y1Oa5;TXbzuGp9-T9Oq z$YEVg)KuyX1Il6*_*`JqvVUV`u9*no)aTx=ZgIuy%bC_>f%_T+t5`mzY1OR0<3)rX zx)v5}X*D>nGyiST9O>sK4pnKaV>UfKKb{9fQQ?P+53TOs#12bluHNuq)b*8fng@;8 zog45l-H9stvPBgK&ifTs2+d1pTb@{BkR%ejGK|j2EtI9%8lEZY^XyIOXWk5@GrwJ| z>nCuKhc!?B@v4G$bMFRlL&S?4zJC9Hd+NepjjZ#kT1-MYmY%--eg)jZAV6((YirdR z&vA|pV&}j6ZJd~4h$4V}@nvyxrLzJGv}2-}3J=HHfxi7(kR((9h*09(ciixWoU_x% z&Ij*#-_}xxcH0GKme%pHTk^X6YwqawSNHzip5NX*?H$Wix(QCQAwm>nHe0E%hvVal z-^njKfQt-)kUy962f1CmYR3F$=GRJx=VclC^2w7QFuLC1Cq!2sEr*Hs103YXQUx^V zgV^Tew4_=LK&q{+#0%+kuJnaLYb_i1HvlDkxg94&Td&6giVh1KyZ&QBJ{1gG0x)AW zwXZsk$H^3vLI4S2aCmiXZICb_hD>NY*)9dR7-05b=QA3KmhCRtL`3~3Y|~bUj*IPQ zFsQm*C=gFiZ8$4j!0rG%+U{T7i?{Yxsxuc_E17eQe6m8PmTnardiB4lK##~;XC z0q6kjC%@}Q7v?QHbP-Wza~>HPb!E$4Vegyb*VNoqhfmNK+)MAY<5XS~k}}an zpj3E5*;p5f77c7OFUvfJLoJHch2Po}#)=}BEQb6|NEO>tTUKiS9^Pl+ zZ+ynXiV6Fd1jtLIIz^?TP5=j14=zv_$LX%F_Qs(axAhP)lVwXzRl82d`e1#8(A6-sWeiLux`jnY?KYb-JA9%(*8)s zh<$%oTUc-b(VonjN`D6VNYBEoFsqY0(W0-O<^~<0d^K8}Zb6%@Br2Zmi%lFTSq)3k z9nUL1(pPK9DVQF~d&B$Z#Ca1$F4n+Z_Hi3p!gTSXL6(sRmFAi52KKzwkJ1adyQb!~ zJ&>sT004dGv2_;B3-uABz^-B7ul^jZZ8931(~Vxj(f$h7-TIJ7RV!BRyk-iD+kXxY z)boS3diEy&!#<5n_Obs?M{@^f@1TxbXO+0b0A6tE;nc%G^#aC)9$kbFNv#cuWZ+Y` z$?HRZg1IlOy@RS&1@jI2!OVcC&>-7mT4`asLIM|)sGAyn zypR$aIARKtE#Yj=-a912QMVnd9d8}E5;dd<{wQj1w`jw=m?!M3;dz@tP-qA^6OcRd zDd!FS8`nz0)No=+WrSJdRE*Uk#!KIVqR()|CfX$MCU_;~vMo6Z!RAbh)stJ`B%IYDmkitI;};;sEZDqP1UD=>$SJTte?>f* zoTV%^bwqg(gxp>fW~TXku$-KOxf`+O2T(oo>Il?IKv~#zPMPy*(Hqp@eCGvlrKjUX z5?RjDwi8Yl@thz({?gk?8mjuu(>RVYJFE{=?nz0O>|)VMSovnXdTZ_@EtRnGm8Yb7 z@NI1&P&i@%<(yTozEq;D&oigc|5Qvl_Xp8VQ%U_j_0)(deBYTNPvAQPY-s8b8Gmd;;z284lQbsG?^i+GN^Vh%SDF z3Mq#S3V!2u&0Vzk?mNh(4}Sn-Y+fU=IfWPZH9(?!6+j#TZzxv9M7A;5TDBvI{UfR{ z0IKON2gZ*d%w;qi%;YsQz7&Ut10x3Zv2!hA!I#i8+SyTZQF>)2fsojDM4Na zU^n-Vb4PMd1Uw)Bz_C!Mnoa7ZOPfF2&Cua?1Ei;z)5>eclbyq;U%a|7v8Td%opnIQ z94>V1C6*W_neMn0li2@Qne;r`NvTfvV<7j0O zd5F4rN-3j4%A-T$(q&4eu=3|VbeV^FPsiTMW}cB2!VuwvSdjAYVv#|9ovj!%=b4me z0w25Ee+e_46{!5mq1-j7G|^buz*$nXcX6&NOb0^Q_4k$NS$ua67HZ42_h~DEn1a|j z9SACdbi$`MVZC{MN2#ivKna{F=@2ADe%;4xYx`H2Wq3~nHiRo_Uj3Td znYc2Uyp<9PN(b*;zNfPKwd3B*~w6ku`RgjUj(aM zPQ4;Ve^6{#d7AQ=Dl0W^XL%cke+@?)^JXX|1rqh|c5S0`)D}!pG?n+C#{m z=v+fT8UhBKTDujCV`JT~MI-qgXN@ntgd2jqLr##2>0yJ-)7@XfMHsYdJL_v^1ffk2ro67Yzx)oYx{gNog%*y31VPWF6`u)5m#VdN`~sJ?Vg1^!7c<-eh&IK+KBS6@YqNf z&Iq3lV0_ADj@*D=ney=`(^3gI22yL%dLSM0?=Ouj?gfraZxq$m_}V7N$HxEx= z?>e}!T1VPJhGN&&*1pm!I2*8MFh%0-^a#&dSp;r)0ibeka2E2C5{N9f)iNNdufFF1 z2A@*FPzdL|EPX+4*`;_#p+bu#)<`_nVGxUm*=fn;rI+?1oD!_{*7$q-#yv{xVf(n^ zamJcqD7_yU<+r3+{kPP_e z1&Sj^xRS!aMw{Vo|2A4#atmQ3RjoL)TW6wwg&{Zasky%NSSLfbT4{tXM4I%p4K8x& zEh-gw)uK+sVWj7WX_9-2`%#|J&t-8lO|1+(c4bYC<6h;en&r6q^B$zZ1CLsK$$Lrl zv@uoB54hyO2jA$6^UqTE(T=O2#!nD3vAcg(ApXEo`%%P~oB(FnMRE4NPYqC_q@T6a zLGs;84jeWP4q8Gt1yYqtA?R`R3NQOH5->u^Wz{%Oo;Ry4Hb(-qql?JEKN~Ool4NAk zTbyF}SMHrh`AAeD3yJO{T_Z-FYEV$?j)WjWbQH}$Rd@HZEo)DL^t_Tu$RytA=xDiZ z^YUGYa|#z4o!RvAe>pNf?<(2(x|F|usXO%|+UZXDa1i8fm{AL2_yUSJKkF%+hLZtb z$u`$32_!;?0nAEeJ%Epi>KYnmp!nm>68Fy$Ka8HP7*EiO#CU9U^e&Ys2E1kB1%2aD!lVg z9Gckr#C#`M$XG6&l@ZJ$n@^S7l~y9+Y!TSKB(wN$a70WoXbrwJurkrDD0b|fpPx@A z(xuHPTC&Ki%CN``kkb=nPf*t5q3|L7@ezjn>rasI4J>}lsp1E(NEHPT5ANm@;UiO? zMw|`Jr`=_8#J@rDBhy+mAU!rj5Ro4Tpo<6qHy%=~BybE2Ha<^SanS>LQIX2>nAR{W zmI2!wCWm>q^;X4bMy|(Awc%e%uRvr7kOK`nzpi4~z^Pw|JrgxGHPOS{@t;2ke0j#7 zMEZ{UIF0@QFS@@Tlj~XImZFwNbk6>v*icwXo#_G*SK~S>x!)S8dZt=ky$ifJGnFS2 zlw1G3>u;T5QBEjs`KQOy|pe@>D}% z2ljYYnPqDu2xZ>zB59!FhV7lLUaX1Tzj9sA{j&J}r|aTBixw$$&Fu|Z*} zqV6i%XBrqkxTpW# F{{iSzRyqIx literal 27064 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, U: Iterator>( config: &mut Config, config_path: P, client: &reqwest::Client, + quiet: bool, maybe_usernames: Option, detach: bool, ) -> Result<(), Error> { @@ -45,17 +46,20 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( config, &config_path, client, + quiet, [username].iter().copied(), )? { if !detach { children.push(c); } - println!("Game launched successfully!"); + if !quiet { + println!("Game launched successfully!"); + } } } - if !detach { + if !detach && !quiet { println!(); } }; @@ -64,11 +68,13 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( return Ok(()); } - println!(concat!( - "Welcome to ", - crate_name!(), - "! Type help or ? to get a list of commands.", - )); + if !quiet { + println!(concat!( + "Welcome to ", + crate_name!(), + "! Type help or ? to get a list of commands.", + )); + } let mut command_buf = String::with_capacity(0x10); 'outer: loop { @@ -92,14 +98,14 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( None => (), Some("help") | Some("?") => { help(); - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("about") => { about(); - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("quit") | Some("exit") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; if children.is_empty() { break; } else if children.len() == 1 { @@ -137,9 +143,9 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( } }, Some("update") | Some("up") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; if children.is_empty() { - update::update(config, client)? + update::update(config, client, quiet)? } else if children.len() == 1 { println!( "There's still a game instance running, can't update \ @@ -155,28 +161,30 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( }, Some("login") | Some("play") | Some("launch") => { if let Some(c) = - login::login(config, &config_path, client, argv)? + login::login(config, &config_path, client, quiet, argv)? { children.push(c); - println!("Game launched successfully!"); + if !quiet { + println!("Game launched successfully!"); + } } - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("instances") | Some("running") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; display_instances(&children); }, Some("kill") | Some("close") => { - check_children(&mut children)?; - kill_instance(&mut children, argv.next())?; + check_children(quiet, &mut children)?; + kill_instance(quiet, &mut children, argv.next())?; }, Some("accounts") | Some("logins") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; display_accounts(config, &children)?; }, _ => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; println!( "Unrecognized command. Type help or ? to get a list of \ commands.", @@ -280,6 +288,7 @@ fn display_instances(instances: &[(String, process::Child, time::Instant)]) { } fn kill_instance( + quiet: bool, children: &mut Vec<(String, process::Child, time::Instant)>, arg: Option<&str>, ) -> Result<(), Error> { @@ -316,7 +325,9 @@ fn kill_instance( let pid = child.id(); let uptime_sec = timestamp.elapsed().as_secs(); - println!("Killing instance..."); + if !quiet { + println!("Killing instance..."); + } if let Err(ioe) = child.kill() { if ioe.kind() != io::ErrorKind::InvalidInput { @@ -324,18 +335,25 @@ fn kill_instance( } } - println!("Joining instance's thread..."); + if !quiet { + println!("Joining instance's thread..."); + } child.wait().map_err(Error::ThreadJoinError)?; - println!("Successfully killed {}'s instance with pid {},", name, pid); - let secs = uptime_sec % 60; - let minutes = (uptime_sec / 60) % 60; - let hours = uptime_sec / (60 * 60); - println!( - "which had an approximate uptime of {}h {:02}m {:02}s.", - hours, minutes, secs, - ); + if !quiet { + println!( + "Successfully killed {}'s instance with pid {},", + name, pid + ); + let secs = uptime_sec % 60; + let minutes = (uptime_sec / 60) % 60; + let hours = uptime_sec / (60 * 60); + println!( + "which had an approximate uptime of {}h {:02}m {:02}s.", + hours, minutes, secs, + ); + } children.remove(i); } else { @@ -381,6 +399,7 @@ fn display_accounts( /// Naïve implementation because, let's be real, how many instances of the game /// are you really going to run concurrently? fn check_children( + quiet: bool, children: &mut Vec<(String, process::Child, time::Instant)>, ) -> Result<(), Error> { let mut i = 0; @@ -388,15 +407,20 @@ fn check_children( if let Some(exit_status) = child.try_wait().map_err(Error::ThreadJoinError)? { - if exit_status.success() { - println!("{}'s instance exited normally.", username); - } else if let Some(exit_code) = exit_status.code() { - println!( - "{}'s instance exited abnormally. Exit code: {}", - username, exit_code, - ); - } else { - println!("{}'s instance was killed by a signal.", username); + if !quiet { + if exit_status.success() { + println!("{}'s instance exited normally.", username); + } else if let Some(exit_code) = exit_status.code() { + println!( + "{}'s instance exited abnormally. Exit code: {}", + username, exit_code, + ); + } else { + println!( + "{}'s instance was killed by a signal.", + username, + ); + } } children.remove(i); diff --git a/src/config.rs b/src/config.rs index c3b907d..b477215 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,6 +44,7 @@ pub fn get_config( config_path: Option<&str>, install_path: Option<&str>, cache_path: Option<&str>, + quiet: bool, ) -> Result<(Config, PathBuf), Error> { let inject_arg_values = |c| { let c = if let Some(ip) = install_path { @@ -96,6 +97,10 @@ pub fn get_config( } }; + if !quiet { + println!("Using {} as the config path...", config_path.display()); + } + match File::open(&config_path) { Ok(f) => serde_json::from_reader(f) .map_err(Error::DeserializeError) @@ -129,6 +134,10 @@ pub fn get_config( }, } } else { + if !quiet { + println!("Not using any config file..."); + } + Ok(( Config { install_dir: PathBuf::from(install_path.ok_or_else( diff --git a/src/login.rs b/src/login.rs index 5c7e5ab..cf79105 100644 --- a/src/login.rs +++ b/src/login.rs @@ -22,6 +22,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( config: &mut Config, config_path: P, client: &reqwest::Client, + quiet: bool, argv: A, ) -> Result, Error> { let (mut maybe_username, mut nosave) = (None, false); @@ -44,7 +45,9 @@ pub fn login<'a, P: AsRef, A: Iterator>( let (username, password) = if let Some(username) = maybe_username { if let Some(password) = config.accounts.get(username).and_then(|val| { if let serde_json::Value::String(p) = val { - println!("Using saved password..."); + if !quiet { + println!("Using saved password..."); + } Some(p) } else { @@ -72,7 +75,9 @@ pub fn login<'a, P: AsRef, A: Iterator>( let password = if let Some(password) = config.accounts.get(&username_buf).and_then(|val| { if let serde_json::Value::String(p) = val { - println!("Using saved password..."); + if !quiet { + println!("Using saved password..."); + } Some(p) } else { @@ -95,9 +100,11 @@ pub fn login<'a, P: AsRef, A: Iterator>( let mut params = BTreeMap::new(); params.insert("username", username); params.insert("password", password); - if let Some(response_json) = - handle_login_negotiation(client, post_to_login_api(client, ¶ms)?)? - { + if let Some(response_json) = handle_login_negotiation( + client, + quiet, + post_to_login_api(client, ¶ms)?, + )? { let username = if username_buf.is_empty() { username.to_owned() } else { @@ -112,7 +119,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( let old_acc = config.add_account(username.clone(), password); commit_config(config, config_path)?; - if old_acc.is_none() { + if !quiet && old_acc.is_none() { println!("New account saved in config!"); } } @@ -142,7 +149,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( "Expected \"gameserver\" key with String value", ))?; - launch(config, play_cookie, game_server) + launch(config, quiet, play_cookie, game_server) .map(|c| Some((username, c, Instant::now()))) } else { Ok(None) @@ -151,6 +158,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( fn handle_login_negotiation( client: &reqwest::Client, + quiet: bool, mut response_json: serde_json::Value, ) -> Result, Error> { loop { @@ -172,11 +180,14 @@ fn handle_login_negotiation( match success { "true" => { - println!("Authentication success!"); + if !quiet { + println!("Authentication success!"); + } return Ok(Some(response_json)); }, - "delayed" => response_json = enqueue(client, &response_json)?, + "delayed" => + response_json = enqueue(client, quiet, &response_json)?, "partial" => response_json = if let Some(rj) = do_2fa(client, &response_json)? { @@ -260,6 +271,7 @@ fn do_2fa( fn enqueue( client: &reqwest::Client, + quiet: bool, response_json: &serde_json::Value, ) -> Result { let eta = response_json @@ -272,21 +284,23 @@ fn enqueue( .ok_or(Error::BadLoginResponse( "Expected \"eta\" key with a String or Number value", ))?; - println!( - "Waiting in queue... ETA: {}, position in line: {}", - eta, - response_json - .get("position") - .and_then(|val| match val { - serde_json::Value::String(s) => s.parse().ok(), - serde_json::Value::Number(n) => n.as_u64(), - _ => None, - }) - .ok_or(Error::BadLoginResponse( - "Expected \"position\" key with a String or unsigned Number \ - value", - ))?, - ); + if !quiet { + println!( + "Waiting in queue... ETA: {}, position in line: {}", + eta, + response_json + .get("position") + .and_then(|val| match val { + serde_json::Value::String(s) => s.parse().ok(), + serde_json::Value::Number(n) => n.as_u64(), + _ => None, + }) + .ok_or(Error::BadLoginResponse( + "Expected \"position\" key with a String or unsigned \ + Number value", + ))?, + ); + } let queue_token = response_json .get("queueToken") @@ -330,10 +344,13 @@ fn post_to_login_api( fn launch, T: AsRef>( config: &Config, + quiet: bool, play_cookie: S, game_server: T, ) -> Result { - println!("Launching the game..."); + if !quiet { + println!("Launching the game..."); + } process::Command::new("./TTREngine") .current_dir(&config.install_dir) diff --git a/src/main.rs b/src/main.rs index 63c03a4..01c66b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn run() -> Result<(), Error> { .long("config") .aliases(&["conf", "configuration"]) .value_name("CONFIG_FILE") - .help("Configuration JSON file to use") + .help("Configuration JSON file to use.") .long_help(concat!( "Configuration JSON file to use. Defaults to \ \"$XDG_CONFIG_HOME\"/", @@ -56,7 +56,7 @@ fn run() -> Result<(), Error> { Arg::with_name("no-config") .long("no-config") .aliases(&["no-conf", "no-configuration"]) - .help("Don't read or write any config files") + .help("Don't read or write any config files.") .takes_value(false) .requires_all(&["install-dir", "cache-dir"]) .conflicts_with("config"), @@ -66,7 +66,7 @@ fn run() -> Result<(), Error> { .short("i") .long("install-dir") .value_name("INSTALL_DIR") - .help("Directory of TTR installation") + .help("Directory of TTR installation.") .long_help( "The directory of the TTR installation, which will be \ automatically created if it doesn't already exist. \ @@ -81,7 +81,7 @@ fn run() -> Result<(), Error> { .short("a") .long("cache-dir") .value_name("CACHE_DIR") - .help("Directory for caching game file downloads") + .help("Directory for caching game file downloads.") .long_help( "Directory for caching game file downloads, which will \ be created if it doesn't already exist. Overrides the \ @@ -96,7 +96,7 @@ fn run() -> Result<(), Error> { Arg::with_name("no-auto-update") .short("n") .long("no-auto-update") - .help("Suppress auto-update behavior") + .help("Suppress auto-update behavior.") .long_help( "Suppresses auto-updating, although you can still decide \ to update via the \"update\"/\"up\" command.", @@ -107,7 +107,7 @@ fn run() -> Result<(), Error> { Arg::with_name("username") .short("u") .long("username") - .help("Username(s) to immediately login with") + .help("Username(s) to immediately login with.") .long_help( "If this option is supplied, then after (possibly) \ auto-updating, the game will be launched with these \ @@ -125,7 +125,7 @@ fn run() -> Result<(), Error> { .long("detach") .help( "Exit after auto-updating (and possibly launching, if -u \ - is supplied)", + is supplied).", ) .long_help( "After auto-updating (unless -n was supplied), and after \ @@ -138,13 +138,26 @@ fn run() -> Result<(), Error> { ) .takes_value(false), ) + .arg( + Arg::with_name("quiet") + .short("q") + .long("quiet") + .help( + "Don't output anything unless necessary or explicitly \ + requested.", + ) + .takes_value(false), + ) .get_matches(); + let quiet = arg_matches.is_present("quiet"); + let (mut config, config_path) = config::get_config( arg_matches.is_present("no-config"), arg_matches.value_of("config"), arg_matches.value_of("install-dir"), arg_matches.value_of("cache-dir"), + quiet, )?; let client = ClientBuilder::new() @@ -152,15 +165,18 @@ fn run() -> Result<(), Error> { .map_err(Error::HttpClientCreateError)?; if !arg_matches.is_present("no-auto-update") { - update::update(&config, &client)?; + update::update(&config, &client, quiet)?; - println!(); + if !quiet { + println!(); + } } command::enter_command_mode( &mut config, &config_path, &client, + quiet, arg_matches.values_of("username"), arg_matches.is_present("detach"), ) diff --git a/src/update.rs b/src/update.rs index 23da5dd..e9d6c74 100644 --- a/src/update.rs +++ b/src/update.rs @@ -13,7 +13,11 @@ use std::{ pub const BUFFER_SIZE: usize = 0x20_00; pub const DEFAULT_ARCH: &str = "linux2"; -pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { +pub fn update( + config: &Config, + client: &reqwest::Client, + quiet: bool, +) -> Result<(), Error> { ensure_dir(&config.install_dir)?; ensure_dir(&config.cache_dir)?; @@ -27,12 +31,14 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { let mut install_dir = config.install_dir.clone(); for (i, (file_name, file_obj)) in manifest_map.iter().enumerate() { - println!( - "[{:2}/{}] Checking for updates for {}", - i + 1, - manifest_map.len(), - file_name, - ); + if !quiet { + println!( + "[{:2}/{}] Checking for updates for {}", + i + 1, + manifest_map.len(), + file_name, + ); + } let file_map = if let serde_json::Value::Object(m) = file_obj { m @@ -69,14 +75,19 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { } if !supported_by_this_arch { - println!( - " Not supported by this OS & architecture, skipping..." - ); + if !quiet { + println!( + " Not supported by this OS & architecture, \ + skipping..." + ); + } continue; } - println!(" Checking to see if file already exists..."); + if !quiet { + println!(" Checking to see if file already exists..."); + } install_dir.push(file_name); @@ -84,10 +95,12 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { Ok(f) => Some(f), Err(ioe) => match ioe.kind() { io::ErrorKind::NotFound => { - println!( - " File doesn't exist, downloading from \ - scratch..." - ); + if !quiet { + println!( + " File doesn't exist, downloading from \ + scratch..." + ); + } let mut file_buf = [0u8; BUFFER_SIZE]; let compressed_file_name = file_map @@ -138,6 +151,7 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { &mut file_buf, config, client, + quiet, compressed_file_name, file_name, &compressed_sha, @@ -156,6 +170,7 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { update_existing_file( config, client, + quiet, f, file_map, file_name, @@ -168,7 +183,9 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { #[cfg(unix)] { - println!("Making sure TTREngine is executable..."); + if !quiet { + println!("Making sure TTREngine is executable..."); + } install_dir.push("TTREngine"); let mut ttrengine_perms = fs::metadata(&install_dir) @@ -181,14 +198,20 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { .permissions(); let ttrengine_mode = ttrengine_perms.mode(); if (ttrengine_mode & 0o100) == 0 { - println!("TTREngine isn't executable, setting executable bit..."); + if !quiet { + println!( + "TTREngine isn't executable, setting executable bit..." + ); + } ttrengine_perms.set_mode(ttrengine_mode | 0o700); fs::set_permissions(&install_dir, ttrengine_perms) .map_err(Error::PermissionsSetError)?; - println!("TTREngine is now executable!"); - } else { + if !quiet { + println!("TTREngine is now executable!"); + } + } else if !quiet { println!("TTREngine is already executable!"); } } @@ -199,12 +222,15 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { fn update_existing_file, P: AsRef>( config: &Config, client: &reqwest::Client, + quiet: bool, mut already_existing_file: File, file_map: &serde_json::Map, file_name: S, full_file_path: P, ) -> Result<(), Error> { - println!(" File exists, checking SHA1 hash..."); + if !quiet { + println!(" File exists, checking SHA1 hash..."); + } let mut file_buf = [0u8; BUFFER_SIZE]; let initial_sha = @@ -223,20 +249,24 @@ fn update_existing_file, P: AsRef>( })?; if initial_sha == manifest_sha { - println!(" SHA1 hash matches!"); + if !quiet { + println!(" SHA1 hash matches!"); + } return Ok(()); } - print!(" SHA1 hash mismatch:\n Local: "); - for b in initial_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in manifest_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in initial_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in manifest_sha.iter() { + print!("{:02x}", b); + } + println!("\n Checking for a patch..."); } - println!("\n Checking for a patch..."); let patches_map = file_map .get("patches") @@ -278,7 +308,9 @@ fn update_existing_file, P: AsRef>( ) })?; - println!(" Found a patch! Downloading it..."); + if !quiet { + println!(" Found a patch! Downloading it..."); + } let mut extracted_patch_file_name = String::with_capacity(patch_file_name.len() + ".extracted".len()); @@ -289,6 +321,7 @@ fn update_existing_file, P: AsRef>( &mut file_buf, config, client, + quiet, patch_file_name, &extracted_patch_file_name, &patch_map @@ -320,11 +353,15 @@ fn update_existing_file, P: AsRef>( 5, )?; - println!(" Applying patch..."); + if !quiet { + println!(" Applying patch..."); + } patch::patch_file(&extracted_patch_file_name, full_file_path)?; - println!(" File patched successfully!"); + if !quiet { + println!(" File patched successfully!"); + } did_patch = true; @@ -332,7 +369,9 @@ fn update_existing_file, P: AsRef>( } if !did_patch { - println!(" No patches found, downloading from scratch..."); + if !quiet { + println!(" No patches found, downloading from scratch..."); + } let compressed_file_name = file_map .get("dl") @@ -362,6 +401,7 @@ fn update_existing_file, P: AsRef>( &mut file_buf, config, client, + quiet, compressed_file_name, file_name, &compressed_sha, @@ -456,6 +496,7 @@ fn download_file, T: AsRef>( buf: &mut [u8], config: &Config, client: &reqwest::Client, + quiet: bool, compressed_file_name: S, decompressed_file_name: T, compressed_sha: &[u8; 20], @@ -490,12 +531,14 @@ fn download_file, T: AsRef>( }; for i in 1..=max_tries { - println!( - " Downloading {} [attempt {}/{}]", - compressed_file_name.as_ref(), - i, - max_tries, - ); + if !quiet { + println!( + " Downloading {} [attempt {}/{}]", + compressed_file_name.as_ref(), + i, + max_tries, + ); + } let mut dl_resp = client .get(&dl_uri) @@ -518,53 +561,67 @@ fn download_file, T: AsRef>( .map_err(Error::CopyIntoFileError)?; } - println!( - " Checking SHA1 hash of {}", - compressed_file_name.as_ref(), - ); + if !quiet { + println!( + " Checking SHA1 hash of {}", + compressed_file_name.as_ref(), + ); + } let dled_sha = sha_of_file_by_path(&compressed_file_path, buf)?; if &dled_sha != compressed_sha { - print!(" SHA1 hash mismatch:\n Local: "); - for b in dled_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in compressed_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in dled_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in compressed_sha.iter() { + print!("{:02x}", b); + } + println!("\n Re-downloading..."); } - println!("\n Re-downloading..."); continue; } - println!(" SHA1 hash matches! Extracting..."); + if !quiet { + println!(" SHA1 hash matches! Extracting..."); + } decompress_file(buf, &compressed_file_path, &decompressed_file_path)?; - println!(" Checking SHA1 hash of extracted file..."); + if !quiet { + println!(" Checking SHA1 hash of extracted file..."); + } let extracted_sha = sha_of_file_by_path(&decompressed_file_path, buf)?; if &extracted_sha != decompressed_sha { - print!(" SHA1 hash mismatch:\n Local: "); - for b in extracted_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in decompressed_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in extracted_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in decompressed_sha.iter() { + print!("{:02x}", b); + } + println!("\n Re-downloading..."); } - println!("\n Re-downloading..."); continue; } - println!(" SHA1 hash matches!"); + if !quiet { + println!(" SHA1 hash matches!"); + } break; } - println!(" Deleting compressed version..."); + if !quiet { + println!(" Deleting compressed version..."); + } let mut loc = if to_cache { config.cache_dir.clone() @@ -574,10 +631,12 @@ fn download_file, T: AsRef>( loc.push(compressed_file_name.as_ref()); fs::remove_file(&loc).map_err(Error::RemoveFileError)?; - println!( - " {} all done downloading!", - decompressed_file_name.as_ref(), - ); + if !quiet { + println!( + " {} all done downloading!", + decompressed_file_name.as_ref(), + ); + } Ok(()) }