From 02d9063a112d48baa093fcb8aa7d0d3e381784c0 Mon Sep 17 00:00:00 2001 From: admin123 Date: Tue, 19 May 2026 18:50:03 +0800 Subject: [PATCH] feat: add extension update check --- README.md | 7 + dist-release/background/index.js | 31 +++ dist-release/manifest.json | 3 +- dist-release/popup/index.js | 213 +++++++++++++++++- docs/aigc-user-guide.md | 25 +- docs/internal-extension-distribution.md | 23 +- docs/【超简单版】插件安装使用指南.md | 10 + package.json | 1 + release/latest.json | 11 + .../star-chart-search-enhancer-internal.zip | Bin 98986 -> 100730 bytes release/星图增强插件-超简单安装使用指南.pdf | Bin 612279 -> 627519 bytes scripts/manifest.mjs | 3 +- scripts/write-latest-manifest.mjs | 35 +++ src/background/index.ts | 55 +++++ src/popup/index.ts | 142 +++++++++++- src/popup/view.ts | 89 ++++++++ src/shared/update-check.ts | 94 ++++++++ src/shared/update-config.ts | 2 + tests/background-index.test.ts | 44 ++++ tests/manifest.test.ts | 5 +- tests/popup-entry.test.ts | 95 ++++++++ tests/update-check.test.ts | 49 ++++ 22 files changed, 919 insertions(+), 18 deletions(-) create mode 100644 release/latest.json create mode 100644 scripts/write-latest-manifest.mjs create mode 100644 src/shared/update-check.ts create mode 100644 src/shared/update-config.ts create mode 100644 tests/update-check.test.ts diff --git a/README.md b/README.md index 9d6c611..346b3d3 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,17 @@ npm run build:release npm run package:internal ``` +生成更新清单: + +```bash +npm run write:latest +``` + 生成结果: - 构建目录:`dist-release/` - 压缩包:`release/star-chart-search-enhancer-internal.zip` +- 更新清单:`release/latest.json` 说明: diff --git a/dist-release/background/index.js b/dist-release/background/index.js index df638d0..0ed7e76 100644 --- a/dist-release/background/index.js +++ b/dist-release/background/index.js @@ -3203,6 +3203,18 @@ }); return true; } + if (isDownloadUpdateMessage(message2)) { + void triggerUpdateDownload(chromeLike, message2).then(() => { + sendResponse({ ok: true, type: "update:download-ack" }); + }).catch((error) => { + sendResponse({ + error: error instanceof Error ? error.message : String(error), + ok: false, + type: "update:download-error" + }); + }); + return true; + } if (isBatchSubmitMessage(message2)) { authController ??= createAuthController({ authClient: createLogtoAuthClient() @@ -3270,6 +3282,18 @@ return true; }); } + async function triggerUpdateDownload(chromeLike, message2) { + if (!chromeLike.downloads?.download) { + throw new Error("chrome.downloads.download is unavailable"); + } + await Promise.resolve( + chromeLike.downloads.download({ + filename: message2.filename, + saveAs: true, + url: message2.url + }) + ); + } async function handleAuthMessage(authController, message2) { if (message2.type === "auth:get-state") { return { @@ -3323,6 +3347,13 @@ const candidate = message2; return candidate.type === "download-market-csv" && typeof candidate.csv === "string" && typeof candidate.filename === "string"; } + function isDownloadUpdateMessage(message2) { + if (!message2 || typeof message2 !== "object") { + return false; + } + const candidate = message2; + return candidate.type === "update:download" && typeof candidate.filename === "string" && typeof candidate.url === "string" && candidate.url.startsWith("https://"); + } function isBatchSubmitMessage(message2) { if (!message2 || typeof message2 !== "object") { return false; diff --git a/dist-release/manifest.json b/dist-release/manifest.json index 9df1c42..669a3bb 100644 --- a/dist-release/manifest.json +++ b/dist-release/manifest.json @@ -53,6 +53,7 @@ "https://*.xingtu.cn/ad/creator/market*", "https://login-api.intelligrow.cn/*", "https://talent-search.intelligrow.cn/*", - "http://192.168.31.21:8083/*" + "http://192.168.31.21:8083/*", + "https://*/*" ] } diff --git a/dist-release/popup/index.js b/dist-release/popup/index.js index 2003be9..2c2f7b5 100644 --- a/dist-release/popup/index.js +++ b/dist-release/popup/index.js @@ -19,10 +19,74 @@

\u5DF2\u767B\u5F55

${userInfo?.name ?? userInfo?.username ?? "\u672A\u77E5\u7528\u6237"}

${userInfo?.email ?? ""}

+
+

\u7248\u672C\u66F4\u65B0

+

\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...

+
`; } + function renderUpdateStatus(root, options) { + const container = root.querySelector('[data-popup-update="root"]'); + if (!container) { + return; + } + if (options.status === "checking") { + container.innerHTML = ` +

\u7248\u672C\u66F4\u65B0

+

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

+

\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...

+ `; + return; + } + if (options.status === "error") { + container.innerHTML = ` +

\u7248\u672C\u66F4\u65B0

+

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

+

\u6682\u65F6\u65E0\u6CD5\u68C0\u67E5\u66F4\u65B0

+

\u5982\u679C\u9700\u8981\u65B0\u7248\uFF0C\u8BF7\u8054\u7CFB\u7EF4\u62A4\u540C\u4E8B\u83B7\u53D6\u66F4\u65B0\u5305\u3002

+ `; + return; + } + if (options.status === "latest" || !options.manifest) { + container.innerHTML = ` +

\u7248\u672C\u66F4\u65B0

+

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

+

\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C

+ `; + return; + } + container.innerHTML = ` +

\u7248\u672C\u66F4\u65B0

+

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

+

\u53D1\u73B0\u65B0\u7248\u672C\uFF1A${options.manifest.latestVersion}

+ ${renderReleaseNotes(options.manifest.releaseNotes)} + + +

\u4E0B\u8F7D\u540E\u8BF7\u89E3\u538B\u65B0\u7248 zip\uFF0C\u5E76\u5728 chrome://extensions \u91CC\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002

+ `; + } + function setUpdateDownloadStatus(root, value) { + const output = root.querySelector('[data-popup-update-download-status="text"]'); + if (!output) { + return; + } + output.textContent = value; + } + function renderReleaseNotes(releaseNotes) { + if (releaseNotes.length === 0) { + return ""; + } + return ` + + `; + } + function escapeHtml(value) { + return value.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); + } function renderDevPanel(root, authState) { const panel = root.ownerDocument.createElement("section"); panel.dataset.popupDevPanel = "root"; @@ -134,10 +198,78 @@ return response.value.accessToken; } + // src/shared/update-check.ts + function compareExtensionVersions(left, right) { + const leftParts = parseVersionParts(left); + const rightParts = parseVersionParts(right); + const maxLength = Math.max(leftParts.length, rightParts.length); + for (let index = 0; index < maxLength; index += 1) { + const leftValue = leftParts[index] ?? 0; + const rightValue = rightParts[index] ?? 0; + if (leftValue !== rightValue) { + return leftValue - rightValue; + } + } + return 0; + } + function parseUpdateManifest(value) { + if (!value || typeof value !== "object") { + return null; + } + const candidate = value; + if (!isVersionString(candidate.latestVersion) || !isVersionString(candidate.minSupportedVersion) || !isHttpsUrl(candidate.zipUrl) || !isHttpsUrl(candidate.guideUrl) || typeof candidate.publishedAt !== "string" || !Array.isArray(candidate.releaseNotes) || !candidate.releaseNotes.every((note) => typeof note === "string")) { + return null; + } + return { + guideUrl: candidate.guideUrl, + latestVersion: candidate.latestVersion, + minSupportedVersion: candidate.minSupportedVersion, + publishedAt: candidate.publishedAt, + releaseNotes: candidate.releaseNotes, + zipUrl: candidate.zipUrl + }; + } + async function fetchUpdateManifest(manifestUrl, fetchImpl = fetch) { + const response = await fetchImpl(manifestUrl, { + cache: "no-store" + }); + if (!response.ok) { + throw new Error(`update manifest request failed: ${response.status}`); + } + const manifest = parseUpdateManifest(await response.json()); + if (!manifest) { + throw new Error("update manifest is invalid"); + } + return manifest; + } + function parseVersionParts(value) { + return value.split(".").map((part) => { + const parsed = Number.parseInt(part, 10); + return Number.isFinite(parsed) ? parsed : 0; + }); + } + function isVersionString(value) { + return typeof value === "string" && /^\d+(?:\.\d+)*$/.test(value); + } + function isHttpsUrl(value) { + if (typeof value !== "string") { + return false; + } + try { + return new URL(value).protocol === "https:"; + } catch { + return false; + } + } + + // src/shared/update-config.ts + var UPDATE_MANIFEST_URL = "https://example.com/star-chart-search-enhancer/latest.json"; + // src/popup/index.ts async function bootPopup(options = {}) { const currentDocument = options.document ?? document; const popupConfig = readAuthConfig(options.config); + const currentVersion = options.currentVersion ?? readCurrentVersion(); const root = currentDocument.querySelector("#app"); const HTMLElementCtor = currentDocument.defaultView?.HTMLElement; if (!root || HTMLElementCtor && !(root instanceof HTMLElementCtor)) { @@ -150,9 +282,15 @@ baseUrl: "http://127.0.0.1:4319", sendMessage }).loadProtectedMockData; - await renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi); + const fetchUpdateManifest2 = options.fetchUpdateManifest ?? (() => fetchUpdateManifest( + options.updateManifestUrl ?? UPDATE_MANIFEST_URL + )); + await renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi, { + currentVersion, + fetchUpdateManifest: fetchUpdateManifest2 + }); } - async function renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi) { + async function renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi, updateOptions) { const response = await sendMessage({ type: "auth:get-state" }); if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:state") { renderLoggedOut(root, "\u8BA4\u8BC1\u72B6\u6001\u8BFB\u53D6\u5931\u8D25"); @@ -163,16 +301,19 @@ root.querySelector('[data-popup-sign-in="button"]')?.addEventListener("click", () => { void runAuthAction(root, popupConfig, sendMessage, { actionMessage: { type: "auth:sign-in" }, - fetchProtectedApi + fetchProtectedApi, + updateOptions }); }); return; } renderLoggedIn(root, response.value); + void runUpdateCheck(root, sendMessage, updateOptions); root.querySelector('[data-popup-sign-out="button"]')?.addEventListener("click", () => { void runAuthAction(root, popupConfig, sendMessage, { actionMessage: { type: "auth:sign-out" }, - fetchProtectedApi + fetchProtectedApi, + updateOptions }); }); if (popupConfig.enableDevAuthPanel) { @@ -195,12 +336,74 @@ root, popupConfig, sendMessage, - options.fetchProtectedApi + options.fetchProtectedApi, + options.updateOptions ); } function isActionError(response) { return isAuthResponseMessage(response) && !response.ok && response.type === "auth:error"; } + async function runUpdateCheck(root, sendMessage, options) { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "checking" + }); + try { + const manifest = await options.fetchUpdateManifest(); + if (compareExtensionVersions(manifest.latestVersion, options.currentVersion) <= 0) { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "latest" + }); + return; + } + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + manifest, + status: "available" + }); + bindUpdateDownloadButtons(root, sendMessage, manifest); + } catch { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "error" + }); + } + } + function bindUpdateDownloadButtons(root, sendMessage, manifest) { + root.querySelector('[data-popup-download-update="button"]')?.addEventListener("click", () => { + void downloadUpdateAsset(root, sendMessage, { + filename: "star-chart-search-enhancer-internal.zip", + url: manifest.zipUrl + }); + }); + root.querySelector('[data-popup-download-guide="button"]')?.addEventListener("click", () => { + void downloadUpdateAsset(root, sendMessage, { + filename: "\u661F\u56FE\u589E\u5F3A\u63D2\u4EF6-\u8D85\u7B80\u5355\u5B89\u88C5\u4F7F\u7528\u6307\u5357.pdf", + url: manifest.guideUrl + }); + }); + } + async function downloadUpdateAsset(root, sendMessage, options) { + setUpdateDownloadStatus(root, "\u6B63\u5728\u4E0B\u8F7D..."); + try { + await sendMessage({ + filename: options.filename, + type: "update:download", + url: options.url + }); + setUpdateDownloadStatus(root, "\u5DF2\u89E6\u53D1\u4E0B\u8F7D\u3002\u4E0B\u8F7D\u540E\u8BF7\u89E3\u538B\u65B0\u7248 zip\uFF0C\u5E76\u5728 chrome://extensions \u91CC\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002"); + } catch (error) { + setUpdateDownloadStatus( + root, + error instanceof Error ? error.message : "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" + ); + } + } + function readCurrentVersion() { + const runtime = globalThis.chrome?.runtime; + return runtime?.getManifest?.().version ?? "0.0.0"; + } async function runProtectedApiProbe(root, fetchProtectedApi) { setProtectedApiResult(root, "\u8BF7\u6C42\u4E2D..."); try { diff --git a/docs/aigc-user-guide.md b/docs/aigc-user-guide.md index 5f5abef..572092a 100644 --- a/docs/aigc-user-guide.md +++ b/docs/aigc-user-guide.md @@ -369,12 +369,31 @@ CSV 会包含: ## 十三、如何更新插件 +插件弹窗会检查是否有新版本。 + +### 方法一:从插件弹窗下载新版本 + +1. 点击浏览器右上角的插件图标 +2. 查看 `版本更新` 区域 +3. 如果提示发现新版本,点击: + - `下载更新包` + - `下载使用说明` +4. 解压下载到的新版本 zip +5. 打开: + - `chrome://extensions` +6. 找到: + - `Star Chart Search Enhancer` +7. 点击: + - `重新加载` + +如果没有看到新版本提示,可能是网络暂时无法访问更新清单,也可能当前已经是最新版本。 + +### 方法二:收到压缩包后手动更新 + 当你收到新的插件压缩包时,不需要重新从零安装。 按照下面做: -### 方法一:替换文件夹后重新加载 - 1. 删除旧的解压文件夹,或用新的内容覆盖旧文件夹 2. 打开: - `chrome://extensions` @@ -383,7 +402,7 @@ CSV 会包含: 4. 点击: - `重新加载` -### 方法二:重新解压到新文件夹再重新加载 +### 方法三:重新解压到新文件夹再重新加载 1. 解压新的压缩包 2. 打开: diff --git a/docs/internal-extension-distribution.md b/docs/internal-extension-distribution.md index 6d1cf4f..65b3042 100644 --- a/docs/internal-extension-distribution.md +++ b/docs/internal-extension-distribution.md @@ -13,7 +13,28 @@ 1. Run `npm test`. 2. Run `npm run package:internal`. -3. Send `release/star-chart-search-enhancer-internal.zip` to coworkers. +3. Run `npm run write:latest`. +4. Send `release/star-chart-search-enhancer-internal.zip` to coworkers. + +## COS Update Manifest + +The popup checks `src/shared/update-config.ts` for the update manifest URL. + +Before publishing the COS-based update flow: + +1. Upload these files to COS: + - `release/latest.json` + - `release/star-chart-search-enhancer-internal.zip` + - `release/星图增强插件-超简单安装使用指南.pdf` +2. Make the COS path publicly readable. +3. Replace the placeholder `UPDATE_MANIFEST_URL` in `src/shared/update-config.ts`. +4. Rebuild and package the extension. + +The release manifest can be generated with a real public base URL: + +```bash +UPDATE_PUBLIC_BASE_URL="https:///star-chart-search-enhancer/releases/" npm run write:latest +``` ## Coworker Install Steps diff --git a/docs/【超简单版】插件安装使用指南.md b/docs/【超简单版】插件安装使用指南.md index e908eae..c4de7ce 100644 --- a/docs/【超简单版】插件安装使用指南.md +++ b/docs/【超简单版】插件安装使用指南.md @@ -114,6 +114,16 @@ https://xingtu.cn/ad/creator/market - 输入批次名称(例如:`5月母婴达人第一批`) - 点击确认 +### 4️⃣ 更新插件 + +- 点击浏览器右上角的插件图标 +- 在 **"版本更新"** 区域查看是否有新版本 +- 如果提示发现新版本,点击 **"下载更新包"** 和 **"下载使用说明"** +- 解压下载到的新版本 zip +- 打开 `chrome://extensions` +- 找到 `Star Chart Search Enhancer` +- 点击 **"重新加载"**,或重新选择解压后的新插件文件夹 + --- ## 🔄 如何更新插件 diff --git a/package.json b/package.json index 6f709ba..ea3c13d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "mock:protected-api": "node scripts/mock-protected-api.mjs", "package:internal": "npm run build:release && node scripts/package-release.mjs", "package:release": "npm run build:release && node scripts/package-release.mjs", + "write:latest": "node scripts/write-latest-manifest.mjs", "test": "vitest run --passWithNoTests", "test:watch": "vitest --passWithNoTests" }, diff --git a/release/latest.json b/release/latest.json new file mode 100644 index 0000000..5f155bf --- /dev/null +++ b/release/latest.json @@ -0,0 +1,11 @@ +{ + "guideUrl": "https://example.com/star-chart-search-enhancer/releases/0.2.0421.2/星图增强插件-超简单安装使用指南.pdf", + "latestVersion": "0.2.0421.2", + "minSupportedVersion": "0.2.0421.2", + "publishedAt": "2026-05-19", + "releaseNotes": [ + "支持在插件弹窗中检查新版本", + "支持一键下载最新版插件压缩包和使用说明" + ], + "zipUrl": "https://example.com/star-chart-search-enhancer/releases/0.2.0421.2/star-chart-search-enhancer-internal.zip" +} diff --git a/release/star-chart-search-enhancer-internal.zip b/release/star-chart-search-enhancer-internal.zip index be82975d6ac3b9a54da6258070311f19c359bc10..56da8558347269f66adae5f6689c3d4fa7a774b6 100644 GIT binary patch delta 6511 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 delta 4724 zcmZu#1ys~q(BGvSq@*R4UK*rRkW@gH4k_tax|SuET98@<6eXmVl8{#w{(JdN%Vl^1W|3;C+HiW zYzqKDN2?UdpF>mCRt#PF6J*}Z%#8z&rL-`afKI^QGd1@N6HH?uk=0RF)sT`>T zYZ-Qy+3*NNk!BNx4z>LRFLuEM9)DL#LiEAc*6U9 zt@^87Xy>sIgYuB6iPKW-WC!@;UH8(J5aeDe=Ih<8;5D0dEc z%ObNbe?W`7#E2VKSnUf4)6Fg<4pYEys_AARPoOHw-8RUm(q~23p9(=aF2VJZ6mo?O zCcIYp6s!wDnU_i+P9#~5lYb<-5KlZGXj&4;7JcM;e8h_RN?bWgF`yzcps*!?OCS3;^OHg&W%JVs;f8SZ;Gg%fcL zG|3V1>w!di5l243e#i4%DM`dDRMWmxtdH;xD+zQuth|Z6J|Nsa;o8Jnc*j#{78Dbr;G{`12Tl8xGw7U{!>-wQ0Jh=W_3R%7lmEM-N>Z`vAfZ zM=%-2*q9He{F10TM7F;>g|2-P;}H;A&&*$L|Okpml&u z*B_l<5k$;RJ`pDOHmM6rKv`#Lj}D-!FUjp4Gb4CADSJ2+9+rcz(WC$c40evmET1Wx zPf2YZO*%d56!GNL6p2QKa^HP0Ut7Fgy+`Kw@hN%W7H9lu5fsgGGGc|#3({K`B-f?1 zUSB*3_Jbx~TIkw+w(7~m`|Lp@j)f6%lB~qpwPzt0?3Xw=Qf4TtQK>xN)bE0iQ5Mla zlw$&upCHh)Gs80sHTMRUzoO4u>rJ3->~`HO8_q5_U7tTe5l<5cHP$~?Rn05S@~WpH znSc1J-)%H+4r=L>!sJW6%fS1HFqHN;!s@b!aHk^=yNxJO=L9m6(^l>KA!*lsOKtvY z&qytbe`L!jUzk6Ah>yDPdt=Yrx{IHDbZmW7+;iKy-SRfSDPbA=9YU1y+YWKVK|^HN zuuLPr@$|st!fK!QkFNX!2@<#X51R8{dC#Pll{dUki-a~O-6w((cJBNV!XjKILl{e6 z%IcAy+4DWj<_l;f7jbI4N*s!9*NAR(isuJCt@`xiYYFyyrlYpXypf;``qqhiM$@yL zds7@R2^U3lPyEl8Mn)aU*Cg;^GfhnobC&_yxgaktlHVr63(S@*Rv&inXo?Y{y%M+} z%`})N(rwU-zB-{~1EncL2CsSnd^<#v>QgK)>d*FTNut}8>t-i@Y!WH*mfy_pTY24C zWY@GNO=QU?P}M87b?Jb060&8xyEla*;~35kkWmMs>|g6LdmL#V7@dR`KUU?{60-y! z^8*}vJikSES$k_GM+^t1U|#UCR@uC3TMA&(PS$}k{4m|t$@nQ-KuRfMuGp>@7Q^gL zA%;B7XFp)MelB5E#z{h(L6X~-0N-{{tp@r{?0t)W(0b+ENipZ#jSdzHwTH5fuU;na zs0fZb(EKuCHlqub3)fSX=EJNI97K!s5xG*rqP4;7yDnD8kGdk;3uU=GQ{Wfe!**|) zJ;I?iOI^v?o{K;9805?r0ou`3udx@Whd{PxeI_342apfSzv&zDUWCzP6bPmPgd8;R zqUYV5>2z`KV9wxa7dWdVXfo$mwGM1eV{9Xr%*T6)mn83j%q(p&0`;n})!4PboGgTR zPF;qn@zX9VIP%45@FhH!Zg;YzbBQ1?X-BANb@+(XJw#IbL^N~#bkZ|>35HJ0DWkJX zA{@Q#39^>#O1ybN<3@$BWuLZ40V4~W zaBm>O>$*gHwRIfi*&?;Y8p`BJtH+edVHNx9b?Ld4 z3mcpGzZjSs^TL7;H_h~wX>|011-xGbZyO!Cs zK+aTgYX3P!xy$@|US``JPI>=QVwLyK;^7i^{t1# z&)PTHxs1k^Vgf7M2p=7~J2(_CHHo{v?8n`z0r!Q`hU%ddaM@(F zy{}SPXP06El32{-9{grGWU_nmaZ7PFmMkS*c{@)dgO@NelFCgRbx7d&Uy!vo9PC-_-g>7_{*r z-ic-Q;dx+23!WnTULr=esJ<#PC`obV&(6{PoPNL8(Cwa%Jj+?l;dQakYIUOf$yC1N zTd!Ievs~M3JI>u z!{7dWrq2TcO*BLxjSMGFw+qH}`Io#HLD>ZwX}oeW<^$k z_K+0+A{&ez-%YmYr!3~su@ip>B4Gi&6jXXlP%T!B8aiivQQ&j-as0Bmuo5eMPE-hD zh|&G6a=l25Ar$teUubX-CXrQH7!STAh(#G);s;g-VC-+EUL_r(KZ&I|S{RMwncMi`qg#)D?_khwd}egf^mIj=@@I z_ul@HsnVAmH%wJ`l&DqF@+@7y+gklfeNpG@W{y^KCRogSbD$(C;q|Kxxrpn)(d^Ca zE2q=4sf=%Ck|xlL!SEmM3>I2V;%h~|-d-t8-jZf5AL_|{St^C3*ACK*+zh{#uYY$l zsGJhpB9ki^J9W`fs0}EzGPO$ug|{}lm`axK42idO1SSh;3Mva9`V2RVKlN|`T{|l- zu;GCQ50xeQ6e@;GYj_YgCd0!tkA@7Z`wa>f^i|UM*LR^z1ru`yS&q&xCbXjU3oY7O z)O~*xG;{_vC}Gz_6yc-aHFEvjX2;m|fp7K7sEuoD zsz3FSyz_*PGX%eY99aiyy$A{4B0BR?-|LP;~Y~H^MVdb>#LsD6t#l) zp+S#W2-aL=L&ls)qWnIt4Z3L{|q~`Mb zmHcGx(9SfrhZE;ze`y`@)o-_dR!_;k>^H?z^?l#)yqo=FDIGBN&L3q|9E2@E1rq=m z!vO$@Z^|eaD^~|QTZq?94dv#Vra$eOt45kvKzpDy2PZx=-v0h)+_+h^Perg%;B_-O)*bn%6vJlf5YM=2S>rI?=Y&K<+NTXu zE9rQgD)GHtwntD4@U$)+?!tt)sZvwC(+iIBh|9CHH#}OSynHjgq_m%9ryldv#Sr-6 zQ_BE4LfMTra}*2U7j0yG`w10rUOh43SUzNH2325}5ObFWp zqh%aNbN062;PKw{3e~m6m~W zTZ;iEbCJ+|{}y(&?{7gbjym#LHT3PD%`FobcwG*af&1tThW0y>WEUSyb-Nmo)VMNA zR;ebA@Nqa5;i$`2Zl>pKCY;;Ql;~yFU>0KMj0lM4Hj6ez8bPGLON&~3Y?5tpD?E^1 znYS%x@T%J=7WG{;sMNPJu+i(Q`;1B}n6q9qNz%%;EOOCWd^gqrRY{pipbJ&4%d$G< zC}e{s)Os#f$=U9?3(-xE;csGpm$Tg7+^(^IgDn1p5KFum0pu@VywqwZ`C6ekke9(b#B^_fo_>h z-Jru#lP2kmG1q6;(#_1|cA!#1G-HR7c|gfQiiBY=lJCIzdE;~tR~8R0M=h_r&s-Uw zu^H?5YkMbJ%E_-bt##~Hkelzsd7s~NTCe6=$COmZV3<&d<>+TiWbFq-Ld;Xyl3{Rr zgF@S}Yxs)gw_*0$G7aK6(IaE<;iG4rJK)yxE9`#;W3}mR;}1aAgMbV-(TE%e0l99Y z5-0$a!n|cY=Ha}2^1E)ZI1rH z|Lb!T*nbfjU`t{1X29@gtMo(zh{1$Od2@z$GlW3$L;)FqWJt9r;JpX`Uw?Ir0lZoH zFdX~8Ado*Jfm9Oz)pygA{YAI>*xdmDYd2RfTURg8e>6_tXv9!=N1jFjnQlFzjRrDc z4p9J+&2&Jf$N#=uZTjCtb*tk~du%y?|4v(fivB%bLFU}x>VM+|0<0hqTQA68X8e8p z@5j1Lfq&Ai@n`=h-8eV}O)Gf@1vcuJ->{U2XasY|y+y1OVJF zn!llM_I%iL-dizbG#p5N>wMNNRLH|W{)NZ`ae4pizmi{VQreBfVmHZ};V+~={ReyB bNO9kS@W$ML-1q$h#5@K_jgu2{d*y!sVCZow diff --git a/release/星图增强插件-超简单安装使用指南.pdf b/release/星图增强插件-超简单安装使用指南.pdf index 8cae8a73d1c1645d2f5718e5ad89eaeaf51386f6..ad8d5e189bad36adf268862601bd2577dc38f674 100644 GIT binary patch delta 72159 zcmZsC2{@G98+Xq$cG)RQWXUcWX6#Ftku|$YBqU|ui(+KSPAEqaAz8C$N@d9!WvQr0 zi3*iusVM0?lh?fe_xrxCYi7>)RQ^u>N=L-JQs%_b$ zL{e5&#c68`2L=VWIeRmm&VB57xO&GO|A>62p#kKT%fkM>2Pa;2nTPs`3J;v092dTj ze0plj>Z)#frAvCJTHr3hHf+t;nNPagcc~6_H{+!Bg-$7FC)Tt-C_jgZMgBC~O zSWJL=yK~!}r>mT7^sMLJ{0UeklhoJ4R>w%4SC8ud-v28$Wu4v3`}^vr_m9MPx?>A= zxYx3$kyfV)YTl6Uo?R)@i1;;cqFuRXH6AM%d37z(F#e=&oxf~GC1HQ-eBMNc#{PJT z=Mg+BzkIhd$KgkE->!t!ey9xUVd-UEJC~g#Lf0`7bF`-IvRT5MmTGwX`bzRm*T$Dw z=SeqCa5eKK$L`>$FY)geJ??6Z#cw5%N4nIe!}X(U>ABYor3bHNdlMeTWt;lunzdCG zOtjt$X4x(O6Qj6a_yw!T8Ik;8e%73KTrS_G`=)0fHOFwjbAQ5jul~*>!5dGTj+tK2 zPjXMdTBQZkEtvM(Pv0oh(+oG_OWtmC?zFlgi9M6+UG!-^tdFQt$5X9r-0S-X3#<&Jc!*J0^AC81&GJepdM9<|!o6ryuh>^Fj2*fq_2h5YUJxEixq#=tz-`2ToBK7E zC{6l6*jmP#;t^_%g0ia?oxL>$<@tO5_^*CjT$x>bYyS#aUs?V{dj%U^ zRG!V!T~ZCw%-@5lr=%m=4*E0I;c|`oBb>{6zK8VLPe;xC+Bv5mx1;3}|MKE&K;cVu z#6f+(A=c(hy-UlVk*?fc_2aq6W7OZh=>Abn`txnNC1P#m?c1d{f2IeVw12-R{fRhx zui2qm`o&t`Lf@Y5simjy+j%0Jzb(|_&#t<6h_w$?v1#m!a+q*#dAWb&oYKS76PJd< z--%0KalD-Dn!PZ*y1L!9V~r;B-7+1s&=KzWS5L1B3GF<_c6oHw{Uv4q`59TA=Qgtt z%W&`^2~Et8k~=!(oN5kVYijoB6`!$Tmu}p6@Xr?&IJyJ<42%I^Qj`*^F#HY@iK;go z6ODr|`<&qXNyz8<^Wc(jLGNs=$@=yyzt#@!N z8F$bK1#1@tN^f_`x~eum<$1r!FO18p@JOGg3&}eCnG0PjuJ6)=#emzt>+tvKr#=`Q zJ#zA0|0_KeFFr%P){Cz{6iMy}rtBsx2ZiO98V2`9FL}zvT7*m-lcSX{J;;PjGcP&F zG=$GWw-4csd}A)8NcR_T7n(@L4)Pm|oG;4OmnI}7?T@kId0>RkPr4D#RNS@nwz1p& zd^8{lrdk}`>K(IHGn(UYd|9tTOuXn6kAzS+KB`A?i%UejVZth1`ieTyib40$_iUYa zSLnBEHJR;-J(0rrLHdRILTF>-dY+gx;khAGEj~kUYk+j%uGrFq6FbE}$psGYPqzsd z?Tq3#LHNfFE$d}6CeNAI^;ze}+~ab!qAL+CBk8^|YRP4~p6#S>P89Ck7QuAA^^!;G zc`^4hLYZ|x+0uFkRKK$%Ts5{~dHGE0*LuHDOr=djuQ9RWrcKbOF_BzvHFQ#z=YE~l z(0rxMGVG|nX|t^H_Xz`|>~Mo)yt>YInYMh6UNLoUk1l<#kA_O@VH!8o%T7!79%ClO zpKd?CRn)vIc17eS`@&88vfk$}jfr<_tvKvtd7RygMZGF*aPUR-@I@zNc~Tm!hCXjR zX?MWaUwR;EC70Z2RVX0sVQ^TQe`VL*Cb}r6%Xl`?roPQXPV=WtLKOQNkZ`Nh@8yR!?UaD3xd z)`zT9X==R^4=4MS&07x%CztY5zc=)ZaZncA= zc-ec!m5Y#P>NcdN{NeDeJH+=d*qEUb)@j+4&b*&CHvnma!0 z+NQ;MCJJ$Sd3=D=I5u}d8{gBtjrm%lq|+f*ccZ!cHZGotLbqm--XC>>`ZCt`?-Wtm8ni;=|G^&-UE_PCq6PEVWsI^=To)9HG%F~P-X??v5^S09AJ z25_y)tKUVXhdxwM*e@8LN<(vk%3WVk}#G z;p?C4Q%{!~&L~)oD)y;+O)Y(MuY6GaQX+b-`4=)@OMaWIcHfhK_;z-YY49jNw<&Vd zyS9ycaCDmprOEMtlhP#pZAWco^7?h3rlAp^u~6y#CNG1bG0i2_-CLmARP=@NZl-Xr zvA!LaL#MS1OBOD3xIbjwM^HYmEUJ>%#<0*~B z*KZqdz4vfFL+wPDUL-+9@7amHR-z{-tU|iEi!X3tCEN^Ut_dz*U6w72%v!}SFZ*z| z*`Jb35Pq6@VAMe9t`}S1m%b2Ew^g~Q{GR#mr+)US{5bW+H5`{OZTbxR2oy$*qG?(Ct8W*uxN+v9zQ zyKI~Lm8&{ZQe>TP`HO${a$pn?IB>7gzjNNpVPUk3r<&yLu#iKLF7zyXwr#-STYZXb zM4kVugG?9R>@p7Bn@I@sp6cS36!|gQ#W5^#3(nr>b#U45#qIt94ds5m+rCq(5~ha^ za9U`pCW;umq_6Ius<*dnd3T`wo3GY|{w{qtd}8OFFXzMtOZJ^y z$h8%C!Ekfi0O`>Eb1B)4r{k-(4IH|4F69EHdD6IJ1SjtDk~`Z>s4(zKooM@HL8|#S zU(KB#JDvE#r0xpvYtSj<&X^v3u?1^;Qa)blNtMFFi**K36aCIL_H8MDQ`RBP7~v0o zk9OLt)Nl-KW3&8p#h=T%^h~2q-tI47^e*ofDy-<#CwbjE9e*+@ZpLF_aFYGNG|T6o z1moD(ty$xSMo$G^Xnr*c2~EtraLUEBcd$&k?D26-&dZt^=l7JDzHqSHJ;^<(lICpq z&eE2x>-T@0JNwp=hkvk%?fUclrlBUbWmCGaXWu*NIX2%tjhi_s;BJD3_2Y1biqhqy@8l;eFNgK7vzkB9*0WjDl1|I2{&@3isRO&(owwoi zNe1mJ3adHSj5*k?)+J`FXgZYt{%p6AM)d?pT$CTrn3U{(QQ;=S3m(pO3Atj1sXGcj zxQBcR<`|4BOUz6&Q8=i`mxIC5duiqC$AIrQ zOK=A}o$@XXUj8I_@=2!jSCV$Ix_pI|V2q7vMsOLcOHTH#Pga7!wv1J8quKF{Uv=I% znB8%tHB@HUKU8{{Zy*-)sN7~>h~!z1kz#dM^nuB=cNr^(+u~a2?qLo>o?b$wNpQ9= zUgBZ74ZVn9=Ji`P^yy}%8NJ6@a_f#@N*v2r3uPpXnr!H6%}Ayhb*V<2f%wP8>i?TS zXRQQQjTlUZ*$BXYC3)RZEr{pZa}X z7g{#<$jtmTLObMHK+Ne--S5^TP5*I!sO%B0jHLY~vP16XzV}Z5W^oVTb&o=;bJHhY zm+mGx#n`paq`Y1vnhF>Y4z$ncdasIJXAvvxb73h6u05Z9q*A0wZbSyRwJ6T5@08|F zdsS_vW!n%{+?lQ32e;(4De$-Q}`*XTBYHAQp~*YzgNr#&Ne zZQ1s12P2JM~XTBml(zh5N#6argJezkS`NW=OS0CZ72QTg%ugK0G=}_KJy3?c5_T!1} z0+Hc=&_(bpf&TWIidl}tS};F~JKt`B9iCo_&@A5C6($$MIv&g&Q3 zAHlCzpOK=m$e7kQTI` zJEt$-48+Etvc~qDkfZIHFWgy@qmeh^xV+ud(ptm#3vWGd`oN0tKb0|?b#WGRmF|lVk zyMa5RF!dQnVWG_pUEi|c4!*Lh9lB2@PqBtKg)4S-3O!lbw$AIGJolE}d1Z(H+3or} zA4q$Zdxsfz%w5yjx2EAkEbme-kHW^-9OMpe<8{fYk@^^g-C5M6#fla1%(GT6D6P`e zH58AX{L;%scz)d?mn745)rjQ4z) zExg1%KyXy-%B?tOX(R5+Fxx6sCGHwO(eb=h%12&n!O|%#D!U(um7_(ao?X!R42C|o zO4)z-D#3KM$RDUhdtl?WdMc?>AYT>VB;SGKGEf%&Y5h55hI zf6;{f$`8xmlH&hzd8@~OHTlpF%{vw!zs-5~zpA)7q~a(!s6iq(DLN_~m{$(SP@M{E zupF(qv-0_pan<8+m8rvfY=%TWUOII~ZZ;)Hy!xWT8}-5M0U6y>E3N~&BW9lxXDlVa zdB5gyUyXZ}{#v9^&IduUB1W-Exb&RN5(x+N> zWAgmRi`*q*^rqy9B-;am!BKC6#haTW)I**;pSOA<;Iq#{HYng_aM4A+J3bdjZ|JV# zXdh3XsdGk8q!ZjtO& zs^QW09*C~P6*?MMGhN{r*%z;_T`BWBJ$~fyN70c${`e6hwy;24hh4U8@5zH^8LHDW zA!tXKI<4iau36uaj-q`ljk6c|0F=*$qTKd|VhjdRI28Eb5?nD*FPv$0_rz{9+^ZyE~ZQ^sDWc zTPnt-x+FbWS$i+~hH&KVWWIL1SjSxstkIxG)m2rKSsFFHY5Pgtej2`LZGtJ^Jk~2m zHAA_dJT7F^e&y_~JW}aZ{%7R0U5CHg_hrB$F1Ou3<~xR1@Q2_m#5wUmBsNA{tn*}$ z6m6P;1ntG+!o<)=woFjsy=c}xuc7!^Es!+9^dUV;GI9EFdwFB(a+gg+(FJ<^3_^X)f6WUXT2%6zjZ`jg1{g% z?-BOn!2%15!akXVuMx~A(i%Nn{`{tG@CbB8e)nFDDBaffeEs!FH?8KGxitA=yty8} zHMp2Cb>zSa4?@%9@_kDWzMkhET{&8{=iu*08N6g?%hX_p0du+BYI^Ot@D<(5Xhnbc z3;)xpbe*10EC(KU>yRF(p7>sr0N9>iOFN!MK5JPtQSV*YC+n(DChuc@v&Y(+Q!wUe zqW{^{geDpvvvRQpiD9nOmu&Vua8DZn^My>`zBbHh*OQvGt>sXoOcRCjyR&e`1~tD#F_*h;gXT zoSBbY`Ed7O>|*`?`0eUn%(z-|QB(zX2zWjyb%R5~)S+>zbp%qsz zk#hu(5-!z0`2C~vP$)Uj?sj+!cb7=xwl0wy)mwFg`73MBL|B zHMJarqUQrTlsgO08pw^h?WGYHhI(R|n!lr<7ctXk(bC8wOf?+lSpdu7?|#YUFcde&@Tb=;2Uo zr9g5CGtC_M|DQBmS7aZ)KB^F29Kj*5O=|~pZvVg;=G#M7POf6iRg z5#w9R%29q3lD2rYMXZlBf8wIfb(L}NW&49VH-4WOZkTs)ZZiDcqqvrB=(~R9p&$SA zGo<(szn0hAqCe-;?(-g6v6XmwSxi;aY*0mix-xtJmn7{4oASr!cFDKAfAT3~$sB8^ zvcAJ(-shJ7l)2Zil!d?Xo+E8T!>=dPuBQq#>|D9!>{gXb>toz})>C^uX!Ys)KU>z~ z2k&NL$GI{whEgOYoU-D7F3b*_r0pWJH2$_2@bNM#92sdU;_=arXMy(dao@r8T}>yogtRgy!$FdIJJ< zzNhOAkM$5=G8i#BHS7F-&o*XWl5c)&Fkq6DnIH7@z>vM2kVHq#WriIpT)TU}m-sfu zet*9-`^opjueAZ|7d@ihq7nL9lW_#bGl}(eB?KX9x=Yo%iw%6-470CdSK!dah2?K7 zQ|Entt+X@NYxyw?oJ$$&-f7NexU(^h^xU?fGO>%UZg11iDJODVV5O|gPWLUUenD=u zq+>$Q(^fSqMCSICVU58k`IT}$z2Pt7@3^(5vDiDCF)KEIDK=nYinH^Q+u4nYdZp7}C^BhS@cI4Wsn2~?aR&vHJf=+ByA7Bxbyb}= z;#oU){SGQ{xBJk&qUFJ-q@v{+U4Op`ZJi?wIXQEy99ca-f-iYi6jlqkGH)e!EaBxj zVtq&tZ`C{QZvc1i_)9*Bjo$gRy7Lnk+pN3()3S#{0lMW41qs_ckG(ivcX<3oX6ei6 zy@6Rb_VyJ^#Dt&Kmlv7xy=byKnJsl}`pLJ&!qrs{pXk*ySF{cHW#7&5O~ZM8;XCl` zVRO=Ml|5^D7JI!Cv^!BfjS^anRo`bjNxHA9aRwyMGv1iAQ-ykdEj%)VmP2yWyRQu@ z-gJ8uOpN^6aE#e;rta7SYqR%x<0>STOTNu*5BLCP&HmB=S!Ikz>o{>c*JY`GUx~23 zoCL(-6W07{$qxo8?K@Z$7lVZc6M+x7_!Y z1EC{+25d|(#rQgr+%316w`e`sZC&Cb)=w0!q4 zNTy?$lbUvr=HJp%6PL^;RKO!Z%F|W7*N=w3wUp&2HCt8NZ5!dM8%exZ;PWkN;hEtt zx@E0N`s{%(lPzNLgXbSVXttMr`VM^Z;<(c?GOA&#(_FJJxt`l=?t}dE1L~!+X@VEu zKlu4JL`Yp~T6Q%cV)f@k_q(_{DHMco*6-J-DaCpZpc8Qz8b_2Ho1R5?# z4<`*DRoJ>M+Ka$ICxva8yuV^vH!1E*CmJAc%{S|OY9urW!plJ{?>PyvB3|}@W4|ZZj#(ek4QV+^pY{9aY{M@> zV#W6ksgqwwU0j)ytF5|GYFd zK6xyDVb_R!;a%42VLZFe+){TW@f8+&3r)JK9*=L38RSj3{fZ5_o9KGsfUD_4i%R8U zvs?2QojO_WYMQQp484+b=}fUqr&GkR#Psjo{%N?HSGXUfVn=!3cSEgVb32<1XTI6- zIJ_5h8mtd}kP9DFV8&AW*F{mi2k$t522RX6n&*mo6H4E7$fnmZX= zENy;=i6(aB+)nK|bHZWu__FebQ={L-i_Udr)Z8pCX_4^p9rgLdTpu`GM%I5N|N4_j z^}1+v2-Ec_<)Yq8yn0_s6K&4jxEAEeGb^+I+>vCg zIH7j*qWW12V!1%bofj2`3)7yq9dG9k5LtZ+9IuD-EZ9DX=u29WKd5nzke+p5ai2#NZ08YZFsua;P#hq1THEbZC(-lKz>7iy3B!Y2Y;#n zdj+Gi@L}ttt*uobX+WnGSC!pV@Yb!V0K|o$bHp#TeZ)ui=E{?n!3#|KG{Cw3j_4Uf9*GKj=&V{Qwb!|WNkde{Q{dRIlY@eZL=8oA?qtpiF zheNyl_{KRL49E}Mf@B>GPSJp&xwlr*7zcybZEnB94IlTq^}Kz1TVyQfC`JZHOSd*t zzTd(+S<%@Fe}ul;=N;qwavcNJ$_Nv`%WLZGZVmK)eEx5Q_mMO`E{F+TbE6sF;qLvG zVYgW22|j1<3t~I)Jscx+YI;jDk4}`eBwHe$(V9Dy4EQTq0(j0QI;!gRc_d5oWelI# zFQBQ{_c@MlcSUpt#w3zeJIj}>a4G&ZSvHG0i%?2&D%_D9YKb);UM-IngphiVkn ze@wEQ4DA%W$7iizvYSp=*XVxxs@Ai6%Kmqc%?h)fX?NaXrXFU?@SVtZ|BOW=+grTJ zVS72j{O?bL_VA8;R85pwJicTvH6PK<7CDdqqA@lo)~1ikQhUah)pEm9usiuMZqNOt z!;g$oCCgqP?f)(_PW$7H0BM=HJm_h$wd#I}4w?UjWQ)_Ubp^kqkjaqgrRcQSN9p0_ z+@rSj@45Es^oZ~>>3)1?KOsJ{I+y-M%JkJ0&y_sS-Z7l-u4K%$mgfgDMdBNL1zUPS zTTgiW#r`%vLSuuk)OpMg+0g_uqVEfhq=Lt04vF3hh0zj*k(Yvn`T0p1@bpD-#5S_6 z_4Arz*?rylaL~lUjvG-I=b?K(zR>C^*;q50zoKl>-d%f6HP>i2w)aS~t#D}pmi6+o zN=}5J0$cdO-jlxP4I`9hVy&OnmJH|VvvOnwMw7n$>8AZQX?3FcK=J6YIJ-+eBahpO z0l2G9{R=hpoZae2Z(}$~?hFKn9E+C-V^wwHFAiNL?sJ|7-}468BsMXP=#Vt6lv}q*eHGR>@J0 zr}wVCFs*d0i4SeCD7lrpJFrIm@sun7NgL7V11@>XK^X}&p)F>CDPg2Tb}~^-{L(CY z12~UP0$NHJJPLgQAWe$;4Uv9*2@(ap_v|}h-LFvetFUEyjBjUai4WTbQAYk z!JXb&miBx~H@Dej5X|1SJu`mfJbbqBy5j56v-?hFj2Mk_)OF{ZPZ_hiv4S56vV@fd)( zVYbAk^2n8p#-{rBKkk;ej7QDHS2c9Am?GI*8s48Wck8nK^F8##u)lo7{=n+sL$f z6(!zR0;A*E!U10=>r@99JMPv9T)CuL7pChPFBMJ4a)++z$ydW;`iDB2uA4{J76=KX z`E705o*EF${Im%4g_|Kgc~gHg}- zO{OdBxvHsSt~BgP5#4hKwSTE<)t-}7db=!4?38YG%f2T+`#E*vj_-=#4}E9$>W6pb z*LB9gsh*fWXmB^jo8Q}Sjkip#vEBXhfIOM55_*X(-PX(?Q)HbBFzrR8!Eqg=81U*M zl3>P_o*n4zMMglp9wJHB(M609z)nD<$TfP%Q3Mnb;qY888dmZ?0^)!Gt$lD*FA)hu zfS@5F1>E)_w}F%q9AsdKOaiPid}d*UOaM+3`0S7|(ge1d!e<&L$QVG(;2X6}kq)4} zAGSPtY1zmsW(Yl8)*R9kel%<#Xg~50kSrj1f0BWXWP8CRwL^h{@FTZSK9WXxXJB5k z!J(ixB#j3TuMgjqRCr%*#c{5cDYr~2r?ex@%FUc+K8f&E6s+ufy5)?t0q+Z$x2UqC zYUvKm`(F#485>2iUyj+tURkYYX`Igdu0^@Zzi-)NZcPx6Wqv+HiyxXMDt2+QVB2g~jVF|_4HABxv z4m3x$A^>GXr9g=V(g_yq5lNDgqVoTqLO7=P`LqkO6Mro6$Ym1Wk*^vuNVnC#BknBE zVe@>S~`|ttD3GtB$M$|DsSldloKh@bixiH~q?ihW3*@`ixZ+TEKLxa^ymzzsO zqn_w9-xYE`^0`~RJYBc_H!cff!>{L}9g>ec{33TlH4^9p^uhS zQcJfop2LdP#6`9=EO}~(GUm=%Fxwbh`Q|tEIDazmYI=u!>RJ5wF2BoTtics@H2mk2 z2g_X|jo0obar)l*F@B)p-1+SWC$e_A)8Y2-nC8G-Sy`HjMa*2gOA?XCirvM-$6}{n zEk0aIM;>cA-L%!-BY1!jW1qXbq+oc5YjT44R7C+G@(d0c zIW*)5JLD09QBhURT)6Tah#o=;ND4S%MVx}Lg0L0S9(NV2KBTalloF*+kxJ=7N@BNL zM(%(dM`-Cs<1rk7#R0hq(vCpaK4^@vfv*loC8&0SByTE)4Lor~?t`IiFjibEKv_ZO z5#%FCc80x)oCq8Fy%QpeAj*Kj8HoWOT;St+XCxSmy26&Z3j#ob8=T4Niu8da$6@Pq z1)Riw3^|P;Dw*j&B|(iFQVpd1VAozD>!t5Dt)FOC4ktGp>*9FfwuscRgOvWlwK=AuNXGi53>25_hfl^FwQTq=K= z+0e^BYEeNwHY*J9{&_Vv8lqiDU zRDv#aC`HvxCFnw@QG{0U&q!rxEvkx#Hc2>4QI*OJ5i+AnWrj#uhRO_)GLg!R0j2MM zJnkROs{Z3}(H9VDa&a=^hXSv3D1NOp#1M)*1In}V0@4ObGGR;I1o~YOjIn^}5>(m! zU|Lr4jSK`qz|JfNfZ7I#G*G&Pds<>ys&VP@-^fL0?e+%o!l=#b|K($G30V!3c>{5A_R|s_8V|fX>OFA z9CIDvfiEeAtF#s)C;~>x;H*zKkRSwDR6wQ#SYZGFrO007FYF+%mm$^&_<0L*5L$t# zqQJ6?_OI_Bp~QMDv=%-94P`6&OcnBhmg?)uSOZ~2wN1?`E5YEYwy9ZV7~vJwHhoT8s|Io|;P?>=*Q-a3)&nwjQAw^|I%>YtVW^@%HMP)`;4N_EQbSd+w%;-`2RD=)wvnT-z z$xWMACQz24GDA=nR>D%5Arc`)WyS!`!~SLFf5VUx7KrSl*8}Evpn}5m=-A2FM&uF# z^zK5fd?6#Q2>5ajYV`CSq!;-MgvclFBC*g!+M(X}HedwFiuaK!B(p8(arw8&{)`|GQ;Q0_TsNIb$fCIhIXAWFr18zOY4`BTW zKHqbkjvZt^gs@jv7#eA0FY*)thn~TnKR@ZX$SIGI9wgKGTTPzQ>ea)u<-v*M=Kv5LBIdy1QChomkfsj^Vih1*l4%0f{OZeH=P zEdH((^UY}8re%A}=hW%5t>}1&y1cv~wF{m%-+t9auyn-_L@&b`SLFH@s zRC5fui-5cd_*7^dNkzcxNx09)!q8=>UQ@c<-odWU34{*?bMIl-em*)5^0q0&903#4 zkgnE)ew*_Su|mL(k8mjW2c!=HZJ*)V^fL%I3Z~~^Q~x7ELc#bvoG|+t`2)_ip;Bb_ zFUVtPHYpe>keUtiIM-Js72Nx|x#;t+2nJ>kCYo(z2>mY6kv8p`fF(ddY}z$JQAJou zX;a_?McAjbDQ|)jbUCPj4P_7@;8KE5HYq4QITwj2?6yB`Py|a2YDBBgq9wrh_KvJMs*R;fq~Ed;({s!)rLh5Eu`r< z8Q6d*1}y|qbdZ!ILRj$=gEAnXj2^BiLyN9csv$|TIUQ<`fUQihIY^HxBH$7;9Dl?D z7Ky5i=uJIYG#V@CO4Mq`7cnOV^9poJZk%#6Iik?B-N z5B9R6Z-4_QoEo18EzOP%Jqa1(hGRe8K-kIO+0o+&*v|uB8qJB45RkbIHet#Uhk2xu zMhXb3z?v5%q=J^Tsd$_LGy^Jx z$HN$`M1}BpirG;SJYEqR6BWVZp*bp15j-9mk`fic;~@}Hq9S-aTu+IL;PDWlE8+2* zhK5&$MnQ$}coi5KHy}K$Snw*8zD*;#IQ08gQS=xDr4mr5rn}IeKurp&%v&5ijDQo;usJV*8bhov3;S1g(X#?yDRebc z_l6`nO&WayF%k}{v852I5y+wtqHY$4uqcoN7x+;*z|Ksg10n%R%!oJKNH>2$rve|! z4|7f{IJ$!-n0!wGT|!AzB#u?0M2-z84&{rb1Q8{b&Cr3RNL~pRW*efxQUt0*1*KRe zT^MJms1&P2fcmGxQbRHW76+7Xi#Vu-T!3>Z4#0Hi5i0Iu4X{VM|d5Z3U@%umy84 z8<2%A095v(Yruv8r`YSFFek(qz~vkD(5rAEL)e6Qk^u!1Mo{Q~Lwb_|^ilB91a{#J z(VGz4*`mxKxeXO0Ga93B5io8G*M}&LjVx@6enSu(IClc^|BK=kUec1X1`!ExR2>ln z7nWgckK{*bK;$Yt4G@-xm^0rT75f*o>BAhZM1|w}iqM*6QqavVcLyxK*UYQ9Od|mtn7|zpD2* zj!{T0%9k#H1vocl8aoB2!w(PiJ5%y@A9M^u+Dx)oeIiA+o52>6P}5Xk4N2%VP*MMQ zoW22!MpR^tCBR^eqe5#e0Y+6E6=0~V7E`k*!#>grxFCC3G#uuQvr3aSJi(sGi| z2B9hl&G7On|F zD;s$+3gt%tDGt)}0kFC!#GoMv_!JN4-_nDj^lL0-y+?_#-!BN3c8zhA7$lbrm*Px7 zn-K6g1rB|!Ps2t=lTaB1n5My@+b%;^jwMr4GG{v6dG1N*+n7|;2p;fcY%C3}HVuWi z^3Fv#KKvwP#V8#$LqGu=gA}a&WU?NeLh6w-%PayuWP&HWl;r>PbYHHBv{zd+3 zFv#HkMgD5K(5n7L{%U&gP5&Z)HF$W3`xp7E=|cnEK>mNX1T9h@2l2<|iwTeqMXIN$ z5hzRl%N9)4xD9;#AA?m=+=x;k1*it2n=67Xc(%6!xQn3~ zz>F&o;oS|WR@)OW3W!}t7eGr19HUu`4uY0aREmWA&)?#irT=pmpiOk#l91n)D_Jxm zr}*PdYP`nmk%gFwEzt@}yz$#L>zl@?7~3D8^eK=X@jNMK;~vY<_I$3`Ms2k zV3Xz=+Ub42c!`tB9}izk#Koy)9Efuz^q;SZl8&P7x|*d&95a1g!}*?cP>~~;*4r6l z_TG~}R6#?7%MQ81}^O$-~R{{nzgkHS2uL%Y+7V>f5 z0)NI3zle6nH}&D?LXJli8JPDlCeYR?-i~Uh{9_}0>&TUupo{{3;T*0e?sw|`$z4rp z-&=3}SPG14?)F^6%%vRf0SjfQ23hF_ngol@3MiQmCFl!aTM1jQ1z=40R*JGC;Q38R z!!tb&pk0nG0V> zngYKq?!uAqFog}&)}YHk`yM1Ishi}O{x~sOfxUY^G;zn6zGXe$j^UiL%;^_wBXgL8 zg5$0H`lf8nzcXrsoY@##EVry2)8-2D{!`slOsyOO^* zEwM4r`*`e5uyMqFnshFItiUBAm7?wZEa{Z&_|;#lbZ0p4-xbPL78`f8t(UY6B$K|= zODN=Z5sXLM_lkZS9VLgL`~{yaejL5`{nOj>D=qQW!>HQ{$;0^ZSM4ritPY+A!lJ3- zJhtMD+3Rl(KTvt-J=1)6AK{TWkLJzWyF{zdrP~(?yJn`1cn*rxwQ-C(fNtki_@C_5^OQb+=|8t{TPgQ&cDC|Yhl;D-7O_jrJZ+is!15i;UNZG)BIx`; zD~{kYTjRD?C4yy+%KpeG_gCyJ$wUoo^Q?x{_<*@oNMB}K%99AD{3`f0>!RkXv;5Mo`iZp;i zAF2-arZ9+r*3Y_-<(BD1i>XSOdJ@a$Fzek35+TD$bjJkvXZbnn-TMy z53Fip;>bI8Vaie9rvs;RNW%VSIv7AEKcQ3R0pD#g3FJsE%sc`-4#D|%buj#3@DQBu zu@{rd1FBBK`6N5cXB1$(;rzx!7=C!qGjs^!h^PRLFEq+zH+zf`8))*uaAeKUg^=+c zn0^#d1^zl1W3b;FE>{(dVFsGU$PRGS1XkyH-WUM{4iK5b@PG+xT3+B-Pp=PTd@;}M z|H*0x;T0XsuA5~nBq_q(yqlqrP*0onC?xUF4mV3XNW$6_w^_VF5*{1kR5Bgn#6W}} zMvnq^F*sFtTPR6y1qS>v^5Cc%Ei)MO$8h~6GvZk(zdOkAD;qsRt*kd#+JqJx9BsnJ z4Td(8@CHAduD-#}Cf?lOhFUy>y`dN^xXMY}2*ScJEZ|NsMjJW+Je~`|$YFqH1O`?P z3iKSA)#-E~J`}SI3L+T(ip_yM7lvV{6k=_Dm~E&k9$0$NY$xwNi^)Uesr3{@64Yu6 zh7H_CG4&t+R8{_q3{afv->Ta+0yBgF)p+>gzuAVx50;amk(l>DC;{s6^DI5nU#(^K zXK0ao&SAE1l;lvPYV||?X$Ym{uFHY<9OO8Rfas=xusB_)qyP7U1gG}Tp+OQx8aTyc znh~{)ze6AhNk6{f{6zA z0UQsnD<1*l%NR*Aa~cL#u9O3Vf4CDs$S`%Fjz}4~xmO�mN-oHvbXy-*V<}AOvdZv})i;E=HQHbCBT} zWlwK&VKDQ*jCljvis0kWE0}2nI2Oah(qAL+^lw0mek=KUE~XS--<4o^5sIwE5K17U zB%gg7LeGXMp%AkuxoL+6@Fo;bt(pvAiHwIKY-0lkx(49FO-vN|QxPTr0VUN?au)dz zmQeIfE-c2tVzKQ7RdPc}M!X{BEsfIjh8SRBjdB35n=qC*+`};N=@ThS|26Ud-7#JP z)GEUZh4eaj5eVx~HnK<+2G%-!4Ny7#)fis{!Gg9W1}V^5h_YwaEYXw0YcV|V9O52E ziriF(f!9q-_hA#BYxGjaQZ9rks>~ef-}ARv$cSJ3`wJrFQ6gl|kDPlO(~2?OOpwa( zJ_P^o4GFC7@&9u}f)&P7>k4IfCxYK7EB>_1ntA6uY-nj69M)Q_e#Ly#AkjU*{a ztP7mzgj#|JpOYZ08xGpk7YiBNiYY;W-9w7L$O~=>9PVdCbBH&ynG!#D@20?O5Hzo@~6&3yo02GtB^^g1A zL&3FvjDQ%mO2ET3j^8L={7t8 z5?q*tA^-2WcKb(Y@0Uoh{$>;~|qO>oTvPMOu^gnk- z)7$^|`Mj^@%zDnb-*e7)d7kGYnJh~AcSa$Ip2Q&T0V|3gnvqC*K6Mvu!# zh^^7XG7=~hAZcRS+9QGRPmNx+An5_iqgO3RplqN zK^zU%8Cp#R$?wR(Lq8dl;CwVB4d-45D;oaAI0>I-gk;j^+c+sTYm7ILQzOy?m5F#p z%=b``5{jPjK&m2Ybe9sTim1_C%71=P6;F#MUqg^A+=GUyVP-5Ooh~}J0j_3*T;Odu z@Z(w#bPXMD|)(Xa+Xq1aG3&Bz%=2R?0CPqz7^qT;NId zAy9f*t}ag&=sC z$peAp4)bP+HT_|tDC}4U5W~}iF+bYG1}nImQGE7sQvX=k$i{RUyl{Zcc}gKSk-~^qW0Hg1sM#u zTLy}ve7A)RfIle*x^Zoli3{Fv9LG*UZ-Kx8@}JW(cYQNSLBo1SAz?{+Z33?c4s)b> z0nGWINm_>&q16bNqENCF6Ilo(l?lq=XPAu8+>{YH=n)EDRsrqfoFKLIMjk3hP(%OO z)}5%MPm47|&YH9=UP`DEWP+ma**bWz9_SvK4!~}x(VWD8xX0-=OcnYC4%MCDp*{i1N5N+_Fwztb5)_Go$F+dneV0OUQrgwQJY3cVZ;IXtv7zC6 zdf>vG(0_al z&_rhB&mM$V1Aea>tu}+?j?_S$r$z@O;gRBy+8;+5yowwOe`+9Hpsf#fB3cmynNL{D z9O8rJ_u`1K+CFF-d^HH{#NhOMj6_~wd0R1oM58Hm7zOL^2a^ZR!cI8Z5@LlPy5Kg! zj{BhZG{7kUmvX`BSf#0PG=yrfsy;bCnJe0_Q4t?az@& z1dr5c5TSpJhqRt3)3gT*y`B}UUk_^tloMNzVq_>+Z6IY7?BfP5H&{c4XxPRB7&FMy zh*Dzgq1(W3_5vP?8VL^;@?PZnuAB1*(EDqYBxh&VB|*R%n8HBwW(&v-R|i7`P=B?On83J!vL^yMih_T~f}aMbGbd&26yyiW zyz!t7a19$M31ny-`2-yixC^n2^|=*8{#8S25F6onPn0~Z37*peZ`z8qjKS+VqjEvke5UyCFtt#4f5{I3Qw%?d<?NUxXRPI`JZT?eM_Lo*OUUiKbwW3*S)`G@O6K$M z6=&9Gx4cX&4{SHc-CvNt|GcEvWNrU`lfkhh)|*~=a(D%{z945I#e5~btej&mKPI_m zDpJB#a$HEEZs)$apPPJiWOM$g=t9!gwrU5fV^@ljZ^v}=dP%#H2`W1-S7q;zeaNOK z^oW$Jm8E1%UNj~z)jNG>53YQ@(l*`kFlM7_`4fj9s1K09Tl#s-GOdi8`YXc@FD z79VwjhWiQvt2f@+s3D_%WI}K_C)f8 ztT;!0Hlu7V+ccZ!z^NIV2$h~iYR#C|*l8}5Nb2!n#{)4@xTNst!`?!5?J z0{%BAMf?H;iavrcST&j#P+XMY6i5wJW^%#mdz=b^B=ym2U}1uVx`A>r9a*S3dElil z;PU{hlMhLg0g~>&wq=+4C?3GtJ3fEq-SkoqFZKE+imT3$QGI4JVV3d6j&7EX5*?eq zEG66ondKh8j+J+-du#{?UG7SMdtzF-+dS;p#Rn(rcE*jJJ4H z9uN5#S#?-v+1P#<9h$kj%pASk#1tXlk6w<#Y#$LnelOsP`cSHhROCl*t!>c!sJc>s zJ@dQW+$&dD-W|-=8ejF8c`s(g<{jY%hkP7Zu9?0HwZdpohCiJqrndX5YSNINiXj=popiv;AG)2jz=cWSGPzm$} zuBQMK1r=0IigPKXj)GO|z<2*v2I0V98FUJ^YJj9Y)m8p$r3WA4St7OB^anKyudvFy znwSv2b5&S2Psqg2GB{FG4UME`2*bXf%p8G*}AI-;(ryWpBwmbVW>fX zZ!P4cQ|wB7#{fJRnBp+?Gc2rYyMWo`=6A^2#|0;mAr`V!g4pwu+oQ!& zz31~bOieI~c+RkRS$FjSf`?=bZ=Ik&wl5~!{g%(|j!f-O=W`DvM1AY60WDzJOfnJeS0Z0+TdO=pv9U!Mb>yLG-AeK+B#;OqX zKRFU5i$ffwnCEcj(JgolB>--Np!0Gl19Ko)42 zw;dP+h$T2F-gVFn3YP2uFOeG{W;8s7JS=a5Q~`kb8i*9wS|E^$dH)n62j`?>IPSGU zJScdOhe;OR)ecR(CVfbn7>s1RY)0K|(XsKVlxu;Rd(`tNdleUd%sz;N|%&5+!{&k;uhKD$b# ze}1UM!JN|F8O`wi0h{=HORgv{G{hLqybEgU1I!sWT}+&o$qF`Li^vY-d}X^`}OR{=lY3PRo{P+X9FKS|2R|i zU4s!~c(@P4RIuS;*Sx0xoU;PMa~6gIR=EiU0eh}YhAvYEt6IlJqt0rIBv0fBlUQgk ztYx#%=900Ap^i`6;PkfzweivoGfe2V1{N^~hXaQezMZ<-Qp=!>8JKmrd)!_~<7En3 zJD$ODByTtC$H_OG6X=xd4CLdF^5QRAk~q>M#fiH=~<3T~3Qap@vche(7BqKFcAE7CShv&+y_$A9-R<=IN^q zDtptJ9;Zb2J{{V-W$)WFt~pEZzV(dwEUuk5e|(r+Rhv-m_WC=6_Os%+yO(@0*yc)W zMg~Kc*9&?w0`d%JEQa!vS`oH6^86@mpdKN1hEZ7zx2Kg%l8F{77dh1On>;dk@?kgi{E zk4QL4$DFTbsL< z`+dsx*Y6CDiYJHmb$;PL7GrsrPcHm);g45-1BXa^Y{d<1-%A~fiQly1_JXBPV^;op z>A)Uar?Wpw%yZ|$^|*z0M`>s3`SQL>?-4$=fnWX2_7h=`=bS|=$2_7vleoM^qUPp2 zcdK6IBUVQ537QrzdKo-kzsY{#hG_=*&=?bExRZ`~RZIcq>Rnltcwr2shmUt>&eglE z=-G@PPxnmty3QFEBqd`KMAQP3yj_zTj^B`GsJknR8Zh1V|E9vjo@^}< z?EQUmcUg>DyHN6;D;9T02ANb6vXh!VEWep*{ouSfD^)FeyV}xnM)0%M<0q}$r7@Ww z61ST(YB<%n0ZXPZ{xR~X`##5N~1+&8Z@`bj$c^y2Mh5irD<_r%THG)Yj&$cH| zP6oQ#Fg!e~flARUeJJDgt(~arZ)zG#4piS*?B(^r`$&7pGDCKavGzOPs5^T(8A^8t z31AI|Rc9?O^$Oi#IbsG^k=|GzdB+@?XJ+c8)9}Q42F27YG#irQb2f6q5;Y=I!g&2V zOS3GA@yt2a6ctw$b*#JN=Ac%g5e5ft#E zVJE)Rdjb{&v&99P4K>d(_^d4{jId?B=OyTECAe@IO7WG$4OoUtoMOF>Is2GVPCJ(0 zm)!Htj!7!#x_Y*;oUPwWWI9IzBP#d0Ugfk8fI>+$63xI^>C+vgL;UD*|e z%Z!2}S}pHh6p8lEJD7Qa9AnhNT<8Q7oFkvbO!~-W-JU&B?+73Ip;sXD!1|{!f!s`p zN{*sRaGvbs3J`^>yr z6knaIDraMLBwf_oQjZ!Q3m#+bv{wg z;dgk@R+RC1sdK}4z9{2@qJvxc{fHz7w|C^@4c!Zm>>Hfg6{qmah0O9@c)?G;)c`WwQwH$70JtXE5cfF?H8sOHi(cP zE#&tSmbf~52@MA>++QtC`jtHDM-hDPcWn8+%}+!Zt0a=T^-&Xe;H%&WuI4_Dggf>Mt4nzY5)sK|A=U=xjH(b!{T*xK)zMOJ6zJWga=-}0$sbN?fK{=-H*wtR8LXea{yWW)mm zY7bi-kGY`Py}+E@tG?ZK$61Bq&H}z7pGme7gZ55!&58D{A_C$5gU^;dcrFJX>8c|Y|m3gobgZGKx;qP#4A+c@~OdkD0<|Fi<8AYFYR9Lv;B4OQhW(9?c2;1@0-OWY9 z-zPGAezHjMQCo!DH;ln0bMvnzVVB)o8yFT=dOkIZbaHOk_*E@=f+WYcH{jvHFV?<7 z$zAa-5;xx+PkylL5Fyc}pI0PPsPmjz%gjU4<-Wn^zVxD}vjT zw{u5sE$hNngCKtqPN8n>@t_^M9@g@UZZf%g#?VO9_`{VhytwA&t;Z8_8SS0UBAr&r zc#+w`m4}*}@{eue&$&P-e(1C5ZjT^FIe}c6x4YY&Kbd7gY3t_kE(57;GUt5+JP8$D z28nFX`$e1_-FPzf?j8fd>D(<*~2Y%blA2lbI?>Mq|# zu6(oQ05jvFC9||?UKCp%lg8U=4as=%Lo*7xmz4HtT{`|)Qn*XTkYT?=xnzu05ryes ztM;!0t%m6yVo!btta9zJdz;R%Xr(RS96aznQComxs*u|(Q=f77)FQ)=CdWq2wyE%h zeOuXv%(rH%#$nUgu?%_+wAkWx!s-;rIdHlcc=H|m_ zPqH4m$XWc2|GJUjtz09LCpY^TIW`_0JH?tD&r)GQ?a+FE)JqS|rjOcI+US*3|98wG zL3hJ!o}JIj*YgST&;L7luHg<^mOskzzVu{AX81wI#_=utz2Z}{Z+Zea)LoL zz6o`}DDmZX+3GJN&BrIn1F*>>IviOF=Q)aHG7mLY-X68A8 zK5u&O`-H8uh>lvn)M+wJ9wV0FR!q;2mJo~mAI<6c5}Bq>-kp~{rC$}k$6*`9Fvc+O z6(ttHFmjTFWzz@Y86`O^)gguJ=ds1To8P}&@mg!}Dta+jteWsT+REU2d;6wydV??V zAIc|F8tfb{u=`us^SH)k_y@R?2a1Ku8YKjUy>GrWIl{5e^>|qR?7g55!eTO&TVL+< zA@$XfANib)$=z~N(tqjds`TcFPeI1LlX;Bk0a*4ei>~U{M#5P39mI~#M_;Rc5`Q-M zv2iYnm{b%f%b>ZXd~(w|B#v zX1sQUy5C5DZfX#dRKnH%RMqkXd?l)pj9L zZ%0%LcdiaP&H!LJWuv(Bo}1hyTj!@6a#vV;j_mIio0N3_r1AWX$IO+$pfa*UJFD>< zt(M;}YL`E_Z0q0dMXK?7Ir{NJdhCVGUT)$2$-;KO+Rp4QyHfI<{Cp{{^XvN?XZkMn z9^UD!k{NRU*JfGm*qk?ekG_ou9IiaRm8)JbxGV6)pasJ`IZ1}Y zZ7MDya=V%ovq4^HJ>a*Wm~A0m#3>103P<&kYk6)fuiP!imbVHILt zRUj^PrftBgN=KECbjzbYr2N(O%--pP2V9Qcy&DpA`)Qh=Os!Gb*25KJZa=tH(p5w= z`X8d|orupBW(YHcxwtpS-ilW3JP|_9uD#K@Z|XyjP+3jD!!|WX$NmAQe1l{+ec8Q> zKvsa8E3@NE59Cf@#5r@#z#f zwtB9CKl`o9t)$wn=;M7O@?LR$3)^|tI)!WK9>Z25G2P?zrYQxB`lA-EIytsk#@!u1 zOoty04ehdQESmOu(f=hx>;8$GCE^;KoXVOtLAA3V_QKJHg#rs9%egDL%aiBbeJnOu zGG|XU8NI&C?JWL4!2Na-NnG#POx&j(7s=D#`fjJ&n204`NZ)BQw|wj2PTwxdT59^6 z3W;FzwU3hx=?+r9x|?6&gC7TOy-#}j&1*8jCGb3(xJ2wFtM1qqProG5mF|_m!+TyA zzbL3&m8*_Dl%jXS$uX%|#dbP~eZsAhXO>sr>5Mbp?7(cES!j*j#hI%atg}3W`qKs; zWZO3DDD5!4=NaD5-rCii-Rpb1tgN)O>`ioOYt4NO7nG-rA5*hs!WzZGrBBmRC&p}_O zFP>}j?*~hlaKfK5ajZ_+as`-5|r$_ z;N?3wH_O&TY~UZ>Pk6?FPrbD<)7XE46nKuK_oi$q>zwrTN*#lrgdT?oe<}M0&AR5d z8RV$awW6qJs^0T)Lyt#uc}~ez+`O^Ot6}4npSKunI2fD?tUYl5SkX}WSxaXfRZ~s{ z{*P@f0eg)f9qFE(RS@sI_|o@Q_{-PD>OFE1^?Q@JewY+!NN;pMcI5to_3xX(8ySh3 z^?q*?SL!<(%VlTV<1bG?v)y#(5ffAGN6nw}L~4}YkYS^IFo}+`ICLfOG$_82=PzL8VgvozE-l%gFC|?UR*| zD785)zQ5qc83*z1D2ALT8MEI<8+F${iZ$ccID7K=wrEFjHR)s9_7zI(-RFz{+?HNv z$)9gFz?ynM_3Z8@(vDBZJS(En=Hc#-%rdjOhYHAfR_)@F(l2+KblW-3mGU;Db@922%NUgL09($Y>;$|>>gIz`FX0^Gkoa1>&7 z4cVig>?Z3JCh$93C2rp<*mG{OgLS-B&Ph#W(xNb7_s%4z3g>LzeB*ZB%W_Gr7D1%m zOXsGgMkR}^mD#V`X#Jyh`nZuxf4J#4-VwceRu$;#U8 z?Y`A>ysEB)b!GbGCe9jWZTC2TPL%9*^$PfFRdF+*L-a?Y^Xk1?S)~m+q2Dy;pZ!u+a+$ul9_vS zcemT^K*zwJ-B#A5r`~(NJ7CYr)5DiABd<Dsp(OpF;mVQrXMcD+mB-YRkC%*(#MAL(gfP)SvnfbAJC@^RnKO!g7xc84-FDQwEA zd^l39UU#%fnu5EW=6tGurFjPSNtf!$OlMi~>%1Rco~(Gnp5LT3IV`dF!p-}&*Buv? zj-+cYQ$7dVT`PcdZHVtS1@qkvb|~0V8qI4p{?+p&rBQnJp7d7facQY`j|>XCS2wd) zX?0F)k)=mYy)_y5F>D2IHnb&77^ZoM?z-&V@g@z;ud9zL2>oKb`XqsLc!v;O9MjlzC$84KH1JuV>G^5BylRBV_!Qj@nFB?tJ=M*=wyU zzh5<}=oaO^dYQhl<4JAEiq+YuY}KMQHET|tuND0RiQ(Z9@Bp@b~mzx5?>6+oeiY+#ao+JbHMjwqZl$p(l^;e-y+;@MPFs)c4veS47+s zr#-Npsm%k2#@4^l9?BX7j#{H#Vfq(#?yU!K(isDmJW`YTYG>{S-TS7Wa^kZcm;P#n z;@m_6P9%*DGKw$^+hR2CT5&hCBvn7oAkCv(XwT#8=d8bppDl}4z4!?OU#HBslI9bRSXLkR_}C0|5bLdf&53Y#pCZvTS~- zcZs2379}1mCdsi1^r0C{*%DNBc^@Il0>4`gYdcl1)p|AL!Z_-k;)+_m)-;_M^ zMYezKGmPGr{GwbEQ&4cocuU3scn;zhBYKE-%UsdI0v<-2Py4{GH(~H&S^5B-~>X zX1CV8N$g?~kCwUak$F>ANO)24^o^2fvHRfy!`93(oJBH>TMG@W%?|M7NEDnmSWS$* z7{1?)w^#P^ef=F*^Uj9fnHgO1ROKRCT)r`OExC4e#zOWdhwHXSlWAd_o`eJS-%Uc7 z7qYK4sGslXOlmKRIq7-!QNfGn=St>(q2)p@!KqxJJfA-W`ER6_4gUct6KGT^fO^}o z3Q%twlbH5UnL0?BDGlUA`=glsY5M-J;okE{&iwzBvSUyK_V;w z&JPGO`(W))SOR5g8B#=p&osv23}Kg5fc>k(0g&=vZbj=VG!ARBU|7>j(zejJFap1z zr<{L)tyb>(pqiO4#XjOn9vE;!3X^vaq4KR~(#@k6#~cv=X&1gN0g zln@pSV4vUHh>?L4WUyT1-XsY;oBrqcJZ{eB-_lp@*&;kXlI`{_fg62os%w|KZ6LLU zbEv`?lf!YdP0QXUPE;hcX`iycV&MjxZ3OQJ7t52bi@a;DR^>CnKg$qD-D!4nh6am& z+NAy{4oX=x^)*mFATIH-<`9PcRq>CX9^$U~YFvrl)f-I)@q}cv2V}RUBKcOguSI>W z{kln6{BjerC&q-bFyryFGU@7NmvR`t_gMJ5_6%wjnvGw7CXqSADqR~0I^efIXi+@h7*g8|oF@TJE2)7KM3dVjV)i|Gu= zJZWquK7B*^eb$8vY_je}a?8mbDR_?kGX|O0`|~Zi%bt)4nqkkv@5s&TAM zU36!rc$I<^OI+*H)h)vzs^8PDa+`G-%Az+nay`3(%PC;zbqDa@mlLh-oRs_mb;@>S{fBa4~=4U>fHCTexV$}{Sy4Wq&A6LEBSrM=z1iq z!-L_4e~AE#^4^b#qjq~eP~vQSboe1&9eO^=Ef6jCruqE#p*~#K;}O20%9Qc5zniR> zWxpvs$Qtk4wP{;sWrdX3>U_GFtfODalB#*a;b>9z4&5;QV+U#u;)^YIIPSK*H!b2p zg(<|&q+?ZZ_dm>)6eceb5Xqr+(4nJle zBdjF@p5+zBv+VK~JE%sbFq;H1=QV1TBP zlo{ym4^0e!ZuFXA*x;Ewpoik!gW;fE7j7L)5zxCtOppfkr*gL}VC_9n3x!i3a}(13 z1IBiz>R}N63eq4F7lc2YMj&aS2aW__V_-=CbQIRMfMj7Y3I^Pdbw7q3ZXn>8;J1bt zCAilTa2$WyphPIOwK!`u8r)obVE}Y@R|5`A|JV^QFf%jEDLC8#bo`ka<}lpj1YVAB z#z`~6wyprcBFBs7fM4wdFt4`#7@+y6vj@vh0sKuL1k8=d^`Qx*^r#Dhlv4*Ws#r7n ze1neuL9GA=B7qLT2HI!@x(YepmR}o99T%c z14af7vj%`pes#ilq2U8T;A#M-Fb5^w6$7*jE(U`!UGruVpR zKsi9+9N5+WE^E#ZOf{9%ygtuh45}2_lNf168#;oSYWQ>nGZj8XM=(>D0Ug0iT?TXn zGu7~E2 z@C?!hs$`;+p*XOdkbMEsj6=3`@Z&%Y6(BE9({}U$6rA;g(K#(^7koAaYCaVYU$p%+t{sBOL6{li&QE*)j==MY!<^&pH zI{;m>OPC927+VOg@s2B)D!A_!7zoPa=ZMgH;gOs)rQNTcAdB4F!AFfH?p%<6IPM z5yp8P@p<7k<_6IJYXUFXlww}P$D6_X9m>FH07sF6FUN#n_t9~FcpU&cBhrC>ps5O) zfA$Hy4l+(U)DN!%__f6UWiJwy|17#vc)AtL?KcW02)1tn6P{XwsRV4;4vfIx)$#?< ziYVpvm_alf9UBP9U+`o%CW-7+u0T0o@X{Qg-qDm2=(*$@~j5NZdUSkShO_hW=5=>S1IK?(c@4I%jNZ%}y$x(HrThNATdQ-OjF z-hkf|8pHsm%g|deCsg(_ny7*>$KjA6%muh`6g;gk47MtmXB-#+%QMVluxckTe`qm8 z+7vkoFp+_N#vh8tPSCeV%GwJ|DH>66q#f0Jz%oSWJ?kwXVS%vj*IR(wOr*;Yn6 zM7k`-9vvdA@d;ei<8P3QYBx!n8BvPhJFs8Dj%yHA-@^lL1`N;i=FAybY7`^9g)WwX zCjm<&(&DdwW&{cR^kC*0j2s2X-s%AsDFnWn9?DUy#xdzAxSWOd{Z?R14KV*FjIaTQ7e zrZJ0f^(vTJK#;ZrT*EbBkWCsm9$5Ggj+Ok__hlqLI$E3K)Ig9{bH$~h0aAxQ$I7bn z=gOE(l6yS%B%T|#dt%L#a%y?^BJXk4L*X`X-?r8$DHn0YeH;0FEvLLLb6CAr`_+Wa z+_`gmv-+0R8{H)>pF?kbQy$lrw+4XjP*8bl}{1w@Q=>Ct5A3dFt@wn=zBF zH1C-q&&rnQUqMByS{={km=aV!9wvGX-rZ5uWxSJXUY@7xI7vV4G+A1BJlQ0QGbpGJPOzvbyZpb z84$z>b&&N?nRORMG5&&)2E=1-Y&g94E=tghNT-7mfXWk*E^$Hthba-bDl`*B1b2z_ zhyWpw6KMg#KQ;qM(;(p1O>a(=fr0QECq?HQMjj2n#bISAA#ZR%YLAH-D@*ZS##{sp z4HodM^bgDh6x`2>m8QI2#cW5z-t6F^@)~k7+HqiI;fRN*4b@m|4+^&B#0mhi9AKNN z(|4ZD$Ro9NftngH#%Nf6C(0Zy??4}-^gviwwAJ6pLF{X0pgnY zSJOlnOa$>S3se`V&k*S$1YTDc4}ajtMj`8g6Bb~?eu1TguwYM`1P7irGj=Orf(e7R zb~Et$vstis6r3#r+CbQI0|jEkx&i%XNh}-8&Wjd-FGixc;Cyy$Ev&f}jJV-Cpkk+U zU^|hxhAK-y+tL6I8xa}bx4;yOP$~~nCm}8N92m7D?0p{PnwB+BQQ*b;qiyIB45Bbj zq(v~mpFrt)4=QwkM@pmz6*@rhn@9^P{<**en#h5(47iFuADLRgxh{v5 zqnHa}fqVfZ51xH0jO{?d9NWReb`fkFcvcB3NV{yQR0+$%gr=;jV&hP@^jHOvTO`s$6+~^3NQ+cJHxWfeBAu+Mhs-FQtcmC=68~2> zlSrgytaM>$HyDQ@5xWdV7XwZtprC1nN=Nm|P=E+x6B2~{=d62%@Bw+Mnll@~n$g1k z1;^u6k<*qQYTyyc9wIH+_~)vU)(^i@b6}EvM=>H4MQyAE8qPWb+P}1b$PiG-21I%i ztYZNvE8q?a9PmMXY&rbG9&{5hLIF#2))D(hHF}J``M~8FkT&SpH8dsL7;A;n{YwBP zfCz;6mjFsYyi~fvC7uAX21Htn@^4Q`Fjo@OK5DiS-1I^nPEEr;hJ~H6>~K;J(^i_c z5Xl8JZOyU!5ylZnPTDdO)s<=bJ=4idhuNsjze&s9ET()hc(a+QeEj(qxB ztT&wFgcXvYYp>8gLOtyN84yiSQx|^jg_R{MtNxc=aBu)<%!#q>9#k(5-B=#o(ycZ zDNuZFq(?R(Tk6f}5%260u}vs0l;>W`xvP5md=E7gM|e%IKhQ3#QLMVu7}2Bk^0No* z{|(23CaP1V-()$^obUl>>;ya?02XSa0~6RVCj!A{2qK0Jlpa^?E)Xq-fy?^vE0ZYv zyA-$zQcg@D@GS`gZvv|3k6}0hOM=ziv0s6iMm+{m8<6r_g9jqP-T-tLj)08C8Dxq{ z`2WtaU8*T^H=CI6f$`Ra1g4jsGkbImnB%r8{>ZOWk7RTaDC%HJkMVQR$vZHG{+4tF z_nF;<(Akk0IrG5$c0pug#fvAq>>9T;3^>Y!JtXBQ*la6~%07!ijf(%Hqkk+6a;nz|b(T#)GGVnhIr1ip!OdLW8# zBzgdhD87;C0WhNYMpEMap9q*li-2|D!f0S$I}6Z&?-ht`M&NIFOl*Xv$?WoAg1#8Eu(wMZ-;zK{SmQ|h6L zNCJS{i%=5}oYdIsO$7KUxV#ia{UI>@smO^$J3?n>m;|?y{)WQH*-4^>!vEcBNceTK zzwt$|j%J&H=+{al7A&FL7r`$7Gl@|Y-Uos~Sf~s%K{js_#o;U#R9b{8LEE$*WOxRm zvF%h9qjjmIzn<9fX`p-rF0>ZtRWt>V&#O_I^l%&Dos($MHaHcL0FXo%142SR5-m{v zx37qwp?4XX>bHnUdr3TYjC$(@AOx@}-Qm?3T$_lkT$eXP#DId=Cw>`k$WwT0(!05;n9l9yv*#!1A@=LQn5~OqaXrK8@*K3)={w>{sZjq=XK>h{8 z8fPRa1JMI>tSxN30J^^|9=9J2?s-8Kv1_fxGV{WdUqDY^S~KpUb>Ffd>%oWy%BfT> zJKSS%2>x0E@Ax}#mGyx)OEVJr;GfIjYvmtf_fSCPZz~$DqK16Z84Y|1>X5%qVWUyt zzBIJU0F>!KLV)xq4hKyjV@Fb<%>ZQv%z(;2GvG!Os}pNwDox7@g1hFh%Zh(;J+yE7 zLvf^i5q(DWz)lT;SZ+`o0aO)L?uh<$O6DSE@nK1;y;2ewC&nWnjBu<91^*eTistFEm^pGys z%Sj=uV6UU#4tbpHy;baU6dIH-fnK=ZzZ)UVqeOVoV3V|fo6kUqEMptR^Eb8;?MDyi z@v0y}L85CC0S^vrS9G0A&;)DyZ|ts01hYts-4VYS(VZjFRe|uTK;DN$i^l)4d{wo- zmJi6>;@#*$Mv^LF-ELHYv^}sJ@C=YGjK>{8gDNW3Y_4H&!W-coBrt=2%|=HY2gEmi ztAlx>T79)7z`!N$!~ri+25g#?H9+v>+lsSCasAOCvI1F0upxtQ2Q^-CxIhZ03u?&J z;1wtpBDG#ej08OjrM~xnBTW)5($s-RG;!>R`Va+3JL@2uF$x3LoAq{F9SU~ci<717 zQUVW=AD|W@z)k@?3vdNAko^;hhv7Rp&OeJ}^tXaVw=gxD zmLS|_h?Ap$dohRrMHFLTAMMmgB+djUOOuTu?7$sDLODFRH5Elc9{UdHo?C*C+}FT? z1bNW`Fm->l$ONhKF#1|Je&hqxIUy00L8n1d1n7HEkKDHcOqXb#{{)hCmgr5CeY$aM}?tvG&vyVUz}_mMD!evQzwwaiD14>;m3Y$BGf9JTk#i1&@Hp639y`gTvw! zGV#X9A3fS45c9-vRVfv*q9|MzxM`FrJs8ymf>tDYFiJf#=oK#NkwLF;=>jQg60O4Z z?-15Y|I0^laxm4sY_r6T!-mJeY_o9y>hXVk$i!pdQXwKu@Vf)J-|$mE(EKB8hfVjr zh9%EP2Fo((OgYY9M_BN#p0g|;E>Ww?2B5lJ-pf|6@^Jf|mx0Cv^lvt^5J9JMS9HHG zv+(uKLGEqe9ZQl!F4teZ=-%M_==F}h**3x=Jm^UBdykKTheom!r~P}E_bLg>CzaO@ zy}rEQyRa6|vp@QbAu|@&F-;tQI~?8YTIKUh_=d-5UH#DOw;kW7xRx@&-9}yrWj8(+ zA?|#|`|BF{fMZ^XWbAFZjooce#78Ht%zL*!YByf0@sp+mElAw7 z*VT?+QBb!5cgowG`?X*C;B5!8TEH}nI*hx7Q3nNN;OC8iJX?i7PLL6pAGmTF)awOq zLIEt02N+)>tl@_hPRn|=?#GG2#x^)%x)vkiw~^@5OH|*CUhD(Hz3{tWoH(MjM1o~P z!1eH%!-?LrMG7FCp-2;9hJ%ue80F;=9B{CxEPKR+z&c1;KjwYV>7Q~0B}nvO8>wrM zXur zn$8k3a`@IA+`9Pg0Qhz)QU~szhO*(f3eZGAJ@72@NF)?U!YWqbfM7=s&J_F_b(4oq z;@)t;Cu_iz{N3cK5i)FAi{pj+<8T(Bh$j}0vqPe5>SwCsafzJkvGzI;i1vwFjkHgw z!)`e^L71%xeCuC-LVewz;Ju2=;R4?&{um4D!w8Is7Lk)cYz%-zM)1=L@ZsNWpr?_c zI1{uwO^cTdwC?|9<7c`bwtT+U`St4D#+pZf0En_MKu;78z z;d_VHXBWn@G8rs+-qvjm(B{8iE2guJ`>yJOe9|t7Lt`H3zE0FB4Tt*8tdfqNZW&C_ zF`j49kV2oc^r5K-y=Oy@*62oG`%xUneSoVWAVJBVtIhC~Ueaw6(xSkpans-Nx` z({NkWC@Ef#-DrMZk9LDy`Uj))E?Ba8-j?kR7(<09zI_>@9r}a8T=C`LZk3RIY@YF& zI{WvQ@As=}P9DqJhu)Uv_r^tjAKI43!;4Ej?zYnFE6!GdN6hcZiiE=lKMmn$?kIP51A$5hJGg?O{D;Fz}^mx5T3}=wk-WXQFoT z9!vD>tFZf(d7w6Y;>)Xo&;7rr-%OPz4cl%M;7Fmwd4Crud$m2g&aJ2a_$$oK()8O2 zE(P|I9y+YEw{o^8$sYqVJ!Y+xl9iWGHES2?H}EpV&1>=PN53~a!$;>b?tIQ}Izj&U z@R{u^4Vk&@qUfuQr@#N~3lD^w5-wkE(TPZ#_@(@b z)N1@ai4BlZ)Q88f3jEB;jhZ3jORp|{{^<17sce({@lW3a4>#pD286$V@uPM4<-#DJ zjz{$9)Xh($f?a2^CLRMnPLL!I-Dr--9wS3XV~_SOM4Y`>787@=I>Y#_S=njJrsY|2 zr+~$*$vaIsb<2Ka|G3RE6|*PP%_umN zcUlO2Anj;z?0!ul)hsVIe^~tRA?ZO^#E~0J%6lv!yt{&w2S7Pn5Q!n82P7 zc~hg2g%13=CW#K8G=i(W*KEFDzXAS!F7lr2PUsoqeQSGTqorURPGUiflc{7V;nEMm zn{1yp4!OCd^AtZX>YY7*WoBr6sQaK^C%HjvpR@Ij`7dH-{Muriq>~JVOywo&I>)VY zbG${Z<1RS(>>Nw9D<2cke{YejVSeBoa}Osvs(IU4=wR$-FBq!CuOb% zlD{cffBCw(Ei*S{QQ>6#@V6P+Y_*Ar>s^A6o|_)pYdB@FThin}jC%5Ri_il(8Pz8g zZNe|FN#47<)%LTs<@e{>higNQm-sEa`gscQw5N7IZBe;7S9Ngl{;l4Ay+Qx0#pg>r zw-)8wO6cx8N4a@fSuOwbE*BufV3@eF+tj!F6&YU@Hu+J1Q zD5HllG`y{oJ81QVlP zyeDOMW)2}bz?r>W)-qFX;w2^4?wJm23LknNTkbb z;Hux|cTl$ZwKT^C1DEv5dtVB<6ccQu`AYMP;j%fIZ;NhjAGRne$t9WyYN~Fj?Pk?J zK9fHBqNj4?25DE%civAEY==HPFpA*gI-D?K_(VFiY?H+;Nza^=4zttTX(NWGkKb?) znj8M={*u+MsfmLO?QI|Q*Ks|Pd$q1=!2>qvY-4$(^`*#Psgx&gK;JWN9q=_?ZCqCGn}`fstY}1I z-#u)SP5$C~L;xR|l6`mR{X_ zLeA~vn&n8A(Id>=T^UKd(d^afJ z+wV0qqV<`bJ5rWaU-0;|`3KU9U-@!L)bWM6c>xF8G%Z^0da(Wb)7p#etF>5mWz5Uo zqsM+B57Kw5{qELV&H3`hZO4;Jye{RK*v9|gVwY#O+Gf5`ZRo1W=~AX9+fle<=!W$^ zPya3G9euFpgS7`v*;aTB7@C~>Vc+9lbH@H#J}zl~ZsoK_Pr`=n^Vzg>>+4v3MDxIY zz3LCy>mT@RpWnhQ^VTKA`ag=YPZ;}mM4h>VDnuO$Y+n0RPQiB?-wE0KLO+{Y;A8lW zKP_3iw(Z+?@}y<)*1k*jbq*({jl=yN8c>c`}URmPer|nc;!FymhZ)sd2bV@ zRJ^+4-tN2ttv_CGvt?xGfzRK*u$Q%L{-O2CdY5*6y!m0Dru5#+yX>#e9MaV6{-}TO zFR$d9-Rq40@Al=~i>Frpv10Fuj1j|L&k4%?C)c{?{%^+ap_44jM?Nin%zx(x->$P3 zjQa7NFE-bnQOW;Y-?#d!T4gV%_B-|JUHa1>FJAk7_@3≧p$)ee=}BC+kYhweHTE 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 delta 61697 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 diff --git a/scripts/manifest.mjs b/scripts/manifest.mjs index 1de02bf..db32060 100644 --- a/scripts/manifest.mjs +++ b/scripts/manifest.mjs @@ -58,7 +58,8 @@ const hostPermissionsByTarget = { "https://*.xingtu.cn/ad/creator/market*", "https://login-api.intelligrow.cn/*", "https://talent-search.intelligrow.cn/*", - "http://192.168.31.21:8083/*" + "http://192.168.31.21:8083/*", + "https://*/*" ] }; diff --git a/scripts/write-latest-manifest.mjs b/scripts/write-latest-manifest.mjs new file mode 100644 index 0000000..dc68d31 --- /dev/null +++ b/scripts/write-latest-manifest.mjs @@ -0,0 +1,35 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { createManifest } from "./manifest.mjs"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const projectRoot = path.resolve(__dirname, ".."); +const releaseDir = path.join(projectRoot, "release"); +const releaseManifest = createManifest({ target: "release" }); +const latestVersion = process.env.LATEST_VERSION ?? releaseManifest.version; +const publicBaseUrl = + process.env.UPDATE_PUBLIC_BASE_URL ?? + `https://example.com/star-chart-search-enhancer/releases/${latestVersion}`; + +const latestManifest = { + guideUrl: `${publicBaseUrl}/星图增强插件-超简单安装使用指南.pdf`, + latestVersion, + minSupportedVersion: releaseManifest.version, + publishedAt: new Date().toISOString().slice(0, 10), + releaseNotes: [ + "支持在插件弹窗中检查新版本", + "支持一键下载最新版插件压缩包和使用说明" + ], + zipUrl: `${publicBaseUrl}/star-chart-search-enhancer-internal.zip` +}; + +await mkdir(releaseDir, { recursive: true }); +await writeFile( + path.join(releaseDir, "latest.json"), + `${JSON.stringify(latestManifest, null, 2)}\n`, + "utf8" +); + +console.log(`Update manifest written to ${path.join(releaseDir, "latest.json")}`); diff --git a/src/background/index.ts b/src/background/index.ts index 56f4160..aa8d602 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -49,6 +49,12 @@ type BatchSubmitMessage = { type: "batch:submit"; }; +type DownloadUpdateMessage = { + filename: string; + type: "update:download"; + url: string; +}; + export function registerBackgroundMessageHandler( chromeLike: ChromeLike = readChromeLike(), dependencies: { @@ -77,6 +83,22 @@ export function registerBackgroundMessageHandler( return true; } + if (isDownloadUpdateMessage(message)) { + void triggerUpdateDownload(chromeLike, message) + .then(() => { + sendResponse({ ok: true, type: "update:download-ack" }); + }) + .catch((error) => { + sendResponse({ + error: error instanceof Error ? error.message : String(error), + ok: false, + type: "update:download-error" + }); + }); + + return true; + } + if (isBatchSubmitMessage(message)) { authController ??= createAuthController({ authClient: createLogtoAuthClient() @@ -161,6 +183,23 @@ export function registerBackgroundMessageHandler( }); } +async function triggerUpdateDownload( + chromeLike: ChromeLike, + message: DownloadUpdateMessage +): Promise { + if (!chromeLike.downloads?.download) { + throw new Error("chrome.downloads.download is unavailable"); + } + + await Promise.resolve( + chromeLike.downloads.download({ + filename: message.filename, + saveAs: true, + url: message.url + }) + ); +} + async function handleAuthMessage( authController: AuthController, message: Parameters[0] & { type: string } @@ -239,6 +278,22 @@ function isDownloadMarketCsvMessage( ); } +function isDownloadUpdateMessage( + message: unknown +): message is DownloadUpdateMessage { + if (!message || typeof message !== "object") { + return false; + } + + const candidate = message as Partial; + return ( + candidate.type === "update:download" && + typeof candidate.filename === "string" && + typeof candidate.url === "string" && + candidate.url.startsWith("https://") + ); +} + function isBatchSubmitMessage(message: unknown): message is BatchSubmitMessage { if (!message || typeof message !== "object") { return false; diff --git a/src/popup/index.ts b/src/popup/index.ts index c00292a..5a870d6 100644 --- a/src/popup/index.ts +++ b/src/popup/index.ts @@ -2,6 +2,8 @@ import { renderDevPanel, renderLoggedIn, renderLoggedOut, + renderUpdateStatus, + setUpdateDownloadStatus, setProtectedApiResult } from "./view"; import { readAuthConfig, type AuthConfig } from "../shared/auth-config"; @@ -10,17 +12,27 @@ import { type AuthResponseMessage } from "../shared/auth-messages"; import { createProtectedApiClient } from "../shared/protected-api-client"; +import { + compareExtensionVersions, + fetchUpdateManifest as fetchUpdateManifestFromUrl, + type UpdateManifest +} from "../shared/update-check"; +import { UPDATE_MANIFEST_URL } from "../shared/update-config"; interface BootPopupOptions { config?: Partial; + currentVersion?: string; document?: Document; fetchProtectedApi?: () => Promise; + fetchUpdateManifest?: () => Promise; sendMessage?: (message: unknown) => Promise; + updateManifestUrl?: string; } export async function bootPopup(options: BootPopupOptions = {}): Promise { const currentDocument = options.document ?? document; const popupConfig = readAuthConfig(options.config); + const currentVersion = options.currentVersion ?? readCurrentVersion(); const root = currentDocument.querySelector("#app"); const HTMLElementCtor = currentDocument.defaultView?.HTMLElement; @@ -48,15 +60,28 @@ export async function bootPopup(options: BootPopupOptions = {}): Promise { baseUrl: "http://127.0.0.1:4319", sendMessage }).loadProtectedMockData; + const fetchUpdateManifest = + options.fetchUpdateManifest ?? + (() => + fetchUpdateManifestFromUrl( + options.updateManifestUrl ?? UPDATE_MANIFEST_URL + )); - await renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi); + await renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi, { + currentVersion, + fetchUpdateManifest + }); } async function renderCurrentAuthState( root: HTMLElement, popupConfig: AuthConfig, sendMessage: (message: unknown) => Promise, - fetchProtectedApi: () => Promise + fetchProtectedApi: () => Promise, + updateOptions: { + currentVersion: string; + fetchUpdateManifest: () => Promise; + } ): Promise { const response = await sendMessage({ type: "auth:get-state" }); if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:state") { @@ -71,19 +96,22 @@ async function renderCurrentAuthState( ?.addEventListener("click", () => { void runAuthAction(root, popupConfig, sendMessage, { actionMessage: { type: "auth:sign-in" }, - fetchProtectedApi + fetchProtectedApi, + updateOptions }); }); return; } renderLoggedIn(root, response.value); + void runUpdateCheck(root, sendMessage, updateOptions); root .querySelector('[data-popup-sign-out="button"]') ?.addEventListener("click", () => { void runAuthAction(root, popupConfig, sendMessage, { actionMessage: { type: "auth:sign-out" }, - fetchProtectedApi + fetchProtectedApi, + updateOptions }); }); if (popupConfig.enableDevAuthPanel) { @@ -103,6 +131,10 @@ async function runAuthAction( options: { actionMessage: { type: "auth:sign-in" } | { type: "auth:sign-out" }; fetchProtectedApi: () => Promise; + updateOptions: { + currentVersion: string; + fetchUpdateManifest: () => Promise; + }; } ): Promise { const response = await sendMessage(options.actionMessage); @@ -121,7 +153,8 @@ async function runAuthAction( root, popupConfig, sendMessage, - options.fetchProtectedApi + options.fetchProtectedApi, + options.updateOptions ); } @@ -133,6 +166,105 @@ function isActionError(response: unknown): response is Extract Promise, + options: { + currentVersion: string; + fetchUpdateManifest: () => Promise; + } +): Promise { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "checking" + }); + + try { + const manifest = await options.fetchUpdateManifest(); + if (compareExtensionVersions(manifest.latestVersion, options.currentVersion) <= 0) { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "latest" + }); + return; + } + + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + manifest, + status: "available" + }); + bindUpdateDownloadButtons(root, sendMessage, manifest); + } catch { + renderUpdateStatus(root, { + currentVersion: options.currentVersion, + status: "error" + }); + } +} + +function bindUpdateDownloadButtons( + root: HTMLElement, + sendMessage: (message: unknown) => Promise, + manifest: UpdateManifest +): void { + root + .querySelector('[data-popup-download-update="button"]') + ?.addEventListener("click", () => { + void downloadUpdateAsset(root, sendMessage, { + filename: "star-chart-search-enhancer-internal.zip", + url: manifest.zipUrl + }); + }); + + root + .querySelector('[data-popup-download-guide="button"]') + ?.addEventListener("click", () => { + void downloadUpdateAsset(root, sendMessage, { + filename: "星图增强插件-超简单安装使用指南.pdf", + url: manifest.guideUrl + }); + }); +} + +async function downloadUpdateAsset( + root: HTMLElement, + sendMessage: (message: unknown) => Promise, + options: { + filename: string; + url: string; + } +): Promise { + setUpdateDownloadStatus(root, "正在下载..."); + try { + await sendMessage({ + filename: options.filename, + type: "update:download", + url: options.url + }); + setUpdateDownloadStatus(root, "已触发下载。下载后请解压新版 zip,并在 chrome://extensions 里重新加载插件。"); + } catch (error) { + setUpdateDownloadStatus( + root, + error instanceof Error ? error.message : "下载失败,请稍后重试" + ); + } +} + +function readCurrentVersion(): string { + const runtime = ( + globalThis as typeof globalThis & { + chrome?: { + runtime?: { + getManifest?: () => { version?: string }; + }; + }; + } + ).chrome?.runtime; + + return runtime?.getManifest?.().version ?? "0.0.0"; +} + async function runProtectedApiProbe( root: HTMLElement, fetchProtectedApi: () => Promise diff --git a/src/popup/view.ts b/src/popup/view.ts index eb51477..e5fce55 100644 --- a/src/popup/view.ts +++ b/src/popup/view.ts @@ -1,4 +1,5 @@ import type { AuthStateValue } from "../shared/auth-messages"; +import type { UpdateManifest } from "../shared/update-check"; export function renderLoggedOut(root: HTMLElement, error?: string | null): void { root.innerHTML = ` @@ -23,11 +24,99 @@ export function renderLoggedIn(

