From 2d7e79f9246902b83f4294c78ee5b878ce3664a5 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:01:43 +0900 Subject: [PATCH] wip --- .../src/EngineBase.ts | 1 + .../src/Firework.ts | 121 ++++++++++++++++++ .../src/envs/lobby.ts | 55 ++++---- .../assets/world/other/firework/flare-1.png | Bin 0 -> 2704 bytes .../assets/world/other/firework/flare-2.png | Bin 0 -> 2684 bytes .../assets/world/other/firework/flare-3.png | Bin 0 -> 2708 bytes .../assets/world/other/firework/flare-4.png | Bin 0 -> 2695 bytes .../assets/world/other/firework/flare-5.png | Bin 0 -> 2721 bytes .../assets/world/other/firework/flare-6.png | Bin 0 -> 2717 bytes .../assets/world/other/firework/flare-7.png | Bin 0 -> 2699 bytes .../assets/world/other/firework/flare-8.png | Bin 0 -> 2696 bytes 11 files changed, 153 insertions(+), 24 deletions(-) create mode 100644 packages/frontend-misskey-world-engine/src/Firework.ts create mode 100644 packages/frontend/assets/world/other/firework/flare-1.png create mode 100644 packages/frontend/assets/world/other/firework/flare-2.png create mode 100644 packages/frontend/assets/world/other/firework/flare-3.png create mode 100644 packages/frontend/assets/world/other/firework/flare-4.png create mode 100644 packages/frontend/assets/world/other/firework/flare-5.png create mode 100644 packages/frontend/assets/world/other/firework/flare-6.png create mode 100644 packages/frontend/assets/world/other/firework/flare-7.png create mode 100644 packages/frontend/assets/world/other/firework/flare-8.png diff --git a/packages/frontend-misskey-world-engine/src/EngineBase.ts b/packages/frontend-misskey-world-engine/src/EngineBase.ts index f8734dbf5e..77b8cd78ea 100644 --- a/packages/frontend-misskey-world-engine/src/EngineBase.ts +++ b/packages/frontend-misskey-world-engine/src/EngineBase.ts @@ -20,6 +20,7 @@ export abstract class EngineBase extends EventEmit protected engine: BABYLON.WebGPUEngine; public scene: BABYLON.Scene; + abstract sr: BABYLON.SnapshotRenderingHelper; protected fps: number | null = null; protected disposed = false; diff --git a/packages/frontend-misskey-world-engine/src/Firework.ts b/packages/frontend-misskey-world-engine/src/Firework.ts new file mode 100644 index 0000000000..4f19614c35 --- /dev/null +++ b/packages/frontend-misskey-world-engine/src/Firework.ts @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as BABYLON from '@babylonjs/core/pure.js'; +import { cm, WORLD_SCALE } from 'misskey-world/src/utility.js'; +import { randomRange, Timer } from './utility.js'; +import type { EngineBase } from './EngineBase.js'; + +export class Firework { + private engine: EngineBase; + private timer: Timer = new Timer(); + + constructor(engine: EngineBase) { + this.engine = engine; + } + + public launch(options: { + position: [number, number, number]; + }) { + this.engine.sr.disableSnapshotRendering(); + + const texture = new BABYLON.Texture(`/client-assets/world/other/firework/flare-${Math.round(randomRange(1, 8))}.png`, this.engine.scene); + + //const emitter = new BABYLON.TransformNode('emitter', this.engine.scene); + const emitter = BABYLON.MeshBuilder.CreateBox('emitter', { size: cm(10) }, this.engine.scene); + emitter.position = new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]); + const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene); + ps.particleTexture = texture; + ps.emitter = emitter; + ps.minEmitPower = cm(100); + ps.maxEmitPower = cm(500); + ps.minLifeTime = 0.5; + ps.maxLifeTime = 1; + ps.minSize = cm(3); + ps.maxSize = cm(30); + //ps.direction1 = new BABYLON.Vector3(0, 1, 0); + //ps.direction2 = new BABYLON.Vector3(0, 1, 0); + ps.emitRate = 20; + ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; + //ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3); + //ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2); + ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); + ps.start(); + + this.engine.sr.fixParticleSystem(ps); + + const launchAnim = new BABYLON.Animation( + '', + 'position', + 60, + BABYLON.Animation.ANIMATIONTYPE_VECTOR3, + BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT, + ); + launchAnim.setKeys([ + { frame: 0, value: new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]) }, + { frame: 60, value: new BABYLON.Vector3(options.position[0], options.position[1] + cm(randomRange(1000, 3000)), options.position[2]) }, + ]); + + emitter.animations.push(launchAnim); + const animating = Promise.withResolvers(); + const animationObserver = this.engine.scene.onAfterAnimationsObservable.add(() => { + }); + this.engine.scene.beginAnimation(emitter, 0, 60, false, 1, () => { animating.resolve(); }); + animating.promise.then(() => { + this.engine.scene.onAfterAnimationsObservable.remove(animationObserver); + + ps.stop(); + + this.timer.setTimeout(() => { + ps.dispose(); + emitter.dispose(); + }, 1000); + + this.explode({ + position: [emitter.position.x, emitter.position.y, emitter.position.z], + texture, + }); + }); + + //this.engine.sr.enableSnapshotRendering(); + } + + public explode(options: { + position: [number, number, number]; + texture: BABYLON.Texture; + }) { + const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene); + ps.particleTexture = options.texture; + ps.emitter = new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]); + ps.minEmitPower = cm(2000); + ps.maxEmitPower = cm(4000); + ps.minLifeTime = 0.7; + ps.maxLifeTime = 1; + ps.addDragGradient(0, 0.1); + ps.addDragGradient(1, 0.8); + ps.gravity = new BABYLON.Vector3(0, -30, 0).scale(WORLD_SCALE); + ps.minSize = cm(20); + ps.maxSize = cm(40); + const sphereEmitter = ps.createSphereEmitter(cm(1)); + //ps.direction1 = new BABYLON.Vector3(0, 1, 0); + //ps.direction2 = new BABYLON.Vector3(0, 1, 0); + ps.manualEmitCount = 100; + ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; + ps.color1 = new BABYLON.Color4(1, 1, 1, 1); + ps.color2 = new BABYLON.Color4(1, 1, 1, 1); + ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); + ps.start(); + + this.engine.sr.fixParticleSystem(ps); + + this.timer.setTimeout(() => { + ps.dispose(); + }, 2000); + } + + public dispose() { + this.timer.dispose(); + } +} diff --git a/packages/frontend-misskey-world-engine/src/envs/lobby.ts b/packages/frontend-misskey-world-engine/src/envs/lobby.ts index a6c8c40602..b6a453208c 100644 --- a/packages/frontend-misskey-world-engine/src/envs/lobby.ts +++ b/packages/frontend-misskey-world-engine/src/envs/lobby.ts @@ -10,6 +10,7 @@ import Hls from 'hls.js'; import { findMaterial, GRAPHICS_QUALITY, Timer } from '../utility.js'; import { WorldEnvManager } from '../env.js'; import { RecyvlingTextGrid, createPlaneUvMapper, randomRange } from '../utility.js'; +import { Firework } from '../Firework.js'; import type { WorldEngine } from '../engine.js'; export class LobbyEnvManager extends WorldEnvManager { @@ -447,31 +448,37 @@ export class LobbyEnvManager extends WorldEnvManager { this.engine.sr.updateMesh([...hourHands, ...minuteHands], false); }, 1000); - const emitter = new BABYLON.TransformNode('emitter', this.engine.scene); - emitter.position = new BABYLON.Vector3(0, cm(-1000), 0); - const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene); - ps.particleTexture = new BABYLON.Texture('/client-assets/world/envs/lobby/bubble.png'); - ps.emitter = emitter; - ps.isLocal = true; - ps.minEmitBox = new BABYLON.Vector3(cm(-1000), 0, cm(-1000)); - ps.maxEmitBox = new BABYLON.Vector3(cm(1000), 0, cm(1000)); - ps.minEmitPower = cm(100); - ps.maxEmitPower = cm(500); - ps.minLifeTime = 30; - ps.maxLifeTime = 30; - ps.minSize = cm(30); - ps.maxSize = cm(300); - ps.direction1 = new BABYLON.Vector3(0, 1, 0); - ps.direction2 = new BABYLON.Vector3(0, 1, 0); - ps.emitRate = 1.5; - ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; - ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3); - ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2); - ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); - ps.preWarmCycles = Math.random() * 1000; - ps.start(); + //const emitter = new BABYLON.TransformNode('emitter', this.engine.scene); + //emitter.position = new BABYLON.Vector3(0, cm(-1000), 0); + //const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene); + //ps.particleTexture = new BABYLON.Texture('/client-assets/world/envs/lobby/bubble.png'); + //ps.emitter = emitter; + //ps.isLocal = true; + //ps.minEmitBox = new BABYLON.Vector3(cm(-1000), 0, cm(-1000)); + //ps.maxEmitBox = new BABYLON.Vector3(cm(1000), 0, cm(1000)); + //ps.minEmitPower = cm(100); + //ps.maxEmitPower = cm(500); + //ps.minLifeTime = 30; + //ps.maxLifeTime = 30; + //ps.minSize = cm(30); + //ps.maxSize = cm(300); + //ps.direction1 = new BABYLON.Vector3(0, 1, 0); + //ps.direction2 = new BABYLON.Vector3(0, 1, 0); + //ps.emitRate = 1.5; + //ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; + //ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3); + //ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2); + //ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); + //ps.preWarmCycles = Math.random() * 1000; + //ps.start(); + //this.engine.sr.fixParticleSystem(ps); - this.engine.sr.fixParticleSystem(ps); + this.timer.setInterval(() => { + const firework = new Firework(this.engine); + firework.launch({ + position: [randomRange(cm(-2000), cm(2000)), cm(randomRange(1000, 3000)), randomRange(cm(-2000), cm(2000))], + }); + }, 1000); this.registerMeshes(this.meshes); } diff --git a/packages/frontend/assets/world/other/firework/flare-1.png b/packages/frontend/assets/world/other/firework/flare-1.png new file mode 100644 index 0000000000000000000000000000000000000000..cb77aa9ce161ad8b1ac7a466e830aa1964e7cad2 GIT binary patch literal 2704 zcma)8c~leE8Xt&&giR^O6(I(Qf@Wn+BtQ%x0ix^#iAYQaGLVgAAVDhz1i`pHwJ2(^ zQA?pHf(21fABb>VP;f(0TLs>$QtJksiip-X35pA~=lyYKa_{f=?caAN8zYu3u|m&6 z0{~#f3JHut-U0eG*%WzJLK*h~z{C=Y;lLbrIE^nA6Ld9K*IW=F}`v^3N0!y_`NW)qhp0I zETa*LN~MyZbSFsVsYEiBN+psgL<$9uFz||O3CvUBB?>3KiZLC5pn@-lWH2O^VDvh9 ztE8DQ9g9V9%m>fJvT@}S#rx=yJP=hp8IepN5kDo%gi=_l5K6xyG7e7=1Xa+-7(O$j zM<&o=DCH}3Ju-ogna{-A;Baz10Y^eZB$^Kim4~<0m zl8y9-fCuybAO3j8X?pgUS4eOEvr8X^m{O5cj(CSe;coEuBgA4dBjnN)NQ7XDs3nUr ztRSWrnd;?*rx3^nuD)`#2uKBrIDwEDlqircqhq~1z5o-x0vc>bBg2Il7*nXPEsZ7S zrGoL002Yqx`gk4=N>aZB^c50i>RUWk0wFb}80;HlI3F=O)|*27#7x2jNIx_fUqdU= zLLdb!m1i4{#wIBm%oy8^ZAFk_gfJLGBhh$#y?r`XCYK5_`Jlky0-|mVRY+4{B~K1A zQjs2_V;Lza5aMYz#+^VRjHP{?suY5VnlH-tNskcUyF}Da^9P@Ni4(l`H4r`-e?)HV z47pa2`-wPyK_Q#*D-M((y(331uorVe)c|0W3n5J~q4)qWe|zTkQ(-8^l)|P!7h5Ov za?X5v+p2@F)VeJ}tto!Sfa-Z`#K8Q3a2wbybD~@j;K9+p0vRzX?bCft%j_6-=l$IUtj)*VaY@cNySU|?DO=(KoN)7J zq0u3_Tz|$ak?5wHZk1f8dtsKATOcbo6?+`0#YAGATdi#`ihns?LbdKVbLuU<{nwlw z=~>GAYag^f>8Ku_WX^9Gw7Y5n8=Gu%Y~FQVisBqAsNMI2-}d~-_Ttps#Ae_ss;-JF={b8le&ktvD5!ub6FPCd6Ll$&+DA84cpGz}>- zTq&(3cx}OQ?{w3Ebx$`5MoWj8=KV)KX)4ozZ9^+BJiP5^xhP=wZQtG|sd|6!l^ebt z>jy!`Xx60aZOM*z_Vl)~yk&=8_iZogpZk2ajO-E#)mn4?d_CfZ)l>K0&W_kr-+OMl z^=fre=el`kT&i5XaxLm*FMEYHCAyJPv;Ke)w7pex#OvjoGkOjKHQWRsXXZ}+hCICX zsobXD+pW#=ZA7+-sU@1+2B@!&zHBmY%3RBJH7a*`eDz?L*6cUMw!qTvI=9jtmj+@M zL|s4yIH+$~t82IoW?GM`)+uXpt%LVY-544yjIAF8{$+--31~Mq*@f`ce@=au3c(VZ8FVjBl&D@^~g2ONM*;F zQc9Uy(2tio)(;Q7ioaa;ZyfvWe=^qcDdJdHc{NSkk% z7wqinf195XW82qt@=4sW;4(O?>DsxRke^kJj-JY*9r>}wemYJ01F%umIPLW>2MT4s f4IO6f?tF(@nCZAb3@q!@|B++`Ee$-nI63cs_GSXq literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/world/other/firework/flare-2.png b/packages/frontend/assets/world/other/firework/flare-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a1357badb2df29b77a42d96e40e24f8ac1669259 GIT binary patch literal 2684 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 literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/world/other/firework/flare-4.png b/packages/frontend/assets/world/other/firework/flare-4.png new file mode 100644 index 0000000000000000000000000000000000000000..8c073ac0e1ce1e61b79f010d3b2bbef6d2829948 GIT binary patch literal 2695 zcma)830P9;8V0@YX{A}_m=TVSjj<{u1S)|V2DuleB`60uDobz-FiSK|)9Si3Gqy@K z6-6yM;A3wcBFaIzBVb0m~L|^W2B$hx7mM`|aQNb2djT3$?d( zwM8Hh_Ut9BDEK$XxU4PV?<#Q39R$K+3K+wKcw7!OSth{>gt8<6tCq-N9D$$(s^x;@ zGyp;+0V$xAj(*zMghqivI(h|(i|5LjfEZkosQ{ugm&GJ!rX^E^=)eG5nwknLkN}VX zrIw^il~gqyZPH7HpN+>jG|EJQ(&%U&Hv+|!DF74+OTyyO0k$ZbLMWm}u|nPo!#g@! z3_)@#4yRJ7uqt1yOp$^kP$(1}o`@q7F)#z8)JP$L8Y5MD7*&kxU;)Zx1t^C=nG|Kz zDM*rKKy)-3#!>G)lgKBOOODL zj1iechd|M1=tg7`9nLkE``1xOBp(H$go4+?iFljTj~sdzw=zZ}2XIkeQ^4NAQTUp?eGjpj%m{@{1g687GAeX2 ziXF@(6DVXdhKMDYxW>v+BS1Bf&SQZRK&phhjE*MzeFDaP1~l1@hKCC_Fs{&8TPj;3 zNC8%WLP$KJ>-{+gkfwYJ7%P;XVQleODG1k;XtHmT;l0P`=!Hbw2WH|XLB^p$(M+vG zT>>g0nL=Ya8lR+SV9oe$e47rMMhJy6H4;^jY_v~D%M~(VMlv8Yxd5vhN0l-Wq!K6q zMhe_RbTmUG0%1=zC|@iQJD&Cls!9yNYCb972R(v&>k`g5&F_4o;U;-aGZ8)*e^_q( z48B(2`w2I3LBX4eD-Mvty`z9HFc%`X7=b|MfN&E`Dn0_?U7AtaxYV36t)PkJ>F8m* zlIQK_SiS$XR<||y;w*iz<9R(-p|R1pscg`vb0tBHlh0xY5_Q#ljCB#Z@D%UsTl(Ef zHi~g|!H*-4WvWg8j;pnbPQ9g{tA)G{j~>ptk|buYIeSlM_mwn3aJ}<^Sve#1RzIEW zbLVB;snp8R?w$JyOpEvfLlsqnls>TU=BeGHXWQhBJEw%^|C~oZlMwOxpIsiF8&3E~ z-jfx-&}F+ls%{C}U*r*c%NhJoUY%HduLziF=Gb^?5n;$Te`@}0FPGL1 z)B)nU!Q{dXagiR`x{AQ?<%-xHq#OT=^JJ8{xkrvf(Y*-ROioBq#?i6t(bS6t1!31$ z1&Gz;pI*7k(=UXd_iNh58R>U^>p`wx@fTjqu1X5yQOrWr^;c(dHXk2X+6CKt0{MX7`99QB4yxVR^%`6Kaq`m zNt_aauyZmlBx2`o7X-q5JDbIbQSW}dE0E(9>DC(fbc>gR^zy}!y*3-m9UNE(oNDzp zMVoSvjy%3<+RTK6?S+eq`4B(y=oEkJJ$?iGZFZS&4$aG}CoD-lt5nx)|2A!%>Re;@ z%O~Yf!<};*vhSX~Gx}=OCh79&+tERRo%X-d0ua6Km0W%-H3_$DJ$hS+q=RmE+tM;8 zz`$xdRMhG{oyn-)*PLbDu(OPqfd^(tB;rFAQZbbik19dqo4OKRM8 ziO`SDzZ=eM!CP_OXc%O_AgeLgdZ(P)FWb$TTRB4`vnme$o@+(2S=Tji=nOq*tiLk! zVB56&UDJzC{o@#@-OxKrd!JAkR)+43PlJa1g8n{|2>w*J-eql$dyS^0RHfb9hv}r8 z-&h1hwl2@4kYGf7mlSNCbZ#+V}WXx1e_2RPg%ys&_0;*2WGNp6gaM<6yw>(nXeuS za39;$aIL%kNH*0n`HGuX$VQUwO}YW>ZnPG&YxWqXSjbIKRqwL1l2YH{-!WU~_I$LZ8*i{-pU+Iixd3 z_8~KSToxbH)!BtVE1mCv^a+6oEwt)JP1N7KzV}%DdOeEMewAdvR4-&*P9&P^vULSF zb}n#^xSypn%*#U}GC7Z}r28IpAL{9J{p~``76z1G?xAmKKQ8JWX`h+;pWm+V`h=v+ zK!Mped1_MC+M~R~3Dm~B1ERo-aWuL%EI7@}=BRZR%Q+lZ2R(x@&l{L?`>ynN-@{gp ZO=VrPe$)CgV5#x_ksZ8@b$l^D_fH8A1APDh literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/world/other/firework/flare-5.png b/packages/frontend/assets/world/other/firework/flare-5.png new file mode 100644 index 0000000000000000000000000000000000000000..01a89aea550b7a44ab22e029aa112ed8bd1fc5a9 GIT binary patch literal 2721 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 literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/world/other/firework/flare-7.png b/packages/frontend/assets/world/other/firework/flare-7.png new file mode 100644 index 0000000000000000000000000000000000000000..a715ff28f04d300e5d7431be494a35a43a233c73 GIT binary patch literal 2699 zcma)82~<+)9=~d$QjWQs5#6xV7THV+;--jbl$cwFZ6nJ?uCfUjpuHj|)9mD{?Dfp7 z@o0-jSc)vjQo{*ZF^QtAbP-)l2%V2*>KUj4Ijj|c zdbv!YVdx=(RWAemZaF3qKr2O?4iWggSdgt$!(a$8gh(dL$AV0?Si*>phbB%Mx2)CCij>QoYiPN$Q|R1%dMgffCO28C9j4^n9SEGmX|M8F!68c}Hxr2@3* z6bO}>T8KbEaqxp@a@B}(h30+qXdXy;Sl1ZPERZ^u^sgWwbA~FJx5`^{0#~3~{ zV?jpIwTR>^bPF)j`|Bv=^3MX%XgRCVM7&SxXAXUcTa#!|!K8Rtqs&x`V9sh- zq4l%o0=33qt6_l_jzAYgppvPyAo83bDm{@xX9Uw2)R38EI)h9eVe^z?L}K`#Y&s(( z_)9k0A7X)4@c-~fGS0BDhrL33^RHd{D8yFElxoyFG>TxWw;v%cn;olGN)Q=}Y2u^8 zK`w_)qtI!zAS#h!VTA_mGKfH%{RNo(70_xs0Ua*Xz_3C~Z5dp- zAQfJUh_%uYT_4Y*VMXeffTcpROiPO|Q6OkdsaE?|8U9BMBFv$ZJ~5L#3bG6h$h5W+ zV*#SkD%A$-(eNZCz!}54;jIj@jt~f18;KzhS?ogum0Bsz6v1Mv3#htbRHKw=bpkca zN=17JBCsS91ohMa1{0~o;k1uXby65r^F{eS=@HUc&#RA^=H`c8 z#t+1~RhPdqmTlqu;$6vcJ6p+98=MR{ofF|yjy#NY^7)ePZ_BDvf*cD7`6m91_R3NX z7i9fD>%@y*rEcThx&f+P5&P;&v){C}KhBNo zRBnD*whs5W`rN|u0>34P{a>Cu_7hIW_{Y*qgFmk7EP%ai-RjQIqdW`Fb;+IJ?{nc2 zSV7HxB+6f#9Ot*LtT=RWl6uLmkQ>*Nr?Ix<@NqBVA%6-nD>||u^U%9>LutR{bxOf$Rt|_lOx8UJ?<4)e(`YP$Rl{GhW3ZsG! z=WUMPQv>1iPA5peVcm9~`_Dzt%%_?@;H>lOs`Q(;^H$OC9q$_}o0!_&vnH+u{Uvfz zElAb?z*u+7vH?m;eE`6&m>a=L)R*?|4vqdJ7Iz`^Xr#Nt98o7nc+MO@36~!kkmBm@ z;cRC&^;p9ba8^xCpsUVneM3X}UaA?qvyT-}w8-1RZCZHv9iOSGvPm8Dp17Q;JJmLD zcjXXQF}?S}(9lEE(|b>D5N18-WMe)qFQ4ec4G#yof{pAO(1Ti!nIn$mdnav>ZI-c^{)thC?gJ1I}PrYwfS z{?`4_81*(25#Wml`qs;&M(o=VRp=N&#&-LS6L*>a<5^tsCdYy9l-<#NpcV={^Wx~a z_}{8GXCzn@heO0&xJOc(K9#9uU&Fe4i%A zVZx>D1=Y5v|854VgB!;dtun{FJdcg~W9y)Ejc-w9%|*MmOL@Qc;K`9)7#H<*+OoCx zYaA+H{;BI+-rOVft|3GZInKy#@Ypk%8Rkt*Dr+`wdu5V7n44r{=0{>)?dKKZspn1( zZiZ4~4|zc2!XJ71GzUg_vw`s5+wc5e-N>wq2d+$PVsGAO??Qbz-_9T`O00EWcp-s1 zwa7Ot4ShPD7tF>`CrtU_@qWx!U-Z%2t=1m8))Z5VOETz}*S1Pi5{d@|8H63JGdM2E zf$~k&=^o{qGh;E1EgfwCDgL>=!W+ozWhuNOpGmk2CHO6#N2~7KPF`6h6rb{8mNF-; zV&SLgW*AaTe}?DU^xRqFAH$(&2)b)>w%BeLt`+&W(WTY9W$N_Pb-Bnp0B^g_&&$if zUhHN{_cvUISc3NNjTb8u&o?EW8P`|4yL?7tAAGYwDE@iX&OrSo&$ZFn#GS_*v=zI3 zeakj(5s0x_bFc6FLh2qQfGW?ie@9blglUp#QU%^_#U?{{oFnzPvA{%OHL&*c7V z%Zm2n)TM)-%rRsjY|9UC8dmlnnbfzCy>4p(#qp?0?U6k9R;w%vui8X6?+L bzSr+MB$z$pu=n;`{zGy(F%d_?Q*!T|T%3BM!7qdOHhi%W=9yTiU;!KiMlw8$9 zpE`BZ@M?&taZ_w4`wet+-3-+$X4wmjI< zY_=Hy0G8|!Rs{NH=$5Go`dI<3{{;YyEug4qB$^XS<--y@PXNb*c$Gwk;s8MNSIKz% zBoM*Gg9(t7jvc72!(t!-9lOehL*&Q;K@k*^CI=(amPhf^lK2z>*5A*JrlO(>Bp|}W zs3c;kf~ulp^?Ir3cik}oi_ue%Bsw;l6NU+dxKnP>I9|HU}0!!qh)vdlRWd z->=zde+YO8@BiUXWSpvFk9&po=AXOtNhlB&!*bL+Gzu@hx1S((U|^UW7D8eaQ$z#@ zVAw%{WKRm2j3ePa^;})$s9}%_6i2fl2`E*dT}H=}y}truz5(iON20@p8W>lot1Xo+ z;U$2pAORwp(Dms&6qF`>4d^N)PS&;fN-2cal%%(>mx=y_(Xoq2gwM>xOoDVngQ4kL zi5dba5Llk7KN_E;NO1l5ZhR|-^dp49=o^X3ytVM`@C#V^{gar}QzH`}9e2(|+>X6Hw(&;1h`s)Dm&SaabT#jObGPAMX5ynB zI(fk_|Bk6iJp8t`xYRSy_-|!{MHSB}olxh)niAnqo~*XmA~@^zHu|O2VXvC*xVWZQ z`-XSHJ4Q7bj=xuGmzL(ZtUT#9dhYaPM6De~vrPTGH|d$V%7{WAA)eCsMiyVqQ7+maWI zJE`6gaquGDNqr$wWW{W^^xeOVzF%dW@BX2-;f~k+2Xfu4q}Q%2iPtVGL1dWO2Q!00 z!@Mml^6L$2x1R3kDrG&6nNnu7BNnV@_LeheaoR%jSljcbFEU~8R9X!b-jPcNs+40( z2mILk`=9iWjWzcFBctvxMksEj8jlzrWHkL|bo$xQLx5W@OZn~Iye`qbl*+U9xHzEK zVEHz2h3QEE-mHx9ZEta3XnVlmeA2-wZkd1WSQ_<$JLC{OrMq1AUsg-pU6Zz|WD9!( zC&Qj%?$ceI4uin}vz~QcmRaQb6r90`!LH0@joG3t$#G`U`?TwS@}7PJXs>B98fGYq zdiWY3cWLK4i#Ks`M&i~>R+mkhrfeb$Q!*Dv_#WOu6Bz&aFs0J7puKV?&7EW1UbAE? z?dgfBy|bQJ$OsqlF1HN#rmxMnv}|suGn58n7P4Q~$GO5X%yp1kJBA+;E z-Vfg{jSyse&M(P|UH8D7QTM{Ue#oBX%AV0%u9j={3JlG2 zkfZ56>eLKJI->nSEE>Dv{WN zUB~W(;Jq?$q0hZJ`H2goNCB}AZ&+Zw&}Y;{T*T$&?-Wx`4i9oUCp_zO?3$zywqTLR zRf|-2cstI)Ed}Pn`yV}_K{UaT*aV`1ww!dF5{%&VsRo~-wD6+yvaLJCQ za^973b#-6T<9q&2t?NQvD?ON2&#clU*$d0|ls(#MIQY*u@%!dJOTJ*&WZi)uTqNYN z!&t828-#mWAKMmaUz_G$KkC7B>jU#!pV-}Z*tepLTYxz`dWO}ou4-^oUU&R_>rnEg zAC4HLwb`?dYMlRasKX`F(U68+*$r+H)YOeoic$om(d`VZ3L| zs`QER&|G`XXb3bl0!E4+nLlPVp5jzj`HX!3gZCC<5i}|p|y$6yPn7PD%4Ke!rP~= ct?_&BT!2jTxA?UitNR1V4qDEt3W(eCKd4;_EdT%j literal 0 HcmV?d00001