From b80656f58cf587bb6ea3f2e1f6d49ff17d2d3140 Mon Sep 17 00:00:00 2001 From: nuttylmao Date: Sun, 6 Jul 2025 07:17:10 +1000 Subject: [PATCH] Added basic TikFinity support --- horizontal-chat/script.js | 179 +++++++++++++++++- horizontal-chat/style.css | 4 + multichat-overlay/script.js | 24 +++ multistream-alerts/icons/platforms/kick.png | Bin 0 -> 1169 bytes multistream-alerts/icons/platforms/tiktok.png | Bin 0 -> 41499 bytes multistream-alerts/script.js | 172 ++++++++++++++++- multistream-alerts/style.css | 4 + 7 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 multistream-alerts/icons/platforms/kick.png create mode 100644 multistream-alerts/icons/platforms/tiktok.png diff --git a/horizontal-chat/script.js b/horizontal-chat/script.js index f05da84..145a3aa 100644 --- a/horizontal-chat/script.js +++ b/horizontal-chat/script.js @@ -310,6 +310,60 @@ function CustomCodeEvent(data) { +////////////////////// +// TIKFINITY CLIENT // +////////////////////// + +let tikfinityWebsocket = null; + +function tikfinityConnect() { + if (tikfinityWebsocket) return; // Already connected + + tikfinityWebsocket = new WebSocket("ws://localhost:21213/"); + + tikfinityWebsocket.onopen = function () { + console.log(`TikFinity successfully connected...`) + } + + tikfinityWebsocket.onclose = function () { + console.error(`TikFinity disconnected...`) + tikfinityWebsocket = null; + setTimeout(tikfinityConnect, 1000); // Schedule a reconnect attempt + } + + tikfinityWebsocket.onerror = function () { + console.error(`TikFinity failed for some reason...`) + tikfinityWebsocket = null; + setTimeout(tikfinityConnect, 1000); // Schedule a reconnect attempt + } + + tikfinityWebsocket.onmessage = function (response) { + let payload = JSON.parse(response.data); + + let event = payload.event; + let data = payload.data; + + console.debug('Event: ' + event); + + switch (event) { + case 'chat': + TikTokChat(data); + break; + case 'gift': + TikTokGift(data); + break; + case 'subscribe': + TikTokSubscribe(data); + break; + } + } +} + +// Try connect when window is loaded +window.addEventListener('load', tikfinityConnect); + + + ///////////////////// // HORIZONTAL CHAT // ///////////////////// @@ -1312,6 +1366,129 @@ function KickBan(data) { }); } +async function TikTokChat(data) { + // Don't post messages starting with "!" + if (data.comment.startsWith("!") && excludeCommands) + return; + + // Don't post messages from users from the ignore list + if (ignoreUserList.includes(data.comment.toLowerCase())) + return; + + // Get a reference to the template + const template = document.getElementById('messageTemplate'); + + // Create a new instance of the template + const instance = template.content.cloneNode(true); + + // Get divs + const userInfoDiv = instance.querySelector("#userInfo"); + const avatarDiv = instance.querySelector("#avatar"); + const timestampDiv = instance.querySelector("#timestamp"); + const platformDiv = instance.querySelector("#platform"); + const badgeListDiv = instance.querySelector("#badgeList"); + const pronounsDiv = instance.querySelector("#pronouns"); + const usernameDiv = instance.querySelector("#username"); + const messageDiv = instance.querySelector("#message"); + + // Set timestamp + if (showTimestamps) { + timestampDiv.classList.add("timestamp"); + timestampDiv.innerText = GetCurrentTimeFormatted(); + } + + // Set the username info + if (showUsername) { + usernameDiv.innerText = data.nickname; + usernameDiv.style.color = '#9e9e9e'; + } + + // Set the message data + let message = data.comment; + + // Set furry mode + if (furryMode) + message = TranslateToFurry(message); + + // Set message text + if (showMessage) { + messageDiv.innerText = message; + } + + // Render platform + if (showPlatform) { + const platformElements = ``; + platformDiv.innerHTML = platformElements; + } + + // Render badges + if (showBadges) { + badgeListDiv.innerHTML = ""; + + if (data.isModerator) { + const badge = new Image(); + badge.src = `icons/badges/youtube-moderator.svg`; + badge.style.filter = `invert(100%)`; + badge.style.opacity = 0.8; + badge.classList.add("badge"); + badgeListDiv.appendChild(badge); + } + + for (i in data.userBadges) { + if (data.userBadges[i].type == 'image') { + const badge = new Image(); + badge.src = data.userBadges[i].url; + badge.classList.add("badge"); + badgeListDiv.appendChild(badge); + } + } + } + + // Render avatars + if (showAvatar) { + const avatar = new Image(); + avatar.src = data.profilePictureUrl; + avatar.classList.add("avatar"); + avatarDiv.appendChild(avatar); + } + + // Hide the header if the same username sends a message twice in a row + const messageList = document.getElementById("messageList"); + if (groupConsecutiveMessages && messageList.children.length > 0) { + const lastPlatform = messageList.lastChild.dataset.platform; + const lastUserId = messageList.lastChild.dataset.userId; + if (lastPlatform == "tiktok" && lastUserId == data.userId) + userInfoDiv.style.display = "none"; + } + + AddMessageItem(instance, data.msgId, 'tiktok', data.userId); +} + +async function TikTokGift(data) { + if (data.giftType === 1 && !data.repeatEnd) { + // Streak in progress => show only temporary + console.debug(`${data.uniqueId} is sending gift ${data.giftName} x${data.repeatCount}`); + return; + } + + // Streak ended or non-streakable gift => process the gift with final repeat_count + console.debug(`${data.uniqueId} has sent gift ${data.giftName} x${data.repeatCount}`); + + const giftImg = ``; + + const message = `${data.nickname} sent ${giftImg}x${data.repeatCount}`; + + ShowAlert(message, 'tiktok'); +} + +async function TikTokSubscribe(data) { + let username = data.nickname; + + const message = `${username} subscribed on TikTok`; + + ShowAlert(message, 'tiktok'); +} + ////////////////////// @@ -1521,7 +1698,7 @@ function ShowAlert(message, background = null, duration = animationDuration) { const alertBoxContent = document.querySelector("#alertBoxContent"); // Set the message text - alertBoxContent.innerHTML = message; + alertBoxContent.innerHTML = message; // Set the background alertBoxDiv.classList.add(background); diff --git a/horizontal-chat/style.css b/horizontal-chat/style.css index 4891d2c..baf5c59 100644 --- a/horizontal-chat/style.css +++ b/horizontal-chat/style.css @@ -280,6 +280,10 @@ li { background: linear-gradient(#466edb, #1c56f5) !important; } +.tiktok { + background: linear-gradient(#262626, #000000) !important; +} + .blank { background: #adadad00 !important; } diff --git a/multichat-overlay/script.js b/multichat-overlay/script.js index f904a1d..e199ca1 100644 --- a/multichat-overlay/script.js +++ b/multichat-overlay/script.js @@ -1181,6 +1181,10 @@ function YouTubeMessage(data) { avatar.classList.add("avatar"); avatarDiv.appendChild(avatar); } + else + { + avatarDiv.style.display = 'none'; + } // Hide the header if the same username sends a message twice in a row @@ -2094,6 +2098,10 @@ async function KickChatMessage(data) { avatar.classList.add("avatar"); avatarDiv.appendChild(avatar); } + else + { + avatarDiv.style.display = 'none'; + } // Hide the header if the same username sends a message twice in a row // EXCEPT when the scroll direction is set to reverse (scrollDirection == 2) @@ -2501,6 +2509,22 @@ function TikTokChat(data) { avatar.classList.add("avatar"); avatarDiv.appendChild(avatar); } + else + { + avatarDiv.style.display = 'none'; + } + + // Hide the header if the same username sends a message twice in a row + // EXCEPT when the scroll direction is set to reverse (scrollDirection == 2) + const messageList = document.getElementById("messageList"); + if (groupConsecutiveMessages && messageList.children.length > 0 && scrollDirection != 2) { + const lastPlatform = messageList.lastChild.dataset.platform; + const lastUserId = messageList.lastChild.dataset.userId; + if (lastPlatform == "tiktok" && lastUserId == data.userId){ + userInfoDiv.style.display = "none"; + avatarDiv.innerHTML = ''; + } + } AddMessageItem(instance, data.msgId, 'tiktok', data.userId); } diff --git a/multistream-alerts/icons/platforms/kick.png b/multistream-alerts/icons/platforms/kick.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc9afaedddcf0f850be6412b56b69af9fd90ac2 GIT binary patch literal 1169 zcmeAS@N?(olHy`uVBq!ia0vp^zd)FS8A$FoTE!2f6p}rHd>I(3)EF2VS|IWbFBlj~ z4Hy_+B``2p&0t^1l+s{j)dD+417gZp(+x2vL||D{6yN!soZ z3j8V&@JYgYlMsgl6Q?XQrwlWfEHk?ZQ^bEM+nqxG?O4NVC7?E6JlZ&WMbuK zViRWKkYwVLV`dj+`v3pGoOMYb$QMc8?k*1hZpPdIa@b2eeO=jKvPpCBGfi@O+0Veh zwA|ChF{I+w+q*xDW(9~eeC(Fi>)?)Q$ylVAc}r)lTITFqU;o};^;dj@@tKtpFMjS5 zxA^B&qNW~W($;|nJZ20NqmyGe; zAIUd+E*1nR);>GS9JsLe)FoxAxjp6l!SJc+vg1ds@Amz;9hY78)DdPA*vc=nEPuO$afq&1t_P2W19|yaBh`Q)}f9)Ht>+|**oIaGh?CM{GEVuBQ zs|fc3P1#%bW%9d+uUz;07FApP{u9XgSMmPxFPqt_=InX1@6G^{!PrnIHUD zuTAya(Y{(d_G2ijGukfvTpao^wEkw@?dQMt0sT;QebToBz6-0SUF`bL8pwefNal^} zzHOL(OS!J``rnT`&Tjkt)0;W=V`1Ftp90&TE&koQ03MuR2EXU@W#2FU$l5R9`0;we zi+`VlkwYBhgTOBuyxiQ@s$V+ozkSMFAYELy@m@^Y?KRCI%zG7gZ~qcT!d zK$MO;Qqn*WHB=oTfFLMUitw(Jzn!kFJT?J3#f%~j?i}y(=tX!+N&VEw} zG(`J;*>yCeb+99Rwu|z7{#$Qw?=V-jE!x+|)kmhrhaDR0`}4NnemitMHZky)vuaAd zSLXKfe;)Yj05S1;#@5YA**OaPuW#l@bVf#`!`rU_SV2#aNWS(giDV^yW=r z=)ZTPB18JC%;I}T_hxZchpO51J~p9W9gWz?xowhhwQ$>wf^Ax<(ye#uMH_!sCaC4O zwWQ3M1@=2%wh}>&TQ}Ov;n(%hOSD#$k4=hOi{Mewv3aYy&$21!Wa-CJoW>>%mLrly znBN)6@8NT4;Q{_b9Ose0>_~{}E}ONFmZ6{QH1aU(qY4gX7e)1S-X(q*YNr`H8F?W* zdc%EW71831P~zan_VMdgL)@Pdln|*T%#CBkd1J+TlRMtzI)zX+ea~oZdsZ7I+>b>s ze6J*dY%e`Npfz>h{iUR~I6@D<`3%+hmY6>6nV5a9Dg`8-jB#6Ow`6G_Z!03|@fvD+ z%G`J&aV26Ll46dr>wvaOzqd3(tskdmbqsrp+p`8Pu$Ayg?@A{v%Z{g!?p`oSKxl*C zzM(p;01Ll5|B(!=`9KUOnq9Y!x0zFe5M#MXN*BMhJtLixt^+R%$C=SSG!8*MM@|G$ z{YEC+;|2n(Ba?b#E&{0wAI(iE1XYUe8yST3{!k6Lkk5KjVqhaLf}rA5o9d1dz4g8KLu-K6o7y^`^eNsB3oD?-F`=<2hcvle z))x_p_m-W-BNR5h#G1VS*MUAtiJbFUCW`i#k9F+`_n-_D5eljQLe%QzPhJ5YlFbFd zeD^Dx5ON{Pez@(B;VlJZ&ikf5?Y5@*K)jy(+q@@gG;{XtN(pq7^?mTx<$_yKn{mvq zA#^HeNLv(-V*EoUm>0RzB8X(%o>3TZaPBmOxZDv6zo&XIvGX28Vo>;|syf=#!Ht9^ zQ2)-J;)druQx5hO*~Miy6#N4K1s4BF)ZXLfXn_#vX^E*b zix&D1$RC(2YZv!}P`whN#xGgi-FB%1l0c>QbIKIa$X*5yre<=8JLVHqvEn@^jr|+` zlsyd~c<#N)&xqLmR1S}$77yHl+HE0ppncgsUcEqjy~pG2E0Jg3E}r2q$LIYZvGIth;_~`cHD)8qdu@# zR^R@)%N#F?u)n!Ra%bF=90{YfuJehg+sf_I_Tzijy3A57A^ z+^*^D|5ut?z~)4`i(t}h_%KOSS)aZOF}~%d9~lu7l=T&qn^);u$VQkr$Xb$5`<WLwx6E`EqqNDbExZNrjT=qXDZk7LyT+Vr5FfF5M; zk*?d#J6H)2mYzIvueZ@8A-&)qnU?Tx*=g1zcYVlWKwJKY+Az0)W4ojBs>2S~0876> zftZCc6zhWx+boV=Q${VX6GbSy$YtKZ*Ygkc#F&7SSzN6RV%gjSmioE$BZM~Sx=5Ex zH1~7|le6)`=;$s=Y=fQMOYjcTOIi9$UEO!x#3On}!AP&tanybNJd|6Msqf*}l0AJk z;@`io>1NM1_LzfOA5{494v8(2uj>?Wo(|Tbdm`g#;Co2z^cRJUs{uDQ$xUufs3{^> z-ul9Z;-hSR;+7~~3*`WDlCl@`(yY=EEDDZte^ZEGA5gJE+~=PI)^eP`GP3eGSoQY} zl)ZBfwQrt!3!1KgM`TFWVsSFkQ3yJ8bj)#F~( zrqWntNP$8?9qlAuj8BICe!@}34WKJu*Cz#yl0H)?mG+1L2pyQtV^BXEbf(JSN>-cT5 z7_ihNnbbmx*R zn>$?}LHr>FbQ|~oD0B|%d7z=Qdk;mF@kxqn$Kzl`e1rB)ur@;w#rW=zj6091)~Ffm zHrY~d0 zdKb|m6N>v>*7xRx{v(MeeM-$xbW6i9FlwK7pPYRz`K1@gp01s3!aSRFKQ*52kuTfY zKtQd-k7jMeQbAfqf}Tf}NusmdShgniW9>CD}cbMC|XwJ>T_iKEC#1|cH506TW zaOpocNBJgRVmQV?Ue@x$TY@rn9*tg=`lqjn=%YMxkBR^rN3S2Vn+Y5x6nM9S5^9-_ zak>#x-@x)6&mP-D(i^ z{Nht&IiK;V1Vdcv!==F#Rg7xv#}aLOf&81=Pk8G9ClxH{oWVVE{RhmmYV*t@X68W4^F`6=4 zvl365sZe)*vKlLM<_%@l22^YkrA`nH=;PVHfU{hAo0!>@!Gdw8=*Nz+5(R(g&Zx^$ z6ON61($M)0H75HWY*>XUnf(WimT{xt{Yn;}Khe{lKJ2yv3)!R0S3Ff4+Aic-a&an> zpN4@Hkk9lBeFN&Sa^n>}Tm{vdta-$F-OK1vz?}fQw^#&|+<%z0^_qb%sT&xXv-AYj zS``Z}%=wAoT&8MzJnUGQf=QFLKJ;*o64GeTui>}L*Nb`5I)l4%UrhEV?y(4eNJW~hIj6@50n5hs(RuG=!B2oN2g z(`xIU3!8g05GG!&HbrAaLCscLJl*XV)2Pqm;7Ubgn~{F#1Ll=v{1%R1gU3Hr%?JvMX5v z^-Md&el>$0PD$P^X?8E#)>2D}p4C68Rq@ zp4?LmgJ`NA8H_6%X$zY@IuNk0+*>odYxPD@?&ROS1@@5|DDl?>hg%mrTY#Fz%LJaL zp#<8Rno9R53f6-n);E$t!-l)_Tf*1O>&CLT3XnQ^@mRn<%cZF0ZN~D#;z?bor>;j_ z?@mRwj;53#a=0S+$fLsq%0V7I@x(+eiqsJgTLEQ_o4q{(HP@jBecu%Zek=z=-0+RR zPsv2K`r*Cm`crWhK+1?YG36S0f^U=e=0LY~z_ID@UNBkXejAUr*`HDN^`#}x_h21p zqspX5Vf&Fzo1A}aa59O@9p^9(maZdrBv&Ch=Z0AugRhY=3ubWc^%(b<5+0UcMVf3} zXAbZvVx5vrr7uGgVHmj`1j%?e|9$&JzG1gT~U4jc=VwLj}!+Lq<8xX z#o|iXRZNgw8@cTELrj}{8CQ`sb4q|nAL(VlA+hBs=I-_`rrt2jxslNuBVu8qdhg+l z_>jY~Un?Q2W~~0H`d^1*FKqsb_CV!2U0Q?Zu0Tz_>sxuo^Xf?N()j=jq6Y@2=gyn% zL4K=IY1^ar)cVdCC!_NKw}f}&aSUUtI*#ne4d54~^`Scn0l~+jzP4Nt zBX!L_#2gtis7D#;mB)TOKQSqboa-ZoA#FvaZ@gra6_+B%GhGo)Gcd2DY8n!Pd!8Pf zy?A0&77g^Qm;K-f;*bnOHmCO(;27$X>=?Uu##l|iky@X$JvkGX^Z&I#Ho;g3kPJ^5 zJLhz+C=F{sA$wxKIf3CA_IdQG-V-g;n@)U@s4kk-<#e9Gv@X0~X!m5J*vUN9sAcFT zGK`@kSMAHwvpLp#)jm%dIdk(nPeY;JZ-+oetnjWe>P#FCjlz6{G{K%+LX9=htm2*> z-hs8PyX})&b@bEKQ%N^*gGs~B1Ta3A* zC;pMIW)8aoTYGuKTF%ovu^h&=y^-nPIuBu-v%?E_ZS)&cbXyyXGO~75q(hf&v) zcvB42Xf(jT(`ks%)|ox)N}^5k$7)Q(8dGr}M0jt) z#Sp{iCJj0xa_CLesCy*f(&TbPg$~Y+URR1I9fW+E2ls*A zicT1O$Nz=(82MUqDf&9B`0`y-n=$kP)Xn3}l%_3cOZ`V)`wR{-{H9Y;_Dv%37qqvg zJE0T$w(;h7qNL1>j6?Y9dfCsJ(0jwg(l=x>YP76Oqru1gwdm2Ibs=AHNE8MkqOSa#9Z0Wdw7)+|9A!TwuSVzJ5S)kd zuYL?ZfkM2CM@mJ|8=m%RG_I#Q^JY8J>s{?c5im?POPCv9ifY|5PAFiAX5Ve01UllY z`^vipq>yd!Wz(OQWj|cuVP%T1RwdNsU}dJd??p_PeFZ!Qsa|%1E`yD}Rz^>J#-p$P%GT&j#{**NKS+D?@MJ3# z6|`8PvsPD9)+4iw=T3G4GACr>UH30XuA|Zq!58tU+FK#1g|!SR9*BCVCM?kFeHM?e zKIJ&`8phS5pS(LiTB5zuoWBC_)wRtm^<~heL>wvY8;;0LMB1j|p{4?flU=)fPFkX! zCCkmd!B3Xib%-J@r*!(!pV9lx#-TfK=;S&GJ`H_yLXILj_|-_DMeaXQM@>RBBt(BqevP2=gZ^xt% zp`h@@3Mis^;;AWLlC2-eBC}+bhZ|vp)~y#s565n)iBV$;b520l3=XxnGgY=_Ia2*T zXD;xk9KD`r50+5J30(tXu&iQbfUC~=a_daXGE_T_RZ;JiM$~tnOz{V6P>s9dLr8ab zOucwaUj=#EeDuSE(6v-l{EASnLqo2+DD}iZ=H$_>D7x-BX7y8K$JMC(?WO2kfX7Ir z{1lACY$FvEl7|cRSc@m!pVh{pZAr#3iTaowJO4JUR-F2h@IqY>l#SBLBNLV@Pz9yv z9ds4R>G4^hbH$3Fu}|a1MriOIQSms8EPqeComYmCe>T|s9`~WbNg3FF`g^uT082NeuNuI^n6`Wr6Rzo--ILiM+{KC&1ePpUZ<;*J5N* z>;yU?0A9M8Fzf@KwatIDRS?jDjF-C4zTvAk$^M%J^~Y;GQdgm5-?P$QMW|7Ec%&3; zXE2bCTtZ_%XRA-fE<Wx+shHOFh-?r$gx4&4A_*2ATC zfRuXEkT|Z`5J_^VlAw}AgngkX)c}uF`42-~+zrcEItxQJ0CF=Vp=j((h700WchVeZy&k8;I zb>?o=q$stbbw>1OSnlE_gWiufg}P3PBG3=@k?il*OQ6i4t(_C-(Y^2@DB7!Bn7;}g z_nEQkn?`3Jkzkyu9oe8lO>%mr_`U@?Q|SV5qz$YiAn4~0#ZL84^^p(#+i`KkaP{@Y zQ=1tZL2p4M4w>2;yZzYJ7X`(^e+&XCZiKCCJ zW=hu0<}XJxt@4P++W(|9x7pYSc&! z(u0;`TqlTti9+ZR!5W5MFJI5T6{lX~v6}#hWTJ2QGksEp4^7|591W(Z9DsIq)8Ds| zs7c;TvrI+Q`Kt${mCe!sPRVgayr(aEzpXh}5|KPcK-6{bA3b^3nZ?76z zoJ-HC(5sQ&BGpdoV6-lT?uxNwVu+0%omR1v0r3qQM3K7T)`1`=^uDz>i?A9nBokIVry+6@Gjm<24zCg z`xFNTY?zg<7_9eX-Q^t*(ZFpfvg*(YNf5|)-a8=(7pc&Plcot z1zsl7TtunTrC$Da=zU8XlvLa+2VYY+e0T?69Y%A5RKE1G1$1-TTfNU)p;V6pP*BUZ z!q_>KJl%pqAd*lAS#dQAJcMMDdCA~UWjjTo%eK#-ZJs&45f$6m9KfSSM}xYf$|%=r z*r$08J-WOB6gh|~Qoa9S=ZTGoe`*z?4vnn?I=fJ6;!Ze%{QN=Qag^Jw<^+!nd|0=VG73C}`skcoaYS<6xfAlplaF^aJ@m!71WliW z@ucPvxmXupeSMt6E?$DFUIJN?iNs2myTv~NiR|(U81qr)N;DmYp%LRon$UsTzK>^L z&aze@LbDGMGVl67!E+za@t%zfb&+F}d2ayf;v{H8!gZd(Q>CR*g>IV{jOu9@2uygV zt7>Y$9+BPRTA3WJ5u>%N%f6lFGuwL#jnut_P5Z> z0D{{n)S<0|v`=RP5ME0I<7#hm-2shUTQ?nvMvo#s6`W#;RBMFeP-Ax5h&0%yj=W<9 zO1FbFwq`s?(Qb(n2xeQki`M|dhhffL93$AEU>)c;Sf>ZU6>6~WVe%5HRI?9sxN^K{ z9{3Hb*<8Lz1BHk}Q>o$0pl~JU)H-AWwxeEonyF=vYu$jzrn3_{tQiuGyHq43XB31+IVzyk5ne4)x&*WQJdfsMmMybOrH!$;k8QBufQ$gL_=(=hD_QI#nu+(06Q|Y#BjKQ4e2z;3}HifZi5CaNiA$ z!uszR$U~|KKqP}7@j?Q9!nj?ZeCy*X${4Cy4i9S{Zg<`f8$#oJEVMtnoa%HJC83b* zNRq961N6Rk(_LQ~oj1_sXo;h)c^CjrUJkgvifZJ|glrk1Cy)H0f4B7zQ1<%w#>OQQ zZ+Ib?JEf(jP0Hc2wIEkTwu-85msTO1l4~9g_O7PG*C^RK=Ts=5nv)`k+VmyUF&e#T z?n@D=_VmUgM(eMKtEi{MsrRCbAb0Lb&sYJJ?i@N3rh}rt(zd}Y`sFv8mnb80+O6&e z&Lt7zC;MvUR87;7N9c*}^eglM^X)e^g9?724d&YyreCf2M=U$xkU(g{PG=C>@Qx|; z;Z(U+eSZVIt=14!WMoyw9RpeFn~c$HCv;|_z$EBL^E!63}ijBzU*hvM0RXSB#+-i&63Ba3M9`|4C4@^D(bOf^-hY zpsxiYEomd1+%sZ~EgaJ(m@A>Lr(OoYycf4^4~*lGwV!Fu0Cg2A!v4As)m`jjnJ_Qe z{~A&-NT;T~48Tfam^)RE==Vkunj}d}+p%`)1(w{2tpwY>=<7-nEKFY95O8S~^)m%S z?KuBC49BDvB4&5>=EUa0SXr!VLi-K3tanS5rK$<4o%;1l#=ti_QquU~EfoN!n)xLT z`uL+KZf-OH=Ett}*emIz5prSV^1y8`4F(U7byI8*v1o55d=f-VNTKrwwAc8Rd z*_Rzh)+!4t3_nu9f(z)4T+sB_6B=vEc`rSaMix}w<~W~0hut9zI@{8g06W-tz`8v~ z;E|C8NrH$H{3i9^>)j*kDMo_d)FuvdNx#R!Z{L*VP46VBP>$}l>3G~vSy1$;$HB>0 z`btntnv!O(j}elu4CYfTgjkYkR{eyOpgC!SLYCG(M1`NIC)|UJ^*fkZ68%7J z^5SnN&3c!`-vbU=$Jh&S$d(v=TKs)J!1}Gh0vsycpMBgGAc*0vrMWKrma4ZYfE_iV znatOdFE0L8zt3+zql*o&0A?)bX;a$*XvW)8-2PYu?Ls~$WKoO?2YSpR>&GRnwRpTh zY=6ehC87d2E;~(~Iym;2N(Gwet~Yb()bN=80tab!l3mLJhxDZMg1;9y7#f`D&0Dm4 zRR+yw=I{ogv8{;)>&cHc2}Pg0;*hSt=n~_jEFbShUF&XAQWtenz2C!zT{dBR@$OP9 zy#;g(m|BI4C>WZUv+p-IuM|k>?#+B$qIX9UCv-Mn$`LYc!P!0qxW_J{JIx;@s>8mZ zu+~$4uU+k;E?LgRWedKsC6VnC7JZV(t#2&IL&vW_a6Teny-#nP5SM2k_p@4k=o0*_%k%6Z0)$ zn7e`4`bvNdso%1Dv}6-OO4zQ{I^Y7Ay?3EqB=Ib1uHm$RH+4j+p?7qYZLq-3fYm@b zq#}pMyo(VyIx?fdUb)aL&nA|cNi;IGUXW$gR77M_$rXXOZ0is!(Mut(UX;wwj~!fC zyeL^>1;zd#=j0J8CTL>biFMsJQ-N1#LMA>xC_Y2%rLum@FejoGNU^R>9au-!U#RWt z63cWX61*2{UkD)0#SN1mY$svF_E-J(-uNm1Hd}9r5U!L}qX8EAoQQ?iem5Lay$ih4 ztQKS@PMx09+T%eLwq_O|H=|d%pRP$?5XBu)C#;53UBdVF`l{VpQ-|N`2$}Q5_;s^phVHwj>N_ut=V9U*WQ=*g!onaT_oy1{1`%Yz)}0`2tF1=(`CvuAay8m`eiC51rcC9EE~ z?~uMk)@`9cYhQ8Q-%}oy=~Mmg(tsuM)w<93FWIh2zT%2g!fLrY*RkuCmTV91dBe7GzD&i+5`AJc>V6O1mclXoGrRL0l362#CT>3oR0^sUP3(4 zn>K5*B28HJs40O!7`?b9xTn-1eIOt_Iduuv|1yrQCg_N7DKR(fX>~}EAI&|4(Lnq4 zRYrBS>RqRf`EjjFh*1GHf)0fAx0w5YPv(|TjVcbOglK5Ik&4x}4OsSmv;CHR8@U{4 z!1A5CkfkSyg(Hb}#odpu`J;Cxz}~NcQ?lb}@AhUTtV!aTmfTW3F%!CZ&twUu-+8io z$tU59kmp5yZ!h$BnWmUmtr3|^uIg2^^Vy7f3$BC2p1dq{Q;#Ehj;`bEn2341%A&-oPRQa((2NlnOfFN%Qe8l+_!V)7eD|_N zlKDRLm!r=XNMiW>m}LuPzB@w+s{0ta@Z@eE-&}A|Q&*G>wM* zdfWZM&J%TQ?XV3754M#AU7~Z{uM5n+d{oHvrQ|FsdftG&E3|qcd9}|V5VktkjouSb z+1B=wXf)8Px|lI47Epp%9g9!9Y00ZceiJ5t%!#81nQ}y8Lz*yy^jX2Turu#8CtZ`|jFBZ5j#>7z8Q^=|oi3o6)igBa8&_VP1ccr{vKSdIYU~!xBYBPF<3m zN0OXs$-Q(*>tV_Llxg?9VIF7Gnzb%B6ZSPJTR2TCdo+5_*=Ml{2j=@rOe)9d>w2b4 z(mY1ovg!&$w>0$LGD%m(9&T$eUxxlOOL|&rD$f5z)SQ_)EC)m2HVb+*Gc}r9hcRM3 zx;t;A_p+(VV$NLByLrAP9%~eGMmpr%@CyE%N!-lnqZFyWpQ6}p0f%GjclCQnlEC5i zN6AFjzmI0B$)+EYO*%$UyF)176;)&{TihP_)n|@2GkO!6CeQt#m#E$hy>{{7*%PsK zONmCqb+)b;_%VMIbI8A{kO!NhHaN2t#V-_u9gpgWnhu=HDhoIo6?V$q5|GByK`@yvs3=$WR&E*{)ev4YUgjm&UHVg4h+@b3av{Q z@qAiasO`+LAAO$dDv&p4y#6yS^%^btZ(6E;L?0_>jO}H&BfVD!7UY#0_~}!_<(m|l z{2GjfQCn(m${AYP6J27?{dy(j=mpmacJqvC-PTu$i-7POd_7g%Pm$fc-m+vUMNL1g zMjM76I3zt8$yaFIMNh#i!HUz#s$6ucxAjCVQqGF)Mgh znAxclbd?DO`=-=|8_3^-XeQ*f^%+KMyX?+Tj+*@+$$CoU^P zA<4A4SplmsFwV84WpWDksgzk)tmdujTlS9MYQ=pWYA+@y0z5)q_p!NyY_7@~1IzVi z#Zlw2p}Mls*9vLDZnt$Hco>yoKVWA~>LKYxqOg*xn1&5M5_mDJt7r~8YnpEL=aX#QzuKP|n4mJnIfcN`XxIzDkDv}-+{maC@AW4s-{ z!(x_400IxwY^`6o4sYQ1`m89f|y*M8C=Pz z4ls#JpzIIgoaVKx@5LJGb9kF61Vj1o2T>NIl5pikgZrvvXAZwwA$cDkj7C*U#cqu_ z>Nc){T{iWOl!Q?_Z?kxaCKhFS`H?)cGWV2d!tURnnTvRu90>5u=bR%dT_vXxF&J(| z*9Fn&hU7=v)xNtMkX)xvn9&$}81!v(+lL-{^yk!SN8=w z(=xtsC{u=%UIM!nyTiyq6I^>;=9(qvL{T;z;@+oO|6wqzqVPbNoG4&p)Y~-Ak@Z~$ zvbLF~0sZ3*=>cc&r3-+b2B5z2qSn~v~(dT)e-aXo1tdFtZiMPt^~B*vYN72`fO`eO@y6f;()(h>hH4j3k5a?`r>i_ z+=ugzEr$NwyHiJEDO1kgL)c(rW0pXpC4L(5#ySpL^CKhu?Fkg!cm5Z_DIKSd8o+LBYV`Z=#I_+ANK(xfah%kNVcoWMn$+OL4m1dPZ0oVXTYlA zX}hvP{OSTJX4~lL_49$t_P~h3G!HnfX%#QYDq`2cML47W(=uQUC%w(X+(TduI8pYp z#NeIEJ~8*Odzu_v)>_ODU0+hHV%a1MMEY}M`1U1Z^Z_&GPMZ<`xSG z`mbNrha^M36^h=|l)@irYBo_qsHNn4m#QMG^$MJdNfnvL;kG6Y70tzvwn=|6Et0aMOTVZO=|C}=SgAv`3 zCQJWDi~DA$oO7>!ufTC)B6R(~UDZa7*EWW?{J`y_N3*_L)%|8w_dPfHTfhGnaBQxg zMlHW@j3C;J-Iq~Z9&EPEuk4%i5j?$9^Uwt&V~{`2$wH-eW*hQI1M z!Fe`jupTqG53RxNo-FJnk}tmN+#a{(PQm^fH!DlG5KFgTu6Vdvl0(E~C1Hqts6R>@ zJOk$@w#~E6oyX&zM-3F}iAUG{5zYPs{z|ewNOBt`_pNxj3A&Qc^c6jqH%`Hw)SAK) zt;rpeQAXP?r_AZ=SvXJkZnE=%0|AUye(!R-my&u)u(inuH%YD?F(fqhw1?vZADkaa zaOfLR#38KXWa?`yr+5cp_xAK)hlYCawX#3Qqu@I5!QMVOzm8lA-8$pqPCQ(vdOa1C zFSxQKRkHz+#J!lfDIZIjOV_cz6sYcbS!$%k$4?A??SEwc2&!rw8I*n<4=aM1c4c8(X&-~U!{yGRzGTL$6(rqhUM zD4%*!ZUk)0Z~|oXgI)Xt*8=pRi_U)heCpJMz6gdhsosD?q& zV!PttN@stJ#AMteL!6Uhzzd!bi1P!FqgH}===>)jM4J*S3&#cG$Jy7Wc3qJJ5xnYF zq3oDr0YPxr!wF8cB2acoS^|Y2P|iLU?ptZpHDD)(NqI0zU4NJ1?`Do^2_2NrlMFhI zOm+VXI53E z;E1ZDi@#TuXs4&+PCdtJLZoI~E7{_m4%|*^uE70<_emQN+y%g+MBmz3jXP|V2iRlE zt_?UFnYwF1P~N_&dwW8G!j2D2oLbIyI_ou=YJhDgVv_VF5Jq873tQBK&bczhagq0* zB|G8fPisA#0wBRa-P$+1Qy#m;0vDv+yu0rUF20b|r({UkiRURXn8%S|Io>xd2i6Q3 zmqWmyAc)kNHixWRi-H`SIxV(HqKq#N*MI`Ifn$Pdp4xEbcpAGzhLQK@PW5{O0U#Lv zCB+|h2pOvZM9f=W?$q!Q+<+8C+uDo+9ytFcFq`{~OJ%&uf*OMrQ#Q(^`y&88NM70z zK4OPO3n=(y8y0<3=*NsT=)n_;rBrwUkAZhAM)Vh6xrc`z9A*6^ki=QHw`F9Cm^O+&0Lk(*raBI19eeZDetBzbyz5Z`fVc?6$y& z!!GG}U-+GubVIjVvXO+jHiY5JnEJc2?qZ(Xq`NVN8=t3*{;<*((UZXf5qqv;bGaG| z@PDDeUV0-Hf*v!Nc$j~zF2JM&knwxg0Apy7=xfQ{XG0)e4iEw>{n#=x6}O-W?}J0? z>qVu8Bg_Xdj|aE#SzegAit#)YL{viP%UFK-OTe27+XiiF^X{VASoensBkj$PYQ`cD zUTu}nxS`v$@Oyw(NWg9gVoheOI$cDwB^SCG>(1m!m=+7TPy!w-z*g+V9UqL!mRWGo zyPZ>hH4E`3h-lG^+=%B3QpsnI!alc9jDbuFgayb4)|lY=_=;w0 zEU@0)nHDU&z`B`|w!qpzyZ0}ir0tnlfl7}KJF|=|;V0(wWrbCX@|`)TgI|Lk(;>kD z0vAuNwew;iZ|`EKEkM{NUT}34W90%Rg~E|@i-IR*q?j$@e5CRgZ0HMmpyE3P>8pgJ zk_61Rb5p=$gwTkLbm;wGW8|-5>=aV{s^-t!v?$-R3^Ev%1im)T4AyOzwA~`aFQh)o z4eoRZ&7Y&N=#WxeTK^fbZOKCXw(P5ngOf=@P30+z4qUwdpuW(D`YV%PTT)*Loq+UZ zLz-#Kg4Ft>i%~vz<6nDOH?eG-kg?Yn5nk(pP3+B87nP|P;f(2vyjci^C+B?(bQaw7 zZT+_e5$v&hA!MqYF#Z|IopjowaETe7LN%MBHbp3N$O|%u>()xx8e=0m^yLI^{+0!e z=WcwcB2+IppRtC$EY3^Vvr^?`6BYpuTuxvwy7X2!t>(oN*p`~sN7s@U+8}UV%Uf>2 z9P-^AmefS!2nLV z<;Hoy6CNGy48l%7Vn6Rz<(a!e9qNg5DSAu7>v5z;#ML+g4zYQSDyrs~KqS-#JsEV?AQagz1e%H&Q9_Qi+gNIm7a{4%P0%*7kr-u{*0b1n>VJ{i-fum=L_d#({=3hbI3od zxF1%zPhXGaWz>`y_Dl@g(B0XdW!`O5q8!|<6`FrwKFXYC98jx1ci~74IRLBg{>94L zSql!p!aQz6`Yuaq(8)ymk@WVguAWJ|Hzf1?tyA`M$vIBbFTKCOBA=c4fXAivQW$8F z$2rC^$oH$QU){ri1Ag_6N#DPj(cu#>TUNk51t@!k~Q$_%%&Wb#3>+o zEK$U7q$S(&V9l;*y*wttFN)(QwNL)JeuOo<^F&XLiQQNO<(wZUZz?QJcSoE1j8En! z7JSJEOa*=uuhOfejIFiNyZ20;nLCz4ACI5atYWQiBBZ;`_|S>{pYjB;dqL6KU%A@5 zJT86YjzfI9dPGf?^6_Vz47(F#GcpV9gTDQS`3zMpJ@rR4diZs(Cimt@vx(>R6qB@J zep!DKkw)*(XW_E5vIXd zt_<~L6N6_RU;N;=N3@E+!=l&ro#EF*mJG3t^|Dh9 zvm971fIPn?ozN+?)@A!n02xDj4%Z4TzGH_d)e2*a@8sV$mIA>Ejqlbu;ALN>}SRWHhgRb$5>t> zLS1ImBzm-U^^}!al82C(dcpn)13Y|vrHi>|WQ7F=YBf`1ud}l4pF*xM zR>zc*x+?px-qGKEK8(QSB|n(1sPSXq6uw%YAyLne2BP`FtWK>)1pS?Lf8?>xXF)YM z->T-`;o~i;#&1!F*G#=MO#Ei_1c{T=h`L5>-9XU}U@L$H;MI+f6CGjCL$t zmV+5zcATkhyTs9dMyE~&VY6kD2u%9c2K=!!`;W51sC+EhlzO!R9j%eui1zNzNRq;4 zL5*kIaU}P0$A`D^8|#fnHbAH4y&(KLxQvlp7nfSXT+} zux}kmv4GTX;;8BU#yb0e5=d|$#4cF6Rj%@MG4yC?$ELn=Y0Bv6i;MlNgAZOZ5see;g;k&K`#ix%9ALqr{Fv@L3B724veQOvrizsq z8sGi-^2zv{J#i);FbJrzTGmSWI?Ujy zR`mthkS86yKxk0IL>g`@Y;5o=c_FM3de6gDxskKZy%#=*BdB3jId2m@;}OL67wVMh z?Z3J)Z>T|fDpRNd#W(euB}2X=;S1%eu%z&dAHMW;CQow`L+|#OHZJCj&FV(qA&wxV zz%c4o+-XZjx=Gvy%2Qz*b+`}L(Q|7sqYF#xaHzCqqYA^`3l0ilX*H;KUI9L*RS_pLVj*;!cd}`D(WLeE@yY@D3tTuhipq_z zVmXG<0!urx_MoPggALm)5p-SD{1$U#xr>_P2@0o01uVSE{;FEl_w&=<9ig2<9xa`o z_|nD;JmL)@9FFr>+Uq3(Y4;1l=N2#xOLt3L)wlUZp|hW!&|Fs?tw<@M{*f+1sv80H zW0k2|Se_4>);?nE;T`{FmcyL~Oby4N{Wi*tONJUE&8AlfY7h{qH(WCuKK~#Hhu|~J zSWCw8a>I96&I1%0#-jD{nL~pSJRyb52vMcX;kOD{;s8K7Wx<6d`$W^xzl10lOL6&@ zj3Ybh+ZHVr&VeDO@o%$R!&m|W6w^geVE#bBZ5TCHVx79r&F;L==RycN?zvxD)%VLV zlMV?lgiA-md*5 z5+YPmFmCXrt(QS6jD+_1o0vNA_^Mcial|C^@<=Yo3(R%KSU$>)+haL-zyaZ?mO929 zOUCNs4uQSmsY+;}mzenFTTLYrtH zV}KGXY`n^sj5lJ(m#ZEC=fa@#OkUcj?a^Z?WUcJQ6|-bqHc46ps`*~Ouc%SoeacN? zdmSQN0{r$3dMMykO-`dq2RLMD!_X>$^wfe;qt0Av;et`T9F7z48~!yP!7^^Z_z=eW zA73KogV6XH8RY&3C%gn|tc1y4-qb~5&2#$huF8$L*vTKj2LN{ScKdCW=hJk`E#doH zzQ5v)s`nKBBcxPkf}>89nWbRP4yH<1MU9cFsh}SA0MQp|*n4;ZS^H*Xbmr+icCHQt zE{(Aw8F!=)V>1P)+Yz|B@gThcPGDmWilY{oCi@F%!pGqz$4!0}0v>3g+bL1>a`{w& zP?~SPaVpA<(p@Y^q4{f|Z~Zb#T#eZhT(LjDUP|~v?R~Xq(aTBY%zhMXgHc%t zwc1Q>QH0iOf!h+T{1+zJGy+~qV=ps2g#2Q4WPLBH$JY{OuqNyX@qBDvXwV_7S1lUUto*MXfeg&jGXU`6*-Z`gl15Pa}ZD95pG36yuvdm-MA-ZDm>G4cx< zzfr#vO%)QpYp-t_LsAa`j-c03Jw#%eCbS9ddQ7iXwCF`%D0k5arS?JsE#0fAMKuqF z&WQ){Fn}5v3OGhja<@=TDme2HM_GV3gh$g9c6l5aBzvI7fTs(x|9#?${Ka)M6>td$ zAWE|gOMks=2$Ks(y$%cHr#{_O5j=Rwoxz_Pd~Jd)EC5I|-+KqD5MUx*FZs6>1b)w}lbd!kV# z1EJYa>tjUto`z}K`e>Adt);@`Aqy)1y<3RSXV~6`?e2@Pd;mC3v|}eWKxY6z1f~mj zHxh8rh6Ou4;+xrzUTxbp+f^Dx6uXkNJtyE zV=Qqg}^DWailRGhmspqtI_xC>Az|mpE#ovjNo<<^o;-7F9Cg* zgmOinMNs8tr^lDTr!oPZFC|ZICI^V<98KAS{tr{%9o6L0JiJM$iXw_~Q9$WPl>|Yg z#fpMR6b0!P0!Y;aL5dJmuz-aY3^i6zu@Q+931o}R#6qgT>!ym`p6PA#v5Et>){r`Staych~TCm$2 zj9yZ_PwgPDumNF<(NJj-!?!MTeESmU4olXyXbCpWV~DOG_9|Pc%gp6L_~MdhI%JIN z>R+4yQ#6i%eGeQ9$JupwpbdXG7~kChv;>gh#9~y(_-+Y|eF(Zm%dCR&Ho)>4nfFRi zb^){JS`W!!xNL`tD@GOPW$PdK1X0su0Xitxh&;l|=34j%{s+x~}k1)0` zF50ETIG;Wa{3!u{9+AbpT9Jv{ItLyZfJSwZ2Y70xz+U9-ar2N-Wwk6j9TaMX5JHU* z5V8)!dxYdcn=1(yiUsDN4TO4^1VcxYEa|ic7y6U&KUkEZw9H44t{7eBh?Ci-j*73X z-2oV{!VnlvwZQ$(a=c(2I7doGbxt6@col4J18{{wWQhOF&=hZE-Y7w_)Fd{@lr@TM zr2q)FVVn5uN{<7jvTRxx%r}@Tfgs3qGkYaz~bZ(03cuw&?x> z*LN}a!Iial$2N{apyvNTdn0QHn@E0gAJCDH}w#0F8q&&>;#AFoJjRD?e*Bl-viaw zz;+_v232vd)1qfN&?C+ptZg zj-xcl-2yu8k~i@r1w*8$bEgj58%PbuQ0<;&rXb4?R-$$I{Q69M_v8uq|c2d zH#DCt+0{wOEd9P@(V`=6iXnIJjxC3bh5LG|cJHA`Y{_x>@qBWftX$@`nE_uL;@aUl3iG;Wsu;FQm_F7*mNEVl^+p)kD2#a~;wac2BP)Iv?VAGdp_(p*5%;A;ADemQ9&xdZz*XwnIPi-4)t6n}?@TAT&PGbhT0^ zphN~qp|WawEw*$w?V${X9lj#@EZL+A!S{@L|76Q*v=h#3LrITZT$d#J&~VsPS!;IV zWA^_kF~KXo{JeNSf`MU>&bBvNjE!H0(^Z1%wXueOP(8j%2Aw}}#8n~DheN<1BA|Wj z(b7a23Nl9Q$@SLD{()(NzN?^^rY)#FE@gr`#)dIKsiCL;`T|%A@~~xp0d*ayM>{% ze*NFgY$-21MgZ#L1*>ezH!fU^%lWcoF@?YpoyI7z=M`ab`ypdIL%_2gUz)i5xEXyj z(2%YFdPq{?%heO5Pi5M*-fSZ~J)R?sgR(l#rqf>*??hZRtAk(rc^P94VRE)g##0UQ z5|upa7Qhz%g9Xcb&nc8?m(bl#zVKM$e?<6l&DjAhsC24OO3b;EJ~TI#LqW5j!k0(# z)MF4mwAI9|6&_i?1%tt1z0JJKK3{T|Y+)pOJX?Tnv;Jsf?Lk|&kxlY4wKp@Qru>#E z;RqOcq5TK5?ada3RDACK4-2HQg#ffO;#yaFwXgXzWTQdRq+3fY0_uE=UdP$ORx)or z1HHxR5}nPOENwij?_QGC_04Rzr>k&gFL(0XC4&4z=MH-{MU2t)W7d&i+$jM` zgY13p%JnVmn<9U84AuOKF}=XJ_$_#TZO?ggfEVz28m+Tu|88I9G|F5o2tZ6%(Uy>}9sW z@~E>nptM%zx93X0H0X^tDo)ZC6>5;3j0#Q8lUsN=M3D>qs+j1%&vf9O4&jNp=8C~B z%54AmD<r@HtEUbpy;OlR60ML!vZr8AaWsmG=u@1OL_*%t`Qh9WR@=t?MP{B1~W==V9uQEEl6(>SPG@vqbU+WAxm;|uFhw+Dr->OE_u#P($fc%OlF1X;0>QUbC@!n zS#y&BOH~hNbN>F2n!k44oAc!SK7AZ4a&4c{*F}jrJ*#Jp@rLb-#e2K`*sWoi*!JlU zJE*oOasBVGE=An3Ptxwr65m213KW1jQUBNVvc;!v(kr6Y9e5g9xhYxdA02G8e^9&L z%I57F^)-fR^yy!h;8d$!e$z!FCv?A$Q-X5wDR*A~DV@)%tu3Y+lqgkq?InIl@1JlS z1$EG24{e#9woT!p@S_aA-GZZqb6nV57<#gk>n~=?e7}_?GEfMV$)3dhgGu`Zlj0Fg zyw>(^T9|7Z2pPt_1d~r{NReEa+D3yFG4bQpY7ho*HLI1f$Uu@o5>e z#9g-Jv?>Y4Mt8#jPO6;QOB)^u2(snGy6mD$a%R1GC3)M4NRg?E6h~H^IiS(LYMdKA zBXeU*XujRPnGVHD4~%cgAF5;+uPwDcE>2ul=3(5n7}D~MAq&qu8|r|Ed--n5l{0Iu z8_L#b-z_!xI>dzFRC-u#DUMw~g4p|C3*r?5*&U>P5+2(My+Xv!9jO&_v>vPSz%LJc z-}_ZS-n`Ci14fj3=bM zQVwIMryV460(W%%2-PM(gC+RfEYd>D$4*pPr*O%)RWJLVCA)b0&+(6qco}|q=(tz< zD?fHwWXl$i5l(zKGX6)GMUrN#25esB=sY$&L%lDT+0Lx8<#Nd`Px96houwEjIRpki zC#~)rc}bkv(C3M>jN&_@ za&|nB>SNRFS@PkMtX$50IkP?k_xIX+koJDy_Maa2mn71^F>Pk!8D294PQm8#PA&Y_keZ18I&t4VT zcF)~gY94h@a>|_EpA7LoN5-k7+1)Ax;>?IWnQ4h9f6QP?uJdK5*J^yy5z76x^ThT& zE87Z*WT|<#NJ{6hFUyY>NGQHEu4>HsVD?stzF}EL;`6Gt&U2%d|ENq|nt1Y`Oe;>l zoY{uLytI|kYLZEVcuYqXv#P}TGK#P7RGDsqjm2yzq^HX%z8mq<$LyHS)^IKMe#b}7 zTrxq~YL}mzU@2y7up_q$)D-kC+lr%iitKe4l(ObK>zOIRt38N(Azv3KDdKr$zM`_n zY%hEE#iZkNFW<%NFh+N^9@y#o7q&cvO?m8Bl2;a$%C2v1Gn^Z=LPtPT(982CT3a=c z^9>6`qJf_ZC-KA0?i$#@qvB>10o z0Y!C-Iy)Cuy%}5V@W~A`cgZ#pQ|70hPx*zlRTC+2tv$KKn2==A&yR-XpqSJ(MkweN zhtiy-xa0+L4VIR6gwt$^_)#g$Af=dO2<;X0N|uT$Qn0G(?Y1#pI7n$mjmvU{cM2da@ z^&)1DQG7dSS7kEm3!>MZ;gXdMb5lfIImMH^Ss5J65(cxKlnnQVV<7oaF z`W3m%)(>OAjFONp+SvA(<YXl> z$!uCyWn!RQymr;Kt<4>Z&R=Bm=yDVS>}VB=Oy0Zd$aK^!#1h z?+Q+Ov5uW)4;r_K=Egr{lW(w@eS=%?NZanZS`c7=@0A5`!6=r92x8 zz`==oN%Xf_@!H~w7G>UcDUatiJRb?hJCJgVt1Y8a$cK&6!Uun-Xm93vsu%IYxCtJw zFJU%2L$J;X?+|(~uW*=?w8-dg_|Dc0aY>!uVP)r`wmBH+UjJ>~oZ0WATu>NGBs<0= zY#r=0)RZt9>}+0&874W0E_y1w#ZL)3l=Cw>+|Dl}>LoPWm9iFGl%}*E*Ta?bgief6E=_ z=VX!Q_&~7UNL8bq7}@+#j{fF%`tmC#0#=+R;Raj#ukE2NC{SUJ7E_K37bPwu8O~SF)49 zHox7+Qr*m!JT`bOj^r$}YyV$5yhpJ1G@Cz~F+9gK8tc|1EK6jn;=S_6`H|}L0&lD2 znz&E9$VO4^=aA9U{eCL?fn3?c9-4VP4IyKYRS(-jC53;kM3Z1N&d*CDiS8_N`opCa#_6m)I^?A< zIP0Z_$uz~r09v)op66wGxg8{rvr?W!d%+F4#V4DT^PRjH62M@uh-=#Xw3UlfKU*3o zRj*=i=;F#++H&V_&{i#+JJd3+iDRB>PCP`a;Um(ID`|glt_`;0{kDNMb`gyU0{gjD zSB6SN=g|DM>Xm}7-hxLDO+qUPja zS1+^2bL@ccu>a5q)28(HDY?Fhr0G3#prsTJb!d<+A_miXb9(6Z1%|&qJo2hY7%0qA z-Sg#Yc4_=AE~Zndk7BlhaotYHAZknw&7?LIHybqu`;c-2QbN)~IlH=5Hh#I;#{b`5 z+!3GNmI9?7tuFcRQEM%>&eNT5A-7L^MZiEvS_@|jlm3wHU(mLdrH&CXv(X`1-?0g; zCF-{MM{EsSIAaM2e;jEw;B$(9+J6$bATC1VH@vk;LTBi7pLpH6!&fLeQF~; z+StTD>DH0Uv3{sn0uF<_I)rr^s9wW62zn_)uhOZ(t0DRXWcac+q+k~jl8jVQ z+4oAbSxr1L>R}+BmD+Qtyx1q#@fU?YVa{Y7U&{BVCltr}iT?UcIsaojt3Oezm%S8JR-hsct0V2*z}Ch8UjF*_3VJ=S0HU#kr3D<6>C z40vlrzj8viOB%)JWl&jJYg`lD_)W+OK;$IvE5n-+J1IY-XEXX#D5&5kmE0%nE#IZq z@E;Mir@y9l)Bq)zN`OT6=Ew~r!@v5aQl3KWRS z2}3B_$afKr!8A2^b90jv5|Gf9t9Y+GgDr3YTCPP;0Ufu<1_#d0CZKH~P9EDUYwV11 zj1M-sS7E(l==2al1Gsyo5HxBvw$X|p&8F9x=p}&!ZQAI&vq&f_T7w)yGyjGl!z+&H zldl@r0?;oL2);CD;uuMCsFp7qKD9k;DUOjowR21X$B@j0V|4i2H0LQJ9C`JHhN#VG zzXE~Ls9#_ASPtZ6PS*9_zbhF@x$g?L>(_f$L7PxH=M41vtg{@|TVb6_t4MZ$;}(`5 zLgPSJ)a2)Xk!!7t373K+$`H`|;j6qFk5bGZ85#K3F8sc8#n4kZ0O)y*`l$|e0!pdy ziq*O4B7MB*jZjhn>D6u*p9Y5Uew)@f%F4a%P+#+xm;f-J{4;3{yVKj$Qg!rP4XU43 z&3*)w**`RNPyv0(Id=|+4BJn~Jzok(^sWvuxZNY(Yk@wiE zEU$nOWU5LZBi60ltQXeP@{EFi0wCpdqP$lFkDMlwdI3F~AGCMO8%CVcE6X41-4)D~ z0Ear!sS{D#mm?cf1HwCA!41;Dd&ZX7)w3od*mK)oKh|7;Y<|(!`_@U+gNuL5hoKr^ zTt&JlJbJGbit+b42uWgQW*-3GCDU$UAQzU)As-5%`j)1>KUC8;`}e*0oDBNeE1F%7 zQg;!mzwuQHs$hqZ+p4BkGWy}tJhGv=B*XVFnwy@nRuRyXA9*uoOj z1d5Icq2d+1RdERHlMn0ZJGM4K&Bor$2j?)in&O+xII{-o@LzH<@iv1EhmL@K4>Jk!CY}TJJoVb^McSXXdf= zOBK&@oihMoVv~^oYKC3W?==e9>KAr2T>dcm9+BmpT4pekf)N&>Nk0xgH?sUO!DDM+ z-SUaS8fjDj#ELwIaiGo5(dk_Y1g&Z&uQ%@rL1bxu5;QDw`D`VzV!_EL7GcpkHfDxw9hQo{z#8 z&U%FM??DsXb;{_=HD$|oSc#bEY2VqYE?oUKD%-rE)t=}rg{s-4H-a!2H``udhyJ-K z*V$xaxn7ls9&Yn(17S(A(;Tux$2Th%=iBiOG|)qtgoa6wM6v{wjmS=a^=5&R^N)I7 z+*u?CMRYy;za=*Pia-hZsY6> zceZwTLE|6zP`qm=IQQQ9G@lXPfzO((Tz|uCG0ftH|4ob2ElZ zprn=;3!i7U=Is~Dlds!MPw*22qCG?<968^qF+My&MHg(K6ia8w<_Udil>lNaXa7dq zPv#Vq^`ix|e3y^MgUNk*h_ntfp%^YCXq#t>0%JcoyRXj>h^~`cLRl*~ATf+aXTf+! zW}EDpEt!?G?KM$oM{D3swt`xNG|63xu`Dv))&P%Me!R5Go)xV?T2cCv7mm73aQ7%9 zkIq72BRFTt^xhw1D}xHhb0h*U_WuFY(MANKis8YmK;1V>P>{BT@4YJ#t`4-Qba) z%{Z_S*{);xAMw{uJhgitimpC0ZaEsJC<#W1nuWh(I0G|Bh$=T_fNSOV8d!cwUAky-gU{|58)dK3@b$fv{Zjv4ih+7p~vo~f&DU{uw2xe zv@Nz^@sf}Bn$4~Z^Q?Cs&voNu2DKZ)BcPQ83B7YEw9aX@3OOLDhigNv`0p9Xdus%O z$oK5%_>6%OfIG>TKL8e@Vxy7BcP2nR+_YK-<$SB1t^*SZj&21B77r!a`<6Y$Z5%$^mx{l#HJ1O(QHQ&S&D)G)|?=CLxga@3upRd#bT4= z()A;~H&x7f*78hTAl&guII9Sloc}T*>ASu5VNYs}44U`p)=2gT_%Sou(!2=vph92i zr&%x!lA=8O3*D$lFV)@BYzX$5X$IGhE1E%keo5udjB(!gy^e;*UQLo|o#k{;CY37}+ayEbI>Hqc-v-yAF zvuD37^)Tb0LB}sE!tl49Nt|?jZ7+M3Vq>RV<4x$$dsF-nw)U2&(dW$Bl;!9#pc>%1 zkoy1}AjKqFpg$;{AJXV+3;HxZZ{yo$?hi2-`wQN&!Udf92~ZpR{DFU;&(eD|?CLYz zoww)}JP`DF|6U+R9&c{Zr9YKJna_&lJbpU|`VOA?UhJuNV_fjKISa?WuQQ|x%bNL0 z!{l@L_}?=qXTXBjw%|7U_9bcLYtS~R9e^HwQGLnvkDJn$eO2atzp04`1-sA6HHu*A zmT@=-Zy8P(8OBK0-{`%srTG2{&-4;#OnO4AF*a_aQ;Nq-6ct_ex~--7p@YZET*!XC zv+WtCqN%j^*AmXdX|&&fS7}h!gZq+RC63rR@vj~7ID*>Ci_Y4lE$BS0;b~acWJ*Lo zyMrw|H7`RN-4{=lo{utLe;LVKK}BDZ4_lh~My*_mn(n3; zOjH=hKh7eWpV*T``;twk!C}pts3T1UJ2vw}ZArRYwQxyIHDQ0;*q)_L2O}@GT6CiuJBl*1=q~#+M^pX$exT={{-LZ^wuDpbt^VI^$1f5=}V`E?~$Z(T{@@aF}E- z?S22ApAaR5`u=rAim(11DVXnvj-Tm)=Ofc`4A=GxSuyZq!tP~F0j?KYSF43deqUDC zVhcevbnkQ9FJ)w%cBVXuxZY?J5rnW7U6iH5Vr@k2%g4AG@GJ1F!|=BeW)T(XhkH#l z%ELZ677?5Uhm)m0_E&K2{E+_WSV&k}N1neTYm@LS zjDPE5Nybpkq+@j*;S;a-s#)1dgVJMTX}CalC4VcBSRNl*`n+c*{ZRXQ5Z z37_Y%meBUxnvWw7e|y#hmAu4mO(|dR;*M>E{4aH-?VC63F)urRo#rpqgvu_zp>I zCL$xK(c7rN(vU#+?%QVzCP(6D90&P^SJ#!LSH!7*Y&p0QX`5Ty4;}@bccP=z;nuO) z?DEO)8Q%BTl`&hV*ICslBE27l2a5s%0G&IZoo(D_CL_@0>8(ctZ6^J5y$lJIjRV58 zygc4UL|I_tl~#GPs4gs`%SF{Atq6~(^w5i~`@n)bU&M)DA1j<6TTNh->h`L7bV%~F zFEygfm#KMqSgfC-Jv0#_{wPvKjn&bmZw3hLPf~+rDkcQVae4j#lz$X`N)j~DYK`g+{SyR$Zh;{jl!z3GEwQ4uxy-OaR3L3 z-&7=^JF{;kHl zR(kaG%C*?qd^{vUkzOKvtAeS{wSOyyxU)Zn=J9Z9nD=;fZtRFOM6RjaX?H1f=Z@Rm z?-f4r!ZRGmn%#S3TPv+azTGcF$j{Rzp!dJX72jG+#z${HIZ;}82<=@%%=RO@w!GVo zoP;0Z+BMIj;)-xVfB&?we+=!@G4YeN$K5%|pI&F*1gZfdk>h^}lw&TOtvZteLfNEH zvX+^mDp`E-s3jPhqK#<5ugcmFaH-FDq)%8kNni{PUBvImFX?+lIe%5*#OJhTq$7G8@bxtm0{D2LDWBEbca~Yh9%bH_sa^ z#T#!y5w_WPEGOadal0L{PCm`otDY$&eyb++40^J(CE9~01t%=u!Z`h7)gFek!E4dB zo%GG@CVzf{uz%V~hOKmqZ@@F1l*OU(h@ep09rw(~Dg*YI)Aq2xB@Yg%EtL7$kR`s9 z3MO&?=(&*Hxo^VX2T7Cd<3AT8H$Tc#7VvYQaF1=KIp^jh>o|#QTf^B!M1`0kIC8r>etjrBc7xeo?2e=6a(3FDqJLD)0y|KroMH1eKFTR!WQisq;M zgf(*9m8GucX?XqFqGwU`eaZ82$XoQv+KVgiHmr)Uc*cMpPQ-DGPrpZHG*uIIhgK^i z_T2&~j_Api|JP?gX`QYeJ(D4>QSae@NnMK94?G^(wg}|Lmy0VuM2da?z}~L6&Rwdy zdjAGy!*+2DQxUH}kTf0My8R54DN`LN4fF4u*wi(n&_^%bJP}dCkepRN>S^4Z&Z}Oy zWE(s1)=-h9Vbt;7l_=uFB<;jKJ3pJJvp%+MF?9KTnX1B$5ko@R!;91AzAf`NLODUF z#`Uay!}8reXOyOb;zt8 zKdl~dmhOi?vu8?2{qH|L(~*FMcO)zS5z zkKuS>{K@B-2PX1ZaUmm0q-#SetJz2^%mf`LX~H&Is7B>Pv=)j z=Y}rc%cF$qAfM!+Y*yYR^{6R3(|>4|M!A3Y7a;}5jxlaA`6fyno>aVlkJL+g${6!l z?b}i$hhzH*1k-XYu;0n!$NYz_DTVUhb)i#}Lk{)}zuf;J_A+m>WNAufZnlrl-XOjK zs;={O;c)r1v-ijAA9W_X3Fv2Yw|L{lHl)sOUr*mVW2FhZw)-!?`q*D7^s9E)#}ifE zZwWDis=T~oqEkDv@$-WB^=D&Sf#R5O`=ikASp1pzp58<9fRO>e!%~|ogOj9tKFtA* z&glNuJW*9y0>bA`T!X1ZOh8hcv92Xjcpv{N05B+cXyzWtH? zW{3VYjaqk+eD7!50kMPmQvCAT-*x)4o*yf6 zeYz{B~YiQ zeZ}n|xSjCf?0Ejlrj;sA?5?rqXS`KK0Xd2kr4E{_6kiW`An^3Zt^{$RRNvKEn`pDY zD!bTf%tl?|%@TEq&i3Ea8Uce#0eDk^UxxMGS?7)-b>HS2C26B7E^IY_{{3m+f)=R) zd2sz~e#&(A+vmRxhc3|k<3FBt?&xBh1eB+?lI@ok7kP_#Dw$6=k}vgTcL-~mm*COz z!ye`hju(D!zEGXe_3w1=F3E4hT`D=hgng+Q`07v}hpXOv%f3b5{f4xbF$4t*#$>m?mvHH@Vr!8UERbI*LC_Nn6vJ_aX-OD$)S6KJR z3Z>gt+2vY2Cl459Z=$8!F;+Ex&&&Eq%>fwW_(!X+suCG-x4i}rE5rTgC$-=K?z8YS;f=8R0j6Ac<;_5C5Zx0>rKKR zaclnGU{m|De23&&h7w4ztxd$*n$QI06&(#PMN7)& z6T%slG=kUd&5hQ%9|e`sd!WGLsZ;dBB->Dtam*9-*!ADYyNn7>(2q>C5qDFLFQFec zZZ;Yd$|LGgZz+qRB^Kf6q5Ib3Dyt|Ve>tAXgGVmSzrpq&toFLhC3((6dY7trI`Vr% z(dE4U-)GcNgm2+U=B8AfUM5SK=}0?#Yda26MICWh-3zN(1PEMR881pK{gVC6QfpJ` zNky~hud|cW>TZ7U*ePYJNx(p@>nj{t*qAr^n?QZ1>q*_Vu;te7_9Gqi6UL3cM0c3* zf%D+B;Dit^bac~WBacWSKF23{P?OhjZ%5!+H~QZD4e!mT31nVhns-k0$NmbP1aXgG ztjuaYgXUqm62yLjl*5L6>s$ljP;X}RZg}zMm|szEU$ats*H4Kd!9PPdia&w4Ze^o% z=|#oP?|)9k(ze`hCP2sGbq2cTlagi$@H*gDYIFde5WnwpW~PuyeQa$HksuO*>%2ELF|@X!b{2@c?RP z4#OMVxIm*}0YSWfqKUZsq09q*^|Vn!8y%as+A`K$G?DNMmNl3E^e0@2y;tO1(bCT| zsHxtyYMf{>>A!ELz>4GsndzY%&fcwSXQ^dNwcbPt_YO(4S5NtKlxcS849G*0krt^Qp?A##M2v6fLRs|<&xJ06Lh zj{59)B!xo7o)gECkyfLAxE#KMV|k~YJ0nf9hO8&GCKXG>sH`y_cP_%!pDf8ZQ<}+< z_;k;;tpcjL_*1%;Twf#@JSW%oU9RoPtH(D@5M^^m>6QZhck_b`ysl-?l0_2xXIxvl zcsiZ|!?i_>1V&}`c4gSLzR5!e#wQ@QG%+rwKJuabc$yH>wt&~i!aqFnxAZ_o3p>Q$ zm+alrl%ZT;Pb6L%{Hihf3F`liy&mx{3s*b;Tk2h`kitAt0Wl;8p2m2KzjCHi=}DC* z<~Ew5ZEB60%B+AvNIaZa@QSJIU8c0RS@ni*!=-!^Wb^2td7}<*U9Mk7$#B|9Z!?m! zpfR;ILplF#w2o>zmb>q;)1W^^Ux3&)7F4$YZ~^_~O7T{$@cUa*_=~f1S;nAK#>ahQ zbx*%1JQKttHgl}`J`3(1?OhSDd0A8!>fHIUB>xvDzCWX!v$Lz^&eG}&pGIo0m_{47 z4T-I@O_eibcglb=_NV5i8vZxmU@R)Zw{bGh0-oo#3l7LH$v;-Q)wSiD`&xq{=lOBo zbdv1=$$Wrle5ik)ux?NlW<2^dZ{;#k(o(qQ1L4{;Bx&~1DL;M*^L=ShSA)L0ra?eU zN#2a)iE4T>~>`VgUUJt!WZTp={Uxj1%R~yAD9{rQ>2qF%#LNb#!fy_S4b64k5 z#TGL|zOxl^%)8uj52*f~0R_NGrX3UW3CqWs` z%|9%;VsQ8UC9QG1nZRsi7#2|9nK)ASPw7G;0#}w9C+a$djggRhWw1QL&q3fHB=C#z zr*8H4kMZ|UFNRxMu(cH@UoHK+kdiI9-nt4wnaWQ>m3@QRZa;DL4$*pd*QG$4-s2xU zYZE20WQCILr*o|u&@^xS@jnV zJ;gbIyJPiKN{GpZhTE1E#m*3?L2RKwF!0KECj0YZh*BGm@;WRbm6?qD>m2W!oXvAh z&l^={KFQk)6Dc;g@M=_Qx_TTkB3e=#=CvAPv-=&aXrl9v-yXerZYmDKC3HxZWjz1V zY)W;X$>yt}2eBFkLnm5Iu)hDL=6Mt-^|;x_$!)Gp6Rqo^arsE+bXlHB?Y*)_CGG_tk0lMXAoOMRk$MpOZCBF?_qRN(=~Qh_ zs4&FcH!k+vi%X4fzaD{dKJbLAs^zs>?yRt%@adSd-=mQ+6^y{RWI->nZn`3UD7=j? zK8wBB$yi@wz0zpX_-Dntl_zh~0;DXL!1u-1-;{3hF__G5@4}xsfW;#7E&xoOje{ds zc2Q?Fx;;OUt-&AJCI)8@**jwJtk7hZ8^5GJA%@uK)4Cn{e)|;6e+qTE7ohZ9&S7&p zyetQmkP})1JO}0<4rXmC^&4x5&1Yewwx8lzcF2Ki>{M?)KMxE6)Y))1+P5Gm%jDLR zq=n62R5E$3a9v>u%^9 z^VMD)AADj%s8Q6}Zo2!zBe$Sy`+PS(qnQNhRND05iiirVY13ptrEAq>0$i<0e@~C< zI`SH8B^=^xdR^9^{k}h4dia&f<*%*oFlcq?)`cOj_z8CxqV&&}`l_v-SmRC7o58WJ z>336QBO6v^@svm4<{V@s=fy8IC`C!egrauV!w5 zOTZdv_5S`LP9y)`AAWiH@6RhP2Xj(5|G?60c?`ibe}ja?P@@DHw}yMXmn^tQR=+W| zIV`%oyzXViJeAjzgA*m+LZlGdkMn76jjniK*Dx_prJ;xu?nAc)zFgz$BK+LtJL7f; zUAE4=CdNgKGB*PDCUv8K%2Dm>O5^;2TzW zUbR1%<6m)<35|RDCB=KnpMJ88xZ_@bcAx9p7f&|cZ(G(H16VXEr=1W6Ev@@r z(WEBKqHQv#3$WRmuJcGHZX(COdNjWD8o zNtxS>)^X$Uw)ydxC@FiWROs&(!YQKp;}8n1A@-zEhaBB<=N zZfR6O_UA%i`+KkbDy=mDP4fKXhOzE5E5O;}$kUZ?gnks-_0sIzC(zW(g{CH~>7Zt5 z?CYle=%L;KCkmXpFvE?pCR^63Q#i6)ZTb`1Jzy!M9dQT?H?2Wm?i^N5hqx+;cUGN$ z-Hx;a@l)F#A`$IyS98}!XwG~cPT%a$-4BI-@~bo)sk-XW=S(p2OJpR*GD{H3_i zL^*EPp!9Av%+l7!lojvqK8=l8(h3g=GM^!KcIVBL^g4*e+EobO;K$!CKu=|ZVbKPDSk7Nf>zvM*9R*$eo z@;v>pNzPhvYWQ_H@`)YIe?;~eo#%aO<5?~7`?7wrV!R+)Om}UVz;H2p|JBl%4qz7- z!J(YRd(#JXGEmM9P2Z;38!l(Z9;J@5F7Z!7_6<<&v%lbqmm%OY5Rzq33L$N%;wK6#0FzvA~sF(B-%oXJKHzzTa@4Ia~g@`ieFE)P!s_JEz z3*U_BVQZJ&m%B-rD)$RC`xGlr)L~Zxo>A1U9l-xotFh_Hzc@;`G~dE~D+WPQPWpgI z8mQV7IxxL@9K&jVqFT$d=*`Jf!hhLDb1>bMk3&W%LCBOcz$au}VEGmttu!w+hx4mO=M2~9qHecVD zYTk_#A9KA7t;LUJEzR8;fW^DJn!-6Xu+-$FzAKl8B$bzQwb2C&OQl<+nkt+o&~-aq zbT5whK=y55Br@ZURjmT2DTttE7fWI#w_OfvV(0RX8)7`c( zGMn0)Hb8VpzIH^Op`o1rgm&;2_?97LnHr}J9IA9q6}{s4v^M%+kZDH-U*rxD6~X`g zO0;L9@f;R`K@^7$QP#)-v9EO`QhZ-+X>|&d77l`OOVhR{%4V#Q#Iw-#yM}>$xHkO| zr;wkpD_U-UT3@!P)S=>`Gcbf+qNDJ0ug<2U?jFlN7Fd#UF{&y4n<2h5y(#%1;P<R{V70q#k05mfQic$Ox&@>vmt@*e zS+ZEJ&De6i33!Z=*((D}ZL57V*>IV?>1$$MMn%Z@Z)jhz*21oBL)Gg1-I>@gAp>~@ zCouGv4<^T%%X2A^38}|KTwCsyJxYsvjqR$RO(~Yi-&Pt% z7@IYwMMJtQjng>9f9SQdb%>LREs@2JHf8Y!oq2E1gUH(3(tN>ES2fyq>O71T@hoq8 z{mK?!qRaU%KWXw^PhH=Zqf$1Q336=k-LzYQ;&a5Ht;oD;`7az?(X##fo@Oc#;V$U% zislbc^${_|hBI|Ju^_4^?#^|bup6S7Q=s)?r zGUxL~IE*jw~vS)GUvVp zH5(e#+H#4sRR*r>hkjMbFbP#a`EwtZBxJ`Zu2h93f?AaTDKa& z{N2_3hPEwI0gveiKjTKpXa^bS503pxl{_bGmAAxbWefgGU5qE7rr;-Xjp{re512}{ zmY6+wNqIE@RF-^<#x@0{43-Jw4jG#eudt`5pEEqkf1_7?)aQc<2V;+EuY} z0xJw$x*LdY+5wN%Hu#Ft6@gh)Pn5dYra$AkVxN4v?FFt@y1yf!1;tdQ0=7*!VQ2+z z5YYnQlfI8D3Fvs=V&3Xgq;);(44~q^0_KL|uZ(sAgg^DUwuC9?UGh5y-{{?ztx|s> zoU}HOlmdHel(&Ao?GJ~(ObM@bC-*Z!{=_ez5!8*SZvK=aHy7&O)#TD7*)kNFSe;@y+RdHPR|sQ?+!HIStMQ z6uN4(MwH-wFY64^Z6W+D!))5hGwkv22^oeG0w6?stqVSbw}+PClSY8-vO7)=

hD0H+2U*svw=4}=xXV9nSWwRK?`m4_P73zR zDoM|J=erCsHs)mgh_*E0zp`LXA0oasny!a~VHmF@C#$q+#cXVr;U7rJgyh5<7PHZ- z2Z**Ne12-1BTH)mkor)(l2I~LUx2AtwZt`|BqgyV)hf9t6-Y4{85o)98d&HWS%esxSs58xnHp&u7+4t?tnLtb fhN2-iKP5A*61Rq1SJy-VH86O(`njxgN@xNASjSp) literal 0 HcmV?d00001 diff --git a/multistream-alerts/script.js b/multistream-alerts/script.js index deedede..66fef18 100644 --- a/multistream-alerts/script.js +++ b/multistream-alerts/script.js @@ -318,6 +318,57 @@ function CustomCodeEvent(data) { +////////////////////// +// TIKFINITY CLIENT // +////////////////////// + +let tikfinityWebsocket = null; + +function tikfinityConnect() { + if (tikfinityWebsocket) return; // Already connected + + tikfinityWebsocket = new WebSocket("ws://localhost:21213/"); + + tikfinityWebsocket.onopen = function () { + console.log(`TikFinity successfully connected...`) + } + + tikfinityWebsocket.onclose = function () { + console.error(`TikFinity disconnected...`) + tikfinityWebsocket = null; + setTimeout(tikfinityConnect, 1000); // Schedule a reconnect attempt + } + + tikfinityWebsocket.onerror = function () { + console.error(`TikFinity failed for some reason...`) + tikfinityWebsocket = null; + setTimeout(tikfinityConnect, 1000); // Schedule a reconnect attempt + } + + tikfinityWebsocket.onmessage = function (response) { + let payload = JSON.parse(response.data); + + let event = payload.event; + let data = payload.data; + + console.debug('Event: ' + event); + + switch (event) { + case 'gift': + TikTokGift(data); + break; + case 'subscribe': + TikTokSubscribe(data); + break; + } + } +} + +// Try connect when window is loaded +window.addEventListener('load', tikfinityConnect); + + + /////////////////////// // MULTICHAT OVERLAY // /////////////////////// @@ -1268,6 +1319,49 @@ async function KickIncomingRaid(data) { ); } +async function TikTokGift(data) { + // Set the text + const username = data.nickname; + const tiktokIcon = ``; + const giftImg = ``; + + // Render avatars + const avatarURL = 'icons/platforms/tiktok.png'; + + UpdateAlertBox( + 'tiktok', + avatarURL, + `${username}`, + `sent ${giftImg}x${data.repeatCount}`, + '', + username, + '', + '', //twitchSubAction, + data + ); +} + +async function TikTokSubscribe(data) { + // Set the text + const username = data.nickname; + const tiktokIcon = ``; + + // Render avatars + const avatarURL = 'icons/platforms/tiktok.png'; + + UpdateAlertBox( + 'tiktok', + avatarURL, + `${username}`, + `subscribed on TikTok`, + '', + username, + '', + '', //twitchSubAction, + data + ); +} + ////////////////////// @@ -1596,4 +1690,80 @@ function SetConnectionStatus(connected) { statusContainer.style.transition = ""; statusContainer.style.opacity = 1; } -} \ No newline at end of file +} + +let data = { + "giftId": 5655, + "repeatCount": 1, + "repeatEnd": true, + "groupId": "1750261118899", + "userId": "6955276871237370885", + "secUid": "MS4wLjABAAAAWFtVMVXKfBB_hnuByyirANl3y8R4o8PC9clvNivtbD5JvdS6JtmCo0GR9int0mNU", + "uniqueId": "deejayamme", + "nickname": "Amme", + "profilePictureUrl": "https://p77-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7332939462534447110~tplv-tiktokx-cropcenter:100:100.webp?dr=10399&refresh_token=b162ebd3&x-expires=1750431600&x-signature=9bDYBHHAzrlaBnA9%2BkBW37toUrI%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=fdd36af4&idc=no1a", + "followRole": 0, + "userBadges": [ + { + "type": "image", + "badgeSceneType": 6, + "displayType": 1, + "url": "https://p19-webcast.tiktokcdn.com/webcast-sg/new_top_gifter_version_2.png~tplv-obj.image" + }, + { + "type": "privilege", + "privilegeId": "7138381861675357988", + "level": 22, + "badgeSceneType": 8 + } + ], + "userSceneTypes": [ + 6, + 8, + 6 + ], + "userDetails": { + "createTime": "0", + "bioDescription": "", + "profilePictureUrls": [ + "https://p77-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7332939462534447110~tplv-tiktokx-cropcenter:100:100.webp?dr=10399&refresh_token=b162ebd3&x-expires=1750431600&x-signature=9bDYBHHAzrlaBnA9%2BkBW37toUrI%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=fdd36af4&idc=no1a", + "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7332939462534447110~tplv-tiktokx-cropcenter:100:100.webp?dr=10399&refresh_token=e43e92cc&x-expires=1750431600&x-signature=UD9nuFnspy%2B%2Bi0ouX2FfTf1EUX0%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=fdd36af4&idc=no1a", + "https://p77-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7332939462534447110~tplv-tiktokx-cropcenter:100:100.jpeg?dr=10399&refresh_token=32267bb8&x-expires=1750431600&x-signature=rEkdnHYpCSdnuS4IFZ7Xgg6qb0A%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=fdd36af4&idc=no1a" + ] + }, + "followInfo": { + "followingCount": 9109, + "followerCount": 6426, + "followStatus": 0, + "pushStatus": 0 + }, + "isModerator": false, + "isNewGifter": false, + "isSubscriber": false, + "topGifterRank": 1, + "gifterLevel": 22, + "teamMemberLevel": 0, + "msgId": "7517314100029606678", + "createTime": "1750261122519", + "displayType": "webcast_aweme_gift_send_messageNew", + "label": "{0:user} sent {1:gift} × {2:string}", + "gift": { + "gift_id": 5655, + "repeat_count": 1, + "repeat_end": 1, + "gift_type": 1 + }, + "describe": "sent Rose", + "giftType": 1, + "diamondCount": 1, + "giftName": "Rose", + "giftPictureUrl": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.png", + "timestamp": 1750261122520, + "receiverUserId": "7050235313499374598", + "originalName": "Rose", + "originalDescribe": "Sent Rose", + "tikfinityUserId": 1903738, + "tikfinityUsername": "nuttylmao" +} + +TikTokGift(data); \ No newline at end of file diff --git a/multistream-alerts/style.css b/multistream-alerts/style.css index 2b2a330..58a1cd1 100644 --- a/multistream-alerts/style.css +++ b/multistream-alerts/style.css @@ -335,6 +335,10 @@ html { background: linear-gradient(#466edbbf, #1c56f5bf) !important; } +.tiktok { + background: linear-gradient(#262626BF, #000000BF) !important; +} + .blank { background: #adadad00 !important; }