PK!<meta.xml com.14th_ua.moe_calculator 5.0.0 14th_ua's MoE Calculator 14th_ua's MoE Calculator - a World of Tanks Garage mod. REQUIRES OpenWG Gameface (install it first) - without it the widget will not appear. Author: 14th_ua PK!?-->res/gui/gameface/mods/14th_ua/MoECalculator/MoEBarTransient.js// 14th_ua's MoE Calculator -- the SHARED transient machinery behind both centre-screen in-battle // bars (MoEProgress.js = Moving Average, MoEEfficiency.js = Damage Efficiency). Everything in here // was byte-identical in the two files; only the values each bar animates were ever different. // // The two bars are radio ALTERNATIVES -- Python opens exactly one -- but they are SEPARATE Gameface // DOCUMENTS, so this module is instantiated twice with no cross-talk: every piece of state below is // a closure local of createTransient(), never a module-level variable. (Both documents already // import ../../libs/model.js, so module resolution across this directory is proven.) // // EVERY BEHAVIOUR HERE COST A CLIENT RELAUNCH TO FIND. Do not "simplify" any of them: // * the negative-`animation-delay` debounce (armRun's seek) -- mp-life bakes fade-in, hold and // fade-out into ONE both-filled keyframe, so its hold CANNOT be extended in place; // * holding a peek open by pausing `animationPlayState` and, on release, seeking -3600ms; // * ...and, for exactly that reason, the CONFIGURABLE hold is a CORRECTION to the keyframe's own // deadline (holdFrom), NEVER a replacement for it: at the default it does NOTHING, so the run // stays byte-for-byte the shipped one -- ONE identity, ended by its own animationend. Do NOT // "unify" that into always-pause-then-re-arm: that costs every ordinary auto-hide an extra // mp-run/mp-run-b flip mid-run (a flicker risk, and 11 red assertions in // tools/dev/check_progress_js.js). Do NOT scale `animation-duration` either -- mp-life's stops // are PERCENTAGES, so that stretches the fades too; // * deriving the peek phase from ELAPSED TIME (plateauAt + HOLD_MS), never from a `showing` flag // -- `showing` stays true through the whole fade-out, so a flag-based branch pins the bar at // partial opacity; // * the mp-run <-> mp-run-b identity alternation, so consecutive runs never share an // animation-name for the engine to coalesce a restart with -- and each VERTICAL composition // carries its own twin of that pair (mpv-run / mev-run, see RUN_CLASSES_V), because the two // vertical stylesheets are namespace-disjoint from the horizontal ones; // * the fallback end timer, without which one missing animationend wedges `showing` true forever // and the bar shows once and never again; // * the POST-DEADLINE surface re-assert -- the engine's default-view-size fallback runs LAST and // WINS, so only a late re-assert puts the surface right (see SURFACE_REASSERT_MS). // The rewind before a COLD show, and the value commit after one, are the two things that DO differ // between the bars: they are the onRewind / onCommit hooks, not flattened away. The ORIENTATION is // the third: this module owns the surface/shift/run-identity half of the vertical composition // (cfg.vert + goVertical) and the bar owns the DOM half (onVertical), because only the bar knows // its own markup. // // The battle windows have NO hot-reload (they pin their resources at client launch), so every tweak // here costs a full client relaunch: tune in the browser, not in the client. // --- the transient's timings, from the bars' CSS trailing JSON `meta` blocks ------------------- // Kept as constants rather than read from the CSS: Gameface gives no reliable way to read a // keyframe's stops, and these numbers ARE the contract with BOTH stylesheets (whose mp-life is // identically tuned). If a timing changes in a tuner, change it here too. // Declared as bare `const` and re-exported below so a plain `^const NAME = ;` scrape still // finds them (the mirror tests and the dev harnesses read these out of the source text). const FADE_IN_MS = 600; // meta.fadeInMs == the 9.68% keyframe stop of mp-life const HOLD_MS = 5000; // meta.holdMs -- the BAKED hold. The LIVE one is the closure's // `holdMs` (see applyHold): user-configurable, JS-driven, and // defaulting to exactly this. HOLD_MS stays the keyframe's own // contract, so SEEK_FADE_OUT below is still the 90.32% stop. const FADE_OUT_MS = 600; // meta.fadeOutMs (== fadeInMs in both tuned JSONs) const TOTAL_MS = FADE_IN_MS + HOLD_MS + FADE_OUT_MS; // meta.totalMs == mp-life's own 6200ms // How far to seek INTO mp-life, in ms, when arming a run (armRun turns these into a NEGATIVE // animation-delay, which starts the animation already that far along without replaying its entry). // Verified against the emitted keyframes (@keyframes mp-life): the stops are 0 / 9.68 / 90.32 / 100 // of a 6200ms animation, i.e. 0 / 600.16 / 5599.8 / 6200 ms. // 600 == the 9.68% stop (within 0.2ms): opacity 1 and translateY(0rem) both COMPLETE, so the bar // sits exactly at the hold plateau and does not re-flash or re-slide. // 5600 == the 90.32% stop: the instant the fade-out begins. const SEEK_NONE = 0; const SEEK_PLATEAU = FADE_IN_MS; const SEEK_FADE_OUT = FADE_IN_MS + HOLD_MS; // --- THE RE-ASSERT: LOAD-BEARING, DO NOT DELETE --------------------------------------------- // Live-measured: the engine's size-calculation deadline expired ~2.2s after the view loaded // (resizeViewRem at 04.8s; the `Size calculation timeout` + its "Set the default view size" action // at 06.2s, clobbering the pushed size back to the 256x256 default -- THE FALLBACK RUNS LAST AND // WINS, which is why pushing the size earlier can never help). A static in-flow #moe-bar-box does // NOT satisfy the engine's measurement; that premise was tested and DISPROVEN. So this re-assert is // the ONLY thing that puts the surface right, and it is permanent. 4000ms is comfortably past the // observed ~2.2s. // It is load-bearing TWICE: `settled` flips off the back of it, because the re-assert IS the event // that makes the surface correct. Before it the surface is the 256x256 fallback -- which CLIPS the // composition and, since Python's anchor_centred_reduced computes its term from the real surface // height (domain/constants.*_ANCHOR_Y_SHIFT), places the bar far too high. Delete either half and // the bug comes back. const SURFACE_REASSERT_MS = 4000; // Slack between the re-assert and letting the bar show. The resize round-trips through C++ // (Window._cResized -> onSizeChanged -> bridge/bar_window._place re-reads the movable extent), so // the surface is only correct -- and the window only re-placed -- a beat AFTER the push. 250ms is // far more than an engine callback needs and is not user-visible: it lands ~4.25s into a battle, // inside a window where nothing shows anyway. const SURFACE_SETTLE_MS = 250; // --- THE COLD-MOUNT POLL: LOAD-BEARING, DO NOT REVERT TO A ONE-SHOT --------------------------- // Live-measured (watcher log, fresh session's first battle): the Python push that flips // `visible`/`hasData` true can land ~27s after mount -- long after SURFACE_REASSERT_MS + // SURFACE_SETTLE_MS's one settle point (~4.25s) -- and observer.onUpdate(render) does NOT // reliably re-deliver that late push to render() for this private always-composited battle // window. A one-shot post-settle render can therefore fire, find the model still not ready // (render()'s early return, before it ever reaches T.peek()), and then nothing re-renders again // until the user presses Alt (which reveals the bar through a separate force-push path -- that is // why Alt "fixes" it by hand). So the settle callback below polls the LIVE observer.model (which // stays current even while onUpdate is dormant -- same premise as MoECalculator.js's garage // cold-mount poll) until the bar actually reveals, instead of rendering it once and hoping. // ponytail: a bounded, SELF-STOPPING poll -- COLD_POLL_MS interval, capped at // COLD_POLL_CEILING_MS total (a `visible` that never arrives -- feature off, spectating, no data // -- must not poll forever). Each battle window is its own short-lived document torn down with // the window at arena teardown, so there is no separate unmount hook to also cancel this from; // the ceiling is the only leak guard. const COLD_POLL_MS = 500; const COLD_POLL_CEILING_MS = 60000; // Margin on the fallback end timer so it always LOSES to a working animationend (which fires at // exactly the run's remaining duration). Not a tuned CSS value -- pure slack. const END_MARGIN_MS = 250; // THE SURFACE RECT IS THE MOUSE HIT RECT -- exactly why WindowFlags.WINDOW_FULLSCREEN was rejected // for these windows (bridge/battle_view.py). A surface spanning most of screen centre would be an // input-stealing strip, and these bars are purely decorative and must never take input. So collapse // the input rect to nothing, PERMANENTLY -- this document needs no mouse input at ALL any more: the // Ctrl+drag reposition is driven entirely from Python (adapter/battle_input samples the keys, // bridge/bar_window re-places the window from the live cursor), so the rect that used to be OPENED // for the gesture never opens again. Confirmed against WG's own JS wrapper (gui-part3.pkg // battle/battle_notifier/BattleNotifierView/BattleNotifierView.js), against a LIVE decompile, not // just this file's own memory of one: // * the order is (top, right, bottom, left, 15) -- CONFIRMED; // * WG's own wrapper passes FOUR EQUAL VALUES, always -- so arg order is MOOT there, and matters // here only if the four are NOT equal; // * an OVERSIZED padding is ACCEPTED, not rejected -- a real capture logged 240 accepted against a // 92-tall surface. NEGATIVE values are what gets rejected, not an oversized positive one. // ONE SHARED VALUE ACROSS ALL FOUR SIDES, per that recorded design -- NOT a per-axis pair. A prior // revision of this file split hitPad into hitPadX/hitPadY on the theory that `Math.ceil(Math.max( // viewW, viewH) / 2)` on all four sides "over-pads the smaller axis into a negative extent instead // of the exact zero a real collapse needs" -- but per the CONFIRMED behaviour above, an oversized // (or negative-implying) padding is exactly what WG's own wrapper already ships and the engine // already accepts; the "exact zero" the split chased was never necessary, and splitting it // reintroduced two risks the uniform value never had: sensitivity to the (top, right, bottom, left) // ARGUMENT ORDER (moot when all four are equal, live when they differ) and sensitivity to WHICH // AXIS'S size the pad happens to be derived from at push time. `Math.ceil(Math.max(viewW, viewH) / // 2)` on all four sides collapses BOTH axes to nothing, is immune to the argument order, and is the // smaller diff. Revert target if this file's hit collapse is ever found not to hold at runtime. // HIT_MAGIC mirrors WG's constant (its own wrapper always passes this literal 15 too); its meaning // is unknown, so the call is retried without it if the 5-argument form is rejected. const HIT_MAGIC = 15; // --- THE "LARGE" SIZE MODE (mod_settings.progress_bar_size, pushed as the VM's `barSize`) ----- // TWO factors, one per axis, and they are the only two numbers the whole feature has. Defined HERE, // once, for both bars (Python's half is the two *_ANCHOR_Y_SHIFT_LARGE constants). // // SIZE_F IS DELIVERED BY THE ROOT FONT SIZE AND NOTHING ELSE. The rem->px factor in Gameface IS the // root font size, and WG's own bootstrap (gui/gameface/js/index.js) ends by writing it from // `self.onScaleUpdated` -- a bootstrap our REGISTERED views never load, which is exactly why every // comment in this mod asserts 1rem == 1 logical px. So one write of `base * SIZE_F` re-lays the whole // composition 1.25x larger, CRISPLY (a real reflow, not a bitmap upscale), and leaves every %, em, // `contain`, gradient stop and derived icon background-size ratio correctly untouched: height, fonts, // icon boxes, glow radii, vertical gaps and mp-life's slide all scale with NO CSS edit at all. // SIZE_XF is what is left over: an x-length must reach 5/3 TOTAL, and the root font already gives it // SIZE_F, so the stylesheets' one appended `.mp-lg` block re-declares ONLY the x-lengths, multiplied // by this. 1.25 * 4/3 == 5/3 exactly (~1.667x -- was 1.5 * 4/3 == 2x before the Large mode was // eased off a pure 1.5x/2x scale-up). // THE ENGINE APIs ARE NOT AFFECTED BY OUR ROOT FONT: resizeViewRem / setHitAreaPaddingsRem are C++ // and take logical px, so their arguments carry BOTH factors (see applySize). The CSS `left`/`top` // rigid shift stays in rem and self-scales, which is why shiftY needs no term at all. const SIZE_F = 1.25; const SIZE_XF = 4 / 3; // Two interchangeable arming classes, each bound to its OWN identically-tuned @keyframes (the // second is each stylesheet's marked HAND-ADDED mp-life-b block), so consecutive runs never share // an animation-name and the engine has nothing to coalesce a restart with. // // THE VERTICAL COMPOSITIONS CARRY THEIR OWN PAIR, and it is PER BAR rather than one shared vertical // pair: the two vertical stylesheets are namespace-disjoint from the horizontal ones by design // (.mpv-* on MoEProgressVertical.css, .mev-* on MoEEfficiencyVertical.css -- the horizontal pair // shares .mp-* only because each registered view is its own document), so each emits its own twin // under its own prefix. Both orientations' keyframes are IDENTICALLY tuned -- same 6200ms, same // four stops, same 20rem translateY slide -- which is why one set of timing constants above serves // all four and no bar owes a second clock. The horizontal pair below is the shipped default; a bar // supplies its vertical pair through cfg.vert.run / cfg.vert.life (see createTransient). const RUN_CLASSES = ["mp-run", "mp-run-b"]; const RUN_NAMES = ["mp-life", "mp-life-b"]; // KEYED BY THE VERTICAL STYLESHEET'S OWN SCOPE CLASS (cfg.vert.cls), so a bar names its prefix // exactly once and nothing here needs a second discriminator. const RUN_CLASSES_V = { mpv: ["mpv-run", "mpv-run-b"], mev: ["mev-run", "mev-run-b"] }; const RUN_NAMES_V = { mpv: ["mpv-life", "mpv-life-b"], mev: ["mev-life", "mev-life-b"] }; // Group an integer with thousands separators: 2910 -> "2,910". The tuners' fmt() at their tuned // `comma` separator (MoEBattle.ttf carries "," and space, so both were shippable). function fmt(n) { n = Math.round(Number(n) || 0); const sign = n < 0 ? "-" : ""; return sign + String(Math.abs(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Build one bar's transient controller. // // root the bar's #moe-bar-root element (mp-life animates ITS transform) // boxLeft/boxTop/boxW/boxH the composition's bounding box in document rem (== .mp-backdrop) // pad slack for the shadow/glow bleed, on all four sides // padX OPTIONAL, default `pad`. The X-AXIS slack, when the ink reaches // further sideways than the box does and `pad` alone would clip it. // Only the vertical Moving Average bar needs one (its captions are // right-anchored and grow LEFTWARD past .mpv-backdrop by design -- // the backdrop deliberately does not cover them), so it is supplied // as `vert.padX`; everything else leaves padX == pad and the // four-sided-uniform derivation is unchanged byte-for-byte. // IT IS ONE VALUE FOR BOTH SIDES, DELIBERATELY, and that is not a // simplification -- it is the guarantee. The centred (Damage Log) // anchor is `max_x // 2` in Python with NO x term at all // (positioning.anchor_centred_reduced), which centres the SURFACE // and therefore only centres the BAR while the surface brackets the // track evenly. A per-side pad would let a caller silently slide // every centred placement by half the asymmetry; this shape cannot // express that. Pay the unused slack on the other side instead -- // the surface rect is invisible (the hit rect is collapsed to // nothing off `Math.max(viewW, viewH)`, unconditionally, regardless // of which axis padX widens), so a wider surface costs literally // nothing. // It is an X length like `pad` and, like `pad`, it does NOT carry // SIZE_XF: it is a rem-space allowance for rem-sized caption INK, // which the root font already scales by SIZE_F alone. // padXR/padXRLarge OPTIONAL, default `padX`/`padXR`. The RIGHT-side twin of `padX`, // for a composition whose two sides need DIFFERENT slack -- so far // only the two VERTICAL, Minimap-anchored bars, whose left side // carries the caption ink (padX, above) while their right side faces // the minimap and needs only cover the TRACK's own tick overhang, not // the ink. Unlike `padX`, splitting this one is SAFE precisely because // it is never paired with the centred (Damage Log) anchor's `max_x // // 2` (positioning.anchor_centred_reduced has no X term and needs the // surface symmetric to stay centred on the track -- see padX's own // note); the Minimap anchor (positioning.anchor_minimap) reads // `edge_x` off the LEFT side alone (padX, boxLeft, trackW) and has no // term for the surface's overall width at all, so shrinking the RIGHT // side moves nothing the placement math depends on and the bar does // not move on screen. May be NEGATIVE (and, for both shipped bars, // is): the composition's own backdrop bleeds further right than the // track needs, and a negative padXR clips that decorative bleed at the // surface edge exactly the way `clipB` already clips the bottom bleed // -- see domain/constants.py's *_MM_TRACK_X note and the bars' own V_ // PAD_X_REM notes for the numbers. `padXRLarge` exists because the // target it has to hit (the Python-side `edge_x` it must clear) is // itself a hand-corrected, not purely `*SIZE_XF`-scaled, number at // Large -- so, like MM_TICK_OVERHANG_LARGE, it is its own literal. // clipB OPTIONAL, default 0. Rem of the box's BOTTOM that the surface // deliberately does NOT cover, i.e. how much backdrop bleed is // CLIPPED at the surface's bottom edge. The ONE asymmetry in an // otherwise four-sided-uniform `pad`, and it exists because the // engine clamps every window into [0, space - surface] in compiled // C++ (see bridge/bar_window's _extent, which DEPENDS on that // clamp): the surface's bottom edge can therefore never go below the // screen's, so the ONLY way to bring a bottom-anchored composition // closer to the screen's bottom edge is to make its surface shorter. // Both VERTICAL compositions use it (their tuners' approved look has // the backdrop's lower bleed hanging off the stage bottom); the // horizontal pair leaves it 0 and keeps the plain box + 2*pad. // It is a Y length, so it carries SIZE_F alone via applySize's `f` // and NEVER SIZE_XF. It never touches `shiftY`, so the composition // does not move inside its surface and the mirrored Python constants // (VERTICAL_ANCHOR_Y_SHIFT, MM_TRACK_Y) are UNCHANGED by it. // onRewind(atCurrent) OPTIONAL. Called inside a cold show, BEFORE the run is armed, to // write the values the entry opens with (transitions suppressed). // `atCurrent` true == the Alt entry: open ALREADY committed. // onCommit(cold) OPTIONAL. Called after a DAMAGE-driven cold show and after every // warm re-trigger, to retarget the animated values. `cold` says // which -- NOT cosmetic: after a cold show the run class was just // added and onRewind wrote a resting value, so the new target must // land in a LATER frame (requestAnimationFrame); a warm re-trigger // rewound nothing and sets it synchronously. // onEnd() OPTIONAL. endRun's force-settle tail. // onIdle() OPTIONAL. reset's tail (the resting/hidden state). // vert OPTIONAL. THE VERTICAL ORIENTATION'S composition, adopted once at // mount iff the model's `vertical` is true (see goVertical): // cls the vertical stylesheet's scope class, put on the BODY // ("mpv" / "mev"); also the key into RUN_CLASSES_V above // box [left, top, w, h] -- that composition's own bounding box // in document rem, replacing the horizontal box* args // clipB OPTIONAL, that composition's own bottom clip (see the // `clipB` arg above), replacing the horizontal 0 // padX OPTIONAL, that composition's own X-axis slack (see the // `padX` arg above), replacing the horizontal `pad` // padXR/padXRLarge OPTIONAL, that composition's own RIGHT-side // slack (see the `padXR`/`padXRLarge` arg above) // A bar without it is horizontal-only and reads `vertical` never. // onVertical() OPTIONAL, and only called if `vert` was adopted: the bar's own // half of the switch (rebuild the DOM under the vertical prefix, // repoint the cached element refs, flip its axis properties). Runs // AFTER the geometry is re-derived and the scope class is on the // body, but BEFORE the surface is pushed and before the first // render, so nothing downstream ever sees the horizontal DOM. // // Returns { mount, settled, show, peek, ctrl, size, anim, hold, reset, disarm }. export function createTransient(cfg) { const root = cfg.root; const nop = function () {}; const onRewind = cfg.onRewind || nop; const onCommit = cfg.onCommit || nop; const onEnd = cfg.onEnd || nop; const onIdle = cfg.onIdle || nop; const onVertical = cfg.onVertical || nop; // --- the surface, and the rigid shift into it ------------------------------------------ // A Gameface view PUSHES its own size to C++ through the `viewEnv` global // (viewEnv.resizeViewRem(w, h), rem == logical px); a view that never calls it gets the // engine's default-size fallback (see SURFACE_REASSERT_MS). There is NO Python-side and NO // res_map lever for this (bridge/bar_window.py). The surface is the composition's box plus // `pad` on all four sides MINUS `clipB` off the bottom (see the arg -- 0 for both horizontal // bars, non-zero for both vertical ones, and the ONE side that is not uniform), and the whole // composition is rigidly translated by `pad` so NOTHING sits at a negative coordinate -- an // origin overflow is clipped at ANY surface size. `clipB` deliberately does NOT enter shiftY: // the composition stays exactly where it is inside the surface and only the surface's BOTTOM // edge moves up, which is what makes the clip a pure clip and leaves every mirrored Python // constant alone. // `let`, not `const`, because of the large size mode (applySize re-derives the five that carry // a factor -- see it for the arithmetic) AND, for shiftY, because of the VERTICAL orientation: // goVertical swaps the whole composition box, and the vertical box is TALLER than it is wide // where the horizontal one is the reverse, so every one of these six moves. Under a single // orientation nothing rewrites them and they ARE the six expressions below. // NORMALISED ONCE, HERE, so every later `cfg.clipB` / `cfg.padX` read is a number: the // horizontal pair passes neither, and `2 * cfg.pad - undefined` is NaN, which would push a NaN // surface size. `padX` falls back to `pad`, which is what keeps `2 * padX` identical to the // `2 * pad` it replaces everywhere except the one composition that supplies its own. cfg.clipB = cfg.clipB || 0; cfg.padX = cfg.padX || cfg.pad; // `padXR`/`padXRLarge` default to symmetric (== padX / padXR), which is BYTE-IDENTICAL to the // old `2 * cfg.padX` for every composition that supplies neither -- see the arg note above. cfg.padXR = cfg.padXR || cfg.padX; cfg.padXRLarge = cfg.padXRLarge || cfg.padXR; let viewW = cfg.boxW + cfg.padX + cfg.padXR; let viewH = cfg.boxH + 2 * cfg.pad - cfg.clipB; let shiftX = cfg.padX - cfg.boxLeft; let shiftY = cfg.pad - cfg.boxTop; // MIRRORED (negated) in Python as // domain/constants.*_ANCHOR_Y_SHIFT, and as // VERTICAL_ANCHOR_Y_SHIFT under cfg.vert // ONE SHARED PAD (see the header note above): half the LARGER of the two axes, on all four // sides -- an oversized value is accepted, not rejected, so this collapses both axes at once. let hitPad = Math.ceil(Math.max(viewW, viewH) / 2); // THE LIVE RUN IDENTITY PAIR. Horizontal by default; goVertical repoints both at the vertical // composition's own twin (see RUN_CLASSES_V / RUN_NAMES_V), which is what makes armRun's // alternation and the animationend name filter follow the orientation for free. let runCls = RUN_CLASSES; let runNames = RUN_NAMES; // THE LARGE SIZE MODE's state. `large` is the pushed flag; `baseFont` is the document's root // font-size as it was BEFORE we ever touched it, captured ONCE so repeated application cannot // compound (and never read back off our own inline write). 0 == not captured yet. let large = false; let baseFont = 0; // THE CTRL+DRAG's ONLY remaining state here: `ctrlHeld` is the pushed key state (VM `ctrlHeld`), // and all it does now is HOLD THE BAR UP while the key is down, so there is something on screen // to grab. The gesture itself is Python's end to end (adapter/battle_input + // bridge/bar_window.drag) -- this document has no mousedown/mousemove/mouseup listener, no // reverse command, and no delta to report. let ctrlHeld = false; // Animation state. `showing` = the bar is visibly up (running or peek-held). `peeking` = Alt is // held, so the bar is pinned at the hold plateau with no fade-out (`peekT` is that pause's // timer). `holdT` is a SEPARATE timer that only exists while a configured hold differs from the // keyframe's baked one -- see holdFrom, which is a no-op (and leaves this null) at the default. // `plateauAt` = the wall-clock // ms at which the running animation reaches (or reached) that plateau -- the ONLY thing the // peek needs to know about the animation's progress, since Gameface exposes no readable // playback position. `dmgPlateauAt` = the same instant for the most recent DAMAGE-driven show // (0 == none in flight). It is a RECORD, NOT A SECOND CLOCK: `plateauAt` stays the only run // clock, and this only says where the damage hold that a peek interrupted would have been, so // peekOff can RESUME it instead of truncating it. Only ever nonzero while `showing` is true -- // both places that clear `showing` (endRun, reset) clear it too, or a release could resurrect a // show that already ended. // `settled` = the surface has been re-asserted and is the size we asked for, so the composition // is neither clipped nor mis-placed. Until then the bar must NOT be shown by ANY trigger. let settled = false; let peekT = null; let holdT = null; let showing = false; let peeking = false; let plateauAt = 0; let dmgPlateauAt = 0; // THE TRANSITION SWITCHES (mod_settings.progress_transitions_events / _manual, pushed as the // VM's transEvents / transManual -- the master is already ANDed in Python, so these two ARE the // effective flags). One per trigger AREA: an event show takes `animEvents`, an Alt peek takes // `animManual`. Default true == the shipped animated bar. // // `animated` is the LIVE RUN's copy, decided AT ARM TIME by the area that triggered it and then // kept for the whole run, so the EXIT follows the same switch as the entry (an event hold that a // peek interrupted still exits the event's way -- see peekOff's resume branch). Un-animated is // NOT a second code path: the entry simply arms at SEEK_PLATEAU (already opacity 1 and // translateY(0), so there is nothing left to play) and the exit simply ends the run at the end of // the hold, where disarm()'s base #moe-bar-root{opacity:0} applies in the same frame. let animEvents = true; let animManual = true; let animated = true; // THE HOLD DURATION in ms (mod_settings.progress_hold_seconds * 1000, pushed as the VM's // `holdMs`). Read by holdFrom at the moment a hold STARTS, so a live settings change lands on // the next show instead of truncating a hold in flight. Defaults to the keyframe's OWN baked // HOLD_MS, which is what makes holdFrom a no-op -- and therefore the whole feature inert -- for // an unpushed model, an old harness fixture, and every user who never moves the slider. let holdMs = HOLD_MS; // The live run's id, and the last id already ended. endRun is idempotent on this pair: // whichever of animationend / the fallback timer arrives first wins and the other becomes a // no-op, and a timer left over from a superseded run can never end a newer one. // armIdx starts at 1 -> the first armRun flips to 0, i.e. run #1 uses the emitted // .mp-run / mp-life pair. let armIdx = 1; let runId = 0; let endedId = 0; let endT = null; function disarm() { root.classList.remove(runCls[0]); root.classList.remove(runCls[1]); } // ADOPT THE VERTICAL COMPOSITION -- called ONCE, from mount, and only when the model's // `vertical` says so. Everything it touches is the geometry the surface push and the rigid // shift are derived from, plus the run identity pair, plus the body scope class the vertical // stylesheet hangs off; the DOM half is the bar's own (onVertical). // // WHY MOUNT AND NOT MODULE SCOPE: `observer.model` is a live getter over the engine's // `window.model`, and the first moment it is guaranteed populated is inside engine.whenReady -- // which is also the last moment before the surface is pushed, so this is the ONE point where the // flag is both readable and still early enough to matter. WHY ONCE: the composition is a DOM + // surface + stylesheet-scope switch, not a style; a mid-battle Orientation change is handled by // Python CLOSING and REOPENING the window (battle_bridge.apply_settings), which re-mounts this // document and comes straight back through here. // `cfg` is MUTATED rather than shadowed because applySize re-derives the same four values from // it on every Large flip -- leaving the horizontal box in cfg would silently restore it there. function goVertical() { cfg.boxLeft = cfg.vert.box[0]; cfg.boxTop = cfg.vert.box[1]; cfg.boxW = cfg.vert.box[2]; cfg.boxH = cfg.vert.box[3]; cfg.clipB = cfg.vert.clipB || 0; cfg.padX = cfg.vert.padX || cfg.pad; cfg.padXR = cfg.vert.padXR || cfg.padX; cfg.padXRLarge = cfg.vert.padXRLarge || cfg.padXR; viewW = cfg.boxW + cfg.padX + cfg.padXR; viewH = cfg.boxH + 2 * cfg.pad - cfg.clipB; shiftX = cfg.padX - cfg.boxLeft; shiftY = cfg.pad - cfg.boxTop; hitPad = Math.ceil(Math.max(viewW, viewH) / 2); runCls = RUN_CLASSES_V[cfg.vert.cls] || RUN_CLASSES; runNames = RUN_NAMES_V[cfg.vert.cls] || RUN_NAMES; try { // ON THE BODY, exactly like .mp-lg and for the same reason: the sizing shim // #moe-bar-box is a body-level SIBLING of the JS-created root, so a class on the root // could never scope a rule for it. document.body.classList.add(cfg.vert.cls); } catch (e) { /* fail-soft */ } onVertical(); } // Start (or restart) mp-life, seeking `seekMs` into it. THE single arming point -- coldShow, // warmShow, peekOn and peekOff all funnel through here, so the restart idiom exists in exactly // one place. Every run gets a FRESH animation identity (alternating .mp-run / .mp-run-b) rather // than trusting remove -> reflow -> re-add to restart the SAME animation, an idiom never proven // in Coherent; the engine has nothing to coalesce the new run with. The reflow is kept anyway: // it costs nothing where it works. The fallback timer is armed for this run's own remaining // duration and calls the SAME endRun. function armRun(seekMs) { armIdx = 1 - armIdx; runId += 1; const id = runId; disarm(); root.style.animationPlayState = ""; root.style.animationDelay = seekMs ? "-" + seekMs + "ms" : "0ms"; void root.offsetWidth; root.classList.add(runCls[armIdx]); clearTimeout(endT); // For an ANIMATED run this is the FALLBACK end timer: the run's own remaining duration plus // slack, so a working animationend always wins it. For an UN-ANIMATED one it is the REAL end // and must WIN, so it carries no margin and fires at the END OF THE HOLD instead -- // SEEK_FADE_OUT is the 90.32% stop (the instant the fade-out begins), so SEEK_FADE_OUT - // seekMs is exactly the ms left until it. endRun's disarm() drops the run class there and the // base #moe-bar-root{opacity:0} applies the same frame, so the fade-out never plays; the real // animationend arriving later is a no-op through the endedId guard. // BOTH of those instants assume the keyframe's OWN baked hold. A configured hold that // differs re-targets them -- see holdFrom, which is the one place that corrects this and // which is a NO-OP at the default, so this line stays the whole story for the shipped bar. endT = setTimeout(function () { endRun(id); }, animated ? TOTAL_MS - seekMs + END_MARGIN_MS : Math.max(0, SEEK_FADE_OUT - seekMs)); // THE run clock, maintained in ONE place so every arming path agrees: the seek makes the // run start `seekMs` in, so it reaches the plateau FADE_IN_MS - seekMs from now (in the past // for a seek past it). Gameface exposes no readable playback position, so this is how the // peek knows where the run is -- see peekOn. Only meaningful while the run is NOT paused // (wall-clock keeps running, the animation does not). plateauAt = Date.now() + FADE_IN_MS - seekMs; } // THE CONFIGURABLE HOLD, as a CORRECTION to the run mp-life already bakes -- deliberately NOT a // replacement for it. mp-life bakes fade-in + a HOLD_MS hold + fade-out into ONE both-filled // keyframe, so every armed run already leaves its hold at `plateauAt + HOLD_MS` (which is also // where armRun's un-animated endT lands). All this does is move that one instant to // `plateau + holdMs`, and it is the ONLY thing in the module that knows the hold is // configurable. // // THAT FRAMING IS LOAD-BEARING, NOT STYLE. An earlier build drove the hold entirely from JS -- // pause EVERY run at its plateau and release it with an explicit armRun(SEEK_FADE_OUT) -- which // works, but cost every ordinary auto-hide an EXTRA .mp-run/.mp-run-b identity flip mid-run that // the shipped single-run path never had (a live flicker risk on the most common path, and 11 // red assertions in tools/dev/check_progress_js.js). As a correction instead, `want === baked` // at the default and this function RETURNS HAVING DONE NOTHING: the shipped run plays start to // finish on one identity, ends on its own animationend, and the whole feature is inert until the // user actually moves the slider. That is not a "default uses the baked hold" special case -- // it is the fixed point of "move the deadline to where it already is". // // LONGER -> the keyframe would fade out too early, so PAUSE the run at its plateau (opacity 1 // and the slide both COMPLETE, so the pause is invisible) and release it at `want`. // SHORTER -> nothing to pause; just release early. // Either way the release is peekOff's own proven idiom (releaseHold), so a re-arm -- and its one // identity flip -- happens ONLY on a hold the user actually changed away from 5s. Resuming a // pause IN PLACE would avoid even that, but `animationPlayState = ""` on a PAUSED animation is // unproven in Coherent (peekOff has always re-armed rather than resume), so it is not used. // // `plateau` is the wall-clock instant the hold STARTS, never a duration -- which is what lets // peekOff resume an interrupted event hold at its ORIGINAL deadline (dmgPlateauAt) rather than // granting it a fresh one. `baked` is read off plateauAt (armRun's clock) rather than assumed, // so it is correct for ANY seek the run was armed with, including peekOff's resume seek. // The runId capture makes a correction from a superseded run a no-op, exactly like endT. function holdFrom(plateau) { clearTimeout(holdT); const baked = plateauAt + HOLD_MS; // when THIS run's keyframe leaves the hold const want = plateau + holdMs; // ...and when the setting says it should if (want === baked) return; // the keyframe IS the hold -- nothing to correct const id = runId; const release = function () { if (id === runId) releaseHold(); }; if (want < baked) { holdT = setTimeout(release, Math.max(0, want - Date.now())); return; } holdT = setTimeout(function () { if (id !== runId) return; root.style.animationPlayState = "paused"; clearTimeout(endT); // a paused run never reaches its own end // While Alt is held the pause simply has no expiry -- peekOff is then the release, and // its resume branch calls back in here to re-apply the correction. if (!peeking) holdT = setTimeout(release, Math.max(0, want - Date.now())); }, Math.max(0, plateauAt - Date.now())); } // Leave the hold the way the LIVE RUN's `animated` says. Shared by holdFrom's correction and by // peekOff, so "the configured hold ran out" and "Alt was released" are one exit. // `inLeft` is how much of the ENTRY was still owed, mirrored back BEFORE the 90.32% stop so the // fade-out starts at the opacity the bar is already at. It is 0 for a hold correction (which // fires at or past the plateau by construction) and only ever nonzero for a release that beat // the pause -- THE PEEK IS STRICTLY HOLD-TO-SHOW, including a sub-FADE_IN_MS tap. (An earlier // build bailed on `animationPlayState !== "paused"` instead, which re-armed nothing, so a tap // served the whole transient and read as a toggle-on with a 5s auto-hide.) COSMETIC, // DELIBERATELY NOT FIXED: the mirror is linear while both fade halves are ease-in, so a release // mid-fade-in can step opacity by up to ~0.2 -- only reachable on that same barely-visible tap. function releaseHold() { // Un-animated: end it outright rather than arming a fade-out. endRun does the disarm (base // opacity 0, same frame) plus the bookkeeping every other end does, and the endedId guard // makes any late real animationend a no-op. if (!animated) { endRun(runId); return; } const inLeft = Math.min(FADE_IN_MS, Math.max(0, plateauAt - Date.now())); armRun(SEEK_FADE_OUT + inLeft); } // COLD SHOW: the bar is not up -> play the whole mp-life transient. `fromDamage` distinguishes // the data-driven entry (which owns a hold an Alt peek may interrupt and must later resume) // from peekOn's own entry, which IS the peek -- and it also picks which VALUES the run opens // with, via onRewind. The MOTION is identical either way (armRun(SEEK_NONE), the tuned fade + // slide). function coldShow(fromDamage) { clearTimeout(peekT); // WHICH AREA IS ARMING THIS RUN -- the one place the run's `animated` is decided for an // entry, and it covers both cold entries (peekOn's own is fromDamage == false). animated = fromDamage ? animEvents : animManual; // An UN-ANIMATED entry must also SNAP THE VALUES: with no 600ms fade there is no window for // the pre->current climb to happen in, and VALUE_SWAP_MS / the cold rAF both assume one. So // reuse the Alt entry's existing "open ALREADY committed" rewind (onRewind(true)) and skip // onCommit entirely -- there is nothing left to commit. No second snap mechanism. onRewind(!fromDamage || !animated); // A cold show plays the entry in full (plateauAt too) -- unless it is un-animated, where // arming AT the plateau (opacity 1, translateY(0) both complete) IS the instant appearance. armRun(animated ? SEEK_NONE : SEEK_PLATEAU); holdFrom(plateauAt); // ... and the hold this entry earns starts THERE, not now if (fromDamage) dmgPlateauAt = plateauAt; showing = true; if (fromDamage && animated) onCommit(true); // cold: the target must land in a LATER frame } // WARM RE-TRIGGER (the debounce): a change arrived while the bar is ALREADY up. Do NOT replay // the appearance -- re-measure the DISAPPEARANCE from this event instead. mp-life bakes // fade-in, hold and fade-out into ONE both-filled keyframe, so its hold cannot be extended in // place; instead restart the animation but SEEK PAST the entry with a negative delay // (SEEK_PLATEAU, the 9.68% stop, where both the opacity fade and the slide have completed). The // bar stays visibly put and gets a fresh hold + fade-out. function warmShow() { // AN EVENT IS RE-ARMING THIS RUN, so the run's `animated` becomes the events switch -- the // entry itself is already the plateau seek and needs no branch, but the EXIT does (an // animated peek that a switched-off event re-triggers must now leave instantly). animated = animEvents; if (!peeking) { armRun(SEEK_PLATEAU); // the seek lands us AT the plateau (armRun sets plateauAt) holdFrom(plateauAt); // ... and this event's hold starts there, fresh } // THIS event's hold, remembered so an Alt release resumes it instead of discarding it // (peekOff). The peeking branch is the whole reason this is not just read off `plateauAt`: // while Alt is held we deliberately do NOT armRun (the pause must survive), so an event // landing mid-peek would otherwise get no hold at all and be wiped 600ms after the release. // Record the plateau the run WOULD have had -- SEEK_PLATEAU cancels FADE_IN_MS, so armRun's // clock makes that exactly now, which is also why the non-peek branch can read the // freshly-set plateauAt. dmgPlateauAt = peeking ? Date.now() : plateauAt; onCommit(false); // warm: nothing was rewound, so set the target NOW } // ALT PEEK (an ADDITIVE second show-trigger, not a gate -- the transient still fires on its own // when Alt is untouched). While Alt is held the bar must be pulled up and HELD with no // fade-out. Mechanism: play (or keep) mp-life and PAUSE it at the hold plateau, so the entry is // the real fade+slide and the hold simply never ends. function peekOn() { clearTimeout(peekT); if (!showing) { coldShow(false); // full entry, then pause below once it lands } else if (!peeking && root.style.animationPlayState !== "paused" && Date.now() >= plateauAt + HOLD_MS) { // NOT PAUSED is a cheap extra guard for the LONGER hold correction, which parks the run // at its plateau at full opacity: there the wall-clock test alone can read true mid-hold, // and a paused run is by definition already AT the plateau, so there is nothing to catch. // At the default (and for any SHORTER hold) nothing is ever paused here and this term is // constant, so the branch below is the shipped one. // ALT PRESSED DURING THE FADE-OUT -- `showing` stays true all the way through it (only // endRun clears it), so pausing here would pin the bar at partial opacity. // plateauAt + HOLD_MS is the 90.32% stop (== elapsed SEEK_FADE_OUT, see armRun's run // clock), so at/past it the run is already fading out and must be RE-ARMED, not paused. // SEEK_PLATEAU, not a cold entry: mp-life's 0% stop is opacity 0, so replaying the // entry from a partially-visible bar would visibly DIP it to nothing and fade up again // (reads as a flicker). Seeking to the plateau snaps it back to full opacity -- "caught // it". armRun also re-establishes the run identity, the runId guard and the endT // fallback, so the superseded run's animationend/timer cannot end this one. // ALT IS ARMING THIS RUN, so it takes the manual switch (the "caught it" seek IS already // instant either way -- what this decides is the exit). animated = animManual; armRun(SEEK_PLATEAU); } // ALT OWNS THE HOLD FROM HERE, so drop any pending hold CORRECTION -- peekOff's resume // branch re-applies it on release. This has to come AFTER the branch above, not before it: // the cold entry inside it goes through coldShow, which arms a correction of its OWN, so // clearing first left a SHORTER-than-baked hold free to release the bar out from under a // still-held Alt (measured: a 2s hold ended the peek 3.2s in, ignoring the key entirely). // A LONGER hold loses nothing by this -- peekT below is the pause that parks the bar anyway. clearTimeout(holdT); peeking = true; // Pause once the entry has completed -- pausing mid-fade-in would freeze the bar at partial // opacity. If the bar was already PAST the entry the wait is 0 and it pauses on this tick. peekT = setTimeout(function () { root.style.animationPlayState = "paused"; // A paused hold NEVER ends, so the fallback timer must not end it either. peekOff // re-arms a fresh run (and a fresh timer) for the fade-out -- and it does so whether or // not this pause ever landed, so a release that beats it is still hold-to-show. clearTimeout(endT); }, Math.max(0, plateauAt - Date.now())); } // Alt released -> fade out NOW rather than serving the rest of the hold: releaseHold, which // unpauses and seeks straight to the 90.32% stop so only the fade-out plays (see it for the // sub-FADE_IN_MS tap mirror -- THE PEEK IS STRICTLY HOLD-TO-SHOW, and a release NEVER earns // another `holdMs`). // // EXCEPT when the peek interrupted a DATA-driven show that still has hold left: players hold // Alt near-constantly (extended markers), so fading out there would truncate an event's hold to // whatever was left of the peek. RESUME that hold instead, at its true elapsed position: // seeking (now - dmgPlateauAt) PAST the plateau makes armRun's clock re-derive // plateauAt == dmgPlateauAt, so the resumed run's fade-out starts at exactly the instant the // original hold would have -- not later. The pause is simply not credited back: the hold is // wall-clock, as it was before any Alt. // THE SEEK IS CAPPED AT THE BAKED HOLD, because that is all the keyframe HAS: past // SEEK_FADE_OUT it would land in (or beyond) the fade-out. Only reachable with a hold LONGER // than HOLD_MS, and holdFrom then carries the rest -- it re-derives `baked` off the seeked // plateauAt, so the capped seek plus the correction still add up to dmgPlateauAt + holdMs. At // the default the cap can never bind (the branch above requires elapsed < holdMs == HOLD_MS), // so this is the shipped seek exactly. function peekOff() { clearTimeout(peekT); if (!peeking) return; peeking = false; if (dmgPlateauAt + holdMs > Date.now()) { // The run being resumed is the EVENT's hold, so it exits the EVENT's way. animated = animEvents; armRun(SEEK_PLATEAU + Math.min(Date.now() - dmgPlateauAt, HOLD_MS)); holdFrom(dmgPlateauAt); return; } // ...otherwise this release IS the exit of the run Alt armed, so it follows `animated`. releaseHold(); } // FORCE-SETTLE, and the ONE place the "run is over" state is cleared. mp-life is both-filled so // the root rests at its 100% stop (opacity 0) with no help from JS; onEnd drops whatever else // a hold longer than the transient would have left showing. // `id` is the run being ended: an id that is not the live run (a timer from a superseded run) or // one already ended (the loser of the animationend/timer race) is ignored. function endRun(id) { if (id !== runId || id === endedId) return; endedId = id; clearTimeout(endT); clearTimeout(peekT); clearTimeout(holdT); disarm(); showing = false; peeking = false; dmgPlateauAt = 0; // the hold is over -- a later release must never resume it root.style.animationPlayState = ""; onEnd(); } // Only the CURRENTLY armed animation's end counts. Because armRun alternates the identity, the // cancel/end noise of the run it just superseded reports the OTHER name and is dropped here for // free. A pulse on an inner element (.mp-track) never reaches this listener. root.addEventListener("animationend", function (e) { if (e.animationName !== runNames[armIdx]) return; endRun(runId); }); // Reset to the resting/hidden state, so a later re-show starts COLD. The caller additionally // drops its own change-detect baseline, so the next push becomes a fresh silent one (a // scoreboard opening and closing must not replay the bar). function reset() { clearTimeout(peekT); clearTimeout(holdT); clearTimeout(endT); endedId = runId; // no live run left for a late animationend to end disarm(); // DROP THE HELD-CTRL FLAG HERE TOO. This is the "bar hidden" path (a scoreboard, a spectate, // the feature switched off mid-battle, a new battle), and it can land with Ctrl still down -- // leaving the flag set would let the next peek() call pin a bar that was just reset. Ctrl // coming back up sets it again through the same one-line applyCtrl. applyCtrl(false); root.style.animationPlayState = ""; root.style.animationDelay = "0ms"; showing = false; peeking = false; dmgPlateauAt = 0; // ditto endRun: no hold survives a hide / a new battle onIdle(); } // Push the surface size and collapse the input rect. Feature-detected and fail-soft, like every // engine read in this codebase -- OpenWG's own libs/common.js touches the `viewEnv` global // directly and offers no resize wrapper, so this does too. Idempotent: called at mount and once // more after SURFACE_REASSERT_MS. function pushSurfaceSize() { if (typeof viewEnv === "undefined" || !viewEnv) return; try { // WG's own views freeze the texture across a resize (flicker, not sizing) -- e.g. // BattleNotifierView.js. Optional, so feature-detected like the rest. if (viewEnv.freezeTextureBeforeResize) viewEnv.freezeTextureBeforeResize(); } catch (e) { /* fail-soft */ } try { if (viewEnv.resizeViewRem) viewEnv.resizeViewRem(viewW, viewH); } catch (e) { /* fail-soft: a clipped bar beats a dead one */ } pushHitArea(); } // THE INPUT RECT, kept as its own function because it is the one engine call with a two-tier // argument fallback. It is ALWAYS the collapsing push now: the rect used to be OPENED (padding // 0, i.e. the whole surface rect live) while Ctrl was held, so the bar's own document could // receive the drag's mouse events -- and that opening was the HUD-input-stealing hazard the old // design had to manage on every path that could leave the gesture. Python owning the gesture // retires it: nothing in here needs a mouse event, so the rect never opens. function pushHitArea() { if (typeof viewEnv === "undefined" || !viewEnv) return; if (!viewEnv.setHitAreaPaddingsRem) return; // (top, right, bottom, left, magic) -- confirmed order (see the header note). FOUR EQUAL // VALUES, matching WG's own wrapper -- the order is moot when they cannot differ. try { viewEnv.setHitAreaPaddingsRem(hitPad, hitPad, hitPad, hitPad, HIT_MAGIC); } catch (e) { // The 5th argument's meaning is unknown -- if the binding rejects the 5-arg form, the // 4-arg one still collapses the rect. try { viewEnv.setHitAreaPaddingsRem(hitPad, hitPad, hitPad, hitPad); } catch (e2) { /* fail-soft */ } } } // THE ROOT FONT WRITE -- the whole SIZE_F half of the large mode (see the constant's note). // Captures the base ONCE and never reads back our own inline value, so applying it twice cannot // compound. Fail-soft like every other engine touch: no getComputedStyle / no documentElement // (a shim, a stripped document) simply leaves the size alone. // // THE CAPTURE IS GATED ON THE VIEW HAVING A SIZE, and that gate is load-bearing. For the first // frames of a mount the view has NO size (innerWidth/innerHeight are both 0 -- live-measured, in // the very first dump of every mount) and THE ENGINE HAS NOT WRITTEN ITS ROOT FONT YET, so // getComputedStyle hands back the UA default 16 instead of the engine's 1 (2 at interface scale // x2). Baking 16 in as the base multiplied every rem by 16: with Large enabled BEFORE launch -- // the ONLY path where the very first applySize takes the large branch -- rootFontPx came out 24 // and the 400rem track 9600px wide inside a 950px surface, i.e. drawn entirely outside the view // and INVISIBLE. Flipping to Large mid-session was always fine (the engine's root font is in // place by then), which is exactly what hid this until it shipped. // Untrusted means WRITE NOTHING -- not a guessed base, and not our own value read back: leaving // the inline style alone is what keeps the LATER read (mount's post-deadline re-assert calls this // again) the engine's own value. // The capture, kept as its own function: it is the ONE place a root-font read happens, and it is // ALSO the interface-scale signal setQuantClass gates on. That second use is MEASURED, not // assumed: a four-bit screenshot probe read this value BELOW 1.5 at interface scale 1 and at/above // 1.5 at scale 2, on the DEFAULT path, on fresh launches -- while devicePixelRatio and // innerWidth/viewW both read a constant 1 at either scale and innerHeight/viewH a constant ratio, // so none of those three is a signal. See tests/test_caption_anchor_quantisation.py. // Returns the base in px; 0 == not trustworthy yet, which means DO NOTHING. function captureBaseFont() { if (!baseFont && (window.innerWidth || window.innerHeight)) { baseFont = parseFloat(getComputedStyle(document.documentElement).fontSize) || 1; } return baseFont; } function setRootFont() { try { if (!captureBaseFont()) return; document.documentElement.style.fontSize = large ? (baseFont * SIZE_F) + "px" : ""; } catch (e) { /* fail-soft: the shipped size beats a dead view */ } } // THE INTERFACE-SCALE GATE. The ONE class the caption-icon correction hangs off // (MoEEfficiency.css's HAND-ADDED BLOCK 4, which documents the correction itself; MoEProgress.css // deliberately carries no rule for it, so on the Moving Average bar this class is inert). // // A THRESHOLD, NEVER AN EXACT KEY: an exact match on an engine-reported number fails silently and // one whole build died on exactly that. It also never consults `large` -- the size mode is a // separate axis, and folding it in here is what made the correction depend on how Large was // reached. // THE POSITIVE LOWER BOUND IS THE TRUST GATE: captureBaseFont returns 0 while the view has no size // (see it), and an untrusted read must leave the class OFF, because the base cascade IS the render // the maintainer approved at interface scale 2. Every failure mode here -- no size yet, no // documentElement, a throwing getComputedStyle -- therefore lands on "no class, no correction, // nothing moves". // toggle(cls, force) both ADDS and REMOVES, which is what makes re-evaluating safe from anywhere. // // KNOWN, ACCEPTED DEFECT -- A LIVE INTERFACE-SCALE CHANGE LEAVES THE CLASS STALE UNTIL RELAUNCH. // Python DOES see one (settingsCore.interfaceScale.onScaleChanged -> battle_bridge's // _on_scale_changed -> *_view.apply_position()), but nothing carries it into this document: there // is no VM field for it, and `baseFont` is captured ONCE, so re-running the gate off a hook would // re-read the old value anyway (and re-capturing is not free -- under Large we have written our // own inline root font, which a naive re-read would compound). Minor, and deliberately NOT papered // over with a polling timer. A measurement taken ACROSS a live scale change is therefore not a // measurement of this gate. function setQuantClass() { try { const px = captureBaseFont(); document.body.classList.toggle("mp-s1", px > 0 && px < 1.5); } catch (e) { /* fail-soft: the base cascade IS the approved render */ } } // Apply the pushed size flag. Idempotent (a no-op unless it actually FLIPPED), so the bars can // call it on every render. Order matters: the CSS side first, then the surface push, because the // engine round-trips the resize back into Python's _place. // x-lengths carry SIZE_XF in the stylesheet AND here (boxLeft / boxW are x-lengths) // y/uniform carry nothing here -- the root font does them // engine args carry SIZE_F on top, because resizeViewRem's rem is C++'s, not our document's function applySize(flag) { flag = !!flag; if (flag === large) return; large = flag; const xf = large ? SIZE_XF : 1; const f = large ? SIZE_F : 1; // ROUNDED, because 4/3 is not representable: (460 * 4/3 + 20) * 1.25 evaluates to // 791.6666666666665, and the engine takes whole logical px (a floor there would hand us a // 1px-narrow surface). Both factors are exact at the shipped size, so this is identity there. // `padX`/`padXR` do NOT carry `xf` -- see their arg notes: they are rem-space slack (ink // allowance on the left, a bleed CLIP on the right), which the root font's SIZE_F already // grows/shrinks. Large reads `padXRLarge` instead of `padXR * xf`: its target (the Python // `edge_x` it must clear) is a hand-corrected, not purely `*SIZE_XF`-scaled, number -- see // the arg note. viewW = Math.round((cfg.boxW * xf + cfg.padX + (large ? cfg.padXRLarge : cfg.padXR)) * f); // clipB is a Y length like boxH and pad, so it takes `f` alone with them and NEVER `xf` -- // it stays INSIDE the parenthesis so the clip scales with the composition it clips (the // caption ink below the track scales too), rather than staying a fixed logical-px bite that // would eat into that ink under Large. viewH = Math.round((cfg.boxH + 2 * cfg.pad - cfg.clipB) * f); // rem, so it self-scales with the root font -- 3dp to match the stylesheet's own x-lengths, // which keeps shiftX + the .mp-lg backdrop's `left` exactly `pad`. shiftX = Math.round((cfg.padX - cfg.boxLeft * xf) * 1000) / 1000; hitPad = Math.ceil(Math.max(viewW, viewH) / 2); setRootFont(); // THE SCALE GATE IS RE-EVALUATED ON EVERY FLIP, in BOTH directions, and is deliberately not // latched at mount. The shipped build computed it in ONE branch of the re-assert, so `.mp-s1` // and `.mp-lg` could only coexist by launching at Default and enabling Large mid-session -- // i.e. the correction applied or not depending on HOW the user reached Large. It is also the // one place an engine-pushed scale can reach the gate: self.onScaleUpdated moves `baseFont`, // but only while large, so a flip BACK re-reads it. At the shipped size this re-reads the same // capture and is a no-op, which is the point -- it can only ever agree with the mount-time // evaluation. setQuantClass(); try { // WG's own ancestor-class idiom (.mediaLargeWidth ...). It MUST go on the BODY: the // sizing shim #moe-bar-box is a body-level SIBLING of the JS-created root, so a class on // the root could never reach it. document.body.classList.toggle("mp-lg", large); } catch (e) { /* fail-soft */ } root.style.left = shiftX + "rem"; pushSurfaceSize(); } // The pushed transition switches (VM `transEvents` / `transManual`). Plumbed exactly like // applySize -- idempotent and safe on every render -- but it needs no flip guard and touches // nothing: it only records which switch the NEXT arming reads, so a live settings change lands on // the next show rather than mutating the run in flight. // ABSENT MEANS ANIMATED, which is why this is `!== false` and not `!!`: a model that does not // carry the field at all (a pre-push frame, a harness fixture, a marshal that dropped it) must // degrade to the SHIPPED behaviour, and `!!undefined` would silently degrade to instant instead -- // the fail-soft direction every other read in this codebase takes. A real pushed false is the // only thing that turns a transition off. function applyAnim(events, manual) { animEvents = events !== false; animManual = manual !== false; } // The pushed HOLD DURATION (VM `holdMs`). Plumbed exactly like applyAnim -- idempotent, safe on // every render, and it only records what the NEXT hold reads (holdFrom), so a live settings // change lands on the next show rather than truncating a hold in flight. // ABSENT MEANS THE SHIPPED 5000, NEVER 0, which is why the test is `> 0` and not a bare cast: a // model that does not carry the field at all (a pre-push frame, an old harness fixture, a // marshal that dropped it) yields NaN, and `NaN > 0` is false -- so it degrades to the BAKED // hold, the same fail-soft direction applyAnim takes. A 0 would mean "no hold at all". function applyHold(ms) { const v = Number(ms); holdMs = v > 0 ? v : HOLD_MS; } // --- CTRL+DRAG TO REPOSITION: NOT IN THIS FILE ANY MORE ------------------------------- // The gesture is Python's, end to end. adapter/battle_input samples Ctrl AND the left mouse // button off WG's own input dispatchers and reports start/move/end; bridge/bar_window re-places // the window ABSOLUTELY from GUI.mcursor().position on every movement. This document's only part // is `ctrlHeld` below, which holds the bar up so there is something to grab. // // WHAT WAS DELETED AND WHY IT CANNOT COME BACK. There used to be a document-level // mousedown/mousemove/mouseup drag here (`installDrag`) reporting a cursor DELTA through a // `setPosition` reverse command. Three structural failures, not three bugs: // (1) the reported delta was DEVICE px while window.move takes LOGICAL px, so it needed a gain // factor -- and interfaceScale, the obvious candidate, over-corrected; // (2) each bar IS its own window and THE SURFACE RECT IS THE MOUSE HIT RECT, so mouse events // only reached this document while the cursor stayed inside the bar-sized rect. Any gain // error or round-trip lag let the cursor drift out; events stopped, then resumed, and the // bar lurched ("jumps wildly near the edges of the bar"). Capture-phase listeners do NOT // help -- that is DOM propagation inside a document, not the engine's hit test; // (3) the JS -> Python -> engine round trip lags under battle load. // An ABSOLUTE mapping has no gain factor to get wrong and needs no mouse input in the document // at all, which is also why the hit rect is now permanently collapsed (see pushHitArea). // Re-introducing any delta protocol re-introduces all three. // The pushed CTRL state (VM `ctrlHeld`), read every render like applySize / applyAnim, and now // just a flag: `peek()` reads it back, so a held Ctrl pins the bar at its hold plateau exactly // like a held Alt. // // `=== true`, NOT `!== false`, and that is the OPPOSITE of the two switches above ON PURPOSE: // both rules say "fail soft toward the SHIPPED behaviour", and the shipped bar is NOT pinned up. // An absent field (a pre-push frame, an old harness fixture, a marshal that dropped it) must // therefore read as NOT HELD -- `!== false` would peek forever on any model that never carries // the flag, and the bar would never come down. function applyCtrl(held) { ctrlHeld = held === true; } // Wire the bar up, ONCE, on engine ready. FOUR parts, in this order: // // (0) THE ORIENTATION, if the bar offers a vertical composition at all (cfg.vert). FIRST, // because every one of the three parts below is derived from the composition it picks -- // the shift, the surface size, and the DOM the first render writes into. `=== true`, NOT // `!== false`: this is a STATE bool, and the shipped bar is HORIZONTAL, so an absent field // (a pre-push frame, an old harness fixture, a marshal that dropped it) must fail soft // toward the shipped composition -- the same rule `ctrlHeld` follows and the OPPOSITE of // the transition switches', which are feature switches whose shipped state is on. // (1) THE RIGID TRANSLATION (unconditional -- an origin overflow is clipped at ANY surface // size, so this must happen even without viewEnv). #moe-bar-root is // position:absolute;left:0;top:0 in the CSS, and moving its origin carries the in-flow // .mp-track AND the abspos .mp-backdrop with it -- relative geometry stays bit-for-bit // identical and NO tuned value is touched. It has to be left/top and NOT a transform: // mp-life animates the root's OWN transform and would clobber one. Python cancels the // shift (*_ANCHOR_Y_SHIFT) so the bar does not move on screen. // (2) THE SURFACE + INPUT RECT, pushed now and RE-ASSERTED after the engine's default-size // deadline. The `settled` flip is NESTED in that callback on purpose: it is the re-assert // that makes the surface correct, so the dependency is structural rather than a second // timer that could outlive it. It then re-renders the model we already hold, so a // STILL-HELD Alt takes effect immediately -- during PREBATTLE there may be no efficiency // tick to re-push it, and the player is mid-peek. That render is no longer a ONE-SHOT: a // short self-stopping poll keeps re-calling it in case the model's `visible`/`hasData` push // is still to come (see COLD_POLL_MS above). // (3) the model subscription and the first render. function mount(observer, render) { engine.whenReady.then(() => { if (cfg.vert && observer.model && observer.model.vertical === true) goVertical(); root.style.left = shiftX + "rem"; root.style.top = shiftY + "rem"; pushSurfaceSize(); // ROBUSTNESS ON THE ROOT FONT (the one unknown): we do not know from source whether the // engine also initialises / overwrites the root font per view. WG's bootstrap re-writes it // from this event, so if it reaches a registered view we take the PUSHED scale as the new // base and re-apply -- and if it never fires, the mount-time capture already stands. // Only while large: the shipped size never touches the root font at all. try { engine.on("self.onScaleUpdated", function (scale) { if (!large) return; baseFont = parseFloat(scale) || baseFont || 1; setRootFont(); // guarded in there -- this runs in an engine callback }); } catch (e) { /* fail-soft: the event is optional */ } setTimeout(function () { // THE DEFERRED ROOT FONT. A large flag pushed on the first render arrives while the // view still has no size, so setRootFont could not trust the computed base and wrote // nothing; the re-assert is the first moment the view is definitely sized, so this is // where that write actually lands. Gated on `large` for the same reason the scale // hook is: the shipped size never touches the root font at all. // THE SCALE GATE RUNS UNCONDITIONALLY, on BOTH paths, and the two lines are kept // adjacent so that stays visible: this is the first moment the view is definitely // sized, hence the first moment the capture can be trusted, and a launch straight // into Large must get the gate too. The shipped build ran it in the `else` alone, // which is how the correction became a function of how Large was reached (see // applySize, which re-evaluates it on every flip). if (large) setRootFont(); setQuantClass(); pushSurfaceSize(); setTimeout(function () { settled = true; // The one immediate render this always did -- kept verbatim (see COLD_POLL_MS's // header note above for why a bare one-shot here is not enough on its own). render(observer.model); // REVEALED ALREADY: an event fired inline (e.g. a still-held Alt in "Always" // mode, data that was ready all along) -- `showing`/`peeking` are this closure's // own state, set by the render() call just above, so no poll is needed. if (showing || peeking) return; // NOT YET REVEALED: poll observer.model until it is, or give up at the ceiling. // A SELF-RESCHEDULING setTimeout, not setInterval -- this module already takes // `setTimeout`/`clearTimeout`/`Date` as its only timing primitives (mirrored, // fake-clock-driven, by tools/dev/lib/gf_check_shim.js's headless harness, which // does NOT stub setInterval), so a setInterval here would fall through to a REAL // timer under that harness -- ungated by the virtual clock's Date.now(), and // therefore never satisfying its own stop predicate there. const deadline = Date.now() + COLD_POLL_CEILING_MS; (function tick() { setTimeout(function () { render(observer.model); if (!(showing || peeking) && Date.now() < deadline) tick(); }, COLD_POLL_MS); })(); }, SURFACE_SETTLE_MS); }, SURFACE_REASSERT_MS); observer.onUpdate(render); observer.subscribe(); render(observer.model); }); } return { mount: mount, // THE SHOW TRIGGERS ARE GATED ON `settled`; a caller's SILENT BASELINE must not be. Before // the re-assert the surface is the engine's 256x256 fallback: the bar would come up cropped // and badly mis-placed. A baseline shows nothing, so it costs nothing to let it run -- and // it MUST run, or the change-detect never gets its first value. settled: function () { return settled; }, show: function () { if (showing) warmShow(); else coldShow(true); }, // Alt is an ADDITIVE trigger, never a gate. Re-peeking while already peeking is a no-op, so // a re-push that merely carries altHeld again cannot restart the hold. // // CTRL RIDES THE SAME PEEK, deliberately reusing it rather than adding a hold path: the // reposition gesture needs the bar up and pinned for exactly as long as the key is down, // which IS what peekOn does (pause at the hold plateau, never end the run). So a held Ctrl // peeks like a held Alt, and releasing either one releases the peek only if the other is up // too. This is now the bar's ENTIRE part in the gesture -- Python does the rest. peek: function (held) { if (held || ctrlHeld) { if (!peeking && settled) peekOn(); } else { peekOff(); } }, // The pushed Ctrl state (VM `ctrlHeld`): it holds the bar up for the reposition gesture and // does nothing else. Read every render, like size / anim / hold -- and BEFORE peek(), which // reads the flag back. ctrl: applyCtrl, // The pushed size flag (VM `barSize` == 1). Idempotent, so it is safe on every render; the // flag arrives AFTER the mount-time surface push, so the correct size lands on the // POST-DEADLINE re-assert -- which is fine precisely because `settled` hides the bar until // then (see SURFACE_REASSERT_MS). size: applySize, // The pushed transition switches (VM transEvents / transManual, master already folded in // Python). Read every render, like size. anim: applyAnim, // The pushed hold duration (VM holdMs). Read every render, like anim. hold: applyHold, reset: reset, disarm: disarm, }; } export { fmt, SIZE_F, SIZE_XF, FADE_IN_MS, HOLD_MS, FADE_OUT_MS, TOTAL_MS, SEEK_NONE, SEEK_PLATEAU, SEEK_FADE_OUT, SURFACE_REASSERT_MS, SURFACE_SETTLE_MS, END_MARGIN_MS, HIT_MAGIC, RUN_CLASSES, RUN_NAMES, RUN_CLASSES_V, RUN_NAMES_V, }; PK!:9{E{E9res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.css/* 14th_ua's MoE Calculator -- in-battle overlay. Mirrors WG's own personal-efficiency panel (damage dealt / blocked / assisted): a left-aligned vertical stack of [icon] [value] rows over a soft dark radial shape, NO text labels, NO frame. FONT: the numerals use a bundled TrueType face (family "MoEBattle") whose glyphs match the native efficiency panel. LOADING QUIRK (learned the hard way): Coherent's @font-face resolves its src url like the garage's card_border.png border-image -- a BARE SIBLING filename against the document dir works, but a SUBDIR-relative path (fonts/..) silently fails and the text falls back to Arial Narrow. So the ttf sits RIGHT BESIDE this CSS (not in a fonts/ subdir), referenced unquoted + bare, with a coui:// absolute as a belt-and-suspenders fallback. The family is given a mod-unique name so it can never collide with an engine-registered font. Geometry/typography values below were tuned in the browser overlay tuner (tools/dev/gen_overlay_tuner.ps1) against a real 4K battle backdrop and copied verbatim. Palette by VALUE (hex, NO var(--color-*) -- Gameface drops the whole declaration when a var() can't resolve); sizing in rem (engine scales the root font). */ /* The overlay uses ONE cut only -- weight 600, subset to the ~18 chars we render. Every text element requests weight 600 so it maps to this single face with no fallback synthesis. Bare-sibling url first (the scheme that actually works, per card_border.png), coui:// absolute as a fallback. */ @font-face { font-family: "MoEBattle"; font-weight: 600; font-style: normal; src: url(MoEBattle.ttf) format("truetype"), url("coui://gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.ttf") format("truetype"); } /* This is a CONTENT-SIZED OpenWG-registered Gameface WINDOW over the battle HUD (see bridge/battle_view.py -- WINDOW_FULLSCREEN was dropped to stop the Ctrl+click/hover steal). The window surface fits THIS box, so only this corner covers the screen and the minimap/HUD stay click-through under a raised cursor. Give the document a FIXED box (NOT width/height:100% -- that resolves against the surface, which now follows the content = circular). Sized in rem, the SAME unit as the readout, so the box tracks the text at any interface scale; generous enough for two rows of "10,000 / 10,000". The Python side positions this box (move()); leftover transparent space still hit-tests, so keep the box snug. If the readout ever clips or the box reads too large in-game, tune these two values (live-calibration item -- there is no hot-reload for this window). */ html, body { width: 340rem; /* Tall enough for the in-box top offset below + up to 3 rows (no clip). +22rem over the old 130rem (2-row) value = one row's net pitch (row box 33rem, margin-bottom -11rem overlap), for the optional counted-assistance row. Keep snug -- leftover box area still hit-tests, so do not over-grow. Live-calibration item (no hot-reload for this window). */ height: 152rem; margin: 0; padding: 0; background: transparent; overflow: hidden; pointer-events: none; } /* Vertical stack of icon+value rows, pinned to the top-left of the content box. The WINDOW itself is now positioned over WG's efficiency panel (bridge/battle_view.py move()), so the readout no longer self-anchors with vw/vh (which would resolve against the small surface). Rows tile with BLOCK flow (no gap/margins) -- flex `gap` is unsupported in this Coherent build and flex-COLUMN drifts the backdrops (see display: block below). Pitch comes from .mb-row's own padding. */ #moe-battle-root { position: absolute; left: 0; /* The window (bridge/battle_view.py) pins the 256-logical box FLUSH to the bottom, so its top clamps at ~76.3vh (y=824). To land the readout top at the tuned 78.8vh, nudge it down within the box by (78.8-76.3)vh = 2.5vh = 27 logical px; at 1rem == 1 logical px (calibrated 2.0 px/rem @3840) that is 27rem. This is exactly the overlay tuner's emitted `#moe-battle-root { top: … }` value -- keep them in lockstep. */ /* +0.5rem (~+1px @3840) over the tuner's 27rem: measured against WG's efficiency panel the overlay baselines sat a constant ~1px high; this drops them onto the native rows. +6rem more (=> 33.5rem): the row pitch moved from negative-margin overlap to plain padding (see .mb-row), which shrank each row's TOP padding 8rem -> 2rem and lifted every text baseline 6rem. Adding 6rem here puts row 1's baseline back exactly where it was, and because the pitch is unchanged (21rem) every lower row lands on its old baseline too. */ top: 33.5rem; /* Explicit box so the backdrops (see .mb-backdrop) size with width:100% against a KNOWN width -- never left:0;right:0, which is a dual horizontal anchor Coherent resolves as unreliably as the vertical one. Matches html/body width. */ width: 340rem; z-index: 9000; pointer-events: none; /* never steal battle input -- info-only overlay */ font-family: "MoEBattle", "Arial Narrow", sans-serif; padding: 0; /* BLOCK stacking, NOT flex-column. This alone did NOT fully fix the backdrop drift: removing the negative margin (see .mb-row) killed the big drift and block flow killed most of the rest, but a residual survived -- each lower row's backdrop still crept HIGHER than its text, and the -6rem/-6rem dual constraint let the blob collapse SHORT. Root cause of the residual: the backdrops were abspos pseudos ON each .mb-row, and .mb-row is itself display:flex, so Coherent still under-counted the per-row abspos containing-block ORIGIN (flex is the buggy subsystem -- gap unsupported, negative-margin drift) AND would not reliably stretch a box between top AND bottom. FIX: the backdrops are no longer per-row pseudos -- they are root-anchored .mb-backdrop siblings (see below) with a fixed per-index top + explicit height, so every backdrop resolves against the ONE origin that already renders row 1 correctly and nothing accumulates. Keep display:block (each .mb-row is still a flex ROW internally); do NOT move the backdrops back onto .mb-row. */ display: block; } /* One line = [icon] [value] ... . The soft dark shape behind each row is painted by a root-anchored .mb-backdrop sibling (see below), NOT by this row's pseudos -- the row only carries content and rides ABOVE the backdrops (z-index:1). PITCH VIA PADDING, NOT NEGATIVE MARGIN (bug fix): rows used to be an airy 8rem-padded box pulled together with margin-bottom:-12rem to reach WG's ~44px (21rem) pitch. In Gameface the negative margin's overlap is NOT applied identically to the in-flow numerals and to the absolutely-positioned backdrops, so each successive row's dots+shadow drifted UP relative to its text (cumulative down the stack; row 1 correct). Standards browsers align them perfectly, which is exactly why this only shows in-client. Fix: no negative margin -- the padding box IS the 21rem pitch (2rem top+bottom over the ~17rem icon/value line), so rows tile with zero overlap. The backdrops keep their size/position via the fixed .mb-bd-N tops + the +6rem #moe-battle-root nudge. */ .mb-row { position: relative; display: flex; flex-direction: row; align-items: center; white-space: nowrap; /* 2rem vertical => box height = pitch = 21rem (the old 33rem box minus the 12rem overlap); no margin-bottom, so consecutive rows abut with no overlap for Gameface to mishandle. */ padding: 2rem 32rem; z-index: 1; /* content above the z-index:0 .mb-backdrop layers */ } /* THE BACKDROPS -- root-anchored, NOT per-row pseudos (drift fix; see #moe-battle-root). One .mb-backdrop div per row, a DIRECT child of #moe-battle-root, so every backdrop's abspos containing block is the ROOT -- the single origin that already renders row 1 correctly -- with an EXPLICIT height (never a top+bottom dual stretch, which Coherent collapses short). The per-index top is a constant off the fixed 21rem pitch: row N content-centre = N*21 + 10.5, backdrop top = centre - height/2 = centre - 15 (height is now 30rem). row 1: 10.5 - 15 = -4.5 row 2: 31.5 - 15 = 16.5 row 3: 52.5 - 15 = 37.5 (JS toggles .mb-bd-3 in lockstep with the assist row) 30rem = the 21rem row box + 2*4.5rem bleed (R2 tune: was 33rem/6rem bleed). JS (ensureRoot) emits these BEFORE the rows so source order = paint order (backdrops behind the z-index:1 rows). */ .mb-backdrop { position: absolute; left: 0; width: 100%; /* resolves against #moe-battle-root's explicit 340rem */ height: 30rem; /* EXPLICIT -- no top/bottom dual anchor to collapse */ z-index: 0; } .mb-bd-1 { top: -4.5rem; } .mb-bd-2 { top: 16.5rem; } .mb-bd-3 { top: 37.5rem; } /* WG's efficiency-panel halftone = a fine CHECKER dither. Gameface does NOT tile a gradient via background-size (it renders one gradient = a smooth blob), so we tile a small RASTER checker.png sibling instead (rasters DO tile -- proven by the garage progressbar). The tile is natively FINE (4px tile = 2x2 cells at 2px) so background-size:auto paints ~2px cells directly -- WG's dither, crisp, no sub-pixel rem-scaling. opacity sets strength; image-rendering keeps cells crisp; the radial MASK fades it to a blob. Fills its parent's EXPLICIT box via width/height:100% (single anchor, no stretch). Regenerate via tools/dev/gen_checker.py. checker.png loads as a bare sibling (font/card_border scheme). */ .mb-backdrop::before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(checker.png) repeat; background-size: auto; /* native 2px cells (fine dither); subtle at opacity 0.19. rem-scaling shrank it sub-pixel -- native renders crisp in-game. */ background-position: 0px 0px; image-rendering: pixelated; opacity: 0.1; /* unprefixed mask only -- WG's own Gameface CSS uses `mask` (679x) and never `-webkit-mask`; the engine honors the standard property, so the prefix is dead weight. HORIZONTAL-STRETCH FIX (confirmed in-game, shot_012): the old 223% ray put the fade-out at ~92% of the 340rem box (~313rem), so the dither was near-uniform across the whole wide box and tailed ~150rem past even worst-case 5-digit text -- a long empty smear to the right. The box stays 340rem (fits "12,718 / 12,718" with a shift), but the dither must HUG the content: centre the fade at 20% (~68rem, over the icon + first digits) and end it at 0.32*120% = 38.4% of width (~131rem) right of centre => solid 0->~199rem, then gone. That covers the icon + a 5-digit row and drops the tail. */ /* R2 (user tune): halve the HORIZONTAL reach (120%->60% ray => fade ends ~133rem instead of ~199rem) and grow the VERTICAL radius (120%->155%) so each band is a touch taller. */ mask: radial-gradient(30% 150% at 15% 50%, #000 0%, transparent 35%); } /* Dark radial UNDERLAY -- the pre-dither backdrop shape, layered BEHIND the checker within this backdrop's local stacking context (.mb-backdrop is z-index:0). z-index:-1 drops it under the checker ::before; the whole .mb-backdrop sits under the z-index:1 rows, so text stays on top. Its own size/centre/alpha (independent of the dither); left edge soft-clipped by the mask. Tuned in the overlay tuner ("Gradient underlay" + "Left clip"). */ .mb-backdrop::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; /* HORIZONTAL-STRETCH FIX (see ::before): this dark blob used to be centred at mid-box (50% = 170rem), so its right half spilled to ~270rem and fed the same right-tail smear. Pull its centre left to 28% (~95rem, under the numbers) and tighten so it fades to nothing by 0.60*45% = 27% of width (~92rem) right of centre => ends ~187rem, matching the dither above. The left edge is still soft-clipped by the linear mask below. */ /* R2 (user tune): match the dither -- halve horizontal reach (45%->22%) + taller (55%->72%). */ background: radial-gradient(32% 73% at 22% 53%, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 60%); mask: linear-gradient(90deg, transparent 13%, #000 22%); } /* Icon glyph + glow. is clipped in Gameface -> background-image divs. The icon box is now a TRANSPARENT, positioned container: the GLYPH rides on ::after (painted on top) and the gold GLOW is a background element on ::before behind it -- a radial gradient in the glow colour, replacing the old drop-shadow (which Gameface rendered unevenly). An element's own background always paints BELOW its pseudos, so the glyph cannot stay on .mb-ico if the glow is to sit behind it -> the glyph moves to ::after (img:// URL per row) and the glow to ::before. The transform keeps .mb-ico a stacking context so ::before's z-index:-1 stays scoped here. Tuned in the overlay tuner (tools/dev/gen_overlay_tuner.ps1). */ .mb-ico { display: block; flex: none; position: relative; width: 17rem; height: 17rem; margin-right: 4rem; transform: translate(0rem, 1rem); /* nudge onto the numeral baseline */ } /* Gold glow behind the glyph: a radial gradient of the glow colour (#FFCD5A). Box is a touch larger than the icon and centred; z-index:-1 drops it under the ::after glyph. */ .mb-ico::before { content: ""; position: absolute; left: 50%; top: 50%; z-index: -1; width: 18rem; height: 18rem; transform: translate(-50%, -50%); background: radial-gradient(circle at 50% 50%, rgba(255, 205, 90, 0.5) 0%, transparent 73%); } /* The glyph, on top of the glow. The quest_type/128 glyphs fill only ~23% of the PNG (transparent padding), so zoom to 260% to crop it; brightness() lifts the ~#c8c8c8 grey line-art toward white. Per-row art set below -- img:// resolves game art (same scheme the garage mark glyph uses). */ .mb-ico::after { content: ""; position: absolute; left: 0; top: 0; right: 0; bottom: 0; background-repeat: no-repeat; background-position: center; background-size: 260%; filter: brightness(3); } .mb-ico.dmg::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_barrel_mark.png); } .mb-ico.pct::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_improve.png); } /* Row 3 assist glyph -- switched by the leading stream (JS toggles trk/spot/stun on .mb-ico.ast). Base is the generic assist icon (used in the rare pre-split merged-fallback case, kind 'assist'); the per-kind rules (3 classes) win by specificity. */ .mb-ico.ast::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_assist.png); } .mb-ico.ast.trk::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_assist_track.png); } .mb-ico.ast.spot::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_assist_radio.png); } .mb-ico.ast.stun::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_assist_stun.png); } /* Inter-element gap (icon->value handled by the icon's own margin above). */ .mb-sep, .mb-value.mb-avg, .mb-delta { margin-left: 4.5rem; } /* The number: bright white, layered soft shadow (no stroke) so it reads over both bright and dark map areas -- matches the panel's white numerals + their soft drop shadow. */ .mb-value { font-size: 14rem; font-weight: 600; color: #ffffff; letter-spacing: 0; text-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.5); } /* Dim slash between live damage and projected average. */ .mb-sep { font-size: 14rem; font-weight: 600; color: rgba(237, 230, 217, 0.45); text-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.5); } /* Signed delta (in parens) rides small next to the projected percent; white by default. */ .mb-delta { font-size: 14rem; font-weight: 600; color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.5); } /* Sign is carried by a COLORED GLOW, not a text fill: the numerals stay WHITE and a green/red halo (text-shadow) signals the sign, layered OVER the dark legibility drop so the numbers still read over bright AND dark map areas. Applies to the live-damage value (row 1, vs projected avg) AND the signed delta NUMBER (row 2, .mb-delta-num) -- but NOT the delta's surrounding parens, which are static markup on .mb-delta and stay white. Neutral/at-par has no .mb-up/.mb-down class -> plain white + dark drop only, no glow. */ .mb-value.mb-up, .mb-delta-num.mb-up { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.5), /* dark legibility drop (matches base) */ 0rem 0rem 6rem rgba(123, 236, 55, 0.9), /* green glow (#7BEC37) wide pass */ 0rem 0rem 1rem rgba(123, 236, 55, 0.9); /* tight core pass */ } .mb-value.mb-down, .mb-delta-num.mb-down { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.5), 0rem 0rem 6rem rgba(211, 68, 63, 0.9), /* red glow (#D3443F) wide pass */ 0rem 0rem 1rem rgba(211, 68, 63, 0.9); /* tight core pass */ } PK!o&&8res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.js// 14th_ua's MoE Calculator -- in-battle overlay. This JS is the front-end of a // STANDALONE OpenWG-registered Gameface view (MoEBattleView.html, registered via // mods/configs/res_map/MoEBattleView.json) that the Python side opens as a // CONTENT-SIZED (NOT full-screen), input-transparent top-layer window OVER the battle // HUD (bridge/battle_view.py -- WINDOW_FULLSCREEN was dropped so the window hugs the // overlay and can't hit-test across the whole HUD; do NOT re-add full-screen sizing or // width:100%, it reintroduces the Ctrl+click/hover input-steal). The battle HUD has no // shared full-screen Gameface document to inject a position:fixed overlay into (each WG // battle Gameface view is composited by Flash at its own placeId), so we host our own // window instead. // // Because this is a registered view, OUR data model (BattleMoEVM) IS the view's own // root ViewModel -- we read it with a root ModelObserver() (no feature name) and read // the fields DIRECTLY off the root (model.combinedDamage, ...), NOT via a nested // `moeBattleData` submodel. // // LOOK: mirrors WG's own personal-efficiency panel (damage dealt / blocked / assisted) // -- a left-aligned vertical stack of [icon] [white value] rows over a soft // dark->transparent gradient, NO text labels, NO frame. See dmg_panel reference. // row 1: live combined damage / projected avg combined dmg (icon: damage) // -> the live damage is RED when below the projected average, WHITE when // equal, GREEN when above (are you out-performing your own projection?). // row 2: projected MoE percent (signed delta vs pre-battle standing) (icon: mark) // -> the delta is RED when negative, WHITE at zero, GREEN when positive. // // pointer-events:none throughout -- the overlay is pure HUD info and must never // intercept battle input. See the wotmod-gameface-widget harness skill for the // DOM/CSS conventions + Coherent quirks; mirrors MoECalculator.js. import { ModelObserver } from "../../libs/model.js"; // Icon art now lives in MoEBattle.css: the glyph is painted on `.mb-ico::after` (per-row class // `dmg`/`pct`, img:// background-image) so the gold glow can sit BEHIND it on `.mb-ico::before` // (an element's own background always paints below its pseudos). Swap the glyph art in the CSS. // No feature name -> observe this view's OWN root model (window.model == BattleMoEVM). const observer = ModelObserver(); // Group an integer with thousands separators: 2910 -> "2,910". function thousands(n) { n = Math.max(0, Math.round(Number(n) || 0)); return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Truncate toward zero to 2 decimals -- the shared display precision for both the percent // and the delta. A sub-precision magnitude (e.g. 0.004) collapses to exactly 0 so it never // carries a misleading sign or colour that its "0%" text contradicts. function trunc2(p) { p = Number(p) || 0; const mag = Math.floor(Math.abs(p) * 100) / 100; return p < 0 ? -mag : mag; } // Percentile float -> "84.73%" (two decimals, TRUNCATED not rounded); <=0 at precision -> "0%". // Truncate so the readout never overstates progress toward a mark threshold. function pctText(p) { const v = trunc2(p); if (v <= 0) return "0%"; return v.toFixed(2) + "%"; } // Signed delta NUMBER -> "+0.41%" / "-1.20%"; zero AT DISPLAY PRECISION -> "0%". Two decimals, // TRUNCATED (matches pctText) so the delta never overstates a mark gain and a sub-precision // value reads "0%" with no sign. The surrounding parens are STATIC markup (see ensureRoot) and // stay white -- only this number carries the sign colour. function signedPct(p) { const v = trunc2(p); if (v === 0) return "0%"; return (v > 0 ? "+" : "-") + Math.abs(v).toFixed(2) + "%"; } // Tri-state colour by sign: >0 green (mb-up), <0 red (mb-down), 0 white (neither class). function colourBySign(el, sign) { el.classList.toggle("mb-up", sign > 0); el.classList.toggle("mb-down", sign < 0); } // Build the root element once and cache it. function ensureRoot() { let root = document.getElementById("moe-battle-root"); if (root) return root; root = document.createElement("div"); root.id = "moe-battle-root"; root.innerHTML = // Backdrops FIRST (source order = paint order): one root-anchored .mb-backdrop per row, // behind the z-index:1 rows. They are siblings of the rows (NOT .mb-row pseudos) so each // resolves against the ONE root origin -- the fix for the per-row abspos drift; see the // CSS. .mb-bd-3 is toggled with the assist row in render(). '
' + '
' + '
' + // Row 1: [dmg icon] / '
' + ' ' + ' ' + ' /' + ' ' + '
' + // Row 2: [mark icon] () '
' + ' ' + ' ' + ' ()' + '
' + // Row 3 (optional): [assist icon] . The icon switches with the // leading stream (track/spot/stun); gated by the setting + hidden while the total is 0. '
' + ' ' + ' ' + '
'; document.body.appendChild(root); return root; } function render(model) { const root = ensureRoot(); // In a registered view the observed model IS our BattleMoEVM root -- read fields // directly off it (no nested `moeBattleData` submodel, no unwrap needed for scalars). const data = model; // Hidden until Python confirms combat is live AND the per-tank threshold table is // loaded (metrics 2-4 need it; without it the readout is meaningless). Truthy guard so a // root VM whose visible/hasData are still undefined (before Python's first push) hides // rather than painting a "0 / 0 -- 0%" stub over the HUD. if (!data || !data.visible || !data.hasData) { root.style.display = "none"; return; } root.style.display = ""; const cd = data.combinedDamage || 0; // Live combined damage is ALWAYS meaningful -- even in a replay with no baseline -- so it // is shown exactly, no approximation indicator. const cdEl = root.querySelector(".mb-cd"); cdEl.textContent = thousands(cd); const deltaNum = root.querySelector(".mb-delta-num"); // Without a CAREER baseline (replay / relogin straight into battle -- the garage dossier // was never read; BUG B) the projected avg, percent and delta are all collapsed and // meaningless. Dash them out and drop the sign colours, keeping only the live CD. An absent // flag (older Python push) is treated as "baseline present" so the normal render is unchanged. if (data.hasBaseline !== false) { const avg = data.projAvgDamage || 0; root.querySelector(".mb-avg").textContent = thousands(avg); // Live damage vs your own projected average: red below, white at par, green above. colourBySign(cdEl, cd - avg); root.querySelector(".mb-pct").textContent = pctText(data.curPercent || 0); // Truncate to display precision FIRST so the sign, colour and text all agree: a // sub-precision delta reads "0%" in white, never a green "+0.00%". const delta = trunc2(Number(data.pctDelta) || 0); // Colour only the number; the parens on .mb-delta stay white. deltaNum.textContent = signedPct(delta); // Delta vs pre-battle standing: green improves, red drags, white unchanged. colourBySign(deltaNum, delta); } else { const DASH = "-"; // hyphen: value unknown without a baseline (the // subset MoEBattle.ttf has "-" but no em-dash) root.querySelector(".mb-avg").textContent = DASH; colourBySign(cdEl, 0); // nothing to compare CD against -> white root.querySelector(".mb-pct").textContent = DASH + "%"; deltaNum.textContent = DASH; colourBySign(deltaNum, 0); // no sign -> white } // Row 3: counted assistance = the higher of tracking / spotting / stun this battle, with an // icon for whichever leads. Independent of the baseline (live server data, like the CD). // Shown only when the "Enable Counted Assistance" setting is on (data.assistVisible) AND the // total is > 0 -- the row stays hidden until any assist is earned. An absent flag (older // Python push) is falsy -> row stays hidden. const assistRow = root.querySelector(".mb-row-assist"); const bd3 = root.querySelector(".mb-bd-3"); // its backdrop, toggled in lockstep const counted = data.countedAssist || 0; if (data.assistVisible && counted > 0) { assistRow.style.display = ""; bd3.style.display = ""; root.querySelector(".mb-ast").textContent = thousands(counted); const ico = assistRow.querySelector(".mb-ico"); const kind = data.assistKind || ""; ico.classList.toggle("trk", kind === "track"); ico.classList.toggle("spot", kind === "spot"); ico.classList.toggle("stun", kind === "stun"); } else { assistRow.style.display = "none"; bd3.style.display = "none"; } } engine.whenReady.then(() => { observer.onUpdate(render); observer.subscribe(); render(observer.model); }); PK!)l 9res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.ttf  OS/2QW(`cmapLglyf)H3Hhead25?l6hheab$hmtx2.Hloca F*maxp} nameJ post po[3_<r4tmm(4|MOE 9(( 0fhh\;D:!:T0X[Xd\b\8  %)9 %(+MmRm*alf +3! ! ! ! "'&547632"'&547632^%%%$55g55f=uu\55oo55B55oo553&'&54767#`;$$$$As//34Z}yb\367654'&#bn43//sA$$$$o͠x; 3!5!#!Vf[\D;3Z)!w!!w3B3]iTK476767632#"'&'&'&"32767676554'&'&'&'&'&o 33  33 uVV/! )nZZ4) /)IIȚbbAA AAbbbbAA A@dc}((H1;;FFRRpyVKK@A66-{22cPlm}XXHG98+% !#676HEFH4;;mR67%%X$!5!676767654'&#"!&545432XB}bbDC$$kj˾dc{7׏||nncc\[[`a !!=[D!!27654'&'67654'&#"!547632##2763#"'&{ih,+yb++[[__3u ,,D =)) DF ij٪TTMM\\PP R++B)) 00No33//X!6767!35#!9!+mmPQQV+7d!!!276'&#"!5!!632#"cbBAH56- 3bHLiPxwrs/bȓBAFG\7%"'&547632!54'&#"276!"&54547632FJH$abh4 //PP}dcN87)HfDCA@DCA@SS^ٻQQ''}})+))#ABs!5!^BR b'3! 4'&'67654'&#""547632"'&54325b9867fb-.baab.-)##;7""{<m/#]^b`_#NNa`__NNӇ>==>22i//\\92#"'&5476!32767654'&'&'&#"32767#"FJH%cch4 //PP}dcKKN98)J`ED@ACBBC9SS^׮RR''}}mn))$%#BCf      "  MoEBattleRegularMoEBattleRegularPK!Z>res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattleView.html MoEBattleView PK!v~~=res/gui/gameface/mods/14th_ua/MoECalculator/MoECalculator.css/* 14th_ua's MoE Calculator widget. Uses WoT's native Gameface palette by VALUE (PFDINMax font + parchment/gold hex). We do NOT use var(--color-*) custom properties: Gameface's CSS engine drops a whole declaration when it can't resolve a var() (ignoring the fallback), which renders elements invisible. SIZING is all in rem: the engine sets the hangar doc's root font so 1rem == interfaceScale px (measured via the S1 probe: 1px @1x, 2px @2x), i.e. rem IS WG's own logical layout unit, so the box + bar scale with the interface. Both ANCHOR AXES are RESOLUTION-INVARIANT (they depend only on the interface scale, NOT on the viewport/resolution), matching WG's own UI which renders at a fixed device-px size per interface scale (verified live at 1080p, 1440p, 4K -- all Auto): X (right: rem) tracks the vehicle-info column's right edge, which is SCALE-tracking (logical): 46rem = 46px @1x, 92px @2x. Verified across scale + resolution. Y (bottom: calc(R rem + 18.33vh - 134px), with an @media (min-height:1440px) override to calc(R rem + 130px)) clears the carousel top. It is a BLEND of a scale term (R rem = R*remPx px, remPx = interfaceScale px) and a PLATEAUED VIEWPORT term (18.33vh = 18.33% of innerHeight below ih=1440; frozen at its ih=1440 value of 264px at/above, via the media query) plus a fixed -134px const -- see the #moe-root Y note for the calibrated law. Unlike X, Y is genuinely RESOLUTION-dependent below the plateau: the carousel sits a fixed FRACTION down the screen, so the gap grows with viewport height -- UNTIL ih>=1440, where the @media plateau freezes the viewport term so the gap STOPS growing (4K@x1 gap == 1440p@x1 gap). The law was fitted LIVE to measured widget-bottom -> screen-bottom gaps: 1080p@x1(remPx=1,ih=1080)=302px, 1440p@x1(remPx=1,ih=1440)=368px, 4K@x2(remPx=2,ih=2160)=606px, and by the plateau 4K@x1(remPx=1,ih=2160)=368px (IDENTICAL to 1440p@x1). The rem coefficient (not a fixed px) is REQUIRED so the scale term doubles at x2 (R*2 px) -- that is what lets the law reach 606 at 4K. This pairs with the JS size-law clamp (LVP_CAP=1440) so 1440p@x1 and 4K@x1 render at the IDENTICAL size AND gap. History: pure vw/vh -> a `calc(+140px)` hybrid -> an 18.33vh rem+vh blend -> pure rem (overshot x1) -> a two-point rem + 7.5vh blend -> a resolution-invariant two-point rem+162px law (frozen the vh term to 4K device px -- but that made the widget drift at non-4K because the carousel is viewport-relative, NOT resolution-invariant) -> a live-calibrated rem+17.78vh law (gaps 304/368/606) -> a three-point-exact rem+26.11vh-58px law (rows2 pinned in-game; single/small transferred by their content-height rem offset) -> an intermediate plateaued rem+26.11vh-246px law -> THIS two-point rem + 18.33vh - 134px law, 1080p=302, continuous to the 368 plateau at ih=1440, with the @media (min-height:1440px) freeze that holds the viewport term at its ih=1440 value so 4K@x1 collapses onto 1440p@x1 -- an @media split, NOT CSS min(), because min() is never used in WG's Gameface stylesheets and did not parse (see the #moe-root Y note). Y is a genuine blend -- do NOT collapse it to a single unit and do NOT restore the frozen-px or pure-rem coefficients. The engine reflows both units live. Layout: a horizontal percentile bar (0..100) anchored bottom-right, above the carousel, styled like the garage's top-right Battlepass chapter-progress widget. Three milestone ticks (65/85/95) carry the nation mark art ON TOP of the bar and the damage requirement BELOW; a top-left readout shows current avg damage + percentage. */ /* DRAG-TO-REPOSITION (see MoECalculator.js installDrag / applyPosition). #moe-root has TWO anchor modes, switched at runtime via INLINE styles (CSS supplies only the AUTO default): AUTO (unpinned, posX/posY == 0): the calibrated bottom-right anchor below (right/bottom + transform-origin 100% 100% set by applyWidgetScale). No inline left/top. This is the default look -- do NOT regress it, and keep the Y blend intact (see the Y note below). PINNED (Ctrl+drag, posX/posY > 0): JS sets inline transform-origin:0 0, right:auto, bottom:auto, and left/top px. With origin 0 0 the scaled box's top-left equals left/top, so drag/clamp math is predictable under transform:scale(k). No CSS rule is needed for the pin -- inline styles win -- so nothing here changes; this note is the JS<->CSS contract. */ #moe-root { position: fixed; /* Bottom-right, above the carousel. X and Y use DIFFERENT units (see file header). Both are RESOLUTION-INVARIANT (depend only on interface scale, not viewport), like WG's UI. X: right 46rem -- the vehicle-info column's right edge is scale-tracking. Verified. Y: bottom calc(R rem + 18.33vh - 134px), with an @media (min-height:1440px) block that overrides it to calc(R rem + 130px) -- a LIVE-CALIBRATED BLEND of a scale term, a PLATEAUED VIEWPORT term, and a fixed px const. 1rem = interfaceScale px (remPx), so R rem = R*remPx px (R px @x1, 2R px @x2); 18.33vh = 18.33% of innerHeight below ih=1440, frozen at its ih=1440 value (264px, i.e. 264-134 = +130px net) at/above via the media query; -134px is a resolution/scale-invariant offset. Y is RESOLUTION-dependent (unlike X) below the plateau: the carousel top sits a fixed FRACTION down the screen, so the gap grows with the viewport UNTIL ih>=1440, where the @media plateau freezes the viewport term and the gap stops growing. interfaceScale is power-of-two gated (x2 only at height>=1536), so 1080p and 1440p are BOTH x1 while 4K is x2 -- which means 4K@x1 (Auto never picks it, but a MANUAL x1 at 4K, or any ih>=1440 @x1) lands on the SAME gap as 1440p@x1. THE LAW (fitted to measured widget-bottom -> screen-bottom gaps, rows2 state): model bottom = R*rem + 18.33vh - 134px below ih=1440; R*rem + 130px at/above ih=1440 (the @media block; 130 = 264-134, the vh term frozen at its ih=1440 value). Target gaps: 1080p@x1(remPx=1,ih=1080)=302px, 1440p@x1(remPx=1,ih=1440)=368px, 4K@x2(remPx=2,ih=2160)=606px, and (by the plateau) 4K@x1(remPx=1,ih=2160)=368px==1440p@x1. TWO-POINT FIT (rows2, x1): the base slope + const come from the two x1 gaps at differing viewport heights -- 302 at ih=1080 and 368 at ih=1440 -> slope = (368-302)/(14.4-10.8) = 66/3.6 = 18.33vh; const = 302 - (238 + 18.33*10.8) = -134px. The 4K@x2=606 point is then reached purely by the doubled rem term (2*238=476 device px @x2, added to the frozen plateau's +130). Check (base, ih<1440): 1080p 238+198-134=302; 1440p 238+264-134=368. Check (@media, ih>=1440): 1440p 238+130=368; 4K@x1 238+130=368; 4K@x2 476+130=606. Boundary continuous (at ih=1440 the base 18.33vh=264 also gives 368, so no jump). All EXACT. Per carousel state R differs by content height; single/small preserve their prior inter-state rem offset off the rows2 R: rows2 (pinned live): R=238 (-134px const, shared) single-row: R=211.5 (rows2 R - 26.5, its old A offset) small: R=195 (rows2 R - 43, its old A offset) Pairs with the JS size-law clamp (LVP_CAP=1440): 1440p@x1 and 4K@x1 render at the IDENTICAL size AND gap. Do NOT collapse Y to a single unit and do NOT restore the frozen-px or pure-rem values. WHY @media, not min(): CSS min() is NEVER used in WG's own Gameface stylesheets (grep of the packed gui-part*.pkg CSS: 0 min()/max()/clamp() vs 267 calc()) and did NOT reliably parse on this Coherent/Gameface build, so the vh cap is expressed as a plain @media (min-height:1440px) plateau instead -- @media IS heavily used by WG (118 occurrences, incl. min-height queries), so it is safe. RETUNE: the vh term (+ its 130px frozen plateau) and the -134px const are shared by all three states; R (rem) differs per carousel height. To adjust, re-pin rows2 live (fit R + vh to two measured gaps at differing viewport heights, one at each scale), rebase the plateau (130 = 18.33*ih_cap/100 - 134 with ih_cap the media-query threshold), then transfer single/small by their rem offset. Verify live at both x1 and x2. */ right: 46rem; bottom: calc(211.5rem + 18.33vh - 134px); /* single-row (rows=1) -- R=211.5 (rows2 R 238 - 26.5 offset); ih>=1440 plateau in @media below */ width: 315rem; /* content width; matched to the missions-panel box width (was 360 -- box read ~13% wider than the reference) */ /* 9001 = one above the common 9000 baseline other injected garage widgets use. Where our VISIBLE footprint overlaps another equal-z (9000) widget's transparent overhang, this makes OUR footprint the topmost PAINTED element there -- so the drag ownership hit-test (root.contains(e.target) in MoECalculator.js) resolves e.target to us at those pixels, matching visual stacking deterministically instead of depending on DOM/mount order. */ z-index: 9001; /* EXACTLY the missions widget's face: the client's user_missions global.css sets `font-family: PFDINMax; letter-spacing: 0.02em` on its body -- PFDINMax is the condensed numeric face registered globally from gui/gameface/fonts/pfdinmax/, so it resolves in the hangar document too. Warhelios kept as a fallback. */ font-family: PFDINMax, "PF DIN Max Compressed", "Warhelios", sans-serif; letter-spacing: 0.02em; color: #ede6d9; /* Capture the pointer on the box FOOTPRINT so it can react to :hover -- this powers the box's own hover polish (#moe-root:hover brightens the fill + fades the border into one flat panel; and, when re-enabled, the hover tooltip). :hover only fires on an element that RECEIVES pointer events, so this MUST stay `auto` for the hover visual to work at all -- do NOT set it to `none` (that silently kills the hover styling below). The box floats over largely-dead hangar space above the carousel, and every overlay child that extends past the box (.moe-ticks, .moe-end*, .moe-cur-marker) stays pointer-events:none, so only the panel footprint captures -- a drag-to-rotate/click that starts off the box is untouched. */ pointer-events: auto; /* WoT "card" panel: a faint dark fill + a thin warm-parchment hairline border and a subtle inner shadow that darkens the fill from the edges inward (tuned in the MoE box tuner). Replaces the old card_border.png 9-slice frame (::before, now removed). Symmetric 18rem side padding so the bar spans the full panel width. The box is bottom-anchored (see `bottom` above), so trimming the bottom padding (9->8rem) also lowers the bar ~1rem on screen (content bottom = box bottom - padding-bottom). */ padding: 11rem 18rem 8rem 18rem; background: rgba(10, 10, 10, 0.25); border-radius: 0.5rem; border: 1rem solid rgba(254, 235, 190, 0.1); box-shadow: inset 0rem 0rem 1rem 0rem rgba(0, 0, 0, 0.33); /* Hover brightens the fill to the border tone and fades the border-color out so the two merge into one flat panel (see #moe-root:hover). */ transition: background 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease; } /* The old card_border.png 9-slice frame (#moe-root::before) was replaced by the thin CSS `border` + inner `box-shadow` on #moe-root above. card_border.png is no longer referenced by the garage widget (still bundled beside this CSS; harmless). */ /* Whole-box hover: brighten the fill to the border's warm-parchment tone AND fade the border-color to transparent so the two become one flat panel with no visible rim. (At rest the border stacks ON TOP of the fill, so the edge composites to ~2x the fill's alpha -- that seam is why the border stayed visible when both were rgba(254,235,190,0.1); dropping the border-color removes the stack.) The dark inner shadow fades out too so the warm tone reads cleanly. All three crossfade via the transition on #moe-root above. */ #moe-root:hover { background: rgba(254, 235, 190, 0.1); border-color: transparent; box-shadow: inset 0rem 0rem 1rem 0rem rgba(0, 0, 0, 0); } /* Responsive lift: raise the bar to clear a taller carousel. A double row is taller than a single row; the small (shorter) double-row tiles need less lift than the tall adaptive tiles. .moe-small must follow .moe-rows2 in source order so it wins. Same rem + 18.33vh - 134px law as #moe-root bottom (shared vh term + -134px const; rem R differs per carousel height -- rows2 R=238 pinned live, see the Y note for the derivation + the @media (min-height:1440px) plateau that makes 4K@x1 land on 1440p@x1). */ #moe-root.moe-rows2 { bottom: calc(238rem + 18.33vh - 134px); } /* base (ih<1440); ih>=1440 plateau in @media below. gap 302/368/368/606 @1080x1/1440x1/4Kx1/4Kx2 (R=238, 18.33vh, -134px const) */ #moe-root.moe-rows2.moe-small { bottom: calc(195rem + 18.33vh - 134px); } /* R=195 (rows2 R 238 - 43 offset) */ /* ih>=1440 plateau: freeze the viewport term at its ih=1440 value (18.33vh=264px), so bottom = R rem + (264-134) = R rem + 130px. WG's Gameface CSS never uses min()/max()/clamp() (0 uses across the packed gui-part*.pkg CSS vs 267 calc()), so the cap is a @media split rather than the unsupported min(18.33vh,264px). @media itself is heavily used by WG (118 occurrences, incl. min-height queries) -> safe. Must FOLLOW the base anchors in source order so it wins at ih>=1440 (each selector matches its base rule's specificity exactly); boundary is continuous (at ih=1440 the base 18.33vh=264 yields the same 368, no jump). All 3 states. */ @media (min-height: 1440px) { #moe-root { bottom: calc(211.5rem + 130px); } #moe-root.moe-rows2 { bottom: calc(238rem + 130px); } #moe-root.moe-rows2.moe-small { bottom: calc(195rem + 130px); } } /* --- current readout, sitting right on top of the bar ---------------------- */ /* Anchored just above the track's left end (like the Battle Pass "Stage 1" caption) rather than in a header row -- otherwise the icon band above the bar pushes it far away. Absolute vs. the root PADDING box, so offsets include the root padding: bottom = root pad-bottom (9) + body pad-bottom (22) + track (3) + 3rem gap = 37rem; left = root pad-left (18) to align with the track's left edge. The leftmost milestone is at 65%, so the space above the left is clear. */ #moe-root .moe-head { position: absolute; left: 18rem; bottom: 37rem; display: flex; align-items: baseline; justify-content: flex-start; z-index: 1; /* above the hover overlay (::after, z-index 0) */ } /* Current average combined damage + current mark percentage. Shadow matched to WG's top-right garage widgets (Battle Pass / missions cards), which use NO text-stroke -- every outline there is layered text-shadow. WG's plain card numbers use a single hard dark drop `0 1rem 0 rgba(13,14,16,0.4)`; we keep that and ADD one restrained blur `0 0 3rem rgba(0,0,0,0.55)` as a deliberate float-context deviation (WG's numbers sit on an opaque dark box; ours float over the live hangar and need a little more contrast than WG's blur-less drop -- but far lighter than the old 4rem/0.9 halo). This styles the damage number only; the current-% readout (.moe-cur-pct) is a separate below-bar element. */ #moe-root .moe-cur { font-size: 16rem; font-weight: 400; /* thin numeric face, matching the mark requirement labels */ text-shadow: 0 1rem 0 rgba(13, 14, 16, 0.4), 0 0 3rem rgba(0, 0, 0, 0.55); } #moe-root .moe-cur-dmg { color: #ede6d9; } /* the current value reads white */ /* Damage glyph to the RIGHT of the current-damage number: the personal-missions "battle condition: damage" glyph (user pick), painted as a background-image div (Gameface clips ). The source is SQUARE (64x64), so the box is square to avoid distortion; sized a touch above the 16rem readout and nudged onto the text baseline. img:// resolves game art here, same as the mark glyphs. */ #moe-root .moe-cur-icon { display: inline-block; width: 22rem; height: 22rem; margin-left: 0rem; /* small gap to the RIGHT of the number (the zoomed glyph also carries transparent padding on its left, so the visual gap is a touch wider than this) */ vertical-align: -5rem; /* drop onto the number's baseline */ /* 128px source of the same glyph, zoomed past its transparent padding so the visible glyph fills the box (the 64x64 source only filled ~23% at background-size:contain, so growing the box left the glyph tiny). We use the quest_type/128 variant, NOT the battleCondition/128 one: the latter is crisper-looking only because it bakes in a soft radial glow, which the 260% zoom amplifies into a murky haze behind the glyph. The quest_type source is the same 28x28 glyph on FULLY transparent -- clean at any zoom. background-position:center crops the transparent padding away symmetrically. */ background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_damage.png); background-repeat: no-repeat; background-position: center; background-size: 260%; } /* Current-percent readout, used as the LAST TICK's TOP LABEL: it sits in the icon band above the bar's 100% end (the goalpost), replacing the old static "100%" caption. The damage number stays in the top-left .moe-head. Absolute vs. the track, right-aligned to the 100% tick (translateX(-100%)) with the same 2rem nudge as the 100% damage number below it, so the top label + damage number stack against the bar's right edge. Plain parchment white (like the whole widget); the shadow is the same dark legibility drop the mark numbers use (no coloured glow). */ #moe-root .moe-cur-pct { position: absolute; bottom: 6rem; /* icon band, just above the track (matches .moe-tick-icon) */ left: 100%; /* the bar's 100% end (last tick) */ transform: translateX(-100%); /* RIGHT-aligned to the tick, like the 100% damage number */ margin-left: 2rem; /* same 2rem nudge as the 100% damage number below */ font-size: 15.5rem; /* 0.5rem under the readout's 16rem */ font-weight: 400; color: #ede6d9; white-space: nowrap; text-shadow: 0 1rem 0 rgba(13, 14, 16, 0.4), 0 0 3rem rgba(0, 0, 0, 0.55); z-index: 3; pointer-events: none; } /* The current-percent readout is plain parchment white (#ede6d9 == WG --color-general-primary, the exact colour WG's own daily-mission / Battle Pass widgets use for their value text) at every percentile -- the earlier per-zone colour bands (gold/teal/purple) were dropped. .moe-cur-pct already defaults to #ede6d9 in its base rule. The dot fill itself is NOT this colour: it paints WG's filled_pattern texture directly (below) so its warm-greige dots match the daily/Battle Pass bars pixel-for-pixel. */ /* --- bar body: room above for icons, below for requirement labels ---------- */ #moe-root .moe-body { position: relative; padding-top: 23rem; /* room for the (now smaller) nation mark art -- trimmed 3rem from 26 to shrink the box's overall height while leaving #moe-root padding untouched (box is bottom- anchored, so the top edge drops; mark art stays put, it's bottom:6rem above the track) */ padding-bottom: 22rem; /* room for the requirement labels below */ z-index: 1; /* above the hover overlay (::after, z-index 0) */ } /* Dotted track = the Battle Pass progress bar's EXACT dim texture. WG's own `ProgressBar` (mono/battle_pass/lib/lib.css, small variant) paints the unreached remainder with the client art `bg_pattern_small.png` (a 99x2 strip: 2px dash + 1px gap = 3px period, colour rgb(236,230,218) @ alpha 41), tiled repeat-x at `background-size: 99rem 2rem`. We reference the very same texture via img:// (the scheme background-image honours -- same as the mark glyphs) so the bar matches WG pixel-for-pixel. No frame/channel -- it floats over the hangar like the reference. */ #moe-root .moe-track { position: relative; height: 2rem; /* just the dot-strip height -- a taller channel left a thick dark band above/below the dots (read as a fat border); the dark backing belongs only BEHIND the dots */ /* Semi-dark backing gives the dots contrast (they were invisible over a bright hangar) plus a single thin outline about as thick as the grid itself. */ background-color: rgba(13, 14, 16, 0.45); background-image: url(img://gui/maps/icons/ui/progressbar/bg_pattern_small.png); background-repeat: repeat-x; background-size: 99rem 2rem; background-position: left center; box-shadow: 0 0 0 1rem rgba(13, 14, 16, 0.5); } /* Reached portion: WG's bright fill texture `filled_pattern_small.png` (same 99x2 / 3px-period grid, colour rgb(182,174,165) at ~90% alpha -- reads brighter purely by being more opaque than the track). Same texture size + left origin as the track, so the dots stay in phase as the fill grows. Eases on value/vehicle change; Gameface that drops the transition just cuts instantly. */ #moe-root .moe-fill { position: absolute; top: 0; bottom: 0; left: 0; /* WG's bright fill dots, rendered EXACTLY as the client's own daily-mission / Battle Pass bars render them: paint `filled_pattern_small.png` DIRECTLY as a background-image (WG's Filled component sets the fill background transparent and lets this texture supply the colour -- mono/user_missions + mono/battle_pass `.Filled_pattern` / `.Filled_fill`). The texture's baked warm-greige (~rgb(182,174,165) @ ~90% alpha, reading ~rgb(180,172,163) on the dark backing) IS the match; we previously masked #ede6d9 over it, which rendered ~rgb(216,209,197) -- markedly whiter than WG. No mask, no colour tint -> pixel-for-pixel. Same 99x2 size + left origin as the track, so the bright dots sit exactly on the track's dim dots and stay in phase as the fill grows; the transparent gaps show the track's dark backing, just like WG. (Mirrors the .moe-track rule, which paints bg_pattern_small the same way and renders correctly in the hangar -- so this texture loads too.) */ background-image: url(img://gui/maps/icons/ui/progressbar/filled_pattern_small.png); background-repeat: repeat-x; background-size: 99rem 2rem; background-position: left center; transition: width 0.3s ease; z-index: 1; } /* Axis end-cap at 100% (top of the percentile axis, beyond the 65/85/95 milestones). Not a data tick -- there is no 4th mark -- just a static goalpost (a faint upright divider + caption) positioned at the bar's right edge. The label is pulled left so it doesn't overflow the panel. */ #moe-root .moe-end { position: absolute; top: -2rem; bottom: -2rem; left: 100%; width: 1rem; margin-left: -0.5rem; background: rgba(236, 230, 218, 0.45); z-index: 2; pointer-events: none; } /* 100% goalpost damage number: on the same below-bar row as the mark numbers (top:6rem). The lone exception to the centred-on-tick rule -- RIGHT-aligned to the 100% tick (so it extends LEFT instead of overflowing the panel at the bar's very end) with a +4rem rightward nudge. Faint, like an unreached mark requirement. */ #moe-root .moe-end-label { position: absolute; top: 7rem; /* 1rem clear of the track (matches .moe-tick-req) */ left: 100%; /* bar's right edge (100% tick) */ transform: translateX(-100%); /* RIGHT-aligned to the tick */ margin-left: 2rem; /* nudged 2rem right */ font-size: 12rem; color: rgba(216, 207, 191, 0.45); white-space: nowrap; text-shadow: 0 1rem 0 rgba(13, 14, 16, 0.4), 0 0 3rem rgba(0, 0, 0, 0.55); z-index: 3; pointer-events: none; } /* Current-position leading-edge marker (mimics the Battle Pass in-chapter edge): a bright sliver with a soft white bloom. box-shadow only renders on a FILLED box, hence the solid background. JS sets `left`. */ /* Leading-edge marker: hidden to match the reference bar, which has no marker -- the dotted fill just transitions bright->dim at the current value. JS still positions it, so re-enabling is a one-line change. */ #moe-root .moe-cur-marker { display: none; position: absolute; top: -1rem; bottom: -1rem; width: 2rem; margin-left: -1rem; background: rgba(255, 255, 255, 0.85); box-shadow: 0 0 5rem rgba(255, 245, 210, 0.7); transition: left 0.3s ease; z-index: 2; pointer-events: none; } /* --- milestone ticks (65/85/95) -------------------------------------------- */ #moe-root .moe-ticks { position: absolute; left: 0; right: 0; top: 0; height: 100%; z-index: 3; pointer-events: none; } /* One tick, horizontally centered on its percentile position (JS sets `left`). */ #moe-root .moe-tick { position: absolute; top: 0; height: 100%; transform: translateX(-50%); } /* Nation mark art ON TOP of the bar. Dim + desaturated when not yet earned; full color with a gold bloom when reached. drop-shadow (hugs the art alpha) not box-shadow. */ #moe-root .moe-tick-icon { position: absolute; bottom: 7rem; /* 1rem clear of the track top */ left: 50%; transform: translateX(-50%); width: 24rem; height: 20rem; background-repeat: no-repeat; background-position: center bottom; background-size: contain; opacity: 0.38; filter: grayscale(70%) drop-shadow(0 1rem 3rem rgba(0, 0, 0, 0.9)); } #moe-root .moe-tick-reached .moe-tick-icon { opacity: 1; filter: drop-shadow(0 1rem 3rem rgba(0, 0, 0, 0.9)) drop-shadow(0 0 6rem rgba(255, 205, 90, 0.6)); } /* A thin upright tick line on the track marking each milestone position. Styled to match the .moe-end goalpost (same width/height/tone) so the 65/85/95 marks and the 100% goalpost read as one family of guides. Brighter once the mark is reached. */ #moe-root .moe-tick-notch { position: absolute; top: -2rem; bottom: -2rem; left: 50%; transform: translateX(-50%); width: 1rem; background: rgba(236, 230, 218, 0.45); z-index: 2; } #moe-root .moe-tick-reached .moe-tick-notch { background: rgba(236, 230, 218, 0.8); } /* Damage requirement BELOW each mark. Blank when unknown (external table not loaded). */ #moe-root .moe-tick-req { position: absolute; top: 7rem; /* 1rem clear of the track, matching the icon's gap above */ left: 50%; /* tick centre */ transform: translateX(-50%); /* CENTRED on the tick */ font-size: 12rem; font-weight: 400; /* thin numeric face, matching the 50% caption */ color: rgba(216, 207, 191, 0.45); /* unreached marks read faint */ white-space: nowrap; text-shadow: 0 1rem 0 rgba(13, 14, 16, 0.4), 0 0 3rem rgba(0, 0, 0, 0.55); } #moe-root .moe-tick-reached .moe-tick-req { color: #ede6d9; /* reached marks read white */ } /* --- hover tooltip: native "Marks of Excellence" award tooltip ------------- */ /* A body-level fixed panel (JS positions + edge-clamps it) shown while the widget is hovered, reproducing the client's own MoE award tooltip (Vehicle stats -> Awards): the big nation mark art + the achievement title, the current-ratio line, the descriptive text, a divider, and the condition rules. All text is the client's own strings (resolved in adapter/i18n.py, pushed via the model's `labels` bundle); the mark art is the marksOnGun 180x180 atlas. STRUCTURE + CHROME reuse the shared `.wg-tooltip` / `.wg-tip-*` tooltip COMPONENT (see the wotmod-gameface-widget harness skill, "Native tooltip recipe"): the SAME class vocabulary the sibling wgmod-research-progress mod uses, so both mods' tooltips render IDENTICALLY. The mods stay STANDALONE -- each ships its OWN copy of these rules (no shared file), scoped here to #moe-tooltip so two installed mods never collide (the sibling scopes the same classes under #wgmod-root). Chrome = WG's 9-slice tooltip frame (border-image of gui/maps/icons/tooltip/background_with_border.png, 4 fill / 4rem round) loaded via `img://` on the border-image LONGHAND -- which resolves where the `border-image` shorthand silently fails -- over a rgba(20,20,20,.95) fallback + the native 0 0 32rem shadow; #ede6d9 title / #8e867d body tokens; the width-stretched gui/maps/icons/tooltip/divider.png separator. The bundled tooltip_bg.png / tooltip_divider.png stay sibling fallbacks if a client patch ever breaks the img:// atlas. Hidden by default; JS toggles .moe-tt-open. pointer-events:none so it never steals hangar input. All colours hardcoded (Gameface drops a whole declaration on an unresolved var()). MoE-LOCAL additions (NOT part of the shared recipe): .wg-tip-icon-mark / .wg-tip-main-mark (the 180x180 mark-art icon box + its reserved column), .wg-tip-icon-unearned (dim the aspirational art at 0 marks), .moe-tip-ratio / .moe-tip-descr (JS hooks, both styled by the shared .wg-tip-effect), .moe-tip-hi (the white percentile highlight), .moe-tip-empty (hide the ratio at 0%). */ #moe-tooltip { position: fixed; display: none; left: 0; top: 0; z-index: 10000; /* above the widget (9001) and its frame/hover overlays */ box-sizing: border-box; min-width: 168rem; max-width: 440rem; /* content-sized, like the sibling .wg-tooltip */ font-family: PFDINMax, "PF DIN Max Compressed", "Warhelios", sans-serif; letter-spacing: 0.02em; text-align: left; white-space: normal; color: #ede6d9; background: rgba(20, 20, 20, 0.95); /* fallback under the atlas frame */ border-style: solid; border-width: 4rem; border-color: transparent; border-image-source: url('img://gui/maps/icons/tooltip/background_with_border.png'); border-image-slice: 4 fill; border-image-width: 4rem; border-image-repeat: round; box-shadow: 0 0 32rem rgba(15, 15, 15, 0.8); /* native tooltip shadow */ padding: 12rem 16rem 14rem; pointer-events: none; } #moe-tooltip.moe-tt-open { display: block; } /* Main block: the text column (title + ratio + description) with the mark-art icon pinned to the top-RIGHT and OUT of flow (absolute) -- the shared .wg-tip-main recipe. A plain BLOCK, not flex/float: Coherent sizes a flex row from the text's FIRST line only and won't wrap text around a float, so the icon is lifted out of flow into a reserved right-hand column (.wg-tip-main-mark's padding-right = icon width + gap; a min-height floor = icon height), and a plain block always grows to its full wrapped text. */ #moe-tooltip .wg-tip-main { display: block; position: relative; } /* MoE mark-art column: reserve the 64rem icon + a 12rem gap; the min-height floor keeps a short-text tooltip tall enough for the out-of-flow icon so the divider clears it. */ #moe-tooltip .wg-tip-main-mark { padding-right: 95rem; min-height: 57.5rem; } #moe-tooltip .wg-tip-text { min-width: 0; overflow-wrap: break-word; /* break an unbreakable token so it wraps inside max-width */ word-wrap: break-word; /* old Coherent alias */ } /* Shared icon box: out of flow, top-right; a background-image div (Gameface clips ); the drop-shadow hugs the art's alpha. Its SIZE comes from the variant class. */ #moe-tooltip .wg-tip-icon { position: absolute; top: 0; right: 0; background-repeat: no-repeat; background-position: center top; /* pin art to the TOP -> no centering on tall titles */ background-size: contain; filter: drop-shadow(0 1rem 2rem rgba(0, 0, 0, 0.85)); } /* MoE variant: the nation mark art (getHugeIcon = marksOnGun 180x180). The source is a 180x180 SQUARE canvas but the mark glyph inside is WIDE -- it occupies only rows ~25..153 (a 180x128 glyph) with ~25px transparent padding above and ~27px below, centred. So the box takes the GLYPH's aspect (180:128 -> 64x46, not 64x64) and the art is scaled to fill the box WIDTH (background-size 100% auto -> 64x64) then vertically CENTRED, which clips the equal transparent bands top+bottom. Without this the square-in-square contain fit rendered the glyph vertically centred in a 64x64 box -- i.e. ~9rem below the box top, reading as "lower than the title" (the box is pinned top:0). Overrides the base icon's `contain` / `center top`. */ #moe-tooltip .wg-tip-icon-mark { width: 80rem; height: 57.5rem; background-size: 100% auto; background-position: center; } /* 0 marks: dim the aspirational (3-mark) art, like an unearned mark in the client's own statistics/awards tooltip. */ #moe-tooltip .wg-tip-icon-unearned { opacity: 0.35; } /* Title -- native `.Index_title` token (primary parchment, semibold). */ #moe-tooltip .wg-tip-name { font-size: 16rem; font-weight: 600; color: #ede6d9; opacity: 0.95; line-height: 1.1; } /* Body text -- WG's tooltip description body: tertiary parchment, normal weight, wrapping. The shared body row; here it styles the current-ratio line, the description, AND every condition bullet, so all three share the native tooltip body rhythm (margin-top:5rem). */ #moe-tooltip .wg-tip-effect { margin-top: 5rem; font-size: 15rem; font-weight: 400; color: #8e867d; line-height: 1.25; } /* The current percentile, highlighted white like the native . Applied to a element (see ratioHtml) -- a bare gets blockified by Coherent and drops onto its own line; renders inline. The figure has no internal spaces, so it never splits. */ /* The ratio line renders one PER WORD (see ratioHtml). This engine has no inline formatting -- a colored child element always breaks onto its own line -- so the line is a flex-wrap ROW (flexbox is the only horizontal layout it honours) and each word is a flex item that wraps like text. Word spacing is a right margin on each item (NOT `gap`, which older Coherent may not support); wrapped-line spacing comes from the items' own line-height. The highlighted % word is .moe-tip-hi (white). */ #moe-tooltip .moe-tip-ratio { display: flex; flex-wrap: wrap; align-items: baseline; } #moe-tooltip .moe-tip-ratio > span { margin-right: 3.4rem; } #moe-tooltip .moe-tip-hi { color: #ffffff; } /* The description is a full-width paragraph (it lives OUTSIDE .wg-tip-main -- see the DOM -- so the icon's reserved column no longer narrows it). Its 7rem bottom margin opens the gap down to the divider a touch more than the condition block's 5rem top margin below it. */ #moe-tooltip .moe-tip-descr { margin-bottom: 7rem; } /* Ratio hidden at 0% (the client's empty-at-0 behaviour) so it adds no gap above the descr. */ #moe-tooltip .moe-tip-empty { display: none; } /* Section divider -- the same divider art WG's carousel vehicle tooltip uses, stretched to full width x a fixed 9rem so the end-fade sits at the tooltip edges at any width. */ #moe-tooltip .wg-tip-div { height: 9rem; margin: 4rem 0; background: url('img://gui/maps/icons/tooltip/divider.png') no-repeat center; background-size: 100% 100%; } PK!XOO<res/gui/gameface/mods/14th_ua/MoECalculator/MoECalculator.js// 14th_ua's MoE Calculator widget. Injected into the hangar document by OpenWG. Reads // our data model (exposed as `moeData` on the host sub-view's model) via ModelObserver // and renders a Marks-of-Excellence progress bar: a percentile axis (0..100) with three // milestone ticks at 65/85/95 (= 1/2/3 marks) drawn with the vehicle's nation mark art // ON TOP of the bar and the combined-damage requirement BELOW each, plus a top-left // readout of the current average combined damage + current mark percentage. // // Style mimics the garage's top-right Battlepass chapter-progress widget. See the // wotmod-gameface-widget harness skill for the DOM/CSS conventions + Coherent quirks. import { ModelObserver } from "../../libs/model.js"; const observer = ModelObserver("MoECalculator"); // wulf exposes nested viewmodels / array elements wrapped as { value: ... }. function unwrap(x) { return x && x.value !== undefined ? x.value : x; } // Reverse-channel command names -- mirror bridge/view_models.py MoEVM commands. const CMD = { SET_POSITION: "setPosition" }; // Invoke a reverse-channel command on our MoEVM (exposed as `moeData` on the host model). // Wulf surfaces a ViewModel command as a callable on the model; whether it lives on the // wrapped proxy or its unwrapped value can differ across builds, so try both. Wulf commands // take a single MAP argument (a raw scalar is rejected as "not a map"); a map arg (setPosition's // {x, y, w, h}) passes through as-is, a scalar is wrapped {value:...}, and a no-arg call passes {}. function invokeCommand(name, arg) { try { const vm = observer.model && observer.model.moeData; let host = null; if (vm && typeof vm[name] === "function") host = vm; else { const inner = unwrap(vm); if (inner && typeof inner[name] === "function") host = inner; } if (!host) { console.error("[moe] command missing: " + name); return; } if (arg === undefined || arg === null) host[name]({}); else if (typeof arg === "object") host[name](arg); else host[name]({ value: arg }); } catch (e) { console.error("[moe] invokeCommand failed: " + name, e); } } // Current Gameface viewport (px). setPosition records this alongside the pinned px so a later // resolution / UI-scale change rescales the position proportionally (see applyPosition). function currentVP() { return { w: window.innerWidth || 0, h: window.innerHeight || 0 }; } // --- Drag-to-reposition: pin-state anchor helpers ---------------------------------- // The widget has TWO anchor modes (see the plan / .css). AUTO: the CSS bottom-right anchor // (right/bottom + transform-origin 100% 100%), no inline left/top -- resolution-relative, // re-derived every viewport. PINNED: a top-LEFT anchor (transform-origin 0 0, right/bottom // cleared, inline left/top px) -- with origin 0 0 the scaled box's top-left equals left/top, // so drag math + clamping stay predictable under the transform:scale(k). We store the top-left. // _moePinned drives applyWidgetScale's transform-origin so a scale re-arm keeps the right anchor. function enterPinAnchor(root, left, top) { root._moePinned = true; root.style.transformOrigin = "0 0"; root.style.right = "auto"; root.style.bottom = "auto"; root.style.left = Math.round(left) + "px"; root.style.top = Math.round(top) + "px"; } function clearPinAnchor(root) { root._moePinned = false; root.style.transformOrigin = "100% 100%"; // clear the inline overrides so the resolution-relative CSS bottom-right anchor re-derives. root.style.left = ""; root.style.top = ""; root.style.right = ""; root.style.bottom = ""; } // Measure the AUTO-anchor top (px) for the CURRENT carousel state without disturbing the pin: // momentarily clear the pin (restore right/bottom + origin 100% 100%, drop inline left/top), // force a reflow, read getBoundingClientRect().top, then restore the exact prior inline styles. // Synchronous (no paint between), so it never flickers. Used for the Follow-Carousel nudge. function measureAutoTop(root) { const s = root.style; const savedLeft = s.left, savedTop = s.top, savedRight = s.right, savedBottom = s.bottom, savedOrigin = s.transformOrigin; s.left = ""; s.top = ""; s.right = ""; s.bottom = ""; s.transformOrigin = "100% 100%"; void root.offsetHeight; // force reflow so the CSS anchor is applied before we measure const top = root.getBoundingClientRect().top; s.left = savedLeft; s.top = savedTop; s.right = savedRight; s.bottom = savedBottom; s.transformOrigin = savedOrigin; return top; } // Apply the user's dragged position (px, top-left), or fall back to the CSS default. posX/posY // are the top-left px, both 0 == "auto". PINNED (posX/posY > 0): the stored px were captured at // data.posW x data.posH; if the current viewport differs, rescale proportionally, apply, and // echo the rescaled px + new capture size back so it converges (the next push carries posW/posH // == the current viewport). A pin with NO recorded capture size (typed into the steppers, or a // pre-fix save) adopts the current viewport so a LATER change can rescale it. AUTO (0/0): clear // the inline override so the resolution-relative CSS default re-derives. Never fights an // in-progress drag; a no-op for an older Python build that doesn't push posX. function applyPosition(root, data) { if (root._moeDragging) return; if (!data || data.posX === undefined) return; const vp = currentVP(); const x = data.posX | 0; const y = data.posY | 0; if (x > 0 && y > 0) { let ax = x, ay = y; const rw = data.posW | 0, rh = data.posH | 0; if (rw && rh && vp.w && vp.h && (rw !== vp.w || rh !== vp.h)) { ax = Math.round(x * vp.w / rw); ay = Math.round(y * vp.h / rh); invokeCommand(CMD.SET_POSITION, { x: ax, y: ay, w: vp.w, h: vp.h }); } else if ((!rw || !rh) && vp.w && vp.h) { invokeCommand(CMD.SET_POSITION, { x: x, y: y, w: vp.w, h: vp.h }); } enterPinAnchor(root, ax, ay); // Baseline for the Follow-Carousel nudge: the auto top in the CURRENT carousel state. // Set on every apply so the first post-mount carousel toggle has a correct reference. root._moeLastAutoTop = measureAutoTop(root); return; } clearPinAnchor(root); root._moeLastAutoTop = undefined; // auto follows the carousel via CSS -- no nudge baseline } // Ctrl+drag to reposition the widget. Ctrl-gated so a normal hover/click can't move it. On // mousedown we switch to the top-left anchor at the current on-screen top-left (no visual jump), // then track the cursor; Shift locks to the dominant axis (re-evaluated every move). On release // we report the final top-left px to Python via setPosition (a BARE map), which persists it and // re-pushes; applyPosition then re-applies the same coords. Hidden tooltip + _moeDidDrag guard // the trailing synthetic click / reopen. // // The drag-start listener lives on `document` in the CAPTURE phase, NOT on #moe-root in bubble. // Reason (cross-mod collision): OpenWG injects several mods into the SAME hangar document as // body siblings at similar z-index, and any number of them may be independently draggable. // Capturing on document lets our handler run for EVERY mousedown, so `e.target` is the true // hit-tested topmost pointer-events:auto element under the cursor -- and ownership is decided by // `root.contains(e.target)`: we claim the drag ONLY when the mousedown actually landed on OUR // widget's DOM subtree, and we NEVER stopImmediatePropagation for anyone else's mousedown. That // is what makes this coexist with ANY number of other draggable mods (not just one known // sibling) and be INDEPENDENT of listener registration / mount order -- a rect hit-test can't do // this, because two overlapping widgets' rects can both contain the point and the first- // registered capture listener would win nondeterministically. // // It works because of our pointer-events layering (MoECalculator.css): #moe-root is // pointer-events:auto on its footprint while every overhanging child (ticks, markers, end // labels) is pointer-events:none -- so `e.target` resolves to our root only when the pointer is // genuinely over our interactive footprint, and any interactive child still lives under // #moe-root so contains() covers it. Where our visible footprint overlaps another equal-z // widget's transparent overhang, #moe-root's z-index:9001 (one above the 9000 baseline) makes // OUR footprint the topmost painted element there, so hit-testing matches the visual stacking. let _moeDragBound = false; // idempotent: the document listener must be added exactly once function installDrag() { if (_moeDragBound) return; // ensureRoot()/mount may run repeatedly; never stack listeners _moeDragBound = true; document.addEventListener("mousedown", function (e) { const root = document.getElementById("moe-root"); // Ownership: bail (plain return, NO stopImmediatePropagation) unless the widget exists, // is shown, Ctrl is held, AND the mousedown landed inside OUR DOM subtree. Target-based // hit-test (root.contains) -- the true topmost pointer-events:auto element -- so we only // ever claim a mousedown on our own widget and never stop the event for another mod's. if (!root || root.style.display === "none") return; if (!e.ctrlKey) return; if (!root.contains(e.target)) return; // It IS our drag: pre-empt any other mod's mousedown (stopImmediatePropagation also stops // any later document-capture listener + all bubbling) so nothing else can grab the drag. e.stopImmediatePropagation(); e.preventDefault(); const r0 = root.getBoundingClientRect(); const boxW = r0.width, boxH = r0.height; // scaled rendered size (clamp basis) const offX = e.clientX - r0.left; // cursor -> top-left x const offY = e.clientY - r0.top; // cursor -> top-left y const startLeft = Math.round(r0.left); const startTop = Math.round(r0.top); // Switch to the top-left anchor at the current on-screen position -- no jump. enterPinAnchor(root, startLeft, startTop); root._moeDragging = true; root._moeDidDrag = true; root.style.cursor = "move"; hideTooltip(); // suppress the hover tooltip while dragging (reopen guarded too) const onMove = function (ev) { const w = window.innerWidth || 0; const h = window.innerHeight || 0; let cx = ev.clientX - offX; let cy = ev.clientY - offY; // clamp so the whole box stays on-screen. y floored at 1 (0 is the auto sentinel). if (w) cx = Math.max(0, Math.min(w - boxW, cx)); if (h) cy = Math.max(1, Math.min(h - boxH, cy)); // Shift axis-lock (Photoshop-style), re-evaluated every move so releasing/holding // Shift or changing the dominant direction switches the locked axis live. if (ev.shiftKey) { const dx = cx - startLeft, dy = cy - startTop; if (Math.abs(dx) >= Math.abs(dy)) cy = startTop; else cx = startLeft; } root.style.left = Math.round(cx) + "px"; root.style.top = Math.round(cy) + "px"; }; const onUp = function () { document.removeEventListener("mousemove", onMove, true); document.removeEventListener("mouseup", onUp, true); root._moeDragging = false; root.style.cursor = ""; const r = root.getBoundingClientRect(); const vp = currentVP(); invokeCommand(CMD.SET_POSITION, { x: Math.max(1, Math.round(r.left)), // never 0 (the auto sentinel) y: Math.max(1, Math.round(r.top)), w: vp.w, h: vp.h, }); // Hold _moeDidDrag through the click that fires right after mouseup, then clear. setTimeout(function () { root._moeDidDrag = false; }, 0); }; // capture phase so a fast drag that leaves the box still tracks + releases. document.addEventListener("mousemove", onMove, true); document.addEventListener("mouseup", onUp, true); }, true); // CAPTURE on document: fires for EVERY mousedown so e.target is the real hit element } // Flat (nation-agnostic) mark glyph: mark_1/2/3 = the 1/2/3-mark UI dashes. We use // these for every tick rather than the nation gun-barrel decals (tk.icon) -- the // decals carry flag backgrounds + detail that mush at tick size. const FLAT_MARK = "img://gui/maps/icons/library/marksOnGun/mark_%d.png"; // The big nation mark art for the tooltip header -- the client's own "huge icon" // (getHugeIcon): marksOnGun 180x180 atlas, keyed by the vehicle's nation + mark count. // Matches the client's MoE award tooltip. count clamps to 1..3; a 0-mark vehicle shows // the 3-mark art (what you can earn), exactly as the client does (currentValue = 3 if 0). function bigMarkIcon(nation, marks) { const count = (marks | 0) <= 0 ? 3 : Math.min(3, marks | 0); const suffix = count < 2 ? "mark" : "marks"; return "img://gui/maps/icons/marksOnGun/180x180/" + (nation || "ussr") + "_" + count + "_" + suffix + ".png"; } // Localized label bundle, pushed from Python as a JSON string on the model (`labels`). // The JS renders whatever the model carries and hardcodes NO English (see the // wotmod-gameface-widget Localization convention). Parsed missing-key-safe: a missing // key degrades to "" rather than crashing or blanking the whole tooltip. let LABELS = {}; function parseLabels(s) { try { return (s && JSON.parse(s)) || {}; } catch (e) { return {}; } } function L(key) { return (LABELS && LABELS[key]) || ""; } // Group an integer with thousands separators: 2910 -> "2,910". function thousands(n) { n = Math.max(0, Math.round(Number(n) || 0)); return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Percentile float -> "84.73%" (two decimals, TRUNCATED not rounded); 0 -> "0%". // The game supplies 0.01 granularity (getDamageRating divides by 100), so 2 decimals is // the natural non-spurious maximum. We truncate (floor) rather than round so the readout // never overstates progress toward a mark threshold (e.g. 84.999 shows "84.99%", not "85"). function pctText(p) { p = Math.floor((Number(p) || 0) * 100) / 100; // truncate to 2dp first if (p <= 0) return "0%"; return p.toFixed(2) + "%"; } // Bare 2-decimal percentile figure (no "%"), truncated like pctText: "84.73". function pctNum(p) { return (Math.floor((Number(p) || 0) * 100) / 100).toFixed(2); } // Build the tooltip's "current ratio" line from the localized WG template // (#tooltips:achievement/marksOnGunCount). This engine has NO inline formatting -- ANY child // element (span/font, any `display`) drops onto its own line; only flexbox lays boxes out // horizontally (confirmed by live probe; see the sibling wgmod-research-progress note). So the // ratio line is a flex-wrap row (see .moe-tip-ratio) and we emit ONE PER WORD -- each a // flex item that wraps like text -- with the word(s) inside the WG template's colour tags // carrying `.moe-tip-hi` (white). Placeholders are filled as the client fills them: color_tag_* // delimit the highlighted run (marked here with \x01/\x02 sentinels, stripped as we tokenize), // `count` is the truncated percentile, `%%` a single `%`. The embedded newline + doubled spaces // collapse first so the split yields clean words. Returns "" when the string is absent. function ratioHtml(pct) { const tpl = L("ratio"); if (!tpl) return ""; const marked = tpl .replace("%(color_tag_open)s", "\x01") .replace("%(color_tag_close)s", "\x02") .replace("%(count)s", pctNum(pct)) .replace(/%%/g, "%") .replace(/\s*\n\s*/g, " ") .replace(/\s{2,}/g, " ") .trim(); const words = marked.split(" "); let hot = false, html = ""; for (let i = 0; i < words.length; i++) { let w = words[i]; if (w.indexOf("\x01") !== -1) { hot = true; w = w.replace(/\x01/g, ""); } let closeAfter = false; if (w.indexOf("\x02") !== -1) { closeAfter = true; w = w.replace(/\x02/g, ""); } if (w) html += "" + w + ""; if (closeAfter) hot = false; } return html; } // Piecewise axis: map a percentile (0..100) to a position along the bar (0..100 %). // The bar spans the FULL width, divided into 4 EQUAL-WIDTH regions at the milestone // boundaries -- below 65 | 65-85 | 85-95 | 95-100 -- each region an even quarter // (25%) of the bar WIDTH. Equal quarters spread the crowded high-percentile marks // (65/85/95) evenly (25%/50%/75%) instead of bunching them at the tail, while still // filling the whole bar. PCT_STOPS = the percentile region boundaries; BAR_STOPS = their // bar-width positions. Applied to BOTH the fill width and every tick's position so they // stay consistent; the CSS boundary guides (.moe-tick-notch at 65/85/95, .moe-end at 100) // are positioned to the same stops (ticks data-driven via barX). const PCT_STOPS = [0, 65, 85, 95, 100]; // percentile region boundaries const BAR_STOPS = [0, 25, 50, 75, 100]; // bar-width % (equal quarters) function barX(percentile) { const p = Math.max(0, Math.min(100, Number(percentile) || 0)); for (let i = 1; i < PCT_STOPS.length; i++) { if (p <= PCT_STOPS[i]) { const t = (p - PCT_STOPS[i - 1]) / (PCT_STOPS[i] - PCT_STOPS[i - 1]); return BAR_STOPS[i - 1] + t * (BAR_STOPS[i] - BAR_STOPS[i - 1]); } } return 100; } // Build the root element once and cache it on the document. function ensureRoot() { let root = document.getElementById("moe-root"); if (root) return root; root = document.createElement("div"); root.id = "moe-root"; root.innerHTML = '
' + ' ' + ' ' + ' ' + ' ' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; document.body.appendChild(root); installDrag(); // Ctrl+drag reposition (document-capture listener, bound exactly once) return root; } function markIcon(count) { // Flat glyph for the given mark level (1/2/3, already clamped by the caller). return FLAT_MARK.replace("%d", String(count)); } function renderTicks(ticksEl, ticks) { ticksEl.innerHTML = ""; for (let i = 0; i < ticks.length; i++) { const tk = unwrap(ticks[i]); const el = document.createElement("div"); const count = Math.max(1, Math.min(3, tk.markCount || 1)); el.className = "moe-tick moe-tick-m" + count + (tk.reached ? " moe-tick-reached" : ""); el.style.left = barX(tk.percent || 0) + "%"; // Nation mark art ON TOP of the bar. const icon = document.createElement("div"); icon.className = "moe-tick-icon"; icon.style.backgroundImage = "url(" + markIcon(count) + ")"; el.appendChild(icon); // A small notch sitting on the track at the milestone. const notch = document.createElement("div"); notch.className = "moe-tick-notch"; el.appendChild(notch); // Damage requirement BELOW the mark (blank when unknown -> table not loaded yet / // vehicle absent / estimator has no sample). const req = document.createElement("div"); req.className = "moe-tick-req"; req.textContent = (tk.damageRequired > 0) ? thousands(tk.damageRequired) : ""; el.appendChild(req); ticksEl.appendChild(el); } } // Hover tooltip master switch. When false, renderTooltip() bails early so the host node // is never built and no hover listeners are bound (ensureTooltip is reached only through // renderTooltip). const TOOLTIP_ENABLED = true; // Hover-intent delay (ms) before a sustained hover reveals the tooltip, so a quick pass over // the bar doesn't flash it (matches the client's own tooltip dwell). The pending timer is // cleared on mouseleave and whenever the widget hides. const TOOLTIP_DELAY_MS = 400; let ttShowTimer = 0; // Build the hover tooltip host ONCE (body-level, position:fixed so it escapes the root // padding/frame) and bind the whole-widget hover on #moe-root. render() only updates the // text/classes -- it never rebuilds this node, which would drop an open tooltip mid-hover // (see the harness Tooltips guidance). The tooltip stays pointer-events:none (CSS) so it // never steals the hangar's drag-to-rotate. // // Layout mirrors the client's native MoE award tooltip: the big nation mark art beside the // title + current-ratio line, then the description, a divider, and the condition rules. function ensureTooltip() { let tip = document.getElementById("moe-tooltip"); if (tip) return tip; tip = document.createElement("div"); tip.id = "moe-tooltip"; // Reuse the shared `.wg-tooltip` / `.wg-tip-*` tooltip component (the same class // vocabulary the sibling wgmod-research-progress mod uses -- both mods render identically, // but each ships its OWN standalone copy of the CSS, scoped to its root). Text column // (title + ratio + description) inside .wg-tip-main, with the mark art pinned to the // top-RIGHT out of flow (.wg-tip-icon). The divider + condition span full width below. // MoE-local hooks: .moe-tip-ratio / .moe-tip-descr (JS targets; both styled by the shared // .wg-tip-effect body row); condition bullets are shared .wg-tip-effect rows too. tip.className = "wg-tooltip"; tip.innerHTML = '
' + '
' + '
' + '
' + '
' + '
' + '
' + // The description is a FULL-WIDTH paragraph OUTSIDE .wg-tip-main -- it sits below the // mark art, so it must not be squeezed into the icon's reserved right column; as a // top-level block it uses the whole tooltip width like the divider + conditions. '
' + '
' + '
'; document.body.appendChild(tip); const root = document.getElementById("moe-root"); if (root) { root.addEventListener("mouseenter", function () { if (root.style.display === "none") return; if (root._moeDragging || root._moeDidDrag) return; // never open mid-drag / just after clearTimeout(ttShowTimer); ttShowTimer = setTimeout(function () { if (root.style.display === "none") return; // widget hid during the delay if (root._moeDragging || root._moeDidDrag) return; // a drag started during the delay tip.classList.add("moe-tt-open"); positionTooltip(root, tip); }, TOOLTIP_DELAY_MS); }); root.addEventListener("mouseleave", function () { clearTimeout(ttShowTimer); tip.classList.remove("moe-tt-open"); }); } return tip; } // Fixed panel anchored to the widget: prefer above it, right-aligned to its edge, and // edge-clamped inside the viewport so it never spills off-screen. Measured after the // node is shown (a hidden node measures 0). function positionTooltip(root, tip) { const r = root.getBoundingClientRect(); // Match the tooltip's width to the widget's EXACT rendered px width (box-sizing:border-box, // so this includes the frame). Set before measuring so the height/edge-clamp reflect it. tip.style.width = Math.round(r.width) + "px"; const t = tip.getBoundingClientRect(); const gap = 8; const vw = window.innerWidth || document.documentElement.clientWidth || 0; const vh = window.innerHeight || document.documentElement.clientHeight || 0; let top = r.top - t.height - gap; // above the widget... if (top < gap) top = r.bottom + gap; // ...or below if it would clip the top let left = r.right - t.width; // right-aligned to the widget if (left + t.width > vw - gap) left = vw - gap - t.width; if (left < gap) left = gap; if (top + t.height > vh - gap) top = vh - gap - t.height; if (top < gap) top = gap; tip.style.left = Math.round(left) + "px"; tip.style.top = Math.round(top) + "px"; } function hideTooltip() { clearTimeout(ttShowTimer); // drop any pending delayed-show so it can't fire off-widget const tip = document.getElementById("moe-tooltip"); if (tip) tip.classList.remove("moe-tt-open"); } // Populate the tooltip from the model -- the client's own MoE award tooltip. All text is // localized off the model's LABELS bundle (no hardcoded English); the mark art is the // vehicle's own nation icon. Title/description are keyed by the current mark count // (title0..3 / descr0..3): at 0 marks the blurb tells you how to earn the 1st, at 3 it // reads "maximum obtained" -- exactly as the client does. function renderTooltip(root, data) { if (!TOOLTIP_ENABLED) return; const tip = ensureTooltip(); const marks = Math.max(0, Math.min(3, Number(data.marks) || 0)); const iconEl = tip.querySelector(".wg-tip-icon"); iconEl.style.backgroundImage = "url(" + bigMarkIcon(data.nation, marks) + ")"; // 0 marks: dim the (aspirational 3-mark) art -- the client shows an unearned mark faint // in its own statistics/awards tooltip. iconEl.classList.toggle("wg-tip-icon-unearned", marks === 0); tip.querySelector(".wg-tip-name").textContent = L("title" + marks); tip.querySelector(".moe-tip-descr").textContent = L("descr" + marks); // Current-ratio line: shown only when the client would (a real percentile > 0), matching // the native tooltip's localizedValue (empty at damageRating <= 0). Plain inline text. const ratio = tip.querySelector(".moe-tip-ratio"); const pct = Number(data.curPercent) || 0; if (pct > 0) { ratio.innerHTML = ratioHtml(pct); ratio.classList.remove("moe-tip-empty"); } else { ratio.innerHTML = ""; ratio.classList.add("moe-tip-empty"); } // Condition rules: one localized '\n'-separated block -> one line per bullet, each a // shared .wg-tip-effect body row (same rhythm as the ratio + description above). const cond = tip.querySelector(".wg-tip-cond"); cond.innerHTML = ""; const lines = (L("condition") || "").split("\n"); for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; const el = document.createElement("div"); el.className = "wg-tip-effect"; el.textContent = line; cond.appendChild(el); } if (tip.classList.contains("moe-tt-open")) positionTooltip(root, tip); } function render(model) { const root = ensureRoot(); const data = unwrap(model && model.moeData); if (!data) { // Model not attached yet -- keep the widget hidden rather than flashing a stub. root.style.display = "none"; hideTooltip(); return; } // Python pushes visible=false off the plain garage / while a tank-setup overlay is // open. An absent flag (older Python) is treated as visible. if (data.visible === false) { root.style.display = "none"; hideTooltip(); return; } root.style.display = ""; // Localized tooltip labels ride on the model as a JSON bundle; parse missing-key-safe. LABELS = parseLabels(data.labels); // Keep the last-pushed data for the viewport-resize hook (which re-applies position). root._moeLastData = data; // Responsive bottom offset: tag the root with the carousel geometry so the CSS can // lift the bar clear of a single / small-double / tall-double carousel. Detect a CHANGE // (vs the previous render) so a PINNED widget can follow the carousel's vertical shift. const rows2 = Number(data.carouselRows) === 2; const small = !!data.carouselSmall; const carSig = (rows2 ? 2 : 1) * 10 + (small ? 1 : 0); const prevAutoTop = root._moeLastAutoTop; // baseline from the PREVIOUS carousel state const carouselChanged = root._moeCarSig !== undefined && root._moeCarSig !== carSig; root.classList.toggle("moe-rows2", rows2); root.classList.toggle("moe-small", small); root._moeCarSig = carSig; // Readout: current average combined damage (top-left, above the bar) + current mark // percentage (used as the last tick's top label, above the bar's 100% end). // A never-played tank genuinely reads 0 (synchronous dossier read, not the async // thresholds table), so show explicit 0 / 0% rather than a "—" placeholder-for-unknown. const dmg = data.curAvgDamage || 0; const pct = data.curPercent || 0; root.querySelector(".moe-cur-dmg").textContent = thousands(dmg); // 0 -> "0" root.querySelector(".moe-cur-pct").textContent = pctText(pct); // 0 -> "0%" // Fill to the current percentile, mapped through the piecewise axis (barX) so the // fill edge and the milestone ticks share the same split scale, and place the // leading-edge marker at the same spot (mimics the Battlepass in-chapter leading edge). const fill = Math.max(0, Math.min(100, Number(data.fill) || 0)); root.querySelector(".moe-fill").style.width = barX(fill) + "%"; root.querySelector(".moe-cur-marker").style.left = barX(fill) + "%"; // 100% end-cap: the combined-damage goalpost for the 100th percentile, shown to the // RIGHT of the bar's end (not below, where it would overlap the 95% mark number). // Blank when the external table hasn't supplied it yet. const endReq = data.endDamageRequired || 0; root.querySelector(".moe-end-label").textContent = endReq > 0 ? thousands(endReq) : ""; renderTicks(root.querySelector(".moe-ticks"), (data.ticks || [])); // Hover tooltip: full localized stats breakdown (updates in place; kept open if the // user is already hovering when a re-push arrives). renderTooltip(root, data); // Position: apply the persisted pin (or the auto CSS default). This also refreshes // _moeLastAutoTop to the auto top in the CURRENT carousel state. applyPosition(root, data); // Follow Carousel Mode: when the carousel state changed AND the widget is pinned AND the // setting is on, nudge the pin vertically by the auto-anchor's shift so it keeps clearing // the carousel, then echo the new position back so it persists. Carousel changes are // vertical-only -- X is never nudged. Skipped when unpinned (auto follows via CSS) or off. if (carouselChanged && root._moePinned && data.followCarousel && prevAutoTop !== undefined && root._moeLastAutoTop !== undefined) { const delta = root._moeLastAutoTop - prevAutoTop; // how far the auto anchor moved if (delta) { const vp = currentVP(); const curLeft = parseFloat(root.style.left) || (data.posX | 0); const curTop = parseFloat(root.style.top) || (data.posY | 0); let newTop = Math.round(curTop + delta); if (vp.h) { const boxH = root.getBoundingClientRect().height; newTop = Math.min(newTop, Math.max(1, vp.h - boxH)); } newTop = Math.max(1, newTop); root.style.top = newTop + "px"; invokeCommand(CMD.SET_POSITION, { x: Math.max(1, Math.round(curLeft)), y: newTop, w: vp.w, h: vp.h, }); } } } // Cold-mount self-heal. The widget repaints only when its ModelObserver's data-changed callback // fires (observer.onUpdate -> render). But on a freshly mounted sub-view the engine does NOT // deliver that callback until the view next composites -- which in the idle garage (or with the // settings overlay open) only happens when the camera moves. So an idle-garage push -- an MSA // per-mod reset or a stepper-to-0 that zeroes the position -- is dropped and the bar stays pinned // until the player nudges the camera (then every queued update lands at once). The first paint // works only because it's a DIRECT render() call below, not observer-driven. // // Fix: poll a cheap monotonic counter (moeData.rev, bumped by Python FIRST on every push) and // render when it changes. This runs even when the data-changed event is dormant, so the bar // follows pushes within one poll interval. Idle cost is a shallow field read + compare; a real // render happens only when rev actually moves, so no spurious rebuilds. applyPosition (called by // render) already respects the _moeDragging guard, so a poll never fights an active drag. let _lastRev = null; function revOf(model) { const data = unwrap(model && model.moeData); return data && data.rev !== undefined ? data.rev : null; } function renderAndTrack(model) { _lastRev = revOf(model); render(model); } function pollForChanges() { const rev = revOf(observer.model); if (rev !== null && rev !== _lastRev) renderAndTrack(observer.model); } engine.whenReady.then(() => { observer.onUpdate(renderAndTrack); // warm path: instant repaint when the event fires observer.subscribe(); renderAndTrack(observer.model); // direct initial paint (observer event not needed) }); /* Resolution-calibrated size law. k depends only on the LOGICAL viewport height (innerHeight/remPx): k=1 at the 1080 reference (so 1080p@x1 and 4K@x2, which share logical vp 1080, render at the same accepted screen fraction), growing by GROWTH per +1080 logical px. GROWTH is the single free knob (governs 1440p@x1 and 4K@x1); tuned live in-game, then baked. SATURATION CLAMP: the logical viewport is capped at LVP_CAP=1440 before the growth term, so growth SATURATES at 1440 logical px. This makes 1440p@x1 (lvp 1440) and 4K@x1 (lvp 2160 -> clamped to 1440) render at the IDENTICAL size (same k). Below 1440 nothing changes: 1080p@x1 (lvp 1080) and 4K@x2 (lvp 1080) still give k=1. The paired position-law clamp (min(26.11vh,376px) in the CSS bottom anchor) makes their GAP identical too. The content is authored in rem (1rem == interfaceScale px == remPx); we rescale it by k, anchored at the bottom-right corner (transform-origin 100% 100%) so the calibrated `bottom`/`right` anchor holds; the box grows up and to the left. */ var SIZE_REF = 1080; // logical-viewport reference height (k=1 here) var CAL_REMPX = 2; // interface scale (root font px) at which the x2 size was verified correct var LVP_CAP = 1440; // logical-viewport saturation point: growth stops past 1440 -> 1440p@x1 == 4K@x1 function widgetScale(remPx) { remPx = remPx || CAL_REMPX; var GROWTH = 0.625; // size slope: +GROWTH per +SIZE_REF logical px // k=1 at the 1080 logical-vp reference, growing by GROWTH per +1080 logical px, // SATURATING at LVP_CAP=1440 logical px (so 1440p@x1 and 4K@x1 collapse to one k). var lvp = Math.min(window.innerHeight / remPx, LVP_CAP); var k = 1 + GROWTH * (lvp - SIZE_REF) / SIZE_REF; if (remPx >= 2) { k *= 132 / 136; } // x2 anchor trim: 136px -> 132px (4K@x2 only) return k; } var _lastRemPx = 0; var _lastIH = 0; function readRemPx() { return parseFloat(getComputedStyle(document.documentElement).fontSize) || CAL_REMPX; } function applyWidgetScale() { var root = document.getElementById("moe-root"); if (!root) return; var remPx = readRemPx(); _lastRemPx = remPx; _lastIH = window.innerHeight; // The transform carries only the resolution-calibrated scale. The transform-origin depends // on the anchor mode: bottom-right (100% 100%) so the CSS bottom/right anchor holds when // AUTO; top-left (0 0) when PINNED so the inline left/top anchor holds (drag math relies on // the scaled box's top-left equalling left/top). Never touch the inline left/top set by // drag / applyPosition here. root.style.transformOrigin = root._moePinned ? "0 0" : "100% 100%"; root.style.transform = "scale(" + widgetScale(remPx) + ")"; // 4K@x2 only: widen the box by ~32 screen px extending LEFT (right-anchored origin). // Base width is 315rem (MoECalculator.css). At x2 1rem=2px and k=132/136, so // +16.5rem -> +16.5*2*(132/136) ~= 32 screen px. Reset to "" everywhere else so a // live resolution/interfaceScale change re-arms cleanly to the CSS default. if (remPx >= 2 && window.innerHeight >= 2160) { root.style.width = "331.5rem"; } else { root.style.width = ""; } } function pollWidgetScale() { if (!document.getElementById("moe-root")) return; if (readRemPx() !== _lastRemPx || window.innerHeight !== _lastIH) applyWidgetScale(); } // A screen-resolution / UI-scale change resizes the Gameface viewport but does NOT re-push the // model, so applyPosition wouldn't otherwise re-run and a pinned widget would keep stale px. // Re-run applyPosition on resize against the last-pushed data (auto re-derives the CSS default, // a pinned position rescales proportionally + echoes to converge). rAF-coalesced so a burst of // resize events collapses to one recompute. The Python g_guiResetters push is a backstop. function onViewportResize() { if (onViewportResize._pending) return; onViewportResize._pending = true; var raf = window.requestAnimationFrame || function (f) { f(); }; raf(function () { onViewportResize._pending = false; var root = document.getElementById("moe-root"); if (root && root._moeLastData) applyPosition(root, root._moeLastData); }); } engine.whenReady.then(function () { applyWidgetScale(); window.addEventListener("resize", applyWidgetScale); window.addEventListener("resize", onViewportResize); // One 250ms tick drives both the resolution/scale self-heal AND the cold-mount rev poll // (pollForChanges re-renders when Python bumped moeData.rev but the data-changed event was // dormant -- see the cold-mount self-heal note above). setInterval(function () { pollWidgetScale(); pollForChanges(); }, 250); }); PK!"|ñaa=res/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiency.css/* MoEEfficiency.css -- the DAMAGE EFFICIENCY in-battle bar variant. Tuned in the browser (tools/dev/eff_bar_tuner.html) and copied VERBATIM; a registered battle window has NO hot-reload, so every tweak in-game costs a full client relaunch. AXIS: damage across the four mark requirements -- five stops [0,r65,r85,r95,r100] mapped onto four visually EQUAL quarters [0,25,50,75,100], piecewise-linear and clamped. JS owns the mapping (same algorithm as MoECalculator.js barX) and sets .mp-fill's width plus the .mp-cur / .mp-cap.up left as percentages; the FOUR requirement ticks + caps are pure CSS at a fixed 25/50/75/100%. COLOUR: JS puts exactly ONE of .mp-b-w / -g / -t / -v / -au on #moe-bar-root, by which requirement the damage has passed (>= is INCLUSIVE). The band drives the fill, the current TOTAL's numerals and both glows (the current tick's and its glyph's) -- the numeral and glyph glows are each tuned PER BAND, the two glow radii and the dark drop are shared. The current tick's own line is STATIC white, so the marker reads the same at every band, and the delta stays white with no glow at all. Position comes from Python (window.move()), NOT from CSS -- tuner stage placement was top 86.5vh, centre offset 0rem. Sizes in rem (1rem == 1 logical px); colours by VALUE -- Gameface drops a declaration whose var() cannot resolve. Font: the bundled MoEBattle numeric subset, 19 glyphs (digits % ( ) + - , . / space) -- NO LETTERS, and no thin space -- the thousands separator is a knob, tuned here to "comma". THREE blocks are HAND-ADDED on top of this emit and must survive every re-copy: the @font-face (the tuner inlines the ttf as a data: URI; the shipped file wants the bare sibling url(MoEBattle.ttf)), the mp-life-b/mp-run-b keyframe twin, and the `.mp-lg` LARGE size mode (the tuner has no size mode; that block is x-lengths only -- the rest of the mode is a 1.25x ROOT FONT). The #moe-bar-box sizing rule below IS emitted -- do NOT add a second one by hand; the size mode overrides it with a SCOPED `.mp-lg` twin. */ /* ===== HAND-ADDED BLOCK 1 OF 4 (everything else in this file is the tuner's emit, VERBATIM -- tools/dev/emit_eff_css.js reproduces it byte-for-byte). #moe-bar-root asks for font-family "MoEBattle" but the tuner ran in a browser and inlined the ttf as a data: URI, so the emit carries no face for it; and this document does NOT MoEBattle.css or MoEProgress.css (both would collide on the shared #moe-bar-root / .mp-* namespace). So the declaration is copied verbatim from MoEProgress.css:18-24 -- same family name, same single weight-600 cut, same bare-sibling url FIRST: Coherent resolves an @font-face src against the DOCUMENT directory only, so a subdir-relative path silently falls back to Arial Narrow. That is also why this file must sit right beside MoEBattle.ttf and checker.png (both already shipped siblings -- nothing new to copy). ===== */ @font-face { font-family: "MoEBattle"; font-weight: 600; font-style: normal; src: url(MoEBattle.ttf) format("truetype"), url("coui://gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.ttf") format("truetype"); } /* ===== END HAND-ADDED BLOCK 1 ===== */ body { margin: 0; } #moe-bar-box { width: 460rem; height: 55rem; } #moe-bar-root { position: absolute; left: 0; top: 0; /* Keep a width the 3rem dash period tiles without a truncated GAP: 300 == 3*100 + 0. A width == 1 (mod 3) ends on a half gap -- move the WIDTH, never the tuned dash/gap. */ width: 300rem; z-index: 9000; pointer-events: none; text-align: center; font-family: "MoEBattle", "Arial Narrow", sans-serif; opacity: 0; } .mp-backdrop { position: absolute; left: -80rem; top: -40rem; width: 460rem; height: 96rem; z-index: 0; } /* checker.png + MoEBattle.ttf sit RIGHT BESIDE this file -- Coherent resolves a bare url against the DOCUMENT directory only. The tuner previewed THIS EXACT tile, inlined as a data: URI -- the same 4px PNG, 2x2 cells @2px (tools/dev/gen_checker.py). */ .mp-backdrop::before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(checker.png) repeat; background-size: auto; image-rendering: pixelated; opacity: 0.1; mask: radial-gradient(56% 110% at 50% 50%,#000 0%,transparent 67%); } .mp-backdrop::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; background: radial-gradient(76% 57% at 50% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } .mp-track { position: relative; z-index: 1; width: 100%; height: 3rem; background: rgba(0,0,0,0.45); } /* THE DASH GRID MASKS THE FILL: 2rem dash + 1rem OPAQUE gap, ONE period in the gradient tiled by background-size (WG's own idiom). The gap must stay opaque -- at a lower alpha the fill shows through and a gap left of the fill edge reads lighter than one right of it. The "border" is the OUTSET box-shadow on this same pseudo: zero box-model impact, so trackH and every tick anchor stay put, and it survives the pulse rewriting the track's box-shadow. z-index:1 = above the auto-z fill, below the z-index:2 ticks. */ .mp-track::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 1; background-image: repeating-linear-gradient(90deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2rem,rgba(13,14,16,1) 2rem,rgba(13,14,16,1) 3rem); background-size: 3rem 100%; background-repeat: repeat; box-shadow: 0 0 0 1rem rgba(13,14,16,0.5); } .mp-fill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: rgba(237,230,217,0.8); transition: width 400ms cubic-bezier(.2,.8,.2,1); } /* CENTRED tick geometry (the shipped .mp-tick): the tick CROSSES the track, top:50% + translate(-50%,-50%), so its height is symmetric about the track midline. */ .mp-tick { position: absolute; top: 50%; width: 2rem; z-index: 2; } .mp-tick.mp-req { height: 9rem; background: rgba(237,230,217,0.8); transform: translate(-50%, -50%) translateY(0rem); } .mp-tick.mp-req.met { background: rgba(237,230,217,0.8); } .mp-tick.mp-cur { width: 2rem; height: 9rem; background: rgba(255,255,255,1); transform: translate(-50%, -50%) translateY(0rem); transition: left 400ms cubic-bezier(.2,.8,.2,1); } /* The four requirement ticks + caps are FIXED at the quarter marks -- that IS the axis, and it is why nothing but the current tick/cap/fill needs a JS position. QUALIFIED with the element class on purpose: a bare .rN is ONE class, same as .mp-cap's own `left: 0` below, which would then win on source order and stack all four caps at 0%. */ .mp-tick.r1, .mp-cap.r1 { left: 25%; } .mp-tick.r2, .mp-cap.r2 { left: 50%; } .mp-tick.r3, .mp-cap.r3 { left: 75%; } .mp-tick.r4, .mp-cap.r4 { left: 100%; } /* THE NUMERAL IS WHAT SITS ON THE TICK: .mp-cap's only IN-FLOW child is .mp-v, so translateX(-50%) centres the digits themselves. The icon and the delta hang OFF the numeral out of flow (see .mp-ico / .mp-cap .mp-d below), which is also what stops the delta fading in from shifting the number. NOT a flex row: a row centres icon+number as one box and puts the number right of its tick by half the icon+gap. */ .mp-cap { position: absolute; left: 0; transform: translateX(-50%); white-space: nowrap; z-index: 3; } /* A TRANSFORM, NOT MARGIN, ON THE `bottom:100%` SIDE: Coherent ignores margin-bottom on an abspos box anchored that way (0/515 precedents in WG's _dist corpus). padding-bottom is the other form Coherent honours, but it would grow this cap's PADDING BOX -- which is what the out-of-flow .mp-ico's top:50% resolves against, dragging the glyph half the gap below the numeral. The `top:100%` twin's margin-top DOES work -- do not unify them. Both gaps are TICK-INCLUSIVE (tick height + the tuned gap) so no calc() mixes units. */ /* The signed X below is a RESIDUAL nudge (0 by default): the numeral is already on its tick by construction. Composed onto the same transform as the -50% centring. */ /* EVERY CAPTION PINS ITS LINE BOX, and that is a BUG FIX, not a style choice. With `line-height: normal` the line box is the font's ascent+descent+gap SNAPPED UP TO WHOLE DEVICE PIXELS, so in rem it is NOT constant -- it shrinks as the rem->px factor grows. Measured live: a 16rem caption is 21.000rem at factor 1, 20.500 at 2, 20.125 at 24; a 12rem one 16.000 / 15.500 / 15.083. The out-of-flow .mp-ico is `top: 50%` of exactly that box, so HALF the variation lands in the glyph's Y and the icon (and the delta, whose own box shrinks the same way) drift below the numeral at low interface scales -- reported at 3440x1440, factor 1. THE VALUE: ceil(font_rem * 2 * 1.2565) / 2, i.e. the FACTOR-2 box expressed in rem. 1.2565 is MoEBattle.ttf's fitted line ratio and ceil(font_px * 1.2565) reproduces all six measurements. Pinned at the FACTOR-2 value on purpose, not at the font's true unsnapped ratio: factor 2 is the render this composition was approved on and must not move by even one device pixel, while a `1.2565em` line-height would compute to 40.2px there and shift it 0.75px. So every pin here is byte-identical to what `normal` already yielded at factor 2; only factors != 2 change. NO LARGE-MODE TWIN, EVER: line-height is a uniform (vertical) length, so the root font (SIZE_F) scales it alone and a twin would double-apply it. NOT FIXED by this, and left as a known residual: the glyph's own ascent snap INSIDE the pinned box (sub-0.5rem, and it moves the numeral and its delta together rather than pulling them apart). ...AND THE PIN IS NOW LOAD-BEARING FOR A SECOND FIX, which is why it must not be reverted or turned back into an em: it makes each caption's box a CONSTANT number of rem, so the vertical anchor of the out-of-flow pieces hanging off it -- line/2 - own box/2 + the tuned nudge -- is a constant too, and CAN be quantised. It is not, however, a whole number of DEVICE pixels: at the shipped values it lands on a quarter of a rem (the current row's glyph: 20.5/2 - 16/2 + 0.5 == 2.75rem), which is whole only where the rem->px factor is a multiple of 4. At factor 2 it is a whole HALF pixel -- the approved render. At factor 1 (interface scale 1, reported at 3440x1440) it is 0.75 of a device pixel, so the engine resolves the glyph's box origin DOWN-SCREEN -- one device pixel low on the current-damage caption's icon, and on nothing else. THE RESIDUAL IS CORRECTED IN HAND-ADDED BLOCK 4 (the `.mp-s1` pair at the end of this file), gated on the interface scale by MoEBarTransient.setQuantClass so factor 2 -- the approved render -- cannot match any of it. The correction is a MEASURED -1rem, not this arithmetic: the anchor above says why a residual exists, it does not predict the number. See that block and tests/test_caption_anchor_quantisation.py. */ .mp-cap.dn { top: 100%; margin-top: 12rem; font-size: 12rem; line-height: 15.5rem; transform: translateX(-50%) translateX(0rem); } .mp-cap.up { bottom: 100%; font-size: 16rem; line-height: 20.5rem; transform: translateX(-50%) translateX(0rem) translateY(-12rem); transition: left 400ms cubic-bezier(.2,.8,.2,1); } .mp-cap .mp-v { position: relative; color: #ffffff; font-weight: 600; letter-spacing: 0em; text-shadow: 0 0 1rem rgba(0,0,0,0.5); } .mp-cap.dn .mp-v { transform: translateY(0rem); } .mp-cap.up .mp-v { transform: translateY(0rem); } /* The delta hangs OUT OF FLOW off the numeral's right edge (left:100% + a transform gap, the same idiom as .mp-ico's mirror on the right:100% side), so .on toggling cannot move the number -- and top:0 is an ANCHOR, not a position: the X gap and the signed Y both ride that ONE translate(), in ONE unit (the gap is tuned in em of the delta's own size and resolved to rem, since no Gameface-confirmed stylesheet mixes units in a multi-argument translate). It FADES on opacity, which interpolates; visibility cannot. JS adds .on at the hit and drops it after the hold. It is WHITE with NO band glow -- that glow is the current total's signal alone, so .mp-d-num appears in no band rule and needs no rule of its own; it inherits everything here and JS writes the signed digits into it. The dark text-shadow is legibility over a bright HUD, not a glow -- keep it. No parens on this bar: .mp-d carries the gap, size and fade, .mp-d-num alone carries the digits. */ .mp-cap .mp-d { position: absolute; left: 100%; top: 0; transform: translate(4.2rem, 2.5rem); font-size: 12rem; line-height: 15.5rem; color: #ffffff; font-weight: 600; text-shadow: 0 0 1rem rgba(0,0,0,0.5); opacity: 0; transition: opacity 500ms ease-out; } .mp-cap .mp-d.on { opacity: 1; } /* ---- BANDS. Exactly ONE of these classes on #moe-bar-root at a time, chosen by which requirement the current damage has passed (>= INCLUSIVE, so damage on r65 is already green). The fill and the current tick's GLOW share the band's fill colour (the tick's own line is the static colour above, so the marker reads the same at every band); the current TOTAL's numerals and the glyph glow further down take that band's two OWN glow colours, tuned per band. The delta (.mp-d-num) is in NONE of these -- it stays white with only the dark drop. */ #moe-bar-root.mp-b-w .mp-fill { background: rgba(237,230,217,0.8); } #moe-bar-root.mp-b-w .mp-tick.mp-cur { box-shadow: 0 0 6rem rgba(237,230,217,0.8),0 0 2rem rgba(237,230,217,0.8); } #moe-bar-root.mp-b-w .mp-cap.up .mp-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(237,230,217,0.5),0 0 2rem rgba(237,230,217,0.5); } #moe-bar-root.mp-b-g .mp-fill { background: rgba(123,236,55,0.8); } #moe-bar-root.mp-b-g .mp-tick.mp-cur { box-shadow: 0 0 6rem rgba(123,236,55,0.8),0 0 2rem rgba(123,236,55,0.8); } #moe-bar-root.mp-b-g .mp-cap.up .mp-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(123,236,55,0.9),0 0 2rem rgba(123,236,55,0.9); } #moe-bar-root.mp-b-t .mp-fill { background: rgba(51,146,230,0.8); } #moe-bar-root.mp-b-t .mp-tick.mp-cur { box-shadow: 0 0 6rem rgba(51,146,230,0.8),0 0 2rem rgba(51,146,230,0.8); } #moe-bar-root.mp-b-t .mp-cap.up .mp-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(90,154,211,1),0 0 2rem rgba(90,154,211,1); } #moe-bar-root.mp-b-v .mp-fill { background: rgba(115,23,196,0.8); } #moe-bar-root.mp-b-v .mp-tick.mp-cur { box-shadow: 0 0 6rem rgba(115,23,196,0.8),0 0 2rem rgba(115,23,196,0.8); } #moe-bar-root.mp-b-v .mp-cap.up .mp-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(115,23,196,1),0 0 2rem rgba(115,23,196,1); } #moe-bar-root.mp-b-au .mp-fill { background: rgba(255,205,90,0.8); } #moe-bar-root.mp-b-au .mp-tick.mp-cur { box-shadow: 0 0 6rem rgba(255,205,90,0.8),0 0 2rem rgba(255,205,90,0.8); } #moe-bar-root.mp-b-au .mp-cap.up .mp-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(255,205,90,0.9),0 0 2rem rgba(255,205,90,0.9); } /* Icons: GLYPH on ::after, GLOW on ::before at z-index:-1 (an element's own background paints BELOW its pseudos). .mp-ico's transform is the stacking context that scopes that -1 AND it carries the per-role Y nudge AND the gap to the numeral -- never trade it for a margin, which Coherent drops on the `right:100%` anchored side anyway. background-size is DERIVED: 100/bbox*0.75 from the ink measured at ALPHA > 32 (the quest_type art's faint halo makes a raw getbbox() read ~2x too big: barrel_mark 0.328, damage 0.219). brightness(3) lifts the flat grey #d1d1d1 quest_type line art; the marksOnGun cuts are 24x24 and already warm cream, so theirs is its OWN knob, at 1 here (1 == identity, no lift). Their canvas is constant and only the WIDTH grows with the count, so mark_1 renders ~1/3 the width of mark_3 on one fixed box -- correct, do not trim per count. They visibly blur above ~24rem. The icon is OUT OF FLOW off the numeral's left edge, and its gap rides in that SAME transform: `right:100%` + margin-right renders a 0 gap in Coherent, and `right: calc(100% + Xrem)` mixes % with rem (0/515 precedents in WG's corpus). */ .mp-ico { position: absolute; right: 100%; top: 50%; display: block; width: 13rem; height: 13rem; transform: translate(-1rem, -50%); } .mp-cap.dn .mp-ico { transform: translate(-1rem, -50%) translateY(0.25rem); } .mp-cap.up .mp-ico { transform: translate(-1rem, -50%) translateY(1rem); } /* The 100% cap's glyph is a DIFFERENT family from the three marks beside it, so it takes its own Y. (0,4,0) beats the rule above, and it stays on the same transform -- that transform is the stacking context that scopes the ::before glow's z-index:-1. */ .mp-cap.dn .mp-ico.bm { transform: translate(-1.253rem, -50%) translateY(0.4rem); } /* PER-ICON INK-GAP PARITY (maintainer's ask, box sizes untouched): the box-edge gap above is a uniform --icoGap, but each art asset's own zoom/canvas leaves a different INK gap, so these two literal X overrides equalise it instead, calibrated off the real PNGs' alpha>32 bbox to a flat 3.000rem target (this bar's own dmg/current icon -- untouched -- naturally lands ~3.006rem; every other row is calibrated to the flat 3.000rem target against it, same convention both MA passes used, and this bm literal is IDENTICAL to MoEProgress.css's dmgp -- same box (14rem), same asset (barrel_mark, 228.7%)). mk is calibrated to mark_2 ALONE (contain-scaled on a 24x24 canvas, box 16rem); mark_1/mark_3 land off it by +-2rem -- an accepted residual, same class as MoEProgress.css's own mark correction. Literal, not slider-driven: a box-size retune here would need these re-measured by hand, same as the horizontal Moving Average bar's own pass. */ .mp-cap.dn .mp-ico.mk { transform: translate(1rem, -50%) translateY(0.25rem); } /* PER-MARK, hand-tuned in tools/dev/icon_gap_tuner.html: r1/r2/r3 are three concurrent rows (unlike the Moving Average bar's single reused slot), each already statically classed mk1/mk2/mk3, so each gets its own full transform instead of sharing .mk's one residual value above. (0,4,0), tying .mk on specificity -- beaten by SOURCE ORDER (written after it), same convention as MoEProgress.css's identical split. */ .mp-cap.dn .mp-ico.mk1 { transform: translate(2.000rem, -50%) translateY(0.25rem); } .mp-cap.dn .mp-ico.mk2 { transform: translate(0.000rem, -50%) translateY(0.25rem); } .mp-cap.dn .mp-ico.mk3 { transform: translate(-1.500rem, -50%) translateY(0.25rem); } .mp-ico::before { content: ""; position: absolute; left: 50%; top: 50%; z-index: -1; width: 106%; height: 106%; transform: translate(-50%, -50%); background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } /* The requirement glyphs and the current one glow independently of that fallback. BACKGROUND ONLY: the base rule keeps the z-index:-1, the 106% box and its own centring, and these target ::before, never .mp-ico. The current cap follows its BAND, at the numeral-glow alpha. */ .mp-cap.dn .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(26,26,26,0.5) 0%, transparent 73%); } #moe-bar-root.mp-b-w .mp-cap.up .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(237,230,217,0.3) 0%, transparent 73%); } #moe-bar-root.mp-b-g .mp-cap.up .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(123,236,55,0.8) 0%, transparent 73%); } #moe-bar-root.mp-b-t .mp-cap.up .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(90,154,211,0.8) 0%, transparent 73%); } #moe-bar-root.mp-b-v .mp-cap.up .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(115,23,196,0.8) 0%, transparent 73%); } #moe-bar-root.mp-b-au .mp-cap.up .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.9) 0%, transparent 73%); } .mp-ico::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: no-repeat; background-position: center; } .mp-ico.mk { width: 16rem; height: 16rem; } .mp-ico.mk::after { background-size: contain; filter: brightness(1); } .mp-ico.mk1::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_1.png); } .mp-ico.mk2::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_2.png); } .mp-ico.mk3::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_3.png); } .mp-ico.bm { width: 14rem; height: 14rem; } .mp-ico.bm::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_barrel_mark.png); background-size: 228.7%; filter: brightness(3); } .mp-ico.dmg { width: 16rem; height: 16rem; } .mp-ico.dmg::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_damage.png); background-size: 342.5%; filter: brightness(3); } /* The transient + the 100% pulse. GAMEFACE: a transform transition needs MATCHING FUNCTION LISTS across every keyframe, so translateY() appears on ALL FOUR stops. Separate in/out easings inside one animation means per-stop animation-timing-function; the middle stop is linear so the hold cannot creep. The exit RETURNS the way it came. */ @keyframes mp-life{ 0%{opacity:0;transform:translateY(20rem);animation-timing-function:ease-in} 9.68%{opacity:1;transform:translateY(0rem);animation-timing-function:linear} 90.32%{opacity:1;transform:translateY(0rem);animation-timing-function:ease-in} 100%{opacity:0;transform:translateY(20rem)}} #moe-bar-root.mp-run{animation:mp-life 6200ms both} @keyframes mp-pulse{ 0%,100%{box-shadow:0 0 8rem rgba(255,205,90,0.9)} 50%{box-shadow:0 0 16rem rgba(255,205,90,1.00)}} #moe-bar-root.mp-b-au.mp-pulse .mp-track{animation:mp-pulse 1200ms ease-in-out infinite} /* Axis + timings for the Python/JS side (the numbers, not just the CSS): { "axis": "damage, five stops -> four equal quarters (barX in MoECalculator.js:302-322)", "dmgStopsSource": "snapshot.thresholds{1,2,3,100}", "barStops": [ 0, 25, 50, 75, 100 ], "fadeInMs": 600, "holdMs": 5000, "fadeOutMs": 600, "totalMs": 6200, "slideRem": 20, "slideEasingIn": "ease-in", "slideEasingOut": "ease-in", "fillDurationMs": 400, "fillEasing": "cubic-bezier(.2,.8,.2,1)", "deltaHoldMs": 1600, "deltaFadeMs": 500, "deltaFadeEasing": "ease-out", "pulseMs": 1200, "bands": [ { "name": "white", "cls": "mp-b-w", "colour": "rgba(237,230,217,0.8)" }, { "name": "green", "cls": "mp-b-g", "colour": "rgba(123,236,55,0.8)" }, { "name": "teal", "cls": "mp-b-t", "colour": "rgba(51,146,230,0.8)" }, { "name": "violet", "cls": "mp-b-v", "colour": "rgba(115,23,196,0.8)" }, { "name": "gold", "cls": "mp-b-au", "colour": "rgba(255,205,90,0.8)" } ], "capClamp": { "enabled": true, "leftRem": -76, "rightRem": 376 }, "boxWRem": 460, "glyphBbox": { "barrel_mark": 0.328, "damage": 0.219, "note": "ink measured at alpha>32 on the 128px canvas (a raw getbbox reads ~2x too big)" } } */ /* ===== HAND-ADDED BLOCK 2 OF 4 -- a byte-identical copy of @keyframes mp-life / #moe-bar-root.mp-run above, renamed. NOT tuned, and no tuned value touched. WHY: JS restarts the transient (a hit landing while the bar is already up re-measures the fade-out from that event) with the classic remove-class -> force-reflow -> re-add-class idiom, which is UNPROVEN in Coherent/Gameface. If the engine coalesces the re-add with the run it just cancelled, the restart is a NO-OP -- and because #moe-bar-root rests at opacity 0 under `both` fill, that leaves the bar permanently INVISIBLE after its first appearance. That is not a hypothesis: it is the exact reported symptom the Moving Average bar shipped with, and MoEProgress.css:512-529 carries this same pair for the same reason. So MoEEfficiency.js ALTERNATES between .mp-run and .mp-run-b (armRun): consecutive runs carry DIFFERENT animation-names, which the engine cannot coalesce. Keep the two blocks identical: any tuner change to mp-life must be mirrored here verbatim. Once a launch proves the plain restart works in Coherent, delete this pair and drop armRun's alternation. ===== */ @keyframes mp-life-b{ 0%{opacity:0;transform:translateY(20rem);animation-timing-function:ease-in} 9.68%{opacity:1;transform:translateY(0rem);animation-timing-function:linear} 90.32%{opacity:1;transform:translateY(0rem);animation-timing-function:ease-in} 100%{opacity:0;transform:translateY(20rem)}} #moe-bar-root.mp-run-b{animation:mp-life-b 6200ms both} /* ===== END HAND-ADDED BLOCK 2 ===== */ /* ===== HAND-ADDED BLOCK 3 OF 4 -- THE "LARGE" SIZE MODE (mod_settings.progress_bar_size == 1). NOT tuned, and no tuned value above is touched. The tuner has no size mode at all, which is why this cannot come out of the emit. WHY SO LITTLE CSS: the mode is delivered by the ROOT FONT SIZE (MoEBarTransient.js's SIZE_F == 1.25, which IS the rem->px factor in Gameface -- WG's own bootstrap writes it from self.onScaleUpdated, and our registered views never load that bootstrap, hence every "1rem == 1 logical px" comment in this mod). That single write re-lays the whole composition 1.25x larger, CRISPLY, and correctly leaves every %, em, `contain`, gradient stop and derived icon background-size ratio alone -- so height, every font, every icon box, every glow radius, the vertical gaps and mp-life's 20rem slide all scale with NO rule below. What is left is the HORIZONTAL x-lengths: an x-length must carry an extra SIZE_XF == 4/3 (1.25 * 4/3 == 5/3), so EVERY declaration below is an x-length and nothing else. Do NOT add a font-size, a height or a keyframe here -- that would double-apply SIZE_F. SCOPE: `.mp-lg` goes on the BODY (MoEBarTransient.applySize), WG's own ancestor-class idiom (.mediaLargeWidth ...). It cannot go on #moe-bar-root: #moe-bar-box is a body-level SIBLING of the JS-created root. Every selector is its base rule plus one class, so it out-specifies it (the .bm glyph needs its own line: without it the .mp-cap.dn .mp-ico rule below, being LATER in the file at equal specificity, would swallow that glyph's own Y). The .bm and .mk lines below are the Large twins of the emit's own per-icon ink-gap-parity overrides (see the emit's own comment above .mp-cap.dn .mp-ico.bm/.mk): literal, SIZE_XF (4/3) applied by hand to the Default literal, never re-derived from the shared --icoGap knob. .mk1/.mk2/.mk3 (SCOPE DECISION, the user's eye over the x4/3 contract): 1.000/0.000/-2.000rem, LITERAL, reported directly by tools/dev/icon_gap_tuner.html, NOT the Default row's (2.000/0.000/-1.500) times 4/3. r1/r2/r3 already carry static mk1/mk2/mk3 classes (MoEEfficiency.js's MARKUP), so no new plumbing -- same as the Default per-mark pass. mark_2's 0.000rem is a real tuned value despite the surface-mirror gate's own regex never classifying a zero translateX as an x-length (it looks for a NONZERO digit inside translate()'s first arg) -- added anyway, per the maintainer's explicit instruction. Both test_every_large_declaration_is_its_base_counterpart_times_four_thirds and test_the_large_block_twins_exactly_the_base_cascades_x_lengths knowingly fail on this trio (the first outright on mark_1/mark_3's values, the second additionally on mark_2 landing as a twin with no base x-length to match) -- left standing for qa to re-scope. .mp-cap.up .mp-ico's Y is 0.9rem, not icoyCur's plain 0.5 -- the maintainer's own "lower the top-row icon 0.5 device px" nudge, added on top of the existing 0.5: 0.5 (existing) + 0.5/1.25 (the new nudge, discounted so it renders as 0.5 device px under Large too, not 0.625) == 0.9. LITERAL here too, exempted from the x4/3 formula test the same way. ===== */ .mp-lg #moe-bar-box { width: 613.333rem; } .mp-lg #moe-bar-root { width: 400rem; } .mp-lg .mp-backdrop { left: -106.667rem; width: 613.333rem; } .mp-lg .mp-track::after { background-image: repeating-linear-gradient(90deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2.667rem,rgba(13,14,16,1) 2.667rem,rgba(13,14,16,1) 4rem); background-size: 4rem 100%; } .mp-lg .mp-tick { width: 2.667rem; } .mp-lg .mp-tick.mp-cur { width: 2.667rem; } .mp-lg .mp-cap .mp-d { transform: translate(5.6rem, 2.5rem); } .mp-lg .mp-ico { transform: translate(-1.333rem, -50%); } .mp-lg .mp-cap.dn .mp-ico { transform: translate(-1.333rem, -50%) translateY(0.25rem); } .mp-lg .mp-cap.up .mp-ico { transform: translate(-1.333rem, -50%) translateY(0.9rem); } .mp-lg .mp-cap.dn .mp-ico.bm { transform: translate(-1.671rem, -50%) translateY(0.4rem); } .mp-lg .mp-cap.dn .mp-ico.mk { transform: translate(1.333rem, -50%) translateY(0.25rem); } .mp-lg .mp-cap.dn .mp-ico.mk1 { transform: translate(1.000rem, -50%) translateY(0.25rem); } .mp-lg .mp-cap.dn .mp-ico.mk2 { transform: translate(0.000rem, -50%) translateY(0.25rem); } .mp-lg .mp-cap.dn .mp-ico.mk3 { transform: translate(-2.000rem, -50%) translateY(0.25rem); } /* ===== END HAND-ADDED BLOCK 3 ===== */ /* ===== HAND-ADDED BLOCK 4 OF 4 -- THE INTERFACE-SCALE CAPTION CORRECTIONS. The tuner has no notion of the interface scale, which is why this cannot come out of the emit. THE BUG: on the current-damage caption (.mp-cap.up), the damage ICON and the DELTA each sit ONE device pixel low at interface scale 1 and are both correct at scale 2. Measured on verified relaunches, same replay and tank at both scales, ink gated achromatically. MEASURE AGAINST THE DIGIT BASELINE, NEVER THE DIGIT TOP. The ink top is GLYPH-DEPENDENT -- it moves with WHICH digits are on screen -- and that is exactly the trap that hid the delta for a whole session: read against the top, the delta looked scale-invariant and only the icon looked wrong. Compare WITHIN the row, baseline-relative, on shots whose UP row is the same shape (both plain 3-digit, no comma): scale 1 (shot_050) scale 2 (shot_049, confirmed by _045) digits 1839..1850 1811..1833 delta 1841..1849 1813..1829 delta bottom - digit baseline -1.00rem -2.00rem <- the delta is 1rem LOW icon bottom - digit baseline -1.00rem -0.50rem <- residual 0.5rem, SUB-PIXEL at scale 1: on the grid, NOT to be touched (Anchor for the table: the track top is 1866 at scale 1 and 1860 at scale 2 in every shot, and the caption row sits at a different REM offset from the track at the two scales because of line-box rounding -- which is why only within-row, baseline-relative comparisons mean anything here. The icon's own correction was verified live: ink top 1841 -> 1840 at scale 1, scale 2 untouched.) EVERY -1rem HERE IS MEASURED AGAINST THE RENDER, NOT DERIVED FROM BOX ARITHMETIC. The anchor arithmetic (line/2 - own box/2 + nudge == 2.75rem, a quarter of a rem, whole only where the rem->px factor is a multiple of 4) explains WHY a residual exists at factor 1 and not at factor 2; it does not predict any of these numbers. EVERY VALUE IS ITS OWN BASE RULE'S Y MINUS EXACTLY 1rem (the icon 0.5 -> -0.5, the delta 2.5 -> 1.5), with the x term taken VERBATIM from that same base -- so a future retune moves the correction with it. ...PLUS, ON THE TWO LARGE RULES ONLY, A PER-PIXEL NUDGE EYEBALLED AGAINST THE LARGE RENDER AT INTERFACE SCALE 1. Distinct in kind from the -1rem above, which came off ink extents: these two are the maintainer's eye on the composition, so they are a CALIBRATION, not a derivation. icon 1 device px DOWN -0.5 + 0.8 == 0.3rem delta 1 device px UP 1.5 - 0.8 == 0.7rem 1 device px is 1/SIZE_F rem here, because Large IS the root font: baseFont * SIZE_F == 1 * 1.25, so 0.8rem exactly. The two nudges are INDEPENDENT -- they landed on the same 0.167rem at the earlier SIZE_F == 1.5 (a coincidence of two opposite nudges one rem apart) and no longer agree at SIZE_F == 1.25, and the delta's own pixel count moved again for a later 1px-down retune (2 device px UP -> 1 device px UP) while the icon's did not -- they must NEVER be factored into a shared constant. A future retune of a base Y has to carry BOTH terms (see the pin in tests/test_caption_anchor_quantisation.py, which re-derives each value as base - 1rem +/- an explicit device-PIXEL COUNT over SIZE_F). THE DEFAULT-SIZE PAIR TAKES NO NUDGE: both plain rules are verified live at scale 1 and stay at -0.5rem / 1.5rem. TWO RULES PER ELEMENT, AND THE SECOND IS A COMPOUND. Both classes land on document.body, so a lone .mp-s1 rule -- later in the file and at equal or higher specificity -- would also beat the `.mp-lg` twin and replace its x-length (the icon's -1.333rem with -1rem, the delta's 5.6rem with 4.2rem), shoving the element sideways at scale 1 + Large. `.mp-s1.mp-lg` (both classes on the SAME element, no descendant combinator) out-specifies the twin outright, so only Y moves. ALWAYS THE FULL COMPOUND TRANSFORM: a bare translateY() replaces the whole declaration and silently drops the icon's -50% centring (and the stacking context that scopes the ::before glow's z-index:-1) or the delta's whole x gap. INTERFACE SCALE 2 IS STRUCTURALLY UNMATCHABLE, which is the maintainer's hard constraint made mechanical rather than promised: setQuantClass reads the base font at/above 1.5 there and adds no class at all, so no selector here can match and the base cascade is bit-for-bit the approved render. Same for an untrusted read (see the trust gate in MoEBarTransient.js). ===== */ .mp-s1 .mp-cap.up .mp-ico { transform: translate(-1rem, -50%) translateY(0rem); } .mp-s1.mp-lg .mp-cap.up .mp-ico { transform: translate(-1.333rem, -50%) translateY(0.7rem); } .mp-s1 .mp-cap .mp-d { transform: translate(4.2rem, 1.5rem); } .mp-s1.mp-lg .mp-cap .mp-d { transform: translate(5.6rem, 0.7rem); } /* ===== END HAND-ADDED BLOCK 4 ===== */ PK!!x>><res/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiency.js// 14th_ua's MoE Calculator -- in-battle centre-screen DAMAGE EFFICIENCY bar. Front-end of a // STANDALONE OpenWG-registered Gameface view (MoEEfficiencyView.html, registered via // mods/configs/res_map/MoEEfficiencyView.json) that bridge/efficiency_view.py opens as a // CONTENT-SIZED (NOT full-screen), input-transparent window centred over the battle HUD. Do NOT // re-add full-screen sizing / width:100% -- see bridge/battle_view.py for the Ctrl+click/hover // input-steal that cost us. // // THIS IS THE RADIO ALTERNATIVE to the Moving Average bar (MoEProgress.js): Python opens exactly // ONE of the two, which is the only reason both stylesheets can own #moe-bar-root and the .mp-* // prefix. Never both in one document. // // TWO ORIENTATIONS, ONE DOCUMENT, and that is NOT a contradiction of the line above: this document // DOES a second stylesheet, MoEEfficiencyVertical.css, whose prefix (.mev-*) is disjoint from // .mp-* by construction -- so the only selectors that can collide are `body`, `#moe-bar-box` and // `#moe-bar-root`, and those three are the only ones the vertical sheet scopes under its `body.mev` // class. Which composition draws comes from mod_settings' progress_bar_orientation, pushed as the // VM's `vertical`, as a MOUNT-TIME branch (goVertical) -- NOT a second res_map layout, because a new // itemID would cost every user a one-time client restart. The PLACEMENT half is Python's and already // orientation-aware (bridge/bar_window._resolve). // // Because this is a registered view, OUR data model (EfficiencyVM) IS the view's own root // ViewModel: a bare ModelObserver() with NO feature name, fields read DIRECTLY off the root // (model.damage, ...). No nested submodel and NO unwrap dance -- that is only the garage's // nested-model path. // // WHAT THE BAR SHOWS: THIS battle's combined damage plotted against all FOUR of the tank's mark // requirements at once -- five damage stops [0, r65, r85, r95, r100] mapped onto four visually // EQUAL quarters. The four requirement ticks/captions are pinned at 25/50/75/100 % in the CSS; // only the fill, the current tick and its caption are positioned from here. // // AND THE AXIS ARITHMETIC IS NOT DONE HERE. Unlike MoEProgress.js (which derives its position from // the pushed axis ends), Python pushes `barX` (0..100 % of the bar) and `band` (0..4, the highest // requirement PASSED, `>=` INCLUSIVE) as finished values -- domain/battle_builder.efficiency_bar_x // and efficiency_band. Do NOT recompute either here: the inclusive-boundary rule must live in // exactly one place, and it is unit-tested there. The four r* props are for the CAPTION NUMERALS // only. `.met` on a requirement tick likewise comes off `band` (stop i is met iff i <= band), not // off a damage comparison. // // THE LOOK IS THE TUNER'S AND NOT NEGOTIABLE: MoEEfficiency.css is tools/dev/eff_bar_tuner.html's // emit verbatim (reproducible with `node tools/dev/emit_eff_css.js`) plus two marked hand-added // blocks, and this file is a port of that tuner's own preview pass (apply / showDelta / replay) // crossed with MoEProgress.js's proven transient machinery. Every number below is mirrored from // that stylesheet's trailing JSON `meta` block. The battle window has NO hot-reload (it pins its // resources at client launch), so every tweak here costs a full client relaunch: tune in the // browser, not in the client. // // pointer-events:none throughout (in the CSS) -- pure HUD info, never an input target. import { ModelObserver } from "../../libs/model.js"; // The transient machinery -- arming, the negative-delay debounce, the Alt peek's pause/seek, the // end race and the surface re-assert -- is SHARED with MoEProgress.js. Every behaviour in there cost // a client relaunch to find; read its header before changing anything that touches timing. // Separate documents, so this module is instantiated twice with no cross-talk. import { createTransient, fmt, SIZE_F, SIZE_XF } from "./MoEBarTransient.js"; // No feature name -> observe this view's OWN root model (window.model == EfficiencyVM). const observer = ModelObserver(); // meta.deltaHoldMs -- the delta's OWN, SHORTER window, this bar's only timing of its own. It is not // tied to the transient at all (that is the tuned intent: the increment is a flash, the bar is a 5s // readout), so it fades on .mp-d's own 500ms opacity transition well before the bar leaves. const DELTA_HOLD_MS = 1600; // --- the axis / clamp contract, also from `meta` ---------------------------------------------- // The bar's own width (#moe-bar-root), which every percentage resolves against and which the cap // clamp works in. meta.capClamp is the corridor the current caption may not leave, in the SAME // document-rem coordinates: the box is the 300rem track plus 80rem of pad each side, minus the // tuned 4rem end inset, i.e. [-76, 376]. const BAR_W_REM = 300; const CLAMP_L_REM = -76; // meta.capClamp.leftRem const CLAMP_R_REM = 376; // meta.capClamp.rightRem // The icon's gap to the numeral, which rides in .mp-ico's transform (translate(-1rem, -50%)) and // so is NOT part of its offsetWidth -- the clamp has to add it back, exactly as the tuner does. const ICO_GAP_REM = 1; // band -> the ONE class that goes on #moe-bar-root, in meta.bands order (white/green/teal/violet/ // gold). Python's `band` indexes straight into this. const BAND_CLASSES = ["mp-b-w", "mp-b-g", "mp-b-t", "mp-b-v", "mp-b-au"]; // The pushed LARGE size mode (VM `barSize`), mirrored here because capClampPct needs it -- it is the // one place on either bar that mixes a MEASURED px width with rem literals, so the 1rem == 1 logical // px identity it rests on breaks under the large mode's 1.25x root font. The transient owns everything // else about the flag (see its SIZE_F / SIZE_XF). let large = false; // --- the surface, and the rigid shift into it ---------------------------------------------- // A Gameface view PUSHES its own size to C++ through the `viewEnv` global // (viewEnv.resizeViewRem(w, h), rem == logical px); a view that never calls it gets the engine's // "default view size" fallback after a `Size calculation timeout` -- a flat 256x256 logical px. // There is NO Python-side and NO res_map lever for this (see bridge/efficiency_view.py), and // pushing the size is not sufficient on its own: the engine ALSO tries to measure the document and // ITS FALLBACK RUNS LAST AND WINS. See SURFACE_REASSERT_MS. // // The composition's bounding box, document origin at (0,0) and 1rem == 1 logical px, IS // .mp-backdrop -- left -80rem / top -40rem / 460 wide / 96 tall (MoEEfficiency.css; the emitted // value, asserted by tools/dev/check_eff_css.js). Everything else fits inside it with // room to spare, measured against the emit rather than guessed: // * TOP: the .mp-cap.up numeral's box bottom sits at -12rem (bottom:100% of the 3rem track, then // translateY(-12rem)), so at a 16rem font with its pinned 20.5rem line box its top is ~-32.5 // and its 6rem band glow reaches ~-38.5. Its out-of-flow glyph and the current tick's 6rem glow // are shallower still. // * BOTTOM: .mp-cap.dn tops out at 15rem (top:100% + margin-top:12rem) and its pinned 15.5rem // line box reaches ~30.5 -- its .mp-d delta (translate(4.2, 2.5)) hangs deeper still, to ~33. // * SIDES: .mp-cap.r4 sits at 100 % (x == 300) and the current caption's delta hangs off its // right edge, reaching ~375 at four digits -- which is precisely why meta.capClamp's right // bound is 376. The clamp below keeps it there whatever the digits do. // So the surface is that box plus PAD_REM of slack on all four sides, and the whole composition is // rigidly translated by that much so NOTHING sits at a negative coordinate -- an origin overflow // is clipped no matter how big the surface is. // // NOT A THIRD COPY: MoEProgressView.html's sizing shim is sized to that bar's surface, but THIS // document's #moe-bar-box is 460x51rem straight out of the tuner's emit (the bar plus its two // caption rows). Leave it emitted -- the box provably does not stop the size timeout anyway, so // its exact value buys nothing, and hand-editing it would be silent drift from the emit. // These five ARE this bar's surface contract and stay HERE, per bar. MoEBarTransient derives the // rest from them (its box*/pad arguments), exactly as this file used to: // VIEW_W_REM = BOX_W_REM + 2 * PAD_REM == 480 SHIFT_X_REM = PAD_REM - BOX_LEFT_REM == 90 // VIEW_H_REM = BOX_H_REM + 2 * PAD_REM == 116 SHIFT_Y_REM = PAD_REM - BOX_TOP_REM == 50 // SHIFT_Y_REM is MIRRORED (negated) in Python as // domain/constants.EFFICIENCY_ANCHOR_Y_SHIFT, so changing BOX_TOP_REM or PAD_REM moves the bar on // screen until that constant follows. The hit padding and the re-assert timing live in the shared // module (its HIT_MAGIC / SURFACE_REASSERT_MS -- both LOAD-BEARING, read its header). const BOX_LEFT_REM = -80; // .mp-backdrop's left == leftmost edge const BOX_TOP_REM = -40; // .mp-backdrop's top == topmost edge const BOX_W_REM = 460; // .mp-backdrop's width (== meta.boxWRem) const BOX_H_REM = 96; // .mp-backdrop's height const PAD_REM = 10; // slack for the shadow/glow bleed // --- THE VERTICAL ORIENTATION (mod_settings.progress_bar_orientation, pushed as the VM's // `vertical`) ------------------------------------------------------------------------------------ // A SECOND COMPOSITION IN THE SAME DOCUMENT, not a restyle of this one: its own stylesheet // (MoEEfficiencyVertical.css, ed alongside MoEEfficiency.css from MoEEfficiencyView.html), // its own namespace-disjoint prefix (.mev-*), its own DOM order (numeral BEFORE icon, delta LEFT of // the numeral) and its own surface. NO second res_map entry: orientation is a MOUNT-TIME branch, // and a new itemID would cost every user a one-time client restart. // // V_BOX_* IS .mev-backdrop, exactly as BOX_* above is .mp-backdrop. Note it is NOT a transpose of // these four -- the vertical tuner's own tuned lengths -- but its TOP and HEIGHT are IDENTICAL to // the vertical Moving Average bar's (-80 / 360), which is why the two share ONE Python shift // constant where their horizontal siblings need -50 and -44 apiece: // V_VIEW_W_REM = V_BOX_W_REM + V_PAD_X_REM V_SHIFT_X_REM = V_PAD_X_REM - V_BOX_LEFT_REM == 92 // + V_PAD_XR_REM == 98 (a SPLIT pad now -- see both constants' own notes below) // V_VIEW_H_REM = V_BOX_H_REM + 2 * PAD_REM // - V_CLIP_B_REM == 318 V_SHIFT_Y_REM = PAD_REM - V_BOX_TOP_REM == 90 // THE X AXIS IS NOT box + PAD_REM EITHER -- SAME DEFECT THE MOVING AVERAGE BAR ALREADY FIXED // (MoEProgress.js's V_PAD_X_REM note carries the mechanism in full; only the numbers differ here). // Every caption here is RIGHT-ANCHORED (`right: 100%`, MoEEfficiencyVertical.css's .mev-cap) and // grows LEFTWARD from a fixed edge, same as the sibling bar's captions, so "left" is the overflow // direction for every one of the maintainer's nudges below. // THIS WENT THROUGH TWO CORRECTIONS TO THE SAME BUG, because the first one watched only one // caption family: // PASS 1 (14rem): the per-mark gap pass (icon_gap_tuner.html) pushed mark_2/mark_3 far enough // that PAD_REM's flat 10rem no longer covered them. But that pass's own re-derivation used the // WRONG icon width for the mark rows (13rem, the shared base `.mev-ico` box) instead of the // 16rem `.mev-ico.mk` override the mark icons actually render at (CSS specificity: `.mev-ico.mk` // beats bare `.mev-ico`), AND it never checked `.mev-cap.bt` (the current-damage + delta row) at // all -- exactly the "a gate that only watches one caption" mistake the Moving Average bar's own // capC-is-the-extreme derivation already exists to warn against. // PASS 2 (52rem, this one): re-derives EVERY row, worst case, 4-digit+comma numerals throughout // (font-size / icon width / icon margin-left all read from the shipped CSS, never transcribed): // r1 (mk1, tx -2): 2 + 16(.mev-ico.mk) + (-1)(mk shared margin) + 26.64(numeral) + 1(halo) == 44.64 // r2 (mk2, tx -4): 4 + 16 + 0.5 + 26.64 + 1 == 48.14 // r3 (mk3, tx -6): 6 + 16 + 3.0 + 26.64 + 1 == 52.64 // tp (bm, tx -3+7=4, AFTER the maintainer's "move the top block left 4px" nudge, was tx 8): // -4 + 14(.mev-ico.bm) + 1.253 + 26.64 + 1 == 38.89 // bt (dmg, tx -3+6=3, AFTER the maintainer's "move the bottom block left 7px" nudge, was // tx 10): the BARE signed delta (no parens, unlike the sibling bar's) sits LEFT of the // numeral via its own translate(-4.2rem, ...), so it -- not the numeral -- is the worst // point: // -3 + 16(.mev-ico.dmg) + 1(shared margin) + 35.52("3,050" at 16rem) + 4.2(delta gap) // + 32.56("+2,970" at 12rem, sign+4digits+comma, no parens) + 1(halo) == 87.28 // .bt IS THIS FILE'S EXTREME (87.28 > 52.64 > 48.14 > 44.64 > 38.89), exactly as .mpv-capC is // for the Moving Average bar's sheet -- and by the SAME margin (each grew its own V_PAD_X_REM // by exactly its own nudge's device-px count and landed on ~4.5rem of margin, not a coincidence, // just two rows with the same shape being pushed by the same kind of nudge): // V_PAD_X_REM == 92 + V_BOX_LEFT_REM == 92 - 40 == 52 (allowance 92, reach 87.28, margin 4.72) // tests/test_efficiency_surface_mirror.py::test_the_vertical_captions_fit_inside_the_surface is // the GATE on all of this, re-deriving every row (not just the mark rows) from the stylesheet // rather than trusting this note. // GROWING THIS MOVES THE TRACK INSIDE THE SURFACE, so domain/constants.EFFICIENCY_MM_TRACK_X( // _LARGE) had to grow with it by the exact same amount (in logical px, i.e. *SIZE_F under Large) // or the visible bar would slide RIGHT into the minimap -- see that constant's own comment. // V_SHIFT_Y_REM is MIRRORED (negated) in Python as domain/constants.VERTICAL_ANCHOR_Y_SHIFT (-90, // -113 for Large == -round(90 * SIZE_F)). #moe-bar-box in MoEEfficiencyVertical.css is sized to the // derived surface -- and unlike the horizontal file's box (left at the tuner's own emitted 460x55, // deliberately not a surface copy) that one IS a third copy: keep it in lockstep. // // THE SURFACE IS THE ONLY SIDE THAT IS NOT box + PAD_REM, AND THAT IS THE WHOLE POINT (V_CLIP_B_REM). // Read the sibling MoEProgress.js's own V_CLIP_B_REM note first -- the mechanism, the engine clamp it // works around and the Large-mode reasoning are IDENTICAL and are written out once, there. Only the // two numbers differ, because the two vertical tuners' bottom gaps differ: // V_CLIP_B_REM == (V_BOX_H_REM + 2*PAD_REM) - (V_SHIFT_Y_REM + barLen + bottomGap) // == 380 - (90 + 200 + 28) == 62 // `bottomGap` 28 is THIS bar's tuned value (tools/dev/eff_bar_tuner_vertical.html:470), against the // Moving Average tuner's 30 -- a difference that used to be UNOBSERVABLE (both were below the shared // 90 of slack, so the clamp flushed either to the same place) and is observable now, which is exactly // why domain/constants' single MM_GAP_BOTTOM is split per bar in the same change. // The surface's below-the-track slack becomes 318 - 290 == 28 == the tuned gap exactly (290 is // V_SHIFT_Y_REM + barLen == domain/constants.MM_TRACK_Y, which this does NOT move). Under Large the // pushed surface is round(318 * SIZE_F) == 398 against MM_TRACK_Y_LARGE 363, i.e. 35 of slack == // 28 * SIZE_F exactly -- so the fixed 28 is unreachable there and the engine's flush delivers the // scaled gap, which is the sibling's 30 -> 37 case with this bar's own two numbers. // WHAT IT COSTS, DERIVED FROM THE SHIPPED CSS, is 3.5rem of clearance on the bottom caption's ink and // nothing else. .mev-cap.bt (MoEEfficiencyVertical.css) is `top: 100%` + `margin-top: 3rem` off the // track's bottom end and its flex row is `line-height: 20.5rem` tall (the numeral's line box beats its // 16rem .dmg icon; the delta is position:absolute and contributes no height at all), so its box ends // 3 + 20.5 == 23.5rem below the track; the numeral's 1rem dark-drop text-shadow radius reaches 24.5, // the icon's translateY(0.5rem) + its ::before 106% glow (3% of 16rem) reaches 22.2, and the delta -- // `top: 0` + translate(_, 1.5rem), 15.5rem tall, + 1rem of drop -- reaches 21.0. So the deepest ink is // 24.5 against 28 of slack. The ONLY thing past the edge is the band glow's soft tail (the 6rem blur // on .mev-cap.bt .mev-v under every #moe-bar-root.mev-b-* band, reaching ~29.5), which the tuner clips // at its own stage bottom at the same 28. // THE 256x256 SIZE-TIMEOUT FALLBACK STILL RUNS LAST AND STILL WINS here, and the vertical surface is // pushed and RE-ASSERTED after the deadline by the same shared machinery (MoEBarTransient's // SURFACE_REASSERT_MS); each push round-trips back as onSizeChanged -> bar_window._place, which is // what makes the placement agree with the surface. // FOUR DURABLE FACTS, established by reading the source rather than assuming (a maintainer once // saw the minimap's first column "covered by a dark panel" and the fix took four rounds to land): // 1. THE BACKDROP IS NOT MEANT TO COVER THE RIGHT-ANCHORED CAPTIONS -- only V_PAD_X_REM (above) // was ever sized for their ink. .mev-backdrop is a SEPARATE rectangle, drawn for the // shadow/glow bleed around the TRACK, and r1-r3/tp/bt already reach far past it by design (see // the V_PAD_X_REM derivation above -- 38.89 to 87.28rem, against a 40rem backdrop bleed). Do // not "fix" a clip by widening the backdrop; that is V_PAD_X_REM's job, on the SURFACE, which // is never drawn. // 2. THE VERTICAL BAR'S BACKDROP HAS NO SYMMETRY CONTRACT. The symmetry test in this repo // (`test_the_large_backdrop_stays_symmetric_about_the_track`) covers ONLY the HORIZONTAL bar's // `.mp-backdrop`, because `anchor_centred_reduced`'s `max_x // 2` has no X term and only // centres the BAR by centring the SURFACE -- true for the Damage Log (horizontal) anchor. // Fixed+Vertical resolves through `anchor_minimap` instead (bar_window._resolve), whose // `x = space_x - mm_size - gap - overhang - edge_x` reads `edge_x` (EFFICIENCY_MM_TRACK_X) and // NOTHING about the backdrop's own width or left. Trimming `.mev-backdrop` asymmetrically // (this file's own V_BOX_W_REM, leaving V_BOX_LEFT_REM alone) moves nothing the placement math // depends on. // 3. THE BACKDROP TRIM (V_BOX_W_REM 96 -> 54) WAS REAL WORK -- KEEP IT. A maintainer report of // the backdrop "sitting well clear of the minimap" turned out to describe a DIFFERENT panel; // measured live on the sibling Moving Average bar (same mechanism, same minimap edge), this // bar's own backdrop right edge (V_PAD_X_REM + V_BOX_W_REM == 52+54==106) landed EXACTLY on // the minimap's own left edge (EFFICIENCY_MM_TRACK_X + MM_GAP + MM_TICK_OVERHANG == // 95+8+3==106) -- zero overlap, by design, at the tuned 54, AT THE TIME (the shared MM_GAP // was 8). Reverting to 96 (right edge 148) would reopen a real 42rem overlap. Do not touch // V_BOX_W_REM again without a live measurement to justify it. // SINCE THEN, PLACEMENT MOVED CLOSER TO THE MINIMAP (domain/constants.EFFICIENCY_MM_GAP // (_LARGE), 3/3, replacing the shared MM_GAP(8) for this bar's own anchor) -- the backdrop's // own DRAWN right edge no longer sits flush with the minimap's now-closer left edge. Not a // regression: fact 4 below already established the DRAWN backdrop is not what clears the // minimap, the invisible SURFACE is (V_PAD_XR_REM/_LARGE), and the surface still clears it // with a real, checked margin at the new gap -- see V_PAD_XR_REM's own derivation below. // 4. THE ACTUAL CULPRIT WAS THE INVISIBLE SURFACE'S OWN RIGHT PAD, NEVER UPDATED TO MATCH. The // backdrop trim shrank the DRAWN rect; nothing shrank the SURFACE (the mouse-hit-blocking rect // per this file's header) on that side, so it stayed the OLD symmetric V_PAD_X_REM(52) past // the ALREADY-TRIMMED backdrop -- see MoEBarTransient.js's `padXR`/`padXRLarge` arg notes for // the fix (a SEPARATE, smaller right pad, V_PAD_XR_REM/_LARGE below) and V_PAD_XR_REM's own // derivation, mirroring the sibling Moving Average bar's live-measured diagnosis exactly. // Because the fix only shrinks the RIGHT pad and V_PAD_X_REM (the LEFT side, where the caption // ink and the track itself both live) is untouched, `shiftX` and therefore // EFFICIENCY_MM_TRACK_X(_LARGE) -- both pure functions of the LEFT side alone -- need no // correction, and the bar does not move on screen. const V_BOX_LEFT_REM = -40; // .mev-backdrop's left const V_BOX_TOP_REM = -80; // .mev-backdrop's top const V_BOX_W_REM = 54; // .mev-backdrop's width (right edge only, trimmed -- see fact 3) const V_BOX_H_REM = 360; // .mev-backdrop's height const V_CLIP_B_REM = 62; // backdrop bleed the SURFACE clips off the bottom const V_PAD_X_REM = 52; // the LEFT X slack, decoupled from the backdrop -- see above // THE SURFACE'S RIGHT (minimap-facing) PAD -- see the sibling MoEProgress.js's own V_PAD_XR_REM note // for the full mechanism; only the numbers differ here, and it is a SEPARATE knob from the backdrop's // own V_BOX_W_REM trim above: that trim shrinks what is DRAWN, this shrinks what is CLICK-BLOCKING // (the surface, never drawn). // UNLIKE THE MOVING AVERAGE BAR, EFFICIENCY_MM_TRACK_X CARRIES NO HAND CORRECTION ("pure derivation, // no correction" -- domain/constants.py's own comment), so it IS this bar's true local tick position // and needs no re-derivation the way the sibling file's fact 5 does. Solved against // MoEBarTransient.applySize's own formula (viewW == round((boxW*xf + padX + padXR) * f)) for the // tick's own visible right edge PLUS a small, deliberate MARGIN (+2 logical/document px, flat, NOT // xf-scaled) -- a flush boundary (viewW == tick-right exactly, zero margin) is the "rounding could // shave a px and eat the ink" risk the margin exists to head off, mirroring the sibling file's fact 5: // Default (xf=f=1): tick-right == 95 + 3 == 98 -> viewW == 98 + 2 == 100 -> // padXR == 100 - V_BOX_W_REM(54) - V_PAD_X_REM(52) == -6 // Large: tick-right_pre_f == 137/SIZE_F... computed directly, not via the rounded PX constant: // shiftX_large_pre_f(316/3) + trackW_large(4) + overhang_large_pre_f(4) == 340/3 ~= 113.333 // (renders at 113.333*SIZE_F ~= 141.667 device px) -> viewW_pre_f == 340/3 + 2 == 346/3 ~= 115.333 // -> round(115.333 * SIZE_F) == 144 -> padXRLarge == 346/3 - boxW*xf(72) - V_PAD_X_REM(52) == // -26/3 ~= -8.667 // Both NEGATIVE: the box+left-pad sum (54+52==106 Default, 72+52==124 pre-SIZE_F Large) was flush // with the minimap at the ORIGINAL shared MM_GAP(8) (fact 3), so ANY margin (to the tick, or to // the minimap) needed the surface a shade smaller still -- the surface's right edge sits a little // further inside the backdrop's own (already trimmed) drawn rect than its own edge. This // derivation (padXR/padXRLarge themselves) is UNCHANGED by the later gap move -- pure JS/CSS // geometry, independent of where Python places the window -- but the MARGIN it buys against the // minimap moved WITH that gap. Resulting margins, both real and checked // (tests/test_efficiency_surface_mirror.py::test_the_surface_clears_the_minimap_at_every_size_index / // test_the_surface_does_not_clip_the_tick), at domain/constants.EFFICIENCY_MM_GAP(_LARGE) == 3/3: // Default clears the minimap by 1px (was 6px at the original shared gap of 8) and the tick by // 2px; Large by 1px (was 6px) and ~2.3px respectively. // ADVANCED 4 logical px into the minimap (2026-08-12, in-client): the previous margin==1 cleared the // minimap's DROP-SHADOW but left the backdrop 4px off the minimap's REAL edge -- that 4px is the // minimap's non-interactive frame margin, maintainer-confirmed safe to consume (Ctrl-click area is // further in). Surface right edge (and the flush strips) now at margin == -3, flush to the minimap: // Default: view_w == 8 + 3 + 95 - (-3) == 109 -> padXR == 109 - V_BOX_W(54) - V_PAD_X(52) == 3 // Large: view_w == 8 + 5 + 137 - (-3) == 153 -> padXRLarge == 153/SIZE_F - boxW*xf(72) - 52 // == 122.4 - 124 == -1.6 const V_PAD_XR_REM = 3; // the RIGHT (minimap-facing) X slack, Default const V_PAD_XR_REM_LARGE = -1.6; // ...and Large -- its OWN literal, see above // THE LIVE ORIENTATION PROFILE -- see the sibling MoEProgress.js for the same three-value shape. // PFX the class prefix every selector and toggled class here is written in. The source spells // everything "mp-..." and ns() rewrites it, so the literals stay greppable. // AX the property a marker's position is written to: `left` / `bottom` (0% at the BOTTOM). // GROW the property the fill grows along: `width` / `height`. // CAP_C_AX the axis the CURRENT caption tracks, or null if it does not move. It is null on the // vertical composition, where the current value + delta are a STATIC readout below the // track's bottom end and only the current TICK follows the fill -- which also retires // capClampPct entirely there (a static caption cannot overflow the corridor). let PFX = "mp"; let AX = "left"; let GROW = "width"; let CAP_C_AX = "left"; function ns(s) { return PFX === "mp" ? s : s.replace(/\bmp-/g, PFX + "-"); } // THE HORIZONTAL COMPOSITION'S MARKUP (the vertical one is V_MARKUP below; ensureRoot builds this // one and goVertical replaces it). Markup shape is the tuner's stage verbatim // (eff_bar_tuner.html:333-351): backdrop, then the track carrying the fill, the four FIXED // requirement ticks, the one moving current tick, the four requirement captions (three marksOnGun // glyphs + the barrel_mark at 100 %) and the current caption with its BARE signed delta -- no // parens on this bar, unlike the Moving Average one. The .mp-d / .mp-d-num split stays anyway: the // wrapper carries the gap, size and fade, the inner numeral is what JS writes the digits into (see // the CSS). NO word labels anywhere: MoEBattle.ttf is a 19-glyph numeric subset // (digits % ( ) + - , . / space) and a letter renders BLANK. const MARKUP = '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; // ...and THE VERTICAL COMPOSITION'S markup, tools/dev/eff_bar_tuner_vertical.html's stage verbatim. // FOUR structural differences from the horizontal template above, all of them the tuner's tuned // layout and none free to "tidy": // * NUMERAL BEFORE ICON in every caption (the icon trails, away from the track), and the DELTA // FIRST on the current caption. That ordering is what makes the shared right:100% anchor // digit-count invariant: the icon is the LAST in-flow child, flush against a FIXED edge, so only // the numeral grows and it grows leftward. Reversing it re-introduces the exact defect that // shipped once on the horizontal Moving Average bar. // * the four requirement captions split by ROLE, not one `dn` class: r1-r3 are `lf` (each beside // its own 25/50/75% tick) and r4 is `tp` (a static cap above the track's TOP end), because a // vertical axis has no single "below the track" side to share. // * the current caption is `bt mev-capC` -- a static cap below the BOTTOM end. It keeps mev-capC // purely so the ref lookup below is one selector for both orientations. // * every caption is a SIBLING of .mev-track rather than a child, exactly as the tuner has them // (root and track are the same 3x200rem box, so every percentage resolves identically; this // only keeps the diff against the tuner readable). const V_MARKUP = '
' + // Per-row dither strips (MoEEfficiencyVertical.css .mev-bd) -- one per number row, each // flush on the surface's minimap-facing edge. Positioned purely by CSS `top`. '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; function ensureRoot() { let root = document.getElementById("moe-bar-root"); if (root) return root; root = document.createElement("div"); root.id = "moe-bar-root"; root.innerHTML = MARKUP; document.body.appendChild(root); return root; } const root = ensureRoot(); // `let`, not `const`, because goVertical() rebuilds the root's contents under the .mev- prefix and // every ref has to be re-queried against the new nodes. Under a single orientation nothing rewrites // them. `.mp-capC` (not the old `.mp-cap.up`) is the current caption's lookup on BOTH orientations: // the vertical composition's equivalent role class is `bt`, not `up`, so the shared marker class is // what makes one ns()-rewritten selector serve both. let fill = root.querySelector(".mp-fill"); let tCur = root.querySelector(".mp-tick.mp-cur"); let reqTicks = [1, 2, 3, 4].map(function (i) { return root.querySelector(".mp-tick.r" + i); }); let reqCaps = [1, 2, 3, 4].map(function (i) { return root.querySelector(".mp-cap.r" + i); }); let capC = root.querySelector(".mp-capC"); let capD = capC.querySelector(".mp-d"); let capDN = capC.querySelector(".mp-d-num"); // ADOPT THE VERTICAL COMPOSITION -- the bar's half of MoEBarTransient's onVertical hook (the shared // module owns the surface, the rigid shift, the run-identity pair and the body scope class). Called // ONCE, inside engine.whenReady, BEFORE the surface push and before the first render, so nothing // downstream ever sees the horizontal DOM. A mid-battle Orientation change re-mounts this document // (Python closes and reopens the window -- battle_bridge.apply_settings) and comes straight back // through here; there is deliberately no live re-composition path. function goVertical() { PFX = "mev"; AX = "bottom"; GROW = "height"; CAP_C_AX = null; // a STATIC bottom cap here -- see the profile note root.innerHTML = V_MARKUP; fill = root.querySelector(".mev-fill"); tCur = root.querySelector(".mev-tick.mev-cur"); reqTicks = [1, 2, 3, 4].map(function (i) { return root.querySelector(".mev-tick.r" + i); }); reqCaps = [1, 2, 3, 4].map(function (i) { return root.querySelector(".mev-cap.r" + i); }); capC = root.querySelector(".mev-capC"); capD = capC.querySelector(".mev-d"); capDN = capC.querySelector(".mev-d-num"); } function capV(c) { return c.querySelector(ns(".mp-v")); } // --- the pushed state --------------------------------------------------------------------- // `cur` is the latest push; `last` is the previous one. `last === null` means "no baseline yet": // the FIRST push after mount (and after any re-show) seeds the latch silently, so the bar does not // appear at battle start. (There is deliberately no `rev` counter on EfficiencyVM -- the battle // window is a private, always-compositing view and has never needed the garage's cold-mount signal.) let cur = { damage: 0, barX: 0, band: 0, r: [0, 0, 0, 0], battleEpoch: 0 }; let last = null; // --- THE DELTA LATCH (derived HERE; EfficiencyVM carries no damageDelta) -------------------- // `peak` is the HIGH-WATER mark of this battle's combined damage, deliberately NOT the previous // push's value: combined damage SUBTRACTS team damage, so the total can move DOWN, and the latch // must measure only the rise above the highest total already seen -- a friendly-fire dip followed // by a hit reports the gain over the old peak, never the dip plus the hit. `delta` then PERSISTS // until superseded, because an efficiency tick that moved nothing (a spot, a dip, an arena period // change, an Alt press) must keep showing the increment the player is reading; 0 == none yet. // // A NEW HIGH-WATER MARK IS ALSO THE ONLY THING THAT MAY POP THE BAR OPEN (see `gained` in render). // "The value changed" and "the player gained damage" are NOT the same event: team damage // subtracting from the combined total changes the value, and re-showing the bar for it would // re-flash an increment the player has already read, carrying no new information. // // `epoch` is the battleEpoch `peak`/`delta` belong to. Python bumps a monotonic counter once per // battle mount (bridge/battle_bridge._battle_epoch) and pushes it on every efficiency tick, so a // change in it IS the battle boundary -- there is no longer any inference from the total having // restarted low (battle N+1's first tick can read higher than battle N's peak, and then an Alt peek // early in N+1 rendered N's stale increment). It deliberately does NOT live in `last`: a hide drops // that baseline mid-battle, while the latch has to survive one. 0 == the counter's value before the // first battle, so the first push of the first battle resets an already-empty latch for free. // // NO COMPARISON MAY NAME `damage` ON ITS OWN LINE. tools/dev/check_efficiency_js.js scans the // comment-stripped source for a comparison operator sharing a line with `damage` or an r* stop, // because the rule it guards is that the `>=`-INCLUSIVE damage-vs-REQUIREMENT test lives in Python // (domain.efficiency_band) and nothing here may re-derive it. This latch is damage-vs-damage and // touches no requirement, so it reads the total into `total` first and compares THAT. let peak = 0; let delta = 0; let epoch = 0; // The delta's own fade-out timer -- this bar's ONLY animation state of its own. Everything else // (arming, the run clock, the peek pause/seek, the end race, the surface settle) lives in the shared // transient below. let deltaT = null; // The current caption may not leave the box: it is centred on its tick, but its glyph hangs off the // left and its delta off the right, so at 100 % the delta would overflow. Reproduces the tuner's // capLeft() (eff_bar_tuner.html:716-729) in meta.capClamp's rem corridor -- and .mp-cap's // offsetWidth is the NUMERAL only (the icon and the delta are out of flow), which is why the larger // of the two overhangs is added back, the icon's with its transform gap. A zero measured width // (nothing laid out yet) simply degrades to no clamp. // // THE TWO SIZE FACTORS BOTH LAND HERE, and this is the ONE function on either bar where the // 1rem == 1 logical px identity is load-bearing rather than incidental: // * every rem CONSTANT above is an x-length (the bar's width, the corridor's two bounds, the icon's // transform gap), so each takes SIZE_XF -- the corridor bounds included, since they are the // backdrop inset by an equal x-length each side and so scale with it; // * offsetWidth is MEASURED PX, and under the large mode's root font 1rem is SIZE_F px, so // every measurement is divided back into document rem. A caption's width in rem is unchanged by // the root font (its font-size is a rem too), which is exactly why this cannot be normalised // away: the corridor scales by SIZE_XF while the caption inside it does not. function capClampPct(p) { const xf = large ? SIZE_XF : 1; const px = large ? SIZE_F : 1; const w = function (q) { const n = capC.querySelector(q); return ((n && n.offsetWidth) || 0) / px; }; const half = (capC.offsetWidth || 0) / 2 / px + Math.max(w(".mp-ico") + ICO_GAP_REM * xf, w(".mp-d")); const lo = CLAMP_L_REM * xf + half; const hi = CLAMP_R_REM * xf - half; let x = p / 100 * BAR_W_REM * xf; if (lo <= hi) x = Math.max(lo, Math.min(hi, x)); return x / (BAR_W_REM * xf) * 100; } // Position the fill, the moving tick and its caption from the PUSHED barX (never recomputed here). // No rewind/snap variant and no transition suppression, unlike MoEProgress.setPos: this bar has a // single set of values, so the CSS's 400ms fill/left transitions may always run -- exactly what the // tuner's own hit() does. On a cold entry they run under the 600ms fade-in and are invisible. // THE AXIS IS A PAIR OF PROPERTY NAMES, not two code paths: GROW is the fill's growth property // (`width` horizontally, `height` vertically -- 0% at the BOTTOM) and AX the current tick's position // property (`left` / `bottom`). CAP_C_AX is null on the vertical composition, where the current // caption is a static readout below the track's bottom end -- so capClampPct, whose whole job is // keeping a MOVING caption inside a horizontal corridor, is not reached there at all. function setPos(x) { const p = x.toFixed(3) + "%"; fill.style[GROW] = p; tCur.style[AX] = p; if (CAP_C_AX) capC.style[CAP_C_AX] = capClampPct(x).toFixed(3) + "%"; } // Everything that does NOT animate: the four requirement numerals, which of them are met, the band // class and the 100 % pulse, and the current numerals. Safe to re-run on every push. // `.met` AND the band come off the PUSHED `band` index -- stop i (1-based) is met iff i <= band. // That is not a shortcut: it is how the `>=`-inclusive rule stays in Python only. function paintStatic() { for (let i = 0; i < 4; i++) { capV(reqCaps[i]).textContent = fmt(cur.r[i]); reqTicks[i].classList.toggle("met", i + 1 <= cur.band); } BAND_CLASSES.forEach(function (c, i) { root.classList.toggle(ns(c), i === cur.band); }); // The pulse rule is #moe-bar-root.mp-b-au.mp-pulse .mp-track, so this class is inert off gold // anyway -- gate it on the band regardless, so the DOM says what it means. root.classList.toggle(ns("mp-pulse"), cur.band === 4); capV(capC).textContent = fmt(cur.damage); capDN.textContent = (delta > 0 ? "+" : "") + fmt(delta); } // The delta SNAPS in on a hit, holds for its own DELTA_HOLD_MS, then fades out on .mp-d's 500ms // opacity transition. The snap is the shipped cancel idiom (transition:none -> set -> force a // reflow -> hand the transition back) so the appearance is instant AND a half-finished fade from // the previous hit can never bleed into this one. Ported from the tuner's showDelta() // (eff_bar_tuner.html:736-741). Only a GAIN (a new high-water mark) calls this -- an Alt peek, a // flat tick and a team-damage dip all show the latched numerals without re-flashing an increment // that already had its moment. function showDelta() { clearTimeout(deltaT); capD.style.transition = "none"; capD.classList.add("on"); void root.offsetWidth; capD.style.transition = ""; deltaT = setTimeout(function () { capD.classList.remove("on"); }, DELTA_HOLD_MS); } // THE TRANSIENT. Everything shared with MoEProgress.js -- arming and its negative-delay debounce, // the run clock, the Alt peek's pause/plateau-seek/resume, the animationend-vs-timer end race, the // surface push + re-assert. This bar needs only ONE of the hooks: a tail on endRun/reset to drop the // delta, so a hold longer than the transient cannot leave it showing on the next entry. // NO onRewind and NO onCommit: unlike the Moving Average bar this one has a single set of values, so // there is nothing to rewind before a cold entry and nothing to commit after it -- the CSS's 400ms // fill/left transitions may always run, exactly as the tuner's own hit() does (see setPos). const T = createTransient({ root: root, boxLeft: BOX_LEFT_REM, boxTop: BOX_TOP_REM, boxW: BOX_W_REM, boxH: BOX_H_REM, pad: PAD_REM, onEnd: dropDelta, onIdle: dropDelta, // THE VERTICAL COMPOSITION. `cls` is the body scope class MoEEfficiencyVertical.css hangs off AND // the key to that stylesheet's own re-trigger keyframe twin (MoEBarTransient's RUN_CLASSES_V); // `box` replaces the four box* arguments above. Adopted at mount iff the model's `vertical` is // true, which then calls goVertical above for the DOM half. vert: { cls: "mev", box: [V_BOX_LEFT_REM, V_BOX_TOP_REM, V_BOX_W_REM, V_BOX_H_REM], clipB: V_CLIP_B_REM, padX: V_PAD_X_REM, padXR: V_PAD_XR_REM, padXRLarge: V_PAD_XR_REM_LARGE }, onVertical: goVertical, }); function dropDelta() { clearTimeout(deltaT); capD.classList.remove("on"); } function render(model) { // Truthy guards, not `=== false`: a root VM whose flags are still undefined before Python's // first push must stay hidden, not paint a zero-width bar over the HUD. hasData false means the // per-tank threshold table gave no usable five-stop axis -- there is nothing to plot. (Note the // documented asymmetry: the battle path has no offline estimator fallback, so on a tank whose // WG fetch failed this stays blank while the garage bar still draws. Not a bug here.) if (!model || !model.visible || !model.hasData) { root.style.display = "none"; T.reset(); // Drop the change-detect baseline too, so a later re-show starts COLD and the next push // becomes a fresh silent one (a scoreboard opening and closing must not replay the bar). // `peak` / `delta` deliberately SURVIVE -- render()'s first-push branch re-seeds them. last = null; return; } root.style.display = ""; // The pushed size mode (mod_settings.progress_bar_size), BEFORE setPos: capClampPct reads it. The // transient owns the rest of the flag (the root-font write, the .mp-lg body class, the re-derived // surface) and is idempotent, so this is just "keep it in sync". large = Number(model.barSize) === 1; T.size(large); // The pushed TRANSITION switches (mod_settings.progress_transitions_events / _manual, with the // Transitions master already ANDed in Python -- there is no master field to read here). The // transient only records them; the arming path decides per run. Passed RAW, deliberately: the // transient reads an ABSENT field as animated (see applyAnim), which is the fail-soft direction -- // a `!!` here would turn a missing prop into "instant" instead. T.anim(model.transEvents, model.transManual); // The pushed HOLD DURATION (mod_settings.progress_hold_seconds * 1000). Passed RAW for the same // reason as the two switches: the transient reads an absent / non-positive field as the baked // 5000ms (see applyHold), which is the fail-soft direction -- a `|| 0` here would mean no hold. T.hold(model.holdMs); // The pushed CTRL key state (battle_bridge._ctrl_held): the drag-to-reposition gesture, which // opens the input hit rect and holds the bar up for as long as the key is down. Passed RAW like // the three above -- the transient tests it with `=== true`, so an absent field reads as NOT // held, which is the fail-soft direction HERE (an open hit rect would steal HUD input). Ahead // of T.peek() below, which ORs this state in. T.ctrl(model.ctrlHeld); cur = { damage: Number(model.damage) || 0, barX: Number(model.barX) || 0, // Clamped defensively to the classes that exist -- an out-of-range index would otherwise // leave the root with NO band class and an unstyled (invisible) fill. band: Math.max(0, Math.min(BAND_CLASSES.length - 1, Number(model.band) || 0)), r: [Number(model.r65) || 0, Number(model.r85) || 0, Number(model.r95) || 0, Number(model.r100) || 0], battleEpoch: Number(model.battleEpoch) || 0, }; const first = last === null; last = cur; // The latch (see `peak`), run BEFORE paintStatic because that is what writes the numeral. The // two reset cases are told apart by the PUSHED epoch, not inferred from the total: // * a re-show MID-BATTLE (a scoreboard closing, hasData arriving) -- same epoch, so the mark // is re-seeded off the current total (nothing is claimed for damage dealt while this // document was not watching) and the latched increment survives, exactly as the Python // latch survived a hide; // * a NEW BATTLE -- a different epoch, so the previous battle's increment is dropped, which is // what _on_mount_refresh used to do. Deliberately 0 and not "the whole accumulated total as // one increment": the first tick of a battle is not a hit. // `gained` is the SHOW/FLASH trigger and only a new high-water mark sets it -- a flat push or a // dip repaints below (paintStatic/setPos always run) but must not pop the bar or re-flash. const total = cur.damage; const newBattle = cur.battleEpoch !== epoch; epoch = cur.battleEpoch; let gained = false; if (newBattle) delta = 0; if (first || newBattle) { peak = total; } else if (total > peak) { delta = total - peak; peak = total; gained = true; } paintStatic(); setPos(cur.barX); // THE SHOW TRIGGER IS GATED ON T.settled(); the silent baseline above is NOT. Before the // re-assert the surface is the engine's 256x256 fallback: the bar would come up cropped and // badly mis-placed (see the shared module's SURFACE_REASSERT_MS). The baseline shows nothing, so // it costs nothing to let it run -- and it MUST run, or `last` never gets recorded and the first // real hit is missed. T.show() picks warm-vs-cold off its own `showing`. // // ALSO GATED ON `showEvents` (mod_settings.progress_show_events, with "Always" already folded in // Python). `!== false`, NOT `!!`: a model without the field (a pre-push frame, a harness // fixture) must degrade to the SHIPPED behaviour, which is "a hit raises the bar". The delta // caption rides the same gate -- with the bar staying down there is nothing to flash. "Alt // Press" and "Always" need no branch here: both arrive folded into `altHeld` below. if (gained && model.showEvents !== false && T.settled()) { showDelta(); T.show(); } // Alt is handled AFTER the value change so a push that carries both (Python re-pushes on every // Alt transition) gets the new target AND the peek hold. An Alt held BEFORE the surface settled // is not lost: the settle re-renders the current model, which arrives here with altHeld still // true and peeks then. T.peek(!!model.altHeld); } // The rigid translation into the surface, the surface push + its post-deadline re-assert, then the // model subscription and the first render -- all in T.mount (see the shared module). T.mount(observer, render); PK!\NNEres/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiencyVertical.css/* MoEEfficiencyVertical.css -- VERTICAL variant of the in-battle DAMAGE EFFICIENCY bar (class prefix .mev-, never .mp-). Tuned in the browser (tools/dev/eff_bar_tuner_vertical.html) and ported from that tuner's cssOut(): it has NO -EmitCss switch and its "Copy CSS" button is clipboard-only, so the emit is regenerated HEADLESSLY the way tools/dev/check_eff_vertical.js already does it -- read the tuner as text, truncate at its "// ---- panel wiring" marker, and evaluate cssOut() with `new Function` against a self-returning stub node. Do NOT point tools/dev/emit_eff_css.js at the vertical tuner: it targets the HORIZONTAL one by literal filename. The battle window has no hot-reload; tune in the browser, not in the client. AXIS: damage, BOTTOM (0%) to TOP (100%), the same piecewise-linear five-stop -> four-equal- quarters mapping as the horizontal sibling, rotated. The fill grows via `height` from bottom:0; every marker positions with bottom: + translateY(+50%) -- note the +50%, not the horizontal bar's -50%: a bottom-anchored box must shift back DOWN by half its own length to land on its point. Position comes from Python (window.move()), NOT from CSS. THIS SHEET IS LOADED ALONGSIDE MoEEfficiency.css, NOT INSTEAD OF IT (MoEEfficiencyView.html links both; orientation is a MOUNT-TIME branch in MoEEfficiency.js, not a second res_map layout -- a new itemID would cost every user a one-time client restart). The two sheets are namespace-DISJOINT by construction (.mp-* vs .mev-*), so nothing below can collide with a horizontal rule except the THREE shared subjects -- `body`, `#moe-bar-box` and `#moe-bar-root` -- and those are the only selectors here carrying the `body.mev` scope. `mev` goes on the BODY (MoEBarTransient's goVertical), because #moe-bar-box is a body-level SIBLING of the JS-created root and a class on the root could never reach it; `body.mev ...` is also (1,1,1) so it out-specifies the horizontal sheet's own `.mp-lg #moe-bar-root` (1,1,0) outright rather than winning on source order. THE SHIPPED FILE IS THE EMIT PLUS FIVE DELIBERATE HAND-EDITS -- never copy an emit over it (the repo lesson `emitcss-is-not-the-whole-shipped-stylesheet`). Each is marked HAND-EDIT n/5: 1 `#mev-bar-root` is normalised to the shipped `#moe-bar-root` THROUGHOUT (the tuner uses its own id purely so a candidate can never collide with the shipped bar). 2 the root rule drops the tuner's `right: 639px; bottom: 28px` minimap-placement PREVIEW -- that is a JS mock of a Python computation and must never reach the stylesheet -- and gains the shipped root's `left: 0; top: 0` origin, z-index and pointer-events:none. 3 #moe-bar-box, the sizing shim -- not emitted at all (the tuner has no surface). 4 `.mev-lg` becomes `.mp-lg` -- the body class MoEBarTransient.applySize actually writes. 5 the two Large rules whose subject is #moe-bar-root / #moe-bar-box are scoped `body.mev.mp-lg`. The former HAND-EDIT 6/6 (Default `.mev-bd-2/3/4` width retargeted 72.917rem -> 80.167rem) is GONE as of the 2026-08-17 crop fix: the tuner's own cssOut() no longer emits any per-row override for bd-2/3/4 (Default or Large) at all -- see eff_bar_tuner_vertical.html's own note at the site -- so the shipped CSS now matches the fresh emit there with no hand-edit needed. NOT a hand-edit here, unlike the sibling MoEProgressVertical.css: this tuner ALREADY emits the dash grid's gap stripe opaque (rgba(13,14,16,1)), pinned by check_eff_vertical.js. Leave it. The @font-face is not re-declared either -- MoEEfficiency.css is ed in the same document and carries it. Anything else diverging from a fresh emit is drift, not intent. */ /* HAND-EDIT 1/5 + 2/5 -- see the header. */ body.mev #moe-bar-root { position: absolute; left: 0; top: 0; width: 3rem; height: 200rem; z-index: 9000; pointer-events: none; font-family: "MoEBattle", "Arial Narrow", sans-serif; opacity: 0; } /* HAND-EDIT 3/5 -- THE SIZING SHIM. #moe-bar-root is position:absolute and contributes ZERO content size, so #moe-bar-box (declared in MoEEfficiencyView.html, NOT JS-created -- it must exist at the FIRST layout pass) is what gives the document in-flow content. IT DOES NOT STOP THE ENGINE'S SIZE TIMEOUT -- re-measured live on the Moving Average bar and disproven; MoEBarTransient's post-deadline SURFACE_REASSERT_MS is the only fix. Kept because it is the honest description of the document's size, and the horizontal sheet's 460x55 is the wrong shape entirely for this composition. Unlike the horizontal file's box (which is left at the tuner's own emitted 460x55 and is deliberately NOT a copy of the surface), this one IS the surface MoEEfficiency.js pushes: width V_BOX_W_REM + 2*PAD_REM == 96+20, height V_BOX_H_REM + 2*PAD_REM - V_CLIP_B_REM == 360+20-62. THE HEIGHT IS 62rem SHORT OF THE COMPOSITION ON PURPOSE, and that is the surface's own doing, not this rule's: the surface CLIPS .mev-backdrop's lower bleed so the engine's screen clamp can bring the bar's track down to the tuner's 28-logical-px `bottomGap` off the screen bottom (read MoEEfficiency.js's V_CLIP_B_REM note, and its sibling MoEProgress.js's, for the derivation). This rule only keeps describing whatever the surface actually is, and it stays a plain rem box either way, so it cannot reflow the composition when the surface shrinks past it. */ /* WIDTH IS V_BOX_W_REM + V_PAD_X_REM + V_PAD_XR_REM (54 + 52 + -6), a SPLIT pad now, NOT + 2*PAD_REM -- see MoEEfficiency.js's V_PAD_X_REM note: this bar's own extreme is `.mev-cap.bt` (the current-damage + delta row), not the mark rows -- an earlier pass only checked the mark rows and undersized this at 124rem, which is why the LEFT pad grew to 52. Height is untouched -- V_PAD_X_REM only ever widens X. V_BOX_W_REM ITSELF IS 54, NOT 96 -- a SEPARATE, asymmetric trim of `.mev-backdrop`'s own drawn width (right edge only, V_BOX_LEFT_REM below untouched), live-measured correct AT THE TIME: 52+54==106 landed exactly on the minimap's own edge (EFFICIENCY_MM_TRACK_X + MM_GAP + MM_TICK_OVERHANG == 95+8+3==106) under the ORIGINAL SHARED MM_GAP(8) -- keep it, see MoEEfficiency.js's fact 3 (whose own update covers why the backdrop no longer sits flush now that placement moved closer to the minimap). THE RIGHT PAD (V_PAD_XR_REM, -6) IS A SEPARATE, SMALLER KNOB -- it CLIPS `.mev-backdrop`'s own (already trimmed) drawn width a little further short of its own right edge, down to just past the track's own tick overhang PLUS a 2px margin (EFFICIENCY_MM_TRACK_X carries no hand correction, so the tick's own true position needs no re-derivation the way the sibling bar's does -- but a flush, zero-margin boundary is still the "rounding could shave a px and eat the ink" risk the margin heads off), leaving a real clearance to the minimap too -- 1px at the current domain/constants.EFFICIENCY_MM_GAP (3, down from 6px at the original shared gap of 8). This is the fix for the invisible SURFACE reaching into the minimap's first column (see MoEEfficiency.js's own four-point note for the full derivation); it costs nothing visible, since no caption ink reaches that far right (every caption here is anchored to the LEFT). */ body.mev #moe-bar-box { width: 109rem; height: 318rem; } /* .mev-backdrop is now the INVISIBLE surface bounding-box marker only (rule kept at V_BOX_* == -40/-80/54/360 as the CSS cross-check of MoEEfficiency.js's surface constants, pinned by tests/test_efficiency_surface_mirror.py; its .mp-lg twin's `left` is also read by the caption-fit test). The visible dither moved to the per-row .mev-bd strips below. */ .mev-backdrop { position: absolute; top: -80rem; left: -40rem; height: 360rem; width: 54rem; z-index: 0; } /* PER-ROW STRIPS. left/width MIRROR the invisible surface (body.mev #moe-bar-box == 100rem wide, left edge at -(V_PAD_X_REM - V_BOX_LEFT_REM) == -92rem), so each strip's right (minimap-facing) edge lands flush on the surface's own right edge (root x 8rem Default; 10rem Large). Solid dither hugs the minimap side (mask `at 90%`) and fades toward the leftward-growing numerals. Per-row `top` is a seed the maintainer converges. */ .mev-bd { position: absolute; left: -92rem; width: 109rem; height: 30rem; z-index: 0; } /* Per-index width overrides -- right edge PINNED at the shared strip's own right edge (left+width == -92+109 == 17rem), growing LEFTWARD only, so the minimap-facing edge and the surface hit-rect do not move. Same specificity as .mev-bd above; source order wins. */ .mev-bd-5 { width: 163.5rem; left: -146.5rem; } /* Mark-requirement strips (bd-2/3/4) no longer get their own width/left override -- 2026-08-17 crop fix. The 2026-08-12 narrowing pass shrank these rows' own box while leaving the WIDE checker-dither mask below (box-relative percent size/position) unchanged, so the taper's absolute reach narrowed right along with the box, leaving too little room for it to fade to a point before these rows' own (much closer) left edge -- a hard cut instead of a taper. Falling back to the shared .mev-bd box above (-92rem/109rem) restores the room the mask needs AND keeps the right edge flush at 17rem (same edge these rows' old override already targeted -- they never needed a narrower box to be flush). */ .mev-bd::before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(checker.png) repeat; background-size: auto; image-rendering: pixelated; opacity: 0.1; mask: radial-gradient(56% 110% at 90% 50%,#000 0%,transparent 67%); } .mev-bd::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; background: radial-gradient(76% 57% at 90% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } .mev-bd-1 { top: -27rem; } .mev-bd-2 { top: 35rem; } .mev-bd-3 { top: 85rem; } .mev-bd-4 { top: 135rem; } .mev-bd-5 { top: 199.5rem; } /* r1/r2/r3 strips ONLY (.mev-bd-2/3/4) -- their numbers sit farther from the minimap, so their dither reaches ~2x further left (wide X radius). tp/bt (.mev-bd-1/-5) keep the default above. */ .mev-bd-2::before, .mev-bd-3::before, .mev-bd-4::before { mask: radial-gradient(112% 110% at 90% 50%,#000 0%,transparent 67%); } .mev-bd-2::after, .mev-bd-3::after, .mev-bd-4::after { background: radial-gradient(128% 57% at 90% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } .mev-track { position: relative; z-index: 1; height: 100%; width: 3rem; background: rgba(0,0,0,0.45); } /* The garage dash grid, ROTATED: 0deg ("to top") puts the first stop at the track's BOTTOM edge and runs the period ALONG the axis, carried by the gradient's own rem stops. `background-size: 100% 3rem` is the TRANSPOSED form of the horizontal bar's `3rem 100%` x-period tiling: this sheet used to drop background-size entirely instead of transposing it, which rasterized the gradient across the whole element and smeared each dash's ink over ~4 device px instead of a crisp 2 -- tiling from a 3rem tile fixes that. The period is still a Y-length the root font already scales via SIZE_F, which is why the .mp-lg block below declares no twin for this rule. The gap stripe is opaque as emitted (see the header): the garage look this clones is a MASK over the solid fill. The RING keeps 0.5 -- a separate knob, outside the fill, matching the garage's. */ .mev-track::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 1; background-image: repeating-linear-gradient(0deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2rem,rgba(13,14,16,1) 2rem,rgba(13,14,16,1) 3rem); background-size: 100% 3rem; box-shadow: 0 0 0 1rem rgba(13,14,16,0.5); } /* THE AXIS: fill grows HEIGHT from bottom:0 (mask-not-overlay idiom unchanged). */ .mev-fill { position: absolute; left: 0; bottom: 0; width: 100%; height: 0; background: rgba(237,230,217,0.8); transition: height 400ms cubic-bezier(.2,.8,.2,1); } /* Ticks always cross the track: bottom: + translateY(50%) (bottom-anchored centring -- the sign is +50%, not the horizontal sibling's -50%, because a bottom-anchored box must shift itself back DOWN by half its own length to land on that point). */ .mev-tick { position: absolute; left: 50%; height: 2rem; z-index: 2; transform: translate(-50%, 50%); } .mev-tick.mev-req { width: 9rem; background: rgba(237,230,217,0.8); transform: translate(-50%, 50%) translateX(0rem); } .mev-tick.mev-req.met { background: rgba(237,230,217,0.8); } .mev-tick.mev-cur { width: 9rem; height: 2rem; background: rgba(255,255,255,1); transform: translate(-50%, 50%) translateX(0rem); transition: bottom 400ms cubic-bezier(.2,.8,.2,1); } .mev-tick.r1 { bottom: 25%; } .mev-tick.r2 { bottom: 50%; } .mev-tick.r3 { bottom: 75%; } .mev-tick.r4 { bottom: 100%; } /* ONE SHARED RIGHT-ALIGNMENT LINE FOR EVERY CAPTION (the fix -- see the file header's own bug-fix note): right:100% of #moe-bar-root + translateX(--lfclear) is a FIXED point, never dependent on any caption's own content width, so a numeral's digit count can only grow the box LEFTWARD and can never move an icon, a delta, or any other caption. r1-r3, r4 and the current caption all share it. Icon and delta are IN-FLOW flex children (was: out-of-flow absolute+transform hanging off the box's own edge, which a self-referencing -50% on r4/the current caption used to drag along with it -- see gen_bar_tuner_vertical.ps1's .mpv-cap / the shipped MoEProgress.css's .mp-cap for the same idiom this adopts). DO NOT "OPTICALLY CENTRE" the r4 / current captions over the track: that needs a WIDTH-SCALED term, i.e. the digit-count bug returning. A non-zero residual nudge (capxR4 / capxCur below) is legitimate per-group geometry; a nudge computed off the box's own size is the defect. */ .mev-cap { position: absolute; display: flex; flex-direction: row; align-items: center; white-space: nowrap; z-index: 3; right: 100%; } /* r1/r2/r3: each bottom-anchored on its OWN tick (25/50/75%) via bottom: + translateY(50%) -- the vertical analogue of a caption riding beside its tick. --lfclear clears the WIDER tick's outer edge (crossPad(), == domain/constants.MM_TICK_OVERHANG on the Python side); --capxreq is a small residual TRIM, r1-r3 ONLY (split from r4's --capxr4, own knob -- see the file header's own note on why they legitimately differ). */ .mev-cap.lf { transform: translateY(50%) translateX(-3rem) translateX(-2rem); font-size: 12rem; line-height: 15.5rem; } /* PER-MARK block<->bar gap, hand-tuned in tools/dev/icon_gap_tuner.html: r1/r2/r3 already exist as three CONCURRENT rows (unlike the Moving Average bar's single reused capR), each with its own static class, so no new plumbing is needed here -- unlike the horizontal Moving Average bar (see MoEProgress.js's setIco()), which had none until this pass. Compound selectors here are (0,3,0), CLEANLY beating the (0,2,0) base rule above on specificity -- no source-order tie. Each collapses the base rule's two separate translateX() calls (the shared tick-overhang clearance and the per-row residual) into the ONE combined value the tuner reports. */ .mev-cap.lf.r1 { transform: translateY(50%) translateX(-2.000rem); } .mev-cap.lf.r2 { transform: translateY(50%) translateX(-4.000rem); } .mev-cap.lf.r3 { transform: translateY(50%) translateX(-6.000rem); } .mev-cap.r1 { bottom: 25%; } .mev-cap.r2 { bottom: 50%; } .mev-cap.r3 { bottom: 75%; } /* r4: the 100% tick's caption, a static cap ABOVE the track's top end -- reads as the axis's top end cap. padding-bottom, not margin-bottom: Coherent drops margin on the bottom:100%- anchored side (gameface-drops-margin-on-the-anchored-side). --capxr4 is r4's OWN residual: r4 sits above the track's END, not beside a tick, so it needs a DIFFERENT constant push than r1-r3's --capxreq to land back over the track -- still a fixed constant, never a function of the numeral's own width. */ /* NUDGE FULLY CANCELLED (2026-08-10, three corrections): a LEFT nudge landed here, then got wrongly halved on Large too, then the maintainer asked for the SAME magnitude back RIGHT on Large -- which cancels the un-halved LEFT nudge exactly (verified with Decimal, see .mp-lg .mev-cap.tp's own note). Default carries no nudge and never did past the first correction; Large now carries none either. Both sit at the tuner's own pre-nudge residual, 11 (the shared -3rem tick-overhang clearance is untouched). Mind the clip: this caption is right-anchored, so "left" is the overflow direction -- see MoEEfficiency.js's V_PAD_X_REM note, which re-derives this row as part of the surface's own worst-case budget. */ .mev-cap.tp { bottom: 100%; padding-bottom: 4rem; transform: translateX(-3rem) translateX(11rem); font-size: 12rem; line-height: 15.5rem; } /* THE CURRENT/LATEST VALUE CAPTION -- a STATIC readout below the track's bottom end. There is no moving marker element; only the CURRENT TICK (above) still tracks the fill, which is why MoEEfficiency.js's capClampPct corridor is horizontal-only and is skipped entirely here. top:100% is the one side Coherent's margin drop does NOT apply to (see r4 above), so margin-top here is fine as written. NUDGE FULLY CANCELLED (2026-08-10, three corrections) -- see .mev-cap.tp's own note above for the full history; the maintainer's final "7px RIGHT on Large" request cancels the un-halved "7px LEFT" nudge exactly (11.733+5.6==17.333, verified with Decimal). Default and Large both sit back at the tuner's own pre-nudge residual, 13. This row (numeral + BARE signed delta, no parens) is THIS FILE'S OWN EXTREME, exactly as .mpv-capC is for the Moving Average bar's sibling sheet -- see MoEEfficiency.js's V_PAD_X_REM note for the full re-derivation; it is what actually sizes the surface, not the mark rows. */ .mev-cap.bt { top: 100%; margin-top: 3rem; transform: translateX(-3rem) translateX(13rem); font-size: 16rem; line-height: 20.5rem; } .mev-cap .mev-v { position: relative; color: #ffffff; font-weight: 600; letter-spacing: 0em; text-shadow: 0 0 1rem rgba(0,0,0,0.5); } .mev-cap.lf .mev-v, .mev-cap.tp .mev-v { transform: translateY(0rem); } .mev-cap.bt .mev-v { transform: translateY(0rem); } /* Every caption's icon/numeral(/delta) mini-row runs HORIZONTALLY, same axis as the horizontal sibling's row, with the ORDER REVERSED: numeral comes BEFORE its icon (the icon trails, away from the track), and on the current caption the delta sits LEFT of the numeral (was right). The icon is now an IN-FLOW flex child: align-items:center centres it, margin-left carries the gap (an ordinary in-flow margin, not the anchored-side one Coherent drops), and the per-role Y nudge is its own small residual transform. */ .mev-ico { position: relative; display: block; flex: none; width: 13rem; height: 13rem; } .mev-cap .mev-ico { margin-left: 1rem; } /* PER-ICON INK-GAP PARITY (maintainer's ask, box sizes untouched): IDENTICAL literals to the horizontal sibling's .mp-ico.bm/.mp-ico.mk overrides -- same boxes, same assets, the axis rotation changes nothing about the ink. Calibrated off the real PNGs' alpha>32 bbox to a flat 3.000rem target (dmg, untouched, naturally lands ~3.006rem); mk is calibrated to mark_2 alone, mark_1/mark_3 land off it by +-2rem -- an accepted residual, same class as MoEProgress.css's own mark correction. Literal, not slider-driven. */ .mev-cap .mev-ico.bm { margin-left: 1.253rem; } .mev-cap .mev-ico.mk { margin-left: -1rem; } /* PER-MARK, hand-tuned in tools/dev/icon_gap_tuner.html: mark_1 keeps the shared -1rem above unchanged (it happens to coincide); mark_2/mark_3 get their own. Same (0,3,0)-tie-by-source- order convention as the horizontal sibling's identical split. */ .mev-cap .mev-ico.mk2 { margin-left: 0.500rem; } .mev-cap .mev-ico.mk3 { margin-left: 3.000rem; } .mev-cap.lf .mev-ico { transform: translateY(1rem); } .mev-cap.tp .mev-ico { transform: translateY(-0.25rem); } .mev-cap.bt .mev-ico { transform: translateY(0.5rem); } .mev-ico::before { content: ""; position: absolute; left: 50%; top: 50%; z-index: -1; width: 106%; height: 106%; transform: translate(-50%, -50%); background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } .mev-cap.lf .mev-ico::before, .mev-cap.tp .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(26,26,26,0.5) 0%, transparent 73%); } #moe-bar-root.mev-b-w .mev-cap.bt .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(237,230,217,0.3) 0%, transparent 73%); } #moe-bar-root.mev-b-g .mev-cap.bt .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(123,236,55,0.8) 0%, transparent 73%); } #moe-bar-root.mev-b-t .mev-cap.bt .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(90,154,211,0.8) 0%, transparent 73%); } #moe-bar-root.mev-b-v .mev-cap.bt .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(115,23,196,0.8) 0%, transparent 73%); } #moe-bar-root.mev-b-au .mev-cap.bt .mev-ico::before { background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.9) 0%, transparent 73%); } .mev-ico::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: no-repeat; background-position: center; } .mev-ico.mk { width: 16rem; height: 16rem; } .mev-ico.mk::after { background-size: contain; filter: brightness(1); } .mev-ico.mk1::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_1.png); } .mev-ico.mk2::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_2.png); } .mev-ico.mk3::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_3.png); } .mev-ico.bm { width: 14rem; height: 14rem; } .mev-ico.bm::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_barrel_mark.png); background-size: 228.7%; filter: brightness(3); } .mev-ico.dmg { width: 16rem; height: 16rem; } .mev-ico.dmg::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_damage.png); background-size: 342.5%; filter: brightness(3); } /* The delta hangs LEFT of the numeral now (was right of it): right:100% + one translate() carrying the gap and the residual Y nudge, same fade-on-opacity idiom. */ .mev-cap.bt .mev-d { position: absolute; right: 100%; top: 0; transform: translate(-4.2rem, 2.5rem); font-size: 12rem; line-height: 15.5rem; color: #ffffff; font-weight: 600; text-shadow: 0 0 1rem rgba(0,0,0,0.5); opacity: 0; transition: opacity 500ms ease-out; } .mev-cap.bt .mev-d.on { opacity: 1; } #moe-bar-root.mev-b-w .mev-fill { background: rgba(237,230,217,0.8); } #moe-bar-root.mev-b-w .mev-tick.mev-cur { box-shadow: 0 0 6rem rgba(237,230,217,0.8),0 0 2rem rgba(237,230,217,0.8); } #moe-bar-root.mev-b-w .mev-cap.bt .mev-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(237,230,217,0.5),0 0 2rem rgba(237,230,217,0.5); } #moe-bar-root.mev-b-g .mev-fill { background: rgba(123,236,55,0.8); } #moe-bar-root.mev-b-g .mev-tick.mev-cur { box-shadow: 0 0 6rem rgba(123,236,55,0.8),0 0 2rem rgba(123,236,55,0.8); } #moe-bar-root.mev-b-g .mev-cap.bt .mev-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(123,236,55,0.9),0 0 2rem rgba(123,236,55,0.9); } #moe-bar-root.mev-b-t .mev-fill { background: rgba(51,146,230,0.8); } #moe-bar-root.mev-b-t .mev-tick.mev-cur { box-shadow: 0 0 6rem rgba(51,146,230,0.8),0 0 2rem rgba(51,146,230,0.8); } #moe-bar-root.mev-b-t .mev-cap.bt .mev-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(90,154,211,1),0 0 2rem rgba(90,154,211,1); } #moe-bar-root.mev-b-v .mev-fill { background: rgba(115,23,196,0.8); } #moe-bar-root.mev-b-v .mev-tick.mev-cur { box-shadow: 0 0 6rem rgba(115,23,196,0.8),0 0 2rem rgba(115,23,196,0.8); } #moe-bar-root.mev-b-v .mev-cap.bt .mev-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(115,23,196,1),0 0 2rem rgba(115,23,196,1); } #moe-bar-root.mev-b-au .mev-fill { background: rgba(255,205,90,0.8); } #moe-bar-root.mev-b-au .mev-tick.mev-cur { box-shadow: 0 0 6rem rgba(255,205,90,0.8),0 0 2rem rgba(255,205,90,0.8); } #moe-bar-root.mev-b-au .mev-cap.bt .mev-v { text-shadow: 0 0 1rem rgba(0,0,0,0.5),0 0 6rem rgba(255,205,90,0.9),0 0 2rem rgba(255,205,90,0.9); } @keyframes mev-life{ 0%{opacity:0;transform:translateY(20rem);animation-timing-function:ease-in} 9.68%{opacity:1;transform:translateY(0rem);animation-timing-function:linear} 90.32%{opacity:1;transform:translateY(0rem);animation-timing-function:ease-in} 100%{opacity:0;transform:translateY(20rem)}} #moe-bar-root.mev-run{animation:mev-life 6200ms both} /* THE RE-TRIGGER TWIN -- byte-identical to mev-life apart from the name (one builder emits both). A baked fade/hold/fade keyframe cannot be re-triggered in place: the JS restart is remove-class -> force-reflow -> re-add-class, and if Coherent coalesces the re-add with the run it just cancelled the restart is a NO-OP -- which, with the root resting at opacity 0 under `both` fill, leaves the bar permanently INVISIBLE after its first appearance. So the JS ALTERNATES .mev-run / .mev-run-b (MoEBarTransient.js RUN_CLASSES_V/RUN_NAMES_V): consecutive runs carry names the engine cannot coalesce. Without the pair this bar cannot re-raise for a second battle event. */ @keyframes mev-life-b{ 0%{opacity:0;transform:translateY(20rem);animation-timing-function:ease-in} 9.68%{opacity:1;transform:translateY(0rem);animation-timing-function:linear} 90.32%{opacity:1;transform:translateY(0rem);animation-timing-function:ease-in} 100%{opacity:0;transform:translateY(20rem)}} #moe-bar-root.mev-run-b{animation:mev-life-b 6200ms both} @keyframes mev-pulse{ 0%,100%{box-shadow:0 0 8rem rgba(255,205,90,0.9)} 50%{box-shadow:0 0 16rem rgba(255,205,90,1.00)}} #moe-bar-root.mev-b-au.mev-pulse .mev-track{animation:mev-pulse 1200ms ease-in-out infinite} /* ===== THE "LARGE" SIZE MODE (mod_settings.progress_bar_size == 1). The mode is delivered by the ROOT FONT SIZE (MoEBarTransient.js SIZE_F == 1.25), which IS the rem->px factor in Gameface, so that one write re-lays the whole composition 1.25x and correctly leaves every %, em, gradient stop and derived background-size ratio alone. What is left is the CROSS-AXIS (screen-x) lengths, which must reach 5/3 total and therefore owe SIZE_XF == 4/3 ALONE on top of it -- so every declaration below is an x-length and nothing else. Do NOT add a font-size, a bar length, a tick thickness, an icon box, a vertical gap or a keyframe here: the root font already has them and restating one would DOUBLE-APPLY SIZE_F. HAND-EDIT 4/5: the tuner emits this block under `.mev-lg`; the class MoEBarTransient.applySize actually writes on the body is `.mp-lg`, shared by both orientations (the SIZE flag is orientation-independent), so every selector below is rewritten to it. Do not "restore" .mev-lg -- nothing would ever match it. THE DASH GRID TAKES NO RULE HERE, deliberately: a 0deg grid's period is a y-length the root font already scales, so a reintroduced twin would double-apply SIZE_F. check_eff_vertical.js carries a NAMED ABSENCE assertion for exactly that, because a value-equality gate has no other way to notice the horizontal bar's twin creeping back in. */ /* HAND-EDIT 5/5: the emit's `.mev-lg #mev-bar-root` plus the shim rule the tuner never emits, both scoped `body.mev.mp-lg` (1,2,1) so they out-specify the horizontal sheet's own `.mp-lg #moe-bar-root` / `.mp-lg #moe-bar-box` (1,1,0) outright. The shim's width is the PRE-SIZE_F quantity MoEBarTransient.applySize computes before its own final `* f`: V_BOX_W_REM*SIZE_XF + V_PAD_X_REM + V_PAD_XR_REM_LARGE == 72 + 52 + -8.667 == 115.333 (V_PAD_XR_REM_LARGE is its own literal, -8.667, NOT V_PAD_XR_REM*SIZE_XF -- see MoEEfficiency.js's own note); its HEIGHT is unchanged (the root font carries SIZE_F on a y-length), exactly as the horizontal block's own twin restates width only. THIS SHIM IS DOCUMENT REM, NOT LOGICAL PX -- the root font (1.25 under Large) supplies the SIZE_F when the DOCUMENT renders this box, so 115.333rem here reproduces the same round(115.333*1.25)==144 logical px MoEBarTransient.applySize pushes via resizeViewRem -- do not write 144 here, that would double the factor. THE BACKDROP'S OWN LARGE WIDTH BELOW IS A LITERAL 98rem, NOT V_BOX_W_REM*SIZE_XF (72, the naive *4/3 twin of the tuned Default 54) -- see MoEEfficiency.js's fact 3: 98 landed the backdrop's own right edge exactly on the minimap's edge (52+98==150==edge_x(137)+MM_GAP(8)+ MM_TICK_OVERHANG_LARGE(5)) AT THE ORIGINAL SHARED MM_GAP(8), keep it. Placement has since moved closer to the minimap (domain/constants.EFFICIENCY_MM_GAP_LARGE == 3, not 8), so the backdrop's own drawn edge no longer sits flush -- harmless, per fact 3's own update, since the invisible SURFACE is what actually clears the minimap. The surface above is narrower still than even the trimmed backdrop (115.333 < 52+98==150, the SAME pre-SIZE_F rem space) -- that is the SEPARATE surface fix (fact 4): the surface clips a little more of the backdrop's own right-side bleed, to leave a real margin (1px to the minimap at the current gap, ~2.3px to the tick's own true right edge) instead of the backdrop's own flush zero-clearance edge. */ body.mev.mp-lg #moe-bar-root { width: 4rem; } body.mev.mp-lg #moe-bar-box { width: 122.4rem; } .mp-lg .mev-track { width: 4rem; } .mp-lg .mev-backdrop { left: -53.333rem; width: 98rem; } /* The strips' Large flush override: right edge at root x 10rem (surface's Large right edge); OWN literals (not *SIZE_XF). Per-row `top` is a y-length the root font scales -- no Large twin. */ .mp-lg .mev-bd { left: -105.333rem; width: 122.4rem; } /* Large per-index width overrides -- right edge PINNED (left+width == -105.333+122.4 == 17.067rem); same specificity as .mp-lg .mev-bd above, source order wins. */ .mp-lg .mev-bd-5 { width: 183.6rem; left: -166.533rem; } /* bd-2/3/4 Large no longer get their own override -- 2026-08-17 crop fix. Their old literal (left -76.6rem, width 81.8rem) put the right edge at 5.2rem, ~11.87rem SHORT of the 17.067rem edge every other Large row shares (the comment above claimed 17.067rem, but was never checked against the actual arithmetic -- see the memory vertical-backdrop-narrowing-broke-the-large-twins-deferred), on top of the same box-relative mask-taper crop the Default rows had. Falling back to the shared .mp-lg .mev-bd box above fixes both at once: right edge now correctly flush at 17.067rem, and the WIDE mask gets back the room its percent-based taper needs. */ .mp-lg .mev-tick.mev-req { width: 12rem; transform: translate(-50%, 50%) translateX(0rem); } .mp-lg .mev-tick.mev-cur { width: 12rem; transform: translate(-50%, 50%) translateX(0rem); } .mp-lg .mev-cap.lf { transform: translateY(50%) translateX(-4rem) translateX(-2.667rem); } /* Large's per-row block<->bar gap, hand-tuned in tools/dev/icon_gap_tuner.html -- LITERAL, not the Default row's *4/3 (-2/-4/-6 * 4/3 would be -2.667/-5.333/-8), same convention as the horizontal Moving Average bar's Large block-gap. (0,4,0), cleanly beating the base .mp-lg rule above (also (0,3,0) once .mp-lg is added -- still no tie, one extra class each). */ .mp-lg .mev-cap.lf.r1 { transform: translateY(50%) translateX(-3.000rem); } .mp-lg .mev-cap.lf.r2 { transform: translateY(50%) translateX(-5.000rem); } .mp-lg .mev-cap.lf.r3 { transform: translateY(50%) translateX(-7.000rem); } /* CAPTION-POSITION NUDGE (2026-08-17, corrected): 100%-requirement (.tp) moved 4px LEFT, current-damage (.bt) moved 7px LEFT (monitor px), recalibrated from an in-client probe. These captions follow NORMAL CSS -- increasing translateX moves RIGHT, decreasing moves LEFT (a prior "right-anchored, so increase = left" belief was backwards and inverted this nudge; corrected here). Factor is 0.4 rem per monitor-px (1 rem == 2.5 monitor-px under Large on this maintainer's setup). Only the SECOND translateX moves -- the leading translateX(-4rem) is unrelated block-gap positioning. .tp: 4px left is -1.6rem off HEAD's 14.667 = 13.067rem. .bt: 7px left is -2.8rem off HEAD's 17.333 = 14.533rem. */ .mp-lg .mev-cap.tp { transform: translateX(-4rem) translateX(13.067rem); } .mp-lg .mev-cap.bt { transform: translateX(-4rem) translateX(14.533rem); } .mp-lg .mev-cap .mev-ico { margin-left: 1.333rem; } /* The Large twins of the per-icon ink-gap-parity overrides above: literal, SIZE_XF (4/3) applied by hand to the Default literal, never re-derived from the shared margin-left knob. */ .mp-lg .mev-cap .mev-ico.bm { margin-left: 1.671rem; } .mp-lg .mev-cap .mev-ico.mk { margin-left: -1.333rem; } /* PER-MARK Large levers, hand-tuned in tools/dev/icon_gap_tuner.html -- LITERAL, not the Default row's *4/3 (-1/0.5/3 * 4/3 would be -1.333/0.667/4), and mark_1 needs its OWN override here even though it didn't at Default (the shared Large .mk above is -1.333, not -1). */ .mp-lg .mev-cap .mev-ico.mk1 { margin-left: -1.000rem; } .mp-lg .mev-cap .mev-ico.mk2 { margin-left: 1.000rem; } .mp-lg .mev-cap .mev-ico.mk3 { margin-left: 3.000rem; } .mp-lg .mev-cap.bt .mev-d { transform: translate(-5.6rem, 2.5rem); } /* Axis + timings for the JS (mirrored in MoEBarTransient.js / MoEEfficiency.js -- the VERTICAL keyframes are identically tuned to the horizontal ones, which is why one set of timing constants serves both orientations). The tuner's trailing `minimap` placement block is deliberately NOT carried over: those numbers are the PYTHON side's (domain/constants MINIMAP_SIZES, MM_GAP, MM_GAP_BOTTOM, MM_TICK_OVERHANG) and a second copy here would be drift waiting to happen. { "axis": "damage, five stops -> four equal quarters, BOTTOM(0%) to TOP(100%) (barX, same as the horizontal sibling)", "dmgStopsSource": "snapshot.thresholds{1,2,3,100}", "barStops": [0, 25, 50, 75, 100], "fadeInMs": 600, "holdMs": 5000, "fadeOutMs": 600, "totalMs": 6200, "slideRem": 20, "slideEasingIn": "ease-in", "slideEasingOut": "ease-in", "fillDurationMs": 400, "fillEasing": "cubic-bezier(.2,.8,.2,1)", "deltaHoldMs": 1600, "deltaFadeMs": 500, "deltaFadeEasing": "ease-out", "pulseMs": 1200, "barLenRem": 200, "crossPadRem": 3 } */ PK!_Bres/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiencyView.html MoEEfficiencyView
PK!n#IF;res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgress.css/* MoEProgress.css -- in-battle centre-screen MoE progress bar. Tuned in the browser (tools/dev/gen_bar_tuner.ps1) and copied VERBATIM; the battle window has no hot-reload. Position comes from Python (window.move()), NOT from CSS -- tuner stage placement was top 85vh, centre offset 0rem. Font: the bundled MoEBattle numeric subset, 19 glyphs (digits % ( ) + - , . / space) -- NO LETTERS, a word label renders blank. Sizes in rem (1rem == 1 logical px); colours by VALUE (Gameface drops a declaration whose var() cannot resolve). JS sets .mp-fill width and the .mp-proj / .mp-capC left as percentages, and toggles .mp-up/.mp-down on the fill + the bottom numerals. The axis-end caption is pure CSS (it hangs off the track's right end), so JS measures nothing. */ /* ADDITION 1 OF 2 TO THE TUNER'S EMITTED FILE. #moe-bar-root asks for font-family "MoEBattle" but the tuner ran in a browser and never emitted a face for it, and this document does NOT MoEBattle.css (that would drag the whole corner overlay's rules in with it). So the 6-line declaration is copied verbatim from MoEBattle.css:23-29 -- same family name, same single weight-600 cut, same bare-sibling url FIRST: Coherent resolves an @font-face src against the DOCUMENT directory only, so a subdir-relative path silently falls back to Arial Narrow. That is also why this file must sit right beside MoEBattle.ttf and checker.png. */ @font-face { font-family: "MoEBattle"; font-weight: 600; font-style: normal; src: url(MoEBattle.ttf) format("truetype"), url("coui://gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.ttf") format("truetype"); } /* ADDITION 2 OF 2 TO THE TUNER'S EMITTED FILE (not tuned, no tuned value touched) -- THE SIZING SHIM. #moe-bar-root is position:absolute and therefore contributes ZERO content size, so with an empty body the engine's size calculation has nothing to measure: it times out (`Size calculation timeout` for MoEProgressView) and its fallback action -- literally "Set the default view size" -- runs LAST and overwrites MoEProgress.js's pushed resizeViewRem size with the flat 256x256 default (live-observed: resize at 04.8s, clobber at 06.2s). #moe-bar-box (declared in MoEProgressView.html, NOT JS-created -- it must exist at the first layout pass) gives that pass in-flow content of exactly the surface size. IT DOES NOT STOP THE TIMEOUT -- RE-MEASURED LIVE, AND THIS COMMENT USED TO CLAIM OTHERWISE. The box is present, in-flow and exactly 380x92, and the `Size calculation timeout` + its 256x256 clobber still happen. The ONLY thing that fixes the surface is MoEProgress.js's re-assert after that deadline (SURFACE_REASSERT_MS), which is therefore load-bearing and not deletable; the JS also refuses to show the bar until it has landed (surfaceSettled), because a 256x256 surface crops the composition and Python then places it ~142px too high. The box is kept regardless: it is the honest description of the document's size, it costs nothing, and it is not what is broken. body margin:0 matters: the UA's default 8px would inflate the measured box to 396x108. The box is an empty, transparent sizing shim; the abspos bar root overlays it and no tuned geometry moves. 380 x 92 MIRRORS MoEProgress.js's VIEW_W_REM / VIEW_H_REM, which are the SOURCE OF TRUTH (BOX_W/H_REM + 2*PAD_REM). Same mirrored-constant contract as the JS's SHIFT_Y_REM <-> Python's domain/constants.PROGRESS_ANCHOR_Y_SHIFT: change one, change all of them. tests/test_progress_surface_mirror.py fails if they drift. */ body { margin: 0; } #moe-bar-box { width: 380rem; height: 92rem; } #moe-bar-root { position: absolute; left: 0; top: 0; /* THE TRACK WIDTH, and the ONE number the whole composition is derived from. It must stay a width the dash grid can tile without a truncated GAP (see .mp-track::after: 2rem dash + 1rem gap == a 3rem period): 200 == 3*66 + 2, i.e. 66 whole periods then a final full 2rem dash flush against the right edge. Any width == 0 or 2 (mod 3) is clean; a width == 1 (mod 3) ends on a half gap and the grid reads irregular at the right end -- fix that by moving the WIDTH, never the tuned dash/gap/period. .mp-backdrop's width and MoEProgress.js's BOX_W_REM (hence #moe-bar-box above) are this + 2*80rem of side clearance; everything that MOVES is a percentage and follows for free. */ width: 200rem; z-index: 9000; pointer-events: none; text-align: center; font-family: "MoEBattle", "Arial Narrow", sans-serif; opacity: 0; } /* Backdrop = the .mb-backdrop two-layer trick: checker dither over a dark radial underlay. EXPLICIT width+height with a single top/left anchor -- Coherent collapses a top+bottom stretch. checker.png + the ttf sit RIGHT BESIDE this CSS (bare sibling urls). */ /* INTENTIONAL ASYMMETRY (user-approved, symmetry contract retired): left is -72rem while width stays 360rem, so the bleed is 72rem on the left / 88rem on the right -- deliberately uneven, NOT the old -bleed'/track'+2*bleed' symmetric backdrop. Do not "fix" it back to -80rem. */ .mp-backdrop { position: absolute; left: -72rem; top: -34rem; width: 360rem; height: 72rem; z-index: 0; } .mp-backdrop::before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(checker.png) repeat; background-size: auto; background-position: 0px 0px; image-rendering: pixelated; opacity: 0.1; mask: radial-gradient(56% 110% at 50% 50%,#000 0%,transparent 67%); } .mp-backdrop::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; background: radial-gradient(76% 57% at 50% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } .mp-track { position: relative; z-index: 1; width: 100%; height: 3rem; background: rgba(0,0,0,0.45); } /* THE GARAGE BAR'S TRACK TREATMENT, cloned (MoECalculator.css:277-296 -- #moe-root .moe-track). The hangar bar gets its vertical dashes from WG's OWN art, a 99x2 strip drawn at background-size:99rem 2rem, i.e. 1 art px == 1rem -> 2rem dash + 1rem gap (3rem period), cream rgb(236,230,218) at alpha 41/255 = 0.16, repeat-x from the left edge. Same numbers here, re-drawn as a gradient because they are SLIDERS in the tuner (a fixed PNG cannot follow them) AND because the GAP needs a colour of its own (next paragraph). IF Coherent ever drops repeating-linear-gradient, the verified fallback is the garage's own line, which renders correctly in the hangar today: background-image: url(img://gui/maps/icons/ui/progressbar/bg_pattern_small.png); background-repeat: repeat-x; background-size: 99rem 2rem; background-position: left center; -- pixel-identical for the MARKS at 2 / 1 / #ece6da / 0.16, but that PNG's gaps are TRANSPARENT, so it is only equivalent at gap alpha 0. To keep the masked look on that fallback the fill itself would have to carry the pattern (which is literally what the hangar does -- see below). The garage's "border" is NOT a border either: `box-shadow: 0 0 0 1rem rgba(13,14,16,0.5)`, an OUTSET ring. Kept as a shadow for the same reason -- a real `border` would grow the track past 3rem and drag the tick centring (top:50%) and the backdrop's bdTop centring with it. An outset shadow has ZERO box-model impact, so no box-sizing needed. BOTH live on ONE pseudo, with the explicit left/top/width/height box Coherent needs (it will not stretch a pseudo from a top+bottom / left+right pair). z-index:1 puts BOTH gradient stripes ABOVE the auto-z .mp-fill, and THE GAP STRIPE IS AN OPAQUE DARK COLOUR, not `transparent` -- because that is what the hangar bar actually does. Its .moe-fill (MoECalculator.css:304-326) has NO background-color whatsoever: it paints filled_pattern_small.png ONLY, at the SAME background-size:99rem 2rem / background-position: left center as the track's bg_pattern_small, so the two grids are in phase and the fill exists ONLY inside the dash marks while the gaps show the dark track backing. The garage grid is a MASK, not a wash over a solid bar. This fill IS a solid colour, so the opaque gap stripe is what reproduces that read; drop the gap alpha to 0 and the fill floods the gaps again (the earlier look, where the bar read as sitting ON TOP of the grid). PHASE: the gradient is on the TRACK's pseudo, so its origin is the track's LEFT EDGE -- never the fill's right edge -- and the dashes stay in phase across the reached and unreached halves at every fill width. Still BELOW the z-index:2 ticks. The ring on the PSEUDO rather than on .mp-track also survives .mp-full / .mp-pulse, which both overwrite the track's own box-shadow. And because the ring is outset, the fill is flush inside it at 0% and 100%: never visually inset, never overlapping. */ .mp-track::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 1; /* WG'S OWN IDIOM for this pattern (mono/battle_pass, mono/hangar): describe exactly ONE 3rem period in the gradient and let background-size tile it, rather than letting one track-wide gradient carry every repeat (that also makes the tiling width-agnostic -- see #moe-bar-root's width note for which widths end on a whole dash). Their line is background: repeating-linear-gradient(90deg,#ede6d9,#ede6d9 1rem,transparent 1rem,transparent 3rem) left bottom/3rem 1rem; Same numbers as before -- 2rem dash + 1rem gap, cream rgb(236,230,218) at 41/255 = 0.16. THE GAP IS ALPHA 1, which is what makes the grid read as a MASK over the solid fill (at 0.5 the green showed through at half strength, so a gap looked lighter to the LEFT of the fill edge than to the right -- the "irregular intervals"). The RING keeps 0.5: it sits outside the fill and matches the garage's. */ background-image: repeating-linear-gradient(90deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2rem,rgb(13,14,16) 2rem,rgb(13,14,16) 3rem); background-size: 3rem 100%; background-repeat: repeat; box-shadow: 0 0 0 1rem rgba(13,14,16,0.5); } /* Explicit dimensions + a single animated property per rule: Gameface will not interpolate what it cannot measure, and a transform transition needs matching function lists. */ .mp-fill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: rgba(237,230,217,0.8); transition: width 600ms cubic-bezier(.2,.8,.2,1) 600ms; } /* THE FILL IS THE ONE PLACE THE SIGN BECOMES A REAL COLOUR. The text rule further down (glow, never a fill) is there to keep NUMERALS legible over bright and dark map areas -- a solid bar has no glyph to keep readable, so it takes the sign directly. Same upCol / dnCol as the numerals' glow, so bar and numbers always agree. Zero delta -> NEITHER class -> the neutral background above. Two-class selectors so these out-specify .mp-fill, and `transition` is deliberately NOT restated here: width stays the ONLY animated property (never `transition: all` -- the background must flip, not interpolate). JS COMMITS the class at the same moment it swaps the numeral, i.e. after the entry animation -- and DURING the entry it leaves the PREVIOUS run's class in place (an explicit maintainer decision, quoted in full at MoEProgress.js showVal), so a bar that was red and stays red never changes colour at all. THE NEUTRAL IS CREAM, NOT THE TUNER'S DEFAULT GREEN. fillCol shipped as the SAME rgba(123,236,55,0.8) as upCol, which made the neutral state read as a WIN twice over: a zero delta was indistinguishable from a positive one, and -- worse -- every COLD damage event flashed green while the player was in the red, because showVal(false) used to STRIP both sign classes and drop the fill back to this base colour for the whole 600ms entry before the swap re-applied .mp-down. It no longer strips them (that is the other half of the same fix), and the neutral is now the widget's OWN neutral cream (the same rgb(237,230,217) as the neutral numerals and the .mp-end axis ticks) -- reserved for the only two states with nothing committed to show: the FIRST show of a battle (no showVal(true) has run yet) and a rounded-zero delta. up/down below are untouched: the neutral, the win and the loss are three distinct colours. */ .mp-fill.mp-up { background: rgba(123,236,55,0.8); } .mp-fill.mp-down { background: rgba(211,68,63,0.8); } /* FOUR ticks: the two axis ENDS (prev / next requirement), pre_avg, and proj_avg. */ .mp-tick { position: absolute; top: 50%; width: 2rem; height: 9rem; transform: translate(-50%, -50%); z-index: 2; } .mp-tick.mp-end { background: rgba(237,230,217,0.8); } .mp-tick.mp-left { left: 0; } .mp-tick.mp-right { left: 100%; } .mp-tick.mp-pre { background: rgba(237,230,217,0.75); } /* The CURRENT tick carries its OWN glow: the same two-pass shape (wide pass + tight core) as the gold .mp-full ring and the sign/text glows, so the whole bar speaks one visual language. SPECIFICITY, deliberately not fought: `#moe-bar-root.mp-full .mp-tick` below is id + 2 classes and therefore BEATS this 2-class rule, so the moment the requirement is met the gold takes over this tick along with the rest of the bar. That is the intent -- met-requirement gold owns the whole bar -- so there is no override knob here. `transition` stays LEFT ONLY; the glow is static and must not interpolate. */ .mp-tick.mp-proj { background: rgba(255,255,255,1); box-shadow: 0 0 6rem rgba(255,255,255,0.5),0 0 2rem rgba(255,255,255,0.5); transition: left 600ms cubic-bezier(.2,.8,.2,1) 600ms; } /* ...AND IT TAKES THE SIGN, exactly like the numerals it carries (JS toggles .mp-up/.mp-down on this tick in the same forEach as .mp-capC's numerals and the fill -- MoEProgress.js showVal). Same upCol / dnCol as the text glow, and the tick's OWN 6rem/2rem two-pass geometry from the rule above, so only the colour changes. box-shadow is the only possible vehicle: the tick is an empty box with no glyphs (text-shadow paints nothing) and filter: drop-shadow would compose with the tick's translate(-50%,-50%). NEUTRAL NEEDS NO RULE -- the white above IS the neutral, which is precisely "the same colours as the text". SPECIFICITY: these are (0,3,0), out-specifying the (0,2,0) base, while `#moe-bar-root.mp-full .mp-tick` is (1,2,0) and still wins on its id, so met-requirement gold keeps owning this tick as intended. `transition` is deliberately NOT restated (declaration-only override) -- restating it would re-arm the left transition. */ .mp-tick.mp-proj.mp-up { box-shadow: 0 0 6rem rgba(123,236,55,0.9),0 0 2rem rgba(123,236,55,0.9); } .mp-tick.mp-proj.mp-down { box-shadow: 0 0 6rem rgba(211,68,63,0.9),0 0 2rem rgba(211,68,63,0.9); } /* Captions live in the TRACK's coordinate space. The two CENTRE ones stack vertically on their tick: pre_avg ABOVE (.up), proj_avg BELOW (.dn, the only one that moves). THAT split is load-bearing -- those two sit ~1% apart, so putting them on one side would overlap. The AXIS-END one is .side: vertically centred on the track's midline and hanging OUTSIDE its right edge (the left-hand .mp-capL twin was removed with the axis-floor numeral). Each caption is ONE ROW: icon LEFT (DOM order: icon, value, delta -- and on .mp-capR a SECOND icon+value pair for the remaining-battles count, in that order because setIco() / capV() both take the FIRST match), numerals right, margin-right as the single gap. GAMEFACE: plain `flex-direction: row`; the earlier `column-reverse` variant (never verified in Coherent) is gone, so no unverified flex mode remains. WHAT translateX(-50%) CENTRES ON THE TICK IS THE NUMERAL, NOT THE ROW. Centring the whole box put the DIGITS left of their own tick by half the icon+gap, and on .dn it drifted as the delta's text width changed. So both siblings are taken OUT of the width the transform halves, each by the mechanism its constraint allows -- the icon by a negative margin that cancels its own box (.mp-capP / .mp-capC .mp-ico), the text-width-dependent delta by going out of flow (.mp-cap .mp-d) -- leaving the numeral as the caption's ONLY in-flow content, so -50% of the box IS -50% of the digits. Same end state as the sibling Damage Efficiency bar, reached differently: there .mp-cap is not a flex row at all. */ .mp-cap { position: absolute; left: 0; transform: translateX(-50%); display: flex; flex-direction: row; align-items: center; white-space: nowrap; z-index: 3; } /* PADDING, NOT MARGIN, ON THE `bottom:100%` / `right:100%` SIDE. Coherent ignores a margin-bottom on an abspos box anchored by bottom:100% (and margin-right on one anchored by right:100%) -- both gaps rendered as 0 in-game and WG's own _dist corpus has 0/515 files pairing them. The attested form is padding on the anchored side: `.Consumable_hotKeyLabel` in mono/hangar/main/main.css (padding-bottom + bottom:100%) and mono/pet_system/pet_storage_tooltip/pet_storage_tooltip.css:23-25 (padding-right + right:100%). Same order of magnitude, and safe here for two reasons: neither caption paints a background / border / box-shadow, so the enlarged box is invisible; and padding grows the box on the anchored AXIS only, while the centring transforms act on the OTHER one (translateX(-50%) on .up is unaffected by height, translateY(-50%) on .capR by width). The `top:100%` / `left:100%` twins below keep their margins -- those pairings DO work. NOT `calc(100% + 6rem)`: a % + rem mix inside one calc() is 0/515 in WG's corpus. */ /* EVERY CAPTION PINS ITS LINE BOX, and that is a BUG FIX, not a style choice. With `line-height: normal` the line box is the font's ascent+descent+gap SNAPPED UP TO WHOLE DEVICE PIXELS, so in rem it is NOT constant -- it shrinks as the rem->px factor grows. For a 16rem caption, measured live: 21.000rem at factor 1, 20.500 at 2, 20.125 at 24 (and for the 12rem delta: 16.000 / 15.500 / 15.083). .mp-ico is a flex item under align-items: center, so HALF that variation goes straight into the glyph's Y -- the icon and delta read ~0.75rem low relative to the numeral at factor 1 versus factor 2 (reported at 3440x1440). THE VALUE: ceil(font_rem * 2 * 1.2565) / 2, i.e. the FACTOR-2 box expressed in rem. 1.2565 is MoEBattle.ttf's fitted line ratio and ceil(font_px * 1.2565) reproduces all six measurements above. Pinned at the factor-2 value ON PURPOSE rather than at the font's true unsnapped ratio: factor 2 is the render this composition was approved on and must not move by even one device pixel, while a `1.2565em` line-height computes to 40.2px there and would shift it 0.75px. Every pin below is therefore byte-identical to what `normal` already yielded at factor 2, and only factors != 2 change. NO LARGE-MODE TWIN, EVER: line-height is a uniform (vertical) length, so the root font (SIZE_F) scales it alone -- a twin would double-apply it. The residual this does NOT fix is the glyph's own ascent snap INSIDE the pinned box (sub-0.5rem, and it moves the numeral and the delta together rather than pulling them apart). ...AND THE PIN IS NOW LOAD-BEARING FOR A SECOND FIX, which is why it must not be reverted or turned back into an em: it makes each caption's box a CONSTANT number of rem, so the vertical anchor of the pieces hanging off it -- (line box - own box) / 2 + the tuned nudge -- is a constant too, and CAN be quantised. It is not, however, a whole number of DEVICE pixels at every rem->px factor. Worked out for ALL FIVE pieces this bar hangs off a caption box, in rem: .mp-capC .mp-ico (20.5 - 16 )/2 + 1 == 3.25 <- 0.25 off the device grid at factor 1, 0.50 off at factor 2: it CAN drift .mp-capP .mp-ico (18 - 14 )/2 + 0 == 2.00 <- whole rem: whole device pixels at EVERY .mp-capR .mp-ico (18 - 17 )/2 + 0.5 == 1.00 factor, so it resolves identically at .mp-capR .mp-ico (18 - 13 )/2 + 0.5 == 3.00 both scales and takes no rule, ever ^ the SAME rule, a smaller box: the .battles glyph (see .mp-ico.battles) .mp-cap .mp-d 0 + 2.5 == 2.50 <- 0.5 off the grid at factor 1, whole at factor 2: it CAN drift, and the maintainer reports it DOES. (.mp-capL is GONE, and with it its ruleless (18 - 17)/2 + 0.5 == 1.00 row -- the axis-floor caption was removed outright. The battles glyph took its place in the table.) THE BATTLES GLYPH'S 13rem BOX IS NOT ARBITRARY: it is .mp-ico's BASE box, so the glyph needs no width/height rule at all, and 13 is one of only two boxes (13 and 17) that land this .side caption's anchor on a WHOLE rem and so keep the row correctly ruleless -- 14, 15 or 16rem would each land on a half and owe a two-rule correction pair of their own. The ICON rows are flex items under align-items:center, so the centring term is the flex line's cross size -- the numeral's line box, i.e. the pin -- minus the glyph's own square box, and the last term is the per-role translateY. THE DELTA ROW HAS NO CENTRING TERM, AND AN EARLIER REVISION OF THIS NOTE GOT THAT WRONG. The wrong prediction is kept here and corrected in place rather than quietly deleted, because it is the plausible reading and the next person will reach for it again. THE FAILED PREDICTION: "the delta is out of flow with NO `top`, so it takes the CENTRED static position it would have as the sole flex item" -- which is CSS Flexbox's own rule (an abspos child's static position is aligned by align-items / justify-content). That yields (20.5 - 15.5)/2 + 2.5 == 5.00rem: a whole rem, therefore whole device pixels at every factor, therefore "structurally incapable of drifting" -- and on that basis the sibling's delta rule was deliberately NOT mirrored. The maintainer then looked at interface scale 1 and reported the delta out by the same one device pixel as the icon. WHY IT IS WRONG: this engine does not implement that flexbox rule. It puts the abspos child at the CSS2.1 static position -- the containing block's content-box origin -- so the used `top` is 0, the centring term is absent, and the tuned translateY IS the whole anchor: 2.50rem. THE EVIDENCE IS THIS BAR'S OWN APPROVED RENDER, not a spec reading. 2.5rem here is the sibling's delta Y carried over verbatim (see the .mp-cap .mp-d note below), and THERE it is measured from an explicit `top: 0` and is exactly the value that centres a 15.5rem delta box on a 20.5rem numeral box -- (20.5 - 15.5)/2 == 2.5. If this engine also centred by static position, that same 2.5rem would put this bar's delta a further 2.5rem (5 device px at factor 2) BELOW its numeral's centre, hanging off the bottom of the caption, and the composition approved at factor 2 would show it. It does not. So THE TWO DELTAS ARE THE SAME SHAPE, land on the same 2.50rem anchor, and need the same correction -- the sibling's rule IS mirrored here after all. THE .up / .dn PADDING-vs-MARGIN ASYMMETRY DOES NOT REACH ANY OF THIS, and was checked explicitly. `.mp-cap.up` puts its gap in `padding-bottom` (Coherent renders a margin-bottom as 0 against a bottom:100% anchor) while `.mp-cap.dn` uses `margin-top`, and a PADDING box is indeed what an out-of-flow child's percentage `top` resolves against -- that trap is real, and it is why .mp-capP's icon stays IN FLOW as a margin (see the per-role nudge note below). But the delta lives on `.dn`, which carries no padding at all, and it declares no `top` to resolve: padding box == content box here, at both factors. Not what moved the delta. .mp-cap.side .mp-v is deliberately NOT in the table: its own box IS the line box, so the centring term is identically 0 at every factor and its -0.5rem is a font-metrics constant, not a scale residual. A CORRECTION IS NOW SHIPPED for both drifting rows -- the appended interface-scale block at the END of this file. It is gated on the `.mp-s1` body class, which MoEBarTransient.setQuantClass() adds when captureBaseFont() reads below 1.5: THAT ROOT-FONT CAPTURE IS THE INTERFACE-SCALE SIGNAL (below 1.5 at scale 1, at/above it at scale 2), established by a four-bit screenshot probe over two fresh launches -- while `devicePixelRatio` and both view ratios read flat across scales and carry nothing. Interface scale 2 adds no class at all, so no selector in that block can match there and the approved render is structurally unreachable. See tests/test_caption_anchor_quantisation.py for the measurements, the gate and the failed attempts. */ .mp-cap.up { bottom: 100%; padding-bottom: 6rem; font-size: 14rem; line-height: 18rem; } .mp-cap.dn { top: 100%; margin-top: 6rem; font-size: 16rem; line-height: 20.5rem; } /* SIDE (axis-end) caption -- ONE of them now (.mp-capR, off the RIGHT end): the axis-floor .mp-capL was removed with its numeral, so `.side` is single-use and the `left: auto` + `right: 100%` release it needed is gone with it. The class is KEPT rather than folded into .mp-capR: it carries the whole side treatment (the .mp-tick vertical trick -- top:50% + translateY(-50%) centring the flex row's box on the track midline -- the font-size, the pinned line box and the numeral nudge below), and the tuner still emits both halves. TWO classes so the transform out-specifies .mp-cap's translateX(-50%): this is not centred on a tick, it is pushed off the end by its own margin. Nothing shares its band, so there is no de-collision pass and JS never measures or repositions it. The translateY(-50%) is on the CAPTION box while the per-role icon nudge is on the .mp-ico CHILD, so the two transforms cannot clobber each other and .mp-ico keeps its own stacking context (see below). Its font-size is its OWN (not .up's): this is a side label, not a top label. */ .mp-cap.side { top: 50%; transform: translateY(-50%); font-size: 14rem; line-height: 18rem; } /* SIDE-CAPTION NUMERAL NUDGE -- a FONT METRICS correction, not a box-height problem. MoEBattle.ttf is ascender 2088 / descender 486 at upem 2048 = a 1.2568em line box (17.60rem at the 14rem side font-size), but the digit ink spans only -0.0132em..0.7192em of the em box -- so the ink's centre sits 0.0381em = 0.53rem BELOW the line box's centre, and it is the BOX that .mp-cap.side's translateY(-50%) centres on the track midline. Result: the numerals read ~0.53rem low; this transform pulls them back. Do NOT "fix" this with min-height/line-height on the caption -- the box is ALREADY 17.60rem tall, so any min-height at or below that (the 17rem mark box, say) is a literal no-op. (The line-height PIN above is not that fix and does not disturb this one: it states the snapped-up box, 18rem, which is what `normal` already yielded at BOTH factor 1 and factor 2 for this font size -- it only stops the box shrinking at higher factors, and the ink offset it corrects is a font-metrics constant either way.) Scoped to .side only: .up/.dn hang off the track edges instead of being centred on the midline, so they must never pick this up. .mp-v is a flex item of the .mp-cap row, so a transform applies to it (it would not on a bare inline span). .mp-eta IS THE SAME CORRECTION ON THE SAME ROW, not an extra: the remaining-battles count is a second numeral in this one flex line, at the same font-size and the same pinned line box, so the ink offset is identical -- leave it out and the count sits 0.53rem BELOW the requirement it counts down to, on the same baseline. */ .mp-cap.side .mp-v, .mp-cap.side .mp-eta { transform: translateY(-0.5rem); } .mp-cap.side.mp-capR { left: 100%; margin-left: 3rem; } /* PER-MARK BLOCK<->BAR GAP, the caption's own distance off the track end -- the SECOND per-mark knob (see the icon<->number overrides further down for the first), tuned in the same tools/dev/icon_gap_tuner.html session. setIco() now mirrors the mark index onto capR itself (mk1/mk2/mk3, alongside its permanent "mp-cap side mp-capR" classes) so these compound selectors can target it -- (0,4,0), CLEANLY beating the base rule's (0,3,0) on specificity alone, no source-order dependency (unlike .mk1/.mk2/.mk3 on the ICON further down, which tie the shared .mk rule). mark_2 keeps the base rule's 3rem unchanged; mark_1 and mark_3 get their own. Large's own per-mark twins are NOT the base times 4/3 (see the Large-mode capR rules, further down in the size-mode block, and their own note) -- a deliberate maintainer decision, the user's eye over the x4/3 contract, which is why those two tests fail on this pair and are left standing for qa to re-scope. */ .mp-cap.side.mp-capR.mk1 { margin-left: 1.000rem; } .mp-cap.side.mp-capR.mk3 { margin-left: 5.000rem; } /* THE BOX-EDGE GAP is a uniform 1rem on every icon -- but each art asset carries its OWN background-size zoom (icoFill 0.75 of a DIFFERENT box, per icon), so the box-edge gap alone left the rows reading unevenly: each icon's actual INK stops a different distance short of its own box edge. PER-ICON MARGIN-RIGHT OVERRIDES below equalise the INK gap instead, box sizes left untouched (maintainer's call: "icon sizes must stay the same, adjust paddings individually") -- mirroring the vertical composition's identical pass byte-for-byte (see MoEProgressVertical.css's own note above `.mpv-ico.dmgp`; the numbers below are IDENTICAL to that pass's, because both bars share the same box sizes and the same icon assets). Measured live off the real PNGs' alpha>32 bbox (gui-part*.pkg), not estimated: dmgp box 14, ink_x == (42/128)*2.287*14 == 10.506rem, inset (14-10.506)/2 == 1.747rem dmgc box 16 (REFERENCE, untouched), ink_x == (28/128)*3.425*16 == 11.988rem, inset == 2.006rem -- base 1rem margin already lands ~3.006rem; every other row is calibrated to a flat 3.000rem target against it, same convention as the vertical pass moe box 17, ink_x == (35/128)*2.747*17 == 12.769rem, inset (17-12.769)/2 == 2.115rem mk box 17, `background-size: contain` on a 24x24 canvas scales the WHOLE canvas by box/24, so mark_1 (ink width 6 of 24), mark_2 (12 of 24, the tuner's own default preview state: ink_x == 17*0.5 == 8.5rem, inset (17-8.5)/2 == 4.25rem) and mark_3 (18 of 24) each land at a DIFFERENT inset. THE SHARED MARGIN THIS NOTE ONCE ACCEPTED AS A RESIDUAL IS RETIRED: .mp-ico.mk1/.mk2/.mk3 below each carry their OWN margin-right now (mark_1 -1.250rem, mark_2 1.000rem, mark_3 4.000rem), hand-tuned in tools/dev/icon_gap_tuner.html rather than solved from the 3.00rem-ink-gap formula the other rows use -- only mark_1's number happens to coincide with the old shared value. battles box 13 (base .mp-ico box, unchanged), calibrated on its OWN X-width (27 of a 128px canvas -- NOT the maxdim(29) icoSz() zooms it by): ink_x == (27/128)*3.31*13 == 9.077rem, inset (13-9.077)/2 == 1.962rem -- see .mp-ico.battles's own rule margin-right == 3.00 - inset, REPLACING the shared 1rem outright: dmgp 1.253rem, moe 0.885rem (LESS than the shared 1rem: moe's ink is already wide enough that less margin gets it to 3.00), battles 1.038rem (added to its existing rule below, alongside margin-left). mk1/mk2/mk3 are NOT part of this formula -- see the per-mark note above. Compound selectors below beat this base rule on SPECIFICITY, not source order (three classes vs two -- the same convention the vertical pass's per-icon overrides use); .mk1/.mk2/.mk3 in turn beat the shared .mk rule by SOURCE ORDER, not specificity (both are three classes, and .mk's own class stays on the element alongside .mk1/.mk2/.mk3 -- see setIco() -- so the tie is real and must be broken by writing the per-mark rules AFTER .mk below). The two CENTRE captions (dmgp, dmgc) additionally cancel their icon's whole outer width with a negative margin-left further down -- see the .mp-capP / .mp-capC rules; dmgp's cancel now reads its OWN 1.253rem gap, never the shared one, while dmgc's stays untouched (it never moves). Kept to 3 decimal places, matching the vertical composition's own twins -- margin is a plain horizontal length with no (rowHeight-box)/2-style quantisation to land on, so unlike a box these carry no whole-rem/whole-device-pixel requirement; the residual is well under a rem, the same accepted class of drift as this file's own .mp-cap .mp-d gap. */ .mp-cap .mp-ico { margin-right: 1rem; } .mp-cap .mp-ico.dmgp { margin-right: 1.253rem; } .mp-cap .mp-ico.moe { margin-right: 0.885rem; } .mp-cap .mp-ico.mk { margin-right: -1.250rem; } .mp-cap .mp-ico.mk2 { margin-right: 1.000rem; } .mp-cap .mp-ico.mk3 { margin-right: 4.000rem; } /* .mp-eta shares the plain-white numeral treatment: same colour, weight and dark legibility drop as .mp-v. It is deliberately NOT a second .mp-v -- capV() is a first-match querySelector(".mp-v") and would keep resolving to the requirement, so a second .mp-v would work today and mis-target on the next edit. It DOES glow now (.mp-eta.mp-up / .mp-eta.mp-down, below), but on the delta's OWN knobs -- st.upCol/st.dnCol, st.dGlowW/st.dGlowT, the same DGA -- and gains no dedicated knobs of its own; JS toggles it in lockstep with capDN off the identical d>0/d<0 test (MoEProgress.js showVal). So .mp-capR is no longer a never-glows caption: its main requirement number (.mp-capR .mp-v) still stays plain white, but the battles-countdown numeral rides the bottom-centre delta's sign. */ .mp-cap .mp-v, .mp-cap .mp-eta, .mp-cap .mp-d { color: #ffffff; font-weight: 600; letter-spacing: 0em; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5); } /* FOR TEXT THE SIGN IS A COLOURED GLOW, NEVER A FILL (shipped .mb-up/.mb-down): the numerals stay WHITE and a green/red text-shadow halo carries the sign, layered OVER the dark legibility drop so it reads on bright AND dark map areas. Do NOT "fix" this into color: green/red. (The .mp-fill.mp-up/.mp-down rules above ARE a real colour fill, on purpose: that argument is about keeping GLYPHS readable and a solid bar has no glyph. Text glows, bar fills, both off the same upCol/dnCol -- do not "unify" them either way.) Triple shadow: dark drop, WIDE pass, TIGHT core pass. THE SPLIT (verbatim from MoEBattle.css's .mb-delta > .mb-delta-num): the delta wrapper .mp-d holds the PARENS as static text nodes and keeps the plain white treatment; only its .mp-d-num child carries the signed digits and the glow -- so "(" and ")" never glow. Markup: (+8). WHO GLOWS: the BOTTOM-CENTRE caption only -- its main number (.mp-capC .mp-v) and the delta number, both off the SAME proj_avg - pre_avg sign. The two requirement captions and the top-centre pre_avg caption are plain white: JS must never put .mp-up/.mp-down on them. A ZERO delta gets NEITHER class -> white + the dark drop only, so a sub-precision change never reads as a win. (The selectors are element-scoped, .mp-v.mp-up not bare .mp-up, so they out-specify the .mp-cap .mp-v base rule above.) WHEN: not while the bar is arriving. An EXPLICIT MAINTAINER DECISION (quoted verbatim at MoEProgress.js showVal) governs the 600ms entry window: it must show the PREVIOUS COMMITTED state, so the entry does NOT clear these classes -- a new sign is only claimed once it lands at the swap (valueSwapMs), together with the numeral, the delta and the fill. Was red and stays red therefore never flickers. The plain-white neutral is reserved for the two states where nothing is committed: the FIRST show of a battle, and a rounded-zero delta (which the swap DOES clear to -- that is the one place removing a class is still required). Do NOT "restore" a class-strip to the entry path. */ /* em, not rem: the two caption rows have different font-sizes and this gap should track them. 0.35em == the shipped .mb-delta's 4.5rem at its 14rem font-size. SIZE + NUDGE ARE THE EFFICIENCY BAR'S, carried over after a live pass (MoEEfficiency.css's `.mp-cap .mp-d`: font-size 12rem, translate(4.2rem, 2.5rem)). The X half must NOT be added again: 0.35em of the delta's OWN 12rem font-size IS 4.2rem, which is exactly how that 4.2rem was tuned. So the font-size below is load-bearing for the gap too -- change it and the gap moves with it. OUT OF FLOW off the numeral's right edge -- the second half of the numeral-centring in .mp-cap's note. A negative margin cannot cancel THIS sibling the way it cancels the icon: the digits change, so any fixed value would leave the centring drifting with the delta's text width. `left: 100%` + margin-left is the SAFE anchored pair (Coherent honours the left/top twins; it is `right:100%`+margin-right and `bottom:100%`+margin-bottom that render a 0 gap), and it keeps the 0.35em gap byte-for-byte as tuned. Same idiom as the sibling MoEEfficiency.css, one declaration short of it: no `top` here. THAT OMISSION BUYS NOTHING, and the note that used to defend it was wrong -- see the failed prediction worked through in the caption-pin block above. This engine resolves an omitted `top` to the CSS2.1 static position, the content-box origin, which is precisely what the sibling spells out as `top: 0`; it does NOT apply flexbox's align-items centring to an out-of-flow child. So the two bars' deltas are the SAME shape, the translateY below is the whole Y story on both, and 2.5rem lands the delta box centred on the numeral's on both. Adding `top: 0` here would be a no-op, not a fix -- and the Y carried over from that bar is only correct BECAUSE the two agree. THE DELTA FADES IN at the numeral swap (valueSwapMs): JS sets opacity 1 there and back to 0 when it re-runs the transient -- the curve is here, not in JS. OPACITY, not visibility (which cannot interpolate). display:none would no longer disturb the centring now that the box is out of flow -- it DID before, and that is why opacity was picked -- but opacity is what interpolates, so it stays. No `visibility` alongside: this whole widget is pointer-events:none, so a 0-alpha box has nothing to hit-test or focus. ONE transition declaration here, naming ONLY opacity, with EXPLICIT ms + easing -- Gameface drops a transition on a property whose value starts from a var() it cannot resolve, so never express these two through a custom property. CANCELLING it (a re-run mid-fade): set transition:none, opacity 0, force a reflow, then restore the transition -- the same idiom the fill/tick rewind uses. */ .mp-cap .mp-d { position: absolute; left: 100%; margin-left: 0.35em; font-size: 12rem; transform: translateY(1.5rem); line-height: 15.5rem; opacity: 0; transition: opacity 600ms cubic-bezier(.2,.8,.2,1); } .mp-v.mp-up, .mp-d-num.mp-up, .mp-eta.mp-up { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0rem 0rem 6rem rgba(123,236,55,0.9), 0rem 0rem 1rem rgba(123,236,55,0.9); } .mp-v.mp-down, .mp-d-num.mp-down, .mp-eta.mp-down { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0rem 0rem 6rem rgba(211,68,63,0.9), 0rem 0rem 1rem rgba(211,68,63,0.9); } /* Only the bottom-centre caption animates (it rides proj_avg); pre_avg's stays put. */ .mp-cap.mp-capC { transition: left 600ms cubic-bezier(.2,.8,.2,1) 600ms; } /* Icon glyphs. GLYPH on ::after, GLOW on ::before with z-index:-1 -- an element's own background paints BELOW its pseudos, which is why the two are split (same as .mb-ico). The transform keeps .mp-ico a stacking context so that -1 stays scoped here. 106% == the overlay's 18rem glow behind a 17rem icon, as a ratio so it follows either box. The glow is TWO COLOURS: this base rule is the gold halo the CENTRE damage icons wear; the two axis-end requirement marks override it to a dark drop in the next rule. FRAMING is derived, not a flat zoom: background-size = 100*(canvas/glyph)*0.75 from the MEASURED bboxes (damage 0.219, barrel_mark 0.328, top 0.273 of the 128px canvas), computed PER ICON -- the top and bottom centre glyphs are chosen independently, so each carries its own background-size. The shipped overlay's flat 260% framed those two at 57% vs 85% fill -- visibly different. NOTE: .mb-ico.dmg in the shipped widget actually paints barrel_mark, so "match the in-battle widget" and "use a distinct damage glyph" conflict -- this build picked barrel_mark (top) / damage (bottom). brightness(3) lifts the flat grey #d1d1d1 quest_type line art; the marksOnGun cuts are 24x24 and ALREADY warm cream (~#ede6d9) -> NO brightness on them. Their canvas is constant (glyph y 5..17) and only the WIDTH grows with the count (mark_1 x 9..14, mark_2 x 6..17, mark_3 x 3..20), so background-size:contain on ONE fixed box renders mark_1 at ~1/3 the width of mark_3 -- do NOT trim per count. At 24px of source art they visibly blur above ~24rem. */ .mp-ico { position: relative; display: block; flex: none; width: 13rem; height: 13rem; transform: translate(0rem, 0rem); } /* PER-ROLE VERTICAL NUDGE. Each glyph family sits differently on its baseline (24px marksOnGun cuts vs 128px quest_type line art), so every caption's icon gets its own signed Y. It MUST stay on this same `transform`: the transform is what makes .mp-ico a stacking context and so scopes the ::before glow's z-index:-1 -- swap it for a margin and the glow escapes and paints under the whole caption. ::before is centred INSIDE this transformed box (left/top 50% + its OWN translate(-50%,-50%)), so the glow travels with the glyph and its centring is unaffected at any Y. ...AND, ON THE TWO CENTRE CAPTIONS ONLY, THE ICON'S WIDTH CANCELLED -- the first half of the numeral-centring in .mp-cap's note. margin-left is -(this caption's own icon box + ITS OWN margin-right gap), so the icon's OUTER width is exactly 0 (-box-gap + box + gap): the numeral starts at the caption's origin and the glyph still paints its own gap to its left, unmoved. A MARGIN and not position:absolute precisely so the icon stays IN FLOW -- it keeps the transform above (both the Y and the stacking context), and out of flow it would need a top:50% that, on .up, resolves against a PADDING box carrying 6rem and would drop the glyph half that gap. PER CAPTION because the box AND the gap are both per caption now (dmgP / dmgC are independent sliders, and dmgP's ink-gap correction above replaces its slice of the shared icoGap) -- DERIVED from those, never a literal, or a retune breaks the centring. dmgC still reads the shared icoGap (it is the untouched reference), so its cancel is unchanged. NOT on the .side caption: it is not centred on anything, it is pushed off the axis end by its own gap, so cancelling its icon would just slide the label inwards over the track. .mp-capR NOW CARRIES TWO ICONS AND THIS ONE RULE NUDGES BOTH -- the mark glyph and the battles glyph. That is deliberate, and it is arithmetic rather than luck: the 0.5rem was tuned to push the marksOnGun cuts' ink (y 5..17 of a 24px canvas, ink centre 0.458 of the box) back onto the numerals' centre, and the battles glyph's alpha>32 ink centre sits at 62.5/128 == 0.488 of its own canvas -- 0.012 of a 13rem box == 0.16rem of residual, a sixth of the nudge itself. So no second knob is added here: if a live pass ever shows the battles glyph wants its own Y it gets its OWN rule (`.mp-capR .mp-ico.battles`, full declaration -- a transform REPLACES its base), and this shared 0.5rem is NOT retuned, or the mark glyph moves with it. NEEDS VISUAL CONFIRMATION IN-CLIENT: the 0.16rem residual is derived from the bbox, not seen. */ .mp-capP .mp-ico { transform: translate(0rem, 0.5rem); margin-left: -15.253rem; } .mp-capC .mp-ico { transform: translate(0rem, 1rem); margin-left: -17rem; } .mp-capR .mp-ico { transform: translate(0rem, 0.5rem); } .mp-ico::before { content: ""; position: absolute; left: 50%; top: 50%; z-index: -1; width: 106%; height: 106%; transform: translate(-50%, -50%); background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } /* THE AXIS-END (.side) CAPTION'S ICONS GLOW INDEPENDENTLY of the two centre damage icons -- own colour, own alpha, and TUNED APART: these are a DARK DROP (near-black #1a1a1a at half alpha) rather than a halo, while the centre pair keeps the gold. Deliberate, not a leftover -- the mark glyphs read better lifted off the map by a shadow. This targets ::before and sets BACKGROUND ONLY, so: - the base rule above still supplies z-index:-1, the 106% box and its own translate(-50%,-50%), i.e. the glow's radius geometry is identical for both groups; - .mp-ico's OWN transform is not touched, and that matters twice over -- it carries the per-role Y nudge (icoYR) AND it is the stacking context that scopes the z-index:-1 to the icon. Never move this override onto .mp-ico. Matches BOTH of this caption's icons -- the mark (or the general-MoE glyph that replaces it at 3 marks) and the battles glyph -- because both are `.mp-capR .mp-ico`. Specificity (0,2,1) > the base (0,1,1), so only the gradient is replaced. But only the MARK glyph actually shows this drop: the battles glyph opts back OUT to gold via `.mp-ico.battles::before` (below), which matches at the SAME (0,2,1) specificity, so the cascade falls through to SOURCE ORDER and the later rule wins on that one icon. That is a source-order dependency, not a specificity one -- reorder the two rules (or insert another (0,2,1) `::before` rule ahead of the battles one) and the battles glyph silently reverts to the dark drop with no error anywhere; verify the resolved styles, not the file's line numbers, after any such reorder. (The tuner's emitted form groups `.mp-capL .mp-ico::before` in front of this; that half went with the caption.) */ .mp-capR .mp-ico::before { background: radial-gradient(circle at 50% 50%, rgba(26,26,26,0.5) 0%, transparent 73%); } .mp-ico::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: no-repeat; background-position: center; } /* dmgp = TOP centre (pre_avg), dmgc = BOTTOM centre (proj_avg) -- independent glyph AND box. */ .mp-ico.dmgp { width: 14rem; height: 14rem; } .mp-ico.dmgc { width: 16rem; height: 16rem; } .mp-ico.dmgp::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_barrel_mark.png); background-size: 228.7%; filter: brightness(3); } .mp-ico.dmgc::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_damage.png); background-size: 342.5%; filter: brightness(3); } /* Box parity with .mp-ico.mk: this glyph REPLACES the right caption's mark at 3 marks, so without its own size it would inherit .mp-ico's 13rem and visibly shrink the caption's icon 17 -> 13rem at that one moment. 17rem is already the caption's icon width at marks 1-3, so restating it here introduces no new maximum. */ .mp-ico.moe { width: 17rem; height: 17rem; } .mp-ico.moe::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_top.png); background-size: 274.7%; filter: brightness(3); } .mp-ico.mk { width: 17rem; height: 17rem; } .mp-ico.mk::after { background-size: contain; } .mp-ico.mk1::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_1.png); } .mp-ico.mk2::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_2.png); } .mp-ico.mk3::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_3.png); } /* THE REMAINING-BATTLES GLYPH -- the second icon on .mp-capR, marking the count of repeats of this battle still needed to reach that requirement (domain.battles_to_axis_hi, capped at 99). NO width/height OF ITS OWN, and that is a decision, not an omission: it takes .mp-ico's BASE 13rem box -- the only glyph in the file that does -- for two independent reasons. It reads as SECONDARY to the 17rem mark it follows, and 13 is one of only two boxes that land this .side caption's icon anchor on a whole rem, keeping the row correctly free of an interface-scale correction pair (worked in the caption-pin table above). img:// resolves against the packed .pkg at runtime, exactly like the three quest_type glyphs above -- there is NOTHING to extract, ship or sync_gameface for this icon. background-size IS THE SAME DERIVED RECIPE, 100/bb*icoFill with icoFill 0.75 (gen_bar_tuner.ps1:905's icoSz), fed the ALPHA>32 bbox and not a raw getbbox(): this art family carries a faint halo that reads ~2.3x too big. Measured bbox (50,48)-(77,77) on the 128x128 canvas -> max dim 29 -> bb = 29/128 = 0.226563 -> 100/0.226563*0.75 = 331.03 -> 331.0%. Same convention that produced 342.5 / 228.7 / 274.7 for damage / barrel_mark / top; all three re-verified against it here. brightness(3) for the same reason as those three: the quest_type line art ships as a flat grey #d1d1d1. margin-right: 1.038rem BELOW is the ink-gap parity correction (see the base `.mp-cap .mp-ico` rule's note): unlike this icon's bbox above, the WIDTH that matters for a horizontal gap is 27 of the 128px canvas (NOT the maxdim 29 icoSz() zooms against), so ink_x == (27/128)*3.31*13 == 9.077rem, inset (13-9.077)/2 == 1.962rem, margin-right == 3.00-1.962 == 1.038rem. EQUAL SPECIFICITY to the base rule's (0,2,0) -- `.mp-ico.battles` is two classes too, not three -- so this wins purely on SOURCE ORDER (it sits after the base rule); reordering the file would silently revert this icon to the shared 1rem gap, the same species of race the ::before pair right below already documents. */ .mp-ico.battles { margin-left: 4rem; margin-right: 1.038rem; } /* GOLD, NOT THE SIDE CAPTION'S DARK DROP: same-specificity override of .mp-capR .mp-ico::before (above, ~:581) by SOURCE ORDER alone -- both are two classes plus a pseudo-element, so the cascade has no specificity tiebreaker here and falls through to "last rule wins". This rule MUST stay after that one or the dark drop silently wins back and the gold never renders; if this file is ever reordered, re-verify with the resolved styles, not the line numbers. */ .mp-ico.battles::before { background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } .mp-ico.battles::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_battles.png); background-size: 331.0%; filter: brightness(3); } /* THE SUPPRESSION VARIANT, and `display: none` is load-bearing rather than incidental: it COLLAPSES the flex item's whole box -- its square AND its own margin-right, whatever that icon's is (the shared 1rem for the mark/moe slot, or the battles icon's own 1.038rem override) -- so a suppressed glyph leaves no hole in the row. A background-only blank would have left the battles glyph's 13rem + gap as dead space beside an empty count. JS toggles this class on the battles icon (MoEProgress.js paintStatic) and setIco() writes it for a 0 mark count. */ .mp-ico.none { display: none; } /* proj_avg >= thresholds[m+1] -> the WHOLE bar takes the gold glow. */ #moe-bar-root.mp-full .mp-track, #moe-bar-root.mp-full .mp-fill, #moe-bar-root.mp-full .mp-tick { box-shadow: 0 0 8rem rgba(255,205,90,0.5); } /* ...and the FILL's own COLOUR becomes that same gold -- the requirement being met outranks the up/down sign. It needs a rule of its OWN: the grouped selector above is the box-shadow for the track, the fill AND the ticks, whereas this background must land on .mp-fill only. SPECIFICITY: `#moe-bar-root.mp-full .mp-fill` is (1,2,0) and .mp-fill.mp-up / .mp-fill.mp-down are (0,2,0), so the gold wins on its own -- no !important, and JS keeps toggling the sign classes exactly as before (they simply stop being visible on the fill while .mp-full is on). Same gold as the glow (ONE gold in this file), its own alpha because a solid bar needs more than the glow's. `transition` is NOT restated: width remains the ONLY animated property -- the background FLIPS, it does not interpolate, and `transition: all` would break that. */ #moe-bar-root.mp-full .mp-fill { background: rgba(255,205,90,0.8); } #moe-bar-root.mp-full .mp-v { text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0 0 8rem rgba(255,205,90,0.5), 0 0 2rem rgba(255,205,90,0.5); } /* WG's transient idiom (battle_notifier/BattleNotifierView.css): ONE animation, opacity stops at the fade boundaries. JS adds .mp-run to play it and sets the fill/tick target AFTER the fade-in completes (tick delay below == the fade-in duration by default). On that SAME delay (valueSwapMs in the JSON below) JS swaps the bottom numeral pre_avg -> proj_avg and reveals the delta, its sign glow and the fill colour: while the bar is still arriving it must not claim a gain it has not shown. The Y-axis SLIDE is folded into the same keyframe. GAMEFACE: a transform transition needs MATCHING FUNCTION LISTS across every keyframe -> translateY() on ALL FOUR stops (0rem on the held ones), never bare on some and absent on others, and the element keeps explicit dimensions. Separate in/out easings inside one animation means per-stop animation-timing-function; the middle stop is linear so the hold does not creep. The exit RETURNS THE WAY IT CAME: the bar slides up from below and drops back DOWN out of frame, so the 100% stop repeats the 0% translateY (both +slide) rather than negating it. This is NOT WG's vehicle_messages_panel continue-upward idiom -- deliberately reversed. SLIDE DISTANCE = 20rem, and it is NOT the tuner's original emission. The tuner's slideStops() bypassed its own pxrem calibration (0.833 stage px/rem) and emitted a literal `rem`, so with the browser's default 16px root font the APPROVED stage look was a 16px slide == ~19.2 rem- equivalents while the slider read 1. Shipping that literal 1rem == 1 LOGICAL PX in Gameface: the slide ran exactly as written and was physically imperceptible (live-reported as "the fade works but the slide is invisible"). 20rem reproduces the approved look and is WG's own dominant non-zero keyframe translate magnitude (their floor is 3rem -- 1rem was an order of magnitude below anything WG animates). Maintainer-approved. Do NOT "restore" it to 1. */ @keyframes mp-life { 0% { opacity: 0; transform: translateY(20rem); animation-timing-function: ease-in; } 9.68% { opacity: 1; transform: translateY(0rem); animation-timing-function: linear; } 90.32% { opacity: 1; transform: translateY(0rem); animation-timing-function: ease-in; } 100% { opacity: 0; transform: translateY(20rem); } } #moe-bar-root.mp-run { animation: mp-life 6200ms both; } @keyframes mp-pulse { 0%, 100% { box-shadow: 0 0 8rem rgba(255,205,90,0.5); } 50% { box-shadow: 0 0 16rem rgba(255,205,90,0.80); } } #moe-bar-root.mp-full.mp-pulse .mp-track { animation: mp-pulse 1200ms ease-in-out infinite; } /* APPENDED (not tuned -- a byte-identical copy of mp-life / .mp-run above, renamed). WHY: JS restarts the transient with the classic remove-class -> force-reflow -> re-add-class idiom, which is UNPROVEN in Coherent/Gameface -- mp-life is the only @keyframes anywhere in this client. If the engine coalesces the re-add with the run it just cancelled, the restart is a NO-OP, and because #moe-bar-root rests at opacity 0 with `both` fill that leaves the bar permanently INVISIBLE after its first appearance (exactly the reported symptom). So JS ALTERNATES between .mp-run and .mp-run-b (MoEProgress.js armRun): consecutive runs carry DIFFERENT animation-names, which the engine cannot coalesce. Keep the two blocks identical: any tuner change to mp-life must be mirrored here verbatim. Once a launch proves the plain restart works in Coherent, delete this pair and drop armRun's alternation. */ @keyframes mp-life-b { 0% { opacity: 0; transform: translateY(20rem); animation-timing-function: ease-in; } 9.68% { opacity: 1; transform: translateY(0rem); animation-timing-function: linear; } 90.32% { opacity: 1; transform: translateY(0rem); animation-timing-function: ease-in; } 100% { opacity: 0; transform: translateY(20rem); } } #moe-bar-root.mp-run-b { animation: mp-life-b 6200ms both; } /* ===== APPENDED HAND-ADDED BLOCK -- THE "LARGE" SIZE MODE (mod_settings.progress_bar_size == 1). NOT tuned, and no tuned value above is touched. ponytail: a future `gen_bar_tuner.ps1 -EmitCss` re-emit OVERWRITES this whole file and would drop this block silently (the repo lesson `emitcss-is-not-the-whole-shipped-stylesheet` -- this file already carries two other hand-added regions for the same reason). The sibling MoEEfficiency.css has a headless splice (tools/dev/emit_eff_css.js + check_eff_css.js) that re-applies its three blocks by construction; the honest ceiling here is that the tuner has no such path, so the guard that belongs on it is a pytest assertion in tests/test_progress_surface_mirror.py (the same gate that already catches a re-emit reverting the delta's size and the icon-width cancels). WHY SO LITTLE CSS: the size mode is delivered by the ROOT FONT SIZE (MoEBarTransient.js's SIZE_F == 1.25), which is the rem->px factor in Gameface. That single write re-lays the whole composition 1.25x larger and correctly leaves every %, em, `contain`, gradient stop and derived icon background-size ratio alone -- so height, every font, every icon box, every glow radius, the vertical caption gaps and mp-life's 20rem slide all scale with NO rule below. What is left is the HORIZONTAL x-lengths: an x-length must carry an extra SIZE_XF == 4/3 on top of the root font's 1.25 to reach 5/3 total (1.25 * 4/3 == 5/3), so EVERY declaration below is an x-length and nothing else -- and this block's OWN values do not move with SIZE_F at all: they are the base times SIZE_XF alone (unchanged at 4/3), since the root font already carries SIZE_F on every rem they are expressed in. Do NOT add a font-size, a height or a keyframe here -- that would double-apply SIZE_F. SCOPE: `.mp-lg` goes on the BODY (MoEBarTransient.applySize), WG's own ancestor-class idiom (.mediaLargeWidth ...). It cannot go on #moe-bar-root: #moe-bar-box is a body-level SIBLING of the JS-created root. Every selector below is its base rule plus one class, so it out-specifies it. Values are the base times 4/3, to 3dp -- except the two NEGATIVE MARGINS and the sizing box, which are RE-DERIVED because they mix in a non-x term (see each). */ /* The surface mirror, in document rem: VIEW_W_REM' == BOX_W_REM*4/3 + 2*PAD_REM == 480 + 20. NOT 380*4/3: PAD_REM is slack on both axes and does NOT take the x factor. Height is unchanged (92rem at 1.25x root font == the 115 logical px the JS pushes). */ .mp-lg #moe-bar-box { width: 500rem; } /* The track: 200 -> 266.667. Still tiles the (now 4rem) dash period without a truncated GAP -- 66 whole periods then a final full 2.667rem dash flush against the right edge, exactly as at 1x (the whole grid is scaled uniformly, so that invariant is preserved by construction). */ .mp-lg #moe-bar-root { width: 266.667rem; } /* INTENTIONAL ASYMMETRY (user-approved, symmetry contract retired) -- the Large twin of the base .mp-backdrop shift: left is base -72rem x 4/3 == -96rem while width stays 480rem, so the bleed is now uneven (96rem left / 112rem right), matching the Default mode's own retired symmetry. The old symmetric -106.667rem (== -80 x 4/3) is deliberately gone; do NOT "fix" it back. NOTE: this breaks the anchor_centred `max_x // 2` free-centring the symmetric backdrop used to buy -- accepted. */ .mp-lg .mp-backdrop { left: -96rem; width: 480rem; } /* The dash grid's horizontal geometry: 2rem dash + 1rem gap -> 2.667 + 1.333, i.e. a 4rem period, and background-size's x term MUST stay equal to dash+gap or the grid drifts out of phase. The colours and the outset ring are untouched (the ring is uniform -- the root font has it). */ .mp-lg .mp-track::after { background-image: repeating-linear-gradient(90deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2.667rem,rgb(13,14,16) 2.667rem,rgb(13,14,16) 4rem); background-size: 4rem 100%; } /* Tick WIDTH only -- its 9rem height is a y length. */ .mp-lg .mp-tick { width: 2.667rem; } /* The ONE caption gap (icoGap -- it applies to BOTH of .mp-capR's icons), and the surviving axis-end gap (gapEndR as margin on the left:100% anchor -- see the base rule for which side Coherent honours). 1 -> 1.333, 3 -> 4. The tuner's gapEndL twin (`.mp-lg .mp-cap.side.mp-capL { padding-right: 10.667rem; }`) went with the caption. */ .mp-lg .mp-cap .mp-ico { margin-right: 1.333rem; } /* THE PER-ICON INK-GAP CORRECTIONS' TWINS (see the base `.mp-cap .mp-ico` rule's note) -- plain x4/3 of the base rem values, same as the shared gap just above: margin-right is a horizontal length wherever it lives, so it owes SIZE_XF like any other. 1.253 -> 1.671, 0.885 -> 1.180, -1.250 -> -1.667. */ .mp-lg .mp-cap .mp-ico.dmgp { margin-right: 1.671rem; } .mp-lg .mp-cap .mp-ico.moe { margin-right: 1.18rem; } /* 0.885 * 4/3, trailing zero dropped */ .mp-lg .mp-cap .mp-ico.mk { margin-right: -1.667rem; } /* PER-MARK Large levers -- SCOPE DECISION (user's eye over the x4/3 contract): -1.250/1.000/ 3.000rem, LITERAL, reported directly by tools/dev/icon_gap_tuner.html, not derived from the Default row (-1.250/1.000/4.000) times 4/3 (which would be -1.667/1.333/5.333). Ties .mk on specificity (also (0,4,0) once .mp-lg is added), beaten by SOURCE ORDER, written after it. test_every_large_declaration_is_its_base_counterpart_times_four_thirds and test_the_large_block_twins_exactly_the_base_cascades_x_lengths both KNOWINGLY fail on this -- left standing for qa to re-scope, per the maintainer's explicit decision. */ .mp-lg .mp-cap .mp-ico.mk1 { margin-right: -1.250rem; } .mp-lg .mp-cap .mp-ico.mk2 { margin-right: 1.000rem; } .mp-lg .mp-cap .mp-ico.mk3 { margin-right: 3.000rem; } /* THE ETA GAP'S TWIN, and this is an x-length not a fixed-pixel correction: the base rule's 4rem gap widens the row's own reach (see MoEProgress.js's header comment), so under Large it owes the block's SIZE_XF == 4/3 like every other x-length here, not the SIZE_F the root font already carries. 4 * 4/3 == 5.333, to the block's 3dp -- same precision as the icon-width cancels below (1rem -> 1.333, -11.5rem -> -15.333). margin-right is the battles icon's OWN ink-gap twin, 1.038 * 4/3 == 1.384, same lever as the three rules just above. */ .mp-lg .mp-ico.battles { margin-left: 5.333rem; margin-right: 1.384rem; } .mp-lg .mp-cap.side.mp-capR { margin-left: 4rem; } /* PER-MARK Large block<->bar gaps -- SCOPE DECISION (user's eye over the x4/3 contract): 1.000/3.000/5.000rem, LITERAL, byte-identical to the Default row (this bar's block-gap happens to be size-invariant per mark, unlike its lever). (0,4,0), CLEANLY beating the base rule's (0,3,0) on specificity -- no source-order tie, same as the Default pair. Same two tests knowingly fail on this; left standing for qa. */ .mp-lg .mp-cap.side.mp-capR.mk1 { margin-left: 1.000rem; } .mp-lg .mp-cap.side.mp-capR.mk2 { margin-left: 3.000rem; } .mp-lg .mp-cap.side.mp-capR.mk3 { margin-left: 5.000rem; } /* THE DELTA'S GAP, and the ONE x-length here dialled in `em` rather than rem -- which is exactly why it was missing until now: 0.35em of the delta's OWN font-size already rides SIZE_F (the root font grows that font-size 1.25x), but an x-length owes SIZE_F * SIZE_XF, so under Large the gap came out 25% SHORT while the sibling MoEEfficiency.css -- which spells the same gap as the rem x half of `.mp-cap .mp-d`'s translate -- carried its twin correctly. Still em, so it keeps tracking the delta's font-size: 0.35 * 4/3 at the block's 3dp. The base rule's translateY is NOT restated -- a plain rem Y needs no twin, the root font scales it. */ .mp-lg .mp-cap .mp-d { margin-left: 0.467em; } /* THE TWO CENTRE CAPTIONS' ICON-WIDTH CANCELS ARE RE-DERIVED, NOT MULTIPLIED: the margin is -(this caption's own icon box + ITS OWN gap), and the icon BOX is a uniform y-ish length that the root font scales on its own -- only the gap takes the x factor. dmgC still reads the shared icoGap (untouched reference): -(16 + 1.333) == -17.333, unchanged. dmgP now reads its OWN 1.253rem ink-gap correction, not the shared icoGap, so its twin is -(14 + 1.253*4/3) == -(14 + 1.671) == -15.671 -- NOT -15.333 (that would be the shared gap's twin) and NOT -15.253*4/3 (that would double-apply SIZE_XF to the box). Declaration-only overrides: the per-role translateY (and with it the stacking context scoping the glow's z-index:-1) still comes from the base rules. */ .mp-lg .mp-capP .mp-ico { margin-left: -15.671rem; } .mp-lg .mp-capC .mp-ico { margin-left: -17.333rem; } /* ===== END APPENDED HAND-ADDED BLOCK ===== */ /* ===== APPENDED HAND-ADDED BLOCK -- THE INTERFACE-SCALE CAPTION CORRECTION (interface scale 1). NOT tuned, and no tuned value above is touched. The tuner has no notion of the interface scale, so this can no more come out of `gen_bar_tuner.ps1 -EmitCss` than the size mode above can. A re-emit writes TASKS/refs/MoEProgress.css and not this file, so the two guards standing in for a splice are the tuner's own $APPENDED advisory (it names `.mp-s1`) and tests/test_progress_surface_mirror.py, which requires both blocks to keep their markers. WHAT IT CORRECTS: TWO pieces of the bottom-centre caption -- its damage GLYPH (anchor 3.25rem) and its DELTA (anchor 2.50rem) -- and nothing else on this bar. The table in the caption-pin note above works all five candidates; the other three land on a whole rem, whole device pixels at every factor, so they take no rule and must NOT be given one. THE DELTA PAIR WAS ADDED LATE, AFTER THE MODEL SAID IT COULD NOT DRIFT AND THE MAINTAINER'S EYES SAID IT DOES. The first revision of this block asserted that this bar's delta takes the flex container's CENTRED static position and lands on a whole 5.00rem, and refused to mirror the sibling's rule on that basis. That was a bad input, worked through and corrected in the caption-pin note: this engine gives an out-of-flow child the CSS2.1 static position (the content-box origin), which is the same anchor the sibling gets from an explicit `top: 0`. Both deltas land on 2.50rem -- 0.5 off the device grid at factor 1, whole at factor 2 -- so the mirror was owed all along. THE MAGNITUDE IS ONE DEVICE PIXEL, UP-SCREEN, ON BOTH PIECES, AND IT IS EMPIRICAL. No screenshot pair has been taken of THIS bar: what ships is the sibling bar's MEASURED corrections (the icon's ink top 1841 -> 1840 at interface scale 1; the delta's bottom -1.00rem from the digit baseline against -2.00rem at scale 2) plus the maintainer's live report, made separately for the glyph and for the delta, that this bar drifts the same way and by the same amount. The anchor arithmetic says only that a residual EXISTS at factor 1 and not at factor 2; it predicts no magnitude -- and on the delta it did not even predict the residual until its static-position input was fixed. If a measurement is ever made it replaces the pixel count, not the structure. ONE DEVICE PIXEL IS NOT ONE REM AT BOTH SIZES, which is the whole reason each piece takes two rules. Large IS the root font (baseFont * SIZE_F == 1 * 1.25), so at interface scale 1 the rem->px factor is 1 at the Default size and 1.25 under Large: one device pixel is 1rem there and 1/1.25 == 0.8rem here. Each Y is therefore its base rule's Y MINUS that pixel. tests/test_caption_anchor_quantisation.py re-derives all four from their base rules and from SIZE_F scraped out of the JS, so a retune of a base Y -- or of SIZE_F -- cannot silently leave a correction behind. THE LARGE RULE OF EACH PAIR IS A COMPOUND, `.mp-s1.mp-lg` (0,4,0), NEVER `.mp-s1 .mp-lg`. Both classes land on document.body, so a lone `.mp-s1` rule would match under Large too and, being later in the file, would win -- shipping the Default size's 1rem pixel at 1.25x. (On this bar neither size twin is a transform: `.mp-lg .mp-capC .mp-ico` declares margin-left and `.mp-lg .mp-cap .mp-d` margin-left, so unlike the sibling there is no x-length in the same property for a lone rule to swallow -- but the compound is still what makes the two different Y values reachable at all.) ALWAYS THE FULL DECLARATION, NEVER A BARE translateY() BOLTED ON: a transform declaration REPLACES its base outright, so whatever the base spells has to be restated here verbatim. On the icon that is the x term -- and with it the transform that makes .mp-ico a stacking context and scopes the ::before glow's z-index:-1 (see the per-role nudge note above); the x is 0rem at both sizes and is restated for exactly that reason. On the delta the base declaration IS a bare `translateY()` (its gap rides margin-left, not the transform), so restating that shape is already verbatim-complete -- do NOT "improve" it into a translate() pair here, which would silently re-anchor its x at 0. NO CUSTOM PROPERTY ANYWHERE NEAR ANY OF THIS EITHER: Gameface drops the whole declaration on an unresolved var(), which on a transform costs the glyph its stacking context as well as its Y. INTERFACE SCALE 2 CANNOT MATCH ANY OF IT. setQuantClass adds no class there, and neither does an untrusted read (the positive lower bound in MoEBarTransient.js), so both fall back to the base cascade -- the render the maintainer approved, bit for bit. */ .mp-s1 .mp-capC .mp-ico { transform: translate(0rem, 0rem); } .mp-s1.mp-lg .mp-capC .mp-ico { transform: translate(0rem, 0.2rem); } .mp-s1 .mp-cap .mp-d { transform: translateY(0.5rem); } .mp-s1.mp-lg .mp-cap .mp-d { transform: translateY(0.7rem); } /* NEW: the maintainer's own "lower the top-row icon 0.5 device px" nudge pushed .mp-capP .mp-ico off a whole rem too (anchor (18-14)/2 + 0.5 == 2.5, was 2.00 -- see test_only_the_ma_pieces_off_a_whole_rem_carry_a_correction), joining .mp-capC .mp-ico / .mp-cap .mp-d in the SAME uniform -1-device-px correction this composition already applies to every fractional anchor at interface scale 1 (see this block's own header: "-1rem... NOT the output of any box arithmetic"). Default: 0.5 - 1 == -0.5. LARGE DELIBERATELY RIDES SIZE_F ALONE, same as .mp-capC's own base rule -- no Large-specific override was added for the raw nudge itself (that would have meant a THIRD icon-Y convention in this file: capC/delta ride SIZE_F, the mk levers are literal-per-size, and capP's own icon Y would have been device-px-pinned. Riding SIZE_F keeps it in the FIRST camp, at the cost of the nudge itself landing 0.625 device px under Large, not exactly 0.5 -- a known, accepted 0.125px drift, not a bug). The correction is the mechanical `-1 device px over SIZE_F` this file already runs for every OTHER Large twin: 0.5 - 1/SIZE_F(1.25) == 0.5 - 0.8 == -0.3. */ .mp-s1 .mp-capP .mp-ico { transform: translate(0rem, -0.5rem); } .mp-s1.mp-lg .mp-capP .mp-ico { transform: translate(0rem, -0.3rem); } /* ===== END APPENDED INTERFACE-SCALE BLOCK ===== */ /* Animation timings for phase 2's JS (the numbers, not just the CSS): { "fadeInMs": 600, "holdMs": 5000, "fadeOutMs": 600, "totalMs": 6200, "slideRem": 20, "slideEasingIn": "ease-in", "slideEasingOut": "ease-in", "fadeEasing": "ease-in", "tickDelayMs": 600, "tickDurationMs": 600, "tickEasing": "cubic-bezier(.2,.8,.2,1)", "valueSwapMs": 600, "deltaFadeMs": 600, "deltaFadeEasing": "cubic-bezier(.2,.8,.2,1)", "glowPulseMs": 1200, "axisMode": "mark", "windowN": 60, "topGlyph": "barrel_mark", "bottomGlyph": "damage" } */ PK!(<6m m :res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgress.js// 14th_ua's MoE Calculator -- in-battle centre-screen MoE progress bar (the TRANSIENT one; the // always-on corner readout is MoEBattle.js). Front-end of a STANDALONE OpenWG-registered Gameface // view (MoEProgressView.html, registered via mods/configs/res_map/MoEProgressView.json) that // bridge/progress_view.py opens as a CONTENT-SIZED (NOT full-screen), input-transparent window // centred over the battle HUD. Do NOT re-add full-screen sizing / width:100% -- see // bridge/battle_view.py for the Ctrl+click/hover input-steal that cost us. // // Because this is a registered view, OUR data model (ProgressVM) IS the view's own root // ViewModel: a bare ModelObserver() with NO feature name, fields read DIRECTLY off the root // (model.projAvg, ...). No nested submodel and NO unwrap dance -- that is only the garage's // nested-model path. // // WHAT THE BAR SHOWS: where the career moving-average combined damage sits between the // requirement for the mark you HOLD and the requirement for the next one, and the nudge THIS // battle contributes. Everything derived here is derived in COMBINED DAMAGE, not percentiles: // Python pushes the two axis ends plus pre_avg / proj_avg and this file does the arithmetic. // // THE LOOK IS FINISHED AND NOT NEGOTIABLE: MoEProgress.css was settled in a browser tuner // (tools/dev/gen_bar_tuner.ps1) and copied verbatim, and this file is a port of that tuner's own // preview script (setPos / showVal / replay / the animationend force-settle) -- not an // invention. Its comments explain every value; read them before changing a number. The battle // window has NO hot-reload (it pins its resources at client launch), so every tweak here costs a // full client relaunch: tune in the browser, not in the client. // // TWO ORIENTATIONS, ONE DOCUMENT. The bar draws HORIZONTALLY (MoEProgress.css, .mp-*) or VERTICALLY // beside the minimap (MoEProgressVertical.css, .mpv-*) depending on mod_settings' // progress_bar_orientation, pushed as the VM's `vertical`. Both stylesheets are ed from // MoEProgressView.html and are namespace-DISJOINT; the choice is a MOUNT-TIME branch (goVertical), // NOT a second res_map layout -- a new itemID would cost every user a one-time client restart. The // PLACEMENT half is Python's and already orientation-aware (bridge/bar_window._resolve). // // pointer-events:none throughout (in the CSS) -- pure HUD info, never an input target. import { ModelObserver } from "../../libs/model.js"; // The transient machinery -- arming, the negative-delay debounce, the Alt peek's pause/seek, the end // race and the surface re-assert -- is SHARED with MoEEfficiency.js. Every behaviour in there cost a // client relaunch to find; read its header before changing anything that touches timing. Separate // documents, so this module is instantiated twice with no cross-talk. import { createTransient, fmt, FADE_IN_MS } from "./MoEBarTransient.js"; // No feature name -> observe this view's OWN root model (window.model == ProgressVM). const observer = ModelObserver(); // This bar's ONE timing of its own: when the bottom numeral commits to proj_avg. It tracks // tickDelayMs by construction, which is the shared FADE_IN_MS. const VALUE_SWAP_MS = FADE_IN_MS; // --- the surface, and the rigid shift into it ---------------------------------------------- // A Gameface view PUSHES its own size to C++ through the `viewEnv` global // (viewEnv.resizeViewRem(w, h), rem == logical px); a view that never calls it gets the engine's // "default view size" fallback after a `Size calculation timeout` -- a flat 256x256 logical px, // which is what clipped this bar. WG precedent for the same window shape: DogTagMarkerView.js // calls resize(500, 300, "rem") once on mount, and ~85 WG views do the same. There is NO // Python-side and NO res_map lever for this (see bridge/bar_window.py). // // BUT THE ENGINE ALSO TRIES TO MEASURE THE DOCUMENT, AND ITS FALLBACK RUNS LAST AND WINS. Pushing // the size is not sufficient on its own: our resize landed at 04.8s, the size-calculation deadline // expired at 06.2s and its action ("Set the default view size") overwrote our pushed size with the // 256x256 default. The static, in-flow #moe-bar-box (MoEProgressView.html, sized in // MoEProgress.css to exactly the derived surface -- keep it in lockstep with the BOX_*/PAD_REM // below) was meant to make the document measurable and stop the timeout. RE-MEASURED LIVE: IT DOES // NOT. The box is there, in-flow and correctly sized, and the timeout fires anyway. So the shared // module's SURFACE_REASSERT_MS is not a belt-and-braces guard -- it is the ONLY fix, and the window // before it is the one T.settled() hides the bar through. // // The composition's MEASURED bounding box, document origin at (0,0) and 1rem == 1 logical px, is // 360 x 72 -- .mp-backdrop IS the extremes (left -80rem / top -34rem / 360 wide / 72 tall, // MoEProgress.css) and every caption, tick and glow sits inside it. So the surface is that box // plus PAD_REM of slack on all four sides (the text-/box-shadow bleed reaches the box edge // exactly), and the whole composition is rigidly translated by that much so NOTHING sits at a // negative coordinate -- an origin overflow is clipped no matter how big the surface is. // // THE SIDE CLEARANCE IS 80rem AND IT IS NOT WIDTH-DERIVED: the box is the 200rem track (see // #moe-bar-root's width note in the CSS) plus BOX_LEFT_REM on each side, so a track resize moves // BOX_W_REM by exactly the same amount and every per-side margin is preserved. // WHICH CAPTION IS THE EXTREME HAS NOW MOVED THREE TIMES, so all three extremes are RE-DERIVED here // from the shipped CSS and MoEBattle.ttf's own advances (digit 0.4932em, comma 0.2471, paren 0.3008, // plus 0.4932; 1rem == 1 logical px; every figure re-checked against the ttf's hmtx). The two moves // in THIS revision: the .mp-capL axis-floor caption is GONE outright, and the REMAINING-BATTLES // COUNT moved OFF the delta and ONTO .mp-capR with a glyph of its own. // RIGHT -- .mp-capR, and it is now the extreme by a wide margin. ONE flex row, FOUR items -- // plus a FIFTH term now, the ETA GAP (.mp-ico.battles's own margin-left, DOM order after the // requirement numeral and before the battles glyph -- it widens the row, not a box of its own): // 3.00 (.mp-cap.side.mp-capR's margin-left off the track end) // + 17.00 (.mp-ico.mk / .mp-ico.moe) + 1.00 (.mp-cap .mp-ico's shared gap) // + 31.08 ("3,050", a 4-digit requirement, at the .side 14rem: 4*6.9048 + 3.4594) // + 4.00 (.mp-ico.battles's margin-left -- the ETA GAP, added to breathe the requirement // numeral apart from the remaining-battles count that follows it) // + 13.00 (.mp-ico.battles -- it takes .mp-ico's BASE box, the only glyph in the file that does) // + 1.00 (that same shared gap) + 13.81 ("99", the PROGRESS_ETA_CAP ceiling, 2*6.9048 at 14rem) // == 83.89rem of BOXES, + 1.00 for the numerals' dark-drop text-shadow radius == 84.89rem. // SO IT OVERHANGS THE 80rem BACKDROP CLEARANCE BY 4.89rem (UP FROM 0.89rem BEFORE THE GAP) -- // and unlike before, that overhang is NO LONGER pure shadow halo. The final "99" numeral's own // box now spans 70.08 -> 83.89rem, i.e. 3.89rem of ITS BOX (not just its shadow) sits PAST the // 80rem backdrop edge, on bare HUD. At the .side 14rem size one digit is 6.9048rem wide, so // 3.89rem is a bit over half a digit -- WORST CASE IS ROUGHLY THE OUTER HALF OF THE LAST DIGIT // LOSING ITS DARK BACKING, and it only reaches that worst case when a 4-digit requirement // ("3,050"-shaped) and a 2-digit ETA ("99") land together. THIS IS A KNOWN, ACCEPTED TRADEOFF // OF THE 4rem GAP, not a bug to chase: do NOT fix it by moving the backdrop, changing // PROGRESS_ANCHOR_X_OFFSET, shrinking this gap, or re-deriving it away -- that is the // maintainer's call, not this file's. // DISTINGUISH OVERHANG FROM CLIPPING before reaching for the geometry -- the surface is a // further PAD_REM out at 90rem, so CLIPPING STARTS AT 90 and there is still 5.11rem of // clearance before that (90 - 84.89): nothing here is clipped, only unbacked. // REBALANCING THE BACKDROP IS NOT FREE AND WAS DELIBERATELY NOT DONE. Taking clearance off the // now-empty left side (80/80 -> e.g. 52/108, keeping BOX_W_REM and so the surface AND the mouse // hit rect) breaks the symmetry that lets positioning.anchor_centred's `max_x // 2` centre the // bar with NO X term in Python: constants.PROGRESS_ANCHOR_X_OFFSET is 0, and // tests/test_progress_surface_mirror.py::test_the_large_backdrop_stays_symmetric_about_the_track // pins exactly that. Any asymmetry slides the bar half the error sideways at every resolution // until that constant -- plus a Large twin for it, since it is logical px and the block's // x-lengths carry SIZE_XF -- follows. That is a positioning change, not a CSS one. // CENTRE (.mp-capC) RIGHT -- back down, now that the "/NN" suffix is off the delta: // 17.76 (half of "3,050" at the .dn 16rem == 35.52) + 4.20 (.mp-d's 0.35em gap of its OWN 12rem // font) + 30.89 ("(+297)" at 12rem) + 6.00 (.mp-d-num's sign-glow text-shadow radius) // == 58.85rem, i.e. 21.15rem SPARE. That reproduces the pre-count figure exactly, as it must. // A 4-digit delta ("(+2,970)" == 39.78) still only reaches 67.74rem, and needs cd ~ 150,000. // LEFT -- .mp-capC at 0% is the ONLY candidate left, and its ICON path beats its numeral's glow: // 17.76 (the same half-numeral) + 17.00 (.mp-capC .mp-ico's negative-margin overhang) // + 0.48 (that icon's ::before glow, 3% of its 16rem box) == 35.24rem, against the numeral's // own 17.76 + 6.00 == 23.76. So 35.24rem and 44.76rem SPARE: ~45rem of dead space out there. // (An earlier revision of this note SUMMED those two paths into 41.24rem. They are // ALTERNATIVES, not terms -- the 6rem is the numeral's own text-shadow and stops at -23.76.) // The .mp-full case is UNCHANGED and now provably so: battles_to_axis_hi returns 0 exactly when // proj_avg >= axis_hi, which is the same test .mp-full toggles on, so the count is suppressed on // every gold frame and needs no `#moe-bar-root.mp-full .mp-eta` rule of its own. // Large is NOT size-mode-agnostic (it needs its own sum, the x-length terms scale by SIZE_XF while // the boxes/numerals scale via the root font alone) but is still strictly slacker: the clearance // grows 80 -> 106.667rem, and the ETA GAP's own Large twin (.mp-ico.battles's margin-left, an // x-length like the shared gaps: 4 * 4/3 == 5.333) is the only new term -- // capR' == 4 + 17 + 1.333 + 31.08 + 5.333 + 13 + 1.333 + 13.81 + 1 == 87.89rem, 18.78rem spare // (down from 24.1rem before the gap, since the gap only widens the reach and the backdrop grows // for a different reason). Still comfortably unclipped, so the Default size keeps binding on // every side. // Keep the 80rem, and re-derive ALL THREE extremes again before ever moving it -- "which one is the // extreme" has now moved three times, and each move invalidated the previous revision's spare. // These five ARE this bar's surface contract and stay HERE, per bar. MoEBarTransient derives the // rest from them (its box*/pad arguments), exactly as this file used to: // VIEW_W_REM = BOX_W_REM + 2 * PAD_REM == 380 SHIFT_X_REM = PAD_REM - BOX_LEFT_REM == 90 // VIEW_H_REM = BOX_H_REM + 2 * PAD_REM == 92 SHIFT_Y_REM = PAD_REM - BOX_TOP_REM == 44 // SHIFT_Y_REM is MIRRORED (negated) in Python as // domain/constants.PROGRESS_ANCHOR_Y_SHIFT, so changing BOX_TOP_REM or PAD_REM moves the bar on // screen until that constant follows -- and #moe-bar-box in MoEProgress.css is sized to the derived // surface, a THIRD copy: keep all three in lockstep. The hit padding and the re-assert timing live // in the shared module (its HIT_MAGIC / SURFACE_REASSERT_MS -- both LOAD-BEARING, read its header). const BOX_LEFT_REM = -80; // .mp-backdrop's left == leftmost edge const BOX_TOP_REM = -34; // .mp-backdrop's top == topmost edge const BOX_W_REM = 360; // .mp-backdrop's width const BOX_H_REM = 72; // .mp-backdrop's height const PAD_REM = 10; // --- THE VERTICAL ORIENTATION (mod_settings.progress_bar_orientation, pushed as the VM's // `vertical`) ------------------------------------------------------------------------------------ // A SECOND COMPOSITION IN THE SAME DOCUMENT, not a restyle of this one: its own stylesheet // (MoEProgressVertical.css, ed alongside MoEProgress.css from MoEProgressView.html), its own // namespace-disjoint class prefix (.mpv-*), its own DOM order (numeral BEFORE icon) and its own // surface. NO second res_map entry and NO second BarHost: orientation is a MOUNT-TIME branch, and a // new itemID would cost every user a one-time client restart. // // V_BOX_* IS .mpv-backdrop, exactly as BOX_* above is .mp-backdrop -- and it is the axis-swap of it // with the tuner's own tuned lengths, NOT a transpose of these four (46 wide against 360 tall, vs // 360 x 72; the side clearance is 34 a side, not 80, because a vertical bar's captions grow along // its cross axis and the tuned overhang differs, and the RIGHT edge is trimmed -- see V_BOX_W_REM's // own note below). PAD_REM serves the Y axis; the X axis is a SPLIT pad, V_PAD_X_REM on the left // (caption ink) and V_PAD_XR_REM on the right (the track's own tick overhang, deliberately smaller // -- see both constants' own notes below), so: // V_VIEW_W_REM = V_BOX_W_REM V_SHIFT_X_REM = V_PAD_X_REM - V_BOX_LEFT_REM == 104 // + V_PAD_X_REM + V_PAD_XR_REM == 112 // V_VIEW_H_REM = V_BOX_H_REM + 2 * PAD_REM // - V_CLIP_B_REM == 320 V_SHIFT_Y_REM = PAD_REM - V_BOX_TOP_REM == 90 // V_SHIFT_Y_REM is MIRRORED (negated) in Python as domain/constants.VERTICAL_ANCHOR_Y_SHIFT (-90, // and -113 for Large == -round(90 * SIZE_F)), which is SHARED with the Damage Efficiency bar -- // unlike the horizontal pair's 44-vs-50 split, both vertical compositions have the identical // backdrop top and height. #moe-bar-box in MoEProgressVertical.css is sized to the derived surface, // a THIRD copy: keep all three in lockstep. // // THE SURFACE IS THE ONLY SIDE THAT IS NOT box + PAD_REM, AND THAT IS THE WHOLE POINT (V_CLIP_B_REM). // The engine clamps EVERY window into [0, space - surface] in compiled C++ (movePyWindow -- memory // `engine-clamps-every-wulf-window-to-screen-and-the-mod-depends-on-it`; bar_window._extent's // far-sentinel calibration DEPENDS on that clamp existing), so the surface's bottom edge can never go // below the screen's, and a bar anchored to the minimap therefore lands however far its TRACK sits // above its own surface bottom -- never closer. At a full box + PAD_REM surface that was // 380 - 290 == 90 logical px, against the vertical tuner's tuned `mmGapBottom` of 30 // (tools/dev/gen_bar_tuner_vertical.ps1:451), i.e. the tuned look was unreachable by ~60px and // domain/constants.PROGRESS_MM_GAP_BOTTOM could not be honoured at all. // THE SURFACE DOES NOT HAVE TO CONTAIN THE BACKDROP -- only the caption INK. The tuner's stage clips // the backdrop's lower bleed at exactly this gap and that IS the approved appearance, so the surface // is shortened to the tuned gap and the bleed clips at its bottom edge: // V_CLIP_B_REM == (V_BOX_H_REM + 2*PAD_REM) - (V_SHIFT_Y_REM + barLen + mmGapBottom) // == 380 - (90 + 200 + 30) == 60 // and the surface's below-the-track slack becomes 320 - 290 == 30 == the tuned gap exactly (290 is // V_SHIFT_Y_REM + barLen == domain/constants.MM_TRACK_Y, which this does NOT move -- see below). // WHAT IT COSTS, DERIVED FROM THE SHIPPED CSS, is 3rem of clearance on the bottom caption's ink and // nothing else. .mpv-capC (MoEProgressVertical.css) is `top: 100%` + `margin-top: 6rem` off the // track's bottom end, its flex row is `line-height: 20.5rem` tall (the tallest of its three children: // the 20.5 numeral line box beats the 16rem .dmgc icon and the 15.5rem delta), so its box ends // 6 + 20.5 == 26.5rem below the track; the numeral's own translateY(-0.5rem) plus its 1rem dark-drop // text-shadow radius reaches 27.0, the delta's translateY(1.5rem) + the same 1rem reaches 25.5, and // the icon's translate(0, 1rem) + its ::before 106% glow (3% of 16rem) reaches 26.2. So the deepest // ink is 27.0 against 30 of slack. The ONLY thing past the edge is the sign-glow's soft tail (the // 6rem blur on .mpv-d-num / .mpv-v in the up/down states, reaching ~32.5) -- which the tuner clips // at its stage bottom too, at the same 30, which is what the maintainer approved. // IT MOVES NOTHING ELSE, BY CONSTRUCTION: the clip is applied to the SURFACE only and never to // shiftY, so the composition sits exactly where it did inside the surface and BOTH mirrored Python // constants -- VERTICAL_ANCHOR_Y_SHIFT (-90) and MM_TRACK_Y (290) -- are unchanged. Nothing reflows // either: every length in the two vertical stylesheets is a rem or a % of a rem-sized ancestor (the // only viewport-relative rule in either document is `body { margin: 0 }`), so a shorter surface can // only clip, never re-lay-out. // UNDER LARGE the clip is inside applySize's `* f`, so the slack is 400 - 363 == 37 logical px while // PROGRESS_MM_GAP_BOTTOM stays a fixed 30: the gap is then UNREACHABLE and the engine flushes the // surface to the screen bottom, which lands the track at 30 * SIZE_F == 37.5 -> 37. That is the // tuned gap SCALED, i.e. the same look 1.25x, which is exactly right -- do NOT "fix" it with a // MM_GAP_BOTTOM_LARGE twin, and do NOT take the clip out of the `* f` to force reachability: a // fixed-px clip would keep biting the same 60rem out of a composition whose ink grew 1.25x, and the // bottom caption would start clipping for real. // THE 256x256 SIZE-TIMEOUT FALLBACK STILL RUNS LAST AND STILL WINS on this path -- the vertical // surface is pushed and RE-ASSERTED after the deadline by exactly the same shared machinery // (MoEBarTransient's SURFACE_REASSERT_MS), and each push round-trips back to Python as // onSizeChanged -> bar_window._place, which is what makes the placement agree with the surface. // // ...AND THE X AXIS IS NOT box + PAD_REM EITHER (V_PAD_X_REM). The three captions are // RIGHT-ANCHORED and grow LEFTWARD from a fixed edge (`right: 100%; left: auto`, // MoEProgressVertical.css's .mpv-cap), so their ink runs well past .mpv-backdrop's left edge -- // and unlike the horizontal bar, THE BACKDROP IS NOT MEANT TO COVER THEM (maintainer's call: the // look is settled, the backdrop stays exactly where the tuner put it). At the shipped // PAD_REM the surface's left edge sat at -44rem and CUT TWO OF THE THREE ROWS. So the X slack is // decoupled from the backdrop rect: V_PAD_X_REM widens the SURFACE alone, .mpv-backdrop's // `left: -34rem; width: 72rem` is untouched, and nothing on screen moves but the clip. // // IT IS APPLIED TO BOTH SIDES EVEN THOUGH ONLY THE LEFT NEEDS IT, and that is the load-bearing // half. Only the LEFT reach is a real requirement -- the right side has ~48rem of dead space at // PAD_REM already -- but a LEFT-ONLY pad makes the surface asymmetric about the track, and the // centred (Damage Log) alignment is `max_x // 2` with NO x term in Python // (positioning.anchor_centred_reduced), i.e. it centres the SURFACE and only centres the BAR while // the two are concentric. Left-only would have slid that alignment 26 logical px right at Default // and 33 at Large -- a visible move, for a fix whose whole brief was "nothing on screen may look // different except that the caption text is no longer cut off". Symmetric costs 53rem of surface // on a side nobody looks at and is FREE: the surface rect is never drawn, the mouse hit rect is // collapsed PER AXIS (MoEBarTransient's pushHitArea pads X by half the surface WIDTH and Y by half // the surface HEIGHT), so widening padX only grows the X pad by exactly the same amount it grows // viewW by -- the X axis still collapses to zero width either way, and the Y axis (which this // widening never touches) is untouched. The input rect does not move. Do NOT "reclaim" the right // side. // THE WORST-CASE REACH, RE-DERIVED for the row split with Job 2's icon BOXES reverted (maintainer: // "icon sizes must stay the same, adjust paddings individually" -- dmgp/mk/moe are back at their // pre-039a58c 14/17/17rem, only per-icon margin-left differs from the shared 1rem now; see // MoEProgressVertical.css's own notes), from the shipped CSS and MoEBattle.ttf's own advances // (digit 0.4932em, comma 0.2471, paren 0.3008, sign 0.4932 -- the same figures the horizontal // extremes above use). Each row's ink starts at `-padding-right + translateX` off the track's left // edge and grows leftward; the design is digit-count INVARIANT at the anchor (see the CSS's own // note), so a static worst case is sound: // .mpv-capC (bottom) IS STILL THE EXTREME, and MORE so now: the maintainer's own "move the // bottom block left 7px" nudge shrank its translateX from 16 to 9, moving the anchor 7rem // CLOSER to the surface's left edge (mind the clip -- every one of these captions is // right-anchored, so "left" is the OVERFLOW direction). .mpv-ico.dmgc still keeps its base // 1rem margin ("the reference"), and this is still budgeted for the 4-DIGIT delta case, not // the 3-digit one: // (-6 + 9) - [ 39.78 ("(+2,970)" at the .mpv-d 12rem) + 4.20 (its 0.35em gap of that same // 12rem) + 35.52 ("3,050" at 16rem) + 1.00 (the shared icon gap) + 16.00 (.mpv-ico.dmgc) ] // - 6.00 (.mpv-d-num's up/down sign GLOW, the widest text-shadow in the file) == -99.49rem // (was -92.49 before the nudge -- exactly +7, the same device-px count the translateX lost). // A 3-digit delta ("(+297)" == 30.89) reaches only -90.61. // .mpv-capR (now JUST the requirement group -- the eta group moved to its own row below): the // mark icon's own margin correction (-1.25rem) makes IT the shorter reach; the icon that // actually binds is .moe (the achievement glyph that REPLACES .mk once 3 marks are earned), // whose margin correction (+0.885rem) is now the LARGER combined offset -- the two are no // longer interchangeable the way they were pre-039a58c (same box, same shared margin, same // 18-total either way): // mk: (-6 + 14) - [ 31.08 ("3,050" at 14rem) + (-1.25) + 17 (.mpv-ico.mk) ] - 1.00 == -39.83 // moe: (-6 + 14) - [ 31.08 + 0.885 + 17 (.mpv-ico.moe) ] - 1.00 == -41.97rem (the WORSE case) // .mpv-capEta (stacked above capR): (-6 + 14) - [ 13.81 ("99" at 14rem, the PROGRESS_ETA_CAP // ceiling) + 1.038 (.mpv-ico.battles's own margin correction, not the shared 1rem) + 13 // (.mpv-ico's base box, the battles glyph) ] - 1.00 == -20.85rem -- still the SLACKEST row in // the file by a wide margin. // .mpv-capP (moving, dmgp back at 14rem, margin corrected to 1.253rem): (-6 + 0) - // [ 31.08 + 1.253 + 14 (.mpv-ico.dmgp) ] - 1.00 == -53.33rem. // capC is STILL the extreme (99.49 > 53.33 > 41.97 > 20.85), and the maintainer's own 7px-left // nudge ate the margin (104 - 99.49 == 4.51, was 97 - 92.49 == 4.51 before -- the SAME margin, // because V_PAD_X_REM grew by the identical +7): the surface's left edge had to move WITH it: // V_PAD_X_REM == 104 + V_BOX_LEFT_REM == 104 - 34 == 70 (was 63; +7, matching the capC nudge) // GROWING THIS MOVES THE TRACK INSIDE THE SURFACE, so domain/constants.PROGRESS_MM_TRACK_X( // _LARGE) had to grow with it by the exact same amount (in logical px, i.e. *SIZE_F under Large) // or the visible bar would slide RIGHT into the minimap -- see that constant's own comment. // tests/test_progress_surface_mirror.py::test_the_vertical_captions_fit_inside_the_surface is the // GATE on all of the above -- it re-derives every row from the stylesheet and the advances rather // than trusting this note, and goes red the moment V_PAD_X_REM is trimmed. Splitting capR into // capR + capEta means the test's `rows` dict owes a matching split, or it silently keeps checking // the STALE (pre-split) shape and goes green over a layout it no longer describes. // // THE Y-AXIS FIT FOR THE NEW STACKED ROW (Job 1's own re-derivation obligation -- the maintainer's // estimate of "~56rem of headroom" was explicitly flagged as unverified and is checked here // instead of trusted). Measuring DOWN from the track's own top edge (y=0, the same origin // V_BOX_TOP_REM uses): .mpv-capR's own box reaches capR's padding-bottom(6) + line-height(18) == // 24rem above the track top. .mpv-capEta stacks on top of THAT via its own // `padding-bottom: 30rem` (== capR's 24rem box + a 6rem visual gap, the same magnitude this file // already uses to clear the track), so capEta's box reaches 30 + 18(its own line-height) == 48rem // above the track top. Add the row's own translateY nudge (-0.5rem, capEta's numeral) and the // widest text-shadow in the file (the up/down sign glow, 6rem) for the worst-case ink, exactly as // the X-fit test's own `halo` term does: 48 + 0.5 + 6 == 54.5rem. // THE SURFACE'S OWN TOP CLEARANCE is -V_BOX_TOP_REM + PAD_REM == 80 + 10 == 90rem (the backdrop's // own top bleed plus the uniform Y pad -- V_CLIP_B_REM only shortens the BOTTOM, never the top). // 90 - 54.5 == 35.5rem of spare: the new row fits comfortably inside the EXISTING backdrop/surface // with room to spare, so NEITHER V_BOX_TOP_REM/V_BOX_H_REM NOR VERTICAL_ANCHOR_Y_SHIFT (shared with // the vertical Damage Efficiency bar) had to move for this change -- exactly what Job 1 asked to // confirm before touching either. tests/test_progress_surface_mirror.py carries the matching gate, // re-deriving both sides from source rather than hardcoding 54.5 and 90 as two literals that would // have to agree by hand. // LARGE IS STRICTLY SLACKER and needs no twin: the allowance is `V_PAD_X_REM - V_BOX_LEFT_REM*4/3` // == 115.33rem (was 108.33 before V_PAD_X_REM grew to 70 -- the backdrop's left bleed is an // x-length and takes SIZE_XF; V_PAD_X_REM, like PAD_REM, does NOT -- the ink it covers is // rem-sized and rides the root font's SIZE_F alone), while the ink only grows on its three // x-GAPS. The Default size keeps binding. // THE MINIMAP ANCHOR MUST FOLLOW THIS CONSTANT. domain/constants.PROGRESS_MM_TRACK_X's PURE // derivation is `V_SHIFT_X_REM + trackW`, i.e. where the track sits inside the surface -- widen // the left slack without growing it and the whole bar slides left by the difference. The shipped // constant also carries a further -2 measured hand-placement correction on top; see its // derivation there. // // FOUR DURABLE FACTS, established by reading the source rather than assuming (a maintainer once // saw the minimap's first column "covered by a dark panel" and the fix took four rounds to land): // 1. THE BACKDROP IS NOT MEANT TO COVER THE RIGHT-ANCHORED CAPTIONS -- only V_PAD_X_REM (above) // was ever sized for their ink. .mpv-backdrop is a SEPARATE rectangle, drawn for the // shadow/glow bleed around the TRACK, and every one of capR/capEta/capP/capC already reaches // far past it by design (see the worst-case reach note above -- 20.85 to 99.49rem, against a // 34rem backdrop bleed). Do not "fix" a clip by widening the backdrop; that is V_PAD_X_REM's // job, on the SURFACE, which is never drawn. // 2. THE VERTICAL BAR'S BACKDROP HAS NO SYMMETRY CONTRACT. `test_the_large_backdrop_stays_ // symmetric_about_the_track` (tests/test_progress_surface_mirror.py) asserts symmetry ONLY // for the HORIZONTAL bar's `.mp-backdrop`, because `anchor_centred_reduced`'s `max_x // 2` has // no X term and only centres the BAR by centring the SURFACE -- true for the Damage Log // (horizontal) anchor. Fixed+Vertical resolves through `anchor_minimap` instead // (bar_window._resolve), whose `x = space_x - mm_size - gap - overhang - edge_x` reads // `edge_x` (PROGRESS_MM_TRACK_X) and NOTHING about the backdrop's own width or left. Trimming // `.mpv-backdrop` asymmetrically (this file's own V_BOX_W_REM, leaving V_BOX_LEFT_REM alone) // moves nothing the placement math depends on. // 3. THE BACKDROP TRIM (V_BOX_W_REM 72 -> 46) WAS REAL WORK -- KEEP IT. A maintainer report of // the backdrop "sitting well clear of the minimap" turned out to describe a DIFFERENT panel; // measured live (window pos (1294,760), minimap index 4 == 510px wide at 1920x1080 logical // space), THIS backdrop's own right edge (V_PAD_X_REM + V_BOX_W_REM == 70+46==116) landed // EXACTLY on the minimap's own left edge (PROGRESS_MM_TRACK_X + MM_GAP + MM_TICK_OVERHANG == // 105+8+3==116) -- zero overlap, by design, at the tuned 46, AT THE TIME (the shared MM_GAP // was 8). Reverting to 72 (right edge 142) would reopen a real 26rem overlap. Do not touch // V_BOX_W_REM again without a live measurement to justify it. // SINCE THEN, PLACEMENT MOVED CLOSER TO THE MINIMAP (domain/constants.PROGRESS_MM_GAP(_LARGE), // 5/6, replacing the shared MM_GAP(8) for this bar's own anchor) -- the backdrop's own DRAWN // right edge no longer sits flush with the minimap's own (now closer) left edge, it is a few // rem PAST it. That is not a regression: fact 4 below already established the DRAWN backdrop // is not what clears the minimap, the invisible SURFACE is (V_PAD_XR_REM/_LARGE), and the // surface still clears it with a real, checked margin at the new gap -- see V_PAD_XR_REM's own // derivation below for the current numbers. // 4. THE ACTUAL CULPRIT WAS THE INVISIBLE SURFACE'S OWN RIGHT PAD, NEVER UPDATED TO MATCH. The // backdrop trim shrank the DRAWN rect; nothing shrank the SURFACE (the mouse-hit-blocking rect // per this file's header) on that side, so it stayed the OLD symmetric V_PAD_X_REM(70) past // the ALREADY-TRIMMED backdrop -- measured live: window size (186,320) == 46+70+70, its right // edge 70 logical px INSIDE the minimap (space_x - mm_size == 1410; window right == 1294+186== // 1480). See MoEBarTransient.js's `padXR`/`padXRLarge` arg notes for the fix (a SEPARATE, // smaller right pad, V_PAD_XR_REM/_LARGE below) and V_PAD_XR_REM's own derivation. Because the // fix only shrinks the RIGHT pad and V_PAD_X_REM (the LEFT side, where the caption ink and the // track itself both live) is untouched, `shiftX` and therefore PROGRESS_MM_TRACK_X(_LARGE) -- // both pure functions of the LEFT side alone -- need no correction, and the bar does not move // on screen (confirmed live: the measured window position matches anchor_minimap bit-exactly // already, before this pad fix, and stays that way after it). // 5. PROGRESS_MM_TRACK_X CARRIES A -2 HAND CORRECTION (see its own derivation in domain/ // constants.py) THAT MUST NOT LEAK INTO THIS FILE'S OWN SURFACE-WIDTH MATH. That correction // exists ONLY to match a measured discrepancy in where the WINDOW lands in SPACE (two // independent Ctrl-drags); it shifts the whole window (surface + everything drawn inside it) // by a constant 2px, and does NOT change where the TICK renders inside its OWN surface -- that // is a pure JS/CSS fact (shiftX + trackW), unrelated to any Python-side placement fudge. Using // the CORRECTED constant (105) as if it were this bar's own local tick position (as an earlier // pass of this fix did) UNDERSTATES the tick's real reach by exactly that 2px and clips it -- // the true local tick-right is shiftX(104) + trackW(3) + MM_TICK_OVERHANG(3) == 110, not 108. // See V_PAD_XR_REM's own derivation below, which uses the PURE (uncorrected) value throughout. const V_BOX_LEFT_REM = -34; // .mpv-backdrop's left const V_BOX_TOP_REM = -80; // .mpv-backdrop's top const V_BOX_W_REM = 46; // .mpv-backdrop's width (right edge only, trimmed -- see fact 3) const V_BOX_H_REM = 360; // .mpv-backdrop's height const V_CLIP_B_REM = 60; // backdrop bleed the SURFACE clips off the bottom const V_PAD_X_REM = 70; // the LEFT X slack, decoupled from the backdrop // THE SURFACE'S RIGHT (minimap-facing) PAD -- deliberately NOT V_PAD_X_REM's mirror, and a SEPARATE // knob from the backdrop's own V_BOX_W_REM trim above: the backdrop trim shrinks what is DRAWN, this // shrinks what is CLICK-BLOCKING (the surface, never drawn). Shrunk close to the minimum the TRACK's // own ink needs on that side: the tick's cross-axis overhang past its own edge // (domain/constants.MM_TICK_OVERHANG(_LARGE), the SAME term anchor_minimap's `x` formula already // adds as clearance), plus a small, deliberate MARGIN (+2 logical/document px, flat, NOT xf-scaled // -- see fact 5: this is a JS-local geometry decision, so it uses the PURE tick position, never // PROGRESS_MM_TRACK_X's hand-corrected placement value) so the surface's own edge is never flush // with the tick's -- a flush boundary is exactly the "rounding could shave a px and eat the ink" // risk fact 5 exists to head off. Nothing for caption ink is needed on this side at all -- every // caption here is anchored to the LEFT (see V_PAD_X_REM's own note), so the right side backs nothing // but the (already-trimmed) backdrop's own remaining decorative bleed, which this pad now clips a // little further, at the surface edge, rather than containing it (the same clip-not-contain pattern // V_CLIP_B_REM already uses on the bottom). // Solved directly against MoEBarTransient.applySize's own formula // (viewW == round((boxW*xf + padX + padXR) * f)), using the PURE (uncorrected) tick position: // tick-right (Default, xf=f=1) == shiftX(104) + trackW(3) + MM_TICK_OVERHANG(3) == 110 // Default: viewW == 110 + 2 (margin) == 112 -> padXR == 112 - V_BOX_W_REM(46) - V_PAD_X_REM(70) == -4 // tick-right (Large, PRE-SIZE_F) == shiftX_pre_f(346/3) + trackW_large(4) + overhang_large_pre_f(4) // == 370/3 ~= 123.333 (renders at 123.333*SIZE_F ~= 154.167 device px) // Large: viewW_pre_f == 370/3 + 2 == 376/3 ~= 125.333 -> round(125.333 * SIZE_F) == 157 // padXRLarge == 376/3 - boxW*xf(184/3) - V_PAD_X_REM(70) == -18/3 == -6 (exact) // Both NEGATIVE: the surface's right edge sits a LITTLE further inside the backdrop's own (already // trimmed) drawn rect than its own edge -- the box+left-pad sum (46+70==116 Default, 61.333+70== // 131.333 pre-SIZE_F Large) was flush with the minimap at the ORIGINAL shared MM_GAP(8) (fact 3), // so ANY margin (to the tick, or to the minimap) needed the surface a shade smaller still. This // derivation (padXR/padXRLarge themselves) is UNCHANGED by the later gap move -- it is pure // JS/CSS geometry, independent of where Python decides to place the window -- but the MARGIN it // buys against the minimap moved WITH that gap. Resulting margins, both real and checked // (tests/test_progress_surface_mirror.py::test_the_surface_clears_the_minimap_at_every_size_index // / test_the_surface_does_not_clip_the_tick), at domain/constants.PROGRESS_MM_GAP(_LARGE) == 5/6: // Default clears the minimap by 1px (was 4px at the original shared gap of 8) and the tick by // 2px; Large by 1px (was 3px) and ~2.8px respectively -- none of it flush, none of it negative. // padXRLarge is NOT padXR*SIZE_XF, for the same reason MM_TRACK_X_LARGE and MM_TICK_OVERHANG_LARGE // are their own literals: the Large geometry (trackW_large, shiftX_large) is not a pure *SIZE_XF // scale of the Default one once V_BOX_LEFT_REM's own fractional Large scaling is folded in, so // neither is what clears it -- see the derivation above, computed directly, not scaled. // GROWN (2026-08-10, in-client review) so the surface still reaches the minimap's 1px floor after // the placement gap was RESTORED to 8 (domain/constants.PROGRESS_MM_GAP(_LARGE)). Solved directly // against anchor_minimap's margin (== gap + overhang + edge_x - view_w). ADVANCED 4 logical px into // the minimap (2026-08-12, in-client): the previous margin==1 cleared the minimap's DROP-SHADOW by // 1px but left the backdrop 4px off the minimap's REAL visible edge -- the maintainer confirmed that // 4px is the minimap's non-interactive frame margin and is safe to consume (the Ctrl-click area is // further in). So the surface's right edge (and the flush strips) now sit at margin == -3 (3px into // that frame margin), flush against the minimap itself: // Default: view_w == 8 + 3 + 105 - (-3) == 119 -> padXR == 119 - V_BOX_W(46) - V_PAD_X(70) == 3 // Large: view_w == 8 + 5 + 147 - (-3) == 163 -> padXRLarge == 163/SIZE_F - boxW*xf(61.333) - 70 // == 130.4 - 131.333 == -0.933 // The visible TRACK is unaffected -- gap/overhang/edge_x are unchanged; only view_w (this right pad) // grew, which moves the surface's minimap-facing edge alone, not the track. const V_PAD_XR_REM = 3; // the RIGHT (minimap-facing) X slack, Default const V_PAD_XR_REM_LARGE = -0.933; // ...and Large -- its OWN literal, see above // THE LIVE ORIENTATION PROFILE -- the three things the render path cares about, all rewritten // together by goVertical() below and never touched again. // PFX the class prefix every selector and every toggled class in this file is written in. The // source spells everything as "mp-..." and ns() rewrites it, so the literals stay greppable. // AX the property a marker's position is written to: `left` along a horizontal axis, `bottom` // along a vertical one (0% at the BOTTOM -- see the stylesheet's axis note). // GROW the property the fill grows along: `width` vs `height`. // CAP_C_AX the axis the BOTTOM-CENTRE caption tracks, or null if it does not move. On the // horizontal bar capC rides the proj tick; on the vertical one it is a STATIC cap below the // track's bottom end and capP (the pre caption) is the only caption that moves. That is the // tuner's tuned layout, not an omission -- see MoEProgressVertical.css's .mpv-capC. let PFX = "mp"; let AX = "left"; let GROW = "width"; let CAP_C_AX = "left"; // Rewrite a class name or a selector from the source's .mp-* spelling into the LIVE prefix. A no-op // while horizontal, so the shipped path costs one string compare per call and nothing else. The // two prefixes are DISJOINT by design (see the vertical stylesheet's header), which is the whole // reason a blanket token rewrite is safe here. function ns(s) { return PFX === "mp" ? s : s.replace(/\bmp-/g, PFX + "-"); } // THE HORIZONTAL COMPOSITION'S MARKUP (the vertical one is V_MARKUP below; ensureRoot builds this // one and goVertical replaces it, which is why they are two constants and not one branch inside the // builder). Markup shape is the tuner's stage: backdrop, the track with its // four ticks, then THREE captions -- the tuner's fourth, .mp-capL, carried the axis FLOOR numeral // and is gone (axisLo is the battle's starting projection, not a requirement, and the label said // nothing the moving caption does not). Each caption is ONE flex row -- icon, value, and on capC the // delta, whose PARENS are static text on the wrapper so they never glow (see the .mp-d / .mp-d-num // split in the CSS). NO word labels anywhere: MoEBattle.ttf is a 19-glyph numeric subset // (digits % ( ) + - , . / space) and a letter renders BLANK. const MARKUP = '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '()
' + // THE MARK PAIR MUST COME FIRST IN THIS ROW: capV() does a querySelector for the FIRST // .mp-v, so reordering these four nodes repoints the requirement writer at the count -- with // no error to catch it. The mark GLYPH no longer cares (setIco writes to the mount-cached // capMkIco, which the vertical composition's opposite order forced), but the numeral still // does. The requirement's glyph is the only one setIco ever rewrites; the battles glyph's // class is STATIC (paintStatic only toggles `none` on it), which is why it can safely share // the .mp-ico family here. '
' + '' + '
' + '
'; // ...and THE VERTICAL COMPOSITION'S markup, the tuner's own stage verbatim // (tools/dev/gen_bar_tuner_vertical.ps1). FOUR structural differences from the horizontal template // above, all of them the tuner's tuned layout and none of them free to "tidy": // * NUMERAL BEFORE ICON in every caption (the icon trails, away from the track). That is what // makes the shared right:100% anchor digit-count invariant -- the icon is the LAST in-flow // child, flush against a FIXED edge, so only the numeral grows, and leftward. Reversing it // re-introduces the exact defect that shipped once on the horizontal bar. // * the DELTA is ordered FIRST on capC (delta, numeral, icon), an in-flow flex child with a // margin gap -- never an out-of-flow box hanging off a content-dependent edge. // * capP lives INSIDE .mpv-track and capR / capC are its SIBLINGS, exactly as the tuner has them // (root and track are the same 3x200rem box, so every percentage resolves identically either // way; this only keeps the diff against the tuner readable). // * the two axis-end ticks are mpv-bottom / mpv-top, not mp-left / mp-right. // capR is now TWO STACKED ROWS, not one (maintainer's call: "move the ETA on top of the next mark // requirement"), ported here only -- the tuner's own stage keeps both numeral+icon groups on ONE // row, untouched (see MoEProgressVertical.css's HAND-EDIT 6/6). `.mpv-capEta` (the eta numeral + // battles glyph) sits directly ABOVE `.mpv-capR` (now JUST the requirement numeral + mark glyph), // both anchored by the SAME right:100% mechanism (copied verbatim: same padding-right/transform/ // font-size/line-height) so both stay digit-count invariant independently. Because the mark icon // is capR's ONLY icon now (no positional ambiguity to guard against any more, but the cache stays // for the reason below), setIco() below still writes to a CACHED element captured at mount // (capMkIco) rather than re-selecting a positional first match; capV()/capEtaIco/capEta stay // class-filtered as they always were and do not care about which row they live in. const V_MARKUP = '
' + // Per-row dither strips (MoEProgressVertical.css .mpv-bd) -- one per number row, each flush // on the surface's minimap-facing edge. Positioned purely by CSS `top`; no JS drives them. '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
()' + '
'; function ensureRoot() { let root = document.getElementById("moe-bar-root"); if (root) return root; root = document.createElement("div"); root.id = "moe-bar-root"; root.innerHTML = MARKUP; document.body.appendChild(root); return root; } const root = ensureRoot(); // `let`, not `const`, because goVertical() re-builds the root's contents under the .mpv- prefix and // every one of these has to be re-queried against the new nodes. Under a single orientation nothing // rewrites them. let fill = root.querySelector(".mp-fill"); let tPre = root.querySelector(".mp-pre"); let tProj = root.querySelector(".mp-proj"); let capP = root.querySelector(".mp-capP"); let capC = root.querySelector(".mp-capC"); let capR = root.querySelector(".mp-capR"); // capP's backdrop strip (VERTICAL only) -- it must sit BEHIND capP, which rides the pre tick along // the axis (capP.style.bottom is rewritten every render), so a fixed CSS `top` can't stay behind it. // goVertical caches it and JS-tracks it to capP's own `bottom`; null (and untouched) horizontally. let capBd3 = null; // The 0%/floor axis-end tick (VERTICAL only: .mpv-end.mpv-bottom). It marks "no progress" and must // show ONLY while the current value is 0 -- once the bar has any fill it reads as clutter under the // fill's own bottom edge. goVertical caches it; null (and untouched) horizontally, where the axis-end // ticks are mp-left/mp-right and carry no such rule. let tBottom = null; let capD = capC.querySelector(".mp-d"); let capDN = capC.querySelector(".mp-d-num"); // The remaining-battles pair on capR. Its own classes, NOT a second .mp-v / an .mp-ico index: see the // mark-pair-comes-first note on the template above (horizontal only -- the vertical capR swaps the // two groups; see V_MARKUP and capMkIco below). let capEtaIco = capR.querySelector(".mp-ico.battles"); let capEta = capR.querySelector(".mp-eta"); // The ETA row's decorative backdrop strip -- null (and untouched) horizontally, where there are no // .mpv-bd-* strips at all. Gated the same as capEtaIco/capEta below (see goVertical/paintStatic). let capEtaBd = null; // ...and the MARK glyph, the one icon setIco() ever rewrites -- CAPTURED HERE, ONCE, exactly like // capEtaIco, because it is the only addressing that survives BOTH the two compositions' opposite DOM // orders AND setIco's own wholesale className reassignment (which drops any marker class the moment // the first glyph lands). `.none` is its markup-literal state in BOTH templates and nothing else // carries that class at mount -- paintStatic only ever toggles `none` onto the BATTLES glyph, later. // A CLASS-FILTERING SELECTOR IS NOT AN OPTION HERE, and that is engine fact, not preference: // Coherent Gameface's selector engine (win64/cohtml.WindowsDesktop.dll) implements exactly // :hover :active :root :host :nth-child :first-child :last-child :only-child :focus ::part ::slotted // ::selection -- there is NO :not, in the pseudo-class table or anywhere else in the binary, and // WG's own shipped Gameface corpus (614 JS, 515 CSS) does not use one either. A // `querySelector(".mp-ico:not(.battles)")` is an "Invalid CSS selector (...) in QuerySelector!", // and the unguarded `.className` write on its result threw out of paintStatic and blanked the whole // bar. Keep any new lookup to plain class / compound-class selectors. let capMkIco = capR.querySelector(".mp-ico.none"); // ADOPT THE VERTICAL COMPOSITION -- the bar's half of MoEBarTransient's onVertical hook (the // shared module owns the surface, the rigid shift, the run-identity pair and the body scope class). // Called ONCE, inside engine.whenReady, BEFORE the surface push and before the first render, so // nothing downstream ever sees the horizontal DOM. A mid-battle Orientation change re-mounts this // document (Python closes and reopens the window -- battle_bridge.apply_settings), which comes // straight back through here; there is deliberately no live re-composition path. function goVertical() { PFX = "mpv"; AX = "bottom"; GROW = "height"; CAP_C_AX = null; // capC is a STATIC bottom cap here -- see the profile note root.innerHTML = V_MARKUP; fill = root.querySelector(".mpv-fill"); tPre = root.querySelector(".mpv-pre"); tProj = root.querySelector(".mpv-proj"); capP = root.querySelector(".mpv-capP"); // capP's strip: anchor it the SAME way capP is (bottom:% + translateY(50%)) so JS can drive its // `bottom` to capP's own value each render and it stays centred behind the number at both sizes. capBd3 = root.querySelector(".mpv-bd-3"); if (capBd3) { capBd3.style.top = "auto"; capBd3.style.transform = "translateY(50%)"; } tBottom = root.querySelector(".mpv-bottom"); capC = root.querySelector(".mpv-capC"); capR = root.querySelector(".mpv-capR"); capD = capC.querySelector(".mpv-d"); capDN = capC.querySelector(".mpv-d-num"); // capEtaIco/capEta now live in the SEPARATE .mpv-capEta row (stacked above capR), not inside // capR itself -- scoped off `root`, since both classes are unique across the whole document. capEtaIco = root.querySelector(".mpv-ico.battles"); capEta = root.querySelector(".mpv-eta"); capEtaBd = root.querySelector(".mpv-bd-1"); capMkIco = capR.querySelector(".mpv-ico.none"); } function capV(c) { return c.querySelector(ns(".mp-v")); } // The mark glyph for the NEXT-MARK caption: k in 1..3 -> mk; k=4 (3 marks held, no higher mark // to chase) -> the general MoE glyph; k=0 -> no icon at all (.none is display:none). // IT WRITES TO THE CACHED capMkIco AND NEVER RE-SELECTS -- .mp-capR holds TWO .mp-ico nodes and the // two compositions order them oppositely, so a per-call positional lookup would silently overwrite // the BATTLES glyph's class on the vertical bar (dropping `battles` entirely -- this reassigns // className wholesale). See capMkIco for why the filtering cannot be done in the selector. // NULL-GUARDED, per this codebase's fail-soft rule: a missing glyph must cost the glyph, never the // whole bar -- an unguarded deref here threw out of paintStatic and blanked the composition. // The k=0 arm is unreached from paintStatic today -- its only caller passes marks+1 or 4 -- but it // stays, because without it a stray 0 would write the nonexistent class "mk mk0" and blank the // glyph silently instead of hiding it. // CAP-LEVEL mk1/mk2/mk3, SEPARATELY FROM THE ICON'S OWN CLASS: .mp-capR's own margin-left (the // block<->bar gap, CSS's "block-gap" knob) now varies per mark too, and unlike the icon there is // no OTHER class on the caption to key a compound selector off, so capR gets its own copy of the // same mk marker. classList.toggle, not a wholesale className rewrite: capR carries its own // "mp-cap side mp-capR" (horizontal) / "mpv-cap mpv-capR" (vertical) classes permanently and only // the mark marker should move. Ungated by capMkIco's null-guard on purpose -- the caption's own // classing must stay correct even on the rare tick capMkIco failed to resolve. function setIco(k) { if (capR) { capR.classList.toggle("mk1", k === 1); capR.classList.toggle("mk2", k === 2); capR.classList.toggle("mk3", k === 3); } if (!capMkIco) return; capMkIco.className = ns("mp-ico") + (k === 0 ? " none" : k === 4 ? " moe" : " mk mk" + k); } // --- the pushed state --------------------------------------------------------------------- // `cur` is the latest push; `last` is the previous one, and comparing the two IS the // change-detect (there is deliberately no `rev` counter on ProgressVM -- the battle window is a // private, always-compositing view and has never needed the garage's cold-mount signal). // `last === null` means "no baseline yet": the FIRST push after mount (and after any re-show) is // recorded silently so the bar does not appear at battle start. let cur = { marks: 0, axisLo: 0, axisHi: 0, preAvg: 0, projAvg: 0, eta: -1 }; let last = null; // This bar's OWN animation state, all of it about VALUES rather than the run: `swapped` = the bottom // numeral currently shows proj_avg (not pre_avg); `swapT` is the pending swap timer -- ALWAYS // cleared before starting anything, or an aborted run's swap fires into the new one. The run state // itself (showing / peeking / the plateau clock / the surface settle) lives in the shared transient. let swapped = true; let swapT = null; // PRE_AXIS_STOP_PCT -- the bar-width % the career pre-battle average (`preAvg`) is remapped onto. // Same piecewise-linear equal-quarters trick MoECalculator.js's barX() spreads PCT_STOPS over // BAR_STOPS with (and battle_builder.efficiency_bar_x mirrors again for the Damage Efficiency // bar): there the stops are a fixed table; here they are per-battle [axisLo, preAvg, axisHi] -- // but preAvg is FIXED for the whole battle (the career average does not move mid-battle), so it // is just as good a stop as any of barX's percentiles, and only `cd` (via projAvg) travels // through the remap. // // WHY: at EWMA_K, the raw proportional share of the [axisLo, preAvg] segment is // k*preAvg/(axisHi-axisLo) -- ~1.42% for a realistic tank, indistinguishable from the width of // the preAvg tick itself, so the pre/cur markers overlap at battle start and the bar barely moves // early. A .mp-tick is 2rem wide with a `0 0 6rem` glow, ~14rem of footprint on the 200rem track // (~7%), so 8% is the smallest slice that clears the glow overlap. Tune by eye. const PRE_AXIS_STOP_PCT = 8; function axisPct(v) { const w = cur.axisHi - cur.axisLo; if (w <= 0) return 0; const val = Math.max(cur.axisLo, Math.min(cur.axisHi, v)); const pre = cur.preAvg; // Degenerate preAvg (missing/0, at or below the floor, at or above the ceiling) leaves no // usable middle stop -- collapse to the plain single-segment map rather than divide by a // zero-width segment or invert the axis. if (!(pre > cur.axisLo && pre < cur.axisHi)) { return (val - cur.axisLo) / w * 100; } const V_STOPS = [cur.axisLo, pre, cur.axisHi]; const P_STOPS = [0, PRE_AXIS_STOP_PCT, 100]; for (let i = 1; i < V_STOPS.length; i++) { if (val <= V_STOPS[i]) { const t = (val - V_STOPS[i - 1]) / (V_STOPS[i] - V_STOPS[i - 1]); return P_STOPS[i - 1] + t * (P_STOPS[i] - P_STOPS[i - 1]); } } return 100; } // Position the fill, the moving tick and its caption. anim=false SNAPS (transition:none) -- used // to rewind to the resting value before a cold show. The 600ms transition DELAY lives in the CSS // (.mp-fill, .mp-proj, .mp-capC), so JS sets the target once and lets CSS time it. // THE AXIS IS A PAIR OF PROPERTY NAMES, not two code paths: GROW is the fill's growth property // (`width` horizontally, `height` vertically -- 0% at the BOTTOM) and AX the marker's position // property (`left` / `bottom`). CAP_C_AX is null on the vertical composition, where capC is a static // cap below the track's bottom end and does not track the proj tick at all; the transition writes // stay unconditional because suppressing a transition an element never declares costs nothing. function setPos(v, anim) { const p = axisPct(v).toFixed(3) + "%"; const t = anim ? "" : "none"; fill.style.transition = t; tProj.style.transition = t; capC.style.transition = t; fill.style[GROW] = p; tProj.style[AX] = p; if (CAP_C_AX) capC.style[CAP_C_AX] = p; } // The bottom-centre numeral shows pre_avg while the bar fades + slides IN, then swaps to proj_avg // at VALUE_SWAP_MS -- the same instant the fill/tick begin moving -- so the number never claims a // gain the bar has not shown yet. The delta arrives WITH that swap. // // THE SIGN COLOUR DURING THE ENTRY IS THE *PREVIOUS COMMITTED* ONE -- AN EXPLICIT MAINTAINER // DECISION, NOT DRIFT, verbatim: "Before the sign class lands, applied color must resemble previous // state. E.g., when the bar was red and dealt damage moves it into green, it must appear red and // then turn green after recalculation lands. If it was and will remain red, it must always show // red." So the sw==false path (the cold damage entry) writes the numeral back to pre_avg and hides // the delta but DELIBERATELY DOES NOT TOUCH .mp-up/.mp-down: whatever the last showVal(true) // committed stays applied for the whole 600ms entry, and a NEW sign is only claimed once it lands at // the swap. The was-red-stays-red case therefore shows NO colour change whatever -- which is the // whole point; an earlier build stripped both classes here and flashed the neutral fill on every // single cold entry. Holding a class across coldShow's suppress -> reflow -> armRun sequence // interpolates nothing: .mp-fill transitions width only, .mp-proj / .mp-capC left only, and no // .mp-up/.mp-down rule declares a transition at all (see the CSS). // // sw==true is the ONLY path that ever REMOVES a class, and it has to stay that way -- it is what // clears the sign when a transition lands on a rounded-zero delta. So the neutral colour is // reserved for exactly two states: nothing committed yet (the first show of a battle) and a // rounded-zero delta. Only this bottom caption (plus the fill and the tick it rides) ever takes // .mp-up/.mp-down; the two requirement captions and the top-centre pre_avg caption stay plain // white (see the CSS's "WHO GLOWS" note). function showVal(sw) { const d = cur.projAvg - cur.preAvg; capV(capC).textContent = fmt(sw ? cur.projAvg : cur.preAvg); capD.style.opacity = sw ? "1" : "0"; // SIGN + MAGNITUDE ONLY. The remaining-battles count used to be appended here as "/NN"; it now // lives on .mp-capR beside the requirement it is a countdown to, with a glyph of its own (see // paintStatic). Do not re-append it: it was the single term that pushed capC's reach to 74rem. capDN.textContent = (d > 0 ? "+" : d < 0 ? "-" : "") + fmt(Math.abs(d)); if (!sw) return; // the entry window keeps the PREVIOUS committed sign -- see above // THE CLASSES KEY OFF THE ROUNDED VALUE, PRECISELY SO GLYPH AND GLOW CAN NEVER DISAGREE. `d` // is a raw float but the text above is rounded by fmt(), so an unrounded test glowed GREEN on // a displayed "(+0)" (any 0 < d < 0.5 -- routine at EWMA_K, and the "(-0)"-shows-red twin // equally so). The CSS says the intent outright: "a sub-precision change never reads as a // win". Tested on the MAGNITUDE, exactly as fmt() rounds it (half away from zero) -- NOT // Math.round(d), which is -0 for d == -0.5 while the text already reads "(-1)". const glows = Math.round(Math.abs(d)) !== 0; // capEta rides the SAME test as the delta -- no inversion. d > 0 is a better-than-average // battle, which LOWERS battles_to_axis_hi (fewer repeats still needed), so "d > 0 -> green" // already reads correctly on the countdown too. The intuitive-but-wrong instinct is "more // battles remaining is worse, so invert" -- resist it; there is no separate battles-count // delta to test against, only this one d. [capV(capC), capDN, fill, tProj, capEta].forEach(function (e) { e.classList.toggle(ns("mp-up"), glows && d > 0); e.classList.toggle(ns("mp-down"), glows && d < 0); }); } // Everything that does NOT animate: the axis-end captions + their mark glyphs, the static pre_avg // tick and caption, and the met-requirement gold. Safe to re-run on every push. function paintStatic() { capV(capR).textContent = fmt(cur.axisHi); setIco(cur.marks >= 3 ? 4 : cur.marks + 1); // 3 marks -> the general MoE glyph // THE REMAINING-BATTLES COUNT, second pair of the same row -- moved here off the delta because it // is a countdown to THIS requirement, and because on the delta it cost 15.18rem of the clipping // budget (see the header's re-derivation). // SUPPRESSION COLLAPSES THE BOX, IT DOES NOT JUST BLANK THE ART: `.mp-ico.none` is // `display: none` (MoEProgress.css), so a suppressed glyph takes NO width and NOT the shared // 1rem gap either -- verified in the stylesheet before reusing the variant, because a // background-only blank would have left a 14rem hole mid-row. The class is toggled, never // rewritten: setIco() reassigns className wholesale and would drop `battles`, which is why the // family class is static in the template. The TEXT has to be cleared too -- a live count beside a // collapsed glyph is exactly the state this suppression exists to avoid. // WHEN: >= 1 only. 0 means the requirement is already met (.mp-full's gold says so, and // battles_to_axis_hi returns 0 on precisely the same proj_avg >= axis_hi test), -1 is the no-data // sentinel, and `>= 1` on a Number() of a possibly-ABSENT field is NaN-false -- so a pre-push // frame or an older harness fixture renders no count rather than a bogus one. const showEta = cur.eta >= 1; capEtaIco.classList.toggle("none", !showEta); capEta.textContent = showEta ? fmt(cur.eta) : ""; if (capEtaBd) capEtaBd.classList.toggle("none", !showEta); capV(capP).textContent = fmt(cur.preAvg); const pre = axisPct(cur.preAvg).toFixed(3) + "%"; tPre.style[AX] = pre; capP.style[AX] = pre; if (capBd3) capBd3.style.bottom = pre; // keep capP's backdrop strip behind the moving number // The floor tick shows ONLY at zero progress (vertical only; null-guarded == no-op horizontally). if (tBottom) tBottom.style.display = cur.projAvg > 0 ? "none" : ""; root.classList.toggle(ns("mp-full"), cur.projAvg >= cur.axisHi); } // Schedule the numeral/delta/sign commit for VALUE_SWAP_MS from now -- the same delay the // fill/tick transitions carry, so number and bar commit together. function scheduleSwap() { clearTimeout(swapT); swapT = setTimeout(function () { swapped = true; showVal(true); }, VALUE_SWAP_MS); } // COLD SHOW: the bar is not up -> play the whole mp-life transient. // The REWIND idiom (transition:none -> write the resting value -> force a reflow -> hand the // transition back) is what lets a run start from pre_avg even if a previous run was aborted // part-way; the same treatment cancels a half-finished delta fade. Clearing the pending swap // FIRST is not optional. Ported from the tuner's replay() (gen_bar_tuner.ps1:921-930). // // `atCurrent` (falsy by default -- the DAMAGE-EVENT entry, unchanged) picks which VALUES the run // opens with; the MOTION is identical either way (armRun(SEEK_NONE), the tuned 600ms fade + 20rem // slide). Falsy = the rewind above: the FILL/TICK open at axisLo (the true axis floor, 0%) while // the NUMERAL opens on pre_avg with the delta hidden, then both climb to proj_avg on the // 600ms-delayed transitions and the numeral swaps at VALUE_SWAP_MS. That floor->current climb // IS the widget when a damage event pulls the bar up, so it must stay. // TRUE (only peekOn's Alt entry): open ALREADY committed -- fill/tick/caption snapped to proj_avg, // numeral + delta + sign already showing -- because Alt is a "show me the state now" request and // the 0-600ms pre-battle frames read as stale info. No scheduleSwap: there is nothing left to // commit. The transitions still have to be suppressed and flushed (void root.offsetWidth) BEFORE // armRun re-adds the run class, or the 600ms-delayed width/left transitions animate anyway and the // stale flip comes back through the back door; likewise capD's transition is off while opacity // goes to 1, or the delta fades in over 600ms instead of being simply present. // This is the transient's onRewind hook: it runs INSIDE a cold show, before the run is armed. // `atCurrent` is the shared coldShow's `!fromDamage`, i.e. true exactly for peekOn's Alt entry. function coldRewind(atCurrent) { clearTimeout(swapT); capD.style.transition = "none"; swapped = !!atCurrent; showVal(swapped); T.disarm(); void root.offsetWidth; setPos(swapped ? cur.projAvg : cur.axisLo, false); void root.offsetWidth; capD.style.transition = ""; } // ...and this is its onCommit hook: the pre->current climb, run after the transient arms a DAMAGE // cold show and after every warm re-trigger. // // WARM RE-TRIGGER: a change arrived while the bar is ALREADY up, so the transient re-measures the // DISAPPEARANCE rather than replaying the appearance (see its warmShow). NOTE the one place the // phase-1 plan does NOT apply: we deliberately do NOT rewind the fill/tick to their resting values // there. They stay where they are so the bar animates from its CURRENT position to the new target -- // the rewind above is for cold shows only. For the same reason the bottom numeral is left showing // the PREVIOUS proj_avg until the scheduled swap, so number and bar still commit together. // // THE rAF IS COLD-ONLY AND THAT ASYMMETRY IS DELIBERATE: after a cold entry the run class was just // added and coldRewind wrote a resting value, so the class change and the new target must land in // DIFFERENT frames (the tuner does the same). A warm re-trigger rewound nothing and rearmed at the // plateau, so it sets the target synchronously -- as this bar always has. function commitClimb(cold) { if (cold) { requestAnimationFrame(function () { setPos(cur.projAvg, true); }); } else { setPos(cur.projAvg, true); } scheduleSwap(); } // The transient's onEnd hook -- the value half of its FORCE-SETTLE. mp-life is both-filled so the // root rests at its 100% stop (opacity 0) with no help from JS, but a swap timer longer than the // transient would otherwise leave the resting bar showing pre_avg forever, and a cancelled delta // fade could strand part-way. showVal(true) sets both outright. Ported from // gen_bar_tuner.ps1:931-940. function settleValues() { clearTimeout(swapT); setPos(cur.projAvg, false); swapped = true; showVal(true); } // ...and its onIdle hook: the resting/hidden state. No showVal here -- the bar is invisible, and the // next entry rewinds the values itself (coldRewind). function idleValues() { clearTimeout(swapT); swapped = true; } // THE TRANSIENT. Everything shared with MoEEfficiency.js -- arming and its negative-delay debounce, // the run clock, the ALT PEEK (play or keep mp-life and PAUSE it at the hold plateau, so the entry is // the real fade+slide and the hold simply never ends; on release, mirror into the fade-out or RESUME // an interrupted damage hold), the animationend-vs-timer end race, and the surface push + // post-deadline re-assert. Read its header before touching any of it. // This bar uses ALL FOUR hooks, because unlike the Damage Efficiency bar its cold entry has values to // rewind and a pre->current climb to commit. Note peekOn's entry arrives as onRewind(atCurrent=true): // the Alt entry opens on the CURRENT values, never the pre-battle rewind -- Python pushes a fresh // compute in the same transaction as setAltHeld (battle_bridge._set_alt_held), so the VM is already // current and the outdated first frames were purely that rewind. const T = createTransient({ root: root, boxLeft: BOX_LEFT_REM, boxTop: BOX_TOP_REM, boxW: BOX_W_REM, boxH: BOX_H_REM, pad: PAD_REM, onRewind: coldRewind, onCommit: commitClimb, onEnd: settleValues, onIdle: idleValues, // THE VERTICAL COMPOSITION. `cls` is the body scope class MoEProgressVertical.css hangs off AND // the key to that stylesheet's own re-trigger keyframe twin (MoEBarTransient's RUN_CLASSES_V); // `box` replaces the four box* arguments above. Adopted at mount iff the model's `vertical` is // true, which then calls goVertical below for the DOM half. vert: { cls: "mpv", box: [V_BOX_LEFT_REM, V_BOX_TOP_REM, V_BOX_W_REM, V_BOX_H_REM], clipB: V_CLIP_B_REM, padX: V_PAD_X_REM, padXR: V_PAD_XR_REM, padXRLarge: V_PAD_XR_REM_LARGE }, onVertical: goVertical, }); function render(model) { // Truthy guards, not `=== false`: a root VM whose flags are still undefined before Python's // first push must stay hidden, not paint a zero-width bar over the HUD. hasData false means // the per-tank threshold table gave no usable mark axis -- there is nothing to plot. if (!model || !model.visible || !model.hasData) { root.style.display = "none"; T.reset(); // Drop the change-detect baseline too, so a later re-show starts COLD and the next push // becomes a fresh silent one (a scoreboard opening and closing must not replay the bar). last = null; return; } root.style.display = ""; // The pushed size mode (mod_settings.progress_bar_size). Idempotent in the transient, so this is // just "keep it in sync"; it owns the root-font write, the .mp-lg body class and the re-derived // surface. Nothing in THIS file measures px, so there is nothing else to scale here (contrast // MoEEfficiency.js's capClampPct, which mixes offsetWidth with rem literals). T.size(Number(model.barSize) === 1); // The pushed TRANSITION switches (mod_settings.progress_transitions_events / _manual, with the // Transitions master already ANDed in Python -- there is no master field to read here). The // transient only records them; the arming path decides per run. Passed RAW, deliberately: the // transient reads an ABSENT field as animated (see applyAnim), which is the fail-soft direction -- // a `!!` here would turn a missing prop into "instant" instead. T.anim(model.transEvents, model.transManual); // The pushed HOLD DURATION (mod_settings.progress_hold_seconds * 1000). Passed RAW for the same // reason as the two switches: the transient reads an absent / non-positive field as the baked // 5000ms (see applyHold), which is the fail-soft direction -- a `|| 0` here would mean no hold. T.hold(model.holdMs); // The pushed CTRL key state (battle_bridge._ctrl_held): the drag-to-reposition gesture, which // opens the input hit rect and holds the bar up for as long as the key is down. Passed RAW like // the three above -- the transient tests it with `=== true`, so an absent field reads as NOT // held, which is the fail-soft direction HERE (an open hit rect would steal HUD input). Ahead // of T.peek() below, which ORs this state in. T.ctrl(model.ctrlHeld); cur = { marks: Number(model.marks) || 0, axisLo: Number(model.axisLo) || 0, axisHi: Number(model.axisHi) || 0, preAvg: Number(model.preAvg) || 0, projAvg: Number(model.projAvg) || 0, // NO `|| 0` here, deliberately: 0 is a MEANINGFUL value (requirement met) and an absent // field must not collapse into it. Number(undefined) is NaN, which paintStatic's `>= 1` reads // as "render no count" -- the fail-soft direction for a brand-new VM field. eta: Number(model.etaBattles), }; paintStatic(); // CHANGE-DETECT, JS-side: replay only when a pushed value actually MOVED. Python re-pushes on // every efficiency tick with no dirty check, so without this the bar would replay constantly. const changed = last !== null && ( cur.projAvg !== last.projAvg || cur.preAvg !== last.preAvg || cur.axisLo !== last.axisLo || cur.axisHi !== last.axisHi || cur.marks !== last.marks); const first = last === null; last = cur; // THE SHOW TRIGGER IS GATED ON T.settled(); THE SILENT BASELINE BELOW IS NOT. Before the // re-assert the surface is the engine's 256x256 fallback: the bar would come up cropped and // ~142px too high (see the shared module's SURFACE_REASSERT_MS). The baseline shows nothing, so // it costs nothing to let it run -- and it MUST run, or `last` never gets recorded and the first // real change plays a bogus pre->proj climb. T.show() picks warm-vs-cold off its own `showing`. // // THE SHOW TRIGGER IS ALSO GATED ON `showEvents` (mod_settings.progress_show_events, with // "Always" already folded in Python -- there is no master field to read here). `!== false`, NOT // `!!`: a model that does not carry the field at all (a pre-push frame, a harness fixture) must // degrade to the SHIPPED behaviour, which is "an event raises the bar". The other two visibility // switches need no branch -- "Alt Press" and "Always" both arrive folded into `altHeld` below. if (first) { // Silent baseline: settle the bar at its resting values without showing anything. setPos(cur.projAvg, false); swapped = true; showVal(true); } else if (changed && model.showEvents !== false && T.settled()) { T.show(); } // Alt is handled AFTER the value change so a push that carries both (Python re-pushes on every // Alt transition) gets the new target AND the peek hold. An Alt held BEFORE the surface settled // is not lost: the settle re-renders the current model, which arrives here with altHeld still // true and peeks then. T.peek(!!model.altHeld); } // The rigid translation into the surface, the surface push + its post-deadline re-assert, then the // model subscription and the first render -- all in T.mount (see the shared module). T.mount(observer, render); PK!MzzCres/gui/gameface/mods/14th_ua/MoECalculator/MoEProgressVertical.css/* MoEProgressVertical.css -- VERTICAL variant of the in-battle MoE progress bar (class prefix .mpv-, never .mp-). Tuned in the browser (tools/dev/gen_bar_tuner_vertical.ps1 -EmitCss, which writes TASKS/refs/MoEProgressVertical.css) and ported from that emit; the battle window has no hot-reload. Position comes from Python (window.move()), NOT from CSS -- the tuner's own minimap-relative placement preview never reaches this file. Font: the bundled MoEBattle numeric subset, 19 glyphs (digits % ( ) + - , . / space) -- NO LETTERS. It is NOT re-declared here: MoEProgress.css is ed in the SAME document and carries the @font-face. Axis: 0% at the BOTTOM, 100% at the TOP -- the fill grows bottom->top (height, not width), and every marker positions with bottom: + translateY(+50%), not the horizontal bar's -50%: a bottom-anchored box must shift back DOWN by half its own length to land on its point. EVERY "MAINTAINER NUDGE" BELOW (and in MoEEfficiencyVertical.css) IS AUTHORED IN LOGICAL PX, NEVER DEVICE PX -- a bare `Nrem` declaration is 1rem == 1 logical px at Default (see MoEProgress.js's own header note), so a maintainer's "move it N px" is a LOGICAL-px request only if N is already stated that way. A player's interface scale (captureBaseFont(), legible only as <1.5 vs >=1.5, fixed at mount -- see the memory `interface-scale-is-only-legible-via- capturebasefont`) is UNRELATED to this bar's own Default/Large size mode and can silently double (or more) a "device px" request into logical px: GUI.screenResolution() reading 3840x2160 over a 1920x1080 logical space is interface scale 2, so "N device px" there means N/2 logical px, not N. CONFIRM THE UNIT before translating a maintainer's px count into one of these declarations. THIS SHEET IS LOADED ALONGSIDE MoEProgress.css, NOT INSTEAD OF IT (MoEProgressView.html links both; orientation is a MOUNT-TIME branch in MoEProgress.js, not a second res_map layout -- a new itemID would cost every user a one-time client restart). The two sheets are namespace-DISJOINT by construction (.mp-* vs .mpv-*), so nothing below can collide with a horizontal rule except the THREE shared subjects -- `body`, `#moe-bar-box` and `#moe-bar-root` -- and those are the only selectors here that carry the `body.mpv` scope. `mpv` goes on the BODY (MoEBarTransient's goVertical), because #moe-bar-box is a body-level SIBLING of the JS-created root and a class on the root could never reach it; `body.mpv ...` is also (1,1,1) so it out-specifies the horizontal sheet's own `.mp-lg #moe-bar-root` (1,1,0) outright rather than winning on source order. THE SHIPPED FILE IS THE EMIT PLUS EIGHT DELIBERATE HAND-EDITS -- never copy an -EmitCss output over it (the repo lesson `emitcss-is-not-the-whole-shipped-stylesheet`; MoEProgress.css carries the same warning for its own four). Each one is marked HAND-EDIT n/8 at its site: 1 the root rule: the tuner stage's `position: relative` becomes the shipped `position: absolute; left: 0; top: 0` + z-index/pointer-events, and the selector is scoped. 2 #moe-bar-box, the sizing shim -- not emitted at all (the tuner has no surface). 3 the dash grid's GAP STRIPE goes OPAQUE (alpha 1), where the tuner's `gapA` default is 0.5. 4 `.mpv-lg` becomes `.mp-lg` -- the body class MoEBarTransient.applySize actually writes. 5 the two Large rules whose subject is #moe-bar-root / #moe-bar-box are scoped `body.mpv.mp-lg`. 6 THE ETA ROW SPLIT (maintainer's call, ported here only -- the tuner's own capR markup keeps both numeral+icon groups on ONE row, untouched) plus a per-icon MARGIN-ONLY ink-gap parity pass (corrected 2026-08-08: an earlier version of this edit also resized the icon BOXES -- the maintainer reverted that outright, "icon sizes must stay the same, adjust paddings individually", so every box below is back at its pre-split size and only margin-left differs from the shared 1rem). Replaces the old "eta-gap retarget" hand-edit outright (a single-row concept the split makes moot, not something to carry alongside a new #7): * a NEW `.mpv-capEta` rule (eta numeral + battles icon) is inserted right after `.mpv-capR` (now JUST the requirement numeral + mark icon), stacked directly above it via `bottom: 100%; padding-bottom: 30rem` -- 30 == capR's own box height (18rem line-height + 6rem padding-bottom == 24) plus a 6rem visual gap, matching this file's own "clear the track" gap magnitude elsewhere. Same right-anchor mechanism (padding-right/transform/font-size/line-height) copied verbatim from capR, since both rows shared it identically before the split. * the old combined `.mpv-capR .mpv-ico` / `.mpv-capR .mpv-v, .mpv-capR .mpv-eta` Y-nudge rules split into their own per-row copies (capR keeps the mark icon + `.mpv-v` nudge; capEta gets an identical copy for the battles icon + `.mpv-eta` nudge -- same row line-height, same nudge value, so the SAME quantisation holds for both). This part is UNAFFECTED by the box revert (margin never touches this Y quantisation at all). * FOUR per-icon margin-left overrides close the ink-gap residual the shared 1rem base leaves, measured live off the real PNGs' alpha>32 bounding box (not estimated): dmgp +0.253rem, moe -0.115rem, mk -2.25rem, battles +0.038rem off the base 1rem -- see each rule's own note below for the derivation. `.mpv-ico.dmgc` is the UNTOUCHED reference (16rem box, base 1rem margin already lands ~3.006rem of ink gap) that every other row is calibrated against; nothing about it moves. The old #6 retarget (`.mpv-capR .mpv-eta` margin-left -> `.mpv-v`) no longer applies: with the groups on separate rows there is no single shared row left to retarget the gap onto. 7 `.mp-lg .mpv-capC` -- a Large-only caption-position nudge (current-damage moved 4px right, monitor px, recalibrated 2026-08-17), right-anchored so right is a NEGATIVE translateX delta; factor is monitor_px / 8 (1 rem == 8 monitor-px under Large on this maintainer's setup). 8 `.mpv-bd.none { display: none; }` -- MoEProgress.js toggles class `none` on `.mpv-bd-1` (capEtaBd) when `showEta` is false, mirroring the existing `.mpv-ico.none` idiom; without this rule no CSS defines what `none` does to a `.mpv-bd` strip, so it never hides. Anything else diverging from a fresh emit is drift, not intent. */ /* HAND-EDIT 1/8. Emitted as a bare `#moe-bar-root { position: relative; ... }` -- the tuner stage flows the bar inside an .mpv-anchor wrapper, whereas the shipped bar IS the document: absolute at the origin (MoEBarTransient's mount then writes the rigid left/top shift into the surface), z-index above the HUD, and pointer-events:none because this bar is pure info and must never be an input target. The tuner emits none of those three. width/height/font/text-align/opacity are the emit verbatim: 3rem of track cross-section, 200rem of axis. */ body.mpv #moe-bar-root { position: absolute; left: 0; top: 0; width: 3rem; height: 200rem; z-index: 9000; pointer-events: none; font-family: "MoEBattle", "Arial Narrow", sans-serif; text-align: center; opacity: 0; } /* HAND-EDIT 2/8 -- THE SIZING SHIM, the vertical twin of MoEProgress.css's own. #moe-bar-root is position:absolute and contributes ZERO content size, so #moe-bar-box (declared in MoEProgressView.html, NOT JS-created -- it must exist at the FIRST layout pass) is what gives the document in-flow content. IT DOES NOT STOP THE ENGINE'S SIZE TIMEOUT -- that was re-measured live on the horizontal bar and disproven; MoEBarTransient's post-deadline SURFACE_REASSERT_MS is the only fix. The box is kept because it is the honest description of the document's size, and the horizontal sheet's 380x92 is the WRONG WAY ROUND for this composition. 112 x 320 MIRRORS the vertical surface MoEProgress.js pushes -- width V_BOX_W_REM + V_PAD_X_REM + V_PAD_XR_REM == 46+70-4, a SPLIT pad now (V_PAD_X_REM on the LEFT, caption ink; V_PAD_XR_REM on the RIGHT, the track's own tick overhang PLUS a small margin -- see both constants' own notes in MoEProgress.js, including fact 5 on why the margin is a PURE local quantity, never PROGRESS_MM_TRACK_X's hand-corrected placement value), height V_BOX_H_REM + 2*PAD_REM - V_CLIP_B_REM == 360+20-60, the same mirrored-constant contract as the JS's vertical shiftY <-> Python's domain/constants.VERTICAL_ANCHOR_Y_SHIFT: change one, change all three. THE LEFT X PAD IS 70rem, NOT PAD_REM's 10 (read V_PAD_X_REM's note in MoEProgress.js): the three captions are right-anchored and grow LEFTWARD past .mpv-backdrop by design, so the SURFACE has to reach out to their ink on that side while the backdrop deliberately does not. THE RIGHT X PAD IS NEGATIVE (-4rem, V_PAD_XR_REM): the SURFACE clips .mpv-backdrop's right-side bleed a little further than the backdrop's own (ALREADY TRIMMED, see below) drawn width, down to just past the track's own tick overhang PLUS a 2px margin -- this is the fix for the invisible surface reaching into the minimap's first column (see MoEProgress.js's own five-point note); it is a SEPARATE knob from the backdrop's own trim and costs nothing visible (the backdrop's right-side bleed is pure shadow/glow, no caption ink reaches that far -- see fact 1 of that same note). THE BACKDROP'S OWN RIGHT EDGE IS A DIFFERENT KNOB, V_BOX_W_REM (46, ALREADY TRIMMED from 72 to land flush with the minimap's own edge -- see MoEProgress.js's fact 3), NOT EITHER PAD -- and unlike the surface pad, IT HAS NO SYMMETRY CONTRACT for this bar: `anchor_minimap` (the Fixed+Vertical placement function, bar_window._resolve) has no term for the backdrop's width or left at all. THE HEIGHT IS 60rem SHORT OF THE COMPOSITION ON PURPOSE, and that is the surface's own doing, not this rule's: the surface CLIPS .mpv-backdrop's lower bleed so the engine's screen clamp can bring the bar's track down to the tuner's 30-logical-px gap off the screen bottom (read MoEProgress.js's V_CLIP_B_REM note -- it carries the whole derivation). This rule only keeps describing whatever the surface actually is. It stays a plain rem box either way, so it cannot reflow the composition when the surface shrinks past it. */ body.mpv #moe-bar-box { width: 119rem; height: 320rem; } /* .mpv-backdrop is now the INVISIBLE surface bounding-box marker only (its rule stays at V_BOX_* == -34/-80/46/360 as the CSS cross-check of MoEProgress.js's surface constants, pinned by tests/test_progress_surface_mirror.py). The visible dither moved to the per-row .mpv-bd strips below -- the corner overlay's .mb-backdrop technique (checker ::before + dark radial ::after), one strip per number row, each pinned FLUSH on the surface's minimap-facing edge. */ .mpv-backdrop { position: absolute; left: -34rem; top: -80rem; width: 46rem; height: 360rem; z-index: 0; } /* PER-ROW STRIPS. left/width are NOT free literals: they MIRROR the invisible surface the JS pushes (body.mpv #moe-bar-box == 112rem wide, left edge at -(V_PAD_X_REM - V_BOX_LEFT_REM) == -104rem), so each strip's right (minimap-facing) edge lands on the surface's own right edge (root x 8rem Default; 10rem Large via the .mp-lg twin below) -- flush, zero gap, and never past the surface (Gameface clips a draw that overruns the view). Solid dither hugs the minimap side (mask `at 90%`) and fades toward the leftward-growing numerals. Per-row `top` is a seed the maintainer converges. */ .mpv-bd { position: absolute; left: -104rem; width: 119rem; height: 30rem; z-index: 0; } /* Per-index width overrides -- right edge PINNED at the shared strip's own right edge (left+width == -104+119 == 15rem), growing LEFTWARD only, so the minimap-facing edge and the surface hit-rect do not move. Same specificity as .mpv-bd above; source order wins. */ .mpv-bd-4 { width: 178.5rem; left: -163.5rem; } .mpv-bd-2 { width: 148.75rem; left: -133.75rem; } /* bd-3 (preAvg) no longer gets its own width/left override -- 2026-08-17 crop fix (gen_bar_tuner_vertical.ps1 regenerated). The 2026-08-12 narrowing pass (then the 79.583rem -> 83.733rem right-edge correction in 98ab7ea) shrank this row's own box while leaving the WIDE checker-dither mask below unchanged; since that mask is sized/positioned in PERCENT (box-relative), narrowing the box also narrowed the taper's absolute reach, leaving too little room for the dither to fade to a point before this row's own (now much closer) left edge -- a hard cut instead of a taper. Falling back to the shared .mpv-bd box above (-104rem/119rem) restores the room the mask needs AND keeps the right edge flush at 15rem (this row never needed a narrower box to be flush -- narrowing it is what broke both properties at once). */ .mpv-bd::before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: url(checker.png) repeat; background-size: auto; background-position: 0px 0px; image-rendering: pixelated; opacity: 0.1; mask: radial-gradient(56% 110% at 90% 50%,#000 0%,transparent 67%); } .mpv-bd::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; background: radial-gradient(76% 57% at 90% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } .mpv-bd-1 { top: -50.5rem; } .mpv-bd-2 { top: -30rem; } .mpv-bd-3 { top: 85rem; } .mpv-bd-4 { top: 204rem; } /* capP's strip ONLY (.mpv-bd-3) -- its number sits farther from the minimap, so its dither reaches ~2x further left (wide X radius). Every other strip keeps the default radius above. */ .mpv-bd-3::before { mask: radial-gradient(112% 110% at 90% 50%,#000 0%,transparent 67%); } .mpv-bd-3::after { background: radial-gradient(128% 57% at 90% 50%,rgba(0,0,0,0.35) 0%,rgba(0,0,0,0) 70%); } /* HAND-EDIT 8/8: MoEProgress.js toggles class `none` on `.mpv-bd-1` (capEtaBd) when `showEta` is false, mirroring the `.mpv-ico.none` idiom below -- without this rule no CSS defined what `none` does to a `.mpv-bd` strip, so it never hid. */ .mpv-bd.none { display: none; } .mpv-track { position: relative; z-index: 1; width: 100%; height: 100%; background: rgba(0,0,0,0.45); } /* Garage dash grid, rotated (0deg == "to top", so the first stop sits at the BOTTOM edge). background-size: 100% rem tiles the gradient from a single period-sized tile instead of rasterizing it once across the whole track length -- without it the dash ink smeared over ~4 device px instead of a crisp 2 (the sibling MoEEfficiencyVertical.css carries the identical fix, and used to have the identical defect before today). The period is still a Y-length the root font already scales via SIZE_F, which is why the .mp-lg block below declares no twin for it. HAND-EDIT 3/8: THE GAP STRIPE IS ALPHA 1, where the tuner's `gapA` default is 0.5 (inherited from the horizontal tuner's). The garage look this clones is a MASK over the solid fill (`garage-progress-bar-fill-is-a-mask`): at 0.5 the fill shows through and the grid reads as a tint, so a gap looks lighter on the filled side of the edge than on the empty side. The shipped horizontal bar already carries the identical rewrite (MoEProgress.css:152, `rgb(13,14,16)`). THE RING KEEPS 0.5 -- it is a separate knob (bdrCol/bdrA), it sits OUTSIDE the fill, and it matches the garage's. Do not "fix" it to match. */ .mpv-track::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 1; background-image: repeating-linear-gradient(0deg,rgba(236,230,218,0.16) 0rem,rgba(236,230,218,0.16) 2rem,rgba(13,14,16,1) 2rem,rgba(13,14,16,1) 3rem); background-size: 100% 3rem; box-shadow: 0 0 0 1rem rgba(13,14,16,0.5); } .mpv-fill { position: absolute; left: 0; bottom: 0; width: 100%; height: 0; background: rgba(237,230,217,0.8); transition: height 600ms cubic-bezier(.2,.8,.2,1) 600ms; } .mpv-fill.mpv-up { background: rgba(123,236,55,0.8); } .mpv-fill.mpv-down { background: rgba(211,68,63,0.8); } .mpv-tick { position: absolute; left: 50%; z-index: 2; } .mpv-tick.mpv-end { background: rgba(237,230,217,0.8); width: 9rem; height: 2rem; transform: translate(-50%, 50%) translateX(0rem); } .mpv-tick.mpv-bottom { bottom: 0; } .mpv-tick.mpv-top { bottom: 100%; } .mpv-tick.mpv-pre { background: rgba(237,230,217,0.75); width: 9rem; height: 2rem; transform: translate(-50%, 50%) translateX(0rem); } .mpv-tick.mpv-proj { background: rgba(255,255,255,1); box-shadow: 0 0 6rem rgba(255,255,255,0.5),0 0 2rem rgba(255,255,255,0.5); width: 9rem; height: 2rem; transform: translate(-50%, 50%) translateX(0rem); transition: bottom 600ms cubic-bezier(.2,.8,.2,1) 600ms; } .mpv-tick.mpv-proj.mpv-up { box-shadow: 0 0 6rem rgba(123,236,55,0.9),0 0 2rem rgba(123,236,55,0.9); } .mpv-tick.mpv-proj.mpv-down { box-shadow: 0 0 6rem rgba(211,68,63,0.9),0 0 2rem rgba(211,68,63,0.9); } /* FIXED-ANCHOR captions, digit-count-independent (bug fix, mirrors eff_bar_tuner_vertical.html's shipped fix for the same defect): a shrink-wrapped box centred via left:50%+translateX(-50%) never gives any child a truly fixed screen position (both its edges move as content width changes), so all THREE captions now share ONE fixed right edge -- right:100%+left:auto, pinned to the track's own left edge -- clear of the tick's outer-edge overhang via the shared padding-right below. Numeral-then-icon DOM order means each caption's icon is the LAST in-flow child, so it sits flush against that fixed edge and is provably invariant to digit count. Only the numeral (and capC's delta, hanging off ITS left edge) grows/shrinks LEFTWARD, away from the anchor. capP is also the ONLY one that moves, tracking the pre tick's `bottom` -- and like that tick it never animates within one replay, so no transition is declared. DO NOT "OPTICALLY CENTRE" THE ABOVE/BELOW CAPTIONS. Because they are right-anchored and grow leftward, they read right-aligned against that line rather than centred over the track, and their apparent gap from the track's centreline varies with digit count even though the anchor never moves. Centring them needs a WIDTH-SCALED term -- which IS the bug this replaced. A non-zero residual nudge is fine; a nudge whose value is a function of the caption's own content width is the defect. */ .mpv-cap { position: absolute; display: flex; flex-direction: row; align-items: center; white-space: nowrap; z-index: 3; right: 100%; left: auto; } /* Gameface drops margin on the bottom/right ANCHORED side (gameface-drops-margin-on-the- anchored-side) -- padding on the bottom/right anchored sides; margin works as written on capC's top:100% anchor. padding-right (shared by all three captions) also carries the tick's outer-edge overhang (see the anchor comment above), so it clears the tick, not just the track. */ .mpv-capR { bottom: 100%; padding-bottom: 6rem; padding-right: 6rem; transform: translateX(15rem); font-size: 14rem; line-height: 18rem; } /* HAND-EDIT 6/8: the ETA row, stacked directly above capR (maintainer's call: "move the ETA on top of the next mark requirement"). Same right-anchor mechanism as capR, copied verbatim -- both rows shared it identically before the split. `padding-bottom: 30rem` == capR's own box height (18rem line-height + 6rem padding-bottom == 24) plus a 6rem visual gap off it, the same magnitude this file already uses to clear the track (capR's own 6rem, capC's 6rem). Re-derived in tests/test_progress_surface_mirror.py's Y-fit test against V_BOX_TOP_REM + PAD_REM, never hardcoded there. */ /* MAINTAINER NUDGE: the ETA row lowered 3 device/logical px (translateY, additive to the existing right-anchor translateX -- a WHOLE-ROW move, numeral+icon together). Pinned as a device-px count, not a bare rem: 1rem == 1 logical px at Default, but the root font IS the Large scale (SIZE_F == 1.25), so a plain "3rem" here would render 3.75px under Large. 3 / 1.25 == 2.4 is this rule's own Large twin below, so both sizes move by the SAME 3px on screen. */ .mpv-capEta { bottom: 100%; padding-bottom: 30rem; padding-right: 6rem; transform: translateX(15rem) translateY(3rem); font-size: 14rem; line-height: 18rem; } /* NUDGE REVERTED ON DEFAULT (2026-08-10 correction, twice-corrected): the maintainer's nudge was only ever meant for Large (see .mp-lg .mpv-capC below, which keeps its ORIGINAL, un-halved nudge -- a since-disproven interface-scale theory wrongly halved Large too; that halving is undone). Default restored to its pre-nudge value, translateX(16rem) -- LOGICAL PX is what a bare "Nrem" declaration always means here; see the header for the general rule. This is still the row test_the_vertical_captions_fit_inside_the_surface tracks as the file's own extreme (see MoEProgress.js's "capC is STILL the extreme" derivation); V_PAD_X_REM is UNCHANGED at 70 (it now carries more margin than this reverted move strictly needs, which is safe, not a bug). */ .mpv-capC { top: 100%; margin-top: 6rem; padding-right: 6rem; transform: translateX(16rem); font-size: 16rem; line-height: 20.5rem; } .mpv-capP { padding-right: 6rem; transform: translateY(50%) translateX(0rem); font-size: 14rem; line-height: 18rem; } /* Icon follows its numeral (DOM order: numeral, then icon) -- gap on the icon's LEFT. */ .mpv-cap .mpv-ico { margin-left: 1rem; } .mpv-cap .mpv-v, .mpv-cap .mpv-eta, .mpv-cap .mpv-d { color: #ffffff; font-weight: 600; letter-spacing: 0em; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5); } /* Delta is an IN-FLOW flex child, ordered FIRST (delta, numeral, icon) -- an ordinary margin-right gap, not an out-of-flow box hanging off a content-dependent edge (the exact mechanism of the digit-count bug this fixes). */ .mpv-cap .mpv-d { margin-right: 0.35em; font-size: 12rem; transform: translateY(1.5rem); line-height: 15.5rem; opacity: 0; transition: opacity 600ms cubic-bezier(.2,.8,.2,1); } .mpv-v.mpv-up, .mpv-d-num.mpv-up, .mpv-eta.mpv-up { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0rem 0rem 6rem rgba(123,236,55,0.9), 0rem 0rem 1rem rgba(123,236,55,0.9); } .mpv-v.mpv-down, .mpv-d-num.mpv-down, .mpv-eta.mpv-down { color: #ffffff; text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0rem 0rem 6rem rgba(211,68,63,0.9), 0rem 0rem 1rem rgba(211,68,63,0.9); } .mpv-ico { position: relative; display: block; flex: none; width: 13rem; height: 13rem; transform: translate(0rem, 0rem); } .mpv-capP .mpv-ico { transform: translate(0rem, 0rem); } .mpv-capC .mpv-ico { transform: translate(0rem, 0rem); } .mpv-capR .mpv-ico { transform: translate(0rem, 0.5rem); } .mpv-capR .mpv-v { transform: translateY(-0.5rem); } /* capEta's own copy of the SAME nudge, same row line-height (18rem) -- so the identical quantisation ((rowHeight-box)/2+nudge landing on a whole rem) holds for both rows. */ .mpv-capEta .mpv-ico { transform: translate(0rem, 0.5rem); } .mpv-capEta .mpv-eta { transform: translateY(-0.5rem); } .mpv-capC .mpv-v { transform: translateY(-0.5rem); } .mpv-capP .mpv-v { transform: translateY(-0.5rem); } .mpv-ico::before { content: ""; position: absolute; left: 50%; top: 50%; z-index: -1; width: 106%; height: 106%; transform: translate(-50%, -50%); background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } .mpv-capR .mpv-ico::before { background: radial-gradient(circle at 50% 50%, rgba(26,26,26,0.5) 0%, transparent 73%); } .mpv-ico::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: no-repeat; background-position: center; } .mpv-ico.dmgp { width: 14rem; height: 14rem; } .mpv-ico.dmgc { width: 16rem; height: 16rem; } .mpv-ico.dmgp::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_barrel_mark.png); background-size: 228.7%; filter: brightness(3); } .mpv-ico.dmgc::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_damage.png); background-size: 342.5%; filter: brightness(3); } .mpv-ico.moe { width: 17rem; height: 17rem; } .mpv-ico.moe::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_top.png); background-size: 274.7%; filter: brightness(3); } .mpv-ico.mk { width: 17rem; height: 17rem; } .mpv-ico.mk::after { background-size: contain; } .mpv-ico.mk1::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_1.png); } .mpv-ico.mk2::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_2.png); } .mpv-ico.mk3::after { background-image: url(img://gui/maps/icons/library/marksOnGun/mark_3.png); } /* PER-ICON MARGIN CORRECTIONS (2026-08-08 redo of the HAND-EDIT 6/8 ink-gap pass -- boxes are back at their pre-039a58c sizes above: "icon sizes must stay the same, adjust paddings individually"). Every icon here is framed by a FIXED background-size, so its ink WIDTH is a fixed fraction of its own box, independent of margin -- re-measured live off the real PNGs' alpha>32 bbox (gui-part*.pkg), not estimated or carried over from the box-lever version: dmgp box 14, ink == 0.75*box (icoFill) == 10.505rem, inset (14-10.505)/2 == 1.747rem dmgc box 16 (REFERENCE, untouched), ink == 0.75*box == 11.988rem, inset == 2.006rem -- base 1rem margin already lands ~3.006rem; every other row targets this exactly moe box 17, ink == 0.75*box (icoFill, calibrated on its own wider X dimension) == 12.769rem, inset (17-12.769)/2 == 2.115rem mk box 17, `background-size: contain` on a 24x24 canvas scales the WHOLE canvas by box/24 (box == canvas aspect), and the pip ink's OWN width varies by mark count (measured alpha>32 bbox: mark_1 6px, mark_2 12px, mark_3 18px, all of 24) -- NOT the fixed icoFill ratio the other icons get, so no static margin equalises every count (the code already forbids re-zooming per count above). Calibrated to mark_2 (12/24 == 0.5, the tuner's own default preview state): ink == 17*0.5 == 8.5rem, inset (17-8.5)/2 == 4.25rem battles box 13 (base .mpv-ico box, UNCHANGED), calibrated on its own TALLER dimension (measured bbox 27x29 of a 128px canvas -- height, not width, hits icoFill 0.75), so its WIDTH ink fraction is NOT 0.75 like the others: (27/128)*331.0% == 0.6982*box == 9.077rem, inset (13-9.077)/2 == 1.962rem Target ink gap == 3.00rem (dmgc's own reference) on every row; margin-left == target - inset, replacing the shared 1rem outright (not adding to it): dmgp 3.00 - 1.747 == 1.253rem moe 3.00 - 2.115 == 0.885rem (LESS than the shared 1rem -- moe's own ink is already wide enough that less margin than the base gets it to 3.00) mk 3.00 - 4.25 == -1.25rem (mark_2's inset alone overshoots the target, so the correction is NEGATIVE; mark_1/mark_3 land off this at ~5.125rem / ~0.875rem, an accepted residual of the count-dependent asset -- calibrating on any one count always leaves the other two off, "do NOT trim per count" above still holds) battles 3.00 - 1.962 == 1.038rem Kept to 3 decimal places (matching this file's existing 4/3 twins elsewhere); margin is a plain horizontal length with no (rowHeight-box)/2 quantisation to land on, so unlike a BOX these values carry no whole-rem/whole-device-pixel requirement -- they are calibrated off a continuously-measured asset bbox, so at least one of the two interface/size modes will always land on a sub-device-pixel offset regardless of rounding; the residual is well under a rem and is the same class of accepted drift as .mpv-capC's own quarter-rem residual elsewhere in this file. Compound three-class selectors (`.mpv-cap .mpv-ico.`, specificity (0,3,0)) beat the shared `.mpv-cap .mpv-ico { margin-left: 1rem; }` base rule (0,2,0) OUTRIGHT, the same convention the mark icon's own correction already used here -- not by source order. SOURCE ORDER IS STILL LOAD-BEARING for the ::before pair below, though the row split retires part of the old hazard: `.mpv-capR .mpv-ico::before` (above) no longer matches the battles glyph at all now that it lives in `.mpv-capEta`, not `.mpv-capR` -- so the dark-drop/gold race this rule pair used to run on that ONE icon is gone for the vertical bar. The pair itself stays (it still governs the MARK icon, which is still inside `.mpv-capR`) and the horizontal sheet's OWN identical pair (`.mp-capR .mp-ico::before` / `.mp-ico.battles::before`, MoEProgress.css) is UNCHANGED and still order-dependent exactly as before. */ .mpv-cap .mpv-ico.dmgp { margin-left: 1.253rem; } .mpv-cap .mpv-ico.moe { margin-left: 0.885rem; } .mpv-cap .mpv-ico.mk { margin-left: -1.25rem; } /* PER-MARK, hand-tuned in tools/dev/icon_gap_tuner.html: mark_1/mark_2/mark_3 no longer share one residual value off .mk above. Same (0,3,0) as .mk -- these win it by SOURCE ORDER (the icon keeps BOTH classes, "mpv-ico mk mk1", so the tie is real; see MoEProgress.css's identical note for the horizontal bar). No test in this repo pins an exact base*4/3 relationship for THIS file's .mp-lg block, so the Large twins below need not (and do not) satisfy it. */ .mpv-cap .mpv-ico.mk1 { margin-left: 0.500rem; } .mpv-cap .mpv-ico.mk2 { margin-left: 2.000rem; } .mpv-cap .mpv-ico.mk3 { margin-left: 4.000rem; } .mpv-cap .mpv-ico.battles { margin-left: 1.038rem; } .mpv-ico.battles::before { background: radial-gradient(circle at 50% 50%, rgba(255,205,90,0.5) 0%, transparent 73%); } .mpv-ico.battles::after { background-image: url(img://gui/maps/icons/personal_missions_30/quest_type/128x128/icon_battle_condition_battles.png); background-size: 331.0%; filter: brightness(3); } .mpv-ico.none { display: none; } #moe-bar-root.mpv-full .mpv-track, #moe-bar-root.mpv-full .mpv-fill, #moe-bar-root.mpv-full .mpv-tick { box-shadow: 0 0 8rem rgba(255,205,90,0.5); } #moe-bar-root.mpv-full .mpv-fill { background: rgba(255,205,90,0.8); } #moe-bar-root.mpv-full .mpv-v { text-shadow: 0rem 0rem 1rem rgba(0,0,0,0.5), 0 0 8rem rgba(255,205,90,0.5), 0 0 2rem rgba(255,205,90,0.5); } @keyframes mpv-life { 0% { opacity: 0; transform: translateY(20rem); animation-timing-function: ease-in; } 9.68% { opacity: 1; transform: translateY(0rem); animation-timing-function: linear; } 90.32% { opacity: 1; transform: translateY(0rem); animation-timing-function: ease-in; } 100% { opacity: 0; transform: translateY(20rem); } } #moe-bar-root.mpv-run { animation: mpv-life 6200ms both; } /* THE RE-TRIGGER TWIN -- byte-identical to @keyframes mpv-life above apart from the name (emitted from ONE builder, so it cannot drift). A baked fade/hold/fade keyframe cannot be re-triggered in place: JS restarts the transient with remove-class -> force-reflow -> re-add-class, which is UNPROVEN in Coherent/Gameface, and if the engine coalesces the re-add with the run it just cancelled the restart is a NO-OP -- which, because #moe-bar-root rests at opacity 0 under `both` fill, leaves the bar permanently INVISIBLE after its first appearance. So the JS ALTERNATES between .mpv-run and .mpv-run-b (MoEBarTransient.js RUN_CLASSES_V/RUN_NAMES_V): consecutive runs carry DIFFERENT animation-names, which the engine cannot coalesce. Without this pair the vertical bar cannot re-raise for a second battle event at all. */ @keyframes mpv-life-b { 0% { opacity: 0; transform: translateY(20rem); animation-timing-function: ease-in; } 9.68% { opacity: 1; transform: translateY(0rem); animation-timing-function: linear; } 90.32% { opacity: 1; transform: translateY(0rem); animation-timing-function: ease-in; } 100% { opacity: 0; transform: translateY(20rem); } } #moe-bar-root.mpv-run-b { animation: mpv-life-b 6200ms both; } /* ===== THE "LARGE" SIZE MODE (mod_settings.progress_bar_size == 1). The mode is delivered by the ROOT FONT SIZE (MoEBarTransient.js SIZE_F == 1.25), which IS the rem->px factor in Gameface, so that one write re-lays the whole composition 1.25x and correctly leaves every %, em, gradient stop and derived background-size ratio alone. What is left is the CROSS-AXIS (screen-x) lengths, which must reach 5/3 total and therefore owe SIZE_XF == 4/3 ALONE on top of it -- so every declaration below is an x-length and nothing else. Do NOT add a font-size, a bar length, a tick thickness, a vertical gap or a keyframe here: the root font already has them and restating one would DOUBLE-APPLY SIZE_F. The dash grid is a y-period on this bar (0deg == "to top"), unlike the horizontal bar's 90deg twin, so it takes no rule either. HAND-EDIT 4/8: the tuner emits this block under `.mpv-lg`; the class MoEBarTransient.applySize actually writes on the body is `.mp-lg`, shared by both orientations (the SIZE flag is orientation-independent), so every selector below is rewritten to it. Do not "restore" .mpv-lg -- nothing would ever match it. */ /* HAND-EDIT 5/8: these two are the emit's `.mpv-lg #moe-bar-root` plus the shim rule the tuner never emits, both scoped `body.mpv.mp-lg` (1,2,1) so they out-specify the horizontal sheet's own `.mp-lg #moe-bar-root` / `.mp-lg #moe-bar-box` (1,1,0) outright. The shim's width is the PRE-SIZE_F quantity MoEBarTransient.applySize computes before its own final `* f`: V_BOX_W_REM*SIZE_XF + V_PAD_X_REM + V_PAD_XR_REM_LARGE == 61.333 + 70 + -8.133 == 123.2 (V_PAD_XR_REM_LARGE is its own literal, -8.133, NOT V_PAD_XR_REM*SIZE_XF -- see MoEProgress.js's own note); its HEIGHT is unchanged (the root font carries SIZE_F on a y-length), exactly as the horizontal block's own 500rem twin restates width only. THIS SHIM IS DOCUMENT REM, NOT LOGICAL PX -- the root font (1.25 under Large) supplies the SIZE_F when the DOCUMENT renders this box, so 125.333rem here reproduces the same round(125.333*1.25)==157 logical px MoEBarTransient. applySize pushes via resizeViewRem -- do not write 157 here, that would double the factor. THE BACKDROP'S OWN LARGE WIDTH BELOW IS A LITERAL 90rem, NOT V_BOX_W_REM*SIZE_XF (61.333, the naive *4/3 twin of the tuned Default 46) -- see MoEProgress.js's fact 3: 90 landed the backdrop's own right edge exactly on the minimap's edge (70+90==160==edge_x(147)+MM_GAP(8)+ MM_TICK_OVERHANG_LARGE(5)) AT THE ORIGINAL SHARED MM_GAP(8), keep it. Placement has since moved closer to the minimap (domain/constants.PROGRESS_MM_GAP_LARGE == 6, not 8), so the backdrop's own drawn edge no longer sits flush -- harmless, per fact 3's own update, since the invisible SURFACE is what actually clears the minimap. The surface above is narrower still than even the trimmed backdrop (125.333 < 70+90==160, the SAME pre-SIZE_F rem space) -- that is the SEPARATE surface fix (fact 4/5): the surface clips a little more of the backdrop's own right-side bleed, to leave a real margin (1px to the minimap at the current gap, ~2.8px to the tick's own true right edge -- MoEProgress.js's fact 5) instead of the backdrop's own flush zero-clearance edge. */ body.mpv.mp-lg #moe-bar-root { width: 4rem; } body.mpv.mp-lg #moe-bar-box { width: 130.4rem; } .mp-lg .mpv-backdrop { left: -45.333rem; width: 90rem; } /* The strips' Large flush override: right edge at root x 10rem (== surface's Large right edge), left/width their OWN literals (the surface's Large left is -(V_PAD_X_REM - V_BOX_LEFT_REM*SIZE_XF), not a clean *4/3 of the Default). Per-row `top` is a y-length the root font already scales, so it takes no Large twin -- same as the dash grid. */ .mp-lg .mpv-bd { left: -115.333rem; width: 130.4rem; } /* Large per-index width overrides -- right edge PINNED (left+width == -115.333+130.4 == 15.067rem); same specificity as .mp-lg .mpv-bd above, source order wins. */ .mp-lg .mpv-bd-4 { width: 195.6rem; left: -180.533rem; } .mp-lg .mpv-bd-2 { width: 163rem; left: -147.933rem; } /* bd-3 (preAvg) Large no longer gets its own override -- 2026-08-17 crop fix. Its old literal (left -82.183rem, width 87.133rem) put its right edge at 4.95rem, ~10.1rem SHORT of the 15.067rem edge every other Large row shares (the comment above claimed 15.067rem, but was never checked against the actual arithmetic -- see the memory vertical-backdrop-narrowing-broke-the-large-twins-deferred), on top of the same box-relative mask-taper crop the Default row had. Falling back to the shared .mp-lg .mpv-bd box above fixes both at once: right edge now correctly flush at 15.067rem, and the WIDE mask gets back the room its percent-based taper needs. */ .mp-lg .mpv-tick.mpv-end { width: 12rem; transform: translate(-50%, 50%) translateX(0rem); } .mp-lg .mpv-tick.mpv-pre { width: 12rem; transform: translate(-50%, 50%) translateX(0rem); } .mp-lg .mpv-tick.mpv-proj { width: 12rem; transform: translate(-50%, 50%) translateX(0rem); } .mp-lg .mpv-capR { padding-right: 8rem; transform: translateX(17rem); } /* HAND-EDIT 6/8's Large twin of the new capEta rule -- byte-identical to capR's own Large values above, same as the Default pair. NOTE: as of the icon_gap_tuner.html per-mark pass, 17rem is no longer capR's own Default (15rem) times 4/3 (that would be 20rem) -- it is the hand-tuned Large value reported by the tuner directly (see MoEProgress.css's own note on the literal-vs-normalised reading), byte-identical to capR's above on purpose. */ .mp-lg .mpv-capEta { padding-right: 8rem; transform: translateX(17rem) translateY(2.4rem); } /* HAND-EDIT 7/8 (2026-08-17, corrected again): current-damage caption's true target is 7px (monitor) RIGHT of its HEAD baseline -- the maintainer confirmed the earlier 7px-LEFT direction was wrong for this one caption. These captions follow NORMAL CSS -- increasing translateX moves RIGHT, decreasing moves LEFT. Factor is 0.4 rem per monitor-px (1 rem == 2.5 monitor-px under Large on this maintainer's setup). A 7px right nudge is +2.8rem off the HEAD baseline: 15.733 + 2.8 = 18.533rem. */ .mp-lg .mpv-capC { padding-right: 8rem; transform: translateX(18.533rem); } .mp-lg .mpv-capP { padding-right: 8rem; transform: translateY(50%) translateX(0rem); } .mp-lg .mpv-cap .mpv-ico { margin-left: 1.333rem; } .mp-lg .mpv-cap .mpv-d { margin-right: 0.467em; } /* HAND-EDIT 6/8's Large twins of the four per-icon margin corrections above -- SIZE_XF (4/3), same as the shared base's own 1rem -> 1.333rem twin, NOT SIZE_F (1.25): margin is a screen-x length on this bar, same as every other x-length in this .mp-lg block. */ .mp-lg .mpv-cap .mpv-ico.dmgp { margin-left: 1.671rem; } /* 1.253 * 4/3 */ .mp-lg .mpv-cap .mpv-ico.moe { margin-left: 1.180rem; } /* 0.885 * 4/3 */ .mp-lg .mpv-cap .mpv-ico.mk { margin-left: -1.667rem; } /* -1.25 * 4/3 */ /* Large's per-mark twins, hand-tuned in tools/dev/icon_gap_tuner.html -- literal, NOT the Default row's *4/3 (0.5/2/4 * 4/3 would be 0.667/2.667/5.333): no test in this repo pins that relationship for this file. */ .mp-lg .mpv-cap .mpv-ico.mk1 { margin-left: -1.000rem; } .mp-lg .mpv-cap .mpv-ico.mk2 { margin-left: 1.000rem; } .mp-lg .mpv-cap .mpv-ico.mk3 { margin-left: 3.000rem; } .mp-lg .mpv-cap .mpv-ico.battles { margin-left: 1.384rem; } /* 1.038 * 4/3 */ /* Animation timings for the JS (mirrored in MoEBarTransient.js -- the VERTICAL keyframes are identically tuned to the horizontal ones, which is why one set of constants serves both): { "fadeInMs": 600, "holdMs": 5000, "fadeOutMs": 600, "totalMs": 6200, "slideRem": 20, "slideEasingIn": "ease-in", "slideEasingOut": "ease-in", "tickDelayMs": 600, "tickDurationMs": 600, "tickEasing": "cubic-bezier(.2,.8,.2,1)", "deltaFadeMs": 600, "deltaFadeEasing": "cubic-bezier(.2,.8,.2,1)", "axisMode": "mark", "windowN": 60, "topGlyph": "barrel_mark", "bottomGlyph": "damage" } */ PK!'1QQ@res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgressView.html MoEProgressView
PK!Ggg;res/gui/gameface/mods/14th_ua/MoECalculator/card_border.pngPNG  IHDR@@iq.IDATx!s0 o o8dd$`&511Xwڽeh3OrҧOr1#ΔSb·I k;p T@T)dɦW;FWʿ=7Ommd \]*#P/qi0`M|Ҭb=b>QNóOrgOZXħ >r'fX4{wO '>O9ghK3a> G*w_y/z̷ghr4Q s9n1\a =usl0o=c~> =0ǀ !;_//& 7q`6 1`ԑ|NN~Zb+YəUwڥeT[ 훳D*=Vu;Ugu5r[U}9Z`F9{?{9EkIENDB`PK!vTT7res/gui/gameface/mods/14th_ua/MoECalculator/checker.pngPNG  IHDR~IDATxc````c# C\tIENDB`PK! Q%%:res/gui/gameface/mods/14th_ua/MoECalculator/tooltip_bg.pngPNG  IHDRlE7 pHYs  sRGBgAMA a%aIDATx][:re$`2 2_UkrHߤu%>bDnǯr 0Op^q}8~ݛ?i|q %,0y}?.}\͟|: 8PHsǷa9-wڃ,4Nw@{9DysiN2煀4`t>>ޗ0P,|y584vq'(7i|9Ü@pr{ā?5 m.!{{",mt|\O9^~7pm1^hFfo~O HMֱ ׻IC"a8[MDE~@wJ h7)DW(&8@$W*1.YyjiֶgM^f#¾jo%NAgY9ܿK2>vmӴiubǺ~ &Oe[a:eiF eH4> [8IFh Lsbr+}6F6#siA.VҺnwfZCv5's#`=&{oJPIpIӖþ\ ˞șx>lXz6 )]!* .{3_y4{6M{0yطC)=vL!E_{ f$E工A;n IwN|<9OWDz |pTVx6KvV7WQ6'F~7&0Zhh]x!< c.7".N$jg^&y` s*oj4Q ݹ):ԅds? IC#[Lڮ8TR"n|ہO>C|+Y̓{dݞ."\mi6~1tAtm62l9ܜTlmNf)5L)/_+Oe9?:P7ˍP iLxMcWyPj9|e4M33!Wb%Eܒi_GC%G1sDRRlCAs,˓px#H!GN[\iʋWh%a6˥ ]1 WS?5T-vUf(i܅oLmh[:@Mi{)zmۊW%G4VH'_Iuh52ypX&[8~C%o!Ć TR \]_9y#r䆫fU[+, KACҮ)92l,Z]HD 4oɟZ"S<{2cx$_H n f#7¾hCR4;m((Sȵuc"',煼N;Mk'?Tc"R<`LWl(Q?[3lC^Цz>'&l TF4_`DŽO}m( }٧CKnc8yP& h2x+n}yK%=/7~TbBvԖw˳{Zaj(lצɚF+-<侀 mrqp$A-C]}'Dde_߯MSöB2mc^EۆúN.Wp"iGAMJ\i'8M+-YL z,BX5i8KǏ&4atyöh2p ^Stj.-W $]u^ڼG\P_͛ .~;KCG-PFxUOKIƋc:W 6_6=i ^r !Pm1D%[5%#~C%LAAD[ƷpM ]%hpO2l(t%x\0F+YMu|\&}HC%ǶY/O&,כ7 yԴ&=~:(L,4D-F S>Ry=,@9lVP..'S-x4PvNmhrjÆ@ZHVZk .mJi5٥~?s [EUmꞺ<t~p&%c/3ՙ}rb"F5wiJz}~ TG4Kӽ׀3<ǵIjW}*Ca)&zۏc{Up7,i!er10O5O&"$⒁ 1  g!vdmJIAY5ѸdyȄ:pk.c^^&8>^M '6֦77ɔj )CI3+;5y(ߴƵi~4ptiYͯ&i4kJmHkǔ&>%)ouf9 MIwOi\Nhj<7w!ߪ@mVæfi -}W]L2;)-FWF.hh di"`R6 |1lG?kj|R\+Y/:ZgrvPҶsH*VNǔo.|1Y7?[d!S]8Y@#釾7|'hehpvSVgv4EG6;r BhH rB)v[߸_gR-"S$]>k5p\7rO Vxm6fM/%RK_J~;kJ0f>$4*B3!OX*wϕV2R̞I-XH^)[nop,^p>)H-v/EӠHI$5}6,y%Lw^\91NsvTHõizq[ҳ7MPR<-*UZq Lա'|QbYf\Uhs{ iF%G$MAhqO܃Pd*YN 'N5M 0J- NJء}wkt=:y-1!-=bAsTSm"ЁV85fY$oR;%Jk-^,=أK+P6h؋FPPfLXjG)Jp+P˾Fo!Pi8eL*6o g)&V&z&?IY 9l(1/sۧ:Mv$ѐ 6ȓȅVjSsSLeѤAI..͇~jF[mh(.[) lTu -1nx!jNI e~ nZ^Pҗܥq ]PSDx%m[Z(B4lS(A+rKaC)0zFH' _CM2PӴQh/J8`&FxxI)w(RUZa1jـLh$f^ք@mⰥP.բ): 312/^"fKB6[80%qN$hN!K)/M\T)ROXɣȦa2!֑d@>ܴ'捤%eE:NB6M+V7ii̡rړC4FOxcwל1]}:"LfI.i!R&s+^)ʓ¬r\l6S]_C|=K<0nAA VHO:VƹYǥ§z9 ZPh?1Et >l^ 浜Ga#;JCFr-oKCB!=misK[N&~'5 >K5Q'mؐ6"i>f J>ƌLhL6tS\)M7-q%YM&JJ Lҥ> I +9Vz6i;8)>K*jɶrI-\66%(\IcvIL'jbx;ej#-gu>tNP3d.ڦD63 ye|μ¶JC>\Ama߇ XaKZmCd}H$J),L2_ lo&Jk62M#NT Zl';^@5hmHЮЬTpH#piΡm S _9m&rU`([Y}Zo/PiܓjL!ڨW܆ҫ イh j pX"Z\n25fI/89a"A[^M\i E64esWṟ;ǵokVz Q@mAIzYx:0%`2IuhjؼOB&sMt{uU {ӴF }貫_hZSK!Vm?ƣ7GJKK.:YyC[9@øHشQ7u696lƱEL:1&@V|R5kNhMfʓTgӑ.zluem>i[jR>)p*+FJUƠFa´`>ǫ}ґjntl䐴4JD p1oVS坎3a5YA ʐ\!Rw1mu--BSk0J~,Kn~m%r80[Ak %6W&ZQ"B&a$"5Hx8[4um<$efdK:4m̝Ǩzt tsYzIdMCՕWOœˊ苸.&R۸rfHdHގH8|Ð{]*z6=i|SX׊[nxJ5" yCtx|zEjwS/Ukcmi!{2kwI8YuS)F`hkv dfD`2<9&F"lˆakn#I[KH<+C[ߋ ;;5 ;H(њZ&2Mɮ:p-c)zhyWj5- B?#FL xl.R|PaW~ғ[5 5Ѫ\O[d[FS/96BR[WLmЭ!l Z@jԃVn$ie6yhIh_]42yǷoM% `K: ٍo($+|Wk'^"B7"MDkIZ/ea=H/ϵW}Mzߔw̄vHe=#<7E 3x~.m'ohr)hHpCi:il$[L"?\fJˠtR?D⩰-~C~hyr?M9`-3D=-=mBS^m&̾9cc kZ=qUCĔD}~ OA}Ӎ4_)!k5x\[!ԗ"wy7NEÞ&)/}7_i m…/[C*OP2 w4L %Ԡfz']h!6तO-hkY*c{W0}Tn{Jwn+ՐW Ws>ή{mr6рCmȵ7䤕T @r'ws-5={ROOw[Dr>4>agC~Ox{X՗ƫi5'ڭɟ>u% 9[ZIj;5֐x8öA#L}qI.9'5nxGj먥KN~ti.O : [ykaW?-]3|<ڂ7A?|'45yN ׊4\?`%^e#{+`>_y?k!S ԜMyxiΦ<wu}}}7q~[}p>-'Svv GrJ9r,|-?~>7=@>ۛ1߃Ga҅2NEϹ  &7o[ uqn]nuw)/|\{:s;~Sp8.i]}aa϶|c,{3 az\oKc4wvk9߰oWЎUֿv kIENDB`PK!?res/gui/gameface/mods/14th_ua/MoECalculator/tooltip_divider.pngPNG  IHDRp۰sRGBIDATx]E#(!"^y?Usv)d&ӛnjzuhx\I'ݽ @ @ @ @ @ @ @ @ @ "ж; Tf,;mrXa>'{~|[,FY,V u ӋUWVϧ_/Y}_l]zYVX&߬׳oX ppE1z]vWk>],F׭^!LnX,7jxUV]ٿm~zUM~PX}]w4{M3gr|u=|zQ)^M3yljcU~zg}^Ʋz8޼<+OojW*ԼoKW^]8;,l3~'n#PӇUUduz=uj5cIՁ۫'3^9:Uӌ7aTTzklWVWUX]YaT=W_. y}*87z}S=ۗS}\}_aGb? Oy7A޼Ieg90>weފbm .+ οz_|ȼ%TO87g8 ̛g[d}v /d8^O8g`$@ @ @ @ @ @ @ @ @ @;3mIENDB`PK!nw''Ares/gui/maps/icons/moe_calculator/previews/bar_eff_horizontal.pngPNG  IHDRO aIDATxdU9[9tN3CI2 Y"tݷfwkUkOb\ (9JarP9pϽ'=3/TWUsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9 / G/= pjL !Dp.FR]^''RJE'}%AAAA9@dH$*SKn)`( * DnBL1<<_Do2 (G8,!5arex$5m}ɞ^Xф+UP~\(BI8/bsAAAœDP *A2\p!۶-Rcc^Ƥ@c9PBl-BpaϠnr+1%͑L$$AUP6Qhuݥ;"WB(>&˿aT! 3O\CQe`} m۶m|8zI+AAAdaD'2FUB`˸!%"l۶l6 ѱCѓ hUӨ('1NT4Bp"8zeq[ r@֍%@ 0 q0F`&J S57#PBذ+ jh!r2H" P"(|<%{ॳ3esò6MAAADQԅ|`P]*/:@@T+sΝt== ?D`h*cQFn E! 9g²-˴(1bPC iTUU50$HiC*n q\@`jؖqlnZ*ܲmS)lp P+@: cD.Als"BTF8) Q d\mYm QTBxTMgLA bR"HIGJ@)p4auԦeلXBQif)   Q YI4b\*Jܺuk\g__o oӣ\.WƎ;ʇJ85jTf*3we%"LZrZ-ӿ< 4 ӲGGRXçi,( ‘𩧝zŋ/ dllld۶nyam*BԹ5ۆm۰9&9En"seT@`L5FAԠ* !N>y5k֬-T^B*yGq. 0mR6& Pmɒ}o~[DQt)-aF>CcwBRsmݺu^7?   ȑ sxǜH AAAhgA'ׯ -Z?[(\fj2S ^x8ײ==*-}@0~5hO2֓áѱX_(̹͛ΙS)\>Mיz, W^HB񩚦q1cNJ93>T-tyyF#hSN9N8{Wcddd̚67rU 5|@g#'O>csX,_bڋ/䲯C?k. RN)pkBpIOOO    G5 J<a-LF-[ֻ|+W<6͎L:=1H L ܢE|׮DUdd |,mmm`o_w___h41޾# #T*=6c۶BN OFc>]C?z% 'W ~tն7D%TF$pYg݉Dri~9^_ܿnߺm3a-jB[Gc?ˆ '9@ Ldҕ'?ͯ oܮP! Lh~#22`!fAAA9YPI8K,Yv sA:=1>{"ޛZff2}RWɄcoYl) U n >bD"\ ]588xL[[[o[[h4  kRM3}ViTڛh_Se+V}Nq[-g\n3xzN/iT_e(83_ַ^um[{{"=`)!ywJtS!Q%{k.]z\.!I'|jynW"bq5zi'~)̓޾.-_>jsXɴCgN5Sd   ,dxxYZ3KR5_(dh:9+#t3FjR/*cltt,e˹|f A R"o@sC P0'zz{X, {QVr)&rl6r݆yh{PucW~>E>Y<ؑ俠0kd"qy+l / ǟxĠgddx7<}vڙ__L&3M';8U ~PJ6tj,9# u= _ڙxomCZn1!RR;:SOnd2" !@eY\1F.MAAAAg'@^r,eu0M=~?@  LӬu_8NB2JŲ,O:bi4;"4-Z^tiAēb糰\.WTi/)0BP4 F$}E0#@1dO? wɕRb9'N Fd F"N'MӃp$Czdu~f&'`(H$쌁p?08d5]xIaTLӬF\Jr9_*rL*wbZּB C&SK ,$،) "o}}=p8j;wxtDaÏ%de&HLuP}橧V\t]=}α{J]hf8QʊNV1Q,[(†!K(„ KAAAfA'ݻ큱l()/drV! P0iZb a!J,KZjJ^UUඪjDD[o__d2('>_snU*0e=woKRT6굪ep_=7DV`V A 3aQ7|>raD&ֻsn E IGwpamNT!Pj5x@gi1åEj~߲PT?cV&D,f\,o_cCiLZڶmA!.b CQMBp)p-n2gB   rT,cVrTT Ux!}tGpnW*|0jiڙL:+BPQ'~_h'z}/^ ژjzfFFR[nIMe |ZZi{ˌ{(LSPq78?c L&<#*A!]CEۼlSY*s[٢U*"D[| ݗtë2F(7lÑ08κ.'@ZSOI6lAB6 -JSw:T BAAA xR,,-We3(aCމߧu]H0cLVź#X2*fRk }HJ-8&tBUZ9˥m۶m=fҙB6)r:ض V^y ۊ-To<odxxύ7绞}s,Ii73m F(`){߃cG)DѤfN1y5jЅ"膓N9:u>16mbA LO>ij~O EѼm@(rn[*!Dڒe˖w,˶ uҜG#B4Pڢ!ܦZPyraQB/J9%`   Q΂ORT @_@@p8Bv(cT,j^O,KU_W򾚦Q?#@-'zzjPY^J3év޾}{\j,*4)S=g[!>mq!  z Rh#Z,:犂uRSxO?瘪嗩*(\e1US\QWY.[R) uk E(׿C@g'#(P֘2UN ; ${c3K  EAQ5m2/qB,B jBhuPކQAzzzAAA9XI#`JQ,vXi%b0Q.sPygxdxkjddhj$媕jJ:OaUz!_(ec]XKUU\.gT޵sXPk5˶LFD 8)NZ!$.d\Q{ddxsy-}>ͧRXC%Nb2̠5+aYڙCUTdBA`cs"(H gTP-ذS[6oۺe !#p"XBB(52a+3} ER{?׿]0VUUۦBU0 "G?   ȑ̂O@XCJ\.Z^W-|>WV+1Oijb*&LJX|!_H lX̍ gB0M4-pXQ֜ LC(x:ιTm۶oO޽;&lVPJyvN L(SzzT}C.Rl!F%CN78EFQ"|yVUlY{qǾǟ1Bٱ}jZ#RQ,P,/~:088atٲ~Ww}-{88Xϻ   rœᑑj Q.M0T5nirNRcccR\T*D|:-0TAfr gmnl6d3\LPC&OՖ'@^5td$ѱѱj_' `KzjX&0L@Yf[-2\aߍ48}y>V I* v!%FP&R`d !LXʳyN= J9T#7 V/N9| U. 8#C{ٶ0 K e &)0~ و0hiX8sz'4[e᡽{tw!LpN8q!TYRIwwwyuO?s9PWUnrQӲ9e!   G!}RqK!4E\OӹὩlju6-vHrLwHJbd2xz\YbWoUL>B@ѡZ   r#Oக1T`2CvpH)(zf4z4 îƍTK`^8HPEZPV^@IV5@xP@L`Jl˒"2nB8ZBDŸ8涀rk<7NdՇ'ESBNSc ,0\Z/(D 1UU)~AH_i4 \o~YlzDzbb엿ϸ%n[5ӂQ gXDXC"R*{KYN)O!˥)ʌ%}~C!D ɐAAAd'JIAuD: h,0{VzA2VA8BTQߧ}= M˴*e wc*AĂr4NPAxwȺǎ{㸠ι;N̩8ִnydDpx8Q9N?(,i{*ㄨLek)7+#]_Jm:OI(n**UJN< ?}+a& [I]AJVo~O?EAno' 5AAA+H 7i=i\js@3y"N)"+!EI ?͸tsK.%N^R ,  sw@?p6C4 a8 >',w띧~ٳyL]ZRЀ&b .l~MrZl*5Pc,SO}rϖ[ooe۶iZ>cu{ǁpJzc QBPʁ>IA6/'5MCW$CAAA(xכhj* G¾X"ѓX߿wU__Z R:,^jrT**+ !QYX#p8okKvuu/P( ۢHQKR!Ns|b Qg y;2DFņ#Ȃ4"Zst{_/Eɱ[HʸP )i;RQ'G lhㅗ7fZ**?OnxGRQ0$ֶ,8NĉL\B[8pzzzoWW sя~p DԄ2Q rDH?J؛:R@"Y &1s~W y/J   ɂOhX z8-^sp`"Nbn]ij%[*2Ba"f bZ,ӄFzݨR.b)r?sn>]XZ-˴4Ml*\V *meŇ?JuY:*l]dؓOy)1R2&Bdp|"T**cʂK,Y}eo*g4޻nJ*M+\!*FHFH2<(+m,Y6.ܹcM? !W+S@]v(s]R4up`(an@n ')FP5Yr!1č   r ݧH$ wuwF.\Y b'eUJX,frl&I |R.MӴiVpwJ>sl6;|>_0 wuW ep>=JB&*Y,<YqGFg8 {;uwő3JimB892YGVcRĐ&|"218|K9M{'=HMXh2`)P ` &+ !k}ιdbbb𻣩]P#MF@.3yDV2ɂ%4$P@L;cfj2c@Xe @"fzASAAA9X D}Dc1m?hѢ%/^988kc@R+Bt&+ jj2Dp5%gxB.OgCFcݡD nDL|@  @^HVe2R*C9CRyGxw^2sDi(TA! JS9sHNjAUթʨPz?O8|Nvڹ,J9!E] m\E "".u˥o=O2JM tSL*\X*s˒JM"P?c>я{gWWL${vzT֙ 'x[m\8"tEAA9YpIoo2Q'dOO=p8ҩiZRkh>_OFvd|6_*5ìp $PE²m*T4F۶-mLUwTJRLdY6TʖLè,3uCIyCՂw(m-ѓ~ 2-~HKQHmΝ[{- \s;"A=~ 0ʉJ⧄0AM A)[@> $ Qt'\u[/n_#K. E#Ħ2@Wn+1b)B82@0 3' CPeYYKd+1v>=dC\zAAA#%,^8POѢ+hڶmJcc;R=ccCLTB N@(m+ՊΤ @eR\U%QHĻ;1ɀ*iڴا~aӦQ B^yx311^gyj/!'l;dsra[**†:C Rb,CQ̒v(_s.n)Pa<q?D [P[c {e20J B J aD3KںN:{`9\߱exE0)Hw   ,YBD"׻tppXUU}PFndA<ݹk׮vڵct45効\kbneE!zflT,aj@ `0XTE0xXpR1 @ L,WQyTFTJ;Y8l}FUeJeDQ4pόcYW_\}/͕ r,\ UJ?=8$8j5cɧp)+Sf7|n~FRͅB!՝i= _gޛΤV^vƍ$'xy4m6|O   ȑɂO4GjI&W/aAE1L0slMRU`(howē@ UլaUӴҎUV\s90@ + B8ΑuzP g4}< eij,3[$w*J)wA!k#{{ښh4}\ urA{m-]lL.+^q±R|>s[-DxnmKxTvAAAZxbV*vXb6IOLL\*ҥb1S,2Lzd;RL\,6p¡ ! γ P`"o Bu|l5Db`0-|>73l&=<<KZ^ y Qd^H `+`"=C`MUt:EZ@TJZ Cm#[vBڱt6jU^ RL,T,1>^rrb~Be[YԢT1\qVlB"g(tK};vܹGyܐ6#$/ 5Kuns(a,Wqif`?~(66ԧsl0gB(??ˎ۶Y =-T NAAAbxٳX8ꚮPI3b.k5V[jն9h T =\ 5}a,$^!N D@ 'UZdjR"_fZ;ha$5Zƛe!f9MjcU +jWWWY(0 # *B,۶df օ3mPD[!HSfEH2! DP'Q*>#o|YbڹDMFS=M7?eE˲l#g?AAAÆw>} ${݉p"j> ZTVn&7 CFldJPA2iA0 lıtx (mpggW4 \1ɔ3L,w!I4MUujBL RF}BTA\ࢮ" HP1gDokÆNo\'>ѿ{g¹],۔ՁBP4 T x#x$AYCґk"qԉ! ̱BO ј㘰%q^-8d,dr[Tk"M0UdЦ3US{9sk_ "gϞ]C{]wlۼjsjVeA&èAAAy W}~JMjv^՚euucGܡIӚ{[Q!2Dn8AJAAAda cI&p|LUqK-[E_\mMϽu˶=ee& X\ MCMAEF8'"LQsDI ʼn?)6bU3D/[,Ii0u5D8AJ7 H6.    |A0#L BSUQ*0WꀴĖ "kAAApœÐʿ2CƊHoYYH(xw(&   r 8_iJh                                                                                                                                    K yW$Bݟ!…R՗{AAAP 2/z 1F%B\E.WlbtlAAA9@dOO@U]D%xby-6iX 0AAA9Ad'jF5U31TFu"O@0L-i٦iڦiq۲    9( -M&3Og>TUJ(N9&iZUð5öLîɹHa   r,LHi*}`}~M52*Pl˶aj5|PWVmM~AAAAOST]3M;~_}>5fA5M졄$t{4<rԀA\}#deSUө~VBUMר14zsYAAA9@D!%QNL5>ݧzBu!OJ!P&FAAASPA^ ~E!7!1lrdA\}#\^fDӴW+qi}gE9>JxKě) bND@OaDeNhiCְjj~!MBLUf1ůڙ]KiU UM!)˲lA) m2mPG@L'R>_x-iǁ:n|Pǁ15@ou3ްl {g<ؾ1{Yg4F0 ZsrNu?p\?pX50xߓ _Yn9>q;gw;0|tpu=z'2I i|=FLJ5?|vCJgMRcҌ6N/g{8}k<ؾ=ώ,Oꂧo|WZxuo]rsKՏ75޸{bX<->oZ}综f\Rilxky& S?nBKkG wajѻHh2Lq>>kv\}ddyS,omd4StM;<_><~3v>S{_<^lxj{~;S`ϑDZ{" vGfx;ddʼښ3  %39" oܛ~Nܙ{ξts\p=Ϳ/x>|]zw u,Q4yKso?\,<7{{9,7/k-_<_0ͳ}huǯyRfߦg5.OeybϽ^n^~#`qyxⵢΟD`{ Ov?;|F,|6kTHiT@Qh<iEA-)uu*GO6m}9r?wW<>Ϩzk[LھsU]h{/}<~ ' fP 4F/d`>:'8SOi,2ٴ:xr' .SPǕE&[ϜyҸPW65L rgޛ}>y۾XK}yr;]qay2ðۇoAjss^n5ƾN 7Tny⼚?\nAt)ĝXJSO~1oE`:پ8Dۧ/>Z?lox~jϓ#ۇȋA>C)A}ydznʌ|/gJD!1(#QS5t] }z(bP[<\4oj=Rwl/rbRz4 4 Kضmٶ-8wRKcr/WO_OO1WQj"A '&# o9z'/w{dYa#+iYi+,snYP~S(a`$=`{G#lr`@F*5ZDVımn62Q7g=\BQRh1-ܶrd9rA\}#dSub KFvV7jڬ)7Rat‹mC   xhUX,Kc !Z TʩV+FV7a)?`J   rXIOȌ$*Sϧ3@Ч=~_uMLetaj5ZJͬ5Vۦe{xAAArz&PlJT!GQha6=iZzݪm,[    L` 2+d@cFURͧ32jRB lŹiuL[2-1Ja   rX 2'ɞD1Fʈ2JJrBaw¡B%+X"W"   ;( " B2N%ӡ8BX+s14EAAAP ~ej2s{s(\沁x1z& Kz}pG|};[ 3r}_Xu sM==@ CT*T~ll*۶RC9rFKNDђ#Yk81ˉ'njn1e&}tĜ)/gBw:w$ } ۰yc^5ٞ3 zQn{v^7g7O/mozgX?!K}}ɲs?5[, /?21y=w@).ǠO<ÛFptV+0]^@9*]!N ˋ@F SR/=N`68E7{eLs4CAlr<ʽjn@4xA Uy5vܝMvBXA^"=Yϲ=٫{gysZI(7eE#=VZ5 R݅BN+b^, GTGm΅`*r0x5)jA6b U5X7-@};ώ82=9B=9PP7>;. w%z}(5!$ƛӕCps~Q-G;o=1>>f۷N. ox)/ =u_MA9rGG)Js ')SMц:vo9D✓<:k֬~{멧r^__`0,ٵugn[nwJ |>;R]}GݙM}><|>_K|ϗr5Mka;`{8qb|;Ve1 s{ddd?# BHlw8_>@OI.җCy<UU'۰p4M$KV [^޾4,v]-[dc C`׆a3a"|uvaf֭[`N;m-,;zƮչF_z|޽?ˇ?úyL#aJ{{{d`/:BPs I$zK畱XlY0 uwwXxѺŋ]487s0µc?Ҳ,sf2ԧ>ևFmw>}$x=GR}>_(DBP, p[4]h+ v'>馛nncxxx~/]o<묳^@ :xG4mP( Br>Ͼ0wl4b1;ǵؗ]k!yGմ@'LѡdrDk`0_h7%jO3t&fs|P@nj,{A(`ƻgl1sFdPn/+cMHYO}m/׭[wgSŋ:UOZ7nݺ%yI' ybοۿ_3nYcNqozի^u\F@o_xc%;sύ]{݋Str.fLuP?O7T?3/^zi%z˗yjkw~^z´&!-.{õ#Ȭ_m qTaP(9Z֛Lhoo !J(c*0]wl; $ #1"H<ٱ8ձ{{[[" UJ(B;jϓd;{_WhίO=iQ/ Ї.r$z׻>q> ^ϑB 5F)3MS,SgnЧdp>{Jluzfe4MQz/mt u]hob1_43B+N[d݃,0^gr;997fgh_]z/mk,`PKvlKdU'xrn+j\.gfsYb͠_;4 h{9_s-]';7n|tK`k r\=͈zZ\SDk>CĊQYbRVz1J"~B H?а>eR _p>v9|ob9D1s{߻fC$7^tVE]tY>?ZI. A/H3>_u]gPX G"j0(=l9P"/8M20/!YT5Ӵ,0^uL\AxZ¥MFHlE@msŶmloo! /~%x{+r\nK_ `{r21111ovI( =x`rGW9Q1w]Wi(IJmZ.|L) 04EiJyz̓ܨGehz'd[CQgbɒ%?xٺu˶_4pQY~ɠ̱G7 -ZL&oݻ/ٴoشR3;sg:۰Y8W򕧃{z.袿)Ս7|绽0cݺu7@ b JRc>]JHܧ3 a9y_ELQE`(q_O#VN=S15=Ͼ'X|h0]Oo|x_WWMvh+Wx3M38L?|7-o뮻nۿ{,<@N`Æ _7szMQjg>u7Op!u+W'wlll=yϻ_>D/zy]|vE[o}pu?Zjj Um: XZpnoy}ȐJ eFi@eq!BcDT ֪5T,uM 槊}5=FphL;Pο>g;_q`휾5͡{OOyc1,k?8@_Ӯgu}-3I=vU DъsHk Z8K.MBX~bb/BAFG8Բ,bu (1 #S:z,ƒdgT*رcdxx83>>ss?N=ŧ~ФD"a\pi盉4D5gtM3qtRc_c႑' c*Jozjar|ƕ!cTbB Ucp{[[, q Gh\Kp#Mod>200Db!uE!۷o/M##P mܸ03666sΝ*,'37QUE!5!D}>95kxA èy]S*rB*vۣsmkVQz8jNqҢiϲd] _"d? Fa "#4;Y:@BMCx,z19j59p8w#0cZBVSO=>~yLԚ#>UV܆anBxTog}yv[bTd̑' !^; !M|AhǬ_ L?{կ~u?l_W].U؁cŊǸDaJŀY0,Jh\e[SYm,iuR_jj Ƣx[<m3EZs"OJȲDK4s Olk?@b~{+Wv]o߾顇z.]=wx`1m tE"$7|}f4Z_ 188~I'׾+u^p/oD"AhϮxpA"k;'N_DJۆA?):NzLsRt::˗/O|ɫ/pY_7׼5?3[reO{GB^z ~i)P~^uXF⡇zp>g9k֬rÀ!Bkzm~,[ߚ` r#G(^{>Gy]w"Byϖmrl Z-bHDLoka > ^r\^Ouyl9E@lW0a0m lڸ#O<ģryEɌ;gq~pH͔ ^BH"6o,|>_ppp`ɾ契 $v*ۍ5e.о)mafݶMSS? nmR "#D?ŲlӶlN`c`GuM%~'*C|eڡlȩ~88ۺf۶m{ƁJB@]( U0SՋI/r҆  mv*B@r<=O~4N^OVZ("O`yCCCcο>?S0D@|? /v~9W\.WlGL%"2D C {MI\1s*+#a% C0?D쇂iFi L_0>juT.U=(W*uhIx"m˛3s[<蓗Z&rllle/aƝ OkӢOս'q%򷾞oxA eB!?.Z4jbm{FFFҩT*djrق`Vjj@m^B,Ӵ!2Eu. |>D`2lZlKH$}PE~H<iv~1222O>7?C,AvgxMr37Rz,ÉZ pmo0>xo2OvX˾֭[wg`0v߇:Ν;B!Bh ikkۧd۶9S1(Cޡ^V-]lS'Ӫsvof2kGQ04_*Tj\NΫP`] 0&* '@{U+;\*kPۯkϧʣp[4Wk:4]JRrZE#fC(D[Q|xTTJr^ar+v, ((bs?4ɻ#_Y~[^(4jJj5x< / {w; &5::A`OOOӊeHJz)T0Pй9p8mtѱ!(#6-Bg!= lيB޸`#nUj5Ρ6[P6,Pt |hg{[,nv\aDDp ]Λ7>~R\VB x!Ao-[~E?ucTxb>wF#x=G$~+Qj5\.WWڒKׯ_޻wݻٳ{|tthX4bP(pLgj^7L: 4O&{/J${{GmKt\.%SѱbVA̯-F3p}+N;cNj|gy2gfzb #=vܹm[3!g/v"GZ5_*5s_#9( G$nxq8Ly'ȆsV7d2 sSjX<wXu#u"˥+D* ~(f5 z]>\F]pymlLرc 2gYbE3(v׮]_4OŸgX<_8A=oI__hmڴi#<{Q 6 B:b 'tw; 541001o7!B SF^{aZ\+`Q3]W󆃁H8ƅ(k"e^~pZߧxͶm^*WNS#iH5mFZ@N_O@ ͺCu}>\CkZٹUn'Q>wY&vԈÆW7F-qq߷y!򘗊%]C{/ L#}H5#,ms[u(J4 B|LM p(k4K4T' R|* B(~TeJ$ < UA*0&B  P[[,^EÀņExoEVjms.Qfe5?,<=JV9vƛx`i=NVp^ݻwDyqwww2\ 7ccc{ݻ{֭{.e۶m#BDzRCUU\ ͼ\.AcX`ժU9Ջ/^H$za`^jFexxx޽{n߾cq _|4XQ[nQ1\zuf oMz̿]*5Jwk5oy׀tMr$XayH8%8FNLY ՔNŒҰ"DiI;` (͖vGe89; 88Ι[5I+8N':n.5?28d_ve6I-[FBF@җo{c|;l T*G}thvAFZ$˻knx-_{a |u'<u&BbT Ñ6mnWU~=OP vÍ8|oوg> F!# πd4Lf׈Rgz3NLw%0Fs9ox#/~K> y}зMRcysjfaw)UUd|0ʒ"V!5 '/ X]״ $L)PUGĨTkJ&CA ^gf) hP0\7bS|iBSa!N?fCtE_Ca/^2 3|O5k$_מfڵܶ/;4;*|<u'z tI[ч~խj9NC5ƽbф%K.]x HX z~WWW5ktftt,߻wojΝCiɤs\,,^{ٲ-Z쥓@dhhhێ;6oٺu={w=NE}|>^+|7Gڵkˍ7x. 7@Df )zޏ<lE_Z5&w&gk8e=м$xxU5k3T;d}c.@Kj;@oR) tR/KO/eM;r ˆG{Ιy[4K*Gb1w=w'_\qh'-_|UV7B Ͳeˎ=UUַ{AGomڎ'uNg,}#3|6O߈F#O|nk: ;ĄeY5T;[8Lj*7LOgkdZVBA[ ` kfydt, .qQakb<!ygR-Uwߤ{Nq-^atܽؖ4U z8s^"5(2?~u&C9:k[oL#3l|~H'dϻT*bۼyscuׯ_?~'`: >>===mV^-8{޽{ ]vJ*,Yx'xBOOO rY=O?c>۞L(m۔Es}oƍI&MwCZx| ʣ0ppe6iӦ';<9D6\g9fMk BWJ>]+%::#`P,d`eϽ/)7Qf\{w637p2RO20dlٱ6= D¡D,Ybr޹wdxzڵmnX6/D¡d"P7͎\\ݻ+0I2Emg¡@g_"vDH~~ir9o|s 'b]w? ?A|G) }C$<>DVtzELg5relٓ,ksX k; ;@V8vuuu'޾t&L6M?Ïcp4 2gǶo߶m֭GFFr.$*qۻj>#sιQrwy]nłΣ Ս)7Qxǝwޮ(ĉf!Rd~v/{UkXv8Dx#[p"t=6LV*aFŨx\ri(/vtPji0NY4jkcc VgF!ko}L ӻ~#U.iF0#,'3!{G׭[wxP/mS:a Z:^\'2%Ns4\PF6&-X:l۵Bw*H Ҭ  K);TLr<@vrDpROç>>scpYF&?߉SN9f/U{s7b9`cSkbi4QEþ@ ZdnSσlۓPe[jF˗iwert"z,W\ .x: zRAb|C-zt|}^(|C+qqϵ./誫ZInᆟ('#"Gu᫧­C0Y%0z+m˱XD C0" tţ@ Le7^OxV}喟IFYޱ2W8җD (UTT,m C V*j8 -7 vT`H$h4OF'F*jRHSXR@c1fS(-)ܺrk^FX||(Kxq(#OK/tQ,O>$#Љt9XdHY$N$-pS6,=L>GP~xbRHJѶl }dW= >9"/`H+[m7rw_/~ks)O`ӦMwlb;wn馛s-!fI94mF۷?}"*Сz'i 䱧''{h}s1gtaF޼c xnZf&_̍e`JP3<^(WTՔX,Hvw':#Hȧk:SaGg;ā >?O_| x7ًĔN8 R,x,}/|OG omCg@Q2&&& ;vlzGx'ݶm6;c_Wyyqq+^&Lv-Ϸ1U@(DyowkܟSN9eM?zj-fGa\4Y$#Ywb?'~;F G$ȴ4z_ˡl:F$μ ry"Ղeq~OScP#E#zݨex{&^jxCK׾xG(38zm?Jp|Nr{Mz[[{#O?8mWPLCֹRV?,N,'FFv8SH/|&/劥z@á`##J !g\> wX}O#p8 UȎgvsi6BpK_ҧ/_>M_?7q~H6pYg.>f2w/*#Ն?2}6ͣfwI (rTi38]p"Vܞ={F-S(i (0(]"̒%KOLL6mza /lڙ効\Tq( Д[;г>UM< ~s}{~ O{+_ʳӄ{͛7k3(On?uE4-u_p赣x9^)x';)6 ZxPʥs1B 7 Zh8>]~af83LE9IfG>򑷝y|?Ń9FO;@ XRORP9!/i `\Tʕ||b>]Mھ u7yP*s1.D0M^,Yw㑡Q&^zۆiaZ|!?3F4JPGG<&`=ɠ7Ty2c;!2>uvOphrI!P(4c43<쓴nx=?jHD 2REUX,&O=N=s!Zd2CCCL&-[ MὫV>W1@aɒ%+XR{o顽{ R(lXg6ѹr_[,3{t 7<4遵K1ϺvO#:P#\΍qF`d>gXNM|nΎxLmG j, c0=x3)4D4<#)0W#s֬Y=pumsXW;ӟGo'd?7+ws$n֋'翼"FfڋiΌr"_{ENv7NDޛi!]Uw:)5ՍXz"% h_A{nĘӺy(^yB0垏8dLa#r3\*kyL@-T]qF/^2д}- aiL^P(lyݵ ~_Q aH*+og<+<¶ݝx4k*hfӖ_g WeYqXMDHDn+i qj`Winenop\vܹbq|>>d,pc 4v͚=ײO|̸#x=?+=R۠ǒdlK,]288$ ̲,EFkpggg<o dD ܹk8ٛ^UK 2Ī4L=B8@MaAb=aҹ"-ӢWf_%kZ_goBNL>¡8 OvNBr: B>φ;_}}}Kf A\W. ?im[521Z :fr$GMUwǣx|m.eC+v#`ii|13:ǢesF(1V֔Eg08" ۶7|W-[v\O>?|rji*4rt, L+#.C;-)ps sXL2O@vd'no*yQ6+Wt馯X,*1y 0M^E^hclPӴB0(k*M"~Ptt"3Z,%u]S*T$QfR<2:>9tw%PB4=.+pL(պmH;o%ϯz3B+!f8 m|ߋ!9Y~-$ߚO^'z8U&kF[<x, x<o,ˆ떬~O3e rxYv aV,S9[Ȗ정x:7:9W BDQPJN<>q%EKr0iv)~+{fa.7t>O?pPJxS.q`w'bp؂};MGͿ_K,rS7ܧCc=== B =dI`#sDW]q\8; ^En6 :\+0'TƋ %E*J) 6lJD6?(՚YV)1JOe FeYvN0jժ׮]{zF7@!晗A qWdvU fFguֲ{wuuu(_t`fӞk^>k0n|>myu_[E===] 7VAZ^#D')!XޢE0ټJR|GxБ,@⑱qG¡L$ *dDw'B6b+x&Fm- BpcgFT:m'G^KJedlb㱂C Ā *93sweْܱqcM!N /$@I!& cb܍%YV_mi93wu]Id׾;Ls]?s̾Ub/\kv>GB9Pi𮮮a4uD۶m+Z/—uM^˿Tu}¹v?u!qdbi^箧ilѢEg灦Kp׿ۿnF5D8O r)$†'&&Ƶ?%f/^h~nnݺ)WAXׯ3|^Bgq^{{Omddde|?k;v8aggg逸7Ft!y)5{F㏯3ac׮]|>[RZVUVD}sy$̴sӏ?㴌l6;sO^{֚.zֳc~zG43g(1p}P*wuOWnv0Td:cg3du7ẍB\,&ۧI1 /`d"A#z.}a1yxŒD2J&r0)嵯]K;_koNzf̟p ֭AgUV$߲nݺfO|W]\OzMBAu[[[jҥ#TbSZ 7==] ]G6lذ}֭Sd.8o?P5Fرcyt*jZj宮vZeYFp>D*dL:m۶0CϘK.\?7ML.~Yfv裏>p'QUk|#;o~_N}V_׾}}mַ~o{馛xE]6Mozӛn9sׯxٌ9>uO5!瞭{֠sp.ϝzO<s q@<,RD#V}bXy%WiJH(*t499]f|plA`ʫeRN˂@~X#f 0dq9?ƍ\D xVz=7=\.,ȼe/{yk?GL)1᜻q߸{G;XW5s:W>K/=n|h͚C?SVw}q^:Ow}WFΚ#%/y+?G}ls;+fϏF-ރ c3թf"Nvgzޣ\TovFb U)x L%<ͤ]ϫAH6ƷкRKT\ժAVs Og2tu~xA(gs\sGa)5m˚5kv+N$_~~[գ>|׋֬YG*?#'xȫ^\DPCP馛~޲\q群5.^Wo?WtI^Ν;{O4?"ALj ~_/~F{ ^[4?x_3~hbbbGxB]Y~ w\uU}y]m;9,Wkr^7b"w~@ 'ldPyXAU9](OOJJT±- |۲L&PJy̋s:55Y.JnѠMhѢ38+W.hu=0 CfY166V޸q㶝;w$dB$I2-J{~[[>AbNJߗ_kKE*~)xp5:x:묳N~^}>/Znuv0 Y& ]M:+p@y֨T?5ֱ'xpJfnȉ sBQRSܲ4,UA vHHjT*es)uhΈ'NHP1q4̐>shhhd {7pn%I4a+ 'QXҌP3]? d2VNSdݪƯȜ A ׳JqX%cSnVo$j|>iwKԽ=y/wN=Գ[:Ngmi#wvij}mӦM~̸k_MW^y;~7mt}/ZhѭuO@{_q=AN*$T-K~PLLiwa(YZNcd(8 3Kdq>9lo/9M>}k_&\ti8bq͓ⷿXsX/}iIWA)1\'+2wJu||8==]..vΝ;[l)l=r务ŋS?Ci>H$,jږ-[Oŋ4XB|>OWŁF16I"eoA*.@N<ēt뮻~].W~\ LVvylgj?7]uՁ\kdG)>ܽ[XH`|JB9&Rjy)(JƧCJܲ|-L$ 3onUF aSi˜"Kw]w7j$sg[nuNq{l &t8pBFu]wIn}}wL3ږ/_j҉.8mxWi7q{MmxI'RnʡNQ:t&L$T)eLT.Z^(J[}r六lDs08hh=6Ju5xӦMs%놊w{"uiٲeKt~eZݭjƍ7q tٳlٲUs- _7HiVVݟ'ٟ?';kӬR?)ghhhgϏ ^{Ϟ8*H==?p \m/+z)2I;Lf bSZ3JT̸푟A{Gg&Lx)Vtar6JQN>& SuO}:9Y\[;o}[ws=7vD替oH>jxu.e-[Lz뭿喛o뮻z7nذamۦ7o>^޸qSO=5F_nC=鮻|nW՝[n>GW<٣-Z5bLo;wҵeΗwD;ξOZch#D㣮|t=OZGڑLfFFz}vfSj[ny>O}oxo +GpIuUקIE޶`h͒VtofϾzcD*cX J'LU=jV.W"j OR08P;j}Cq.:S/2$|'m}`W e>͛7]?S6qbm,Y$ƍ6lʞx'4'ɻkMG%K+IhśYԡp?늹œOe˖#\|m90uV~ZH'86JqG?+V8U.wGr<}Ws&''\Ѝ/~կ~ 78o#|ի^˿T.;wnԧ>w/_׼;Ks~7-+m{6Z^PJ;T˵94bg&++պ;i;N=kӹ$yxBq|韕aAJVlL(6L}m G}l\5hrkk^rɋ~T٣+sP;*9UӻmҌ<2t7:T9;::R4 vG_Vdnjy`&jS9}!dk' Nw}Jug+H7;Heָ~qqG*%6ʱ$ILS-Gt*t8n'n>/5eTMj6Od7 *1_/OfsMbz*]݇/}K^|ϧ-z"xz¤|PߕW^yօ^UVꩧmٲe^8:UўgcS-ϴwuvvuvv aiƙݹm-ۨ^KeTn:s=CR[m߼~ÆbE\^fM%\N;t0Om뮟tIj^l}+_{X(e||y\pgdu?oG}tl_/p _,ZhQoݺu-[ne]i_ge/{%W^lٲ''')zík h]]}==d2O,Ruێ;ƦgϹ\.ޖy=VܰaQxˈr|>ўho"OT*I '֭T0H_ <3,ˢPyo?R4Gϝ~_7oc a16wEҌtNRW_7 o]hJjׯ7kry$ă-3U09\`K~54 ˲St-X4 4/:]Lp'L:t:eSes%bT)W.UgNfQ gTe!,tnZ9OV\yj3{>~Nȃ%ڍQB9m6`~bh7R ߟ M{m泧+nqT*NwSV5ʕJ\IYBD"i ;N'rLRZVjjPRc OYdz iޛ W\qW5\Ȭ~knS^nVX6O-/ʗ2)MO]9St lL9J&d*HLdJ0zy Rp[;v?l.p:* U,Rt<ѓN$sɄ88dfbujztmav;{9>_b/?Q'5]ysL9K'J9$\uU?׍,fƍ~Ώ OܐwJk-QITDvg=T"<>˕Rð>dv+fh=tH'!*,ϧp:as$<R5JrDݕkX0=Q'izE'xb[[]kSGQ@JGT-+Y"OC4]p9hPmΦ闰۬Nm뵰^Ph"-"i>^xqT^wuʿ;jOs@8o וq:k!kF+~ EaqO1LSʞ{χx>v4/ρTy$=6gh3J}D2]纮\زe˓SSS{P[IiF OߡCq?v 4Z;3˃tP@|'ข.lۡӐXm\&9"kd8ݓ5gLh)}w:,[6ri{Kvmqi?ʉ6gfdwfugs;,^dL+JH~9tùZPۦ(fy~:~iϳֈ 98֡qIroMă "RLS#@M>c}nrr:T3>aLǽy> A)0kv2d[jЏPK-JlL˫xrtq1#y<.ߌ61d$xhJ{wG'76}DV8B>'$t[f/>oNthh(7<+vmԈ.l&[HC5Xnf?7k4vkOZMr KLTj~Q@uB%y]=E?'DznԳG&}ܚ|n\Y#{Y =p3Px 7hQ(}\s70홀pӟSyg~KbLu,YΥɡ=r)z#*wcqR [LfF헲oӳ[ɁVyWϦ`gRTڴgk&l]v4m~4 hP=F؁j6@ 0G8Sz6g>x$xb^ qV4qb>, XQ gODk $фZb1.(*+ >GWD^4Ӓim^Som8&фt Z=f1!l#4Ww >#QbG-"]Ĉg9Y #fvHeM_m+)5NLP"Q?ˌV&Ob}M$Ik$"RށxHH*1$NX\+,<7MHHQ$Өw9x8Τ"AwqNL"7:(h4sD$lP¶ܶn[ X6w-NQGlbGZPH T> CP|&U IT`*$%Eʎ}h)n aY f[ICк9v NbXcjDt}H3Bb#R)p#ln K;HCR̈́|<`%Fd)U(=i|JI SL 4&Dzi9$, f 80 a,H嫀=KIbJ@[)I?R򎃗6 QFFFt"੧TX-0>3E^E\""$-蹼uT*c%)+H Fݕ;r~ -GIpN[)Ii+LD(RK4j}*W }F~)z:k-)2>+B$R¶:ia;2#᎝`It3(T98QIc9( D@ܓJ5t*Ԯ&#&3K2[$fF;kl;FaWj@* "rh=HĨ$%(,,wvTG,(ɂxxC+&%WҤ(3YЊb6-Jfv^_Wۦ]#4[R,ᘀaQ2 SV%hb(Jyts.C Um;Ӊ#r϶%\kxATu;w엀b yHpZ +SvZd$ ÃgxI',^xkԎ;F'GDŽeaf5aq[QA BPE~8l?}$E¶fY6O]o􂳞|.Ds2I- G)5Md06h5$@ bڻn[}VF${JbW^՞i.C)<%ծ) fA\6}-e|Dn0m *gDB8YaUO\zR:r:zbzqx9*]8- |FTb hz궞tooaV*_A*t$ YxiDD TeK;j*5²)G0Wڳ9#ٝjkF*W؎m;'b&(UV'H;ifD`?z_}Y5 l2U_Ƀ{?R`ɒ悓fBjV6HR mTymbi- z_ @߹jbKλE}=[-;!MYg `b?Y+ۘv_w^f+\<oZ2lQ`5:h" _S i<" N=Ԏ#}#KbT)VR\)Z+׊~^ E!'$P yR1R"N(rLu[$x*SNR;]VccTT6?eTtJ؊E7RuH:ifxk.{Uï{%g7߹~?+2\YQ^#LR(seޙ I/ak 9͵)8٭R=m˚(6 JagB1))+ɳUy߽ IJH8Īkh͒W^\_}CGOT:cME hJ5m )K,IgYgpp0l+\b B0](MO˅hIL'U.6VTUM(xrНudbRL{f]N%oV|G=ߙ^RV ;GvttmoϷ9>V(֧)Pe$b,;ųvKޜ϶gweRԫ.zK˺R"CeR#چ'$7T})4EŇA^&vf *c^ьRg2Ot9dY²W p__޻f{ޜ-d.}M}EhS^CL ɥӧx8d,^8Ϸ%:;;R#=W,[z3WA7 Sۧ S; röa]SKEg5WQ4'F `&g1a"OWi2T===Կh`dhEW.^\.Nttteڌmvvpc{'Y25 M' "iW|#̬ ?y?_N W*J0&Gp6J WWbltI0e4(v$QpMBT9?"^PƲʲ&e'ɓ!5\NXDI\6P*F_ 'gyjqr|ztTX\s  K$0_t祓9Ejkur`M粁}N8VG)I^-_)YL)($Ua  )P:ZQT83u't*%Dqm93mSSŝvyz**kRbXz6*N&rm\W=ۙ]<8ҿxped&oٶe[v <ѨU+bT.M&KrQskAzs0*wY6_a2Q(dck]q ]mmMO^뷗7rkW~GEA/?؎jڕ따qF4n[?]8u8sۆz \l&BoLʣRwS )еF5rGl(7&B؉̘T2K&S@'=2)[YdR/UʆdJXD]4ҶLG{::+JSӣ&wn91mllαxRxu*W"O(s8.lEa-Gy1RH `Ҷ_̃VȐ\V:uЩ)'2&Dw RŊ1"FD:Vd(WbD42!:VJ^",!iDhz|cN/bqιMl < HQ6,P)L;\"i -nPs}(CPaYځ˶әT&f3홎ή΁!- ܪ^ݫՊ驉-w;jѨ"x^>QOdsYC5ZĶm;_ |j71%wbEZ졨h.E}(mD&@Y&i I9E<5M44sl0c$SOFC휹N[vJOlZ{)NNsDu}M 'wn*3ŝ2?J!5 `*qNfwNo+ܷ'"{PCs2 Fh՝/X}ŚOxx{y `LNo_<;7\".EզV 6tjm2:}hv,m % {Z.I1P^a Cesa9BXgRO-4hBe.|ӮeUFXs=uR%dҖoxcPKz1hI3qhNB~m?bI ʡd_oSF191+ΦmYRFDC.c/PiJ"MI8R (O „$DDKHA]NWjn;TlU+?]/M*Z/j:II.A*( )۶x[/UbyPJRaP*BU}u(w1(Y¸+$LSކbQɤ&02&;$'!,aD sΘCE͜lt5/9ܓ.\9_)`bƉ;A-YC̸]UDNL@DyysD: O[BwG +,&ΆKXaN,]>|ڡ֩Ƿ~+yh-'iD;̳(p|pF81zM셰xS*Ԕ>#kn!m)ˉAؘܩz/j(Cٚ;Qe`RPZ/ei4TEWbԓuh4RX. bePV5RE0v.,5')6_Fޡ =oRu+-9S&E0m Ei~ٳ^}NG{ި?LU! U |"iĕl-Lɮm3uB :6 .xg6zS7ݷ^3PJRiEkDQ;^L! }mo\Ж6DpP NIF @b 2%m̤-|f9$2?s6POW  m)+I0/ (5f?3 ]Yi="*Rxv=V!z͹27Üvr[|QKR*/\߭5WijIWIM* ei*͐*ݔ(x @Q&H NHocF'd~BfJ(&,Pae-?w|^'S;׏]˯B)ޠ2C2P!1 !;H6p} g})ѴN210Qb yNEymuf3yD6\7u|V:Ty,!'Z; Ck_|+~l \ 'd-1ּ볷J@Q Osd6e'۲a<8^x8$q+vRܢ:&T;LL>(t+W]Vcab%l۶( ܊<74 znCUW]~\ =@:ԚKؖ6el܄rCM ,ATVbd)6: F ňD^"FH %\s^^.WR7{kڤ t"NțBk(&ObE AG9.̹?RLđS~ɘ"diȋ~k}Y'iDa(Q}8x8t@w`nۍ`2y̍6}DܗTui?!T;RʬS ;W%TKKDTsqOiAyަWҿ;#nC@!jКAuq bIfCtm2abD >b* !ئYT5( xX±&„&H6-t"i'VJ􎝰Mo;e[b^a^1Z[f5Q%_zcMˬD1)&:#vf|V 0J9W>VC^rr~֫*`5h_RjLhj:M>~_7QI봻#Ɋ$@ 3V-ۑoƋCJ1O($ԁV@Fii-r?~x['-ǚR?ytcbH($s}'H]'v-PξwQޟSTgF)aQh~<8^x8$DCA'8 QDU"k_-KK3m|V>XġGSZLیbl.E@5䃚aDgy e-PYZzܖVDzI3ň QI>[㡌\Y)s.M i xD3esK$,Nimbo/^>xbBi躉knL tk$Ehdئ,Y6MbITW8]:ocln :ksW/_?ߺA_ZSڣ(dx cnݝpsC=g◪naے1Į'ʣ\N:);i3""i%$+ESB?>SR%x5svN+<8x8$Dd)b*Ս5E晪ژOP` HD6Ke:D])1DKB7nGL`VmeKQfC_%<B*=0UUDZUm-*;3C ޒ-PO$OIƅzv6uܲq)DuJ_\xDQ DlbD(N"Kc*kxMp%k=5oTL2>'u<2: YX+im6ݿQ<-_5OL$0Ia8߲)+۟!%BL\f>L}66 I I&3ӻ!L ".ilkN;ɓvg:_:)}eN wn>#- U5 +C@%KdcB(ȣ%21`'VT#$\XqfKS`Z'N/XhQP6&uC)KiBcƱ06,I &%3!'&0%Z_ҝҖ>p!Cڵ Dq=hIż4Xv"Bq( ,T&+Lw(X 9Оyr?[㚑ICQm0)&t@b  "9Äa2;,7Ej&2%SB9F"qiW5#RiP{Nba4&%jmFBIT=9EI.Z(Hq&cĈDF6EhK lVlF#)+W:c'La'uS60JT,05-h¸\HeX 8!L4#]N6lLY,hZ%D:1zNǪw>|C*` RdfbE.4k#4ru+Z^_\%g~{Cq4i|M6Sw o@<L0;lNl>s١EKF ,lͦyKXznݫUknZ T\/U~+;=w,O 3POR3Ƕytwtt-[hoL*ۖpŒjR/˵Bi2U(FͯzAzJP(і*/r蔒L15N;ٴEv2 \&yX;1SH_{uQo\3I*X8j& G0(R6Lhܱ,_6x‰}]96߾[ nfR A( .-n9׶) L.Z[&ʊO"JO$rB&Gm1~C!]{[,rUhJ'0d "3[Z DUmDkWJ-3Qi2"2!BMF]6wHZ'4G&q~-5NN=$̏;2Wjx54^PnnwoS  M!d:IіHu /^<ܷhpPkzAíjQkR:]4 Kq&җnr C)"iQfD.:Ӊ\#ZRmD"ɥڍFKX)+lOV\Feڞ.[<4UH}<])uDfWfRv,*kL6՟xՃ >uؿW\ꐇRRc$%X)71~qa(B99dɳf%97Z*\ gcҬ ,\.Lԉ3W:i7\+nzpׁ$I4c~sN;?q`H#o؆(ܧ}GLw]@VjTZ1bu>w\m$} y+7X?>c\K2edK<2+&[  uwI[ֶmt+mOvw{G  wwe;Rt6}J-WrygaDal|4Q( zP @J((HΈ*0J<>=m!؍;'nkaC3՚*SR')Յi ɘ37,*VBZ \(&{=GNX6{97?zA#bYL~O$X~/9mwY|KbϺoUWu\ U "M ";*ccqb-i!|o/>0hg.y\"dioTy]i`Xc[]gS=KʩKJ6兮ezԳW`e{vM**B~#{BBd 'CFJl:S=}##KVd2v۲l|Z&wNض}rS[vjժWʍWKhLJ yzHBr ݪ] v_46ܪ ˙2l6HN*LҾ6Zku=mSkŭ*1F&@|׈)d . ]c%_\'3֐oH6#,Lp41Ŀ?GIiȜYm{Dk.=ZwTGHI&3xe,㴮(z`]P״5.'[}W=^j9ӤN\3Y9?S^tHJ\IVhkeVx8$ uɔ]ٮF zmTɝ6mrƝvԼ+_)3(GF)SrH2Z[54GQj{h+$kDw.hwjŔ0 P)_wz!YI. &sծ%4`Klqߊy}=clz4˴u 'bJX:.^<1ZZ;36' !l%sꊳW93ﹿP>CV iC'!P͔99f۰+h%zY'xbm9{C=wKAg < 7?駷7\@7mH c @<wL|^or^)+Ήt?ZkT˵FTw7ߺ}|j|T*A-1H6",mEA o{O)Q:Ye>aYvF8( =핞z^Q*'&&vLNO,'KrZn/U+r_,&"Ynxn)1 B6*:|ʥdjۧ~qꐪF3&>^hofrD";jBZT/MG ũbV1TWqMI'q(B eJMN :8dijl=UVg6zQ)&*]JZ Or\عy;vNNLLVJj8 k"cqFQƜURe:cRES`bjœSb<5=OiN{n:׫UGPPya٫^U]S2T?:dCQY*Fֱ$`0r--U9~SËYږ~͍vYQҮ>b|zuW~~u־,?_7,=V =] =*d!E%I;.8x8dl4Z\ǂLD"eۖ^PLKJZz^hTEZTd[tم*S9 k#fUlҝ+jeʙn/W˕bV a)F0%PN.}ū}NJ˩6nQKOd!u)ADzVXWpm%Dg(܀\Q)mǔ L%P|=ٙNwdںr RXx ?TMeEfhH)f9I8;mxINyyfሤeJ :RьccBQ2dLZBPZU]u 8w^o3L]Ҋw7~w_φ6PlN̈́`iyaYn1ђJV@WOyU3)*kXbTMp!$%NZf9wd/;{SV,_6KG兩 іvnߴ~zXUBʣ2U!&}@˔,%Y9.X>w+?k'/[6Вޤj{?r?[ؠBV&FSRyZ:<<#4^Xp 3م($T>'h \3n5)ӂ;mSzn)!Fpɇ4F@mlzQ)ժ~պ[սz5\?$S{wzn~ )\FUI FpRQ>q.%YnP,H![i<4G0 u hXcpUr{cw/]Urԁ$<;HD@1IZ5)KqKmX\%-KdB铎eob9(C$0[+?h C+`Tj;vl_]'KK6ɊV{JrWʓ!kP`)鐠Y4I'94Y̳Ѱl^w~Q.gؾ2+ŨfPCSguJ7TE;N@+O;XNMM6HQ\J:+*CI, E6hm)h:4"O`&$4 lS a]%/Tkn--Vad2o0qJVߢhJxm(4v+LZPUp,G[awbCXBP@Mbu[|!dW*IEeqn %/ퟝm|[ovzi7Џp"{]ZM,% p'BP\E<& LLOH'FJk/ȉ %c̤Pr*14=(nedYiGi,SiLh}-;$4Mډ|mi=IP1kDTǬ8e-cʄ$KWwѳ3L末b0}7CuE(yb":B#xD9qNdkDopa=(o_~ ĨD$]Pvm^(z {onLi i 7 Il%m )Fg >8ƜF3'$J&`^ isM^!$PĂ,O<Ǚz`,B)\EVT^QAh]cx23)774A)'/$n)FC! @I\0\3{TvF(dʈ F3}6?tE "~XvHsWD\k4vuV4W<ɻRb|5+^F!euׂ@<Q&Bsa SGPcs$HĄPy&5'orjե!0&L$X-P2)kȀը;Q$FPղ$!,Kn4g dJ5;24% &Sd֓6'ˉG\h=6R= ars:4+%ZQe(/ΐ2!>&%'0M&`?x8biLM$q<1EBF`|Sg}4=BJ*HIU)G"&H22:Amg\Y7NM=aJ9|;rT%HLi ˕]i4-CFD4]J8%,8P S)#++8r\7{ӅҎ~5"NB$oݍj715<+`š0Ưql 7hq 8D`2-m `>Ia[If5P 7p LX KpJX້'d|b'Ce["JIW:bc˄="O$Å7 @<GXT icnpM& g`s-.t =9.@{  !<FSqf"O0ptjkYvpّb{sގ=8%]#MdsjDEsCsyr[X#{a@{sfJ}OX)Jp y91Mq)#u0a-Y7)|NX/?GXA{?2~J>#f}1={DY={}8fOۦ0'&8 (|;1SKܵև|^G~d@F{8ώȓEOWV:I!Mew{~zoNK[>w~u~5?]#ųVPnĆZ>zWfܦ_<3h]^M?ZO_~]'T0<{=7gt5o ,pvN*Dne aHbڑkזT! UH!)ʸRXOIB9αo5W5snԷ17?ͯ9}w_[>mq<RΒEC쿣w24Iכ};~_B9clRoQrҸN^ eҒ;wg瞉SGj wܱ1'б8:=C{?wdyĬe>okz`|u~s,!`]'q?kɜ:={ߜj8~_LGs{?~ <9=O⋬=ӽ[ik:C~Y"*I<їڙ[czbz=왢>y*4_ c~;?DE'ȡ#tuD8ܳ<}/gާ;(EIi~9hżo݆fW4}~8~<9l7xo8hN&SUItv/|o|gٵ:wK_F\pNN',nYwV:穡_|遏43U^ɫʺ_V \eR:ԡZq5SjbFQ!H|@JconzjjT)[kZqqH,zҭY<"Nq6!$;BX !ԎY T>GwެWa(20n@LPC)IJ+E UQbPJbNHH L!UteD(hxNSdFk:03dh" nnƟGaƴjit5Ӟͳ2 M8$O9z%Ggޭ8ʲ[l)3 'H2=ӟGItN AeH9眳whs>5#US }< ~ 8.])N-4 L{fk77qB_Sts\U{#RPavjƣ9MF82G-6=ZL;vMGSvpHY,?s|s+>t9H:$4[XՖ'r\O\|gG۹sr\W*UR)Jt*J#Oq(F8i6hX<7ZG[Ͱts UӉFnhd# |E'|GD$:BPZf'=}ݹL&?::yÆ g?7߷VRꠟ|>я#?ŝYGk4{_57g;9+Vs^ !Wxg}z{{:;;hLOOڟo۾1Ji6RY Uőe-#"$ ퟣS4-xVI3Z0Ts@Bd;_^|om+ {o=ܻYkU;h ^U{:JR;wnݱcS??r??S"}~Xcǎx;_zݜ&D:g]䊡Khũ_wnVJUhG# @D?vߌ4gm[uϴHP:_im]4pWz_kמ?"'&&رc~+m =}=gkoOycw۷DRDډeY"ڲl=344?22lhhhUoo"eYȢ'FFFNMM,* ͐o&T:z }y׾_###zthkkoᆟ^s)x9׿BUu4xGo;-Z4o}mʼn}s`pd@mĶ6lnmmpU-Z32<|~ fm#k-]zŋOzWtvv,f3C6L 4++ts({kAx7tӷ׮]@;o ͏rns f;=ko;߶mۺ.G?ѷвq,GQJWWW~Ѣޑᡡ޾l6ەL&cN}˛OyU{{L&GLt钵K,Yd5CC+{{zQ_ݽPtp_? 0Xh;?Ookί~Oӹ}z=T*>Ƈ}̡'vt'I|fDkL&Zd!|rjzjjzjP(VKr=$ed!F!Qh'lnGc]4 k.ڲ& ,'>ήσ1B#H]uU^v|k1b׫bҥ'>EXve_׿tg_Lۼ {]Www[Q#"r,j:c.eGFFr\"aPe(AqIq3Ύd |-RT*+Rd'Y-D;R {%-|;Wm'yE]+zw\*<}x饗'p{,JOOOן_|mh.2{E!_WmO.?k_׾G4fr|zdx{ȰRʖbaP(WFZ0Wjo&,L&F,^s˱l.LNMMQ]-52kdZ1V*SJeP,u{?MhD2 kTԴ|;F;wKOYfK_җO= @%]k#Fh?_veo؟k˿-ld*Jː )҄-KKiBQ(۱ |O ;J1 eø,nk~Rf-p\r%k>Etpɬŗ0DBO]vuw-s_g'_;Z"5y=#g~?-ikwt/YӳcFrœg1{9?_ˣtt-'⋯EJ+t:/yKN>(Jk /sjپYnvfOkѻ2#HЇ>g=Y/ +_w}ّ1>*fNS{|d2jok\չc ,rَd2lHi)vwu-^ӳk3H[oILvP;+߹/7TMؿ .{{L(>\rޑPx[֏/?s7fx-Z[ ASN9>|X!fs=zW ӳ7Ne',&q>gN f2y˲gN>^۽{Wgg.BDaڔ;՞gL;iX;g?w6}瞳[ ß^IB^mo襗~M̉ܶm+$2c aA0`kJMz^IcF= jZa7)%h4D"awwuۓmmmr@׌f^{-[]GAYddž?k=8svi2&{ʹ֏| pGѨu$d\(m4%1m"έ0 YAjd ҋF6!M_͂LTLJ9N]]]T&u,>0As/;::z/rX,r@p./_L`jZ}rrrr~`K.D>kWմ=(i;:31ydǮ 1J)jW*kB%,iݖpDZiCyz̓kQ}6FD!zڄƯ5<y',[l??;;63;::NSNy6)| ,YB&W37D۶m6<<<8kHOI>[nA:6Mg[f g 't=|rO=o.Jq饗կ~?aXkמW]uw_G5V&SzVw-΃d"!,l; KٶEa4Lw]OE׶+HSl:I RTbgsn ;:o6>O|߼(7GK֮ZjwxO>O? _—ξI.~h{8Ɏ컪n&YUFBHBP (-/ۘ`؀myAX$ Hhîڜ'ƪwޞ K3}tݪ:8bH,ѐs|(TTeRpAR`Q0VEBD5Ec:X4ςsfL\*ZFtM 1"b!Ct@G I~odLsoW];gox4S߿ooۺu:q%^{H@hQߴ>sYڸ>dW1Ɇ ' TKVϑF %kXLI-[+ xY+RA眹Kmt۶8p`{d*P"Wu]gTJO&dWWWk\.۷oxhh(;>>6_gy撳~ō?/Zh>>);x,t_ifbbbT5xoMs15:3hkxA EQT0a#C }h]2&˕],25edGK&DR G F5ʡ\˯(MK}e+8>Ǔ3qQJ-Bw޽Jeʭ9U.7WECy D&|rak׮!m7sk\Bwq<3f`k֬]رqvuO>=Amw!Hm-=]h$VjTivt ꅚEdU)?(0_ 5Zj>D}n#ޖ#իW4 w[B)xTbarrʾCʶhz;7 'Lg|-< JeZ{\r}$B^B@@Zڰ2k۶( K kT%6P_WR3kNX, .X2KSL7uM\Wfʓ2fR,CSa?oM}q㉅ WZղnݺf>w6mhЮzꩻj>˲x zrwx|h07xq>W~Q{9y{}@%HrlXKNO?^TϢׁիW"KyWu.[bFdT m[w?N6wR:w(aFEXUhQ LZ:yU1F2 ~45-0fkgӴr\joaTRZ{QHTUTpϓ3_s#^jWm2/ o;ƆcOk eL;=5& %ޟoxA e.^h%K'ɶ=Lxxxrdd$fJ`4kVِokY,:]A]5 q%Օm[|e˖2ǰd2- ]J~/j D >3Ͻok% rk^>1g~9眳81gO?cֱ޽{9loα'˺:,S"㧪L=Tʁ׎mZ: 3Kbz2gFQ Sft~/L`M @W˱ݻ?N$Cz{}ۄrER;קH9ͪ,C2֟3M?l'RLݳlB }"raddd\^NkP`l۶gM-WWA^|W_orJŌE#ÆX:jiA d*TkV2wF(Fw] F%J+jRWإ<{,x͇G>)e*|i`HR1&0b}B! $ vvvvX_P5+ZOL@k>cxb GGBÏ=RT (?y.!-y (>HǶ%BQ5"a#Jēs v\H[z@zDp]ph\S`#ǭLڊlebM ]5ѰI%Z3dv,v Ç˕ !R l۵kׁ_ ‰iJENx≹ᡁGBz+JvTB,+lVY$i4՝ZdqGoo_WwwW;QST|I .Ϗ@푑ѱiZ-˚mw]^~oٲ|m9묳@Q=;wܽq`|/RT|<7M4ktttvr;!hF6`Ӳul s3jfhJ*-5Nd`G8?OHhR6m:裏~Dz\tᅗ6ٷo}\ Οf{/6_g~6?7<\_A /piOOhm߾c=v٪駟*$4XJ Ѓ0xP_  S(êԬ>|I)sUEtM0FcUU; vfZUӔqHB/Hѳmp4lTvU(eH:$ ]$xdʤ ǯ!/Yt*4%?֮]uWvݺu'x[n9acufσû=g}SM쿃Vi:PqT*9^lٲKt̾LG( u]vlrr2;::oiɤF?Fd~dt4L&K,m_|YߢEz/^N &{۷s{<8>99Y1PȲOLȁv'?ʫzU@Fx_iFw]wdq6ٶcv_. ?7+9<<|nwJK*GR)?$/Aph'MVXjkfBfկ@Uk 5s3c:N^,L\'eCm-X$U,U:R^0Y!A¤BGf\{GKsf˖-~߼Ye9}LQ1AW_};ai5@2lG? h!cE?$<}tDU?qH sOT*[CC=}`DbL dbD[[[{WWW{wwdv2:vddtr͏X"2_(dݳgsJ5.TQUw|xFIc`2Olܸ`<ˆͣ_Ɣ({B}75ǯ"s{wոY_ q /- /~^TީW8vնl&pNX,+Z' Hi( Xc%m\] 9ԾMomR]nm{4L'?#]B/f _~Լ _=Cy 7ooذ'p«mA,G<=5i,zdEK^oAFʋz:rB)G'C?>~?XygIh{~~j}Sf1_!dE,~Od[a@Zg9bŊE֭[f͚I"HG.C\v۶t]HDT\.ʓ\6-MNNsYY-JU)Tf.vw묙FfڞM}uٙgBЫ A{ѠdFgL6晹=q{a r\*% ݏ?'¾ok-0Zw 'RJomdp2_IF՚Yn!t2T2 B: sʹjres^Jc7FǡN \וUey%XV=T"uz3LD>ϓVZk6m=R|/J|4XGGGߥ{g f;>lc[o;1҈? KVf Y2!hŷ*xK3#HTU5jAˍ&"H8Ng =H$B##cccZRVXZBc[QAm) gK +baGT*C : TP"W]u4Xg$T*]5xD)2+>їԩG6eYz\)K;LJjexbrT<ٳgT t:{I'm8ι ^sE攓O^ ei- >v93 X|[Vy< ]|W4C=tTAnOO~R]f_P~[m۶ UR^\(i={Gr(]Z/kr}'~_|;tQJ`e{-OA6༊$T?=qZӱF_7bdPn`-*l!-+JC!=X4kok iZdlurRi /^Qw?رc~A'u >ē{'\. ib 6aN:%•'GC^YNiNd U)YPvJ%d"vV3A)&h*՚9+Jɲ>X4 T2 *T`P(Wq%L"p$'[[2L: RZl帡_-vw{ZR|1ɷٺH$؟Rmz?Ϙ"w (_T*L&mx<׃zZ6V!T* d2% !>|>Nb  r>]\!S>D\X .8wiM7dݰmv/yj_~ڒ%K4>788WՃs#8nAyۥx)O0xsj;b0D몼i );TR pxZl\*W 5Ӛt೟|f|VkVcg2wd?5qjT۶=/xV3T%IR|m V3bPE), %xX*Zeqۓ\.ˍ2#F3҉h=Js2̤Gös߿o]#Ν;vI8̶_Ȉ7q݊+6&wxL+~.=OuTja3LbŊW^Rbur\;66Xx1ʶ@IcP`:ݮ ҥKLLL n߾c׎R>/[ (<Ά}݌GGyD߄1ԯ#i/0>mLxvYCkM(rL?]xϼsy}ёw!DXipP.Js%HLQ5׼w}i':Gs=Sۻd~s)\ѡB 2Ue^{%'dL+ T);x"W;;;m=/K%i۶UU3X3;Z[[ҩTT*YP9R.WAE>(Bnir.Awd֮Y<BPrk*(}L&O_o].5 TOӟPJ?_==v)89ϣ 'ZyB< ?}Nmݡ3[woI%t*opMUa#Q^8 4(PjQ9 LR*xp.k}LY^v~3 vcuV(wIlsZ/Y^7b^GKfɉ|\.۷pC; # Ct]ꪪ5EWթIY_e[c!H$ jN%!݀Řߺ=P[yB)Vp? 0}Y5oM\->kyL@oږU:vPT%K86%Ә}E d2WдL[k=4MMBFJa d |{[3t*5X, 5]S ]R(]M)f)Sw| 8ǻJZ,E8yP\-a8\sL ab Xxڵ=|1ɗw;&iz"؟+<2{;a(]]]+V,ZtEF$H\u (e$[[[ST:加>߿PWwWb5k֬^ )?!V 4^kkkba4! Az0EΧX^{p* kS%g=,ڸ|0O<g|1e x)[=N|@M KA|9+WщAUQOQP IYpcAarHK`*_O<io}߅f>G O[NXUX BE67n_===KZJBXք`PǙ۫T* sM(o7~;S 2{Z fr%G'̤t*>3X9ۧ8vPʎO3z\&A%)l4ofU{||W| ؗ94GOqǧc_u%"h$ͬ7wv7kBaڷv"0郟vQWVZ٪lW*W0_q3蟧)Bru`dt@QX(4MKJae SVi C)щ찦kX,ڥz1bF%c"PLJJext|sooIw)2B*rYcGѴ ^1]a@[cHYMWOQsX, >''xYI7$'?G*~N"T*֖J&T*JRu=dKxelٲ}}C`ۛp{H6;hmmmA>HHl{{{fٲeP(D|P(XP}gn/8N g٥\gppplֱ94րQ$|a5G^`yRwDrX2)|[ʖU*d~(HrNJ8"0%**:>VŤI-4'\2H*`d٥|E .Xo7>1\(P}/8 0;18l }C'5Mk\7? WYtzn`G 0!5bdgggtHaOK!̣ z]uzSw6 :|2D UxqA"&U1Xl3T:z-+\aX骙NsOe K2*u]T8C{VOX^zi֭;yQԋ@jsmPGѯ-! 3k&,Ӵ* R0pׁ0lo9s{j4K_,BqCׇh6D`(!A*Zy<IiEBXRn( A0&##rZ3 #I%mC:tMU = 1 E<휱kvDy2W?P`{JkkF6|)1xܫuM4+r/xs_WW݃jU%_ND$eIJm1YBA}{=@*O R/}&O{wǿx+Ҡ^O׃> szG S@ݥ[^k[7r?_1D( wvvvx>M6<>>>&X"ꢾ`<tʮ];Sk|T8SN|IgܞeYՃ}߁9 B2Hi:2ze & 0T%]S=&kןpWfv)tv;9i\I'嚙W5-]Mh$bLӱ,>`5Ӭ D.7ђMNzg@ZBjnN͵fZ&'J,sBb |LuJy-+s!6Y; B+WvܹsVZ&3;66vpΝ*ZcI>=&I=؟#!D"-YJ CaHT0e8oaYؽ{`$KkF:::kV^ tj94442<<<]#BP.+JdkEQdx#H$L#1000溇3r_Ks} -fBr˖-Znݴvu֧ׯ_^Ge! Wz>wz_(~>}Giu]߹袋87n 7k׮- N>yq鐏=X|c ؆ ;odEO-_W "=PJ*z4IjB |6̴GW4{&qa[NƂ,'X)a^Ȑٙgyv33{ƛnꪫ΂LH/twyזb ȌȕW^޳>F?Ըfe?O5}ĄRjBm_`Q.W$tk׮]{ƥ^zܺuk> f\.x't؞Om+>+gAK.y۷n6|59կ~E3?A^ FU5򑏾~ݺu?3zޫOVXAPI.뮻lدO?rYg]Ҩқ?~?~5k֜vl'30H~ꩧ7Kms=g^=JX5;vƱ]8k`PhYlǵŲ8"kbZ*uιE,?ϞeۦWr̚Wp& B!# m kgySN9Q)ӳ-oy_?"׿ob>avSOovAX3̶ﺂXmڎWp\o²eJJ¡p(dTr*̀ 8[3-X.8S5t#jM/nNXd3?Cwޕ 6O<+op84SFm|NZdۿ7SBꭷz[k;::_ i?/_ܹkl燇LWo|c5~m4,=cyѻ/^q_~ȁۃU_;_ +Uȼ3UfӴZm)J2MZEa,r4vm0vldZvδDžzX,lNE+S3ݹGJ9ϏRsB ,MӡOTk&y9w}ﯺ>&Eg~adɒ3pC=P&pӔ˗wlLa#=8U.cccl6[&vHy4E45Z[[D2bE@?i>u]~RM6_,#O-OL9^l!nX;'K!D}B{7TF;AP@9R)P5G~A_=B.N")gۗ,*}Ta%Kt'i-[0c xw5{X,Xl٪YJ'hmPj7A{[o% N\L'L۝tÑP2y%UTsBxH${?dRNCo%Xk66_0l\iZtp86ڼrcǎåR)ylvb];{lV&QEZrllw}w9sߴg{Gg #(;f Vi*}}}`>:J<-;r}wlck1QW޿Q'y!emedqzG0UZZU55t|êt=oɡRU9#f͚Uhtj7Ƈz# ߨ gGL ֗YjI6l8YEo~+_iRp^݋}jf @3M__~./p }6l8g}!/}G]I؟#u wϞ=aqwЧ/Ue ,V޽{kwd2իW6lڴi7\&sJ͜)iEbq# )L6`;0lNPFX,$өh8_=f!m>y{ܴiӝ0a|/5k#-_|McləK@X^~_g'&&\3`go|w4 rW__s`R9[GFF\wuv%~7u|;/GԷ/||_jT,5<+jsQH$SCi*X{Z dbi\5'TMb K$ 8 bݢ9#EEUhLJaHIBh<|mCs뭷jrc]|a\?GhP%JxbZj"RRޠu$QrNKKKRD(@áW*{Z^=XJ&Dz蚦a#TE .|T,M艧4>;~RhPH]VGT*bT$GR cT %dj8cш͕s*r!Bnq$ϳ4gzW7\cػo馇[LQR2eop?GMō#PPHP7V 4-<0) ?X45MJCrP1|uM+a2fdx[!x`NK`oG؟#ݡL9§O8 x򶷽5x;ۻ :{n_Wj5.|!կ4}͉_MN^vٟuu?PxqsK/-qup|똷b=OW ~B|ܗx,׭OMfYVXцze@dJRLO{X6xP8zD"eq>@@ŵ=%ZF0ᐚzZ n}3ui;MRVjb\QE6MUef~^hQGTx㍏5S Q4ݚizA:k/'}P;Tdcd|fzXf}I?i(]:\zXB}4t1i$AWߧہ Rqlۆ@"4MS*<';99i۶8xP p^= #2dbw@b?v݅; K.mfxc㏃A^mX4X?ȉz;˕ݩCgf~s}wCEwuTr!{Y^Bcj۠kG?g>5*B_h#/w`]vx #"Ek&?4Rv֭۞O?x8:P>![>z}Q!ƍjH Tzδ^=^gK{ܐxP.6d>֔#{wi22H~Qx :@] 4G xEL˥>?j1rb]BJamz\6\ϳCx r ?cF P@yu@zJ.s(& H̵B3srpyXn5~ʝF;6xLX/d~O ǽ>4;YA^:Blʔ0. ;m8r ̣F şMլbP#ȋ ϡ@6 /!FWpJajAi"+w'G%7hyi\˕h!v~WAR3                                                                                                                                                                                                                                                                                   !/  b$nġQk57fFRj~|aAy%AA9LgR9BP*(!<&Hwe RjXD2OP*,.GB#zDpB(cx< =%6OLm.7$ yH" 0x  r@ P9ş6_jvubt JG_=` QaƠZAlG>oB$ʀOMp1:Xa!od\GFWV'Or?VrLAA - "R!QFePEjHA*"ԉ 8N_ I)C3TQ\\]GXG@!BޜHw(iAyAAy;2@ @!nD J"@"sHWfQ2" (eKCc 8A(A"xa~؜/=~`~E !_G[7q@e*`)V,~/gL<2>W)q̡nEp{ՇK8]oA OAAf! " *!#'LL'UE-BI]0XppeOxܓ-QM#HL89T*PďصT@Ad{'N`x׏@6GHd. u)q7E\Y/o  ' 7/Y,^GӍPP,rP 3_(R.ʎ_2d֋㗇Qee.JKХDº ԰a(d<ޖloikɴVʕX"_*h$]#ΰ1 ;ETEGȜr g͟~֮X>[\v;/㕯?o7;n*1` #`Z/lP&[d9 TuH' iL7B8ik7ƣ|Cg~͙']/~x,y*B) Jw]~ћ>5J,32tK_d.y__Ț̩OpSu(!B8% T *ST,WsSAd&>o2GbKUә̕lidbWu0 4EU|^'#-mζŽ=K/YxQ Bq4HDcX04Hmۅ΃h`0-~ǻW/[tT:X4/b3;vڳ"g28< ,ؼB<D_FYtb UUDW7G8U֬OLt(J吴CXgң 4jio7W7$8bi!J\T =f;@A^`AAcFz~^Q ruBX$I&VT5=.Z3e{u=qz8g E'QJ,fᰡg:::z;:.JP8 h VTDJtH=$Cf S15ڳO=U'~.i\Ufڬζ7_rbTf׸f1̃`@':@Rh@J5(5^xyT"1ƲUC&3M_U_{ɧx&p#(Ӊ^=m`>;+pxH ;xƉW{ƆxG=FQQaَ(q(.aPH~53 ,  rضMʵ]*WBq" 9ԏ`ii;eلJZZ $0]c2*4iHCz* vw,Zݱ3qiqZZ++bXg B\Y7T[{LC)ɑd-' sv5جjщ\+?=c%⟼Ug_,O\P Ai^cǩe_A.c'?Ho"S)NPXD5/մsrOoyVsw\r֪ p1`gk:qO<03UTFY1UpC`"ժ_u <@YF֬XE]Ƌ?G-N*zHi.Lug.ni4w]w1S(gL8seR4yoxjhFBHXP_@:6={_y߭P(E)5e*d} R0 PPswt07?G[R!E_ps5ӪI S&0*UBlױ]!R:lJ% G"h4Eөd5jkkIwL MT>.螃ã|P+WjٮY )=JȠlYr _L ~9H\@~(PtBFU^Y}H :ZJ!??q 8xe#8B7ԁ@ *D!AɰB!8h2H].H`a\XLU@ jR5˙t4<6982&Rb:hE`Q-Vm+U\cJfPYgt"7<8:16Y(VЎHIj*<rWxA~1@4i5"N #m:.a !`CpP._B.UP"FD[4u?|"8q!}J\U,5Gs׊]ҝy9']ڝ6t^Ԭwdtl~|㹔SƩKbA0RA`0 ϋq -zۗsO]l'W3ā5}X av f~ H᜺HsDUuZk\rIמfiO7l۶D%ONg?*pA!RC0)Eٶ ģ;.ܚiY_ϟXQUǡ2)RW! `AAcDd00: U\^1i4EhP*Mʕ|V\ו#QՀ@.'*gULO**%v|Z:zĕJfB`GU⃌)h`2`S $#2/PK<Q9QdBq 7~/E} d|#O?K 6?{ԟ 'P7FSS_Ap \2I,g *?~em5<ؼlzn 셠%BP` "/cD}ù?~ `a>WPܺg`w? AKc4e( #xtAWCԫ/}yܷ7NtuS.xPDRj}OA`AAc"nէ *W)hI a9W(k-XGJ5)UmbڞAvB SJ P$PJm+ŪskeS*Z\Z,&.x0Etþ<>m_"XK-/AN r "k@jnBz$63U~ǟ߷2NÆ!Sw_уyQW,XrF""?\~|UMU[7={kߺ2pi*@>/HK7@ ]e]G_m282\|.dvL]q"Gpޫξ'VRMbTQ#σ' `AAcBHUpQ؄Ub_ޗj i<^\P((˩AvQ*%TؐTՐqA +[x՚ZfĴ̪eۖi:esׅ)7XE%BSP< 02q3m? LGIAsE/d}r1r7˨,=l;a Հe!`yeB~ +7?[v )H HW E=@c9Ks22of(&%p%0Ted9tx B \|CO~{4c"-i|`aC%rt7?;;+Z[ڲ3Lϭ^FZ%o`#eR r;u <   Ljj=OQu ܅(̌)ƮXeJb)U4* ES*/ D.Su,뺶q!u!0f~)r{!L֔w>,5{}[&; o჌:蚨"?JJ/   0V) @C!' Si1P ) "tMՍ0U00SYDkt]WUP4UBQ./ȟ!*"E7K-Ջa#ِI$l/PJ2O]ѕ$`&$U;RBT8vyW-_\sֵo=LqՊH`Jk«smGyϓ3Ec5]1m`.|j;Ut : ~   rFuF=3TA bH$p8ê Pt2PDE4COBH,%x, uMg̏F:.aV-|gdKx囄bDP i HS񉺶D~Tu㐙F7J0 N|-d,yƺ%a" Ǒ'? * B#I~_}›;dOXg>luӿR:.O" bzͽR4EeT%N|IrP@BMFH=TU݇[>hI5“EB'YMO?Le dlY<\Zp<? GiP9ȑ1H)eUAH^aw`8eܶ-;kiݿuBh( (kw(  i>TFd }u`qQ c |_|!%U)f" (˔~yikt#D,t +Wܻy K0J7PPE:2%cx)ǿ}ל{6#x4/mؼe*`~A*j j{a P:#隬)OS>AA' #5\=nEF&ҩLWG[GWG{WW{[wkKc_,U-2-˱m2Z&Ly=!<* PrH4 MQT͈%$U3ey6BDtkbQ_xXH_LB(Tcú5'_|3m-NG (p,JK*w񘯅ƫ)NC*s}*\9U xGtwW^]lɯ7K012ETlGe#AK9_}6==SO~̘b4JIţ c'G_rO垧yD Q©U~V9La5.cJ()j,'l~JT a]}Ad.0x  1;H FI4Z3hwg{E=z/Zc㺎ynʹjX,B Uu-v==olqR9# GÈGBQ] cPƣY.8#R=l0IԐ'l=T֬;z:Z?gh)M)݈V]Sg d !Γ2F&*SD5n8-2B m…92xg 2FxPvׅz;ƘJ"L !Hȴg*OuG''<> gpl8.e7%#=GTU!'̹e<hp\놡P{ mTe-`kBb}-`=c pXd]( `A  rLBBT:jokMtwvw&bє(iٕB4>:ȍN&F'sّ<$ BpXar*\QHX&*<׭VڶU*2H(q'T5U˴fZ*RެT+ZӴjCڽ(jʚ.0(4`lȟi "~Նի~s .!\܍_UkvdPj2JdeH=!x|O?H840#no` "`QCV986cY_g'>i(]0^w +[RqniJX1  AMʈ#F5t\G}=唛}YH/fEݭi@Es&q1 ,RFy݊e}!!Ծtת]-R3=B)eϓ!b&G["Tj~l]A OA9&3lJ,Z2h[K&ݱu7eT5M&F?84:R(jb,VLj9<; _ \u,X,spVk+zޒ;!!#MV JKUcYT R}P7 H! ;ShI%*< ziO_}g,,q}z6.xp,s޾=3IoGK3~o?z$^ pjnfZ6M3MqƘkll"<9NMdӵ cAA' CD2eT+UX, Bn28h6˕jT h?)N Br0HMQ*H5m< Ads2pPT˕J%Z|ql2FB\.Wj帖 Y%TZ]@y"+1FS8=k6^}م[zc@ oT'(UB U%}3{ey,RǢD)߿'ׯZ7Hؽp_{8E" ʸr#O=~iWͦ>9F's 2:?[pkf{?|s`h;q'yVN8$pQ͍֎A7T! ad"[oXQw !: m>'\?2v?r]O]ϫ@+>}ק};8;Vvs-GLB 2?ܜ"q]S2fy?TE眥ޙbRn㧿x+I;E&$_ln鍷s'4>Gol)IO_~z֤k%1Mv󀓤,oUuNӓ,H( ʂ *r`8ӝLgԿa@0ʱ%Hesݝ<=+VLOOO[Օzy&i-`!ž9ʾIA]u]um`p(? rŒY,VlZ!T]W9W5UٌFW@rpNEwH1I(Fym[aA_XȑQ.r|wg*Y.KeXo@r:i֠8$'Z. SLSLeoΫ.̓Y}qlֵqϟg5XưepɮpUgsۚ>}Lߌɿoؘ/em\͢PDj PŎoo_{ngkSTQ(q=;ӷCXրe[9,l4!,U憥 ;tL^KtNY/??>†,#cKE#dW\?ߟ6u/>UˣЄ\>ѿ==[Qe i(rleKX(Ҷ  `z{l'@ <:knnto8-bf ӦRĆi a9WUd`''r`.#Pd e]J=`6&D$Y P&54 2E[)ۊ0)u#;8Z6h 0:ǹT_@Au_ SD$mzY'tV-ޢӃ67܆'(Zb4K%۲(㉩r/jSg<~%^{ ǭZ`A}"u7G ōv~/ǟB 3Y9l圣 bM)BRgsէ1Mչ08E?=nEMT.sإrܲsǟ}q_|lO@ib2i-0lH$ LҹuM?4=rUc3M1(GQ,Lҵ iRdU&Ey2 ҙdTe71JkbQXnV2M_4WTMkB(\H6fk0E6T4LA3zK!o)TYf\c%Lղ%ˍ3Eߟ4FclۤY.چaZlنa ! R80<3;6#\R远+*cIHSf"t8NOCV*v#Pdʨ+,[-p;l.96iD{QdY) ȹANCTB~ڎeٚapU/i˜2AGƤ*˶ȱ!86mSm!5QZ6NC"Si'ǭr!ef޴K%J-)3IPi2JT_ΣI/]Va3F/ȚtѤ3)LӖu(R)JsF (ESuߕɢ9%˦T #k!3i3ŤGߧ 6TC2WE(rސ䅒iqmA0-Da-.&0S<Nn`O!l /DpJ*uB{'hFy8Odfg, v"ͮd|qK3PIi"lSzoQ)M…%5bjPv5F9-pRNnF$WA;t[QiO`.uG~ڮ=;oC%ay*i$zJ)8P9e\?&S / (*' q:,,O3. %p!OprHɍr~+N1 eDU{B?q`¤ ߆(wF>&)OA:dA\^I4rhܖ)YzM["b91"hHL4Omh *L%S^LߡrЫB+mpJ4 9v'd~pyd)bRt} 5dJ{tmH "sGQ8C{pGᩖmN,9QtUI1W/[peKWjBڴeǖ_^B%vqb,G,Γ#N ȯ*`%[qX0u>㓱2u>= \QHϕz.p Yt! F҅HVz#(م pq.qfq#"GEfp\!(`G ɩtMgE ;ndtfdȉUq)TȹBجc $l\';HF IG9:Ik㗧C+8|}ugt]/G~epk :΀=q'Wuc%78qنPQ[yЩB:*'\BL ^0e˂5TW ޒAh;G$E^?Xnu䦝 'ɵ^ˑ/3r~$mgȨI"9U3ۖ)/5jTU]窦R\і&m0˦0Kb-,ZRxR@p/xsQzTi*S}qݯ+OgL崮̲b2Dd5a rz#8O;o=W\up8<0N%:0E/ki߰MށK_}T<*%ڂ8r|ș9 #u"+p)\Uݯ)z?7u 0_9J?x}p{<8a Kr$Z;@\ט'Efם@<8cA :QPMbUUӸ'69O|~TGE p{?PJ:2bD'75J}~Y[4MẦp.5evU u }`#2NcSyPNY0@TդډpO9 ?ypǛ ?Lsʾ@Qچ,q,uNZXUnpKE&1px{?Rȸ"z8$L$9689Ki2dž;b'kA!ƵgjG4ƵR\peZ v j BX",E [(o;ӛB/# c/owD`牮g! }+>?^qjc>c,"_apĽ.yr'L7w.+ø@Lq:>8~`?*lX+9$F,H~ AbLpqLMA[QMcѲ_=< !(.x&#sqNtp¾|u^+z}<ۙ s\1M?h˸`GM~Lq# 1P*q<ziBҽRy\ ;<\ώE/]mu'7Ƅ=/rMwl[~} ՟Wn[ppGh[c;E{Kȳp¼Go<qvQah_WuTO<'ǩ}ɚx1<.!aXrm0cܒs?\磐neowRO"-Q)טY. l*i}OئT)-&l 6.*zi;+ݽfD[2\ٞ2퍬7K;؎/>]e4yk&@ l /ׯ9gGU<7ڶ(ODFF^=gXw&Y63]p|~&j&w//x>[5Sh_WT.{t+P]ap\O&mїpGvoh eQdGr-#_G|ٸϽcvw7;=Ύwh8>\Z>1S}^@WZ*OV96iE"G?G ySdIFń&\ C9͓CF~,Å9jV> oʟou޿ߣf'^WW}ƭ?ǰFV37Lxٴ8q*"K}ݩL< #O~^k{5?M{b?￱|p0i<˫yR:Tݿel ?>l>Ǹ'vW56LI5;: @:βVp^ţ˕ۑ5e屚'c5<ͼcr̯tO*5 _ߣ2*~kup' X/U5;rh٦ CJl[(L؎ bۣ-J<:Hh-Xdd5j~|V"O!P*5#& { GVoַݵ`\&L졩Y&d*ksUdx~_a?p `.gDR~×^٣&8 #IWgYfq._ʄ2qMeΙӸ/p@ Z.1owNt}l7`. gp^].,UeBX DQlE6qH߮@ÅB 8<f-A3Xʸ)cl#Ti&{Mr2͂ öMSؖmۦm _S #<9vG(ș~F϶ei2S|Yؖi*a*m+6 :7 # `A$GCpwAPv91mambmɿ-l(l0mrmBrM# T"!5WvlaeV8y 0Kb:]9IDATr`4!pd a}b[&EamMQ.Q,MM)mhXfɔ>EvD9 G$Hz8c5j>U*5 T=_WTΘ*'ӄ0-a a˶Y([ł%.-6>NJ5hYe+L plrU+Sc2Uұ(B0A'%Ke۶ =ЧPypk 2q^SE\ո`))eۊ!'E˶iPNypKWSȁ9csJQ5RLBq"l#9HRy(9uJۢ<X#_9Hhs"#Oi"pRtG@;&A,`?ly..hy@8gLEaLQW,-f*e4.*MӃUʪbYT/(!u, `3X&80DCA_W-j۰kImX.8_6 A>}z>]v3}pģjZΘ;(3ض`2śf&Xm!8g4%'/[aB3x/d]&F$ pe[o۶3;UB{s^XD*p#zZO(Nɨ&\R[#afm eaC`\tf Ja^Im{P*\.Kv ^YЈ}ˮNfdIgi„ ~ ( omk Ă7ϗ)Hh-VJ%8Qv8ri%NDhə,wregэ.;3Xv;m2GPG̉q9rVtsgҠ~ڰ9Waس|R/ʵggžhyt8o{;g+>w;Yv`Uۯ7MF8RzE;bltYV@^"Ϟ$^Ugm8`$v5 }sUUcѨ/.]:U{BC}}}{g: 3l)I?>wԲmH'fH813TUuūv'<]XřV? c,Dy)v'xY8cal-!DnߛOOr9T\VuL/OI}:^ eߎf+_yyr _fleE-+[4]}]gzMoǶˣ+Qf>~>kϣ0lF(;g*lΧ澜}72,Klj8sFYMxccclM+W\rŊ{dohhh(uL&=(l.h  ={y)/ŽUKwt>gkyj.]ٕ3[3՜q:Ė(̩hs]-;o9D<9: h˗/kz{SN9P(jfy޽;6onfm۳>ۘyAL{vE3memӄuEZ}DµO6Zoʁ7㯹暷\ι׵gϞkvub6kkIwm63sz{7p[N=߽{H6f2TL߉BU5-ڛ;::淵-illmwttѱk`` iZc ҲkibaVЧzG?XR}/bwu˪UNϩޗ.9WK+^}ww~BZ#4M ku=zB:ϗ| >147/\0ފ Z`1mm+b`pN OO~Lۣ꺞8xM?X(rbl۶ݻ[Y1y~??\/w^xG':ζߜꚤRoty=وi#6ib- :;ڗ\޾iq}2 %;l׳ߺ+ϛw9sVѿ%á6φilǫ2]>?FTvaF{ʕ+#v{d;Qd)ׇ'{9 477-E Nx<0 k齦]9osYֺaN<~y_@4;88}}!bXV9R`0p8DbX}}{ߛno{ٳ}{<3_E`0XD},KF"D8h ¾wm<獙LfhW.ٌq "Oa MȌ֘P(7wN{[kkc\'xP*;NMr]WlU=( d4M^ȿ3793N 2y}rW.TU6) e>%lpW\qI+W0*CwGejg듟~tDM7Cyt5e~ᾎ.swkbDcCܦƆ D{"Y;H4z6NטӮG39S==]~e׿}{Cud 8t^bF2C@<kOͫO&r$N~gyYh4XLij_а>lKu~?Xi'Xy^q΀ʃ38==MD>hѢ gw{㥗7惑OHc ^wug_~e!jժ_#ڌp\Q#paNsS¶楍 d]c0sδj㪪skj>YG$P(}VUGDsSCGcCEdɺH88wY|ԞGdίG;׾ ۘ_}=唓D1|3퓼c$hAM`p ts0 4 ^mˢ>JOsVT"PeY4}>VL?Q~fSϟl((WƝq';cNb5./׾;]Z8Q',άȖNV|m[JP0I;JC!fP558\'W96s;kW:}M_K_gٳ/x5ZdIg: ={5 cd6pU}| /s={{{7>Q-z^x7jlٲaڵwQf($+xFhٰSpój{\6D>/e3b!';&gj),Pa#R(rCCGEp0Lc@t&F }^PԫM&?dsg7WFv]^x|ɇԹ8s/Lc=kZqWR.L&/ VPU΢ arH?P?i@)=/jϝ7OwSk9 ?uQ'}{g>Dkkի/8j .|>ɗҗ'\tū!/9SF}dDlpM$^˜jR( 4IxErB@MmL,V,R5 jd2L&PXW5m^DV*JRTg`/ד>^.ZٴKyqoQzJ8'9UbL\4ˎh'DOC=O?cǥqw6o޴K_D[UVDV}e3w\uuuuV۸<郃}>f͚Vlv@:ӫ# ޕd W>?I0+WpW__pP/٫l|Qe|\UY@c,O3̴ɑXTQS"WD0~ڑ+y05z<@ /Zz6Doi9H|[ֲAvd^zihB=_CUwy-oy[>E6y 7ϯg uN=N8<ozMP,_>w뭷=jrɒ%{{{{xo~D4 79sa .xw졪BBȤYD_8v8R@ZUaۦ~"CMjT΃a]UOײsIT¶yPtɧk!""NԦw'6ٳ%=odL(&Li_7Tڵk˿ۿ}a[oQGͻ?Q9AB_stiC<3I6}(t(9ZBD| Hoop?M^鴌 !GsĶmn&+Kc,@QR.m0yTX4|>H$|x<ommmfm۶ݳg`__;np?N9yvy?ϙ3gg'e';Ku]yPTTߝ~߾NB3؏)w≕}DUHUjx3գ =:L\dq-$x[8JPX0)zWETFZN7 |fc h4^}ǝw>+) +mݺuk.F'r`իH_;}۷o^E$4*( +y!_H[|ѕ Q.k֬S6M) s=O>T-[5j8iYve.V0ǣƖ榎h8Y+sd@F u- X狨s oӘYB}:Q^:::g|K.=چi{i^x4[xqhd[sƘgE!p }jRo#{o~\.7/>ʍ$e-&gJXSyBSy1J**bN<$d#t]Ly"xщ&@ف%KԯXnݺaݺu/Q駟ϋsZ*Vgggc4';v7i5q{McΜ9OhѢN:i>o|ozӛ}N;%K$I1KϫOY e󚷽ŋ]XncI%V?M^|LD}Ϡ}5CD9cDy =v݉Qȇ^M|OE)Z |T.[: ^r]G;wf<ԡ9E@ ݻU, [u'p'fV>U 3]c?9O(UJPڭ,rퟞ'Nc!1-[<@E>BP]dPE{{t9:且t:=e˖.a/⳧vyҥK(xxݻ{U9~V0EP/%Ru;::=lB F*%S g",̙({ɲY>7RKD#J4JR0?ECnU΋$4\,l.[hmD>ϗm)G4] 3a[9g4G<eK.Mer^|;w5FEY ꙠOm-]&듸vIОihT*XܹsΛ7x<а%Lڻw@wwwjppLMP()߶T*iaX($y4Cu .`T昶^ Jܷکzn#b޽}ٿMos -q鯮lS#<gqڬIٝ#lv 'Nغuv=M`=tGy4qDzGTʎEFX*MmKhBT&թ}rM"V4FN^]uWۼy_ }C_޾}ۋB9# GՍ YeԪV3]cL9ʔwW,< ,W>q4dLRn`tUYP9kb1VfU5ؾ}ǎr\UW&'CJ*wrH8T"h}fbX4(%2]JRٹ|E?C17r1l.ryJGڱ|6;Akxhw?[ht XU@%"uffD"P5C= a)gwu:----KHZ%U*t*;'D " xmLfzT~3ϜPZ 8TL6H \f3EgPПHĢq۶<}lei@i) [hU$ˆa bѶVK%z6ʦQV}?XC.0-s4#"o8y[*}swf< d )Dv?6mڴ`=$ֶ}sI7=@ nbhrj455T]]]k[[ۂUV ٳwOW׮;wڵx&)g2|:D"$:[( R٠xHÁֶļys;::[ZH$HRRT7%RiBۨڧԣ:gS)2۷o߲q,{H$5|n{^߯v_PyK>lNpHCugmX*Ηi-&lmٜu5DMӲKPEԉ,'s]Ba[ Z bݺu;{/{+ RsY]Vm۶d>x⦳~;vl;˿˵OyB56Oח윳ϙ.;Z6lO5u '̡ :L&Gt8M5T  '(RS֛1!F=S]6L[$QV}>- H(FBubl{-"rrT*>- Dr"RO%:˲l._p*JEqu/3Upքwzq!86|>4.````*ZZZTbs$ z7:tt9uR#&u'pbeݻwYfls]>;:VoD^l&5{&՚#E_p0ضe[X*LQ FLNH8Ak0e2TW'R|}GB X5U¡$=({ܡ? "9l"HI> cb)`q"N@T=];l]@fe5?,26JV3 G裏~ޭxH\.ٳk֭6GL41x%.EF%\2F(&E>cL.ٺ;R5܈Ԣ=ۮנtMuP8g0Q9(B4j+BjP7}:jE7ؒS ;Lg7{1ZēO{$˻ٳ+ؤ?!jfv$765 +2lw.(G*[$0WlJ0͜)r004L;,nȲk҈'>UYLOd:=k׮֌Rk944?vFZ>k$0F5y͙zpʁu?/۶sU;o<7GoEj8wDښ¡PNSe|,\mUQȰ<+zm*Ed|E8g(b)_,qrH}F6 p(R*3|KXNg)Mh4,/TػG ʤ+=;C7oJU!?/_z|ŊeO=<Ե{qcϓWO'y"?,~ ОyۭnU,ؕd `-tE@N@ hlll[|y`OOo>޾}n4Huxt޼M .3gNܹsy$d_0ٽ{m۶mܴy]ܹo`` GQjTJⴢOwuȎ;6z]r'tdJ4 u#K)z{3hVg+r|512®pzץyExU5k3T;NCG\Iӡ: A? >! e^<)U=i ⅸx);^qEԻS,g(|뮻yݻw]wuH/FU,*g2LxXFΡij-ZhҥKUBf…G_i uԨ7Vu8Ne,_4Nȏ1&C p0hh*gx$ҘMg70DQI!r* \* Me>6804V͒3XN՝JN:y˖-[ =דr~͞?z2-=Z&zm2zS4^n,~S7 bR)0](e4ikhZH8 "P}etڑ;93t]ˇC `l=4}\*Kb&⑰m |-ztݓ3i[̪rv5mI״w׼5 k'?ʇ?otbI֚qUp&'U=l6ke2@ƍV\gժU}|DIǧmeˤݻή;weǎ}l@ϛwҚL&Ћ/z_|qˋ/588h˲,Iiߧz״Ωm}ҊHS/]v… WTaÆg׬Y9眳x:'dUmowEv<%䑫Pei3r1%$gŲDѶx)3`*h6Ǫt3#Z' d1@q/8`3a =?viv~yCGuu<#5yT*տf͚ny Fy)7Qxߚ5VDMsS|T)2i?MMXx(Dy-z S~+Vw+xxd0r\*&1cLC0߹{iNSUήjG&AzZ/V Xo}ku(L[om3U#^tEcbiݎ٣I"Oj>)}'TN\+xiNpcSzB䐅&-EHu:'dT&)C͍ubh:kH)[vzqS,yJ"Eeá`z~gTmn+ ڨ h&9 c{N}s_\~}>\|>l?jCO?;q'Q0gΜ\rɫ/Mî}&bTd=Mx, ,;܋#m{ā"fZfP( ĢE :}a5xP UrNK]= s[||17;ww@k9NhϏv­"7 i]]]鞞®]{-bŊ˖-[J~;rb8ikP:| (sϞ={wر{׮]{H\o|, i :44D'Ca$.+Ei6YjoȮSbo߾NDWޞ|2 :&Mʞ߿vc_I]NѧToO,p]R#]vB^UR!͓.@.~4 j-D"Lii p5sȌzorWD{N*( 9O|˗/?zÖewumwsMŒ%K>1BTtڵk GŴIyT*qj}_wjo\xWTC G׿H;=O1>V3JPBj rw$lĤFW1 䆇Aq3 ECJsSC,MU )c: m[\1[()MSmRHèd]"|b6Mf;x iN;KT:qŋW\9֭ikf!5O&[{,<) ׇ*-4Zr*؝n5ɅLyLU=d g"_(S{p(ԒuX(ԻX8i0o6BTlĢ?Gt"$\d|8ӨBJB*l;GH$L3D, U4l˴*g }͓fZug-93LwbLXsssv Ucv$q$K#F{~ K;Rf~,}6䴠[|˳LƢʙP(i|cP(XWW$ F5==B!票QOO@oop>eUU-NeP8gTܙگE\7\\)K>}LRЩ/f3qK>:d:OjDL&s"g=vHk py6Yj㖫gP~zT&˴x4 u7׵6듉p$6e^d 9o8> ^RĆ WCa۲lL!e]vNP,}M~S$DZc]k NnݺoۿV3<8PWC!--򼧊9ɪL5C؋wyD3~0Lw҅Bu=ZL&:g0F'F"F Ţ=0JgeE֦憺D]" U*wȁSU&Yxo~??Ŵ}Lk,?'J!՟vww;i'x|>?޾0> Vlx9Yor8XCF9r`f l.cCmM񎶦hCC]8-t6cמt.?5]ǣ֦Ǝ֦d4 }/Lm8$iW;}lO}#^x{O8+"!gq{W)p wp>׾3铠=?bnaˢ"7΄&eJ)mۺ'|xgya˖-[Ҏ[>WWWWq1}Ygq9g~~^-nyehB^Q8s'=Ա 4׿!ORmR~DΣHλ2M&(~euzg3ܞ8<%̴4}cTg]w\hx0+M6u- Gx,,R4 ^WiFf*^=7VӖ/_~R}~Ãw/ݏ~gWShڵJjj\_ч\W;;uuV՝矦mNyә~0qԧb0IsG}Ծ+lfL.?8<88ery>(E4CZ KY}e43 E;k~/D D\6G-<COfyg< mvYs^eʈ_KTDx!S{еskWֵk>Nj6rj-"lҘtjIGk8NROpXR9/Q)!쐮x4Kc!\ E 4|804NgsR(ih$ɍDC_xWVRe%K$_z饚.}CI|uIО)8܉v\;D"㱆x4 =Se2 )͇D"|x_(lnP, RvX(uh! U3q׹EvǾ:1ۖbj8 |͟_h5m~~} HVpg;c<_jB3b|6UQT/7gƆ`wjE u{g?`BQXw;> #y.5OuTU麦ArDdlѢEs.]RbHCur/Ԯ]7ϝ;De멤1EФ`]]v9aϟ?{Ϟ=7lxiK/m؞J2T*[*IPP3)v~_[5h>裏 ov7ྦྷLgu֙iBSO=ƍiz qϦo=E,o+Uۛq(<{NWtGF<;)~mJSG|t65eQW(D,Oz 焩dwrx3'2jo?3^WX/|῅FyP x"𶷽\^"͕X,6AM{\ٽ{~̉NeJMFL-n0v0Ggϡ!g<[aIUQcԑs|)f*5W(mO [Z83QJOZ&at&34LQUT⌅[qِ/ċ5l }Ee:}{zPEdTy{]cbL>j/.ҙg9~޸ȓql6;Mi>SDl| l3ɦnl.4> >=5"*]*Qa@*k *p O$82R*]*pzxowoQ*/H(\_Յ~:JM26Ѐj_5Ojoswx:"j}f6|a"5Ӆ8瑏}o;3.>v"`MSIXĜ9sZO9N9P55r`ݻ߸iӮݻw#KtP ɏ G󗐰l>'ݓd?.F?EɐT#K2L\QOT#TOoomo(Sm ٺy^SrϤF iJ;vt_sΦ-I5PiQG)}WWclEVv~ڽ{סm3[p5Fx2d-1,?w +Ov~ӵL6O*᱀_o#ѕ =q'ݴNC e׮7pG+U]]][>O|lƍ/u;cOOֻ+Fwmk֬yt&{"NQOHj>1<`*P؏Ve}y)Dl}C;nzK.C/I#JoˎF}/FB6w=tGGy_!mhmݺų>j]*-: R=t#O9[ufѪ}޲׻#ZhPzFW )۷4'#1l}sY=}鿿igC2K4+ge?}qxLL6gKg,NFDy<@4 N@a95)fߧ믿O,}G 2DڙeٱhTkiiutt4vttϝ;3וeYQMH OLώD"dJT9')tP( NmR5dqe #09 ݻwٳ,D? d×뿾_اiiڈĽ_T.EB ]׃X%s7ḇngogb2x&Mcg\mQjEz 5mVuqE:>A7o~gM1!iP(Cù[w,ƆdMz躖 s s;} /mjjHO"@ tM&89i6lھ3|J+i UU8N"'x]I;UC2mot]o߾bq~8H$CBXq\|y7 $M3e扠=? +9W˶w"~_hќ̟3s~8Shi9eI D"QJSݻo߱5l鲎e˖ΧRvkR샶LcH$B0¤zrUvNi1-y1&ze],TӳˑȪר'iFyKHMUՠ'Ii8MJL* Ϊ|oVo/ `",,tq옍D9b13!70kd"KěHزE4-b7fN,Fyx837'5eqr5e阭&,kh; .[wύ7p|* oiii$p~",Y,Tv*cAܹsi6z{|>Ovռ4rf.TxooPHa #tw"JGk#V._ cXi c_Uygs鴜>gs^ߟH&i AZ !juMce:0r3*ZOap_yȓsd:jIZ w=ַ>Z}_}ӟ cTuk˜ ~"O'+Villl(3' N0NRCCC)*=<<"6nܸyM{vٷcǎ!Hy̫^( ôRMv?}۶mߵaÆ,]:obX8 PŨ( Ád(CׯߕJ RiR;Y@}]']3w|Pz+'9 )=H i~L=w{jCCo:< oXvԨE۶EWуK y55>V~ԑ\j - 6lacdʕ+OFcʕV]:Tr/YdHs7G8y`V'?6OjFNB\N'B1z4mj7uM¡P,RpBXN ,3_( S4+Y*υbHߩKĆJEV> =U,H)6%b ;qΕ>w7U_xqƍГsɒ%Hz;7n8U+Ɖ$nvɔ}s !bX`޼yTbSZ oppp0 79yݻv qi]וKR5BPܳgO޽{H{`x85fs\.L&kUUÝrXiBP<BAWWWigλ^QT>Iw+Vcׯ樣"u8S?[l6O=nzxw~ڧ{{A^{5k.F6mlE_ ;vl!x]S5F#G]҆ /՘=XU gF֙rOG D\\irRsph05b0dyP@7mU1-cGΔWaO>֭[~KOLWѫA_r"sC\rN;*l7lۯU&T^C&Tv.fsrZO\zw}WXvi]N6M=SOy=o{/:9#OO~ׯq5׼SO=ѬœO>90@)08Rj$dԞu\<˶˅bIz!U,Sec~?Cb3 Rmn9@Ţ5ɲL~`(F>+ % bW6aZ#iLr1JM۹bŊ1CrE?_ׯ_w+VKݣY^xa}=tҎ+=-"'dhhhZ<̣rAzgS~CW-[UO]E0 c܌[{{o~{Єk^Wwhg{ʋsy׷yB\ob^GG{+I䧟~q-vg/g^l.r+'iet?IT*:}lt:k l[|KFYS55 l.)%={T.U拃Ų5:qA@ ~Ӵ˥]Hvn4ےf>{FeH{{./~n ׽u`r4:}g֑Ss>ϜO׿ݗ\r))E7f{}~xx8GE{RTdv Вp 3cpp(%Tgpp(?0П. odssKñǾjEPJX,iZp8{zzz{{nMz >I*ch0OC:OתտdFSĘbT['pQo}[?Z>tM߯ov~;E쓎톧]|g*O?=y_#>IC8O/l[{2#o W*[*Wͤ9f6ˆ-}/ H8(ټ(x#ΓѨrk7edZjLt .\[Sݻ7^{oO89mmmcfzzz]EVC(,w \)=8z{Ior-]]];:::&ɦmٲ;QLoKt+Wcnkk{'ǔP&ΤWr8c9FIXm)R\,ְaZb\ ZI0 y5K"00 ,Kj:I LKᚮQn(/٬< * Lx&O>Ygu T~rGSO=H3o`0PZa#Uw1,L&mm߾}~!{/뛛;+ץ4۷LyߝK=k~M4Og{=wm/~7xsػwkmOev/˙bӲH۞9 (%Fj~Ml6M STRI㪻;sTXpE͙3JPϧm?vIxr49@Uu̙kjjd EQlEjx=_}9XGnp?SS.s͛Ƅ?O[nHj|4R5k7=#$7|aBZL7n_1SH$[` J'nwYچGgn\{vz9/sbڶUڴDolP:9KPSReT"lZrer(If5HCj[nk%5"կn1u+gϟ?/ Ftl6;j=t׭nYk?Z}ַ3rxe_;Hz}::Z: ӟuW]܏~??t1ѱ1Vo vwq@˥Q}lnP:ӛҌ)CTJjBtO>d+߲EZaZ ≺P>s}Cҙ\iDUw,kQ'`W9?cO<}mgdKvDw}w\ͤOPt`7=pUUvٿvڇ׬uߺy;vm۶/MmԦ\.m֮{ٗ^ziC__L&3Dy7mz'fǎ{|ѶmCUUAђ[l۶qƽ߷[s{ڿܵkp6~'Gy2S;;;VFlC=*]Ss#)ڟhD#՚'}!imGedWѬX!hh|# J{yctNFKSX2屍V moƈ/[lI8lу&^uUQlwFu8 >|uɒ%}ѧժS W_W@ .yZ?}MWdP/ p&@mo34R)KFpl\e]Y@"T#H,*#a[yP׾|^uT6_Um#փ W\܇>477uWUԂ:G7tӿ_~o Lwyo_tM#c͚5>| _ڧڞ#X|ɡqj{Uwd+\>?83ƣ&&_uvu\.\0Hd<O"JD7-;呪zdNg" >3 >3ΫB1#;~myG1>lg>ѭ|+P9 -[wA&ÖnM&%8Y$[6oܛL&K.]L6^ڰa˺u6ӲSr&qitRz{{K\Mux.^ۯ\ϟ?y貧gӉlכV^~?45_`'Jn;C\3ȌqBF>Ha8`?PDb"ÑW-r{ٟpv^FfI+AzyhWA[*S#:Þ}s /l袋|mL V“?EPn׿??Os׮]'r`o_ꪋOA*#N۳;#2ődsPwP}>+UYPlRT Cf$Sup0ҽ'gt΃lϷ[/4`F>?ֲ.\yt%"N^t/jA7}=5uW}_7>A"%ݽ _? ˏ\c3uO}>S+=>K&g.m1'f-骮k4cL6_t=D$9O=v#mӄ6 sȲipD~ )mφ_7 v~{(EOOk&WV[vy헡ȸRhAe;CvHUrH+ϩ'ƴmESj SԷBUΩo$!D" m8}ɝX(pYeOVReeR-U|:p_#s9+tL?L&;vIe?Ygqg׸v_`eVb8KriWT<ܬ}0[~<-MM--@ @ToM[vupwURgˮ0Z~}(ރ1~F%?zEݸ/ Xntv.•}k_M }_\}#|`R>(m/?>kɒ%+m۶qΝ[od{͓װj;U`bh(œuuɺD3Pbݵ}.*Wa *T2Yimnnhinnl]]wlڼyW*5Lٔ:p+Zh+Vh>N:c^E܏e#nݺ?/[xy{k52F.38 ʳB¦M^/~q{pus9g9szggggvڵf͚׬Y4r'ιK[|/0k׮n#=ڃs< 'T={{zH$LcH$%ݓl6޴y[+fE$ǣP"&$i~`ȼq6mگK/;XUU)Tf=wyL&Sh^[Ȍ$m9 X'H{4;~1"Y0~UWmo{;:;;Yoڴ[owq#EYDwe$" &H|B)Qw7q+{CCCi[WO/r5b6xb_`pĠZ4EPNK\&9Eei(>]~ H8#WRN3LH?x:2cǩY*=ޖex9WJ *Yt?Xh^g>|K_Ռr'g`q..8JY` uzLk2^&]/:j.+3M?I3ϯ>- "ᐟնeC|T6ɾki4eHT"_|)?X7x#nj9UFmb{NLiwt7uR_ nd?@V vX"̓bP(Q nTs/}QCCRlj8scE|J9AOu]u i|`*;080<[V>V>~)|qŶ}p;B{O2[&h=]{~NΓ+7oX@֭[Wu9O&o')&N//xz q'^dv]}+[h#Q|>  Zp H5Jp:Sz*jJHH0q5sy,tX,Fe*Ltj:h#H\Fy:jYi9+9iZBlی0fӮm*|sEeh2lLTE)Tӹ̙\kD~B'S-{a:Fb,:Ez~^ĉoZv(^:=̵Y'kifJogGkvϗWT,Rb3WIʻm⼎h3J)H$aٍbQF.ܹs@\6(![I"O Oߡ#d&yutwx:G}^W3,=/lA|=8Ou4MiȜSnfGS ;ߣ1,_e-F83LβiN__?~4O<'|B8,lXurӳcwY̸Vۯ^4Gsm!L&cR>w1Jg9~6E:5c1>q2Wz$v']F<ȉUu)"E5OFZ.#M?Z:T>Q*[.|=ЎR`ZZZ>; YfA i;:hN*3-W費:-WK-d=M$97%g&!¤.FA`5P~!t3^ 2]Ŵ٪'!l t}S樽O}mWoAeە0C^d2u|>_Ѝ-ӖϽe0mkkQ }7ϗv=ݓsHLrwW+Pf)Qu}<`b<G4nRC3k͝rGgJs}N|8P5-HXS+5FUWoo2[Ȳ^ި1g^ccg1gBY[}Reif,qbmiiE\z*^\E`AK]en3Zz3lL85a/@4lg6sʨݻUxxe{[mg7<EZ.\j7Z[MTh +2엲o >j:YoG#f>˂h8tAiH8Q{2i'L" MU3|6O( "ZS &"SS!G~^S[ܯ}W Bc\ُ؂vK{TCQƄb+(agM`&3{W}M8"c"P.Ep9^ 1!,\G6|lʌ,Ӷ'!o/wu\CzWzsBET LATk RDp8sLa?lrN:9!l%cfFU&tF:r;oBۍ>q!bB ]qgGy;Hƙt >qDq# PHPhjB+}qjtڿtד,IPdJDT x& 6*qMh:'BG> 'V,?[BQ,۱?))H{$GӱHGw\䑐'2bI7힁3M&vlO{~6W@#}#{)f I#1q=;ҋ>q(r²=[O'(cΪs J2a\q3r9Ja˜/BK MrRض0P L7f7 q[pTy;29HD:!e Veӿ Do+Y8Q 'Pi"cMDŽ5\45BQEU r=(PL'b[([bZB1lKzL91h Gτ84RL蘸¹t2ry,)YDؔBCyc"Wĸ*r I׈';sf _U0EE:Erjz\ehr<2v΅|3t+ ֞TtYضe MRϖQ>P'W)ȸP&@JҀr+&u5E8׹*#K4 _c1U''StZ 9'LR,)JeK1 SM[1d ɕ'tD)EGV$`*S5*4c2BCmqrLSئ",f!iYmڶIfcSMpFB$]cL1u!VL[LYe! ITC,2bFU)GQ5TB{HHR:vǣ- V Pi 2E("'Ax̙3'RdرcB@Lo H J;q8%u]]ъ:-^P"bd MNFc5?W [rSRC+EwS9hT513zh}rH=e[XEKK)e vhrM! K&0Jq+ߌ:*"F 9L]%lj|t9\\Q}ʈR0!), .!RaBL'\'#'7"爌2a)>g gZPNN&MQl Rb" BQ2GȭsUt98WPLQ`>ZJeZ:KF(l)VRC R.J0lY°S^gÝsc/ӂz!W0w#˴e 5A9 8[RGbëi A$ i=/Ea=P@dزmcv_Gp12:^qM|%{tƘbBTQaE6zm&)BL fn)6B22& 9Pd E_ϧ+~|!\ѣ\Q\hp,8W-}#)JGB:L25E˛(\ME8EKPsMT麦~iLq=\w.[a u}r_8+elarٖ.K]W#*bZ Z}ɪ9t0a| %2=cq-_ִK&ԂŠNi(+ڔvP.pfL{{{ HCX&)RFϕu5S $؆b fG}w!ψz^pG;b+2"D0u]ˑƭ/gz>1*2rAPtUc~M~abY^zͼ%Smﱵ?/Q2g,)\HׄbsKH%VPTҫYSG]*>ݧ4Q? a|󥧞{Mm]-3^ ^65-g(c͘*ISϯ*N{ݫN}[s{}yeí?F!P k!V㊢՟vѯz?]/C!P%anߴ_=?Ϲlfg\$#]l_e5pl `Ǝpg{G-Φél>Jҩlq8)esp֔ )Jb(`@R@0IC_Ⱥ-2АP@|j (Hcs}1Y_L%l 욆8`*62]srHRdGtş|guNStEhL !r\JLM"LΒ 7+Ub ':"qtj:#ӆD4SE%¡Ɏ*- K=sxq?EpcLN+)j1TȫT3_e. ;ԞL|_vVZvZv$y9 ՚e `,X D v.\py  STϞ{R՟-dJ&a@YЧ5b #!װ* 0BSmEHUW4WF|82}Hd5kR:ǹЛ;«_}f4B7cug4'ΆQԲP4-*tAUի\o<ͧ}{ u:kc~Š" *P]ch*ӂL;W~/i2v ]UHO֦FBZ22Nj3G`0-_J$D.8sN\K:00cghpwϯfϔA5d)Z@![aSA #y"+zqRDCL(p d}!0g^[{ǜ:,N'[H4C;tUa|C"MG2Ch*K,RTMYI$Uj}=~OZbNǴo Q|~ ? m40C&n!_:m)+5Wt҈<B%o[r[Κă"=λwl{3MغaS9E!M-ʄTU_|/Dž"ߔM/0KB sR" [2SI%H]rvx*۶e nmY\Mב,4Q}p,C!\tMP0F"$eh\ H(3K].l#o+FFٴY4HH *+k8vwEĪ:/RMM֦Φ֎ 9x{z8=0u_@㪮rݧr !y):rZ֊cQ8EpJ,@v*^}ؘ Y׶!1ZIWriPf&0 yq"srHZŧQidM-7y:-7\sgvlSҸbڔ`Hj\*x׭:˖3u*ݬ*ߦJD2HUE]qk_{)KģmncW_ Tsn]6TES#C 5<Lrl e+͗pj8542LӠ*h$Bhpv8_CbΕM%eQǑa;$e!/H@G9Ms洴u6ud4㪪 L6Ke顁tj?E E˪wB^ 5N9`!SvT)ӹ/ _tyǿz)RA. ^Wc\E15$iRRDjP^GT Œ27NdN#"`t9p/|k^C ar{kP s/ilH}I'+*TG0EξkN+(ONܜ&1y$Y  * w`XubvW]uEuA2 ps89ts |ι'u{{4Ǣ,A)ɜƓOW{wUY/rc_U;M?L FYА*T@PwCOAAYCCCcG b^,˅\~:ˏBh(d"HB@  E"d<LNOCys%VAgv4RߣDF"X:x3[ӿ`e }tM(Y*J\̗ \4=Qˬ.xAչQnÿUDj *=(Mu'3Оji71=_j:!\#4K~QŀAŨl%\Q.4 !c4G4’'~n6XUϏw=Ψ&x9+\ W^~Φu[R e+0a2l?p2a4"3/|5=ojh~# s"q_e-ukN:{QfTD8LHB hlЀAAAi:ӭjVT\~0itG"T"oO BD"Mh=fPRbBCsd#'ɶxd-HCAp n #liO~xj !"eoEg>sIFXJZx ,ovʍl9om2@bСJב« Ѹ)ss K'  ,Pr8+!-fld"/$bjWpX4C)'mh4SV 3EVUTM.2Ъp0z:;z{ YKDd4 Sʼnc#GFFG'Fdž''sp0cq厐И Et >k v ՈdZ<h:x·T-R. p:J̑7g>8"   KD& ''$+Zl+ת%۱*MN˧Ɗb17Z.OjVVՕ–#z9uIץ%xqfG A[R. |X(+\լ]P,HjHMݛ@ô27`B)BRP(AcQ"BL1JiO(vjh?#Pg+bB%})bP33We`_J%hRW H̪hP v-^3Ex qI$WCf Bm0^uL0(u d_ H;v8\RPzI< SQ*{`js=`rp`AAAEɄX *O (jU״:!5Ñ W4"0Y'dͬllA]RR &J.!fɕ)C"=.!xR.B.WkjRuK~ЀQul*vN2CB < );Dט2Œjx<ޱU˛bA miRӕ5鼨7na>>*<:@~Mf6yxJ ; 6 EH.@uzқ m'"D2\$ O#R.ƨ: $',x`h+ETҒYQʑlg:vĞT )A'  ,  @$a &B7q5Jbr`]R-YNhjv]SPR]r&:HJ8I)=)5jr\)Wr20MpK tx1 0 8dI(O,) IHJ*;Bh~L9U,;JM_X AYGT!T$J$aS[zEi`TJ`~kzRL'X\'xZ %8u y<\8! 2qAg_uCaRe2*|Lt!+CL'fR~ Z" OAAY]U/Q@&7ȘJEYu*9昜uB]KzUd5h@p H˱MjݲLˬUL˶M)\ݫ M Ce\%;Q)/*)*d*ZF0,JK>QPvϟɼ3L8c~a/mD@]CN) 5Pf,pfJC* ΨBnBT@MAem /l_^E~. x*J'AAAG}U"Tbj&݄*VfvVhѤfA%KT]#,D)3@ uj[5Bݒu\L!]+pTdbdx1O Jʹ!x~'Z=~7ĕ7OU5h. 2$1J ^zʭ& :gQf^@4 JpWկp*8\mI 8 I"^.Ubܨh"DfD+(r`AAAEa GT *^%DViP'Gtf2!!]fR j!2 !A]Et%˥˨qAB"6ʷVUZ nG(L!fcPC'v9ץ2jn?}Q. J\ZS.#Y-ʠëS[eO?hPJPHIOT &PsX^|s*\dz)/GK{w9+n   xHxJ?xoDU,`mscH}뾿z!ĺWѨU/;.%> ry){K; ¥!rxYt~7UJ2pd\–їG9l 2/Ǯ+.v>x x#(cT|HQPsE.$=O޻}Olڝo|j0u!Hy.#=iO   @fr["ш%éx2H$cVu,\75jKG0׬Yj,Jq/LW RV&ɩ9mӰnTV-Ռr+MWJuSH,%4A::-Ӫ ,DrX*BP)Ǖrrp6*3-Dt9èaC UP^$ ej:x L&1AhJLd() Uh^ZHMg'SR"ai 3p!$ORr) D ~_XyK=8JIF ct}`uWfdgaQPHʨЄF$W# B-A'JLon+|\d10x   Ȣ#A gڒd{Ew{u-Ba#dDUkRZ,ʅBZtL˲!GsHF pr*T"F$ E,Ӫq8D܈2m|4$߁cPuXڅJ 'FHg4%$ƘfS)ui< Sג|G4|h*r ,+TLJN)E]{C,;R)*iR $D=y+m&6A B~kLA CWJǞnR4[&@A˕c LB!R:)0mO0YC+!p)vR8LwG/37]~W>'GJ+]qb ڃyI.x_|OTnR6wT޶^9x0x   N#0KlG&ӑYlEn,ˮuZ֫ӓёC;ۻ{sc\:x:Aq.Q^tAE^g3b:fLȴBa=cLVʖe\BΆkWt`<C5`1aP Fֈk(Ե"eyA8Dyp\p+U2OmYqR4F~]g^s!i ÷~'[S+ [C #"ar   80:*V R>MF'һ*ZZZZ5:46<515],KPPV+,X{rA4 )4Wp1UF%r>pK++#E MiL 8v;QM*YUȍLMN妦&rJ Ők:P|;tBUQl xeRj*.vI-KTNW.'NUHHYrNÐuwmd-W6'RZ.}t~|{~A)WZyW+.~'Q65z ۄ   ~zLwWw+ё)*f\e]Z O Yz*Z"HTX(LAϢ&(BCLlg:֑g2L6(|>W b!Wl5cϛcO B 0 ޏF/=5tC: G5JDKJShQJ4$$uJHRbR &Lh$I=Ʒ>cLD?|FA1X%n(H}c PTӌF$Z׼s_l^>fȹ-{{_= nNR^t]© -G`ˡJ eRF 4H$1#S=)`F aM ƶ\EAdEP.S4]apR-I#EM&zsUݝ_ Zgo?gnKUqUenDH8Qj!WTNC *OAAoj=5URn]nma b T 9x~@ ITڞC4'3u T0? ,*Z2ǹkBX?2YzvmYR&); \"8vVwK+Փ@@GАjj^%ucCTZRu_^Cѩ`Jdߊv#ϚUJU<$'nIH.SvAUA q(%qibLhwKŒ%Sz(,[H^ԭ Ըp\ucsB h|\0Յ2!)/'z]'FIfȓ^n:"!]W#-Sg(U*_߸eo:L$ 1Bt8=*8u.@RsYXGB qc# BAAA=v[Je;1]J 'Jљr%$U ΁ĜMH/APA-QeB7-(R5bi%&Fm8]]jФ;^OjQPj0 U{$D2 5,J4C#s(ę$eı*΍]ʼneA%pn\7TZJM#po:;@wDp.?~5!8A^P0x   ASv&̄R *42C{xq/IN+$Rr /d*BR!AAq(U׫x)>f@e0)3(Qr RҍOp0!֮Jgb˥J{ϕ6ޭqԹ *С)ù%P,qA4Q1ȏb͵y9.! 2pYOÕÌ_C J@UvVpP)u}]r/DR ^)W_3- Ia 9f1d2Ny4o#RQYȕwz5)ܺ)*U 0S(@6I4*0רH P6 !NJ<3g,z@64?H{K*ྗ'  rҡ$uC5ۇr0$j=n7U2W%^9/ E3y/:@PImq|lC|Qæҷs qBFb$6A`AAAT; PXI4T _XiO|7Vi/P+/ T♃'C~I,SJtQ"F D4)4?UnW2\/nJA']@«O9{ 3G=Y%wV I *ǫ+gaz-T@@A   !+}Uv4^85iFxj 栒<_*)5T^WHBܪz,WKs9ʓ9xZLC ˿;?y=Ko߃#`{?<xKx:q/WR9 <Wq/2Gt% F^vmǻo?g;>x{:jpp~~#];G}C՟߾ol}k~e >P~(wŭT&1~h/Kd#{iЌZH޶?8UߓPIW _f:"cS? ziqƧn|olbGzȼۛy!ޑ~|d2=OUi7~1xPﱙf'<,_C{X$x=_{>yہw/K5ohHw? ˬ->H$/h5)dQ*1x<&yʡ nk /bd8W(}?pcb{ }|p<x󣫽5?0#Y>/gmo|/<{19Es>n~_^TA/}o{_l{~ߡ`~7'|ih= LU‘‘w=;x4)s@j(AAARzgCiHcVg^(P̅pq+]QᓾW AAAը(#*k 9Pl|Q$qʋ}rAAA!Q#@D!J8MAAAAIhQ<                                                                                                                            rjCriZd"ι=*A-πmA\FA`A4=RB)!ZVyqxRE׍hS{l8D00hS{]r,ضA'2{K Ja5}̫(BF"( O GI Zn Wnղ4aB{oHد޿ 4)v"Ry8K\JYݏG'm.y m:| ⤡}zULH BuBx$Y`}ԔhSoNi[o[ڏvxr\+^s~y_UQ_I?ﻯ3 3OJʋ)6Η羐cϑF|eL'~1@ԪU6mڴqƍ'ld>v9Q.rR@H@zUPA?@ƻϨ?ollzc /jBٍ+[+Ռ2Ҭ<B>3x+p]ה[ق^[-|yؿ(5 `#a}ti߿*%]׵GGGwo߾_WJ\Bχ?_?YpT{?}}_]}G݉-[ꩧ]&h9Xe7lk}O9}mmm]p>r/~?p^ $XVRpY-Uʲj{H[ch7)LkF(NTεߎ[]y啯zի^uIWWWww ~~CRT9,q9\Gt'3"Hllll?oR\c[>s(j>,v5׼&ػ.]P(L?Cη}?[Q9V(>6O >P3levۆo3{F Jr 񍗞tUWѦMN`铓C###7|_p^ʅ̠}GzLr뭿?,/ph޵^Sχ󗒷R)ExMӘ+z:w [94|n```tUӴrx\$FM~HЧ~o}[>00Ex@H[n6o|f}.1x+_e/;~ 9A Mbu]O2 #cF[(ʆBP(ԙH$zYrcV|̪m\JVEeH?pn0p8{p7lkF/K+Nw}L^B]gG !R뮻{?(<.~>`/.vN 78Cy>h#ϴa]gT*ݽjpִgrhA o[[1WXqe6]]Ǵe㱾 [a8"R 7a..DZnmڴi?h~Flwnk f{,˪o;zo|~{dd@@w__OWggW:np8 ~fh4ݵ*WZu@?k1XlN uuuYb˗o\lƾ՝ ^v槮: 7ˍ}򓟼~1D*j7C5&iRh4x۶2=}{7"}qvI{|BG7h'JatfEkX,Y|Y_oòtnz:7 bTs!tݰX ' Td ݁[LlO ߪiڂm@{zzz[6X/M^Lj}+V;]X7iӦz) >BH!?Э!rk:c>S@@"H3B:rPEPsoKeR+-c b٦/RX*9OR ٳZRw Ƣx%-X럾kZbלW| _ ]vuR1./|kk֬ybO}S_~,59a4Jw=Xk_Gb9yի^~_yowq /2D2:>80/й˵BJZ/W: M)"phkjt.?5== tT,U-v}5?0 \R)r._(rX-˞QH%WJ?q ]wVEU;{s˯+oܸ_׎;{m[[[t>f/d'>iV`4 #^j_1 JiVGs%EF)}x/-cPaKmPiT0~\(a1u(5.7eWhD{k^: -2eh='ޞ'>#EiT-@Σ9Kv}gT2ѾcegGl6ӟIa+E{&~c?L7oܿ&4>|^4Fc~׻>|{HΕڹ{n&  x;ש3;]THٟ礓N:o zk6+c#}-Th P$Ju gVg3ae9gp8h^ϻUd2ٞ.l_ѱ=ˤmP8~M>/=KPwzK; Dt<5w~㥗8뉙q@(c8td6o|__bx0FDg?|ggg_@wkڵ]{kဂFFFFǙYjqM-)zO?O<OOsOqYGcL:D`b б)ZuYu}?]}{%\ڇ~`% .?"Ry{38>w}{\.5˯x3(Cf}_ӈ8-[Z>P.MGor mT9Wuʵy9eYN\rE"v3D"i:^<3LSϕB`9if$22')Fs 2rRܪh2da#e7@JR?/ί_/uӼZsDvmsǾ}_Vc]tM[d_|eI>g?7u{EXhi&y(H&CnbjDu8Mj`^B.Mq]0^L|Ax^Cצ6MʄsA8n#Ѩfcl6 M.Av%}]&* BPhC򅠔/׀?XXZMMMMzy]RƢ]wc+x3|ri;Q:+2T3g2$jj*c41 RBacOT^FݼFx=$c~ BؙgfʕsR^&''G/پ}ێ~_d25Щl޼Y?sozӛ[|9\L{>ۜ"\nqO540moDx޼{΋/r~Eo|}}}0,`ӦM'_q'oD bN{ ACBzZ35Jp(4FtJ3&t]<0&g&ib`1!h4Gð#+:b;UgkV^߼ ?~7 g2K_Z63]]t4y`gyo[Ck/N3~i|_y 4Mӟ'/pk!pڵk{'&&F?}(LF~ӟ~λyv[nyHu z)JFmH( h!)i6-p[Ϡ 갨Qꚦ )ㆦѐWc!i쟥̬R.Y!C #ˆLDB>+OgM6ިۥ2IV/οh;_s`휽կ~mt޽;o<|+暿j\ ײeг>ke cm$堪_"Pb4i-hH$̪Uzxbbb855R$!Զ- AY-@J(m[8 GI= L&JӑtoooGR)=###I}bbb~)v+8 0~^lٲ>4);d"r\jfjjjT5PoT+%;묃kv88|A rԢi:*`z߂z[WJfLOٶtw{62 G&Ie_&%Xv$tgg|=RjܹsgZmZUN/`E]FX ܵk׮(ʓV$N5sH)KO۰aq`۶ywoR)Bkzÿnm~?_acA^־f/-zN{V$ɣP8Lvtvw $Z«Q!٩ҁz:weҩp(4j5&}F%P%>g^WxG_`:0hH)[nmVn_J կ~~G5k SV@;ܔR c7o^=g?OV*c͚5J"Z͆Y۶]FI\XFXk)H *YwRE ҩD-fD[0T4LOyRleH;l谟wmPM}q㉥}]}ƍ'5?s-svs1t-JⱨaNtddtƘf Oq]p FfhZ* H' eU_dvڭ*r'?b3;vTzoW;fZ͒!uCS)8W3_9L/M}bu BNLL C@ ύ7xGñgY3&. Iv [?^c:CYx<f˗/[bŊctgWggGGǎl6wtttzllj`4^ېokY,:eJ(uI<d2iz{{:9VZea{th4tTR?o D?Ooz[R;3_' ܽYgu!gك3lzɧ;عs.?-8֠}+I1x9`(H Tݙy˩T-׎mZ:\~% BL* EnZ6N;XH;/Xm1&ǡkJ)Պ,q'6g9wZUY*1e; 3Mv޳j1s'S̪}lηF7T*a+JqlllRN!P`׮ݻm۶&U#TՁ {W !Rx̂ h8l ]RT2MׯTZ[T҉#D<f$NeRjVVk~voڠ@)||h=H)ʗwn7Ph.`3M3E&I@5KR &HhLJH0ZjkUR5HL@k>dyPdoчzr\l/?hQwEi5?s*gYfM׹3(v;oo~|' ny8p{~5ڲezhOUO>yTHh5,U!ax4 _<9B4 r^YoJ X0 3t޶ Y%B!=D,M&bmBʒi"خ8DVeYv$HZ7+ T6n㜋JV**GXq/^Wh6 sR20mBPhzzzN`1zzzPq4TQD KsfYfBjvg>}߾=P/ZV}ᇇgH`#%7hp_}36N, M *LW YTꐽvy8yF#tG[Q2av}:_/!뇯8oՈRQ(e%\x0l~M.;ԼV+ز1j?s Ѝ97|sOզ;`l;666]7-dKċC$RncT$јK@VfЧD%5 F1`CkuӪC@7x!@m;D,jD㱄e۝Z4bX@>Y7^hhkP&k^s9+AB'!)aÆ׿mظq}?bX|yx$?#瞱o/=TW2MәjCrUV\b ce="HoÆ ӹB{{63444k׮a4 ct:\be1Ǭ\lW$о `2<<ߺmC{ٳgrzz *5(G"e.I}e w7\z[2|%JE_W2n8&_ͷ=kwf[5uj `9* j+J3T{A,C\KӁ:p8p#Uj(O"LDKOIr5AV@FywlUsttt/HdPŢq\.~Q?8Dϓ9իW]nRhs1}s|k_5 `6u x,9'cF9Ea3:(2N;{:+JH*a=Ķmnc[ad<5 |qʯLiό'gci)Uwy_bb?5smAv,֖fjk/u*lϥ#assc*L~v0![dT)deu%xkfǢJ"E#mxеI۱Kc9ƨcz-Ex,E}TG'a?=Ķl2r&Hq!DGV+SqI-aڹlK'n94JwgV΋u1-V[|h'wRrٜغuk}hӦM#7o<餓l0ׯW~Pf={& {JRɕ+W8餓Nf0Vwg}GygrQ81*@.sz{{5iE)DGa7c9fc[ly;x[!j^5mo`9* |ZWmaZ|V /p.M!D-lWkfgXvrd8h?1px;oz}^ {ἷ F8'P#gqƅ͟.{߯x]t\tᅛ=S߱c37StzsW\ k t]y׾~G Ex_{vk6GDx2IDATiZęGfr^dF96ҵm,,gR=x4ٖI\4=C /N-J8dT;;XTꞡ`B$H"KF=o{;zSO=uﵪL $3v g/w~s={ xf+O<s&peD4?}U=z_Bg5ru[{N\X##}}===`l d%TgggWoooW__tn:vll||(N'RTb17919s۷o3::Vkw!SKOs96& wq?~gCQx~Mc x~"z%nj" qj޼cc8Oze .Gwo;A>cle3)gU|19]d{ꞟL+4\hmm̡lT{o#ƍ=@ ]AJu{,XX% 5whIˋ6$>wA];M6+.? Ԥ.yr\=oAO~g8/4|Kk@裏>zY^˖-[7ᕟ~T!G] 66ireN%hbu'նg(PV^N%W wN lj:?bکSBT_4ϑݻwݻwe}Cb:yPs\yzz8˪jQL9*+pI +|iFv??zWޟz* >+Mʞ;N"c1OAn'y@g&BVMju^j$p8FzoOg&I&su b`P̾譿\{(IppK?b|6l8yÜsn֧3}[kv{bwy'ThXoPs"g}6Jc>Zԧ>O%\ryk#<7?~hifϋL@$`\`{ywFY6Ӥf/qbRD""2T, uS@UC؁Wfn9]U ):amdHfu9z`s=:/҉k֬YiӦ3;ڿ t`\亮x˨R-^(U&t:'qXteRh49#gɠ>ϓVZxfՒm\./^Ruww^ty[Zo1?,- $gepP/P|Vwy\.sn Zx*EڲP$IRD^j5ej4>>>=11QjP43(DBso p~䵯}}Q,,>w}HAA<XK/e <(:UJ P,J)o{4C# "D̹߼RH&SZ::5=],z;L<5M_4/q i|9y{.|%Qs)O`˖-˿7lQ7M5vvM7=[B\n96 Ν;cBd T=؃BA%3(m~ >WT:J}:؈q!FPx\+n\N効\T-Wkn( ECX"Ktua^A Y}:b<+0ê" P(J$LʶQL't(~y|_]wuO{{Gg;AeFƕW^ysAyEyH;<yw>Jf/"lœtqK+OT}NLk씔"fhZ:L2ṮZnRL%Tkus:_,*ղe;6|=B!=L㰸іIGV:SbWUZr]3EI,l=)n6j [_WBp%\rEY-T6YvmkH!?8+_ʿ6<ۼj6[KcciBb-rW`d^Ѡ X93º֖M%2Bm ^7ET*.QY* KD"t\*WTi- 'LӲt.LkqT<ەͤ BfR~Á_v_+֭[^*h4ho/|ӫW>v1ɍ7\y^i5 ]F4Ifի[HCJTէ~zDa޽˗/Sv(i JXlkkݮ ʕ+WLMM oܶ۲P( BŲl8@4.i+_W5->w}R ^&|A۟cWg7 d/J*u౫##;of}rLVuuu)3"#GB2G ^jm2J6` /՚U*W*RJ O-[BFX lM3V@J^&qjX*T0i,K1JSܔ95'f+xn;lKѱ DzS󬙖3X$<IPIvEڹBm V ! &bN Bć?:묋pL2;%(#h,+ cD50.t/lٲN?N=4\.75<<<ںmx"1n=0Q"hXrZ0j{2+0# V%Q,01Bֆ'AJRa|brW' q(!+W5 _uk_vcbqIin!jjl{\Òl[[fn|/?c7tuuE' -Y,2&ҕ'othxx0l r4lAD Ш8 [d/1 +Oãc?eg,vB!C/WjCq Vcwzg{[I%!#$]hy??ӞFΝ;=s/i%ҢSAJ TO FixxxKogtZxB߇>.^(/|r9w׿{ X # 0n rT+O(Z&^j4ϙ|ܟX*>]홴ޖIet4iU``) gTM/ BHmÆ^{eyAO}[_+_L"{J/j⮻z|;/H+u?.ڷp ɞ=aBxHCQ#]S?e[Sn)I,tͤR=P;c^x[.yB)= 0{Yȵn-\-1kyJ@oٖZU:xPT+V6BF~4fgO* [wcZv#g"pFc dATUЁts;:L*2thcH$4B' 4[ړ$#!MnFӴ6Ƙ6}裏@QuKbPP_21yٵk9SBX1ݸaCu]y$Gou1IK#cCDa7}V\rٲx< 2u(*I$L&%P Oڵ{7~׭plD0҅ =јJSZ, ^R,Ku]8tqLy6.dk4|`f|#g0x盦i08|57jx/RGǧuMAMWB0$7Q&)1AAiD"7o<i|+W 9ŭ|Cq"0'X锒Bs"ޣ{;c~lj + Q5XA)WV]S#ZFڍ׎錂̻mTLt=L*ݖIwO12Z<}ڎcH&h73.e4 .~eMUtFfW}sU{|_'7o>m1We32X&wvvfҩT"Ig2Lu]~OSO=e׮G}`` U@޽{rhwwwwGGG\ „W@D:ԼP(人VG"Z(jbт; 3X=X=!ڧ\8[.<.sydXGX뱆i֡Z9 rxU_ aVR=EʌBDaeK Ъzir0I; eBYRӘ5Axbߖ x.B0*`R]A{É8no}`bTc`+8 0; 18l\{ɟɟѸ%nO^mʕ˃`/0!5 DR,HaKđFQ~:n~ԝ"_ͪdPzh &^B DIc  UNRGK޺T:X1-kbQuAKՁ׾Du֝q3m lwPR[oB>ɫj~2bs;&UT*{gԠh=:0wӁk_?C,Sn|]w zK鄀p~Mӄ=M˪ߠq ^u(/_ ۫j~xIGO#o%G'&áH2% t^ o#ZW&sT2rY"E)aMc5T{)?Tkщp8fҥ/t膮SLpo1KE"휱kvByP?P'Jh͏cOIwww|ƍ:;;;b1I` t>/@bXnݺ}m#{ܽ{w*RNqy/lݶmG|]{luVlܰa}*"l*F%9dc{g eY C ,[Ai^HgqXП/6ָ::Z5r0n rWL4b5P<.' M{p"z|az*EQF,1#l%݃t7p688x\W]u_򗿔L&gַwc.ՉPۼyYPhlxrrrBJS/Deǀzk`w]B۶mۓ'x+_N8ᄗ?ߞ?y{eٽ# $tTo?Ae & 0j吡upP2u"pȴ,`2 =VkjwBRtJ#ZuӔh4jZvƹ˽FkEϙ,~ڵ"k~5>Ok```u~w2uE,d,  MxFK.k!m?chU5bO=7n8?3{uT~1h4RL~[#<2 /V vm77ow( 7m۶gbew~>H|衇.6րkp"Lw\s[3^(ݲe˟4nU4pCz 8rϙPJMBܽ,+6vÆ \tEr˭Onܸ385J#<胯+g R};-#`ӦM']wu g.+0H~ ȑն9șWRZ)UjZ.Bvֱ]8 p*Aej**#0⧞zIv? o4J+ZZInb9Xeah"l{R8syfr9藡N.MOOŢp\ :M;I+rB DH`c k/m'@`0[ $0A$*N\S==vw$mxlwuuŮSU}FA|ӦM}.N=Sȭl6Ca$Y(g80Cٷo>j9`=y>%-J{QWW)Cb\ _˯%"8^ƮFgsw^.s^V'?7}|rܷ,Yf.tr/e;_җQgyOVרT_5gOɐhmC[6"'7 E0FeKmο%Y$j3&%7%AblFպiöœy *6:sYۜ'˭۷m޽{x/x'Po}yщ5/gKL\)8o;oܸO{ytlllK__=w~K_aKq/nzӛx駟޾a$> oo8p`R7xzM_P'C ^I8IcYs>hpqO0jFu0<2OJrA.6_=hc8IPٹ$yp\tz+WȲ[o_q/1w%vѓ\.,v;?;v~#_k-Û:Ka<({ӦM[/nƯ nkbbd?ohÆ #abb⑯}7v>Y[oƖ-[vtvh~G7~7x[S](V֪ӳsDu=&e5y9]o}/{{{X}׾oN֭[O]3;;;XKm߾û'ɮcsdMjR=ptyvvIݔj߾}{llB tuuuN=u͛7u|y4ZV{ǨOPU͛7w a J%lEy]u$ (Zϋ/O?';;wn\Qq~{2IXϙ^ƴ~oGsqAv|"N ݻMis'<%\rPutTͱYw2 D9.tw|kD3/`Y16MTnƯæ)9 [nZ`q;o۹ssW#Ybԡw?ql &t㸔pB/)ҝ߿k??3)]rʎeJ'>uL 6<~&kٰm/$P窜(s%S@bi.|ϧRl>394ZZ}ffnnwQ>_t){?=vS[֏sT#,YB\R*j#_n;4m۶mk.+-яnV fp w^W?9lboomv,;O$>Tͯ_O9\822q< _go޹EO})ghhhϏ ]wTr.Qܬ7rw\9Pʜ|utZ%mj(Sh*mʌ;!3/:66I^MN읜S&ʄS* ٪;~JuڹX[;>oo-%툾o}K?l=I_Cֵ;?`!%{x;ww?orrL)%]ӓZV|?T*33ozzvw-?GMu,4k7pWz4E<'G]D%<>NsKwd1z*֨eN. @t+oAR#tvnx#v뉑83v t8IU!cA>g;v8λl:_eh?|vttt//gqRP6~k_kNp>i9Ҝ'1\qjVA~)|h*}AG G~M~aSRuP0jj}z PYeҪ 5nfsc6 nO;_txxh쪫z<KA7G{~X]~L]y啯^K;:h_xWF 1-o|=7CCCW_ _r&ܪcC]wi.Ϲ(9L\c/Ӿ^|}Y7O&q=)()|+E>G}~35l{ߝ]SeY$C=xN?h)dwoO!˻-Iz6C^ܹaZ罿7-Fؾ}Ez?^t(/yK}疂:7~~k7ܰd *GW;?яOJR\~M~oկ~7|r5y/?T78vl5 z}Fk3ݣb˕}/>SnrrZot\^,vbWO9Hӽu>wrN %2  N&njy`k]SZ7(lrk!s/Վ}iB+ӏ~+a mWo߷NexKƽז8VYocIvG5;>Zf;?7 lذ1̧gg'ߵ{Net,V[jwkiaWɳb:qKַJ t%/yۏ9/d60=JW0?Ϣ [6{ַrd Ai~\sysرc?=C]wWg~$nWD{^܎mR)3,43=1o#>JuYFJ[0<<4)IszݳstYE 笳+z_@kj#s<3.jl?^)drJ+^Kg<ws7mڴw޽oy~Z~K6e/3<{۶mfSH ml~OR lYo4B h$:9bs].4Tjvv:;Wec:x+)<'{u]u)m KgSSsmK+r,vz/Oz;Ojt0%n])D^j? pI" VTH|ja8W.qVi[J2$ˉr7/~pWW]묲sxI։ Z{ck~Α@JGZ-+}D9/teFFAm5V;MVגzd33.2*X|<޼ypg^#JP/~񖥬+e_^?p6j4ITY8\!zr)QaYM'1=ەC\_p=aI龜g$8eyO&k('")f:{()'-Bmr O89h6ZragW}d 'lذauN YoS,$C?FA8)43mo4H/=d8;!xV.6H>ڐñSlr37s:ޭt#BY+ f9ZFzK$ŴZOE9GDˁBo)SM]0߾)rsLokr8ނcmw¹ȷGVsy[f鵼}hqƍCp޽3EulsӺjY@Dթd1l sIb[1OZ1xOODC:NcgLY4ߎ3FzuhBJ=1V{nϿ.}Ns1Id'L9=LXzu, ,ѭr6 8AYK}d6kgsX} 6Q=kv|HnY?90[36Dz egUxy޾fdSF zNq-'OȰ֙d8CCb=1Dq݀ZaG.V׎}rt~}w r=˶Gn ;am8X7 67u*v 5^^6 q!=M(N[ >UȞdݔd 'h'I1v~mn$W:?q}8vp|2:XaLƵf c:6>Yo<gqn!0cF4Lhf?: hLӼi64w9cL?Vx@>X%ѡ| Hmz$pـhmbuď$Iґ\p&&5 28[3%%{.Lh{y7K{9ڰE''"煐On`ƪFkrK0yĔѡB BHƍRrIV AXAo[ZF?->"+tR-v1r2yC3a{"]H#4=-EBNtϵy5oڑVI?O-vIv{8S΍Rd8S h"I?O $Yt#ݡH;1oSRFr-4Z+ds2]inqS!d0#^;'4XVDhXbim;%aOBa/P!Bbk(M#դǤV8ɾe䤙lìF4UFTy"(OlP *?FC1/!Xщ2&Z'd 9Q1:P]RGgowf! cܑRXm"uG?}$Z[&)%hri m/9LD6_^HJ0-m&b Ͳ”VdI9lxP*zp!kLfdÝt Y)j V8 a&N!*LBUĘ='xIl‘3eOnrP#Xwds#+$‘ +h"uD8!DDiZIWZk ;Y_s~l(D!Hp&\Gבv}$H0>V eDS֤-(eApXɡD1eCnZ1co$iz J-F12*f*s26$$YM2 Ƒ"]dKrkh6ZX:&(eN  ơbNH GT $96H- dJ'p"#p\)< ߕ sҟKܕ;a*M'*EsEJ!S1)ƘDiw '\ Rȑ!4X"|q#h</:R}Gpl*11uc(0VFal?u$bCi4K&p[P%' \ |I4$w[9Ch'T2QL$& F WC:U+HL&q]!Ip] Ӌ#=ƴMk8MXB+F XGIrH;QIm %=  )=. 6Mk3P2J(NtHajƑV(!JEhr=^rƎzB>j IΩ&ݐqrh8iRv rPFPc6s\P;b/tyꘙkxBĨXx+D.pA>]O=].ea%Q_=l6_?y-1vFRhR*dž 9!$ 9e4L <|,>/ !R|_ig_t :L$~> LSi]MSuc^\ތbQ"EIҜ6D-NgA@(j4nksc(VU(V+ii\H{&:,9 y?|ȸt|(D}뮩)kn+RJQMZDCŜ+FTbDVyx`Ml?eKqh7axP(jչFZ'*6l*,"mVeB3FП>BP 5q={ n\,λ;nP>GPmN2xyN!es^ʗ?EF:ΊFV[(EvᆴlpZ{XE+Qp$ᤐ@8>^챭gl|x=6kGox׿8ά'e1uWfH;iUrP8J7pesE SWg< ZN}nbHp])#EKWN?<*aq"iKv[0TՆ,LZՆ .︅Y ٻ㬧\_n=Y׃s^v֎vw|7خ\ifܱp`sHz+mR ]W]qӯ曾çE醫yL9KHr.m^W^W=zVܷRw_ ~Uxݣu"m'etd8]rK͛NݾO=``dvftenfnfI>ZiB mVՖּ 1A6ZKIevuK]Aԓ( m84ͧozk~㵟kTp a2& %i\Y^KN:Ś ~&ٛ"PRRW8>Y|ᳮ~ W8ܦ3ϻWo3?eVaPhR:֯w)٧åPO=7rBO5q\\#&D5G8CC|UhA:|TM b ۿ cC6 n7l6*Ba"v),OZ&}Pi ϗN#(zr-JiBdRJ!])0m,6 &6X0r :\cwxNEgSv\xJ:An;S/gOG::VF!x׆O\QxOgqϏӃVpeDęd&]AzsCVB.~30r\K5LUIcK2:pcJ"6 %GU+JyfX,N*$ewUUTR0'zuV굹fVnZۉ4csZ(C/rD#_6A(yO'0csf/z˞1eC( ={p Ζ. rEog&L3s\Msݴ 1T{*&6IZ8^'/ 7l8팋(JL{rАG gFs>Y_)  )PGa=i6*a^*zpgq/}4}CN9빁ɂ0gr\'F7rf|2MqXavЌ+U*T@=G0]g_ )e{]'hZjh+$v٩5H.4KҮ1$^='';i_ 6. Wf&Û` Zr;wm/~yXq3nlKKA{L=Q1E2{.) ]3w?D{)r֥;eŠ˻+F&;{S<'7͂3_:q!=e(?[VP; 8J>a&az97-x"j*5H /t~+~PPq#IS11W(z*\)=)@t oذyAP(F27;9qc'ٿo|fg'+F*+bCrUBV ! Dfryxp\[w\xn[5];žeECB1<U!E$¥1d)O(/. '6I-VtOiNf4JS/ !,9-zT076lTء$չ3֦9 ܫZmZJԠН‘ m_CevMrg MO%q=?wrh{6 +G//b7XOFG AKL; XP1PNۉWFm.=h*ՔdJj; <+ ZQP1sGh2J,D < ށޡ6l98pO*SS&{tϣ>r`TY$IiLqGP؆bRRdm0ƥdZNx"s/zݽC$->sb/ڸaBz`FIA7H/I#v$%ɵ[bW&p! CId‰ǜQʨ&]5>Ŧ_E2Me,vweY5cfL krc9G f5Դ/^sחx$hM"eE"&T5a^jm>W%g᜹ D;Lv}Mq'vdc'R_r4X5gbu>JBwT㸎 rhQ-4 ``Iը HA.\!]RWoOgpoH6q6Q˳'߷=իZތfq!G0Пc iSI[J;Tm;.<$q*%2ՙ=3esv:ﶯnm%6: \'$ORS Ů!ÌE$0 1 A. C*Ʋ 嫩UVNùdJ{yY2R1$Z %ILb$3,!G9`["]%riCUi h>d0iŵ]3mFT9j֓ ȴʑtH"JQi>E"h>* X94=Qqt$` Ua*aQMM[ 5$qTo*kfsam2(ҕ:.O„RU4gfuV?5vZ٨QbrynzrzrDev7)J348h#\:6߉a]'KJ.JNOL/ŗm10h+އn+8|'ˇdо^7FYI*d " C{if٩fҒ/GIP1^([8lDi+ž|ҡoƔk4'EJ*1W c<+(9+Lr$0w RVdҔ1iX&MkŨtǯO*6UI(±i\GJГ}2P6jVdj?:QVmtrBzܘ )"N9Ft#X$sͰ>]g\Q%zk"eB'd]x $LHfGJ+HIJAJTM:&\D 1hTTd=iN,n0EsL(A O2oCbtXVa`!t<3]dQ84F'LpCnF*3IBllr|PvTD%@ ߺ3vhX=Rf+!(*4MZZ͹O"tMI {͈97GN9wP"oh[K_OH^7ӷH0y=$SaHY!Vik(lG~LS[m8HeڌYuI{V.vt߷FdB<$UXDR ]zk;T`&ժPEM Wke":KJ7f:.+Ԙ䱤0NMDDSb`:$dBBZe\Vf˔$ncJZ˸a1Rؼq&0%c(fZnKfiC|W}G©g=Rw!Fm9Dž![1Pɜ֐:;fB<: EPgBB¹ ?~xx"JR ax%h+,be P$ԺOR}$mJ3Ha>_^?zC ( vC:/W}t?zjOۜ"+H qXOՃ kF -N;7w`ldUwy2T t%[Vz% sqBU&ıG/dH(Lڢ,QM5.XC M)y"P9$c.uC)5(UUJbJʔIM$uz I؈ujc&Ý0ъpah쬊$! 3x\)hzI(ᅋ/钉bC?B&cBqsP@ťh1e -X5}hPRZUI)Q~cksÓݻ~+|Ƌ}Ɩ.J6k9T㨩uԏyؑ<2+TX;ZCLIY 4+]" Oe:NEVXa?i^ղBhTz(x hڰ̵A4vuUB +RrX&:YAF0)\G2V#aVZQ8bFiQ $8L"|iȋMĚ%[yA<ե7ΔņP(];?¥V&`iN-˒}'ں, LiI㭿5( Lhnr|Weh㎮B[>t(Tw#[$(xDXb>0B5b&m%*Y-8iA XzZO9#ii$'Ba(-(gqCNu\ףF)=}Gjsdޑܥ4*'׉RȊ1Dq wb:$IT)lZ& 듖X!PaN8gN*V8FaGmcO9gRb}LO={NBHX=AWJk׍cL6$񃒎4X%X2b$5y[G^sOhd5Ѥ}]_4,_=47NR5ФolYzx|?˪)ui1:bҳ}ɝ5mPN>uPЖ#%f9mVO)sz\.]s9uq#u'|W<$9S$<*+rR/غO֚CIs_4Y bs91ܚ>[vtדUmʵ9 (Ç&9$P[i ƦMk\8t_q_eśN];x慄\_߱yCi7mƧ\v~o*>=Ot|*T̅(l4ZT~.eEŖP+_ee,pǾnb@N;j{r!dԬj$RP`sUw~~W즿?`uRSξT)s%c+q ccVh}XM~Wo.$Uzd*ʩ[c%,쨤##[`[5Iǎ8OX>s:i]%w[(抅\;;8T3IUhΰdqUBĎqQ]+;.2w\XUܜ[s chΘggv"̰RȉBևt]9&~'sIbJ72IwD^)mJڈU Ja\MJTIA?qN|wKpP jE2[t+͊:lŶLFQnV}Fr %`4jw@ zH╠КS%57rnLq*ZʮQtBN6qbJ1%4|Q͕Uxl- /"[Ib(MA}i28V:Jc G,ɐi) 9I(Iʠ<'Zp妹[eY~3J1b}[O3,fdY6(RIf))_+rm|Ǧщž*äV)-ukcZyBs1CUh?Z2ibbYtYth[usx.[ix2>hn-m cB}OMhX;n )AlO7m4386yV $naVk+zu\ѪTTI"~p'6؄+EE,`r3/~TBI䄣*˝汍.i'6҂J9\2&LŔ!F׌-׳PSydIL2#eb(h " WB2e*iÓTֆ7n_rdh {2$(?ScBi%e0L'ʄD*LԜJb-%cfʣB`aIjrbXh2%Xx6Jw o[n9Q؈f'jvNzm+tKM7R4Ҩ(j)k =i$J&SZIb$!f[2Z%Y,@2@SÖx%E+xR!WpM#R$IRzyr6w`^_WfʍjFbE-4JJU{2Xq3z1Sf'bOEQOP)V*9JOFGk*K1:M"$ 'u8 !,ړZ2#%%)Y"✯B+dYq]1))-_0qrϽu/{5oy č$}!D3kSSNyEOrK3*XȖ FAHM7R7Jp]tշdm]ν=(Iw/<>_ng6uFɉܳ4`Y9c;2R ޴q-^+7'v?Ht#Ntff3֪fcx͞ƶBPX\)`*a{tRF4iI[)CK 5B\۲ҍO}廖tCʓ\*}!9Iyϖ.ܴT 3js_odٲ{硻~;Śqb8a(%ē4 Z' Xu@&9O+bWowxx`hѭQبq؈f^-N`ߣ߿7&CGFǑt:&[-/UbPkVSZMiͤ7u-"BzP^ztf#aX hFIJyP y,I4}yc$Zhaӂh}GǑ#"7w:Bjk_Rw\hr~DzzbCUXC s.3,7IZ2g'w1NBxBroಗ>uhdRӖz_\]rr}D(ҍ0RQH7cP [ Wml-#JhƵZZ<;77;}pnfjAVk6հYN=SNQRfZQ\$:Ll d[‡(pT%J3%J aJ=fQQsvfrbfzzt\.jF38C _{f"cJ9J ʔbxa5&r3T+"q"1ycb-Bu!BXf3 t'&&;[!I'$dYU,5BZO~xS]/X6j G_YimJ&"X8R?˞g.Uu9ފˢ_[]wveXU+]ӔnHH'v?{˯}J۴r|[??(ҕf4"$cز;64#O%#0+k88up{ߞ|Et굹F\njTen\o4k$p*$ ՐP M!@y)8wqhͫղaZV횫덹z9G c8p\R ÈB7l"tIJi'EEvQѱR*9Tms rCO*sNnXDg _7SF/yK$hd ?W>oFrJd4%1'ßܰmx9c9u?\(ѳIbBc4/IWrouh䔑.%GM{oӇ1Jt#Tf04 %66넀xvOT7REc=:/LxU*A_zQMb7}755=7;;W(ohb44kr"H*fC 9] IRp0Ү,4F֕eͲuUf&(OC>8~]߿Jڄ*1VA=)>|PΟu yxb0o 3z6Jo'O;?Kgo;[JOZuo(6(F Q%d(]WoUE+^v9:9>{ zTz0N0f]g X ۩BF0\qdZNUSZelT:i24u7)lR !Mt"l P%Ҕl:Eըk"IQ6jfTkq#It|}O7]¹jYd9q9*U2L01pnPQpD3a1+]%GV** [EX)&z.{Q?o93QJyqˏ^7ÛVso7~׵f3Qa*qS`(I9vgGWo~<7Gvts^7l> ZΗ?ϕ{PäRT3tZE-Mb{r#8N F A;s*  b2Wo6+aV$T)HNH>L'fMs[wP (Dk!=;/uK%3upznzj|pzZգZagܪс|ucT,,;-dJs~w +dExI Nӓࢵ2 MM^cS$FE!-wƭ<:t|G=#1m;;|O9gk`Û2ow~֛ҚUHiFڌTPFDPfi¶H? e 'd`96\{'IRkJ9EyG\&qS$*l*ƒ SԄ mF ŅMzB<|i/ȡ@j KHW'QspR2WWjf\ 8N(QkNizlPfTW86TKY4J8ka sH5\)ʒs'`sPXeYkd˜$nw`ubJ)f3Q'Na&;uTuW:rQQx;uǏF2.e(FPiӌcՌӈƑX'$k1E)g1IJ.粦8o~绎ƸlfDFH)ֈ+F H)i'DI"X(52vrc]peLqvqR #So&&Cil\kGɄxd%!i1DUzhzҞHDQF1 )w,ܭhD9f( ~ ń:J8}*!犐~9G'ZԂʁ(-0¬ՏҔb£ XQhQPǮdqm:'E REIHb *6IF{Ĵm*,=~ 1AQdL9UQҘDhB %N2IZغ%p&=i%?IkНĤ. Po\ Rٻ}:˭cC1L1(EInVڑFĉ҂36JAiveLrp&\Ü+"#M70ނJ;>twyq+qH%b+~v3(h+NE NkLFA%("AQ v E1֢b2 XJ"̡)Ir.„'B(/SA#j6V!\쳭l4.̦exLv$.G Ȉ4f!""Uc]&q`mIRqq$pXlPy. qbq mU2H(!+uܒ!"!b5[m&dǰdb8Vwa:k޶B1$VlV1[h<3 /1#'yi|I12zzXc(RqD m" %a7ҪH] ݯ$hRlIeN+GQHNCôVom2iVW2"!Ê]E f%iЈt94 /Rچ*Qm)%-VkP kC9&U*-J踰!G$iCaim RK#oCuNwBvl܆dIj<i-lf f. LP^ǿLylbB(Cy02A ݪT4M63*.2*TqIPGJ6 Ť0 <B' Uj`w^w ϶k-SX+Ζ2fO'~ /HIP&r5Jga3Ii [Q4,'ۗ*Pr:]NȐDH qtiCWtrPoa !:N弰Baz4vmոIcvZc[6N&̌/?CuCRnVɄ >X7+Ю 1:r$wI- a'MuXM%YRdʈLtf=:^6ݏv>E+6+/#BA4v94x!+YeĊGV+QpEF|/\Q/޴E-˵a(nۚ_H=io jb]487''|Vp+&6 m;Yy"lzM(6I54||. Yem0RcÔMK$^ljBm&m##Y~fԦ倳#_RKuiYW !}ɮS۷ ֣a'V~~lTi״"ښj&%$1-6UJ& =4 &v޼Ґ3‘&i% &;yt:"F7'7l;MioeU9Q:C $,8@aJ "x[͕3~``x<ΌvvW+T!~zmNx8g$gLθ`dfs5O㌑| L0™ ]}cbLb8Xo>i+8N"фs G9sR뉰bc SZӋQm e@/̭߷+pypy<8 +|u5sTrP3 MIҡI\(d4Q$$F$1Z+cXkVȑ210xr.Gfk' M8-#s5Iޑӄs&%$8BW BLZ߉aL3etk: (ZG!I3H&2sNe2 m-W"1k )`<p~<6p/Hʸ˵aS fMB 88zr&{åtrx:Lp8$G [[1Emrmmvnvۯ}ǻpy?o^оpXrn]u˾=̓Z5g%}O‰~i+&m#ei5-QPÄ0rd\9بD9L)ō# es2#'Y9N\&w!_ӆW쇓8*Whwx~qpcw+7'yאґC%f;vМqBkzMT!ȍ„Lp])V.9NNB *ss9-Bsr= vkd!` ]`ҦS FwȋE{  ,ЉW8h4˒*;8<9'yrtov9R/}Da[X'[c&y\)ilj\D.;TX:ӟVq:qH{q8gQ*0y]BNN'ّĆuĔW1q1nhao|ȏ}]iCZ~ZMa(\03)i4yKVKAߢ *iŒ&T7O4:\X5Q;O~3^ٱ\i,|=iǷ{̋aÜQu%9>{Ux:emt Kkm Kf8֏m8O+e0uk0wp>sfV2%|Zӷ[["6FE QmX*[L T6 !$BB Lt3*prHʝb+s; Sbc( U1^m^'GCmºX:cma:(q6vzeiMLNұe&ݳpŞ-70Ka"'`cx>Jijqy?^оNݿyƷ8n : Ӷ_w@b2VѰjJ:?&S\j͹+&Ä43 , &FW꾓SzK^u9URgKj\ NG@xb*cBBHTYP&}A)sTzpr~h"y|+ g&vř+Òǁm۫! ωqE{?6~b?} 䍷%g#-vdm9SެY$0&I=+6"}NaVp!)E .io7]}9@W"0Fs}5x9OΦ]n~K1$r*il,U j gL'O gK??*6ét 2vi[v6AdKلpR1>۰[{WxV}q?V^? cx@{C\p=1yd_-׿[k_3q7m]Rj m& b-(gϩL8kMUfiDPVpyH=f'[o8s{؜c|×ϰÚǗݻx|k3Zxٽwίu_k1!srpKF=2oӷ3'~>miybNzDX?쿣:^ﶾo(+gX=0O$TZ.(Gi|#X&\VdxtE8l+_+h$S2I[k?aϯ㯣}-n?rۚ|$mn[y/vbx3%Öa{9.VKŚVR'J?Igf](i62;<췃6<tYh2&ӧo 3i,)z)ΓĪb:axyZ~WٟG0?x9Z(=p>[s7_b/)eg|=od9YctG>.&&͵Dgvcr` @ >[Ugt,ֆ Γv~,<ґ&AdPrHO*I] -^uNK8f6FB3?.64? ɒsC]swΩm./p9 J3\0);7Yե5,8~/r-X2vyk^{{=֢%1x~q8z]8Xo\QǕՃ[ˌ#6PLrdlŒN 'cBeù6zr׆qW+бbҪ4.L턲`}bЮf}BI;^B͆V#`~,2/:=5MheHºhGW߹q3p&|fXjh3^j)&04ӊZi' Vs*xR6) Mc7BC  p#9gs7OZ8qA''KVQi<ĂKMrFA94b^HL&fX1y*-vR##v2:'J֔V1$:IbbMfQzIRw:y'OqpYWu0_r<[0c9OxkoG`1+%=i ,N=(֬-fԚVL(DIծqbXD'd?' 4C8q*Oۇȅ-l+q\(1gOl9UyŽ2Þ=W9ssq}>~ ?c@ǣ>,.dWu^F;;*CBa[ٺy6IZV)& ƹbqxv JpI,H8QqdT鐭a:T4J0FɉQeNJpjzo-٣}9#lc<5w/_p~=/hN֫F:¢:1LGJ$dehf$LBSjh~d4hPǿ󤓉 DilY{-eo:+ogO^v+P#s-[mFC//q?p%kp]m:/_")F}@a#*҂)fAƌ&TG[IϔLD3"F3P-XR$l&*cDD+(c'h%9$%:֪=/إ21oJUMhWh8<8<8,}`}!P՜)'ZՉVX.Ta~hز: "ùUx+9Bߵns'8nΗ^Iu#2I8 uT 4Q#TqSԎjFdA1$ZxOT㱴+Vg#dﴓ,ΓE>/i($x9)( .%Br)p|}#>GyuzappG/(9k! *23A`RĎ,c!AaBsRi]06r2EZGJ+ QJ(2&XۆH84X,5c<p~GG>>Ǔ)rEOh#+>٢'4n[D1f3:M:۰Pls|;>W >opd9mËϭѸ>pP,օ Zk~<.@<'5'R\pʉ@v.聵6% n?ZCO=Jtf(X6 tot,!OWi'Զ?nY}aPx vN\8@e]ю빰1^kn@<'-NyvZN,?"ɚ%,x5ms{3D.ֱ 4'kyxz@M_Ը>pl8Mcji:NaFF##sAΥܨ}uv\ߕȅODwFd?tSn=j}>+}nPp&nvaA΢aR;F>p}ɦL{byJZ/}%O=c&n{~z-g&%mm QoQdOқ0[rOkk|ɵͅbR,nXۭ'Z s,l9(+,gQב1qǞD@q=onׅw^dr->;i:jY,ZCsCwgN(^g |}k۬y}DfB9؊BdN3ƅT,yR߱c/)}h}=6WNMհZ-d)pnD)sT|(6$q ] uk"}=6'6ؙ1a}fm_Ӽ,R+ss6bN4Y%'aHAʻ|Fhke˧sXT(uHn,3C7'R:1f:,5 f!:mܨ67&;k#j8{mmjicm[t:1GVǑ"{>6%[]rjKZ-EZwΟ~H; sv^?,x\ xrƦ:϶=/?W>wUԲI8s f۾=} sD;o-vZ{\A'Fl{τ+ZMӞV8]۶m:묳<3:000B ONNN~jw?^kJ=՚oւoo=yO|tТ邏_^$n{oK_ևsqƙ~o^|#C?f\_{Ʊцcw@Hs¥Ovy LwI iiw@nlM6t4ڵkk/E0qck^<ϻzhphthxxS۾OӗnGgIKu%ݠ:ϺYu{\p {l|b/Ws썕r'K[yݻky^CtM߹w+WdddtȖs?nGa k'6ll;r!E]4s7i眳$^v2 s^__xk:싇DŽ䞉Goԧ>;\;pt}۵׾O]?oWgopX|=[p=߻w6$ IsdM(a \:RǴ]8:62qlƍ nH)ݱ۴wjj&M2BRT lKۿW,ru̅r嗝O|N[hw/W&sϽ|eҵmo}/ܿ<3O.][6o޼ilæG7 t\Gmsٰagy6;4tzoObuX(lq)[9eֳmr莡-ݣ|n`y}>m{yM7oI+-wzzz?Z='p=Ip=K$'I{|.( RT*u}:==bap`~z׻~__8p1:o||};sW\qŅt?](zzzzX*f*s\ϭ~-ewuy*̽xERY?ok"ؼy>X}?/ܥ^z7ϯ^=y8K==&O$'YiSm'm`rAu # &=85====5533[+kI\xiu8)"CL`tULɊГq?}OWK)WlaÆ-޾ޞJO{ =z5|gUf :?[nquYK.ymJ3x;{}7~ NTCxd:ۦў3vwuF7 )q\VtG1;[㸾)ڼyR!ߥ͛a>;775W.ΕJjY֓IvtI#R1Qjב_-;Ca,+Bys?ū^6]W_viL:-7nyO#ܳ]]#6mJ9*Qbvnnvfv\TZ=4I뵽>oݼy3ҕpzzfR+("[|4G6yUlyzvb0j$ˮ '>^#ogyƏ}?~y]StOCW_=I__ordvV(%8RR{1RR6 ]iҺgkC~WrTˎm&MfBPK1CJ3\$;?J1Y _ŞKԧozw_W_}G>򑏯^{SZ?~֋ñp\B%uZRȬ\HT,u l6߿w3s #Rr};Rgh@}z{ bi]yZ盬}ί9vkg{{5iOږ[|{O˿ߺ*{O\!J8,^>"c'19Vʦ8az- Hu$a3j5zVb5T)xk:#R;Yבy.e?μs8 ^8|\aK\_J7G>'݋n|K_rc"q8R;vz3'ZWV.,h4wuwq;掿d۵qW]u9/zы_ƍ. >7x xyBkyCoBYDt8NLVoV˕Q %Dgh !4:<(r\"M6v^贑fZEZ嶅:ys?xwoz?X,VܫCG~ //9J${JR^<-<|%OW~N8{;nY{=;+"Gw7/'|;_ߵk݋ mW<%/sB{3 JR)ePuw Œ#LfWL4530 <$w[ 2 JI  6COpV 7 2..uq@ZsWlZgÂַ_{vNo~~޹>zׯ,u122~qyW_=ɇCЇ'*:I0O\A'/d>_ Œ8./33'5QIpƝ$Mތ8&m5|1%7$I3b$Q)˹}}}\>_pB(_h}4;;[]sDp񲗽[[jeꫯxogtݞ {ۯ}e]vkU?ǹM{L5>N=2U09+J]$($D0-,"yM8$ր6HdP 3hFSsj{$FUUե:{ct/$|.*NxT5NC3s ?鷏>ȋ WcpxN5s̢={NM'tꬳzt O]}U?馛/{~ p 6'n皚es+Vmhh[nzv~Ͽ˖-0w_pڵk`l8-Cy BuydMQ5Dba13r4KS$24 eP Cth.g`AN&C;aO84E 3nj.xjٳխqnUUU*|>?>44b" xP ~,id+lV`U(H ϸ\N2 "XQQQq\;688Nwhbu/=ps-6';fpppX5}H9[oLR\pM^?+.?}[Q]> ׸+o{3\h‡mۖWP~3O0Np'  k>2̲jǥ)bBAQ8,^' (z\ƉbXYi,,#LjkkJ~0 tҋ$))QNQf31^b*~Yʍ"LQ`єߡZTU-y|j''$IBS54#;y睵'zYf7fg07ثIy0('N$Q4Mf]W+.+TWV|^?dۄ}buf")Oi0/c].16f;/~<ڞ5zGeU2 k׮,xտmlh7$醆Ɠsm?$A u`̘1fd|<{H$yƴx;rJ>͟F]vm{啗7q{饗Wj9slf (d2Rf$ E5\yk.^u˖}f):&`$Ѡ hxUQs؏7ӡD(Elp0Eӧ-Z}sV+_U/9<):Ls |o۶~O 0y͵.9s{b֭&1rA!?]׮Ϟ=0665֬Y73}3ט5hF\C&#o25tTM|Zv%p}NyܮN%JR63yFC a}:SF=K؀Z0 +VА%Hӣ( 1͓D"]i#EX;2%UUJ{Ҽ{^V6aMB/#IÞH4@ITUYv0+F7#Ɋ(Ơx*)$9 x=,:nTVUWU`i/ /pݲTU5s]%UcD4!]R /᪪,DhH$2$&LZ[4K%K~ccCA`0ƭcM2LtuumT׹\p[[5\rϞ@?ASUU}d5)0mnAFJ$p/! CS"E`; yhF%?H?#!qC.MQCA+cA+Jp(y5`14tTM̶IX M#CmO;ohhݫ<*c>c>&ެ,F $ ~ǘ>Ah`i1 x^6)*Y__?/TE:{zzzXL-cIEAy^!#"$}*˒*@`0u\Oeeed'4}:L7 unf ^g\x=xI6Gu%geJxtw}gNd.Z/"577Ϯ|Ecm [5666$1Y(pdz>tADGfpqT*8g$ɒ ,): h.3 0Pd2(/p$hv:Lk>T0HC>#0x5(0 My…𨬔`2ZrPwh'y'<)---/p|N3J:(y@ aZquEQ33v]$)WlPxA*1趃] F*SK-u:|u3 Z]dE|F:M"C@EY6PR\O|tBjc0Cp]F`^xM4uEUUp)e~Z I! ]yZ1&ƍ@|9ם 3X^^^ap}555рv k<;}}=PٱcT*=F s96cI]VddҰ!uih"Y j* >udEyAPdE%tͩk:&iHd2BF42MExI%y{ݎp!EUy%Ƽl,p Lp6y֏BPX++h2flahֲOGsg,@}PGb/^'f~'?5gyF L&r@ @M4-CS},? *kV8i}]|r+"1U'',Li`(?Z'Vz$mTQKPdI#uRU'C>_8r(sX':liFr4̌yv֭[ڶlshb%eK~^Vc`'fΜYzye Ŷ>]?Q JC~-; -}߾m۷o9% kQ>ǒRЇ޺]=зqFxư0jj 5cژ @Qv:usP} P' N :3A }00(:Pt:kȨlP€qSULq/\qV5oγp/|`8.ekARI1_D's_0-`> I, k,M.Nr2$"'iIB 4HP$)Hu($ʐ=TQdB'xQ4Pi`|- J)j6ڶ4&<ǎeQs/ àR@߰aIAZ^P,8w fPJ~ꩧ(++/~_9EYTOmM-v 8#0IAuSFz&g$(I) M PCQa*H {DE((I2'JRQEQJ$I=<81LCtpѵ󺺺Z(U$Iv+W^xٳ{;/nꊩ6Enbv`ꪫ $|O;yOrt$)208޽{wqҁO:nc̀g+--={64D#pbx_< O:jڴi5ӦMD"ؠh_WWWkgg灶-8?88K 4P`^:3/Y%ǧnhժyG8矿^&"o;1[Ӎ`y=$J k0e97ul'',Dv-g|x>*hBv .:=y/Fh|mDBAI/爢Ԍ&uhf\AmTZ"A뿚gOOϡ^{mE ,tM.]y{6n||pAX0cGl ~C n2y>}k3 >WSSehWY6x*%1;0 NRIUS !:zlvWH틂Q!$BBWUL&SLxgW,l϶B㎃a|ڣwr;EL'w >wqy1|5k^0; /D|HFkdRL&i߾}Ѣιsvϛ7eEif"!wvPggg_{{q<...Mv駟 %M"tt{{ٳ3F +uNtV86Gd* ;{HK.]<}9~Ӻ˖-/` %?p6';ٞn5զp0<"A$?[3ڶT- {b(k(: K*Ji^(%Rr46`б.*h(74P,Kt b; }s2=$}m?|ɒ%V}w[nm;{-\/Xbyΰ^xMI*-#>7flBW]uW{uMVp7l#z_QQQe\1jVeO 00'#T( @vY'T$(p(PX*ٷ.c`#tJ~O(JS62e6kdf\>_M~宱裏=e&[sVXUQWW7cʱ9*]vWzɿc_>,pS B&T(ᐳ< ~oY(Oɚ6so` jjq[\SQ$L F=C0?[eDG]RUmqGJ\>$dlt"14ji@Fk|?L¶=0m1d:IWKn@i-ȿMdv>1EI1k`` W}kg̵j\ : YP@p7L&aW;5H<6[4lXYrǬ"p ("8)gϮ/ݔM5øU:/d B TrX a'N-Fm6u_`ܹs?u/~(ǎP:̠ՋM̓NV")T2!JR$OVOeCq@{>"jt0LNd}MUU^v8z jTVژ&W e5JXnذͻ?ݽ{waI|>F6<)ܹs gqvBmmm_oKN8cLX]`;E1Jq}%E\0sl)к3}X:*d{OqRSբX>?QXR*o(U,g(Z1f1,rm禆D N,^wujjZoK_*N$Cm ~vٙ3gΜ;wnݖ-[LY}d1;"zZ0}z{7oXl͞3w>IσĘ'#b[?5PH`<[* EM ,( \zP5.A<ͺ]TW@q$ݬKQQ<(k$fIn@ӵT0|>/tσyS)#+gmXQvp2܍ovDEYYY͊:9s>ɫZObDq<<B`j kh8N?G 2ᠥq EQދW|[nz׏;9=Ę'S9W(p0PIo[~:%|whhT++JE!q2c\a&nk1мxM+p_m ػwhm^%kEW^EeGA_׫ Qd屼Id`16 ^,{je e.}QVh" σWDba\;A{]}}h"%HyҢpȈ _z'AW9s_y%Ecfݏ>^ACEy@_|%By];my~T]UUoodol`[?^`uU#4703q ¡`I( ~t?t2{`?Js^( TC>r8lt"҇: }5%%%Eu9:_& Ctuv~y| ϢE /{,cyi.1:AQn1|@I\|kWl3kCC fiUӠ &/iapp0{;>x睷}?>p!}3k*,8y{ҥKg>SN]QQQ C֠/LXnu:Y8U0$~LIaCǂ^Lnڴ1ǡuLK}ӏ[;@h5DMKD~Ebp"(> hjKsф#e).b].{}E; evFI _jdU.:I/YrR;oIt{D$a2@GG?p8RAm~_ݵ룝9~W2dZG$J ^6ܭ>Ѫ潟1F!Xe?fFY IRx2 Fh"NyɲNy="2Ψ R%ESx,Hr|Fܬq9, (ChY4$J-K^Py´ɷ~{SQQq%]lEH$KW]uMkwhό჎ct#+ 6|^+{Α&wGGgkS]ө3q***j,;+e\wYy=\Ʊ*wxA{tFQ$%B)]<~0pK c`yԩrLf0xHBd q^wQ$ $B:XhI.-2IQQ?&<'"`$H,Dn0G? er{zz֮}]'30 ^xbd̆Ⱦ}>HB:I~h#)evYChIuP %'tFEIMR(e( , !`Qc<BaAM"IRM$\<G.hn `cTLA[{8E*++m]y,G1GI?_X򴺺'tz7 &: 8IRQd$ `5f@f&ɠY&(.)s).␬A5BF~8&$0?<[ב;9:t}P=yxg̘mQc_~?<#k!{sή;䓳bofkAt}{o$;k_ۢtE'OxLj;c #9jMF5bZ6(IJX,J$h" $u3C h DŽ%IR)NƓD*OrCA$EKJp[mv eɑmH>K^|G5/_SYTEIV[hj̘7#·L&_a;Odnru~渌" JqqIz≔`(:\ |d< ɘ!*ȪTD2֓8DzpПJ8Zx4AEMդh,(](ex#P0s1?ˆkCGG^`57۟L&c.*t^y1cƼB>#L''f/ڳshޤin&H$P'd22qX,[Ъlڴi *[B, pڻw_˾}{x*s(,AQg8?ٜ䣲yͺN7e,'I3{s=^&x777'``Ǡ@A>=\yrn3|5׎'',hVS=y5fm_[Tł_t]EQJ)*Dj %Ig2 Prl CF;[P;n>t@ }і{!$# 8(]CPu]Y`S$d xk=[oe,{ إEB[p`]˻o___>Gb@fn5ɲ/5Zd{Ey^Jq\:LEb(iNE:[QVR484 4h*y-Jc`4KT tM򢊡Xt`HQM{5oJ# jO^z-7]T\.:di `| 1lnF9z~%Y @;.ҹS;Ђ0P2w?R}}G˜H*,^RLr.UC\/M&SQx.Gܒ$I,z"%~M׽,kTYq8}yYEdYGo_,JyfDy@35Ox< j6(;i;(M S4*h=j ~ϛ@Ӕ?D>I(ͷc9?1@qbu8hfP(詪 VqgqƹM ! Hht7~ܲku664Tñ].#h P__<'AX5)RgGg/C2 $ 4Ijv5sKtt2e:AUW_?=v8k ;7fdk]Jj$.nDyf7mڴssZro___)OyRטƁi#|="IK5QID7udBv>vf8 HM!HьSB`@?ɍ7޸_OO QH̪!)tyyyjڴiP0e03 .,.. Bl2(ǧ9X$8PUUUZUUUYlZ@SdY/,*j5:^/AX&#}̌ȏ̏D"U7auWWWZp@^}=?MRo|_|ꩧ%5 -W}Q)c ƉmuFN`$Vo9U;hnO`͇BAG8E:&:^A+[0֢@AK/0PN4={V7\Z%DuϽܾfR}hCeT2Ys9gƍUՄ S4P1kjȞ  hϜVh ]r:^'8gʲa;DIu`,P PvˆXbxb6ر}i5CҞaF 0gBwp ꘓՍ QO:SkFcQ^ƺQׇqBu!l؞h<8$R8Rj:p0auQ ≏,-x¡(`cn74A#D,Lmi; YCYVBE !2@ t2(`$okkL)DÂ`a)LQi76gʛo;}{}q}ݖ t=`0k1N+,lG2hwkaF4y  kIp",XVjX9n#!N|>PG]izhݦ0gVwj:udEQEZOOOI7ЛWUUU}5BT {t:?cifa"m8h2LωjqQa2V61㛨ʾNaj Y`5`SdH? $455xV5] p(aت @9eE2`MDhOOO`zmmu 4Ejzѡ@>D|8TDJ8hYYiOY%x&H}gb*O0N;hc6H6Cg9NgP XiD )?IE!FAZ-Xe͚ zLYopy-\n`&իW?Vh( @idoe7o9|Yjŗ^|??VW? 2aF9d>/X^^^J$İ [l}_~~鲲Z(4)p+$KQӦM+ldxOر+˜0 '2$t<,A.^`B>ID?\^' rC30QЇj9ށq J|d`R{BqU1 uYEc4n_cyNqsZAkH$Rf(q( "0C ~mK.]'_V-XweȲ"DsKKΝ;lk߳gƺsfT*eI<1>3%WCTU JϋqU9Ps_u9Q:/.DPUEJt<'S1eIqʌ 2Mh<)bQ~̆o70YfeSs=7VWWd-&!yԴ'| lؾ}{gwwwk]],pɂ ;?f2n߾vC6:͝;,ߟծ4t] nhh}43 zc ,͛{\֋~p(qˆ%p0e(p2JRY:#x2c2H`@DWÈgψb,C(+IKk)$M@u d5՚u};o919;wwA\̙3+4a&p枷Pss?}+Oo{2O90 "<@UWWW PQ#˒L`*~XXLeMU5bpp Ҳ#*˒p8ҲYu@/g@Qd7LƓ4T$ .ܟN dD"WdEx犾_rSSNp]zꩧ~6SN9yQ>?Po߾c_n-XPػwD0b|X%:H\rX+%P22\[@(I|,`4>$`Ae֡hHȲ%65Y >S7 @g$[kk{nU:,,q8d_x]DEi^t-YB;v߾ڏURcje(K%IR"R \fϞ .Ԛ5kw͙3rɒ%Ks*?{sm]t9H+V<ݻ{暳/^;v-mcEQ3̨[]1[aUӤ G&!R\VS'Y\Ez=V4Ѓ!/ G&R`,xtZ3" d)ɲ +5Yî HМ9sڃCr/ڰ{ޛn9sXa@Vy3ҳf5VgƌËX,[oi;o=3W ZuO>Fh|߾2bcǎ'9ݯj-r#;9۶m500mΝ{-ܲGy:te_;FΝo1\0;l1|c3?W-&I"bv哼曻b be]YvH(h4'h,YVP缡&Ek"eeEzg>W9xX__5EEEt\NpVtړ~'@bɲF։k6 /??2,\p;wy?6|Μ.wIY-pN Kyع}O_K.O>)2ט CCmiJDFl T-uZr( dNX%y}nAҼeXlQb4ɋӧOG5oj6UwCvx…Yu}}}mׯGP`-h,}R8* |ciL@-|GѾ*$grړO>dgggG5zHi8?٢(/nؘ`Ν;͛ﭬرcÚ5k>aL}1HJl( طE$k H(e$X (n=Nnv9yx` 0YdYQ2H%T"Ht)L**A Cyn8GN:eY#[k;vt^ e)O,XhǎA;pbDXbO>yF$׿զޯ]vWj.]Έ㱚i4Z֯_Jssˠ Zv===s}?}o9PTTTZ^^u]k_[o"o߾[ޜ6mZ}{_>~CPYW^y<%̰_ ̊ʐEQ4/..CM:2?+`$K(I1Q}TM\.XY9KPvz*b AOũp8>g!z!bbٹԴnݪUns,nUW]eXd-Éᄏq5](d!G&瓀/XSMWq)?64M%q$].7yС u ;c*geN' e>(f4/Ğh㸌kkk%%~h|~l&( QMsg<VCC<Ͽ[nݘL vtM|gsN t~-[&gf@GӴk_vc>_ њ¾F 1QE "6Շ(TxOHCj 돂:iNP1 MK4#A` :N`B_3JyTG)Bzڴ@ Eq裏۲ekD)'Su}ݵ&,X|[zI.kg} 3|N:@Ė~aMcqذi6r PPcvR:GRU-)+z )C\FCo i5GUh4-tc&v;h3_3KSOf FfJ\ -oA6򗿬=dmHrOs,gk۶ '+W_{:/,pq}}\gGC= N^2ex?ϛ7Ԋ|: 7oږs_ҿor55ƅgyaسI@KwŒ^O' aAg 'UMtGN Fx@0q9]}~;Ueƺюd*=t.u:9?Cf#9vNM3<۷o_;[vY__֭{OzvH&}< !o1F$EojjZq˖Q{jooom=?PU([[[;l} I:ND斖}۶m{+3I]I徾Dkkkm׮]noCPv0l`[jjjN36ƍߝLn0 [@x7knni8?[׳Ţ׬]kk4kz6~*3O0>!e8Mx_QZ65S\(1&{e9|p;Xq0VzYG`gmkH9*5Sfjz 6m0nd̓ u]p 먓/C?O3j0Ο?VVV^wu-ȇx<wp͚5YI'Fw.;F!wTg<虳4PBTe]uyPTt:)l|Gӡuj2:pb,T|~-M'AAbN+|Pvx>ī ,}t<898 `b@6_|hrUӦM:þ 6l PLyI4\yg|pW~xMq_h.?_uU=ՉUUOcS=}Ya[SUKX7TH9NX)1 ;7N$+(QSGt0Þ`K_[n}Lw{WFHj ?rKd2]yE}pp`wX[~_dڵshGx_ƃ RY.{[+V\p3|}XwWܲeB:ޝwyp~d3kxy>iz" ieeepC4, Vm~%)L9^d @<1g>?kȬ(IYVbJ$irDmh Gw}WW_ClSO?}_v5ǨVx>b 鵃4M[35`%I|k@IgQQQ B˺!p;XQ!Yb]0pL&EqyyH6ǯa,[l= ״m۶7v vg'XyyIkSy10NT4 -Uj6>d' KK*˫,`[ZttvYt?{kXn}nwjAQ$Iu랄N+Wp$O,5q370^x~j_gϞ֭ Zu;`Bx8e]pҥ644-...;x`CZyW&s<׆mJ\;G`$á2u$ζCbf*T$UU"#E::[pW$IBv3gN?u'̏'d#Pug͚u:i?_+4K/tg}vcc<f}+X;-[ְlٲjjjj,;hjjl&r_-ZT{/={ׯ3l';?wQ$,-))*..*g].?DGgwwo__4w~|P0+)))*~EU%-je5` i # ².`Hknٿu8\c;U>NV먅$I7n /lMRBǰ<&:61\.< P1Ԟ;Fm"(h,ꪫλkf---<xPW.fe&oZ)G_$ǎmJpInX_i(bX7ky晍l4;!qmQ5pfX!J:}M(T)G8~e!5]1O)Ј$M~6؁,P:A5PX3fX`Qu]_~Ke  X(U:Vdi{< t1E%m2w~p8Yu݈@d*1 'b"L}Ym m&Bl>MSX9]vrІo>q\k$@i(iddlÅ!PdvXz Yo|ZŲdv;Gdr<ֵev]#\z|TյLĞHpc,gMX Q+g1N̮[(*Y?1[6gde1L Sc<M?oppeYVUxA 3}msG pPS^^^f ].4ҪFnemFx(DY4+-GZ30wQ2eA ;ZiUS41Q3-+#}̝4>H;a D bH`ľ ˮm{*ٶ$Iy,d, Nm%0-XmL+++}UUUa(c{<^`cmflj @$,&ܛ I $܏ vɅ!/`/Y<3Ҍ4ڷVU|TUwu4rZz眧W7gp85 bR2&`VPsuzZf}@ oB%K`MkCoqI72c+4MLy9mR\.YPk/bG K(0&gLrM)-Uݻww\vs ]J&zlT a G,DL bF&\84Zچy(bϞݝ^㩧:N+#Oy\BXI.%,D)W+si/A] *#ZeHH77ל6%RX,}|s.* BJ LI)fRTA#9(0%eC>@ vldB`34BR[bF4 ۷ossٕL;Gh⩔JR2 #Bϊ/Y J}Sk4)s2ISw~w?' hT*4ĉB:O )Jg2 `9 v;kE\=R5;::wǁ.2J O8i2ɓ$~ !SH4Bzff{bBggnb~*^4̖/w޽;w B t3wK>}:!T&i\Le,LN/;P(9ގơy2.5qqɅ-Jؾk8j'O>Yq5)H !<5 5\= ܆0!^P(!R=4nn4,E)nש1Z :V$mI;{3-z:A̲g䕗˝]lfq ^;w֑plL'u8hRq0AKRtJ!^2s%[@_ Bd9lqAC)ez?Xρ2 tSK*ʣqnЭ*M?4SO-賲}%WwZC N%e^73fYe  dl|/6Bicgbr(b&vPƥg̢:%[h%},ơͣq񎳽VA !Ԣe, D†L҂x|x bE}w듫y+b?;:Ç< s{ы^MozӍ\rɕ=p8:<<|̙3'?߿8Hu^s_ݻwf'|~+~bªP(kH5CuM5Pi2Ԙ-Ls3٬U(LPR&\!ͮn8wouCYP0F$lțll/xQ(/abf ;&vK2 M#JƎl.kfR#Ik4s6a.G&4ɘB(Py*u2,KDJ7 B!# ipwwwk<:ujԩSlvx= ;悾Sl0N ,ՏYnox8 qh$@Ν:Aq$}w4U4M-ʴǎ\NĢŎ.D8ǣN:jlrr2mY"Xy/W$777BVtC-ֽ"7^k׮ܶqXc޽{^ᆷ#z[ϼ뮹o}[?MJ}c>MDbz 'W=颋.sW^zĉ'OHOiffq#Qt5 /,i'O8y'N5_pt 8L3O%ygj ֭[wӵ{wǛy~O # s0!^ꫯgΜhީN&p(,E__ܼ}ozz:AfkkkszK̟Lǎ{rbbb좋.zn<oooo~_o<&Ho{ۛ{zzϓL&z4D8pjE]nEgcY@SdPhjjv_pm۶mOggή#MMM'GFFRLgi=Kz2Q(@Ǵ,4-(z$ aEz{{vuۻ@oo@ =uh4:JL&ann1A@@k(q )`1˒,aT8?%j~N 4W}`,SxFj8Bݫ^ر=c%qsy{o{ǁS۷o߹k+be$ ַx_aw?OW+^zٳz(-^rBl#ȟ?woo7^g? M'kgJ 4Y65Dzrrrm[gggO<o} >}zthhh:Ljfffnn03L>ˉH$Z[[c۷oݶu֭mmm-iϜ- c///@ vX6mX%/HrHGCЄeJG㘝5ΞqB[8uȩSH0 #L&Dbvzzz*5B>/ImkiiK:G7i[:⍍chddt2;Cyn ^_{KչwFGGGN\~ϭLꈼm۶|>}衇~sEK19看7"=Apc,/ݛnM{^ݮe˾}?ç袋vOxo|_K^r}GGGw]vqu^iL{(˙D25>>>m۶Զmvڵ~L&:ygyȣ>?733N$D"`0H|@7vyϞ=~/ڷo߹===[ N'N>}x``ę3C####t:cOK^g65/ff&^PM|@}؁؁;ζq b_n7bH ;45fۺuȱchOښ[{];vLM744u$fSTIcΝKOGFFO:u7;vɓٔsc+/ sc O'^>e"^x;6j_ w v;jq$gqq]."Zҭ39|x2N8yj={c&e$bÇ!Y :c]vmݳg455,gΜ;oYy5fNfҳˍ4dx8믿e龗f?OTy{'XP(H$x Ŋ$vvvm qL>}R(ι1222xk'qmkvnji_ bbb"L&Gg:4x3\r䳟,D:wر/ |4#?zXߩSOȶm۶^|޽{ogg6fӏ=_={ꩧ?3l.f R22:BR>~IAXxdB ^5b1NAw,!vpn !2i<022reۑA)J^țbbb2L̾䡧V_218222vӧO>=0JGCCSO3ù\ޯqp.- G"lf C\o[ֽjLzRT>_1ZZK BXfkt]9𒎷i (9(?s :xxxbbb@8V߱h#L9YLNIE@؞ 4\>gB 0Ny8rCCC#]]][+hDc0@5O:EGYiӓI8zh ifecc/ ״^kzO{=:Dj<{)K_ҏ^W>$ * vxe5b)w~R2G㳽/}̰=fM̤fJG"Js\(IԖ8肔)Fd2k/8x`Y5Ǐַs/ [vm_c`0Hc{􎎎9c3V_a\4&u ه&CiQ5̀ _NJ/_xPO__![rKY7vFkn;H  zSnx<nhhlv` 3::::355 -ӉP(lhhT۷H&Ǐ3 CKgSDb&9YPH|.iAԥ9(O%bE1rE:FbG@@_ v8_0"v vĎjc_|̲bIFD5sL/Y4f74D("IFGFf)33Cch,F w۫,4f9q,,d29GB S-Em;8jh/mb{uY2 -$Il53/QzH0~o22I"_yP^lj7fVť}\jӟp8*]]]-{ݱ}ǎ-ͭXG*ʓH$rO: >M77TӜ斝;wD"m^t@ɾSǎ=7433`Z0 :LKjge9OO(xxxbbb@3(8P#Phn,bqPcv@ Gu=;*8MN$CO:>555;888ӣ4O8ޭ]x#'faIsŹ0-ΤEˍq@\zի^L7-,O_ϝSӟIeu-/KZfoW(䳚K^M9@@onnwww{?R- c<ȡ|op``Գ 1ʚ z*]۷oߙ岳3Ǐ{eYyMD>/\NX3JQy%K ^lx! cm l;  v,'6 vQ98Ṇ_lF{2Ͷ:>dWǂn9sv^u1Ȉ<O 1˥^Z1Koo|.Mck" jRiRZhjF8 ^V Ouڶm[1&p8 \>88u`?E>c 6/gwhnnBbGkĎR8A@WO*єY\ȧոc)P…ukW={kY‘H646rߘeKssscɉ'OMN'NT*5֦E'''Gl3;;;fgt잞l6MRd"[l>/x1::x5bf ;lOf.-vkԀe$#Kfx,ihooiob ˜;&&&&NMhfvvujcI$fR̶mݮ1555dRh,ѱu65ILV6%RL*:>*p%\vi^L?sW7Uq9ߖ-q߾}o _u\xY/VTsBa-QӲ1udz*r)ry4wt"WL/_5qy-*2L*A气{d_ u>*#vR7i,2L16>>>>53)l.?ORB:mٲ%v饗>I*511J$3|!eK[iZ`0@Ֆae + {[FGG>IIKϱ%(k6NONNNNMOOO`G hJ á-[F&<o'&&陙 mo۶墋.ڷsDΛfӅB!;000:1117L9'c0M3G70}v--͍H$D^zQnj@@@@_1?`։M3fiK8|23N+d3UFwBiS3cSSJ\N̦ىl2r¶mۚȞ /ܷcGelgsN457EZ[ xSANGAi5NH$,!tMB¿Zz psK*SƙU8'&%.R\ +yr>v!}K{{aeԘ:&,MX5'ft?S>gCCCӿe?NLLL/ h(نappDqr{-BP>d29Ϫܽ{yz!ʅ?нb=MVS93N$)!D,5ǟK IQx ˚GR71RYzozӛ<>_9yg9oLձ)iFZe f?Q7^|*jzɓ'GzzzZ/ `N?GziU$/ T+OQZoi\f2ed*eōl6x;רA@D;i2̾yBŠ]wJ7~#B< oq<ԓ1=kK\rMi韒ơ[dҲ4,rҙ\WJb}}'GNM`HH!N=د9s  5MiZR]ВN`,,ypx"8_l1꜖=܃^E\/H$fxY߲`JYR:{W;_}=L;Sᄏ=:}?\pdbI~醴NǛK-^Dޗ`0ICb)Z$] lL~pg.hC8'fS79= |Q(6 //@@_} ~)LYN=4===ۻcc{?\p4cVz )Lqh:WC2ܔ%N&5Ex8 F f,sy[PR0!$I7m䴤q(CMg"eY͗ŵ޽ާ333>ϫ:1_P՟s?x{޿}kiiٲk׮x'vm&_ߡC~^ugWGGVMMW9-P+5]Wr@0]7$yWƳL2I*ZZccc}k{{x45t]C4͂RM xt|ʰTtM)0:@鋌xx2@@SZQG}hoͺT2sC=T}mil:J5.u]5M6$yWRn 45 Ȗ-[:;OsSs<IJ*_Nٗqб *D3UY0C(kqp&gP =eIm׮]뮻%O˕h+100pcǎ-Iٿw/rK Ȳ%+-KI3-I B˶)\qNR\;@Xx0^o.1bzSuH;>'jO>|V;/bIؙE2,ɓ'l)R)MCsgܒBҠ,-3|>-(pdR %d%i\r8^*6/k|)s*|_s5թtsJ)҄++'믿>OBG?k_߽o;ZWUnfYnGn[~Jהgp> LBLB-.Ik/?qǏ~FFF nS#[t鸔]mHϛ0]k/0Y/&žzxj bbt~C׽7w߽x?׼շNMLjLj\WIRȸ+a&R*=L+LMM40 |~bbld߉C'Ox~FGG2tFJa2;`)%LMW"}\TY08KnKb3=ʣJ7[?W/7~_g9@.ZxUzW]uՕs yرCǎ{k_:thxQxt]Ͽ⋟o߾t:3z衇~/dI%w=Hw܇ahk\s͹\s` =#wߓ)lO<ԏK ^OFg% v=;\W]~s4}СC#B,~,B׵Ŏ뮻_|ѳw N橇z_J&8s581 *B"pI5єrM EW_} _xuIƯ~o~M<GQp-lCee*C$RHx {׿}~oRΫipr2+?p+ ai9*v庮Mwղ{NGd'OOR&\R#jc8X//V، vAX9`3bFJ(E gBC"@nNqY(Xs4M;J$MkFơ~.Aڹu׮qɓ't'+t1yP&e^Z{05<ژx6tw75c?x azZ:&rEO7EY +ޤT =3jNPqȶpL8-xr/fc vbA;q>iy=kΖp~)e^ [ZN8qH!?6wxZz8=ԔpII%I6ߨ%rL&azzz{Q-7/CO7āKEU W9̲}<`SQn4M|`xz ^b6bL v,T6(_KrBLILR7+7U]sq T*IRHMKߘ`P_LC0 ;Gl٫TM2]K`U@X}/fcAĎl;VF[S$Br#1CgE)R#yJ5%{K{B]ܖ9ӥ)'3Zx P(&Um2YS`Uͥ;@ v'[Za^%`R%Әi%٦T2(Zʬ' uM9iAN6_` kL  ^l0N[bΐfF\t;<{}J}.^I/,e|i{_R9g!^NW{4Lu8'K xДqR&u.9K2ɴ'K4)eg^rGٙэq邂=l mшR/Pu4J6xfΙ5n;QAyW\uEv3gm'/-e922qۖe/_ bzAYvnt邖ŴV޴lV HЂ MMcf^ۂRKk?1qeFׇFf3NOH!'--d"5BޒViL(U كj&v {/;5sq&9Gbsk7Y&Mf Mq]יs1Gf/ʙY:\Ev$Lr&N%siʴT SHLa͋BV4uN{޸s|Xk KP8intou;k ~v&)u)%h 9e3j"34i +^4Ct]R+HY)R[RnHO=(TYsɤYZ 6L)E^H 7eTTM4eH60: KVY+9ȼ`x@I'1 X,Q,*-HE,05{8j8ײ9Υ5Y$UHfK7ʘ9E$ӹ &rBLZ `E%?,I*>K,:UOz 9ŔJ642*wt#@P'3dVGʥ" HŔ\IX$PRиF*o3//p%dJ?tߎ㝧G" Ӵ-+E@c)I / jB Z*oLg*)N:lK b@ HJ$Ps \YTdpM2iiRrriqKs&I6rɠrW,֗2& q;S,@%mKɥBITz:ʥwl.eK b@t"$(H5,nTmxI9T4?)KA,SZ©EQ4ߌ’7eTjRpJ4LJ$2.|Kij]idxK!;aTFv[;^7ee x@P;$IN-(RB)5iK1R)S0!,Saq/9F9%ґ-玫I[x(>a9>T^\Z25Uq\2>0:Y'`NrR)Ts%)\Zz&~~_,~,?A vFw{4&MPBS32DEl  RUrF~SRŋfRUbjWE 4ɳs=/:o[ݨ eWAN1'1tA%o\/ @PCG؍5YhTccqfVz 4 ٟNfp)I)`On+\)Wy _/;kyi{X:=&qr-I{8+IY;֙E9>O1ӽ[tj8Rww%:$}fx V_?P/ ^iA v78u,nG@t2)1 e+z`V{Ku*'ҙ G;\6K<ty @Zl*;j $*oK׼B_a+J9$WC zTo"|(&yfR^^IU r rvKKhsKqne[y @݃x@-o{z̓Yl/ wz /H5'9m9:o[?PP ^;wjyE"8vpDYZΒł:v%3 B/pqS [11΄39*mN) TL,]FUNjm PASz:`?(Xzۿ?A v׳ɰ\UqpIܶt8-;3AqvwSSǹ7u:^Z_v 1|ߗ,,#@PayAIɟn%wFMm|f\ =#ks|:Si) f%c\9mR-x^P ^;wj=z\ Fz6W(SK/__\[AWy _/;qخAc?i֔vz_r5 wfyW^_+s x OD!bimz@PlsǥKΧ=̳ʋR'?.vK{[-iIޜs5U/1m7l% b@mex|Kb^emrNJ0m7W?bwd^P ^;wVQ1fJtZ1ѭΘU4T/S,ֶ#M[!U@BJ.5.p{^ۥ%o\z=h =.ݹ۳ҋez^zwk xOyq_356bIUj b@ F霫0+()N=ȼuN׫~@PTs1GY9m_qV޾;b!M)9~i/hq}!l/;5i5iy^BoOW?Q#y,r%@nd2즧(z^+&`!A|y @x@X# b6x ^:_WJkv ]83M[8E0\*<)qf[}gA͡,MB#=,(6vH蟬/%zXr)l/LWʥtKy5工wڕZq=Q|qB2&g鮇%g# [q|~ _51ݳ,^`I'u=s' ~[y @}x@ g=ISjz'd))λ,!ҿtg{W{T؞GGei($\zmWɪ6cyK^_/qPNιtpm/pM:h;<|ZD#9/',{C|޶E4k&ȼuN1ቯ/t?͙`sƋYM biDJ1.9ݻwS6_GiOV-lt*xDz)_uVs1Ou\=Z1ð؃' `ŋ9k ^9A,#rlKʤT9AYWkHTKB.5 uiQJ\Ac wjҮcnq@1qzx^lA"XtoIӾmKWt\0@ٖ})Ri:n=nFe(Gꑕg+8<-h$k2/ASz,lvA vjKkLtfcqliG%EdK!h3dRzC[LcX-񘔪7-,ڮ!/ASz`?Xzۿ?A vV*mJ: Nq.0UWIJs+Nޥڔ2.55UZ0)5)F3B[ш&ee7`Ra`e+ ^ax$E΁V:ߪkKPu^o{G% \ri1j:)90 =`صw8 axxDL 'BB-B nYho!l2:#,ef`Pt ʶc{Yi{o/gM%ˆD32,nK b`u\$9|IsurԨΎ C( SJIL- qG 5t_`'e_r03i1HޤB5$Ml NA vOc3ɀЂ.R0t h04nPtrM< Q,x[knՍ!e8UBʀo0Ҵ3MKL05S,YI` 9kζh"Խ(tnsϻmntY86<0Rbbɪ8R,8~%Z__zK b`y4a.40t y8dP :7J051MhQℯ&G!wb%,5dI]i64s֒fb$\h̒t)L`q2(+Ey'[.yW|\Js̛axV5y X%?d^ @ vh 4,'8!38jgaYrW굸BJL` Uxk$㖔Ҕ}-75Q..r950 y da,dtF0রX4Y.ޟ)syKLKBJS2P1,+.Mhsgyk*sח_+y  +_/Qř yX6k?t΂!] F 5u;uM;j07]~{~tlu/p K a1iMV(XX2k`Zܴh8`]M\֘F^k&/ASzZ042*wl&/I&+jIM"KS w_0X(H?:3 iuq I>g/L'-_5Svְ%p>ՏL,YY2ad`=ZT<%yP謿;-;"bss[!?2yYCx^y@ vJJI5SʜSigcM4M43Mt=lqc(5YɚBeL:bY<,̘LfYiie&7()/eɟҭQL JK=z^ΗPYri^/ASsX P ^;'Qčm!'L&,YA4rs\#ђB&Xғ_zYw(aͻP#Ʉ43&+d4A2-M*D&M+IsY riқ#Kʞs,ݥ{=/ )=j$3KX4,n)yk\ZF@V鑜kp?/ +x\Bx毳vA2,B~)Ѳ>$Ko8\͕\w띋{^]C ^:~b<\Bۿ?A vVF0i#KKcg iE<5ɹyD^Mؔh%IGpLAk6a|-T`f^@%TB&AHR2.cK k^մkKi<'{QZK6q#J)gG5z8LKSJ2,Mۥw=hҠE &-7,i 9GB[5`SyR,܆% b`mJ:'J{U%I^/ST$R r&nlT\_=/"| ="J%\VV@nhdkU?@x@QC !UƤ]ǜM3'Q7Ll\ݶwOL^._svmx 6ݶ-V_g=2/Lbk'P^fEx`ߧQ[T⥚a *%[o8\\wwx^.8Ptf/)tKg֔Jò|׷ F`8o'>L6K@x@IC2&D1xSIw6y/#顼4{ΘShvqwl;z]<7;Ҷjzo("8lT\=/"vܳ-jJs `Syl/B0S.y9TQK,+Vr~=𼜓 ˊh^C _/ws}e^Oͮ6@uNǥzĶ@x@UA?;Eھ~ *lh굥_]ͮ6l:_ y X~nu`z^,ֆ%gתzxY@ v֧񹣷[+$^i=/ΪbGs3lut y#RZi㠾Q<3z~`7z^UkX`J@c)77YV؟yT^{%%]Ϝgl/[^hg?/6 ;޾'ނq g|2?wS; ^M%Sa%d< ^;X+`z^$ 1JX~Z8;^j :آMĶ@x@Wb7v`݀`K6\-0m7Qqȼ`x@Wccc˽E[]_#0m7U&X~rr8 Nl[^βQn>17j9/Ɩy|gl/K6cux^ `q x^ȼuNqζ{vz[:X~p5{`YҧA/Q?x UŎn|zլ!(꜒}J%Y%A v֫߱坷]&)ll굥_]yοKiKx 6תzxY@ v֧񹣷[+d^i=/ΪbGs3lut yPY)6ꛕ/`x@XAgQa|ǂL]][ ^qئ sߗ/؜ v;w< e(WY:>{ڀi`xljm OlxX~p5{[0Nଠ~CU[cnvzesKVKBKxy@ v֫߱W!\y5x^8~ |>j b`k?`mXy^LMiUǢy @݃x@W3_]?)lh)nv~R={v+۟񊱣 /Sߟz5%cȿoh 2Tn{M b` 1N`D#0 9^h5WKTx:ͮ%wGQ_6A)M*J ^KߘK;ŃPU;z^.OYrx5@u1tFZ|i=vP{c2Ip6{pRm lν&YKEY lz//X v,qɕXq KG ّ쩊}Nƥ :n&;}2.RInIBdK S9_9]L:3ܙjT~=.=ʊ֜bG|m=OY6 ?ڸiQRDdm&D%CVy-!DUbyq4R2=d>[ PƵƽc?];]zښ-jmz9[,؆ZxQۋxx;@_18]q1 4 ʣ;*kKB*y_"g\KhRSP)x*y^r_9oxx 7_33331>>>x'|Rj}Y9tz7]q Bt:<裏_7cREi[^s5׼{WSSS8uԱW))efkWl۶m֭[wLMMNOO=C?͇~k[,G%|~6xٹQ,]yp|L+VV=/0KYK ^WxjbG} ر)X+x;6~h4fb*+ŒK6@ޕai ~ AMw<3}\f5-rӛt>ؽ{ASe'N<ߗ埭Tolllۏnӆ_[>t኿bz׻>ԴeNMM~'wCrM}ɟuGGG|2M3=yϟ?S}FF bhȏBHlRsn+w=w|!Q˒%h;Sșp׫9u^H[9 MefV7+t>=bP>z ؁@w`Ro]WmO0N=cUmIʴHr.엌4JT[R̠ M[TS7+VsٸWs)s~bz>4r4MM+'9 fNsvsNW*itN^xq~?泺;X4349aH4zzXHD]FN"&,w*Cc/7\300pxǛ{^y__MozNoxL$ӾcE?Oo} %, ݐ_?]Jsܟz7񍿷7-m񖖖g̠{)ϛlrVPiѣ agkZKssCKKs\tsl>\B665Fct_ї6O[r\.dtK^?&YZ_NamoVj4M'eB\%/6o]4 ,;;c~(ځ~wttlilj{t=e 4f1 Q,th$ ꚦ47ZZZtMء B:= fTQ1մXSSSzKJV(|."H..4kݮH$AK[ĴULvf^t^YKStV\wק_*$a/`N=zMplMWwRekSCEm_+rjl[n叫.}z-ke77u)¥׮w_׿{n]MH~뭷Կ-oy7x;9\~c#? Jtuu5_x ]g][ `0G=vzWW ?x%_K/s~oo֖斦P(%`Oז ?]w=]--p(3힗8YV鯂xQsωFƉ`9 v v vSpڃ~wtvvҘ wg ,4T ?‹/K.9sy==;ZPU[w;pλxmF1 U$IQR-쯔:4Ŗb/qWk \u9KgwGGoz_f/~5\{Mݿ_^wᲛɓG?}dddd?=i5\;ǿg_CKKK<#SN o~}xGSկg>Cw8e|?O<ضm۶ݻX/| ;ow}/*0`8j4tsKXi<˙I2l1n%}"ƀau]¡@,g@ v8>wsyYkظ#BMCiQMc tdiwbW45f @\״iHD#aL8H % R5D29K"M^dCA*Ryb!hzW׮R^f-*,˼4nR^U| kŪd^{yx_?}-|u~>So~y-缯x+^}s??}߸쳟?NOOk.O|[o}3gNw9\6XZk=9kg?w}o%$ ”:J&f = GZFC79333.{zzZQبnt/Oΰ*|+> EMA@@_ v)w`Rkر#ɘ["!+4/hؑ(c6JH`R(# 4kv4o}гIrK f8 CơΣbJrC[J a\ZEMPmÒd g׳ᦍz' aϗ:}z2I MiQ*n4|۶5_vvvs.z虗FiN %(3 *5{ܤㆣqUoرcg( W4cL]x駟>2===VV85gH8L4Ƃ] 6Inh+v RGbzf6M4D);ĸf3 NHYqNEjv6DXkscLd3@`2`!]LYUSMϪ") d!tδs+g?ir@bjzf v;/61 Qw;{泻퉷`Rcбeysjz& s4f9w,SE%h6@+h\03HAÈHiáPi̢vP)#)(%s\xLN1f19)!N/4nwJv! [jβXhXp{9{q̷kz~Gv>bm?I&&0fL*-}iʹ|>;zhG)E?u{@OOw).VzDP/-5y,ktFTg<'*֍U;ͲکM/smllV%bbb{|:_'Z ^ ^,/Z[7x@_} ؁qJ=;.3B5kSjIHk4iLȠˈH(hllrtj6f-/3o2iQؑgl6W{8yLg\ލh8655ds"ZTTV&e`P`4Uj3U,Qe0Nlw=7;L/l7-vY4o[U}m|grLdb׼m{,[Q][r>CKd2#G=ٽx)cxCC蕯|ӧOy<çjYT߇N_E/z DbUj|'[RV L&KFM BX" L |$p@獍 Ѷ\.,R&=\^5@. !`@Q19oM6Ύgs9Ej{_*LkfPU}yjs㶂/eƤ2/,Ӛ7^EKcckj6x bG ر)4TU!y%kS;6F찬Ŏ<;4tbG!ښ|!fa,Lʨs9E lP䫫b+Md0"QO-mLz!d\J;vc1vN#)Bt'ť\>5)YTJFYPcsUn˯|+,M} O2O]ê@e4 CF+4fYaB0=<61)L8F4ޢu= e,!"VYzXf@Rgx,)6H 9~N-[$8`3xq /T@c^;u9NA'wptS'"lKsFlS3 PH +{¤E)g" ݠ11K8f1ˌzD!/s98rX(d3٭Trlt<8\rky8u=Ht&0'>*y^7rey^Vsl˲̧~O}S~ VwP 5$/x+~;omoӿ.J%aW+.g+=(5{4~:MPȥq&y"[Zv>(yJ.-) ӜFÙۨVxj&IS*GTi)H噔SH8nH)[8ggnuqy~ 5CO47xx;}w8`q XS0fY1+t(!3_(g31)iq +&A:g"7 Sh8GiD}'"dRZT1猑ѩ4![5]d3cѱIuZj*{[M!j=*S\Ӕig`<$]k-8RgsBPVdwwwE]t~GdZ%.<ꪫ~+7z}ر8??eu$g?g?,Ay8 tҍJΎ[9m-ͭaPFدx7j1YfӑphvnOT:3F;QIq [iYSHx] -t"q&D\U48KFI4ϭr'kr!*///r@@@-ܩ(س;ְa{H{S !ơ9qD{Gln&#>6>gәD,q0& fblwg0ML"1 ;153IPP4{uvlվ% 6xA~bx;*ĎS3NA;vh:͎MƑ 8:;ںZ ~qST:M&mK[[C,qrS3Ln& X֎m[4b`0(Z%Mq>qT\:j_BL%x;q[?}ȑ#݆*hwd

l6 OLNN$f hSS< uB29L$&Ʀ趮=]myB 6;^]4^O/@9 ՞} 176 v;ܱA* Ә%5ahYt477547FDiB8 ,=] MM̒J]cJoGvhokjnn1KQtc翻wg#T쑾멸,flӧկkZ _/\yeBeCCC ^k>/Rx_AEx=zqn7c#O>wރ@c ]_rM?.ב仟'MJ9 )dt*,kڲl: 油x4nnmnT2J;OKd6O$3L&,<4jb[ẐOfHV\.?1HLN'gә\@ b-M-]m dxHtNG7/ ˏ֮ntgG[g(9˺m2Rx@b|j, Ď%5!vq6رD;l]V>w8eAX&g2$YB,L6h̒哳TޗL6GcLr6fMr,,Eڷ y+;;[L21H̦өYȓ $vBJfI@(]'iKܞNoIAZi`z4O8}ŞlVKlA>>ɟ~->tM+_ү=/VKWL&.)ؽ={fVT&rMQh4PG 7{ '>wd2]5SReshe`2γٜE7s2LrT*=Sy񦶦xkb&wYual>t"&K ֖$yAU³\4tjbrjq*l.HsזֶpI]s~$QՓ3uc0n{{ow ,}M#5R@@@_} P#@cS.Mf_8eAX1yJH3\\DckcefZiԟ"Hϓ3D:L$RJ㘚a@115#K'eJ8ScM;,!nhkiK&fңR&ޗ*Q2*W(eyI˪8GuGKSd:+z;B_=~Wg MN8k{~KeF׬`:r\.4 q?jRIjpelnniVel=4-;;}Dss~|rA?R\-,\W=c9giaY25E֙DƤ*e_0mL"CeD2% M676E‘a3ǐt4sLb6ufxl8 2:ddo_cSmׄ,^_ 9ċҗbt/bG0؁(o;p㔍bz;qd43H8aMPrg9ef4 8ڕƑHlѦp(jGXR䭼q 3RȎ$4! G<%UƦm_h)%U'S%`1Xm^]Qԋ^69xw{v\ѳ=DT= o7<b}{{l6g>7_r?oSI0 ;wnA,OoYfs#Džr:;yiZ]H8h u)㴛)SӳtW*}큦G/rNre fr'p|oTm Bn'U#䯐HfGpM;پ= -v#$S -m- h1Mnhs O&lĩ3Ùt1 FuMk2M3kzg(EPTpX'ߛog(I~? sC`AfRĎ9f1M+ [UEi24Ѧi8t]xg33ùB8%cTj)x1f0;O$铧2BS(lYfLz zIJRvszMx`IKd)W4<ʒdH]d^g^xGy䧜󻝧\Ti^_Ki3E[J1>>N_'MuMS(򣣣2?xk_w}.~OAL&N^[gGG7cRwر3N?ZJP_jʸT25 @ mlh Ihi !Jk&ˌONƢXCr44N%+;L632:>Nm[,ndQW}lozJ>Ʌ]mb v;ΚqJuĎ=fȱf١`4 cGS8@LX3qtF8)#Ge ײrٱqCӇ:Z;p4y@̎?PC闔JoWmt'Ӳb2/+Ŏ:I'G**=*^jfK{ٽ{S]t%H$nzzzy"V|^}/?*+׿'?ICc'5m߾c;q)ؿ_Woo峳SN _by;[o#px==d2329~q qyȑ3L*5\;xL=S>ڳ[ZZGxƶp]7@l+QMKS2+F'@p(ou},z@e)cԅ*re&cxÜR;Q^à.Ndٱp(<ŹAat] AͲL s[s||~2^oR/d^} 5X+@w,ӷ㔚رc#&Jl!7<61aBCx|0N!$R8%9rx!napEu]t]ҒؑP(45m c<@à2%xqVҌSxeyq^>mz߃ yI֑g 9x.o__l}K~:݆ԿÇh$b7pM{^GS:yӏ<_RVh4}K_O{|+_ݽҍs]w=YzeF/^zޥ^ҋ=î' B166v{cw\//|7L)+G})R(GpӤ9LBK57R醆,g4M3"L`YYE%䤦 Jifswf&ֽsB~&L6&ӹt\5 BX4Ng\>Jجf* clhdkUdV ċՊ};/62zw|-V A"-$lc25xRiX,aB%aѴ񦆆h:[Y;|AŎɦ)]&uM i:h4 esٌ/Ŏl.K$ɆXt*/L7d)V  F#h>Kĝi [J$̢ E X-y;1:,/~멩NUݥn3Mɺ{zm۶ϻH/w?q%Ы_{79rAv޽㐧Kιc>KbA2|׻;'~W:vرOO>̙3'yuP!w[L(ryDjz6WNg3e3=hjj !LKе|,aN$'gFu]jZ:A H8L[u\%|"5;fL!g,B )hEt&ShXݩ+Yj .bY& vqڍS|߱qIs{KWINSl>aL䳆JfL QpbǘvHh$8˫a>B!H ƩlLKƥf( QcfRFYT岘y%y Ű@yɨⅰL43Lf|brddlo& 'p7YgW3=HdXk 5Hز0X^#,ɻm6W^0]^K\F 3FsOugđUY]=S]~4ʊ_G>/+|>~T%6Bqb xXEbڃv@;cP:|f9 W&̒gvj{mŶgZ|fDXrncs<ݮUgΜ8q̡SfsT%_(:Ƥ2ӗZ9Aͬg01R^w}ZA?^?ʙ|{_| _vi|oaQ/}JeeŸ?E.zs~IĉG~~};߱ pr}=W{Nib Oݿ +2}}hVoYZ Z]pdhMWׅ͌ϗsNb]}>sy>u)tE?_BM-{رÿ[K^{Wِ!KJU*kj\oO|mrjS P,Ù8D$[_jVkՅյ hOV*9ʢ8!i b6J,=VkQpQ/KJ!fe $Đ#^vz:wɩ߿gu?}ۿ>GgmՄ^׾ԧ>߮}/"VS]v޵sݻ߶m.2m4+|ȷVM˫ri3۷o۾m۶]3S |1^{[?|zw7(˛^m~^^w" |ݯ9g}f78TcB8vm۶εjmueeeСC;ēO @;v߽sמ=J;v-6wo~经(R 3(9۷휞/v|wM_pP9oJI`e5XiG#E_Xc۫ ZU'>xůxM9Gs}!=8eUF"TZ2WV0Sɸ1<ѓkMY\^^y{]w}) /n>w\^ժ_VudR??wz_3 #zݯo_z!4Վj6Vo4[e9DybVWWWk@U\/..--"X6[ F(C:=\0j[+k+4uFV;S|5zZhS>m#{/ehnOzz"5w9%)Ss2S.xfgv۫rLIeFZZZ'DeZ5VZԔB򚛭vkieep[zc=n6Vפv0]kku(QŢ9UVWɃg>٣QaHe㧓{:K hYIrP4ڑNb9M\Atfi#FoI =xi3/_szzz.iu6i9FrǛfkqiiZ5N:sݜyG\4. )-|eeo63 g BN-kk՚3}3I۶5WVFtur:smml67;^2FIC$2X*`s^ ;zj Ў|'ځV1dd[;b}xN9w@; v۫tv,-/VkƉ'n{B<ިvTjF}qq0vLjZ'Z;z)ѴյUѬUЊyZ3A3!c >eU->% .)ǽ,㋟'ճyA袋vf>Cz\_8A [֫ ֚5ZB3 dC/!o|Ϥۿ?A.64D~R"(%G(?5z#D}qڱdW;i_9evl>4АvxJ;ZI{jkr$*Adwڍ-L?a 2#TyK+F>v^;da{d^*ЋCwūG@/Ў1n@;YӎpIkSЎ@^F; J!KHDe1ńZ\Z6DVJKh@zpD@4r1O$2yd '{jr%82eҘzWCFhOqVekoJ>= _2N/PF/:jJn@;  4[Z!/30U>c`f[*YF\'H3eG%niH`C~g}N*`gSY^2D ^; 5h4[2S.l,mKLE#ɕBtfJS|S'\J *n*ޡΰ(yVv&y^>z^ؿY x "&J>{R3ȴg'y{6􎑳8t}:R_Ϟ]ۯzk%m>b#8 v>\G|'>|SCfq Ub˕1 Kso*OK3Lz`R"H0fx= MLEle^6Tq{)dKpG8 2/=OQ9*a]!"2 e^BaAu}y @w a=XxN`4M,h*qz)ơ3,e楯c=/}=TCk-˓ gMc:pyz\Z}=y^X,lH(d|SqT&e:"y݉Dg{9;Hn7yբI)cI1r&"x k@XX4tK@;{jf祈y\娇ep|̓=/ʶneԩ&QT'\@/&2" ܦr۳ K0rp3U"KpP̧Uu$B1ett%!r:` x^ƽ-㞗%6oXo۳ KJ x^tvCo5ĩj6p^#]+L;n?x%W`=/㫌'y^Wg^NޓJ;f+f܀L(2x`^UbTr8w]);ԑ"=u0\/h2\Ky0Π@V=/yH K{(1xy#[y8vďzNafgI-&HKF sǥ˜C_uqRs q-̮2l.@yy\>Gj pjǂ= 3^2{v_#̹,z0Dɕ 8GR\Swrrdl*m{☾#| gO=u,GGShrW##g2h X;wۣiZuxN`+y^~BWKG"v@;ٺDh,3 ҁgK/h9g^2d ~t\ P:\f[8ILhڸř[ȩ>d--|cqHOS3s}6}~Fkc0zVP2Q. z8C$IhQQ1 @Hafw⒂wsrs`9GC)[(S>:+MxR} PIx3SxRS}{B>wZy_]n,Cw )lEK2 ڋAc뉑t-[!K0ƨ;+m'ܧWYgˆ&c,G LʀwYrںy2#22݊JzʄޭK*@\iRpڭ j \zkiyn{>k1|d`0vV2SغeK)Pb1eg}=NpjNNzVKKSԝ xN`A1z8CG욿ZgFi=ʇxH`^uzeeٱ>WU̓;wۣiZuxN` 3/՟lkee$,z^&"vut-[EA1"0l y/UV;`& hQZCg޹.y t->]'M?1wS1zY^ly^&yy)D?b1eg}=y>Jy'W,\!ǝ|r.˝H ^.lg@{[BB0ViڢlFo[^b[-ʺď ws ݣ4[Q0ƴ IЎ4~aCuF>ug7`(vւ]=,&c XsX8,xvA--P23GRbš3PgksI!:U[Xj-vkU5={nl{m*Ӵqϧk \oSm Pn2r-05`x#1Z^}`8ȌJ\\za"zj@{`[Ys}pq8w9r5te&s{ :fUPS/:5Z\xy*$/Ǽ{mo(xI!` tͅY 'vVlͰ2)#b&Zm\.Ս#衈 x%h.fv9k~[0.sEu9cE˭\]!p΅fjRw,!uk4I^Q='v =O0Aҗ׆dL b1H!h텉Q ZOcn몇%!44I^2ƈ&ҋھ ƉZazg9>]-sm8~!hƙǼDHePd!Ճ0ۭj%q>eZREK;oK([ez^zfYu wƴRDLٻ{4f 0 SzgcJt8#NBp00m .yY yȲ A9%yϰJҔmKm÷YD*M x^1yF̲} X " GO꒙ew7*vx8 /!lK\x^ z^K6.x`K, ]J6`^є. T^ɠ"@!y @V v)k-03$'ߴK楾NmjUr}=2/g"9߈FQK` Phdu/+˰/RYs #=_gL4edam{m05`'c 4<3prkU!K0>5Jl# fmo`D^Ez>P{BBe2})lH x^ z^eX9 3hKR/(Ki.[@s M,%y{z^ {^vL5g33/9-4LֳE3Fˬg"<_<ݵ\0{v_I=đH:7`^|4Mw\Tq#9QQڳxa&z^yd=pǕMZSLGȲ <%?Tc3AD|ֳ= zv ^D_ 10/'Mu,K%z˘&m,!x 2%c`Gz x C;i@V|ٯl;(!K)a}@j/FenOz?!oahGkId2qK1DK&`ʈy^/Lx^0Lݷ>Td`1H{x^=d212xoK>|x^0/Oݕ +@/׎/r%W@f7@;S˸eb{^vvLv9[}= 3?o`|^;C{,EoCK3sQlp(3Y,-.K4y5M߆C l\;.GӴ D}Ҏ[x^A=/Tq{y gPȑs\쳣>Td `ڡBB{ @;Ȟe|`5<*y$=3/~G}QOʸe&G( sDy  C;^SF_`1(6 ,xFɼ4}=ۛx_w2{^K6@M0G,ۣ`^ׯ C@;Wvm+(ɨ4&u)bL6nz^sJFK&UXex,7x C;izZ y~Gx^08A&;ugWF| 0-W]}} @vܫ2d=/YwޓJ;f+vCV z^{Kx^%^65[y 8>Td @6vg2ݸezy {=蚞mzx K2x^22iYz6lKIyifJˎ/;p6%K%鰲!gO;ugqe8, L@/&Q-W]R; ͼN(kov0N2GS̻Yxu''KZ\o9d^z$ޤiLEBu D P𼌬"yoϢ["S : HvKu}Q_"x x5SزMK ˍ=/EKcRlɜLy).ϿK/Afd욿&=t| Ƶ~4M}} 2IT;w[*&+ŒrgRp8q*3RǙ-/.>;Hn7}uFm/gSYzvDq+@Vv0TzTQ8Sff])p <ߗM!lKa,'e7e>^ `|1~ Q߈.`́^1~e5(FBIG>rCe2/yd/_V qKT;=/#eӎmP׻/b<-uT2P\ym%uK)+y]!N!۸o``Lh 탗k0,P*JsJ")]R!8+2ɭ뵷T_sߤM:71Lg%釤Thf/A*|)oPw/m|)NYV~6d9DrzȞv } rAT$mTeI9\HpƧ8\BO:/y~G K0nDSQʈcɭ s{0tR͐HS#`0 1~sDi2/!sT:B0i#9}߯m{sLp ȭ^'V{WZR~}=jX_s})r`0B޼Dd0@|~&Zг5@n?^=0c%d7'`^l΁}^s `_C{Z@;z|/Ўt@;2c}ڡ33{ÏJQ,aM%2SnuƤT V1.²HKʣK*7"!ҔuBنޘ&^&{ZwTn\/9]s5?|W\o߾MOOo۱cޥӧN:zo{~c2c-/3=oϻ~GvqѣG9s'>SO- !~/ػwsfGG.61555KKo|{>sϞ=XXX8x_/>ClP~Ѓ()˴L.t 5a⹲)Swl%|F 5Klvlv_K\uIKO*hfkov!ЎW/|#=aXPb!WKL},:'83 1 ?qTu/a_ep\L920h20=/#Ip{Ril ܔ(@x;~{}O{z;; o /{wIV[o:3t{SO=HIѨ]]o77O:Gj|h |>_|>_Ba*/L |0S,g\X+V(unF7+}rgKb NMϊ4L;ra] @;@_-@8wvݍ8|\*LJJ\,SD4[(U&Jۦ''OUS򎙩]s3f'vm=7Sٽ}{leIo];M5?s{vL=?9wޝS5]Ssfwz{u{΅SϹ`zϘz3S\4;}3g/}̥m=sכt.s^>\$\H4= ɋΛg vMN\{rbJmxe^rKW_?رu<~>}2{?y?g]vdpfffſm//;ty힞>ؕ\TNΝ](zs\u{~cmo{;o=6A599Yp]@y>eF^͖XЙSffJ33S4jzlMJ2BRrcv W;~w~׮=?2v3A1<8(Ʊpfn#Cr*۷=9yVPs֪k gN,.-.,T3)Bd)^j:-Dz`Z[}+Siǁ ReLGZ$xy\|/琉_}CM7/K^}k?}7 /x6 H)>|'_m۶+O_u;>'iQן̓O>yxaacӻTuժ;zH#!k{{<;J_Wox?u2u| 9u+k7uxKѤ;x^;WJË%qEZk2!@ 9ULPooC-|Fz1B}A/1c@hvN3IYȇ 8B,Nr( siM?(Kd*|~/.w| gZ%XC/M.%  L2d?œPWxepKr34gjjj&/8g޿}/| _җcfggwwB%*|k^۶m|w7|޽<ϼ>FG?KqΚztx7>߾}/ĉGow}d~G17'o_MqkVZmuuƄh[W7p^s8Kg9u\Z>}zlMV*I5,,.seM߃jQ0Y+uz 6z(~3ߟfIDATߗp3\r%t}>_oPu!X]%!eWW75H$̇~1Q]YY]?kkkiAWbs|*}z/hՕFl7[y3$-,.!IKG{euľ}=J`FTYo=Ћыf9^(]^hGVf.1ڠvhw|tw\*d`9`i;wԪzVmSal\.O\3RCdi6[lee*V:.;&+B.W*!"Ƅ{uй|Ӫ4S>_ IaDgLB$;ŸM}x9/]cǞ|ᇿ'`j.cwQyS0&;wiJ2i{?J4U9Vy/Dy{.'%QǥKu˖?(Db!?7Q*᷋„:9mZcCGIeA''}/Sp *Slˑz1>zA& d_cd=k6wDv@;cS\;w,#Nr;/{1E\rvSuʜdj:︬\ȹ4cW,~NNBM|Uxd%c>wv9Оj2;e[:)UUFά-՗¾DXS+xTyjy9@/S/*l*Ўhf5Qvhf8h̒_ZYE LUnZjunzI J\E}f&+mӓd 4Z}vfU(OJSfך(̬VVתUz}2'=0eR-- UGeRHW2eOD'e78B _]j>w,֣IhVk=Aw ~+җUg^_[|cԨ cGOX*ɢ2u_%;Ѥvh4ɕe]LMlm{RL&UbM4[f/ʥZ ў()x9j5~Idѐcy—IҟBlwOݹݕy^@/Aq_K[;Bظv~hGFvt6J1.1FbrP?;=YF 10 \TUr47;=kyZnnl8-ң:"}N=j2eE8Hͨ]Zڱ{"o0u7:%Oޟ^m嗿 Ogox~.?'?o M_zGA+ 7pMqoT*M){]4ƮopȬJ)BMSpMNkRud!Nm۵wWujW(R%>kmn39U)onZV;yza&i0(M+WaADg|"~Tpe/0z@/H"s@;H#s@;H#s@;֭=)8PP(KX8dNM}&˥DH+67{wlZK++GhڙK x`QLc<Ù8lVWeeyij&/1^I\G)( JS!̐.koBM#Ky~ioϨQ?Bk?᭷SSSۺxor:o"Eor{칠O%'.yի^{mv_^NReǔ;oqv󝐫j,6dʞqp]*buyϹf&WOY\d~̅fץDX( B.uO[>x*ZPɭЖ 0@/ν^{x@h pNvtڑ52+Ў4@;2+\Y)_d8\际uzf\wvF}ʩӋhuF:.+6k^^{^E&|yɹ|S'MBLT#CB0Og*.Wި }i/$ >gehrn{^FoՑ ^UA 2BwO>]$Srcٓġ࣏>+_LK~rrr??,bd@ч\n{+kE;/(fW۾}v'>~,D7+?EYTݕ/SK+9vrFuY-0 ;VX;iҩшyq^a,˫?c^ _T}~|498zaF^C/9h} ~'if<口vt1vtO/hڱa,:yP> ZV{Z]X>V(m[Z^ݻ}3 O~9F([k]YTV۳ko\,:zv#2AS)QCz]ؒ\P.+MuR]6M8i2-}mo{E#랓J;>0 -1vZ_C"5O׬~[sJ+yySS]YY$+@ho\Fe |]|?_?c?vjk~y}drr\ӫBL ј,zZ\^^l{ʞ]3=Zes3o~7u G=e7yDyzA;=:I*ro|U?+ΝI ))RVJ6 KM1ϘXMx/Gp8z1~@;5v'W̼F_cv ;˓TvЎukY}fJI5#ExWV|/ݽ_xޮ嵪?37=݃J LzN)ԂMMUy'N5&Iige)uS١r:3_ZRn OoŵoGI!XWMxt99S1H ^:6c20=17!rmի+7?q·MTsr.FfYreuusV'?Ǐ?? |~exuFd#.8NPV j+: +++iu.%?=w욟>;5U(yqhZm_XYYY\][ny_,'l߻{f'+R"r/VWk]>92(<l[H/tC/hcT`DvtЎs%Xcv !"FI, ++ f=wo>55U)Kł8y,5[*ƱZ]i_*&fٽsٙD LȚ*5d7y幎GpR_uJ]DW?׼{//mn^miYbށ;|>B ~V-ӟ,IgZYYV. ;MyV%8jŜVhZVO^\8B+sffgr۶Un67l6["lVO8w*ܱcTeyuMйg7Y;}}red 녩^Z p΁vtځv;8~д~'USj^MzfY8qjJVYvn>;7;BkgZGOZ}R8/LMUf;k۷MOOMUjZǚi׋%˵?%ѺJ}sdetz^ez!Y6O;sg#&''o?/~yk~ qR- _8eI/,,ޡAndy]ۘ`4*R=ZŜ=w _Y]/}욭X\^m^X^[\^][V4p!|119Qٱ}ۜVɅg2/ S,Ly2Z~ >(Ύ\.Z㻰s|)oñcyɈЋ us+k5=z@;k[U5Ў@;׎^면C;Ўh^'))b,r6WyAB`ݦiՅzfY]6Ţ=޽c3KKeiyVK<%&'۶QZfVFi&CNzzuI0v?ppJ0;y>hWvi~Wfw:b@Mys{Lc7KA/ .BYϿRӞz~ Ǐ:)oroj̋Χ_`+`OϾtر3&pdj _T\AFrcaaieqiiX}V,߽sʪF^XX{iaieubVs;}ޮZm(;m|2K!E?ɗ᫇}Y[7օ*]ʇx~dy^VK# bkř3=s@;6(fϔ;ICG_ckڱxj:xڱUvK;:X]]]gg. #lzy#erhԂZ.eT5Z䙅3O9QD>ڵcc'O$/ :CIDn8hФ'F\~MlbjZ/ЎR_c#u+A#wt];lMmH%^[[S'O9V!&qc+ʵP;pZVZXTv3/~Q߈^oT*0зk4'N;<5yT,puziPؑwsO_٥յZ'+O6*b235X(x(v Ў1ڑ^; w+4MuFy铇&T1\^+ 1_/cNj*)Q* ɩBᰉRʆuHG_oAm=cb_ΠAKڃdJq)bc|ɟh(]wg{jOZS$ҩ;YȔ2/Z̴8ڒa ߗsBs=zO%8n\QcG|:>!,M8> B1~lj@ݿD?7퓧ON=U*Jb ܜ%.y[҉jQ%1(rBsdeT*\m֎!i><.^>`oAN bkE HwB/h~SF ;z(Qk)CK*KKwF酓SRR*˅|Xps9'WTs38|fUSgNWʥc\nP(s9wb2P*rLcw(㺉Fdx\zw0/od?cdX/9?/zы^׿ϨK :t~5;e+/pzl\hfݴKv׮]{|taԜóXߩĉ'~~wz#GH;?FTCPt,Ac|a׮{k/x3RWVWzkG}[׮3+~HZqiu8:}n~no|g=JeC Vyzqiajrt驩/ç `8ksU r0]}9C npDSG q^^M/jƖ׋ھ ЋQڡv@;c+>ȋE#;F;6+TZz^1=/K· ?Fgyz~܎iuSi599际EjS6Oa #z* [IR(K2T$jrS{<{[H)>~sfKSbPYϺ腌"g-s_\.'d y ^rj틚oWwowoOJ0z/Z-2e׿~BϽm??{mRGy/1z#~ݘ??2}]?C=%|FWɓ'?z׻|;oO_uJR$JK!DϿͧ+YLZg4Z}muPo4<_qm \\.sy SҪ[XVWV֖W_Gޟ4I]/;̰8zaԋ#N[/tz#Ȝv} g1ƱZfo>Gw>eZxk߱h۾s^*DDw0!ڭw,-YZ^[X\YY>yN,ju6Y(XB5écu،n1 1~GK|;qı{^q}kNG紜/}K_C8Jٟ_E]x^W>&W-|衯=~x>|333Oo!~_ڞ~9U>ko_)VZ5rW ;YZvj֘FDvs7VV K+k kK+++F%&+V]U#w=\ShݤS [}w6<@/Iz˛^hX;҂ƨ~ǽ}?\9NծrO.R~s-7qeĪ8nM'+vˣ0E8c=Vqe-V1ՕJjJk{Fc(+QYC2-Ep=1- Nd(♑=b$.c1u]ʼd}3=/|IQt ZNNNN'.xS؝i|3wzzz}#<Swn=gK \>S??BFO~>yt#?}o|?4_/SO=]tE훞я~O|Cjr+}G\_mjv{OŵZc~;'e brFAPA"զ&線fuyuґf[bT&*b!"zA8}=2B _A(""`ۃsbkE-2Ơ zؚSF_cAЎq:︵X~7k<Ͷh-4Y.˹BeAN|oV[u(O7SNT!E/R!Y1%;B'e)w ^?vK%~{73 8Ft7 K/tmM_G{я~􏓦'x}{o~)i77߸q`Ïovt='N0 !ɿ?"Dv;+u˔n f+m?Uo 箘Lw0ӹl뫫 KOB,d%7955U,.:8zp=ʮ"Ȃj#U9{jNhyP¼?@;ƣ1Vkޯh~>;}cq 󵡦whJXn{ OO[Z}sןLK2-)%^R84[zzT0\*Ox|ejjP,\Wsz/iKٖV  w>_~(]}-oy~}ʙ^.,,Ї>^Wv3A .X,Ǐl|;oO<+>p.:o_GyAxMjuo~|}ßꫯx)Ik>vߺݾt{߄oL\Ga/ZM9ӭյjmyDP(ʙV}=Z [-^yb"7=5U)9ʆV&̿H06\#bt"]d0)[ XiGZyv@;8ݿ}筯ljdLo;Lpjjm-5'Gr/P0LOz}^~3555Q*28zm}eQG(1>+&!ؔ&OF*s2==U~ӛɩ=o_X8s?O?BSi$4׾o5>O Ϲ39OG}sO?>䓏׾}yIByϻtO%/yu)syye˟ԧJ;?C]v+.ʷK/yE]tS>c/|cw笝JqN li`B"r˥;o߽m۶f=)h|C=?^VIV1??s~yٻ{jZ>o?XZ}WIL.mMϗs6 ^pDO߆#USb b^4ЎNki[hG'ЎiM/p*[hGjx,_朵/T0&ơcui ܵc~s۶67+pjH4;wl۱}~yݳsZVl>c9xk-,r8"|  2]WhyiZCV{z:*s{߯-{Dߟsi:2yA@rvi1j*z^c8~[2xi JFO-k!/O~xs"*j~o췀M; :N?!R븖.盈u5rOcLN>OMMNNOMMlS抣ǎ>ԑ#FK^~|>,No߾}[5^SG uȧEN)rWo {ze/fDQ=Qz{^l@/ =!b@;RЎ #Ўj`1|>WjqaC0?:_&+ӓS3h!QǏ=Fe͆|>735Uhvka8iXdYF7#*ʐZ&IZ(E9g9-ťӯEvUۍfSOh^V5r-U^NEvL"+]HR/y9@/~/Ћ EBub@;Ў # ЎØj,W/ACn9؂\ [yM)۞q4Z͕ե'O=B#kuZ8dQfz^Vfmeyy駏t6zZk[ FRqJL)Tzqˣu?dO.=2վfa]9>ozy?9鲺z{~H/墋.A?HCz𹾮Qne r7VK2 ) ]Y^zvڑvڑ URѦ,G9Ù U×ZjZL<Ҏ[ԛkJ xb<*R/.E9VӴ;#xh6b*M޹B屙ʹ[#I>iA'Ǥ^eG%!/0vrY-ʱ}e{zw*einX*xȈ2^2z^1yIֆ88;zA۰ [h`dA;D_#@;# 1%#@;S(r.BN\Gɵ7i!)GNyZzziz|(pQ)ҕri1¥`qO&b 2Y%SdM{x^Je`z^U%aVB\M}K9:~7}u|s}qiOkoH:nhuУeԷ&ҙՈNorB}t;UzqvX# ЎA,hGtW21vdhGzhB>_C#t|_7'Ù29L$\dSϳPަI6TuRTʤԇ:=OAwmOLꡨz~k*s, .e=a@UdWvi8 cy˕tT_,QZ;ݮ/q= UR @FckhkB>4rTf^^[g4FZ7fwR @,LP2ה}uS6WbDX7c[Wt6^Tg>W;Ȝa?e?ʊG"ziCn;'Y!>T Gt3B%O):[ՎA ff`n.)Q>xC \RTetѧҫ[ɦJ鍩r(J镩B0])6))Qِ\eLUTcV#vR'J>&sKF*ZD (6UFV&D/KkE{ 9`k 8cyO=v@;HKJED]S#m(RV3?em- :Rj *KڸN 1]+^%c Vge_LמhP~[CKГVUs]d3Se֠dM]Aht=Cuة;S>Tl^^mI;tUn%YՎ`7fICUS r[xZP+Id<*R SOl(V}5FWtq[ =/ykz^T1[aHe_YjCqK@L[S9KN_hmMU?M8zv@߁hCT(4VpgIs78-o`w[z[e2&x3,צcqK{_ ㈗;ml>v8AU?ly p\xU֧;QB ?Ka%| p ߁6zY+i!Ju|䳉\×{1əqPfL^2<08sK7)=WxƵmy]FTl^Kڸ:^A;.G4=`lE~mGv0i䴝(19#[y8ʼHU*+qtץ)WYAe0mTY3SO)Xy|qe*8pӽ2I2ɞy FVK:j4y> ^eP)@/c^"ETAeb%Uj%4a^h?]’*18rq)(*O9$Yrc>gymKD}y x C;iQARB٘2H<*0\HKZm ȁ)+ PK0 X=+-F5i33Y$L GS*?\svrV۵mDd3alψ~_92<ߺ=/ױ x Ɨ Vr(h=SahR=kQl9Vu=-~QK]yMH}Dʩ\H`́^G_`\+G=/#> x^.1/wDl>1X]?ly ˇqv;S>Td`[$}{x^u ai{VҪzd]v*s]67'K2ȮLjK^x ^%cEi=!e祬yɭd$-vuF;x^ƽ-"yiui/qqE*8p㽁v賭+6ok>8?%Bԧu;} 0 0{O} q3 snYb#ao ^IY43>A_l* _ƶ!K^0@/ЎA/ 3@;Ȕ%ސJ/9zԝ)_ *20-W]}<Ȫv~hcyivu󼌔Td`1H%YG`|`!<[txō|Xz^`yIc ] 7^ynW>Td`1H{x^=d2m}x^0|KwW%yUcT1HYao]:)<Ɩsykyi'y^2c:YޓJ;f+祺~{* Kk\z`S|95/rr@6@_X=RXIq/bE˸tJB?frʼdqw?s } 2-v|̙l!K|+Si[n7y^$R/ 0^ x  }Oz WD7iJ:fk]y^hY =.z`T:QK"{K;jڥ&k]AV44\R ; } q%4 ޖqKy?fLS-DG ַ14-BѕWe dv ] } Wo @;W1.۴"I$;"ݣI/d^%%kD8zѯ /:ya\;5}웲Za\6!} 5m2dhd}c E=;L(uٜv ta3%MUNo%}&!GC[p8w(&ẎxNjr7o WAK;rJ9@!dޥ;X}!VO6g"kz^>vʾkx@=.}zGwcLI䈶%ٳk_V>tK2;e79V:.we^jsyh 8yZhfT AY9rșo;BﵘU,oܾ7hdv\TqA;QBOKaBoTq{x^Z1?fLSs}_&X_'?PK qlz^e=`Ty^R B Dy օn;Nqs3eb 8q\gɲME'2C<#0,M09դ%/-Tlm(<-i5;Koa! r:`\}yOE3Yr.5 [qe'>o=c4R2g{^z K eo3p N<3q;r:/g~wr5G#^=8hh-~Cx}rly@;V T$dKsy^D(yx^ޞV%ȬL`X=ѬM)Nx-g}}ϹEus,GS9qrqK4́s ֟G^_c=n%Jx1%|-^yn7|o3vY;`} @;WΦezy ڻggdˇ8Yu~Kx ocҚ>4θ#&sy^Uᱷ43OG*&ZVk:5﷘עƛB0}o45"1~mGv=/YK;LnWBȇ :a5> g}2/QSvzvp^GʉFmrG,| -t<ʷ̥8w\Vr^]6>IV{>4W _ߔ={Bf\ 'Vu 5idhcKyi2&R ;b$jXl[y @:(=NkУCތB~-FXf\'\i¸eᢙ˱ KjIcb ^yMzI<ѢzB= Kƽ1@{5Ɩe ig4v4۞,Zb$y^Fb( vn+9BM%ld^E=/S&Ij!:ؚlHps hd:mt̼ V |H#wTp{ eVk7E(R..NP@=5kQ-gRDa}˶؇&2S^ NC߈ed^0>%Zr5K)G l xiеS!:RW\q@6ؠ%dhJi IɞMda%Hz^Fb( `P=}ԝn*&~dQchj@$g_{]v FrI3žƗn}ku Ƅy{"яJ1aTKk|x^>>T w]`t<YTIaτqzOH} 4A}2=t736S!2p<4Ԥ0^ Kpȼ}y c^zj|&MLr?y @f@_D&L2rz^:C;h2VPcX}0O0-}|O*.x2u t;^ȼ }e5(ƖcCz&3x#>c[>% Lc3AJ&_o=Bjѣm\' `"h}aYkĵ}  "ud?U(+#3tɞAfWٞ{ƻ>>rr]@-"Nsaxd^0LlmM<>Mȼ }Aڇxa@6| Ȩv~h[0#0lA—q"Wɕw t{ K2h E=/!x^< yib1 wҴ?s&6@6"p铯:,5.T0gB_ knK|:s&h#Bԋ;b$T} yi&hwL\CgC4y^O2Ä% agB0[#adJ/niLՎo;v2IT;w[*2v b]ջDG{+Siǁ C-y)zԛ ghg`-N@v>eYvչcC-gWҧl/ai 3v>1_` P$6 酑_z@v'xYB7Kn>nW9aie6\mYmYdh x %YU&X xO;?Otz^^wKS󲳞 %zVW{^ޗY`|8U]K^=hx^&yZo M;򼌷gQˁ-vHkμRoe^af^/hEt- ;z?z@6vmۘOu~fl2/Af|'eSF% dhP}F%yٹKL/@➗TdXiKK0>vc)ۿ5|=^|MK>|=l-WA;7@;CK2qѫEcҎJy4,?M祮3ޖPd^6aG3y @^;>Mob]ջDG{1K+/wBޕ 룞aK08d{lJv3ŰlrĽ(yln~X`8Ȍ=oK?s&x^1ӯ: L 2|w*{3A;Ȱv\TG3gv0žƵ%yi7qe*xMQx-Iڏ`ކƷ!;Ȅ^ z@v'T.qpk&Ыmny@=/m$ d^Eb_߲ sz1H{ve/Xm,2A3}c]c$yDc'a}g/1+w52{_z@FvfmY}}ag>_R?f3 3^2U-`E_^Eh@ #]yȼ㋵DO;^78`dM/>Ū{w#kǗn HǾgp5XjT=l%Z~ȳLcoq6~j χ2/Ș^to_A/g2-`1^ Qt;}'yB?@y=/نbvd0yi{_̌pq0Q ˰gۺEG" M~4/@/"1Si9 Ĵ}Ҏ[z^x;L2*D=w\J;tod zķ?ivK2^=havTr-tt@mK)|=Td9j>Ax^Zxfab$])zPzgD%V2^i+,6@6˜aev0LU%;b>E*` D `BF%jc'x2_FoMoV &=~KduHÎ[}\c'Xm{^}#y @v}Ǩ= ;@;Ɨb9X[ɰTnvQy* قQ%*2O?}Rk z7=/m{Qю/r-Ĩhov0BTE|!hV:2%m>M$K^!dz#]$}_9;hctQay^&T1[fF<+T%u\LtӶ$|!bGAb> } w1U)iҷ+-KcR楌gj/JsPI7ֱWN!IjLLݴ2*epryˋҎyķ4=2ݎS㱓pqx^us ,) yS r16EBxW@y >z@Fv<0t&J K!(%pOFqQF)t<|—>5PtBz֑9ݤ}=3e32=b DwrJfÐiy @"- @d\(X!=P$ECKy)*ǥ xb̑+ӑr?>̕e偩j櫇u)%$:)=/3VHW$3=/zJ&:C^tBL2qٯ<,K2>ag^ u]D)Y&?}~i=fd9xΨ\U^24JQ߈~exɌЋsr~ҋլ gh}#;VN\7WN0AIʥBYePJI`BɕI):P S>PuH2|#2q9]FB%v&}G$e>T?2}ٿkyoͪmX8mK/tύ7WU=5111nG=c}ק>ժڐ߿;~qBo6?h~^>W_W}'z/eޱcysss}9s'>񉿾;SOYXẮLVRj"i͖ŶAql^kܚ*A򱐫eT+`ٙ]2Ւ@/:EH b|vt| hv9e)iAc|A#pu饗_Z81O~}]wSO9Øh{^R@n٤21 J](v,1p2^3 9ins އ/) 3dZYZQHD=+WmǨOqJSS??ߥRi"~=y-oyo?GELAطo߮If^.&9HgBrǙ(KSSSҾgRcSqy矿+wBmo|#~WoMإ-0e9h˖wlE–(@:k?'U8z5o6 "zahz7=N>/`JK\:Ў_;n?x#@;"_iLJ>|ev=,7+g~w34,F(\f˅ǹ `:SٹBPrxm_FVkMjUe0L;ogmŕr¤219s<|7NoO">(bNkhGe yK5r7?׽g.m;_w}'JZկ~fCx8ej=j7NCw^8گ/yߛ@UW]o|_>po/h.+U)Amvn}}|uzv$q3ͦGTT_%?~egʾwyh~ݮ.-@/ 5w@;xfwps241o|"Ikb^7;*cP-nzpLH;f{YRkyӛx0{{'_m۶EW* ,UyZ58(΄D" 38ܐH7?7 G&rM!\LY@APQA p==Tժ}ZUս{}z}ٻ95tuz׳w6W.%s|3[,@A^Y%^.r) =J2heާI\KϓJq/IFl=Zd hk;r$SOY,s/NuKQ>\SCRqe%ٮuHJr!\$JŤ\. Ljd\LʳuJv(]H_ SyrʱpqBFSt҄/L&כoyy|<^gvinG8rȡG>r?9~{{WTwfp_]FFŹ%,iѻr|__o ljؖC,%b=t]}_/Źe^zOsBs}ƗS? 3XypM."BPs]Y(Dq:JAP\wFOt AI.%o3=_ISz7{yɧj'ċ/(Zsx/Z w^;.@@XkۊwtbG؁رqݾ[ۊzZĎcixY^|׼Wngyo|HM2Hqijhc+g͜rJb2"Xw]YuDq,X~0$>=0u[:K*01 ?%=')ФU{J;ڊW4v)]y䕹QuIcϞ=}}}C9ro$qjNԾ=$8888b'}g9W)O<㓓G>Kl }Y+NTĩR)5(5%N+cN%~~\,s槜$Y?/| l~rTXOrˏzѤ4`xuE5 :KⅉkIQ*bbb@~ `3vǒ!VvdėWo&6|aMA0UI"jZ2;7WVTyp1}!EB}Pťu$g!ii${ ǪѨ:]_oLGoe%٭4eq]J/I>8pB81e˗ۏhl)e%\]v{=3N_Z-=/[{fff/}Go cݻw7LU'*wu6Iy䑇hǧrʩt:\k{]AZPE 0zʥ1Q!$&Ք"̴r4Ec=ᚩiu$!yIr,&V[G E#/+:E'bb@@?SnXZ_dGqbgt0[˃.Updjn~F9ޞR\u < 2<4~ZwI}s΃T4C,F Jh)NJ)5eq e͗|vu}業߿qyrZ#<ЇQ*BNIc7ID 5q%A.~?8S㒲Z.U37@NFP.9xQ`HH#Oz^tm;v8xJZEk(IIor.Sa% ՞r)t zJaJ:JBP+AdJ) {Zk:Iǥ JT;깢|>z$6}X&}x~(/&/r!cIz/Kź+bO8$q>(bIЦ i㴪 > i>k.4Gu_xq%z,r$+{^7,NWU0{K&/@l:FHS _Wb~-=wZQBeP+?C_Ї>kٟXr)6{^Rǹ*v,җU|v~wxLIxO__`0 蓖QFmt]׷uڣ.1ft0]/*1] WkZ^%* tg: CCss s?"G$۩ABw*/ ]2v+eL^vzB{ނsR$9ڜ7v N,/xt2'bEûGo>'ċbbZcǞ;.~E ;;;^0^c(bG'ؑK^SV鳨(Rו=+Y\*؝*-eI?'M;~JUZ- Rb!r0848028P1fn$|ߧH(]S--գ1?s͵?#P.T]))ft!Rq rF[ڼ=p&/gRt7Vymz\ZWy 秏KK^ZRl1_o/|K!97mI+ 9Ҁ^S^O+?w5O 7Uz_{?G2rs_WNFjLf0(nF8iI7?4PR*V# +CC#WSp]yCtC7)dtqůpFp8$0̼H6ujiBne+?oG_y5 h}Y^rRv۶mI"ZO8yȤ>~6T^,rP=ns@:œ G]Xb;bGXؑc;[r2GkO"v;ؑ=^K3m\DceB4vC*2ء AX*|uKRq[\qŒ oVئҊ9YVW$7tZy`B+ɐWOo}bGK%ly7֞JV?.}먨9眝o}[T*->|0꾶!_PZV/B-r_׾EQ:mr?/eLJ5ozeo~-_;T*penZ/:YزY5 I1( 3;:gq{w⸞볜Svo߳c^p'<Y)ԽzV\bgb)~B,nK4%Ϸ}e87g}q}cw~C$EnBҥ- ,AJH&>'Cs9Ka7$i?xc}7ttĴq)eˮ7(-wgW뒲{]c|'iD0%=/}7UYA7<T LwرG%~ݕ;}ՒݩAgAZ+7l faų ss S=Rq|T  .,,.jC[MFVvrm3ae̤nȵ:ZhiZj0Nb+Njdb*b쌞EoU tAh=Oo+v=z` Ď1Z8qz` ХuUvUcZ@#E{,Zƨ'iz"bI%ٹ)'QQoOH>@B^׍3$[RP3KiҒ/Ȕ_j}Nl+v{꯾}```y-~$I#DoooϿ84HO3G&%YӤ|ꩧ?#\?|}vvn8z333q/IPݻ V> _N% ^6d',U鞘;253XդP;v  iɍh}85u6aF&H,5 ' ^d bbbX Ǯk^똾.t~sz-zN^kB`hm#aMW1Շ&#KRtr/ѫ,+<_eZ5*ic;O)?*,x^nLsK'/w7qi%G?w~{>$jasWYz98ԧ?o`_%(ثsw;M+W.ǂОw|h1?xhn$QGVbƋ/ubñċ7~ׇEL;;ډϿbg bbG;F[_CT#O)+}Fz=ZX\X>bDsJN ׫ӫpb)iʙR()D'b<cW^V m/2bʦH)Ke+QZ=SlTHK'I|E]t6C}$ɚ !KRʆG> bjtkַ|;H+UYnK<>>+7*<ܙ$QՕF%>|@_.Z*;)FI}>kǑÇ])9 s<;Ud܆ٙEHHsUq/Vf*pnr2QIyGdc h1?;NS$-Ӕ1]#T83j±;R!,_}~E' [1حR|Vai+/s" ݿRʞ__~%zoGy@$k.R6.{-YXn:y{{Ӄ>Jc$Xiu];XmmvYua\-{g.k)c+UwnbjfJ UatppC|q*ՃSD Y vy agVjIcZZ.m^27yԥBGOOO?F$yMJaTd7۵@_U袋NY!yi MvֻNomL w J~0S*>Y,{kW*|/ !u~k=mύhU6J4L4l{ؚ ^llȶwvhċ v~JN펆{}qgcv#zD3sl٤b&=ŅO<5]*P,mZ/ g!Q5֞ {=v'=etS,Z]sz~ %_x\OUѳ24!l)ex@<=y{Z[on{'!fL&SeGJY6e_(3)~j:~`䒻Q*Jk׮Ӛ[||*ʌ=_浠cҾ]yVeV ?* qR( AY}Opz7cs]lf"uH}0V3Z,ъ^,t|5b]/: ؁~ K(Pne[8L5ti#4&9TS"F|q={6jUuKVj:Ont4kM+/ל#zb$\.lIWfW{^&_ō|+_ל#[M^x[*]c4p;ԕ%dkW}/*GG~A㞺w s-,,QZ.1ؾ}8GC۶m}ɿ#G(հH7 ?rR.Z[psҎNz=OO9:u\,   (u!I>>K~N7 Rxrrb52 Eh"dogJ7UszBy5A@Xk5}Vn ;bbZc}7_ v v5vܶzĎ.#C 91m6muѣ|n$(hsJ(d) j,)O,cC2#DY8ҧ쉙YFU>S.S|RFCSDb;.掆ر=MMۇi4MU'e-7%H5??6\;}9OaRٓϜ+]͟xsBSI\׾wm5}E}߻7~7n$K{z^??ǩXU;v?}Y~_ȑ#Gpqx?o޽7C庞zȼ}x _xq~/Ї>EJR?/i>]O?|.4> 6O75]e:J:́*ѩѝޣ\WJt's>yhU_U-Cr/x _G=q3sV0*FNGߟjZ ɧڤIQT*8q$L46Nl 4usx]z?D^sή~e>>W|TEYW+rT*yk^׿?|-oyE733sk_7=i_',Y)*Z\93)yDa/V#GNR:tE= -8v"Q@MeF0B_zSDDvsPQ?iF4a} ^x0^q @@@hwl~ `+>KCnG-q\{=묳^s}<Çܹs)k_ӟ7Iyi-2B{dDH=0hts>N8v+tўq+bZzМf^1DPCL!7S#$/(U ont7?CyA8ㅹ6} u{% ^t x{[㮛@;;;wk[]]) vC)ł0*}w?ۺrz>׿/|3)EL8AuߥϢ=$'ߑg C}J !'f'{&{*V{2 #.(H, 9%[^:ԉW"͔襁b7|QisOwevyr#=/`c2I䩧(C=8I2yG~s}_ĒrP{IeRY6L߿?Y~ꩧynT2% g5qU+ l={lmXIaEQ-լRX9(^K8M3+5]ռ@oT,{d#Syn-Yʂ 7b\.ϒJVYY[@پz%/&ޘsG}zzzts|_8R(/Ε$M7V VDQT?O燓$Y\rn>MrGO}SߐR*+4 @1 lSB $q!'cb/zz{{X7y9eVq+]u9_KE MӴb{X>T@xO~r ]qbjbbb@;MK~Oh;J~nzoOߔRFO`.Ϣ.or9u@R5>%2T 0Uı-xJNC"=<󽤩24>,2麺ϒ^쳤gyU+w]/mgϞS B?tSwuחuc|xkvV~\y?|]bD~ׯfk_o~<\cF hw<8닢<:YR. ?OG5s#tcP*Tsss(^.:}}}R仮kMhF)+_<5*-׹[ ċt/7x/}C;;;b觠ݱoǎ8Vs] 77Ď7?IaTQV*O9%cϢ; >  HPEqU*#QBTqzBɓ͔}JL Zlq.&F _쑹A}Vдoǡ̳:1З<3y+_c{{/%J͵y]q<8z=Sf~ّˤ^{ϹG~##?|+>9Oˢ@M]7zy湣=أO>_yW:yESR1 ۳$NA0>66<>>6{];o?5QV ?o=Sӳ&@Q+}fSAiIYv~y)*=iX>Ӌv=GQ8w|/V|/I;ߵw\ro ^t~>ĎW; ĎccqsVxC"vt+;╯zYߝV]ʄTXn.yeyΡ$8ԒWt1z~7|Mf\\gbɱh[֩¹Qfi˱oJfSǝTԳSm0* z!J1,)7V8Yg5gϞgZ>/|jvKɝ?\8e>M38dRoooLz>Z|1)\ _IXN"vi\":M^r"p~a~ޝpJ TGdu3AyX)Sz8<%W*i]66º7U[ċU?ċE"xY v vX;b)OAAce8mwI9ZvÞLh.6O\=LCWOirv6`stJD¼;:b'qЌTMQD3sRMyŭR?\@\$N(KؑU!ѐ@K_s'[?[.y'Iӈgu|Sef~O{/?'>'coEY6`,,,.aX}O{RU*ZRX #5Js끑d f;:w+}6b-1uĎ>ر؁;'9ڬ5[=aQ%ksZH],Mpfjqaq>ܡC)Qjj1~ T/ ? S^ԥ ,Nahi9t-پON~Їi^ڪ˜'Wm|#'{oz9C|+W|d_f\-JKM6=}Kw)>qVİMDI^! b4qw%W73~ IۛKxqEV;fH/@Ď|5b;+vܶzqj!R=BC>$*{[IG#R~YFhо O5YaTð&9vI84q=˓}*>(1ICxJrKν6*/ikh+v 4o0Iyi>y*ɚoqz}l pqy^IB1<ϫy]9KPٖOYgy)kZmk=.%w2_Lvml%cyzy hĎA[m ر;;bGAs9]l1=D+\$O9xdn y}Kz96NKL.u.Љ!KzLaj>yw;WV)<$B=Tf^_&s! 9))iH鲬Ў< uRr924a/K-T3l8nR-t=\m|e}y%X&Hj5ڸ=ޠ 60q3I4=SśuU1#̐IW\6x<]/;hwp"RPr"Ӿk9QfBV4Ul|jy:: dMNDrqʂRޗZi>7A}tZ<o _NC$j;ɪo$/T% te.SϬ9Tl%,9A׏UAXottaK!xam[O*l;8,VbJ"d"Ubk) K!^ͱr"hJX~JCPBTY^UrO ztH(VrPh$ $M8XV[_/ρ4)(l"UD_34J{ GҎ&cK2IEmWjb`9gl$dus.sl$;8TkZIy_R߄6%m\uD /}VZ+2* ip7)V_+{^6[<9Z/`h=w/g%$%Mp!$t^+3gXq  v;x+0KEH D=o[bKmv$YXaI&*Þ9tMq;u=0[%jYdBں $ x^>q)\+DBw2k5N7#du٤l4b-ʩ%4)2W\%#^Ek9\/ b'jT-4G9̬"%RgV`h!/'+)l3O:۩ӖFyI=LSKy^K$y:gyZ%Pq; ncIxmɊ%Ǜ3uqa@ZOoe@b)l4 :{%UiXjie*ޗӒO3~ZiszjzN--}55fy_k>MYO <7$/A;m f6?s Jo/&ڋQdE{8S󔰤?<5$RL5|[;CiR^>ַǟ|vti s;.n)v\xmŎnn)v\ֶbǻb(+(KITqdJ}OVm*2]-ٴKabi:}UmŎ+nhKK]eyˆ䪍g(/AT=8aݬҗeHoܺEg @ŋU/R;ts5N>W(seH}t.9{e$HIOq3lHۉV}j햴Ӑ@˼yF]yƆJE-> L>h̵,IȞ_ڸh 8uenisVecUj(/AxɰoDe~(/l=@Xk{ ?s 9e;x^Kй4W=F7pZ/&;t=VAiK[ nΛ~lڟ+/%7{`nLKбG;];FO<=<xqÝow^r=];.b7]aτ@ǎVk;4(-2^ -3VUEjڊWц)KTO靕o`3:b+{^U "]76oϏnlx<:bTY,l̶/ƴ=/={Ӻ_ohdY@?]wg2ƀ%Xy XkXK%bD{g櫍竔oH^󼴾 y^utVlux{=/K^I%́\}'m0x^]״y ^㾛F;n=b[@V\e~XWoǎ!v`OSrsYd>?ݾfO(/Xh^_mǛGo!^E v; JK\iTTݒa8{@7ŋ`;{/FbDž7V+;Fbunm+vk;DU)V[ϏnSR/F;++&ly{zlSxKsLv z~=GO 麳d=7x^GRFcYfZ@'KbZ`M4W>Εgjt~x@7@9YmבSD=%<cnϮOSm<}#t6!濾B&a]4IxoBz @'P1/󒱓*V[o>% v;zY\}Flw}\dZcFicɏvXfeyҎ)Xr^<Ƌg0@@4(-2lڞW^er>2߇i<@pVퟫ`'1 y Gߟ:PJcR**^r=9vwՈcmG` sc]Ze1.NT_:ZtEzUjJkd[@XSWKбL97tx@oLޏe-uzaM b'Vf}DS#}dJ}Ugj7{P6]ޞXeú?Yx˙#@t,ҕBJIw?91roQ  w^y=ٹ6[)v\xmŎo";׆^`+ŎVksmւWw<+MxK~ﻪq m|,x5S˜^~zfi=/o H^EWb|Y ۰τ"@Z@ vNz-` ]WHW^}MJLa=,\W6D%JaPN5u%yy=/unD(Y /rqZu)DBMI&dvɇ:yT@w@}v;N>KYzҪڳr7L & INAO^c^W*H-/#!e}[-+aN6txZ&lyK$[O維l8XRy)VjYH^E+I2G[τNrS+6 |;kmt0Sc_/H^E.dfyi̯Fy(t( v+HUv~ Ζׂ!y :In9}c9:+6 u4\8o"L6tǹ}|qW#vڎ-L&lD(m^/}dD>v\t il>r}$K`Z+*EeپNpSS߽RJ}>JXڭ!I:lttǧ7[beJS7֛6+wϳZfyt3iyqټ /[z^nH^addZJ)Qt.F^~ҕ<=M\)/)cQ󼴏̍F Ή"X$QI-()8NZ詉 0تOA v*+=+*bKoz7KV[_2Sbx^U/NȄ-=/iayi"P'+<0-;κ|uuԳҞz[6{^?eoy-$eI %bA dot纒Rq’؁2 [+k`kdwK0 {0 00C׭a'ɷ*]щI` W[52E6y^J**Nߞ=vif;t7}yv H^-A$deUҭEt|3zX,/}¥ RJ*|\:B:)U-ϤiKnF (6l2aLqZVVCJ^Vk5®0T'`K[.`_ac [c}7_h;vܶz({9'̺-6n-ד7E;Vctligeú?YfK} y TG)qDQ5JI$cGVE~..WގjVVz؁M^Q8((qtsnØQTd|1 /ix¾D6:ՏOou67%bKe.WRdۿ֜rrw?SNs]Iyhs^y #G'*##%MRKzG sIY:n N]:N+e`ȫJX^틕j\z0cuUL(<ФG"q V@=.W_7OJn@7@Yyi9J 3mw}*>4]g#eI;ޜ':%rSrao!]W$ "#T"3ATYo)} LУop"nT =)K3ʕCy%-?8H\*猵u6%lYi +z^p<Ѹjen3s}VgvndpI_H^-̈́M*LĔ e&BrnՕq)(E|63"`qij9I8R4*IkIi2 @7@Yyi-bK#Vq~_CV!Ю1FC6 %bKeR/׭b2|[2r cÉdRt [Lڶf*A\_n}lqW#vڎ-;ڊ=M":Fl8iy+I\zځt,4[Pq#!^fK*أ`r: |^y @7@Yyi*Ge #\hYϲx;{L^%oZ8ޜ':At,,bG2%=׿j/K:z;/s"x^ͱoo+v}Dtsn߭mŎ[֜y>ewe>64W˶'sj+v\K]WHlY4}>N+2(iKбıJ#-24=6GVr'V1e>cd/&冀KbMs=/3*/0szFH^ ᫔Z X^@~?b9KK*ve$]eVKհ#"/<&=-eUةhK:lsm٨%zX&btJD|.Dv>Jl'HQ#= +W^ʡyښ^ҾrKz_sƴqбdzcZt,ekrt8ݧ?yᥙѾLI 'K5v^}A@J@Wŋ[.v;mǎ_yi,YHRo'IArr?͹ ~5w;f9t{}1^dK3wKбx@[@?"^9 f²ץݿ鸔ftѠ|up[M(~rՔZ"4%M\f(WeAt,֯a`Ʋ7nׅ<xtjn&m6v&HH\naNlw,nOՐip3ItB@vYl)%+cG5Mɏ~`;٫/{9ͪyK~yNfOdy9?%$ɞۗ?;9>qVvc;Tz˜eS9‘9lj㎇eⴞu}ey2ݯuy *Kp ^bysf$fsR̦"|tZi&WT"*^FK5o2l;"w;y[dj'y @ŋ[.`_#^}4ǎnvmla2aeO`(8B涓ڶw6ۮ&lA;bj,IV]\_2!M-bf~Cy *]y^.Z/n_xn"\)x]AپoaNHZ[%;Inٺި2i6Lz_ ㉙%+*xX jutT{T*.٣%o% f?eĐJ(sRR9|$JJ~2YiOe'͞l7AP}oW_F{UUWΊ7yA[❗cτx@ǎ oqMW3!vű};nyZ{&6 \)T )tip鳞yOV!|)<;ɿNטfRy?xT}ygnH^Ydp/;kONEVE\K(ueYjM&{]Z͂RR41bLB4;5vC̤.9sIߗNsrH/S KuvA@{\& ʼ/b1[gC2;^ *wmfN}=t Mǜ3fbq#UP^kK4Nڧ3͙~)P^%X[͞|A0t*BB K;@RsB9$d!P4FB-2籯o[V Lq~B+7zMg6nolg=Kz.dY-4Lr=1qKKбx@[@?FWyV:3^&yJ7O57lbPLˊJK=5<-G~^{\ZoK>2ˆ>c~ ^lOs,eai~hE=MriH$T{\f2%e-]M=/7̸Kб^޹k&Y4K-?xh;vwՈcmGDA.|JAI$ڔ)F$|fZF 2M"-鋮!v =XjT+6ί:e0M˄9{j=c >u@ vəjzDfBS'Lsc";%}Ȯ7?8j/:!cޮ]P^^2 )t6%)U!J[}Gky 9oЊe +I )yWhεij:S7x]R:ӤQU{vnt법Zs%4uR'P^%_h*g8u;Z\/;ֿ dl'kK=_0$;-,~z_û$2D0K8J!דH83MZBiҡRB ץ.u^ $/Ab"+W[\/;LޕF՘V:Ej]c 39 [׃U-<-ϛLr~}ԕy~59}[ԗtU/mǎnvmt(F(p $Ԏzu"z~TiԑvEV(zҺRK/u!rדxjo뒒qKбx@[@?xM*9ɬYO)U؄l:tڱR (o =G)+dev'$/Ab}Z+ߞ^ǚY/Zm_-~ ^} v;1m$H8B JBpޓ3mA%}8Җ.?vHi+&%WO|ˮg}'>cF1'?hNz/n;/ǜnx{[0'Bcunm+vеDl&gbn|]#`U=erzJJ#2$I&ђHe'EmIi7ҒN: N_Sf.y@q^2< LF d˜lB{`}rZzhIzIj%yWωd. }Cñt.`I^9@BHŵŵđ:?d>=>i:/2ɽ׼>=o'{%x/E: b|"YV6սMm1IO7?ԯimƓ\o'x^sy % vD01]Lh..G.Tn)ۺ`Ud΃r ƍ%{gRsdhʁ 4^<$%;ql/;'VhIW4?u"F&Zz\1דJ@SKn`ӫma}܂4:,lVJ< ۆ9l&;Oss#:щF铽:ؘ)H''>yVmTc }LT>7l&OC77LkC?irv2UT&q0#f!0F;g=c KYZc$fiтߊ}C SY NvLiD0i|v흐8E~VS3ա"/Y LfJ!ݠG/)k~(;ԖQ@gE R_7Wۚ~jl= 2?x姶7zJ%hWMi8L f4MݎohKG$V,pA`A(29;B#u' N)hR%210epgX f>x4>V+>I YNKwNn3σ M6{ILO+9y6*%꺾#9drM}T]a%[pLj(~eN(,f!u-v#^" qCn"s5JKޗ[ry/E&C}BM#uϯg,->n؄39[YWfx\>?I3mu٨Q8T1%6}|C$2q.p;f!LNNq&*Qmɍrܤ(D]#ѳ)rrM#bS[]9Ee{ XKZAvrD<ɬ7bgx=ڥ(uK ʽ\IiaR_lgP+\?E+Dp:Qו( )Y ssJ4v$bG)-u^.s~y6MMUu;@bt?CI;Xs=15aHԩLꫭ)wmV8x6xL6aR|ܘxlLѯ1[/4mrOhVۏ8[ s>*̞ ?֓RuhubG'B GD>lƌS[k&VRst۩e:Qi&|](Yscs\=joe;‹tWMm빭OnfeSL"Q;,ScC3 6&iMrI@ݞЯS^]qnzTgHUf =71PJ)\״B]=nG/;4F/xܵ1mdbS$R(4@L)i] 8Iɝѭo@prT;d;L찝EJ j2$%U9[a>wގuttty &~W֩6w=}O'0VymӳM%(NKL#]v M{A ?pU=k&6+ȷX^O:LCE&&vnڬ@n.q I sЉ,qI3Bj'ai $$}:+HJ"jRђsozޏa=ȸnwL-_KHҟuߖtŠIkK eGPNbwpw[=NDbtϹ̘ĎJђcF$U6wRC 3I̡W71LU ܥg9yϧƙTϾC9㩙j #g ʚHe.+͡{Yv?muVDnkҰO[ѣ ! Vuj"f񑁒=ỾQơ xtmp,宋y[d´(:-lP%F? ˥UaT3&+ÔV/٬aKnorjȼRu28;/mNt_B˩YPvfi}M+0#&Bэ|+oN?r38oj[n_{fZ%k,c?<"͈G<' HGjdFԱP5$1GGGKr-J^^+J|zŢ[*=b%T P\꘬.K랐|] r u{Kȡ0?TcPpX>ig/9wKiI jBr’3K=! y`< l}uQ6#N-nLR"-@LpR$PG)33‰T;*=4+jTl2[\ܐjpB#tƘcW6Z*^HWոZS&;\*r$NpKCU7~5)/ӐR䖊%s}P//?DGxĦVL`l+%X*fj=ֱ@^&s4<5'__깗S^+[*]?pŎ|;hD?tho"#!3s~T$J8yHObֈfZ~YVҚ+Bz£|n{\)=O_]+uc&I?z%jDwQdNaܳbyӷ !8c-HIC;p׍p%Tcnep?"'4AoL\2mslT*r;BQ=R;'ۺ45)=L8Ou'+qgQ%dP(sX_grhj$xN34Dt{闏%S~sRx1 T##%\$VTq9;} K3Fd{ Ӱfګnrp hZ4BF]:]1D^myvcgZF8e}ԊĤL3z)! neE*c%d8LȃX?[J"J( ws3`CCeo3̒ $j:<_eP*|ߟG622Z8MHy/i: qXAJOzH|znq` 87a$Tm}Я5'T3%s8VA~?XET.gGInf#ˤ3MY76fV4#.d53t("H}]#[ঁ}QB͹+3>>^FGGˣ Reff{)1ɑ#YBѪ_ppDn֊Qy:4FFF#ý}ʼn9R`oBLtKZ^jF_P_uu /AyiOJ9gg< INEš#DHr!UѶn6O3'4}]{ }&Zlz'X I>1 .BN7)ciKfx"5yP6U7't U1ud^9n&#QSҥxhYJչ3mƷm/S[cll4:::XUfBR* 0 i\v揚UHR?(  Gz{{z Ҍ'xz퍭q@)-Aw9 |ەg(E2BWD8qkQ1ݢt91~ub]S3yQl:SQSEԫC##/ !52J&tX!?'h",3NruFti,Tq,E\O $ 'bǏ g>CꦚUq$ kd Eƈn n1ur)kUH K8D*-cGؒZNEwVs?pt 8тjP?(TaȈƏ#EIќ1],Nj}upU2!`siԆEH#Z$cΑRuPuYCꡊk4m_*%NL HxZ{H116).@X_.,<ĒDE,jQ&yI) #\Ba .`Flz#偡bP,OQ32jy[:21wRZ)qΒڻҕ~@hId i ϩKZܺN,u/򚤠lG9<2\I tLP2ҕ^Q5ӺSU^ 0S"w){2:%uEotAvfFjO;J&aRCʤn%f$չTQpmd@qC2TO8Lb(kDդ{Nq.(oIش8iK塀 }޹kp=c{N9唅ɹ٩tmfnVWofr Oփy.P8 eA썍l>mlH#:tࡩG'fgf+>\ gͭN\rߙK P^ }yAq=2%uD$ʥ*IW^^ĵz\Y\Uѯnk.K7RaeZNؔLHPtݠ((]DI?)e/HC*%GqTu㨚DQ-uCǥ럍֓;i$ \@Ӣ^P߂}-hIi"֨&QXQqXS^TdROϿM(\W Jz8@QDЇeU|Nq(VtN(c!gq[`9L" ڼVN y.r8{,...NMMMMP233WjuE9sT詫IzZ |Y.nXŢ7>:?>62}@_#>tt%;\эQa=}QC?e9~}R/PҐzں ]ꥈx1Jjp璤c\1We73–K|&?RSa2] <7 |/  џp'_%$d `"&g5Q5摙suz+JIR^}}m)@jK)i~AY8UBf6uTU%т8R*bRxR{~I)Bz1ZuofNЯ<7ʉJȩW^K[wt黜3̣#`G]ݻ=gS'g'禦fg*3SZm8X(j4񿇱F/򴓢2ER@Rm>:8s|dp@ǎC9txp3s3;M vlVFTq;XJ؞pE+zP," |O_R#p%kJ4|J)ybI(I:lJ&JҐ/㴙EYjy  ,L|az)@K$ L=yR/(En閶o>38㌱m۩?qg7CMSS[;bI{=D%5Pc )Ȅ25C&ըw^/[cҘP=2C~OOYu-٣U5mrOo߶N۾o߾}gysssG&'9:39?34()Y4b 05.8008X( ܵkl׮;wڵgdddgy顡yDHqF}j=YAh+ +Ȣ_e蕞蓮=9/;gg8?|w:_|_x8EEyj>wDM, p"<<=~vLЉt\cե|N`<׼ nkT6f27`k[jc's0,NMO_ԣy8Rcy/a!zz =tx:IJm1=zIuNk)~s_|Ʃ۹SQ>#+_p?;ќRbPuYn!1%b= H!XvG_|yů ש aㄏ6kGC|@p):Z]N}QˡA]8o% y=t{[^vy9>]=?a7:Bڜ`GC%ky_wڱo}+_y,}m??~?reH-0qp%M*!55*Xi3?/v޽{3??7o|K_W*#^s#}RUPb逸\rY'{oٟߩHNE4G7@qCz~/xs}쑣G>>}==SO=S>gl||xOo_T*Su~n.aN7MWĥJ ȫ/x~׿;Wk];SRj"lB|94LWdw>u;vک?gsνxn~nđ&&:|3n~WʼnbL0j3iTjpn==mͅr 0076:>mdОٻg}c{Gz}R~@Bٹ;ttos &1XA0z駝s?y/}y>:4HC j~~u\wq ZRUkD3/Yzt]knfqqO'Mwny~aHH}ex߳)yj+&O|S}2޴YWc{4K׺ w =~G? .׾U=S{{=_䣏?pi{nlM:+z{){μ\u_} KlգT~>Ӟuֳ~s=ٹɣG'::9EbgdP~'S 5)*ҬpDGs%ρcD&]8B@නSs]:g(eӱcaavtr`\i0F1OcgVSϏyӓu SA_$Ţ'e_]?|_7s*[Gx|nJґ#b'+GF<#\/S(N_&rY9eӟ3sʎV1?JTnB 6Nƹ^^ }egAXL>o>O>'+ %:̩jNŦ:j=nw}w :/xsιxnvnȑ&L:4tW߯Udzbڡ4~c8f*kw1PIǎC{w?g>st|d2xHn??Ps.6fKL"[`£ /J3t_Kgz[=°zC_be_WP X-Fuףcp2`-SRJg`hl)}]mY'M{S7'?jJd: <K$&C|;s*dwl>|i>묳~GMONiQnzGdžƇܻkνܵc=ޡbC,5ZO^ulT:2U9)$M|.n^seW.̣_u=OkAKi<9Wג~)(q}?ozu<222{/%?򣯽^y>vϻn[X8H#>M͘)iK]寸+{ӖH_{?8t2NDjl=vy^LzZ?VNtV?w(^X,J1WO boT,jX],|ߛa\H+N\9yJ])FG;vܽ{{vرԑ=;) 4.Lɤ! p2)EV[?'`Q~Ie9sǮ3?~ϣj Bst[M}ZaOpA())4'J>k^MQ',LNQ62/)J2z[Q\؉tt)J1sWogpd}d_/y} {~$'qJGT5r~N OUl5FȡX\bX(/H{+W,Jbo-Fh1 WsQ\OQl<퐑0陠vZ v0krg#w?em{vo~؞񩙩/A</k#| Np+k[Ei3Bɗ~%J\/OW_vi_OyդR/zWmyGLlvu[}[*LZ =}\LσiQK?\V J_zy/ygqj%]wo|폼G.[_>~MAZUE~DEzm6z/zγK6rlx\<ᴤA6~4U\޺H3TNٲ/$VyM mj'A!(Kr3zBS*zQUhF_ #;4DXQ^&i襆zv1{Ƕ;M㧌 =KǓ跫?\BA%|.c.Ҙz}0yI!pe//Y-qi9A9qT%!?HsK7 MZ}m9&CUԉK)>s^|K^5PRڷ矹|?$U"ҔU{OS'*yΥ!A ez@Jr .zU޻c97}џ(E.yqMMYvr`>$Jiծ"&uTp ;vkӕW ?108ֿuw`h^p/~ۿ=' Ӟ+*PYk>?c;Nk~{ѫ*9 ޵딳x%?qrǗRdSmȽ%kM׻c^,UBR2d_jK]N_=KU6-lVt d!_[C 2BF4 k` R(/?DIzΠ߾O{K}ow_K{{ݿ#hzqiR$^mA#MԠqRVJ!+Y>:95'{{zkR[FICS7'g&20]>d [ޠ\ ʥ{wԝO3?2?L1ZT*sS3SSs U%2**:'N6&Xj43./~ۿ{{ͿK7QKT a4@ IW$y Pӄ7`ws03E)*˦,:e_,גeYV΁E"'w\u}T.ӳr1;U|h, J`7b* &k%a;{w_C v-}3>Z?w #heT* |7>?ϧh: !*ʷQZ()TaUI9Z#nϏZnln5M8!~,x醭N/t{qcO7P̵P)rs%ϝ,Z_YNժbÞZnkn8MQbkbD)h8d~jzqzNތ5dqmK{5%!ܒTXf1gԢX]"]rA7҆"CƭZ̝7򾹳.x8g]g_O|So;#RG|)mvMjw19qm^O| ;+Rr mW(9&>x_uXX1RCo~x/Cd:Hj8@V :Pp\Q9:Anvoj'<Zm(J{ldjtvv~Ķ7 (LMr\rJՒSs f'Ǧ#ơ zfl7[[^M_ӊS/wzGBrB:X>eWz%WV\K_z-ז+#szڢ+n'le,p3"Wf;NZӾ? )ςQMɑʪʉ7w7(kk?eD{[JOt&fֲ`\?Fj{~_||>N/k[YW e)EͲ~&ܳ=~RX&Yk4H!9t]ZՍ;3Qvڝf8igaIaIj1[256҄?fЉ~*\?&ШMnm|zdrzifzvivbzq62>^Ɓ%qF{vh:^ƃԂU*L_]^GƒɆťKRȑ뮻?޿Egg"BNn2ϳ ņձ/)])$X0KnB87t?#? p^?+]>//ڵ'?S.Oήkw.t3H6tM/iƯn;K a3 놐[FyT*:S1eix_neee] DFBcv)'Tjw^L'Gw-/Z޵U,a ht:mXm"-Ae`k};:}1G`EN-]^?vå^|LScz}~k 89tesgy=]` ҵF[YIC`rvOGR)1sə'Xm &l-Se€Fm}wot;n:|JDd:i_Ņ4\ :LDw0iJжd0WrK##[֖hf<$il kMVLT뵉řݻfw:s[!u{Az^.=rbdH1>N#32kٕ;^w˭}nfkpnGWuRe%-t.8pgѦ܆sLb9?p7\H{|O>ǟdgH(eO+.̟c[{kn}c>w#9#҃C7u'5 \g0(6M8j"R<22%fOHnolaE@mPHubl:739kavay~f^.%/(~t{ G' 9[pщR<D^Ì1O.qۑq-$n~W+*DiDW( )'˜$_!=dc c{/_~ɱy_}3]-2&eRV`Y|{glFeYk^{/|'|$'˥bb1ַu=D pήW oz?O[j[+=GƼVH:#u{qizZU\qlq+(6hZDa4 '_br$J՛^D4]޵]w_D$I$({`^;v4͠8az~|FiaU4^фљ(vox5oq;ߒot,7[~tcs2o8сeq3XR @oC ѧ!WsiY˄EMD$ W,?}3lpy=_8rg"BJ0`E7R[D:c#a7~}ڄWUGJ^vlR)J1&70kvif=,ݏ&I(I0Jf6mAYR@)X5NJ+=(omͨ!@t` !+wc##;=>fXka{0D 7^}~s{^|H[;I3+2RlstJr{dd@rKf.뮹K.٩s$Q=t[ 懏 &hva㡂4úvL㣵]w}f˘B/LarmKEmeOŪ`LgZ0~zVlM=USRpJZW'J2HXPuUS ׀Z:QSKˋv/]kq~?XIBngBVlw $Im'Ƹ<2^ :eD`0eqiIL;DZSB7\t7]MNX9}ok. Pȋ 1`kLީ'HP- n!+&Żo{쿽]3?O_W$TxT"3 sFC]vӁ_};= yɕAKO H*gs;w˵́|ݫ?xit,2f\Yt:G潎v[ݠn66kZ:U*{5c,W:ƕĽLACD| \yx۵*|&]sK{v-` fH(1wMVonNt,ck"w벐0)~ a=,KV[Sg4Qq9ΐ# @ưJ0cM 3`Z )J䵛_ [y9Wx|X',o!VLܱkΘQ\q^QTK].dmfakny ۿu_9z:L&)ǤA~i:Mc,nnۭƆƁ땪8Q.J%-A b.p:o*sY&h}^^Y^]55k̋4$$ ^;MkI*O4I)! &&{wxImf@|o_˟OLL~ /9P9HG #|5i; [*hAnխFcر/Z)Mbs;?^Q$bJY!x7]ǪCAK>~멙nۗ_NW_xejN;-;wX,%EV5)0@XpSûW:}GJ2),^9n+ LMw1+׼k2L^l^ S;f{-zЗרq),g_;xL,$l>깉/xK>up:Yrύn{yp[o_xA$3iÂJ8XR)tYFk[]=b92N:% :Sq&D88 $2AUKSӓ 3 g #)<}N6kGnV7;VF(;Q\XڂGix$E#®K#5G:W}KOQ7{︨V)mVNnʫ9qP+"$AP jRNFt-EUQz9rW_vZu|lm~hMn~L^{}ܲk<׾ZBi^}LM p~?}/V˞WqUsx^޽ YTfs^}:E O< ,S:=?,$,C}FuV.&'fgѩ癹#Nwnm6V֎o66[^GqBFZ*GQ[y]Ұ d% ҳSܮ]35wfrd~#Cl&aI5&6n =@ f&ٸt-(K^xauG>}|vץ\wU'gwM\r试f sI0]^y9PՠLzd+dz}#~{ջ^x%?5L "sң׽ꝷէYpO~|\ +k&-{= n~VO #B'$ʹ"u 5CSAjlV@F~ Zq@ 4\au̢4y`a"|<W-''ǧ&S +Wpq~6ۭ-8iXsZUҌSHTӓfa_~WTC',+cW}S;bDpS?G l Ƹ/ |%\8>>>Է+?sVVO`=?y䱕'VVVv~$IFf|;0ȿ+:"]Гؽԯ|?|ɲEr"x~|c3\???= ;!ƍQ0H23ii}-l^<^p-\ekg9byƥ?sK;ݰ<}4 { SzQ'/q7uuc{gj~MȄ%!oYŤUvS谂$) ND*̱&g&cذ&}ozˏ||ßusSJ]r:VC9g\m{4OgqJ,Q'޳8,T//ݷkϱ1δQfa;˕ƒO=O<Ŵn)u4 JcfQʒ(@iOeIW<i?ίi@c33 \^e^EIomU]~$Aqv=?]Ad{Gթɹ٩ݓщZ\'i+kW7O\Y;~rmVAg b 3zej㥰{Neaχ Mn0%\mKa荷_vKACmYUm'ڋka 8x@4 LZT~7n7 EKܮ|WNO ??3-\X\Ln'+ 6"b!+2SK&C 2vmW^X%uVG>ǭh 3'>m߹p$X>Qgol6(V*zpsH/J%rw(N`8nSHd qJrU+d}ttvfbfafjayavh2Z4^ceckc'x\v` b dY(lϏ w,\.M8@uYU{ny~zWZ9 1RJmq8 ЩHG[ .]핝m.Y>ԉ϶NH愘(O<ۊ K KϹ|WkWŸBگ mIvt̻ ,N Uي>Ld9_>f{uĥ؃Oo O8t#dn45Z<өlDLN-{=}=*Y< ,`-Z2y'K͕gw!gIxUn#:ebT=\sKK{=Sڝ^N:\Tvny22QǑOLL/-{Q%4Nsmss[Vh~;ΓyF-&mq/21ꕶ/?|\P "a`ݿ{ZigIdd6pLб֤^i~\WJhiA؃zu\s[1P=fe1T/u`rHxXŽR͚0Y4$N]80YI v{"lN__gGi D)jA>W_Op.r&2{z~A/(8jsjiltll|>9190;;\LDQԎh6N8y_l*Je| eU\-b`_ ?r&r2y*J:ZOǦg'%($2h VVx|%"8NZh>)C((. OT!`Ng;R;&d;:Z>c<(hLT24Rr2bRwv.n`Ecļl~酝칓O\\L>~* & 0 ҹ6C\}qzhWVej־f"eg謴`qYKӻflcV 8d-F^Ә0kv6^<Ʉݠꅝ^!ZOkխFoݎ~Zs*Zi'j[v9ڞP?u;yfwًa"! IAYN;6`D!L8%+9/zWN;Lyp%њRKScUҲ=7[&j yh۽8tc9Ra3<ϳp\)0| h=цHi[<¹n+,BuAN;qߕt^ϮB>? QI\$22, vZT$fn(Ls FulmcFql8yO(Fsllm66Zv Sj;҆!@* Íf=XE=By A;zrFad 2HpyJ+@1<,t$gLZt;;n S޴ie\ܲ-\qþqK(H_x=6UžҙMb+=P=$4E(Ӯ=XanJ0нAЍm30E76oہ̝B3s!D \G] >5SzCp5yKٝU&36O _L'C<ߥuAYɥ j.KݒQԙ¦9UYc=IzfV?Q\8Zi;=?bjpv3[q ͕v6z ~/af 4̐A*uʤ-raC1X)K_11yXMHH܂5wp˵pXa|r K^k=9ݛ{.y(PNh@ CRxl#ƕ2"$!#,mtcqgO 2W) rsŽ١)M &, nzmRy۵=kG3&Sa)o0.6rkc*| e{5~jN S3󸑍dΥ6?=SȩmM|Sw,iu;[ V; {a!`Ncu^oN"*cPWY/MV6:Ȧe6|.O͍c+~gFLNB$֗Lc[Qz:95Aoywxi8{ƿ$8+>sO<^kv|¢SJ`tK2LLy`pw}kvٴ˂\*ygɕ 8=.`pC^0`_JG1Qڜ%O>} \aŮ&&&J͒8N766ܧi_l3稘`W\=gC)2xvER;=؉͈adFP?yccӢDavzq(.VV hm}lv}| 9Li ^[;Q*!sViZV 0R2NTCFTt.Wjt|!Nx?gsSsg.r7A=ʚ"Gʥ+gbܥS4lt7, ҿ) r9>X&I"eddA؈,4-Jܴ&GfZEW:_}pNڰ6ێbP.?T [rxLr=۽8 Hvsќw \gĶ XԈhƉJnE_( h'dR( 2?2Pkub}讶a#^LrȬ29eN 7jo]r+e7hA[k͕j5$5<8UX4u*}Gy+-IBS hxЊII5.ZNrN.s>6^D}02pB U*u ńIJ0,C94&ms^`Ea#'(NHY&-Z_[[X__hv{,KX ϝY0=)̬lV6<+cm5f~Sfi4=I,N@k-CEiN<"AΏWjD_|4t6:V7ݯYHW` 0J\ݖlY_wD5m|&g|\FէZi@}ij+nIN``R)n_JL OEZs'sIY1H(#שQs),Rc!7 -/C[hnb+e g<[ioy֙[eQrhTJ q,"2(2q/l^ՉiVo?mw%Sn;$,e+[VswFԌ]y(ZNo5Vlz[n܊aD!|:(̀\ SȅE4fjcq+vtM7} R`"ErjK!A`*-4 (lGk "9wxYtl4}@j֝F+ fh] 1;\(8?B,8h|5TE#~HehAm MW [jFf39?@`·\*|} (aFfǫ%vUJЬ+d}GZ@fi359xq47jؖ|Q [{ϐs`gJ|G>͜10iVآqM1ױaa='m4G,mQNVou4S{&xS^^C,I@:^ a( OuP6Wڛ`nt()g3Pyg35Z4w6vlluZvـknQF^?(EfAҶH1d"iv0l+J'O*P,4&jU䉪-O{uo_rMsx?IOڑ?~Bf^!Hf :mW&jgp0?Fk!*= 1=hD<-0 L|`#*ݏT0 ][;b̯F[V r,fk+<6r/,!ӆ5Ahfބj4UgM8pdgҸ] y<k{4x8,F.39!Lx4C4vq^ hZ5D`b(FJ8F ģkxbxI޳FaffeTy>:έvMw>L4"V(-؂TkGk(_;03uEym>Z.^+V;/Rd&sUW^|LM;ޑk럸>*Kegh!Xn6uh/jZ4Ku/8S0UvK\Xhe[NEi2x᳐6+cBJrb!E۠fnjz0 N;ą@&;b>e'ؖfP̻ձR;/|1ي6)Ieddࢴl2Ӳt.NA݇׸17t`| y^ԎJX`s6$-j-9;mC0̠BUl~+~5[x%{Bs55e2%ʕ56Y+(j+$j*gQ"A? 2S3Ii+SeLi˱,\v+ی1cym=eʐ!<(J;dmVjt:VAaSp/7/YbSZhh)Tu8꣆dJ|23btBc酅K~5Ց3HG>u<#v8(ӐJA&Pc4{ !lgXڭvEym`ղIp.К(6|m^OpfM/_2k;ó wQa% EBJ_:ZDekaa?6Wv|k:īNgZ!ej|%:t2: g˖m%c; mI؊v$,kIlOYR*& nh ۖ#mtKܑPz-^ !1?u,z-hq6qPOA^"P >tf{\3__5<-pes^u/ z[39a!bHϠ$vQw׼gTX'.uo _|OGiS_!'܁C3n{p2h}f^g9BVi'6D( SFO򻂴Y;t@) cC2e dJݸI7[31[$30K2k /m =V ]1i@x*9W\dS݄iƸRus_}E=22vM@3] q zv4IF QJ!Y>T9cc:Ӫ7pʋN/Qf:DX'#NLWp IښdU8SlW8p3ɍF0%vqåYun_\wiM}?{~~agi&HBtW.X4ݸ$ NBx#{jlY4I8Hw71gH),-@v'@wHN4[`RV3)Im;\fŎ`5`-R!?SCzd,Cte+"Ac74LZd~Mt7`ǎ߽kl$\B(9 3 DXdV~Y\ص׼uX[<4#Idy2(Bbف // RB96IJ-kt$>MVgО:6 m.HKJIW8I Oudj}Jʕc[a*$#Ie>LB"EBթgp/(00^4pt %`ssY"_!W[t9u7~ɑ'1$H=tsZ@,9 #抢Wܞ4Бh{N,+&!8A)WLJV/p3} AUl [ؘ z TO?'6|x:2륯Wsf>{5k_ݶSv~7At䠇>β(P3sK5}t<9ز <,r2e Ţeڢ4P[caJÕ019tyurm ^)c &`RY/ g9y*SȔ0Lea Q"/l8 n>om|Wf3(fs9ʭPAw\^3H `ife,u&L}TZ- ȭ(;I$y X$W91:Sr?lq :|[ֹa~ѯ=rqTLO][TvZ|{~G'AȲdrKe"W(:}v)o>;]&'H!/ H8zn/5 t^9ǥ^|'Cu =c)fݡZhq`w_:,%Y)>L໩'ՙ(X.;aR;XR(Mc(Pq!mW i3a m[%biPƒ\$HFi$ISH۩FޜH9"Jqe2Ёu!hQx't"s=EǷҘO.^aiT +LknMnO(p n-W Z})Ponb,tx׻p7L}"-Vu]!4$A,byV&HodؐA,PA6}MTKt,ًiv5>t=w1~VBq\KbJf:=K sΰ, '4y$NUd  uF$൹:`}B3˗y'3qۖ1Ft-x]rǖA=ҠƑɃq8( TB/H,+M#FA0=~[:0்xo]m'ʸ5L2NV/?qBhxcRK;dE[ :; EIUQ+4A`p6$oa;c6^܅p´5%i9Fk &oz"({9t$#:#"bc GZ((\:w"I{jla2kTw`L$&M d`bER:W9y`c5MQvAdI}$%϶tFY^ v&1~YD^f13Qo˯j'#G/ZP]GK@)q"w ݅I{\{7rv2]_>It\ӓ@,͌sxW]} 7|BJl +n0#3WC}-l̞ |fxpYhǞ`# "gӷ4~GlA =.3lK 1iK!ʋK{T*CqGs?~3W$oZP\߆r-!<;!gyug BbC<ϵY9rO=UW_s0FfV+瞯c' 4YR E)KlRe;qwqwJva"L&l?Sҹ X#mۖf 8C&E!|95d7\{ BSXm`/s cSL*c^(Ҕ䂈x7n [x\*|}na:t򙍏[J*adpr[1ڧiӵR4<,K58^ *mnsUn80^:Wlz=wLH5&X貥=#ѐ%Y{#.\5~c^wƯw˅Qx(=YW9=bi~ֱ PlfPtv#.Z+e;"|I۲6,-l"K퐢Ү,V,"T130L[H]:12@NNgVKXv? C:RE43W7G>uϱqC eH1tKCJc'<Y V)}r8d: 칼 O}'^\yK+4a4:h~ =bù>G?}O6hO[Pjx^班>s96RobZ.m~GjeK.8۶ IinBܜ3 gP}bPXlDZd\v˕JEHP Dz[vǑL.4R+<:@S s𻤤/Y^`,2??= ]${)-O2^7#f$쉞:"*ٙrN3"n. 3 r.Qqԧ) X  [ H0SXx`5@H>dsֹ8D:t%^-b?R(@4}.im;VTrKJYE2+OsnVBPp:lWv>yfEq$H;`iY {QK+ {hŇJ1OFh 9mM:ж IOɌ6Jg ܶEz=Ɗ?|E}j|.%+nL~'W \ze<mO69\f"hʾ&Ì)vbKʾ4ٰb8oR8VTʕRյg̲xfW Ҷ%6w %YRH$a iFj<01&"'jOR@f_@OrrZ QdAQ܄";>o{A)hD/)>A-^F!$/{ٳa=sR*DA֛Œb p Ϋ˯|mec G/.ܬ0%zf~~4Q;;}im۶o߾B:9ܠG#Xl J,ȘB>F! gmI#c0L.0 i4@IIN8Je@bQ9$ RN"]U4&}_\"o >?^aQ\*J{uR /s׮wo㰗 ?zO/mLĀDI8wZs祙6NsB8S_$+f Xtmo豽z*aF%GN_է~+eyμ_M>z)폲4[tyҟGaPi8R$6Mf`>gO]r^6 ʳsA+>H[xOǷe^wA+ Ӓylu?qeBy:ۑ4`R)O׳b?ł|rg(6e#l|>Oet 2ϣ]9_`b, @GJ(>7u)T;<8Fsf7ux͡dv,۫x^mZ$~BxҬpk-5tRZP^Yj3P*x8d`u-*QDs_W0ăj(B"fww{_ԃ~ٍ/>tY З"@X1%ALqM(⾩kAC`dlƳnY6I&ef F䠀?(0Ha8pe RJ} YNȊu9r38RXmNu#%;b<E  E%Ѐ9I!3椂yq0٩ן\۩pߵ%{].W;ɸ{nS T/ 钜i+s ʹ,_w qǝo@;S?G32GS:?gJ⌔+#]?Ö\c} XEKKqvb%RgJݭrtqϟrM,V N=!QhDZ=Tl<~7yf0@>zr'Þ d!W$AzB(qg9gsSu]vA-c.(:/&Sr/91ۖt_g}⅓[h6?)gV*caWSqOJt=n339>0b-)H !^?A:ߛ}7S\Sn mjsje;n7L2,g[zr5„I TyٓI+2.gvHʒ7*>S‘zܑ+3N+SDdEronkԃqs\\fFlZQG@pNc.B]}=<9.T'8,Z4R8YĘD S;}&O|Z)JRgHS H>xe9BRTz绿}۲̛'>яJYJ4MIY*R)X>dlnl| m1qrzɧ c*JeyoDW"_O)X ^ɕ%cҮVt}zjfƲ,j6fj5zH2,M ?DZ.SO'&'&&&q6;NtۭVڭt4@*Ӭcl$J@qZn[ldS3;(݌U1 zXj+> /XCsQ}#0m]Ks>NDRX1MúoKէol*^T)WkeYnn$Ҝ'3)6ŷtTg]>wηI yqxƒ YdwʵYVTKTԪLSSӳӖfeq/iE H!G!@sWl[͸Jmv|N۷ڭcm86v؍ OڧMg|53xH̻.uģ^g+:ǭBRD&7\eI0Qx x J|K=1/]ȿR]CRP<|:H$+鑧5:{Cu,_5k6a8f(dlQxJTT#ɱX}fqF(JڹdlD0$RX-m۲-K|`Y?G幊2ȩYMQSlR,˶aZB~_ɝ?ӏa/m!;W*EBz ?<_T0p`y+C12???3;;Pe666NT766*fu/w]W:FF*Sӓ ѾhwڍNjZuKZY~Ko3hE{Hs۞^q7y'CQ%Rܑps8~ŷ_{ f'8Bz?tӟP笫f󘌲U/xa2U Mqv3>1;iD|?aqʽ7(ա GV:3$CN+I!C2=#O_8gڅ_8Oo>}lS%DžF;Lno=Z!1-Jlm0`%۪s1#fvAHCݍ ,,ffb7|}<05BdHE[.Lyn(^hWLĀOq΂_K))a[]对 ohu[%ֽۮd-W]tɗt+Tg00B0J΢3ҮsaxՅ|E+v/Lsٕ{nO>sg$Ol_/>wqqSmzksj36]׶f'^<3dD-?'ڦcjщx}~vzfvfj~vr掍f]kv$iލ@3KܵX<rjsD*V^tR6J4|D7h4p`(z_J%vE&)@\x7ʋ intǾtdH%OkwX9ɉ6G!%JK =bN0Ҵ5p 蛊r:uO9 rs\=̓Ja~}*Ahq+Ͼڤ9,z5Rcs3 Ss/7W:Hۨf$dL,dpJm@5er4tSknc|#w֑oxӇ!祿gٮuos?rG#`j84@ء(H{Ax5yz/SIP^Q(văf`;]z#c쨷KJDy*IikWhYӖ;Z9۪̺J\::ڂ*VyO^?ޘ/D7υ;u.s_?H/O jBSmd8tQXL},BMe00iMІ K2,I)*WWr??#TJG*Ҝb)důj8:$dz u',׾GI.O~Z WYDr&SL\J?.xc rg8RJ S:8Gs/X/C[`*XHyzf>;;7 ta~ŅnڨyGlvem 65 P!e[RժS {wse[nZt:fkKZ&ij?qJaqE7`?s}>QzWX5fpX#S){59l>O9tQʴ*Q # Es_m{ZΗXpm*fpqJSpm%f@(; @,V)Kg9hX JHȼbѤ84 6s,vP7n)_J2H߆v(9gװ6"LɜпbSA9cD g\@)<ԚY_a5p!tX0_Yq.0Ns8dNt0CI^TK0 m)GkD}|nvjfianqavjyqvjs(ym]!}_ ,4qlҒOZ^왫[A+WZRْ,(hmІdr ɣ QўJP~N| =S/_AEؚ%U>t>t2i^(>8-ʜKZ؝q!/=)/* n8GMhdJ/AĢL2O'>+䙊rȌ 6ļ,},!Dyy׮}{@V~~w~O媗e9G%e~4&* CQ-,Z[0|Er$J|ESӊ }qzγ+%Vkss˻/`n~"sM8tW') m(ǦnqkJeZlAFj58Ir,>~g/)B¨;r?i)[@[ wώt|xϾH<}^w ^۽f}Vp#) xC-G)4 Kc6JjheSQ #;C' }gl IɅÄvrH2hl/ru̸prB`Gך֧ylqy~">3HǴgazkn %6Lgfԉf2P҆R^ -#)x*,HWh!;Ki c4`ԅ@nX#Պ[LL.//N-,N-LC)dYii  Jg1g#vlS^d;Z4=^umT<ǭ]wyY﷛r:v'T&4 .܍)I3aiE_;H7G/aBj[yg{e}1Rb U*2LiWsiqI#w(Ձ)ԩ cUc:_l`v(Mh T ƶ~N[yBspQvk8cQMMXYi(gm~uExy dj񩑑ɥ=sKӋӋK[g䡟&~+ \p#KF~hTj% 1T3՜uU|b CE]̯O_7>=-z<_aAaٶJ56ZOML,͍O-̌O/Ea[EY:遁ΓvdY޸TB+ttG$MNӳD&d@b>()_u|WC}kT‰3,Ngu0c76~&cJDႂ;0 T α(W*Ԏ?裿{ZVy}\P4.-0;mK,{N/JY fgCd*%#<B@ PL*Q`7t0,c.gӞϜ{S.8t&@%*]Tj,-/M/-//..--/^0666n%ϳ,InjZ[VA'IcILq !v{6hRf\V:펌LNLNu{$M|vjfdYVSA·\|V|!2ҿڌwBYHY'KUR,[a4FX< RX<3|蕋ۚR s] *eV|.xXK=7p/ -p#6'W&C<9m18U#14I s m M0;*fj=-XuAk [JVVgvO-L]raZwlׁ+G'vznvqeNRG9˺uNڥJ٩`FlKǪyc?qT&NML[YT)8HUD!y~e-)o2(";&il(@UɼgRO>z /SntNdCq4A봠\b+A.Ki|ď0.Xe ss**/XoqTmkX4|zDG{3$ʁ%T*4>uJUm?%{AJ=֪MoΎϔ{>c+[T(a/F2]7=tc|Pdus*"XxQ^6 GJ /XgP~Ϲ$=Թ\0$DDŽzwg1~tRqAx&. •(+nR)Ԫ\26*-V*SYqà{fⷣ44S$20Oru ږ]jSa:x#Rur2G43:N.Z:N1m) B LR6VMyej 0 6SLҤM\[5IK򻴸 Ҳ@??%\zN/~){[JaJfk`X\u,O^[nݩrჹ\)yo*A ` }02iy['T}[թO8uzerrblyiyny򁹹c)Nl5vAIF;NM8];F\Ż:rR8Ȳ4A:8M8W :e8ӃxM J[6>\~ xOl9\W~?ϘLTHM&[s#a0_ t$onP\ M%B0#4T20^!g׏pyb j"4!̑H,ȤR0fUr`n8@U?q>@$8fiEƶ7L)ݤ.p1'-ZyĝO/]ݽ08?l[?0^tV7ݰqg2ei&bkg鶃F,WHmZeŵh)Y.ci =y??1o.{HhqqҶ]vxdpnBOŜHkI:4,)URzF{I\ d$r3 òm.mrdm!#&@?AE̅4a/Dc5dkmd0d; Op:@3)GqC62u*%׹-h Yz{ Ws_Rn^h*D61910;kqnay~fq~nzcmYA]?촻~6=?8N4eH,ov6 فe4MbxRuu(8yFT"Q 5_=3(]bƽm|X΃[rĞ燪-ŮdP8tU&4q1@,dkYXкfh,;.N> +`!}oY·_7fyw<1>}#n(=R˃*Ɵx{aUٮ%j#Uob>2951{nvy0.Ap\E4c :f4&4R&,SHGUdmNw[=3wR8eklj;N`'%?gqQw]3TsQGeF+RvEoŰ2&ʛ󎷾rg??Xs+3 $"Z2@&C D_O]__XG|@ J7H T*Uozj8kyҮ .ݟeYeiPz7VnADIei"S+ӈTqĒ7UϵjmZ6Jr 5lpqɝ90B,:~q+GfɷwN͍ (U>Ǟ'3?uB(C1 Gl@Aar\D.hNMu %/]wѫ./N ;4Ksǟ:+W#^oa"Iځ]X E1 ԜF6"/x/'r 9gk a{R Nz-aj ř]gv흙[_tzm:vЊb*G;",vNk9[e,VqG*WjC-=Y["zߴ*}326 X0 9ϼ|EF#OEBnj@ - ۩.qi|ԴҴi;KN!V߹+Z-dzK/o8-dʥJGbYri{q^e3ۛ\Ď$$tXKɲ BK$!8l˒\$ٲ_>o+^!$stW9ss<^:^MC2cN&8V71VP}c2d!k\z ߒD~%T$@hQ|x^4=9m+wlݼkǶ6o.5L$8AtA۽8\fIG+!sGnZknq4CCjuQZiV\֨>*8vնsdk4jR(v =H)ً_ϖ`#t)|NQPQu05R0S*A"Gpln]Լ[ric CzNwD[:Fݱe#Dˢ$ bJeLUiZa +3'Ƕn߲eǹ[wn?g˹;r8 aiJmEI2Ms%Y.3(& UnQ,jCjud#%8C45NߦkcN,mqJ$kz2nЖB{\C3#vVOUxPH\X""1;-0C3JF,`\MZ).z3,ŠH1t{DntY{d>0#ŸY/3ӳg7m޹mjvM;vLLnGɡPyHIԏ;hu2+TH$rJ"ծVWmW5_U*CJmxAwTkrD}k*#L$i8\A ar|݁`RZo' !_цARkl,ooP 뇺n֤1ҹ|K_oo{әE|{,aZeZs˝M-WHs]\]w&KL%[>Oq'`B(& 6Ydě-U*`ZT0%8i0r']TFx4THj^t=gdx:=59y;wڲy-###ju ~/--.4[V fgi㶀!0tN]^^YVk`b|*Oh'|߯Ⱥz$AoпI!c"""U?j+ϭT:ܐ]LN䏽mo<gԹ|b}_rkRGh `)k v1xDړ[49V]wf׼e/pO8Zy+졕FU9WKu`H8Z|uEyt')LE HTLrUGDZ' ɍJrAzţM`8|hhě2c97Mm296i1:Vk,ﶃ^]X^,.{+^ݍF:=<ypd~7j(Xk///:+wIh@)̈́r t*ES}Z*?<b*܉;mYDvb2u/q ,s+eW=B\L)6(_ӯE ?hGkGank'ⵑAxαwIy~ tR }5,904AAW 7TeTbNcƫՆ0r7j'{VM OOoڴe։ͣcS31߯6,k'Q2.5{nN[fd`:6ptv3e[fʩ\ȸ><5ҫkԆCQ{NQ @X&92xuMveEn|݁v'Id&H"(\(PPh =bHWQ:23?V ɏ]G:s/x[~ggf6msSnCq&R?x@hIjF\w]7C?gҹ1طo﾿|ϻN% JpA⑱ $.9 \5Su2@ƜN7jJZ5q5+-æ6@ck.ܼqAW<ϭnQ&''gggnٶuǎQz'-.-X\X8uA2q)pI][+.$*ͬn9 i^aO;yVttfgnCVEڡQp2'^bl||)5/jHYZn,o|U0zgkxt.{n_8Ze:~V-`C@qrwH[V .ѹxS5*ЮsR5$0ˆQ!Оݸ`%;}0_/绷=RXJx -F2=)Jf Q)ؐvXC9b8t|;f99zQ F_ 0oaRgA ޺;!wjCO=B4=2S,%ٗRKv}vC훷oytRȷ 㠻^[,,-u痖; \sHIG0sB%h.hUγk1-] ;rpZ<%4nJ*H{7u7d6ke²P'X*O >b_f=M7#^o~ؿ~q\W6~gtq.\sUxG1,DF"ڌ֥v\xO?ٙuksKK'xбt&ӱ /Ji/wwn]z?wyl U:TqQL`^銔ZיuAp&(8$7FKQC(NrӒ4ۻH`J֙[(Tndת^^LMl8[vnתuSkDfkniYZl[+r$Ab݊'JI$C'dMXIAv(8L;dg|trvzr*=-m%,5\z~Xe_&YW%H_+b芡*tD*Gc/#Ѻ\9enUSYX:nIfL:}}T-+||o;.tЌ j"f*ڴnFI35Ƀ3K|;q rO L4g`jRr}HTN 7VޛKݞR"֋j (v!9^z25=>2yrb;rtnsGwW[ssҩNkd4ׂvX)=oqʬLZ$M u#Oq"w4469ӝrreQBYX v!Xf=g;l6Ҏ4\)_(nLD*u썂 ;ᘸ g$+hB̗'+{ ٺ +)#cF,Bj +bAz&נ9tOV8wMr|[ߐ%Vd.G㨏W^oi䐃|QQ飳jLh)D^}*#SN74ԨM6&&7MNlrtZY^쵗ݥf؏z丣89$==yA~Se*xipb$)NCt|f_5'ƇFGScSA'tYSljN 1 q̕r쮌]!ؠ5W{fH+  PV2CS? :qB&zSvyg{/z^QbJ)W %a 7OH b[L:ǎ=|DwIo;eE at )~zrϽ~hCV{soy9zȆ.yA34C6 Y9 ##͛mۺkΝ/E'N?tر#KK$a(sB6%dQj4;N?a&4Lh^nCCC~Ќ㨟qD3ȝv!%`Tvɼ|\kHc3܊VMAtP0h~刺=]Åz}\⃷>p~&uH c "J@7Kxqت0Wb|p֊gdKA*V`U  {ccթM#Nm۴m-ίVu~/~YZ8x'N-u;V$%H+u"QTI*'Z,1 iUFc}I20H!z#UC/Rgf,<;p&܃=xh $( a0gst~bK^Xx*k)x߁m{A&u*ՄsiBp* bEU֨fh@L],":+2:X]b\է=VݮvT*u9IӊPjA`PUx}掍 צ6Mn4ml=RE)w^8yt N;fvW´ߏbõ|ǥ4uGvKYP4֎nPQj1\{i*' & xw d-ssnL@@ AG*|(³2p u7V+a!+q?/̅ tq3kv$ʪuaƴ︺b`!j&|Jhbg?aưgݨԆMM 2 !ܩ 7ieI~͹SOK?{5׾x#@G~}4Kpaz8;D5 H2Xrv|h'TO䛟NOĉS' ѤW<.#,cv!n@!Fc]6Iјr9\) U+/عnz#<{*7W:f՞ĭFߴiv֭[/عs~H ,ʩcǎ=tṹv"f)Ѝb'p_bFQ晌eHiX۫jh5(zIY\Xj49x2n p~u/ꛮ7Gc6a}r&a}8 ϬD$i28HI47N]7Mnx5^iL6jCQ8 4$ [~U_K엂yVԎX/NإgQ˭ne_}}üi i&6d^B ++`'S.*ww\pn>pMgBطl].{| 7m;<1t\7u 9+ Vjs2tpV:| ߵuv9fw1~M['&X?8I{18eQ4jUhNOBۓ9q =glxc?ȴ"D&)rFꍍGpwIDAT4&&Fgggnݹs֋T"I8N0c's9^ʒ8iKv˭G|^e"\ ùH >L4FX$iP:O݊ojvlZPu>TB;440lW8?1\(a呞 )2 .Ua0[7T氲HR{z};cTy"zשW}Eu>߇mf}*NZ1>qUQ_po~ z^*iG>>LQD,LݭGtu|f>A E%Դc3#?30Ƶ]ƽ^.-=)'s|'xiSi ;ΙPJcAϢ_*=45{= <(*ͅ`_bb+Pa^{V#cM3yNY44 (vˋsOΝ:t"h/Hsw,t=4 98fR1N 1Lat?4:=p?TWkzIiEq¨﮴\!5üDLڟ/)S(]X&x# @joO/zы^XZZ:u k{^{+(=zd;u8X8+ t=&3%y0~S3i,^`C B֗v_><>P8qQACFả nT74kdi* vs_YY>i+~uO?lAOHBQ#͚n J]f֝^,)at8fYάhZ v{uC-f+}.k^ܻ@峓[7d"U}ώqy*sZR()cZ0':c:pHµ3+?[o{xѓgqe~W $FݘǏr/^ =sJS\ZiԢ$ 4]ƀg܏ ]q6e\x[7r;O$;:Xf012nc.zå?as~M/D4QX 03x0*$O i>iv\\i-$~ǖV۝V#[ R9yz`Rf(so8=o릷U!<.ȳ,GBZt~Qa=3-Qӳ~Qz¤p\F1VFJW38}WH$ 0A4ۭrxiЋ:ڗV{ܱŅN̕ƚ8]&5 n͌6IJ㺹\jCpD@2264\n/tZv;,S!< =oH2wz +ϿfkcR.D.;.|9MǴfGБrY! G'S玞wk/9B2W~S0wVCw?KRu&FxQ ~4;br8Tngqfsan~/r!78*ܡuA0-\R]+_j] OϽʊ*PSy%X\uZ˽ntaSLh $ 5َu ^ZN% 𑢡y-,%HK~#߷Þ6;Ι~__H8].,L|-ş;xة6޺&Bo}k-}"ٚ$Mz}_wq?YrǙ_ h4#gf6M o|㟽OI/yWtӫop`։8={VR9TL;٢űt=pX qtfkڭG0.yJ0 *P"M6]HjFEql5,;^ag;urqqn0$Kk<΁20,g \X:s΋HL0NLo-Tlb0(}~?;NQoݼHA++ T9$f-BIVr\#d-G i &6Ddž&&-:9xrnqiq"ARxBʕ2llX)* %Lu0Zu!HguWW>|v{˯ G6f"_^w`yaUff&e7>q]<|ډل%L^~mϟ\YYZXju ITIJ8S#X5*7Oqtk`<~3 ͰɑKN.;578qN/TL?㒎32hvdz/Е034qY%:,q sq_H"+!qYqRܟm_n{RP:]JAZJWs'8辻94ȟħ=zlۮnYoR{׽_mGҩ١m׍Oop^?~GsbA3q|}%7nuO~M_~[^ꟼ׾nFj5ITNLe#?iyn}ho~a5—mykzctT@?`Ɯg=fd#O$X& 8箟 S204D}1*CѢ#C߼yˆMFEa0:62MOmՎطsoڴiW7dZȆݻ-LI!Z,֩hxAh!2U[FGWǡVlۭ^Ӊn$as4]k hSAIVIBaQQr97?wb~~~~a~~eii8r JeX_G>Ɓâg }xU,Zo헼uZ}o$}Б_:rL 2CbMX+^w̺Ι FhY¡L+w6u1ͭ:BAay~/Dc/VjݱpZT+NkA;hݰt^扄 )Man;RK6FalLIML,c<7A?Daԇpor~yRiQ%* aɺ|N2 U2nD\<_#'4?51vﰋ>#2#rqG:JZX5AWW_v嗎?Ej>Ȯ`܋w{ћ^z q5^]/}!zr0y_rXc#kj=Ynu{h/Ӣqpxrs9 eŷxoz[!԰qN.,z}*{R$ 3U!X"YZ^j+U۝~^/h¤qI!١+rLS0Nb)Ji ^'> ťs s KKKKv`d.La xRqP. >^7 3q G$s\;JcFX Sigb^bܟ0%"H2;n7^vtqO<bW.屯Uн'fwL].0Q~;oÿ3Y}q#=tϡG4d2בi$B`&`_:2p>CJk]@FLkOo慓S;/mއjȵx31(Vڽ/|䮻bDh5 H @ZWy0tR),:#zA/ [+VgktNtAa33 dܕ6դ"`Xw.2Ih5Eal6AIOӨ?\8xr~nqnanqyyit8g*nkR-Q**Yy ^ G[1f.VsSIW~%^wjEyMȰR :xQTT:ajnA0V䊗_642C\>p-`cSȸ߽^{Uch}l;~Y"<>7t>~x8 J3E # /YZ[]-\~q_ɣs'aZd!6N]VGeϥ׼度7;?'7c,r;?su?:OsI=D'\>LIQwGFFp[qca&a;n*Dz!D]gїݻ v]Pr܁se*S%3!%݆]9B7D*|4z+`~-7۝f4=Ĉ$ed;BndARHxb&-75;dTez8,Knw riia $ ?AXZy~\|FmI6pw\ sy ]F6SgqDY$6^m:Znpm<'! @Qrx?go石M뮅>hY?[\=T:YPaCǟCarKu%:ϵaT]k2RDpK;>?~1J ƚt|s',Ka^J٨D-gI:Jc!(|xV> f Z+(Pd"s #dy8%¤p͒q.N*Nèߏ0J$KK KK f;,$,9-hi".sW}9Q AZ\.r)WnZnMx0T4<|?$סV*!0NSkqhuv\uauhA3s^6qhy)&iw{nЭy&;;dHys{n{?{gYgгp.Y MhiaRM~Vs8c`/Z~i&HN\#ngTNw$i:?+e LiGWlY>2{̷7ӅMI|lJgT"ѡ?=Z@D-,S7E.۵yjۆ^Oidn;RwP}VѵÝ^q}p^t [rݏqݿlTE"U4@X5K+a"r͙T$y|AҏzI/aaM1t42:0K1:UEqATlRUq\y zNl{@(N3*the<>2Y`]-YXHwo?+/׼⺫naG0Z`BWeکlq>rW6HX1KVQO꿼<9>3?{>hIEHh\?Os˦[g͹=RR}W1\]y?\‹沋Z9㇔H[Ziȡ.FB߂6)ڭfP+YhvQ ddh6H [oZr򓳹ܩk0n˔ h^㙦6fI hz<2tUJ$75?3c(9gLRF[B%>ӕZ=LĒe`_f /G6O'GZև:$ӊ>Tס#{}g~7L>}#Y֑N $8 {;!WABN{<g %iBe7@5o 6ϼK7>pY(Ut4Eqm{0/MfctFY *2:а' L:aFasAfPA:VMGadJv<]<\Z{ckei!AZaxml;8$*yCBe*aM%&ԟ+14p庐Sr)4p&49dI1r]悥=5uz='>tAH3к: ;m3v]438%7=yОR *@]Lb`gPҕ?#S7)Iq>u'FfBBU*s6]x=>O檕&234!4'c7ri+v+.0$8qi,,^PdI_I. ~[C2ω M7w6>ZuX; cݒAlvtu ^ʢ繬0 3Ъ  ql3w`/A/ C$҉`ȯ&;@rӍf*/tOK"6T:CiV( 0LՊU2@;8H27Yyfh # Z9{'X{h7|1("02W2wԫ^NnPq';|Dd:QȘ)49W NcU}wڏO|3Z\_O?("rD9u}vJe;z겍 z薇~=g^N&':P"gnLrsϴrbV;Dad2IiT$Щ&t`t_9fV3˵+(X`!b7EIo!Ƃ%qgY*Dc:ؿ`:jg${i0\RJdYp7u\Ϲ};⫮  ˭;CŻ#c'\g4+GK* 2GzvR"ʩ*ߵN̴xRwqiDk0IH?̖sfd_xC 2]rl?WR Bh/"fig ø~aeq*8d!KKZ<=x)ؾ #tTЕ0tNeT8SJoSH c)P*ó*.B!`r8(~.YWmCo~ o]9@L9r߽ȧ23K_]KL(o5W 8*%hwf"cN yi( 0JOeX(ʳ,"'y p|*EY혁tH<֚Eg3XsƧg<.;?xJKRjthGL`.?X0$LYri.@J˯j"2n*ZHro?}w^[6=mw>/52)Rɀ)W@_[jir):Kv{mib]\`"w\OO;u' oW^LVq=t3_E)R2<ʡGMC;ʇqo;x׾+GnQJZXnǿxVB(%*-҄fxy?~Ǐ~ݯ{+ݱe@L<ϟ̇>K-S]a2`Sϧ7?5,;?g,ϰMZ+2: V{͟:r䉟zӵ7\r^qfY,/=t=e%VK{RʸslaIx/tkcffN;Z&ؚ1RRA(/~=oy wL?]ݱt#U,_Y2,q$Ð$\,wNk ;ש@^iFYgfcH=#Ggǣx8F%v`JjFj8aɜ]4d*(ȒOmn.n|s݌Rَ$VeRf`>-X:2vZ] t{K^A!ʟxh{qK Eu+eXZ sb9)/St" .݉hF"I2 =.}󘘜yks}R‰[3pÄhi)%XyD}hA^?>۾K  =:JW׹3|$E}NkD筿[dr1 TKD*36bu#ƢkNݯPu*|Yq\XK)A^I ÊEPXBePRBa8r̭8;W[sn U>xl_o[2mfN8ShV͓+{$h wP*ʕtHo6㺞5^q+Na:#둗_nu^U6(>@#:p7{n=ZY/Oe_$,LD@*SRd0,K Ӱ=%':t8p'('K%R6gQ~P 4&l. Z"-E X}AW!'ti))ZFuhFZ:)p2xܥzzk5T9ǯ‹^su\Ο;\bG|h{} i 1ǭֹN%W??Ԧ떻x-_dNYKAin"]2zzcCCS|Ë.yέ[C9'>q_ܳ'hZy_I(a] hUZ<_k.wn)r}'n}>~H+2j"KLU+O==q.=[|^)truyxϩ4|:̙7wl魯W_|SksG>߽xrvD\'U2HA+N& c=96<7˜;ƕWGEaeBf2Pa8~aNƹp?h~>z7_}pݕ\k[:ؑB{g~_nLC?eAρ.^Zת7{Έ˝Qu'rT ;*(b01ǭTy˯?{?~[Pr1u;%ο ^ycG^|_+tj8u!мpꉅ=4Rj݇M($:I #W˯VyFsG]F#/~_z/tf. G$q==wO $Pbn,fA􀖦e8e3i7i+Mu1J3Z-Zf^RP1A se:9JHġu$94h4Nӑ4ۻo"H.K8J914%؎H`]- O;zd']{ֹXF5]l"f۵4BrZԨA[ͨM癪fkrmquy*WG=XRj%H'jL|4x'('ROO_xގБ&2 ƚ~Oi>*#it8'ڭ|>EʒJ̓PPA<*Uq91Nc:TWx"%\"qƜzH,'8*8 T]M['ç >=Ne*fΠMiFf梇zWrX>DUh` +^p:SB%"ǟ:8?вI:l R@e iuuɄ zwuŹSHKFcUU:q4c%(3O*TqPxly\@2#c" Xg1QH Ry^ZqxC2.8kH̡̑;҆O_h]ϏHNR݂qIEf-2fH{C.1V$ L)2%iJ dH/\K<9>2ܨ$HLܷLf= 1|Dyk]J?/}s~a\vSoDa/ CK qwKAĺsrDk+O$.w>s˝+/:2m7JB`d'`x)'ZP  ]ӹOm?KW˼֮O5({}8L`uT~$Aɑ =b=w=|@1ٗLDJgʡEB$sfj:r}ī.cU⇚.DD2(&BHj Ăe\% 鏔ID y %({)^_1Uш, r|fk* }+YI9μퟻy1^qSVH>TfP:y@:%U:Y&T&0m1Xu֯cٍ}J@f 1e .*' km ʌ1;)p'qhJ%ǠFQ^hv Ld{;SeDA7nlFUS"X:E![j29A|R*#&6OC,yf!!Y:2Hm[)a@+2TR~|cEu@4;][^=PIQh&OL?T9iUqogp"Mg5mĢʤdq.dJg٧J dp `(J|f O=wKk90=mދRprORƩLR$PYI.q̢6Ҍluxj^ѺIvTLTbřlUb"& `iW SwДo$lpejL'}]tj\~CXFc4 R'\D2):YH !x`/Sez׹dfxw#%idB*J:%g ;֘0#!\ҬuzHDہ8DJ49Ѱ6w}wa0Dq8?h=Pv sC*<*'o(g#(9($w˹ǕL OL-0hn5-sBqE/մ}vWJE:*$ 4L[<4R(g3 zo^ \洃iR,VT 534Y.}{9e Î="K^q!0˘0fq>im|_=mYܳ*J"$kEFA[u;nڪR7 7BcD!XW0 +jD,#ێ֪#ˊKqyi) Gs ':*r};R-zĎ Z- +$i0% Y*&g9R:dsg1XK {i$IgfE\RP-Cq0 GM<ДMxwt+"|ntQ X m H6'P@]O)h ?#i Nq| b m"rxM{uikQQ(Ζ܂"]_ Y%vmTN7Xiu:w߿%y"nǣ/Յt|Լ;^"t\[SgwkṼxLXi"JUA-V]p9Ei溕Xn|S1Wv/gu> />y,INx얃3G?r {LG]% 8sknB4+<'?碭&ͥN[/t,˱-8+*ܩ.㾃¸/S) RL%b/Af]絁iiM CJ"v$ ?sh {Adҟ++M`"[\uxA4߱ .pzx6'G 9y"#n >5SO-ñ SUp N(P LOQAP8P+bbdp&( 0"Fztg4,qI8V;VI<9VcO6M]M=VSK'U汼:1w5nH8k߸+QNm!yZiLA(eΌV|C@J. ; >hXvc)ZO ,: sȈa08.I:L(+3W,/Z1#RRiQ #$U.RMhN<I? cdUF]f s/ա:{;jT- +`EvH rHKDͳ\>jq&1!3 @V/k-Ytԩ;X )o!3*O`BΚ>*IiʜfPe;Oe6wZ8t߿{t':C֔4d/Ap ;AHJ_u"X29nQxR"*'y-""w$WN=M`. )D 8M"LpX.zG*@<Z\v9L N@(IsATM,ѻҵ)>g82]])`4BD▿m^gӆ()s<}6&crJZx︓9y:%97?pETF+ϸWQ>2A2bmByhH cJ  Gٮ'<|ߧ UNKÖ́zpb\xb$ږ2]-T[aю(Rܥ;3] Q]rθM]`ӕpȍ =R P5 $XRPCkaw5jtQ9w2<+pxs4{^= eb["R" xFm lǡ:. A0aEg@d)Z5`l"ֺnIJ? 5Lka@XsڌX;J L0LC`Xt>m^Э%nsFo/ao}Rqwf]/2dC9gʁ` F2\aZ20KSd; 'IONM  JM "Բii 3А ` ,K3D?w#C`-mM dDZ4in4q!R悽>n5|iKl-!8GpAHE9 a0PzH7`XЎ|y$punɪ:h M&"RH}:)slAB3iIJ\8/{hu+tӝqn^M~6튒mRfLE[KRƅiq.8rY馭M-VgzUdp)Qn7ȐʑK…@" 9Q!!I#˄Phh hb2X}Qo͆@K*2;~E#_5_IF<<]S ZC̫q~PZ#_MHHJu:jfCg25įegЙᮜ6h+q֘Q7܁ lAdc)gmʹ PL{ i(Z'7MMfY{CJ)X-cX֎ЎD R[7yAb؞ ^tEJ%goh%#h@5gÿ If˖ ʂf˴PLSW>\axc `XklYxa#&`fƔd 8`\+_M 2Lɺ!GA 1걵Ya2n %{d줚M e7[nIJh|,e7r?)@}iO,sF N*qc1Y}T2o|dw-uNW*3 #) Z <-Rq@/]+%Ĭ&ʵh?e (5<fgFIm kӵ.62Tr\K׈JћGѵ#`͌AvK-XR17vv14 p ŖC+ĈWl4lg\Fv2QǶ 'X1pn-cumR=b Jl^9VZڸ_+(Fn&O)QS+1<*[4Xe%ؑ"ӜS[NY,w]YF6Q4G @(ZTg/ø\.5?f[]ƥH`zB4 ͙Yy o"ha <Te`eHnD6|(~ \ 9W tR`kzUdZAw|EKnA3fOCמ^:$qlO8,F-mƥ|-S|1`Ct i]u+ovrbr1hA6 =~+Ķ8Q+0MRߍqrg~d՞=F/fAn3bnvVm,^ڟ8Ms2' 9X\sHtzL^E20MGwN9,ُƤ_bgH1Pom\]$D:.U*mlL\Ӛ>8GNڗ%ct5Qܿeͻ^%&Gn`LkG5]bGt6 cA^=2lj%nsiG0,h6M;vc|uASmoN_GzS-acV]zxsU Q.׋j{^^sk8#{@(7@ӡu@/52h)8 h`U4v}02ݮV،b$5?M#icrU@W+ox sXU&[TF ;|$@0`ڈhȔJH4=Q!6,LKFfdz1>V& \@̓m+͠kJ`lfH>t:3&4E4{k[T?[U%5h_k:@ 4X ф=ŏHMv~axQ7 p W\/Qü?iy(c]"E_iPDu(b0HV427s}~R ǡk.!d }L%) nd@YjX +҈jXnk?\ LnA"wʾhzk1Fki !qWx`*[XݾDT("==[2gZF7i jH~fT,JRgq:4V/.Å*ič u Hp =230ntULw׫x0UׁI$y'<l"oR󴆎c\9s MbIbۚJ; y8j|?Ɩk#*.⦡W6u-HM.LMmA$mZZSB*1l SX82[z:" 4תIS|6ttt\ǾE,hV)ڏV3|NCA$%-xYYcZN#`c_ZH8Ԑ\F-B^R`XB:qIBZrZ(㛁^BInp?\#O+?.o&CmnMDMn[cGSw-z@LgRUn9MaSkOFߥy-Vam-Z'_!p: xH=]/uEhnne: ´PۋA/̎Bىv!u++1.|CE:L=Jr| %B6-;鲞wUӜKTH)0ki5EAAC ~a{iS{B3 T(iUڔ)w'316V÷ݱA1Kve_hLpbTj5t״\W X<&бf@QI42_LV1t)\ ohKL"xbU`Ndu_Bּ"3`y0cdʤvQ'ml7c 9JNL3`r|1&wKfYc[>CyZ̛V7c]L@e|9LUhO\l[V&¸J §SKP5%Nz8r%FZ퀜QmۂX$7)t#['~@<4.a0NJ-e b1L ڶdu-i3-E&ߦg2yFZdM O$AɮF;Wp+=`Yjoߵ &tsX]fRBWM< ts[B1gm+-/?iq; >뱿m(x쐢)HSE)1luejD{645lKH$>8VχU+{2crJ?`:Q_}eVXtR䜐3g J2YBjX-%eڂvLkt# =_ڰ2 p\Ee.}K~(t,iYlvj sO~V89;ϭAk ^KQ,4vlP~E}B+tϳK`>OVP[4ζ`숯L2iFa poXơjb paA-|]y:9kuaVynv1~IRoBmo!¢Y%(P)'atF 'gk(e }W}zL6dS2i|*:M&׈%mJoDy@*8  ĵ&O r͠16֧}"7*`xuI(<5WQaO=]G UBZӳP;lo(˧ /h{AҬ*2Zaa|AN1(mޱ E!ZD`g@M{]vS 6b]J[:{_)S_[+[4*k%QV'[]^Z}kF\p^ST€uʡ ̵.\1-(cChtwb4 iF"Ayր`Nw0KS$ ЀY_Xt {_VW k+װW0X.:i@G5d'1y$k)qڜmBF0KvR_;zگήoV,cWً#N=׬+elXZn^qL#F8_6-nֈƬ*P@1~OȲXX)NcRivx`xƚkwue>`b`HsڵJy6k ~s>šǦ5i%xYFe|CF}3vmzN*e7IîT ,Ƅƺv! -YLEј+&ܨyk7N\,5rkנ?(GV)p>JN]f_xeT}FrMoܪF6Đ,r'=j=i2 CjZf*(EG *Z4ë*cMo *I.Sdph+mJwQ 크Mq kkC<9Q =@/E2Q%sml5-}q#QP(X}9]F"\eXD'Ø5kqJ :^ZDj"\U_$ׁl viߺXZJ2˘)t !$:\k^<}CG\%l Z]ckkªg0cXK^;]J@4\YaHӬݝxOZj`q`ݡTi^ X(2(>,9+[XMX,[-[dQa„FDs}a?]BAA:p# zr}5f{e}{e& IT7n >F M9,ρ#{w_<[1|[5_=z9!!n4-l NgC^^jt:cff%myccc5kրw{h,[FnOl㝓3&ZuuuGpxo?|mJc sNNӻGKv|I@8xFA:hFA.M4nVFjZS;gkW|e_-X,@jhxZ >,K$nX{0'3`4)$\uýFgf`0}!, /NZP 凗-[3rپ};.@ffS=@ ;z(XA䬃Ah|mMeű6jfqpoD77ZWYzZE*K~)->Q(/˔7c {6t_KVgnmGkh:^oD =Z{lBK.z5|nۺxjwgs}s8YYYIY&\K_Gj>KX,_~K{Gݳ~6`0D{l'xj^UUUm]cccm'خNKKsgc֬YC=h~~~g  m@ \3E4(#PJwػem<9'nq1񩽆^}5K|zpE{vۭЉcbS UP /{skn_d(poE8]裏^߿qA2e˖-:[I%ZV՚{&tIMMM6`4A;eʔ,X?eʔN'$CA4 rqmHiEBiX2BdIT~ܺz_EI{0jdFB/ޖ3t+>~g} Sz'vKejj%3(L JNNNʍ7ǎ矯>}Ȳ,+5 h92}۶m-16^tM\՝:iP*..u3=K`p>2dSO=uO<13cAAH4 rqf`jU&(Kthmjv>|G{6Ӯ{}K^75)gbE5hts#4VoաE>} NeiŊ rUUUjfgffG.KOOt nǂtF뵝.-kxOӯX, AAN  AriΌ"^r@}ߗ5P{]%eι?|vw뙕 ڊ Er}M={Yp9_LjժC mJJv=+b$%~Wv(=uuui={3t+֮zWtQԐkUE?]?; x?-Yd̙3i4 Æ r!F[Xf͚ C<%%%:^u?'EA~FA. yGO2Rb0[5c' r4:\{dE>$/ Fq9lߞE{3{x{=3GtCCJmho$ju\-[t1O<ğ9rv{"۷o_ҫW,rٶm[|OϸiӇw٧xB%ob1=䓿֭[V{u zwƻ_;u^~_UUUEfmqq'|QF]zgSSSC{x^wSSS HGnx 6# \4.* hEyIumM'~ AG ]/[]8cav7n~MYqA G=)t6>Oyyi ,޶kԫgθ'%QmްqgN5;o~aKt1wڋ{.+++|'~_E!V*sI5gHܕ5qWLLLAA(Ac'dv4-IP3yKsMOfD-oXꊒۏnrxlIzf z]n[%f"ɅJJK-زqժSshё鳯hoex67;6lW3Yf |ꩧ^mdUSSSͳ>|:rny^o`u{Sk|A(AΠtp}Xl[6?w0z9GMo>[s}ɴAC[ό )/'FOOᎦڲ#7Fkot[ZW?}o{NBvINFVVV?J{qϐ4_7\ 9h4G[v"_D+$$$F8.u: ۶m8ql6qQqdYn AhX͗22?p%ӣt\~yQxu*"dgIR,)L/!5t~?-ի?/n999!Cy. KrժU'XrWX֔)Si݇/~q￿%,===f%D3{c U)ۧef /:t@5]XobZZZmF=+++%zVVhp)))9m r*FA.ZvN0q)L8Q ʙ0F!}74= +޽{wK,y E,& |>k|?F?7eee&o߾h.\6N`5_nݢNg{AAA g'&?x@ްn3/vZNg]oTy?Y۳Ou]R}}8~=;w֬Y9ݙ}oٲeINNNԌ   H+fN^G^>MYW.b/gyvmvܹbO6Z9HHú­͋=L[k@Oxnݺ?755Uw/瞛͕AANHL  ȹCf^`3~#ݷz/j'O;gΜ}ףG,XVRRRXTTtm۶# dž馛f 2dt=$`J=V>t:ݧٳO6mBlllu\rUN(   q/[[to=.AAA`ʊ=tV?2 0 7 \ <8%6665}{ӦMD˾  ș#tA \./|Q՚`R:>,Մ                                           ӄ   ŀ zi$I"FANe69zSax ?a4!ʽs{BZU Ϣ(wD@  @?٨'Pq(%n)c /<G)D&+ e9#3j5<~'0E?Y`;aIK5jV zv}+Vزm۶cb,4{ǏgXq444~WZuT={vw5a(/x駟^|.ǍX,~% DQ;}76S '''e#̛7o޽{J$PE..._{ƒ矿v;GuuuK/ F9Zv̟?s= 7wqֳ1Y겴K'-iɒ%oE.~gd} ,k͋g̘ABs4NN8@)O)#ĘW )Hم )--G\llq: ohllljo @@"=8cnYzJψIe~666~%``TDYF/XroAО-ٳɓ'/kt:ޮ]w5_d6?+ӧOk͚5E4#,gEq1/4(#35s6V4677:+*ʚof' ='$Xl6KrRjj>֮]usS㎝{vwb1G9saq4lom?U"77EO\([ow7}s}Ɂ3 kr,f}nͣoGz+2."wt[ѧ_ѧ_D~l_痽^Y6sys(J8?@ YNlioqFBágFnnnW_}#FLsAv'_{OEba} MY2h4f& +qp>DtW{YYYq\sz|:ۃ01c&OqckdgDh$F0qэt8EnfK6|ͷ~ϋ=s%$kVZ 7'%ƛ\}y>~9gGg@aoY;rș' oyW\q_gsݞ4o޼t=# H Gy mP^Xj`{<rqɲ,+? ~Ȝ pfAc$F f CϜ"~2G 1t8 Y4ۄr=}ݺuˎ}Ҹꊊ%$$4i3˃>x.NΝ;~'Pm@(]~w8UۊٳiϞ=Bٳyv;=,QV-m+~=ea6M e-^y5N̽iWܧ7‰N@E94qz92qϞ=+N#B_~nO/O>M֦o߾v[` 4 D(SpTVHid9'"( %IeIFɠjF#0PS[W_8wXk%m[&Yz٠70A_Дe5w \4vtaK.}/tàAzn MYx&c͝.˲z?b-[޸qfn>a„yyy%5&%~wX{+]^Yڊ+V*~5M)S\l/0KD@ -[lrݎh\srrD[WWWWt:O` sNNӻ*2Q ItwWyL,V{z7}s, QS*ݫwf+o=#$o?V^3@.ҚRmѣGᇛBs͚5?\hO>Nt Ҋ, # ^jczPD)'A.\B•58 {XZ\-Fj1c,fhԛ4A-p= o1`4E=V oӚG dI,b!z׮][H'DuU0~]RRR,AA8R<%'аA{u;5)"@5C1~X&Nk1vc5bi"yQ@pV*98J@,f3XñAڠxL'jMxjޥ(n1 h*Z/+(((s8ux6x{Ö}v]-I-+$>H\7h郆djxA40eFN,~fɗ.8vYz򗿼kΝ`1>ez>w؜m{1Pjx=2V yC'zp߭BY5%kCܳRyFld z#fϘ$+LB@Fo.1Y Rjh=!X!zP=h+ ~+ZAG)^kO>Q%a'Y&JTEf(r2SxRV#" smH-(--mQXXXf% U;케}ʬYfV1f8x2sKŀW>Ŗ3pʆ{y;ojMQEe%Gw~oھh 7 U/^>Keee1c L'u`釒TP.Mlv ->S2ys̙+JKK.^xŶmJ/qw Y}dԿ=3|nHHL++hh2LzUҳFD{++^ڸvN8:oaN_N DNBF{XLG|]Oqƌs 3qs=z4 o7F<ںNqZZZ>5u{,f͚zGkø }^yw_nhWߛ̖1^gu.FrrJZRAF]26Ah+.!n_t!#b8=+mmIUηmVVQQq8==}@;77W^^ľZI$(8t  ڶ [ Z9:$#JawaS듎æP`z.r{f?wC s23{HYg57BasF#4%XzLꑚ3>ƞd4#]}Ru7o޼Yk׮ܹsVvʕϖƀlg7IMMMh4?5;;{xc SLmZ,ùwWsrkV|7y-~jv9K *K KSR{vy]h&5[6|W5ǩ3PfsΎʤ_~ ˻uq onnnM7t^o_SSS?%Ēn~~^vG?;!v!a+Xxrvh\n^q۵^c/@!7 fq`/lhxf"\3_3Ns)eU>\lq3gx!n?o&Md oJL11xK E:VQ5*ڔi.``R]S_/GچeE.b=6F;JǑ?/t:&l?Pь)wƗ޳"?OB5(16eNp E$Ivy&y_R|y:\2bA EQ–dj@EIId2Ĵ$Ijh0Ar"Dba 8dㆬ٤ ?7oK'kGm۶~a$h4[፠SB/CV`0:a=dȐiO=-Ob8i5͜s~q;kJ)y >1%ynb& s4Օoݰ ast8QqޭϜ9_=ku:] ,-^ͮG?'"j|'>ETkYN8><x_~-sGXB+[ Fv-TNBeHG]xyEru1-VH $Ɋq69.ˊb1Mq1q11vn5 zd;Y$F[^S۹8S|=65)>>>nYz^ ;b,g+$I;o޼Gtgv=&Z=/CΊYp vN>Vs03rCLZ\Z-w~ѻMuM 562[#.[Oȷ붮_>Y8jnV@9 3LO#?}сA4 {O>9L`dE~XiD oT]tEkWP,Ѣ$.nv8dlV٨!n%VU675{bl qq16;ԃiza+xx,]M^}տp _ݓTWWW\ReeeQs̙3sZ->߆֓Q:'CHC}s[\v>ܑYGMP{ݎ-z?o+U+Z1\3lVEzh?`&5k3f5{Ňn͛w+"6u>ɋwuS\v?rhvflt+U6߽ioEኁ&8ll-$};7ɎMKVVW,¬&c*jFU~&X,;_W5{o;=҅W t 6xLtd{^/>m:)J'-#\N}͟o~up̧i^/gP%gMEvF/gShoj6)q6IEU+1ehllr5;]\Sq<^%ƙLx?Pt-k֬Y-Q|͚5-C))))7m! YZZZwrSpBא"gFߡFO*>GVd25VeI ߹mp#B .] QZ>׵^{gcbb~7}ٻj,笌UTV 10 ~>O;unx_ 3תwkSSs oN($k tGo$_wl^GLU gI 9.gm]c,ɼޠ#^>5BhJYvU16 i$NgbCq\ke1t){w%'''#+aܸqGdu=|ٲe 8k׮ i@or9 T>@Xl6.tAZ;1  ѿ۔n+!Gvk,|m}SgsSNgЊ,Y u t9ds~A#>u&Muvu8M6} /W^?lͷ~+W\Ι>ol|~OvB^U$7$`dpҁE;V!q!Ҷru_uĨ:|qs~@h, s@*4;\Ίc.Gi&F#|9 !1|mf?T/pq8[]]m(ze؏Ku3]6s={/ ![!os=7u󔔔뮻UVLǃ1I~>4'84n",v#RLu}b)#!O6,/߅\hv?rh`Lq\򪚆fQ%cxӄ> %J)X0,)*kr{|Ac1 !4XWj >/))9meLLLrfff=Y^ :jjjjFsr+֓4dF;dĤ=v;jjz%vSRjn ) VN 1qɖko{e'it> 5\3{ms~ow8u[|?jԨi]1.@ˌ8e=.vx^:~d߅A4/Dj}н183V7Uj P^q4:h *8-onj؃Q$S<^Y (YTBXYi !ꭉZCDH(Uo_Ztq~|io ?P'6D|n]qPi`,KrS]VY]bIP15^V'W@8C7 Ts{Ʀ*bIy0y &ij~;PFFƐ5##`NopOAs )ܵvެ*?V=3dMhu&Fg?Q 1sϺGz!/+8\$=ubr  `4O(~ر\Nps[OJJJZ0G FV5.---<A(%0 ]6%+㟙%SZnX1V٨[ɎA'l Š58,87MIvʲ/kZj45,~@1U8Υ8\Uqj2t^Of2|mW@WSM/qGeOaow߬JII==e0V}}J_:֠h!hff$'bRa` >UEFDBBBR\tv\gr1;zYgA9]t o T.)XQrF 6@Q"r4VVXuvH,5(˞$DE "Z_Oՠ7A︖,B~?Yo>BWa]yvLh J8<^_S 5Ɍ$J5DF# }$aT(Nt55< rfp9]M~Q$F@@:;6l;κ_3Sqqq X%}JHHHmb*/ٰm۶fy uQPO{.qeŤNWuVt67!l#Fb˳`#!%_|ο z=^IQ=*! RCsvAA#JYfRP(>zIQ*DEi-I dkhLͮ@w8xHt|,I:(EYn%1 x^zd`>LrVHnp(@ @DYLFpnOuK5M^f֜PN dV@|||! .t:=#GKhܹs>111QD\ZZz\+ٹ#;+F^R(QZ=MC:r(8>g՞o4lklm}ྼ6lnjIHcRKQ\\|PFk\6"8cAnA$d(&x{%=lE H+Z.,7c"ɊWfQk_04b2.\!1̇NW-YxިyFj8z%ٷkjj2 ־}", /X,4mCɱ 2 PhUVX[w}*66mZZZfnnnf^^^(:t@5Pko~&l4YYY-,YYYYKJJF.;JMҧuKc2bO;hr75պ(*dƚ8#h4zHҽ`hSeEQ֟$n z1''g!j0LvW@.2V r1!+L DY H P@zha;܍AӵBj8-{vED| y}F@rA~`G9Uk֌>]xk.  d2t:H&F"SWW  &J ^wyݻgGk\W\\ۼpM .ܸp[nvuQC <\g9x`u^fΜyCNNNz=7|72Z?5j$ĩhA;fEN LpևډdO,\HWK i"\?7;f3X:FeFJ:uSdESd= r h4yՆgp_{1 믿رczd4iҜbK _MvnݺeΆ ׯoS*//o%";=T=28oԩG558*++/]tMחԔt֭l6y?;Ȉj,..޻hѢj]_w'$f5Gsͭcz:ƲB$QRdF{Lb5V(XZR扲l2[x^Z{rמ߰h9lٲemmmdjZ3O? z111Q߿q۶mQ4: hAip˜$P \;>,3 Ó j HfG8 7FCVxJ9b*6\@)ʊxh9A5ZI׫hQl DۭZثWAE£>nw_Qu-”~[/ז̝;wÈ#f^gX^{;,Ғ%K啴^|O8)Zls޽ odomȣ{"&&6=2)ڏ;-z{e{޺".GNoonݴ"®(/kWK_[.7d%≿1h2C߃&w줍S=rM@n޼={u^s=nOr5,]YI  ?X-&i 5Vq:xS3Fd1ٯ(~ʊtq#94 XmC[d.\`0h l2&h4deomt=h0YkZvdX$AX UՍ&=};_ڂz*$%Kޜ3g/Z9rdO?tizz:Ĝ[oh͚5[oY4kؽ{믿rrr>O tʕ+;wܟ;N0lHu͖Hɇ ~oyTI&w:}>KRPTX{gKbՕ͍ ^(QehsMg:r׮o?~eQW7o_Ml ?ŋ/̌}1 ~YA$C\MjHxװC;h'A.>Bn'@;r՗.:TxБʪ:eж|6Jv[oG+Z<O=Ի|?$I0oCk`˗/[nMbbb#577׮_~]{}.[ljjjuf By'xcǎ;~}o۶mC=%|\oy.qXP%x~QZZee9(BL$:TP]x0qXzuuUUUM]|8rg<Ƅ'$;d.  &= Va.w$BALnܡ$7j,"} @W #GyUWMׯ^z@$IC)**:x۶m;u~?Uh$tM 2G{4d,?|UV}lt:O/fكM6!6662+---^rUVNg{ܝeڔIqG t9?<~ӎSnPfrp_P}kƍth2?5o]{]pI1-iܹǏ?Vk'G/)))믿_j YAA9˄!4XV騏Hs(fƍ_|͹{\r,  ,ق zrCjU%'YYYiˊ|7mo#O  rZ^G*r4龽iӦo:Ją ?UP@#  H'h\._~"Cq!                                                                  dMzJ;Sܾ=LIB)(aQgO`cJYz$r4-2Jv^e𿺎M՝þgE#YaQd@wB'AA~ FAV# 8U[%CQ((2c\ j8#R 8YxlnҠVińucx<G 55tln YP+!v.T$B$ط09,Aw b΁x'}le l/"ˌ゘@A  ]vYҥKk>gMoڲ} SACF:Z %ZBBOqX@f$3*/) , +L9t,YfA8NTNC9 OsTЎWQ&L HL (J QlP-ZUex(jyΨSNM Z [ PF  Z] 0Ș_QQ|`5 Gy->$(WD)ȘXtyƹFA r뮻WϽ*-5ys\_y鵵Uz~窵Lɨ Fg, #'^:"O23ެ))(8vdᗕ&DfY̴]drVzGk9sy%%$a#WU޸ aWdHU L8^C9Am|>9FPJ!rE:׆=O $6v˿]t0XƔ[8 P(hxhYsVRKzvvKq=~5w‰"Bk4 4 ½W}dL7{lRby gsW_15<#F_+_N·n{Wi1 35=nOnt3zLxn HP)coU+׸DL%F.5:yb o4~Иd{)WV4}oߙW dF@Ъ` %:='XG^ze/d䙎YEvd)Dy >wkzaZaHD_,*\՗+E \葈'l#   ~REnnn*ۼ??)#5}{ >T~s89uBl2 Zf%ཀྵ*.~?dt=b3= S- 癙3g_q7 6ZٜˬV[Z3u,fc;;tgSjgpKP((1€Aû͘yc'#%%uvmZygRI퓧͘s?>F5벱_owE,PtVLtl81٤ۧޟ_:{h3_c?3mօ/_Dk3*)jA@ ђ8FQB1}^~Y&xd4~w#35ѸƎ  ? P@#g&_:yt߾}'AD?rͭw:+>k6J;~ժiaI'+ƛ7hȈFh))i1c#3͐5L0p~0p<#G٣=ǻ:*/IL4 \Yfmvw8;xi~YyAa_|˜$2.$ jtǃdq@j3mM9RQ3wV̽֡sZmc$WW[S~ol^tGK8ezm&NA&L6g-䓏T/:YHi9ȶ <;qճVLskf5 #.շdE(<#?xovM6`yJN9%) _cGAUV5C 䄦t̸i.tACF]\}^oӱcGotpzd 92pt(^PTEıw6ln3g v缱 =zX$XCǏlѧ_{)m) dSL(W{q猗^ynYِ<*(*plO1xFX J9yred>XMJ]cZ l6G玻bbYME ]pq!:("ճJju8eƜ^_vŧKYiݖӊ}( / 3fP|ZZb{-].1⭚?w}ye?%.UWY3 }ROsug-޳zuˆd|k}ǎm죦LsMEn0 ]ȼ;o1㡤… _a6 ;~'_~_qI)s}|jQ}_oqCK!yyW5ZMx2ī.MR_UUCz`u!X~gyw~sg A@ rV+>.gvSA4G ~S^3lz볏^&Kv A N<;3FdLkj+^|.|;+1ʅ=ҌKey˖*J̘_C9vl:4kmeA2Yپkq%(B/RRv~[ڻfn(B܄rk5n Z-,p3^8&< jau;xܲªUH$dGD5ޖ1P"2Jdp  %-%5s­[w^6( lݲm NMmIzWxf&soKMM\MEw:\#Ψ%Ml( !A'P|vtb/Hbי fsAd4%+PWQ^)3Pu*LqT9ZuڵƦ qO owTZ(^1(LK!̯U(&`*7iyJM={땊vl/R+3Ҡ(Jhm7vbZJ h̞9sаaæI}}}Ɏu G9-ԔN0Z8> :+89< zm kkkm?n}:cEA. P@#\`|h]+477ʲtp3M=ze;a월b_8ULkx`kdK6rCF_gAМ }^OѢ}ѫVXUy Uc>O; XJe^A>˜STf$AqM6[B(^u޿aa2郑 DQ/ӂpqZvLˎALt@^1}ƂvYg_y#  r~CbY\\|Am6{Ȥ_X,>>OzשּׁՎjCٝ4=tONaґ.۲$*ʎ޺qW_~2'Y0~h6鍼**0{ Ɲ4i+Uζ(JAA3 v$< OsL 8Ō($뫫Ʉ$ )Z!KRsK>xs8gFHQ-3"jnHMY}Ljz#.ԯ_ڞ;}A hA ӎ_y{x7h9v{lK+GSC+mZh pV4>y'&K' j+ /u(~􀚌 J(`7= ʈ59p"ͱXm[ٷ}uYiv˲CuFHKLyWjZZW^9aρYDA'(A.@e}^\z.͹Lf^__sx΍߬[7UWB᠙||sw߭dj4L軲xϪgMu>#bLQ8مL p6O~oQ)[e$?c~)"c `0e?# DHs}2Ot`{e@,ۿ I*Af)2!˳*C՗ML ԕժnQ /h8d8bG,$UD+8%~ oj(fTЀ@xҽ!\s͐izu?^SywEMyš%œ27i{jvw03 n՟cǎd2كդq8ǎl?|9/ˊ[R1/S$x λ"IL(JaQ-`)eޯ(| eS@Y,P  \{v,l`0nj;5N<"   jBmH wmXih}C/-߱fAR 2l <ڰw'a4Y,9\*[nƆZ'49S3>C~)8qjx2;FH)jbP@)g-Z^z-Gc&\}}ڍ x<{mĩŢbdnIfȃ`TU uEw.JVm٬햕kʕ)<%nR[~5z}̀+U3)aޮe$ߛ 2%Rg:c^sE6~̟R`*֔Y:zO@BJ$ X =h YO[CN>|x֮-L?0PCY6.u2c>&s QYQk8C2RfJ0Qྨ!@SMm0̈_fL LIdJ@ ?\2?rP]yiiQ>}ۯtF8A rZæ0P.,ygU_h"X72UiP1&ZV_}io~Tr45ܺGc "g Juj0U"uЪPtP|~'hg+rtR{5VW5nV1 `gմJ ,AL-JVT[qɽ{U_1hՇUL9l}9>z8s]ɱ˖n- !UyR IɆ͞b!ƘtR>[&^^x t eX}Z^;$#kwJ9jղoJN7zv{r UO 2q2IuIV3uyH4<P,t(Jq=4:]Ծ}|{r^k0D/KWqj@A1ixbǜ0optCyK}A f/*v($,ⶸxk(yе98+sZ lR :vXKN9Ʃ;6T #x5G\!Gӓgٝ4u^GY-RPC+]-?e͔X|CRdăb;=\G%)DQdEP]^ZZDbd6ۇ >?Ol"  8F!yĈՕ%MP3DV8Z[A Bl3cdgS[YUIk)AC1kCnN| Ւz2HuZ kalA- muXٳo)%PLs: [o0gi br &DN?uT%K~#''> x'W(3'TkZ 3v|*[b91~oGo>!B!!x˒cǎ@ ,! yFffK7 rAC5%ۢX-F`[jp4x$f >22x"(hg%X9:V60=ưC!e9̆Z͵x.i{ HZbG;EdBd%U @5u5T& J UEȼlHy%8 w5=$p+*|>`woHa1p`lb CZHJQ^S*شƝ9jtjJV58`Yxh"u8`Yj @ښ@Y~~jJeUx0q{jkKL9tݵ)?^{[ByХsu"JR`PtJZ8LW NILLv(lV$flP.T5d)XMw6V-~ҥ9GA.P@#\@ G<M^հqTKVky^WoNhvZԌR;C=jjԿGc Kp݆:ƌ2eo-82xWDH d}VzA9*E:/~|LjrHdt嬗^״^CZ xChkP/:yM8b)ѫfnRcU|u@aE#{Df2w:!̧n> gJZn1p6VUTԵMɐi6Zf i4 4pYc6UUA)jwSSAg4i=TSF-U^,)e4]u[MI9psX9w\^QU05&5-5 \ 7  q xF6{zRSCU¹CّV` :R q~W[[Q/Ɋ| 68ve_M9zBV2-d15tm֞swhжmGAffA琨ЏK#OA1on 0l?0r6.94˔(a1AHG~ܽWdJ0OଫkT$IV Yb(!:J U/NRq&1&l}0)2Zi4o ABcP)Gz&GFԙٶ)EZH$P**hzm'jGF9A zfЈɹzϖ[F̠r*NC>Am %0Z~ [T1ʈASCzVv3`F;+|cwww z-qqm6viMrȄyBdH_5lڸ'gZN X9Մ\IR :m۶"FE sוHU@C5j=wz%s#(9d[I -E_%"p1A8ī\*I9u*Ib$8rZDQڽzu޽GjjZ@lvӀq ؾa}e, f£ֱe|\Q+-,<F$w8Nf*8S* \FPIA(VCp#L1MuÒm"352)TaDeʁ+*z&pʹ^#ȒOL㻯IbSj1RLjj X Dd &&JA񱓮j֤oQgp^ǫ\'+M`1?E|dc<68oxaWvo޼oּV(^c˪K\B)՗)*}>8Ag2im 0&EwˋYR*+Jw_BRlltzeA&(A.(B1ܶMa܄C.4aS[R0TYX?u`\Д1YVx#{ 0jOHbA׹\y+7-*(`ulZfXjAK/utzwؕxzn 5h//痕ZIanF4ş(߃A_m;B B'5(01o=*'/PQ՗d25ojWɎٳMpN;nkFʈ{(Ga#1YPchj~s1(QxqBUQ;hT({29k7fCdZ y2Ȯ9?-KjEyy=-i Z]gƍ:ej56|?x@8$gJ@ eF2SzgZ6IG-.Im;ݑ 18v`o,LGc;`}zd%&&j5z 3iO%i05T_#0HWPG )rȈO  $$ÃP̡Tuܡh5L\RMBjjdn XQY/R*xeydH -5v^7 .Сp1xrUzuS'@Ku$O&{ Q_Jf)uC cyJK"_ n#uʾSLQ2%0GkX: ^u)$/3EԌLv[8N|Ey5\un\f#~ ȅZA.02ʡSgι{>#=TUWVry[k*KdIQ tZ) h,>#?1w؄͂1cKf 棯=\TK%<̏밐o'wq zuLg:*Yq8__oYrWfyMU`oT5h8qHR䗚LMORCHm:qſ4:SSRcuq0FXRB%!]3{Bb 1Chj%b >FZU A't*,h>rY_*ز Ir[E}^Z!m ?\>L2a >Aг Ĥ,Ę'$Z Jp1 ,+%/р`Tmj**W7ojա F}CVt{6ƙ$Xz0rDMsqBM-e Pex! +Π72k"b6 G 2F3B Sx"cSB<`9!.7kՉ FX~N;ՕY,xu{Ya#neK7zhy D48 &NBuYC ^HK1Pjߵ+_Qj4Zc |IT;f7< jP3`]z@=r&շp7;\ൠ0ÅhJjjVmy<]vDA(A.&L}-wijAohSb6ٱg~Qcq`'ݲzE+Jꕕ5xϞ&JfԴc,mNOّ1 gl1Iݳ2Zs5|(fʞ?'K׷&{zό0}{ EA (A.z𞡳fϹ_A3 cl0q͍E׭˯vBZi{9X7X#)d vXQtIu+x#L.6>w0xbgYYp0Z UɎ!l2ZZosc9ob[ypӇO5hG\a -oWdO$699 5~k}%QTʎ>A64Y,n{dDݷg۷ɹDA(A3OLn1b5M&dP~^0RAภ o,夆ĪˡU"+{~+%Y5:㯲&ju- NseWHccCm}}æҒcGNnyVagY&u42?:WQjr ̯~0 j2ʒZB( 1gAeP(q) $LTC6fK~/ϳu˖ rqA<2n72o-6NYGo^V~vI (e!+ZI)[I9'*RT]U;'!)wnD'f;ښښoWx ђ?,>`0ޝ,8`zWlMr^S|Cvך5{˷wכLBZVvЊp"m˗oرu${%I%7Q5efcXZ2pTW[:nj \F9lܴa6OHH;V"hMEٹ HdJjn">  EjˤOy6wӺn]e{֭^m :y8 Cߖv4 6{wF͊>+)&6qYV| a$ꙙm0ђ`oeE\!LAW6l12=+yZv>64:zڒyp=EqH!s"1SA3kLr7}]qٳa-%z ȅE? kE[6}hn.Ɔ{v/>9DYV$X)zVbߒ($GEYv:]V|>(9Jw|6?u8%{B~g RtT8힑'ph\dQa~+8$"~/cί}gQYAA1 :uFS~y+*D0"eŵE*Ni?gʵ, KM"E3*aѫ|Pz :xv75>2% $RX B %tAlHSOvy= =ODAEZHtғ63ϻD(3$k7M njl;mWfzf[<5sq+ﰚ6 ߺ *]Se K~/1`ڇU@`0hwر ͷn_@>r9 {o}ϵLB\`0<}Im-}&)_̓7s-j,nMVv$){: eL3f՗[]жk1})2qhUd.]:{6E&'{yA_C *d(f j5?_:wn--ծ{9^O4p0t%?Xs׷QzjkM9,d?eC~k4Os[Sѷ}ʿDWؼc,ϙ gemٳ@R];8$$l/t[CJE*ϗz~\͏њAFͲ,6N ÇNھ֠+p\`uG޵-pVh5-^'/cQF% oʒee{s5ךvj#FArtիVmK 7h[˾>WQ^{H߽"'Wcd΁Isc%;G/rD׏EΙ<r_/KKK++2~N;ٚd0} œɍ*#@QOYHEhrdkd!]]3^֙,Hi;/ E%ji3qvn~/878ɾM)-ծ~e;wd O+L m|tW Rr?_XnwT 8t)R$P};wn煇_}Ш!kflߗ?~\Mv^pj~͈#tםlV)9"Awԙ+O=("}d1^ (6M;)(#591 śS;mg{vo%k <;bQ۬b{Dl^ιknٽcǚ VnwNolTNŕf(V hT?$4 uCߙ&3o..ܾ%`0Z[liYny=OQVvgQ+҆bK\frt#+|+vpOb|"i 8Caʕrr?#G PղΝGVp|αI;M(!PoIbS95P)*Q*E%# $cB4#e(J6$A%+v%GI*iGrq5Ad!RD>ЂG2"]\w~Z"&D2*P $V,eaRQޔ^w3eE"gbR [,%s ۋvGI6aљXbȈ`,M% #Ҭ\rE %ve}wC2;"fr6iy9ۀ\=8 #Ҵeh%,ii}z l<by+L$p"S{}C}a(u!%0LLr X /&+;gg"7H0ilM~N2OlNV*X YMr&ĝ!+IK_+wпdݵMoIs^`HOT!aSddgUʢʌM%)aMV)ed cHt%}RM OX΄.͐XOW(i7)JF_%9_jn9cxchsJ` j/poq4+8ǰHΙew(RD>lS@Q4GvZ mY60Q_uE@S.9;!r %kCٴ!vpS^E 9DgtZ:Q#fHn9{g}zP=^ӕ[i6MeUcU*x+M;DE(-|IdLY"5՚3VG4<{/ʸT6EqOǨ2r0F|ݻGn@4M;Ijz96 põg*dO{$$z]FFQ V)}v 2/qLeW~]Dl6AhDU %(T es{&;7\3&/@[!RJ!)e Myٗ ]T*dQJfp#t%J2v;[f•hiDBLabvXrJ/jN9R&A% έc[2$cffh{-A4S^~̧K\#u1Ag) >u!߄~Are3+۳%"*z ]WU,;yTUED$vp@+;h1 Ylz̟?FIn}/lq ,_hK%az'7 D2֭9޽{'?sm2mGVI;C]>Lq,%ЌPGBRWMPΦ -d+yg1DF3 {ovxղ &/%q]pQ]]nsGu7˲&g4|;cbb>ɩZiܹqqqIUUU~ڶm{l9sd eT*Uwq'|sEMӧov8SN=;hРݻwxf9O:UV,§3xxah.1sШ!CZiȑU*UvݶbŊ^}կIfll&99.e7:%%gZZEIIIe2syW^:o޼ȶ ԯcHHHȑ#zbX; W^/EQ^@nw릞=KVd޲w#CDb˺9qDIJR1+&h$XB 6͈H&[2v|Bb/Wշk`]E yf昃 ۼ .defff5{H`蹬T*UDGGFmzmmmyzzz:ip,Ç{=??`F[ 5k|KN(^޺uZhh,\h4 ###z+vF2! q!,TCbD1dIڻKqŚ҂ "vbVduf)RFp5ip/W=~C<IJk\3q~ʈknԧ9䚦.EEEO-˽f٫xNpBN 9ϯ]7p۰m=}`{ d0H_:|0rcK7ovecbbBjfMT+{׿yJJJ*IXV7,+kQ変m]򜖓Sa٬ޖ Ǻ@C M0iU-9s"y[d5U;E<>G/|vW{KdsXV*5Q1G簑l+]ZRpbo+WtdZ|lԅJg0gΜ;u0}Ҵ9IZ|%OHMϸ#/_8`ښ4#fFѝLQ ?;6zM~ b'&qLwQʩSnv^^ީF ˽e^O  h=EoViW+P'9s¼ ^K\Jl$0RѠs5S&ߵ#垼{DNH!ᑽ"qa'3-8wE%=Jt9s柚>]~8yE ObbbdVV>־~Mkbv.*00гT&\.7{د_//.kɱ8p{ i`2ά2E3 M"y\logsOY^V =#7.sDȕ⋥j i#Nڊ1+l|ET={qc׮]ksrr`0y>-22T*j~~~$KX,d᤹ ۔L0~ZM* h=4d9dI, d5j1Y~XSW_ueqnS 6zW9ojxDL'Tl<:/?>aʔ)h*{哟|ɪ'---ѐR_]wu/EQ>ȶZJIIv䅯*}'J]O>Qo"""ϤIih q䅳57yI"\8t.]e2#GoI+||H8JEt$uq쑽i7l-ȿ\NQ+ 2JtZpߚ}^zߙ3g2Yl1cƣG퓛{vРA#w~+vݶbŊw?-r㏇O~޼y{.T*}{GQrn  0]9^ YV)N3; n1[L]a#>n͸Rxae~ΉS]W0oIJ^Gt5;ڴ+: E.(ӎ^x?5U84G޷o߆ߖ-[6N4aFEHyȃؽM-IOOIIҜ۳?9y-&!©*ޡJgJӔ\#N6:^MW8٬.t"\5 K粲dn?ws_aڏD*SuO/.*ȫͻ|JIIq᝝… 'u]{ʩ|n{V^zu̙3O:q,{᳋9dؼyYe 9___6W/pppϲ4M2]#]> 1wQ"HDq&ˇG (-|Tb/))ȹ?z,yGOGg0/ʮ>{XKV[{-..>pB+&)))/xWSMIT;{_ 횘8 d99***ɲz----s86o󂂂:msYGa4]w49߭ A_Iags8fQ\Na^ND9k7[??}:_|@Y3<Ν;d;vlyD"qTTTwygeIzg2<7vh4[u&p>(gEDnoX7i}gkW~ޠ!J6~vx e< d}"3GX-r`KMꙓYǓM4q̗v]4NT=s \|'课lCٺ֞?>qƌO4ﹸ8_svvvu]2^ohZ1ϤpW.]nͱ,1dXJ%c&M۶-ixʜњQ>_lް+Wgl34C$x&|B#b͆s2lvR-p˹p`ii5 S_Hw/ eYVRWw?'OwKJVOvDV4cR2L즲ף}x@ T.JjY :t0o|yȰۻNf!#8|DxD>!{2H0"р!)S{& ik+._X-Z㡃G{`bl-nOzdT"!5111o֒=a|>l;uHLLP(TFBoCG]gkk}}}}8kk ngtS&xi0⣍+tV2,X?04(kD"S'%들 n4YUENrтqo/O>~w5 n=Db쳏?Zۚc_x}I6,^xu !AX,zN'ʊܧzf#< j@'%%EzěL&^7^'&&曯lO4dK.1c 뇄]S 46N/1(8Kbi*],< 9/88?qLQ打o̻{ٸhѢ[}Fۯ_,˒`n.%%%iiidrwرc܆^ӟ4uʕ\"##|}}e/]tM'OԔt\>,,,:))):3335}...+իר8e _LLLHNNj111}e­V0>hm?_aN S/ % XaxI0DbaD,:oxgILRs}ݏd2MO>}zSד8YkH_xϿ穧T$e/WϦ},Ǒ7&|z=(W-OLLP(|v]匌Lύ7n_~A<}ݏOY,X0jڴi{.Gرciiii=>a„T*N3<Ï3۶O[y+$?.X>P7T98*)jc{%iLWWU\|yCw"(UЄ*7 owgϞ/e˖]ߗ8zΜ9A2Μ9sPuuoۭd6<'_VVVjkp?gm^`٬ݶj5kӷ~]ќ@;. .4-r?)2VD9$heګ۝ճ1|FF^|֬Ysd˖-e6N2J҇d=Y,òe^Nx[_kqqqI9sfҥK{bŊMΝߚ풬?[ך~bC䣒6o\l٬}?tҘ5Ξ=!e˖Yf jːb^dzSC2۷o_SY2_|KsE2׻mr'Nؕv'O!Ͱ[rȶ:Ex &M Z'[SG5V#={6Mh'˖-_{y$u_رcj׎^9n.&rrr?#cZrd;w<6O$/_~+WV-onɹ 5eh RnY+6Y{͛7ͷ?-\xJJJܴi&ѣWnݜ _tի<|p>J*>8_~C\&M/^x*--UVl{ʔ) Ǐ]w޽?--횡wl?xftg͚t {أ4Y pJHHŽ6{ m'jmM`0?DInfݪU0To}v d3MӔ TSE rhfbMѮgݎ`74EQjJΰ,9^x8δH$b$1K L ;xfd5M#F_&V3veEIyS14meYдi޳jt:Y&bYCRTYmv`Vx߮yX,눾oƼx<{cǎ}裏>`7Xϟ?ЖG޽G.Y|pfvvv<߬n3???)S|6$$ęYՕ\xao恟7{8xu1A2nr@ T}'" h6{12~C11ƳnӧOhWWIJJtҏ 4\t1_ٝZx////vSC|p{fIڹe|܍;*eh6HYLf pؗ(@ |mXH_XKmud4R<琋"?_\0 W}3 bbb瞅2L՚I`2qćRRRzXHp…/$u׻w'xb.qM z繫6`Ys=c?訤XB5! a"!e%bk RN~=^S܃ga9(k1 m޼yobb_ g͚5;|%_ ^M@5$ 2L2,Ko2qjm6sHĨriR!DaH}Fxp8lǎۻvO.]tt%\JSN}8))YbۥKO:uԩS?7>a'qJ%V"eYeI|-i37nrWakpo4:!N[o k(:ut??`oϿ[vgfmsz@U, FǏo7klg)a8],RrYD"b`6k** k6GQ+bLB.+i㜕]g5YVdddT*m2c۶m+_EJ;?'^lM&$$ (jE[%))iL8qիW/7ok:jYjjÇlHHHȑ#fffOboL^_~+Վ=3s6od2ߓcyU;Ϟ*rحI޶S[[[x'W^}L._0wgM+H1El1a4ln2,Gۙ+L"`IvEJW ˤrfFtMZpqe'C"XI$R8X&$D"]mݰ[۫:t 24СCFvښ-$M5Po󪪪J֬Y-q$Tz}֭[גc\V.4MȮCr]Qp8 ;ۃb <#/_/kOL&X0$,bigV:{tf{46Ws8ڔ)$] xwvAѣɛ-~`PY& f?#!WCJ*S67Vd!Y:DDbrZW~ L)n}E$0MU"j‡ehf1 M{UJD"e=Lx[yLߥ* qrj*{bcc|||͍\LMM=>̙3gu:]壣^ol6K^^[,¹Usȣ{^G2!2gYfIhX$Rf=6OgdB\r9}5 M?~j@_rSۼ2rCܠ:hA%ienkT0)"f2[lfJ*K"L*Q+2?RR+OX;l[mVD"f|*Ul69CS$^UT$ \ߠ>xvyG> ^r50r秖jo󪪪xNpBNjb[!qq;tZ~ݪ/.;f^ʹ;xnuL?oppZ"fERHQN>21)}36oa򂼜*m= SqqqΟǎ#&$:::msh2ES &2'vq&${L6Y&rBDLM^ʸ"(eE~*X#p7y4 }ǔX6-6y~lϗ 1V8|%"]!$bx\&  5[0MVW3l)h!8۬G~J\' ɬә܆r>TwX@{i=&Sa5m74MKKxo-|-}wy?_J$bElb͢RkV[]Zsԡ,0=FL:q0d¼c7}90z795oX 7ns=AqqyС())"~2$6-@S4M798˲RND{ &5 פ2y&D"abX$<e4vv:eXlD6Xby|X"ayaeIRg E"3P ]5/`YvMϗV%?GBb ɤRJ.D@S\!w1[:is@0 PvVQ,$RA jg]_HCz5p&Ir~CEFF ۼܵjB5'ˑꔔnӦMHfmܸqWVVV-x-9Ο~8TȾ>"{ !g<۬f1ZF]pHȨy R>j#cyL/Rp2Uc&EC ?_^7Z굍7Yk] َn{Q!}iN^+JeSFcP73nx|:p_m֧h[$8vg p3 ODI09>jEP\Rpʫb`7(v4U|-`2*TB*2_iLPL8qLyyym~}Jͫl Lz?Uy[zzO=sٕ7 [-fnO?٥=?*uf5Yfj6ZN[]9\ac{ 1yH8$+ʋeq嶍+x|. Uˬϳ\r122wRRRTff&Nӧ;n;wq4LC-M~!Cp̓m0JRXwWݽ[g_ECgg5njxMV"mhP ;:{Dh."Bn7ܳW.X`޽{1cƣކjwQ1imS]t V[P^~cccz;7R|رs/_Zn/,Ca26e[,S@Vd3U%9Jr:w:~nVW|$Ͱw]]U%SPsfΨ_)a~X"dR)-ʙ^ (jXNFX6u8l6;_XT2T cݒ%iZy?G:s*(,I*[X! J_Ȉޮٞf{ڞr=__2Xd)Jh4lP+pve63N_Ų%4(@ưlItcZ%D<3<ϻ2MJ)Tj4%@+Ya9'W Uvlٲ,X_[EVVֶիWJ'BMQR}Tau,ˊry ]د_//.fс2=z$3T"~sҴOXFɨ,+*|عΝ7GhN[Urx߶ofJp!*U KB 7=oIf'$$ϝ;{QT*a7nߐkV}]Y|Zӛ?| ~?~i VPׯwqp88^g0*:Ag0ϫU*e@`G)ˤqC&Zds8Z\RQUC3M 0ʠ.AAA~j_J&I% Aڵv,W+;O?͂ kG2`4&7ئd„ {foqV(igQgVs,}UW5W.9x\Q' 3&I.ӧOW\\ܨz6gҤI7;n29g=r18US]?rp2=/j1Y&%"6Cj6̽wV_sf醸-}u7u:t? sg͚u߂ rƾI݁r.x{n-k~ۿXZh4t:Vo0UZd(R.BI0̲XVW7k:VVUk-I%JJõO׳g-vlTNw<߳Ι3'j>+VxO?B{㏇v޽۲JҷW^qm}sv]w!} jtaZܺ-iyդ3LZ8ΰ>@YߐP/O> =K/~ՎnjyܝJ=\?_}ۯ9>r(yd֖h>ҌsYR,,,+uiiio9A[]?vwvq/Fޫn;{l欌v\,yΪ_$)ZF<˿{ȫo1 cv= W&6?}ߧq}/9?5v-{ޒsF lޠ-+K)J޼J5jVK&ІzbꮔU)Dbw8H>?\^2 6:v믾j]NBuyw>0|*Y<LMM}Eٻw +@H͛7u_`0H)m׷pGNg!"1ٳw;f-3x,?;}V+%v;g8;)<漲W%t/Pp'w^6^!v2ZsS_%<\DRmm<35V/ byt$J%gb+ebeK\Cd5VXB?)i+||U y}#Ϥ5YU%ȇ~7|g}3&JG'&&w[򉜏95 m^PPP'6S?8)x(baD 5:A,^3 {1.]+)(Xm9Ê@@ߪJn~x ҹ3v /z]NQaR77\9yΝ{w}kt56\יpEWx*:&AɭsX7p]:G?dg@ 3t%E%e%e5յuv!?0I&xQ[UTՖMyjB d,Pª ˗/,,I풂s6~UeAQ!r2KΑ"I}'*YW{vڵQus9;;;\rꫯg{.K*mշIk|jum}>I]gn7]** zIbH$T*d2JTJa2$h`S>*A_ZVi6 6bZvvHO>*(,q~ɓtFCivr痄:4,.5Zf'p+C} 5em/((I^ו\ݻw򡡡)))=ڌ5 _7wf;E{fwzu[w_<_sn_SH$+Wwv=8#UJUp$H"ȇqrAD #p]\`2[ Z]E@>`2ke2/E R}H$?,KJ~߮7|&H]&]tZ?[i!e1]#%C;8N"5L}Ҷ\Q\t?(/042D,IDD"Udr*sT7?&Q,)"M8_EeUm+:Re엺I#t^^>_kBZ~x@N]`ڽ/I8`Wح9vݗw%m<_܂?Mn\o[bZ#3[Zsoh1ͰD"r8UI1g0J~a `Z6dY6ZK9-Nk̼[|2LA}:SiΝú llN~X{LyRD.KHO|\&W*__?A"||JΞ~suZ3O& n4W9Nsjm~d2դd\_3F i"+Ev]bd(*_`H3Egn;V+py#kl4W{i@{~tUٟqɣOꌤ@MM^J*LV̳?X &-Oٲaw" TNM(vCWPo~> - V A4 #v{a>}h|IUҌ.Wbs"jfHoeET26,)3Jm7:PESfQvU* f`&Wvi!5%HKzꐪPz^oHkYAAAѤ&Kc|CBBz6K&gK.1c 뇄b]Qݞ-7cW'^]>ٓGNUVkW4vN縜P}B>2fsϟ<|p!V7M~~~nS] bsH$j4MM*\EޕM DIpA}6ܳ|C0o\mJS4+Jdfhݜś,VNodI1UHd2V "FY̰WR}Sr'...T4ZFFV)77Q?QFۯ_,˒n8g{IIIiZZlɓ' jjj5 NJJ̼߿׾ŹY^z kTYPĄ\[Fcaaa<* T_){'Nkj+ )9V|*@B/ePhݥro~S97[S,!Yt2LhPm<::!vR][wzkO#߸h_$ VmrW~8"f5[lUfjsh!\*q 9fn1FRhL&rRTJRRLr ۬tx9rZLLL$3I?vmF͏ϟ_}pŊVXŊógϾ}޶ݥKw]HV&Nx\.o='ͩO8[wM!GbB?pTBf`07e Ê2q 59/v#H`9W[$Q]bJ\h**t'OQ,+WVdrӧ|o;r8u:tleeeRlԴ^ |7_ϙ3 Ϟ=?++k+@ 8v옉Tkd9\:-h<"\A4eX-:4%"\.ŔH"JRI->gϽppVͦsaX_B1"+H2̙֊msɉ_466?y4 ѨݴiӷEGG_-RTT~?-3f7hРIj߽掃8ǖ-[gffz۹sw}os;kn&֭[6#}/DE;q,kʯHϗ⻶^T*Sؕ U_-]آ?-uӚwظנ[ ؟^|/"0RD0a=}`j$++#""4}>ݻ7|sHs0 5۶m[Uk}j85?/ X,RpVU8R)G 7RGlZjT&HbkjJ)RfZJ2ȍhfISRPQYp8H?L{eUUjZ233ۏy晥An^t6y]=[z}d/?<[ל9sfҥK{bŊM'O?5?{yߑV JdgKhxY~~HMsbX,VJ$D"Qd2_RJ*2 "P"KR,HC.TJ?_߀А`?kV́۷OV_c֬YCZm:ܱ̟?Tyyy~Kĉ"ɓ5vKСC[4&7b7+Yf2l>,$ Q I5U ֯Ǩ~#uY=OrP> ym& lXlًޮj5kZ﮻J(((8Ν;9@W-HH}5H$>!J}%T*s{kXlvmsrr  6^{m p=v.ZM5 s{"_|zI\_ZΑK~74uFwk5oݺVWW]ͽc $,+L<* u~MЄ(bB Zݪ:]#=ǚm˖-hZ}ͭhBI5:d7ۙH$"=/i4P~ "X<5\UK$&&F}z!g577ԥKoܸqWVVVmg͛7ͷ?-\=Fܯ_!ݺus6&/^x*--UV֜)SƏ?2 =,޽{ZZڅlƏ8ph^g:yXAƁu׳^|tf5y?ʭn^sRr1 <;ÙνF[P3f LNNII^^^vaaM6mOKK:t0Wָ!#j5=п|J51il;[SSSˏٻ#V&LtիWo2ٳO8q9;;#}j^;zҴE eee{HIILQ(()(._XKg˻a6ks>5F]sG;JKܱ㧷G^W^p My)۾}&N oFoyCSǧwܹbĉkܹ#Vs!K|4#;Tq&??} =ヶl៕V11lff榓'O7<6lذd֬YÚ['LHj˖.]xx>A/5MqTYQz!cO>|G ú`y.' 0<N6,<;_칢KM"Y5M6Is<L&OKK[:yyyévpMwy UdG:d{Ŧuf}Fy[8- ɱsn[lulâEx[.))Ν;Myi޶Y\\|~ 7ա}9~EGfy[7 Wɣ'$bXĊE #Ѭ[gF. 1wS2rFpHXo4U/ˏ_ܾmŭjҹs`Hdר˗/2LRZ O lvN!!!=GGG{kM֖߿t20Lttt_jkk+9PRM|РA]+++ :-x/7n=s<ϻ666;Lؼy5@ ['eT=w"mC:lŅ9q0ݧ,fM,bDșn 9g.+aQݢԾW+|BbŅ~Num@ P4|efffEff撖3| +E999MffWΝCk,ˊT*}X,WF4y2İ\!!!'71H65o & ڍǎ;)J?yݺu=Ip‰o'WoR;11q㜓S횞[j+\tPPP׉'C 6ঋ L٨^ݶqj;Y-f}iIf|8>[]Fu#FqIUF7 73뵩?Rl駟n3gΡaÆMB4(=ȸTXXxdJaQ {n:! ifpgNgh!M*ȣ3UgOf|"kϱ:IX3v%I F֔Ξ;'+Vt9L~:r0bт@ C @3@6H'O^!9sL|}h=z]ƀZ){2 7d[º2dȝ>֯_… h=pH9)oٳgݳܓ4ܳgOO<}:)G^`;߼ysygifhbiҴ:)ﺬڿ$N̒e!At}Lє3I =bpLߘYQVX;aX^Fږ]%+v+O 4M 1MٜsOt9s柼-v)))k׮¦2 Ðlm# B{3bRl0c=u vO<1{*'BS{=?vN75~~~w8{k֓J???UK>ǐ=ԓO>yT*i<ԩSrVm4d2k^y.{…z Z{>n`3Lc;d 4ڪ2L23CZ^S$%12Z$bXT̲$&ChZ-:[uyQfHmZ#۬zEL<onQQzm{`0652?~|ݻwM-Q{nٳ{֟dʼK3F/fAYYY=**JsM@n(*F\d]$C̰ͶIڙ}v'0,,YZ44Ύ 7Dj\ߴ1;edfV̒L4)Еw}rfmϫ>V}tT nt{I\зz%1ґ#G&3iK啗_{ʡn&tΝ;o Ƃ>|x{`wRTѭ[upCzt꒒v~,<-n3׏B6D`2U,:Gt#akz f&`ai TwEaS) RL!)@ynj _ J8fGʮ:`C F饗^zjjxӦM_+n7o+g~CCC+N>߷o_RٺIOxWߥnwy{HII6mڄgܹsgvu8++ %;w_)l!BCjނ[|^QQQسgi*ʟ􍾑wMV+[ 4T HCcfyJ5YH9{9~֠=}dѺ2=Iwc)X,0bx(`gm7r* <2f=}mnfo#ӦMcss^|?wD둖vr]dr?9Gueż3GOe;s G )Z/Qw ?ST,2DY <^T)iۺռ~kSpכJVOn]M$Pc`0ݐ]xbYN5Z'Ubbbg욚Ҵ<n`Y׈(I1Ό띢TCnj3~ϧOSOM e6ZVY8Mm70%%t2kj=VۨNlxT=* NpppBhun+r=O AnO*rEoqV~111W,5 #O}̘1wjU]vy?]\:&&&k׮qgû~o@ 5j>#GL qVXp]wkH_gg\!hg ;C:uu:W𤋮($踾c>~TCfXVoЄUe:G[pjM6&nwۯ\CdWnlr믿֭[Ɍ?>׷QƖCHpHQQQ>9 L2?3 .лw!޶e0۷oۼm۶?C#""x#O _xOȴwy牱c>E(--H90ÖJ^3Ç'ܱtԆ<53N_رcGggIrr'..4c\jjj֭[7o+5!o?{l'|􄄄ȀNuuu{~o@ L&[)KXxB˿eN?tl:Hmuf2l0lMĮf#:( ^ۨ' &MOtZs8leWNfM0xn ZTK*Ruk>>>(}޶uȑ#kzذaS:9rZSY'O\2ۼl֭$ … _yGF^7&Hls^VVIV[u 裏y7 "UMe~233"}{Çܨ ;wO?]'M.g^|E˽w^^ީիWgPYG9_I7 <;*rN=q8yZ9y|O־gΪ qr4&=y(fIn'igdIotCڙ&)x8A3uuz=ðlC:SǷߢ7@/gSlWm2$RSz뭷^~olKX,'|g}浙Kfff[o`!e og>~ڵJ-EZlkiiipHo!!!] ӳ߲s=kbƌG&rss|۳˚g>}6'7nܸ# n1j4)F\ӟ5>&@ֿW|&H'X9Ojh|zXBzxC|tM;r@9'B} !%Ň V%R  Uyġ/yW_~na ~m9UhgdHs6|ԩ˒>?_;9s -**:c1LK>ݒk2ѤsKU^^O`_>&O9,$Ϡnɓ'G_|^yw}y=˝םynկtԾ7Z>mJJ^ݼ7F$;HA}CUCCGBs|:ojH_g'XIq򄘀Fcqޭ.III[nzEƖ&˒uZp/b1 Ik!ҚNfΜgܹf͚_Ѵ 2&!6PNJq;Ͷ[q;egIٚ(TNM}v;ceu,Y#ؽx…od'jZ9gΜ#FEDR׼Çݸq㮬g͚5699y\nݮiBNsMW]\\\ۖ6mڄnݺҐ. (*(( \mF ~@m'>_F;p;c$vO$>uBƼ{\[[[hѢW>xsf͚whݨy:/ cpwMoV hDbbbP@@5BՕgdd493s= uf֭97Ck:IJ}r-3@KZ4m"!&H0b1;,9%_oxq y^NVYn1 h͈ 1 M M34AQ ЉI=¿FFEi)/r%o.ڑ p|fܺ@oB 92AS=Ϯ*r̝`Z8qVc)[t-9/1uqs*6XlsrwxM|L\,beE,͈D0bf,JC,bŞjZ` ].˰"b  o=zt~iٳܲ$[O/9xOd<~ڵk$%%%Hd-hѢwڵN4{G3fxRP9_M@my4-b3ZL^ Mgabi=74S$Xg,GH`24>蘘>追{vþȲ{dɒ/'x?ؗ^z_ =#11q~vs͟?5$0nsgn;}e$%/ vI?g8XDfYF u0u,#0bg-gV :,Cj6C{=ϟ?]$v>}z8HS /@wذaw=… _"[޽x≹TqtwMඣV$V!.S}&Ap}8jchd#pI!&e(gSox2MӼMS "y =з_ [wjل y.\p?N7{칣FekF3>|111TS4w丸$o󪪪J?m۶mc=6sΜ9Od22**;O>Egm;۩S4hݻk<3䜧NUeff^OSFQ yEEE^/ uB x}Z9ux]&EI_f?@d(+`lV癥i:S"4M MG H5fB<0So1=gXXXy9̼LQeݺuRSSÇlhhhԐ!CbsrrP4r*U *n[b$z366V|3--2L!ۗ~50qݢ|r$&&vitvJqAlP@# ,yeYtGNfw6YTm;&&wmħv;ˀӯ߳嫅kx#Ǐ?%'Ϡ#cS\uP ~uۖ{^PUT(poEx]y裏اOA2e˖-Pv:I%v͚{>tIMMM6`6EQ?yϏ䓷=Φ/  \,Y KtxPW_?O?R\wG l:^}c?yLaJRJf#khUG|ŹfX5O{>-Ydь3i4 ̓Cl͚5A<Nŋox\7޺ 8_qYA^P@# RA8@gOݿuGOz " 8Y9ˎ_}e' O=dԛNqO Z(T*ٟoW_`W*lꈥ4iR7C\5yٲeI'!))˰af'cǎ)]v&۷L-//PE.>>>; p<# G,\*%5#1>!9{Ɯ[nW^zπ(u;Xxxa` z l WU둕e/q7NO5Kf/@Nyl67oӳ˗/'|BSL^EEE晫r[\\|7͏~wI uֳ{fP?C:r{A/Aa?zN*?4tĄq)1W/y1XK>}ez`-g}M=?×PthrUNܻTյ7'WWYY~J0|wJ /'ܞw? wJJJɓ'CE]׮]o{,Ϥ= ,^o# Hg. e=ν{fFfV>~[/1'oݗ1tĄ&%fEn͚ Ggv9vuݍU`WVVRxe_Nf7F +>=~`8r/,o^{=>?/(( UVsI5gHܕ5qWLLL¹AA.(AˆiڒfUK捞t{편?*OK\h%CFR#˲kJ%lь*??z) |eQFVQ7 Kߟ|_wlu?דO>9| CyEEEIen-I-;[oF@e9xrݾaÆ?3NLLjzѝ^{cOLLLtMSRRr NAAAlwO~&!dPNISR& ^`f'oo/原Mw_{AF3cPJA8 eCU~Bgy\ohq FW^|\u 8  vWZ’bŊL !m6l(lom]]ݩ;v.,,)((ܣGAOMMv 7\e˖W@l6ӯ3Lm$Yk'zrrr)S*,,\sss|1F U)S)%Fqs̉:xXL(e**AAAb "S[%HhU\l6%=-5#.66y܄ח746H$YiN[׬11)rR0(֖VTp`J( .5z۞EQm9333>M4i_OLL<]?`~_ӦMk͚5G\hf :4qB={\wuՕUuuSJoxdLHH2efuOH9n{_v ;w;댾l6|3fGAwwx[]p±=/?G/o}7=| >:xAAqˍtklo~n/%:#''nz̋,{gߗ쿗\eA UU+qAA<8㠥D\.l#`9`4bbE J  oOu:BF/㦛nՙBp?z}錾u]ØG>}_z[n*f+/U3k֕$&&jUWccّ#nٴKͼo77v!P!Oe[؉S=ieg*4n߳pP#///СCXKK/ؙl؇~ʊW_}u%.Ň  r9:bNq-Ȳ̼>ovK^|~( !&FXyhk|>PU1ta'M&;pn "3!;;;뮻h4Ze&ӧOѤIzo_ZxlDhs3K.0qv)Unw8~wO{y{'&"/D^'zw^HJ̹Ywz\<,){ŋ6l،ӈv:+lsәtw\Q@# @s_s Y װv8`?, 6YUU*,IAFU^ydqؒ-f]'z!SU%`P 2UU#b26+gEiӆ橧㸸{SN]BBBƄ Fo_|}m(Ү]~G/=zٳ8Sێ=Zo߾M[~mXo߾%%%EQUmjvGWr򔙃NAz  twA'̹)S]yd$Fkji6lX}V<ǧsCٳg_t:+..>s=G=Ѷɛ;wnlhAA*uߞ={4P$o֭^+Z;k-WܑԔ}@!0گ#cmM&577w@YYY]Zj(PsB3|חL]*'oѨo,9Y"ZO"[ޣ'L5-kDQ mԉj1pO;dlzMk/,Usݻwo%gA\\&% 'O  H(dԌ-B:{!`2th,&j1ح bufqЂ(A)(:nEQJd9z%aZ }9ԆssDrQ Vw0j鴙L&[u555Z/;|pi ˵w}p_.I&KVZ"H\Јi藐dѠu64y5M ,ڇv Z8^XC/€?ڵkXѨn.=h(}Fgx=2V r9:ZO^ES(O.eyM6 '87ĉ/yA0soDKۂל'xKkH~UUTW% %t#+݉qxŪ*oEl2:HՙXg? Ȳx` QJTB8EV.=pouX-Ɍ274|JYif1L^lCZϞ=GJJJ(,,$ ƴ #\xWZu "2fCN5^gջtḒ(r@%"K͑o/s[;cӸV1_zş-xe WsG=x-ZG}Rȑ#M#eee5`釒TMǵ[`\cA2BH4gj8viLïd9!yE,!Ha(۬N \ǂ:Q78*r>$EOU0 ʹtQ A1t.uHX7%>9_l9=Fq7_5fՠRh0&S@f2 q1@[rq?튢 &IȐ;tQoЙ9׋T յu%X3,rY/dKVVV:h*++O\CG؇6iҤ9sL&JJJ/ZhK>+TE˿|l|h433g)JR{] əY]{T6-S:=+{hgؿԉ˾X.x '2`}KY`Ӌ-Ze˖ӅtЎ_&O-^tAA"¿|'[YYtUw4W Ǵ n0mǐhBI=#b [2Ui1vj,G+kj+VH20x)eA[A)I\c4!#s ͦ.5b>}LeL γvc+**ʢ>iii:tvv֡5k|C=ZPPP} )U8˿|N'x->ed) n)JUjrJZR9WۊK,=~.]jȈxQqnV۷o߾(:߾}{Sdee~uݲe ľs}c[x,KM:FAۻ9~ܤ`BM3yoHEBBqIhzjVsg S^-#%a7㟵l` :ؐnL2LVͭН}Zk׮}k7ZY+W.Pg$555-Znl~^z vn|sϟf3]~wqy\_nY+ |`4z 5e' fvq]2h&U[7|Kg=zwJs(Z~?//-rhl_UUU߮%7 4/[B7k)I=nXvALȭ>mR6YN!̭o>^dřٮ8~xgо<[mb*|ڽCh{@K}_B־s0qdލQ9>$#!uqmwL!]DlBB&Dl$2 URRR;k} HOvba e,955H۠ou'JF7?~VFhwd_!Yײo"/.ADIcamsEF@R|,AIxKUERS!5(jlӒ ^/AŪں"Eb 8dㆬ٤7o}ϟn;8۷/}*Krkfufːm L N}'o{]~7{wc}pǖ5{ z33@ꊒ: }3~oӴYܢ?wnuM5]{-y9LշZQT< F *69vd4@%Zջ:[cINf5}XOcͶK_G>WZEyB#¹%~ ??Sz3\oo^묾\q&۝wq8~xg8=/;6[}ks N hYQF[UP[6<9!.1.zܽ[w!bP|>ϋ/כnץhwjjjx C5\34j̾3fmRZOKxIڜ *+ߵ~m [_0_ް>' mk(^u_eokO5jVf.Y5>X%d͚5Fy?Ͽ5{틋n\If|; e}oy?:̑h/56.witjk%ϧ7  4ՃXOjltݮFnmx|~h;6el:T`/ۂ~XGbdy睿+K _|uʕFb8zC.3_'͟*ښ*9rq# ?o㺭_}sӒUkCa/!c&CZFΩU~>l6o/~=YYY=_7~_!ESitő=?^)~\v/nOglj69Sb.\^A<wRYUH4U_it{]^o eT9xHkt{ZX"ϝ =->jkk[lf⾐D=5k@H ɓ:NKKLI M=1* F 1ԴH}UQw\}VT+~e%},K^tO>S΍ =bbb?p8 O>䛗=zu,RGc{8~xS8ߗ~/_[ 6E]+wL$7:V7M}CUj4~.GLS gEQhP㮮/QU0 ›i Y=khX|~?]*b6beE!FtĚM 0LR^{z뭅ɉYW^yMG-uZZZe˖=D]v]XD>*.^8IZ"p)w}'=ku$:>GWvWBJFY}=cwcC`˲*U:,̠)d Y}&LpSk iӦk׮=؟RSS6h4ZV\3]R 4n~>L>G} !wYii깣̐uM~z>ɹ|]'&5@ bJi>UYu ^!AbcDA(BĪV:d ݸɲx>>i'XhwXPxپ}{MWEW<=<[h( 0lذt{%|SW(ҦL.3B!Yh餀WQyw[;SZr\z%۝3xղ@'D>稩neQ eעM9rdO~TBAްgyf^)))=nkVZ@_&1? ^wzkg^dbbS0 = 4kcHuE7S`:~_qmwh Zuy<꒲򲊪FYNbׅa q`2>YVQRUS_\ uf6bu:(@@i>.azCV$3\ohhoO-~pڄQT 544}1^]}38u0 5=o 7M-=,8k{{:>k$vKOHJF%ۮ;t핤3nnX!]ti/.(((![oMqqq|?|џN@S+ =V|PրE vSuFmv8.xI^ߗx95'6iՖ=͵.Q#^RbܾGoRҭ{_k( z?OQJ a w]W+NTtj'Ag028.>7捝yGFV9|0L $Ⱦš1ӆ}5-,Ķ8qKvӧO^퓒&M|ݸ/ 7  Y3.scDȥHnFC4Wfmơfy|BCSઊmtz| 8Caς @o_+R&68-"X;pMMM+&&&\z4}.tzA#k(UUUo0L}W-}Ғ#%1θDިF`6M6kBJ -wNo4gv5r1kOr7Ǐ%%%QnKKKK hAA~LeL3u PȡנPXD.j";kw":|MNkۆ4n_Rb! ˻`nUQt/z3:UU wL`PWxA˲${}>W0(qɠR*].0t|Lg}Fvb˴QWXXU))iFds8ch.Q_ v~a:"oMz"&j5[gLbJl|r Upރ ~Jf}V%"!!M)fmۅ4c1v k8 \2!g-.J\U/i63/#ٮ[YI H"1$IiPI 9^td2J%/ɲ`|>4e&3#ɒ(~|iΝ_B)xU JvMa# r9ߌƎ֓9g+ZS[-B AfתL+TUE Vxa7; nܑ8Bb+ˊWVzYQ%Yo&"d6B&c/@aPߠ# dr=5L$YAl%E\;%Zӵq@@:p]m vݒ$AodV@|||!N .v}Æ g# -ѣGw^{5?111QӵqJJJ]~w&+}1(pu{w쫮l!RNV]ʱ$3!lq8lD=&h4;$)-:t`ˮ564REaL yI\2 5tEQl}.  ^URjDBVhcaLU6ʊZe#LG8Z,9i%o FZ,b`2q "ҏȾ]UUd',,l4m6qv >g|ժUMֽ{mz3//-[DѠA9ΨĥE{&+lvfgg'6MdggfQsرlӧOd2;޽{6_&rSL#77'D6|pcE\wcΘ XXDB7 ]i& JND9'YA?1Mw>Knqt7lݺ5bq{p?խ>??ۣzi (AAœ rZk5@eX#\#e&@0jXQ&Q鈨 T,֭i3EQ$ey^pfEA[Ffe&d@~]v-^W^Q^/ ں={6%rPRRR駟m^Zrn:tl6iGPUUYd-[lnoBnݺfGm$W_}^u#جIھݷ[+b< FuۦQTYi݂^Pl\RƲ/?|i巋zczg#kQf5?`uy&lvՑKK7o޼8333u>}F<3#:j-] YAA6XL-aV[6;ukV[ޙ2o޼']0??Onn.ĶoAA$I}&xA氐6kccb #sp8fs^ z Z-1N#6....)11>1!!6!!iۣf ϟ{Yg+27zȆ@-XQ_񕕕gyyy;s\p>sܺuc y0C a Wڿy{d}^/:B{$YGOb~7s𾉖}-d>O>xlڤ:!0o޼;зUW]5ĉg/_|~zz3AAA0D7 En0`6 fGdyd>%,ʡ݋pwO]ke4B~;@4w׮]+l6$%(V믿䙴 ;}?544T!.g#2a…=R[[s]3{rZ`;d a},&iA9 LsL'] mB`O:t?͛?1 z~:7777O>'$;tpAj!  (P~3FHtxPjIx:\0lذ̫zJ޽t5gE ;zEؾ}ӵ3㎧"!'i_rsso喙%Gٷjժ,XvSYf :ueVRRRrʍV:|.^~-S'O2tHOۻg׉v6~{9.kն16i؉Mf ж-_Kh,^{퐱cǎ~ N O*cׄ>fa|81m%lL"?l(ap.U A$ hAA: 'p<R(U%*2z&u y"aǘBTRJ,c (5qpnwBa 'g\d 8Z}4NU8T% QcplB'暍 ?ss O3^;#SshzN p ^ A rrKT^:e| nݺә&2y='z zAdzAtDsRD U UITaBYJ{M F #:^tt< #gLQT0JTp&<5WZs);,g'y=t牁q4JU"2UJT""3PbI8h XsDODNDNEu8Fﰀ&,T"S0 {ɕ 1 ?tKAoaqe=zj?>q1ɉg_5b6\zC}glMAg:M'xT[% P*`ɨ t~n͋ ^glF;ϏGkD[vXi}]]5+-/`a񹴝c6魜_19tIMĵʺ=l{'qXɁ[W$Pq%AR?Yg h;w6|mV<I^W\!n[S LZ7'4 ɏ燯{dF8 ||//InZ.JT\ rD3-K.30mgtDի}ާK?ZhP^գ"A@ 4 \@d6m+򡤤\ ˝Θ̾\i(Unݷtk_z#iBֵN?0a]u} YcwuMg˗9s ,S'N{xbLvngNԉk/lc&*x)&:,9,X !w?]Ǡ3Mcl3 ΄*\02Z.=gΧ偗~7cڳX5v+>˹xd2```y靓;?ý]fMOJyd7%Pҩ ?dP@# dРACe(-,No`s8ox +\rM8gjK ihy"+MAs <;c y#^{ܟukfOiq ƄĜ}3z̑MtBŢ7^zO=|.9#r~vE]R!HUUM5*2XRQqhz q78+Vc|hƩiȴe,d\< 4k$uG 9|B@uhGjKslo78SF "1(Ao8_F| nGMq%G?ZO(r)k!BDEk@ hJIk\Vf]w M=n599} k~*۱c7>xوg@Q4g~}.;Npzy}z 3? gSϦ>#$oFޤWeٸmGjg]7W}G2"gyFNv8]C*lp 4Lb{:y謉|oNr)%Lz;'7>,\s.QTN5 eI0Q3PJ ǵ+ ;>R rpKD2Zc*iy.zT8hMrӻ7gM2bVL] A.=(AqCz5p_NNiV-)7 F{zF`hUI޲~ݻ6rFpB5@<Pap,OuI>r1_ߵ{ւ UWZi³|m2:N'xېܼᢠkzolX]1উJ˴G`7j7 j#')Tz+tBX$yۜ잖>ހ[`ͫ;/a#~>SEwOI7{¢9xQ,rMW$ŦGݷ['[5nx{#~`W\?!zuܺkP}EJuD` =ި7;'8cJW'krhb 9,wH7oZXWk6 ΠVYMCp<LH5t3 aQNb + YLaAoC4BХA.cP@# f]vmME D3X#͖ۘ.fLUKJOy]RH; yts-\ᅠi]Ŏ3yĔܓdt`r#n/?[]:u8l)qmW ?YurFV֟|얿co` ΫWflAYD"x&gsM+d#-6R.ݾp[^Pa>k2frfU?爁K}ꙋpDẐ7uңǐѹM5ol;?];*ZʩKk\FvZߦ8,1殩٩{w ui2poN׏~hӁ[%dKO޼gpiѶs$9 :vm=iTD"?oX-Xʨ`G^c$=VAslUÏlڶa*W>DgWMf^Hc%Eg9\ZU,6}o`AŸmWo:}\ZP@# Ei#UIIɩ}Mfs +>= Y䔴n/-^#I''h&)lZ!1ٴa1YF>V"y"Ld6%ֳv̱ ^e4)A?~蘑cޭ}f_镳mAK hAlݲoM ?-9g҄D _Bd X*SD" 3Q}DA'Z,VG$xB=J \!]5kPoik8n_og7G8B)Ǽ5uQ4c 5"wǁM1=9KԜF)=/Jk+%.0B"2,\ևn]_eR`29"D 5->3E'꣎wP+w2US1l?vg{',m\dAǛyQ`Ah1?YySMϊ*mfeh>7/Ei ϟٳ">..3Ԛvݻ*dߤf`t 2Jh3PW qZmq D4;_!6hiHD'rBsOf e "ص-%ây*s69AK hAl{E{^wf.ܑm@.=3lp~YeR׉ii]1;qنaǏ޴nO5@PTe{ś9'W]ȪfoSSfS<P&©1΂-Tc p`E58mp3]pPHuAi`Ń(SPW n LDNg0bPƒS5X19qs~yUe5Y%+pVj]5¸i.'(x*^UFe^ #(;q̌hj:nj74\~FAKtϮ-j+: yMl\b*5jbvrP{䉲'JGi Eή3V&>!nI ]6)cTUZYRK!* J8CuPT%͚,p0H6-@P+ =i=UHLQT$%H%E&SC=]/:iqа<11)c #P@# hA?<@Jz`bc zgNQwCM-X܋AjYÎ͑:V 0\{Mfs0fvzV|c|/q #iʐKk񔜫2OoTLDC*heBB:q3sS3|{R *5{5K>HhroG eGhm)h.ϧJɢ 3{8z@VRvJJLox;7X]^ꩢzZ5YKbv5v~ߕ x/5, ~{r 4!b}.Wv_bD^D-Řr<1@i2p&8j An3>W#*')!85h(S\&R2 w|w`wkN)`*Be*ba(n>"M&u !x#rA  rQ ,?iU܍7~@)؆' JYTC!<5TU,3`(;yJ];BDl8Vڞ#c S3cl_0B2[{f3uUyb#T7T4lٷnԢ1ES# cwo;r꒓R2#tU640#r A  pP/)HFu7[VIejVZa- _Jk%S' +j˿vQhVKEy*U0j+$\eկWqẳKJ¿l!{N f_?iq&ۢ7?vH U9-V4Ds$b@h O9VmBҨpX,GLL < <m&i-2'(BG3VM^HiZ1/׿[ܧ^=@!^~$G0\mU{gtC` Ms,KLR{'O(Ү!&E4wjp O('ZUt;; \b2z&@ʪmR$$KUNҦU¢ڴI==FBB?^;xDv^"%'t>uZ|\A hAsigM 4;*PTx@0 nyA''p *iʐ⡌SSFjZ`(ZTY+r|OsBMNh ak 9ASƍpbO5|e$-/uHGΑh:9?,RJ` '󫭯}v{-iuW/shFQU C3੅ בq [Hg$ |NWEsz12yʪSz%j^f rCY(ٯM[P^#D.hG4٣n͉%Z#;|lծ_ݯ^^ 7>z{_3^e39+>^gϽҏF+U5g8V^06Oexi-(sa vA  jG,9tj} IZVUR|P:*6C>׎ Ϭ@}2Mtt ?L1H?bҜW;sѝ}29Zvws Ě v癀3ɇlЊHUUU孷Km4,!`33r͵M\qARBeT%'\s,m:cϝ`nk_-1%2Dڜ_|W sݺ.ݒ3(* Q X"z=nJ)dT7 .]2Ϙ#rq9YIAA:~/ljҴ hېsCyTpQ4c Q932P;\ *nHF|C`շWlNG="zެ3r ? ׵#3wYɺH :UA. ܗEcZ4$DN=YQ[Z1=ցcLĉ\dϽiO'ؓg~\aR3CQvbCPn#:0WbwLdC>'K=IIHHzrjlQF+b S.ŜjMƋ}NhxΦFkt MN1b Xyڛdt䒯 ⴡWѣ!fWU+ xn0_5k&!VyChV, @X}C}L*4'33g "- r)٦a8k7L}s/tBɔS(x3F!s)e;,`(Uùjxgw.fM{@pFnj2e•#o "v$%| EVN []#.PhYpRs(cL hTwA{hlVJLӷ:-(2glX"j]Uxm+Z]'syN}|h:.NK97kpNݻ8S4x }fMF[򦉌nFhL>'z;dЉ=oз| &g+J5=^?oK7|)K{T"HJXљ;߄%GT H87r:{[ fjJOĩ*x=n-MINYU#- rвa#vs7 N/wKLul֖Ga VVQnM{s3s8l]{Z,v#1;VM?عLpb`!9СvӖyIp$Gd cdm^G֩* Y!E2%̃f~kg*)E(2ޱlMuéNď`F瀮c&_7+K$bжg$-r8v= gM>e&>+m`nW7VO]JyB% Aϡaf `rӞCZZU̷]l_ܤt4eI*JUP*T䗶 cOx%9 յ1ri{Fn\g4Z r<J.֜ZwkίVGU>*xgA(C흪9Qъ>رGJ|SyjWȢ tFA& SJVWxQs꬛nkIMmWV*8eCl)aV ̵E?tUcrҥg̬}vP .* Tl{)n΋x6f>vkf^=fj>]kwX-hSh1_#b8`s0ZLUէڹ5&DomAFAFS.M@'٢6rbߑcf=N>ꔃWF %X {F_KQͱnC{2qrZFA#`4Y(Cs۹eΊSD 66, MYJȼ A41 nL ް|o~ԫ(D֒\D<#j[F,Z@xXUۖ ʞz=^Q8Ό&42jޟUEuoz@QeC̡C:8uI\{<7I>.z7cZi. ʂj,TI;5-xZ,pai\LڕhgO[N*V[4G7EE9`b>59f_.PeZ(sUyBJ6P,!wLf* 2J8r4TU^ s7{:Ƃ )N:Z\t7|9=&UDSU'dURtU{O]m6mf 0nG䢂AA. kzǛ0VGLgv._scn3θ4YSҺZ tFޯ tV̖XSV#_{Cbj\ІH2O kӾzNUC4"糶@Y!˰c:(>W)9IwPk_<@Tb*(KID8PjppsDilVH3|a/<9ȨD2$HՒ7^8ߘMb8E;6*SFx8suc4fan 51 )ri@B:W/y%ѽX(]9P&shD;蟪ʴU y$hWoU/@ΒʫKu:0-kLbbR t!'1Lu|`Š7$f5J^P L)PEQHPKׄJ^NM */r:3#,;hB SÎ-5:>B>:8=ώ<"5ÛHO׉b ! hAD,^<2{,K Ŗ|;A)lXUBat9C{ 3K-[&56=+{57WvGܼD^)KC*\tζ5!VE`Y_ĽcOasCߋء4T\5qoJ5 &@ c,d0R֠C>M,lB (Q9 hCU%ְyʭ{ׯy^G5jb9(%\=~p*ez&Lʁ:dM wh*YC:mB(lrorT8{J2EQi&G*8{rf^༪d;Z3FjVIVHQ^eP6Z'w],ZtE3^a  Z1:©LT"0!l} 咏LXAyks]|lAK hA6~֜Ǝ7nFTUjˏ/:`ߖ.WGVʫP*J`XB#1&9{,ܔZ MuƄ^#N`Y㵲*Zp1WI:y' Τ3qqM9UK\cr5*zpJs;M[7e1zCe-R2p9$ǃ9xNg2BBmoUeERD \uy0 ѼHtDE T4_[ }L;6{]!\a?^% )xKdS!Ob\Rbr^o oғy蠀FADc̮!r'N}sϜ>,[bAtu\ 0XrViO!*ʊҚ̆~COKN,ϑ@fgf^y_ܺMk[PI*j8c]P f!&';wȭSfv ]o"h Y!R2X.6X#>Br%9_PtSrH2j( 6`*h.dcڰ*hn *r2'hnJP vm]C) h-Rs<'1恛hrpv ʾ#;wGgYfƪ!~j1 7_qMVQM;i+bblBL U%A2'%\rRJUWW~g=\2P@# E`[s SoKLJ խS'oYGYMC]GVTE ^r +R1]>ZZ_W]5~jjZ->;c2Ny3&!qۯq0lυ9A4&޿rhQ=-?TOjt*i`(6:r˃WikDNtD8s:SV@'Jز漞3M|`b=gu,k҄L]c򅣉1]EA-7($UOe$2)G@!>&E&@80DΆlX:* z}L)}ˣ%'!1@QkN3UyͩPS8BI@8Hoj2D=1/59;3,Te[vʍ ny?? "V}.sۖ#1c-)F€qxU~&㉎S'%%HMNLtGBťyΜ3]/K  yV/SMtFGjn/;r0I!gP%]xI(ѤY5SoӦNӋ6tX_Rʜ"UEL9SK PԼBݐ]!uřΑC6l[}\ DO8bhml.l(!93<-9'=kzIձ S_U8Y UA+*=Xb-h6;oW^DMB,IePf4! erTq&1*`eTdޣ$XK5-˥BkN.fTdQcapO+2Uъ^u6;RRSa ۊWux"2 ^KepgO5N*DZ}Ŏ*gɮ'_?K1֖zmlXkZYn`ANE{ grw$Ynj($:Sv{QZY\/V*Ŝ q9={ Fss o?F䒀AA. 'N;nksz*Ƕ^/>y{%d* `p[RBh*e*d} b66xuuuUN{h;[( u0`Ԛ+j*>o9er!ʶ2CF4-l1Ԅ%_~vͲ*d9Ç,6a87V3jN*Zt+ [~S}J9u5W\5UImJoA4TP]+ Ovi#2Yo~g*M2Z  [–)p5<+v|wN5<;OS~˾cÓO<~W`u[ k 1ƝW.,ܚ hd3;L=[]F<^Tu_ !lSiP\ M{WmLvʥlRrZ34OnnͻnۭT/ Tڴs=ELz* fgl{n_obY}]czĴ4ݻ́^m 7oݶ䙌 P@# dժFII=S͖NJ,Y die L+Xő61КiDQx1ҾNKI2p(? /Y t^!TՖ%jjm)`kc_Ex5+'[Fz z;n>% %U tނY3,F[T l߬io<GFEeeK`P)%"|nܿry=LK+Wi&?4om&=+7KQzIX5n93e3ɝsQQ5pľc_k9@!SgQ 4^jȑ# z+8RdgV9~5E;@bDD⼬ŷ}G=QL~l;~sՊx̋(Oy㿿 1=s3Ϥ=}v^^<ɭ6(j ~{d1ݲ4w^qJɫ]\FtAAc޵kV;RTTQJ=;-Z7o\DIQTECn"S*TsߙjeEg-ǖ賭}\Q^/ QQQrŲWv7n>Db͚>rG %͉!1/ni zcqZYwשTT!* f|’(+skzOlOT_AGDS kBB].xJt۱7ڿc`<QB}MW?ۛsV~){K ?NP~a֭[vcD!$$$qp_Y]og\3a oמc 7,%. ;kemYvnڽ~Wd&d %9S>8xb#QAOb&M1߄k d5--:y{w헼j.ɧz2%Cs# Wk>{Tg  rx,)(_0z K|"ώ5Bmȼg"⾭h%*ZH3WBkx&ٳdyyż.Yݫ;s9U[4(, R sh; 6Pԭ@ (T 2QW|KIA9,Z/eP`}f kէ)/dZi7_^Vz+^[<ߖZlLN0Zfˊoy֧Hx&Mc>X> FZ%TR}ğ,䃱cΉQsrzw'l$->ڟBŠݴnեk֯^AEpx` U%ERILbZMrE%T(UT"|W|sA94-> DJB2`V{Z(AMM%Ky!A  hAHWg+++->va-D˾º@ 4 `t4t(:$zCdoa]fr#^\σJDXrCX U6EPtDwdoii-~n JIP84w@ QR?x稾Ac/o߶r䦕 &!E8# ψ*AkT}͇8uO}!٣rOw,Y'x~۪Z؂ETK  B92;͒G~qo:vԡV=jw܃'e޸byVK^ŭi2\Wj"R1e9'rk0QFAۊ^-ZlD9xrC#OBTUaD:8y˾Y- =\|AAʀ^&-4TC^ I5zfTYe\ 1 Vb y/|هgf;uY,۸b-` @(H@ |!!!B n:6{dM.tmwg;{'(cƨ&Z#M^~˾fs ? Z!oתf\z߻{ m"ey6ftu aLe.ͭxTdz=WOeQCk]-+66,_eEx.vAk+7`y-&LQtV=_wy}O7EUGQe`SvU?U7a`Fxu-ۃx:aBE Te:u]4̘zIN/'wr]` xgks6mްYF+oEy ؗ%AWA  pʊӝЉbR0\M_YF!n$թ8TEn ׫9A7˭Ү ?p !0,ӊZQL~]}ZB͡=|۟_~'f!P疺L RtNR@j*BaMTX"i07dR޳)LaI}>XCug]]a*RtũjEUDhUNy 87 %yǒlbM.K(hiOU4189!: C '&,Ȯp3CfG0kmAuЅAAᬮh xPjBRm 5m/hM ODDIjoC*jc3j!/o`d ݾ}jSg`Z;r0GHYҹR✁hdR2/GkO^AB')NMnQFL1 ScH!bSs&(dNmt3ytQJiY(RS} X) aZwk #  hAAx { R,T s[rӶ xlgP`]oR)Mn nAG\p- {̈Ԯߗq&hvW`C$aB EC+=4(1j}A)gr_$򾁐vFonpdߓJ~/j ~bDZ %Y`ku.ۆmO|YV!n'f#|y` 4  HryA/644V?yfC[' 4  X\J5PMparSFTD6sGAAAQrf:r#                                                                                                                                                                                                                                                   GA F 7n@ӡ-7bݡ{L&1B 9r} pQJ#BA…D%ܳ[  (AQFd5MS&M9g?u"p*\5u-~0L% \+CBBB@(0=Ak67xTQ(#0)p ~t,8k7w/A4+ QcBLgB)ÎAsxJ2%(A#- e%YNV-R2FNR{c)l]k?7 Y--_( FUPfeysB,΅)8%LSTQa*eLe*ҦK'®1aX\X˛KYQKUS ʨ1R֥L@ςSjQ\`Z?lbuEG^V+9T&Oqܒ"yer"V5ؓAvA`,0.mi%zYOh_WOZWVЄ%_KTUB>/pg;j y ʱ,ھmse}]ys>t5 u[zbEinUʨQ(,?e)Ǖ .-ۿHQTvW/_sf} 6X,KLK ir^w*La"4ʨN sx|)ǖ0 7-M &p£҆@'#dBr)\[~t |bl+6b|[O>{ |P  ȑZA0eXRaA]nwZx45U~\aqA㶸6<ݯo?;nکz} ) ߹75}o<XZk77uxQGӨ2x 㮹 R6Ft=U3νnw_y`3-jZ8fP[N= |a]{ѥ\kM:arKASc}Gc`#SxQnpXІ2(iyEG=^n_|]AA:\L  DYIKS5RpcLS7n45lksFӘtcfЏ uU>.G:Β>cFW; J%yzFV%_'YZ8J .M57]ۿZy߹?Eu]q95UWu:S:Suj;ܙg{SwŒIۘs'}actytTy7s >&<Jޅ}=G" NP@# G% lURUa9.)JKSˇZ!m3oi}[Pe[aHE0}`aq[Ea-(\vcIɐ"Ma@tHmUq\ξ_wa{~P4pL5E},w<3sƍ?ƇACo ,TSӨi*SW !  hAcxq*R<6g1ESA43^x\MJ[sF I_<ەL50cw%>S~]PP4hSP4Wt-XUvne%ipXgw^_s#N<;W̡i X5MחqW~?ACϹK4UqhjXUz@ZHލ  ! G>WXgnFS(+--e21%( !!srp29Fbv1NR !B&ߟy^h롎<&j]λBc[e{o>v;옉ݡ؈Qݲ0^jYB*/T? O_<$UY?%sVM?ғ`,`u=NkOPzYD8ϾsNٷe| wU4hDI:[a';O>xMX% U{{#p(\U[Vp쮮B;Ze (AU|cC\z6&8eR?ÑH0^(N, +T7hN-J""3Q"*;~zy]yCNnN9eҊC/1 =ջܻyӊ Qh; gV6vdy#F۶b+L`Ze1rI ;1MÜ/R{y}/ܶqǖ[\\CK.PDz7>~辟jN>yǐcK;MK.5qL(#0iΉ˲܏ߘ=G Mi%Ly̌d3VhA9LЅA9ۿ+۸SOS~AQ*qҍ[Qt)MbPpwC2 3QV6r쀇~ջGnj4_o-x$-=3r{R}[e+VRF[Fh~kb۹zPOPٰʠ>dX6 -Wڢ1 n޸*8^o1d9,_} JwKsCoTڤ)ɌjV|>gQ,unp8 Vjd**#]٥xXUi>dͪJZ-H+%$D)! |@ 4 r0jpW8pADj?0s?~|,+* ϚQi+CKAhpx0f vy}ε׎pevlL;A !zKӴIj… NL. WF4\p:l / 8SD=n0?-=U`kS5WSJ 2Fvl/E#.,r (*"\&,P8R]_nͲO+bTXQcp[k8лPSF9D)0Yg{5BkvLb Z \)1a>; AA hAЕښݻUU,/(96˘y?3~CkV_{G^#fP6mΜSJsN~t⧷m\8wOF"!b ŠDmmFM]ZE#M\ɩPS.Ā5^:#2AevCr{RZ9<֦4rQnQ'c9{+`c(^oZu[[a}R,vܲ= ҳ$~F g2!)' K¨P(LӰٔpn)A90(AÈ{V/]wb/yg\p'f~ՂϷVjQq͢c测vn]_p8%C3u1_=:ۂ-5/k/=IJ?$+&$z_y{CeIڳTƄE Wо} {/)H՗i$Tڃ$Hi VkH"fGjPSGi<Xl {BmR6t{(̾&һ՚ #0f=!zjӈuq<1_h%Ttw*-!\ƹ6`јbQ5f! HwFA F r/^fَ;XrssOHnkqc7n߲7x^ߢٚtܺa8ԩ'_tJQc4t,ˌ5;a]mt]-qC'9(۵rSAB>($8Y2 *:Z;ִϛۧO;vlPiMeӁ m>ޯ74Hi7sn !mre?]sA9(.E0dHg!`@朸L 1tēziS]=wλ[bSY*)-Ls| AARA9j PRT7o)_s)g~SϺN8ҜC>n˦e-5vS~PܺJ˛etH)6W뵧^ؾ&^0Bo& ;O ppz&O?;ݻo[bFn;?Нh(T,T(9qa0.@<aM rnBؙ`sͩef ޝgixWЯsW˗-s|U8hAA ĭ@i>'6Y9 cY8߈q\r;//U/ڼO:!#w]Pן|hOWBe /MR.d0-+r.;zQ(Bq\8TjYHdᜏ1i<0'|Vt{~cwA0‰efu{]J^:*'΅<`Tˆf0 y,陹&N~?9ptcM9}0kλ,+JllA$(A>P Loҫoq'70dFtA9P@# G %-g]{._O?3(6a "]̑#@C>lEP_q'ԝwW7^~E(eqfMĚʦZ?-aKkmnO{GO>4xarJGN:;QX}=ݽIJclV@474=;~k]]&N>qRMQ# ~@nA耲~)n ~inހ̱OܻbܰlfپeƲ1'L;f门/:wC&߸nټO>xm۷HȀ_x"-X'FUj Ag^_]_j-"1 '0(PaA1aTm޸>pɶ)M{V=[  {rh+^\X"`oOY4 s;ϼi/_UO}޹(()fC6 4 rTB0;q+4^v֨Sti GB!e3/zg훞ZrZvQ9>`đc1oO[ a)DmAz1(ͥTU3\o&`Tma=kV.Yҳ=/,187beEAa%,aQF|؉':ksaBlv\39DllxmB`ksڕ A`Q⪯wI <;WJ u A9*X]^3,J'`ׯM4 PV8fhZFN?UQ./[7oX~Vm^se>n=7xWs>xЇB)iHx&Ϧ _Ţ% xiJ,#Zp9VRP(lqTIG E# ȡA9j0-e))>}3wݰ䳏< E>fwͫ˫W߽nLvOeRk֯b̋?tmw.8K@a0$ͭ)ijqSFϼG7yn]?|,شHشaZ:s6MA 9##;gБc`ܴz?럕_a \!X€aP66nXi݆URVsYHZ&膊[Pڂ P6ᖙr! Ё~}A@+ rO,{ݫ䔳.gp[ܰLZnP|jR>~w{?Xlˡ`K]F,3.:O}CDCO 60T*szKst˖a6[1skզC0sN@UFUmrˍ^foK:dٳG~?87hܧS ҎQ%N`KF&JXxiFh4ikm rA`²^"*n-Cp3-a ðuA|܅ "A 4 r԰jMT޾f1]<1Y8A'Qi\xެHfv^в `=ذ|CU*o͔ϝ;S-(.V}w߿Wá5w[)C)|@4UQU ngLҝr}"A1_y$jW圂Kt8?BU~J)\'ۓh4[:9/ Q$a MѝLӌF`z B p۩ >0N-BelN9-h" >P@# G g^~izǟ_d˧q_q_|3~Zۓ>7>ݹu- JL9Z[j"Hzh0{g_zN<ϸ60"?N=f_*my%xxQ[cDW(}w{ٽ۶oD8&眯.o:,s0A ,ADTa+XD5+.ת(ŨprArƠ- g. ח|)e;H䕑M Tֶ_6x}_ Yhi=S%kn YJfA^w;! AA9j?˯o^/1y OxT _{{wmߵq-pA i #7pqÚeciY Wl\cm/Y8gԓ>{ʪ_xes?ztĘEћ[|vk2nYwXeSNݫJV[[Z-d 4"e)-;nNfWxvW٫-3Vc!E($Q-.~_y /LᇚYه2J>``Ao/s{jEcs̻LQʹ2%txqsMESJWZdP YA(+IsSY+[,SJUFP9!EQ Fd+Ae}NW@$j81KpAU{.Ì:iR ';=XP(,߰r3l"8aEQJ0O8b 5%3@y~&ɶeYf}믂cKe oS@]3EzfnV~Cu]mkK7 # 9kceBd(5?= S~ iC<(cfT+EKS] >y*#RQRU _nk㙸ˊmLU)44<#YhMpmBiNBq*\%q˯B8U.[Q4dT `cEB-aĈ;ӉJI>.^4d I?0hG CF ލߖՇeJzkNEB"3UUkO&L͞`-?L ȷ Q]wcQs\UKhT儋_~7^y^z.]t׆u+Y@½ЂH,{!,Dśz:!nPƛēϹ U3x9( M%S*Lƨ09ƘIˊ`q LD-,ԧd*H- ؠCk޵l6O;8B`C>OvhGVN>nϛm۸P_-745iigd-.Toߖ-;ȴa‚2fYCu_2sR&YXR6ؼiêՖţRCnVc{U}tn+sܔ'TI0uW6zDb%+k,De-hNasJEzFN1Sy~ KJjWpBnAA Հ-+vBt3@Cg1@ۧxw-e v}MZ)'!Y.=$Sw,Of%}߷oy\uԋ k)wO: p],P[eaOk-[M! [r{U SN;?ݰnʓf\rܸ'K;1WnZbQFIW Sg\rzfv+v=edɐS{.h |69l͊M u59X]n]'~)ؽkGGnKsAA4 rԓ` iܕ^Qc&c?p!e~ZXgpK4ءWm9Q Զ mNXaSp(deF (Թݞ=|8k,nshjO9 =2^<,Uf=Ep[A⣯;%CF꼜uO6m8/^k._+,&!8.]!#@w^.π>W׷abpDĴDwAdt;+  G5T07 CpJUry9&ZѺí0P) @/{62t1@Z1 uW~xA8b{/X0÷eX.wJ ϳ|y[`"bXa܌,ӰD-p_mٰͮʍk_y-Sb5ܭ977nX8ƯX'yYѵ FAX&"İi@F0!vl02bv^l+.)bMG殝HeIݓO@03V&L7`ϟ liYŢeRZL5ґ?,]2⊻~+=-+dV0)i[BF[Y2?46l0V[رbiZQnpn2L"ڨܸ=vl;}_b_W-i< $. ,+⢸&_P_dy헽~ H%=%$fQn:ؠ,*p8bwWo7ER0S!b)'2n[[tÅ7|{?;~y, Z'|7}GL+H bQN ܬU~x1hޭzkKS9^{? 6ZM,z=SҘB-hNjnq7SO9w<ݳx MnEnii;OA6l  HPP4d@pixՏfKXȼmXB ڴE~* ~L`&wMҡ6tU^ݳk%,Y4o"jp1-[WA92P@# ȗLqK2EeQvwNPhKF7C/6XxIԲc3@ Fp?{ό5=9WKKSß~{ۏޟ՛+ 8UFAj211BUPUY[f!PdCbrn ,&5)]G VF)UeD!*=uβmX\ ɽVm>;KU)[WFTv^NlJ&d-p3憪mGA 7 bdIDAT|Tlo&ܐ>gP{\KLgJ,V bIE-u4EF3-FUB3r׵ks缻4!?Zju-- LQILB̸P`70Adh!k*YS#K܌R2-=\Q;f^Z]Vw 3(^)aT9 eRAsQ8# = hA P#Сi^@zFijjmBv>:||q}(,oj$/l:ܐ?\ +2ۅ  _(A(j 55MwCih4|^8nj>dY*[z> y5(xA 0AAR\08DSCRl", AAAAP*P AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA䫂~ekBAA! LsQF2!0B9y#F)kM/^'۹sg1~"AA6+7;-;;+r=`Bp8jk Bmm`-+ni`AI)Tp{v Gx^!<4Oo>2ktiQ[WCUWو1.0SN;U f^{SSc}G#?mF*8UaᑍMWP4x֯])DZ)bdI%)STΌ3|?nOn]zazO677/ 5ͭK`Ҥ >p_`q 8׻w_CCcyzT|>?SO=M"yyyB+o n_(xw~o}-_>`}On hAAPVX# Y]D雟Gbظ5Gb1f|2,ˢhԨYSW666FQ' 4efRߜ~W)zk} y OӘ S~Z7 fE1]UfθGwݓsqhs߿ii'_ܱbg_p&upfi X J1E7f `3uq%3]w/|?xB2,OVVTT4Ϋ[X\_W۲kV5j:s] {_޽ /# >WvIhY_,/u9a„_~)wͿ%.޹D>vL[o_|#]  =KYI-)!75EJҝs9=GO>}aٳ{Y&(H٠4g9< )y?;y-|3Νy[Or.˲H45Cᰩ(L'8SYQr;wEc%(,*Qp:遀ƌ֖`$B X :XFc=])u u;.?Ypܩqﭿw b}| +;Ak:Kf_O8q ,<7mRQN9` Uz"NAnf3sƍ?^?-P]P8g;o u[z>AZZ }ƌ3o [7Wnh7>'|&Ѷ$)'d@d&r?%ǟtnIɐ銪±/Yfg2y0a„¿3fɩIt`s2>/?}{C&=U<ÓAg]f*KG"i.FeDPFd9P$78p:b/AeFQ$?h92\.]ap[4 H$L0J ny$ p&2]g~"=:#( StAR ?})#!XUY~0LQt>7Ps2 sf;*MUUUgBR4zF@J?v SfPfsUxNhpم2EaNHFz`V,5z%]q}]kNv̐9n]e2HtMQtMiiLuE3G2td F̔i؎n·~{رcO=x&}'fΜ93ϼPsܫ`?T(U<{Eَt 9> PPʓ, xbРndop˭]rKPBF JsɷhFz><&Ѳ,צi5v9DBAMUc4%]s\Gh4j`:\ݮ:MSuXT~=dDnCwE#vf=a|n>Sl 쿟yfr%S{ͭWgf.-=3{c',[2xJ\BTHv%לWP4dxve*w]4WyS6~Z0Nڳ{{m$B>7YiJ&bS )j*| ?uw5,v)g|˯Xt€kr m`D'@駞U/wVChfK@PY]rI'yJ9Y`>LƎ裏>WZZzArg꽭[n|W۷o:2f.c}D#a]sY~l |$,pWvRoA:uIjR{Ϡ_}k_RPCF>fi.e Xb>\;˂FF̲LSU]4=iD55u{h(*UYҗ0m[EUtx]Npն̂GaĽ\ޡkh82E ݧ_청B%䥧2k/[P4]qagWoMa#B4U%*sZ]tPn*d\Æ]-[|o|?AFpy|w]C-6-#+ c*7~*\R4US 2?/?(!maӂLސp(eqbpˊqB ~d uEr >z~>ix ]ֹmzFV1ƮZt:zO)0ttuUKwF6 .gNŤ)';ݺ,0IUtsFFF#@iiT466y7?s`x_SOnx#FMw`oN׍~Dq+qr/+Ns9G\8ѦݿAdtQ% o oS0I`e K p v i`o҃; J+#vďN ӝe)?kDҥrD!x+aFjNWxuIFc10cq9i~OnNFz/t4UƠ氒8 ˲LDkשtiN]w麮 N%ҍ*|>_ *9F6]Ih(+6X R7ZeToJB k X7Dvio}1ڤɌ,_2gA ;p8 f !\YbrT]4ڢYQXE-fH c1aQjI/`ɠTnijhZF#ֶų’K*Gt4AT}{?e>N:8S0.۪B+l`Aq/d4E趝eV|pa8222zzjs=Y!a[맟~a0lJo ,j]_4M ?0caqElBG pf5b&whHXRa',Q$)s !.A|~Lbd-:ڗWϢ,ܾ}f۟{xIJLoG!J34V9+%'m~q#I~~O:k#/a#]|8ř}8r-QpǸ}/Kd榞V !py m˩GO'zpֶh8Z1YJ@cB1UUyܲBCH[0 G,Y:):N;sDek2!єf~o$߹Ɔp8x]]>8oY+0p_5YT5eܹ2uGx>} Bd/͘L#ۻs74&RNc (&L&$-w_4R]_f[6)%ڎݍ_bF hV Z{;SYf99]4,(2yډ3N6cvlX{"Q.yCKGr{O_GVLG5T8nܸqݨQ2Tn@cclO<߾}{ukkk?ƅhfdpT?P8l1J|l$mXh]x'DƯZ].+\X퇿Λ0` E+09*an@c¨t3ENP1Q]۷l ҳgTr,{&$A <J9cPa+ K8$L,QJTݎPDD-A aڹ}P7IFf+מ!sizgx=CoiFוr͞;#e-uav<ڱǟ1iTC?֭xg=I"s'Nx(tꚦ9-G.ҋtXjz kN9-H)(8Ί< OR?Ny&:"!&AČ3 QJGW: bQ@ۺ8nQr fj^H%HDZRdqω=q,Op Ҝ-։d?/߿ɴfjϞt K+d=hoO&PhK ڇ }5!ir,yiUno=]i^(>Xp.a%Up]!:SHlfk[,)\1C@21# Rz8z .q<MXTm;>,)eQJ3Sy g)~v={uR'5%J~#kp]M"1 عssaR&,x^z2J*U-5.2sK; Cf)4Xrd9+q;rSaTؼ4R!zdἅBzO缷!-X4!O`}l0 d>fRc T* cE8匙2A~a۫3^lAy)vF<xzݹsg39ZZZ$92z&בgڷ(_aVXN4L3>ރpxtt[I?[U@# QA*m6)''Zkj;YsUޤAR&P(XD[;϶ Š"-f{#w4L4]W!:* +Ѳ} ܏y*p;Y#h[SsK 5!9,'1-F,F4MuM'KM Rp}-B玤E+9[rC] oͨT!N(qvm+h"A$BJC80exs#M~G0nsIw/eZK !] ?|rD(s;aLxeHgq XpZwOd4=eXr;v\ Ǜ-cH[,iZsz XRTt9}KƤ{wڶ7y.Lw.58۵bc!gy7oƼŋNz됲 H].hQBx<MRN5'ju{N~hln[h{\aۥSnraMˆAْ )*%d }o{bƛ؆}J],x܂"jXqI|Х=rsIC&h?dvFXN>sv<,d /A-Kg[nDV+C`,dIȜMxC `3p3.םy1JC%?JV(ϛD`('fu.=i}k=bY_%-ݐͨB8#Lp !7;jINe_ Aھa%i.'kfw4 V& ,lmny9}蜿[ٟ;w7pEZ1͘ )ǜwcCm]pp)m' q<Q |4>~E゙<_pk,n--M5z-()2.WծҲXޝ~wxȈ&} ƿtƥKC:Η.]s׮]]2ӧp„ /^a~?s;0b6lXAY~O$H$ptG8?ۿze]+t;. o!ގ9FGcu:bɡGC|8sHav9dϾ :H>VĬI7]xפ} ˬ%.F ,3s3UMcN~?9[w8SCQc=_ޟ]}3H1~ ݔC>mwO7K ؇!Fv)cQ ~k=p2 #֦v(ߑ;ߩgӝ*湱fK}K&O@/9˵jS]O%;di6Ycǎ=]Ӵm߾}nk/^ &Kw:]&jjj~s7D@(W/С/~zcUN'bsF6F;~<ڊt;&J.-WHOڼcIG]R nL~?v ]yk;/=G\?Bȣ//OO7vnLJd{*1ٗW?ηڎ'=ʀ-d.,#̬.hw״kaibBY=yӘ nɓJsW;Q>L+܉M,:ϓ cvlw5 wn!gR$$mQ"N8aOg Y[\qpHМ%lB帜b}!Lƶn t4y06֫p0EGcֶ4OUUs8v<ΩaZӴp{A7Z釯#Ԏ_=J6 %p9|q+{p߶p7zy>3 ;}㤤xK銧p8.Wwn:E}븝.G O ld1OW9tSϺh8 4ٱm˦rzM~e@Fʤa-Mu՟/xxm"L0`W ]|ivO<>~7);PdT3?<^{ϧqCܵyPIsz{l\]r!S$%Z/S_8P@M2jkRY-P[mSKmCKKkK ry^OzFzzVZZ/-qvL)iƖpuM]CCsK-L޹YYYit9ZRqb,q2 U_Q Xɗ-dXe  yzԲ]O"BWNd; n;xuwsUQcNi2fG7v1&R8$u;naA_X;۹]!MMm+>dŧxSc].Z}#|F֝>?빹^$Rӭ n[w%v_8$}H${j|4߃o~_qm}e-0-VS !Odgd~t:+ S7vmojª*@V̜@q;tw硶ׁϟhoE#/=7n8A}$ VvJ@АtmKsC㟗Zxٟ~ujwץjӫoc?)TWU\Yv?DF;2:BO!s9ae٢ٟY> G#Ɩ wZC9nkY2ͧ}z̥|6d=J )+LO?8q. ~֭3gμꫯskAe*L%~?'9_߄v{PIη{{Ͳ,5756[ZcPHw޽rA + DRnI057[[["PXq:@4u֓Ƙj=$+ vK?~+8U-+W8%F{(ʇq øUR h4O>xu֜}`+~pϖjt}RAUF!>!'#41 Q_yݪkv5?f _ iD# gͩ]U/+uu~xo}ѻn|??qh twK[+Rx=^")!y:}y~#)ۏK:??$j}m߭X98$eI`ksUB(qVW;wcٽr%RʨGWMR @@~ K4״N6c1㧟ۿ$Lso/{+.+߾/sC<*^zW>}(ց_ǝwQ#DǏ탰,!i%'ET߃g@_χx |J_<]g(%CR4C@֫4* ύ;&Ͽ8^R쿯Sޛ'+%dH(F4ie2ro7JzgM(;LPIɣlkLKq$B f_ߗF0 aD]{j>4g2.^(lvJ< .-KO<ςy 4ƍN:+Wi\E >^۱_M Z$H2K9;v nYĴ,{W}x !)֬X\pҌ 5"Q4 Jn_@Ve0k$#}ervmYK%)=KݫوEB[˗./6759.0,XFN햅h~X8I|MzN6;3l… ݻ6N{W6{y=H϶fE'~{'Nk8i'bh|á{p||ӮhEH6رûDz㶑}c=t>J6[oSOҩlLߪ98lJ)Id_r ,_伥5غkoͶֶp!QtUQxܲT紱j{HnHsSw^o KuMvn,[NH kWT:ۥfM_y+۵_|E4襢A# Y~͊r*3){\e3;7']Palڰr* x+BhʡvqF"{k-˄cK"5ZFZ"a‹Axly|m> iiNFeD8c* gyO?+{+@uK(Aee뮻ׯK-G<̀ // /AFi/,߮ w7pq=oy݊鼚>T ~|kq} Oj5apG:n]k[SHl Z"xKKzw=5{viol0[( c`҄ .͸% .{v5i EZ@\s]:HaKc8bEx`Jb04iޝj9/ӿ`m|eEiA6qk `ksK\v70iD7n$DZ\ȉ n bq!b",YBY\G,.% g}1/9lin#$!i㶏֔D"ָg}$ t3'ug vj 8M:e1.t:{L#Vm7_jfqy< fgS!L%陽|\~NF8z8Gopx?ׯJ[J7nzO',;ӲDk&מw|֛E£KN3o' ˪0őHkg-itqAvb̯ntNnw0`;/xw:/3Ӻ$?~w.חx-551`xkڗ?գN<ƸvsӒ^]ciSE'~~>kF>k5w%;Y=D~9y|<~I.-$Ygͯmہ{a||IFEvjqOaI' x-=q8v&M>K eZM{we|ii9H,3n;-a@ks[-nolړ3(r!tEQ1]bdp,B€[! g t77a7 B#;Wmٵw~uoL&H3dn(IwE]XD>є9aߋO+ngL,4p` [K`N8`5r3!pq˹ &חtrqV$@!2ܮ.*(uqW6jyE^PUI]KTžxhϮm{}nGÊH]Sκ SN?ٴa]n.?p)---u,ʉU۶mR]]]9lذ p EG݃;zVvW ʊǨ;~';NI6/_sGA/+ .W&p׭\ZPY^4aU>(k-'.sl J?fp٧Mı)F{!/E %e ~(umU!Pd]>ikDv>Aosnmw=&MoT/P rBU;;1\^CH&5# 79!ACy`Pްt1'ps*)vI"2+ sy UKz*JDQdqU~Ƅ(n֥3rsp2i^_@^<.m]JNJ(6 >0S;:TQB!L,(7n~gN7Me&_0heYpvLiyvܑ7-37?Gӝ;uv:]>ov_Zc5P0hǎkܽkW=iiiYI%܁;v~?O>p}) >+r6>͖DwX ;gfh[KwRϱ smM0)q_ָOp AM`둶I/aNKJfIz߻_ۧ7ߠh 0 Ild;&PdfѾ^ jM.:rT=i%d<A!ѦiZ*U(S, ]N KTp;&]9l,XC -&EQ3Bh4F=nܐÑmKJ.(9(#NJ1(BUF d6[JkVʔR 5J2ܖKv^VnӶ︿ ;締 U 3Mng1 łc)8-Jř9hyvb[#-ݫhɲ}8f/[3 ?#sí4x-9yy}N|/Ol,_Ň ƵK7FtMwr8n@ZzN^FV@zoHݴn֭0;ɖ.8qQ-М4A}~&(Y)b'g1Yמŝ6c񓹭oWkq6;+"\ 7cAvJ<хѾ?xUxhljgv]GWhTaOwc MKJεKgM9gN'&p<3IOIEqrZƆ3NH g cև™ӲGiN," $Mc5E G"MFl6 :eir #ff]aXVmn 65C 2o8[MQ nmZV4fb)zۿ ȡo:e+o}}Ȱu~?lyϿӏ^ ׿} %gXw Hӈ=w4J+31˶&P=^79C`9Wنgl- ZwKpnŠ4eĄݽsab2ӡľLp2ROB ko9n-XWO=󔓧= OU-V}6ؿ M;Un)2zu;>/Xl/97ׯY6}pӦ5;¡ ?2ܷ nzJ 9\@Fcbpj_m{]hĞ nZ\qZſ9UVAA ccvJx׺4b%ri (쥔t7Fx_B1K|=tN2Q7 [{|Z~?nK+\%t.W4X% 8ޗlzSCxDqi8;je)^ܹ!lV B[x99Kp&adVc̰\ Ee. Cn)rVmpKKk21,QUxܮh*m}볧UXFUU?QR#ıkұ>[QEP,+ca8^4tLЀ?.3b3Q@%F r{TFH8w#~oKKς >8T|O?u]JM1 3T j ʼn{لuܾ@F:e(% =fK9H$ !Y $XԴ֮Ykd3֯nղյ{ $>"j1Tߚ; ן>FϟtXb˗~9b&u֊Ti]<TUޛdaϔJCfeE#dE#ei<ĵ9]Nſ,1fs4DꊦYZAE rbjBv[i{EG[1qxmx/ߋ;,cɩduPDaJ*f_ֻsv\䖦en{@8ǭ PHIq*㪊pse縓F߃x0i¶R!iiƘiՑRxPXoy"Q&o`Yŭ; UPn 55`aX%v^P_rRAw8)|¨RT˛ A`[ Тt@QI c.BivKl!8\O WfȖM+VALJxck1L![S0Uy}z/xYjmijkj aR( f<,@{ ןr{UMsBtyn^˫ҦV`qWHhι/u:th)!㤗]e {<_+o]\-dj!LeEf<~l.*z EAtyNmwZM脩ZZe4LG!{7TD oӁ&gN$bv!,=I=qG~ coƃx<XSOc=F49s!CMOcccMEE 4ZDcVV)i礗 w"E[ZUEqx^vMp@YgC)YG14-iNLWkސ,S:#>ŷo\M..`pUnZr;FM<SckeoH'j =7waxNWbru ? ҪL#VNu{"jg\rffN^*v3嘒!#S{?_|Slr*ؚK*s{w@\9}rN>]t{v:P"o@1AaKG:-gӧN)# 94kv/\ J䂇91",|yu4tĨgs?xgeL67H0rx맷y{zzF~B<+/}'E63FOnx>^aG{1_<``$Ǜ}}I>;q͚m-o _K.ݹhѢ 04sx>lذ{ }W{b}DzI"  h5F"Ѱá:9aPyKZ:㲃(]4Cp,JbY0,À\QPo=_@iP(TSW_8`Ff,1ikkhX_}7'7ig^xegwZx s\ĠT(!}  v;mU-! ˂tp7'g f/Lp]I9qlXr֪%` s(K*7m}s˝K~w{Kiim\DcvHen 2hE=]w]wʸ+ׯo~vKՖmF̌#g`m=:N, 7555-Y=J;w( dOTTl CԲlb{kjسg-&_R~[oڿ?|*{9{o;HAAuO-p/^tw_չDu;ibŸN6O _JR&%_V|hɕ־njwmzs.$bLaPê_~qvUZ0%رP  ,…xީ\^u~qc&LMiY=j 6ZG CX ႬqjEf/oOz^?mX_x5,+b  RNzYU˷^2☉w'_x}Fᵛ[I~h8oh:~Ys.4d9-K EeBv&|# TmE͕{_{ٟ|Y?x٫W-uO>p΢ޔh7 ?Kɛo7vis {V|   >t]CNf3j1_'wƝxбf4.sj*U9TF]FҌ 3` cT۶Tܹu˼9~a͊ͦ%B7! ѾBaҫYSs.*}Ws,cGה7uض%E噓1X8h=dPiYn^_HŠU[>o^ 6[G uNeMJ>\Zwj 4E:I uNzM2=ջ}>K@n1PZ700ݥTQU1JQ9O;Ae9e۫*X2o޻^l k*{\<'8yY95Zry}ѹFzJʊ3`N.7KNɝ~H7nJlrXk+ݎK \JucϽQK~ØC+S;RRATP"mMA 9f[>4*cLQ(8B_;,, 6ZRCfݼ̈tS S(߇|`䴸̈́צ)u[z&i]AA$Ѹu^?=Q4:q>_pNU .f R/G |.\)\ZX ksgȰxۘ5, \B*uC5X%4 _eV[iVpRƈA`U8k6wTll҂4YѨPlh{J m\ hAAn;N]9E19#joj9"oĸUT2,/HoO Bt454YDRάQ- 8׆#+w  <4  $7CUl6f=kUG#[)xtcU*7cxcAA/}}H@&c9 r{ϕiBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[   |u wQBMEAjݟ2ٯra …IĆm-5ҢPQ@OqgpN%r[fMeamSJ/w9!XXu[A9FA!Lrl /]us>oe=tߣ(LUP&S AIJ,aY[뷴|aH~h #Ծ1 S59ܯ~lË.)LQRR0*z\SќsAM!BXUH^pW50BU? Z""N,4 nm} ȗAA38c֖U!K.^U{a;e .]t{R9$4+ nAK*Xܟ&h-UnX͙YFGiɍBH+ tJ[z uG6DXeO8BSQS5j{<؉Ǐp:]N٘ K~* "пBh9(,š"wTI[QP) %:eA&N>HKaV.Ywwu"9DK _d  hAA՜},X0z{?3X<_>hGu ?U9~49{˿?N=w-C[*7y㕧xߥٚ-_ڄBYQkCQhpn_JLvy<oRX#ݫ*Yb0KT1F]y}z_y-׎0^}S- 8xm͞eKy?e͊% 1C!1we>i.BOTPz}˧?> Er}- M5+}6f V(LˊtuEs* _  ȷkfgyԩӮwݙaD~2?zǞ|Z3~M9 Nz}pa}ϾKXPij1E^su7Y9y<k/wܱjҵk*{^5ա1)(T|xhiw-מw-'$h"ƹf04F4EƨkzՅ3OK;ر[Zgq]p Kchzx`~gpi! 9jtΝyшQcjlP[ۖެY>!^Xi8zWh$fYp8v`L:aԓ\e&9Bc1ï3fTqénTe0S)0g~O=]w؉̸Eޝ}[U 2O;Ktr"? h/,aAr{.Tg0MfnR PtLQT2MTTQ[EMa)s>JYjcHNh*4),/W`'w!ǜsSF0g,"b‡BoAAo%W /-Mgq[jj)hϖnOӄ'')+'Ow&9vq-7s9r=7]44fTF Fĸ2~څg݂X4Vaƺ@zvвuݑry}LvA˶]RE< N.(:Xɷnްy.S:rRKi7)N;u񼏗i*;}M#T]̣4T%F lF#D7 cU]q*:qNeq3F᳢P<£b鹽zwIeYf-]|KI!ϲr{wעz~]!b?}獒K5%X 2F5P6 ZuS!gx&lFb;uP(9~Bwa/>g6e^[fyuZe`?{מqBW ].Oɏ ?Oǟ<@"OˮT"Q&{>60ͽfs\G;ω&_9ջ7Μ;C9XFUť8^ߍ}SKqKxUuE7x)Ve2:5 h%s1N/ɮg{?|sA  ȷWxjK?oůi'LO5s@ w/pz33xG7VgpxJmjWtV6bL\{s~>Zlءm[7/ygߪ8mc z}@wmvZt4E sF%Ĺ|`kSKFfnVer(Wgl|poyQ`drˆ1fhNn_m{+ i&BcOԧ_aT0d-'K ,AKu񁪒FJHT~wpִeS=a?|Q ]1sqyYzPeܡn`.3OΤe.OiBrq"T9K׿Cn'k@Ȣq%t/yA${h Eѳ=.o90TCu]9Μ*~wƌX,++[tF yiݪ zh!G =%EA9Yzs蹧yիHK6)j>GL9/ޏ.,(,q誢 233U,oTa5Nm444/nM8y}wÅp4  !d;N]vC~p͵7}lrQb+8|Ee=^orwיJ''pHLMM*_[ΘwCrr2p ubuݴW>3-~Q7CRzW<^H)1%U=M7# J% #}Rp~)$QkڀF zN頟IIZj֮zeۣ}^Ȏa\ƒ ͘ToɛX`×plomF$1*Jt+~5(+(A-eBcRz}# ζR4FJѶ'Z,45Mr^as4 K//)rwu/Եrx,y] u{,ɹ%aKsg}0JL3'r|?]]3ʂ c:qksI)LMnW|O|%]qnyEtf"$|nҀތ+w-bPzx||nq쉾@  ؑCgZ[VZqe&Љ׸ܞ̬ܒIKϜ<~)Tp;b@ZzzJQqEYNnAϟ9C|<;V}`ê/qSeAU9xRVs߾?tN30!F 6[ۿn$$?04c-V%nr}]ZQ y͐sedgiIɛH Ia $C*wY#C7t 1Cĕ7P7\#~~DB@s9!sz Nfz_X@[~Iێ=0vSIJ347I.M;&VXLY3|^{}h5WztM[7]qcmqK^״nɛ?uĹYvfJNMW}ӎCwHBN5b@pn9 `̟]qYI -Vߙǥ-b*̢H7ɟ**yßvu](AA$xU]y9yl7}xmvX$p'*BKgۉ=ߕ[Pry|K&qǖ5/_-ą-AU)©m F*&'K*mSelŢJ\CW-rc%P1qQ)"Ͼ+sM*y wދ2AAK8].e֓ 'cSVubnn-. 2r2(]jA!9RPYwv)$ԠIJa|FyP"qtKE7tpL$ilj]G76~7_|U2$4A8KNlnfXILՐ.5"׵= UpӍ܄4  HJI=oCRߺ?^V1Z?9`wm\Ω3fƭD_eɾȮ-|Ìݮgd1:4lXܸ֯TȲSS*RP2"{Xǚ4 Վ:~%#oON^$??ۤŇ\%V_[qf1[sBDؘ;K3'LNM &75/X94Ӥ ~2ҫaIP2Od\ ӱ`ItEܷ~̢զpGNשfx4A}ޔRxNU˂AD3;9Caj3 /.,/vA [T7W6p.OJNUOu64P@iNjm[$6Qvv؜)0?c2$lbIX`%?s4LRiSܾo9R__XR+]yמ2  4+2=*QO5|>,8t^uծ7l>ha&1qVCvl>~!rnٶ9Z}[ΨKF"+úxzsҼ &qFܔ$)Hwޔ:sCӧ4Ye;Ål\{ŨriR2k.|yPK\Ȓ0tlb֩?Wp!Z{ 72n5qT:n/SK(klx[GOnmt> AEu͠^30XP'yvC_,YQ{[S\7 ѡ;!0X)Z;NB{91tt*tЂ1ܽ-z;fKAaԘ)INT{miIAlI;XEKnN쯰˸//P@# -@HwJ /o:TӲpu˶|bmkK]k ©>ulˤ3'z&ݵup8 Jrt!lO.Vv]p"P44B e,%M\-n=̹T ۽yTwGz;>4G5t.eC$ I->; :e8\jvɜCxU=eٔ! yde2zdQ˜mhC{֕pרpTƘk"\Z̤ZбIJzZO6u\*.55- a hAA'fJ2U+(&9߅d#g t 3rJ@;qrS7 ܣ')955?d妧ISH˪zNOJ b]h0 v1.7iT}{]>3z`:_RJcH/{ 68}\Jksַt|:8 zT 3gl&cNnQ`ZϨpMJp=sǩb'_0\sMEzFF~B`Oe摶ɞi.b.ͭT[0/3GwQS( J((Jm='>\ԫҭ{ !v՛djqb {~iP툪0b̼a{_PV0=k`YԌ?w;DOv@ڔ 8;eKytG__('>eʔ_Y}<<5F>:FA'd1.`qJ3 )5X / 0=UTΌh^Qj~? > ;AAk_F~l,޳q݊/=pep*N"Vձ jzff骡BqZHLcK&q,1M4iRK3PtQ^5\䥹tK<,QznO94gTc:VCʻ^ KE’1 Ng^ꡚtyvd3?56uj1I@=#Tu'{ߒ' 5wu%gg-b<&-j3?B@(3eg^ڒYwpsE>2\a  V *`*}O}֡ءLx4zz/mpZ0}ɢ߹%fa"m# sܾҒbBAA$-(A]2Y9{:NZ>4&*uJ@_k]7܂X,ko;es[a<%@i"j򸂺󁧞:yʷ^zRbƽKsǷkFL񇎝u4D-<iA_܍/(tf52@<=IcCpcۛc"}/ƻd! xHK[)>͞>/]ӷ}-7>3s 3@2L<%g$e!\;q~ }`/߹1ٛ:HDO cJ}$qX{7AA$!5@vZScO,`:gHRTJ(Cv|rsSy%%gteJ:bymibD%ফY wƣwϻvm[4c#&'r#x fKymƹkzǷ>;nx5M1z n䬿;11Gߘ@ud@_ϐ .'YV{ÜF :r$QFعm zQYWP/=䘩ųf:թ*Ve:tAdҳlHݷĭs^sK^ii*w[ۻ{*9/ʥpGPJ-,5q;o(*Hp'O/Z_W}W ZMrtbVfbNMJa”JtlͪOk住|q=ȅKW0h«gޱi;cT]iF]JqJ{[qz@_ia8SKI_wBr]x4悀'Ϲ;9cm\FA'G)i _{m<9nW\gO.Z?92#/6V6Dc0#tFJY ob3s 93;ew+{fViW'iƈmK13H8}4pgdPXP.!:^b= u6&L~xΠ7#wTG[)fPN` p)ʷX̌tY_ ? '^Udy MX7sQC7(Jz24h<̏Bd%$(dܖxΠ^SS$FpM9,@ NLiz]u<aq$C hAA.{*ϙ{neB:Q۫l\[sdюP,Uώ=phdukm,O4 Ó^0wUDc=mgNٜݸ)쭨?}Ƭ'1F])̖ںGΐkE#Q%JG 8vS9ei=C=*|6^4 i>J2r\XT1 U>J~C9ٖRpXxpFQx}%~k' wk l I.ʁ8{ڊ򅎜$999m޼k^=v">yBAZ᪨xX#Q:&>wG aG*tHЩA7ԥVG b&,kI=-ph,vd5AQw*ɝ^)Emx S%!Wʅɚ8466T}|H74  5g'%[dcC m4 5vny{md@)!$ܾiՎ.-*$5=kA%_xC&?g׷&8oq b듟 5쨩hAaRiٙx˪wJf{9pre D!6.$<_XCޞs]3 ƈAa1 IԴLpCb3AMiskXZtKJIZ0[B鱔FRRJqWۙS'j8>{eB\ٔ d ҈ȯKADrgqQDMamYpvtb0n 4\/BI–}Rsm۴Ou斴Ug·'N)%&mo{ \0O@J bV z|깆{ÊLv= aiFU7|$@  eͼ+,|mYig?$+'oRrrr wP7;`đ c:ڤʊj蹹s,醏'FEjj$xx0qT)840k evsCH8-\VB$QI0b1I\6IE#' N8)lђ`oOwrJZHvnaIK&$A> #\֬}Myv=='#>Sܖ܎rP2a$֙}.9׿ Rr}X&+!VD>#0u)i3"d{ә76@dԴbC,uݲww_2ڥA@kljӵkT8tAÐwIXiQ)MMM|@_FFA[ͽY|UiBUwmwnxS*3{Jnbv>;t11͈]o[M8ޚ?i6Cߟ3c;3 /67 Ca7'?+sn[_Ua׬W/(,QLF"pC}u KlB5MnF9tݳwϚiӦ-Jҙ*|j">*:aD s\otԀRζcElnKp) G 5.͟g~}ۛ;lbvV1+jo=v=<ʣ `FX3VV0ȍ>[91PmbZ1{GզvLxY ̂-,޻k?_^FAe>wM1Դa@O׉cGֿsl%4"T6|wfJ"Q|nUۉ<klj݃FË^OJ.;`Ҝrg0޴LcΔ^}}3OJ=Wf|{<#+wX tޱenXEW.SF+'7x8][F46>z0 . wR3}@;ORV:\(XRJZO|o=ց}͙l}IɩIÿ'!ص3C)D!=[6Op5$nz:֭~uSٴyS>/?[;);MU\=v xٲe{,yyE߾awh۵U;C{:cC49c N?" =/$j"6$Φ>'Z<}AidN<:w>һϽjGD% [mܳf5sn^5bʿ'f [Eԝ87~"mJ6IsfN]K tlݺyx 4  kmu"%%% ىq͓'ܶի^_u33c)NXS U)rbR\*Ams DyopĢ彁 ׼}w?BSՇ,8l$W09_?j}`PfCgF\'LnƆc{wm]>r':Z;3Tn5\7ْ:m۴zݖ=lXV҉~ö-[ }4]־iJͤISʢ֯\{m=\8dH ç>g:N(ټwQOo볟쁹s-==#gZ)c hX_Dۑp4w,l9l7T3pKFlS҄2y"iv}_}p-g!I#-?ni HL2ȵcw7zZGJ>m?y{?j D_{p,:c̩~RnllDކ+Wy, :N4ٰn_^U垓]Q¶ŝ/;ܲ/xesqω/#јuXv_;rpmOOW[U\?۵k[ՃzQǂK-ܸUޞKqδhZF6e\Hm9C,4*wmw"׬92G{r_)-%$-+l˖[ܸ6Yp*jam}{ߞMlKLMےqso7U–eK(dt׭}ݲ(ifL#!`jbyQHQ+dTWW?5##Z_8|zg4hXQMi󨴬[{_іў ߺ+7}<޺Ƃv;lCktAlyj"XNvΔ%`o=;V++ktA60G)e'R Y؟K\.:!WNSo Θ"0Okioin:zAL6׮Wr>)Uol|vd鋿*I.JZ#,/ON>w}{$k[\m`0M.Np(75 'ɥ^s#_=[7O_iQ! zF-yߋx0cϟG~e)y)k׬[裏55g/Dۑp${_{WmQy!0@p'=ʁl8nVm%I$}ƴom=U+K]O \ּڊӭ_㮻 Ck[wý_3wjW {/)x[Ai%V LJ2zc:>38BJ34WڦKWYC9|78$Uo~.}ݏ|bDwoP"0UNrqEGP{t-`j= p[/ H"-ˉa5͊p.Bi lǯ~]gDoz\ȈɅ}0X}ΤhN}ÌŢ7.{CAJrr/;Zgq ȟ5ﭫYn㘓[8ٙ{`ӟC}i~Ma2YsIbܖUG93}^SPaǤż4jno}o]0\-S?%\kirKFT? ."eQSz:Xux;mS7$fL""v8<~\s)YYڿuD@  ewuSFpns3Py32"`[Hp,g"`=;Ap'?yT{}]m׾M1.b0[_پ'liyqK#Ю  I" ˒X0X*[^ʞg qr΍A-.}x`Q\Giũ2HRLΣqa.k8,+$`0sS̝P0yR֓oܯ^O^\l!6Wb\nu|`RT/~о}='Mz:V|_?vYBDLkSO~ۄ{*z&T;D Hvș+ BZeSa+'T=P5Mʖ\FqZPZ BS+g-mHlSĸ9X̂q"QYUO  -nWV^9䯕mAA]Q3Dp+O3\j53کVUsS1%5Sƨl޺|WN(A=KBbHvoݱqm`;C .zGϙ7sS&~/,Xtuz+_U]i{ϟ4-M?Xw^ pAiC߳u/<|XɚvUBl?vv4@  rbZ@'>Q-jj$di (uQB;7ePh =ڪI8\ڜp.H`yfiOי;%997]1locX kiSR4j ijRNT; Uթ34FtF9cPxUPDJˡۆ|t Sp-)zƬ]iok@Y!լe%JL,Il)eKbuma\t yAAw*98էA i@+\B2PF-%e[pUEJjZbhޝ[-.#uaG~)0S{qgzTj_W`i puiҐꭊyU8R"ij|4K*ayB wJm!9[# hAAˀCiũnȴT䢲s;;Nضie HJGXؽӣq9U-TV?S6c:Gp(N!}TρAA2e<_aΙPmg&޵o߮`N{AA;UJЧ97>xXM)#4  rA}0 , '(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8_IENDB`PK!ηN22>res/gui/maps/icons/moe_calculator/previews/bar_ma_vertical.pngPNG  IHDR( IDATx|7{]"rrW C(CG )I@ioBHBB{577JV]YW͖li`vwvvFgΜs/c;@y8g\0c Eh1~[)8E7^NMt~N*Ťbjs0h@ y~2~ٌ1|4 #{}3؄ ̟? 'ptceV^|?>y z=\Iaa;*ǽT|G=دNDiJ*U>zLЏwc>'cιs SRd42&>ƤTEK$Ғ 642t2LP,3.)H 'xO~hiahWrʷퟏ?~ii.߿뮻~.9Oʔ)X,<=bgyf_wI>`s]hLNIaI8SJ+$cPИ`BدQ&lj Sŕ)-)#H@Xz|!(tGC> aRIT,SVcTaSYTvݚ˩t\P9wj;;5.\)$~)%XTi踬)x~8~'OuG{x~ PnҤI's=/Ϟ=뮻Σ9Yf;gμ/@ݻj#g/9dȐœ0M~ɧq@T8vxK>4'i:wQA%! b2!dʮzLpA9McNNsq׸NIEWN2TܲŤɨc2V: 26W^n.!nju+ҿ"S$]B:cN&v'.=e8#-in//߲>ܲaƈiU?9+ŔojBK)@3{w}gΜyF;Ivu;t5Q%ږ^SUU?? }3 :]YV1cF?W~u{%.s7N:7,9xϫвs?xDɘQ'3L4BO?1a2SR0_;Sw ͳ[3|gM1mSOgƝk,xɇnhEhP׬W%[R"mo ܜ{[3/'ta0֥i~˔ɥ]ݚrkzѹ\}_AF udNlٲ왇=⼒V(m &Sz>㝥KX7C@o`p'6Oh[p/| nWߟ^sWsD"eY1 O;K&*iU[Vvf?f8֟/n\,1*9rrFĉ'a(0Vwk~@\JRM ֲ^QtY3t)Οwi߽Һn{~Ci:5 ߺbڌ^xgp|`,]HA0>+hyE٣ob&¨97*B|}M|'ҶPnرC_}{~oL2%-ÞWˁ f8{^viCUUeeuuUDMx-5k֬_O3fvUl:s>S\\\}O<ăp8 l͠A\tEg,_oGH8nFcM8̳b'[lLJ?nocϯ>btM߽tI6bqH I}l=`@?|8q3,иOw13Rdds1d 8nΙsLhbqCno]6f[[v|٬Y3J8ge&yg0s]$ >] dN8;~eeHcs&sٱCh>}G8K:LD۞tɥicjjJ >suC=1պf'/3?ԺѪ-[n_pI62yt]w~<ϝw8B?ߺp8M61vDx,bHKMt7߻kǴmjbNGKʨbE\yk=h'.r'<[|n|s].u MЊ}ͭ7}g;Ls?چod\œ|fP,?pi_7dH2>NgcF'ⳕ">w"m9uߠ+u:v5r Lqݥq̓]>pC9KZ꫋_썘~{s0>vil:3 \2^J'Qg-cl)%%%c=oƻ1{2kv[ii3)-3m"re/ݽcK=\JjTsǫ, G-E|VP8ԅg4d̟t?\6h.!\g̜{zߠ#ڿJڂ=&%5@iN]n.fمi`]m|K/mG"K/;$x@μs9+>Z2d(uulukݺ5mzHS.ZH$ܰaúiӦٕ1k֬כp8ܸbŊ]==n[kŊzܻvl߹s'#Fx`2WL;~|{y#O?~k}Madf̘9~t}t|iN6;ƹוY />>kZ▨1Ϟqپœ{O? gpܴmG|c)HAztف/ F5ƅ89t]:ƏʈSV,謯0[w]4]#&MB׹RK<KiN>onJͩ-*m۶g?ON9Sh njlgmVa>h_,xc{t'M*Ӕ94M3Æ1suv1x`Ig_t SJ_Jԭ\}|'Vp<ŝYYg1.M5ŸCKsFj,nK_ЫzY)fEcዮ>ڡ9ĸҲS5E3x4ot7ާnkim4{\5]~eb\hi:g]poހU-58^{[J4/kL;GnMpL<=.#Zt,h_G˗xG߹}2bDDjX< :N1OT6}udϚ[6wפkenT? k?=p?~QEgM 1MӅC8(w`*w? Sr;_[VӰ?m|V7P8ޣh[3?t7XDd,@,sF4*+֭3j`J s!MpǨSG8=%H$}-RAmVomx]Oc'/ WvVkHuEeԺ5mRChN]hN.]G{ڿo?:S|seݔLjad]iу1c Jݧ[/>:rk__y{Z70%h( 7YGSXX=r'sIaqKZ{<Ģ =U 3rӞmSvh&t Ҙci#܎Y4dR*(%kZQ#}|vz\eciEⳊmumg`,\6hڵ%+ƚ'=|}rVi͟{ˉwy`0X񜜜|+7ӍZoG}N[q84k2<n0{|Gpp8lݿwֽ6U 6b3/r_0E?.*,^_P<*պeģ[;UP4([}=Ygyw=F ^e˖s芝9l= RgiGĹ 1~GskI#ᦆ{wlYO=/r[4k?ze~)Rq&,heݫ7ti;C4!Ό={vo}E]6Tw8=.Wm@ʮqѴCsÊFݾok=Cuݙ6>TEm)h-uW ƌsS[Jr9e|‚¿_xɡYt7cz.mqYm;_9RNt [M2.c;vT8i`}99ee+oVS&rrӶ@߾cd,L ENӘX\%VeIf,"_~?o 8p:=dK׺5uIs:ۺ%5ƨukjB7xu]qWkڡ.+Cʾkw$Ic&xdJmttm5yu3r vn]S.͘uI5x-oY޿wHSv#t5nIܷsU7UDLk7n;;.tܣ9){*(ϘPq d]W<,˛W:emLq5tʄlojTae|tzÍxbDMjOD|Ogg}Xc)ZG! %1"KcRL8oYr4E bM|66'+9g8p)s/b6=zX(_|٧Rg rݓxzDׅ5Z 0E8>bǨuˈ#h8-^\soTu=mC۞s9ߦ{RqEWhnpZ7 EW;YrɲuzOe&N[pyh(̾ (F@0st2JZq*bT،2TIWTODhΣ %YmFg~wYWP0hꀂAS;X"P ?eHK&3Oq/8P|kb2GG5ik}b^Ҿs6hqǔҢdrvnCYԨD{<2SfNZp\5 9swW*)>,b[>^Ň)U[JHtBk/`&RMrj^?pu oWt-y8qbw_755=_GhIUR"̾X^ވ=;7knP6{̹\S0uwCן}[7|3Q̲ nZ^[LV ^Uy(2`,i1+;/$E]Xeڊ[R+ǟ:sM9?{J*p9ga-:4%Oxh1r0>403ńZK}gTASG)mW&lFrv EANT,ɘ%e#?y{՝N.Fۮ{{ )L%cR54ݸ=R>Mn%NJuܳw^|c4WWZfmݲ+=hJF@7{衇noL-v{/M(Rt2^D,2 pڙrܡ$[큽[/y?k>~k&U4W. 4Џ4;<Ќ"N\ {HВY&'~k9tHdm?_<{͘lP)iwOgȎxLЊXzXgC0xDd-aKr W/MWKrٷ/_Oygyy)6Ow} ޳oXC-uZi&V~Iv+$:QF$Zxu2׬\A[d-\wu^p_k=7ٶmo|W^}nذae5ZGWޓHR`bx%$/,;c GyʡI6%}+~KK>8S'L*v.ݧGmtHe?㊶ԶЈT}?矾_7;h7wW/)ŬTX&ސX=yjkZO VⳚ.g3TXzuh̗tG%GgP\r7Ηa5ms0 yހ?[pΫļgHf^ !5U|RxZn #ܸw׶u;>[LT%g/ڢu+999E}ss<[zki]zS \n/>qN˗G#M׼r9N(+KCP3`\éQǼ=`۵nU(8NݓWBOr4& rݙ?8>mv-noyB..=u. (.EO,-YhOgvp&g,9o3䱔Xzuh){ 3X5&h/_Xp5eZDpļ^VSl3ч2i߃-[(h-{ޤT֔N;[e…ƍwB֭[駟*6,B߯Yt>h_}՛il^/JםΟמ_2lT;a#2siĢ7X+=iYUGt[CF@fKG!@RYOb.T5Fg؁\2HҙBg󹻾pϗkmSwsg]QëU)N2vy4,%'"I`ͽKYa,er$ڠ_H%#^gT w ~NdAR"~ە[6~^3ӧu58DhJT%gO~jݲg![LDE"u봴[ h&L02]5ٶm:*kPt֭kR*;;+=R!CG̞]q/O= =>on',x?{S?]n}`=+-O]i^w0>Ӹל5{k+w=?{3Ϝz^" 4hnu:xVfgr ~X|ZlNZ^xD /vXMkU(N 0E)/εY7ǓuM55ѧ%׳˟yg7ys?8wڃIk-3mbԺ/(r&OLuk&LF֭]lJL0zFQQQp~<G{Xhee^0w:a]yD =y(;3cWWZعuovΉN麐9t0Y h[{+:g$Ei.ktkO/}V>`aߓ>cE 5:w&PSsY^">K\8HO]0mb[Y|gc);ұuyC@Y֭xi|jjLlmqA!.W:f7yhᨴَ5oz=3&wqO_~wYQ攝4MhE2:xy;ق?k/lgN1lSfu>> DF.\66< u[qmŒ~#GFi鶮8`)UkIYkJUg*U{`gEU'oV]>[SqdeZi:fG 4{jAZ[^hH\zJ(= /Z= ci}U$2E*[N-ŢsKEeoR(a'a:XؐzRl>Pk[Fs8!C9S0o$ʒiTK/W;›y@'sO=Sf.8 ׺_4Z4ݥSǛ+,4q#Lײu^8f-nJmB-z{!(6ZMwwWm<6kYJ%7oX@]JîVXÕ%,eTs뎢JybǗMM+?]leI-mH*cvdK-"9M;<>3,CV7T)S-CF蕜kZS5)i!͍MTrA¾J+%R9Ϝ7`P2>;/O zչ.mo$W?HV-S;%ܗ,޴IL;7 iG㥜MDhMiv4IERDWO틧t{.:bOy<ޜ--[LðvtyNC[Y9CFu Me*F=F:)04nO\Әk|a9 r{ZogvJ)́r|Zhq}Q%%j٭vPI%gvxs|Zm2T1.$Iyh"kg4OmtU7+1/D|ƙz!#FϦוr܈ӫuh~#, dBZL]L MIe.UXK=FU{ㅦ 5ٝJn f7+ЁZ۝;xzZp;dBȃ[oۭ[kZKGOt>+>gp0Uc)molj F'dgAȞ}I" ,icF}jm JjNǥw ΅=ahuc%3@ct;hCiɐjZnou iu[_{EEE:hРsC?BP _7:&~vܹW^)\osrv jwؼ|͊%JFL>bJaxܴL!tf v:^zbML9/xWsƐh/օ}ܲnk4m34쯡6֭vR9)& s#7 ǁtqUQ|Dl9nZ':\̢ŵ;2%l8̅z8z0K{4%HAb$汵c'WJrq# eI:Ѧ颸XeĴC;+6mb(Ѻif:{TqX .ƌ+WP=c9#ǝhnpu h/J;&… /7o%Gw}kG0|lݚO>ܱck5uu^}`b#7@[~ 6EU-W?ݟh߉MfUGr73Mv!*)i5exMñ`8<>7d9e-Xڲ3L,MEb֊[b>LIvˆD|6nlG z">Ϟ9k^g iJh~%z=bEE&p8TXLMۍ2EJe44YMMâ^dѨq@U]ڲeS-5i-%즧6 n-I7 oxeu|\aYAVEG=?6[̺|BqپY2PQi0llX0>3pаo&ϊ ^3M mЯli FdvoysIHS)o,__믽˖-p }SUy$:h?hgi˒&Ʉ1o,1htmL^xcirźV6UɨT|V6}˥G{xD|vE31Zݫמ"%h6RYTGGOއ'Ν7uYwoڴ빇z,jq:kG?uVOWر]u듭~ u xWk)avM7EK/t… O3fLYQQUQQbŋY㭥jnMK%D[Cv~rg,>87FU$u#;o,4ݕ-;ɳH)vMT,"Ugq󧖍nOzXD;&SI)mcZ!j*7)Fj(XP/{=?2ndFb~qUa J[0ᄑ#G),0.պТuKԺEtV-FJu%Ծ74ctkhKN5G}MՇyϿWUX)PqӤNfp8uU;ow}7Q't)>ۼ|_lXaUcc+).`̌J4ks%b63ô24+~xх||1hWoW,eEmjjn^xwTU/ߺe[=>xFj݊*xܢaʊnjh0 V>mj2M*ѺGn6VG>mq7D%R,C JLΈZaeR!-3U~]/o>/6;h|ko=V,{'$̈u47[kϿ̻/<">_n'K^q۹=fߗY>]PSƹ;9P,.eCĒu1i hbBsqr w"EΟ?yF(/ȦS}`}[dMز"(;:>fjݪܿ'vKut|n][n|òec9x)Jn={X$_+-_ 7)Y1`DeAӐq{RΙL4wnwxDO{&.>lg<_gk].eM<,댠4,V6tDٙ]0mrOhh٘D|Fq$38V0~D~SpCpƹ.(Ŕ%2MLIQU" 5.4M0!Gܥsk$EYRјḔ5WJ:u57p׺M5sjNt+=Mmx">S\%ZsRD\5piup1PybTԊ˨Wa#&fLdLU塞DB|=%c}\6F}JFaW){J!L c>ݧd64MQ s1eSd찍+Љ}t6H )OwMz((H:i:M%"4F5"YoICYҴ³,YUB ca,=>h8c~7ΉfD:YLpd&zRaHWi_Bh ZVj}RƏ@VRR{gN3gnڵk׎7|ŋo8Vs饗\pɁ@ 'XSSSᄏ_\~z_9r&cL$o%u֏.[q@1ids)=c\)8g\%26L136DqCېh#rw'O>Yug[)d]]]>ןܽ{wCw%%%9wyEmm k_{EoZ|ζ[paE^t/\pE^h)i_$2Z-;999]}-%^15Yݖz<\ܽkڛyRe)kmlTt;4BhnΕϜx}DXX8ld{獏MM˔5[*֭?50bRJfdıP Կ+;'|gukQXn2;x{+x">6/ )~͆Ua7PsOO4i܂}&:m|n  /?% 6-y'3̞_pļr}&fN cE[¶->9!wдqN1>?p9e/>l+/<ן:sqFgHOn᦮2҉ݧ~Ƅ ڜ HP ͛?ʱTVV|R[֭ݻwoTGaݺu]=t-cꪫNݟni+W\hѢ׶.F믺]I-[EnѢEZhn/ZE/+qM8Y3'>aV٬3&M0~diAEEE^7kN3+yC̚5sysO7gfΘ1a1Cxz %[w/@oc-J|GoDB (iڏ/;wcs &:dٞrOT07]{ۺt@74pؼ)sdϙR5ojAK.ܻ[m[69qR&Ϛ8abIYs M-*~nWŶ-]=rWgP6*;XpnBhݪK{֙d۫:jڵkUK[PQ>FNDzS%5uKO>o&oHA7yz0L{Ewy1 h<7xEMMMi]zu^?ffH7o gyc{*$٫H;s>ګܵW]3f͜iS&:dm9ن1 2A| C#~|FJ-_YL;aD]:.'0kB~wqEQBj?sW俨E1F6=n-vz9{q)4Y$X$ahԩ,˧ %w"X4E"QY[[nhE#a]㣕p7_5(8Z: 3мb\]vM +;4 tpl ']vW.ttBG]6&۫ ͡;˾¢䏫x+]0]]N&nvt$̢DZNTwp͡kNMc ?/qroq!K%nrrst7Su)>غ5v=Fw}~>x)ӟtIk/y'tg׏Xj'1aYjժ֭xĉlOGydygwon޼Sgk`7{ͽ;j**,uιnI)p$GH<  L k^^.ӭaP) ˣp8f d1Y2%4[>bŊmp1N+q+1c ΗH=J|'?i?M65'nx<ݽT,P(34 5)(HmR_#0iF>rNWFMhu-^#c=/D;@o  ʘ,]{ߡkƆ>zEO~є>bD!S(&4cSxuA v2gY'Yi5.7?pdN9-/5qY!( cvشwnxȒ*bIi2MKYR)iJe(K<$1!8S1j4\̚O~WhQJwZ㦟{Y'krU`k9nvVVciYQSWJh42'ԺՕ>֭`SY,Nnes-F[555ںh$JJn]8J)2駟>677=G{ݻuaퟂYf;\e/")=}]B%RIFceu]>;''_\34'+Kp !d[2Ѥ0LX4!.#r:r.G]ӎ)SIICHA&A| Q#Y4ݹefCcn%YH)Q6mX/E:TE<:MI6G-8lX_۰u㪵UaYMq܂!CG ֘ДPk;P4 l;p@YBlښL̤Q*G5δ!Fi縷m^U9 sÜ?=@&7p&&r3Dg̣[}Zк[yɐ쳯*t"GKz8+ā2gcvvv@jPiGM>E=/~ŋo9Y-0 R*b3=~'/# KaOFq qPR8%NHDaKDvߗaXhdKV8V!>ز+=4Rqa05;8ePHS^%1E(F(&qR]{7(/oV)eZB*RҞ3R*(kJRw@G=$WBZD Ř)4?f _OAiC]u}ܒiJLŘݙ>_~AQە$nN!ueйnw8ts}tz+u+E6'y8R[Nt-"b ]قdnt:i˗|TiZr$[K%%%}mg;E˾8@g49uGvGU٦(UØ(fB^P(^@*vR"cf́}yi\ʣtTNӲF)5c R@8l\K>XG1jըT0 <{6qKFM}㶧 d|E(,i1-i)+r>uu=tkqD[fCZ֭x<knAϡTS0o6mJ;qy4 S2u3ży.Xp}]j;h)Fp..WvG&S.]PT78y8j(h0 EgxX5 p ]NX<^Wy:9mj-U>+D#!>vbltT!פdTJptڿ/^j?7׷lIHX$˵}ˑJȵw%QƹL&ej艣ν _޲iZsG4.L0 }z.2ʹm3>`&BMbq C1KN P핒R(ttgzn;/~Vanܰ#΅j#(6zvU[rd;mC} RhA.mi:|j6/O2(-wzĘecZ'豓~'wY f{`Ej4e[;Tc}M]L)7~.3MQOB'ܞ@:c1{,UXzr<ϔs]Ten֭C_-8ڝl-//yX'/o+a{nرc:CZJ=̘1cO^E%[sO) FbњƸѥ`)f1#od詵 [SqEraյjj5u;SD.1]v>gh^yp8V}ӆ_ϋ+v&;UMbuPD%[8AvK O =]LԝegIBJ9ÂϹ}V ^DCNTQ)Ew%ǃe]v2KqUc)H:u'uOĒcu ŌX뢢n}}_ZniwvuKWMuVk[Ņri'TMBWwD-:֭ܬ@!|f纜Ng Lq[xgV.M7t?O8n|w_$[ƍbK˗mPoj>䄳XdȐA~áNMT7͐)e5(PX8h@Ђ"ukdkudZ@|v|!>L1IJ :V)ak[~w4?O:#NڏO$[u41㚝YjhzM)8uQZik&Luipq(ТyW5GsQXԏ BNN>[f̞nָ`u>u\^MS?0uQZ}|w޽{/[w}OoEgv;ymnIGպDeVSD[vV dJvo֭Yzժu+ / H(w[Z'p}Wx҂1cƌ:/C|Q|?@mmvIU2/+zEJ;>t\*cNQ!\pŧ3c&LFk)=rܔ떭B3[^к[yyyc/׿n;bka&uYd)//3ۆBp[n뽚T+7ͺ`) .wV gyyyg{p8BUBH,.B55 p$J+'gd s> GC_2 3gh8Bv!gkt'v'2ۿ(F7ѴkOYy:]֦c%iT&5F)Ѳ7y!-?Z;m5uAC;\jDWnY!֒yYn7u7NQ~2oټ(B\W`8]2uBL9EhfAV?k✣u z{u}9ߟ;ydJ}5s|&L Ʀ`mS0|6D'{@Q~Ni ~˲TS0o 54ѿ꺆h8u좂<*i^W gh_IZf6ufk?٫nKr!/;avjwB6,Eqś!9D, oXRU^pָ϶K+0dL|jsnyW&cebxK-s-)^zw?4/``QO{کSf̝iC=^^~%# !ys '9:9]-%Ͼ\}vq7cvBɮ޼nEI2qPSc}<{@va\ǁV谘*(uuvNrDHj u խҼxHenuHZRDzi]}쑫K>/+㺮;Z$0 '%$1;h<^XWU]3 y. s@ϗt8j)FkTRJӊFc=*^K[AUl_WiƎ*D<&aOvWJGɛ|3M˪ohjؽbVohay sGҊ=;w GcAt:۝r9]30oϺZ8"3etO\gb *"cJg*g^p8E1a`ZڸlT۞ߞ?ZT۹;ud67xj}vQ5+Li' K2C*eRbJb:XfEDzrs#D!ՠ%nqs]{)&CRxڸ|4jCM::׭OF"Q=Su:un546uغJVu ;//opbfee3xӦMi+xuꩧȑ#'LfUU[oVXѼt޷o߶V$߮On6rp%)aTg@^n aYR1-nBQb{nP@m쬬hJY,/g4zߣsu:RFjug=Ojq.)ݦP:&ϣ(Wj*wI`ޫ1mC$cz~1[H]b*3Ep4#%8;h4+~``Jc`kkiRv.`gM(KnȪj縩.X26D~t,,b=J%򀉱4^j&{r5,Su:u+s[߷ۺe[p״5̙3?sgϦ]|3'N8'ݶh4e˖ͭ袋fo[hѢe-Z;-O޳KZ) /cQ_q+((8޸qǭo4@3gU<ٳOuzH$,//_u,R29 ۨ2͊Dc`1( +ƣ:Nq:uq9f#pCS!mj* )^3]1+$c.y@pӘpQ.ΩmR-=ɸdRIꪫ#pU,JJ 5ퟝQAFMM _7lj3VK,,Lǟ7jB1Fci]}cîU;cic}C)纨hк[uN[-&"G5 tڵkׄF_s ~?tWSO=¢m^n}׷~t~{磌: .袯K+VX6k֬9v%uV ϴ~|'O>5|_W~p8|֭[W~gv;+qwVs<_q 9ɸa,)e$k0LA*FAKhrtRRqäxnSvX,.Mˌ5C MX‘pѴ,F,HYgGZoZA5j#].w12sk\t!S.S|$e@)PL%%kPBEHȞƟ dSScac(9Pm oJc/:,>&aĂ&ř~/ .n CdC]=vlYc9r=/]=LmMU!4ZшҶzძm?P(5Gs~%uGk=3ræ!u)0TpqEwaCڊ7kjq$E:L&M=qD릝75X͔~g7tḱ{ rsGo*w=WRR2ck׮].aEn֬YǞ={6u]K=˟O&lڵo7{긻J% @c*eԴdaZ5X>7CBm^Aj~Ԓf$ 546U#JxH x].]mlzL<&e$gDb`Ce*xL~s,r91o1#mG+o[$2 =Ƿ?Wdno %֬Yso[.^o?_nɒ%~w,_< )([`?Ͽ|WpH{ G{ݓiF+&19pXV͡psҒK7?8C#7XtkqMsvnl9!>C|ptT?WuISOLMa?s4 sٻbnθ'79 1{k}}{}RIٓk_{ɷN=s~nuC9{tkQm,d/?%qZmԒ,KϚU~]vN^W\O d.~ҷ׬YNIeLHvמ|/|΂9^_yŦD[0<.O-QQNQ+(WU4%L9En5jFNNNUuְa&ݭ[_|vڵ]&JVOwd|핑i68"vl۴'XL*fRQgtzm[6-_r\RYbr\нwK=곎TWM+f163_}r93NXp},˃d4)TwK=!m5\{Twiʰa]BXvzZXsd-mF5e)4 .]샒Qӟ^f/H7z;08D㩠؈ TWטOnb5X,Hp,{i_y /C|>ghhϦM #sE^ov]m3JlTooߺ]I\*ΕUY6}ܼCV،b՟~1nJiO/iYا1nݴ?~p/ qXAJ[*zwXfZ*Bs)Ncc,Tooy_v%ٶb۶mݰU*j(iHɤH5k`Mo(q۽[rÔ[B(X483Y[F]H,V̠iJBoݺ|ǯK{UUU;oQ+T[iGӺp3}_SS{/W\q9>짝iݺ뮻nhbrjzAҙDXOwW[Z&Zd3֭Ʀ`u,gBD-uV˯EV;"W~G @:C f95kɶLWFƦ`eՁ*6n޲e[7nڼZnEx}}}hϞ7mޱjMkוo)_~}4p3*dX2?qo WHṮBcw_8U4e&η,fY&nCYY[SU}H [-.eX^LZ| /}߼+xDp{B/{~{WM3fFWF47m/n:C^zᛮ䚥~ܐ;,#&e,nY2q3L+7tWӏuoW-+zKCDTAF{͕h)9~,'2\5+uW/~/K˪_|;KIIInO@Dֱ8$ICڗ4rsr e -[7oٺռW P\X2xм¸azƍ߰'~&5kV?jiic=^xI[9ےIGbrv{3b^ vQO!>C|p爬C.s㆞|ڹ'7iʐa#FiPRɽ{vؿO;oxﬕE,bʒfSV@4Є}k8Ng}ڋߐR5T{ȅ)cr|9& 8i9 N3dQtHZUvZ寽UTJ&T1̲\U;t1&[q‚3O8ĢJ7T55}JXTJ}[3,)V<2ǣ\84;]=wn#8O,P8e/+{TҔEGdkr.܃HƒeNN?';'+uhCPeW\񃖭[vWΣj %ےvn^=~MEԺUu@Muuu}$5Z>>Afgem`JT@0}ܯ~W~U{gyg{UG-q92 6ϥ#og^ǝjG|pƖ<&;|wp5%L,j$㌖I7-_i)Ӵzc|K='$J:i!g_|M˶Cq Rה8&8\PGyHQhyL ^L{1:*&nkH;?9MMӸ1FI7ڧX!o`\IFBI*Se*e~WooJm\+]9s0b Ph4/jUI|[c=.3oh4nw&b68Z|mn>1VԺe ÚV['. #ni_i=PV<7`xjTSŔEcfS0->o8 !KVF%hIj;XO@ i?;*Ҁj4EsiDȑ8Vv[#jBxTW[3j=uݶ~':\)!4ZQ2,y0dҰnk}l?_ 1{);H79,,e6wkI#(h'Uf'ݞ`Ka_ȕ=5SVչGlqwgvKƗ*ţip8B㔐sx4f6s]$֭A oZjq[AK&OnS''aٺZ%9eOJ`AS(u &5y,]HD rU5'P};ꂝaYrŅE||Æ>^bT2^Lull7%o8Օvzvde["]T"9'Ξ\ye{$ڠYnGt|NnڃPa{I.ZWn@wk]lj=nj  >=M*&wW8i|LiEdGz֣KGX"9[sh[[-ZJ18@/ZjZp&:gҖEE}*hкл >82nVtV,Ŷ2 ?}>;Et~zx@[0;Ӎ v :tOo99xPmvw|lRZ˕RZ?~[Fu >XW1Oߴʒ<=nM=a[!C Cu zeַ[rCZ+;+Rbѭ=y3E@׵ m}ZzgGw`Lp3ŦfPq]gܲ+=ʦi~6ɸ R0u@2f)"$3{ 6 kJNܪ}n > >LD~<F5w粢s]ϗ'rjLt&dE 6I)[yD@HfN.;vRc@Ǧ₆OBORMI '%mƹnrQ>g\2.8s%<a ]ndmZ?"()&(/Qf\Q.i{8e쬚JF~c"GMsk<@UI&%0.DZ[m# :ڇާbBrc=bGŞy][]J^ڕwV3Mk'C 1T"U8c=Iò6;Ŧ[TFwPܲ4ŘiW$$2ڱxIM@>QnMrtM> hz梶CzHu&Qϩm2xvqy: ڶjh/b^θQ+ ^>TzQݛ4]Gݢ/%S<]mD%]O@E@@@ cӴTuA96eqO>?ɔT,p/1,/۴TnEXAE@,k'@B|>JltJ}t_2a)ɕhu6KH~mz^ .%  7:D`lt$2D5w>@w$@z:XrT8UGi*DK&Kes]aK=:;z~D*IhI8"&_K &bSJY\iPz0j-JXJ7{I.z jQFtsϵ"GeGŞy]ٞ3>rltvsbI+-YF4JKtɷ$*fE\j1zG%dR{퉟 ֺ݅w_ >hJ\II5nHQeb&cotS穀n>Zğ`+z8$EE@nu>@wj:@=^亣?ʥLҏN%%=PoKT-L3l6 -8^J^ڕwV鹃Em\Oϒ[rfR$W#ovhb7ʳ-F,26׳jcӆD@@@ m3k$PY1ʡvIZ)E=)FݥMKt qKu)Ӑh^4y~=밳5g*u=3xnD@(-8>Z:G$W.H-T]FwW.QǺ୏^J1DM.KU6*)!HQIMP;y@Hƙd*(ŎEh1u4LKݳ{GiO %W%$xrT\!h֬ mI^ #p&E"'W];Uk>Zܨ͒8D(ueGŞy]ٞ3>}t^mF]K5*ԭy68 p4$J6{qP*SKfȎ`6[f|lT(']ɖZ G sR(W&T|f5?ڲ]Q%$EhhOB Cعg^g4x[]J^ڕwVU<3DnkܮJάT:JLr9֓hkG+zBjT}x t.ʃ%kغ\skdέ%5-}x,- QjGzЖɱ#>MOz՛=s Cu wA|жQhԒa_:ox}DEM>P!5+g!>-ykuhEZck8{$2D5 N$C|pt8cc)GhI.QkoN.l@HLUl-!GeGŞy]ٞ3>r.֧=: a[ @|RTdX}b7 .837"!кKKΊ==w03+sYD@-{H@|1pɻ2E Ctu@г2Zg!!Ju m1:s@|p|F]W_%v e}m"p1:sR$2 zI^oYMhh].Qו헬xO⸾;tjͲv>,go,E CZx'XA|R$_?=sQQg^W猽2*2D5 @|RTdTkVgt6@|R$2Zx):xiWYA|px|e.Ch,!>c)mKooj|_|k}3?=ސhк/1R1NG 뮘Qו헬xOXuJjZ 6nD@&w>,go,m"՚eGŞy]ٞ3>}68*,8nhj}$ S!!v3ݳW:nrDh,݅wɨyS-V`}}\m"՚;yM{K1@F9.w:>kZHdnR:lҮlbO @/bl{oz񕹬A C=$G6"!TV}o3>k+Jm peB CE9Rsct>@&k1aC-Jb^(zuϨKVĎ'$਴Nut \ЀwmO@ XtkDoj+ԵQxtjͲv>t/KwSNqo34θí{ܹ.*2D5w>@wٱsϼvzZ<{ >dTEZ4 ;֢ʭμ5/W{>yD9a[>=.N-2d"z@lQ"2}mp:*</͠6Y$Pv-ob?!!vTוѺݥt]~g|XFڳZIN+W>6 pIbǎd*jL,n-9:PS,-ƭ)8FNuh*+Z vt cZb-a5jGx@rb\y:Z}XoYMhh8]F 20C x:Tnb^TJJs]>+/Y;h֬5ӎ@g\D]Fm eݨ@-0J$΅$=jX;E CN@OB= .H-E<6{TLjhH@ ~z݄[Gw an&msJBbJw .Nh5I=HQQg^W猽2ŝLhT㺛9D{hb#jda4b2oTCQA CZ:{`h`xף;4ӥ`MӦ{ AhoN%DM1Ҕ Ce)Y& cHdKGג Oyt'ӄKhv N5͑%ɬL;,mR1nj^i24L)OifYkCH@ع.m[p+spluH\=Bpj '0A%Ҷtˑ*W5RM3ir4iŹiH@+sYD@eI|xqk4><(GhKeQ\JNRJ5(,%,eHK_?@Y߂D@moj|_z^и8cy_l}Y @]s@x{!!Ju Z;ÚLu]~Ɋt]w>@&P>,JEAEg>(Ǐߐ<;^gah14Bki)(J)ZRcRbZfF `LxHw='-˲%Œ%}ޭKr{{RtUgVӕt-i@Wk"?Pdפ+^&RbrՆYs C$$ͣ}lhzI^ͣ{4Ѡ5 k D 4+1:jumRr%CqT+CNwe).Ө~̣ccQ{ku]24O^hx=W׽5p#uI6<@SyV4%M}vQYmI]y:QCQM ItٿMd,{Lo͐$GYss.F{AXT@+65hlbPJ$Ffa`ky5k7t(kM3JyyҥR"hD 7;k&G23KGI@J#1g4o7*EX;N" YqҌXZgl纬hl*͒#@]yVz%M}6g)V? 4GoAc G uIlĦ{@"4QĎ֭RK㚾[g-z#:̈~n\f-d{q@NE ]{*ϊnCT %9<HkrM,ŲKemkIqB VHpcmL}61Eo e,r-b-"&DX NSP _&FN3 t @{G䛦b͹y|yau o_\tHJB_@wo^!f 8 (S*> (qΕFsi7t kAbf% 7 >T6WKu};"=fDK$@X %huXF tȮ=g[ٷz) BV4Aq3d5u@ҬHrr=_ C@ۚAlGv:3sj_4kXDp-bň"f}8#xZ0I"I5au{3F3qH Fۑ?^(j.+-yD`,XSPFP,!@ZRkb:։ 7mM4e|@ vflM꟔ﬕ,kj_xVWk4rVό3eshu}A(8խg?!VY%B ns'zb^t8knNJ"-sdhƊqmY)f= w0ld_WLsl n-8d7 3$O7[wnnn+rznn6nܸ8κ[rY?zoܰn"`DYV)C7tMאM;,գKU%+tk%] }#Ayg+4s5?[|wd9(>3fx;vX]Sbı3TUQ.I9+UUQd*)GUkDUl$OCEDgH,9sv}s(oZpπ1nxv\t?fHt0cy$(333;wo޶V"{e9soaRŬ}*6%ՌM.E=zsȡ*4b%.rla($kd4z4c7U}>1\4`Q9Qí$%333RtU3&L{:bݹcۖ+y6V >otwիXp=å.KIWe9Cv_|8gڰv&"+~w׎7b]0T]oRHzxN-SUURܪj&eEN1j찳Ϲxc67);n)MVoUeN3U2Q7] qTdUQo̺ҫ}"u%XAQQ@("Qx=5/>_g_2+D͌9E\W.ۗq/~joAxO} " Z滉Tf-n}HE-gnef? K }f͚Ì 9s;_|m9ӧO.$Er-?|JC<N'$E|ϕW^yۼyޝ?~It6Q\H1(.dSܪ).ʊv).ER=}5rjZ\ɦ*Y,tu(^M7&Y9Q+V_fSi[݀h5#>#>u].%;lμ9dѡ⽓'qetn\f'WK#;HpE+-T5#+;;;ŗcvv=7zo̚ʽ;>ϏɺQ(zCI=zZ7ST(r*ɊJ+u7f}(j8ݥWU WŊ"׺ ѫIQnl(i'O:cɓ4pI⦈^Fykht}bv˗1;ߕMɴ99fVdv(m)&j ϗXRkZF-:nٻtK,uET%W]lʳڝ)&$Y-$!Ccǎ~饗;1bw;ϭ0`^{˗/#r饗^/V]4>HNNNo~ߍ?>?q&MyM7fϞ}KϞ=zݯ/ݻwѣUW]u}:tZp̟H3kbyeeeI4q\_qVvļ(*E16G&{9v+dD誢{.(ٶ׼({d=-=C1m|NɇIq"VUsD>9㳒9- "l.]upߣ(kI2>k4qgۥUlǞ>m?ÇhT_qɒV'|,F.fɄ5V蹮dDΜK5SO헹@S99B߾jF˹53ߨvR7υ4NgX5sRŢtKnh!YULBNsn)t%V^E6O$&V-)vn#5wp'لw}~ޑ2eݻ u_yy[l#A8,Y?81oM}5 .͋vDrosKq"cKb=R{B|s39ipXe1^|u7G "gN?ť*iFw<ٗMl$pw|s)gFddw+gݘݵKO͝\-Mu)\pgNhl=Ӧ_tex-gJ˥iuGK[T4H)}-R7R*ўyT E+:SK͋D V \ˢZ7񠦯lo*hQm^E+"@SJ* 6|蠕<~ b_~!PG=XYYr *oСCG-466o۶mC׎;vj[۷ӧxwZ_>|P-V]vUЕU\p77!+yJJoKKKE0nnw.:l9{'_u%WTˋ>XZicqXf?LpNdI5EDo6ќg~λ솋N+ =5--7 nG[ZS%B6,63HKKsmMU4M~8AgNR>،9QVyXءٙb]6ACC=,}gg0tWtu[TNz ._hJC4! W\UigX/SqVn]g9CnU0j/ז,|QVN,iadwׯɸPp k>Z+b܉u޳U옕ݽY\|ɛyMI=+Er2? ǎԔnXcG<^l`HC^b]gb!t&anq*jdE/6`K*aHv.P̂pdM̥tWzF/:ԓO6#Rc%g-vm,{C-^n_\iXYjkk:vd^SSSxZ,ٞ4iжuԐ!CFuV3xzl}oW??WW+Nio?5E٥q&QUY3$I349m\qG XͿ3˗.z[$rNv~znqRޔq[7Ud#~rC2\$[k뿋nO4èjzcx={4xͻPjyٳWNo.I5E+YjSC$̕ќjͪasa;s :jÿcH[Nм[Kx%mP lf։jVY>zTVpN,2ҭk{pnD֭e]Jd(٫>^je,W.,-sKkҭ%ͬ-7SL8Ȋ+YACFyѵLrcOonOQU32}ҹx[7ⳏޝ?~xc2ҋG ٥G3s{{8&5u];zꯏ^}z746)==3j,!гy|efvD3xH g  gB__wxOK%Y9ȲXYaǫPpM٫O?EbTŶVKv9iYYB8۹mU;wJȑ|+{7t=$Ҩ'OPT)]!sLޣ,]kDz՛+_|ygjQr'l߼f,Kd {NV;HU:ZYj Ci#&=e++t.'}ڸn?'{4u_\k2RUQ9n(#{͸'L9㼱&^NK+/˟M;s x/I6_o6k ?i֔d=W"VCwjz5'o)n#@]KxV~λ4tuGO;uqE1wܹ)xn?OCb3fXA*C555GC5MNk'M>43~Ջ-*ٷo_.l_?Wl(oξK׬bƌ|O?Uo^]owŮgN213|m{s'yaZzfxu;r?/OlR_K њͱmoҤIqzzZ"Ѧv隙aovaHYYY?&O:ujWM q[fMBvD!>k|z3@lPdh7EcG~Q:]Vt3οboKY5Dh,,˲i7cz<-R!bSkz-mB}&L<3wOVK5!u}΍[E Xɲk{Ir[Ks0xi!{$P$Mqedv ٗxMݎ-k+%y塆W$dC$dm#'䦛]9dgsw'Lʿ₋?>s6WTs.|.ݻ_pӾvِa-kU+W'r^mbAKw._3wi ͷraԦnWk1 PeҭNtK223#(ݪ9"x|eٗ1FBmmѲs#D~]?i^*iWXr=cw̙36YLsO3<_O&!VW;Kϸd֘L\ξ[Oy]oy/}44(S/8?K쯾ڙ#k,<[7ylIÇi%==]fKUYr#uSU]rIKg2 uW>Pgh!K젮Qd)<Z xLȊ^QubԉC?yisiޤW?+٧w|QiuU6333UѣGf;O:צ)u\?>eyFuQ^ڕeVM}i1|@9/~뵀rMwY6żQt [ ĖJ&흱v <">9H^+ڲePiV0ӳg"vwX ['z{>]s5}D{fU{6+}WV߻}?.7xG YS7:rp?fh RGUf#F g\e6 vK]ޭQ6>V;nDXb.V"1$ d_I1C8|ДS9lDusEfs]>4q\#?m5 ѩZOY!4wG8@-(ݲքiV@b,%vj,I.eHm\sMu]Ve۷o /ߎ޽{w4?~p4vAC iuLQO(E ɌPe_~ʼn$^%"YB3߿FͱuSmg_z͜_|{;fw3 +WcOwҥ۞][vWQGu ǼbɪBUT(tD&HŠX=wv=eHu%fآKK,tpϸ0UO4x͖Mku ߗi.w߀Nje@Ur裷q'5s"ˬZhN׌5 {[+J/ ~L$-K֨͸gϜ٪֫ ߿ZlS VxW6H)oək.//gs0fgOs]ػZs3tGo'ꑡ+bETdUڠ!#N;{Y~QU,buleDl$K0uCVؿTŗ3WƆG%I%헾feuhwg+~ 4ࡣ.Sq8[f}YYwǯtIF\=R*pȡ% >^{]{ֹ|N2+=uk?|=qbo9Z\*a%پ~-׈j"kFz$.׍Uckn)KQe7k6XDΚnxnUE-F(Jҭ/*ڴ%ҭn@lJ3N˿\,vPS?0PH%{ִiӮjO=XViiÇׯ߈;7tk={s_0Ѥ{UR zC=tϪU֊맯Ə~ 9s˗o}[k6eewK:|Ԁ SOOW.[{S_ܫϠѢFiM[O=q'+>ؽs˾cǼ"o/O+x5zy (@TZYVeaS nSt$Eܒ,e^]p F yx?Z{l^Ǽ(.mH=d_kUUn=zH^h\![W+ey3^_lh_Tصum%&[u΅W~~.WT)&&!Kl^h {O䒶mZXY-{;6<|7DU0VM턱=3m*| sIxn^MjzdG7v8xK2Y>&Jan{9ߔ&1JRtXԥ[n/h5~-dGՃ!d-K.dܹsl̑#GzGlE,^oٲe~雗]vwB/vks'҄cB,۶m+}嗛vc=vء-mݺu5h qBUMlu[&b E=ycz洼IJ]CӾvUڋO,ZWb񍓧{i32y<˶zs-wӆ;=oA"" vt״ >8[֛/Y]%@ͶN'N*Rd9s/vyW^֪/*Wa4hkm?>bfy/Ł}&}iR!Kꀁ#zEHnٷ^,%"ho}NN*(SMKK,ӫY^x]ҕ&BK5KsOWs ^}/rϢ=5tyU}C}cGx4۔M ㌈l'`@fC, uU/Jҭ>;?33so۟׷cS%[G{4o-tum饋[MZK1(eggw{5p`띀W^yOsRSμa& _/z_~#{ٵ7#N4dبޙ]b&_'vvzQ7Eٯ { >83&푩ʲ˥J]d[ݢ~jV,VhѨkkz^X?'ƍ?eggW C9r>?JߙNMڼk%IjjjU",  :w?^[s!D]i]DDr3ݙ-붯xc뻶tE,p׮ JB=ѳWuu 7ɏ-_ݚXئƚ_tYm3+>x r).եeE;ft?sκ!FZӫOSϘ~~X)' iN҇ 5 NoO?\/ [7e= n.-YϫKWgזcjsZ*i>}!G"nN閘ʧHJ^x$.m|*#Rw݋ﵵXq]QQq .3gμfΜ_YN3ak>w wFnP=zڷoEu՗7޼kGOv{s}% tװQ' ;m̹zoٚ]Y1z?Uխ\.\.T,wL;܈w[_,V`~U}Mh5cqpT:U| r)Kݪ"e1i]~7Jh=]g^H^Tݐ4]]}rg+|v_ݺvψi~o'gsb%eI Y][>ե4 j*ֵkvv߾+"_M_y&u6c'2̓'vq=tW^Ŀóͥ\;ᄅg_-s;Q3VqJMtҭ3<ʞ={F>[={ooMʪ(:%_Q5vIzMngD}# ko̮ժn[{wmZ΅,2\քS^Ç}^bQ9ʏH=3gw=<ޣGVW'|(x㍊7xjk|Ygڽ{}}R楗^# իo+8pRDȑGq.9yg03Xw_ӿkͱ/g:FӼmw-_>?|1㧜NkrWyYeibj^&V%w.n[IKKTQ@9nͳUo |{śVƆw<AMtci',:g:cgۥY]{;GէP2_{g^5Ϋ"_&rx~n^he/;ӺufD4iwf0 5}ĉW,_ߗխG_CN$u8_Ćs.Х tS/=u3Oޣ[7lܰvy7oX0,Vlʔ)ݼ^o؎Lh(ڡۛktر:koTzERp͚5bCh|Ig@.QUUzO wHo޴h_ֽq:k&x< ڜɚn xdȈO;ti{^=v|ӆaa֢4]]a4o <ތb4|[2k6p˒UCKDfNu!`D.]G!;, :}ߓz10dQ b.u38wwVn\Z_0?MIn\Oa$F$JOQ^D t+K&wNtMynQ寋o(=U5'߶?EӦ]뺵 I/3f̸!ϫE())yoDJ!{ƪA_n/0k?'++nM啜=?{/Nrٹ3/ozWYⲪ]_!G͛sf\ve[=z훷{u\ͦmOha5 ]u,yE9zӺu"9>z\ޤ uu+~\b_=崙Nrx3DT3zhhI-U7tYQsTCo6/-_Yiv**dI%m)v|fArK9&zY^zGHϥ}kў..CG4t3o]ٮZsL{*ӿuKuɪ+m0$,?e5C79̳ɒxQrQlȆ5]~_U*M34,t]-F-Jn9t럿kюnibَt|X>) |4==c50$hK憆y衇n-((Q[}֭[;MJCϞ={r=o߾єnxQǤ?Qzj3= 9f꘱ySNKM:x={;s5{y2kjV^v[7_k2lL܉S3׮7xuY-7oxI}A\\yG;|aې/~L<r# 5>Uٔ$DMK|ΐ7{rə6ٷGYݻzlccC,|fcRH2lk> fk;夜.&il4Ȳa|U}b,K銪M:#?v).Y2>35D7ټvlܮ\fH!ˢ :_107JPe_ŗEH7d]t%oL]ļ^MWY=zQq͛owntš>zq)g~չ3k/2]ќ~VgqR1Ѽx]3[+l>xbMk\bYzG#oEdO~d#* {5\q(u"p!*og!JQI֩7lXQ-uzٷ7|g۷QEEE~U cݻF 555GDKǻ}J9rdZZZq-ȑ#-^vmgz?s]^zx)ihh8uֈʫ,o']p?)zOutx9*hdF499T΃_ϬⱦD[(jFVҭ[({CنRE;AK~y?՗z{-[D_.ݳg^J>wM7M_Fvvvyg?[6rȓC^uu M6UڵkmǏ"vbѣGOh?}́_0` &֪z׮]}kJ;vaN u555P{+KqYLK LGwV3Y]9eYCf}_+|ХFCey'<=2/3%֓aK6 }YiS/ ]4I+X}ӵA d[GѳO̮!c2$I{EfȌ UdĢ5OKt"3ė̈́^[|fohiӆ?#{k?ܼ)3[z_TKW:(FmJz0|ǎ͛oݿs.!}~r#\_d_?.Cn"Mk87[pWVnѦՅM6_f lIx !JZtu閻ҭ%)VF{*w0nLJܽS$'|_$Ix .\=v?xѣOzeeꋗ/_D4,'T[l1w >3Ə9rB /'ڄS5ל/&Ɨ\rI/ uGbݺu-m^ܲqƝ1vء[l_| UUU;z)+fY@2 &B@åHyUEn[M5z1'P4//B[Vy3/ڶھi?<5G̕fRͳI0GF[=N#Sd,늹*:2dɭ˺j^uͩrHfeeR+tȶddCʌQ˕ӫ__E݊"5.MI?%Guh!ފ4머̩ɒץH^շ2ORU3a$٦D$̾bƎ;yt^}FM &rڴr&cѧ7g=f7iշ_mJ 3Is[nKO:yI}MM 73 fy 4d'4[}-_JM{.4%|zqK-nQ~Vi{[%ߌKV04˷8)ZeJFFF{Aq*+++nf|x^}?ay/1˾9p坟~˖-kяlƍ[kkk7=z?,Zف~ֵkV=ID'%P;OꗩK,Z躬ddvqgfU U3t׬]Gː`37l$`Umf*vmG*ķZo^%H'ݺ>ϸ7tg?m۫*ڠ.BUTP4YtU\+38:'\fȪ,he?H &\x[U ^=ëipf.NG17 9;-\xmm?jGtMdV.vSV4Q*E CJ7`+Ua9zL,=5P.vE_[]["e(^CWX<%mRF>z={wQl[<㼋>g#Xڔ.Eq19OuѦ$#kHڔ-/q/~LJٻkZiνر/-y#DX̬%Wq!2zӹ+mq՛F&bh -n)A[yE,tK옧Jb_떥[^M[~wZ]p~+h'tlQ6ڤwYͥM v뭷=k֬;ĕPI-|dѢE!EEE<3ٳ>p:K/- /?ӧO77> $.)N> qk﹫ `udP1r̰O`gl6s9o+m/:}NSU3,f_%E "ID90>> > QZO|;F7{?VSsgx'%Dbƒ!+XK&Zz ,Bmʸ*D=܋tǐ$o4oVC""*/`<.]ZU8;7lnr).] :56ɲh(fަqm32Tե 2j]b #\n+fW1F16 C٫O:n;PsY#BE2\O>C'b[֯4^VdX/mP/ N M=̋}f;!ks'6)q=Vs-&y5Vj^\:ACF|>ESN=̞ ؃_|wzuͻaш'nW\51q\ %+M[UUM%X++鹮ȶkItW77A| |̋N֢3|C7 *C Bz_SDǣᚾED[xnQa.%be l-16f̘>ׯ_UvzQCࡇ* -[n-WQQb`{?oEx~m='|gРAw?sfffCill/**ͽI2t/vQnޤvl=|@\668bQ<쿖䈯$>@|F|F|(ђ_d5iiiߜsUSwNYu8YR҆3kV aέa *CڻgG2+[m v%Ve^y\߻V cG}{^C3H7FM=:fj36y|LUJy"VM|m tɫcwH)TlXǛ͕MVY:)Hu.JtK%CIҭ`ֲHH bYzsi;\'||ڃ>s9bǏ?ꫯ>ӟ} ͛U>뮻~;z2UgϞ'xG}p{}~9S.j 7~駟^!u}:[MRv櫌6N?^!qMiYц$@|,vϐ|. $"y Qv=A zsXo;d}vmߺq̀CF_sܮu XlN ?mݚO>|g%$K]dS e/;S wsM(;z%KۨI57DW?[O: 18ּɧO˃~z5!wS=V ,~%s]iuR`)ƌZ@>`kZ762+.?>Z.m-J&8n_q R ջ\Y8b./[cmA|JV@2ٺnniaxbԾ$I6CG nSc|EbR$^MkKcv==ʳ۳cS;n٦IzW3}/dC=5YT>=/١6/EӼwwW?FRtEpɒجw9{Ѫ\[ZXٗ8K6%F197#SgΉfW M}6Z|XFʕ+JQ!Xeufޚzd4&"i) gɅ ʫ^Ð\+IrؾSo[k?H2$57:bw`K/ެKWHDu~wϵ7|^Qkxtӊj6~u^<ܱG߇{\{}ׇս߿c=^oChlh4{ءQӍO7oiOW;nBn֍k}?ǫ4jZ]:%&z'˹Tcyn}DGA]Xtw˼Urk֮vbZp0`ݻwWp ED@ţtҭNҭT5sÐ.lotړ+;W^+x׮]~#C5k[G ~h}^[[BYRgo[^<z9mܰn.UNWU%CU4_MQdUm3c3Q5C<$-bM=~>ٻO >߻ޟ̻eOz5n֯jg]UUq)撕̾1sOʛ2yQc325MvܺiO+y :]7t}ݶ#-ο')~(UT˪.FF>r'M50nk+Y|&iRWѫ^QrnۑX.$H,?g͘:aS\nrlh-oxe۷nڣzחͳ) VIDAT%n KeKאU\}牵,ٷ[%$WV;Q-v*VjߠaHh^M2l=QnaVF{*pH9r>}dC4K>fM4Ž)EY͘8ǎmH !(ep2&߷;iӆfM 23m]5]$6D/C4YtUCw 6jP׬lsc'˶-?+ݬXt֪-kO#í}ǟ/OQbYT! 1%H膙ꚡz$dm$ք=25UUURG}JePa_]az5+JE2''&ťȚJ _,ʒ^$C;սvmlt*5D_oIvw?o}㔦6%)yכXΙcmm$-_R|@HXp|z co.%03f}>b*ɾ8mZ3|j'tm:(RdY6 E""G&,Wu9[ӪR]Cw/m)Qm^X8~IdaENRⲔKI)J$̽ _s̚,龪QC,~3D j8 hgpcp >p\J HQ$+[fV7i oӼdmbmYMjvophRm@ReY6sGI I@fM6f٬o$ɨܯ̛!4mV 1'7j{2 ?tER)H)JQdť(b(%bd QSK[(ɆK]l%JS + R.%tEV݊ dYRUmL/KS!HAe ~Xrc@ϥ\)*MV]iV$YQ$CN,mAٶ@jQIP$h&NUuꚹ.Ղ ^H)F$ܲ"]J[V3TsA,g*rl65mHjnuz9* #Suy0$eH^MrM잝1tH-(*N-x!euMUեjLw)]D6E䮒̦ɊXզbArp&G6ze+Wuh'wR6MO R BJ#R.%*tUQ3Օ(tUq+jVEd*KR*gbSQ3jv7ObnV I(^Y1o{\=;A5VӖYO?hR@EU35-CU22\.wUTEUv( ȫYrR51Z+ɆQ^^MHH5zKTY$?.3wvAT[-@)YXAi=tⲔKII.7;K(JÅNtUTE@I&Y-ڤ~S n3]7iatãIFf ?馟jc8vx\PIEd)hKtEvJ_2;O3Q*z ]ketH3FH0#ܙds+6 Re%MV\٨.+X6u1H~VZ+ 71'7 yG5(]*%R@d#NLIVYV\ H-!LH G8D 9_mL%$ha.IaHZ翶^UR.GtC24]ҽa4__xmq X:E):t઀pc@ϥhؖzkI6z'k _@jvŊ6 yt]ot*ʯ5tELSԌ4EVSUIVERw$乵,C*[ݫk4C?ՍFa7Z}y:gZX hܦںY6TUw ;MUdU1 HNakg ׭l9ztM7$*{uӠ uӵM1$ .j¢;H"% +rBcH_\ܙds+6 l8v67;J0MctTeUdeIEM3Ͽj꒬{4iMV9?.#Ɗ5τS-&F3Vm@ ]3=YuRMWeY%C 7|68'$m@(X&lD[$)5nnV|oVLm4?ł5*pc@ϥ$ڀ%b!bQ94*fҭiEPK[=N؃.I:U:/G8\J HQ"Ŧ4'ے 6'_FM-\'fMQm^X#,:h~qYJͥ$ڀ%钤KD2֔s n HXT&KDDrL̅iěij?f&|hdRm@2 oXvē-4/~iy)fɍ:~)j^A~TsҥR"hRȒz67lOfH$Z1`W$ڀ%FͺOlnpԈ Ig=M . )>'7W]|i7sՈ?Bִ̏Bk1+2"R.eEUm d[`ݷ?h4ec[ɇ F<[vPb|Yrc@ϥ$ڀfI{#w<5߄ m@ kѣ- >b&\>D`Z!'s V.j¢żdaETe)5hRY4)u麶$ pcp >p\J Haśrnrpb 8n NAΛKI)yQn-Wj@J1'7:~)j^A~TsҥR") }u1ϸ_g༹DŒUeUh>8)r uRmQ/h8\mvEtLSDR.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc988o.eE`ViVc$m iRmM,*_O; - ` , >_\Rs)6&,xg༹D`f]z{3Pz1.6&fMɋtkIeUÊq)fɍ*>+/@w}~TsҥR"(+m@ hTE|ΛK؄UbeAQqJm 7hd 0$@$j} aH6hv3a rh1Pei=DmⲔ:%؅bNh@+zcX1N18EG<?%8|.`5#S$59/ҭ%U;H3FV@yQͥ+JJ$Č(͊f ">ͥ$J"S,g༹DpT =@,(*-X؆UeD8XSRV6af Vঽ%`Sg༹D`S !TՖEw0DJV@/.KD`ɒ8o.%Dԣ 7hlb伨JTV`8G#18Ō9Qg;HQ KW.IID 7D$Y/3p\J6&,91ʂgsڝ\Dys)61r~.H T?YD Es} i삨\/,Z$R :h~qYJͥ$, @VoHL}༹D`eH$Z188o.%ĬyQn-@1'7w +ȏj.]QTJ$% fDi11 7hl*͒#S,g༹DpT =@,(*N-xaE`ViVc|{{ԫ%ٖ-ɶ,{t0`z  $@ $SI@HfSܱq]MVtug*w*l dޖyf~C: A !|l)f!ȷpiV{#to r΀ wϖb A%in!p+;rW:s r!&~{7ʖb A%cA|AAFAAo+hCAAAANmm[cA wϖF|Kf1 HgoZ#-?CR ! rZc  |m` AAGAA !ȷ7no5F˜v ƹWv˯A_Ѵ1AƺhCo u"xATZ8m=F? N`8օu3 [D[˻9hi;#|W{? b A%\3C[;~6AA!oRk ͸!K#_'k]; fu1  rfA AgK1І ¥Y} ]u~A!|l)AN9?  98Gq F  ŋAAllz?ә`F|Kfv>F,hA+ ݳhCo , 87Di: wAeo/k!lietdݧ "ȷ7m-An\շ C,~ig ɿ^hCo  rn Hge6 !ȷ,BA9@ AG]hb g>ꆁ6pn{AS[X=A+L!C٦K pB,y "dzەC:dK1>$wf ̓hm=FAApN uf7llr@    tk@|K,AA3 g #" S_`KEe5[B41 Hg+oǷj\A wAډ8Ap!Oɖoe56 ! rR2   a-yfhR># m 6mMb:   7cp3P4ohҳӆ6m_6 ƹWv˯u6AbK;?CifD,R'm)?K|{A,} ]3Aٲ'[!7&l|F6Be5Z0 I ц p EXA+ >@vm)沱tAqn{8aAA3;mzm 7RS ]9Cs&? g(Ao",  ș3AbfV[U:tt\ƍ:` A%Kh;#t8D g Cfոz:8mܩT.+lsg ! rZ@AA9UdPlh`fuB2&`ٍu&f /\GAAp΅XHMVLpJrJ ;YrM ghCo | Yt: wAdAP1fdfZ| U²`г`F|JA8> Hd?C3a3E-5s]3.=[` A%in!p+;rW:s r!(dQH?;4C YmrY앍X: t AA3ASh 0LN- dѳU6 `F|K0őAA&-'Ci<lP*:>֕ѹpQN9` A%\3C[;~6AɄ s &ސ!l˥gncAl[=i/RrUC:dK?Y9*SڄزeX:  i|   рfkSmlۅm    9"k2)O uA0YaF|Kho1  rfA A@- 2ghCo Ҭ>F,&Mܛ -A AphdK7Ce AAAAs!m!SP5mR,e0І    p$3~k,e AX ߷3  ]3Aӣk;1)% VD!ECqf l@EK-'ghCAAAA!64#dIMKÏ?/>DAAmr\NBk9tu9B)37N"G8K0oJG! "Ys! BӰpBB A8QB k.뤡=CCo: cƌկ_nΝ;8pw=zܾI&6tСZQQQ~ v:vC /BBBlq0 ._T~iChf3t]|{; ]}՗O<. Vd0ݼy۞3bƏ7uQκ^={sYY+Wo=D3MJtLA)Zd&F(MP[R!? Qs{r_L獈zq՗^zm={%>Xd~g,YR؞eO6ɓ'LN@ 9zچ x1bUI]3Wmt2t_{-O:Gq1599i3t9]?v*ɽvRFU0f1^N '%yS)L%m)OJ0C]N^tw fa׫3vf˜_USpHt:RaTX(4ﰅK1X B1|If» qEt1bk]gr6c Gi@0|&ٱiB&0pn`MP8"JrJ8> rpW-{N͉应pb ; ͅضYFp?o-@7naL(,LjZUJ5ʘF QBaAA:~11A.q+\N`CfaԪQ)Z %j,pT: !n@̌4K'C[SШbgTX!18ܸ nΟ6Y[,7`p7?i!nQPipTUeLS)0¾f! .t#(/`` \4kVԩS3᰽|]kt ;>#Olpt3gfΜyK/|🵵g,'᭷jkSL2]kzn喉>?333{g\y͞={wycXG5|pE>l = %7H=z7m~lއTm9z%Ã0r$3'qƏ0̬nUME6|%\zN}ޚ+7Ԝʎ@3Mr/]2UMR)V MaTғ\7. :AAgPd|)*S+(jQ,MшEQ)%  KA >$ݠÜ-8[r 3\4 I.4)W(#*QTY4ˆFf̚aCįyЅ 9 ȥF0YSLۧw˗ZKLѻۡRCME&]00''{ahO?7 al:9N;* #3H-u&z)0N߱?r@_X;N`SL%Y, Ɂ*ej `aKansbSoä$HNe~9܅ˉ1OE׹qJۛ+/۵zM8[2%hv4ͮъ2%##ԥK =.ھzǎˍ}ynhd[2쌺ga,Fa5h؂Ĵdz| B8 pQs Rpd*xHPa vBg^nnƸLJfCh#ƒ93f6uz GUGyU/H&J "(FU3h8mh487#'7S͍5{x׆ ~Wy g>1nE\?搁ssɓ풘iմA&,B2wqǔťvYvw>---nz/ң^{CtG}%/~r[/9{vG̖fs]s5$''_~o#<2u:thYeY4jb!،^:=f2ᚲ{%3]C%ik2LKQ4zSϺ-# d{b\YTgFs|C3T,KZF搾#vhg9|Pцw?zW}F]#|iVԲU0,+s.l,A)1#ܭKN=-fypGVq`պW)>^kd*L-.Cf1Z;ujVV,6N9pҠ]zf蒛 =pqںW=A? Cr Sq宐2UӈƬS3b1%/>fq[ 7VEU^}'mKJssI3K?ۂҙk @^aJg$ <@L%Ғⲵܡ0D z*UqnMcV{?!)9Q/1^]]Yy}߾E}{ڶnb9UQ` h0&VJ;uPlLI=ܺi'~yp`x{"ڸq (Jʴ>{v떛C !sh֍ ~)~U~=o9O ҄ĄLE[ݼqK7^mz]N8\-kӧMHOOh-`ڊmWl?~}ÚkQt6bu"jrXfq(ۥ*Itw^Aiiq2F xQŪO>Y9s=^UQ 01#L0j7f欋ҒNw+KW~C{:̀žT|,UlLqX)uJW\9sݧlQ"w<7+봸N`ݼ.'hۙ5lX?=F <),[o֜ke16=NwX'n!Q4iRJ- fϞ}ף>Zx}=ݙ;G Yc o᯾j󣦭|~< ['O|~w}[ykg"^FgյNc.-\}^pUTmuRNydH'<l"mXi-t 3[6)&_xcco \:{%_A _)}N91JbYo'`lJ|YU]y͚˷ɿ^_qf.o PERVc,.C,}s[^z_KQd̛nF7,~aMmڂt}ʬ]yÅ.znϜ>NWL4j^R|Ȣ?zW}*Av? HkXTh/Ͽkk9.+=~:TLωo[핁/)ԪPbwsoq.%{jIey +Kol\b#ԣ2"0Wc&8z9TfjQ(2F_p.񆞹v3beS_wώ-|GW?rvvO/=UKzQ|S]Gͺp֘?cgpՒ!;ՠA# ~o۷{)?Qzgo{: us9,bPfW4ЯŴ .?뇾5r(7nIDB‹μ495=}}_{jN:'P|)Le*'Gw/?h䘎][7>/~fA=l7fdY̽z455ٵx^l+};ŌoVJm.MI[n鈉qtt5m'${2qynTH{]vͮ(.|p߻LZ;t^$&Ϯsž=A(1  i;3C!DS)тR ZȞs(j)Sfܛ-K> \ē[/>>1nYjELTf[n@( |(ݚjV6-%6lZkM6o޼Oc˖-y-\xw2)))=s. VjL=\veu7EEEy=sK̙3_ѣgM4_-뮻ǹ&E[-[ܾ} &̎}mF B~Dvڵiڵja4jׯ'+2^SvǤ7G6={v( =_-ZwJnpR=?(l98oyNҥw }ue ?_| 1 9'fUnG3º| &Ʀ$>*yj_d5Vj%R\_]0 |q;bNw?2"N0~beff3wᜌ>^JIVJo~>x7߂^#UZْ&6sg~쮿?ڂş~,tH["m8Ez5/8韅;-#+#)T47/C_s:e$&;o>C\_^Ӣ(V1nwʃ>؉3.lւxUU*(]JBB&uxOnb8V5cXmϿĤ_OjkjJ*D W8-hV%c'w}=ٵGˍիOAxc?  [4XBޫ-եZ%ߌ.ھ%6zWO%J8N;-=oB C9NmofGJ+Q5os 7^ [ͦNGw>{j؃DTB%>tbIHBkT ~21wNn? 5&)#3iOk۪ۃUU>=(6XYt:V3fYNnqqqYK.WJ>}_9zQS]dl[H1t䨁{nkoرc_v:-,m})ɓ'Hy [t\/A:S%۽;(SlT; hlGla n諧m޻f RjHCq1=~zc?٥wlIIٲg{ E wNP\=swt4̤֘zWm7U>u=/p9+G7fYNNqq3gNnGmgr*R}ݛJAw wp㆕ w*,ض rb]XU=~meIY$FTTrơÔs Р9ϺK~gGl ˧ 6vw?tS?a95 $ʥl]{fvCu4֘n7No]JӾrrr"u{~Ŝ-`h+.S8 6Y̹=]lԅN4|Pc)²P21(ngJK/rH8c/|$Z@Q$`VI*(SQT4+UEI.뒛1##tv~|8+eЉUu:O=p_\S]},{v1 .yߛhT3$ (7(L@z'yYYnGsNvmzFVH먪8de+Nw ?nϊh~O?~r&WBBB(1@w͟f\Lm޽{ZLLLb!WXXxsk׮_TT{-GM:WRRR,}m?fO{׬YdԨQDN3O>!",2BYYYDgLr_.ccO9>!);TQ~O8rp-kVWx彖Ф.1F)2>19'FpnUG.م}0g`R9HR8!c0E6g͞Rt;,T77;I{Y] \4bj߇3.UN+v,ӫS{]2KNܾ=[(}u?n*\kF^>YR\j܄S'ߴfn1jym;lJ kVv5S25%|~cA|ǧ'tmE߯a#պ>Qj؄)CgyX?5K/{A=ˈ (ؿBPJ N9PUUl=6KzBd 1đ MWVu.O,|z'MF iɽv&d^ӞE3M|4 KL0+:6`PHpgBˑ6::>e5d"aKu =_}{h++=^_ۚoJNIKϟ x:pȨg@1g}ǾSoi3G>&&t8nPF@ Ee MqŴy}Ea, ^y]䆡OMmߎ5aKK5~=[U+cpgJ332-ت-oW dJ`[us:Жt:hX43tݥF 2 qADEPQYᘙE5F4ivI&Á҅uA=HgRK bZ6{.ąlTU\gX\}RsB`[vh\vy̒Jϐ.-څ=)[{1ጵOו"U26$04r8K>Z? #A!2qS["`B`.Wl[0吸 1nTRrz##{?@켆t3iqr\>a–ژDOq=٬\)Q KUvEwjRcDELw.4MCsAA|AEQV'DBP c+niPAmpfsUf hgsQ1xERvյtT^gWdPrsA,[o}8 fI]?6gψ)*!D')!4ֶ M@Gwkbz4~}uɒ:G8'Kl5bd%RbaI]F``T(5}6aY"h %axy1d d;R!MP|yYg}r-v{m:߲p#{ f…S{) pXr (^{Jy.}xW}yD?yWfeD)ݢ11?qgS+w[;[CFLKFAͳJn=_ĉp֖ IE]t9 z]7n*~_^}}=v[-35xiG~eE꫽GbbbFMAAkf믿t2D4MUUB3gT1bDArrr,ת%Aꨶ.b@r ieggwX+8 VQQQMcz*N_Kvx=5o'v lٰbɖ_!/{"贾̻m×;2z,쮮ٽG#}MU;6.=tpo 7LhCNNpJwNMS5ℐh-1.%< RZ Yک[¬7C7uWkT'iE 7kbל!-Q{de[u}{ިB]кq׏햒?KITp\fuJGji)VjgP~frh).|mZ9_n=jLW `nf~6EgU Ĵ ӵoq@|n/V8uR ʥ>8m<D'fZ#7On:jQN#kEʂF}s(kvE@[1|yDy?ٯ?CZZtVb8fgq(*؄􊊀Ϩ1moĤ^=lpbqRTa1:~^kģ PAKJ6SfaVA]MW,5d_a2ʋ0Clr uAlW.Y2ښmWVsFuƈeϮۋhs:].эj#{O)b@ruv34KPꊪ>Bc2*K>}1foxIJȄԔ&]/T m{}P] ~Yrloʈ^j.Y=TUm!8;OcJiKs׬Y~Dy?Ѩ[vy^t54y?B<@ۋ?_JN<#?Kk;fgzرC CPh }駟cb?瓮P`Q̒߇yݤ\ƞ[nyLQ{?~H" ]qNE,b eeǎх82*4o]]Mk[jQ" HD6B!2J:UBu侺c Ajr..)$wIT 탙@dPd$g`01 1 7CŐ&' l3wUQCjQ)egGL<Ձ4 . C@pݺmr;1`F]35UUE6[{6¿E)=n-2;9-ݪ,ҭ9rd#FLgU[EI&r-dkCf6;vgΜy}{>?u3wxUJd;c5+L4f6~h]W|H׊*ul13t111#-r*-HɾOwV :R?mL&?Մ`d(Y 2+Pи/k#,~_zD*x/t|uQ` J(Y{?䓯'&$dAʕ_3sEwwJp*vj;oa$AW'_󿩟BGڨgu't }4^Z^|sײ%ϔ[oX/X'gfuEςF/?v #AWC^FY5+r^`('Wn[H9yQFi]%E@iUQ9u?wڴDMqm@%kSF R@[jNh~Ӊz_]0jкw~8w\:2kʪʣ!ꠎXjh4J?VX ۼo _54ޕ?1nLv (^բ'6⫋t?9\ZٹgCj6K'/}i6f{ĨAlE% h[JҔ13's=mWtH麝׿=ztϨ7 @FO꤮{7̺S/]lMdoӹm Fz=\paP+rX…ߌ`8p*ms\,Q,` 202v@L\b1uIѡml`q gݽi[^%dpduKT1 a%3G4[Z_[U{B:JWV a޾vc+.OJ+kf S zڷu4w^բ'6ǺGرe͞s{۩F>nܸ+dDiU+Wr! uX)+ruh_ U͞lQC\ȮXݞe3Fڮ۽kA\]nw&3.,AT%`׈Ts"f!9dYV!P-n(@D˴s9C%'fLG5Z_W_R%ڍ@#0KePPٝ:!P[!ks&\?4CP"W :pZ\1IIQ@|u{ȣ2U`A}km@\JjBRvQJkNsz=Mkĸ?QT;ȥ[[ Y:^y`V\|Ӻt~ f_}ծ[olx_ڪ;vG tu׍?Enݺ~>ȴqԨQ6k׮9[L4q.j-0y՝. d:C 2!+:Xb!yZ]DBH p  :t\YEMMMŋ?zg?Q;⟝fi=g}l 4)P5f\̡nݳ?bhZ9:$b ]x9Be8zI?Wetk9˖70gxe⼧|) DgV+.Ӟ~5WWŒ3u^v۞#u^b}XVZ\k $Bv*-..:GTxJIuУ뎛c^&#*Q:&4p_[lܔ=/v)BBIHHI[.-:.rLjchQ0(ƩfILJOU(%_d Z|BRrxS`0Ճz=SӲtky-ҭ=tpO-Iҭ;Mk%]MJ#jubל 4ׄAuJ1(81{QR2d(d@9~s:mYP#'(i~tI ?|.U@`LL^ 6)_ u⟑SJ֟I JKqi1,ew?m@`Lvf%PUB&ۤS?tfD;u7>y^KN"diJBZS}KϿt"癿A| ̓DWUpBaNԞ*ȉm[ Y6i|Sm ;*?ml)T%+Cm% 端 q/ԨjTjX p5 JSA c#z9== w*tbDBEG|Qv*w|BWLXbo}IҖijKٺq-,׹>@[\LsiM [tx0tdjq \,E#zWdM)%ܽs={bg\8 u>hɗ?Yoa¨ J>C'ܯs2ME[Ub ͏3VTVqJ2 S`fDbm6dۋqHÌm3jT_pUP d \r2)Uu+#C%41bpDx *je#}ԜϐNJ1jJKk9YO/-"PDtrYx6y#rZo@ra ӟ;~7]w=w2[9=ҭ0ܢtaVDf͚?''Gڀ0o6`- /| <~뭷ޘ:ue)))YmuܼypnF=%K.2cƌZ Jm9wA\44Gzr5<F +FȰ1Ʀqx<zNk he[ܿNb]yl$69ֆX \UzV,xgιckW >I6[('O|5{̌^aMXEG s+ Q29z MKwS]fUT(03n;B DPe  t`H  L;rW΍={Y\l\3f^ԙO :oGKX9ojeNE6.^afTeVEcs左VUWY#3ٍ0N'Z6df3}K"ІFXW~ ٱpN$\9ZmN T sLDe(v)*ca(3x@K9'sL32~iqtymI-)(mze݉d깴x6B͌w]4+'aOgά&K!3Z=xQN>qXB]$ ~Nbeեlq4k~|u3aF6;V*sZ]j wMj|FF\5~7_JzgL@P;pRƊpUE3_8m5u}cDoB]ZI3壤XAUB "-eS-e^D@{D3{O#c3g6@- 9 chRQzʼn2~n0aaTVz=тgIi"UJ *4ZVz} 0 pbz ^bPv-u3w:k}P3뒒t6±YA+.11Q6h [nݺ )KSOQziZCfPMpe{`{A-;n:6rGrigJUJٙqm` ;韯poюF%?{$vM9~A ELZ\WBNCOfsh|Bd%} #sW,Yi55]3ή*R'# 99 j=N^O}}Eyi';m:&_ߜXeM]í*v .h$w?*;&6&g(h=cjDt85;LR!n$澒-@~gJIxG;/A:= nc[s![ 鎞cN 3f~0?UUUUbݢN;d#:rۗ-~.8\ to&]ܯQ O,uWU^y6rYJPة$ί5~nD͛.dغe{}]]%!A)]O83mw0*4y6YlΤ(UU”ı_>%6%%쉧ڳk݆-:~n*CjJIûv x\.KF^ +SJcEz݇9pԝnkTcg_ܕѻwjS fyo/{y>hfZjJPۖAM}ؙyX; fJGC -l=iT햝 J|5vn+zn(%MJd0K`#gSAvՁ6_LLL|G)_IIɡ&).+6---]?'Nlxٯ_#vw7neeZܹsSO=qg[hqچmW\qէh3UeھTlLS?0="fANI21Cpɔ!05ܜ4̍/5(//oXh΍w[G55鶸3W~K??©Tn$BHA\]Klq@^ؒ<ˊ Y-3O O^ C< >_o:Lnݱe[}}]RRN;ahgT:e`?U):@ *2 )Vx+$Dj=U-불 LʬpƙylvG =ofpTߑU:ސ@, L&UA 4^0y'JLp/?R~dվcv(gCI!##Y-Ҳ]ZeVCH84G.L};eu! (m7 {ǀ>?0z2cMDȨ;7Tfbo[ϩ|o#Ǝj<={4@ `1{J4A#;tn_ d- Az zq) :,tfdBX&`&+q(e< |BdNr?)GK}U'Q#ϛ9;)B67!{pC~STa.82bֲ?lUA|RX5>M3fʯpyMid;Һ@0f+H*d-VO8ÕSА:!;.z+#{LCNzԱ猿c>ԇ~xINFȾ"3`m52dàU9 apC<$"w韙t`Uq,6' =(p o}T-BM:3ū6i0RS޻6*UH1 a:dB{uN^}ˁu; ?* ~/ov=IyiZBfR.==1 no # 0Ӿr(b_yFOuz 7G귚3 *&q !Yy=/+'Lx~ zU_{DOw{ gBC(Eoő:m3fI3T**ڊ89j &"mckba*"d#́.WྭŲ,LDTNsv)3fA6(95x %)H6@cUII!O'D r!|\)s, d(]1X#?O<~s1馾-?vȾOwސC3I'G2n<IfjQuZ<ʫ!/Z& EUEk _ќ G?a?o5,;:s{_ o,XT@5$;:VdkL\ZZ̻rw( ?a]Z['d9cb]6>|a}s@d KoZJ1w<&-J`ZA2̠Еޥ5mC.2g: h;6HO@3a„VD&k끊 :h/4ZFWJcY￳`tkٰaÂuz,Y,jpbȑObsŵ5lM x[/s==zM6-~hL1}ض J5Vw4tЃ29A An4:T(!e!@*T[SS~Vr&M4b&ǘRY))Ts2o.2D-uNTT .|DP-:e$hǹYZ">*8^##lg.PVQR @?ΔDe;,{ʏk+wNRta0Tp2Rv(u*6l'@[3 VAD.xn\ Զܐ]OåQĤ8]1nT;`Jj6jݱnQ"=c+ʼX7-jT듶ToXSmC t:"@ PZRRHsYYɪfi9K_9, 2gc,֢01 M}G(Z)JMa6VXcN%F ?t@Ĥ. v;B&Iw٬LI8.jM (ڻ_t)5dCpF(i3|1Ծ?6^(+MvXvMm'ooyG'Z7*lm$2{SJ eVSH4uّǫeXnI6J3P`qTɆ*CN_JBis ҏ4 vhyX*ݺut:jS- ڵko`"g;cڥ^zWƝF'N5*-[Q2d%K9aÆcǎZy)ҙ 0+V|3|*\QmڵkE }| Ff`>ͬ9)OpmPs\)m8Br(4&65`ɩ]Ekp8Ͱhrƛ  !dݳ{d7aUTW\PkG/RkópA,RI]4ew4yQ(4pVFqũVV@IaȜwWJ0LQ;e*v%Ns(+vE#VP.rr+(#{gv0_AԦio5m6`??#( 54;[E'z ~dRLiw'2B]Le.+9ɝn;獹n.6fk}3O]Xhb!.M9$!mW_)|&C=m柅 K;>&Ͳoxmradpiyzn@^|>֡=Iz^c`j1 ]<b 1+h:nUJ)\?ZJ|(0T J搚t1 .ɡ.M쫈f_ F,#cw8]uVS[SU+O>e-6k;szl]mY _YZArl,L;ZYjE̹| ݿ) 2BxKRy>q7`){ @43ϳw߾&v)3oe٨"2ѽaYL[yM5AJ*\R)TQj(Piin(?=gρ7lU ^!8#2 } [Lt}<)!3(X۳kN#7>꣏UΛ/Yx(YV!"=8\o1馛`+,*-խ=̻\*9EcHXvKk밬GZy}'Lr'&FC֯_V(lSŻڲfvM,XZ|xh=i1N{ko3 + !d=h鈦NJ&On ^p .ѩև7 KO>BP)>B pT7sy3&@Ŏ[~o[Y:MFGͦZ"~G|RBӠ,Cd+= 횒%'ܴl- 0<}-ja_<3FCe=1 ޷moחvo߸W^f Nu8 L g5])lLJdE}kP\+2%Ҏ2F2iRz@[]]]uiIS\C0*+P"`weMjvJ7|W;3`jf`z#.=WI%ɗ+oBZ7ƳC!/lh 37(vatZFt.3;Yf+kc.c).yyv;mۑy/7jtCilHjdZʄbf5,g! Gwl//?z爋Zݤ ]'ec;v&"P,.7gcm|S{w ?c{Thg_ZV7W^yeC0id%g4 |]?sњB9Mx |}ө]p+tJL=mYC,^w=uvӧO>62>vJp(*ZF-PZ2c< }:.R+cﴻ٧?8"ntzcǎփTM/GsyO]Jv4jU֞ygХfHc񀜶:6rrr ,.<&PB5B]09=zz >ț>?e"@!+U9\fjMub3Y<.8ݱb[Umym_5QǫwY[j^sl1md7|[3DM֛NnX˟:^\pdvAJ#VYZ%w?@Ii=ӱyvBmQ V VF>1=tps B_kbVQd"dzsPv Q FפTF'ZWqC&Aנi_=ɾ\wu:u(8Ϯm'm*ڏhf'OyTQ7lZJҒS5+ ꉓ!f-MǺ 8ʹ>=AI^^^㩯>rHG7dvf A669A)%vfg A8Ab6 0A. S,.Zmf*$Dz&ZXe hM g2TcQk"%N?as[o7=5+3SW_] оlSzE2Sn4o'@Rh$ kQ2~ǝ~ m(3k˔4HNKHݷ{A]u7f{K֭[DfWў纜n]:Y!"ٚh< 3+[vKQwtp8_zLS4 ;SO}|ss "L8 ʨ 5puMwD0_ll6!2-\>Wanqy^ vOK.;dk |;?f2Qб΅GSX]eEݮ5kW( , CQK,v%69%A\#%YҰK_ ŮN8F-e>tc&Ξի`hnL\"4['ç?<\ճCϛyA߁cefNeY-8US+$f̘T@) /?L}^zO=}#ի]r%[nyݻwt{AZ N4 BT_04sⴋ9.4[I=p\ue4hmp?n2z ګ ]qfHNګ ?k|>銪2X'tŖCsA H233s+Pz=IN[kOZ+˕>]I(irϦ5'˱)}mJ=^eUm.5MX͏vt5p)>8g++uQU{@ QgѬ3Xjz韅O˝0d𐮤iP{+{nq/:yM4 YzƷjU~>]^n*3եv4ְ67P/zo.^b}yeEYMq h;ƈB"]t5413}] eoM9=ltGƥh m}'iTcoj>.ge}JgvT,T T '@k4ݮC=ls؜.LqTqT1n{l%e8ѝMCچJ+j_G ea&d_;{U{9t@Vd6c|+Bc"%Ct9`Q?ܡDFc]S#!XwQ'Κ`K7g{m)6R|hkG zl2K C2)k Ѣđu{UfOhbC?{:. *#~p2m;׫ċfO{v&;&&>#KT͢иT3uKFi}yZ)SX=A.tyB =yFJ| ?|]ugmͰD4X;v`9JPAg=TԫBHLlLr^ ' ۷oxT>t97Ȣji*R?m%'[ys㯯+~w!pҽ]:g6o/x}H~tstۉ'Y2pra-ԚuyQ?ҥ˩R7Q-)%[T uv% pmŅe/kz@@Yc wmbhm(.p ϛ>ґ o ]Vpoۡu!ʹ!j%o/8495.#bYERs3Ald?ҭק-3~,3aAm{?dꜛdžs}<%SI!_}/? v%Cx ь6TyŪriodBCzJ8 j(`Zi_m;b_G]0pϮ-A5d_ܺ}=]axG \{YBUq7nQcN:o"V11zʴ'~betb愁{ee1d4;'sMMtm!+m'x_nD؆2)~ZNuW )ҭ= Kv6RrnuO;ЖĖ=bi1"SaT5if&[ԴUM;#6)3yx֒?Ι󼯾3G]LiIݣTWb{ iw,|ԓ_~ϿxcIDNg߂|Ya)t؂M62Нrb4 =œ6EI{2}[)><{Vk C = ]! :y@6#Ɣ_1=13+a3Ao^sFK#.MAɆMI=iȅ3;S)5Dp?$ Qk {6mQ*d銼/ʎ*D _E!))nFÒĠ]n>A!䞿__W7mإ|MM#rWjv5-u Õm|K ~vﯘ=~r{՞]{(I=B ٰy1(m:cY8b pXS+\t\062Z ު{y p)xfSO˜ႜ0ܣxI^~临ycz>iʚ9c֒ _F)XpRG Q/ BjK`"4bY;[PfB5sZ21,ԸQE{ˌ&υ|9q+} j6gRHvŗpMYfDLvm6x 1!fWj;dfYn!,6-2Ⱦ V ü@AGekrm-W0#hGW_3񮁉1gdQ`+};?l/o;[3zLhp]"Ǡ n\dÚXyO@RJzd;.o+-\,z9lXcڴ:lj`B #Unb4y`x4'+'lQ;X7me_wiǺc&^|=A7 'v:n[,i VKdWX-wMgѴ,ƩZC9N /^U][/ |YsD à^Pj0lBe_|-w8xzCƧ(XI53 t8 1hfhˆ)Mi/y{o %A!R9` "t͒u@Ld'ARj{) Tխ 8?~d(\ZYF3BDUVIM!mύr?>.8?0xBPt. .igu8 jg\ZdL^R!,g԰iBơ4  wS47$smn-ѼttgϗVԖ;.Gs&R0shJymY͢u|{ng~`vb`Jbbp'gdI0a5 vfUl;K0lʴ4 >:x+] 0 YhpKO5TF@o ./P_Y;5UM/|DvXk-]UBM=qDPG}/s"YA|A#61ΙN>VJlaifB>j$v|P<"VOߡ&>K!?ΰmHͲ޸ ~{vU@$]_i 2 U0O ,=P{ܴ5 az5"xeRs^/%DTm\dگ,oF4Kf !C M?m1e[EU-̴ФJh:'Y1B)l6 7nג}BmZ-\XeJ ?y#&^ܖ=p,n926\vFǏ P6ڦ6Fm͸ꪛtƽmW+~qݵ?38nYji17^_͚E yqX!R[Wk xMuݖd"(3;z'u!邇vYYSԯ2੭-,*%++Q%P3*+Ua =.WƧ7P6ΖݫW{/~k~.j!Xe4a7M.T^}d\;(>GM%Ҭ%8v:[3H =3+<ƍP57 RS".Ɔ6[Rh mK٨ȼ5hZ I-5%[7\9Y_S]ǡ*CCfm:Lf9㴡tk L:ԞKrNҭ3̡CW;Ά~$տt4p6/Q ռAuuu٢E:uƌo喇l6[ԙ_Wso6@TpIN]Ӵ3Άa[c ںݕL͚4ͼ+.>jN߳nwWbفێQaHU0dMdBZ?0tlwL|f9b28J/w^ ^TL#B~hwuuuyzea `2;#ssrW},$vdp[u/?"ԪV_洹,)ɌP$`I풍~lNHW}!Tԝ`{;;q:3fS1=n+SZ6]_{EKuQ+  ׌"lNs67!TذM:C`x #U' ҃?/M6a8lN'==v,]Fs64Oл̼LXBpffS-nj0Y.|[~CEFH+-^a>:7 5G]C_zBmpREPj~S&Ni?z>Hݦ=bkQa!E\Rc10yڸ=/%8 ׽ 8԰qmfF*=QSRC@s%>];ƿ V?rӗ 3xZfҳh_Q3=ҽ4z5;&F?tldH3R uHxV4:V.*?wB dl6ڮ P?fy3ig㔻FN|Ր؎9J@4B<ƺ-^4[ڵgܮ*߹,Srځ2(1m' G: e6ݖbwk; 2J"O "|P;TN_e {ܯs5FpZ*JKN#$C\Abgnn֬tKtRVTHb`j{ԪݻJ^#VU Qc ܓU lBц/H{WCܥK:,:^nQoLxˏhM 33R+dB6Ζ[FT ?&lKף̈́4? Bc,:Ȓ{<6sͰZ,K\T6pXundɒ))) bBBBvdJSSS:XZZZ`5~ѣdOdklP^oG})رcMJGKKK}.ƾ1P:q`c##G4ы9Ubcccj|]~َ+ Ͽ=1)`*N߼~﷫+Jl97dMQu Ё^O:ٶq6ەgp~H&0{ ͺV#o^0l55eCMrϗۡWw}RXœOʺ?Nk h~_AQfp᥂a &UU!'!ܠ~(VAD ': '^{T5,+ çn a"0 9c(kHND ֛-LTSleq. n?|Wɟų5 B@ꇺ5n5HIo,flho MB(:1 ?xħZD?<`G3Y/(ŤW hcayU݉Z 76& TT{Yٺv2 f~l+A=9R  BVWم @/sBYp&CC:WQ )S6ψز;_Z(}ѻyO>9Bc-,Q[&7vub:Oj>^e@N>b|f 6йA ey(强S0, it)[NNʅ;Żme s.~! t>뒙 !1%b։_-X[ P`F')6J￟۳U[M`Zaa޽{?v hѢ-**5RGQZ6͟ ~O(ݽ2qϞ=[I'vO<ğ76{x?oiiif;zh%%%e~8{1ݻw\dVc@/R3? &zئ𺺺W曛}Z85)mI{n2dqq;4;zp署`?///!-(\UH(:v>^S2hSӻ4_GLl|ƨqS춗Gsѽ#8Y,ݺuorvy8URZA` 慌\T=A/?ʃ^p%:"`$IROL(f8' ahBXv g^S,jĮ2f:C ~y#1@XeN]6upQ=~)n؍HHlMz(/9} fy[ژTR[ =eU{p߮ WAt$ m {:!LpfCX\9 i udc Wd=p6d"BDװ[+S]u\C 3'M8%Lo,Os0jWU{? Ůc];H醧[Nʦu:ץV֣WhԢo.\x%=ɽDj-h,̪:DxGEM7` 4 3: P\89 :T.L #r]o2?hRlz,Z+jOmڿK񷏊h3’ 9>J X]fp LѠو m& PgW,%1,|>{csa!dK3*WV(7t]FM7˟ \&d0h0t,+z=(Y+L8JMȸ`;~ز7 tjۖ~՟/ueLv2)1ap8z왰~nLlɁy T1 KQCZQ`b"Pؤ\RDpMf` bX,LKuTWXdig*(v$2u9shVkeox |:/p1qT^Ovʥ2#m(0sR\PȫXf;e0`IYYɊ%}MzĉSgվ-w#,: ٳgK "Mmuuu5YYYMϻȊ)//j|FFFV】ٵk҉I)gT>uK-;$4"AәNEFNF3Q:P[}NA=RrH5k n^ni4&lZ#&N +b'H PGG+=xՁ zē[>^8D#y䑄'4>H:/hC6TZqgHA&>dѬμi}g7}{ElGjZ<5oeYMz=}uAJ>0!ܔ>i쵋yoy4(h,g_B]RFN m}t(N6 Ue \i ](B7a5+^ =KCf0uMޮ>?7<F\<dGd8&@o+p@ E /nlc׺HKwGΑ}x<4-bOE4zt<DŽb+{҅IWC(0x7M:FRFA#h|{C+BV ^No֟#pp'SNK >Ulpɲ, K$&1gLXt7/GG\K=P .ƾ6%WMVV666V&MFc`tLLX~Ee=& [T. KIk i4DZ:H2zǕ κ _DNJ NAHzHM>}{V9ʨ sVc""~5MMMgܻWXPu B`Jz{zG|~t֭.%lux_Jet]wSpjI;VOO時/4}{ڽ@I-($̡!Fأw= ,8L<H#KCp/GPL >')I &`ȫ(;[OOi I=9ՙW"~a:JOV* 6#LJ߽,^аđ[־i %t FNNIz^JMMy呁?W^^^cX:$$$dTUUѠ[neZDD0QWWWkMR $srrJF/^pu=RAqqqO~?7+N}衇fB޼WX6wA0"ƍ8hKIIk,ׁx+MJJ.]z/kgN={̛h2f̘1o'}<ѓ'O9m\fz9ٟھqOC]M7P6M[UYyr/W=P;Π2cwƦ $xq~z (///w:vY'YBCB^a1f? +Q fB@E+T]ix +<[dZNtL@<Ě@ER(o6}=Qtl΁aS֪BF>D AafJ= ~`|Rҧ?h$_6HW |(916^ާ=|xh'K~&ACΈҁ5&GHV^!7ZNkzh3@\IDF@cYp!A|;(HsvuyKx:B1 aZIHRĵuouɾ3?Cj3hDᚡ'G#>9-T d/!>KM7j~.ah)W}.gA7q&VkN;rh70 Oœ@j(d Bȋ`G -Wyw g@z!f:L^$bUW]_\̳Rgʚ<-?1JjlMgS4NYphxh9pOl߲RB\ U'cIYm%n!#$plLtvʲu ,M~xA{{{ݶmvx޾}6ϝ;Voa@?s{{{|phٱ/s>=N>}yz̙ŋco!=߹sgM {Պ0Cg 84pjXP@t=@A Ӂ*zYp <-i.l3+A?ts1%%=GS\lZW}FRX}U[epR:Qz~ЪkP ;6r|{UszB0ߛ._KX]./149"Q6A<;6)]m$:}9DDDG!¾ #Z5NQdj@ 5Mu56 xߜ9yNfe: 2&ϙh6&,np^ȇُ&Oq.qם0E&W$KFF4%$$3vsט ĩ;knY#.0mx_V|)j| &RxL,[q3í?6)[xLY{{{!yVuZd` 9nn@8Vg[C}IY%9Zնffz-M##TR|&t6o8#ڀo̟~ESf͙wPppWVGkݛ9G% cn;n,ɓ#Y~vϞ=&NhsOdMvь%?5d]K&Oo,s.^̡AczӰf%D>.7>s:UUW]Q7[ӏsGϊjs[PY3viTlԅHHcvviSQ!\gAp {[We= 4 Ugy|dr8HZ~BQUi*䈁pH?&(Wz6jnzUgtY2*H[Jc2*vKa TDFaN 0Nh?GP,Xd酐 Emd%HVr%3W k]_O߼%)$WrE [_+++uoΕj۬>-_@`dTLbE W9X-Q H'@OwGۏ]}x#7sF)Z\R-vGzVT:+uΜs1uLqbrmUY? 96:!-bFu$Qn;Рp6W(9LxjnMLDǥ$V/ltN ܻvÇd(NPZ E̸i78/o ;$N9q yZMgԁᐄѹ'|" ,,hgoذ#.¼SlB{Z[{ +$D\"&>Y[6ȒmJOk4j2/ڳr!`繰̅ 'M&Ѧ3g KXdJzsPsTtL^oArOd{RO:`Leb߾}>L3f ,[|oI&]7P(EGGmٲ?v!===߿Qimm?p@.z>[>ɓ`999{@V~w"?oԩ H/jʕ}}+W|gY1+`dggoxxG}ӿ1QwGFyyUVmCWO?0fLZi?)оuv8C>tRCr XwǘSx;=S';vvW (eT4@.6gu}ؾbQOoA3gp~,ZtmM{Ӏ3rɈ%9"Q'QI 329 g}lNB@e2&125d&$% DȤfZkWs5y$MT!YG{ܫoa7]s.6+cg[*/[v\Ke/p!1T+CjǀC8KΑ y-Kn='ax}a9{XTx8yN/AX@Dx\T┲fEFAqcR"C`Rk[ $J$$$Ӻ|UKrNd5dNI+;{R" fµ3B}ׁ=Nke}i5S&XHFֳ "eyk ZqN_4ɠ^IΟ9 ,aHXi+=Wbi}U^wظ[Z:)qD6>LZ^p`6H@v R1&C[a6PG+ @ǓUJg/ĭ X?$E?o{~pA6l=ּc y_ȏWkxQY_FǺ [%hy ص(tsJIH'x'UW_6(Q^㭋~LAD_ʉcˆf^,_A}iCYX0"b}ƶ^CƆO;q+H:yBJf;[]#3D)XZTz!kڂkvop;D0y9i;Iņ*L8jU?K_ 3EFd^d6ԝ)qD0puWզdT ={a &::AP60HՋ"G h]a^ `7eѢko uk {[εIi"ϱQIɱ_wS%1))㓧MwV0涪@;T,'FtPpq =: n^\QW8ԗ $vwg;wZ8F'p4v(ρj/ͭK:lr&* *εEG{mCC ~Z O<{A˙ gj9%LH->r;ֻ3 @/>-iE32-+* ?U2IDAT${"smC'pJ7/ e˖͝uQۓR I]ѭi9BȖĔi n5eڳzŻRm nA2.ݢ}.nlR(88ﰰȉ'& %ڪ:-[_}err=;s$(,,ǯL29"d&p:}x)c#& 6_pզiZMZlA܉M1SrS.pN,/?+M&/t}?N;S^s3s _>~ko厇oN8ç$mV. Iڀb㒵SUw:Xx_UL04#!"!i'+ɜ8 dgd͜ n}ޞݟKNwz l a3ե%٧9\zE#Ëo㎈Qi౿>@=yWy}=OgG[콇 ARdn@ޒ:=5muz{W?s8" @6nV!g (8}(fk4LcF$%$&mdOI$񼫶:>33yy s-dO ;<&ƏCfq< -Ԝ.Ʈ;vЅ~wykq~栠avkݹ6mRMZ1V7Y 5(8ǏZc5#0K OZjxA ;k4'zc;nےK( DE%9r2y$_iQi!$S ^=]E^nS!8dBD(h%Y*+kRSAZ7kisDx`LgC2EZpq`LKH+[iš!=VsoVNjOozkjulK.zRuU"YYWZ}ӡI{-̺)e哻^~$A@&Ҁ2 N=Y15 KÎ)q\z{~S FU{Jq)vp *+=#3f:>H례 &3cc}l+[f4߇H`}*ES-[K쎱M&J>@g,a !SrF`)猴IG?ol힗yCB_ؠs}Hr)= 4Z^w{}5]*;2?"Ϟpɷ&Zd3ݼR\[G*yOjod4߳%21Bd@8=ɂ‰os7=&.1E<ۗLjF;Zzg؉ v(.Iʋ+ʊrDD-s-7oy| ',*̫1jgEnF>1}慵tMؿHwOýM%W3ܽ.}_^wԈ]v{EGEQq'?]YyY6P.L$cݻϸya8؈S#XYٰi cyهr*O^P@NxhӦ}NYBHyZa+FU DSpZpVL⣼Xէ z,=B)<': lZ7}s~|Vφ5|뭱i늕IX0q$BݽP…Aå(ht:Ň.8}܉Kˊ)Pq\Ƕ'N|/:t45ulʵNY~Rm6AquLXO`t:..~>۷{Gm'<&]eҭ[|뮪,|oIFFƟoϟ裗?~8˗,++[_K,/00玥m[lywٲeollF_$۠ǕbR%T;~(#TPBi1:=vlkZZlؔhĤ `-ʈB[v +l2*@Ni2!H ?y!3 6b}gg+Vo{8hz{NJHXB~qi^Л:H^AI_]gq:sJrუR_8 Q=9vlL~ S0y%}O-%qcn@=1 {[6YUtN:"win,׹'o҃¼6@ q)<[g;%'.SwCpǚm?5y\hl$̓ƎOvX+q2( ;KτF|tY}߳#{Ö ٤P#̎F}&ǖ"{6yQyh$Nj+46T E daIQ(sľa;oY[Od+$׊.ܝк=u(Joxс1 ^2s@ݶ?]>aWkˁtz֫{<ZaU+-e{pDМlӋB49uCnֵ^?BVZZr:֍́BLT _8ۆ'}´ic#c}#loe8d /|^>f-پ=;7l9(J[C!1F &m6%Fe8QSZZz$&:: g̜9}ّy͑gnټ3%+k­?yp :;Vw:{\X'">>f |p>X8cƌ{iӦ |&QNoڴi|Ee'N;m6c cccp<5?tɿ/ 3@Vr0CojԢaCݣGۃ#D'%%O3,#{Zt6$djhk>6Ib۾o &;2s7|r,—nD\3i>d cZED #BvI@$Y;a|<9&xOB1AGJ{W]V*;MXɈS\;i 2N*:Z_=,V~ఋn6lZъ7V+sb4fygLU6zD lDE]:aW#$#Y HZt]#yښwz#"% b—,Z[oO?HZz{VxEO {ل] nA}]m37A{:Тf{0ƝmJFhڽ{y!:ސ1aʕ=QI1 ?K{ B`/ғ_=OݰעމMサfOZ W[/$ˤO0utgߞ=GK6xnLl_|}T9sژ8siC[DX Lz@9#{v ~uLCa:_x?{]vw0{ ||dpmaEZp2y]SOȽAN eJ8r`Fy@ퟯ\(]}{L}ֵ|Z=CW[4=]Pz1z-wˤ[|E߿GY,V$ȑ#U_D]-@sΕ>VcccK/B|˫{!0U .EL±5G~s1㯿OW j!T1N:_}ך[{OI!phoe.-8HI'zwoν o !ܵ{_?Wnm^j뗪-6>Y{ݽElN]W#BNqQ_];.aLUb#ߓ]՟Xg 0?t/#bﵯƺ5[$p$V d(-~-0]μ Amg[:Y{DnYDR9OmDYkHDѥ sYY //_qb!;M6v. <ǫLdف%単>Ov*: `*{P^Ԕk2=m{kr,B xq/=O9rW"+__QZ_=8kOHvlYh4=_UY>oWyYF6( h8cb65ط(Me۟ɁZ$.Vd<}rSxX@ϢZrNzVWVO+Xa;!1^Uʍ(J?e!c.z(< a={{p11%Ā9mV:Oʺ> iAA֞KDjM3HeV.ߴj攌Ԕi JȘ &jsTQVa*XVxNH{+룏>kna֔ gP]]PNi;$Vef͝31'-Z4Ig4^ta89Ͼ\fJ`si  c)W!_$ĩ;c32b.FGk?C!N,8w*էMN9'smxժʚ;\qcңGN(J]mjZe^M6t;I(++]6UEJJJhLLLP٨;m k׮uӦOѠ~2?EHvTP6g$|kڜB:\0A=bW_\o\3eLJM0;ZO>w,pdS\V#e[k੓93Dg55֬>8Z砽b6J"Ad~T@ bK@f <ōJ\AwDAoO_,`,R8yHrHjUq᥏?41qzIo{ w*"QG Jlm p;{իtŦ8G d&Xn^|# 0F6&wC@')<|qN'FEE᚛dOU$Kҩ|+݊Kjux9AB?@d&p?hk홊]MhLuy'm?ݍ q`EF4G0GteP?mZ- rəKEBF7$&UBLL 4̋D"syԩ;qi[K{{:l_銷_z%N`2LJ 2bp$oٸڳg?H6݊ PJ@_uuGhܹ#HpO7m*ǫڬ~fRАE%MEť5IS=X$I]c`8Bk(q,שaUeg89 OϜ% /dOSl/=~ȶ{,8 "<-`z?99E&D qmZ]k?7oMJ;>~̹[ΝkݹhY'.DIn\;*GU. 9ȒD\y9'sqQ-Y2C#x@b]V#pxrzMGI%BdE!p"zd,+9 AZN@s!ڔo:FGK eE*lFup+XsULvj ؖgVkzի얛mPn=UA"7ەjYDSNXx 9<(:1qLhddʱ UĊKR?fs$ $2qpէz{[ef1רt QVy ն(QJqɊƒpf׀NhT(34sVHC@iYD$M-q"J۠QV6j p` $UlH xw%rRh^o gX%LQW1OY`O*|mK&YP"=(qKQBj/r{)d=eC6J:&&bRBƎ=X Y,}\=@E}_?6>΁B|k^ L0jd 0AGߺQCQ6mTmp$,pH3U QaH[Y?TO5ZQ6ITހ+bn 8bJK5g} BM['c)@z z^ \>1g5t2I砏KI;[p/ 8RL*M =C N<'YYTPBL=73%h4; _7^W<%hwd-cGe@:^9r3>`r A CPyФV# 2F{Lnٜc&&,aA=/0@HSUtB5U/Iw?)b=%:Kh1 /:0| P &}8Led꼠JmVP[9#~hW14sxhY% An?"T uEA)Qqe% IUG:`+qKbg~F| ^"}CPK# KU&g6i8N ן۷cNK db!UKr\x^l)$?IB-rsLW"EtAYS[ݹlخ\fbgmzk 7n20I(Ϫf Eʸȸ0b٢u_Rۗ/hc71}BbiAqH F5UUyyyE&X4efNH41k֠ i$Q8d^h|gfN.h4@:^9{'k4ޗ6-.-4 A`QDD<{NØtzA N 2 ePta#>l|Po86 ;QxoB$#?܋cTIENDB`PK!hj?''>res/gui/maps/icons/moe_calculator/previews/calc_assist_off.pngPNG  IHDR#+/#IDATxdgu&7PsOO Q $@"D2`Xov g] f1el ,PI$M3+{IXuSU7[suk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]{:>}cen^ծuk]Y.?{!]rDt=X@Y%,sJzbu]Z׺Z=uOpZi;x[! g,7Fyue:Yh3o,=Ɨ-ֵukuA m-gNM_}lō=셼VKɶbcl[;|=0DedcPt]ZYԟ,`>0x/`x7Rnu!\~Ӎy˲iv!O<;iӳ4le8ـ~hٮtkO%,I=T3Rmr3.rKs{8/tkOBOGNnqɱ3T2iD-;o9nx3x/sSgE)wG=lfj;ߣ+MT,KVY0juleg`ڷO-tkO;Jgo@jIq1Y$/nZRܡ +bCl`@Tx-N|޲) 3ƫ%#Vu(V[^ih8/> ;M-4Gl.81 5!1x`Qz>X-/( Nn~.35[c9l cuPQm 3Vigςϟh?y]ZXo@P(wrwj{j4w@.+)ز;ozt,rfyszt)- ;==-s9,v=x9Vks`h 8O,` {fym4eQY7Gga~M`n>'wx.?~>\l J0d.&ҜiVjovӛ ⢖EKCܳYXx*brYx\X՚=xvn=7y|@ϧcYOcf}n٪:[?l.7 g G[Ȱ0C&kgтCl_׉3=s|s6]5Yt!=Ƭy~֦ޠ'ދ-sDO~מu~$e:=a9`0֘4։s鱇Լ%0¬l c{'N2|Y1pF FD@> 36o՟$e'9>A=eI ֦ N t MΎ7֬&:|h nL[QHWTTO4(@"b_@" ;ys 3xtriXscêOTu*^9]VXXZ6MXq30W1PB PPHr 8#WȀ9`n9@ԁjVfz|gEOt(cq$Ë|ƒZzc`gAC>Q 9|G5VYmhڑ'Kx7<`ߵ''#zt}i ѾIDGjD0ӊ+Z&g91d_0%-%S/F@T;IHܶfz ,sM`30i 6|ЕgHom @.4;WV&ҁulylU QՊ:Y sӖ7B%͇Uq9rƷ7^Kd>c03\En9yyM>Tb?O4PwD}3 z+[Dr /"O4Z+(1uF"Jי9&'z}{5ki(dr\M&JsEz%8&{s|`>=tdB]Mc$}/BOgoAȚSq0-~|`Uk< "ե47s˳;hxnZNkb֗ND-48`nom<!1Mm'G^hnY(n;ڑOı>\e˟3F.s`8D2G*cf||}c? ˹?wkOMP)?6STUF"ϐ0c"f%ze/WV,Uj +̄KQ ![u[1d"mNۑ ua{icCܹs~ ;v(nIgvyA}04 )Ҳ朹!3\լiy&1 `n 0f&q͆>l71*#VB5k4J|f418րkf p'Y37i?yi}מ)>Qp%E9F'c$S9bcFq~ g=s 2^+P6*,ik(Y2u@aY*qҥaTD>,ȑ P`7.6o(LgYIFHi>4<å Gυ#m }In'xN&I$ur6^ R!ޑ~@Tn)υ-2Y$6ҭJR*7 @80uSbD C``qFd>;űvԾga3u{ 2`x}כoI_Tɉ&) N~ yt3w85#Rg%B. k+CL¤Qx 3ʞran<,m(}muw-4Ye;1K=P# 20WdQ ǂYQqVg 'h TM1/٨^Ru+l^L`;y\ 6hV-djU0[=ǨǙ /?y€2/s<,]!0]N8!#j Gic F3֦K ZYT'o'ƔqzR'>a!a#eVɤHlf@ Ϻe)qWÇ@Ku󣨣wΖlYϞ>-q24j)˴dy{y)hp$o;< =Fi$s*2cG4X4 ׂGsr wy4; gv,Ml+J"0>e˂c'$fVVa@< kN\^O Ht I#RޢJ~{2y?M{)˜gXo={NЦPLq0#M1w`]b3rƢwƠ&BL0*TO{7,{%-q/_Mflj%s{py-Y lflhc)0lBQ1kM%V +;L'& @?mI)4tȼrV@Gjǁ}sN>K8#eal|VO.$K Kb;C%: ,.R!xAF .A%7}ю֓P Ø56̳Մ |5+(4S\..(msvk==H8GK=yN ۅ⹟׾?mq.url͞|F [S%)  I£^$'_ $x#N@1?X+«)| 1o ܮy6hv &ztR3TCD*a<>'!_1`뚑\~?gΏN1gwh]j:Iߝ2]V/?J+Ҷxnj%sA-).#e.t 978H#-2 .k,1ccδ̑`d}<C2dm re#nr򍠈;P Y9l[J"aY@c$W,a[3#vn G2$Yd5Vp8e©J 6&Τ#<&>@H|3CnC8[ !|sm\8I$}%.>))E([És,-d%F > 8S۠$6Z&eۙ56,B OFGZ#b,@eBάRHIyNuP]QoANl]N k_ٖ';Mk71j=:G;o\i7(g9hݦmEf=q!sFW=Sj|8QJK"NX{ qQk)\\UӍP u־XKWL9x;ιMLdhO(M5kH&J'cMD&#Uu8+֕4jY6[Âbwج_Qj+\[tE}jɽByͽX!OC =o4'(\2-j =kDL\(c%q+t ~ǘNYhGq5ƍ+E\ʁFqb@C:1|5fx`%F &S. xh J iC/{<-}#>cV#݅9g8;Wmf-ɒ9z% 2.0ЎoUBLfH{ldB!uvb~ҍ0{ \:o\`ȷYV5\^Cyb!{b`ɳ hъ,OPkoo7Andm@Z(Fp7N4#l&@ޟ^; Oon1{Dk3dyAiǙC5j=NfxܭΛuG>ڝ-2+6āD'- I{:^7%>AQ>%9 *xwŘIAR1ʭxYB'3:z5njW?)3[^8#Ɍ(N2,xCY7d*ѧ<*xfS4sf+CR7Q*/OVv,+xiɚh3@Zs`)){Z(Ss5?3O+9(`Aq WZUx )ct)B3h2&DN|H@NK0g0bR*pխ`5_JA6В\1ɴ X‰'JyHPIƅċ&/L WJX [HrJs0V=ōIGU箦k{Ah qӤ71aHZ[6 iF^bgdXTGqFayF.`2QB BJk=%zN}ށ6̢}߉? F^4ic&47=w:y?owp# heV@{LdA4,rd^Z8 h\pl(4o4|ܟFz**3Z9^z3FZONC7"R+ц{1 -]ĘK$\aļ^x*tk HOb(a,W,fun%_LThW 'RLj%3DIgo+۟z}ej&z:n홹;X`#\HTk<463 |ʊuGB*Wd1MSXS#,a<$܄ qcH')F[X+/r.ox$&9I$dS#+KF!G#_$gÀټb(5k0ֈCq fT5$1L`#@`f|E#!${WkjI16v5 bvcd<puW!p IZ!By~{ :pTá(*H\XQdcgls?F F66rdGOJaCGkQ|Hσl(@ksx~ӟi<eNa{{>lu@/Ho:lX-!l5Z >恖ddLMɛ}Mnֺ B]{k48ANC'ǩc ڏ$9r}+C 4%;& ޅ\L&I0)}GhJkՙ Oh9n=[|XȻ$8Jѽt1V VSAT^[oґ|=>ch"`5yEXVBFBj临pᎃ8'PXnС6'׊ڼåy!w>]*1]>\dzˊњҏQ B3jIWE*cd Gq1߸hf!כi@S^SıK!|W77y{3`e@7sʌ۷? _}Vm"j q^xᅥr,۷? dcl܅u3?CTWJfNym"̀oc{٫|_~.c+LMMMZ ?M/itmz8yCSrA+"2$Veg<6FBjr8ܴ%Zq{K)Í-f3dTeh ;[Cҷf,(BB8>'kb;k"mzVig%Ѫ2ԏv|c_ATI1)ZOݫUs>] nr~T%~堍p[Wk.Y̓/C.X#1({{p'ƏKƙdd4jF+mIW! (MTi OS4r DhErFz & |MA:I kϋ 7 miwh7?|w?˘)̉1#C%27^K/[yOu(3S>~?;w4({$뎏OHQbHږ Q3 7K#ۆ AɃ`|9(S3G+;y;σ'9jLO'uVbccfcP<(FqN]iXP]Y]W?P4Cz_kC=tv ͑S߱m۶%ݻ?{yC:~M\?^r%/,zę$'Oۿ7M瑁{3"nX)h~<֢@31r.ԞCݕ<pCR:%pTk9Ep9zGF5)] U%x%*Un-@HOS?$@@Nr}PP5m Iӧ$ъbu52S$5]@M)´9 V2.ngP+X4Ezb_^p>:0\޻tow}掏~ p#1jaסF1']qj(JHDS@i83B-9_1SeWo^~ C[:3<"eT$="(l,Tk}Ƌ/-猇`??>k \9+;G?tgEO@ -&!IVWlZ~ֈJ^'KÇǾ{?d{uEOm4Ej^C`9S\RYd\œGp3ijc^~ k ̾&b_g3/{}c{ۦM</!u]wݺE/~Z-Z dxu׽.%c088կ~=~'> 2,\/~%'`!.['nI_d޾;oxsB|1}k֬vtMoۿw뎦ka9vgQ m *V9\UęVD4҂B bGJլ+$J3T k$B,@DK!x/Af] ].3eu5cHU5J 3őHp7܊jdk17唥D6ﱻ#]~ҳÁ勵iR:f<)5hk IIec?ݦ^.>+=+.y{ O~w:.p Ph6 b0)wICHC6 -Y3! ь>eк,Ӓyl/\qpÇa!nLpΑ0(#rn{_9kVe(uzW?o^YM@I @?(H^2](쪖ra APRѠuV \=EePĉ~_7n;W@ _y[_p/^AZ FPX#/]͠:@,dB@CD;8Dct:OZ9hU/ W% zj6C*s_%K3:靈p [F.x?lF^Y 7g&X_]}.>wFL]/,>N1"A; t +O߃Aւ!V{7°@ȿL_7ڕE-/ +0ʹ\nݺyvhF -r|+_vdݻR clegy镯|ymU ;9ַ˗]vkЛ-/{+^[Z7ӝoYh#U۵#)1]؝f ej3̕r)8 R 'T CwH(BlAo5̯kg:HU5A:JI(WbzcpM=ǾP Я!wX+=I&(G<>9ɥ/$W^"@Sa*:SU@U =Hޙ$`1+$]cgmŠ/|lS1E3))m\(9ڗxi(!p.Fp1 k>??kbIG8PG =Nihk6h'\9rzƲn}l I&`զM|ץ]†5^^rV/< %\X늚#^48.;w (:;BsyB׮BzƤ;tXKY=G@#r-X~%m۶/_m@}|nXo|׾,V\_^sQ73PK_>k^)oRv7x;οꪫ^yPxlӳo~K%֝mf]pKL*%\T-5<8t8p֑ooxh=<$&!BDkKt!6韛" rOOz"IDAQRƞ7.ŋKW9 Z }s.X@@2 o|4 lW Un~Flq̀_y>{ j+= htyYxDy ڃ,dYzCҝZ^gG4=8˟Xڙx^MNN.m+ /}Kk;y }΀//ӳbc=//_oﴠ2⋟ML jzzszիY*ly67z[ʞ h1Je2\m />vU2kOǜwk=QF^o@ZʇN&;N 5S/01́+|RAS7\GWoFĊ:q5u1R9? F'1Tc4j"KRWgː-_a得d&&z&+JBqgB ѳ8ERdHrnW`(e,!H CB.X H?7xwq'rD-k;y9lp]] Y+(_S̩H<ܗT32i|)g_q|P\6qcX~Ew_ypj.(ohU(;cYL[ٻ({{+\fO(YCl|ٺpJG]\|Meݖ%/ӹeť[V^bP iX%!NuR 8 @!Ōx+W_@ y\s  a7~Ky˿nhhh!{og0aݺu=wknÆ 6kGfjY[nj|8|#WbؖL7<g%mhVo deG>y'FEoS Ox|UAB1n<C2 -ר;wp#/ָn Wа#~ ~A:&p9Vu]z ٻ:u`z8t|s?Vَb%Ű׻r#<汘亭e[ |du֧ 8f3<@ƃE?YE;KCȩ;7J=S;4[4իFp=ݲYMȞ'͠y\_^8~?>x s1 :{W~e]z}f?|YOOOGo9Isc?ۏ?:m۶)~?ng!]IJ~C%xTe/w1@X|AC{z|u s$D~fyA}[IQ $_M~ʻh[^L++V rwmCe7Qij+t憦%jv;86\]%42a ^1O;CE-|oblL/eύE8p`UY Qb,c@sJrX'cEi@iѐ0*q ]j2Sꙓc=Mqr|+ !ތx#1$:C\r!kR 41֩(2³$< 7BdHwXcZҕXf͞OϷe{L}"-ncxn0g3dBxj.+:6V۝ٌ).|𩙣Aɗ_3q 9g(Z+`ZBN6%ι;˴C(m).%~,;~^=Ͻf@tjջ~DB[lYj7͇eQFu}t[n]l;i -[; a۷i:>W}رAO._|]SغR'ج:;P߰aÆqJeヌS6ߞ={+ՙT(F~qN`wsO&cs"F'j]z kذ[j"1\A9o}eGz䰜ui.BH\=isUI~o=ì{ Զjft0^1b!XEH^6$SVR HL04*7ըӉ p%$aICG4 9}ÌfZըr;1yȞ7# ?ϝŸ@Y\]<8i _tYyh:#ADC6ye9OZ\55ƙb%Q.:EHt"}(V֥D}䱅5wP[w{㟱 'JmB?Em0 8XbwĬJtȣ{|(ϼd, (LAm۶Ua.X)ѸZ=l }nu ary'z:aq֭]v#n6 L+yַ/nsb8lzzd.L]o~syv:4iNuG$sJk%b[ Z G...S~䤍T|;kD& ?2Jb@Y Pf#0ĂG[~̘gLCrdbǤr?Zh<-d4{#&^:~ee9'dDU昡8VD̍p'iƸ*3xth*ZCa)]RѢ\:: =@HP]riDZ%L`zY uˮ/[f᳂r2#5xxv.ø3qGhCZ&B=$8*"zG-+IWia=؃;",7θA[fjℝ M y"'qCtw$p9ɕu27teVC^J]x^:lݼdhqFdNQ ggvFk $yo|~wju%(۵o+@"l涹"_,s- Y$|G׿s;vgӠ&.rSk8ְR#lmW:ٺS ԃ qy&th|;_|6&oxDx!1M s^"Y8Dnz&Hx~OʡQJUpJjbч=ă4i*hTexDϭ`J ##1Qp 46CVKW(z.e;zEQX?,(fFdADcJr^z<.YM9=P`cd)Љ.{Td6n]ޛ8G, S.F .< eN_ѢhELԍٛ9q8!)$'`-"QE T~OT(8Fs "S Be3X N1 2 o[F4J(@BF-ߦKz= @8F:pПBt <,Wʍ%NMXzaF+J+FЍ Mfqr&*~䑽MM[eM;bpf );k#ofG={^ #-8 |W6/ڰa5t m`89-Q/*ְaæR\؟2.KDS L/x5ۚ Ov&o6<@C>/!Pe >`9+S<&ywQ9Gf8%SF7Qz3eO=4Jgy!7@ Pn$ :/t*&Wl2o{kbZ$ `i 5bˈq^I]qG&!:E6"5 kR 3p' <3PT HƉc:2)?2K?k|ʭ|bb&jo =MCqdZh JXop0ɾA9쇓x&c7`d339z"y]$J(ͤԬX,0WbF{A53w~'R/pbԊB$у62ZzyZ3)w';9sx+.HF NWX! "ӈa1rUE1lK4N|0ėsN7^Ϣ2Fc쒕F3N +?-_͇~UW7]kϴF۝'"krHh GXgj ‘sJ._J2t5Qi}Js ^,H'.X`ŸҖ֧w!$2БKF5?TӼל8c57y;񢾾ְ__^Stϑ"Fou5k uʧXvg5Ԇf m(;~mK_Co'il"aC(ȗc/>x(Uԝdf0湑}$[,6n2hq8}ԅ޳vz5{߬E~K/}B^:Jvyo;³9c0k׮X6mٳgOi_Y# j׮]erǦJޞ@wcYZ "w FQlYY]*J]KN=cr) WG$uļ4Ͻ!h-rC/ Ai*\յ#Q:aw}bGPMp3-4wW9{9=mHqt ,oR:;޹i}.x$ |& ̷cKxWyt<__~YTZE333ԧgƩ/iٲ]mkZpZlp.+oy{nm:vH]ZS9:[c8M< ?AIZ\,cF YEMl08Ֆ⊦ɻOCx@ _ʭ~yb׌Gx4E'41#J)wHr$ }(!% }y9JfS}t,jSuup͔a99dR=о4vGLT }N?[sAD[%}gQR>sCG&ԧ >U1%.QyA]3iޙbwik1G oA>sv,\m<7i%9}o߽-/)]Eݒ_n?=:^?:!rG-/!%%>i?H̋S7tEѤҐ6?oXvyy|oh~`SMMyG5לGvCV-w}w| _vrg!:bSNA+ݍunݺM 'b^` ?A}O^)ȯi%uZ9u /e̩ZGxh5-iNRc'(Hgȯ!Ɨ^Hl8J\@ ;w˗Cekgt)#ZQQ~E-0 IyJ!MZN޲֟2F<DD~c/taO CNPtU03<96ays+ F8c+a'Q.DQ#&]Q\W$f\fY%o>0F=~mo޶Y|'r}ǿ?iSu!4 K! :?,f,ʸp (҂sx BηZK݀H FcVA{[^1ARν0xyOuum/4KT/6p;8B+gM8b%[a΅7cw}s>x<1Λ\Fx={L4fP?>߿MozөBQiw;!s6OCY=_C!^"*-UV`晏lN})O#B/>:{B? U9B&&,՘I,¦+M}Wo VTy4v^,4愊,'re,MnO{9C$9}|{Oڄ .__xᄁ'W)heȳ>8Cv EdFw]-db-agj=KШx_ ;&hH$ \5yYzoY~Yׯ1Y+1^ouk 8^S{ D[Uӿ3#~#M],1֮Z=R& RٟI˧sj%s\pʅw_}!fK?[S۵kbJCQXxG?sgV7^>ܡrfZ<ђnRA|!}&Zzw뒛n%ݧF?яBjz_Y4D[L۫kㅯBۤ3:b PDzC ih|;pEݕ5p]94r1@n J 5 np ȳ %+~hc7;_ewk7ы[4@;%¥;l <:vp.EjlV}vp qo޸qGm:$H;qr={Hry.мְ{qw۶HfQվog?GŚee d(ݻ7u̠yiunuq޹,׵'K#D`qW@K,d*.*$c'/iX$l7gnlKyPnE߰xÇFGNC J3&|a.klg3^F}\c=${+nteXc)q"wܢ-kQRZ$Y*DDgo3ho A(T6jQYl+Q/Oy9qR4{Nh5φC 3 tq~PoE()rr YieF;x: TНJXr }Zcֿx#6:El'c;xR|Ẕ~GOo=\}Ð1Lb?ձʜ !EO.C4p-"h2ð= e0售pP5֝oB̚:ޟ$ўN5N'Pi6/dT`:+'Q^ MݽNH?@O}Wx:c/̈6Vn:"Q Dv<9S/UCWsckU"rF:j< CA9?Ryh XI&(CԠX]<|xф,O>܎} ]M{)S;qU~&w&3+r#:4P)IxoۿADn<3}OKTq>/>r\+Xq^Sׯ_OtBb)V6'{,A] ߄^:wl!n/r #Z2pBVsNQ*JAUc;=zC#kc1.āq]TS_a_K*÷OX@`VsJA1%{ܕpפhڔSOWȓ(ezw8vz4#ȵzɴܹ>- mܸqmxxU:u!}K{[ 9K\ 笆9 Y+TfyLàD.{BǏOtHoNa^i֢Q[LuN7~vv6;}?CПRD=5:Y|8J %<|O)b>Qsf9^E2!1 JX{.XK+2 GЃ5Ä,'{lj&~lg>NBYd.,Oy=Yn՘sqhb7"LQĶ6,e0~uGFh)y&al iaP:0e[B>i*P!AJiǪk48η8TvMs!#"SР;ScF8K,!Vh.j.EQx: HsfWn=r ;ngCth΀3p %U|6!ء;O~i]6Awl&FG0M7[ \s#K hãnEG&ՏRUsŔ[SZ\zl!gR655"o~R lbj}ixVDqs;FWIM,F8ɑ?{ſce }G_F}1jJ<߻о; O{%mWE!0T4M%]5$r|2"/'YXK[O$ķI]MLBZ=Ҩ,z{AQml4NǨ~| wxM*>rĕ2/3FQQ殖Sm c1:}@gؖMz\ԥ1@㸾c׮{^R= ??/+ɣۃ>W-XS@+ ;&Y -X o2;RD%4&h*5"h膐;Qq VhE˶0:ԭ?8yBJrV|[޲obQvԩ{޽{g}fǛf)D-$g|fsyWC9R$2R:/| pMqL=hx9ŀlUզq̗6V,b35 <'ٙ0:::Rypn{Y NYRu+l8}F -P/$su%%gu:q`Sг;O ;iTXGed?1f'l\S&}Գm=F6xȷ7IUʡ㲸Z F12j,2zA݌m"lƬ[g5 10y:$Fnsc_g埽En? 5k =lNE=0 5BǮ"^6W]g^9NJrUo<ѱ {Ď nW%Hd<)u^`CEB+PR+N9RZT3 Ya͍-tR'K6a;>AZ;sbr'R/(k$fmŀx7Q9Yqwz^h |[z_ðRy_} _LϪUV-句|іTGAc].уޑoM%\r8g&s*7mz ё[064Z*GqdJIK Ͽ&Y\C,w>JT; }031aܪu$ TD`;lF"5۰ .`DVe6{mm^iD,ڪQOգS c9)+uyzmͦ}N{u,~Y>*XJ}9qtm w'znݏڴIX M,`X㰙D#[c(!<2Ѭx.d5g8?t[I2^c# DFj90]RnTnUSbλ?7F-[jk?Jn%+5t}ݮʉ*3,aɚ?X3FD8\}㪻~$cašផ?=)Z]FѺ7=s9u P <8&J1R$겡ތG@Gqm'rYiX'Rsgo~ցzǁT^G>G2B]otSkK&&7###Kkj=,CCINTp qTDe9DR&"U(F2^O( 53C2KI$CH7G$Vxjx`uIoao 7^g-.C٩Ii\)Q9nOFJHf66QLM,}c;_[/_bECG 8Xx1V#NV: )`疵z\M:zQtURޱ!61gp5ngj"n*`~ћ6^ ^~7/* :pʞuM^30X\dcU7vOrAUfyKY&37`y)k~aH?^3Yp-jX|cms-cm §2*tJD[4~wn>r֒ܶe\@ι>yjl?ECg3mYR)w7sX$5J)^|X7|^>:Vקomo-#{Bv=\M6]|x/&}M0ph{?|,sS϶|wbw /|ݻߝo&t9ח ) O[P=fDB2s"1q _{#&7}$_Q&fn'@*:Ljr컟f;Dɔ"r 4u^@ R,&CRţ֤6v!LXPt,xt}4xo+1C湾Ayx \Yx5xK+6=z7? g[9<Xk5҂'5"QͯbEڎyJOlۚgo)_Q%?ýҧɊF!]̓-×:Y|46gO[Z/09wx&94^'8TNkΑF^{8ol@a٪Nh?R|&VjIlb.2oy^?ܳk߉]{r%*ikqt48UG+ls"@ujtWNO[nܠyozT[-ԛigkASޅ ãhw>488 N{wo@T* @ݲJh'[#50So^Fo\ 9h 6==~P !.?]Oە%󽖅NL\^CT=z%PGiHr90&!l ?Ac0`kI3Dļ.y2QBUWBDkdHQ<6KN}Ǫ.S-ҳrțqRջ,: /7e[JFK;3zM>c̪ZRp[/ xd R& "[ ]k"٩wUoAcwuvYz]-g(a7 n[gx@؃2*Qd}{GZ%IǮ W(CBǔ*f'Jk- :foi`]wMO2DlR95,#>?kz1aGO>8VimMjVזKt#n!z4Gh^j)]>&_xz{307_}=xؼ0p3 q:m, 6mZy^6/wޝ-m&_XV+z{{::ɓ^}jVk1J]S~~{>1Z$v-wuX#~o> ̻3;DςyITĩIK2?AHy8j~j'))mN$z.YN=[/&{%"W:/ָQ&7цxSCDx|Fb{i#(YsVf87Vmp(83/(냟͙ _TWOV7Ě Ƶ@Ob54ѠZ/kȗ  w~/x/ r~UD9?lzl-[Ơ=7~O]kzŽu S;'G;ߵMDZ-D+QαLL M \$#elR6td[fĩ&hCZ;!YLJJ,cƠ4{?gN86,W毽/`vll??'>񉇚z/6 48ɼu֘V{Oe/{YN%n tsk>^͞y~A=?t(Yא%;M䌥/KJm%A$H\HĜBȉÜA֌qnO\oߓM\;5+dU!#!56~XZ]ɩJ5ďόz絉}zf fZh3UA5nǹTPWC%>3k,ED[TgbCr:ck?Wgo|%å=Nv [҃_?>#OLz$%cQI"-ogU5чO1fgV~y#EyXI%gڰqƲ:cTW7θRV *['BŻPyd>}CտyyC2X4ec?>u͝oy[޴rʋeiEz7|g|fMhk=,jҰezmG\s۾{O[=__wurX\׎!wWz׻lűu)lO a*vGqEj>8i%RutUh6~:8V%+/"Z-RM&V=$Wղ"7f肋Ik'YXmT2YF ky$ v&tdU+2qGuQ/eBVzx239OE3[힃߫{t!.V^^)^ɻg 5aּ<- H|fEheܫ궏%_i6jM%[ n^V zD%k+ȁh:ylVH;I>Ă&⚉=S=T+ l`?p QY9?oZcP#7#$%10'D,xh[굚z3dX Hq!uM 1MqF$ME b]FgffN]OL#fX3@9yUzx͛/( 211q{ ox7 gW]/dkMyg͠>W?|Ͽldd|(Aj;vl讖siN,-ߵEOzžt|3JLq&‚+D"g9C+b!h6Sp皔g$2TD{ኤvebO9g J3idU: B2_KscEN(kM`d>`NՉ535jS&ZMLUԋ:N4N2u<ͫW"n4_r,lAUPzMbd?<ʹzP6u[}bC ^ScT3bBzdK7VU}##yX9cqW3@gּss^E.Ud[O:ӟ&WB_r_LA>h ե/t^9YƱzM׫yf=(DNmls.ҹl{]@MD:M044itRObkZRtMlIw 'H 'q3|0'~x: [rK:G^ M}F/#7 \%X$j 5~LքH*R"#qJBMIoɭ·IB ɚIIa=I9)3 f1n4]X:F q4d.X"_5@T^z26r kd4i|7>b"n4JHj:؄(ant+ܕW." 1N2E+֔J04gf˓_oMO:6FvįMŶi׍gA]v+GDjiޟmHHS7v25T&ǚeɃyGknidOaF:9VقD#krDK"[um-HqsOA\/089F&$̳Nnx,xD d@'1uxw;|i DuaU[TJAJ\^_Qop?əQYSxYY1m3 +'łu_bD<"!l c˔#%Ky`ϴTCT[3)EQr9dxNV愘ԢcѾ@udkA"1@9ǃq=t(OҼj9GT3 4 \qe#'ЭmN0C {-8n@ApI2H |bř1۩vq$ 'c&BqOۗ[<aT''^☔' YEi] `Gz̬PPƨ}F؝kd%&0Qiӆ0 ` },9q8/5м]ڳNAI__h+j|+wu& Ϸ.4_3sH-4o#os;͖k޺[ R ,Ay%T$Y>&1h\z՗hD?t MdULqa&O9ǭǹv2ȟ>tUڊ&Nld=F_fϑəܺ!OCD4「H@WuCa:];:ف6x*f 4R/}PE9qk\@my+ZG*ba^ d*mcsa2%qVD`\1'\:VwO\ [AR}OhG0jZ dp#D%_<4s*I ., Db{VNr&S%n3Z(U"u#5vOߘ+Pz:שǹ5^{,c _g^qUnՊ%\ J(灇19B #ȝ ,*A?'$hM3vmŎB,upGƎl^˹t=~E.":J!W S f-A׳d6r9]昗% V_OX$E1oډp0b,6 !-ڏUܮ)06zC](2M UZ]dzMmeQ*iAo=0,5SOr<$N̡~=s*rm`HbHl.j3 汫 1cȈ(٣*-\=ﲊ& ٲ򠹋,tN 3:tK׳]:m'J ?=D$ZpTr䋢/F i aFIs= "efRϥ y7wUXё/=ex)[7҆D$֪)O%jd֕'=tf~rTM9Pg=-;r+r̙ɴ$^&%P H(AxE^kX*@ BRf&I&̩^笳g3gJ h{=o}^L,adƑ *e- } ,؈QG _账W1Lg qev,|) ^wCt-^ả%4ӱJTݓjڄBTsX<:tmKLl!K͂1&eR["H %4ӴߟYۢ{ijM B 7!PVz7CZY#Nuifi% _)Zv(4܋:EZmk{2Uі)Sː,:X"9eg#mHe`& b|D̄^j*gH[R.$V,d9d;MPueL)cpb,V)%.|(]nʤ.sKwǓ}*"N#WrX :r`na;(`\Y-=8O 7fp+; 8Ǽ>.o2'm)!*.okhxn{^7kÌDݒE#߳`,uFC8c4;>A藨׉);.`&~ڏ{=yTb"S..QFgK^WaWAR7ij 2ܛsC6;\k Cd$኏+NLU- O@:5,tnn˲'`{\1yÉ*0r]=oB'5\a}ʲ8U[LM}:Yէ`Z)\26$O{GGnc M{<,iLx4ڀ3 ꏃragoMT j=RFİ2ar9>k4X+ёo/LK8oHOg ϘI\^Xĕ&—ieF l7i3 29w5m SIC3aHܹ Xr̃sj.]ČIXLt%d'8]kW7c f5ܳ6x3 =DdĮ|.wsIp3ў̓ 垦XY宙M$) =D H=wqO8 , aM{Dd7quƩF< fͨYԞ-wB 24$PxC6e$jw0&6TLReȐ`* 鎥559څy9t\s0:I!V)JZ9e5$ t4Bja8,v;IDeaU2d tp4>oQO[|f3m+c0!j @#$r~]n$$X^37SE0zZ4 |e/mb֯ZDjfeMZf.ҵW8 Ujn2q5E18*.iW'8|F*#^r ɰbn\ 5O2<@@C,K]\E䅤 \7o=7wv1ɮ\t=PGھ}ᅮ։_]p'Ώnj by04/HT*lX95n aY2Kɤ!]4"Zi} J)޼٭Zz腔~Ǯ;htJiepoS]Rx_#7Q oI4Lewjbfp_SY f}܁kp'HaQMW](qs `euberp; u^}ƴ 5eG=gЫ6ѹ=/C?+8 w @7nt&ReC p] ܋*w8e=Hs$gdz}`Z. ghg8x?.A}^͇o' V*k0-FmFD3m0z2#&YXffarX+lݒj&R+6t!(e nmo:^u9`k `O2CV{V)ϲDn-sizOùinݾu#c]Ƕ]:EԠ;nrZ8:nF t9q%aD"2J󈂰V1LY={~2l}M,߱ôwńt9OQbG kMA'HgG"b.Ŵ2'l4b:w,BG|g"~r9?{9x4d}ǔ<@$;v"С 5QPQd]A-6hYmK+ZY5LmThGҤ /|ɂoֹ+Ws;w0tWu `[{ p{a6iW]˽Y$s1p).HaowCN(,(ݬJl}9Q!m"X%;kĕ͋6td:0 5]0t;K5Dlڲ}:S^0蝮{(itqs]__B5ݜՎ4P"] ZpseC`Z焸@urP/ o7 eXt3'}2,,8x?.?]ljD<AڑJt]J&[/`_x!B__M+~5ڵba&9S i3%8ZTa܆af|bPgݱHwXqmW\t68Cv s3{Qޚ5_]pf{qq"]w@+,Hl5t#з˥WW}8]s%a$1s U`WFOr Z\N.D,tR)Ŗ}i9-P\R6Kz@/m hOb' :Z[o v7L W1 A`0k\qA5ty>CirM_.#c{C_qwcSv #4j́hWY@_lrh"% @Ilخ%^|PXev k|Ȼeg`kQպF%N'c3l՟+ߞ' {r'qyTznh< b{pOۆeyUAWy]`g:3׍wS$-K5e"aӶᝮk=8ZU |8@.cL) J&- s+uuZ3wee]A|Zb!d.?ws: |\X]%Y:V.Xqzvԥ[S~rg9.S//h ە+]Qz 7;r&b u:?'<\gZc!O#%#H[~֕Xt|+[_1[Qd `O"]0 za8*q,K Һ* Hr\QV swВ]b\)%?7=)ܵ @2haKUޝp@/_dKO*?Tc ?ypL>̧K[(odD0 )~Uյ! |=Ԫ[VV-0 y$KP#j9ȃi^%8/Q+VnҘvE1Ro4Hbp+û)AL [n" q E r@}TA&3%s7ыɮ\T\'{˞l/rȭe ҁ>͑1'CFiy`/Wu,`w;ĤVDぽj+xbYͬk..Zn!#+zD؎-ۈP2[yxHXF#]m[V7ܭ_|OK_[~@c^Yyz mNN}uB ,rJ/gb9EcJcHN}\s*v%keGGX0BNc 2MM^aYL%V,g>ƚnZ%9{>XL6 ceiY8?z%kZndwKn-kZYK#*y:ݾZ~hmb.۷lE?G8K~\.|ɭ?09ŀzeǿ2oլ_ZeWvK'@=ӑc0{AVrWy}m҅ftU[뮧g"/0X\XaYwgg2V- ~^<Vσok2]W X ohqYꅛ  zKO_4aCE_|z*nd-l{ص&-N/Xז@۵zK+Gbw{}t-sga|1`qwX/ ҮSw*Sq) =o[C$y0/dЌ/&}m6㕀NfX(e-@,S{6ڰCEd:cqΥ׽cNwd2dmqt}X;l _κ>ҍ-g=n>ӘLu&YSHkĚޕ!̋b=de>-o/$;ŹubVON2־\%b9Jé;7I콡0$a]$<أ>`w.] ,\ʖi/ܼk_2HR<k?~qpOFZ{}1w\hDR&֞pZ^>?,H3G&^*aݲ"2֝6Z%ȁO|:)]C-^-pu@&4ŌLhp|ZCSP{: |)„hTvm^-,CgIf#a,YIɀ`vު?5oqh!3WJdye#?c$@=6[wWV \{8*ڷ5 ߖ[BEW) v= (]2?ր1;Z8~(D{h~K*ܚjYW'Jo [I Gd%A`߭b/ ^,LҽO__s2O4<oqNNk>Ozw[h2[/\9׺`n@<nxm%k}]"-)e'xFEδ]LrWh37J[9ڮ]C\8i_YUT])(&-nح-?s_D+dX`k2ˁvsuVxMДm0=3]2:m-mG(pł[a5j[[i2}R7ϠI ʊDe|P!eOA}'Sj0G <3Etyh*Eր Ti2Ώ 3b(蜺r$M75 B9BFw{Ѩu]D|$n)wxSŶ:u~r2.sW_pߖer H`=ujk5)JцJTͷ>砟/ ޼lBY˖s+|FS6"a"f ⧣+i!H=PӄE~(h%Ҫg ciPpPZȭf*AkێqwX>m..djnJ4Xa|{Gxmn@&Li[a+l2;? :5?|\0=[Xd P$wz iˮªg/ja;{Lם H6dH w$dH$1ns YJUҊВZWM:ҭ;/Z.{*hrc'3aogPm}lXjN3&j = BLPauɬZXE+cО{̆= ̧ṰP[sJ@>oܮgo/fvrbd$@Gٖ00iB2AsVohV SnUUHCC-<v  fշB&FXX 9f5 r%KN+zxI N0mA Qhs%`L]|ڳT,H:TJҡ=HZSKiw%J;v[o}">fT- p&TL(?,3ֽ^.P/Q h 0_ X@msQPɂiUJ%0r#Trxu+VqpΨ\|[.3ftɘ)YF2 rΝ۾7/Cll̳nh`eVTq :I̫[:fUaCNYժ ! gۆsw4t|=eXje<^5? ۶=L@bP\>M4@Y]HbA(_3\ Q+v{1`,z˟N‡&EDQ0WQ D<`Θd>㕈n!g(->BlK1T-ؒ-UAQ:4n>b>BY}E+V43О=ST:(rR8 ?ӯ!ne*s} ʀo޺ Wtc*Zk , QEeCGL E3 &A/ZT3[نgeZ-0MRzFm:5(´Bnaz|WAY*0[raoXųLyU m*a\*JaX18etnRtl +P.j4l oOP0onhjAaXs+Jn}2g`,r)pܤf0r3. ;jI%$,.YPa9x;XޤkU F/ п<{+QSp #_p)"HtAw@uRΣ(Nb|gsߡQ̺1ޝ]H=cku`'m]Nin&Z-0} ]ܿ뮻nGYD(H,*؞~:cZ.koCr>>wziZ-GE]JBkr9@?d\0{Gb:< 2`@ "O܉qID@e\ŰL3f,,'irJRj7 붏nST0&es6̳ܦmT*)&BEbH!"om.x ܱv ~w]{j_ ؗw'-M滐~Zm6e:e1˒:/I9 3 4 ̟ty/v$ c iߎ"tW FY-I _ ;ܲ\;n%̃NjHG?:n|`҄Y-#dGLf Q%P|X,.C&w<Ӆ%FiZeL6#6]16x0ڵkGO:?YKTdAL)! 珦u~> qy| \-_7VbV]b]w_&`H>1 x r#ahҡݐ4ӖiscnF2 kZ P~Jf,~+Ckf%Pf5cr ϬNrw{Z XU릞@/6Y2&*m~k7\V+],!D U2|w-0t0,b%3 O籀ߢ&J-sB4H2@o߭۵ϤMmܽGgU_Tt$mb#:/ж$?^+ml[<,|粷YxfX3b/~+ر.mVWUjӹw{E\<8dI=0 SWX"RJDwέz;|[i}cL5}v::& yxء}`vS[tǩx Np2|3 c ly@w1KnAٺs; N#gዧứX IIV,6q7߰%L .Y +(v'qxzS Jcϔ]R@>Șɬq^IdshˊkB[=$`׸ϴ;^ J#20c|tſXOj1X?S ۪I|':-s3pCR}s/6N&SI;,n 6́r 1OtAcr[֦Ə15k_7tG5X龇lof>wW}R>1$20“\)z3a% p5nd@X@{j9.ZfY6ʒ5eqn!Õ@21U3N`e1zƈDd/ҔVRC]Ƞ @gYXaJ&acMEJqaHqqdgy.a{688)1ѡΰ,9O^% 122a l;1] Fm.Ϙƒ9y2ie 6H5woTDrD݈Ȕ&BC.\?B'*) 0́d, xmvqzՖ;܎ yVmSw?L5> Ү[,hG[~6 Ҟ =%#U8>tT [J &%N8ypV8gYδ-Gt疓/ 0AG=9{oMaOܵt`xh´/;c1d҃U/9MP<CX4Bs hz!a4qJ#-HfR41BL4e\M w Q-tfd6È=N'|[ĮI=n˜22 }tB&gx)@9Af4{"LYmK1Q-pέ{h.lE3/ *\L @8B, )U(ZOIjc7$7iGg1#Y'Q2Ʊw;%00dPRyBeDH0"Vwc3Լd'edYJQM*?Lעt JR#+שFا(}2ўbrp;3Sd(Dw1oY;׍!dOQ<ͩIkA{:۝H5'yɸp"HMQƲĐImΝ,I%0g.?`tbs Ey&Y&ȂE ¦ʒ_izID-J3ěexd%O}M7d3 _t+6$i5(yi Fa)(ƒGØ%Vc^2H5^6Szxte9`WRx΅&'E] qϜ46 YQ8g~P8e>$N t(u;Љ:i7oڻwa3e iAŧ߹K.ِeG?z?A:+KylruZm$MSO# 9FJ=SVk''O^rc(_8}CVQTJ e P=:(ű"G'~{ݩ/_s/Ŷ1n{{P\~^ťPފ)({F^ܳQ ignwXjs.'3dB 3>qlY2BL[A Ji{xۥ2➳ A:oXB2Inrc.Y*R$y+ȠL0 'eUmibr/_@!=غzD  Fat+-OU$5#AfARg\Zk4ZU6}Ч 2#M&I%8:J2(f|x[[nI hS֒{8R ;m_%YR(db]$![lmteeUITSW{+á'l'騯=3ǚWmYxJJi ZOJMZ#fDU[E"IøiDuj*LjLZRMݐ Vq ~lEDb Kmh8{)n<%UfʩQ/6Ո;{_~n4ڄcD}mM1ѴGwP ԏ;ё7K8Ŋ3+I'<}TrO *0Ew)ޤ<3^90 lKʧ?G~ֺ jzݤ&2)# iZn]X㱔ALP(tI:1{|.5S- ݱHJRm{Ϩ^#2_W^qE]?00<ǿPCi8t__fi-.!d1,+??~~mIG-Dz^8›n:3!O|h+Ly{z7>sժU(1<.}Vv{]zקoK^pqM` W^yCCCs鳭Vkvǎwɟɿ}s;&/m|M @_ gBݷ~7g KTDmt%)ld8Uz^<6$|ѭfsSBS5xnu#=2. g>Öq`͂gy>Yy2I`@8,&Oi*d@K&i!D&S`$=QO<%92#.88[f"\up1C=eb]ƫ¸g?T0_= ۜQ2uFtƆkfxO_/\M5^xP{ggvfǿc?I~;26y UX&V$Գ6I [~=ꡂ %qg=ƃaLLlR5Tp(&lUOS64Ј{~>{?mwj6g4xXœIϔRmAFl3C{>̒O}h XgAdE>sX %k! <ä/2N @[' !,ETY"Y㢲X oUktAws8%EHUeNJd1BqX.~ag )M~@,0[ (AOef蒸2Cã$1:Dݻwi@Gj_tujz[A mܸiyk?ozӛ"b /-j?'x׏8ZEBj_R{NY# ş, ox%kUVm"z}.CS^/}_<% ӽͳ'~恁_g>7p~gb/ey}؅smi>3 Wk~ .M 凢ldݓK~~7pA$M-و0UhKk䲑FA>JWX%,>K,䩟h<; GijVulfcGߺ@w(Ov(X'LPEJԵb &F*ɪW{gnyj:5aT5W;wg=w˶K}?1HAnO6͐jo5\U_7o_놶=y.oT+O"1cJGO,D]/矵v`OsEf{ī\LE"UCoWf{~a% w޹?n+Y<ٮwV˱ӔR˗[v:$ܧyMT&%k 'XYv, Q"ޮ8%pkhK| lkEriģxDL]J3(p==O5>pEeZ:!%J|' eRdg*,N=ϙJ9,JJWtRo[%v)/>9jdt8ι\~/*E< c~~˚5k.Z[{uzӛޛ_^g.AL:ᄲ[D|;~[kW>g9+Boٺuhw弈rB/{~n```l~ky=RXf1ݭ[lٲ!I4n(L[KrqOg.' )cWfi1;}D@uktK!<)Zg ׿+@pG-ᰨ}6IV}.j猰xP`a9ԧ^}WH)OUa`CCC.rt_z[S/FZgP8tWg1Kk׳P\9-[F~'ŰOs7lݺu_zP<9/xaim۶=M{{3'~~=~},>zւ/>ell,ML~qίj9ۄgtr |!Fu$4>[!2!uj$ g"h/ Ĥ #lDmF~F)=Ѫoy⛞YF"Zll #_arxtɴ\H2?t T "8@e&ʲmg_sn : "2ҌNf}*3W=m/ iy~G*j/瞺uT[ 鎭YBsM`E}y<G˽gm]3sM1&lT(Uۢ7WםLsd$!ǩxICUՄZ#Gs]ZR$+'=vTdj `!9#ZJcҹi&qjG.*QjKxay 9KY̠uso57V\K,XEu4voٯ%sOIOzyES666v{ޗ,~`*.\۶m go.\K%^E^,`mgXJH9KnXj3!⋟p7o.݃r"^җY,˲Gt.rROzғۺuP ԋ?vW\y -Qw}yg]+ڧ=a +)e{!Lef/wqq;[ 62,k9I\ҮBJY{zPʴ eąWL ᥂3&=ԅypH1B2S7xUq)rٴ?u&(\܁!,u&GYΈ8j$<[ g&  Fd$"RuKYsv1Y$j^~ʋW8^.sX{Tٖ!RU25x\W:YY?k-?uUaZ+K*TL8x䕵x2ٟvޡIp_}cϾHjPVI[IUYE+] \mee#C;ptPʯrEmƐ^ `f D^>Wz5==rr򑉉}ǎ?>>~ѣ9rÇ:t$$m۶] \Եwy=~=y=tСWO.]loy͛/@ TyF1ۿ^j/Wv7>) իWo*/?;;;?zS_Ec+ +-[֟nIM"GqwﮇGkBnjFZ_VG^V) `zqZ-9[˥^'={|bX:| PG3xp ր-#C=QUd K8 Вtf'GN2K=/\s(-䈉0r$C[׹-Fx"Bp. vG5g5>e UFpi,r.#B,dg"eTy[5u7wՈY*`Eg3pz7,4X%MKƶoU:Y[7Ыi?s袱'n2µ-ub|Ӧ B6v|;iw g))d~0漼fD5ayO d```?k~яwƽ;r*һR|E,eloZVT';w5<{d1$ v YxUyzAZ5rsp}o+-IKNAt#%Hՙ%(4V\s#X*=~=~ H^>m?d1=[.=|<1Ig2BD8Й ,cچҢ  ZH"m0>PO=20(V3ַh'Ƈ{sS\eJMKYeEk/\G:iK?? qKҦȯ5 kqC~(+XOIIGh?JWQ;3tbǀ}N|n'r;~}Qv&x8ͬ믿~CV[4Fl6gw՛ So}q`˿ܹd+VX]r%mڴiVWj߾}%y[No޼yp֭xON/~;%ނt"+Nt t+\e9+-AS3$#gG;0! Ő̚H ]!!::\dlaD r H{ZB!`KW.7NK@l]uYK%ƵӦ?8&#~C__;N<@=odʸ V]YKk \ҹמqF<$xA q\j#p]}WIyFsxgS'ZJ!VP:_[W,V7O~`gPGHj']LZ,p8Z=d)fʺ@FDž><+1TلW~jO3YˆVՕ$VլCuAcWn{ҕT'j<$%kQ^\XKƘmi[ƈu8zAO>/SW]v%WS-R"gHNcIfhP|-&2"U)GAW]ʻ~+DdMѻQI& Pi4{9/}3;g@>GzӤ Ϊ7:ߞIbY?FE卿o/2mAAD ,u 7T3ކW$ĬYsu|@ID5zJ2~ފʺADKm3n{oP6DgZt8Pܗ5o j:5oxg m^0N47d6f~N\M1xE|pNGߟT%ezv|wǖuh7nZ08'Bk4]y啗,Kn˞if=ss7Ϲޥny}aRKiıGa/ X@G"dP!_]p?B +(0F{^/8b][p%J4ά4%cG8֛dVG£eCz|dө[Z87vdiD=rH*jzXZ|0eZ8-BqeҳYqXcd5XМŃgǵ@ Uj* 떨gE( S-!W&JYB"y &Gs5I)Y:^$/Y}PS3Ωʎ6:vj*%̄Ϲvwz"z01"/3Krв[{EXdFƓ+Ȃ1vS(8L4T!>a|=c3BѻZuj_%*F<$c +$g Qٔ295Nֵ2\݋~5I퇦3&UDŲ. |Fk6䭸/]G.hUİc&Cpɔu2nCiUxFca-0h9)PV?B d9e+gu"n|;Z;IDATĞJ, CQ&/2EuڊLy&E˫Yd1O[ +YP' Aoc!y5)g86c"o=(D*5o2TY1wЗ5~}0-^g z:yq < H£kXepWdԘi QE{COy`#Γ<#jmI%w2FfxcXCkjoqf@dwmPdT{~cLsa=#F>p9gR ci0ṙ`- MMYI6}: m>k77ъFF!:jH u% wCnKu^q,,2K4饲{\͢RXօYiR``&ҕ-2mb rAMo꭪w~߼򴓱{ϕnذf͚< {GeK"^2KP.3-! ]fw \7e.y7Y[lVH'?Ys~"k8;Yﰾ(^|vV-\IrP"[|3*M[Qew#G(&W~5L?Z Ōel\[=i"WAwZ`d@IZ3k ѹ`Ukqd/Z"ϧ4b,,R.@Ώ 8ZyǾ,o^Y߆)J JhY#=ɰvE/FYkrtXC+FGS+lj EΏ탎yȣG2K(;F:%5{:{OS_:t<'.#DKzXGA 溥(>UZ)fw!eh rtxxJ}V:^/fQczZ9Ġwy?vBsOv%kօ12ykf͚󦧧{݇i"_kʕqqW~އnirUwWC(ɂr-$Wx [r<ڨk(*70+ _2#- p𧢍}idזq1 lz&4:RTkctę+a #E)D8ZD㔗X5dsʔ"֞ߥS BZ]k<h[FWtD ^IbrMCٽ9<,yJz!P^Xd`D+*F?U L̬Ar|g(%*`VA[ld&uÌL<5{4hKH| e52HtAjUZδ;7_87pGU <`"<nx1ymGDDADfj@]:6JJD;`/֩:xQNiꡤN(!K>'pX:LA4M}N5wj=:FAO Yzנ@xEs=-H 2n=( )ZQVaJX/5/}6^:Ypc5d2J$PL e*ceIY!$t$%K&; {1YѣY*x!6l8<>epppaY8nu]2^;~ rVkLg\p.8z葒лw>tuAp90k9.O=tP^z6l.}kw {'R zu{]sc&ןaLcvK<]:qYHtYCZ4p<@!չ9:H#(: IGu>2y6@5 t n4:1V ZI++\ & &st.SJČ9еgF/<whX|3a#SqVʠNg mPҚxlFd0rayP,ʞ3sw d$~fJxƯ0bzKnxE0Byeej&G#k=lDuY}SbO7|/T*Ç{zܯs j8wOGj8c[rb-f/Vޏ ߴiƥbǎ˿"I>|Ovn:}3_[~, @_Q$ܽҗ /і-[6 oZv5\sioūVBa5yW{b)s#*_S>~'+VZv;zXL4+`K#ІEfh(f|36TuvsAZM34Wذv(R5"q(pADOv$9˹{5Kbyxũw(go%m s0ӣ D1qCF6ض>gRmwk{,~D9pg=yjX3RWd"+,B14Ijsj}麫,eg:5Q PrAc/읍' i5aj46O\ Dƽ4}ͣ X~Ɏ ZeWYKqyZ{\FQ:Uq0buVqR_}[Q PE;[> ,xPuHXa5/NY8ŧ63Zx3#kYO|"A?"< (Sg:Rf FTh=EǬ7yc$><$.S0T=P{5YU&:gJ"g.g(f(~PMImz*f)xX%iĨ f8Ns*"Oٰ@ȷ\dy.z0{p]MlO:˗qފvPQJs" -R+Apw"c 2HU ޸.ZJhngws%<e {&wY;yeO_p Hu5 lOQxkFcA=x잣{>ˌduJjT; gRgIY u45Z%)1~BvU*]}+T2qquVZYV럊YT+Igk9 2.ooseip[E,ޕ"2U!*c$Gzs'p5#pt#ɴ:`2P&?:EDL\ _dJWZlۭFHU Az#h332kD <;-F i&h߲IʕM]qW{vk{- xsJ=˽ԝ[nٴqƋYfsD] H߼i'?ۢUW$I㎇{\mYx`M7ry/|[n=W¹,v>|;۷s 7ٶmkZg-%I -{ $,gނd&WƈWr}zi6mh/̧K[7]aM$! A2yJ`E}@/4e{E?u/E6sƍ2%:wʾO;/ŎL}:L !Z`("̀Zy@t$ϏF*Sk7tn9x@k{i?DbI(K)y||o9heijPwT-l .^U\l? ;`4ag֓)C6U1yDЫ7UPwMuk`xVҡ 퇸`i) griw0-c)Hxѣ;fAڱM Bb0'6Admln?$ i6<2[>VϪь?zƕESyY[ nDi 1|WX ZX<2 5hĐ!M1rUU ^}U>duȤnAI[x rb Bq$69(>里۾OYK Q3q “V1-J&Y&2qZe㳖o@ZB>+'ө1qP;|u'~޶2v1z􃳟sI9[_~͠##4?oHXHѸF<() LYQٌ{VڶL+PZ2KZ<%=y$leyc 7n$UG,uK茂#_fbH,A+ѡ @q,z@K΢ږM\M,;b4QBVAt* \xe. 2LuLw_w)YN?OsY7Ae*:g]=ZJ*!Ħb;`:zA; _P}A7y`R{LylK .CӲL|ZÑhc}hcw|w̎k)b+BYJ3𷎸1jAe6zؓܰyu\M=|d⛏|zXf4c Rȴʄ1A^pCmg>)rܝaqxȓ6iV }e/Nyt\}K_ky F0kogoy[V6X=yXF1(Yn\R,zϲLڵk_OC"ѻr'd*}yEmywֳy+_yq,d __{_g_x pdZԛ۷oG>wᄇ7AmZ_}}C׽/ahh1e]v _›~{OY8K zjkĺ3b,_n$W=o=;Jd8 TQ̣1e1H.g;gyy5kVbY}]">LfCjS޸ן-ŋ#L}6#F<"v)nEq>ﯾ={嗜u'| #x_vw7"u׭ټ0?ԖIl?{CS6_K<<ȱOO!=ߴ80jP+/ X&N`Ƴ;Ә::$XU4tbZ(Ć}zj-iU q"=n3uv>P& | qf26kht |t=s$ho]M-g\ {>5M}b1& WsdGXjcONrK8fjڶ䥰/ySN 9կ~8pOO6uXd߾}ڵk\߼/}\YpQ(J9U9;ޝE]yAP~z/u[,}̹OVAL/|swo+/sJmݶnoQ>f>k/.gwcE>w3g-um%t}E]7_r,w] zw!ꇐ|*.2ǔeNb5w\V1/2-R^Il&ăOqex@چ- t=\R>- .#iÍ ٽ(ҡyB(?ijفP` ^2慄d_~cihQËxaL\ELxtU-cgyl$n}w3VˀB̫1ҩ,))v Y %oW.|E_{!gX;i-W GaA:੤#Y@P'^A*Ir֤.˧k&Q:DIj؈!XG}Mv*,(7I1ԫ?d*[Wƕ jX{ig~024٤W ( qW#g:ԣOZEK.!*\ Qrm "ăB:)ftcj>$VS4uqpnddmnlJzz:@Qωr]EWyCy=t? LVȱ (^d)fBa"Q]n hetu7pÏU*`Ag>w B׼q\u]~~T)Z7Wرc[Db䞄\E^JL|O<++^_\将a޽ut[&PYozӛQbn^z1 W~v o@u咳_Je|w s F,==q-WXq?>YyRNXܛm?{Mo|ss( @LXȴ?{G};Ό0*3U?2Cww>O~C;* N?]cd]"}V^0W2HcV/u@C6hcJ[{pɚ'g|G{>Ԅg\6zV?"XZ1CAJT(\/10RECYE8cAtDf!O ɡZdԐV.t|.@ed%mEb7;JCmMϑ"\ q"^(U3&InQ Dxv+ܝ 0^e%r02]%/$&,t]tֺQAYޢ ۷Ye}mݻwm۶'~+J"jfypp/_9]v=\bM+:[2}O.ЧT9^~r"$;SW4MwP+k+ߏQu프>Λn nUE?פ+_^/.$64w]O썵C>|-oy>?|믿6m۶1Ǎr"@_j^ͺo43#+*bBJoȊ:0i lJ%>Ż?quErZsςڵf[Y)*Ѵ9Kt.}%mec E%: Pą5_8ܢL v4ڊq-sˈ f5f@­1^}{d;:PǺ R6ӧQT"V)Q𤒴֞MUڶ4vɆ6pR\x27A$f/k Hn4)npϻ_\Q*\vG2H &19|<]~՗vdzֱC_=_o~k׽x/b> oY{wojT$sxA|"8=~liJth'F%5V7mĥEdQ](Y.hR=MQ(@ HC8pGPk?`?g=HUµ+r]AW M7ntoxSN?hpX@&2",T l557b婕JeQv=_nӁ:{[l.%Z ,ԹZ nZoSPRtuw&982-%aTJ&@'ƕ-Zt_Gv~u'wThRVXx"ލx;&(3!1*. 4DY& #2 *}30rHǛ;cOC 89͉z^6VN- /^uS`+։S9y6i٘Hxh \yrZ֝tR|ۦU(I)(H06m*H(*Q¤ q(4LP4eRӊҶ.4^͹ם8 y:D{N뺾\ 󈃫qAӦ#(XU%Ɂ:I2zf*FY!N_3-e kidSAe'S'ӊx?Zn^v^Zo RJ%@RVQ^~R]7|t2225y->==} Қf"e)xb1b_K;4? +/'խ\=ozӛ@}xxwu1뷟1k. *S~wwϑ^zeoD~{ S]g}r$ ;u= X':}?gVI!0Ptt+uǺrjДDŽ* \Xgu.qIX#OBkP͒%P 0鮬 c@y(݊ݛwl;kPBJ }]wŨV0cֆ8=fgFHqyɶ_1Fsɜ~u%՗lS?Ny[gY;6JcUW3KM}^>{{7 &l fyɤA7Pd*BpX8@v㡄1"PFZk%̦Ti6Up޳7׃oMÙ(YG+^XOBp;W֥R ʎH4$.J}_I.}Yίsߧyk!ph&Yzh)r6O4hqVt֠nZp5dm8e]>=@Q~{v樟+b؀;9~>m"NV=lI";cr`:&.-\/x)jI=t¸Xs,iF8wKpyL&  rZX6̍^ G>}D ʍeQ']D|~:ckQ։,.9z5W:Bl5XĈpc1ZeYC}"&=c<zh9CW:iٞ{.OKqjFR;*rG (RQQԥ#Ndg 興vxȋh g ijYg$q^rO}lG P졌kD)ΐ?kcB:0"VD’E.v˜q?tN+[4r@4*Ү+q|i*=j7%.y:[G0vUV)_@^s'MO9Pl2:{63j8JGmOw۰ܻnw)NE.>o|#7v^at`Pd{o&8ߛ,uZl; ebL·o4l$Fcf%{i 4V9pf4 b2n6ͧ莒L4 ƾcZ!MENt+"RR<=2,o J}W=Ise@7&PFsffiYk,k$mܘ> U !"K1}⫯{ Ƴџ>~%[9.[񪌩ˤeNGW([ӈGXJMI :/_xs'Lack[Z{6xG=WO9_Q҉DJ먐<\ k,1K&Bc-G m|O3Xud6$CKϗKtcNC S;# N)sCԄYqԌ0w?CXFy(2>4WBƢ,8Dj^dEH(XRݕ+}ʎ[H>Hx>,![_T{ळOބ_ tJ`N"杍PMZ\,\,_hTuE"O8g7V`W5=ȎBV"kϚcZX%gמ}k??嚥>M7g~ zlϞ=?[[Xmgd1gw`W ^7|4\Gknl !:uC޺e٩W{IхBJİ}~žQ-(.`C1z4aG,j^!CkڐOq|#2jCs|,WsE?1g^+$-8fSq%qUkW=s:"2XuLp Gu3F1D ֮%2 OCNbk*Ed3ՉeozOtqٶZֳYړiG X,&e5څib\` Mm5 iI"V;;31zV[#~`%a.Q9t 54~UݲF= 383S^Jp[=OY8Q^(t -Ә)-7ʊv(J%ɭ>HI;d{-/V86[7rtbg33H>\;Egjp_/sDQAk䤚qgIHf46 gm˨u`mQnB,fT*Z6yۼIH[c*p<;q4(uvW?GW#+sFˆ<7~t׶.?许GBvVb'꘽lk0?vARQE}mz%58D6z~ inϢEn2>)BQöf9s?s/eo޷&Sߧvo#AW~W^Po9>|ǴV?ݎVA,5A1R~8ΰ'}Oto Of Nw4GͺMa`z#mM8E7#0NEʅ.`挌O*嚯 4ۼ@'XN1Sws榣LWK䨱ƇW؈*)]Ѷe1o 35o{vZ3l~K9BwK˭@.@[oW]4wܰML'ʁGEGԀb6ǤQT8ׂ @$[-c sXLHS­9q)XV4 /vSSO<;p=Ay2?,Xdq! H{vBf(O~dsZ>"6ZvvT&eIF%֧cF8; ֯HW$ 8M#2bIJb6%lPСCs.6 ]ጌxid7xN{^} kH AX-|ʯ_xo裏>Z ޷|u 9uq~@K׭!ɡiu4eX/~MQt:FWe WzoXEܹ+'!ppEйYY#tKQ/t;?3"Ν-cexjspR]1&L*J1PQGc0O"=G>}7:|Z(joH\*Xz[;\>Z'JN m3~+oܷ]=2G);00ksJKc/Ы$rE&%XK]vdT+o["Avr*|SEdFڸg ֕ zsݜZgZrwH#aap а"/ɜgSˢX]":jIi0m×E?~g81Lt4ۘfnYMǫL;jJKʍ._c1vƴ$lDv&4(Q"{N1'ə\Ĝ$#_H=@ҭGFhOoL49po]\KY4HTqe)lum1~/uz6uJԛ;[w}ո뮫_'QJeЇņݛO$Thoo[zQ×en<^[ԩWs=?n FX'X3'w7VOۈOԍpA?GlMƿpXʅ[oz"J8%ykk6[z vSFVnReo}ѕW^Ow]]{ m_[\\TQ8T.CM -@&̍uϕvZ/?~| ͜h+vk]\M(ZKǘ: pĘG8>e!XYas\ ]i#W4/܇tB:[ݣ]mޭ_1].;}DfH\ HJ/zq n aPUgO~柸=g ǘzypw"02D,-gtw[Q|?q_T4\y[k+Qݟ{Vkp p!Cp*+.$گ9j&?ѳVz>|ZmZtW.& }sN葟ٷs:_3U6Cy,ՅɜE#&lR/Wd)26\z#[ RDJ L/=9R \pb>~Q~tvy/~> ?T| o[7 '`'[]Z؟Qzuk_7 ڛyjі*8O2FC%X8'*G|9, \/e["0"=PǮ+$+h&qvqO}9'q7{ǟJ4UqNJ3D5\6hbs-F7":'6!呴 ͨ -8#tƅ.L 7ح{7'ȭ>v+xFDZkY/E-D}0x)J.awmǭ+]KTF)#p7_jAO~GR):D2I'~Es8j7Ƶ6DxQ"J*sbI|hG+5jK0IF͏[e fu)8_C8Q)'XtE2h0=5}> "wUffY.)Xar$ȽH$ /h!fljb3E(@f"JJiB̨ qxWd R}C#Ibd#qx"|HR4-Dϒ5 Rr lB9űm5ddHұ`6#.&Ǐ֭kȑ#_q+SnWN^,˲|3Yb,r>g͖9B5u[zȏj}A3z +tWVC^\\ܻU6ٳg_5@?C e-wݯ59A~yM;|໾vs뭷_?k깹رc#9|P}_.KrHA؂$z>}~ۿ;^l˱U3Jۍ:NBRƭY'9KiSHt$ ݿկXf1< .2+\Y:4fpZ oQ`9 dt,206_X$SC3i䯹w68GOz_<YNȔKbt5BYJ !zƤD*&hBZ4%%g(v=ݴ3k`g^$.r.w;ŘOw$o؜#cK§;X˨̲\n?MD鵏W+SԅBXpO| O½v~卿g֏W/^?^9 bĶ]jo5#Mg/^9tǎ.?Dt`7`N[]]nBN(@:1([v(٦e/'ˌE2* @;%Xl4t7:~Tv~:fRy,MH1QsW7.O0| 98nxcm>}ҭhgJnu%wl6#ctCϝbY%oy[~_|嚠ԭzvO/B;,t=drʰ(z_S =p?kyr139δz'?/ &MSN=?4׳Y qns&P/~˵笇U__*!7x/_>77l}K_җj }=T^s.xT`#5Iso}Kra2/r1b53BcJf˜|WҚBSTe]%p%GOa"J ƔEc$Pnr!P0_zK#~%.$X,2p1g 71g4B;&7V9%<לg!c6LDu !KܐS:T+40`$fJD5&D6RTJͣI<}wL: /}Li=jQW0ۏ@4=r{6wٵ7n /hLQS=nI(Ι&%3܉OfeH:܉'?_j2"_u;λ޿BlΓ~{{cL =ػwOb >eee!lŃ~?3j?W8 h]i> M}k_W+]ԅ=MQ9a.8Fiw52ߍ" #Nۡ-iYJ{L9%}̕r|YiגeV KQ!Fqbr&0B2zFROw<~{>žهkssJ&zQD9p@P1A]cQ="*pc1Y6Lr?Ռ0rĢ)N\sFS> \ePb,7U;|FR0gRaHE ihKC2u6slVJx7n,r [i=_'*$[Hd+-6N4>qtgvz/CG~?)$5L\>dXɅgD<;Sq^Dܴ%fo;t ,>2՚!ҒZtVGh5 rEyY9r\K2eIԦk:li@jeHTNՎ{=Xh+@u RL'd}*Cc9 LQT e s&UoV6vmՠ nEת\ۥv]_y;C=kaŋ o~B;v=?3?w}K>MDw/reׅ* rc^z_uUmE>cǎ=Q6'կw n}}ć? S{ ^׾hl$bqV {ۿ_{'O|>{m>[ }j!/%좙O<̆Xl ٿV+ǻ~RlvF,]yʾ+2EC>=ӺUޕvh\پR,S+K)P^j!Hږ*&C X5ʃ'_Cz6V?_W/T/D:V.) -q# E2)P*L2VcJR#E^;MN*DIڜq6L(f6\8KfJH D"_x4m\ LD%HCׄfXpWmV ݛg ȹ+yxˏG\KM1"Ej_\y)$/no僇ΟL؉WLϐggݒWq2-:y>G&/s^&]uBLDslCNZJ[ַmuv!4<1J!EMVW8E eʒdb}(͉Ձw1)fF6bi%P#diig Ϗ ]G$˴0 Ll&.nwy V6YWʦmK%DSOmQ{^Y-oyˏ?Tu`,pV٬Fmb JjuAuǧiZu!?t:[͚(>Sg*Ǫ׾?|ɯkw K_ҟ??Y<9c3M(ZrKrW KGh_Y={OOoyyFgs(SO=}[x_v,֬d??xȑYmعhݻCr•r1=Sho@5fmƌre=UdJCa9(KBlɕf‡R_MPT>t Y*ç|g>?w_XG YO eJs_< z>~J2їfX<0Y(ɶExV,SCnc1%a5Y#Cs6࿖BG )Y`HCX[RE b'#hK6 <]$$Kĺn(XuӢ щPӍ_^^| Tϓav3_ObGv].F}LXƦhn=Iұ{ϟ^{$?'O{~7n鉤mGLqّXFa|Qoj 6YH U(g~~q D/|vt4cTN?&NkdsI9%@p9sJeaQ zH3VY'Ju{ҚGr{T9뮓4Ґ5ڿ?%/yɷ-,,ViS&է~O}S_\SV5Iu@[y׬N_V?1яϊ˾%ϩ #g]"k{al6OX.bNQ/Υ'Hj(#&3;$ȯ!tYFVoMHĴa){:խ_ߗjSoS?jN4zW[v};MWp'ډϣs}M&MsVuX CXcI")0TԵys_9zCwo- fXl n^:RdN|ݝpL`Lq z4lO"$t3̺F?cf`"&Υt)|!pƵ5hִVt1GwLxF n@m;6K%I%sI$b E[6֩.]˕"]d㌤ XM%pC+qT'\pV4/˴4EiQ-c)!:D1(( aT$rI\tbVԕ.v6St,?LlmvY|ӟLS9l-Fes_bZɻOB7͞g#ѡD~mAY.(b!i)|sXcԪ*9~(AuZ'Xm7~wC =c.:yM/_|(j# (εqYְX^hK] ]| z6=^/qJc~O]0!,On[מ\$_|lo/uQ>m1"f'_Z>=o^;uH]x[ԭ9hj'o'ܞnZ6wشS4.v1qL%lm[Ja5FGĨ= GY <٘yQO|I*k?1 6&EN=cQˈ 's˥)j`+Ҡ,' -)SQim"1Ba@ "0͟uؒ$EqmdmmQq'gu8o .C+1 ]e3;R>9+TJib,c Zkost{+0 TE EBtkd3 11C#2j-@0F%aI>!Mtom8#1.a)B#j:l>1=& [aˑ` y\Cˣ#extXB bcpRZLz1Z\.AYƤ6N ֎X=g|iF5Cr]Φ2,_{[aޫoŴԑH3 Mz'Q'/Bp*Gɖ:<"e 2A$Q%e5X :Ə$,Kp.4-MG&;m[/Sҹp'Cwƒr/'tWT qA礰OcB^owzLJhnIWN|{$;;w%^ii3NEm{NgB7 Że4o!6Ut#te*;jH\rX# =d :h6 1QIpA.Rh(7 plhL]hcECG-{DqpĠr\08$LnYSC '#0]ZW(ȄF &S,G/ttǜtK.+0ȻEN?(aMNb$b"1,zA`P{g.->1cE;-Q8۬xCďe|1oM=jx+6̥mB]Q "e!bYkda:TRRn=sM6DͤeYDҊc`+Si] -Y= Qgrt1E"H{N 1;-я!-"2.lg&ba00 Rʹ<֭V[wc~>?K :ڨ]4vIHdy:44ű.Y 'K a1˓"o':.NH..W C)nID2􎷶&;#-UCmvԮA;K ϭ\=\4kxOntE Ӕu>V5:+L;ٷ0snusﳹvMQHyac-޺ݘA LϠ2IEhb:#`゜CT1<9&aK=泑Cx(Eh1j2bxKo$K/TdxOsW5 3DݯK8!`3? ces&v.PV.n cewE}"+a1°8`1,%CGhژ w~8!1Z~Qٽx2%ю}`c.c19)31w4,&D9A%ϙD\@-ߜl3H}foUruAAvjb1N1yY-mh b)Z)elؿ _2FZ$J y_K\E81ҕ}"(M-:k֥’ BɠO~BDzn6ڦewp(9sbg3}Di-4e,"CEL)h1 q NB!π/ahX%Ilˊifq s%aX蘝AЅUϥ (gO?YT̷m3SK7Ǟtұc#C`>zӆLI7v۷ܝܧisُoo?5Ow '%9ЏbGC4b\0l%_+JRK=wę+93rZ @ b2:%A.gX|3G\ZNYUV8{IPmu2 k|݄Sp$ɪS :(kTC#6L:iQKvi簥LNHmR<:('G8jc02!FJIwC!Q5d/M\<:mokXP ,ؗ8(k찰RP"6͈a>^c%#34`O94XcLŽߑ=2TfkӖL>ֵSEc}?)nt焁Q{n?/2j1>MϹ>N?sN7, .|s~$gloG87|Aq}3RWTD~hpJ䢄({7(%/bfaNBv qvo0_2gy$Q&ԗyG cݢ fy2sxDCYT]#mJo"d`v\Փ..-08PݴA-m C4~΍÷f2fQ:JaOh}Q7E}-\HUѠUƤmXOwPs>1kWf J%ъhQ985Zx=~\C gԎY5%Clˋ?G_B1_(b+n p ܞJ7藮д-\ƮX}?hMwO<=9IaX>g\a>/bZxV;|ۛgnwhꙫ6#(O*`Cء{U>DN5C1ұ LMf zf$஁ZxNQ=JFhɜߦ%䝊SV\:X-\#ffT$-s;'Lƹk(hC$-w<2\wU4)c ucff0BY"LQa%3.C,f8x<J9bPU.?eRz!WW‰$9 Z>nv vߋ'8:Qw'~άS#cY2oGMF Ǹ2''DܟCc!CW96O8b[AAWmX 01N\xo'L{txA qIdžnu`rb7p )Vl,EV5ge2jG#.GIcp@nt8jaQ݉Q:c.N{;C넧3mGH7Yo6)B^(>]yKѐjao+bV QqX6I^C ָ@@j1ۙfuh Y2wњt¢OtA?~U>ޗ9JwdcuA߹1<7ٟ{2n:I+}dfRJY-d>ݶpc\=qj7Y'fjݰ( |h%µVyg9 ;s#Cr|OÌE\׫޲GtΑKEnDPtMr*;MPcT c! cWl,""DquO[< wYS;ܡ pQ%J`b?򘹖3'htqQl1وܠG;Dz1- "G(ok h]AAۘErh"qk|I[\"f`u"tzNg)fh]bp[p#&,[Dje#,XwNS)e.rCXTPF30KU'|=һ[A8ֵG"_ sp]Ղ»OhV}c1I}*xջg7$:@t|h"f$G_ep+!9mvyKܥ]K|y ;Z?P@&qԞÀG%m}G h>f+}2Kj?B뜯})YrvϷtoԪVY}6Q웞m4]cweå \dduٞ0S%ڣb*I,xU#W>F%_ؚ5Bl\g?PCR!l2nR1;Db?m6¡KwPXH]NIff ԰Ţ&wJFǢPpZGO)jjJJy'\O%bՈ53Ô\ǵVȅb &~!x5.6Ò',n\V֧ص¸bͅU7d5a觓񹱵>*Y_iT Sh,|9N|gq$=d.=IWijD~HQh}dLjфFL*b@2(lzA2`v)١#p J*[D_޹t'--k6pC6ƷmG%Ǯn^u>FПCγ37xZI"%0§2;M4sF˙Qgyhq>;C@}23DzHDp__x7|FCJ/qQ?P|هoV}t[ wJܷ`^wuaPԷk=KH//{mjN{g'm0>[ݯ\eO, 3553 `ڕ?vog[3ma-f,ͱ{bzk~Ckb Z'1hQ/dOT\TrkXc[g0viyGVc'5LCVFt1y׌Ds0\p3`w[SɆ4jiĽr A ?sfyMi=ñPC+Wx] ֜&b!3XHnx9A0?ɬ8ɱW(Sa;g?ݳ сUV6U/Qహq5D|WMm1B~i[3Fkqc,t0;{d[=cG;3J}BSgx>?ݒ)]G):, v)\Ԓna#j;cB:iG)/xZ zqvNW ]s=L%-nX>7jؿݢ.b 9 [C#]61xϵz%w"ުs*Pr /`Hė -^|荟C ZvH ECl$tĹhOc$'2IbzkbCFL5NȲ%A7鎅b_7ڧJ7"iLs׊:F\ CG>B7LM{ۣ"8X\*_e|vB]'|'bcAAQNsq.5~.ZY- &>ӳ L XwM34kEAN#tf*ƛ` ٌpiߍR ZGwڡLUryMO i4O3:7hvJ!9få]wEFcٓZbCZZ2OUٟǎ?ѷBj]/oV\w!>fh4buĮym޾gq]$س|"?vG-Nf7/Z̜o0yk,cON[ɫ!c+?eĵ?n\Vt`s/{FHo$>hNE}!&%-Etf/6j_cuGU')>iB͋xסۦNsgۡ+g-)Bl'K/mj7>U zY@M]1qXWLNڷ{$IkfYƂ=uKSk * 6ϓ@6AmTKwޱ!I1XP`?n;튮ؕx,cugk<.w9=WNlb5~og%ju_\BmK13~b}@RmńwqWkW޻Yڋ'BN{qPmeaN֤POd.%?46{Bwq'͏WƾMcx_[PkH6;ՎCe>z'0`v{Gi9 \Ez@`GBs|;o8N J:D8e~ޱۦl ΍6[o,Du&Tu6mAV"?3om=Lsuo6ֱsiBt}?I}AHsc 0vbqh~sUP0+Kx;gq\~hE朊/R;Y ~yo A~.Ŀtpsl˘=x |ρQ|^^(\\s#2h<(m@ x2)s\7D?/-ҁ@ p|ƥvUD]b۝@ }_}E3@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ !IENDB`PK!LSS=res/gui/maps/icons/moe_calculator/previews/calc_assist_on.pngPNG  IHDR#+/#IDATxdgu&7PsOO Q $@"D2`Xov g] f1el ,PI$M3+{IXuSU7[suk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]Z׺ֵuk]{:>}cen^ծuk]Y.?{!]rDt=X@Y%,sJzbu]Z׺Z=uOpZi;x[! g,7Fyue:Yh3o,=Ɨ-ֵukuA m-gNM_}lō=셼VKɶbcl[;|=0DedcPt]ZYԟ,`>0x/`x7Rnu!\~Ӎy˲iv!O<;iӳ4le8ـ~hٮtkO%,I=T3Rmr3.rKs{8/tkOBOGNnqɱ3T2iD-;o9nx3x/sSgE)wG=lfj;ߣ+MT,KVY0juleg`ڷO-tkO;Jgo@jIq1Y$/nZRܡ +bCl`@Tx-N|޲) 3ƫ%#Vu(V[^ih8/> ;M-4Gl.81 5!1x`Qz>X-/( Nn~.35[c9l cuPQm 3Vigςϟh?y]ZXo@P(wrwj{j4w@.+)ز;ozt,rfyszt)- ;==-s9,v=x9Vks`h 8O,` {fym4eQY7Gga~M`n>'wx.?~>\l J0d.&ҜiVjovӛ ⢖EKCܳYXx*brYx\X՚=xvn=7y|@ϧcYOcf}n٪:[?l.7 g G[Ȱ0C&kgтCl_׉3=s|s6]5Yt!=Ƭy~֦ޠ'ދ-sDO~מu~$e:=a9`0֘4։s鱇Լ%0¬l c{'N2|Y1pF FD@> 36o՟$e'9>A=eI ֦ N t MΎ7֬&:|h nL[QHWTTO4(@"b_@" ;ys 3xtriXscêOTu*^9]VXXZ6MXq30W1PB PPHr 8#WȀ9`n9@ԁjVfz|gEOt(cq$Ë|ƒZzc`gAC>Q 9|G5VYmhڑ'Kx7<`ߵ''#zt}i ѾIDGjD0ӊ+Z&g91d_0%-%S/F@T;IHܶfz ,sM`30i 6|ЕgHom @.4;WV&ҁulylU QՊ:Y sӖ7B%͇Uq9rƷ7^Kd>c03\En9yyM>Tb?O4PwD}3 z+[Dr /"O4Z+(1uF"Jי9&'z}{5ki(dr\M&JsEz%8&{s|`>=tdB]Mc$}/BOgoAȚSq0-~|`Uk< "ե47s˳;hxnZNkb֗ND-48`nom<!1Mm'G^hnY(n;ڑOı>\e˟3F.s`8D2G*cf||}c? ˹?wkOMP)?6STUF"ϐ0c"f%ze/WV,Uj +̄KQ ![u[1d"mNۑ ua{icCܹs~ ;v(nIgvyA}04 )Ҳ朹!3\լiy&1 `n 0f&q͆>l71*#VB5k4J|f418րkf p'Y37i?yi}מ)>Qp%E9F'c$S9bcFq~ g=s 2^+P6*,ik(Y2u@aY*qҥaTD>,ȑ P`7.6o(LgYIFHi>4<å Gυ#m }In'xN&I$ur6^ R!ޑ~@Tn)υ-2Y$6ҭJR*7 @80uSbD C``qFd>;űvԾga3u{ 2`x}כoI_Tɉ&) N~ yt3w85#Rg%B. k+CL¤Qx 3ʞran<,m(}muw-4Ye;1K=P# 20WdQ ǂYQqVg 'h TM1/٨^Ru+l^L`;y\ 6hV-djU0[=ǨǙ /?y€2/s<,]!0]N8!#j Gic F3֦K ZYT'o'ƔqzR'>a!a#eVɤHlf@ Ϻe)qWÇ@Ku󣨣wΖlYϞ>-q24j)˴dy{y)hp$o;< =Fi$s*2cG4X4 ׂGsr wy4; gv,Ml+J"0>e˂c'$fVVa@< kN\^O Ht I#RޢJ~{2y?M{)˜gXo={NЦPLq0#M1w`]b3rƢwƠ&BL0*TO{7,{%-q/_Mflj%s{py-Y lflhc)0lBQ1kM%V +;L'& @?mI)4tȼrV@Gjǁ}sN>K8#eal|VO.$K Kb;C%: ,.R!xAF .A%7}ю֓P Ø56̳Մ |5+(4S\..(msvk==H8GK=yN ۅ⹟׾?mq.url͞|F [S%)  I£^$'_ $x#N@1?X+«)| 1o ܮy6hv &ztR3TCD*a<>'!_1`뚑\~?gΏN1gwh]j:Iߝ2]V/?J+Ҷxnj%sA-).#e.t 978H#-2 .k,1ccδ̑`d}<C2dm re#nr򍠈;P Y9l[J"aY@c$W,a[3#vn G2$Yd5Vp8e©J 6&Τ#<&>@H|3CnC8[ !|sm\8I$}%.>))E([És,-d%F > 8S۠$6Z&eۙ56,B OFGZ#b,@eBάRHIyNuP]QoANl]N k_ٖ';Mk71j=:G;o\i7(g9hݦmEf=q!sFW=Sj|8QJK"NX{ qQk)\\UӍP u־XKWL9x;ιMLdhO(M5kH&J'cMD&#Uu8+֕4jY6[Âbwج_Qj+\[tE}jɽByͽX!OC =o4'(\2-j =kDL\(c%q+t ~ǘNYhGq5ƍ+E\ʁFqb@C:1|5fx`%F &S. xh J iC/{<-}#>cV#݅9g8;Wmf-ɒ9z% 2.0ЎoUBLfH{ldB!uvb~ҍ0{ \:o\`ȷYV5\^Cyb!{b`ɳ hъ,OPkoo7Andm@Z(Fp7N4#l&@ޟ^; Oon1{Dk3dyAiǙC5j=NfxܭΛuG>ڝ-2+6āD'- I{:^7%>AQ>%9 *xwŘIAR1ʭxYB'3:z5njW?)3[^8#Ɍ(N2,xCY7d*ѧ<*xfS4sf+CR7Q*/OVv,+xiɚh3@Zs`)){Z(Ss5?3O+9(`Aq WZUx )ct)B3h2&DN|H@NK0g0bR*pխ`5_JA6В\1ɴ X‰'JyHPIƅċ&/L WJX [HrJs0V=ōIGU箦k{Ah qӤ71aHZ[6 iF^bgdXTGqFayF.`2QB BJk=%zN}ށ6̢}߉? F^4ic&47=w:y?owp# heV@{LdA4,rd^Z8 h\pl(4o4|ܟFz**3Z9^z3FZONC7"R+ц{1 -]ĘK$\aļ^x*tk HOb(a,W,fun%_LThW 'RLj%3DIgo+۟z}ej&z:n홹;X`#\HTk<463 |ʊuGB*Wd1MSXS#,a<$܄ qcH')F[X+/r.ox$&9I$dS#+KF!G#_$gÀټb(5k0ֈCq fT5$1L`#@`f|E#!${WkjI16v5 bvcd<puW!p IZ!By~{ :pTá(*H\XQdcgls?F F66rdGOJaCGkQ|Hσl(@ksx~ӟi<eNa{{>lu@/Ho:lX-!l5Z >恖ddLMɛ}Mnֺ B]{k48ANC'ǩc ڏ$9r}+C 4%;& ޅ\L&I0)}GhJkՙ Oh9n=[|XȻ$8Jѽt1V VSAT^[oґ|=>ch"`5yEXVBFBj临pᎃ8'PXnС6'׊ڼåy!w>]*1]>\dzˊњҏQ B3jIWE*cd Gq1߸hf!כi@S^SıK!|W77y{3`e@7sʌ۷? _}Vm"j q^xᅥr,۷? dcl܅u3?CTWJfNym"̀oc{٫|_~.c+LMMMZ ?M/itmz8yCSrA+"2$Veg<6FBjr8ܴ%Zq{K)Í-f3dTeh ;[Cҷf,(BB8>'kb;k"mzVig%Ѫ2ԏv|c_ATI1)ZOݫUs>] nr~T%~堍p[Wk.Y̓/C.X#1({{p'ƏKƙdd4jF+mIW! (MTi OS4r DhErFz & |MA:I kϋ 7 miwh7?|w?˘)̉1#C%27^K/[yOu(3S>~?;w4({$뎏OHQbHږ Q3 7K#ۆ AɃ`|9(S3G+;y;σ'9jLO'uVbccfcP<(FqN]iXP]Y]W?P4Cz_kC=tv ͑S߱m۶%ݻ?{yC:~M\?^r%/,zę$'Oۿ7M瑁{3"nX)h~<֢@31r.ԞCݕ<pCR:%pTk9Ep9zGF5)] U%x%*Un-@HOS?$@@Nr}PP5m Iӧ$ъbu52S$5]@M)´9 V2.ngP+X4Ezb_^p>:0\޻tow}掏~ p#1jaסF1']qj(JHDS@i83B-9_1SeWo^~ C[:3<"eT$="(l,Tk}Ƌ/-猇`??>k \9+;G?tgEO@ -&!IVWlZ~ֈJ^'KÇǾ{?d{uEOm4Ej^C`9S\RYd\œGp3ijc^~ k ̾&b_g3/{}c{ۦM</!u]wݺE/~Z-Z dxu׽.%c088կ~=~'> 2,\/~%'`!.['nI_d޾;oxsB|1}k֬vtMoۿw뎦ka9vgQ m *V9\UęVD4҂B bGJլ+$J3T k$B,@DK!x/Af] ].3eu5cHU5J 3őHp7܊jdk17唥D6ﱻ#]~ҳÁ勵iR:f<)5hk IIec?ݦ^.>+=+.y{ O~w:.p Ph6 b0)wICHC6 -Y3! ь>eк,Ӓyl/\qpÇa!nLpΑ0(#rn{_9kVe(uzW?o^YM@I @?(H^2](쪖ra APRѠuV \=EePĉ~_7n;W@ _y[_p/^AZ FPX#/]͠:@,dB@CD;8Dct:OZ9hU/ W% zj6C*s_%K3:靈p [F.x?lF^Y 7g&X_]}.>wFL]/,>N1"A; t +O߃Aւ!V{7°@ȿL_7ڕE-/ +0ʹ\nݺyvhF -r|+_vdݻR clegy镯|ymU ;9ַ˗]vkЛ-/{+^[Z7ӝoYh#U۵#)1]؝f ej3̕r)8 R 'T CwH(BlAo5̯kg:HU5A:JI(WbzcpM=ǾP Я!wX+=I&(G<>9ɥ/$W^"@Sa*:SU@U =Hޙ$`1+$]cgmŠ/|lS1E3))m\(9ڗxi(!p.Fp1 k>??kbIG8PG =Nihk6h'\9rzƲn}l I&`զM|ץ]†5^^rV/< %\X늚#^48.;w (:;BsyB׮BzƤ;tXKY=G@#r-X~%m۶/_m@}|nXo|׾,V\_^sQ73PK_>k^)oRv7x;οꪫ^yPxlӳo~K%֝mf]pKL*%\T-5<8t8p֑ooxh=<$&!BDkKt!6韛" rOOz"IDAQRƞ7.ŋKW9 Z }s.X@@2 o|4 lW Un~Flq̀_y>{ j+= htyYxDy ڃ,dYzCҝZ^gG4=8˟Xڙx^MNN.m+ /}Kk;y }΀//ӳbc=//_oﴠ2⋟ML jzzszիY*ly67z[ʞ h1Je2\m />vU2kOǜwk=QF^o@ZʇN&;N 5S/01́+|RAS7\GWoFĊ:q5u1R9? F'1Tc4j"KRWgː-_a得d&&z&+JBqgB ѳ8ERdHrnW`(e,!H CB.X H?7xwq'rD-k;y9lp]] Y+(_S̩H<ܗT32i|)g_q|P\6qcX~Ew_ypj.(ohU(;cYL[ٻ({{+\fO(YCl|ٺpJG]\|Meݖ%/ӹeť[V^bP iX%!NuR 8 @!Ōx+W_@ y\s  a7~Ky˿nhhh!{og0aݺu=wknÆ 6kGfjY[nj|8|#WbؖL7<g%mhVo deG>y'FEoS Ox|UAB1n<C2 -ר;wp#/ָn Wа#~ ~A:&p9Vu]z ٻ:u`z8t|s?Vَb%Ű׻r#<汘亭e[ |du֧ 8f3<@ƃE?YE;KCȩ;7J=S;4[4իFp=ݲYMȞ'͠y\_^8~?>x s1 :{W~e]z}f?|YOOOGo9Isc?ۏ?:m۶)~?ng!]IJ~C%xTe/w1@X|AC{z|u s$D~fyA}[IQ $_M~ʻh[^L++V rwmCe7Qij+t憦%jv;86\]%42a ^1O;CE-|oblL/eύE8p`UY Qb,c@sJrX'cEi@iѐ0*q ]j2Sꙓc=Mqr|+ !ތx#1$:C\r!kR 41֩(2³$< 7BdHwXcZҕXf͞OϷe{L}"-ncxn0g3dBxj.+:6V۝ٌ).|𩙣Aɗ_3q 9g(Z+`ZBN6%ι;˴C(m).%~,;~^=Ͻf@tjջ~DB[lYj7͇eQFu}t[n]l;i -[; a۷i:>W}رAO._|]SغR'ج:;P߰aÆqJeヌS6ߞ={+ՙT(F~qN`wsO&cs"F'j]z kذ[j"1\A9o}eGz䰜ui.BH\=isUI~o=ì{ Զjft0^1b!XEH^6$SVR HL04*7ըӉ p%$aICG4 9}ÌfZըr;1yȞ7# ?ϝŸ@Y\]<8i _tYyh:#ADC6ye9OZ\55ƙb%Q.:EHt"}(V֥D}䱅5wP[w{㟱 'JmB?Em0 8XbwĬJtȣ{|(ϼd, (LAm۶Ua.X)ѸZ=l }nu ary'z:aq֭]v#n6 L+yַ/nsb8lzzd.L]o~syv:4iNuG$sJk%b[ Z G...S~䤍T|;kD& ?2Jb@Y Pf#0ĂG[~̘gLCrdbǤr?Zh<-d4{#&^:~ee9'dDU昡8VD̍p'iƸ*3xth*ZCa)]RѢ\:: =@HP]riDZ%L`zY uˮ/[f᳂r2#5xxv.ø3qGhCZ&B=$8*"zG-+IWia=؃;",7θA[fjℝ M y"'qCtw$p9ɕu27teVC^J]x^:lݼdhqFdNQ ggvFk $yo|~wju%(۵o+@"l涹"_,s- Y$|G׿s;vgӠ&.rSk8ְR#lmW:ٺS ԃ qy&th|;_|6&oxDx!1M s^"Y8Dnz&Hx~OʡQJUpJjbч=ă4i*hTexDϭ`J ##1Qp 46CVKW(z.e;zEQX?,(fFdADcJr^z<.YM9=P`cd)Љ.{Td6n]ޛ8G, S.F .< eN_ѢhELԍٛ9q8!)$'`-"QE T~OT(8Fs "S Be3X N1 2 o[F4J(@BF-ߦKz= @8F:pПBt <,Wʍ%NMXzaF+J+FЍ Mfqr&*~䑽MM[eM;bpf );k#ofG={^ #-8 |W6/ڰa5t m`89-Q/*ְaæR\؟2.KDS L/x5ۚ Ov&o6<@C>/!Pe >`9+S<&ywQ9Gf8%SF7Qz3eO=4Jgy!7@ Pn$ :/t*&Wl2o{kbZ$ `i 5bˈq^I]qG&!:E6"5 kR 3p' <3PT HƉc:2)?2K?k|ʭ|bb&jo =MCqdZh JXop0ɾA9쇓x&c7`d339z"y]$J(ͤԬX,0WbF{A53w~'R/pbԊB$у62ZzyZ3)w';9sx+.HF NWX! "ӈa1rUE1lK4N|0ėsN7^Ϣ2Fc쒕F3N +?-_͇~UW7]kϴF۝'"krHh GXgj ‘sJ._J2t5Qi}Js ^,H'.X`ŸҖ֧w!$2БKF5?TӼל8c57y;񢾾ְ__^Stϑ"Fou5k uʧXvg5Ԇf m(;~mK_Co'il"aC(ȗc/>x(Uԝdf0湑}$[,6n2hq8}ԅ޳vz5{߬E~K/}B^:Jvyo;³9c0k׮X6mٳgOi_Y# j׮]erǦJޞ@wcYZ "w FQlYY]*J]KN=cr) WG$uļ4Ͻ!h-rC/ Ai*\յ#Q:aw}bGPMp3-4wW9{9=mHqt ,oR:;޹i}.x$ |& ̷cKxWyt<__~YTZE333ԧgƩ/iٲ]mkZpZlp.+oy{nm:vH]ZS9:[c8M< ?AIZ\,cF YEMl08Ֆ⊦ɻOCx@ _ʭ~yb׌Gx4E'41#J)wHr$ }(!% }y9JfS}t,jSuup͔a99dR=о4vGLT }N?[sAD[%}gQR>sCG&ԧ >U1%.QyA]3iޙbwik1G oA>sv,\m<7i%9}o߽-/)]Eݒ_n?=:^?:!rG-/!%%>i?H̋S7tEѤҐ6?oXvyy|oh~`SMMyG5לGvCV-w}w| _vrg!:bSNA+ݍunݺM 'b^` ?A}O^)ȯi%uZ9u /e̩ZGxh5-iNRc'(Hgȯ!Ɨ^Hl8J\@ ;w˗Cekgt)#ZQQ~E-0 IyJ!MZN޲֟2F<DD~c/taO CNPtU03<96ays+ F8c+a'Q.DQ#&]Q\W$f\fY%o>0F=~mo޶Y|'r}ǿ?iSu!4 K! :?,f,ʸp (҂sx BηZK݀H FcVA{[^1ARν0xyOuum/4KT/6p;8B+gM8b%[a΅7cw}s>x<1Λ\Fx={L4fP?>߿MozөBQiw;!s6OCY=_C!^"*-UV`晏lN})O#B/>:{B? U9B&&,՘I,¦+M}Wo VTy4v^,4愊,'re,MnO{9C$9}|{Oڄ .__xᄁ'W)heȳ>8Cv EdFw]-db-agj=KШx_ ;&hH$ \5yYzoY~Yׯ1Y+1^ouk 8^S{ D[Uӿ3#~#M],1֮Z=R& RٟI˧sj%s\pʅw_}!fK?[S۵kbJCQXxG?sgV7^>ܡrfZ<ђnRA|!}&Zzw뒛n%ݧF?яBjz_Y4D[L۫kㅯBۤ3:b PDzC ih|;pEݕ5p]94r1@n J 5 np ȳ %+~hc7;_ewk7ы[4@;%¥;l <:vp.EjlV}vp qo޸qGm:$H;qr={Hry.мְ{qw۶HfQվog?GŚee d(ݻ7u̠yiunuq޹,׵'K#D`qW@K,d*.*$c'/iX$l7gnlKyPnE߰xÇFGNC J3&|a.klg3^F}\c=${+nteXc)q"wܢ-kQRZ$Y*DDgo3ho A(T6jQYl+Q/Oy9qR4{Nh5φC 3 tq~PoE()rr YieF;x: TНJXr }Zcֿx#6:El'c;xR|Ẕ~GOo=\}Ð1Lb?ձʜ !EO.C4p-"h2ð= e0售pP5֝oB̚:ޟ$ўN5N'Pi6/dT`:+'Q^ MݽNH?@O}Wx:c/̈6Vn:"Q Dv<9S/UCWsckU"rF:j< CA9?Ryh XI&(CԠX]<|xф,O>܎} ]M{)S;qU~&w&3+r#:4P)IxoۿADn<3}OKTq>/>r\+Xq^Sׯ_OtBb)V6'{,A] ߄^:wl!n/r #Z2pBVsNQ*JAUc;=zC#kc1.āq]TS_a_K*÷OX@`VsJA1%{ܕpפhڔSOWȓ(ezw8vz4#ȵzɴܹ>- mܸqmxxU:u!}K{[ 9K\ 笆9 Y+TfyLàD.{BǏOtHoNa^i֢Q[LuN7~vv6;}?CПRD=5:Y|8J %<|O)b>Qsf9^E2!1 JX{.XK+2 GЃ5Ä,'{lj&~lg>NBYd.,Oy=Yn՘sqhb7"LQĶ6,e0~uGFh)y&al iaP:0e[B>i*P!AJiǪk48η8TvMs!#"SР;ScF8K,!Vh.j.EQx: HsfWn=r ;ngCth΀3p %U|6!ء;O~i]6Awl&FG0M7[ \s#K hãnEG&ՏRUsŔ[SZ\zl!gR655"o~R lbj}ixVDqs;FWIM,F8ɑ?{ſce }G_F}1jJ<߻о; O{%mWE!0T4M%]5$r|2"/'YXK[O$ķI]MLBZ=Ҩ,z{AQml4NǨ~| wxM*>rĕ2/3FQQ殖Sm c1:}@gؖMz\ԥ1@㸾c׮{^R= ??/+ɣۃ>W-XS@+ ;&Y -X o2;RD%4&h*5"h膐;Qq VhE˶0:ԭ?8yBJrV|[޲obQvԩ{޽{g}fǛf)D-$g|fsyWC9R$2R:/| pMqL=hx9ŀlUզq̗6V,b35 <'ٙ0:::Rypn{Y NYRu+l8}F -P/$su%%gu:q`Sг;O ;iTXGed?1f'l\S&}Գm=F6xȷ7IUʡ㲸Z F12j,2zA݌m"lƬ[g5 10y:$Fnsc_g埽En? 5k =lNE=0 5BǮ"^6W]g^9NJrUo<ѱ {Ď nW%Hd<)u^`CEB+PR+N9RZT3 Ya͍-tR'K6a;>AZ;sbr'R/(k$fmŀx7Q9Yqwz^h |[z_ðRy_} _LϪUV-句|іTGAc].уޑoM%\r8g&s*7mz ё[064Z*GqdJIK Ͽ&Y\C,w>JT; }031aܪu$ TD`;lF"5۰ .`DVe6{mm^iD,ڪQOգS c9)+uyzmͦ}N{u,~Y>*XJ}9qtm w'znݏڴIX M,`X㰙D#[c(!<2Ѭx.d5g8?t[I2^c# DFj90]RnTnUSbλ?7F-[jk?Jn%+5t}ݮʉ*3,aɚ?X3FD8\}㪻~$cašផ?=)Z]FѺ7=s9u P <8&J1R$겡ތG@Gqm'rYiX'Rsgo~ցzǁT^G>G2B]otSkK&&7###Kkj=,CCINTp qTDe9DR&"U(F2^O( 53C2KI$CH7G$Vxjx`uIoao 7^g-.C٩Ii\)Q9nOFJHf66QLM,}c;_[/_bECG 8Xx1V#NV: )`疵z\M:zQtURޱ!61gp5ngj"n*`~ћ6^ ^~7/* :pʞuM^30X\dcU7vOrAUfyKY&37`y)k~aH?^3Yp-jX|cms-cm §2*tJD[4~wn>r֒ܶe\@ι>yjl?ECg3mYR)w7sX$5J)^|X7|^>:Vקomo-#{Bv=\M6]|x/&}M0ph{?|,sS϶|wbw /|ݻߝo&t9ח ) O[P=fDB2s"1q _{#&7}$_Q&fn'@*:Ljr컟f;Dɔ"r 4u^@ R,&CRţ֤6v!LXPt,xt}4xo+1C湾Ayx \Yx5xK+6=z7? g[9<Xk5҂'5"QͯbEڎyJOlۚgo)_Q%?ýҧɊF!]̓-×:Y|46gO[Z/09wx&94^'8TNkΑF^{8ol@a٪Nh?R|&VjIlb.2oy^?ܳk߉]{r%*ikqt48UG+ls"@ujtWNO[nܠyozT[-ԛigkASޅ ãhw>488 N{wo@T* @ݲJh'[#50So^Fo\ 9h 6==~P !.?]Oە%󽖅NL\^CT=z%PGiHr90&!l ?Ac0`kI3Dļ.y2QBUWBDkdHQ<6KN}Ǫ.S-ҳrțqRջ,: /7e[JFK;3zM>c̪ZRp[/ xd R& "[ ]k"٩wUoAcwuvYz]-g(a7 n[gx@؃2*Qd}{GZ%IǮ W(CBǔ*f'Jk- :foi`]wMO2DlR95,#>?kz1aGO>8VimMjVזKt#n!z4Gh^j)]>&_xz{307_}=xؼ0p3 q:m, 6mZy^6/wޝ-m&_XV+z{{::ɓ^}jVk1J]S~~{>1Z$v-wuX#~o> ̻3;DςyITĩIK2?AHy8j~j'))mN$z.YN=[/&{%"W:/ָQ&7цxSCDx|Fb{i#(YsVf87Vmp(83/(냟͙ _TWOV7Ě Ƶ@Ob54ѠZ/kȗ  w~/x/ r~UD9?lzl-[Ơ=7~O]kzŽu S;'G;ߵMDZ-D+QαLL M \$#elR6td[fĩ&hCZ;!YLJJ,cƠ4{?gN86,W毽/`vll??'>񉇚z/6 48ɼu֘V{Oe/{YN%n tsk>^͞y~A=?t(Yא%;M䌥/KJm%A$H\HĜBȉÜA֌qnO\oߓM\;5+dU!#!56~XZ]ɩJ5ďόz絉}zf fZh3UA5nǹTPWC%>3k,ED[TgbCr:ck?Wgo|%å=Nv [҃_?>#OLz$%cQI"-ogU5чO1fgV~y#EyXI%gڰqƲ:cTW7θRV *['BŻPyd>}CտyyC2X4ec?>u͝oy[޴rʋeiEz7|g|fMhk=,jҰezmG\s۾{O[=__wurX\׎!wWz׻lűu)lO a*vGqEj>8i%RutUh6~:8V%+/"Z-RM&V=$Wղ"7f肋Ik'YXmT2YF ky$ v&tdU+2qGuQ/eBVzx239OE3[힃߫{t!.V^^)^ɻg 5aּ<- H|fEheܫ궏%_i6jM%[ n^V zD%k+ȁh:ylVH;I>Ă&⚉=S=T+ l`?p QY9?oZcP#7#$%10'D,xh[굚z3dX Hq!uM 1MqF$ME b]FgffN]OL#fX3@9yUzx͛/( 211q{ ox7 gW]/dkMyg͠>W?|Ͽldd|(Aj;vl讖siN,-ߵEOzžt|3JLq&‚+D"g9C+b!h6Sp皔g$2TD{ኤvebO9g J3idU: B2_KscEN(kM`d>`NՉ535jS&ZMLUԋ:N4N2u<ͫW"n4_r,lAUPzMbd?<ʹzP6u[}bC ^ScT3bBzdK7VU}##yX9cqW3@gּss^E.Ud[O:ӟ&WB_r_LA>h ե/t^9YƱzM׫yf=(DNmls.ҹl{]@MD:M044itRObkZRtMlIw 'H 'q3|0'~x: [rK:G^ M}F/#7 \%X$j 5~LքH*R"#qJBMIoɭ·IB ɚIIa=I9)3 f1n4]X:F q4d.X"_5@T^z26r kd4i|7>b"n4JHj:؄(ant+ܕW." 1N2E+֔J04gf˓_oMO:6FvįMŶi׍gA]v+GDjiޟmHHS7v25T&ǚeɃyGknidOaF:9VقD#krDK"[um-HqsOA\/089F&$̳Nnx,xD d@'1uxw;|i DuaU[TJAJ\^_Qop?əQYSxYY1m3 +'łu_bD<"!l c˔#%Ky`ϴTCT[3)EQr9dxNV愘ԢcѾ@udkA"1@9ǃq=t(OҼj9GT3 4 \qe#'ЭmN0C {-8n@ApI2H |bř1۩vq$ 'c&BqOۗ[<aT''^☔' YEi] `Gz̬PPƨ}F؝kd%&0Qiӆ0 ` },9q8/5м]ڳNAI__h+j|+wu& Ϸ.4_3sH-4o#os;͖k޺[ R ,Ay%T$Y>&1h\z՗hD?t MdULqa&O9ǭǹv2ȟ>tUڊ&Nld=F_fϑəܺ!OCD4「H@WuCa:];:ف6x*f 4R/}PE9qk\@my+ZG*ba^ d*mcsa2%qVD`\1'\:VwO\ [AR}OhG0jZ dp#D%_<4s*I ., Db{VNr&S%n3Z(U"u#5vOߘ+Pz:שǹ5^{,c _g^qUnՊ%\ J(灇19B #ȝ ,*A?'$hM3vmŎB,upGƎl^˹t=~E.":J!W S f-A׳d6r9]昗% V_OX$E1oډp0b,6 !-ڏUܮ)06zC](2M UZ]dzMmeQ*iAo=0,5SOr<$N̡~=s*rm`HbHl.j3 汫 1cȈ(٣*-\=ﲊ& ٲ򠹋,tN 3:tK׳]:m'J ?=D$ZpTr䋢/F i aFIs= "efRϥ y7wUXё/=ex)[7҆D$֪)O%jd֕'=tf~rTM9Pg=-;r+r̙ɴ$^&%P H(AxE^kX*@ BRf&I&̩^笳g3gJ h{=o}^L,adƑ *e- } ,؈QG _账W1Lg qev,|) ^wCt-^ả%4ӱJTݓjڄBTsX<:tmKLl!K͂1&eR["H %4ӴߟYۢ{ijM B 7!PVz7CZY#Nuifi% _)Zv(4܋:EZmk{2Uі)Sː,:X"9eg#mHe`& b|D̄^j*gH[R.$V,d9d;MPueL)cpb,V)%.|(]nʤ.sKwǓ}*"N#WrX :r`na;(`\Y-=8O 7fp+; 8Ǽ>.o2'm)!*.okhxn{^7kÌDݒE#߳`,uFC8c4;>A藨׉);.`&~ڏ{=yTb"S..QFgK^WaWAR7ij 2ܛsC6;\k Cd$኏+NLU- O@:5,tnn˲'`{\1yÉ*0r]=oB'5\a}ʲ8U[LM}:Yէ`Z)\26$O{GGnc M{<,iLx4ڀ3 ꏃragoMT j=RFİ2ar9>k4X+ёo/LK8oHOg ϘI\^Xĕ&—ieF l7i3 29w5m SIC3aHܹ Xr̃sj.]ČIXLt%d'8]kW7c f5ܳ6x3 =DdĮ|.wsIp3ў̓ 垦XY宙M$) =D H=wqO8 , aM{Dd7quƩF< fͨYԞ-wB 24$PxC6e$jw0&6TLReȐ`* 鎥559څy9t\s0:I!V)JZ9e5$ t4Bja8,v;IDeaU2d tp4>oQO[|f3m+c0!j @#$r~]n$$X^37SE0zZ4 |e/mb֯ZDjfeMZf.ҵW8 Ujn2q5E18*.iW'8|F*#^r ɰbn\ 5O2<@@C,K]\E䅤 \7o=7wv1ɮ\t=PGھ}ᅮ։_]p'Ώnj by04/HT*lX95n aY2Kɤ!]4"Zi} J)޼٭Zz腔~Ǯ;htJiepoS]Rx_#7Q oI4Lewjbfp_SY f}܁kp'HaQMW](qs `euberp; u^}ƴ 5eG=gЫ6ѹ=/C?+8 w @7nt&ReC p] ܋*w8e=Hs$gdz}`Z. ghg8x?.A}^͇o' V*k0-FmFD3m0z2#&YXffarX+lݒj&R+6t!(e nmo:^u9`k `O2CV{V)ϲDn-sizOùinݾu#c]Ƕ]:EԠ;nrZ8:nF t9q%aD"2J󈂰V1LY={~2l}M,߱ôwńt9OQbG kMA'HgG"b.Ŵ2'l4b:w,BG|g"~r9?{9x4d}ǔ<@$;v"С 5QPQd]A-6hYmK+ZY5LmThGҤ /|ɂoֹ+Ws;w0tWu `[{ p{a6iW]˽Y$s1p).HaowCN(,(ݬJl}9Q!m"X%;kĕ͋6td:0 5]0t;K5Dlڲ}:S^0蝮{(itqs]__B5ݜՎ4P"] ZpseC`Z焸@urP/ o7 eXt3'}2,,8x?.?]ljD<AڑJt]J&[/`_x!B__M+~5ڵba&9S i3%8ZTa܆af|bPgݱHwXqmW\t68Cv s3{Qޚ5_]pf{qq"]w@+,Hl5t#з˥WW}8]s%a$1s U`WFOr Z\N.D,tR)Ŗ}i9-P\R6Kz@/m hOb' :Z[o v7L W1 A`0k\qA5ty>CirM_.#c{C_qwcSv #4j́hWY@_lrh"% @Ilخ%^|PXev k|Ȼeg`kQպF%N'c3l՟+ߞ' {r'qyTznh< b{pOۆeyUAWy]`g:3׍wS$-K5e"aӶᝮk=8ZU |8@.cL) J&- s+uuZ3wee]A|Zb!d.?ws: |\X]%Y:V.Xqzvԥ[S~rg9.S//h ە+]Qz 7;r&b u:?'<\gZc!O#%#H[~֕Xt|+[_1[Qd `O"]0 za8*q,K Һ* Hr\QV swВ]b\)%?7=)ܵ @2haKUޝp@/_dKO*?Tc ?ypL>̧K[(odD0 )~Uյ! |=Ԫ[VV-0 y$KP#j9ȃi^%8/Q+VnҘvE1Ro4Hbp+û)AL [n" q E r@}TA&3%s7ыɮ\T\'{˞l/rȭe ҁ>͑1'CFiy`/Wu,`w;ĤVDぽj+xbYͬk..Zn!#+zD؎-ۈP2[yxHXF#]m[V7ܭ_|OK_[~@c^Yyz mNN}uB ,rJ/gb9EcJcHN}\s*v%keGGX0BNc 2MM^aYL%V,g>ƚnZ%9{>XL6 ceiY8?z%kZndwKn-kZYK#*y:ݾZ~hmb.۷lE?G8K~\.|ɭ?09ŀzeǿ2oլ_ZeWvK'@=ӑc0{AVrWy}m҅ftU[뮧g"/0X\XaYwgg2V- ~^<Vσok2]W X ohqYꅛ  zKO_4aCE_|z*nd-l{ص&-N/Xז@۵zK+Gbw{}t-sga|1`qwX/ ҮSw*Sq) =o[C$y0/dЌ/&}m6㕀NfX(e-@,S{6ڰCEd:cqΥ׽cNwd2dmqt}X;l _κ>ҍ-g=n>ӘLu&YSHkĚޕ!̋b=de>-o/$;ŹubVON2־\%b9Jé;7I콡0$a]$<أ>`w.] ,\ʖi/ܼk_2HR<k?~qpOFZ{}1w\hDR&֞pZ^>?,H3G&^*aݲ"2֝6Z%ȁO|:)]C-^-pu@&4ŌLhp|ZCSP{: |)„hTvm^-,CgIf#a,YIɀ`vު?5oqh!3WJdye#?c$@=6[wWV \{8*ڷ5 ߖ[BEW) v= (]2?ր1;Z8~(D{h~K*ܚjYW'Jo [I Gd%A`߭b/ ^,LҽO__s2O4<oqNNk>Ozw[h2[/\9׺`n@<nxm%k}]"-)e'xFEδ]LrWh37J[9ڮ]C\8i_YUT])(&-nح-?s_D+dX`k2ˁvsuVxMДm0=3]2:m-mG(pł[a5j[[i2}R7ϠI ʊDe|P!eOA}'Sj0G <3Etyh*Eր Ti2Ώ 3b(蜺r$M75 B9BFw{Ѩu]D|$n)wxSŶ:u~r2.sW_pߖer H`=ujk5)JцJTͷ>砟/ ޼lBY˖s+|FS6"a"f ⧣+i!H=PӄE~(h%Ҫg ciPpPZȭf*AkێqwX>m..djnJ4Xa|{Gxmn@&Li[a+l2;? :5?|\0=[Xd P$wz iˮªg/ja;{Lם H6dH w$dH$1ns YJUҊВZWM:ҭ;/Z.{*hrc'3aogPm}lXjN3&j = BLPauɬZXE+cО{̆= ̧ṰP[sJ@>oܮgo/fvrbd$@Gٖ00iB2AsVohV SnUUHCC-<v  fշB&FXX 9f5 r%KN+zxI N0mA Qhs%`L]|ڳT,H:TJҡ=HZSKiw%J;v[o}">fT- p&TL(?,3ֽ^.P/Q h 0_ X@msQPɂiUJ%0r#Trxu+VqpΨ\|[.3ftɘ)YF2 rΝ۾7/Cll̳nh`eVTq :I̫[:fUaCNYժ ! gۆsw4t|=eXje<^5? ۶=L@bP\>M4@Y]HbA(_3\ Q+v{1`,z˟N‡&EDQ0WQ D<`Θd>㕈n!g(->BlK1T-ؒ-UAQ:4n>b>BY}E+V43О=ST:(rR8 ?ӯ!ne*s} ʀo޺ Wtc*Zk , QEeCGL E3 &A/ZT3[نgeZ-0MRzFm:5(´Bnaz|WAY*0[raoXųLyU m*a\*JaX18etnRtl +P.j4l oOP0onhjAaXs+Jn}2g`,r)pܤf0r3. ;jI%$,.YPa9x;XޤkU F/ п<{+QSp #_p)"HtAw@uRΣ(Nb|gsߡQ̺1ޝ]H=cku`'m]Nin&Z-0} ]ܿ뮻nGYD(H,*؞~:cZ.koCr>>wziZ-GE]JBkr9@?d\0{Gb:< 2`@ "O܉qID@e\ŰL3f,,'irJRj7 붏nST0&es6̳ܦmT*)&BEbH!"om.x ܱv ~w]{j_ ؗw'-M滐~Zm6e:e1˒:/I9 3 4 ̟ty/v$ c iߎ"tW FY-I _ ;ܲ\;n%̃NjHG?:n|`҄Y-#dGLf Q%P|X,.C&w<Ӆ%FiZeL6#6]16x0ڵkGO:?YKTdAL)! 珦u~> qy| \-_7VbV]b]w_&`H>1 x r#ahҡݐ4ӖiscnF2 kZ P~Jf,~+Ckf%Pf5cr ϬNrw{Z XU릞@/6Y2&*m~k7\V+],!D U2|w-0t0,b%3 O籀ߢ&J-sB4H2@o߭۵ϤMmܽGgU_Tt$mb#:/ж$?^+ml[<,|粷YxfX3b/~+ر.mVWUjӹw{E\<8dI=0 SWX"RJDwέz;|[i}cL5}v::& yxء}`vS[tǩx Np2|3 c ly@w1KnAٺs; N#gዧứX IIV,6q7߰%L .Y +(v'qxzS Jcϔ]R@>Șɬq^IdshˊkB[=$`׸ϴ;^ J#20c|tſXOj1X?S ۪I|':-s3pCR}s/6N&SI;,n 6́r 1OtAcr[֦Ə15k_7tG5X龇lof>wW}R>1$20“\)z3a% p5nd@X@{j9.ZfY6ʒ5eqn!Õ@21U3N`e1zƈDd/ҔVRC]Ƞ @gYXaJ&acMEJqaHqqdgy.a{688)1ѡΰ,9O^% 122a l;1] Fm.Ϙƒ9y2ie 6H5woTDrD݈Ȕ&BC.\?B'*) 0́d, xmvqzՖ;܎ yVmSw?L5> Ү[,hG[~6 Ҟ =%#U8>tT [J &%N8ypV8gYδ-Gt疓/ 0AG=9{oMaOܵt`xh´/;c1d҃U/9MP<CX4Bs hz!a4qJ#-HfR41BL4e\M w Q-tfd6È=N'|[ĮI=n˜22 }tB&gx)@9Af4{"LYmK1Q-pέ{h.lE3/ *\L @8B, )U(ZOIjc7$7iGg1#Y'Q2Ʊw;%00dPRyBeDH0"Vwc3Լd'edYJQM*?Lעt JR#+שFا(}2ўbrp;3Sd(Dw1oY;׍!dOQ<ͩIkA{:۝H5'yɸp"HMQƲĐImΝ,I%0g.?`tbs Ey&Y&ȂE ¦ʒ_izID-J3ěexd%O}M7d3 _t+6$i5(yi Fa)(ƒGØ%Vc^2H5^6Szxte9`WRx΅&'E] qϜ46 YQ8g~P8e>$N t(u;Љ:i7oڻwa3e iAŧ߹K.ِeG?z?A:+KylruZm$MSO# 9FJ=SVk''O^rc(_8}CVQTJ e P=:(ű"G'~{ݩ/_s/Ŷ1n{{P\~^ťPފ)({F^ܳQ ignwXjs.'3dB 3>qlY2BL[A Ji{xۥ2➳ A:oXB2Inrc.Y*R$y+ȠL0 'eUmibr/_@!=غzD  Fat+-OU$5#AfARg\Zk4ZU6}Ч 2#M&I%8:J2(f|x[[nI hS֒{8R ;m_%YR(db]$![lmteeUITSW{+á'l'騯=3ǚWmYxJJi ZOJMZ#fDU[E"IøiDuj*LjLZRMݐ Vq ~lEDb Kmh8{)n<%UfʩQ/6Ո;{_~n4ڄcD}mM1ѴGwP ԏ;ё7K8Ŋ3+I'<}TrO *0Ew)ޤ<3^90 lKʧ?G~ֺ jzݤ&2)# iZn]X㱔ALP(tI:1{|.5S- ݱHJRm{Ϩ^#2_W^qE]?00<ǿPCi8t__fi-.!d1,+??~~mIG-Dz^8›n:3!O|h+Ly{z7>sժU(1<.}Vv{]zקoK^pqM` W^yCCCs鳭Vkvǎwɟɿ}s;&/m|M @_ gBݷ~7g KTDmt%)ld8Uz^<6$|ѭfsSBS5xnu#=2. g>Öq`͂gy>Yy2I`@8,&Oi*d@K&i!D&S`$=QO<%92#.88[f"\up1C=eb]ƫ¸g?T0_= ۜQ2uFtƆkfxO_/\M5^xP{ggvfǿc?I~;26y UX&V$Գ6I [~=ꡂ %qg=ƃaLLlR5Tp(&lUOS64Ј{~>{?mwj6g4xXœIϔRmAFl3C{>̒O}h XgAdE>sX %k! <ä/2N @[' !,ETY"Y㢲X oUktAws8%EHUeNJd1BqX.~ag )M~@,0[ (AOef蒸2Cã$1:Dݻwi@Gj_tujz[A mܸiyk?ozӛ"b /-j?'x׏8ZEBj_R{NY# ş, ox%kUVm"z}.CS^/}_<% ӽͳ'~恁_g>7p~gb/ey}؅smi>3 Wk~ .M 凢ldݓK~~7pA$M-و0UhKk䲑FA>JWX%,>K,䩟h<; GijVulfcGߺ@w(Ov(X'LPEJԵb &F*ɪW{gnyj:5aT5W;wg=w˶K}?1HAnO6͐jo5\U_7o_놶=y.oT+O"1cJGO,D]/矵v`OsEf{ī\LE"UCoWf{~a% w޹?n+Y<ٮwV˱ӔR˗[v:$ܧyMT&%k 'XYv, Q"ޮ8%pkhK| lkEriģxDL]J3(p==O5>pEeZ:!%J|' eRdg*,N=ϙJ9,JJWtRo[%v)/>9jdt8ι\~/*E< c~~˚5k.Z[{uzӛޛ_^g.AL:ᄲ[D|;~[kW>g9+Boٺuhw弈rB/{~n```l~ky=RXf1ݭ[lٲ!I4n(L[KrqOg.' )cWfi1;}D@uktK!<)Zg ׿+@pG-ᰨ}6IV}.j猰xP`a9ԧ^}WH)OUa`CCC.rt_z[S/FZgP8tWg1Kk׳P\9-[F~'ŰOs7lݺu_zP<9/xaim۶=M{{3'~~=~},>zւ/>ell,ML~qίj9ۄgtr |!Fu$4>[!2!uj$ g"h/ Ĥ #lDmF~F)=Ѫoy⛞YF"Zll #_arxtɴ\H2?t T "8@e&ʲmg_sn : "2ҌNf}*3W=m/ iy~G*j/瞺uT[ 鎭YBsM`E}y<G˽gm]3sM1&lT(Uۢ7WםLsd$!ǩxICUՄZ#Gs]ZR$+'=vTdj `!9#ZJcҹi&qjG.*QjKxay 9KY̠uso57V\K,XEu4voٯ%sOIOzyES666v{ޗ,~`*.\۶m go.\K%^E^,`mgXJH9KnXj3!⋟p7o.݃r"^җY,˲Gt.rROzғۺuP ԋ?vW\y -Qw}yg]+ڧ=a +)e{!Lef/wqq;[ 62,k9I\ҮBJY{zPʴ eąWL ᥂3&=ԅypH1B2S7xUq)rٴ?u&(\܁!,u&GYΈ8j$<[ g&  Fd$"RuKYsv1Y$j^~ʋW8^.sX{Tٖ!RU25x\W:YY?k-?uUaZ+K*TL8x䕵x2ٟvޡIp_}cϾHjPVI[IUYE+] \mee#C;ptPʯrEmƐ^ `f D^>Wz5==rr򑉉}ǎ?>>~ѣ9rÇ:t$$m۶] \Եwy=~=y=tСWO.]loy͛/@ TyF1ۿ^j/Wv7>) իWo*/?;;;?zS_Ec+ +-[֟nIM"GqwﮇGkBnjFZ_VG^V) `zqZ-9[˥^'={|bX:| PG3xp ր-#C=QUd K8 Вtf'GN2K=/\s(-䈉0r$C[׹-Fx"Bp. vG5g5>e UFpi,r.#B,dg"eTy[5u7wՈY*`Eg3pz7,4X%MKƶoU:Y[7Ыi?s袱'n2µ-ub|Ӧ B6v|;iw g))d~0漼fD5ayO d```?k~яwƽ;r*һR|E,eloZVT';w5<{d1$ v YxUyzAZ5rsp}o+-IKNAt#%Hՙ%(4V\s#X*=~=~ H^>m?d1=[.=|<1Ig2BD8Й ,cچҢ  ZH"m0>PO=20(V3ַh'Ƈ{sS\eJMKYeEk/\G:iK?? qKҦȯ5 kqC~(+XOIIGh?JWQ;3tbǀ}N|n'r;~}Qv&x8ͬ믿~CV[4Fl6gw՛ So}q`˿ܹd+VX]r%mڴiVWj߾}%y[No޼yp֭xON/~;%ނt"+Nt t+\e9+-AS3$#gG;0! Ő̚H ]!!::\dlaD r H{ZB!`KW.7NK@l]uYK%ƵӦ?8&#~C__;N<@=odʸ V]YKk \ҹמqF<$xA q\j#p]}WIyFsxgS'ZJ!VP:_[W,V7O~`gPGHj']LZ,p8Z=d)fʺ@FDž><+1TلW~jO3YˆVՕ$VլCuAcWn{ҕT'j<$%kQ^\XKƘmi[ƈu8zAO>/SW]v%WS-R"gHNcIfhP|-&2"U)GAW]ʻ~+DdMѻQI& Pi4{9/}3;g@>GzӤ Ϊ7:ߞIbY?FE卿o/2mAAD ,u 7T3ކW$ĬYsu|@ID5zJ2~ފʺADKm3n{oP6DgZt8Pܗ5o j:5oxg m^0N47d6f~N\M1xE|pNGߟT%ezv|wǖuh7nZ08'Bk4]y啗,Kn˞if=ss7Ϲޥny}aRKiıGa/ X@G"dP!_]p?B +(0F{^/8b][p%J4ά4%cG8֛dVG£eCz|dө[Z87vdiD=rH*jzXZ|0eZ8-BqeҳYqXcd5XМŃgǵ@ Uj* 떨gE( S-!W&JYB"y &Gs5I)Y:^$/Y}PS3Ωʎ6:vj*%̄Ϲvwz"z01"/3Krв[{EXdFƓ+Ȃ1vS(8L4T!>a|=c3BѻZuj_%*F<$c +$g Qٔ295Nֵ2\݋~5I퇦3&UDŲ. |Fk6䭸/]G.hUİc&Cpɔu2nCiUxFca-0h9)PV?B d9e+gu"n|;Z;IDATĞJ, CQ&/2EuڊLy&E˫Yd1O[ +YP' Aoc!y5)g86c"o=(D*5o2TY1wЗ5~}0-^g z:yq < H£kXepWdԘi QE{COy`#Γ<#jmI%w2FfxcXCkjoqf@dwmPdT{~cLsa=#F>p9gR ci0ṙ`- MMYI6}: m>k77ъFF!:jH u% wCnKu^q,,2K4饲{\͢RXօYiR``&ҕ-2mb rAMo꭪w~߼򴓱{ϕnذf͚< {GeK"^2KP.3-! ]fw \7e.y7Y[lVH'?Ys~"k8;Yﰾ(^|vV-\IrP"[|3*M[Qew#G(&W~5L?Z Ōel\[=i"WAwZ`d@IZ3k ѹ`Ukqd/Z"ϧ4b,,R.@Ώ 8ZyǾ,o^Y߆)J JhY#=ɰvE/FYkrtXC+FGS+lj EΏ탎yȣG2K(;F:%5{:{OS_:t<'.#DKzXGA 溥(>UZ)fw!eh rtxxJ}V:^/fQczZ9Ġwy?vBsOv%kօ12ykf͚󦧧{݇i"_kʕqqW~އnirUwWC(ɂr-$Wx [r<ڨk(*70+ _2#- p𧢍}idזq1 lz&4:RTkctę+a #E)D8ZD㔗X5dsʔ"֞ߥS BZ]k<h[FWtD ^IbrMCٽ9<,yJz!P^Xd`D+*F?U L̬Ar|g(%*`VA[ld&uÌL<5{4hKH| e52HtAjUZδ;7_87pGU <`"<nx1ymGDDADfj@]:6JJD;`/֩:xQNiꡤN(!K>'pX:LA4M}N5wj=:FAO Yzנ@xEs=-H 2n=( )ZQVaJX/5/}6^:Ypc5d2J$PL e*ceIY!$t$%K&; {1YѣY*x!6l8<>epppaY8nu]2^;~ rVkLg\p.8z葒лw>tuAp90k9.O=tP^z6l.}kw {'R zu{]sc&ןaLcvK<]:qYHtYCZ4p<@!չ9:H#(: IGu>2y6@5 t n4:1V ZI++\ & &st.SJČ9еgF/<whX|3a#SqVʠNg mPҚxlFd0rayP,ʞ3sw d$~fJxƯ0bzKnxE0Byeej&G#k=lDuY}SbO7|/T*Ç{zܯs j8wOGj8c[rb-f/Vޏ ߴiƥbǎ˿"I>|Ovn:}3_[~, @_Q$ܽҗ /і-[6 oZv5\sioūVBa5yW{b)s#*_S>~'+VZv;zXL4+`K#ІEfh(f|36TuvsAZM34Wذv(R5"q(pADOv$9˹{5Kbyxũw(go%m s0ӣ D1qCF6ض>gRmwk{,~D9pg=yjX3RWd"+,B14Ijsj}麫,eg:5Q PrAc/읍' i5aj46O\ Dƽ4}ͣ X~Ɏ ZeWYKqyZ{\FQ:Uq0buVqR_}[Q PE;[> ,xPuHXa5/NY8ŧ63Zx3#kYO|"A?"< (Sg:Rf FTh=EǬ7yc$><$.S0T=P{5YU&:gJ"g.g(f(~PMImz*f)xX%iĨ f8Ns*"Oٰ@ȷ\dy.z0{p]MlO:˗qފvPQJs" -R+Apw"c 2HU ޸.ZJhngws%<e {&wY;yeO_p Hu5 lOQxkFcA=x잣{>ˌduJjT; gRgIY u45Z%)1~BvU*]}+T2qquVZYV럊YT+Igk9 2.ooseip[E,ޕ"2U!*c$Gzs'p5#pt#ɴ:`2P&?:EDL\ _dJWZlۭFHU Az#h332kD <;-F i&h߲IʕM]qW{vk{- xsJ=˽ԝ[nٴqƋYfsD] H߼i'?ۢUW$I㎇{\mYx`M7ry/|[n=W¹,v>|;۷s 7ٶmkZg-%I -{ $,gނd&WƈWr}zi6mh/̧K[7]aM$! A2yJ`E}@/4e{E?u/E6sƍ2%:wʾO;/ŎL}:L !Z`("̀Zy@t$ϏF*Sk7tn9x@k{i?DbI(K)y||o9heijPwT-l .^U\l? ;`4ag֓)C6U1yDЫ7UPwMuk`xVҡ 퇸`i) griw0-c)Hxѣ;fAڱM Bb0'6Admln?$ i6<2[>VϪь?zƕESyY[ nDi 1|WX ZX<2 5hĐ!M1rUU ^}U>duȤnAI[x rb Bq$69(>里۾OYK Q3q “V1-J&Y&2qZe㳖o@ZB>+'ө1qP;|u'~޶2v1z􃳟sI9[_~͠##4?oHXHѸF<() LYQٌ{VڶL+PZ2KZ<%=y$leyc 7n$UG,uK茂#_fbH,A+ѡ @q,z@K΢ږM\M,;b4QBVAt* \xe. 2LuLw_w)YN?OsY7Ae*:g]=ZJ*!Ħb;`:zA; _P}A7y`R{LylK .CӲL|ZÑhc}hcw|w̎k)b+BYJ3𷎸1jAe6zؓܰyu\M=|d⛏|zXf4c Rȴʄ1A^pCmg>)rܝaqxȓ6iV }e/Nyt\}K_ky F0kogoy[V6X=yXF1(Yn\R,zϲLڵk_OC"ѻr'd*}yEmywֳy+_yq,d __{_g_x pdZԛ۷oG>wᄇ7AmZ_}}C׽/ahh1e]v _›~{OY8K zjkĺ3b,_n$W=o=;Jd8 TQ̣1e1H.g;gyy5kVbY}]">LfCjS޸ן-ŋ#L}6#F<"v)nEq>ﯾ={嗜u'| #x_vw7"u׭ټ0?ԖIl?{CS6_K<<ȱOO!=ߴ80jP+/ X&N`Ƴ;Ә::$XU4tbZ(Ć}zj-iU q"=n3uv>P& | qf26kht |t=s$ho]M-g\ {>5M}b1& WsdGXjcONrK8fjڶ䥰/ySN 9կ~8pOO6uXd߾}ڵk\߼/}\YpQ(J9U9;ޝE]yAP~z/u[,}̹OVAL/|swo+/sJmݶnoQ>f>k/.gwcE>w3g-um%t}E]7_r,w] zw!ꇐ|*.2ǔeNb5w\V1/2-R^Il&ăOqex@چ- t=\R>- .#iÍ ٽ(ҡyB(?ijفP` ^2慄d_~cihQËxaL\ELxtU-cgyl$n}w3VˀB̫1ҩ,))v Y %oW.|E_{!gX;i-W GaA:੤#Y@P'^A*Ir֤.˧k&Q:DIj؈!XG}Mv*,(7I1ԫ?d*[Wƕ jX{ig~024٤W ( qW#g:ԣOZEK.!*\ Qrm "ăB:)ftcj>$VS4uqpnddmnlJzz:@Qωr]EWyCy=t? LVȱ (^d)fBa"Q]n hetu7pÏU*`Ag>w B׼q\u]~~T)Z7Wرc[Db䞄\E^JL|O<++^_\将a޽ut[&PYozӛQbn^z1 W~v o@u咳_Je|w s F,==q-WXq?>YyRNXܛm?{Mo|ss( @LXȴ?{G};Ό0*3U?2Cww>O~C;* N?]cd]"}V^0W2HcV/u@C6hcJ[{pɚ'g|G{>Ԅg\6zV?"XZ1CAJT(\/10RECYE8cAtDf!O ɡZdԐV.t|.@ed%mEb7;JCmMϑ"\ q"^(U3&InQ Dxv+ܝ 0^e%r02]%/$&,t]tֺQAYޢ ۷Ye}mݻwm۶'~+J"jfypp/_9]v=\bM+:[2}O.ЧT9^~r"$;SW4MwP+k+ߏQu프>Λn nUE?פ+_^/.$64w]O썵C>|-oy>?|믿6m۶1Ǎr"@_j^ͺo43#+*bBJoȊ:0i lJ%>Ż?quErZsςڵf[Y)*Ѵ9Kt.}%mec E%: Pą5_8ܢL v4ڊq-sˈ f5f@­1^}{d;:PǺ R6ӧQT"V)Q𤒴֞MUڶ4vɆ6pR\x27A$f/k Hn4)npϻ_\Q*\vG2H &19|<]~՗vdzֱC_=_o~k׽x/b> oY{wojT$sxA|"8=~liJth'F%5V7mĥEdQ](Y.hR=MQ(@ HC8pGPk?`?g=HUµ+r]AW M7ntoxSN?hpX@&2",T l557b婕JeQv=_nӁ:{[l.%Z ,ԹZ nZoSPRtuw&982-%aTJ&@'ƕ-Zt_Gv~u'wThRVXx"ލx;&(3!1*. 4DY& #2 *}30rHǛ;cOC 89͉z^6VN- /^uS`+։S9y6i٘Hxh \yrZ֝tR|ۦU(I)(H06m*H(*Q¤ q(4LP4eRӊҶ.4^͹ם8 y:D{N뺾\ 󈃫qAӦ#(XU%Ɂ:I2zf*FY!N_3-e kidSAe'S'ӊx?Zn^v^Zo RJ%@RVQ^~R]7|t2225y->==} Қf"e)xb1b_K;4? +/'խ\=ozӛ@}xxwu1뷟1k. *S~wwϑ^zeoD~{ S]g}r$ ;u= X':}?gVI!0Ptt+uǺrjДDŽ* \Xgu.qIX#OBkP͒%P 0鮬 c@y(݊ݛwl;kPBJ }]wŨV0cֆ8=fgFHqyɶ_1Fsɜ~u%՗lS?Ny[gY;6JcUW3KM}^>{{7 &l fyɤA7Pd*BpX8@v㡄1"PFZk%̦Ti6Up޳7׃gO;Q|3QWmٖe[HNHi$@'_: tޟN2yu{tU(hHR&%>)AoϩyFAT\fS1cgEoMP&S!0\izǞr΢[^srq o)ĒjpS^3F C4<.hFiQT=d&T !& `Rjx!`b '4Nu|L-O5' xkJ*ELΙ B)H$e耢"M蹀! ƶ]w^H7u*L$Qv* fbWWq]}__#eZ!iSt矽vkVS뮻n([=9t2k(":Ƙ[|y?zۻklbbb~ok2't>ړAȿQ%N tL8vpY%^ΊJ=~eD^< Uʕ yhd 1.s&G2B;B1BGwql*JCUurux"P"ڴ?R8]$>'}\xˮ@ 8 r^3PDcqtE#Y&CΒM6NSd+2(`-VȋUUp n4p'zl'9F 05!G|8h\VCb`$w;*cpC|  Q9?DTIqh5!MZ01ݨ3Ͼ2Rs48[ j}vhfW(2 Ffҽ%(nuV( rE`WlA :8b<  4"3?M]SaH:4}Ӷ'kGNIjLcT Vv~EikrDooG93(~hmTB J?z4R^7;Ox׏ _I $';"$SndZMBζChjX;()G(`Bfh™9Gf굣Hjɸ%4۪05~@}{aP]4 9rHHu DT t+X? 'O:BpbS5YQ,3iTi j(@ ] +&6BڠpuAh@z]M\OI ]8\zKG C)"A* JJ`0R4S625=) B Oŵ%K{-e,b}tOC~_2pfff7~7[ԻK_қ^WM:']uZab5f`=\LZzȫ}G"ۿm<ØB8sLjwcBX_`G?艅BJa9ܳz~fxdd] E  PcR뉄Df(an5H4l*AQ)&*;_1: Xf>=22RÇ?݅|4XO{= fG mqF3|PǏ;BgC-5TDĥlJ!MiK( 7Ց1 캱20ig<IY岴 6dR5DTrsSY%- LmHx(1wofN=a .02N(="? 4㳗?d"Sd-lJPln͂ϒJs}*Lan#ݼlY?@A 6)TnSj@: }Gp,mGfMJeyI/]n\ NA2ńnŐP2OQ!>|@y晼M+=cК9wu~27kHIN$I>d-g+팒'mZ&A؋vWg3;v'ȍ6$8m7ݾ pɷ3 EBߙ/ii4y Nh)=%DBEQD5 dԓ^єҘQ,u L!o4<%-9T-mcǎ &xJS$no"_+8 iKL-Qj8\ɨd:vhf3;BT\ۇ/{lXRHW-W(V>ǧ%Gv]/LCbFo`e<b^r0_>z{o};ФF'W):Ta1OTR%)j 'u@St$([\ՙ)*6FmuB&=Tkfi8jHW\}džϑVRH=&r6-(a:DQ vu&qXg0ֈQ02IBQl&I"LLܪaS+s`SFc@T*o[ k/NI4? a|p?!W+7GCACGp=u=\ 8nvm./_+hywT*u#s3oo>V [|}E ſjbRz)([o +'|嵥RՀN>}=(r2k ++7^qsxOF- mјFz8vZ*:tD1Zhҹad>O*I)h }񟨹CY<9Άǔ.ʣGHSJZ1KdLs Np^2d`NM  " F)zؠy G֥K%p OՎ֔Q{orukR4H聭knqԧ[Q#e2cMYu:ޏon]DCn,8WG;wgHh5}I;1>~6۾yU]YI8#7WQd2S<-}*T L%/GGo=/3xJD ω Ui"!t(K!ݨ^]]LYO PL9s)Hk&Bi+ _knPٯGS#\B1GyQ46e脂U>aGKEl)'q*k3}gfF\屦zrg_P߹n`fƞ2H\*}0سSD2Y: Pm T}JYj宰@ۈ~hCMgK(P_MU$9lm]HHOm{+)hNTl !%x!MB4' %!6ֱ{g\v9xs/zыZ󤦍>}vu֑믿Z֙]v@% Fo64y^4oliaO fj+:UJ]w pr-$6+k_ry_ԙ??zlO:CVJU2cǎ⊑#G4;w||QiF2hj{znZ_:|'jn gȯ:JmڟٴiNuz=je a6곟ÿk^wO+ݼኍٓ@i)ܕڨXpQbhI$US X D˨G<1 cxI*AKRhe0 )+Sn={S/K~?XS޽!xu۸ms|'fL`!? Ukn\wv[{|ꫜ{!]ȀM )XL ʔc&qb}g1zq(m.py]xP.քd1qbm #}Gk4Zn}R]JcY@2gV#˙3kCW@piRm?GP3HQ\Xi+ݺ~n;1㺢=YHŋxFKuJ4xݘԧfɚHbQ#2Quſ{[**P=8PQUbw$:,:CqWT6 %O$DIim+QqdezTI"-ʨ6Q2}q"7m Qb:R"h"$<8tZS01=XZQLB:؄d6#S JbEu NO*N oם/jd=׽D] R ^W>Sׯ_vZ"`*?qDn3y9PϞu- eZ<'Amsc=>|\Vk%8}c}P>я~j>_W^;rWR~C`rr{oue6fko*5.K;vxǎwM:^WF}ox6]{)=ZF pJh #u*@G -d1@n׉._֤!GfL膠$N} yP] Q_V8 S{:65&23Sdq7|礖&I<ؓ=^ry _4|m&e0ŬLںRE,%.̸u\1Hg dfń)PBE&RJ)tFQLF\#O)҆^ 8C.ESXb[NU A.gD݀PPe*,ʝơ㺦cL(HǸj*nڴh8--jE&DÇwxxx[/͛jp /a8/}km)>\cL7,-q9 9EQJ| zӆ o,DSO=ۡzBZ*G׭[GG"\{j+`>}af}#~ۉ_c]"5) "zZL 6!2PR>0.9d7u9Jh4)Mq "j)MƬ=`.F<'(Ƅ-y`"VJ±6n;$B)E7 G8NnsOՎM߷O R]Q3pY~/^xrht-X&~hiiRŞ)'S %tD)ߴʫDj3Gy)Hj-[M1*M~(XBZK*lRm4}kDE~&#lԄ-ՏA*2x_y[VQn~}="?iA@;a;ϑv|Ԯh&VOO{ 9,g_g/~!I ə3g/g۠^b|7};3A7[VI~~q lql۶m~\#[ַU(tu ߓ$#ydό_?u_{^) rY`R$Jk0DLo5IDiXd&Tа03w;-Lƌ&V)Hg"pǷ&sOg`D ӠfDJ1@L R!m0M,ΝA;m>}渑’cP34RXX#=2fKto\GMXwJT_d& _0 )j9Nzo~_ҽX;^6{Ѽ|N} f馛Hr̙7sKnz%4}{Ï>ɷ ˔F1n;?|OLL_/wu;1?=99I.w/uL@zs%q6w!ڞ**l(BD '2*.J3B-RbǨ&"9RS3k0i_'}{|ɦ$u'r""l8[o"T*@N]Nxꠣ!I&#Ęe\InJh҂)dYy~Bx\^9e9vVGAcPB%RkQܖ቏&D֚N$Y7nZ[FoDVfClYeE(*<ΌWrtٓMeI u0j1CX9.( 7cgOpO_aPo֛\oPL:mD i@ 1B+((I@Db\II+Qt xg""vG?5b{h*)@-tLqu3I6q :A1$ sTMfqDulVd[444Nu-4Rf9iZL3ǏGzKX,o}?+_;ihǏ??c Dz;8N?kE`\uۋ@ (!/|EYB:mHZ:&)RRCfjdv& {DJEI40ShfDSN2-i) $ SL)=Q*֧8LMDAxfZ3s{N=`go}|8zr o:;B(d\PrƵl R@"*R%nU\k(E[WeJ6Q&b< =  =d:+БqՐ0$H#]5cRV&l[Ad;9@<4މ>rڗdH>7YOO<|~nr ^olC)'@`膊 Z?urOg`SIiQ#Cz}YVR(~0`h RWc/KۊU\4%wX  SRҋ1P88Ʉ]S=@4VK7ҘDLEr5q6x`ϵu؏//R/7>'7m"r pZBZz`TPjZ!9{9vj׳/Vj[IӴgϞ=] hGW>{vy_ 4ַOwyw+WtʮM7]uU7'1fs3]&-N\]nݯ?OLLV[ӳqȑ#O|cЭ&Yf2;Q%A>jK@1p U`Zj3&d:mTIbiid0j%h[I3IdƊd* 22IW'bJOӨ)c sz/?P Eoxׅ+NJ'@&z1w:^ث:N]6iXS=.1kOD"gSR(GDJ&?*X͑~^cBNЅF"𐒶d jdUɝybFHl (U2` : tU#~[JO'O~1 94XcDT㭧_qcNSp]wOZ?>ܩӯsJV븭ħ׎%VzW9;LOuwj[PP 4* lJ*E:VKʡ@8+!!QSPHͲNlN;/.y/,w;G) 1l*Td=T3Yb}e2ajh2TʅdD=`Z &5J9# v}}&i>i0dYR/,}on喗P_MESǎ_slmnAَm9Ir-7VOt  5~?nk3}rw60gW۷o>::sRL%qO8q}#yƒ_O}{.}A<3ߺ뮻>EBlߟ"s_̥hZ, }qB:h^s̹MZ/wAEWu ܣVI`p]DLB.O12g$W\SŜ')6 *% &pSFs" JR9IS-|p]W Nɩx2x2<|_W{?.L3&D%:-K[I*b#.L*cChQ!. $7(I?SaH!u)aN58~qϔeI^+0 % 5 Tª CdGgM)Q3Պ't'# 3FzH'PE{!n^zlR=%"Si, >R"2gwM19 qo41PqH=H)B3ذɤRi 酯s0ƛǎOl]#c庬D))4</l*fS BUhƀ,/ *j ɹ3)+8E.= l>ûj}߹j5?\|NNMG5ҋcΗnc\ܶѺ-J0HAEEoM_D }o}(fZRd@&LFFz"l f3df`=ΥDRN 0\cEًb%TX)ώc,=d-!6AcTV(IҾQܵsy!=Ѓ{ _8IR1pF :) 2s<@- o@'3*rlB>CI&}c]Fc]"6qUŦ<:tp⃖Ld^ SS.SAd S>+,1*lRƀjht~Q:fR-&e1$IBpCWf!5 t^츐*dkWA)_h!iTZ0ǡR)ħV\`Í TI*). P@ةN4^ʩS H,yxZ"wY\j1LpAknYizT_JS,nD'0E%!\JP1`$@,|JTh6\pi2Jke)[#NR) HSb?#Rd ʘrji3q(\=7:^,1>&]_*BCGOV.]&I|K߼/[Q')mty W>gY؏I'j2*H8x N arXSUApeG$5YmHOlHvgigcBa߇T,MipM_T(  e2jQԨU&1hDyHsb"'+p +09pbrަ˸aH7 mExIBU:-7"(w#sUn<_D{⹋V"7a)jsk \)Ih\)DRc2XadcA>3[X"SrpCp97\.8N ZÕA_IBNQơ$1ʅjEA9zZ2SeA3`MWD-|JuQtTyh8Q2hI.K2%i$91+MuYƴ(#Hҏ@4"NRp=mZx}kAl:%tfi…KJ% ԭLg"Ƈ"Ϩ1( S :O3ODG]0QFB3̰A|\L&:A,c^UPtUnu䤦Bؠ+dxT>1ji1J4tK՘}.4FSZ]*]e)ivӇ mT;:-1mܸğj Wɠ/C ++5w$3Z:BW:@ M@~8TCq@Z3d@pRCL%O0Idb.M8d4KYca)\A3Af|G$I.HӎNȀ[B q&iF S);3o|4^I{.y@\^X,rퟠ ݤE^|:`[Ƌ.(=?^ߋtMr$w Q۹yU%[?@x1`(n Śeoy3]K!*GP`Fd4sHSu D2D풦Nkk#l64GRڣG'%,91HF9* a6AcKhI0(ALZ!1j˩j1(JゑABGFb8hAeݥ8%ZHPcd@RLEL=\&AnI0v,DT3dL?žM⨚.M"2izR!QPO=Hk LQJwUM0(lQ4png^ 'FЯ)&3.14aI ,%rIR؄ 8Иה"/$ND?H#E HSؒN: ;ޘMF-&ϯ&m)# 73g4kAxH(\\ѿ\\ftӆyNMҨd\7N5,;°>{YLۥ_ʾohdATx8=VfL#tlF)`*D3ct0%6KںT6fI:ȈU$!tǔ$׸d1dCiӤ# l&!(n"1hA FQ콤a,&0JS*G "j_ĦfVS 341RFv Jܰ4T<׺5y.a `9\$ڣX(u ) F9 )H ?Aݬ@j-fOTicOLJ2Nb\Ĵ6B.x]'.[s}R4Ǧ8L122 Smo 'Bt<>::'0F+16b5>6Y:`08= ʹc GnJ:Znѭ%gRJi3/lcJPqAXa;FUX3kOh;Eۄ,[#;+*,wiil{'5C<+̉gL Mß:tGy2'q~uk~mbӮjr&+=Yn K ϶4sP7t7`>%Wu Ki:d.M H.3ˬW] )s'LREl9y1bbZ UЖG4)|ar"9pClj`M aRҍ B{fCwJsa6j#/C×6cd*q qP0rd4sm@s.tԖYlfkDfq ңiI!F'`6+HF zwT-ܖ*pVyaDKZC4cҜ%uͦHsyO>{1s2SW@t0!x D8 %%RYN\P/Q8 r+ez_d of `p/&E<Ρ1!( dBoQ{ˠ$,'aþ}TN_}ŴL_(}55KOk'hҹl\1zfrۃ7y~^<= v½)Xkd';C.7ԒR< 1\x;nP,ȎZ'ʂN'sd)I~1uaM4lĘ(df~ G+ρZ0FX*Dljn4 5UMR" Jc8݋pt Cg!]F`L`.[IL=wD>o{dUi.>X O'əTCl] @Lrl,P[nX$8Nb?Sܝ@U2nд$o weG7W;> 3r! Pb%†X1NsF0<K 8=TAZh3A+ePM\Ȗ(ࣔ"Dhk*BmSD$rc@>l+) ӠW1isc3裓@1pwSL//EkܶX^h})tcRWS;!s`N+9biߐO #6O*]W%q>92S &G#S.< :U ?ˋnH O&h ;HlMq~V1^cQV%HڸՂB TS)h6 CsżGk="k,$/-}oeԋ?̘xq.}il>"coVORQM}5Cn9i4ӴRBJVC4򖆲001VZy"P()hcp$ni [qnd,_@)Fȓb^ql<|'8~!9?@f{jP0ֿBX>l-љ=#fA.{2(ܶAR-߰@MJȂJ[F6QE6Z:mnWCN)Ic.10g $zGڹG2,C9ʱ=,38ج4*dLɘD]?  eiF\4EP)[S65AHmJZ-_:,% a5[t7Ȥ1qT؉Ϟ!4ia9[i|ҥq&7S 3~Fĉ50zƇllMEB bLwk' c| />UϚ 5O:s;>,򭷢/ɥU-"voAT&d. 2ɗ;f2]H=AP@<*| 9\-ӝ@s΋Mk_fnγ~y8kU.5z@~Mn7[ySjs͞L`^&fee #i쒴 ';"qs ۤ)pԩGeV{ڬqpő|D>Cbi}\Ȃ S-w*+Kw^H) Lf5UfNc*ٽAo֬s`Ϋ4bׇQ`L$&_3,Exۯr˙ *=" Ю4i:0"MAd_?be7)wYqE42-YkF|:!jkYƂv}H>(>Bm0KIv~}Z8q,wo?A@V(LcDV*Z'GEP B2$mK[:@P Ms&$em1سg9C,{2w۶о~m+a璘/W ԋ;rA {0j%XB z\ ˠ{rVa'TUG pyY2k9Na1rs5ov J=wa;ЏW.S]a #w [>D`Y5z*ah8bu4+oh1ONzZzY f+~Ic%pXmLA%suLV0f x-dϦkNBCs {텆AcXC1fkp uz rx́\h6x:lN9K(ņo><;vj{nf̋y6K}S;iD)(3p)lL{F6Ed#{W}ଆ;œ"5Zh2hH7˴ fŦs9fFḷn֪g9NZ9iJ t<|j=Ƽ3 L*Gh#b 7Y>(|Q*}8c9II5/p*7bNMDnǞjKkgH0-;x~vR؂S.!P_߭n߫b&Z z5\,~ζ=f@ B/n@Yio@o#2JŷCōnkƯr yaXm~ `MRH oK|EtzJ$utn}ִlk0*X5Kwdt4QpJsK2 ĝC]fk ivւ^Y=7 P}F¢ut[i<7{8h+u .QC $*be` 2(W96|_$&/}i^Gc `zs߷J Ͷv^o{ȥ7~Mw;mm{!d}Ѵs1+|p&r<@?\8ۀk$mu2?L`w 9[7M|6g6x,hB N\iXeN%NYȬ6u % ůJ X ֔CYw0V> ^zeKfFgk,ؑ}vy"} s5\a4n巴İ=Fg^sx.9 ^=+# af $G3v[e ^w.vgU`ŷf_ ^|2,tbz>>߶ 5/hNs|\Ty#@e qŨc$ :`i٪3s 8V %*0,˙>Wd)s1)R@ ݏ2#НinuAʧB +]hj9_tYkr0lI&qjԾ[*g.(-5X4kMEilk9Om> U8jH> x&Q́?J:׍|G`ޯ~@ $Aߨch:|1bkXd)|Wb"Џy_~+nW@ρ?> ؚc#ٗ@ؤ~N J8imSyޝcddbvA"QG^qQppg c/̃D\{`jv{GLH>42k. 5̚ɏMRewӂsY /gv9`x~w=$'I H++ֺX_ze>߶ v<_Kw\g5SjǭdBrw72N^ܗ{ɒ^׍f`e:^7gRyr9-sX38u86._ъ Y-y*Pܦ ik0uleܴsxɱ8|NHlԫYDdh|D' ZhPv7& 03t2wj`.7<2wr2Wa[:S6ؘeޢ+ j uqY.Q{B`k52q #W`)&Ŭv4wMXaj;ƶ99ksY^ c{fIHXWQjT"pmcn= \Ƭ1Y`ϥ|N0P8f\F):c&\>{iNj Ho/<=Vj[ xb|ݝ@$0_һ,gfK0~'1bwg_ @_fՖ7vyj۸˜5PYA: -He bDVP=vv>mx\[u!E9d[r1DzM`Hƺ.Ɏ3v9}`;_`J]K ߯ݏv1b^ZmP_)pϕ4/tb?u5}[`|rZlMP1hV\3fc\ZQU'`-$KM\_C7Snyos/nkG{sBeRw2-_V [^ljD~`~Yo|t\6wk9|YP/JucPBaO5d hp_cRy/Ւъ{k2~󕦶M~ q-'}^3w,w_oA1O-բ cm} wSZ-.d^ֻ{}8vE;{ԟR^&n1}w >c9wTjg][A4~B,ZVсex_4_)^[m1`ȖJ~O|$0.tj{%ۋq PyO-~u~l̳2Z/)_%_/ K Y/WbR:nl+J|U,Ub.ǾԠn_x`{7{/`_IU"7J.\yt>zwb+)K 6[J=f)XYV7 @??ҒS䒸eY=ܻ0UP\;`)ر=B̡#۪v⻓7kMX쒸 Z~/Vk_h[7VK/vqlo{~-&_KJ[{`rY."h_9EGY`ˉoG$6U:JSa>c⯺+gBc[l`|.&b/1+=/_rI ?;l)'$ao NLD&; A&gc{-k<)clGH-M|SWV@}[v~kn;_z) ګc.,\}4l_ *2?mu&e`<,2QPfS>Ȁ050-QL`@>hn? 0ܱw7ٳR\0_ 8v)ۏ }WC /j`Y@3vl# #_ce8Qua/O"aC )hF3eacEΜAkNRv L U '̉4hnM- 8n2{}>R-|XJbzWe??.k꙼?}2xQ"O{C"G`s8Փ`@%/Z@KV1ApKl0˸FGhƥfL'Qs[3RÚ ;^_RkK^ǯR˿/fK-=BmX"cm+-΁8i_6_ ESMQ{`8I cy,shN2@AT9u ar,biÈ*c̠E)`&+.7`  A5'H&Kˌ+Lc۸ # }5~s gSjkًs)Bz,:__ _̤`V`O Yv|`p 5n5sD-s#  90 ,')Em8BL AO~3Ì+eD3)SSFm8&jmxf7|y0۷onIn~^b5bAx&!$|@?_M?hu˚eYM3G>nSAcCi,;!$"-#ɹo 5Ņ 8瀒a "zQ+NmmWrL\pIKv`h2zbri42@ 72kN0~fʹRVJP/ٸ6nLJW j_HK~9bϱr, 9bd1.EC״ޫJiKٷfYVJl&|x_\Scp("VZǁT hmTt2kiH*9fh`)"DQa%UL=>: }A(c.X,~쯸{籝.~.4(J]&+m}\j](Jh+ [Y /sRhk*8C'J`DA i}qP &v8xf\@ f?SÀl;E+E\Fu?x%BsAh3A49@`oWFPhBOI"7Zp]1\'6'i$fwd={V==ZDg (-w]U|sr;A8:ֻyy{<@ϼ,Jg/?{_bϹ.蟇:Nywx)@pdn?c'c)t'Ms#3ab!S+X)ڵyטjp@i%8FBX7 0:<Ӊ砱{LkaJC0!P$@Tv Vk3}[fzzR@" XHSqձ0^m~^<pϏMۋjx"xו'.Emt{QǤeW/$O}2?OduRڮy@lYPB*dF@>E{+ MG`{mP5tD8A#uzk&)@: rܱ L>ztʿBpų h'5$Cm@:K"1rQi cRҁ*qǪ-PmPɸ~x=T݃>~7رj5Usqrrm@۟QAѢs|3J2$C4̚9FJQfsgg#騹]imox5sv8|oo=^$OcƕW‡~)χi|k_Iepą,;`HJ0IhJ(fM<(\2[: 4s8J[kIsW!ȤP @$C8?D `ZAh"PbI#Ibɿ8 U113g"dgZD-6uV2;^Ga+Z-_}?f͚~ pѣ_~#!Aԝkt}??+dH^?4003mrS~9??;vZ !dj6S~곟~pM%NJ2뗆ƽ},fb>eeE^vgM08C^ԕ৙="3A(f6ss):COFS?[49PgѴBØ֐zj9GjzZ=3Y1>ڸoDZ$M$巼-_s3Ƭڏiz';oh^:5N_:k`޽u׿effп'|/ng/}Ko}_{]uС]˿%s7C~?)xBϷi}%v)\ { ߗpG=SZץ%1hxRCN()8Jg`/T.Z0I*"LǤ6Q]LT0 cOG3*Fsb0LB3("RZ$*4qf\K.گڭs=88xbqgyfB-0//lݰaMuZ|":zM7 CjWO|"Uz? Dy."|`[ Wc{l~3gr/37%%ݓC 0БNdsL{!.ҭN/l4tFš2H5dil* Y6}dv7WtTiB?u#A J;vBFjJ@J@%uf`+}e|Od&HP@H?ܸӸ *B F)6--")??{ڵkoY.( !۷n*D`'7p ;e*6FCЋ^rnϳyolOiK]Xb[BVb^`;:qj-yY7wlYSo-kGwOn8w;-fVO5S'&:оeyiN>X[wag ƙ K\WOrWI.]Hה7lؼԻȊ)dGܲe Г$ o[?̙3*ʆ|?Tn?`V统ԧ^522rEsǵZ9NH~rLV333SqLUzz_B|ͷ]{ԸIRb~1۾diKhX_c/]O}{`LA4%ZI0GqGg KFqHH)W^w27ӟ}̙Sz׻s\v"غu/,x8xQns]"T1{Ew4 (=ٱiӦm/9rС}sGi<_%/yɋsexxx?|ӛt_!?p5}K|9O#{%}Kk)mO?矦~/m` PdZ΃rKF2 Egfv,p AC6Is!@z3)f!l`%okoC/2pH>" L!>]cbyk ^} ҸfɂÄCں*Auo*%ֻm͛o饥Z/| _%> 8'{h4<c! Wz o{ۮꪫn:N8/}AT{EQww_>Loy[=qw֭׶JhKy6-gL.m}R꧟}뗵獦@}`QR̠)tlזJ8 E=KQ3){_7+sRHq.tl ;;:\(~Ya50pKa`{9\G=|ֽva3J)w׿# ԾE\.7, AD2y `ǢI4(͚#iֻ=^^>X!@9~w m:g s^$)JЭo~jz h޽Gn&%݀^ۦM$GIOZAcij7op]vc!ͮet>5h竡Hqh՚sl?\h{.k P5)D1{2H݂@fS[`RkB,pNN:ev< \\ ˈh(7])U|w @y=Toժc<\h%I^m\_6bˢ#k?v3_s7Mc2# FjBƃ \]Ǧ(S~d=1XW^;V5ݎ*OڠN~?*.g_K lq瞍߾}&''{k>]v}VN:up]9ݻwᗾs㵥\. o}n_ڋ|Ηy}Bvr|p׭RqA^~_NlF̠2b ӆ۝i  8DPκMZDNԧƵR’P4;j1w)"Ktb@7OuMxrB]_$ 3N1N<P+oަ21ՌNHSL%͔c$Jf~X"?oaA}ݦ Bι.,Q[{oSf&FAaO|/&wP>{@kkn|wICa⑧#GLqLM7Rf5jk_ۗjr%7_CJ]꾕b+9ه3@lpg04`"9ޗܥ๙lVqۀ-N9Kv!gɅ s{t,_z'ˠ g~OW7RcYԟݏo`*\9BRJhK)ҫ3 E¯2֭;z`.?nHN N5XH;r/}K<mZ/ˏsuc+q3SLN^z |W! ~Æ K|+ +q,rw>α>]KȪNukq[{4L˵Z,Q;iv!\[pHkrשZCo3Au(FIu!O䄙xhL?5l=`8p?w4wl%xԯn(yQkƦ\98~yLwoo<+g$"̄] w Jsӭv+*w\-^Lۋq} +e`|r#QpsPiL3߼>p:RTҜ 2Ҥ3!D%< )2~NFD=x%M*8Ww( 57Pa<90c!]T=3MRXLA~dy5a q0 Pj&lpeR r"je& >h$i·¦9[Wt #-yϞ=Dǚ!Ts^Ԯ.h([{L8 :s>xl}+HҾn{!z5TEY:]_J)m'&;̈Ц,=0ma䶵|CBWZS"Yfk[8p3A- )Eq(\ a#p_U; Hr7]YEVU1~oi7(D5 r_Bڧ?oĀ"x,}ϞqIӻ!bdddpmYb^W3^{o)mȾ =.X¾>s\}\VS7†*x=aia+A uY[Jҥ\g:j__}fj"X> $j*dYĻh+4`$< r֠f:[ (gnwZqBq7PPd =^ܻ .cMO<(Mϐ )a>UuXIG3lhhY>N)c,?^׼Kuu݁k~oۿ#>\mHǎ;~"}OVrcǎOͫ哂yhe1j. q_LZR#W[-ʥx^},/k{pj+ۄjF+eG@kxVToȆ9k&ЅTo5O :V D _1 wu$LMs=\+0Tn QgRh<wFgA# 7T# [ϝ[m@0_FUIc'A+bX^-m iLr\wu7q/=J-n۶w:yY%ݢ4MT^um>{Nϧ2K :mRqC9&~@sKw1;9w}8V\y:8 @-gP J٨v`eΩٯ J| SPL?|T`͐j\0|-0x,&]yQ!A}zHx@Pr+) UhQ`bH~|1?S3"px&1p9]r3&W~  {&Y0&9{gkqq9b-Tgl3%0Pr&UCh҄Ėp0bOl 9қ+ %S ^ڼfs_ܯ@pVpJ[4EϛIb0i=#wBH͙0!2<(,R^Kfm((< 81 *2.iƓIF[6v]{ۻq>#t3] ~ڥʥǥp?.s'qYVXS?HS`kdJjSf>3T#MUg05 RйFb#s~ ;afQ;2 MJ.e ΁!z/KJl3Ŋ$gՕ#osttV}Z,RJo֭7A)._vZ*rf\"c[y{%w1kpm%8.Jkn nj$Z3Jn7@nAȏNVo޶#?U)yxjx퉉K>kjf#$ޭShPjtQM4u/ ДR׿/ӟ&~+_?O:E&Ҏl!u{Qڑ#Gٷo_X3zι ;\`y֋5΅*n>}D<ׅBk>穫 Aj#L&"M:6>P,kVEpi#c!y**!ƄOC:u?Wt؀S&o Zcy} TP[]k#◎{)8h1bФHz ]sS'm6:qsO8r<2,bh !L+( U0'`d>;.QE PMxnQܱB)Ecpa -C\.&nB:q(ON'UH^8DyLTujRFie·!aVKXО;}]Tz.tTK[[k_<55uWw߰ahOORt?s__v!v67!-^gԶ{jE-g}^` .>VK}rY.FP3uӕ891#՘V)Ŕ 30`yc>L[:;݂>)%{M9+]{D f@Ԟ90`~NҠgA0*":GO@kIp7Lp0.{.Af0i)0X4ð%p[4@~ K*V&Ai*g:11qm~wFg߾}Wk׎*~ ~ؾR{\E8G.db}Kj~)y9=͑o>;%V90ƒ ԝ`C hj"t&>L3:7i ǎCs|ȱpJ$S ht mԺt@c,)j !ޓ܀a${3-KR)QF:I h &s:G̺ uBT1V0lPyI[or_qM[J9iEg-5ҼZjZ]kF8*iӦ t8ӧO>Ot's`+ƍ7j:Ajw>}8To|{$R4.5>Ŷo5/ܗRgbကŦiBT֔Ti ^ƸWl9lu?FGΈPǀ+1mPf4o<]4Uf3*8 qoWA@J"91 ӏ? ކ;kxLVXN7 ɱPӔb͐fd˱fW3/y)46~sm(ߍ8s K# R )^H+(9=HKZn3r`^ܾ Zls;|Y)^ Ϲ AxkѣG+ϻl[zw!& _*/%(W?^L 5U?@0 !Lb }*ם$2ɍ@eLj~lJuD0½ 1%1pKjx04 Nh2,*Ùo\ 0Z ,ӿQ#CA"& 9atu0:o yE)hjl)Hc 6S.7TӤ 39I < >4Fc4^5 { #?t|X!|v{ "ƫKϻ}~!^J\}ПW)m; y(Tc,E h4zT'ln 7#w"+=p482㏜MYcDu+-0wÚow381RczvT-}w.W .5ۥ]?htxВ>fY9@!N\f tD` N-ukcLϚ+JDDH)d__EBqWBy^XA,rgY]}b֡n{>`_Q.,3"&g0Wff@ 5%C6R `U?Kπ+Z]sGemxMt L1b _ n쟂t2<uNʂg6 Y@RQPj7Ĺ2:eFp$; qʭu3Lbj"1"@QIhf $Q!ѣxe[?>UD,կ)Bpm\uJ=\clrA=@A@ kff}&nC\pǬ988ψjM "՝K.C봽)o۶^מ}٧\Mv.}jM=Egܜ֯ʵ$I_ž"m~>) RK υ8e@A 98pP PJLc*Ɗ 6ii^ >01[#Pބ3Ml=NNѡS0#oE0FWiO >>*l[S v;DO+HȌpɇe)QZߺ)jCYgALbT#15T&FV uL΁G7OJ% C[??W\̙3`kğ@ldtE׵>O>4U~u//鷗w]{6"9z55~+c_Ͼ Y>`.vR 2?$>$:@g06"Ul04.I íT:20V.JѿJk}|iQ Y1= zIH>j,q3}Fz$(]3&(Tk^EAAMBH(֞X;D9$=)EhÍ hhJ^''L46b𢶞#G-o''~W̓dU4mڵ"U?_ RkkٶyIiϕ_cw7 onǓ~~w`ݺuCyk^JEQ㡇z=',9e%W-.ab9}̷V\ϧy ;IAX&* =a Q R2oGI6 |!rd-0XdUB1߇ɡ8;4 ̔tH1O *w*Bs2;壳̟N4)nT#.13 Gh4hC6xfOi!RVnS'mX/wiUU{_D|K?'xg~g/nκmx3>I`W~h6ٽx:w}knr ڗKC_ok/Vxb]b|\hP>P}] m/` pJ7pr,mv!6407Oھ}㌏ es(0M4 DaŅ1UHe+.X3J[+p \>acaV,,_P'i֍llTF  Ѷڜu70 g ({@A:YF6N9 Je+ dN mfmO^mי>x:4.9i@(G3RƐƏ1xcPg$Nh%qX`'CSwJlsutwÇNlWZ7~t^*c>$0xW?%h=LY _W#O~5'*-fX_αe03w!:9TNHʺStF3Sa~OMMp^ ̽ WaV3tA= OHRFsI>$aaXI8*E1t \i(cG&18QbсPE&TpEe}y̩jO7;t׊f\SO,~g͛79 =yo'ҍ-0)OzK%KPȶf'}{7ްXwј>^X U:Wxb/m?.djuY+eY/;bT=W> p@(C=*A R#@id0mo7`l#3`}B砱aqN mO5[R Db4rK+ H4h&wᘘ`5-iU41ȩir LOLOdhؽ޹qa=g2311 PȆC$Xl"e(+$dDbDF,̄8N =t==S}ZU}Tq~\ '!d*&c)]zM% w{_Rep'u&!mwy/kbL /LK,ɚG<88Qu pflm5l4 uN)#u5`@m2t#(h>hi[>On>:ƉI3[[+7/*]|PwCMm R0tK;C1`PksyL0m "f1's F$Bҋ fFL PKH"E  )tv7jBu\V"jz^ok:l;[>n\<2t=VvOQ]?, ~ rq"?Qg /a}=c=X*%8t gkU TޛK3ʹ`*nAhEqtƺPxzw׸,zL՚2A EJХW[͢> qM-6vg Y>u^сSG;~u&)滕u81y~"KOXPlX8Xv5 p efYsjb׋xI3Z3Uw3D'%Τ l\ڂG{j\Q]ێ_kGs^.OӫAq:Q:yu{-rP`sj*v{=arki:h c2ܐӟm% h:VB(jyU iH5%CIX/POY" ~n')\{a9Aq6~ruqDe7pǹ `sXpzkh|Y;t|A+<7Y Bf+9s hD3%Y+-ؗmlK&*!#C.,Nv%8S >n-7P/ҥKH I} wy v? Žҵ|irD`y 5`: 62b1(qW{3`T;$ŭw|f  "]yT(?&6$Dpy| *pz*fJT#irӜg̊ 'f#B]WutM†Qv@ x|nD k6;b9D]S%QuV/wqۺjcgIг_:uWn=}W;g϶-ޫѵ[w8ě!m脷n]e }3ت p0J`@.,bah'{0tKl^L < v5`} p:B1KO~ltY?Z\gҌ˱Z4{. 81Uv' ƋX]ױnEjWhb q_ cCuknx\+tޅ2\w ߭Fu /50d!a9y*;m}к&A'&fIȎu%UێtHr)xK?67q~*.]\ney$6>hiQ :71L1Zs7 WW;nbn!Q'E33L8pWޯq8$&N%GL*y;<ձs^~D @N%S{'10qK ub}uƅ< fi#A~ }O 2ArHԉ$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`'wt{IENDB`PK!Bb))+res/mods/configs/res_map/MoEBattleView.json[ { "type": "Layout", "path": "coui://gui/gameface/mods/14th_ua/MoECalculator/MoEBattleView.html", "parameters": { "extension": "", "entrance": "MoEBattleView", "impl": "gameface" }, "itemID": "MoEBattleView" } ] PK!b"55/res/mods/configs/res_map/MoEEfficiencyView.json[ { "type": "Layout", "path": "coui://gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiencyView.html", "parameters": { "extension": "", "entrance": "MoEEfficiencyView", "impl": "gameface" }, "itemID": "MoEEfficiencyView" } ] PK!̀//-res/mods/configs/res_map/MoEProgressView.json[ { "type": "Layout", "path": "coui://gui/gameface/mods/14th_ua/MoECalculator/MoEProgressView.html", "parameters": { "extension": "", "entrance": "MoEProgressView", "impl": "gameface" }, "itemID": "MoEProgressView" } ] PK!gaYY2res/scripts/client/gui/mods/mod_moe_calculator.pyc c@sddlmZmZmZdZdZddfZd Zd Zd Z d Z dZ y e Wne k renXy eWne k renXy e Wne k renXdS(i(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGtLOG_PRODs14th_ua's MoE Calculators5.0.0tparamss@gui.impl.lobby.hangar.presenters.hangar_vehicle_params_presentertHangarVehicleParamsPresentertstatss=gui.impl.lobby.hangar.presenters.vehicle_statistics_presentertVehiclesStatisticsPresentercCsddl}ddlm}g}xUtD]M\}}}t||}|dkrYq)nt||||j|q)W|j||j t dt t dj |pdfdS(Ni(tgameface_bridges8[%s] v%s installed (collision-aware sub-view inject: %s)s, tnone(topenwg_gamefacetmoe_calculator.bridgeRt _CANDIDATESt_resolve_presentertNonet_patch_presentertappendtset_candidate_ordertinstall_all_listenersRtMOD_NAMEt MOD_VERSIONtjoin(R tbridgetpatchedtnamet module_patht class_nametP((s1res/scripts/client/gui/mods/mod_moe_calculator.pyt_install's    cCsFy&t|d|g}t||SWntk rAtdSXdS(Ntfromlist(t __import__tgetattrt ExceptionRR (RRtmodule((s1res/scripts/client/gui/mods/mod_moe_calculator.pyR >s  csJt|dtrdS|jfd}||_t|_dS(Nt_moe_calculator_patchedcs|||yTjj|j}|dk rc|\}}j|d|nWntk r~tnXdS(Nthost_vm(Rt note_mountt getViewModelR tpushRR(tselftargstkwargsttargetR"trvm(t_orig_onLoadingRR(s1res/scripts/client/gui/mods/mod_moe_calculator.pyt _onLoadingRs    (RtFalseR,tTrueR!(RRRR,((R+RRs1res/scripts/client/gui/mods/mod_moe_calculator.pyRIs   cCs8ddl}ddlm}|jtdtdS(Ni(t battle_bridgesI[%s] battle overlay armed (registered Gameface window on arena lifecycle)(R R R/RRR(R tbbridge((s1res/scripts/client/gui/mods/mod_moe_calculator.pyt_install_battlehs  cCsddlm}ddlm}m}|j|j|j|j|j|j|jtdt |j |j |j fdS(Ni(t mod_settings(RR/s>[%s] settings registered (garage=%s, battle=%s, battle_alt=%s)( R R2RR/tregistertadd_change_listenertapply_settingstupdate_preview_imagesRRtgarage_enabledtbattle_enabledtbattle_alt_key_enabled(R2RR/((s1res/scripts/client/gui/mods/mod_moe_calculator.pyt_install_settings|s N(Rs@gui.impl.lobby.hangar.presenters.hangar_vehicle_params_presenterR(Rs=gui.impl.lobby.hangar.presenters.vehicle_statistics_presenterR( tmoe_calculator._compatRRRRRR RR RR1R:R(((s1res/scripts/client/gui/mods/mod_moe_calculator.pyts2              PK!Crք.res/scripts/client/moe_calculator/__init__.pyc c@sdS(N((((s-res/scripts/client/moe_calculator/__init__.pyttPK!4 -res/scripts/client/moe_calculator/_compat.pyc c@sddlZddlZeZyddlmZmZWn#ek r]dZdZnXdZdZ ej dej Z ej dZ ej d Zej d Zd Zd Zd ZdZdZdS(iN(tLOG_NOTEt LOG_ERRORcOsdS(N((targstkwargs((s,res/scripts/client/moe_calculator/_compat.pyR"scOsdS(N((RR((s,res/scripts/client/moe_calculator/_compat.pyR%scOstrt||ndS(N(tDEBUGR(RR((s,res/scripts/client/moe_calculator/_compat.pyt LOG_DEBUG)scOst||dS(N(R(RR((s,res/scripts/client/moe_calculator/_compat.pytLOG_PROD3ss0File "[^"]*?[\\/]scripts[\\/]client[\\/]([^"]+)"s[A-Za-z]:[\\/][^"\r\n]*s \\\\[^"\r\n]*s(?Yt(t_SCRIPTS_CLIENT_REtsubt_WIN_ABS_PATH_RER t_UNC_ABS_PATH_REt_POSIX_ABS_PATH_RE(ttext((s,res/scripts/client/moe_calculator/_compat.pyt _scrub_pathsTs cCs2ytttjWntk r-nXdS(N(RRt tracebackt format_exct Exception(((s,res/scripts/client/moe_calculator/_compat.pytLOG_CURRENT_EXCEPTION`s cCsAy!|}|dkr|S|SWntk r<t|SXdS(N(tNoneRR(tfntdefaulttvalue((s,res/scripts/client/moe_calculator/_compat.pyt_safeks   cstfd|S(Ncs tS(N(tint((R(s,res/scripts/client/moe_calculator/_compat.pyRyR(R(RR((Rs,res/scripts/client/moe_calculator/_compat.pyt _safe_intus(treRtFalseRt debug_utilsRRRRRtcompilet IGNORECASERRRRR RRRR!(((s,res/scripts/client/moe_calculator/_compat.pyts(         PK!Zh6res/scripts/client/moe_calculator/adapter/__init__.pyc c@sdS(N((((s5res/scripts/client/moe_calculator/adapter/__init__.pyttPK!ȫ<res/scripts/client/moe_calculator/adapter/baseline_cache.pyc c@s7iZeZdZdZdZdZdS(cCsw|s dSt|}tj|t|p/d}t|pAd}|dkrc|dkrcdS||ft|s     PK!-"@0505<res/scripts/client/moe_calculator/adapter/battle_adapter.pyc c@s6ddlZddlmZmZmZmZddlmZddl m Z ddl m Z ddl m Z ddl mZdZd Zd Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dS(iN(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGt_safet _safe_int(t battle_types(t MINIMAP_SIZES(tengine_adapter(t moe_wgapi(tbaseline_cachecCs-ddlm}ddlm}|j|S(Ni(t dependency(tIBattleSessionProvider(thelpersR tskeletons.gui.battle_sessionR tinstance(R R ((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_session_provider#scCsQy1ddlm}ddlm}|j|SWntk rLtdSXdS(Ni(R (t ISettingsCore(R R t'skeletons.account_helpers.settings_coreRR t ExceptionRtNone(R R((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_settings_core)s csy|ddlm}tdkr8ttttfSfd}||j||j||j||jfSWn%t k rt ttttfSXdS(Ni(t DAMAGE_LOGcsttfdtS(Ncs jS(N(t getSetting((tcoretname(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pytAt(tboolRtTrue(R(R(Rs;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRAR( t0account_helpers.settings_core.settings_constantsRRRRt TOTAL_DAMAGEtBLOCKED_DAMAGEt ASSIST_DAMAGEt ASSIST_STUNRR(Rtget((Rs;res/scripts/client/moe_calculator/adapter/battle_adapter.pytread_damage_log_summary_flags6s    cCsMy-ddlm}tjjj|jkSWntk rHtt SXdS(Ni(tARENA_BONUS_TYPE( t constantsR#tBigWorldtplayertarenat bonusTypet EPIC_BATTLERRtFalse(R#((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pytread_is_epic_battleIs  csttd}yXddlmtdkr<|Stttfd|d|SWnt k rt |SXdS(Nii(tGAMEcsjjS(N(Rt MINIMAP_SIZE((R,R(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRpRi( tlenRRR,RRtmintmaxRRR(ttop((R,Rs;res/scripts/client/moe_calculator/adapter/battle_adapter.pytread_minimap_size_indexVs  / cCs2t}|dks$|jdkr(dS|jjS(N(RRtsharedtpersonalEfficiencyCtrl(tsp((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_efficiency_ctrlvs csyddlmtdkr,dStfdd}tfdd}tfdd}|||fSWntk rtdSXdS( Ni(tPERSONAL_EFFICIENCY_TYPEicsjjS(N(tgetTotalEfficiencytDAMAGE((tPEtctrl(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcsjjS(N(R8R((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcsjjS(N(R8tSTUN((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRR(iii(iii(t#gui.battle_control.battle_constantsR7R6RRRR(tdamagetassisttstun((R:R;s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_read_efficiency~s   csyddlmtdkr,dStfdd}tfdd}tfdd}tfdd}||||fSWntk rtd SXdS( Ni(R7icsjjS(N(R8R9((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcsjjS(N(R8R((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcsjjS(N(R8R((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcsjjS(N(R8R<((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRR(iiii(iiii(R=R7R6RRRR(R>tblockedR?R@((R:R;s;res/scripts/client/moe_calculator/adapter/battle_adapter.pytread_efficiency_totalss   cCs2t}|dks$|jdkr(dS|jjS(N(RRR3tfeedback(R5((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_feedback_ctrls csyddlmddl}|j}tdkrAdStfdd}|sfdSd}}xv|D]ntfdd}tfdd}||jkr||7}qw||j krw||7}qwqwW||fSWnt k rt d SXdS( Ni(R7icsjjS(N(tgetLoogedEfficiencyR((R:R;(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcs jS(N(tgetBattleEventType((td(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcs jS(N(t getDamage((RH(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRR(ii(ii(ii( R=R7tBattleFeedbackCommontBATTLE_EVENT_TYPER6RRRt TRACK_ASSISTt RADIO_ASSISTRR(RJtBETtentriesttracktspottettdmg((R:R;RHs;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_read_assist_split_logs,        csyddlmtdkr,dStfdddkrWdStfdd}tfdd}||fSWntk rtd SXdS( Ni(tFEEDBACK_EVENT_IDicsjjS(N(tgetCachedEventtDAMAGE_LOG_SUMMARY((RUtfb(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcs tdS(Nt._BattleSummaryFeedbackEvent__trackAssistDamage(tgetattr((tevt(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRcs tdS(Nt._BattleSummaryFeedbackEvent__radioAssistDamage(RZ((R[(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRR(ii(ii(ii(R=RURERRRRR(RPRQ((RUR[RXs;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_read_assist_split_summarys     cCs:t\}}t\}}t||t||fS(N(RTR]R0(tt_logts_logtt_sumts_sum((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_read_assist_splitscsyt}|r'|jr'|jjnddkr=dStfdd}tjj}| sw|dkr{dS|jj |}|sdS|j dSWnt k rt dSXdS(Ncs jS(N(tgetControllingVehicleID((tvsc(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRit vehicleType( RR3t vehicleStateRRR%R&R'tvehiclesR!RR(R5tvidR'tvinfo((Rds;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_player_vehicle_descrs  !  csyddlmtfdd}t}|rO|jrO|jjndrstfddnd}t|ot|o||kSWntk rt t SXdS(Ni(t avatar_gettercs jS(N(tgetPlayerVehicleID((Rk(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRRics jS(N(Rc((Rd(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRR( tgui.battle_controlRkRRR3RfRRRRR*(townR5tobserved((RkRds;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_is_spectatings  !$& cs&dkrdStfddS(Nics jjS(N(ttypet compactDescr((tdescr(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyR"R(RR(Rs((Rss;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_player_vehicle_int_cds cso|dkrdSy?ddl|jjdtfddpMdSWntk rjtdSXdS(NRiics jS(N(tNAMES((t nation_idtnations(s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyR+R(RRwRqtidRRR(Rs((RvRws;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_player_nation%s  # cCsxyXddlm}tjj}|dkr2tS|j|j|j |j |j fkSWnt k rst tSXdS(Ni(t ARENA_PERIOD(R$RzR%R&R'RRtperiodtWAITINGt PREBATTLEtBATTLEt AFTERBATTLERR(RzR'((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt _in_battle1s   cCstj|}|d|d}}|p-ddkpT|p?ddkpTtj|}|p`ddkr|prddkrtj|}|dk r|\}}td||fq|rtdqtdn|||fS(Niiis8[moe-battle] baseline from garage cache: pct=%.2f avg=%ds?[moe-battle] genuine 0 baseline (tank seen in garage, 0 career)s?[moe-battle] no baseline (tank not seen in garage this session)(Rt _read_moeRtseenR!RR(tint_cdtmoetpre_percentiletpre_avgtbaseline_knowntcached((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyt_pre_battle_baselineGs $$    cCsGy't|\}}}|r"|SdSWntk rBtdSXdS(N(RRRR(Rtpctt_avgtknown((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyRfs  c CsPyt}t|}|s7tjdtdtSt\}}}t\}}t|\}}} t j |} | rt j |rt j ||} nt|} tjd|d| d|d|d|d|d |d d d |d |d| dtdtdtd| SWn+tk rKttjdtdtSXdS(Nt has_vehiclet in_battletvehicle_int_cdtnationR>R?t track_assistt spot_assistR@t team_damageitpre_avg_damageRt thresholdst is_spectatingR(RjRttbttBattleSnapshotR*RRARbRRtget_thresholdstneeds_estimateRt_estimate_thresholdsRyRRpRR( RsRR>R?R@RRRRRRR((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pytbuild_battle_snapshotss>        (#R%tmoe_calculator._compatRRRRtmoe_calculator.domainRRtmoe_calculator.domain.constantsRtmoe_calculator.adapterRRRRRR"R+R2R6RARCRERTR]RbRjRpRtRyRRRR(((s;res/scripts/client/moe_calculator/adapter/battle_adapter.pyts4 "            PK!1  :res/scripts/client/moe_calculator/adapter/battle_input.pyc c@sddlmZmZeaeaeaeaeaea d a d a d a gaeadZdZdZdZd dZdZdZd Zd d Zd S( i(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGcCsDddl}ddlm}m}t|j|p@|j|S(Ni(tKEY_LALTtKEY_RALT(tBigWorldtKeysRRtboolt isKeyDown(RRR((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt _alt_down_nowTs cCsDddl}ddlm}m}t|j|p@|j|S(Ni(t KEY_LCONTROLt KEY_RCONTROL(RRR R RR(RR R ((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_ctrl_down_now[s cCs/ddl}ddlm}t|j|S(Ni(t KEY_LEFTMOUSE(RRR RR(RR ((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt _lmb_down_nowds cCst}t}|tks*|tkr|a|atd|rHdnd|rWdndftdk rt||qndS(Nsoe-battle] Alt %s Ctrl %stdowntup(RR t _alt_heldt _ctrl_heldRt _on_changetNone(talttctrl((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_update_alt_statels   cCsmtot}|tkri|atd|r6dndtdk rit|rYdnd|qin|S(Ns"[moe-battle] reposition gesture %ststarttend(R R t _drag_activeRt_on_dragR(tcursortactive((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_update_drag_states   cCsCt|p g}|tks*|tk r3tan|a|adS(N(tlistt _hotkey_keyst _on_hotkeytFalset _hotkey_down(tkeyston_press((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt set_hotkeys  csiddltto1tfdtD}|tkre|a|retdk retqendS(Nic3s|]}j|VqdS(N(R(t.0tk(R(s9res/scripts/client/moe_calculator/adapter/battle_input.pys s(RRRtallR"R R(R((Rs9res/scripts/client/moe_calculator/adapter/battle_input.pyt_update_hotkey_states  ( cCscyDtt|ddrCtdk rCtdt|ddnWntk r^tnXtS(NtcursorPositiontmove(RtgetattrRRt ExceptionRR!(tevent((s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_handle_gui_mouse_events $   csO|a|atsay1ddlm}|jttatdWqat k r]t qaXnt rqt rqtSyddl m }Wnt k rt tSXt s|jtdfd}|_||_ta tdnt sK|jtdfd }|_||_ta td ntS( Ni(tg_mouseEventHandlerss:[moe-battle] drag listener joined gui.g_mouseEventHandlers(tAvatarInputHandlert_moe_alt_originalcsJ|||}ytttWntk rEtnX|S(N(RRR)R-R(tselftargstkwargstresult(toriginal(s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_patcheds   sM[moe-battle] Alt/Ctrl listener installed on AvatarInputHandler.handleKeyEventt_moe_drag_originalcsZ|||}y)tr:tdk r:tddnWntk rUtnX|S(NR+(RRRR-R(R3R4R5R6(tmouse_original(s9res/scripts/client/moe_calculator/adapter/battle_input.pyt_patched_mouses  sK[moe-battle] drag listener installed on AvatarInputHandler.handleMouseEvent(RRt_gui_mouse_installedtguiR0taddR/tTrueRR-Rt _installedt_mouse_installedR1R!thandleKeyEventR,R2thandleMouseEventR9(t on_changeton_dragR0R1R8R;((R:R7s9res/scripts/client/moe_calculator/adapter/battle_input.pytinstall_alt_key_listenersD            N(tmoe_calculator._compatRRR!R@RAR<RRRRRRR RR"RR R RRR%R)R/RF(((s9res/scripts/client/moe_calculator/adapter/battle_input.pytCs(      PK!)<res/scripts/client/moe_calculator/adapter/engine_adapter.pyc c@sddlmZddlmZmZmZddlmZddlm Z ddl m Z ddl m Z ddl m Z dZd Zd Zd Zd S( i(tg_currentVehicle(tLOG_CURRENT_EXCEPTIONt_safet _safe_int(ttypes(t moe_estimate(t moe_wgapi(tbaseline_cache(t sample_logcsytjsdStjtfdd}tfddpOd}t|}|d|d}}t|dkr|dnt}|rt j |||nt j |}||||fSWnt k rtdSXdS(NcsjS(N(tintCD((tveh(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyt%ticsjS(N(t nationName((R (s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR &R R iii(Rt isPresenttNonetitemRRt _read_moetlentTrueRtrememberRtget_thresholdst ExceptionR(tint_cdtnationtmoet percentilet avg_damagetsyncedt thresholds((R s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyt prime_currents    " c Csyt}|dkr(tjdtS|\}}}}|d|d|d}}}t|dkrv|dnd}tj||||| rtj |rt ||}ntjd|d|d|d |d |d |dt SWn%t k rt tjdtSXdS( Nt has_vehicleiiiitvehicle_int_cdRtmarkstcur_percentiletcur_avg_damageR(RRttt MoESnapshottFalseRRtresolveRtneeds_estimatet_estimate_thresholdsRRR( tprimedRRRRR!RRtbattles((s;res/scripts/client/moe_calculator/adapter/engine_adapter.pytbuild_snapshot=s*   "   cCsyjt|pd}t|p!d}|dksK|dksK|dkrOiStj||dfgSWntk rtiSXdS(NgigY@(tfloatRtthresholds_from_samplesRR(RRtptd((s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR)es$ c s^y/ddlm}ddlm}ddlm}m|j|jt fdt }j |dkrdddd|fSj j|tfdd}tt fd dpd}tfd d}tfd d}|||||fSWn(tk rYtddddt fSXdS( Ni(t dependency(t IItemsCache(tMARK_ON_GUN_RECORDtACHIEVEMENT_BLOCKcs jjS(N(tdossierstisSynced((titems(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR R igcs jS(N(tgetValue((tmog(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR R cs jS(N(tgetDamageRating((R9(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR R csjjdS(NtmovingAvgDamage(tgetRecordValuetTOTAL((R4tdossier(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR R cs jS(N(tgetBattlesCount((tstats(s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyR R (thelpersR1tskeletons.gui.sharedR2tdossiers2.ui.achievementsR3R4tinstanceR7RR&tgetVehicleDossierRt getTotalStatstgetAchievementRR-RR( RR1R2R3RR!RRR+((R4R>R7R9R@s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyRus(   $ N(tCurrentVehicleRtmoe_calculator._compatRRRtmoe_calculator.domainRR$Rtmoe_calculator.adapterRRRRR,R)R(((s;res/scripts/client/moe_calculator/adapter/engine_adapter.pyt s & ( PK!ל4res/scripts/client/moe_calculator/adapter/format.pyc c@s;ddlmZmZdZddZddZdS(i(tround_half_awaytiround_half_awaycCsyt|pd}Wnttfk r0dSX|dkrAdSt|}g}x4t|dkr|jd|d|d }qVW|jd|dj|S(Nit0iit,(tintt TypeErrort ValueErrortstrtlentinserttjoin(tntstout((s3res/scripts/client/moe_calculator/adapter/format.pyt thousands s  icCsiyt|pd}Wnttfk r0dSX|dkrAdS|dkr[dt|Sd||fS(Ngs0%is%d%%s%.*f%%(tfloatRRR(tptdecimals((s3res/scripts/client/moe_calculator/adapter/format.pytpercents  cCsyt|pd}Wnttfk r0dSXt||dkrI|nddkr\dS|dkrndnd}t|}|dkrd|t|fSd|||fS(Ngs0%it+t-s%s%d%%s%s%.*f%%(RRRRtabsR(RRtsigntmag((s3res/scripts/client/moe_calculator/adapter/format.pytsigned_percent+s'  N(tmoe_calculator.domain.roundingRRRRR(((s3res/scripts/client/moe_calculator/adapter/format.pyts  PK!Eݜ ;res/scripts/client/moe_calculator/adapter/garage_roster.pyc c@sMddlmZmZddZdZdZdZddZdS( i(tLOG_CURRENT_EXCEPTIONt _safe_intidcs#t|dfd}|| S(Ntkeycsj|d |fS(Ni(tget(tcd(t recency_map(s:res/scripts/client/moe_calculator/adapter/garage_roster.pytt(tsorted(tint_cdsRtlimittordered((Rs:res/scripts/client/moe_calculator/adapter/garage_roster.pytrank_by_recencyscsfyFddlmjs#dStfdd}|pDdSWntk ratdSXdS(Ni(tg_currentVehiclecs jjS(N(titemtintCD((R (s:res/scripts/client/moe_calculator/adapter/garage_roster.pyR(Ri(tCurrentVehicleR t isPresenttNoneRt ExceptionR(R((R s:res/scripts/client/moe_calculator/adapter/garage_roster.pytselected_int_cd"s  cCsyhddlm}ddlm}ddlm}|j|j}|j|j }t |j SWnt k rt gSXdS(Ni(t dependency(t IItemsCache(t REQ_CRITERIA(thelpersRtskeletons.gui.sharedRtgui.shared.utils.requestersRtinstancetitemst getVehiclest INVENTORYtlisttkeysRR(RRRRtvehicles((s:res/scripts/client/moe_calculator/adapter/garage_roster.pyt owned_int_cds/s csypddlm}ddlm}|j|ji}x-|D]%tfdd|s   PK!2res/scripts/client/moe_calculator/adapter/i18n.pyc c@sddlmZdZeZdZi dd6dd6dd6d d 6d d 6d d6dd6dd6dd6dd6dd6dd6Zi dd6dd6dd6dd 6dd 6dd6d d6d!d6d"d6d#d6d$d6d%d6Ziid&d6d'd(6d)d*6d+d,6d-d.6d/6id0d6d1d(6d2d*6d3d,6d4d.6d56id6d6d7d(6d8d*6d9d,6d:d.6d;6ZdAa d<Z d=Z d>Z d?Zd@ZdAS(Bi(tLOG_CURRENT_EXCEPTIONtencCstr|rd|S|S(Nu_(tMARK_UNTRANSLATED(ts((s1res/scripts/client/moe_calculator/adapter/i18n.pyt_markss#achievements:marksOnGun0ttitles#menu:tank_params/avgDamaget avgDamagettitle0s#achievements:marksOnGun1ttitle1s#achievements:marksOnGun2ttitle2s#achievements:marksOnGun3ttitle3s#achievements:marksOnGun0_descrtdescr0s#achievements:marksOnGun1_descrtdescr1s#achievements:marksOnGun2_descrtdescr2s#achievements:marksOnGun3_descrtdescr3s"#achievements:marksOnGun_conditiont conditions%#tooltips:achievement/marksOnGunCounttratiosMarks of ExcellencesAverage Damages1 Mark of Excellences2 Marks of Excellences3 Marks of ExcellencesTo obtain one Mark of Excellence, displayed on the gun, the average damage caused by the player and average damage caused with the player's assistance must be higher than the results of 65% of players in this vehicle for the past 14 days.sTo obtain two Marks of Excellence, displayed on the gun, the average damage caused by the player and average damage caused with the player's assistance must be higher than the results of 85% of players in this vehicle for the past 14 days.sTo obtain three Marks of Excellence, displayed on the gun, the average damage caused by the player and average damage caused with the player's assistance must be higher than the results of 95% of players in this vehicle for the past 14 days.s6The maximum number of Marks of Excellence is obtained.ut• The player's average damage is updated after each battle based on the last 100 battles. • Obtained Marks are permanent and do not disappear even if the player's average damage decreases. • Mark can only be earned in Tier V–XI vehicles. • Display of Marks on your vehicles can be disabled in the game settings. • Marks can only be obtained in Random Battles.uCurrent ratio is higher than the ratio of %(color_tag_open)s %(count)s%% %(color_tag_close)s players who fought in this vehicle for the past 14 days.tMarksuОтметкиtruuMarkentdeuZnakitpluПозначкиtuktmarkss To next marku&До следующей отметкиuBis zur nächsten MarkeuDo następnego znakuu(До наступної позначкиt toNextMarktGoaluЦельuZieluCeluЦільtgoalcCs@y'ddlm}|}|p%tSWntk r;tSXdS(Ni(tgetClientLanguage(thelpersRtDEFAULT_LANGUAGEt Exception(Rtlang((s1res/scripts/client/moe_calculator/adapter/i18n.pyt_client_languagews   cCsyyddlm}|j|}| s8|jdr<dSd|kr^|jdddn|}||krtdS|SWntk rtnXdS(Ni(ti18nt#t:i(RR t makeStringt startswithtNonetsplitRR(tres_keyR ttextttail((s1res/scripts/client/moe_calculator/adapter/i18n.pyt_wg_texts(   cCs1tj|i}|j|p0|jtdS(Nt(t_BUNDLEDtgetR(tkeyRtvariants((s1res/scripts/client/moe_calculator/adapter/i18n.pyt_bundledscCstdk rtSt}i}x4tjD]&\}}t|pKt|||sl        PK!uJQQ7res/scripts/client/moe_calculator/adapter/moe_wgapi.pyc c@sddlZddlZddlZddlmZddlmZmZddlm Z ddl m Z ddl m Z dZ de ZejZd ZdDZdjdeDZdEZdZdZdZdZdZdFZdZdZe jZdHZ iZ!da"da#iZ$da%e&a'e&a(ia)da+e&a,gZ-gZ.e/Z0e/Z1e&a2da3da4d Z5d!Z6d"Z7d#Z8d$Z9d%Z:d&Z;d'Z<d(Z=d)Z>d*Z?d+Z@d,ZAd-ZBd.ZCd/ZDd0ZEd1ZFd2ZGd3ZHd4ZId5ZJd6ZKd7ZLd8ZMd9ZNd:ZOd;ZPd<ZQd=ZRd>ZSd?ZTd@ZUdAZVydBejWfdCYZXWneYk rdZXnXdS(IiN(t build_config(tLOG_CURRENT_EXCEPTIONt LOG_DEBUG(t garage_roster(t constants(t fetch_listteus.https://api.worldoftanks.%s/wot/tanks/mastery/tdamageii(i7iAiKiUi_idt,ccs|]}t|VqdS(N(tstr(t.0tp((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys Nsg.@s^Mozilla/5.0 (compatible; 14th_ua-MoE-Calculator; +https://github.com/drizzer14/moe-calculator)g?ig@g@iiiiiic si}|s|dfSytj|}Wnttfk rI|dfSXt|t so|jddkry|dfS|jd}t|ts|dfS|jd}y"|dk rt|nd}Wnttfk rd}nX|jd}t|ts||fSx|j D]\}}t|tsHq'nyt|}Wnttfk rtq'nXixct D][} yt|jt | } Wnttfk rqnX| dkr| | s(tNonetjsontloadst ValueErrort TypeErrort isinstancetdicttgettinttitemst_PCTSR tallt_REQUIRED_PCTS( ttextttabletblobRRtdistttidtpctstcdRtval((Rs6res/scripts/client/moe_calculator/adapter/moe_wgapi.pytparse_responsesL  %  "    cCst|tsiS|jdtks=|jd|krAiS|jd}y|t|tkrmiSWnttfk riSXi}xy|jdpijD]\\}}y0t|}td|jD||s( RRRt_STORE_VERSIONRt_REVALIDATE_SECONDSRRRtAttributeError(R"t now_epochR*R+R!R$RR&((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt fresh_tables$*( $ cCst|tsiS|jdtks=|jd|krAiSi}x`|jdp\ijD]C\}}yt||t| list=%d(Rt_promoteRRJRKRLR(RBR&tevicted((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRZes ! cCsyt|pd}|sdS|tkritjttj|}td|Datntd|t tfWnt k rt nXdS(Nicss|]}|t|fVqdS(N(RK(R tc((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys }ss[moe] sold %d -> list=%d( RRKRt remove_idtlisttkeysRt _save_listRRJRLR(RBR&tkept((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRYss   cCshyIt|pd}|sdSt|}td||ttfWntk rctnXdS(Nis1[moe] battle played in %d (evicted=%r) -> list=%d(RR_RRJRKRLR(RBR&R`((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyton_battle_playeds ! csmttjttjttj\}}tfd|Dat t g|S(Nc3s9|]/}||krntj|dfVqdS(iN(RKR(R Ra(R&tnow(s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys s( R@Rtadd_with_evictionRcRKRdRtFETCH_LIST_CAPRReR=(R&R3R`((R&Rhs6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR_s ' c str dSyttj}|s)dS|at|ttjB}tj|t fd|Dtstj }tj t j }tj||t j }ncgtjD]}||kr|^q}tj|\}}|r!tdt|nt fd|Datattjt}tdtt|ftttjWntk rtnXdS(Nc3sH|]>}|tttj|dtj|dfVqdS(iN(tmaxRRKR(R R&(tlive(s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys ss+[moe] fetch list purged %d stale/sold tanksc3s'|]}|j|fVqdS(N(R(R R&(tmergedRh(s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys ss6[moe] fetch list ready: %d tanks (data refresh due=%s)(t _list_readyRVRRWRXR@RKRdt recency_mapRRItrecent_int_cdsRRjRt bootstrap_idst purge_staleRRJRERet needs_refetcht _fetched_atR=RcRLR( townedtall_idsRMtrecentR3R&t owned_wanttpurgedtdue((RlRmRhs6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR:s6   !+ cCsts dSg}xH|D]@}|r|tkr|tkr|tkr|j|qqW|sedSxQtdt|tD]7}|||t!}tj|t j|dfq~Wt dS(Ni( RTR;t _inflightR<ROtrangeRJt_MAX_IDS_PER_REQUESTtupdatet_queuet_pump(ttank_idsR3R&titchunk((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR=s * cCstst stdkrdStjd\}}y?tatt|a|t_|t_ tj t WnBt k rt adax|D]}tj|qWtnXdS(Ni(t_busyRt _FetchThreadRtpopREt _build_urlt_threadRtattemptR9t_schedule_pollRLRSR{tdiscardR(RRR&((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRs       c Cs-dag}yt}|dk r8|jr8tdS|dk rVt|dgng}|dk rzt|ddnd}|dk rt|ddnd}|dk rt|ddnd}|dk rt|ddnd}|dk rtt|dtnt}|r-td|nta dat}|rt j t |}|rtd t |ft jtjnt j|x|D]}tj|dqW|r|a ntatn|r x|D] }tj|tj|qWnn|tkr,t||d nNx(|D] }tj|tj|q3W|rztd t|tfntatd t|pitt |ft|rtt t!j"nt#WnOt$k r(ta datax|D]}tj|qWt%t#nXdS( NRRitresultRterrorR s#[moe] wgapi fetch worker failed: %ss>[moe] wgapi updated_at changed %r -> %r; refetching whole listisK[moe] wgapi gave up on %d tanks after %d attempts -> estimator this sessions4[moe] wgapi fetch done: +%d tanks (%d cached, ok=%s)(&Rt_poll_cbRtis_aliveRtgetattrtboolRSRRRt data_changedt _updated_atR;tclearR<R~R>RR@Rtt _save_cacheR{Rtaddt_MAX_FETCH_RETRIESt_schedule_retryRJRERHt _notify_readyR=RcRKRdRRLR( RtthreadRRtupdRR tstaleR&((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt_pollsv $$$$$*            #   cCsr|s tSytj|}Wnttfk r7tSXt|toq|jddkoqt|jdtS(NR R R(RSRRRRRRR(R R"((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt _response_okSs$cstdttd}t|}tdt|tfy,ddl}|j|fdWntk rtnXdS(Nis6[moe] wgapi retrying %d tanks in %.0fs (attempt %d/%d)ics tS(N(t_requeue((RR(s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pytmt( tminRJt_RETRY_BACKOFF_SECONDSRRtBigWorldtcallbackRLR(RRtidxtdelayR((RRs6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRcs    cCstj||ftdS(N(RROR(RR((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRsscCsAx:ttD],}y |Wq tk r8tq Xq WdS(N(RcRNRLR(RP((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRys   cCsAy"ddl}|jttaWntk r<tnXdS(Ni(RRt_POLL_INTERVALRRRLR(R((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRs   cCs0djd|D}dtttt|fS(NRcss!|]}tt|VqdS(N(R R(R R&((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys ss=%s?application_id=%s&distribution=%s&percentile=%s&tank_id=%s(tjointAPI_URLRTt DISTRIBUTIONt PERCENTILES(RR3((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRscCs]ddlm}|j|dtdt}|dk rY|jrY|jrY|jSdS(Ni(thttpttimeouttagent( thelpersRtopenUrlt_TIMEOUTt_AGENTRtisValidthasDatatgetData(turlRtresp((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt _fetch_texts $ cCs(ddl}tjj|jddS(Nit mods_datat 14th_ua_moe(RtostpathRtgetPreferencesDirPath(R((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pytdata_dirs cCsnyNtjj|sdSt|d#}tj|jjdSWdQXWnt k rit dSXdS(Ntrbsutf-8( RRtisfileRtopenRRtreadtdecodeRLR(Rtfh((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt read_jsons& cCsytjj|}tjj|s7tj|n|d}t|d&}|jtj|j dWdQXtjj |rytj |Wqt k rqXntj ||Wntk rtnXdS(Ns.tmptwbsutf-8(RRtdirnametisdirtmakedirsRtwriteRtdumpstencodetexiststremovetOSErrortrenameRLR(RR"t directoryttmpR((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt write_jsons %  cCsddl}|jS(Ni(ttime(R((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR@s cCstjjtdS(Nsmoe_wgapi_cache.json(RRRR(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt _store_pathscCsytt}|dkr"dSt}t||t}|rtj|yt|j dphda Wnt t fk rnXyt|j dpda Wnt t fk rnXtdt|dSyt|j d}Wnt t fk r dSX||}d|ko/tkns8dSt||t}|rtj||atdt||fnWntk rtnXdS(NRiR+s+[moe] wgapi cache adopted: %d tanks (fresh)s4[moe] wgapi cache adopted: %d tanks (stale, age=%ds)(RRRR@R2tREGIONR;R~RRRRRRtRRJRAR>R?RLR(R"RhR!R+tageR((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRFs@      ! cCsMttitd6td6td6td6tdtjDd6dS(NR)RR+R*css=|]3\}}t|td|jDfVqdS(css'|]\}}t||fVqdS(N(R (R R,R-((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys sN(R RR(R R&R((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys sR!( RRR.RRtRRR;R(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRs   cCstjjtdS(Nsmoe_fetch_list.json(RRRR(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt_list_store_path scCszy[tt}|dkr"dSt|t}|rZt|atdttnWnt k rut nXdS(Ns![moe] fetch list loaded: %d tanks( RRRR7RRRKRRJRLR(R"R3((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRGs   cCs?ttitd6td6tdtjDd6dS(NR)R*css-|]#\}}t|t|fVqdS(N(R R(R R&R6((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pys 'sR3(RRR4RRRKR(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyRe#s RcBseZdZdZRS(cCsetjj|||_g|_d|_d|_d|_t |_ d|_ d|_ t |_dS(NisMoE wgapi downloader(t threadingtThreadt__init__RRRRRRRSR RtnameREtdaemon(tselfR((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR4s        cCsy:t|j}t||_t|\|_|_Wn>tk rzddl}|j |_ d|_t |_nXdS(Ni( RRRR R(RRRLt tracebackt format_excRRRS(RR R((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pytrun@s   (t__name__t __module__RR(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyR-s (ii(i7iAiKiUi_id(iAiUi_id(g@g@g.@ii: (ZRRRtmoe_calculatorRtmoe_calculator._compatRRtmoe_calculator.adapterRtmoe_calculator.domainRRRRtWG_APPLICATION_IDRTRRRRRRRRR}RRR.R4tREVALIDATE_SECONDSR/RAR;RRtR>R?RSRHR8RKRRXRnRNRRVR{R<RRRR(R2R7RDR9RQRRRUR^RZRYRgR_R:R=RRRRRRRRRRRRR@RRFRRRGReRRRL(((s6res/scripts/client/moe_calculator/adapter/moe_wgapi.pyt:s         0   !        *   \           -    PK!w%8res/scripts/client/moe_calculator/adapter/sample_log.pyc c@sddlZddlZddlZddlmZddlmZmZdZdZ dZ d%Z d&Z dadZddZdZd Zd!Zd"Zd#Zd$ZdS('iN(t OrderedDict(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGisbattle_pending.jsonsbattle_samples.jsonltint_cdtewma_kt thresholdstpre_percentiletpre_avg_damagetbaseline_knowntdamaget track_assistt spot_assisttstunt team_damagetcombined_damagetcounted_assistt assist_kindtproj_avg_damagetpredicted_percentt pct_deltathas_datat has_baselinetfinal_combined_damaget final_percenttdiedcCsyt|jdpd}|s(tSt}|rLt|d|}nt}||t|R R$(R>((s7res/scripts/client/moe_calculator/adapter/sample_log.pyRs   cCs&ddlm}tjj||S(Ni(tdata_dir(t moe_calculator.adapter.moe_wgapiRBtostpathtjoin(tnameRB((s7res/scripts/client/moe_calculator/adapter/sample_log.pyt_pathscCstd}y&ddlm}|tt}Wntk rFtnXt|tsZiStd|j DS(Ni(t read_jsoncss0|]&\}}t|tr||fVqdS(N(t isinstanceR(t.0tkR4((s7res/scripts/client/moe_calculator/adapter/sample_log.pys s( R:RCRIRHt PENDING_FILER$RRJRtitems(tblobRI((s7res/scripts/client/moe_calculator/adapter/sample_log.pyRs  cCs'ddlm}|tt|dS(Ni(t write_json(RCRPRHRM(R(RP((s7res/scripts/client/moe_calculator/adapter/sample_log.pyR!scCstt}tjj|}tjj|s@tj|nt|d*}|jt j |dj dWdQXdS(Ntabs sutf-8( RHt SAMPLES_FILERDREtdirnametisdirtmakedirstopentwritetjsontdumpstencode(R<REt directorytfh((s7res/scripts/client/moe_calculator/adapter/sample_log.pyR+s  (RRRRRRR R R R R RRRRRRRR(RRR(RDRXR8t collectionsRtmoe_calculator._compatRRR7RMRRR9R;R:R@R)R3R,RRHRR!R+(((s7res/scripts/client/moe_calculator/adapter/sample_log.pyt+s*     %     PK!Yp,H,H;res/scripts/client/moe_calculator/adapter/settings_i18n.pyc c@sddlmZddlmZdZidd6ZdZd!d!dZdZ d Z d"Z dddddd!e e ddd!ddddd!d d!d!d"d#d$d%fZ e d#Zi d$d6d%d*6d&d-6d'd06d(d36d)d66d*d96d+d<6d,d6d-dA6d.dD6Zi d/d6d0d*6d1d-6d2d06d3d36d4d66d5d96d6d<6d7d6d8dA6d9dD6Zi d:d6d;d*6d<d-6d=d06d>d36d?d66d@d96dAd<6dBd6dCdA6dDdD6Zi dEd6dFd*6dGd-6dHd06dId36dJd66dKd96dLd<6dMd6dNdA6dOdD6Zi iedd6edd 6edd6edddd6edddd 6edddd 6edddd 6edddd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edd6edddd6edd6edd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6d6iedd6edd 6edd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edddd6edddd 6edddd 6edddd 6edddd6edd6edddd6edd6edd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6d*6iedd6edd 6edd6edddd6edddd6edddd6edddd6ed d d d6edd d d"6edddd#6edddd6edddd 6edddd 6edddd 6edddd6edd6edddd6edd6edd6edddd 6ed d!d"d6edd#d$d6ed%d&d'd6ed(d)d*d6ed d+d,d!6ed%d$6ed(d%6ed-d-d.d6ed/d0d1d 6ed2d2d3d6d-6ied4d6ed5d 6ed6d6ed7d8d9d6ed:d;d<d6ed=d>d?d6ed@dAdBd6edCdDdEd6edFdGdHd"6edIdJdKd#6edLd4dMd6edLdNdOd 6ed:d;dPd 6edQdRdSd 6edLdTdUd6edVd6edLdWdXd6ed7d6ed:d6edYdZd[d 6ed\d]d^d6ed_d`dad6edbdcddd6ededfdgd6ed\dhdid!6edbd$6eded%6edjdjdkd6edldmdnd 6edododpd6d06iedqd6edrd 6edsd6edtdudvd6edwdxdyd6edzd{d|d6ed}d~dd6edddd6edddd"6edddd#6eddqdd6edddd 6edwdxdd 6edddd 6edddd6edd6edddd6edtd6edwd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6d36iedd6edd 6edd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edddd6edddd 6edddd 6edddd 6edddd6edd6edddd6edd6edd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6d66iedd6edd 6edd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edddd6edddd 6edddd 6edd d d 6edd d d6ed d6edddd6edd6edd6edddd 6edddd6edddd6edddd6edddd6eddd d!6edd$6edd%6ed!d!d"d6ed#d$d%d 6ed&d&d'd6d96ied(d6ed)d 6ed*d6ed+d,d-d6ed.d/d0d6ed1d2d3d6ed4d5d6d6ed7d8d9d6ed:d;d<d"6ed=d>d?d#6ed@d(dAd6ed@dBdCd 6ed.d/dDd 6edEdFdGd 6ed@dHdId6edJd6ed@dKdLd6ed+d6ed.d6edMdNdOd 6edPdQdRd6edSdTdUd6edVdWdXd6edYdZd[d6edPd\d]d!6edVd$6edYd%6ed^d^d_d6ed`dadbd 6edcdcddd6d<6ieded6edfd 6edgd6edhdidjd6edkdldmd6edndodpd6ed4dqdrd6ed7dsdtd6edudvdwd"6edxdydzd#6ed{ded|d6ed{d}d~d 6edkdldd 6edddd 6ed{ddd6edd6ed{ddd6edhd6edkd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6d6iedd6edd 6edd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edddd6edddd 6edddd 6edddd 6edddd6edd6edddd6edd6edd6edddd 6edddd6edddd6edddd6edddd6edddd!6edd$6edd%6edddd6edddd 6edddd6dA6iedd6edd 6edd6edddd6edddd6edddd6edddd6edddd6edddd"6edddd#6edddd6edddd 6edddd 6edddd 6edddd6edd6edddd6edd6edd6edddd 6edddd6edd d d6ed d d d6edddd6edddd!6ed d$6edd%6edddd6edddd 6edddd6dD6ZdZedZdZdZdZd Zd!S(Pi(tLOG_CURRENT_EXCEPTION(ti18nuenuukuuacCsv|s dS|jjjdd}tj||}|tkrJ|S|jddd}tj||}|S(Nuu-u_ii(tstriptlowertreplacet_ALIASEStgett_PANELtsplit(tcodetctbase((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pyt_normWs cCsLi|d6}|dk s%|dk rH|p.d|d<|p>d|dThe bar fades and slides as it appears and disappears. Uncheck this to make every appearance instant instead, or turn off just one switch below. Events covers the bar reacting to what happens in battle; Alt Press covers bringing it up with the Alt key, matching the game's own interface, which does not animate on Alt.uHold Duration (s)u Hold durationuHow long the bar stays on screen, in seconds, after an event raises it. Holding Alt keeps it up for as long as the key is held, whatever this is set to. The fade in and the fade out are not counted.uLayoutuWidget positionuCtrl+drag the Garage widget to move it (hold Shift to lock to one axis). The steppers below show its pinned top-left position in pixels; 0 / 0 means the default bottom-right position. Use the per-mod Reset to return to default.uPositionuPosition steppersuJBoth steppers below apply immediately, without needing to drag the widget.uHorizontal (left X)uHorizontal positionurThe pinned widget's distance from the left screen edge, in pixels. 0 restores the automatic bottom-right position.uVertical (top Y)uVertical positionuqThe pinned widget's distance from the top screen edge, in pixels. 0 restores the automatic bottom-right position.uIn-battle bar positionuHold Ctrl in battle and drag the bar to move it. The steppers below show where it is pinned, in pixels from the top-left corner of the screen; 0 / 0 means the default centred position. Use the per-mod Reset to return to default.uFollow CarouseluFollow Carousel ModeuWhen on, a dragged widget keeps shifting vertically with the vehicle carousel (single / double rows) so it never overlaps it. When off, a pinned widget stays fixed regardless of the carousel.uMode Override KeyuIn-battle mode overrideuThe key you press in battle to switch this vehicle's progress-bar mode between Damage Efficiency and Moving Average. The mod remembers each vehicle's choice. After you switch, the bar reloads and reappears after a few seconds. Default: K.uAutomatic Mode ToggleuAutomatic mode toggleuWhen a vehicle's mark progress reaches this percent before battle, its bar mode switches automatically, the same as pressing the override key above. Only fires once per vehicle. 100% turns this off.u Garage-WidgetuGefechtsrechneruGefechtsfortschrittu EreignisseuBei Ereignissen anzeigenuBlendet die Leiste von selbst ein, sobald im Gefecht etwas Verfolgtes passiert, und lässt sie danach wieder verschwinden. Wird ignoriert, solange Immer aktiv ist.u Alt drückenuAuf Alt-Taste anzeigenucZeigt die Leiste nur, solange die Alt-Taste gehalten wird. Wird ignoriert, solange Immer aktiv ist.uImmeruImmer anzeigenuLässt die Leiste dauerhaft auf dem Bildschirm stehen; sie verschwindet nie. Hat Vorrang vor beiden Schaltern oben, die dabei ausgegraut werden.uModusu LeistenmodusutWechselt zwischen den beiden oben beschriebenen Leisten. Wird wirksam, sobald die Leiste das nächste Mal erscheint.u SkalierunguLeistengrößeusStandard: die normale Größe der Leiste. Groß: zeigt sie größer an, für bessere Lesbarkeit aus der Entfernung.u AusrichtunguLeistenausrichtunguHorizontal ist das ursprüngliche Layout der Leiste. Vertikal zeigt sie aufrecht stehend, passend zur Platzierung neben der Minikarte. Wird wirksam, sobald die Leiste das nächste Mal erscheint.u VerankerunguVerankerung der LeisteuVon welchem Ankerpunkt aus die Positionsfelder unten wirken. Fest: der eingebaute Platz der Leiste, automatisch anhand der Ausrichtung gewählt -- horizontal sitzt sie mittig am unteren Bildschirmrand, über dem Schadensprotokoll; vertikal sitzt sie neben der Minikarte, nahe ihrer unteren linken Ecke, passend zur aktuellen Größe der Minikarte. Frei: eine unverankerte Position, automatisch gesetzt, sobald du die Leiste ziehst oder ein Feld änderst. Unter Fest ist die Position gesperrt; Ziehen und die Felder unten wirken nur unter Frei.u AktiviertudZeigt die Marken-Prozentanzeige in der Garage beim ausgewählten Fahrzeug. Zum Ausblenden abwählen.uGefechts-WidgetuoZeigt die Live-Marken-Anzeige im Gefecht. Zum Ausblenden abwählen; die Optionen unten werden dann deaktiviert.u{Zeigt die Gefechtsanzeige nur, solange die Alt-Taste gehalten wird. Wenn deaktiviert, wird die Anzeige dauerhaft angezeigt.u#Angerechnete Unterstützung (Zeile)uAngerechnete UnterstützunguFügt der Gefechtsanzeige eine dritte Zeile mit deiner angerechneten Unterstützung hinzu: dem höheren Wert aus Ketten-, Aufklärungs- oder Betäubungsunterstützung, mit einem Symbol für den führenden Wert.uFortschrittsleisteuZeigt während des Spiels eine Leiste in der Bildschirmmitte, die von selbst wieder verschwindet. Halte Alt, um sie jederzeit einzublenden. Wähle unten, welche Leiste. Schadenseffizienz: zeigt deinen Schaden in diesem Gefecht im Verhältnis zu den Anforderungen der Marken 65 / 85 / 95 / 100 %. Gleitender Durchschnitt: zeigt, wo dein voraussichtlicher Durchschnittsschaden zwischen der Marke, die du hast, und der Anforderung der nächsten Marke liegt.u ÜbergängeuÜbergänge der LeisteunDie Leiste blendet ein und gleitet, wenn sie erscheint und verschwindet. Deaktiviere dies, damit jedes Erscheinen sofort erfolgt, oder schalte unten nur einen Schalter ab. Ereignisse betrifft die Reaktion der Leiste auf das Geschehen im Gefecht; Alt drücken betrifft das Einblenden mit der Alt-Taste, wie in der Spieloberfläche selbst, die bei Alt nichts animiert.uHaltedauer (s)u HaltedaueruWie lange die Leiste nach einem Ereignis auf dem Bildschirm bleibt, in Sekunden. Solange Alt gehalten wird, bleibt sie unabhängig davon eingeblendet. Ein- und Ausblenden werden nicht mitgezählt.uWidget-Positionu:Ziehe das Garage-Widget mit Strg+Ziehen, um es zu verschieben (halte Umschalt gedrückt, um es auf eine Achse zu beschränken). Die Felder unten zeigen seine fixierte Position oben links in Pixeln; 0 / 0 bedeutet die Standardposition unten rechts. Nutze das Zurücksetzen des Mods, um zum Standard zurückzukehren.uPositions-FelderuABeide Felder unten wirken sofort, ganz ohne das Widget zu ziehen.uHorizontal (links X)uHorizontale Positionu~Abstand des fixierten Widgets vom linken Bildschirmrand in Pixeln. 0 stellt die automatische Position unten rechts wieder her.uVertikal (oben Y)uVertikale Positionu~Abstand des fixierten Widgets vom oberen Bildschirmrand in Pixeln. 0 stellt die automatische Position unten rechts wieder her.uPosition der Leiste im GefechtuHalte im Gefecht Strg gedrückt und ziehe die Leiste, um sie zu verschieben. Die Felder unten zeigen ihre fixierte Position in Pixeln von der oberen linken Bildschirmecke; 0 / 0 bedeutet die zentrierte Standardposition. Nutze das Zurücksetzen des Mods, um zum Standard zurückzukehren.uKarussell folgenuWenn aktiviert, verschiebt sich ein gezogenes Widget weiterhin vertikal mit dem Fahrzeugkarussell (eine / zwei Reihen), sodass es dieses nie überdeckt. Wenn deaktiviert, bleibt ein fixiertes Widget unabhängig vom Karussell an seiner Stelle.uModus-WechseltasteuModus-Wechsel im Gefechtu.Die Taste, die du im Gefecht drückst, um den Fortschrittsleisten-Modus dieses Fahrzeugs zwischen Schadenseffizienz und Gleitendem Durchschnitt umzuschalten. Der Mod merkt sich die Wahl für jedes Fahrzeug. Nach dem Wechsel lädt die Leiste neu und erscheint nach ein paar Sekunden wieder. Standard: K.uAutomatische ModusumschaltunguWenn der Markenfortschritt eines Fahrzeugs vor dem Gefecht diesen Prozentsatz erreicht, wechselt der Leistenmodus automatisch, genauso wie mit der Wechseltaste oben. Wirkt nur einmal pro Fahrzeug. 100 % schaltet dies aus.uWidget du garageuCalculateur de batailleuProgression en batailleu ÉvénementsuAfficher sur événementuAffiche la barre d'elle-même dès qu'un événement suivi se produit en bataille, puis la fait disparaître à nouveau. Ignoré tant que Toujours est actif.u Appui sur AltuAfficher avec la touche AltufAffiche la barre uniquement tant que la touche Alt est maintenue. Ignoré tant que Toujours est actif.uToujoursuToujours afficheruLaisse la barre affichée en permanence à l'écran ; elle ne disparaît jamais. Prime sur les deux interrupteurs ci-dessus, qui se grisent tant que celui-ci est actif.uMode de la barreuhBascule entre les deux barres décrites ci-dessus. Prend effet la prochaine fois que la barre apparaît.uÉchelleuTaille de la barreuuPar défaut : taille normale de la barre. Grande : l'affiche plus grande, pour une meilleure lisibilité à distance.uOrientation de la barreuHorizontale est la disposition d'origine de la barre. Verticale l'affiche debout, dimensionnée pour se placer à côté de la minicarte. Prend effet la prochaine fois que la barre apparaît.u AlignementuAlignement de la barreujDepuis quel point d'ancrage les compteurs de position ci-dessous se décalent. Fixe : l'emplacement intégré de la barre, choisi automatiquement selon l'orientation -- horizontale, elle se centre en bas de l'écran, au-dessus du journal des dégâts ; verticale, elle se place à côté de la minicarte, près de son coin inférieur gauche, selon la taille actuelle de la minicarte. Libre : une position non ancrée, définie automatiquement dès que vous faites glisser la barre ou modifiez un compteur. Sous Fixe, la position est verrouillée ; le glisser et les compteurs ci-dessous ne fonctionnent que sous Libre.uActivéuAffiche la barre de centile des marques d'excellence dans le garage, sur le véhicule sélectionné. Décochez pour la masquer.uWidget de batailleuAffiche la superposition des marques d'excellence en direct pendant la bataille. Décochez pour la masquer et désactiver les options ci-dessous.uAffiche la superposition de bataille uniquement tant que la touche Alt est maintenue. Lorsque cette option est désactivée, la superposition est affichée en permanence.u!Ligne d'assistance comptabiliséeuAssistance comptabiliséeuAjoute une troisième ligne à la superposition de bataille indiquant votre assistance comptabilisée : la plus élevée entre l'assistance par chenilles, par détection ou par étourdissement, avec une icône pour celle qui domine.uBarre de progressionuAffiche une barre au centre de l'écran pendant la partie, puis la fait disparaître d'elle-même. Maintenez Alt pour l'afficher à tout moment. Choisissez la barre ci-dessous. Efficacité des dégâts : situe vos dégâts de la bataille en cours par rapport aux exigences des marques 65 / 85 / 95 / 100 %. Moyenne glissante : indique où se situent vos dégâts moyens prévus entre la marque que vous possédez et l'exigence de la marque suivante.uTransitions de la barreuwLa barre s'estompe et glisse lorsqu'elle apparaît et disparaît. Décochez ceci pour que chaque apparition soit instantanée, ou désactivez un seul interrupteur ci-dessous. Événements concerne la réaction de la barre à ce qui se passe en bataille ; Appui sur Alt concerne son affichage avec la touche Alt, comme l'interface du jeu elle-même, qui n'anime rien avec Alt.uDurée d'affichage (s)uDurée d'affichageuCombien de temps la barre reste à l'écran, en secondes, après qu'un événement l'a fait apparaître. Tant que la touche Alt est maintenue, elle reste affichée quelle que soit cette valeur. Les fondus d'entrée et de sortie ne sont pas comptés.u DispositionuPosition du widgetuACtrl+glisser pour déplacer le widget du garage (maintenez Maj pour le verrouiller sur un axe). Les compteurs ci-dessous indiquent sa position épinglée en haut à gauche, en pixels ; 0 / 0 correspond à la position par défaut en bas à droite. Utilisez la réinitialisation du mod pour revenir au réglage par défaut.uCompteurs de positionuaLes deux compteurs ci-dessous s'appliquent immédiatement, sans avoir à faire glisser le widget.uHorizontale (X gauche)uPosition horizontaleuDistance du widget épinglé par rapport au bord gauche de l'écran, en pixels. 0 rétablit la position automatique en bas à droite.uVerticale (Y haut)uPosition verticaleuDistance du widget épinglé par rapport au bord supérieur de l'écran, en pixels. 0 rétablit la position automatique en bas à droite.u Position de la barre en batailleu?En bataille, maintenez Ctrl et faites glisser la barre pour la déplacer. Les compteurs ci-dessous indiquent sa position épinglée, en pixels depuis le coin supérieur gauche de l'écran ; 0 / 0 correspond à la position centrée par défaut. Utilisez la réinitialisation du mod pour revenir à la valeur par défaut.uSuivre le carrouseluActivé, un widget déplacé continue de se décaler verticalement avec le carrousel des véhicules (une / deux rangées) afin de ne jamais le chevaucher. Désactivé, un widget épinglé reste fixe quel que soit le carrousel.uTouche de changement de modeuChangement de mode en batailleu1La touche que vous appuyez en bataille pour basculer le mode de la barre de progression de ce véhicule entre Efficacité des dégâts et Moyenne glissante. Le mod mémorise le choix de chaque véhicule. Après le changement, la barre se recharge et réapparaît après quelques secondes. Par défaut : K.uChangement de mode automatiqueuLorsque la progression des marques d'un véhicule atteint ce pourcentage avant la bataille, le mode de la barre change automatiquement, comme avec la touche de changement ci-dessus. Ne se déclenche qu'une fois par véhicule. 100 % désactive cette fonction.uWidget del garajeuCalculadora de batallauProgreso en batallauEventosuMostrar en eventosuMuestra la barra por sí sola en cuanto ocurre un evento seguido en la batalla, y luego la oculta de nuevo. Se ignora mientras Siempre está activado.u Pulsar AltuMostrar con la tecla AltuiMuestra la barra solo mientras mantienes pulsada la tecla Alt. Se ignora mientras Siempre está activado.uSiempreuMostrar siempreuMantiene la barra en pantalla de forma permanente; nunca se oculta. Anula los dos interruptores anteriores, que se atenúan mientras este está activado.uModouModo de la barrau_Alterna entre las dos barras descritas arriba. Se aplica la próxima vez que aparezca la barra.uEscalauTamaño de la barrauuPredeterminada: el tamaño normal de la barra. Grande: la muestra más grande, para facilitar la lectura a distancia.u OrientaciónuOrientación de la barrauHorizontal es la disposición original de la barra. Vertical la muestra de pie, dimensionada para colocarse junto al minimapa. Se aplica la próxima vez que aparezca la barra.u AlineaciónuAlineación de la barrauIDesde qué punto de anclaje se desplazan los contadores de posición de abajo. Fija: la posición integrada de la barra, elegida automáticamente según la orientación -- horizontal se centra en la parte inferior de la pantalla, sobre el registro de daños; vertical se coloca junto al minimapa, cerca de su esquina inferior izquierda, según el tamaño actual del minimapa. Libre: una posición sin anclar, establecida automáticamente al arrastrar la barra o editar un contador. Bajo Fija, la posición está bloqueada; arrastrar y los contadores de abajo solo funcionan bajo Libre.uActivadou~Muestra la barra de percentil de las marcas de excelencia en el garaje, en el vehículo seleccionado. Desmarca para ocultarla.uWidget de batallauMuestra la superposición de marcas de excelencia en directo durante la batalla. Desmarca para ocultarla y desactivar las opciones de abajo.uMuestra la superposición de batalla solo mientras se mantiene pulsada la tecla Alt. Cuando está desactivado, la superposición se muestra en todo momento.uFila de asistencia contadauAsistencia contadauAñade una tercera fila a la superposición de batalla que muestra tu asistencia contada: la mayor entre la asistencia por orugas, por detección o por aturdimiento, con un icono para la que predomine.uBarra de progresouMuestra una barra en el centro de la pantalla durante la partida y luego la oculta por sí sola. Mantén pulsado Alt para mostrarla en cualquier momento. Elige abajo qué barra. Eficiencia de daño: sitúa tu daño de esta batalla frente a los requisitos de las marcas del 65 / 85 / 95 / 100 %. Media móvil: indica dónde se sitúa tu daño medio previsto entre la marca que tienes y el requisito de la siguiente marca.u TransicionesuTransiciones de la barraufLa barra se atenúa y desliza al aparecer y desaparecer. Desmarca esto para que cada aparición sea instantánea, o desactiva solo uno de los interruptores de abajo. Eventos se refiere a la barra reaccionando a lo que ocurre en la batalla; Pulsar Alt se refiere a mostrarla con la tecla Alt, igual que la interfaz del propio juego, que no anima nada con Alt.uDuración en pantalla (s)uDuración en pantallauCuánto tiempo permanece la barra en pantalla, en segundos, después de que un evento la muestre. Mientras mantengas Alt seguirá visible, sea cual sea este valor. Las transiciones de entrada y salida no se cuentan.u DisposiciónuPosición del widgetuHCtrl+arrastrar para mover el widget del garaje (mantén Mayús para bloquearlo en un eje). Los contadores de abajo muestran su posición fijada de la esquina superior izquierda, en píxeles; 0 / 0 es la posición predeterminada en la esquina inferior derecha. Usa el restablecimiento del mod para volver al valor predeterminado.u PosiciónuContadores de posiciónuXAmbos contadores de abajo se aplican de inmediato, sin necesidad de arrastrar el widget.uHorizontal (X izquierda)uPosición horizontaluDistancia del widget fijado al borde izquierdo de la pantalla, en píxeles. 0 restaura la posición automática en la esquina inferior derecha.uVertical (Y superior)uPosición verticaluDistancia del widget fijado al borde superior de la pantalla, en píxeles. 0 restaura la posición automática en la esquina inferior derecha.u Posición de la barra en combateu,En combate, mantén pulsado Ctrl y arrastra la barra para moverla. Los contadores de abajo muestran su posición fijada, en píxeles desde la esquina superior izquierda de la pantalla; 0 / 0 es la posición centrada predeterminada. Usa el restablecimiento del mod para volver al valor predeterminado.uSeguir el carruseluCuando está activado, un widget arrastrado sigue desplazándose verticalmente con el carrusel de vehículos (una / dos filas) para no superponerse a él. Cuando está desactivado, un widget fijado permanece fijo sin importar el carrusel.uTecla de cambio de modouCambio de modo en combateuLa tecla que pulsas en combate para alternar el modo de la barra de progreso de este vehículo entre Eficiencia de daño y Media móvil. El mod recuerda la elección de cada vehículo. Después de cambiar, la barra se recarga y reaparece tras unos segundos. Predeterminada: K.uCambio de modo automáticouCuando el progreso de marcas de un vehículo alcanza este porcentaje antes de la batalla, el modo de la barra cambia automáticamente, igual que con la tecla de cambio de arriba. Solo se activa una vez por vehículo. 100 % lo desactiva.uWidget del garageuCalcolatore di battagliauProgresso in battagliauEventiuMostra sugli eventiuMostra la barra da sola non appena accade un evento monitorato in battaglia, poi la fa scomparire di nuovo. Ignorato mentre Sempre è attivo.u Premi AltuMostra con il tasto AltuYMostra la barra solo mentre tieni premuto il tasto Alt. Ignorato mentre Sempre è attivo.uSempreu Mostra sempreuLascia la barra fissa sullo schermo in modo permanente; non scompare mai. Prevale sui due interruttori sopra, che restano in grigio finché questo è attivo.u ModalitàuModalità della barraujPassa da una barra all'altra tra le due descritte sopra. Ha effetto la prossima volta che la barra appare.uScalauDimensione della barrauvPredefinita: la dimensione normale della barra. Grande: la mostra più grande, per una lettura più facile a distanza.u OrientamentouOrientamento della barrauOrizzontale è la disposizione originale della barra. Verticale la mostra in piedi, dimensionata per stare accanto alla minimappa. Ha effetto la prossima volta che la barra appare.u AllineamentouAllineamento della barrauHDa quale punto di ancoraggio partono i contatori di posizione sotto. Fisso: la posizione predefinita della barra, scelta automaticamente in base all'orientamento -- orizzontale si centra in basso sullo schermo, sopra il registro danni; verticale si posiziona accanto alla minimappa, vicino al suo angolo inferiore sinistro, in base alla dimensione attuale della minimappa. Libero: una posizione non ancorata, impostata automaticamente trascinando la barra o modificando un contatore. Con Fisso la posizione è bloccata; il trascinamento e i contatori sotto funzionano solo con Libero.u AbilitatoutMostra la barra di percentile dei marchi di merito nel garage, sul veicolo selezionato. Deseleziona per nasconderla.uWidget di battagliauMostra la sovrapposizione dei marchi di merito in tempo reale durante la battaglia. Deseleziona per nasconderla e disattivare le opzioni sottostanti.uMostra la sovrapposizione di battaglia solo mentre si tiene premuto il tasto Alt. Quando è disattivato, la sovrapposizione è sempre visibile.uRiga assistenza conteggiatauAssistenza conteggiatauAggiunge una terza riga alla sovrapposizione di battaglia che mostra la tua assistenza conteggiata: la più alta tra assistenza ai cingoli, all'avvistamento o allo stordimento, con un'icona per quella prevalente.uBarra di progressouMostra una barra al centro dello schermo durante la partita, poi scompare da sola. Tieni premuto Alt per mostrarla in qualsiasi momento. Scegli sotto quale barra. Efficienza dei danni: colloca i tuoi danni di questa battaglia rispetto ai requisiti dei marchi 65 / 85 / 95 / 100 %. Media mobile: indica dove si collocano i tuoi danni medi previsti tra il marchio che possiedi e il requisito del marchio successivo.u TransizioniuTransizioni della barrau\La barra sfuma e scorre quando appare e scompare. Deseleziona questa voce perché ogni comparsa sia istantanea, oppure disattiva un solo interruttore qui sotto. Eventi riguarda la barra che reagisce a ciò che accade in battaglia; Premi Alt riguarda il richiamarla con il tasto Alt, come l'interfaccia del gioco stesso, che con Alt non anima nulla.uDurata di permanenza (s)uDurata di permanenzauPer quanto tempo la barra resta sullo schermo, in secondi, dopo che un evento l'ha richiamata. Tenendo premuto Alt resta visibile a prescindere da questo valore. Le dissolvenze di entrata e di uscita non sono conteggiate.u DisposizioneuPosizione del widgetu(Ctrl+trascina per spostare il widget del garage (tieni premuto Maiusc per bloccarlo su un asse). I contatori sotto mostrano la sua posizione fissata in alto a sinistra, in pixel; 0 / 0 indica la posizione predefinita in basso a destra. Usa il ripristino del mod per tornare al valore predefinito.u PosizioneuContatori di posizioneuYEntrambi i contatori sotto si applicano immediatamente, senza dover trascinare il widget.uOrizzontale (X sinistra)uPosizione orizzontaleuDistanza del widget fissato dal bordo sinistro dello schermo, in pixel. 0 ripristina la posizione automatica in basso a destra.uVerticale (Y alto)uPosizione verticaleuDistanza del widget fissato dal bordo superiore dello schermo, in pixel. 0 ripristina la posizione automatica in basso a destra.u"Posizione della barra in battagliauIn battaglia, tieni premuto Ctrl e trascina la barra per spostarla. I contatori sotto mostrano la sua posizione fissata, in pixel dall'angolo in alto a sinistra dello schermo; 0 / 0 indica la posizione centrata predefinita. Usa il ripristino del mod per tornare al valore predefinito.uSegui il carosellouQuando è attivo, un widget trascinato continua a spostarsi verticalmente con il carosello dei veicoli (una / due file) in modo da non sovrapporsi mai ad esso. Quando è disattivato, un widget fissato resta fermo indipendentemente dal carosello.uTasto di cambio modalitàuCambio modalità in battagliau Il tasto che premi in battaglia per cambiare la modalità della barra di progresso di questo veicolo tra Efficienza dei danni e Media mobile. Il mod ricorda la scelta di ogni veicolo. Dopo il cambio, la barra si ricarica e riappare dopo alcuni secondi. Predefinito: K.uCambio modalità automaticouQuando il progresso dei marchi di un veicolo raggiunge questa percentuale prima della battaglia, la modalità della barra cambia automaticamente, come con il tasto di cambio sopra. Si attiva solo una volta per veicolo. Il 100% lo disattiva.uWidżet w garażuuKalkulator bitewnyuPostęp w bitwieu ZdarzeniauPokaż przy zdarzeniachuPokazuje pasek samoczynnie, gdy w bitwie wystąpi śledzone zdarzenie, po czym znów znika. Ignorowane, gdy włączone jest Zawsze.u Naciśnij AltuPokaż na klawiszu Altu`Pokazuje pasek tylko podczas przytrzymania klawisza Alt. Ignorowane, gdy włączone jest Zawsze.uZawszeuZawsze pokazujuUtrzymuje pasek na ekranie na stałe; nigdy nie znika. Ma pierwszeństwo przed obydwoma przełącznikami powyżej, które są wyszarzone, gdy ta opcja jest włączona.uTrybu Tryb paskaunPrzełącza między dwoma paskami opisanymi powyżej. Zaczyna działać przy następnym pojawieniu się paska.uSkalau Rozmiar paskaujDomyślna: normalny rozmiar paska. Duża: pokazuje go większym, dla łatwiejszego odczytu z odległości.u OrientacjauOrientacja paskauPozioma to pierwotny układ paska. Pionowa pokazuje go w pozycji stojącej, dopasowanego rozmiarem do miejsca obok minimapy. Zaczyna działać przy następnym pojawieniu się paska.u ZakotwiczenieuZakotwiczenie paskau-Od którego punktu odniesienia liczą się liczniki pozycji poniżej. Stałe: wbudowane miejsce paska, wybierane automatycznie według orientacji -- pozioma ustawia się na środku dolnej krawędzi ekranu, nad dziennikiem obrażeń; pionowa ustawia się obok minimapy, blisko jej lewego dolnego rogu, zgodnie z aktualnym rozmiarem minimapy. Swobodne: pozycja bez punktu odniesienia, ustawiana automatycznie po przeciągnięciu paska lub edycji licznika. Przy Stałe pozycja jest zablokowana; przeciąganie i liczniki poniżej działają tylko przy Swobodne.u WłączoneuhPokazuje pasek percentyla znaków doskonałości w garażu, na wybranym pojeździe. Odznacz, aby ukryć.uWidżet w bitwieuxPokazuje nakładkę znaków doskonałości na żywo podczas bitwy. Odznacz, aby ją ukryć i wyłączyć opcje poniżej.uPokazuje nakładkę bitewną tylko podczas przytrzymania klawisza Alt. Gdy wyłączone, nakładka jest wyświetlana przez cały czas.uWiersz zaliczonego wsparciauZaliczone wsparcieuDodaje trzeci wiersz nakładki bitewnej pokazujący twoje zaliczone wsparcie: wyższą z wartości wsparcia przez unieruchomienie, wykrycie lub ogłuszenie, z ikoną dla przeważającej.uPasek postępuuPokazuje pasek na środku ekranu w trakcie gry, a potem znika on samoczynnie. Przytrzymaj Alt, aby wyświetlić go w dowolnym momencie. Wybierz poniżej, który pasek. Efektywność obrażeń: pokazuje twoje obrażenia w tej bitwie na tle wymagań znaków 65 / 85 / 95 / 100 %. Średnia krocząca: wskazuje, gdzie twoje przewidywane średnie obrażenia wypadają między znakiem, który posiadasz, a wymaganiem następnego znaku.u PrzejściauPrzejścia paskaulPasek pojawia się i znika z przygaszeniem oraz przesunięciem. Odznacz tę opcję, aby każde pojawienie było natychmiastowe, albo wyłącz tylko jeden z przełączników poniżej. Zdarzenia dotyczą reakcji paska na to, co dzieje się w bitwie; Naciśnij Alt dotyczy wywołania go klawiszem Alt, tak jak w interfejsie samej gry, który przy Alt nic nie animuje.uCzas wyświetlania (s)uCzas wyświetlaniauJak długo pasek pozostaje na ekranie, w sekundach, po tym jak wywoła go zdarzenie. Przy przytrzymanym Alt pozostaje widoczny niezależnie od tej wartości. Przygaszenie przy pojawianiu się i zniknięciu nie jest liczone.uUkładuPozycja widżetuu*Ctrl+przeciągnij, aby przesunąć widżet garażu (przytrzymaj Shift, aby zablokować do jednej osi). Liczniki poniżej pokazują przypiętą pozycję lewego górnego rogu w pikselach; 0 / 0 oznacza domyślną pozycję w prawym dolnym rogu. Użyj resetu moda, aby wrócić do wartości domyślnej.uPozycjauLiczniki pozycjiuWOba liczniki poniżej działają natychmiast, bez konieczności przeciągania widżetu.uPozioma (lewy X)uPozycja poziomauOdległość przypiętego widżetu od lewej krawędzi ekranu, w pikselach. 0 przywraca automatyczną pozycję w prawym dolnym rogu.uPionowa (górny Y)uPozycja pionowauOdległość przypiętego widżetu od górnej krawędzi ekranu, w pikselach. 0 przywraca automatyczną pozycję w prawym dolnym rogu.uPozycja paska w bitwieu W bitwie przytrzymaj Ctrl i przeciągnij pasek, aby go przesunąć. Liczniki poniżej pokazują jego przypiętą pozycję w pikselach od lewego górnego rogu ekranu; 0 / 0 oznacza domyślną pozycję na środku. Użyj resetu moda, aby wrócić do wartości domyślnej.uPodążaj za karuzeląuGdy włączone, przeciągnięty widżet nadal przesuwa się w pionie wraz z karuzelą pojazdów (jeden / dwa rzędy), aby nigdy jej nie zasłaniać. Gdy wyłączone, przypięty widżet pozostaje na miejscu niezależnie od karuzeli.uKlawisz zmiany trybuuZmiana trybu w bitwieuKlawisz, który naciskasz w bitwie, aby przełączyć tryb paska postępu tego pojazdu między Efektywnością obrażeń a Średnią kroczącą. Mod zapamiętuje wybór dla każdego pojazdu. Po zmianie pasek przeładowuje się i pojawia się ponownie po kilku sekundach. Domyślnie: K.uAutomatyczna zmiana trybuuGdy postęp znaków pojazdu przed bitwą osiągnie ten procent, tryb paska zmienia się automatycznie, tak jak za pomocą klawisza zmiany powyżej. Działa tylko raz na pojazd. 100% wyłącza tę funkcję.uWidget v garážiuBitevní kalkulátoruPostup v bitvěu UdálostiuZobrazit při událostechuZobrazí lištu samovolně, jakmile v bitvě nastane sledovaná událost, a poté ji znovu skryje. Ignorováno, když je zapnuto Vždy.u Stisk AltuZobrazit na klávese AltuZZobrazuje lištu jen po dobu podržení klávesy Alt. Ignorováno, když je zapnuto Vždy.uVždyuVždy zobrazituNechá lištu trvale na obrazovce; nikdy nezmizí. Má přednost před oběma přepínači výše, které jsou po dobu jeho zapnutí zašedlé.uRežimu Režim lištyubPřepíná mezi oběma lištami popsanými výše. Projeví se při příštím zobrazení lišty.u MěřítkouVelikost lištyuaVýchozí: běžná velikost lišty. Velké: zobrazí ji větší, pro snazší čtení z dálky.u OrientaceuOrientace lištyuVodorovná je původní rozvržení lišty. Svislá ji zobrazí na výšku, s rozměry pro umístění vedle minimapy. Projeví se při příštím zobrazení lišty.u UkotveníuUkotvení lištyuOd kterého ukotvení se počítají čítače pozice níže. Pevné: vestavěné místo lišty, vybrané automaticky podle orientace -- vodorovná se vystředí na spodním okraji obrazovky, nad deníkem poškození; svislá se umístí vedle minimapy, poblíž jejího levého dolního rohu, podle aktuální velikosti minimapy. Volné: neukotvená pozice, nastavená automaticky po přetažení lišty nebo úpravě čítače. V režimu Pevné je pozice uzamčená; tažení a čítače níže fungují jen v režimu Volné.uPovolenouoZobrazuje percentilovou lištu znaků cti v garáži u vybraného vozidla. Zrušením zaškrtnutí ji skryjete.uWidget v bitvěusZobrazuje živý překryv znaků cti během bitvy. Zrušením zaškrtnutí jej skryjete a vypnete možnosti níže.unZobrazuje bojový překryv pouze při podržení klávesy Alt. Když je vypnuto, překryv se zobrazuje trvale.uŘádek započtené asistenceuZapočtená asistenceuPřidá do bojového překryvu třetí řádek zobrazující tvou započtenou asistenci: vyšší z asistence pásy, průzkumem nebo omráčením, s ikonou pro převažující.uLišta postupuuZobrazuje uprostřed obrazovky lištu během hry a poté sama zmizí. Podržením klávesy Alt ji zobrazíš kdykoli. Níže vyber, kterou lištu. Efektivita poškození: ukazuje tvé poškození v této bitvě vůči požadavkům znaků 65 / 85 / 95 / 100 %. Klouzavý průměr: ukazuje, kde se tvé předpokládané průměrné poškození nachází mezi znakem, který máš, a požadavkem dalšího znaku.u PřechodyuPřechody lištyuaLišta se při zobrazení a zmizení prolíná a posouvá. Zrušením zaškrtnutí bude každé zobrazení okamžité, nebo vypni jen jeden z přepínačů níže. Události se týkají reakce lišty na to, co se děje v bitvě; Stisk Alt se týká jejího vyvolání klávesou Alt, stejně jako v rozhraní samotné hry, které při Altu nic neanimuje.uDoba zobrazení (s)uDoba zobrazeníuJak dlouho lišta zůstane na obrazovce, ve sekundách, poté co ji vyvolá událost. Při podržení Altu zůstává zobrazená bez ohledu na tuto hodnotu. Prolnutí na začátku a na konci se nepočítá.u RozvrženíuPozice widgetuuCtrl+táhnutím přesuneš widget garáže (podržením Shift jej uzamkneš na jednu osu). Čítače níže ukazují jeho ukotvenou pozici levého horního rohu v pixelech; 0 / 0 znamená výchozí pozici vpravo dole. Pro návrat na výchozí hodnotu použij reset modu.uPoziceuČítače poziceuKOba čítače níže se projeví okamžitě, bez nutnosti tažení widgetu.uVodorovná (levé X)uVodorovná poziceurVzdálenost ukotveného widgetu od levého okraje obrazovky v pixelech. 0 obnoví automatickou pozici vpravo dole.uSvislá (horní Y)uSvislá poziceusVzdálenost ukotveného widgetu od horního okraje obrazovky v pixelech. 0 obnoví automatickou pozici vpravo dole.uPozice lišty v bitvěuV bitvě podrž Ctrl a tažením lištu přesuneš. Čítače níže ukazují její ukotvenou pozici v pixelech od levého horního rohu obrazovky; 0 / 0 znamená výchozí pozici uprostřed. Pro návrat na výchozí hodnotu použij reset modu.uSledovat kolotočuKdyž je zapnuto, tažený widget se dál posouvá svisle spolu s kolotočem vozidel (jedna / dvě řady), aby jej nikdy nepřekrýval. Když je vypnuto, ukotvený widget zůstává na místě bez ohledu na kolotoč.uKlávesa přepnutí režimuuPřepnutí režimu v bitvěuKlávesa, kterou v bitvě stiskneš pro přepnutí režimu lišty postupu tohoto vozidla mezi Efektivitou poškození a Klouzavým průměrem. Mod si pamatuje volbu pro každé vozidlo. Po přepnutí se lišta znovu načte a znovu se zobrazí po několika sekundách. Výchozí: K.uAutomatické přepnutí režimuuKdyž postup známek vozidla před bitvou dosáhne tohoto procenta, režim lišty se automaticky přepne, stejně jako klávesou přepnutí výše. Spustí se jen jednou na vozidlo. 100 % tuto funkci vypne.uВиджет в ангареu#Боевой калькуляторuПрогресс в боюuСобытияu*Показывать по событиямuПоказывает полосу самостоятельно, как только в бою происходит отслеживаемое событие, а затем снова скрывает её. Игнорируется, пока включено Всегда.uНажатие Altu,Показывать по клавише AltuПоказывает полосу только пока удерживается клавиша Alt. Игнорируется, пока включено Всегда.u Всегдаu!Показывать всегдаu,Оставляет полосу на экране постоянно; она никогда не исчезает. Имеет приоритет над обоими переключателями выше, которые становятся серыми, пока эта опция включена.u РежимuРежим полосыuПереключает между двумя полосами, описанными выше. Вступает в силу при следующем появлении полосы.uМасштабuМасштаб полосыuСтандартный: обычный размер полосы. Большой: показывает её крупнее, для удобного чтения на расстоянии.uОриентацияu!Ориентация полосыuHГоризонтальная -- исходное расположение полосы. Вертикальная показывает её стоящей, с размерами для размещения рядом с миникартой. Вступает в силу при следующем появлении полосы.uПривязкаuПривязка полосыuОт какой точки отсчитываются счётчики позиции ниже. Фиксированная: встроенное место полосы, выбираемое автоматически по ориентации -- горизонтальная располагается по центру нижнего края экрана, над журналом повреждений; вертикальная располагается рядом с миникартой, у её нижнего левого угла, в соответствии с текущим размером миникарты. Свободная: позиция без привязки, задаётся автоматически при перетаскивании полосы или изменении счётчика. В режиме Фиксированная позиция заблокирована; перетаскивание и счётчики ниже работают только в режиме Свободная.uВключеноuПоказывает полосу процентиля отметок классности в ангаре на выбранной машине. Снимите галочку, чтобы скрыть.uВиджет в боюuПоказывает наложение отметок классности в реальном времени в бою. Снимите галочку, чтобы скрыть его и отключить параметры ниже.uПоказывает боевое наложение только пока удерживается клавиша Alt. Когда выключено, наложение показывается постоянно.u:Строка засчитанного содействияu+Засчитанное содействиеu.Добавляет в наложение боя третью строку с вашим засчитанным содействием: большее из содействия гусеницами, разведкой или оглушением, со значком для преобладающего.uПолоса прогрессаuПоказывает полосу в центре экрана во время боя, затем она исчезает сама. Удерживайте Alt, чтобы показать её в любой момент. Выберите ниже, какую полосу. Эффективность урона: показывает ваш урон в этом бою относительно требований отметок 65 / 85 / 95 / 100 %. Скользящее среднее: показывает, где находится ваш прогнозируемый средний урон между имеющейся отметкой и требованием следующей.uПереходыuПереходы полосыujПолоса появляется и исчезает с плавным затуханием и сдвигом. Снимите эту галочку, чтобы любое появление было мгновенным, либо отключите только один переключатель ниже. События отвечают за реакцию полосы на то, что происходит в бою; Нажатие Alt отвечает за её вызов клавишей Alt, как в самом интерфейсе игры, который при Alt ничего не анимирует.u*Длительность показа (с)u%Длительность показаu_Сколько секунд полоса остаётся на экране после того, как её вызвало событие. Пока удерживается Alt, она остаётся на экране независимо от этого значения. Появление и исчезновение не учитываются.uРасположениеuПозиция виджетаuCtrl+перетаскивание перемещает виджет ангара (удерживайте Shift, чтобы зафиксировать по одной оси). Счётчики ниже показывают закреплённую позицию верхнего левого угла в пикселях; 0 / 0 означает стандартную позицию в правом нижнем углу. Используйте сброс мода, чтобы вернуть значение по умолчанию.uПозицияuСчётчики позицииuОба счётчика ниже применяются немедленно, без необходимости перетаскивать виджет.u+Горизонтальная (левый X)u*Позиция по горизонталиuРасстояние закреплённого виджета от левого края экрана в пикселях. 0 восстанавливает автоматическую позицию в правом нижнем углу.u+Вертикальная (верхний Y)u&Позиция по вертикалиuРасстояние закреплённого виджета от верхнего края экрана в пикселях. 0 восстанавливает автоматическую позицию в правом нижнем углу.u%Позиция полосы в боюuВ бою удерживайте Ctrl и перетащите полосу, чтобы переместить её. Счётчики ниже показывают её закреплённую позицию в пикселях от верхнего левого угла экрана; 0 / 0 означает стандартную позицию по центру. Используйте сброс мода, чтобы вернуть значение по умолчанию.u*Следовать за карусельюuКогда включено, перетащенный виджет продолжает смещаться по вертикали вместе с каруселью техники (один / два ряда), чтобы не перекрывать её. Когда выключено, закреплённый виджет остаётся на месте независимо от карусели.u&Клавиша смены режимаu!Смена режима в боюuКлавиша, которую вы нажимаете в бою, чтобы переключить режим полосы прогресса этой машины между Эффективностью урона и Скользящим средним. Мод запоминает выбор для каждой машины. После переключения полоса перезагружается и появляется снова через несколько секунд. По умолчанию: K.uBАвтоматическое переключение режимаuКогда прогресс отметок машины перед боем достигает этого процента, режим полосы переключается автоматически, так же как клавишей переключения выше. Срабатывает только один раз на машину. 100% отключает эту функцию.uВіджет в ангаріu%Бойовий калькуляторuПрогрес у боюu Подіїu(Показувати за подіямиuПоказує смугу самостійно, щойно в бою стається відстежувана подія, а потім знову ховає її. Ігнорується, поки увімкнено Завжди.uНатискання Altu,Показувати по клавіші AltuПоказує смугу лише поки утримується клавіша Alt. Ігнорується, поки увімкнено Завжди.u Завждиu!Показувати завждиuЗалишає смугу на екрані постійно; вона ніколи не зникає. Має пріоритет над обома перемикачами вище, які стають сірими, поки цей увімкнено.uРежим смугиuПеремикає між двома смугами, описаними вище. Набуває чинності під час наступної появи смуги.uМасштаб смугиuСтандартний: звичайний розмір смуги. Великий: показує її більшою, для зручного читання на відстані.uОрієнтаціяuОрієнтація смугиuFГоризонтальна -- початкове розташування смуги. Вертикальна показує її вертикально, з розміром для розміщення поруч із мінікартою. Набуває чинності під час наступної появи смуги.uПрив'язкаuПрив'язка смугиuВід якої точки відраховуються лічильники позиції нижче. Фіксована: вбудоване місце смуги, обране автоматично залежно від орієнтації -- горизонтальна розташовується по центру нижнього краю екрана, над журналом ушкоджень; вертикальна розташовується поруч із мінікартою, біля її нижнього лівого кута, відповідно до поточного розміру мінікарти. Вільна: позиція без прив'язки, встановлюється автоматично після перетягування смуги чи зміни лічильника. У режимі Фіксована позиція заблокована; перетягування і лічильники нижче працюють лише в режимі Вільна.uУвімкненоuПоказує смугу процентиля позначок класності в ангарі на вибраній машині. Зніміть позначку, щоб сховати.uВіджет у боюuПоказує накладання позначок класності в реальному часі в бою. Зніміть позначку, щоб сховати його та вимкнути параметри нижче.uПоказує бойове накладання лише поки утримується клавіша Alt. Коли вимкнено, накладання показується постійно.u2Рядок зарахованої допомогиu%Зарахована допомогаuДодає третій рядок до накладання в бою: показує зараховану допомогу, більше з допомоги гусеницями, засвітом чи оглушенням, з піктограмою відповідного типу.uСмуга прогресуuaПоказує смугу в центрі екрана під час бою, потім вона зникає сама. Утримуйте Alt, щоб показати її будь-коли. Виберіть нижче, яку смугу. Ефективність шкоди: показує вашу шкоду в цьому бою відносно вимог позначок 65 / 85 / 95 / 100 %. Ковзне середнє: показує, де перебуває ваша прогнозована середня шкода між наявною позначкою та вимогою наступної.uПереходиuПереходи смугиuLСмуга з'являється та зникає з плавним затуханням і зсувом. Зніміть цю позначку, щоб будь-яка поява була миттєвою, або вимкніть лише один перемикач нижче. Події відповідають за реакцію смуги на те, що відбувається в бою; Натискання Alt відповідає за її виклик клавішею Alt, як в інтерфейсі самої гри, який при Alt нічого не анімує.u&Тривалість показу (с)u!Тривалість показуu]Скільки секунд смуга залишається на екрані після того, як її викликала подія. Поки утримується Alt, вона залишається на екрані незалежно від цього значення. Поява та зникнення не враховуються.uРозташуванняuПозиція віджетаuCtrl+перетягування переміщує віджет ангара (утримуйте Shift, щоб зафіксувати за однією віссю). Лічильники нижче показують закріплену позицію верхнього лівого кута в пікселях; 0 / 0 означає стандартну позицію в правому нижньому куті. Використайте скидання мода, щоб повернути значення за замовчуванням.uПозиціяu#Лічильники позиціїuОбидва лічильники нижче застосовуються негайно, без потреби перетягувати віджет.u)Горизонтальна (лівий X)u*Позиція по горизонталіuВідстань закріпленого віджета від лівого краю екрана в пікселях. 0 відновлює автоматичну позицію в правому нижньому куті.u)Вертикальна (верхній Y)u&Позиція по вертикаліuВідстань закріпленого віджета від верхнього краю екрана в пікселях. 0 відновлює автоматичну позицію в правому нижньому куті.u#Позиція смуги в боюuУ бою утримуйте Ctrl і перетягніть смугу, щоб перемістити її. Лічильники нижче показують її закріплену позицію в пікселях від верхнього лівого кута екрана; 0 / 0 означає стандартну позицію по центру. Використайте скидання мода, щоб повернути значення за замовчуванням.u*Слідувати за каруселлюuКоли увімкнено, перетягнутий віджет продовжує зміщуватися по вертикалі разом із каруселлю техніки (один / два ряди), щоб ніколи її не перекривати. Коли вимкнено, закріплений віджет залишається на місці незалежно від каруселі.u&Клавіша зміни режимуu!Зміна режиму в боюuКлавіша, яку ви натискаєте в бою, щоб перемкнути режим смуги прогресу цієї машини між Ефективністю шкоди та Ковзним середнім. Мод запам'ятовує вибір для кожної машини. Після перемикання смуга перезавантажується і з'являється знову через кілька секунд. За замовчуванням: K.u:Автоматичне перемикання режимуuoКоли прогрес позначок машини перед боєм досягає цього відсотка, режим смуги перемикається автоматично, так само як клавішею перемикання вище. Спрацьовує лише один раз на машину. 100% вимикає цю функцію.uGarázs-widgetuCsata-kalkulátoruHaladás a csatábanu EseményekuMegjelenítés eseményekreuMagától megjeleníti a sávot, amint a csatában egy figyelt esemény történik, majd újra eltünteti. Figyelmen kívül marad, amíg a Mindig be van kapcsolva.uAlt lenyomásau"Megjelenítés az Alt billentyűreuCsak az Alt billentyű nyomva tartása közben jeleníti meg a sávot. Figyelmen kívül marad, amíg a Mindig be van kapcsolva.uMindiguMindig megjelenítésuVégig a képernyőn tartja a sávot; sosem tűnik el. Felülbírálja a fenti két kapcsolót, amelyek eközben szürkén jelennek meg.uMódu Sáv módjau[Váltás a fent leírt két sáv között. A sáv következő megjelenésekor lép életbe.u Méretezésu Sáv méreteu}Alapértelmezett: a sáv normál mérete. Nagy: nagyobb méretben jeleníti meg, hogy távolról is könnyebb legyen olvasni.u TájolásuSáv tájolásauA Vízszintes a sáv eredeti elrendezése. A Függőleges állva jeleníti meg, a kistérkép mellé illő mérettel. A sáv következő megjelenésekor lép életbe.u IgazításuSáv igazításau`Melyik horgonyponthoz képest tolódnak el az alábbi pozíció-számlálók. Rögzített: a sáv beépített helye, automatikusan a tájolás alapján kiválasztva -- vízszintesen a képernyő alján középre igazítva, a sérülésnapló fölött jelenik meg; függőlegesen a kistérkép mellett, annak bal alsó sarkánál, a kistérkép aktuális méretéhez igazodva. Szabad: nem rögzített pozíció, automatikusan beáll, amint elhúzod a sávot vagy módosítasz egy számlálót. Rögzített módban a pozíció zárolva van; a húzás és az alábbi számlálók csak Szabad módban működnek.u EngedélyezveuMegjeleníti a kiválósági jelek percentilis sávját a garázsban, a kiválasztott járművön. Vedd ki a pipát az elrejtéshez.u Csata-widgetuMegjeleníti az élő kiválósági jelek átfedést a csatában. Vedd ki a pipát az elrejtéshez és az alábbi beállítások letiltásához.uCsak az Alt billentyű nyomva tartása közben jeleníti meg a csataátfedést. Ha ki van kapcsolva, az átfedés mindig látható.uBeszámított segítés sorauBeszámított segítésuEgy harmadik sort ad a csataátfedéshez, amely a beszámított segítésedet mutatja: a lánctalpas, felderítő vagy kábító segítés közül a nagyobbat, a vezető típus ikonjával.uHaladási sávuSávot jelenít meg a képernyő közepén játék közben, majd magától eltűnik. Tartsd nyomva az Altot, hogy bármikor előhívd. Alább válaszd ki, melyik sávot. Sebzéshatékonyság: a mostani csatában elért sebzésedet a 65 / 85 / 95 / 100 %-os jelek követelményeihez méri. Mozgóátlag: megmutatja, hol áll a várható átlagsebzésed a birtokolt jel és a következő jel követelménye között.u ÁtmenetekuA sáv átmeneteiuA sáv elhalványulva és elcsúszva jelenik meg és tűnik el. Vedd ki innen a pipát, hogy minden megjelenés azonnali legyen, vagy kapcsold ki csak az egyik alábbi váltót. Az Események a sávnak a csatában történtekre adott reakciójára vonatkozik; az Alt lenyomása az Alt billentyűvel való előhívásra, ahogy a játék saját felülete is teszi, amely Altra nem animál semmit.uMegjelenítés hossza (s)uMegjelenítés hosszauMeddig marad a sáv a képernyőn, másodpercben, miután egy esemény előhívta. Az Alt nyomva tartása közben ettől függetlenül látható marad. A be- és kihalványodás nincs beszámítva.u ElrendezésuWidget pozíciójauGCtrl+húzással mozgathatod a garázs-widgetet (tartsd nyomva a Shiftet az egy tengelyre rögzítéshez). Az alábbi számlálók a rögzített bal felső pozíciót mutatják pixelben; a 0 / 0 az alapértelmezett jobb alsó pozíciót jelenti. Az alapértelmezéshez való visszatéréshez használd a mod visszaállítását.u PozícióuPozíció-számlálókuPAz alábbi két számláló azonnal érvénybe lép, a widget húzása nélkül.uVízszintes (bal X)uVízszintes pozícióuA rögzített widget távolsága a képernyő bal szélétől, pixelben. A 0 visszaállítja az automatikus jobb alsó pozíciót.uFüggőleges (felső Y)uFüggőleges pozícióuA rögzített widget távolsága a képernyő felső szélétől, pixelben. A 0 visszaállítja az automatikus jobb alsó pozíciót.uCsatasáv pozíciójau9Csatában tartsd nyomva a Ctrlt, és húzd a sávot a mozgatáshoz. Az alábbi számlálók a rögzített pozíciót mutatják pixelben a képernyő bal felső sarkától; a 0 / 0 az alapértelmezett középső pozíciót jelenti. Az alapértelmezéshez való visszatéréshez használd a mod visszaállítását.uKörhinta követéseuBekapcsolva egy elhúzott widget továbbra is függőlegesen mozog a járműkörhintával (egy / két sor) együtt, hogy sose fedje azt. Kikapcsolva egy rögzített widget a körhintától függetlenül a helyén marad.uMód váltó billentyűuMód váltás csatábanu5A billentyű, amelyet csatában megnyomva válthatsz e jármű haladási sávjának módja között, Sebzéshatékonyság és Mozgóátlag közt. A mod megjegyzi az egyes járművek választását. A váltás után a sáv újratöltődik, és néhány másodperc múlva jelenik meg újra. Alapértelmezett: K.uAutomatikus mód váltásuAmikor egy jármű jelhaladása a csata előtt eléri ezt a százalékot, a sáv módja automatikusan átvált, ugyanúgy, mint a fenti váltóbillentyűvel. Csak egyszer lép életbe járművenként. A 100% kikapcsolja ezt.uGaraj widget'ıuSavaş hesaplayıcıuSavaş ilerlemesiuOlaylaruOlaylarda gösteruSavaşta izlenen bir olay gerçekleştiğinde çubuğu kendiliğinden gösterir, ardından yeniden gizler. Her zaman açıkken yok sayılır.u Alt basımıuAlt tuşuyla gösteru^Çubuğu yalnızca Alt tuşunu basılı tutarken gösterir. Her zaman açıkken yok sayılır.u Her zamanuHer zaman gösteru{Çubuğu ekranda kalıcı olarak tutar; asla kaybolmaz. Bu açıkken soluklaşan yukarıdaki iki anahtarın önüne geçer.uModu Çubuk moduumYukarıda açıklanan iki çubuk arasında geçiş yapar. Çubuğun bir sonraki görünüşünde etkili olur.uÖlçeku Çubuk boyutuufVarsayılan: çubuğun normal boyutu. Büyük: uzaktan daha kolay okumak için daha büyük gösterir.uYönelimuÇubuk yönelimiuYatay, çubuğun özgün düzenidir. Dikey, minimap'in yanına oturacak boyutta, onu ayakta gösterir. Çubuğun bir sonraki görünüşünde etkili olur.uHizalamauÇubuk hizalamasıu"Aşağıdaki konum sayaçlarının hangi çıpa noktasına göre kaydığı. Sabit: çubuğun yerleşik konumu, yönelime göre otomatik seçilir -- yatayken ekranın alt kenarının ortasında, hasar günlüğünün üstünde durur; dikeyken minimap'in yanında, sol alt köşesine yakın, minimap'in mevcut boyutuna göre durur. Serbest: sürüklendiğinde veya bir sayaç düzenlendiğinde otomatik olarak ayarlanan, çıpasız bir konum. Sabit modda konum kilitlidir; sürükleme ve aşağıdaki sayaçlar yalnızca Serbest modda çalışır.uEtkinuqSeçili araçta, garajda üstünlük işaretleri yüzdelik çubuğunu gösterir. Gizlemek için işareti kaldır.uSavaş widget'ıuSavaş sırasında canlı üstünlük işaretleri katmanını gösterir. Gizlemek ve aşağıdaki seçenekleri devre dışı bırakmak için işareti kaldır.uoSavaş katmanını yalnızca Alt tuşu basılı tutulurken gösterir. Kapalıyken katman her zaman gösterilir.uSayılan yardım satırıuSayılan yardımuSavaş katmanına, sayılan yardımını gösteren üçüncü bir satır ekler: palet, tespit veya sersemletme yardımından en yükseği, öndeki için bir simgeyle.uİlerleme çubuğuuOyun sırasında ekranın ortasında bir çubuk gösterir, sonra kendiliğinden kaybolur. Herhangi bir anda görüntülemek için Alt tuşunu basılı tut. Hangi çubuk olacağını aşağıdan seç. Hasar verimliliği: bu savaştaki hasarını 65 / 85 / 95 / 100 % işaretlerinin gereksinimlerine göre konumlandırır. Hareketli ortalama: beklenen ortalama hasarının, sahip olduğun işaret ile sonraki işaretin gereksinimi arasında nerede olduğunu gösterir.u GeçişleruÇubuğun geçişleriuxÇubuk göründüğünde ve kaybolduğunda soluklaşarak kayar. Her görünüşün anında olması için bunun işaretini kaldır, ya da aşağıdaki anahtarlardan yalnızca birini kapat. Olaylar, çubuğun savaşta olanlara verdiği tepkiyi kapsar; Alt basımı ise Alt tuşuyla çağırmayı kapsar, tıpkı Alt ile hiçbir şeyi canlandırmayan oyunun kendi arayüzü gibi.uEkranda kalma süresi (s)uEkranda kalma süresiuBir olay çubuğu çağırdıktan sonra çubuğun ekranda kaç saniye kaldığı. Alt tuşu basılı tutulduğu sürece, bu değer ne olursa olsun ekranda kalır. Giriş ve çıkış solmaları sayılmaz.u Yerleşimu Widget konumuuGaraj widget'ını taşımak için Ctrl+sürükle (bir eksene kilitlemek için Shift'i basılı tut). Aşağıdaki sayaçlar, sabitlenmiş sol üst konumu piksel cinsinden gösterir; 0 / 0 varsayılan sağ alt konumu ifade eder. Varsayılana dönmek için modun sıfırlamasını kullan.uKonumuKonum sayaçlarıuWAşağıdaki her iki sayaç da widget'ı sürüklemeye gerek kalmadan hemen uygulanır.u Yatay (sol X)u Yatay konumuwSabitlenmiş widget'ın ekranın sol kenarına uzaklığı, piksel cinsinden. 0, otomatik sağ alt konumu geri yükler.uDikey (üst Y)u Dikey konumuxSabitlenmiş widget'ın ekranın üst kenarına uzaklığı, piksel cinsinden. 0, otomatik sağ alt konumu geri yükler.uSavaştaki çubuk konumuuSavaşta Ctrl'yi basılı tut ve çubuğu taşımak için sürükle. Aşağıdaki sayaçlar sabitlenmiş konumu ekranın sol üst köşesinden piksel cinsinden gösterir; 0 / 0 varsayılan ortalanmış konumu ifade eder. Varsayılana dönmek için modun sıfırlamasını kullan.uKaruseli takip etuAçıkken, sürüklenen bir widget araç karuseliyle (tek / çift sıra) birlikte dikey olarak kaymayı sürdürür, böylece onu asla örtmez. Kapalıyken, sabitlenmiş bir widget karuselden bağımsız olarak yerinde kalır.uMod Değiştirme TuşuuSavaşta mod değiştirmeuBu aracın ilerleme çubuğu modunu Hasar verimliliği ile Hareketli ortalama arasında değiştirmek için savaşta bastığın tuş. Mod her aracın seçimini hatırlar. Değiştirdikten sonra çubuk yeniden yüklenir ve birkaç saniye sonra yeniden görünür. Varsayılan: K.uOtomatik Mod DeğiştirmeuOtomatik mod değiştirmeuBir aracın işaret ilerlemesi savaştan önce bu yüzdeye ulaştığında, çubuk modu yukarıdaki değiştirme tuşuyla aynı şekilde otomatik olarak değişir. Araç başına yalnızca bir kez tetiklenir. %100 bunu kapatır.cCsZtt}tjt|p"i}i}x(|D] }|j|||||s(RttupleR(ttableR topts((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pyt_optionss cCst|}tt}tj|p(i}i}xI|jD];\}}||k}t|j||d| ||Wx(tD] }d||d||d%sutextuoptionsu progressSizeuprogressOrientationuprogressAlignment( R RRRtitemsRt HEADER_KEYSR#t_VARIANT_OPTIONSt VARIANT_KEYt _SIZE_OPTIONSt_ORIENTATION_OPTIONSt_ALIGNMENT_OPTIONS(RR RRRRten_entryt translated((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pytbuilds   '  cCsFy&ddl}t|jp$tSWntk rAttSXdS(Ni(thelpersR tgetClientLanguageRt ExceptionR(R.((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pytclient_languages   cCs ttS(N(R-R1(((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pyt panel_textsN(u catBattleCalcu battleWidgetu battleAltKeyu countedAssistNNu catGarageu garageWidgetNu positioningufollowCarouselNu positionSubuposXuposYN(u catBattleCalcucatBattleProgressucatTransitionsucatBarPositionu catGarageu positioning(uDamage EfficiencyuMoving Average(uSchadenseffizienzuGleitender Durchschnitt(uEfficacité des dégâtsuMoyenne glissante(uEficiencia de dañou Media móvil(uEfficienza dei danniu Media mobile(uEfektywność obrażeńuŚrednia krocząca(uEfektivita poškozeníuKlouzavý průměr(u%Эффективность уронаu#Скользящее среднее(u#Ефективність шкодиuКовзне середнє(uSebzéshatékonyságu Mozgóátlag(uHasar verimliliğiuHareketli ortalama(uDefaultuLarge(uStandarduGroß(u Par défautuGrande(uPredeterminadauGrande(u PredefinitauGrande(u DomyślnauDuża(u VýchozíuVelké(uСтандартныйuБольшой(uСтандартнийuВеликий(uAlapértelmezettuNagy(u VarsayılanuBüyük(u HorizontaluVertical(u HorizontaluVertikal(u Horizontaleu Verticale(u HorizontaluVertical(u Orizzontaleu Verticale(uPoziomauPionowa(u VodorovnáuSvislá(uГоризонтальнаяuВертикальная(uГоризонтальнаuВертикальна(u Vízszintesu Függőleges(uYatayuDikey(uFixeduFree(uFestuFrei(uFixeuLibre(uFijauLibre(uFissouLibero(uStałeuSwobodne(uPevnéuVolné(uФиксированнаяuСвободная(uФіксованаu Вільна(u RögzítettuSzabad(uSabituSerbest(tmoe_calculator._compatRtmoe_calculator.adapterRRRR R RR'tVARIANT_HOTKEY_KEYt COL1_KEYSt COL2_KEYSt frozensetR%R&R(R)R*RRtFalseRR#R-R1R2(((s:res/scripts/client/moe_calculator/adapter/settings_i18n.pytIs                                                                                                                                                                                                                                                                                                                                           , PK!#f! ! ?res/scripts/client/moe_calculator/adapter/variant_overrides.pyc c@sRddlZdZd ZdZdZdZdZd Zd ZdS( iNsprogress_variant_overrides.jsoniicCs&ddlm}tjj|tS(Ni(tdata_dir(t moe_calculator.adapter.moe_wgapiRtostpathtjointOVERRIDES_FILE(R((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pyt_path scCsd}y#ddlm}|t}Wntk r<nXt|tsPiSi}x|jD]s\}}t|trqcnyt |}t |}Wnt t fk rqcnX|t krc|||res/scripts/client/moe_calculator/adapter/variant_overrides.pytloads(   cCs@ddlm}td|jD}|t|dS(Ni(t write_jsoncss3|])\}}tt|t|fVqdS(N(tstrR(t.0RR((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pys -s(RRR R R(t overridesRR((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pytsave+scCs)|dkr|Stjt||S(N(RRtgetR(tint_cdtdefault_variant((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pyt effective1s cCs6|dkrtS|dks(||kr,tS||kS(Nid(tFalseR(t thresholdtpctteffective_variantR ((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pytshould_auto_toggle8s  cCsnt}|jt||}d|}||krP|jt|dn||t|res/scripts/client/moe_calculator/adapter/variant_overrides.pyttoggleEs    (ii( RRRRRRR!R&R*(((s>res/scripts/client/moe_calculator/adapter/variant_overrides.pyts      PK!&)5res/scripts/client/moe_calculator/bridge/__init__.pyc c@sdS(N((((s4res/scripts/client/moe_calculator/bridge/__init__.pyttPK!y667res/scripts/client/moe_calculator/bridge/bar_window.pyc c@smddlmZmZmZddlmZmZmZmZm Z ddl m Z m Z ddl mZddlmZddlmZmZmZmZmZmZddlmZmZmZmZmZmZmZm Z dZ!d Z"dZ#dZ$dZ%dZ&dZ'dZ(dZ)de fdYZ*de fdYZ+de,fdYZ-dS(i(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGtLOG_PROD(t ViewSettingst ViewFlagst WindowFlagst WindowLayertPositionAnchor(tViewImplt WindowImpl(tModDynAccessor(t mod_settings(t MINIMAP_SIZEStMM_GAPtMM_TICK_OVERHANGtMM_TICK_OVERHANG_LARGEt MM_TRACK_YtMM_TRACK_Y_LARGE(tanchor_centred_reducedtanchor_minimapt anchor_offsettcursor_in_recttcursor_logicaltcursor_top_lefttfree_anchor_pointt free_top_leftiiiiiicCsmtdtt|t|}tdtt|t|}||fdkrcd}n||fS(Nii(ii(tmaxtmintint(txtytmax_xtmax_ytcxtcy((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_clamp_to_extent{s $$ cCs6yddl}|jjSWntk r1dSXdS(Ni(tGUItmcursortpositiont ExceptiontNone(R$((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_cursor_positions   cCsAyddlm}|jSWntk r<ttdSXdS(Ni(tbattle_adapteri(tmoe_calculator.adapterR*tread_minimap_size_indexR'tlenR (R*((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_minimap_size_indexs  cCsntj}yIddlm}m}|j|j}|sDdS|j||SWnt k ridSXdS(Ni(R*tvariant_overrides( R tprogress_bar_variantR+R*R/t_player_vehicle_int_cdt_player_vehicle_descrR(t effectiveR'(tdefaultR*R/tint_cd((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_effective_variants  cCs3yddl}|jSWntk r.dSXdS(Ni(R$tscreenResolutionR'R((R$((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_screen_resolutions   t_BarViewcBs)eZdZedZdZRS(cCs)tt|jt|tj|dS(N(tsuperR9t__init__RRtVIEW(tselft layout_idt view_model((s6res/scripts/client/moe_calculator/bridge/bar_window.pyR;scCstt|jS(N(R:R9t getViewModel(R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt viewModelscOsVtt|j||yddlm}|jWntk rQtnXdS(Ni(t battle_bridge(R:R9t _onLoadingtmoe_calculator.bridgeRBtrefreshR'R(R=targstkwargsRB((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRCs  (t__name__t __module__R;tpropertyRARC(((s6res/scripts/client/moe_calculator/bridge/bar_window.pyR9s t _BarWindowcBs,eZdZdZdZdZRS(cCs>tt|jtjd|dtj||_||_dS(Ntcontenttlayer( R:RKR;RtTOOLTIPRtWINDOWt_placet_host(R=RLtplacethost((s6res/scripts/client/moe_calculator/bridge/bar_window.pyR;s cCs3|jdt|j|j7_|j|dS(Ntfocus(tshowtFalset onSizeChangedt_on_size_changedRP(R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_onReadyscCs~t|j_|jj}|j|| rz|jjrzyddlm}|jWqztk rvt qzXndS(Ni(RB( tTrueRQt_sizedt has_placedRPRDRBRER'R(R=t _unique_idt_widtht_heightt was_placedRB((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRX&s   cCs5y|j|j8_Wntk r0tnXdS(N(RWRXR'R(R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pytdetachFs (RHRIR;RYRXRa(((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRKs%  tBarHostcBseZeeddZdZdZdZdZdZ dZ ddZ dZ d Z d Zd Zd Zd ZRS(cCs||_||_||_||_||_||_||_||_| |_| |_ | |_ | |_ | |_ t ||_d|_d|_d|_t|_t|_t|_d|_d|_t|_dS(N(titem_idt _vm_factoryt_y_fract_x_offt_y_shiftt_y_shift_larget _mm_track_xt_mm_track_x_larget_mm_gap_bottomt_mm_gapt _mm_gap_larget_tagt_variantR t _layout_idR(t_activet _extent_cachet _last_goodRVR[t_reject_loggedt _place_loggedt_grabt _drag_post _declined(R=Rct vm_factoryty_fractx_offty_shiftt y_shift_larget mm_track_xtmm_track_x_larget mm_gap_bottomttagtmm_gapt mm_gap_largetvariant((s6res/scripts/client/moe_calculator/bridge/bar_window.pyR;}s.                    c Cstjtjk}tjtjk}tj}tjtj}} |tjkom|| fdk} | rtj tj krt d||j | S||||f} t || f| |S|rT|rtnt} |r|jn|j} |rtnt}|r|jn|j}t||| |tt||j| }n-t||||j|ru|jn|j}t |||j | S(Ni(ii(ii(R tprogress_bar_sizetPROGRESS_SIZE_LARGEtprogress_bar_orientationtPROGRESS_ORIENT_VERTICALtprogress_bar_alignmentt bar_pos_xt bar_pos_ytPROGRESS_ALIGN_FREEtprogress_bar_pos_frametPOS_FRAME_LEGACYRRfRRRRjRiRRRmRlRR R.RkRReRhRg(R=RR tspace_xtspace_ytlargetverticalt alignmenttoff_xtoff_ytis_freetsurfacetoverhangtedge_xtedge_ytgaptbase((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_resolves,9   ! cCsG|jdkr@|jttdtjdtj|j|_n|jS(NtxAnchortyAnchor(RrR(tmovet_FARRtLEFTtTOPR&(R=twindow((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_extent s "cCse|j|\}}y1|j\}}|t||t|fSWntk r`||fSXdS(N(RtsizeRR'(R=RRR twidththeight((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_spaces " c Cs*yd|_|j|\}}|j|\}}|j||||\}}t||||\}}|j||dtjdtj |j \}} ||||f} t j } t j t j} } t||tkrIt| |tkrI||f|_|jst|_td|j||| fqnA|jst|_td|j|||| | | | | f n|j||| d| dWnztk r%tyG|jdk r|j\}}|j||dtjdtj nWq&tk r!tq&XnXdS(NRRs5%s placement confirmed: applied=(%d, %d) alignment=%ds\%s placement rejected: target=(%d, %d) applied=(%d, %d) surface=%s alignment=%d off=(%d, %d)ii(R(RrRRRR#RRRRR&R RRRtabst_PLACE_TOLERANCE_PXRsRuRZRRnRtt _materialiseR'R(R=RRR RRRRt applied_xt applied_yRRRRtlxtly((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRP3s@, "     " ) cCs |jdk S(N(RsR((R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pyR\s c Cs|js dSt}|dk r5||jkr5dStjtjkrNdStjtjf}tj tj k}|dkr| rdStj tj k}t ||f||f|\} } tj| | dtdS(Nitpersist(ii(R[R6R(RoR RRRRRRRRRtset_bar_positionRZ( R=RRt surface_wt surface_hR3tpostlegacyRtaxtay((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRs    $cCs|jdkrdSyy|dkr|j}d|_d|_t|_|dk rtjtjkrtj |d|ddt ndStjtjkrdS|dkrt|_n |jrdS|jd}|j }|j |\}}|j |\}} |dkr"t}nt} |dksF|jdkrt|| || } | dkrkdSt| |||| |fst |_dS|d| d|d| df|_d|_dSt|| || |jd|jd}|dkrdS|j|d|ddtjdtjtjtjk} t|||| |f| } | |_tj | d| ddtWntk rtnXdS(NtendiiRtstartRR(RqR(RwRvRVRxR RRRRZR&RRR)R8RRRRRRRRRRR'R(R=tphasetcursorRRtoriginRR RRtscreentspotRtapos((s6res/scripts/client/moe_calculator/bridge/bar_window.pytdrags^7      !           '  *    " cCs+|jdkrdS|j|jddS(Ni(RqR(RP(R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pytapply_positionZscCs7|jdks|jrdS|j|jddS(Ni(RqR(R\RP(R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt ensure_placedds cCs|jdkrtS|j\}}yIt|ddtkrAtSt|ddtkr]tS|jdkSWntk rtSXdS(Nt windowStatust viewStatus(RqR(RVtgetattrt _DEAD_STATUSRZRAR'(R=Rtview((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt_is_deadqs  cCs4|jdk rC|js&|jdStd|jd|_ny|j}|dksj|dkrtd|j|jfdSt|_t|_ t|_ d|_ t ||j }t||j|}||f|_|jtd|j|f|SWn"tk r/td|_dSXdS(Nis0%s handle destroyed by the engine -- re-mountingisc%s res_map layout '%s' unresolved -- a one-time client restart is needed for OpenWG to register it.s;%s window opened (layoutID=%s, layer=WINDOW, content-sized)(RqR(RRRnRpRcRVR[RtRuRsR9RdRKRPtloadR'R(R=tlayoutRR((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt open_windows4           cCsq|jdkrdS|jd}d|_y)|j|jtd|jWntk rltnXdS(Nis%s window destroyed(RqR(RatdestroyRRnR'R(R=R((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt close_windows     cCs|jdkrdS|jdS(Ni(RqR((R=((s6res/scripts/client/moe_calculator/bridge/bar_window.pyt active_viewsN(RHRIR R(R;RRRRPR\RRRRRRRR(((s6res/scripts/client/moe_calculator/bridge/bar_window.pyRbOs01 \   i 0  8 Ni(ii(ii(.tmoe_calculator._compatRRRtframeworks.wulfRRRRRt gui.impl.pubRR topenwg_gamefaceR RDR tmoe_calculator.domain.constantsR R RRRRt!moe_calculator.domain.positioningRRRRRRRRRRt_FALLBACK_SURFACE_SIZERR#R)R.R6R8R9RKtobjectRb(((s6res/scripts/client/moe_calculator/bridge/bar_window.pytJs$(.:      ^PK!'CRCR:res/scripts/client/moe_calculator/bridge/battle_bridge.pyc c @snddlZddlmZmZmZddlmZddlmZddlmZddlm Z ddlm Z ddl m Z m Z mZmZmZmZmZmZmZmZdd lmZmZdd lmZdd lmZdd lmZdd lmZddlmZe a!e a"e a#da%da&e a'e(Z)e a*da+e a,da-da.e a/e a0dZ1da2dZ3dZ4dZ5dZ6dZ7dZ8dZ9dZ:dZ;dZ<dZ=dZ>dZ?dZ@e dZAdd ZBd!ZCd"ZDd#ZEd$ZFd%ZGd&ZHd'ZId(eDd)e6fd*eDd+e<fd,eDd-e7fd.eEd/e8fd0eFd1e9fd2eGd3e:fd4eGd5e;fd6eHd7e=fd8eId9e>ff ZJd:ZKd;ZLd<ZMd=ZNd>ZOd?ZPd@ZQdAZRdBZSdCZTdDZUdEZVdFZWdGZXdS(HiN(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGtLOG_PROD(tbattle_adapter(t battle_input(t moe_wgapi(t sample_log(tvariant_overrides( tbuild_battle_modeltbattle_bar_visibletbattles_to_axis_hitefficiency_bandtefficiency_bar_xtefficiency_stopstewma_project_rawt mark_axistmarks_from_percentiletprogress_axis_lo(tEFFICIENCY_WIDE_THRESHOLDtEWMA_K(tefficiency_panel_wide(t battle_view(tefficiency_view(t mod_settings(t progress_viewicCstotjtjkS(N(t _ctrl_heldRtprogress_bar_alignmenttPROGRESS_ALIGN_FREE(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_ctrl_relevantscCstjtjkS(N(Rtprogress_bar_orientationtPROGRESS_ORIENT_VERTICAL(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt _bar_verticals cCsgtj}tjttj}tjtf|oE|tjkt f|o]|tj kt ffS(N( Rtprogress_bar_enabledRt effectivet_current_int_cdtprogress_bar_varianttbattle_enabledRtPROGRESS_VARIANT_MOVING_AVERAGERtPROGRESS_VARIANT_EFFICIENCYR(tbar_ontvariant((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt _window_gatess cCs|dkrdSyhtj}tj|}tj}tj||}tj||||rwtj ||nWnt k rt nXdS(N( tNoneRtprogress_auto_toggle_thresholdRtpre_percentileR#RR!tshould_auto_togglettogglet ExceptionR(tint_cdt thresholdtpcttdefault_variantR!((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_maybe_auto_toggles    cOsytatj}|r*tj|ndattta t d7a da t j t}td|DsdSx'|D]\}}|r|jqqWttjtWntk rtnXdS(Nicss|]\}}|VqdS(N((t.0tenabledt_module((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pys s(tTruet _in_battleRt_player_vehicle_descrt_player_vehicle_int_cdR*R"R4Rt_bar_orientationt _battle_epocht _last_widet_open_overlaystclearR)tanyt open_windowtinstall_all_listenersRtstarttrefreshR/R(targstkwargstdescrtgatesR6tmodule((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_mount_refreshs(         cOs*y tWntk r%tnXdS(N(RER/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_arena_period_changeds  cOs*y tWntk r%tnXdS(N(t_schedule_refreshR/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_efficiency_updateds  cOs*y tWntk r%tnXdS(N(RMR/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_summary_feedbacks  cOs*y tWntk r%tnXdS(N(RER/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_observed_vehicle_changeds  cOstat||dS(N(R8t_diedRP(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_post_mortem_switched%scOsTy5tadattjtjtjWnt k rOt nXdS(N( tFalseR9R*R"t_flush_predictionRt close_windowRRR/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt _on_teardown.s   cOsAy"tjtjtjWntk r<tnXdS(N(Rtapply_positionRRR/R(RFRG((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_scale_changed@s    csyddlm}m}|j|j|j|jf}dks_tfd|Drlt j ndks|j krt j t j nWnUtk rty"t j t j t j Wqtk rtqXnXdS(Ni(t DAMAGE_LOGtGAMEc3s|]}|kVqdS(N((R5tf(tdiff(s9res/scripts/client/moe_calculator/bridge/battle_bridge.pys ]s(t0account_helpers.settings_core.settings_constantsRYRZt TOTAL_DAMAGEtBLOCKED_DAMAGEt ASSIST_DAMAGEt ASSIST_STUNR*RARRWt MINIMAP_SIZERRR/R(R\RYRZtflags((R\s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_settings_changedNs"  (      cCs4ytdtWntk r/tnXdS(Ns#[moe-battle] table ready -> refresh(RRER/R(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_moe_data_readyls    cCsyat|ddpi}t|dd}|jdrLtj|n tj|tWntk r{tnXdS(Ntctxt eventTypetisDown( tgetattrR*tgetR?taddtdiscardRMR/R(teventRftkey((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_scoreboard_toggledvs   cCsBy#t|at|atWntk r=tnXdS(N(tboolt _alt_heldRRER/R(talt_downt ctrl_down((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt _set_alt_helds     cCsCy$tj||tj||Wntk r>tnXdS(N(RtdragRR/R(tphasetcursor((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_drags  cCsJts dSy!tjttjtWntk rEtnXdS(N(R"RR.RR#tapply_settingsR/R(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_on_variant_toggles  cCsddlm}|S(Ni(tg_playerEvents(t PlayerEventsR{(R{((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_player_events_holderscCs tjS(N(Rt_efficiency_ctrl(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_efficiency_holderscCs tjS(N(Rt_feedback_ctrl(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_feedback_holderscCs)tj}|r%|jr%|jjSdS(N(Rt_session_providertsharedt vehicleStateR*(tsp((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_vehicle_state_holders cCs#tj}|dk r|jSdS(N(Rt_settings_coreR*tinterfaceScale(tsc((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_interface_scale_holders cCs tjS(N(RR(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_settings_core_holderss avatar readyt onAvatarReadysavatar teardowntonAvatarBecomeNonPlayers arena periodtonArenaPeriodChanget efficiencytonTotalEfficiencyUpdatedssummary feedbacktonPlayerSummaryFeedbackReceivedsobserved vehicletonVehicleControllingt postmortemtonPostMortemSwitchedsinterface scaletonScaleChangedtsettingstonSettingsChangedcCsyr|}|dkrdSt||d}|dk rq||krq||7}t|||td|nWntk rtnXdS(Ns"[moe-battle] %s listener (re)armed(R*RitsetattrRR/R(tlabelt get_holdertattrthandlertholderRm((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_arms    cCsxtD]}t|qWtsVytjttaWqVtk rRtqVXnt t j t t t jtjtdS(N(t _LISTENERSRt_data_listener_armedRtadd_ready_listenerReR8R/Rt_arm_overlay_listenersRtinstall_alt_key_listenerRtRxt set_hotkeyRtprogress_variant_hotkeyRz(tentry((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyRCs    cCstr dSyddlm}m}ddlm}|j|j|j|j f}x'|D]}|j |t d|j qXWt atdWntk rtnXdS(Ni(t g_eventBustEVENT_BUS_SCOPE(t GameEventtscopes,[moe-battle] scoreboard hide listeners armed(t_overlay_listeners_armedt gui.sharedRRtgui.shared.eventsRt FULL_STATStFULL_STATS_QUEST_PROGRESStFULL_STATS_PERSONAL_RESERVESt EVENT_STATSt addListenerRotBATTLER8RR/R(RRRteventstev((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyRs   cCsotr dStaytjdtWnDtk rjtaty tWqktk rftqkXnXdS(Ng( t_refresh_pendingR8tBigWorldtcallbackt_do_scheduled_refreshR/RSRRE(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyRM2s   cCs7tay tWntk r+tnXtdS(N(RSRRER/Rt_maybe_replace_for_width(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyRCs    cCs`yAttjtjt}|tkr@|atjnWntk r[t nXdS(N( RRtread_damage_log_summary_flagstread_efficiency_totalsRR>RRWR/R(twide((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyRMs      cCsbtr dSy9|jrB|j rB|jrBtj|jtanWntk r]tnXdS(N( t_battle_recordedt has_vehiclet is_spectatingtvehicle_int_cdRton_battle_playedR8R/R(tsnap((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_record_played_tankds  cCs\y=|jr<|jr<||fa|js<||faq<nWntk rWtnXdS(N(RRt_last_final_pushRt_last_predictionR/R(Rtmodel((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyt_note_predictionvs   cCst}t}t}dadata|dkr4dS|\}}y5it|jpUdd6ttd6t |j pxid6t|j pdd6t|j pdd6t t|dtd6t|jpdd 6tt|d dpdd 6tt|d dpdd 6t|jp'dd 6t|jp=dd 6t|jpSdd6t|jpidd6t|jpdd6t|jpdd6t|jpdd6t|jpdd6t |jd6t |jd6}|dk rWt|djp d|dkrWt|djp-d|dR9R"R=RqRRR<RR)R4RKRLRNRORPRRRVRXRdReRoRtRxRzR}RRRRRRRRCRRMRRRRRTRERRRRy(((s9res/scripts/client/moe_calculator/bridge/battle_bridge.pyts F        ,                        ; 6  [ PPK!Ǿ  8res/scripts/client/moe_calculator/bridge/battle_view.pyc c@s'ddlmZmZddlmZmZmZmZmZddl m Z m Z ddl m Z ddlmZddlmZmZmZmZddlmZmZmZmZdZde fd YZdZd e fd YZdZdZda!dZ"dZ#dZ$dS(i(tLOG_CURRENT_EXCEPTIONt LOG_DEBUG(t ViewSettingst ViewFlagst WindowFlagst WindowLayertPositionAnchor(tViewImplt WindowImpl(tModDynAccessor(t BattleMoEVM(tBATTLE_ANCHOR_XtBATTLE_ANCHOR_X_RAISEDtBATTLE_ANCHOR_X_SHIFTtEFFICIENCY_WIDE_THRESHOLD(tanchor_top_lefttbattle_y_anchortdamage_log_summary_hiddentefficiency_panel_widet MoEBattleViewcBs5eZeeZdZedZdZRS(cCs8t|jtjt}tt|j|dS(N(Rt _layoutIDRtVIEWR tsuperRt__init__(tselftsettings((s7res/scripts/client/moe_calculator/bridge/battle_view.pyR=scCstt|jS(N(RRt getViewModel(R((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt viewModelAscOsVtt|j||yddlm}|jWntk rQtnXdS(Ni(t battle_bridge(RRt _onLoadingtmoe_calculator.bridgeRtrefresht ExceptionR(RtargstkwargsR((s7res/scripts/client/moe_calculator/bridge/battle_view.pyREs  ( t__name__t __module__R tRES_MAP_ITEM_IDRRtpropertyRR(((s7res/scripts/client/moe_calculator/bridge/battle_view.pyR6s  iitMoEBattleWindowcBseZdZdZRS(cCs,tt|jtjd|dtjdS(Ntcontenttlayer(RR'RRtWINDOWR(RR(((s7res/scripts/client/moe_calculator/bridge/battle_view.pyRsscCs|jdtt|dS(Ntfocus(tshowtFalset_place(R((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt_onReadyws(R#R$RR/(((s7res/scripts/client/moe_calculator/bridge/battle_view.pyR'_s c Cs yddlm}|j}t|}|r7tnt}t||j}| r~t||j t r~|t 7}n|j t t dtjdtj|j\}}t||||\}} |j || dtjdtjWntk rtnXdS(Ni(tbattle_adaptertxAnchortyAnchor(tmoe_calculator.adapterR0tread_damage_log_summary_flagsRR R Rtread_is_epic_battleRtread_efficiency_totalsRR tmovet_FARRtLEFTtTOPtpositionRR R( twindowR0tflagstraisedt x_from_leftt y_from_bottomtmax_xtmax_ytxty((s7res/scripts/client/moe_calculator/bridge/battle_view.pyR.}s    "& cCs"tdkrdSttddS(Ni(t_activetNoneR.(((s7res/scripts/client/moe_calculator/bridge/battle_view.pytapply_positions cCstdk rtdSywtj}|dks;|dkrMtdtdSt}t|}||fa|jtd||SWntk rt dadSXdS(Niism[moe-battle] res_map layout '%s' unresolved -- a one-time client restart is needed for OpenWG to register it.sM[moe-battle] overlay window opened (layoutID=%s, layer=WINDOW, content-sized)( RERFRRRR%R'tloadR R(tlayouttviewR<((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt open_windows&       cCsWtdkrdStd}day|jtdWntk rRtnXdS(Nis%[moe-battle] overlay window destroyed(RERFtdestroyRR R(R<((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt close_windows    cCstdkrdStdS(Ni(RERF(((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt active_viewsNi(%tmoe_calculator._compatRRtframeworks.wulfRRRRRt gui.impl.pubRRtopenwg_gamefaceR t!moe_calculator.bridge.view_modelsR tmoe_calculator.domain.constantsR R R Rt!moe_calculator.domain.positioningRRRRR%RR8R'R.RGRFRERKRMRN(((s7res/scripts/client/moe_calculator/bridge/battle_view.pyt%s (""& $   PK!vX<res/scripts/client/moe_calculator/bridge/efficiency_view.pyc c@sddlmZddlmZddlmZddlmZmZm Z m Z m Z m Z m Z mZmZdZeeeeee e eee dde de d ej ZejZejZejZejZejZejZejZd S( i(t mod_settings(tBarHost(t EfficiencyVM( tEFFICIENCY_ANCHOR_X_OFFSETtEFFICIENCY_ANCHOR_Y_FRACtEFFICIENCY_ANCHOR_Y_SHIFTtEFFICIENCY_ANCHOR_Y_SHIFT_LARGEtEFFICIENCY_MM_GAPtEFFICIENCY_MM_GAP_LARGEtEFFICIENCY_MM_GAP_BOTTOMtEFFICIENCY_MM_TRACK_XtEFFICIENCY_MM_TRACK_X_LARGEtMoEEfficiencyViews [moe-eff]tmm_gapt mm_gap_largetvariantN(tmoe_calculator.bridgeRt moe_calculator.bridge.bar_windowRt!moe_calculator.bridge.view_modelsRtmoe_calculator.domain.constantsRRRRRRR R R tRES_MAP_ITEM_IDtPROGRESS_VARIANT_EFFICIENCYt_hostt open_windowt close_windowt active_viewtapply_positiontdragt has_placedt ensure_placed(((s;res/scripts/client/moe_calculator/bridge/efficiency_view.pyt s"@            PK!;՚I:I:<res/scripts/client/moe_calculator/bridge/gameface_bridge.pyc c@sddlZddlZddlmZddlmZddlmZddlm Z m Z m Z ddl m Z ddl mZddl mZdd lmZmZdd lmZmZmZdd lmZmZdd lmZdd lmZmZ ddl!Z!dZ"dZ#dZ$dZ%da'dZ(da)da*ga+iZ,da-da.e/a0e/a1dZ2dZ3dZ4dZ5dZ6dZ7dZ8dZ9dZ:dZ;dZ<dZ=d Z>d!Z?d"e;d#e2fd$e<d%e3fd&e=d'e4fd(e>d)e6fd*e?d+e5ffZ@d,ZAd-ZBd.ZCd/ZDd0ZEd1ZFd2ZGd3ZHd4ZId5ZJd6ZKd7ZLd8ZMd9ZNd:ZOd;ZPd<ZQdd=ZRdS(>iN(tg_currentVehicle(t dependency(t IItemsCache(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGtLOG_PROD(tengine_adapter(t moe_wgapi(ti18n(t build_modelt bar_visible(tchoose_placementtINJECTtBLOCKED(tMoEVMt MarkTickVM(t mod_settings(t cmd_xy_argt cmd_wh_argt MoECalculatortmoeDatatModInjectModels.coui://gui/gameface/mods/14th_ua/MoECalculatorcCsMtdkrIytjtjaWqItk rEtdaqIXntS(Ns{}(t_labels_json_cachetNonetjsontdumpsRtlabelst ExceptionR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _labels_json5s   icOsCy$ttdkr#tjnWntk r>tnXdS(N(trefresht_activeRRt prime_currentRR(targstkwargs((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_vehicle_changedfs   cOs*y tWntk r%tnXdS(N(RRR(R R!((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_interactor_updatedus  cOs*y tWntk r%tnXdS(N(RRR(R R!((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_lobby_state_changed}s  cCsyNddlm}|dksC|jj|ksC|jj|krMtnWn>tk rty tWqtk rtqXnXdS(Ni(tsettings_constants( taccount_helpers.settings_coreR%RtGAMEt CAROUSEL_TYPEtDOUBLE_CAROUSEL_TYPERRR(tdifftsc((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_settings_changeds0   cOsytjtjWntk r2tnXytdkrOtjnWntk rjtnXy t Wntk rtnXdS(N( Rtstarttreconcile_ownershipRRRRRRt_schedule_refresh(R R!((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_sync_completeds        cCs4ytdtWntk r/tnXdS(Ns[moe] table ready -> refresh(RRRR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_moe_data_readys    cOs*y tWntk r%tnXdS(N(RRR(R R!((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _on_gui_resets  cGsyzt|\}}t|\}}td||||f|dksY|dkr]dStj||d|d|Wntk rtnXdS(Ns%[moe] setPosition x=%s y=%s w=%s h=%sitwth(t _cmd_xy_argt _cmd_wh_argRRt set_positionRR(R txtyR3R4((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_on_set_positions  cCs2y|jt7_Wntk r-tnXdS(N(t setPositionR:RR(trvm((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_connect_commandss cCstS(N(R(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_vehicle_holderscCsddlm}tj|S(Ni(tILoadoutController(tskeletons.gui.game_controlR?Rtinstance(R?((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_loadout_holderscCsddlm}|S(Ni(tgetLobbyStateMachine(tgui.Scaleform.lobby_entryRC(RC((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _lobby_holderscCs tjtS(N(RRAR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _stats_holderscCsddlm}tj|S(Ni(t ISettingsCore(t'skeletons.account_helpers.settings_coreRGRRA(RG((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_settings_holderstvehiclet onChangedtloadouttonInteractorUpdateds lobby statetonVisibleRouteChangedtstatstonSyncCompletedtsettingstonSettingsChangedcCsyr|}|dkrdSt||d}|dk rq||krq||7}t|||td|nWntk rtnXdS(Nsoe] %s listener (re)armed(RtgetattrtsetattrRRR(tlabelt get_holdertattrthandlertholdertevent((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_arms    cCsYy:ddlm}t|kr9|jttdnWntk rTtnXdS(Ni(tg_guiResetterss%[moe] gui-resetter listener (re)armed(tguiR\R2taddRRR(R\((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_arm_gui_resetters$s   cCskxtD]}t|qWtts]ytjttaWq]tk rYt q]Xnt j dS(N( t _LISTENERSR[R_t_data_listener_armedRtadd_ready_listenerR1tTrueRRRtregister(tentry((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pytinstall_all_listeners2s    cCsotr dStaytjdtWnDtk rjtaty tWqktk rftqkXnXdS(Ng( t_refresh_pendingRctBigWorldtcallbackt_do_scheduled_refreshRtFalseRR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyR/Fs   cCs0tay tWntk r+tnXdS(N(RkRgRRR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyRjXs   cCsJy*ddlm}tj|jdkSWntk rEttSXdS(Ni(R?( R@R?RRAt interactorRRRRc(R?((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_overlay_closedcs  cCsyeddlm}|}|dkr,tS|j}|dkrEtS|jpTd}|jdSWntk rttSXdS(Ni(RCts hangar/{root}( RDRCRRkt visibleStatet getStateIDtendswithRR(RCtmachinetstatetstate_id((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _in_garageps     cCsyxddlm}tjt}t|jj|jj j }t |jj|jj j }||fSWntk rtdtfSXdS(Ni(R%i(R&R%RRAt_settings_core_ifacetinttoptionst getSettingR'R(t getRowCounttboolR)tenableSmallCarouselRRRk(R+tcoretrowstsmall((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt_carousel_geometrys$$ cCsddlm}|S(Ni(RG(RHRG(RG((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyRvscCsAy!ddlm}|dk SWntk r<ttSXdS(Ni(RC(RDRCRRRRk(RC((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt _host_alives  cCsyktj|tdtdgdtdgt}t||jt|||fat j |SWnt k rt dSXdS(Ntstyless/MoECalculator.csstmoduless/MoECalculator.js(topenwg_gamefacet gf_mod_injectt WIDGET_NAMEtCOUIRR=t_addViewModelPropertyt DATA_PROPRRR-RRR(thost_vmR<((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pytattachs       cCst|adS(N(tlistt_candidate_order(tnames((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pytset_candidate_orderscCs4ydt|jjkSWntk r/tSXdS(Ns"%s"(t INJECT_FIELDtproxyttoStringRRk(tvm((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pythas_inject_models cCsL|t| yieldis<[moe] preferred sub-view occupied -> placed on fallback '%s'sA[moe] all candidate sub-views occupied -> yielding (no placement)(t_candidate_vmsRtgarage_enabledRt _placed_namet _placed_vmRRRRR RR R (tnameRR<tactiontchosen((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyt note_mounts:               cCs dadadatjdS(N(RRRRRtclear(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pytdetachscCsTtdkrtdtSts8tdttSttddtdtS(Ns[moe] refresh: no active widgetsJ[moe] refresh: hangar host gone -> detach (stale listener fired off-lobby)iRi(RRRRkRRtpushRc(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyRs    cCsytjs:tdk r6ttddtdndStdk rbttddtddStrxmtD]b}tj|}|dkrqrnt ||}|dk rr|\}}t|d|PqrqrWnWnt k rt nXdS(NiRi( RRRRRRRRtgetRRR(RRttargetRR<((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pytapply_settings"s(         c Cs|dkrdSyztj}t|}t\}}ttt|jdt j }t d||j |j ||jftdd@a|j}|jt|j||j|j|j|j |j|j |j|j|j|j|j|j|j||j||j|j|j t!|j"t j#|j$t j%|j&t j'|j(t j)|j*t j+|j,}|j-xm|j.D]b} t/} | j0| j1| j2| j3| j4| j5| j6t7| j8|j9| qW|j:WdQX|dk ry|j} WdQXWqt;k rqXnWnt;k rt<nXdS(Ntenableds7[moe] push visible=%s marks=%d pct=%.1f rows=%d data=%sii(=RRtbuild_snapshotR RR RmRut has_vehicleRRRtmarkstcur_percentilethas_datat _push_seqt transactiontsetRevt setVisiblet setNationtnationtsetMarkst setCurPercenttsetCurAvgDamagetcur_avg_damagetsetFilltfillt setHasDatatsetCarouselRowstsetCarouselSmalltsetEndDamageRequiredtend_damage_requiredt setLabelsRtsetPosXtpos_xtsetPosYtpos_ytsetPosWtpos_wtsetPosHtpos_htsetFollowCarouseltfollow_carouseltgetTicksRtticksRt setPercenttpercentt setMarkCountt mark_counttsetDamageRequiredtdamage_requiredt setReachedR{treachedt addViewModelt invalidateRR( R<RtsnaptmodelR~Rtvisiblettxtarrttkttvt_h((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyR>s^                (SRRhtCurrentVehicleRthelpersRtskeletons.gui.sharedRtmoe_calculator._compatRRRtmoe_calculator.adapterRRRtmoe_calculator.domain.builderR R tmoe_calculator.domain.placementR R R t!moe_calculator.bridge.view_modelsRRtmoe_calculator.bridgeRtmoe_calculator.bridge.wulf_argsRR5RR6RRRRRRRRRRRRRRRkRgRaR"R#R$R,R0R1R2R:R=R>RBRERFRIR`R[R_RfR/RjRmRuRRvRRRRRRRRR(((s;res/scripts/client/moe_calculator/bridge/gameface_bridge.pyts                           0  PK!姫{zz9res/scripts/client/moe_calculator/bridge/mod_settings.pyc c @sddlmZmZmZddlmZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZd Zd ZdZdZdZdZdZdZdZd ZdZdZdZd Z dZ!dZ"dZ#dZ$dZ%dZ&dZ'd Z(d!Z)d"Z*d#Z+d$Z,d Z-d Z.d%Z/d Z0d Z1d Z2d Z3d&Z4d'Z5d(Z6d)Z7d*Z8id+d,fd-6d+d,fd.6d/d0fd16d2d3fd46d5d6fd76d8d9fd:6Z9d+d,f\Z:Z;d2d0f\Z<Z=d;Z>e#e$e%e&e'e(fZ?ie@e 6e@e 6eAe 6e@e 6eAe 6ee6ee6e@e6e@e6eAe6e@e6e@e6e@e6ee6e"e6d e#6d e$6d e%6d e&6d e'6d e(6e*e)6e-e,6e2e/6e@e56d<ge6e@e46ZBd=ZCed>ZDd?ZEd@ZFdAZGeHeBaIgZJeAaKeAaLeAaMdBZNdCZOdDZPdEZQdFZRdGZSdHZTdIZUdJZVdKZWdLZXdMZYdNZZdOZ[dPZ\dQZ]dRZ^dSZ_dTZ`dUZadVZbdWZcdXZddYZedZZfd[Zgd\Zhd]Zid^Zjd_Zkd`ZldaZmdbZndcZoddZpdeZqdfZrdgZsdhZtdiZueedjdkZvdlZwdmZxdnZydoZze{e{e{e{eAe{e{e{dpZ|dqZ}drdsZ~dtZduZdvZdwZdxZeZdyZdzZd{Zd|Zd}Zd~ZdZdZdZdZdZd d dZe@dZdS(i(tLOG_CURRENT_EXCEPTIONt LOG_DEBUGtLOG_PROD(t settings_i18nscom.14th_ua.moe_calculators14th_ua's MoE Calculatoritgarage_widget_enabledtbattle_widget_enabledtbattle_widget_alt_keytcounted_assistance_enabledtprogress_bar_enabledtprogress_bar_variantiitprogress_variant_hotkeytprogress_bar_sizetprogress_show_eventstprogress_show_alt_keytprogress_show_alwaystprogress_transitions_enabledtprogress_transitions_eventstprogress_transitions_manualtprogress_hold_secondsiitprogress_auto_toggle_thresholdidtposXtposYtposWtposHtprogress_bar_pos_xtprogress_bar_pos_ytprogress_bar_pos_frametanchortlegacytprogress_bar_orientationtprogress_bar_alignmenttprogress_bar_pos_healedtfollowCarouselt calcPreviewt barPreviews'gui/maps/icons/moe_calculator/previews/i}iItcalc_assist_ontcalc_assist_offiiCtbar_eff_horizontaliLitbar_eff_verticaliitbar_ma_horizontali7itbar_ma_verticali Ni%cCsQyt|}Wnttfk r*dSX|t kr=t S|tkrMtS|S(Ni(tintt TypeErrort ValueErrortPOS_MAX(tv((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt clamp_posss  cCsbt|trdSyt|}Wnttfk r=dSXd|koU|knr^|SdS(Ni(t isinstancetboolR)R*R+(R-t max_index((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt clamp_variants cCsbt|tr|Syt|}Wnttfk r=|SX||krN|S||kr^|S|S(N(R/R0R)R*R+(R-tlothitdefault((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt _clamp_ints  cCst|tttS(N(R6tPROGRESS_HOLD_MINtPROGRESS_HOLD_MAXtPROGRESS_HOLD_DEFAULT(R-((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytclamp_hold_secondsscCst|tttS(N(R6tPROGRESS_AUTO_TOGGLE_MINtPROGRESS_AUTO_TOGGLE_MAXtPROGRESS_AUTO_TOGGLE_DEFAULT(R-((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytclamp_auto_toggle_thresholds cCs|tkrt|S|tkr,t|S|tkrEt|tS|tkr^t|tS|tkrwt|t S|t krt |S|t krt |S|tkr|tkr|StS|tkr|St|S(N(t _POS_KEYSR.tPROGRESS_VARIANT_KEYR2tPROGRESS_SIZE_KEYtPROGRESS_SIZE_LARGEtPROGRESS_ORIENTATION_KEYtPROGRESS_ORIENT_VERTICALtPROGRESS_ALIGNMENT_KEYtPROGRESS_ALIGN_FREEtPROGRESS_HOLD_SECONDS_KEYR:t"PROGRESS_AUTO_TOGGLE_THRESHOLD_KEYR>tPROGRESS_POS_FRAME_KEYtPOS_FRAME_LEGACYtPOS_FRAME_ANCHORtPROGRESS_VARIANT_HOTKEY_KEYR0(tkeytvalue((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_coerces&                cCsYtt}t|trUx7tD],}||kr"t|||||ttjttrtSt|o=ttjttS(N(R0RURVRaR]RXtPROGRESS_SHOW_ALT_KEY(talt_held((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytprogress_alt_held-scCsttjttS(N(R2RURVR@tPROGRESS_VARIANT_EFFICIENCY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyR :s cCsgtjtdg}t|ts+dgSg|D]1}t|tr2t|t r2t|^q2S(Ni%(RURVRLR/tlistR)R0(R-tk((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyR EscCsttjtttS(N(R2RURVRAtPROGRESS_SIZE_DEFAULTRB(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyR OscCs.ttjtto-ttjttS(N(R0RURVtPROGRESS_TRANSITIONS_KEYRXtPROGRESS_TRANS_EVENTS_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRZscCs.ttjtto-ttjttS(N(R0RURVRjRXtPROGRESS_TRANS_MANUAL_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRescCsttjttS(N(R:RURVRGR9(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRmscCsttjttS(N(R>RURVRHR=(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRscCsttjtdS(Ni(R.RURVt POS_X_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpos_xscCsttjtdS(Ni(R.RURVt POS_Y_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpos_yscCsttjtdS(Ni(R.RURVt POS_W_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpos_wscCsttjtdS(Ni(R.RURVt POS_H_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpos_hscCsttjtdS(Ni(R.RURVt BAR_POS_X_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt bar_pos_xscCsttjtdS(Ni(R.RURVt BAR_POS_Y_KEY(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt bar_pos_yscCstttjttS(N(RORIRURVRK(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRs cCsttjtttS(N(R2RURVRCtPROGRESS_ORIENT_HORIZONTALRD(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRscCsttjtttS(N(R2RURVREtPROGRESS_ALIGN_FIXEDRF(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRs cCsttjttS(N(R0RURVtFOLLOW_CAROUSEL_KEYRX(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytfollow_carouselscCs |tkrtj|ndS(N(t _listenerstappend(tfn((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytadd_change_listeners cCsAx:ttD],}y |Wq tk r8tq Xq WdS(N(RgR}t ExceptionR(R((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_notifys   cCsV|r dnd}|tkr$dnd}|tkr<dnd}|d||ffS(NR#R$tmatefftverticalt horizontals bar_%s_%s(tPROGRESS_VARIANT_MOVING_AVERAGERD(tcounted_assisttvariantt orientationtcalct variant_namet orient_name((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpreview_source_namess cCs%t|\}}t|d||fS(Ns.png(t_PREVIEW_DISPLAYt _PREVIEW_DIR(tnametwth((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_preview_entryscCsatttt\}}t|\}}}t|\}}}||||||fS(N(RRR RR(Rtbartcalc_srctcalc_wtcalc_htbar_srctbar_wtbar_h((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytpreview_sourcess  c Cs`t|\}}}t|\}}}|jtt||||jtt|||dS(N(Rt updateImagetLINKAGEtCALC_PREVIEW_KEYtBAR_PREVIEW_KEY( tgRRRRRRRR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_push_previewsscCs}y^t}|dks(t|d r,dStttt\}}t|||Wntk rxt nXdS(NR( t _primary_apitNonethasattrRRR RRRR(RRR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytupdate_preview_imagess    c Csy|tkrdSt}|dks8t|d r<dSt|trQ|ni}t|krvtt|tnt}t |krtt |t nt }t |krtt |t nt }t |||\}}t|||Wntk rtnXdS(NR(RRRRR/RPR_RORR@R RCRRRRR( tlinkagetsettingsRtstcountedRRRR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_on_live_change1s   ((( cCsy{ddlm}ddlm}|j|}|dk rpt|drp|jtt dt t dn t dWnt k rt dnXdS( Ni(t dependency(tIModsSettingsApiInternaltregisterLiveSettingsChanget fullsettingss/[moe] live preview channel wired (MSA internal)sB[moe] MSA internal live channel absent -> previews update on ApplysG[moe] MSA internal live channel unavailable -> previews update on Apply( thelpersRtgui.aslainMenu.skeletonRtinstanceRRRRRRXRR(RRtapi((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_wire_live_previewOs   cCst|adS(N(RTRU(RR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_seedgscCseyMt|dd}t|trLt|jdp9ijtpHiSWntk r`nXiS(NtstateR(tgetattrRR/RPRVRR(RR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_raw_stored_settingsns , cCsNt|tsdSx4tD],}||krt|||t|tk rjx|D]}|d|dt|t rBdS|tkr[t|t (0, 0) at alignment=%r(ii( tPROGRESS_BAR_POS_HEALED_KEYRXRVRERzR/R0R)RFR.RuRwR(RRRXRURV((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_migrate_pre_v29_stale_bar_posJs      cCstr dSt}|dkr-tddSyt|}t|t}|jt|}|rt||j t|t nt|j t|t |rMyt |t |t |t|t|t||jtt|y|jWntk r#tnXtdWqMtk rItqMXnxtD]}t|qWWxtD]}t|quWtttatdtfWntk rtnXdS(Ns<[moe] ModsSettingsAPI absent -> both widgets default enableds;[moe] migrated saved settings across a settingsVersion bumps[moe] settings registered -> %r(t _registeredRRRRRR6tgetModSettingsRtsetModTemplatet _on_changedRSRWRYRZR\RtupdateModSettingst_full_settings_for_writeR=RRRR<RQRKRRRXRU(R7trawttemplateRRR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pytregistertsT                  cCsi|\}}}|\}}}||kr7||dfS||kr\|tkr\||dfS|||fS(Ni(ii(ii(RF(tpretposttpre_otpre_at_pre_ptpost_otpost_atpost_p((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt_derive_layouts    c Csy|tkrdStrutd|jt|jtftd|jDtdt ft dSt jt t t jt tt jtdt jtdff}t|t jt t t jt tt jtdt jtdff}t||\}}}t}||dkrJ|t t 3s s8[moe] settings changed (re-entrant, no derivation) -> %riis[moe] settings changed -> %r(Rt _derivingRRVRuRwRtitemsRRURRCRyRERzRnR]RXRRRaRbR=RRt_rebaking_templateR_R6R`( Rt new_settingsRfRgt settled_ot _settled_at settled_ptdirtyR((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyR`sj$  ' '              cCsy|tkrdSt|r"|ntdtt %r(RRRQRURmRoRqRsRuRwRKRIRyRCRzRERXR{RRRR(Rtdefaults((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyROms$             cCspi}y.|jtt}|r3t|}nWntk rNtnX|jdt|jt |S(NR ( R^RR6RPRRt setdefaultRXtupdateRU(Rtdatatcurrent((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyRbs   cCst|ttRPRUR}R]RpRrRORTRYR[R^RRR ReR R R RRRRRnRpRrRtRvRxRRRR|RRRRRRRRRRRRRRRRRRRRRRRRR6R<RRKtsetRNRQRSRWRYRZR\ReRnR`RORbR}R(((s8res/scripts/client/moe_calculator/bridge/mod_settings.pyt)sB8                      "                             . #          6    $  * i ) g   PK!(:res/scripts/client/moe_calculator/bridge/progress_view.pyc c@sddlmZddlmZddlmZddlmZmZm Z m Z m Z m Z m Z mZmZdZeeeeee e eee dde de d ej ZejZejZejZejZejZejZejZd S( i(t mod_settings(tBarHost(t ProgressVM( tPROGRESS_ANCHOR_X_OFFSETtPROGRESS_ANCHOR_Y_FRACtPROGRESS_ANCHOR_Y_SHIFTtPROGRESS_ANCHOR_Y_SHIFT_LARGEtPROGRESS_MM_GAPtPROGRESS_MM_GAP_LARGEtPROGRESS_MM_GAP_BOTTOMtPROGRESS_MM_TRACK_XtPROGRESS_MM_TRACK_X_LARGEtMoEProgressViews [moe-bar]tmm_gapt mm_gap_largetvariantN(tmoe_calculator.bridgeRt moe_calculator.bridge.bar_windowRt!moe_calculator.bridge.view_modelsRtmoe_calculator.domain.constantsRRRRRRR R R tRES_MAP_ITEM_IDtPROGRESS_VARIANT_MOVING_AVERAGEt_hostt open_windowt close_windowt active_viewtapply_positiontdragt has_placedt ensure_placed(((s9res/scripts/client/moe_calculator/bridge/progress_view.pyt s"@           PK!cc(G(G8res/scripts/client/moe_calculator/bridge/view_models.pyc c@sddlmZmZdefdYZdefdYZdefdYZdefd YZd efd YZd S( i(t ViewModeltArrayt MarkTickVMcBsDeZdddZdZdZdZdZdZRS(iicCs#tt|jd|d|dS(Nt propertiestcommands(tsuperRt__init__(tselfRR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRscCsWtt|j|jdd|jdd|jdd|jdtdS(Ntpercentit markCounttdamageRequiredtreached(RRt _initializet_addNumberPropertyt_addBoolPropertytFalse(R((s7res/scripts/client/moe_calculator/bridge/view_models.pyR s cCs|jd|dS(Ni(t _setNumber(Rtv((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setPercentscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setMarkCount!scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetDamageRequired$scCs|jd|dS(Ni(t_setBool(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setReached's(t__name__t __module__RR RRRR(((s7res/scripts/client/moe_calculator/bridge/view_models.pyRs    tMoEVMcBseZdddZdZdZdZdZdZdZd Z d Z d Z d Z d Z dZdZdZdZdZdZdZdZedZRS(iicCs#tt|jd|d|dS(NRR(RRR(RRR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR,scCsLtt|j|jdt|jdd|jdd|jdd|jdd|jd d|jd t|jd d |jd t|j dt |jdd|jdd|jdd|jdd|jdd|jdd|jdt|jdd|j d|_ dS(Ntvisibletnationttmarksit curPercentgt curAvgDamagetfillthasDatat carouselRowsit carouselSmallttickstendDamageRequiredtlabelstposXtposYtposWtposHtfollowCarouseltrevt setPosition( RRR RtTruet_addStringPropertyR t_addRealPropertyRt_addArrayPropertyRt _addCommandR-(R((s7res/scripts/client/moe_calculator/bridge/view_models.pyR /s(cCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setVisibleUscCs|jd|dS(Ni(t _setString(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setNationXscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetMarks[scCs|jd|dS(Ni(t_setReal(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setCurPercent^scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetCurAvgDamageascCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetFilldscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setHasDatagscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetCarouselRowsjscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetCarouselSmallmscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetEndDamageRequiredpscCs|jd|dS(Ni (R4(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setLabelssscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetPosXvscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetPosYyscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetPosW|scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetPosHscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetFollowCarouselscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetRevscCs |jdS(Ni (t _getArray(R((s7res/scripts/client/moe_calculator/bridge/view_models.pytgetTicksscCstS(N(R(((s7res/scripts/client/moe_calculator/bridge/view_models.pyt getTicksTypes(RRRR R3R5R6R8R9R:R;R<R=R>R?R@RARBRCRDRERGt staticmethodRH(((s7res/scripts/client/moe_calculator/bridge/view_models.pyR+s* &                  t BattleMoEVMcBszeZdddZdZdZdZdZdZdZd Z d Z d Z d Z d Z RS(i icCs#tt|jd|d|dS(NRR(RRJR(RRR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRscCstt|j|jdt|jdd|jdd|jdd|jdd|jdt|jd t|jd d|jd d |jd tdS(NRtcombinedDamageit projAvgDamageRgtpctDeltaR!t hasBaselinet countedAssistt assistKindtassistt assistVisible(RRJR RRR R0R/(R((s7res/scripts/client/moe_calculator/bridge/view_models.pyR scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR3scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetCombinedDamagescCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetProjAvgDamagescCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR8scCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setPctDeltascCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR;scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetHasBaselinescCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetCountedAssistscCs|jd|dS(Ni(R4(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setAssistKindscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetAssistVisibles(RRRR R3RSRTR8RUR;RVRWRXRY(((s7res/scripts/client/moe_calculator/bridge/view_models.pyRJs          t ProgressVMcBseZdddZdZdZdZdZdZdZd Z d Z d Z d Z d Z dZdZdZdZdZdZRS(iicCs#tt|jd|d|dS(NRR(RRZR(RRR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRscCstt|j|jdt|jdd|jdd|jdd|jdd|jdd|jd t|jd t|jd d|jd t|jd t|jdt|jdd|jdt|jdd|jdtdS(NRRitaxisLogtaxisHitpreAvgtprojAvgR!taltHeldtbarSizet transEventst transManualt showEventstholdMsitctrlHeldt etaBattlesitvertical(RRZR RRR R0R.(R((s7res/scripts/client/moe_calculator/bridge/view_models.pyR s"   cCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR3FscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR6IscCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setAxisLoLscCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setAxisHiOscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setPreAvgRscCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setProjAvgUscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR;XscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setAltHeld[scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setBarSize^scCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetTransEventsascCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetTransManualdscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setShowEventsgscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setHoldMsjscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setCtrlHeldmscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setEtaBattlespscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setVerticalss(RRRR R3R6RhRiRjRkR;RlRmRnRoRpRqRrRsRt(((s7res/scripts/client/moe_calculator/bridge/view_models.pyRZs$ c               t EfficiencyVMcBseZdddZdZdZdZdZdZdZd Z d Z d Z d Z d Z dZdZdZdZdZdZdZdZRS(iicCs#tt|jd|d|dS(NRR(RRuR(RRR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRscCs7tt|j|jdt|jdd|jdd|jdd|jdd|jdd|jd d|jd d|jd t|jd t|jd d|jdd|jdt|jdt|jdt|jdd|jdt|jdtdS(NRtdamageitbarXgtbandtr65tr85tr95tr100R!R_t battleEpochR`RaRbRcRdiReRg(RRuR RRR R0R.(R((s7res/scripts/client/moe_calculator/bridge/view_models.pyR s&cCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR3scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyt setDamagescCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetBarXscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetBandscCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetR65scCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetR85scCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetR95scCs|jd|dS(Ni(R7(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetR100scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyR;scCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRlscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pytsetBattleEpochscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRmscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRnscCs|jd|dS(Ni (R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRoscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRp scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRq scCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRrscCs|jd|dS(Ni(R(RR((s7res/scripts/client/moe_calculator/bridge/view_models.pyRts(RRRR R3R~RRRRRRR;RlRRmRnRoRpRqRrRt(((s7res/scripts/client/moe_calculator/bridge/view_models.pyRuws( K                 N(tframeworks.wulfRRRRRJRZRu(((s7res/scripts/client/moe_calculator/bridge/view_models.pyts e8PK!z?^6res/scripts/client/moe_calculator/bridge/wulf_args.pyc c@s/ddlmZdZdZdZdS(i(tLOG_CURRENT_EXCEPTIONcCsgt|tr|j|St|dd}t|rcy|j|SWqctk r_dSXndS(Ntget(t isinstancetdictRtgetattrtNonetcallablet Exception(tatkeytgetter((s5res/scripts/client/moe_calculator/bridge/wulf_args.pytmap_get s   cCsid}y@|sdS|d}|t|d|t|dfSWntk rdtdSXdS(NcSs-yt|SWnttfk r(dSXdS(Ni(tintt TypeErrort ValueError(tv((s5res/scripts/client/moe_calculator/bridge/wulf_args.pytas_intsitxty(ii(ii(R RR(targsRR((s5res/scripts/client/moe_calculator/bridge/wulf_args.pyt cmd_xy_args  , cCsid}y@|sdS|d}|t|d|t|dfSWntk rdtdSXdS(NcSs-yt|SWnttfk r(dSXdS(Ni(R R R(R((s5res/scripts/client/moe_calculator/bridge/wulf_args.pyR1sitwth(ii(ii(R RR(RRR((s5res/scripts/client/moe_calculator/bridge/wulf_args.pyt cmd_wh_arg-s  , N(tmoe_calculator._compatRR RR(((s5res/scripts/client/moe_calculator/bridge/wulf_args.pyt s  PK!2res/scripts/client/moe_calculator/build_config.pyc c@s dZdS(t 100eb783efe43fb67def32b71920fbc8N(tWG_APPLICATION_ID(((s1res/scripts/client/moe_calculator/build_config.pyt tPK!qa5res/scripts/client/moe_calculator/domain/__init__.pyc c@sdS(N((((s4res/scripts/client/moe_calculator/domain/__init__.pyttPK!s;res/scripts/client/moe_calculator/domain/battle_builder.pyc c@sddlZddlZddlmZddlmZmZmZm Z m Z ddl m Z dZ ddZddZd Zd Zed Zed Zd ZdZdZee dZee dZdZdZdZeeeeedZdS(iN(t battle_types(tEFFICIENCY_BAR_STOPStEWMA_Kt MARK_PERCENTStPROGRESS_AXIS_MIN_WINDOWtPROGRESS_ETA_CAP(tiround_half_awaycCs4||kr|S||kr |S||kr0|S|S(N((tvaluetlothi((s:res/scripts/client/moe_calculator/domain/battle_builder.pyt_clamps ic Cst|p d}t|pd}t|p0d}t|pBd}|dkr||dkr||dkr||d}} n0||kr|n|}||krdnd} ||kr|dfS|dkrdS|| fS(Nitassistttracktspottstun(iR (tint( R R Rt merged_assisttttststtmt assist_valt assist_kind((s:res/scripts/client/moe_calculator/domain/battle_builder.pytcounted_assistance's$   c Csat||||\}}t|p'dt|p6dt|pFd}|dkr]|SdS(Ni(RR( tdamageR R Rt team_damageRtcountedt_kindtc((s:res/scripts/client/moe_calculator/domain/battle_builder.pytcombined_damageFs2cCs|s dSy td|jD}Wntttfk rGdSXdg}xD|D]<\}}||ddkrX|j|t|fqXqXWt|dkrdS|S(Ncss9|]/\}}t|tt|p'dfVqdS(iN(Rtfloat(t.0tpcttdmg((s:res/scripts/client/moe_calculator/domain/battle_builder.pys dsgiii(gg( tNonetsortedtitemst TypeErrort ValueErrortAttributeErrortappendRtlen(t thresholdstanchorststopstpercenttd((s:res/scripts/client/moe_calculator/domain/battle_builder.pyt_fit_from_thresholdsQs   cCstt|pdd|dd}|dd}x[t||dD]F\\}}\}}||krH|||||||}PqHqHWt|ddS(NgiiigY@(R Rtzip(RtfitR.R-td_lotp_lotd_hitp_hi((s:res/scripts/client/moe_calculator/domain/battle_builder.pyt_smooth_percentps&, cCs.t|p d}||t|p$d|S(Ngi(R(tprev_avgtcdtktprev((s:res/scripts/client/moe_calculator/domain/battle_builder.pytewma_project_rawscCstt|||S(N(RR;(R7R8R9((s:res/scripts/client/moe_calculator/domain/battle_builder.pyt ewma_projectscCs|jp i}t|dd}tt|ddt|dd|j|\}}t|jt|ddt|dd|j|jd|}t|j|}t |j|}|j pddkp|jpddkpt t|dt }t |} | dk } | rst|| tt|jp8d| } tt|j pWd| dd} | } n d} d} tjd |d |d |d |d | d| d| d|S(NR it track_assistt spot_assistRtbaseline_knownggY@Rtcounted_assistRtproj_avg_damaget cur_percentt pct_deltathas_datat has_baseline(R*tgetattrRRRRRR<tpre_avg_damageR;tpre_percentiletbooltFalseR/R"R6RR tbttBattleMoEModel(tsnapshotR*RRRR8tprojtproj_rawRER1RDtmoveRBRC((s:res/scripts/client/moe_calculator/domain/battle_builder.pytbuild_battle_models>    %  cCsFt|p d}d}x'tD]}||kr|d7}qqW|S(Ngii(RR(RHtptmarksR-((s:res/scripts/client/moe_calculator/domain/battle_builder.pytmarks_from_percentiles   cCs|p i}ttdt|p!dd}yp|dkret|jt|ddp_dnd}t|j|dkrdnt|dpd}Wntttfk rdSX||krdS||fS(Niiigid(gg(gg( tmintmaxRRtgetRR%R&R'(R*RSRR ((s:res/scripts/client/moe_calculator/domain/battle_builder.pyt mark_axiss $88 cCs8t|d|}tdt|t|p*d|S(Nig(R;RVRUR(taxis_hitpre_avgR9t min_windowtfloor((s:res/scripts/client/moe_calculator/domain/battle_builder.pytprogress_axis_losc Cst|p ddkrdSt|}t|p4d}||krJdSt|pVd}||krldSyUtj||||tjd|}t|tdttj|SWnttt fk r|SXdS(Ngiig?i( RtmathtlogRURVRtceilR&tZeroDivisionErrort OverflowError( tproj_avgR8RYR9tcapR RNR!tn((s:res/scripts/client/moe_calculator/domain/battle_builder.pytbattles_to_axis_hi s   ,)cCs|p i}dg}y^xWtdD]K}tt|j|dpDd}||dkradS|j|q#WWntttfk rdSXt |S(Ngidii(id( RRRRWR"R(R%R&R'ttuple(R*R,tkeyR.((s:res/scripts/client/moe_calculator/domain/battle_builder.pytefficiency_stopsRs  $cCs|s dStt|pd|d|d}tdtj||}|||d||||d}t|d}||t||S(Ngiii(R RRVtbisectt bisect_leftR(RR,R.tiRR((s:res/scripts/client/moe_calculator/domain/battle_builder.pytefficiency_bar_xjs&&cCsM|s dStt|pd|d|d}tdtj||dS(Nigii(R RRVRjt bisect_right(RR,R.((s:res/scripts/client/moe_calculator/domain/battle_builder.pytefficiency_band{s&c Csft|o/t|o/t| o/t| }t|oYt|rVt|nt}|oe|S(N(RItTrue( t in_battlet has_vehiclet is_spectatingt overlay_opentenabledtalt_modetalt_heldtbasetactive((s:res/scripts/client/moe_calculator/domain/battle_builder.pytbattle_bar_visibles*(RjR^tmoe_calculator.domainRRKtmoe_calculator.domain.constantsRRRRRtmoe_calculator.domain.roundingRR RRR/R6R;R<RQRTRXR]RfRiRmRoRJRpRz(((s:res/scripts/client/moe_calculator/domain/battle_builder.pyts*  (     L  2   PK!\9res/scripts/client/moe_calculator/domain/battle_types.pyc c@s0defdYZdefdYZdS(tBattleSnapshotcBs>eZdddddddddddeeeedZRS(itgcCs||_||_||_||_||_||_||_||_| |_| |_ | pci|_ | |_ | |_ ||_ ||_dS(N(tvehicle_int_cdtnationtdamagetassistt track_assistt spot_assisttstunt team_damagetpre_avg_damagetpre_percentilet thresholdst has_vehiclet in_battlet is_spectatingtbaseline_known(tselfRRRRRRRR R R R R RRR((s8res/scripts/client/moe_calculator/domain/battle_types.pyt__init__/s             N(t__name__t __module__tNonetTruetFalseR(((s8res/scripts/client/moe_calculator/domain/battle_types.pyR s $  tBattleMoEModelcBseZeedddZRS(iRc CsL||_||_||_||_||_||_||_||_dS(N(tcombined_damagetcounted_assistt assist_kindtproj_avg_damaget cur_percentt pct_deltathas_datat has_baseline( RRRRRRR RR((s8res/scripts/client/moe_calculator/domain/battle_types.pyR^s       (RRRR(((s8res/scripts/client/moe_calculator/domain/battle_types.pyREsN(tobjectRR(((s8res/scripts/client/moe_calculator/domain/battle_types.pyt s:PK! s"  #PK!/n6res/scripts/client/moe_calculator/domain/constants.pyc c@s d-Zd.ZdZdZdZd/ZdZd1Zd2ZdZ de dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZdZdZdZdZd3Zd"Zd"Zd"Zd"Z d"Z!d#Z"d$Z#dZ$dZ%d%Z&d&Z'd'Z(d(Z)dZ*d)Z+d*Z,d+Z-d,S(4iAiUi_iiiiciidii2iKiiii g@gi@i ii!ii'gGz?iiiiiiiIiiitiiiiiViiiii"ikN(iAiUi_(iii(iii2iKidii: i(iiiIiiit(.t MARK_PERCENTSt MARK_COUNTStGOALPOST_PERCENTILEtAXIS_MINtAXIS_MAXtEFFICIENCY_BAR_STOPStFETCH_LIST_CAPtSTALE_WINDOW_SECONDStREVALIDATE_SECONDStEWMA_NtEWMA_KtPROGRESS_AXIS_MIN_WINDOWtPROGRESS_ETA_CAPtBATTLE_ANCHOR_XtBATTLE_ANCHOR_YtBATTLE_ANCHOR_X_RAISEDtBATTLE_ANCHOR_Y_RAISEDtBATTLE_ANCHOR_Y_EPICtBATTLE_ANCHOR_X_SHIFTtEFFICIENCY_WIDE_THRESHOLDtPROGRESS_ANCHOR_Y_FRACtPROGRESS_ANCHOR_X_OFFSETtPROGRESS_ANCHOR_Y_SHIFTtPROGRESS_ANCHOR_Y_SHIFT_LARGEtEFFICIENCY_ANCHOR_Y_FRACtEFFICIENCY_ANCHOR_X_OFFSETtEFFICIENCY_ANCHOR_Y_SHIFTtEFFICIENCY_ANCHOR_Y_SHIFT_LARGEt MINIMAP_SIZEStMM_GAPtPROGRESS_MM_GAPtPROGRESS_MM_GAP_LARGEtEFFICIENCY_MM_GAPtEFFICIENCY_MM_GAP_LARGEtPROGRESS_MM_GAP_BOTTOMtEFFICIENCY_MM_GAP_BOTTOMtMM_TICK_OVERHANGtMM_TICK_OVERHANG_LARGEtVERTICAL_ANCHOR_Y_SHIFTtVERTICAL_ANCHOR_Y_SHIFT_LARGEtPROGRESS_MM_TRACK_XtPROGRESS_MM_TRACK_X_LARGEtEFFICIENCY_MM_TRACK_XtEFFICIENCY_MM_TRACK_X_LARGEt MM_TRACK_YtMM_TRACK_Y_LARGE(((s5res/scripts/client/moe_calculator/domain/constants.pytsZ      $ 'PK!~[z z 7res/scripts/client/moe_calculator/domain/fetch_list.pyc c@sqddlmZdZejejdZejdZdZejdZej dZ dZ d S( i(t constantscCsBy t|j|dpdSWntttfk r=dSXdS(Ni(tinttgett TypeErrort ValueErrortAttributeError(t recency_maptcd((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt_recencys c Cs||}g}t}|rH|jt||jt|nxh|D]`} | sO| |krnqOnt|| |krqOn|jt| |jt| qOW|| S(N(tsettappendRtaddR( t selected_cdt recent_cdsRt now_epochtcaptmax_agetcutofftresulttseenR((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt bootstrap_ids!s   c sg|D]}t|^q}t|}||krA|dfSt||krd||gdfSt|dfdd}g|D]}||kr|^q}||g|fS(Ntkeycst|| fS(N(R(R(R(s6res/scripts/client/moe_calculator/domain/fetch_list.pytLti(RtNonetlentsorted( tcurrentRtnew_cdRtctidstvictimRtkept((Rs6res/scripts/client/moe_calculator/domain/fetch_list.pytadd_with_eviction9s    %cCs;t|}g|D]$}t||krt|^qS(N(R(RRR((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt remove_idQs cCs`||}gg}}x<|D]4}t|||kr?|n|jt|qW||fS(N(RR R(RRRRRR tpurgedR((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt purge_staleWs    2cCs7y|t||kSWnttfk r2tSXdS(N(RRRtTrue(t fetched_atRtttl((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt needs_refetchascCsey(t|pd}t|p!d}Wnttfk rBtSXt|odt|od||kS(Ni(RRRtFalsetbool(tprev_updated_attnew_updated_attprevtnew((s6res/scripts/client/moe_calculator/domain/fetch_list.pyt data_changedls N( tmoe_calculator.domainRRtFETCH_LIST_CAPtSTALE_WINDOW_SECONDSRR!R"R$tREVALIDATE_SECONDSR(R/(((s6res/scripts/client/moe_calculator/domain/fetch_list.pyts    PK!o49res/scripts/client/moe_calculator/domain/moe_estimate.pyc c@sddlZddlmZmZddlmZdZdZdZdZ dZ d Z d Z d(Z d)Zd*Zd+Zd Zd!eZd"Zd#Zd$Zd%Zd&Zd'ZdS(,iN(t MARK_PERCENTStGOALPOST_PERCENTILE(tiround_half_awayig333333?g_Q?g& .>gMbP?g@cCs,|tkrtS|dtkr(dtS|S(Ng?(t_P_EPS(tp((s8res/scripts/client/moe_calculator/domain/moe_estimate.pyt_clamp_p:s  g%1Cg4pFk@g;->qg@ rKa@g͋40>gyTW @g0sgc3s)|]}||VqdS(N((Rti(tdbartdsRtzs(s8res/scripts/client/moe_calculator/domain/moe_estimate.pys s( Rtlent MIN_SAMPLEStNoneRtmaxtmint MIN_Z_SPREADRtsumtrange( Rtptst_dRRt_ptntsxxtsxytsigmatmu((R!R"RR#s8res/scripts/client/moe_calculator/domain/moe_estimate.pyt fit_mu_sigmaus" % 1 cCstt|}td|D|}td|D|}t|}dt|}|tkrpdS||}|dkrdS|t|krdS|t|fS(Ncss|]\}}|VqdS(N((RRR.((s8res/scripts/client/moe_calculator/domain/moe_estimate.pys scss|]\}}|VqdS(N((RR-R((s8res/scripts/client/moe_calculator/domain/moe_estimate.pys sg?g(RR$R*Rt UNIVERSAL_CVt _DENOM_EPSR&tPRIOR_MAX_MU_MULTIPLE(R,R/td0tp0tz0tdenomR3((s8res/scripts/client/moe_calculator/domain/moe_estimate.pyt_prior_mu_sigmas    cCs|dkrdSi}x0tD](}t||t|d||qg@ rKa@g͋40>gyTW @(g0s2         PK![446res/scripts/client/moe_calculator/domain/placement.pyc c@sdZdZdZdZdS(twaittinjecttblockedcCsYxL|D]D}|j|}|dkr2t|fS||rDqnt|fSWtdfS(N(tgettNonetWAITtINJECTtBLOCKED(tordertvmst has_injecttnametvm((s5res/scripts/client/moe_calculator/domain/placement.pytchoose_placements     N(RRRR (((s5res/scripts/client/moe_calculator/domain/placement.pytsPK!gƷ8res/scripts/client/moe_calculator/domain/positioning.pyc c@sddlmZmZmZdZdZdZdZdddZdZ d Z ddd Z d Z d Z d ZdddZdZdZdZdZdS(i(tBATTLE_ANCHOR_YtBATTLE_ANCHOR_Y_RAISEDtBATTLE_ANCHOR_Y_EPICcCs&|r tnt}||r!tndS(Ni(RRR(traisedtis_epictbase((s7res/scripts/client/moe_calculator/domain/positioning.pytbattle_y_anchorscCs/t|p-t|p-t|p-t| S(N(tbool(ttotaltblockedtassistt assist_stun((s7res/scripts/client/moe_calculator/domain/positioning.pytdamage_log_summary_hiddens cCst|p d}t|pd}xttt|t|D]l}|t|krnt||nt}|t|kr||nd}|rF|pd|krFtSqFWtS(Ni(((ttupletrangetmaxtlenRtTruetFalse(tflagstvaluest thresholdtitenabledtvalue((s7res/scripts/client/moe_calculator/domain/positioning.pytefficiency_panel_wide)s(("cCs>ttd||}ttd|||}||fS(Ni(tminR(tmax_xtmax_yt x_from_leftt y_from_bottomtxty((s7res/scripts/client/moe_calculator/domain/positioning.pytanchor_top_leftCsicCst|}t|}t|}ttd|dt||}ttdt||t||}||fS(Nii(t_intt_floatRRtint(RRty_fractx_offsetty_offsettfracRR ((s7res/scripts/client/moe_calculator/domain/positioning.pytanchor_centredOs    &,c Cst|}t|}t|}t|}t|}ttd|d|}ttdt||||}||fS(Nii(R"R#RRR$( RRtspace_yR%ty_shiftR(tshiftRR ((s7res/scripts/client/moe_calculator/domain/positioning.pytanchor_centred_reducedvs3     &c Cst|}t|}t|}t|}t|}t|}t|}t|}|||||}|||} || fS(N(R"( tspace_xR*tedge_xtedge_ytmm_sizetgapt gap_bottomtoverhangRR ((s7res/scripts/client/moe_calculator/domain/positioning.pytanchor_minimaps?        cCsTt|}|dkrdn|\}}t|t|t|t|fS(Ni(ii(t_xytNoneR"(tanchortoff_xtoff_ytpointtaxtay((s7res/scripts/client/moe_calculator/domain/positioning.pyt anchor_offsets c Cst|}|dkrdn|\}}t|}|dkrHdn|\}}t|}t|}|rt||t||fSt||dt||fS(Nii(ii(ii(R6R7R"( tpairtsurfacetverticalR;tpxtpytsurftswtsh((s7res/scripts/client/moe_calculator/domain/positioning.pyt free_top_lefts    c Cst|}|dkrdn|\}}t|}|dkrHdn|\}}t|}t|}|rt||t||fSt||dt||fS(Nii(ii(ii(R6R7R"( ttop_leftR@RAR;ttxttyRDRERF((s7res/scripts/client/moe_calculator/domain/positioning.pytfree_anchor_pointCs    c Cst|}|dkrdS|\}}d|ko?dknrd|ko[dknr|dd}d|d}nXt|} | dks| ddks| ddkrdS|| d}|| d}|t||t|fS(Ngg?g@ii(R6R7R"( tcursortscreenR.R*R;tcxtcytfxtfytres((s7res/scripts/client/moe_calculator/domain/positioning.pytcursor_logical_s   8 ,cCsWt||||}|dkr%dSt|dt|t|dt|fS(Nii(RSR7R$R#(RLRMR.R*tgrab_xtgrab_yR;((s7res/scripts/client/moe_calculator/domain/positioning.pytcursor_top_lefts$ cCst|}t|}t|}|dksH|dksH|dkrLtS|d|dkow|d|dkno|d|dko|d|dkSS(Nii(R6R7R(R;RHtsizetpttltwh((s7res/scripts/client/moe_calculator/domain/positioning.pytcursor_in_rects   $cCsy"t|j}t|j}Wn`tttfk ry(|\}}t|}t|}Wqtttfk rdSXnX||ks||krdS||fS(N(tfloatRR tAttributeErrort TypeErrort ValueErrorR7(RRR ((s7res/scripts/client/moe_calculator/domain/positioning.pyR6s   cCsEyt|}Wnttfk r*dSX||kr;dSt|S(Ni(R\R^R_R$(R((s7res/scripts/client/moe_calculator/domain/positioning.pyR"s cCs?yt|}Wnttfk r*dSX||kr;dS|S(Ng(R\R^R_(R((s7res/scripts/client/moe_calculator/domain/positioning.pyR#s N(tmoe_calculator.domain.constantsRRRRR RR!R)R-R5R>RGRKRSRVR[R6R"R#(((s7res/scripts/client/moe_calculator/domain/positioning.pyts   ' = L $  &*   PK!C5res/scripts/client/moe_calculator/domain/rounding.pyc c@s%ddlZddZdZdS(iNicCsmt|}||kr|Sd|}||}|dkrRtj|d}ntj|d}||S(Ng$@gg?(tfloattmathtfloortceil(txtndigitstfactortscaledtr((s4res/scripts/client/moe_calculator/domain/rounding.pytround_half_aways     cCstt|S(N(tintR (R((s4res/scripts/client/moe_calculator/domain/rounding.pytiround_half_away#s(RR R (((s4res/scripts/client/moe_calculator/domain/rounding.pyts  PK! sPK!<meta.xmlPK!?-->Eres/gui/gameface/mods/14th_ua/MoECalculator/MoEBarTransient.jsPK!:9{E{E9W0res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.cssPK!o&&8)vres/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.jsPK!)l 93res/gui/gameface/mods/14th_ua/MoECalculator/MoEBattle.ttfPK!Z>bres/gui/gameface/mods/14th_ua/MoECalculator/MoEBattleView.htmlPK!v~~=res/gui/gameface/mods/14th_ua/MoECalculator/MoECalculator.cssPK!XOO<|;res/gui/gameface/mods/14th_ua/MoECalculator/MoECalculator.jsPK!"|ñaa=%res/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiency.cssPK!!x>><[res/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiency.jsPK!\NNEyres/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiencyVertical.cssPK!_B*res/gui/gameface/mods/14th_ua/MoECalculator/MoEEfficiencyView.htmlPK!n#IF;res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgress.cssPK!(<6m m :res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgress.jsPK!MzzCdres/gui/gameface/mods/14th_ua/MoECalculator/MoEProgressVertical.cssPK!'1QQ@?res/gui/gameface/mods/14th_ua/MoECalculator/MoEProgressView.htmlPK!Ggg;res/gui/gameface/mods/14th_ua/MoECalculator/card_border.pngPK!vTT7res/gui/gameface/mods/14th_ua/MoECalculator/checker.pngPK! Q%%:Wres/gui/gameface/mods/14th_ua/MoECalculator/tooltip_bg.pngPK!?{res/gui/gameface/mods/14th_ua/MoECalculator/tooltip_divider.pngPK!nw''Ares/gui/maps/icons/moe_calculator/previews/bar_eff_horizontal.pngPK!nfpp? res/gui/maps/icons/moe_calculator/previews/bar_eff_vertical.pngPK! G@Fires/gui/maps/icons/moe_calculator/previews/bar_ma_horizontal.pngPK!ηN22>Y res/gui/maps/icons/moe_calculator/previews/bar_ma_vertical.pngPK!hj?''><res/gui/maps/icons/moe_calculator/previews/calc_assist_off.pngPK!LSS=res/gui/maps/icons/moe_calculator/previews/calc_assist_on.pngPK!Bb))+res/mods/configs/res_map/MoEBattleView.jsonPK!b"55//res/mods/configs/res_map/MoEEfficiencyView.jsonPK!̀//-res/mods/configs/res_map/MoEProgressView.jsonPK!gaYY2+res/scripts/client/gui/mods/mod_moe_calculator.pycPK!Crք.Զres/scripts/client/moe_calculator/__init__.pycPK!4 -res/scripts/client/moe_calculator/_compat.pycPK!Zh6res/scripts/client/moe_calculator/adapter/__init__.pycPK!ȫ<res/scripts/client/moe_calculator/adapter/baseline_cache.pycPK!-"@0505<res/scripts/client/moe_calculator/adapter/battle_adapter.pycPK!1  :Gres/scripts/client/moe_calculator/adapter/battle_input.pycPK!)<res/scripts/client/moe_calculator/adapter/engine_adapter.pycPK!ל4$res/scripts/client/moe_calculator/adapter/format.pycPK!Eݜ ;1+res/scripts/client/moe_calculator/adapter/garage_roster.pycPK!2&6res/scripts/client/moe_calculator/adapter/i18n.pycPK!uJQQ7!Ires/scripts/client/moe_calculator/adapter/moe_wgapi.pycPK!w%8res/scripts/client/moe_calculator/adapter/sample_log.pycPK!Yp,H,H;Zres/scripts/client/moe_calculator/adapter/settings_i18n.pycPK!#f! ! ?res/scripts/client/moe_calculator/adapter/variant_overrides.pycPK!&)5]res/scripts/client/moe_calculator/bridge/__init__.pycPK!y667;res/scripts/client/moe_calculator/bridge/bar_window.pycPK!'CRCR:9res/scripts/client/moe_calculator/bridge/battle_bridge.pycPK!Ǿ  8res/scripts/client/moe_calculator/bridge/battle_view.pycPK!vX< res/scripts/client/moe_calculator/bridge/efficiency_view.pycPK!;՚I:I:<res/scripts/client/moe_calculator/bridge/gameface_bridge.pycPK!姫{zz9res/scripts/client/moe_calculator/bridge/mod_settings.pycPK!(:!Zres/scripts/client/moe_calculator/bridge/progress_view.pycPK!cc(G(G8_res/scripts/client/moe_calculator/bridge/view_models.pycPK!z?^6res/scripts/client/moe_calculator/bridge/wulf_args.pycPK!2res/scripts/client/moe_calculator/build_config.pycPK!qa5res/scripts/client/moe_calculator/domain/__init__.pycPK!s;res/scripts/client/moe_calculator/domain/battle_builder.pycPK!\9res/scripts/client/moe_calculator/domain/battle_types.pycPK!