From d67df295bd98dd834b220f15213976fb42ab695c Mon Sep 17 00:00:00 2001 From: humingxing <930621236@qq.com> Date: Thu, 15 Oct 2026 19:24:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E8=80=97=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../battle/ai/runtime/AiHeadlessBagHost.ts | 2 +- assets/script/battle/bag/BagPrepConfig.ts | 18 ++ assets/script/battle/bag/BattleBagSession.ts | 22 +- .../DailyShopLotteryIcon.ts | 34 ++- preview-template/workbench/css/workbench.css | 85 ++++++- preview-template/workbench/js/agent-assets.js | 207 ++++++++++++++++-- .../workbench/js/panels/assets.js | 173 +++++++++++---- 配置表/excelList/常量表.xlsx | Bin 11177 -> 11492 bytes 8 files changed, 478 insertions(+), 63 deletions(-) diff --git a/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts b/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts index 361de19..270ae94 100644 --- a/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts +++ b/assets/script/battle/ai/runtime/AiHeadlessBagHost.ts @@ -154,7 +154,7 @@ export class AiHeadlessBagHost { } } - /** 下次召唤费用(Const 4/5) */ + /** 下次召唤费用(按当前空开启格相对满额 5 格折算) */ get nextRefreshCost(): number { return this._bagSession?.normalRefreshCost ?? -1; } diff --git a/assets/script/battle/bag/BagPrepConfig.ts b/assets/script/battle/bag/BagPrepConfig.ts index c22f772..9d51bcb 100644 --- a/assets/script/battle/bag/BagPrepConfig.ts +++ b/assets/script/battle/bag/BagPrepConfig.ts @@ -175,3 +175,21 @@ export function applyWanReduceToRefreshCost(tierCost: number, reduceWan: number) const reduced = cost - Math.floor(cost * wan / 10000); return reduced > 0 ? Math.max(1, reduced) : 0; } + +/** 召唤按钮一次最多补的空开启格数量(满额对应 Const 刷新消耗) */ +export const BAG_SUMMON_SLOT_MAX = 5; + +/** + * 按实际补格数折算召唤消耗(满额 5 格付满费;3 格 → floor(满费×3/5))。 + * @param fullCost 满额消耗(已含省金等减免) + * @param fillCount 本次实际补入空格数 + * @param maxCount 满额格数,默认 {@link BAG_SUMMON_SLOT_MAX} + */ +export function scaleBagRefreshCostByFillCount(fullCost: number, fillCount: number, maxCount: number = BAG_SUMMON_SLOT_MAX): number { + const full = Math.max(0, Math.floor(fullCost)); + const max = Math.max(1, Math.floor(maxCount)); + const fill = Math.max(0, Math.min(max, Math.floor(fillCount))); + if (full <= 0 || fill <= 0) return 0; + if (fill >= max) return full; + return Math.floor((full * fill) / max); +} diff --git a/assets/script/battle/bag/BattleBagSession.ts b/assets/script/battle/bag/BattleBagSession.ts index e6b0bed..c736340 100644 --- a/assets/script/battle/bag/BattleBagSession.ts +++ b/assets/script/battle/bag/BattleBagSession.ts @@ -27,7 +27,7 @@ import { logBagRefreshDebug, logBagRefreshSection, } from '../debug/BagRefreshDebugLog'; -import { getDiscountedBagNormalRefreshCost } from './BagPrepConfig'; +import { BAG_SUMMON_SLOT_MAX, getDiscountedBagNormalRefreshCost, scaleBagRefreshCostByFillCount } from './BagPrepConfig'; import { MapPlaceValidator } from './MapPlaceValidator'; import { MapDragGuideHelper } from '../view/MapDragGuideHelper'; import { TextListCellState } from '../view/TextListLandHost'; @@ -59,8 +59,8 @@ const BATTLE_CARD_MULTIPLIER_WEAPON2_ID = 910001; const BATTLE_CARD_ATTR_WEAPON2_ID = 910002; import { getTowerLevelDownHost } from '../combat/TowerLevelDownHost'; import { getTowerRuinHost } from '../combat/TowerRuinHost'; -/** 召唤按钮一次最多补的空开启格数量 */ -const REFRESH_EMPTY_MAX = 5; +/** 召唤按钮一次最多补的空开启格数量(与 BagPrepConfig.BAG_SUMMON_SLOT_MAX 一致) */ +const REFRESH_EMPTY_MAX = BAG_SUMMON_SLOT_MAX; /** 项目层背包会话:桥接 MergeSession 与 MapManager */ export class BattleBagSession { @@ -185,7 +185,19 @@ export class BattleBagSession { return this.merge.compositions; } + /** + * 本次召唤消耗:满额按 Const(含省金),再按当前空开启格数 / 5 折算。 + * 无空格时为 0;按钮预览与扣费共用。 + */ get normalRefreshCost(): number { + const full = this._fullSummonCost(); + if (!this.landStateOf) return full; + const fill = Math.min(REFRESH_EMPTY_MAX, this._emptyOpenSlots().length); + return scaleBagRefreshCostByFillCount(full, fill); + } + + /** 满 5 格召唤档位消耗(Const + 省金,未按空位折算) */ + private _fullSummonCost(): number { const reduceWan = resolveCarriedSummonCostReduceWan(this._currentCarryPassives()).reduceWan; return getDiscountedBagNormalRefreshCost(this._normalRefreshUsed, reduceWan); } @@ -462,7 +474,7 @@ export class BattleBagSession { if (!this.canNormalRefreshFill()) { return 'pool_empty'; } - const cost = this.normalRefreshCost; + const cost = this._fullSummonCost(); if (slot.gold < cost) return 'not_enough'; if (!slot.spendGold(cost)) return 'not_enough'; if (this._ownerPlayerId === 0) { @@ -540,7 +552,7 @@ export class BattleBagSession { console.log('[BattleBagSession] tryFillEmptyOpenSlots: player slot missing', this._ownerPlayerId); return 'failed'; } - const cost = this.normalRefreshCost; + const cost = scaleBagRefreshCostByFillCount(this._fullSummonCost(), count); if (slot.gold < cost) return 'not_enough'; if (!slot.spendGold(cost)) return 'not_enough'; if (this._ownerPlayerId === 0) { diff --git a/assets/script/ui/PopDailyShopLottery/DailyShopLotteryIcon.ts b/assets/script/ui/PopDailyShopLottery/DailyShopLotteryIcon.ts index 2e1b39e..ba5b7b7 100644 --- a/assets/script/ui/PopDailyShopLottery/DailyShopLotteryIcon.ts +++ b/assets/script/ui/PopDailyShopLottery/DailyShopLotteryIcon.ts @@ -380,7 +380,7 @@ export class DailyShopOwnedDesc { const nameNode = descBg.getChildByName('name'); this._setLabel(nameNode, parsed.name); DailyShopLotteryIcon.applyNameOutline(nameNode?.getComponent(Label), parsed.quality); - this._setLabel(descBg.getChildByName('desc'), DailyShopLotteryIcon.battleBuffDesc(parsed)); + this._setDescLabel(descBg, DailyShopLotteryIcon.battleBuffDesc(parsed)); this._raiseDescLayer(descRoot); descRoot.active = true; } @@ -471,4 +471,36 @@ export class DailyShopOwnedDesc { const lb = node.getComponent(Label); if (lb) lb.string = text; } + + /** + * 描述文案:固定宽度、按行增高,避免预制体 CLAMP+矮框裁切多行。 + * @param descBg 描述底板 + * @param text 描述全文 + */ + private _setDescLabel(descBg: Node, text: string): void { + const descNode = descBg.getChildByName('desc'); + if (!descNode?.isValid) { + console.log('[DailyShop] descBg 缺少 desc'); + return; + } + const lb = descNode.getComponent(Label); + const ut = descNode.getComponent(UITransform); + if (!lb || !ut) { + console.log('[DailyShop] desc 缺少 Label/UITransform'); + return; + } + const width = ut.contentSize.width; + if (!(width > 0)) { + console.log('[DailyShop] desc 宽度无效', width); + return; + } + lb.overflow = Label.Overflow.RESIZE_HEIGHT; + lb.enableWrapText = true; + if (!(lb.lineHeight > lb.fontSize)) { + lb.lineHeight = lb.fontSize + 6; + } + ut.setContentSize(width, ut.contentSize.height); + lb.string = text; + lb.updateRenderData(true); + } } diff --git a/preview-template/workbench/css/workbench.css b/preview-template/workbench/css/workbench.css index 717ed4f..c941aea 100644 --- a/preview-template/workbench/css/workbench.css +++ b/preview-template/workbench/css/workbench.css @@ -1080,7 +1080,7 @@ body { .pw-assets-row { display: grid; - grid-template-columns: 1fr 110px 72px; + grid-template-columns: 1fr 90px 72px 36px 72px; gap: 6px; align-items: center; padding: 4px 10px; @@ -1127,6 +1127,89 @@ body { font-variant-numeric: tabular-nums; } +.pw-assets-ref { + font-family: var(--pw-font-mono); + font-size: 11px; + text-align: right; + color: var(--pw-info); + font-variant-numeric: tabular-nums; +} + +.pw-assets-meta .pw-asset-kv { + display: grid; + grid-template-columns: 56px 1fr; + gap: 6px; + margin-bottom: 4px; + font-size: 11px; + line-height: 1.45; +} + +.pw-assets-meta .pw-asset-kv span { + color: var(--pw-muted); +} + +.pw-assets-meta .pw-asset-kv b { + font-weight: 500; + word-break: break-all; + color: var(--pw-text-2); +} + +.pw-mono { + font-family: var(--pw-font-mono); + font-size: 10px; +} + +.pw-assets-refs { + border-top: 1px solid var(--pw-border); + padding: 6px 8px 8px; + max-height: 160px; + overflow: auto; +} + +.pw-assets-refs h5 { + margin: 0 0 4px; + font-size: 10px; + color: var(--pw-muted); + font-weight: 600; +} + +.pw-asset-ref-item { + padding: 3px 4px; + border-bottom: 1px dashed rgba(255, 255, 255, 0.06); + font-size: 11px; + cursor: pointer; + border-radius: 3px; +} + +.pw-asset-ref-item:hover { + background: rgba(47, 111, 237, 0.15); +} + +.pw-asset-ref-item::after { + content: '双击定位'; + float: right; + font-size: 9px; + color: var(--pw-muted); + opacity: 0; +} + +.pw-asset-ref-item:hover::after { + opacity: 1; +} + +.pw-asset-ref-item b { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pw-btn-mini.copied { + background: var(--pw-ok); + border-color: var(--pw-ok); + color: #fff; +} + .pw-assets-tag { display: inline-block; margin-left: 4px; diff --git a/preview-template/workbench/js/agent-assets.js b/preview-template/workbench/js/agent-assets.js index 467a1eb..568f557 100644 --- a/preview-template/workbench/js/agent-assets.js +++ b/preview-template/workbench/js/agent-assets.js @@ -455,44 +455,213 @@ }; } + /** 更稳的位图预览:HTMLImage / ImageBitmap / ImageData / nativeUrl */ + function imageFromAsset(asset, type) { + if (type === 'SpriteFrame') { + var tex = asset.texture || (asset.getTexture && asset.getTexture()); + return { + img: (tex && tex.image) || (tex && tex._image) || null, + rect: asset.rect || asset._rect || null, + nativeUrl: (tex && tex.image && tex.image.nativeUrl) || (tex && tex.nativeUrl) || asset.nativeUrl || '', + }; + } + if (type === 'ImageAsset') { + return { img: asset, rect: null, nativeUrl: asset.nativeUrl || '' }; + } + var im = asset.image || asset._image || null; + return { + img: im, + rect: null, + nativeUrl: (im && im.nativeUrl) || asset.nativeUrl || asset._nativeUrl || '', + }; + } + function buildPreview(asset, type) { try { - if (type === 'SpriteFrame') { - var tex = asset.texture || (asset.getTexture && asset.getTexture()); - var img = tex && tex.image; - var data = img && (img._data || img.data); - var rect = asset.rect || asset._rect || { x: 0, y: 0, width: asset.width, height: asset.height }; - if (data && typeof HTMLImageElement !== 'undefined' && data instanceof HTMLImageElement) { + var pack = imageFromAsset(asset, type); + var img = pack.img; + var data = img && (img._data || img.data); + var rect = pack.rect; + + // HTMLImageElement + if (data && typeof HTMLImageElement !== 'undefined' && data instanceof HTMLImageElement) { + if (rect && type === 'SpriteFrame') { var ih = data.height || img.height || 0; var sw = Math.max(1, rect.width | 0); var sh = Math.max(1, rect.height | 0); var cv = document.createElement('canvas'); cv.width = sw; cv.height = sh; - cv.getContext('2d').drawImage(data, rect.x | 0, Math.max(0, ih - (rect.y | 0) - sh) | 0, sw, sh, 0, 0, sw, sh); + cv.getContext('2d').drawImage( + data, + rect.x | 0, + Math.max(0, ih - (rect.y | 0) - sh) | 0, + sw, sh, 0, 0, sw, sh + ); return { kind: 'image', w: sw, h: sh, url: cv.toDataURL('image/png') }; } - return { kind: 'none' }; + return { kind: 'image', w: data.width, h: data.height, url: data.src || '' }; + } + + // ImageBitmap:画到 canvas + if (data && typeof ImageBitmap !== 'undefined' && data instanceof ImageBitmap) { + var c2 = document.createElement('canvas'); + c2.width = data.width; + c2.height = data.height; + c2.getContext('2d').drawImage(data, 0, 0); + return { kind: 'image', w: data.width, h: data.height, url: c2.toDataURL('image/png') }; + } + + // ImageData + if (data && data.data && data.width && typeof ImageData !== 'undefined') { + var c3 = document.createElement('canvas'); + c3.width = data.width; + c3.height = data.height; + c3.getContext('2d').putImageData(new ImageData(data.data, data.width, data.height), 0, 0); + return { kind: 'image', w: data.width, h: data.height, url: c3.toDataURL('image/png') }; + } + + // TypedArray / ArrayBuffer 位图 + if (data && data.buffer && data.width && data.height && typeof Uint8Array !== 'undefined') { + var c4 = document.createElement('canvas'); + c4.width = data.width; + c4.height = data.height; + var ctx4 = c4.getContext('2d'); + try { + ctx4.putImageData(new ImageData(new Uint8ClampedArray(data.buffer, data.byteOffset || 0, data.width * data.height * 4), data.width, data.height), 0, 0); + return { kind: 'image', w: data.width, h: data.height, url: c4.toDataURL('image/png') }; + } catch (e1) { /* */ } } - var im = type === 'ImageAsset' ? asset : (asset.image || asset._image); - var d2 = im && (im._data || im.data); - if (d2 && typeof HTMLImageElement !== 'undefined' && d2 instanceof HTMLImageElement) { - return { kind: 'image', w: d2.width, h: d2.height, url: d2.src || '' }; + + // nativeUrl + if (pack.nativeUrl) { + return { + kind: 'url', + url: pack.nativeUrl, + w: (img && img.width) || asset.width || 0, + h: (img && img.height) || asset.height || 0, + }; + } + if (asset.nativeUrl) { + return { kind: 'url', url: asset.nativeUrl, w: asset.width | 0, h: asset.height | 0 }; } - if (im && im.nativeUrl) return { kind: 'url', url: im.nativeUrl, w: im.width | 0, h: im.height | 0 }; - if (asset.nativeUrl) return { kind: 'url', url: asset.nativeUrl, w: asset.width | 0, h: asset.height | 0 }; } catch (e) { /* */ } return { kind: 'none' }; } - function previewAsset(uuid) { + /** 反向引用:谁依赖了 uuid(资源/节点名) */ + function reverseRefs(uuid, cc) { + var deps = []; + var depUtil = cc && cc.assetManager && cc.assetManager.dependUtil; + var assets = cc && cc.assetManager && cc.assetManager.assets; + if (!assets || !assets.forEach) return deps; + try { + assets.forEach(function (asset, id) { + if (!id || String(id) === String(uuid)) return; + var list = null; + try { + if (depUtil && depUtil.getDeps) list = depUtil.getDeps(id); + } catch (e) { list = null; } + if (!list || !list.length) return; + for (var i = 0; i < list.length; i++) { + if (String(list[i]) === String(uuid)) { + deps.push({ + uuid: String(id), + name: asset && asset.name ? asset.name : String(id), + type: fmtType(asset), + }); + break; + } + } + }); + } catch (e2) { /* */ } + // 场景节点名:遍历当前场景找引用(spriteFrame/texture 等) + try { + if (cc.director && cc.director.getScene && cc.UITransform) { + var scene = cc.director.getScene(); + var walkN = function (node) { + if (!node) return; + var comps = node.components || []; + for (var c = 0; c < comps.length; c++) { + var comp = comps[c]; + if (!comp) continue; + var vals = ['spriteFrame', 'texture', 'spriteAtlas', 'skeletonData', 'clip', 'audioClip']; + for (var v = 0; v < vals.length; v++) { + var a = comp[vals[v]]; + var au = a && (a._uuid || a.uuid); + if (au && String(au) === String(uuid)) { + deps.push({ + uuid: node.uuid || '', + name: (node.name || '?') + ' / ' + (comp.constructor && comp.constructor.name || ''), + type: 'Node', + }); + break; + } + } + } + var ch = node.children || []; + for (var k = 0; k < ch.length; k++) walkN(ch[k]); + }; + walkN(scene); + } + } catch (e3) { /* */ } + return deps.slice(0, 40); + } + + /** 详情:预览 + 路径 + 反向引用 */ + function assetDetail(uuid) { var cc = global.cc; var asset = null; try { asset = cc.assetManager.assets.get(uuid); } catch (e) { /* */ } - if (!asset) return { kind: 'none' }; - return buildPreview(asset, fmtType(asset)); + if (!asset) { + return { kind: 'none', name: '', bundle: '', path: '', uuid: uuid, ref: 0, usedBy: [], refs: [] }; + } + var type = fmtType(asset); + var preview = buildPreview(asset, type); + var path = ''; + try { + cc.assetManager.bundles.forEach(function (bundle) { + if (path) return; + if (typeof bundle.getAssetInfo === 'function') { + var inf = bundle.getAssetInfo(uuid); + if (inf && inf.path) path = inf.path; + } + }); + } catch (e2) { /* */ } + var bundleName = ''; + try { + cc.assetManager.bundles.forEach(function (bundle, name) { + if (bundleName) return; + if (bundle && bundle.cache && bundle.cache.has && bundle.cache.has(uuid)) { + bundleName = name || bundle.name || ''; + } + }); + } catch (e3) { /* */ } + return { + kind: preview.kind, + url: preview.url || '', + w: preview.w || 0, + h: preview.h || 0, + name: asset.name || uuid, + type: type, + bundle: bundleName, + path: path, + uuid: uuid, + ref: asset.refCount != null ? asset.refCount : 0, + refs: reverseRefs(uuid, cc), + }; + } + + function previewAsset(uuid) { + var d = assetDetail(uuid); + return { + kind: d.kind, + url: d.url, + w: d.w, + h: d.h, + }; } if (global.PWAgent) { @@ -508,12 +677,14 @@ } }; global.PWAgent.prototype._previewAsset = function (uuid) { - return previewAsset(uuid); + return assetDetail(uuid); }; } global.PWAssetsUtil = { collectAssets: collectAssets, previewAsset: previewAsset, + assetDetail: assetDetail, + buildPreview: buildPreview, }; })(window); diff --git a/preview-template/workbench/js/panels/assets.js b/preview-template/workbench/js/panels/assets.js index 59ada5f..c6633dd 100644 --- a/preview-template/workbench/js/panels/assets.js +++ b/preview-template/workbench/js/panels/assets.js @@ -47,6 +47,7 @@ '
Zp_X1kGbO>pe6BzUDo7Ut+)qBp+s3 ziRjR+Qe+X9KV#{~%2qcs>Q`WO9w&NMhXyXvRjP~4ki9uhL>elqQeBvqaGDpy_%u?{ zu0t>Ti{rw_c&U8OzNtc^MyHa$x~%GLAnNX7)VzT{5kwP=@t**V&j);E`Ql3OxVUOIrztfuPoK9X6Dqu^M~ zpV-ih#3$|!YU%v7wI1e@t&{aGl>Q&US6K?AC%A0;--eGOVI;4odgwf6U03Ty7?IfC zD8Ny^9d3GfwR&=MMtx+kZgH{UjeJ-?a~_}vq^)c?7|JdlkwM7!rJ~MW7liH!=|xtK z{^hPJ`T(04nDTxv6Dews@1p7$?b*dj4?*IW;&{1=XTfQwc;*4*6};6N$K%K>m8)~e zp&oAYjcSCvhbxc^7dy#ta#)InCwcWU;fzj+zWqFjwm_^le~`1ffPmFNp5tY1DL=Ro z2nn&+ Xf7v?O;hS7eE#gI@SBZ(qvs{esu#{a6v0!Kb9 zpSpv7W^6S>j<$|3k+HfO^+AUH&7xU1Uaf$*!B?eD{44yLPNvl{{ )#;d 7e>OIKLFa6`Ml@W zYwwB ^`-x)5Fsw2M3i ziO!8|4JF@$ hc_(SB$if+!m!Z z&wQ^wM=P#mYU8fUu=c^2{cy@LyWQ{>PkTyuzm>HjcDUk{U{*%NJRXG&ps7fhcDAwz zvCUXs>6H;}XbPX@c~ZSr)(+UE&x+`LY=Kf`^ht4UXH>tcO6`9dLbjjvf6tQDzVh|z z|5(+@t9ZJnSp7wjiQ*hjbW^0?+*MB5x*)w==c1 &MbpD GeO)Mnih~?3qQ_D!<>`;@!n$g0+cqZ%(Gs!7(1BjzbY}*uhcZbM^ zScib$>H5)NC;D)gNm$Gm7^QPD>aNn?-!2!xO?3hYE@-413?3h8y_x03;rUC8_dbcB zxEs1XHWNd<9;kk!&5Vg@!om>PYLS{$HaL}+Pyd9XjZOc#{&`Vov$G-gVlOY4qL^kw zDBZR9uoBF4Fj;y%2^I^q;ZckaGfJjBwaG~l`g^@mYC{zYKYbXE*VV^xBAi*AE(+YO z9`<4n0D@$|ulNM4*f+$&zpQU!N_JEyOL8B$i@IP17?D#Cu<+avx1CjNUpt?Qq?y#v z8|rO(aXfisG;CZM;-;V%naI+jvZjGXn+gApMe)tn;Aw41an5goDp(Wve6OYtokOv> zf-i+Jh|J|Ca-=nUq`TZ(B7ogLwL}Nkba<36S-<5AM@OC?v Ug+niKmjG7bVo9A(Y(^&G_>h%k E-5EOZd zX2q*n6WYqYz?O_j&K&`c+7gUUVLlHc6GWDLH{kc-(-yZOzB%L>j$bRlX{|TOcl6n{ zm)u3G!?RkTjn}^cEYm>^|4fhd D8)1MBU7YYJ-%kbZH@*$dI{AE)ldZ@Z2<) z$N@sJa9NCfj#awMWRwk=IR6?x`+Hss?y*i5HIeNMO`QD {M!o$Qe27wQ(%>v4 zX04ufbk26j&&D&yqxwfz)JFjAucFjq#b~FHaM>JIya&H72f3EJ!8H4xeQ`*yk-P&r zIpz1J_Xf6KP!lEIimts 59Ue|}~58oulzNUUm)lk@V zRG?X1comc|kQ&K>I({+OQtLwFN?k+-MT8=ET#w7Gu1^X^fR*M@YV%kXa1NF0I!^K5 z@zr{(Qb#nk_`RScP?D>wghHF4g0>TBLzjutUgt$!+=DhO!-C}e1T+PcA0b8R?y2Q4 z^{kMefSU8jFZGgQlsTImb0|SkM*wJAiJR&1lwze>;0AB(AR-4WEw^nqgb*QHilyJ3 z%gIAGG Z|+6s<8(9=%Ojap~oeVPPE!Q)lIC@0b@QBV}pibh~`)1jvlR$ zcO2KRlfn7U|C_{@og28@z%{&Jtbv0EGr@2e31H()tcdCKAP_8(g%F0zObY*n9>&3( zg!-SBA#8{lLiXIXGJ9$uK0Z~pFQ2miXMqDzKWS1J35z&N)zdT7Q>6>TWg~~-U?9SR zSkT~i8DKFiWaR%``xCM4$&~cz`z-&OqBFvd>B(UmEI8! 1k|>Ey1a2HA%0@%}pUw~&2t@o$ id6IwEyhVgzAdwQPDIz^Jj-ETFxFD3L0}e7j|NR%_WBGpo delta 7161 zcmZ8m1yohf*1vRjcU>9@X^`%|ba!{Ra42aIxrEXs(q3t#ge!0f2`T9gkrt%{KK#G; zz4xteuXSdxGrP|G&di#by|+!PjbSB7K-`csH3SI+azF-wh(M3r+aBWQ?c>j9@9pQv z8{+8^k*TWz=O=x!hW4N^9G+XzWQpgA!4>Yu|IJ}DC2re`yVX_eY1>`+bWkl_^2?6B z<(K}vYL!Ecr#-UyU3#2lEHTd@Wtkm|mHUpuKkc`vMzgn--ZCn&^Sk7&tb&0ur?RiG zNkhEFU7KerdhtmTN|NsG@gImJIXbAs6Z|$Szp}O+SGTqAZpL~eVZ Ea?ivBekQ~*%ICL-W!ie2fuj2K-iVmy3w8BmWZ@&zJcOKm) zJ<}YCa2H}N)fhmMw$XFaS1yc~ el-tde5*C+ z1u3%sqk+p@OkBKLuR4Z^d$EOdhKyKTo_}DzMTcmhpprg9jR{K7M&FceEy8qw@}MvS z?s5EtFV=AG2r`4UQWs~HEW6}gOC38`<}=-v$%KeV+AP%{!ne%ALyvYm cL6^?dyvijBEYj zObV95Z(iwz{djl5XXQpMjl3wQnG$Mw5{N0^UDl6DV s1T zuIwCcKwxnBF;9a0pu$R)`693dNA!JkrEZAEBME&_w4V^da!oE}(nE8V5(<#7J|ZkE zDoK_Jj}kPm!KmY;Y6{azf1Ux|W7*T #_qsyQpoR{j%3+m}zCNBr z2Z0!%glG&vn(30)k}_cg-z30zMXv^Syha|CQ $QuBflDURxMF z9K)}c4TDt_HVHaAPtbpzxf}AnWeYR5v~EiXEEpsAt-#L@GH0-wJF^BN?|n#A?jUrn zhST&j688-^S6lE2nU&(jWA}%e8A7>uh2C`Qgbg4>wD>aLxaIwgX}AGK;^Cr~HQs4U z_?yciZ9{WG*R`?f0XyL}<6lgzRL37R{F*y0yLBBqLzimdHqd~YYV`HB-nk+Aridl0 zEbk>lb`$P%TT%_0v+K;A#I>H)0ME7K_=U=qi6<>*T;6+aeG-@Xx@AdDN43X4md;SX z(*3|@(T_^{p8OqVCSgd?^midiy4!`_brTpm>%6}(srTLF@u*wXW ^yW9p?C`=s%XV`V-PB3cvnTP`6OckT(;nn4wH~-Ws9+FG^o%dx0bz zTc{3#4XY|mhaAyQ@2&NffOukm>sVkgtQbi1>Is-KI;v@N;#k}*4wLL^*vel>?rpG- z`!iJ(srzg62WYvGYQHstChw*sQvakT`uaym^$)K_^yE)#F4peDLsLCBPPz6tpSI(A zFOaTQqkd0|ExwkPU~{69CQ{U54w30l#6bjfUcAR4apWcH>Qpop(YXH6uc(oWxoQcN z84?Q-gze>^w?x94x&L;R&3x-evo!6f9_H#~qTiCbcrrHvGk3TsWxe%TYk7y6E_j&j z=sIhQJ{I)eY4X>-i7SKpaSkIqZ4mfcHoZh2%@#%(0hlaLtOcSaAchjbilp|6)XeHB zQM*@MZ&b#jKkl8N1#kl0H5m_I0cR2Jv7y9TLfurN$HokGPe&a2zJz#XeKcrezcey1cOM^oC0HrU Row8z=*F%%PxX?sp z5D*iWaS^F=h{>l{@{&&wA2jij>y<@-MRB#q3EKOri`FYuUeOeSYW0EC56dx;(S)N~ zBKYM{EM&jM*-7lDeDYGs+uKb2l%r3sC@`nC8xqYSCgGdyF#3W1fCdj^{y}UUFEn{g zTfY60<0rKmtM61kG>Dx<7&EZzdEoSe+prA ;GDQY`Qb7O31~XOol^%T5#hK*Pi`d|ELOXyy@^Hyq-q)y5dJNk$c5 zgTLvC6-@I=en#`Ligme<_@LZAR(DXjV5r}DQgrI(cTE6Gw8(%!_;yo&Lv)j+Vu7R$ zvj~R{|43qry-^4*QCpMP*;IDk1a^{tucNw(zHmNk>r)+m^=E><)Yvbls8s9a&H@%a zzQAO*?DqT^0LKB&-W81mEHgjllkd$-dA1XB`;3>mgK|}{fY(tdo*~~7TsyToR@me* zJ6=A;w<}jqz!HPVDBy$6+0z;%s_6%%VWTgkT%||E60NfFNqkCL;%M8Cp5iYD?Fh5# z2&mKM1ep4V!6?UV)nf3(eJ&ko+k-3Ry+e~9W7wzzkKPKV!Iw6J(ULCe{wr2CS-zC6 zU+s|b_k^moNZ+HRqJ-6o&oKi qxWZ)kW%h)ZXAI#|huf&I~ zqYvLik-LZ`3h#0%Q(=7V+OiSoBG@|~XmTwUg5P^23-3y+(>AF7%!!4g(yF$}F^mC% z@6W7W+fGD>xm@ F2=ooV*wYhLue@APfNckC85TzV10*?N}MpO z3MGF8>DfQ-C$RuLjMBE{$H38?bZqNB+R%S%3(fyRDo=&0LhXw!3a7W5b)5F&;$soT zk0JTLZhvDp-V+**$n*jW2FSysuR5h4VI$1riNOWu$YP!r6yvj!iNfz8$pbsm>I3i9 z4&!Y$1mb(H-VI1!v=IcpoK3muKCn7aU=X%+! uo!m5kU`&shD(nQ=nbfN6k&rv)Vd%L-s8z5#DmX2Ak@Rr|L*~B z*22?!X^!k(+U6nJ1{Q(oq)|~tQJK?ZA`*?f0%4@$x1m8cEAv3k+SfI(38u{8{nAB_ zh$>rY3`Co2K{OJibOyr7E40p?xlC`Gdtv_8h;Y6@PTgvyDI&t3N6SA8{DGqIWA2W? zyY@ZK-~yZVo4d*y&m6;n?`?PKOENAsG9Mj1g$x`C7w^)Kt|Q)67m1<#y7}GK+aipq z^K5UobSn; fHTx=OTtFuH2hUiO7w zhta`;m-Wi(0YSJCA1#L`@C_iyuOYJ5Lln+S`b 0M1GBsjbOi%Cxr zkG0pKg~pC3n&2KyHLDzi<%59-la$7jHpTMJ?%7|rJcy6zy2{3_Z2-DAXRrss)jKBV zwulLWEJ7Dl-9h7 AUZ_C*_i!Nt=!V20RxeffcU}m35xD8lc#3Tbc}4 zXpA28cN}xWdo>T9<^gQ_t)zla4;HM8C@3hKOc(bE1rG*s@N(CcJz^nm{9(yP4h91U zEh!FVHq;a_4*%t pFHuE_Uh&&F|ag=%Fld(75!%!*g}EGlurS6(1pL|ROwNCMrH_nF*F<|;vy5^`%X zOW0C9fqtmnrP2ZYuizT0ejC#m(Gg|e#pD-I(R=oS2$N&Uk7Xg_)XJ9L8~Ah5-5b9p z$3LJHo>TW&Y=WH8a?3`)P7y4$%Ud>&&l|7?OofzpnTl#PmCjP9#k(3b7kG5*D)m11 z5H_x3Q};Hibp#sBjA?r;O!TZNH0%WJbBv 3t)5)ogK4fs&D&kq*-ig&TZq? zZRTkptS{PJz=5WZtE-HdpP#ueASR&RYc;!$YaX%4^H#OLIX-$VzA!SyZf(vPp}G6x zIgL m^%@7?Eqg*I}e;ioh#yU3ed{u|6Kb88O+LEm%US4h5_FK9ku^ zzq0^3t}U=p4ic2_I5o8!<6e}PRP~UuD^+SD#yQL*GjUj{``joJ^k<`I4}_=s*$F4> zvuEj8T_KJVIEOcD*p1uAXz(DBPwL$ke)tERt3EUc-PuFFZu}Qcr? O#-9yq0OH*bMr&c-wqIA|@r-F3qJ#bp1lSQeZ6taU>l~dGu90n5z1Rm+4(3IO;== zP(Tp!X*|fset6tF HFT_mx_X9S5{US1 z$q)JkjB?CX>6nWI_-YS{Nk}XvJd00xpYJncsXsy%Ipk1Q96=_Q?%~}*Dj;&&lc9lR zsI5X8NbV-~hUB2&I?+u+3mZmLsmg)Z1?+rpRH9S1_#o5QhL$GbSKr0?T1AWdWE&se zHjqXkXHnpUY4nr#g@1>^3;c302#<*6395~D4RJ(Ij7V}UVxHSX#gQ;2ORH4r Q3WQq+3{Ljx<5P{`Pavvb@U*eR;<_Zu%x`r9KYI!Kn;%Qu~WIy;q z2(-RPizdsg2|J5Tv3f;0XdG*YH`BiFW)ZUSv=$@7X*X_u QkWcLnGgk$ z9^WxzrhBw5MFJYl`ox(-Ptu!|R)81W#~i(VAVMugz6Q-jsxbQI^RpmsYcrt}hT_$* z`N>v*ZrFAP2Pd=K!8Tl$b})I;k3uN>M{XZ9%+}niVbuV8X=6v0Ttw~sS0$`lZTwYs zi|8_Iq-SAWvwzBAi?Nx#aeC+ZKoG);id>x8^=s2E8~&vE(eGNmJeH$IS3sz}NOz}{ zq20TWElP>|7fjSPRAFGpM-?T+=9OEd5l_KHhZ=FI->1MSB!?E37}@x`DN~`!r14y& z*S_T_C(;lSG*4-#j@$D#RAY`R`Q-*O-wAb#4blsyxJrqzn}G8xI$qRUh56XD@4jT} z*qZluAr}`%#aRIPaMVjNDxj-gjI%tqx7>rH{C$zuy|4G5+vzE2!nBS|QP=GYWUR!` z^r5+&4H@2ainm@IGs7ta%9jjE#2mo_Sd_!?)w~L;7~xD=drr3KHG~>=D*f{9&2{XQ zccj$azQVYo>R|ymQbv-~l}Ct3*jzILt@kR6$MIsV3G>MTFKnpv5@7uBGJ$5ew1^MN z^8SFG*3>+aEU?OiDSo-*p+n|wec-CiSMhWghmAFD #Obep_YrHgvv>sj+smadeiNY)0yt!I`hBVHJJ zgMn71@ bp%^{~U%$}oF%X97{cSWOvVBu#PI(ZT s@ z{L!0&*%8-4+2oV_x1J%T37=R*u?nc@$rdn`pzYv9MdV~6>)rJw6J29 up9P)mOGnxu*Bh;sWDLocCn(`F#CK)Aw7OY5$V@)gh&-;Aw3mNZR0Bhp9fx}qkW zK*rM8!iDEoBmO9^H>7nCfy6gNxWL2tLsY_++b|*n3mT*@`pwV2RF0$rQP#B4?bGj8 z15U1(c+09Aw?rp#3@a9b(&3`$r{tu64CAAh41f=9`l7*?JQ3x(tF9iDWbZ!O8U+W5 z)+oC>I|t7{9S!UFrGaqXFOQy27q;JpM@zNQU7_^Sc(rawJ?UKvTpB-ohw>$pD&iR- zc8AF6dUX`FM&Fvld>&V@{5s3iT#(2$1C1{AX9nTrdzt^6LEDrKuOM)oKm~zLns|tV zkbtsiT`(~Cf~_aF#bnCN+oexW;fLj`ZsHx;VTDYs7+tBHutTr)5!Pi`R!quX2j`U? z1w?OZOOoS^s^!*&yMASMHi+b;cNPjGcw=my`-yXsVQ+ot^U-Fdn117#Cz&;!oXN%c zvHtUs8&jlh+QqR+o* z2>G?^#Djbxt}6*=OeprS$gGjs1I#t8?}J9>NB*GDzzV5n zQ5xHI3KEUFWnXBo;WELem~cg!Y$b{y=p8 z9A(Qqd*>dh+Q`W#&V6F{2it`9kecrLlH{^qml=M8dJ>^tg9cLN`~haN-)ZnI+g>$l zh?jWdb`o|c%jc#k%5}bdngRLhUiAbGdwy6S&M1N%QgUC T;jEhNmcf&&IniVT`6P{7v8KTfP)s9qFN2euVe2 zVs`T;($H{~#=N7(Euty|37p+``;H&!VifNaHTtR|olf%%%QqfzYh&}k@?@ZdSCXzJ zcRmHL+stmkkLphIUa-~aR1Cd{+Tc*6#M@^_mXZP^+TRa4N4Y14%h=B8KDPbH#ilV! zdbHBum|Fr3XO9xeY3u&yeKMC~w1s~%xb;lu-A;ZTkdsyyEz8%79jTWyqo<+J)v)`= zqEfFU=ZUrl;E7iJ)SkEmp4{j~^-2GMMbEhn-FPjFfqvxA;8wp&)I(V!XQw9U$lJDv z9sM%p9#3QC (q Ez z1~5`sA{M{&Ns>Jud#iYqx(H%^^6P8?9gi9^{oDj58U1=C;|=+<@XCm?%!fD2WuwaS zf*~|l)}_Aw$fznX%rVSM7uEY0Co!|;{g_7pE>;#d&9NGXkF8MB+*|2qpT29XtQXwn zBarwGdwN0tEKA_une9#4OOF^4xyRDN?&Cx7uUluZx1YP6x3~M>duQ4!Ep7N?#`{ur zx$nG4LMtD;j4k_$WTk|+q)zLZYuycdqop4BH;*`qWcnlyQ{R)I*_2vTBlI#7(AUSSwm8m#aUc4i$>RSSM&Rd@KujDj% zY!`$W$rxED+@|4qIvUkB3zE!T4c;BfE9Oc`o6;6oRI&~MarK_-{Hh$j`8Us5$h_Pq zlyx;t@7?`2V6H2?tU~wv-sWFbSv-C+DpftDW @YOU z^V^CMrKTkTxfZy^alI$(qf09tCo=?WZua~T2XPKu-W!n_^d9^Z0=|+&&(qcvB)n8r z828CZE5kR_9F3V~6i#0(hZ0+Qs}{C-8*k1O6!h-~0>5&UD$NMy=pKJ+7<6w!;_g?J z-$wQCRoTT`c1VJ6#`Z(Ey n2SZp6B;lpE%i{x=4{v{+3<6}z% zHQ