wherdr 1.3.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/BDNMzG2s.js +1 -0
- package/.output/public/_nuxt/BETID3_E.js +1 -0
- package/.output/public/_nuxt/BHenDMeH.js +1 -0
- package/.output/public/_nuxt/{CJKsMzIp.js → BYZVrreW.js} +1 -1
- package/.output/public/_nuxt/BhgehRdJ.js +1 -0
- package/.output/public/_nuxt/BtH82ZuZ.js +9 -0
- package/.output/public/_nuxt/C3Bkn4ac.js +62 -0
- package/.output/public/_nuxt/CuUQ4mEf.js +1 -0
- package/.output/public/_nuxt/DFGEl0v2.js +23 -0
- package/.output/public/_nuxt/{DMLmW6JM.js → DFmgQVme.js} +41 -42
- package/.output/public/_nuxt/DZGKxROq.js +6 -0
- package/.output/public/_nuxt/DmkWvmnE.js +2 -0
- package/.output/public/_nuxt/DrKKeFFE.js +31 -0
- package/.output/public/_nuxt/DyfFwwGq.js +1 -0
- package/.output/public/_nuxt/FaNto0ga.js +105 -0
- package/.output/public/_nuxt/NIF0VwHk.js +25 -0
- package/.output/public/_nuxt/{w7Rm7unj.js → R0Y4VoeX.js} +1 -1
- package/.output/public/_nuxt/board.CEEcFc6M.css +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/0b28b3e9-664e-4347-a35b-afb0a711d5c5.json +1 -0
- package/.output/public/_nuxt/entry.CKoXcwRa.css +2 -0
- package/.output/public/_nuxt/settings.Cdb21nNw.css +1 -0
- package/.output/public/sw.js +1 -1
- package/.output/server/chunks/_/branding.mjs +1 -1
- package/.output/server/chunks/_/changes.mjs +4 -4
- package/.output/server/chunks/_/fileDownload.mjs +278 -0
- package/.output/server/chunks/_/files.mjs +44 -17
- package/.output/server/chunks/_/machineOrder.mjs +1 -1
- package/.output/server/chunks/_/onboarding.mjs +1 -1
- package/.output/server/chunks/_/package.mjs +9 -3
- package/.output/server/chunks/_/plugins.mjs +92 -125
- package/.output/server/chunks/_/restart.mjs +1 -1
- package/.output/server/chunks/_/selfupdate.mjs +1 -1
- package/.output/server/chunks/_/updates.mjs +1 -1
- package/.output/server/chunks/_/worktrees.mjs +1 -1
- package/.output/server/chunks/_/ws.mjs +43 -6
- package/.output/server/chunks/nitro/nitro.mjs +14033 -10618
- package/.output/server/chunks/raw/check-doc-links.mjs +5 -0
- package/.output/server/chunks/raw/check-leaks.mjs +1 -1
- package/.output/server/chunks/raw/check-release-notes.mjs +5 -0
- package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
- package/.output/server/chunks/raw/install-claude-statusline.mjs +1 -1
- package/.output/server/chunks/raw/prerelease-summary.mjs +5 -0
- package/.output/server/chunks/raw/prerelease.mjs +7 -0
- package/.output/server/chunks/raw/reveal.mjs +1 -1
- package/.output/server/chunks/raw/test-affected.mjs +5 -0
- package/.output/server/chunks/routes/api/_..._.mjs +6 -5
- package/.output/server/chunks/routes/api/agents.post.mjs +6 -5
- package/.output/server/chunks/routes/api/ask-tab.post.mjs +6 -5
- package/.output/server/chunks/routes/api/attach.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/disable.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/lock.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/login/options.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/max-session.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/register/options.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +6 -5
- package/.output/server/chunks/routes/api/auth/status.get.mjs +6 -5
- package/.output/server/chunks/routes/api/changes.get.mjs +7 -6
- package/.output/server/chunks/routes/api/chat/image.get.mjs +7 -6
- package/.output/server/chunks/routes/api/chat.get.mjs +20 -7
- package/.output/server/chunks/routes/api/choose.post.mjs +31 -17
- package/.output/server/chunks/routes/api/claude-setup.post.mjs +42 -0
- package/.output/server/chunks/routes/api/claude-statusline.post.mjs +7 -6
- package/.output/server/chunks/routes/api/clear-queued-input.post.mjs +42 -0
- package/.output/server/chunks/routes/api/close/status.get.mjs +7 -6
- package/.output/server/chunks/routes/api/close.post.mjs +6 -5
- package/.output/server/chunks/routes/api/codex-update.post.mjs +7 -6
- package/.output/server/chunks/routes/api/commands.get.mjs +7 -6
- package/.output/server/chunks/routes/api/config.get.mjs +10 -13
- package/.output/server/chunks/routes/api/dirs.get.mjs +7 -6
- package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +7 -6
- package/.output/server/chunks/routes/api/dismiss.post.mjs +7 -6
- package/.output/server/chunks/routes/api/effort.post.mjs +7 -6
- package/.output/server/chunks/routes/api/efforts.get.mjs +7 -6
- package/.output/server/chunks/routes/api/file.post.mjs +7 -6
- package/.output/server/chunks/routes/api/files/download.get.mjs +12 -31
- package/.output/server/chunks/routes/api/files/download.head.mjs +41 -0
- package/.output/server/chunks/routes/api/files/read.get.mjs +8 -7
- package/.output/server/chunks/routes/api/files.get.mjs +7 -6
- package/.output/server/chunks/routes/api/health.get.mjs +6 -5
- package/.output/server/chunks/routes/api/input.post.mjs +7 -6
- package/.output/server/chunks/routes/api/interrupt.post.mjs +24 -21
- package/.output/server/chunks/routes/api/isgit.get.mjs +8 -8
- package/.output/server/chunks/routes/api/machine/awake.get.mjs +7 -6
- package/.output/server/chunks/routes/api/machine/awake.post.mjs +7 -6
- package/.output/server/chunks/routes/api/machine/order.get.mjs +6 -5
- package/.output/server/chunks/routes/api/machine/order.post.mjs +6 -5
- package/.output/server/chunks/routes/api/machine/reconnect.post.mjs +40 -0
- package/.output/server/chunks/routes/api/machine/rename.post.mjs +7 -6
- package/.output/server/chunks/routes/api/machine/status.post.mjs +39 -0
- package/.output/server/chunks/routes/api/menu-left.post.mjs +40 -0
- package/.output/server/chunks/routes/api/menu.post.mjs +7 -6
- package/.output/server/chunks/routes/api/model.post.mjs +7 -6
- package/.output/server/chunks/routes/api/models.get.mjs +7 -6
- package/.output/server/chunks/routes/api/nav.post.mjs +7 -6
- package/.output/server/chunks/routes/api/onboarding.get.mjs +6 -5
- package/.output/server/chunks/routes/api/onboarding.post.mjs +6 -5
- package/.output/server/chunks/routes/api/phone.get.mjs +8 -10
- package/.output/server/chunks/routes/api/phone.post.mjs +8 -10
- package/.output/server/chunks/routes/api/plugins/actions.get.mjs +6 -10
- package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +6 -10
- package/.output/server/chunks/routes/api/plugins/projects.get.mjs +10 -9
- package/.output/server/chunks/routes/api/plugins/projects.post.mjs +11 -8
- package/.output/server/chunks/routes/api/prompt.post.mjs +22 -13
- package/.output/server/chunks/routes/api/push/quiet.post.mjs +7 -6
- package/.output/server/chunks/routes/api/push/subscribe.post.mjs +7 -7
- package/.output/server/chunks/routes/api/push/test.post.mjs +7 -6
- package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +7 -6
- package/.output/server/chunks/routes/api/quotas.get.mjs +7 -6
- package/.output/server/chunks/routes/api/rename.post.mjs +6 -5
- package/.output/server/chunks/routes/api/requeue.post.mjs +7 -6
- package/.output/server/chunks/routes/api/restart.get.mjs +6 -5
- package/.output/server/chunks/routes/api/restart.post.mjs +6 -5
- package/.output/server/chunks/routes/api/reveal.post.mjs +91 -8
- package/.output/server/chunks/routes/api/screen-key.post.mjs +7 -6
- package/.output/server/chunks/routes/api/screen.get.mjs +7 -6
- package/.output/server/chunks/routes/api/search.get.mjs +7 -6
- package/.output/server/chunks/routes/api/seen.post.mjs +7 -6
- package/.output/server/chunks/routes/api/sessions.get.mjs +7 -6
- package/.output/server/chunks/routes/api/sessions.post.mjs +7 -6
- package/.output/server/chunks/routes/api/settings-tab.post.mjs +7 -6
- package/.output/server/chunks/routes/api/{plugins/thread-limits.get.mjs → settings.get.mjs} +10 -9
- package/.output/server/chunks/routes/api/settings.post.mjs +40 -0
- package/.output/server/chunks/routes/api/space.post.mjs +34 -18
- package/.output/server/chunks/routes/api/state.get.mjs +7 -6
- package/.output/server/chunks/routes/api/tasks/action.post.mjs +39 -0
- package/.output/server/chunks/routes/api/{plugins/profiles.get.mjs → tasks/add.post.mjs} +12 -16
- package/.output/server/chunks/routes/api/tasks/after.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/approve.post.mjs +39 -0
- package/.output/server/chunks/routes/api/{project/report.get.mjs → tasks/archived.get.mjs} +12 -14
- package/.output/server/chunks/routes/api/{index.get.mjs → tasks/autopilot.get.mjs} +13 -14
- package/.output/server/chunks/routes/api/tasks/autopilot.post.mjs +39 -0
- package/.output/server/chunks/routes/api/{gitroot.get.mjs → tasks/board-settings.get.mjs} +12 -14
- package/.output/server/chunks/routes/api/tasks/board-settings.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/coordinator.get.mjs +40 -0
- package/.output/server/chunks/routes/api/tasks/coordinator.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/details.get.mjs +40 -0
- package/.output/server/chunks/routes/api/tasks/limit.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/links.get.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/models.get.mjs +40 -0
- package/.output/server/chunks/routes/api/tasks/pick.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/question.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks/scheduled.get.mjs +40 -0
- package/.output/server/chunks/routes/api/{project → tasks}/settings.get.mjs +10 -12
- package/.output/server/chunks/routes/api/tasks/start.get.mjs +40 -0
- package/.output/server/chunks/routes/api/tasks/tell.post.mjs +39 -0
- package/.output/server/chunks/routes/api/tasks.get.mjs +39 -0
- package/.output/server/chunks/routes/api/unqueue.post.mjs +7 -6
- package/.output/server/chunks/routes/api/update/status.get.mjs +6 -5
- package/.output/server/chunks/routes/api/update.get.mjs +8 -10
- package/.output/server/chunks/routes/api/update.post.mjs +8 -10
- package/.output/server/chunks/routes/api/upload.post.mjs +7 -6
- package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +6 -5
- package/.output/server/chunks/routes/api/worktrees.get.mjs +6 -5
- package/.output/server/chunks/routes/favicon.ico.get.mjs +6 -5
- package/.output/server/chunks/routes/icons/_name_.get.mjs +7 -6
- package/.output/server/chunks/routes/renderer.mjs +8 -7
- package/.output/server/chunks/routes/uploads/_...name_.get.mjs +7 -6
- package/.output/server/chunks/routes/ws/_..._.mjs +7 -6
- package/.output/server/chunks/routes/ws/events.mjs +9 -7
- package/.output/server/chunks/routes/ws/term.mjs +7 -6
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +7 -6
- package/.output/server/package.json +1 -1
- package/README.md +44 -1445
- package/bin/lib/commands.mjs +44 -9
- package/bin/lib/panel.mjs +3 -11
- package/bin/lib/service.mjs +41 -2
- package/bin/lib/skill.mjs +1 -1
- package/bin/lib/tailnet.d.mts +6 -3
- package/bin/lib/tailnet.mjs +70 -32
- package/bin/lib/userpath.d.mts +14 -0
- package/bin/lib/userpath.mjs +142 -0
- package/docs/README.md +58 -0
- package/docs/RELEASING.md +174 -0
- package/docs/board.md +164 -0
- package/docs/command.md +58 -0
- package/docs/configuration.md +39 -0
- package/docs/conversation.md +132 -0
- package/docs/development.md +38 -0
- package/docs/devices.md +58 -0
- package/docs/files.md +29 -0
- package/docs/herdr-projects-1x.md +278 -0
- package/docs/home.md +52 -0
- package/docs/installation.md +174 -0
- package/docs/machines.md +69 -0
- package/docs/migrate-from-1.x-docker.md +160 -0
- package/docs/networks.md +154 -0
- package/docs/notifications.md +83 -0
- package/docs/overview.md +71 -0
- package/docs/phone.md +26 -0
- package/docs/plugins.md +109 -0
- package/docs/quick-start.md +89 -0
- package/docs/quotas.md +65 -0
- package/docs/release-notes-2.0.0.md +84 -0
- package/docs/security.md +117 -0
- package/docs/terminal.md +15 -0
- package/docs/troubleshooting.md +45 -0
- package/package.json +9 -3
- package/skills/wherdr/SKILL.md +24 -173
- package/.output/public/_nuxt/BEJHMUrj.js +0 -1
- package/.output/public/_nuxt/BOtcEDnA.js +0 -1
- package/.output/public/_nuxt/BUaYhQ2r.js +0 -6
- package/.output/public/_nuxt/CJNhn9sA.js +0 -36
- package/.output/public/_nuxt/COCvtdHN.js +0 -89
- package/.output/public/_nuxt/Cl45J6_Q.js +0 -1
- package/.output/public/_nuxt/CndPDbMI.js +0 -2
- package/.output/public/_nuxt/Ctbx58Um.js +0 -23
- package/.output/public/_nuxt/Dl1PHLOB.js +0 -1
- package/.output/public/_nuxt/Nhex3_iH.js +0 -1
- package/.output/public/_nuxt/OpWX45i7.js +0 -89
- package/.output/public/_nuxt/builds/meta/4994f3a4-4126-4f57-a9e5-c7ebb25850bc.json +0 -1
- package/.output/public/_nuxt/dTj21DMs.js +0 -1
- package/.output/public/_nuxt/entry.BohTWE-n.css +0 -2
- package/.output/public/_nuxt/kwSoIiM7.js +0 -1
- package/.output/public/_nuxt/mkEwYka4.js +0 -1
- package/.output/server/chunks/_/pluginPolicy.mjs +0 -93
- package/.output/server/chunks/_/projectBoard.mjs +0 -363
- package/.output/server/chunks/_/projectDocs.mjs +0 -106
- package/.output/server/chunks/_/projectInbox.mjs +0 -135
- package/.output/server/chunks/_/projectThreads.mjs +0 -46
- package/.output/server/chunks/_/projectThreads2.mjs +0 -61
- package/.output/server/chunks/_/projectsActions.mjs +0 -143
- package/.output/server/chunks/_/projectsPlugin.mjs +0 -30
- package/.output/server/chunks/_/projectsPlugin2.mjs +0 -57
- package/.output/server/chunks/_/reveal.mjs +0 -115
- package/.output/server/chunks/raw/dev.wherdr.open.mjs +0 -7
- package/.output/server/chunks/raw/docker-entrypoint.mjs +0 -7
- package/.output/server/chunks/raw/install-host-open.mjs +0 -7
- package/.output/server/chunks/raw/wherdr-open.mjs +0 -7
- package/.output/server/chunks/routes/api/board.get.mjs +0 -148
- package/.output/server/chunks/routes/api/plugins/thread-limits.post.mjs +0 -45
- package/.output/server/chunks/routes/api/project/inbox.get.mjs +0 -44
- package/.output/server/chunks/routes/api/project/inbox.post.mjs +0 -44
- package/.output/server/chunks/routes/api/project/memory.get.mjs +0 -43
- package/.output/server/chunks/routes/api/project/routines.get.mjs +0 -44
- package/.output/server/chunks/routes/api/project/thread.get.mjs +0 -45
- package/.output/server/chunks/routes/api/project/thread.post.mjs +0 -47
- package/bin/install-docker-skill.sh +0 -20
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const checkDocLinks = "import { existsSync, readFileSync, statSync } from 'node:fs'\nimport { dirname, extname, resolve } from 'node:path'\nimport { execFileSync } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport { marked } from 'marked'\n\nconst root = fileURLToPath(new URL('../', import.meta.url))\nconst repo = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))\n .repository.url.replace(/^git\\+/, '').replace(/\\.git$/, '')\nconst rawRepo = `${repo.replace('github.com', 'raw.githubusercontent.com')}/main/`\n\n// GitHub heading IDs preserve each space as a dash, including consecutive ones.\nfunction anchors(tokens, source) {\n const ids = new Set([...source.matchAll(/\\bid=[\"']([^\"']+)[\"']/g)].map(m => m[1]))\n marked.walkTokens(tokens, token => {\n if (token.type !== 'heading') return\n const base = token.text.replace(/<[^>]*>/g, '').replace(/[*_`]/g, '').toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\p{M}\\s-]/gu, '').trim().replace(/\\s/g, '-')\n let id = base\n for (let n = 1; ids.has(id); n++) id = `${base}-${n}`\n ids.add(id)\n })\n return ids\n}\n\n/** Check Markdown/HTML links and repository documentation URLs without network requests. */\nexport function checkDocLinks() {\n const files = execFileSync('git', ['ls-files', '--cached', '--others', '--exclude-standard'], { cwd: root, encoding: 'utf8' }).trim().split('\\n')\n const cache = new Map()\n const errors = []\n function document(path) {\n if (!cache.has(path)) {\n const source = readFileSync(path, 'utf8')\n const tokens = marked.lexer(source)\n cache.set(path, { source, tokens, ids: anchors(tokens, source) })\n }\n return cache.get(path)\n }\n function check(file, href) {\n let target = href.replace(/&/g, '&')\n if (target.startsWith(`${repo}/blob/main/`)) target = target.slice(`${repo}/blob/main/`.length)\n else if (target.startsWith(`${repo}#`)) target = `README.md${target.slice(repo.length)}`\n else if (target.startsWith(rawRepo)) target = target.slice(rawRepo.length)\n else if (/^[a-z][\\w+.-]*:|^\\/\\//i.test(target)) return\n else if (target.startsWith('/')) return // App/site routes are not repository paths.\n else return checkLocal(file, target, dirname(resolve(root, file)))\n checkLocal(file, target, root)\n }\n function checkLocal(file, target, base) {\n const [path, hash] = target.split('#')\n const full = path ? resolve(base, decodeURIComponent(path.split('?')[0])) : resolve(root, file)\n if (!existsSync(full)) { errors.push(`${file}: missing file ${target}`); return }\n if (hash && extname(full) === '.md' && statSync(full).isFile() && !document(full).ids.has(decodeURIComponent(hash))) {\n errors.push(`${file}: missing anchor ${target}`)\n }\n }\n for (const file of [...new Set(files)]) {\n if (!/\\.(md|txt|vue|ts|mjs|css)$/.test(file) && file !== 'website/public/install') continue\n const full = resolve(root, file)\n if (!existsSync(full)) continue\n const source = readFileSync(full, 'utf8')\n if (file.endsWith('.md')) {\n const { tokens } = document(full)\n marked.walkTokens(tokens, token => {\n if (token.type === 'link' || token.type === 'image') check(file, token.href)\n if (token.type === 'html') {\n for (const [, href] of token.text.matchAll(/(?:href|src)=[\"']([^\"']+)[\"']/g)) check(file, href)\n }\n })\n }\n // Also cover plain URLs in agent guides and URLs composed from REPO in Vue/TS/shell.\n const expanded = source.replaceAll('${REPO}', repo).replaceAll('https://github.com/$REPO', repo)\n for (const [url] of expanded.matchAll(/https:\\/\\/github\\.com\\/[^/\\s]+\\/[^/\\s]+\\/blob\\/main\\/docs\\/[^\\s\"'`<>)}$]+/g)) {\n if (url.startsWith(`${repo}/`)) check(file, url.replace(/[.,;:]+$/, ''))\n }\n for (const [path] of expanded.matchAll(/(?<=[\"'])\\/blob\\/main\\/docs\\/[^\\s\"'`<>)}$]+/g)) check(file, `${repo}${path}`)\n for (const [url] of expanded.matchAll(/https:\\/\\/github\\.com\\/[^/\\s]+\\/[^/#\\s]+#[\\w-]+/g)) {\n if (url.startsWith(`${repo}#`)) check(file, url)\n }\n }\n return [...new Set(errors)]\n}\n\nif (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n const errors = checkDocLinks()\n if (errors.length) { console.error(errors.join('\\n')); process.exitCode = 1 }\n else console.log('Documentation links: files and anchors OK (including app, site and agent guides).')\n}\n";
|
|
3
|
+
|
|
4
|
+
export { checkDocLinks as default };
|
|
5
|
+
//# sourceMappingURL=check-doc-links.mjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ROLLUP_NO_REPLACE
|
|
2
|
-
const checkLeaks = "#!/usr/bin/env node\n// Leak check: gitleaks + forbidden patterns read from a local, untracked file (.leak-patterns).\n// (default) scans the content of the git index (tracked or staged files)\n// --staged only scans staged files (pre-commit hook)\n// --range <revs> scans every commit of a revision range (`origin/main..HEAD`): the lines\n// each commit adds and its message, so a leak added then removed is caught\n// --no-gitleaks skips gitleaks (patterns only)\n// gitleaks runs from the `gitleaks` binary, otherwise from the `zricethezav/gitleaks` Docker image\n// (read-only mounts), otherwise it is skipped.\n// In a linked worktree (`git worktree add`), .leak-patterns (ignored by git) often only\n// exists in the main checkout: we then fall back to that one.\n//\n// .leak-patterns format (see .leak-patterns.example):\n// # comment\n// <regex> forbidden pattern (case-insensitive)\n// <regex> !! LICENSE, docs/*.md pattern allowed in these files\n// ! <glob> file never scanned by the patterns\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport const PATTERNS_FILE = '.leak-patterns'\nconst ALWAYS_SKIPPED = ['.leak-patterns', '.leak-patterns.example', 'package-lock.json']\n\n/** Simple glob: `*` = anything but `/`, `**` = anything, `?` = one character. */\nexport function globToRegExp(glob) {\n let re = ''\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i]\n if (c === '*' && glob[i + 1] === '*') { re += '.*'; i++; if (glob[i + 1] === '/') i++ }\n else if (c === '*') re += '[^/]*'\n else if (c === '?') re += '[^/]'\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n }\n return new RegExp(`^${re}$`)\n}\n\nconst matchesAny = (file, globs) => globs.some((g) => g.test(file))\n\n/** Parses the pattern file text. Throws a readable error on an invalid regex. */\nexport function parsePatterns(text) {\n const rules = []\n const skip = []\n text.split(/\\r?\\n/).forEach((raw, i) => {\n const line = raw.trim()\n if (!line || line.startsWith('#')) return\n if (line.startsWith('!') && !line.startsWith('!!')) {\n skip.push(globToRegExp(line.slice(1).trim()))\n return\n }\n const [source, allowed = ''] = line.split(/\\s+!!\\s+/)\n let regex\n try { regex = new RegExp(source.trim(), 'gi') }\n catch (e) { throw new Error(`${PATTERNS_FILE}:${i + 1}: invalid regex (${e.message})`) }\n const allow = allowed.split(',').map((s) => s.trim()).filter(Boolean).map(globToRegExp)\n rules.push({ source: source.trim(), regex, allow })\n })\n return { rules, skip }\n}\n\n/** Reads the pattern file; `null` if it does not exist. */\nexport function loadPatterns(file) {\n if (!existsSync(file)) return null\n return parsePatterns(readFileSync(file, 'utf8'))\n}\n\nconst git = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 << 20 })\n\n/** Root of the main checkout when `root` is a linked worktree; `null` otherwise. */\nexport function mainCheckoutRoot(root) {\n let common\n try { common = git(['rev-parse', '--git-common-dir'], root).trim() }\n catch { return null }\n common = path.resolve(root, common)\n // Bare repository or submodule: no main checkout next to the common .git folder.\n if (path.basename(common) !== '.git') return null\n const main = path.dirname(common)\n return path.resolve(main) === path.resolve(root) ? null : main\n}\n\n/**\n * Pattern file to use: the current checkout's, otherwise the main checkout's.\n * Returns `{ file, from: 'checkout' | 'main' }`, or `{ file: null, tried }` if none exists.\n */\nexport function findPatternsFile(root) {\n const own = path.join(root, PATTERNS_FILE)\n if (existsSync(own)) return { file: own, from: 'checkout' }\n const tried = [own]\n const main = mainCheckoutRoot(root)\n if (main) {\n const shared = path.join(main, PATTERNS_FILE)\n if (existsSync(shared)) return { file: shared, from: 'main' }\n tried.push(shared)\n }\n return { file: null, tried }\n}\n\n/** Shows enough to find the value without displaying it in full. */\nexport function redact(value) {\n if (value.length <= 4) return `${value[0] ?? ''}…`\n return `${value.slice(0, Math.min(4, Math.floor(value.length / 3)))}…(${value.length} chars)`\n}\n\n/** Hits of the rules in numbered lines (`[{ n, text }]`), without the file filters. */\nfunction matchLines(lines, rules) {\n const hits = []\n for (const rule of rules) {\n for (const { n, text } of lines) {\n for (const m of text.matchAll(rule.regex)) {\n if (!m[0]) continue\n hits.push({ line: n, pattern: rule.source, excerpt: redact(m[0]) })\n }\n }\n }\n return hits\n}\n\n/** Looks for the patterns in some lines of a file, honouring ignored files and exceptions. */\nfunction scanLines(file, lines, patterns) {\n if (ALWAYS_SKIPPED.includes(path.basename(file)) || matchesAny(file, patterns.skip)) return []\n const rules = patterns.rules.filter((rule) => !matchesAny(file, rule.allow))\n return matchLines(lines, rules).map((h) => ({ file, ...h }))\n}\n\n/** Looks for the patterns in a file's content. */\nexport function scanText(file, text, patterns) {\n return scanLines(file, text.split('\\n').map((t, i) => ({ n: i + 1, text: t })), patterns)\n}\n\n/** Unquotes a path as git prints it in a diff header (`\"a\\303\\251.txt\"` when quoted). */\nfunction diffPath(raw) {\n if (!raw.startsWith('\"')) return raw\n const bytes = []\n const s = raw.slice(1, -1)\n for (let i = 0; i < s.length; i++) {\n if (s[i] !== '\\\\') { bytes.push(...Buffer.from(s[i])); continue }\n const c = s[++i]\n if (/[0-7]/.test(c)) { bytes.push(parseInt(s.slice(i, i + 3), 8)); i += 2 }\n else bytes.push(({ n: 10, t: 9, '\"': 34, '\\\\': 92 })[c] ?? c.charCodeAt(0))\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/**\n * Lines a commit adds, per file, from `git diff-tree -p` output. Merges use the combined\n * format (`--cc`: one marker column per parent), which only keeps conflict resolutions:\n * the lines of the merged commits are scanned with those commits.\n */\nexport function addedLines(patch) {\n const files = new Map()\n let lines = null\n let parents = 1\n let next = 0\n for (const row of patch.split('\\n')) {\n if (row.startsWith('diff ')) { lines = null; continue }\n if (row.startsWith('+++ ')) {\n const target = row.slice(4)\n if (target === '/dev/null') { lines = null; continue }\n const file = diffPath(target).replace(/^b\\//, '')\n lines = files.get(file) ?? []\n files.set(file, lines)\n continue\n }\n const hunk = /^(@@+) .*?\\+(\\d+)/.exec(row)\n if (hunk) { parents = hunk[1].length - 1; next = Number(hunk[2]); continue }\n if (!lines || !next) continue\n const marks = row.slice(0, parents)\n if (marks.includes('-')) continue\n if (marks.includes('+')) lines.push({ n: next, text: row.slice(parents) })\n next++\n }\n return files\n}\n\n/**\n * Scans each commit of `range` (as `git rev-list` reads it): the lines it adds, with the file\n * rules, and its message, with every rule. Hits carry the short commit and `file: null` for\n * the message.\n */\nexport function scanRange(root, range, patterns) {\n const commits = git(['rev-list', '--reverse', range], root).split('\\n').filter(Boolean)\n const hits = []\n for (const sha of commits) {\n const commit = sha.slice(0, 9)\n const message = git(['log', '-1', '--format=%B', sha], root)\n const msgLines = message.split('\\n').map((t, i) => ({ n: i + 1, text: t }))\n hits.push(...matchLines(msgLines, patterns.rules).map((h) => ({ commit, file: null, ...h })))\n const patch = git(['diff-tree', '-p', '--cc', '--root', '-r', '--no-color', '--no-ext-diff', '--no-textconv', '-U0', sha], root)\n for (const [file, lines] of addedLines(patch)) {\n hits.push(...scanLines(file, lines, patterns).map((h) => ({ commit, ...h })))\n }\n }\n return { commits: commits.length, hits }\n}\n\n/** Copies the index content (all files or only staged ones) into a temporary folder. */\nfunction exportIndex(root, staged) {\n const list = staged\n ? git(['diff', '--cached', '--name-only', '--diff-filter=ACMR', '-z'], root)\n : git(['ls-files', '-z'], root)\n const files = list.split('\\0').filter(Boolean)\n const dir = mkdtempSync(path.join(tmpdir(), 'leaks-'))\n if (files.length) {\n execFileSync('git', ['checkout-index', '-z', '--stdin', `--prefix=${dir}/`], { cwd: root, input: files.join('\\0') })\n }\n return { dir, files }\n}\n\nconst GITLEAKS_IMAGE = 'zricethezav/gitleaks'\n\n/**\n * gitleaks command line: the binary when installed, otherwise its Docker image with read-only\n * mounts at the same paths (a linked worktree's `.git` file points into the main repository).\n * `null` when neither is available.\n */\nfunction gitleaksCommand(mounts, args) {\n if (!spawnSync('gitleaks', ['version'], { encoding: 'utf8' }).error) return ['gitleaks', args]\n const docker = spawnSync('docker', ['image', 'inspect', GITLEAKS_IMAGE], { encoding: 'utf8' })\n if (docker.error || docker.status !== 0) return null\n const user = typeof process.getuid === 'function' ? ['--user', `${process.getuid()}:${process.getgid()}`] : []\n return ['docker', [\n 'run', '--rm', '--network', 'none', ...user,\n // Files belong to the host user: let git inside the container read them.\n '-e', 'GIT_CONFIG_COUNT=1', '-e', 'GIT_CONFIG_KEY_0=safe.directory', '-e', 'GIT_CONFIG_VALUE_0=*',\n ...[...new Set(mounts)].flatMap((m) => ['-v', `${m}:${m}:ro`]),\n '-w', mounts[0], GITLEAKS_IMAGE, ...args,\n ]]\n}\n\n/** Runs gitleaks on a folder (`dir` mode) or on a commit range (`git` mode). */\nfunction runGitleaks({ dir, root, range }) {\n const gitDir = range && path.resolve(root, git(['rev-parse', '--git-common-dir'], root).trim())\n // --verbose lists each finding (commit, file, line, rule); --redact hides the secret itself.\n const opts = ['--redact', '--verbose', '--no-banner', '--exit-code', '1']\n const args = range ? ['git', root, `--log-opts=${range}`, ...opts] : ['dir', dir, ...opts]\n const cmd = gitleaksCommand(range ? [root, gitDir] : [dir], args)\n if (!cmd) {\n console.log(`gitleaks: not installed and no ${GITLEAKS_IMAGE} Docker image, skipped (https://github.com/gitleaks/gitleaks). Forbidden patterns still run.`)\n return true\n }\n const r = spawnSync(cmd[0], cmd[1], { stdio: 'inherit' })\n if (r.status === 0) console.log(`gitleaks${cmd[0] === 'docker' ? ' (Docker)' : ''}: no secret found.`)\n else if (r.status !== 1) console.error(`gitleaks: failed to run (exit ${r.status ?? r.signal}).`)\n return r.status === 0\n}\n\n/** Loads the pattern file and says which one is used; `null` (with a warning) if none. */\nfunction patternsFor(root) {\n const found = findPatternsFile(root)\n const patterns = found.file && loadPatterns(found.file)\n if (!patterns) {\n console.warn([\n `WARNING: no ${PATTERNS_FILE} file found, forbidden patterns were NOT checked.`,\n ...found.tried.map((f) => ` looked for: ${f}`),\n ` Copy ${PATTERNS_FILE}.example to ${PATTERNS_FILE} in the main checkout and fill it.`,\n ].join('\\n'))\n return null\n }\n console.log(`patterns: using ${found.file}${found.from === 'main' ? ' (main checkout)' : ''}`)\n if (!patterns.rules.length) console.warn(`WARNING: ${found.file} has no active pattern, nothing is forbidden.`)\n return patterns\n}\n\nfunction mainRange(root, range, gitleaks) {\n let ok = gitleaks ? runGitleaks({ root, range }) : true\n const patterns = patternsFor(root)\n if (!patterns) return ok ? 0 : 1\n const { commits, hits } = scanRange(root, range, patterns)\n for (const h of hits) {\n console.log(h.file === null\n ? `${h.commit} message:${h.line} ${h.excerpt} [${h.pattern}]`\n : `${h.commit} ${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n }\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${commits} commit(s) of ${range}.`\n : `patterns: ${patterns.rules.length} pattern(s), ${commits} commit(s) of ${range}, no match.`)\n if (hits.length) ok = false\n return ok ? 0 : 1\n}\n\nfunction main(argv) {\n const staged = argv.includes('--staged')\n const gitleaks = !argv.includes('--no-gitleaks')\n const root = git(['rev-parse', '--show-toplevel']).trim()\n const r = argv.indexOf('--range')\n if (r !== -1) {\n const range = argv[r + 1]\n if (!range || range.startsWith('--')) throw new Error('--range needs a revision range, e.g. origin/main..HEAD')\n return mainRange(root, range, gitleaks)\n }\n const { dir, files } = exportIndex(root, staged)\n try {\n if (!files.length) { console.log('check:leaks: nothing to scan.'); return 0 }\n let ok = gitleaks ? runGitleaks({ dir }) : true\n const patterns = patternsFor(root)\n if (patterns) {\n const hits = []\n for (const file of files) {\n const buf = readFileSync(path.join(dir, file))\n if (buf.includes(0)) continue // binaire\n hits.push(...scanText(file, buf.toString('utf8'), patterns))\n }\n for (const h of hits) console.log(`${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${files.length} file(s).`\n : `patterns: ${patterns.rules.length} pattern(s), ${files.length} file(s), no match.`)\n if (hits.length) ok = false\n }\n return ok ? 0 : 1\n }\n finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n\nif (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n try { process.exit(main(process.argv.slice(2))) }\n catch (e) { console.error(`check:leaks: ${e.message}`); process.exit(2) }\n}\n";
|
|
2
|
+
const checkLeaks = "#!/usr/bin/env node\n// Leak check: gitleaks + forbidden patterns read from a local, untracked file (.leak-patterns).\n// (default) scans the content of the git index (tracked or staged files)\n// --staged only scans staged files (pre-commit hook)\n// --range <revs> scans every commit of a revision range (`origin/main..HEAD`): the lines\n// each commit adds and its message, so a leak added then removed is caught\n// --no-gitleaks skips gitleaks (patterns only)\n// gitleaks runs from the `gitleaks` binary when installed, otherwise it is skipped.\n// In a linked worktree (`git worktree add`), .leak-patterns (ignored by git) often only\n// exists in the main checkout: we then fall back to that one.\n//\n// .leak-patterns format (see .leak-patterns.example):\n// # comment\n// <regex> forbidden pattern (case-insensitive)\n// <regex> !! LICENSE, docs/*.md pattern allowed in these files\n// ! <glob> file never scanned by the patterns\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport const PATTERNS_FILE = '.leak-patterns'\nconst ALWAYS_SKIPPED = ['.leak-patterns', '.leak-patterns.example', 'package-lock.json']\n\n/** Simple glob: `*` = anything but `/`, `**` = anything, `?` = one character. */\nexport function globToRegExp(glob) {\n let re = ''\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i]\n if (c === '*' && glob[i + 1] === '*') { re += '.*'; i++; if (glob[i + 1] === '/') i++ }\n else if (c === '*') re += '[^/]*'\n else if (c === '?') re += '[^/]'\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n }\n return new RegExp(`^${re}$`)\n}\n\nconst matchesAny = (file, globs) => globs.some((g) => g.test(file))\n\n/** Parses the pattern file text. Throws a readable error on an invalid regex. */\nexport function parsePatterns(text) {\n const rules = []\n const skip = []\n text.split(/\\r?\\n/).forEach((raw, i) => {\n const line = raw.trim()\n if (!line || line.startsWith('#')) return\n if (line.startsWith('!') && !line.startsWith('!!')) {\n skip.push(globToRegExp(line.slice(1).trim()))\n return\n }\n const [source, allowed = ''] = line.split(/\\s+!!\\s+/)\n let regex\n try { regex = new RegExp(source.trim(), 'gi') }\n catch (e) { throw new Error(`${PATTERNS_FILE}:${i + 1}: invalid regex (${e.message})`) }\n const allow = allowed.split(',').map((s) => s.trim()).filter(Boolean).map(globToRegExp)\n rules.push({ source: source.trim(), regex, allow })\n })\n return { rules, skip }\n}\n\n/** Reads the pattern file; `null` if it does not exist. */\nexport function loadPatterns(file) {\n if (!existsSync(file)) return null\n return parsePatterns(readFileSync(file, 'utf8'))\n}\n\nconst git = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 << 20 })\n\n/** Root of the main checkout when `root` is a linked worktree; `null` otherwise. */\nexport function mainCheckoutRoot(root) {\n let common\n try { common = git(['rev-parse', '--git-common-dir'], root).trim() }\n catch { return null }\n common = path.resolve(root, common)\n // Bare repository or submodule: no main checkout next to the common .git folder.\n if (path.basename(common) !== '.git') return null\n const main = path.dirname(common)\n return path.resolve(main) === path.resolve(root) ? null : main\n}\n\n/**\n * Pattern file to use: the current checkout's, otherwise the main checkout's.\n * Returns `{ file, from: 'checkout' | 'main' }`, or `{ file: null, tried }` if none exists.\n */\nexport function findPatternsFile(root) {\n const own = path.join(root, PATTERNS_FILE)\n if (existsSync(own)) return { file: own, from: 'checkout' }\n const tried = [own]\n const main = mainCheckoutRoot(root)\n if (main) {\n const shared = path.join(main, PATTERNS_FILE)\n if (existsSync(shared)) return { file: shared, from: 'main' }\n tried.push(shared)\n }\n return { file: null, tried }\n}\n\n/** Shows enough to find the value without displaying it in full. */\nexport function redact(value) {\n if (value.length <= 4) return `${value[0] ?? ''}…`\n return `${value.slice(0, Math.min(4, Math.floor(value.length / 3)))}…(${value.length} chars)`\n}\n\n/** Hits of the rules in numbered lines (`[{ n, text }]`), without the file filters. */\nfunction matchLines(lines, rules) {\n const hits = []\n for (const rule of rules) {\n for (const { n, text } of lines) {\n for (const m of text.matchAll(rule.regex)) {\n if (!m[0]) continue\n hits.push({ line: n, pattern: rule.source, excerpt: redact(m[0]) })\n }\n }\n }\n return hits\n}\n\n/** Looks for the patterns in some lines of a file, honouring ignored files and exceptions. */\nfunction scanLines(file, lines, patterns) {\n if (ALWAYS_SKIPPED.includes(path.basename(file)) || matchesAny(file, patterns.skip)) return []\n const rules = patterns.rules.filter((rule) => !matchesAny(file, rule.allow))\n return matchLines(lines, rules).map((h) => ({ file, ...h }))\n}\n\n/** Looks for the patterns in a file's content. */\nexport function scanText(file, text, patterns) {\n return scanLines(file, text.split('\\n').map((t, i) => ({ n: i + 1, text: t })), patterns)\n}\n\n/** Unquotes a path as git prints it in a diff header (`\"a\\303\\251.txt\"` when quoted). */\nfunction diffPath(raw) {\n if (!raw.startsWith('\"')) return raw\n const bytes = []\n const s = raw.slice(1, -1)\n for (let i = 0; i < s.length; i++) {\n if (s[i] !== '\\\\') { bytes.push(...Buffer.from(s[i])); continue }\n const c = s[++i]\n if (/[0-7]/.test(c)) { bytes.push(parseInt(s.slice(i, i + 3), 8)); i += 2 }\n else bytes.push(({ n: 10, t: 9, '\"': 34, '\\\\': 92 })[c] ?? c.charCodeAt(0))\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/**\n * Lines a commit adds, per file, from `git diff-tree -p` output. Merges use the combined\n * format (`--cc`: one marker column per parent), which only keeps conflict resolutions:\n * the lines of the merged commits are scanned with those commits.\n */\nexport function addedLines(patch) {\n const files = new Map()\n let lines = null\n let parents = 1\n let next = 0\n for (const row of patch.split('\\n')) {\n if (row.startsWith('diff ')) { lines = null; continue }\n if (row.startsWith('+++ ')) {\n const target = row.slice(4)\n if (target === '/dev/null') { lines = null; continue }\n const file = diffPath(target).replace(/^b\\//, '')\n lines = files.get(file) ?? []\n files.set(file, lines)\n continue\n }\n const hunk = /^(@@+) .*?\\+(\\d+)/.exec(row)\n if (hunk) { parents = hunk[1].length - 1; next = Number(hunk[2]); continue }\n if (!lines || !next) continue\n const marks = row.slice(0, parents)\n if (marks.includes('-')) continue\n if (marks.includes('+')) lines.push({ n: next, text: row.slice(parents) })\n next++\n }\n return files\n}\n\n/**\n * Scans each commit of `range` (as `git rev-list` reads it): the lines it adds, with the file\n * rules, and its message, with every rule. Hits carry the short commit and `file: null` for\n * the message.\n */\nexport function scanRange(root, range, patterns) {\n const commits = git(['rev-list', '--reverse', range], root).split('\\n').filter(Boolean)\n const hits = []\n for (const sha of commits) {\n const commit = sha.slice(0, 9)\n const message = git(['log', '-1', '--format=%B', sha], root)\n const msgLines = message.split('\\n').map((t, i) => ({ n: i + 1, text: t }))\n hits.push(...matchLines(msgLines, patterns.rules).map((h) => ({ commit, file: null, ...h })))\n const patch = git(['diff-tree', '-p', '--cc', '--root', '-r', '--no-color', '--no-ext-diff', '--no-textconv', '-U0', sha], root)\n for (const [file, lines] of addedLines(patch)) {\n hits.push(...scanLines(file, lines, patterns).map((h) => ({ commit, ...h })))\n }\n }\n return { commits: commits.length, hits }\n}\n\n/** Copies the index content (all files or only staged ones) into a temporary folder. */\nfunction exportIndex(root, staged) {\n const list = staged\n ? git(['diff', '--cached', '--name-only', '--diff-filter=ACMR', '-z'], root)\n : git(['ls-files', '-z'], root)\n const files = list.split('\\0').filter(Boolean)\n const dir = mkdtempSync(path.join(tmpdir(), 'leaks-'))\n if (files.length) {\n execFileSync('git', ['checkout-index', '-z', '--stdin', `--prefix=${dir}/`], { cwd: root, input: files.join('\\0') })\n }\n return { dir, files }\n}\n\n/** Whether the `gitleaks` binary is installed. */\nconst hasGitleaks = () => !spawnSync('gitleaks', ['version'], { encoding: 'utf8' }).error\n\n/** Runs gitleaks on a folder (`dir` mode) or on a commit range (`git` mode). */\nfunction runGitleaks({ dir, root, range }) {\n // --verbose lists each finding (commit, file, line, rule); --redact hides the secret itself.\n const opts = ['--redact', '--verbose', '--no-banner', '--exit-code', '1']\n const args = range ? ['git', root, `--log-opts=${range}`, ...opts] : ['dir', dir, ...opts]\n if (!hasGitleaks()) {\n console.log('gitleaks: not installed, skipped (https://github.com/gitleaks/gitleaks). Forbidden patterns still run.')\n return true\n }\n const r = spawnSync('gitleaks', args, { stdio: 'inherit' })\n if (r.status === 0) console.log('gitleaks: no secret found.')\n else if (r.status !== 1) console.error(`gitleaks: failed to run (exit ${r.status ?? r.signal}).`)\n return r.status === 0\n}\n\n/** Loads the pattern file and says which one is used; `null` (with a warning) if none. */\nfunction patternsFor(root) {\n const found = findPatternsFile(root)\n const patterns = found.file && loadPatterns(found.file)\n if (!patterns) {\n console.warn([\n `WARNING: no ${PATTERNS_FILE} file found, forbidden patterns were NOT checked.`,\n ...found.tried.map((f) => ` looked for: ${f}`),\n ` Copy ${PATTERNS_FILE}.example to ${PATTERNS_FILE} in the main checkout and fill it.`,\n ].join('\\n'))\n return null\n }\n console.log(`patterns: using ${found.file}${found.from === 'main' ? ' (main checkout)' : ''}`)\n if (!patterns.rules.length) console.warn(`WARNING: ${found.file} has no active pattern, nothing is forbidden.`)\n return patterns\n}\n\nfunction mainRange(root, range, gitleaks) {\n let ok = gitleaks ? runGitleaks({ root, range }) : true\n const patterns = patternsFor(root)\n if (!patterns) return ok ? 0 : 1\n const { commits, hits } = scanRange(root, range, patterns)\n for (const h of hits) {\n console.log(h.file === null\n ? `${h.commit} message:${h.line} ${h.excerpt} [${h.pattern}]`\n : `${h.commit} ${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n }\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${commits} commit(s) of ${range}.`\n : `patterns: ${patterns.rules.length} pattern(s), ${commits} commit(s) of ${range}, no match.`)\n if (hits.length) ok = false\n return ok ? 0 : 1\n}\n\nfunction main(argv) {\n const staged = argv.includes('--staged')\n const gitleaks = !argv.includes('--no-gitleaks')\n const root = git(['rev-parse', '--show-toplevel']).trim()\n const r = argv.indexOf('--range')\n if (r !== -1) {\n const range = argv[r + 1]\n if (!range || range.startsWith('--')) throw new Error('--range needs a revision range, e.g. origin/main..HEAD')\n return mainRange(root, range, gitleaks)\n }\n const { dir, files } = exportIndex(root, staged)\n try {\n if (!files.length) { console.log('check:leaks: nothing to scan.'); return 0 }\n let ok = gitleaks ? runGitleaks({ dir }) : true\n const patterns = patternsFor(root)\n if (patterns) {\n const hits = []\n for (const file of files) {\n const buf = readFileSync(path.join(dir, file))\n if (buf.includes(0)) continue // binaire\n hits.push(...scanText(file, buf.toString('utf8'), patterns))\n }\n for (const h of hits) console.log(`${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${files.length} file(s).`\n : `patterns: ${patterns.rules.length} pattern(s), ${files.length} file(s), no match.`)\n if (hits.length) ok = false\n }\n return ok ? 0 : 1\n }\n finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n\nif (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n try { process.exit(main(process.argv.slice(2))) }\n catch (e) { console.error(`check:leaks: ${e.message}`); process.exit(2) }\n}\n";
|
|
3
3
|
|
|
4
4
|
export { checkLeaks as default };
|
|
5
5
|
//# sourceMappingURL=check-leaks.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const checkReleaseNotes = "// Validate reviewed stable-release notes without generating or changing their text.\nimport { readFileSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\n\nexport function checkReleaseNotes(body, repo, tag) {\n const link = `https://github.com/${repo}/blob/${tag}/CHANGELOG.md`\n if (!body.includes(link)) throw new Error(`Release notes must link to ${link}`)\n const summary = body.slice(0, body.indexOf(link)).replace(/\\[[^\\]]*\\]\\($/, '')\n const sections = summary.replace(/\\r\\n/g, '\\n').split(/^#{1,6}\\s+(New|Improved|Fixed|Update)\\s*$/m)\n const summaries = []\n for (let i = 2; i < sections.length; i += 2) {\n // Only prose inside a recognized section counts, excluding links, code and comments.\n const prose = sections[i].split(/^#{1,6}\\s/m)[0]\n .replace(/<!--[\\s\\S]*?-->/g, '')\n .replace(/```[\\s\\S]*?```/g, '')\n .replace(/\\[[^\\]]*\\]\\([^)]*\\)|https?:\\/\\/\\S+/g, '')\n summaries.push(prose)\n }\n const prose = summaries.join('\\n')\n const words = prose.match(/\\b[a-zA-Z][a-zA-Z'-]*\\b/g) || []\n const sentences = prose.match(/[.!?](?:\\s|$)/g) || []\n if (words.length < 12 || sentences.length < 2) {\n throw new Error('Write at least two readable English sentences about the changes under New / Improved / Fixed / Update, followed by a CHANGELOG.md link. Link-only notes are not accepted.')\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n try {\n checkReleaseNotes(readFileSync(0, 'utf8'), process.env.GITHUB_REPOSITORY, process.env.GITHUB_REF_NAME)\n } catch (error) {\n console.error(error.message)\n process.exitCode = 1\n }\n}\n";
|
|
3
|
+
|
|
4
|
+
export { checkReleaseNotes as default };
|
|
5
|
+
//# sourceMappingURL=check-release-notes.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
2
|
|
|
3
3
|
// ROLLUP_NO_REPLACE
|
|
4
|
-
const herdrPlugin = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyIGFzIGEgSGVyZHIgcGx1Z2luIChoZXJkci1wbHVnaW4udG9tbCk6IGJ1aWxkIChpbnN0YWxsICsgZmlyc3Qgc3RhcnQpLAojIHRoZSBwYW5lbCwgc3RhcnQsIHN0b3AsIHN0YXR1cywgb3BlbiwgdXBkYXRlLCBzZXJ2aWNlLCBza2lsbCwga2V5LgojCiMgICBoZXJkciBwbHVnaW4gaW5zdGFsbCA8b3duZXI+L3doZXJkcgojCiMgVHdvIHdheXMgdG8gcnVuIHdoZXJkciwgcGlja2VkIG9uY2UgYXQgaW5zdGFsbCB0aW1lIGFuZCBrZXB0IGluCiMgJFdIRVJEUl9ESVIvcGx1Z2luLmVudjoKIyAgIGRvY2tlciAgTGludXggd2l0aCBEb2NrZXIgQ29tcG9zZSB2MiB1c2FibGUgYnkgdGhpcyB1c2VyOiB0aGUgcHVibGlzaGVkCiMgICAgICAgICAgIGltYWdlLCBydW4gZnJvbSAkV0hFUkRSX0RJUiBleGFjdGx5IGxpa2UgaHR0cHM6Ly93aGVyZHIuZGV2L2luc3RhbGwuCiMgICBuYXRpdmUgIGV2ZXJ5d2hlcmUgZWxzZSAoYWx3YXlzIG9uIG1hY09TOiBEb2NrZXIgRGVza3RvcCBjYW5ub3QgcmVhY2gKIyAgICAgICAgICAgSGVyZHIncyBVbml4IHNvY2tldCk6IE5vZGUuanMgMjIgKG9yIEJ1bikgcnVucyB0aGUgcHJlYnVpbHQgR2l0SHViCiMgICAgICAgICAgIHBhY2thZ2Ugb2YgdGhpcyB2ZXJzaW9uIChvciBhIGJ1aWxkIG1hZGUgaW4gdGhlIHBsdWdpbiBmb2xkZXIpLAojICAgICAgICAgICBjb3BpZWQgdG8gJFdIRVJEUl9ESVIvYXBwIGFuZCBzdGFydGVkIGRldGFjaGVkIGZyb20gdGhlcmUsIHdpdGgKIyAgICAgICAgICAgaXRzIHBpZCBhbmQgbG9nIGluICRXSEVSRFJfRElSLgojIEhlcmRyIGJ1aWxkcyBhIHBsdWdpbiBpbiBhIHRlbXBvcmFyeSBmb2xkZXIsIHRoZW4gbW92ZXMgaXQ6IGEgc2VydmVyIHN0YXJ0ZWQKIyBmcm9tIHRoZSBjaGVja291dCBkdXJpbmcgdGhlIGJ1aWxkIHdvdWxkIGxvc2UgaXRzIGZpbGVzLiAkV0hFUkRSX0RJUi9hcHAKIyBzdGF5cyBwdXQsIGFjcm9zcyBwbHVnaW4gdXBkYXRlcyB0b28sIHNvIHRoZSBidWlsZCBjYW4gc3RhcnQgd2hlcmRyIGFuZCBhCiMgbG9naW4gc2VydmljZSBjYW4gcG9pbnQgYXQgaXQuCiMgV0hFUkRSX01PREU9bmF0aXZlIChvciBkb2NrZXIpIGluIHRoZSBlbnZpcm9ubWVudCBvZiBgaGVyZHIgcGx1Z2luIGluc3RhbGxgCiMgZm9yY2VzIHRoZSBjaG9pY2U7IGVkaXQgcGx1Z2luLmVudiB0byBjaGFuZ2UgaXQgbGF0ZXIsIHRoZW4gcnVuIFVwZGF0ZS4KIwojIFNhZmV0eSBydWxlczoKIyAgIC0gbm90aGluZyBnbG9iYWwgaXMgaW5zdGFsbGVkLCBubyBzdWRvOyBmaWxlcyBhcmUgb25seSB3cml0dGVuIHRvIHRoZQojICAgICBwbHVnaW4gZm9sZGVyIGFuZCAkV0hFUkRSX0RJUiAoZGVmYXVsdCB+L3doZXJkciksIHBsdXMgdGhlIGZvbGRlcnMgdGhlCiMgICAgIERvY2tlciBzZXR1cCBtb3VudHMgKH4vLmNvbmZpZy9oZXJkciwgfi8uY2FjaGUvaGVyZHItd2Vi4oCmKSwgYW5kIHRoZQojICAgICBsb2dpbiBzZXJ2aWNlIG9ubHkgd2hlbiBhc2tlZCAoa2V5IEEgb2YgdGhlIHBhbmVsKSwgcGx1cyBhICJ3aGVyZHIiCiMgICAgIGxpbmsgaW4gdGhlIGFnZW50cycgdXNlciBza2lsbCBmb2xkZXJzIChzZWUgY21kX3NraWxsKSwgcGx1cyBvbmUgbWFya2VkCiMgICAgIGJsb2NrIGFwcGVuZGVkIHRvIEhlcmRyJ3MgY29uZmlnLnRvbWw6IHRoZSBrZXkgdGhhdCBvcGVucyB0aGUgcGFuZWwKIyAgICAgKHNlZSBjbWRfa2V5KTsKIyAgIC0gdGhlIGluc3RhbGwgc3RhcnRzIHdoZXJkciwgYW5kIEhlcmRyJ3Mgc3RhcnR1cCBob29rIHN0YXJ0cyBpdCBhZ2FpbiwKIyAgICAgYnV0IG9ubHkgd2hlbiBub3RoaW5nIGFuc3dlcnMgb24gdGhlIHBvcnQ6IGEgd2hlcmRyIHN0YXJ0ZWQgYW5vdGhlciB3YXkKIyAgICAgKERvY2tlciwgc3lzdGVtZCwgYnkgaGFuZCkgaXMgbmV2ZXIgdG91Y2hlZCwgbm8gc2Vjb25kIHdoZXJkciBpcyBzdGFydGVkOwojICAgLSBzdG9wIG9ubHkgc3RvcHMgd2hhdCB0aGlzIHBsdWdpbiBzdGFydGVkIChpdHMgcGlkLCBpdHMgbG9naW4gc2VydmljZSwgb3IKIyAgICAgdGhlIGNvbnRhaW5lciBvZiBpdHMgb3duIGNvbXBvc2UgZm9sZGVyKS4KIwojIFVuaW5zdGFsbDogSGVyZHIgaGFzIG5vIHVuaW5zdGFsbCBob29rLiBTdG9wIHdoZXJkciAoYW5kIHJlbW92ZSB0aGUgbG9naW4KIyBzZXJ2aWNlKSBmcm9tIHRoZSBwYW5lbCBmaXJzdCwgdGhlbjoKIyAgIHNoIHNjcmlwdHMvaGVyZHItcGx1Z2luLnNoIHNraWxsIHVuaW5zdGFsbCAgIChpbiB0aGUgcGx1Z2luIGZvbGRlcikKIyAgIHNoIHNjcmlwdHMvaGVyZHItcGx1Z2luLnNoIGtleSB1bmluc3RhbGwgICAgICh0aGUgSGVyZHIga2V5IG9mIHRoZSBwYW5lbCkKIyAgIGhlcmRyIHBsdWdpbiB1bmluc3RhbGwgPG93bmVyPi53aGVyZHIgJiYgcm0gLXJmIH4vd2hlcmRyCiMKIyBTZXR0aW5ncyAoJFdIRVJEUl9ESVIvcGx1Z2luLmVudiwgb3IgdGhlIGVudmlyb25tZW50KToKIyAgIFdIRVJEUl9NT0RFICBkb2NrZXIgfCBuYXRpdmUgICAgICAgIChkZWZhdWx0OiBjaG9zZW4gYXQgaW5zdGFsbCkKIyAgIFdIRVJEUl9QT1JUICBsb2NhbCBwb3J0ICAgICAgICAgICAgICAoZGVmYXVsdDogNzY4MykKIyAgIEFQUF9VUkwgICAgICBwcml2YXRlIEhUVFBTIGFkZHJlc3MgICAobmF0aXZlOyBEb2NrZXIgcmVhZHMgaXRzIC5lbnYpCiMgICBXSEVSRFJfUlVOVElNRSAgYWJzb2x1dGUgcGF0aCBvZiBub2RlIC8gYnVuIChuYXRpdmU7IGZvdW5kIGF0IGluc3RhbGwpCgpzZXQgLWV1CgpST09UPSIkKGNkICIkKGRpcm5hbWUgIiQwIikvLi4iICYmIHB3ZCAtUCkiCiMgQnVpbGQgY29tbWFuZHMgZ2V0IG5vIHBsdWdpbiBlbnZpcm9ubWVudDogdGhlIGZvbGRlciBjaG9zZW4gYXQgaW5zdGFsbAojIHRpbWUgaXMgcmVtZW1iZXJlZCBpbiB0aGUgcGx1Z2luIGNoZWNrb3V0IGZvciB0aGUgcnVudGltZSBjb21tYW5kcy4KaWYgWyAteiAiJHtXSEVSRFJfRElSOi19IiBdICYmIFsgLWYgIiRST09ULy53aGVyZHItZGlyIiBdOyB0aGVuCiAgV0hFUkRSX0RJUj0iJChjYXQgIiRST09ULy53aGVyZHItZGlyIikiCmZpCkRJUj0iJHtXSEVSRFJfRElSOi0kSE9NRS93aGVyZHJ9IgpjYXNlICIkRElSIiBpbiAvKikgOzsgKikgRElSPSIkUFdELyRESVIiIDs7IGVzYWMKQ09ORj0iJERJUi9wbHVnaW4uZW52IgojIE5hdGl2ZSBtb2RlOiB0aGUgaW5zdGFsbGVkIGNvcHkgb2Ygd2hlcmRyIChiaW4gKyBidWlsdCBzZXJ2ZXIpLgpBUFA9IiRESVIvYXBwIgojIEdpdEh1YiBzb3VyY2Ugb2YgdGhpcyBwbHVnaW46IGl0cyBtYW5pZmVzdCBpZCB3aXRoICIvIiBmb3IgIi4iIChvd25lci53aGVyZHIpLgpTT1VSQ0U9IiQoc2VkIC1uICdzL15pZCA9ICJcKC4qXCkiJC9cMS9wJyAiJFJPT1QvaGVyZHItcGx1Z2luLnRvbWwiIHwgaGVhZCAtbiAxIHwgdHIgLiAvKSIKIyBjb250YWluZXJfbmFtZSBvZiB0aGUgY29tcG9zZSBmaWxlICh3aGVyZHIgdW5sZXNzIHlvdSByZW5hbWVkIGl0KS4KQ09OVEFJTkVSPSIkKHNlZCAtbiAncy9eICpjb250YWluZXJfbmFtZTogKi8vcCcgIiRESVIvZG9ja2VyLWNvbXBvc2UueW1sIiAyPi9kZXYvbnVsbCB8IGhlYWQgLW4gMSkiCkNPTlRBSU5FUj0iJHtDT05UQUlORVI6LXdoZXJkcn0iCiMgVGhlIGVudmlyb25tZW50IHdpbnMgb3ZlciBwbHVnaW4uZW52LgpFTlZfTU9ERT0iJHtXSEVSRFJfTU9ERTotfSIgRU5WX1BPUlQ9IiR7V0hFUkRSX1BPUlQ6LX0iIEVOVl9BUFBfVVJMPSIke0FQUF9VUkw6LX0iIEVOVl9SVU5USU1FPSIke1dIRVJEUl9SVU5USU1FOi19IgppZiBbIC1mICIkQ09ORiIgXTsgdGhlbgogICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMTA5MAogIC4gIiRDT05GIgpmaQpNT0RFPSIke0VOVl9NT0RFOi0ke1dIRVJEUl9NT0RFOi19fSIKUE9SVD0iJHtFTlZfUE9SVDotJHtXSEVSRFJfUE9SVDotNzY4M319IgpBUFBfVVJMPSIke0VOVl9BUFBfVVJMOi0ke0FQUF9VUkw6LX19IgojIE5hdGl2ZSBtb2RlOiBhYnNvbHV0ZSBwYXRoIG9mIHRoZSBub2RlIChvciBidW4pIHRoYXQgcnVucyB0aGUgc2VydmVyLiBIZXJkcgojIHJ1bnMgYWN0aW9ucyB3aXRoIGl0cyBzZXJ2ZXIncyBQQVRILCB3aGljaCBvZnRlbiBsYWNrcyBudm0gLyBuIC8gZm5tIGZvbGRlcnMuClJVTlRJTUU9IiR7RU5WX1JVTlRJTUU6LSR7V0hFUkRSX1JVTlRJTUU6LX19IgpVUkw9Imh0dHA6Ly9sb2NhbGhvc3Q6JFBPUlQiCgpzYXkoKSB7IHByaW50ZiAnJXNcbicgIiQqIjsgfQpvaygpIHsgcHJpbnRmICcgIOKckyAlc1xuJyAiJCoiOyB9Cndhcm4oKSB7IHByaW50ZiAnICAhICVzXG4nICIkKiIgPiYyOyB9CmRpZSgpIHsgcHJpbnRmICcgIOKclyAlc1xuJyAiJCoiID4mMjsgZXhpdCAxOyB9CgojIEFueSBIVFRQIGFuc3dlciBjb3VudHMgKGEgbG9ja2VkIHdoZXJkciBhbnN3ZXJzIDQwMSk6IHRoZSBwb3J0IGlzIHRha2VuLgphbnN3ZXJzKCkgewogIGlmIGNvbW1hbmQgLXYgY3VybCA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIGNvZGU9IiQoY3VybCAtcyAtbyAvZGV2L251bGwgLS1tYXgtdGltZSAyIC13ICcle2h0dHBfY29kZX0nICJodHRwOi8vMTI3LjAuMC4xOiRQT1JULyIgMj4vZGV2L251bGwgfHwgdHJ1ZSkiCiAgICBbIC1uICIkY29kZSIgXSAmJiBbICIkY29kZSIgIT0gIjAwMCIgXQogIGVsaWYgY29tbWFuZCAtdiBuYyA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIG5jIC16IDEyNy4wLjAuMSAiJFBPUlQiID4vZGV2L251bGwgMj4mMQogIGVsc2UKICAgIGRpZSAiY3VybCBvciBuYyBpcyBuZWVkZWQgdG8gY2hlY2sgcG9ydCAkUE9SVC4iCiAgZmkKfQoKZG9ja2VyX3VzYWJsZSgpIHsKICBbICIkKHVuYW1lIC1zKSIgPSAiTGludXgiIF0gfHwgcmV0dXJuIDEKICBjb21tYW5kIC12IGRvY2tlciA+L2Rldi9udWxsIDI+JjEgfHwgcmV0dXJuIDEKICBkb2NrZXIgY29tcG9zZSB2ZXJzaW9uID4vZGV2L251bGwgMj4mMSB8fCByZXR1cm4gMQogIGRvY2tlciBpbmZvID4vZGV2L251bGwgMj4mMQp9CgojIE1ham9yIHZlcnNpb24gb2YgYSBub2RlIGJpbmFyeSwgMCB3aGVuIGl0IGlzIG5vdCBvbmUuCm5vZGVfbWFqb3IoKSB7CiAgIiQxIiAtcCAncHJvY2Vzcy52ZXJzaW9ucy5ub2RlLnNwbGl0KCIuIilbMF0nIDI+L2Rldi9udWxsIHx8IGVjaG8gMAp9CgojIEEgdXNhYmxlIHJ1bnRpbWU6IE5vZGUuanMgMjIgb3IgbmV3ZXIsIG9yIEJ1biAoaXQgcnVucyB0aGUgYnVpbHQgc2VydmVyIHRvbykuCnJ1bnRpbWVfb2soKSB7CiAgWyAtbiAiJDEiIF0gJiYgWyAteCAiJDEiIF0gJiYgWyAhIC1kICIkMSIgXSB8fCByZXR1cm4gMQogIGNhc2UgIiQoYmFzZW5hbWUgIiQxIikiIGluCiAgICBidW4pICIkMSIgLS12ZXJzaW9uID4vZGV2L251bGwgMj4mMSA7OwogICAgKikgWyAiJChub2RlX21ham9yICIkMSIpIiAtZ2UgMjIgXSAyPi9kZXYvbnVsbCA7OwogIGVzYWMKfQoKIyBBYnNvbHV0ZSBwYXRoIG9mIHRoZSBydW50aW1lOiBXSEVSRFJfUlVOVElNRSwgdGhlbiBub2RlIG9uIHRoZSBQQVRILCB0aGVuIHRoZQojIHVzdWFsIGluc3RhbGwgZm9sZGVycyAobiwgbnZtLCBWb2x0YSwgZm5tLCBhc2RmLCBIb21lYnJldyksIHRoZW4gQnVuLgojIFByaW50cyBub3RoaW5nIGFuZCBmYWlscyB3aGVuIG5vbmUgaXMgZm91bmQuCmZpbmRfcnVudGltZSgpIHsKICBmb3IgYyBpbiAiJFJVTlRJTUUiICIkKGNvbW1hbmQgLXYgbm9kZSAyPi9kZXYvbnVsbCB8fCB0cnVlKSIgXAogICAgIiRIT01FLy5uL2Jpbi9ub2RlIiAiJHtOX1BSRUZJWDorJE5fUFJFRklYL2Jpbi9ub2RlfSIgXAogICAgJChscyAtZCAiJEhPTUUiLy5udm0vdmVyc2lvbnMvbm9kZS92Ki9iaW4vbm9kZSAyPi9kZXYvbnVsbCB8IHNvcnQgLXIgLVYpIFwKICAgICIkSE9NRS8udm9sdGEvYmluL25vZGUiIFwKICAgICQobHMgLWQgIiRIT01FIi8ubG9jYWwvc2hhcmUvZm5tL25vZGUtdmVyc2lvbnMvKi9pbnN0YWxsYXRpb24vYmluL25vZGUgIiRIT01FIi8uZm5tL25vZGUtdmVyc2lvbnMvKi9pbnN0YWxsYXRpb24vYmluL25vZGUgMj4vZGV2L251bGwgfCBzb3J0IC1yIC1WKSBcCiAgICAiJEhPTUUvLmFzZGYvc2hpbXMvbm9kZSIgL29wdC9ob21lYnJldy9iaW4vbm9kZSAvdXNyL2xvY2FsL2Jpbi9ub2RlIC91c3IvYmluL25vZGUgXAogICAgIiQoY29tbWFuZCAtdiBidW4gMj4vZGV2L251bGwgfHwgdHJ1ZSkiICIkSE9NRS8uYnVuL2Jpbi9idW4iIC9vcHQvaG9tZWJyZXcvYmluL2J1biAvdXNyL2xvY2FsL2Jpbi9idW47IGRvCiAgICBpZiBydW50aW1lX29rICIkYyI7IHRoZW4gZWNobyAiJGMiOyByZXR1cm4gMDsgZmkKICBkb25lCiAgcmV0dXJuIDEKfQoKUlVOVElNRV9IRUxQPSJOb2RlLmpzIDIyIG9yIG5ld2VyIChvciBCdW4pIGlzIHJlcXVpcmVkIHRvIHJ1biB3aGVyZHIgd2l0aG91dCBEb2NrZXIuCiAgICAgSW5zdGFsbCBpdCBmcm9tIGh0dHBzOi8vbm9kZWpzLm9yZywgb3Igc2V0IGl0cyBhYnNvbHV0ZSBwYXRoIGluICRDT05GOgogICAgICAgV0hFUkRSX1JVTlRJTUU9L3BhdGgvdG8vbm9kZSIKCiMgVGhlIG1hY2hpbmUncyBzaG9ydCBuYW1lIChubyBkb21haW4pOiB3aGF0IHRoZSBhcHAgc2hvd3MsIGFuZCB0aGUgY29udGFpbmVyJ3MKIyBob3N0IG5hbWUuIFdpdGhvdXQgaXQgdGhlIGNvbnRhaW5lciB3b3VsZCBiZSBjYWxsZWQgIndoZXJkciIuCnNob3J0X2hvc3QoKSB7CiAgaD0iJChob3N0bmFtZSAyPi9kZXYvbnVsbCB8IGN1dCAtZC4gLWYxKSIKICBlY2hvICIke2g6LXNlcnZlcn0iCn0KCmhlcmRyX2JpbigpIHsKICBpZiBbIC1uICIke0hFUkRSX0JJTl9QQVRIOi19IiBdOyB0aGVuIGVjaG8gIiRIRVJEUl9CSU5fUEFUSCIKICBlbGlmIFsgLXggIiRIT01FLy5sb2NhbC9iaW4vaGVyZHIiIF07IHRoZW4gZWNobyAiJEhPTUUvLmxvY2FsL2Jpbi9oZXJkciIKICBlbHNlIGNvbW1hbmQgLXYgaGVyZHIgMj4vZGV2L251bGwgfHwgZWNobyBoZXJkcgogIGZpCn0KCnJlYWxfZGlyKCkgeyAoY2QgIiQxIiAyPi9kZXYvbnVsbCAmJiBwd2QgLVApIHx8IGVjaG8gIiQxIjsgfQoKIyBDb21wb3NlIGZvbGRlciBvZiB0aGUgYHdoZXJkcmAgY29udGFpbmVyLCBlbXB0eSB3aGVuIHRoZXJlIGlzIG5vbmUuCmNvbnRhaW5lcl9kaXIoKSB7CiAgZG9ja2VyIGluc3BlY3QgIiRDT05UQUlORVIiIC0tZm9ybWF0ICd7eyBpbmRleCAuQ29uZmlnLkxhYmVscyAiY29tLmRvY2tlci5jb21wb3NlLnByb2plY3Qud29ya2luZ19kaXIiIH19JyAyPi9kZXYvbnVsbCB8fCB0cnVlCn0KCiMgVHJ1ZSB3aGVuIHRoZSBgd2hlcmRyYCBjb250YWluZXIgYmVsb25ncyB0byAkRElSIChvciBkb2VzIG5vdCBleGlzdCB5ZXQpLgpjb250YWluZXJfb3VycygpIHsKICBvd25lcj0iJChjb250YWluZXJfZGlyKSIKICBbIC16ICIkb3duZXIiIF0gfHwgWyAiJChyZWFsX2RpciAiJG93bmVyIikiID0gIiQocmVhbF9kaXIgIiRESVIiKSIgXQp9Cgpjb21wb3NlKCkgeyBkb2NrZXIgY29tcG9zZSAtLXByb2plY3QtZGlyZWN0b3J5ICIkRElSIiAtZiAiJERJUi9kb2NrZXItY29tcG9zZS55bWwiICIkQCI7IH0KCndhaXRfdXAoKSB7CiAgaT0wCiAgd2hpbGUgWyAiJGkiIC1sdCAiJHsxOi0zMH0iIF07IGRvCiAgICBpZiBhbnN3ZXJzOyB0aGVuIHJldHVybiAwOyBmaQogICAgaT0kKChpICsgMSkpOyBzbGVlcCAxCiAgZG9uZQogIHJldHVybiAxCn0KCiMgVGhlIGNvbW1hbmRzIG9mIHRoZSBuYXRpdmUgbW9kZTogdGhlIGluc3RhbGxlZCBjb3B5LCBvciB0aGUgY2hlY2tvdXQgaXRzZWxmCiMgKGEgbGlua2VkIHBsdWdpbiBidWlsdCBieSBoYW5kLCBvciBhIHBsdWdpbiBpbnN0YWxsZWQgYmVmb3JlICRBUFAgZXhpc3RlZCkuCmNsaV9yb290KCkgewogIGlmIFsgLWYgIiRBUFAvYmluL3doZXJkci5tanMiIF0gJiYgWyAtZiAiJEFQUC8ub3V0cHV0L3NlcnZlci9pbmRleC5tanMiIF07IHRoZW4gZWNobyAiJEFQUCI7IGVsc2UgZWNobyAiJFJPT1QiOyBmaQp9CgojIFRoZSBwZXJzb24gcnVubmluZyBgaGVyZHIgcGx1Z2luIGluc3RhbGxgIHNlZXMgb25seSBIZXJkcidzIG93biBsaW5lczogdGhlCiMgb3V0cHV0IG9mIGJ1aWxkIGNvbW1hbmRzIGlzIGNhcHR1cmVkLiBJbXBvcnRhbnQgbGluZXMgYWxzbyBnbyB0byB0aGUgdGVybWluYWwuCnRlbGwoKSB7CiAgcHJpbnRmICclc1xuJyAiJCoiCiAgeyBwcmludGYgJyVzXG4nICIkKiIgPiAvZGV2L3R0eTsgfSAyPi9kZXYvbnVsbCB8fCB0cnVlCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGJ1aWxkCmNtZF9idWlsZCgpIHsKICB0ZWxsICJ3aGVyZHI6IGluc3RhbGxpbmcgaW4gJERJUiIKICAjIEZpcnN0IGluc3RhbGwgKG5vIHBsdWdpbi5lbnYgeWV0KTogdGhlIGJyb3dzZXIgb3BlbnMgb24gdGhlIHNldHVwIGd1aWRlCiAgIyBvbmNlIHdoZXJkciBydW5zLiBVcGRhdGVzIGtlZXAgcGx1Z2luLmVudiBhbmQgb3BlbiBub3RoaW5nLgogIEZJUlNUX0lOU1RBTEw9MAogIFsgLWYgIiRDT05GIiBdIHx8IEZJUlNUX0lOU1RBTEw9MQogIG1rZGlyIC1wICIkRElSIgogIHByaW50ZiAnJXNcbicgIiRESVIiID4gIiRST09ULy53aGVyZHItZGlyIgoKICBpZiBbIC16ICIkTU9ERSIgXTsgdGhlbgogICAgaWYgZG9ja2VyX3VzYWJsZTsgdGhlbiBNT0RFPWRvY2tlcjsgZWxzZSBNT0RFPW5hdGl2ZTsgZmkKICBmaQogIGNhc2UgIiRNT0RFIiBpbgogICAgZG9ja2VyKSBkb2NrZXJfdXNhYmxlIHx8IGRpZSAiV0hFUkRSX01PREU9ZG9ja2VyLCBidXQgRG9ja2VyIENvbXBvc2UgdjIgaXMgbm90IHVzYWJsZSBieSAkKGlkIC11bikgb24gdGhpcyBzeXN0ZW0uIiA7OwogICAgbmF0aXZlKSA7OwogICAgKikgZGllICJXSEVSRFJfTU9ERSBtdXN0IGJlIGRvY2tlciBvciBuYXRpdmUgKGdvdDogJE1PREUpLiIgOzsKICBlc2FjCgogIGlmIFsgIiRNT0RFIiA9ICJkb2NrZXIiIF07IHRoZW4gYnVpbGRfZG9ja2VyOyBlbHNlIGJ1aWxkX25hdGl2ZTsgZmkKICAjIFdyaXR0ZW4gbGFzdDogYSBmYWlsZWQgYnVpbGQga2VlcHMgbm8gaGFsZi1tYWRlIGNob2ljZS4gUmV3cml0dGVuIG9uIGVhY2gKICAjIGluc3RhbGwgZnJvbSB0aGUgbWVyZ2VkIHNldHRpbmdzIChlbnZpcm9ubWVudCBvdmVyIHRoZSBwcmV2aW91cyBmaWxlKS4KICB3cml0ZV9jb25mCiAgb2sgInBsdWdpbi5lbnYgd3JpdHRlbiAobW9kZTogJE1PREUpIgogICggY21kX3NraWxsIHJlZnJlc2ggKSB8fCB3YXJuICJ3aGVyZHIgc2tpbGwgbm90IGxpbmtlZCAob3B0aW9uYWwpOiBydW4gJDAgc2tpbGwgaW5zdGFsbCIKICAoIGNtZF9rZXkgaW5zdGFsbCApIHx8IHdhcm4gIm5vIEhlcmRyIGtleSBmb3IgdGhlIHBhbmVsIChvcHRpb25hbCk6IHJ1biAkMCBrZXkgaW5zdGFsbCIKICBidWlsZF9zdGFydAp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBza2lsbAojIEluc3RhbGxhdGlvbiBpcyBzaGFyZWQgd2l0aCBucG0gLyBIb21lYnJldzsgRG9ja2VyIHJlYWRzIHRoZSBwdWxsZWQgaW1hZ2UuCmNtZF9za2lsbCgpIHsKICBjYXNlICIkezE6LX0iIGluCiAgICByZWZyZXNofGluc3RhbGwpCiAgICAgIGlmIFsgIiRNT0RFIiA9IGRvY2tlciBdOyB0aGVuCiAgICAgICAgKCBpbWFnZT0iJChjb21wb3NlIGNvbmZpZyAtLWltYWdlcyBoZXJkci13ZWIgfCBoZWFkIC1uIDEpIgogICAgICAgICAgV0hFUkRSX0RJUj0iJERJUiIgc2ggIiRST09UL2Jpbi9pbnN0YWxsLWRvY2tlci1za2lsbC5zaCIgIiRpbWFnZSIgIiQxIgogICAgICAgICkKICAgICAgZWxzZQogICAgICAgIFdIRVJEUl9ESVI9IiRESVIiIHNoICIkUk9PVC9iaW4vbGliL2luc3RhbGwtc2tpbGwuc2giICIkMSIgIiRST09UIgogICAgICBmaQogICAgICA7OwogICAgdW5pbnN0YWxsKSBXSEVSRFJfRElSPSIkRElSIiBzaCAiJFJPT1QvYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIiB1bmluc3RhbGwgIiRST09UIiA7OwogICAgKikgZGllICJ1c2FnZTogJDAgc2tpbGwgaW5zdGFsbHx1bmluc3RhbGwiIDs7CiAgZXNhYwp9CgojIExhc3Qgc3RlcCBvZiB0aGUgaW5zdGFsbDogc3RhcnQgd2hlcmRyIChvciByZXN0YXJ0IHRoZSBvbmUgdGhpcyBwbHVnaW4KIyBydW5zLCBvbiBhbiB1cGRhdGUpLiBOZXZlciBmYWlscyB0aGUgaW5zdGFsbDogYSB3aGVyZHIgdGhhdCBjYW5ub3Qgc3RhcnQgaXMKIyByZXBvcnRlZCB3aXRoIHdoYXQgdG8gZG8sIHRoZSBwbHVnaW4gc3RheXMgaW5zdGFsbGVkLgpidWlsZF9zdGFydCgpIHsKICBzZXQgK2UKICBvdXQ9IiQoIChjbWRfc3RhcnQpIDI+JjEgKSIKICBjb2RlPSQ/CiAgc2V0IC1lCiAgcHJpbnRmICclc1xuJyAiJG91dCIKICBpZiBbICIkY29kZSIgLWVxIDAgXSAmJiBhbnN3ZXJzOyB0aGVuCiAgICAjIGh0dHBzOi8vd2hlcmRyLmRldi9pbnN0YWxsIHByaW50cyBpdHMgb3duIHN1bW1hcnkgKFdIRVJEUl9JTlNUQUxMRVI9MSkuCiAgICBxdWlldD0wCiAgICBbICIke1dIRVJEUl9JTlNUQUxMRVI6LTB9IiA9IDEgXSAmJiBxdWlldD0xCiAgICBbICIkcXVpZXQiID0gMSBdIHx8IHRlbGwgIiIKICAgIFsgIiRxdWlldCIgPSAxIF0gfHwgdGVsbCAi4pyTIHdoZXJkciBpcyBydW5uaW5nIOKGkiAkVVJMIgogICAgaWYgWyAiJHF1aWV0IiAhPSAxIF07IHRoZW4KICAgICAga2V5PSIkKGtleV9ib3VuZCkiCiAgICAgIGlmIFsgLW4gIiRrZXkiIF07IHRoZW4gdGVsbCAiICBJbiBIZXJkciwgJGtleSBvcGVucyB0aGUgd2hlcmRyIHBhbmVsLiIKICAgICAgZWxzZSB0ZWxsICIgIEluIEhlcmRyOiBoZXJkciBwbHVnaW4gYWN0aW9uIGludm9rZSBwYW5lbCAtLXBsdWdpbiAkUExVR0lOX0lEIgogICAgICBmaQogICAgZmkKICAgIGlmIFsgIiR7RklSU1RfSU5TVEFMTDotMH0iID0gMSBdOyB0aGVuCiAgICAgICMgQWxyZWFkeSBwdWJsaXNoZWQgb24gdGhlIHRhaWxuZXQgKGEgcmVpbnN0YWxsLCBvciBgdGFpbHNjYWxlIHNlcnZlYAogICAgICAjIHJ1biBmaXJzdCk6IHRoZSBndWlkZSBvcGVucyBvbiB0aGF0IGFkZHJlc3MsIHdoZXJlIHBhc3NrZXlzIGJlbG9uZy4KICAgICAgZ3VpZGU9IiQob3Blbl9hZGRyZXNzKS8jL3NldHVwIgogICAgICBpZiBvcGVuX2Jyb3dzZXIgIiRndWlkZSI7IHRoZW4gWyAiJHF1aWV0IiA9IDEgXSB8fCB0ZWxsICIgIFNldHVwIGd1aWRlIG9wZW5lZCBpbiB5b3VyIGJyb3dzZXI6ICRndWlkZSIKICAgICAgZWxzZSBbICIkcXVpZXQiID0gMSBdIHx8IHRlbGwgIiAgU2V0dXAgZ3VpZGU6IG9wZW4gJGd1aWRlIGluIGEgYnJvd3NlciIKICAgICAgZmkKICAgIGZpCiAgICBbICIkcXVpZXQiID0gMSBdIHx8IHRlbGwgIiAgUGhvbmU6IHByZXNzIFAgaW4gdGhlIHBhbmVsIHRvIGdldCB5b3VyIFRhaWxzY2FsZSBhZGRyZXNzIChwcml2YXRlIG5ldHdvcmsgb25seSkuIgogIGVsc2UKICAgIHRlbGwgIiIKICAgIHRlbGwgIiEgd2hlcmRyIGlzIGluc3RhbGxlZCBidXQgZGlkIG5vdCBzdGFydDoiCiAgICBwcmludGYgJyVzXG4nICIkb3V0IiB8IHRhaWwgLW4gOCB8IHdoaWxlIElGUz0gcmVhZCAtciBsOyBkbyB0ZWxsICIgICAgJGwiOyBkb25lCiAgICB0ZWxsICIgIE9wZW4gdGhlIHdoZXJkciBwYW5lbCBpbiBIZXJkciwgdGhlbiBwcmVzcyBTIHRvIHN0YXJ0IGl0IG9yIEwgZm9yIGl0cyBsb2cuIgogIGZpCn0KCndyaXRlX2NvbmYoKSB7CiAgewogICAgZWNobyAiIyB3aGVyZHIgSGVyZHIgcGx1Z2luIHNldHRpbmdzIChoZXJkci1wbHVnaW4uc2gpLiIKICAgIGVjaG8gIiMgVG8gc3dpdGNoIG1vZGUsIHNldCBXSEVSRFJfTU9ERSBhbmQgcnVuOiBoZXJkciBwbHVnaW4gaW5zdGFsbCAkU09VUkNFIgogICAgZWNobyAiV0hFUkRSX01PREU9JE1PREUiCiAgICBlY2hvICJXSEVSRFJfUE9SVD0kUE9SVCIKICAgIGVjaG8gIiMgTmF0aXZlIG1vZGU6IHByaXZhdGUgSFRUUFMgYWRkcmVzcyAodGFpbHNjYWxlIHNlcnZlKSwgZm9yIHB1c2ggbm90aWZpY2F0aW9ucy4iCiAgICBlY2hvICJBUFBfVVJMPSR7QVBQX1VSTDotfSIKICAgIGlmIFsgIiRNT0RFIiA9ICJuYXRpdmUiIF07IHRoZW4KICAgICAgZWNobyAiIyBOYXRpdmUgbW9kZTogYWJzb2x1dGUgcGF0aCBvZiB0aGUgbm9kZSAoMjIrKSBvciBidW4gdGhhdCBydW5zIHdoZXJkci4iCiAgICAgIGVjaG8gIldIRVJEUl9SVU5USU1FPSRSVU5USU1FIgogICAgZmkKICB9ID4gIiRDT05GIgp9CgojIFByZWZlciB0aGUgcmVsZWFzZSBhcmNoaXZlLCB0aGVuIHRoZSBhbHJlYWR5LWJ1aWx0IG5wbSBwYWNrYWdlLiBDb21waWxlIG9ubHkKIyB3aGVuIG5laXRoZXIgc291cmNlIHByb3ZpZGVzIGEgdXNhYmxlIHBhY2thZ2Ugb2YgdGhpcyBleGFjdCB2ZXJzaW9uLgpmZXRjaF9wcmVidWlsdCgpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxICYmIGNvbW1hbmQgLXYgdGFyID4vZGV2L251bGwgMj4mMSB8fCByZXR1cm4gMQogIHZlcnNpb249IiQoc2VkIC1uICdzL152ZXJzaW9uID0gIlwoLipcKSIkL1wxL3AnICIkUk9PVC9oZXJkci1wbHVnaW4udG9tbCIgfCBoZWFkIC1uIDEpIgogIHRtcD0iJChta3RlbXAgLWQpIgogIGZvciBzb3VyY2UgaW4gZ2l0aHViIG5wbTsgZG8KICAgIHJtIC1yZiAiJHRtcC9wYWNrYWdlIgogICAgaWYgWyAiJHNvdXJjZSIgPSBnaXRodWIgXTsgdGhlbgogICAgICB1cmw9Imh0dHBzOi8vZ2l0aHViLmNvbS8kU09VUkNFL3JlbGVhc2VzL2Rvd25sb2FkL3YkdmVyc2lvbi93aGVyZHItJHZlcnNpb24udGd6IgogICAgICBjdXJsIC1mc1NMIC0tbWF4LXRpbWUgMTIwICIkdXJsIiAtbyAiJHRtcC93aGVyZHIudGd6IiAyPi9kZXYvbnVsbCBcCiAgICAgICAgJiYgY3VybCAtZnNTTCAtLW1heC10aW1lIDMwICIkdXJsLnNoYTI1NiIgLW8gIiR0bXAvY2hlY2tzdW0iIDI+L2Rldi9udWxsIFwKICAgICAgICAmJiAiJFJVTlRJTUUiICIkUk9PVC9iaW4vbGliL3ZlcmlmeS1yZWxlYXNlLm1qcyIgIiR0bXAvd2hlcmRyLnRneiIgIiR0bXAvY2hlY2tzdW0iIDI+L2Rldi9udWxsIHx8IGNvbnRpbnVlCiAgICBlbHNlCiAgICAgIHVybD0iaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hlcmRyLy0vd2hlcmRyLSR2ZXJzaW9uLnRneiIKICAgICAgY3VybCAtZnNTTCAtLW1heC10aW1lIDEyMCAiJHVybCIgLW8gIiR0bXAvd2hlcmRyLnRneiIgMj4vZGV2L251bGwgXAogICAgICAgICYmIGN1cmwgLWZzU0wgLS1tYXgtdGltZSAzMCAiaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hlcmRyLyR2ZXJzaW9uIiAtbyAiJHRtcC9tZXRhZGF0YSIgMj4vZGV2L251bGwgXAogICAgICAgICYmICIkUlVOVElNRSIgIiRST09UL2Jpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIiAiJHRtcC93aGVyZHIudGd6IiAiJHRtcC9tZXRhZGF0YSIgbnBtICIkdmVyc2lvbiIgMj4vZGV2L251bGwgfHwgY29udGludWUKICAgIGZpCiAgICB0YXIgLXh6ZiAiJHRtcC93aGVyZHIudGd6IiAtQyAiJHRtcCIgMj4vZGV2L251bGwgfHwgY29udGludWUKICAgIFsgLWYgIiR0bXAvcGFja2FnZS8ub3V0cHV0L3NlcnZlci9pbmRleC5tanMiIF0gXAogICAgICAmJiBbIC1kICIkdG1wL3BhY2thZ2UvYmluIiBdICYmIFsgLWYgIiR0bXAvcGFja2FnZS9wYWNrYWdlLmpzb24iIF0gfHwgY29udGludWUKICAgICMgTGVnYWN5IHBhY2thZ2VzIGhhdmUgbmVpdGhlciB0aGUgc2tpbGwgbm9yIGl0cyBoZWxwZXJzLiBLZWVwIHRoZQogICAgIyBjaGVja291dCdzIGNvbW1hbmRzIHNvIHBsdWdpbiBza2lsbCBpbnN0YWxsL3VuaW5zdGFsbCBzdGlsbCB3b3JrLgogICAgZm9yIGVudHJ5IGluIC5vdXRwdXQgYmluIHBhY2thZ2UuanNvbiBza2lsbHM7IGRvCiAgICAgIFsgLWUgIiR0bXAvcGFja2FnZS8kZW50cnkiIF0gfHwgY29udGludWUKICAgICAgaWYgWyAiJGVudHJ5IiA9IGJpbiBdOyB0aGVuCiAgICAgICAgWyAtZiAiJHRtcC9wYWNrYWdlL3NraWxscy93aGVyZHIvU0tJTEwubWQiIF0gXAogICAgICAgICAgJiYgWyAtZiAiJHRtcC9wYWNrYWdlL2Jpbi9saWIvaW5zdGFsbC1za2lsbC5zaCIgXSB8fCBjb250aW51ZQogICAgICBmaQogICAgICBybSAtcmYgIiRST09ULyRlbnRyeSIKICAgICAgbXYgIiR0bXAvcGFja2FnZS8kZW50cnkiICIkUk9PVC8kZW50cnkiCiAgICBkb25lCiAgICBybSAtcmYgIiR0bXAiCiAgICBvayAid2hlcmRyICR2ZXJzaW9uIGRvd25sb2FkZWQgKCRzb3VyY2UgcGFja2FnZSwgY2hlY2tzdW0gbWF0Y2hlZCkiCiAgICByZXR1cm4gMAogIGRvbmUKICBybSAtcmYgIiR0bXAiCiAgcmV0dXJuIDEKfQoKIyBxcmNvZGUtdGVybWluYWwgKHRoZSBwYW5lbCdzIFFSIGNvZGUpLCB0aGUgb25seSBwYWNrYWdlIHRoZSBjb21tYW5kcyBuZWVkCiMgYXQgcnVudGltZSwgd2hlbiB0aGUgZm9sZGVyIGRvZXMgbm90IGhhdmUgaXQgeWV0IChubyBucG0gY2kgd2FzIHJ1bikuCmZldGNoX3FyKCkgewogIFsgLWYgIiQxL25vZGVfbW9kdWxlcy9xcmNvZGUtdGVybWluYWwvcGFja2FnZS5qc29uIiBdICYmIHJldHVybiAwCiAgY29tbWFuZCAtdiBjdXJsID4vZGV2L251bGwgMj4mMSAmJiBjb21tYW5kIC12IHRhciA+L2Rldi9udWxsIDI+JjEgfHwgcmV0dXJuIDAKICB0bXA9IiQobWt0ZW1wIC1kKSIKICBpZiBjdXJsIC1mc1NMIC0tbWF4LXRpbWUgNjAgaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcXJjb2RlLXRlcm1pbmFsLy0vcXJjb2RlLXRlcm1pbmFsLTAuMTIuMC50Z3ogLW8gIiR0bXAvcXIudGd6IiAyPi9kZXYvbnVsbCBcCiAgICAmJiB0YXIgLXh6ZiAiJHRtcC9xci50Z3oiIC1DICIkdG1wIjsgdGhlbgogICAgbWtkaXIgLXAgIiQxL25vZGVfbW9kdWxlcyIKICAgIHJtIC1yZiAiJDEvbm9kZV9tb2R1bGVzL3FyY29kZS10ZXJtaW5hbCIKICAgIG12ICIkdG1wL3BhY2thZ2UiICIkMS9ub2RlX21vZHVsZXMvcXJjb2RlLXRlcm1pbmFsIgogIGVsc2UKICAgIHdhcm4gIk5vIFFSIGNvZGUgaW4gdGhlIHBhbmVsIChxcmNvZGUtdGVybWluYWwgY291bGQgbm90IGJlIGRvd25sb2FkZWQpLiIKICBmaQogIHJtIC1yZiAiJHRtcCIKfQoKYnVpbGRfbmF0aXZlKCkgewogIFJVTlRJTUU9IiQoZmluZF9ydW50aW1lKSIgfHwgZGllICIkUlVOVElNRV9IRUxQIgogIG9rICJSdW50aW1lOiAkUlVOVElNRSAoJCgiJFJVTlRJTUUiIC0tdmVyc2lvbiAyPi9kZXYvbnVsbCkpIgogIGlmIGZldGNoX3ByZWJ1aWx0OyB0aGVuCiAgICBpbnN0YWxsX2FwcAogICAgcmV0dXJuIDAKICBmaQogIGNhc2UgIiQoYmFzZW5hbWUgIiRSVU5USU1FIikiIGluCiAgICBidW4pIGRpZSAiVGhlIHByZWJ1aWx0IHdoZXJkciBwYWNrYWdlIGNvdWxkIG5vdCBiZSBkb3dubG9hZGVkLCBhbmQgYnVpbGRpbmcgaXQgbmVlZHMgTm9kZS5qcyAyMiB3aXRoIG5wbS4KICAgICBDaGVjayB0aGUgbmV0d29yaywgb3IgaW5zdGFsbCBOb2RlLmpzIDIyLCB0aGVuIGluc3RhbGwgdGhlIHBsdWdpbiBhZ2Fpbi4iIDs7CiAgZXNhYwogIGJpbmRpcj0iJChkaXJuYW1lICIkUlVOVElNRSIpIgogIFsgLXggIiRiaW5kaXIvbnBtIiBdIHx8IGNvbW1hbmQgLXYgbnBtID4vZGV2L251bGwgMj4mMSB8fCBkaWUgIm5wbSBpcyBtaXNzaW5nIChpdCBjb21lcyB3aXRoIE5vZGUuanMpLiIKICB0ZWxsICJ3aGVyZHI6IGJ1aWxkaW5nIChhIGZldyBtaW51dGVzIHRoZSBmaXJzdCB0aW1lKeKApiIKICAoCiAgICBjZCAiJFJPT1QiCiAgICBQQVRIPSIkYmluZGlyOiRQQVRIIiBucG0gY2kgLS1uby1hdWRpdCAtLW5vLWZ1bmQKICAgIFBBVEg9IiRiaW5kaXI6JFBBVEgiIG5wbSBydW4gYnVpbGQKICApCiAgb2sgIndoZXJkciBidWlsdCBpbiB0aGUgcGx1Z2luIGZvbGRlciIKICBpbnN0YWxsX2FwcAp9CgojIENvcGllcyB0aGUgY29tbWFuZHMgYW5kIHRoZSBidWlsdCBzZXJ2ZXIgdG8gJEFQUCwgd2hpY2ggb3V0bGl2ZXMgdGhpcwojIGNoZWNrb3V0LiBBIHdoZXJkciB0aGlzIHBsdWdpbiBydW5zIGZyb20gdGhlIHByZXZpb3VzIGNvcHkgaXMgc3RvcHBlZCBmb3IKIyB0aGUgc3dhcDsgYnVpbGRfc3RhcnQgc3RhcnRzIHRoZSBuZXcgb25lLgppbnN0YWxsX2FwcCgpIHsKICAjIE5pdHJvIGxpbmtzIHNvbWUgcGFja2FnZXMgKHRzbGliKSB0byBpdHMgb3duIGZvbGRlcjogY29waWVzLCBub3QgbGlua3MuCiAgaWYgWyAtZCAiJFJPT1QvLm91dHB1dC9zZXJ2ZXIvbm9kZV9tb2R1bGVzIiBdOyB0aGVuICIkUlVOVElNRSIgIiRST09UL3NjcmlwdHMvcGFjay1vdXRwdXQubWpzIiA+L2Rldi9udWxsOyBmaQogIG5ldz0iJEFQUC5uZXciCiAgcm0gLXJmICIkbmV3IgogIG1rZGlyIC1wICIkbmV3IgogIGNwIC1SICIkUk9PVC9iaW4iICIkUk9PVC9za2lsbHMiICIkUk9PVC8ub3V0cHV0IiAiJFJPT1QvcGFja2FnZS5qc29uIiAiJG5ldy8iCiAgaWYgWyAtZCAiJFJPT1Qvbm9kZV9tb2R1bGVzL3FyY29kZS10ZXJtaW5hbCIgXTsgdGhlbgogICAgbWtkaXIgLXAgIiRuZXcvbm9kZV9tb2R1bGVzIgogICAgY3AgLVIgIiRST09UL25vZGVfbW9kdWxlcy9xcmNvZGUtdGVybWluYWwiICIkbmV3L25vZGVfbW9kdWxlcy8iCiAgZmkKICBmZXRjaF9xciAiJG5ldyIKICAjIFRoZSB3aGVyZHIgdGhpcyBwbHVnaW4gcnVucyAoZnJvbSB0aGUgcHJldmlvdXMgY29weSwgb3IgZnJvbSBhbiBvbGRlcgogICMgcGx1Z2luIGNoZWNrb3V0KTogc3RvcHBlZCBmb3IgdGhlIHN3YXAsIHN0YXJ0ZWQgYWdhaW4gYnkgYnVpbGRfc3RhcnQuCiAgaWYgWyAtZiAiJERJUi93aGVyZHIucGlkIiBdIHx8IFsgLWYgIiRBUFAvYmluL3doZXJkci5tanMiIF07IHRoZW4gY2xpIHN0b3AgPi9kZXYvbnVsbCAyPiYxIHx8IHRydWU7IGZpCiAgcm0gLXJmICIkQVBQLm9sZCIKICBpZiBbIC1kICIkQVBQIiBdOyB0aGVuIG12ICIkQVBQIiAiJEFQUC5vbGQiOyBmaQogIG12ICIkbmV3IiAiJEFQUCIKICBybSAtcmYgIiRBUFAub2xkIgogIG9rICJ3aGVyZHIgJChzZWQgLW4gJ3MvXiAqInZlcnNpb24iOiAqIlwoLipcKSIsJC9cMS9wJyAiJEFQUC9wYWNrYWdlLmpzb24iIHwgaGVhZCAtbiAxKSBpbnN0YWxsZWQgaW4gJEFQUCIKfQoKYnVpbGRfZG9ja2VyKCkgewogIG9rICJEb2NrZXIgJChkb2NrZXIgdmVyc2lvbiAtLWZvcm1hdCAne3suU2VydmVyLlZlcnNpb259fScgMj4vZGV2L251bGwgfHwgZWNobyAnPycpIgogIHN0YW1wPSIkRElSLy5jb21wb3NlLWZyb20tcGx1Z2luIgogIGlmIFsgISAtZiAiJERJUi9kb2NrZXItY29tcG9zZS55bWwiIF07IHRoZW4KICAgIGNwICIkUk9PVC9kb2NrZXItY29tcG9zZS55bWwiICIkRElSL2RvY2tlci1jb21wb3NlLnltbCIKICAgIGNrc3VtIDwgIiRESVIvZG9ja2VyLWNvbXBvc2UueW1sIiA+ICIkc3RhbXAiCiAgICBvayAiZG9ja2VyLWNvbXBvc2UueW1sIGNvcGllZCIKICBlbGlmIGNtcCAtcyAiJFJPT1QvZG9ja2VyLWNvbXBvc2UueW1sIiAiJERJUi9kb2NrZXItY29tcG9zZS55bWwiOyB0aGVuCiAgICBvayAiZG9ja2VyLWNvbXBvc2UueW1sIGlzIHVwIHRvIGRhdGUiCiAgZWxpZiBbIC1mICIkc3RhbXAiIF0gJiYgWyAiJChja3N1bSA8ICIkRElSL2RvY2tlci1jb21wb3NlLnltbCIpIiA9ICIkKGNhdCAiJHN0YW1wIikiIF07IHRoZW4KICAgICMgVW5jaGFuZ2VkIHNpbmNlIHRoZSBwbHVnaW4gd3JvdGUgaXQ6IHNhZmUgdG8gcmVmcmVzaC4KICAgIGNwICIkUk9PVC9kb2NrZXItY29tcG9zZS55bWwiICIkRElSL2RvY2tlci1jb21wb3NlLnltbCIKICAgIGNrc3VtIDwgIiRESVIvZG9ja2VyLWNvbXBvc2UueW1sIiA+ICIkc3RhbXAiCiAgICBvayAiZG9ja2VyLWNvbXBvc2UueW1sIHVwZGF0ZWQiCiAgZWxzZQogICAgd2FybiAiS2VlcGluZyB5b3VyIGVkaXRlZCBkb2NrZXItY29tcG9zZS55bWwgKHRoZSBuZXcgb25lIGlzICRST09UL2RvY2tlci1jb21wb3NlLnltbCkuIgogIGZpCiAgaWYgWyAhIC1mICIkRElSLy5lbnYiIF07IHRoZW4KICAgIGhlcmRyPSIkKGhlcmRyX2JpbikiCiAgICB7CiAgICAgIGVjaG8gIiMgd2hlcmRyIHNldHRpbmdzLCByZWFkIGJ5IGRvY2tlciBjb21wb3NlIChzZWUgLmVudi5leGFtcGxlIGluIHRoZSByZXBvc2l0b3J5KS4iCiAgICAgIGVjaG8gIkhPU1RfSE9NRT0kSE9NRSIKICAgICAgZWNobyAiUFVJRD0kKGlkIC11KSIKICAgICAgZWNobyAiUEdJRD0kKGlkIC1nKSIKICAgICAgZWNobyAiUE9SVD0kUE9SVCIKICAgICAgZWNobyAiIyBQcml2YXRlIEhUVFBTIGFkZHJlc3MgKHRhaWxzY2FsZSBzZXJ2ZSksIG5lZWRlZCBmb3IgcHVzaCBub3RpZmljYXRpb25zLiIKICAgICAgZWNobyAiQVBQX1VSTD0ke0FQUF9VUkw6LWh0dHA6Ly9sb2NhbGhvc3Q6JFBPUlQvfSIKICAgICAgZWNobyAiSE9TVF9MQUJFTD0kKHNob3J0X2hvc3QpIgogICAgICBlY2hvICJUWj0ke1RaOi1VVEN9IgogICAgICBpZiBbICIkaGVyZHIiICE9ICIkSE9NRS8ubG9jYWwvYmluL2hlcmRyIiBdOyB0aGVuIGVjaG8gIkhFUkRSX0JJTj0kaGVyZHIiOyBmaQogICAgfSA+ICIkRElSLy5lbnYiCiAgICBvayAiLmVudiBjcmVhdGVkIgogIGVsc2UKICAgIG9rICIuZW52IGtlcHQiCiAgZmkKICBjb21wb3NlIHB1bGwgLS1xdWlldCB8fCBkaWUgIkNvdWxkIG5vdCBwdWxsIHRoZSB3aGVyZHIgaW1hZ2UuIENoZWNrIHRoZSBuZXR3b3JrLCB0aGVuIGluc3RhbGwgdGhlIHBsdWdpbiBhZ2Fpbi4iCiAgb2sgIkltYWdlIHB1bGxlZCIKICAjIFRoZSBwYW5lbCBydW5zIGZyb20gdGhlIGNoZWNrb3V0IHdpdGggbm9kZSB3aGVuIHRoZXJlIGlzIG9uZS4KICBmZXRjaF9xciAiJFJPT1QiCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHN0YXJ0CmNtZF9zdGFydCgpIHsKICBpZiBhbnN3ZXJzOyB0aGVuCiAgICBzYXkgIndoZXJkcjogc29tZXRoaW5nIGFscmVhZHkgYW5zd2VycyBvbiBwb3J0ICRQT1JULCBub3RoaW5nIHRvIHN0YXJ0ICgkVVJMKS4iCiAgICByZXR1cm4gMAogIGZpCiAgY2FzZSAiJE1PREUiIGluCiAgICBkb2NrZXIpIHN0YXJ0X2RvY2tlciA7OwogICAgbmF0aXZlKSBzdGFydF9uYXRpdmUgOzsKICAgICopIGRpZSAid2hlcmRyIHBsdWdpbiBpcyBub3Qgc2V0IHVwICgkQ09ORiBpcyBtaXNzaW5nKTogaW5zdGFsbCBpdCBhZ2FpbiB3aXRoIGhlcmRyIHBsdWdpbiBpbnN0YWxsICRTT1VSQ0UuIiA7OwogIGVzYWMKICBpZiBbICIkTU9ERSIgPSAibmF0aXZlIiBdOyB0aGVuIHJldHVybiAwOyBmaQogIGlmIHdhaXRfdXAgNDU7IHRoZW4KICAgIHNheSAid2hlcmRyIGlzIHJ1bm5pbmc6ICRVUkwiCiAgZWxzZQogICAgd2FybiAid2hlcmRyIGRvZXMgbm90IGFuc3dlciBvbiBwb3J0ICRQT1JUIHlldC4gTG9nOiAkKGxvZ19oaW50KSIKICAgIGV4aXQgMQogIGZpCn0KCiMgTmF0aXZlIG1vZGU6IHRoZSB3aGVyZHIgY29tbWFuZCAoYmluL3doZXJkci5tanMpIGRvZXMgdGhlIHdvcmssIHdpdGggdGhlCiMgcnVudGltZSBzYXZlZCBhdCBpbnN0YWxsOyBpdCBzYXlzICJzdGFydGVkIiBvbmx5IG9uY2UgdGhlIHBvcnQgYW5zd2Vycy4KZW5zdXJlX3J1bnRpbWUoKSB7CiAgaWYgISBydW50aW1lX29rICIkUlVOVElNRSI7IHRoZW4KICAgIHNhdmVkPSIkUlVOVElNRSIKICAgIFJVTlRJTUU9IiQoZmluZF9ydW50aW1lKSIgfHwgZGllICIke3NhdmVkOitUaGUgc2F2ZWQgcnVudGltZSAoJHNhdmVkKSBpcyBnb25lLiB9JFJVTlRJTUVfSEVMUCIKICAgIHdhcm4gIiR7c2F2ZWQ6KyRzYXZlZCBpcyBnb25lOiB9dXNpbmcgJFJVTlRJTUUgKHNhdmVkIGluICRDT05GKS4iCiAgICB3cml0ZV9jb25mCiAgZmkKfQoKY2xpKCkgewogIGVuc3VyZV9ydW50aW1lCiAgc29jaz0iJHtIRVJEUl9TT0NLRVRfUEFUSDotfSIKICAjIEEgcGx1Z2luIHN0YXJ0ZWQgZnJvbSBhIG5hbWVkIEhlcmRyIHNlc3Npb24gZHJpdmVzIHRoYXQgc2Vzc2lvbi4KICBzZXNzaW9uPSIiCiAgY2FzZSAiJHNvY2siIGluICovc2Vzc2lvbnMvKi9oZXJkci5zb2NrKSBzZXNzaW9uPSIkKGJhc2VuYW1lICIkKGRpcm5hbWUgIiRzb2NrIikiKSIgOzsgZXNhYwogICgKICAgIGNkICIkRElSIgogICAgSEVSRFJfQklOPSIkKGhlcmRyX2JpbikiCiAgICAjIFRoZSBydW50aW1lJ3MgZm9sZGVyIGZpcnN0OiB0b29scyBpdCBzdGFydHMgZmluZCB0aGUgc2FtZSBub2RlLgogICAgUEFUSD0iJChkaXJuYW1lICIkUlVOVElNRSIpOiRQQVRIIgogICAgZXhwb3J0IFBBVEggV0hFUkRSX0RJUj0iJERJUiIgV0hFUkRSX1JVTlRJTUU9IiRSVU5USU1FIiBIT1NUPTEyNy4wLjAuMSBQT1JUIEhFUkRSX0JJTgogICAgaWYgWyAtbiAiJHNlc3Npb24iIF07IHRoZW4gZXhwb3J0IEhFUkRSX1dFQl9TRVNTSU9OPSIkc2Vzc2lvbiI7IGZpCiAgICBpZiBbIC1uICIkc29jayIgXTsgdGhlbiBleHBvcnQgSEVSRFJfU09DSz0iJHNvY2siOyBmaQogICAgaWYgWyAtbiAiJHtBUFBfVVJMOi19IiBdOyB0aGVuIGV4cG9ydCBBUFBfVVJMOyBmaQogICAgZXhlYyAiJFJVTlRJTUUiICIkKGNsaV9yb290KS9iaW4vd2hlcmRyLm1qcyIgIiRAIgogICkKfQoKc3RhcnRfbmF0aXZlKCkgewogIFsgLWYgIiQoY2xpX3Jvb3QpLy5vdXRwdXQvc2VydmVyL2luZGV4Lm1qcyIgXSB8fCBkaWUgIndoZXJkciBpcyBub3QgYnVpbHQ6IGluc3RhbGwgdGhlIHBsdWdpbiBhZ2FpbiAoaGVyZHIgcGx1Z2luIGluc3RhbGwgJFNPVVJDRSAtLXllcykuIgogIG1rZGlyIC1wICIkRElSIgogIGNsaSBzdGFydAp9CgpzdGFydF9kb2NrZXIoKSB7CiAgWyAtZiAiJERJUi9kb2NrZXItY29tcG9zZS55bWwiIF0gfHwgZGllICIkRElSL2RvY2tlci1jb21wb3NlLnltbCBpcyBtaXNzaW5nOiBydW4gdGhlIFVwZGF0ZSBhY3Rpb24uIgogIGlmICEgY29udGFpbmVyX291cnM7IHRoZW4KICAgIHNheSAid2hlcmRyOiB0aGUgXCIkQ09OVEFJTkVSXCIgY29udGFpbmVyIGJlbG9uZ3MgdG8gJChjb250YWluZXJfZGlyKTsgc3RhcnQgaXQgZnJvbSB0aGVyZS4gTm90aGluZyBkb25lLiIKICAgIGV4aXQgMAogIGZpCiAgIyBDcmVhdGVkIGFzIHRoaXMgdXNlciBmaXJzdDogRG9ja2VyIHdvdWxkIGNyZWF0ZSBtaXNzaW5nIGJpbmQgbW91bnRzIGFzIHJvb3QuCiAgbWtkaXIgLXAgIiRESVIvZGF0YSIgIiRIT01FLy5jb25maWcvaGVyZHIiICIkSE9NRS8ubG9jYWwvc3RhdGUvaGVyZHIvY2xpZW50IiBcCiAgICAiJEhPTUUvLmNhY2hlL2hlcmRyLXdlYiIgIiRIT01FLy5oZXJkci1wcm9qZWN0cyIKICBjb21wb3NlIHVwIC1kIC0tcmVtb3ZlLW9ycGhhbnMKICBvayAiY29udGFpbmVyIHN0YXJ0ZWQiCn0KCmxvZ19oaW50KCkgeyBlY2hvICJjZCAkRElSICYmIGRvY2tlciBjb21wb3NlIGxvZ3MiOyB9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gc3RvcApjbWRfc3RvcCgpIHsKICBjYXNlICIkTU9ERSIgaW4KICAgIG5hdGl2ZSkgY2xpIHN0b3A7IHJldHVybiAwIDs7CiAgICBkb2NrZXIpCiAgICAgIGlmIFsgLW4gIiQoY29udGFpbmVyX2RpcikiIF0gJiYgY29udGFpbmVyX291cnM7IHRoZW4KICAgICAgICBjb21wb3NlIHN0b3AKICAgICAgICBzYXkgIndoZXJkciBzdG9wcGVkIChjb250YWluZXIgJENPTlRBSU5FUikuIgogICAgICAgIHJldHVybiAwCiAgICAgIGZpCiAgICAgIDs7CiAgZXNhYwogIGlmIGFuc3dlcnM7IHRoZW4KICAgIHNheSAid2hlcmRyIG9uIHBvcnQgJFBPUlQgd2FzIG5vdCBzdGFydGVkIGJ5IHRoaXMgcGx1Z2luOiBsZWZ0IHJ1bm5pbmcuIgogIGVsc2UKICAgIHNheSAid2hlcmRyIGlzIG5vdCBydW5uaW5nLiIKICBmaQp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHN0YXR1cwpjbWRfc3RhdHVzKCkgewogIGlmIFsgIiRNT0RFIiA9ICJuYXRpdmUiIF07IHRoZW4KICAgIGNsaSBzdGF0dXMKICAgIHNheSAiICBQbHVnaW4gICBuYXRpdmUgbW9kZSwgc2V0dGluZ3MgaW4gJENPTkYiCiAgICByZXR1cm4gMAogIGZpCiAgc2F5ICJNb2RlOiAgICAke01PREU6LW5vdCBzZXQgdXB9IgogIHNheSAiRm9sZGVyOiAgJERJUiIKICBpZiBhbnN3ZXJzOyB0aGVuIHNheSAiUG9ydDogICAgJFBPUlQgYW5zd2VycyAoJFVSTCkiOyBlbHNlIHNheSAiUG9ydDogICAgJFBPUlQgZnJlZSI7IGZpCiAgaWYgWyAiJE1PREUiID0gImRvY2tlciIgXTsgdGhlbgogICAgb3duZXI9IiQoY29udGFpbmVyX2RpcikiCiAgICBpZiBbIC16ICIkb3duZXIiIF07IHRoZW4gc2F5ICJDb250YWluZXI6IG5vbmUiCiAgICBlbGlmIGNvbnRhaW5lcl9vdXJzOyB0aGVuIHNheSAiQ29udGFpbmVyOiAkQ09OVEFJTkVSICgkKGRvY2tlciBpbnNwZWN0ICIkQ09OVEFJTkVSIiAtLWZvcm1hdCAne3suU3RhdGUuU3RhdHVzfX0nIDI+L2Rldi9udWxsKSksIG1hbmFnZWQgYnkgdGhlIHBsdWdpbiIKICAgIGVsc2Ugc2F5ICJDb250YWluZXI6ICRDT05UQUlORVIsIG1hbmFnZWQgZnJvbSAkb3duZXIgKGxlZnQgYWxvbmUpIgogICAgZmkKICBmaQp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gbG9ncywgZG9jdG9yCmNtZF9sb2dzKCkgewogIGNhc2UgIiRNT0RFIiBpbgogICAgbmF0aXZlKSBjbGkgbG9ncyAtLWZvbGxvdyA7OwogICAgZG9ja2VyKSBjb21wb3NlIGxvZ3MgLS1mb2xsb3cgLS10YWlsIDEwMCA7OwogICAgKikgZGllICJ3aGVyZHIgcGx1Z2luIGlzIG5vdCBzZXQgdXA6IGluc3RhbGwgaXQgYWdhaW4gd2l0aCBoZXJkciBwbHVnaW4gaW5zdGFsbCAkU09VUkNFLiIgOzsKICBlc2FjCn0KCmNtZF9kb2N0b3IoKSB7CiAgaWYgWyAiJE1PREUiID0gIm5hdGl2ZSIgXTsgdGhlbiBjbGkgZG9jdG9yOyBlbHNlIGNtZF9zdGF0dXM7IGZpCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBvcGVuCiMgVGhlIGRlZmF1bHQgYnJvd3Nlciwgb24gYSBjb21wdXRlciB3aXRoIGEgc2NyZWVuIG9ubHk6IGBvcGVuYCBvbiBtYWNPUywKIyBgeGRnLW9wZW5gIG9uIExpbnV4IHdpdGggYSBkaXNwbGF5LiBGYWlscyAob3BlbnMgbm90aGluZykgb24gYSBoZWFkbGVzcyBzZXJ2ZXIsCiMgb3Igd2l0aCBXSEVSRFJfTk9fQlJPV1NFUj0xIChzZXQgYnkgaHR0cHM6Ly93aGVyZHIuZGV2L2luc3RhbGwgb3ZlciBTU0gpLgpvcGVuX2Jyb3dzZXIoKSB7CiAgaWYgWyAiJHtXSEVSRFJfTk9fQlJPV1NFUjotMH0iID0gIjEiIF07IHRoZW4gcmV0dXJuIDEKICBlbGlmIFsgIiQodW5hbWUgLXMpIiA9ICJEYXJ3aW4iIF0gJiYgY29tbWFuZCAtdiBvcGVuID4vZGV2L251bGwgMj4mMTsgdGhlbiBvcGVuICIkMSIKICBlbGlmIFsgLW4gIiR7RElTUExBWTotfSR7V0FZTEFORF9ESVNQTEFZOi19IiBdICYmIGNvbW1hbmQgLXYgeGRnLW9wZW4gPi9kZXYvbnVsbCAyPiYxOyB0aGVuIHhkZy1vcGVuICIkMSIgPi9kZXYvbnVsbCAyPiYxICYKICBlbHNlIHJldHVybiAxCiAgZmkKfQoKIyBUaGUgdGFpbHNjYWxlIENMSTogb24gdGhlIFBBVEgsIG9yIGluc2lkZSB0aGUgbWFjT1MgYXBwLgp0YWlsc2NhbGVfYmluKCkgewogIGlmIGNvbW1hbmQgLXYgdGFpbHNjYWxlID4vZGV2L251bGwgMj4mMTsgdGhlbiBjb21tYW5kIC12IHRhaWxzY2FsZQogIGVsaWYgWyAteCAvQXBwbGljYXRpb25zL1RhaWxzY2FsZS5hcHAvQ29udGVudHMvTWFjT1MvVGFpbHNjYWxlIF07IHRoZW4gZWNobyAvQXBwbGljYXRpb25zL1RhaWxzY2FsZS5hcHAvQ29udGVudHMvTWFjT1MvVGFpbHNjYWxlCiAgZWxzZSByZXR1cm4gMQogIGZpCn0KCiMgIjxtYWNoaW5lPi48dGFpbG5ldD4udHMubmV0Wzpwb3J0XSIgb2YgdGhlIGFkZHJlc3MgYHRhaWxzY2FsZSBzZXJ2ZWAKIyBwdWJsaXNoZXMgZm9yIHdoZXJkcidzIGxvY2FsIHBvcnQsIHJlYWQgZnJvbSBUYWlsc2NhbGUgb24gdGhpcyBtYWNoaW5lLgpzZXJ2ZWRfaG9zdCgpIHsKICB0cz0iJCh0YWlsc2NhbGVfYmluKSIgfHwgcmV0dXJuIDEKICAjICI8bmFtZT46PGh0dHBzIHBvcnQ+IiBvZiB0aGUgV2ViIGVudHJ5IHdob3NlIHByb3h5IHRhcmdldHMgb3VyIHBvcnQuCiAgaG9zdD0iJCgiJHRzIiBzZXJ2ZSBzdGF0dXMgLS1qc29uIDI+L2Rldi9udWxsIHwgdHIgJ3ssJyAnXG5cbicgfCBhd2sgLXYgcG9ydD0iJFBPUlQiICcKICAgIC8iW14iXSo6WzAtOV0rIlsgXHRdKjpbIFx0XSokLyB7IGtleSA9ICQwOyBzdWIoL15bXiJdKiIvLCAiIiwga2V5KTsgc3ViKC8iLiokLywgIiIsIGtleSkgfQogICAgLyJQcm94eSIvICYmICQwIH4gKCJcIihodHRwcz86Ly8pPygxMjdcXC4wXFwuMFxcLjF8bG9jYWxob3N0KToiIHBvcnQgIi8/XCIiKSB7IHByaW50IGtleTsgZXhpdCB9JykiCiAgWyAtbiAiJGhvc3QiIF0gfHwgcmV0dXJuIDEKICBwcmludGYgJyVzXG4nICIke2hvc3QlOjQ0M30iCn0KCiMgd2hlcmRyIGFkb3B0cyB0aGUgYWRkcmVzcyBgdGFpbHNjYWxlIHNlcnZlYCBwdWJsaXNoZXMgYnkgaXRzZWxmOiBhIGxvY2FsCiMgcmVxdWVzdCBtYWtlcyBpdCByZWFkIFRhaWxzY2FsZSBhZ2FpbiBhdCBvbmNlLiBBIGNvbnRhaW5lciBzdGFydGVkIHdpdGhvdXQKIyBUYWlsc2NhbGUncyBzb2NrZXQgKGFuIG9sZGVyIGRvY2tlci1jb21wb3NlLnltbCkgY2Fubm90IHJlYWQgaXQ6IHRoZSBhZGRyZXNzCiMgcmVhZCBoZXJlLCBvbiB0aGUgaG9zdCwgaXMgc2VudCB0byBpdCBpbnN0ZWFkLiBCb3RoIG9ubHkgd29yayBmcm9tIHRoaXMKIyBtYWNoaW5lIChzZXJ2ZXIvdXRpbHMvcGhvbmUudHMsIHBob25lQWNjZXNzKS4KYWRvcHRfYWRkcmVzcygpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxIHx8IHJldHVybiAwCiAgY3VybCAtcyAtbyAvZGV2L251bGwgLS1tYXgtdGltZSAyMCAtSCAnY29udGVudC10eXBlOiBhcHBsaWNhdGlvbi9qc29uJyBcCiAgICAtZCAie1wiYWN0aW9uXCI6XCJhZGRyZXNzXCIsXCJ1cmxcIjpcImh0dHBzOi8vJDEvXCJ9IiAiaHR0cDovLzEyNy4wLjAuMTokUE9SVC9hcGkvcGhvbmUiIDI+L2Rldi9udWxsIHx8IHRydWUKfQoKIyBEb2VzIHRoZSBwaG9uZSBhZGRyZXNzIGFuc3dlcj8gIm9rIiAod2hlcmRyLCBhbmQgaXQgYWNjZXB0cyB0aGF0IGFkZHJlc3MpLAojICJob3N0IiAod2hlcmRyIHJlZnVzZXMgdGhhdCBhZGRyZXNzKSwgb3IgIm5vbmUiLiAvYXBpL2hlYWx0aCBnb2VzIHRocm91Z2gKIyB3aGVyZHIncyBob3N0IGNoZWNrOyB0aGUgc3RhdGljIG1hbmlmZXN0IGFuc3dlcnMgZm9yIGFueSBob3N0IG5hbWUgYW5kIG9ubHkKIyByZWNvZ25pemVzIGEgd2hlcmRyIG9sZGVyIHRoYW4gdGhhdCByb3V0ZS4KcGhvbmVfcmVhY2goKSB7CiAgY29tbWFuZCAtdiBjdXJsID4vZGV2L251bGwgMj4mMSB8fCB7IGVjaG8gbm9uZTsgcmV0dXJuIDA7IH0KICBib2R5PSIkKGN1cmwgLXMgLS1tYXgtdGltZSA4ICIkezF9YXBpL2hlYWx0aCIgMj4vZGV2L251bGwgfHwgdHJ1ZSkiCiAgY2FzZSAiJGJvZHkiIGluCiAgICAqJyJuYW1lIjoid2hlcmRyIicqKSBlY2hvIG9rIDs7CiAgICAqJyJjb2RlIjoiaG9zdCInKikgZWNobyBob3N0IDs7CiAgICAqKSBpZiBjdXJsIC1mc1MgLS1tYXgtdGltZSA4ICIkezF9bWFuaWZlc3Qud2VibWFuaWZlc3QiIDI+L2Rldi9udWxsIHwgZ3JlcCAtcSB3aGVyZHI7IHRoZW4gZWNobyBvazsgZWxzZSBlY2hvIG5vbmU7IGZpIDs7CiAgZXNhYwp9CgojIFRoZSB0YWlsbmV0IGFkZHJlc3MgYHRhaWxzY2FsZSBzZXJ2ZWAgYWxyZWFkeSBwdWJsaXNoZXMgZm9yIHdoZXJkcidzIGxvY2FsCiMgcG9ydCAoaHR0cHM6Ly88bWFjaGluZT4uPHRhaWxuZXQ+LnRzLm5ldFs6cG9ydF0pLCBvbmx5IHdoZW4gaXQgYW5zd2VycyBsaWtlCiMgd2hlcmRyLiBQYXNza2V5cyBhcmUgdGllZCB0byB0aGUgYWRkcmVzczogdGhhdCBpcyB0aGUgb25lIHRvIG9wZW4uCnRhaWxuZXRfYWRkcmVzcygpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxIHx8IHJldHVybiAxCiAgaG9zdD0iJChzZXJ2ZWRfaG9zdCkiIHx8IHJldHVybiAxCiAgYWRvcHRfYWRkcmVzcyAiJGhvc3QiCiAgWyAiJChwaG9uZV9yZWFjaCAiaHR0cHM6Ly8kaG9zdC8iKSIgPSBvayBdIHx8IHJldHVybiAxCiAgcHJpbnRmICdodHRwczovLyVzXG4nICIkaG9zdCIKfQoKIyBUaGUgYWRkcmVzcyB0byBvcGVuOiB0aGUgdGFpbG5ldCBvbmUgd2hlbiBwdWJsaXNoZWQgYW5kIGFuc3dlcmluZywgZWxzZSBsb2NhbGhvc3QuCm9wZW5fYWRkcmVzcygpIHsgdGFpbG5ldF9hZGRyZXNzIHx8IHByaW50ZiAnJXNcbicgIiRVUkwiOyB9CgpjbWRfb3BlbigpIHsKICBhZGRyZXNzPSIkKG9wZW5fYWRkcmVzcykiCiAgb3Blbl9icm93c2VyICIkYWRkcmVzcyIgfHwgdHJ1ZQogIHNheSAiJGFkZHJlc3MiCn0KCiMgYGFkZHJlc3NgOiB3aGF0IGBvcGVuYCB3b3VsZCBvcGVuLCB3aXRob3V0IG9wZW5pbmcgaXQgKGh0dHBzOi8vd2hlcmRyLmRldi9pbnN0YWxsKS4KY21kX2FkZHJlc3MoKSB7IG9wZW5fYWRkcmVzczsgfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB1cGRhdGUKY21kX3VwZGF0ZSgpIHsKICBjYXNlICIkTU9ERSIgaW4KICAgIGRvY2tlcikKICAgICAgY29udGFpbmVyX291cnMgfHwgZGllICJUaGUgXCIkQ09OVEFJTkVSXCIgY29udGFpbmVyIGJlbG9uZ3MgdG8gJChjb250YWluZXJfZGlyKTogdXBkYXRlIGl0IGZyb20gdGhlcmUuIgogICAgICBjb21wb3NlIHB1bGwgLS1xdWlldAogICAgICBjbWRfc2tpbGwgcmVmcmVzaCB8fCB3YXJuICJ3aGVyZHIgc2tpbGwgcmVmcmVzaCBmYWlsZWQgKG9wdGlvbmFsKSIKICAgICAgaWYgWyAiJChkb2NrZXIgaW5zcGVjdCAiJENPTlRBSU5FUiIgLS1mb3JtYXQgJ3t7LlN0YXRlLlJ1bm5pbmd9fScgMj4vZGV2L251bGwpIiA9ICJ0cnVlIiBdOyB0aGVuCiAgICAgICAgY29tcG9zZSB1cCAtZCAtLXJlbW92ZS1vcnBoYW5zCiAgICAgICAgc2F5ICJ3aGVyZHIgdXBkYXRlZCBhbmQgcmVzdGFydGVkLiIKICAgICAgZWxzZQogICAgICAgIHNheSAid2hlcmRyIGltYWdlIHVwZGF0ZWQ7IGl0IHJ1bnMgdGhlIG5ldyB2ZXJzaW9uIGF0IHRoZSBuZXh0IHN0YXJ0LiIKICAgICAgZmkKICAgICAgOzsKICAgIG5hdGl2ZSkKICAgICAgIyBBIG5ldyBjaGVja291dCwgYSBuZXcgY29weSBpbiAkQVBQLCBhbmQgd2hlcmRyIHJlc3RhcnRlZCAoYnVpbGRfc3RhcnQpLgogICAgICBzYXkgIlVwZGF0aW5nIHRoZSB3aGVyZHIgcGx1Z2luIGZyb20gJFNPVVJDReKApiIKICAgICAgIiQoaGVyZHJfYmluKSIgcGx1Z2luIGluc3RhbGwgIiRTT1VSQ0UiIC0tcmVmIG1haW4gLS15ZXMKICAgICAgOzsKICAgICopIGRpZSAid2hlcmRyIHBsdWdpbiBpcyBub3Qgc2V0IHVwOiBpbnN0YWxsIGl0IGFnYWluIHdpdGggaGVyZHIgcGx1Z2luIGluc3RhbGwgJFNPVVJDRS4iIDs7CiAgZXNhYwp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBwaG9uZQp0YWlsbmV0X25hbWUoKSB7CiAgdHM9IiQodGFpbHNjYWxlX2JpbikiIHx8IHJldHVybiAxCiAgIyBTZWxmIGNvbWVzIGJlZm9yZSBQZWVyIGluIGB0YWlsc2NhbGUgc3RhdHVzIC0tanNvbmA6IHRoZSBmaXJzdCBETlNOYW1lIGlzIHRoaXMgbWFjaGluZS4KICAiJHRzIiBzdGF0dXMgLS1qc29uIDI+L2Rldi9udWxsIHwgc2VkIC1uICdzLy4qIkROU05hbWUiOiAqIlwoW14iXSpcKVwuIi4qL1wxL3AnIHwgaGVhZCAtbiAxCn0KCiMgVGhlIHBob25lIHNldHVwIGlzIGEgcGFnZSBvZiB0aGUgYXBwIChTZXR0aW5ncyDigLogUGhvbmUpOyBgd2hlcmRyIHBob25lYAojIHByaW50cyB0aGUgc3RhdGUgYW5kIGl0cyBsaW5rLiBEb2NrZXIgd2l0aG91dCBOb2RlLmpzOiB0aGUgc2FtZSBzdGF0ZSBmcm9tCiMgaGVyZSwgd2hlcmUgdGhlIHRhaWxzY2FsZSBjb21tYW5kIGlzOiBwdWJsaXNoZWQgb3Igbm90LCB0aGUgYWRkcmVzcyBoYW5kZWQKIyB0byB3aGVyZHIgKGFkb3B0X2FkZHJlc3MpLCBhbmQgd2hldGhlciBpdCBhbnN3ZXJzLgpjbWRfcGhvbmUoKSB7CiAgaWYgWyAiJE1PREUiID0gIm5hdGl2ZSIgXTsgdGhlbiBjbGkgcGhvbmU7IHJldHVybiAwOyBmaQogIHNheSAiIgogIHNheSAiICBXSEVSRFIgwrcgUEhPTkUgU0VUVVAiCiAgc2F5ICIiCiAgaWYgYW5zd2VyczsgdGhlbiBzYXkgIiAg4pyTIHdoZXJkciBhbnN3ZXJzIG9uICRVUkwiOyBlbHNlIHNheSAiICAhIHdoZXJkciBpcyBub3QgcnVubmluZzogcHJlc3MgUyBpbiB0aGUgd2hlcmRyIHBhbmVsIGZpcnN0LiI7IGZpCiAgcHVibGlzaD0idGFpbHNjYWxlIHNlcnZlIC0tYmcgLS1odHRwcz0kUE9SVCBodHRwOi8vMTI3LjAuMC4xOiRQT1JUIgogIG5hbWU9IiQodGFpbG5ldF9uYW1lIHx8IHRydWUpIgogIGhvc3Q9IiQoc2VydmVkX2hvc3QgfHwgdHJ1ZSkiCiAgaWYgWyAtbiAiJGhvc3QiIF07IHRoZW4KICAgIHBob25lPSJodHRwczovLyRob3N0LyIKICAgIGFkb3B0X2FkZHJlc3MgIiRob3N0IgogICAgcmVhY2g9IiQocGhvbmVfcmVhY2ggIiRwaG9uZSIpIgogICAgaWYgWyAiJHJlYWNoIiA9IG9rIF07IHRoZW4KICAgICAgc2F5ICIgIOKckyAkcGhvbmUgYW5zd2VycyIKICAgICAgc2F5ICIiCiAgICAgIGlmIGNvbW1hbmQgLXYgcXJlbmNvZGUgPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICAgICAgcXJlbmNvZGUgLXQgQU5TSVVURjggLW0gMiAiJHBob25lIgogICAgICBlbHNlCiAgICAgICAgc2F5ICIgIChJbnN0YWxsIHFyZW5jb2RlIHRvIHNob3cgYSBRUiBjb2RlIG9mICRwaG9uZSBoZXJlLikiCiAgICAgIGZpCiAgICAgIHNheSAiICBPcGVuIGl0IG9uIHRoZSBwaG9uZSwgYWRkIGl0IHRvIHRoZSBob21lIHNjcmVlbiwgdGhlbiBpbiB0aGUgYXBwOiIKICAgICAgc2F5ICIgIFNldHRpbmdzIOKGkiBFbmFibGUgbm90aWZpY2F0aW9ucywgdGhlbiBTZWN1cml0eSDihpIgRW5hYmxlIHBhc3NrZXkgbG9jay4iCiAgICBlbGlmIFsgIiRyZWFjaCIgPSBob3N0IF07IHRoZW4KICAgICAgc2F5ICIgICEgTm90IHJlYWNoYWJsZSBmcm9tIHlvdXIgcGhvbmUgeWV0OiB3aGVyZHIgYW5zd2VycyBvbiAkcGhvbmUgYnV0IHJlZnVzZXMgdGhhdCBhZGRyZXNzLiIKICAgICAgc2F5ICIgICAgUmVzdGFydCB3aGVyZHIgKFggdGhlbiBTIGluIHRoZSBwYW5lbCk6IGl0IHJlYWRzIFRhaWxzY2FsZSBhdCBzdGFydHVwLiBUaGVuIHJ1biB0aGlzIGFnYWluLiIKICAgIGVsc2UKICAgICAgc2F5ICIgICEgTm90IHJlYWNoYWJsZSBmcm9tIHlvdXIgcGhvbmUgeWV0OiAkcGhvbmUgaXMgcHVibGlzaGVkIGJ1dCBkb2VzIG5vdCBhbnN3ZXIgbGlrZSB3aGVyZHIuIgogICAgICBzYXkgIiAgICBBIG5ldyBhZGRyZXNzIGNhbiB0YWtlIGEgbWludXRlIChIVFRQUyBjZXJ0aWZpY2F0ZSk7IHRoZW4gcnVuIHRoaXMgYWdhaW4uIgogICAgZmkKICBlbGlmICEgdGFpbHNjYWxlX2JpbiA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIHNheSAiICAhIFRhaWxzY2FsZSBpcyBub3QgaW5zdGFsbGVkIG9uIHRoaXMgbWFjaGluZTogaHR0cHM6Ly90YWlsc2NhbGUuY29tL2Rvd25sb2FkIgogICAgc2F5ICIgICAgWW91ciBwaG9uZSBuZWVkcyBpdCB0b28gKHNhbWUgYWNjb3VudCksIHdpdGggSFRUUFMgY2VydGlmaWNhdGVzIGVuYWJsZWQuIgogIGVsaWYgWyAteiAiJG5hbWUiIF07IHRoZW4KICAgIHNheSAiICAhIFRhaWxzY2FsZSBpcyBub3QgY29ubmVjdGVkIG9uIHRoaXMgbWFjaGluZTogdGFpbHNjYWxlIHVwIgogIGVsc2UKICAgIHNheSAiICAhIE5vdCByZWFjaGFibGUgZnJvbSB5b3VyIHBob25lIHlldDogd2hlcmRyIGlzIG5vdCBwdWJsaXNoZWQgb24geW91ciB0YWlsbmV0LiIKICAgIHNheSAiICAgIFB1Ymxpc2ggaXQgKHByaXZhdGUsIG9ubHkgeW91ciBUYWlsc2NhbGUgZGV2aWNlcyk6IgogICAgc2F5ICIgICAgICAkcHVibGlzaCIKICAgIHNheSAiICAgIHdoZXJkciBlbmFibGVzIGh0dHBzOi8vJG5hbWU6JFBPUlQvIGJ5IGl0c2VsZjsgcnVuIHRoaXMgYWdhaW4gZm9yIGl0cyBRUiBjb2RlLiIKICBmaQogIHNheSAiIgogIHNheSAiICBHdWlkZTogaHR0cHM6Ly9naXRodWIuY29tLyRTT1VSQ0UjaW5zdGFsbC1pdC1hcy1hbi1hcHAiCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHNlcnZpY2UKY21kX3NlcnZpY2UoKSB7CiAgY2FzZSAiJHsxOi19IiBpbiBpbnN0YWxsfHVuaW5zdGFsbCkgOzsgKikgZGllICJ1c2FnZTogJDAgc2VydmljZSBpbnN0YWxsfHVuaW5zdGFsbCIgOzsgZXNhYwogIGlmIFsgIiRNT0RFIiA9ICJkb2NrZXIiIF07IHRoZW4KICAgIHNheSAid2hlcmRyIHJ1bnMgaW4gRG9ja2VyOiB0aGUgY29udGFpbmVyIGFscmVhZHkgc3RhcnRzIHdpdGggRG9ja2VyIChyZXN0YXJ0OiBhbHdheXMpLiIKICAgIHJldHVybiAwCiAgZmkKICBjbGkgc2VydmljZSAiJDEiCiAgIyBXaXRob3V0IHRoZSBzZXJ2aWNlLCB0aGUgcGx1Z2luIHJ1bnMgd2hlcmRyIGFnYWluIChhbmQgaXRzIHN0YXJ0dXAgaG9vawogICMgc3RhcnRzIGl0IHdpdGggSGVyZHIpLgogIGlmIFsgIiQxIiA9ICJ1bmluc3RhbGwiIF07IHRoZW4gY21kX3N0YXJ0OyBmaQp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBrZXkKIyBBIEhlcmRyIGtleSB0aGF0IG9wZW5zIHRoZSB3aGVyZHIgcGFuZWw6IEhlcmRyIHYxIHBsdWdpbnMgaGF2ZSBubyBtZW51LCBzbwojIHRoZSBpbnN0YWxsIGFwcGVuZHMgb25lIG1hcmtlZCBbW2tleXMuY29tbWFuZF1dIGJsb2NrIHRvIEhlcmRyJ3MKIyBjb25maWcudG9tbCwgb24gdGhlIGZpcnN0IGZyZWUga2V5IG9mIEhPVEtFWVMgKG5ldmVyIG9uZSBIZXJkciBvciB0aGUgdXNlcgojIGFscmVhZHkgYmluZHMpLiBFeGlzdGluZyBsaW5lcyBhcmUgbmV2ZXIgY2hhbmdlZDogdGhlIGJsb2NrIGlzIG9ubHkgZXZlcgojIGFwcGVuZGVkLCB0aGVuIHJlbW92ZWQgYnkgYGtleSB1bmluc3RhbGxgLiBOb3RoaW5nIGlzIGFkZGVkIHdoZW4gdGhlIHBhbmVsCiMgYWxyZWFkeSBoYXMgYSBrZXksIG9yIHdoZW4gbm8gY2FuZGlkYXRlIGlzIGZyZWUuCkhPVEtFWVM9IiR7V0hFUkRSX0hPVEtFWVM6LXByZWZpeCtpIHByZWZpeCt1IHByZWZpeCt5IHByZWZpeCttIHByZWZpeCthbHQrd30iCkhFUkRSX0NPTkZJRz0iJHtIRVJEUl9DT05GSUdfUEFUSDotJHtYREdfQ09ORklHX0hPTUU6LSRIT01FLy5jb25maWd9L2hlcmRyL2NvbmZpZy50b21sfSIKUExVR0lOX0lEPSIkKHByaW50ZiAnJXMnICIkU09VUkNFIiB8IHRyIC8gLikiClBBTkVMX0FDVElPTj0iJFBMVUdJTl9JRC5wYW5lbCIKS0VZX0JFR0lOPSIjIHdoZXJkcjoga2V5IHRoYXQgb3BlbnMgdGhlIHdoZXJkciBwYW5lbCAocmVtb3ZlIHRoaXMgYmxvY2sgdG8gdW5iaW5kIGl0KSIKS0VZX0VORD0iIyBlbmQgd2hlcmRyIgoKIyBIZXJkcidzIGRlZmF1bHQga2V5bWFwLCBmcm9tIHRoZSBydW5uaW5nIGJpbmFyeSB3aGVuIGl0IGNhbiBwcmludCBpdCwKIyBvdGhlcndpc2UgYXMgb2YgSGVyZHIgMC45LjMgKCJuYW1lPFRBQj5rZXkiIGxpbmVzKS4KZGVmYXVsdF9rZXlzKCkgewogIG91dD0iJCgiJChoZXJkcl9iaW4pIiAtLWRlZmF1bHQtY29uZmlnIDI+L2Rldi9udWxsIHwgYXdrICcKICAgIC9eXFtrZXlzXF0vIHsgayA9IDE7IG5leHQgfQogICAgayAmJiAvXlxbLyB7IGV4aXQgfQogICAgayAmJiBtYXRjaCgkMCwgL14jIFthLXpfXSsgPSAiW14iXSoiLykgewogICAgICBsaW5lID0gc3Vic3RyKCQwLCAzLCBSTEVOR1RIIC0gMik7IGVxID0gaW5kZXgobGluZSwgIiA9ICIpCiAgICAgIHYgPSBzdWJzdHIobGluZSwgZXEgKyA0KTsgc3ViKC8iJC8sICIiLCB2KQogICAgICBpZiAodiAhPSAiIikgcHJpbnRmICIlc1x0JXNcbiIsIHN1YnN0cihsaW5lLCAxLCBlcSAtIDEpLCB2CiAgICB9JykiIHx8IG91dD0iIgogIGlmIFsgLW4gIiRvdXQiIF07IHRoZW4gcHJpbnRmICclc1xuJyAiJG91dCI7IHJldHVybjsgZmkKICBmb3IgcCBpbiBoZWxwOj8gc2V0dGluZ3M6cyBkZXRhY2g6cSByZWxvYWRfY29uZmlnOnNoaWZ0K3Igb3Blbl9ub3RpZmljYXRpb25fdGFyZ2V0Om8gXAogICAgd29ya3NwYWNlX3BpY2tlcjp3IGdvdG86ZyBuZXdfd29ya3NwYWNlOnNoaWZ0K24gbmV3X3dvcmt0cmVlOnNoaWZ0K2cgcmVuYW1lX3dvcmtzcGFjZTpzaGlmdCt3IFwKICAgIGNsb3NlX3dvcmtzcGFjZTpzaGlmdCtkIG5ld190YWI6YyByZW5hbWVfdGFiOnNoaWZ0K3QgcHJldmlvdXNfdGFiOnAgbmV4dF90YWI6biBcCiAgICBjbG9zZV90YWI6c2hpZnQreCByZW5hbWVfcGFuZTpzaGlmdCtwIGVkaXRfc2Nyb2xsYmFjazplIGZvY3VzX3BhbmVfbGVmdDpoIGZvY3VzX3BhbmVfZG93bjpqIFwKICAgIGZvY3VzX3BhbmVfdXA6ayBmb2N1c19wYW5lX3JpZ2h0OmwgY3ljbGVfcGFuZV9uZXh0OnRhYiBjeWNsZV9wYW5lX3ByZXZpb3VzOnNoaWZ0K3RhYiBcCiAgICBzcGxpdF92ZXJ0aWNhbDp2IHNwbGl0X2hvcml6b250YWw6bWludXMgY2xvc2VfcGFuZTp4IHpvb206eiByZXNpemVfbW9kZTpyIHRvZ2dsZV9zaWRlYmFyOmI7IGRvCiAgICBwcmludGYgJyVzXHRwcmVmaXgrJXNcbicgIiR7cCUlOip9IiAiJHtwIyo6fSIKICBkb25lCn0KCiMgT25lIGxpbmUgb24gdGhlIGNvbmZpZzogImJvdW5kIDxrZXk+IiB3aGVuIGEgW1trZXlzLmNvbW1hbmRdXSBhbHJlYWR5IHJ1bnMKIyB0aGUgcGFuZWwsIGVsc2UgImZyZWUgPGtleT4iIChmaXJzdCBmcmVlIGNhbmRpZGF0ZSkgb3IgIm5vbmUiLiBBbHNvCiMgIm9sZCA8a2V5PiIgZm9yIGEgYmluZGluZyBvZiB0aGUgcGFuZWwncyBmb3JtZXIgYWN0aW9uIGlkICg8aWQ+LndoZXJkcikuCmtleV9zY2FuKCkgewogIGRlZmF1bHRzPSIkKGRlZmF1bHRfa2V5cykiCiAgeyBwcmludGYgJyVzXG4nICIkZGVmYXVsdHMiOyBwcmludGYgJ1wwMDFcbic7IGNhdCAiJEhFUkRSX0NPTkZJRyIgMj4vZGV2L251bGw7IH0gfCBhd2sgXAogICAgLXYgY2FuZHM9IiRIT1RLRVlTIiAtdiBhY3Rpb249IiRQQU5FTF9BQ1RJT04iIC12IG9sZD0iJFBMVUdJTl9JRC53aGVyZHIiICcKICAgIGZ1bmN0aW9uIG5vcm0oaykgewogICAgICBnc3ViKC9bIFx0XS8sICIiLCBrKQogICAgICAjICJwcmVmaXgrVyIgaXMgInByZWZpeCtzaGlmdCt3IgogICAgICBpZiAobWF0Y2goaywgL1wrW0EtWl0kLykpIGsgPSBzdWJzdHIoaywgMSwgUlNUQVJUKSAic2hpZnQrIiB0b2xvd2VyKHN1YnN0cihrLCBSU1RBUlQgKyAxKSkKICAgICAgcmV0dXJuIHRvbG93ZXIoaykKICAgIH0KICAgIGZ1bmN0aW9uIHN0cmluZ3Mocywgb3V0LCAgIG4pIHsKICAgICAgbiA9IDAKICAgICAgd2hpbGUgKG1hdGNoKHMsIC8iW14iXSoiLykpIHsgb3V0Wysrbl0gPSBzdWJzdHIocywgUlNUQVJUICsgMSwgUkxFTkdUSCAtIDIpOyBzID0gc3Vic3RyKHMsIFJTVEFSVCArIFJMRU5HVEgpIH0KICAgICAgcmV0dXJuIG4KICAgIH0KICAgIGZ1bmN0aW9uIGZsdXNoKCkgewogICAgICBpZiAoY2tleSAhPSAiIiAmJiBjbWQgPT0gYWN0aW9uICYmIGJvdW5kID09ICIiKSBib3VuZCA9IGNrZXkKICAgICAgaWYgKGNrZXkgIT0gIiIgJiYgY21kID09IG9sZCAmJiBvbGRrZXkgPT0gIiIpIG9sZGtleSA9IGNrZXkKICAgICAgY2tleSA9ICIiOyBjbWQgPSAiIgogICAgfQogICAgJDAgPT0gIlwwMDEiIHsgY29uZiA9IDE7IG5leHQgfQogICAgIWNvbmYgeyBzcGxpdCgkMCwgZCwgIlx0Iik7IGRlZltkWzFdXSA9IGRbMl07IG5leHQgfQogICAgL15bIFx0XSpcWy8gewogICAgICBmbHVzaCgpOyB0ID0gJDA7IHN1YigvIy4qLywgIiIsIHQpOyBnc3ViKC9bIFx0XS8sICIiLCB0KQogICAgICBzZWN0ID0gdCA9PSAiW2tleXNdIiA/ICJrZXlzIiA6IHQgPT0gIltba2V5cy5jb21tYW5kXV0iID8gImNtZCIgOiAiIgogICAgICBuZXh0CiAgICB9CiAgICAvXlsgXHRdKigjfCQpLyB7IG5leHQgfQogICAgewogICAgICBlcSA9IGluZGV4KCQwLCAiPSIpOyBpZiAoIWVxKSBuZXh0CiAgICAgIG5hbWUgPSBzdWJzdHIoJDAsIDEsIGVxIC0gMSk7IGdzdWIoL1sgXHRdLywgIiIsIG5hbWUpOyB2YWwgPSBzdWJzdHIoJDAsIGVxICsgMSkKICAgICAgaWYgKHNlY3QgPT0gImtleXMiKSB7CiAgICAgICAgb3ZlcltuYW1lXSA9IDE7IG4gPSBzdHJpbmdzKHZhbCwgcykKICAgICAgICBmb3IgKGkgPSAxOyBpIDw9IG47IGkrKykgdGFrZW5bbm9ybShzW2ldKV0gPSAxCiAgICAgIH0gZWxzZSBpZiAoc2VjdCA9PSAiY21kIiAmJiBzdHJpbmdzKHZhbCwgcykpIHsKICAgICAgICBpZiAobmFtZSA9PSAia2V5IikgeyBja2V5ID0gc1sxXTsgdGFrZW5bbm9ybShzWzFdKV0gPSAxIH0KICAgICAgICBpZiAobmFtZSA9PSAiY29tbWFuZCIpIGNtZCA9IHNbMV0KICAgICAgfQogICAgfQogICAgRU5EIHsKICAgICAgZmx1c2goKQogICAgICBpZiAob2xka2V5ICE9ICIiKSBwcmludCAib2xkICIgb2xka2V5CiAgICAgIGlmIChib3VuZCAhPSAiIikgeyBwcmludCAiYm91bmQgIiBib3VuZDsgZXhpdCB9CiAgICAgIGZvciAoYSBpbiBkZWYpIGlmICghKGEgaW4gb3ZlcikpIHRha2VuW25vcm0oZGVmW2FdKV0gPSAxCiAgICAgIG4gPSBzcGxpdChjYW5kcywgYywgIiAiKQogICAgICBmb3IgKGkgPSAxOyBpIDw9IG47IGkrKykgaWYgKCEobm9ybShjW2ldKSBpbiB0YWtlbikpIHsgcHJpbnQgImZyZWUgIiBjW2ldOyBleGl0IH0KICAgICAgcHJpbnQgIm5vbmUiCiAgICB9Jwp9CgojIFRoZSBrZXkgYm91bmQgdG8gdGhlIHBhbmVsLCBpZiBhbnkuCmtleV9ib3VuZCgpIHsga2V5X3NjYW4gfCBzZWQgLW4gJ3MvXmJvdW5kIC8vcCc7IH0KCiMgSGVyZHIgYXBwbGllcyBrZXliaW5kaW5ncyBvbiBgaGVyZHIgc2VydmVyIHJlbG9hZC1jb25maWdgIChubyByZXN0YXJ0KS4Ka2V5X3JlbG9hZCgpIHsKICBpZiAiJChoZXJkcl9iaW4pIiBzZXJ2ZXIgcmVsb2FkLWNvbmZpZyA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIHRlbGwgIiAgSGVyZHIgcmVsb2FkZWQgaXRzIGNvbmZpZzogbm8gcmVzdGFydCBuZWVkZWQuIgogIGVsc2UKICAgIHRlbGwgIiAgUnVuIGhlcmRyIHNlcnZlciByZWxvYWQtY29uZmlnIChvciByZXN0YXJ0IEhlcmRyKSB0byBhcHBseSBpdC4iCiAgZmkKfQoKY21kX2tleSgpIHsKICBjYXNlICIkezE6LX0iIGluCiAgICBpbnN0YWxsKQogICAgICBzY2FuPSIkKGtleV9zY2FuKSIKICAgICAgb2xkPSIkKHByaW50ZiAnJXNcbicgIiRzY2FuIiB8IHNlZCAtbiAncy9eb2xkIC8vcCcpIgogICAgICBbIC16ICIkb2xkIiBdIHx8IHdhcm4gIiRvbGQgcnVucyAkUExVR0lOX0lELndoZXJkciwgcmVuYW1lZCAkUEFORUxfQUNUSU9OOiBlZGl0IHRoYXQgbGluZSBvZiAkSEVSRFJfQ09ORklHLiIKICAgICAgcmVzPSIkKHByaW50ZiAnJXNcbicgIiRzY2FuIiB8IHNlZCAnL15vbGQgL2QnKSIKICAgICAgY2FzZSAiJHJlcyIgaW4KICAgICAgICBib3VuZFwgKikgdGVsbCAiUHJlc3MgJHtyZXMjYm91bmQgfSBpbiBIZXJkciB0byBvcGVuIHRoZSB3aGVyZHIgcGFuZWwuIiA7OwogICAgICAgIGZyZWVcICopCiAgICAgICAgICBrZXk9IiR7cmVzI2ZyZWUgfSIKICAgICAgICAgIG1rZGlyIC1wICIkKGRpcm5hbWUgIiRIRVJEUl9DT05GSUciKSIKICAgICAgICAgIGJsb2NrPSIkKHByaW50ZiAnJXNcbltba2V5cy5jb21tYW5kXV1cbmtleSA9ICIlcyJcbnR5cGUgPSAicGx1Z2luX2FjdGlvbiJcbmNvbW1hbmQgPSAiJXMiXG5kZXNjcmlwdGlvbiA9ICJ3aGVyZHIiXG4lcycgXAogICAgICAgICAgICAiJEtFWV9CRUdJTiIgIiRrZXkiICIkUEFORUxfQUNUSU9OIiAiJEtFWV9FTkQiKSIKICAgICAgICAgIHNlcD0iIgogICAgICAgICAgaWYgWyAtcyAiJEhFUkRSX0NPTkZJRyIgXTsgdGhlbgogICAgICAgICAgICBzZXA9IgoiCiAgICAgICAgICAgICMgQSBsYXN0IGxpbmUgd2l0aG91dCBpdHMgbmV3bGluZSBnZXRzIG9uZSBmaXJzdC4KICAgICAgICAgICAgWyAiJCh0YWlsIC1jIDEgIiRIRVJEUl9DT05GSUciIHwgb2QgLUFuIC1jIHwgdHIgLWQgJyAnKSIgPSAnXG4nIF0gfHwgc2VwPSIKJHNlcCIKICAgICAgICAgIGZpCiAgICAgICAgICAjIENoZWNrZWQgb24gYSBjb3B5IGZpcnN0IHdoZW4gdGhpcyBIZXJkciBjYW4gdmFsaWRhdGUgYSBjb25maWc6CiAgICAgICAgICAjIGEgY29uZmlnIEhlcmRyIHdvdWxkIHJlamVjdCBpcyBuZXZlciB3cml0dGVuLgogICAgICAgICAgdG1wPSIkSEVSRFJfQ09ORklHLndoZXJkci1jaGVjay50b21sIgogICAgICAgICAgeyBpZiBbIC1mICIkSEVSRFJfQ09ORklHIiBdOyB0aGVuIGNhdCAiJEhFUkRSX0NPTkZJRyI7IGZpOyBwcmludGYgJyVzJXNcbicgIiRzZXAiICIkYmxvY2siOyB9ID4gIiR0bXAiCiAgICAgICAgICBpZiAiJChoZXJkcl9iaW4pIiBjb25maWcgLS1oZWxwID4vZGV2L251bGwgMj4mMSAmJiAhIEhFUkRSX0NPTkZJR19QQVRIPSIkdG1wIiAiJChoZXJkcl9iaW4pIiBjb25maWcgY2hlY2sgPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICAgICAgICAgIHJtIC1mICIkdG1wIgogICAgICAgICAgICB3YXJuICJubyBIZXJkciBrZXkgYWRkZWQ6ICRIRVJEUl9DT05GSUcgd291bGQgbm90IHZhbGlkYXRlIHdpdGggaXQgKGhlcmRyIGNvbmZpZyBjaGVjaykuIgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgICAgZmkKICAgICAgICAgIHJtIC1mICIkdG1wIgogICAgICAgICAgcHJpbnRmICclcyVzXG4nICIkc2VwIiAiJGJsb2NrIiA+PiAiJEhFUkRSX0NPTkZJRyIKICAgICAgICAgIG9rICJIZXJkciBrZXkgJGtleSBhZGRlZCB0byAkSEVSRFJfQ09ORklHIgogICAgICAgICAgdGVsbCAiUHJlc3MgJGtleSBpbiBIZXJkciB0byBvcGVuIHRoZSB3aGVyZHIgcGFuZWwuIgogICAgICAgICAga2V5X3JlbG9hZAogICAgICAgICAgOzsKICAgICAgICAqKSB3YXJuICJubyBIZXJkciBrZXkgYWRkZWQ6ICRIT1RLRVlTIGFyZSBhbGwgdGFrZW4uIEJpbmQgb25lIHRvICRQQU5FTF9BQ1RJT04gKHR5cGUgPSBcInBsdWdpbl9hY3Rpb25cIikgaW4gJEhFUkRSX0NPTkZJRy4iIDs7CiAgICAgIGVzYWMKICAgICAgOzsKICAgIHVuaW5zdGFsbCkKICAgICAgaWYgISBncmVwIC1xeEYgIiRLRVlfQkVHSU4iICIkSEVSRFJfQ09ORklHIiAyPi9kZXYvbnVsbDsgdGhlbiBvayAibm8gd2hlcmRyIGtleSBpbiAkSEVSRFJfQ09ORklHIjsgcmV0dXJuIDA7IGZpCiAgICAgICMgRHJvcHMgdGhlIG1hcmtlZCBibG9jayBhbmQgdGhlIGJsYW5rIGxpbmUgd3JpdHRlbiBiZWZvcmUgaXQuCiAgICAgIHRtcD0iJEhFUkRSX0NPTkZJRy53aGVyZHItdG1wIgogICAgICBhd2sgLXYgYj0iJEtFWV9CRUdJTiIgLXYgZT0iJEtFWV9FTkQiICcKICAgICAgICAkMCA9PSBiIHsgc2tpcCA9IDE7IGlmIChibGFuaykgYmxhbmstLTsgbmV4dCB9CiAgICAgICAgc2tpcCB7IGlmICgkMCA9PSBlKSBza2lwID0gMDsgbmV4dCB9CiAgICAgICAgJDAgPT0gIiIgeyBibGFuaysrOyBuZXh0IH0KICAgICAgICB7IHdoaWxlIChibGFuaykgeyBwcmludCAiIjsgYmxhbmstLSB9IHByaW50IH0KICAgICAgICBFTkQgeyB3aGlsZSAoYmxhbmspIHsgcHJpbnQgIiI7IGJsYW5rLS0gfSB9JyAiJEhFUkRSX0NPTkZJRyIgPiAiJHRtcCIKICAgICAgIyBSZXdyaXR0ZW4gaW4gcGxhY2U6IHRoZSBmaWxlIGtlZXBzIGl0cyBvd25lciBhbmQgbW9kZS4KICAgICAgY2F0ICIkdG1wIiA+ICIkSEVSRFJfQ09ORklHIiAmJiBybSAtZiAiJHRtcCIKICAgICAgb2sgIndoZXJkciBrZXkgcmVtb3ZlZCBmcm9tICRIRVJEUl9DT05GSUciCiAgICAgIGtleV9yZWxvYWQKICAgICAgOzsKICAgIHN0YXR1cykgYj0iJChrZXlfYm91bmQpIjsgaWYgWyAtbiAiJGIiIF07IHRoZW4gc2F5ICIkYiI7IGVsc2Ugc2F5ICJub25lIjsgZmkgOzsKICAgICopIGRpZSAidXNhZ2U6ICQwIGtleSBpbnN0YWxsfHVuaW5zdGFsbHxzdGF0dXMiIDs7CiAgZXNhYwp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBwYW5lbAojIFRoZSAicGFuZWwiIGFjdGlvbjogb25lIHBvcHVwIHdpdGggdGhlIHN0YXRlLCBPcGVuIHdoZXJkciwgU2V0IHVwIG15IHBob25lCiMgKG9wZW5zIFNldHRpbmdzIOKAuiBQaG9uZSkgYW5kIHRoZSBvdGhlciBjb21tYW5kcyAoYmluL2xpYi9wYW5lbC5tanMpLAojIGRyaXZpbmcgdGhpcyBzY3JpcHQuCmNtZF9wYW5lbCgpIHsKICBjb250cm9sPSIkKHByaW50ZiAnWyJzaCIsIiVzIl0nICIkKHByaW50ZiAnJXMnICIkUk9PVC9zY3JpcHRzL2hlcmRyLXBsdWdpbi5zaCIgfCBzZWQgJ3MvW1xcIl0vXFwmL2cnKSIpIgogIGlmIFsgIiRNT0RFIiA9ICJuYXRpdmUiIF0gfHwgeyBbIC1uICIkTU9ERSIgXSAmJiBSVU5USU1FPSIkKGZpbmRfcnVudGltZSkiOyB9OyB0aGVuCiAgICBXSEVSRFJfQ09OVFJPTD0iJGNvbnRyb2wiIFdIRVJEUl9NT0RFPSIkTU9ERSIgV0hFUkRSX0hPVEtFWT0iJChrZXlfYm91bmQpIiBjbGkgcGFuZWwKICBlbGlmIFsgLW4gIiRNT0RFIiBdOyB0aGVuCiAgICBzaF9wYW5lbAogIGVsc2UKICAgIGRpZSAid2hlcmRyIHBsdWdpbiBpcyBub3Qgc2V0IHVwICgkQ09ORiBpcyBtaXNzaW5nKTogaW5zdGFsbCBpdCBhZ2FpbiB3aXRoIGhlcmRyIHBsdWdpbiBpbnN0YWxsICRTT1VSQ0UgLS15ZXMuIgogIGZpCn0KCiMgRG9ja2VyIG1vZGUgd2l0aG91dCBOb2RlLmpzOiB0aGUgc2FtZSBrZXlzLCB3aXRob3V0IHRoZSBRUiBjb2RlLgpzaF9wYW5lbCgpIHsKICBzYXZlZD0iJChzdHR5IC1nKSIKICB0cmFwICdzdHR5ICIkc2F2ZWQiJyBFWElUCiAgd2hpbGUgOjsgZG8KICAgIHByaW50ZiAnXDAzM1tIXDAzM1sySlxuICBXSEVSRFJcblxuJwogICAgKCBjbWRfc3RhdHVzICkgfHwgdHJ1ZQogICAgcHJpbnRmICdcbiAgUyBzdGFydCAgWCBzdG9wICBSIHJlc3RhcnQgIE8gb3BlbiAgTCBsb2cgIFUgdXBkYXRlICBQIHBob25lICBRIHF1aXRcbicKICAgIHByaW50ZiAnICBSZW1vdmU6IFgsIHRoZW4gc2ggJXMga2V5IHVuaW5zdGFsbCwgdGhlbiBoZXJkciBwbHVnaW4gdW5pbnN0YWxsICVzICYmIHJtIC1yZiAlc1xuJyAiJFJPT1Qvc2NyaXB0cy9oZXJkci1wbHVnaW4uc2giICIkUExVR0lOX0lEIiAiJERJUiIKICAgIHN0dHkgLWljYW5vbiAtZWNobyBtaW4gMCB0aW1lIDUwCiAgICBrPSIkKGRkIGJzPTEgY291bnQ9MSAyPi9kZXYvbnVsbCB8fCB0cnVlKSIKICAgIHN0dHkgIiRzYXZlZCIKICAgIGNhc2UgIiRrIiBpbgogICAgICBzfFMpIGFjdD1zdGFydCA7OyB4fFgpIGFjdD1zdG9wIDs7IHJ8UikgYWN0PXJlc3RhcnQgOzsgb3xPKSBhY3Q9b3BlbiA7OwogICAgICBsfEwpIGFjdD1sb2dzIDs7IHV8VSkgYWN0PXVwZGF0ZSA7OyBwfFApIGFjdD1waG9uZSA7OyBxfFEpIGJyZWFrIDs7CiAgICAgICopIGNvbnRpbnVlIDs7CiAgICBlc2FjCiAgICBwcmludGYgJ1wwMzNbSFwwMzNbMkpcbicKICAgICggdHJhcCAtIElOVDsgImNtZF8kYWN0IiApIHx8IHRydWUKICAgIHByaW50ZiAnXG4gIFByZXNzIEVudGVyIHRvIGdvIGJhY2suICcKICAgIHJlYWQgLXIgXyB8fCB0cnVlCiAgZG9uZQp9CgpjbWRfcmVzdGFydCgpIHsgY21kX3N0b3A7IGNtZF9zdGFydDsgfQoKY2FzZSAiJHsxOi19IiBpbgogIGJ1aWxkKSBjbWRfYnVpbGQgOzsKICBwYW5lbCkgY21kX3BhbmVsIDs7CiAgc3RhcnR8c3RvcHxyZXN0YXJ0fHN0YXR1c3xvcGVufGFkZHJlc3N8dXBkYXRlfHBob25lfGxvZ3N8ZG9jdG9yKSAiY21kXyQxIiA7OwogIHNlcnZpY2UpIGNtZF9zZXJ2aWNlICIkezI6LX0iIDs7CiAgc2tpbGwpIGNtZF9za2lsbCAiJHsyOi19IiA7OwogIGtleSkgY21kX2tleSAiJHsyOi19IiA7OwogICopIGRpZSAidXNhZ2U6ICQwIGJ1aWxkfHBhbmVsfHN0YXJ0fHN0b3B8cmVzdGFydHxzdGF0dXN8b3BlbnxhZGRyZXNzfHVwZGF0ZXxwaG9uZXxsb2dzfGRvY3RvcnxzZXJ2aWNlIGluc3RhbGx8dW5pbnN0YWxsfHNraWxsIGluc3RhbGx8dW5pbnN0YWxsfGtleSBpbnN0YWxsfHVuaW5zdGFsbHxzdGF0dXMiIDs7CmVzYWMK");
|
|
4
|
+
const herdrPlugin = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyIGFzIGEgSGVyZHIgcGx1Z2luIChoZXJkci1wbHVnaW4udG9tbCk6IGJ1aWxkIChpbnN0YWxsICsgZmlyc3Qgc3RhcnQpLAojIHRoZSBwYW5lbCwgc3RhcnQsIHN0b3AsIHN0YXR1cywgb3BlbiwgdXBkYXRlLCBzZXJ2aWNlLCBza2lsbCwga2V5LgojCiMgICBoZXJkciBwbHVnaW4gaW5zdGFsbCA8b3duZXI+L3doZXJkcgojCiMgSGVyZHIgYnVpbGRzIGEgcGx1Z2luIGluIGEgdGVtcG9yYXJ5IGZvbGRlciwgdGhlbiBtb3ZlcyBpdDogYSBzZXJ2ZXIgc3RhcnRlZAojIGZyb20gdGhlIGNoZWNrb3V0IGR1cmluZyB0aGUgYnVpbGQgd291bGQgbG9zZSBpdHMgZmlsZXMuICRXSEVSRFJfRElSL2FwcAojIHN0YXlzIHB1dCwgYWNyb3NzIHBsdWdpbiB1cGRhdGVzIHRvbywgc28gdGhlIGJ1aWxkIGNhbiBzdGFydCB3aGVyZHIgYW5kIGEKIyBsb2dpbiBzZXJ2aWNlIGNhbiBwb2ludCBhdCBpdC4KIyBTYWZldHkgcnVsZXM6CiMgICAtIG5vdGhpbmcgZ2xvYmFsIGlzIGluc3RhbGxlZCwgbm8gc3VkbzsgZmlsZXMgYXJlIG9ubHkgd3JpdHRlbiB0byB0aGUKIyAgICAgcGx1Z2luIGZvbGRlciBhbmQgJFdIRVJEUl9ESVIgKGRlZmF1bHQgfi93aGVyZHIpLCBhbmQgdGhlCiMgICAgIGxvZ2luIHNlcnZpY2Ugb25seSB3aGVuIGFza2VkIChrZXkgQSBvZiB0aGUgcGFuZWwpLCBwbHVzIGEgIndoZXJkciIKIyAgICAgbGluayBpbiB0aGUgYWdlbnRzJyB1c2VyIHNraWxsIGZvbGRlcnMgKHNlZSBjbWRfc2tpbGwpLCBwbHVzIG9uZSBtYXJrZWQKIyAgICAgYmxvY2sgYXBwZW5kZWQgdG8gSGVyZHIncyBjb25maWcudG9tbDogdGhlIGtleSB0aGF0IG9wZW5zIHRoZSBwYW5lbAojICAgICAoc2VlIGNtZF9rZXkpOwojICAgLSB0aGUgaW5zdGFsbCBzdGFydHMgd2hlcmRyLCBhbmQgSGVyZHIncyBzdGFydHVwIGhvb2sgc3RhcnRzIGl0IGFnYWluLAojICAgICBidXQgb25seSB3aGVuIG5vdGhpbmcgYW5zd2VycyBvbiB0aGUgcG9ydDogYSB3aGVyZHIgc3RhcnRlZCBhbm90aGVyIHdheQojICAgICAoc3lzdGVtZCwgYnkgaGFuZCkgaXMgbmV2ZXIgdG91Y2hlZCwgbm8gc2Vjb25kIHdoZXJkciBpcyBzdGFydGVkOwojICAgLSBzdG9wIG9ubHkgc3RvcHMgd2hhdCB0aGlzIHBsdWdpbiBzdGFydGVkIChpdHMgcGlkIG9yIGl0cyBsb2dpbiBzZXJ2aWNlKS4KIwojIFVuaW5zdGFsbDogSGVyZHIgaGFzIG5vIHVuaW5zdGFsbCBob29rLiBTdG9wIHdoZXJkciAoYW5kIHJlbW92ZSB0aGUgbG9naW4KIyBzZXJ2aWNlKSBmcm9tIHRoZSBwYW5lbCBmaXJzdCwgdGhlbjoKIyAgIHNoIHNjcmlwdHMvaGVyZHItcGx1Z2luLnNoIHNraWxsIHVuaW5zdGFsbCAgIChpbiB0aGUgcGx1Z2luIGZvbGRlcikKIyAgIHNoIHNjcmlwdHMvaGVyZHItcGx1Z2luLnNoIGtleSB1bmluc3RhbGwgICAgICh0aGUgSGVyZHIga2V5IG9mIHRoZSBwYW5lbCkKIyAgIGhlcmRyIHBsdWdpbiB1bmluc3RhbGwgPG93bmVyPi53aGVyZHIgJiYgcm0gLXJmIH4vd2hlcmRyCiMKIyBTZXR0aW5ncyAoJFdIRVJEUl9ESVIvcGx1Z2luLmVudiwgb3IgdGhlIGVudmlyb25tZW50KToKIyAgIFdIRVJEUl9QT1JUICBsb2NhbCBwb3J0ICAgICAgICAgICAgICAoZGVmYXVsdDogNzY4MykKIyAgIEFQUF9VUkwgICAgICBwcml2YXRlIEhUVFBTIGFkZHJlc3MKIyAgIFdIRVJEUl9SVU5USU1FICBhYnNvbHV0ZSBwYXRoIG9mIG5vZGUgLyBidW4gKGZvdW5kIGF0IGluc3RhbGwpCgpzZXQgLWV1CgpST09UPSIkKGNkICIkKGRpcm5hbWUgIiQwIikvLi4iICYmIHB3ZCAtUCkiCiMgQnVpbGQgY29tbWFuZHMgZ2V0IG5vIHBsdWdpbiBlbnZpcm9ubWVudDogdGhlIGZvbGRlciBjaG9zZW4gYXQgaW5zdGFsbAojIHRpbWUgaXMgcmVtZW1iZXJlZCBpbiB0aGUgcGx1Z2luIGNoZWNrb3V0IGZvciB0aGUgcnVudGltZSBjb21tYW5kcy4KaWYgWyAteiAiJHtXSEVSRFJfRElSOi19IiBdICYmIFsgLWYgIiRST09ULy53aGVyZHItZGlyIiBdOyB0aGVuCiAgV0hFUkRSX0RJUj0iJChjYXQgIiRST09ULy53aGVyZHItZGlyIikiCmZpCkRJUj0iJHtXSEVSRFJfRElSOi0kSE9NRS93aGVyZHJ9IgpjYXNlICIkRElSIiBpbiAvKikgOzsgKikgRElSPSIkUFdELyRESVIiIDs7IGVzYWMKQ09ORj0iJERJUi9wbHVnaW4uZW52IgojIE5hdGl2ZSBtb2RlOiB0aGUgaW5zdGFsbGVkIGNvcHkgb2Ygd2hlcmRyIChiaW4gKyBidWlsdCBzZXJ2ZXIpLgpBUFA9IiRESVIvYXBwIgojIEdpdEh1YiBzb3VyY2Ugb2YgdGhpcyBwbHVnaW46IGl0cyBtYW5pZmVzdCBpZCB3aXRoICIvIiBmb3IgIi4iIChvd25lci53aGVyZHIpLgpTT1VSQ0U9IiQoc2VkIC1uICdzL15pZCA9ICJcKC4qXCkiJC9cMS9wJyAiJFJPT1QvaGVyZHItcGx1Z2luLnRvbWwiIHwgaGVhZCAtbiAxIHwgdHIgLiAvKSIKIyBUaGUgZW52aXJvbm1lbnQgd2lucyBvdmVyIHBsdWdpbi5lbnYuCkVOVl9QT1JUPSIke1dIRVJEUl9QT1JUOi19IiBFTlZfQVBQX1VSTD0iJHtBUFBfVVJMOi19IiBFTlZfUlVOVElNRT0iJHtXSEVSRFJfUlVOVElNRTotfSIKaWYgWyAtZiAiJENPTkYiIF07IHRoZW4KICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzEwOTAKICAuICIkQ09ORiIKZmkKTEVHQUNZX01PREU9IiR7V0hFUkRSX01PREU6LX0iClBPUlQ9IiR7RU5WX1BPUlQ6LSR7V0hFUkRSX1BPUlQ6LTc2ODN9fSIKQVBQX1VSTD0iJHtFTlZfQVBQX1VSTDotJHtBUFBfVVJMOi19fSIKIyBOYXRpdmUgbW9kZTogYWJzb2x1dGUgcGF0aCBvZiB0aGUgbm9kZSAob3IgYnVuKSB0aGF0IHJ1bnMgdGhlIHNlcnZlci4gSGVyZHIKIyBydW5zIGFjdGlvbnMgd2l0aCBpdHMgc2VydmVyJ3MgUEFUSCwgd2hpY2ggb2Z0ZW4gbGFja3MgbnZtIC8gbiAvIGZubSBmb2xkZXJzLgpSVU5USU1FPSIke0VOVl9SVU5USU1FOi0ke1dIRVJEUl9SVU5USU1FOi19fSIKVVJMPSJodHRwOi8vbG9jYWxob3N0OiRQT1JUIgoKc2F5KCkgeyBwcmludGYgJyVzXG4nICIkKiI7IH0Kb2soKSB7IHByaW50ZiAnICDinJMgJXNcbicgIiQqIjsgfQp3YXJuKCkgeyBwcmludGYgJyAgISAlc1xuJyAiJCoiID4mMjsgfQpkaWUoKSB7IHByaW50ZiAnICDinJcgJXNcbicgIiQqIiA+JjI7IGV4aXQgMTsgfQoKIyBBbnkgSFRUUCBhbnN3ZXIgY291bnRzIChhIGxvY2tlZCB3aGVyZHIgYW5zd2VycyA0MDEpOiB0aGUgcG9ydCBpcyB0YWtlbi4KYW5zd2VycygpIHsKICBpZiBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICBjb2RlPSIkKGN1cmwgLXMgLW8gL2Rldi9udWxsIC0tbWF4LXRpbWUgMiAtdyAnJXtodHRwX2NvZGV9JyAiaHR0cDovLzEyNy4wLjAuMTokUE9SVC8iIDI+L2Rldi9udWxsIHx8IHRydWUpIgogICAgWyAtbiAiJGNvZGUiIF0gJiYgWyAiJGNvZGUiICE9ICIwMDAiIF0KICBlbGlmIGNvbW1hbmQgLXYgbmMgPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICBuYyAteiAxMjcuMC4wLjEgIiRQT1JUIiA+L2Rldi9udWxsIDI+JjEKICBlbHNlCiAgICBkaWUgImN1cmwgb3IgbmMgaXMgbmVlZGVkIHRvIGNoZWNrIHBvcnQgJFBPUlQuIgogIGZpCn0KCiMgTWFqb3IgdmVyc2lvbiBvZiBhIG5vZGUgYmluYXJ5LCAwIHdoZW4gaXQgaXMgbm90IG9uZS4Kbm9kZV9tYWpvcigpIHsKICAiJDEiIC1wICdwcm9jZXNzLnZlcnNpb25zLm5vZGUuc3BsaXQoIi4iKVswXScgMj4vZGV2L251bGwgfHwgZWNobyAwCn0KCiMgQSB1c2FibGUgcnVudGltZTogTm9kZS5qcyAyMiBvciBuZXdlciwgb3IgQnVuIChpdCBydW5zIHRoZSBidWlsdCBzZXJ2ZXIgdG9vKS4KcnVudGltZV9vaygpIHsKICBbIC1uICIkMSIgXSAmJiBbIC14ICIkMSIgXSAmJiBbICEgLWQgIiQxIiBdIHx8IHJldHVybiAxCiAgY2FzZSAiJChiYXNlbmFtZSAiJDEiKSIgaW4KICAgIGJ1bikgIiQxIiAtLXZlcnNpb24gPi9kZXYvbnVsbCAyPiYxIDs7CiAgICAqKSBbICIkKG5vZGVfbWFqb3IgIiQxIikiIC1nZSAyMiBdIDI+L2Rldi9udWxsIDs7CiAgZXNhYwp9CgojIEFic29sdXRlIHBhdGggb2YgdGhlIHJ1bnRpbWU6IFdIRVJEUl9SVU5USU1FLCB0aGVuIG5vZGUgb24gdGhlIFBBVEgsIHRoZW4gdGhlCiMgdXN1YWwgaW5zdGFsbCBmb2xkZXJzIChuLCBudm0sIFZvbHRhLCBmbm0sIGFzZGYsIEhvbWVicmV3KSwgdGhlbiBCdW4uCiMgUHJpbnRzIG5vdGhpbmcgYW5kIGZhaWxzIHdoZW4gbm9uZSBpcyBmb3VuZC4KZmluZF9ydW50aW1lKCkgewogIGZvciBjIGluICIkUlVOVElNRSIgIiQoY29tbWFuZCAtdiBub2RlIDI+L2Rldi9udWxsIHx8IHRydWUpIiBcCiAgICAiJEhPTUUvLm4vYmluL25vZGUiICIke05fUFJFRklYOiskTl9QUkVGSVgvYmluL25vZGV9IiBcCiAgICAkKGxzIC1kICIkSE9NRSIvLm52bS92ZXJzaW9ucy9ub2RlL3YqL2Jpbi9ub2RlIDI+L2Rldi9udWxsIHwgc29ydCAtciAtVikgXAogICAgIiRIT01FLy52b2x0YS9iaW4vbm9kZSIgXAogICAgJChscyAtZCAiJEhPTUUiLy5sb2NhbC9zaGFyZS9mbm0vbm9kZS12ZXJzaW9ucy8qL2luc3RhbGxhdGlvbi9iaW4vbm9kZSAiJEhPTUUiLy5mbm0vbm9kZS12ZXJzaW9ucy8qL2luc3RhbGxhdGlvbi9iaW4vbm9kZSAyPi9kZXYvbnVsbCB8IHNvcnQgLXIgLVYpIFwKICAgICIkSE9NRS8uYXNkZi9zaGltcy9ub2RlIiAvb3B0L2hvbWVicmV3L2Jpbi9ub2RlIC91c3IvbG9jYWwvYmluL25vZGUgL3Vzci9iaW4vbm9kZSBcCiAgICAiJChjb21tYW5kIC12IGJ1biAyPi9kZXYvbnVsbCB8fCB0cnVlKSIgIiRIT01FLy5idW4vYmluL2J1biIgL29wdC9ob21lYnJldy9iaW4vYnVuIC91c3IvbG9jYWwvYmluL2J1bjsgZG8KICAgIGlmIHJ1bnRpbWVfb2sgIiRjIjsgdGhlbiBlY2hvICIkYyI7IHJldHVybiAwOyBmaQogIGRvbmUKICByZXR1cm4gMQp9CgpSVU5USU1FX0hFTFA9Ik5vZGUuanMgMjIgb3IgbmV3ZXIgKG9yIEJ1bikgaXMgcmVxdWlyZWQgdG8gcnVuIHdoZXJkci4KICAgICBJbnN0YWxsIGl0IGZyb20gaHR0cHM6Ly9ub2RlanMub3JnLCBvciBzZXQgaXRzIGFic29sdXRlIHBhdGggaW4gJENPTkY6CiAgICAgICBXSEVSRFJfUlVOVElNRT0vcGF0aC90by9ub2RlIgoKaGVyZHJfYmluKCkgewogIGlmIFsgLW4gIiR7SEVSRFJfQklOX1BBVEg6LX0iIF07IHRoZW4gZWNobyAiJEhFUkRSX0JJTl9QQVRIIgogIGVsaWYgWyAteCAiJEhPTUUvLmxvY2FsL2Jpbi9oZXJkciIgXTsgdGhlbiBlY2hvICIkSE9NRS8ubG9jYWwvYmluL2hlcmRyIgogIGVsc2UgY29tbWFuZCAtdiBoZXJkciAyPi9kZXYvbnVsbCB8fCBlY2hvIGhlcmRyCiAgZmkKfQoKIyBUaGUgY29tbWFuZHMgb2YgdGhlIG5hdGl2ZSBtb2RlOiB0aGUgaW5zdGFsbGVkIGNvcHksIG9yIHRoZSBjaGVja291dCBpdHNlbGYKIyAoYSBsaW5rZWQgcGx1Z2luIGJ1aWx0IGJ5IGhhbmQsIG9yIGEgcGx1Z2luIGluc3RhbGxlZCBiZWZvcmUgJEFQUCBleGlzdGVkKS4KY2xpX3Jvb3QoKSB7CiAgaWYgWyAtZiAiJEFQUC9iaW4vd2hlcmRyLm1qcyIgXSAmJiBbIC1mICIkQVBQLy5vdXRwdXQvc2VydmVyL2luZGV4Lm1qcyIgXTsgdGhlbiBlY2hvICIkQVBQIjsgZWxzZSBlY2hvICIkUk9PVCI7IGZpCn0KCiMgVGhlIHBlcnNvbiBydW5uaW5nIGBoZXJkciBwbHVnaW4gaW5zdGFsbGAgc2VlcyBvbmx5IEhlcmRyJ3Mgb3duIGxpbmVzOiB0aGUKIyBvdXRwdXQgb2YgYnVpbGQgY29tbWFuZHMgaXMgY2FwdHVyZWQuIEltcG9ydGFudCBsaW5lcyBhbHNvIGdvIHRvIHRoZSB0ZXJtaW5hbC4KdGVsbCgpIHsKICBwcmludGYgJyVzXG4nICIkKiIKICB7IHByaW50ZiAnJXNcbicgIiQqIiA+IC9kZXYvdHR5OyB9IDI+L2Rldi9udWxsIHx8IHRydWUKfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gYnVpbGQKY21kX2J1aWxkKCkgewogIHRlbGwgIndoZXJkcjogaW5zdGFsbGluZyBpbiAkRElSIgogICMgRmlyc3QgaW5zdGFsbCAobm8gcGx1Z2luLmVudiB5ZXQpOiB0aGUgYnJvd3NlciBvcGVucyBvbiB0aGUgc2V0dXAgZ3VpZGUKICAjIG9uY2Ugd2hlcmRyIHJ1bnMuIFVwZGF0ZXMga2VlcCBwbHVnaW4uZW52IGFuZCBvcGVuIG5vdGhpbmcuCiAgRklSU1RfSU5TVEFMTD0wCiAgWyAtZiAiJENPTkYiIF0gfHwgRklSU1RfSU5TVEFMTD0xCiAgbWtkaXIgLXAgIiRESVIiCiAgcHJpbnRmICclc1xuJyAiJERJUiIgPiAiJFJPT1QvLndoZXJkci1kaXIiCgogIGlmIFsgIiRMRUdBQ1lfTU9ERSIgPSBkb2NrZXIgXTsgdGhlbgogICAgdGVsbCAid2hlcmRyIDIuMCByZW1vdmVzIERvY2tlciBzdXBwb3J0OiBzd2l0Y2hpbmcgdGhpcyBwbHVnaW4gdG8gdGhlIG5hdGl2ZSBzZXJ2aWNlLiIKICAgIHRlbGwgIlN0b3AgdGhlIG9sZCAxLnggaW5zdGFuY2UgYmVmb3JlIHN0YXJ0aW5nIHRoZSBuYXRpdmUgc2VydmljZTsga2VlcCBpdHMgZGF0YSBmb2xkZXIuIgogICAgdGVsbCAiTWlncmF0aW9uOiBodHRwczovL2dpdGh1Yi5jb20vJFNPVVJDRS9ibG9iL21haW4vZG9jcy9taWdyYXRlLWZyb20tMS54LWRvY2tlci5tZCIKICBmaQogIGJ1aWxkX25hdGl2ZQogICMgV3JpdHRlbiBsYXN0OiBhIGZhaWxlZCBidWlsZCBrZWVwcyBubyBoYWxmLW1hZGUgY2hvaWNlLiBSZXdyaXR0ZW4gb24gZWFjaAogICMgaW5zdGFsbCBmcm9tIHRoZSBtZXJnZWQgc2V0dGluZ3MgKGVudmlyb25tZW50IG92ZXIgdGhlIHByZXZpb3VzIGZpbGUpLgogIHdyaXRlX2NvbmYKICBvayAicGx1Z2luLmVudiB3cml0dGVuIChuYXRpdmUgc2VydmljZSkiCiAgKCBjbWRfc2tpbGwgcmVmcmVzaCApIHx8IHdhcm4gIndoZXJkciBza2lsbCBub3QgbGlua2VkIChvcHRpb25hbCk6IHJ1biAkMCBza2lsbCBpbnN0YWxsIgogICggY21kX2tleSBpbnN0YWxsICkgfHwgd2FybiAibm8gSGVyZHIga2V5IGZvciB0aGUgcGFuZWwgKG9wdGlvbmFsKTogcnVuICQwIGtleSBpbnN0YWxsIgogIGJ1aWxkX3N0YXJ0Cn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHNraWxsCiMgSW5zdGFsbGF0aW9uIGlzIHNoYXJlZCB3aXRoIG5wbSAvIEhvbWVicmV3LgpjbWRfc2tpbGwoKSB7CiAgY2FzZSAiJHsxOi19IiBpbgogICAgcmVmcmVzaHxpbnN0YWxsKQogICAgICBXSEVSRFJfRElSPSIkRElSIiBzaCAiJFJPT1QvYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIiAiJDEiICIkUk9PVCIKICAgICAgOzsKICAgIHVuaW5zdGFsbCkgV0hFUkRSX0RJUj0iJERJUiIgc2ggIiRST09UL2Jpbi9saWIvaW5zdGFsbC1za2lsbC5zaCIgdW5pbnN0YWxsICIkUk9PVCIgOzsKICAgICopIGRpZSAidXNhZ2U6ICQwIHNraWxsIGluc3RhbGx8dW5pbnN0YWxsIiA7OwogIGVzYWMKfQoKIyBMYXN0IHN0ZXAgb2YgdGhlIGluc3RhbGw6IHN0YXJ0IHdoZXJkciAob3IgcmVzdGFydCB0aGUgb25lIHRoaXMgcGx1Z2luCiMgcnVucywgb24gYW4gdXBkYXRlKS4gTmV2ZXIgZmFpbHMgdGhlIGluc3RhbGw6IGEgd2hlcmRyIHRoYXQgY2Fubm90IHN0YXJ0IGlzCiMgcmVwb3J0ZWQgd2l0aCB3aGF0IHRvIGRvLCB0aGUgcGx1Z2luIHN0YXlzIGluc3RhbGxlZC4KYnVpbGRfc3RhcnQoKSB7CiAgc2V0ICtlCiAgb3V0PSIkKCAoY21kX3N0YXJ0KSAyPiYxICkiCiAgY29kZT0kPwogIHNldCAtZQogIHByaW50ZiAnJXNcbicgIiRvdXQiCiAgaWYgWyAiJGNvZGUiIC1lcSAwIF0gJiYgYW5zd2VyczsgdGhlbgogICAgIyBodHRwczovL3doZXJkci5kZXYvaW5zdGFsbCBwcmludHMgaXRzIG93biBzdW1tYXJ5IChXSEVSRFJfSU5TVEFMTEVSPTEpLgogICAgcXVpZXQ9MAogICAgWyAiJHtXSEVSRFJfSU5TVEFMTEVSOi0wfSIgPSAxIF0gJiYgcXVpZXQ9MQogICAgWyAiJHF1aWV0IiA9IDEgXSB8fCB0ZWxsICIiCiAgICBbICIkcXVpZXQiID0gMSBdIHx8IHRlbGwgIuKckyB3aGVyZHIgaXMgcnVubmluZyDihpIgJFVSTCIKICAgIGlmIFsgIiRxdWlldCIgIT0gMSBdOyB0aGVuCiAgICAgIGtleT0iJChrZXlfYm91bmQpIgogICAgICBpZiBbIC1uICIka2V5IiBdOyB0aGVuIHRlbGwgIiAgSW4gSGVyZHIsICRrZXkgb3BlbnMgdGhlIHdoZXJkciBwYW5lbC4iCiAgICAgIGVsc2UgdGVsbCAiICBJbiBIZXJkcjogaGVyZHIgcGx1Z2luIGFjdGlvbiBpbnZva2UgcGFuZWwgLS1wbHVnaW4gJFBMVUdJTl9JRCIKICAgICAgZmkKICAgIGZpCiAgICBpZiBbICIke0ZJUlNUX0lOU1RBTEw6LTB9IiA9IDEgXTsgdGhlbgogICAgICAjIEFscmVhZHkgcHVibGlzaGVkIG9uIHRoZSB0YWlsbmV0IChhIHJlaW5zdGFsbCwgb3IgYHRhaWxzY2FsZSBzZXJ2ZWAKICAgICAgIyBydW4gZmlyc3QpOiB0aGUgZ3VpZGUgb3BlbnMgb24gdGhhdCBhZGRyZXNzLCB3aGVyZSBwYXNza2V5cyBiZWxvbmcuCiAgICAgIGd1aWRlPSIkKG9wZW5fYWRkcmVzcykvIy9zZXR1cCIKICAgICAgaWYgb3Blbl9icm93c2VyICIkZ3VpZGUiOyB0aGVuIFsgIiRxdWlldCIgPSAxIF0gfHwgdGVsbCAiICBTZXR1cCBndWlkZSBvcGVuZWQgaW4geW91ciBicm93c2VyOiAkZ3VpZGUiCiAgICAgIGVsc2UgWyAiJHF1aWV0IiA9IDEgXSB8fCB0ZWxsICIgIFNldHVwIGd1aWRlOiBvcGVuICRndWlkZSBpbiBhIGJyb3dzZXIiCiAgICAgIGZpCiAgICBmaQogICAgWyAiJHF1aWV0IiA9IDEgXSB8fCB0ZWxsICIgIFBob25lOiBwcmVzcyBQIGluIHRoZSBwYW5lbCB0byBnZXQgeW91ciBUYWlsc2NhbGUgYWRkcmVzcyAocHJpdmF0ZSBuZXR3b3JrIG9ubHkpLiIKICBlbHNlCiAgICB0ZWxsICIiCiAgICB0ZWxsICIhIHdoZXJkciBpcyBpbnN0YWxsZWQgYnV0IGRpZCBub3Qgc3RhcnQ6IgogICAgcHJpbnRmICclc1xuJyAiJG91dCIgfCB0YWlsIC1uIDggfCB3aGlsZSBJRlM9IHJlYWQgLXIgbDsgZG8gdGVsbCAiICAgICRsIjsgZG9uZQogICAgdGVsbCAiICBPcGVuIHRoZSB3aGVyZHIgcGFuZWwgaW4gSGVyZHIsIHRoZW4gcHJlc3MgUyB0byBzdGFydCBpdCBvciBMIGZvciBpdHMgbG9nLiIKICBmaQp9Cgp3cml0ZV9jb25mKCkgewogIHsKICAgIGVjaG8gIiMgd2hlcmRyIEhlcmRyIHBsdWdpbiBzZXR0aW5ncyAoaGVyZHItcGx1Z2luLnNoKS4iCiAgICBlY2hvICJXSEVSRFJfUE9SVD0kUE9SVCIKICAgIGVjaG8gIiMgTmF0aXZlIG1vZGU6IHByaXZhdGUgSFRUUFMgYWRkcmVzcyAodGFpbHNjYWxlIHNlcnZlKSwgZm9yIHB1c2ggbm90aWZpY2F0aW9ucy4iCiAgICBlY2hvICJBUFBfVVJMPSR7QVBQX1VSTDotfSIKICAgIGVjaG8gIiMgQWJzb2x1dGUgcGF0aCBvZiB0aGUgbm9kZSAoMjIrKSBvciBidW4gdGhhdCBydW5zIHdoZXJkci4iCiAgICBlY2hvICJXSEVSRFJfUlVOVElNRT0kUlVOVElNRSIKICB9ID4gIiRDT05GIgp9CgojIFByZWZlciB0aGUgcmVsZWFzZSBhcmNoaXZlLCB0aGVuIHRoZSBhbHJlYWR5LWJ1aWx0IG5wbSBwYWNrYWdlLiBDb21waWxlIG9ubHkKIyB3aGVuIG5laXRoZXIgc291cmNlIHByb3ZpZGVzIGEgdXNhYmxlIHBhY2thZ2Ugb2YgdGhpcyBleGFjdCB2ZXJzaW9uLgpmZXRjaF9wcmVidWlsdCgpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxICYmIGNvbW1hbmQgLXYgdGFyID4vZGV2L251bGwgMj4mMSB8fCByZXR1cm4gMQogIHZlcnNpb249IiQoc2VkIC1uICdzL152ZXJzaW9uID0gIlwoLipcKSIkL1wxL3AnICIkUk9PVC9oZXJkci1wbHVnaW4udG9tbCIgfCBoZWFkIC1uIDEpIgogIHRtcD0iJChta3RlbXAgLWQpIgogIGZvciBzb3VyY2UgaW4gZ2l0aHViIG5wbTsgZG8KICAgIHJtIC1yZiAiJHRtcC9wYWNrYWdlIgogICAgaWYgWyAiJHNvdXJjZSIgPSBnaXRodWIgXTsgdGhlbgogICAgICB1cmw9Imh0dHBzOi8vZ2l0aHViLmNvbS8kU09VUkNFL3JlbGVhc2VzL2Rvd25sb2FkL3YkdmVyc2lvbi93aGVyZHItJHZlcnNpb24udGd6IgogICAgICBjdXJsIC1mc1NMIC0tbWF4LXRpbWUgMTIwICIkdXJsIiAtbyAiJHRtcC93aGVyZHIudGd6IiAyPi9kZXYvbnVsbCBcCiAgICAgICAgJiYgY3VybCAtZnNTTCAtLW1heC10aW1lIDMwICIkdXJsLnNoYTI1NiIgLW8gIiR0bXAvY2hlY2tzdW0iIDI+L2Rldi9udWxsIFwKICAgICAgICAmJiAiJFJVTlRJTUUiICIkUk9PVC9iaW4vbGliL3ZlcmlmeS1yZWxlYXNlLm1qcyIgIiR0bXAvd2hlcmRyLnRneiIgIiR0bXAvY2hlY2tzdW0iIDI+L2Rldi9udWxsIHx8IGNvbnRpbnVlCiAgICBlbHNlCiAgICAgIHVybD0iaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hlcmRyLy0vd2hlcmRyLSR2ZXJzaW9uLnRneiIKICAgICAgY3VybCAtZnNTTCAtLW1heC10aW1lIDEyMCAiJHVybCIgLW8gIiR0bXAvd2hlcmRyLnRneiIgMj4vZGV2L251bGwgXAogICAgICAgICYmIGN1cmwgLWZzU0wgLS1tYXgtdGltZSAzMCAiaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hlcmRyLyR2ZXJzaW9uIiAtbyAiJHRtcC9tZXRhZGF0YSIgMj4vZGV2L251bGwgXAogICAgICAgICYmICIkUlVOVElNRSIgIiRST09UL2Jpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIiAiJHRtcC93aGVyZHIudGd6IiAiJHRtcC9tZXRhZGF0YSIgbnBtICIkdmVyc2lvbiIgMj4vZGV2L251bGwgfHwgY29udGludWUKICAgIGZpCiAgICB0YXIgLXh6ZiAiJHRtcC93aGVyZHIudGd6IiAtQyAiJHRtcCIgMj4vZGV2L251bGwgfHwgY29udGludWUKICAgIFsgLWYgIiR0bXAvcGFja2FnZS8ub3V0cHV0L3NlcnZlci9pbmRleC5tanMiIF0gXAogICAgICAmJiBbIC1kICIkdG1wL3BhY2thZ2UvYmluIiBdICYmIFsgLWYgIiR0bXAvcGFja2FnZS9wYWNrYWdlLmpzb24iIF0gfHwgY29udGludWUKICAgICMgTGVnYWN5IHBhY2thZ2VzIGhhdmUgbmVpdGhlciB0aGUgc2tpbGwgbm9yIGl0cyBoZWxwZXJzLiBLZWVwIHRoZQogICAgIyBjaGVja291dCdzIGNvbW1hbmRzIHNvIHBsdWdpbiBza2lsbCBpbnN0YWxsL3VuaW5zdGFsbCBzdGlsbCB3b3JrLgogICAgZm9yIGVudHJ5IGluIC5vdXRwdXQgYmluIHBhY2thZ2UuanNvbiBza2lsbHM7IGRvCiAgICAgIFsgLWUgIiR0bXAvcGFja2FnZS8kZW50cnkiIF0gfHwgY29udGludWUKICAgICAgaWYgWyAiJGVudHJ5IiA9IGJpbiBdOyB0aGVuCiAgICAgICAgWyAtZiAiJHRtcC9wYWNrYWdlL3NraWxscy93aGVyZHIvU0tJTEwubWQiIF0gXAogICAgICAgICAgJiYgWyAtZiAiJHRtcC9wYWNrYWdlL2Jpbi9saWIvaW5zdGFsbC1za2lsbC5zaCIgXSB8fCBjb250aW51ZQogICAgICBmaQogICAgICBybSAtcmYgIiRST09ULyRlbnRyeSIKICAgICAgbXYgIiR0bXAvcGFja2FnZS8kZW50cnkiICIkUk9PVC8kZW50cnkiCiAgICBkb25lCiAgICBybSAtcmYgIiR0bXAiCiAgICBvayAid2hlcmRyICR2ZXJzaW9uIGRvd25sb2FkZWQgKCRzb3VyY2UgcGFja2FnZSwgY2hlY2tzdW0gbWF0Y2hlZCkiCiAgICByZXR1cm4gMAogIGRvbmUKICBybSAtcmYgIiR0bXAiCiAgcmV0dXJuIDEKfQoKIyBxcmNvZGUtdGVybWluYWwgKHRoZSBwYW5lbCdzIFFSIGNvZGUpLCB0aGUgb25seSBwYWNrYWdlIHRoZSBjb21tYW5kcyBuZWVkCiMgYXQgcnVudGltZSwgd2hlbiB0aGUgZm9sZGVyIGRvZXMgbm90IGhhdmUgaXQgeWV0IChubyBucG0gY2kgd2FzIHJ1bikuCmZldGNoX3FyKCkgewogIFsgLWYgIiQxL25vZGVfbW9kdWxlcy9xcmNvZGUtdGVybWluYWwvcGFja2FnZS5qc29uIiBdICYmIHJldHVybiAwCiAgY29tbWFuZCAtdiBjdXJsID4vZGV2L251bGwgMj4mMSAmJiBjb21tYW5kIC12IHRhciA+L2Rldi9udWxsIDI+JjEgfHwgcmV0dXJuIDAKICB0bXA9IiQobWt0ZW1wIC1kKSIKICBpZiBjdXJsIC1mc1NMIC0tbWF4LXRpbWUgNjAgaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcXJjb2RlLXRlcm1pbmFsLy0vcXJjb2RlLXRlcm1pbmFsLTAuMTIuMC50Z3ogLW8gIiR0bXAvcXIudGd6IiAyPi9kZXYvbnVsbCBcCiAgICAmJiB0YXIgLXh6ZiAiJHRtcC9xci50Z3oiIC1DICIkdG1wIjsgdGhlbgogICAgbWtkaXIgLXAgIiQxL25vZGVfbW9kdWxlcyIKICAgIHJtIC1yZiAiJDEvbm9kZV9tb2R1bGVzL3FyY29kZS10ZXJtaW5hbCIKICAgIG12ICIkdG1wL3BhY2thZ2UiICIkMS9ub2RlX21vZHVsZXMvcXJjb2RlLXRlcm1pbmFsIgogIGVsc2UKICAgIHdhcm4gIk5vIFFSIGNvZGUgaW4gdGhlIHBhbmVsIChxcmNvZGUtdGVybWluYWwgY291bGQgbm90IGJlIGRvd25sb2FkZWQpLiIKICBmaQogIHJtIC1yZiAiJHRtcCIKfQoKYnVpbGRfbmF0aXZlKCkgewogIFJVTlRJTUU9IiQoZmluZF9ydW50aW1lKSIgfHwgZGllICIkUlVOVElNRV9IRUxQIgogIG9rICJSdW50aW1lOiAkUlVOVElNRSAoJCgiJFJVTlRJTUUiIC0tdmVyc2lvbiAyPi9kZXYvbnVsbCkpIgogIGlmIGZldGNoX3ByZWJ1aWx0OyB0aGVuCiAgICBpbnN0YWxsX2FwcAogICAgcmV0dXJuIDAKICBmaQogIGNhc2UgIiQoYmFzZW5hbWUgIiRSVU5USU1FIikiIGluCiAgICBidW4pIGRpZSAiVGhlIHByZWJ1aWx0IHdoZXJkciBwYWNrYWdlIGNvdWxkIG5vdCBiZSBkb3dubG9hZGVkLCBhbmQgYnVpbGRpbmcgaXQgbmVlZHMgTm9kZS5qcyAyMiB3aXRoIG5wbS4KICAgICBDaGVjayB0aGUgbmV0d29yaywgb3IgaW5zdGFsbCBOb2RlLmpzIDIyLCB0aGVuIGluc3RhbGwgdGhlIHBsdWdpbiBhZ2Fpbi4iIDs7CiAgZXNhYwogIGJpbmRpcj0iJChkaXJuYW1lICIkUlVOVElNRSIpIgogIFsgLXggIiRiaW5kaXIvbnBtIiBdIHx8IGNvbW1hbmQgLXYgbnBtID4vZGV2L251bGwgMj4mMSB8fCBkaWUgIm5wbSBpcyBtaXNzaW5nIChpdCBjb21lcyB3aXRoIE5vZGUuanMpLiIKICB0ZWxsICJ3aGVyZHI6IGJ1aWxkaW5nIChhIGZldyBtaW51dGVzIHRoZSBmaXJzdCB0aW1lKeKApiIKICAoCiAgICBjZCAiJFJPT1QiCiAgICBQQVRIPSIkYmluZGlyOiRQQVRIIiBucG0gY2kgLS1uby1hdWRpdCAtLW5vLWZ1bmQKICAgIFBBVEg9IiRiaW5kaXI6JFBBVEgiIG5wbSBydW4gYnVpbGQKICApCiAgb2sgIndoZXJkciBidWlsdCBpbiB0aGUgcGx1Z2luIGZvbGRlciIKICBpbnN0YWxsX2FwcAp9CgojIENvcGllcyB0aGUgY29tbWFuZHMgYW5kIHRoZSBidWlsdCBzZXJ2ZXIgdG8gJEFQUCwgd2hpY2ggb3V0bGl2ZXMgdGhpcwojIGNoZWNrb3V0LiBBIHdoZXJkciB0aGlzIHBsdWdpbiBydW5zIGZyb20gdGhlIHByZXZpb3VzIGNvcHkgaXMgc3RvcHBlZCBmb3IKIyB0aGUgc3dhcDsgYnVpbGRfc3RhcnQgc3RhcnRzIHRoZSBuZXcgb25lLgppbnN0YWxsX2FwcCgpIHsKICAjIE5pdHJvIGxpbmtzIHNvbWUgcGFja2FnZXMgKHRzbGliKSB0byBpdHMgb3duIGZvbGRlcjogY29waWVzLCBub3QgbGlua3MuCiAgaWYgWyAtZCAiJFJPT1QvLm91dHB1dC9zZXJ2ZXIvbm9kZV9tb2R1bGVzIiBdOyB0aGVuICIkUlVOVElNRSIgIiRST09UL3NjcmlwdHMvcGFjay1vdXRwdXQubWpzIiA+L2Rldi9udWxsOyBmaQogIG5ldz0iJEFQUC5uZXciCiAgcm0gLXJmICIkbmV3IgogIG1rZGlyIC1wICIkbmV3IgogIGNwIC1SICIkUk9PVC9iaW4iICIkUk9PVC9za2lsbHMiICIkUk9PVC8ub3V0cHV0IiAiJFJPT1QvcGFja2FnZS5qc29uIiAiJG5ldy8iCiAgaWYgWyAtZCAiJFJPT1Qvbm9kZV9tb2R1bGVzL3FyY29kZS10ZXJtaW5hbCIgXTsgdGhlbgogICAgbWtkaXIgLXAgIiRuZXcvbm9kZV9tb2R1bGVzIgogICAgY3AgLVIgIiRST09UL25vZGVfbW9kdWxlcy9xcmNvZGUtdGVybWluYWwiICIkbmV3L25vZGVfbW9kdWxlcy8iCiAgZmkKICBmZXRjaF9xciAiJG5ldyIKICAjIFRoZSB3aGVyZHIgdGhpcyBwbHVnaW4gcnVucyAoZnJvbSB0aGUgcHJldmlvdXMgY29weSwgb3IgZnJvbSBhbiBvbGRlcgogICMgcGx1Z2luIGNoZWNrb3V0KTogc3RvcHBlZCBmb3IgdGhlIHN3YXAsIHN0YXJ0ZWQgYWdhaW4gYnkgYnVpbGRfc3RhcnQuCiAgaWYgWyAtZiAiJERJUi93aGVyZHIucGlkIiBdIHx8IFsgLWYgIiRBUFAvYmluL3doZXJkci5tanMiIF07IHRoZW4gY2xpIHN0b3AgPi9kZXYvbnVsbCAyPiYxIHx8IHRydWU7IGZpCiAgcm0gLXJmICIkQVBQLm9sZCIKICBpZiBbIC1kICIkQVBQIiBdOyB0aGVuIG12ICIkQVBQIiAiJEFQUC5vbGQiOyBmaQogIG12ICIkbmV3IiAiJEFQUCIKICBybSAtcmYgIiRBUFAub2xkIgogIG9rICJ3aGVyZHIgJChzZWQgLW4gJ3MvXiAqInZlcnNpb24iOiAqIlwoLipcKSIsJC9cMS9wJyAiJEFQUC9wYWNrYWdlLmpzb24iIHwgaGVhZCAtbiAxKSBpbnN0YWxsZWQgaW4gJEFQUCIKfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gc3RhcnQKY21kX3N0YXJ0KCkgewogIGlmIGFuc3dlcnM7IHRoZW4KICAgIHNheSAid2hlcmRyOiBzb21ldGhpbmcgYWxyZWFkeSBhbnN3ZXJzIG9uIHBvcnQgJFBPUlQsIG5vdGhpbmcgdG8gc3RhcnQgKCRVUkwpLiIKICAgIHJldHVybiAwCiAgZmkKICBzdGFydF9uYXRpdmUKfQoKIyBOYXRpdmUgbW9kZTogdGhlIHdoZXJkciBjb21tYW5kIChiaW4vd2hlcmRyLm1qcykgZG9lcyB0aGUgd29yaywgd2l0aCB0aGUKIyBydW50aW1lIHNhdmVkIGF0IGluc3RhbGw7IGl0IHNheXMgInN0YXJ0ZWQiIG9ubHkgb25jZSB0aGUgcG9ydCBhbnN3ZXJzLgplbnN1cmVfcnVudGltZSgpIHsKICBpZiAhIHJ1bnRpbWVfb2sgIiRSVU5USU1FIjsgdGhlbgogICAgc2F2ZWQ9IiRSVU5USU1FIgogICAgUlVOVElNRT0iJChmaW5kX3J1bnRpbWUpIiB8fCBkaWUgIiR7c2F2ZWQ6K1RoZSBzYXZlZCBydW50aW1lICgkc2F2ZWQpIGlzIGdvbmUuIH0kUlVOVElNRV9IRUxQIgogICAgd2FybiAiJHtzYXZlZDorJHNhdmVkIGlzIGdvbmU6IH11c2luZyAkUlVOVElNRSAoc2F2ZWQgaW4gJENPTkYpLiIKICAgIHdyaXRlX2NvbmYKICBmaQp9CgpjbGkoKSB7CiAgZW5zdXJlX3J1bnRpbWUKICBzb2NrPSIke0hFUkRSX1NPQ0tFVF9QQVRIOi19IgogICMgQSBwbHVnaW4gc3RhcnRlZCBmcm9tIGEgbmFtZWQgSGVyZHIgc2Vzc2lvbiBkcml2ZXMgdGhhdCBzZXNzaW9uLgogIHNlc3Npb249IiIKICBjYXNlICIkc29jayIgaW4gKi9zZXNzaW9ucy8qL2hlcmRyLnNvY2spIHNlc3Npb249IiQoYmFzZW5hbWUgIiQoZGlybmFtZSAiJHNvY2siKSIpIiA7OyBlc2FjCiAgKAogICAgY2QgIiRESVIiCiAgICBIRVJEUl9CSU49IiQoaGVyZHJfYmluKSIKICAgICMgVGhlIHJ1bnRpbWUncyBmb2xkZXIgZmlyc3Q6IHRvb2xzIGl0IHN0YXJ0cyBmaW5kIHRoZSBzYW1lIG5vZGUuCiAgICBQQVRIPSIkKGRpcm5hbWUgIiRSVU5USU1FIik6JFBBVEgiCiAgICBleHBvcnQgUEFUSCBXSEVSRFJfRElSPSIkRElSIiBXSEVSRFJfUlVOVElNRT0iJFJVTlRJTUUiIEhPU1Q9MTI3LjAuMC4xIFBPUlQgSEVSRFJfQklOCiAgICBpZiBbIC1uICIkc2Vzc2lvbiIgXTsgdGhlbiBleHBvcnQgSEVSRFJfV0VCX1NFU1NJT049IiRzZXNzaW9uIjsgZmkKICAgIGlmIFsgLW4gIiRzb2NrIiBdOyB0aGVuIGV4cG9ydCBIRVJEUl9TT0NLPSIkc29jayI7IGZpCiAgICBpZiBbIC1uICIke0FQUF9VUkw6LX0iIF07IHRoZW4gZXhwb3J0IEFQUF9VUkw7IGZpCiAgICBleGVjICIkUlVOVElNRSIgIiQoY2xpX3Jvb3QpL2Jpbi93aGVyZHIubWpzIiAiJEAiCiAgKQp9CgpzdGFydF9uYXRpdmUoKSB7CiAgWyAtZiAiJChjbGlfcm9vdCkvLm91dHB1dC9zZXJ2ZXIvaW5kZXgubWpzIiBdIHx8IGRpZSAid2hlcmRyIGlzIG5vdCBidWlsdDogaW5zdGFsbCB0aGUgcGx1Z2luIGFnYWluIChoZXJkciBwbHVnaW4gaW5zdGFsbCAkU09VUkNFIC0teWVzKS4iCiAgbWtkaXIgLXAgIiRESVIiCiAgY2xpIHN0YXJ0Cn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBzdG9wCmNtZF9zdG9wKCkgeyBjbGkgc3RvcDsgfQpjbWRfc3RhdHVzKCkgeyBjbGkgc3RhdHVzOyBzYXkgIiAgUGx1Z2luICAgbmF0aXZlIHNlcnZpY2UsIHNldHRpbmdzIGluICRDT05GIjsgfQpjbWRfbG9ncygpIHsgY2xpIGxvZ3MgLS1mb2xsb3c7IH0KY21kX2RvY3RvcigpIHsgY2xpIGRvY3RvcjsgfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIG9wZW4KIyBUaGUgZGVmYXVsdCBicm93c2VyLCBvbiBhIGNvbXB1dGVyIHdpdGggYSBzY3JlZW4gb25seTogYG9wZW5gIG9uIG1hY09TLAojIGB4ZGctb3BlbmAgb24gTGludXggd2l0aCBhIGRpc3BsYXkuIEZhaWxzIChvcGVucyBub3RoaW5nKSBvbiBhIGhlYWRsZXNzIHNlcnZlciwKIyBvciB3aXRoIFdIRVJEUl9OT19CUk9XU0VSPTEgKHNldCBieSBodHRwczovL3doZXJkci5kZXYvaW5zdGFsbCBvdmVyIFNTSCkuCm9wZW5fYnJvd3NlcigpIHsKICBpZiBbICIke1dIRVJEUl9OT19CUk9XU0VSOi0wfSIgPSAiMSIgXTsgdGhlbiByZXR1cm4gMQogIGVsaWYgWyAiJCh1bmFtZSAtcykiID0gIkRhcndpbiIgXSAmJiBjb21tYW5kIC12IG9wZW4gPi9kZXYvbnVsbCAyPiYxOyB0aGVuIG9wZW4gIiQxIgogIGVsaWYgWyAtbiAiJHtESVNQTEFZOi19JHtXQVlMQU5EX0RJU1BMQVk6LX0iIF0gJiYgY29tbWFuZCAtdiB4ZGctb3BlbiA+L2Rldi9udWxsIDI+JjE7IHRoZW4geGRnLW9wZW4gIiQxIiA+L2Rldi9udWxsIDI+JjEgJgogIGVsc2UgcmV0dXJuIDEKICBmaQp9CgojIFRoZSB0YWlsc2NhbGUgQ0xJOiBvbiB0aGUgUEFUSCwgb3IgaW5zaWRlIHRoZSBtYWNPUyBhcHAuCnRhaWxzY2FsZV9iaW4oKSB7CiAgaWYgY29tbWFuZCAtdiB0YWlsc2NhbGUgPi9kZXYvbnVsbCAyPiYxOyB0aGVuIGNvbW1hbmQgLXYgdGFpbHNjYWxlCiAgZWxpZiBbIC14IC9BcHBsaWNhdGlvbnMvVGFpbHNjYWxlLmFwcC9Db250ZW50cy9NYWNPUy9UYWlsc2NhbGUgXTsgdGhlbiBlY2hvIC9BcHBsaWNhdGlvbnMvVGFpbHNjYWxlLmFwcC9Db250ZW50cy9NYWNPUy9UYWlsc2NhbGUKICBlbHNlIHJldHVybiAxCiAgZmkKfQoKIyAiPG1hY2hpbmU+Ljx0YWlsbmV0Pi50cy5uZXRbOnBvcnRdIiBvZiB0aGUgYWRkcmVzcyBgdGFpbHNjYWxlIHNlcnZlYAojIHB1Ymxpc2hlcyBmb3Igd2hlcmRyJ3MgbG9jYWwgcG9ydCwgcmVhZCBmcm9tIFRhaWxzY2FsZSBvbiB0aGlzIG1hY2hpbmUuCnNlcnZlZF9ob3N0KCkgewogIHRzPSIkKHRhaWxzY2FsZV9iaW4pIiB8fCByZXR1cm4gMQogICMgIjxuYW1lPjo8aHR0cHMgcG9ydD4iIG9mIHRoZSBXZWIgZW50cnkgd2hvc2UgcHJveHkgdGFyZ2V0cyBvdXIgcG9ydC4KICBob3N0PSIkKCIkdHMiIHNlcnZlIHN0YXR1cyAtLWpzb24gMj4vZGV2L251bGwgfCB0ciAneywnICdcblxuJyB8IGF3ayAtdiBwb3J0PSIkUE9SVCIgJwogICAgLyJbXiJdKjpbMC05XSsiWyBcdF0qOlsgXHRdKiQvIHsga2V5ID0gJDA7IHN1YigvXlteIl0qIi8sICIiLCBrZXkpOyBzdWIoLyIuKiQvLCAiIiwga2V5KSB9CiAgICAvIlByb3h5Ii8gJiYgJDAgfiAoIlwiKGh0dHBzPzovLyk/KDEyN1xcLjBcXC4wXFwuMXxsb2NhbGhvc3QpOiIgcG9ydCAiLz9cIiIpIHsgcHJpbnQga2V5OyBleGl0IH0nKSIKICBbIC1uICIkaG9zdCIgXSB8fCByZXR1cm4gMQogIHByaW50ZiAnJXNcbicgIiR7aG9zdCU6NDQzfSIKfQoKIyBEb2VzIHRoZSBwaG9uZSBhZGRyZXNzIGFuc3dlcj8gIm9rIiAod2hlcmRyLCBhbmQgaXQgYWNjZXB0cyB0aGF0IGFkZHJlc3MpLAojICJob3N0IiAod2hlcmRyIHJlZnVzZXMgdGhhdCBhZGRyZXNzKSwgb3IgIm5vbmUiLiAvYXBpL2hlYWx0aCBnb2VzIHRocm91Z2gKIyB3aGVyZHIncyBob3N0IGNoZWNrOyB0aGUgc3RhdGljIG1hbmlmZXN0IGFuc3dlcnMgZm9yIGFueSBob3N0IG5hbWUgYW5kIG9ubHkKIyByZWNvZ25pemVzIGEgd2hlcmRyIG9sZGVyIHRoYW4gdGhhdCByb3V0ZS4KcGhvbmVfcmVhY2goKSB7CiAgY29tbWFuZCAtdiBjdXJsID4vZGV2L251bGwgMj4mMSB8fCB7IGVjaG8gbm9uZTsgcmV0dXJuIDA7IH0KICBib2R5PSIkKGN1cmwgLXMgLS1tYXgtdGltZSA4ICIkezF9YXBpL2hlYWx0aCIgMj4vZGV2L251bGwgfHwgdHJ1ZSkiCiAgY2FzZSAiJGJvZHkiIGluCiAgICAqJyJuYW1lIjoid2hlcmRyIicqKSBlY2hvIG9rIDs7CiAgICAqJyJjb2RlIjoiaG9zdCInKikgZWNobyBob3N0IDs7CiAgICAqKSBpZiBjdXJsIC1mc1MgLS1tYXgtdGltZSA4ICIkezF9bWFuaWZlc3Qud2VibWFuaWZlc3QiIDI+L2Rldi9udWxsIHwgZ3JlcCAtcSB3aGVyZHI7IHRoZW4gZWNobyBvazsgZWxzZSBlY2hvIG5vbmU7IGZpIDs7CiAgZXNhYwp9CgojIFRoZSB0YWlsbmV0IGFkZHJlc3MgYHRhaWxzY2FsZSBzZXJ2ZWAgYWxyZWFkeSBwdWJsaXNoZXMgZm9yIHdoZXJkcidzIGxvY2FsCiMgcG9ydCAoaHR0cHM6Ly88bWFjaGluZT4uPHRhaWxuZXQ+LnRzLm5ldFs6cG9ydF0pLCBvbmx5IHdoZW4gaXQgYW5zd2VycyBsaWtlCiMgd2hlcmRyLiBQYXNza2V5cyBhcmUgdGllZCB0byB0aGUgYWRkcmVzczogdGhhdCBpcyB0aGUgb25lIHRvIG9wZW4uCnRhaWxuZXRfYWRkcmVzcygpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxIHx8IHJldHVybiAxCiAgaG9zdD0iJChzZXJ2ZWRfaG9zdCkiIHx8IHJldHVybiAxCiAgWyAiJChwaG9uZV9yZWFjaCAiaHR0cHM6Ly8kaG9zdC8iKSIgPSBvayBdIHx8IHJldHVybiAxCiAgcHJpbnRmICdodHRwczovLyVzXG4nICIkaG9zdCIKfQoKIyBUaGUgYWRkcmVzcyB0byBvcGVuOiB0aGUgdGFpbG5ldCBvbmUgd2hlbiBwdWJsaXNoZWQgYW5kIGFuc3dlcmluZywgZWxzZSBsb2NhbGhvc3QuCm9wZW5fYWRkcmVzcygpIHsgdGFpbG5ldF9hZGRyZXNzIHx8IHByaW50ZiAnJXNcbicgIiRVUkwiOyB9CgpjbWRfb3BlbigpIHsKICBhZGRyZXNzPSIkKG9wZW5fYWRkcmVzcykiCiAgb3Blbl9icm93c2VyICIkYWRkcmVzcyIgfHwgdHJ1ZQogIHNheSAiJGFkZHJlc3MiCn0KCiMgYGFkZHJlc3NgOiB3aGF0IGBvcGVuYCB3b3VsZCBvcGVuLCB3aXRob3V0IG9wZW5pbmcgaXQgKGh0dHBzOi8vd2hlcmRyLmRldi9pbnN0YWxsKS4KY21kX2FkZHJlc3MoKSB7IG9wZW5fYWRkcmVzczsgfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB1cGRhdGUKY21kX3VwZGF0ZSgpIHsKICBzYXkgIlVwZGF0aW5nIHRoZSB3aGVyZHIgcGx1Z2luIGZyb20gJHtTT1VSQ0V94oCmIgogICIkKGhlcmRyX2JpbikiIHBsdWdpbiBpbnN0YWxsICIkU09VUkNFIiAtLXJlZiBtYWluIC0teWVzCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHBob25lCiMgUGhvbmUgc2V0dXAgdXNlcyB0aGUgbmF0aXZlIGNvbW1hbmQuCmNtZF9waG9uZSgpIHsgY2xpIHBob25lOyB9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBzZXJ2aWNlCmNtZF9zZXJ2aWNlKCkgewogIGNhc2UgIiR7MTotfSIgaW4gaW5zdGFsbHx1bmluc3RhbGwpIDs7ICopIGRpZSAidXNhZ2U6ICQwIHNlcnZpY2UgaW5zdGFsbHx1bmluc3RhbGwiIDs7IGVzYWMKICBjbGkgc2VydmljZSAiJDEiCiAgIyBXaXRob3V0IHRoZSBzZXJ2aWNlLCB0aGUgcGx1Z2luIHJ1bnMgd2hlcmRyIGFnYWluIChhbmQgaXRzIHN0YXJ0dXAgaG9vawogICMgc3RhcnRzIGl0IHdpdGggSGVyZHIpLgogIGlmIFsgIiQxIiA9ICJ1bmluc3RhbGwiIF07IHRoZW4gY21kX3N0YXJ0OyBmaQp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBrZXkKIyBBIEhlcmRyIGtleSB0aGF0IG9wZW5zIHRoZSB3aGVyZHIgcGFuZWw6IEhlcmRyIHYxIHBsdWdpbnMgaGF2ZSBubyBtZW51LCBzbwojIHRoZSBpbnN0YWxsIGFwcGVuZHMgb25lIG1hcmtlZCBbW2tleXMuY29tbWFuZF1dIGJsb2NrIHRvIEhlcmRyJ3MKIyBjb25maWcudG9tbCwgb24gdGhlIGZpcnN0IGZyZWUga2V5IG9mIEhPVEtFWVMgKG5ldmVyIG9uZSBIZXJkciBvciB0aGUgdXNlcgojIGFscmVhZHkgYmluZHMpLiBFeGlzdGluZyBsaW5lcyBhcmUgbmV2ZXIgY2hhbmdlZDogdGhlIGJsb2NrIGlzIG9ubHkgZXZlcgojIGFwcGVuZGVkLCB0aGVuIHJlbW92ZWQgYnkgYGtleSB1bmluc3RhbGxgLiBOb3RoaW5nIGlzIGFkZGVkIHdoZW4gdGhlIHBhbmVsCiMgYWxyZWFkeSBoYXMgYSBrZXksIG9yIHdoZW4gbm8gY2FuZGlkYXRlIGlzIGZyZWUuCkhPVEtFWVM9IiR7V0hFUkRSX0hPVEtFWVM6LXByZWZpeCtpIHByZWZpeCt1IHByZWZpeCt5IHByZWZpeCttIHByZWZpeCthbHQrd30iCkhFUkRSX0NPTkZJRz0iJHtIRVJEUl9DT05GSUdfUEFUSDotJHtYREdfQ09ORklHX0hPTUU6LSRIT01FLy5jb25maWd9L2hlcmRyL2NvbmZpZy50b21sfSIKUExVR0lOX0lEPSIkKHByaW50ZiAnJXMnICIkU09VUkNFIiB8IHRyIC8gLikiClBBTkVMX0FDVElPTj0iJFBMVUdJTl9JRC5wYW5lbCIKS0VZX0JFR0lOPSIjIHdoZXJkcjoga2V5IHRoYXQgb3BlbnMgdGhlIHdoZXJkciBwYW5lbCAocmVtb3ZlIHRoaXMgYmxvY2sgdG8gdW5iaW5kIGl0KSIKS0VZX0VORD0iIyBlbmQgd2hlcmRyIgoKIyBIZXJkcidzIGRlZmF1bHQga2V5bWFwLCBmcm9tIHRoZSBydW5uaW5nIGJpbmFyeSB3aGVuIGl0IGNhbiBwcmludCBpdCwKIyBvdGhlcndpc2UgYXMgb2YgSGVyZHIgMC45LjMgKCJuYW1lPFRBQj5rZXkiIGxpbmVzKS4KZGVmYXVsdF9rZXlzKCkgewogIG91dD0iJCgiJChoZXJkcl9iaW4pIiAtLWRlZmF1bHQtY29uZmlnIDI+L2Rldi9udWxsIHwgYXdrICcKICAgIC9eXFtrZXlzXF0vIHsgayA9IDE7IG5leHQgfQogICAgayAmJiAvXlxbLyB7IGV4aXQgfQogICAgayAmJiBtYXRjaCgkMCwgL14jIFthLXpfXSsgPSAiW14iXSoiLykgewogICAgICBsaW5lID0gc3Vic3RyKCQwLCAzLCBSTEVOR1RIIC0gMik7IGVxID0gaW5kZXgobGluZSwgIiA9ICIpCiAgICAgIHYgPSBzdWJzdHIobGluZSwgZXEgKyA0KTsgc3ViKC8iJC8sICIiLCB2KQogICAgICBpZiAodiAhPSAiIikgcHJpbnRmICIlc1x0JXNcbiIsIHN1YnN0cihsaW5lLCAxLCBlcSAtIDEpLCB2CiAgICB9JykiIHx8IG91dD0iIgogIGlmIFsgLW4gIiRvdXQiIF07IHRoZW4gcHJpbnRmICclc1xuJyAiJG91dCI7IHJldHVybjsgZmkKICBmb3IgcCBpbiBoZWxwOj8gc2V0dGluZ3M6cyBkZXRhY2g6cSByZWxvYWRfY29uZmlnOnNoaWZ0K3Igb3Blbl9ub3RpZmljYXRpb25fdGFyZ2V0Om8gXAogICAgd29ya3NwYWNlX3BpY2tlcjp3IGdvdG86ZyBuZXdfd29ya3NwYWNlOnNoaWZ0K24gbmV3X3dvcmt0cmVlOnNoaWZ0K2cgcmVuYW1lX3dvcmtzcGFjZTpzaGlmdCt3IFwKICAgIGNsb3NlX3dvcmtzcGFjZTpzaGlmdCtkIG5ld190YWI6YyByZW5hbWVfdGFiOnNoaWZ0K3QgcHJldmlvdXNfdGFiOnAgbmV4dF90YWI6biBcCiAgICBjbG9zZV90YWI6c2hpZnQreCByZW5hbWVfcGFuZTpzaGlmdCtwIGVkaXRfc2Nyb2xsYmFjazplIGZvY3VzX3BhbmVfbGVmdDpoIGZvY3VzX3BhbmVfZG93bjpqIFwKICAgIGZvY3VzX3BhbmVfdXA6ayBmb2N1c19wYW5lX3JpZ2h0OmwgY3ljbGVfcGFuZV9uZXh0OnRhYiBjeWNsZV9wYW5lX3ByZXZpb3VzOnNoaWZ0K3RhYiBcCiAgICBzcGxpdF92ZXJ0aWNhbDp2IHNwbGl0X2hvcml6b250YWw6bWludXMgY2xvc2VfcGFuZTp4IHpvb206eiByZXNpemVfbW9kZTpyIHRvZ2dsZV9zaWRlYmFyOmI7IGRvCiAgICBwcmludGYgJyVzXHRwcmVmaXgrJXNcbicgIiR7cCUlOip9IiAiJHtwIyo6fSIKICBkb25lCn0KCiMgT25lIGxpbmUgb24gdGhlIGNvbmZpZzogImJvdW5kIDxrZXk+IiB3aGVuIGEgW1trZXlzLmNvbW1hbmRdXSBhbHJlYWR5IHJ1bnMKIyB0aGUgcGFuZWwsIGVsc2UgImZyZWUgPGtleT4iIChmaXJzdCBmcmVlIGNhbmRpZGF0ZSkgb3IgIm5vbmUiLiBBbHNvCiMgIm9sZCA8a2V5PiIgZm9yIGEgYmluZGluZyBvZiB0aGUgcGFuZWwncyBmb3JtZXIgYWN0aW9uIGlkICg8aWQ+LndoZXJkcikuCmtleV9zY2FuKCkgewogIGRlZmF1bHRzPSIkKGRlZmF1bHRfa2V5cykiCiAgeyBwcmludGYgJyVzXG4nICIkZGVmYXVsdHMiOyBwcmludGYgJ1wwMDFcbic7IGNhdCAiJEhFUkRSX0NPTkZJRyIgMj4vZGV2L251bGw7IH0gfCBhd2sgXAogICAgLXYgY2FuZHM9IiRIT1RLRVlTIiAtdiBhY3Rpb249IiRQQU5FTF9BQ1RJT04iIC12IG9sZD0iJFBMVUdJTl9JRC53aGVyZHIiICcKICAgIGZ1bmN0aW9uIG5vcm0oaykgewogICAgICBnc3ViKC9bIFx0XS8sICIiLCBrKQogICAgICAjICJwcmVmaXgrVyIgaXMgInByZWZpeCtzaGlmdCt3IgogICAgICBpZiAobWF0Y2goaywgL1wrW0EtWl0kLykpIGsgPSBzdWJzdHIoaywgMSwgUlNUQVJUKSAic2hpZnQrIiB0b2xvd2VyKHN1YnN0cihrLCBSU1RBUlQgKyAxKSkKICAgICAgcmV0dXJuIHRvbG93ZXIoaykKICAgIH0KICAgIGZ1bmN0aW9uIHN0cmluZ3Mocywgb3V0LCAgIG4pIHsKICAgICAgbiA9IDAKICAgICAgd2hpbGUgKG1hdGNoKHMsIC8iW14iXSoiLykpIHsgb3V0Wysrbl0gPSBzdWJzdHIocywgUlNUQVJUICsgMSwgUkxFTkdUSCAtIDIpOyBzID0gc3Vic3RyKHMsIFJTVEFSVCArIFJMRU5HVEgpIH0KICAgICAgcmV0dXJuIG4KICAgIH0KICAgIGZ1bmN0aW9uIGZsdXNoKCkgewogICAgICBpZiAoY2tleSAhPSAiIiAmJiBjbWQgPT0gYWN0aW9uICYmIGJvdW5kID09ICIiKSBib3VuZCA9IGNrZXkKICAgICAgaWYgKGNrZXkgIT0gIiIgJiYgY21kID09IG9sZCAmJiBvbGRrZXkgPT0gIiIpIG9sZGtleSA9IGNrZXkKICAgICAgY2tleSA9ICIiOyBjbWQgPSAiIgogICAgfQogICAgJDAgPT0gIlwwMDEiIHsgY29uZiA9IDE7IG5leHQgfQogICAgIWNvbmYgeyBzcGxpdCgkMCwgZCwgIlx0Iik7IGRlZltkWzFdXSA9IGRbMl07IG5leHQgfQogICAgL15bIFx0XSpcWy8gewogICAgICBmbHVzaCgpOyB0ID0gJDA7IHN1YigvIy4qLywgIiIsIHQpOyBnc3ViKC9bIFx0XS8sICIiLCB0KQogICAgICBzZWN0ID0gdCA9PSAiW2tleXNdIiA/ICJrZXlzIiA6IHQgPT0gIltba2V5cy5jb21tYW5kXV0iID8gImNtZCIgOiAiIgogICAgICBuZXh0CiAgICB9CiAgICAvXlsgXHRdKigjfCQpLyB7IG5leHQgfQogICAgewogICAgICBlcSA9IGluZGV4KCQwLCAiPSIpOyBpZiAoIWVxKSBuZXh0CiAgICAgIG5hbWUgPSBzdWJzdHIoJDAsIDEsIGVxIC0gMSk7IGdzdWIoL1sgXHRdLywgIiIsIG5hbWUpOyB2YWwgPSBzdWJzdHIoJDAsIGVxICsgMSkKICAgICAgaWYgKHNlY3QgPT0gImtleXMiKSB7CiAgICAgICAgb3ZlcltuYW1lXSA9IDE7IG4gPSBzdHJpbmdzKHZhbCwgcykKICAgICAgICBmb3IgKGkgPSAxOyBpIDw9IG47IGkrKykgdGFrZW5bbm9ybShzW2ldKV0gPSAxCiAgICAgIH0gZWxzZSBpZiAoc2VjdCA9PSAiY21kIiAmJiBzdHJpbmdzKHZhbCwgcykpIHsKICAgICAgICBpZiAobmFtZSA9PSAia2V5IikgeyBja2V5ID0gc1sxXTsgdGFrZW5bbm9ybShzWzFdKV0gPSAxIH0KICAgICAgICBpZiAobmFtZSA9PSAiY29tbWFuZCIpIGNtZCA9IHNbMV0KICAgICAgfQogICAgfQogICAgRU5EIHsKICAgICAgZmx1c2goKQogICAgICBpZiAob2xka2V5ICE9ICIiKSBwcmludCAib2xkICIgb2xka2V5CiAgICAgIGlmIChib3VuZCAhPSAiIikgeyBwcmludCAiYm91bmQgIiBib3VuZDsgZXhpdCB9CiAgICAgIGZvciAoYSBpbiBkZWYpIGlmICghKGEgaW4gb3ZlcikpIHRha2VuW25vcm0oZGVmW2FdKV0gPSAxCiAgICAgIG4gPSBzcGxpdChjYW5kcywgYywgIiAiKQogICAgICBmb3IgKGkgPSAxOyBpIDw9IG47IGkrKykgaWYgKCEobm9ybShjW2ldKSBpbiB0YWtlbikpIHsgcHJpbnQgImZyZWUgIiBjW2ldOyBleGl0IH0KICAgICAgcHJpbnQgIm5vbmUiCiAgICB9Jwp9CgojIFRoZSBrZXkgYm91bmQgdG8gdGhlIHBhbmVsLCBpZiBhbnkuCmtleV9ib3VuZCgpIHsga2V5X3NjYW4gfCBzZWQgLW4gJ3MvXmJvdW5kIC8vcCc7IH0KCiMgSGVyZHIgYXBwbGllcyBrZXliaW5kaW5ncyBvbiBgaGVyZHIgc2VydmVyIHJlbG9hZC1jb25maWdgIChubyByZXN0YXJ0KS4Ka2V5X3JlbG9hZCgpIHsKICBpZiAiJChoZXJkcl9iaW4pIiBzZXJ2ZXIgcmVsb2FkLWNvbmZpZyA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIHRlbGwgIiAgSGVyZHIgcmVsb2FkZWQgaXRzIGNvbmZpZzogbm8gcmVzdGFydCBuZWVkZWQuIgogIGVsc2UKICAgIHRlbGwgIiAgUnVuIGhlcmRyIHNlcnZlciByZWxvYWQtY29uZmlnIChvciByZXN0YXJ0IEhlcmRyKSB0byBhcHBseSBpdC4iCiAgZmkKfQoKY21kX2tleSgpIHsKICBjYXNlICIkezE6LX0iIGluCiAgICBpbnN0YWxsKQogICAgICBzY2FuPSIkKGtleV9zY2FuKSIKICAgICAgb2xkPSIkKHByaW50ZiAnJXNcbicgIiRzY2FuIiB8IHNlZCAtbiAncy9eb2xkIC8vcCcpIgogICAgICBbIC16ICIkb2xkIiBdIHx8IHdhcm4gIiRvbGQgcnVucyAkUExVR0lOX0lELndoZXJkciwgcmVuYW1lZCAkUEFORUxfQUNUSU9OOiBlZGl0IHRoYXQgbGluZSBvZiAkSEVSRFJfQ09ORklHLiIKICAgICAgcmVzPSIkKHByaW50ZiAnJXNcbicgIiRzY2FuIiB8IHNlZCAnL15vbGQgL2QnKSIKICAgICAgY2FzZSAiJHJlcyIgaW4KICAgICAgICBib3VuZFwgKikgdGVsbCAiUHJlc3MgJHtyZXMjYm91bmQgfSBpbiBIZXJkciB0byBvcGVuIHRoZSB3aGVyZHIgcGFuZWwuIiA7OwogICAgICAgIGZyZWVcICopCiAgICAgICAgICBrZXk9IiR7cmVzI2ZyZWUgfSIKICAgICAgICAgIG1rZGlyIC1wICIkKGRpcm5hbWUgIiRIRVJEUl9DT05GSUciKSIKICAgICAgICAgIGJsb2NrPSIkKHByaW50ZiAnJXNcbltba2V5cy5jb21tYW5kXV1cbmtleSA9ICIlcyJcbnR5cGUgPSAicGx1Z2luX2FjdGlvbiJcbmNvbW1hbmQgPSAiJXMiXG5kZXNjcmlwdGlvbiA9ICJ3aGVyZHIiXG4lcycgXAogICAgICAgICAgICAiJEtFWV9CRUdJTiIgIiRrZXkiICIkUEFORUxfQUNUSU9OIiAiJEtFWV9FTkQiKSIKICAgICAgICAgIHNlcD0iIgogICAgICAgICAgaWYgWyAtcyAiJEhFUkRSX0NPTkZJRyIgXTsgdGhlbgogICAgICAgICAgICBzZXA9IgoiCiAgICAgICAgICAgICMgQSBsYXN0IGxpbmUgd2l0aG91dCBpdHMgbmV3bGluZSBnZXRzIG9uZSBmaXJzdC4KICAgICAgICAgICAgWyAiJCh0YWlsIC1jIDEgIiRIRVJEUl9DT05GSUciIHwgb2QgLUFuIC1jIHwgdHIgLWQgJyAnKSIgPSAnXG4nIF0gfHwgc2VwPSIKJHNlcCIKICAgICAgICAgIGZpCiAgICAgICAgICAjIENoZWNrZWQgb24gYSBjb3B5IGZpcnN0IHdoZW4gdGhpcyBIZXJkciBjYW4gdmFsaWRhdGUgYSBjb25maWc6CiAgICAgICAgICAjIGEgY29uZmlnIEhlcmRyIHdvdWxkIHJlamVjdCBpcyBuZXZlciB3cml0dGVuLgogICAgICAgICAgdG1wPSIkSEVSRFJfQ09ORklHLndoZXJkci1jaGVjay50b21sIgogICAgICAgICAgeyBpZiBbIC1mICIkSEVSRFJfQ09ORklHIiBdOyB0aGVuIGNhdCAiJEhFUkRSX0NPTkZJRyI7IGZpOyBwcmludGYgJyVzJXNcbicgIiRzZXAiICIkYmxvY2siOyB9ID4gIiR0bXAiCiAgICAgICAgICBpZiAiJChoZXJkcl9iaW4pIiBjb25maWcgLS1oZWxwID4vZGV2L251bGwgMj4mMSAmJiAhIEhFUkRSX0NPTkZJR19QQVRIPSIkdG1wIiAiJChoZXJkcl9iaW4pIiBjb25maWcgY2hlY2sgPi9kZXYvbnVsbCAyPiYxOyB0aGVuCiAgICAgICAgICAgIHJtIC1mICIkdG1wIgogICAgICAgICAgICB3YXJuICJubyBIZXJkciBrZXkgYWRkZWQ6ICRIRVJEUl9DT05GSUcgd291bGQgbm90IHZhbGlkYXRlIHdpdGggaXQgKGhlcmRyIGNvbmZpZyBjaGVjaykuIgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgICAgZmkKICAgICAgICAgIHJtIC1mICIkdG1wIgogICAgICAgICAgcHJpbnRmICclcyVzXG4nICIkc2VwIiAiJGJsb2NrIiA+PiAiJEhFUkRSX0NPTkZJRyIKICAgICAgICAgIG9rICJIZXJkciBrZXkgJGtleSBhZGRlZCB0byAkSEVSRFJfQ09ORklHIgogICAgICAgICAgdGVsbCAiUHJlc3MgJGtleSBpbiBIZXJkciB0byBvcGVuIHRoZSB3aGVyZHIgcGFuZWwuIgogICAgICAgICAga2V5X3JlbG9hZAogICAgICAgICAgOzsKICAgICAgICAqKSB3YXJuICJubyBIZXJkciBrZXkgYWRkZWQ6ICRIT1RLRVlTIGFyZSBhbGwgdGFrZW4uIEJpbmQgb25lIHRvICRQQU5FTF9BQ1RJT04gKHR5cGUgPSBcInBsdWdpbl9hY3Rpb25cIikgaW4gJEhFUkRSX0NPTkZJRy4iIDs7CiAgICAgIGVzYWMKICAgICAgOzsKICAgIHVuaW5zdGFsbCkKICAgICAgaWYgISBncmVwIC1xeEYgIiRLRVlfQkVHSU4iICIkSEVSRFJfQ09ORklHIiAyPi9kZXYvbnVsbDsgdGhlbiBvayAibm8gd2hlcmRyIGtleSBpbiAkSEVSRFJfQ09ORklHIjsgcmV0dXJuIDA7IGZpCiAgICAgICMgRHJvcHMgdGhlIG1hcmtlZCBibG9jayBhbmQgdGhlIGJsYW5rIGxpbmUgd3JpdHRlbiBiZWZvcmUgaXQuCiAgICAgIHRtcD0iJEhFUkRSX0NPTkZJRy53aGVyZHItdG1wIgogICAgICBhd2sgLXYgYj0iJEtFWV9CRUdJTiIgLXYgZT0iJEtFWV9FTkQiICcKICAgICAgICAkMCA9PSBiIHsgc2tpcCA9IDE7IGlmIChibGFuaykgYmxhbmstLTsgbmV4dCB9CiAgICAgICAgc2tpcCB7IGlmICgkMCA9PSBlKSBza2lwID0gMDsgbmV4dCB9CiAgICAgICAgJDAgPT0gIiIgeyBibGFuaysrOyBuZXh0IH0KICAgICAgICB7IHdoaWxlIChibGFuaykgeyBwcmludCAiIjsgYmxhbmstLSB9IHByaW50IH0KICAgICAgICBFTkQgeyB3aGlsZSAoYmxhbmspIHsgcHJpbnQgIiI7IGJsYW5rLS0gfSB9JyAiJEhFUkRSX0NPTkZJRyIgPiAiJHRtcCIKICAgICAgIyBSZXdyaXR0ZW4gaW4gcGxhY2U6IHRoZSBmaWxlIGtlZXBzIGl0cyBvd25lciBhbmQgbW9kZS4KICAgICAgY2F0ICIkdG1wIiA+ICIkSEVSRFJfQ09ORklHIiAmJiBybSAtZiAiJHRtcCIKICAgICAgb2sgIndoZXJkciBrZXkgcmVtb3ZlZCBmcm9tICRIRVJEUl9DT05GSUciCiAgICAgIGtleV9yZWxvYWQKICAgICAgOzsKICAgIHN0YXR1cykgYj0iJChrZXlfYm91bmQpIjsgaWYgWyAtbiAiJGIiIF07IHRoZW4gc2F5ICIkYiI7IGVsc2Ugc2F5ICJub25lIjsgZmkgOzsKICAgICopIGRpZSAidXNhZ2U6ICQwIGtleSBpbnN0YWxsfHVuaW5zdGFsbHxzdGF0dXMiIDs7CiAgZXNhYwp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBwYW5lbAojIFRoZSAicGFuZWwiIGFjdGlvbjogb25lIHBvcHVwIHdpdGggdGhlIHN0YXRlLCBPcGVuIHdoZXJkciwgU2V0IHVwIG15IHBob25lCiMgKG9wZW5zIFNldHRpbmdzIOKAuiBQaG9uZSkgYW5kIHRoZSBvdGhlciBjb21tYW5kcyAoYmluL2xpYi9wYW5lbC5tanMpLAojIGRyaXZpbmcgdGhpcyBzY3JpcHQuCmNtZF9wYW5lbCgpIHsKICBjb250cm9sPSIkKHByaW50ZiAnWyJzaCIsIiVzIl0nICIkKHByaW50ZiAnJXMnICIkUk9PVC9zY3JpcHRzL2hlcmRyLXBsdWdpbi5zaCIgfCBzZWQgJ3MvW1xcIl0vXFwmL2cnKSIpIgogIFdIRVJEUl9DT05UUk9MPSIkY29udHJvbCIgV0hFUkRSX0hPVEtFWT0iJChrZXlfYm91bmQpIiBjbGkgcGFuZWwKfQoKY21kX3Jlc3RhcnQoKSB7IGNtZF9zdG9wOyBjbWRfc3RhcnQ7IH0KCmNhc2UgIiR7MTotfSIgaW4KICBidWlsZCkgY21kX2J1aWxkIDs7CiAgcGFuZWwpIGNtZF9wYW5lbCA7OwogIHN0YXJ0fHN0b3B8cmVzdGFydHxzdGF0dXN8b3BlbnxhZGRyZXNzfHVwZGF0ZXxwaG9uZXxsb2dzfGRvY3RvcikgImNtZF8kMSIgOzsKICBzZXJ2aWNlKSBjbWRfc2VydmljZSAiJHsyOi19IiA7OwogIHNraWxsKSBjbWRfc2tpbGwgIiR7MjotfSIgOzsKICBrZXkpIGNtZF9rZXkgIiR7MjotfSIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCBidWlsZHxwYW5lbHxzdGFydHxzdG9wfHJlc3RhcnR8c3RhdHVzfG9wZW58YWRkcmVzc3x1cGRhdGV8cGhvbmV8bG9nc3xkb2N0b3J8c2VydmljZSBpbnN0YWxsfHVuaW5zdGFsbHxza2lsbCBpbnN0YWxsfHVuaW5zdGFsbHxrZXkgaW5zdGFsbHx1bmluc3RhbGx8c3RhdHVzIiA7Owplc2FjCg==");
|
|
5
5
|
|
|
6
6
|
export { herdrPlugin as default };
|
|
7
7
|
//# sourceMappingURL=herdr-plugin.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
2
|
|
|
3
3
|
// ROLLUP_NO_REPLACE
|
|
4
|
-
const installClaudeStatusline = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyOiBpbnN0YWxscyBDbGF1ZGUgQ29kZSdzIGludmlzaWJsZSBzdGF0dXMgbGluZSAocXVvdGFzICsgYWNjb3VudAojIGZpbmdlcnByaW50KSBmb3IgdGhlIGN1cnJlbnQgdXNlci4gU2VsZi1jb250YWluZWQgKHRoZSBzdGF0dXMgbGluZSBpcyBpbmNsdWRlZAojIGJlbG93KTogd2hlcmRyIHJ1bnMgaXQgYXMgaXMgb24gYSBtYWNoaW5lICgiSW5zdGFsbCIgYnV0dG9uKSBvcgojIGhhbmRzIGl0IG91dCB0byBwYXN0ZSAoIkNvcHkgY29tbWFuZCIpLiBTYWZlIHRvIHJ1biBhZ2FpbjoKIyAgLSB3cml0ZXMgdGhlIHN0YXR1cyBsaW5lIHRvIH4vLmNsYXVkZS93aGVyZHItc3RhdHVzbGluZS5zaCAodXBkYXRlKTsKIyAgLSBubyBgc3RhdHVzTGluZWAgaW4gfi8uY2xhdWRlL3NldHRpbmdzLmpzb246IGFkZHMgb3VyczsKIyAgLSBhbm90aGVyIGBzdGF0dXNMaW5lYCAoY29tbWFuZCk6IGNoYWlucyBpdCBiZWhpbmQgb3VycywgaXRzCiMgICAgb3V0cHV0IHN0YXlzIHRoZSBzYW1lOyBiYWNrdXAgY29weSBzZXR0aW5ncy5qc29uLmJhay13aGVyZHIuCiMgUXVvdGFzIHNob3cgdXAgYWZ0ZXIgdGhlIG5leHQgZXhjaGFuZ2Ugd2l0aCBhIENsYXVkZS4Kc2V0IC1lCmRpcj0iJHtDTEFVREVfQ09ORklHX0RJUjotJEhPTUUvLmNsYXVkZX0iCm1rZGlyIC1wICIkZGlyIgojIC0tLS0gc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKSAtLS0tCmNhdCA+
|
|
4
|
+
const installClaudeStatusline = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyOiBpbnN0YWxscyBDbGF1ZGUgQ29kZSdzIGludmlzaWJsZSBzdGF0dXMgbGluZSAocXVvdGFzICsgYWNjb3VudAojIGZpbmdlcnByaW50KSBmb3IgdGhlIGN1cnJlbnQgdXNlci4gU2VsZi1jb250YWluZWQgKHRoZSBzdGF0dXMgbGluZSBpcyBpbmNsdWRlZAojIGJlbG93KTogd2hlcmRyIHJ1bnMgaXQgYXMgaXMgb24gYSBtYWNoaW5lICgiSW5zdGFsbCIgYnV0dG9uKSBvcgojIGhhbmRzIGl0IG91dCB0byBwYXN0ZSAoIkNvcHkgY29tbWFuZCIpLiBTYWZlIHRvIHJ1biBhZ2FpbjoKIyAgLSB3cml0ZXMgdGhlIHN0YXR1cyBsaW5lIHRvIH4vLmNsYXVkZS93aGVyZHItc3RhdHVzbGluZS5zaCAodXBkYXRlKTsKIyAgLSBubyBgc3RhdHVzTGluZWAgaW4gfi8uY2xhdWRlL3NldHRpbmdzLmpzb246IGFkZHMgb3VyczsKIyAgLSBhbm90aGVyIGBzdGF0dXNMaW5lYCAoY29tbWFuZCk6IGNoYWlucyBpdCBiZWhpbmQgb3VycywgaXRzCiMgICAgb3V0cHV0IHN0YXlzIHRoZSBzYW1lOyBiYWNrdXAgY29weSBzZXR0aW5ncy5qc29uLmJhay13aGVyZHIuCiMgUXVvdGFzIHNob3cgdXAgYWZ0ZXIgdGhlIG5leHQgZXhjaGFuZ2Ugd2l0aCBhIENsYXVkZS4Kc2V0IC1lCmRpcj0iJHtDTEFVREVfQ09ORklHX0RJUjotJEhPTUUvLmNsYXVkZX0iCm1rZGlyIC1wICIkZGlyIgojIC0tLS0gc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKSAtLS0tCmNhdCA+ICIkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoLnRtcCIgPDwnV0hFUkRSX1NUQVRVU0xJTkUnCiMhL2Jpbi9zaAojIHdoZXJkcjogQ2xhdWRlIENvZGUncyBpbnZpc2libGUgc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKS4gSXQgb25seSBrZWVwcwojIHRoZSBhY2NvdW50IHF1b3RhcyAocmF0ZV9saW1pdHMsIHdoaWNoIENsYXVkZSBDb2RlIHBhc3NlcyB0byBpdHMKIyBzdGF0dXMgbGluZSBhZnRlciBlYWNoIGV4Y2hhbmdlKSBmb3IgdGhlIHdoZXJkciBob21lIHNjcmVlbiwgYW5kIGFuIGFjY291bnQKIyBmaW5nZXJwcmludCAodHJ1bmNhdGVkIGhhc2ggb2YgaXRzIElELCBuZXZlciB0aGUgSUQgb3IgdGhlIGVtYWlsKQojIHRvIHRlbGwgYXBhcnQgbWFjaGluZXMgdGhhdCBkbyBub3QgdXNlIHRoZSBzYW1lIGFjY291bnQuCiMgSW5zdGFsbGVkIGJ5IGluc3RhbGwtY2xhdWRlLXN0YXR1c2xpbmUuc2ggKHdoZXJkciByZXBvc2l0b3J5LCBSRUFETUUsICJRdW90YXMKIyBvbiB0aGUgaG9tZSBzY3JlZW4iKS4gRXhpc3Rpbmcgc3RhdHVzIGxpbmU6IHBhc3NlZCBhcyBhbiBhcmd1bWVudCwgaXQgcmVjZWl2ZXMgdGhlCiMgc2FtZSBkYXRhIGFuZCBpdHMgb3V0cHV0IGlzIGtlcHQgKHNoIHdoZXJkci1zdGF0dXNsaW5lLnNoICdjbWQnKS4KZD0kKGNhdCkKY2FzZSAiJGQiIGluCiAgKicicmF0ZV9saW1pdHMiJyopCiAgICBkaXI9IiRIT01FLy5jYWNoZS9oZXJkci13ZWIiCiAgICBta2RpciAtcCAiJGRpciIKICAgICMgQmluZCB0aGUgZmluZ2VycHJpbnQgYW5kIHRpbWVzdGFtcCB0byB0aGUgcGF5bG9hZCBpbiBvbmUgYXRvbWljIHJlbmFtZS4KICAgICMgTm8gZmluZ2VycHJpbnQgVFRMOiBhIGxvZ2luIGNoYW5nZSBtdXN0IGFmZmVjdCB0aGUgdmVyeSBuZXh0IHJlYWRpbmcuCiAgICBwcmludGYgJyVzJyAiJGQiIHwgcHl0aG9uMyAtYyAnCmltcG9ydCBoYXNobGliLCBqc29uLCBvcywgc3lzLCB0ZW1wZmlsZSwgdGltZQpmcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGgKY2FjaGUgPSBQYXRoKHN5cy5hcmd2WzFdKQpjb25maWcgPSBQYXRoKG9zLmVudmlyb24uZ2V0KCJDTEFVREVfQ09ORklHX0RJUiIsIG9zLmVudmlyb25bIkhPTUUiXSkpIC8gIi5jbGF1ZGUuanNvbiIKdHJ5OgogICAgYWNjb3VudF9pZCA9IGpzb24ubG9hZHMoY29uZmlnLnJlYWRfdGV4dCgpKS5nZXQoIm9hdXRoQWNjb3VudCIsIHt9KS5nZXQoImFjY291bnRVdWlkIikKZXhjZXB0IChPU0Vycm9yLCBWYWx1ZUVycm9yLCBBdHRyaWJ1dGVFcnJvcik6CiAgICBhY2NvdW50X2lkID0gTm9uZQphY2NvdW50ID0gaGFzaGxpYi5zaGEyNTYoKCJ3aGVyZHI6IiArIGFjY291bnRfaWQpLmVuY29kZSgpKS5oZXhkaWdlc3QoKVs6MTZdIGlmIGlzaW5zdGFuY2UoYWNjb3VudF9pZCwgc3RyKSBhbmQgYWNjb3VudF9pZCBlbHNlIE5vbmUKc3RhdHVzID0ganNvbi5sb2FkKHN5cy5zdGRpbikKc3RhdHVzWyJfd2hlcmRyIl0gPSB7InZlcnNpb24iOiAxLCAiYWNjb3VudCI6IGFjY291bnQsICJhdCI6IGludCh0aW1lLnRpbWUoKSAqIDEwMDApfQpkZWYgYXRvbWljKG5hbWUsIHRleHQpOgogICAgZmQsIHRlbXAgPSB0ZW1wZmlsZS5ta3N0ZW1wKHByZWZpeD1uYW1lICsgIi4iLCBkaXI9Y2FjaGUpCiAgICB0cnk6CiAgICAgICAgd2l0aCBvcy5mZG9wZW4oZmQsICJ3IikgYXMgZjoKICAgICAgICAgICAgZi53cml0ZSh0ZXh0KQogICAgICAgIG9zLnJlcGxhY2UodGVtcCwgY2FjaGUgLyBuYW1lKQogICAgZmluYWxseToKICAgICAgICBpZiBvcy5wYXRoLmV4aXN0cyh0ZW1wKToKICAgICAgICAgICAgb3MudW5saW5rKHRlbXApCiMgQ29tcGF0aWJpbGl0eSBmb3Igb2xkZXIgcmVhZGVyczsgbmV3IHJlYWRlcnMgdXNlIG9ubHkgdGhlIGVtYmVkZGVkIGFjY291bnQuCmlmIGFjY291bnQ6CiAgICBhdG9taWMoImNsYXVkZS1hY2NvdW50IiwgYWNjb3VudCArICJcbiIpCmVsc2U6CiAgICAoY2FjaGUgLyAiY2xhdWRlLWFjY291bnQiKS51bmxpbmsobWlzc2luZ19vaz1UcnVlKQphdG9taWMoImNsYXVkZS1zdGF0dXMuanNvbiIsIGpzb24uZHVtcHMoc3RhdHVzKSkKJyAiJGRpciIgOzsKZXNhYwppZiBbIC1uICIkMSIgXTsgdGhlbiBwcmludGYgJyVzJyAiJGQiIHwgc2ggLWMgIiQxIjsgZXhpdCAkPzsgZmkKZXhpdCAwCldIRVJEUl9TVEFUVVNMSU5FCmNobW9kIDc1NSAiJGRpci93aGVyZHItc3RhdHVzbGluZS5zaC50bXAiCm12ICIkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoLnRtcCIgIiRkaXIvd2hlcmRyLXN0YXR1c2xpbmUuc2giCmVjaG8gInN0YXR1cyBsaW5lIHdyaXR0ZW46ICRkaXIvd2hlcmRyLXN0YXR1c2xpbmUuc2giCiMgLS0tLSBzZXR0aW5ncy5qc29uIC0tLS0KWyAtZiAiJGRpci9zZXR0aW5ncy5qc29uIiBdIHx8IGVjaG8gJ3t9JyA+ICIkZGlyL3NldHRpbmdzLmpzb24iCmNwICIkZGlyL3NldHRpbmdzLmpzb24iICIkZGlyL3NldHRpbmdzLmpzb24uYmFrLXdoZXJkciIKcHl0aG9uMyAtICIkZGlyL3NldHRpbmdzLmpzb24iICIkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoIiA8PCdXSEVSRFJfUFknCmltcG9ydCBqc29uLCBzaGxleCwgc3lzCnBhdGgsIHNjcmlwdCA9IHN5cy5hcmd2WzFdLCBzeXMuYXJndlsyXQpkID0ganNvbi5sb2FkKG9wZW4ocGF0aCkpCm91cnMgPSAnc2ggJyArIHNobGV4LnF1b3RlKHNjcmlwdCkKY3VyID0gZC5nZXQoJ3N0YXR1c0xpbmUnKQppZiBpc2luc3RhbmNlKGN1ciwgZGljdCkgYW5kICd3aGVyZHItc3RhdHVzbGluZS5zaCcgaW4gc3RyKGN1ci5nZXQoJ2NvbW1hbmQnLCAnJykpOgogICAgcHJpbnQoJ2FscmVhZHkgaW5zdGFsbGVkOicsIGN1clsnY29tbWFuZCddKQogICAgc3lzLmV4aXQoMCkKaWYgY3VyIGlzIE5vbmU6CiAgICBkWydzdGF0dXNMaW5lJ10gPSB7J3R5cGUnOiAnY29tbWFuZCcsICdjb21tYW5kJzogb3Vyc30KICAgIHByaW50KCdzdGF0dXMgbGluZSBhZGRlZDonLCBvdXJzKQplbGlmIGlzaW5zdGFuY2UoY3VyLCBkaWN0KSBhbmQgY3VyLmdldCgndHlwZScpID09ICdjb21tYW5kJyBhbmQgY3VyLmdldCgnY29tbWFuZCcpOgogICAgZFsnc3RhdHVzTGluZSddID0geyoqY3VyLCAnY29tbWFuZCc6IG91cnMgKyAnICcgKyBzaGxleC5xdW90ZShjdXJbJ2NvbW1hbmQnXSl9CiAgICBwcmludCgnZXhpc3Rpbmcgc3RhdHVzIGxpbmUgY2hhaW5lZDonLCBkWydzdGF0dXNMaW5lJ11bJ2NvbW1hbmQnXSkKZWxzZToKICAgIHByaW50KCd1bmtub3duIHN0YXR1c0xpbmUsIG5vdGhpbmcgY2hhbmdlZDonLCBqc29uLmR1bXBzKGN1ciksIGZpbGU9c3lzLnN0ZGVycikKICAgIHN5cy5leGl0KDEpCndpdGggb3BlbihwYXRoLCAndycpIGFzIGY6CiAgICBqc29uLmR1bXAoZCwgZiwgaW5kZW50PTIsIGVuc3VyZV9hc2NpaT1GYWxzZSkKICAgIGYud3JpdGUoJ1xuJykKV0hFUkRSX1BZCg==");
|
|
5
5
|
|
|
6
6
|
export { installClaudeStatusline as default };
|
|
7
7
|
//# sourceMappingURL=install-claude-statusline.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const prereleaseSummary = "// Rolling releases describe the current Unreleased changes, not just build metadata.\nimport { readFileSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\nimport { checkReleaseNotes } from './check-release-notes.mjs'\n\nexport function prereleaseSummary(changelog, repo, sha) {\n const unreleased = changelog.split(/^## (?:\\[Unreleased\\]|\\d+\\.\\d+\\.\\d+ \\(unreleased\\))[^\\n]*\\n/m)[1]?.split(/^## /m)[0]\n const entries = unreleased?.match(/^- .*(?:\\n(?!\\s*$|[-#]).+)*/gm)?.slice(0, 3)\n if (!entries?.length) throw new Error('Add user-facing Unreleased entries to CHANGELOG.md before packaging a prerelease')\n const notes = `## Update\\n\\n${entries.join('\\n\\n')}\\n\\n[Full changelog](https://github.com/${repo}/blob/${sha}/CHANGELOG.md)\\n`\n checkReleaseNotes(notes, repo, sha)\n return notes\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const repo = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).repository.url\n .replace(/^git\\+https:\\/\\/github.com\\//, '').replace(/\\.git$/, '')\n console.log(prereleaseSummary(readFileSync('CHANGELOG.md', 'utf8'), process.env.GH_REPO || process.env.GITHUB_REPOSITORY || repo, process.argv[2]))\n}\n";
|
|
3
|
+
|
|
4
|
+
export { prereleaseSummary as default };
|
|
5
|
+
//# sourceMappingURL=prerelease-summary.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
|
+
|
|
3
|
+
// ROLLUP_NO_REPLACE
|
|
4
|
+
const prerelease = base64ToUint8Array("IyEvdXNyL2Jpbi9lbnYgYmFzaAojIFJvbGxpbmcgcHJlcmVsZWFzZSBvZiB0aGUgdjIgYnJhbmNoICguZ2l0aHViL3dvcmtmbG93cy92Mi1wcmVyZWxlYXNlLnltbCkuCiMgVGhlIHJlbGVhc2Ugdjx2ZXJzaW9uPiAodmVyc2lvbiBvZiBoZXJkci1wbHVnaW4udG9tbCwgZS5nLiAyLjAuMC1kZXYpIGlzCiMgcmVidWlsdCBvbiBldmVyeSBwdXNoOiBpdHMgdGFnIG1vdmVzIHRvIHRoZSBwdXNoZWQgY29tbWl0IGFuZCBpdHMgZmlsZXMgYXJlCiMgcmVwbGFjZWQsIHNvIGEgbWFjaGluZSBjYW4gaW5zdGFsbCB2MiB3aXRoIGZldGNoX3ByZWJ1aWx0CiMgKHNjcmlwdHMvaGVyZHItcGx1Z2luLnNoKSBhbmQgbmV2ZXIgY29tcGlsZSBpdC4KIwojICAgcHJlcmVsZWFzZS5zaCB2ZXJzaW9uICAgICAgICAgICAgICAgICBwcmludCB0aGUgdmVyc2lvbiwgaWYgaXQgaXMgYSBwcmVyZWxlYXNlIG9uZQojICAgcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+ICAgICBjaGVjayB0aGUgbnBtIHBhY2sgYXJjaGl2ZSwgd3JpdGUgPHRnej4uc2hhMjU2LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDT01NSVQgYW5kIHByZXJlbGVhc2Utbm90ZXMubWQgbmV4dCB0byBpdAojICAgcHJlcmVsZWFzZS5zaCBwdWJsaXNoIDx0Z3o+IDxzaGE+ICAgICBtb3ZlIHRoZSB0YWcsIHVwZGF0ZSB0aGUgcmVsZWFzZSwgdXBsb2FkIHRoZSBmaWxlcwojCiMgcHVibGlzaCBuZWVkcyBnaCB3aXRoIEdIX1JFUE8gKG93bmVyL25hbWUpIGFuZCBhIHRva2VuIHRoYXQgY2FuIHdyaXRlIGNvbnRlbnRzLgojIFNhZmV0eTogb25seSBhIHZlcnNpb24gd2l0aCBhIHByZXJlbGVhc2Ugc3VmZml4IChYLlkuWi1zb21ldGhpbmcpIGlzIGV2ZXIKIyBwdWJsaXNoZWQsIGFuZCBhbiBleGlzdGluZyByZWxlYXNlIG9mIHRoYXQgdGFnIG11c3QgYmUgYSBwdWJsaXNoZWQKIyBwcmVyZWxlYXNlOiBhIHN0YWJsZSB2WC5ZLlogdGFnIG9yIHJlbGVhc2UgaXMgbmV2ZXIgbW92ZWQgb3IgZWRpdGVkLgpzZXQgLWV1byBwaXBlZmFpbAoKZGllKCkgeyBlY2hvICJwcmVyZWxlYXNlOiAkKiIgPiYyOyBleGl0IDE7IH0KCnBsdWdpbl92ZXJzaW9uKCkgeyBzZWQgLW4gJ3MvXnZlcnNpb24gPSAiXCguKlwpIiQvXDEvcCcgaGVyZHItcGx1Z2luLnRvbWwgfCBoZWFkIC1uIDE7IH0KCmNtZF92ZXJzaW9uKCkgewogIGxvY2FsIHZlcnNpb24gcGtnCiAgdmVyc2lvbj0iJChwbHVnaW5fdmVyc2lvbikiCiAgcGtnPSIkKG5vZGUgLXAgInJlcXVpcmUoJy4vcGFja2FnZS5qc29uJykudmVyc2lvbiIpIgogIFsgIiR2ZXJzaW9uIiA9ICIkcGtnIiBdIHx8IGRpZSAiaGVyZHItcGx1Z2luLnRvbWwgKCR2ZXJzaW9uKSBhbmQgcGFja2FnZS5qc29uICgkcGtnKSBkaXNhZ3JlZSIKICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rLVswLTlBLVphLXouLV0rJCBdXSBcCiAgICB8fCBkaWUgInZlcnNpb24gJHZlcnNpb24gaXMgbm90IGEgcHJlcmVsZWFzZSAoWC5ZLlotc3VmZml4KTogc3RhYmxlIHJlbGVhc2VzIGdvIHRocm91Z2ggcmVsZWFzZS55bWwiCiAgZWNobyAiJHZlcnNpb24iCn0KCmNoZWNrX3NoYSgpIHsgW1sgIiQxIiA9fiBeWzAtOWEtZl17NDB9JCBdXSB8fCBkaWUgIm5vdCBhIGZ1bGwgY29tbWl0IFNIQTogJDEiOyB9CgojIFRoZSBhcmNoaXZlIG11c3QgaG9sZCB3aGF0IGZldGNoX3ByZWJ1aWx0IGluc3RhbGxzLCBhbmQgbm90aGluZyBjb21waWxlZCBmb3IKIyBvbmUgcGxhdGZvcm06IHRoZSBzYW1lIGZpbGUgcnVucyBvbiBsaW51eC1hcm02NCAoUmFzcGJlcnJ5IFBpKSBhbmQgeDY0LgpjaGVja19hcmNoaXZlKCkgewogIGxvY2FsIHRnej0iJDEiIHRtcCBtaXNzaW5nPTAgbmF0aXZlCiAgdG1wPSIkKG1rdGVtcCAtZCkiCiAgdGFyIC14emYgIiR0Z3oiIC1DICIkdG1wIgogIGZvciBlbnRyeSBpbiAub3V0cHV0L3NlcnZlci9pbmRleC5tanMgYmluL3doZXJkci5tanMgYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIGJpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIFwKICAgIHBhY2thZ2UuanNvbiBza2lsbHMvd2hlcmRyL1NLSUxMLm1kOyBkbwogICAgWyAtZiAiJHRtcC9wYWNrYWdlLyRlbnRyeSIgXSB8fCB7IGVjaG8gInByZXJlbGVhc2U6IG1pc3NpbmcgcGFja2FnZS8kZW50cnkiID4mMjsgbWlzc2luZz0xOyB9CiAgZG9uZQogIG5hdGl2ZT0iJChub2RlIC1lICcKICAgIGNvbnN0IGZzID0gcmVxdWlyZSgibm9kZTpmcyIpLCBwYXRoID0gcmVxdWlyZSgibm9kZTpwYXRoIikKICAgIGNvbnN0IE1BR0lDID0gWyI3ZjQ1NGM0NiIsICJmZWVkZmFjZSIsICJmZWVkZmFjZiIsICJjZWZhZWRmZSIsICJjZmZhZWRmZSJdCiAgICBjb25zdCBoaXRzID0gW10KICAgIGNvbnN0IHdhbGsgPSBkaXIgPT4gewogICAgICBmb3IgKGNvbnN0IGUgb2YgZnMucmVhZGRpclN5bmMoZGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHsKICAgICAgICBjb25zdCBwID0gcGF0aC5qb2luKGRpciwgZS5uYW1lKQogICAgICAgIGlmIChlLmlzRGlyZWN0b3J5KCkpIHsgaWYgKGUubmFtZSA9PT0gInByZWJ1aWxkcyIpIGhpdHMucHVzaChwKTsgZWxzZSB3YWxrKHApOyBjb250aW51ZSB9CiAgICAgICAgaWYgKCFlLmlzRmlsZSgpKSBjb250aW51ZQogICAgICAgIGlmICgvXC4obm9kZXxzb3xkeWxpYnxkbGx8ZXhlKSQvLnRlc3QoZS5uYW1lKSB8fCBlLm5hbWUgPT09ICJiaW5kaW5nLmd5cCIpIHsgaGl0cy5wdXNoKHApOyBjb250aW51ZSB9CiAgICAgICAgY29uc3QgZmQgPSBmcy5vcGVuU3luYyhwLCAiciIpLCBiID0gQnVmZmVyLmFsbG9jKDQpCiAgICAgICAgY29uc3QgbiA9IGZzLnJlYWRTeW5jKGZkLCBiLCAwLCA0LCAwKTsgZnMuY2xvc2VTeW5jKGZkKQogICAgICAgIGlmIChuID09PSA0ICYmIE1BR0lDLmluY2x1ZGVzKGIudG9TdHJpbmcoImhleCIpKSkgaGl0cy5wdXNoKHApCiAgICAgIH0KICAgIH0KICAgIHdhbGsocHJvY2Vzcy5hcmd2WzFdKQogICAgY29uc29sZS5sb2coaGl0cy5tYXAoaCA9PiBwYXRoLnJlbGF0aXZlKHByb2Nlc3MuYXJndlsxXSwgaCkpLmpvaW4oIlxuIikpCiAgJyAiJHRtcCIpIgogIHJtIC1yZiAiJHRtcCIKICBbICIkbWlzc2luZyIgPSAwIF0gfHwgZGllICJpbmNvbXBsZXRlIHBhY2thZ2UgJHRneiIKICBbIC16ICIkbmF0aXZlIiBdIHx8IGRpZSAibmF0aXZlIGNvZGUgaW4gdGhlIHBhY2thZ2UgKGl0IHdvdWxkIG5vdCBydW4gb24gYW5vdGhlciBwbGF0Zm9ybSk6CiRuYXRpdmUiCn0KCmNtZF9wYWNrYWdlKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIGRpciBuYW1lCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIG5hbWU9IndoZXJkci0kdmVyc2lvbi50Z3oiCiAgWyAiJChiYXNlbmFtZSAiJHRneiIpIiA9ICIkbmFtZSIgXSB8fCBkaWUgImV4cGVjdGVkICRuYW1lLCBnb3QgJChiYXNlbmFtZSAiJHRneiIpIgogIGNoZWNrX2FyY2hpdmUgIiR0Z3oiCiAgZGlyPSIkKGRpcm5hbWUgIiR0Z3oiKSIKICAjIFRoZSBmb3JtYXQgYmluL2xpYi92ZXJpZnktcmVsZWFzZS5tanMgcmVhZHMsIGFzIHJlbGVhc2UueW1sIHdyaXRlcyBpdC4KICAoY2QgIiRkaXIiICYmIHNoYTI1NnN1bSAiJG5hbWUiID4gIiRuYW1lLnNoYTI1NiIpCiAgcHJpbnRmICclc1xuJyAiJHNoYSIgPiAiJGRpci9DT01NSVQiCiAgbm9kZSAiJChkaXJuYW1lICIke0JBU0hfU09VUkNFWzBdfSIpL3ByZXJlbGVhc2Utc3VtbWFyeS5tanMiICIkc2hhIiA+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgewogICAgZWNobwogICAgZWNobyAiUm9sbGluZyBwcmVyZWxlYXNlIG9mIHRoZSBcYHYyXGAgYnJhbmNoLCByZWJ1aWx0IG9uIGV2ZXJ5IHB1c2guIE5vdCBhIHN0YWJsZSByZWxlYXNlOiBuZXZlciBtYXJrZWQgbGF0ZXN0LCBuZXZlciBvZmZlcmVkIGFzIGFuIHVwZGF0ZS4iCiAgICBlY2hvCiAgICBlY2hvICJDb21taXQ6IFxgJHNoYVxgIgogICAgZWNobwogICAgZWNobyAiQnVpbHQgJChkYXRlIC11ICcrJVktJW0tJWQgJUg6JU0gVVRDJykke0dJVEhVQl9SVU5fSUQ6KyBieSAke0dJVEhVQl9TRVJWRVJfVVJMOi1odHRwczovL2dpdGh1Yi5jb219LyR7R0lUSFVCX1JFUE9TSVRPUlk6LX0vYWN0aW9ucy9ydW5zLyRHSVRIVUJfUlVOX0lEfS4iCiAgICBlY2hvCiAgICBlY2hvICJcYENPTU1JVFxgIGhvbGRzIHRoZSBjb21taXQgb2YgXGAkbmFtZVxgLiBJdCBpcyByZW1vdmVkIHdoaWxlIHRoZSBmaWxlcyBhcmUgcmVwbGFjZWQgYW5kIGF0dGFjaGVkIGxhc3Q6IHdoZW4gaXQgaXMgcHJlc2VudCwgdGhlIGFyY2hpdmUgbWF0Y2hlcyBpdC4iCiAgfSA+PiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGVjaG8gInByZXJlbGVhc2U6ICRuYW1lIGZvciAkc2hhIGNoZWNrZWQiCn0KCmNtZF9wdWJsaXNoKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwdWJsaXNoIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIHRhZyBkaXIgcmVwbyBzdGF0ZSBhc3NldHMgZXhpc3RzCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIHRhZz0idiR2ZXJzaW9uIgogIGRpcj0iJChkaXJuYW1lICIkdGd6IikiCiAgcmVwbz0iJHtHSF9SRVBPOj9HSF9SRVBPIGlzIHJlcXVpcmVkfSIKICBmb3IgZiBpbiAiJHRneiIgIiR0Z3ouc2hhMjU2IiAiJGRpci9DT01NSVQiICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiOyBkbwogICAgWyAtZiAiJGYiIF0gfHwgZGllICJtaXNzaW5nICRmIChydW46IHByZXJlbGVhc2Uuc2ggcGFja2FnZSBmaXJzdCkiCiAgZG9uZQoKICBpZiBzdGF0ZT0iJChnaCByZWxlYXNlIHZpZXcgIiR0YWciIC0tanNvbiBpc1ByZXJlbGVhc2UsaXNEcmFmdCAtLWpxICciXCguaXNQcmVyZWxlYXNlKSBcKC5pc0RyYWZ0KSInIDI+L2Rldi9udWxsKSI7IHRoZW4KICAgIFsgIiRzdGF0ZSIgPSAidHJ1ZSBmYWxzZSIgXSB8fCBkaWUgInJlbGVhc2UgJHRhZyBleGlzdHMgYW5kIGlzIG5vdCBhIHB1Ymxpc2hlZCBwcmVyZWxlYXNlICgkc3RhdGUpOiBsZWZ0IGFsb25lIgogICAgIyBHb25lIHdoaWxlIHRoZSBhcmNoaXZlIGNoYW5nZXM6IGEgcmVhZGVyIHRoYXQgZmluZHMgQ09NTUlUIGZpbmRzIGl0cyBhcmNoaXZlLgogICAgYXNzZXRzPSIkKGdoIHJlbGVhc2UgdmlldyAiJHRhZyIgLS1qc29uIGFzc2V0cyAtLWpxICcuYXNzZXRzW10ubmFtZScpIgogICAgaWYgcHJpbnRmICclc1xuJyAiJGFzc2V0cyIgfCBncmVwIC1xeCBDT01NSVQ7IHRoZW4KICAgICAgZ2ggcmVsZWFzZSBkZWxldGUtYXNzZXQgIiR0YWciIENPTU1JVCAtLXllcwogICAgZmkKICAgIGV4aXN0cz0xCiAgZWxzZQogICAgZXhpc3RzPTAKICBmaQoKICAjIFRoZSB0YWcgZm9sbG93cyB0aGUgcHVzaGVkIGNvbW1pdC4gTWFkZSB3aXRoIHRoZSB3b3JrZmxvdydzIHRva2VuLCBpdCBzdGFydHMKICAjIG5vIG90aGVyIHdvcmtmbG93IChyZWxlYXNlLnltbCBhbmQgbnBtLnltbCBsaXN0ZW4gdG8gdiogdGFncykuCiAgaWYgZ2ggYXBpICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciID4vZGV2L251bGwgMj4mMTsgdGhlbgogICAgZ2ggYXBpIC1YIFBBVENIICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciIC1mIHNoYT0iJHNoYSIgLUYgZm9yY2U9dHJ1ZSA+L2Rldi9udWxsCiAgZWxzZQogICAgZ2ggYXBpIC1YIFBPU1QgInJlcG9zLyRyZXBvL2dpdC9yZWZzIiAtZiByZWY9InJlZnMvdGFncy8kdGFnIiAtZiBzaGE9IiRzaGEiID4vZGV2L251bGwKICBmaQoKICBpZiBbICIkZXhpc3RzIiA9IDEgXTsgdGhlbgogICAgZ2ggcmVsZWFzZSBlZGl0ICIkdGFnIiAtLXByZXJlbGVhc2UgLS1sYXRlc3Q9ZmFsc2UgLS10aXRsZSAid2hlcmRyICR2ZXJzaW9uIiAtLW5vdGVzLWZpbGUgIiRkaXIvcHJlcmVsZWFzZS1ub3Rlcy5tZCIKICBlbHNlCiAgICBnaCByZWxlYXNlIGNyZWF0ZSAiJHRhZyIgLS12ZXJpZnktdGFnIC0tcHJlcmVsZWFzZSAtLWxhdGVzdD1mYWxzZSAtLXRpdGxlICJ3aGVyZHIgJHZlcnNpb24iIC0tbm90ZXMtZmlsZSAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgZ2ggcmVsZWFzZSB1cGxvYWQgIiR0YWciICIkdGd6IiAiJHRnei5zaGEyNTYiIC0tY2xvYmJlcgogIGdoIHJlbGVhc2UgdXBsb2FkICIkdGFnIiAiJGRpci9DT01NSVQiIC0tY2xvYmJlcgogIGVjaG8gInByZXJlbGVhc2U6ICR0YWcgbm93IGF0ICRzaGEiCn0KCmNhc2UgIiR7MTotfSIgaW4KICB2ZXJzaW9uKSBjbWRfdmVyc2lvbiA7OwogIHBhY2thZ2UpIHNoaWZ0OyBjbWRfcGFja2FnZSAiJEAiIDs7CiAgcHVibGlzaCkgc2hpZnQ7IGNtZF9wdWJsaXNoICIkQCIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCB2ZXJzaW9uIHwgcGFja2FnZSA8dGd6PiA8c2hhPiB8IHB1Ymxpc2ggPHRnej4gPHNoYT4iIDs7CmVzYWMK");
|
|
5
|
+
|
|
6
|
+
export { prerelease as default };
|
|
7
|
+
//# sourceMappingURL=prerelease.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
2
|
|
|
3
3
|
// ROLLUP_NO_REPLACE
|
|
4
|
-
const reveal = base64ToUint8Array("
|
|
4
|
+
const reveal = base64ToUint8Array("IyBUaGUgY2hlY2tzIG9mICJSZXZlYWwgaW4gRmluZGVyIiAvICJPcGVuIiAvICJPcGVuIGluIGVkaXRvciIsIHJ1biBvbiB0aGUgbWFjaGluZQojIHRoYXQgaGFzIGBvcGVuYCAobWFjT1MpLiBDYWxsZWQgd2l0aCAkMSA9IHJldmVhbCB8IG9wZW4sICQyID0gYWJzb2x1dGUgcGF0aC4KIyBTaW5nbGUgc291cmNlIG9mIHRydXRoOiBzZXJ2ZXIvdXRpbHMvcmV2ZWFsLnRzIGVtYmVkcyB0aGlzIGZpbGUgdmVyYmF0aW0gaW4gaXRzCiMgUkVWRUFMX1NDUklQVCAodGVzdHMvcmV2ZWFsLnRlc3QudHMgcGlucyB0aGVtIHRvZ2V0aGVyKS4KIyBFeGl0IGNvZGVzOiAzIG1pc3NpbmcsIDQgb3V0c2lkZSBob21lLCA1IG5vdCBtYWNPUywgNiBgb3BlbmAgZmFpbGVkLCA3IHJ1bm5hYmxlLgpwPSQyClsgLWUgIiRwIiBdIHx8IGV4aXQgMwppZiBjb21tYW5kIC12IHJlYWxwYXRoID4vZGV2L251bGwgMj4mMTsgdGhlbgogIHI9JChyZWFscGF0aCAiJHAiIDI+L2Rldi9udWxsKSB8fCBleGl0IDMKICBoPSQocmVhbHBhdGggIiRIT01FIiAyPi9kZXYvbnVsbCkgfHwgZXhpdCA0CmVsaWYgWyAtZCAiJHAiIF07IHRoZW4KICByPSQoY2QgLVAgIiRwIiAyPi9kZXYvbnVsbCAmJiBwd2QgLVApIHx8IGV4aXQgMwogIGg9JChjZCAtUCAiJEhPTUUiIDI+L2Rldi9udWxsICYmIHB3ZCAtUCkgfHwgZXhpdCA0CmVsc2UKICBkPSQoY2QgLVAgIiQoZGlybmFtZSAiJHAiKSIgMj4vZGV2L251bGwgJiYgcHdkIC1QKSB8fCBleGl0IDMKICByPSIkZC8kKGJhc2VuYW1lICIkcCIpIgogIFsgLUwgIiRyIiBdICYmIFsgIiQxIiA9IG9wZW4gXSAmJiBleGl0IDQKICBoPSQoY2QgLVAgIiRIT01FIiAyPi9kZXYvbnVsbCAmJiBwd2QgLVApIHx8IGV4aXQgNApmaQpjYXNlICIkci8iIGluICIkaCIvKikgOzsgKikgZXhpdCA0IDs7IGVzYWMKWyAiJCh1bmFtZSAtcykiID0gRGFyd2luIF0gfHwgZXhpdCA1CmlmIFsgIiQxIiA9IG9wZW4gXTsgdGhlbgogIGNhc2UgIiRyIiBpbiAqLmFwcHwqLmFwcC8qfCouY29tbWFuZHwqLnRvb2x8Ki50ZXJtaW5hbHwqLnBrZ3wqLm1wa2d8Ki53b3JrZmxvd3wqLnNjcHR8Ki5hcHBsZXNjcmlwdHwqLmphcnwqLndlYmxvY3wqLmluZXRsb2N8Ki5maWxlbG9jfCouZG1nKSBleGl0IDcgOzsgZXNhYwogIGlmIFsgLWYgIiRyIiBdICYmIFsgLXggIiRyIiBdOyB0aGVuIGV4aXQgNzsgZmkKICAjIEEgZm9sZGVyIG9wZW5zIGluIHRoZSBjb25maWd1cmVkIGVkaXRvciAoV0hfT1BFTl9FRElUT1IsIG9yIHRoZSBmaXJzdCBsaW5lCiAgIyBvZiB+Ly5sb2NhbC9zaGFyZS93aGVyZHIvZWRpdG9yIOKAlCBhbiBhcHAgbmFtZSBmb3Igb3BlbiAtYSk7IHBsYWluIG9wZW4KICAjIHdvdWxkIGdpdmUgdGhlIGZpbGUgbWFuYWdlci4gRmlsZXM6IHRoZSBMYXVuY2hTZXJ2aWNlcyBkZWZhdWx0IGFwcC4KICBlZD0ke1dIX09QRU5fRURJVE9SOi19CiAgaWYgWyAteiAiJGVkIiBdICYmIFsgLWYgIiRIT01FLy5sb2NhbC9zaGFyZS93aGVyZHIvZWRpdG9yIiBdOyB0aGVuCiAgICBlZD0kKGhlYWQgLW4xICIkSE9NRS8ubG9jYWwvc2hhcmUvd2hlcmRyL2VkaXRvciIgfCB0ciAtZCAnWzpzcGFjZTpdJykKICBmaQogIGlmIFsgLWQgIiRyIiBdICYmIFsgLW4gIiRlZCIgXTsgdGhlbgogICAgb3BlbiAtYSAiJGVkIiAiJHIiIHx8IGV4aXQgNgogIGVsc2UKICAgIG9wZW4gIiRyIiB8fCBleGl0IDYKICBmaQplbHNlCiAgb3BlbiAtUiAiJHIiIHx8IGV4aXQgNgpmaQplY2hvICIkciIK");
|
|
5
5
|
|
|
6
6
|
export { reveal as default };
|
|
7
7
|
//# sourceMappingURL=reveal.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const testAffected = "#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { pathToFileURL, fileURLToPath } from 'node:url'\nimport net from 'node:net'\n\n// Reviewed supplements to Vitest's import graph: Nuxt auto-imports, templates,\n// CSS and transport boundaries are not ordinary static imports.\nexport const domains = [\n { name: 'references', source: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText)/i, tests: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText|quote)/i, e2e: ['reference', 'send-message'], reason: 'References cross templates, composer state and the send boundary.' },\n { name: 'guards', source: /(?:server\\/api\\/(?:prompt|input|choose|menu|nav)|Identity|guardedSend)/i, tests: /(?:guard|Identity|stoppedAgent|agentPrompt|menuRoute)/i, e2e: ['pane-replaced', 'question-reply'], reason: 'Identity and stale actions must be checked through transport.' },\n { name: 'terminal', source: /terminal|server\\/routes\\/.*ws/i, tests: /terminal/i, e2e: ['interactive-terminal', 'terminal-size'], reason: 'Terminal rendering and websocket lifecycle cross the built app.' },\n { name: 'board', source: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, tests: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, e2e: ['machine-groups', 'projects-1x'], reason: 'Board auto-imports and cross-machine navigation need explicit coverage.' },\n { name: 'startup', source: /router|app\\.vue|onboarding|app\\/plugins/i, tests: /onboarding|directRoute|stateReady/i, e2e: ['startup-hash', 'onboarding'], reason: 'Startup and routing depend on Nuxt registration.' },\n { name: 'appearance', source: /app\\/assets\\/|themes?\\.|font/i, tests: /layout|sheet|CompactDefault|ChatViewRendering|SettingsTyping|Composer|BoardPanel/i, e2e: ['theme', 'sheet-close'], reason: 'CSS and themes affect layout and overlays without import edges.' },\n { name: 'chat-rendering', source: /ChatView|OmpTool|Settings/i, tests: /ChatViewRendering|CompactDefault|SettingsTyping|OmpTool|settings/i, e2e: ['settings-tabs', 'tool-images'], reason: 'Rendering assertions moved from e2e to components; retain integration boundaries.' },\n]\nconst doc = p => /\\.(md|rst)$/.test(p) || /^docs\\//.test(p)\nconst test = p => /\\.test\\.[cm]?[jt]s$/.test(p)\nconst e2e = p => /^tests\\/e2e\\/.*\\.spec\\.ts$/.test(p)\nexport const literalPattern = p => p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\nexport function parseChanges(output) {\n const fields = output.split('\\0'); const paths = []\n for (let i = 0; i < fields.length && fields[i];) {\n const status = fields[i++]\n paths.push(fields[i++])\n if (/^[RC]/.test(status)) paths.push(fields[i++])\n }\n return paths.filter(Boolean)\n}\nfunction git(args, cwd) {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' })\n if (result.status !== 0) throw new Error(result.stderr.trim() || 'Git command failed')\n return result.stdout\n}\nexport function changedFiles(base, cwd = process.cwd()) {\n let warning\n let committed = []\n try {\n const ancestor = git(['merge-base', 'HEAD', base], cwd).trim()\n committed = parseChanges(git(['diff', '--name-status', '-z', '--find-renames', ancestor, 'HEAD', '--'], cwd))\n } catch {\n warning = `Cannot resolve merge-base with ${base}; fetch the target branch. Selecting broad coverage.`\n }\n return {\n warning,\n files: [...new Set([...committed,\n ...parseChanges(git(['diff', '--name-status', '-z', '--find-renames', 'HEAD', '--'], cwd)),\n ...parseChanges(git(['diff', '--cached', '--name-status', '-z', '--find-renames', '--'], cwd)),\n ...git(['ls-files', '--others', '--exclude-standard', '-z'], cwd).split('\\0').filter(Boolean),\n ])].sort(),\n }\n}\nexport function inventory(dir = 'tests') {\n return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {\n const p = `${dir}/${entry.name}`\n return entry.isDirectory() ? inventory(p) : [p]\n })\n}\nexport function select(files, available, warning) {\n const unit = new Map(); const browser = new Map(); const selectedDomains = new Map(); const related = []\n let broad = Boolean(warning)\n const add = (map, p, reason) => map.set(p, [...new Set([...(map.get(p) || []), reason])])\n for (const file of files) {\n if (doc(file)) continue\n if ((test(file) || e2e(file)) && available.includes(file)) {\n add(e2e(file) ? browser : unit, file, 'Changed test: run explicitly.'); continue\n }\n const matches = domains.filter(d => d.source.test(file))\n if (!matches.length || /(?:package(?:-lock)?\\.json|(?:nuxt|vitest|playwright)\\.config|tests\\/e2e\\/|app\\/plugins\\/|transport)/.test(file)) broad = true\n if (available.includes(file) && !test(file) && !e2e(file)) related.push(file)\n for (const d of matches) {\n selectedDomains.set(d.name, d.reason)\n for (const p of available) {\n if (test(p) && d.tests.test(p)) add(unit, p, d.reason)\n if (d.e2e.some(name => p === `tests/e2e/${name}.spec.ts`)) add(browser, p, d.reason)\n }\n }\n }\n if (broad) {\n const reason = warning || 'Unknown, deleted test or shared infrastructure: conservative fallback.'\n selectedDomains.set('fallback', reason)\n for (const p of available) if (test(p)) add(unit, p, reason)\n const smoke = 'tests/e2e/startup-hash.spec.ts'\n if (available.includes(smoke)) add(browser, smoke, reason)\n }\n if (files.some(p => !doc(p)) && !unit.size && !browser.size) throw new Error('Unexpected empty selection; update the domain table.')\n return { files, domains: Object.fromEntries(selectedDomains), related: broad ? [] : related, tests: Object.fromEntries(unit), e2e: Object.fromEntries(browser), broad, warning }\n}\nfunction assertFocusedE2E(specs) {\n const all = inventory().filter(e2e)\n if (all.length > 1 && all.every(p => specs.includes(p))) {\n throw new Error('Refusing the full Playwright suite locally; leave it to CI and review a smaller selection.')\n }\n}\nfunction run(command, args, env = process.env) {\n const result = spawnSync('flock', ['/tmp/wherdr-heavy.lock', command, ...args], { stdio: 'inherit', env })\n if (result.error) throw result.error\n if (result.status !== 0) throw new Error(`${command} failed (${result.status ?? result.signal})`)\n}\nasync function freePort() {\n for (let port = 7690; port <= 7699; port++) {\n const free = await new Promise(resolve => {\n const server = net.createServer()\n server.once('error', () => resolve(false))\n server.listen(port, '127.0.0.1', () => server.close(() => resolve(true)))\n })\n if (free) return String(port)\n }\n throw new Error('No free E2E_PORT in 7690–7699')\n}\nexport async function main(args = process.argv.slice(2)) {\n let base; let dry = false; let project = 'chromium-phone'\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--base') base = args[++i]\n else if (args[i] === '--dry-run') dry = true\n else if (args[i] === '--safari') project = 'webkit-phone'\n else throw new Error(`Unknown option: ${args[i]}`)\n }\n if (!base || base.startsWith('-')) throw new Error('Usage: npm run test:affected -- --base <target-branch> [--dry-run] [--safari]')\n const changes = changedFiles(base)\n const plan = select(changes.files, [...new Set([...inventory(), ...changes.files.filter(p => existsSync(p))])], changes.warning)\n console.log(JSON.stringify({ ...plan, project }, null, 2))\n if (plan.broad) console.log('CI must run the complete reduced suite. Local fallback adds all Vitest tests and a startup e2e smoke; review additional journeys manually.')\n if (!plan.files.length && !plan.warning) console.log('No changed files.')\n else if (!Object.keys(plan.tests).length && !Object.keys(plan.e2e).length) console.log('Documentation only: no tests or browser required.')\n if (dry) return\n assertFocusedE2E(Object.keys(plan.e2e))\n const tests = Object.keys(plan.tests)\n // Explicit domain tests run once below; related supplies only additional tests.\n // An empty related graph is allowed because explicit coverage is already selected.\n if (plan.related.length) run('npx', ['--no-install', 'vitest', 'related', '--run', '--passWithNoTests', ...tests.flatMap(p => ['--exclude', p]), ...plan.related.map(p => `./${p}`)])\n if (tests.length) run('npx', ['--no-install', 'vitest', 'run', ...tests])\n const specs = Object.keys(plan.e2e)\n if (specs.length) {\n const env = { ...process.env, E2E_SCOPE: 'full' }\n // One lock covers build and browser run, including the shared .e2e-tmp directory.\n run(process.execPath, [fileURLToPath(import.meta.url), '--execute-e2e', project, ...specs], env)\n }\n}\nif (process.argv[2] === '--execute-e2e') {\n const [, , , project, ...specs] = process.argv\n if (!['chromium-phone', 'webkit-phone'].includes(project) || !specs.length || specs.some(p => !e2e(p) || !existsSync(p))) {\n console.error('Refusing an empty or invalid e2e selection.'); process.exit(1)\n }\n assertFocusedE2E(specs)\n const build = spawnSync('npm', ['run', 'build'], { stdio: 'inherit' })\n if (build.status !== 0) process.exit(build.status || 1)\n const port = await freePort()\n const result = spawnSync('npx', ['--no-install', 'playwright', 'test', ...specs.map(p => `${literalPattern(p)}$`), '--project', project], { stdio: 'inherit', env: { ...process.env, E2E_PORT: port } })\n process.exit(result.status ?? 1)\n} else if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {\n main().catch(error => { console.error(error.message); process.exitCode = 1 })\n}\n";
|
|
3
|
+
|
|
4
|
+
export { testAffected as default };
|
|
5
|
+
//# sourceMappingURL=test-affected.mjs.map
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const _____ = defineEventHandler((event) => sendError(event, 404, { error: "Not found" }));
|
|
33
34
|
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const agents_post = defineApi((event, b) => createAgent(b));
|
|
33
34
|
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const askTab_post = defineApi(async (event, b) => {
|
|
33
34
|
var _a;
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const attach_post = defineApi((event, b) => {
|
|
33
34
|
const q = getQuery(event);
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const disable_post = defineApi((event) => auth.disable(reqOf(event)));
|
|
33
34
|
|
|
@@ -16,18 +16,19 @@ import 'node:events';
|
|
|
16
16
|
import 'node:buffer';
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
|
-
import 'web-push';
|
|
20
19
|
import 'node:os';
|
|
21
|
-
import 'node:child_process';
|
|
22
20
|
import 'node:net';
|
|
23
|
-
import 'node:
|
|
24
|
-
import 'node:readline';
|
|
21
|
+
import 'node:child_process';
|
|
25
22
|
import 'node:dns';
|
|
26
23
|
import 'node:util';
|
|
24
|
+
import 'web-push';
|
|
25
|
+
import 'node:string_decoder';
|
|
26
|
+
import 'node:fs/promises';
|
|
27
|
+
import 'node:readline';
|
|
27
28
|
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
28
29
|
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
29
|
-
import '@simplewebauthn/server';
|
|
30
30
|
import 'node:url';
|
|
31
|
+
import '@simplewebauthn/server';
|
|
31
32
|
|
|
32
33
|
const lockAll_post = defineApi((event) => auth.lockAll(reqOf(event)));
|
|
33
34
|
|