From 64a1396b97057d906e7cf2145cc7125816494ae6 Mon Sep 17 00:00:00 2001 From: lax1dude Date: Fri, 9 Aug 2024 20:28:45 -0700 Subject: [PATCH] :>1.0.0 Add new EaglerXBukkitAPI plugin files Use IEaglerXBukkitAPI.getAPI(player) to access the new official API for communication between your Bukkit plugins and an EaglerXBungee/EaglerXVelocity server --- gateway/EaglercraftXBukkitAPI/.gitignore | 10 + .../EaglercraftXBukkitAPI-Latest.jar | Bin 0 -> 116125 bytes gateway/EaglercraftXBukkitAPI/build.gradle | 40 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + gateway/EaglercraftXBukkitAPI/gradlew | 234 ++++++ gateway/EaglercraftXBukkitAPI/gradlew.bat | 89 ++ gateway/EaglercraftXBukkitAPI/settings.gradle | 2 + .../EaglerXBukkitAPIListener.java | 58 ++ .../EaglerXBukkitAPIPlugin.java | 86 ++ .../api/ClientBrandUUIDs.java | 37 + .../api/EaglerRPCException.java | 35 + .../api/EaglerRPCInitException.java | 45 + .../api/EnumSubscribeEvents.java | 39 + .../api/IEaglerRPCCloseHandler.java | 22 + .../api/IEaglerRPCEventHandler.java | 24 + .../api/IEaglerRPCFuture.java | 48 ++ .../api/IEaglerXBukkitAPI.java | 243 ++++++ .../api/ImageDataLoader.java | 96 +++ .../api/event/EventToggledVoice.java | 39 + .../api/event/EventWebViewMessage.java | 59 ++ .../api/event/EventWebViewOpenClose.java | 35 + .../api/event/IEaglerRPCEvent.java | 24 + .../response/EaglerRPCResponseException.java | 37 + .../response/EaglerRPCTimeoutException.java | 29 + .../api/response/IEaglerRPCResponse.java | 26 + .../api/response/ResponseBytes.java | 42 + .../api/response/ResponseCookie.java | 44 + .../api/response/ResponseString.java | 42 + .../api/response/ResponseUUID.java | 44 + .../api/response/ResponseVoiceStatus.java | 46 + .../api/response/ResponseWebViewStatus.java | 48 ++ .../impl/EaglerRPCFutureImpl.java | 55 ++ .../impl/EaglerXBukkitImpl.java | 788 ++++++++++++++++++ .../impl/HelloPacketFactory.java | 41 + .../bukkit_rpc_helper/impl/PlayerDataObj.java | 196 +++++ .../impl/ReusableByteArrayInputStream.java | 80 ++ .../impl/ReusableByteArrayOutputStream.java | 81 ++ .../src/main/resources/plugin.yml | 6 + 39 files changed, 2876 insertions(+) create mode 100644 gateway/EaglercraftXBukkitAPI/.gitignore create mode 100644 gateway/EaglercraftXBukkitAPI/EaglercraftXBukkitAPI-Latest.jar create mode 100644 gateway/EaglercraftXBukkitAPI/build.gradle create mode 100644 gateway/EaglercraftXBukkitAPI/gradle/wrapper/gradle-wrapper.jar create mode 100644 gateway/EaglercraftXBukkitAPI/gradle/wrapper/gradle-wrapper.properties create mode 100644 gateway/EaglercraftXBukkitAPI/gradlew create mode 100644 gateway/EaglercraftXBukkitAPI/gradlew.bat create mode 100644 gateway/EaglercraftXBukkitAPI/settings.gradle create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIListener.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIPlugin.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ClientBrandUUIDs.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCException.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCInitException.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EnumSubscribeEvents.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCCloseHandler.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCEventHandler.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCFuture.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerXBukkitAPI.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ImageDataLoader.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventToggledVoice.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewMessage.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewOpenClose.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/IEaglerRPCEvent.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCResponseException.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCTimeoutException.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/IEaglerRPCResponse.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseBytes.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseCookie.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseString.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseUUID.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseVoiceStatus.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseWebViewStatus.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerRPCFutureImpl.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerXBukkitImpl.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/HelloPacketFactory.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/PlayerDataObj.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayInputStream.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayOutputStream.java create mode 100644 gateway/EaglercraftXBukkitAPI/src/main/resources/plugin.yml diff --git a/gateway/EaglercraftXBukkitAPI/.gitignore b/gateway/EaglercraftXBukkitAPI/.gitignore new file mode 100644 index 0000000..e30d0db --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/.gitignore @@ -0,0 +1,10 @@ +lib/* +.idea/* +*.iml +out/* +/.gradle/ +/.settings/ +.classpath +.project +/build/ +/bin/ diff --git a/gateway/EaglercraftXBukkitAPI/EaglercraftXBukkitAPI-Latest.jar b/gateway/EaglercraftXBukkitAPI/EaglercraftXBukkitAPI-Latest.jar new file mode 100644 index 0000000000000000000000000000000000000000..5c6b63e86942db4a4a6402b95fa329ab850ebc0d GIT binary patch literal 116125 zcmcG0WpEu`lBL)piz?l3ov$}yb|YrG zBC3An&8)h0Pr}Jtr6>aqfd&Es4Gn^q52FS0=K%ZL<<9~0=adsu6{44t7iR1erDyj@};&*bB6S6Y&40B&)=xL@WXBw257Fl-= z_YT4Sld_d^@V{7v_@m4Y;PMxP|0?tKA2K#Z9?Yh$rhxxa_-}XkH--OO7+_>>18_2N zGBW$Gtq}ZI1KpSnxc*DCFfnj& zvUjmJvA6lZG)vrG+>ZUxs0a!IqW#~}EcPE$DExP$%8DY2|1e3$%wS?;_^+@K74oyxgS9yv!|=WW%tCD`3{XUJs z{2ILUzD*9l9c9G1Qg7KR^+PDkK`dB*2Y~?T%LNGxUn^Y*jASC~|5@~Zdo|?s_gmqA z;NkiO1jP8?Gl7bKn^PB2fZ5+CvPo4(0aXd$idc)nr`Vk|D zdTmxPP!r4%oD>V)<78s=_B_bAU_CCSF*64~dv+_l^4<6%Z|SjJZl&e4xq`xy5ZrzSdo3NKh45EnMgDMHZ|T&fU4Ttja=dKsd=&8cm^ z{>hePhqKCc=F&y_g@%<4K58FqsO5F6QF zg-VPrwFZ`~Wuw?$Vp9>e(NC_uUGe3&8PZI{S0!Jns$_`0Goc_RN}6iMAFkVrfL7ZT z{&`cH026ODUY8et1MFD0&6wT_|DC&|U8IWhnVqXOL1+kY3f9iYYg6Us{ZV=IZbd5S z)wW&r9L9wTZmO(&4D5%CTBVszV^I59N+x(5u_eGo?&t`(Kni5}fDq5c8OsxU6S|9t zgn;V{VCtR0F1&-tFv-^dSdLhq_?^7=<&%4!gbP~+Y%%)6=pK~QLP~CKIhuGNGolcl zQO|Y3EvT0~fnArPYPchQnzqnW!9DBJ@(v5z`4=?muXE(!Hjm&sk>o3yY^?||x6uZv zx{jn7@L$Vgj^8fNzAb`)2 z1s%eJfZ$SrfN1_(fbjR_-=*#8gZ6;_`B6V&!vPKt4$6U~ghW+Lj=uE*z)@ zT}a?q&#MK+(J*mN2P&$g(D-obt9dp@)2I%qil9`8*}S%p)7@P?k8S~nV$DWW{|s8Iv8^Js$#npvZf2y8ynr4xh7HN7UPs< zz=}=9nWko%y)}ph&%t~*)mP11c7ODjvvGYEP zO=6k3(i+DvO$={@vLIwXEtG?O0-#r^Wyq3EvGp;iFy|dcmv+mO=3;9-+nj(HhG^!RY z@G?C=L8Et6nm`C5Qc4{PW}?b@(t@QS*`H3yCR@H7gzb*J;ck8CWuO!ZnM@ELzCau}s`KhFv`t zhW%kYc0=JszPxp%0^aP!%qF|+%u`sqNm}fLJV{fBQ|iFJ(@_aPD{MxvJT~*7_x`fv z5}Q>s26KoOn#{`H*;G_K)5CKFelr7D8c9IHLE6@1e2T#7@7nOZ`X8&}6lvpYeX1I> zB)<2rh8J#v943*$g;92CU8VAT>CHK_^xAyqi!{F8jNlV+b?H>4B4j~TER}Dj4t};( zh-?qH55F*2mrS4*x*8m3IgK-;2)Z?s(!CT0Cs#AD7s$_Zhi0l!r8(>F|vK%w5(XT@* zGX$8pjl;UlU8xdQllGRW1QOSG8-3aLN)_7D(LNku*ys&+BNcHCD7B?wk`hY1Xw@3F z+YlE2<>PRFYOr=oO)C7^{H%u5@1UL_OBZvuWA{+w#$bfw{@+Hg`CWfux zn+rzN5F&Fh)br+6{Bn?KDgiBkBG7TbsZxtE;Znk5`0e<+t`5k~J(@N!b{`exGUY~U zLu8C?8im%3^0+%e3Fcayjrm$fxwvdgP{LeGWSS{v=4E-yCZVC_bS% zpSx5>AtA8`SUt#z{%z^$D>+PXUepyQk`MzdmTdLZ`x1nXlNDMX(dGG!H-Ij(z+Rx! zs8kw`u*jZ)J{C~%=7}A9P=WWgr8z{0myA!H?LHZ;RZHgR__ya9zTv96g$@?=?PHWm zxoUqRJT5R@Ia*xYf@T+KKy84}qoSL=!u-5R$~M$aY_d8jm=sMOiV#+@X;|E$2n5EzIW9ag{?^c3J{)!Dj8Wa z!wu(^M_WF#VXQD16Nqm+%Cyx2il{^lXvFK8_qp|!X9YxM;xhgE zkq9r}p$yucxaci6Z6u3Xg6~;G%#q_?*o%EwKnGG=Nv^!%c(TR;hhG`52vPfi(`HrTKBtj<94cxXO;% z+XxGmRov^FWjbfiT0s~&ftZD2M!{=I5td^dQ!HFA2-~(+n{UEV2nmgl4Ao*-X+mL- z6hS({x&t-HmReD^#66KOl9l(36DeESQ>sAC(q~E;APVWUy-Ld}e8HDZe5NSg&EUq3 zUz4pbpCj5pOsH*ZG{ovrOp3Sm*50qWrc|}&bD_fXi{8slpUvoS0XLEBflqP4Tj>|4 zdn*GbuvAk6v$;HoUkQl`QVJK~Ke{_qBQP3v=yeLYGOj(abf9AwC6B7#`RWRrohhp< zU^eyZNasg28i`*n>0TyU(o!^!f=pMw&!j{~28@bK5y}Co(z@q&g!Da&i=CfsEXJbK zitWNZ4!C<7V-Ha(2B3TU)1KSf zb@kGpVI(R;kM8B@{~A6{P?5uaf&{iCeT}Uu5I(jf!Cdu@H0_I$XXPb0)6}bS3DX+O z|9unGz0KUNtK}6&7Qq9t!0i%dk}tyZLZa@w7o932Uzk|_9#Kj;?eQTI4x-UggD*bV z7S$LrLk)sQZ0=A9YUwngv9Dd&(wDk`!8awl`&#}Iug8TXJ>e{c`iZAbk4RThER@A?)7z`j&GMSYxW-9yOZO8zQHQ*Ty%#;4U4>>F3|GL_||$Nlbs=X9#m1;vF7YPoaPBc0FozfjEr24Bo)m5&PpdbQX>G)oed-z3LkEGx%c{lIraKtok%_9 zY*Dh7BHD|)j1r7Idd(0_mOT*+Rd+wGIQ6&whPfjsG3oV&UJ=B-p1rrD5$bJ-HQNqH zqdTAcY0O{=LlYkd46HghhgTXGC#_#}`m%J6Qe~?f?d|ZDV6ds*uIgGTJ2KkHWNd|_ zT$3A@lB%I4mdE?22ZzwA10!6VuMG5|pE~hzBM3&OWTW#!DPWo^P;-BmJDmHR?2|Kj zd>jLYS0P`!-;E=jW|J*VzUQfKJgdNGdGivLJVuco>2gwoawhC^Ze1A-UD!l3tkXQ!n0VgX$KPF$$sz^vQ(LyyM1$nMrju)aqk>ZYxlY9IX6yF(Jx2Vgqgr}c}};8{3K3E zydwQmaE8>>dfSePBEMHAfa96t}60} zTqHh$hgzi02n}Cp$pn%z1-P-2=S34?1#6b zsm73Q5(}X4wUcywoa*5$hD%s!(Vk~d643Z+D}h&3dKwv1N@cQm#l2?%sC)&NP)&Av zkU$v30%X0Kl(Q-nTbm;V zN=TBRvCE(>aakPln>b4Xlo?k+CD0=#?1seZhNTL>MiI;t{0McJPd(yA^a|33g~4!1 zbM)7~a5Maa4Le312c4M)GPZ6T8&7sNZ4T?Itk4ij2CfOQc76qy5Zd)<{#Co!e_OkWjU~YD|2AUU@?{zC4^83^2?C<`KV?MZ@65;_vPsm^*~r)i zVERvnM9&^Y2#p^+N$gvdExlDml{Wh6NU;(sYBcjaj#L<%wj~>d=_0_7wu1kj=ixq0!M+I``8CuleQljKQ`)h{ty)0_s9~(}*;o6eG7-LWlMJ za%;{t@BTUXpOnf{?@7dZ)ogI1yGbEF$dG8*TQqqvzOB3B)wPgUUL-EUTXTbi?F>)WO6@`>h zW>Gg+UMP$4M(W?47cftbMV7np1D8q9^ph;-ZwARwQdlf%+vxD-XUgFkb0f{r?t5AA z&aT_L`iY?|If$67?UcXauZoMwLLy$#Gnux2ZmBW?e}Sc>$3+$22B|mp6m6B z;V{PkAnp*|2I#(E{#>gwrA0NZa9Qn}%R%NDKC-Lv4@&MoI2o^1#NMBZ_Hb?mo{6Wi zZ(!ALV#6j&`{$HiT&4+^#S3#zoiE$}m9!WtQa&XF2LWOJ!`|us&o4_cyZ^i@)qdJ7 zd_&_;EV4r_agoykYpe_hXV%k%gI3Z;E}M;L2AvDtTU{6=UrpIh@&gI{+zG+dkNZ{% zeFN$Pv;7^(!F(_H+XU);-(z-1miJ}C*wGcC0BBmj3mCE}`k?CI+|X=`kqwU5lmpGH zuxC&vsK|=idR@>N{G3hoVvyZEm1L=;Fo24ikLaq(vBJnP8#fu}Np4#c@qX&2Nv2)H zTGd8^5%-tLrKWYad9`OZZfmj5Lf1%u-LlOk#Oq|f1N0^R^dygX+b}&az-!=6S8!+9 z7)#MStP&&fct`-!m*$nZcb4&Ft=ew_Ix2skJu{35jr^Z@KU zjd<-378f7`8yI$`$LTsKVvzAq>$VJpjk5^pkh z)07iL23nCu^;(S2ug9`R-q9^DUt_V}fD;8xO z%S)0pZeH#RNlH>GeA)p=s~%<&6OEFDoxUd;ZD0hVPrL@u*rF)VHCX#>mQfsHj{JB! zf*H?B<6In$8R0Us{Gf^igZ;(AE=S76?u?C`<=0jB65V4D2T15@7K#nMdJ$kZGlX=w`hN7PWW zRzUp|H5O9r2x*C^a;YL_1iqu+M3X4936~=U;K;%Mv?~EPY}%$!-xj^L3yiqrS>5tQ>{{tLWt|qj91!d&X_o)2RSoyC z!_*+*N*k7w_AU?Nockqb2o>uZZ+1gwii>E^u(tlYOb%_Ox&z-G!*=^;mN@zc*k8e@ z1>m6W{R75N=s$g~e4kjk|_Wkofve5*>{tp8_T*8x7ZFxZvFl= zr|$5~+XPp|Yr>9`USgZ=biH_C^;-KOI_2oqZnNoOxw&S=cEZJ{tF<5U<5b%5=R;MM zXTcnswfp9bgtWZ3gcohjp;wB(AVNSb5IP_1Pq`7_Yo3f+%ru2(jI%dM+^(yqmr>zx zoCGBY#29bEkgmYvDaZ>IDTiOWbf{DiL3u~R)yk~!(JY7YApFr93;`9VJXf=eHw`Cx z%JEfs$A&|r&HNmDaLDp>Y0BGdvt*48sH!^~*GF4;as@U_PV5cbQYyoF9Ta%&Eu{BxgnqK(~dCk(i90~MW%UW$wakT+#N zXl+nhcWqg(!Xkl*&^J1+06WqTmW*Q_G?_I%-raNjYHt)6N-A~%`}}ib0xP!H^{YK= z@-cCu!<_AGlow5k2}6rJhul?6ou$gb879?4HkWyT=};B!W5%x5BrOr9TNHkx^9Ysl zbdPm>t;duV4{-ajl~0B=?}Jm$|HJPE>Z#|Ar7^e?*n5(pAd?cMo=dJyRC@GVWsF76 z2ze=b0Mz%TCR>loaf|g2o$I`=zu9TYyg%tr-#x4f*;v1ymcv*6t2zP@pzxtF?edOq z!p|$-!7sOs=IR#5==R-)uU6a8do@2+LEtAFp-V33lm_*SQhCXMFqg`~*Th4E{GcsD z$46`^f;h_Sn973zdxt{8upqT367hj9VgY@3MJ{X-mSe?JvoUF zyGNP#X2nU~IsuQmC`g4lH@OE%jFdK_QeaUbV-;lk;Afa?cuYpxet$U|Anh9v1!DtJ z=d+6FHjXM?Ozm1%hu!oIk)l zzzEfPLlZ#WV5OBPklIW6YeG~q(%}(h^%wVJzWqcVV9P3jkX~Dpm_Qcw1VM+T$%D?~ zbPcUMdL*xh;jgqFOR^iWwH=2M?6Kcdk1x;sisK zQ&bK53}(pbPmc zl9aQUm04_v|~b&&(wRUz?@3+d%>VcwsU z3f3?E3Mzech0>CjUUk=M;jGjzRBC^yvEwPsH`kky7#GoHx++j{5&1d|0gti*_oN_0 zHFt~4H1Av?H=W2^*gVxhB&3=#(2_lHM!>kLbH5-5XqT~9I@J8KP-4w4!uw*YCo@RL zN{zg!5kSh-cPvP)xVF49g5?i22l9&MgUTGBHyjS5+Ev1r6EK?lAN1>u~}4M86`AFGpPy|Ak!Q@%On$IT~w|lsT#9#mXLOa)*~i4 z&-e@fU5tJJ+$>m{Dw2e7uU9Woi9=%h0_)65HKn5J#6qP!Nid04%P zEVkp6ix)hl3Jf?Vc$!jNKb@Y<5IX)S56b-EpRVPl@!GaHl37nmAlq+SvL0r=^+88L z8%XT9An6mL*vze_R!5DKt+42-I5ry4UZkC`lhkP=a1aXa_?SF?;QE^_5_WwojOZ zNo>;6gVM(?&cpC3S2NS{r;oK9>GLmQ4SU*FstsR%@#k%)a~!{>x6TB>yfxXrpLHN3 zd`1@9J9AdNt%3^%DZPxerKXyHP}r`X-N&}Nd?Z4ZI30DB|K_3$sYha$+l(n}loc z1$Hlv&&!dwCMNB>+1p%;pS~YRc4gp|aVPG}+v`_wD%X&W)N)=v4TEoajN*12YKp6t zz4@iKGT=Z)7oCB6KVkN8q_tJS1~BRy;@}crU(| z<2{x?EOEP(J+O1*sh){&T$NCWS}lu4Ps!_;?vQb2*2U;4Y-K7+*i(ie z8ybR^j+jtmpk~kvDQp!@PS_)%PS|5nlZt>-qo-z2i!N-{B#!vSzELPiwa_iE9ZrH= zvb4Q7+7<(twI_Z0P3^^fh2IoO`w@E+J>w8TJF66#oWQ5kky52%`75sXLGg@F$vnJ# zV0Dk32CZ%%Ok&CGv)>ltt>=4BaOBc?k9PAlHbtvxHB9Q%Lw}Jq0_0e?W#a5;(9S$( zsIZQ9qlceJ9(OGCG=1A5%78Jg?Mlj8kd763r*yUbcWo6i+>irc<^y&oqqFphZrMWyGF*>Tcgq|Qm z%{C!fvkJS0APNgwWX2);V{ksAVg5I~0s-AoCnz3KT88DiSbE0o&8ErKwE4IqRT`&pdYyGq69U{7@x-F%=!9YG$r3Yj zW_xb_LScow2pE#To@VH!Zekdb;30pGAL^tbw)sfhv83qETtHgI>P}_1B|`E>aMqFb zz^o**Sx|FWP;VV>DIU|{M}!34b>;2w^x;%ncloY({jO%;=zDnlva(L7JAkim@9)v| zz6;h8@l)ei4Ya9E%_E??h&Fh=!lkJ*tfcn45Z!!Hi)d*VFtseROKcmlEc~6kdLLox zEeq%8_CC~y=*}}--lKi+vj2`+JGcRAQ!6z=-UFb6I8S({ zhlJ1f^*xhLTEEbz2qyoQ?=Ky}FYYkkshO37U$AICq9aEJVVgZ$*`c3}(T4|LgRwS< zPPU1-*V>_uuXabaI^3d`_u%+e^BDF4oCZS*>%U#nKV*kDcGl2y0*L$qe~fF~_-X5xkdC_zeF*oRX3; zzm#qcN%pgljfru)nx4+)z02I5?E2mE`L?S7g0Ry<%+^=ZS3~;UEPy^WidMXzBg@B_ z&v|T8I^Y-RMBPE|cgAJ@g+L;0wqTb=Va(R!w1h^?$D?s>RwEqGbvm=i;YwNEpZ>cJ z`G%=?DT$+4KPQS4I~3_m8POuDT^g#hsdQ7qD{a$bWZ@NR1GBQQ2%L-9GsoMf3)5Sq z=jmXBvob2l91OHyG*VKsvDjgyzGgzMsRJmZ=kdlwRv`>%*N~QL)kZiPR~qR!9XH~{ z$ElO38|lRsM&)?PX|K}S^2995iBxcSAUJBYvvcI}&8@R}1cEQXgmO~cvOARp(S;#+ zv3d~UAdE}oU1x%khUC9?xbTH-f|+~@N?Z9N<}7x`bN=)Uz;H9X9m{(Ug_zXz(lZ^q zydP#rw;3An5EYS?;PisvSSkuIRCFMyZm$Olj6Eb=K9DqTRhS??!dj?XnsyUmqBkGC zObOus<_`KuaGhGbF6~{`9xS_w52@6OOF6UPqMEI<@{-1&rxa9eKF`vEM_%$3!lNLZ zX|;3Na=<8v&`@9A8B>aUL2t^k5Q6Mx#ldCA$XBOcbH6sUXS*7w$~<0)9|TDbR-!_( z1M^-MKd;inG{{Dk;$R-7$U!=eDB99t4l{ueRc)WI?eJW#joHT{{w1}t@VCrP@Q3>G zK%(qWBG^T=Pp0J%b=Gp+GIIoTz_s>eRBF+<$;47Vxm*pw+rbgMxsmXQN*Wnvsc~ea z3dKp&lCGjC5iTU!BwnnUT5^&OCGs zchKSDn+aL@kGW}kqr@^PSbY;bHj^uHx7q=M#WaFo8WI6V?z3-=mTXLMLP`?hsb3SO zql{AJ?63j&8Vg%E?sL{;tEH$k6e6ke&mT77`0k5w)MmW3{=~qYL#LleG!}>>y~%1 zy3b*K;KpZkl7UruZIz!dPE2*CF~JdFbTBiSy9*?3XHJCIVo){`(CI-(C_HOCUQTVn3Gxn0=>$;WDp)fM09>(YOZl=|WL<&L)gF;=aUo!B;cGj~ZxfXZ_6!<_ zrnw}<;J2k|waAON-xs=9b0p||Yr0hiIb9MJiuJZjjZ~Q2L3=QAZHLCod`6D)1)l|L zk1Wd&6621Od$qPn(i?K%G{~z`+h636JiKD=a$AWb1loZ@yS{8asKcjTZx^rBk&l`d(EM&Wi*yK`vcw5*El~mdk^Ijuq zd1BFfh-yW6tf|TH-ERCo9jBr5^c>o)nLB3p>1tmS9KA7XFY&T7S!mN~ja`n^s1@4@ zvv-hK$vp0e9_3EhVBFEO&#Txb^v6ZK|KjEMrD|atyL5+`a9aNY$pZ;&eY z+>IrH&Vjmu;z6-6Z;p8DjJXMhd$R z9(=@}F@*KSVp!lUZ0q;fvg?~>p5$nyp-&Lg#~2Q*=c`QNjAje*HA76K`&{+zTaQD2 zSsTLbk3I7xWiD-i6VsMTUm)i6nw6wb0qYS>Xb>#|#Er94Hrxr+TE((HCCT%Nz>a}b zYO{l5ulFhESd8s+2$vNq^pOjmg54c(n2dZ3poN!+*>!BNT{|>%O{AZ8y+&fN>(#_n7;}O<+8n8w(Za%#81HTrU z(qRrLOm`%f=u)PQ{b4hkqgMhTpS^;@lq9j6aca~iY|bzNu>OIBSdSgWi0TQb?u=Z@ zJwoq+zL=XLw2Z2!;^?jJflBELd+K?wEZmbnc5S|&&j<0l!>nIB%R8>_N1oHzbFS@) zcq4z=2ua4_umG1H*WfIhX+{q9QrZJn7CL{W6CieHpa3_gmB==9WW8eA<39N4n~6y_ zrPUgN-Ck{=`K;(r!SKE)zsUQo!#n{vyLB@Q5!i+(D<`sHY4M_<@@z;!5_GKXnpGvx z8ehc$&vr1xwwRoHYOCq>AP*EjD{ESB($$|feCrMXO>I0+Y98tN|LHOMKTE`-uueG`+~kBLORWK{|S}!C}HDF zqQ+}EM|D@ti>V__JEE4G%p-luL|RzKT!^b};AExS09?Gmx=0G1ti{1qqR;Lz=OFi1 zR$wYs;M0ItJNqJ}b>Qp|+5FQ3`TeNmMno9VLAp>*g8GYOycSfRX0y$8D$Px^AfTr#E4 z_gSf*Uc*>!)d{*SP%Kq(kZzZbI=jgHl*Wma4PQNe!FUoE8)qOlSx&ZonJPqImOsvl zxQJzFfyzNU&;1<*4o~5W)w3}B6zRh1)GI7dbvNi9=!O6bLsa7idR~lFcapjN5XmBqAqOu}pC zug#qGpJS52eL~b3cMqdl?7yY*cs0K&ul71Lx*-=8EWuGx_DnC^E*TgpT)4+!)_Eq8 zH7nwVUqSLE_al6n)^)9K3-zZb-VhE4@iA?RsTO;<-})vv^S~wD(}rhD?@1eqS+k>t zEMtw}POCp~7A!~c!g;(Hz`5Y*{oQH!qu63Q-#wfR=hzwDzJ%1U#Ul21=Y-={ALCnm zzdn%hM#Sr)ptYQHcXwsADGWF#c8;sp8;}rmXHl6m5}$yfJz3xidLj5yu5#@3{p>v| z=ZtGwqXqfYnIL7Hd|X`5w=GHd2Y5?e8~2PxGG}Z68ZaAaLaDBkMoIp1I*k4r@-51nwVW*uTM1FR-l_tBm!N+J-*AXM%Lif@i5^rvX6^OH>#@0)s9|y zAKW#Z8CktM$W=T#rDcf%`K>qU06c(qWLn8sRr;iOG-}XyEb+{>AUwi~zjM1(oLkaR+Zp)^?fhB4=6+b)dJQ8sg?r7KWLn9N zjIsqOrd*A4kPgS`#Bn!tvQuA8H|~0PBz(Ho^Ve{eVa{=I@TUov_J=k9H+0060j8Et z023EQ8zawu)}l@SY`Kx8`@qu&W6)_!Y8Od;E2b``dY6T@wW5-gv;wp_u(XkZ@5?ST zl^qH`v-;eNrKW_qF1haEpj*C#ZU-Cbl`#%1Bn%@3=yMgWH>y{@928A?2 zM;65fy4{<%o1M7H=-8e+448y%vDq$kOfkhxE$xR9R}O)iT7TVKJ#=%PxWLlEU%9~>sB4_AF2PP2vsIw23J0BxZvfnxHC?pk&=t`&>nl1U7r;9rH*7Rj`T`~08qz9gJ+6Xr1oZLtJq-H3&@h+; z5|ggj_Oq_FcSvZf@^9Lm+BF>XTrm$?Eme6hDW^ZjYHWoe?qQ%}iD=&w4KPVT$j44D ziJhyV6Gj9UV6^DydxLnqYxl7O<8#0cmx_*{t~`oOM&e9b7Z*6>w2P;@8jrXvC+c+4 zA&QykYt6A3%(fR-C9>4=c6pW-_VgXM_f^+K9|bM!FcMn>xFPRo1o}!AyY{=ZF1+fw z!wGd4_JuV1e>zn&xY3tB>o$^;Xe4S5%0afMZVclC*E&4yr0l3(CrsNy7nx){#E}3oKdJdm03ISu5PQW|#gU!>SHw3c4 zu4bvPn>_moW!rnX4_q-&AKZTWQW#FI1sz@VUM#mMAUr7}b|JkHc~d0hSG+l93G=-C zrFDsl-S1?}AuaSw@bgj}ZW{OUxr#e6`rYJ~xpdauMx8%2bun1a4M`D_uR=J8v<4q%bS2*1Az2O&w{qY+{nf*Hx~2}G+3 zLd$3t`^OtnNY={6lW-8D9F+KnIwc+A9ea_Y80iY(X#k3q1bIfu#HG@+cR>l}Ge+A) zUWTUc?}?$XKccE+XYh>4g5PAK__JToQxTXv!KlTsdfA1?jG?)Wvr{cB1r-SCqge=$ z)w3>#7?tuiY1wd#)2Uzihpl>dB-SY1Fm8K(w1+19%+frKy6PKK4$rMa zUg5T`vHH)NO}ug8QNxR@(EjY7lPwPu0zCiRC8#r~Ve62qcC_vp+5}o(c&=3>uaz%b zx<1)TROm#fZdfjF$QLX-uIqQq*;!_%<}6$M+_-6!RYKxxNMnAf(epb-*I7n(|7u<{ zh2-jOBAya}-S4k0rkghM8h@)4I^qD@0LxI`8q5uZbHa7gnb6JwaAh-Gh&Z+_vEeD$ z4I-g3RJ4+;vXUq}B3$@}axO>^l=%i%z*d(%WBp*7d|iUoQy3TXbGD6@=`!rsERW!h zq_GQwQNli>_Knbi6;Qe1wqsS@Vl-&ain|P<)>EJ_kphQ54LApw3SfJXxNm)FXjWCL z9aQ|N9tWD>cbL%fzxxPT?nJ`Vp?&FFf z1K^!W=K?Kla6FOWndqV*XvtrtY)@b6iDa{MWh^H~SL(~0qz8j2_tRCC2!}-|H(5ja zQ}QB-_*>5k`m%(kn;O%{&8>^-sV!g!qHh|@?NXwI{k}ypZ3xKN2NM7^`63x^={*wR zITdagv9Plbln&5dJP{(~ch?|y zzRb(2KwIOllHx{Kc}^6O!@Xy>pIu&R5*d0pm{=*_``(VObim}x*qva;`*N?(vl8JB z8;7!eufEr7Sh;UP`5Q;_)_M%rZK8YTf#KyT;D`hYpukBA7k$)woV1EO!x47NXx{BI z!qhxpYXo1tT>JJL{JsY7NA&ebzUCBoqu*sG)TewK4dsOPKN^UIDe>WwXW~s!?7%cGO~Dwcs{P33ADAkKieqWMa%@z-_~`#kl>1MU7vbN&rgyE4ET@DKkZ z=W63(`40!AwkeM*f%Y-1-(cN|Gy-7}wfV-z_LyKQBQwtiEHwO9XX=NBBC!Wmby3%4 z)X}`W&$glJ8Oy&Yq z#u0~m1_7c~zyi|a*-%iZ+sGNa-gY%llgQ-?Vxas*E^4D#$MWO(bY87>&V;WKraR!f zN3)L4aEI=>*EBL>vsaD-_Fe$n1%A5#_^TIaSfDbuojoe%x9DqY<(Xb zZ(OSZ?PH4D93H=Hcz81zDX}325q^#C9TS=ZTAo|@na^!tzt^B%ogO7DW3t{4`zOEB z+nqL*htUL@7V8)dM=*_3-vSD4yVSn6>tgKt4T1MVTKIh@X($hKr$hg*%0lANYTnU6 zzPvJLFf8M*GnObW>c(lSs7baHC-)sV+a4;Cfs>If4 zYA|1PPc;DbOk+0QteXIi?1*jc7%zWJ6qhd^u~I&H!GJwp2< zYh!632CfoiWt2cZMV0J4)*SlvG4yrEEX*o=lYjzwYUwdgw|Z|)s90z(=O{z^(oNdl zC2H#zQ`>$Ih2xWviCJcu&a?UNDk8xU%@2f?>qpu*^yy@bh$o-Ou)cQ3=HHk#HEaEX z1dbCAU=mD}{bZyQ(0p@cyMp4`lH3AiAxfeOOF>F2*w8x^&PZt}($ipM;M1v)P$wYv z18~p_DoJTUCD3*%bsNsR@LC#x3t^>fapX5QNOva0=3!cS4KNbV-u-k+xNyrbc0j!t z{U89(NOJsTl#x4B&a9nhkUI0qj9ZC+0m&NU0H4WtJ&#i|$v{P8apRugU&|)$j9zEn zKR=L3`;*c98_Fh?KYv(JHgcB(I6E7e|C0k$m(y4mN9!`NF*UgXKsPp8Lc)aC!N3xJ zmCB{>`?inqC8EzVmz!uJsEUY;P-}Xm+`st9WkJq6qp*?RWn0Z(Nnu;Eo|xGsvA))f z&Fk*c_o|z7zvtuS0;?CEz?~?V1I7p&xsmmrZ!X8Gyi5z=TJ;=!#vt;$(+K<09Nu=U zP8eQkkj!N?OvKE?#xb?>heFCJd9_oOjgy3XqpyZ9Pn)++RmMZTQJI*W;EuZGO4(_L z+KAi#;_V&6E05Q7(TY*AZL4A@72CFL8x^hCc2?|E#kOtRwo^%N_CCA&-rjd`27USr z*6ja0YxMi{%65Z&;WVJ)w77>}eWLO^n7c9GKaL(3nlVdOTInn<_^)*`qIGn3%w%fv z(1*H1zek+|l~SYZ?iu^R-pD5wu!MLbnaHLof%=2waEx%?ZS;L=4-tp+VLqD+l?jJQ z%pcy-#I4C&9jQ|$b#THJ^p61>I(Sz*zA(bf{N15&nO7-cruKdLpXs;Tl)=Eh9j%er zMB>Ez6C_+@{l)Udjh6Gr7rY^@MD!u?XN^D-V=Pj*4tfMjSpz#wwgQ_QrA{NBYD!-< zn+_Udv?VN~Ub7;*j2~DeBiRFggrE|z65|r$F=D(o#frI^TU6a>QS2D+*&OPu$EIBM zT;bOugiO<53e{co9S3F+PC^bFE6`euR@KsZBBb?`PpAhXJ(|Jx($FAy2OOwZaPGed z4cL$kJ8dF8IcLspr^QM>JGZO9JV8UsC+LLdVJmx__w(L$Y z>y0s^C01arz9kVwa2lr`qaEw9(S79kY3xrHtFg9lLfYuEe9tfrdoo};SA#p<+W1Z} z$mk&!9ZmrK+Az}&X8us|+v>;S)03#&+ax0qmAYr!<+0BIQjadbd>u?YF858o%L>z})lK1B zq@4i8B|OfWCB{w8(}`_{n3yry1I{^RMsQqFNi%H#arU`;!fR3Qs#ajmA4oagyvD+aK zElEuIgrMlc{Qe_CFd&(~*A(zGA3R;|J#dm#2WH3i+7YxPfLLamMg`HQ+kFw7aDcm$ zq8mOV)Do{mpCA+D8L^(?+&P%2qxXT}z}w{`=0-d`e5v`Rq?_;Z{qkyXw_XFyhAj7( zlAvynbRCA6=%q!zc7l{k$O?wsLkJ0%(VQ>U1GHj-`&tE3>nW)HT@G{7szY3K z$8Zkj)@H11*G102ZP~0OtF-x0-RtAOF%agbUIr_^1am}RwkqcT=Mjv5)Gl>XBQ;CY z|60E~)U?(Afnmrs%YX(^gn29#YRLwo2vF0g5hJsXR)HJMG&(YK1;-mE$WhRAtUN;9 z|FK?asy+}Vd{t5p5w$(hc6})8D!t%0hlB&|)Od><=X!H{e0gko8qf9rtcBf%>$D3* z{JO}ivgXATdx*DHkjqTaPz>I=H(xTc>M_#wwG1m@Mw^0Nljh|~in6FcPV6FRZe1~` zeCO?H$RDxYSTxJ--?&^~5m~9kfTxXLy7#n0cXHF5O1?-?o|QJs=e;6xncGfDl#qo6 zGj}3MCa%Nf&1HM;P}D245S^T^oU%+Am|(IEaH}Hy!932{Xo&tMD#xR8E)o}osnb+8 zz>Hm2KiyEi9KsI3&tXul#p6!tai?90aywW2tv0Dp0TAiReeW+!) zT8X1fEBm<}@ZW*3N>PU_s(Q1aEALG8Ns$ zr;!_dTim2)QLn{EE>jj2vcQ$KL(k@d*nn$WjFXH-+*tBlVUkKAEWt)7TE7jZFPGOS zaUFp<@=W`YlszDU+B!{(;vH(}?&5p_u4In=*j_2224B~GL2(b9jP(Ot+Qw*7t?-`5 zF|5z6;ifc22N#Gc!EU*$>hzPhhO054HekuwCihXqyL)v(Gf@eVVIzorefa8_F6bB= z3sYl={)NSl9wq5W1HSBV{GHkdksg}~7In?ktS-%wD@gpJ81FlJM}-5lcjowf`E+-9 zXI$W+eh!M*DWRbrWGmbdP*69KxP#}0n}!zD7(^W>P|MH`mp2DIl|fmznY5n{v%{>{ z!H2fJE6Qt_hRn&LH;DwXN)*NUlOb2(#~6_DEdcu0CpG0VI+sXNIR=HTIvnn2dT9Tb~U0G!gxM(&r<0T>zf z=ozGPYAhA)F@wB%?6So}kd)@Z5sH75ia-}^j=~IY{+tTstSM`4CKWUmTAQiW!T)&* zewfS>44(Ofy2g66o2jy7(hL7-77)G!Dtl%e z%|4NkZN2kk19!!&H)y{mB}ksfRXr7JWs1le>t%go*U9kExYH~nnXXOxH=4r*)-ah` z)ixUuch@Oi9sQ5;b`W$&h;P4;+>bzCDiVn^E~8vT$cwA_^CL@9eT;;b^;%z7SKd9f+LGxM_itZTr>z!IDT+5;zKq*}RkFv=*i3K;(*Xqt(p{1iJf(dG@f z)ZcB?`hIyn!DG>Ow=XVR;sFde(f~p~Rd#a}zWaN}veCkM_7a8i(@3&JXG|eG4H+_} zzciER8N5rS0Y_iW$4pEjE$6oIU+S3gET5=hX1OpQoeqfzHAh3q7T11%F^P<>;af(u z*Q-J}R2MtU=x4jpI;altIr7(G)D^%6%TgWwuOONO^t{vs-O-s)Z?Y;%NzC_402~imMXq6&bv0s?>o8TVK6t!_Y-t`I%hBBI@d|kSQfG~ zZZN_*(#PqTq#YC*@O;l_$a3>y&6i@(Rj{8k@E@?m4Z)5=_O1}vgy0b@_e83Zv~e-C z&)wQm4FXki`EK#$;8~*3M-JcKRW`n3k)E&`rt}fbFo)YaV1K#NTrouv9!Gy*so&tv zdH}51O8NE0AGm<8Fgs6iG&}jP)RO3|!JvFSlkiCXfGIv2gt&B~$S%^(Kpk5{UG7-L zUyhzSZPrbGS%muA0q5YadUyHRso9X==!h?CD1fz})#A2EuQIYh;7hps(v}Yk{{|75 zwIe|3{sZmC`yc8TE((UO&Ze@acCNy%&Mx-0|DvpEeD_ga!2Zl7yO5n-V}}4$69mm~ zq}EVa1d0~Mew*pEk@A!kUR`etU@aSwwN*q$J9--#EOsusDpQfj|)C=up zEv+jsr!7=gxL7)%QFXDocNrTF#jjn?*de zv<3{(t{1USKrSv%ODTvGv4}iYj7Bc5xMmDZa3EX3mJfz^eUWMBQ65l~$>|si-PtHm z#p`Qha9;XycR0={^Gc6!@;Fh5-&AN?#5z4I*rR}mfX6Mom#9xrD*`dANDJBn$3to2 zFANQ{gwzuzD^tfbU^t}a)Ej`=C#8yCi}xTecr*5;uC1X3hV+gZk4U)7d|yI1&A3Nw zO{eiu>j6cl+$9UZPGA-*%;p1%BxI52g&OTBkm#6?OOCZ4*h&X}2S>2S3bG-I=l||l z8z@R6*JBjW7<=f-FR5T{lQ@UHNx8jGirq<~puWg>IKS|*Kv-$~q7hmLT2NpU&yD_I zgYb4M@S8&6=&3FswNxX*)CHB!O_Bx&pG-Tcs*K+LXhT^wi^4Y7@<>3Q7f5R%qaWVR z^r+OTONql7rwvX)uwEfaCKTjTB*)r!D)P-1Hl@O1D1sHS?Dx-N>kTa-ffGbgWi98_ z?tNze!+06E)(BONDud{VsU0|{7CJ;y!nnyld6mQ*u`02;)P!v&_(he422}!cpZ-Hi zxO+7BD#vqk85=9E-o(aXP+B?G=YrbK`bpMBpqTU|S?>zLS9;9D#}IPkxKRXQ0f z@%68>&r?2|BfUurtb-`tXReSH%{Qdq5&2o^W`o2T#Wyl1ZMifD^o+?pJ0V&~WZ^Z9 za;lEF`yF2nVv1SY+?`eX=QKJRL|KBZZn>Y1{kzP>W2KD<4?`jDt&8|;g9ewfZsG1- zbDEKOY)KVcnN5~~v(QkHPhaZ6x~5i>TW1}uiq42&D&@q~q)$VHwFCV~6q#>_?`z(; zafPROMZ^yW=+%UHcpOxFjMZS?ixUF*ur;6GF@fEUh- zq%|&Ihn$rvBShROf^h6eJX>wg<;y&c^^#qX>JU$J@m?>)8s5TPL%oqN*4qYOEB+RS zhLkA-T68d9t%hfByk0c3A#cjPh*1td_D&rlr%h;a?pG6^Y7g)vC}+wke*sgyGxu)Y zYaNQYQdnc`mfUtkm){<_|MG6D%2p?z=JR{@ZKsy-+Me?e>#3vZj64EQ@o#sv!OrF$ zmDIV2SI9oE25%kZ@0H{?$rKAM`2GD^Yt6Sx(0?xB(7@QauJzLdtGH!RY*KNsQA15K01h4 z1FXkj-fL#ci`KhskJna0#sR!-lsRfzdbl~G)lCCCWMIi+y)v==LsR|1@PvrfJp?G5 zv~N!a#wW1`#H!Z2t8Gu~x8%zNFaNyimInSgFXh_Bzp@t}?1Y(ND3+6Qi!h}h;H8$( zCuQIZx#j0-4m-<#IpwPKRp_VV=WrSRHWvhjET5Vf>#rk)Tgp;fWuV#uV@d~gecD;j zY!S&xcsVd_z2t*wERIUH7eF(|{)W~kx6~H9;ngFGrq2}|HSXf6C)QOlE~hs3^W;`L z5iVNud!`yz47>4dw8<0H=$g|BW@l@N|Fn{$_pRckI{>Dnl+vQycRN3dLe^X8@(zqJ z>&qqlJuk?k=f0MbvUe|RZRH%2!xJY+uB)~P)7J~>I3yh>qb)R-Kk{M*wsS(*$IpXZ ztOVFG`leCurI7MRtIkO_wi#w6$j)l>+X*YLG3HQ!ejl3K?xRGn6DXQ$do92yMJx@T zHIb5UrK^4pE{szbY0zkztVRnfLCIcCfEGWB5-v*FTV^(a@uw>$Kg|c4DD5@9s#O!stLN*qm!OQb< zFn{8|Uqb~_W}=LaJfC#v&*V6Q)Fe{)_vgZ$t)wI-8ENtN&@RKWs;ETeDQ%lvsi@zG zH6E&%1_j65Uj{ny+<2&Lek+`uD@^|N-D5+0hkMKG2Y(&rf)5xvs+G-CzS^WzyILpM z?oUf-ZNzYkVR>V7AOTY_I#)eOW0|k*0h-JPnyKug#*6Ma$Gmc%yNc$!4JrBL4O{PKV8Z~r;E#P-rBO95yK`gvxf4w1q6eVB}3+EIc@Ab^b z!yRy3CgTs9*cH(sI&}nE3}SqlbcXxA=0rvgVCaxk_ZAu9GN7(Gwlu@5hw(U&>mIA_ z3hL13^t0`HdKGjk`<7v`@xQD=Ci-(O(7QPbxv4!~ZusPiVIt+8#+ogxjVs6Z{~NLVc!;YFIKi@ux)O`K3`?iQqb_7CA54WsmMcZ($<3=hI96q5lzp=rf- z!iW6I*QD?v&dokWq4uELCkaI+Da%5E0NoxP!@txXvAbSLcGVu^+@Fe|1Vz$rhjz>p zD$BEDWDmaS1mKdGSm=xi(FeL(q!$C3cyX{$+04H!!O!Rx*pB9ljePsTC7)B<*Z}wCJIu!G$P@P1(-al`7HLIb15oZA~L2ZsP z>nqWBlsW>58_Ts&sk}B6X=7YH8WScYb(2wW#C0-NoTR(~OD`-!F`>BEQXxz&at7e~ zNsDto*oHn37;0Ajg@jY(fp zIuq%-c(@oK>yW`*mTvQw+xOy|r3Md53gl}d`qICy^quI=%j zv_DK;6fqJ*MbU;8(LG*r>3f!+(Gos$1@;qG%r!6E*DGQp#FraTLEY2$OAkaHojxHvv_KRAR*HbPgfA z8lt`M(@qO?$J^27-%30zNZz0|n>ul~S+a3F13Ij=`Aw}}yyV=|O)+^R7FlvNIuvQH zs3F{DUPuWK+lCTCclCM)_BilaUg6K1sz1NMRhDhXVyE>u0;nT>0yE*_-wx1b)1D;@rwj{rZUL4>RiyVa7`INR(vb%VF2~uQp6tLKlZAo&) z5BnqZ!6SvyMb2yZ*X@lt7B@ch4yXP4}axg2}x1~HU&UL z0rws;51sRpI6q$+(F*7aTFe}-NWm}-l{W4@)AU)@;pNofl2ihjd^1QaE6K0_1dKKJ zIy_yhwwL`#3Nk*umA!1V3@UYNP@Q2m*lt->JhjwiJ3|HVeA=@M!-&!9WwP=p*XcU8 zeHu$YyL*fQvt1_Yn(O*}wL3yH6;~Q0XSWD#2k##aGo*^<-HO(UmqHYD_i~3?ZzGys zy}irXoNFBOh)7*gpOR8W8TUujg(0oxndI9qe;KwCpPbTfey2r=FvO~PX*BW(I%O>q zai{9BkA)7AI)QE?ZBwZSEIrZxF|DARY6q%fsz%2Zy z&#lo^MJ;OVP%mGZh&V*&SY?5kBNr*&QfrEB2gCam3lBK(!8ypo`)Qf0{OUcSlt4?# zF?cmCWrYA?irB@Ya3mOV5DXm$U+Rq;l?q{G$tW}W;2N!`!IG=UPohVIN;6g9G|4u3 zrj>LU=p{@e*meQ`gqT!h@T8m08_O#Vzzh^1-KL{y7Bt8-5x3MW+`{OD4)7<=810V$w1J(ZL9EaYCB8hS`%vHTiM$iG!k>>$x>f_rz?JtcFGyXmzzU9t3sfQ>pxye? z6t06*RTwE}?wCD}*cF{W@bEF1hLJ!@Ki{zQ_;0r%Z3}0%&MzFa_X`I#`JccN{>7>g zwzs#o{Lk7kC6B9)^s)ImwCW-G3rPaHP!6}74gym`NlQqGc)HoK8{9#QgiUh|vCgo~ zn%){VmFiRMhbm&S(+RnfqKI};6TvHoY7vWlGzc|UQT%~#-QD5D_|ruDO4sN61=}y{ z=T-x4g?PV}CicMd$>qHfn~5@YTMq5oQSI3(-bd?$A-1jW?X^cH*4l!N=gYJ3 zwayUi&;)3QY98Z(gJZc6o7O`f^&0z%isc`rC@_D+7 z2Hu+N!z~Tmj?;(I6}5+UYpUvMW>27H%fmM#h;W53X_FLO90nVqko>)>0c2+wr!jSu zNMpPi_%x?jNSy9y#7(SS+9?g)kL%#fph3jvE-OyDKO|C3R&UnJ@8^1o4~mCs^yO2j z9v_o2?)&y5;J;^0?Z;X-qC7WhXXDTmGX^T+Yl7t($mH#j6&HEs36OU^T?hay^3!!Z zEPC^*^H5XH^Dn$J6ttFBDoW5)jE~_>Iom^s!kGf@lT^E%Jn{(TezbZ zzb%#b_&vAM%BIsF9`Kqdbm8ol3Vhmdd|huzWd5kOt86WAgJydNfjkTYj8&;0OgzSJ zXVEQmVTR9qD;5QoW^KHgWy*@VVb^@QZI&x&?2a0o8@<@ zb0@4a+u~mxkDT#!A@IHc{_a-2U5zD!bbt&>(gKJb#zi>M-_M8jDwQL*hzHCh^*fMA z84197fauQ>n3AH@qZW1SUV|_|%Vc)Un9t>l33 z?CP#!!4LRsJ|ZT;bY`wWVU$_pM9@$Yu|T86@C%ZJQyixAinhoGE$QTt09;Dq1WD z_zRDj$%epyS>|ouv{`&$G*^OtMut8By|Uc99?%JBQgtN^m~8YIR+5VEr{jMql9bR{ zL6g(@GYL=!tU%go5^tXhqv8QeYrUQc|0|Cq=AhF=;cN0L`BH@cPu5Q{IYD(%yZ@l2 zttp`jBJm~K)CSNwA%|gtw;Q6wp^HKYN(<5{qlcitlOyh$u>=peax}=aw`=$T`~rS- zYLJ`m1QBkFhx65CB1!ou5!BAjt@%!#<`L68fHZX|Wh()c6>ke*g#(xqV4}U79quu(p|aL{0Q5{^AU2J#v?RpT!Nq>s^AY1W*lpG*K=DMz3=uBsr+8j- ze(`DY?X~SjVDVaFvoe+)8nJQ+-6mLtRu&d?!hyPS62dnAjn6|!6T_t@EuEbV@<+!Y zAWj6j6;iF50YGC-q*bsAjO6*w>%l{|o#)Mz7~0_JZ&Y;bTa1MZ^=vLCk7v;0N-!sU z$D+;_I4>2S+^qiTa^!+r7E!08#D5gJbT3s0AYJWOYUWD(rsAvc{+LN2S zW+}?I0*_;iZwK?(B-MoYre-c-zvds258P!;W+P5{c~4x>plQZnG}`|@_eQ;0SN#)##i0s;}NN^^iZP9aMaCr+72qN3y&3+`m4GTvB4E%FJ> zh?E=B0-j@|=5)g8P2b>Z-#`rYtnid7qu8e3=D@^lzg`~sFz<6x*+=B49TKM527qH) zzgKuW%d{Iz;0LA>cWarl$+^@yfK&|9+aV7Vb$=H6mie8+k&R{_40&u5A@;CK$lijY zE$BSBe(NglC!hnRw~kSAnVh`i=eWHTA;rm3m@sT7NL48*=|X=}MwAYVje7pM`?+X; zk#X1NSz5&86Z;>@&Up(zC@^64B6fOVimvTUvel`SVaEONO@^R;Fgr%Hw#?glza-6+ z%UISxhBJGG8;3vGe|^yd$F=xv{}*;CWoyg-e9!;BOWA#6`$@A_tkP{X5UiFTpaS-Q z#JecVESpkY$F&ACOS$z|+UI`2dEX&0=k+qtKYobk>rL}s2m20BZlv=(yfdvEclMFRmfm)-WaNy>!*!=G{rzk#eNf;cMBT z6Z+jUxhXm5uT`7Qk<(fOVvGKkJ9rQ=@5wp-qDkr-6kH{6TOKQ|M-os5b_-+2EJBc? zBw@@DpbUBVr<<{Y#gX?ch5jPq_+f`FsOi&ndq4tr*30-;Iq?=b0dXq)2f z0a*dOuy7|gc-FpUiL8Ft_#@()Vs+8mn^2Gpefg~?cZ^*YjVM{wSXAZU#;>fRvl`Od z!eHu-(K{cR4W7#SR1ib+2WyQMbC8M`Ruz?|-3I0rLuDnd3ze~0m+xIGaO7C@-nNsB z%C6vDYoDDX@7`{6McFP3)+?7W7d)qY>rtcC!U-Rb9xTN*9BT?RMUAuv2rUf3r#PRy zi^=NkD_d*IRq5U#U=Y}4naw5jDga{nE<9$1f*8+JRVcVQS4s7&<&NJZKrFxwjy(-v zsZ>r`$|V%#?`xVuX%Yh_{z_5)LPzJ;u6E4m?Ygy=tL6eUc7{DNqt22%&L7sobR75k z!I6lQBkqo>*)P88L2kgilo&Y2aoHf31A!tAIbotHxZH9#CASJ3N8dNZ`Rx){F^J(@ z-v|-E6Y669U@2uJqyj1i0~Ab0&{P)*mSzlqiW*ID`iu00M-E#LLf4_3{)slUG0Z|*OL*(|rXDuK6mO%Q8 zth~7((?4|>VkV;X*ac&0#OG;@N=xU;KFX4qYgS0s+xGMOe=Qv&zYbkszDkGE|Ijet zYUFI}WNBn7>h|TO?) z@yV>1@hlAPz4*&+R7}u6Bj5H`Y_;regL%okCokPQ`Mf8a-rlCB^uHb6RAR!oSV){6 zi(m?WdV3GC^RCrkzl?fcLIbKrm)r+f05SJ2Wl$T(Gt(8M5ZOCbQxL$PQ)&e?9L>6S z9>>9tDU5DrW3f>H%mtmT(&b60OZ73sK5C9$0dTo(>}bSZ2j0}TUdAOdfy$cnkkZ!@cwI6 zFYQ{TP(XzhmerzfC{*QPw$*VH#pRg=%T=u9NpScwGl1) zujH*FrNvdcqovA)+Vn9@Isl8=w*B`tO!Boz4=Bk5CLJz@+Xhvtc8xz|bUh9yjFoBn znj@MAO8nL|G6}Edkg6yXD_LiE3&+MGp##NHkj`KEbL2cOMTGJcq8sEB9XuDkiNl2g z+Q~R_M==&@8NwVjD7LnemT>Q20%VKkp&Y@|)LsoM zE&lZNsw)xx&Pu8Tr2ff)YW5o;6UwV0R;P|#6sIa3LP#M9`fjF2L$S7t_?qZC1?E3M z5-1X|NaZQLg+`HG zA`3Aep3Nj0-%e@AGl?Dq9}7-e){~5DdB$HQkR~krpbR&K)FhL*wO zToFjWZzDYj^G49#@D^X@jGP;tQ(f`0N*TvCwN0!=4|(KU{r=UHcA>VOCUTU@E}xp= z*Km-8A{wkzr&nnsA_5!8!3DuYK!Nx?vlAPKwfoC_S5P6?`p>21AheMX~{ZhjXD8t{gIpfpsP4@>j#@FNup*c>Iy&MJ9_^vgx9H|F? zb-y@zfC6CPrks1~*1#ua<=Dgx?#I(r-vdH6?UFlWMDsSW0+>KC-B0*c8=*TM78&kX zK=<%Fx=5KpVnfqp_Wkxj~Dh@yR8= zmW49uY-mAx6U&QBH&r4`BcXYjKt^K-UPbjxy|`*)D6SxZUkYNc_Qq9*ii57iXnY|8 zxIpW0gUp7EEIut$OR2t1#v7=(AZ0nV63T7G}y$f{x2zZQJ zRuba%fDQ-Lhdyi^@g zqB$Q;wau}`##sSITI+eAnO@RA!6=zy)V$zR&g%+;%a!0gqZ1=@#4g`x>XXXl#suh$ z!*8kNN4dC4Op_R|9z{#v!Zae1YzYRfs_;dN#@k9tk{tMaY=(Oc2WOS4LlKzB*DHA0 zi{i<3f{WHGn)eOd>#C}fMgQ6rEB~Gv|I>VOZq!h zD@{`ekJi@R!ExDHmrc@y>*)i53Ebl)b#~V?)3WX%EnJFh0yK{=jS7_5N^$6FJ5UhZ z(1k0zj#~Ht-0OVTrR4())EGXUl3#mw;O+xvEb%pSz@Huf6V;ul@K*-{RKBO#%U8>G zqA%_h0_z=r_+5WzJ@@pA*h8!Xp@Q^VbvML=SBpEGPOy0c6Kv`>S3_4^j(ZYCLXsu>)! zM=?q!$#%FW-^HmLrQD-jmJ~-TX9MGDVrBzWwOExF6kmI2=&?_v#ZSa5>TL?q#ZM?J z?vvv?-IDworPxTTxTU%@irDC@&i2m!UDxXUGW>^6cUkQV-2iKdZLYTMp&C}Jo(jNlyJ%1IPSm7 zhYyb)XKp}5=h(Kjfe#9No~z7W0UGr&QK!v2U%#VvO8?KhH{5ScH^O+t!RQh+Byres ze6zX78C5*+Rj1x5a|Us?bC%DUa69V)E#DRU(fU`+i=ca^vHfr&Iq$A)3-GP!q+*bIj>y%oZCXPK={wy#>$ z&oPLV=zZOrIe~hBocHa6mXqw(m3#W7@Lf8X!1=mGw?+4j$_wu356)T6l6=IYvV54a zKYt|wE8*9Gcxi^ch`gkp%kIFHzgUX#F4&l4G-^QHaa<@|g*J$_$ zsDwY67RqaQ0GHUdsJ&dRD!N_T^vPpzNBrknJy?DD!g$(S*i2f0vUIOL_KwyP`{&if z_y?vc%O;$Zf`$9nloPBoy}HiLd!4PSFID0CZG)wu0$l(1yCP4y7g$*FL)+@d;mW(4 zop0bYa2*#2_>k$N-tzshPODua z%J|OQ{Js^GZ0UB&BWxBpZL}%I{1$xG>6`g_b>WHS&8{1Ii+qu}Yceg1tILdhfVu3z zxsc6AK07bE?-}l`_oS>6HpyQyIiYne2T@^bQ2=}1%Bx(vL+l3D0QCyBB zfwtw4tk|f3BERnklY}tIUMZ3t`-UuztFHDe#r3$FF#Ym_o7HL!0JY7bwn!V0rJE)3 zl=ummh%plNEE*Q&7+Z*>f~~Jul=X^(ULK|VL@k!)BfAT72p#TehN66#;sJ7R{GHm*+p0Z9FGhr;61mI7m? z;Xv+xgOF+wxd!Z3)eG_@TBa+V9!Digt`&hBufo9W`ri&<<3oLU417>MtjTJRUBGxs zJo2=ePc^;iJ}zAm{sdX?b0Q=;RzgypiN+HCOldH-j5%1W_wkHW_W>-Ut~I=y!|8^X zDgE%8uE>)Y#iQxtNqy_z%&vh{t#+(9bg0?Y#O-Wkv1hP?rz~BmR%@iWYSCuv5F4=Z zaP877Ipf;$$$==^;l?bqq0lH)&cp030}^GrWyDRj~Ht*-2T;iUk3)80FY1rIpDc zmarl|pSXb>fSF{KMU5ZFX56_m6FQw1r!DifKy$3g!n4ap`xd{EuTmkSvdDgQvb zRXRj0;;(FU23*|gTm#2D@}UXQqZMm3#c=<}{Q57S&TYpf9+E)>Hpm!QY_UrRAs5_HTHOu`l4IX`?F~TA( zOz;(+r?x}sTnMm7%{lH)3`WKGh;XO{lTQ?_`LV)O+j`&+nAXL?j@}r#GSDY;P5Iaj zf#QlznB%IQj{}EyH~DlmuBZMjB-3+&3OaIQukcZp6>=N{qm(Z417DshI{3Ue;rFgm zwjsgydJ5J#*$EFPFGO>!$8dmnCeX1_m~j&$YA*XSe%-gWfR#Vb9yu04N}jSyXr)g9 z9IEKZQioIR^#pyLaLu22z5JMKZps z6pFz0xoUrocet+Y#%wW58GQ?a1*pIo2OA0$o3^YvZ!F!(bx3-`d+2buX8}}Q!~Pt4 zb;>a1_G493HJ9(=3}Qp_=yGIs-e0`zYw{yz=b!i#C-sw6)21mgMPmc9Bhk%-xp}|m zP(P)%8qXp^Hc&L=)8Pq|>o(6LRGLb`nqfD7+H-^8s@iR^aS4|jaQ#)iGY;`y3(Stt zbAaDqILRTu+?guXud|>SP0eB!rpqpgQA!;Mt~bJ$#r(j|XEQ{vVRd&GWdVGNN#ml0 zgO+^9TybDAhRaQpwrsi>$qob>ng>4)VT< zRFpG$RJ+6$Xj^5cwtvtueM>xgu+c+*pZ zE{-aGjKDY_m51ts8LgJDN4DM()#F!atvzi&a^6IUZxogODyQR%c|$=!yc?MM!NttK z!He672V>%2&9LyR8UFW;cmCCJ|3A&}ABRL0dvo)zj6^kiOXL6Shr0iayi#6em>v)k zOp1uuD$4u1XOPe&;aKAk)h`}PZ(Jgny8a{c%E&0{=P)K}bPtsOub-nH=B@Oq^Oy%f z9_OP?@5yX$`J=U`ANnBUBulZ-UaTUn{Yd6mK6ZAQ0BbK-;Z8P`dR=84ulY_>VC9=k#{w>KPB>D0%{$yKbtgk#B!GQ^xF_<&)mIcb3t&{&4pFx@v4BH-xR#6kK$W5Ld!r z+`duw-UJ84&Hm$X7>W&;H^tl1U=Pu}#*uBEFzA+ji*GuZ=d=6KkrL)oBLph$pwgEX z!y3a>*vg`wDOB{>0gKn8%{3!qSewx8m^JO7Gz2ck#QWN0wy)Z&G$z~OVc^A%&v=|^ zrLHt#w4J^y=X!_AL>nLg=#kEyzNdAROs%QML=B3JHOO;a+-D2K| zz~-DqKrAqtTQMrd_wmLyN(Y4r1L}|d*+`v{am+P3GF53`Twji>Bm9v4_D+rmI(nti zPK;-j1K^6Vfx=MZApis?IAmT8Px;Vi)Aq)1adAu89Q}M(C;t$KF2L zZBfU}obO23f}``>isw#y9y?|j>D)%^5I{~iu=HXba=_ren35dX;a$OOJ%?LK)OAa7 zyLX~dq+Gx$(UtKn8E%!LEnrJ|hkFz(l9^NQoF!_dn%pM2xK~4B=uuE$(m?>p8Gg!I zECe4Wcmt>B`G5iQR-gt2QAI7%dMjNNRw)S1vM36Pb4rD_Oek0K+``rYs?IK>(eKSE zw_%xR498g8LnhjzXKOt%$qAF@5cd+20{8}9LYZWna>+5gx*cVi^h)Nave)yrWY=L^ z2$gbd#I0!FkTV*Ew*uVTu%fq@0J`LzngeXBqsIt%gz}F zpY|pdqdD3fym^{CnuFS`08b8_BAE#0IN_aF+x-h8LQ9OK*@g@>)+bQ^^&)8)UKm*Y zrP?O@Qf*uO56rdyc*_4<**1zuyR|}vqyi|F=l~5FWVBG;KV{nqc)b#7l9Z@PoAvJ? zzUNwxRn{-lp`G)phKky+YP!CsKdjoO(qSM$^ecTO4zqlD-hAHHybq_k{58QGF!VWk zg18|bXmF;7r@hp*=Sf5-s6+Ln)Dn~(LRGT2h8MS^%Gf|QAvjv66xBJ>k)+% z!2x_+$dNys`Z`DIEVH+8_YP{+w&5mPxF#4qn9AsmT51uskNA1-7S;3zS*^033FeW21(Cvf0x7#YmVh$Qs@XA09K3w=$bZQ zmgI&3y=33l`YI)Zg#-&&5I(NMb*9S~f&iN(y z0JCplyBa`;cpZ|^F~1T_a39&fX}XNRuEP^B&jsMCp~*+@NIOzPg;Y2iAQHY}AEHac zKwK{Te*f?UwQtJ<)&oi%a^+3Ku*19|LYo{G2v^cHYM408=c^Emg+ZJT2Ne{40soa; zmd8018oU%1QPC`RP$xT-0OV_4$;GQ-0oSR9azbDkV|!u=Q_a@<+8o*kM@0j016X{) zeE99Tg=u2iis*nplD|9GvSk)UBbAn zGN_kI3naSpCP!4I5byy)4)+)GKSr)J0cD?$a+C4%NyaxSR?k+vENm>uQ-#G8s3R3{ z^sL*XtP}a)b!d(b&KPc1NCMn zMpv+B7hKs`iJw2GjhEX*yD0j9kwb>BsEX$IHB{hl1of6PX{TqSKWsLHfc#O5LT!S{ zScJm0%^?3-@lWBl!G=^J$RJ;@^yB3H-vN8m3tttsSB-f2t!CbOUNw6Cpkl|}BYeR}nC zb@6KOw_Or#EcYh&HqbS{-pO<^kM(_Kz6~kF?lD>vaf>l3CIE4+!*TN@QXcMYFhP2C z<$=M7{G!s&_sY-ugJ(pD+u)ix!H9zA0%5Z-W6Op^Tha7t6PKPB%&xII;rnM2RzMjP z$J-_}W!5c)B^o!Dzo+X`v2EM7RWWAFiYqoN z=AYHQ`rqAaANF2n^WeMY^&NcUeFvWB9)D^_xHRy#L(uwqDPBi79%+LXScYM{n^lVV zkg29-0+s1wzVp=Vh`3QNer@InUnQ?VwMYD!HSz_Z=)y<>oU`bs3p6M&LEriVM@SrV z$s9m*RQwLHe1(VV9&^fG)}#L84l@6ldix=aW;^d0=hL|T=;Kqpf%oklU$0FWpM+Hi z(@xDDBYm}>$5~eKAI9xaqfg^Dmfp@kjN8Ueg*tKBP)#%pH*RDAx1ZXvt5kR88Bi8F zc5$I|CzbzNVSPvaay|9g8%}})1GD`1-WhWCCblBhcK-z||Ac*LeGavLQj%FCN>PUf z2x|olWk8q*1r!(G$ANK-=W`%KD0i#?3=CGHGZBJ&cbZc-kLLRW9~XETUlHCh?=n}& z{rq&5z2dW1E?JvYP|}Y#U)L$Nss~?)Y7@1&ngb*OfPU^*-8@=G<$jf9^tWOB znq-z18^_56uGHXpUYboYtUFP2tf~ry7I*5#Q%8#gGzv8p?E#mNFsAg1^aBPFs`>;V zCiJJkMh4Vv`AwH+4M$y@volUQ(e(fvyaR_FJo{VFKsZ_--Fyo?b+iye=|jm z03uQasJj|yD42lId#gF*B3?UHg4dU5di=VnlnvBKCot_~x}QAkWko`Woz+1sBS5=5hV zMLy7<=`)=;N4#5p?DSLEnBvQ}R%&P0>n2Xr;O$x)7uj8pY1)UKf(Nj?Sff)k+a`yD zPC#po#?efdHsc1h!DW)pJcfAF$6!W>^XPGD6VWjwX7I*ii$p|uUF8Qhk2gnl7gDi` zQGH7b#Z<*PK6pXOqqvValqw5)^G}mFGKzMWq{6?>h_QcJfG-|!Aru{ucau2PJFQb@ z(+XYtoF>zdY{}%*r$4fEUUM7dYj0d9XP=UYf8D)-6gE-mg&AeKz_5D~_o_(jV`5NcWcEl&t@5J7Y%REljvbhPd8AQZhbEw@BNm4@a}y-=lSB|oWOAo)b_ zJ3RP)z6|BS^mh8YKe#h=9FOSq+^^W9jS=Wlnxk)e-++0F<|2X}=4s>>00Oo63blA) zoYSOsglwidAruZEF4@?(H)-pqPiG0swuVf%=zOg?Du_^VtKb+pP^$Xa2k^E7(!4r! zlYqM>7EigqRyfV(U%yNCdThHx>AoN))qVz6;p<1t#O2hT8Dv~_3;db~gP3{(gQ$ao zJ)>Yp#}=S0@0kUh-FkEfb4#wrqx8NTFPxLB$aW zZV#|~E&M4e9)P+1zVHRJTUd5(pBTMi)_9~?hhHOYyiBrWb_+&uHH^>T2H~mN{oRLO zw{Sr^D^IscmS0VC@n84WevH{QBY&Q%ho5e#e?w9I$&$3Uvvo32_OLe*_HZ`&uhx~S z)F=K8`xE~L8Yb~0o}r*d0j~ZI5#_sal~np`zK$x*9EZA!xU+K^Plv$UYxO*#5h|;%%v#Pp3BV_e$%~A`r8}KFLrAe(jbQa#AZL|V0VV-vQ|~- zQt@w_#1eZhH%Z%tj+v36s}Kb)!nNOL4tkNA4^~#Q~8B2rF)quTXi;Dyo>-e%lf77XVHl z;cf7KxNJ3m7uIz{^2VNHZwut@7V{D~8IZh0H!30gb|c8{r2Uv`KO6MJd1mi@3;WNNEq zs>@CtLsMVgZLf+-E7iXgQ|=jHEY`bW_GyS9y@90$HM$1J$X^y%To(^FqPnR?D@Lm( zM7pk&RpZrAZw3z4wHnQp(`9=vEF712aak+7Ie=+-h6XI1@U3YWV9>L-w2H|<#V~)1 zyC)`pgI!^vAKhLiep5|K3mmawx<%)A^wH-MQVl3E-{$w+Dslhu00fT9R$>t4Aj20o z3|CjQiU4U>5n3m(q*03RiS|2aZh{m#azykWg$0h$gotn`Y^`t$*&;{HayCmWjM>Cl zLiKxR$$}VJUcE$N2Ad5ISeRZ<@r(n3G#P^P9)_}^e!%US z!G+eJIY=Er9!+c2q`9s>Ozvmlv%(L(F3zqiJ z@c8J|84g4TVvlPuB2YDWQR42cqhDoc+OrasVn!Qbz=G?7C`TFx^DgKtfn{2r9xS^c zH}4Q#XKX&LuoptAZIiflCPnL8`zhIVzNr4QRYz~W=c7wI78xB!ip9>~sjkQ7ZUjg- z9vDNL0Bk}7rIw-Are({-I69dwMw&v8S1UXQ8ctK5RkBUn#LJ?^hkqTd-RaPQPCm~h zhR;mT?EihH_utQ?|8B+V{*OcHlW>cf0)X4b7zK|Q3&h5=|5hyX6n=u(%v9#Fn?fYoTxHoFfTJrJ(ho*-^uW-)N$6rU+gBn6CdK7SORZVb0E;;)!Xj2 zr}y#ffb}c%PcjT~mGG>BKa9v^MZIki-2g+;aAPIkA+soy^xCa0bI>k9qk?%@McIM^ zWOiR&`;R3&{wK$r(l&*+}6KRw#=={&IHqA+^Q9A z2gQ=>I)}EFmcrQXiD)8;UCPd9sJWYTH^d_vtlT0C`+CV9V;}%)U6e$g<_K_sN%^n{ zXfepqfH|G$DO7gqyin+$Kc|L-m(z!=DXo@|B10p4$`#lMXl_uR2f_wM>Ch=vSAaen z68FaSINLK-g<|TN!2`t=84p}PqPgsHZ016Sn~vpDxbeqtJzuRp{nMc#URO}&jtM39E}BiOd}`o2D4%><-e6FgOnr;^7$4v5X|*tblle% z99jel>BY|_SzCqdKmPX0MWRs~!XCKw)k=t!i00ngvw)I|N$2oY|CzOa(Uiu1a>Pt& zrrsE074e|2bgeppDstgVmFY>Dqk&u~9>_3kC%8MDM;?Rd+FKW43<806)K6lW^Tah; zqP~(7wX{vz8;%#cBSjg?YwY*^jt3^6mHYfES^n~NoDzmGLXFsAyyd&C)44}~PNgKT zcJJkM!Jm&@Kd9cPMVwHQ)sVScSfXEbz7GSw9{7#GB5i~QSnYe8F>rFMbys>xZkc=@Rqo3^@ zW^e0Q$9;-CftPFO`wUr@QCqsXYL5q;%1Qt#X8Wrjnq2;iWW5_`i+lM7AQPUF%O=SV z)N1B^{3Z&e82~vJYI1X))F7d>p4fauCfP9)Y1^T#!c-{i$Cg>`Gd>;yeDVG!bc zYg6>%7&8tRe@^Z#u894&=u+4iX>tcCu%sY2|}n4iIwKoe+(C)F2tilK%Vz{8$qWcOj)E8N(V+EIpYxbj9a z)=_c=)??WPPj}b%52^Kc4aY`Wa7eadNEw8&y7e_-lWzoyOEP9K+N9$(O2?e`xNmJy zUufPbW*zXLpbSW(5u*NRt;a90KeOY@KLnM%1e~C=S;)WtvQ}cd!3Ebdq(15wy204g zWT_8C5lk%1_9k*JB@&uNlxO2BupUGjSx(w0$uEw~SWfWUyTTOXdv`^Nc0k4XlJTs|>_BJ5)f%gh+x`wIH8 z5dR^osF>vOQ~z<6b9V7?zOu3M{(AQY?FT!-DIydY5f&mYinHn(?IXg77 z6gH*avd?d7E>X;xi7fKjbwzM62V7cT#6R?@_c7XM;|-y@$t?fAzkRE(26k)TM5a_9 zA~?ma1=F`$+a~LbI7yclr9SX=_iy-IoLJHJ_i5>*YwagD7^yuzm$K;D>x`I~J3c|@ zs&%dNfrDV*RS{sDn9a4_yZ$6cDC_|Uq(<6nJ!(v_N_UUGmqsuk0G(Nzq@Y2whX~W7 zD<-+Rr5)>3d)9ISjFev)EZU-I^G%F=;y;sA0fZNtn)0K0dxEz?-PrCkFI2w!*=9b5 zS<-TCPo+VCWt)F~h0G46lJ5Zgp;lWpNilIWU|{%3vilpjDLAXjbGrf75x9!O4@;{C z3;g$2^3l&7$kF)Y|pbH{adE&rsNyT|HA zObQ_OA^6NiauV=mRRj*Z;igDOVl64WS(HUmvyks{#wLr5bS3Qx>OL49lGHh(8~&D9 z_*8^a20n`^f*E!(tdsZ`UVT200^)ng1G1&*BQpJnJORYlajF0zwpmAup}3$kr2fy@ z=8#B6(1fzFfb7SYh$0U$#iFDMxS+puDhJ^Z9vejNDs3JLnb)n+wkWITfLTjyuZ! z)DXmdY6$-KT>t-T!1><;QP#!U`kyL-r2p_tjC^QG&U3^|34K?9V4Q(Rm6tbj#{a=! zWX97EwuGa{W6{v$pEl?m_?YeOAU@IuE$Bxyer=qY@`82~x6#;n_&T-XBzr%-rPup~ zZpQ)>_LfS*@<=SgK!5o+r}KzC-m|AqYGwfOUB9c%bwWO+UYTi}xVVsNAY63*fuqnW zG`y<0LpB~lD72~m8H|r_{=M`=cAY_|=LXY5o7Ljit*R$~O1^m~XJ5G^dcw26-?vu7 z&<78OZz$}Za@Ka%^t|6Wobf}Xe+dS6k&n{?s;UZ*-r%6v03;(!RE5p_K10ajD|aGr zYOrkv$vVWlTeGPzkG;5w-07G8KCN2T#9?qn05IhI!z;f>o#K(9`hCoY8iy={?rI$WQ%+Iis@37 zBD&!f09V#-`hV?Nxhg;NVyRg%NWzyK#RL7&kBw$UMC4Q=igdYUXHV++zIa9o_VvWa z{nEiL90A-eQ!x8`ky+S~uaAIdkp5B!sFO}gaN>Q5*cHsfS9qQg*(FmbiObIpW1Cxw z0mc_e@(i$<9?=;xj7T@D^L*w~Xfv+n^K8@j;1xP~5qxk#v7?V?*E6WQXa5nK8A zhE)FZN2rsHSOs@VM;>&8>FyYX^Tj*FwpsgABE%b{wjCguT?Oqhu|308Ywfh4n`RJj zEW6kU1L#cKK&B@5{x27m!OqNN%4c1G_V2F?l$;$cY|Z}ZY51@9FEU45agvCTMet1E zfoLl}4OLUiwtit2S)8PTLnBT?a9yS?2aMV~4r6z{9K75h^kw%A^wZ-9rzDcJCJ7lHsAwYlo{5BPya0w29)xQ^uc6jt7KdmPOY8IUs( z3tKShu`0w&MV^cpGEJbZLuwb2c*8#3a$63q{fPaojoKQ~O2$G&u;WxyQqC zdUSPxQD=(*R?|*RWpZ2NGy#1x3I6(Ga=MBx&8lj6Edi#-xQjIH$jr&rp^2_zVk3Z# z8b(`T*1r<)WyHzsNYh=W3zrK+6srT{wyZ5gH$?VWe|5F$;sjW!UQ$erxZDT?C0j{F z_&q3hF?J74bf~a6VNRFawCqN#oYL6-0S5x7r&8gAMWB4$Sy6zr*nCP|G@+`1?SJ+O z2I8_>!vf=%vr&^7_D@t*-5OXI9m40TYbWhwSZ*1!obIzqR+;=_2Y&|RK*7E_PD^M$ zimMDFmpbmZWpX)l=L3Sakekxw?NjqRRqOU{*8Te;Yb>sWP z{wYU#C{1{uByk-saZNoCZGYo90#;(NTX}_oawk7z<}SMLaGtT}*?+hTYk&=_aE}vW zh2FUiBqf(aS6F=<@Io4`KFLv68I40ECB_@&gez$!GhB=0Dt)!CKtZ@H_70^S5|or%6jc@t!BCNqt`mu-OONnFiag6%bI%4s+Eh50?yg!MKg5$iZC=^I1Z z>Q_(xdiG77xk_@S%}vbC1s{KK5wCO4Tf}ZVR-yD$vvfM4@+w@}Esd-SLvs0PF*Jzp z%c=F9WmqQX=-4h#3yK0>T2I;qN@J2^%c3v01o`se@ayC49u->S47^aeoWT+yn@zQD zV%0}GNHd`ExD-84y5n|}ot1)?V9%dVZyDl73oMpzvqp7#WxE4VK0^ZlKmiUhUtx}> zOFu zPR5P&J^vDB(Kx9sYBsm{#a#kvf{&suYz*o`%H=|8ke~9wYj`(@(hBU1F^ZOHy2=>3 za}!E{M6iCvU%e?HnI=>mMH(#;8nw3dL~R5<&yT;HDDt3UWhW=cyC?V5L$he#Au!I{ zg?PnL`So7}72f+{80w!n{Mcs>|8GtmR8)YX|0O{DPrGG`uA=!KgFAGeC8OnFXF%9D zOG}g=c`*W`MaPO?*~^ci?gT%*mZN#B?_i%6uN4`sFW0ahqZcb1PCb|Fjz8a@@4T`a4HFPwTqxWI#- zE)H{HlwkXj)QqxiA}S8)A;kWpdM&r;Qk-#9lP! zj@o@RKU2F)1%>Uo(720(L~oF8OP?3VmaAnlk3mDBG{77(wLyit7Zj7oH53=O3OQX( zb>|HYS6-Jygb;vqIHf1O}P!{7P!F+pRoP`urAl>yq(1&5hW@8$Gx*rhJM21~v z&wRKz6rkjgjWN=q&3qo#5j1%+x=m6nlpZQ8I{!5D-he2wij?5vuk`{JwOtWn#e?w- zH89r~!Cna{88E9@L<7;!Lk9L#6hW#;hd6fFkLobzP+PVQ)jj%x!#z>;vg&@WD8ax_ z6@=eRY3nslu5g~$y0Wg+Z1Vn*gO{pMf3kp6C4!WZFKBaNb1xmAFLG}-|K#tyT^pjN zd97I2Kyo_Y8vE6M;%A+Q43}uR|9f*!Ndotlr-4KThqWWZ#Q~g_PW;{F!^}xi$=hk5 z>$sq%VtZaS$IIXSPj-WB<$86P%J^mg)+2}S-e?T=vl|K{sArx%^^3SUff(;(t!xqcp1t{!Uy@>j(0nmpa*o`Nzo#oJd?(_gls)x5EcCriuCpuW|>6%VxN#64L-{{N8z~V za_xKgCL2JjkmQe^omUQ)_=D{Po->4%Z#%SXq9asCmAs=$^f&17f}0}m5T>M!N=5W{ zXzgblHBAO~F1Cu2w&%ZOn(Wa=cgtz4{Wpc1q@sm?bi4>Q`|X@qdjAL~twx=ut~UGE z@_a77W=Z-pw5L8p+xp+z4gC+6%oH+V>CnCO*;irVrHwT zRP!#fFKk+3I0#|Ij0+9Y`Un?0EO>Xh-u0582&A8WL?$b&@L>udXhtOI2Whul*7=P! z@AsQ)G(XU9Y*7es+yWlMFxDu6Mpybmi*^^I#^nt?n8O!_CM)LbfgQWJDxl46+s_f?nIz~T$jnQou$eT9 zy8iB4=g=Dcw9VhSQ%pv$n90a~RH01boq7YDf1ov&! z5E1o%iL$_6X7&e$fS=IEnC;PhMmTNWh`B(kWeM$ql{AjM{0Q+eKMj5CdW({qhs|5F zC~rU^Zp<-P3>v`b%{A~qrDzp`Lv`mj6-d$y$aY-$Ry49`Eir-QpF1z%EO26yI47-p6zQsy%_r@W z|7s;?X=rOP?%{+qIujeT7g)1{3w-DQWL3O}#aPL%Vh_0Y();$BMaV-o>PE8`!Nq_s zp{Fa?88sFuvZFBg)+|%#x8h%>43ydMEhmOQBtPZKHj0r7BOuvxQ!^T!$NWjPBDF4D zYdeqt_D49l|DN7T7dd{xoPA_hhwOprbU#y(XB)`n%B$vzRNfd(koA_Q0q^5hj`s$u zy0#{dy<@9y*LP5u+s3h#0XM0;;4{2?Pe*0bo@}l$ja|)Y$jpDU6j>|~ibL@nJ2l)f z$-Th)yg;tv`Mg9H&336wW-GGDYD!l}HffQJNer_P{o1UElWH1YL6jzy{A(7@#_wEE z?<*!WWZw*aCHf8@Ck^zQn0=UG8QC;?#9P4j2Rk&+7D7E_7OstpEA6jCELsTRVWW0Y zdfK#7r=YeVOh{78n3y;>ND{h<;~;MqXh4DFk$dR?L!c)Qi$VPV5(UheA9cfe6LgCLbhdC6YD8l@r8YZ zEVK@pT_INT_UAx*2Kg=V8|6&5KWJW1NH%Q0(JNts3icA99;M z&Gq#^rgXVza7)$<+#s#VklCH!YKq*${emgZzbU58T7aL4g4Taiil>;ERQ_-k{3!#= zx4yXvDI6Q>V}=ChnnJFsG7srH#j(j|1r+5vfwW3&7j}fQe#K!8!08SELyQ!K>;_HQ zq?DpfGk<%@)TpQoB;2YP*lYIT<+vbwX^n>aYQtM+jRk!e~nG2e!y zqQ)0s9X=E{3yeQsT81V?yuD5?hCK7&rB1n;M!0 zA>%)(W+ad#C%kZ*7*E#=?Fx;mUGA~lk2zB8nV!nqGE#Qfx`Q|&A31TNTD5BJIKNzO zAHVBx<}^iOvy?^T!;K-(Dj($Eg^Y<{W(U_uO9zpa$IG{ghxXsM1Xz%L3i+)SPnosh zi0FLxex;!CGiXo1U{Qy#iarEK2z1Hu8-~Wh(5m$Ddw+jwz-^%z(0|P17fT!TQOE@h zgb&nVh%q?92@KMCR60oQrH=b@ydo8AONMozqfdlWoF%)!8WIwD)aU7=NCBJ}IUA@g z;_6~83@;VE=AdM@Ba&_$i*S|(j@4W^2Z!u^`sE+((pUU(WT#6}#n{>P#<5D^%M~fK zsP+#X+s~|t#ncq^5}0PAG{ven5BQzS12j#0fdcGW(vvBs3$M;3*{D2cezG?g&J>A~ zsR_r{0_>#D+H6~)r^Zg@Q8P#R8qypU&aDJ8r%=;P%b;~S^Zkylb6kvS-34i#s%)9o z<^m=7>Yk3dnV?XWySjT*m@r;PMv#cCmfKd3B8c%|^VnxO0sGj|%R{5-_q7OJ**Em| z23I{Ro-FWe_)vU^ebKWa{7s_yo)hDlz5zrY{vNa5#|HlQ0D}bNE?Tcd_76d^{PjIN zo5udjBNByeUxjH93B5Dp(@~}WwvoF7YOXMGI~flql6kdDHK?h^xw^9HK@WZsucs3t0oqU@q!cELDtt(yu7smcrWRHGNSYnw`9`8xZJs znZMzJ-9${q>Iidp|tg^HONk>An$sq!dLL_2$Rv zitK=VFA-!$y`Q)247Q7Y4(AiDP5!G53dWB4pZw2(F zLyUyrw2_{xjYfdJv1_9IRvUvVaLF*NjjXuEP=m~d=NOaowwA^fBG@amM@@m1v-8}K zSOR5hy_@3H7QOe2K+|^j0&%W4OlPMln(o@0q8qly11kruOClUv0T%hU(E7Ik&T{P5 zxZ>1n64V6+AW8ZOvQE+7C5p~DvJQDcCZYn8b}y-yBhm7Y-;TJu92#(1TjtJKVt7C| zr}CsLFP7D~>gDk50kcQ#dvc!(uFW||20sHzskb*mN(`i);I#*x(2^e&CLJBFza7>S z2+nvMwA|l?3!ZNN8<}Id0$c+Po7zO|3m6#mXV>?CPv%f_w6ir+l>aBISj^qX#NOG$ z?!UlV@_mxv%;;H7&6UlX)ki{ngPC{w$mozmQnN}Z^`G>T44)10W#jM_ML|&FpFX6k z!a-|{+nrem-2()XgGsLscOP(jzh;l5PaVNjMv$Ifvj@c@zsE%`%T7#E3G9%!F~Nh; z4vkw()S;2ZPSUz70>*?`*%FFDj=^79*&>Nz;Gm0b*U!Aa zvo7896xe8Z65smjN9Xuv#Q~8hGJN*wxW-eSmDV&3 zUW}&H!eNyfA$ptp*{ZSmb1lrwY&@$oChtsSZls|W`WXb3#;b|4SZ|yf*G6xnGncO* zX-YtI&17}~yiS|VTmBlYYOoDmkPKF6FrESPg69#U0vt@3Yvvi`{vnu@I$SfRu0DZ^ zwLW*=b1DF#YC=FGn>sW1f8ODr*Y^K!0T%pU-Qh0I7S{il`Ii+u{q+9x!?^!U{Pq6# ze=lq2Y+-6)WbltqLfF9A%tYA5!rIuxk&OADZB7*{xrOiO{NNzW6cYFXK6Ih-E@c{; zumCu^NaWN|I)7xcqNah1?-t8*0XuGJyGYlKX~>3ve>e)el)lkMzzP}6-%qt?XFDBC zrB6K&={4QI;I*0oJVM@{n2v!?j?6gt)am|hVQ=Xy>s zsBs+8ymdS`})o*@j=nVXFcV0fKBC9uXB=cD&vN5bEMP#My;I<}WaJZw*n?!KWv2bPP%wO169oRC8 zW@R;J1DwF(XYO6hDVG(5hwKtnt<2ngF2v%b^r*?#2+`^tX(8?n`qmnk*8m5 z4K0E*1wFxQl7?NNHCrk!-M#M+EU-c(A#A4 z!?NttKfNuD6_dXcTO7%m;CnectAtz|PXR@hG7h7O#}n5<<%(whow(UAwo~70%TO=R z8dPZwjS(L%7uE%1z}{EDS4E0FIp7%}3F9`4jp*p4rCZJ0=E4Qjw+0b;Qx~YuhIEO# zPPEs^Cnz6msV$6+g9sW9wf?P0F zpE15jfWHCTS+Jm!;94WtGn&9>0za`Zo-p*|OpIs7>HQ%Uwc18Zs2nQXZ3Fkx&Meic}EL7M+;|S_@;hR;wHB5Z zNUTp4ML|n`iH2%bvJE1*NKvG|=-S`9HMF7aEa99X{;{-(OqdNf=S^XlJG6r8By&S% z%Gk6g{mFD{AGC~=`$bw`QwR&ZwY^m1Ia7P1)+zcFA+j^1($0O=*49UIt^PH{!is&v zee(RdqtmGBvMuHiJEr(4$HD>>V`iHca*-axU%HIvJ;hngsdTJ(f472rCCmZ`WLbdYRPRNhnLfWcv zit)o3Cwr9oefO>5?=`khT}^#V>D(CncE^*Z?@9S*?Ijzdxi#NVM_)x~Y7EjSRGDn% zGfj`Cv!b=fRY_om%pFBgL`mgI!{F&F4bhDZV-kRg2DFLi3uNJcA1eAhN@Yc&uw*hB zU)IFhpcq+5($6U0Vlsv|Bk0%S53XO>#qud<271?=XFTnkJZ4Nh||Q5oXK zRFBHA0F~W>UcKjr`6B1iXuawy*E)fM>|&(Hy^t~R0f3VP8z(hF@l9oUef1YPX`Bw< zZJxx!MsA5(19Q{we6nC;=2{gtI9M#qRD@ss$v$kN6xIpmLVyvBOTs(+p0TqJF>E0Y zngesGB;L51c!K^67SZG@M<`G+eGomTSg$&oi)iSMZIo}$f6Xy)9ARdVs0xkBMYK0Q zezXO=1n^*Bq>YJ6ulI4p10l$-n{HsMaLtM3YoN5`#~0-zU2Ab|^EP_k5>1X1z^Ft zk8BeGCH7XzoZMdK9_~z4%cp%kVL3450o|r=*&w9a^4K3xFHz<`a!k(3u^~v5JNX0G zq7zZUhVjor^I;2@Vd>(vC~z6#bgTG)hvUgWak45(bU3d)hv}S_OxTJIVUy~(_`84t z^#SW7D)hU-ez)d9sGa&ULUL{2PJLV$BHOA2bCs z_(a2bCeq!@y+wS44EXz46 z0%uqPq=T6>SL^R4HM zZWg25kT35H>{))fo_LCE*Q%QKMz z6xq_RnD=ZK4EzQVq{9wCYmaMv65#UhBh!5FdG?@KJUer)fWn|vez8a(J>UlK1Y{aqMNZeSCwd5$R;De7qNA zN1Kr95w*{pi$h;9>B)-a6goU7F`-=Ffvt%)pgk=A<7xlg&o|Qzj{FpzIG#56#Y0k#()&Cz3UFXol)9Br7U`YR)p5* zp5MV#wG-{y4k}unw!j|3Aw)Nwkd1}IEAf?YD?W32G-Aw|x7RHwBy;+jo#3LGyQ1gE zNX5p{NK*z^jID|@Rv{6Eil$=f%cR*{U~pHlsDhp)p-Qf_!rxT}rl+jFLhmAS-;59) zZA+W0rtaX8Ujy$02oprndshm+d}ihMslX{=ZP>`3eEj=Po3plBm7CEG*G^y0G(Ej? zF0Q=A%r#R;*|85uFyg_46TgSDz!l&PY&Y#q;&?Ho8%=NXR7_1F5jQ@f5*bIS0hsp8 ze1C0dO#mjNuk4S#quty_ehJQTOBgIsGLP8C07Y=0GmHp+*;^Z;th6YpJGidQOv$=+ zca8{Ln)oxEB!j+bK>!N}{mM$+Ai9w2O^onZs-y4V<2e2d{Z0h5J3z;?r&TkP*Y$Uy zH8Q`d5YBX!>&SJY<94Z<>8aJQ8gDDHx*6KI52X$iIAk!RPXu=_Ji|Q#Dr*f7BV!DXgOzMqu zyD`*Ta~z)<*!~=pzn4V3-DESjjJ(a}v6t6tLy;VxW}SUIITSNCQO|P9m3Dhho}9`G zojsBMTsGIIt&S||X7?baz!d0tu-2fMU0sf7l3IFiiQ0Bkv}P{GLm)#a+kto( ztbSMTU3Mi$XLNp9kBX<-T@T{654@zJDRsJ^hmNM=OiH)oBZF7W)lu?TzIYk#O}Xh? zvWX;ap6Rz%twF=kpl%W?^eiApm8Nh}6%@l!1IJhG*MTvH{g<^;b%Y>T7VA1a3`0QG=uiWne%53jN z)%6_^vCX7{U0-pReeD<-v=Xb z!hUf+VIsb8nXYNhZHwn^n2c+D&8x3I*CgH7R(tpS))l7<=vtzkKDbhX;MK%rXfBhYSn2Z}{Irg^&aVo<#eVmF+YEmCEo0;| zN7ZQ&WDEZjW0|f9rB^y}&wg0@mAuE0TOa%#PLCWzEF%7t-W#p4>v#1}e-;q+$EtXi zQ~a9HAk9ycted>uq|oX7L;PoI3+#P@FZD4|a{@7~;!0?el(J!(Xmp%0r4-82S;(yv z>hIb1ue`t`Ql=H&pHP?8UaRjxdM1#RW!)P{qeQQdUTDqUewv88xIeZG8u0p{t8!wy zk$4<#h$&?S&IZSRWN|&QfBrlf92?2v@)(RjV-6XCgGYKZg>fSd2))J@5c72&>Kol$#%XY6(hb!x3d(`wfig0_uW@dysjHJm zOp$sFLJPkuYUuU&V%k4{T$O8w@Kay7WJ=2H#O{w>_Rt!a)=dD#%YJjVTh@Bv$baXFA7j^BW?Hbu-K9F*uCMt_6l`W zN`0}NG>@_CQdp3Y>;73yF$_d+13E&~6iGvOT8PWpw<_r>wm%BdCTb>f{k#|GO>zj$ zbaPB~W9;UsgP+{A@8~BN9$0Ihdv7IX1 z&pzn6w-w(`0#A7#(g8kt&WjIv*P5DoFYAk6mnE0nf}P`O^-6m5rV47&`@SB(xNn%i zALNev-KwZbe1!PsHbAQS@53FRYI}so^~6IaEbM;WhOUw-5!TE)#@KQWz9o8$&s3vx z4ZWqWdF3GXp@b)E$At;{aGq>>mzJpQ5Pq)rD!J#Cad$ncTqkM>Xj8Nm97`Hk8 z6?kF$b^EX;4wvOyIsWG>?jn}=VI+*3!JY-jE(Y=zB_kH;wFzq`!vdXxZ+kD|RNF;p zh>H}3X+U2sqQQ?5)FiA}iB&p;J?9DLG~FcB(B`~_HRB-Xv=ECpnGfvGO$bvunpv27 zi;T^MfPFJQ@Ry+RUbx0Z66LZ}y7w<$CKtkxws8NRTr?l@yD6Bswrn(l;bfjYy^k~uwX&hqt zH!A?g`#Px6U3sft@Alv4UK1>n4ByC?qFnv?CPX5@&92J(f5;i;Y<$=pV`YydzKrMa zL{57j9i7QUN31Yhn|gl+q}Cd62YU3N~T+NvL8Invw} zU9HMnr*SSW>Owk|siC+ruC-><)qH*^a}H)_9(t9xqazP_ZLt_=ri?xP_u#(aWQcq* zb~)KU_ZpM4gv7EtqMX7dw7ET->N`Fmdn6}Mu+i}*|M6xZ*X1qY0Moo%9K#KtU5MD3 zhkMqg%Fx+<1RfUy3Fl`zNXwvsJ~}<^EAoDM&QG4%&Gi69^IP^@wSi!FQc_?l4E`pC z#s)T#Pkq|s2n@2K%7PGTh*c6U>>`fFF5|)X|Fnzs8z3}nd#3kHKS#cjpXsiA-9+$5w1mL1`lci3K)DQ%WLFNowRWLb*QahZP}X*-cNTbBclw<3zTQvE#e$vn8zZ}19nA<|^;06}uuo@(2ORIAiKJ`Lp29soTaUQDK=Rd3 z)q}ml9KnRh$Hx7#7;&W5IiFN(pE+;4<9)feDOxT+wkAtrWGdK@wQk&= zluef$Y0IodM@CblBLM*6aq^oTR2P<5!MS6dW$}`Jo12@jKvtFF?7;y|O}8a1Vhcma zeAVR6&G+6A?I46&I#S2$=V^jrtAIH(6vmb2Ert_;Nu_6XTS{;J8uBPK4W*`{#c{-x%E5;D z@J?^1zJ_d5>na|5wzl)(#fHjHomubMXvxfLjD|#calU%UVew z8vmTAa2|ciyRVR-XSj^YcrT9O(;4Pf=a31G|G{riMpHMem+{R#9CoeeqB{RQX>lQA z5V(H2SPry(*$xc^IK0VPb4vdFV?XoxuS7~;iOB(CfJAd%g8Zn$o&@ucvBkg^qwJaq zld2mWR;6#0Eb0>(!OV@;AgAc^cGml@Usr!ls}ImO_UY9GJZBtlE+$69{Wr;s;)_)a zt2M=QYSq5ptrC%#J|+KVEJkV1iUWb2k}IX>w2W8nsqqEk!oU8G?n}^VhWinL@nZ_y zMZX7ET<4kFBt;q5WhJ@K%!cU$Jzg{K=>w`G%Id@gdX;;a#ygqRbVE0trEk`-IIB5k z4fX8+E9zFl#oBm!x&DFQJgG27xiCx2@(^sNMrbtt*By);q@>k)=58eN^^(`juFb;? z@?}rx6~WD^ebOner62eY5#F!A{Zx+fs;Oe)@${BP9J0XB$=~3_fYUA!2|fIKJ;5m% zhdL({)ces}Vvq5v+0WbQg1H?lRcDNAa7$;m#1&|KGwQva!Ca+&IAfHoO!K-ap z-_8Z0AFOhUmakg22GJRp;K_VK7`1(w*Bz+K@dQ4GuKJ{af*O3#fQ>6T9RKp#x=9%G z_R9GC6|1rDk*4mXcmV!&3H+71S?AW$#+qP|W(y?vZwylosq+>fBCnvqN_S)y%d%wDCpQ^XspL14?IXs>*9{$q) zUNA^6xN{iFE8}8r67F1%bNbCkmEAvy6&jOY9Fdk#hPy2*8{%U5 zQ%1hw38lm=$MN@qexWBB;u5xssO{&>Y3xV>sVf+vG~j@MA!j_FmJuwreiq~;b}o(< zPea{7<{~d*6yJ*HDfX2jnTzwe+*r^^vfd6x-rZ<_*yMi5xP8kYJf(%>>44LtBq@^z zNd{ejW95PbM7xvpV9GaDoO%BVB{HkDy^=UtG_e7xMO`^u{xeWkuo3UawkkaG8fpHq zJ-2az<4jA-@C!-_h#;PPO>3d*>h7$c)6kJsBksMb)M=ubti97b89L$3;G_lBFeJ;E;HD)2*=kM{mLOs7|XX3(eM64!PY9<(ijJ!cOmQ~NVsUUtWUKv9mkTPal|tXZ@Hm(Ado~cGn}<3>$iTD7_UcMwbjXg91u+QI z8HNS&Tm6lB2R1wfis;Qzp+Mo*0wyr?e7M4?Z_%+jxb!i1Bc#&A4{nmpTh?))`X(O< z6zzZRIygOsUbBc?OW<2$I__wUQ7%s-`a(x08@A(d0y`T=oGsi2p-suxxnrD}WuKYB zspq;hRHM;e-sDSmXk7%jtvLvsxot+`G$f zwtu(fz8KsroU>w=k3HC5z8v-&Gn8nW$Z-5h>11mY&`^0KZ5l~9c&(pLR{&?qrnr_a zd6K&8flr-vF1~;*DNBZa^yV*FSD#Rq4`SFy_rsacLMiAzCRx(H35j?zO|Jp6Y(T== z*cBn(hZ74?u#DX|+~1;@g@h?X&z=or6pOR3Ag`*h>FLv;YDgKR51?VzNuf%Zn>*vS#*@K71W+2M6k%j^|1kwg@!0 zhg>x8Uq7n(5=96%JvTQ)Byqw@?){jneJsg#s^EYJHWcx$!rE235wmrFZYMboaF}(l z%nBi4eQ*FTlP!H6$i6oduIFl-WQZm_I@BIyWDEO(d$D`CNM8j(x_S=Y@e{+0v7}WQ zVPMXf-;F*5fAf=$92q+~NruM2e1RaT4<$*4x<<*8Sj2ocBbZXP-&GFn$Op>@787WL zRsI%>%e~CyP21}6e9VT*sWK{raC)f zVlIit?8BanlWTFA$w%%M-XDQQ__?oOX*U=iy!jA#+SAqrUA?Agm+1r#so4r$eFVA} zBX0xTwz}y*xaW%&8O>C&icO{$Sr!Tv!_m)m zXOBujM4DIb?(Jm?eu@+b=^D{LmyN}n@48N+D1I+P$1x`e5sDy!1WX4G%WBF=A9p8; zz>a5+1|h^_s@-lx?J%IyR|@@U9lEEKD#cylLKmb_R1~|(x(j@IM?}mad?v$4ZQ624 zHRu+~duZnurzHSrYjI1Kry&LoFH(6CG&10 z#`P48Q)e8v<_1c|)j8nU(>M1>z^M~PG6Zgx#@^BsRpvV1*+H*@VmwQy~aINrfk zEgMO5>iZn_jn@*w`fp(UpnV#aDVCc(#ZZS1J3# z+tl^LtS7k!p_-w+I<}7T$jEUmdWrl(`Q`yM{DyL57t>Yi=bR>r}GM>-P7plMoV&SG&PS~gf^E%r~NbvOH&x? zK@Zh3+ZE~W6RMfL7ftLxoFhOVS*o{wy0%;zfNbupKa6QyU~)3rRMaunLo-)^$@}h% z)4z;My2M&TZ;_G_+j$VN^?gCj@+3P80|y&3s!9g%$^P>8?cyV5c*Dri9SiF!zixJQ zqz@}*az0_y(DlVerC?vM`TTqGVT;@3dbY@d!#iokes)soeO(lok?nO|T4mV&5_~&H z5qf>HYrIs1M?(2m8h~=wL;?)I+&@MN8!Mm22=GmazYx?AI+xffEn5oKM_6ymsGQ zQ@*)Ai9dZF*LZkjzD=g8*0n!JrT0k&=n@PqCf^66YSFDnzkm;JSJDr%mD=_8B8yKd zzMHU`+pR0e+E3o9pen`m2@8vxbt_U{jwx6@O!L$WYuPBdkTt z@1T;;bpYam0}iF)!-KlIDz@W=Pfw5y^^fMK%6;#WxHmoCeiJS6?UDZg(tJ}FeXEap z?v%crw=I#=t;{1Tiy5XKkPl?Dkz}$!MzvT0my&GtIs0l?QHtmn6bR0h<*xtO$qpM; zGUhI&N|U8#d#pb`Saf`MLR9{odH*8 z&yrSh0qW!5rqb*=5bB?~*}w2wtpDRg&Dqk@+)3BL&QRCvZ~54ta9XXM;D357=l}o5 z>f4$B>Cs_@VCt>vV3_cqyB|M3+XnJ~?a_i(=ATD#1sp!vx_)nP{bRwSQt4aA@uX;btr6mXG%nq#p1Oo%x(akYHfa6L3t|qc4ffWrzEPz$!=@uN)`-5a3qxJafVPH2_-{)f!JtyQ*C_@u|G`3 z;AX-YK84kRLtYK@nE9@Qb|G=p&+YF)*<@6f*3reoDmYy*$4#;xAirFX|JGYsl6mHC zv>XWrT)9B3JL`btPeer1oPCIvkquYKh2E0`C5ULmMW8m_N)g$GHJRujWrFtgrq|9x zi^ig`qwGiO>_wGDQKSJ&=R^YmqmhQvK7;i9b|A7qOIOg51QC0@OckX>TZXV*%}npm+2l}|5fB0Q4SxoQnLm27=5AQcTh zeotF9fZ|Sl>~fJdvS>w&VTVRoS-p`tZGQxF+RS5^EV)r>QeF_n!LPjjbrpAOw8RfL zWqnx6XGu8~Q${ur&6Dp)F|zBWy-+-h>fzKWyZK76JzS_Q_aTzaa8oyCwPn%puJOSKZQ-SJ zQvR~#nx%&HoGD6*CW!T>^2X=tu;#yf5^w;mS>;9;2CCn94?Wb&*=JvZM6+=QJL~7t zcmrh3UG772ac^^3js;d~E6|*+qn%n{YFN!W&tFklZm^4Ma#D{67Ts0t1rNiNJHwpI zBQEM~O~bV#C`X*BWq-e{01B@Moo1&BK>Q`NRm;e_kR`{Vyqn zxQ)5fe=0`&mdzX;@(}NXt{D~!y5$PlcblHYKz^oBr~(3;BIPnAc+FxRd}SL8g?g&c zS);Su7JfkG9e=RxT=-!dC2In38W+PCY~RC&71GJSk(#^tWkNcPV3DPeot1dJ+YJ0 zZZ*Ex6L~j#lRGkm`pbIlh5owWOWaT~ri5;csB1M)CbxjLtnAi1`dV3)1$*b7!Gj&&tg#wLxr6Pm$r=ee|*%F;il^3c83qn8nSoY4MU;HyNBjFTm0 zUY`V^S7Mqqox5I$W~)+bu^e?Cz7-}0H?iHER_v$f*?nNnB# z_n9W{WS^xHH9rFX>=J8vLdZOS@WqgEr7+M_y2%vrIXMFS^8$$7DFyVvnVIVqy!{qW zO%y*cJUY16m3GsIjP`ccEnlx^NImFi#3Mwtt1~|5iRS#q8k6!Sbyw@Hn~6le4Rq#< z5^2^7&MXa>rNxY%tMsH=i+1TX)rq2f3!Rp#;Dw}pPG!xtn$Da=e?BFCXnQ}O$~sYq+h6Y!FG_RwE9{X7qR3m~U zCQ4(s!pA&C+iYzhi2aExvry7#Zof`y0*hjMM}a?&UgW5LHED&JLOmMYm$V&+i7)AB z)2QmIt^8J_en)C2(F-6G-@ywoDaFAm#oF+L5^%Rwdq#N4s*%Li`pECn?S6CvI)m>3 zPr(k<6l6y+>JWGi(7W|5_Vx*K>9E5es)Y=`l*8{^iY!4=kFnpaZL+}AuTHc5-MG}CLj zs=@!46%hWv77UDklUDqx0?6$ESO4rA@MV8S8@*2(H~eqBK=}7-{+;HA=wDmk|75&L z_#3a(@JF)qsS4D1s35!-Ujj@52Z*pJI5=Z3Rg9dLKt!sxD@Ne#M3wfd8UrFeCQS94 z+>oOrh|`d2mGs3q`-AVrQ|8O`B`=RJ5Z(7f1`qU2j`caKUBRjo)z+cNvY1+l+6na~8P!cOmG+ zDDpz+?~Vf_74-8v>dI(4$xzY92CEJx!}sh_AY!?2O|%gvB`K7CCO}!5cJZLRiN)D= zG$?s#Ph)I$9y4V7BUg=xm7(`22bGvF;Y`xSjH0?mCh@0crZwrT>=%iy@@vJ@7Z{)~ zh5pi#vwQXKv%zSZT585HVMNPIw$5J}*R?y!vSe?39fUUU*L#;oVYQ3LXR&2ZYVL`d zbP}mDk+c^=(WsqaL$oj1xvdKGOo0za(__M*NVRHCj^^_|0yIW5vphF(HM#t+*=f6xA%Xu2)J zu^Ia8!dP|vFs6b}&Rgp$j=nIE39l^dU-^;@C2Xjnl^e z94;O%xN`_7mksWzd^f6ZpDB(&>|4j9`EcUseVtd*4VeZ=bOlAPyXm zG)-xUB#OUT4B%DovT9AG7#4!Jq=n#ObDs5T(Imx=TYwh&D+P4cyFhKJW-Q@4j}Q^v zP(e=&(5?&=fjEg6 zc0_}7%}H}93Y)X18?XQ}6bMn(2iah;bmWVTIgPE0iOXjCwa3HK&bP0KS zUDzaC_*>^Xof6jg(+Z5%=w#)761k5xVkmO_%EK@~toGr#%|du8DOqrewkN~0Na~!5 zL1p`D+-r?5!NJ-;oS!qB2JITgTRvjVk6Q#QBz^m%5>a5HRxxP%r=G*$Oa|{@g83~) z37-eYv@ybTJT5|)4|MoqEm&{dx3APFJ{U@fN#mj>bodRaLA|LEU*-awK<|f?KY*bJ z^%I7=+$a}_nm^3-bT_;}^O1rGY{0xYP!w^PgB~ckK~5}x>U|!ehMmXN7v`qF6H}g_ zAS&NEZINsd-sHTuiKS-k_G8Z0=CkGL<~x>by2jNApzF(q+nW%_J`jg=A6VvhgV*1}zuT#nTlYtE0C&{w)7uO~Q zVC7?9_$tuP3V-@95Mt9zr7_bQg0J7!49UTU8(TM(-&6rZ;Uj~l-pO{)+$B(UnjO-| zjZCsq-Cb;4yFVUZVS1o(%a8QjP9e9P9$(f~YKWzJ%cHKSqHSMH7@MC4DmeKUTqY!H znoVEQbv9Pl5oEO8NUGP0%pjLoRSUeRDU3BcJjpR(bWnCx=c8-jWsFD_M z%W2Um0$rLjsM)T{iU`7aC_5b=35Ma@ zursUD-I+%A(bzgzT&PSmj#bro_5IpS3;Tle9o^uF2dJW@mxtcgffU|y4Z40M>C8Bo z71NPAD(`Z|#<{BTI~Dxm)KN>6KIVAG`RY4hKi@AelT9*G_$4#5RNy#;=p*#O6l|T5 z+}^KsL&Oo$A@4TmnpM^_dmfNYlq%of!mcDbc4CU%dtoDf4Wb!I zNoqj9>o|p^<#Nc&H3-U`hxKvN)l%$mQsE=e-!GI- zMm4mcBIdgQlpHBZaC9usqikE4xH!&(;J8vXNwtd503Q|6CfWyNQ!cguxy=A5wCfePnj8qa6l5&OBA`afss{y)|oe@}Y;mXrM14F2JDKaruIsz2PVIhjRG z+ASZ(TLZY7H4@4@Lm+S}ZjpnjAqfrVyjHbepp|}#vX3{bN`#0c?Ztc@%`myCT>$DO zpyT4=YGTU6$;rv<>-`414LeRIaHNoH#ui8?xTV=O5y{bPIdprYDR2Kdyh^fez5S%4 zHKO;Q3n>Y)I0_n)s|l1`yfiI4FQWslUIp6hTWwYY+uyH$^YR(__s7Jwdiu*vdV5P5DBJ z@x5)(?!@?~xp|Vl(^HJSUP9OoLDiT<+Ynunn(W7#f{FsPI858P2wUa^byZiG9we)h zlqKC~TH_jlo$BIAxkb}V5v7c(Q+5Q}Z!$BEB4KILmcqOwL21I%-D1Sh!6xI5jX++w zgX+%x3&~Xaa{44Z;xJjC)c%n*!^^z7I9?c(c&e00~nDxMz>L2-k(9U^!`T=@L zu+0lkvuB!vW8p&Pq~84W->_)9@}8z~hr09>`eF@|&*Pkvhnq1rrk6A@}967RBOY5Nk(d-Hi&I{YSSzJt~cT`!iE|{Ip!H z|90^D55}ZQ#a^4=+0t4Yy|~~UFqt)(+z~N^!r!tbHh7Fug*_qZJwDpS)fJL84$B|4 zK(8oYmBp|h0eB$kPnGNd?8S|b&nMkXHpl1AqO-TUfZU?`5f^K0`p67{K!VPpy0%qD z76wk9&9>`=%5v?aw-E zcIeW@jGtEa3#B@VU^_~|4P(`~l9JTG6E&KKVz0ExHy;dgIrN#(pwoL3D2WAvr$)-0 zKN^_DkV;9cH%3%2P^=V#5s1U+fjBAif;dSolI-C)p(i2VRw&Y87<_SwX3^Z!9fP#j z8Z&cQ>vY>me~p~pTMwT)c><;9Zgr~HHHB)Iwbk{Jx@0-6UhX+#xM2GJa9?!7h>&3- zX{6LH4TzuciiK{)J9rlT0;ioNX06K^=|mwO+gu*;mW^Y^n1U1w%R4mSylS@D&<0(| zpFr&AMtIM3@5^Fe5ZH&b+Q>||PFis?SX`{QP%c{h%T_PCMrM)oE$yhHq07H9OS{+V zT=(a%L$0eY`Y@nBarJS8Z>;pQdA9XZgM!_F_gJO-Z_-I-nWD)p#2tl--%Y*v@8>R8 z1J_++mNXAAm+sLcbMmwPlS2leGp42UQ=`y6wM*r{p;_X8bjyENtACFLg;BL(fb{S| zA8sdEs_KvMt8Cz^;7N7@(Tz*>Si)*Bm~!?IHi-Y;KXx;MUf z<;UmX*VJK;jQlV|bCsfk>eq39LMp*FHgq6CT~)x17R6z>RBAHaU59+oc zJ*$6W#yIb7mv}%yL6JaZTtG=gf_ggU5#KTfAo~+$6O`WO2ktWF^Y-!v8W7(Y`rV-3 z{4-|n#<|`KX3x&X;~w+;_Z}nWGyLZX-Uj@oyk%8uZgK!jKLNlyO3?!y$X}B){Q_h8 zzf#sxA(+|dv~~F^s8~2a5CXY^s%F~f~O&0poNAApnAR2Y6MZZttB1X8v0F_(8J z(=?HxApFkcvUKc+Jv21ZGtx5-02skHT*px3rv`n-7Z>UW^lv@)---A5vwG;4Phs7D zCg1-xf&DG(_?te>QOLg-di2q*#!>ve&{aGIbx6dNV=4Xrp#8pX7Kfzqh#M;7C z%GOH82(i;;5H>Ceg5ihDv6!YG0iDsCdh8xbTqs-`0WAsY4jvHjEi=O$$-r3nZMx=` zUlxBc0$Qv0sZe;d)Fzd^=PGt6tK*LEc^Mr89U}#U?;AqOsv5@fH!qj3(VxN&!Kab| zrJL2qe{q#m-r{c;4_bQFQ5Dr_}Qqz zm{Dg_CVaTf*9=uxghJ6*0#SOCR%KJzaW(!DDLw2`poczEWm^o{+MGK7oGx%8Xkkd( zoUV^9eR(Tb#nEI_l4fiXmC)C)FdsXOy%slWvont(2rM6DqeD@6-$pHkkCC+NQ`S3C zmu4>&j|LOlk*7s~Ck)+;vL2cX)(H(UQC4RBgPLxO4pH=LaLv^5 zY*4Wx)(haCq=`|q3{QJ{@U;(m=dM8F(or>aTSNCJXSoneP1outlI4(ArW*{Gq6Ut) z^28-JG1=_3&TqKaEbFT}#dTzM^&ZGDIE{WoWPUal!U&qIds4Ba8(SwzT+rfa6)|g7 zNvq!w$lwaq!h%F3nGq z@l8EHD{3g?TvWAKcuYEtP;uLEO+xRx9w1$vQJ$EV-q5*4B@3!PP@O&GZQ5HMEVO*B z!z6{D(1@BJD7s)d-+mfOcg;PT1=mN1e&`IgL1RI4u;B6#RuXyP#@;xoEe#UViBW14QMj9$T`sHnTS%4X?-i>U%;mv~x;6nh8 zU^%%15bdWb?dN}s1HX|YUzzYXM?Mb#`jP?wDEzg+`40nA6Zl)1#V;rR_n^6;@#L$e zjPlWyDqbY6lV)PsMwC#;EV-5og(8MIQ6SDqEIua{Hw&zxV`4*6ojQ)S=^4)w5&{|a zQkApQSN08ZWcC}XFbD|9gSP#a+&jQ4S(fKk=4g5$aa@4xIb7?*`pd;r)@AEqR=ZU8 z^AsT|fYmTm;Z@IRu&gjb7|I<<3QmaSaFdXtJgS}s)#P|cY2=#UF?BF4G|_HpN)~uT zAqlDTOHFD7c9z~X5hKvE5(DnhCma$Jxf9<)UJl#PMbuZUSIID1e`s$6KytZ_8|f(8 zl5yP1`b3@WgwNO1bxbBTVz((tA4B4mOj#aOxtF+Ft~+TSC>Q$;vW(iq6-V-fq~4={ zqlkXN6kB=Q5}Fw%S&yCKRV_CUQ5o_X_1jvam~^0`p~}Ggu-X!n`?$h3&YU%fL||O>IV2@ka(<;sZIGaH5h8o1&%EL-g0%)zffYCIa=to}zDcsd z=jol=C^!n6Ii$9Y$@>abd(=r4IZ?mZTr_7U5a-_7TJnK6x2mw)8h*czD?8CCIaRgZ z_nAO=>TS8OcoL?UnLGnR7ILy|Lw@KHWNJ)hxwU1&)m;q&)MZwe0O7O6qF7__7;9~u z_Ug^LCxJ<;@UY6|BE85##F;PWW~O6xk)=M?BsOLtYW?I7J|Gbnc#NWrcZvQJSTs_lCrV6iCG%u+x>u z*5(51au7Emn9L(JK89_qH6*7asC+_N(|l}l^rcR$l1(fjlMsZ=gy?v`Nxrd_7y#!( z!cy6}JVR^ZEfJfp zGIHr-TkoIIs@j7Gqfp5j-IJqRY8l)W>GO_EP&%k41A3FYgbS>6B=+UZg(#?0AI%_D z&@wX*jq_Vm$xthEiwK3oSr$ziuc&1pt4uTSwgw`b>H+Lv9L2<>ZjG8q*dTyC{6Sj8%nkgXmDfLL$%6 zB?-|t(MWhlhNdMOWtZbG{!y3(po)+)ml>>Hq4^R=g+GZ&m~cpF-*2#UBnZ>L=Y+XR zyX4Nj;u@ByV2VlnnB{MFEJ9jQ=xw++5Cd=ez?*t1e zxc#O^+RLM{U|gNKYS&1VD~sn)1&s}77C*j-;50x4Kqua_lc2gY1VIxs-}r%wtOkm` zrgLEmt~6F_E(svSMS>$5vR1U&Drx(t`>@xp^(J3`Ax382neGQzP*Wq7 zP%-$u)&!GnhIiv=QG|ICqdPN*2DwRp_yvUxAY7JA*3rRLFd8t^uu_S$Y*Rrxkg8%% z;?ZI%l|=G!h*axOB?j{pmi+Xkld~-TT>va7ESbDYYPa}52#FA+AoWP3oSWD0uNOMu{COXd@5|_u`*@#S`0l6 zZY8?C=f(Bs4tckgTc#)UKC0TO3miuD^@Jjl-*yPfzi+8$N^V*gGj420Ok~VwTk~{- za~>=iH@DkV7vFPn1VNfu)?$V3R&iajzUj3C+K0zm0Y|D)70u zptIb82V!n0lW}i2bG*zLm)aeqQQ;=g1UtJhP3&dOrHUt2%8dL7W^xZfJKX+x{yG}g zoiY>4K(VvVh^bUVQ(8#1C>hLiSSZ#l(NWd%D~{1j_lWitfqz!s$!jK?v(G)mAXsD2 zUA(PxysjZd$`X064RuVD{*NO7=9%KDf7Ccrh zLmcmFttQV|==D1};n)toL#ai*As4)h6>pQF=P$Wy1yVo9wK#PnmotDud_?u zDf0Ejmt<{*(aG4F)6sj~&OzUfF65u2baEeAD%6|npicu2a1dD*o5?#~eA*ov>p+X0 z@KU2U#@71sZVM+N7eMa@kADoGh)bc$gcm$Jr_icDNcD=_ur6t>BXoS}K;bvRM8bD} z+bgDV9MQ{WpoE$WjWnIR4K7ZRDD#78VP}4)H=##LY~23+g?4G2-jlToB?QY6p?NL@ zN^A|*&#j12fZ!(0kHSxhpoW{~4AJjAc3C{zpHd%CNrO!@fkh!NV@O^ew?Bfcy6@C{ zJY6ohTpX$Sek0&C-=WjBxVbZTe}KBA%+`GQ8DOk>!#z{A^|lZ#?bKBMyw@A!b}1+2 z-395+CLyl9yi_Z)Q|Kome_<-}vs^eU{1+Ju?y6oakkb1WR4nl2@6JX-D2cX3iwbV< z(nI95c|lSYgmLQw%pduoyK6ZjB{g3?Q(Lo2!6rTAp#~n+Y}$z5_XK& z0ldV2>SVupx$^m$1GoJ>?=^;smkQ?r0iy_SFfy-0oa2|_qnpSSsaV$vv2Wa-?EXmh zWGwG)oGt#-BK8wYvKQy5>s~}Rqv*R;)N3pD%Z0X00^v2-=k}#vK0* zr!0NpgmSv3iG7zUaJA^TOX*Q-?7=RHDg(ttfEoEkVKvIEXZPJ!^3^voyaB;HuasT+ z6%m9U`)EUzonHtvaBhw6=k`{`#*X$pH#iCF7f!^)%-<_^5MmSD&gH#QyHu`FGGf}` z#+)@aJ6v|{8(5K*e9&MzIqN}>cOz~bxJVL{cgvY32`#XPB$ZqwDRe2Nh{crJZe}is zDIO-$$94l^%iH(aejzWu0UY~W5w&$slA6h|uJDSb2Cwmk*or}ie_Vd0C{Nd9S4{3?lIJ2fP#ù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 EKW*&OzW@LL literal 0 HcmV?d00001 diff --git a/gateway/EaglercraftXBukkitAPI/build.gradle b/gateway/EaglercraftXBukkitAPI/build.gradle new file mode 100644 index 0000000..eef042b --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'java' + id 'eclipse' +} + +group = 'net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper' +version = '' + +repositories { + mavenCentral() + maven { + url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' + } + maven { + url = "https://oss.sonatype.org/content/repositories/snapshots/" + } +} + +sourceSets { + main { + java { + srcDirs 'src/main/java' + srcDirs '../backend-rpc-protocol/src/backend-rpc-protocol/java' + } + } +} + +dependencies { + compileOnly 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT' +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +jar { + compileJava.options.encoding = 'UTF-8' + javadoc.options.encoding = 'UTF-8' +} diff --git a/gateway/EaglercraftXBukkitAPI/gradle/wrapper/gradle-wrapper.jar b/gateway/EaglercraftXBukkitAPI/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gateway/EaglercraftXBukkitAPI/gradlew.bat b/gateway/EaglercraftXBukkitAPI/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gateway/EaglercraftXBukkitAPI/settings.gradle b/gateway/EaglercraftXBukkitAPI/settings.gradle new file mode 100644 index 0000000..6c86aaf --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'EaglercraftXBukkitAPI' + diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIListener.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIListener.java new file mode 100644 index 0000000..29d5f8e --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIListener.java @@ -0,0 +1,58 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.messaging.PluginMessageListener; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.PlayerDataObj; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerXBukkitAPIListener implements Listener, PluginMessageListener { + + @EventHandler + public void onLoginEvent(PlayerLoginEvent evt) { + PlayerDataObj.setupPlayer(evt.getPlayer()); + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] data) { + if(EaglerBackendRPCProtocol.CHANNEL_NAME.equals(channel)) { + PlayerDataObj dataObj = PlayerDataObj.getForPlayer(player); + if(dataObj != null) { + dataObj.firePluginMsgRecievedInternal(data); + } + }else if(EaglerBackendRPCProtocol.CHANNEL_NAME_READY.equals(channel)) { + PlayerDataObj dataObj = PlayerDataObj.getForPlayer(player); + if(dataObj != null) { + dataObj.firePluginReadyMsgRecieved(); + } + } + } + + @EventHandler + public void onQuitEvent(PlayerQuitEvent evt) { + PlayerDataObj dataObj = PlayerDataObj.getForPlayer(evt.getPlayer()); + if(dataObj != null) { + dataObj.firePlayerQuitEventInternal(); + } + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIPlugin.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIPlugin.java new file mode 100644 index 0000000..2a97fa4 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/EaglerXBukkitAPIPlugin.java @@ -0,0 +1,86 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper; + +import java.util.Collection; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Logger; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.PlayerDataObj; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerXBukkitAPIPlugin extends JavaPlugin { + + private static EaglerXBukkitAPIPlugin instance = null; + + private Timer timeoutHandler; + + public EaglerXBukkitAPIPlugin() { + instance = this; + } + + @Override + public void onLoad() { + + } + + @Override + public void onEnable() { + EaglerXBukkitAPIListener ls = new EaglerXBukkitAPIListener(); + getServer().getPluginManager().registerEvents(ls, this); + getServer().getMessenger().registerOutgoingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME); + getServer().getMessenger().registerIncomingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME, ls); + getServer().getMessenger().registerIncomingPluginChannel(this, EaglerBackendRPCProtocol.CHANNEL_NAME_READY, ls); + if(timeoutHandler == null) { + timeoutHandler = new Timer("EaglerXBukkitAPI: Timeout cleanup thread"); + timeoutHandler.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + Collection pp = EaglerXBukkitAPIPlugin.this.getServer().getOnlinePlayers(); + if(!pp.isEmpty()) { + long now = System.nanoTime() / 1000000l; + for(Player p : pp) { + PlayerDataObj.getForPlayer(p).fireCheckRequestTimeoutsInternal(now); + } + } + } + }, 0l, 5000l); + } + } + + @Override + public void onDisable() { + getServer().getMessenger().unregisterOutgoingPluginChannel(this); + getServer().getMessenger().unregisterIncomingPluginChannel(this); + if(timeoutHandler != null) { + timeoutHandler.cancel(); + timeoutHandler = null; + } + } + + public static EaglerXBukkitAPIPlugin getEagler() { + return instance; + } + + public static Logger logger() { + return instance.getLogger(); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ClientBrandUUIDs.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ClientBrandUUIDs.java new file mode 100644 index 0000000..e7662c4 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ClientBrandUUIDs.java @@ -0,0 +1,37 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ClientBrandUUIDs { + + public static final UUID BRAND_NULL_UUID = new UUID(0l, 0l); + public static final UUID BRAND_VANILLA_UUID = new UUID(0x1DCE015CD384374El, 0x85030A4DE95E5736l); + + public static final UUID BRAND_EAGLERCRAFTX_V4_UUID = makeClientBrandUUID("EaglercraftX"); + public static final UUID BRAND_EAGLERCRAFTX_LEGACY_UUID = makeClientBrandUUIDLegacy("EaglercraftX"); + + public static UUID makeClientBrandUUID(String name) { + return UUID.nameUUIDFromBytes(("EaglercraftXClient:" + name).getBytes(StandardCharsets.UTF_8)); + } + + public static UUID makeClientBrandUUIDLegacy(String name) { + return UUID.nameUUIDFromBytes(("EaglercraftXClientOld:" + name).getBytes(StandardCharsets.UTF_8)); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCException.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCException.java new file mode 100644 index 0000000..ba9d358 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCException.java @@ -0,0 +1,35 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerRPCException extends RuntimeException { + + public EaglerRPCException() { + } + + public EaglerRPCException(String message, Throwable cause) { + super(message, cause); + } + + public EaglerRPCException(String message) { + super(message); + } + + public EaglerRPCException(Throwable cause) { + super(cause); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCInitException.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCInitException.java new file mode 100644 index 0000000..0429a60 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EaglerRPCInitException.java @@ -0,0 +1,45 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerRPCInitException extends EaglerRPCException { + + private int code; + + public EaglerRPCInitException(int code) { + this.code = code; + } + + public EaglerRPCInitException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public EaglerRPCInitException(int code, String message) { + super(message); + this.code = code; + } + + public EaglerRPCInitException(int code, Throwable cause) { + super(cause); + this.code = code; + } + + public int getFailureCodeEagler() { + return code; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EnumSubscribeEvents.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EnumSubscribeEvents.java new file mode 100644 index 0000000..63ca14f --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/EnumSubscribeEvents.java @@ -0,0 +1,39 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCSubscribeEvents; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public enum EnumSubscribeEvents { + + /** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventWebViewOpenClose */ + EVENT_WEBVIEW_OPEN_CLOSE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_WEBVIEW_OPEN_CLOSE), + + /** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventWebViewMessage */ + EVENT_WEBVIEW_MESSAGE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_WEBVIEW_MESSAGE), + + /** @see net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.EventToggledVoice */ + EVENT_TOGGLE_VOICE(CPacketRPCSubscribeEvents.SUBSCRIBE_EVENT_TOGGLE_VOICE); + + protected static final EnumSubscribeEvents[] _VALUES = values(); + + public final int bit; + + private EnumSubscribeEvents(int bit) { + this.bit = bit; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCCloseHandler.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCCloseHandler.java new file mode 100644 index 0000000..943f5cf --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCCloseHandler.java @@ -0,0 +1,22 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerRPCCloseHandler { + + void handleEvent(IEaglerXBukkitAPI api); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCEventHandler.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCEventHandler.java new file mode 100644 index 0000000..7f7299f --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCEventHandler.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.IEaglerRPCEvent; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerRPCEventHandler { + + void handleEvent(IEaglerXBukkitAPI api, EnumSubscribeEvents event, T data); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCFuture.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCFuture.java new file mode 100644 index 0000000..b3b68e7 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerRPCFuture.java @@ -0,0 +1,48 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import java.util.concurrent.Executor; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerRPCFuture extends ListenableFuture { + + public static final Executor SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor(); + + /** + * Warning: Futures.addCallback is recommended! + */ + default void addListener(Runnable runnable) { + addListener(runnable, SAME_THREAD_EXECUTOR); + } + + default void addCallback(FutureCallback runnable, Executor executor) { + Futures.addCallback(this, runnable, executor); + } + + default void addCallback(FutureCallback runnable) { + Futures.addCallback(this, runnable, SAME_THREAD_EXECUTOR); + } + + void setExpiresMSFromNow(int millis); + + boolean hasExpired(); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerXBukkitAPI.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerXBukkitAPI.java new file mode 100644 index 0000000..5036cf0 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/IEaglerXBukkitAPI.java @@ -0,0 +1,243 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.bukkit.entity.Player; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCNotifBadgeShow; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCSetPauseMenuCustom; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.NotificationBadgeBuilder; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.SkinPacketHelper; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.IEaglerRPCEvent; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseBytes; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseCookie; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseString; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseUUID; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseVoiceStatus; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.ResponseWebViewStatus; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl.EaglerXBukkitImpl; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerXBukkitAPI { + + public static IEaglerRPCFuture getAPI(Player player) { + IEaglerRPCFuture futureRet = EaglerXBukkitImpl.getAPI(player); + futureRet.setExpiresMSFromNow(EaglerXBukkitImpl.DEFAULT_TIMEOUT); + return futureRet; + } + + public static IEaglerRPCFuture getAPI(Player player, int timeoutMS) { + IEaglerRPCFuture futureRet = EaglerXBukkitImpl.getAPI(player); + futureRet.setExpiresMSFromNow(timeoutMS); + return futureRet; + } + + EaglerBackendRPCProtocol getRPCProtocolVersion(); + + int getEaglerProtocolVersion(); + + boolean isOpen(); + + void closeAPI(); + + Player getPlayer(); + + void sendRPCPacket(EaglerBackendRPCPacket packet); + + default void subscribeEvents(EnumSubscribeEvents...events) { + int bits = 0; + for(int i = 0; i < events.length; ++i) { + bits |= events[i].bit; + } + subscribeEvents(bits); + } + + void subscribeEvents(int events); + + default void unsubscribeEvents(EnumSubscribeEvents...events) { + int bits = 0; + for(int i = 0; i < events.length; ++i) { + bits |= events[i].bit; + } + unsubscribeEvents(bits); + } + + void unsubscribeEvents(int events); + + void unsubscribeAllEvents(); + + int getSubscribedEventsBits(); + + default Set getSubscribedEvents() { + Set ret = new HashSet<>(4); + int bits = getSubscribedEventsBits(); + EnumSubscribeEvents[] enums = EnumSubscribeEvents._VALUES; + for(int i = 0; i < enums.length; ++i) { + if((bits & enums[i].bit) != 0) { + ret.add(enums[i]); + } + } + return ret; + } + + void addEventListener(EnumSubscribeEvents eventType, IEaglerRPCEventHandler handler); + + void removeEventListener(EnumSubscribeEvents eventType, IEaglerRPCEventHandler handler); + + void removeEventListeners(EnumSubscribeEvents eventType); + + void addCloseListener(IEaglerRPCCloseHandler handler); + + void removeCloseListener(IEaglerRPCCloseHandler handler); + + void removeCloseListeners(); + + boolean redirectPlayerSupported(); + + void redirectPlayerToWebSocket(String webSocketURI); + + void setBaseRequestTimeout(int seconds); + + IEaglerRPCFuture requestPlayerProfileUUID(); + + IEaglerRPCFuture requestPlayerRealIP(); + + IEaglerRPCFuture requestPlayerOrigin(); + + IEaglerRPCFuture requestPlayerUserAgent(); + + IEaglerRPCFuture requestPlayerSkinData(); + + IEaglerRPCFuture requestPlayerCapeData(); + + IEaglerRPCFuture requestPlayerCookieData(); + + IEaglerRPCFuture requestPlayerClientBrandStr(); + + IEaglerRPCFuture requestPlayerClientVersionStr(); + + IEaglerRPCFuture requestPlayerClientBrandAndVersionStr(); + + IEaglerRPCFuture requestPlayerClientBrandUUID(); + + IEaglerRPCFuture requestPlayerVoiceStatus(); + + IEaglerRPCFuture requestPlayerWebViewStatus(); + + void sendRawCustomPayloadPacket(String channel, byte[] data); + + default void sendRawEaglerPacketV4(byte[] data) { + sendRawCustomPayloadPacket("EAG|1.8", data); + } + + boolean pauseMenuCustomizationSupported(); + + void setPauseMenuCustomizationState(CPacketRPCSetPauseMenuCustom packet); + + void sendWebViewMessageString(String channelName, String data); + + void sendWebViewMessageBytes(String channelName, byte[] data); + + void forcePlayerSkin(byte[] skinData, boolean notifyOthers); + + default void forcePlayerSkinPreset(int presetID, boolean notifyOthers) { + forcePlayerSkin(SkinPacketHelper.writePresetSkinPacket(presetID), notifyOthers); + } + + default void forcePlayerSkinCustom(int modelId, byte[] texture64x64, boolean notifyOthers) { + forcePlayerSkin(SkinPacketHelper.writeCustomSkinPacket(modelId, texture64x64), notifyOthers); + } + + void forcePlayerCape(byte[] capeData, boolean notifyOthers); + + default void forcePlayerCapePreset(int presetID, boolean notifyOthers) { + forcePlayerCape(SkinPacketHelper.writePresetCapePacket(presetID), notifyOthers); + } + + default void forcePlayerCapeCustom(byte[] texture32x32, boolean notifyOthers) { + forcePlayerCape(SkinPacketHelper.writeCustomCapePacket(texture32x32), notifyOthers); + } + + void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported, boolean saveToDisk); + + default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit, boolean revokeQuerySupported, boolean saveToDisk) { + setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), revokeQuerySupported, saveToDisk); + } + + default void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported) { + setCookieData(cookieData, expiresAfterSec, revokeQuerySupported, true); + } + + default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit, boolean revokeQuerySupported) { + setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), revokeQuerySupported, true); + } + + default void setCookieData(byte[] cookieData, int expiresAfterSec) { + setCookieData(cookieData, expiresAfterSec, false, true); + } + + default void setCookieData(byte[] cookieData, int expiresAfter, TimeUnit expiresTimeUnit) { + setCookieData(cookieData, (int)expiresTimeUnit.toSeconds(expiresAfter), false, true); + } + + default void clearCookieData() { + setCookieData(null, 0, false, false); + } + + void setFNAWSkinsEnabled(boolean enabled, boolean force); + + void setFNAWSkinsEnabled(boolean enabled); + + void resetForcedMulti(boolean resetSkin, boolean resetCape, boolean resetFNAWForce, boolean notifyOtherPlayers); + + void resetForcedSkin(boolean notifyOtherPlayers); + + void resetForcedCape(boolean notifyOtherPlayers); + + void resetForcedFNAW(); + + boolean notifSupported(); + + void notifIconRegister(Map iconsToRegister); + + void notifIconRegister(UUID iconUUID, PacketImageData imageData); + + void notifIconRelease(Collection iconsToRelease); + + void notifIconRelease(UUID iconUUID); + + void notifBadgeShow(CPacketRPCNotifBadgeShow packet); + + default void notifBadgeShow(NotificationBadgeBuilder packet) { + notifBadgeShow(packet.buildPacket()); + } + + void notifBadgeHide(UUID badgeUUID); + + void setMeta(String key, T value); + + T getMeta(String key); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ImageDataLoader.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ImageDataLoader.java new file mode 100644 index 0000000..44bcb32 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/ImageDataLoader.java @@ -0,0 +1,96 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.imageio.ImageIO; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.SkinPacketHelper; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ImageDataLoader { + + public static PacketImageData loadPacketImageData(File img) throws IOException { + return loadPacketImageData(ImageIO.read(img), 255, 255); + } + + public static PacketImageData loadPacketImageData(File img, int maxWidth, int maxHeight) throws IOException { + return loadPacketImageData(ImageIO.read(img), maxWidth, maxHeight); + } + + public static PacketImageData loadPacketImageData(BufferedImage img) { + return loadPacketImageData(img, 255, 255); + } + + public static PacketImageData loadPacketImageData(BufferedImage img, int maxWidth, int maxHeight) { + int w = img.getWidth(); + int h = img.getHeight(); + if(w > maxWidth || h > maxHeight) { + float aspectRatio = (float)w / (float)h; + int nw, nh; + if(aspectRatio >= 1.0f) { + nw = (int)(maxWidth / aspectRatio); + nh = maxHeight; + }else { + nw = maxWidth; + nh = (int)(maxHeight * aspectRatio); + } + BufferedImage resized = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = (Graphics2D) resized.getGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g.setBackground(new Color(0, true)); + g.clearRect(0, 0, nw, nh); + g.drawImage(img, 0, 0, nw, nh, 0, 0, w, h, null); + g.dispose(); + img = resized; + } + int[] pixels = new int[w * h]; + img.getRGB(0, 0, w, h, pixels, 0, w); + return new PacketImageData(w, h, pixels); + } + + public static byte[] loadCustomSkin(File texture64x64) throws IOException { + return SkinPacketHelper.loadCustomSkin(texture64x64); + } + + public static byte[] loadCustomSkin(InputStream texture64x64) throws IOException { + return SkinPacketHelper.loadCustomSkin(texture64x64); + } + + public static byte[] loadCustomSkin(BufferedImage texture64x64) { + return SkinPacketHelper.loadCustomSkin(texture64x64); + } + + public static byte[] loadCustomCape(File textureNx64) throws IOException { + return SkinPacketHelper.loadCustomCape(textureNx64); + } + + public static byte[] loadCustomCape(InputStream textureNx64) throws IOException { + return SkinPacketHelper.loadCustomCape(textureNx64); + } + + public static byte[] loadCustomCape(BufferedImage textureNx64) { + return SkinPacketHelper.loadCustomCape(textureNx64); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventToggledVoice.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventToggledVoice.java new file mode 100644 index 0000000..dacb14f --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventToggledVoice.java @@ -0,0 +1,39 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EventToggledVoice implements IEaglerRPCEvent { + + public static enum VoiceState { + SERVER_DISABLE, DISABLED, ENABLED; + } + + public final VoiceState oldVoiceState; + public final VoiceState newVoiceState; + + public EventToggledVoice(VoiceState oldVoiceState, VoiceState newVoiceState) { + this.oldVoiceState = oldVoiceState; + this.newVoiceState = newVoiceState; + } + + @Override + public EnumSubscribeEvents getType() { + return EnumSubscribeEvents.EVENT_TOGGLE_VOICE; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewMessage.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewMessage.java new file mode 100644 index 0000000..5558023 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewMessage.java @@ -0,0 +1,59 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event; + +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EventWebViewMessage implements IEaglerRPCEvent { + + public static enum MessageType { + STRING, BINARY; + } + + public final String channelName; + public final MessageType messageType; + protected final byte[] messageContent; + protected String asString = null; + + public EventWebViewMessage(String channelName, MessageType messageType, byte[] messageContent) { + this.channelName = channelName; + this.messageType = messageType; + this.messageContent = messageContent; + } + + public String getContentStr() { + if(messageType == MessageType.STRING) { + if(asString == null) { + asString = new String(messageContent, StandardCharsets.UTF_8); + } + return asString; + }else { + return null; + } + } + + public byte[] getContentBytes() { + return messageType == MessageType.BINARY ? messageContent : null; + } + + @Override + public EnumSubscribeEvents getType() { + return EnumSubscribeEvents.EVENT_WEBVIEW_MESSAGE; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewOpenClose.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewOpenClose.java new file mode 100644 index 0000000..c9419b3 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/EventWebViewOpenClose.java @@ -0,0 +1,35 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EventWebViewOpenClose implements IEaglerRPCEvent { + + public final String channelName; + public final boolean opened; + + public EventWebViewOpenClose(String channelName, boolean opened) { + this.channelName = channelName; + this.opened = opened; + } + + @Override + public EnumSubscribeEvents getType() { + return EnumSubscribeEvents.EVENT_WEBVIEW_OPEN_CLOSE; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/IEaglerRPCEvent.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/IEaglerRPCEvent.java new file mode 100644 index 0000000..b3977fa --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/event/IEaglerRPCEvent.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerRPCEvent { + + EnumSubscribeEvents getType(); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCResponseException.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCResponseException.java new file mode 100644 index 0000000..69d5e34 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCResponseException.java @@ -0,0 +1,37 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerRPCResponseException extends EaglerRPCException { + + public EaglerRPCResponseException() { + } + + public EaglerRPCResponseException(String message, Throwable cause) { + super(message, cause); + } + + public EaglerRPCResponseException(String message) { + super(message); + } + + public EaglerRPCResponseException(Throwable cause) { + super(cause); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCTimeoutException.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCTimeoutException.java new file mode 100644 index 0000000..164831c --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/EaglerRPCTimeoutException.java @@ -0,0 +1,29 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerRPCTimeoutException extends EaglerRPCException { + + public EaglerRPCTimeoutException() { + } + + public EaglerRPCTimeoutException(String message) { + super(message); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/IEaglerRPCResponse.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/IEaglerRPCResponse.java new file mode 100644 index 0000000..2da386d --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/IEaglerRPCResponse.java @@ -0,0 +1,26 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface IEaglerRPCResponse { + + IEaglerXBukkitAPI getSource(); + + int getRequestID(); + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseBytes.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseBytes.java new file mode 100644 index 0000000..093da63 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseBytes.java @@ -0,0 +1,42 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseBytes implements IEaglerRPCResponse { + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final byte[] bytes; + + public ResponseBytes(IEaglerXBukkitAPI source, int requestID, byte[] bytes) { + this.source = source; + this.requestID = requestID; + this.bytes = bytes; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseCookie.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseCookie.java new file mode 100644 index 0000000..357cdb2 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseCookie.java @@ -0,0 +1,44 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseCookie implements IEaglerRPCResponse { + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final boolean cookieEnabled; + public final byte[] cookieBytes; + + public ResponseCookie(IEaglerXBukkitAPI source, int requestID, boolean cookieEnabled, byte[] cookieBytes) { + this.source = source; + this.requestID = requestID; + this.cookieEnabled = cookieEnabled; + this.cookieBytes = cookieBytes; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseString.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseString.java new file mode 100644 index 0000000..2d1c4e0 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseString.java @@ -0,0 +1,42 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseString implements IEaglerRPCResponse { + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final String string; + + public ResponseString(IEaglerXBukkitAPI source, int requestID, String string) { + this.source = source; + this.requestID = requestID; + this.string = string; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseUUID.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseUUID.java new file mode 100644 index 0000000..811f666 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseUUID.java @@ -0,0 +1,44 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseUUID implements IEaglerRPCResponse { + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final UUID uuid; + + public ResponseUUID(IEaglerXBukkitAPI source, int requestID, UUID uuid) { + this.source = source; + this.requestID = requestID; + this.uuid = uuid; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseVoiceStatus.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseVoiceStatus.java new file mode 100644 index 0000000..da3013c --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseVoiceStatus.java @@ -0,0 +1,46 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseVoiceStatus implements IEaglerRPCResponse { + + public static enum VoiceState { + SERVER_DISABLE, DISABLED, ENABLED; + } + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final VoiceState voiceState; + + public ResponseVoiceStatus(IEaglerXBukkitAPI source, int requestID, VoiceState voiceState) { + this.source = source; + this.requestID = requestID; + this.voiceState = voiceState; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseWebViewStatus.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseWebViewStatus.java new file mode 100644 index 0000000..e2508d3 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/api/response/ResponseWebViewStatus.java @@ -0,0 +1,48 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ResponseWebViewStatus implements IEaglerRPCResponse { + + public static enum WebViewState { + NOT_SUPPORTED, SERVER_DISABLE, CHANNEL_CLOSED, CHANNEL_OPEN; + } + + protected final IEaglerXBukkitAPI source; + protected final int requestID; + public final WebViewState webviewState; + public final String channelName; + + public ResponseWebViewStatus(IEaglerXBukkitAPI source, int requestID, WebViewState webviewState, String channelName) { + this.source = source; + this.requestID = requestID; + this.webviewState = webviewState; + this.channelName = channelName; + } + + @Override + public IEaglerXBukkitAPI getSource() { + return source; + } + + @Override + public int getRequestID() { + return requestID; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerRPCFutureImpl.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerRPCFutureImpl.java new file mode 100644 index 0000000..6590598 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerRPCFutureImpl.java @@ -0,0 +1,55 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import com.google.common.util.concurrent.AbstractFuture; + +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCFuture; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerRPCFutureImpl extends AbstractFuture implements IEaglerRPCFuture { + + private volatile long timeStart = -1l; + private volatile int timeoutAfter = -1; + + @Override + public void setExpiresMSFromNow(int millis) { + if(millis > 0) { + timeStart = System.nanoTime() / 1000000l; + timeoutAfter = millis; + }else { + timeStart = -1l; + timeoutAfter = -1; + } + } + + @Override + public boolean hasExpired() { + return (timeStart > 0l && timeoutAfter > 0) ? ((System.nanoTime() / 1000000l) - timeStart) > timeoutAfter : false; + } + + public boolean hasExpiredBetter(long now) { + return (timeStart > 0l && timeoutAfter > 0) ? (now - timeStart) > timeoutAfter : false; + } + + public void fireCompleteInternal(V value) { + this.set(value); + } + + public void fireExceptionInternal(Throwable value) { + this.setException(value); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerXBukkitImpl.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerXBukkitImpl.java new file mode 100644 index 0000000..6db93be --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/EaglerXBukkitImpl.java @@ -0,0 +1,788 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; + +import org.bukkit.entity.Player; + +import com.google.common.collect.ListMultimap; +import com.google.common.collect.MultimapBuilder.ListMultimapBuilder; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.*; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.*; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EnumSubscribeEvents; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCCloseHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCEventHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerRPCFuture; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.event.*; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.*; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class EaglerXBukkitImpl implements IEaglerXBukkitAPI { + + public static final int DEFAULT_TIMEOUT = 10000; + + public static EaglerRPCFutureImpl getAPI(Player player) { + if(player == null) { + throw new NullPointerException("Player cannot be null!"); + } + PlayerDataObj data = PlayerDataObj.getForPlayer(player); + if(data == null) { + throw new IllegalStateException("Player object is not ready yet for EaglerXBukkitAPI.createAPI()! (Try hooking PlayerJoinEvent instead of PlayerLoginEvent you hooker)"); + } + boolean sendHello; + synchronized(data) { + if(data.openFuture != null) { + return data.openFuture; + } + if(data.currentAPI != null) { + EaglerRPCFutureImpl completeImmedately = new EaglerRPCFutureImpl(); + completeImmedately.fireCompleteInternal(data.currentAPI); + return completeImmedately; + } + data.openFuture = new EaglerRPCFutureImpl(); + sendHello = data.hasRecievedReady; + } + if(sendHello) { + sendHelloPacket(player); + } + return data.openFuture; + } + + protected static void sendHelloPacket(Player player) { + player.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, HelloPacketFactory.BASE_HELLO_PACKET); + } + + protected static EaglerXBukkitImpl createFromHandshakeInternal(PlayerDataObj playerDataObj, SPacketRPCEnabledSuccess pkt) { + return new EaglerXBukkitImpl(playerDataObj, EaglerBackendRPCProtocol.getByID(pkt.selectedRPCProtocol), pkt.playerClientProtocol); + } + + protected final PlayerDataObj playerDataObj; + protected final Player playerObj; + protected final EaglerBackendRPCProtocol protocol; + protected final int gameProtocol; + protected boolean open; + protected final Map metadata = new ConcurrentHashMap<>(4); + protected final EaglerXBukkitAPIHandler packetHandler; + protected int subscribedEvents = 0; + protected final ListMultimap> eventHandlers = ListMultimapBuilder + .hashKeys().arrayListValues().build(); + protected final List closeHandlers = new ArrayList<>(4); + protected final Map> waitingRequests = new ConcurrentHashMap<>(); + protected int baseTimeout = DEFAULT_TIMEOUT; + protected final AtomicInteger requestIDGenerator = new AtomicInteger(); + private final ReentrantLock inputStreamLock = new ReentrantLock(); + private final ReentrantLock outputStreamLock = new ReentrantLock(); + private final ReusableByteArrayInputStream reusableInputStream = new ReusableByteArrayInputStream(); + private final ReusableByteArrayOutputStream reusableOutputStream = new ReusableByteArrayOutputStream(); + private final DataInputStream dataInputStream = new DataInputStream(reusableInputStream); + private final DataOutputStream dataOutputStream = new DataOutputStream(reusableOutputStream); + + protected EaglerXBukkitImpl(PlayerDataObj playerDataObj, EaglerBackendRPCProtocol protocol, int gameProtocol) { + this.playerDataObj = playerDataObj; + this.playerObj = playerDataObj.player; + this.protocol = protocol; + this.gameProtocol = gameProtocol; + this.open = true; + this.packetHandler = new EaglerXBukkitAPIHandler(); + } + + @Override + public EaglerBackendRPCProtocol getRPCProtocolVersion() { + return protocol; + } + + @Override + public int getEaglerProtocolVersion() { + return gameProtocol; + } + + @Override + public boolean isOpen() { + return open; + } + + @Override + public void closeAPI() { + if(open) { + try { + sendRPCPacket(new CPacketRPCDisabled()); + }finally { + fireAPIClosedEventInternal(); + } + } + } + + protected void fireAPIClosedEventInternal() { + if(!open) return; + open = false; + synchronized(closeHandlers) { + for(int i = 0, l = closeHandlers.size(); i < l; ++i) { + IEaglerRPCCloseHandler hd = closeHandlers.get(i); + try { + hd.handleEvent(this); + }catch(Throwable t) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, + "[" + playerObj.getName() + "] caught exception while firing close handler " + hd, t); + } + } + } + } + + protected void fireAPIPacketRecievedInternal(EaglerBackendRPCPacket ret) { + ret.handlePacket(packetHandler); + } + + protected void fireEventHandlers(T eventObj) { + EnumSubscribeEvents type = eventObj.getType(); + List> lst; + synchronized(eventHandlers) { + lst = eventHandlers.get(type); + } + for(int i = 0, l = lst.size(); i < l; ++i) { + IEaglerRPCEventHandler handler = (IEaglerRPCEventHandler) lst.get(i); + try { + handler.handleEvent(this, type, eventObj); + }catch(Throwable t) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, + "[" + playerObj.getName() + "] caught exception while processing event type " + + type + " using handler " + handler, t); + } + } + } + + protected class EaglerXBukkitAPIHandler implements EaglerBackendRPCHandler { + + public void handleServer(SPacketRPCResponseTypeNull packet) { + EaglerRPCFutureImpl future = waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(null); + } + } + + public void handleServer(SPacketRPCResponseTypeBytes packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseBytes(EaglerXBukkitImpl.this, packet.requestID, packet.response)); + } + } + + public void handleServer(SPacketRPCResponseTypeString packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseString(EaglerXBukkitImpl.this, packet.requestID, packet.response)); + } + } + + public void handleServer(SPacketRPCResponseTypeUUID packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseUUID(EaglerXBukkitImpl.this, packet.requestID, packet.uuid)); + } + } + + public void handleServer(SPacketRPCResponseTypeCookie packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseCookie(EaglerXBukkitImpl.this, packet.requestID, packet.cookiesEnabled, packet.cookieData)); + } + } + + public void handleServer(SPacketRPCResponseTypeVoiceStatus packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseVoiceStatus(EaglerXBukkitImpl.this, packet.requestID, translateVoiceState2(packet.voiceState))); + } + } + + public void handleServer(SPacketRPCResponseTypeWebViewStatus packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireCompleteInternal(new ResponseWebViewStatus(EaglerXBukkitImpl.this, packet.requestID, translateWebViewState(packet.webviewState), packet.channelName)); + } + } + + public void handleServer(SPacketRPCResponseTypeError packet) { + EaglerRPCFutureImpl future = (EaglerRPCFutureImpl)waitingRequests.remove(packet.requestID); + if(future != null) { + future.fireExceptionInternal(new EaglerRPCResponseException(packet.errorMessage)); + } + } + + public void handleServer(SPacketRPCEventWebViewOpenClose packet) { + if((subscribedEvents & EnumSubscribeEvents.EVENT_WEBVIEW_OPEN_CLOSE.bit) != 0) { + fireEventHandlers(new EventWebViewOpenClose(packet.channelName, packet.channelOpen)); + } + } + + public void handleServer(SPacketRPCEventWebViewMessage packet) { + if((subscribedEvents & EnumSubscribeEvents.EVENT_WEBVIEW_MESSAGE.bit) != 0) { + EventWebViewMessage.MessageType mt; + switch(packet.messageType) { + case SPacketRPCEventWebViewMessage.MESSAGE_TYPE_STRING: + mt = EventWebViewMessage.MessageType.STRING; + break; + case SPacketRPCEventWebViewMessage.MESSAGE_TYPE_BINARY: + mt = EventWebViewMessage.MessageType.BINARY; + break; + default: + return; + } + fireEventHandlers(new EventWebViewMessage(packet.channelName, mt, packet.messageContent)); + } + } + + public void handleServer(SPacketRPCEventToggledVoice packet) { + if((subscribedEvents & EnumSubscribeEvents.EVENT_TOGGLE_VOICE.bit) != 0) { + EventToggledVoice.VoiceState vsOld = translateVoiceState(packet.oldVoiceState); + EventToggledVoice.VoiceState vsNew = translateVoiceState(packet.newVoiceState); + if(vsOld == null || vsNew == null) { + return; + } + fireEventHandlers(new EventToggledVoice(vsOld, vsNew)); + } + } + + } + + private static EventToggledVoice.VoiceState translateVoiceState(int vs) { + switch(vs) { + case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_SERVER_DISABLE: + return EventToggledVoice.VoiceState.SERVER_DISABLE; + case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_DISABLED: + return EventToggledVoice.VoiceState.DISABLED; + case SPacketRPCResponseTypeVoiceStatus.VOICE_STATE_ENABLED: + return EventToggledVoice.VoiceState.ENABLED; + default: + return null; + } + } + + private static ResponseVoiceStatus.VoiceState translateVoiceState2(int vs) { + switch(vs) { + case SPacketRPCEventToggledVoice.VOICE_STATE_SERVER_DISABLE: + default: + return ResponseVoiceStatus.VoiceState.SERVER_DISABLE; + case SPacketRPCEventToggledVoice.VOICE_STATE_DISABLED: + return ResponseVoiceStatus.VoiceState.DISABLED; + case SPacketRPCEventToggledVoice.VOICE_STATE_ENABLED: + return ResponseVoiceStatus.VoiceState.ENABLED; + } + } + + private static ResponseWebViewStatus.WebViewState translateWebViewState(int vs) { + switch(vs) { + case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_NOT_SUPPORTED: + default: + return ResponseWebViewStatus.WebViewState.NOT_SUPPORTED; + case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_SERVER_DISABLE: + return ResponseWebViewStatus.WebViewState.SERVER_DISABLE; + case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_CHANNEL_CLOSED: + return ResponseWebViewStatus.WebViewState.CHANNEL_CLOSED; + case SPacketRPCResponseTypeWebViewStatus.WEBVIEW_STATE_CHANNEL_OPEN: + return ResponseWebViewStatus.WebViewState.CHANNEL_OPEN; + } + } + + @Override + public Player getPlayer() { + return playerObj; + } + + @Override + public void sendRPCPacket(EaglerBackendRPCPacket packet) { + if(!open) { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + "] Sent " + packet.getClass().getSimpleName() + " on a dead connection!"); + return; + } + if(packet == null) { + throw new NullPointerException("Packet cannot be null!"); + } + byte[] ret; + int len = packet.length() + 1; + if(outputStreamLock.tryLock()) { + try { + reusableOutputStream.feedBuffer(new byte[len > 0 ? len : 64]); + try { + protocol.writePacket(dataOutputStream, EaglerBackendRPCProtocol.CLIENT_TO_SERVER, packet); + }catch(IOException ex) { + throw new EaglerRPCException("Failed to serialize packet: " + packet.getClass().getSimpleName(), ex); + } + ret = reusableOutputStream.returnBuffer(); + }finally { + outputStreamLock.unlock(); + } + }else { + ReusableByteArrayOutputStream bao = new ReusableByteArrayOutputStream(); + bao.feedBuffer(new byte[len > 0 ? len : 64]); + try { + protocol.writePacket(new DataOutputStream(bao), EaglerBackendRPCProtocol.CLIENT_TO_SERVER, packet); + }catch(IOException ex) { + throw new EaglerRPCException("Failed to serialize packet: " + packet.getClass().getSimpleName(), ex); + } + ret = bao.returnBuffer(); + } + if(len > 0 && len != ret.length) { + EaglerXBukkitAPIPlugin.logger() + .warning("[" + playerObj.getName() + "] Packet type " + packet.getClass().getSimpleName() + + " was the wrong length after serialization: " + ret.length + " != " + len); + } + playerObj.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, ret); + } + + protected EaglerBackendRPCPacket decodePacket(byte[] data) throws IOException { + EaglerBackendRPCPacket ret; + if(inputStreamLock.tryLock()) { + try { + reusableInputStream.feedBuffer(data); + ret = protocol.readPacket(dataInputStream, EaglerBackendRPCProtocol.SERVER_TO_CLIENT); + }finally { + inputStreamLock.unlock(); + } + }else { + ReusableByteArrayInputStream bai = new ReusableByteArrayInputStream(); + bai.feedBuffer(data); + ret = protocol.readPacket(new DataInputStream(bai), EaglerBackendRPCProtocol.SERVER_TO_CLIENT); + } + return ret; + } + + @Override + public void subscribeEvents(int events) { + int newEvents = subscribedEvents | events; + if(newEvents != subscribedEvents) { + sendRPCPacket(new CPacketRPCSubscribeEvents(newEvents)); + subscribedEvents = events; + } + } + + @Override + public void unsubscribeEvents(int events) { + int newEvents = subscribedEvents & ~events; + if(newEvents != subscribedEvents) { + sendRPCPacket(new CPacketRPCSubscribeEvents(newEvents)); + subscribedEvents = events; + } + } + + @Override + public void unsubscribeAllEvents() { + if(subscribedEvents != 0) { + sendRPCPacket(new CPacketRPCSubscribeEvents(0)); + subscribedEvents = 0; + } + } + + @Override + public int getSubscribedEventsBits() { + return subscribedEvents; + } + + @Override + public void addEventListener(EnumSubscribeEvents eventType, + IEaglerRPCEventHandler handler) { + synchronized(eventHandlers) { + eventHandlers.put(eventType, handler); + } + } + + @Override + public void removeEventListener(EnumSubscribeEvents eventType, + IEaglerRPCEventHandler handler) { + synchronized(eventHandlers) { + eventHandlers.remove(eventType, handler); + } + } + + @Override + public void removeEventListeners(EnumSubscribeEvents eventType) { + synchronized(eventHandlers) { + eventHandlers.removeAll(eventType); + } + } + + @Override + public void addCloseListener(IEaglerRPCCloseHandler handler) { + synchronized(closeHandlers) { + closeHandlers.add(handler); + } + } + + @Override + public void removeCloseListener(IEaglerRPCCloseHandler handler) { + synchronized(closeHandlers) { + closeHandlers.remove(handler); + } + } + + @Override + public void removeCloseListeners() { + synchronized(closeHandlers) { + closeHandlers.clear(); + } + } + + @Override + public boolean redirectPlayerSupported() { + return gameProtocol >= 4; + } + + @Override + public void redirectPlayerToWebSocket(String webSocketURI) { + if(gameProtocol >= 4) { + if(webSocketURI == null) { + throw new NullPointerException("URI cannot be null!"); + } + sendRPCPacket(new CPacketRPCRedirectPlayer(webSocketURI)); + }else { + EaglerXBukkitAPIPlugin.logger() + .warning("[" + playerObj.getName() + "] some plugin tried to redirect player to \"" + webSocketURI + + "\" but that player's client does not support websocket redirects!"); + } + } + + @Override + public void setBaseRequestTimeout(int seconds) { + baseTimeout = seconds * 1000; + } + + protected IEaglerRPCFuture requestSendHelper(int type) { + EaglerRPCFutureImpl ret = new EaglerRPCFutureImpl(); + ret.setExpiresMSFromNow(baseTimeout); + int rqid = requestIDGenerator.incrementAndGet(); + sendRPCPacket(new CPacketRPCRequestPlayerInfo(rqid, type)); + waitingRequests.put(rqid, ret); + return ret; + } + + @Override + public IEaglerRPCFuture requestPlayerProfileUUID() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_REAL_UUID); + } + + @Override + public IEaglerRPCFuture requestPlayerRealIP() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_REAL_IP); + } + + @Override + public IEaglerRPCFuture requestPlayerOrigin() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_ORIGIN); + } + + @Override + public IEaglerRPCFuture requestPlayerUserAgent() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_USER_AGENT); + } + + @Override + public IEaglerRPCFuture requestPlayerSkinData() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_SKIN_DATA); + } + + @Override + public IEaglerRPCFuture requestPlayerCapeData() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CAPE_DATA); + } + + @Override + public IEaglerRPCFuture requestPlayerCookieData() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_COOKIE); + } + + @Override + public IEaglerRPCFuture requestPlayerClientBrandStr() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_STR); + } + + @Override + public IEaglerRPCFuture requestPlayerClientVersionStr() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_VERSION_STR); + } + + @Override + public IEaglerRPCFuture requestPlayerClientBrandAndVersionStr() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_VERSION_STR); + } + + @Override + public IEaglerRPCFuture requestPlayerClientBrandUUID() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_BRAND_UUID); + } + + @Override + public IEaglerRPCFuture requestPlayerVoiceStatus() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_VOICE_STATUS); + } + + @Override + public IEaglerRPCFuture requestPlayerWebViewStatus() { + return requestSendHelper(CPacketRPCRequestPlayerInfo.REQUEST_PLAYER_CLIENT_WEBVIEW_STATUS); + } + + protected void cleanupTimedOutRequests(long now) { + if(!waitingRequests.isEmpty()) { + List> expired = null; + Iterator> itr = waitingRequests.values().iterator(); + while(itr.hasNext()) { + EaglerRPCFutureImpl itm = itr.next(); + if(itm.hasExpiredBetter(now)) { + if(expired == null) { + expired = new ArrayList<>(4); + } + expired.add(itm); + try { + itr.remove(); + }catch(Throwable t) { + } + } + } + if(expired != null) { + for(int i = 0, l = expired.size(); i < l; ++i) { + try { + EaglerRPCFutureImpl itm = expired.get(i); + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + "] An RPC request timed out before it could be completed!"); + itm.fireExceptionInternal(new EaglerRPCTimeoutException("The request was not completed in time!")); + }catch(Throwable t) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + playerObj.getName() + "] An unhandled exception was thrown while firing request timeout signal!", t); + } + } + } + } + } + + @Override + public void sendRawCustomPayloadPacket(String channel, byte[] data) { + sendRPCPacket(new CPacketRPCSendRawMessage(channel, data)); + } + + @Override + public boolean pauseMenuCustomizationSupported() { + return gameProtocol >= 4; + } + + @Override + public void setPauseMenuCustomizationState(CPacketRPCSetPauseMenuCustom packet) { + if(gameProtocol >= 4) { + sendRPCPacket(packet); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to configure pause menu customization, but the player's client does not support that feature!"); + } + } + + @Override + public void sendWebViewMessageString(String channelName, String data) { + if(gameProtocol >= 4) { + if(channelName == null) { + throw new NullPointerException("Channel cannot be null!"); + } + if(data == null) { + throw new NullPointerException("Data cannot be null!"); + } + sendRPCPacket(new CPacketRPCSendWebViewMessage(channelName, + CPacketRPCSendWebViewMessage.MESSAGE_TYPE_STRING, data.getBytes(StandardCharsets.UTF_8))); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to send a webview channel message, but the player's client does not support that feature!"); + } + } + + @Override + public void sendWebViewMessageBytes(String channelName, byte[] data) { + if(gameProtocol >= 4) { + if(channelName == null) { + throw new NullPointerException("Channel cannot be null!"); + } + if(data == null) { + throw new NullPointerException("Data cannot be null!"); + } + sendRPCPacket(new CPacketRPCSendWebViewMessage(channelName, CPacketRPCSendWebViewMessage.MESSAGE_TYPE_BINARY, data)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to send a webview channel message, but the player's client does not support that feature!"); + } + } + + @Override + public void forcePlayerSkin(byte[] skinData, boolean notifyOthers) { + if(skinData == null) { + throw new NullPointerException("Skin data cannot be null!"); + } + if(skinData.length > 32720) { + throw new IllegalArgumentException("Skin data cannot be more than 32720 bytes!"); + } + sendRPCPacket(new CPacketRPCSetPlayerSkin(notifyOthers, skinData)); + } + + @Override + public void forcePlayerCape(byte[] capeData, boolean notifyOthers) { + if(capeData == null) { + throw new NullPointerException("Cape data cannot be null!"); + } + if(capeData.length > 32720) { + throw new IllegalArgumentException("Cape data cannot be more than 32720 bytes!"); + } + sendRPCPacket(new CPacketRPCSetPlayerCape(notifyOthers, capeData)); + } + + @Override + public void setCookieData(byte[] cookieData, int expiresAfterSec, boolean revokeQuerySupported, + boolean saveToDisk) { + if(gameProtocol >= 4) { + sendRPCPacket(new CPacketRPCSetPlayerCookie(revokeQuerySupported, saveToDisk, expiresAfterSec, cookieData)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to set a cookie, but the player's client does not support that feature!"); + } + } + + @Override + public void setFNAWSkinsEnabled(boolean enabled, boolean force) { + sendRPCPacket(new CPacketRPCSetPlayerFNAWEn(enabled, force)); + } + + @Override + public void setFNAWSkinsEnabled(boolean enabled) { + sendRPCPacket(new CPacketRPCSetPlayerFNAWEn(enabled, false)); + } + + @Override + public void resetForcedMulti(boolean resetSkin, boolean resetCape, boolean resetFNAWForce, boolean notifyOtherPlayers) { + sendRPCPacket(new CPacketRPCResetPlayerMulti(resetSkin, resetCape, resetFNAWForce, notifyOtherPlayers)); + } + + @Override + public void resetForcedSkin(boolean notifyOtherPlayers) { + sendRPCPacket(new CPacketRPCResetPlayerMulti(true, false, false, notifyOtherPlayers)); + } + + @Override + public void resetForcedCape(boolean notifyOtherPlayers) { + sendRPCPacket(new CPacketRPCResetPlayerMulti(false, true, false, notifyOtherPlayers)); + } + + @Override + public void resetForcedFNAW() { + sendRPCPacket(new CPacketRPCResetPlayerMulti(false, false, true, false)); + } + + @Override + public boolean notifSupported() { + return gameProtocol >= 4; + } + + @Override + public void notifIconRegister(Map iconsToRegister) { + if(gameProtocol >= 4) { + sendRPCPacket(new CPacketRPCNotifIconRegister(iconsToRegister)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to register notification icons, but the player's client does not support that feature!"); + } + } + + @Override + public void notifIconRegister(UUID iconUUID, PacketImageData imageData) { + if(gameProtocol >= 4) { + Map toReg = new HashMap<>(1); + toReg.put(iconUUID, imageData); + sendRPCPacket(new CPacketRPCNotifIconRegister(toReg)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to register notification icons, but the player's client does not support that feature!"); + } + } + + @Override + public void notifIconRelease(Collection iconsToRelease) { + if(gameProtocol >= 4) { + sendRPCPacket(new CPacketRPCNotifIconRelease(iconsToRelease)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to release notification icons, but the player's client does not support that feature!"); + } + } + + @Override + public void notifIconRelease(UUID iconUUID) { + if(gameProtocol >= 4) { + sendRPCPacket(new CPacketRPCNotifIconRelease(Arrays.asList(iconUUID))); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to release notification icons, but the player's client does not support that feature!"); + } + } + + @Override + public void notifBadgeShow(CPacketRPCNotifBadgeShow packet) { + if(gameProtocol >= 4) { + sendRPCPacket(packet); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to show notification badge, but the player's client does not support that feature!"); + } + } + + @Override + public void notifBadgeHide(UUID badgeUUID) { + if(gameProtocol >= 4) { + sendRPCPacket(new CPacketRPCNotifBadgeHide(badgeUUID)); + }else { + EaglerXBukkitAPIPlugin.logger().warning("[" + playerObj.getName() + + "] some plugin tried to hide notification badge, but the player's client does not support that feature!"); + } + } + + @Override + public void setMeta(String key, T value) { + if(key == null) { + throw new NullPointerException("Key cannot be null!"); + } + metadata.put(key, value); + } + + @Override + public T getMeta(String key) { + if(key == null) { + throw new NullPointerException("Key cannot be null!"); + } + return (T)metadata.get(key); + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/HelloPacketFactory.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/HelloPacketFactory.java new file mode 100644 index 0000000..7b5a608 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/HelloPacketFactory.java @@ -0,0 +1,41 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCEnabled; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class HelloPacketFactory { + + public static final byte[] BASE_HELLO_PACKET; + + static { + try { + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + DataOutputStream dao = new DataOutputStream(bao); + CPacketRPCEnabled pkt = new CPacketRPCEnabled(new int[] { EaglerBackendRPCProtocol.V1.vers }); + EaglerBackendRPCProtocol.INIT.writePacket(dao, EaglerBackendRPCProtocol.CLIENT_TO_SERVER, pkt); + BASE_HELLO_PACKET = bao.toByteArray(); + }catch(IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/PlayerDataObj.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/PlayerDataObj.java new file mode 100644 index 0000000..13b3c17 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/PlayerDataObj.java @@ -0,0 +1,196 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.entity.Player; +import org.bukkit.metadata.LazyMetadataValue; +import org.bukkit.metadata.MetadataValue; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.EaglerBackendRPCProtocol; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.SPacketRPCEnabledFailure; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.SPacketRPCEnabledSuccess; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCException; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.EaglerRPCInitException; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.IEaglerXBukkitAPI; +import net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.api.response.EaglerRPCTimeoutException; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class PlayerDataObj { + + public static final String METADATA_BASE = "EXRPC_PDataObj"; + + public final Player player; + + public volatile boolean hasRecievedReady = false; + public volatile boolean isSupported = true; + public volatile EaglerXBukkitImpl currentAPI = null; + + public volatile EaglerRPCFutureImpl openFuture = null; + + public static PlayerDataObj getForPlayer(Player player) { + List vigg = player.getMetadata(METADATA_BASE); + return !vigg.isEmpty() ? (PlayerDataObj)vigg.get(0).value() : null; + } + + public static void setupPlayer(Player player) { + player.setMetadata(METADATA_BASE, new LazyMetadataValue(EaglerXBukkitAPIPlugin.getEagler(), () -> new PlayerDataObj(player))); + } + + protected PlayerDataObj(Player player) { + this.player = player; + } + + public void firePluginReadyMsgRecieved() { + synchronized(this) { + if(!hasRecievedReady) { + hasRecievedReady = true; + if(openFuture != null) { + EaglerXBukkitImpl.sendHelloPacket(player); + } + } + } + } + + public void firePluginMsgRecievedInternal(byte[] data) { + EaglerXBukkitImpl apiObj = null; + synchronized(this) { + if(openFuture != null) { + try { + handleOpenResult(openFuture, data); + }finally { + openFuture = null; + } + }else if(currentAPI != null) { + apiObj = currentAPI; + } + } + if(apiObj != null) { + handleAPIMessage(apiObj, data); + } + } + + public void firePlayerQuitEventInternal() { + synchronized(this) { + if(openFuture != null) { + try { + openFuture.fireExceptionInternal(new EaglerRPCException("Player quit before the connection could be established!")); + }finally { + openFuture = null; + } + }else if(currentAPI != null) { + currentAPI.fireAPIClosedEventInternal(); + } + } + } + + private void handleOpenResult(EaglerRPCFutureImpl apiFuture, byte[] data) { + EaglerBackendRPCPacket ret; + try { + ByteArrayInputStream bis = new ByteArrayInputStream(data); + ret = EaglerBackendRPCProtocol.INIT.readPacket(new DataInputStream(bis), EaglerBackendRPCProtocol.SERVER_TO_CLIENT); + if(bis.available() > 0) { + throw new IOException("There were " + bis.available() + " bytes available after reading packet \"" + ret.getClass().getSimpleName() + "\"!"); + } + }catch(IOException ex) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] Could not parse incoming RPC packet from bungee/velocity server! (protocol: INIT)", ex); + apiFuture.fireExceptionInternal(ex); + return; + } + if(ret instanceof SPacketRPCEnabledSuccess) { + SPacketRPCEnabledSuccess pkt = (SPacketRPCEnabledSuccess)ret; + if(pkt.selectedRPCProtocol != EaglerBackendRPCProtocol.V1.vers) { + try { + // send raw CPacketRPCDisabled + player.sendPluginMessage(EaglerXBukkitAPIPlugin.getEagler(), EaglerBackendRPCProtocol.CHANNEL_NAME, new byte[] { 0x03 }); + }finally { + apiFuture.fireExceptionInternal(new EaglerRPCException("Server tried to select an unsupported protocol: " + pkt.selectedRPCProtocol)); + } + }else { + currentAPI = EaglerXBukkitImpl.createFromHandshakeInternal(this, pkt); + apiFuture.fireCompleteInternal(currentAPI); + } + }else if(ret instanceof SPacketRPCEnabledFailure) { + SPacketRPCEnabledFailure pkt = (SPacketRPCEnabledFailure)ret; + String msg = "Server responded with failure code: "; + switch(pkt.failureCode) { + case SPacketRPCEnabledFailure.FAILURE_CODE_NOT_ENABLED: + msg += "FAILURE_CODE_NOT_ENABLED"; + break; + case SPacketRPCEnabledFailure.FAILURE_CODE_NOT_EAGLER_PLAYER: + msg += "FAILURE_CODE_NOT_EAGLER_PLAYER"; + break; + case SPacketRPCEnabledFailure.FAILURE_CODE_OUTDATED_SERVER: + msg += "FAILURE_CODE_OUTDATED_SERVER"; + break; + case SPacketRPCEnabledFailure.FAILURE_CODE_OUTDATED_CLIENT: + msg += "FAILURE_CODE_OUTDATED_CLIENT"; + break; + case SPacketRPCEnabledFailure.FAILURE_CODE_INTERNAL_ERROR: + msg += "FAILURE_CODE_INTERNAL_ERROR"; + break; + default: + msg += pkt.failureCode; + break; + } + apiFuture.fireExceptionInternal(new EaglerRPCInitException(pkt.failureCode, msg)); + }else { + EaglerXBukkitAPIPlugin.logger().severe("[" + player.getName() + "] Unknown response type from bungee/velocity to API open request: " + ret.getClass().getSimpleName()); + } + } + + private void handleAPIMessage(EaglerXBukkitImpl apiObj, byte[] data) { + EaglerBackendRPCPacket ret; + try { + ret = apiObj.decodePacket(data); + }catch(IOException ex) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] Could not parse incoming RPC packet from bungee/velocity server! (protocol: " + apiObj.getRPCProtocolVersion() + ")", ex); + return; + } + apiObj.fireAPIPacketRecievedInternal(ret); + } + + public void fireCheckRequestTimeoutsInternal(long now) { + EaglerXBukkitImpl apiObj; + synchronized(this) { + if(openFuture != null) { + if(openFuture.hasExpiredBetter(now)) { + try { + EaglerXBukkitAPIPlugin.logger().warning("[" + player.getName() + "] An RPC open request timed out before it could be completed!"); + openFuture.fireExceptionInternal(new EaglerRPCTimeoutException("The request was not completed in time!")); + }catch(Throwable t) { + EaglerXBukkitAPIPlugin.logger().log(Level.SEVERE, "[" + player.getName() + "] An unhandled exception was thrown while firing request timeout signal!", t); + }finally { + openFuture = null; + } + } + return; + }else { + apiObj = currentAPI; + } + } + if(apiObj != null) { + apiObj.cleanupTimedOutRequests(now); + } + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayInputStream.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayInputStream.java new file mode 100644 index 0000000..543797f --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayInputStream.java @@ -0,0 +1,80 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ReusableByteArrayInputStream extends InputStream { + + private volatile byte[] currentBuffer = null; + private int idx = 0; + private int markIDX = 0; + + public void feedBuffer(byte[] b) { + currentBuffer = b; + idx = 0; + markIDX = 0; + } + + @Override + public int read() throws IOException { + if(currentBuffer.length <= idx) throw new IOException("ReusableByteArrayInputStream buffer underflow, no bytes remaining"); + return (int)currentBuffer[idx++] & 0xFF; + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + if(idx + len > currentBuffer.length) { + throw new IOException( + "ReusableByteArrayInputStream buffer underflow, tried to read " + len + " when there are only " + + (currentBuffer.length - idx) + " bytes remaining", + new ArrayIndexOutOfBoundsException(idx + len - 1)); + } + if(off + len > b.length) { + throw new ArrayIndexOutOfBoundsException(off + len - 1); + } + System.arraycopy(currentBuffer, idx, b, off, len); + idx += len; + return len; + } + + public void mark() { + markIDX = idx; + } + + public void reset() { + idx = markIDX; + } + + public int getReaderIndex() { + return idx; + } + + public int available() { + return Math.max(currentBuffer.length - idx, 0); + } + + public void setReaderIndex(int i) { + idx = i; + markIDX = idx; + } + + public boolean markSupported() { + return true; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayOutputStream.java b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayOutputStream.java new file mode 100644 index 0000000..cbafe88 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/bukkit_rpc_helper/impl/ReusableByteArrayOutputStream.java @@ -0,0 +1,81 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.impl; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class ReusableByteArrayOutputStream extends OutputStream { + + private volatile byte[] currentBuffer = null; + private int idx = 0; + private int originalSize = 0; + + public void feedBuffer(byte[] buf) { + currentBuffer = buf; + idx = 0; + originalSize = buf == null ? 0 : buf.length; + } + + public boolean hasGrown() { + return currentBuffer.length != originalSize; + } + + public byte[] returnBuffer() { + return currentBuffer.length == idx ? currentBuffer : Arrays.copyOf(currentBuffer, idx); + } + + private void growBuffer(int i) { + int ii = currentBuffer.length; + int iii = i - ii; + if(iii > 0) { + int j = ii + (ii >> 1); + while(j < i) { + j += (j >> 1); + } + byte[] n = new byte[j]; + System.arraycopy(currentBuffer, 0, n, 0, ii); + currentBuffer = n; + } + } + + public int getWriterIndex() { + return idx; + } + + public void setWriterIndex(int i) { + idx = i; + } + + @Override + public void write(int b) throws IOException { + if(idx >= currentBuffer.length) { + growBuffer(idx + 1); + } + currentBuffer[idx++] = (byte) b; + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + if(idx + len > currentBuffer.length) { + growBuffer(idx + len); + } + System.arraycopy(b, off, currentBuffer, idx, len); + idx += len; + } + +} diff --git a/gateway/EaglercraftXBukkitAPI/src/main/resources/plugin.yml b/gateway/EaglercraftXBukkitAPI/src/main/resources/plugin.yml new file mode 100644 index 0000000..58d06d1 --- /dev/null +++ b/gateway/EaglercraftXBukkitAPI/src/main/resources/plugin.yml @@ -0,0 +1,6 @@ +name: EaglercraftXBukkitAPI +version: 1.0.0 +main: net.lax1dude.eaglercraft.v1_8.plugin.bukkit_rpc_helper.EaglerXBukkitAPIPlugin +description: Official EaglercraftX API for Bukkit servers +author: lax1dude +api-version: 1.8 \ No newline at end of file