已登录

${userInfo?.name ?? userInfo?.username ?? "未知用户"}

${userInfo?.email ?? ""}

+
+

版本更新

+

正在检查更新...

+
`; } +export function renderUpdateStatus( + root: HTMLElement, + options: { + currentVersion: string; + manifest?: UpdateManifest; + status: "checking" | "error" | "latest" | "available"; + } +): void { + const container = root.querySelector('[data-popup-update="root"]'); + if (!container) { + return; + } + + if (options.status === "checking") { + container.innerHTML = ` +

版本更新

+

当前版本:${options.currentVersion}

+

正在检查更新...

+ `; + return; + } + + if (options.status === "error") { + container.innerHTML = ` +

版本更新

+

当前版本:${options.currentVersion}

+

暂时无法检查更新

+

如果需要新版,请联系维护同事获取更新包。

+ `; + return; + } + + if (options.status === "latest" || !options.manifest) { + container.innerHTML = ` +

版本更新

+

当前版本:${options.currentVersion}

+

当前已是最新版本

+ `; + return; + } + + container.innerHTML = ` +

版本更新

+

当前版本:${options.currentVersion}

+

发现新版本:${options.manifest.latestVersion}

+ ${renderReleaseNotes(options.manifest.releaseNotes)} + + +

下载后请解压新版 zip,并在 chrome://extensions 里重新加载插件。

