From bb2e9d7247002f69263aa1e8c6041db20c2ce933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deniz=20Tun=C3=A7?= <49831545+creeperkafasi@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:15:58 +0300 Subject: [PATCH] feat(en): Add Skythewood translations (#2363) --- plugins/english/skythewood.ts | 242 +++++++++++++++++++++++ public/static/src/en/skythewood/icon.png | Bin 0 -> 14222 bytes 2 files changed, 242 insertions(+) create mode 100644 plugins/english/skythewood.ts create mode 100644 public/static/src/en/skythewood/icon.png diff --git a/plugins/english/skythewood.ts b/plugins/english/skythewood.ts new file mode 100644 index 0000000..172673c --- /dev/null +++ b/plugins/english/skythewood.ts @@ -0,0 +1,242 @@ +import { fetchApi } from '@libs/fetch'; +import { CheerioAPI, load as parseHTML } from 'cheerio'; +import { Element } from 'domhandler'; +import { Plugin } from '@/types/plugin'; + +class SkyTheWood implements Plugin.PluginBase { + id = 'skythewoodtranslations'; + name = 'Skythewood Translations'; + site = 'https://skythewood.blogspot.com'; + icon = 'src/en/skythewood/icon.png'; + version = '1.0.0'; + + async popularNovels(pageNo: number): Promise { + // I'm fetching all the completed project here in one go + // There are no novels in the ongoing projects page right now so that won't work + // And this is a blogger site with a messy link structure so not every novel is visible + // tbh idk how i can fix that but some is better than none so "\-(シ)-/" + if (pageNo > 1) return []; + + type SkyProjects = { + names: string[][]; + novels: { + name: string; + href: string; + cover: string | undefined; + }[]; + }; + + const doneProjects: SkyProjects = await this.getDoneProjects(); + const ongoingProjects: SkyProjects = { names: [], novels: [] }; + + const projects = ongoingProjects.novels.concat(doneProjects.novels); + + const novels: Plugin.NovelItem[] = []; + + for (const proj of projects) { + const newNovel: Plugin.NovelItem = this.projectToNovel(proj); + novels.push(newNovel); + } + + // console.log(novels); + + return novels; + } + + private async getDoneProjects() { + const pageRes = await fetchApi( + 'https://skythewood.blogspot.com/p/done.html', + ); + + const page = await pageRes.text(); + + const $ = parseHTML(page); + + const anchors = $('.post-body > div a').toArray(); + + const projects = anchors + .filter(el => $(el).attr('href')) + .filter(el => { + const href = $(el).attr('href')!; + return ( + href.startsWith('http://skythewood.blogspot.sg/p/') || + href.startsWith('http://skythewood.blogspot.com/p/') || + href.startsWith('https://skythewood.blogspot.sg/p/') || + href.startsWith('https://skythewood.blogspot.com/p/') + ); + }) + .filter(el => $(el).text()); + + // console.log(projects.map(el => [$(el).text(), $(el).attr('href')])); + + const dedup: Element[] = []; + const names: string[][] = []; + + for (const proj of projects) { + if ($(proj).text().length == 0) continue; + + const dupIndex = dedup.findIndex( + el => $(el).attr('href') == $(proj).attr('href'), + ); + if (dupIndex === -1) { + dedup.push(proj); + names.push([$(proj).text()]); + } else names[dupIndex].push($(proj).text()); + } + + const withCovers = findCovers($, dedup); + + return { + novels: withCovers, + names: names, + }; + } + + async parseNovel(novelPath: string): Promise { + const pageRes = await fetchApi(novelPath); + const page = await pageRes.text(); + const $ = parseHTML(page); + + const name = $('.post-title').text(); + + let artist: string | undefined; + { + const boldEls = $('b').toArray(); + const authorEl = boldEls.find(el => $(el).text().startsWith('Author')); + if (authorEl) { + artist = $(authorEl).text().split(':')[1].trim(); + } + } + + const chapterAnchors = $('.post-body a').toArray(); + + const filtered = chapterAnchors + .filter(el => $(el).attr('href')) + .filter(el => $(el).attr('href')!.includes('skythewood')); + + const withVolumes = findVolumes($, filtered); + + const chapters: Plugin.ChapterItem[] = []; + + for (const ch of withVolumes) { + const name = ch.volume ? `${ch.volume} - ${ch.name}` : ch.name; + const chapter: Plugin.ChapterItem = { + name: name, + path: ch.href.replace('http://', 'https://'), + }; + chapters.push(chapter); + } + + return { + name: name, + path: novelPath, + cover: $('img').eq(1).attr('src'), + artist, + chapters, + }; + } + + async parseChapter(chapterPath: string): Promise { + const pageRes = await fetchApi(chapterPath); + const page = await pageRes.text(); + const $ = parseHTML(page); + + const body = $('.post-body').html(); + + return body || ''; + } + + async searchNovels( + searchTerm: string, + pageNo: number, + ): Promise { + if (pageNo > 1) return []; + + const projects = await this.getDoneProjects(); + + const result = new Set(); + + for (let i = 0; i < projects.novels.length; i++) { + const names = projects.names[i]; + if (!names) continue; + + if ( + names.some(name => + name.toLowerCase().includes(searchTerm.toLocaleLowerCase()), + ) + ) { + result.add(this.projectToNovel(projects.novels[i])); + } + } + + return Array.from(result); + } + + projectToNovel(proj: { + name: string; + href: string; + cover: string | undefined; + }): Plugin.NovelItem { + return { + name: proj.name, + path: proj.href.replace('http://', 'https://'), + cover: proj.cover, + }; + } +} + +function findCovers($: CheerioAPI, anchors: Element[]) { + const anchorSet = new Set(anchors); + const result: { name: string; href: string; cover: string | undefined }[] = + []; + let lastImg: string | undefined; + + $('.post-body') + .find('*') + .each((_, el) => { + const $el = $(el); + + if ($el.prop('tagName') === 'IMG') { + lastImg = $el.attr('src') || undefined; + } + + if (anchorSet.has(el)) { + result.push({ + name: $el.text(), + href: $el.attr('href') || '', + cover: lastImg, + }); + } + }); + + return result; +} + +function findVolumes($: CheerioAPI, anchors: Element[]) { + const anchorSet = new Set(anchors); + const result: { name: string; href: string; volume: string | null }[] = []; + let lastVolume: string | null = null; + + $('.post-body') + .find('*') + .each((_, el) => { + const $el = $(el); + const text = $el.text(); + + if (text.startsWith('Volume')) { + lastVolume = text; + } + + if (anchorSet.has(el)) { + result.push({ + name: text, + href: $el.attr('href') || '', + volume: lastVolume, + }); + } + }); + + return result; +} + +export default new SkyTheWood(); diff --git a/public/static/src/en/skythewood/icon.png b/public/static/src/en/skythewood/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a49837a286fa7e5f05b3f5e5bd7264f79376d55d GIT binary patch literal 14222 zcmY*=1yCGM@a`RY$iWdHxCaRCZil;T2tk8uaOXIjpn(KJu;3D0g1ZH`;O;I#4(HFW z-m6#tS35gXHCw&iyVX0>{q?s|8fx-jOj1k$00350kkNV>P5(PVXfORns+Zu)Ky9I* zr3wJ}G5`RuPypcWWeTx|aB&NB3kq}b zuyAq;b8^D51{wc90Y~SLwpKp>TYytQn3G4CPvHLuGge;V9v9WCA5%^Y3+ zx6FS^goOG2uadDLei#72@1!UrspGv+)@qwXuK0!iTIbjW5vf3~E4EC#l<#u${QTE7 z^y6tL-U70+!CvkM5rU;MD1$>b>aYB*R)DJBC{kh67&@E#FB6NLEr!W8ae3s zzJ2rg?)NkL^LG2g>do(<`=E0~`?E+}Ku~}E$=f<83N?TlYA9__SVkC05XlPw%b-}{ z?jpCuyRgGP03vCqd4Y!b(+m(i5C{bp*(pQKzDO4e5}j)8*Rv< z^k)tMzHc*M6-Z8}wgGjnyM904KMt=j5#L0twr?O-gSt%upTR+ohbHI0+aJL}_lv7% z9MAtaZvJhvl+UuHyFD-ST|8@k=E(VMU@vVCuH&n1ouyJLKwI7z&Se>%HIfq{&T$Gn+PARrkOb2Ol-r_0e=ddS6Hq1UySRi&5=Z)VWt z>T@zM&`<}jb|%41l8K~|U|LJ#&@6$Wzw5cXm$5o1dn)97*PtOK?CI8iulDZo^ie+& zGRmPK{(v!uVIJ;=4O?ps!KI`@>488jWFmnyGB=R5RsrNQiPmo~x9)kZewSE>>Rbkv zuGLF)>#IMVLs0lB4G85p$=8ARU1{ZV(s|I#o(==3-+5n z^*29f@dLmT%MSYb$vHtKhqgslFpuTRa+Z3>?)p;&ru`@za9vaeO2ECpF(GZhrWMMg zjzr(Vh3xd{l7XU zM94BIW&B&|Ri`5L0o`qkdC3~~lEs8|1biL!n~#sd2rr(ldNXy5{4699pbQk5q7Zfi zO1|#;BhIk}HLaa8&s>flh#)qVmlXR>j=tXeIPOw5vSgnWxPfs*4npat?Bv-IT08da zP2tEoyE@c=cuHA4OKE>VZGYbO^1po``Mn69J^YIe={S1&p8vRutzj?A-gGnO(R*>* zQ|~l4RUX(zkZhRnr4M%h7)5n@+6`c$-!jycTN>}(Zd2GKsHFeG{aWe+{vuK-S(lK_ zpih*Em*CSIhR8=%lms~&)u8g!;7H!h^I=dXmu$q4W!H->h3Z*n+e6m=kN;3jg6^X$ zOxiat3e|T4twOaqpG^2+sf&tCW{aMpSu7_A^b2|9=3_Sy1owx}8!m?$)}_aT{o(jN1cCjTM-IRfozh9#ux28A=2#3ger zL^>U*z_zcNywj`E$mQMT_ubyt5?y}iRtWXRtSoF7H4a&nd^^+S-!DFZk3gUYwzQY} z`G{7PlWFN8CbPuoe=Wu}Ki+4)axG57nBN$3LAeX^67+uep#6Fp3=l>--5&}xUNU(M zY4OjB0mwkk5^G*vNf+7{iR>aGOi~z%%8Kvn@_HJhXNYB%N1kwd0IKx8(ZwYq3r5js zGw6X2-u;Nv)0^|nxcf)0rJ;csJ6U$r`^+;V0nu3sKjyc(Q-5*m{uU|Gp!_@`9`Jvz zGL)iP!V%9CZ5MBQUYmOS(MZLu8m0(cLJn^#Sb%AfX|d1MzdTFyi&szac2v%SwY5fY_wCN=C_DHco>$2bflw^5hwGYkXy=BqsE zi|dcbqe$*$s_G9-8&ib>{=WC2cX~iT9LdV#CiKA$Hj|*-S%2y+p5@(c&wsJmPqEtG zz8UX)dUJh@-WJsU1L&EoC1-l9`>8G~$xV`-u#7_T>wbEF?WS}!KpEv#De4iGiPrGc zpN=eYc#8W4LAZQyz+H12dtm|nOswSHLYhu8ZGv7cPBl_(a&*9KSkMwxLr|N=hj!Xs z?BEWe2nbS_#Co{#2Mx!!ji#%fOH{ZIH&4hx{?9)@KlkJEbiBNiAOo1{+k6~E7iKoL zmtGmvUUm4l9n7y7rbcKx26sQVoJMXpcD!2~6gQL%Gz0n8Q32guB@O+tsKJn!yq~Gc z?DTYnp#h6${^I8itLINoarc{X$**KkR_-;~eiN@hN%CJNVUaSfRc-X&Q>?ZHP`#+8 zdU*qnais7+8RWUa-@%oZK(fn641X?btxg?!~*NT3DYjh;pVjo;Q@w z;ouClo`@{@4lI`fj?*H%G(Z_0wNJ&EEq|S3yW8a0Akl>7JG=WBhq%X&k3gOK@F+pzvhCXkO_R*F#^-oSQxnk& ztdo#%n4lvJ5F4fFsyr1z|8VDFlx>nh*d>^8cX3~D76wJJQJpYWm`Z2D_(GSLM+ra~ zo(lc_TVQGA?PC4A1S{{;ep>(GIPr9Vm=lxr$UPOy%BgzGYF2}Up6D!i@mqqcBonv} z(@^A8AUGSG5PMrIy}yepCXwDHp4zBD5|3luz>zJjk;9Hs|Z2QWjH>iqX( z9^ISgJumH|m|Z@kM&2B-T8p+*4n$e^DBV*in4j;VS*wbA9nXL>4M;l}4S&=xKJOq$J3T>LCGZ2hnk zx;`EWd>j#mWw12`;K*z88=nqsP+_fT>I!FI(o|g%(ODdF>=iN_HVsY9x;pRzd-j=# zq-^0vWLo8O*D<^Go97y}Yrc(i-WBD<9d7_Rmhi$3e_cb@c56N_CQB6q+g7$knC_|2m$sVsG()>^ismCdrqlzT61he{2SPs zSl*wC4;uE2$Xn6rzi8D+ma2Z}Cs?*jbuUbR3!7*UN#C%9n!d6(nY|ge{jm(lb zB$kPoYl}c-+Z`!;#rrL}uWW#ztoVF~4Vf?aUhFM`h?y~je09;}gNXSTNn%doW-uMO z#^?%3=dX{+wbxUMSC1o?y{GEM;JS3m3m^ZDq5ayRy-@d!ZMMs>l&U>i!UQ`;Xorlc zEj4iNsqkqWC|j$~DkUw2DeaR_-_*_%+~~QLxlDQ^=$sw@^SjDPm#H9#?@`xN zs)yNnxq*af-ojt8?C;W*z0!$U=+IB|B8v&-zhM=+wX|7BdDb97|zx0^iHsZuI&lo%W!E?9;)#bWA zqV9|Rd#JkqyNiEmX18$zbk66_*XHz{UB$J1a0nLCWRqYqQ^s8yWKBpAZ+x)g71v!YCTpGgp zCGg!cFNsL%D6vhj@V`u222t5E`n-G4?89FpK9f09VQ{A<6cZ{$iKJu8RUFX`(}=Bq zRjLpn!lRp^AeP9=t%N>f_s6b9BBFYvCp&)rtNY&=(%>kX;XRS6ECAkHXJgFC%w&;O zoRgMx8H`=(Q;~vpr$;j1H9>!U$DMW;!*M$6j;u#SX)i)0a>eXl%wF&s#tPS*5T_p} zIt&?w5{y$PwADADyZW*2VqDF&Z-zOKiCLMN*Sr!$iUq}qp=@EzoBX~c&@KvhK{!|B zK}fi!wJjOM`~58;pHChfSI>-)3xv{StR))huGm{C&*J-$g@|6l8;=iFo?_~13?fX| zazD@lg{bIm*MhbRdrztL)Hy6%8dNA}zgMZ?Tx>yFl%66f01;?%jyU;vS~L!*&>44J z*U3-c;D%UsBX+RSLOkiB`4fHAR|sGDyr&RYDsq%eIqui~*c=*z+$NeGdSN!XLSGwx zrdseHVsgrqp>f3w0nZ5fhx-rU%HzR%@ma?D0Nq~cKSgEPigjTqACosmB9lxKR$Ola z_a#$MGJ}}}m)P;LoL?G#xiU0n#l=mIFk4588J>)4|7yHIL_G0nrR~O7if4fn%2O9s z6E@rHXbMn^g(BH5^?J9jF>D$5tKXd_wiRjn+J`2^zG3=aBqhODU@mYs=>SZ={*?-NG%_u%ay&E6! zl*sVpPoJrH(@hUv5{)*kd6rGkUn-)})vNiM16yFkXIM7lZbcIrvUXI__EP){D}5+mem zl!B49T7GjpME3M=kvU##8-2k&*Y9)MH#r5lsGMa&LYjUKaj$!}zNAi_$K2hG zPO!Wj13jqu82sK4k~1?)%aH%#Kyd;)fbtQ`Fa%R4}`#eC}+z6b?5h zVIIx~J265hk-=<^sBpSUPEwH}D^Qv8ZUoZ%b0SIPI<$2(GvKEh=x_*n!BpQqypkp< z=ua??8@6F#fBu)msq&K|!C%2uWu+dA>EMLKnjGj;`_p4P4r&M~O>w66s-`{a_deO| z)a&eN8}jRrZDHk)#nu6aE&~o^$UZtq#a8f@3u{QM^ zb?8*@?-$e|o*@GIEB&(q4UD-+h}X{4(@u~FFm)IuhQtvB5ewvn^NUNF;*di*V5}cT8E?WjfDIDk1LDH_a)4_Nr zDOda&-MulDEYAlbz{wTK_m!bYf0}5cI<=woDi6=K{=@3Uvyt(~ z^kMAh%|%32B*m5;65Aut(k*)pe~tI+eMjX`l*@jR7-AXs!^7UZXKN;ipXI7@e)$KZ zRPD0FcDT<<)i7{~pi+f$XiK9s#4ByAhHnGN@a7t0SWLMTlh*T=?j!XMEISdnb{$BH z-%v#_(Q1k>{V{0yfvcwe+AGvJ=`Bq5B^Iu9*M75yW2TM9+4FIu z|Dt4qiX)!4+a(W+RFn>d5AKD%TNIMcQ6=4I6@EcUqtiposoJ>_*3a!{^g4b z#{ct1rF|Q=J~ytXo(h*9G~@KGvol)>9ZzeT_Y4g8)8y0J#H_Ed{6fdZN9XY>DRMns zJ|@YjYX=YB{em?K9HuuKv8SexOo>{gG4u%1^Z}l;o)OOXG?DO|48a=)W;nE@3XIgI@{to}-|3uYNy_-V z$4Z*`*H1O9{3fSflPG^0pf~I&{bt0QOnY6Gt#jXSU?q(|ZQP((Gu#eW-0a1>S8JvM zRE6LIRp7*;^G*Ks$L8|+=dUy{t%S{oju^n9H3Zo>Z0hybsOjuOockBd~@WJwqYOPg-H<%f0XIWXj#emzwA=xJm z>hlD?gnvn)c9yjrkaHWh0}Olg{tVY3Of4<3u}l_0fes@>3idiCf{*@E>hDap{~2a; z^N^z^%p!64zI>Vfx4#}g{s+&!Kte9f%P#wcX2uYB#Pe*>qyC`_>s&qf6v5aQ@C-DM z&?38Tg}I5%>Q_{UO2(yo%6Lg`qHvmDMxF}-ca2eY4ZxF2fa0{Gx8F!WlIl=EB4YapL^1*j75w&s}qFnq#UD z16q)CtcQ~}KKzH^6`C9cI@+dPqC6BnKeWdp9i1EC6`n#M*J7KGZSe193r?O(jYOBy zsscB_?$xhC!vCI$DGK)R;J>d&a*52;|0ENFf8OT)`7UgXe5{pTyV=7<=N&)7h;mxl zNHLno7kyT=G`}a6owN-uE&|qz(S;)I@^oP6f*PUfQba`_e_Ac&*J^+^d%ExVXw#%b zB8bIyn9NT`mS!Xh0!>7$;U0@TJP*$8&*A3&Fa$7PXNjtmpN!1RL`m)sNq*;~ra*Fc z_oMrtunD+K3ChJv8sX8WQQQ3Ygm=^-KY!TJ5W+Q+>b*%LGcdZ6yDm>4;fb2D4yMMl z^h~+7k(L&m0xWm#HxU=8Tdzoo8=2SoRdP$p47cBTx);@qp;4P#GW_s-pUIP(g(;AT zZ^{(%?b6x#C3x=kiPs|CxP)2gA-%D7I1Imfff9*yXkZj`sE~V_^#mG$s<+gJEw(@6 zI>9tuw*d191}Hn>93mH(^LqOAcpl52bj4+it&HMx^7PUWkrP!nF~X6)gsUo$&2ch= zePzrZ{ofRwn!bTOcVZ|=*e$riXcKI0CpNSbtJSu+!@{a#We6rQR+-s8@ z-IGRi4_TLXUPst~=iDT14_=$&yyeUOlNY@7z+BZt4(S%k*6nEY++*ACF~AG<>~iXC zO}S@ArCGfFCCw+;fdwt67KqqgS?d<(uGFeK{mzPYSglZy!mZ3z)CV9^pr6K`ma&=7 z{ff;n=N)pWAYW*U#PhQb^AuS$Q5rN(gCEX1W0;`b)g*rIy>#BtPPdKeN=Z{cB}z$| z=CeQUtp7u^5`Mr5=tKvD}QCvbjp%#|;S%Wc0!*Y3p5l3nP$ULKrKuW{xbq$%Dlg@dmaDVOT+;8w= zJ?$>qHBhDrIx521IE7Ipzu5fsIWB|EN+vQ1+zy%68~*Syl6PyP_Q)#+B4!>FIieIK z0$w6YH#-~PYRUaGQ8VNxg>NyVqJ?Wd>~e3%M9rn7S zfhyAqOoMtfW!P*9?19$BIz5AVg8*$tn^o2EvC6tq@>&Zg4x!T z{pQR1upGM*-9G~pruQ~dkRx&miHNyghfAHu9OSaHP-@Br z9NLlq2!tYG}zRiYSdj?O(zlfKi41(y5my6)u@^wb=qACr?_fKJukMKZ-Tf zphr|awGg9+L{?C?jg=j%*geC9d8hu7PPaTm=u}ou$BMefz3>Po%&np0~SA^L%pN085^2q*=5Dc}5FBz#$; z`yK<)@ywPzrIuu}e+ZdhP(16+Ye*uY4TVAIq*!fCA$}@T@IS8qd?w5XcHx$pl`8l4)g!j*wGDOX^qBL?BJ%ofp&s)#J!c8gFV)Yu zbw_PC)GjtLi)BL(cDe{~Ffd87JC_S?hKS}6O64ORVa@rlrm(Q5uzcHwTN-nYl&GZc zVx$PIaibbB#1CyHGT_$6d>kgvW;ErE(GHm-Z^ZpIKtp)~DrIXyP}0b$OojTS#bdlT z7xcBq3=Jc8Y5s7&=xmaxjfB7M`tI!bUSwsJia*q%zpap_7baOB2kU_HzHyB+o@Xt^ zls?7Dh$-BrB82}cDF!w{H0!xy3HWGFZ^{FPV@ zD=RLoMpbhL-)+-6WKs*WX@iBK1hR)PxglrMIW;mlj>)akARZ zM*VJzoV<1VQ?S@mu*}of5Mr?{jb6Sc>{xAqj}FTLltY%CEqkowNIJlDPjFjV(Zcun zox_ewsy<#1A_Da5&QY4}XkxF>REGq4K1Z9%Dxg&;a}lSWauewtYo?eQY7IPy3vIXt zGj9NOi`JCLrI8s@Kg_ekL@U#KT)0;?H+m|kP$SQVGdcGvarAyL6$Qp+85=`T9mPD# z!0L;BO}P?&Pk}bx+ip}IsU2!Edu92W9N#RBp`~@XR>u>E%bOF=u6Rx$gRW|l>E=t( z>F;GKWD86uQLdW_7F77Pnks&QE%!|}EsCo1ypZL_IGMcgsomhlj1T(ZDtAoy2x{*d zmpT$2+C5B55$w{qQ9Yb$-M!w*?s7S(J$%mD#qYDVrGc6IT8bunkm)tFu-Vkzi&7-Z zz|TK@>bsk`cPMe+eTEgEj6~Sexi`5sB=+}5J^o$K))+v|DF)&m`GOp*g_g>zJGJa( z?9Y!8<*DskAvq}oClW9yw@nML74=yt<>HFc%7Tl# zsv-BXoZu<-S4y=B8npV}3Th_UM`$v4OmL+NP6EaRJ~en0n@8SD zBc*kRvq3*pUTi$Td6xOALeu0|2LI1!oIARB!I#VqlHTzX-NP~IKrXVaSvjAeH5d3* z`7kf}*hMQAFJl^&jv84mmibKuWrxuh5{ra?K@aEs#UP6w;+F;cWAxeRJIuds`qoXE znO^wgcN>Qj8L_v~nQM)~8q{n*|58l;nsGrI##xa~R^)mxZt+nEshJ4kzSj74cw!?) zVG*Vt&5ReYdBjUmp227yusnerM+Tbj(w}@IRq_<5Y@y3J6Xhlbq!rtqnaiykuxTT4 zsjG1qXx{w9pyFncGhD3wv`7`Smxtf&xML|-`t47eIZ}b{wr0SBln+u5xXUv0vPgY` z&VaGC7H;U3Os>Pdp^GsR3~7ysq;m81y`S{4`|I;#1hslB9{{F_5I@Ad@fHB}tsi_ePDaKIV(p*48>XbQYKpA zB?sdKOm}t^?Gg8!S7Tc^g>o63Kt6+MfRa~FTH~a(BwVL&`Q0lKPKmZZ<Vn@VYyQCg-aITOL>oE8Y6YPfCsK z1y@8t5A8@e=zNpvxL)WZm7eTL_XAT)sk80Ww14JoT&@CoX6!|Vh-$n;s#`717$2}e z>q*6RH%}WC{(GTF!f?D9gzvy44Jrz+iH}|s5h-!TE08a3e2bP_c3F zgi0xO*L0Ew`*&!_lWjpAmQmi#Y6e!gr$Ad&p<{ztbbrv>x`XtI zNqpP)kX?);3Z=6D>aF5I*<0Yyf_Iqv$#Xt>?p&ipHw~}=D4kq6yvdrr+f8cFcI`>A(H9WrN>-iLoYUhea*AOB@2+=nPZgX#zknZ-Di`o(IkhfF)Kq+m{yKlECXA7+2`vV0okF7b;JERNd z9HBlPSE!uD{PRw`HMX)48?VDJ-ZE3u9yd@<%y5hZ+s7dw{VdAX&lZQ|_)kA)8xB!T zz6PtXQE}{fk}Y*ke{NeqV;L0gI1&bIvNa*7k z)&1nCs+YXvjNg8!})p2+#hS zzH<0#7xltl7g+_XB@FS6e>%B#nb$I#N%5q$-*WzJ>GDfNGLMwTn`9SK3759zjr7Jp z#q-pvQM3mCqM#5_-XpP8zVv{=ar_ETy-`9*Hb_#~jei8W4TlRRDXh(r zKjE&ajHD^+Vg(~<7{(de;8J}dqI99Nwb=cYJ6QmX%3`n=TRKqMGLOwfjFSULgIS^X z*#a^z*hvq`r!+2AB9)qxr@&unvBmu>vg&XR`w7!kTe#~j-S^ac$@qQ8w%w;b5tLfs* ztgq#56&DAQN)pjGsCQpA#!-OW{s>r>>_?hlNl^R>R&U8gg<#sh!Y7v1!2 zT=Q*RuV(EA2u~gh0`rexA2|uV*+FeIXp$goA|#{K_3lu?kuyoEUE0)E*T3R@+EmnW zR+jsXzmc0kR7Ar=;NQQ;8d?LYJM#k0tpzKJt?hFxaO^_jMdsxHB1Ktgzi0Lq^-@^} zj^VrjDvnczv}iJ=;D`NiTF)6)SJIe?Wt}>><}b~r=E}H}0bzEbw!1Qv1@~lsO_t9e}Z5!9uine`^N?mVVsa}^(kITFke^u~@6VM2Q5UE^% zhql49zd5|`AIQW5?qarGWh3$DQ2+YzgByBqg!EM|;%ozHorowFzt&POy7fLbN*n60 zIU1yp%v$zcO)^Fg*c9w7vxXu&pMG_;PkZ(4iz?|C4PT3;%*xY)!>spxZpw4@@Z`EV zd_h4XNCE1nMpMIb!!Z?}0zo=8d~;4o$M&2OFT8gje)6z*<~>F^wpy%`E1B2o0sc`7 zbVpzn+=d@s;g|nbPc1<0j2I=f4|Ve7$>5zxjQK?oxkcBK1<6HQvTR&;4d}k|B!(HF z{?6B_90G7@v8N)y7p}cln046j=@@20CccC>WUiWOxkke4tAwwvb%GJX0BOz7zJ@mz zokMMO&SaDIG{+)eP#5_KkBVunSqeH1?xj0;$K>9%nKiCJ3Q<3$9m!#b?7aKYf6sK} zRQU~_?&YxZzNwT#BH@?U>KV$Z<1xFwQH22OP_Nc|^wTor1k|E}78}n_wJeNd^q<+^ zH9+`M>5zhV>M#=62h=%9l++YBJ$>E>Mmb58=8Lzs$ae6^6{ea(v_yyb7#yjCTx#ud zg<|TyhiWYJ%D>BMY7v}vi;2GpeU9bEDdArn3Eoddab$>J8o&R%<1?`nwfG|w{u2N6 zk3xT+Ao&cF9R%1O8EmR9tzTmtO)tM<89Vl$_V|3TP+&XbGYM$1pFh#6vU9yOGKU#Dj-sJdpF}m8BIeM_qitoqZ049aVX7eu7!Xu|rs(Q_d zhG(D(T8CoTvLbO6Q&$%84u{D1chH5*fo4*vG@$8w$x-m( zH%L0(VqAPPDa9d!X*C!qxM#p^N2r69@aj#O&3$91wgU!^B+!>(V{~D##j>Nazvpz$<3`3*O<=>s8cY3k1crkz3fbD%@AlO zSrbek#CVe~$zHTG$xYb5fINlZ$6zoZVCLUmI)Scf8N3bq>ATW9D3O`U<-x{^*Sr2}``ypzP!Cd{C5fj2Gi>BMk6|Y(bHT|>(@Ftk?}l%Zd_TWZ&^ylk zCNv9xr~e-H33y12_a8vs^^r4XpX1O!TEridMNY>B#yyS$k5$jpzWnVN>C6ACXNcOCpA zrc~5<7t6wOc?3P~+y(fJKQIO%aYe!i%;a0A!#n`+~U}PMZUqr9S@Ti%&qyuUj$luN7b$ik456-j+ zxY>r#vJ&#<8N8{U^{uYdUT>#m(JUsVX2}>DECCqo*Xv z?*R(c7Xr?Lnt46+NL9{Q?rcOT<4KeqldToG+Kzd+tWz<>8QezLP#uC`Tq7-VN;sn7 ze}bAJBe5n)vn6PayTXq|NF@@(s)&M>NyvG@9%ytSpcgu-lDFuI_wzMaqAjTVu^;zn z5i_zV`NH*YCwwRdLJ)V7P>bjk7Liz@sY$s|5zJUTn%fch3@d>O7pRGRS=8u8GZr{{ z2j&~Wa{4WB?m zz^^DuA~q&8r6CGZL%6kK+0{)Wm_I%&Tm}<5myreYYglB11c_V}Fb8`xc{%g=@&fwr z{MQ1XgHKnVBpzg^6y4F9S*eXzv zO{>_aMlx@yQEYR>$(FWS_~B2KAzuJNGfLB#LaFC+Qa$u`BG#>?QhT;l_293S5OQnN z3ngL*gUwoDf#x1WYQh5R=P4PykQ@fjPx@vF9xuLqKo60 z=!OFkVs~AKHDR>tY)WS^Pp?yU6oVlOicp(n^=hjuNALN ziW&>X-`ZRLT)+l-k5Ulc#B`cinzjK{MF({Cs??MxeHPkaHP!5DI2Q7uT30mCVAf9wPZD!m2l1kKm z1%>%+tT!(x4P$}itA z9*sCY5-5maW~WU|;wT#as6EDbmvv{oKuy0mqJo)!;jT#&e*sOWnL_1e%eDoo6OH== z)%DNZgMYkkXy_o>rC{|Iw&-%ryiEIAV7|fhvb$lzO*5@pT3chCymv=Q#u`i4Lx4Mr zyXUeF6sy=7qNCDT#VOH(<|x+?iQq!ii({S_f6oY-@^hSzrST46Jre}C{%mGhQwmlt zRQ}?}`Av;uX6l8zt;L6y{wPt;_|Zi29&=DJgiRU*hn*~e{+jOMQAlUG}{vEtdW|>QfPtATsF@i$ty!u$y%dTw+yhz`|%Lf0XUmF zo`Njw)y|_irSYBF%yC}vibP^TQ`dH}3Jw{U$^}|ynx{O~z??gq9#zMw3<`8p>%*R8 z_3X zY+Qx!|HHW0R{cvcB`U{qnZe4xYJ&+(!cE-_J@%DdsMC)FyJlgJTWFKFtH|Gm;rSbs zTg-4%e=GS*=U9`-RY@HV;ZrxBMr9j9y{I)P*_J1_p{-!dZcYxoFlIw9U*W*BlmD~o z<)5^f_9_vxSQe|K1=$uk);fX(LyM8R~KX&jdx$Ym$y_BnuHX#5c$bJi+pM)$OFkgUCyxJjeMO} zt4VDLu&fK+CDL>#(c{c$w)G~FCg#_E@;~suyjD-4=nuJzc4Xg2=Rvd;a?nFGg=}}x z(GsJR--O?DLQ)Cpt|Zq{iJ&Vi^Bb+IK~a$zW!!3W5jI3FlxQ}EGScYsLR$p9WJfjJ zF4!=NClg~Gl?pUds<_4!+ClkO`(XK;Vf-r3A4xp(;R4}<)Jqd%e=T zdC#AyXXBfXRyf0t-hA9-;wj8XEZDt~;qe*4W6|IbWJ>56#YQ}b2 zlo!@1oZrI1r5Neb7lGJJ#ozi^=Hoxv?#UCbRy^H512x*00(fclDPI0o11QR>$&^c( G!v6=qoFTdZ literal 0 HcmV?d00001