From bf5b2a3b39866ff1d799ff0e1bbe3e2adb9e964e Mon Sep 17 00:00:00 2001 From: izo Date: Sat, 3 Jul 2021 02:09:03 +0700 Subject: [PATCH] first commit --- Dockerfile | 26 ++ LICENSE | 21 ++ README.md | 33 ++ index.js | 77 +++++ lib/chatAI.js | 139 ++++++++ lib/font/Indie-Flower.ttf | Bin 0 -> 55300 bytes lib/font/ObelixProBIt-cyr.ttf | Bin 0 -> 22364 bytes lib/index.js | 4 + lib/json/bot.json | 3 + lib/json/simi.json | 4 + lib/removebg.js | 24 ++ lib/scraper.js | 42 +++ lib/tsc.js | 29 ++ message/ID.js | 92 ++++++ message/index.js | 1 + msgHandler.js | 594 ++++++++++++++++++++++++++++++++++ package.json | 52 +++ settings.json | 17 + util/color.js | 8 + util/dist/index.dev.js | 8 + util/dist/msgFilter.dev.js | 89 +++++ util/dist/nocache.dev.js | 112 +++++++ util/fetcher.js | 102 ++++++ util/getBase64.js | 14 + util/imageProcessing.js | 25 ++ util/index.js | 6 + util/msgFilter.js | 77 +++++ util/nocache.js | 62 ++++ util/options.js | 32 ++ util/stat.json | 4 + 30 files changed, 1697 insertions(+) create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 index.js create mode 100644 lib/chatAI.js create mode 100644 lib/font/Indie-Flower.ttf create mode 100644 lib/font/ObelixProBIt-cyr.ttf create mode 100644 lib/index.js create mode 100644 lib/json/bot.json create mode 100644 lib/json/simi.json create mode 100644 lib/removebg.js create mode 100644 lib/scraper.js create mode 100644 lib/tsc.js create mode 100644 message/ID.js create mode 100644 message/index.js create mode 100644 msgHandler.js create mode 100644 package.json create mode 100644 settings.json create mode 100644 util/color.js create mode 100644 util/dist/index.dev.js create mode 100644 util/dist/msgFilter.dev.js create mode 100644 util/dist/nocache.dev.js create mode 100644 util/fetcher.js create mode 100644 util/getBase64.js create mode 100644 util/imageProcessing.js create mode 100644 util/index.js create mode 100644 util/msgFilter.js create mode 100644 util/nocache.js create mode 100644 util/options.js create mode 100644 util/stat.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..10b26bf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM node:lts + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install +RUN npm install --only=dev --ignore-scripts + +COPY . . + +RUN set -x \ +&& apt-get update \ +&& apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \ +libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \ +libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \ +libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \ +ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget --yes --fix-missing \ +&& wget --no-check-certificate https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ +&& dpkg -i google-chrome-stable_current_amd64.deb || apt -y -f install \ +&& rm google-chrome-stable_current_amd64.deb \ +&& apt autoremove --yes + +EXPOSE 8080 + +CMD ["npm", "start"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..635737d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 izo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..19e6e81 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Tesy-bot + +## How to run the project. + +* Download And Install Git [`Click Here`](https://git-scm.com/downloads) +* Download And Install NodeJS [`Click Here`](https://nodejs.org/en/download) + +###### Download & Install Module +```bash +> git clone https://github.com/mrijoo/Tesy-bot.git +> cd Tesy-bot +> yarn install +``` +###### Run +```bash +> yarn start [sesion name] +``` +| Feature || +| ------------- | ------------- | +| Text To Stiker |✅| +| Gif To Stiker|✅| +| Image To Stiker|✅| +| Video To Stiker |✅| +| SimSimi |✅| +| Google Text to Speech |✅| +| Info Gempa |✅| +| Screenshot Website |✅| +| Info Covid |✅| +| Kalkulator |✅| +| Teks Alay |✅| +| Arti Nama |✅| +| Arti Mimpi |✅| +| Ramal Jodoh |✅| diff --git a/index.js b/index.js new file mode 100644 index 0000000..9e138ef --- /dev/null +++ b/index.js @@ -0,0 +1,77 @@ +const { + create, + Client +} = require('@open-wa/wa-automate') +const { + color, + nocache +} = require('./util') +const updateJson = require('update-json-file'); +const argsS = process.argv.slice(2) + +const start = (client = new Client()) => { + console.log('[DEV]', color('mrijoo', 'green')) + console.log('[CLIENT] CLIENT Started!') + + client.onAnyMessage((fn) => messageLog(fn.fromMe, fn.type)) + var messageLog = function messageLog(fromMe, type) { + return updateJson('./util/stat.json', function (data) { + fromMe ? data.sent[type] ? data.sent[type] += 1 : data.sent[type] = 1 : data.receive[type] ? data.receive[type] += 1 : data.receive[type] = 1; + return data; + }); + }; + + client.onStateChanged((state) => { + console.log('[Client State]', state) + if (state === 'CONFLICT' || state === 'DISCONNECTED') client.forceRefocus() + }) + + client.onMessage((message) => { + client.getAmountOfLoadedMessages().then((msg) => (msg >= 1000) && client.cutMsgCache()) + require('./msgHandler')(client, message) + }) + + client.onAddedToGroup((chat) => { + client.sendText(chat.groupMetadata.id, `Halo member grup *${chat.contact.name}* terimakasih sudah menginvite bot`) + }) + + client.onIncomingCall((call) => { + client.sendText(call.peerJid, 'Maaf, bot tidak bisa menerima panggilan. Bot otomatis memblokir apabila menerima panggilan') + .then(() => client.contactBlock(call.peerJid)) + }) + .catch((err) => { + console.error(err) + }) +} +let session +if (argsS === undefined) { + session = 'session' + nocache(session) +} else { + session = argsS +} +nocache(session) +const options = { + sessionId: `${session}`, + headless: true, + qrTimeout: 0, + authTimeout: 0, + restartOnCrash: start, + cacheEnabled: false, + useChrome: true, + killProcessOnBrowserClose: true, + throwErrorOnTosBlock: false, + chromiumArgs: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--aggressive-cache-discard', + '--disable-cache', + '--disable-application-cache', + '--disable-offline-load-stale-cache', + '--disk-cache-size=0' + ] +} + +create(options) + .then((client) => start(client)) + .catch((err) => new Error(err)) \ No newline at end of file diff --git a/lib/chatAI.js b/lib/chatAI.js new file mode 100644 index 0000000..27665cb --- /dev/null +++ b/lib/chatAI.js @@ -0,0 +1,139 @@ +const fs = require('fs') +const axios = require('axios') +let { general, apikey } = JSON.parse(fs.readFileSync('./settings.json')) + +const chatAI = async (chat, isCmd, prefix) => new Promise(async (resolve) => { + var regex = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; + chat = chat.replace(regex, ""); + chat = chat.toLowerCase(); + let isiChat = [{ + pesan: "hello", + jawaban: "Hi" + }, + { + pesan: "%menu", + jawaban: `${prefix}menu untuk melihat menu` + }, + { + pesan: "#menu", + jawaban: `${prefix}menu untuk melihat menu` + }, + { + pesan: "/menu", + jawaban: `${prefix}menu untuk melihat menu` + }, + { + pesan: "assalamualaikum", + jawaban: "Waalaikumsalam" + }, + { + pesan: "apa kabar", + jawaban: "alhamdulillah baik kamu?" + }, + { + pesan: "gimana kabar mu", + jawaban: "alhamdulillah baik kamu?" + }, + { + pesan: "aku baik", + jawaban: "alhamdulillah kalau baik ada apa ni?" + }, + { + pesan: "aku juga baik", + jawaban: "alhamdulillah kalau baik ada apa ni?" + }, + { + pesan: "makasih", + jawaban: "Sama - sama" + }, + { + pesan: "terima kasih", + jawaban: "Sama - sama" + }, + { + pesan: "mau curhat", + jawaban: "Silakan tapi maaf kalau ga nyambung dan jangan disingkat nanti aku ga ngerti" + }, + { + pesan: "boleh curhat", + jawaban: "Boleh tapi maaf kalau ga nyambung dan jangan disingkat nanti aku ga ngerti" + }, + { + pesan: "bisa buatin stiker", + jawaban: "Bisa kamu kirim aja gambar dengan caption .stiker atau reply .stiker gambar yang sudah ada nanti ku buatin" + }, + { + pesan: "bisa bikinin stiker", + jawaban: "Bisa kamu kirim aja gambar dengan caption .stiker atau reply .stiker gambar yang sudah ada nanti ku buatin" + }, + { + pesan: "buatin stiker", + jawaban: "Kamu kirim aja gambar dengan caption .stiker atau reply .stiker gambar yang sudah ada nanti ku buatin" + }, + { + pesan: "bikinin stiker", + jawaban: "Kamu kirim aja gambar dengan caption .stiker atau reply .stiker gambar yang sudah ada nanti ku buatin" + }, + { + pesan: "ok", + jawaban: "Ok" + }, + { + pesan: "hmm", + jawaban: "Kenapa?" + }, + { + pesan: "cobaa", + jawaban: "Simply count all typed entries and divide by five to get the number of words typed. To give an example, if you typed 200 characters in 1 minute, your net wpm typing speed would be (200 characters / 5) / 1 min = 40 WPM. If you typed 200 characters in 30 seconds your net speed would be (200/5) / 0.5 = 80 WPM." + } + ] + + for (let i = 0; i < isiChat.length; i++) { + if (chat == "") return + if (!isCmd) { + if (chat.match(isiChat[i].pesan)) { + resolve(isiChat[i].jawaban) + break; + } else { + if (i == isiChat.length - 1) { + if (general.simsimi) { + resolve(simsimi(chat)) + } else { + resolve(simi(chat)) + } + break; + } + } + } + } +}) + +async function simi(chat) { + const respon = await axios.get(`https://api.izo.my.id/sim?text=${chat}`) + return (respon.data.result) +} + +const simsimi = async (chat) => new Promise(async (resolve, reject) => { + const headers = { + "Content-Type": "application/json", + "x-api-key": apikey.simsimi, + }; + const options = { + utext: chat, + lang: "id", + country: ["ID"], + atext_bad_prob_max: 0.5, + } + await axios.post("https://wsapi.simsimi.com/190410/talk", options, { + headers: headers, + }) + .then(re => { + resolve(re.data.atext); + }) + .catch(error => { + console.log(error) + resolve(`Simsimi Error`); + }); +}) + +module.exports = chatAI; \ No newline at end of file diff --git a/lib/font/Indie-Flower.ttf b/lib/font/Indie-Flower.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1070aacda9489240308493094defb23ce0d1bedc GIT binary patch literal 55300 zcmbTf378~jc_tWt+*d}%9g&flk$2>sS(Rsk~7~Vb->=XV&9`VLisi*yFKzyoTBJuw$FY-p4k0jIXYJ|H$fATZjQx zkNT*n?97P&|Bm;2zxVr#Aq>N0nP(V|dFt@s^clt?k21{f{t2%7m+u^orl0a(%`iVv zz}FAImpuL2G86C>hWUt&@7s?(_4q5qfA+pP!+iJ|eE&6% zKk}NVj*l50@Ar9pUw-_X-uT%6^5!@EBL4n&4D*3APrUSzNB_s#8}RxcUct556SyG# zEcY^o`Ouf~b^VD~y!H*>|8MR4@%<+lM)>}3deuuFDgWqSznoz{h7+Ri+?aJ^5)_EK-Wx=+ZEsw- zdgswxXSJ-s%buHI@i2@^zR3JGH)6`ngkhWkw@qgA*?c^j;Ep)ANJL4@;)4flb3t&4 z59nH1A43x1nS7VH@77sR;h1v|w*Y|?))-XP3%fuRw~#;Lf8&fSi$#)kUHD<5=oy|!s>%^T5(ukjO->NhIAdChTh144vzE7A zmCqF;R**}TjKLC(Rdt(~ z*uyFAS>{`qcQYSieu?>gScSpC5Xr1L5ay|Ave;;Ty2VWg+%3zPyMZ6L2Fa4;?iGkf z4PrK)Brx-_7jx7Cng;O-te<`*NPpc)(0hz=7miCi04c>FH`@YM~lByUOyg!Gf zO`EQW7cKbaWSZKa=ozfrgk6+K%+9Il!T8|U*p52O%bJAmv%J_CO}i1#nW~qxTA^WQ zWS$sFIUwPgHcM3B=jkF+x6W7@R>y{^s?TN3jBdFyZxU}hti0-_tYpHUv8%jtkI7G zSMt?bvD8i^HD4^1W4LC$SFg?X7ZaUTHI>-KxSr>1uC|hKC!>yHW-=xbMUEq~hBs3* z*gQv!PGT58D9N%S@|q%&)|n=o$>?0vTis~A?3+b3^bAr6-6}SR6#MgN?Oa)^t;{CA z4-d1mGZQ1ionsziUPB}9LPRhllIt0qWbp8A#9i#>b76SEj?>UV=Chmo zhs{S=!G+sjHK!54Pa{ma$?q(U_RpMI?})reNI08~TrsM*8d*curT&QDe&zh4hFIMvXNRy}8gMZ+vOYSB5m z@A1bTJnAZnz_YDWr;Y~d?BM*ub=^DcLBC(|!baaMF2-fuuga_yyPmJ+0<$ul*qlW! z<|ge-#;Nq9{3r>Wa;K;Sp2_j5U$U|VKVyc4G&3CEAiuzVf_a>IbGl;e9KMCHN`K7} z9s{5Hj^rXLVhP3zellIK{z>FS4CIS0Xh-kZhELf(-vc*Q* z$X080lPz_}gBsun<08Y}!~O~KKI3c=*iS5YF15G;H*tAc)Znc=61WMs6Vg~iEb!L+@Gxg>fn8jKSSQnUSs;{Zg4lvkiHSMJVYmK1I=0nN$52u0Zw~~XMdC2o>M#>7smBsEN4A0$p*M3LV4Sbfv{CDzQ@Y%Ou&C=`( zbCO_e^kE4CDy%RKwlu55h^Rv%ry~#0yTTvyP1c=nk{|&J82L!)93pvYt_!mK3swsj z3^davc#fp$i_$=NmIxxPX({w6Q=p_}a5#lz* zLip-oBtPVIsbJJw9bZJwPb9febZyUu70DuNX9OfX5!uc51w~TyEO|FR5s^MDM(BqI?t^eVFDY47z^)J&r(G(B8P>q7)~U4-GF0L?OpqMA|YqRT8%G=(!uWz#f)fbg{L+mYh%I+jC<%INAx z@M%bJUZm@yRB4o@)H)Z;OPF^7$5QKLr&}bMOvM!PA87no z$h_|lS4Jbm4qau5F1w{d($wYVXx1x8S_bc)W&VoXOAeVl>@i&n3J~b>!4c*wh$&ndVghLbDS)bL!vsihfk5hf`y#G61*RLnE7eu7h&f#7r{nvqW=Ng z&)AOS#t3^}l*#&*{IFcEgkCu@^*FM5=tKX<5sQ+#T`LlQOPxZ)3U zK;aoh=7?Qt_Xf?foH46LyVumnFB_d!m1kAM5VMzG{+4H6f8Sb2BfbOMct80$#$yId zo%t9e3_r#&r|6O)!d#BEi5CqQ?V~WCV#&xkY1KRaSYoyH(3L4vKVAtA$vcwg{M#VnT8|$1#WBzwJPkF+aU`9o_|t1 zrK|ERfj0vp@Pf>{VVsYYkQGFMeO6W_QOTlc0kVcm8m0kTbSa1-YBHP*8=43l4<`-c zO5Vu8+eWPvqi!;CSTG~-5aDIgQ@_(h}H+xf3glc#wwpbY~GE@CeJgOQ69Pk5Wu)u?3C5OEdOdihY;( z0GZw;jwKaWPY>;S!S0;8u-j!39@N%wr4@yxikmbFL8RHP^3I@H$mT16S*3Y5qvyNR zDA%8zc{58y%Lf1zjL_-KYPM+rLKB1r)SISPbm()!nML0ZP#cS0rQ>-8-#6iGS~7}@ z)lxriutG3OpX>(tC+y3Z?X-fRbzh2SfLtW(1I?i@;54}|@1I^l{h8*S0V1w}y1;2p zD~5=&7h&9H9pBM{dagR}R|1$*C?l@Zcow=DO(62;`BE5pDoR7M-4)XNba*gpG13|NSHvLLv_7zj1RnmmdVR2Iv) zjq)>@A{22;^cA2=J#k2S+f^VgR5YoH1+>QTVQ(nm9oBR*T+~|Wl=;fRyc&;oPahNk zMff1}d4l|d!pyJsdWqq#taMNVBW|bQiOrYGisT12i8&i(1qp+wq%-ab8n^4*}vKzoa#8MnZsFOZBPuVZM%Lj zDgJizMc1$Fw0R-`vx}LGqG*UKUSl|3bp=`Gqv5I6;8e?QY+Y~{Tf7?es&=OyWTH0g zuZY<7ZnncXY6s@JQbm{C0!)~5}5OU~%U`HSbG>!|<=9H%Or zTW@wFY%{BeJ_|g<@?PNby=xr_RlO^!BKd4ah7od%g}Z)~J;#jF3W@ zEEDbmgm6+2z+pJ*I?G5#QT~a^f@En{>FRT|VD^E@z}{fbaAj4sY~QHGE-NZwHE|r% z=_MIGsz%6rB~6RtS?kJX{=lmb^J?Uox#kLLS=dBiYIV+w&8)=xp{*)PspwWB=d&Pc zKrc{MOb-iXSFhBo5%5sYf_g{;2iy}-X}J_L zxGasEps`dpnN>on^$c^MsPzmXD%=o$i2u%G4&LnbnFW1ux1*~ zu>&aGByma;lxu6cq-A}AGTqWq_5jfWRx13Xx`EPDC4VKGpaoO~-ylS{Y`p*RpB*1C zPm*^qA=3oQNm0lQL28M!X(>QvPJ%K~iV=MfZ`iEqc|dKvs(Xs4J3(wpaQ+(c0*jZC zz^DOAJ4PAA#K^ze|3MS*Lyk1_=0v z1JlFPLLnBw@p&$NvgSaVUt|k|we^Xk<_iU#RTPrUId2&*k@p6i3YFE z(s-(B6qgj>!#_Yi!>rO36X%pTYa(x)kk6MGz&Sp5?a6G|n%7UZYaW2sL z>R`1~@Thgl*gu|oEu*E8@RoH}6E3YSlUfyAEST_{Ac{OZDIc9b+MU`cAc>UC)x)ri7=^Ia>aXVN>n*>2>b{w|wb8S6qnxb7{nLX` z4_lGjZf3IzVxb}{1rx;%iZj=j3#}-_BKF;NXL<4T{qyqr<%gbFYaE_AQ&+>;<@+9~ zzVxjhcwqSOJr~z1PNlax4UJyEpA9y*)_X{KmZ#E~lOJwX#t)zCWed&F$V<6qKAS8q zHN$q%vWph#w_Ld%tEwB<%OTHNKuq%F)ULaB@6ogw2>i}NuU|}`dh&t8mg$&Qj0jHB z$OXo(&Z*2bihLS~EFjk@)qn(;wj*3IC7lq$(4QFaXqYsUVG5_`TX^l1LjPCn z^Cd@X5+GM>0q>FD0XXC3!sg~ytTfw}$s-{unjmCDCnI5XP*tL!r%XF9Wb!NL)_RBY zHfT2_O;!n?K9i0#>U~^c)X!y z)auHL>#FfaFB)IG_tGe+wdz6G=sJZhUyt)P8YQle;3FI6>!1DBT|q;hBe7~*Su{7y zT-kNPs8`GDtWzCrAGSJcl`JP|&$zLVeGt4>ZS~Zkl#e}plIE53el^r}d;F$1zaho( z$K*@w4^kYDl$!$fCF)(8OASb)mikf(KhoTXY7@;FWCh-d20IrzolY34fS>?60a_kB zJGkedl_}5L)&2ebDl(pJvVX{C_{y|h#2$OCyRTo`vaPzGsa68jv24u{?9Gc0OsjXC z9%QmQuL_`f$tuZr*B1-iqkH_9?C-H}W9~l5zcFaioA4cf_a$nfHCQkuQV<=o1a~)0 zP%_c}RT@@kOsV4Ae=Vp&du5;qy?f6M3&Wi=M-}2YAWsBM&YChhJPM1dRXVyp4ivy1 zO09rTDt0IR5*fetn;*YCtZrSo_o2QL<*bElX@*WJTbBp*)4Q{7EbhMgWuwsuSXPz` z>zD4jTGf+wO-?&b6pxEYaJ=Dyh~*_@eAx5!M}j5Yr-jg zx*-&BkJFF{&Io-o;50x4x&WJLbvX9Z3X8)|QRGgm%E^*@f`J0{20l_c5X+D}$fMJ> zvUhIR^I6VvO>TPSfjbJIYZ21H&6)7Ur~J!1JBm3ui`BYrCz2?qSi3$gkeD z*u6(}EpT`%>^f2TpO%T3p|~B77se(!6v*YRcH87#&*5m7jY#N;&>jp$nhq)z&ZrdP zPI94X`WX@3md~1|$N~?cazX!wlZnHSgST zSMv%Yj$~x(yyH1MZi{X{LXb#|GY`M|HLtv0C~)QN#ZFZ&wK{d5XLU1ex}ATZrL8}9 z$npY8F;I?{;^gbau+Yf6S+H_4r8bZejd1mFAS-A%g1aK9+XcfnWs=SN0B|l!Y)-L^ z>}0;8iJ~2#soWnIt)Q9U9$*=jxMO>|RP?v23wm^A%NzaO2ptF6FF*3!;VW)TX>~=rTvzl9SB}MdF^SukL zLa&$=a|5}f*k;h~Y1 zb|q<#5(e*}D%ea3Dg>$}BnJ*hUlP~xoRq_-{bfW2TFoM7HOV(AwZW+0058k~iE>(m z+6V1BWHEHwL3^|$x{2Y|llSuI6pM;RnP8DJtMCQv1LagHwx$IUG7n4c;4LrkP5xKV zp+G--zNU^h zrWz}&a3l~hsNLhX>&m3ioy}HEtV$Lf=X=>1gR&{j(1>Ew+0C?!Z2qvIfGrletfA>) z7&xGZ0nSBTmy*UES7EE!(fUScy7Rjpe(c^e=>BL3Y?_gw5yuCX{kQC=nKkG$5IgbC zfU$F*w(pnd2^W?WFgJte_)UtXPPY%YH}bNXkqzC~z^&)IYa4T4M>Zm4st2wEB8_?v zB1709a({Ebs)8wW?5sh7hblzdTkG9izP;Lm>kFQPj`{0L;`pvdUUE4MS#!LxIgD|4 z4mxN52YU~52&)Ik1}U1>fh-~%y;HjH*kk5Vq2?| zQ7ddM&h3rl@|mMEak|8o#hbnHBxej}YrQ;?kcYFm$s`K>=KfZck9gCuRPN+Su7a&- z(3$~0ixR=0MvCA(rsV=G9qkz!!C4162pu;Szc?M0EL=s^{*%J_cFHOYF3#c~s=eq% zcP=bTWLtaJ?zy|J1}+FqVhgs8Flsb*mY>Lq?5mlJ%e6~p@B@nBkROTfaVf8rG}B~3 z;{;ZcA1~8Q$^)g{MkGyoPYL-rsxqWVY$>ou{iwCMNd*dkW}1Lzoo3ouH&>0qO1Ipa zRy zO!cRI1C*rUxqNcEIezq|kB(%O7x7HseAv6Nif1VfprC)5=#UMN3563_MuQ%G8r(b$ zbrh=-D*HM4nk|axkK(3vaEz*)PbLS~CZ%DVE!9h+VOHYE)e7Uo?(qC(zZ^&zUC_}n z)6|U2Z4V!OU@#m+D>;FtGPeHc6OZ4qO1#D>ZtgD@b;GQ$oj%yGx`)$ZeSLSmZijiP zJTFP0P_s^2t)Vl(UL${&b_N)SmiaRz=O8s)>^wx*G_u%lMvlF@tib5PQCSa7pMEf+xC22K3kWI=H-lzX z8X#_AW5j~y$-^cyCgwSb~hsE-0Qm{Z9@S+gqT?Az_jx@*6 zB*?F7<9cnSy56rif}qq6YP@BFd1smE_LZo~7}T3v;VhO{55LF|DLv_@Id7 zDDnk11K|@@gb^4%Z>x>zs%4XECy=3EK`IhjmtMAItlWRpE6)!vUaaQ(jgq0-Mc=h; z)yuV$h^WKMYbK;5M%HQ7OKN=>_$W)Fis`kRrj?cRIV)+jB*VY4(2ql7wfITY>^ig;v@0sjff zL9(;~lx)kOR2BOAX*M|%RbDfY^~g>--V;k|YNatFg`Z}08WJm?<(4f{CQ$o(|3P{kV}bAZAS zprhHim27yA;*ll)AQ~K6G9Wv(!5x#ymV0WegFd#Ez45zd?CS09!`SGJR+F4jjLX%; zbGFvo$tjq{W<{M`dGQmEUEBJo8hFO3^DPOS2+71HNc>Fshm?G!VJ9m^T~N(j#g|3X zb#<1{mJ0cPyV2~7){iDdMMdp``{oc&K8z^8n)VqpH~Wk&+GlJn`-~Y7sv&xf3`kV~ zUt0f9!InWgA)-J+D}-jylSq$;g)3~G`GEsS(n$8)OJDznr|uq$dgJKmd{fIh3M>|Azqz_*C>Q|34xgbQVnk#n)#{BWeUxxbycgC)> zeFl0@RGYLi10YxiXlgYJxF;5S!NTrho|c&KJW4juKwco6Y=#!XgpPJBh_j$EX%x=w z_NA;QLD6M{Gea*sZ$L)kqQj@Fg&G>RVRv^>vSspiP;1SSOJ!gAa?C{sXOA{pEcA1m zWxlgESSb(sLScHg9UmPXj4NSL*Rx?EG~0W3-F*k{oc45ofVCOODxEaJVA+IVAq6uZ zP!*UQYlk2qI9b^#=RKLTgIs8GVg^CaG_!IR>am~*e`i%9Lv#avvgpWzb!N7IZhuN`m4>(fo!m$>dk3-$fLyE& zP#RU@fv=%4EA4=!#UCXs(m2inH1f1JhgY-Y0xd#%v$DY@^G2YfPEk!@Pf^NvCEukrGl>!#GNEY(0y&I=W*SGyRTn}xJJjalC4WuFKsv6 zLaZ9~q^cVlZyDuF`+d9I36rD4!$v_FUB2VcN)BdabRw6&_e*RZJH3!&c6UIP841TL7ZgYJRT2UNX5HmSJ4hTv0nrAkodb7%v4^Qs~N_TY- z$Z<62^a4S2u_F{on6@iH$b3416 z9Y=O&>vPX3)M|zyON~~UMGv2`kN*tXns-s`e4^+=bAWP>03y(RfIMFa6sAz*v6TBJ zzp7*rhS}!Y-n_z7u1u6dz|V2s_Gq^N8pCW@Z^an|OSl=&WvwjN-QV5sK$}SH%4qNE z2%CZ)=V~)(4Iyjrd>(v-GJnZ~54`xvElr{PGZmCIPRo%ZuPBmt5WYZLTM za96ZArj|ev;1WhtctkNjw3%34Y9sU&sVa?TK>(GLA`2igeX{}iNL-IoAVjqw#r0Up zRyJ3f1)HzUc8g&rsaQauwUt$KaPR4kC<$&{i#;O2JJBQ*c)q#bt6Qj%>W8Om^(s`( z#_qT6^JoKex$r30>$E+z3s6YtMo9#LtVP3SeYKR)Q9!X`R4`eyb2K-72M&nJ2}?$k zqpFB#ekL0S1y&=bV%n07y2udy0+DHr=^lR&z2M(u9)=&o%#gW&9SN-!33x84mc~OM zAX+qU5Pt;qB6@JE5LluPMJ}Y#zm_s!@OCmyCWu$4O$PA(ZGx^x@5xubY6bcmX zKt#9F$}G83Z5czzhY*L+9;cNRO>k-KpjJRrz#VF9b++16c;GE?G_|!e=g!P4qGq7@ z=lQ#}(c<*ZNEgeUZWa!)b>*IWE^pf+_(&F0fDIo+POrCK`>1gs7!afk^~SD4a` zFGj`?dQ(<5_|ZT5u6Mlsbx^#~)P(95k10yEQH+M=;R7#!<;(9sa%@?X`SiXx zE=%o{zAZM8%=~-wjFv&00OpUrO|>9rz>C$Fpmf#Acd9LTx+%8lsgYz8vlgV>r@Oq zBnreH-8@7F)XGI-N2bEJ7kAv<8?>n54>u}klc`o%@xzKoWg~=xK+rI_be^Khy5iM|&L~C>?@r`60EmdGSJAHgc`;bmCTOlkd+ z2lE2Y=Xx8b&nMFA=IFS$+cq`ZspNaroT(&qM{utnB_9XcXx*+K>rq_STjDy}D7S&@ zdib;OoQ4dx1$UZI)I{SsH=D!smJ=E&LyR85=B1w7Z$*Nv@sm-q)$$;4y>Ouh9T4%$ z5D|$R51gw1*WR7GiQ-mrd>A^zo$};Vb+Fa2MZ_w^e4?3X<3#hj(k?B7qV5a0*MnPk zYu!Ymx8Ly$cT4a3)NOYgAR=HJDAz}q9w`b+a%#jVi&Nl2wGl8_$7$~j!jqFd=KR5K_?<)cMw`l2(Fs`=jKp{6p)sAeGEvR1q1(u2 zit}rW|IJ*T&%%wzF7=5%dFZIi7uxwKu5UCww9N$+2neik({Y=z&2r`Oq8d#`gId7p zJ}Tqn^h;2;{S|EHw~*Puj*yXrF{h*n4?Pi(fIb&!b1yC9(IWsv9DqGdgArYBYA!`| zt~qkm;}oa2*Q_D5A*Tio7B}mZp86uQC8mp z-G&HXJ$};-oxC2Zgk9z?$Y!AIp)&>ua!AW*&yBJ=xaVc{NulCWmdZQJn1sB1GlF5z zhRU<##^#y5DAaSc9G!&$+=WgtUyO~ytQpp}?;O_qIgRH;LHDYw<>>6?ON->UG_T~0 zr!LlB_sq&#)4%Zr6zRMYdVZ%`Kn#sK)9J{PyK7sMG886ZGAZ=#zp$bnKJk{fy=4;Y z?425y^e9=~CVy&IqHJrcS}UN}Y&7NoyX5#Uuw(DUj-l#opl!X3xpa1FISYWsD^y0$ zb+%HdMvD#-^O%A;!Vnm-tK%Ak`B-3r$rR}ObTHR~f~^M~}VfJC6#@QYC`FA2>X^IxAp68pvjR0f=C%@=;}ABNxsB(L^eAWGgD)AdJB0UD101zuSysj| zRDm6XzX?G6nnKovzVBWLk9@wQs*^_^dU#?K`lqj5+{Q?aM4V7X{i~!}nRncnGM{Jf zV!9M{W6BP~3qVsqZR&oM;!K(|_~SSh4LmX;IPM2JF!HXId(I3X?SixPsdP6*EiSt-V>D){gi5n}2=%`gKW_ zcxmI_*ZiZmzUj&HP2T1Wv=Y1sO%Vf$pB&%7&i(-VTIT!`gJXfVSm>y6!!v5d0dOS@ z87n3kD8y64rulnG0WWJ_n0GRweFwr>j>RjU?^{$UqhTN+9~G)T%3Y)0ZkN1be{Bu5 zrouY;qUx_tfv-)CSF#zu$Xc$&TYjj!kQWXff9%EWFuQi=^(66F^q1>73v_O0&~0V? zdhBJ<#WNva6$=%^03B-JNtg%SDGOK(QX}t0iqHdm;G- zl_SuJHp7t*zxVsT=Zq{upDe!PKfG?urAUL;|DPv6$zTSwF@e!g;q#J9g4t6*abi8o z?1dn^1T>)9Xni{YaD<>9!8eUuY1mC80)wN&MpoUXypOHiH$MCfnS|=VppLW0`LtrG&3=* zP$(C9?*MVHTgb=RVj(v5uyg9%sZNlre&z6s(l<3E%oEaq8v1QdON~B_ z-E`?dV@`@08N4bJ{*-a5G6A6#57uLkY4vbDO}kEPt+M&)oL`L+4gwY*d54u<~t%Dh;d zT%4EIJ2@cN_Ud%H>N&{<#Y#8cjTY&nH+^l1uTQc=%HyWNVHsQ@X$8oq`NDTsB|v%< z3IO6x@9ZPf?j5^HJlUy~_t)xPv*kLzIUQExm93aBwR#OIl!VqFx^{@9foEmt1pFZI zF&+HvJJ%;+VRSTTjf=YI_ga>N62yvw>ZoG#O2!GZy4GkESabi*`|sS#rg$DS2HV)V zde8N9D3P$fH-45p16HTW?7%mc=;2mv&ZV9qQ6(PQ+{?Dnh}Nz*D|y1RwrjGhr+Z#$ z>#nK0(kjFNN33nSpkP@sYkbnKhEdrcxB@5Y8K+P+ldUewUOZD{aiueQ)n0#J>9ITl}5XJyQ9)?7Uz(xNSV^%xpOruvgN@6>;WtTe!G|aIs-~-d@~NG)6Q;M zPcNYbWfs9V(q$F_id^xPe%S}t3>Fx1jds^f)=ru&$MC$+#OR@Dc88;Z>zNX(I~L>) ztp^{zuOVTMh?ch^o0gau+eIac$3?J#b4A6q>2x~DtHI6t`U~=(nbWkEL19Nz5N-pZ z7R>&Pf*_Q9^de0QP>%syq7O$WK3L#SsC#9_&SKIsDn-@2w>3*h1;y_ncxNJx53lU^ z2@8>}N;Ezhtq+SRjn7^@+NhRSHzu3gi)rVLBBx|frJ_^@N-oC53K)oNxlrhpy8-bA zRX56zOwMt9MKB{PuGq4aiO20yA6h>#lc#+dIy!KkeKTg-YlsFNL;)MW6#QZUp%p}g z9R6hRXO%{VB?_I5@w{*@3Q%c@SwayAW*`BYKyVZRv;VQ&>ee{4Z~R%r~|{W>Jwpn5anzk~3MMh&8fvvb!DN04!xy8Eu9 z)D{Ht7v%qj<|%(f^2i8$2$gnT^ipRA_xwS=Lu3U0Q0! z)Sv;nC{KXlHbX%72TC_yqQm1Lfdkt5RP3PSf-{EscwxSf<5UA`(*6ZikoDh`j)r#g$HWzu-rITY8DvUosg?$Hb zV&rVr52uw5)WrPOJsmNL_nx-!5%5BLE+WFR}-+N%~?1zQs^JRoqm zGb?F#++=6c%2VNPmd7Zr9VOGMztTl}j+!;(KQ4w{Sf_I^a_4LFZvMuvNOWq?nvN2Z z@2zdjTy?m<7+2h!i#h0{qq0=4M&rG4;k}CLDK6r)WT}jrIMDQfMI*` zavAfLd|36zlNCqS3%%L2uN&=VbYOKbc>z*O2EhZ;5+VcEE#{DBe9xfVt!nKyG9CLEP&TXMt#K9e810=}w%F z?b@`P^u|@i!+5)-TVWOgWvMu&btbh4=IzjUwy_#`+*AvK#emi)rG3)`35TRq0j79q zZwO(QKqiAj2%tab(4Yk8EO3;N)>T)aVx`ugBM&ZLyfmmLNu5p>&N4mNg(g zmXmHGTLqq=J5-KDCn-7Qjf;QC$+<8{IGp05rz26OsmV@%zl8zb(J;yQm3prXRH)iG zX~ZdJf0%ZD#JFY)2q7dRfMph1RTI$y5lt!9SMp_qx1&WyPu5CO>$WEfV_vineEaYr=kZs4CRY72Gc$ciej+ENM}xzsHW zH3Q*2#Goy!h0QV`Ft2axNc!kofF9(?FRE%-R9PfzTL{B$NyYTE>>`#?1?LL%3M%Ip z3~1vRFa+N5Uoqdo{3@yb;k z5aO16N{6;K%z3zlM=m{a3F=R*zeG3jl?A9FT8i?hITrX|M=r7kskXKX0afAI+ z_Vdh}mXVplG~fz)^UJ_Q9}5CjdKAxmypU2Dx19e<`7VjJooE|jStTQ=}S5Z6OvNT6<&pfQ)!sFrj5LU*TMT^;2&DBrWqh7n4ciR>JZre$F zaGburzaL^Sjs*`7sjC9DBMwnPN2=7H&nNBBX@D=&H47ly3Om~kp2`40$Y~J8Vm*V_ zWNWtsm7*L(CJyw#JcCz-<&>Emd!8-Ba_$6D!dd}3V&Bt91}G0R!teMp1xEo*-OzB* z_Awov0+)bMODs``PPMQQyRpksl>E8da7XhCGb86aBF@Li;hcf2St+<8m4owo5yswn z>7+3B-A3$je#3Hum1eHT3s8y zcE-At@eSouX}6A?)>WLYgxaA^UJQ-|aJM_%+C;g(xm}LyUKro_{Z;g+!5gES3zL!- zP+!Wri?r|&m<8mmEE61mk+~Zzlb-hF=%gF=2D0xRGJ{|XnF<{=m_3R%v{LWnFjS|R z3i@#b<;aqBqJ=DJKJhKknwjiie|v9O2`i_nyWx_7^42z@(8ec0a)4O%qs(RIrLZB9 znhPQ!jAvOELXQH!y1gn)O((^JlwDj6G5uVwk{xYq^z&?WXsf@Cu&>)V<|@RgB)H}l91Ux8nmkJ`K#Adk?2 zlRiEse{SNW<=3YniWEf*dP%D3sAx}0A5^lKr$>FGW<8vn2J-fgct|}(&2$wpn^Cl^ zCE|j9+t+j|ws!n??EBEk%wZPvCHUlIL1pb2L4>g8Hc=#P9zzwG)?znrYXW@`YRj0z z#=zUr!l0>Rz}0YC52R9swI?6EG|Tf+d-L$@>HOkl7rHA@Pu|%w=KDum4WW5>-vgaa z9)2BUl@}4KzS%u#jR{dSO4>GtxEm{Liz*0SQtot=wTqJiaf_#RHwFb(vinC5ylSU9 zZiJS~x6eMlKe)V&g4^`V&2ZhADzRa+ zhl<2sS;a7DuHK=;pyO$iM5?Q~$Q|xVerFr=pxQS$56TMMav=0=NW#rlJ(C5a%OV|} zjFEELVzurfq)>8PvT~U6#Q+h~vWOGo=(!{`iee6#JWT#M*lY%o#aKdqoQG$yU`7ZK z=Zvff-L3s~oUDiTbRW47qkW(nSn?o9VwwqA2U8lSl`wFjHo=HnJO|^{QjxC{e=KlLTodRsyAqo6wv%mDC`{73uG$c;^=+ZWhUcm-Rl$y#E z2eHoc(dy2kkT-dBg>b+WPPjvzVwf%4LgC0|qQI~$!309)&==FfRv}mOb>s(9%|#8& z7JFgQTs(epiZc*&ZSypmZqzP*4^!yv^h~Me?H{4SfKSm<&i0d_Sg+KJQD>GXHrr;E z^duTds+Ayk0r!Df_K5i$JA=nw1*=qu&vyRT)H+J!ljKjB2a##ggAjdMM5p$F>^)Cr zv>~*_YqS`{PSG5W!wYC3v^+g%PP4mT;<0JVJw$bb(}PAc(lW-Y4JeM1PE#wcudm0d zzp`J$et52?pmErGfmmAi+8kb!+xh$uNKh!uL;3fB+UrGB>Bj%@=e?vNyIe327AL*tgIt5$NaXuj4U;2LqG^x?!P$k>c44cwV z%zJNq0^R#O)b~t^!-2O`Y5i;<0z$!<-ISH4xf&kvUW5%ZF66T~luyI(Y%Qr5ER5u%GIWbcG4~mPgFa9S!XSd6E|cqm03qmcsC+q(18aKSupa1EzJ}`a_|KTn zGS9NFf|a?)f5?2U`yV=Q`YN8vrhUmbVlHEqd4%THuQ}C^^!vQAe>yUOA|tI&1!RG5 zZ0`T_-1_Bf+ipmY2w1J%c0|C|_RTW_#Qy)UGXk1=f3`VosYG|v;{;@aNNU(PP5^CU z(bnx^F2s2P{q#Hmian11h`q@EwfQ(uph7wwt^HyA-Dci;{KtdOojSs52Bdxb<-zsl z5U&=GKh0J#z=>BM{~hz0VKUxLU;WJSr&qu4l$iScpEF$Rso@=XwSN3jw!{7kUV*cF ziC+2j_CfmUcN~9o@Q+V@GJWqg#!epVT*IqFyr#kaJ+4;a2Y>(XKKU!Zj;nNnrq2De zolqoiO3+UH68Y9!*Z=*k>rXRpC*O7J`XAi9PIkah|K+Xg|Kis5)66D$^{wk4xOp84 zzC-dhVASR3{y3_JH!|OuMkq?iBO%kel2(>CC-TxFoKlLku1AnTy@?lOk*>e$u>F+c z-8med(Bz(K&OmKp!jTrKxJ(E}E{>3{Z%SC@qUF2#&|ZIV|{&!?`&A)D%BJ#t~$YKI5prZ(#qHM=78@ zibi+6`5x6XF#xf04nt+k=v{6km@AKsG6^7#9o98yX z85{i^x)$jy$IT-ffPD}!Q>tM;Kx_56!y9OMO6auS?dLZD-JNhj;6Z7Kg<2Q#sS<%2 z0+{$WaI%1n!y`irx(h@^)F?RD!G-X>uvUb4!NtK?nEO)r+mClZ7x#tFcL3D=io+t% zn}H`;8*BRoP`LMh5m;g$yYo7 z0mpZL#bFZkpn+yKKm@@aE@xl=Bi0z_4w(`;4Hn>JZ`o_?Z{hmr#76$)w(Gxk>-y8o zuRV7ihe9u3FOr>V^(5gmO6Ze9JUTkr8C^D5@O*w+cOMIIp+s2-M14*+)4 zQZr?;X+?9Be@#2Rl+Fk71aew~dY&FW>=k_hBmYVmTEuc~9Im9BChvQubzaX}%3v`==z*uwa^4S7JC zv)_ZYc@Jg~&NKHRzED9RjVWju&?GST1In~xs{B?C$8FMy$10LVn#bo7ED0{DSL0XtZiw`8E8s^*iWbAJ6VTUw+TNL>(>m zXEsJqZxh~UOq2bTPkx>&4c6D^ogBIG^5+ZiVdItK*R$u?Pf*@Hpl1X@ma(8UIPN>8 zji{&w&|;Zlps_!RMzotwt9J<5rT4ONHDXPuYHds}`-8;62u#PwKycUEKE2(lZ=O9{ zsp8-%ND$r4-JNj>r~h0W;}HMa&C`Fr6ZLdP?LYCVSHJ3sdyiHy=Kqz){S*7ZL)dyREF~p#e%i-8|Kg^e)zsiC@6-1}^K_Wo|P1~p^7zk!bZl6&AP=+0+Twpq>fMkmZ zmo9b#6v{u`i-49O$^U$;2ea?le2iI#m9o*@Z6swqq_YnB(3ssEb!dAk&ZU>Ln0EN6 zxiX&z8;>k&E5-;5kzV&8uAD)VIL<*;k|6MR0%z8KX$ zxFR}{iFsApw@uYI6u)Ecg_?BQz@=~=>3inCz&wG6iVG_*4{PZt4q=; zNQiU!ud*7X`!!}6x#LgaF8>RA9e3HMQ`#?hpSRJ3Co$)i67_`Tdx0As;^Y8v*)PO_ zQW^#?KB#80!mXAfF1+wM{+HXjh`jJZZAF#|kH1LX#}=XRdlYsGVy>1(#FTNQ{0wc1 z1WV-zen1VFmH@^DAqGW&)X?Z_XtM+kyWo88L}(95CP*Lj;ql&P80%(aYj$(dO)f54 zQGciI#Dy3?yYvwj%7uN#zDoSAFLEsI{YjZc%G=WYBLliB(j^cAy;S>Nc?HX$E|5(}p*hoWPuQXT`&8T??P(8G!TkSXB& zg^ZwM@B=^6$hGW{{$v_r-}q0tdJc#FC1$A^Vt#l^Ju#g&VBZQ)g!&Qwd0M_3SHW85M+H_+P zEGX*N>w*_I5Clc>Q@Gp$KLy!DP{a*UQBd?+a2Evx1@Bcl-~WHk`_7UkZRx!~zwh@I zCht3E&U@Z-p7WgNJm)#j`9BrF)oqYlGb@2@bro_C$qW6z>=A7r*Y-B~W1y_IK!$9@ zj2D42$hls1oSNXExYOvPY;W3Qi1U=T@}N8IoV55={pYXD@s}ud0ZYt9GA+eXke(@d z2q6;=v5xEvn2_O0fUP4(PN{h&q0$3)W1ll4`&NA_!RrYFGbAeyT@=U(UY3_5J-4|$ zJgAThzu&Y#d8CmC763No&BfLs`ox(J9|e1+b$|f@E`Xbqm0qh)Fd)`MYD%D>va+(G zH0ZjaWD%UM{tDl}2&tPT;8Shf1Bz`X9Yz1X%VVkcnyJ*TuNT+E(kXFOZrMFR`syVi3TH;I~VPAt-6ukNgBD*|GM*IV1Sw5!razeK}WxPSX- zcTTk*Fw1Z`EeeF2!&xctZwh3@+PB4QpF`{_>q4rw-+maW+HSm0Y?iy2uC(G$Af4K; zL+o1@w*r5~$}M}vo$}$6a;GBw?N||0JDWDTV51xthq0$aI>D=in|auseM^R5+8PrO zSINJSKkZ4tt43q%x+aGmj-bH|93r8iXid!wbZuqLRd?P6H4Z*9A{1wn4PodYJ(Sh|;`0sn%fr#I3 z$<4pm2Ed0AbF4loeVUu$L-{GB51Hw=iYYVwFKV@}@?*8WQm@V++wV3gADADqx;kEZ zsa3k{6OV|OW2HA+r6V0{j#%k^vHU%-K|LMIKNTyzr;53i_0N`u)JoP-_K1h9m7>va zGcqH@^+Wo4`6Bj%;?}|$C4JQF9JBFZ4CwuDIQ-FvAqM$MpR82KCfW@A?f9Zrk}(9> zIgN;Og22MfO+}u`^SO8q*u;Z{z)JI}o&N$4y!lVYhMm`VI2SnVqUHt4bpV_3g@rMg z*vd#Xa4+af025(x^(@HPQ`ijk?g$juVw}ETO@DvO%BpAtC+OLS>SJmTu~Q*il<5^a zCA5jDLnnFMG@&#%kKM~hU{S?Jln+{&-8t`h`-H>!05i!86m}wVPeZ_m6Hsvc2?CDk z#Pzd|}&keUlgeV4MKg zX`A^zah~Q;wN{~pQ>{tFzPBB;a@)dIZpicZ$x^1P+?;3CiU;YR7nXMO2b&|7zYpnZ z1gQL9h~?*q(df$4u(@2ySb30VoDjnF-+;hUhHPk`%FTnzbE=iG&87L!e~To;W)`C$ z_7ZF)P){}fFAg%|q%(!w^-k8AGejKW=55u+X$Rq5p|Y`9WNP6fe0i>)d7?^i^z z*=s9XR@c7;P=-QaT4hqge?T>xTcFv4<6UnNq5(cL(8v>H`X7{BR2&MqxZ0A7Xzjx$ z4>@GdinZWGh5W1bfNGSq>=q9Q=rbB2K}mE_hZ0>$XpIw0ZARzr6~|b%nY#_?I(P3t zt5vq~FR|Qx(kHgWa#Q~6+!W&71A8(4yOsMFwokL(i~+_ZJjwKF@%MDI2eL5SZ~Q} zgSJ(@zcv{CD7DKd{2pYpaSPVpee?({kjEU$?;C>Ek@B4Q zv5$%zochSg4rS*7$GZ#1J`9_A>|;)2#&2;J1n~B;vmiM<{(%ruJQRVWAONX1kAfJ{ zAAld8GbYgj;^)n2<%w?)>gl|N`vY@Sy4&32%PXotOoU)fK|!I+n%hbsgVZr|Ic>!} z^Yv?z_97AT)k^po%qjHW4?y%W>1?Ab1 zW}KOY>s}a`bMsZtk&=T0@bwWoQ{w2N59g2q%GxNR)8bped`4aLsVTjh;5-dRhu0?n zpuznd3zdLA*NcP)3n@Of zhI7FQqyqN@sjGErJ!cN$c&|5JLMo!Pt3AQ@i3gGUCHSb6db0hVW@v@(@%9iWJjZv;)h+FbQ`>t_sM8@&(2cxgpBneaAJ2xry-DHG_4zN zDoM!(vO1zCBHT-w3&&t(w#;&5(S^WUR#Myu-%p@kMDNG^`bA?CwOpQj!UP$q#Bhvb zvgE0{QUStdYox`Q8jJ*CEtte1J}>4rb&|db9t(Cqjyz$QyS$k>U6(EOAskw2!HWK? z`{RPg?Tx_QV&#nhJCyb=(3VA7t!P=Ked>U?3KTAa z?f~R&E597W9wRA_bmE?v`O&8CliAcj?qSt#`_? z=y4lHq_X&IFdjp?_KesEI~Vm5ZRe~;y0TD;eWRK)fXr=Bb5gmX@jsT3`#dYR>>Ynw ztZa^WoqGuFiI>e4vMO5+ZB-s@LfSUUzhH%S2#lq4drTgP!2}~TB8_7GnhV#p95}Wq z-!-C{#|E`8f6ZCdBxt(~f8* z&AkJCZDC2M8#{n+9Ru$jaM-bB?yTuuH5d%FEzfqZ%M<0BR_%t3T4!@_^y+sH&>)}a3`~$d? zq;xlELc(FVET031WZ=}$S#Eda6qMyq$H3GFyEYgSQ(*dy>Htk%_2TjsZ)?K*Q&v@{ ztZP5B&B&Kv+uTRn08RH)Z({qL3e|S5g#djyXe`LVrmeE%>&;F}R|HWjT4`0rh9|lJ zPRiH?;B;o9)8qhS#K;H~pVMC26hegK9zwWfdu)hyk)OVBVRd?bd2U%}6(R~?4-rSv zQh}9HYi(}ss4U9O%nNI58+oPS4TTh_jfHXpR4$taxWN&3!-$lW6ZEZZe$2O$V7@ag z&rg`~{Q5Gt$HaaM7nB8jg#^c0nd1uv@^fH6j#w}`0T)nFAZZn*x2+v~32COr<%==} ze4GV-+^YP3U}J~%^U$u{%#CmrKmfOLW3;{>CD3yG05M;Xu5xR+Y?eJ3%iV)W=g-8- z=4jQqdtT=_Q%KvYCV;(BHTg}fCa6ay^q0H0`~zLiu|X?)ZyrwMZv3~#HGO_ zQ~CS5;F3vyf4~|R<_BxM3VcJ*N+Q~GG@hh#KnqPawI}`Yoqe1g)kDBRhC!QvLJ5t-p^%!Y?5&0;^ zg^>mXAf#_n+&z}cv7^x5)x4;4_rR})vyKa_|9PeBFgGo#m>-d@eY!ZicBu40%s|Yq z_l3BhuXl?ES6ms(&G}O0hOB)@Lhfx=Zn3YgGnSk4r7qjFG?-;?w{pwgsfk$b7h<{l zaV9EWli^tI{?2&4IlJnzhhk%%dt$NOFF7RM4GXjsRnc>eorWN-l$A{j@i=lkW=sV& zkJ$iN^O$L28ik~vg*9)kR*WrJM!B&-!R8A7&4!V;Fz6kQ(}B>toDDu&jy`LyT@Z4} zmhSar5>>vYZ^Jq3OPrx{g-Gvmrv*b9J_Si%X*co}B>kfL1>uG|N0A9h-x{*(1rEn) z^zB9t@Rl~jc1cu=;iw2-Oe`7B2y=-ZKWc9Yhm{kzlYkxhmZ6wZjc|rqRK5%QAi;uq zgz+K>9mcrxt>ZJL$xOXP1ik@h8xN`dj84VD-QsqWxwaL;kv?^AR{8gmLUl!CmuPmR0dApfrjb7cZ)Z`#_=0L-5uh z5MRKervZ6w31?wbyi$R@X5b{~+E4$l@vKl@T1m}15N!q@IoGfS1%BLOuybT zr6SWHf%ypog6;uo`Ge`la_i-e2STI5Dgo^=n{yN0c%eSS%a@jwTsnWG`ssqoa_}u2 zxy^%M6Nb?`Qfo%z833Y1Izp3UMFuF@^5U46Z($Ig`)TfsZBUr2Q&Nr;6j(03zqZ_d z!-Xa36_H#-uNY1|*4X1J^EnYndU&Vl^6M^eWQGy8KGlr?L?NduI}mgDwR<9n+%kc% zJ_vUr`!Qph?!Eu8e1MAs*|Ki?WFt>Crsq~#=Ox1~MLl|X?82(O3u|d#N|D|g z0#$gPSkVs1BdK}T)_*0>&cKHP8QPT^1&tXpluj00zoddP&! zz*_~_PH?k?!;C_Egu0!Uo?Vuglab~0IBqYhqYuT$O(zS)n#%~ZwB{9-n$A=>^_dMU zFi&vR0=ic?oq!&8XVcpfa8G`x$Chj2Ln27iH{e8(;dZ(mzd|5~Nat5gM+-!@^_LCz z=gZIMR+bifad@-^heyFPr_}b(6VU) z3x_t%6R=*w{k1*g^PVZF3xXzOK@{INKQlf3CDFDZ0&v&;>|gH+p$G98T?@HDn` ze*so{=gS*qzA+3fB7|qvO3&iJWH;aQO*daRJSJgkEy209m|w0}zMSBf>#0w6rA2#- zqLbox7y&S~YAdF#9Y+*ksr-pG^_TbxmeyeI{+OP-vvE43LT^i*5w=o-+5J@5N-oD4 zVk<%0Ou|+Ir3&DU>M;6nS~{pGMR}!6RN+Vq$D(;(;48?)`Z6uI9>ZwHS6G_icjh*f zrn}`&a1H}#f3EC;s<11!FfRwU!RioD5%sLAB(IuvMZYXen04tPree+4%YDvE-&Z3Q+PaE^x5#*PPSA9iS@ zoj8Fk>qU6E2RZwK7byqn=LC-f8zKQOlpjbB7a;Z?%F0Qv* zd4NG%T)Ch=;z@Tpi|ZK{@_(?LK=e51_fy7^plt;)5qKU3YNV|Vn70UKnF;@EM9j@0#+A}W>#9<1fzj+W-42((HW z>F8fvV-Ld$Yshq8#_!UMq6HltjhK={&0UKc|6i=nis+Rx7yd7bJ~&Tef;)g1+`mNB z`jg4?9LR&%t1ypw0nh*en*rFPRJYUdA(AHxD+!?QcwLG-_I2S!EltG{SfOOaqW(@$ zhk!L8&hOKV;)X@-jTvqdr*i@LhMYWs6PLp#M*~$D9F0?Xbmc?OD-<$xKDN0Ct0v17 zRz+p2!sz2J4-vSjQ^7VM=`;f@+loA#VnIw`qAKA1 zaklbBt<8v3Cd-?ehuryTb=|9~z^Hb@zyjt6Q6~`&2+;HPmWK4I@?a+W*p;1~EAMyM za%yrxz_hH4?98r#P;q9QCicqqp5m=I7oCpaC^)DahyeV=?#lG0r^>9FV4OItQ)qA~ zTpogsgp+j{aIcVvsR9zgR`5BrXcwbCVrIpBLHmyKp+NI?X9W;^u%I&E>njXrt zSDG_a>ha{3MluS`KNA^2{L_p~NRN`@JS+;KOJySb7y=0f7A#m0DC-;?T;dD&42?7ds|@&kV8hO3 z6xB3V7kFD*D>JY`?Si8{W+(#MA}V8s&l3cWx7VHD*xVF!<>ml&&7YqR1W4e-R{?f1 z%aa~%udW(hzrHfZUDLO2Rd43varQKUij7dy;zzs^3??EIZC>zCyzbO$QY01Kh zLPT%?bUaqpuFRZVKbFwW%si~0Z2F(wmK|;=bUQH#<211|opC$iz7E76NRD7eq_?p! z1HSBDw;xz6j>^vdPR2a5MNinb8Z+=n<9S`iEK80B%pQin48!TFr3D5kPCkJ2*z+L8 zl~W}adRSmXDB1vGW5o-$=Pd*f75a#DXMXf%#Ga?B1Pc&Q?}w^87pt?I0e}Pp4b4$D zFj!t*5f3Jr279&{Oww)!p3Gc3b=4L7sth7)=Z6?nIE)hw2(RS;o>wODJb?@`cSvE6 zO9vG8=DBRy*t~Jg8HlpOj9F<*aT4huA@Fb^_MlFVJN!SXPaeQ7_Sd5y7sW~nGaN1E zS%-P5T`C-U%E<$%h;)_iNcZO;LWv_IFOzWNCw>8FT2H<+#fxZYIM-fW5UKQd%1f~t z^FlBq0?>=fQZ&weGNNIsvs9R@)nO{7VshaKeeA441LbK)4nT*Zf^q|(@myF^0t*fC zGko40FA$*M0p$Phgbr$M#L4hHMD_!CGJ?W%`Q7VP`XlJ4{F0`s8rmn2zI7{lVAe|$Y(z4TT zN_*3}+4*x-|}8 z_%{1)&h}=10m!LGa-Pj?%e^f31%H?SXkLEajd|Y<Zmll;C4ST}Zg}-0+zOwJ( zzn_+GDu1J5U&XH?`H{~>ep$J@@=#SyRZrE<>QMDS^_uFZs-LU=O^vKMx8{zT@6@K( z=GT_je!ljR+GlECs{PNpl)9|CqPpt3wz^mApKq9MxV+c9f?+;Drty$z2wd~d-weW)rZ&-L+ zyQ@97y|ld!Sn&hxzw6lB@%E1Qc6_+w=8oGt?(KN2-BEg?d=Y9mvuLEU(x+w_Y>VucOUP5vHOi4qbI#5 z*i+Hd)U%{#xM#HIwcZc+-qL$}@4dZ`_CDGBlipwV{<-(fzO=s2^)K(=*neUFp8muA z@9h6z|0nuy>%Y7Iq5g07Kiz-4|Hb|{25bYD54OX5%OlqR+O~~diJ}3koTIvrVxI+Nx)Js(ro?6--FK^BFD%yulU`_i2fYqlp=4Y zxI<*fM}=P=$8+QOtqh;Nq6nXCW{HMMfy;j~7Js~a^ zL1>nRphXedl5ON7FKII_vWyJ8V=dlk;QB#aZ$X*ghGzU4zCVLJ*MSDtx?T)x-lME*-f2+w6gx5-0U@<(6~dC$t>ZsIpEiI8PLN(d*er!P2EX88m>ZodVZBcE}rC^W7H9R`42J|H}xeL&Hjw4e2{ zJ*#P;XhC|IA8|+YPx$;6pC|G8i0U(|AJ`WOANg(3s=lKy*dNx1eF0iG8|R^KLHD^n zw)cQW>6`$|n^Q8Qg2w45VzDW9P294N1=!?V;`vQGdsIF``>oEJu z{x{!0=asy=0nhPj(T8>A{i&|tXYv$iG4~a`PJYAZPSE#Gwh^Bnfd6f{zJja3^;P`# zH_)P+V?y!eanu*Q$+00WkG`z0pfkV!N(6b88`af=-|y$xA>C$Q%``D;vc@#V70OWK z%erFheug|uK8m%&tRKfcKCR+6h)#B+Xp-l^PM-pLa6D#+0wpu>p4r#fdm|WsUdTVl zM)MP(?BqwDFIJ%Jpga3b6vW z>K{#=@^8BLbJDzWUzV-R=^ZCc`KECu9t6iUTjH$NZrEmS; zeL~c&L`ox=?6va^RS}5MPWsB-E7R&Q=#1 zI%caFTEDq$OXz6m=<;nxLqnmRW803|E7TP~OdQ>^AaqQOZl1*74Vz1k^=v7K-A-)T z(us2HEC-Ju`_U~ZVV79~t}1E4o5++>w=#6h7FoM_-R5IQ1`3Y#3~VVVEe#DGdt~kA zV~-3Jly2FAT#i^xQR6En17@95QD;XDeoxb-jBY;GQ*cadIeL_3j&3e1J$B^i(SoCB zhxz?J@yM(MDP|}1m?~_N?qA*;_N(-1!R$5kydTtrOyPb6_M>h|mrlniz z8LX;S+>bu9i_}_t(X~b2!GbU33D|dWjzQQyVfLn1e45;8hY=9oxa3#fOK|4_^WMNt z-TTaYn;60jsPmA6tvo3>H+|epcR;VOoA+s$e}m?|GvVF^^v+H*-6LA%67$|0-YfT- z_vvC`*>TYi3+`T^YR*75>;Ssd0q}kmPEuFn+AJDjA8W*Um=I12O^S=*!8C!Kdyqeb z^P>|uS$7zJClT$QPwk$SXGcz<4N=xsZMIJuSapW9e0Nn&DkS5#~xhALAxpBpFnSg&@b#Y_EQM? zcjAsuFBc=Yt^pO8H?icAq!P$ObM*!LBZU9rbxVG;RUh)sUX-ZoLO#@d!*a(|&8(bb z_+>wGGyM=glZu}%!e7?-Fut?){FSxsg*Q9z51jvD7pr86x>L~us*ApSsoTFl) zdUgV%eFnYGvB>ex5!DD!Nxti!-$K68qVZZtib3?;D$$3Q4aRtz{ksEwqd6diyX{D^ zc=hx=N*Shml+uswW{C$BFYU*b5>QL0112w#5B6YGkgGU0LhA1!+>tx?B0on3$C<7R zxp)u$8v||mEctE{T*@c6BSq)ki(jVU4>tksBj1t7ty&yJse9G4EY)gT{8{qrgjueZ zcoQg@zt5<$teT9W>@ii_i&2Adlx2+~j=w1-hbakIKmMv^H`_mj6sA)8CyqW{LtXbn z_+8V3qinmX6WeILgS64|g1?O^IvrMZ+>Km(KSwI1)wmj~R{JQsE=GRxBV|Acb=ZmT zY%^t)RX%&ls)_zZm$_HvJ%I8l$M`JAHu)+p7p6_B^7n=q&rv?{eVRY`CiWv|F4oEF zhh*8s8YR|TQ%KkQAf98*NI_EhAnvtvW6H%SncugYY4Minmg=6NWV#4Xk{k8A_$zsj z^chn%V;$L>)^}Y~{X27q@GD!)T97wc&PD2Zo%3Q<&pnDqNe?Zl`CPnZtTE|3j^}kd ztT#@nlJu-WK2PL#tG_iDksI0TnmTM1XB*0FO`{3WguiXWe^%P5XrVb_0oug*D&Dqu zKQjmEz~7Q*K#OxU50fIK1?#T+flu+>?7&aJk{`*Oo>*U& zy$}62sc00JfLaD6@(oMnJk2LKs`VI6tO@Bpmp(!YOyeoi+G^Pt>bDoIV(;j3t#&Z) zIBFEHOI%7?t>?_HxmNRiay>N{>0j8c`FbEOF9t9#4Pn+@jn4*rI1`U5X%a@dCFw_T zm&kizlN#I6Hp(BXC03o-Tk+Y1(t*9md?)v4;wTQyspk*l?HuuZR~1U(taoPA*Q1NG zg61M?O~789fhMe}swL2Vlu0RW@rdqEONuAT4K2^7k$(nHXc=R*kTQl+f!{d-k~Oo$ zk&)cjTH=u2@xBSGl}7UDjrYlFw1J#5Utd^Ul{nt_tFbYT+9gVC_KVee){s3-TC-R6 zY@)T=dt4`;b zA{D5?a#rNHIgH<^&+2ihDUdktQBS2LX8pBJ${CB}mfSy^*EI#K{+pjxaSCv)wjL{) z<(M6~g5x|90^S%UHtz>cnm^X68c}QCuc)DGrll(Th%tzUIZ^~&e1wU)EMMX?o~)q0Ck z9Ea9w!lJC^Ft&w~g?+pq77A+x+@$8})o87@W@zrU%A23>w6;V^lq_*r3MDz;&Ufnd z8`u7%6YDZt4w0hF%@xt?xk!(q)5&eEuUdM5)=N3g64xNQUhJ>!3G;WeYW>;2_ssil z_G2$ zhnzBn{G>Q%YqmsmZ5cK&3~FZ<22yvfb$UlP9i_wrTdqZWbTPMOQ-x{ZTUuC zb=}C5+tiq`R+QHJtQP26T%<~-7Qi_;-YU|WeKgnld>X&7Zd#YL-jhscy>=swST4sa zXIxG3WQ|M9*qMa!(_%^w&Sa+>rDro%^c&;+w;uI6owl90{$Q_iZlnHi3HnR(A7w#& zzGm-{>+~Eo_iUIv|5=)z#St6{Gx(41(mGaL|La$Lk~~ThS4$0e^M=^?&}C?CfEK&B zK0RgjkF_?n=8j}NL31Se+u{ryXK@{pE)>)n*OyHN%$EacH`N^gquIXNm>E7Y7Y zH$Bdj&RR~!-!eC)*%y{1vhr$6#p%Y7<|=9s$)hN)qqZe+&;0#Jy0K?Cj^gWJ-5+yl zRLrlX=IPc+x@7VKdqZ;u-!j*Fll;Iw=Qz>Q@l0$Qe1k=4TDkR`l6i5yHzt;E@mS&- zV!ruPTW$V-u$9fv6LBuu5L@Z27QHc>7`ZPlNs}q1dzzz)b1>(FDfEn%5>{Uw!mqT` zl9MQH;`C3HJ+n0+t>s#hnk7^AYT3x1BOi0tkJp~-uu-hZMo{ADZ&K5?&Y z6dLgm+O!EdxlhG?>QVgVuGJdsfiB0IZV;ak*1Nsx7ycervTPH6-GH-UYk=Cb0XcLT z>yeN9cw3OdvP0@SzpX@mt`W(-gTNEfJ7Zi)GUs~yWnI^*{Xf2w`S=9eu@T>SzYJ-8 z=KEITDZZEcg!bzO#1Sp&W6scFS^ z^jf@|IhLVb8&oa$Cbo__NtF%wy%(kOdA@a}O4T(ZP1wtp2u0wxn z%IorGw}S23q^K6ByQVa2NKWA!En7*vm-$ZC*{Tn@mfU2Gg*a6>&R7$^iM`Eld;`Y< zd1(!3%HOPUsNbP$6GH7ZAL@4Txn%lUEfYa0AZI}rZ0Ux|M zbKn={hv#Ad_y$3oZz~i_1ckHMtg4uZPrKpgeS%@%C0= zrY(fmK?h>=bRy>A5}>wpiEj7@lIHztkoYJN3EmCVa70i7rub*1A&$Zy`JM1Nd{w+A z-Y-4|bd<-$e~3SePl_*yzXB)fb@+AtoA{>qhPV^@$hf!`bI`XjXFMUkCB6qd#_x(J z#qTjA{ZKpw&+~tWrud5Zkod89TKot-@}l??;u!D3oV6P>%^u8aw_qOIr?h+8iVi?` zJuLo!)z4+nST9F}khjC}>{Gymx>6hwSBXE0m&E-z=V}M;9S*U{G@SWAA%XZU-O?kX zQb;dOHZwSUCXV|00AiUVbERMA;bcA{56c4aH}Rhu&0LnqkSvv9StiTjFByT~W0kB1 zR=_i|1|E=gvK~=l7RW~UQ8vpKcto~|7sM~+LU>hnz&o;2E|yCqPgHly9@#7VfO&nF z?3V*_P!7puau~jsE96Q!BK|J^0pH$V%T;oucq$2 zbnniIsS8qjFCH78nVw1=(^p6DMKcqJCLCkxlG;1HV|r?0cj}nFy8Fi`XT}d+ynWBa zCGPR~y{muQ^ntPQ@rkJeuJPEdV_w)8A_J(U(#E)P8kwkH)Fw-XFjBY)B};b0Fc1V}mZ{fWBw9b(nhl_2hFx@ z)NMJaE-4#lCZ~3!9OPf`#>AF*4<>#~-DvjeL93d&c(f)c4czd(UV>(>?nWzBo4Rm>I*kJ*+RA)T55W z>f+qAZE|8}V*liR=V9y4u|;RRR9)pB$)u}pF zb?R*Q5=sa$kCI6(z~^ zDY&m&y!`A%haNl&_jR`s(sl8Yg>x5t!QMZJdq2acaS1ZS8~K%JkH_z_B`el$So4#k z7vlFf(cVjEEL=U%^o{&!g!GjINBi=X^XK+k=DG-xnowr>in$wBk;lo^NaH?<49s1z zFm(Bmt%OWmg1pC9tz5Hq{(|`j2$@`l`gKGb3qDityKnpH*4DoeKU;?!^30zC)!O&Z z`nG*bU9DRA7`F(cFciycH&BP&q25I1@(Ex!D@zb)m-GIfUNy#%HMY z0sA%bB81W3qfJI+I#T_dyr$hDPF8{MrRpc_LgJ@k^)St-t3jz6dJD>aNIc|C^&{Fu zWb#*HVOOeOuxa>x1L4_7)N4{dU@4@-Xm$k3AH?r-)i2p<^$+AIktnD`4-tXhMjYHc z^>bFGs?4u`MPES~(1-rKSm$$w6~Wx{zN7Z9&G4NRN zU8R1^IQ37g9<4zR#Xl-)0u|GbXF=ura{fN(5$Ce@70f&#;%&59m9DC(o&`{CDAJ zWyFq;o<-C*SwMYy=<^5qntG5fB7Jn7`Z_&NJwTsO|3qHLI5oOhF*c1hkK*^jLE3O_ z>U;Ea^>?fm^ctZa#h6s84$%elD$?aE%qwV9q^U*|(12?JO*DE;L;jbTlMe~cjZkl6 zW0C(`(D+MYphwg%If9jieg;UEE>}ON)71~zRFY*Jv2r7@ zCR>SukCo{$zcYywm-YucRkiVPi!PchLJY1k(@{NlY8lG zI+t!>zvU@EA>xYoBB4kul8m%Ox+3?)95FX|l(uK$sL??-4b_-~8n2>;E#i!LB7tI! z<`ZkE|D+yK-%wvy=c{uIYN1g0{jn`a=O3MR;c*0(o`<760{0FELN9npgy8NrFo#6qkXv7IwaUg9Hu z(1nm7J|PlDD^buTPRdAvBuR>tlL}Hvsz^1dA+@9qJxr4f$&wstAdMtXnn*Kg0UcXG zmv&I5lME*#$Vk#fx=9ZiMMje`q?e2(<47MFPbQFlGLcLolgSh^l}sbk$qX`+%mVIH z$f}=vcGZ$u7#V$E#WqB*Kzl7AMk{4;#cu|_}>T-AtUS(UJ@;0 zlQ>D-CjM1&Ni(ENr6;AMI*)FhZjbIh-SfH+^h95#AE)1{KcGKqs5M+@*l&2=@V?Pv z%oryb&oMr1e97c6Z8zO$y2tcWv&GzQ-e7*v{Jf>wGTySla(-z!vBVY!2KQ_+H@kAPKeyX9sr%p9~%ekx*}FAaqygNLUwc3NH`e z6@ES9h|G)ZiQEx+IPz5FmB^csFQblVd9*irTlCTBq3FA@TxpY?NB9X* zYPoznr-V4k!lmR?GNo|IGnJUz%rkGK(y7Ee29EPYDtoC_G`(7TrJi?&qIQ?hrDMF} zi`(rXr{QDv^1Sm+g^7A?DjE3IE?UDL!hS@CQ&gl>LIazOuC+ee;McF?*h5z=s{S&# zZE@fz`r{-u?0N99a_ltX%!^V!r2)l4B~i&Mq9li@l)@Jp5v??pM>>^PWH%C9@8`LN z(mg!AR430K`S6RsBn?p)1QuC5_|{(icGCD?FJZ!f>W)7`CGO(_?N zNUIt1dD7AIC|_M2T}c_YTIitS8vSy26+fJ6;{jJyf5jr~1+to4Kz5>sSw#xdEIK6z zsg+B|>S(f#YFU_F?aC;bFcq;RMO?1pw<5)3bu6At#X#YPd?w$R&!Ui=bt##KI+jeK zg=9PjP)y-Au52cc46fLqlGSK}3uqcqKa)p8s1%RA(ruuOkDg+RCL~F*865#vi-U^1 zB^gVFDrL%Z62}D0s5=mL`>?r$c0HraI69_t=WIMrC5{uzWwWU(z?i6yQrSgKwla_2 zZDv$5RC?0&q5(B%4=oeTI#Cpu)xliO`zeh$MV;BgoFS%2dd6N5ED=r=^ahFAydyGt zNzXB9K#)YcKIRu3O0qJ}hg}ATk>i=jv7{t;1VJZE{2(Fq**zWRxFLbB_?+Z(`x=aMrq zPnZjkxHt!K(7lcoshW=}uB@!MT~->Cu$(liVoq?cgEr;`RLN#KD5x73m6(vx+9(pf zifVJ0OEqNcP)?g33DY->qHu#&SQ3BGAbPz#*H9jAW;uVzD)Ew4tc=vrN~_+SwP$&% z<66fp99C}{;jgHe+%#co;Q)1rR+mkr)Z+?K16|Ua(iu3>66`25>a$6kK~E{>QeT^n zRB&da+2j^kNbfQV>^hS{s_~3S$9P_FS%Y#SrdZ-0$;eDDo(oL3Q1iS^Tl?!+E0u>e zZ=QPI729Nq`8}djXEcA-BE<5Qv3A9nbSa{XIZbJyx;}AlL>G#%fT*`=8<_)l@UXMl zgd#OBDz5v%)h$agTo`cNg;g(OJz_<6U`HsfFw^c>sjIjV+$dwEb<`?gt!fvR^Wf6X zH{fS170;&{vpFqGiHq)H>l*1Bl5tMankX*y29y(}*sF=k;jsXvJQYNaGnSdnf`N9+ zlEUdY(2sZNQVGt?7$<~%-h@dq`W;T8rmMkkcgGr<-Q}i0P-mo=0*l@e^;@GH#hRu( z9}W6wR+KqKl6+yFii&?cb-3L$V-($%Q@E%gunD5Q(rb4alMY)#FmjB`nnM<&Y@I0$V6pHL^+qB#=14|Ng0>^{Mx&wD7BhNncG=>HSeZZLH;Sf|DdyI*g(geL zW)PAlJ#VlT-cm5TOw^h9iC%}scc^-p`N=Kpml_9hg5lk=VbUyi|E}0x?cQp27et`< zA@M+UaY}^#V$qJS!lTs9UMyT%n3JH7(3???)S%pfp>l+#9Nc<3s_@R31v}XLh0_aT z6Lde_pp_%Ejc#PyAQ=%XcSTBSoHh>*oXRJ`YdgS-r99o3X`C^}Sj({`dQ*e3c|mz~ z%Q$JF$k9_-G8oK{7NYUEZKggXbu}rz$#s)xx$MeoW5K>Wl|E0OgEU4GL!2B;Y=amgYo>kJ^pLk zzp?t1SJ1Xh-lAT5wstR(M61-hb&*qjPcUAsNyL;`aNfNQ*#%PaiKpFScif}rsW(*R zRLWdtftMo{f9rHB;{O8L!5(&zhJz}EOVMBasPNKvzQ-=ADBM=~gMuITf}Y! zo&-vPb0`|~5jEbEDz1B_xNEe0uy!o^RFZaXo>c90i@N^VyDywlVR!My-nrL~tc&qX zX9&f!UCA)VA`y1$l5A&N&)M_OU0C1IHtO7kn;xCe-W2hbxxMMi=FX1x;y8I|MVGO2 zHLaRrO>k0*uJcs=(7)Ht&Mkbq@KrfI=(tszYxPq$id{}3SUc!fw$xK8p=djGaEqpD zakwacwmn%pbNU%RWmN9$(`>XsKK8j$^aRQtoGbDo7x!l@blVg4mYSByV@EeuMkKmZMLM^DdhHfL^~x(Hktx=rib3`YRjKlHqn| zCr}X3fmN{!Ang+hGa7?fveYbCx27pT*Rt9_blXZ zVJ$6@D@FYny5IY~8+o*c3+Mku&38Vc0&ny1>l!+8HS=4;t?>%8!)T|*h|}z_ zczDYNFT;WZ83`ZOg*gjBC(+gxHYjjOLzAa5+M#8J*>g5(bC464fH#=9$fY^+kWf<8~wTQR-7H`mzeX* z*&b+CmC%$3#jLxFyJ2WAp!=9|jq&4-BquCXk@M{o9oM#umRZ~&wUmBxwpXC@W^dkd z`Y4Oil<1yn=O~>z@r+dyJ51pFh4&Mf`R;g5CuQ^vi3+1WS(eBrlLl!F-B>xpCQl#P zrW2c!En~aW(MXHgIXYJ-2vxCqt99&1notrPgFxVXjq?N&K`YLWKrrFcG(!g4jfnH_ zYOJHU#>qZ=E?EKvdT`QI4oQh zis__q;3J{2e3(m~)!8mdjg_r!!(RB7@+)pNs|?Eu4ly|*8_bw*i7X@U!^Yv%R$cx? z8U2LxfV<3NfSew!aC)K)myD&~%Qj3PtIDVMoT0`HDi4DgOn95TB@&+{%{ncWd` z=-v{X!I;w?aOybT6^z*(L8k$DsroW0051=Y4NhyN&J&UUu`{$iKT=L8IO>#ejqHhg zjRLPkYkqa*T1sup{&t%JSxTRz&!A1n71%+kgi{0b?qA)Qrr&5f@K6KYLPr^u3uA>R zbl!`i+In}WAJZ$@P0-(C+UZwE+o_ZvB)iC+K!P8LTa0%)pRsK}Z4)nT2yd3-MT!(P z7sbT$o=63CcS^fb7a6aT;x#i@_t*+A{0$XGoA1xn54khgYtZgTqMwb5#u~AMG%6IC zb#cdOYg5~N+VU)MPOOCETpn7>amJRU52cdK>eQDTT~3=JxI{KHY5t_yH%x35h5DN- z1pUZitLB}(bNw!zFs}2C({#hf)FmrEkZU>tX9|J}33Rm5jE z)XpEbVd|NSFB!ONYG|LjaMXmDIp}(cIDP1vrdPUu^GiF-NwH4Z0qr|}c>{9HtFh<#^jS$=ljTWysmxLxUv;ZWL zUO0E4YrbNnk+Qz(%*rcSTzrNXdlLzhzA}~P*lJnQ*NmJJiH>UP%17jSo{>`vzwH|4 zYi!8ZD{eLe(*lh6&==V5;+d%7ad*%`Jp-cFU_uj?Q^g-N-&oJsq)7(jcu!@F4Xm(P zr!HN(i8C53;*XxN+nVS{5+AZunM}jljJzaFv{)xi5G;02ZqfD6Ep^HL6N_>X*0)L@ zU^}&y;8cowwIXo|MSPk)?>~E~==xDD-JUpyzHwS)z1_BUWjR|`agzv+psk?+tf66p z^w;>{aUo%74;1I(Yqnj~RNH6=9pd>K9pkY(8!Md_o6f)>K)XDNy4JQaolUulY__Gl zy*e!$!pXKwqRg18kEidv)xadlY_Qk$jG5c+^ws+O!9X}1jSPdPF)SGJd9vAt7Pqsf ze_D+%#IumU7Am8uqtmDOqv1p(6!48tXvejB3==Ftu7%tQO9TW?sH&-=0Lr~+;O03F zJIkN8MLYG@ACEN}B3P^I`h&1N4y|jnhOE)Vb^s&cAiFf?6&$cI0Z8;|flleV|A~*Ecuch2&sGJ-)pmCD z>@Mt|OuM&jNe-?l1AP$tRU*V*lzT+!#}>=aL$~~a4Fo=Z#&e54JBR}o@lSAmTZ$YZ z@27b%1tY~j?GHUNI(UD6%MWMxZfGy}KqDO+Ej&$Y%!R{+N20W&@S>59FWfaq7ZL3Q z*$uF(!fI38GzzEDx43fAW$|gzmPokVj-R+v4^!U)pD0=%Wao$c*|jsXA=)1(+;+5_ zg*JzbOXnoPe+w9U9%C=c&(0z4s&Se@-rA58k`Q^sqGqV^Ww4vJaa-3-t#P~HcIn@` zZgSG=rpuyrxsXitMsKjZA>d^2qO6_M(9}F~^_;WjR<^edUvF<7)7TR9mf7X%M3W{u z12@(Q{fzB}oftMTCrb@+fg%TRDH3EVjp2j8dG*e_7N3y^2Tulv^~`r2q&Iey`voae zK9V+4V>TfQwe_ctZAr%}%^hnU)2Kw_zGT*J(v&*weEpDZV*5aQc-gQ+u#>bgX?rIR zHUm*eTc5`d6K#9Z(Ad!iU$Ca5u8iYahmE?k#!=gE&+H6On0j7+%4O&Ey|b^{NNYop z`m*}5ZNtY_*2L*mnYNu*mW}J}NYBZ(wsftZzd;+L`V~xIdtn;~Cv|?!((+IMfEQ;n zkYnhNu|%{9R1aq9s+%LOo!(p8PyMN2x!>&nHhrSqrldkLqsH*}S6?U8Unv8((9-n5WTHEAjP+>Fsq@zyRBu_RW3&&SS3p7SZiBZwXcb{uG_F?6$^$E2Aek(3wW)V z4!gCfb4p9llUwW-B(uY%=uKw1{`5^3NnnOl{ge7BRbc}KFN8!QVvhkz`2F`oXD##xsZ_NVBZ6o#fd%Zp?D3SPny;G@u$onQr6po1rViVHJMF2rG!&pfO6 zslZdNr@`lA-G_o<>#03AUft1PVp}YG_8L-gcMrH0z1sN8-z>?M+iZO!&e8hyKD<~T zp>23QoiY}k!Z?X>kGksI-0QvRFO$pI&aH({)Qc>I_X|%4VZc~{E}`Dr@Pa*yxy7D_ z5mVdEjMH|upR#BB{ZBOoA80=NK%aa6h$LH8_^R-5jQR?H*3$${mlY1vR%79I3O6)W zKf~DE?3?hIU~Do(puD1SpOkjIbNlMOO5ACC<$>u_uGqNbn=>Zg&AvG;S=X0}n+u1w zubO?}!HSFaQ%(I;-+}CG!#dFVqfs^mQ)ZDz@| z@z8g^JF%**v;EcLc)-ILYXOgf&aSN^jjGU2d2|C@RZ6iqZ>m_G#J-|_rSOxV)uz_& zUvg#@+g`CDwZ5z}=QrOfx^AvmcZ+1ZQ=<ZEz_8DJJU`> z?NopzQ+`w6d~#EL&D$4SO@dX&36#~{mGMU!vR;LQEzY9j0u(k=(*+fD`|kD~*NyKR zYcZFJ>;h2|_-Qk{_ueu=TUP4tU^9qu?&8^lreR?MLN3+SJ2Bojd1}?!6UIk+`}(4s zd(*{@8#iCj(y?NFcJ0Q^tyR4xf|Cn=mDi*pGsDLS08 z18XLEqNQb-JMM)o*c*YK5|^QqDB-Hf-o$TB*Wfgb$tIrjgkgk<$!3vL!j*kgSaOw# z{gPGjf84P>D#sNA4-Z9^R@sPDq{1xPBN2zo=hSn&>?^a`BX+|-8Giegr;y-Z=N;jg z)1f&i1lb>R*uxGTd%=I~6SIXj6`tj2$2tB&Pxu|t8Pb|478~+oV4d*lUG#HkDzNhi zWtx)m*TTooyXmKsIdO)@yClV)6LpXR!wk_#e~Gkdw0ZNm=`(tbJ0} zJ}GOTl(kRF+9zf0|377I4!Q$^G}$GPd&7vF(){olxt(evwuQ#v94Sh{PzE3o!?4=U z74LA8y?sQeeZ+{6Fs$9%+R+)HXVvHBTtkz$BAu1f*^H;~YPQjx&F18`sI!){u{rRMjJx$B=ZRIk>4NtYAw02^;zEoM6Ci?jY7TM6p6W{k&2EQ@mQA+b z*nLsW6%M<5`pQ{y;Zca)i2d<9^*ks0<2DDxZvJoN{hpS0PN-VA*;^PP@-X*7Hhx;Q zGGoy$&@!me{TD0)n2bCGI>^&VlEgLfBcEJ=}oXVET)q0~GtBxC{w)n)t=20t_jQZw(yzhVQ>g($}7ruvs zi0=H53u7Pn5RXYHROe(0(I%3j8RAkhsE!=Wfh?Smrtxt;ht2TP(nX_wkQml9$w;&1 z@n%NrE6VdKVY#6numWHCYI|o})x__9=a6yR4g2n$9I3C5Bhn#}7-U>gW-#r!H`o%jmGi+&39A zMSsFafn+k^FE7vdQYjz4(eMAd-mLj(X5J=RmnQEqYJfZItMXx`}_ z-;bCOZl<ue^0}dt(I&o5nA4oV9x=cyJ$+eIPyRN?a8gF-J8MVYF zZSVW;?lr8Z8_|2#tBgL5)-5OsI2i+y`5WoVOa;6|; z$V!TS&f9!`b8PXqzW;}V_fg&Vr5#Vb^6c$$OMOIS>l;rqMpK5s^zH`>KbuHh->ypp zsHgB%KW%up%huN5)?&;xTiz%13;630p$fSGk#3rm7ng=Xvtc9bO$#4Hs+bnxvBoc8 zm+3v8hCOWhtTo;Fmc%1+P;n-Wwp^@7lqxDS2HtE`oMn+rx^DHpaoJ|0fqp*~kP%-4sfh%P9x1o z3fz)5uY;G?*H^3pZ&Yfl%|8+h7W17>M<^WOT{CkDhfyc9%TGCF*4zaH%R-(z_wL&m zyY;%Z@e_tKyGeh;HP`Ib){J@-PhT{$KY_nQfEN4(9^o7?G!}7yJ!7;IW&x&sXxH zJexM|Y~8QuxnrlrLZ{5ws(+21lkO<@Il1Mx2d_;JkGUMegQvvkh4P5rGnVy_jyA?S zh3f3eHEULeCO};H$N7nlso!Vk!*3PExZtzaLVmM2y9fDKBP5tQ9Bvv5V@fi$aFNZR z^VfO(cD*!v4yO~$Ej_8gl*u~NJ;{OUFtxbYrM6Kw?$}JJbZf?9I`iViSMa*Cw%Kg) zuz~3X+G}}a%OFqr0Pz>E;rzq%KU(upvP6w+Lst=Hk;)uB49|-DA#rVUE@3nvl%5yG zB}=I&ih|Pel*Nu%pCf!kfj zstCSYR442A^oq zJhwyV-0DlKsX@}u9@QRC(dO)ufoo0M+w1F%I)AF0s`@?dj`=j`sm}GD*3{^gb=w>U zuP0OO@EEmmaKv2nSzcPi6Tw(Ommy4pi}?gh2t!Lc6ME}|ykX9m_EcYNq(1R?#MzzHCkA7VPwEpV z^@)@E#7TYPq(1S#U!S1r7qpBm!~1Boz+oktV)LbA*Glx!ojal1UqZ|H*w^=XpYG@i z-O#-_{g}?-7HP4B6p_$QI%l~2E;1h97orPL_usppRp-*F~!(K+)a2&(Kj!;DnEURce?HoMPnqEAg-MM|vxDPj6HK*%yl>d;fqa)ej z!Sb-(YNizcI&%K}Y@lM?(v*{(@=o6=m)rh0eD)R4CxM%_7jeUcp<$2X!`koIv@Cu5 zP%nx-!O-A`I0PMcsTQm2gbz!RE$q0n?2qZ`BP#HOUF+m@{q*6Lc#g7lGFuvH>8-5l zYmUX5`>HB?TOt@?jrwPUXfRF~K0#>2Da1rzZaxombPNl1c5Y7ebanWVh_ zu3yp7a>3?}jTdi1T_@fq)yIuOgf5}+5PXR6;uVP>&u3ws#|t9zS}G{jA|*bOycA(c7_pI&4Hc#9(b_yw_&Z8;Y?E=o@*R_0VbB`gKN? zsFPLcj=fB$Z5X5;;akxE2XRxP)vzyjs;>i%Q7-}YO+7t z;2pM*nd(!pc39O7q!UkgzY91*{S>eVJED_JQvVD%743AQ?#qBP(836md>n8*N{)p6 z>1IHydOP0PV^-GzYOQsnCvO9eQMUn3!Fz;yaQAUQtNJ9~>0?1_V*%d-oTR=5I9dHJ z;0*N_c-xN!82bP}!&`sMC_f&xegcR$I3a@CtWE^9sDA;ps?z~G(W?nXToW+rxAB%B zt^G+T`4d2^`U2h=WL6&qw5Z<%w5s<3YP6b+T0h0xgv`j9io3rAw4x_darZgEF{m|_ zOu@77(@^GdK&@}nie;vu%*#lRQ4ir=L>82s4w}3Q*bg`Zma0e)G8ER>8mwFg*H}GCYZbwhHBIjMe-5BH6V$Zjt%^xCt14gk8ci#Zqjd|Qg zu2X+Zt}2$_0r+RK10`R_+h2B}KRc0rf$S=d5nfpIZ5OaV2e=KjcA*dN0qz8@UBL1Y z;9jhgUFi8s;~Sq$R5;v z2vA!Cdr=9hrGizRPYpC@}!egmLY-3Yivy$x_HW^gZRY3ZHVUwcvO zhk(1$lf4-A9>CkxTgi2(y9Uszo&~rKC9lIMo(0?ojQddQ$K-m9?$>~Of%hh)Uk235 z>_^?#0j;3Ge$>^{d(;O2_oD88wD1DC1!Z0a)XLm~{BM)nkaG}F+hw<*x4#73TFlu2 zEVrSzF9T|`p#53Mec&F0f5j)~ib;ySuN%r|*tr!$X%6p*IG)cV9U96PVE@exrA0i) z)&pKed5wM9@OG}jG)0+ZLutG_32(s~%;)fKu;ckW($@~<3wW~Y$)U7}cN)F>t;o8$ z%a$tEXTEwYyc;jhwtTNDboFTU(rguqih;-R+BZzTS*2`J`Eps zJ+2eWMutj9z#CVh{sNR6L)I2sUP|WwU)!igxeVG$<2tduLEJT^)=q4T4NjW+M}jx} z{f)mzkf*)Ljnm%chEw!E`YyL1W;KGSx&Q8WxM^>2JB`dHb3m=H@Sc%($oI(+@@w*j z_GAqesE8*3bySZ>DUH-b&D27z)JE;p0fEp(-BhLu^}zS+qkbBoK|I(KrV$#YF&d|3 zct9&jQ?#5`;Q8z-T1{)H_7qS(P16j`(i{Ri8fl(3(Pr90htXEN#ibn%vramkj-VrH z7v9qL5a|3J@)X{>`3U5zOYk1I1LPoioOY9sq_YN=*4Jkm^m7+2U7AKJYpfkuxpu+A zMOc{WPx9ojZCJLmn)^d#?n~IE47>{wVWxnoGrDSEw!92wVcf! zZzWs8kuBlKmT+WCII<-i*%FRi2}iDkBUi$aE8)nMaO6rjawQzO5{_I6N3MjUu~eh6 zRHLy}qp?(@u~Z{p>Q%nfmwc%&`BGo5QRKn3z z!qHU1(Nx0GRKn3z!qHU1(OkmOT*A>@!qHs9(OkmOT*A>@!qJ@PyU$v^QezNW1PJ>- D?OtR# literal 0 HcmV?d00001 diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..e08c60d --- /dev/null +++ b/lib/index.js @@ -0,0 +1,4 @@ +exports.chatAI = require('./chatAI') +exports.removebg = require('./removebg') +exports.tsc = require('./tsc') +exports.scraper = require('./scraper') \ No newline at end of file diff --git a/lib/json/bot.json b/lib/json/bot.json new file mode 100644 index 0000000..3d445e6 --- /dev/null +++ b/lib/json/bot.json @@ -0,0 +1,3 @@ +[ + "" +] \ No newline at end of file diff --git a/lib/json/simi.json b/lib/json/simi.json new file mode 100644 index 0000000..4afde74 --- /dev/null +++ b/lib/json/simi.json @@ -0,0 +1,4 @@ +{ + "private": [], + "grup": [] +} \ No newline at end of file diff --git a/lib/removebg.js b/lib/removebg.js new file mode 100644 index 0000000..ea9d2bc --- /dev/null +++ b/lib/removebg.js @@ -0,0 +1,24 @@ +const fs = require('fs') +let { apikey } = JSON.parse(fs.readFileSync('./settings.json')) +const { RemoveBgResult, removeBackgroundFromImageBase64 } = require('remove.bg') + +/** + * Remove Image Background + * + * @param {String} base64img + */ + +const removebg = async (base64img) => new Promise(async (resolve, reject) => { + await removeBackgroundFromImageBase64({ + base64img, + apiKey: apikey.removebg, + size: 'auto', + type: 'auto', + }).then((result) => { + resolve(result.base64img) + }).catch((err) => { + reject(err) + }); +}) + +module.exports = removebg; \ No newline at end of file diff --git a/lib/scraper.js b/lib/scraper.js new file mode 100644 index 0000000..86ccff6 --- /dev/null +++ b/lib/scraper.js @@ -0,0 +1,42 @@ +const fs = require('fs') +const axios = require('axios') +const { + fetchBase64 +} = require('../util/fetcher') +let { + apikey +} = JSON.parse(fs.readFileSync('./settings.json')) + +exports.apiflash = async (url) => new Promise((resolve, reject) => { + fetchBase64(`https://api.apiflash.com/v1/urltoimage?access_key=${apikey.apiflash}&url=${url}`) + .then((res) => { + resolve(res) + }) + .catch((err) => { + reject(err) + }) +}) + +exports.covid = (negera) => new Promise(async (resolve, reject) => { + const covid = `https://coronavirus-19-api.herokuapp.com/countries/${negera}` + axios.get(covid, { + headers: { + 'Content-Type': 'application/json' + } + }) + .then(res => { + const data = res.data + const judul = (`*Update Data Covid-19 ${data.country}*`) + const positif = ('\n\n😷 *Positif :* ' + data.cases) + const todaypositif = ('\n😷 *Hari ini :* ' + data.todayCases) + const meninggal = ('\n☠ *Meninggal :* ' + data.deaths) + const todaymeninggal = ('\n☠ *Hari ini :* ' + data.todayDeaths) + const sembuh = ('\n☺ *Sembuh :* ' + data.recovered) + const kata = ('\n\nTetap jaga kesehatan dan ikuti protokol kesehatan\n_#STAYATHOME #PAKAIMASKER_') + const hasil = judul + positif + todaypositif + meninggal + todaymeninggal + sembuh + kata + resolve(hasil) + }) + .catch(err => { + reject(err) + }) +}) \ No newline at end of file diff --git a/lib/tsc.js b/lib/tsc.js new file mode 100644 index 0000000..96ea2c5 --- /dev/null +++ b/lib/tsc.js @@ -0,0 +1,29 @@ +const path = require('path') +const { registerFont, createCanvas } = require("canvas"); +const canvasTxt = require("canvas-txt").default; + +const tsc = async (text) => new Promise(async (resolve, reject) => { + function fontFile(name) { + return path.join(__dirname, '/font/', name) + } + registerFont(fontFile('ObelixProBIt-cyr.ttf'), { family: 'pg' }) + const canvas = createCanvas(500, 500); + const ctx = canvas.getContext("2d"); + ctx.fillStyle = "rgba(0,0,0,0)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + const txt = text + ctx.fillStyle = "white"; + ctx.strokeStyle = "black" + canvasTxt.font = 'pg' + canvasTxt.align = 'center' + canvasTxt.lineHeight = null + canvasTxt.justify = false + canvasTxt.fontSize = 50; + canvasTxt.drawText(ctx, txt, 70, 50, 400, 400) + const mediaData = canvas.toDataURL() + resolve(mediaData) + reject('Error') +}) + +module.exports = tsc; \ No newline at end of file diff --git a/message/ID.js b/message/ID.js new file mode 100644 index 0000000..ea5c9f7 --- /dev/null +++ b/message/ID.js @@ -0,0 +1,92 @@ +const fs = require('fs') +let { general } = JSON.parse(fs.readFileSync('./settings.json')) +let prefix = general.prefix + +exports.textAbout = () => { + return ` +*About* +Bot developed by *izo*. +Bot open source https://github.com/mrijoo/Tesy-bot +` +} + +exports.textMenu = (pushname) => { + return ` +Hi, ${pushname} 👋️ +Berikut adalah beberapa fitur yang ada pada bot ini! + +*${prefix}stiker* [teks/url] +*${prefix}simi* on/off +*${prefix}gtts* [kode negara] [teks] +*${prefix}kodebahasa* +*${prefix}infogempa* +*${prefix}gempadirasakan* +*${prefix}ssweb* [url] +*${prefix}covid* [negara] +*${prefix}kalkulator* [perhitungan] +*${prefix}teksalay* [teks] +*${prefix}artinama* [nama] +*${prefix}artimimpi* [kata kunci mimpi] +*${prefix}cocok?* [nama mu] & [nama pasangan] +*${prefix}ping* +*${prefix}about* + +` +} + +exports.textKodeBahasa = () => { + return ` +*Kode Bahasa* +af: Afrikaans sq: Albanian +am: Amharic ar: Arabic +hy: Armenian az: Azerbaijani +eu: Basque be: Belarusian +bn: Bengali bs: Bosnian +bg: Bulgarian ca: Catalan +ceb: Cebuano ny: Chichewa +co: Corsican hr: Croatian +cs: Czech da: Danish +nl: Dutch en: English +eo: Esperanto et: Estonian +tl: Filipino fi: Finnish +fr: French fy: Frisian +gl: Galician ka: Georgian +de: German el: Greek +gu: Gujarati ht: Haitian Creole +ha: Hausa haw: Hawaiian +iw: Hebrew hi: Hindi +hmn: Hmong hu: Hungarian +is: Icelandic ig: Igbo +id: Indonesian ga: Irish +it: Italian ja: Japanese +jw: Javanese kn: Kannada +kk: Kazakh km: Khmer +ko: Korean ku: Kurdish +ky: Kyrgyz lo: Lao +la: Latin lv: Latvian +lt: Lithuanian lb: Luxembourgish +mk: Macedonian mg: Malagasy +ms: Malay ml: Malayalam +mt: Maltese mi: Maori +mr: Marathi mn: Mongolian +my: Myanmar ne: Nepali +no: Norwegian ps: Pashto +fa: Persian pl: Polish +pt: Portuguese ma: Punjabi +ro: Romanian ru: Russian +sm: Samoan gd: Scots Gaelic +sr: Serbian st: Sesotho +sn: Shona sd: Sindhi +si: Sinhala sk: Slovak +sl: Slovenian so: Somali +es: Spanish su: Sundanese +sw: Swahili sv: Swedish +tg: Tajik ta: Tamil +te: Telugu th: Thai +tr: Turkish uk: Ukrainian +ur: Urdu uz: Uzbek +vi: Vietnamese cy: Welsh +xh: Xhosa yi: Yiddish +yo: Yoruba zu: Zulu +` +} \ No newline at end of file diff --git a/message/index.js b/message/index.js new file mode 100644 index 0000000..17da904 --- /dev/null +++ b/message/index.js @@ -0,0 +1 @@ +exports.menuID = require('./ID') \ No newline at end of file diff --git a/msgHandler.js b/msgHandler.js new file mode 100644 index 0000000..cf8a094 --- /dev/null +++ b/msgHandler.js @@ -0,0 +1,594 @@ +require('dotenv').config() +const { + decryptMedia +} = require('@open-wa/wa-automate') +const fs = require('fs') +const got = require('got') +const mathjs = require("mathjs"); +const primbon = require('primbon-scraper') +const { + chatAI, + removebg, + tsc, + scraper +} = require('./lib') +const { + msgFilter, + color, + processTime, + isUrl +} = require('./util/msgFilter') +const moment = require('moment-timezone'); +moment.tz.setDefault('Asia/Jakarta').locale('id') +const simi = JSON.parse(fs.readFileSync('./lib/json/simi.json')) +const botset = JSON.parse(fs.readFileSync('./lib/json/bot.json')) +let { + general, + sticker +} = setting = JSON.parse(fs.readFileSync('./settings.json')) +const { + menuID +} = require('./message') +let prefix = general.prefix +let GlobalChat = general.GlobalChat +let Owner = general.owner + +module.exports = msgHandler = async (client, message) => { + try { + const { + type, + id, + from, + t, + sender, + isGroupMsg, + chatId, + chat, + caption, + isMedia, + mimetype, + quotedMsg, + } = message + let { + body + } = message + const { + name, + formattedTitle + } = chat + let { + pushname, + verifiedName, + formattedName + } = sender + pushname = pushname || verifiedName || formattedName // verifiedName is the name of someone who uses a business account + const botNumber = await client.getHostNumber() + '@c.us' + const groupId = isGroupMsg ? chat.groupMetadata.id : '' + const groupAdmins = isGroupMsg ? await client.getGroupAdmins(groupId) : '' + const isGroupAdmins = groupAdmins.includes(sender.id) || false + const isOwner = sender.id === Owner + '@c.us' + const SimiPrivate = simi.private.includes(sender.id) + const SimiGrup = simi.grup.includes(chatId) + const isPrivate = sender.id === chat.contact.id + const chats = (type === 'chat') ? body : (type === 'image' || type === 'video') ? caption : '' + const isImage = type === 'image' + + String.prototype.toRandomCase = function () { + return this.split('').map(function (c) { + return c[Math.round(Math.random()) ? 'toUpperCase' : 'toLowerCase'](); + }).join(''); + } + + const convertTime = async (detik) => new Promise((resolve, reject) => { + let menit = detik / 60; + let jam = menit / 60; + detik = Math.floor(detik); + menit = Math.floor(menit); + jam = Math.floor(jam); + jam = jam % 60; + menit = menit % 60; + detik = detik % 60; + if (jam > 0) { + resolve(jam + " jam " + menit + " menit " + detik + " detik ") + } else if (menit > 0) { + console.log(detik) + resolve(menit + " menit " + detik + " detik ") + } else { + resolve(detik + " detik ") + } + const err = 'Error' + reject(err) + }) + + const Platfom = async (platfom) => new Promise((resolve, reject) => { + switch (platfom) { + case 'aix': + resolve("IBM AIX"); + break; + case 'android': + resolve("Android"); + break; + case 'darwin': + resolve("Darwin (MacOS, IOS etc)"); + break; + case 'freebsd': + resolve("FreeBSD"); + break; + case 'linux': + resolve("Linux"); + break; + case 'openbsd': + resolve("OpenBSD"); + break; + case 'sunos': + resolve("SunOS"); + break; + case 'win32': + resolve("Windows"); + break; + default: + resolve("unknown"); + } + }) + + const sleep = async (ms) => { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + function replaceAll(string, find, replace) { + return string.replace(new RegExp(find, 'g'), replace); + } + + function banChat() { + if (GlobalChat == true) { + return false + } else { + return true + } + } + + const isMuted = (chatId) => { + if (botset.includes(chatId)) { + return false + } else { + return true + } + } + + const Calculator = (string) => { + return new Promise((resolve, reject) => { + resolve(mathjs.evaluate(string)); + }) + } + + function TeksAlay(string) { + let a = string.replace(/[A]/g, 4).replace(/[E]/g, 3); + return a.toRandomCase(); + } + async function CAI(iscmd, chat) { + if (!isCmd) { + if (isPrivate) { + if (SimiPrivate) { + let chatai = await chatAI(chat, iscmd, prefix) + console.log(chatai) + let jkr = chatai.length + let jk = chatai.split(' ').length + let typing = (jk * jkr) / 40 / (100 / 2.2) * 1000; + let cekchatAI = chatai === undefined + if (!cekchatAI) { + client.simulateTyping(from, true) + await sleep(typing) + client.sendText(from, chatai, id) + client.simulateTyping(from, false) + } + } + } else if (isGroupMsg) { + if (SimiGrup) { + let chatai = await chatAI(chat, SimiPrivate, iscmd) + let jkr = chatai.length + let jk = chatai.split(' ').length + let typing = (jk * jkr) / 40 / (100 / 2.2) * 1000; + let cekchatAI = chatai === undefined + console.log(jk) + console.log(typing) + if (!cekchatAI) { + client.simulateTyping(from, true) + await sleep(typing) + client.sendText(from, chatai, id) + client.simulateTyping(from, false) + } + } + } + } + } + + body = (type === 'chat' && body.startsWith(prefix)) ? body : (((type === 'image' || type === 'video') && caption) && caption.startsWith(prefix)) ? caption : '' + const command = body.slice(1).trim().split(/ +/).shift().toLowerCase() + const args = body.trim().split(/ +/).slice(1) + const isCmd = body.startsWith(prefix) + const uaOverride = process.env.UserAgent + const arg = body.substring(body.indexOf(' ') + 1) + const url = args.length !== 0 ? args[0] : '' + const txt = body.slice(command.length + 2) + const isQuotedImage = quotedMsg && quotedMsg.type === 'image' + CAI(isCmd, chats) + + if (isCmd && msgFilter.isFiltered(from) && !isGroupMsg && !isOwner) { + return console.log(color('[SPAM]', 'red'), color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), color(`${command} [${args.length}]`), 'from', color(pushname)) + } + if (isCmd && msgFilter.isFiltered(from) && isGroupMsg && !isOwner) { + return console.log(color('[SPAM]', 'red'), color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), color(`${command} [${args.length}]`), 'from', color(pushname), 'in', color(name || formattedTitle)) + } + if (!isCmd && !isGroupMsg) { + return console.log('[RECV]', color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), 'Message from', color(pushname), 'Message', color(chats, 'lime')) + } + if (!isCmd && isGroupMsg) { + return console.log('[RECV]', color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), 'Message from', color(pushname), 'in', color(name || formattedTitle), 'Message', color(chats, 'lime')) + } + if (isCmd && !isGroupMsg) { + console.log(color('[EXEC]'), color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), color(`${command} [${args.length}]`), 'from', color(pushname)) + } + if (isCmd && isGroupMsg) { + console.log(color('[EXEC]'), color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), color(`${command} [${args.length}]`), 'from', color(pushname), 'in', color(name || formattedTitle)) + } + + msgFilter.addFilter(from) + //client.sendSeen(chatId) + + if (body === prefix + 'off' && isMuted(chatId) == true) { + if (!isGroupMsg) return client.reply(from, 'Maaf, perintah ini hanya dapat dipakai didalam grup!', id); { + if (!isGroupAdmins) return client.reply(from, 'Maaf, perintah ini hanya dapat dilakukan oleh admin grup!', id) + botset.push(chatId) + fs.writeFileSync('./lib/json/bot.json', JSON.stringify(botset, null, 2)) + client.reply(from, `Bot telah di nonaktifkan pada grup ini! ${prefix}on untuk mengaktifkan!`, id) + } + } + if (body === prefix + 'on' && isMuted(chatId) == false) { + if (!isGroupMsg) return client.reply(from, 'Maaf, perintah ini hanya dapat dipakai didalam grup!', id); { + if (!isGroupAdmins) return client.reply(from, 'Maaf, perintah ini hanya dapat dilakukan oleh admin grup!', id) + let index = botset.indexOf(chatId); + botset.splice(index, 1) + fs.writeFileSync('./lib/json/bot.json', JSON.stringify(botset, null, 2)) + client.reply(from, `Bot telah di aktifkan!`, id) + } + } + + if (isMuted(chatId) && !banChat() || isOwner) { + switch (command) { + case 'menu': + client.sendText(from, menuID.textMenu(pushname), id) + break + + case 'about': + client.sendText(from, menuID.textAbout(), id) + break + + case 'bot': + case 'getbot': + client.sendText(from, `wa.me/${botNumber.replace('@c.us', '')}`) + client.sendContact(chatId, `${botNumber}`) + break + + case 'owner': + case 'creator': + client.sendContact(chatId, `${Owner}@c.us`) + break + + case 'sticker': + case 'stiker': + case 'gs': + case 'vgs': + case 'tsc': + case 'stikergif': + case 'stickergif': + case 'gifstiker': + case 'gifsticker': + client.simulateTyping(from, true) + if ((isMedia && isImage || isQuotedImage) && args.length === 0) { + try { + const encryptMedia = isQuotedImage ? quotedMsg : message + const _mimetype = isQuotedImage ? quotedMsg.mimetype : mimetype + const mediaData = await decryptMedia(encryptMedia, uaOverride) + const imageBase64 = `data:${_mimetype};base64,${mediaData.toString('base64')}` + await client.sendImageAsSticker(from, imageBase64, { + author: sticker.author, + pack: sticker.pack + }).then(() => { + console.log(`Sticker Processed for ${processTime(t, moment())} Second`) + }) + } catch (err) { + console.error(err) + client.reply(from, 'Error!', id) + } + } else if (args[0] === 'nobg') { + if ((isMedia && isImage || isQuotedImage)) { + try { + const encryptMedia = isQuotedImage ? quotedMsg : message + const _mimetype = isQuotedImage ? quotedMsg.mimetype : mimetype + const mediaData = await decryptMedia(encryptMedia, uaOverride) + const imageBase64 = `data:${_mimetype};base64,${mediaData.toString('base64')}` + const nobg = await removebg(imageBase64) + const hasil = `data:${_mimetype};base64,${nobg}` + await client.sendImageAsSticker(from, hasil, { + author: sticker.author, + pack: sticker.pack + }) + } catch (err) { + console.log(err) + if (err[0].title == 'Authorization failed') return client.reply(from, "Error, silakan hubungi admin bot", id) && client.sendText(Owner, 'key removebg ga bisa bos') + if (err[0].title == 'Rate limit exceeded') return client.reply(from, "Error, silakan hubungi admin bot", id) && client.sendText(Owner, 'Rate limit exceeded') + client.reply(from, `Gambar tidak dapat terbaca, pastikan objek gambar jelas`, id) + } + } else { + client.reply(from, 'tidak ada gambar', id) + } + } else if (args.length >= 1) { + if (isUrl(url)) { + client.sendStickerfromUrl(from, url, {}, { + author: sticker.author, + pack: sticker.pack + }).then(() => { + console.log(`Sticker Processed for ${processTime(t, moment())} Second`) + }) + } else { + const hasil = await tsc(txt) + client.sendImageAsSticker(from, hasil, { + author: sticker.author, + pack: sticker.pack + }) + } + } else if (isMedia) { + (mimetype === 'video/mp4' && message.duration < 10 || mimetype === 'image/gif' && message.duration < 10) + try { + const mediaData = await decryptMedia(message, uaOverride) + const imageBase64 = `data:${mimetype};base64,${mediaData.toString('base64')}` + await client.sendMp4AsSticker(from, imageBase64, {}, { + author: sticker.author, + pack: sticker.pack + }).then(() => { + console.log(`Sticker Gif Processed for ${processTime(t, moment())} Second`) + }) + } catch (e) { + client.reply(from, `Size File terlalu besar! mohon kurangi durasi video.`, id) + } + } else if (quotedMsg && quotedMsg.type == 'video' || quotedMsg && quotedMsg.mimetype == 'image/gif') { + try { + const mediaData = await decryptMedia(quotedMsg, uaOverride) + await client.sendMp4AsSticker(from, mediaData, {}, { + author: sticker.author, + pack: sticker.pack + }) + console.log(`Sticker Gif Processed for ${processTime(t, moment())} Second`) + } catch (e) { + client.reply(from, `Size File terlalu besar! mohon kurangi durasi video.`, id) + } + } else if (args.length !== 1) return client.reply(from, `Kirim Gambar/Video dengan caption ${prefix}stiker / Dengan url giphy \nContoh : *${prefix}stiker https://media.giphy.com/media/fe85BL1FFJ85hKY8RH/giphy.gif*`, id) + client.simulateTyping(from, false) + break + + case 'gtts': + try { + if (args.length === 0) return client.reply(from, `Kirim perintah *${prefix}gtts [ kodebahasa ] [ Teks ]*, contoh *${prefix}gtts id hai kamu*`, id) + let bahasa = args[0] + console.log(args[0]) + const gtts = require('node-gtts')(bahasa) + const text = body.slice(9) + const dirm = "./media" + if (text === '') return client.reply(from, 'Masukkan teksnya', id) + if (text.length > 500) return client7.reply(from, 'Teks terlalu panjang!', id) + if (!fs.existsSync(dirm)) { + fs.mkdirSync(dirm); + } + gtts.save(`${dirm}/tts.mp3`, text, function () { + client.sendPtt(from, './media/tts.mp3', id) + }) + } catch (err) { + console.log(err) + client.reply(from, `Kode bahasa tidak tersedia silakan kirim *${prefix}kodebahasa* untuk melihat list kode bahasa`, id) + } + break + + case 'kb': + case 'kodebahasa': + client.sendText(from, menuID.textKodeBahasa(), id) + break + + case 'simi': + if (isPrivate) { + let cek = simi.private.includes(sender.id) + if (args[0] == 'on') { + if (cek) return await client.reply(from, 'simi sudah on', id) + simi.private.push(`${sender.id}`) + fs.writeFile("./lib/json/simi.json", JSON.stringify(simi, null, 4), function (err) { + if (err) throw err; + client.sendText(from, 'simi aktif', id) + }); + } else if (args[0] == 'off') { + if (!cek) return await client.reply(from, 'simi sudah off', id) + let ceknp = simi.private.indexOf(sender.id) + simi.private.splice(ceknp, 1) + fs.writeFile("./lib/json/simi.json", JSON.stringify(simi, null, 4), function (err) { + if (err) throw err; + client.reply(from, 'simi off!', id) + }); + } else { + client.reply(from, `${prefix}simi on/off`) + } + } else if (isGroupMsg) { + if (!isGroupAdmins) return client.reply(from, 'Gagal, perintah ini hanya dapat digunakan oleh admin grup!', id) + if (args.length !== 1) return client.reply(from, `Untuk mengaktifkan simi-simi pada Group Chat\n\nPenggunaan\n${prefix}simi on --mengaktifkan\n${prefix}simi off --nonaktifkan\n`, id) + let cek = simi.grup.includes(chatId); + if (args[0] == 'on') { + if (cek) return await client.reply(from, 'simi sudah on', id) + simi.grup.push(`${chatId}`) + fs.writeFile("./lib/json/simi.json", JSON.stringify(simi, null, 4), function (err) { + if (err) throw err; + client.sendText(from, 'simi aktif', id) + }); + } else if (args[0] == 'off') { + if (!cek) return await client.reply(from, 'simi sudah off', id) + let ceknp = simi.grup.indexOf(chatId) + simi.grup.splice(ceknp, 1) + fs.writeFile("./lib/json/simi.json", JSON.stringify(simi, null, 4), function (err) { + if (err) throw err; + client.reply(from, 'simi off!', id) + }); + } else { + client.reply(from, `Untuk mengaktifkan simi-simi pada Group Chat\n\nPenggunaan\n${prefix}simi on --mengaktifkan\n${prefix}simi off --nonaktifkan\n`, id) + } + } + break + + case 'gempa': + case 'infogempa': + const getinfo = await got.get('https://api.izo.my.id/infogempa').json() + const { + potensi, koordinat, lokasi, kedalaman, magnitude, waktu, map + } = getinfo + const hasil = `*${waktu}*\n📍 *Lokasi* : *${lokasi}*\n〽️ *Kedalaman* : *${kedalaman}*\n💢 *Magnitude* : *${magnitude}*\n🔘 *Potensi* : *${potensi}*\n📍 *Koordinat* : *${koordinat}*` + client.sendFileFromUrl(from, map, 'shakemap.jpg', hasil, id) + break + + case 'gempadirasakan': + const getinfogs = await got.get('https://data.bmkg.go.id/DataMKG/TEWS/gempadirasakan.json').json() + let gempa = 'Gempa Yang Dirasakan\n' + for (let i = 0; i < getinfogs.Infogempa.gempa.length; i++) { + const { + Tanggal, + Jam, + Lintang, + Bujur, + Magnitude, + Kedalaman, + Wilayah, + Dirasakan + } = getinfogs.Infogempa.gempa[i] + gempa += `\n${Tanggal}, ${Jam}\n📍 Lokasi : ${Wilayah}\n〽️ Kedalaman : ${Kedalaman}\n💢 Magnitude : ${Magnitude}\n🔘 Potensi : Dirasakan (Skala MMI): ${Dirasakan}\n📍 Koordinat : ${Lintang} - ${Bujur}\n\n` + gempa += `════════════════════════════════════════════════\n` + } + client.sendFileFromUrl(from, 'https://izo.my.id/BMKG/Skala-MMI.png', 'shakemap.jpg', gempa, id) + break + + case 'ssweb': + if (!isUrl(args[0])) return client.reply(from, `Screenshot website\n\nPemakaian: ${prefix}ss [url]\n\ncontoh: ${prefix}ss https://www.google.com`, id) + const ss = await scraper.apiflash(args[0]) + await client.sendFile(from, ss, 'ss.jpg', '', id) + .catch(() => { + client.reply(from, 'Ada yang Error!', id) + }) + break + + case 'covid': + if (args.length === 0) return client.reply(from, `Kirim perintah *${prefix}covid [ negara ]*, contoh *${prefix}covid indonesia*`, id) + const copid = await scraper.covid(args) + client.sendText(from, copid) + break + + case 'kalkulator': + case 'calculator': + let sl = txt + sl = replaceAll(sl, 'x', '*') + sl = replaceAll(sl, '÷', '/') + sl = replaceAll(sl, '=', '') + Calculator(sl).then(hasil => client.reply(from, `${hasil}`, id)) + break + + case 'teksalay': + if (args.length == 0) return client.reply(from, `Kirim ${prefix}teksalay [teks]`, id) + client.sendText(from, TeksAlay(txt.toRandomCase()), id) + break + + case 'artinama': + if (args.length == 0) return client.reply(from, `Kirim ${prefix}artinama [nama]`, id) + const getartin = await primbon.artiNama(txt) + client.sendText(from, getartin, id) + break + + case 'artimimpi': + if (args.length == 0) return client.reply(from, `Kirim ${prefix}artimimpi [kata kunci mimpi]. Contoh ${prefix}artimimpi hantu`, id) + const getartim = await primbon.tafsirMimpi(txt) + client.sendText(from, getartim, id) + break + + case 'cocok?': + const nama1 = arg.split('&')[0] + const nama2 = arg.split('&')[1] + const getartij = await primbon.Jodoh(nama1, nama2) + console.log(getartij) + let love, tkcck + if (getartij.love.includes("1")) { + love = 1 + tkcck = "10%" + } else if (getartij.love.includes("2")) { + love = 2 + tkcck = "30%" + } else if (getartij.love.includes("3")) { + love = 3 + tkcck = "50%" + } else if (getartij.love.includes("4")) { + love = 4 + tkcck = "80%" + } else if (getartij.love.includes("5")) { + love = 5 + tkcck = "100%" + } + client.sendText(from, `${nama1} dan ${nama2}\n\nTingkat Kecocokan: ${tkcck}\nSisi Positif: ${getartij.positif}\nSisi Negatif: ${getartij.negatif}`, id) + client.sendStickerfromUrl(from, `https://izo.my.id/img/Bahan/love${love}.png`, ``, { + author: sticker.author, + pack: sticker.pack + }) + break + + //#owner + case 'gchat': + if (!isOwner) return await client.reply(from, 'Anda Siapa?', id) + if (args[0] === 'on') { + if (setting.general.GlobalChat) return await client.reply(from, 'Global chat sudah on', id) + setting.general.GlobalChat = true + GlobalChat = true + fs.writeFileSync('./settings.json', JSON.stringify(setting, null, 2)) + client.reply(from, 'Obrolan global telah diaktifkan!', id) + } else if (args[0] === 'off') { + if (!setting.general.GlobalChat) return await client.reply(from, 'Global chat sudah off', id) + setting.general.GlobalChat = false + GlobalChat = false + fs.writeFileSync('./settings.json', JSON.stringify(setting, null, 2)) + client.reply(from, 'Obrolan global telah dinonaktifkan!', id) + } else { + client.sendText(from, `${prefix}gchat on/off`, id) + } + break + + case 'stat': + case 'stats': + case 'botstat': + case 'ping': + client.simulateTyping(from, true) + const os = require('os') + const loadedMsg = await client.getAmountOfLoadedMessages() + const chatIds = await client.getAllChatIds() + const groups = await client.getAllGroups() + const battery = await client.getBatteryLevel() + const isCharged = await client.getIsPlugged() + const { + receive + } = JSON.parse(fs.readFileSync('./util/stat.json')) + const UPTIME = await convertTime(os.uptime()) + const osPlatfom = await Platfom(os.platform()) + const device = await client.getMe() + client.reply(from, `💻 *Platform Info* :\n- CPU: ${os.cpus()[0].model}\n- RAM: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)}MB / ${Math.round(require('os').totalmem / 1024 / 1024)}MB\n- Platform: ${osPlatfom}\n- UPTIME: ${UPTIME}\n\n*📱 Device Info* :\n- 🔋 Battery: ${battery} ${isCharged ? '🔌 Charging...' : '⚡ Discharging'}\n- 24 Hours Online : ${device.is24h}\n\n*Status* :\n- ${loadedMsg} Loaded Messages\n- ${groups.length} Group Chats\n- ${chatIds.length - groups.length} Personal Chats\n- ${chatIds.length} Total Chats\n- ${receive.chat} Chats Received\n\nSpeed: ${processTime(t, moment())} Second`, id) + client.simulateTyping(from, false) + break + + default: + console.log(color('[ERROR]', 'red'), color(moment(t * 1000).format('DD/MM/YY HH:mm:ss'), 'yellow'), 'Unregistered Command from', color(pushname)) + if (isPrivate) { + client.sendText(from, "Perintah tidak terdaftar", id) + } + break + } + } + } catch (err) { + console.log(color('[ERROR]', 'red'), err) + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ef70b37 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "TesyBot", + "version": "1.0.0", + "description": "Whatsapp Bot - Sticker Creator", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "author": "IZO", + "homepage": "https://github.com/mrijoo/Tesy-Bot", + "repository": { + "type": "git", + "url": "https://github.com/mrijoo/Tesy-Bot.git" + }, + "bugs": { + "url": "https://github.com/mrijoo/Tesy-Bot/issues" + }, + "license": "MIT", + "dependencies": { + "@open-wa/wa-automate": "^4.7.1", + "chalk": "^4.1.0", + "dotenv": "^8.2.0", + "node-gtts": "^2.0.2", + "file-type": "^16.0.1", + "got": "^11.8.2", + "fs": "0.0.1-security", + "fs-extra": "^9.0.1", + "moment-timezone": "^0.5.32", + "remove.bg": "^1.3.0 ", + "canvas": "2.6.1", + "canvas-txt": "^3.0.0", + "sharp": "^0.26.3", + "primbon-scraper": "^0.1.0", + "mathjs": "^9.4.3", + "cheerio": "^1.0.0-rc.10", + "request": "^2.88.2", + "update-json-file": "^1.1.1" + }, + "devDependencies": { + "babel-eslint": "^10.1.0", + "eslint": "^7.13.0", + "eslint-config-standard": "^16.0.2", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.1.0", + "nodemon": "^2.0.6" + }, + "directories": { + "lib": "lib" + } +} diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..2cb2b6d --- /dev/null +++ b/settings.json @@ -0,0 +1,17 @@ +{ + "general": { + "owner": "", + "prefix": ".", + "GlobalChat": true, + "simsimi": false + }, + "sticker": { + "author": "izo.my.id", + "pack": "Tesy Bot" + }, + "apikey": { + "removebg": "", + "simsimi": "", + "apiflash": "" + } +} \ No newline at end of file diff --git a/util/color.js b/util/color.js new file mode 100644 index 0000000..370453e --- /dev/null +++ b/util/color.js @@ -0,0 +1,8 @@ +const chalk = require('chalk') +/** + * Get text with color + * @param {String} text + * @param {String} color + * @return {String} Return text with color + */ +module.exports = color = (text, color) => !color ? chalk.green(text) : chalk.keyword(color)(text) diff --git a/util/dist/index.dev.js b/util/dist/index.dev.js new file mode 100644 index 0000000..f2c2020 --- /dev/null +++ b/util/dist/index.dev.js @@ -0,0 +1,8 @@ +"use strict"; + +exports.msgFilter = require('./msgFilter'); +exports.fetcher = require('./fetcher'); +exports.color = require('./color'); +exports.getBase64 = require('./getBase64'); +exports.options = require('./options'); +exports.nocache = require('./nocache'); \ No newline at end of file diff --git a/util/dist/msgFilter.dev.js b/util/dist/msgFilter.dev.js new file mode 100644 index 0000000..8925d18 --- /dev/null +++ b/util/dist/msgFilter.dev.js @@ -0,0 +1,89 @@ +"use strict"; + +var chalk = require('chalk'); + +var moment = require('moment-timezone'); + +var updateJson = require('update-json-file'); + +moment.tz.setDefault('Asia/Jakarta').locale('id'); +/** + * Get text with color + * @param {String} text + * @param {String} color + * @return {String} Return text with color + */ + +var color = function color(text, _color) { + return !_color ? chalk.green(text) : chalk.keyword(_color)(text); +}; +/** + * Get Time duration + * @param {Date} timestamp + * @param {Date} now + */ + + +var processTime = function processTime(timestamp, now) { + // timestamp => timestamp when message was received + return moment.duration(now - moment(timestamp * 1000)).asSeconds(); +}; +/** + * is it url? + * @param {String} url + */ + + +var isUrl = function isUrl(url) { + return url.match(new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/gi)); +}; + +var isGiphy = function isGiphy(url) { + return url.match(new RegExp(/https?:\/\/(www\.)?giphy.com/, 'gi')); +}; + +var isMediaGiphy = function isMediaGiphy(url) { + return url.match(new RegExp(/https?:\/\/media.giphy.com\/media/, 'gi')); +}; // Message Filter / Message Cooldowns + + +var usedCommandRecently = new Set(); +/** + * Check is number filtered + * @param {String} from + */ + +var isFiltered = function isFiltered(from) { + return !!usedCommandRecently.has(from); +}; +/** + * Add number to filter + * @param {String} from + */ + + +var addFilter = function addFilter(from) { + usedCommandRecently.add(from); + setTimeout(function () { + return usedCommandRecently["delete"](from); + }, 5000); // 5sec is delay before processing next command +}; // Message type Log + + +var messageLog = function messageLog(fromMe, type) { + return updateJson('utils/stat.json', function (data) { + fromMe ? data.sent[type] ? data.sent[type] += 1 : data.sent[type] = 1 : data.receive[type] ? data.receive[type] += 1 : data.receive[type] = 1; + return data; + }); +}; + +module.exports = { + msgFilter: { + isFiltered: isFiltered, + addFilter: addFilter + }, + processTime: processTime, + isUrl: isUrl, + color: color, + messageLog: messageLog +}; \ No newline at end of file diff --git a/util/dist/nocache.dev.js b/util/dist/nocache.dev.js new file mode 100644 index 0000000..9557ac2 --- /dev/null +++ b/util/dist/nocache.dev.js @@ -0,0 +1,112 @@ +"use strict"; + +var path = require('path'); + +var fs = require('fs'); + +var NOCache = function NOCache(session) { + return new Promise(function (resolve, reject) { + /** + * Uncache if there is file change + * @param {string} module Module name or path + * @param {function} cb + */ + var nocache = function nocache(module) { + var call = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; + console.log(color('[WATCH]', 'orange'), color("=> '".concat(module, "'"), 'yellow')); + fs.watchFile(require.resolve(module), function _callee() { + return regeneratorRuntime.async(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + _context.next = 2; + return regeneratorRuntime.awrap(uncache(require.resolve(module))); + + case 2: + call(module); + + case 3: + case "end": + return _context.stop(); + } + } + }); + }); + }; + /** + * Uncache a module + * @param {string} module Module name or path + */ + + + var uncache = function uncache() { + var module = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '.'; + return new Promise(function (resolve, reject) { + try { + delete require.cache[require.resolve(module)]; + resolve(); + } catch (err) { + reject(err); + } + }); + }; + + + var namedir = ["./", "../", "../lib"]; + var namefiles = []; + + var _loop = function _loop(i) { + var directoryPath = path.join(__dirname, namedir[i]); + fs.readdir(directoryPath, function _callee2(err, files) { + return regeneratorRuntime.async(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + if (!err) { + _context2.next = 2; + break; + } + + return _context2.abrupt("return", console.log('Unable to scan directory: ' + err)); + + case 2: + files.forEach(function (file) { + if (file.match(".js")) { + //console.log(file); + namefiles.push(file); + } + }); + _context2.next = 5; + return regeneratorRuntime.awrap(ctk(namedir[i])); + + case 5: + namefiles.length = 0; + + case 6: + case "end": + return _context2.stop(); + } + } + }); + }); + }; + + for (var i = 0; i < namedir.length; i++) { + _loop(i); + } + + function ctk(dir) { + for (var _i = 0; _i < namefiles.length; _i++) { + if (!namefiles[_i].match("".concat(session, ".data.json"))) { + if (!namefiles[_i].match("stat.json")) { + nocache("".concat(dir, "/").concat(namefiles[_i]), function (module) { + return console.log("'".concat(module, "'")); + }); + } + } + } + } + }); +}; + +module.exports = NOCache; \ No newline at end of file diff --git a/util/fetcher.js b/util/fetcher.js new file mode 100644 index 0000000..7bba779 --- /dev/null +++ b/util/fetcher.js @@ -0,0 +1,102 @@ +const fetch = require('node-fetch') +const FormData = require('form-data') +const fs = require('fs') +const { fromBuffer } = require('file-type') +const resizeImage = require('./imageProcessing') + +/** + *Fetch Json from Url + * + *@param {String} url + *@param {Object} options + */ +const fetchJson = (url, options) => + new Promise((resolve, reject) => + fetch(url, options) + .then(response => response.json()) + .then(json => resolve(json)) + .catch(err => { + console.error(err) + reject(err) + }) + ) + +/** + * Fetch Text from Url + * + * @param {String} url + * @param {Object} options + */ +const fetchText = (url, options) => { + return new Promise((resolve, reject) => { + return fetch(url, options) + .then(response => response.text()) + .then(text => resolve(text)) + .catch(err => { + console.error(err) + reject(err) + }) + }) +} + +/** + * Fetch base64 from url + * @param {String} url + */ + +const fetchBase64 = (url, mimetype) => { + return new Promise((resolve, reject) => { + console.log('Get base64 from:', url) + return fetch(url) + .then((res) => { + const _mimetype = mimetype || res.headers.get('content-type') + res.buffer() + .then((result) => resolve(`data:${_mimetype};base64,` + result.toString('base64'))) + }) + .catch((err) => { + console.error(err) + reject(err) + }) + }) +} + +/** + * Upload Image to Telegra.ph + * + * @param {String} base64 image buffer + * @param {Boolean} resize + */ + +const uploadImages = (buffData, type) => { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + const { ext } = await fromBuffer(buffData) + const filePath = 'util/tmp.' + ext + const _buffData = type ? await resizeImage(buffData, true) : buffData + fs.writeFile(filePath, _buffData, { encoding: 'base64' }, (err) => { + if (err) return reject(err) + console.log('Uploading image to telegra.ph server...') + const fileData = fs.readFileSync(filePath) + const form = new FormData() + form.append('file', fileData, 'tmp.' + ext) + fetch('https://telegra.ph/upload', { + method: 'POST', + body: form + }) + .then(res => res.json()) + .then(res => { + if (res.error) return reject(res.error) + resolve('https://telegra.ph' + res[0].src) + }) + .then(() => fs.unlinkSync(filePath)) + .catch(err => reject(err)) + }) + }) +} + +module.exports = { + fetchJson, + fetchText, + fetchBase64, + uploadImages +} \ No newline at end of file diff --git a/util/getBase64.js b/util/getBase64.js new file mode 100644 index 0000000..7acf5d5 --- /dev/null +++ b/util/getBase64.js @@ -0,0 +1,14 @@ +const fetch = require('node-fetch') +/** + * Get base64 from url + * @param {String} url + */ +module.exports = getBase64 = (url) => new Promise((resolve, reject) => { + fetch(url, { headers: { 'User-Agent': 'okhttp/4.5.0' } }) + .then((response) => response.buffer()) + .then((result) => resolve(`data:${result.headers.get('content-type')};base64,` + result.toString('base64'))) + .catch((err) => { + console.error(err) + reject(err) + }) +}) diff --git a/util/imageProcessing.js b/util/imageProcessing.js new file mode 100644 index 0000000..71097fa --- /dev/null +++ b/util/imageProcessing.js @@ -0,0 +1,25 @@ +const sharp = require('sharp') +const { fromBuffer } = require('file-type') + +/** + * Resize image to buffer or base64 + * @param {Buffer} bufferdata + * @param {Boolean} encode + * @param {String} mimType + */ +// eslint-disable-next-line no-async-promise-executor +module.exports = resizeImage = (buff, encode) => new Promise(async (resolve, reject) => { + console.log('Resizeing image...') + const { mime } = await fromBuffer(buff) + sharp(buff, { failOnError: false }) + .resize(512, 512) + .toBuffer() + .then(resizedImageBuffer => { + if (!encode) return resolve(resizedImageBuffer) + console.log('Create base64 from resizedImageBuffer...') + const resizedImageData = resizedImageBuffer.toString('base64') + const resizedBase64 = `data:${mime};base64,${resizedImageData}` + resolve(resizedBase64) + }) + .catch(error => reject(error)) +}) \ No newline at end of file diff --git a/util/index.js b/util/index.js new file mode 100644 index 0000000..bf826b1 --- /dev/null +++ b/util/index.js @@ -0,0 +1,6 @@ +exports.msgFilter = require('./msgFilter') +exports.fetcher = require('./fetcher') +exports.color = require('./color') +exports.getBase64 = require('./getBase64') +exports.options = require('./options') +exports.nocache = require('./nocache') diff --git a/util/msgFilter.js b/util/msgFilter.js new file mode 100644 index 0000000..880173f --- /dev/null +++ b/util/msgFilter.js @@ -0,0 +1,77 @@ +const chalk = require('chalk') +const moment = require('moment-timezone') +const updateJson = require('update-json-file') +moment.tz.setDefault('Asia/Jakarta').locale('id') +/** + * Get text with color + * @param {String} text + * @param {String} color + * @return {String} Return text with color + */ +const color = (text, color) => { + return !color ? chalk.green(text) : chalk.keyword(color)(text) +} + +/** + * Get Time duration + * @param {Date} timestamp + * @param {Date} now + */ +const processTime = (timestamp, now) => { + // timestamp => timestamp when message was received + return moment.duration(now - moment(timestamp * 1000)).asSeconds() +} +/** + * is it url? + * @param {String} url + */ +const isUrl = (url) => { + return url.match(new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/gi)) +} + +const isGiphy = (url) => { + return url.match(new RegExp(/https?:\/\/(www\.)?giphy.com/, 'gi')) +} + +const isMediaGiphy = (url) => { + return url.match(new RegExp(/https?:\/\/media.giphy.com\/media/, 'gi')) +} + +// Message Filter / Message Cooldowns +const usedCommandRecently = new Set() + +/** + * Check is number filtered + * @param {String} from + */ +const isFiltered = (from) => { + return !!usedCommandRecently.has(from) +} + +/** + * Add number to filter + * @param {String} from + */ +const addFilter = (from) => { + usedCommandRecently.add(from) + setTimeout(() => { + return usedCommandRecently.delete(from) + }, 5000) // 5sec is delay before processing next command +} + +// Message type Log +const messageLog = (fromMe, type) => updateJson('utils/stat.json', (data) => { + (fromMe) ? (data.sent[type]) ? data.sent[type] += 1 : data.sent[type] = 1 : (data.receive[type]) ? data.receive[type] += 1 : data.receive[type] = 1 + return data +}) + +module.exports = { + msgFilter: { + isFiltered, + addFilter + }, + processTime, + isUrl, + color, + messageLog +} \ No newline at end of file diff --git a/util/nocache.js b/util/nocache.js new file mode 100644 index 0000000..011610c --- /dev/null +++ b/util/nocache.js @@ -0,0 +1,62 @@ +const path = require('path'); +const fs = require('fs'); + +const NOCache = (session) => new Promise((resolve, reject) => { + + /** + * Uncache if there is file change + * @param {string} module Module name or path + * @param {function} cb + */ + const nocache = (module, call = () => {}) => { + fs.watchFile(require.resolve(module), async () => { + await uncache(require.resolve(module)) + call(module) + }) + } + /** + * Uncache a module + * @param {string} module Module name or path + */ + const uncache = (module = '.') => { + return new Promise((resolve, reject) => { + try { + delete require.cache[require.resolve(module)] + resolve() + } catch (err) { + reject(err) + } + }) + } + + const namedir = ["./", "../", "../lib"]; + const namefiles = []; + + for (let i = 0; i < namedir.length; i++) { + const directoryPath = path.join(__dirname, namedir[i]); + fs.readdir(directoryPath, async function (err, files) { + if (err) { + return console.log('Unable to scan directory: ' + err); + } + files.forEach(function (file) { + if (file.match(".js")) { + namefiles.push(file) + } + }); + await ctk(namedir[i]) + namefiles.length = 0; + }); + } + + function ctk(dir) { + for (let i = 0; i < namefiles.length; i++) { + if (!namefiles[i].match(`${session}.data.json`)) { + if (!namefiles[i].match(`stat.json`)) { + nocache(`${dir}/${namefiles[i]}`) + } + } + } + } + +}) +module.exports = NOCache; \ No newline at end of file diff --git a/util/options.js b/util/options.js new file mode 100644 index 0000000..ff4296c --- /dev/null +++ b/util/options.js @@ -0,0 +1,32 @@ +//const fs = require('fs') +/** + * Get Client Options + * @param {Function} start function + * @param {Boolean} headless + */ + +module.exports = options = (headless, start) => { + const options = { + headless: headless, + qrRefreshS: 20, + qrTimeout: 0, + authTimeout: 0, + autoRefresh: true, + restartOnCrash: start, + cacheEnabled: false, + useChrome: true, + killProcessOnBrowserClose: true, + throwErrorOnTosBlock: false, + chromiumArgs: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--aggressive-cache-discard', + '--disable-cache', + '--disable-application-cache', + '--disable-offline-load-stale-cache', + '--disk-cache-size=0' + ] + } + + return options +} \ No newline at end of file diff --git a/util/stat.json b/util/stat.json new file mode 100644 index 0000000..a12d8b1 --- /dev/null +++ b/util/stat.json @@ -0,0 +1,4 @@ +{ + "sent": {}, + "receive": {} +}