g3tFO`h&
zh+w(>>Gd7ZZ~~qtZL?)VQ%qbo;jC$7jZETY8UR{W(3m^4*e+7fcgxYm6gff4P-W
zH8y-hI*G0-=W&(sQ_V+jSy#U2GUmeNCr&p;QB9hMscvCRQgc%s2#`9S3Itjn4+O4M
zY9WhK^TJ?C(z%mV2~m=C5V953q-MHy-?b=IUdrc6@>Tw=OeduzfwHot<(&+G*oyw9
z6w*`N+IV^jWgGXg^MnZ;6}_#gD858}??$DME-Be;@g8?3P4puCLF0C_dBvHREH26W
zkNLZEeyBP7|BAoAA=;cLo!mz8pkdO@+&W~_tiYOmyPK$HwTsC*bTE*6^jNc1<-0Bw
zJa1N?xkG*DpK3!t$-j%mpSEgFbWpmL)6&ly*?O#AgX^K2XJ=|0xPRX6tQNHSY#)>%
zU34?e2QOc|C-<|m(fm|!{+H};L&VRLB)e>vUE;9pEASty7jK`YF-l{d8>c*e?2Q-5
z6NB@nOXkRUQ+a=i{LfZ9T;9?j-6dW73i(hJNzOZp&KN!o-)4-0hs%aw$1vJ}e&5xZ
zXa0n&EV&T5ty=k~DE(5&%I%Gfi(vh)SDjW&ELdUbzzU`CBbL
zSWO$OeqDCKWwyO4W1rHi(sh4g`i|tl`WUiEqHPm>2GkF+O?FlO)yOXL3y2C=>Th*a
zY9sa6cxC0xSU8|9nx6*ipDvrn($gch%wHjzx-^-%aScIj23EO>hz2=LUoeAMbx%Be6>%*K9geKN2iEfExId}Zm|8*lKgAXKjj|P
zsMCN09g1{!*GukruUqEeP&tyFtnMr^}65f8F@MdTQs`xD<|
zBNp6k{n1I%Cz!{I4o}G@v~cdO%-23TEDlu!$xn{6jdbJ2U(c4==^!!M+hu;pMA
zlTF&f724q0+p=LTC|a+y&MYZTl}<3HPQ-lhzAAS+`>qzn@J9Oe)3
zo^jGe?mc?I&QDOOF^6NmKynjI&fYWc%(H@nd(9x#w?kTAt8*q_V1yj#pp~B~M>3~ro!r?>*uGf4T!*a868VpIGw)!0)cG%3Lr(bR)e*wabSy
z^~H~a`b)28X6U*iM%}3^bw`)PJaV)2$+3=|hsw;nqBN_YAn%$vR?V1!j(Kq2%yG&i
zrtJfoXTAyDXnYFNO-&w*QJOc{ez|}amM@=ELb<@d3P_j~tV=DtGfqvh%k9;DOQDIbGdT_2|YL-S?_
zq%(a&`fA(vp&@iV$SjPpiPZnVfdl48Kl;%b(T=Ns&i*3VJl_hzpLR$-IwHCDF60Au
z=sqAB<1XnJk09SufBeVLEj}WfQzG@ppZOD?_=Ne@uYMKsMRxT`^t`FESoA(qGGSZW
z2dICWlx{{g%Et%i&J6WoZ~#tT&l<5)Iv`tr{U*Pqw-c^Ec9V~Mv9X3Ur|
zb{sx_yvA=a-ga!1ejS?ye8kAM8*=F&?qwYq=&&G0dEzS{A$f%=Qit=-AhA9+r?*LO224}R44-C+HdUo(xn
zZ?{W*Lo&{4iv!IeEDwG~@>D$i7e0T_J@;5${_x?$O-4qBL2r*ui~dZT9((LDlbM+r
zPxTG;haV!dxcN1GST?S0@?~i0@52K(O_jZ8X=~;`^6d!G5dBAX|G4Up?d6MK{G$2R
zx4vb4;aw%MLE!`W-S2+aw&O2<`AeApoO>_wY~e3DwmxIBJ%R(0?6imE)AJ+sQOL+1
z^k?F!V{43D^WcA%Yp?#y
zwg}y6bE^=nr)ruKv^m+Y>r`+Q6JdeY5vXBX0`TpT4lVY}d!$-1ts1
zelYNVzGF^0EN_nLU%x#bpU11OzS{Kc+0&dlRoli%U9lzq{qKLb@0x3B?Xf3FX&
z6DLlzc*17p{86Ljoi5w-gzYOV{Xj$LGLVO4TbQ;&>v@vi{W8$`;y>%r@`ft$n19_q@%sVv
z?~w<6Sa!Uxst=c3AND~mJ!)y#A8n_0YgvHwx6YsQGDpMKiX
z4{MK(9u1!h?L1sAUCd0YGor6De#(cy(egCu<*$(cUS!qnJv1b`x<>U*W1O(MG4)^C
zj*bccjHlPjhfO{RYD1`Qg9Z&UEn2j&{@ZoYPH}OudFrXB?3fJgWM^lG@_;bmaYHok
z0{7INI&co^Jqkq2w^K(_w1eNvPn!!RGflzg&aJ!fXee200p76vAN|aD`6xQSbk?3R
zzJB$qUp4*u^|L+%`0F1!bjT)riN=o~Z*IT+b_@5v{`Id`CUTX>-)&oEiFqq`ij{d?
z-Cg|!$12hFzkWOY!I*WYJ=Fiz^kMj2w108KYgTt3O&?DF@Zd4h0hLN`g^W+V;p>cF
z*x}(tB<5kz74-i7?|qb
zt7=F3&BOEOkC&`{T)MB&oIrMpkUpGpn9q&TxKg6^0q}d~?2kV3h`Ij{_nSZd@sD<0
z1H7KOFzfsFmWGcZRtKkXWw_)O>hARLz?}r`YuqhVy>ExNyj!}(RWs&!m)4%4XIxRX
z<1)`W)+57wH>E-uN9S?6dEl4Vm@b((36_@?M;hEf${
z0kVXvzoSod$b)hxNoTOiB$aG3E2OjK%>8ui=}{B@mnn99LEiPt_>OMGcjhGREx0Nc
zzlm0F|8Mk%U_$5BTK#wzdQW6<2PgmeDfMfO>!C3Z{)OHb-C1OUKOob<8}McI&l8~=
z`MMOzZuz~*1*-$g%eVTgmGE`24b7xu`GMrrMUtmaQbr`b(iZs_+d5INI_+Pg5BcWV
zw(>4Ko;<;=e2Y)Ym!`GwA6U3&W5V@~_5p1GkFq~rBR`l9DtoWfO*RvF5_>|GK-+K4k*s8J*
z9{vb)Q+iTf5oh_3O(&4NZ|_C2iTp~o=oHDU)yz}h$R1_ut~ON3FR(=NZt95q1(QX0
z9px+e2ifUw6JNP5_t4>ss3P?}S4Z;x(!iMfceOTPQ%li8Kf!*Tc+eQZ^F^imWT*ei
z%CenT=N&nE;k?~D0#ymD4Q|RdEtjo!MOooTR+sO(qTpCn^W_zl=M=6@+4eIjOSC8B
z0yKEMnRk}668D8T6?x|?IVZ_+iE}6U69vy&6vdxjRICinErVyRb(dd~ypyzcopXzt
zvwW89ePP5oiF>VgPw1>=T=spP3-vk6y6QXI@>PzjN7z~QwfAa=t+zX?eYQOvgYDB9
zIN0_l1>vC&EnM_rbE8KBh=mu|HYK(6&e(GJjl)~le}}T_q!jYg(hrTbo=n-Em1EU`
zoq_lEZMQbBxw|v9uBu^vh-am8jhyMSiu^#*zHPMiBMbKAT&Fcg-xObbK>WRnY_0t@
zC;j$|^me?;YtQu@5oIirPO*{q2efDZDF?9m3j3_37R-{9fSk5}j#-vPBD
zL<7BZ#?;$>HwWQe_pQp!QhGq?Vx=Y}1Ii1gdv&g4PS;ufN9fP%!X?kTWDK%%Kz(Q1
zGAh3=KggQCz_<97d3x(K3qR#?NU6X2+ou!*C7^MlN#LL|X@5(lWF^~F~%L*RMBn??yY*2k;wp-%|GI{3X@$D@zf-`OV_e+zT~MoK+aG&U@bOOs&IA
z>r45r{m!?oF8tFbc$wzHVQpZXtM5C$vO$NytRkge}nuQ1B^e7
zeW=X9tevTfJCSj(czLDsd897Rzp}n|@Z8z4T^q1v`)#n%aPQjh^djzC^lQ)*dU5IR
zPRr+em1K&$mXzi-Z){os_l$2^6O`Omz6R10gzyMW;^Ps$?ro%((^?~v@c)ANB>EHD
zK%xz8Q@Yz{q4(VT!83XaU`IRUyBaE&?|~;{C}rb+FL)A1prh(~tzgk8v_RY6-Mi%?
ztugD1zpnFLVV$|dh5THs9mEd<+AH4+^N##_C(4JIGl9@#F+|DHP8I-dDm5D$H6iS
zA9TskN)7$6?sJWP>*nJjo^4CELVRJ1C5N>ZEnG>A9pc<2dPLH_>*MI^GCP
zEjNQU5lf?H{J}rY$z72!pbu)Eu~j
z_+q@x4>-ElJS7?5vS@h&b3Z?xqq<~Q?2N1Jz~a?cUo{t8aDnv;!j2kkjdUc;xCaJ{
z)7iync(Z$|yT}
z&@9`%QGFoxd{R2KO5~wfJTTaH+HdEzv1MA1o`!+<{kydmD0-yDdKe*TY
zS+RCgUei31b)&XF`PU0LUiw^e7tvZ)LcGr3KGs0|=YRgEx#W^dZ2XnF)-Ua(
zxpnTIG1N$p5TXIr<2l*#Oxus|F)_%XePX-&W2H70917Ha_|}sVe2covU+|=S3LYTF
zxE}^wOFqQc`T@;pPRd_D)P6m)wiv!Y)Aq9lg!M!4eS9?WBW&!WKz?t;!eRbPeI4$(
zMn?^f`({oEYd?Jf7-)|CEybCuU_ME^N$>!xV+i_qpGp5GzAy4Veus>E_|+5JKUN&D
zhQNmQQ|C7~My>_-*09sZnY152
zb`@&n9@Zd!<};tM@c`io%zv2^)D?F+9(cI+d-kRF!ha17Fke&q(&Zy_ZM61ps4Q+;TXbmm)9Q02OZ9o3W#2Tah_?&+Bv!Asx5cjMry7}gtZJadXQsw02
zgkq(|(`NrWw4XX7zq0-v{Umid$8xSPEZ@*8XlO!vd2FR`o#ccRqCF1su@zV8dx>
z`lH`s=T^>kC=45o@i6zrB&yuKm58_MA+?o0}*>g^Nx@Oi1ccCtdp#A8GrE_jSbkm%uJdinp
z#>q;b&C$X@Fq04CfCjf8e8T&PJBUwqv~?`VLVf!5vFnpBzx;9=BaQD8S*z*V58kjh
z``7H#e)P7|RgWuItaNbhKe(5#-%W4j&DhMGQR~V>;~?}TTfFGMYlHC5x+s-p$N%Zm
zr$&8KJBt!CMu9v^($D*}=-TsnG
z!~++gJHYSlB9P_Wd6h2I`n*u_l)(CYjdKt3;yts_5gtfT4}$Ckt0V&
zd#%=Qw4XN9b`rRg{yXGXBe}3zG|@wJ9yKNs`Vn-+(j^^YyziLyW>|jHccf@9s@#O^
z8tgSfI~eEC^TvA&8#c@|Yu3#2OyZ^1XCENnEn2f8zuSu^C|FVNH?2)eDQfH0(*oezz54#5+bm=%Rleh-)~gV}q$*aMka3vr-*nSWc5Q4TG7T~Vqa|JX&HWv{Om9rQ>$xL^L((c2CnXusOhOuC}M%zNnrF1`-=00;aq
z@M{{R@o+=gwgTDsX6Tz*3*nJ%Sd*u0t*$H4`95)5n>TN6?P-z4eM{
zJ9#nx)9;}%Me8ms{&@xr`fZ$OQp>gp1|BP59!qQm5KaMoEJ{AWsztmIdG`cr86Hu
z59A*Q@Jp?Mz50oCM9^HaVBq{7klWDn0|VN{+@JNRF0n3^c_Hma5AdDue8=J(T}b3%
z+m0_tJ#D8>T4P$R`itN1yRbf<=i2Sgv>zUzwi0uHk!b%E?SCyoFQzzbwS2dD55Je>
zGSNY>FEIB<-$jfF;(bFC@I~f==z*CVv~Jzn+Co_OPdg(I+ji+TC#%2Lg?HLcj4=5`
z)G6nb}fxxAiG1|u`@lomyV}WdnWx_
zYpdm-9bL|g)$YjOmz3lMR#xn6E?C?p8~Q5o6UCD9_@I-kBHK^@0|pvD%$kxs8xOAX
z#1X|OQ_?bgww0$%=K?GM0SbAOHkEQu)Xa=#H@wr>Onaif3s1
zTQnL7!DP*IRu{?qS>IW>)#ztgha5ZoL*GXFj7IZ!0tfQ-s#Klsol+pWZzSAD!b|nH
zGL+6Ol?G|9c?kb+=Ytt)v-*I$1~%S2%8Mll4A85@>;I3Rl{fZ61D?+xe{>~1M;WA`R
zfAN3Acg(@CNogGR@bC43YU%fnNS{%pe7Y^$yY(YytIx*+Px(&-QjeAshx}`5<3!mJ
zkE1{E!yuXr>HN2O&n5Z_^EYe_$ndXb4y~5%`H<$bTSYrdl?DrjPe_ON(?xr7Zx#F%
zQ$Ddc81b|z(RVhVI-yuy*~HbpTz&LO`BLn7IklH)z>DcX`#ignH0VAJGEjbodovsk3@zQ6K%RQa|NZMRh0FIBQ}E_F_{icRwVqLNL475fUCNnZGt
zWbiriy*kM}3cS)cSo@{AlTHbz`!rAAD4pb7*`Im|CVv+V{Xjann^u$;UXpucf3x+K
zdzz%)jadl&0a}nOa<$e8JTH9il3k@jz6tCPFimYoj{1vm`W?xbpIlMCqeb44%0TLY
z(#EXDInN7PP~U7WTDVPi*W1$INtqVZdo$EAxo=M6Ytfe$qV?A$as(d^XGUQ{YT
zgAPR|Xvw(~0S7cc6&RZ9Yy%d!b4O`?0Z&Wq55xJ&;8`yga<9-2Nt_k>!8@~`3`a{8
zWBzk6s!B_ny`Bfp>}$ipo-|?S!r*<9cWx1RE)4!2ab}+zj?g)nZ}W(Av*3N`9IQvP
zh;#GceT#@Q`{!`DcDQq^;O`yXIoNJOHs}z%It9;#oCQZ)5h1{SptJozaJDZB?iR3|
z`Jk1~stI`FgN~dH*x~5nox=aKpHC+xVqApcMCj`M9w&k-pFhq+;5-D*L*QIPKyoay
z9CH%pCaf{}p3;L#KT!(XJMvuD^?dnf1_9wS7OvSxYO3aM=}IL^$CZlpTPG#-#^>ez
zGXs5-e;vdbeu7sheOl>GrAL*zOV{Pc^)Ymk=yWyTCoY9~YtsxfHeWF}i_)q@2aEO1
z-Ac9muA973=L?Jq0pW)J8Hwvh^jmM?dY*8Yt5l(c|FG3XPTaoIjM}nT{y@{r>zN}>
z$J94Xo8)eGZ6LZn^mqL?PO>&DeYZ<_J*RYy(s^DG6$@woM+bYI>5Eq@eL?9LN>3~G
zQJSZet5l(6agDzZ@#gV;?7wlc>5=ia^@GJ1n027e{^#_!et+x7wcl{(w1J9mZh65`
z(ZN*Zi+oVa|M={;{@<$v!PxdQog;DmjD8!Uv`lHc(gCGYN=`3pZA>FJ&o|xEhnjX9
zdYRViJ6oN+vvEb@+Sx2(o$(VGuyKmz8=`@Hl?A<>=LL;Kl7gkfHE}*Zp>&(l@0Ex*
zi@ju-bj{m!KATOYJm3Xg(%(`%oFvLT
zsx(>Y>q^$1(MX{9&}SoffootUn`0QR+v$F+aJN>eNa?U}t=JbS@*7%X<*~uJvyAow
zF|VWzFnzMdhwQQXE{qPq|G2HoYONiJ#B1XBvel>dlT2W3nfN9W%kF=bLVKTm=n&Usa=3D8LBXKPonwhlSlfj9T(=&6F=_Fh~pQ8Pg*L9Fz68j-MXKl)DlV25G
z)Yzj{Ru~PC7cw1vH*q{i=N06I%rH7XTB}-Rst)XT&OGE+B}@MwPVCm*
zs$knM)VYh2mCa{p?G+d!c#c*MB=+pf)?ckIt-E$-%|)&D!vcKGxR%UcGp*yy16}{=`)SXkK35ujK#ik{MVE@TzUXx1wZc2
z^csHBZo?bmJyFL1e|`R~^v8ldxQFj|R642ThlSA6i?I+7^@VJ9xk^k=Yst2Oj>3
zTaSJ=79N;u^vD?AXl45A&e#%b44^*Pkh-M}G1>0Rz
zz+_n7T=T@*+Oa#@Z&?tvzk1>{s(0c<7YYKc+sIGO_hx@8R7FShWOelIFa6vNJRO&{E7xB#cv
zci!1n6X(K@1FpR?-)gin{dDnq=7>7=(DD_R9=cPoY^`_Fb>EzKoL$-3l4`~C`JhY(
zg808dw7z(PaPU$}Pis@Jt52ZY#m4T3Xs!Lq(H<7l+Rci4mKDszVBh@DdVTl$QaN4&p9tK(~#!|NOa
z7@HWQBHPP-gpbKV!3SK
zik>DZj?FY{Csv(oOnu_&yJUaU+!KGVH#Jv?o=2>_{l8BV4Y5|bCMF+k#y(k>EfQXc
z?|_3(G#Wxa^?Xc{;RWkd=l8AtSak#UA-<12C$dfT*=E2+{klL8_itp5R*a}*vuIbA
zSyHUMhw4nc6D!sCZQaio?8>xw?vg$zj0Tv`)X`{HiO;fCFxLO_X&slF&6i$_vD%KBL~dks$<%d
zsp%8t79XrI%ZqbtOl9Is6WhSG8`%e4li*S-f&U5HR+#73*N!(6*>AXStMLN?1NbN*+p~||
zkldLuWggl~pN=*Uhz38$SCB2pSMw{UKmI`w4^7(rU70$^axwyU+6cy
z%eS0~wV=3+nm?uxpVA!B{(JAoWB>8PW>x9tAPtPRcxCLaYu<|=dZKzrU;;0ouPMGe
zykL}Y(Bxx55dTr-eLvpaHT6c!^oxW2M0p#k_np~nZFPwrvY8r0R^Zs|ip^zL9)|C#>L#`?ZWU$jpm*kYGcv&2Eq_ivH0ltsne!
zmtt4pAKxVC58^&3@23UzJmK#RJffkIP@C*xxB8ZSOX7EEs>bG4Mhj
z#G$?6h8t`wU*huKe*5iquZ|8KIvDoyYpkR4m}p@4rkHa;M+criLT!CXB))6kYkZU)
zS-uX{ij~%m*q~<{|3TdQ`2Mh{vVQHl*31b!-N>An_y;a?q?=1C1^0wwZ@hzjC+O?y
zBsLMt{a3&GmEE6W#flY;S5PpgcxZrr&`=);)<2+USKP+2vy0PMD|OcTe-QT}zCT!V
z5adudFR2UXkxYa|oG+oC1L0BlB)xUKIVSmHykF|$xI
zz!$;M**Jo@KO??h)0XJEz`4SGR#~Ar(a7VyLmc}x5UU*Ali0VAy?FldkAIl_{CxM?
zSvwz6Tx@h#(eMusVC_<(e#xE;*hBnd%>l^(tb1>C8NlVKv-RgW6TV+V13^D+;T(9(
zRr|BccZA~XpA94o88XD~TLbQi&(FTK@P76piQJdqY?M!)hff@{`w6hOJneP~{Npp?
zx0%+!sz!FI{hJqyS~B1%;s0snbGGn*#(dvjclNYl9*C?@40ZNfud2P}N~58Hy-DxC
z|NcJKI3U;XSK$3$_`(-L
z`2YOpKX1qVC!To1ut!BxAIxc?0l%*}JOJNOPo}P`&)0rt*Sr*^5fkC+#=?IP_g3Cl
z-HKU_MSwV$hwvW2kTdtOnx
z*|M*=N%}o_C@Cqi`?P|4($!aAZTDto>^~bipLlWa-m_zY^c}Nh=K#ixi}m|K)$j!H
z&zdLM)fz;Yl8fK5Owu0
z?-{-|6W|{UBm)rNQq4{L2;v^T-$|*~dR_c<`{hgw^L30>H~f9r6KU+$cZK^5vvr@w
z`zD6>o;`ca4}bW>P~X2^dvG%keE8vqO-@eE`vvu(dO!o2dkf55^%Z1feAr{b*Z({H
zEa+>JEBxQm5c~&mkG%gQr6Q$}e!^Wd2Czm2+k9Pmf9lglc0Tq6TO{AxZTm}_9QOcq
z(V|6myjM@KJm4GO_=fHK?7z&u0*R7Vh0|#84sLON)wboc0e_gPK5AYn{s`1;Bs)YYX)K9@>+%&+uN*5@-sCncG
zd{=ZGJ!yREojq3lKlU8O!@pK>qH8~Vt0ciwqti1%anbG(1!#*JsY_%q61
z`%jxSd-KgC?XT8W{+{*W9~!`}jtxQh?;|~6Lh%HG_`g(iGn2Jz{jw*8>8AX&z!*?p
z+?Fu>SDYLCCnY6?Y`yS*Y`sqBgCD^A`S9?+B_aINAK#R0Cj88k43JR#NsIsDw2w-M
zJcYHm?KkwbyxWg=|8;$Os&kEhbUx_z@b3ZlEn2iNci(-t<^7W;O*$w1C=q&V2>yY2
zxAdX-)+H^g_doQ|L+?wuKaw^YivM5?stWl6+yPGGJ$RQS{68pv#AD1mm`^g_3*p=+4?q`n
z*{jcW|9|hj_w1hR4*%>;{z2jW(1OE1>q+8`SqsdAaW9U6M~BlyXh7q}_oU+~?VxoU
z@x{@KE}NW7{KNb4@5ROs{++%b{J-J$P66zfm^Hba?yI>#R=M>ZGIbfV%uv&n5ox?Psh9_au1#AO7$M1Mkny&W>cY
z@5_7F|ABiVI(O)V_(I~((}YW6Y{!d!%l|cRU=A>Ckk(z`R}joA<`{tQDew7pQRjO6
zPf1BJH{Eno2>*`vzxd*dX8->E?@N3~R?6X@cm?>#_~XSy!rFgNzYDHAPPctILHzq=
zKw@`vR;+c(kJkT@0b;FRJD2@`#E20gKd*}}y2$+GCqJ=c|GD|BSHPXysyE(
zXA|^dhSfg?0QZ+u`>+PFR5Bp@(j?aZ^}dw>x34_LI*n%)qlERw;5r%&cAa(ecx)Zw)iCjNlXC+>J%&3jfG=pZ@fx
zL;e4fOD-|^dXk_8Z2#y5m3Yf-F0?t@8ACRH?w~IdQ)6nZ2duq_rTg8
zWP)h4z;7S__{Xi!C}RWb!^V#vZ{vhC6)%W||M+5t1=rW*FZR}j?@DZ4co6?q21J(t
zPSGpY71tUXAhwf>gLp3be`;!~UDN0KHf#Ox^?3T}r>zgL!yR%Sw7`6@UAuO6EdaFO
zY=!Q7Y=(>rzyJO3Z9a?(j0sI~M8iKY_QrtvV`bx`jl9UZaP{Sc)`bW0e}($`g8q^L
z9Zu`p+rYoK*15nx_;j+LTi=JA-?3xIn7&?&8La<7Zls^za?34YJON&C^UXI~9Rj=n
z9pculThBTP#KJ%Pm-Uy?bgq$dKu>QkG|7O8#RdZZN*8JD7=kSU84!Hdx4(^lZ>@8I
zfAo7!_G2vnumAcl>*pP>-tXA4V|JWC26S}fcmZpLSuY3;z%z&!bvBQ>@XsEJ_*Mer
zNSwQSp0O{f#^r=#1KIvB|1shJY0WuKxj4nFNx<(XmJGmJHsUio9@8jkj)gj^WH^Dxw
zX4HSUcf~h;p+0?(e(%v*{d;S9{KAX*-IV?x2M!!C_uO+&NcQ{WCqHR%_27dKnl)?I
zB!YhXF7rP8g#5ZB#uQ`3__}@%MB6z4jRyu)X%XT+*O5L6!$-
zEumtsZFBMIpn>+Oy={C$=rA%-uPO3ZWexiyihtUa_$PkDSHAL<5dJ^=+0R-$F{U?E
zX2XAY+_-UJK7@=b%pJf#^NN)#S0+qb@qADp{)rcZkB-+bYt~x%=>T0Jx_Q=xt1lcT($&hx#fKVD4FtkL-KCcG{j{3}@*(E52<
zUenszgYZX*B?EZ8X|9z|n-c&1`}Yr%{aEA0IQ`aJZ=JD?hnR4G{p(-D=7%nR0A);{
zKE2WHiuK_iI7f?>?C<~d*H=9I{Wi$}39Spa{XZxJYE8kZXV!bRNAhI9gBd$x@2`lh
z0R0o|{_qn%+y0-7!SH$dKIy8fuClT^{hv8uV;osoS?0FeZVQzGKX9?5up{Ab+L%W?
z_^)ptOK=s851H_~@L>N(5BM9c;W@+}PUJ^=)~+*I9+L;ao4RETX)^rd?}d+t!#{I1
z`Xzl9ols*O*n@}{i!Y%o2i*{I0Eze#jd|3Ef8ocD0gSc&KJUK##haIQ=&1oOWRYCO`5=u3(KoU1I=p$IB_bo237
zI+e2qUvRhH3p!x$8g!A+VPv9S>{rrV`eQ*`vdb>BctKx>d=CE6*EU8>
zZ-*0j0P}vQV{&ED{~vqoF|%XG4)^LApX0^97c=a&P~UX@9~=>vSH2lXWdnXjIAU#I
zyr{SD@xIc<=#Ysm;Py);@8>)pqnJDZ`CwqyRJ*_F*~CA(e8yi@*d}5+{_>Z
zdt)CPHf%7T`qZaF{=Y{YPHQ^uLGiy}D7~t&>5ZrrW
zs`~!5iQ*mt;2Vt_q;`tQUCmhH#sKus=%Hhc0n~S5{%Y}_6mvG$e@6OxJG~EMKe%e_
zBhto*y%?R~0}ni4CQO*nXvKN>*ZNP%(j)Q~M8!QY2L7I(#>=9C8htSF__e=XzHo1S
zKpTpGz7zlW-IT($hmq$U{yC$AjO7zR-AMQ^C-2>Q)?#|DUAs0+Pm2x+-cOv@#+J!J
zE^`gy#5;cD^vvKtUOPiPL~>BELX%21S^W3P9H)L1dp)+d7Sq$wf*15}(%XA{zc_Ke
zPv3WkhksoN8VM%K^V#S$aNSYyb52Nf%Lo%XlFo`M{Wp0BR`>^-{+>+$jZd?^?YJiWnu-{GEf
z5dYVyj5Wjk$H=3%r6_)S+Q*zlLpYs5YGWTkoCYmJGj_0KjVI%;>S`1IoXq>5efHV2
z!uuT^Oq@8;;8#q!;NPt;smss6eOuR=y#iM6&a?a74A#D2tiOZLl01LD=sGv}EMowB
zVrt&iD16_Kf43%REIxkPZ^FqL)QdRok_|N0NB0Y3{VK6y&K5t{i
zXbh?n;G;!i;#n#PgsJlJM8VPwVf0|9hk9{G!z<
zT1+AA&d40_g@znsf>4eLvp)*U$j-2+4A#
z>@^Tsx8VL0QR@X=xL7fK_iXYjcE2lP-mcn{n^AuB;6sAhYf1?PWEnkrbZ87l7W>w>
zzGeG9wz|fU!D8VNnFGDQqdO;aU<+p5X`+YQC#r7TdprO>I&H_gsBjjJjw&@s&*R5+
zwCf=L?YeMqT|<*zz1mSP#re{EQB&mn1U&+}31~q3IUZ6xbPT9*Z}h_)?2$(v3E=?U
z->-lDYug7C_4P>vU-W%qMmjq)G;r&!w_3Wx$COxui5!)Z^H*w55OB{vchUR3v+cV*
zGZx3e3`pJZ
z4}LSjSTP3bvt
zhWi~+uln}&jb^L%(*SxzbRPB50RC8)Uw(NA5Ac5WZv+4MVKnxE4zWv@E@82Rz&&e8
z8FTP2O2qCXdB-H}*<^8#T>OOgwT=h(9!9NWuvqheSpG_U%eaT!%R6h;FVKO+I(qi(Y3JPFfaLV=;2&R~#)|36JZ|~&<<^hH
z&GlWG#1Mw&&;usoTUa67zb84Levh9t`ZGTqWA*#+-`m*z0pOX!$yw$5YH#QW;{O(v
zn~P6bc%2vnLUCuJ%7D0VvKMf!YteduE1pFLk=?RD~Pp(d-v|0@cImJ#X2B#N6aOieBtN}eJ}b3?EDKC
zE{w~sfIO-9?t>L(>8|WE#yv6@YcTNr7A~d=|7S(s_n|#>3I3&9vg^X-Q(kL-3h?K}
z9jPx?OpPB=G}>mr_x_tESsuAke8ACwMSk#Kd3m{c>Zzwf^M7yzzL<-_mx=L9|HUt4
z>C&Z96aK>N15A8y_I^Z$Yo)cLe!6n`GRELjFnI7_%kLd6`s)o;4DiTBGUrLkOnqw?|h^>C4z1qS2x1l^A_y8B;yNic5*q^5!6xaJ08W0Ze5PvS~ldXA+coFq-_~W{(
z`~>0Odbd^r|HO)M>&e`Ak!ME($Vkw@s**fYd7`#V$T$zL$KMltHCBQL;75QRiT#2b
zB2Vl-yw5DzrGBsazb^lrGsQh?dGNs!44ahi`-vjR1K3;SRp~9t8HZln@Vf9%9C*)8
z70=%8k+EVT@$cQYwlM3JDH>2L`c-(y0DYgnjxQJU
zdDapT6R070$DrlmKHJ*lUe6kFMz{wS@O^x|)UTSH@B8u3b&v)w5gpzyJ5z@EQ8h6F
z+!|r%JkeM&(eaPY!=nM@W%eUjDL#PiB-+6|edNfIhPAt_{lFIJ68EeH#!rJYJ_Fzx
zSq?d&SFc`X_UzeKcZmHSxve2bwal3o_q((0T$cHL!}dz6(fc^QKgsfaxTKr${TiGBoR!nUC*U$j66TEaqNvs|L8s;`o`J|XkTQTW8Vj9K;s}ZuuQs?63JNS`hb5FRF;~ByD~%lp7zmp
z{9^Erp&!R?SM7e!yCJ?`umvOhap2RziopLLR%mVFW9Id_Rv+G))6|3Fgp8eH=e1EZE
z$X<+zqNK^+r;bYOJA@Akb_r}#weZhx{#Y@w;1KKg$Jae?dStzA#~8b3>Q2cOO86Pq
zmFBR&YVh60I#YhEHbUpj+3JqdP`m%v=KG1Q+iP;f`wA2++#KN=T|cL^D=K`1t4Lpx
zSon_iJ92e<#in~TeVFNZZ!!Cn#K+Fl`7I;{dQV34KW`z6(iB%j8zw!JAtcWu~^5UJo5nbMd+xg|UF&Pp2bJ%KA>MZ*d^=vi_|;LV*wFy^_tq}*z9`fcyJM!f2{lX)R{Xkv@>A>-V
zWx78F9W+!va`5t>!KsaRC4LKSIXd&76Q6h19-IATa_!Mw-D{z3+~$b*=+W}|F!23Y
z1S&i@UclbOeU!?;lNVdYi!T@nlSJ>a8wGXbQSr~5jCJgZ%{%L+0q}3vLMtX;EV`3^
zO#7(R_M3L?BM;<#*77S4#!C2QEKq)+f2Unamni*SX^r~iDQrpp*wGFy4LP%KRnRx4
z77c(O_S8NTolLYkq4UNsHWvQ*Ju*JJKObb0H{?@e`Tnl-yY>Eug73#7)F2Je##_}V
z`)C~4#~Kp+$myH(2S0q`z2>{%9@w>Tud?iKeqZ!>^Nr`dhU&bjGkkw?NZwCbWF1$cZxoYnk1o*R
znKM3a*m2-3*mTLCcqqigz@J6B%xcx~u
z1TScSL=3_XIv3+VO57>rEe|iX^)vjAe=_5|zKhC>JzZeUIwn7^nU9k{eyT5}ydnMl
z5bLi%yj{h@g~wNmms?yb|FyEuv&Tw1U8B=rzpYOw**#Zuj@7*LzsCsyV5nsE$Aa-<
z+1sk{BL~Nk{Mp^tADbxM;*_z1ai#V8E{ankd!l?9(bcez!G!JaVW&Q&`N;v5yIt#_
ziK9JO*DprmTK(G6YMf0v|5}0&fCdD6V0?pM4__^Y?-G-YF*uSJaL@jw*ckL~l$0)e
z@d~@{5Zx2k@++#rb+N_u5S8_e(l3+;@w2a1x=8ndX}i`Z*n;z~HwFX*f5!`cAv{Qb
zy#5sXl(P1SzVGOOe$6}(Uom|XEmi6F3gwZjH7)Z*TYYqmycve;V0n#E_49c&5(L1B
z)*nCzw+d%{H0LfOJ{~cuUy+>!zY_HE&VkipB9STFmoQg5Y4l8hjy|agYI44a^AI=>f%6bJ4}tR#I1hpI5I7Hk^ALFdLLlyS
zbIrovEDVI*p9%z8`G4pX2((b>A}L{>tFJ
z%C?6q;CS%f)!5y;0)p9xYFrq6-xUzL4`!I;o(F5($=wGtthw)KYZQ9yW$3D}pKXnO
z_qG66eLc4|4pmn_ke~m)mF`2;*YlRTFVxu`6j11Hbf$o$i2F|U-1{E$y|20!XOZ{5
z>f7i3>Vo6Qdw=z5aG}4vDECPb&pXw1FM#$wl_j?i-?eTUtvKZM<@e?{IO_t#JTIqY8jz0Uhq5zjjs6Gm{6_a^)~
z{KrpF-1`Z@GC&^!U@v|E*?V6FEx+?spe677GW6~{g<9N-$G!|Z+WQ&^dG|FL+Q&6D
zw$;^dE<<R>p#p4m^}egIyLScH>QhFrf-Sk`@CtC*yBc@2&-iC+9QxXWan0Kv
dj9Z1?)mY{{sa=HXHx|
literal 0
HcmV?d00001
diff --git a/PolygonGSArbiter/PolygonGSArbiter.csproj b/PolygonGSArbiter/PolygonGSArbiter.csproj
new file mode 100644
index 0000000..44ab0c5
--- /dev/null
+++ b/PolygonGSArbiter/PolygonGSArbiter.csproj
@@ -0,0 +1,99 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E317FEAE-B541-493C-8DB3-F6662B66FA92}
+ Exe
+ PolygonGSArbiter
+ PolygonGSArbiter
+ v4.7.2
+ 512
+ true
+ true
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ PlayerBetaServer.ico
+
+
+
+ ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4.7.2 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PolygonGSArbiter/PolygonGSP.cs b/PolygonGSArbiter/PolygonGSP.cs
new file mode 100644
index 0000000..729833c
--- /dev/null
+++ b/PolygonGSArbiter/PolygonGSP.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PolygonGSArbiter
+{
+ public class PolygonGSP
+ {
+ public string Operation { get; set; }
+ public string JobID { get; set; }
+ public int Version { get; set; }
+ public int PlaceID { get; set; }
+ public string Status { get; set; }
+ public string Message { get; set; }
+ }
+}
diff --git a/PolygonGSArbiter/Program.cs b/PolygonGSArbiter/Program.cs
new file mode 100644
index 0000000..57e8870
--- /dev/null
+++ b/PolygonGSArbiter/Program.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PolygonGSArbiter
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ ConsoleEx.WriteLine($"Access Key read: {Config.AccessKey}");
+ ConsoleEx.WriteLine($"Current Access key: {Config.AccessKey}");
+
+ ConsoleEx.WriteLine("Service starting...");
+
+ Task.Run(() => JobManager.MonitorUnresponsiveJobs());
+ Task.Run(() => WebManager.StartResourceReporter());
+
+ WebManager.SetMarker(true);
+
+ ConsoleEx.WriteLine("Initializing Project Polygon Arbiter Service");
+ int ServicePort = ArbiterService.Start();
+ ConsoleEx.WriteLine($"Service Started on port {ServicePort}");
+
+ Console.CancelKeyPress += delegate
+ {
+ Console.WriteLine("Service shutting down...");
+
+ ArbiterService.Stop();
+ WebManager.SetMarker(false);
+ JobManager.CloseAllJobs();
+
+ // wait for web requests to finish
+ Thread.Sleep(10000);
+ };
+
+ while (true)
+ {
+ Thread.Sleep(1000);
+ }
+ }
+ }
+
+ public class UnixTime
+ {
+ public static int GetTimestamp()
+ {
+ return (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
+ }
+ }
+}
diff --git a/PolygonGSArbiter/Properties/AssemblyInfo.cs b/PolygonGSArbiter/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1a726d1
--- /dev/null
+++ b/PolygonGSArbiter/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("PolygonGSArbiter")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PolygonGSArbiter")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e317feae-b541-493c-8db3-f6662b66fa92")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/PolygonGSArbiter/WebManager.cs b/PolygonGSArbiter/WebManager.cs
new file mode 100644
index 0000000..17fa1e4
--- /dev/null
+++ b/PolygonGSArbiter/WebManager.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using System.Net.Http;
+
+namespace PolygonGSArbiter
+{
+ class WebManager
+ {
+ private static readonly HttpClient WebClient = new HttpClient();
+
+ public static string GetGameserverScript(string JobID, int PlaceID, int Port)
+ {
+ return $"{Config.BaseUrlHTTP}/gameserver?jobId={JobID}&placeId={PlaceID}&port={Port}&maxPlayers=10&{Config.AccessKey}";
+ }
+
+ static int GetAvailableMemory()
+ {
+ PerformanceCounter performance = new PerformanceCounter("Memory", "Available MBytes");
+ return (int)performance.NextValue();
+ }
+
+ static int GetCpuUsage()
+ {
+ PerformanceCounter performance = new PerformanceCounter("Processor", "% Processor Time", "_Total");
+ performance.NextValue(); // this is always gonna be zero
+ Thread.Sleep(500);
+ return (int)Math.Round(performance.NextValue());
+ }
+
+ public static void SetMarker(bool Online)
+ {
+ int OnlineInt = Online ? 1 : 0;
+ WebClient.GetAsync($"{Config.BaseUrl}/set-marker?{Config.AccessKey}&GameserverID={Config.GameserverID}&Online={OnlineInt}");
+ }
+
+ public static void StartResourceReporter()
+ {
+ while (true)
+ {
+ string AvailableMemory = GetAvailableMemory().ToString();
+ string CpuUsage = GetCpuUsage().ToString();
+
+ Dictionary FormData = new Dictionary
+ {
+ { "GameserverID", Config.GameserverID.ToString() },
+ { "CpuUsage", CpuUsage },
+ { "AvailableMemory", AvailableMemory },
+ };
+
+ FormUrlEncodedContent FormContent = new FormUrlEncodedContent(FormData);
+
+ WebClient.PostAsync($"{Config.BaseUrl}/report-gameserver-resources?{Config.AccessKey}", FormContent);
+
+ Thread.Sleep(60000);
+ }
+ }
+
+ public static void UpdateJob(string JobID, string Status, int Port = 0)
+ {
+ if (Port == 0)
+ {
+ WebClient.GetAsync($"{Config.BaseUrl}/update-job?{Config.AccessKey}&JobID={JobID}&Status={Status}");
+ }
+ else
+ {
+ WebClient.GetAsync($"{Config.BaseUrl}/update-job?{Config.AccessKey}&JobID={JobID}&Status={Status}&MachineAddress={Config.MachineAddress}&ServerPort={Port}");
+
+ }
+ }
+ }
+}
diff --git a/PolygonGSArbiter/packages.config b/PolygonGSArbiter/packages.config
new file mode 100644
index 0000000..5eaa239
--- /dev/null
+++ b/PolygonGSArbiter/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..396e307
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# polygon-arbiter
+Manages gameserver requests sent from the Project Polygon website
+
+This is the backend service that was used to handle the launching and shutdown of dedicated gameservers on Project Polygon, with development having started in December 2021 and subsequently used in production in February 2022.
+
+While developing the gameserver system, I recorded a few demo videos of the arbiter in action, which I've linked below:
+ - [Proof of concept demo](https://youtu.be/bszlNpBIRTo)
+ - [Website integration demo](https://youtu.be/XF-MD0K5IOA)
+
+I've published this here purely for archival purposes, however I've had to omit the commit history from this release due to sensitive info being contained in the configs. I don't recommend that you use this in your work, but I won't stop you.