wherdr 2.4.0 → 2.6.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/{CPlkxpge.js → 2fsYF-LK.js} +41 -41
- package/.output/public/_nuxt/2fsYF-LK.js.br +0 -0
- package/.output/public/_nuxt/2fsYF-LK.js.gz +0 -0
- package/.output/public/_nuxt/{CV6ukk-M.js → 3bE7s96N.js} +1 -1
- package/.output/public/_nuxt/6YTlf8ot.js +1 -0
- package/.output/public/_nuxt/6YTlf8ot.js.br +0 -0
- package/.output/public/_nuxt/6YTlf8ot.js.gz +0 -0
- package/.output/public/_nuxt/{BYZVrreW.js → 7KozZy5Y.js} +1 -1
- package/.output/public/_nuxt/AgentView.BwyQIUef.css +1 -0
- package/.output/public/_nuxt/AgentView.BwyQIUef.css.br +0 -0
- package/.output/public/_nuxt/AgentView.BwyQIUef.css.gz +0 -0
- package/.output/public/_nuxt/{BdJIc1Xf.js → B40shTLf.js} +1 -1
- package/.output/public/_nuxt/{BdJIc1Xf.js.br → B40shTLf.js.br} +0 -0
- package/.output/public/_nuxt/B40shTLf.js.gz +0 -0
- package/.output/public/_nuxt/B5cSia3P.js +62 -0
- package/.output/public/_nuxt/B5cSia3P.js.br +0 -0
- package/.output/public/_nuxt/B5cSia3P.js.gz +0 -0
- package/.output/public/_nuxt/BK1_9FXg.js +1 -0
- package/.output/public/_nuxt/BK1_9FXg.js.br +0 -0
- package/.output/public/_nuxt/BK1_9FXg.js.gz +0 -0
- package/.output/public/_nuxt/{CgUSTIM1.js → Bqz3nVVB.js} +1 -1
- package/.output/public/_nuxt/{CgUSTIM1.js.br → Bqz3nVVB.js.br} +0 -0
- package/.output/public/_nuxt/Bqz3nVVB.js.gz +0 -0
- package/.output/public/_nuxt/{B2KlcBQ-.js → ByLPJEo6.js} +1 -1
- package/.output/public/_nuxt/ByLPJEo6.js.br +0 -0
- package/.output/public/_nuxt/ByLPJEo6.js.gz +0 -0
- package/.output/public/_nuxt/C8tHIeGN.js +3 -0
- package/.output/public/_nuxt/C8tHIeGN.js.br +0 -0
- package/.output/public/_nuxt/C8tHIeGN.js.gz +0 -0
- package/.output/public/_nuxt/CAkH_IfS.js +9 -0
- package/.output/public/_nuxt/CAkH_IfS.js.br +0 -0
- package/.output/public/_nuxt/CAkH_IfS.js.gz +0 -0
- package/.output/public/_nuxt/COWXF9OU.js +123 -0
- package/.output/public/_nuxt/COWXF9OU.js.br +0 -0
- package/.output/public/_nuxt/COWXF9OU.js.gz +0 -0
- package/.output/public/_nuxt/{BDTOz37p.js → CiG2Lovu.js} +1 -1
- package/.output/public/_nuxt/CiG2Lovu.js.br +0 -0
- package/.output/public/_nuxt/CiG2Lovu.js.gz +0 -0
- package/.output/public/_nuxt/CnjxEm0H.js +27 -0
- package/.output/public/_nuxt/CnjxEm0H.js.br +0 -0
- package/.output/public/_nuxt/CnjxEm0H.js.gz +0 -0
- package/.output/public/_nuxt/DNs2cMBZ.js +23 -0
- package/.output/public/_nuxt/DNs2cMBZ.js.br +0 -0
- package/.output/public/_nuxt/DNs2cMBZ.js.gz +0 -0
- package/.output/public/_nuxt/D_x7Rysx.js +31 -0
- package/.output/public/_nuxt/D_x7Rysx.js.br +0 -0
- package/.output/public/_nuxt/D_x7Rysx.js.gz +0 -0
- package/.output/public/_nuxt/{CLf2i_DM.js → T-qXNaMY.js} +1 -1
- package/.output/public/_nuxt/{board.fZYj3O-m.css → board.CpFnG_Ho.css} +1 -1
- package/.output/public/_nuxt/board.CpFnG_Ho.css.br +0 -0
- package/.output/public/_nuxt/board.CpFnG_Ho.css.gz +0 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/e2ee8d99-6a6a-4754-934f-8b7dbecfcdcb.json +1 -0
- package/.output/public/_nuxt/entry.C_hImCpq.css +2 -0
- package/.output/public/_nuxt/entry.C_hImCpq.css.br +0 -0
- package/.output/public/_nuxt/entry.C_hImCpq.css.gz +0 -0
- package/.output/public/_nuxt/{settings.Cdb21nNw.css → settings.ycbeituV.css} +1 -1
- package/.output/public/_nuxt/settings.ycbeituV.css.br +0 -0
- package/.output/public/_nuxt/settings.ycbeituV.css.gz +0 -0
- package/.output/public/_nuxt/useViewport.D9mmYA6A.css +1 -0
- package/.output/public/_nuxt/useWorktrees.BWpb3OO0.css +1 -0
- package/.output/public/_nuxt/useWorktrees.BWpb3OO0.css.br +0 -0
- package/.output/public/_nuxt/useWorktrees.BWpb3OO0.css.gz +0 -0
- package/.output/public/sw.js +6 -2
- package/.output/server/chunks/_/branding.mjs +1 -1
- package/.output/server/chunks/_/fileDownload.mjs +1 -1
- package/.output/server/chunks/_/files.mjs +26 -3
- package/.output/server/chunks/_/machineOrder.mjs +1 -1
- package/.output/server/chunks/_/onboarding.mjs +1 -1
- package/.output/server/chunks/_/package.mjs +1 -1
- package/.output/server/chunks/_/plugins.mjs +1 -1
- package/.output/server/chunks/_/restart.mjs +1 -1
- package/.output/server/chunks/_/revoke.mjs +22 -0
- package/.output/server/chunks/_/selfupdate.mjs +2 -1
- package/.output/server/chunks/_/splitShell.mjs +42 -0
- package/.output/server/chunks/_/updates.mjs +18 -4
- package/.output/server/chunks/_/uploadHashes.mjs +46 -0
- package/.output/server/chunks/_/worktrees.mjs +1 -1
- package/.output/server/chunks/_/ws.mjs +3 -3
- package/.output/server/chunks/nitro/nitro.mjs +15815 -15082
- package/.output/server/chunks/raw/check-leaks.mjs +1 -1
- package/.output/server/chunks/raw/ci-browser-plan.mjs +5 -0
- package/.output/server/chunks/raw/engine-changes.mjs +5 -0
- package/.output/server/chunks/raw/engine-result.mjs +7 -0
- package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
- package/.output/server/chunks/raw/prerelease.mjs +1 -1
- package/.output/server/chunks/raw/test-affected.mjs +1 -1
- package/.output/server/chunks/routes/api/_..._.mjs +5 -5
- package/.output/server/chunks/routes/api/agents.post.mjs +5 -5
- package/.output/server/chunks/routes/api/ask-tab.post.mjs +5 -5
- package/.output/server/chunks/routes/api/attach.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/disable.post.mjs +14 -7
- package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +12 -6
- package/.output/server/chunks/routes/api/auth/lock.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/login/options.post.mjs +7 -7
- package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/max-session.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/register/options.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +5 -5
- package/.output/server/chunks/routes/api/auth/status.get.mjs +10 -10
- package/.output/server/chunks/routes/api/changes.get.mjs +6 -6
- package/.output/server/chunks/routes/api/chat/image.get.mjs +6 -6
- package/.output/server/chunks/routes/api/chat.get.mjs +20 -49
- package/.output/server/chunks/routes/api/choose.post.mjs +6 -6
- package/.output/server/chunks/routes/api/claude-setup.post.mjs +6 -6
- package/.output/server/chunks/routes/api/claude-statusline.post.mjs +6 -6
- package/.output/server/chunks/routes/api/clear-queued-input.post.mjs +6 -6
- package/.output/server/chunks/routes/api/close/status.get.mjs +6 -6
- package/.output/server/chunks/routes/api/close-preview.get.mjs +62 -0
- package/.output/server/chunks/routes/api/close.post.mjs +5 -5
- package/.output/server/chunks/routes/api/codex-update.post.mjs +6 -6
- package/.output/server/chunks/routes/api/commands.get.mjs +6 -6
- package/.output/server/chunks/routes/api/config.get.mjs +6 -6
- package/.output/server/chunks/routes/api/dirs.get.mjs +6 -6
- package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +6 -6
- package/.output/server/chunks/routes/api/dismiss.post.mjs +6 -6
- package/.output/server/chunks/routes/api/effort.post.mjs +6 -6
- package/.output/server/chunks/routes/api/efforts.get.mjs +6 -6
- package/.output/server/chunks/routes/api/file.post.mjs +6 -6
- package/.output/server/chunks/routes/api/files/download.get.mjs +5 -5
- package/.output/server/chunks/routes/api/files/download.head.mjs +5 -5
- package/.output/server/chunks/routes/api/files/read.get.mjs +6 -6
- package/.output/server/chunks/routes/api/files.get.mjs +6 -6
- package/.output/server/chunks/routes/api/health.get.mjs +5 -5
- package/.output/server/chunks/routes/api/input.post.mjs +6 -6
- package/.output/server/chunks/routes/api/interrupt.post.mjs +6 -6
- package/.output/server/chunks/routes/api/isgit.get.mjs +6 -6
- package/.output/server/chunks/routes/api/machine/awake.get.mjs +6 -6
- package/.output/server/chunks/routes/api/machine/awake.post.mjs +6 -6
- package/.output/server/chunks/routes/api/machine/order.get.mjs +5 -5
- package/.output/server/chunks/routes/api/machine/order.post.mjs +5 -5
- package/.output/server/chunks/routes/api/machine/reconnect.post.mjs +6 -6
- package/.output/server/chunks/routes/api/machine/rename.post.mjs +6 -6
- package/.output/server/chunks/routes/api/machine/status.post.mjs +6 -6
- package/.output/server/chunks/routes/api/menu-left.post.mjs +6 -6
- package/.output/server/chunks/routes/api/menu.post.mjs +6 -6
- package/.output/server/chunks/routes/api/model.post.mjs +6 -6
- package/.output/server/chunks/routes/api/models.get.mjs +6 -6
- package/.output/server/chunks/routes/api/nav.post.mjs +6 -6
- package/.output/server/chunks/routes/api/onboarding.get.mjs +5 -5
- package/.output/server/chunks/routes/api/onboarding.post.mjs +5 -5
- package/.output/server/chunks/routes/api/phone.get.mjs +6 -6
- package/.output/server/chunks/routes/api/phone.post.mjs +6 -6
- package/.output/server/chunks/routes/api/plugins/actions.get.mjs +5 -5
- package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +5 -5
- package/.output/server/chunks/routes/api/plugins/projects.get.mjs +6 -6
- package/.output/server/chunks/routes/api/plugins/projects.post.mjs +6 -6
- package/.output/server/chunks/routes/api/prompt.post.mjs +6 -6
- package/.output/server/chunks/routes/api/push/devices.post.mjs +49 -0
- package/.output/server/chunks/routes/api/push/quiet.post.mjs +6 -6
- package/.output/server/chunks/routes/api/push/subscribe.post.mjs +8 -7
- package/.output/server/chunks/routes/api/push/test.post.mjs +6 -6
- package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +6 -6
- package/.output/server/chunks/routes/api/quotas.get.mjs +6 -6
- package/.output/server/chunks/routes/api/rename.post.mjs +5 -5
- package/.output/server/chunks/routes/api/requeue.post.mjs +6 -6
- package/.output/server/chunks/routes/api/restart.get.mjs +5 -5
- package/.output/server/chunks/routes/api/restart.post.mjs +5 -5
- package/.output/server/chunks/routes/api/reveal.post.mjs +6 -6
- package/.output/server/chunks/routes/api/screen-key.post.mjs +6 -6
- package/.output/server/chunks/routes/api/screen.get.mjs +6 -6
- package/.output/server/chunks/routes/api/search.get.mjs +6 -6
- package/.output/server/chunks/routes/api/seen.post.mjs +6 -6
- package/.output/server/chunks/routes/api/send-now.post.mjs +6 -6
- package/.output/server/chunks/routes/api/sessions.get.mjs +6 -6
- package/.output/server/chunks/routes/api/sessions.post.mjs +6 -6
- package/.output/server/chunks/routes/api/settings-tab.post.mjs +6 -6
- package/.output/server/chunks/routes/api/settings.get.mjs +6 -6
- package/.output/server/chunks/routes/api/settings.post.mjs +6 -6
- package/.output/server/chunks/routes/api/space.post.mjs +6 -6
- package/.output/server/chunks/routes/api/split-command.post.mjs +9 -44
- package/.output/server/chunks/routes/api/state.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/action.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/add.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/after.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/approve.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/archive-done.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/archived.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/autopilot.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/autopilot.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/board-settings.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/board-settings.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/coordinator.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/coordinator.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/describe.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/details.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/limit.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/links.get.mjs +7 -7
- package/.output/server/chunks/routes/api/tasks/models.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/pick.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/project.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/project.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/question.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/scheduled.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/settings.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/start.get.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/tell.post.mjs +6 -6
- package/.output/server/chunks/routes/api/tasks/transcript-image.get.mjs +47 -0
- package/.output/server/chunks/routes/api/tasks/transcript.get.mjs +48 -0
- package/.output/server/chunks/routes/api/tasks.get.mjs +6 -6
- package/.output/server/chunks/routes/api/unqueue.post.mjs +6 -6
- package/.output/server/chunks/routes/api/update/status.get.mjs +5 -5
- package/.output/server/chunks/routes/api/update.get.mjs +5 -5
- package/.output/server/chunks/routes/api/update.post.mjs +5 -5
- package/.output/server/chunks/routes/api/upload.post.mjs +6 -6
- package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +5 -5
- package/.output/server/chunks/routes/api/worktrees.get.mjs +5 -5
- package/.output/server/chunks/routes/favicon.ico.get.mjs +5 -5
- package/.output/server/chunks/routes/icons/_name_.get.mjs +6 -6
- package/.output/server/chunks/routes/renderer.mjs +7 -7
- package/.output/server/chunks/routes/uploads/_...name_.get.mjs +6 -6
- package/.output/server/chunks/routes/ws/_..._.mjs +6 -6
- package/.output/server/chunks/routes/ws/events.mjs +6 -6
- package/.output/server/chunks/routes/ws/term.mjs +6 -6
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +6 -6
- package/.output/server/package.json +1 -1
- package/README.md +1 -1
- package/bin/lib/tailnet.d.mts +7 -4
- package/bin/lib/tailnet.mjs +76 -18
- package/bin/lib/updater.mjs +6 -0
- package/docs/README.md +4 -0
- package/docs/RELEASING.md +27 -5
- package/docs/configuration.md +3 -4
- package/docs/conversation.md +11 -3
- package/docs/design.md +1 -1
- package/docs/devices.md +28 -0
- package/docs/home.md +29 -0
- package/docs/installation.md +14 -5
- package/docs/networks.md +9 -4
- package/docs/notifications.md +7 -0
- package/docs/plugins.md +1 -1
- package/docs/quick-start.md +7 -6
- package/docs/quotas.md +10 -1
- package/docs/release-notes-2.5.0.md +25 -0
- package/docs/release-notes-2.6.0.md +29 -0
- package/docs/security.md +61 -11
- package/docs/troubleshooting.md +4 -0
- package/package.json +1 -1
- package/skills/wherdr/SKILL.md +21 -0
- package/.output/public/_nuxt/AgentView.B12D6ccj.css +0 -1
- package/.output/public/_nuxt/AgentView.B12D6ccj.css.br +0 -0
- package/.output/public/_nuxt/AgentView.B12D6ccj.css.gz +0 -0
- package/.output/public/_nuxt/B2KlcBQ-.js.br +0 -0
- package/.output/public/_nuxt/B2KlcBQ-.js.gz +0 -0
- package/.output/public/_nuxt/BDTOz37p.js.br +0 -0
- package/.output/public/_nuxt/BDTOz37p.js.gz +0 -0
- package/.output/public/_nuxt/BGD5AamG.js +0 -25
- package/.output/public/_nuxt/BGD5AamG.js.br +0 -0
- package/.output/public/_nuxt/BGD5AamG.js.gz +0 -0
- package/.output/public/_nuxt/BdJIc1Xf.js.gz +0 -0
- package/.output/public/_nuxt/BxlzUs1i.js +0 -23
- package/.output/public/_nuxt/BxlzUs1i.js.br +0 -0
- package/.output/public/_nuxt/BxlzUs1i.js.gz +0 -0
- package/.output/public/_nuxt/C-BDzEtI.js +0 -3
- package/.output/public/_nuxt/C-BDzEtI.js.br +0 -0
- package/.output/public/_nuxt/C-BDzEtI.js.gz +0 -0
- package/.output/public/_nuxt/CO4sDeSt.js +0 -62
- package/.output/public/_nuxt/CO4sDeSt.js.br +0 -0
- package/.output/public/_nuxt/CO4sDeSt.js.gz +0 -0
- package/.output/public/_nuxt/CPlkxpge.js.br +0 -0
- package/.output/public/_nuxt/CPlkxpge.js.gz +0 -0
- package/.output/public/_nuxt/CTPNZj4T.js +0 -9
- package/.output/public/_nuxt/CTPNZj4T.js.br +0 -0
- package/.output/public/_nuxt/CTPNZj4T.js.gz +0 -0
- package/.output/public/_nuxt/CgUSTIM1.js.gz +0 -0
- package/.output/public/_nuxt/CwurhZnh.js +0 -123
- package/.output/public/_nuxt/CwurhZnh.js.br +0 -0
- package/.output/public/_nuxt/CwurhZnh.js.gz +0 -0
- package/.output/public/_nuxt/D7fCPncR.js +0 -1
- package/.output/public/_nuxt/D7fCPncR.js.br +0 -0
- package/.output/public/_nuxt/D7fCPncR.js.gz +0 -0
- package/.output/public/_nuxt/DFe-cDm2.js +0 -1
- package/.output/public/_nuxt/DFe-cDm2.js.br +0 -0
- package/.output/public/_nuxt/DFe-cDm2.js.gz +0 -0
- package/.output/public/_nuxt/Dpe9TNcA.js +0 -31
- package/.output/public/_nuxt/Dpe9TNcA.js.br +0 -0
- package/.output/public/_nuxt/Dpe9TNcA.js.gz +0 -0
- package/.output/public/_nuxt/board.fZYj3O-m.css.br +0 -0
- package/.output/public/_nuxt/board.fZYj3O-m.css.gz +0 -0
- package/.output/public/_nuxt/builds/meta/75cc4ea7-3027-463a-aa3e-29e474ed7173.json +0 -1
- package/.output/public/_nuxt/entry.KNdllmoL.css +0 -2
- package/.output/public/_nuxt/entry.KNdllmoL.css.br +0 -0
- package/.output/public/_nuxt/entry.KNdllmoL.css.gz +0 -0
- package/.output/public/_nuxt/settings.Cdb21nNw.css.br +0 -0
- package/.output/public/_nuxt/settings.Cdb21nNw.css.gz +0 -0
|
@@ -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 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";
|
|
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 // Index scans run on a temporary export, outside the repository config discovery.\n const config = path.join(root ?? git(['rev-parse', '--show-toplevel']).trim(), '.gitleaks.toml')\n if (existsSync(config)) opts.push('--config', config)\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 ciBrowserPlan = "#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nexport function browserPlan(event, ref) {\n const scope = event === 'schedule' || event === 'workflow_dispatch' || ref.startsWith('refs/tags/') ? 'full' : 'light'\n const include = []\n // Recent light PR runs: Chromium phone 211–284 s/shard with four shards,\n // WebKit phone 199–239 s unsharded, before npm/build/browser preparation.\n for (const [project, count] of [['chromium-phone', 6], ['webkit-phone', 2]]) {\n for (let n = 1; n <= count; n++) include.push({ project, shard: `${n}/${count}` })\n }\n include.push({ project: 'chromium-desktop' }, { project: 'webkit-desktop' })\n return { scope, matrix: { include } }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const plan = browserPlan(process.env.EVENT, process.env.REF)\n for (const [key, value] of Object.entries(plan)) console.log(`${key}=${typeof value === 'string' ? value : JSON.stringify(value)}`)\n}\n";
|
|
3
|
+
|
|
4
|
+
export { ciBrowserPlan as default };
|
|
5
|
+
//# sourceMappingURL=ci-browser-plan.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const engineChanges = "#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { appendFileSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\n\n// Keep engine inputs here, alongside the filter regression tests. Release assembly\n// is added by later distribution work; these paths already require engine checks.\nexport function needsEngine(paths) {\n return paths.some(p => /^(engine|packages|skills\\/wherdr-board|tests\\/recordings\\/wherdr-board)\\//.test(p)\n || /^(package(?:-lock)?\\.json|herdr-plugin\\.toml)$/.test(p)\n || /^(bin|scripts)\\/.*(?:board|runtime|userpath|pack|updat|version|release|engine)/.test(p)\n || /^shared\\/projectsPlugin\\.ts$|^server\\/utils\\/(?:projects(?:Tasks|Plugin)|boardLinks)\\.ts$/.test(p)\n || /^tests\\/.*(?:[Bb]oard|[Pp]rojects|[Pp]lugin|[Mm]igration|[Cc]ohabitation|[Dd]istribution|engine)/.test(p)\n || /^\\.github\\/workflows\\/(?:ci|engine-.*|release.*|develop-prerelease|npm)\\.yml$/.test(p))\n}\n\nexport function engineDecision(event, before, cwd = process.cwd()) {\n if (!['pull_request', 'push'].includes(event)) return true\n const base = event === 'pull_request' ? 'HEAD^1' : before\n if (!base || /^0+$/.test(base)) return true\n // No rename detection: a move is a deletion plus addition, including both\n // sides of moves across engine/. NUL separation preserves unusual filenames.\n const diff = spawnSync('git', ['diff', '--no-renames', '--name-only', '-z', base, 'HEAD', '--'], { cwd, encoding: 'utf8' })\n if (diff.status !== 0) return true\n return needsEngine(diff.stdout.split('\\0').filter(Boolean))\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const needed = engineDecision(process.env.EVENT, process.env.BEFORE)\n console.log(`Engine checks needed: ${needed}`)\n appendFileSync(process.env.GITHUB_OUTPUT, `engine=${needed}\\n`)\n}\n";
|
|
3
|
+
|
|
4
|
+
export { engineChanges as default };
|
|
5
|
+
//# sourceMappingURL=engine-changes.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
|
+
|
|
3
|
+
// ROLLUP_NO_REPLACE
|
|
4
|
+
const engineResult = base64ToUint8Array("IyEvYmluL3NoCnNldCAtZXUKWyAiJENIQU5HRVMiID0gc3VjY2VzcyBdIHx8IGV4aXQgMQpjYXNlICIkTkVFREVEOiRFTkdJTkUiIGluCiAgZmFsc2U6c2tpcHBlZCkgZWNobyAiTm8gZW5naW5lIGlucHV0IGNoYW5nZWQuIiA7OwogIHRydWU6c3VjY2VzcykgZWNobyAiRXZlcnkgZW5naW5lIGNoZWNrIHBhc3NlZC4iIDs7CiAgKikgZWNobyAiRW5naW5lIGNoZWNrcyBkaWQgbm90IHBhc3M6IG5lZWRlZD0kTkVFREVELCByZXN1bHQ9JEVOR0lORSI7IGV4aXQgMSA7Owplc2FjCg==");
|
|
5
|
+
|
|
6
|
+
export { engineResult as default };
|
|
7
|
+
//# sourceMappingURL=engine-result.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+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==");
|
|
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+LnRzLm5ldFs6cG9ydF0pLCBvbmx5IHdoZW4gaXQgYW5zd2VycyBsaWtlCiMgd2hlcmRyLiBQYXNza2V5cyBhcmUgdGllZCB0byB0aGUgYWRkcmVzczogdGhhdCBpcyB0aGUgb25lIHRvIG9wZW4uCnRhaWxuZXRfYWRkcmVzcygpIHsKICBjb21tYW5kIC12IGN1cmwgPi9kZXYvbnVsbCAyPiYxIHx8IHJldHVybiAxCiAgaG9zdD0iJChzZXJ2ZWRfaG9zdCkiIHx8IHJldHVybiAxCiAgWyAiJChwaG9uZV9yZWFjaCAiaHR0cHM6Ly8kaG9zdC8iKSIgPSBvayBdIHx8IHJldHVybiAxCiAgcHJpbnRmICdodHRwczovLyVzXG4nICIkaG9zdCIKfQoKIyBUaGUgYWRkcmVzcyB0byBvcGVuOiB0aGUgdGFpbG5ldCBvbmUgd2hlbiBwdWJsaXNoZWQgYW5kIGFuc3dlcmluZywgZWxzZSBsb2NhbGhvc3QuCm9wZW5fYWRkcmVzcygpIHsgdGFpbG5ldF9hZGRyZXNzIHx8IHByaW50ZiAnJXNcbicgIiRVUkwiOyB9CgpjbWRfb3BlbigpIHsKICBhZGRyZXNzPSIkKG9wZW5fYWRkcmVzcykiCiAgb3Blbl9icm93c2VyICIkYWRkcmVzcyIgfHwgdHJ1ZQogIHNheSAiJGFkZHJlc3MiCn0KCiMgYGFkZHJlc3NgOiB3aGF0IGBvcGVuYCB3b3VsZCBvcGVuLCB3aXRob3V0IG9wZW5pbmcgaXQgKGh0dHBzOi8vd2hlcmRyLmRldi9pbnN0YWxsKS4KY21kX2FkZHJlc3MoKSB7IG9wZW5fYWRkcmVzczsgfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB1cGRhdGUKIyBGcm9tIHRoZSByZWxlYXNlIGJyYW5jaCBvZiB0aGlzIG1ham9yIChgMi54YCksIG5ldmVyIGBtYWluYCwgd2hpY2ggaG9sZHMgdGhlCiMgbmV4dCBtYWpvci4KY21kX3VwZGF0ZSgpIHsKICBtYWpvcj0iJChzZWQgLW4gJ3MvXnZlcnNpb24gPSAiXChbMC05XSpcKVwuLioiJC9cMS9wJyAiJFJPT1QvaGVyZHItcGx1Z2luLnRvbWwiIHwgaGVhZCAtbiAxKSIKICBzYXkgIlVwZGF0aW5nIHRoZSB3aGVyZHIgcGx1Z2luIGZyb20gJHtTT1VSQ0V9ICgke21ham9yfS54KeKApiIKICAiJChoZXJkcl9iaW4pIiBwbHVnaW4gaW5zdGFsbCAiJFNPVVJDRSIgLS1yZWYgIiR7bWFqb3J9LngiIC0teWVzCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHBob25lCiMgUGhvbmUgc2V0dXAgdXNlcyB0aGUgbmF0aXZlIGNvbW1hbmQuCmNtZF9waG9uZSgpIHsgY2xpIHBob25lOyB9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBzZXJ2aWNlCmNtZF9zZXJ2aWNlKCkgewogIGNhc2UgIiR7MTotfSIgaW4gaW5zdGFsbHx1bmluc3RhbGwpIDs7ICopIGRpZSAidXNhZ2U6ICQwIHNlcnZpY2UgaW5zdGFsbHx1bmluc3RhbGwiIDs7IGVzYWMKICBjbGkgc2VydmljZSAiJDEiCiAgIyBXaXRob3V0IHRoZSBzZXJ2aWNlLCB0aGUgcGx1Z2luIHJ1bnMgd2hlcmRyIGFnYWluIChhbmQgaXRzIHN0YXJ0dXAgaG9vawogICMgc3RhcnRzIGl0IHdpdGggSGVyZHIpLgogIGlmIFsgIiQxIiA9ICJ1bmluc3RhbGwiIF07IHRoZW4gY21kX3N0YXJ0OyBmaQp9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBrZXkKIyBBIEhlcmRyIGtleSB0aGF0IG9wZW5zIHRoZSB3aGVyZHIgcGFuZWw6IEhlcmRyIHYxIHBsdWdpbnMgaGF2ZSBubyBtZW51LCBzbwojIHRoZSBpbnN0YWxsIGFwcGVuZHMgb25lIG1hcmtlZCBbW2tleXMuY29tbWFuZF1dIGJsb2NrIHRvIEhlcmRyJ3MKIyBjb25maWcudG9tbCwgb24gdGhlIGZpcnN0IGZyZWUga2V5IG9mIEhPVEtFWVMgKG5ldmVyIG9uZSBIZXJkciBvciB0aGUgdXNlcgojIGFscmVhZHkgYmluZHMpLiBFeGlzdGluZyBsaW5lcyBhcmUgbmV2ZXIgY2hhbmdlZDogdGhlIGJsb2NrIGlzIG9ubHkgZXZlcgojIGFwcGVuZGVkLCB0aGVuIHJlbW92ZWQgYnkgYGtleSB1bmluc3RhbGxgLiBOb3RoaW5nIGlzIGFkZGVkIHdoZW4gdGhlIHBhbmVsCiMgYWxyZWFkeSBoYXMgYSBrZXksIG9yIHdoZW4gbm8gY2FuZGlkYXRlIGlzIGZyZWUuCkhPVEtFWVM9IiR7V0hFUkRSX0hPVEtFWVM6LXByZWZpeCtpIHByZWZpeCt1IHByZWZpeCt5IHByZWZpeCttIHByZWZpeCthbHQrd30iCkhFUkRSX0NPTkZJRz0iJHtIRVJEUl9DT05GSUdfUEFUSDotJHtYREdfQ09ORklHX0hPTUU6LSRIT01FLy5jb25maWd9L2hlcmRyL2NvbmZpZy50b21sfSIKUExVR0lOX0lEPSIkKHByaW50ZiAnJXMnICIkU09VUkNFIiB8IHRyIC8gLikiClBBTkVMX0FDVElPTj0iJFBMVUdJTl9JRC5wYW5lbCIKS0VZX0JFR0lOPSIjIHdoZXJkcjoga2V5IHRoYXQgb3BlbnMgdGhlIHdoZXJkciBwYW5lbCAocmVtb3ZlIHRoaXMgYmxvY2sgdG8gdW5iaW5kIGl0KSIKS0VZX0VORD0iIyBlbmQgd2hlcmRyIgoKIyBIZXJkcidzIGRlZmF1bHQga2V5bWFwLCBmcm9tIHRoZSBydW5uaW5nIGJpbmFyeSB3aGVuIGl0IGNhbiBwcmludCBpdCwKIyBvdGhlcndpc2UgYXMgb2YgSGVyZHIgMC45LjMgKCJuYW1lPFRBQj5rZXkiIGxpbmVzKS4KZGVmYXVsdF9rZXlzKCkgewogIG91dD0iJCgiJChoZXJkcl9iaW4pIiAtLWRlZmF1bHQtY29uZmlnIDI+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 prerelease = base64ToUint8Array("IyEvdXNyL2Jpbi9lbnYgYmFzaAojIFJvbGxpbmcgcHJlcmVsZWFzZSBvZiB0aGUgZGV2ZWxvcCBicmFuY2ggKC5naXRodWIvd29ya2Zsb3dzL2RldmVsb3AtcHJlcmVsZWFzZS55bWwpLgojIFBSRVJFTEVBU0VfVEFHPWRldmVsb3Agc2VsZWN0cyB0aGUgZml4ZWQgY2hhbm5lbCwgaW5jbHVkaW5nIHN0YWJsZSB2ZXJzaW9ucy4KIyBXaXRob3V0IGl0LCB0aGUgaGlzdG9yaWNhbCBzdWZmaXgtb25seSBjaGFubmVsIHJlbWFpbnMgYXZhaWxhYmxlLgojIENvbW1hbmRzOiB2ZXJzaW9uIHwgcGFja2FnZSA8dGd6PiA8c2hhPiB8IHB1Ymxpc2ggPHRnej4gPHNoYT4KIyBwYWNrYWdlIGNoZWNrcyB0aGUgYXJjaGl2ZSBhbmQgd3JpdGVzIGl0cyBjaGVja3N1bSwgQ09NTUlUIGFuZCBub3Rlcy4KIyBwdWJsaXNoIG5lZWRzIGdoLCBHSF9SRVBPIGFuZCBhIHRva2VuIHRoYXQgY2FuIHdyaXRlIGNvbnRlbnRzLgojIEV4aXN0aW5nIHJlbGVhc2VzIG11c3QgYmUgcHVibGlzaGVkIHByZXJlbGVhc2VzOyBzdGFibGUgdGFncyBhcmUgbmV2ZXIgbW92ZWQuCnNldCAtZXVvIHBpcGVmYWlsCgpkaWUoKSB7IGVjaG8gInByZXJlbGVhc2U6ICQqIiA+JjI7IGV4aXQgMTsgfQoKcGx1Z2luX3ZlcnNpb24oKSB7IHNlZCAtbiAncy9edmVyc2lvbiA9ICJcKC4qXCkiJC9cMS9wJyBoZXJkci1wbHVnaW4udG9tbCB8IGhlYWQgLW4gMTsgfQoKY21kX3ZlcnNpb24oKSB7CiAgbG9jYWwgdmVyc2lvbiBwa2cKICB2ZXJzaW9uPSIkKHBsdWdpbl92ZXJzaW9uKSIKICBwa2c9IiQobm9kZSAtcCAicmVxdWlyZSgnLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uIikiCiAgWyAiJHZlcnNpb24iID0gIiRwa2ciIF0gfHwgZGllICJoZXJkci1wbHVnaW4udG9tbCAoJHZlcnNpb24pIGFuZCBwYWNrYWdlLmpzb24gKCRwa2cpIGRpc2FncmVlIgogIFsgIiR7UFJFUkVMRUFTRV9UQUc6LWRldmVsb3B9IiA9IGRldmVsb3AgXSB8fCBkaWUgInVuc3VwcG9ydGVkIFBSRVJFTEVBU0VfVEFHIgogIGlmIFsgIiR7UFJFUkVMRUFTRV9UQUc6LX0iID0gZGV2ZWxvcCBdOyB0aGVuCiAgICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rKC1bMC05QS1aYS16Li1dKyk/JCBdXSB8fCBkaWUgImludmFsaWQgdmVyc2lvbiAkdmVyc2lvbiIKICAgIGVjaG8gIiR2ZXJzaW9uIgogICAgcmV0dXJuCiAgZmkKICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rLVswLTlBLVphLXouLV0rJCBdXSBcCiAgICB8fCBkaWUgInZlcnNpb24gJHZlcnNpb24gaXMgbm90IGEgcHJlcmVsZWFzZSAoWC5ZLlotc3VmZml4KTogc3RhYmxlIHJlbGVhc2VzIGdvIHRocm91Z2ggcmVsZWFzZS55bWwiCiAgZWNobyAiJHZlcnNpb24iCn0KCmNoZWNrX3NoYSgpIHsgW1sgIiQxIiA9fiBeWzAtOWEtZl17NDB9JCBdXSB8fCBkaWUgIm5vdCBhIGZ1bGwgY29tbWl0IFNIQTogJDEiOyB9CgojIFRoZSBhcmNoaXZlIG11c3QgaG9sZCB3aGF0IGZldGNoX3ByZWJ1aWx0IGluc3RhbGxzLCBhbmQgbm90aGluZyBjb21waWxlZCBmb3IKIyBvbmUgcGxhdGZvcm06IHRoZSBzYW1lIGZpbGUgcnVucyBvbiBsaW51eC1hcm02NCAoUmFzcGJlcnJ5IFBpKSBhbmQgeDY0LgpjaGVja19hcmNoaXZlKCkgewogIGxvY2FsIHRnej0iJDEiIHRtcCBtaXNzaW5nPTAgbmF0aXZlCiAgdG1wPSIkKG1rdGVtcCAtZCkiCiAgdGFyIC14emYgIiR0Z3oiIC1DICIkdG1wIgogIGZvciBlbnRyeSBpbiAub3V0cHV0L3NlcnZlci9pbmRleC5tanMgYmluL3doZXJkci5tanMgYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIGJpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIFwKICAgIHBhY2thZ2UuanNvbiBza2lsbHMvd2hlcmRyL1NLSUxMLm1kOyBkbwogICAgWyAtZiAiJHRtcC9wYWNrYWdlLyRlbnRyeSIgXSB8fCB7IGVjaG8gInByZXJlbGVhc2U6IG1pc3NpbmcgcGFja2FnZS8kZW50cnkiID4mMjsgbWlzc2luZz0xOyB9CiAgZG9uZQogIG5hdGl2ZT0iJChub2RlIC1lICcKICAgIGNvbnN0IGZzID0gcmVxdWlyZSgibm9kZTpmcyIpLCBwYXRoID0gcmVxdWlyZSgibm9kZTpwYXRoIikKICAgIGNvbnN0IE1BR0lDID0gWyI3ZjQ1NGM0NiIsICJmZWVkZmFjZSIsICJmZWVkZmFjZiIsICJjZWZhZWRmZSIsICJjZmZhZWRmZSJdCiAgICBjb25zdCBoaXRzID0gW10KICAgIGNvbnN0IHdhbGsgPSBkaXIgPT4gewogICAgICBmb3IgKGNvbnN0IGUgb2YgZnMucmVhZGRpclN5bmMoZGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHsKICAgICAgICBjb25zdCBwID0gcGF0aC5qb2luKGRpciwgZS5uYW1lKQogICAgICAgIGlmIChlLmlzRGlyZWN0b3J5KCkpIHsgaWYgKGUubmFtZSA9PT0gInByZWJ1aWxkcyIpIGhpdHMucHVzaChwKTsgZWxzZSB3YWxrKHApOyBjb250aW51ZSB9CiAgICAgICAgaWYgKCFlLmlzRmlsZSgpKSBjb250aW51ZQogICAgICAgIGlmICgvXC4obm9kZXxzb3xkeWxpYnxkbGx8ZXhlKSQvLnRlc3QoZS5uYW1lKSB8fCBlLm5hbWUgPT09ICJiaW5kaW5nLmd5cCIpIHsgaGl0cy5wdXNoKHApOyBjb250aW51ZSB9CiAgICAgICAgY29uc3QgZmQgPSBmcy5vcGVuU3luYyhwLCAiciIpLCBiID0gQnVmZmVyLmFsbG9jKDQpCiAgICAgICAgY29uc3QgbiA9IGZzLnJlYWRTeW5jKGZkLCBiLCAwLCA0LCAwKTsgZnMuY2xvc2VTeW5jKGZkKQogICAgICAgIGlmIChuID09PSA0ICYmIE1BR0lDLmluY2x1ZGVzKGIudG9TdHJpbmcoImhleCIpKSkgaGl0cy5wdXNoKHApCiAgICAgIH0KICAgIH0KICAgIHdhbGsocHJvY2Vzcy5hcmd2WzFdKQogICAgY29uc29sZS5sb2coaGl0cy5tYXAoaCA9PiBwYXRoLnJlbGF0aXZlKHByb2Nlc3MuYXJndlsxXSwgaCkpLmpvaW4oIlxuIikpCiAgJyAiJHRtcCIpIgogIHJtIC1yZiAiJHRtcCIKICBbICIkbWlzc2luZyIgPSAwIF0gfHwgZGllICJpbmNvbXBsZXRlIHBhY2thZ2UgJHRneiIKICBbIC16ICIkbmF0aXZlIiBdIHx8IGRpZSAibmF0aXZlIGNvZGUgaW4gdGhlIHBhY2thZ2UgKGl0IHdvdWxkIG5vdCBydW4gb24gYW5vdGhlciBwbGF0Zm9ybSk6CiRuYXRpdmUiCn0KCmNtZF9wYWNrYWdlKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIGRpciBuYW1lCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIG5hbWU9IndoZXJkci0kdmVyc2lvbi50Z3oiCiAgWyAiJChiYXNlbmFtZSAiJHRneiIpIiA9ICIkbmFtZSIgXSB8fCBkaWUgImV4cGVjdGVkICRuYW1lLCBnb3QgJChiYXNlbmFtZSAiJHRneiIpIgogIGNoZWNrX2FyY2hpdmUgIiR0Z3oiCiAgZGlyPSIkKGRpcm5hbWUgIiR0Z3oiKSIKICAjIFRoZSBmb3JtYXQgYmluL2xpYi92ZXJpZnktcmVsZWFzZS5tanMgcmVhZHMsIGFzIHJlbGVhc2UueW1sIHdyaXRlcyBpdC4KICAoY2QgIiRkaXIiICYmIHNoYTI1NnN1bSAiJG5hbWUiID4gIiRuYW1lLnNoYTI1NiIpCiAgcHJpbnRmICclc1xuJyAiJHNoYSIgPiAiJGRpci9DT01NSVQiCiAgaWYgWyAiJHtQUkVSRUxFQVNFX1RBRzotfSIgPSBkZXZlbG9wIF07IHRoZW4KICAgICMgUmVsZWFzZSBwcmVwYXJhdGlvbiBjYW4gbGVhdmUgVW5yZWxlYXNlZCBlbXB0eTsgdGhlIGNoYW5uZWwgc3RpbGwgcHVibGlzaGVzLgogICAgcHJpbnRmICcjIyBVcGRhdGVcblxuVGhpcyBwYWNrYWdlIGZvbGxvd3MgdGhlIGRldmVsb3AgYnJhbmNoIGF0IHRoZSBjb21taXQgYmVsb3cuIFJlYWQgQ0hBTkdFTE9HLm1kIGluIHRoZSBhcmNoaXZlIGZvciB0aGUgY2hhbmdlcyBpbmNsdWRlZCBpbiB0aGlzIGJ1aWxkLlxuJyA+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogIG5vZGUgIiQoZGlybmFtZSAiJHtCQVNIX1NPVVJDRVswXX0iKS9wcmVyZWxlYXNlLXN1bW1hcnkubWpzIiAiJHNoYSIgPiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgewogICAgZWNobwogICAgZWNobyAiUm9sbGluZyBwcmVyZWxlYXNlIG9mIHRoZSBcYGRldmVsb3BcYCBicmFuY2gsIHJlYnVpbHQgb24gZXZlcnkgcHVzaC4gTm90IGEgc3RhYmxlIHJlbGVhc2U6IG5ldmVyIG1hcmtlZCBsYXRlc3QsIG5ldmVyIG9mZmVyZWQgYXMgYW4gdXBkYXRlLiIKICAgIGVjaG8KICAgIGVjaG8gIkNvbW1pdDogXGAkc2hhXGAiCiAgICBlY2hvCiAgICBlY2hvICJCdWlsdCAkKGRhdGUgLXUgJyslWS0lbS0lZCAlSDolTSBVVEMnKSR7R0lUSFVCX1JVTl9JRDorIGJ5ICR7R0lUSFVCX1NFUlZFUl9VUkw6LWh0dHBzOi8vZ2l0aHViLmNvbX0vJHtHSVRIVUJfUkVQT1NJVE9SWTotfS9hY3Rpb25zL3J1bnMvJEdJVEhVQl9SVU5fSUR9LiIKICAgIGVjaG8KICAgIGVjaG8gIlxgQ09NTUlUXGAgaG9sZHMgdGhlIGNvbW1pdCBvZiBcYCRuYW1lXGAuIEl0IGlzIHJlbW92ZWQgd2hpbGUgdGhlIGZpbGVzIGFyZSByZXBsYWNlZCBhbmQgYXR0YWNoZWQgbGFzdDogd2hlbiBpdCBpcyBwcmVzZW50LCB0aGUgYXJjaGl2ZSBtYXRjaGVzIGl0LiIKICB9ID4+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWNobyAicHJlcmVsZWFzZTogJG5hbWUgZm9yICRzaGEgY2hlY2tlZCIKfQoKY21kX3B1Ymxpc2goKSB7CiAgbG9jYWwgdGd6PSIkezE6P3VzYWdlOiBwcmVyZWxlYXNlLnNoIHB1Ymxpc2ggPHRnej4gPHNoYT59IiBzaGE9IiR7Mjo/Y29tbWl0IFNIQX0iIHZlcnNpb24gdGFnIGRpciByZXBvIHN0YXRlIGFzc2V0cyBleGlzdHMKICBjaGVja19zaGEgIiRzaGEiCiAgdmVyc2lvbj0iJChjbWRfdmVyc2lvbikiCiAgdGFnPSIke1BSRVJFTEVBU0VfVEFHOi12JHZlcnNpb259IgogIGRpcj0iJChkaXJuYW1lICIkdGd6IikiCiAgcmVwbz0iJHtHSF9SRVBPOj9HSF9SRVBPIGlzIHJlcXVpcmVkfSIKICBmb3IgZiBpbiAiJHRneiIgIiR0Z3ouc2hhMjU2IiAiJGRpci9DT01NSVQiICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiOyBkbwogICAgWyAtZiAiJGYiIF0gfHwgZGllICJtaXNzaW5nICRmIChydW46IHByZXJlbGVhc2Uuc2ggcGFja2FnZSBmaXJzdCkiCiAgZG9uZQoKICBpZiBzdGF0ZT0iJChnaCByZWxlYXNlIHZpZXcgIiR0YWciIC0tanNvbiBpc1ByZXJlbGVhc2UsaXNEcmFmdCAtLWpxICciXCguaXNQcmVyZWxlYXNlKSBcKC5pc0RyYWZ0KSInIDI+L2Rldi9udWxsKSI7IHRoZW4KICAgIFsgIiRzdGF0ZSIgPSAidHJ1ZSBmYWxzZSIgXSB8fCBkaWUgInJlbGVhc2UgJHRhZyBleGlzdHMgYW5kIGlzIG5vdCBhIHB1Ymxpc2hlZCBwcmVyZWxlYXNlICgkc3RhdGUpOiBsZWZ0IGFsb25lIgogICAgIyBHb25lIHdoaWxlIHRoZSBhcmNoaXZlIGNoYW5nZXM6IGEgcmVhZGVyIHRoYXQgZmluZHMgQ09NTUlUIGZpbmRzIGl0cyBhcmNoaXZlLgogICAgYXNzZXRzPSIkKGdoIHJlbGVhc2UgdmlldyAiJHRhZyIgLS1qc29uIGFzc2V0cyAtLWpxICcuYXNzZXRzW10ubmFtZScpIgogICAgaWYgcHJpbnRmICclc1xuJyAiJGFzc2V0cyIgfCBncmVwIC1xeCBDT01NSVQ7IHRoZW4KICAgICAgZ2ggcmVsZWFzZSBkZWxldGUtYXNzZXQgIiR0YWciIENPTU1JVCAtLXllcwogICAgZmkKICAgIGV4aXN0cz0xCiAgZWxzZQogICAgZXhpc3RzPTAKICBmaQoKICAjIFRoZSB0YWcgZm9sbG93cyB0aGUgcHVzaGVkIGNvbW1pdC4gTWFkZSB3aXRoIHRoZSB3b3JrZmxvdydzIHRva2VuLCBpdCBzdGFydHMKICAjIG5vIG90aGVyIHdvcmtmbG93IChyZWxlYXNlLnltbCBhbmQgbnBtLnltbCBsaXN0ZW4gdG8gdiogdGFncykuCiAgaWYgZ2ggYXBpICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciID4vZGV2L251bGwgMj4mMTsgdGhlbgogICAgZ2ggYXBpIC1YIFBBVENIICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciIC1mIHNoYT0iJHNoYSIgLUYgZm9yY2U9dHJ1ZSA+L2Rldi9udWxsCiAgZWxzZQogICAgZ2ggYXBpIC1YIFBPU1QgInJlcG9zLyRyZXBvL2dpdC9yZWZzIiAtZiByZWY9InJlZnMvdGFncy8kdGFnIiAtZiBzaGE9IiRzaGEiID4vZGV2L251bGwKICBmaQoKICBpZiBbICIkZXhpc3RzIiA9IDEgXTsgdGhlbgogICAgZ2ggcmVsZWFzZSBlZGl0ICIkdGFnIiAtLXByZXJlbGVhc2UgLS1sYXRlc3Q9ZmFsc2UgLS10aXRsZSAid2hlcmRyICR2ZXJzaW9uIiAtLW5vdGVzLWZpbGUgIiRkaXIvcHJlcmVsZWFzZS1ub3Rlcy5tZCIKICBlbHNlCiAgICBnaCByZWxlYXNlIGNyZWF0ZSAiJHRhZyIgLS12ZXJpZnktdGFnIC0tcHJlcmVsZWFzZSAtLWxhdGVzdD1mYWxzZSAtLXRpdGxlICJ3aGVyZHIgJHZlcnNpb24iIC0tbm90ZXMtZmlsZSAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgZ2ggcmVsZWFzZSB1cGxvYWQgIiR0YWciICIkdGd6IiAiJHRnei5zaGEyNTYiIC0tY2xvYmJlcgogICMgS2VlcCBleGFjdGx5IG9uZSBhcmNoaXZlIGFuZCBjaGVja3N1bSBvbiB0aGUgZml4ZWQgY2hhbm5lbCBhZnRlciB2ZXJzaW9uIGJ1bXBzLgogIGlmIFsgIiRleGlzdHMiID0gMSBdICYmIFsgIiR0YWciID0gZGV2ZWxvcCBdOyB0aGVuCiAgICB3aGlsZSBJRlM9IHJlYWQgLXIgYXNzZXQ7IGRvCiAgICAgIGNhc2UgIiRhc3NldCIgaW4KICAgICAgICB3aGVyZHItKi50Z3p8d2hlcmRyLSoudGd6LnNoYTI1NikKICAgICAgICAgIFsgIiRhc3NldCIgPSAiJChiYXNlbmFtZSAiJHRneiIpIiBdIHx8IFsgIiRhc3NldCIgPSAiJChiYXNlbmFtZSAiJHRneiIpLnNoYTI1NiIgXSBcCiAgICAgICAgICAgIHx8IGdoIHJlbGVhc2UgZGVsZXRlLWFzc2V0ICIkdGFnIiAiJGFzc2V0IiAtLXllcyA7OwogICAgICBlc2FjCiAgICBkb25lIDw8PCAiJGFzc2V0cyIKICBmaQogIGdoIHJlbGVhc2UgdXBsb2FkICIkdGFnIiAiJGRpci9DT01NSVQiIC0tY2xvYmJlcgogIGVjaG8gInByZXJlbGVhc2U6ICR0YWcgbm93IGF0ICRzaGEiCn0KCmNhc2UgIiR7MTotfSIgaW4KICB2ZXJzaW9uKSBjbWRfdmVyc2lvbiA7OwogIHBhY2thZ2UpIHNoaWZ0OyBjbWRfcGFja2FnZSAiJEAiIDs7CiAgcHVibGlzaCkgc2hpZnQ7IGNtZF9wdWJsaXNoICIkQCIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCB2ZXJzaW9uIHwgcGFja2FnZSA8dGd6PiA8c2hhPiB8IHB1Ymxpc2ggPHRnej4gPHNoYT4iIDs7CmVzYWMK");
|
|
4
|
+
const prerelease = base64ToUint8Array("IyEvdXNyL2Jpbi9lbnYgYmFzaAojIFJvbGxpbmcgcHJlcmVsZWFzZSBvZiB0aGUgZGV2ZWxvcCBicmFuY2ggKC5naXRodWIvd29ya2Zsb3dzL2RldmVsb3AtcHJlcmVsZWFzZS55bWwpLgojIFBSRVJFTEVBU0VfVEFHPWRldmVsb3Agc2VsZWN0cyB0aGUgZml4ZWQgY2hhbm5lbCwgaW5jbHVkaW5nIHN0YWJsZSB2ZXJzaW9ucy4KIyBXaXRob3V0IGl0LCB0aGUgaGlzdG9yaWNhbCBzdWZmaXgtb25seSBjaGFubmVsIHJlbWFpbnMgYXZhaWxhYmxlLgojIENvbW1hbmRzOiB2ZXJzaW9uIHwgZ2F0ZSA8c2hhPiB8IHBhY2thZ2UgPHRnej4gPHNoYT4gfCBwdWJsaXNoIDx0Z3o+IDxzaGE+CiMgZ2F0ZSBkZWNpZGVzIHdoZXRoZXIgPHNoYT4gbWF5IGJlIHB1Ymxpc2hlZCAoc2VlIGNtZF9nYXRlKS4KIyBwYWNrYWdlIGNoZWNrcyB0aGUgYXJjaGl2ZSBhbmQgd3JpdGVzIGl0cyBjaGVja3N1bSwgQ09NTUlUIGFuZCBub3Rlcy4KIyBwdWJsaXNoIG5lZWRzIGdoLCBHSF9SRVBPIGFuZCBhIHRva2VuIHRoYXQgY2FuIHdyaXRlIGNvbnRlbnRzLgojIEV4aXN0aW5nIHJlbGVhc2VzIG11c3QgYmUgcHVibGlzaGVkIHByZXJlbGVhc2VzOyBzdGFibGUgdGFncyBhcmUgbmV2ZXIgbW92ZWQuCnNldCAtZXVvIHBpcGVmYWlsCgpkaWUoKSB7IGVjaG8gInByZXJlbGVhc2U6ICQqIiA+JjI7IGV4aXQgMTsgfQoKcGx1Z2luX3ZlcnNpb24oKSB7IHNlZCAtbiAncy9edmVyc2lvbiA9ICJcKC4qXCkiJC9cMS9wJyBoZXJkci1wbHVnaW4udG9tbCB8IGhlYWQgLW4gMTsgfQoKY21kX3ZlcnNpb24oKSB7CiAgbG9jYWwgdmVyc2lvbiBwa2cKICB2ZXJzaW9uPSIkKHBsdWdpbl92ZXJzaW9uKSIKICBwa2c9IiQobm9kZSAtcCAicmVxdWlyZSgnLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uIikiCiAgWyAiJHZlcnNpb24iID0gIiRwa2ciIF0gfHwgZGllICJoZXJkci1wbHVnaW4udG9tbCAoJHZlcnNpb24pIGFuZCBwYWNrYWdlLmpzb24gKCRwa2cpIGRpc2FncmVlIgogIFsgIiR7UFJFUkVMRUFTRV9UQUc6LWRldmVsb3B9IiA9IGRldmVsb3AgXSB8fCBkaWUgInVuc3VwcG9ydGVkIFBSRVJFTEVBU0VfVEFHIgogIGlmIFsgIiR7UFJFUkVMRUFTRV9UQUc6LX0iID0gZGV2ZWxvcCBdOyB0aGVuCiAgICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rKC1bMC05QS1aYS16Li1dKyk/JCBdXSB8fCBkaWUgImludmFsaWQgdmVyc2lvbiAkdmVyc2lvbiIKICAgIGVjaG8gIiR2ZXJzaW9uIgogICAgcmV0dXJuCiAgZmkKICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rLVswLTlBLVphLXouLV0rJCBdXSBcCiAgICB8fCBkaWUgInZlcnNpb24gJHZlcnNpb24gaXMgbm90IGEgcHJlcmVsZWFzZSAoWC5ZLlotc3VmZml4KTogc3RhYmxlIHJlbGVhc2VzIGdvIHRocm91Z2ggcmVsZWFzZS55bWwiCiAgZWNobyAiJHZlcnNpb24iCn0KCmNoZWNrX3NoYSgpIHsgW1sgIiQxIiA9fiBeWzAtOWEtZl17NDB9JCBdXSB8fCBkaWUgIm5vdCBhIGZ1bGwgY29tbWl0IFNIQTogJDEiOyB9CgojIFRoZSBhcmNoaXZlIG11c3QgaG9sZCB3aGF0IGZldGNoX3ByZWJ1aWx0IGluc3RhbGxzLCBhbmQgbm90aGluZyBjb21waWxlZCBmb3IKIyBvbmUgcGxhdGZvcm06IHRoZSBzYW1lIGZpbGUgcnVucyBvbiBsaW51eC1hcm02NCAoUmFzcGJlcnJ5IFBpKSBhbmQgeDY0LgpjaGVja19hcmNoaXZlKCkgewogIGxvY2FsIHRnej0iJDEiIHRtcCBtaXNzaW5nPTAgbmF0aXZlCiAgdG1wPSIkKG1rdGVtcCAtZCkiCiAgdGFyIC14emYgIiR0Z3oiIC1DICIkdG1wIgogIGZvciBlbnRyeSBpbiAub3V0cHV0L3NlcnZlci9pbmRleC5tanMgYmluL3doZXJkci5tanMgYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIGJpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIFwKICAgIHBhY2thZ2UuanNvbiBza2lsbHMvd2hlcmRyL1NLSUxMLm1kOyBkbwogICAgWyAtZiAiJHRtcC9wYWNrYWdlLyRlbnRyeSIgXSB8fCB7IGVjaG8gInByZXJlbGVhc2U6IG1pc3NpbmcgcGFja2FnZS8kZW50cnkiID4mMjsgbWlzc2luZz0xOyB9CiAgZG9uZQogIG5hdGl2ZT0iJChub2RlIC1lICcKICAgIGNvbnN0IGZzID0gcmVxdWlyZSgibm9kZTpmcyIpLCBwYXRoID0gcmVxdWlyZSgibm9kZTpwYXRoIikKICAgIGNvbnN0IE1BR0lDID0gWyI3ZjQ1NGM0NiIsICJmZWVkZmFjZSIsICJmZWVkZmFjZiIsICJjZWZhZWRmZSIsICJjZmZhZWRmZSJdCiAgICBjb25zdCBoaXRzID0gW10KICAgIGNvbnN0IHdhbGsgPSBkaXIgPT4gewogICAgICBmb3IgKGNvbnN0IGUgb2YgZnMucmVhZGRpclN5bmMoZGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHsKICAgICAgICBjb25zdCBwID0gcGF0aC5qb2luKGRpciwgZS5uYW1lKQogICAgICAgIGlmIChlLmlzRGlyZWN0b3J5KCkpIHsgaWYgKGUubmFtZSA9PT0gInByZWJ1aWxkcyIpIGhpdHMucHVzaChwKTsgZWxzZSB3YWxrKHApOyBjb250aW51ZSB9CiAgICAgICAgaWYgKCFlLmlzRmlsZSgpKSBjb250aW51ZQogICAgICAgIGlmICgvXC4obm9kZXxzb3xkeWxpYnxkbGx8ZXhlKSQvLnRlc3QoZS5uYW1lKSB8fCBlLm5hbWUgPT09ICJiaW5kaW5nLmd5cCIpIHsgaGl0cy5wdXNoKHApOyBjb250aW51ZSB9CiAgICAgICAgY29uc3QgZmQgPSBmcy5vcGVuU3luYyhwLCAiciIpLCBiID0gQnVmZmVyLmFsbG9jKDQpCiAgICAgICAgY29uc3QgbiA9IGZzLnJlYWRTeW5jKGZkLCBiLCAwLCA0LCAwKTsgZnMuY2xvc2VTeW5jKGZkKQogICAgICAgIGlmIChuID09PSA0ICYmIE1BR0lDLmluY2x1ZGVzKGIudG9TdHJpbmcoImhleCIpKSkgaGl0cy5wdXNoKHApCiAgICAgIH0KICAgIH0KICAgIHdhbGsocHJvY2Vzcy5hcmd2WzFdKQogICAgY29uc29sZS5sb2coaGl0cy5tYXAoaCA9PiBwYXRoLnJlbGF0aXZlKHByb2Nlc3MuYXJndlsxXSwgaCkpLmpvaW4oIlxuIikpCiAgJyAiJHRtcCIpIgogIHJtIC1yZiAiJHRtcCIKICBbICIkbWlzc2luZyIgPSAwIF0gfHwgZGllICJpbmNvbXBsZXRlIHBhY2thZ2UgJHRneiIKICBbIC16ICIkbmF0aXZlIiBdIHx8IGRpZSAibmF0aXZlIGNvZGUgaW4gdGhlIHBhY2thZ2UgKGl0IHdvdWxkIG5vdCBydW4gb24gYW5vdGhlciBwbGF0Zm9ybSk6CiRuYXRpdmUiCn0KCmNtZF9wYWNrYWdlKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIGRpciBuYW1lCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIG5hbWU9IndoZXJkci0kdmVyc2lvbi50Z3oiCiAgWyAiJChiYXNlbmFtZSAiJHRneiIpIiA9ICIkbmFtZSIgXSB8fCBkaWUgImV4cGVjdGVkICRuYW1lLCBnb3QgJChiYXNlbmFtZSAiJHRneiIpIgogIGNoZWNrX2FyY2hpdmUgIiR0Z3oiCiAgZGlyPSIkKGRpcm5hbWUgIiR0Z3oiKSIKICAjIFRoZSBmb3JtYXQgYmluL2xpYi92ZXJpZnktcmVsZWFzZS5tanMgcmVhZHMsIGFzIHJlbGVhc2UueW1sIHdyaXRlcyBpdC4KICAoY2QgIiRkaXIiICYmIHNoYTI1NnN1bSAiJG5hbWUiID4gIiRuYW1lLnNoYTI1NiIpCiAgcHJpbnRmICclc1xuJyAiJHNoYSIgPiAiJGRpci9DT01NSVQiCiAgaWYgWyAiJHtQUkVSRUxFQVNFX1RBRzotfSIgPSBkZXZlbG9wIF07IHRoZW4KICAgICMgUmVsZWFzZSBwcmVwYXJhdGlvbiBjYW4gbGVhdmUgVW5yZWxlYXNlZCBlbXB0eTsgdGhlIGNoYW5uZWwgc3RpbGwgcHVibGlzaGVzLgogICAgcHJpbnRmICcjIyBVcGRhdGVcblxuVGhpcyBwYWNrYWdlIGZvbGxvd3MgdGhlIGRldmVsb3AgYnJhbmNoIGF0IHRoZSBjb21taXQgYmVsb3cuIFJlYWQgQ0hBTkdFTE9HLm1kIGluIHRoZSBhcmNoaXZlIGZvciB0aGUgY2hhbmdlcyBpbmNsdWRlZCBpbiB0aGlzIGJ1aWxkLlxuJyA+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogIG5vZGUgIiQoZGlybmFtZSAiJHtCQVNIX1NPVVJDRVswXX0iKS9wcmVyZWxlYXNlLXN1bW1hcnkubWpzIiAiJHNoYSIgPiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgewogICAgZWNobwogICAgZWNobyAiUm9sbGluZyBwcmVyZWxlYXNlIG9mIHRoZSBcYGRldmVsb3BcYCBicmFuY2gsIHJlYnVpbHQgZm9yIGVhY2ggZGV2ZWxvcCBjb21taXQgdGhhdCBwYXNzZXMgQ0kuIE5vdCBhIHN0YWJsZSByZWxlYXNlOiBuZXZlciBtYXJrZWQgbGF0ZXN0LCBuZXZlciBvZmZlcmVkIGFzIGFuIHVwZGF0ZS4iCiAgICBlY2hvCiAgICBlY2hvICJDb21taXQ6IFxgJHNoYVxgIgogICAgZWNobwogICAgZWNobyAiQnVpbHQgJChkYXRlIC11ICcrJVktJW0tJWQgJUg6JU0gVVRDJykke0dJVEhVQl9SVU5fSUQ6KyBieSAke0dJVEhVQl9TRVJWRVJfVVJMOi1odHRwczovL2dpdGh1Yi5jb219LyR7R0lUSFVCX1JFUE9TSVRPUlk6LX0vYWN0aW9ucy9ydW5zLyRHSVRIVUJfUlVOX0lEfS4iCiAgICBlY2hvCiAgICBlY2hvICJcYENPTU1JVFxgIGhvbGRzIHRoZSBjb21taXQgb2YgXGAkbmFtZVxgLiBJdCBpcyByZW1vdmVkIHdoaWxlIHRoZSBmaWxlcyBhcmUgcmVwbGFjZWQgYW5kIGF0dGFjaGVkIGxhc3Q6IHdoZW4gaXQgaXMgcHJlc2VudCwgdGhlIGFyY2hpdmUgbWF0Y2hlcyBpdC4iCiAgfSA+PiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGVjaG8gInByZXJlbGVhc2U6ICRuYW1lIGZvciAkc2hhIGNoZWNrZWQiCn0KCiMgQSBkZXZlbG9wIGNvbW1pdCBpcyBwdWJsaXNoZWQgb25seSB3aGVuOgojIC0gYSBwdXNoIHJ1biBvZiBjaS55bWwgb24gZGV2ZWxvcCBmb3IgZXhhY3RseSB0aGlzIGNvbW1pdCBzdWNjZWVkZWQsIHdpdGggaXRzCiMgICBgY2hlY2tzYCBhbmQgYGUyZWAgam9icyBncmVlbiAodGhlIGNoZWNrcyB0aGUgYnJhbmNoIHByb3RlY3Rpb24gcmVxdWlyZXMpOwojIC0gaXQgaXMgb24gZGV2ZWxvcCAoZGV2ZWxvcCdzIGhlYWQgb3Igb25lIG9mIGl0cyBhbmNlc3RvcnMpOwojIC0gaXQgaXMgbm90IG9sZGVyIHRoYW4gdGhlIGNvbW1pdCB0aGUgZGV2ZWxvcCB0YWcgYWxyZWFkeSBuYW1lczogcnVucyBjYW4KIyAgIGZpbmlzaCBvdXQgb2Ygb3JkZXIsIGFuZCBhIG5ld2VyIGJ1aWxkIGlzIG5ldmVyIHJlcGxhY2VkIGJ5IGFuIG9sZGVyIG9uZS4KIyBXcml0ZXMgcHVibGlzaD10cnVlfGZhbHNlIHRvICRHSVRIVUJfT1VUUFVULiBGYWlscyB3aGVuIENJIGlzIG5vdCBncmVlbiBvciB0aGUKIyBjb21taXQgaXMgbm90IG9uIGRldmVsb3A7IGFuIG9sZGVyIGNvbW1pdCBpcyBza2lwcGVkIHdpdGhvdXQgZmFpbGluZy4KY21kX2dhdGUoKSB7CiAgbG9jYWwgc2hhPSIkezE6P3VzYWdlOiBwcmVyZWxlYXNlLnNoIGdhdGUgPHNoYT59IiByZXBvIHJ1bnMgcnVuIHJ1bl9vaz0iIiBqb2JzIGhlYWQgcHVibGlzaGVkIHN0YXR1cwogIGNoZWNrX3NoYSAiJHNoYSIKICByZXBvPSIke0dIX1JFUE86P0dIX1JFUE8gaXMgcmVxdWlyZWR9IgogICMgRXZlcnkgQVBJIGNhbGwgZmFpbHMgY2xvc2VkOiBhbiBlcnJvciBzdG9wcyB0aGUgZ2F0ZSwgbmV2ZXIgbGV0cyBhIGNvbW1pdCB0aHJvdWdoLgogIHJ1bnM9IiQoZ2ggYXBpICJyZXBvcy8kcmVwby9hY3Rpb25zL3dvcmtmbG93cy9jaS55bWwvcnVucz9oZWFkX3NoYT0kc2hhJmV2ZW50PXB1c2gmYnJhbmNoPWRldmVsb3Amc3RhdHVzPXN1Y2Nlc3MmcGVyX3BhZ2U9MjAiIFwKICAgIC0tanEgJy53b3JrZmxvd19ydW5zW10gfCBzZWxlY3QoLmhlYWRfc2hhID09ICInIiRzaGEiJyIgYW5kIC5jb25jbHVzaW9uID09ICJzdWNjZXNzIikgfCAuaWQnKSIgXAogICAgfHwgZGllICJjb3VsZCBub3QgbGlzdCB0aGUgY2kgcnVucyBvZiAkc2hhIgogIGZvciBydW4gaW4gJHJ1bnM7IGRvCiAgICBqb2JzPSIkKGdoIGFwaSAicmVwb3MvJHJlcG8vYWN0aW9ucy9ydW5zLyRydW4vam9icz9wZXJfcGFnZT0xMDAiIC0tanEgJy5qb2JzW10gfCBzZWxlY3QoLmNvbmNsdXNpb24gPT0gInN1Y2Nlc3MiKSB8IC5uYW1lJykiIFwKICAgICAgfHwgZGllICJjb3VsZCBub3QgcmVhZCB0aGUgam9icyBvZiBjaSBydW4gJHJ1biIKICAgIGlmIHByaW50ZiAnJXNcbicgIiRqb2JzIiB8IGdyZXAgLXF4IGNoZWNrcyAmJiBwcmludGYgJyVzXG4nICIkam9icyIgfCBncmVwIC1xeCBlMmU7IHRoZW4KICAgICAgcnVuX29rPSIkcnVuIjsgYnJlYWsKICAgIGZpCiAgZG9uZQogIFsgLW4gIiRydW5fb2siIF0gfHwgZGllICJubyBzdWNjZXNzZnVsIGNpIHJ1biAoY2hlY2tzIGFuZCBlMmUpIG9uIGRldmVsb3AgZm9yICRzaGEiCiAgaGVhZD0iJChnaCBhcGkgInJlcG9zLyRyZXBvL2JyYW5jaGVzL2RldmVsb3AiIC0tanEgLmNvbW1pdC5zaGEpIiB8fCBkaWUgImNvdWxkIG5vdCByZWFkIHRoZSBoZWFkIG9mIGRldmVsb3AiCiAgY2hlY2tfc2hhICIkaGVhZCIKICBpZiBbICIkaGVhZCIgIT0gIiRzaGEiIF07IHRoZW4KICAgIHN0YXR1cz0iJChnaCBhcGkgInJlcG9zLyRyZXBvL2NvbXBhcmUvJGhlYWQuLi4kc2hhIiAtLWpxIC5zdGF0dXMpIiB8fCBkaWUgImNvdWxkIG5vdCBjb21wYXJlICRzaGEgd2l0aCBkZXZlbG9wIgogICAgWyAiJHN0YXR1cyIgPSBiZWhpbmQgXSB8fCBkaWUgIiRzaGEgaXMgbm90IG9uIGRldmVsb3AgKCRzdGF0dXMgcmVsYXRpdmUgdG8gJGhlYWQpIgogIGZpCiAgIyBtYXRjaGluZy1yZWZzIGFuc3dlcnMgYW4gZW1wdHkgbGlzdCB3aGVuIHRoZSB0YWcgZG9lcyBub3QgZXhpc3QgeWV0LCBzbyBhCiAgIyBmYWlsZWQgY2FsbCBpcyBuZXZlciBtaXN0YWtlbiBmb3IgYSBtaXNzaW5nIHRhZy4KICBwdWJsaXNoZWQ9IiQoZ2ggYXBpICJyZXBvcy8kcmVwby9naXQvbWF0Y2hpbmctcmVmcy90YWdzL2RldmVsb3AiIC0tanEgJy5bXSB8IHNlbGVjdCgucmVmID09ICJyZWZzL3RhZ3MvZGV2ZWxvcCIpIHwgLm9iamVjdC5zaGEnKSIgXAogICAgfHwgZGllICJjb3VsZCBub3QgcmVhZCB0aGUgZGV2ZWxvcCB0YWciCiAgaWYgWyAtbiAiJHB1Ymxpc2hlZCIgXSAmJiBbICIkcHVibGlzaGVkIiAhPSAiJHNoYSIgXTsgdGhlbgogICAgY2hlY2tfc2hhICIkcHVibGlzaGVkIgogICAgc3RhdHVzPSIkKGdoIGFwaSAicmVwb3MvJHJlcG8vY29tcGFyZS8kcHVibGlzaGVkLi4uJHNoYSIgLS1qcSAuc3RhdHVzKSIgfHwgZGllICJjb3VsZCBub3QgY29tcGFyZSAkc2hhIHdpdGggdGhlIHB1Ymxpc2hlZCAkcHVibGlzaGVkIgogICAgY2FzZSAiJHN0YXR1cyIgaW4KICAgICAgYmVoaW5kKQogICAgICAgIGVjaG8gInByZXJlbGVhc2U6IGRldmVsb3AgYWxyZWFkeSBuYW1lcyAkcHVibGlzaGVkLCBuZXdlciB0aGFuICRzaGE6IHNraXBwZWQiCiAgICAgICAgWyAteiAiJHtHSVRIVUJfT1VUUFVUOi19IiBdIHx8IGVjaG8gInB1Ymxpc2g9ZmFsc2UiID4+ICIkR0lUSFVCX09VVFBVVCIKICAgICAgICByZXR1cm4gOzsKICAgICAgYWhlYWR8ZGl2ZXJnZWQpIDs7CiAgICAgICopIGRpZSAidW5leHBlY3RlZCBjb21wYXJpc29uIG9mICRzaGEgd2l0aCB0aGUgcHVibGlzaGVkICRwdWJsaXNoZWQ6ICRzdGF0dXMiIDs7CiAgICBlc2FjCiAgZmkKICBlY2hvICJwcmVyZWxlYXNlOiAkc2hhIHBhc3NlZCBjaSBydW4gJHJ1bl9vayBhbmQgbWF5IGJlIHB1Ymxpc2hlZCIKICBbIC16ICIke0dJVEhVQl9PVVRQVVQ6LX0iIF0gfHwgZWNobyAicHVibGlzaD10cnVlIiA+PiAiJEdJVEhVQl9PVVRQVVQiCn0KCmNtZF9wdWJsaXNoKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwdWJsaXNoIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIHRhZyBkaXIgcmVwbyBzdGF0ZSBhc3NldHMgZXhpc3RzCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIHRhZz0iJHtQUkVSRUxFQVNFX1RBRzotdiR2ZXJzaW9ufSIKICBkaXI9IiQoZGlybmFtZSAiJHRneiIpIgogIHJlcG89IiR7R0hfUkVQTzo/R0hfUkVQTyBpcyByZXF1aXJlZH0iCiAgZm9yIGYgaW4gIiR0Z3oiICIkdGd6LnNoYTI1NiIgIiRkaXIvQ09NTUlUIiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIjsgZG8KICAgIFsgLWYgIiRmIiBdIHx8IGRpZSAibWlzc2luZyAkZiAocnVuOiBwcmVyZWxlYXNlLnNoIHBhY2thZ2UgZmlyc3QpIgogIGRvbmUKCiAgaWYgc3RhdGU9IiQoZ2ggcmVsZWFzZSB2aWV3ICIkdGFnIiAtLWpzb24gaXNQcmVyZWxlYXNlLGlzRHJhZnQgLS1qcSAnIlwoLmlzUHJlcmVsZWFzZSkgXCguaXNEcmFmdCkiJyAyPi9kZXYvbnVsbCkiOyB0aGVuCiAgICBbICIkc3RhdGUiID0gInRydWUgZmFsc2UiIF0gfHwgZGllICJyZWxlYXNlICR0YWcgZXhpc3RzIGFuZCBpcyBub3QgYSBwdWJsaXNoZWQgcHJlcmVsZWFzZSAoJHN0YXRlKTogbGVmdCBhbG9uZSIKICAgICMgR29uZSB3aGlsZSB0aGUgYXJjaGl2ZSBjaGFuZ2VzOiBhIHJlYWRlciB0aGF0IGZpbmRzIENPTU1JVCBmaW5kcyBpdHMgYXJjaGl2ZS4KICAgIGFzc2V0cz0iJChnaCByZWxlYXNlIHZpZXcgIiR0YWciIC0tanNvbiBhc3NldHMgLS1qcSAnLmFzc2V0c1tdLm5hbWUnKSIKICAgIGlmIHByaW50ZiAnJXNcbicgIiRhc3NldHMiIHwgZ3JlcCAtcXggQ09NTUlUOyB0aGVuCiAgICAgIGdoIHJlbGVhc2UgZGVsZXRlLWFzc2V0ICIkdGFnIiBDT01NSVQgLS15ZXMKICAgIGZpCiAgICBleGlzdHM9MQogIGVsc2UKICAgIGV4aXN0cz0wCiAgZmkKCiAgIyBUaGUgdGFnIGZvbGxvd3MgdGhlIHB1c2hlZCBjb21taXQuIE1hZGUgd2l0aCB0aGUgd29ya2Zsb3cncyB0b2tlbiwgaXQgc3RhcnRzCiAgIyBubyBvdGhlciB3b3JrZmxvdyAocmVsZWFzZS55bWwgYW5kIG5wbS55bWwgbGlzdGVuIHRvIHYqIHRhZ3MpLgogIGlmIGdoIGFwaSAicmVwb3MvJHJlcG8vZ2l0L3JlZnMvdGFncy8kdGFnIiA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIGdoIGFwaSAtWCBQQVRDSCAicmVwb3MvJHJlcG8vZ2l0L3JlZnMvdGFncy8kdGFnIiAtZiBzaGE9IiRzaGEiIC1GIGZvcmNlPXRydWUgPi9kZXYvbnVsbAogIGVsc2UKICAgIGdoIGFwaSAtWCBQT1NUICJyZXBvcy8kcmVwby9naXQvcmVmcyIgLWYgcmVmPSJyZWZzL3RhZ3MvJHRhZyIgLWYgc2hhPSIkc2hhIiA+L2Rldi9udWxsCiAgZmkKCiAgaWYgWyAiJGV4aXN0cyIgPSAxIF07IHRoZW4KICAgIGdoIHJlbGVhc2UgZWRpdCAiJHRhZyIgLS1wcmVyZWxlYXNlIC0tbGF0ZXN0PWZhbHNlIC0tdGl0bGUgIndoZXJkciAkdmVyc2lvbiIgLS1ub3Rlcy1maWxlICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogICAgZ2ggcmVsZWFzZSBjcmVhdGUgIiR0YWciIC0tdmVyaWZ5LXRhZyAtLXByZXJlbGVhc2UgLS1sYXRlc3Q9ZmFsc2UgLS10aXRsZSAid2hlcmRyICR2ZXJzaW9uIiAtLW5vdGVzLWZpbGUgIiRkaXIvcHJlcmVsZWFzZS1ub3Rlcy5tZCIKICBmaQogIGdoIHJlbGVhc2UgdXBsb2FkICIkdGFnIiAiJHRneiIgIiR0Z3ouc2hhMjU2IiAtLWNsb2JiZXIKICAjIEtlZXAgZXhhY3RseSBvbmUgYXJjaGl2ZSBhbmQgY2hlY2tzdW0gb24gdGhlIGZpeGVkIGNoYW5uZWwgYWZ0ZXIgdmVyc2lvbiBidW1wcy4KICBpZiBbICIkZXhpc3RzIiA9IDEgXSAmJiBbICIkdGFnIiA9IGRldmVsb3AgXTsgdGhlbgogICAgd2hpbGUgSUZTPSByZWFkIC1yIGFzc2V0OyBkbwogICAgICBjYXNlICIkYXNzZXQiIGluCiAgICAgICAgd2hlcmRyLSoudGd6fHdoZXJkci0qLnRnei5zaGEyNTYpCiAgICAgICAgICBbICIkYXNzZXQiID0gIiQoYmFzZW5hbWUgIiR0Z3oiKSIgXSB8fCBbICIkYXNzZXQiID0gIiQoYmFzZW5hbWUgIiR0Z3oiKS5zaGEyNTYiIF0gXAogICAgICAgICAgICB8fCBnaCByZWxlYXNlIGRlbGV0ZS1hc3NldCAiJHRhZyIgIiRhc3NldCIgLS15ZXMgOzsKICAgICAgZXNhYwogICAgZG9uZSA8PDwgIiRhc3NldHMiCiAgZmkKICBnaCByZWxlYXNlIHVwbG9hZCAiJHRhZyIgIiRkaXIvQ09NTUlUIiAtLWNsb2JiZXIKICBlY2hvICJwcmVyZWxlYXNlOiAkdGFnIG5vdyBhdCAkc2hhIgp9CgpjYXNlICIkezE6LX0iIGluCiAgdmVyc2lvbikgY21kX3ZlcnNpb24gOzsKICBnYXRlKSBzaGlmdDsgY21kX2dhdGUgIiRAIiA7OwogIHBhY2thZ2UpIHNoaWZ0OyBjbWRfcGFja2FnZSAiJEAiIDs7CiAgcHVibGlzaCkgc2hpZnQ7IGNtZF9wdWJsaXNoICIkQCIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCB2ZXJzaW9uIHwgZ2F0ZSA8c2hhPiB8IHBhY2thZ2UgPHRnej4gPHNoYT4gfCBwdWJsaXNoIDx0Z3o+IDxzaGE+IiA7Owplc2FjCg==");
|
|
5
5
|
|
|
6
6
|
export { prerelease as default };
|
|
7
7
|
//# sourceMappingURL=prerelease.mjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
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";
|
|
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 // Rust tests are selected by the conditional engine workflow, not Vitest.\n if (file.startsWith('engine/')) continue\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) && !p.startsWith('engine/')) && !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 or engine only: no JS 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
3
|
|
|
4
4
|
export { testAffected as default };
|
|
5
5
|
//# sourceMappingURL=test-affected.mjs.map
|
|
@@ -17,19 +17,19 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:zlib';
|
|
27
|
+
import '@simplewebauthn/server';
|
|
28
|
+
import 'node:net';
|
|
25
29
|
import 'node:string_decoder';
|
|
26
30
|
import 'node:fs/promises';
|
|
27
31
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
32
|
import 'node:url';
|
|
31
|
-
import 'node:zlib';
|
|
32
|
-
import '@simplewebauthn/server';
|
|
33
33
|
|
|
34
34
|
const _____ = defineEventHandler((event) => sendError(event, 404, { error: "Not found" }));
|
|
35
35
|
|
|
@@ -17,19 +17,19 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:zlib';
|
|
27
|
+
import '@simplewebauthn/server';
|
|
28
|
+
import 'node:net';
|
|
25
29
|
import 'node:string_decoder';
|
|
26
30
|
import 'node:fs/promises';
|
|
27
31
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
32
|
import 'node:url';
|
|
31
|
-
import 'node:zlib';
|
|
32
|
-
import '@simplewebauthn/server';
|
|
33
33
|
|
|
34
34
|
const agents_post = defineApi((event, b) => createAgent(b));
|
|
35
35
|
|
|
@@ -17,19 +17,19 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:zlib';
|
|
27
|
+
import '@simplewebauthn/server';
|
|
28
|
+
import 'node:net';
|
|
25
29
|
import 'node:string_decoder';
|
|
26
30
|
import 'node:fs/promises';
|
|
27
31
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
32
|
import 'node:url';
|
|
31
|
-
import 'node:zlib';
|
|
32
|
-
import '@simplewebauthn/server';
|
|
33
33
|
|
|
34
34
|
const askTab_post = defineApi(async (event, b) => {
|
|
35
35
|
var _a;
|
|
@@ -17,19 +17,19 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:zlib';
|
|
27
|
+
import '@simplewebauthn/server';
|
|
28
|
+
import 'node:net';
|
|
25
29
|
import 'node:string_decoder';
|
|
26
30
|
import 'node:fs/promises';
|
|
27
31
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
32
|
import 'node:url';
|
|
31
|
-
import 'node:zlib';
|
|
32
|
-
import '@simplewebauthn/server';
|
|
33
33
|
|
|
34
34
|
const attach_post = defineApi((event, b) => {
|
|
35
35
|
const q = getQuery(event);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { a as defineApi, k as auth, r as reqOf } from '../../../nitro/nitro.mjs';
|
|
1
|
+
import { a as defineApi, k as auth, r as reqOf, l as eventClients } from '../../../nitro/nitro.mjs';
|
|
2
|
+
import { r as revokeEverywhere, a as askPushResubscribe } from '../../../_/revoke.mjs';
|
|
2
3
|
import 'node:http';
|
|
3
4
|
import 'node:https';
|
|
4
5
|
import 'node:crypto';
|
|
@@ -17,21 +18,27 @@ import 'node:buffer';
|
|
|
17
18
|
import 'node:fs';
|
|
18
19
|
import 'node:path';
|
|
19
20
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
21
|
import 'node:child_process';
|
|
22
22
|
import 'node:dns';
|
|
23
23
|
import 'node:util';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
25
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
26
|
import 'web-push';
|
|
27
|
+
import 'node:zlib';
|
|
28
|
+
import '@simplewebauthn/server';
|
|
29
|
+
import 'node:net';
|
|
25
30
|
import 'node:string_decoder';
|
|
26
31
|
import 'node:fs/promises';
|
|
27
32
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
33
|
import 'node:url';
|
|
31
|
-
import '
|
|
32
|
-
import '@simplewebauthn/server';
|
|
34
|
+
import '../../../_/ws.mjs';
|
|
33
35
|
|
|
34
|
-
const disable_post = defineApi((event) =>
|
|
36
|
+
const disable_post = defineApi(async (event) => {
|
|
37
|
+
const r = auth.disable(reqOf(event));
|
|
38
|
+
await revokeEverywhere();
|
|
39
|
+
askPushResubscribe(eventClients.values());
|
|
40
|
+
return r;
|
|
41
|
+
});
|
|
35
42
|
|
|
36
43
|
export { disable_post as default };
|
|
37
44
|
//# sourceMappingURL=disable.post.mjs.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as defineApi, k as auth, r as reqOf } from '../../../nitro/nitro.mjs';
|
|
2
|
+
import { r as revokeEverywhere } from '../../../_/revoke.mjs';
|
|
2
3
|
import 'node:http';
|
|
3
4
|
import 'node:https';
|
|
4
5
|
import 'node:crypto';
|
|
@@ -17,21 +18,26 @@ import 'node:buffer';
|
|
|
17
18
|
import 'node:fs';
|
|
18
19
|
import 'node:path';
|
|
19
20
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
21
|
import 'node:child_process';
|
|
22
22
|
import 'node:dns';
|
|
23
23
|
import 'node:util';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
25
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
26
|
import 'web-push';
|
|
27
|
+
import 'node:zlib';
|
|
28
|
+
import '@simplewebauthn/server';
|
|
29
|
+
import 'node:net';
|
|
25
30
|
import 'node:string_decoder';
|
|
26
31
|
import 'node:fs/promises';
|
|
27
32
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
33
|
import 'node:url';
|
|
31
|
-
import '
|
|
32
|
-
import '@simplewebauthn/server';
|
|
34
|
+
import '../../../_/ws.mjs';
|
|
33
35
|
|
|
34
|
-
const lockAll_post = defineApi((event) =>
|
|
36
|
+
const lockAll_post = defineApi(async (event) => {
|
|
37
|
+
const r = auth.lockAll(reqOf(event));
|
|
38
|
+
await revokeEverywhere();
|
|
39
|
+
return r;
|
|
40
|
+
});
|
|
35
41
|
|
|
36
42
|
export { lockAll_post as default };
|
|
37
43
|
//# sourceMappingURL=lock-all.post.mjs.map
|
|
@@ -17,19 +17,19 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:zlib';
|
|
27
|
+
import '@simplewebauthn/server';
|
|
28
|
+
import 'node:net';
|
|
25
29
|
import 'node:string_decoder';
|
|
26
30
|
import 'node:fs/promises';
|
|
27
31
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
32
|
import 'node:url';
|
|
31
|
-
import 'node:zlib';
|
|
32
|
-
import '@simplewebauthn/server';
|
|
33
33
|
|
|
34
34
|
const lock_post = defineApi((event) => auth.lock(reqOf(event)));
|
|
35
35
|
|