From 8b3fe48a747186a56d436d723c1ad7871961858b Mon Sep 17 00:00:00 2001 From: MathMan05 Date: Mon, 5 Aug 2024 19:06:26 -0500 Subject: [PATCH] inital emoji support --- .dist/channel.js | 2 + .dist/emoji.js | 67 +++++++++++++++++++++++++ .dist/localuser.js | 56 ++++++++++++++++++++- .dist/member.js | 1 + EmojiList/credit.txt | 2 + emoji-packer.js | 115 +++++++++++++++++++++++++++++++++++++++++++ webpage/channel.ts | 3 +- webpage/emoji.bin | Bin 0 -> 40262 bytes webpage/emoji.ts | 75 ++++++++++++++++++++++++++++ webpage/localuser.ts | 58 ++++++++++++++++++++-- webpage/member.ts | 1 + webpage/style.css | 4 ++ 12 files changed, 377 insertions(+), 7 deletions(-) create mode 100644 .dist/emoji.js create mode 100644 EmojiList/credit.txt create mode 100644 emoji-packer.js create mode 100644 webpage/emoji.bin create mode 100644 webpage/emoji.ts diff --git a/.dist/channel.js b/.dist/channel.js index 2aa588d..62367db 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -8,6 +8,8 @@ import { Settings, RoleList } from "./settings.js"; import { Role } from "./role.js"; import { InfiniteScroller } from "./infiniteScroller.js"; import { SnowFlake } from "./snowflake.js"; +import { Emoji } from "./emoji.js"; +new Emoji(); class Channel { editing; type; diff --git a/.dist/emoji.js b/.dist/emoji.js new file mode 100644 index 0000000..9cdf783 --- /dev/null +++ b/.dist/emoji.js @@ -0,0 +1,67 @@ +class Emoji { + static emojis; + static decodeEmojiList(buffer) { + const view = new DataView(buffer, 0); + let i = 0; + function read16() { + const int = view.getUint16(i); + i += 2; + return int; + } + function read8() { + const int = view.getUint8(i); + i += 1; + return int; + } + function readString8() { + return readStringNo(read8()); + } + function readString16() { + return readStringNo(read16()); + } + function readStringNo(length) { + const array = new Uint8Array(length); + for (let i = 0; i < length; i++) { + array[i] = read8(); + } + const decoded = new TextDecoder("utf-8").decode(array.buffer); + ; + //console.log(array); + return decoded; + } + const build = []; + let cats = read16(); + for (; cats !== 0; cats--) { + const name = readString16(); + const emojis = []; + let emojinumber = read16(); + for (; emojinumber !== 0; emojinumber--) { + //console.log(emojis); + const name = readString8(); + const len = read8(); + const skin_tone_support = len > 127; + const emoji = readStringNo(len - (+skin_tone_support * 128)); + emojis.push({ + name, + skin_tone_support, + emoji + }); + } + build.push({ + name, + emojis + }); + } + this.emojis = build; + console.log(build); + } + static grabEmoji() { + fetch("/emoji.bin").then(e => { + return e.arrayBuffer(); + }).then(e => { + Emoji.decodeEmojiList(e); + }); + } +} +Emoji.grabEmoji(); +export { Emoji }; diff --git a/.dist/localuser.js b/.dist/localuser.js index ccdb395..9d1844d 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -363,7 +363,7 @@ class Localuser { const div = document.createElement("div"); div.classList.add("home", "servericon"); img.src = "/icons/home.svg"; - img.classList.add("svgtheme"); + img.classList.add("svgtheme", "svgicon"); img["all"] = this.guildids.get("@me"); this.guildids.get("@me").html = outdiv; const unread = document.createElement("div"); @@ -407,7 +407,7 @@ class Localuser { const guilddsdiv = document.createElement("div"); const guildDiscoveryContainer = document.createElement("img"); guildDiscoveryContainer.src = "/icons/explore.svg"; - guildDiscoveryContainer.classList.add("svgtheme"); + guildDiscoveryContainer.classList.add("svgtheme", "svgicon"); guilddsdiv.classList.add("home", "servericon"); guilddsdiv.appendChild(guildDiscoveryContainer); serverlist.appendChild(guilddsdiv); @@ -922,5 +922,57 @@ class Localuser { ]); botDialog.show(); } + //---------- resolving members code ----------- + waitingmembers = new Map(); + async resolvemember(id, guildid) { + console.warn("this function is currently non-functional, either due to a bug in the client or the server, it's currently unclear, use at your own risk"); + if (!this.waitingmembers.has(guildid)) { + this.waitingmembers.set(guildid, new Map()); + } + let res; + const promise = new Promise((r) => { + res = r; + }); + this.waitingmembers.get(guildid).set(id, res); + this.getmembers(); + return await promise; + } + fetchingmembers = new Map(); + async getmembers() { + if (this.ws) { + this.waitingmembers.forEach(async (value, guildid) => { + const keys = value.keys(); + if (this.fetchingmembers.has(guildid)) { + return; + } + const build = []; + for (const key of keys) { + build.push(key); + } + ; + let res; + const promise = new Promise((r) => { + res = r; + }); + this.ws.send(JSON.stringify({ + op: 8, + d: { + query: "", + user_ids: build, + guild_id: guildid, + limit: 100, + nonce: "" + Math.floor(Math.random() * 100000000) + } + })); + this.fetchingmembers.set(guildid, res); + const data = await promise; + for (const thing of data) { + value.get(thing.id)(thing); + value.delete(thing.id); + } + this.getmembers(); + }); + } + } } export { Localuser }; diff --git a/.dist/member.js b/.dist/member.js index 3252692..8681e49 100644 --- a/.dist/member.js +++ b/.dist/member.js @@ -101,6 +101,7 @@ class Member { } const prom1 = fetch(guild.info.api.toString() + "/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.snowflake, { headers: guild.headers }); prom1.catch(_ => { console.log(_); }); + guild.localuser.resolvemember(id?.id, guild.id); const promoise = prom1.then(_ => _.json()).then(json => { const memb = new Member(json, guild); Member.already[guild.id][id] = memb; diff --git a/EmojiList/credit.txt b/EmojiList/credit.txt new file mode 100644 index 0000000..e5e6031 --- /dev/null +++ b/EmojiList/credit.txt @@ -0,0 +1,2 @@ +https://github.com/muan/unicode-emoji-json/ +the list is from here, though the actual file isn't included, if you want to compile the binary yourself, just put data-by-group.json in this file and run the needed script. diff --git a/emoji-packer.js b/emoji-packer.js new file mode 100644 index 0000000..2c0845f --- /dev/null +++ b/emoji-packer.js @@ -0,0 +1,115 @@ +const emojilist=require("./EmojiList/data-by-group.json"); +console.log(emojilist); + +const buffer=new ArrayBuffer(2**26); +const view = new DataView(buffer, 0); +let i=0; +function write16(numb){ + view.setUint16(i,numb); + i+=2; +} +function write8(numb){ + view.setUint8(i,numb); + i+=1; +} +function writeString8(str){ + const encode=new TextEncoder("utf-8").encode(str); + write8(encode.length); + for(const thing of encode){ + write8(thing); + } +} +function writeString16(str){ + const encode=new TextEncoder("utf-8").encode(str); + write16(encode.length); + for(const thing of encode){ + write8(thing); + } +} +function writeStringNo(str){ + const encode=new TextEncoder("utf-8").encode(str); + for(const thing of encode){ + write8(thing); + } +} + +write16(emojilist.length); +for(const thing of emojilist){ + writeString16(thing.name); + write16(thing.emojis.length); + for(const emoji of thing.emojis){ + writeString8(emoji.name); + write8(new TextEncoder("utf-8").encode(emoji.emoji).length+128*emoji.skin_tone_support); + writeStringNo(emoji.emoji); + } +} +const out=new ArrayBuffer(i); +const ar=new Uint8Array(out); +const br=new Uint8Array(buffer) +for(const thing in ar){ + ar[thing]=br[thing]; +} +console.log(i,ar); + +function decodeEmojiList(buffer){ + const view = new DataView(buffer, 0); + let i=0; + function read16(){ + const int=view.getUint16(i); + i+=2; + return int; + } + function read8(){ + const int=view.getUint8(i); + i+=1; + return int; + } + function readString8(){ + return readStringNo(read8()); + } + function readString16(){ + return readStringNo(read16()); + } + function readStringNo(length){ + const array=new Uint8Array(length); + + for(let i=0;i127; + const emoji=readStringNo(len-skin_tone_support*128); + emojis.push({ + name, + skin_tone_support, + emoji + }) + } + build.push({ + name, + emojis + }) + } + return build; +} +console.log(JSON.stringify(decodeEmojiList(out))); + +const fs = require('fs'); +fs.writeFile("./webpage/emoji.bin",new Uint8Array(out),_=>{ + +}); diff --git a/webpage/channel.ts b/webpage/channel.ts index 1bcdd83..60af6fa 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -11,7 +11,8 @@ import { Role } from "./role.js"; import {InfiniteScroller} from "./infiniteScroller.js"; import { SnowFlake } from "./snowflake.js"; import { channeljson, messagejson, readyjson } from "./jsontypes.js"; - +import {Emoji} from "./emoji.js"; +new Emoji(); declare global { interface NotificationOptions { image?: string diff --git a/webpage/emoji.bin b/webpage/emoji.bin new file mode 100644 index 0000000000000000000000000000000000000000..d29585e15f271dda09ad3155091e0261e0591b01 GIT binary patch literal 40262 zcmZSJWDpF_&CE%yELKocaLvsx$;{7VSizfKl$n>8nU}7RmYAH%@?rjr25A%_h4Rdj z427i3bcNK))MAi=W_c_MigPn_K&HSHwa6uR|$);C99-R(-gY$xdOTQd8w7Ux%s6f z8E{<_v4nDdL28~tMq*wHDD0L@mqa)XB&d*ImRh6$HU$*sYt<3bV2z+)P)N*60h@rT zc=aMtgyMqKRB&oatpxdX^5)&a& z28x>e(h|7GXKWKl$uB8MO;O0n%u9u-UcHnLY;9(qLUK-iX-YBQhxs$MJ!qRiaHWN_kv7GP_5 zK{^#uD>4#6B?R|}`7_pmt(>%iE2k1k<&vd5#Tkjn)~{Y6nUR{9q5u=l$S=yQ%FioF z%*mu$6mZTPeVj4LxL0-^JO3X`1Ob4a8B~$tG5=)Cy6G5>E3POE)YK{@$1GXSk&#~lbM4ZtoXPn)a4#?2##Nr5Uj_Hy(k)UT!y)-GxhTK5 zI5kBVl$4-xI%6x6>x&CAL8%fX1&YV5ka%3pms(Mflb-@|0>~2}SFPty&M!~OuT;oL zgu7(P0^Wkeq7vjdU%HtuC9^oa6r2M1<)>W5KAE=KL;$Fl$e~Y04l>lCF0VZvMA1igbJ!tmhmO# zfx;Zw;^jPPsfk5trHC?Tg?M6KMP_~}q_BaQQw*!|H;5J|rYIzpmMCE4sioY>MaXeH zW04T3u*s=ZKoegJ$uq^tMbNfMW}X7b5uk!+BR?qa@=NnlkOF6#KtXCzacWsAq;`T9 zFpC9KGK&)n3i31akh02*c@m%|Lvmskbee==8jYGM&Q7tC16RgzhRWYub(%0!gt zUb+#frYSB-P0UqDE6UGR$jdJVCAJw$cvAC<64Q~4Sjd%_myTq`0;G&qT$!7cpHr-m zp9fEUOV)_P>S}Q8f{Jv7jQpZJP^`}A5JeaU@d`|8;(pfR?9!YZmJjnMHHd(j;0g|$ zmy`1IQj6Ih%~bg<%1M1nZ^TeEG9!5 zh`Z#FMIau4`4&`~fTDbdXmVl+L<*dkK~9A>5O+$$6vLHdq$U=Xz#Ch;h2Rq9MUYk` z$R{)QaKl1a0gv2|9JF|fcnkFIq8T+{l@*x#CRA8S_acZh=UcPQ>Sth8Y$jeRz zHCbnN2!kAeMWR!rxF9t#8;eXAcTRp;szOd`2_(cO^$38>fOAXp)iJ-bc0WLIIpeVI0Kc@^@K0{it zljd=il;=Yffl}C{sZiIXq$cMVC4#ymARFdGU6WdooRgRf7G`@ick%lj{X9uU`PrbR z7$_n@N~iFGZ3Lz1w9KMZ-bZtnyx-9et|F!^<;_ja0~c0cHOO)+cXEO<9$1_WqKB&> zGcOzBG?owZS8nIYFG|cyPlbytU&vFLnv;`X4i}j;n>)QI71=ejxRP>85n3kA6aaTI z6i`H0ZsjQ`Eh@-CQa6Vi)C$Xko4lltJ1GZLz=9pf@?rk8C0yx6sg-aAE4Oi%XJnQj zj9Ajk2}*Pdxrs%f>VHxv=#PDpG)y1EA1b1gfQTGC>VI5O*nS zN@i6RD5*_a%?B=Z6;g`w3vyDy-H%Djcv2D}&C$g2M6jwAEE)MZsq7!-Pu=`}M?YV2 zL27DphC)(ePEI}~0j&{9txQ$O%u|3#l_n+SqzZnRKd})OP19Gr-_b9WlbTk7s)+r= ze27#LsF$Vyae5M1KS*l*`yKuKB^mjp=@})+Hm+rkii!exW(fmtKq|=b3Tg^Y`6-o* zjojslkmQ({m(ucK{={x!Xe$_8m*uB{o98Vb<}aBg32xPc3&XU`y!6zfVuj*@oW#o1 zl=ctvr%eErYf!Bqh0TxVbn}*#<|HTPDS+GJsVyJoPn*UMc6fPWQA#n)k(mAs%{ zJh+MhIco+Fs5PySn+kLNl9@7~m;ze}u?w8GLGA{H4Jb-GWO1nghY(0frxY$Fr3E1Q zHs0LKl$4xQs7F9iITfe9phyF0Y8OOvP-#KiqZxDG@9397lSnK9k5!aqrk1A`fx=`f zCpegj6(H94aznW=qx-m_Ni8k2xTN{foG#w{yyW~`kgq`^AlthHK>pWFgZ6;Z>8NX_bPT;TQ`T+akSP!a_> zTcIRBJr&f)0NJ{U6RaX5F&iAWb9vJ8b3n~0uxQJN`7`@@%8S7L2(Zy@kLL7(vQu7S zW{yHZeokg_M$3o!lUmt|Q*+WX!A5N6P0LBGNKH{l%1llz0J&w-D!$y*h1vlLSQ&4=869DL_mHMgC-V zP@fwb(_1(}9I$IZp|}+mRIrX3C@=Q%fPx+-()(fl%wDk7Ak(3tjwuOt7sOHpXu}m` zRv$OWET{m;s6Mz+ykJ+r6eHw7CJ94Lg473~Th0 zL2hd20!0sm4{}XA+%-I4{R-$(AY+7}#(=t-pvogN4^%iWS;h}C3rVo|!~7-7;06jp z48$rAGF1R-YH>zUX?i-;%ftvO1eRXHMpeen+(o52yw7^ zALjQ>hUOb28IU<38TOLY#N>=rP~i(LO8QrWO+ko5P3d0^H3dlqVoLvN)~wQ$^i+fo zr@i0N53UVh;$Sl#%>s#YLwp980hs}jVM|La%0+fc&pvSCfD407`7pm{A2ewoBtV9M zBv_L3^Rp2l(hI2)pn_2Cy|AJcCJfOGQVVShAPktY99*!$8VQJcWy*4Bv4$)KF=)zi z&^R@?%?pWngmL|Ag+TG1mI!GQ!=<4v>t8DZ2^>rX5TpCo^5&a0AOTdW(E(|rO4>Sx43S@)? z#E8BnY>7pv9_(8IHUcgTGhziaeIX>EMyy~h$jr$vfhY7i9k7HB69*gd2rLdw=x`a3 z84wxH#Nv{o{Jg|cq`;ol01j+q8L(L&=Fe(?1~!Tu$TW}~H)ymX4b-zm&N;ItL5jl6 zqEv(&%)Cjkf)G^}YT_h5Q0qAvG}Z=6Y2a4hI&iW@6$iC1KvN-*5+9myaVY^6hny*? zC8^0JnPsW%ALdWp3YyUX#S>g~0#p>ebj7X!WFl*NDWvT=sR>-#fVrT$vI%YmG!oEc zz?$r6rW-U-tXS+DafmkF#en->-l8{V`R~^VkczX{t z37!lZkOy_!TG6iP}fQd9Cl zUA3*?qze}U)sdjd6-df}CSEMEAUD9w0}qjurDlTrAsfKv!G%B`+W_|%)I2P*AoKVN zic-__67xzFz>xxS-3A`G7^FqJx|ts?0to_8Jhbp76{RK?m*}RYrh>-$Kw39K3ni$K z0;n4WsskWdrFRdwKtq>=^kI7Uz#61z^3ZCwcMliHH1Kc~*wcHsgA?;g5*3_t5=%kR z-`C3JTU4wE=P%jDkz1jV43b4E1Y06lmI7l07dTL%KXv}~4Jg|qsT;31!m(PQ1g?boG2Bev-DnB;~qI*8LLWA%@ z+ULWyL#s4&DUg2F63|RI%ZK^Pd&D5VR!C1R0guAxCKeY%B5_iiFvv$}5}?8s(c=+? z_ztHUkY(sLfO`JPrJxa&N$n^$KqWvnAo>JoHejd$*}w<&LwRBjXga>-!~9v>z{vnA z&S8n{C=Q*JUCTdGS>rYZs6v{JFQ*)9*SqCXh_Gsf* zif$LQ7F)IlZkII3@3<|3d3%or9(Cxpz%{{bk%fc=9($mHuty88N(`G|+Tb?9GC#aha9hB|01hi)zTc|~3o=6H!*#&ThZan@Y=HWDuR0>I z2-*SD1GfWK;1-pF7k{>VnBU(FE^wg&y&wUQYVg<)w7|uX1Lb;Hm_sE|f)8#AxFmu4 z3!B1eaO*%ug6swB0EaYw^(f^C)SW4bd7uShpm8~frw{^DcS$1RzPL2AL?I`&EVBeW ze+}y5YxFYu^C0sE2npT~^CyDK8*o^GN(Ovt zKpup35p2XbH+I1XSUAQyJQ&4b1PrX;QMNkVQegXGEV3+R4JM0A#QLtbi#>EiM7I6 zDF<>ixKab#AOWdO@F@dXB@T@|m^#qRE@;UIsOP;;1lb~(49J>&@CX${wFXlW$P!rI z$tq1x2L%tv@SWhi0}}xmis;os^A4sY$S?`0i!<{Sa`H<`ixmp;i!(ukMxf$$hA7C% z7*e3(aR%JY;t)6EQ3bLGR*aND78EBXmVhR+XE(r-J1B*wf+k&O_lQ8_AGVwl6bi+Y z;EmTMpuQ)F2gwA2x=rimP3K3CMJO>u> zm4eCnrJ$8i;CdE3s}6G7L>UZWh*4nMr(n8s;tDBD9Wd8|)T6m};tDxT^~i1p=|KyN zi7Um@5_2NS$Si}IgOG*W2vY)0X+o&xfNTS~9I9$LEPF!@0!gEr1amuDN`fc_ks#N@%!Amv zoEN-^7gT$L2JbWHjXH5LgMedRW^Q5*XfLB*B4{xo!%Xhn ze9&TPP!AL|EIVN<8$^KR!~6-8*wgciK;z_~g;~9v;N`ugC5fPg&dZi_q~yc5KTg=j zoRSY(KQ>`1XL@O7N~!{cyKEhIacWT+XdX8uKb`x-{0URRPFuE%tsp-?1-$=b!b+C% z{G2q9eY=>`@+&}gb+H#ECMQEy#4el50a`Q;TFd}avymCHF>aJtsB4Ah8IvX>LLr7o=MTGk*(fZa!qM z!0JA>6mZyp(nCKhSQ$urAA4zDW^#TJ*qRpBs??;SM3AE=v!tYgw+k)nVNJ>`hB#vl zM{<5S+!5=T!2X-i#0zO{CY7e8LH03DXl70Z?<$+n!cmZk2-xk+1)1Q0oyL-sp9tEF zG+{be0cgP;$TfSJixNSr`6l!;rt>YZ z7AU~QRJ+$ZQ#$zeGH(C_k?Rwk8!kl?Inw%94}`Nyf|A3sOOwg+PgN!g7|B{4&te$*El+ zzosUpgLB%lR+bdVCf8+cEXC!Je7uM`zZ{f8mUXhEusIJ28QB|oPi1H6)T!Wx$1)I@L~tz}8eEC#JuoiLxbq$s}tytWl4 zw15M&X&A;^$Xc8M*;=rygFQdFB)^~(lw~H&Z`7#qEGognwsT8y$B`pWEk6>9hb5bd|T$s%a&8KrXGC*5%lTyKfGM6nW zH5C$Wt2S}xB&Jjp6e4qtcMU|kHx5dTzpi-=72M=T>BP}Pt9Gn0rtz!lEKv_P_ zU$vdRD8Cp~owI+K-w#?>!2;s5e3;*}leauG2fVEerf+EjM@D8+W^pn&)O&Vu7MJG1 z4ei;@o|KahvvUt?Nofvv0ddcEj*Lps_#Aju@~Yh&#i^+&pw2YNj*UD8ph6)L3DKk%@JTnhe|MfO=rRElt zR4U}9f_IOt+Q|oEK}Ks+)4>b1SMB1+EiKLfjkbb}YhmDV%g;|yP*ZRz%FN4VXlF|= zN-O~H`0Q;|6_V%*oCg!Ds(%RCs;0;M|nLg;&BDg?5OF=5Q z#_XNI3M#cg$-8$V2RO}TLYzB^tGJ{nu{ zm1csH?9#bxCHc9D;I!V`%9@{(SqAdV>PhU$`N{ctrC>En*%Qn1lM}&Z>C%ZDsp;vk z1k>Bb2C6B++LumYONN!6OQ&*!R@UdIDL|VQJ$t!8TZ0QyL3`5KKg{ph1{xqvO3lep zfQW&bBojH3OOs1;lfc0p3Mi@iUms}pojzwB7c}ae>E#;sR=lp%>$L|nZ?DBth00iUs7UvDJU;1z?3YV z#+jCrSOVj&p3GiQlv+{+Zoe#D!J3qq4q>k6C`impPRs^J;nI0*<%wx&;KZ@KohLaX zHMKZZp&ZmM0C}~6CpR^*1hm%;y1$@z8ffcaPDxRv0%XTS?{x0u(h|^C8jwm*P_1N5 zN=yc)%%zh#GZJ%?N{b-1eD4&Vw4&6!}c*x4oN%i!(sm$I2B762V)7(jdn{ESPC^2>7|*}S*_($ZeK7@CEO6LS(lk+yU?dqI8yG)?yIXM@y0 zpm6PADNf7*C57cp+{uY~c_4Q~tzFHTl$uwPuaE?8>h^Br0hMbC$wi6D+2EAgJA)G} z0vZ4X6(=*fL7quXft7!~v$&E=i;61Y{Mo$VeY~J@3*=^yo;jSw1&QeyptTzy?p%?g z{KR5V@n2k?np&a&&t$y|Sn^ZA4X@rsti_-`U?Am-dD6hU$BQ$HGIK%uMtYZsfNER? zP@;kcNqJ@wsM_sa%9)#=p9hu!rHys0DbV7lcOgegX>I|ua#%W_FD<{Qq%<#80puI- z8kMCBxJweVQ$d^bAz`s}Axm;mBB*3v*1(>Vp9F0NE}O>&cgeB|tf0yi6!^;~vgKF8 zl&s<_&QB{*0Cl9m+pt02SjJVHkq9~^0a9=DF6Ts%Ucr$9+Uf_%!o4fm;O^>O#ha8_ zRFaXBSPAo2UlV6>Mt)HVC;&i4Z(vU@Er4>CH!>GM{Ii@lIU_$gKPRyyRUrvdvaV)L zPRvUImz`@kazKa66y$?LbS-;wDd=DokWYHoae|vBpm+h9zMdQ0icQKdfizHh_wa%b z4FG4t%p6ctd+BT*P;N>B)vt-^smzaNOl2!cO)LO!TwXm*6tpzEv;Z7epzs9^@`8(i z-mNUfkY-`;HVKFYU_}ZA`H-y#$@$>jp1u3H%0VY?fb9jjX*(aN6;uM+Qw0~>!3S^R zrGRQWkh+~5NvWWdOTdk<-d#e;IncvJV8Wm_Uhi%JxH#A}NKw_qTT+^vl#^Pd02TzL zr)Iu_{8I2X`JBwc(o9fjt)9-84E347kdY7W3it0~;14NEEKAK% zP*VuVNlZ>HX1FDto|B)Hs!*H(-VveTT3VD}kgDsLR+O0xDnEOA#ZVPE=B9$AKrZj; zlR=X!&P>#GECmHmP9|7)zX(J{IcOy(NM}kWq$=x~z*(MOlmi;`F8~b?fsW|m$xSQ( zB{r|b0&pj2`absL{M>>>@Hs!r*NT8Pl|Gi9JAC+G+h4%qA$+oRbV z-tXvVFU!wKPRz>(mG0f3zHeTMLRx7SsM4Ljn>`t{LN6~Jq#3jsLO2Pu2>}xBrMXE( zsW~}`AUV)>0k)LX;?$xN5O)q}$uNYgkXf9Qn3n<)1?`RG%>(c4PRvmN?J@_6&I7rj zxFj(pvosgPpAXs_oD4dH1Kc-BD$N9+J^_-N{eDNkC`>>Bc@-~6b~>o5m;~w?hd z`TYw7!Ayw9(?L_*pnhuqLVoBneVC&_Y8Q!sqXkrr7vvX%DlpLMY>>=iZZv@<92xn= z1(_w_zFGfLmZU^*KfQk$Yes$vxX$cf!3An3E5P}n`IEdd&>F${3jM3t zijy<)^Fc*^|7wAh)PlsKlHAn15`>C1?9jamAeXG=hr1DUas{~P>0i%=U~gbAPfY?dC{>PWLiDn!SmoBsH&u`O)lMtZDh_=^%@H8U^w|6W5UF0hQX|OxMhr zoLN#?oSawy8cOJ&30mY)T$)#uS)2+#kqMkNz^Yr=p>m*%&?*Sms*qTskWvahVW+2! zt++I=7~J{mY3ENW%1lX51<8YL2kGnN29^57pmCJ+Vzx&!K^xuqk`s$SsVxU|$_98K zsc(S*XeKqi2z2gMivx z;!a8|N`lPvg0xNQ;7-mgN-ix{0EG)k*D9`@{N#MlQE%YJ{j4U?cH*3JaBT@PVpg+2 zMrL}3E@*>(ib4r=yX&kLo}|*8oYWG8NGmH`vW+!2wWJ7CNX%;If}C(rlnCzF&+1?= z2Cbw4H#lc?vXnrE^JaB%fR4z4DFU6l1)Z@62|*4Mm^F_Bq*@^vTmsJm4GDmvVpb0i ze7|!NxR*JrmkYe|HMJ7T?_U+PVpDQ=NB)=%RG8ue6LqBMf zH7{65p*T4|A95JT?5&`cBdBZSK%<^}MZhXEt5B95f@Jpag1iT6%w`v7B!bQjo4t!Y zDHCiB$R(S2vNMyjk*(OmRh*qzk_sB`1+@oe@8p4|Vz4mFhxxPja3qx$gNi0lQ)^Z~ z2iWfN#7g!L^Jjx5KtOxb!3h@RW6;RyY|s%O9Qm0!3Mob4YGU>x(0-n@($pM2W`(n$SxIwo#urpw~Vv6B)>obbYua@ z_=!BoRS(GMQJk2W16p0g{Al)8P-8P6lxb&g z;{@kEkOatpC48XDI~8>9ghFvfCa9vH4LVDsUj>jJP(UqxzoVZ8 zq!?ttB96q&B2YIyl?}3UiLW>}F(*d>CJNF3DpZAF0t%2iq7+zQoj`%)}f}NasSu7IGFRmZaw7WR`#mYjDei4OD}J3)@)@ylId# z+=>%Rlfk{P**kbZ!wDJr1qvV<RMt*4#xT&g;lAo8#{HSNP z5JD&~zXU4WznQfhG>*;usAm>;VoqXFF6i94})SQCM)Z|o%PS8jrsBtAwQl6Sqma35ds9|O@NC(S@`BP`}LPT{- zGBP1G=hWrA`FUunCUE8Fr6MVr!wWh`2gRU?prdt=l+5KX$tX%iGiMSHSP)6sJU;L! z9Ewqsxj|w`istjBfsU&~Q8a}cB!;AD0dH|;1*+$!ausJ*ASqeM4?0LI4^`1L9G8zhFLXbEpgDw>5exk^&=kd!PHNX&>32!sUtJQ{T|lO%u#X#A5Dr5vY0$m(1YB5Sqyg z^8{>)p=XvjrhDO%v&As%gv-t022HF$j}`=t?145_Fc+8Ru|1jrS`ftt_ZD2sT;AeR z(0DE4z|Ed{yr5Dt6*3eJ&f=>kuz(tF%#YSi;7NxbT?!Ha1^ay7;*9)!@Crqk&;rif z%$)2>1xV@9)58irXp-&G4A3D%0wDX6QbDawPm`aOi_%*MRz0pxQbgJZ|07zz(uJ2|QQZ)4>lt+7;HB0|j>z2aLz|Xa;DdwFHb0 zaSTX5_>`z(=0`K82*D-u^AsRWTDC{CK_w**sFkTumY-7s9s!xPkQ3y+w4B83RJKRp zSxk12KyD%^?KFeVG=y@&)_{gZKz!y$vs+k`K}T7#J(>ZU`eXs^qXl){m$E~Tssi;< zmP1DC70MIAjozLv1};a?7S_y?%+z9rP`<3hGd|uZ0t2IB2&ws3F?d#sN7D4P4{&wSya$h=IW6D`3*a%#Y@*Uf4@fFF1nFQ}c~#aoh?mzb1Tk_flI8+2GxsshT{XnnnW@XlIFeohY9 zWqrKKiA4pV@s-rXT!;<*pb?=I&;pHIP!pqXf+(mEQUD!01TL~ti&As*^FaNjzKJ}b z(^FFO%2IRk3qXpOFK2@v0oT{SQ(goaJ4nw=1J(C^jr>Kaxu8>xiWDHq*gwqg1NFBB z6H{_C!KcM4fJSLjOF&)fK2R5)4Z;Wcb2T66l;{%BF^IXTDTz5C&ENq8(CAbK$U*&W zJm5BSu>x2DsE69hZ&+LcnyE@og$pii=Qqj&ml?={9sI^c7=oSL#res}sYT$xW_~nl zFGo^haVjW=m>51Uz>hI@C%S_ElQOL+ohRnP7Pvio1S`hq6965=QleIw3?gh;&r7INVgU`M0pUjyA zii^AwaDCFhgC{8;TvMfkh7UmMyF_w9-HOB<1<={j3Z;3OX^;udrQICq`H49SdEjz* zX)8}!PGUM}kx@o|PAc=G*_*+`vf#Em+oRc_`BR>>Oi+g%WI1@`pl>mEN+$T6HRw^a zOZM}^_HPt}+Bl$8u$QGc8xk`6S&DN~!99cRyr9E)K&caSLMbRAF74p}^+JnN!RI0O zt!J&w*R2F~J6AQZWM@L!p^ZG?i8+OW%;FO8h{u%G+y(jhISLlw*alg)kteyRvbZEM z2PQIQ9anB*dSUL zt#1H1t#1PdD6SMzz=O$sn|KOJtEzHR6~N6t(2&zgu9DOg@H{oRpSgSodqL*mjfo|o zF^pBM+_{-WMfs2f2^yAK$qSmN1o<77saLge6&EC?q$+@RsIWbnxd7Cs1Fw*UiGV5@ zo|MeQT+q=$P*tF+g)=#)Gzq2%)Pdqk&H$a>T##6v$M$F@C_l1hUCdbPsoNVp?hms1FXF9A37IJufvmy96AA6Q{73=)#ic#Hp-V(7D5j(^$c~ z=s{7sm<^nNKpA@Z5|(7hvZUopS&Q=_L(xu`pu;9NvLzK|rlx^RUb%^_7&LhSW^ZN#?`Qz&oj4P+-Q-cj z%wkYeq9gJJiIh4v{e=evo1({1oN=yfp*Rw$*1stFw@(L2c3uF2~eFjhh0nGt|yMimXfEMC|9a5YD z?!iu+$Aie?5Rv)Z8Q{$w3Q76kNL;!PJRb@gF$cx-(*2NOC(x$GRM27D5M2u(=V3w2 z2CZZQjbTn)$O9^8Q%k^_!2z=Yvfdx84r;-~MVz3`kqV$e6;PI1#|l2H0TclfAsdOn zsx!dLswPfi2X*2hoW7NO=|zbtrQpG6h2%ugI7HuMuB6PIoYWL3fB7PQc)gX8nv)AI z9#>7105$zfVduI)EC9>0J(@icRBRL!C02qep43F}(eab_bL3<~CNV(mlol3H%NNAz zG1<)C!W%)U!;HqLuhbT-ObOd;5 zE~t$KmFg6RNx>RlPzlhfu%#(bNtO@uCokg6O-)ZM08MOxxR9~wMDQRbXl#4(dX^-} z@}4PE_(3diqfDVVClS1SXv$RH+|pw32t8;q4Jdy5_VB=j^76qYb>CLFB9I6u8vC|^ z=801>^A*60YQWZm+5@1$SsqZAEC(_k3R=F?2O5J1HJd%JWV zFxO|NR>H=v`gXFH6qV){faAVz7h72-=!ABV9lKeR67#Y^cC4Dp0veP8)v=A7IiPF< z<*ov)JS<8~P6T;;RXZza{R$|cR(0?|h7lED?wY(&99aYs)QQlOdM9t5Mp z<%2pc9I(J+d(;Es^T9NL=Anu~Lp#$zT?0<=z#b@zgQ^YC7z!_3VM-==uzk{A?zEiz zf`Uo~n7}@s`~vWK`*4x{%qeA{hQ#Csw#1}F$V#c@>v(eW%Q92J%S6Gmd3{T{(=u~F z=V&M9rh=0YXwHcbELKpI52|JILFsKWXabQpIVTacXazLP240!iw}uN8+GVgKb0_a& z11&%Wn>=~DAcPHxu{3Drn7o4r(zt*~g0k06Ua&|q=xF&8aORl2Md|c?*d{Su+XqtY~LN2hIz}-iX z@@0achJQg~0jNxYcZK@bai(NeCMx74f>#r)nj#0vu1Wd%*${uhx+7(v#R1T?HiaA7 za|9^^`EV*H_^?nIcN*yQ;?z7)U62iup3VtcnFQy~;07@IAGR; zG)`vA0WF3BOnBacYWgX@LS<0yM7*N)x;wH-OGlRwzkK0=s1*2TTYQeA8HS5|dIv9hiR5(n3z~ zT_OsQigwZlmgIc!a?4dSc`89ZPs{_gWNHFB6r(2ZHk4w{sOEO42;P7G8g<(GgK zB|!WM;e!$gXgr>+0JI-Ehwagve$f0w68OaKyv!uFM{_2D>VDWfr9we!9;jpk?UZGP zvO!Ckxe5|9^GcG6N{cf<(xC0oY{^B5mHA-RpmrEbZfY*5R+&7PGYQl{Oil#1=_c&~ zm0_t0pq3w`gl`l8`z;N0*gitENf^{>R{-_ZD-=MTvXs;!P?0wsG>*fOoS2iEmjbTu zCbtTLPQTa9PfJrk7H;E%uI>dT$$~`C*w%EA*Z85rFtwl%nGEWnAnXGrlXe00ga;Ds zfQqK1!jdCMw39O_u}A@|9>ne9OwP$HfYrQ{yV*gEeu0vrOwi>Npw;zo(Fq*I$(hB) z`9;NSkLG{^3^d4+q5ux!r2GnymqEi+JYa$3#H7r;RM2vV>7Y?5?sCuqF33m%NFk^x z$Oanm2lsTROyVfbL+~c^L)efcRshbFQ~FT^A!7hjCNM)86Tt_)W~YMY$fkoj7APVGk%Y^^s{uiCC!oG2TS{Vj zI=E_|4jRktKEjfep9`*97IP-$=jWz^PRs|jy_eDG4eDJxmhQxl8W9?b%^7Fj_T1%M{Xrh`|TBqf3;fE9{C36u?TOeGg&DK_X( z8PH7TdKOR;0ogSjcBug9aFsmXN3%gG8N9J)(o#0CSTP$!kR>BOKO5w~x$GtR`8kkc zV)+I(P{j;x6fWPymXny00!~(|=CCK`q~<1NCbK=71sWdXEJ-acQ79<|uN_~$imM>C zq$m^AdI2rvUA~$*1-wLf`5H)bwm2Cw7&m1NxWNbKt`&q&jVXZY>^!ip$qU(wD?xn; zP|Q#2=utlYs;kO^L&KdDO~F(o6l7&M=Qxc6t}PPXJCP{$C|8{NZQ zT#{Onkq@(TKRS5=+3m+0)q|BO0L4na5V1nU?|{ zQ(iTnIVlxXY=9FXUvhqFat1gSL9Gi=QUH~Ste`*!nYn5rTSaDB;a+1T9i3P6gFBpbCD~64s)`DzKAQP2$Y~UvQ@YSvd#l z!EfP$4go+)lI7c3lc4Lsm+xeQWLJ=~UA&-X0Vw>yr3y%BH(OF^ayHmys}{2q=YuQ6Af)S)eIIaMuPlJho~XcUoy)D(G^g(jt%w zP-B`WFR?1INFgz|6cUch_p^ewCxM5Z*0AK}CxQkOrtfDj$Vmhh)*y#27tTxp9U_{R znGEX!gB!c6Rxz*#L+*@WxXA~`<~)KdfnX%l$$W_~UxmS#8eCMAL=g+XWXWrB8T z%x>WUwXqctlf|=J*~=4)KvP0&k7j`iLqYJ?#G=$Z$YlnQVcS_dIP&rpz(pAIquEoq z3X1YUdo)VGW&Etw+FhCa1+RT-guTY$u4?6Jz6fkRf^70iR!3Z^Pyu%Jygmc*R6gW_|`JwWP2;ngJRpdMjrU2x|DCfWun z$GB01z=!k*q~w?9p(zC|rQ-sL!!)k}Rloco5nXV2Lv3mUmET;*B5PXT@95_(EkIQU znj`=Tf((Ee*#=sM2)XwnuHC zSu`;)2Teg~0o$V`p!FA6O$WJ+?a>m@W*$lK41YOjc^P~y3E0P=n3~cII)4B(`Gimf zkp$gt1sS!U(!%BB=4x;N=9N)ZX(;G8K7wZj>^nDh04Udbhbw`Kz&c{9MFMEko>~-Xbz~6!k1rEl98X1 zUjY-H0UE9r1X}`{dWB6@vpt#t3V$BZHkVYm<7TV_&0XfE=H(Y9f@;jEed5sD20?2K zz&C+_1`;6yI8)ZMWrK!2!NuNsR!7hd2j)jJJJ>=JON&a2nIFyUWOE12Vr4Qvn%TwX z3|cN$#QbPxH?vP_KJ%lQJ*;7wMd=_`FRM>xQc)uFqnUl|!H}I|%#UXFa|b7;XO@&C z7G;7>o51OuSWpDsN6Y+Z=0pxh(9}OfY7$#OW^r;V$j-@}{skGCrO6o}J+u2ni!(|= zn>|34S8{eSQq(u_7Nr(|wt9f}D1hg1rZkE`g+TqcoKz&mP28aMgHQpsN7F!~;KFI( zBT@5h{!u4X9 zootV$gXZ?ZRw$rKF+b{G1zDm19@0S=1ByGo(gKicko~!b59CgT(gLVT=12Xj!DR`$ z!o31ug`oU}P`ZW(&9R_#$XyH?nSz8H+oS%SprWJ*bh}gvR3qD?e(S6?TOa+oM^aH3J;Er8y;;1v!;$kLG|%NtS{fPy(Abl{Ggr56qgz2I>7V zKbkikbhlPnr9x_9DQN3FbQ#;@pt3^{G`55y!Tf0MWMN1n99?{h7(^V|P|(N=^P{;_ zML-5&k(ka|o>*3?0J@Tj?QsLBaU=-ZX_K0lT&a*+0lFOqe52*0jZhCm$6TNup0tS% zG+dsXm;*0hzz6&b6s3ZeM}X#2APo(+M>BVWJM%fIrA4|ask%9tpxzIto55F71a3Gf zq=NQAfSM9hHge@9=7RQ)NS;$r-81+29a|rb6aNb6Q0pqVS;-FqiGo3{d|PG|LCo!S-klsCUK%?z4f- zV16{WM-ah<8#%WRv^^=OQXwZlzkvDCybXfTXa^0b!A19rf)+3+B<6rtOF){4px9x1 z+yELR6$Q65bc+k}vr|(PKpo$r%;IdeM{_`9Btj5Lp_(Hu|($_`yk!S-k_sA0gF zoL^80&SI>GK(#YhQ7Y&h`qZM-6xKta;)AQC2s9lEw)jyCsQm&OUQSLdP*7%923;oB zyci~+#jb@aV8CvGDqzTNh$>*jZiFge%x;V-V8U*KDqzZPiYj2nZiXsg&Tft>V8L#I zDqzWO2@&ATPOSv_#n1p$w9FUH%qu7@QGnE;rJx~b=+MuU1t?PB@hh0rLSBfjJn%M3 zP>D2U5mX40_`pJog(0dSW`n0?i@*{~L>-~&LO}!EZ&WC$EJ)R4|1iH5l)J ze3;+XCyG@Hq!ZL7;dJ(a>I5mC$nEU!k1Q~W+bzh|6-mWp?#w*U1T#3Lu{~-5mEoM8 zE=Ve-a6)oQih?iOqsgGsk;~6D97(}cPCs`f?le(& zS#=R;zfM_d3c^s3n)R~CYLXI*(i1cDP?U5|Krsfiz6G>B14T{8P846@bJQ#aWD5~p zDpd0}p{PnsPEIW-0WB#;QPnw75!o!zPHJce7e!ge4rOFzpbjLc^asrdBSi-&Ft(rs zMpN+4|p%O0zzaFczZcQV9Hir=)IN*HH$%GYvp+eMe~>NK*q@-YM39*S`9rT0WPo# z?7m`93mPON#mY>%daI!sU}qRD{nSQmjf8ye5hHAA4d-zEf+0Z+#viEkHyn1ZQehY&;t zUB^ywP^totP^5#_K|wD@22Z<9*(Hfp64aarxnj2v)N05Oc%niIc*)451w7zE3q;vD zWd<}*A%TS?u^Ac>7!sQpSlx0G(~B8-LFaQ6mVz1-3ZO-8pml|f{16A1f=2$Kg0oig zf*VTE$t6(L*w+I+1qQ05e+zUl8N>%|xB<0vct9&*LBrl4LB0?3`$2->VdS0;0pzwj zNL~OT4{5`5gDyEQNd>!%_rv`DEuh1Fz&9w1g48QGf>xM=?rBx<1aG0__%OeH*@yY< zD9P?80i;5CqqAMlAnnLq3L5oNnixQI*Tyryv5=&BxVM-o^)!C`t#7Qs%)mY!`-zgEq*57Gwq|=H|mCcR(!$ zZL38%XD8GskZ58KLVOo!YCK)Rv8Xf&Zo(dj@rPSMTUMdL4iCP)P{&rK79}NSW+mpq z9J?P9^iKK3d6}TV^GGeKN=?r%%Y?XlIVj#B0qB%il$4l~4>l4cyc}YrQzGcn`IOY+ z43Lo^iIotqIHl&KXO`x|L{|xdeeYCSl%1KEsNj}ZoDY*)4Yi;&Cq1zU;z^J>YoO*N zW`L3^Oz~Q%XlYStUP>lRbR8r>oKo{L!CnLDUoQf-F}Ore!6~t*B;)YPoYdS(m=0)6 zJEa!oLK6!}4>YEoic0fR;f8O9S_wLF1mV0bQefkq6G5wrQxo$P{J@urf z$Ehf>Dl-RW^LD6li5ZExiEyPmph`19XS~6b?i2#s;gnxmmRbUhQ<&UtXsG3vfKHPF zCj*cV_CQTf%}FdOg_{mq(3_a9;FOw^S(OSiVL!x5=fu23NOoBPiftLNmCpIe`Nawv z-jJIcG@*8b%>$`g0mVm^tN>UY4 z9yQGLEX&UT;`TLK_HhFJ|-j0AFV zWdSrrfb{Hxq!Z_=)Z`3Eq6UfXhlsj^Z=wO`m6adnw?p%;OJ-_%zJhyVQ8GjWND5lI zx@2W0fi8sySqTze4>89jH4oGQhKX)~gt80hI$&rBfD~^M2PXrVFlsshDcAxr%`qn( zwDk^V+I~p>c1|rV0hL_7sX4IneHADjL-e>NmnNp<7lHJEM4|PMD`-v%;t7!GDo8ZD zrdJk}z*Me*6sO^-pi@Bd6oL~o5+M~9NCUJGaxKa%DM|&$BuI2S#F${vItiFDJ0M8tFF@G16Jk2#9EQX^g;3C$KrlVKAWnD7%!4KP)gR`!uY;r$x6CYX!2}Xo4~ciT z#GGu9N@$7$Cv=eX27Yk3`hrdX%S$bW*bb7|1SwYB5{vRv(KT&>6bf!dpfP5Ui$EHn zK66h@g5-@gpa6z=0a|H$XXd4+LtFzAT?KUw zcs^gjy)-islG#9V(5k_`G_@$NI2D{ALBeYwA?==lq;xH$u5o!mlGqB#^R9)Z zpn2uY#2k?8^B@TVBo8hA-HTFFli`}SYlCAYIKQ+cLjf8T3Tg@velYalBIH;BnY07y ziPFRp(9kP5$$`XoLK200X(Bx6cR_*^;ssqN(5X+QFrVy!`nj|cDd6@&N?{Ms>Q8SF z5$qVG;G6+%0j&KnzkLIwIQIZux~!n4;G67{pO=`Eg6v3;vQ3b*?g2XIs0dQCfrO#e zr*lz$VhJRqL88zk<&l_K0#45$v7L}q<53Da=Mfy)Akkfrga)dniYk%qTnB1ULITD! z541@Zn#4ik(4^*BlnTljApe6zS3&&mSzMHu3a*bqf*T=qjAwBU_)G|2NaF}311p`V6B-FeTa}%M3Do7NXlD+baQXn1z z32uRy3GSnV90U^E3K8>8&8q|_s|_F{At~OwvM9Z>3f9;LNkEHx=fvEkd}yG6gx5l1 z-aE4>Gbs@gpCDmq8{0WQH@^tda0H2Ng5;Xu5Y1Q+2T<S=yFKX1Np78 zcL9m-g!ss(v?4V(DZjKR9TdYLiCvJu@kuNxLzulA674>jNswpLKCP+0kb_Sk^a zK1j!Eh=gxqN@98 zPSGFC@nuH8yc1{$<>f-0@eUY${;OkAQ{mwGdZy+F})NV zG9dAFkm3TZUj~wa*8P5<31@KO3KE1Cj(({HiQu{cBnB-U{Xo<3Fh@We?0%V$m;@=? z1+%GKAu1KLm@fsU7+RY6=RykMEg$B$Lrdm>#Jt2@uv@o+f(eph15%5?l{H9c6(k3^ zLE1$D`8k#FMjS|bHAFffv7j_j0TjHD8XsgaNE+I63dqO=^+-UYuP_;CVI7c|oe3-V zKpHkc5=KBitil8dZiIAlLHRZyGqtEF6;%C$(r^x>90aM^1a(MeNpfOl5v<<>E@(m0 z(BeFxG_|NCAJp>!7YZPm?U1f!Kw=JPJ~l5iF;4+jgJwb!EJzi!1swo7;V&H$Ga%ue zkhBw!n3D((u|1F!8;}T22H=PVDcuKA8kh)e6>bBCH$-XB;gzMZruTMG#Ro}XLHW6` z{0I_-wuysNi=YV`Bna)W2bC5>GY3czTGR%Cc4~s-79_X_(iaU*EKSK&0F7=zlI{+W zGav;_FsL&L?=pge4kQa5VhK*IOwLHn$$^9kNCKL1f=i)wJ4kFLB>sZSQ&UpG#Vbf~ z6(nl}XXd3R7UV;^#~|@FkP-$IuO6v6sgMRYNCKKTf^PcpYSzD7Y*!Cn>QA zbo{JWBB;QtL|C;R5~3iTiP;DrZh(3olzI{sd{XoCz~vvv(2Y<>fK4jO%mXJ3ki;fP zEChq<5J-%JM4|1-;QUbtgo-YmP#2Von*X2MLnd4f9W4iGpt;=)eqkVDE*bv*1eT zAQnjZK8W*Ni_1ali@*ggNO(Ua&xC;X@F(Ueq$Dahm*!=FQ_N0KvVgcTq_ij-)I4%d z%mj_bAhlpXidI014CjnQaA^Y)S_vMIRe%;5V9$dpCbV1yQn?zUIV3+F9O@t;XxlC% zBQX{MtT1c`2dgj`5wZhn!j52*JHDtACK8zCVF z@)T%v6;}3uq@WQVQks_u%}gNC&5-a6$k06c1W8tq$o2l zGbIs}K11@85)pobHk?CB%Mx?I#RW(cv?>fq%q)kL&LBZ(84{A1R|P8qK*G?onM?^22SUDLA_as!pPKINa3{)QSSRDR)S6$2gM{v zbSEVA!1)L|hzXL~4+=d<%twLRK;Xm)5`?xQqcU@o5|hfosRSep9g=kg4V34l$bhCx zJ}+oo{&_*;qR$H&mwsN*xDLwS4=F8zlk-bJSrA?6=FbZn7k^&RxaISL#{Cdqgo7$i SbamT5FKArzc|jvc{eA#MrkDZ% literal 0 HcmV?d00001 diff --git a/webpage/emoji.ts b/webpage/emoji.ts new file mode 100644 index 0000000..9ed3c69 --- /dev/null +++ b/webpage/emoji.ts @@ -0,0 +1,75 @@ +class Emoji{ + static emojis:{ + name:string, + emojis:{ + name:string, + emoji:string, + }[] + }[]; + static decodeEmojiList(buffer:ArrayBuffer){ + const view = new DataView(buffer, 0); + let i=0; + function read16(){ + const int=view.getUint16(i); + i+=2; + return int; + } + function read8(){ + const int=view.getUint8(i); + i+=1; + return int; + } + function readString8(){ + return readStringNo(read8()); + } + function readString16(){ + return readStringNo(read16()); + } + function readStringNo(length:number){ + const array=new Uint8Array(length); + + for(let i=0;i127; + const emoji=readStringNo(len-(+skin_tone_support*128)); + emojis.push({ + name, + skin_tone_support, + emoji + }) + } + build.push({ + name, + emojis + }) + } + this.emojis=build; + console.log(build); + } + static grabEmoji(){ + fetch("/emoji.bin").then(e=>{ + return e.arrayBuffer() + }).then(e=>{ + Emoji.decodeEmojiList(e); + }) + } +} +Emoji.grabEmoji(); +export {Emoji}; diff --git a/webpage/localuser.ts b/webpage/localuser.ts index 4f9e1f5..72d25d4 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -7,7 +7,7 @@ import {Fullscreen} from "./fullscreen.js"; import {setTheme, Specialuser} from "./login.js"; import { SnowFlake } from "./snowflake.js"; import { Message } from "./message.js"; -import { channeljson, readyjson, userjson } from "./jsontypes.js"; +import { channeljson, guildjson, memberjson, readyjson, userjson } from "./jsontypes.js"; const wsCodesRetry=new Set([4000,4003,4005,4007,4008,4009]); @@ -295,7 +295,7 @@ class Localuser{ } }else if(temp.op===10){ - console.log("heartbeat down") + console.log("heartbeat down"); this.wsinterval=setInterval(_=>{ if (this.connectionSucceed===0) this.connectionSucceed=Date.now() @@ -375,7 +375,7 @@ class Localuser{ div.classList.add("home","servericon"); img.src="/icons/home.svg"; - img.classList.add("svgtheme") + img.classList.add("svgtheme","svgicon") img["all"]=this.guildids.get("@me"); this.guildids.get("@me").html=outdiv; const unread=document.createElement("div"); @@ -422,7 +422,7 @@ class Localuser{ const guilddsdiv=document.createElement("div"); const guildDiscoveryContainer=document.createElement("img"); guildDiscoveryContainer.src="/icons/explore.svg"; - guildDiscoveryContainer.classList.add("svgtheme"); + guildDiscoveryContainer.classList.add("svgtheme","svgicon"); guilddsdiv.classList.add("home","servericon"); guilddsdiv.appendChild(guildDiscoveryContainer); serverlist.appendChild(guilddsdiv); @@ -964,5 +964,55 @@ class Localuser{ ); botDialog.show(); } + + //---------- resolving members code ----------- + waitingmembers:Mapvoid>>=new Map(); + async resolvemember(id:string,guildid:string):Promise{ + console.warn("this function is currently non-functional, either due to a bug in the client or the server, it's currently unclear, use at your own risk"); + if(!this.waitingmembers.has(guildid)){ + this.waitingmembers.set(guildid,new Map()); + } + let res:(returns:memberjson|undefined)=>void; + const promise:Promise=new Promise((r)=>{ + res=r; + }) + this.waitingmembers.get(guildid).set(id,res); + this.getmembers(); + return await promise; + } + fetchingmembers:Mapvoid>=new Map(); + async getmembers(){ + if(this.ws){ + this.waitingmembers.forEach(async (value,guildid)=>{ + const keys=value.keys(); + if(this.fetchingmembers.has(guildid)){ + return; + } + const build:string[]=[]; + for(const key of keys){build.push(key)}; + let res:(r:memberjson[])=>void; + const promise:Promise=new Promise((r)=>{ + res=r; + }) + this.ws.send(JSON.stringify({ + op:8, + d:{ + query:"", + user_ids:build, + guild_id:guildid, + limit:100, + nonce:""+Math.floor(Math.random()*100000000) + } + })); + this.fetchingmembers.set(guildid,res); + const data=await promise; + for(const thing of data){ + value.get(thing.id)(thing); + value.delete(thing.id); + } + this.getmembers(); + }) + } + } } export {Localuser}; diff --git a/webpage/member.ts b/webpage/member.ts index 280aaa7..9d19df6 100644 --- a/webpage/member.ts +++ b/webpage/member.ts @@ -94,6 +94,7 @@ class Member{ } const prom1= fetch(guild.info.api.toString()+"/users/"+id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.snowflake,{headers:guild.headers}) prom1.catch(_=>{console.log(_)}) + guild.localuser.resolvemember(id?.id,guild.id); const promoise=prom1.then(_=>_.json()).then(json=>{ const memb=new Member(json,guild); Member.already[guild.id][id]=memb; diff --git a/webpage/style.css b/webpage/style.css index 0a849b5..42a328c 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -1532,3 +1532,7 @@ form div{ .hiddencat{ rotate:-90deg; } +.svgicon{ + width:.5in; + height:.5in; +} \ No newline at end of file