+ `; +} + +export function setUpdateDownloadStatus( + root: HTMLElement, + value: string +): void { + const output = root.querySelector('[data-popup-update-download-status="text"]'); + if (!output) { + return; + } + + output.textContent = value; +} + +function renderReleaseNotes(releaseNotes: string[]): string { + if (releaseNotes.length === 0) { + return ""; + } + + return ` +
    + ${releaseNotes.map((note) => `
  • ${escapeHtml(note)}
  • `).join("")} +
+ `; +} + +function escapeHtml(value: string): string { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + export function renderDevPanel( root: HTMLElement, authState: AuthStateValue diff --git a/src/shared/update-check.ts b/src/shared/update-check.ts new file mode 100644 index 0000000..9909e29 --- /dev/null +++ b/src/shared/update-check.ts @@ -0,0 +1,94 @@ +export interface UpdateManifest { + guideUrl: string; + latestVersion: string; + minSupportedVersion: string; + publishedAt: string; + releaseNotes: string[]; + zipUrl: string; +} + +export function compareExtensionVersions(left: string, right: string): number { + const leftParts = parseVersionParts(left); + const rightParts = parseVersionParts(right); + const maxLength = Math.max(leftParts.length, rightParts.length); + + for (let index = 0; index < maxLength; index += 1) { + const leftValue = leftParts[index] ?? 0; + const rightValue = rightParts[index] ?? 0; + if (leftValue !== rightValue) { + return leftValue - rightValue; + } + } + + return 0; +} + +export function parseUpdateManifest(value: unknown): UpdateManifest | null { + if (!value || typeof value !== "object") { + return null; + } + + const candidate = value as Partial; + if ( + !isVersionString(candidate.latestVersion) || + !isVersionString(candidate.minSupportedVersion) || + !isHttpsUrl(candidate.zipUrl) || + !isHttpsUrl(candidate.guideUrl) || + typeof candidate.publishedAt !== "string" || + !Array.isArray(candidate.releaseNotes) || + !candidate.releaseNotes.every((note) => typeof note === "string") + ) { + return null; + } + + return { + guideUrl: candidate.guideUrl, + latestVersion: candidate.latestVersion, + minSupportedVersion: candidate.minSupportedVersion, + publishedAt: candidate.publishedAt, + releaseNotes: candidate.releaseNotes, + zipUrl: candidate.zipUrl + }; +} + +export async function fetchUpdateManifest( + manifestUrl: string, + fetchImpl: typeof fetch = fetch +): Promise { + const response = await fetchImpl(manifestUrl, { + cache: "no-store" + }); + if (!response.ok) { + throw new Error(`update manifest request failed: ${response.status}`); + } + + const manifest = parseUpdateManifest(await response.json()); + if (!manifest) { + throw new Error("update manifest is invalid"); + } + + return manifest; +} + +function parseVersionParts(value: string): number[] { + return value.split(".").map((part) => { + const parsed = Number.parseInt(part, 10); + return Number.isFinite(parsed) ? parsed : 0; + }); +} + +function isVersionString(value: unknown): value is string { + return typeof value === "string" && /^\d+(?:\.\d+)*$/.test(value); +} + +function isHttpsUrl(value: unknown): value is string { + if (typeof value !== "string") { + return false; + } + + try { + return new URL(value).protocol === "https:"; + } catch { + return false; + } +} diff --git a/src/shared/update-config.ts b/src/shared/update-config.ts new file mode 100644 index 0000000..360e599 --- /dev/null +++ b/src/shared/update-config.ts @@ -0,0 +1,2 @@ +export const UPDATE_MANIFEST_URL = + "https://example.com/star-chart-search-enhancer/latest.json"; diff --git a/tests/background-index.test.ts b/tests/background-index.test.ts index 64ab09f..5a59ce2 100644 --- a/tests/background-index.test.ts +++ b/tests/background-index.test.ts @@ -48,6 +48,50 @@ describe("background-index", () => { expect(sendResponse).toHaveBeenCalledWith({ ok: true }); }); + test("downloads extension update assets", async () => { + const listeners: Array< + (message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean | void + > = []; + const download = vi.fn(async () => undefined); + const sendResponse = vi.fn(); + + registerBackgroundMessageHandler({ + downloads: { + download + }, + runtime: { + onMessage: { + addListener(listener) { + listeners.push(listener); + } + } + } + }); + + const result = listeners[0]( + { + filename: "star-chart-search-enhancer-internal.zip", + type: "update:download", + url: "https://cos.example.com/star-chart-search-enhancer/releases/0.2.0421.3/star-chart-search-enhancer-internal.zip" + }, + {}, + sendResponse + ); + + expect(result).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(download).toHaveBeenCalledWith({ + filename: "star-chart-search-enhancer-internal.zip", + saveAs: true, + url: "https://cos.example.com/star-chart-search-enhancer/releases/0.2.0421.3/star-chart-search-enhancer-internal.zip" + }); + expect(sendResponse).toHaveBeenCalledWith({ + ok: true, + type: "update:download-ack" + }); + }); + test("responds to auth:get-state with auth status", async () => { const listeners: Array< (message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean | void diff --git a/tests/manifest.test.ts b/tests/manifest.test.ts index 80f8694..a0d67fc 100644 --- a/tests/manifest.test.ts +++ b/tests/manifest.test.ts @@ -43,10 +43,11 @@ describe("manifest", () => { "https://*.xingtu.cn/ad/creator/market*", "https://login-api.intelligrow.cn/*", "https://talent-search.intelligrow.cn/*", - "http://192.168.31.21:8083/*" + "http://192.168.31.21:8083/*", + "https://*/*" ]); expect(releaseManifest.host_permissions).not.toEqual( - expect.arrayContaining(["http://*/*", "https://*/*", "http://127.0.0.1:4319/*"]) + expect.arrayContaining(["http://*/*", "http://127.0.0.1:4319/*"]) ); }); diff --git a/tests/popup-entry.test.ts b/tests/popup-entry.test.ts index 42289a1..1bc2ef4 100644 --- a/tests/popup-entry.test.ts +++ b/tests/popup-entry.test.ts @@ -51,6 +51,101 @@ describe("popup-entry", () => { expect(dom.window.document.body.textContent).toContain("token"); }); + test("shows available extension updates in the popup", async () => { + const fetchUpdateManifest = vi.fn(async () => ({ + guideUrl: "https://cos.example.com/guide.pdf", + latestVersion: "0.2.0421.3", + minSupportedVersion: "0.2.0421.2", + publishedAt: "2026-05-19", + releaseNotes: ["支持检查更新"], + zipUrl: "https://cos.example.com/plugin.zip" + })); + + dom.window.document.body.innerHTML = "
"; + + await bootPopup({ + currentVersion: "0.2.0421.2", + document: dom.window.document, + fetchUpdateManifest, + sendMessage: vi.fn(async () => ({ + ok: true, + type: "auth:state", + value: { + isAuthenticated: true, + userInfo: { name: "Dev" } + } + })) + }); + await Promise.resolve(); + + expect(fetchUpdateManifest).toHaveBeenCalledTimes(1); + expect(dom.window.document.body.textContent).toContain("当前版本:0.2.0421.2"); + expect(dom.window.document.body.textContent).toContain("发现新版本:0.2.0421.3"); + expect(dom.window.document.body.textContent).toContain("支持检查更新"); + expect( + dom.window.document.querySelector('[data-popup-download-update="button"]') + ).not.toBeNull(); + expect( + dom.window.document.querySelector('[data-popup-download-guide="button"]') + ).not.toBeNull(); + }); + + test("downloads update assets from popup buttons", async () => { + const sendMessage = vi + .fn() + .mockResolvedValueOnce({ + ok: true, + type: "auth:state", + value: { + isAuthenticated: true, + userInfo: { name: "Dev" } + } + }) + .mockResolvedValue({ ok: true, type: "update:download-ack" }); + + dom.window.document.body.innerHTML = "
"; + + await bootPopup({ + currentVersion: "0.2.0421.2", + document: dom.window.document, + fetchUpdateManifest: vi.fn(async () => ({ + guideUrl: "https://cos.example.com/guide.pdf", + latestVersion: "0.2.0421.3", + minSupportedVersion: "0.2.0421.2", + publishedAt: "2026-05-19", + releaseNotes: [], + zipUrl: "https://cos.example.com/plugin.zip" + })), + sendMessage + }); + await Promise.resolve(); + + ( + dom.window.document.querySelector( + '[data-popup-download-update="button"]' + ) as HTMLButtonElement | null + )?.click(); + ( + dom.window.document.querySelector( + '[data-popup-download-guide="button"]' + ) as HTMLButtonElement | null + )?.click(); + + await Promise.resolve(); + await Promise.resolve(); + + expect(sendMessage).toHaveBeenCalledWith({ + filename: "star-chart-search-enhancer-internal.zip", + type: "update:download", + url: "https://cos.example.com/plugin.zip" + }); + expect(sendMessage).toHaveBeenCalledWith({ + filename: "星图增强插件-超简单安装使用指南.pdf", + type: "update:download", + url: "https://cos.example.com/guide.pdf" + }); + }); + test("renders a protected api test button in the dev panel", async () => { dom.window.document.body.innerHTML = "
"; diff --git a/tests/update-check.test.ts b/tests/update-check.test.ts new file mode 100644 index 0000000..2c468e1 --- /dev/null +++ b/tests/update-check.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, test } from "vitest"; + +import { + compareExtensionVersions, + parseUpdateManifest +} from "../src/shared/update-check"; + +describe("update-check", () => { + test("compares dotted extension versions numerically", () => { + expect(compareExtensionVersions("0.2.0421.3", "0.2.0421.2")).toBeGreaterThan(0); + expect(compareExtensionVersions("0.2.10.0", "0.2.9.9")).toBeGreaterThan(0); + expect(compareExtensionVersions("0.2.0421.2", "0.2.0421.2")).toBe(0); + expect(compareExtensionVersions("0.2.0421.1", "0.2.0421.2")).toBeLessThan(0); + }); + + test("parses a valid update manifest", () => { + expect( + parseUpdateManifest({ + guideUrl: "https://cos.example.com/guide.pdf", + latestVersion: "0.2.0421.3", + minSupportedVersion: "0.2.0421.2", + publishedAt: "2026-05-19", + releaseNotes: ["支持检查更新"], + zipUrl: "https://cos.example.com/plugin.zip" + }) + ).toEqual({ + guideUrl: "https://cos.example.com/guide.pdf", + latestVersion: "0.2.0421.3", + minSupportedVersion: "0.2.0421.2", + publishedAt: "2026-05-19", + releaseNotes: ["支持检查更新"], + zipUrl: "https://cos.example.com/plugin.zip" + }); + }); + + test("rejects invalid update manifests", () => { + expect(parseUpdateManifest({ latestVersion: "0.2.0421.3" })).toBeNull(); + expect( + parseUpdateManifest({ + guideUrl: "javascript:alert(1)", + latestVersion: "0.2.0421.3", + minSupportedVersion: "0.2.0421.2", + publishedAt: "2026-05-19", + releaseNotes: [], + zipUrl: "https://cos.example.com/plugin.zip" + }) + ).toBeNull(); + }); +});