From edf65c89a45b4a2e45943da94e3c7c87e1f64212 Mon Sep 17 00:00:00 2001 From: winterfx Date: Thu, 13 Aug 2026 10:00:50 +0800 Subject: [PATCH 1/4] refactor(scheduler): deliver deterministic tool via agent-compose workspace Replace the base64-chunked-env-var smuggling of the compiled draft-pr/ issue-triage tool bundles with agent-compose's native git `workspace`, checked out fresh into every scheduler sandbox. Removes the mktemp/ base64-decode dance from both scheduler scripts in favor of invoking the tool directly from $WORKSPACE/workflow-repo, and commits the plain esbuild bundles (agents/*/tool/main.mjs) alongside the existing generated scheduler.js artifacts, checked for staleness the same way. workspace.ref is pinned to a commit SHA (unlike skills/scheduler.script, which stay on `main`) because workspace refs are re-resolved on every new sandbox rather than snapshotted once at `agent-compose up` - a moving ref could otherwise serve a different tool commit mid-workflow across a single Issue/PR's multi-day lifecycle. Adds scripts/pin-workspace-ref.ts to re-stamp both workspace.ref fields to HEAD before a deploy. --- .prettierignore | 1 + agent-compose.yml | 12 + agents/draft-pr/scheduler.js | 30 +- agents/draft-pr/tool/main.mjs | 7957 ++++++++++++++++++++++++ agents/issue-triage/scheduler.js | 22 +- agents/issue-triage/tool/main.mjs | 6047 ++++++++++++++++++ package.json | 1 + scripts/build-tools.ts | 72 +- scripts/pin-workspace-ref.ts | 62 + src/schedulers/draft-pr.js | 30 +- src/schedulers/issue-triage.js | 22 +- test/build-tools.test.ts | 53 +- test/draft-pr-scheduler-script.test.ts | 13 +- test/scheduler-script.test.ts | 11 +- 14 files changed, 14184 insertions(+), 149 deletions(-) create mode 100644 agents/draft-pr/tool/main.mjs create mode 100644 agents/issue-triage/tool/main.mjs create mode 100644 scripts/pin-workspace-ref.ts diff --git a/.prettierignore b/.prettierignore index ea32a92..4fedb5a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ dist/ agents/*/scheduler.js +agents/*/tool/main.mjs diff --git a/agent-compose.yml b/agent-compose.yml index fa86e0f..95f4d97 100644 --- a/agent-compose.yml +++ b/agent-compose.yml @@ -36,6 +36,12 @@ agents: ref: main path: agents/issue-triage + workspace: + provider: git + url: https://github.com/winterfx/engineering-agent-workflows.git + ref: 78db6672cbd38e07d10621f937d55f22c1fcfbab + target: workflow-repo + scheduler: enabled: true sandbox_policy: new @@ -80,6 +86,12 @@ agents: ref: main path: agents/draft-pr + workspace: + provider: git + url: https://github.com/winterfx/engineering-agent-workflows.git + ref: 78db6672cbd38e07d10621f937d55f22c1fcfbab + target: workflow-repo + scheduler: enabled: true sandbox_policy: new diff --git a/agents/draft-pr/scheduler.js b/agents/draft-pr/scheduler.js index 6414ccb..674b99f 100644 --- a/agents/draft-pr/scheduler.js +++ b/agents/draft-pr/scheduler.js @@ -4,9 +4,9 @@ const GITHUB_REVIEW_TOPIC = "webhook.github.pull_request_review"; const GITHUB_WORKFLOW_RUN_TOPIC = "webhook.github.workflow_run"; const READY_LABEL = "agent:ready"; const APPROVED_LABEL = "agent:approved"; -const WORKFLOW_TOOL_BASE64 = "dmFyIF9fZGVmUHJvcCA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eTsKdmFyIF9fZXhwb3J0ID0gKHRhcmdldCwgYWxsKSA9PiB7CiAgZm9yICh2YXIgbmFtZSBpbiBhbGwpCiAgICBfX2RlZlByb3AodGFyZ2V0LCBuYW1lLCB7IGdldDogYWxsW25hbWVdLCBlbnVtZXJhYmxlOiB0cnVlIH0pOwp9OwoKLy8gc3JjL2RyYWZ0LXByL21haW4udHMKaW1wb3J0IHsgcmVhZEZpbGUgYXMgcmVhZEZpbGUyIH0gZnJvbSAibm9kZTpmcy9wcm9taXNlcyI7CmltcG9ydCBwYXRoMiBmcm9tICJub2RlOnBhdGgiOwppbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAibm9kZTp1cmwiOwoKLy8gc3JjL2dpdGh1Yi9hcHAtYXV0aC50cwppbXBvcnQgeyBzaWduIH0gZnJvbSAibm9kZTpjcnlwdG8iOwoKLy8gc3JjL2dpdGh1Yi9mZXRjaC1yZXRyeS50cwp2YXIgTUFYX0FUVEVNUFRTID0gMzsKdmFyIFJFVFJZQUJMRV9TVEFUVVNfQ09ERVMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbNTAyLCA1MDMsIDUwNF0pOwphc3luYyBmdW5jdGlvbiBmZXRjaFdpdGhSZXRyeShvcHRpb25zKSB7CiAgY29uc3QgYXR0ZW1wdHMgPSBvcHRpb25zLnJldHJ5YWJsZSA/IE1BWF9BVFRFTVBUUyA6IDE7CiAgbGV0IGxhc3RFcnJvcjsKICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBhdHRlbXB0czsgYXR0ZW1wdCArPSAxKSB7CiAgICB0cnkgewogICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IG9wdGlvbnMucmVxdWVzdChvcHRpb25zLmlucHV0LCBvcHRpb25zLmluaXQpOwogICAgICBpZiAoYXR0ZW1wdCA9PT0gYXR0ZW1wdHMgfHwgIVJFVFJZQUJMRV9TVEFUVVNfQ09ERVMuaGFzKHJlc3BvbnNlLnN0YXR1cykpIHsKICAgICAgICByZXR1cm4gcmVzcG9uc2U7CiAgICAgIH0KICAgICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCkuY2F0Y2goKCkgPT4gdm9pZCAwKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIGxhc3RFcnJvciA9IGVycm9yOwogICAgICBpZiAoYXR0ZW1wdCA9PT0gYXR0ZW1wdHMpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICAgICBgJHtvcHRpb25zLm9wZXJhdGlvbn0gdHJhbnNwb3J0IGZhaWxlZCBhZnRlciAke2F0dGVtcHRMYWJlbChhdHRlbXB0cyl9YCwKICAgICAgICAgIHsgY2F1c2U6IGVycm9yIH0KICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBhd2FpdCAob3B0aW9ucy5zbGVlcCA/PyBzbGVlcCkocmV0cnlEZWxheU1pbGxpc2Vjb25kcyhhdHRlbXB0KSk7CiAgfQogIHRocm93IG5ldyBFcnJvcihgJHtvcHRpb25zLm9wZXJhdGlvbn0gdHJhbnNwb3J0IGZhaWxlZGAsIHsKICAgIGNhdXNlOiBsYXN0RXJyb3IKICB9KTsKfQpmdW5jdGlvbiBhdHRlbXB0TGFiZWwoYXR0ZW1wdHMpIHsKICByZXR1cm4gYCR7YXR0ZW1wdHN9ICR7YXR0ZW1wdHMgPT09IDEgPyAiYXR0ZW1wdCIgOiAiYXR0ZW1wdHMifWA7Cn0KZnVuY3Rpb24gcmV0cnlEZWxheU1pbGxpc2Vjb25kcyhhdHRlbXB0KSB7CiAgY29uc3QgZXhwb25lbnRpYWwgPSAyNTAgKiAyICoqIChhdHRlbXB0IC0gMSk7CiAgcmV0dXJuIGV4cG9uZW50aWFsICsgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogZXhwb25lbnRpYWwpOwp9CmZ1bmN0aW9uIHNsZWVwKG1pbGxpc2Vjb25kcykgewogIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtaWxsaXNlY29uZHMpKTsKfQoKLy8gc3JjL2dpdGh1Yi9hcHAtYXV0aC50cwp2YXIgREVGQVVMVF9HSVRIVUJfQVBJX1VSTCA9ICJodHRwczovL2FwaS5naXRodWIuY29tIjsKdmFyIEdJVEhVQl9BUElfVkVSU0lPTiA9ICIyMDIyLTExLTI4IjsKYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUdpdEh1YlRva2VuKHJlcG9zaXRvcnksIGVudiA9IHByb2Nlc3MuZW52LCBkZXBlbmRlbmNpZXMgPSB7fSkgewogIGNvbnN0IGNvbmZpZ3VyZWRUb2tlbiA9IGVudi5HSVRIVUJfVE9LRU4/LnRyaW0oKSA/PyAiIjsKICBpZiAoY29uZmlndXJlZFRva2VuKSByZXR1cm4gY29uZmlndXJlZFRva2VuOwogIGNvbnN0IGNsaWVudElEID0gZW52LkdJVEhVQl9BUFBfQ0xJRU5UX0lEPy50cmltKCkgPz8gIiI7CiAgY29uc3QgYXBwSUQgPSBlbnYuR0lUSFVCX0FQUF9JRD8udHJpbSgpID8/ICIiOwogIGNvbnN0IHByaXZhdGVLZXlCYXNlNjQgPSBlbnYuR0lUSFVCX0FQUF9QUklWQVRFX0tFWV9CQVNFNjQ/LnRyaW0oKSA/PyAiIjsKICBjb25zdCBjb25maWd1cmVkSW5zdGFsbGF0aW9uSUQgPSBlbnYuR0lUSFVCX0FQUF9JTlNUQUxMQVRJT05fSUQ/LnRyaW0oKSA/PyAiIjsKICBjb25zdCBoYXNBcHBDb25maWd1cmF0aW9uID0gQm9vbGVhbigKICAgIGNsaWVudElEIHx8IGFwcElEIHx8IHByaXZhdGVLZXlCYXNlNjQgfHwgY29uZmlndXJlZEluc3RhbGxhdGlvbklECiAgKTsKICBpZiAoIWhhc0FwcENvbmZpZ3VyYXRpb24pIHJldHVybiAiIjsKICBjb25zdCBpc3N1ZXIgPSBjbGllbnRJRCB8fCBhcHBJRDsKICBpZiAoIWlzc3VlcikgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAiR2l0SHViIEFwcCBhdXRoZW50aWNhdGlvbiByZXF1aXJlcyBHSVRIVUJfQVBQX0NMSUVOVF9JRCBvciBHSVRIVUJfQVBQX0lEIgogICAgKTsKICB9CiAgaWYgKCFwcml2YXRlS2V5QmFzZTY0KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHaXRIdWIgQXBwIGF1dGhlbnRpY2F0aW9uIHJlcXVpcmVzIEdJVEhVQl9BUFBfUFJJVkFURV9LRVlfQkFTRTY0IgogICAgKTsKICB9CiAgY29uc3QgcHJpdmF0ZUtleSA9IGRlY29kZVByaXZhdGVLZXkocHJpdmF0ZUtleUJhc2U2NCk7CiAgY29uc3Qgand0ID0gY3JlYXRlQXBwSldUKAogICAgaXNzdWVyLAogICAgcHJpdmF0ZUtleSwKICAgIGRlcGVuZGVuY2llcy5ub3c/LigpID8/IERhdGUubm93KCkKICApOwogIGNvbnN0IGJhc2VVcmwgPSAoZW52LkdJVEhVQl9BUElfVVJMPy50cmltKCkgfHwgREVGQVVMVF9HSVRIVUJfQVBJX1VSTCkucmVwbGFjZSgvXC8rJC8sICIiKTsKICBjb25zdCByZXF1ZXN0ID0gZGVwZW5kZW5jaWVzLmZldGNoID8/IGZldGNoOwogIGNvbnN0IGluc3RhbGxhdGlvbklEID0gY29uZmlndXJlZEluc3RhbGxhdGlvbklEID8gdmFsaWRhdGVJbnN0YWxsYXRpb25JRChjb25maWd1cmVkSW5zdGFsbGF0aW9uSUQpIDogYXdhaXQgZmluZEluc3RhbGxhdGlvbklEKAogICAgYmFzZVVybCwKICAgIHJlcG9zaXRvcnksCiAgICBqd3QsCiAgICByZXF1ZXN0LAogICAgZGVwZW5kZW5jaWVzLnNsZWVwCiAgKTsKICBjb25zdCB0b2tlblBhdGggPSBgL2FwcC9pbnN0YWxsYXRpb25zLyR7aW5zdGFsbGF0aW9uSUR9L2FjY2Vzc190b2tlbnNgOwogIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2hXaXRoUmV0cnkoewogICAgcmVxdWVzdCwKICAgIGlucHV0OiBgJHtiYXNlVXJsfSR7dG9rZW5QYXRofWAsCiAgICBpbml0OiB7CiAgICAgIG1ldGhvZDogIlBPU1QiLAogICAgICBoZWFkZXJzOiBhcHBIZWFkZXJzKGp3dCkKICAgIH0sCiAgICBvcGVyYXRpb246IGBHaXRIdWIgQXBwIFBPU1QgJHt0b2tlblBhdGh9YCwKICAgIHJldHJ5YWJsZTogdHJ1ZSwKICAgIC4uLmRlcGVuZGVuY2llcy5zbGVlcCA/IHsgc2xlZXA6IGRlcGVuZGVuY2llcy5zbGVlcCB9IDoge30KICB9KTsKICBpZiAoIXJlc3BvbnNlLm9rKSB7CiAgICB0aHJvdyBnaXRodWJBcHBSZXNwb25zZUVycm9yKCJpbnN0YWxsYXRpb24gdG9rZW4gcmVxdWVzdCIsIHJlc3BvbnNlKTsKICB9CiAgY29uc3QgdmFsdWUgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7CiAgY29uc3QgdG9rZW4gPSB2YWx1ZS50b2tlbj8udHJpbSgpID8/ICIiOwogIGlmICghdG9rZW4pIHsKICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIEFwcCBpbnN0YWxsYXRpb24gdG9rZW4gcmVzcG9uc2UgaGFzIG5vIHRva2VuIik7CiAgfQogIHJldHVybiB0b2tlbjsKfQpmdW5jdGlvbiBjcmVhdGVBcHBKV1QoaXNzdWVyLCBwcml2YXRlS2V5LCBub3dNaWxsaXNlY29uZHMpIHsKICBjb25zdCBub3cgPSBNYXRoLmZsb29yKG5vd01pbGxpc2Vjb25kcyAvIDFlMyk7CiAgY29uc3QgaGVhZGVyID0gZW5jb2RlSldUUGFydCh7IGFsZzogIlJTMjU2IiwgdHlwOiAiSldUIiB9KTsKICBjb25zdCBwYXlsb2FkID0gZW5jb2RlSldUUGFydCh7CiAgICBpYXQ6IG5vdyAtIDYwLAogICAgZXhwOiBub3cgKyA5ICogNjAsCiAgICBpc3M6IGlzc3VlcgogIH0pOwogIGNvbnN0IHVuc2lnbmVkVG9rZW4gPSBgJHtoZWFkZXJ9LiR7cGF5bG9hZH1gOwogIGxldCBzaWduYXR1cmU7CiAgdHJ5IHsKICAgIHNpZ25hdHVyZSA9IHNpZ24oIlJTQS1TSEEyNTYiLCBCdWZmZXIuZnJvbSh1bnNpZ25lZFRva2VuKSwgcHJpdmF0ZUtleSk7CiAgfSBjYXRjaCB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHSVRIVUJfQVBQX1BSSVZBVEVfS0VZX0JBU0U2NCBpcyBub3QgYSB2YWxpZCBSU0EgcHJpdmF0ZSBrZXkiCiAgICApOwogIH0KICByZXR1cm4gYCR7dW5zaWduZWRUb2tlbn0uJHtzaWduYXR1cmUudG9TdHJpbmcoImJhc2U2NHVybCIpfWA7Cn0KYXN5bmMgZnVuY3Rpb24gZmluZEluc3RhbGxhdGlvbklEKGJhc2VVcmwsIHJlcG9zaXRvcnksIGp3dCwgcmVxdWVzdCwgc2xlZXBEZXBlbmRlbmN5KSB7CiAgY29uc3QgcGF0aDMgPSBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgocmVwb3NpdG9yeSl9L2luc3RhbGxhdGlvbmA7CiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaFdpdGhSZXRyeSh7CiAgICByZXF1ZXN0LAogICAgaW5wdXQ6IGAke2Jhc2VVcmx9JHtwYXRoM31gLAogICAgaW5pdDogewogICAgICBtZXRob2Q6ICJHRVQiLAogICAgICBoZWFkZXJzOiBhcHBIZWFkZXJzKGp3dCkKICAgIH0sCiAgICBvcGVyYXRpb246IGBHaXRIdWIgQXBwIEdFVCAke3BhdGgzfWAsCiAgICByZXRyeWFibGU6IHRydWUsCiAgICAuLi5zbGVlcERlcGVuZGVuY3kgPyB7IHNsZWVwOiBzbGVlcERlcGVuZGVuY3kgfSA6IHt9CiAgfSk7CiAgaWYgKCFyZXNwb25zZS5vaykgewogICAgdGhyb3cgZ2l0aHViQXBwUmVzcG9uc2VFcnJvcigiaW5zdGFsbGF0aW9uIGxvb2t1cCIsIHJlc3BvbnNlKTsKICB9CiAgY29uc3QgdmFsdWUgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7CiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcih2YWx1ZS5pZCkgfHwgKHZhbHVlLmlkID8/IDApIDw9IDApIHsKICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIEFwcCBpbnN0YWxsYXRpb24gcmVzcG9uc2UgaGFzIG5vIHZhbGlkIElEIik7CiAgfQogIHJldHVybiBTdHJpbmcodmFsdWUuaWQpOwp9CmZ1bmN0aW9uIGFwcEhlYWRlcnMoand0KSB7CiAgcmV0dXJuIHsKICAgIEFjY2VwdDogImFwcGxpY2F0aW9uL3ZuZC5naXRodWIranNvbiIsCiAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7and0fWAsCiAgICAiWC1HaXRIdWItQXBpLVZlcnNpb24iOiBHSVRIVUJfQVBJX1ZFUlNJT04sCiAgICAiVXNlci1BZ2VudCI6ICJlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MvZ2l0aHViLWFwcC1hdXRoIgogIH07Cn0KZnVuY3Rpb24gZGVjb2RlUHJpdmF0ZUtleSh2YWx1ZSkgewogIGxldCBkZWNvZGVkOwogIHRyeSB7CiAgICBkZWNvZGVkID0gQnVmZmVyLmZyb20odmFsdWUsICJiYXNlNjQiKS50b1N0cmluZygidXRmOCIpLnRyaW0oKTsKICB9IGNhdGNoIHsKICAgIHRocm93IG5ldyBFcnJvcigiR0lUSFVCX0FQUF9QUklWQVRFX0tFWV9CQVNFNjQgaXMgbm90IHZhbGlkIGJhc2U2NCIpOwogIH0KICBpZiAoIS9eLS0tLS1CRUdJTiAoPzpSU0EgKT9QUklWQVRFIEtFWS0tLS0tLy50ZXN0KGRlY29kZWQpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHSVRIVUJfQVBQX1BSSVZBVEVfS0VZX0JBU0U2NCBtdXN0IGRlY29kZSB0byBhIFBFTSBwcml2YXRlIGtleSIKICAgICk7CiAgfQogIHJldHVybiBkZWNvZGVkOwp9CmZ1bmN0aW9uIHZhbGlkYXRlSW5zdGFsbGF0aW9uSUQodmFsdWUpIHsKICBpZiAoIS9eWzEtOV1bMC05XSokLy50ZXN0KHZhbHVlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJHSVRIVUJfQVBQX0lOU1RBTExBVElPTl9JRCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciIpOwogIH0KICByZXR1cm4gdmFsdWU7Cn0KZnVuY3Rpb24gcmVwb3NpdG9yeVBhdGgocmVwb3NpdG9yeSkgewogIGNvbnN0IHBhcnRzID0gcmVwb3NpdG9yeS5zcGxpdCgiLyIpOwogIGlmIChwYXJ0cy5sZW5ndGggIT09IDIgfHwgcGFydHMuc29tZSgocGFydCkgPT4gIXBhcnQudHJpbSgpKSkgewogICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIEdpdEh1YiByZXBvc2l0b3J5OiAke3JlcG9zaXRvcnl9YCk7CiAgfQogIHJldHVybiBwYXJ0cy5tYXAoZW5jb2RlVVJJQ29tcG9uZW50KS5qb2luKCIvIik7Cn0KZnVuY3Rpb24gZW5jb2RlSldUUGFydCh2YWx1ZSkgewogIHJldHVybiBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeSh2YWx1ZSkpLnRvU3RyaW5nKCJiYXNlNjR1cmwiKTsKfQpmdW5jdGlvbiBnaXRodWJBcHBSZXNwb25zZUVycm9yKG9wZXJhdGlvbiwgcmVzcG9uc2UpIHsKICBjb25zdCBzdGF0dXMgPSBgJHtyZXNwb25zZS5zdGF0dXN9JHtyZXNwb25zZS5zdGF0dXNUZXh0ID8gYCAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCA6ICIifWA7CiAgcmV0dXJuIG5ldyBFcnJvcihgR2l0SHViIEFwcCAke29wZXJhdGlvbn0gZmFpbGVkIHdpdGggJHtzdGF0dXN9YCk7Cn0KCi8vIHNyYy9pc3N1ZXMvc2VhcmNoLnRzCmZ1bmN0aW9uIGlzc3VlU2VhcmNoVGV4dCh0aXRsZSkgewogIHJldHVybiB0aXRsZS5yZXBsYWNlKC9eXFtbXlxdXStcXVxzKjo/XHMqLywgIiIpLnJlcGxhY2UoL1siJ2A6Kygpe31bXF1cXF0vZywgIiAiKS5yZXBsYWNlKC9ccysvZywgIiAiKS50cmltKCkuc2xpY2UoMCwgMTIwKTsKfQoKLy8gc3JjL3J1bnRpbWUvdGV4dC50cwpmdW5jdGlvbiB0cnVuY2F0ZVRleHQodmFsdWUsIG1heCkgewogIHJldHVybiB2YWx1ZS5sZW5ndGggPD0gbWF4ID8gdmFsdWUgOiB2YWx1ZS5zbGljZSgwLCBtYXgpOwp9CgovLyBzcmMvZ2l0aHViL2NsaWVudC50cwp2YXIgR2l0SHViQ2xpZW50ID0gY2xhc3MgewogICN0b2tlbjsKICAjYmFzZVVybDsKICAjZmV0Y2g7CiAgI3NsZWVwOwogIGNvbnN0cnVjdG9yKG9wdGlvbnMgPSB7fSkgewogICAgdGhpcy4jdG9rZW4gPSBvcHRpb25zLnRva2VuPy50cmltKCkgPz8gIiI7CiAgICB0aGlzLiNiYXNlVXJsID0gKG9wdGlvbnMuYmFzZVVybCA/PyAiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbSIpLnJlcGxhY2UoCiAgICAgIC9cLyskLywKICAgICAgIiIKICAgICk7CiAgICB0aGlzLiNmZXRjaCA9IG9wdGlvbnMuZmV0Y2ggPz8gZmV0Y2g7CiAgICB0aGlzLiNzbGVlcCA9IG9wdGlvbnMuc2xlZXA7CiAgfQogIGFzeW5jIGdldElzc3VlKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyKSB7CiAgICBjb25zdCBpc3N1ZTIgPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiR0VUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9YAogICAgKTsKICAgIGlmIChpc3N1ZTIucHVsbF9yZXF1ZXN0KSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIHB1bGwgcmVxdWVzdCBwYXlsb2FkIGlzIG5vdCBhbiBJc3N1ZSIpOwogICAgfQogICAgcmV0dXJuIG5vcm1hbGl6ZUlzc3VlKGlzc3VlMik7CiAgfQogIGFzeW5jIHNlYXJjaENhbmRpZGF0ZXMocmVwb3NpdG9yeSwgaXNzdWUyLCBsaW1pdCkgewogICAgY29uc3QgdGl0bGUgPSBpc3N1ZVNlYXJjaFRleHQoaXNzdWUyLnRpdGxlKTsKICAgIGlmICghdGl0bGUpIHJldHVybiBbXTsKICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7CiAgICAgIHE6IGByZXBvOiR7cmVwb3NpdG9yeX0gaXM6aXNzdWUgaW46dGl0bGUgJHt0aXRsZX1gLAogICAgICBwZXJfcGFnZTogU3RyaW5nKE1hdGgubWluKE1hdGgubWF4KGxpbWl0ICsgMSwgMSksIDEwMCkpCiAgICB9KTsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvc2VhcmNoL2lzc3Vlcz8ke3F1ZXJ5LnRvU3RyaW5nKCl9YAogICAgKTsKICAgIHJldHVybiAocmVzcG9uc2UuaXRlbXMgPz8gW10pLmZpbHRlcigKICAgICAgKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm51bWJlciAhPT0gaXNzdWUyLm51bWJlciAmJiAhY2FuZGlkYXRlLnB1bGxfcmVxdWVzdAogICAgKS5zbGljZSgwLCBsaW1pdCkubWFwKChjYW5kaWRhdGUpID0+ICh7CiAgICAgIG51bWJlcjogY2FuZGlkYXRlLm51bWJlciwKICAgICAgdGl0bGU6IGNhbmRpZGF0ZS50aXRsZSwKICAgICAgYm9keTogdHJ1bmNhdGVUZXh0KGNhbmRpZGF0ZS5ib2R5ID8/ICIiLCA0ZTMpLAogICAgICBzdGF0ZTogY2FuZGlkYXRlLnN0YXRlLAogICAgICBsYWJlbHM6IGxhYmVsTmFtZXMoY2FuZGlkYXRlLmxhYmVscyksCiAgICAgIHVybDogY2FuZGlkYXRlLmh0bWxfdXJsCiAgICB9KSk7CiAgfQogIGFzeW5jIGxpc3RDb21tZW50cyhyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcikgewogICAgY29uc3QgY29tbWVudHMgPSBbXTsKICAgIGZvciAobGV0IHBhZ2UgPSAxOyA7IHBhZ2UgKz0gMSkgewogICAgICBjb25zdCBiYXRjaCA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICAgIkdFVCIsCiAgICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9L2NvbW1lbnRzP3Blcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIGNvbW1lbnRzLnB1c2goLi4uYmF0Y2gubWFwKG5vcm1hbGl6ZUNvbW1lbnQpKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIGNvbW1lbnRzOwogICAgfQogIH0KICBhc3luYyBlbnN1cmVMYWJlbChyZXBvc2l0b3J5LCBuYW1lLCBjb2xvciwgZGVzY3JpcHRpb24pIHsKICAgIGNvbnN0IHBhdGgzID0gYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vbGFiZWxzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpfWA7CiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuI3Jhd1JlcXVlc3QoIkdFVCIsIHBhdGgzKTsKICAgIGlmIChyZXNwb25zZS5vaykgcmV0dXJuOwogICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gNDA0KSB7CiAgICAgIHRocm93IGF3YWl0IHJlc3BvbnNlRXJyb3IoIkdFVCIsIHBhdGgzLCByZXNwb25zZSk7CiAgICB9CiAgICBhd2FpdCB0aGlzLiNyZXF1ZXN0KCJQT1NUIiwgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vbGFiZWxzYCwgewogICAgICBuYW1lLAogICAgICBjb2xvcjogbm9ybWFsaXplQ29sb3IoY29sb3IpLAogICAgICBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb24/LnRyaW0oKSB8fCAiTWFuYWdlZCBieSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MiCiAgICB9KTsKICB9CiAgYXN5bmMgZ2V0UmVwb3NpdG9yeURlZmF1bHRCcmFuY2gocmVwb3NpdG9yeSkgewogICAgY29uc3QgdmFsdWUgPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiR0VUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX1gCiAgICApOwogICAgY29uc3QgYnJhbmNoID0gdmFsdWUuZGVmYXVsdF9icmFuY2g/LnRyaW0oKTsKICAgIGlmICghYnJhbmNoKSB0aHJvdyBuZXcgRXJyb3IoIkdpdEh1YiByZXBvc2l0b3J5IGhhcyBubyBkZWZhdWx0IGJyYW5jaCIpOwogICAgcmV0dXJuIGJyYW5jaDsKICB9CiAgYXN5bmMgZ2V0UHVsbFJlcXVlc3QocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpIHsKICAgIGNvbnN0IHZhbHVlID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzLyR7cHVsbFJlcXVlc3ROdW1iZXJ9YAogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVQdWxsUmVxdWVzdCh2YWx1ZSk7CiAgfQogIGFzeW5jIGxpc3RPcGVuUHVsbFJlcXVlc3RzKHJlcG9zaXRvcnkpIHsKICAgIGNvbnN0IHZhbHVlcyA9IFtdOwogICAgZm9yIChsZXQgcGFnZSA9IDE7IDsgcGFnZSArPSAxKSB7CiAgICAgIGNvbnN0IGJhdGNoID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgICAiR0VUIiwKICAgICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9wdWxscz9zdGF0ZT1vcGVuJnBlcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIHZhbHVlcy5wdXNoKC4uLmJhdGNoLm1hcChub3JtYWxpemVQdWxsUmVxdWVzdCkpOwogICAgICBpZiAoYmF0Y2gubGVuZ3RoIDwgMTAwKSByZXR1cm4gdmFsdWVzOwogICAgfQogIH0KICBhc3luYyBsaXN0UmV2aWV3Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpIHsKICAgIGNvbnN0IGNvbW1lbnRzID0gW107CiAgICBmb3IgKGxldCBwYWdlID0gMTsgOyBwYWdlICs9IDEpIHsKICAgICAgY29uc3QgYmF0Y2ggPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAgICJHRVQiLAogICAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzLyR7cHVsbFJlcXVlc3ROdW1iZXJ9L2NvbW1lbnRzP3Blcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIGNvbW1lbnRzLnB1c2goLi4uYmF0Y2gubWFwKG5vcm1hbGl6ZVJldmlld0NvbW1lbnQpKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIGNvbW1lbnRzOwogICAgfQogIH0KICBhc3luYyBnZXRQdWxsUmVxdWVzdFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgcmV2aWV3SWQpIHsKICAgIGNvbnN0IHJldmlldyA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICJHRVQiLAogICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9wdWxscy8ke3B1bGxSZXF1ZXN0TnVtYmVyfS9yZXZpZXdzLyR7cmV2aWV3SWR9YAogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVQdWxsUmVxdWVzdFJldmlldyhyZXZpZXcpOwogIH0KICBhc3luYyBsaXN0Q2hlY2tSdW5zKHJlcG9zaXRvcnksIHJlZikgewogICAgaWYgKCEvXlswLTlhLWZdezQwfSQvLnRlc3QocmVmKSkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoImludmFsaWQgR2l0SHViIGNoZWNrIHJ1biByZWYiKTsKICAgIH0KICAgIGNvbnN0IHJ1bnMgPSBbXTsKICAgIGZvciAobGV0IHBhZ2UgPSAxOyA7IHBhZ2UgKz0gMSkgewogICAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICAgIkdFVCIsCiAgICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vY29tbWl0cy8ke3JlZn0vY2hlY2stcnVucz9wZXJfcGFnZT0xMDAmcGFnZT0ke3BhZ2V9YAogICAgICApOwogICAgICBjb25zdCBiYXRjaCA9IHZhbHVlLmNoZWNrX3J1bnMgPz8gW107CiAgICAgIHJ1bnMucHVzaCguLi5iYXRjaC5tYXAobm9ybWFsaXplQ2hlY2tSdW4pKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIHJ1bnM7CiAgICB9CiAgfQogIGFzeW5jIGxpc3RDaGVja1J1bkFubm90YXRpb25zKHJlcG9zaXRvcnksIGNoZWNrUnVuSWQpIHsKICAgIGlmICghTnVtYmVyLmlzU2FmZUludGVnZXIoY2hlY2tSdW5JZCkgfHwgY2hlY2tSdW5JZCA8PSAwKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiaW52YWxpZCBHaXRIdWIgY2hlY2sgcnVuIElEIik7CiAgICB9CiAgICBjb25zdCBhbm5vdGF0aW9ucyA9IFtdOwogICAgZm9yIChsZXQgcGFnZSA9IDE7IDsgcGFnZSArPSAxKSB7CiAgICAgIGNvbnN0IGJhdGNoID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgICAiR0VUIiwKICAgICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9jaGVjay1ydW5zLyR7Y2hlY2tSdW5JZH0vYW5ub3RhdGlvbnM/cGVyX3BhZ2U9MTAwJnBhZ2U9JHtwYWdlfWAKICAgICAgKTsKICAgICAgYW5ub3RhdGlvbnMucHVzaCguLi5iYXRjaC5tYXAobm9ybWFsaXplQ2hlY2tSdW5Bbm5vdGF0aW9uKSk7CiAgICAgIGlmIChiYXRjaC5sZW5ndGggPCAxMDApIHJldHVybiBhbm5vdGF0aW9uczsKICAgIH0KICB9CiAgYXN5bmMgbGlzdE9wZW5QdWxsUmVxdWVzdHNCeUhlYWQocmVwb3NpdG9yeSwgYnJhbmNoKSB7CiAgICBjb25zdCBvd25lciA9IHJlcG9zaXRvcnkuc3BsaXQoIi8iKVswXTsKICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7CiAgICAgIHN0YXRlOiAib3BlbiIsCiAgICAgIGhlYWQ6IGAke293bmVyfToke2JyYW5jaH1gLAogICAgICBwZXJfcGFnZTogIjEwMCIKICAgIH0pOwogICAgY29uc3QgdmFsdWVzID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzPyR7cXVlcnkudG9TdHJpbmcoKX1gCiAgICApOwogICAgcmV0dXJuIHZhbHVlcy5tYXAobm9ybWFsaXplUHVsbFJlcXVlc3QpOwogIH0KICBhc3luYyBjcmVhdGVEcmFmdFB1bGxSZXF1ZXN0KHJlcG9zaXRvcnksIGlucHV0KSB7CiAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICJQT1NUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vcHVsbHNgLAogICAgICB7IC4uLmlucHV0LCBkcmFmdDogdHJ1ZSB9CiAgICApOwogICAgcmV0dXJuIG5vcm1hbGl6ZVB1bGxSZXF1ZXN0KHZhbHVlKTsKICB9CiAgYXN5bmMgYWRkTGFiZWxzKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBsYWJlbHMpIHsKICAgIGlmIChsYWJlbHMubGVuZ3RoID09PSAwKSByZXR1cm47CiAgICBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiUE9TVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L2lzc3Vlcy8ke2lzc3VlTnVtYmVyfS9sYWJlbHNgLAogICAgICB7IGxhYmVscyB9CiAgICApOwogIH0KICBhc3luYyByZW1vdmVMYWJlbChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgbGFiZWwpIHsKICAgIGNvbnN0IHBhdGgzID0gYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9L2xhYmVscy8ke2VuY29kZVVSSUNvbXBvbmVudChsYWJlbCl9YDsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmF3UmVxdWVzdCgiREVMRVRFIiwgcGF0aDMpOwogICAgaWYgKCFyZXNwb25zZS5vayAmJiByZXNwb25zZS5zdGF0dXMgIT09IDQwNCkgewogICAgICB0aHJvdyBhd2FpdCByZXNwb25zZUVycm9yKCJERUxFVEUiLCBwYXRoMywgcmVzcG9uc2UpOwogICAgfQogIH0KICBhc3luYyBjcmVhdGVDb21tZW50KHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBib2R5KSB7CiAgICBjb25zdCBjb21tZW50ID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIlBPU1QiLAogICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9pc3N1ZXMvJHtpc3N1ZU51bWJlcn0vY29tbWVudHNgLAogICAgICB7IGJvZHkgfQogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVDb21tZW50KGNvbW1lbnQpOwogIH0KICBhc3luYyB1cGRhdGVDb21tZW50KHJlcG9zaXRvcnksIF9pc3N1ZU51bWJlciwgY29tbWVudElELCBib2R5KSB7CiAgICBjb25zdCBjb21tZW50ID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIlBBVENIIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzL2NvbW1lbnRzLyR7Y29tbWVudElEfWAsCiAgICAgIHsgYm9keSB9CiAgICApOwogICAgcmV0dXJuIG5vcm1hbGl6ZUNvbW1lbnQoY29tbWVudCk7CiAgfQogIGFzeW5jICNyZXF1ZXN0KG1ldGhvZCwgcGF0aDMsIGJvZHkpIHsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmF3UmVxdWVzdChtZXRob2QsIHBhdGgzLCBib2R5KTsKICAgIGlmICghcmVzcG9uc2Uub2spIHRocm93IGF3YWl0IHJlc3BvbnNlRXJyb3IobWV0aG9kLCBwYXRoMywgcmVzcG9uc2UpOwogICAgcmV0dXJuIGF3YWl0IHJlc3BvbnNlLmpzb24oKTsKICB9CiAgI3Jhd1JlcXVlc3QobWV0aG9kLCBwYXRoMywgYm9keSkgewogICAgY29uc3QgaGVhZGVycyA9IHsKICAgICAgQWNjZXB0OiAiYXBwbGljYXRpb24vdm5kLmdpdGh1Yitqc29uIiwKICAgICAgIlgtR2l0SHViLUFwaS1WZXJzaW9uIjogIjIwMjItMTEtMjgiLAogICAgICAiVXNlci1BZ2VudCI6ICJlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MvaXNzdWUtdHJpYWdlIgogICAgfTsKICAgIGlmICh0aGlzLiN0b2tlbikgaGVhZGVycy5BdXRob3JpemF0aW9uID0gYEJlYXJlciAke3RoaXMuI3Rva2VufWA7CiAgICBpZiAoYm9keSAhPT0gdm9pZCAwKSBoZWFkZXJzWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIjsKICAgIHJldHVybiBmZXRjaFdpdGhSZXRyeSh7CiAgICAgIHJlcXVlc3Q6IHRoaXMuI2ZldGNoLAogICAgICBpbnB1dDogYCR7dGhpcy4jYmFzZVVybH0ke3BhdGgzfWAsCiAgICAgIGluaXQ6IHsKICAgICAgICBtZXRob2QsCiAgICAgICAgaGVhZGVycywKICAgICAgICAuLi5ib2R5ID09PSB2b2lkIDAgPyB7fSA6IHsgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSkgfQogICAgICB9LAogICAgICBvcGVyYXRpb246IGBHaXRIdWIgQVBJICR7bWV0aG9kfSAke3BhdGgzfWAsCiAgICAgIHJldHJ5YWJsZTogbWV0aG9kID09PSAiR0VUIiwKICAgICAgLi4udGhpcy4jc2xlZXAgPyB7IHNsZWVwOiB0aGlzLiNzbGVlcCB9IDoge30KICAgIH0pOwogIH0KfTsKZnVuY3Rpb24gcmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpIHsKICBjb25zdCBwYXJ0cyA9IHJlcG9zaXRvcnkuc3BsaXQoIi8iKTsKICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzLnNvbWUoKHBhcnQpID0+ICFwYXJ0LnRyaW0oKSkpIHsKICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBHaXRIdWIgcmVwb3NpdG9yeTogJHtyZXBvc2l0b3J5fWApOwogIH0KICByZXR1cm4gcGFydHMubWFwKGVuY29kZVVSSUNvbXBvbmVudCkuam9pbigiLyIpOwp9CmZ1bmN0aW9uIG5vcm1hbGl6ZUlzc3VlKGlzc3VlMikgewogIHJldHVybiB7CiAgICBudW1iZXI6IGlzc3VlMi5udW1iZXIsCiAgICB0aXRsZTogaXNzdWUyLnRpdGxlLAogICAgYm9keTogaXNzdWUyLmJvZHksCiAgICBzdGF0ZTogaXNzdWUyLnN0YXRlLAogICAgaHRtbFVybDogaXNzdWUyLmh0bWxfdXJsLAogICAgdXBkYXRlZEF0OiBpc3N1ZTIudXBkYXRlZF9hdCwKICAgIGxhYmVsczogbGFiZWxOYW1lcyhpc3N1ZTIubGFiZWxzKSwKICAgIC4uLmlzc3VlMi51c2VyID8geyB1c2VyOiBub3JtYWxpemVVc2VyKGlzc3VlMi51c2VyKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZUNvbW1lbnQoY29tbWVudCkgewogIHJldHVybiB7CiAgICBpZDogY29tbWVudC5pZCwKICAgIGJvZHk6IGNvbW1lbnQuYm9keSwKICAgIC4uLmNvbW1lbnQuaHRtbF91cmwgPyB7IGh0bWxVcmw6IGNvbW1lbnQuaHRtbF91cmwgfSA6IHt9LAogICAgLi4uY29tbWVudC5jcmVhdGVkX2F0ID8geyBjcmVhdGVkQXQ6IGNvbW1lbnQuY3JlYXRlZF9hdCB9IDoge30sCiAgICAuLi5jb21tZW50LnVzZXIgPyB7IHVzZXI6IG5vcm1hbGl6ZVVzZXIoY29tbWVudC51c2VyKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVB1bGxSZXF1ZXN0KHZhbHVlKSB7CiAgcmV0dXJuIHsKICAgIG51bWJlcjogdmFsdWUubnVtYmVyLAogICAgdXJsOiB2YWx1ZS5odG1sX3VybCwKICAgIHN0YXRlOiB2YWx1ZS5zdGF0ZSwKICAgIGRyYWZ0OiB2YWx1ZS5kcmFmdCA/PyBmYWxzZSwKICAgIGhlYWQ6IHZhbHVlLmhlYWQucmVmLAogICAgLi4udmFsdWUuaGVhZC5zaGEgPyB7IGhlYWRTaGE6IHZhbHVlLmhlYWQuc2hhIH0gOiB7fSwKICAgIC4uLnZhbHVlLmhlYWQucmVwbz8uZnVsbF9uYW1lID8geyBoZWFkUmVwb3NpdG9yeTogdmFsdWUuaGVhZC5yZXBvLmZ1bGxfbmFtZSB9IDoge30sCiAgICBiYXNlOiB2YWx1ZS5iYXNlLnJlZgogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplUmV2aWV3Q29tbWVudChjb21tZW50KSB7CiAgcmV0dXJuIHsKICAgIGlkOiBjb21tZW50LmlkLAogICAgYm9keTogY29tbWVudC5ib2R5LAogICAgcGF0aDogY29tbWVudC5wYXRoLAogICAgLi4uY29tbWVudC51c2VyID8geyB1c2VyOiBub3JtYWxpemVVc2VyKGNvbW1lbnQudXNlcikgfSA6IHt9LAogICAgLi4uY29tbWVudC5odG1sX3VybCA/IHsgaHRtbFVybDogY29tbWVudC5odG1sX3VybCB9IDoge30sCiAgICAuLi5jb21tZW50LmNyZWF0ZWRfYXQgPyB7IGNyZWF0ZWRBdDogY29tbWVudC5jcmVhdGVkX2F0IH0gOiB7fSwKICAgIC4uLmNvbW1lbnQubGluZSAhPSBudWxsID8geyBsaW5lOiBjb21tZW50LmxpbmUgfSA6IHt9LAogICAgLi4uY29tbWVudC5vcmlnaW5hbF9saW5lICE9IG51bGwgPyB7IG9yaWdpbmFsTGluZTogY29tbWVudC5vcmlnaW5hbF9saW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQuc3RhcnRfbGluZSAhPSBudWxsID8geyBzdGFydExpbmU6IGNvbW1lbnQuc3RhcnRfbGluZSB9IDoge30sCiAgICAuLi5jb21tZW50Lm9yaWdpbmFsX3N0YXJ0X2xpbmUgIT0gbnVsbCA/IHsgb3JpZ2luYWxTdGFydExpbmU6IGNvbW1lbnQub3JpZ2luYWxfc3RhcnRfbGluZSB9IDoge30sCiAgICAuLi5jb21tZW50LnNpZGUgPyB7IHNpZGU6IGNvbW1lbnQuc2lkZSB9IDoge30sCiAgICAuLi5jb21tZW50LnN0YXJ0X3NpZGUgPyB7IHN0YXJ0U2lkZTogY29tbWVudC5zdGFydF9zaWRlIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQuZGlmZl9odW5rID8geyBkaWZmSHVuazogY29tbWVudC5kaWZmX2h1bmsgfSA6IHt9LAogICAgLi4uY29tbWVudC5jb21taXRfaWQgPyB7IGNvbW1pdElkOiBjb21tZW50LmNvbW1pdF9pZCB9IDoge30sCiAgICAuLi5jb21tZW50Lm9yaWdpbmFsX2NvbW1pdF9pZCA/IHsgb3JpZ2luYWxDb21taXRJZDogY29tbWVudC5vcmlnaW5hbF9jb21taXRfaWQgfSA6IHt9LAogICAgLi4uY29tbWVudC5pbl9yZXBseV90b19pZCAhPT0gdm9pZCAwID8geyBpblJlcGx5VG9JZDogY29tbWVudC5pbl9yZXBseV90b19pZCB9IDoge30sCiAgICAuLi5jb21tZW50LnB1bGxfcmVxdWVzdF9yZXZpZXdfaWQgIT09IHZvaWQgMCA/IHsgcHVsbFJlcXVlc3RSZXZpZXdJZDogY29tbWVudC5wdWxsX3JlcXVlc3RfcmV2aWV3X2lkIH0gOiB7fQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplUHVsbFJlcXVlc3RSZXZpZXcocmV2aWV3KSB7CiAgcmV0dXJuIHsKICAgIGlkOiByZXZpZXcuaWQsCiAgICBib2R5OiByZXZpZXcuYm9keSA/PyAiIiwKICAgIHN0YXRlOiByZXZpZXcuc3RhdGUsCiAgICBjb21taXRJZDogcmV2aWV3LmNvbW1pdF9pZCwKICAgIGF1dGhvckFzc29jaWF0aW9uOiByZXZpZXcuYXV0aG9yX2Fzc29jaWF0aW9uLAogICAgLi4ucmV2aWV3LnVzZXIgPyB7IHVzZXI6IG5vcm1hbGl6ZVVzZXIocmV2aWV3LnVzZXIpIH0gOiB7fSwKICAgIC4uLnJldmlldy5odG1sX3VybCA/IHsgaHRtbFVybDogcmV2aWV3Lmh0bWxfdXJsIH0gOiB7fSwKICAgIC4uLnJldmlldy5zdWJtaXR0ZWRfYXQgPyB7IHN1Ym1pdHRlZEF0OiByZXZpZXcuc3VibWl0dGVkX2F0IH0gOiB7fQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ2hlY2tSdW4odmFsdWUpIHsKICBjb25zdCBjaGVja1N1aXRlSWQgPSB2YWx1ZS5jaGVja19zdWl0ZT8uaWQ7CiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihjaGVja1N1aXRlSWQpIHx8IGNoZWNrU3VpdGVJZCA8PSAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYEdpdEh1YiBjaGVjayBydW4gJHt2YWx1ZS5pZH0gaGFzIG5vIHZhbGlkIGNoZWNrIHN1aXRlIElEYCk7CiAgfQogIHJldHVybiB7CiAgICBpZDogdmFsdWUuaWQsCiAgICBjaGVja1N1aXRlSWQsCiAgICBuYW1lOiB0cnVuY2F0ZVRleHQodmFsdWUubmFtZSA/PyAiIiwgMzAwKSwKICAgIHN0YXR1czogdmFsdWUuc3RhdHVzLAogICAgLi4udmFsdWUuY29uY2x1c2lvbiA/IHsgY29uY2x1c2lvbjogdmFsdWUuY29uY2x1c2lvbiB9IDoge30sCiAgICAuLi52YWx1ZS5odG1sX3VybCA/IHsgaHRtbFVybDogdmFsdWUuaHRtbF91cmwgfSA6IHt9LAogICAgb3V0cHV0OiB7CiAgICAgIHRpdGxlOiB0cnVuY2F0ZVRleHQodmFsdWUub3V0cHV0Py50aXRsZSA/PyAiIiwgMWUzKSwKICAgICAgc3VtbWFyeTogdHJ1bmNhdGVUZXh0KHZhbHVlLm91dHB1dD8uc3VtbWFyeSA/PyAiIiwgOGUzKSwKICAgICAgdGV4dDogdHJ1bmNhdGVUZXh0KHZhbHVlLm91dHB1dD8udGV4dCA/PyAiIiwgOGUzKQogICAgfQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ2hlY2tSdW5Bbm5vdGF0aW9uKHZhbHVlKSB7CiAgcmV0dXJuIHsKICAgIHBhdGg6IHRydW5jYXRlVGV4dCh2YWx1ZS5wYXRoID8/ICIiLCAxZTMpLAogICAgc3RhcnRMaW5lOiB2YWx1ZS5zdGFydF9saW5lLAogICAgZW5kTGluZTogdmFsdWUuZW5kX2xpbmUsCiAgICBsZXZlbDogdHJ1bmNhdGVUZXh0KHZhbHVlLmFubm90YXRpb25fbGV2ZWwgPz8gIiIsIDUwKSwKICAgIG1lc3NhZ2U6IHRydW5jYXRlVGV4dCh2YWx1ZS5tZXNzYWdlID8/ICIiLCAyZTMpLAogICAgLi4udmFsdWUudGl0bGUgPyB7IHRpdGxlOiB0cnVuY2F0ZVRleHQodmFsdWUudGl0bGUsIDUwMCkgfSA6IHt9LAogICAgLi4udmFsdWUucmF3X2RldGFpbHMgPyB7IHJhd0RldGFpbHM6IHRydW5jYXRlVGV4dCh2YWx1ZS5yYXdfZGV0YWlscywgNGUzKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVVzZXIodXNlcikgewogIHJldHVybiB7CiAgICBsb2dpbjogdXNlci5sb2dpbiwKICAgIC4uLnVzZXIuaWQgIT09IHZvaWQgMCA/IHsgaWQ6IHVzZXIuaWQgfSA6IHt9LAogICAgLi4udXNlci50eXBlID8geyB0eXBlOiB1c2VyLnR5cGUgfSA6IHt9CiAgfTsKfQpmdW5jdGlvbiBsYWJlbE5hbWVzKGxhYmVscykgewogIHJldHVybiBsYWJlbHMubWFwKChsYWJlbCkgPT4gdHlwZW9mIGxhYmVsID09PSAic3RyaW5nIiA/IGxhYmVsIDogbGFiZWwubmFtZSkuZmlsdGVyKChsYWJlbCkgPT4gbGFiZWwudHJpbSgpICE9PSAiIik7Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ29sb3IoY29sb3IpIHsKICBjb25zdCBub3JtYWxpemVkID0gY29sb3IudHJpbSgpLnJlcGxhY2UoL14jLywgIiIpOwogIHJldHVybiAvXlswLTlhLWZdezZ9JC9pLnRlc3Qobm9ybWFsaXplZCkgPyBub3JtYWxpemVkIDogImVkZWRlZCI7Cn0KYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2VFcnJvcihtZXRob2QsIHBhdGgzLCByZXNwb25zZSkgewogIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gIiIpOwogIHJldHVybiBuZXcgRXJyb3IoCiAgICBgR2l0SHViIEFQSSAke21ldGhvZH0gJHtwYXRoM30gZmFpbGVkIHdpdGggSFRUUCAke3Jlc3BvbnNlLnN0YXR1c306ICR7dHJ1bmNhdGVUZXh0KHRleHQsIDFlMyl9YAogICk7Cn0KCi8vIHNyYy9pc3N1ZXMvdHlwZXMudHMKZnVuY3Rpb24gaXNSZXBvc2l0b3J5U2x1Zyh2YWx1ZSkgewogIHJldHVybiAvXlteL1xzXStcL1teL1xzXSskLy50ZXN0KHZhbHVlKTsKfQoKLy8gc3JjL3J1bnRpbWUvY2xpLnRzCmZ1bmN0aW9uIHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCBpbmRleCwgbmFtZSkgewogIGNvbnN0IHZhbHVlID0gYXJnc1tpbmRleF0/LnRyaW0oKTsKICBpZiAoIXZhbHVlKSB0aHJvdyBuZXcgRXJyb3IoYCR7bmFtZX0gcmVxdWlyZXMgYSB2YWx1ZWApOwogIHJldHVybiB2YWx1ZTsKfQpmdW5jdGlvbiBlbnZCb29sZWFuKHZhbHVlKSB7CiAgcmV0dXJuIFsiMSIsICJ0cnVlIiwgInllcyIsICJvbiJdLmluY2x1ZGVzKHZhbHVlPy50cmltKCkudG9Mb3dlckNhc2UoKSA/PyAiIik7Cn0KCi8vIHNyYy9ydW50aW1lL2Vycm9ycy50cwpmdW5jdGlvbiBlcnJvck1lc3NhZ2UoZXJyb3IpIHsKICByZXR1cm4gZGVzY3JpYmVFcnJvcihlcnJvciwgLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKSwgMCk7Cn0KZnVuY3Rpb24gZGVzY3JpYmVFcnJvcihlcnJvciwgc2VlbiwgZGVwdGgpIHsKICBpZiAoIShlcnJvciBpbnN0YW5jZW9mIEVycm9yKSkgcmV0dXJuIFN0cmluZyhlcnJvcik7CiAgc2Vlbi5hZGQoZXJyb3IpOwogIGNvbnN0IGNvZGUgPSBlcnJvckNvZGUoZXJyb3IpOwogIGNvbnN0IGRlc2NyaXB0aW9uID0gZGVwdGggPT09IDAgPyBlcnJvci5tZXNzYWdlIDogYCR7ZXJyb3IubmFtZX0ke2NvZGUgPyBgIFske2NvZGV9XWAgOiAiIn06ICR7ZXJyb3IubWVzc2FnZX1gOwogIGlmIChkZXB0aCA+PSA0IHx8IGVycm9yLmNhdXNlID09PSB2b2lkIDAgfHwgc2Vlbi5oYXMoZXJyb3IuY2F1c2UpKSB7CiAgICByZXR1cm4gZGVzY3JpcHRpb247CiAgfQogIHJldHVybiBgJHtkZXNjcmlwdGlvbn07IGNhdXNlOiAke2Rlc2NyaWJlRXJyb3IoZXJyb3IuY2F1c2UsIHNlZW4sIGRlcHRoICsgMSl9YDsKfQpmdW5jdGlvbiBlcnJvckNvZGUoZXJyb3IpIHsKICBpZiAoISgiY29kZSIgaW4gZXJyb3IpKSByZXR1cm4gIiI7CiAgY29uc3QgdmFsdWUgPSBlcnJvci5jb2RlOwogIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciIHx8IHR5cGVvZiB2YWx1ZSA9PT0gIm51bWJlciIgPyBTdHJpbmcodmFsdWUpIDogIiI7Cn0KCi8vIHNyYy9ydW50aW1lL2xvYWQtanNvbi50cwppbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gIm5vZGU6ZnMvcHJvbWlzZXMiOwphc3luYyBmdW5jdGlvbiBsb2FkSnNvbkZyb21DYW5kaWRhdGVzKGNhbmRpZGF0ZXMsIHBhcnNlMywgZmFpbHVyZU1lc3NhZ2UpIHsKICBsZXQgbGFzdEVycm9yOwogIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGNhbmRpZGF0ZXMpIHsKICAgIHRyeSB7CiAgICAgIHJldHVybiBwYXJzZTMoSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShjYW5kaWRhdGUsICJ1dGY4IikpKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIGxhc3RFcnJvciA9IGVycm9yOwogICAgfQogIH0KICB0aHJvdyBuZXcgRXJyb3IoYCR7ZmFpbHVyZU1lc3NhZ2V9OiAke2Vycm9yTWVzc2FnZShsYXN0RXJyb3IpfWApOwp9CgovLyBzcmMvZHJhZnQtcHIvY2ktdG9vbC50cwppbXBvcnQgY3J5cHRvMyBmcm9tICJub2RlOmNyeXB0byI7CgovLyBzcmMvZHJhZnQtcHIvY2ktY29tbWVudC50cwp2YXIgQ0lfRklYX0NPTU1FTlRfUFJFRklYID0gIjwhLS0gZW5naW5lZXJpbmctYWdlbnQtd29ya2Zsb3dzOmNpLWZpeDp2MSI7CmZ1bmN0aW9uIGZpbmRDaUZpeENvbW1lbnQoY29tbWVudHMsIGJvdExvZ2luKSB7CiAgY29uc3QgZXhwZWN0ZWQgPSBib3RMb2dpbi50cmltKCkudG9Mb3dlckNhc2UoKTsKICByZXR1cm4gY29tbWVudHMuZmluZCgKICAgIChjb21tZW50KSA9PiBjb21tZW50LnVzZXI/LmxvZ2luLnRyaW0oKS50b0xvd2VyQ2FzZSgpID09PSBleHBlY3RlZCAmJiBjb21tZW50LmJvZHkuc3RhcnRzV2l0aChDSV9GSVhfQ09NTUVOVF9QUkVGSVgpCiAgKTsKfQpmdW5jdGlvbiBwYXJzZUNpRml4U3RhdGUoY29tbWVudCkgewogIGlmICghY29tbWVudCkgcmV0dXJuIGVtcHR5Q2lGaXhTdGF0ZSgpOwogIGNvbnN0IG1hcmtlciA9IGNvbW1lbnQuYm9keS5zcGxpdCgiXG4iLCAxKVswXSA/PyAiIjsKICBjb25zdCBtYXRjaCA9IG1hcmtlci5tYXRjaCgKICAgIC9ePCEtLSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3M6Y2ktZml4OnYxIHN1aXRlPShcZCspIGF0dGVtcHRzPShcZCspIGhlYWQ9KFswLTlhLWZdezQwfXxub25lKSBzdGF0dXM9KGZpeGluZ3xmaXhlZHxuby1jaGFuZ2V8bmVlZHMtYXBwcm92YWx8ZmFpbGVkKSAtLT4kLwogICk7CiAgaWYgKCFtYXRjaCkgcmV0dXJuIGVtcHR5Q2lGaXhTdGF0ZSgpOwogIHJldHVybiB7CiAgICBjaGVja1N1aXRlSWQ6IE51bWJlcihtYXRjaFsxXSksCiAgICBhdHRlbXB0czogTnVtYmVyKG1hdGNoWzJdKSwKICAgIGhlYWRTaGE6IG1hdGNoWzNdID09PSAibm9uZSIgPyAiIiA6IG1hdGNoWzNdLAogICAgc3RhdHVzOiBtYXRjaFs0XQogIH07Cn0KZnVuY3Rpb24gYnVpbGRDaUZpeENvbW1lbnQoc3RhdGUpIHsKICBjb25zdCBtYXJrZXIgPSBgJHtDSV9GSVhfQ09NTUVOVF9QUkVGSVh9IHN1aXRlPSR7c3RhdGUuY2hlY2tTdWl0ZUlkfSBhdHRlbXB0cz0ke3N0YXRlLmF0dGVtcHRzfSBoZWFkPSR7c3RhdGUuaGVhZFNoYSB8fCAibm9uZSJ9IHN0YXR1cz0ke3N0YXRlLnN0YXR1c30gLS0+YDsKICBjb25zdCBtZXNzYWdlcyA9IHsKICAgIGZpeGluZzogIlRoZSBEcmFmdCBQUiBBZ2VudCBpcyB2YWxpZGF0aW5nIHRoZSBsYXRlc3QgZmFpbGVkIENJIGNoZWNrcy4iLAogICAgZml4ZWQ6ICJUaGUgRHJhZnQgUFIgQWdlbnQgcHVzaGVkIGEgdmFsaWRhdGVkIGZpeCBmb3IgdGhlIGZhaWxlZCBDSSBjaGVja3MuIiwKICAgICJuby1jaGFuZ2UiOiAiVGhlIERyYWZ0IFBSIEFnZW50IGluc3BlY3RlZCB0aGUgZmFpbGVkIENJIGNoZWNrcyBhbmQgbWFkZSBubyBjb2RlIGNoYW5nZS4iLAogICAgIm5lZWRzLWFwcHJvdmFsIjogIkF1dG9tYXRpYyBDSSBmaXhlcyBwYXVzZWQgZm9yIG1haW50YWluZXIgcmV2aWV3LiIsCiAgICBmYWlsZWQ6ICJUaGUgRHJhZnQgUFIgQWdlbnQgY291bGQgbm90IGNvbXBsZXRlIHRoZSBsYXRlc3QgQ0kgZml4IGF0dGVtcHQuIgogIH07CiAgcmV0dXJuIFttYXJrZXIsICIjIyBDSSBmb2xsb3ctdXAiLCAiIiwgbWVzc2FnZXNbc3RhdGUuc3RhdHVzXV0uam9pbigiXG4iKTsKfQpmdW5jdGlvbiBlbXB0eUNpRml4U3RhdGUoKSB7CiAgcmV0dXJuIHsKICAgIGNoZWNrU3VpdGVJZDogMCwKICAgIGF0dGVtcHRzOiAwLAogICAgaGVhZFNoYTogIiIsCiAgICBzdGF0dXM6ICJmaXhlZCIKICB9Owp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvY29yZS5qcwp2YXIgX2E7Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uICRjb25zdHJ1Y3RvcihuYW1lLCBpbml0aWFsaXplcjMsIHBhcmFtcykgewogIGZ1bmN0aW9uIGluaXQoaW5zdCwgZGVmKSB7CiAgICBpZiAoIWluc3QuX3pvZCkgewogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgIl96b2QiLCB7CiAgICAgICAgdmFsdWU6IHsKICAgICAgICAgIGRlZiwKICAgICAgICAgIGNvbnN0cjogXywKICAgICAgICAgIHRyYWl0czogLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKQogICAgICAgIH0sCiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UKICAgICAgfSk7CiAgICB9CiAgICBpZiAoaW5zdC5fem9kLnRyYWl0cy5oYXMobmFtZSkpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgaW5zdC5fem9kLnRyYWl0cy5hZGQobmFtZSk7CiAgICBpbml0aWFsaXplcjMoaW5zdCwgZGVmKTsKICAgIGNvbnN0IHByb3RvID0gXy5wcm90b3R5cGU7CiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocHJvdG8pOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7CiAgICAgIGNvbnN0IGsgPSBrZXlzW2ldOwogICAgICBpZiAoIShrIGluIGluc3QpKSB7CiAgICAgICAgaW5zdFtrXSA9IHByb3RvW2tdLmJpbmQoaW5zdCk7CiAgICAgIH0KICAgIH0KICB9CiAgY29uc3QgUGFyZW50ID0gcGFyYW1zPy5QYXJlbnQgPz8gT2JqZWN0OwogIGNsYXNzIERlZmluaXRpb24gZXh0ZW5kcyBQYXJlbnQgewogIH0KICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRGVmaW5pdGlvbiwgIm5hbWUiLCB7IHZhbHVlOiBuYW1lIH0pOwogIGZ1bmN0aW9uIF8oZGVmKSB7CiAgICB2YXIgX2EzOwogICAgY29uc3QgaW5zdCA9IHBhcmFtcz8uUGFyZW50ID8gbmV3IERlZmluaXRpb24oKSA6IHRoaXM7CiAgICBpbml0KGluc3QsIGRlZik7CiAgICAoX2EzID0gaW5zdC5fem9kKS5kZWZlcnJlZCA/PyAoX2EzLmRlZmVycmVkID0gW10pOwogICAgZm9yIChjb25zdCBmbiBvZiBpbnN0Ll96b2QuZGVmZXJyZWQpIHsKICAgICAgZm4oKTsKICAgIH0KICAgIHJldHVybiBpbnN0OwogIH0KICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXywgImluaXQiLCB7IHZhbHVlOiBpbml0IH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShfLCBTeW1ib2wuaGFzSW5zdGFuY2UsIHsKICAgIHZhbHVlOiAoaW5zdCkgPT4gewogICAgICBpZiAocGFyYW1zPy5QYXJlbnQgJiYgaW5zdCBpbnN0YW5jZW9mIHBhcmFtcy5QYXJlbnQpCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIHJldHVybiBpbnN0Py5fem9kPy50cmFpdHM/LmhhcyhuYW1lKTsKICAgIH0KICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXywgIm5hbWUiLCB7IHZhbHVlOiBuYW1lIH0pOwogIHJldHVybiBfOwp9CnZhciAkWm9kQXN5bmNFcnJvciA9IGNsYXNzIGV4dGVuZHMgRXJyb3IgewogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoYEVuY291bnRlcmVkIFByb21pc2UgZHVyaW5nIHN5bmNocm9ub3VzIHBhcnNlLiBVc2UgLnBhcnNlQXN5bmMoKSBpbnN0ZWFkLmApOwogIH0KfTsKdmFyICRab2RFbmNvZGVFcnJvciA9IGNsYXNzIGV4dGVuZHMgRXJyb3IgewogIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgIHN1cGVyKGBFbmNvdW50ZXJlZCB1bmlkaXJlY3Rpb25hbCB0cmFuc2Zvcm0gZHVyaW5nIGVuY29kZTogJHtuYW1lfWApOwogICAgdGhpcy5uYW1lID0gIlpvZEVuY29kZUVycm9yIjsKICB9Cn07CihfYSA9IGdsb2JhbFRoaXMpLl9fem9kX2dsb2JhbENvbmZpZyA/PyAoX2EuX196b2RfZ2xvYmFsQ29uZmlnID0ge30pOwp2YXIgZ2xvYmFsQ29uZmlnID0gZ2xvYmFsVGhpcy5fX3pvZF9nbG9iYWxDb25maWc7CmZ1bmN0aW9uIGNvbmZpZyhuZXdDb25maWcpIHsKICBpZiAobmV3Q29uZmlnKQogICAgT2JqZWN0LmFzc2lnbihnbG9iYWxDb25maWcsIG5ld0NvbmZpZyk7CiAgcmV0dXJuIGdsb2JhbENvbmZpZzsKfQoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL3V0aWwuanMKdmFyIHV0aWxfZXhwb3J0cyA9IHt9OwpfX2V4cG9ydCh1dGlsX2V4cG9ydHMsIHsKICBCSUdJTlRfRk9STUFUX1JBTkdFUzogKCkgPT4gQklHSU5UX0ZPUk1BVF9SQU5HRVMsCiAgQ2xhc3M6ICgpID0+IENsYXNzLAogIE5VTUJFUl9GT1JNQVRfUkFOR0VTOiAoKSA9PiBOVU1CRVJfRk9STUFUX1JBTkdFUywKICBhYm9ydGVkOiAoKSA9PiBhYm9ydGVkLAogIGFsbG93c0V2YWw6ICgpID0+IGFsbG93c0V2YWwsCiAgYXNzZXJ0OiAoKSA9PiBhc3NlcnQsCiAgYXNzZXJ0RXF1YWw6ICgpID0+IGFzc2VydEVxdWFsLAogIGFzc2VydElzOiAoKSA9PiBhc3NlcnRJcywKICBhc3NlcnROZXZlcjogKCkgPT4gYXNzZXJ0TmV2ZXIsCiAgYXNzZXJ0Tm90RXF1YWw6ICgpID0+IGFzc2VydE5vdEVxdWFsLAogIGFzc2lnblByb3A6ICgpID0+IGFzc2lnblByb3AsCiAgYmFzZTY0VG9VaW50OEFycmF5OiAoKSA9PiBiYXNlNjRUb1VpbnQ4QXJyYXksCiAgYmFzZTY0dXJsVG9VaW50OEFycmF5OiAoKSA9PiBiYXNlNjR1cmxUb1VpbnQ4QXJyYXksCiAgY2FjaGVkOiAoKSA9PiBjYWNoZWQsCiAgY2FwdHVyZVN0YWNrVHJhY2U6ICgpID0+IGNhcHR1cmVTdGFja1RyYWNlLAogIGNsZWFuRW51bTogKCkgPT4gY2xlYW5FbnVtLAogIGNsZWFuUmVnZXg6ICgpID0+IGNsZWFuUmVnZXgsCiAgY2xvbmU6ICgpID0+IGNsb25lLAogIGNsb25lRGVmOiAoKSA9PiBjbG9uZURlZiwKICBjcmVhdGVUcmFuc3BhcmVudFByb3h5OiAoKSA9PiBjcmVhdGVUcmFuc3BhcmVudFByb3h5LAogIGRlZmluZUxhenk6ICgpID0+IGRlZmluZUxhenksCiAgZXNjOiAoKSA9PiBlc2MsCiAgZXNjYXBlUmVnZXg6ICgpID0+IGVzY2FwZVJlZ2V4LAogIGV4cGxpY2l0bHlBYm9ydGVkOiAoKSA9PiBleHBsaWNpdGx5QWJvcnRlZCwKICBleHRlbmQ6ICgpID0+IGV4dGVuZCwKICBmaW5hbGl6ZUlzc3VlOiAoKSA9PiBmaW5hbGl6ZUlzc3VlLAogIGZsb2F0U2FmZVJlbWFpbmRlcjogKCkgPT4gZmxvYXRTYWZlUmVtYWluZGVyLAogIGdldEVsZW1lbnRBdFBhdGg6ICgpID0+IGdldEVsZW1lbnRBdFBhdGgsCiAgZ2V0RW51bVZhbHVlczogKCkgPT4gZ2V0RW51bVZhbHVlcywKICBnZXRMZW5ndGhhYmxlT3JpZ2luOiAoKSA9PiBnZXRMZW5ndGhhYmxlT3JpZ2luLAogIGdldFBhcnNlZFR5cGU6ICgpID0+IGdldFBhcnNlZFR5cGUsCiAgZ2V0U2l6YWJsZU9yaWdpbjogKCkgPT4gZ2V0U2l6YWJsZU9yaWdpbiwKICBoZXhUb1VpbnQ4QXJyYXk6ICgpID0+IGhleFRvVWludDhBcnJheSwKICBpc09iamVjdDogKCkgPT4gaXNPYmplY3QsCiAgaXNQbGFpbk9iamVjdDogKCkgPT4gaXNQbGFpbk9iamVjdCwKICBpc3N1ZTogKCkgPT4gaXNzdWUsCiAgam9pblZhbHVlczogKCkgPT4gam9pblZhbHVlcywKICBqc29uU3RyaW5naWZ5UmVwbGFjZXI6ICgpID0+IGpzb25TdHJpbmdpZnlSZXBsYWNlciwKICBtZXJnZTogKCkgPT4gbWVyZ2UsCiAgbWVyZ2VEZWZzOiAoKSA9PiBtZXJnZURlZnMsCiAgbm9ybWFsaXplUGFyYW1zOiAoKSA9PiBub3JtYWxpemVQYXJhbXMsCiAgbnVsbGlzaDogKCkgPT4gbnVsbGlzaCwKICBudW1LZXlzOiAoKSA9PiBudW1LZXlzLAogIG9iamVjdENsb25lOiAoKSA9PiBvYmplY3RDbG9uZSwKICBvbWl0OiAoKSA9PiBvbWl0LAogIG9wdGlvbmFsS2V5czogKCkgPT4gb3B0aW9uYWxLZXlzLAogIHBhcnNlZFR5cGU6ICgpID0+IHBhcnNlZFR5cGUsCiAgcGFydGlhbDogKCkgPT4gcGFydGlhbCwKICBwaWNrOiAoKSA9PiBwaWNrLAogIHByZWZpeElzc3VlczogKCkgPT4gcHJlZml4SXNzdWVzLAogIHByaW1pdGl2ZVR5cGVzOiAoKSA9PiBwcmltaXRpdmVUeXBlcywKICBwcm9taXNlQWxsT2JqZWN0OiAoKSA9PiBwcm9taXNlQWxsT2JqZWN0LAogIHByb3BlcnR5S2V5VHlwZXM6ICgpID0+IHByb3BlcnR5S2V5VHlwZXMsCiAgcmFuZG9tU3RyaW5nOiAoKSA9PiByYW5kb21TdHJpbmcsCiAgcmVxdWlyZWQ6ICgpID0+IHJlcXVpcmVkLAogIHNhZmVFeHRlbmQ6ICgpID0+IHNhZmVFeHRlbmQsCiAgc2hhbGxvd0Nsb25lOiAoKSA9PiBzaGFsbG93Q2xvbmUsCiAgc2x1Z2lmeTogKCkgPT4gc2x1Z2lmeSwKICBzdHJpbmdpZnlQcmltaXRpdmU6ICgpID0+IHN0cmluZ2lmeVByaW1pdGl2ZSwKICB1aW50OEFycmF5VG9CYXNlNjQ6ICgpID0+IHVpbnQ4QXJyYXlUb0Jhc2U2NCwKICB1aW50OEFycmF5VG9CYXNlNjR1cmw6ICgpID0+IHVpbnQ4QXJyYXlUb0Jhc2U2NHVybCwKICB1aW50OEFycmF5VG9IZXg6ICgpID0+IHVpbnQ4QXJyYXlUb0hleCwKICB1bndyYXBNZXNzYWdlOiAoKSA9PiB1bndyYXBNZXNzYWdlCn0pOwpmdW5jdGlvbiBhc3NlcnRFcXVhbCh2YWwpIHsKICByZXR1cm4gdmFsOwp9CmZ1bmN0aW9uIGFzc2VydE5vdEVxdWFsKHZhbCkgewogIHJldHVybiB2YWw7Cn0KZnVuY3Rpb24gYXNzZXJ0SXMoX2FyZykgewp9CmZ1bmN0aW9uIGFzc2VydE5ldmVyKF94KSB7CiAgdGhyb3cgbmV3IEVycm9yKCJVbmV4cGVjdGVkIHZhbHVlIGluIGV4aGF1c3RpdmUgY2hlY2siKTsKfQpmdW5jdGlvbiBhc3NlcnQoXykgewp9CmZ1bmN0aW9uIGdldEVudW1WYWx1ZXMoZW50cmllcykgewogIGNvbnN0IG51bWVyaWNWYWx1ZXMgPSBPYmplY3QudmFsdWVzKGVudHJpZXMpLmZpbHRlcigodikgPT4gdHlwZW9mIHYgPT09ICJudW1iZXIiKTsKICBjb25zdCB2YWx1ZXMgPSBPYmplY3QuZW50cmllcyhlbnRyaWVzKS5maWx0ZXIoKFtrLCBfXSkgPT4gbnVtZXJpY1ZhbHVlcy5pbmRleE9mKCtrKSA9PT0gLTEpLm1hcCgoW18sIHZdKSA9PiB2KTsKICByZXR1cm4gdmFsdWVzOwp9CmZ1bmN0aW9uIGpvaW5WYWx1ZXMoYXJyYXkyLCBzZXBhcmF0b3IgPSAifCIpIHsKICByZXR1cm4gYXJyYXkyLm1hcCgodmFsKSA9PiBzdHJpbmdpZnlQcmltaXRpdmUodmFsKSkuam9pbihzZXBhcmF0b3IpOwp9CmZ1bmN0aW9uIGpzb25TdHJpbmdpZnlSZXBsYWNlcihfLCB2YWx1ZSkgewogIGlmICh0eXBlb2YgdmFsdWUgPT09ICJiaWdpbnQiKQogICAgcmV0dXJuIHZhbHVlLnRvU3RyaW5nKCk7CiAgcmV0dXJuIHZhbHVlOwp9CmZ1bmN0aW9uIGNhY2hlZChnZXR0ZXIpIHsKICBjb25zdCBzZXQgPSBmYWxzZTsKICByZXR1cm4gewogICAgZ2V0IHZhbHVlKCkgewogICAgICBpZiAoIXNldCkgewogICAgICAgIGNvbnN0IHZhbHVlID0gZ2V0dGVyKCk7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICJ2YWx1ZSIsIHsgdmFsdWUgfSk7CiAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICB9CiAgICAgIHRocm93IG5ldyBFcnJvcigiY2FjaGVkIHZhbHVlIGFscmVhZHkgc2V0Iik7CiAgICB9CiAgfTsKfQpmdW5jdGlvbiBudWxsaXNoKGlucHV0KSB7CiAgcmV0dXJuIGlucHV0ID09PSBudWxsIHx8IGlucHV0ID09PSB2b2lkIDA7Cn0KZnVuY3Rpb24gY2xlYW5SZWdleChzb3VyY2UpIHsKICBjb25zdCBzdGFydCA9IHNvdXJjZS5zdGFydHNXaXRoKCJeIikgPyAxIDogMDsKICBjb25zdCBlbmQgPSBzb3VyY2UuZW5kc1dpdGgoIiQiKSA/IHNvdXJjZS5sZW5ndGggLSAxIDogc291cmNlLmxlbmd0aDsKICByZXR1cm4gc291cmNlLnNsaWNlKHN0YXJ0LCBlbmQpOwp9CmZ1bmN0aW9uIGZsb2F0U2FmZVJlbWFpbmRlcih2YWwsIHN0ZXApIHsKICBjb25zdCByYXRpbyA9IHZhbCAvIHN0ZXA7CiAgY29uc3Qgcm91bmRlZFJhdGlvID0gTWF0aC5yb3VuZChyYXRpbyk7CiAgY29uc3QgdG9sZXJhbmNlID0gTnVtYmVyLkVQU0lMT04gKiBNYXRoLm1heChNYXRoLmFicyhyYXRpbyksIDEpOwogIGlmIChNYXRoLmFicyhyYXRpbyAtIHJvdW5kZWRSYXRpbykgPCB0b2xlcmFuY2UpCiAgICByZXR1cm4gMDsKICByZXR1cm4gcmF0aW8gLSByb3VuZGVkUmF0aW87Cn0KdmFyIEVWQUxVQVRJTkcgPSAvKiBAX19QVVJFX18gKi8gU3ltYm9sKCJldmFsdWF0aW5nIik7CmZ1bmN0aW9uIGRlZmluZUxhenkob2JqZWN0Miwga2V5LCBnZXR0ZXIpIHsKICBsZXQgdmFsdWUgPSB2b2lkIDA7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdDIsIGtleSwgewogICAgZ2V0KCkgewogICAgICBpZiAodmFsdWUgPT09IEVWQUxVQVRJTkcpIHsKICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICB9CiAgICAgIGlmICh2YWx1ZSA9PT0gdm9pZCAwKSB7CiAgICAgICAgdmFsdWUgPSBFVkFMVUFUSU5HOwogICAgICAgIHZhbHVlID0gZ2V0dGVyKCk7CiAgICAgIH0KICAgICAgcmV0dXJuIHZhbHVlOwogICAgfSwKICAgIHNldCh2KSB7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmplY3QyLCBrZXksIHsKICAgICAgICB2YWx1ZTogdgogICAgICAgIC8vIGNvbmZpZ3VyYWJsZTogdHJ1ZSwKICAgICAgfSk7CiAgICB9LAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7Cn0KZnVuY3Rpb24gb2JqZWN0Q2xvbmUob2JqKSB7CiAgcmV0dXJuIE9iamVjdC5jcmVhdGUoT2JqZWN0LmdldFByb3RvdHlwZU9mKG9iaiksIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKG9iaikpOwp9CmZ1bmN0aW9uIGFzc2lnblByb3AodGFyZ2V0LCBwcm9wLCB2YWx1ZSkgewogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3AsIHsKICAgIHZhbHVlLAogICAgd3JpdGFibGU6IHRydWUsCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7Cn0KZnVuY3Rpb24gbWVyZ2VEZWZzKC4uLmRlZnMpIHsKICBjb25zdCBtZXJnZWREZXNjcmlwdG9ycyA9IHt9OwogIGZvciAoY29uc3QgZGVmIG9mIGRlZnMpIHsKICAgIGNvbnN0IGRlc2NyaXB0b3JzID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoZGVmKTsKICAgIE9iamVjdC5hc3NpZ24obWVyZ2VkRGVzY3JpcHRvcnMsIGRlc2NyaXB0b3JzKTsKICB9CiAgcmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHt9LCBtZXJnZWREZXNjcmlwdG9ycyk7Cn0KZnVuY3Rpb24gY2xvbmVEZWYoc2NoZW1hKSB7CiAgcmV0dXJuIG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYpOwp9CmZ1bmN0aW9uIGdldEVsZW1lbnRBdFBhdGgob2JqLCBwYXRoMykgewogIGlmICghcGF0aDMpCiAgICByZXR1cm4gb2JqOwogIHJldHVybiBwYXRoMy5yZWR1Y2UoKGFjYywga2V5KSA9PiBhY2M/LltrZXldLCBvYmopOwp9CmZ1bmN0aW9uIHByb21pc2VBbGxPYmplY3QocHJvbWlzZXNPYmopIHsKICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocHJvbWlzZXNPYmopOwogIGNvbnN0IHByb21pc2VzID0ga2V5cy5tYXAoKGtleSkgPT4gcHJvbWlzZXNPYmpba2V5XSk7CiAgcmV0dXJuIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKChyZXN1bHRzKSA9PiB7CiAgICBjb25zdCByZXNvbHZlZE9iaiA9IHt9OwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7CiAgICAgIHJlc29sdmVkT2JqW2tleXNbaV1dID0gcmVzdWx0c1tpXTsKICAgIH0KICAgIHJldHVybiByZXNvbHZlZE9iajsKICB9KTsKfQpmdW5jdGlvbiByYW5kb21TdHJpbmcobGVuZ3RoID0gMTApIHsKICBjb25zdCBjaGFycyA9ICJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiI7CiAgbGV0IHN0ciA9ICIiOwogIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgIHN0ciArPSBjaGFyc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBjaGFycy5sZW5ndGgpXTsKICB9CiAgcmV0dXJuIHN0cjsKfQpmdW5jdGlvbiBlc2Moc3RyKSB7CiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHN0cik7Cn0KZnVuY3Rpb24gc2x1Z2lmeShpbnB1dCkgewogIHJldHVybiBpbnB1dC50b0xvd2VyQ2FzZSgpLnRyaW0oKS5yZXBsYWNlKC9bXlx3XHMtXS9nLCAiIikucmVwbGFjZSgvW1xzXy1dKy9nLCAiLSIpLnJlcGxhY2UoL14tK3wtKyQvZywgIiIpOwp9CnZhciBjYXB0dXJlU3RhY2tUcmFjZSA9ICJjYXB0dXJlU3RhY2tUcmFjZSIgaW4gRXJyb3IgPyBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSA6ICguLi5fYXJncykgPT4gewp9OwpmdW5jdGlvbiBpc09iamVjdChkYXRhKSB7CiAgcmV0dXJuIHR5cGVvZiBkYXRhID09PSAib2JqZWN0IiAmJiBkYXRhICE9PSBudWxsICYmICFBcnJheS5pc0FycmF5KGRhdGEpOwp9CnZhciBhbGxvd3NFdmFsID0gLyogQF9fUFVSRV9fICovIGNhY2hlZCgoKSA9PiB7CiAgaWYgKGdsb2JhbENvbmZpZy5qaXRsZXNzKSB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQogIGlmICh0eXBlb2YgbmF2aWdhdG9yICE9PSAidW5kZWZpbmVkIiAmJiBuYXZpZ2F0b3I/LnVzZXJBZ2VudD8uaW5jbHVkZXMoIkNsb3VkZmxhcmUiKSkgewogICAgcmV0dXJuIGZhbHNlOwogIH0KICB0cnkgewogICAgY29uc3QgRiA9IEZ1bmN0aW9uOwogICAgbmV3IEYoIiIpOwogICAgcmV0dXJuIHRydWU7CiAgfSBjYXRjaCAoXykgewogICAgcmV0dXJuIGZhbHNlOwogIH0KfSk7CmZ1bmN0aW9uIGlzUGxhaW5PYmplY3QobykgewogIGlmIChpc09iamVjdChvKSA9PT0gZmFsc2UpCiAgICByZXR1cm4gZmFsc2U7CiAgY29uc3QgY3RvciA9IG8uY29uc3RydWN0b3I7CiAgaWYgKGN0b3IgPT09IHZvaWQgMCkKICAgIHJldHVybiB0cnVlOwogIGlmICh0eXBlb2YgY3RvciAhPT0gImZ1bmN0aW9uIikKICAgIHJldHVybiB0cnVlOwogIGNvbnN0IHByb3QgPSBjdG9yLnByb3RvdHlwZTsKICBpZiAoaXNPYmplY3QocHJvdCkgPT09IGZhbHNlKQogICAgcmV0dXJuIGZhbHNlOwogIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocHJvdCwgImlzUHJvdG90eXBlT2YiKSA9PT0gZmFsc2UpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHRydWU7Cn0KZnVuY3Rpb24gc2hhbGxvd0Nsb25lKG8pIHsKICBpZiAoaXNQbGFpbk9iamVjdChvKSkKICAgIHJldHVybiB7IC4uLm8gfTsKICBpZiAoQXJyYXkuaXNBcnJheShvKSkKICAgIHJldHVybiBbLi4ub107CiAgaWYgKG8gaW5zdGFuY2VvZiBNYXApCiAgICByZXR1cm4gbmV3IE1hcChvKTsKICBpZiAobyBpbnN0YW5jZW9mIFNldCkKICAgIHJldHVybiBuZXcgU2V0KG8pOwogIHJldHVybiBvOwp9CmZ1bmN0aW9uIG51bUtleXMoZGF0YSkgewogIGxldCBrZXlDb3VudCA9IDA7CiAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkgewogICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChkYXRhLCBrZXkpKSB7CiAgICAgIGtleUNvdW50Kys7CiAgICB9CiAgfQogIHJldHVybiBrZXlDb3VudDsKfQp2YXIgZ2V0UGFyc2VkVHlwZSA9IChkYXRhKSA9PiB7CiAgY29uc3QgdCA9IHR5cGVvZiBkYXRhOwogIHN3aXRjaCAodCkgewogICAgY2FzZSAidW5kZWZpbmVkIjoKICAgICAgcmV0dXJuICJ1bmRlZmluZWQiOwogICAgY2FzZSAic3RyaW5nIjoKICAgICAgcmV0dXJuICJzdHJpbmciOwogICAgY2FzZSAibnVtYmVyIjoKICAgICAgcmV0dXJuIE51bWJlci5pc05hTihkYXRhKSA/ICJuYW4iIDogIm51bWJlciI7CiAgICBjYXNlICJib29sZWFuIjoKICAgICAgcmV0dXJuICJib29sZWFuIjsKICAgIGNhc2UgImZ1bmN0aW9uIjoKICAgICAgcmV0dXJuICJmdW5jdGlvbiI7CiAgICBjYXNlICJiaWdpbnQiOgogICAgICByZXR1cm4gImJpZ2ludCI7CiAgICBjYXNlICJzeW1ib2wiOgogICAgICByZXR1cm4gInN5bWJvbCI7CiAgICBjYXNlICJvYmplY3QiOgogICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkgewogICAgICAgIHJldHVybiAiYXJyYXkiOwogICAgICB9CiAgICAgIGlmIChkYXRhID09PSBudWxsKSB7CiAgICAgICAgcmV0dXJuICJudWxsIjsKICAgICAgfQogICAgICBpZiAoZGF0YS50aGVuICYmIHR5cGVvZiBkYXRhLnRoZW4gPT09ICJmdW5jdGlvbiIgJiYgZGF0YS5jYXRjaCAmJiB0eXBlb2YgZGF0YS5jYXRjaCA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIHJldHVybiAicHJvbWlzZSI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBNYXAgIT09ICJ1bmRlZmluZWQiICYmIGRhdGEgaW5zdGFuY2VvZiBNYXApIHsKICAgICAgICByZXR1cm4gIm1hcCI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBTZXQgIT09ICJ1bmRlZmluZWQiICYmIGRhdGEgaW5zdGFuY2VvZiBTZXQpIHsKICAgICAgICByZXR1cm4gInNldCI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBEYXRlICE9PSAidW5kZWZpbmVkIiAmJiBkYXRhIGluc3RhbmNlb2YgRGF0ZSkgewogICAgICAgIHJldHVybiAiZGF0ZSI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBGaWxlICE9PSAidW5kZWZpbmVkIiAmJiBkYXRhIGluc3RhbmNlb2YgRmlsZSkgewogICAgICAgIHJldHVybiAiZmlsZSI7CiAgICAgIH0KICAgICAgcmV0dXJuICJvYmplY3QiOwogICAgZGVmYXVsdDoKICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGRhdGEgdHlwZTogJHt0fWApOwogIH0KfTsKdmFyIHByb3BlcnR5S2V5VHlwZXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbInN0cmluZyIsICJudW1iZXIiLCAic3ltYm9sIl0pOwp2YXIgcHJpbWl0aXZlVHlwZXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbCiAgInN0cmluZyIsCiAgIm51bWJlciIsCiAgImJpZ2ludCIsCiAgImJvb2xlYW4iLAogICJzeW1ib2wiLAogICJ1bmRlZmluZWQiCl0pOwpmdW5jdGlvbiBlc2NhcGVSZWdleChzdHIpIHsKICByZXR1cm4gc3RyLnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXVxcXS9nLCAiXFwkJiIpOwp9CmZ1bmN0aW9uIGNsb25lKGluc3QsIGRlZiwgcGFyYW1zKSB7CiAgY29uc3QgY2wgPSBuZXcgaW5zdC5fem9kLmNvbnN0cihkZWYgPz8gaW5zdC5fem9kLmRlZik7CiAgaWYgKCFkZWYgfHwgcGFyYW1zPy5wYXJlbnQpCiAgICBjbC5fem9kLnBhcmVudCA9IGluc3Q7CiAgcmV0dXJuIGNsOwp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVBhcmFtcyhfcGFyYW1zKSB7CiAgY29uc3QgcGFyYW1zID0gX3BhcmFtczsKICBpZiAoIXBhcmFtcykKICAgIHJldHVybiB7fTsKICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gInN0cmluZyIpCiAgICByZXR1cm4geyBlcnJvcjogKCkgPT4gcGFyYW1zIH07CiAgaWYgKHBhcmFtcz8ubWVzc2FnZSAhPT0gdm9pZCAwKSB7CiAgICBpZiAocGFyYW1zPy5lcnJvciAhPT0gdm9pZCAwKQogICAgICB0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBzcGVjaWZ5IGJvdGggYG1lc3NhZ2VgIGFuZCBgZXJyb3JgIHBhcmFtcyIpOwogICAgcGFyYW1zLmVycm9yID0gcGFyYW1zLm1lc3NhZ2U7CiAgfQogIGRlbGV0ZSBwYXJhbXMubWVzc2FnZTsKICBpZiAodHlwZW9mIHBhcmFtcy5lcnJvciA9PT0gInN0cmluZyIpCiAgICByZXR1cm4geyAuLi5wYXJhbXMsIGVycm9yOiAoKSA9PiBwYXJhbXMuZXJyb3IgfTsKICByZXR1cm4gcGFyYW1zOwp9CmZ1bmN0aW9uIGNyZWF0ZVRyYW5zcGFyZW50UHJveHkoZ2V0dGVyKSB7CiAgbGV0IHRhcmdldDsKICByZXR1cm4gbmV3IFByb3h5KHt9LCB7CiAgICBnZXQoXywgcHJvcCwgcmVjZWl2ZXIpIHsKICAgICAgdGFyZ2V0ID8/ICh0YXJnZXQgPSBnZXR0ZXIoKSk7CiAgICAgIHJldHVybiBSZWZsZWN0LmdldCh0YXJnZXQsIHByb3AsIHJlY2VpdmVyKTsKICAgIH0sCiAgICBzZXQoXywgcHJvcCwgdmFsdWUsIHJlY2VpdmVyKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5zZXQodGFyZ2V0LCBwcm9wLCB2YWx1ZSwgcmVjZWl2ZXIpOwogICAgfSwKICAgIGhhcyhfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5oYXModGFyZ2V0LCBwcm9wKTsKICAgIH0sCiAgICBkZWxldGVQcm9wZXJ0eShfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5kZWxldGVQcm9wZXJ0eSh0YXJnZXQsIHByb3ApOwogICAgfSwKICAgIG93bktleXMoXykgewogICAgICB0YXJnZXQgPz8gKHRhcmdldCA9IGdldHRlcigpKTsKICAgICAgcmV0dXJuIFJlZmxlY3Qub3duS2V5cyh0YXJnZXQpOwogICAgfSwKICAgIGdldE93blByb3BlcnR5RGVzY3JpcHRvcihfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBwcm9wKTsKICAgIH0sCiAgICBkZWZpbmVQcm9wZXJ0eShfLCBwcm9wLCBkZXNjcmlwdG9yKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3AsIGRlc2NyaXB0b3IpOwogICAgfQogIH0pOwp9CmZ1bmN0aW9uIHN0cmluZ2lmeVByaW1pdGl2ZSh2YWx1ZSkgewogIGlmICh0eXBlb2YgdmFsdWUgPT09ICJiaWdpbnQiKQogICAgcmV0dXJuIHZhbHVlLnRvU3RyaW5nKCkgKyAibiI7CiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gInN0cmluZyIpCiAgICByZXR1cm4gYCIke3ZhbHVlfSJgOwogIHJldHVybiBgJHt2YWx1ZX1gOwp9CmZ1bmN0aW9uIG9wdGlvbmFsS2V5cyhzaGFwZSkgewogIHJldHVybiBPYmplY3Qua2V5cyhzaGFwZSkuZmlsdGVyKChrKSA9PiB7CiAgICByZXR1cm4gc2hhcGVba10uX3pvZC5vcHRpbiA9PT0gIm9wdGlvbmFsIiAmJiBzaGFwZVtrXS5fem9kLm9wdG91dCA9PT0gIm9wdGlvbmFsIjsKICB9KTsKfQp2YXIgTlVNQkVSX0ZPUk1BVF9SQU5HRVMgPSB7CiAgc2FmZWludDogW051bWJlci5NSU5fU0FGRV9JTlRFR0VSLCBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUl0sCiAgaW50MzI6IFstMjE0NzQ4MzY0OCwgMjE0NzQ4MzY0N10sCiAgdWludDMyOiBbMCwgNDI5NDk2NzI5NV0sCiAgZmxvYXQzMjogWy0zNDAyODIzNDY2Mzg1Mjg4NmUyMiwgMzQwMjgyMzQ2NjM4NTI4ODZlMjJdLAogIGZsb2F0NjQ6IFstTnVtYmVyLk1BWF9WQUxVRSwgTnVtYmVyLk1BWF9WQUxVRV0KfTsKdmFyIEJJR0lOVF9GT1JNQVRfUkFOR0VTID0gewogIGludDY0OiBbLyogQF9fUFVSRV9fICovIEJpZ0ludCgiLTkyMjMzNzIwMzY4NTQ3NzU4MDgiKSwgLyogQF9fUFVSRV9fICovIEJpZ0ludCgiOTIyMzM3MjAzNjg1NDc3NTgwNyIpXSwKICB1aW50NjQ6IFsvKiBAX19QVVJFX18gKi8gQmlnSW50KDApLCAvKiBAX19QVVJFX18gKi8gQmlnSW50KCIxODQ0Njc0NDA3MzcwOTU1MTYxNSIpXQp9OwpmdW5jdGlvbiBwaWNrKHNjaGVtYSwgbWFzaykgewogIGNvbnN0IGN1cnJEZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgY2hlY2tzID0gY3VyckRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIHRocm93IG5ldyBFcnJvcigiLnBpY2soKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzIik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgbmV3U2hhcGUgPSB7fTsKICAgICAgZm9yIChjb25zdCBrZXkgaW4gbWFzaykgewogICAgICAgIGlmICghKGtleSBpbiBjdXJyRGVmLnNoYXBlKSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQga2V5OiAiJHtrZXl9ImApOwogICAgICAgIH0KICAgICAgICBpZiAoIW1hc2tba2V5XSkKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIG5ld1NoYXBlW2tleV0gPSBjdXJyRGVmLnNoYXBlW2tleV07CiAgICAgIH0KICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBuZXdTaGFwZSk7CiAgICAgIHJldHVybiBuZXdTaGFwZTsKICAgIH0sCiAgICBjaGVja3M6IFtdCiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBvbWl0KHNjaGVtYSwgbWFzaykgewogIGNvbnN0IGN1cnJEZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgY2hlY2tzID0gY3VyckRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIHRocm93IG5ldyBFcnJvcigiLm9taXQoKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzIik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgbmV3U2hhcGUgPSB7IC4uLnNjaGVtYS5fem9kLmRlZi5zaGFwZSB9OwogICAgICBmb3IgKGNvbnN0IGtleSBpbiBtYXNrKSB7CiAgICAgICAgaWYgKCEoa2V5IGluIGN1cnJEZWYuc2hhcGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBrZXk6ICIke2tleX0iYCk7CiAgICAgICAgfQogICAgICAgIGlmICghbWFza1trZXldKQogICAgICAgICAgY29udGludWU7CiAgICAgICAgZGVsZXRlIG5ld1NoYXBlW2tleV07CiAgICAgIH0KICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBuZXdTaGFwZSk7CiAgICAgIHJldHVybiBuZXdTaGFwZTsKICAgIH0sCiAgICBjaGVja3M6IFtdCiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBleHRlbmQoc2NoZW1hLCBzaGFwZSkgewogIGlmICghaXNQbGFpbk9iamVjdChzaGFwZSkpIHsKICAgIHRocm93IG5ldyBFcnJvcigiSW52YWxpZCBpbnB1dCB0byBleHRlbmQ6IGV4cGVjdGVkIGEgcGxhaW4gb2JqZWN0Iik7CiAgfQogIGNvbnN0IGNoZWNrcyA9IHNjaGVtYS5fem9kLmRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIGNvbnN0IGV4aXN0aW5nU2hhcGUgPSBzY2hlbWEuX3pvZC5kZWYuc2hhcGU7CiAgICBmb3IgKGNvbnN0IGtleSBpbiBzaGFwZSkgewogICAgICBpZiAoT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihleGlzdGluZ1NoYXBlLCBrZXkpICE9PSB2b2lkIDApIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBvdmVyd3JpdGUga2V5cyBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzLiBVc2UgYC5zYWZlRXh0ZW5kKClgIGluc3RlYWQuIik7CiAgICAgIH0KICAgIH0KICB9CiAgY29uc3QgZGVmID0gbWVyZ2VEZWZzKHNjaGVtYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBfc2hhcGUgPSB7IC4uLnNjaGVtYS5fem9kLmRlZi5zaGFwZSwgLi4uc2hhcGUgfTsKICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBfc2hhcGUpOwogICAgICByZXR1cm4gX3NoYXBlOwogICAgfQogIH0pOwogIHJldHVybiBjbG9uZShzY2hlbWEsIGRlZik7Cn0KZnVuY3Rpb24gc2FmZUV4dGVuZChzY2hlbWEsIHNoYXBlKSB7CiAgaWYgKCFpc1BsYWluT2JqZWN0KHNoYXBlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIGlucHV0IHRvIHNhZmVFeHRlbmQ6IGV4cGVjdGVkIGEgcGxhaW4gb2JqZWN0Iik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgX3NoYXBlID0geyAuLi5zY2hlbWEuX3pvZC5kZWYuc2hhcGUsIC4uLnNoYXBlIH07CiAgICAgIGFzc2lnblByb3AodGhpcywgInNoYXBlIiwgX3NoYXBlKTsKICAgICAgcmV0dXJuIF9zaGFwZTsKICAgIH0KICB9KTsKICByZXR1cm4gY2xvbmUoc2NoZW1hLCBkZWYpOwp9CmZ1bmN0aW9uIG1lcmdlKGEsIGIpIHsKICBpZiAoYS5fem9kLmRlZi5jaGVja3M/Lmxlbmd0aCkgewogICAgdGhyb3cgbmV3IEVycm9yKCIubWVyZ2UoKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzLiBVc2UgLnNhZmVFeHRlbmQoKSBpbnN0ZWFkLiIpOwogIH0KICBjb25zdCBkZWYgPSBtZXJnZURlZnMoYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBfc2hhcGUgPSB7IC4uLmEuX3pvZC5kZWYuc2hhcGUsIC4uLmIuX3pvZC5kZWYuc2hhcGUgfTsKICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBfc2hhcGUpOwogICAgICByZXR1cm4gX3NoYXBlOwogICAgfSwKICAgIGdldCBjYXRjaGFsbCgpIHsKICAgICAgcmV0dXJuIGIuX3pvZC5kZWYuY2F0Y2hhbGw7CiAgICB9LAogICAgY2hlY2tzOiBiLl96b2QuZGVmLmNoZWNrcyA/PyBbXQogIH0pOwogIHJldHVybiBjbG9uZShhLCBkZWYpOwp9CmZ1bmN0aW9uIHBhcnRpYWwoQ2xhc3MyLCBzY2hlbWEsIG1hc2spIHsKICBjb25zdCBjdXJyRGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGNoZWNrcyA9IGN1cnJEZWYuY2hlY2tzOwogIGNvbnN0IGhhc0NoZWNrcyA9IGNoZWNrcyAmJiBjaGVja3MubGVuZ3RoID4gMDsKICBpZiAoaGFzQ2hlY2tzKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIi5wYXJ0aWFsKCkgY2Fubm90IGJlIHVzZWQgb24gb2JqZWN0IHNjaGVtYXMgY29udGFpbmluZyByZWZpbmVtZW50cyIpOwogIH0KICBjb25zdCBkZWYgPSBtZXJnZURlZnMoc2NoZW1hLl96b2QuZGVmLCB7CiAgICBnZXQgc2hhcGUoKSB7CiAgICAgIGNvbnN0IG9sZFNoYXBlID0gc2NoZW1hLl96b2QuZGVmLnNoYXBlOwogICAgICBjb25zdCBzaGFwZSA9IHsgLi4ub2xkU2hhcGUgfTsKICAgICAgaWYgKG1hc2spIHsKICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBtYXNrKSB7CiAgICAgICAgICBpZiAoIShrZXkgaW4gb2xkU2hhcGUpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5yZWNvZ25pemVkIGtleTogIiR7a2V5fSJgKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghbWFza1trZXldKQogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIHNoYXBlW2tleV0gPSBDbGFzczIgPyBuZXcgQ2xhc3MyKHsKICAgICAgICAgICAgdHlwZTogIm9wdGlvbmFsIiwKICAgICAgICAgICAgaW5uZXJUeXBlOiBvbGRTaGFwZVtrZXldCiAgICAgICAgICB9KSA6IG9sZFNoYXBlW2tleV07CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIG9sZFNoYXBlKSB7CiAgICAgICAgICBzaGFwZVtrZXldID0gQ2xhc3MyID8gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJvcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSkgOiBvbGRTaGFwZVtrZXldOwogICAgICAgIH0KICAgICAgfQogICAgICBhc3NpZ25Qcm9wKHRoaXMsICJzaGFwZSIsIHNoYXBlKTsKICAgICAgcmV0dXJuIHNoYXBlOwogICAgfSwKICAgIGNoZWNrczogW10KICB9KTsKICByZXR1cm4gY2xvbmUoc2NoZW1hLCBkZWYpOwp9CmZ1bmN0aW9uIHJlcXVpcmVkKENsYXNzMiwgc2NoZW1hLCBtYXNrKSB7CiAgY29uc3QgZGVmID0gbWVyZ2VEZWZzKHNjaGVtYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBvbGRTaGFwZSA9IHNjaGVtYS5fem9kLmRlZi5zaGFwZTsKICAgICAgY29uc3Qgc2hhcGUgPSB7IC4uLm9sZFNoYXBlIH07CiAgICAgIGlmIChtYXNrKSB7CiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gbWFzaykgewogICAgICAgICAgaWYgKCEoa2V5IGluIHNoYXBlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBrZXk6ICIke2tleX0iYCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIW1hc2tba2V5XSkKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBzaGFwZVtrZXldID0gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJub25vcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIG9sZFNoYXBlKSB7CiAgICAgICAgICBzaGFwZVtrZXldID0gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJub25vcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGFzc2lnblByb3AodGhpcywgInNoYXBlIiwgc2hhcGUpOwogICAgICByZXR1cm4gc2hhcGU7CiAgICB9CiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBhYm9ydGVkKHgsIHN0YXJ0SW5kZXggPSAwKSB7CiAgaWYgKHguYWJvcnRlZCA9PT0gdHJ1ZSkKICAgIHJldHVybiB0cnVlOwogIGZvciAobGV0IGkgPSBzdGFydEluZGV4OyBpIDwgeC5pc3N1ZXMubGVuZ3RoOyBpKyspIHsKICAgIGlmICh4Lmlzc3Vlc1tpXT8uY29udGludWUgIT09IHRydWUpIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgfQogIHJldHVybiBmYWxzZTsKfQpmdW5jdGlvbiBleHBsaWNpdGx5QWJvcnRlZCh4LCBzdGFydEluZGV4ID0gMCkgewogIGlmICh4LmFib3J0ZWQgPT09IHRydWUpCiAgICByZXR1cm4gdHJ1ZTsKICBmb3IgKGxldCBpID0gc3RhcnRJbmRleDsgaSA8IHguaXNzdWVzLmxlbmd0aDsgaSsrKSB7CiAgICBpZiAoeC5pc3N1ZXNbaV0/LmNvbnRpbnVlID09PSBmYWxzZSkgewogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CiAgcmV0dXJuIGZhbHNlOwp9CmZ1bmN0aW9uIHByZWZpeElzc3VlcyhwYXRoMywgaXNzdWVzKSB7CiAgcmV0dXJuIGlzc3Vlcy5tYXAoKGlzcykgPT4gewogICAgdmFyIF9hMzsKICAgIChfYTMgPSBpc3MpLnBhdGggPz8gKF9hMy5wYXRoID0gW10pOwogICAgaXNzLnBhdGgudW5zaGlmdChwYXRoMyk7CiAgICByZXR1cm4gaXNzOwogIH0pOwp9CmZ1bmN0aW9uIHVud3JhcE1lc3NhZ2UobWVzc2FnZSkgewogIHJldHVybiB0eXBlb2YgbWVzc2FnZSA9PT0gInN0cmluZyIgPyBtZXNzYWdlIDogbWVzc2FnZT8ubWVzc2FnZTsKfQpmdW5jdGlvbiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcyKSB7CiAgY29uc3QgbWVzc2FnZSA9IGlzcy5tZXNzYWdlID8gaXNzLm1lc3NhZ2UgOiB1bndyYXBNZXNzYWdlKGlzcy5pbnN0Py5fem9kLmRlZj8uZXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGN0eD8uZXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGNvbmZpZzIuY3VzdG9tRXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGNvbmZpZzIubG9jYWxlRXJyb3I/Lihpc3MpKSA/PyAiSW52YWxpZCBpbnB1dCI7CiAgY29uc3QgeyBpbnN0OiBfaW5zdCwgY29udGludWU6IF9jb250aW51ZSwgaW5wdXQ6IF9pbnB1dCwgLi4ucmVzdCB9ID0gaXNzOwogIHJlc3QucGF0aCA/PyAocmVzdC5wYXRoID0gW10pOwogIHJlc3QubWVzc2FnZSA9IG1lc3NhZ2U7CiAgaWYgKGN0eD8ucmVwb3J0SW5wdXQpIHsKICAgIHJlc3QuaW5wdXQgPSBfaW5wdXQ7CiAgfQogIHJldHVybiByZXN0Owp9CmZ1bmN0aW9uIGdldFNpemFibGVPcmlnaW4oaW5wdXQpIHsKICBpZiAoaW5wdXQgaW5zdGFuY2VvZiBTZXQpCiAgICByZXR1cm4gInNldCI7CiAgaWYgKGlucHV0IGluc3RhbmNlb2YgTWFwKQogICAgcmV0dXJuICJtYXAiOwogIGlmIChpbnB1dCBpbnN0YW5jZW9mIEZpbGUpCiAgICByZXR1cm4gImZpbGUiOwogIHJldHVybiAidW5rbm93biI7Cn0KZnVuY3Rpb24gZ2V0TGVuZ3RoYWJsZU9yaWdpbihpbnB1dCkgewogIGlmIChBcnJheS5pc0FycmF5KGlucHV0KSkKICAgIHJldHVybiAiYXJyYXkiOwogIGlmICh0eXBlb2YgaW5wdXQgPT09ICJzdHJpbmciKQogICAgcmV0dXJuICJzdHJpbmciOwogIHJldHVybiAidW5rbm93biI7Cn0KZnVuY3Rpb24gcGFyc2VkVHlwZShkYXRhKSB7CiAgY29uc3QgdCA9IHR5cGVvZiBkYXRhOwogIHN3aXRjaCAodCkgewogICAgY2FzZSAibnVtYmVyIjogewogICAgICByZXR1cm4gTnVtYmVyLmlzTmFOKGRhdGEpID8gIm5hbiIgOiAibnVtYmVyIjsKICAgIH0KICAgIGNhc2UgIm9iamVjdCI6IHsKICAgICAgaWYgKGRhdGEgPT09IG51bGwpIHsKICAgICAgICByZXR1cm4gIm51bGwiOwogICAgICB9CiAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7CiAgICAgICAgcmV0dXJuICJhcnJheSI7CiAgICAgIH0KICAgICAgY29uc3Qgb2JqID0gZGF0YTsKICAgICAgaWYgKG9iaiAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqKSAhPT0gT2JqZWN0LnByb3RvdHlwZSAmJiAiY29uc3RydWN0b3IiIGluIG9iaiAmJiBvYmouY29uc3RydWN0b3IpIHsKICAgICAgICByZXR1cm4gb2JqLmNvbnN0cnVjdG9yLm5hbWU7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIHQ7Cn0KZnVuY3Rpb24gaXNzdWUoLi4uYXJncykgewogIGNvbnN0IFtpc3MsIGlucHV0LCBpbnN0XSA9IGFyZ3M7CiAgaWYgKHR5cGVvZiBpc3MgPT09ICJzdHJpbmciKSB7CiAgICByZXR1cm4gewogICAgICBtZXNzYWdlOiBpc3MsCiAgICAgIGNvZGU6ICJjdXN0b20iLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfTsKICB9CiAgcmV0dXJuIHsgLi4uaXNzIH07Cn0KZnVuY3Rpb24gY2xlYW5FbnVtKG9iaikgewogIHJldHVybiBPYmplY3QuZW50cmllcyhvYmopLmZpbHRlcigoW2ssIF9dKSA9PiB7CiAgICByZXR1cm4gTnVtYmVyLmlzTmFOKE51bWJlci5wYXJzZUludChrLCAxMCkpOwogIH0pLm1hcCgoZWwpID0+IGVsWzFdKTsKfQpmdW5jdGlvbiBiYXNlNjRUb1VpbnQ4QXJyYXkoYmFzZTY0MikgewogIGNvbnN0IGJpbmFyeVN0cmluZyA9IGF0b2IoYmFzZTY0Mik7CiAgY29uc3QgYnl0ZXMgPSBuZXcgVWludDhBcnJheShiaW5hcnlTdHJpbmcubGVuZ3RoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IGJpbmFyeVN0cmluZy5sZW5ndGg7IGkrKykgewogICAgYnl0ZXNbaV0gPSBiaW5hcnlTdHJpbmcuY2hhckNvZGVBdChpKTsKICB9CiAgcmV0dXJuIGJ5dGVzOwp9CmZ1bmN0aW9uIHVpbnQ4QXJyYXlUb0Jhc2U2NChieXRlcykgewogIGxldCBiaW5hcnlTdHJpbmcgPSAiIjsKICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7CiAgICBiaW5hcnlTdHJpbmcgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSk7CiAgfQogIHJldHVybiBidG9hKGJpbmFyeVN0cmluZyk7Cn0KZnVuY3Rpb24gYmFzZTY0dXJsVG9VaW50OEFycmF5KGJhc2U2NHVybDIpIHsKICBjb25zdCBiYXNlNjQyID0gYmFzZTY0dXJsMi5yZXBsYWNlKC8tL2csICIrIikucmVwbGFjZSgvXy9nLCAiLyIpOwogIGNvbnN0IHBhZGRpbmcgPSAiPSIucmVwZWF0KCg0IC0gYmFzZTY0Mi5sZW5ndGggJSA0KSAlIDQpOwogIHJldHVybiBiYXNlNjRUb1VpbnQ4QXJyYXkoYmFzZTY0MiArIHBhZGRpbmcpOwp9CmZ1bmN0aW9uIHVpbnQ4QXJyYXlUb0Jhc2U2NHVybChieXRlcykgewogIHJldHVybiB1aW50OEFycmF5VG9CYXNlNjQoYnl0ZXMpLnJlcGxhY2UoL1wrL2csICItIikucmVwbGFjZSgvXC8vZywgIl8iKS5yZXBsYWNlKC89L2csICIiKTsKfQpmdW5jdGlvbiBoZXhUb1VpbnQ4QXJyYXkoaGV4KSB7CiAgY29uc3QgY2xlYW5IZXggPSBoZXgucmVwbGFjZSgvXjB4LywgIiIpOwogIGlmIChjbGVhbkhleC5sZW5ndGggJSAyICE9PSAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgaGV4IHN0cmluZyBsZW5ndGgiKTsKICB9CiAgY29uc3QgYnl0ZXMgPSBuZXcgVWludDhBcnJheShjbGVhbkhleC5sZW5ndGggLyAyKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IGNsZWFuSGV4Lmxlbmd0aDsgaSArPSAyKSB7CiAgICBieXRlc1tpIC8gMl0gPSBOdW1iZXIucGFyc2VJbnQoY2xlYW5IZXguc2xpY2UoaSwgaSArIDIpLCAxNik7CiAgfQogIHJldHVybiBieXRlczsKfQpmdW5jdGlvbiB1aW50OEFycmF5VG9IZXgoYnl0ZXMpIHsKICByZXR1cm4gQXJyYXkuZnJvbShieXRlcykubWFwKChiKSA9PiBiLnRvU3RyaW5nKDE2KS5wYWRTdGFydCgyLCAiMCIpKS5qb2luKCIiKTsKfQp2YXIgQ2xhc3MgPSBjbGFzcyB7CiAgY29uc3RydWN0b3IoLi4uX2FyZ3MpIHsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvZXJyb3JzLmpzCnZhciBpbml0aWFsaXplciA9IChpbnN0LCBkZWYpID0+IHsKICBpbnN0Lm5hbWUgPSAiJFpvZEVycm9yIjsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgIl96b2QiLCB7CiAgICB2YWx1ZTogaW5zdC5fem9kLAogICAgZW51bWVyYWJsZTogZmFsc2UKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgImlzc3VlcyIsIHsKICAgIHZhbHVlOiBkZWYsCiAgICBlbnVtZXJhYmxlOiBmYWxzZQogIH0pOwogIGluc3QubWVzc2FnZSA9IEpTT04uc3RyaW5naWZ5KGRlZiwganNvblN0cmluZ2lmeVJlcGxhY2VyLCAyKTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgInRvU3RyaW5nIiwgewogICAgdmFsdWU6ICgpID0+IGluc3QubWVzc2FnZSwKICAgIGVudW1lcmFibGU6IGZhbHNlCiAgfSk7Cn07CnZhciAkWm9kRXJyb3IgPSAkY29uc3RydWN0b3IoIiRab2RFcnJvciIsIGluaXRpYWxpemVyKTsKdmFyICRab2RSZWFsRXJyb3IgPSAkY29uc3RydWN0b3IoIiRab2RFcnJvciIsIGluaXRpYWxpemVyLCB7IFBhcmVudDogRXJyb3IgfSk7CmZ1bmN0aW9uIGZsYXR0ZW5FcnJvcihlcnJvciwgbWFwcGVyID0gKGlzc3VlMikgPT4gaXNzdWUyLm1lc3NhZ2UpIHsKICBjb25zdCBmaWVsZEVycm9ycyA9IHt9OwogIGNvbnN0IGZvcm1FcnJvcnMgPSBbXTsKICBmb3IgKGNvbnN0IHN1YiBvZiBlcnJvci5pc3N1ZXMpIHsKICAgIGlmIChzdWIucGF0aC5sZW5ndGggPiAwKSB7CiAgICAgIGZpZWxkRXJyb3JzW3N1Yi5wYXRoWzBdXSA9IGZpZWxkRXJyb3JzW3N1Yi5wYXRoWzBdXSB8fCBbXTsKICAgICAgZmllbGRFcnJvcnNbc3ViLnBhdGhbMF1dLnB1c2gobWFwcGVyKHN1YikpOwogICAgfSBlbHNlIHsKICAgICAgZm9ybUVycm9ycy5wdXNoKG1hcHBlcihzdWIpKTsKICAgIH0KICB9CiAgcmV0dXJuIHsgZm9ybUVycm9ycywgZmllbGRFcnJvcnMgfTsKfQpmdW5jdGlvbiBmb3JtYXRFcnJvcihlcnJvciwgbWFwcGVyID0gKGlzc3VlMikgPT4gaXNzdWUyLm1lc3NhZ2UpIHsKICBjb25zdCBmaWVsZEVycm9ycyA9IHsgX2Vycm9yczogW10gfTsKICBjb25zdCBwcm9jZXNzRXJyb3IgPSAoZXJyb3IyLCBwYXRoMyA9IFtdKSA9PiB7CiAgICBmb3IgKGNvbnN0IGlzc3VlMiBvZiBlcnJvcjIuaXNzdWVzKSB7CiAgICAgIGlmIChpc3N1ZTIuY29kZSA9PT0gImludmFsaWRfdW5pb24iICYmIGlzc3VlMi5lcnJvcnMubGVuZ3RoKSB7CiAgICAgICAgaXNzdWUyLmVycm9ycy5tYXAoKGlzc3VlcykgPT4gcHJvY2Vzc0Vycm9yKHsgaXNzdWVzIH0sIFsuLi5wYXRoMywgLi4uaXNzdWUyLnBhdGhdKSk7CiAgICAgIH0gZWxzZSBpZiAoaXNzdWUyLmNvZGUgPT09ICJpbnZhbGlkX2tleSIpIHsKICAgICAgICBwcm9jZXNzRXJyb3IoeyBpc3N1ZXM6IGlzc3VlMi5pc3N1ZXMgfSwgWy4uLnBhdGgzLCAuLi5pc3N1ZTIucGF0aF0pOwogICAgICB9IGVsc2UgaWYgKGlzc3VlMi5jb2RlID09PSAiaW52YWxpZF9lbGVtZW50IikgewogICAgICAgIHByb2Nlc3NFcnJvcih7IGlzc3VlczogaXNzdWUyLmlzc3VlcyB9LCBbLi4ucGF0aDMsIC4uLmlzc3VlMi5wYXRoXSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgZnVsbHBhdGggPSBbLi4ucGF0aDMsIC4uLmlzc3VlMi5wYXRoXTsKICAgICAgICBpZiAoZnVsbHBhdGgubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICBmaWVsZEVycm9ycy5fZXJyb3JzLnB1c2gobWFwcGVyKGlzc3VlMikpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsZXQgY3VyciA9IGZpZWxkRXJyb3JzOwogICAgICAgICAgbGV0IGkgPSAwOwogICAgICAgICAgd2hpbGUgKGkgPCBmdWxscGF0aC5sZW5ndGgpIHsKICAgICAgICAgICAgY29uc3QgZWwgPSBmdWxscGF0aFtpXTsKICAgICAgICAgICAgY29uc3QgdGVybWluYWwgPSBpID09PSBmdWxscGF0aC5sZW5ndGggLSAxOwogICAgICAgICAgICBpZiAoIXRlcm1pbmFsKSB7CiAgICAgICAgICAgICAgY3VycltlbF0gPSBjdXJyW2VsXSB8fCB7IF9lcnJvcnM6IFtdIH07CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgY3VycltlbF0gPSBjdXJyW2VsXSB8fCB7IF9lcnJvcnM6IFtdIH07CiAgICAgICAgICAgICAgY3VycltlbF0uX2Vycm9ycy5wdXNoKG1hcHBlcihpc3N1ZTIpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjdXJyID0gY3VycltlbF07CiAgICAgICAgICAgIGkrKzsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9OwogIHByb2Nlc3NFcnJvcihlcnJvcik7CiAgcmV0dXJuIGZpZWxkRXJyb3JzOwp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvcGFyc2UuanMKdmFyIF9wYXJzZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCwgX3BhcmFtcykgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGFzeW5jOiBmYWxzZSB9IDogeyBhc3luYzogZmFsc2UgfTsKICBjb25zdCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICB9CiAgaWYgKHJlc3VsdC5pc3N1ZXMubGVuZ3RoKSB7CiAgICBjb25zdCBlID0gbmV3IChfcGFyYW1zPy5FcnIgPz8gX0VycikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSk7CiAgICBjYXB0dXJlU3RhY2tUcmFjZShlLCBfcGFyYW1zPy5jYWxsZWUpOwogICAgdGhyb3cgZTsKICB9CiAgcmV0dXJuIHJlc3VsdC52YWx1ZTsKfTsKdmFyIF9wYXJzZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4LCBwYXJhbXMpID0+IHsKICBjb25zdCBjdHggPSBfY3R4ID8geyAuLi5fY3R4LCBhc3luYzogdHJ1ZSB9IDogeyBhc3luYzogdHJ1ZSB9OwogIGxldCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKQogICAgcmVzdWx0ID0gYXdhaXQgcmVzdWx0OwogIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgY29uc3QgZSA9IG5ldyAocGFyYW1zPy5FcnIgPz8gX0VycikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSk7CiAgICBjYXB0dXJlU3RhY2tUcmFjZShlLCBwYXJhbXM/LmNhbGxlZSk7CiAgICB0aHJvdyBlOwogIH0KICByZXR1cm4gcmVzdWx0LnZhbHVlOwp9Owp2YXIgX3NhZmVQYXJzZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGFzeW5jOiBmYWxzZSB9IDogeyBhc3luYzogZmFsc2UgfTsKICBjb25zdCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICB9CiAgcmV0dXJuIHJlc3VsdC5pc3N1ZXMubGVuZ3RoID8gewogICAgc3VjY2VzczogZmFsc2UsCiAgICBlcnJvcjogbmV3IChfRXJyID8/ICRab2RFcnJvcikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSkKICB9IDogeyBzdWNjZXNzOiB0cnVlLCBkYXRhOiByZXN1bHQudmFsdWUgfTsKfTsKdmFyIHNhZmVQYXJzZSA9IC8qIEBfX1BVUkVfXyAqLyBfc2FmZVBhcnNlKCRab2RSZWFsRXJyb3IpOwp2YXIgX3NhZmVQYXJzZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgY29uc3QgY3R4ID0gX2N0eCA/IHsgLi4uX2N0eCwgYXN5bmM6IHRydWUgfSA6IHsgYXN5bmM6IHRydWUgfTsKICBsZXQgcmVzdWx0ID0gc2NoZW1hLl96b2QucnVuKHsgdmFsdWUsIGlzc3VlczogW10gfSwgY3R4KTsKICBpZiAocmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkKICAgIHJlc3VsdCA9IGF3YWl0IHJlc3VsdDsKICByZXR1cm4gcmVzdWx0Lmlzc3Vlcy5sZW5ndGggPyB7CiAgICBzdWNjZXNzOiBmYWxzZSwKICAgIGVycm9yOiBuZXcgX0VycihyZXN1bHQuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpKQogIH0gOiB7IHN1Y2Nlc3M6IHRydWUsIGRhdGE6IHJlc3VsdC52YWx1ZSB9Owp9Owp2YXIgc2FmZVBhcnNlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVQYXJzZUFzeW5jKCRab2RSZWFsRXJyb3IpOwp2YXIgX2VuY29kZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3BhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfZGVjb2RlID0gKF9FcnIpID0+IChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgcmV0dXJuIF9wYXJzZShfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKdmFyIF9lbmNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3BhcnNlQXN5bmMoX0Vycikoc2NoZW1hLCB2YWx1ZSwgY3R4KTsKfTsKdmFyIF9kZWNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIHJldHVybiBfcGFyc2VBc3luYyhfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKdmFyIF9zYWZlRW5jb2RlID0gKF9FcnIpID0+IChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgY29uc3QgY3R4ID0gX2N0eCA/IHsgLi4uX2N0eCwgZGlyZWN0aW9uOiAiYmFja3dhcmQiIH0gOiB7IGRpcmVjdGlvbjogImJhY2t3YXJkIiB9OwogIHJldHVybiBfc2FmZVBhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfc2FmZURlY29kZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIHJldHVybiBfc2FmZVBhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIF9jdHgpOwp9Owp2YXIgX3NhZmVFbmNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3NhZmVQYXJzZUFzeW5jKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfc2FmZURlY29kZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgcmV0dXJuIF9zYWZlUGFyc2VBc3luYyhfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9yZWdleGVzLmpzCnZhciBjdWlkID0gL15bY0NdWzAtOWEtel17Nix9JC87CnZhciBjdWlkMiA9IC9eWzAtOWEtel0rJC87CnZhciB1bGlkID0gL15bMC05QS1ISktNTlAtVFYtWmEtaGprbW5wLXR2LXpdezI2fSQvOwp2YXIgeGlkID0gL15bMC05YS12QS1WXXsyMH0kLzsKdmFyIGtzdWlkID0gL15bQS1aYS16MC05XXsyN30kLzsKdmFyIG5hbm9pZCA9IC9eW2EtekEtWjAtOV8tXXsyMX0kLzsKdmFyIGR1cmF0aW9uID0gL15QKD86KFxkK1cpfCg/IS4qVykoPz1cZHxUXGQpKFxkK1kpPyhcZCtNKT8oXGQrRCk/KFQoPz1cZCkoXGQrSCk/KFxkK00pPyhcZCsoWy4sXVxkKyk/Uyk/KT8pJC87CnZhciBndWlkID0gL14oWzAtOWEtZkEtRl17OH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17MTJ9KSQvOwp2YXIgdXVpZCA9ICh2ZXJzaW9uMikgPT4gewogIGlmICghdmVyc2lvbjIpCiAgICByZXR1cm4gL14oWzAtOWEtZkEtRl17OH0tWzAtOWEtZkEtRl17NH0tWzEtOF1bMC05YS1mQS1GXXszfS1bODlhYkFCXVswLTlhLWZBLUZdezN9LVswLTlhLWZBLUZdezEyfXwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8ZmZmZmZmZmYtZmZmZi1mZmZmLWZmZmYtZmZmZmZmZmZmZmZmKSQvOwogIHJldHVybiBuZXcgUmVnRXhwKGBeKFswLTlhLWZBLUZdezh9LVswLTlhLWZBLUZdezR9LSR7dmVyc2lvbjJ9WzAtOWEtZkEtRl17M30tWzg5YWJBQl1bMC05YS1mQS1GXXszfS1bMC05YS1mQS1GXXsxMn0pJGApOwp9Owp2YXIgZW1haWwgPSAvXig/IVwuKSg/IS4qXC5cLikoW0EtWmEtejAtOV8nK1wtXC5dKilbQS1aYS16MC05XystXUAoW0EtWmEtejAtOV1bQS1aYS16MC05XC1dKlwuKStbQS1aYS16XXsyLH0kLzsKdmFyIF9lbW9qaSA9IGBeKFxccHtFeHRlbmRlZF9QaWN0b2dyYXBoaWN9fFxccHtFbW9qaV9Db21wb25lbnR9KSskYDsKZnVuY3Rpb24gZW1vamkoKSB7CiAgcmV0dXJuIG5ldyBSZWdFeHAoX2Vtb2ppLCAidSIpOwp9CnZhciBpcHY0ID0gL14oPzooPzoyNVswLTVdfDJbMC00XVswLTldfDFbMC05XVswLTldfFsxLTldWzAtOV18WzAtOV0pXC4pezN9KD86MjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV1bMC05XXxbMS05XVswLTldfFswLTldKSQvOwp2YXIgaXB2NiA9IC9eKChbMC05YS1mQS1GXXsxLDR9Oil7N31bMC05YS1mQS1GXXsxLDR9fChbMC05YS1mQS1GXXsxLDR9Oil7MSw3fTp8KFswLTlhLWZBLUZdezEsNH06KXsxLDZ9OlswLTlhLWZBLUZdezEsNH18KFswLTlhLWZBLUZdezEsNH06KXsxLDV9KDpbMC05YS1mQS1GXXsxLDR9KXsxLDJ9fChbMC05YS1mQS1GXXsxLDR9Oil7MSw0fSg6WzAtOWEtZkEtRl17MSw0fSl7MSwzfXwoWzAtOWEtZkEtRl17MSw0fTopezEsM30oOlswLTlhLWZBLUZdezEsNH0pezEsNH18KFswLTlhLWZBLUZdezEsNH06KXsxLDJ9KDpbMC05YS1mQS1GXXsxLDR9KXsxLDV9fFswLTlhLWZBLUZdezEsNH06KCg6WzAtOWEtZkEtRl17MSw0fSl7MSw2fSl8OigoOlswLTlhLWZBLUZdezEsNH0pezEsN318OikpJC87CnZhciBjaWRydjQgPSAvXigoMjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV1bMC05XXxbMS05XVswLTldfFswLTldKVwuKXszfSgyNVswLTVdfDJbMC00XVswLTldfDFbMC05XVswLTldfFsxLTldWzAtOV18WzAtOV0pXC8oWzAtOV18WzEtMl1bMC05XXwzWzAtMl0pJC87CnZhciBjaWRydjYgPSAvXigoWzAtOWEtZkEtRl17MSw0fTopezd9WzAtOWEtZkEtRl17MSw0fXw6OnwoWzAtOWEtZkEtRl17MSw0fSk/OjooWzAtOWEtZkEtRl17MSw0fTo/KXswLDZ9KVwvKDEyWzAtOF18MVswMV1bMC05XXxbMS05XT9bMC05XSkkLzsKdmFyIGJhc2U2NCA9IC9eJHxeKD86WzAtOWEtekEtWisvXXs0fSkqKD86KD86WzAtOWEtekEtWisvXXsyfT09KXwoPzpbMC05YS16QS1aKy9dezN9PSkpPyQvOwp2YXIgYmFzZTY0dXJsID0gL15bQS1aYS16MC05Xy1dKiQvOwp2YXIgaHR0cFByb3RvY29sID0gL15odHRwcz8kLzsKdmFyIGUxNjQgPSAvXlwrWzEtOV1cZHs2LDE0fSQvOwp2YXIgZGF0ZVNvdXJjZSA9IGAoPzooPzpcXGRcXGRbMjQ2OF1bMDQ4XXxcXGRcXGRbMTM1NzldWzI2XXxcXGRcXGQwWzQ4XXxbMDI0NjhdWzA0OF0wMHxbMTM1NzldWzI2XTAwKS0wMi0yOXxcXGR7NH0tKD86KD86MFsxMzU3OF18MVswMl0pLSg/OjBbMS05XXxbMTJdXFxkfDNbMDFdKXwoPzowWzQ2OV18MTEpLSg/OjBbMS05XXxbMTJdXFxkfDMwKXwoPzowMiktKD86MFsxLTldfDFcXGR8MlswLThdKSkpYDsKdmFyIGRhdGUgPSAvKiBAX19QVVJFX18gKi8gbmV3IFJlZ0V4cChgXiR7ZGF0ZVNvdXJjZX0kYCk7CmZ1bmN0aW9uIHRpbWVTb3VyY2UoYXJncykgewogIGNvbnN0IGhobW0gPSBgKD86WzAxXVxcZHwyWzAtM10pOlswLTVdXFxkYDsKICBjb25zdCByZWdleCA9IHR5cGVvZiBhcmdzLnByZWNpc2lvbiA9PT0gIm51bWJlciIgPyBhcmdzLnByZWNpc2lvbiA9PT0gLTEgPyBgJHtoaG1tfWAgOiBhcmdzLnByZWNpc2lvbiA9PT0gMCA/IGAke2hobW19OlswLTVdXFxkYCA6IGAke2hobW19OlswLTVdXFxkXFwuXFxkeyR7YXJncy5wcmVjaXNpb259fWAgOiBgJHtoaG1tfSg/OjpbMC01XVxcZCg/OlxcLlxcZCspPyk/YDsKICByZXR1cm4gcmVnZXg7Cn0KZnVuY3Rpb24gdGltZShhcmdzKSB7CiAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke3RpbWVTb3VyY2UoYXJncyl9JGApOwp9CmZ1bmN0aW9uIGRhdGV0aW1lKGFyZ3MpIHsKICBjb25zdCB0aW1lMyA9IHRpbWVTb3VyY2UoeyBwcmVjaXNpb246IGFyZ3MucHJlY2lzaW9uIH0pOwogIGNvbnN0IG9wdHMgPSBbIloiXTsKICBpZiAoYXJncy5sb2NhbCkKICAgIG9wdHMucHVzaCgiIik7CiAgaWYgKGFyZ3Mub2Zmc2V0KQogICAgb3B0cy5wdXNoKGAoWystXSg/OlswMV1cXGR8MlswLTNdKTpbMC01XVxcZClgKTsKICBjb25zdCB0aW1lUmVnZXggPSBgJHt0aW1lM30oPzoke29wdHMuam9pbigifCIpfSlgOwogIHJldHVybiBuZXcgUmVnRXhwKGBeJHtkYXRlU291cmNlfVQoPzoke3RpbWVSZWdleH0pJGApOwp9CnZhciBzdHJpbmcgPSAocGFyYW1zKSA9PiB7CiAgY29uc3QgcmVnZXggPSBwYXJhbXMgPyBgW1xcc1xcU117JHtwYXJhbXM/Lm1pbmltdW0gPz8gMH0sJHtwYXJhbXM/Lm1heGltdW0gPz8gIiJ9fWAgOiBgW1xcc1xcU10qYDsKICByZXR1cm4gbmV3IFJlZ0V4cChgXiR7cmVnZXh9JGApOwp9Owp2YXIgaW50ZWdlciA9IC9eLT9cZCskLzsKdmFyIG51bWJlciA9IC9eLT9cZCsoPzpcLlxkKyk/JC87CnZhciBsb3dlcmNhc2UgPSAvXlteQS1aXSokLzsKdmFyIHVwcGVyY2FzZSA9IC9eW15hLXpdKiQvOwoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL2NoZWNrcy5qcwp2YXIgJFpvZENoZWNrID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrIiwgKGluc3QsIGRlZikgPT4gewogIHZhciBfYTM7CiAgaW5zdC5fem9kID8/IChpbnN0Ll96b2QgPSB7fSk7CiAgaW5zdC5fem9kLmRlZiA9IGRlZjsKICAoX2EzID0gaW5zdC5fem9kKS5vbmF0dGFjaCA/PyAoX2EzLm9uYXR0YWNoID0gW10pOwp9KTsKdmFyIG51bWVyaWNPcmlnaW5NYXAgPSB7CiAgbnVtYmVyOiAibnVtYmVyIiwKICBiaWdpbnQ6ICJiaWdpbnQiLAogIG9iamVjdDogImRhdGUiCn07CnZhciAkWm9kQ2hlY2tMZXNzVGhhbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja0xlc3NUaGFuIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgY29uc3Qgb3JpZ2luID0gbnVtZXJpY09yaWdpbk1hcFt0eXBlb2YgZGVmLnZhbHVlXTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgY29uc3QgY3VyciA9IChkZWYuaW5jbHVzaXZlID8gYmFnLm1heGltdW0gOiBiYWcuZXhjbHVzaXZlTWF4aW11bSkgPz8gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgaWYgKGRlZi52YWx1ZSA8IGN1cnIpIHsKICAgICAgaWYgKGRlZi5pbmNsdXNpdmUpCiAgICAgICAgYmFnLm1heGltdW0gPSBkZWYudmFsdWU7CiAgICAgIGVsc2UKICAgICAgICBiYWcuZXhjbHVzaXZlTWF4aW11bSA9IGRlZi52YWx1ZTsKICAgIH0KICB9KTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgaWYgKGRlZi5pbmNsdXNpdmUgPyBwYXlsb2FkLnZhbHVlIDw9IGRlZi52YWx1ZSA6IHBheWxvYWQudmFsdWUgPCBkZWYudmFsdWUpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbiwKICAgICAgY29kZTogInRvb19iaWciLAogICAgICBtYXhpbXVtOiB0eXBlb2YgZGVmLnZhbHVlID09PSAib2JqZWN0IiA/IGRlZi52YWx1ZS5nZXRUaW1lKCkgOiBkZWYudmFsdWUsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBpbmNsdXNpdmU6IGRlZi5pbmNsdXNpdmUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja0dyZWF0ZXJUaGFuID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrR3JlYXRlclRoYW4iLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICBjb25zdCBvcmlnaW4gPSBudW1lcmljT3JpZ2luTWFwW3R5cGVvZiBkZWYudmFsdWVdOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgYmFnID0gaW5zdDIuX3pvZC5iYWc7CiAgICBjb25zdCBjdXJyID0gKGRlZi5pbmNsdXNpdmUgPyBiYWcubWluaW11bSA6IGJhZy5leGNsdXNpdmVNaW5pbXVtKSA/PyBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBpZiAoZGVmLnZhbHVlID4gY3VycikgewogICAgICBpZiAoZGVmLmluY2x1c2l2ZSkKICAgICAgICBiYWcubWluaW11bSA9IGRlZi52YWx1ZTsKICAgICAgZWxzZQogICAgICAgIGJhZy5leGNsdXNpdmVNaW5pbXVtID0gZGVmLnZhbHVlOwogICAgfQogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBpZiAoZGVmLmluY2x1c2l2ZSA/IHBheWxvYWQudmFsdWUgPj0gZGVmLnZhbHVlIDogcGF5bG9hZC52YWx1ZSA+IGRlZi52YWx1ZSkgewogICAgICByZXR1cm47CiAgICB9CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luLAogICAgICBjb2RlOiAidG9vX3NtYWxsIiwKICAgICAgbWluaW11bTogdHlwZW9mIGRlZi52YWx1ZSA9PT0gIm9iamVjdCIgPyBkZWYudmFsdWUuZ2V0VGltZSgpIDogZGVmLnZhbHVlLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5jbHVzaXZlOiBkZWYuaW5jbHVzaXZlLAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tNdWx0aXBsZU9mID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrTXVsdGlwbGVPZiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgdmFyIF9hMzsKICAgIChfYTMgPSBpbnN0Mi5fem9kLmJhZykubXVsdGlwbGVPZiA/PyAoX2EzLm11bHRpcGxlT2YgPSBkZWYudmFsdWUpOwogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBpZiAodHlwZW9mIHBheWxvYWQudmFsdWUgIT09IHR5cGVvZiBkZWYudmFsdWUpCiAgICAgIHRocm93IG5ldyBFcnJvcigiQ2Fubm90IG1peCBudW1iZXIgYW5kIGJpZ2ludCBpbiBtdWx0aXBsZV9vZiBjaGVjay4iKTsKICAgIGNvbnN0IGlzTXVsdGlwbGUgPSB0eXBlb2YgcGF5bG9hZC52YWx1ZSA9PT0gImJpZ2ludCIgPyBwYXlsb2FkLnZhbHVlICUgZGVmLnZhbHVlID09PSBCaWdJbnQoMCkgOiBmbG9hdFNhZmVSZW1haW5kZXIocGF5bG9hZC52YWx1ZSwgZGVmLnZhbHVlKSA9PT0gMDsKICAgIGlmIChpc011bHRpcGxlKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luOiB0eXBlb2YgcGF5bG9hZC52YWx1ZSwKICAgICAgY29kZTogIm5vdF9tdWx0aXBsZV9vZiIsCiAgICAgIGRpdmlzb3I6IGRlZi52YWx1ZSwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja051bWJlckZvcm1hdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja051bWJlckZvcm1hdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGRlZi5mb3JtYXQgPSBkZWYuZm9ybWF0IHx8ICJmbG9hdDY0IjsKICBjb25zdCBpc0ludCA9IGRlZi5mb3JtYXQ/LmluY2x1ZGVzKCJpbnQiKTsKICBjb25zdCBvcmlnaW4gPSBpc0ludCA/ICJpbnQiIDogIm51bWJlciI7CiAgY29uc3QgW21pbmltdW0sIG1heGltdW1dID0gTlVNQkVSX0ZPUk1BVF9SQU5HRVNbZGVmLmZvcm1hdF07CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICBjb25zdCBiYWcgPSBpbnN0Mi5fem9kLmJhZzsKICAgIGJhZy5mb3JtYXQgPSBkZWYuZm9ybWF0OwogICAgYmFnLm1pbmltdW0gPSBtaW5pbXVtOwogICAgYmFnLm1heGltdW0gPSBtYXhpbXVtOwogICAgaWYgKGlzSW50KQogICAgICBiYWcucGF0dGVybiA9IGludGVnZXI7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmIChpc0ludCkgewogICAgICBpZiAoIU51bWJlci5pc0ludGVnZXIoaW5wdXQpKSB7CiAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgICBleHBlY3RlZDogb3JpZ2luLAogICAgICAgICAgZm9ybWF0OiBkZWYuZm9ybWF0LAogICAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgICBjb250aW51ZTogZmFsc2UsCiAgICAgICAgICBpbnB1dCwKICAgICAgICAgIGluc3QKICAgICAgICB9KTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihpbnB1dCkpIHsKICAgICAgICBpZiAoaW5wdXQgPiAwKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgaW5wdXQsCiAgICAgICAgICAgIGNvZGU6ICJ0b29fYmlnIiwKICAgICAgICAgICAgbWF4aW11bTogTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIsCiAgICAgICAgICAgIG5vdGU6ICJJbnRlZ2VycyBtdXN0IGJlIHdpdGhpbiB0aGUgc2FmZSBpbnRlZ2VyIHJhbmdlLiIsCiAgICAgICAgICAgIGluc3QsCiAgICAgICAgICAgIG9yaWdpbiwKICAgICAgICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICAgICAgfSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgICAgICBpbnB1dCwKICAgICAgICAgICAgY29kZTogInRvb19zbWFsbCIsCiAgICAgICAgICAgIG1pbmltdW06IE51bWJlci5NSU5fU0FGRV9JTlRFR0VSLAogICAgICAgICAgICBub3RlOiAiSW50ZWdlcnMgbXVzdCBiZSB3aXRoaW4gdGhlIHNhZmUgaW50ZWdlciByYW5nZS4iLAogICAgICAgICAgICBpbnN0LAogICAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICAgIGluY2x1c2l2ZTogdHJ1ZSwKICAgICAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm47CiAgICAgIH0KICAgIH0KICAgIGlmIChpbnB1dCA8IG1pbmltdW0pIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgb3JpZ2luOiAibnVtYmVyIiwKICAgICAgICBpbnB1dCwKICAgICAgICBjb2RlOiAidG9vX3NtYWxsIiwKICAgICAgICBtaW5pbXVtLAogICAgICAgIGluY2x1c2l2ZTogdHJ1ZSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfQogICAgaWYgKGlucHV0ID4gbWF4aW11bSkgewogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBvcmlnaW46ICJudW1iZXIiLAogICAgICAgIGlucHV0LAogICAgICAgIGNvZGU6ICJ0b29fYmlnIiwKICAgICAgICBtYXhpbXVtLAogICAgICAgIGluY2x1c2l2ZTogdHJ1ZSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfQogIH07Cn0pOwp2YXIgJFpvZENoZWNrTWF4TGVuZ3RoID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrTWF4TGVuZ3RoIiwgKGluc3QsIGRlZikgPT4gewogIHZhciBfYTM7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICAoX2EzID0gaW5zdC5fem9kLmRlZikud2hlbiA/PyAoX2EzLndoZW4gPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgdmFsID0gcGF5bG9hZC52YWx1ZTsKICAgIHJldHVybiAhbnVsbGlzaCh2YWwpICYmIHZhbC5sZW5ndGggIT09IHZvaWQgMDsKICB9KTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGN1cnIgPSBpbnN0Mi5fem9kLmJhZy5tYXhpbXVtID8/IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgIGlmIChkZWYubWF4aW11bSA8IGN1cnIpCiAgICAgIGluc3QyLl96b2QuYmFnLm1heGltdW0gPSBkZWYubWF4aW11bTsKICB9KTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgY29uc3QgbGVuZ3RoID0gaW5wdXQubGVuZ3RoOwogICAgaWYgKGxlbmd0aCA8PSBkZWYubWF4aW11bSkKICAgICAgcmV0dXJuOwogICAgY29uc3Qgb3JpZ2luID0gZ2V0TGVuZ3RoYWJsZU9yaWdpbihpbnB1dCk7CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luLAogICAgICBjb2RlOiAidG9vX2JpZyIsCiAgICAgIG1heGltdW06IGRlZi5tYXhpbXVtLAogICAgICBpbmNsdXNpdmU6IHRydWUsCiAgICAgIGlucHV0LAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tNaW5MZW5ndGggPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tNaW5MZW5ndGgiLCAoaW5zdCwgZGVmKSA9PiB7CiAgdmFyIF9hMzsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIChfYTMgPSBpbnN0Ll96b2QuZGVmKS53aGVuID8/IChfYTMud2hlbiA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCB2YWwgPSBwYXlsb2FkLnZhbHVlOwogICAgcmV0dXJuICFudWxsaXNoKHZhbCkgJiYgdmFsLmxlbmd0aCAhPT0gdm9pZCAwOwogIH0pOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgY3VyciA9IGluc3QyLl96b2QuYmFnLm1pbmltdW0gPz8gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgaWYgKGRlZi5taW5pbXVtID4gY3VycikKICAgICAgaW5zdDIuX3pvZC5iYWcubWluaW11bSA9IGRlZi5taW5pbXVtOwogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7CiAgICBjb25zdCBsZW5ndGggPSBpbnB1dC5sZW5ndGg7CiAgICBpZiAobGVuZ3RoID49IGRlZi5taW5pbXVtKQogICAgICByZXR1cm47CiAgICBjb25zdCBvcmlnaW4gPSBnZXRMZW5ndGhhYmxlT3JpZ2luKGlucHV0KTsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW4sCiAgICAgIGNvZGU6ICJ0b29fc21hbGwiLAogICAgICBtaW5pbXVtOiBkZWYubWluaW11bSwKICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICBpbnB1dCwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZENoZWNrTGVuZ3RoRXF1YWxzID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrTGVuZ3RoRXF1YWxzIiwgKGluc3QsIGRlZikgPT4gewogIHZhciBfYTM7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICAoX2EzID0gaW5zdC5fem9kLmRlZikud2hlbiA/PyAoX2EzLndoZW4gPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgdmFsID0gcGF5bG9hZC52YWx1ZTsKICAgIHJldHVybiAhbnVsbGlzaCh2YWwpICYmIHZhbC5sZW5ndGggIT09IHZvaWQgMDsKICB9KTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLm1pbmltdW0gPSBkZWYubGVuZ3RoOwogICAgYmFnLm1heGltdW0gPSBkZWYubGVuZ3RoOwogICAgYmFnLmxlbmd0aCA9IGRlZi5sZW5ndGg7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGNvbnN0IGxlbmd0aCA9IGlucHV0Lmxlbmd0aDsKICAgIGlmIChsZW5ndGggPT09IGRlZi5sZW5ndGgpCiAgICAgIHJldHVybjsKICAgIGNvbnN0IG9yaWdpbiA9IGdldExlbmd0aGFibGVPcmlnaW4oaW5wdXQpOwogICAgY29uc3QgdG9vQmlnID0gbGVuZ3RoID4gZGVmLmxlbmd0aDsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW4sCiAgICAgIC4uLnRvb0JpZyA/IHsgY29kZTogInRvb19iaWciLCBtYXhpbXVtOiBkZWYubGVuZ3RoIH0gOiB7IGNvZGU6ICJ0b29fc21hbGwiLCBtaW5pbXVtOiBkZWYubGVuZ3RoIH0sCiAgICAgIGluY2x1c2l2ZTogdHJ1ZSwKICAgICAgZXhhY3Q6IHRydWUsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tTdHJpbmdGb3JtYXQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tTdHJpbmdGb3JtYXQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgdmFyIF9hMywgX2I7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLmZvcm1hdCA9IGRlZi5mb3JtYXQ7CiAgICBpZiAoZGVmLnBhdHRlcm4pIHsKICAgICAgYmFnLnBhdHRlcm5zID8/IChiYWcucGF0dGVybnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgICAgYmFnLnBhdHRlcm5zLmFkZChkZWYucGF0dGVybik7CiAgICB9CiAgfSk7CiAgaWYgKGRlZi5wYXR0ZXJuKQogICAgKF9hMyA9IGluc3QuX3pvZCkuY2hlY2sgPz8gKF9hMy5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICAgIGRlZi5wYXR0ZXJuLmxhc3RJbmRleCA9IDA7CiAgICAgIGlmIChkZWYucGF0dGVybi50ZXN0KHBheWxvYWQudmFsdWUpKQogICAgICAgIHJldHVybjsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgb3JpZ2luOiAic3RyaW5nIiwKICAgICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICAgIGZvcm1hdDogZGVmLmZvcm1hdCwKICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICAuLi5kZWYucGF0dGVybiA/IHsgcGF0dGVybjogZGVmLnBhdHRlcm4udG9TdHJpbmcoKSB9IDoge30sCiAgICAgICAgaW5zdCwKICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICB9KTsKICAgIH0pOwogIGVsc2UKICAgIChfYiA9IGluc3QuX3pvZCkuY2hlY2sgPz8gKF9iLmNoZWNrID0gKCkgPT4gewogICAgfSk7Cn0pOwp2YXIgJFpvZENoZWNrUmVnZXggPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tSZWdleCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2tTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBkZWYucGF0dGVybi5sYXN0SW5kZXggPSAwOwogICAgaWYgKGRlZi5wYXR0ZXJuLnRlc3QocGF5bG9hZC52YWx1ZSkpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW46ICJzdHJpbmciLAogICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICBmb3JtYXQ6ICJyZWdleCIsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBwYXR0ZXJuOiBkZWYucGF0dGVybi50b1N0cmluZygpLAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tMb3dlckNhc2UgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tMb3dlckNhc2UiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gbG93ZXJjYXNlKTsKICAkWm9kQ2hlY2tTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RDaGVja1VwcGVyQ2FzZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja1VwcGVyQ2FzZSIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB1cHBlcmNhc2UpOwogICRab2RDaGVja1N0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZENoZWNrSW5jbHVkZXMgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tJbmNsdWRlcyIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGNvbnN0IGVzY2FwZWRSZWdleCA9IGVzY2FwZVJlZ2V4KGRlZi5pbmNsdWRlcyk7CiAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAodHlwZW9mIGRlZi5wb3NpdGlvbiA9PT0gIm51bWJlciIgPyBgXi57JHtkZWYucG9zaXRpb259fSR7ZXNjYXBlZFJlZ2V4fWAgOiBlc2NhcGVkUmVnZXgpOwogIGRlZi5wYXR0ZXJuID0gcGF0dGVybjsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLnBhdHRlcm5zID8/IChiYWcucGF0dGVybnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgIGJhZy5wYXR0ZXJucy5hZGQocGF0dGVybik7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChwYXlsb2FkLnZhbHVlLmluY2x1ZGVzKGRlZi5pbmNsdWRlcywgZGVmLnBvc2l0aW9uKSkKICAgICAgcmV0dXJuOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbjogInN0cmluZyIsCiAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgIGZvcm1hdDogImluY2x1ZGVzIiwKICAgICAgaW5jbHVkZXM6IGRlZi5pbmNsdWRlcywKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja1N0YXJ0c1dpdGggPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tTdGFydHNXaXRoIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoYF4ke2VzY2FwZVJlZ2V4KGRlZi5wcmVmaXgpfS4qYCk7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gcGF0dGVybik7CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICBjb25zdCBiYWcgPSBpbnN0Mi5fem9kLmJhZzsKICAgIGJhZy5wYXR0ZXJucyA/PyAoYmFnLnBhdHRlcm5zID0gLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKSk7CiAgICBiYWcucGF0dGVybnMuYWRkKHBhdHRlcm4pOwogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBpZiAocGF5bG9hZC52YWx1ZS5zdGFydHNXaXRoKGRlZi5wcmVmaXgpKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luOiAic3RyaW5nIiwKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAic3RhcnRzX3dpdGgiLAogICAgICBwcmVmaXg6IGRlZi5wcmVmaXgsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tFbmRzV2l0aCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja0VuZHNXaXRoIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoYC4qJHtlc2NhcGVSZWdleChkZWYuc3VmZml4KX0kYCk7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gcGF0dGVybik7CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICBjb25zdCBiYWcgPSBpbnN0Mi5fem9kLmJhZzsKICAgIGJhZy5wYXR0ZXJucyA/PyAoYmFnLnBhdHRlcm5zID0gLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKSk7CiAgICBiYWcucGF0dGVybnMuYWRkKHBhdHRlcm4pOwogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBpZiAocGF5bG9hZC52YWx1ZS5lbmRzV2l0aChkZWYuc3VmZml4KSkKICAgICAgcmV0dXJuOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbjogInN0cmluZyIsCiAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgIGZvcm1hdDogImVuZHNfd2l0aCIsCiAgICAgIHN1ZmZpeDogZGVmLnN1ZmZpeCwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja092ZXJ3cml0ZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja092ZXJ3cml0ZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBwYXlsb2FkLnZhbHVlID0gZGVmLnR4KHBheWxvYWQudmFsdWUpOwogIH07Cn0pOwoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL2RvYy5qcwp2YXIgRG9jID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKGFyZ3MgPSBbXSkgewogICAgdGhpcy5jb250ZW50ID0gW107CiAgICB0aGlzLmluZGVudCA9IDA7CiAgICBpZiAodGhpcykKICAgICAgdGhpcy5hcmdzID0gYXJnczsKICB9CiAgaW5kZW50ZWQoZm4pIHsKICAgIHRoaXMuaW5kZW50ICs9IDE7CiAgICBmbih0aGlzKTsKICAgIHRoaXMuaW5kZW50IC09IDE7CiAgfQogIHdyaXRlKGFyZykgewogICAgaWYgKHR5cGVvZiBhcmcgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgYXJnKHRoaXMsIHsgZXhlY3V0aW9uOiAic3luYyIgfSk7CiAgICAgIGFyZyh0aGlzLCB7IGV4ZWN1dGlvbjogImFzeW5jIiB9KTsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3QgY29udGVudCA9IGFyZzsKICAgIGNvbnN0IGxpbmVzID0gY29udGVudC5zcGxpdCgiXG4iKS5maWx0ZXIoKHgpID0+IHgpOwogICAgY29uc3QgbWluSW5kZW50ID0gTWF0aC5taW4oLi4ubGluZXMubWFwKCh4KSA9PiB4Lmxlbmd0aCAtIHgudHJpbVN0YXJ0KCkubGVuZ3RoKSk7CiAgICBjb25zdCBkZWRlbnRlZCA9IGxpbmVzLm1hcCgoeCkgPT4geC5zbGljZShtaW5JbmRlbnQpKS5tYXAoKHgpID0+ICIgIi5yZXBlYXQodGhpcy5pbmRlbnQgKiAyKSArIHgpOwogICAgZm9yIChjb25zdCBsaW5lIG9mIGRlZGVudGVkKSB7CiAgICAgIHRoaXMuY29udGVudC5wdXNoKGxpbmUpOwogICAgfQogIH0KICBjb21waWxlKCkgewogICAgY29uc3QgRiA9IEZ1bmN0aW9uOwogICAgY29uc3QgYXJncyA9IHRoaXM/LmFyZ3M7CiAgICBjb25zdCBjb250ZW50ID0gdGhpcz8uY29udGVudCA/PyBbYGBdOwogICAgY29uc3QgbGluZXMgPSBbLi4uY29udGVudC5tYXAoKHgpID0+IGAgICR7eH1gKV07CiAgICByZXR1cm4gbmV3IEYoLi4uYXJncywgbGluZXMuam9pbigiXG4iKSk7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL3ZlcnNpb25zLmpzCnZhciB2ZXJzaW9uID0gewogIG1ham9yOiA0LAogIG1pbm9yOiA0LAogIHBhdGNoOiAzCn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvc2NoZW1hcy5qcwp2YXIgJFpvZFR5cGUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVHlwZSIsIChpbnN0LCBkZWYpID0+IHsKICB2YXIgX2EzOwogIGluc3QgPz8gKGluc3QgPSB7fSk7CiAgaW5zdC5fem9kLmRlZiA9IGRlZjsKICBpbnN0Ll96b2QuYmFnID0gaW5zdC5fem9kLmJhZyB8fCB7fTsKICBpbnN0Ll96b2QudmVyc2lvbiA9IHZlcnNpb247CiAgY29uc3QgY2hlY2tzID0gWy4uLmluc3QuX3pvZC5kZWYuY2hlY2tzID8/IFtdXTsKICBpZiAoaW5zdC5fem9kLnRyYWl0cy5oYXMoIiRab2RDaGVjayIpKSB7CiAgICBjaGVja3MudW5zaGlmdChpbnN0KTsKICB9CiAgZm9yIChjb25zdCBjaCBvZiBjaGVja3MpIHsKICAgIGZvciAoY29uc3QgZm4gb2YgY2guX3pvZC5vbmF0dGFjaCkgewogICAgICBmbihpbnN0KTsKICAgIH0KICB9CiAgaWYgKGNoZWNrcy5sZW5ndGggPT09IDApIHsKICAgIChfYTMgPSBpbnN0Ll96b2QpLmRlZmVycmVkID8/IChfYTMuZGVmZXJyZWQgPSBbXSk7CiAgICBpbnN0Ll96b2QuZGVmZXJyZWQ/LnB1c2goKCkgPT4gewogICAgICBpbnN0Ll96b2QucnVuID0gaW5zdC5fem9kLnBhcnNlOwogICAgfSk7CiAgfSBlbHNlIHsKICAgIGNvbnN0IHJ1bkNoZWNrcyA9IChwYXlsb2FkLCBjaGVja3MyLCBjdHgpID0+IHsKICAgICAgbGV0IGlzQWJvcnRlZCA9IGFib3J0ZWQocGF5bG9hZCk7CiAgICAgIGxldCBhc3luY1Jlc3VsdDsKICAgICAgZm9yIChjb25zdCBjaCBvZiBjaGVja3MyKSB7CiAgICAgICAgaWYgKGNoLl96b2QuZGVmLndoZW4pIHsKICAgICAgICAgIGlmIChleHBsaWNpdGx5QWJvcnRlZChwYXlsb2FkKSkKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBjb25zdCBzaG91bGRSdW4gPSBjaC5fem9kLmRlZi53aGVuKHBheWxvYWQpOwogICAgICAgICAgaWYgKCFzaG91bGRSdW4pCiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0gZWxzZSBpZiAoaXNBYm9ydGVkKSB7CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY3VyckxlbiA9IHBheWxvYWQuaXNzdWVzLmxlbmd0aDsKICAgICAgICBjb25zdCBfID0gY2guX3pvZC5jaGVjayhwYXlsb2FkKTsKICAgICAgICBpZiAoXyBpbnN0YW5jZW9mIFByb21pc2UgJiYgY3R4Py5hc3luYyA9PT0gZmFsc2UpIHsKICAgICAgICAgIHRocm93IG5ldyAkWm9kQXN5bmNFcnJvcigpOwogICAgICAgIH0KICAgICAgICBpZiAoYXN5bmNSZXN1bHQgfHwgXyBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICAgIGFzeW5jUmVzdWx0ID0gKGFzeW5jUmVzdWx0ID8/IFByb21pc2UucmVzb2x2ZSgpKS50aGVuKGFzeW5jICgpID0+IHsKICAgICAgICAgICAgYXdhaXQgXzsKICAgICAgICAgICAgY29uc3QgbmV4dExlbiA9IHBheWxvYWQuaXNzdWVzLmxlbmd0aDsKICAgICAgICAgICAgaWYgKG5leHRMZW4gPT09IGN1cnJMZW4pCiAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICBpZiAoIWlzQWJvcnRlZCkKICAgICAgICAgICAgICBpc0Fib3J0ZWQgPSBhYm9ydGVkKHBheWxvYWQsIGN1cnJMZW4pOwogICAgICAgICAgfSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGNvbnN0IG5leHRMZW4gPSBwYXlsb2FkLmlzc3Vlcy5sZW5ndGg7CiAgICAgICAgICBpZiAobmV4dExlbiA9PT0gY3VyckxlbikKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBpZiAoIWlzQWJvcnRlZCkKICAgICAgICAgICAgaXNBYm9ydGVkID0gYWJvcnRlZChwYXlsb2FkLCBjdXJyTGVuKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKGFzeW5jUmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIGFzeW5jUmVzdWx0LnRoZW4oKCkgPT4gewogICAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgICAgfSk7CiAgICAgIH0KICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9OwogICAgY29uc3QgaGFuZGxlQ2FuYXJ5UmVzdWx0ID0gKGNhbmFyeSwgcGF5bG9hZCwgY3R4KSA9PiB7CiAgICAgIGlmIChhYm9ydGVkKGNhbmFyeSkpIHsKICAgICAgICBjYW5hcnkuYWJvcnRlZCA9IHRydWU7CiAgICAgICAgcmV0dXJuIGNhbmFyeTsKICAgICAgfQogICAgICBjb25zdCBjaGVja1Jlc3VsdCA9IHJ1bkNoZWNrcyhwYXlsb2FkLCBjaGVja3MsIGN0eCk7CiAgICAgIGlmIChjaGVja1Jlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICBpZiAoY3R4LmFzeW5jID09PSBmYWxzZSkKICAgICAgICAgIHRocm93IG5ldyAkWm9kQXN5bmNFcnJvcigpOwogICAgICAgIHJldHVybiBjaGVja1Jlc3VsdC50aGVuKChjaGVja1Jlc3VsdDIpID0+IGluc3QuX3pvZC5wYXJzZShjaGVja1Jlc3VsdDIsIGN0eCkpOwogICAgICB9CiAgICAgIHJldHVybiBpbnN0Ll96b2QucGFyc2UoY2hlY2tSZXN1bHQsIGN0eCk7CiAgICB9OwogICAgaW5zdC5fem9kLnJ1biA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgICAgaWYgKGN0eC5za2lwQ2hlY2tzKSB7CiAgICAgICAgcmV0dXJuIGluc3QuX3pvZC5wYXJzZShwYXlsb2FkLCBjdHgpOwogICAgICB9CiAgICAgIGlmIChjdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgICAgY29uc3QgY2FuYXJ5ID0gaW5zdC5fem9kLnBhcnNlKHsgdmFsdWU6IHBheWxvYWQudmFsdWUsIGlzc3VlczogW10gfSwgeyAuLi5jdHgsIHNraXBDaGVja3M6IHRydWUgfSk7CiAgICAgICAgaWYgKGNhbmFyeSBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICAgIHJldHVybiBjYW5hcnkudGhlbigoY2FuYXJ5MikgPT4gewogICAgICAgICAgICByZXR1cm4gaGFuZGxlQ2FuYXJ5UmVzdWx0KGNhbmFyeTIsIHBheWxvYWQsIGN0eCk7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGhhbmRsZUNhbmFyeVJlc3VsdChjYW5hcnksIHBheWxvYWQsIGN0eCk7CiAgICAgIH0KICAgICAgY29uc3QgcmVzdWx0ID0gaW5zdC5fem9kLnBhcnNlKHBheWxvYWQsIGN0eCk7CiAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgaWYgKGN0eC5hc3luYyA9PT0gZmFsc2UpCiAgICAgICAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICAgICAgICByZXR1cm4gcmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IHJ1bkNoZWNrcyhyZXN1bHQyLCBjaGVja3MsIGN0eCkpOwogICAgICB9CiAgICAgIHJldHVybiBydW5DaGVja3MocmVzdWx0LCBjaGVja3MsIGN0eCk7CiAgICB9OwogIH0KICBkZWZpbmVMYXp5KGluc3QsICJ+c3RhbmRhcmQiLCAoKSA9PiAoewogICAgdmFsaWRhdGU6ICh2YWx1ZSkgPT4gewogICAgICB0cnkgewogICAgICAgIGNvbnN0IHIgPSBzYWZlUGFyc2UoaW5zdCwgdmFsdWUpOwogICAgICAgIHJldHVybiByLnN1Y2Nlc3MgPyB7IHZhbHVlOiByLmRhdGEgfSA6IHsgaXNzdWVzOiByLmVycm9yPy5pc3N1ZXMgfTsKICAgICAgfSBjYXRjaCAoXykgewogICAgICAgIHJldHVybiBzYWZlUGFyc2VBc3luYyhpbnN0LCB2YWx1ZSkudGhlbigocikgPT4gci5zdWNjZXNzID8geyB2YWx1ZTogci5kYXRhIH0gOiB7IGlzc3Vlczogci5lcnJvcj8uaXNzdWVzIH0pOwogICAgICB9CiAgICB9LAogICAgdmVuZG9yOiAiem9kIiwKICAgIHZlcnNpb246IDEKICB9KSk7Cn0pOwp2YXIgJFpvZFN0cmluZyA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RTdHJpbmciLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXR0ZXJuID0gWy4uLmluc3Q/Ll96b2QuYmFnPy5wYXR0ZXJucyA/PyBbXV0ucG9wKCkgPz8gc3RyaW5nKGluc3QuX3pvZC5iYWcpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBfKSA9PiB7CiAgICBpZiAoZGVmLmNvZXJjZSkKICAgICAgdHJ5IHsKICAgICAgICBwYXlsb2FkLnZhbHVlID0gU3RyaW5nKHBheWxvYWQudmFsdWUpOwogICAgICB9IGNhdGNoIChfMikgewogICAgICB9CiAgICBpZiAodHlwZW9mIHBheWxvYWQudmFsdWUgPT09ICJzdHJpbmciKQogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBleHBlY3RlZDogInN0cmluZyIsCiAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdAogICAgfSk7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKdmFyICRab2RTdHJpbmdGb3JtYXQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kU3RyaW5nRm9ybWF0IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVja1N0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgJFpvZFN0cmluZy5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZEdVSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kR1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBndWlkKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kVVVJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RVVUlEIiwgKGluc3QsIGRlZikgPT4gewogIGlmIChkZWYudmVyc2lvbikgewogICAgY29uc3QgdmVyc2lvbk1hcCA9IHsKICAgICAgdjE6IDEsCiAgICAgIHYyOiAyLAogICAgICB2MzogMywKICAgICAgdjQ6IDQsCiAgICAgIHY1OiA1LAogICAgICB2NjogNiwKICAgICAgdjc6IDcsCiAgICAgIHY4OiA4CiAgICB9OwogICAgY29uc3QgdiA9IHZlcnNpb25NYXBbZGVmLnZlcnNpb25dOwogICAgaWYgKHYgPT09IHZvaWQgMCkKICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIFVVSUQgdmVyc2lvbjogIiR7ZGVmLnZlcnNpb259ImApOwogICAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gdXVpZCh2KSk7CiAgfSBlbHNlCiAgICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB1dWlkKCkpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RFbWFpbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RFbWFpbCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBlbWFpbCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZFVSTCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RVUkwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIHRyeSB7CiAgICAgIGNvbnN0IHRyaW1tZWQgPSBwYXlsb2FkLnZhbHVlLnRyaW0oKTsKICAgICAgaWYgKCFkZWYubm9ybWFsaXplICYmIGRlZi5wcm90b2NvbD8uc291cmNlID09PSBodHRwUHJvdG9jb2wuc291cmNlKSB7CiAgICAgICAgaWYgKCEvXmh0dHBzPzpcL1wvL2kudGVzdCh0cmltbWVkKSkgewogICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgICAgICAgIGZvcm1hdDogInVybCIsCiAgICAgICAgICAgIG5vdGU6ICJJbnZhbGlkIFVSTCBmb3JtYXQiLAogICAgICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICAgICAgaW5zdCwKICAgICAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgICAgIH0pOwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgfQogICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHRyaW1tZWQpOwogICAgICBpZiAoZGVmLmhvc3RuYW1lKSB7CiAgICAgICAgZGVmLmhvc3RuYW1lLmxhc3RJbmRleCA9IDA7CiAgICAgICAgaWYgKCFkZWYuaG9zdG5hbWUudGVzdCh1cmwuaG9zdG5hbWUpKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgICAgICAgZm9ybWF0OiAidXJsIiwKICAgICAgICAgICAgbm90ZTogIkludmFsaWQgaG9zdG5hbWUiLAogICAgICAgICAgICBwYXR0ZXJuOiBkZWYuaG9zdG5hbWUuc291cmNlLAogICAgICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICAgICAgaW5zdCwKICAgICAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoZGVmLnByb3RvY29sKSB7CiAgICAgICAgZGVmLnByb3RvY29sLmxhc3RJbmRleCA9IDA7CiAgICAgICAgaWYgKCFkZWYucHJvdG9jb2wudGVzdCh1cmwucHJvdG9jb2wuZW5kc1dpdGgoIjoiKSA/IHVybC5wcm90b2NvbC5zbGljZSgwLCAtMSkgOiB1cmwucHJvdG9jb2wpKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgICAgICAgZm9ybWF0OiAidXJsIiwKICAgICAgICAgICAgbm90ZTogIkludmFsaWQgcHJvdG9jb2wiLAogICAgICAgICAgICBwYXR0ZXJuOiBkZWYucHJvdG9jb2wuc291cmNlLAogICAgICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICAgICAgaW5zdCwKICAgICAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoZGVmLm5vcm1hbGl6ZSkgewogICAgICAgIHBheWxvYWQudmFsdWUgPSB1cmwuaHJlZjsKICAgICAgfSBlbHNlIHsKICAgICAgICBwYXlsb2FkLnZhbHVlID0gdHJpbW1lZDsKICAgICAgfQogICAgICByZXR1cm47CiAgICB9IGNhdGNoIChfKSB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgICAgZm9ybWF0OiAidXJsIiwKICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfQogIH07Cn0pOwp2YXIgJFpvZEVtb2ppID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEVtb2ppIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGVtb2ppKCkpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2ROYW5vSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kTmFub0lEIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IG5hbm9pZCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZENVSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBjdWlkKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kQ1VJRDIgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ1VJRDIiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gY3VpZDIpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RVTElEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFVMSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gdWxpZCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZFhJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RYSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0geGlkKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kS1NVSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kS1NVSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0ga3N1aWQpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RJU09EYXRlVGltZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RJU09EYXRlVGltZSIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBkYXRldGltZShkZWYpKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kSVNPRGF0ZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RJU09EYXRlIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGRhdGUpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RJU09UaW1lID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZElTT1RpbWUiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gdGltZShkZWYpKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kSVNPRHVyYXRpb24gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kSVNPRHVyYXRpb24iLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gZHVyYXRpb24pOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RJUHY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZElQdjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gaXB2NCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmJhZy5mb3JtYXQgPSBgaXB2NGA7Cn0pOwp2YXIgJFpvZElQdjYgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kSVB2NiIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBpcHY2KTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QuYmFnLmZvcm1hdCA9IGBpcHY2YDsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgdHJ5IHsKICAgICAgbmV3IFVSTChgaHR0cDovL1ske3BheWxvYWQudmFsdWV9XWApOwogICAgfSBjYXRjaCB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgICAgZm9ybWF0OiAiaXB2NiIsCiAgICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgICAgaW5zdCwKICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICB9KTsKICAgIH0KICB9Owp9KTsKdmFyICRab2RDSURSdjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ0lEUnY0IiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGNpZHJ2NCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZENJRFJ2NiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDSURSdjYiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gY2lkcnY2KTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgcGFydHMgPSBwYXlsb2FkLnZhbHVlLnNwbGl0KCIvIik7CiAgICB0cnkgewogICAgICBpZiAocGFydHMubGVuZ3RoICE9PSAyKQogICAgICAgIHRocm93IG5ldyBFcnJvcigpOwogICAgICBjb25zdCBbYWRkcmVzcywgcHJlZml4XSA9IHBhcnRzOwogICAgICBpZiAoIXByZWZpeCkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTsKICAgICAgY29uc3QgcHJlZml4TnVtID0gTnVtYmVyKHByZWZpeCk7CiAgICAgIGlmIChgJHtwcmVmaXhOdW19YCAhPT0gcHJlZml4KQogICAgICAgIHRocm93IG5ldyBFcnJvcigpOwogICAgICBpZiAocHJlZml4TnVtIDwgMCB8fCBwcmVmaXhOdW0gPiAxMjgpCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7CiAgICAgIG5ldyBVUkwoYGh0dHA6Ly9bJHthZGRyZXNzfV1gKTsKICAgIH0gY2F0Y2ggewogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICAgIGZvcm1hdDogImNpZHJ2NiIsCiAgICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgICAgaW5zdCwKICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICB9KTsKICAgIH0KICB9Owp9KTsKZnVuY3Rpb24gaXNWYWxpZEJhc2U2NChkYXRhKSB7CiAgaWYgKGRhdGEgPT09ICIiKQogICAgcmV0dXJuIHRydWU7CiAgaWYgKC9ccy8udGVzdChkYXRhKSkKICAgIHJldHVybiBmYWxzZTsKICBpZiAoZGF0YS5sZW5ndGggJSA0ICE9PSAwKQogICAgcmV0dXJuIGZhbHNlOwogIHRyeSB7CiAgICBhdG9iKGRhdGEpOwogICAgcmV0dXJuIHRydWU7CiAgfSBjYXRjaCB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQp9CnZhciAkWm9kQmFzZTY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEJhc2U2NCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBiYXNlNjQpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5iYWcuY29udGVudEVuY29kaW5nID0gImJhc2U2NCI7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChpc1ZhbGlkQmFzZTY0KHBheWxvYWQudmFsdWUpKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAiYmFzZTY0IiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKZnVuY3Rpb24gaXNWYWxpZEJhc2U2NFVSTChkYXRhKSB7CiAgaWYgKCFiYXNlNjR1cmwudGVzdChkYXRhKSkKICAgIHJldHVybiBmYWxzZTsKICBjb25zdCBiYXNlNjQyID0gZGF0YS5yZXBsYWNlKC9bLV9dL2csIChjKSA9PiBjID09PSAiLSIgPyAiKyIgOiAiLyIpOwogIGNvbnN0IHBhZGRlZCA9IGJhc2U2NDIucGFkRW5kKE1hdGguY2VpbChiYXNlNjQyLmxlbmd0aCAvIDQpICogNCwgIj0iKTsKICByZXR1cm4gaXNWYWxpZEJhc2U2NChwYWRkZWQpOwp9CnZhciAkWm9kQmFzZTY0VVJMID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEJhc2U2NFVSTCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBiYXNlNjR1cmwpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5iYWcuY29udGVudEVuY29kaW5nID0gImJhc2U2NHVybCI7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChpc1ZhbGlkQmFzZTY0VVJMKHBheWxvYWQudmFsdWUpKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAiYmFzZTY0dXJsIiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RFMTY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEUxNjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gZTE2NCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwpmdW5jdGlvbiBpc1ZhbGlkSldUKHRva2VuLCBhbGdvcml0aG0gPSBudWxsKSB7CiAgdHJ5IHsKICAgIGNvbnN0IHRva2Vuc1BhcnRzID0gdG9rZW4uc3BsaXQoIi4iKTsKICAgIGlmICh0b2tlbnNQYXJ0cy5sZW5ndGggIT09IDMpCiAgICAgIHJldHVybiBmYWxzZTsKICAgIGNvbnN0IFtoZWFkZXJdID0gdG9rZW5zUGFydHM7CiAgICBpZiAoIWhlYWRlcikKICAgICAgcmV0dXJuIGZhbHNlOwogICAgY29uc3QgcGFyc2VkSGVhZGVyID0gSlNPTi5wYXJzZShhdG9iKGhlYWRlcikpOwogICAgaWYgKCJ0eXAiIGluIHBhcnNlZEhlYWRlciAmJiBwYXJzZWRIZWFkZXI/LnR5cCAhPT0gIkpXVCIpCiAgICAgIHJldHVybiBmYWxzZTsKICAgIGlmICghcGFyc2VkSGVhZGVyLmFsZykKICAgICAgcmV0dXJuIGZhbHNlOwogICAgaWYgKGFsZ29yaXRobSAmJiAoISgiYWxnIiBpbiBwYXJzZWRIZWFkZXIpIHx8IHBhcnNlZEhlYWRlci5hbGcgIT09IGFsZ29yaXRobSkpCiAgICAgIHJldHVybiBmYWxzZTsKICAgIHJldHVybiB0cnVlOwogIH0gY2F0Y2ggewogICAgcmV0dXJuIGZhbHNlOwogIH0KfQp2YXIgJFpvZEpXVCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RKV1QiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChpc1ZhbGlkSldUKHBheWxvYWQudmFsdWUsIGRlZi5hbGcpKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAiand0IiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2ROdW1iZXIgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kTnVtYmVyIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucGF0dGVybiA9IGluc3QuX3pvZC5iYWcucGF0dGVybiA/PyBudW1iZXI7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIF9jdHgpID0+IHsKICAgIGlmIChkZWYuY29lcmNlKQogICAgICB0cnkgewogICAgICAgIHBheWxvYWQudmFsdWUgPSBOdW1iZXIocGF5bG9hZC52YWx1ZSk7CiAgICAgIH0gY2F0Y2ggKF8pIHsKICAgICAgfQogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gIm51bWJlciIgJiYgIU51bWJlci5pc05hTihpbnB1dCkgJiYgTnVtYmVyLmlzRmluaXRlKGlucHV0KSkgewogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH0KICAgIGNvbnN0IHJlY2VpdmVkID0gdHlwZW9mIGlucHV0ID09PSAibnVtYmVyIiA/IE51bWJlci5pc05hTihpbnB1dCkgPyAiTmFOIiA6ICFOdW1iZXIuaXNGaW5pdGUoaW5wdXQpID8gIkluZmluaXR5IiA6IHZvaWQgMCA6IHZvaWQgMDsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBleHBlY3RlZDogIm51bWJlciIsCiAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICBpbnB1dCwKICAgICAgaW5zdCwKICAgICAgLi4ucmVjZWl2ZWQgPyB7IHJlY2VpdmVkIH0gOiB7fQogICAgfSk7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKdmFyICRab2ROdW1iZXJGb3JtYXQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kTnVtYmVyRm9ybWF0IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVja051bWJlckZvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgJFpvZE51bWJlci5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZFVua25vd24gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVW5rbm93biIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQpID0+IHBheWxvYWQ7Cn0pOwp2YXIgJFpvZE5ldmVyID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZE5ldmVyIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGV4cGVjdGVkOiAibmV2ZXIiLAogICAgICBjb2RlOiAiaW52YWxpZF90eXBlIiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QKICAgIH0pOwogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZUFycmF5UmVzdWx0KHJlc3VsdCwgZmluYWwsIGluZGV4KSB7CiAgaWYgKHJlc3VsdC5pc3N1ZXMubGVuZ3RoKSB7CiAgICBmaW5hbC5pc3N1ZXMucHVzaCguLi5wcmVmaXhJc3N1ZXMoaW5kZXgsIHJlc3VsdC5pc3N1ZXMpKTsKICB9CiAgZmluYWwudmFsdWVbaW5kZXhdID0gcmVzdWx0LnZhbHVlOwp9CnZhciAkWm9kQXJyYXkgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQXJyYXkiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghQXJyYXkuaXNBcnJheShpbnB1dCkpIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgZXhwZWN0ZWQ6ICJhcnJheSIsCiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgaW5wdXQsCiAgICAgICAgaW5zdAogICAgICB9KTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBwYXlsb2FkLnZhbHVlID0gQXJyYXkoaW5wdXQubGVuZ3RoKTsKICAgIGNvbnN0IHByb21zID0gW107CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7CiAgICAgIGNvbnN0IGl0ZW0gPSBpbnB1dFtpXTsKICAgICAgY29uc3QgcmVzdWx0ID0gZGVmLmVsZW1lbnQuX3pvZC5ydW4oewogICAgICAgIHZhbHVlOiBpdGVtLAogICAgICAgIGlzc3VlczogW10KICAgICAgfSwgY3R4KTsKICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICBwcm9tcy5wdXNoKHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiBoYW5kbGVBcnJheVJlc3VsdChyZXN1bHQyLCBwYXlsb2FkLCBpKSkpOwogICAgICB9IGVsc2UgewogICAgICAgIGhhbmRsZUFycmF5UmVzdWx0KHJlc3VsdCwgcGF5bG9hZCwgaSk7CiAgICAgIH0KICAgIH0KICAgIGlmIChwcm9tcy5sZW5ndGgpIHsKICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHByb21zKS50aGVuKCgpID0+IHBheWxvYWQpOwogICAgfQogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZVByb3BlcnR5UmVzdWx0KHJlc3VsdCwgZmluYWwsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkgewogIGNvbnN0IGlzUHJlc2VudCA9IGtleSBpbiBpbnB1dDsKICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgIGlmIChpc09wdGlvbmFsSW4gJiYgaXNPcHRpb25hbE91dCAmJiAhaXNQcmVzZW50KSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGZpbmFsLmlzc3Vlcy5wdXNoKC4uLnByZWZpeElzc3VlcyhrZXksIHJlc3VsdC5pc3N1ZXMpKTsKICB9CiAgaWYgKCFpc1ByZXNlbnQgJiYgIWlzT3B0aW9uYWxJbikgewogICAgaWYgKCFyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICBmaW5hbC5pc3N1ZXMucHVzaCh7CiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgZXhwZWN0ZWQ6ICJub25vcHRpb25hbCIsCiAgICAgICAgaW5wdXQ6IHZvaWQgMCwKICAgICAgICBwYXRoOiBba2V5XQogICAgICB9KTsKICAgIH0KICAgIHJldHVybjsKICB9CiAgaWYgKHJlc3VsdC52YWx1ZSA9PT0gdm9pZCAwKSB7CiAgICBpZiAoaXNQcmVzZW50KSB7CiAgICAgIGZpbmFsLnZhbHVlW2tleV0gPSB2b2lkIDA7CiAgICB9CiAgfSBlbHNlIHsKICAgIGZpbmFsLnZhbHVlW2tleV0gPSByZXN1bHQudmFsdWU7CiAgfQp9CmZ1bmN0aW9uIG5vcm1hbGl6ZURlZihkZWYpIHsKICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoZGVmLnNoYXBlKTsKICBmb3IgKGNvbnN0IGsgb2Yga2V5cykgewogICAgaWYgKCFkZWYuc2hhcGU/LltrXT8uX3pvZD8udHJhaXRzPy5oYXMoIiRab2RUeXBlIikpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGVsZW1lbnQgYXQga2V5ICIke2t9IjogZXhwZWN0ZWQgYSBab2Qgc2NoZW1hYCk7CiAgICB9CiAgfQogIGNvbnN0IG9rZXlzID0gb3B0aW9uYWxLZXlzKGRlZi5zaGFwZSk7CiAgcmV0dXJuIHsKICAgIC4uLmRlZiwKICAgIGtleXMsCiAgICBrZXlTZXQ6IG5ldyBTZXQoa2V5cyksCiAgICBudW1LZXlzOiBrZXlzLmxlbmd0aCwKICAgIG9wdGlvbmFsS2V5czogbmV3IFNldChva2V5cykKICB9Owp9CmZ1bmN0aW9uIGhhbmRsZUNhdGNoYWxsKHByb21zLCBpbnB1dCwgcGF5bG9hZCwgY3R4LCBkZWYsIGluc3QpIHsKICBjb25zdCB1bnJlY29nbml6ZWQgPSBbXTsKICBjb25zdCBrZXlTZXQgPSBkZWYua2V5U2V0OwogIGNvbnN0IF9jYXRjaGFsbCA9IGRlZi5jYXRjaGFsbC5fem9kOwogIGNvbnN0IHQgPSBfY2F0Y2hhbGwuZGVmLnR5cGU7CiAgY29uc3QgaXNPcHRpb25hbEluID0gX2NhdGNoYWxsLm9wdGluID09PSAib3B0aW9uYWwiOwogIGNvbnN0IGlzT3B0aW9uYWxPdXQgPSBfY2F0Y2hhbGwub3B0b3V0ID09PSAib3B0aW9uYWwiOwogIGZvciAoY29uc3Qga2V5IGluIGlucHV0KSB7CiAgICBpZiAoa2V5ID09PSAiX19wcm90b19fIikKICAgICAgY29udGludWU7CiAgICBpZiAoa2V5U2V0LmhhcyhrZXkpKQogICAgICBjb250aW51ZTsKICAgIGlmICh0ID09PSAibmV2ZXIiKSB7CiAgICAgIHVucmVjb2duaXplZC5wdXNoKGtleSk7CiAgICAgIGNvbnRpbnVlOwogICAgfQogICAgY29uc3QgciA9IF9jYXRjaGFsbC5ydW4oeyB2YWx1ZTogaW5wdXRba2V5XSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgaWYgKHIgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgIHByb21zLnB1c2goci50aGVuKChyMikgPT4gaGFuZGxlUHJvcGVydHlSZXN1bHQocjIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkpKTsKICAgIH0gZWxzZSB7CiAgICAgIGhhbmRsZVByb3BlcnR5UmVzdWx0KHIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCk7CiAgICB9CiAgfQogIGlmICh1bnJlY29nbml6ZWQubGVuZ3RoKSB7CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgY29kZTogInVucmVjb2duaXplZF9rZXlzIiwKICAgICAga2V5czogdW5yZWNvZ25pemVkLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfSk7CiAgfQogIGlmICghcHJvbXMubGVuZ3RoKQogICAgcmV0dXJuIHBheWxvYWQ7CiAgcmV0dXJuIFByb21pc2UuYWxsKHByb21zKS50aGVuKCgpID0+IHsKICAgIHJldHVybiBwYXlsb2FkOwogIH0pOwp9CnZhciAkWm9kT2JqZWN0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZE9iamVjdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZGVmLCAic2hhcGUiKTsKICBpZiAoIWRlc2M/LmdldCkgewogICAgY29uc3Qgc2ggPSBkZWYuc2hhcGU7CiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZGVmLCAic2hhcGUiLCB7CiAgICAgIGdldDogKCkgPT4gewogICAgICAgIGNvbnN0IG5ld1NoID0geyAuLi5zaCB9OwogICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShkZWYsICJzaGFwZSIsIHsKICAgICAgICAgIHZhbHVlOiBuZXdTaAogICAgICAgIH0pOwogICAgICAgIHJldHVybiBuZXdTaDsKICAgICAgfQogICAgfSk7CiAgfQogIGNvbnN0IF9ub3JtYWxpemVkID0gY2FjaGVkKCgpID0+IG5vcm1hbGl6ZURlZihkZWYpKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInByb3BWYWx1ZXMiLCAoKSA9PiB7CiAgICBjb25zdCBzaGFwZSA9IGRlZi5zaGFwZTsKICAgIGNvbnN0IHByb3BWYWx1ZXMgPSB7fTsKICAgIGZvciAoY29uc3Qga2V5IGluIHNoYXBlKSB7CiAgICAgIGNvbnN0IGZpZWxkID0gc2hhcGVba2V5XS5fem9kOwogICAgICBpZiAoZmllbGQudmFsdWVzKSB7CiAgICAgICAgcHJvcFZhbHVlc1trZXldID8/IChwcm9wVmFsdWVzW2tleV0gPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgICAgICBmb3IgKGNvbnN0IHYgb2YgZmllbGQudmFsdWVzKQogICAgICAgICAgcHJvcFZhbHVlc1trZXldLmFkZCh2KTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHByb3BWYWx1ZXM7CiAgfSk7CiAgY29uc3QgaXNPYmplY3QyID0gaXNPYmplY3Q7CiAgY29uc3QgY2F0Y2hhbGwgPSBkZWYuY2F0Y2hhbGw7CiAgbGV0IHZhbHVlOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIHZhbHVlID8/ICh2YWx1ZSA9IF9ub3JtYWxpemVkLnZhbHVlKTsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghaXNPYmplY3QyKGlucHV0KSkgewogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBleHBlY3RlZDogIm9iamVjdCIsCiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgaW5wdXQsCiAgICAgICAgaW5zdAogICAgICB9KTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBwYXlsb2FkLnZhbHVlID0ge307CiAgICBjb25zdCBwcm9tcyA9IFtdOwogICAgY29uc3Qgc2hhcGUgPSB2YWx1ZS5zaGFwZTsKICAgIGZvciAoY29uc3Qga2V5IG9mIHZhbHVlLmtleXMpIHsKICAgICAgY29uc3QgZWwgPSBzaGFwZVtrZXldOwogICAgICBjb25zdCBpc09wdGlvbmFsSW4gPSBlbC5fem9kLm9wdGluID09PSAib3B0aW9uYWwiOwogICAgICBjb25zdCBpc09wdGlvbmFsT3V0ID0gZWwuX3pvZC5vcHRvdXQgPT09ICJvcHRpb25hbCI7CiAgICAgIGNvbnN0IHIgPSBlbC5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dFtrZXldLCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgIGlmIChyIGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgIHByb21zLnB1c2goci50aGVuKChyMikgPT4gaGFuZGxlUHJvcGVydHlSZXN1bHQocjIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkpKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBoYW5kbGVQcm9wZXJ0eVJlc3VsdChyLCBwYXlsb2FkLCBrZXksIGlucHV0LCBpc09wdGlvbmFsSW4sIGlzT3B0aW9uYWxPdXQpOwogICAgICB9CiAgICB9CiAgICBpZiAoIWNhdGNoYWxsKSB7CiAgICAgIHJldHVybiBwcm9tcy5sZW5ndGggPyBQcm9taXNlLmFsbChwcm9tcykudGhlbigoKSA9PiBwYXlsb2FkKSA6IHBheWxvYWQ7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlQ2F0Y2hhbGwocHJvbXMsIGlucHV0LCBwYXlsb2FkLCBjdHgsIF9ub3JtYWxpemVkLnZhbHVlLCBpbnN0KTsKICB9Owp9KTsKdmFyICRab2RPYmplY3RKSVQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kT2JqZWN0SklUIiwgKGluc3QsIGRlZikgPT4gewogICRab2RPYmplY3QuaW5pdChpbnN0LCBkZWYpOwogIGNvbnN0IHN1cGVyUGFyc2UgPSBpbnN0Ll96b2QucGFyc2U7CiAgY29uc3QgX25vcm1hbGl6ZWQgPSBjYWNoZWQoKCkgPT4gbm9ybWFsaXplRGVmKGRlZikpOwogIGNvbnN0IGdlbmVyYXRlRmFzdHBhc3MgPSAoc2hhcGUpID0+IHsKICAgIGNvbnN0IGRvYyA9IG5ldyBEb2MoWyJzaGFwZSIsICJwYXlsb2FkIiwgImN0eCJdKTsKICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBfbm9ybWFsaXplZC52YWx1ZTsKICAgIGNvbnN0IHBhcnNlU3RyID0gKGtleSkgPT4gewogICAgICBjb25zdCBrID0gZXNjKGtleSk7CiAgICAgIHJldHVybiBgc2hhcGVbJHtrfV0uX3pvZC5ydW4oeyB2YWx1ZTogaW5wdXRbJHtrfV0sIGlzc3VlczogW10gfSwgY3R4KWA7CiAgICB9OwogICAgZG9jLndyaXRlKGBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7YCk7CiAgICBjb25zdCBpZHMgPSAvKiBAX19QVVJFX18gKi8gT2JqZWN0LmNyZWF0ZShudWxsKTsKICAgIGxldCBjb3VudGVyID0gMDsKICAgIGZvciAoY29uc3Qga2V5IG9mIG5vcm1hbGl6ZWQua2V5cykgewogICAgICBpZHNba2V5XSA9IGBrZXlfJHtjb3VudGVyKyt9YDsKICAgIH0KICAgIGRvYy53cml0ZShgY29uc3QgbmV3UmVzdWx0ID0ge307YCk7CiAgICBmb3IgKGNvbnN0IGtleSBvZiBub3JtYWxpemVkLmtleXMpIHsKICAgICAgY29uc3QgaWQgPSBpZHNba2V5XTsKICAgICAgY29uc3QgayA9IGVzYyhrZXkpOwogICAgICBjb25zdCBzY2hlbWEgPSBzaGFwZVtrZXldOwogICAgICBjb25zdCBpc09wdGlvbmFsSW4gPSBzY2hlbWE/Ll96b2Q/Lm9wdGluID09PSAib3B0aW9uYWwiOwogICAgICBjb25zdCBpc09wdGlvbmFsT3V0ID0gc2NoZW1hPy5fem9kPy5vcHRvdXQgPT09ICJvcHRpb25hbCI7CiAgICAgIGRvYy53cml0ZShgY29uc3QgJHtpZH0gPSAke3BhcnNlU3RyKGtleSl9O2ApOwogICAgICBpZiAoaXNPcHRpb25hbEluICYmIGlzT3B0aW9uYWxPdXQpIHsKICAgICAgICBkb2Mud3JpdGUoYAogICAgICAgIGlmICgke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBpZiAoJHtrfSBpbiBpbnB1dCkgewogICAgICAgICAgICBwYXlsb2FkLmlzc3VlcyA9IHBheWxvYWQuaXNzdWVzLmNvbmNhdCgke2lkfS5pc3N1ZXMubWFwKGlzcyA9PiAoewogICAgICAgICAgICAgIC4uLmlzcywKICAgICAgICAgICAgICBwYXRoOiBpc3MucGF0aCA/IFske2t9LCAuLi5pc3MucGF0aF0gOiBbJHtrfV0KICAgICAgICAgICAgfSkpKTsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmICgke2lkfS52YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICBpZiAoJHtrfSBpbiBpbnB1dCkgewogICAgICAgICAgICBuZXdSZXN1bHRbJHtrfV0gPSB1bmRlZmluZWQ7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9ICR7aWR9LnZhbHVlOwogICAgICAgIH0KCiAgICAgIGApOwogICAgICB9IGVsc2UgaWYgKCFpc09wdGlvbmFsSW4pIHsKICAgICAgICBkb2Mud3JpdGUoYAogICAgICAgIGNvbnN0ICR7aWR9X3ByZXNlbnQgPSAke2t9IGluIGlucHV0OwogICAgICAgIGlmICgke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3VlcyA9IHBheWxvYWQuaXNzdWVzLmNvbmNhdCgke2lkfS5pc3N1ZXMubWFwKGlzcyA9PiAoewogICAgICAgICAgICAuLi5pc3MsCiAgICAgICAgICAgIHBhdGg6IGlzcy5wYXRoID8gWyR7a30sIC4uLmlzcy5wYXRoXSA6IFske2t9XQogICAgICAgICAgfSkpKTsKICAgICAgICB9CiAgICAgICAgaWYgKCEke2lkfV9wcmVzZW50ICYmICEke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgICAgIGV4cGVjdGVkOiAibm9ub3B0aW9uYWwiLAogICAgICAgICAgICBpbnB1dDogdW5kZWZpbmVkLAogICAgICAgICAgICBwYXRoOiBbJHtrfV0KICAgICAgICAgIH0pOwogICAgICAgIH0KCiAgICAgICAgaWYgKCR7aWR9X3ByZXNlbnQpIHsKICAgICAgICAgIGlmICgke2lkfS52YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9IHVuZGVmaW5lZDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9ICR7aWR9LnZhbHVlOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgIGApOwogICAgICB9IGVsc2UgewogICAgICAgIGRvYy53cml0ZShgCiAgICAgICAgaWYgKCR7aWR9Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzID0gcGF5bG9hZC5pc3N1ZXMuY29uY2F0KCR7aWR9Lmlzc3Vlcy5tYXAoaXNzID0+ICh7CiAgICAgICAgICAgIC4uLmlzcywKICAgICAgICAgICAgcGF0aDogaXNzLnBhdGggPyBbJHtrfSwgLi4uaXNzLnBhdGhdIDogWyR7a31dCiAgICAgICAgICB9KSkpOwogICAgICAgIH0KCiAgICAgICAgaWYgKCR7aWR9LnZhbHVlID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgIGlmICgke2t9IGluIGlucHV0KSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9IHVuZGVmaW5lZDsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgbmV3UmVzdWx0WyR7a31dID0gJHtpZH0udmFsdWU7CiAgICAgICAgfQoKICAgICAgYCk7CiAgICAgIH0KICAgIH0KICAgIGRvYy53cml0ZShgcGF5bG9hZC52YWx1ZSA9IG5ld1Jlc3VsdDtgKTsKICAgIGRvYy53cml0ZShgcmV0dXJuIHBheWxvYWQ7YCk7CiAgICBjb25zdCBmbiA9IGRvYy5jb21waWxlKCk7CiAgICByZXR1cm4gKHBheWxvYWQsIGN0eCkgPT4gZm4oc2hhcGUsIHBheWxvYWQsIGN0eCk7CiAgfTsKICBsZXQgZmFzdHBhc3M7CiAgY29uc3QgaXNPYmplY3QyID0gaXNPYmplY3Q7CiAgY29uc3Qgaml0ID0gIWdsb2JhbENvbmZpZy5qaXRsZXNzOwogIGNvbnN0IGFsbG93c0V2YWwyID0gYWxsb3dzRXZhbDsKICBjb25zdCBmYXN0RW5hYmxlZCA9IGppdCAmJiBhbGxvd3NFdmFsMi52YWx1ZTsKICBjb25zdCBjYXRjaGFsbCA9IGRlZi5jYXRjaGFsbDsKICBsZXQgdmFsdWU7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgdmFsdWUgPz8gKHZhbHVlID0gX25vcm1hbGl6ZWQudmFsdWUpOwogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKCFpc09iamVjdDIoaW5wdXQpKSB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIGV4cGVjdGVkOiAib2JqZWN0IiwKICAgICAgICBjb2RlOiAiaW52YWxpZF90eXBlIiwKICAgICAgICBpbnB1dCwKICAgICAgICBpbnN0CiAgICAgIH0pOwogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH0KICAgIGlmIChqaXQgJiYgZmFzdEVuYWJsZWQgJiYgY3R4Py5hc3luYyA9PT0gZmFsc2UgJiYgY3R4LmppdGxlc3MgIT09IHRydWUpIHsKICAgICAgaWYgKCFmYXN0cGFzcykKICAgICAgICBmYXN0cGFzcyA9IGdlbmVyYXRlRmFzdHBhc3MoZGVmLnNoYXBlKTsKICAgICAgcGF5bG9hZCA9IGZhc3RwYXNzKHBheWxvYWQsIGN0eCk7CiAgICAgIGlmICghY2F0Y2hhbGwpCiAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgIHJldHVybiBoYW5kbGVDYXRjaGFsbChbXSwgaW5wdXQsIHBheWxvYWQsIGN0eCwgdmFsdWUsIGluc3QpOwogICAgfQogICAgcmV0dXJuIHN1cGVyUGFyc2UocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlVW5pb25SZXN1bHRzKHJlc3VsdHMsIGZpbmFsLCBpbnN0LCBjdHgpIHsKICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7CiAgICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGggPT09IDApIHsKICAgICAgZmluYWwudmFsdWUgPSByZXN1bHQudmFsdWU7CiAgICAgIHJldHVybiBmaW5hbDsKICAgIH0KICB9CiAgY29uc3Qgbm9uYWJvcnRlZCA9IHJlc3VsdHMuZmlsdGVyKChyKSA9PiAhYWJvcnRlZChyKSk7CiAgaWYgKG5vbmFib3J0ZWQubGVuZ3RoID09PSAxKSB7CiAgICBmaW5hbC52YWx1ZSA9IG5vbmFib3J0ZWRbMF0udmFsdWU7CiAgICByZXR1cm4gbm9uYWJvcnRlZFswXTsKICB9CiAgZmluYWwuaXNzdWVzLnB1c2goewogICAgY29kZTogImludmFsaWRfdW5pb24iLAogICAgaW5wdXQ6IGZpbmFsLnZhbHVlLAogICAgaW5zdCwKICAgIGVycm9yczogcmVzdWx0cy5tYXAoKHJlc3VsdCkgPT4gcmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSkKICB9KTsKICByZXR1cm4gZmluYWw7Cn0KdmFyICRab2RVbmlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RVbmlvbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5vcHRpb25zLnNvbWUoKG8pID0+IG8uX3pvZC5vcHRpbiA9PT0gIm9wdGlvbmFsIikgPyAib3B0aW9uYWwiIDogdm9pZCAwKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdG91dCIsICgpID0+IGRlZi5vcHRpb25zLnNvbWUoKG8pID0+IG8uX3pvZC5vcHRvdXQgPT09ICJvcHRpb25hbCIpID8gIm9wdGlvbmFsIiA6IHZvaWQgMCk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiB7CiAgICBpZiAoZGVmLm9wdGlvbnMuZXZlcnkoKG8pID0+IG8uX3pvZC52YWx1ZXMpKSB7CiAgICAgIHJldHVybiBuZXcgU2V0KGRlZi5vcHRpb25zLmZsYXRNYXAoKG9wdGlvbikgPT4gQXJyYXkuZnJvbShvcHRpb24uX3pvZC52YWx1ZXMpKSk7CiAgICB9CiAgICByZXR1cm4gdm9pZCAwOwogIH0pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicGF0dGVybiIsICgpID0+IHsKICAgIGlmIChkZWYub3B0aW9ucy5ldmVyeSgobykgPT4gby5fem9kLnBhdHRlcm4pKSB7CiAgICAgIGNvbnN0IHBhdHRlcm5zID0gZGVmLm9wdGlvbnMubWFwKChvKSA9PiBvLl96b2QucGF0dGVybik7CiAgICAgIHJldHVybiBuZXcgUmVnRXhwKGBeKCR7cGF0dGVybnMubWFwKChwKSA9PiBjbGVhblJlZ2V4KHAuc291cmNlKSkuam9pbigifCIpfSkkYCk7CiAgICB9CiAgICByZXR1cm4gdm9pZCAwOwogIH0pOwogIGNvbnN0IGZpcnN0ID0gZGVmLm9wdGlvbnMubGVuZ3RoID09PSAxID8gZGVmLm9wdGlvbnNbMF0uX3pvZC5ydW4gOiBudWxsOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChmaXJzdCkgewogICAgICByZXR1cm4gZmlyc3QocGF5bG9hZCwgY3R4KTsKICAgIH0KICAgIGxldCBhc3luYyA9IGZhbHNlOwogICAgY29uc3QgcmVzdWx0cyA9IFtdOwogICAgZm9yIChjb25zdCBvcHRpb24gb2YgZGVmLm9wdGlvbnMpIHsKICAgICAgY29uc3QgcmVzdWx0ID0gb3B0aW9uLl96b2QucnVuKHsKICAgICAgICB2YWx1ZTogcGF5bG9hZC52YWx1ZSwKICAgICAgICBpc3N1ZXM6IFtdCiAgICAgIH0sIGN0eCk7CiAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7CiAgICAgICAgYXN5bmMgPSB0cnVlOwogICAgICB9IGVsc2UgewogICAgICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCA9PT0gMCkKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7CiAgICAgIH0KICAgIH0KICAgIGlmICghYXN5bmMpCiAgICAgIHJldHVybiBoYW5kbGVVbmlvblJlc3VsdHMocmVzdWx0cywgcGF5bG9hZCwgaW5zdCwgY3R4KTsKICAgIHJldHVybiBQcm9taXNlLmFsbChyZXN1bHRzKS50aGVuKChyZXN1bHRzMikgPT4gewogICAgICByZXR1cm4gaGFuZGxlVW5pb25SZXN1bHRzKHJlc3VsdHMyLCBwYXlsb2FkLCBpbnN0LCBjdHgpOwogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kSW50ZXJzZWN0aW9uID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEludGVyc2VjdGlvbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgY29uc3QgbGVmdCA9IGRlZi5sZWZ0Ll96b2QucnVuKHsgdmFsdWU6IGlucHV0LCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICBjb25zdCByaWdodCA9IGRlZi5yaWdodC5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dCwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgY29uc3QgYXN5bmMgPSBsZWZ0IGluc3RhbmNlb2YgUHJvbWlzZSB8fCByaWdodCBpbnN0YW5jZW9mIFByb21pc2U7CiAgICBpZiAoYXN5bmMpIHsKICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsZWZ0LCByaWdodF0pLnRoZW4oKFtsZWZ0MiwgcmlnaHQyXSkgPT4gewogICAgICAgIHJldHVybiBoYW5kbGVJbnRlcnNlY3Rpb25SZXN1bHRzKHBheWxvYWQsIGxlZnQyLCByaWdodDIpOwogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBoYW5kbGVJbnRlcnNlY3Rpb25SZXN1bHRzKHBheWxvYWQsIGxlZnQsIHJpZ2h0KTsKICB9Owp9KTsKZnVuY3Rpb24gbWVyZ2VWYWx1ZXMoYSwgYikgewogIGlmIChhID09PSBiKSB7CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogYSB9OwogIH0KICBpZiAoYSBpbnN0YW5jZW9mIERhdGUgJiYgYiBpbnN0YW5jZW9mIERhdGUgJiYgK2EgPT09ICtiKSB7CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogYSB9OwogIH0KICBpZiAoaXNQbGFpbk9iamVjdChhKSAmJiBpc1BsYWluT2JqZWN0KGIpKSB7CiAgICBjb25zdCBiS2V5cyA9IE9iamVjdC5rZXlzKGIpOwogICAgY29uc3Qgc2hhcmVkS2V5cyA9IE9iamVjdC5rZXlzKGEpLmZpbHRlcigoa2V5KSA9PiBiS2V5cy5pbmRleE9mKGtleSkgIT09IC0xKTsKICAgIGNvbnN0IG5ld09iaiA9IHsgLi4uYSwgLi4uYiB9OwogICAgZm9yIChjb25zdCBrZXkgb2Ygc2hhcmVkS2V5cykgewogICAgICBjb25zdCBzaGFyZWRWYWx1ZSA9IG1lcmdlVmFsdWVzKGFba2V5XSwgYltrZXldKTsKICAgICAgaWYgKCFzaGFyZWRWYWx1ZS52YWxpZCkgewogICAgICAgIHJldHVybiB7CiAgICAgICAgICB2YWxpZDogZmFsc2UsCiAgICAgICAgICBtZXJnZUVycm9yUGF0aDogW2tleSwgLi4uc2hhcmVkVmFsdWUubWVyZ2VFcnJvclBhdGhdCiAgICAgICAgfTsKICAgICAgfQogICAgICBuZXdPYmpba2V5XSA9IHNoYXJlZFZhbHVlLmRhdGE7CiAgICB9CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogbmV3T2JqIH07CiAgfQogIGlmIChBcnJheS5pc0FycmF5KGEpICYmIEFycmF5LmlzQXJyYXkoYikpIHsKICAgIGlmIChhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHsKICAgICAgcmV0dXJuIHsgdmFsaWQ6IGZhbHNlLCBtZXJnZUVycm9yUGF0aDogW10gfTsKICAgIH0KICAgIGNvbnN0IG5ld0FycmF5ID0gW107CiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgYS5sZW5ndGg7IGluZGV4KyspIHsKICAgICAgY29uc3QgaXRlbUEgPSBhW2luZGV4XTsKICAgICAgY29uc3QgaXRlbUIgPSBiW2luZGV4XTsKICAgICAgY29uc3Qgc2hhcmVkVmFsdWUgPSBtZXJnZVZhbHVlcyhpdGVtQSwgaXRlbUIpOwogICAgICBpZiAoIXNoYXJlZFZhbHVlLnZhbGlkKSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIHZhbGlkOiBmYWxzZSwKICAgICAgICAgIG1lcmdlRXJyb3JQYXRoOiBbaW5kZXgsIC4uLnNoYXJlZFZhbHVlLm1lcmdlRXJyb3JQYXRoXQogICAgICAgIH07CiAgICAgIH0KICAgICAgbmV3QXJyYXkucHVzaChzaGFyZWRWYWx1ZS5kYXRhKTsKICAgIH0KICAgIHJldHVybiB7IHZhbGlkOiB0cnVlLCBkYXRhOiBuZXdBcnJheSB9OwogIH0KICByZXR1cm4geyB2YWxpZDogZmFsc2UsIG1lcmdlRXJyb3JQYXRoOiBbXSB9Owp9CmZ1bmN0aW9uIGhhbmRsZUludGVyc2VjdGlvblJlc3VsdHMocmVzdWx0LCBsZWZ0LCByaWdodCkgewogIGNvbnN0IHVucmVjS2V5cyA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgTWFwKCk7CiAgbGV0IHVucmVjSXNzdWU7CiAgZm9yIChjb25zdCBpc3Mgb2YgbGVmdC5pc3N1ZXMpIHsKICAgIGlmIChpc3MuY29kZSA9PT0gInVucmVjb2duaXplZF9rZXlzIikgewogICAgICB1bnJlY0lzc3VlID8/ICh1bnJlY0lzc3VlID0gaXNzKTsKICAgICAgZm9yIChjb25zdCBrIG9mIGlzcy5rZXlzKSB7CiAgICAgICAgaWYgKCF1bnJlY0tleXMuaGFzKGspKQogICAgICAgICAgdW5yZWNLZXlzLnNldChrLCB7fSk7CiAgICAgICAgdW5yZWNLZXlzLmdldChrKS5sID0gdHJ1ZTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcmVzdWx0Lmlzc3Vlcy5wdXNoKGlzcyk7CiAgICB9CiAgfQogIGZvciAoY29uc3QgaXNzIG9mIHJpZ2h0Lmlzc3VlcykgewogICAgaWYgKGlzcy5jb2RlID09PSAidW5yZWNvZ25pemVkX2tleXMiKSB7CiAgICAgIGZvciAoY29uc3QgayBvZiBpc3Mua2V5cykgewogICAgICAgIGlmICghdW5yZWNLZXlzLmhhcyhrKSkKICAgICAgICAgIHVucmVjS2V5cy5zZXQoaywge30pOwogICAgICAgIHVucmVjS2V5cy5nZXQoaykuciA9IHRydWU7CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIHJlc3VsdC5pc3N1ZXMucHVzaChpc3MpOwogICAgfQogIH0KICBjb25zdCBib3RoS2V5cyA9IFsuLi51bnJlY0tleXNdLmZpbHRlcigoWywgZl0pID0+IGYubCAmJiBmLnIpLm1hcCgoW2tdKSA9PiBrKTsKICBpZiAoYm90aEtleXMubGVuZ3RoICYmIHVucmVjSXNzdWUpIHsKICAgIHJlc3VsdC5pc3N1ZXMucHVzaCh7IC4uLnVucmVjSXNzdWUsIGtleXM6IGJvdGhLZXlzIH0pOwogIH0KICBpZiAoYWJvcnRlZChyZXN1bHQpKQogICAgcmV0dXJuIHJlc3VsdDsKICBjb25zdCBtZXJnZWQgPSBtZXJnZVZhbHVlcyhsZWZ0LnZhbHVlLCByaWdodC52YWx1ZSk7CiAgaWYgKCFtZXJnZWQudmFsaWQpIHsKICAgIHRocm93IG5ldyBFcnJvcihgVW5tZXJnYWJsZSBpbnRlcnNlY3Rpb24uIEVycm9yIHBhdGg6ICR7SlNPTi5zdHJpbmdpZnkobWVyZ2VkLm1lcmdlRXJyb3JQYXRoKX1gKTsKICB9CiAgcmVzdWx0LnZhbHVlID0gbWVyZ2VkLmRhdGE7CiAgcmV0dXJuIHJlc3VsdDsKfQp2YXIgJFpvZFJlY29yZCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RSZWNvcmQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghaXNQbGFpbk9iamVjdChpbnB1dCkpIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgZXhwZWN0ZWQ6ICJyZWNvcmQiLAogICAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICAgIGlucHV0LAogICAgICAgIGluc3QKICAgICAgfSk7CiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgfQogICAgY29uc3QgcHJvbXMgPSBbXTsKICAgIGNvbnN0IHZhbHVlcyA9IGRlZi5rZXlUeXBlLl96b2QudmFsdWVzOwogICAgaWYgKHZhbHVlcykgewogICAgICBwYXlsb2FkLnZhbHVlID0ge307CiAgICAgIGNvbnN0IHJlY29yZEtleXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpOwogICAgICBmb3IgKGNvbnN0IGtleSBvZiB2YWx1ZXMpIHsKICAgICAgICBpZiAodHlwZW9mIGtleSA9PT0gInN0cmluZyIgfHwgdHlwZW9mIGtleSA9PT0gIm51bWJlciIgfHwgdHlwZW9mIGtleSA9PT0gInN5bWJvbCIpIHsKICAgICAgICAgIHJlY29yZEtleXMuYWRkKHR5cGVvZiBrZXkgPT09ICJudW1iZXIiID8ga2V5LnRvU3RyaW5nKCkgOiBrZXkpOwogICAgICAgICAgY29uc3Qga2V5UmVzdWx0ID0gZGVmLmtleVR5cGUuX3pvZC5ydW4oeyB2YWx1ZToga2V5LCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgICAgICBpZiAoa2V5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFzeW5jIHNjaGVtYXMgbm90IHN1cHBvcnRlZCBpbiBvYmplY3Qga2V5cyBjdXJyZW50bHkiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChrZXlSZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgICBjb2RlOiAiaW52YWxpZF9rZXkiLAogICAgICAgICAgICAgIG9yaWdpbjogInJlY29yZCIsCiAgICAgICAgICAgICAgaXNzdWVzOiBrZXlSZXN1bHQuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpLAogICAgICAgICAgICAgIGlucHV0OiBrZXksCiAgICAgICAgICAgICAgcGF0aDogW2tleV0sCiAgICAgICAgICAgICAgaW5zdAogICAgICAgICAgICB9KTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBvdXRLZXkgPSBrZXlSZXN1bHQudmFsdWU7CiAgICAgICAgICBjb25zdCByZXN1bHQgPSBkZWYudmFsdWVUeXBlLl96b2QucnVuKHsgdmFsdWU6IGlucHV0W2tleV0sIGlzc3VlczogW10gfSwgY3R4KTsKICAgICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgICAgIHByb21zLnB1c2gocmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IHsKICAgICAgICAgICAgICBpZiAocmVzdWx0Mi5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKC4uLnByZWZpeElzc3VlcyhrZXksIHJlc3VsdDIuaXNzdWVzKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHBheWxvYWQudmFsdWVbb3V0S2V5XSA9IHJlc3VsdDIudmFsdWU7CiAgICAgICAgICAgIH0pKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goLi4ucHJlZml4SXNzdWVzKGtleSwgcmVzdWx0Lmlzc3VlcykpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBheWxvYWQudmFsdWVbb3V0S2V5XSA9IHJlc3VsdC52YWx1ZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgbGV0IHVucmVjb2duaXplZDsKICAgICAgZm9yIChjb25zdCBrZXkgaW4gaW5wdXQpIHsKICAgICAgICBpZiAoIXJlY29yZEtleXMuaGFzKGtleSkpIHsKICAgICAgICAgIHVucmVjb2duaXplZCA9IHVucmVjb2duaXplZCA/PyBbXTsKICAgICAgICAgIHVucmVjb2duaXplZC5wdXNoKGtleSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmICh1bnJlY29nbml6ZWQgJiYgdW5yZWNvZ25pemVkLmxlbmd0aCA+IDApIHsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgIGNvZGU6ICJ1bnJlY29nbml6ZWRfa2V5cyIsCiAgICAgICAgICBpbnB1dCwKICAgICAgICAgIGluc3QsCiAgICAgICAgICBrZXlzOiB1bnJlY29nbml6ZWQKICAgICAgICB9KTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcGF5bG9hZC52YWx1ZSA9IHt9OwogICAgICBmb3IgKGNvbnN0IGtleSBvZiBSZWZsZWN0Lm93bktleXMoaW5wdXQpKSB7CiAgICAgICAgaWYgKGtleSA9PT0gIl9fcHJvdG9fXyIpCiAgICAgICAgICBjb250aW51ZTsKICAgICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChpbnB1dCwga2V5KSkKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIGxldCBrZXlSZXN1bHQgPSBkZWYua2V5VHlwZS5fem9kLnJ1bih7IHZhbHVlOiBrZXksIGlzc3VlczogW10gfSwgY3R4KTsKICAgICAgICBpZiAoa2V5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJBc3luYyBzY2hlbWFzIG5vdCBzdXBwb3J0ZWQgaW4gb2JqZWN0IGtleXMgY3VycmVudGx5Iik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGNoZWNrTnVtZXJpY0tleSA9IHR5cGVvZiBrZXkgPT09ICJzdHJpbmciICYmIG51bWJlci50ZXN0KGtleSkgJiYga2V5UmVzdWx0Lmlzc3Vlcy5sZW5ndGg7CiAgICAgICAgaWYgKGNoZWNrTnVtZXJpY0tleSkgewogICAgICAgICAgY29uc3QgcmV0cnlSZXN1bHQgPSBkZWYua2V5VHlwZS5fem9kLnJ1bih7IHZhbHVlOiBOdW1iZXIoa2V5KSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgICAgICAgaWYgKHJldHJ5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFzeW5jIHNjaGVtYXMgbm90IHN1cHBvcnRlZCBpbiBvYmplY3Qga2V5cyBjdXJyZW50bHkiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZXRyeVJlc3VsdC5pc3N1ZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIGtleVJlc3VsdCA9IHJldHJ5UmVzdWx0OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoa2V5UmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgIGlmIChkZWYubW9kZSA9PT0gImxvb3NlIikgewogICAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleV0gPSBpbnB1dFtrZXldOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgICAgICAgY29kZTogImludmFsaWRfa2V5IiwKICAgICAgICAgICAgICBvcmlnaW46ICJyZWNvcmQiLAogICAgICAgICAgICAgIGlzc3Vlczoga2V5UmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSwKICAgICAgICAgICAgICBpbnB1dDoga2V5LAogICAgICAgICAgICAgIHBhdGg6IFtrZXldLAogICAgICAgICAgICAgIGluc3QKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcmVzdWx0ID0gZGVmLnZhbHVlVHlwZS5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dFtrZXldLCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICAgIHByb21zLnB1c2gocmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IHsKICAgICAgICAgICAgaWYgKHJlc3VsdDIuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goLi4ucHJlZml4SXNzdWVzKGtleSwgcmVzdWx0Mi5pc3N1ZXMpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleVJlc3VsdC52YWx1ZV0gPSByZXN1bHQyLnZhbHVlOwogICAgICAgICAgfSkpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCguLi5wcmVmaXhJc3N1ZXMoa2V5LCByZXN1bHQuaXNzdWVzKSk7CiAgICAgICAgICB9CiAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleVJlc3VsdC52YWx1ZV0gPSByZXN1bHQudmFsdWU7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZiAocHJvbXMubGVuZ3RoKSB7CiAgICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9tcykudGhlbigoKSA9PiBwYXlsb2FkKTsKICAgIH0KICAgIHJldHVybiBwYXlsb2FkOwogIH07Cn0pOwp2YXIgJFpvZEVudW0gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kRW51bSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgdmFsdWVzID0gZ2V0RW51bVZhbHVlcyhkZWYuZW50cmllcyk7CiAgY29uc3QgdmFsdWVzU2V0ID0gbmV3IFNldCh2YWx1ZXMpOwogIGluc3QuX3pvZC52YWx1ZXMgPSB2YWx1ZXNTZXQ7CiAgaW5zdC5fem9kLnBhdHRlcm4gPSBuZXcgUmVnRXhwKGBeKCR7dmFsdWVzLmZpbHRlcigoaykgPT4gcHJvcGVydHlLZXlUeXBlcy5oYXModHlwZW9mIGspKS5tYXAoKG8pID0+IHR5cGVvZiBvID09PSAic3RyaW5nIiA/IGVzY2FwZVJlZ2V4KG8pIDogby50b1N0cmluZygpKS5qb2luKCJ8Iil9KSRgKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKHZhbHVlc1NldC5oYXMoaW5wdXQpKSB7CiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgfQogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGNvZGU6ICJpbnZhbGlkX3ZhbHVlIiwKICAgICAgdmFsdWVzLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfSk7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKdmFyICRab2RUcmFuc2Zvcm0gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVHJhbnNmb3JtIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2Qub3B0aW4gPSAib3B0aW9uYWwiOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChjdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgIHRocm93IG5ldyAkWm9kRW5jb2RlRXJyb3IoaW5zdC5jb25zdHJ1Y3Rvci5uYW1lKTsKICAgIH0KICAgIGNvbnN0IF9vdXQgPSBkZWYudHJhbnNmb3JtKHBheWxvYWQudmFsdWUsIHBheWxvYWQpOwogICAgaWYgKGN0eC5hc3luYykgewogICAgICBjb25zdCBvdXRwdXQgPSBfb3V0IGluc3RhbmNlb2YgUHJvbWlzZSA/IF9vdXQgOiBQcm9taXNlLnJlc29sdmUoX291dCk7CiAgICAgIHJldHVybiBvdXRwdXQudGhlbigob3V0cHV0MikgPT4gewogICAgICAgIHBheWxvYWQudmFsdWUgPSBvdXRwdXQyOwogICAgICAgIHBheWxvYWQuZmFsbGJhY2sgPSB0cnVlOwogICAgICAgIHJldHVybiBwYXlsb2FkOwogICAgICB9KTsKICAgIH0KICAgIGlmIChfb3V0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICAgIH0KICAgIHBheWxvYWQudmFsdWUgPSBfb3V0OwogICAgcGF5bG9hZC5mYWxsYmFjayA9IHRydWU7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlT3B0aW9uYWxSZXN1bHQocmVzdWx0LCBpbnB1dCkgewogIGlmIChpbnB1dCA9PT0gdm9pZCAwICYmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCB8fCByZXN1bHQuZmFsbGJhY2spKSB7CiAgICByZXR1cm4geyBpc3N1ZXM6IFtdLCB2YWx1ZTogdm9pZCAwIH07CiAgfQogIHJldHVybiByZXN1bHQ7Cn0KdmFyICRab2RPcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RPcHRpb25hbCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLm9wdGluID0gIm9wdGlvbmFsIjsKICBpbnN0Ll96b2Qub3B0b3V0ID0gIm9wdGlvbmFsIjsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInZhbHVlcyIsICgpID0+IHsKICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzID8gLyogQF9fUFVSRV9fICovIG5ldyBTZXQoWy4uLmRlZi5pbm5lclR5cGUuX3pvZC52YWx1ZXMsIHZvaWQgMF0pIDogdm9pZCAwOwogIH0pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicGF0dGVybiIsICgpID0+IHsKICAgIGNvbnN0IHBhdHRlcm4gPSBkZWYuaW5uZXJUeXBlLl96b2QucGF0dGVybjsKICAgIHJldHVybiBwYXR0ZXJuID8gbmV3IFJlZ0V4cChgXigke2NsZWFuUmVnZXgocGF0dGVybi5zb3VyY2UpfSk/JGApIDogdm9pZCAwOwogIH0pOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChkZWYuaW5uZXJUeXBlLl96b2Qub3B0aW4gPT09ICJvcHRpb25hbCIpIHsKICAgICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgICBjb25zdCByZXN1bHQgPSBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKQogICAgICAgIHJldHVybiByZXN1bHQudGhlbigocikgPT4gaGFuZGxlT3B0aW9uYWxSZXN1bHQociwgaW5wdXQpKTsKICAgICAgcmV0dXJuIGhhbmRsZU9wdGlvbmFsUmVzdWx0KHJlc3VsdCwgaW5wdXQpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH0KICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgfTsKfSk7CnZhciAkWm9kRXhhY3RPcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RFeGFjdE9wdGlvbmFsIiwgKGluc3QsIGRlZikgPT4gewogICRab2RPcHRpb25hbC5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInBhdHRlcm4iLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QucGF0dGVybik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgcmV0dXJuIGRlZi5pbm5lclR5cGUuX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKdmFyICRab2ROdWxsYWJsZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2ROdWxsYWJsZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5pbm5lclR5cGUuX3pvZC5vcHRpbik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRvdXQiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2Qub3B0b3V0KTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInBhdHRlcm4iLCAoKSA9PiB7CiAgICBjb25zdCBwYXR0ZXJuID0gZGVmLmlubmVyVHlwZS5fem9kLnBhdHRlcm47CiAgICByZXR1cm4gcGF0dGVybiA/IG5ldyBSZWdFeHAoYF4oJHtjbGVhblJlZ2V4KHBhdHRlcm4uc291cmNlKX18bnVsbCkkYCkgOiB2b2lkIDA7CiAgfSk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiB7CiAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnZhbHVlcyA/IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KFsuLi5kZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzLCBudWxsXSkgOiB2b2lkIDA7CiAgfSk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IG51bGwpCiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgcmV0dXJuIGRlZi5pbm5lclR5cGUuX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKdmFyICRab2REZWZhdWx0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZERlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vcHRpbiA9ICJvcHRpb25hbCI7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmRlZmF1bHRWYWx1ZTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBjb25zdCByZXN1bHQgPSBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gcmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IGhhbmRsZURlZmF1bHRSZXN1bHQocmVzdWx0MiwgZGVmKSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlRGVmYXVsdFJlc3VsdChyZXN1bHQsIGRlZik7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZURlZmF1bHRSZXN1bHQocGF5bG9hZCwgZGVmKSB7CiAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgcGF5bG9hZC52YWx1ZSA9IGRlZi5kZWZhdWx0VmFsdWU7CiAgfQogIHJldHVybiBwYXlsb2FkOwp9CnZhciAkWm9kUHJlZmF1bHQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kUHJlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vcHRpbiA9ICJvcHRpb25hbCI7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmRlZmF1bHRWYWx1ZTsKICAgIH0KICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgfTsKfSk7CnZhciAkWm9kTm9uT3B0aW9uYWwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kTm9uT3B0aW9uYWwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAidmFsdWVzIiwgKCkgPT4gewogICAgY29uc3QgdiA9IGRlZi5pbm5lclR5cGUuX3pvZC52YWx1ZXM7CiAgICByZXR1cm4gdiA/IG5ldyBTZXQoWy4uLnZdLmZpbHRlcigoeCkgPT4geCAhPT0gdm9pZCAwKSkgOiB2b2lkIDA7CiAgfSk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiBoYW5kbGVOb25PcHRpb25hbFJlc3VsdChyZXN1bHQyLCBpbnN0KSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlTm9uT3B0aW9uYWxSZXN1bHQocmVzdWx0LCBpbnN0KTsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlTm9uT3B0aW9uYWxSZXN1bHQocGF5bG9hZCwgaW5zdCkgewogIGlmICghcGF5bG9hZC5pc3N1ZXMubGVuZ3RoICYmIHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICBleHBlY3RlZDogIm5vbm9wdGlvbmFsIiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QKICAgIH0pOwogIH0KICByZXR1cm4gcGF5bG9hZDsKfQp2YXIgJFpvZENhdGNoID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENhdGNoIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2Qub3B0aW4gPSAib3B0aW9uYWwiOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAib3B0b3V0IiwgKCkgPT4gZGVmLmlubmVyVHlwZS5fem9kLm9wdG91dCk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiB7CiAgICAgICAgcGF5bG9hZC52YWx1ZSA9IHJlc3VsdDIudmFsdWU7CiAgICAgICAgaWYgKHJlc3VsdDIuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgcGF5bG9hZC52YWx1ZSA9IGRlZi5jYXRjaFZhbHVlKHsKICAgICAgICAgICAgLi4ucGF5bG9hZCwKICAgICAgICAgICAgZXJyb3I6IHsKICAgICAgICAgICAgICBpc3N1ZXM6IHJlc3VsdDIuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlCiAgICAgICAgICB9KTsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzID0gW107CiAgICAgICAgICBwYXlsb2FkLmZhbGxiYWNrID0gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgIH0pOwogICAgfQogICAgcGF5bG9hZC52YWx1ZSA9IHJlc3VsdC52YWx1ZTsKICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmNhdGNoVmFsdWUoewogICAgICAgIC4uLnBheWxvYWQsCiAgICAgICAgZXJyb3I6IHsKICAgICAgICAgIGlzc3VlczogcmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKQogICAgICAgIH0sCiAgICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUKICAgICAgfSk7CiAgICAgIHBheWxvYWQuaXNzdWVzID0gW107CiAgICAgIHBheWxvYWQuZmFsbGJhY2sgPSB0cnVlOwogICAgfQogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CnZhciAkWm9kUGlwZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RQaXBlIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInZhbHVlcyIsICgpID0+IGRlZi5pbi5fem9kLnZhbHVlcyk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5pbi5fem9kLm9wdGluKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdG91dCIsICgpID0+IGRlZi5vdXQuX3pvZC5vcHRvdXQpOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicHJvcFZhbHVlcyIsICgpID0+IGRlZi5pbi5fem9kLnByb3BWYWx1ZXMpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChjdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgIGNvbnN0IHJpZ2h0ID0gZGVmLm91dC5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgICBpZiAocmlnaHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgcmV0dXJuIHJpZ2h0LnRoZW4oKHJpZ2h0MikgPT4gaGFuZGxlUGlwZVJlc3VsdChyaWdodDIsIGRlZi5pbiwgY3R4KSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGhhbmRsZVBpcGVSZXN1bHQocmlnaHQsIGRlZi5pbiwgY3R4KTsKICAgIH0KICAgIGNvbnN0IGxlZnQgPSBkZWYuaW4uX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICAgIGlmIChsZWZ0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gbGVmdC50aGVuKChsZWZ0MikgPT4gaGFuZGxlUGlwZVJlc3VsdChsZWZ0MiwgZGVmLm91dCwgY3R4KSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlUGlwZVJlc3VsdChsZWZ0LCBkZWYub3V0LCBjdHgpOwogIH07Cn0pOwpmdW5jdGlvbiBoYW5kbGVQaXBlUmVzdWx0KGxlZnQsIG5leHQsIGN0eCkgewogIGlmIChsZWZ0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgIGxlZnQuYWJvcnRlZCA9IHRydWU7CiAgICByZXR1cm4gbGVmdDsKICB9CiAgcmV0dXJuIG5leHQuX3pvZC5ydW4oeyB2YWx1ZTogbGVmdC52YWx1ZSwgaXNzdWVzOiBsZWZ0Lmlzc3VlcywgZmFsbGJhY2s6IGxlZnQuZmFsbGJhY2sgfSwgY3R4KTsKfQp2YXIgJFpvZFJlYWRvbmx5ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFJlYWRvbmx5IiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInByb3BWYWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QucHJvcFZhbHVlcyk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdGluIiwgKCkgPT4gZGVmLmlubmVyVHlwZT8uX3pvZD8ub3B0aW4pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAib3B0b3V0IiwgKCkgPT4gZGVmLmlubmVyVHlwZT8uX3pvZD8ub3B0b3V0KTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKGhhbmRsZVJlYWRvbmx5UmVzdWx0KTsKICAgIH0KICAgIHJldHVybiBoYW5kbGVSZWFkb25seVJlc3VsdChyZXN1bHQpOwogIH07Cn0pOwpmdW5jdGlvbiBoYW5kbGVSZWFkb25seVJlc3VsdChwYXlsb2FkKSB7CiAgcGF5bG9hZC52YWx1ZSA9IE9iamVjdC5mcmVlemUocGF5bG9hZC52YWx1ZSk7CiAgcmV0dXJuIHBheWxvYWQ7Cn0KdmFyICRab2RDdXN0b20gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ3VzdG9tIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBfKSA9PiB7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9OwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7CiAgICBjb25zdCByID0gZGVmLmZuKGlucHV0KTsKICAgIGlmIChyIGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gci50aGVuKChyMikgPT4gaGFuZGxlUmVmaW5lUmVzdWx0KHIyLCBwYXlsb2FkLCBpbnB1dCwgaW5zdCkpOwogICAgfQogICAgaGFuZGxlUmVmaW5lUmVzdWx0KHIsIHBheWxvYWQsIGlucHV0LCBpbnN0KTsKICAgIHJldHVybjsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlUmVmaW5lUmVzdWx0KHJlc3VsdCwgcGF5bG9hZCwgaW5wdXQsIGluc3QpIHsKICBpZiAoIXJlc3VsdCkgewogICAgY29uc3QgX2lzcyA9IHsKICAgICAgY29kZTogImN1c3RvbSIsCiAgICAgIGlucHV0LAogICAgICBpbnN0LAogICAgICAvLyBpbmNvcnBvcmF0ZXMgcGFyYW1zLmVycm9yIGludG8gaXNzdWUgcmVwb3J0aW5nCiAgICAgIHBhdGg6IFsuLi5pbnN0Ll96b2QuZGVmLnBhdGggPz8gW11dLAogICAgICAvLyBpbmNvcnBvcmF0ZXMgcGFyYW1zLmVycm9yIGludG8gaXNzdWUgcmVwb3J0aW5nCiAgICAgIGNvbnRpbnVlOiAhaW5zdC5fem9kLmRlZi5hYm9ydAogICAgICAvLyBwYXJhbXM6IGluc3QuX3pvZC5kZWYucGFyYW1zLAogICAgfTsKICAgIGlmIChpbnN0Ll96b2QuZGVmLnBhcmFtcykKICAgICAgX2lzcy5wYXJhbXMgPSBpbnN0Ll96b2QuZGVmLnBhcmFtczsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goaXNzdWUoX2lzcykpOwogIH0KfQoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL3JlZ2lzdHJpZXMuanMKdmFyIF9hMjsKdmFyICRab2RSZWdpc3RyeSA9IGNsYXNzIHsKICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMuX21hcCA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgV2Vha01hcCgpOwogICAgdGhpcy5faWRtYXAgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogIH0KICBhZGQoc2NoZW1hLCAuLi5fbWV0YSkgewogICAgY29uc3QgbWV0YTIgPSBfbWV0YVswXTsKICAgIHRoaXMuX21hcC5zZXQoc2NoZW1hLCBtZXRhMik7CiAgICBpZiAobWV0YTIgJiYgdHlwZW9mIG1ldGEyID09PSAib2JqZWN0IiAmJiAiaWQiIGluIG1ldGEyKSB7CiAgICAgIHRoaXMuX2lkbWFwLnNldChtZXRhMi5pZCwgc2NoZW1hKTsKICAgIH0KICAgIHJldHVybiB0aGlzOwogIH0KICBjbGVhcigpIHsKICAgIHRoaXMuX21hcCA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgV2Vha01hcCgpOwogICAgdGhpcy5faWRtYXAgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogICAgcmV0dXJuIHRoaXM7CiAgfQogIHJlbW92ZShzY2hlbWEpIHsKICAgIGNvbnN0IG1ldGEyID0gdGhpcy5fbWFwLmdldChzY2hlbWEpOwogICAgaWYgKG1ldGEyICYmIHR5cGVvZiBtZXRhMiA9PT0gIm9iamVjdCIgJiYgImlkIiBpbiBtZXRhMikgewogICAgICB0aGlzLl9pZG1hcC5kZWxldGUobWV0YTIuaWQpOwogICAgfQogICAgdGhpcy5fbWFwLmRlbGV0ZShzY2hlbWEpOwogICAgcmV0dXJuIHRoaXM7CiAgfQogIGdldChzY2hlbWEpIHsKICAgIGNvbnN0IHAgPSBzY2hlbWEuX3pvZC5wYXJlbnQ7CiAgICBpZiAocCkgewogICAgICBjb25zdCBwbSA9IHsgLi4udGhpcy5nZXQocCkgPz8ge30gfTsKICAgICAgZGVsZXRlIHBtLmlkOwogICAgICBjb25zdCBmID0geyAuLi5wbSwgLi4udGhpcy5fbWFwLmdldChzY2hlbWEpIH07CiAgICAgIHJldHVybiBPYmplY3Qua2V5cyhmKS5sZW5ndGggPyBmIDogdm9pZCAwOwogICAgfQogICAgcmV0dXJuIHRoaXMuX21hcC5nZXQoc2NoZW1hKTsKICB9CiAgaGFzKHNjaGVtYSkgewogICAgcmV0dXJuIHRoaXMuX21hcC5oYXMoc2NoZW1hKTsKICB9Cn07CmZ1bmN0aW9uIHJlZ2lzdHJ5KCkgewogIHJldHVybiBuZXcgJFpvZFJlZ2lzdHJ5KCk7Cn0KKF9hMiA9IGdsb2JhbFRoaXMpLl9fem9kX2dsb2JhbFJlZ2lzdHJ5ID8/IChfYTIuX196b2RfZ2xvYmFsUmVnaXN0cnkgPSByZWdpc3RyeSgpKTsKdmFyIGdsb2JhbFJlZ2lzdHJ5ID0gZ2xvYmFsVGhpcy5fX3pvZF9nbG9iYWxSZWdpc3RyeTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9hcGkuanMKLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3N0cmluZyhDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZW1haWwoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImVtYWlsIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9ndWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJndWlkIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ1dWlkIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjYoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NiIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjcoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NyIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91cmwoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInVybCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZW1vamkyKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJlbW9qaSIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbmFub2lkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJuYW5vaWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2N1aWQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImN1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2N1aWQyKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJjdWlkMiIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdWxpZChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAidWxpZCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfeGlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ4aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2tzdWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJrc3VpZCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfaXB2NChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiaXB2NCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfaXB2NihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiaXB2NiIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfY2lkcnY0KENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJjaWRydjQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2NpZHJ2NihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiY2lkcnY2IiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9iYXNlNjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImJhc2U2NCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfYmFzZTY0dXJsKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJiYXNlNjR1cmwiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2UxNjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImUxNjQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2p3dChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiand0IiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EYXRlVGltZShDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiZGF0ZXRpbWUiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIG9mZnNldDogZmFsc2UsCiAgICBsb2NhbDogZmFsc2UsCiAgICBwcmVjaXNpb246IG51bGwsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EYXRlKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJkYXRlIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29UaW1lKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ0aW1lIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBwcmVjaXNpb246IG51bGwsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EdXJhdGlvbihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiZHVyYXRpb24iLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX251bWJlcihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJudW1iZXIiLAogICAgY2hlY2tzOiBbXSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2ludChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJudW1iZXIiLAogICAgY2hlY2s6ICJudW1iZXJfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIGZvcm1hdDogInNhZmVpbnQiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdW5rbm93bihDbGFzczIpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAidW5rbm93biIKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbmV2ZXIoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAibmV2ZXIiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbHQodmFsdWUsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrTGVzc1RoYW4oewogICAgY2hlY2s6ICJsZXNzX3RoYW4iLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICB2YWx1ZSwKICAgIGluY2x1c2l2ZTogZmFsc2UKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbHRlKHZhbHVlLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0xlc3NUaGFuKHsKICAgIGNoZWNrOiAibGVzc190aGFuIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgdmFsdWUsCiAgICBpbmNsdXNpdmU6IHRydWUKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZ3QodmFsdWUsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrR3JlYXRlclRoYW4oewogICAgY2hlY2s6ICJncmVhdGVyX3RoYW4iLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICB2YWx1ZSwKICAgIGluY2x1c2l2ZTogZmFsc2UKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZ3RlKHZhbHVlLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0dyZWF0ZXJUaGFuKHsKICAgIGNoZWNrOiAiZ3JlYXRlcl90aGFuIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgdmFsdWUsCiAgICBpbmNsdXNpdmU6IHRydWUKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbXVsdGlwbGVPZih2YWx1ZSwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tNdWx0aXBsZU9mKHsKICAgIGNoZWNrOiAibXVsdGlwbGVfb2YiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICB2YWx1ZQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9tYXhMZW5ndGgobWF4aW11bSwgcGFyYW1zKSB7CiAgY29uc3QgY2ggPSBuZXcgJFpvZENoZWNrTWF4TGVuZ3RoKHsKICAgIGNoZWNrOiAibWF4X2xlbmd0aCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIG1heGltdW0KICB9KTsKICByZXR1cm4gY2g7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX21pbkxlbmd0aChtaW5pbXVtLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja01pbkxlbmd0aCh7CiAgICBjaGVjazogIm1pbl9sZW5ndGgiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBtaW5pbXVtCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2xlbmd0aChsZW5ndGgsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrTGVuZ3RoRXF1YWxzKHsKICAgIGNoZWNrOiAibGVuZ3RoX2VxdWFscyIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIGxlbmd0aAogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9yZWdleChwYXR0ZXJuLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja1JlZ2V4KHsKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBmb3JtYXQ6ICJyZWdleCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIHBhdHRlcm4KICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbG93ZXJjYXNlKHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrTG93ZXJDYXNlKHsKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBmb3JtYXQ6ICJsb3dlcmNhc2UiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdXBwZXJjYXNlKHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrVXBwZXJDYXNlKHsKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBmb3JtYXQ6ICJ1cHBlcmNhc2UiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfaW5jbHVkZXMoaW5jbHVkZXMsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrSW5jbHVkZXMoewogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGZvcm1hdDogImluY2x1ZGVzIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgaW5jbHVkZXMKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfc3RhcnRzV2l0aChwcmVmaXgsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrU3RhcnRzV2l0aCh7CiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgZm9ybWF0OiAic3RhcnRzX3dpdGgiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBwcmVmaXgKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZW5kc1dpdGgoc3VmZml4LCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0VuZHNXaXRoKHsKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBmb3JtYXQ6ICJlbmRzX3dpdGgiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBzdWZmaXgKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfb3ZlcndyaXRlKHR4KSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tPdmVyd3JpdGUoewogICAgY2hlY2s6ICJvdmVyd3JpdGUiLAogICAgdHgKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbm9ybWFsaXplKGZvcm0pIHsKICByZXR1cm4gLyogQF9fUFVSRV9fICovIF9vdmVyd3JpdGUoKGlucHV0KSA9PiBpbnB1dC5ub3JtYWxpemUoZm9ybSkpOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF90cmltKCkgewogIHJldHVybiAvKiBAX19QVVJFX18gKi8gX292ZXJ3cml0ZSgoaW5wdXQpID0+IGlucHV0LnRyaW0oKSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3RvTG93ZXJDYXNlKCkgewogIHJldHVybiAvKiBAX19QVVJFX18gKi8gX292ZXJ3cml0ZSgoaW5wdXQpID0+IGlucHV0LnRvTG93ZXJDYXNlKCkpOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF90b1VwcGVyQ2FzZSgpIHsKICByZXR1cm4gLyogQF9fUFVSRV9fICovIF9vdmVyd3JpdGUoKGlucHV0KSA9PiBpbnB1dC50b1VwcGVyQ2FzZSgpKTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfc2x1Z2lmeSgpIHsKICByZXR1cm4gLyogQF9fUFVSRV9fICovIF9vdmVyd3JpdGUoKGlucHV0KSA9PiBzbHVnaWZ5KGlucHV0KSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2FycmF5KENsYXNzMiwgZWxlbWVudCwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogImFycmF5IiwKICAgIGVsZW1lbnQsCiAgICAvLyBnZXQgZWxlbWVudCgpIHsKICAgIC8vICAgcmV0dXJuIGVsZW1lbnQ7CiAgICAvLyB9LAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfcmVmaW5lKENsYXNzMiwgZm4sIF9wYXJhbXMpIHsKICBjb25zdCBzY2hlbWEgPSBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJjdXN0b20iLAogICAgY2hlY2s6ICJjdXN0b20iLAogICAgZm4sCiAgICAuLi5ub3JtYWxpemVQYXJhbXMoX3BhcmFtcykKICB9KTsKICByZXR1cm4gc2NoZW1hOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9zdXBlclJlZmluZShmbiwgcGFyYW1zKSB7CiAgY29uc3QgY2ggPSAvKiBAX19QVVJFX18gKi8gX2NoZWNrKChwYXlsb2FkKSA9PiB7CiAgICBwYXlsb2FkLmFkZElzc3VlID0gKGlzc3VlMikgPT4gewogICAgICBpZiAodHlwZW9mIGlzc3VlMiA9PT0gInN0cmluZyIpIHsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKGlzc3VlKGlzc3VlMiwgcGF5bG9hZC52YWx1ZSwgY2guX3pvZC5kZWYpKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjb25zdCBfaXNzdWUgPSBpc3N1ZTI7CiAgICAgICAgaWYgKF9pc3N1ZS5mYXRhbCkKICAgICAgICAgIF9pc3N1ZS5jb250aW51ZSA9IGZhbHNlOwogICAgICAgIF9pc3N1ZS5jb2RlID8/IChfaXNzdWUuY29kZSA9ICJjdXN0b20iKTsKICAgICAgICBfaXNzdWUuaW5wdXQgPz8gKF9pc3N1ZS5pbnB1dCA9IHBheWxvYWQudmFsdWUpOwogICAgICAgIF9pc3N1ZS5pbnN0ID8/IChfaXNzdWUuaW5zdCA9IGNoKTsKICAgICAgICBfaXNzdWUuY29udGludWUgPz8gKF9pc3N1ZS5jb250aW51ZSA9ICFjaC5fem9kLmRlZi5hYm9ydCk7CiAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaChpc3N1ZShfaXNzdWUpKTsKICAgICAgfQogICAgfTsKICAgIHJldHVybiBmbihwYXlsb2FkLnZhbHVlLCBwYXlsb2FkKTsKICB9LCBwYXJhbXMpOwogIHJldHVybiBjaDsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfY2hlY2soZm4sIHBhcmFtcykgewogIGNvbnN0IGNoID0gbmV3ICRab2RDaGVjayh7CiAgICBjaGVjazogImN1c3RvbSIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwogIGNoLl96b2QuY2hlY2sgPSBmbjsKICByZXR1cm4gY2g7Cn0KCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS90by1qc29uLXNjaGVtYS5qcwpmdW5jdGlvbiBpbml0aWFsaXplQ29udGV4dChwYXJhbXMpIHsKICBsZXQgdGFyZ2V0ID0gcGFyYW1zPy50YXJnZXQgPz8gImRyYWZ0LTIwMjAtMTIiOwogIGlmICh0YXJnZXQgPT09ICJkcmFmdC00IikKICAgIHRhcmdldCA9ICJkcmFmdC0wNCI7CiAgaWYgKHRhcmdldCA9PT0gImRyYWZ0LTciKQogICAgdGFyZ2V0ID0gImRyYWZ0LTA3IjsKICByZXR1cm4gewogICAgcHJvY2Vzc29yczogcGFyYW1zLnByb2Nlc3NvcnMgPz8ge30sCiAgICBtZXRhZGF0YVJlZ2lzdHJ5OiBwYXJhbXM/Lm1ldGFkYXRhID8/IGdsb2JhbFJlZ2lzdHJ5LAogICAgdGFyZ2V0LAogICAgdW5yZXByZXNlbnRhYmxlOiBwYXJhbXM/LnVucmVwcmVzZW50YWJsZSA/PyAidGhyb3ciLAogICAgb3ZlcnJpZGU6IHBhcmFtcz8ub3ZlcnJpZGUgPz8gKCgpID0+IHsKICAgIH0pLAogICAgaW86IHBhcmFtcz8uaW8gPz8gIm91dHB1dCIsCiAgICBjb3VudGVyOiAwLAogICAgc2VlbjogLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKSwKICAgIGN5Y2xlczogcGFyYW1zPy5jeWNsZXMgPz8gInJlZiIsCiAgICByZXVzZWQ6IHBhcmFtcz8ucmV1c2VkID8/ICJpbmxpbmUiLAogICAgZXh0ZXJuYWw6IHBhcmFtcz8uZXh0ZXJuYWwgPz8gdm9pZCAwCiAgfTsKfQpmdW5jdGlvbiBwcm9jZXNzMihzY2hlbWEsIGN0eCwgX3BhcmFtcyA9IHsgcGF0aDogW10sIHNjaGVtYVBhdGg6IFtdIH0pIHsKICB2YXIgX2EzOwogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgaWYgKHNlZW4pIHsKICAgIHNlZW4uY291bnQrKzsKICAgIGNvbnN0IGlzQ3ljbGUgPSBfcGFyYW1zLnNjaGVtYVBhdGguaW5jbHVkZXMoc2NoZW1hKTsKICAgIGlmIChpc0N5Y2xlKSB7CiAgICAgIHNlZW4uY3ljbGUgPSBfcGFyYW1zLnBhdGg7CiAgICB9CiAgICByZXR1cm4gc2Vlbi5zY2hlbWE7CiAgfQogIGNvbnN0IHJlc3VsdCA9IHsgc2NoZW1hOiB7fSwgY291bnQ6IDEsIGN5Y2xlOiB2b2lkIDAsIHBhdGg6IF9wYXJhbXMucGF0aCB9OwogIGN0eC5zZWVuLnNldChzY2hlbWEsIHJlc3VsdCk7CiAgY29uc3Qgb3ZlcnJpZGVTY2hlbWEgPSBzY2hlbWEuX3pvZC50b0pTT05TY2hlbWE/LigpOwogIGlmIChvdmVycmlkZVNjaGVtYSkgewogICAgcmVzdWx0LnNjaGVtYSA9IG92ZXJyaWRlU2NoZW1hOwogIH0gZWxzZSB7CiAgICBjb25zdCBwYXJhbXMgPSB7CiAgICAgIC4uLl9wYXJhbXMsCiAgICAgIHNjaGVtYVBhdGg6IFsuLi5fcGFyYW1zLnNjaGVtYVBhdGgsIHNjaGVtYV0sCiAgICAgIHBhdGg6IF9wYXJhbXMucGF0aAogICAgfTsKICAgIGlmIChzY2hlbWEuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSkgewogICAgICBzY2hlbWEuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYShjdHgsIHJlc3VsdC5zY2hlbWEsIHBhcmFtcyk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBfanNvbiA9IHJlc3VsdC5zY2hlbWE7CiAgICAgIGNvbnN0IHByb2Nlc3NvciA9IGN0eC5wcm9jZXNzb3JzW2RlZi50eXBlXTsKICAgICAgaWYgKCFwcm9jZXNzb3IpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFt0b0pTT05TY2hlbWFdOiBOb24tcmVwcmVzZW50YWJsZSB0eXBlIGVuY291bnRlcmVkOiAke2RlZi50eXBlfWApOwogICAgICB9CiAgICAgIHByb2Nlc3NvcihzY2hlbWEsIGN0eCwgX2pzb24sIHBhcmFtcyk7CiAgICB9CiAgICBjb25zdCBwYXJlbnQgPSBzY2hlbWEuX3pvZC5wYXJlbnQ7CiAgICBpZiAocGFyZW50KSB7CiAgICAgIGlmICghcmVzdWx0LnJlZikKICAgICAgICByZXN1bHQucmVmID0gcGFyZW50OwogICAgICBwcm9jZXNzMihwYXJlbnQsIGN0eCwgcGFyYW1zKTsKICAgICAgY3R4LnNlZW4uZ2V0KHBhcmVudCkuaXNQYXJlbnQgPSB0cnVlOwogICAgfQogIH0KICBjb25zdCBtZXRhMiA9IGN0eC5tZXRhZGF0YVJlZ2lzdHJ5LmdldChzY2hlbWEpOwogIGlmIChtZXRhMikKICAgIE9iamVjdC5hc3NpZ24ocmVzdWx0LnNjaGVtYSwgbWV0YTIpOwogIGlmIChjdHguaW8gPT09ICJpbnB1dCIgJiYgaXNUcmFuc2Zvcm1pbmcoc2NoZW1hKSkgewogICAgZGVsZXRlIHJlc3VsdC5zY2hlbWEuZXhhbXBsZXM7CiAgICBkZWxldGUgcmVzdWx0LnNjaGVtYS5kZWZhdWx0OwogIH0KICBpZiAoY3R4LmlvID09PSAiaW5wdXQiICYmICJfcHJlZmF1bHQiIGluIHJlc3VsdC5zY2hlbWEpCiAgICAoX2EzID0gcmVzdWx0LnNjaGVtYSkuZGVmYXVsdCA/PyAoX2EzLmRlZmF1bHQgPSByZXN1bHQuc2NoZW1hLl9wcmVmYXVsdCk7CiAgZGVsZXRlIHJlc3VsdC5zY2hlbWEuX3ByZWZhdWx0OwogIGNvbnN0IF9yZXN1bHQgPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICByZXR1cm4gX3Jlc3VsdC5zY2hlbWE7Cn0KZnVuY3Rpb24gZXh0cmFjdERlZnMoY3R4LCBzY2hlbWEpIHsKICBjb25zdCByb290ID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgaWYgKCFyb290KQogICAgdGhyb3cgbmV3IEVycm9yKCJVbnByb2Nlc3NlZCBzY2hlbWEuIFRoaXMgaXMgYSBidWcgaW4gWm9kLiIpOwogIGNvbnN0IGlkVG9TY2hlbWEgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogIGZvciAoY29uc3QgZW50cnkgb2YgY3R4LnNlZW4uZW50cmllcygpKSB7CiAgICBjb25zdCBpZCA9IGN0eC5tZXRhZGF0YVJlZ2lzdHJ5LmdldChlbnRyeVswXSk/LmlkOwogICAgaWYgKGlkKSB7CiAgICAgIGNvbnN0IGV4aXN0aW5nID0gaWRUb1NjaGVtYS5nZXQoaWQpOwogICAgICBpZiAoZXhpc3RpbmcgJiYgZXhpc3RpbmcgIT09IGVudHJ5WzBdKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBEdXBsaWNhdGUgc2NoZW1hIGlkICIke2lkfSIgZGV0ZWN0ZWQgZHVyaW5nIEpTT04gU2NoZW1hIGNvbnZlcnNpb24uIFR3byBkaWZmZXJlbnQgc2NoZW1hcyBjYW5ub3Qgc2hhcmUgdGhlIHNhbWUgaWQgd2hlbiBjb252ZXJ0ZWQgdG9nZXRoZXIuYCk7CiAgICAgIH0KICAgICAgaWRUb1NjaGVtYS5zZXQoaWQsIGVudHJ5WzBdKTsKICAgIH0KICB9CiAgY29uc3QgbWFrZVVSSSA9IChlbnRyeSkgPT4gewogICAgY29uc3QgZGVmc1NlZ21lbnQgPSBjdHgudGFyZ2V0ID09PSAiZHJhZnQtMjAyMC0xMiIgPyAiJGRlZnMiIDogImRlZmluaXRpb25zIjsKICAgIGlmIChjdHguZXh0ZXJuYWwpIHsKICAgICAgY29uc3QgZXh0ZXJuYWxJZCA9IGN0eC5leHRlcm5hbC5yZWdpc3RyeS5nZXQoZW50cnlbMF0pPy5pZDsKICAgICAgY29uc3QgdXJpR2VuZXJhdG9yID0gY3R4LmV4dGVybmFsLnVyaSA/PyAoKGlkMikgPT4gaWQyKTsKICAgICAgaWYgKGV4dGVybmFsSWQpIHsKICAgICAgICByZXR1cm4geyByZWY6IHVyaUdlbmVyYXRvcihleHRlcm5hbElkKSB9OwogICAgICB9CiAgICAgIGNvbnN0IGlkID0gZW50cnlbMV0uZGVmSWQgPz8gZW50cnlbMV0uc2NoZW1hLmlkID8/IGBzY2hlbWEke2N0eC5jb3VudGVyKyt9YDsKICAgICAgZW50cnlbMV0uZGVmSWQgPSBpZDsKICAgICAgcmV0dXJuIHsgZGVmSWQ6IGlkLCByZWY6IGAke3VyaUdlbmVyYXRvcigiX19zaGFyZWQiKX0jLyR7ZGVmc1NlZ21lbnR9LyR7aWR9YCB9OwogICAgfQogICAgaWYgKGVudHJ5WzFdID09PSByb290KSB7CiAgICAgIHJldHVybiB7IHJlZjogIiMiIH07CiAgICB9CiAgICBjb25zdCB1cmlQcmVmaXggPSBgI2A7CiAgICBjb25zdCBkZWZVcmlQcmVmaXggPSBgJHt1cmlQcmVmaXh9LyR7ZGVmc1NlZ21lbnR9L2A7CiAgICBjb25zdCBkZWZJZCA9IGVudHJ5WzFdLnNjaGVtYS5pZCA/PyBgX19zY2hlbWEke2N0eC5jb3VudGVyKyt9YDsKICAgIHJldHVybiB7IGRlZklkLCByZWY6IGRlZlVyaVByZWZpeCArIGRlZklkIH07CiAgfTsKICBjb25zdCBleHRyYWN0VG9EZWYgPSAoZW50cnkpID0+IHsKICAgIGlmIChlbnRyeVsxXS5zY2hlbWEuJHJlZikgewogICAgICByZXR1cm47CiAgICB9CiAgICBjb25zdCBzZWVuID0gZW50cnlbMV07CiAgICBjb25zdCB7IHJlZiwgZGVmSWQgfSA9IG1ha2VVUkkoZW50cnkpOwogICAgc2Vlbi5kZWYgPSB7IC4uLnNlZW4uc2NoZW1hIH07CiAgICBpZiAoZGVmSWQpCiAgICAgIHNlZW4uZGVmSWQgPSBkZWZJZDsKICAgIGNvbnN0IHNjaGVtYTIgPSBzZWVuLnNjaGVtYTsKICAgIGZvciAoY29uc3Qga2V5IGluIHNjaGVtYTIpIHsKICAgICAgZGVsZXRlIHNjaGVtYTJba2V5XTsKICAgIH0KICAgIHNjaGVtYTIuJHJlZiA9IHJlZjsKICB9OwogIGlmIChjdHguY3ljbGVzID09PSAidGhyb3ciKSB7CiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGN0eC5zZWVuLmVudHJpZXMoKSkgewogICAgICBjb25zdCBzZWVuID0gZW50cnlbMV07CiAgICAgIGlmIChzZWVuLmN5Y2xlKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDeWNsZSBkZXRlY3RlZDogIy8ke3NlZW4uY3ljbGU/LmpvaW4oIi8iKX0vPHJvb3Q+CgpTZXQgdGhlIFxgY3ljbGVzXGAgcGFyYW1ldGVyIHRvIFxgInJlZiJcYCB0byByZXNvbHZlIGN5Y2xpY2FsIHNjaGVtYXMgd2l0aCBkZWZzLmApOwogICAgICB9CiAgICB9CiAgfQogIGZvciAoY29uc3QgZW50cnkgb2YgY3R4LnNlZW4uZW50cmllcygpKSB7CiAgICBjb25zdCBzZWVuID0gZW50cnlbMV07CiAgICBpZiAoc2NoZW1hID09PSBlbnRyeVswXSkgewogICAgICBleHRyYWN0VG9EZWYoZW50cnkpOwogICAgICBjb250aW51ZTsKICAgIH0KICAgIGlmIChjdHguZXh0ZXJuYWwpIHsKICAgICAgY29uc3QgZXh0ID0gY3R4LmV4dGVybmFsLnJlZ2lzdHJ5LmdldChlbnRyeVswXSk/LmlkOwogICAgICBpZiAoc2NoZW1hICE9PSBlbnRyeVswXSAmJiBleHQpIHsKICAgICAgICBleHRyYWN0VG9EZWYoZW50cnkpOwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICB9CiAgICBjb25zdCBpZCA9IGN0eC5tZXRhZGF0YVJlZ2lzdHJ5LmdldChlbnRyeVswXSk/LmlkOwogICAgaWYgKGlkKSB7CiAgICAgIGV4dHJhY3RUb0RlZihlbnRyeSk7CiAgICAgIGNvbnRpbnVlOwogICAgfQogICAgaWYgKHNlZW4uY3ljbGUpIHsKICAgICAgZXh0cmFjdFRvRGVmKGVudHJ5KTsKICAgICAgY29udGludWU7CiAgICB9CiAgICBpZiAoc2Vlbi5jb3VudCA+IDEpIHsKICAgICAgaWYgKGN0eC5yZXVzZWQgPT09ICJyZWYiKSB7CiAgICAgICAgZXh0cmFjdFRvRGVmKGVudHJ5KTsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgfQogIH0KfQpmdW5jdGlvbiBmaW5hbGl6ZShjdHgsIHNjaGVtYSkgewogIGNvbnN0IHJvb3QgPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBpZiAoIXJvb3QpCiAgICB0aHJvdyBuZXcgRXJyb3IoIlVucHJvY2Vzc2VkIHNjaGVtYS4gVGhpcyBpcyBhIGJ1ZyBpbiBab2QuIik7CiAgY29uc3QgZmxhdHRlblJlZiA9ICh6b2RTY2hlbWEpID0+IHsKICAgIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoem9kU2NoZW1hKTsKICAgIGlmIChzZWVuLnJlZiA9PT0gbnVsbCkKICAgICAgcmV0dXJuOwogICAgY29uc3Qgc2NoZW1hMiA9IHNlZW4uZGVmID8/IHNlZW4uc2NoZW1hOwogICAgY29uc3QgX2NhY2hlZCA9IHsgLi4uc2NoZW1hMiB9OwogICAgY29uc3QgcmVmID0gc2Vlbi5yZWY7CiAgICBzZWVuLnJlZiA9IG51bGw7CiAgICBpZiAocmVmKSB7CiAgICAgIGZsYXR0ZW5SZWYocmVmKTsKICAgICAgY29uc3QgcmVmU2VlbiA9IGN0eC5zZWVuLmdldChyZWYpOwogICAgICBjb25zdCByZWZTY2hlbWEgPSByZWZTZWVuLnNjaGVtYTsKICAgICAgaWYgKHJlZlNjaGVtYS4kcmVmICYmIChjdHgudGFyZ2V0ID09PSAiZHJhZnQtMDciIHx8IGN0eC50YXJnZXQgPT09ICJkcmFmdC0wNCIgfHwgY3R4LnRhcmdldCA9PT0gIm9wZW5hcGktMy4wIikpIHsKICAgICAgICBzY2hlbWEyLmFsbE9mID0gc2NoZW1hMi5hbGxPZiA/PyBbXTsKICAgICAgICBzY2hlbWEyLmFsbE9mLnB1c2gocmVmU2NoZW1hKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBPYmplY3QuYXNzaWduKHNjaGVtYTIsIHJlZlNjaGVtYSk7CiAgICAgIH0KICAgICAgT2JqZWN0LmFzc2lnbihzY2hlbWEyLCBfY2FjaGVkKTsKICAgICAgY29uc3QgaXNQYXJlbnRSZWYgPSB6b2RTY2hlbWEuX3pvZC5wYXJlbnQgPT09IHJlZjsKICAgICAgaWYgKGlzUGFyZW50UmVmKSB7CiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gc2NoZW1hMikgewogICAgICAgICAgaWYgKGtleSA9PT0gIiRyZWYiIHx8IGtleSA9PT0gImFsbE9mIikKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBpZiAoIShrZXkgaW4gX2NhY2hlZCkpIHsKICAgICAgICAgICAgZGVsZXRlIHNjaGVtYTJba2V5XTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHJlZlNjaGVtYS4kcmVmICYmIHJlZlNlZW4uZGVmKSB7CiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gc2NoZW1hMikgewogICAgICAgICAgaWYgKGtleSA9PT0gIiRyZWYiIHx8IGtleSA9PT0gImFsbE9mIikKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBpZiAoa2V5IGluIHJlZlNlZW4uZGVmICYmIEpTT04uc3RyaW5naWZ5KHNjaGVtYTJba2V5XSkgPT09IEpTT04uc3RyaW5naWZ5KHJlZlNlZW4uZGVmW2tleV0pKSB7CiAgICAgICAgICAgIGRlbGV0ZSBzY2hlbWEyW2tleV07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBjb25zdCBwYXJlbnQgPSB6b2RTY2hlbWEuX3pvZC5wYXJlbnQ7CiAgICBpZiAocGFyZW50ICYmIHBhcmVudCAhPT0gcmVmKSB7CiAgICAgIGZsYXR0ZW5SZWYocGFyZW50KTsKICAgICAgY29uc3QgcGFyZW50U2VlbiA9IGN0eC5zZWVuLmdldChwYXJlbnQpOwogICAgICBpZiAocGFyZW50U2Vlbj8uc2NoZW1hLiRyZWYpIHsKICAgICAgICBzY2hlbWEyLiRyZWYgPSBwYXJlbnRTZWVuLnNjaGVtYS4kcmVmOwogICAgICAgIGlmIChwYXJlbnRTZWVuLmRlZikgewogICAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gc2NoZW1hMikgewogICAgICAgICAgICBpZiAoa2V5ID09PSAiJHJlZiIgfHwga2V5ID09PSAiYWxsT2YiKQogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICBpZiAoa2V5IGluIHBhcmVudFNlZW4uZGVmICYmIEpTT04uc3RyaW5naWZ5KHNjaGVtYTJba2V5XSkgPT09IEpTT04uc3RyaW5naWZ5KHBhcmVudFNlZW4uZGVmW2tleV0pKSB7CiAgICAgICAgICAgICAgZGVsZXRlIHNjaGVtYTJba2V5XTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgY3R4Lm92ZXJyaWRlKHsKICAgICAgem9kU2NoZW1hLAogICAgICBqc29uU2NoZW1hOiBzY2hlbWEyLAogICAgICBwYXRoOiBzZWVuLnBhdGggPz8gW10KICAgIH0pOwogIH07CiAgZm9yIChjb25zdCBlbnRyeSBvZiBbLi4uY3R4LnNlZW4uZW50cmllcygpXS5yZXZlcnNlKCkpIHsKICAgIGZsYXR0ZW5SZWYoZW50cnlbMF0pOwogIH0KICBjb25zdCByZXN1bHQgPSB7fTsKICBpZiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTIwMjAtMTIiKSB7CiAgICByZXN1bHQuJHNjaGVtYSA9ICJodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYSI7CiAgfSBlbHNlIGlmIChjdHgudGFyZ2V0ID09PSAiZHJhZnQtMDciKSB7CiAgICByZXN1bHQuJHNjaGVtYSA9ICJodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSMiOwogIH0gZWxzZSBpZiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA0IikgewogICAgcmVzdWx0LiRzY2hlbWEgPSAiaHR0cDovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC0wNC9zY2hlbWEjIjsKICB9IGVsc2UgaWYgKGN0eC50YXJnZXQgPT09ICJvcGVuYXBpLTMuMCIpIHsKICB9IGVsc2UgewogIH0KICBpZiAoY3R4LmV4dGVybmFsPy51cmkpIHsKICAgIGNvbnN0IGlkID0gY3R4LmV4dGVybmFsLnJlZ2lzdHJ5LmdldChzY2hlbWEpPy5pZDsKICAgIGlmICghaWQpCiAgICAgIHRocm93IG5ldyBFcnJvcigiU2NoZW1hIGlzIG1pc3NpbmcgYW4gYGlkYCBwcm9wZXJ0eSIpOwogICAgcmVzdWx0LiRpZCA9IGN0eC5leHRlcm5hbC51cmkoaWQpOwogIH0KICBPYmplY3QuYXNzaWduKHJlc3VsdCwgcm9vdC5kZWYgPz8gcm9vdC5zY2hlbWEpOwogIGNvbnN0IHJvb3RNZXRhSWQgPSBjdHgubWV0YWRhdGFSZWdpc3RyeS5nZXQoc2NoZW1hKT8uaWQ7CiAgaWYgKHJvb3RNZXRhSWQgIT09IHZvaWQgMCAmJiByZXN1bHQuaWQgPT09IHJvb3RNZXRhSWQpCiAgICBkZWxldGUgcmVzdWx0LmlkOwogIGNvbnN0IGRlZnMgPSBjdHguZXh0ZXJuYWw/LmRlZnMgPz8ge307CiAgZm9yIChjb25zdCBlbnRyeSBvZiBjdHguc2Vlbi5lbnRyaWVzKCkpIHsKICAgIGNvbnN0IHNlZW4gPSBlbnRyeVsxXTsKICAgIGlmIChzZWVuLmRlZiAmJiBzZWVuLmRlZklkKSB7CiAgICAgIGlmIChzZWVuLmRlZi5pZCA9PT0gc2Vlbi5kZWZJZCkKICAgICAgICBkZWxldGUgc2Vlbi5kZWYuaWQ7CiAgICAgIGRlZnNbc2Vlbi5kZWZJZF0gPSBzZWVuLmRlZjsKICAgIH0KICB9CiAgaWYgKGN0eC5leHRlcm5hbCkgewogIH0gZWxzZSB7CiAgICBpZiAoT2JqZWN0LmtleXMoZGVmcykubGVuZ3RoID4gMCkgewogICAgICBpZiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTIwMjAtMTIiKSB7CiAgICAgICAgcmVzdWx0LiRkZWZzID0gZGVmczsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXN1bHQuZGVmaW5pdGlvbnMgPSBkZWZzOwogICAgICB9CiAgICB9CiAgfQogIHRyeSB7CiAgICBjb25zdCBmaW5hbGl6ZWQgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHJlc3VsdCkpOwogICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGZpbmFsaXplZCwgIn5zdGFuZGFyZCIsIHsKICAgICAgdmFsdWU6IHsKICAgICAgICAuLi5zY2hlbWFbIn5zdGFuZGFyZCJdLAogICAgICAgIGpzb25TY2hlbWE6IHsKICAgICAgICAgIGlucHV0OiBjcmVhdGVTdGFuZGFyZEpTT05TY2hlbWFNZXRob2Qoc2NoZW1hLCAiaW5wdXQiLCBjdHgucHJvY2Vzc29ycyksCiAgICAgICAgICBvdXRwdXQ6IGNyZWF0ZVN0YW5kYXJkSlNPTlNjaGVtYU1ldGhvZChzY2hlbWEsICJvdXRwdXQiLCBjdHgucHJvY2Vzc29ycykKICAgICAgICB9CiAgICAgIH0sCiAgICAgIGVudW1lcmFibGU6IGZhbHNlLAogICAgICB3cml0YWJsZTogZmFsc2UKICAgIH0pOwogICAgcmV0dXJuIGZpbmFsaXplZDsKICB9IGNhdGNoIChfZXJyKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkVycm9yIGNvbnZlcnRpbmcgc2NoZW1hIHRvIEpTT04uIik7CiAgfQp9CmZ1bmN0aW9uIGlzVHJhbnNmb3JtaW5nKF9zY2hlbWEsIF9jdHgpIHsKICBjb25zdCBjdHggPSBfY3R4ID8/IHsgc2VlbjogLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKSB9OwogIGlmIChjdHguc2Vlbi5oYXMoX3NjaGVtYSkpCiAgICByZXR1cm4gZmFsc2U7CiAgY3R4LnNlZW4uYWRkKF9zY2hlbWEpOwogIGNvbnN0IGRlZiA9IF9zY2hlbWEuX3pvZC5kZWY7CiAgaWYgKGRlZi50eXBlID09PSAidHJhbnNmb3JtIikKICAgIHJldHVybiB0cnVlOwogIGlmIChkZWYudHlwZSA9PT0gImFycmF5IikKICAgIHJldHVybiBpc1RyYW5zZm9ybWluZyhkZWYuZWxlbWVudCwgY3R4KTsKICBpZiAoZGVmLnR5cGUgPT09ICJzZXQiKQogICAgcmV0dXJuIGlzVHJhbnNmb3JtaW5nKGRlZi52YWx1ZVR5cGUsIGN0eCk7CiAgaWYgKGRlZi50eXBlID09PSAibGF6eSIpCiAgICByZXR1cm4gaXNUcmFuc2Zvcm1pbmcoZGVmLmdldHRlcigpLCBjdHgpOwogIGlmIChkZWYudHlwZSA9PT0gInByb21pc2UiIHx8IGRlZi50eXBlID09PSAib3B0aW9uYWwiIHx8IGRlZi50eXBlID09PSAibm9ub3B0aW9uYWwiIHx8IGRlZi50eXBlID09PSAibnVsbGFibGUiIHx8IGRlZi50eXBlID09PSAicmVhZG9ubHkiIHx8IGRlZi50eXBlID09PSAiZGVmYXVsdCIgfHwgZGVmLnR5cGUgPT09ICJwcmVmYXVsdCIpIHsKICAgIHJldHVybiBpc1RyYW5zZm9ybWluZyhkZWYuaW5uZXJUeXBlLCBjdHgpOwogIH0KICBpZiAoZGVmLnR5cGUgPT09ICJpbnRlcnNlY3Rpb24iKSB7CiAgICByZXR1cm4gaXNUcmFuc2Zvcm1pbmcoZGVmLmxlZnQsIGN0eCkgfHwgaXNUcmFuc2Zvcm1pbmcoZGVmLnJpZ2h0LCBjdHgpOwogIH0KICBpZiAoZGVmLnR5cGUgPT09ICJyZWNvcmQiIHx8IGRlZi50eXBlID09PSAibWFwIikgewogICAgcmV0dXJuIGlzVHJhbnNmb3JtaW5nKGRlZi5rZXlUeXBlLCBjdHgpIHx8IGlzVHJhbnNmb3JtaW5nKGRlZi52YWx1ZVR5cGUsIGN0eCk7CiAgfQogIGlmIChkZWYudHlwZSA9PT0gInBpcGUiKSB7CiAgICBpZiAoX3NjaGVtYS5fem9kLnRyYWl0cy5oYXMoIiRab2RDb2RlYyIpKQogICAgICByZXR1cm4gdHJ1ZTsKICAgIHJldHVybiBpc1RyYW5zZm9ybWluZyhkZWYuaW4sIGN0eCkgfHwgaXNUcmFuc2Zvcm1pbmcoZGVmLm91dCwgY3R4KTsKICB9CiAgaWYgKGRlZi50eXBlID09PSAib2JqZWN0IikgewogICAgZm9yIChjb25zdCBrZXkgaW4gZGVmLnNoYXBlKSB7CiAgICAgIGlmIChpc1RyYW5zZm9ybWluZyhkZWYuc2hhcGVba2V5XSwgY3R4KSkKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CiAgaWYgKGRlZi50eXBlID09PSAidW5pb24iKSB7CiAgICBmb3IgKGNvbnN0IG9wdGlvbiBvZiBkZWYub3B0aW9ucykgewogICAgICBpZiAoaXNUcmFuc2Zvcm1pbmcob3B0aW9uLCBjdHgpKQogICAgICAgIHJldHVybiB0cnVlOwogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KICBpZiAoZGVmLnR5cGUgPT09ICJ0dXBsZSIpIHsKICAgIGZvciAoY29uc3QgaXRlbSBvZiBkZWYuaXRlbXMpIHsKICAgICAgaWYgKGlzVHJhbnNmb3JtaW5nKGl0ZW0sIGN0eCkpCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICBpZiAoZGVmLnJlc3QgJiYgaXNUcmFuc2Zvcm1pbmcoZGVmLnJlc3QsIGN0eCkpCiAgICAgIHJldHVybiB0cnVlOwogICAgcmV0dXJuIGZhbHNlOwogIH0KICByZXR1cm4gZmFsc2U7Cn0KdmFyIGNyZWF0ZVRvSlNPTlNjaGVtYU1ldGhvZCA9IChzY2hlbWEsIHByb2Nlc3NvcnMgPSB7fSkgPT4gKHBhcmFtcykgPT4gewogIGNvbnN0IGN0eCA9IGluaXRpYWxpemVDb250ZXh0KHsgLi4ucGFyYW1zLCBwcm9jZXNzb3JzIH0pOwogIHByb2Nlc3MyKHNjaGVtYSwgY3R4KTsKICBleHRyYWN0RGVmcyhjdHgsIHNjaGVtYSk7CiAgcmV0dXJuIGZpbmFsaXplKGN0eCwgc2NoZW1hKTsKfTsKdmFyIGNyZWF0ZVN0YW5kYXJkSlNPTlNjaGVtYU1ldGhvZCA9IChzY2hlbWEsIGlvLCBwcm9jZXNzb3JzID0ge30pID0+IChwYXJhbXMpID0+IHsKICBjb25zdCB7IGxpYnJhcnlPcHRpb25zLCB0YXJnZXQgfSA9IHBhcmFtcyA/PyB7fTsKICBjb25zdCBjdHggPSBpbml0aWFsaXplQ29udGV4dCh7IC4uLmxpYnJhcnlPcHRpb25zID8/IHt9LCB0YXJnZXQsIGlvLCBwcm9jZXNzb3JzIH0pOwogIHByb2Nlc3MyKHNjaGVtYSwgY3R4KTsKICBleHRyYWN0RGVmcyhjdHgsIHNjaGVtYSk7CiAgcmV0dXJuIGZpbmFsaXplKGN0eCwgc2NoZW1hKTsKfTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9qc29uLXNjaGVtYS1wcm9jZXNzb3JzLmpzCnZhciBmb3JtYXRNYXAgPSB7CiAgZ3VpZDogInV1aWQiLAogIHVybDogInVyaSIsCiAgZGF0ZXRpbWU6ICJkYXRlLXRpbWUiLAogIGpzb25fc3RyaW5nOiAianNvbi1zdHJpbmciLAogIHJlZ2V4OiAiIgogIC8vIGRvIG5vdCBzZXQKfTsKdmFyIHN0cmluZ1Byb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwgX2pzb24sIF9wYXJhbXMpID0+IHsKICBjb25zdCBqc29uID0gX2pzb247CiAganNvbi50eXBlID0gInN0cmluZyI7CiAgY29uc3QgeyBtaW5pbXVtLCBtYXhpbXVtLCBmb3JtYXQsIHBhdHRlcm5zLCBjb250ZW50RW5jb2RpbmcgfSA9IHNjaGVtYS5fem9kLmJhZzsKICBpZiAodHlwZW9mIG1pbmltdW0gPT09ICJudW1iZXIiKQogICAganNvbi5taW5MZW5ndGggPSBtaW5pbXVtOwogIGlmICh0eXBlb2YgbWF4aW11bSA9PT0gIm51bWJlciIpCiAgICBqc29uLm1heExlbmd0aCA9IG1heGltdW07CiAgaWYgKGZvcm1hdCkgewogICAganNvbi5mb3JtYXQgPSBmb3JtYXRNYXBbZm9ybWF0XSA/PyBmb3JtYXQ7CiAgICBpZiAoanNvbi5mb3JtYXQgPT09ICIiKQogICAgICBkZWxldGUganNvbi5mb3JtYXQ7CiAgICBpZiAoZm9ybWF0ID09PSAidGltZSIpIHsKICAgICAgZGVsZXRlIGpzb24uZm9ybWF0OwogICAgfQogIH0KICBpZiAoY29udGVudEVuY29kaW5nKQogICAganNvbi5jb250ZW50RW5jb2RpbmcgPSBjb250ZW50RW5jb2Rpbmc7CiAgaWYgKHBhdHRlcm5zICYmIHBhdHRlcm5zLnNpemUgPiAwKSB7CiAgICBjb25zdCByZWdleGVzID0gWy4uLnBhdHRlcm5zXTsKICAgIGlmIChyZWdleGVzLmxlbmd0aCA9PT0gMSkKICAgICAganNvbi5wYXR0ZXJuID0gcmVnZXhlc1swXS5zb3VyY2U7CiAgICBlbHNlIGlmIChyZWdleGVzLmxlbmd0aCA+IDEpIHsKICAgICAganNvbi5hbGxPZiA9IFsKICAgICAgICAuLi5yZWdleGVzLm1hcCgocmVnZXgpID0+ICh7CiAgICAgICAgICAuLi5jdHgudGFyZ2V0ID09PSAiZHJhZnQtMDciIHx8IGN0eC50YXJnZXQgPT09ICJkcmFmdC0wNCIgfHwgY3R4LnRhcmdldCA9PT0gIm9wZW5hcGktMy4wIiA/IHsgdHlwZTogInN0cmluZyIgfSA6IHt9LAogICAgICAgICAgcGF0dGVybjogcmVnZXguc291cmNlCiAgICAgICAgfSkpCiAgICAgIF07CiAgICB9CiAgfQp9Owp2YXIgbnVtYmVyUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgX3BhcmFtcykgPT4gewogIGNvbnN0IGpzb24gPSBfanNvbjsKICBjb25zdCB7IG1pbmltdW0sIG1heGltdW0sIGZvcm1hdCwgbXVsdGlwbGVPZiwgZXhjbHVzaXZlTWF4aW11bSwgZXhjbHVzaXZlTWluaW11bSB9ID0gc2NoZW1hLl96b2QuYmFnOwogIGlmICh0eXBlb2YgZm9ybWF0ID09PSAic3RyaW5nIiAmJiBmb3JtYXQuaW5jbHVkZXMoImludCIpKQogICAganNvbi50eXBlID0gImludGVnZXIiOwogIGVsc2UKICAgIGpzb24udHlwZSA9ICJudW1iZXIiOwogIGNvbnN0IGV4TWluID0gdHlwZW9mIGV4Y2x1c2l2ZU1pbmltdW0gPT09ICJudW1iZXIiICYmIGV4Y2x1c2l2ZU1pbmltdW0gPj0gKG1pbmltdW0gPz8gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZKTsKICBjb25zdCBleE1heCA9IHR5cGVvZiBleGNsdXNpdmVNYXhpbXVtID09PSAibnVtYmVyIiAmJiBleGNsdXNpdmVNYXhpbXVtIDw9IChtYXhpbXVtID8/IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSk7CiAgY29uc3QgbGVnYWN5ID0gY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA0IiB8fCBjdHgudGFyZ2V0ID09PSAib3BlbmFwaS0zLjAiOwogIGlmIChleE1pbikgewogICAgaWYgKGxlZ2FjeSkgewogICAgICBqc29uLm1pbmltdW0gPSBleGNsdXNpdmVNaW5pbXVtOwogICAgICBqc29uLmV4Y2x1c2l2ZU1pbmltdW0gPSB0cnVlOwogICAgfSBlbHNlIHsKICAgICAganNvbi5leGNsdXNpdmVNaW5pbXVtID0gZXhjbHVzaXZlTWluaW11bTsKICAgIH0KICB9IGVsc2UgaWYgKHR5cGVvZiBtaW5pbXVtID09PSAibnVtYmVyIikgewogICAganNvbi5taW5pbXVtID0gbWluaW11bTsKICB9CiAgaWYgKGV4TWF4KSB7CiAgICBpZiAobGVnYWN5KSB7CiAgICAgIGpzb24ubWF4aW11bSA9IGV4Y2x1c2l2ZU1heGltdW07CiAgICAgIGpzb24uZXhjbHVzaXZlTWF4aW11bSA9IHRydWU7CiAgICB9IGVsc2UgewogICAgICBqc29uLmV4Y2x1c2l2ZU1heGltdW0gPSBleGNsdXNpdmVNYXhpbXVtOwogICAgfQogIH0gZWxzZSBpZiAodHlwZW9mIG1heGltdW0gPT09ICJudW1iZXIiKSB7CiAgICBqc29uLm1heGltdW0gPSBtYXhpbXVtOwogIH0KICBpZiAodHlwZW9mIG11bHRpcGxlT2YgPT09ICJudW1iZXIiKQogICAganNvbi5tdWx0aXBsZU9mID0gbXVsdGlwbGVPZjsKfTsKdmFyIG5ldmVyUHJvY2Vzc29yID0gKF9zY2hlbWEsIF9jdHgsIGpzb24sIF9wYXJhbXMpID0+IHsKICBqc29uLm5vdCA9IHt9Owp9Owp2YXIgdW5rbm93blByb2Nlc3NvciA9IChfc2NoZW1hLCBfY3R4LCBfanNvbiwgX3BhcmFtcykgPT4gewp9Owp2YXIgZW51bVByb2Nlc3NvciA9IChzY2hlbWEsIF9jdHgsIGpzb24sIF9wYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgdmFsdWVzID0gZ2V0RW51bVZhbHVlcyhkZWYuZW50cmllcyk7CiAgaWYgKHZhbHVlcy5ldmVyeSgodikgPT4gdHlwZW9mIHYgPT09ICJudW1iZXIiKSkKICAgIGpzb24udHlwZSA9ICJudW1iZXIiOwogIGlmICh2YWx1ZXMuZXZlcnkoKHYpID0+IHR5cGVvZiB2ID09PSAic3RyaW5nIikpCiAgICBqc29uLnR5cGUgPSAic3RyaW5nIjsKICBqc29uLmVudW0gPSB2YWx1ZXM7Cn07CnZhciBjdXN0b21Qcm9jZXNzb3IgPSAoX3NjaGVtYSwgY3R4LCBfanNvbiwgX3BhcmFtcykgPT4gewogIGlmIChjdHgudW5yZXByZXNlbnRhYmxlID09PSAidGhyb3ciKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkN1c3RvbSB0eXBlcyBjYW5ub3QgYmUgcmVwcmVzZW50ZWQgaW4gSlNPTiBTY2hlbWEiKTsKICB9Cn07CnZhciB0cmFuc2Zvcm1Qcm9jZXNzb3IgPSAoX3NjaGVtYSwgY3R4LCBfanNvbiwgX3BhcmFtcykgPT4gewogIGlmIChjdHgudW5yZXByZXNlbnRhYmxlID09PSAidGhyb3ciKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIlRyYW5zZm9ybXMgY2Fubm90IGJlIHJlcHJlc2VudGVkIGluIEpTT04gU2NoZW1hIik7CiAgfQp9Owp2YXIgYXJyYXlQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIF9qc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBqc29uID0gX2pzb247CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IHsgbWluaW11bSwgbWF4aW11bSB9ID0gc2NoZW1hLl96b2QuYmFnOwogIGlmICh0eXBlb2YgbWluaW11bSA9PT0gIm51bWJlciIpCiAgICBqc29uLm1pbkl0ZW1zID0gbWluaW11bTsKICBpZiAodHlwZW9mIG1heGltdW0gPT09ICJudW1iZXIiKQogICAganNvbi5tYXhJdGVtcyA9IG1heGltdW07CiAganNvbi50eXBlID0gImFycmF5IjsKICBqc29uLml0ZW1zID0gcHJvY2VzczIoZGVmLmVsZW1lbnQsIGN0eCwgewogICAgLi4ucGFyYW1zLAogICAgcGF0aDogWy4uLnBhcmFtcy5wYXRoLCAiaXRlbXMiXQogIH0pOwp9Owp2YXIgb2JqZWN0UHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QganNvbiA9IF9qc29uOwogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBqc29uLnR5cGUgPSAib2JqZWN0IjsKICBqc29uLnByb3BlcnRpZXMgPSB7fTsKICBjb25zdCBzaGFwZSA9IGRlZi5zaGFwZTsKICBmb3IgKGNvbnN0IGtleSBpbiBzaGFwZSkgewogICAganNvbi5wcm9wZXJ0aWVzW2tleV0gPSBwcm9jZXNzMihzaGFwZVtrZXldLCBjdHgsIHsKICAgICAgLi4ucGFyYW1zLAogICAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsICJwcm9wZXJ0aWVzIiwga2V5XQogICAgfSk7CiAgfQogIGNvbnN0IGFsbEtleXMgPSBuZXcgU2V0KE9iamVjdC5rZXlzKHNoYXBlKSk7CiAgY29uc3QgcmVxdWlyZWRLZXlzID0gbmV3IFNldChbLi4uYWxsS2V5c10uZmlsdGVyKChrZXkpID0+IHsKICAgIGNvbnN0IHYgPSBkZWYuc2hhcGVba2V5XS5fem9kOwogICAgaWYgKGN0eC5pbyA9PT0gImlucHV0IikgewogICAgICByZXR1cm4gdi5vcHRpbiA9PT0gdm9pZCAwOwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIHYub3B0b3V0ID09PSB2b2lkIDA7CiAgICB9CiAgfSkpOwogIGlmIChyZXF1aXJlZEtleXMuc2l6ZSA+IDApIHsKICAgIGpzb24ucmVxdWlyZWQgPSBBcnJheS5mcm9tKHJlcXVpcmVkS2V5cyk7CiAgfQogIGlmIChkZWYuY2F0Y2hhbGw/Ll96b2QuZGVmLnR5cGUgPT09ICJuZXZlciIpIHsKICAgIGpzb24uYWRkaXRpb25hbFByb3BlcnRpZXMgPSBmYWxzZTsKICB9IGVsc2UgaWYgKCFkZWYuY2F0Y2hhbGwpIHsKICAgIGlmIChjdHguaW8gPT09ICJvdXRwdXQiKQogICAgICBqc29uLmFkZGl0aW9uYWxQcm9wZXJ0aWVzID0gZmFsc2U7CiAgfSBlbHNlIGlmIChkZWYuY2F0Y2hhbGwpIHsKICAgIGpzb24uYWRkaXRpb25hbFByb3BlcnRpZXMgPSBwcm9jZXNzMihkZWYuY2F0Y2hhbGwsIGN0eCwgewogICAgICAuLi5wYXJhbXMsCiAgICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIl0KICAgIH0pOwogIH0KfTsKdmFyIHVuaW9uUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgaXNFeGNsdXNpdmUgPSBkZWYuaW5jbHVzaXZlID09PSBmYWxzZTsKICBjb25zdCBvcHRpb25zID0gZGVmLm9wdGlvbnMubWFwKCh4LCBpKSA9PiBwcm9jZXNzMih4LCBjdHgsIHsKICAgIC4uLnBhcmFtcywKICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgaXNFeGNsdXNpdmUgPyAib25lT2YiIDogImFueU9mIiwgaV0KICB9KSk7CiAgaWYgKGlzRXhjbHVzaXZlKSB7CiAgICBqc29uLm9uZU9mID0gb3B0aW9uczsKICB9IGVsc2UgewogICAganNvbi5hbnlPZiA9IG9wdGlvbnM7CiAgfQp9Owp2YXIgaW50ZXJzZWN0aW9uUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgYSA9IHByb2Nlc3MyKGRlZi5sZWZ0LCBjdHgsIHsKICAgIC4uLnBhcmFtcywKICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgImFsbE9mIiwgMF0KICB9KTsKICBjb25zdCBiID0gcHJvY2VzczIoZGVmLnJpZ2h0LCBjdHgsIHsKICAgIC4uLnBhcmFtcywKICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgImFsbE9mIiwgMV0KICB9KTsKICBjb25zdCBpc1NpbXBsZUludGVyc2VjdGlvbiA9ICh2YWwpID0+ICJhbGxPZiIgaW4gdmFsICYmIE9iamVjdC5rZXlzKHZhbCkubGVuZ3RoID09PSAxOwogIGNvbnN0IGFsbE9mID0gWwogICAgLi4uaXNTaW1wbGVJbnRlcnNlY3Rpb24oYSkgPyBhLmFsbE9mIDogW2FdLAogICAgLi4uaXNTaW1wbGVJbnRlcnNlY3Rpb24oYikgPyBiLmFsbE9mIDogW2JdCiAgXTsKICBqc29uLmFsbE9mID0gYWxsT2Y7Cn07CnZhciByZWNvcmRQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIF9qc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBqc29uID0gX2pzb247CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGpzb24udHlwZSA9ICJvYmplY3QiOwogIGNvbnN0IGtleVR5cGUgPSBkZWYua2V5VHlwZTsKICBjb25zdCBrZXlCYWcgPSBrZXlUeXBlLl96b2QuYmFnOwogIGNvbnN0IHBhdHRlcm5zID0ga2V5QmFnPy5wYXR0ZXJuczsKICBpZiAoZGVmLm1vZGUgPT09ICJsb29zZSIgJiYgcGF0dGVybnMgJiYgcGF0dGVybnMuc2l6ZSA+IDApIHsKICAgIGNvbnN0IHZhbHVlU2NoZW1hID0gcHJvY2VzczIoZGVmLnZhbHVlVHlwZSwgY3R4LCB7CiAgICAgIC4uLnBhcmFtcywKICAgICAgcGF0aDogWy4uLnBhcmFtcy5wYXRoLCAicGF0dGVyblByb3BlcnRpZXMiLCAiKiJdCiAgICB9KTsKICAgIGpzb24ucGF0dGVyblByb3BlcnRpZXMgPSB7fTsKICAgIGZvciAoY29uc3QgcGF0dGVybiBvZiBwYXR0ZXJucykgewogICAgICBqc29uLnBhdHRlcm5Qcm9wZXJ0aWVzW3BhdHRlcm4uc291cmNlXSA9IHZhbHVlU2NoZW1hOwogICAgfQogIH0gZWxzZSB7CiAgICBpZiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA3IiB8fCBjdHgudGFyZ2V0ID09PSAiZHJhZnQtMjAyMC0xMiIpIHsKICAgICAganNvbi5wcm9wZXJ0eU5hbWVzID0gcHJvY2VzczIoZGVmLmtleVR5cGUsIGN0eCwgewogICAgICAgIC4uLnBhcmFtcywKICAgICAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsICJwcm9wZXJ0eU5hbWVzIl0KICAgICAgfSk7CiAgICB9CiAgICBqc29uLmFkZGl0aW9uYWxQcm9wZXJ0aWVzID0gcHJvY2VzczIoZGVmLnZhbHVlVHlwZSwgY3R4LCB7CiAgICAgIC4uLnBhcmFtcywKICAgICAgcGF0aDogWy4uLnBhcmFtcy5wYXRoLCAiYWRkaXRpb25hbFByb3BlcnRpZXMiXQogICAgfSk7CiAgfQogIGNvbnN0IGtleVZhbHVlcyA9IGtleVR5cGUuX3pvZC52YWx1ZXM7CiAgaWYgKGtleVZhbHVlcykgewogICAgY29uc3QgdmFsaWRLZXlWYWx1ZXMgPSBbLi4ua2V5VmFsdWVzXS5maWx0ZXIoKHYpID0+IHR5cGVvZiB2ID09PSAic3RyaW5nIiB8fCB0eXBlb2YgdiA9PT0gIm51bWJlciIpOwogICAgaWYgKHZhbGlkS2V5VmFsdWVzLmxlbmd0aCA+IDApIHsKICAgICAganNvbi5yZXF1aXJlZCA9IHZhbGlkS2V5VmFsdWVzOwogICAgfQogIH0KfTsKdmFyIG51bGxhYmxlUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgaW5uZXIgPSBwcm9jZXNzMihkZWYuaW5uZXJUeXBlLCBjdHgsIHBhcmFtcyk7CiAgY29uc3Qgc2VlbiA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIGlmIChjdHgudGFyZ2V0ID09PSAib3BlbmFwaS0zLjAiKSB7CiAgICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7CiAgICBqc29uLm51bGxhYmxlID0gdHJ1ZTsKICB9IGVsc2UgewogICAganNvbi5hbnlPZiA9IFtpbm5lciwgeyB0eXBlOiAibnVsbCIgfV07CiAgfQp9Owp2YXIgbm9ub3B0aW9uYWxQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIF9qc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7Cn07CnZhciBkZWZhdWx0UHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7CiAganNvbi5kZWZhdWx0ID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShkZWYuZGVmYXVsdFZhbHVlKSk7Cn07CnZhciBwcmVmYXVsdFByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIHByb2Nlc3MyKGRlZi5pbm5lclR5cGUsIGN0eCwgcGFyYW1zKTsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgc2Vlbi5yZWYgPSBkZWYuaW5uZXJUeXBlOwogIGlmIChjdHguaW8gPT09ICJpbnB1dCIpCiAgICBqc29uLl9wcmVmYXVsdCA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZGVmLmRlZmF1bHRWYWx1ZSkpOwp9Owp2YXIgY2F0Y2hQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIGpzb24sIHBhcmFtcykgPT4gewogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBwcm9jZXNzMihkZWYuaW5uZXJUeXBlLCBjdHgsIHBhcmFtcyk7CiAgY29uc3Qgc2VlbiA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIHNlZW4ucmVmID0gZGVmLmlubmVyVHlwZTsKICBsZXQgY2F0Y2hWYWx1ZTsKICB0cnkgewogICAgY2F0Y2hWYWx1ZSA9IGRlZi5jYXRjaFZhbHVlKHZvaWQgMCk7CiAgfSBjYXRjaCB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkR5bmFtaWMgY2F0Y2ggdmFsdWVzIGFyZSBub3Qgc3VwcG9ydGVkIGluIEpTT04gU2NoZW1hIik7CiAgfQogIGpzb24uZGVmYXVsdCA9IGNhdGNoVmFsdWU7Cn07CnZhciBwaXBlUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGluSXNUcmFuc2Zvcm0gPSBkZWYuaW4uX3pvZC50cmFpdHMuaGFzKCIkWm9kVHJhbnNmb3JtIik7CiAgY29uc3QgaW5uZXJUeXBlID0gY3R4LmlvID09PSAiaW5wdXQiID8gaW5Jc1RyYW5zZm9ybSA/IGRlZi5vdXQgOiBkZWYuaW4gOiBkZWYub3V0OwogIHByb2Nlc3MyKGlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGlubmVyVHlwZTsKfTsKdmFyIHJlYWRvbmx5UHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7CiAganNvbi5yZWFkT25seSA9IHRydWU7Cn07CnZhciBvcHRpb25hbFByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwgX2pzb24sIHBhcmFtcykgPT4gewogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBwcm9jZXNzMihkZWYuaW5uZXJUeXBlLCBjdHgsIHBhcmFtcyk7CiAgY29uc3Qgc2VlbiA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIHNlZW4ucmVmID0gZGVmLmlubmVyVHlwZTsKfTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY2xhc3NpYy9pc28uanMKdmFyIFpvZElTT0RhdGVUaW1lID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVNPRGF0ZVRpbWUiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZElTT0RhdGVUaW1lLmluaXQoaW5zdCwgZGVmKTsKICBab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKZnVuY3Rpb24gZGF0ZXRpbWUyKHBhcmFtcykgewogIHJldHVybiBfaXNvRGF0ZVRpbWUoWm9kSVNPRGF0ZVRpbWUsIHBhcmFtcyk7Cn0KdmFyIFpvZElTT0RhdGUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RJU09EYXRlIiwgKGluc3QsIGRlZikgPT4gewogICRab2RJU09EYXRlLmluaXQoaW5zdCwgZGVmKTsKICBab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKZnVuY3Rpb24gZGF0ZTIocGFyYW1zKSB7CiAgcmV0dXJuIF9pc29EYXRlKFpvZElTT0RhdGUsIHBhcmFtcyk7Cn0KdmFyIFpvZElTT1RpbWUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RJU09UaW1lIiwgKGluc3QsIGRlZikgPT4gewogICRab2RJU09UaW1lLmluaXQoaW5zdCwgZGVmKTsKICBab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKZnVuY3Rpb24gdGltZTIocGFyYW1zKSB7CiAgcmV0dXJuIF9pc29UaW1lKFpvZElTT1RpbWUsIHBhcmFtcyk7Cn0KdmFyIFpvZElTT0R1cmF0aW9uID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVNPRHVyYXRpb24iLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZElTT0R1cmF0aW9uLmluaXQoaW5zdCwgZGVmKTsKICBab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKZnVuY3Rpb24gZHVyYXRpb24yKHBhcmFtcykgewogIHJldHVybiBfaXNvRHVyYXRpb24oWm9kSVNPRHVyYXRpb24sIHBhcmFtcyk7Cn0KCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY2xhc3NpYy9lcnJvcnMuanMKdmFyIGluaXRpYWxpemVyMiA9IChpbnN0LCBpc3N1ZXMpID0+IHsKICAkWm9kRXJyb3IuaW5pdChpbnN0LCBpc3N1ZXMpOwogIGluc3QubmFtZSA9ICJab2RFcnJvciI7CiAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoaW5zdCwgewogICAgZm9ybWF0OiB7CiAgICAgIHZhbHVlOiAobWFwcGVyKSA9PiBmb3JtYXRFcnJvcihpbnN0LCBtYXBwZXIpCiAgICAgIC8vIGVudW1lcmFibGU6IGZhbHNlLAogICAgfSwKICAgIGZsYXR0ZW46IHsKICAgICAgdmFsdWU6IChtYXBwZXIpID0+IGZsYXR0ZW5FcnJvcihpbnN0LCBtYXBwZXIpCiAgICAgIC8vIGVudW1lcmFibGU6IGZhbHNlLAogICAgfSwKICAgIGFkZElzc3VlOiB7CiAgICAgIHZhbHVlOiAoaXNzdWUyKSA9PiB7CiAgICAgICAgaW5zdC5pc3N1ZXMucHVzaChpc3N1ZTIpOwogICAgICAgIGluc3QubWVzc2FnZSA9IEpTT04uc3RyaW5naWZ5KGluc3QuaXNzdWVzLCBqc29uU3RyaW5naWZ5UmVwbGFjZXIsIDIpOwogICAgICB9CiAgICAgIC8vIGVudW1lcmFibGU6IGZhbHNlLAogICAgfSwKICAgIGFkZElzc3VlczogewogICAgICB2YWx1ZTogKGlzc3VlczIpID0+IHsKICAgICAgICBpbnN0Lmlzc3Vlcy5wdXNoKC4uLmlzc3VlczIpOwogICAgICAgIGluc3QubWVzc2FnZSA9IEpTT04uc3RyaW5naWZ5KGluc3QuaXNzdWVzLCBqc29uU3RyaW5naWZ5UmVwbGFjZXIsIDIpOwogICAgICB9CiAgICAgIC8vIGVudW1lcmFibGU6IGZhbHNlLAogICAgfSwKICAgIGlzRW1wdHk6IHsKICAgICAgZ2V0KCkgewogICAgICAgIHJldHVybiBpbnN0Lmlzc3Vlcy5sZW5ndGggPT09IDA7CiAgICAgIH0KICAgICAgLy8gZW51bWVyYWJsZTogZmFsc2UsCiAgICB9CiAgfSk7Cn07CnZhciBab2RSZWFsRXJyb3IgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RFcnJvciIsIGluaXRpYWxpemVyMiwgewogIFBhcmVudDogRXJyb3IKfSk7CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NsYXNzaWMvcGFyc2UuanMKdmFyIHBhcnNlMiA9IC8qIEBfX1BVUkVfXyAqLyBfcGFyc2UoWm9kUmVhbEVycm9yKTsKdmFyIHBhcnNlQXN5bmMyID0gLyogQF9fUFVSRV9fICovIF9wYXJzZUFzeW5jKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlUGFyc2UyID0gLyogQF9fUFVSRV9fICovIF9zYWZlUGFyc2UoWm9kUmVhbEVycm9yKTsKdmFyIHNhZmVQYXJzZUFzeW5jMiA9IC8qIEBfX1BVUkVfXyAqLyBfc2FmZVBhcnNlQXN5bmMoWm9kUmVhbEVycm9yKTsKdmFyIGVuY29kZSA9IC8qIEBfX1BVUkVfXyAqLyBfZW5jb2RlKFpvZFJlYWxFcnJvcik7CnZhciBkZWNvZGUgPSAvKiBAX19QVVJFX18gKi8gX2RlY29kZShab2RSZWFsRXJyb3IpOwp2YXIgZW5jb2RlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX2VuY29kZUFzeW5jKFpvZFJlYWxFcnJvcik7CnZhciBkZWNvZGVBc3luYyA9IC8qIEBfX1BVUkVfXyAqLyBfZGVjb2RlQXN5bmMoWm9kUmVhbEVycm9yKTsKdmFyIHNhZmVFbmNvZGUgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVFbmNvZGUoWm9kUmVhbEVycm9yKTsKdmFyIHNhZmVEZWNvZGUgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVEZWNvZGUoWm9kUmVhbEVycm9yKTsKdmFyIHNhZmVFbmNvZGVBc3luYyA9IC8qIEBfX1BVUkVfXyAqLyBfc2FmZUVuY29kZUFzeW5jKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlRGVjb2RlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVEZWNvZGVBc3luYyhab2RSZWFsRXJyb3IpOwoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jbGFzc2ljL3NjaGVtYXMuanMKdmFyIF9pbnN0YWxsZWRHcm91cHMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFdlYWtNYXAoKTsKZnVuY3Rpb24gX2luc3RhbGxMYXp5TWV0aG9kcyhpbnN0LCBncm91cCwgbWV0aG9kcykgewogIGNvbnN0IHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKGluc3QpOwogIGxldCBpbnN0YWxsZWQgPSBfaW5zdGFsbGVkR3JvdXBzLmdldChwcm90byk7CiAgaWYgKCFpbnN0YWxsZWQpIHsKICAgIGluc3RhbGxlZCA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KCk7CiAgICBfaW5zdGFsbGVkR3JvdXBzLnNldChwcm90bywgaW5zdGFsbGVkKTsKICB9CiAgaWYgKGluc3RhbGxlZC5oYXMoZ3JvdXApKQogICAgcmV0dXJuOwogIGluc3RhbGxlZC5hZGQoZ3JvdXApOwogIGZvciAoY29uc3Qga2V5IGluIG1ldGhvZHMpIHsKICAgIGNvbnN0IGZuID0gbWV0aG9kc1trZXldOwogICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3RvLCBrZXksIHsKICAgICAgY29uZmlndXJhYmxlOiB0cnVlLAogICAgICBlbnVtZXJhYmxlOiBmYWxzZSwKICAgICAgZ2V0KCkgewogICAgICAgIGNvbnN0IGJvdW5kID0gZm4uYmluZCh0aGlzKTsKICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywga2V5LCB7CiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsCiAgICAgICAgICB3cml0YWJsZTogdHJ1ZSwKICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsCiAgICAgICAgICB2YWx1ZTogYm91bmQKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gYm91bmQ7CiAgICAgIH0sCiAgICAgIHNldCh2KSB7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIGtleSwgewogICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLAogICAgICAgICAgd3JpdGFibGU6IHRydWUsCiAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgICAgICAgdmFsdWU6IHYKICAgICAgICB9KTsKICAgICAgfQogICAgfSk7CiAgfQp9CnZhciBab2RUeXBlID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVHlwZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgT2JqZWN0LmFzc2lnbihpbnN0WyJ+c3RhbmRhcmQiXSwgewogICAganNvblNjaGVtYTogewogICAgICBpbnB1dDogY3JlYXRlU3RhbmRhcmRKU09OU2NoZW1hTWV0aG9kKGluc3QsICJpbnB1dCIpLAogICAgICBvdXRwdXQ6IGNyZWF0ZVN0YW5kYXJkSlNPTlNjaGVtYU1ldGhvZChpbnN0LCAib3V0cHV0IikKICAgIH0KICB9KTsKICBpbnN0LnRvSlNPTlNjaGVtYSA9IGNyZWF0ZVRvSlNPTlNjaGVtYU1ldGhvZChpbnN0LCB7fSk7CiAgaW5zdC5kZWYgPSBkZWY7CiAgaW5zdC50eXBlID0gZGVmLnR5cGU7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGluc3QsICJfZGVmIiwgeyB2YWx1ZTogZGVmIH0pOwogIGluc3QucGFyc2UgPSAoZGF0YSwgcGFyYW1zKSA9PiBwYXJzZTIoaW5zdCwgZGF0YSwgcGFyYW1zLCB7IGNhbGxlZTogaW5zdC5wYXJzZSB9KTsKICBpbnN0LnNhZmVQYXJzZSA9IChkYXRhLCBwYXJhbXMpID0+IHNhZmVQYXJzZTIoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LnBhcnNlQXN5bmMgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiBwYXJzZUFzeW5jMihpbnN0LCBkYXRhLCBwYXJhbXMsIHsgY2FsbGVlOiBpbnN0LnBhcnNlQXN5bmMgfSk7CiAgaW5zdC5zYWZlUGFyc2VBc3luYyA9IGFzeW5jIChkYXRhLCBwYXJhbXMpID0+IHNhZmVQYXJzZUFzeW5jMihpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3Quc3BhID0gaW5zdC5zYWZlUGFyc2VBc3luYzsKICBpbnN0LmVuY29kZSA9IChkYXRhLCBwYXJhbXMpID0+IGVuY29kZShpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3QuZGVjb2RlID0gKGRhdGEsIHBhcmFtcykgPT4gZGVjb2RlKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgaW5zdC5lbmNvZGVBc3luYyA9IGFzeW5jIChkYXRhLCBwYXJhbXMpID0+IGVuY29kZUFzeW5jKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgaW5zdC5kZWNvZGVBc3luYyA9IGFzeW5jIChkYXRhLCBwYXJhbXMpID0+IGRlY29kZUFzeW5jKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgaW5zdC5zYWZlRW5jb2RlID0gKGRhdGEsIHBhcmFtcykgPT4gc2FmZUVuY29kZShpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3Quc2FmZURlY29kZSA9IChkYXRhLCBwYXJhbXMpID0+IHNhZmVEZWNvZGUoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LnNhZmVFbmNvZGVBc3luYyA9IGFzeW5jIChkYXRhLCBwYXJhbXMpID0+IHNhZmVFbmNvZGVBc3luYyhpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3Quc2FmZURlY29kZUFzeW5jID0gYXN5bmMgKGRhdGEsIHBhcmFtcykgPT4gc2FmZURlY29kZUFzeW5jKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgX2luc3RhbGxMYXp5TWV0aG9kcyhpbnN0LCAiWm9kVHlwZSIsIHsKICAgIGNoZWNrKC4uLmNoa3MpIHsKICAgICAgY29uc3QgZGVmMiA9IHRoaXMuZGVmOwogICAgICByZXR1cm4gdGhpcy5jbG9uZSh1dGlsX2V4cG9ydHMubWVyZ2VEZWZzKGRlZjIsIHsKICAgICAgICBjaGVja3M6IFsKICAgICAgICAgIC4uLmRlZjIuY2hlY2tzID8/IFtdLAogICAgICAgICAgLi4uY2hrcy5tYXAoKGNoKSA9PiB0eXBlb2YgY2ggPT09ICJmdW5jdGlvbiIgPyB7IF96b2Q6IHsgY2hlY2s6IGNoLCBkZWY6IHsgY2hlY2s6ICJjdXN0b20iIH0sIG9uYXR0YWNoOiBbXSB9IH0gOiBjaCkKICAgICAgICBdCiAgICAgIH0pLCB7IHBhcmVudDogdHJ1ZSB9KTsKICAgIH0sCiAgICB3aXRoKC4uLmNoa3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soLi4uY2hrcyk7CiAgICB9LAogICAgY2xvbmUoZGVmMiwgcGFyYW1zKSB7CiAgICAgIHJldHVybiBjbG9uZSh0aGlzLCBkZWYyLCBwYXJhbXMpOwogICAgfSwKICAgIGJyYW5kKCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH0sCiAgICByZWdpc3RlcihyZWcsIG1ldGEyKSB7CiAgICAgIHJlZy5hZGQodGhpcywgbWV0YTIpOwogICAgICByZXR1cm4gdGhpczsKICAgIH0sCiAgICByZWZpbmUoY2hlY2ssIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhyZWZpbmUoY2hlY2ssIHBhcmFtcykpOwogICAgfSwKICAgIHN1cGVyUmVmaW5lKHJlZmluZW1lbnQsIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhzdXBlclJlZmluZShyZWZpbmVtZW50LCBwYXJhbXMpKTsKICAgIH0sCiAgICBvdmVyd3JpdGUoZm4pIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX292ZXJ3cml0ZShmbikpOwogICAgfSwKICAgIG9wdGlvbmFsKCkgewogICAgICByZXR1cm4gb3B0aW9uYWwodGhpcyk7CiAgICB9LAogICAgZXhhY3RPcHRpb25hbCgpIHsKICAgICAgcmV0dXJuIGV4YWN0T3B0aW9uYWwodGhpcyk7CiAgICB9LAogICAgbnVsbGFibGUoKSB7CiAgICAgIHJldHVybiBudWxsYWJsZSh0aGlzKTsKICAgIH0sCiAgICBudWxsaXNoKCkgewogICAgICByZXR1cm4gb3B0aW9uYWwobnVsbGFibGUodGhpcykpOwogICAgfSwKICAgIG5vbm9wdGlvbmFsKHBhcmFtcykgewogICAgICByZXR1cm4gbm9ub3B0aW9uYWwodGhpcywgcGFyYW1zKTsKICAgIH0sCiAgICBhcnJheSgpIHsKICAgICAgcmV0dXJuIGFycmF5KHRoaXMpOwogICAgfSwKICAgIG9yKGFyZykgewogICAgICByZXR1cm4gdW5pb24oW3RoaXMsIGFyZ10pOwogICAgfSwKICAgIGFuZChhcmcpIHsKICAgICAgcmV0dXJuIGludGVyc2VjdGlvbih0aGlzLCBhcmcpOwogICAgfSwKICAgIHRyYW5zZm9ybSh0eCkgewogICAgICByZXR1cm4gcGlwZSh0aGlzLCB0cmFuc2Zvcm0odHgpKTsKICAgIH0sCiAgICBkZWZhdWx0KGQpIHsKICAgICAgcmV0dXJuIF9kZWZhdWx0KHRoaXMsIGQpOwogICAgfSwKICAgIHByZWZhdWx0KGQpIHsKICAgICAgcmV0dXJuIHByZWZhdWx0KHRoaXMsIGQpOwogICAgfSwKICAgIGNhdGNoKHBhcmFtcykgewogICAgICByZXR1cm4gX2NhdGNoKHRoaXMsIHBhcmFtcyk7CiAgICB9LAogICAgcGlwZSh0YXJnZXQpIHsKICAgICAgcmV0dXJuIHBpcGUodGhpcywgdGFyZ2V0KTsKICAgIH0sCiAgICByZWFkb25seSgpIHsKICAgICAgcmV0dXJuIHJlYWRvbmx5KHRoaXMpOwogICAgfSwKICAgIGRlc2NyaWJlKGRlc2NyaXB0aW9uKSB7CiAgICAgIGNvbnN0IGNsID0gdGhpcy5jbG9uZSgpOwogICAgICBnbG9iYWxSZWdpc3RyeS5hZGQoY2wsIHsgZGVzY3JpcHRpb24gfSk7CiAgICAgIHJldHVybiBjbDsKICAgIH0sCiAgICBtZXRhKC4uLmFyZ3MpIHsKICAgICAgaWYgKGFyZ3MubGVuZ3RoID09PSAwKQogICAgICAgIHJldHVybiBnbG9iYWxSZWdpc3RyeS5nZXQodGhpcyk7CiAgICAgIGNvbnN0IGNsID0gdGhpcy5jbG9uZSgpOwogICAgICBnbG9iYWxSZWdpc3RyeS5hZGQoY2wsIGFyZ3NbMF0pOwogICAgICByZXR1cm4gY2w7CiAgICB9LAogICAgaXNPcHRpb25hbCgpIHsKICAgICAgcmV0dXJuIHRoaXMuc2FmZVBhcnNlKHZvaWQgMCkuc3VjY2VzczsKICAgIH0sCiAgICBpc051bGxhYmxlKCkgewogICAgICByZXR1cm4gdGhpcy5zYWZlUGFyc2UobnVsbCkuc3VjY2VzczsKICAgIH0sCiAgICBhcHBseShmbikgewogICAgICByZXR1cm4gZm4odGhpcyk7CiAgICB9CiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGluc3QsICJkZXNjcmlwdGlvbiIsIHsKICAgIGdldCgpIHsKICAgICAgcmV0dXJuIGdsb2JhbFJlZ2lzdHJ5LmdldChpbnN0KT8uZGVzY3JpcHRpb247CiAgICB9LAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgcmV0dXJuIGluc3Q7Cn0pOwp2YXIgX1pvZFN0cmluZyA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIl9ab2RTdHJpbmciLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFN0cmluZy5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBzdHJpbmdQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGNvbnN0IGJhZyA9IGluc3QuX3pvZC5iYWc7CiAgaW5zdC5mb3JtYXQgPSBiYWcuZm9ybWF0ID8/IG51bGw7CiAgaW5zdC5taW5MZW5ndGggPSBiYWcubWluaW11bSA/PyBudWxsOwogIGluc3QubWF4TGVuZ3RoID0gYmFnLm1heGltdW0gPz8gbnVsbDsKICBfaW5zdGFsbExhenlNZXRob2RzKGluc3QsICJfWm9kU3RyaW5nIiwgewogICAgcmVnZXgoLi4uYXJncykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfcmVnZXgoLi4uYXJncykpOwogICAgfSwKICAgIGluY2x1ZGVzKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2luY2x1ZGVzKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBzdGFydHNXaXRoKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX3N0YXJ0c1dpdGgoLi4uYXJncykpOwogICAgfSwKICAgIGVuZHNXaXRoKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2VuZHNXaXRoKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBtaW4oLi4uYXJncykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbWluTGVuZ3RoKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBtYXgoLi4uYXJncykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbWF4TGVuZ3RoKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBsZW5ndGgoLi4uYXJncykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbGVuZ3RoKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBub25lbXB0eSguLi5hcmdzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9taW5MZW5ndGgoMSwgLi4uYXJncykpOwogICAgfSwKICAgIGxvd2VyY2FzZShwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2xvd2VyY2FzZShwYXJhbXMpKTsKICAgIH0sCiAgICB1cHBlcmNhc2UocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF91cHBlcmNhc2UocGFyYW1zKSk7CiAgICB9LAogICAgdHJpbSgpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX3RyaW0oKSk7CiAgICB9LAogICAgbm9ybWFsaXplKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX25vcm1hbGl6ZSguLi5hcmdzKSk7CiAgICB9LAogICAgdG9Mb3dlckNhc2UoKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF90b0xvd2VyQ2FzZSgpKTsKICAgIH0sCiAgICB0b1VwcGVyQ2FzZSgpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX3RvVXBwZXJDYXNlKCkpOwogICAgfSwKICAgIHNsdWdpZnkoKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9zbHVnaWZ5KCkpOwogICAgfQogIH0pOwp9KTsKdmFyIFpvZFN0cmluZyA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFN0cmluZyIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kU3RyaW5nLmluaXQoaW5zdCwgZGVmKTsKICBfWm9kU3RyaW5nLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0LmVtYWlsID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfZW1haWwoWm9kRW1haWwsIHBhcmFtcykpOwogIGluc3QudXJsID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfdXJsKFpvZFVSTCwgcGFyYW1zKSk7CiAgaW5zdC5qd3QgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9qd3QoWm9kSldULCBwYXJhbXMpKTsKICBpbnN0LmVtb2ppID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfZW1vamkyKFpvZEVtb2ppLCBwYXJhbXMpKTsKICBpbnN0Lmd1aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9ndWlkKFpvZEdVSUQsIHBhcmFtcykpOwogIGluc3QudXVpZCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX3V1aWQoWm9kVVVJRCwgcGFyYW1zKSk7CiAgaW5zdC51dWlkdjQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF91dWlkdjQoWm9kVVVJRCwgcGFyYW1zKSk7CiAgaW5zdC51dWlkdjYgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF91dWlkdjYoWm9kVVVJRCwgcGFyYW1zKSk7CiAgaW5zdC51dWlkdjcgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF91dWlkdjcoWm9kVVVJRCwgcGFyYW1zKSk7CiAgaW5zdC5uYW5vaWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9uYW5vaWQoWm9kTmFub0lELCBwYXJhbXMpKTsKICBpbnN0Lmd1aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9ndWlkKFpvZEdVSUQsIHBhcmFtcykpOwogIGluc3QuY3VpZCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2N1aWQoWm9kQ1VJRCwgcGFyYW1zKSk7CiAgaW5zdC5jdWlkMiA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2N1aWQyKFpvZENVSUQyLCBwYXJhbXMpKTsKICBpbnN0LnVsaWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF91bGlkKFpvZFVMSUQsIHBhcmFtcykpOwogIGluc3QuYmFzZTY0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfYmFzZTY0KFpvZEJhc2U2NCwgcGFyYW1zKSk7CiAgaW5zdC5iYXNlNjR1cmwgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9iYXNlNjR1cmwoWm9kQmFzZTY0VVJMLCBwYXJhbXMpKTsKICBpbnN0LnhpZCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX3hpZChab2RYSUQsIHBhcmFtcykpOwogIGluc3Qua3N1aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9rc3VpZChab2RLU1VJRCwgcGFyYW1zKSk7CiAgaW5zdC5pcHY0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfaXB2NChab2RJUHY0LCBwYXJhbXMpKTsKICBpbnN0LmlwdjYgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9pcHY2KFpvZElQdjYsIHBhcmFtcykpOwogIGluc3QuY2lkcnY0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfY2lkcnY0KFpvZENJRFJ2NCwgcGFyYW1zKSk7CiAgaW5zdC5jaWRydjYgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9jaWRydjYoWm9kQ0lEUnY2LCBwYXJhbXMpKTsKICBpbnN0LmUxNjQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9lMTY0KFpvZEUxNjQsIHBhcmFtcykpOwogIGluc3QuZGF0ZXRpbWUgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKGRhdGV0aW1lMihwYXJhbXMpKTsKICBpbnN0LmRhdGUgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKGRhdGUyKHBhcmFtcykpOwogIGluc3QudGltZSA9IChwYXJhbXMpID0+IGluc3QuY2hlY2sodGltZTIocGFyYW1zKSk7CiAgaW5zdC5kdXJhdGlvbiA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soZHVyYXRpb24yKHBhcmFtcykpOwp9KTsKZnVuY3Rpb24gc3RyaW5nMihwYXJhbXMpIHsKICByZXR1cm4gX3N0cmluZyhab2RTdHJpbmcsIHBhcmFtcyk7Cn0KdmFyIFpvZFN0cmluZ0Zvcm1hdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFN0cmluZ0Zvcm1hdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBfWm9kU3RyaW5nLmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RFbWFpbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEVtYWlsIiwgKGluc3QsIGRlZikgPT4gewogICRab2RFbWFpbC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RHVUlEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kR1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kR1VJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RVVUlEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVVVJRCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVVVJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RVUkwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RVUkwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFVSTC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RFbW9qaSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEVtb2ppIiwgKGluc3QsIGRlZikgPT4gewogICRab2RFbW9qaS5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2ROYW5vSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2ROYW5vSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE5hbm9JRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RDVUlEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQ1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ1VJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RDVUlEMiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZENVSUQyIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDVUlEMi5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RVTElEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVUxJRCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVUxJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RYSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RYSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFhJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RLU1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEtTVUlEIiwgKGluc3QsIGRlZikgPT4gewogICRab2RLU1VJRC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RJUHY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVB2NCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kSVB2NC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RJUHY2ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVB2NiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kSVB2Ni5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RDSURSdjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RDSURSdjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENJRFJ2NC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RDSURSdjYgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RDSURSdjYiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENJRFJ2Ni5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RCYXNlNjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RCYXNlNjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEJhc2U2NC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RCYXNlNjRVUkwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RCYXNlNjRVUkwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEJhc2U2NFVSTC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RFMTY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kRTE2NCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRTE2NC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2RKV1QgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RKV1QiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEpXVC5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciBab2ROdW1iZXIgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2ROdW1iZXIiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE51bWJlci5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBudW1iZXJQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIF9pbnN0YWxsTGF6eU1ldGhvZHMoaW5zdCwgIlpvZE51bWJlciIsIHsKICAgIGd0KHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2d0KHZhbHVlLCBwYXJhbXMpKTsKICAgIH0sCiAgICBndGUodmFsdWUsIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfZ3RlKHZhbHVlLCBwYXJhbXMpKTsKICAgIH0sCiAgICBtaW4odmFsdWUsIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfZ3RlKHZhbHVlLCBwYXJhbXMpKTsKICAgIH0sCiAgICBsdCh2YWx1ZSwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sdCh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgbHRlKHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2x0ZSh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgbWF4KHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2x0ZSh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgaW50KHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhpbnQocGFyYW1zKSk7CiAgICB9LAogICAgc2FmZShwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soaW50KHBhcmFtcykpOwogICAgfSwKICAgIHBvc2l0aXZlKHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfZ3QoMCwgcGFyYW1zKSk7CiAgICB9LAogICAgbm9ubmVnYXRpdmUocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9ndGUoMCwgcGFyYW1zKSk7CiAgICB9LAogICAgbmVnYXRpdmUocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sdCgwLCBwYXJhbXMpKTsKICAgIH0sCiAgICBub25wb3NpdGl2ZShwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2x0ZSgwLCBwYXJhbXMpKTsKICAgIH0sCiAgICBtdWx0aXBsZU9mKHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX211bHRpcGxlT2YodmFsdWUsIHBhcmFtcykpOwogICAgfSwKICAgIHN0ZXAodmFsdWUsIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbXVsdGlwbGVPZih2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgZmluaXRlKCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH0KICB9KTsKICBjb25zdCBiYWcgPSBpbnN0Ll96b2QuYmFnOwogIGluc3QubWluVmFsdWUgPSBNYXRoLm1heChiYWcubWluaW11bSA/PyBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFksIGJhZy5leGNsdXNpdmVNaW5pbXVtID8/IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSkgPz8gbnVsbDsKICBpbnN0Lm1heFZhbHVlID0gTWF0aC5taW4oYmFnLm1heGltdW0gPz8gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLCBiYWcuZXhjbHVzaXZlTWF4aW11bSA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpID8/IG51bGw7CiAgaW5zdC5pc0ludCA9IChiYWcuZm9ybWF0ID8/ICIiKS5pbmNsdWRlcygiaW50IikgfHwgTnVtYmVyLmlzU2FmZUludGVnZXIoYmFnLm11bHRpcGxlT2YgPz8gMC41KTsKICBpbnN0LmlzRmluaXRlID0gdHJ1ZTsKICBpbnN0LmZvcm1hdCA9IGJhZy5mb3JtYXQgPz8gbnVsbDsKfSk7CmZ1bmN0aW9uIG51bWJlcjIocGFyYW1zKSB7CiAgcmV0dXJuIF9udW1iZXIoWm9kTnVtYmVyLCBwYXJhbXMpOwp9CnZhciBab2ROdW1iZXJGb3JtYXQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2ROdW1iZXJGb3JtYXQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE51bWJlckZvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgWm9kTnVtYmVyLmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIGludChwYXJhbXMpIHsKICByZXR1cm4gX2ludChab2ROdW1iZXJGb3JtYXQsIHBhcmFtcyk7Cn0KdmFyIFpvZFVua25vd24gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RVbmtub3duIiwgKGluc3QsIGRlZikgPT4gewogICRab2RVbmtub3duLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHVua25vd25Qcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwp9KTsKZnVuY3Rpb24gdW5rbm93bigpIHsKICByZXR1cm4gX3Vua25vd24oWm9kVW5rbm93bik7Cn0KdmFyIFpvZE5ldmVyID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kTmV2ZXIiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE5ldmVyLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IG5ldmVyUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKfSk7CmZ1bmN0aW9uIG5ldmVyKHBhcmFtcykgewogIHJldHVybiBfbmV2ZXIoWm9kTmV2ZXIsIHBhcmFtcyk7Cn0KdmFyIFpvZEFycmF5ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQXJyYXkiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEFycmF5LmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IGFycmF5UHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LmVsZW1lbnQgPSBkZWYuZWxlbWVudDsKICBfaW5zdGFsbExhenlNZXRob2RzKGluc3QsICJab2RBcnJheSIsIHsKICAgIG1pbihuLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX21pbkxlbmd0aChuLCBwYXJhbXMpKTsKICAgIH0sCiAgICBub25lbXB0eShwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX21pbkxlbmd0aCgxLCBwYXJhbXMpKTsKICAgIH0sCiAgICBtYXgobiwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9tYXhMZW5ndGgobiwgcGFyYW1zKSk7CiAgICB9LAogICAgbGVuZ3RoKG4sIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbGVuZ3RoKG4sIHBhcmFtcykpOwogICAgfSwKICAgIHVud3JhcCgpIHsKICAgICAgcmV0dXJuIHRoaXMuZWxlbWVudDsKICAgIH0KICB9KTsKfSk7CmZ1bmN0aW9uIGFycmF5KGVsZW1lbnQsIHBhcmFtcykgewogIHJldHVybiBfYXJyYXkoWm9kQXJyYXksIGVsZW1lbnQsIHBhcmFtcyk7Cn0KdmFyIFpvZE9iamVjdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZE9iamVjdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kT2JqZWN0SklULmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IG9iamVjdFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgdXRpbF9leHBvcnRzLmRlZmluZUxhenkoaW5zdCwgInNoYXBlIiwgKCkgPT4gewogICAgcmV0dXJuIGRlZi5zaGFwZTsKICB9KTsKICBfaW5zdGFsbExhenlNZXRob2RzKGluc3QsICJab2RPYmplY3QiLCB7CiAgICBrZXlvZigpIHsKICAgICAgcmV0dXJuIF9lbnVtKE9iamVjdC5rZXlzKHRoaXMuX3pvZC5kZWYuc2hhcGUpKTsKICAgIH0sCiAgICBjYXRjaGFsbChjYXRjaGFsbCkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLnRoaXMuX3pvZC5kZWYsIGNhdGNoYWxsIH0pOwogICAgfSwKICAgIHBhc3N0aHJvdWdoKCkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLnRoaXMuX3pvZC5kZWYsIGNhdGNoYWxsOiB1bmtub3duKCkgfSk7CiAgICB9LAogICAgbG9vc2UoKSB7CiAgICAgIHJldHVybiB0aGlzLmNsb25lKHsgLi4udGhpcy5fem9kLmRlZiwgY2F0Y2hhbGw6IHVua25vd24oKSB9KTsKICAgIH0sCiAgICBzdHJpY3QoKSB7CiAgICAgIHJldHVybiB0aGlzLmNsb25lKHsgLi4udGhpcy5fem9kLmRlZiwgY2F0Y2hhbGw6IG5ldmVyKCkgfSk7CiAgICB9LAogICAgc3RyaXAoKSB7CiAgICAgIHJldHVybiB0aGlzLmNsb25lKHsgLi4udGhpcy5fem9kLmRlZiwgY2F0Y2hhbGw6IHZvaWQgMCB9KTsKICAgIH0sCiAgICBleHRlbmQoaW5jb21pbmcpIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5leHRlbmQodGhpcywgaW5jb21pbmcpOwogICAgfSwKICAgIHNhZmVFeHRlbmQoaW5jb21pbmcpIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5zYWZlRXh0ZW5kKHRoaXMsIGluY29taW5nKTsKICAgIH0sCiAgICBtZXJnZShvdGhlcikgewogICAgICByZXR1cm4gdXRpbF9leHBvcnRzLm1lcmdlKHRoaXMsIG90aGVyKTsKICAgIH0sCiAgICBwaWNrKG1hc2spIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5waWNrKHRoaXMsIG1hc2spOwogICAgfSwKICAgIG9taXQobWFzaykgewogICAgICByZXR1cm4gdXRpbF9leHBvcnRzLm9taXQodGhpcywgbWFzayk7CiAgICB9LAogICAgcGFydGlhbCguLi5hcmdzKSB7CiAgICAgIHJldHVybiB1dGlsX2V4cG9ydHMucGFydGlhbChab2RPcHRpb25hbCwgdGhpcywgYXJnc1swXSk7CiAgICB9LAogICAgcmVxdWlyZWQoLi4uYXJncykgewogICAgICByZXR1cm4gdXRpbF9leHBvcnRzLnJlcXVpcmVkKFpvZE5vbk9wdGlvbmFsLCB0aGlzLCBhcmdzWzBdKTsKICAgIH0KICB9KTsKfSk7CmZ1bmN0aW9uIG9iamVjdChzaGFwZSwgcGFyYW1zKSB7CiAgY29uc3QgZGVmID0gewogICAgdHlwZTogIm9iamVjdCIsCiAgICBzaGFwZTogc2hhcGUgPz8ge30sCiAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9OwogIHJldHVybiBuZXcgWm9kT2JqZWN0KGRlZik7Cn0KdmFyIFpvZFVuaW9uID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVW5pb24iLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFVuaW9uLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHVuaW9uUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0Lm9wdGlvbnMgPSBkZWYub3B0aW9uczsKfSk7CmZ1bmN0aW9uIHVuaW9uKG9wdGlvbnMsIHBhcmFtcykgewogIHJldHVybiBuZXcgWm9kVW5pb24oewogICAgdHlwZTogInVuaW9uIiwKICAgIG9wdGlvbnMsCiAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQp2YXIgWm9kSW50ZXJzZWN0aW9uID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSW50ZXJzZWN0aW9uIiwgKGluc3QsIGRlZikgPT4gewogICRab2RJbnRlcnNlY3Rpb24uaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gaW50ZXJzZWN0aW9uUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKfSk7CmZ1bmN0aW9uIGludGVyc2VjdGlvbihsZWZ0LCByaWdodCkgewogIHJldHVybiBuZXcgWm9kSW50ZXJzZWN0aW9uKHsKICAgIHR5cGU6ICJpbnRlcnNlY3Rpb24iLAogICAgbGVmdCwKICAgIHJpZ2h0CiAgfSk7Cn0KdmFyIFpvZFJlY29yZCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFJlY29yZCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kUmVjb3JkLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHJlY29yZFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC5rZXlUeXBlID0gZGVmLmtleVR5cGU7CiAgaW5zdC52YWx1ZVR5cGUgPSBkZWYudmFsdWVUeXBlOwp9KTsKZnVuY3Rpb24gcmVjb3JkKGtleVR5cGUsIHZhbHVlVHlwZSwgcGFyYW1zKSB7CiAgaWYgKCF2YWx1ZVR5cGUgfHwgIXZhbHVlVHlwZS5fem9kKSB7CiAgICByZXR1cm4gbmV3IFpvZFJlY29yZCh7CiAgICAgIHR5cGU6ICJyZWNvcmQiLAogICAgICBrZXlUeXBlOiBzdHJpbmcyKCksCiAgICAgIHZhbHVlVHlwZToga2V5VHlwZSwKICAgICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyh2YWx1ZVR5cGUpCiAgICB9KTsKICB9CiAgcmV0dXJuIG5ldyBab2RSZWNvcmQoewogICAgdHlwZTogInJlY29yZCIsCiAgICBrZXlUeXBlLAogICAgdmFsdWVUeXBlLAogICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KdmFyIFpvZEVudW0gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RFbnVtIiwgKGluc3QsIGRlZikgPT4gewogICRab2RFbnVtLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IGVudW1Qcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3QuZW51bSA9IGRlZi5lbnRyaWVzOwogIGluc3Qub3B0aW9ucyA9IE9iamVjdC52YWx1ZXMoZGVmLmVudHJpZXMpOwogIGNvbnN0IGtleXMgPSBuZXcgU2V0KE9iamVjdC5rZXlzKGRlZi5lbnRyaWVzKSk7CiAgaW5zdC5leHRyYWN0ID0gKHZhbHVlcywgcGFyYW1zKSA9PiB7CiAgICBjb25zdCBuZXdFbnRyaWVzID0ge307CiAgICBmb3IgKGNvbnN0IHZhbHVlIG9mIHZhbHVlcykgewogICAgICBpZiAoa2V5cy5oYXModmFsdWUpKSB7CiAgICAgICAgbmV3RW50cmllc1t2YWx1ZV0gPSBkZWYuZW50cmllc1t2YWx1ZV07CiAgICAgIH0gZWxzZQogICAgICAgIHRocm93IG5ldyBFcnJvcihgS2V5ICR7dmFsdWV9IG5vdCBmb3VuZCBpbiBlbnVtYCk7CiAgICB9CiAgICByZXR1cm4gbmV3IFpvZEVudW0oewogICAgICAuLi5kZWYsCiAgICAgIGNoZWNrczogW10sCiAgICAgIC4uLnV0aWxfZXhwb3J0cy5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgICAgZW50cmllczogbmV3RW50cmllcwogICAgfSk7CiAgfTsKICBpbnN0LmV4Y2x1ZGUgPSAodmFsdWVzLCBwYXJhbXMpID0+IHsKICAgIGNvbnN0IG5ld0VudHJpZXMgPSB7IC4uLmRlZi5lbnRyaWVzIH07CiAgICBmb3IgKGNvbnN0IHZhbHVlIG9mIHZhbHVlcykgewogICAgICBpZiAoa2V5cy5oYXModmFsdWUpKSB7CiAgICAgICAgZGVsZXRlIG5ld0VudHJpZXNbdmFsdWVdOwogICAgICB9IGVsc2UKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEtleSAke3ZhbHVlfSBub3QgZm91bmQgaW4gZW51bWApOwogICAgfQogICAgcmV0dXJuIG5ldyBab2RFbnVtKHsKICAgICAgLi4uZGVmLAogICAgICBjaGVja3M6IFtdLAogICAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICAgIGVudHJpZXM6IG5ld0VudHJpZXMKICAgIH0pOwogIH07Cn0pOwpmdW5jdGlvbiBfZW51bSh2YWx1ZXMsIHBhcmFtcykgewogIGNvbnN0IGVudHJpZXMgPSBBcnJheS5pc0FycmF5KHZhbHVlcykgPyBPYmplY3QuZnJvbUVudHJpZXModmFsdWVzLm1hcCgodikgPT4gW3YsIHZdKSkgOiB2YWx1ZXM7CiAgcmV0dXJuIG5ldyBab2RFbnVtKHsKICAgIHR5cGU6ICJlbnVtIiwKICAgIGVudHJpZXMsCiAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQp2YXIgWm9kVHJhbnNmb3JtID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVHJhbnNmb3JtIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUcmFuc2Zvcm0uaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gdHJhbnNmb3JtUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgaWYgKF9jdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgIHRocm93IG5ldyAkWm9kRW5jb2RlRXJyb3IoaW5zdC5jb25zdHJ1Y3Rvci5uYW1lKTsKICAgIH0KICAgIHBheWxvYWQuYWRkSXNzdWUgPSAoaXNzdWUyKSA9PiB7CiAgICAgIGlmICh0eXBlb2YgaXNzdWUyID09PSAic3RyaW5nIikgewogICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2godXRpbF9leHBvcnRzLmlzc3VlKGlzc3VlMiwgcGF5bG9hZC52YWx1ZSwgZGVmKSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgX2lzc3VlID0gaXNzdWUyOwogICAgICAgIGlmIChfaXNzdWUuZmF0YWwpCiAgICAgICAgICBfaXNzdWUuY29udGludWUgPSBmYWxzZTsKICAgICAgICBfaXNzdWUuY29kZSA/PyAoX2lzc3VlLmNvZGUgPSAiY3VzdG9tIik7CiAgICAgICAgX2lzc3VlLmlucHV0ID8/IChfaXNzdWUuaW5wdXQgPSBwYXlsb2FkLnZhbHVlKTsKICAgICAgICBfaXNzdWUuaW5zdCA/PyAoX2lzc3VlLmluc3QgPSBpbnN0KTsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHV0aWxfZXhwb3J0cy5pc3N1ZShfaXNzdWUpKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IG91dHB1dCA9IGRlZi50cmFuc2Zvcm0ocGF5bG9hZC52YWx1ZSwgcGF5bG9hZCk7CiAgICBpZiAob3V0cHV0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gb3V0cHV0LnRoZW4oKG91dHB1dDIpID0+IHsKICAgICAgICBwYXlsb2FkLnZhbHVlID0gb3V0cHV0MjsKICAgICAgICBwYXlsb2FkLmZhbGxiYWNrID0gdHJ1ZTsKICAgICAgICByZXR1cm4gcGF5bG9hZDsKICAgICAgfSk7CiAgICB9CiAgICBwYXlsb2FkLnZhbHVlID0gb3V0cHV0OwogICAgcGF5bG9hZC5mYWxsYmFjayA9IHRydWU7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKZnVuY3Rpb24gdHJhbnNmb3JtKGZuKSB7CiAgcmV0dXJuIG5ldyBab2RUcmFuc2Zvcm0oewogICAgdHlwZTogInRyYW5zZm9ybSIsCiAgICB0cmFuc2Zvcm06IGZuCiAgfSk7Cn0KdmFyIFpvZE9wdGlvbmFsID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kT3B0aW9uYWwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE9wdGlvbmFsLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IG9wdGlvbmFsUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwp9KTsKZnVuY3Rpb24gb3B0aW9uYWwoaW5uZXJUeXBlKSB7CiAgcmV0dXJuIG5ldyBab2RPcHRpb25hbCh7CiAgICB0eXBlOiAib3B0aW9uYWwiLAogICAgaW5uZXJUeXBlCiAgfSk7Cn0KdmFyIFpvZEV4YWN0T3B0aW9uYWwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RFeGFjdE9wdGlvbmFsIiwgKGluc3QsIGRlZikgPT4gewogICRab2RFeGFjdE9wdGlvbmFsLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IG9wdGlvbmFsUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwp9KTsKZnVuY3Rpb24gZXhhY3RPcHRpb25hbChpbm5lclR5cGUpIHsKICByZXR1cm4gbmV3IFpvZEV4YWN0T3B0aW9uYWwoewogICAgdHlwZTogIm9wdGlvbmFsIiwKICAgIGlubmVyVHlwZQogIH0pOwp9CnZhciBab2ROdWxsYWJsZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZE51bGxhYmxlIiwgKGluc3QsIGRlZikgPT4gewogICRab2ROdWxsYWJsZS5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBudWxsYWJsZVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKfSk7CmZ1bmN0aW9uIG51bGxhYmxlKGlubmVyVHlwZSkgewogIHJldHVybiBuZXcgWm9kTnVsbGFibGUoewogICAgdHlwZTogIm51bGxhYmxlIiwKICAgIGlubmVyVHlwZQogIH0pOwp9CnZhciBab2REZWZhdWx0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kRGVmYXVsdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRGVmYXVsdC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBkZWZhdWx0UHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwogIGluc3QucmVtb3ZlRGVmYXVsdCA9IGluc3QudW53cmFwOwp9KTsKZnVuY3Rpb24gX2RlZmF1bHQoaW5uZXJUeXBlLCBkZWZhdWx0VmFsdWUpIHsKICByZXR1cm4gbmV3IFpvZERlZmF1bHQoewogICAgdHlwZTogImRlZmF1bHQiLAogICAgaW5uZXJUeXBlLAogICAgZ2V0IGRlZmF1bHRWYWx1ZSgpIHsKICAgICAgcmV0dXJuIHR5cGVvZiBkZWZhdWx0VmFsdWUgPT09ICJmdW5jdGlvbiIgPyBkZWZhdWx0VmFsdWUoKSA6IHV0aWxfZXhwb3J0cy5zaGFsbG93Q2xvbmUoZGVmYXVsdFZhbHVlKTsKICAgIH0KICB9KTsKfQp2YXIgWm9kUHJlZmF1bHQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RQcmVmYXVsdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kUHJlZmF1bHQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gcHJlZmF1bHRQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3QudW53cmFwID0gKCkgPT4gaW5zdC5fem9kLmRlZi5pbm5lclR5cGU7Cn0pOwpmdW5jdGlvbiBwcmVmYXVsdChpbm5lclR5cGUsIGRlZmF1bHRWYWx1ZSkgewogIHJldHVybiBuZXcgWm9kUHJlZmF1bHQoewogICAgdHlwZTogInByZWZhdWx0IiwKICAgIGlubmVyVHlwZSwKICAgIGdldCBkZWZhdWx0VmFsdWUoKSB7CiAgICAgIHJldHVybiB0eXBlb2YgZGVmYXVsdFZhbHVlID09PSAiZnVuY3Rpb24iID8gZGVmYXVsdFZhbHVlKCkgOiB1dGlsX2V4cG9ydHMuc2hhbGxvd0Nsb25lKGRlZmF1bHRWYWx1ZSk7CiAgICB9CiAgfSk7Cn0KdmFyIFpvZE5vbk9wdGlvbmFsID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kTm9uT3B0aW9uYWwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE5vbk9wdGlvbmFsLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IG5vbm9wdGlvbmFsUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwp9KTsKZnVuY3Rpb24gbm9ub3B0aW9uYWwoaW5uZXJUeXBlLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IFpvZE5vbk9wdGlvbmFsKHsKICAgIHR5cGU6ICJub25vcHRpb25hbCIsCiAgICBpbm5lclR5cGUsCiAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQp2YXIgWm9kQ2F0Y2ggPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RDYXRjaCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2F0Y2guaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gY2F0Y2hQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3QudW53cmFwID0gKCkgPT4gaW5zdC5fem9kLmRlZi5pbm5lclR5cGU7CiAgaW5zdC5yZW1vdmVDYXRjaCA9IGluc3QudW53cmFwOwp9KTsKZnVuY3Rpb24gX2NhdGNoKGlubmVyVHlwZSwgY2F0Y2hWYWx1ZSkgewogIHJldHVybiBuZXcgWm9kQ2F0Y2goewogICAgdHlwZTogImNhdGNoIiwKICAgIGlubmVyVHlwZSwKICAgIGNhdGNoVmFsdWU6IHR5cGVvZiBjYXRjaFZhbHVlID09PSAiZnVuY3Rpb24iID8gY2F0Y2hWYWx1ZSA6ICgpID0+IGNhdGNoVmFsdWUKICB9KTsKfQp2YXIgWm9kUGlwZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFBpcGUiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFBpcGUuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gcGlwZVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC5pbiA9IGRlZi5pbjsKICBpbnN0Lm91dCA9IGRlZi5vdXQ7Cn0pOwpmdW5jdGlvbiBwaXBlKGluXywgb3V0KSB7CiAgcmV0dXJuIG5ldyBab2RQaXBlKHsKICAgIHR5cGU6ICJwaXBlIiwKICAgIGluOiBpbl8sCiAgICBvdXQKICAgIC8vIC4uLnV0aWwubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgfSk7Cn0KdmFyIFpvZFJlYWRvbmx5ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kUmVhZG9ubHkiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFJlYWRvbmx5LmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHJlYWRvbmx5UHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwp9KTsKZnVuY3Rpb24gcmVhZG9ubHkoaW5uZXJUeXBlKSB7CiAgcmV0dXJuIG5ldyBab2RSZWFkb25seSh7CiAgICB0eXBlOiAicmVhZG9ubHkiLAogICAgaW5uZXJUeXBlCiAgfSk7Cn0KdmFyIFpvZEN1c3RvbSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEN1c3RvbSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ3VzdG9tLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IGN1c3RvbVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7Cn0pOwpmdW5jdGlvbiByZWZpbmUoZm4sIF9wYXJhbXMgPSB7fSkgewogIHJldHVybiBfcmVmaW5lKFpvZEN1c3RvbSwgZm4sIF9wYXJhbXMpOwp9CmZ1bmN0aW9uIHN1cGVyUmVmaW5lKGZuLCBwYXJhbXMpIHsKICByZXR1cm4gX3N1cGVyUmVmaW5lKGZuLCBwYXJhbXMpOwp9CgovLyBzcmMvaXNzdWVzL2ZpbmdlcnByaW50LnRzCmltcG9ydCBjcnlwdG8gZnJvbSAibm9kZTpjcnlwdG8iOwp2YXIgSVNTVUVfRklOR0VSUFJJTlRfUEFUVEVSTiA9IC9eWzAtOWEtZl17MjB9JC87CmZ1bmN0aW9uIGlzc3VlRmluZ2VycHJpbnQoaXNzdWUyLCBjb21tZW50cyA9IFtdKSB7CiAgcmV0dXJuIGNyeXB0by5jcmVhdGVIYXNoKCJzaGEyNTYiKS51cGRhdGUoCiAgICBKU09OLnN0cmluZ2lmeSh7CiAgICAgIHRpdGxlOiBpc3N1ZTIudGl0bGUudHJpbSgpLAogICAgICBib2R5OiBpc3N1ZTIuYm9keSA/PyAiIiwKICAgICAgY29tbWVudHM6IGNvbW1lbnRzLm1hcCgoY29tbWVudCkgPT4gKHsKICAgICAgICBpZDogY29tbWVudC5pZCwKICAgICAgICBib2R5OiBjb21tZW50LmJvZHksCiAgICAgICAgYXV0aG9yOiBjb21tZW50LnVzZXI/LmxvZ2luID8/ICIiCiAgICAgIH0pKQogICAgfSkKICApLmRpZ2VzdCgiaGV4Iikuc2xpY2UoMCwgMjApOwp9CgovLyBzcmMvZHJhZnQtcHIvc2NoZW1hLnRzCnZhciB2YWxpZGF0aW9uT3ZlcnJpZGVTY2hlbWEgPSBvYmplY3QoewogIGNsYXNzaWZpY2F0aW9uOiBfZW51bShbImFsbG93bGlzdGVkX3Rlc3RfZmFpbHVyZSJdKSwKICBzb3VyY2U6IF9lbnVtKFsicG9saWN5Il0pLAogIHJlYXNvbjogc3RyaW5nMigpLm1pbigxKS5tYXgoMWUzKSwKICBmYWlsZWRDb21tYW5kczogYXJyYXkoc3RyaW5nMigpLm1pbigxKS5tYXgoMzAwKSkubWluKDEpLm1heCgyMCksCiAgYWxsb3dlZEZhaWx1cmVDYXNlczogYXJyYXkoc3RyaW5nMigpLm1pbigxKS5tYXgoMzAwKSkubWluKDEpLm1heCg1MCkKfSk7CmZ1bmN0aW9uIGhhc0NvbnNpc3RlbnRWYWxpZGF0aW9uT3ZlcnJpZGUoYW5hbHlzaXMpIHsKICBjb25zdCBvdmVycmlkZSA9IGFuYWx5c2lzLnZhbGlkYXRpb25PdmVycmlkZTsKICBpZiAoIW92ZXJyaWRlKSByZXR1cm4gZmFsc2U7CiAgY29uc3QgZmFpbGVkQ29tbWFuZHMgPSBbCiAgICAuLi5uZXcgU2V0KAogICAgICBhbmFseXNpcy50ZXN0cy5maWx0ZXIoKHRlc3QpID0+IHRlc3Quc3RhdHVzID09PSAiZmFpbGVkIikubWFwKCh0ZXN0KSA9PiB0ZXN0LmNvbW1hbmQpCiAgICApCiAgXTsKICBjb25zdCBvdmVycmlkZUNvbW1hbmRzID0gWy4uLm5ldyBTZXQob3ZlcnJpZGUuZmFpbGVkQ29tbWFuZHMpXTsKICByZXR1cm4gZmFpbGVkQ29tbWFuZHMubGVuZ3RoID4gMCAmJiBmYWlsZWRDb21tYW5kcy5sZW5ndGggPT09IG92ZXJyaWRlQ29tbWFuZHMubGVuZ3RoICYmIGZhaWxlZENvbW1hbmRzLmV2ZXJ5KChjb21tYW5kKSA9PiBvdmVycmlkZUNvbW1hbmRzLmluY2x1ZGVzKGNvbW1hbmQpKTsKfQp2YXIgZHJhZnRQckFuYWx5c2lzU2NoZW1hID0gb2JqZWN0KHsKICBvdXRjb21lOiBfZW51bShbImltcGxlbWVudGVkIiwgIm5lZWRzX2FwcHJvdmFsIiwgImJsb2NrZWQiLCAibm9fY2hhbmdlIl0pLAogIHByVGl0bGU6IHN0cmluZzIoKS5tYXgoMTIwKSwKICBzdW1tYXJ5OiBhcnJheShzdHJpbmcyKCkubWluKDEpLm1heCg1MDApKS5tYXgoOCksCiAgdGVzdHM6IGFycmF5KAogICAgb2JqZWN0KHsKICAgICAgY29tbWFuZDogc3RyaW5nMigpLm1pbigxKS5tYXgoMzAwKSwKICAgICAgc3RhdHVzOiBfZW51bShbInBhc3NlZCIsICJmYWlsZWQiLCAibm90X3J1biJdKSwKICAgICAgZGV0YWlsczogc3RyaW5nMigpLm1heCgxZTMpCiAgICB9KQogICkubWF4KDIwKSwKICByaXNrOiBvYmplY3QoewogICAgbGV2ZWw6IF9lbnVtKFsibG93IiwgIm1lZGl1bSIsICJoaWdoIl0pLAogICAgcmVhc29uczogYXJyYXkoc3RyaW5nMigpLm1pbigxKS5tYXgoNTAwKSkubWF4KDgpCiAgfSksCiAgbm90ZXM6IGFycmF5KHN0cmluZzIoKS5taW4oMSkubWF4KDUwMCkpLm1heCg4KSwKICB2YWxpZGF0aW9uT3ZlcnJpZGU6IHZhbGlkYXRpb25PdmVycmlkZVNjaGVtYS5vcHRpb25hbCgpCn0pOwp2YXIgZHJhZnRQclN1Ym1pc3Npb25TY2hlbWEgPSBvYmplY3QoewogIGlzc3VlRmluZ2VycHJpbnQ6IHN0cmluZzIoKS5yZWdleChJU1NVRV9GSU5HRVJQUklOVF9QQVRURVJOKSwKICB0cmlnZ2VyOiBfZW51bShbInJlYWR5IiwgImFwcHJvdmVkIl0pLAogIHdvcmtzcGFjZVBhdGg6IHN0cmluZzIoKS5taW4oMSkubWF4KDJlMyksCiAgYnJhbmNoOiBzdHJpbmcyKCkubWluKDEpLm1heCgyNTApLAogIGJhc2VCcmFuY2g6IHN0cmluZzIoKS5taW4oMSkubWF4KDI1MCksCiAgYmFzZUNvbW1pdDogc3RyaW5nMigpLnJlZ2V4KC9eWzAtOWEtZl17NDB9JC8pLAogIGFuYWx5c2lzOiBkcmFmdFByQW5hbHlzaXNTY2hlbWEKfSk7CgovLyBzcmMvZHJhZnQtcHIvY2ktc2NoZW1hLnRzCnZhciBjaUNoZWNrUmVmZXJlbmNlU2NoZW1hID0gb2JqZWN0KHsKICBjaGVja1J1bklkOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKQp9KTsKdmFyIGNpRml4QW5hbHlzaXNTY2hlbWEgPSBvYmplY3QoewogIG91dGNvbWU6IF9lbnVtKFsiZml4ZWQiLCAibm9fY2hhbmdlIiwgIm5lZWRzX2FwcHJvdmFsIiwgImJsb2NrZWQiXSksCiAgY29tbWl0VGl0bGU6IHN0cmluZzIoKS5tYXgoMTIwKSwKICBzdW1tYXJ5OiBhcnJheShzdHJpbmcyKCkubWluKDEpLm1heCg1MDApKS5tYXgoOCksCiAgZmFpbHVyZXM6IGFycmF5KAogICAgb2JqZWN0KHsKICAgICAgY2hlY2tSdW5JZDogbnVtYmVyMigpLmludCgpLnBvc2l0aXZlKCksCiAgICAgIGRpc3Bvc2l0aW9uOiBfZW51bShbImZpeGVkIiwgIm5vdF9yZXByb2R1Y2libGUiLCAibmVlZHNfYXBwcm92YWwiXSksCiAgICAgIHJlYXNvbjogc3RyaW5nMigpLm1pbigxKS5tYXgoMWUzKQogICAgfSkKICApLm1pbigxKS5tYXgoMTAwKSwKICB0ZXN0czogYXJyYXkoCiAgICBvYmplY3QoewogICAgICBjb21tYW5kOiBzdHJpbmcyKCkubWluKDEpLm1heCgzMDApLAogICAgICBzdGF0dXM6IF9lbnVtKFsicGFzc2VkIiwgImZhaWxlZCIsICJub3RfcnVuIl0pLAogICAgICBkZXRhaWxzOiBzdHJpbmcyKCkubWF4KDFlMykKICAgIH0pCiAgKS5tYXgoMjApLAogIHJpc2s6IG9iamVjdCh7CiAgICBsZXZlbDogX2VudW0oWyJsb3ciLCAibWVkaXVtIiwgImhpZ2giXSksCiAgICByZWFzb25zOiBhcnJheShzdHJpbmcyKCkubWluKDEpLm1heCg1MDApKS5tYXgoOCkKICB9KSwKICBub3RlczogYXJyYXkoc3RyaW5nMigpLm1pbigxKS5tYXgoNTAwKSkubWF4KDgpLAogIHZhbGlkYXRpb25PdmVycmlkZTogdmFsaWRhdGlvbk92ZXJyaWRlU2NoZW1hLm9wdGlvbmFsKCkKfSk7CnZhciBjaUZpeFN1Ym1pc3Npb25TY2hlbWEgPSBvYmplY3QoewogIGNoZWNrU3VpdGVJZDogbnVtYmVyMigpLmludCgpLnBvc2l0aXZlKCksCiAgZmFpbHVyZXNGaW5nZXJwcmludDogc3RyaW5nMigpLnJlZ2V4KC9eWzAtOWEtZl17MjB9JC8pLAogIGNoZWNrUmVmczogYXJyYXkoY2lDaGVja1JlZmVyZW5jZVNjaGVtYSkubWluKDEpLm1heCgxMDApLAogIHdvcmtzcGFjZVBhdGg6IHN0cmluZzIoKS5taW4oMSkubWF4KDJlMyksCiAgYnJhbmNoOiBzdHJpbmcyKCkubWluKDEpLm1heCgyNTApLAogIGJhc2VCcmFuY2g6IHN0cmluZzIoKS5taW4oMSkubWF4KDI1MCksCiAgZXhwZWN0ZWRIZWFkU2hhOiBzdHJpbmcyKCkucmVnZXgoL15bMC05YS1mXXs0MH0kLyksCiAgcHJldmlvdXNBdHRlbXB0czogbnVtYmVyMigpLmludCgpLm5vbm5lZ2F0aXZlKCksCiAgYW5hbHlzaXM6IGNpRml4QW5hbHlzaXNTY2hlbWEKfSk7CgovLyBzcmMvZHJhZnQtcHIvcG9saWN5LnRzCnZhciBkcmFmdFByUG9saWN5U2NoZW1hID0gb2JqZWN0KHsKICB2ZXJzaW9uOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKSwKICByZWFkeUxhYmVsOiBzdHJpbmcyKCkubWluKDEpLAogIGFwcHJvdmVkTGFiZWw6IHN0cmluZzIoKS5taW4oMSksCiAgcnVubmluZ0xhYmVsOiBzdHJpbmcyKCkubWluKDEpLAogIG5lZWRzQXBwcm92YWxMYWJlbDogc3RyaW5nMigpLm1pbigxKSwKICBwck9wZW5MYWJlbDogc3RyaW5nMigpLm1pbigxKSwKICBmYWlsZWRMYWJlbDogc3RyaW5nMigpLm1pbigxKSwKICBza2lwTGFiZWxzOiBhcnJheShzdHJpbmcyKCkubWluKDEpKSwKICBibG9ja2VkTGFiZWxzOiBhcnJheShzdHJpbmcyKCkubWluKDEpKSwKICBicmFuY2hQcmVmaXg6IHN0cmluZzIoKS5yZWdleCgvXlthLXpBLVowLTkuXy8tXSskLyksCiAgbWF4Q2hhbmdlZEZpbGVzOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKS5tYXgoMWUzKSwKICBtYXhDaGFuZ2VkTGluZXM6IG51bWJlcjIoKS5pbnQoKS5wb3NpdGl2ZSgpLm1heCgxZTUpLAogIG1heFJldmlld0NvbW1lbnRzOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKS5tYXgoMTAwKSwKICBtYXhWYWxpZGF0aW9uRml4SXRlcmF0aW9uczogbnVtYmVyMigpLmludCgpLnBvc2l0aXZlKCkubWF4KDIwKSwKICBtYXhGaXhJdGVyYXRpb25zOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKS5tYXgoMjApLAogIHJlcXVpcmVkVmFsaWRhdGlvbkdhdGVzOiBhcnJheSgKICAgIF9lbnVtKFsidGFzay1wcmVwYXJlIiwgInRhc2stbGludCIsICJ0YXNrLXRlc3QtdW5pdCJdKQogICkubWluKDEpLAogIGFsbG93ZWRWYWxpZGF0aW9uRmFpbHVyZUNhc2VzOiBhcnJheShzdHJpbmcyKCkubWluKDEpLm1heCgzMDApKS5tYXgoNTApLAogIGFwcHJvdmFsUGF0aFByZWZpeGVzOiBhcnJheShzdHJpbmcyKCkubWluKDEpKSwKICBsYWJlbENvbG9yczogcmVjb3JkKHN0cmluZzIoKSwgc3RyaW5nMigpLnJlZ2V4KC9eWzAtOWEtZkEtRl17Nn0kLykpCn0pOwpmdW5jdGlvbiByZXF1aXJlc0FwcHJvdmFsKGFuYWx5c2lzLCBpbnNwZWN0aW9uLCBhcHByb3ZlZCwgcG9saWN5KSB7CiAgaWYgKGFwcHJvdmVkKSByZXR1cm4gW107CiAgY29uc3QgcmVhc29ucyA9IFtdOwogIGlmIChhbmFseXNpcy5yaXNrLmxldmVsID09PSAiaGlnaCIpIHsKICAgIHJlYXNvbnMucHVzaCgidGhlIGltcGxlbWVudGF0aW9uIHJlcG9ydHMgaGlnaCByaXNrIik7CiAgfQogIGlmIChpbnNwZWN0aW9uLmNoYW5nZWRGaWxlcy5sZW5ndGggPiBwb2xpY3kubWF4Q2hhbmdlZEZpbGVzKSB7CiAgICByZWFzb25zLnB1c2goCiAgICAgIGB0aGUgY2hhbmdlIHRvdWNoZXMgJHtpbnNwZWN0aW9uLmNoYW5nZWRGaWxlcy5sZW5ndGh9IGZpbGVzIChsaW1pdCAke3BvbGljeS5tYXhDaGFuZ2VkRmlsZXN9KWAKICAgICk7CiAgfQogIGNvbnN0IGNoYW5nZWRMaW5lcyA9IGluc3BlY3Rpb24uYWRkaXRpb25zICsgaW5zcGVjdGlvbi5kZWxldGlvbnM7CiAgaWYgKGNoYW5nZWRMaW5lcyA+IHBvbGljeS5tYXhDaGFuZ2VkTGluZXMpIHsKICAgIHJlYXNvbnMucHVzaCgKICAgICAgYHRoZSBjaGFuZ2UgbW9kaWZpZXMgJHtjaGFuZ2VkTGluZXN9IGxpbmVzIChsaW1pdCAke3BvbGljeS5tYXhDaGFuZ2VkTGluZXN9KWAKICAgICk7CiAgfQogIGNvbnN0IHNlbnNpdGl2ZVBhdGhzID0gaW5zcGVjdGlvbi5jaGFuZ2VkRmlsZXMuZmlsdGVyKAogICAgKGZpbGUpID0+IHBvbGljeS5hcHByb3ZhbFBhdGhQcmVmaXhlcy5zb21lKChwcmVmaXgpID0+IGZpbGUuc3RhcnRzV2l0aChwcmVmaXgpKQogICk7CiAgaWYgKHNlbnNpdGl2ZVBhdGhzLmxlbmd0aCA+IDApIHsKICAgIHJlYXNvbnMucHVzaCgKICAgICAgYHRoZSBjaGFuZ2UgdG91Y2hlcyBhcHByb3ZhbC1nYXRlZCBwYXRoczogJHtzZW5zaXRpdmVQYXRocy5zbGljZSgwLCA1KS5qb2luKCIsICIpfWAKICAgICk7CiAgfQogIHJldHVybiByZWFzb25zOwp9CmZ1bmN0aW9uIGhhc0xhYmVsKGxhYmVscywgZXhwZWN0ZWQpIHsKICBjb25zdCBub3JtYWxpemVkID0gZXhwZWN0ZWQudHJpbSgpLnRvTG93ZXJDYXNlKCk7CiAgcmV0dXJuIGxhYmVscy5zb21lKChsYWJlbCkgPT4gbGFiZWwudHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09IG5vcm1hbGl6ZWQpOwp9CmZ1bmN0aW9uIGhhc0FueUxhYmVsKGxhYmVscywgZXhwZWN0ZWQpIHsKICByZXR1cm4gZXhwZWN0ZWQuc29tZSgobGFiZWwpID0+IGhhc0xhYmVsKGxhYmVscywgbGFiZWwpKTsKfQoKLy8gc3JjL2RyYWZ0LXByL3JlcG9zaXRvcnkudHMKZnVuY3Rpb24gcmVwb3NpdG9yeUNsb25lVXJsKHNlcnZlclVybCwgcmVwb3NpdG9yeSkgewogIGNvbnN0IGJhc2UgPSBuZXcgVVJMKHNlcnZlclVybCk7CiAgaWYgKGJhc2UucHJvdG9jb2wgIT09ICJodHRwczoiKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkdpdEh1YiBzZXJ2ZXIgVVJMIG11c3QgdXNlIEhUVFBTIik7CiAgfQogIGJhc2UucGF0aG5hbWUgPSBgJHtiYXNlLnBhdGhuYW1lLnJlcGxhY2UoL1wvJC8sICIiKX0vJHtyZXBvc2l0b3J5fS5naXRgOwogIGJhc2Uuc2VhcmNoID0gIiI7CiAgYmFzZS5oYXNoID0gIiI7CiAgcmV0dXJuIGJhc2UudG9TdHJpbmcoKTsKfQpmdW5jdGlvbiBzYW5pdGl6ZVRpdGxlKHZhbHVlKSB7CiAgcmV0dXJuIHZhbHVlLnJlcGxhY2UoL1tcclxuXSsvZywgIiAiKS5yZXBsYWNlKC9ccysvZywgIiAiKS50cmltKCkuc2xpY2UoMCwgMTIwKTsKfQpmdW5jdGlvbiBhc3NlcnRBbGxvd2VkUmVwb3NpdG9yeShyZXBvc2l0b3J5LCBhbGxvd2VkKSB7CiAgaWYgKCFhbGxvd2VkLnRyaW0oKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJEcmFmdCBQUiByZXBvc2l0b3J5IGFsbG93bGlzdCBpcyByZXF1aXJlZCIpOwogIH0KICBpZiAocmVwb3NpdG9yeS50cmltKCkudG9Mb3dlckNhc2UoKSAhPT0gYWxsb3dlZC50cmltKCkudG9Mb3dlckNhc2UoKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJyZXBvc2l0b3J5IGlzIG91dHNpZGUgdGhlIERyYWZ0IFBSIGFsbG93bGlzdCIpOwogIH0KfQoKLy8gc3JjL2RyYWZ0LXByL3dvcmtzcGFjZS50cwppbXBvcnQgY3J5cHRvMiBmcm9tICJub2RlOmNyeXB0byI7CmltcG9ydCB7IHNwYXduIH0gZnJvbSAibm9kZTpjaGlsZF9wcm9jZXNzIjsKaW1wb3J0IHsKICBjaG1vZCwKICBsc3RhdCwKICBta2RpciwKICBta2R0ZW1wLAogIHJtLAogIHN0YXQsCiAgd3JpdGVGaWxlCn0gZnJvbSAibm9kZTpmcy9wcm9taXNlcyI7CmltcG9ydCB7IGlzSVAgfSBmcm9tICJub2RlOm5ldCI7CmltcG9ydCBvcyBmcm9tICJub2RlOm9zIjsKaW1wb3J0IHBhdGggZnJvbSAibm9kZTpwYXRoIjsKdmFyIERyYWZ0UHJXb3Jrc3BhY2VMb2NrRXJyb3IgPSBjbGFzcyBleHRlbmRzIEVycm9yIHsKICBjb25zdHJ1Y3Rvcih0YXJnZXQpIHsKICAgIHN1cGVyKGBhbm90aGVyIERyYWZ0IFBSIHJ1biBhbHJlYWR5IGhvbGRzIHRoZSAke3RhcmdldH0gbG9ja2ApOwogICAgdGhpcy5uYW1lID0gIkRyYWZ0UHJXb3Jrc3BhY2VMb2NrRXJyb3IiOwogIH0KfTsKdmFyIEdpdERyYWZ0UHJXb3Jrc3BhY2UgPSBjbGFzcyB7CiAgI3Jvb3Q7CiAgI3Rva2VuOwogICNhdXRob3JOYW1lOwogICNhdXRob3JFbWFpbDsKICAjZ2l0Q3VybFJlc29sdmU7CiAgI2xvY2tUdGxNczsKICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICB0aGlzLiNyb290ID0gcGF0aC5yZXNvbHZlKG9wdGlvbnMucm9vdCk7CiAgICB0aGlzLiN0b2tlbiA9IG9wdGlvbnMudG9rZW4udHJpbSgpOwogICAgdGhpcy4jYXV0aG9yTmFtZSA9IG9wdGlvbnMuYXV0aG9yTmFtZS50cmltKCk7CiAgICB0aGlzLiNhdXRob3JFbWFpbCA9IG9wdGlvbnMuYXV0aG9yRW1haWwudHJpbSgpOwogICAgdGhpcy4jZ2l0Q3VybFJlc29sdmUgPSBvcHRpb25zLmdpdEN1cmxSZXNvbHZlPy50cmltKCkgPz8gIiI7CiAgICB0aGlzLiNsb2NrVHRsTXMgPSBvcHRpb25zLmxvY2tUdGxNcyA/PyA0ICogNjAgKiA2MCAqIDFlMzsKICAgIGlmICghdGhpcy4jdG9rZW4pCiAgICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIHRva2VuIGlzIHJlcXVpcmVkIGZvciBHaXQgd29ya3NwYWNlIHByZXBhcmF0aW9uIik7CiAgICBpZiAoIXRoaXMuI2F1dGhvck5hbWUgfHwgIXRoaXMuI2F1dGhvckVtYWlsKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiR2l0IGF1dGhvciBuYW1lIGFuZCBlbWFpbCBhcmUgcmVxdWlyZWQiKTsKICAgIH0KICAgIGdpdEN1cmxSZXNvbHZlRW52aXJvbm1lbnQodGhpcy4jZ2l0Q3VybFJlc29sdmUpOwogIH0KICBhc3luYyBwcmVwYXJlKGlucHV0KSB7CiAgICB2YWxpZGF0ZUNsb25lVXJsKGlucHV0LmNsb25lVXJsKTsKICAgIHZhbGlkYXRlR2l0UmVmKGlucHV0LmJhc2VCcmFuY2gsICJiYXNlIGJyYW5jaCIpOwogICAgdmFsaWRhdGVHaXRSZWYoaW5wdXQuYnJhbmNoLCAid29ya2luZyBicmFuY2giKTsKICAgIGNvbnN0IHBhdGhzID0gdGhpcy4jcGF0aHMoaW5wdXQucmVwb3NpdG9yeSwgImlzc3VlIiwgaW5wdXQuaXNzdWVOdW1iZXIpOwogICAgYXdhaXQgbWtkaXIocGF0aC5kaXJuYW1lKHBhdGhzLmxvY2spLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTsKICAgIGF3YWl0IHRoaXMuI2FjcXVpcmVMb2NrKHBhdGhzLmxvY2spOwogICAgdHJ5IHsKICAgICAgYXdhaXQgcm0ocGF0aHMud29ya3NwYWNlLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7CiAgICAgIGF3YWl0IG1rZGlyKHBhdGguZGlybmFtZShwYXRocy53b3Jrc3BhY2UpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTsKICAgICAgY29uc3QgZW52ID0gYXdhaXQgdGhpcy4jYXV0aGVudGljYXRlZEdpdEVudmlyb25tZW50KCk7CiAgICAgIGF3YWl0IHJ1bkdpdCgKICAgICAgICBbCiAgICAgICAgICAiY2xvbmUiLAogICAgICAgICAgIi0tbm8tdGFncyIsCiAgICAgICAgICAiLS1kZXB0aD0xIiwKICAgICAgICAgICItLWJyYW5jaCIsCiAgICAgICAgICBpbnB1dC5iYXNlQnJhbmNoLAogICAgICAgICAgIi0tIiwKICAgICAgICAgIGlucHV0LmNsb25lVXJsLAogICAgICAgICAgcGF0aHMud29ya3NwYWNlCiAgICAgICAgXSwKICAgICAgICB7IGN3ZDogdGhpcy4jcm9vdCwgZW52IH0KICAgICAgKTsKICAgICAgY29uc3QgZXhpc3RpbmcgPSBhd2FpdCBydW5HaXQoCiAgICAgICAgWyJscy1yZW1vdGUiLCAiLS1oZWFkcyIsICJvcmlnaW4iLCBgcmVmcy9oZWFkcy8ke2lucHV0LmJyYW5jaH1gXSwKICAgICAgICB7IGN3ZDogcGF0aHMud29ya3NwYWNlLCBlbnYgfQogICAgICApOwogICAgICBpZiAoZXhpc3Rpbmcuc3Rkb3V0LnRyaW0oKSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgcmVtb3RlIGJyYW5jaCBhbHJlYWR5IGV4aXN0czogJHtpbnB1dC5icmFuY2h9YCk7CiAgICAgIH0KICAgICAgYXdhaXQgcnVuR2l0KFsiY2hlY2tvdXQiLCAiLWIiLCBpbnB1dC5icmFuY2hdLCB7CiAgICAgICAgY3dkOiBwYXRocy53b3Jrc3BhY2UsCiAgICAgICAgZW52CiAgICAgIH0pOwogICAgICBjb25zdCBiYXNlQ29tbWl0ID0gKGF3YWl0IHJ1bkdpdChbInJldi1wYXJzZSIsICJIRUFEIl0sIHsgY3dkOiBwYXRocy53b3Jrc3BhY2UsIGVudiB9KSkuc3Rkb3V0LnRyaW0oKTsKICAgICAgcmV0dXJuIHsKICAgICAgICBwYXRoOiBwYXRocy53b3Jrc3BhY2UsCiAgICAgICAgYnJhbmNoOiBpbnB1dC5icmFuY2gsCiAgICAgICAgYmFzZUJyYW5jaDogaW5wdXQuYmFzZUJyYW5jaCwKICAgICAgICBiYXNlQ29tbWl0CiAgICAgIH07CiAgICB9IGNhdGNoIChlcnJvcikgewogICAgICBhd2FpdCB0aGlzLmNsZWFudXAoaW5wdXQucmVwb3NpdG9yeSwgaW5wdXQuaXNzdWVOdW1iZXIpOwogICAgICB0aHJvdyBlcnJvcjsKICAgIH0KICB9CiAgYXN5bmMgcHJlcGFyZVJldmlldyhpbnB1dCkgewogICAgdmFsaWRhdGVDbG9uZVVybChpbnB1dC5jbG9uZVVybCk7CiAgICB2YWxpZGF0ZUdpdFJlZihpbnB1dC5iYXNlQnJhbmNoLCAiYmFzZSBicmFuY2giKTsKICAgIHZhbGlkYXRlR2l0UmVmKGlucHV0LmJyYW5jaCwgIlB1bGwgUmVxdWVzdCBicmFuY2giKTsKICAgIGlmICghL15bMC05YS1mXXs0MH0kLy50ZXN0KGlucHV0LmV4cGVjdGVkSGVhZFNoYSkpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKCJpbnZhbGlkIGV4cGVjdGVkIFB1bGwgUmVxdWVzdCBoZWFkIFNIQSIpOwogICAgfQogICAgY29uc3QgcGF0aHMgPSB0aGlzLiNwYXRocyhpbnB1dC5yZXBvc2l0b3J5LCAicHIiLCBpbnB1dC5wdWxsUmVxdWVzdE51bWJlcik7CiAgICBhd2FpdCBta2RpcihwYXRoLmRpcm5hbWUocGF0aHMubG9jayksIHsgcmVjdXJzaXZlOiB0cnVlIH0pOwogICAgYXdhaXQgdGhpcy4jYWNxdWlyZUxvY2socGF0aHMubG9jaywgIlB1bGwgUmVxdWVzdCIpOwogICAgdHJ5IHsKICAgICAgYXdhaXQgcm0ocGF0aHMud29ya3NwYWNlLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7CiAgICAgIGF3YWl0IG1rZGlyKHBhdGguZGlybmFtZShwYXRocy53b3Jrc3BhY2UpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTsKICAgICAgY29uc3QgZW52ID0gYXdhaXQgdGhpcy4jYXV0aGVudGljYXRlZEdpdEVudmlyb25tZW50KCk7CiAgICAgIGF3YWl0IHJ1bkdpdCgKICAgICAgICBbCiAgICAgICAgICAiY2xvbmUiLAogICAgICAgICAgIi0tbm8tdGFncyIsCiAgICAgICAgICAiLS1kZXB0aD0xIiwKICAgICAgICAgICItLWJyYW5jaCIsCiAgICAgICAgICBpbnB1dC5icmFuY2gsCiAgICAgICAgICAiLS0iLAogICAgICAgICAgaW5wdXQuY2xvbmVVcmwsCiAgICAgICAgICBwYXRocy53b3Jrc3BhY2UKICAgICAgICBdLAogICAgICAgIHsgY3dkOiB0aGlzLiNyb290LCBlbnYgfQogICAgICApOwogICAgICBjb25zdCBoZWFkQ29tbWl0ID0gKGF3YWl0IHJ1bkdpdChbInJldi1wYXJzZSIsICJIRUFEIl0sIHsgY3dkOiBwYXRocy53b3Jrc3BhY2UsIGVudiB9KSkuc3Rkb3V0LnRyaW0oKTsKICAgICAgaWYgKGhlYWRDb21taXQgIT09IGlucHV0LmV4cGVjdGVkSGVhZFNoYSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgICAgICJQdWxsIFJlcXVlc3QgaGVhZCBjaGFuZ2VkIGR1cmluZyB3b3Jrc3BhY2UgcHJlcGFyYXRpb24iCiAgICAgICAgKTsKICAgICAgfQogICAgICByZXR1cm4gewogICAgICAgIHBhdGg6IHBhdGhzLndvcmtzcGFjZSwKICAgICAgICBicmFuY2g6IGlucHV0LmJyYW5jaCwKICAgICAgICBiYXNlQnJhbmNoOiBpbnB1dC5iYXNlQnJhbmNoLAogICAgICAgIGJhc2VDb21taXQ6IGhlYWRDb21taXQKICAgICAgfTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIGF3YWl0IHRoaXMuY2xlYW51cFJldmlldyhpbnB1dC5yZXBvc2l0b3J5LCBpbnB1dC5wdWxsUmVxdWVzdE51bWJlcik7CiAgICAgIHRocm93IGVycm9yOwogICAgfQogIH0KICBhc3luYyBpbnNwZWN0KHdvcmtzcGFjZVBhdGgpIHsKICAgIHJldHVybiBpbnNwZWN0RHJhZnRQcldvcmtzcGFjZSh0aGlzLiNyb290LCB3b3Jrc3BhY2VQYXRoKTsKICB9CiAgYXN5bmMgY29tbWl0QW5kUHVzaCh3b3Jrc3BhY2VQYXRoLCBicmFuY2gsIHRpdGxlLCBjbG9uZVVybCkgewogICAgY29uc3QgcmVzb2x2ZWQgPSB0aGlzLiNhc3NlcnRXb3Jrc3BhY2VQYXRoKHdvcmtzcGFjZVBhdGgpOwogICAgdmFsaWRhdGVHaXRSZWYoYnJhbmNoLCAid29ya2luZyBicmFuY2giKTsKICAgIHZhbGlkYXRlQ2xvbmVVcmwoY2xvbmVVcmwpOwogICAgYXdhaXQgdGhpcy4jd3JpdGVUcnVzdGVkR2l0Q29uZmlnKHJlc29sdmVkLCBjbG9uZVVybCk7CiAgICBjb25zdCBsb2NhbEVudiA9IHRoaXMuI2xvY2FsR2l0RW52aXJvbm1lbnQoKTsKICAgIGF3YWl0IHJ1bkdpdCgKICAgICAgWwogICAgICAgICItYyIsCiAgICAgICAgYHVzZXIubmFtZT0ke3RoaXMuI2F1dGhvck5hbWV9YCwKICAgICAgICAiLWMiLAogICAgICAgIGB1c2VyLmVtYWlsPSR7dGhpcy4jYXV0aG9yRW1haWx9YCwKICAgICAgICAiLWMiLAogICAgICAgICJjb3JlLmhvb2tzUGF0aD0vZGV2L251bGwiLAogICAgICAgICJjb21taXQiLAogICAgICAgICItbSIsCiAgICAgICAgdGl0bGUKICAgICAgXSwKICAgICAgeyBjd2Q6IHJlc29sdmVkLCBlbnY6IGxvY2FsRW52IH0KICAgICk7CiAgICBjb25zdCBhdXRoZW50aWNhdGVkRW52ID0gYXdhaXQgdGhpcy4jYXV0aGVudGljYXRlZEdpdEVudmlyb25tZW50KCk7CiAgICBhd2FpdCBydW5HaXQoCiAgICAgIFsKICAgICAgICAiLWMiLAogICAgICAgICJjb3JlLmhvb2tzUGF0aD0vZGV2L251bGwiLAogICAgICAgICItYyIsCiAgICAgICAgImNyZWRlbnRpYWwuaGVscGVyPSIsCiAgICAgICAgInB1c2giLAogICAgICAgICItLW5vLXZlcmlmeSIsCiAgICAgICAgIi0tc2V0LXVwc3RyZWFtIiwKICAgICAgICAib3JpZ2luIiwKICAgICAgICBicmFuY2gKICAgICAgXSwKICAgICAgewogICAgICAgIGN3ZDogcmVzb2x2ZWQsCiAgICAgICAgZW52OiBhdXRoZW50aWNhdGVkRW52CiAgICAgIH0KICAgICk7CiAgICByZXR1cm4gKGF3YWl0IHJ1bkdpdChbInJldi1wYXJzZSIsICJIRUFEIl0sIHsgY3dkOiByZXNvbHZlZCwgZW52OiBsb2NhbEVudiB9KSkuc3Rkb3V0LnRyaW0oKTsKICB9CiAgYXN5bmMgY2xlYW51cChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcikgewogICAgY29uc3QgcGF0aHMgPSB0aGlzLiNwYXRocyhyZXBvc2l0b3J5LCAiaXNzdWUiLCBpc3N1ZU51bWJlcik7CiAgICBhd2FpdCBybShwYXRocy53b3Jrc3BhY2UsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTsKICAgIGF3YWl0IHJtKHBhdGhzLmxvY2ssIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTsKICB9CiAgYXN5bmMgY2xlYW51cFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlcikgewogICAgY29uc3QgcGF0aHMgPSB0aGlzLiNwYXRocyhyZXBvc2l0b3J5LCAicHIiLCBwdWxsUmVxdWVzdE51bWJlcik7CiAgICBhd2FpdCBybShwYXRocy53b3Jrc3BhY2UsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTsKICAgIGF3YWl0IHJtKHBhdGhzLmxvY2ssIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTsKICB9CiAgI3BhdGhzKHJlcG9zaXRvcnksIGtpbmQsIG51bWJlcjMpIHsKICAgIGlmICghTnVtYmVyLmlzU2FmZUludGVnZXIobnVtYmVyMykgfHwgbnVtYmVyMyA8PSAwKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgICBgJHtraW5kID09PSAiaXNzdWUiID8gIklzc3VlIiA6ICJQdWxsIFJlcXVlc3QifSBudW1iZXIgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXJgCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBrZXkgPSBjcnlwdG8yLmNyZWF0ZUhhc2goInNoYTI1NiIpLnVwZGF0ZShyZXBvc2l0b3J5LnRyaW0oKS50b0xvd2VyQ2FzZSgpKS5kaWdlc3QoImhleCIpLnNsaWNlKDAsIDE2KTsKICAgIHJldHVybiB7CiAgICAgIHdvcmtzcGFjZTogcGF0aC5qb2luKAogICAgICAgIHRoaXMuI3Jvb3QsCiAgICAgICAgInJlcG9zaXRvcmllcyIsCiAgICAgICAga2V5LAogICAgICAgIGAke2tpbmR9LSR7bnVtYmVyM31gCiAgICAgICksCiAgICAgIGxvY2s6IHBhdGguam9pbih0aGlzLiNyb290LCAiLmxvY2tzIiwgYCR7a2V5fS0ke2tpbmR9LSR7bnVtYmVyM31gKQogICAgfTsKICB9CiAgI2Fzc2VydFdvcmtzcGFjZVBhdGgodmFsdWUpIHsKICAgIGNvbnN0IHJlc29sdmVkID0gcGF0aC5yZXNvbHZlKHZhbHVlKTsKICAgIGNvbnN0IGV4cGVjdGVkUHJlZml4ID0gYCR7cGF0aC5qb2luKHRoaXMuI3Jvb3QsICJyZXBvc2l0b3JpZXMiKX0ke3BhdGguc2VwfWA7CiAgICBpZiAoIXJlc29sdmVkLnN0YXJ0c1dpdGgoZXhwZWN0ZWRQcmVmaXgpKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigid29ya3NwYWNlIHBhdGggaXMgb3V0c2lkZSB0aGUgY29uZmlndXJlZCBEcmFmdCBQUiByb290Iik7CiAgICB9CiAgICByZXR1cm4gcmVzb2x2ZWQ7CiAgfQogIGFzeW5jICNhY3F1aXJlTG9jayhsb2NrUGF0aCwgdGFyZ2V0ID0gIklzc3VlIikgewogICAgdHJ5IHsKICAgICAgYXdhaXQgbWtkaXIobG9ja1BhdGgpOwogICAgICByZXR1cm47CiAgICB9IGNhdGNoIChlcnJvcikgewogICAgICBpZiAoIWlzQWxyZWFkeUV4aXN0cyhlcnJvcikpIHRocm93IGVycm9yOwogICAgfQogICAgY29uc3QgaW5mbyA9IGF3YWl0IHN0YXQobG9ja1BhdGgpOwogICAgaWYgKERhdGUubm93KCkgLSBpbmZvLm10aW1lTXMgPD0gdGhpcy4jbG9ja1R0bE1zKSB7CiAgICAgIHRocm93IG5ldyBEcmFmdFByV29ya3NwYWNlTG9ja0Vycm9yKHRhcmdldCk7CiAgICB9CiAgICBhd2FpdCBybShsb2NrUGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pOwogICAgYXdhaXQgbWtkaXIobG9ja1BhdGgpOwogIH0KICAjbG9jYWxHaXRFbnZpcm9ubWVudCgpIHsKICAgIHJldHVybiB7CiAgICAgIFBBVEg6IHByb2Nlc3MuZW52LlBBVEgsCiAgICAgIEhPTUU6IHByb2Nlc3MuZW52LkhPTUUsCiAgICAgIExBTkc6IHByb2Nlc3MuZW52LkxBTkcgPz8gIkMuVVRGLTgiLAogICAgICBHSVRfQ09ORklHX05PU1lTVEVNOiAiMSIsCiAgICAgIEdJVF9DT05GSUdfR0xPQkFMOiAiL2Rldi9udWxsIiwKICAgICAgR0lUX1RFUk1JTkFMX1BST01QVDogIjAiLAogICAgICAuLi5naXRDdXJsUmVzb2x2ZUVudmlyb25tZW50KHRoaXMuI2dpdEN1cmxSZXNvbHZlKQogICAgfTsKICB9CiAgYXN5bmMgI2F1dGhlbnRpY2F0ZWRHaXRFbnZpcm9ubWVudCgpIHsKICAgIGF3YWl0IG1rZGlyKHRoaXMuI3Jvb3QsIHsgcmVjdXJzaXZlOiB0cnVlIH0pOwogICAgY29uc3QgYXNrUGFzcyA9IHBhdGguam9pbih0aGlzLiNyb290LCAiLmdpdC1hc2twYXNzLnNoIik7CiAgICBhd2FpdCB3cml0ZUZpbGUoCiAgICAgIGFza1Bhc3MsCiAgICAgIFsKICAgICAgICAiIyEvYmluL3NoIiwKICAgICAgICAnY2FzZSAiJDEiIGluJywKICAgICAgICAnICAqVXNlcm5hbWUqKSBwcmludGYgIiVzIiAieC1hY2Nlc3MtdG9rZW4iIDs7JywKICAgICAgICAnICAqKSBwcmludGYgIiVzIiAiJERSQUZUX1BSX0dJVF9UT0tFTiIgOzsnLAogICAgICAgICJlc2FjIiwKICAgICAgICAiIgogICAgICBdLmpvaW4oIlxuIiksCiAgICAgIHsgbW9kZTogNDQ4IH0KICAgICk7CiAgICBhd2FpdCBjaG1vZChhc2tQYXNzLCA0NDgpOwogICAgcmV0dXJuIHsKICAgICAgLi4udGhpcy4jbG9jYWxHaXRFbnZpcm9ubWVudCgpLAogICAgICBHSVRfQVNLUEFTUzogYXNrUGFzcywKICAgICAgRFJBRlRfUFJfR0lUX1RPS0VOOiB0aGlzLiN0b2tlbgogICAgfTsKICB9CiAgYXN5bmMgI3dyaXRlVHJ1c3RlZEdpdENvbmZpZyh3b3Jrc3BhY2VQYXRoLCBjbG9uZVVybCkgewogICAgY29uc3QgZ2l0RGlyZWN0b3J5ID0gcGF0aC5qb2luKHdvcmtzcGFjZVBhdGgsICIuZ2l0Iik7CiAgICBjb25zdCBnaXREaXJlY3RvcnlJbmZvID0gYXdhaXQgbHN0YXQoZ2l0RGlyZWN0b3J5KTsKICAgIGlmICghZ2l0RGlyZWN0b3J5SW5mby5pc0RpcmVjdG9yeSgpIHx8IGdpdERpcmVjdG9yeUluZm8uaXNTeW1ib2xpY0xpbmsoKSkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoInByZXBhcmVkIHdvcmtzcGFjZSAuZ2l0IGRpcmVjdG9yeSB3YXMgcmVwbGFjZWQiKTsKICAgIH0KICAgIGNvbnN0IGNvbmZpZ1BhdGggPSBwYXRoLmpvaW4oZ2l0RGlyZWN0b3J5LCAiY29uZmlnIik7CiAgICBjb25zdCBjb25maWdJbmZvID0gYXdhaXQgbHN0YXQoY29uZmlnUGF0aCk7CiAgICBpZiAoIWNvbmZpZ0luZm8uaXNGaWxlKCkgfHwgY29uZmlnSW5mby5pc1N5bWJvbGljTGluaygpKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigicHJlcGFyZWQgd29ya3NwYWNlIEdpdCBjb25maWcgd2FzIHJlcGxhY2VkIik7CiAgICB9CiAgICBhd2FpdCB3cml0ZUZpbGUoCiAgICAgIGNvbmZpZ1BhdGgsCiAgICAgIFsKICAgICAgICAiW2NvcmVdIiwKICAgICAgICAiCXJlcG9zaXRvcnlmb3JtYXR2ZXJzaW9uID0gMCIsCiAgICAgICAgIglmaWxlbW9kZSA9IHRydWUiLAogICAgICAgICIJYmFyZSA9IGZhbHNlIiwKICAgICAgICAiCWxvZ2FsbHJlZnVwZGF0ZXMgPSB0cnVlIiwKICAgICAgICAiCWhvb2tzUGF0aCA9IC9kZXYvbnVsbCIsCiAgICAgICAgJ1tyZW1vdGUgIm9yaWdpbiJdJywKICAgICAgICBgCXVybCA9ICR7Y2xvbmVVcmx9YCwKICAgICAgICAiCWZldGNoID0gK3JlZnMvaGVhZHMvKjpyZWZzL3JlbW90ZXMvb3JpZ2luLyoiLAogICAgICAgICIiCiAgICAgIF0uam9pbigiXG4iKSwKICAgICAgeyBtb2RlOiAzODQgfQogICAgKTsKICB9Cn07CmFzeW5jIGZ1bmN0aW9uIGluc3BlY3REcmFmdFByV29ya3NwYWNlKHJvb3QsIHdvcmtzcGFjZVBhdGgpIHsKICBjb25zdCByZXNvbHZlZCA9IGFzc2VydFdvcmtzcGFjZVBhdGgocm9vdCwgd29ya3NwYWNlUGF0aCk7CiAgY29uc3QgZW52ID0gbG9jYWxHaXRFbnZpcm9ubWVudCgpOwogIGF3YWl0IHJ1bkdpdChbImFkZCIsICItQSJdLCB7IGN3ZDogcmVzb2x2ZWQsIGVudiB9KTsKICBjb25zdCBbaGVhZCwgdHJlZSwgbmFtZXMsIHN0YXRzLCBjaGVjaywgZGlmZl0gPSBhd2FpdCBQcm9taXNlLmFsbChbCiAgICBydW5HaXQoWyJyZXYtcGFyc2UiLCAiSEVBRCJdLCB7IGN3ZDogcmVzb2x2ZWQsIGVudiB9KSwKICAgIHJ1bkdpdChbIndyaXRlLXRyZWUiXSwgeyBjd2Q6IHJlc29sdmVkLCBlbnYgfSksCiAgICBydW5HaXQoWyJkaWZmIiwgIi0tY2FjaGVkIiwgIi0tbmFtZS1vbmx5IiwgIi16Il0sIHsKICAgICAgY3dkOiByZXNvbHZlZCwKICAgICAgZW52CiAgICB9KSwKICAgIHJ1bkdpdChbImRpZmYiLCAiLS1jYWNoZWQiLCAiLS1udW1zdGF0Il0sIHsgY3dkOiByZXNvbHZlZCwgZW52IH0pLAogICAgcnVuR2l0KFsiZGlmZiIsICItLWNhY2hlZCIsICItLWNoZWNrIl0sIHsKICAgICAgY3dkOiByZXNvbHZlZCwKICAgICAgZW52LAogICAgICBhbGxvd0ZhaWx1cmU6IHRydWUKICAgIH0pLAogICAgcnVuR2l0KAogICAgICBbCiAgICAgICAgImRpZmYiLAogICAgICAgICItLWNhY2hlZCIsCiAgICAgICAgIi0tdW5pZmllZD0wIiwKICAgICAgICAiLS1uby1jb2xvciIsCiAgICAgICAgIi0tbm8tZXh0LWRpZmYiLAogICAgICAgICItLW5vLXRleHRjb252IgogICAgICBdLAogICAgICB7CiAgICAgICAgY3dkOiByZXNvbHZlZCwKICAgICAgICBlbnYsCiAgICAgICAgbWF4T3V0cHV0Qnl0ZXM6IDggKiAxMDI0ICogMTAyNAogICAgICB9CiAgICApCiAgXSk7CiAgY29uc3QgY2hhbmdlZEZpbGVzID0gbmFtZXMuc3Rkb3V0LnNwbGl0KCJcMCIpLmZpbHRlcihCb29sZWFuKTsKICBsZXQgYWRkaXRpb25zID0gMDsKICBsZXQgZGVsZXRpb25zID0gMDsKICBmb3IgKGNvbnN0IGxpbmUgb2Ygc3RhdHMuc3Rkb3V0LnNwbGl0KCJcbiIpKSB7CiAgICBjb25zdCBbYWRkZWQsIGRlbGV0ZWRdID0gbGluZS5zcGxpdCgiCSIpOwogICAgaWYgKC9eXGQrJC8udGVzdChhZGRlZCA/PyAiIikpIGFkZGl0aW9ucyArPSBOdW1iZXIoYWRkZWQpOwogICAgaWYgKC9eXGQrJC8udGVzdChkZWxldGVkID8/ICIiKSkgZGVsZXRpb25zICs9IE51bWJlcihkZWxldGVkKTsKICB9CiAgcmV0dXJuIHsKICAgIGhlYWRDb21taXQ6IGhlYWQuc3Rkb3V0LnRyaW0oKSwKICAgIGNoYW5nZUZpbmdlcnByaW50OiB0cmVlLnN0ZG91dC50cmltKCksCiAgICBjaGFuZ2VkRmlsZXMsCiAgICBhZGRpdGlvbnMsCiAgICBkZWxldGlvbnMsCiAgICBkaWZmQ2hlY2tQYXNzZWQ6IGNoZWNrLmV4aXRDb2RlID09PSAwLAogICAgc2VjcmV0RmluZGluZ1BhdGhzOiBzY2FuQWRkZWRMaW5lc0ZvclNlY3JldHMoZGlmZi5zdGRvdXQpCiAgfTsKfQphc3luYyBmdW5jdGlvbiBmaW5nZXJwcmludERyYWZ0UHJXb3Jrc3BhY2Uocm9vdCwgd29ya3NwYWNlUGF0aCkgewogIGNvbnN0IHJlc29sdmVkID0gYXNzZXJ0V29ya3NwYWNlUGF0aChyb290LCB3b3Jrc3BhY2VQYXRoKTsKICBjb25zdCB0ZW1wb3JhcnlEaXJlY3RvcnkgPSBhd2FpdCBta2R0ZW1wKAogICAgcGF0aC5qb2luKG9zLnRtcGRpcigpLCAiZHJhZnQtcHItaW5kZXgtIikKICApOwogIHRyeSB7CiAgICBjb25zdCBlbnYgPSB7CiAgICAgIC4uLmxvY2FsR2l0RW52aXJvbm1lbnQoKSwKICAgICAgR0lUX0lOREVYX0ZJTEU6IHBhdGguam9pbih0ZW1wb3JhcnlEaXJlY3RvcnksICJpbmRleCIpCiAgICB9OwogICAgYXdhaXQgcnVuR2l0KFsicmVhZC10cmVlIiwgIkhFQUQiXSwgeyBjd2Q6IHJlc29sdmVkLCBlbnYgfSk7CiAgICBhd2FpdCBydW5HaXQoWyJhZGQiLCAiLUEiXSwgeyBjd2Q6IHJlc29sdmVkLCBlbnYgfSk7CiAgICBjb25zdCBbaGVhZCwgdHJlZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbCiAgICAgIHJ1bkdpdChbInJldi1wYXJzZSIsICJIRUFEIl0sIHsgY3dkOiByZXNvbHZlZCwgZW52IH0pLAogICAgICBydW5HaXQoWyJ3cml0ZS10cmVlIl0sIHsgY3dkOiByZXNvbHZlZCwgZW52IH0pCiAgICBdKTsKICAgIHJldHVybiB7CiAgICAgIGhlYWRDb21taXQ6IGhlYWQuc3Rkb3V0LnRyaW0oKSwKICAgICAgY2hhbmdlRmluZ2VycHJpbnQ6IHRyZWUuc3Rkb3V0LnRyaW0oKQogICAgfTsKICB9IGZpbmFsbHkgewogICAgYXdhaXQgcm0odGVtcG9yYXJ5RGlyZWN0b3J5LCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7CiAgfQp9CmZ1bmN0aW9uIGFzc2VydFdvcmtzcGFjZVBhdGgocm9vdCwgdmFsdWUpIHsKICBjb25zdCByZXNvbHZlZFJvb3QgPSBwYXRoLnJlc29sdmUocm9vdCk7CiAgY29uc3QgcmVzb2x2ZWQgPSBwYXRoLnJlc29sdmUodmFsdWUpOwogIGNvbnN0IGV4cGVjdGVkUHJlZml4ID0gYCR7cGF0aC5qb2luKHJlc29sdmVkUm9vdCwgInJlcG9zaXRvcmllcyIpfSR7cGF0aC5zZXB9YDsKICBpZiAoIXJlc29sdmVkLnN0YXJ0c1dpdGgoZXhwZWN0ZWRQcmVmaXgpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIndvcmtzcGFjZSBwYXRoIGlzIG91dHNpZGUgdGhlIGNvbmZpZ3VyZWQgRHJhZnQgUFIgcm9vdCIpOwogIH0KICByZXR1cm4gcmVzb2x2ZWQ7Cn0KZnVuY3Rpb24gbG9jYWxHaXRFbnZpcm9ubWVudCgpIHsKICByZXR1cm4gewogICAgUEFUSDogcHJvY2Vzcy5lbnYuUEFUSCwKICAgIEhPTUU6IHByb2Nlc3MuZW52LkhPTUUsCiAgICBMQU5HOiBwcm9jZXNzLmVudi5MQU5HID8/ICJDLlVURi04IiwKICAgIEdJVF9DT05GSUdfTk9TWVNURU06ICIxIiwKICAgIEdJVF9DT05GSUdfR0xPQkFMOiAiL2Rldi9udWxsIiwKICAgIEdJVF9URVJNSU5BTF9QUk9NUFQ6ICIwIgogIH07Cn0KZnVuY3Rpb24gZ2l0Q3VybFJlc29sdmVFbnZpcm9ubWVudCh2YWx1ZSkgewogIGNvbnN0IG5vcm1hbGl6ZWQgPSB2YWx1ZT8udHJpbSgpID8/ICIiOwogIGlmICghbm9ybWFsaXplZCkgcmV0dXJuIHt9OwogIGNvbnN0IFtob3N0LCBwb3J0LCBhZGRyZXNzLCAuLi5leHRyYV0gPSBub3JtYWxpemVkLnNwbGl0KCI6Iik7CiAgaWYgKGhvc3QgIT09ICJnaXRodWIuY29tIiB8fCBwb3J0ICE9PSAiNDQzIiB8fCBpc0lQKGFkZHJlc3MgPz8gIiIpICE9PSA0IHx8IGV4dHJhLmxlbmd0aCA+IDApIHsKICAgIHRocm93IG5ldyBFcnJvcigiRHJhZnQgUFIgR2l0IGN1cmwgcmVzb2x2ZSBtdXN0IHVzZSBnaXRodWIuY29tOjQ0Mzo8SVB2ND4iKTsKICB9CiAgcmV0dXJuIHsKICAgIEdJVF9DT05GSUdfQ09VTlQ6ICIxIiwKICAgIEdJVF9DT05GSUdfS0VZXzA6ICJodHRwLmN1cmxvcHRSZXNvbHZlIiwKICAgIEdJVF9DT05GSUdfVkFMVUVfMDogbm9ybWFsaXplZAogIH07Cn0KYXN5bmMgZnVuY3Rpb24gcnVuR2l0KGFyZ3MsIG9wdGlvbnMpIHsKICBjb25zdCBzYWZlQXJncyA9IG9wdGlvbnMuY3dkID8gWyItYyIsIGBzYWZlLmRpcmVjdG9yeT0ke29wdGlvbnMuY3dkfWAsIC4uLmFyZ3NdIDogYXJnczsKICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gewogICAgY29uc3QgY2hpbGQgPSBzcGF3bigiZ2l0Iiwgc2FmZUFyZ3MsIHsKICAgICAgY3dkOiBvcHRpb25zLmN3ZCwKICAgICAgZW52OiBvcHRpb25zLmVudiwKICAgICAgc3RkaW86IFsiaWdub3JlIiwgInBpcGUiLCAicGlwZSJdCiAgICB9KTsKICAgIGNvbnN0IG1heCA9IG9wdGlvbnMubWF4T3V0cHV0Qnl0ZXMgPz8gMiAqIDEwMjQgKiAxMDI0OwogICAgbGV0IHN0ZG91dCA9ICIiOwogICAgbGV0IHN0ZGVyciA9ICIiOwogICAgbGV0IHNpemUgPSAwOwogICAgY2hpbGQuc3Rkb3V0LnNldEVuY29kaW5nKCJ1dGY4Iik7CiAgICBjaGlsZC5zdGRlcnIuc2V0RW5jb2RpbmcoInV0ZjgiKTsKICAgIGNoaWxkLnN0ZG91dC5vbigiZGF0YSIsIChjaHVuaykgPT4gewogICAgICBzaXplICs9IEJ1ZmZlci5ieXRlTGVuZ3RoKGNodW5rKTsKICAgICAgaWYgKHNpemUgPD0gbWF4KSBzdGRvdXQgKz0gY2h1bms7CiAgICB9KTsKICAgIGNoaWxkLnN0ZGVyci5vbigiZGF0YSIsIChjaHVuaykgPT4gewogICAgICBzaXplICs9IEJ1ZmZlci5ieXRlTGVuZ3RoKGNodW5rKTsKICAgICAgaWYgKHNpemUgPD0gbWF4KSBzdGRlcnIgKz0gY2h1bms7CiAgICB9KTsKICAgIGNoaWxkLm9uKCJlcnJvciIsIHJlamVjdCk7CiAgICBjaGlsZC5vbigiY2xvc2UiLCAoY29kZSkgPT4gewogICAgICBjb25zdCBleGl0Q29kZSA9IGNvZGUgPz8gMTsKICAgICAgaWYgKHNpemUgPiBtYXgpIHsKICAgICAgICByZWplY3QobmV3IEVycm9yKCJnaXQgY29tbWFuZCBvdXRwdXQgZXhjZWVkZWQgdGhlIGNvbmZpZ3VyZWQgbGltaXQiKSk7CiAgICAgIH0gZWxzZSBpZiAoZXhpdENvZGUgIT09IDAgJiYgIW9wdGlvbnMuYWxsb3dGYWlsdXJlKSB7CiAgICAgICAgcmVqZWN0KAogICAgICAgICAgbmV3IEVycm9yKAogICAgICAgICAgICBgZ2l0ICR7YXJnc1swXSA/PyAiY29tbWFuZCJ9IGZhaWxlZDogJHtzdGRlcnIudHJpbSgpLnNsaWNlKC0yZTMpfWAKICAgICAgICAgICkKICAgICAgICApOwogICAgICB9IGVsc2UgewogICAgICAgIHJlc29sdmUoeyBzdGRvdXQsIHN0ZGVyciwgZXhpdENvZGUgfSk7CiAgICAgIH0KICAgIH0pOwogIH0pOwp9CmZ1bmN0aW9uIHZhbGlkYXRlQ2xvbmVVcmwodmFsdWUpIHsKICBjb25zdCB1cmwgPSBuZXcgVVJMKHZhbHVlKTsKICBpZiAodXJsLnByb3RvY29sICE9PSAiaHR0cHM6IiB8fCB1cmwudXNlcm5hbWUgfHwgdXJsLnBhc3N3b3JkKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkRyYWZ0IFBSIGNsb25lIFVSTCBtdXN0IGJlIGNyZWRlbnRpYWwtZnJlZSBIVFRQUyIpOwogIH0KfQpmdW5jdGlvbiB2YWxpZGF0ZUdpdFJlZih2YWx1ZSwgbmFtZSkgewogIGlmICghL15bQS1aYS16MC05XVtBLVphLXowLTkuXy8tXSokLy50ZXN0KHZhbHVlKSB8fCB2YWx1ZS5pbmNsdWRlcygiLi4iKSB8fCB2YWx1ZS5pbmNsdWRlcygiLy8iKSB8fCB2YWx1ZS5lbmRzV2l0aCgiLyIpIHx8IHZhbHVlLmVuZHNXaXRoKCIubG9jayIpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgJHtuYW1lfTogJHt2YWx1ZX1gKTsKICB9Cn0KZnVuY3Rpb24gc2NhbkFkZGVkTGluZXNGb3JTZWNyZXRzKGRpZmYpIHsKICBjb25zdCBmaW5kaW5ncyA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KCk7CiAgbGV0IGN1cnJlbnRQYXRoID0gInVua25vd24iOwogIGNvbnN0IHBhdHRlcm5zID0gWwogICAgLy0tLS0tQkVHSU4gW0EtWiBdKlBSSVZBVEUgS0VZLS0tLS0vLAogICAgL1xiZ2hwX1tBLVphLXowLTldezMwLH1cYi8sCiAgICAvXGJnaXRodWJfcGF0X1tBLVphLXowLTlfXXszMCx9XGIvLAogICAgL1xiQUtJQVswLTlBLVpdezE2fVxiLywKICAgIC9BdXRob3JpemF0aW9uOlxzKkJlYXJlclxzK1tBLVphLXowLTkuXy1dezIwLH0vaQogIF07CiAgZm9yIChjb25zdCBsaW5lIG9mIGRpZmYuc3BsaXQoIlxuIikpIHsKICAgIGlmIChsaW5lLnN0YXJ0c1dpdGgoIisrKyBiLyIpKSBjdXJyZW50UGF0aCA9IGxpbmUuc2xpY2UoNik7CiAgICBpZiAoIWxpbmUuc3RhcnRzV2l0aCgiKyIpIHx8IGxpbmUuc3RhcnRzV2l0aCgiKysrIikpIGNvbnRpbnVlOwogICAgaWYgKHBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChsaW5lKSkpCiAgICAgIGZpbmRpbmdzLmFkZChjdXJyZW50UGF0aCk7CiAgfQogIHJldHVybiBbLi4uZmluZGluZ3NdLnNvcnQoKTsKfQpmdW5jdGlvbiBpc0FscmVhZHlFeGlzdHMoZXJyb3IpIHsKICByZXR1cm4gdHlwZW9mIGVycm9yID09PSAib2JqZWN0IiAmJiBlcnJvciAhPT0gbnVsbCAmJiAiY29kZSIgaW4gZXJyb3IgJiYgZXJyb3IuY29kZSA9PT0gIkVFWElTVCI7Cn0KCi8vIHNyYy9kcmFmdC1wci9jaS10b29sLnRzCnZhciBGQUlMRURfQ09OQ0xVU0lPTlMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbCiAgImFjdGlvbl9yZXF1aXJlZCIsCiAgImZhaWx1cmUiLAogICJzdGFydHVwX2ZhaWx1cmUiLAogICJ0aW1lZF9vdXQiCl0pOwp2YXIgTUFYX0FOTk9UQVRJT05TX1BFUl9DSEVDSyA9IDUwOwphc3luYyBmdW5jdGlvbiBwcmVwYXJlQ2lGaXgocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIsIGV4cGVjdGVkSGVhZFNoYSwgY2hlY2tTdWl0ZUlkLCBkZXBlbmRlbmNpZXMpIHsKICBhc3NlcnRBbGxvd2VkUmVwb3NpdG9yeShyZXBvc2l0b3J5LCBkZXBlbmRlbmNpZXMuYWxsb3dlZFJlcG9zaXRvcnkpOwogIHJlcXVpcmVCb3RJZGVudGl0eShkZXBlbmRlbmNpZXMpOwogIHZhbGlkYXRlRXZlbnRUYXJnZXQoZXhwZWN0ZWRIZWFkU2hhLCBjaGVja1N1aXRlSWQpOwogIGNvbnN0IFtwdWxsUmVxdWVzdCwgY29tbWVudHNdID0gYXdhaXQgUHJvbWlzZS5hbGwoWwogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmdldFB1bGxSZXF1ZXN0KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyKSwKICAgIGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpCiAgXSk7CiAgY29uc3QgcmVhc29uID0gaW5lbGlnaWJsZVJlYXNvbihwdWxsUmVxdWVzdCwgcmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzKTsKICBpZiAocmVhc29uKSB7CiAgICByZXR1cm4gc2tpcHBlZChyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgY2hlY2tTdWl0ZUlkLCByZWFzb24pOwogIH0KICBpZiAocHVsbFJlcXVlc3QuaGVhZFNoYSAhPT0gZXhwZWN0ZWRIZWFkU2hhKSB7CiAgICByZXR1cm4gc2tpcHBlZCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGNoZWNrU3VpdGVJZCwKICAgICAgIkNJIGV2ZW50IGlzIGZvciBhIHN0YWxlIFB1bGwgUmVxdWVzdCBoZWFkIgogICAgKTsKICB9CiAgY29uc3Qgc3RhdGUgPSBjaVN0YXRlKGNvbW1lbnRzLCBkZXBlbmRlbmNpZXMpOwogIGlmIChzdGF0ZS5jaGVja1N1aXRlSWQgPT09IGNoZWNrU3VpdGVJZCAmJiBbIm5vLWNoYW5nZSIsICJuZWVkcy1hcHByb3ZhbCJdLmluY2x1ZGVzKHN0YXRlLnN0YXR1cykpIHsKICAgIHJldHVybiBza2lwcGVkKAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgY2hlY2tTdWl0ZUlkLAogICAgICAiQ0kgY2hlY2sgc3VpdGUgd2FzIGFscmVhZHkgcHJvY2Vzc2VkIgogICAgKTsKICB9CiAgaWYgKHN0YXRlLmF0dGVtcHRzID49IGRlcGVuZGVuY2llcy5wb2xpY3kubWF4Rml4SXRlcmF0aW9ucykgewogICAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgICBhd2FpdCB1cHNlcnRDaVN0YXRlKAogICAgICAgIHJlcG9zaXRvcnksCiAgICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgICAgewogICAgICAgICAgY2hlY2tTdWl0ZUlkLAogICAgICAgICAgYXR0ZW1wdHM6IHN0YXRlLmF0dGVtcHRzLAogICAgICAgICAgaGVhZFNoYTogZXhwZWN0ZWRIZWFkU2hhLAogICAgICAgICAgc3RhdHVzOiAibmVlZHMtYXBwcm92YWwiCiAgICAgICAgfSwKICAgICAgICBjb21tZW50cywKICAgICAgICBkZXBlbmRlbmNpZXMKICAgICAgKTsKICAgIH0KICAgIHJldHVybiBza2lwcGVkKAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgY2hlY2tTdWl0ZUlkLAogICAgICAiYXV0b21hdGljIENJIGZpeCBpdGVyYXRpb24gbGltaXQgcmVhY2hlZCIKICAgICk7CiAgfQogIGNvbnN0IGZhaWx1cmVzID0gYXdhaXQgbG9hZEZhaWx1cmVzKAogICAgcmVwb3NpdG9yeSwKICAgIGV4cGVjdGVkSGVhZFNoYSwKICAgIGNoZWNrU3VpdGVJZCwKICAgIGRlcGVuZGVuY2llcwogICk7CiAgaWYgKGZhaWx1cmVzLmxlbmd0aCA9PT0gMCkgewogICAgcmV0dXJuIHNraXBwZWQoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICBjaGVja1N1aXRlSWQsCiAgICAgICJjaGVjayBzdWl0ZSBoYXMgbm8gc3VwcG9ydGVkIGZhaWxlZCBjaGVja3MiCiAgICApOwogIH0KICBsZXQgcHJlcGFyZWQ7CiAgdHJ5IHsKICAgIHByZXBhcmVkID0gYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5wcmVwYXJlUmV2aWV3KHsKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGNsb25lVXJsOiByZXBvc2l0b3J5Q2xvbmVVcmwoZGVwZW5kZW5jaWVzLnNlcnZlclVybCwgcmVwb3NpdG9yeSksCiAgICAgIGJhc2VCcmFuY2g6IHB1bGxSZXF1ZXN0LmJhc2UsCiAgICAgIGJyYW5jaDogcHVsbFJlcXVlc3QuaGVhZCwKICAgICAgZXhwZWN0ZWRIZWFkU2hhCiAgICB9KTsKICB9IGNhdGNoIChlcnJvcikgewogICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRHJhZnRQcldvcmtzcGFjZUxvY2tFcnJvcikgewogICAgICByZXR1cm4gc2tpcHBlZCgKICAgICAgICByZXBvc2l0b3J5LAogICAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICAgIGNoZWNrU3VpdGVJZCwKICAgICAgICAiYW5vdGhlciBQdWxsIFJlcXVlc3QgZml4IHJ1biBob2xkcyB0aGUgd29ya3NwYWNlIGxvY2siCiAgICAgICk7CiAgICB9CiAgICB0aHJvdyBlcnJvcjsKICB9CiAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgYXdhaXQgdXBzZXJ0Q2lTdGF0ZSgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIHsKICAgICAgICBjaGVja1N1aXRlSWQsCiAgICAgICAgYXR0ZW1wdHM6IHN0YXRlLmF0dGVtcHRzLAogICAgICAgIGhlYWRTaGE6IGV4cGVjdGVkSGVhZFNoYSwKICAgICAgICBzdGF0dXM6ICJmaXhpbmciCiAgICAgIH0sCiAgICAgIGNvbW1lbnRzLAogICAgICBkZXBlbmRlbmNpZXMKICAgICk7CiAgfQogIHJldHVybiB7CiAgICBvazogdHJ1ZSwKICAgIHJlcG9zaXRvcnksCiAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgIGNoZWNrU3VpdGVJZCwKICAgIHdvcmtzcGFjZVBhdGg6IHByZXBhcmVkLnBhdGgsCiAgICBicmFuY2g6IHByZXBhcmVkLmJyYW5jaCwKICAgIGJhc2VCcmFuY2g6IHByZXBhcmVkLmJhc2VCcmFuY2gsCiAgICBleHBlY3RlZEhlYWRTaGE6IHByZXBhcmVkLmJhc2VDb21taXQsCiAgICBmYWlsdXJlc0ZpbmdlcnByaW50OiBmaW5nZXJwcmludEZhaWx1cmVzKGZhaWx1cmVzKSwKICAgIHByZXZpb3VzQXR0ZW1wdHM6IHN0YXRlLmF0dGVtcHRzLAogICAgZmFpbHVyZXMKICB9Owp9CmFzeW5jIGZ1bmN0aW9uIGFwcGx5Q2lGaXgocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIsIHN1Ym1pc3Npb25JbnB1dCwgZGVwZW5kZW5jaWVzKSB7CiAgYXNzZXJ0QWxsb3dlZFJlcG9zaXRvcnkocmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzLmFsbG93ZWRSZXBvc2l0b3J5KTsKICByZXF1aXJlQm90SWRlbnRpdHkoZGVwZW5kZW5jaWVzKTsKICBjb25zdCBzdWJtaXNzaW9uID0gY2lGaXhTdWJtaXNzaW9uU2NoZW1hLnBhcnNlKHN1Ym1pc3Npb25JbnB1dCk7CiAgY29uc3QgW3B1bGxSZXF1ZXN0LCBjb21tZW50cywgZmFpbHVyZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoWwogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmdldFB1bGxSZXF1ZXN0KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyKSwKICAgIGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpLAogICAgbG9hZEZhaWx1cmVzKAogICAgICByZXBvc2l0b3J5LAogICAgICBzdWJtaXNzaW9uLmV4cGVjdGVkSGVhZFNoYSwKICAgICAgc3VibWlzc2lvbi5jaGVja1N1aXRlSWQsCiAgICAgIGRlcGVuZGVuY2llcwogICAgKQogIF0pOwogIGNvbnN0IHJlYXNvbiA9IGluZWxpZ2libGVSZWFzb24ocHVsbFJlcXVlc3QsIHJlcG9zaXRvcnksIGRlcGVuZGVuY2llcyk7CiAgaWYgKHJlYXNvbikgdGhyb3cgbmV3IEVycm9yKHJlYXNvbik7CiAgaWYgKHB1bGxSZXF1ZXN0LmhlYWRTaGEgIT09IHN1Ym1pc3Npb24uZXhwZWN0ZWRIZWFkU2hhKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIlB1bGwgUmVxdWVzdCBoZWFkIGNoYW5nZWQgYWZ0ZXIgQ0kgZml4IHByZXBhcmF0aW9uIik7CiAgfQogIGNvbnN0IGV4cGVjdGVkSWRzID0gc3VibWlzc2lvbi5jaGVja1JlZnMubWFwKCh2YWx1ZSkgPT4gdmFsdWUuY2hlY2tSdW5JZCk7CiAgY29uc3QgYWN0dWFsSWRzID0gZmFpbHVyZXMubWFwKCh2YWx1ZSkgPT4gdmFsdWUuY2hlY2tSdW5JZCk7CiAgaWYgKG5ldyBTZXQoZXhwZWN0ZWRJZHMpLnNpemUgIT09IGV4cGVjdGVkSWRzLmxlbmd0aCB8fCBleHBlY3RlZElkcy5sZW5ndGggIT09IGFjdHVhbElkcy5sZW5ndGggfHwgZXhwZWN0ZWRJZHMuc29tZSgoaWQsIGluZGV4KSA9PiBpZCAhPT0gYWN0dWFsSWRzW2luZGV4XSkgfHwgZmluZ2VycHJpbnRGYWlsdXJlcyhmYWlsdXJlcykgIT09IHN1Ym1pc3Npb24uZmFpbHVyZXNGaW5nZXJwcmludCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmYWlsZWQgQ0kgY2hlY2tzIGNoYW5nZWQgYWZ0ZXIgZml4IHByZXBhcmF0aW9uIik7CiAgfQogIHZhbGlkYXRlRmFpbHVyZUNvdmVyYWdlKHN1Ym1pc3Npb24uYW5hbHlzaXMsIGV4cGVjdGVkSWRzKTsKICBjb25zdCBpbnNwZWN0aW9uID0gYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5pbnNwZWN0KAogICAgc3VibWlzc2lvbi53b3Jrc3BhY2VQYXRoCiAgKTsKICBpZiAoaW5zcGVjdGlvbi5oZWFkQ29tbWl0ICE9PSBzdWJtaXNzaW9uLmV4cGVjdGVkSGVhZFNoYSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJ0aGUgQWdlbnQgY29tbWl0dGVkIG9yIG1vdmVkIEhFQUQgaW4gdGhlIENJIHdvcmtzcGFjZSIpOwogIH0KICBjb25zdCBuZXh0QXR0ZW1wdHMgPSBzdWJtaXNzaW9uLnByZXZpb3VzQXR0ZW1wdHMgKyAxOwogIGlmIChzdWJtaXNzaW9uLmFuYWx5c2lzLm91dGNvbWUgIT09ICJmaXhlZCIpIHsKICAgIGlmIChpbnNwZWN0aW9uLmNoYW5nZWRGaWxlcy5sZW5ndGggPiAwKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgICBgJHtzdWJtaXNzaW9uLmFuYWx5c2lzLm91dGNvbWV9IENJIHJlc3VsdCBjb250YWlucyBjaGFuZ2VzYAogICAgICApOwogICAgfQogICAgaWYgKHN1Ym1pc3Npb24uYW5hbHlzaXMub3V0Y29tZSA9PT0gIm5vX2NoYW5nZSIgJiYgc3VibWlzc2lvbi5hbmFseXNpcy5mYWlsdXJlcy5zb21lKAogICAgICAoZmFpbHVyZSkgPT4gZmFpbHVyZS5kaXNwb3NpdGlvbiAhPT0gIm5vdF9yZXByb2R1Y2libGUiCiAgICApKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgICAibm9fY2hhbmdlIENJIHJlc3VsdCByZXF1aXJlcyBldmVyeSBmYWlsdXJlIHRvIGJlIG5vdCByZXByb2R1Y2libGUiCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBzdGF0dXMgPSBzdWJtaXNzaW9uLmFuYWx5c2lzLm91dGNvbWUgPT09ICJuZWVkc19hcHByb3ZhbCIgPyAibmVlZHMtYXBwcm92YWwiIDogc3VibWlzc2lvbi5hbmFseXNpcy5vdXRjb21lID09PSAibm9fY2hhbmdlIiA/ICJuby1jaGFuZ2UiIDogImZhaWxlZCI7CiAgICBhd2FpdCBmaW5pc2hXaXRob3V0UHVzaCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIHN1Ym1pc3Npb24sCiAgICAgIG5leHRBdHRlbXB0cywKICAgICAgc3RhdHVzLAogICAgICBjb21tZW50cywKICAgICAgZGVwZW5kZW5jaWVzCiAgICApOwogICAgcmV0dXJuIHsKICAgICAgb2s6IHRydWUsCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICBhcHBsaWVkOiBkZXBlbmRlbmNpZXMuYXBwbHksCiAgICAgIG91dGNvbWU6IHN1Ym1pc3Npb24uYW5hbHlzaXMub3V0Y29tZSwKICAgICAgaW5zcGVjdGlvbgogICAgfTsKICB9CiAgdmFsaWRhdGVGaXhlZEFuYWx5c2lzKHN1Ym1pc3Npb24uYW5hbHlzaXMsIGluc3BlY3Rpb24pOwogIGNvbnN0IGFwcHJvdmFsUmVhc29ucyA9IHJlcXVpcmVzQXBwcm92YWwoCiAgICBzdWJtaXNzaW9uLmFuYWx5c2lzLAogICAgaW5zcGVjdGlvbiwKICAgIGZhbHNlLAogICAgZGVwZW5kZW5jaWVzLnBvbGljeQogICk7CiAgaWYgKGFwcHJvdmFsUmVhc29ucy5sZW5ndGggPiAwKSB7CiAgICBhd2FpdCBmaW5pc2hXaXRob3V0UHVzaCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIHN1Ym1pc3Npb24sCiAgICAgIG5leHRBdHRlbXB0cywKICAgICAgIm5lZWRzLWFwcHJvdmFsIiwKICAgICAgY29tbWVudHMsCiAgICAgIGRlcGVuZGVuY2llcwogICAgKTsKICAgIHJldHVybiB7CiAgICAgIG9rOiB0cnVlLAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgYXBwbGllZDogZGVwZW5kZW5jaWVzLmFwcGx5LAogICAgICBvdXRjb21lOiAibmVlZHNfYXBwcm92YWwiLAogICAgICBpbnNwZWN0aW9uCiAgICB9OwogIH0KICBpZiAoIWRlcGVuZGVuY2llcy5hcHBseSkgewogICAgYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5jbGVhbnVwUmV2aWV3KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyKTsKICAgIHJldHVybiB7CiAgICAgIG9rOiB0cnVlLAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgYXBwbGllZDogZmFsc2UsCiAgICAgIG91dGNvbWU6ICJmaXhlZCIsCiAgICAgIGluc3BlY3Rpb24KICAgIH07CiAgfQogIGNvbnN0IGNvbW1pdCA9IGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY29tbWl0QW5kUHVzaCgKICAgIHN1Ym1pc3Npb24ud29ya3NwYWNlUGF0aCwKICAgIHN1Ym1pc3Npb24uYnJhbmNoLAogICAgc2FuaXRpemVUaXRsZShzdWJtaXNzaW9uLmFuYWx5c2lzLmNvbW1pdFRpdGxlKSwKICAgIHJlcG9zaXRvcnlDbG9uZVVybChkZXBlbmRlbmNpZXMuc2VydmVyVXJsLCByZXBvc2l0b3J5KQogICk7CiAgYXdhaXQgdXBzZXJ0Q2lTdGF0ZSgKICAgIHJlcG9zaXRvcnksCiAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgIHsKICAgICAgY2hlY2tTdWl0ZUlkOiBzdWJtaXNzaW9uLmNoZWNrU3VpdGVJZCwKICAgICAgYXR0ZW1wdHM6IG5leHRBdHRlbXB0cywKICAgICAgaGVhZFNoYTogY29tbWl0LAogICAgICBzdGF0dXM6ICJmaXhlZCIKICAgIH0sCiAgICBjb21tZW50cywKICAgIGRlcGVuZGVuY2llcwogICk7CiAgYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5jbGVhbnVwUmV2aWV3KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyKTsKICByZXR1cm4gewogICAgb2s6IHRydWUsCiAgICByZXBvc2l0b3J5LAogICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICBhcHBsaWVkOiB0cnVlLAogICAgb3V0Y29tZTogImZpeGVkIiwKICAgIGNvbW1pdCwKICAgIGluc3BlY3Rpb24KICB9Owp9CmFzeW5jIGZ1bmN0aW9uIGZhaWxDaUZpeChyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgY2hlY2tTdWl0ZUlkLCBhdHRlbXB0cywgaGVhZFNoYSwgZGVwZW5kZW5jaWVzKSB7CiAgYXNzZXJ0QWxsb3dlZFJlcG9zaXRvcnkocmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzLmFsbG93ZWRSZXBvc2l0b3J5KTsKICB0cnkgewogICAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgICBjb25zdCBjb21tZW50cyA9IGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q29tbWVudHMoCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBwdWxsUmVxdWVzdE51bWJlcgogICAgICApOwogICAgICBhd2FpdCB1cHNlcnRDaVN0YXRlKAogICAgICAgIHJlcG9zaXRvcnksCiAgICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgICAgewogICAgICAgICAgY2hlY2tTdWl0ZUlkLAogICAgICAgICAgYXR0ZW1wdHMsCiAgICAgICAgICBoZWFkU2hhLAogICAgICAgICAgc3RhdHVzOiAiZmFpbGVkIgogICAgICAgIH0sCiAgICAgICAgY29tbWVudHMsCiAgICAgICAgZGVwZW5kZW5jaWVzCiAgICAgICk7CiAgICB9CiAgfSBmaW5hbGx5IHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlcik7CiAgfQogIHJldHVybiB7CiAgICBvazogdHJ1ZSwKICAgIHJlcG9zaXRvcnksCiAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgIGFwcGxpZWQ6IGRlcGVuZGVuY2llcy5hcHBseSwKICAgIG91dGNvbWU6ICJmYWlsZWQiCiAgfTsKfQphc3luYyBmdW5jdGlvbiBsb2FkRmFpbHVyZXMocmVwb3NpdG9yeSwgaGVhZFNoYSwgY2hlY2tTdWl0ZUlkLCBkZXBlbmRlbmNpZXMpIHsKICBjb25zdCBydW5zID0gKGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q2hlY2tSdW5zKHJlcG9zaXRvcnksIGhlYWRTaGEpKS5maWx0ZXIoCiAgICAocnVuKSA9PiBydW4uY2hlY2tTdWl0ZUlkID09PSBjaGVja1N1aXRlSWQgJiYgcnVuLnN0YXR1cyA9PT0gImNvbXBsZXRlZCIgJiYgRkFJTEVEX0NPTkNMVVNJT05TLmhhcyhydW4uY29uY2x1c2lvbiA/PyAiIikKICApLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0LmlkIC0gcmlnaHQuaWQpOwogIGlmIChydW5zLmxlbmd0aCA+IGRlcGVuZGVuY2llcy5wb2xpY3kubWF4UmV2aWV3Q29tbWVudHMpIHsKICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgYENJIGNoZWNrIHN1aXRlIGhhcyAke3J1bnMubGVuZ3RofSBmYWlsZWQgY2hlY2tzIChsaW1pdCAke2RlcGVuZGVuY2llcy5wb2xpY3kubWF4UmV2aWV3Q29tbWVudHN9KWAKICAgICk7CiAgfQogIHJldHVybiBQcm9taXNlLmFsbCgKICAgIHJ1bnMubWFwKGFzeW5jIChydW4pID0+ICh7CiAgICAgIGNoZWNrUnVuSWQ6IHJ1bi5pZCwKICAgICAgbmFtZTogcnVuLm5hbWUsCiAgICAgIGNvbmNsdXNpb246IHJ1bi5jb25jbHVzaW9uLAogICAgICAuLi5ydW4uaHRtbFVybCA/IHsgaHRtbFVybDogcnVuLmh0bWxVcmwgfSA6IHt9LAogICAgICBvdXRwdXQ6IHJ1bi5vdXRwdXQsCiAgICAgIGFubm90YXRpb25zOiAoYXdhaXQgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmxpc3RDaGVja1J1bkFubm90YXRpb25zKHJlcG9zaXRvcnksIHJ1bi5pZCkpLnNsaWNlKDAsIE1BWF9BTk5PVEFUSU9OU19QRVJfQ0hFQ0spCiAgICB9KSkKICApOwp9CmZ1bmN0aW9uIGZpbmdlcnByaW50RmFpbHVyZXMoZmFpbHVyZXMpIHsKICByZXR1cm4gY3J5cHRvMy5jcmVhdGVIYXNoKCJzaGEyNTYiKS51cGRhdGUoSlNPTi5zdHJpbmdpZnkoZmFpbHVyZXMpKS5kaWdlc3QoImhleCIpLnNsaWNlKDAsIDIwKTsKfQpmdW5jdGlvbiB2YWxpZGF0ZUZhaWx1cmVDb3ZlcmFnZShhbmFseXNpcywgZXhwZWN0ZWRJZHMpIHsKICBjb25zdCBhY3R1YWwgPSBhbmFseXNpcy5mYWlsdXJlcy5tYXAoKGZhaWx1cmUpID0+IGZhaWx1cmUuY2hlY2tSdW5JZCk7CiAgaWYgKG5ldyBTZXQoYWN0dWFsKS5zaXplICE9PSBhY3R1YWwubGVuZ3RoIHx8IGFjdHVhbC5sZW5ndGggIT09IGV4cGVjdGVkSWRzLmxlbmd0aCB8fCBhY3R1YWwuc29tZSgoaWQsIGluZGV4KSA9PiBpZCAhPT0gZXhwZWN0ZWRJZHNbaW5kZXhdKSkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAiQ0kgZml4IGFuYWx5c2lzIG11c3QgYWRkcmVzcyBldmVyeSBmYWlsZWQgY2hlY2sgZXhhY3RseSBvbmNlIgogICAgKTsKICB9CiAgaWYgKGFuYWx5c2lzLm91dGNvbWUgPT09ICJmaXhlZCIgJiYgYW5hbHlzaXMuZmFpbHVyZXMuc29tZSgKICAgIChmYWlsdXJlKSA9PiBmYWlsdXJlLmRpc3Bvc2l0aW9uID09PSAibmVlZHNfYXBwcm92YWwiCiAgKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXhlZCBDSSByZXN1bHQgY2Fubm90IGNvbnRhaW4gYXBwcm92YWwtZ2F0ZWQgZmFpbHVyZXMiKTsKICB9Cn0KZnVuY3Rpb24gdmFsaWRhdGVGaXhlZEFuYWx5c2lzKGFuYWx5c2lzLCBpbnNwZWN0aW9uKSB7CiAgaWYgKGluc3BlY3Rpb24uY2hhbmdlZEZpbGVzLmxlbmd0aCA9PT0gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXhlZCBDSSByZXN1bHQgY29udGFpbnMgbm8gcmVwb3NpdG9yeSBjaGFuZ2VzIik7CiAgfQogIGlmICghaW5zcGVjdGlvbi5kaWZmQ2hlY2tQYXNzZWQpIHsKICAgIHRocm93IG5ldyBFcnJvcigiQ0kgZml4IGZhaWxlZCBnaXQgZGlmZiAtLWNoZWNrIik7CiAgfQogIGlmIChpbnNwZWN0aW9uLnNlY3JldEZpbmRpbmdQYXRocy5sZW5ndGggPiAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkNJIGZpeCBjb250YWlucyBwb3RlbnRpYWwgY3JlZGVudGlhbCBtYXRlcmlhbCIpOwogIH0KICBpZiAoYW5hbHlzaXMudmFsaWRhdGlvbk92ZXJyaWRlICYmICFoYXNDb25zaXN0ZW50VmFsaWRhdGlvbk92ZXJyaWRlKGFuYWx5c2lzKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXhlZCBDSSByZXN1bHQgaGFzIGFuIGluY29uc2lzdGVudCB2YWxpZGF0aW9uIG92ZXJyaWRlIik7CiAgfQogIGlmIChhbmFseXNpcy50ZXN0cy5zb21lKCh0ZXN0KSA9PiB0ZXN0LnN0YXR1cyA9PT0gImZhaWxlZCIpICYmICFoYXNDb25zaXN0ZW50VmFsaWRhdGlvbk92ZXJyaWRlKGFuYWx5c2lzKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXhlZCBDSSByZXN1bHQgcmVwb3J0cyBhIGZhaWxlZCB2YWxpZGF0aW9uIGNvbW1hbmQiKTsKICB9Cn0KZnVuY3Rpb24gaW5lbGlnaWJsZVJlYXNvbihwdWxsUmVxdWVzdCwgcmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzKSB7CiAgaWYgKHB1bGxSZXF1ZXN0LnN0YXRlLnRvTG93ZXJDYXNlKCkgIT09ICJvcGVuIikKICAgIHJldHVybiAiUHVsbCBSZXF1ZXN0IGlzIG5vdCBvcGVuIjsKICBpZiAoIXB1bGxSZXF1ZXN0LmhlYWQuc3RhcnRzV2l0aChkZXBlbmRlbmNpZXMucG9saWN5LmJyYW5jaFByZWZpeCkpIHsKICAgIHJldHVybiAiUHVsbCBSZXF1ZXN0IGJyYW5jaCBpcyBub3QgbWFuYWdlZCBieSB0aGUgRHJhZnQgUFIgQWdlbnQiOwogIH0KICBpZiAocHVsbFJlcXVlc3QuaGVhZFJlcG9zaXRvcnk/LnRyaW0oKS50b0xvd2VyQ2FzZSgpICE9PSByZXBvc2l0b3J5LnRyaW0oKS50b0xvd2VyQ2FzZSgpKSB7CiAgICByZXR1cm4gIlB1bGwgUmVxdWVzdCBoZWFkIHJlcG9zaXRvcnkgaXMgbm90IHRoZSBhbGxvd2xpc3RlZCByZXBvc2l0b3J5IjsKICB9CiAgaWYgKCFwdWxsUmVxdWVzdC5oZWFkU2hhIHx8ICEvXlswLTlhLWZdezQwfSQvLnRlc3QocHVsbFJlcXVlc3QuaGVhZFNoYSkpIHsKICAgIHJldHVybiAiUHVsbCBSZXF1ZXN0IGhhcyBubyB2YWxpZCBoZWFkIFNIQSI7CiAgfQogIHJldHVybiB2b2lkIDA7Cn0KZnVuY3Rpb24gdmFsaWRhdGVFdmVudFRhcmdldChoZWFkU2hhLCBjaGVja1N1aXRlSWQpIHsKICBpZiAoIS9eWzAtOWEtZl17NDB9JC8udGVzdChoZWFkU2hhKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJpbnZhbGlkIENJIGV2ZW50IGhlYWQgU0hBIik7CiAgfQogIGlmICghTnVtYmVyLmlzU2FmZUludGVnZXIoY2hlY2tTdWl0ZUlkKSB8fCBjaGVja1N1aXRlSWQgPD0gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJpbnZhbGlkIENJIGNoZWNrIHN1aXRlIElEIik7CiAgfQp9CmZ1bmN0aW9uIGNpU3RhdGUoY29tbWVudHMsIGRlcGVuZGVuY2llcykgewogIHJldHVybiBwYXJzZUNpRml4U3RhdGUoCiAgICBmaW5kQ2lGaXhDb21tZW50KGNvbW1lbnRzLCBkZXBlbmRlbmNpZXMuYm90TG9naW4/LnRyaW0oKSA/PyAiIikKICApOwp9CmFzeW5jIGZ1bmN0aW9uIGZpbmlzaFdpdGhvdXRQdXNoKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCBzdWJtaXNzaW9uLCBhdHRlbXB0cywgc3RhdHVzLCBjb21tZW50cywgZGVwZW5kZW5jaWVzKSB7CiAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgYXdhaXQgdXBzZXJ0Q2lTdGF0ZSgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIHsKICAgICAgICBjaGVja1N1aXRlSWQ6IHN1Ym1pc3Npb24uY2hlY2tTdWl0ZUlkLAogICAgICAgIGF0dGVtcHRzLAogICAgICAgIGhlYWRTaGE6IHN1Ym1pc3Npb24uZXhwZWN0ZWRIZWFkU2hhLAogICAgICAgIHN0YXR1cwogICAgICB9LAogICAgICBjb21tZW50cywKICAgICAgZGVwZW5kZW5jaWVzCiAgICApOwogIH0KICBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmNsZWFudXBSZXZpZXcocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpOwp9CmFzeW5jIGZ1bmN0aW9uIHVwc2VydENpU3RhdGUocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIsIHN0YXRlLCBjb21tZW50cywgZGVwZW5kZW5jaWVzKSB7CiAgY29uc3QgYm90TG9naW4gPSBkZXBlbmRlbmNpZXMuYm90TG9naW4/LnRyaW0oKSA/PyAiIjsKICBpZiAoIWJvdExvZ2luKSB0aHJvdyBuZXcgRXJyb3IoIkdpdEh1YiBib3QgbG9naW4gaXMgcmVxdWlyZWQgaW4gYXBwbHkgbW9kZSIpOwogIGNvbnN0IGV4aXN0aW5nID0gZmluZENpRml4Q29tbWVudChjb21tZW50cywgYm90TG9naW4pOwogIGNvbnN0IGJvZHkgPSBidWlsZENpRml4Q29tbWVudChzdGF0ZSk7CiAgaWYgKGV4aXN0aW5nKSB7CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIudXBkYXRlQ29tbWVudCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGV4aXN0aW5nLmlkLAogICAgICBib2R5CiAgICApOwogIH0gZWxzZSB7CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIuY3JlYXRlQ29tbWVudCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGJvZHkKICAgICk7CiAgfQp9CmZ1bmN0aW9uIHJlcXVpcmVCb3RJZGVudGl0eShkZXBlbmRlbmNpZXMpIHsKICBpZiAoZGVwZW5kZW5jaWVzLmFwcGx5ICYmICFkZXBlbmRlbmNpZXMuYm90TG9naW4/LnRyaW0oKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJHaXRIdWIgYm90IGxvZ2luIGlzIHJlcXVpcmVkIGZvciBDSSBmaXhlcyBpbiBhcHBseSBtb2RlIik7CiAgfQp9CmZ1bmN0aW9uIHNraXBwZWQocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIsIGNoZWNrU3VpdGVJZCwgcmVhc29uKSB7CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgc2tpcHBlZDogdHJ1ZSwKICAgIHJlYXNvbiwKICAgIHJlcG9zaXRvcnksCiAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgIGNoZWNrU3VpdGVJZAogIH07Cn0KCi8vIHNyYy9kcmFmdC1wci9yZXZpZXctdG9vbC50cwppbXBvcnQgY3J5cHRvNCBmcm9tICJub2RlOmNyeXB0byI7CgovLyBzcmMvZHJhZnQtcHIvcmV2aWV3LWNvbW1lbnQudHMKdmFyIFJFVklFV19GSVhfQ09NTUVOVF9QUkVGSVggPSAiPCEtLSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3M6cmV2aWV3LWZpeDp2IjsKdmFyIFJFVklFV19GSVhfQ09NTUVOVF9WMl9QUkVGSVggPSBgJHtSRVZJRVdfRklYX0NPTU1FTlRfUFJFRklYfTJgOwp2YXIgUkVWSUVXX0ZJWF9DT01NRU5UX1YzX1BSRUZJWCA9IGAke1JFVklFV19GSVhfQ09NTUVOVF9QUkVGSVh9M2A7CmZ1bmN0aW9uIGZpbmRSZXZpZXdGaXhDb21tZW50KGNvbW1lbnRzLCBib3RMb2dpbikgewogIGNvbnN0IGV4cGVjdGVkID0gYm90TG9naW4udHJpbSgpLnRvTG93ZXJDYXNlKCk7CiAgcmV0dXJuIGNvbW1lbnRzLmZpbmQoCiAgICAoY29tbWVudCkgPT4gY29tbWVudC51c2VyPy5sb2dpbi50cmltKCkudG9Mb3dlckNhc2UoKSA9PT0gZXhwZWN0ZWQgJiYgY29tbWVudC5ib2R5LnN0YXJ0c1dpdGgoUkVWSUVXX0ZJWF9DT01NRU5UX1BSRUZJWCkKICApOwp9CmZ1bmN0aW9uIHBhcnNlUmV2aWV3Rml4U3RhdGUoY29tbWVudCkgewogIGlmICghY29tbWVudCkgcmV0dXJuIGVtcHR5UmV2aWV3Rml4U3RhdGUoKTsKICBjb25zdCBtYXJrZXIgPSBjb21tZW50LmJvZHkuc3BsaXQoIlxuIiwgMSlbMF0gPz8gIiI7CiAgY29uc3QgdjNNYXRjaCA9IG1hcmtlci5tYXRjaCgKICAgIC9ePCEtLSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3M6cmV2aWV3LWZpeDp2MyByZXZpZXc9KFxkKykgaXRlcmF0aW9ucz0oXGQrKSBoZWFkPShbMC05YS1mXXs0MH18bm9uZSkgc3RhdHVzPShmaXhpbmd8Zml4ZWR8bm8tY2hhbmdlfG5lZWRzLWFwcHJvdmFsfGZhaWxlZCkgLS0+JC8KICApOwogIGlmICh2M01hdGNoKSB7CiAgICByZXR1cm4gewogICAgICByZXZpZXdDdXJzb3I6IE51bWJlcih2M01hdGNoWzFdKSwKICAgICAgaXRlcmF0aW9uczogTnVtYmVyKHYzTWF0Y2hbMl0pLAogICAgICBoZWFkU2hhOiB2M01hdGNoWzNdID09PSAibm9uZSIgPyAiIiA6IHYzTWF0Y2hbM10sCiAgICAgIHN0YXR1czogdjNNYXRjaFs0XQogICAgfTsKICB9CiAgY29uc3QgdjJNYXRjaCA9IG1hcmtlci5tYXRjaCgKICAgIC9ePCEtLSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3M6cmV2aWV3LWZpeDp2MiBjb252ZXJzYXRpb249KFxkKykgcmV2aWV3PShcZCspIGl0ZXJhdGlvbnM9KFxkKykgaGVhZD0oWzAtOWEtZl17NDB9fG5vbmUpIHN0YXR1cz0oZml4aW5nfGZpeGVkfG5vLWNoYW5nZXxuZWVkcy1hcHByb3ZhbHxmYWlsZWQpIC0tPiQvCiAgKTsKICBpZiAodjJNYXRjaCkgewogICAgcmV0dXJuIHsKICAgICAgLy8gdjIgc3RvcmVkIENvbnZlcnNhdGlvbiBhbmQgaW5saW5lIFJldmlldyBDb21tZW50IElEcywgbm90IFJldmlldyBJRHMuCiAgICAgIC8vIFN0YXJ0IHRoZSB2MyBSZXZpZXcgY3Vyc29yIGF0IHplcm8gc28gdGhlIGZpcnN0IGZvcm1hbCBjaGFuZ2UgcmVxdWVzdAogICAgICAvLyBhZnRlciB1cGdyYWRpbmcgaXMgbmV2ZXIgc2tpcHBlZCBiZWNhdXNlIHRoZSBJRCBuYW1lc3BhY2VzIGRpZmZlci4KICAgICAgcmV2aWV3Q3Vyc29yOiAwLAogICAgICBpdGVyYXRpb25zOiBOdW1iZXIodjJNYXRjaFszXSksCiAgICAgIGhlYWRTaGE6IHYyTWF0Y2hbNF0gPT09ICJub25lIiA/ICIiIDogdjJNYXRjaFs0XSwKICAgICAgc3RhdHVzOiB2Mk1hdGNoWzVdCiAgICB9OwogIH0KICBjb25zdCB2MU1hdGNoID0gbWFya2VyLm1hdGNoKAogICAgL148IS0tIGVuZ2luZWVyaW5nLWFnZW50LXdvcmtmbG93czpyZXZpZXctZml4OnYxIGN1cnNvcj0oXGQrKSBpdGVyYXRpb25zPShcZCspIGhlYWQ9KFswLTlhLWZdezQwfXxub25lKSBzdGF0dXM9KGZpeGluZ3xmaXhlZHxuby1jaGFuZ2V8bmVlZHMtYXBwcm92YWx8ZmFpbGVkKSAtLT4kLwogICk7CiAgaWYgKCF2MU1hdGNoKSByZXR1cm4gZW1wdHlSZXZpZXdGaXhTdGF0ZSgpOwogIHJldHVybiB7CiAgICByZXZpZXdDdXJzb3I6IDAsCiAgICBpdGVyYXRpb25zOiBOdW1iZXIodjFNYXRjaFsyXSksCiAgICBoZWFkU2hhOiB2MU1hdGNoWzNdID09PSAibm9uZSIgPyAiIiA6IHYxTWF0Y2hbM10sCiAgICBzdGF0dXM6IHYxTWF0Y2hbNF0KICB9Owp9CmZ1bmN0aW9uIGJ1aWxkUmV2aWV3Rml4Q29tbWVudChzdGF0ZSkgewogIGNvbnN0IG1hcmtlciA9IGAke1JFVklFV19GSVhfQ09NTUVOVF9WM19QUkVGSVh9IHJldmlldz0ke3N0YXRlLnJldmlld0N1cnNvcn0gaXRlcmF0aW9ucz0ke3N0YXRlLml0ZXJhdGlvbnN9IGhlYWQ9JHtzdGF0ZS5oZWFkU2hhIHx8ICJub25lIn0gc3RhdHVzPSR7c3RhdGUuc3RhdHVzfSAtLT5gOwogIGNvbnN0IG1lc3NhZ2VzID0gewogICAgZml4aW5nOiAiVGhlIERyYWZ0IFBSIEFnZW50IGlzIHZhbGlkYXRpbmcgYSByZXF1ZXN0ZWQgY2hhbmdlLiIsCiAgICBmaXhlZDogIlRoZSBEcmFmdCBQUiBBZ2VudCBwdXNoZWQgYSB2YWxpZGF0ZWQgZml4IGZvciB0aGUgbGF0ZXN0IHJlcXVlc3RlZCBjaGFuZ2VzLiIsCiAgICAibm8tY2hhbmdlIjogIlRoZSBEcmFmdCBQUiBBZ2VudCB2ZXJpZmllZCB0aGUgbGF0ZXN0IHJlcXVlc3RlZCBjaGFuZ2VzIGFuZCBtYWRlIG5vIGNvZGUgY2hhbmdlLiIsCiAgICAibmVlZHMtYXBwcm92YWwiOiAiQXV0b21hdGljIFJldmlldyBmaXhlcyBwYXVzZWQgZm9yIG1haW50YWluZXIgYXBwcm92YWwuIiwKICAgIGZhaWxlZDogIlRoZSBEcmFmdCBQUiBBZ2VudCBjb3VsZCBub3QgY29tcGxldGUgdGhlIGxhdGVzdCBSZXZpZXcgZml4IGF0dGVtcHQuIgogIH07CiAgcmV0dXJuIFttYXJrZXIsICIjIyBSZXZpZXcgZm9sbG93LXVwIiwgIiIsIG1lc3NhZ2VzW3N0YXRlLnN0YXR1c11dLmpvaW4oIlxuIik7Cn0KZnVuY3Rpb24gZW1wdHlSZXZpZXdGaXhTdGF0ZSgpIHsKICByZXR1cm4gewogICAgcmV2aWV3Q3Vyc29yOiAwLAogICAgaXRlcmF0aW9uczogMCwKICAgIGhlYWRTaGE6ICIiLAogICAgc3RhdHVzOiAiZml4ZWQiCiAgfTsKfQoKLy8gc3JjL2RyYWZ0LXByL3Jldmlldy1zY2hlbWEudHMKdmFyIHJldmlld0ZpbmRpbmdTb3VyY2VTY2hlbWEgPSBfZW51bShbInJldmlldyIsICJyZXZpZXdfY29tbWVudCJdKTsKdmFyIHJldmlld0ZpbmRpbmdSZWZlcmVuY2VTY2hlbWEgPSBvYmplY3QoewogIHNvdXJjZTogcmV2aWV3RmluZGluZ1NvdXJjZVNjaGVtYSwKICBjb21tZW50SWQ6IG51bWJlcjIoKS5pbnQoKS5wb3NpdGl2ZSgpCn0pOwp2YXIgcmV2aWV3VGVzdFNjaGVtYSA9IG9iamVjdCh7CiAgY29tbWFuZDogc3RyaW5nMigpLm1pbigxKS5tYXgoMzAwKSwKICBzdGF0dXM6IF9lbnVtKFsicGFzc2VkIiwgImZhaWxlZCIsICJub3RfcnVuIl0pLAogIGRldGFpbHM6IHN0cmluZzIoKS5tYXgoMWUzKQp9KTsKdmFyIHJldmlld0ZpeEFuYWx5c2lzU2NoZW1hID0gb2JqZWN0KHsKICBvdXRjb21lOiBfZW51bShbImZpeGVkIiwgIm5vX2NoYW5nZSIsICJuZWVkc19hcHByb3ZhbCIsICJibG9ja2VkIl0pLAogIGNvbW1pdFRpdGxlOiBzdHJpbmcyKCkubWF4KDEyMCksCiAgc3VtbWFyeTogYXJyYXkoc3RyaW5nMigpLm1pbigxKS5tYXgoNTAwKSkubWF4KDgpLAogIGZpbmRpbmdzOiBhcnJheSgKICAgIG9iamVjdCh7CiAgICAgIHNvdXJjZTogcmV2aWV3RmluZGluZ1NvdXJjZVNjaGVtYSwKICAgICAgY29tbWVudElkOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKSwKICAgICAgZGlzcG9zaXRpb246IF9lbnVtKFsiZml4ZWQiLCAibm90X3JlcHJvZHVjaWJsZSIsICJuZWVkc19hcHByb3ZhbCJdKSwKICAgICAgcmVhc29uOiBzdHJpbmcyKCkubWluKDEpLm1heCgxZTMpCiAgICB9KQogICkubWF4KDEwMCksCiAgdGVzdHM6IGFycmF5KHJldmlld1Rlc3RTY2hlbWEpLm1heCgyMCksCiAgcmlzazogb2JqZWN0KHsKICAgIGxldmVsOiBfZW51bShbImxvdyIsICJtZWRpdW0iLCAiaGlnaCJdKSwKICAgIHJlYXNvbnM6IGFycmF5KHN0cmluZzIoKS5taW4oMSkubWF4KDUwMCkpLm1heCg4KQogIH0pLAogIG5vdGVzOiBhcnJheShzdHJpbmcyKCkubWluKDEpLm1heCg1MDApKS5tYXgoOCksCiAgdmFsaWRhdGlvbk92ZXJyaWRlOiB2YWxpZGF0aW9uT3ZlcnJpZGVTY2hlbWEub3B0aW9uYWwoKQp9KTsKdmFyIHJldmlld0ZpeFN1Ym1pc3Npb25TY2hlbWEgPSBvYmplY3QoewogIHJldmlld0lkOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKSwKICByZXZpZXdGaW5nZXJwcmludDogc3RyaW5nMigpLnJlZ2V4KC9eWzAtOWEtZl17MjB9JC8pLAogIGZpbmRpbmdSZWZzOiBhcnJheShyZXZpZXdGaW5kaW5nUmVmZXJlbmNlU2NoZW1hKS5taW4oMSkubWF4KDEwMCksCiAgd29ya3NwYWNlUGF0aDogc3RyaW5nMigpLm1pbigxKS5tYXgoMmUzKSwKICBicmFuY2g6IHN0cmluZzIoKS5taW4oMSkubWF4KDI1MCksCiAgYmFzZUJyYW5jaDogc3RyaW5nMigpLm1pbigxKS5tYXgoMjUwKSwKICBleHBlY3RlZEhlYWRTaGE6IHN0cmluZzIoKS5yZWdleCgvXlswLTlhLWZdezQwfSQvKSwKICBwcmV2aW91c1Jldmlld0N1cnNvcjogbnVtYmVyMigpLmludCgpLm5vbm5lZ2F0aXZlKCksCiAgcHJldmlvdXNJdGVyYXRpb25zOiBudW1iZXIyKCkuaW50KCkubm9ubmVnYXRpdmUoKSwKICBhbmFseXNpczogcmV2aWV3Rml4QW5hbHlzaXNTY2hlbWEKfSk7CgovLyBzcmMvZHJhZnQtcHIvcmV2aWV3LXRvb2wudHMKYXN5bmMgZnVuY3Rpb24gcHJlcGFyZVJldmlld0ZpeChyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgcmV2aWV3SWQsIGRlcGVuZGVuY2llcykgewogIGFzc2VydEFsbG93ZWRSZXBvc2l0b3J5KHJlcG9zaXRvcnksIGRlcGVuZGVuY2llcy5hbGxvd2VkUmVwb3NpdG9yeSk7CiAgcmVxdWlyZVJldmlld0JvdElkZW50aXR5KGRlcGVuZGVuY2llcyk7CiAgY29uc3QgW3B1bGxSZXF1ZXN0LCByZXZpZXcsIGNvbnZlcnNhdGlvbkNvbW1lbnRzLCByZXZpZXdDb21tZW50c10gPSBhd2FpdCBQcm9taXNlLmFsbChbCiAgICBkZXBlbmRlbmNpZXMucHJvdmlkZXIuZ2V0UHVsbFJlcXVlc3QocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpLAogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmdldFB1bGxSZXF1ZXN0UmV2aWV3KAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgcmV2aWV3SWQKICAgICksCiAgICBkZXBlbmRlbmNpZXMucHJvdmlkZXIubGlzdENvbW1lbnRzKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyKSwKICAgIGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0UmV2aWV3Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpCiAgXSk7CiAgY29uc3QgcmVhc29uID0gaW5lbGlnaWJsZVJlYXNvbjIocHVsbFJlcXVlc3QsIHJlcG9zaXRvcnksIGRlcGVuZGVuY2llcyk7CiAgaWYgKHJlYXNvbikgcmV0dXJuIHNraXBwZWQyKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCByZWFzb24pOwogIGNvbnN0IHJldmlld1JlYXNvbiA9IGluZWxpZ2libGVSZXZpZXdSZWFzb24ocmV2aWV3LCBwdWxsUmVxdWVzdCk7CiAgaWYgKHJldmlld1JlYXNvbikgcmV0dXJuIHNraXBwZWQyKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCByZXZpZXdSZWFzb24pOwogIGNvbnN0IHN0YXRlID0gcmV2aWV3U3RhdGUoY29udmVyc2F0aW9uQ29tbWVudHMsIGRlcGVuZGVuY2llcyk7CiAgaWYgKHJldmlldy5pZCA8PSBzdGF0ZS5yZXZpZXdDdXJzb3IpIHsKICAgIHJldHVybiBza2lwcGVkMigKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgICJQdWxsIFJlcXVlc3QgUmV2aWV3IHdhcyBhbHJlYWR5IHByb2Nlc3NlZCIKICAgICk7CiAgfQogIGNvbnN0IGZpbmRpbmdzID0gZmluZGluZ3NGb3JSZXZpZXcocmV2aWV3LCByZXZpZXdDb21tZW50cyk7CiAgaWYgKGZpbmRpbmdzLmxlbmd0aCA9PT0gMCkgewogICAgcmV0dXJuIHNraXBwZWQyKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCAiUmV2aWV3IGhhcyBubyBmaW5kaW5ncyIpOwogIH0KICBpZiAoZmluZGluZ3MubGVuZ3RoID4gZGVwZW5kZW5jaWVzLnBvbGljeS5tYXhSZXZpZXdDb21tZW50cykgewogICAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgICBhd2FpdCB1cHNlcnRSZXZpZXdTdGF0ZSgKICAgICAgICByZXBvc2l0b3J5LAogICAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICAgIHsKICAgICAgICAgIHJldmlld0N1cnNvcjogc3RhdGUucmV2aWV3Q3Vyc29yLAogICAgICAgICAgaXRlcmF0aW9uczogc3RhdGUuaXRlcmF0aW9ucywKICAgICAgICAgIGhlYWRTaGE6IHB1bGxSZXF1ZXN0LmhlYWRTaGEsCiAgICAgICAgICBzdGF0dXM6ICJuZWVkcy1hcHByb3ZhbCIKICAgICAgICB9LAogICAgICAgIGNvbnZlcnNhdGlvbkNvbW1lbnRzLAogICAgICAgIGRlcGVuZGVuY2llcwogICAgICApOwogICAgfQogICAgcmV0dXJuIHNraXBwZWQyKAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgYFJldmlldyBoYXMgJHtmaW5kaW5ncy5sZW5ndGh9IGZpbmRpbmdzLCBleGNlZWRpbmcgdGhlIGF1dG9tYXRpYyBsaW1pdCBvZiAke2RlcGVuZGVuY2llcy5wb2xpY3kubWF4UmV2aWV3Q29tbWVudHN9YAogICAgKTsKICB9CiAgaWYgKHN0YXRlLml0ZXJhdGlvbnMgPj0gZGVwZW5kZW5jaWVzLnBvbGljeS5tYXhGaXhJdGVyYXRpb25zKSB7CiAgICBpZiAoZGVwZW5kZW5jaWVzLmFwcGx5KSB7CiAgICAgIGF3YWl0IHVwc2VydFJldmlld1N0YXRlKAogICAgICAgIHJlcG9zaXRvcnksCiAgICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgICAgewogICAgICAgICAgcmV2aWV3Q3Vyc29yOiBzdGF0ZS5yZXZpZXdDdXJzb3IsCiAgICAgICAgICBpdGVyYXRpb25zOiBzdGF0ZS5pdGVyYXRpb25zLAogICAgICAgICAgaGVhZFNoYTogcHVsbFJlcXVlc3QuaGVhZFNoYSwKICAgICAgICAgIHN0YXR1czogIm5lZWRzLWFwcHJvdmFsIgogICAgICAgIH0sCiAgICAgICAgY29udmVyc2F0aW9uQ29tbWVudHMsCiAgICAgICAgZGVwZW5kZW5jaWVzCiAgICAgICk7CiAgICB9CiAgICByZXR1cm4gc2tpcHBlZDIoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICAiYXV0b21hdGljIFJldmlldyBmaXggaXRlcmF0aW9uIGxpbWl0IHJlYWNoZWQiCiAgICApOwogIH0KICBsZXQgcHJlcGFyZWQ7CiAgdHJ5IHsKICAgIHByZXBhcmVkID0gYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5wcmVwYXJlUmV2aWV3KHsKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGNsb25lVXJsOiByZXBvc2l0b3J5Q2xvbmVVcmwoZGVwZW5kZW5jaWVzLnNlcnZlclVybCwgcmVwb3NpdG9yeSksCiAgICAgIGJhc2VCcmFuY2g6IHB1bGxSZXF1ZXN0LmJhc2UsCiAgICAgIGJyYW5jaDogcHVsbFJlcXVlc3QuaGVhZCwKICAgICAgZXhwZWN0ZWRIZWFkU2hhOiBwdWxsUmVxdWVzdC5oZWFkU2hhCiAgICB9KTsKICB9IGNhdGNoIChlcnJvcikgewogICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRHJhZnRQcldvcmtzcGFjZUxvY2tFcnJvcikgewogICAgICByZXR1cm4gc2tpcHBlZDIoCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgICAiYW5vdGhlciByZXZpZXcgZml4IHJ1biBob2xkcyB0aGUgUHVsbCBSZXF1ZXN0IGxvY2siCiAgICAgICk7CiAgICB9CiAgICB0aHJvdyBlcnJvcjsKICB9CiAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgYXdhaXQgdXBzZXJ0UmV2aWV3U3RhdGUoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICB7CiAgICAgICAgcmV2aWV3Q3Vyc29yOiBzdGF0ZS5yZXZpZXdDdXJzb3IsCiAgICAgICAgaXRlcmF0aW9uczogc3RhdGUuaXRlcmF0aW9ucywKICAgICAgICBoZWFkU2hhOiBwdWxsUmVxdWVzdC5oZWFkU2hhLAogICAgICAgIHN0YXR1czogImZpeGluZyIKICAgICAgfSwKICAgICAgY29udmVyc2F0aW9uQ29tbWVudHMsCiAgICAgIGRlcGVuZGVuY2llcwogICAgKTsKICB9CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgcmVwb3NpdG9yeSwKICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgd29ya3NwYWNlUGF0aDogcHJlcGFyZWQucGF0aCwKICAgIGJyYW5jaDogcHJlcGFyZWQuYnJhbmNoLAogICAgYmFzZUJyYW5jaDogcHJlcGFyZWQuYmFzZUJyYW5jaCwKICAgIGV4cGVjdGVkSGVhZFNoYTogcHJlcGFyZWQuYmFzZUNvbW1pdCwKICAgIHJldmlld0lkOiByZXZpZXcuaWQsCiAgICByZXZpZXdGaW5nZXJwcmludDogZmluZ2VycHJpbnRGaW5kaW5ncyhmaW5kaW5ncyksCiAgICBwcmV2aW91c1Jldmlld0N1cnNvcjogc3RhdGUucmV2aWV3Q3Vyc29yLAogICAgcHJldmlvdXNJdGVyYXRpb25zOiBzdGF0ZS5pdGVyYXRpb25zLAogICAgZmluZGluZ3M6IGZpbmRpbmdzLm1hcCgodmFsdWUpID0+IHRvRmluZGluZyh2YWx1ZSkpCiAgfTsKfQphc3luYyBmdW5jdGlvbiBhcHBseVJldmlld0ZpeChyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgc3VibWlzc2lvbklucHV0LCBkZXBlbmRlbmNpZXMpIHsKICBhc3NlcnRBbGxvd2VkUmVwb3NpdG9yeShyZXBvc2l0b3J5LCBkZXBlbmRlbmNpZXMuYWxsb3dlZFJlcG9zaXRvcnkpOwogIHJlcXVpcmVSZXZpZXdCb3RJZGVudGl0eShkZXBlbmRlbmNpZXMpOwogIGNvbnN0IHN1Ym1pc3Npb24gPSByZXZpZXdGaXhTdWJtaXNzaW9uU2NoZW1hLnBhcnNlKHN1Ym1pc3Npb25JbnB1dCk7CiAgY29uc3QgW3B1bGxSZXF1ZXN0LCByZXZpZXcsIGNvbnZlcnNhdGlvbkNvbW1lbnRzLCByZXZpZXdDb21tZW50c10gPSBhd2FpdCBQcm9taXNlLmFsbChbCiAgICBkZXBlbmRlbmNpZXMucHJvdmlkZXIuZ2V0UHVsbFJlcXVlc3QocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpLAogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmdldFB1bGxSZXF1ZXN0UmV2aWV3KAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgc3VibWlzc2lvbi5yZXZpZXdJZAogICAgKSwKICAgIGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpLAogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmxpc3RSZXZpZXdDb21tZW50cyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlcikKICBdKTsKICBjb25zdCByZWFzb24gPSBpbmVsaWdpYmxlUmVhc29uMihwdWxsUmVxdWVzdCwgcmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzKTsKICBpZiAocmVhc29uKSB0aHJvdyBuZXcgRXJyb3IocmVhc29uKTsKICBjb25zdCByZXZpZXdSZWFzb24gPSBpbmVsaWdpYmxlUmV2aWV3UmVhc29uKHJldmlldywgcHVsbFJlcXVlc3QpOwogIGlmIChyZXZpZXdSZWFzb24pIHRocm93IG5ldyBFcnJvcihyZXZpZXdSZWFzb24pOwogIGlmIChwdWxsUmVxdWVzdC5oZWFkU2hhICE9PSBzdWJtaXNzaW9uLmV4cGVjdGVkSGVhZFNoYSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJQdWxsIFJlcXVlc3QgaGVhZCBjaGFuZ2VkIGFmdGVyIHJldmlldyBmaXggcHJlcGFyYXRpb24iKTsKICB9CiAgY29uc3QgZXhwZWN0ZWRLZXlzID0gc3VibWlzc2lvbi5maW5kaW5nUmVmcy5tYXAoZmluZGluZ0tleSk7CiAgY29uc3QgcHJlcGFyZWRGaW5kaW5ncyA9IGZpbmRpbmdzRm9yUmV2aWV3KHJldmlldywgcmV2aWV3Q29tbWVudHMpOwogIGlmIChuZXcgU2V0KGV4cGVjdGVkS2V5cykuc2l6ZSAhPT0gZXhwZWN0ZWRLZXlzLmxlbmd0aCB8fCBwcmVwYXJlZEZpbmRpbmdzLmxlbmd0aCAhPT0gc3VibWlzc2lvbi5maW5kaW5nUmVmcy5sZW5ndGggfHwgcHJlcGFyZWRGaW5kaW5ncy5zb21lKAogICAgKHZhbHVlKSA9PiAhZXhwZWN0ZWRLZXlzLmluY2x1ZGVzKGZpbmRpbmdLZXkodmFsdWUpKQogICkgfHwgZmluZ2VycHJpbnRGaW5kaW5ncyhwcmVwYXJlZEZpbmRpbmdzKSAhPT0gc3VibWlzc2lvbi5yZXZpZXdGaW5nZXJwcmludCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJQdWxsIFJlcXVlc3QgUmV2aWV3IGNoYW5nZWQgYWZ0ZXIgZml4IHByZXBhcmF0aW9uIik7CiAgfQogIGNvbnN0IGluc3BlY3Rpb24gPSBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmluc3BlY3QoCiAgICBzdWJtaXNzaW9uLndvcmtzcGFjZVBhdGgKICApOwogIGlmIChpbnNwZWN0aW9uLmhlYWRDb21taXQgIT09IHN1Ym1pc3Npb24uZXhwZWN0ZWRIZWFkU2hhKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJ0aGUgQWdlbnQgY29tbWl0dGVkIG9yIG1vdmVkIEhFQUQgaW4gdGhlIHJldmlldyB3b3Jrc3BhY2UiCiAgICApOwogIH0KICB2YWxpZGF0ZUZpbmRpbmdDb3ZlcmFnZShzdWJtaXNzaW9uLmFuYWx5c2lzLCBzdWJtaXNzaW9uLmZpbmRpbmdSZWZzKTsKICBjb25zdCBuZXh0SXRlcmF0aW9ucyA9IHN1Ym1pc3Npb24ucHJldmlvdXNJdGVyYXRpb25zICsgMTsKICBjb25zdCBuZXh0UmV2aWV3Q3Vyc29yID0gTWF0aC5tYXgoCiAgICBzdWJtaXNzaW9uLnByZXZpb3VzUmV2aWV3Q3Vyc29yLAogICAgc3VibWlzc2lvbi5yZXZpZXdJZAogICk7CiAgaWYgKHN1Ym1pc3Npb24uYW5hbHlzaXMub3V0Y29tZSAhPT0gImZpeGVkIikgewogICAgaWYgKHN1Ym1pc3Npb24uYW5hbHlzaXMub3V0Y29tZSA9PT0gIm5vX2NoYW5nZSIgJiYgaW5zcGVjdGlvbi5jaGFuZ2VkRmlsZXMubGVuZ3RoID4gMCkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoIm5vX2NoYW5nZSByZXZpZXcgcmVzdWx0IGNvbnRhaW5zIHJlcG9zaXRvcnkgY2hhbmdlcyIpOwogICAgfQogICAgY29uc3Qgc3RhdHVzID0gc3VibWlzc2lvbi5hbmFseXNpcy5vdXRjb21lID09PSAibmVlZHNfYXBwcm92YWwiID8gIm5lZWRzLWFwcHJvdmFsIiA6IHN1Ym1pc3Npb24uYW5hbHlzaXMub3V0Y29tZSA9PT0gIm5vX2NoYW5nZSIgPyAibm8tY2hhbmdlIiA6ICJmYWlsZWQiOwogICAgYXdhaXQgZmluaXNoV2l0aG91dFB1c2gyKAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgbmV4dFJldmlld0N1cnNvciwKICAgICAgbmV4dEl0ZXJhdGlvbnMsCiAgICAgIHN1Ym1pc3Npb24uZXhwZWN0ZWRIZWFkU2hhLAogICAgICBzdGF0dXMsCiAgICAgIGNvbnZlcnNhdGlvbkNvbW1lbnRzLAogICAgICBkZXBlbmRlbmNpZXMKICAgICk7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGRlcGVuZGVuY2llcy5hcHBseSwKICAgICAgb3V0Y29tZTogc3VibWlzc2lvbi5hbmFseXNpcy5vdXRjb21lLAogICAgICBpbnNwZWN0aW9uCiAgICB9OwogIH0KICB2YWxpZGF0ZUZpeGVkUmV2aWV3KHN1Ym1pc3Npb24uYW5hbHlzaXMsIGluc3BlY3Rpb24pOwogIGNvbnN0IGFwcHJvdmFsUmVhc29ucyA9IHJlcXVpcmVzQXBwcm92YWwoCiAgICBzdWJtaXNzaW9uLmFuYWx5c2lzLAogICAgaW5zcGVjdGlvbiwKICAgIGZhbHNlLAogICAgZGVwZW5kZW5jaWVzLnBvbGljeQogICk7CiAgaWYgKGFwcHJvdmFsUmVhc29ucy5sZW5ndGggPiAwKSB7CiAgICBhd2FpdCBmaW5pc2hXaXRob3V0UHVzaDIoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICBuZXh0UmV2aWV3Q3Vyc29yLAogICAgICBuZXh0SXRlcmF0aW9ucywKICAgICAgc3VibWlzc2lvbi5leHBlY3RlZEhlYWRTaGEsCiAgICAgICJuZWVkcy1hcHByb3ZhbCIsCiAgICAgIGNvbnZlcnNhdGlvbkNvbW1lbnRzLAogICAgICBkZXBlbmRlbmNpZXMKICAgICk7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGRlcGVuZGVuY2llcy5hcHBseSwKICAgICAgb3V0Y29tZTogIm5lZWRzX2FwcHJvdmFsIiwKICAgICAgaW5zcGVjdGlvbgogICAgfTsKICB9CiAgaWYgKCFkZXBlbmRlbmNpZXMuYXBwbHkpIHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlcik7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGZhbHNlLAogICAgICBvdXRjb21lOiAiZml4ZWQiLAogICAgICBpbnNwZWN0aW9uCiAgICB9OwogIH0KICBjb25zdCBjb21taXRUaXRsZSA9IHNhbml0aXplVGl0bGUoc3VibWlzc2lvbi5hbmFseXNpcy5jb21taXRUaXRsZSk7CiAgY29uc3QgY29tbWl0ID0gYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5jb21taXRBbmRQdXNoKAogICAgc3VibWlzc2lvbi53b3Jrc3BhY2VQYXRoLAogICAgc3VibWlzc2lvbi5icmFuY2gsCiAgICBjb21taXRUaXRsZSwKICAgIHJlcG9zaXRvcnlDbG9uZVVybChkZXBlbmRlbmNpZXMuc2VydmVyVXJsLCByZXBvc2l0b3J5KQogICk7CiAgYXdhaXQgdXBzZXJ0UmV2aWV3U3RhdGUoCiAgICByZXBvc2l0b3J5LAogICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICB7CiAgICAgIHJldmlld0N1cnNvcjogbmV4dFJldmlld0N1cnNvciwKICAgICAgaXRlcmF0aW9uczogbmV4dEl0ZXJhdGlvbnMsCiAgICAgIGhlYWRTaGE6IGNvbW1pdCwKICAgICAgc3RhdHVzOiAiZml4ZWQiCiAgICB9LAogICAgY29udmVyc2F0aW9uQ29tbWVudHMsCiAgICBkZXBlbmRlbmNpZXMKICApOwogIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlcik7CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgcmVwb3NpdG9yeSwKICAgIHB1bGxSZXF1ZXN0TnVtYmVyLAogICAgYXBwbGllZDogdHJ1ZSwKICAgIG91dGNvbWU6ICJmaXhlZCIsCiAgICBjb21taXQsCiAgICBpbnNwZWN0aW9uCiAgfTsKfQphc3luYyBmdW5jdGlvbiBmYWlsUmV2aWV3Rml4KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCByZXZpZXdDdXJzb3IsIGl0ZXJhdGlvbnMsIGhlYWRTaGEsIGRlcGVuZGVuY2llcykgewogIGFzc2VydEFsbG93ZWRSZXBvc2l0b3J5KHJlcG9zaXRvcnksIGRlcGVuZGVuY2llcy5hbGxvd2VkUmVwb3NpdG9yeSk7CiAgdHJ5IHsKICAgIGlmIChkZXBlbmRlbmNpZXMuYXBwbHkpIHsKICAgICAgY29uc3QgY29tbWVudHMgPSBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIubGlzdENvbW1lbnRzKAogICAgICAgIHJlcG9zaXRvcnksCiAgICAgICAgcHVsbFJlcXVlc3ROdW1iZXIKICAgICAgKTsKICAgICAgYXdhaXQgdXBzZXJ0UmV2aWV3U3RhdGUoCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgICB7CiAgICAgICAgICByZXZpZXdDdXJzb3IsCiAgICAgICAgICBpdGVyYXRpb25zLAogICAgICAgICAgaGVhZFNoYSwKICAgICAgICAgIHN0YXR1czogImZhaWxlZCIKICAgICAgICB9LAogICAgICAgIGNvbW1lbnRzLAogICAgICAgIGRlcGVuZGVuY2llcwogICAgICApOwogICAgfQogIH0gZmluYWxseSB7CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmNsZWFudXBSZXZpZXcocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpOwogIH0KICByZXR1cm4gewogICAgb2s6IHRydWUsCiAgICByZXBvc2l0b3J5LAogICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICBhcHBsaWVkOiBkZXBlbmRlbmNpZXMuYXBwbHksCiAgICBvdXRjb21lOiAiZmFpbGVkIgogIH07Cn0KZnVuY3Rpb24gZmluZGluZ3NGb3JSZXZpZXcocmV2aWV3LCByZXZpZXdDb21tZW50cykgewogIGNvbnN0IGZpbmRpbmdzID0gW107CiAgaWYgKHJldmlldy5ib2R5LnRyaW0oKSkgewogICAgZmluZGluZ3MucHVzaCh7CiAgICAgIHNvdXJjZTogInJldmlldyIsCiAgICAgIGlkOiByZXZpZXcuaWQsCiAgICAgIGJvZHk6IHJldmlldy5ib2R5LAogICAgICAuLi5yZXZpZXcuaHRtbFVybCA/IHsgaHRtbFVybDogcmV2aWV3Lmh0bWxVcmwgfSA6IHt9LAogICAgICAuLi5yZXZpZXcuc3VibWl0dGVkQXQgPyB7IGNyZWF0ZWRBdDogcmV2aWV3LnN1Ym1pdHRlZEF0IH0gOiB7fSwKICAgICAgcmV2aWV3CiAgICB9KTsKICB9CiAgZmluZGluZ3MucHVzaCgKICAgIC4uLnJldmlld0NvbW1lbnRzLmZpbHRlcigKICAgICAgKGNvbW1lbnQpID0+IGNvbW1lbnQucHVsbFJlcXVlc3RSZXZpZXdJZCA9PT0gcmV2aWV3LmlkICYmICFjb21tZW50LmluUmVwbHlUb0lkICYmIHNhbWVVc2VyKGNvbW1lbnQudXNlciwgcmV2aWV3LnVzZXIpCiAgICApLm1hcCgoY29tbWVudCkgPT4gKHsKICAgICAgc291cmNlOiAicmV2aWV3X2NvbW1lbnQiLAogICAgICBpZDogY29tbWVudC5pZCwKICAgICAgYm9keTogY29tbWVudC5ib2R5LAogICAgICAuLi5jb21tZW50Lmh0bWxVcmwgPyB7IGh0bWxVcmw6IGNvbW1lbnQuaHRtbFVybCB9IDoge30sCiAgICAgIC4uLmNvbW1lbnQuY3JlYXRlZEF0ID8geyBjcmVhdGVkQXQ6IGNvbW1lbnQuY3JlYXRlZEF0IH0gOiB7fSwKICAgICAgY29tbWVudAogICAgfSkpCiAgKTsKICByZXR1cm4gZmluZGluZ3Muc29ydChjb21wYXJlU291cmNlZEZpbmRpbmdzKTsKfQpmdW5jdGlvbiBpbmVsaWdpYmxlUmVhc29uMihwdWxsUmVxdWVzdCwgcmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzKSB7CiAgaWYgKHB1bGxSZXF1ZXN0LnN0YXRlLnRvTG93ZXJDYXNlKCkgIT09ICJvcGVuIikKICAgIHJldHVybiAiUHVsbCBSZXF1ZXN0IGlzIG5vdCBvcGVuIjsKICBpZiAoIXB1bGxSZXF1ZXN0LmRyYWZ0KSByZXR1cm4gIlB1bGwgUmVxdWVzdCBpcyBub3QgYSBEcmFmdCI7CiAgaWYgKCFwdWxsUmVxdWVzdC5oZWFkLnN0YXJ0c1dpdGgoZGVwZW5kZW5jaWVzLnBvbGljeS5icmFuY2hQcmVmaXgpKSB7CiAgICByZXR1cm4gIlB1bGwgUmVxdWVzdCBicmFuY2ggaXMgbm90IG1hbmFnZWQgYnkgdGhlIERyYWZ0IFBSIEFnZW50IjsKICB9CiAgaWYgKHB1bGxSZXF1ZXN0LmhlYWRSZXBvc2l0b3J5Py50cmltKCkudG9Mb3dlckNhc2UoKSAhPT0gcmVwb3NpdG9yeS50cmltKCkudG9Mb3dlckNhc2UoKSkgewogICAgcmV0dXJuICJQdWxsIFJlcXVlc3QgaGVhZCByZXBvc2l0b3J5IGlzIG5vdCB0aGUgYWxsb3dsaXN0ZWQgcmVwb3NpdG9yeSI7CiAgfQogIGlmICghcHVsbFJlcXVlc3QuaGVhZFNoYSB8fCAhL15bMC05YS1mXXs0MH0kLy50ZXN0KHB1bGxSZXF1ZXN0LmhlYWRTaGEpKSB7CiAgICByZXR1cm4gIlB1bGwgUmVxdWVzdCBoYXMgbm8gdmFsaWQgaGVhZCBTSEEiOwogIH0KICByZXR1cm4gdm9pZCAwOwp9CmZ1bmN0aW9uIGluZWxpZ2libGVSZXZpZXdSZWFzb24ocmV2aWV3LCBwdWxsUmVxdWVzdCkgewogIGlmIChyZXZpZXcuc3RhdGUudHJpbSgpLnRvTG93ZXJDYXNlKCkgIT09ICJjaGFuZ2VzX3JlcXVlc3RlZCIpIHsKICAgIHJldHVybiAiUHVsbCBSZXF1ZXN0IFJldmlldyBpcyBub3QgYSBjaGFuZ2UgcmVxdWVzdCI7CiAgfQogIGlmICghcmV2aWV3LnVzZXI/LmxvZ2luLnRyaW0oKSkgcmV0dXJuICJQdWxsIFJlcXVlc3QgUmV2aWV3IGhhcyBubyBhdXRob3IiOwogIGlmICghdHJ1c3RlZFJldmlld2VyQXNzb2NpYXRpb24ocmV2aWV3LmF1dGhvckFzc29jaWF0aW9uKSkgewogICAgcmV0dXJuICJQdWxsIFJlcXVlc3QgUmV2aWV3IGF1dGhvciBpcyBub3QgYSB0cnVzdGVkIHJlcG9zaXRvcnkgbWVtYmVyIjsKICB9CiAgaWYgKHJldmlldy5jb21taXRJZCAhPT0gcHVsbFJlcXVlc3QuaGVhZFNoYSkgewogICAgcmV0dXJuICJQdWxsIFJlcXVlc3QgUmV2aWV3IHRhcmdldHMgYSBzdGFsZSBoZWFkIjsKICB9CiAgcmV0dXJuIHZvaWQgMDsKfQpmdW5jdGlvbiB0cnVzdGVkUmV2aWV3ZXJBc3NvY2lhdGlvbih2YWx1ZSkgewogIHJldHVybiBbIm93bmVyIiwgIm1lbWJlciIsICJjb2xsYWJvcmF0b3IiXS5pbmNsdWRlcygKICAgIHZhbHVlLnRyaW0oKS50b0xvd2VyQ2FzZSgpCiAgKTsKfQpmdW5jdGlvbiBzYW1lVXNlcihsZWZ0LCByaWdodCkgewogIGlmICghbGVmdCB8fCAhcmlnaHQpIHJldHVybiBmYWxzZTsKICBpZiAobGVmdC5pZCAhPT0gdm9pZCAwICYmIHJpZ2h0LmlkICE9PSB2b2lkIDApCiAgICByZXR1cm4gbGVmdC5pZCA9PT0gcmlnaHQuaWQ7CiAgcmV0dXJuIGxlZnQubG9naW4udHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09IHJpZ2h0LmxvZ2luLnRyaW0oKS50b0xvd2VyQ2FzZSgpOwp9CmZ1bmN0aW9uIHZhbGlkYXRlRmluZGluZ0NvdmVyYWdlKGFuYWx5c2lzLCBleHBlY3RlZEZpbmRpbmdzKSB7CiAgY29uc3QgYWN0dWFsID0gYW5hbHlzaXMuZmluZGluZ3MubWFwKGZpbmRpbmdLZXkpOwogIGNvbnN0IGV4cGVjdGVkID0gZXhwZWN0ZWRGaW5kaW5ncy5tYXAoZmluZGluZ0tleSk7CiAgaWYgKG5ldyBTZXQoYWN0dWFsKS5zaXplICE9PSBhY3R1YWwubGVuZ3RoIHx8IGFjdHVhbC5sZW5ndGggIT09IGV4cGVjdGVkLmxlbmd0aCB8fCBleHBlY3RlZC5zb21lKChrZXkpID0+ICFhY3R1YWwuaW5jbHVkZXMoa2V5KSkpIHsKICAgIHRocm93IG5ldyBFcnJvcigicmV2aWV3IHJlc3VsdCBtdXN0IGFkZHJlc3MgZXZlcnkgcHJlcGFyZWQgZmluZGluZyBvbmNlIik7CiAgfQogIGlmIChhbmFseXNpcy5vdXRjb21lID09PSAiZml4ZWQiICYmIGFuYWx5c2lzLmZpbmRpbmdzLnNvbWUoCiAgICAoZmluZGluZykgPT4gZmluZGluZy5kaXNwb3NpdGlvbiA9PT0gIm5lZWRzX2FwcHJvdmFsIgogICkpIHsKICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgImZpeGVkIHJldmlldyByZXN1bHQgY2Fubm90IGNvbnRhaW4gYXBwcm92YWwtZ2F0ZWQgZmluZGluZ3MiCiAgICApOwogIH0KICBpZiAoYW5hbHlzaXMub3V0Y29tZSA9PT0gIm5vX2NoYW5nZSIgJiYgYW5hbHlzaXMuZmluZGluZ3Muc29tZSgKICAgIChmaW5kaW5nKSA9PiBmaW5kaW5nLmRpc3Bvc2l0aW9uICE9PSAibm90X3JlcHJvZHVjaWJsZSIKICApKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJub19jaGFuZ2UgcmV2aWV3IHJlc3VsdCByZXF1aXJlcyBldmVyeSBmaW5kaW5nIHRvIGJlIG5vdCByZXByb2R1Y2libGUiCiAgICApOwogIH0KfQpmdW5jdGlvbiB2YWxpZGF0ZUZpeGVkUmV2aWV3KGFuYWx5c2lzLCBpbnNwZWN0aW9uKSB7CiAgaWYgKCFzYW5pdGl6ZVRpdGxlKGFuYWx5c2lzLmNvbW1pdFRpdGxlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXhlZCByZXZpZXcgcmVzdWx0IHJlcXVpcmVzIGEgY29tbWl0IHRpdGxlIik7CiAgfQogIGlmIChpbnNwZWN0aW9uLmNoYW5nZWRGaWxlcy5sZW5ndGggPT09IDApIHsKICAgIHRocm93IG5ldyBFcnJvcigiZml4ZWQgcmV2aWV3IHJlc3VsdCByZXF1aXJlcyBhIG5vbi1lbXB0eSBjaGFuZ2UiKTsKICB9CiAgaWYgKCFpbnNwZWN0aW9uLmRpZmZDaGVja1Bhc3NlZCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJnaXQgZGlmZiAtLWNoZWNrIHJlamVjdGVkIHRoZSByZXZpZXcgZml4Iik7CiAgfQogIGlmIChpbnNwZWN0aW9uLnNlY3JldEZpbmRpbmdQYXRocy5sZW5ndGggPiAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgIGBwb3NzaWJsZSBjcmVkZW50aWFsIG1hdGVyaWFsIGRldGVjdGVkIGluOiAke2luc3BlY3Rpb24uc2VjcmV0RmluZGluZ1BhdGhzLmpvaW4oIiwgIil9YAogICAgKTsKICB9CiAgaWYgKGFuYWx5c2lzLnZhbGlkYXRpb25PdmVycmlkZSAmJiAhaGFzQ29uc2lzdGVudFZhbGlkYXRpb25PdmVycmlkZShhbmFseXNpcykpIHsKICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgImZpeGVkIHJldmlldyByZXN1bHQgaGFzIGFuIGluY29uc2lzdGVudCB2YWxpZGF0aW9uIG92ZXJyaWRlIgogICAgKTsKICB9CiAgaWYgKGFuYWx5c2lzLnRlc3RzLnNvbWUoKHRlc3QpID0+IHRlc3Quc3RhdHVzID09PSAiZmFpbGVkIikgJiYgIWhhc0NvbnNpc3RlbnRWYWxpZGF0aW9uT3ZlcnJpZGUoYW5hbHlzaXMpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoImZpeGVkIHJldmlldyByZXN1bHQgcmVwb3J0cyBhIGZhaWxlZCB2YWxpZGF0aW9uIGNvbW1hbmQiKTsKICB9Cn0KYXN5bmMgZnVuY3Rpb24gZmluaXNoV2l0aG91dFB1c2gyKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCByZXZpZXdDdXJzb3IsIGl0ZXJhdGlvbnMsIGhlYWRTaGEsIHN0YXR1cywgY29tbWVudHMsIGRlcGVuZGVuY2llcykgewogIGlmIChkZXBlbmRlbmNpZXMuYXBwbHkpIHsKICAgIGF3YWl0IHVwc2VydFJldmlld1N0YXRlKAogICAgICByZXBvc2l0b3J5LAogICAgICBwdWxsUmVxdWVzdE51bWJlciwKICAgICAgeyByZXZpZXdDdXJzb3IsIGl0ZXJhdGlvbnMsIGhlYWRTaGEsIHN0YXR1cyB9LAogICAgICBjb21tZW50cywKICAgICAgZGVwZW5kZW5jaWVzCiAgICApOwogIH0KICBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmNsZWFudXBSZXZpZXcocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpOwp9CmFzeW5jIGZ1bmN0aW9uIHVwc2VydFJldmlld1N0YXRlKHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCBzdGF0ZSwgY29tbWVudHMsIGRlcGVuZGVuY2llcykgewogIGNvbnN0IGJvdExvZ2luID0gZGVwZW5kZW5jaWVzLmJvdExvZ2luPy50cmltKCk7CiAgaWYgKCFib3RMb2dpbikKICAgIHRocm93IG5ldyBFcnJvcigiRHJhZnQgUFIgYm90IGxvZ2luIGlzIHJlcXVpcmVkIGluIGFwcGx5IG1vZGUiKTsKICBjb25zdCBib2R5ID0gYnVpbGRSZXZpZXdGaXhDb21tZW50KHN0YXRlKTsKICBjb25zdCBleGlzdGluZyA9IGZpbmRSZXZpZXdGaXhDb21tZW50KGNvbW1lbnRzLCBib3RMb2dpbik7CiAgaWYgKGV4aXN0aW5nKSB7CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIudXBkYXRlQ29tbWVudCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGV4aXN0aW5nLmlkLAogICAgICBib2R5CiAgICApOwogIH0gZWxzZSB7CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIuY3JlYXRlQ29tbWVudCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgcHVsbFJlcXVlc3ROdW1iZXIsCiAgICAgIGJvZHkKICAgICk7CiAgfQp9CmZ1bmN0aW9uIHJldmlld1N0YXRlKGNvbW1lbnRzLCBkZXBlbmRlbmNpZXMpIHsKICBjb25zdCBib3RMb2dpbiA9IGRlcGVuZGVuY2llcy5ib3RMb2dpbj8udHJpbSgpOwogIGlmICghYm90TG9naW4pIHJldHVybiBwYXJzZVJldmlld0ZpeFN0YXRlKHZvaWQgMCk7CiAgcmV0dXJuIHBhcnNlUmV2aWV3Rml4U3RhdGUoZmluZFJldmlld0ZpeENvbW1lbnQoY29tbWVudHMsIGJvdExvZ2luKSk7Cn0KZnVuY3Rpb24gZmluZ2VycHJpbnRGaW5kaW5ncyhmaW5kaW5ncykgewogIHJldHVybiBjcnlwdG80LmNyZWF0ZUhhc2goInNoYTI1NiIpLnVwZGF0ZSgKICAgIEpTT04uc3RyaW5naWZ5KAogICAgICBmaW5kaW5ncy5tYXAoKHsgc291cmNlLCBpZCwgYm9keSwgcmV2aWV3LCBjb21tZW50IH0pID0+ICh7CiAgICAgICAgc291cmNlLAogICAgICAgIGlkLAogICAgICAgIGJvZHksCiAgICAgICAgYXV0aG9yOiAocmV2aWV3Py51c2VyID8/IGNvbW1lbnQ/LnVzZXIpPy5sb2dpbiA/PyAiIiwKICAgICAgICBhdXRob3JJZDogKHJldmlldz8udXNlciA/PyBjb21tZW50Py51c2VyKT8uaWQgPz8gbnVsbCwKICAgICAgICAuLi5yZXZpZXcgPyB7CiAgICAgICAgICBzdGF0ZTogcmV2aWV3LnN0YXRlLAogICAgICAgICAgY29tbWl0SWQ6IHJldmlldy5jb21taXRJZCwKICAgICAgICAgIGF1dGhvckFzc29jaWF0aW9uOiByZXZpZXcuYXV0aG9yQXNzb2NpYXRpb24KICAgICAgICB9IDoge30sCiAgICAgICAgLi4uY29tbWVudCA/IHsKICAgICAgICAgIHBhdGg6IGNvbW1lbnQucGF0aCwKICAgICAgICAgIGxpbmU6IGNvbW1lbnQubGluZSA/PyBudWxsLAogICAgICAgICAgb3JpZ2luYWxMaW5lOiBjb21tZW50Lm9yaWdpbmFsTGluZSA/PyBudWxsLAogICAgICAgICAgZGlmZkh1bms6IGNvbW1lbnQuZGlmZkh1bmsgPz8gIiIsCiAgICAgICAgICBjb21taXRJZDogY29tbWVudC5jb21taXRJZCA/PyAiIgogICAgICAgIH0gOiB7fQogICAgICB9KSkKICAgICkKICApLmRpZ2VzdCgiaGV4Iikuc2xpY2UoMCwgMjApOwp9CmZ1bmN0aW9uIHRvRmluZGluZyh7CiAgc291cmNlLAogIGlkLAogIGJvZHksCiAgaHRtbFVybCwKICBjcmVhdGVkQXQsCiAgY29tbWVudAp9KSB7CiAgcmV0dXJuIHsKICAgIHNvdXJjZSwKICAgIGNvbW1lbnRJZDogaWQsCiAgICBib2R5OiB0cnVuY2F0ZVRleHQoYm9keSwgNGUzKSwKICAgIC4uLmh0bWxVcmwgPyB7IGh0bWxVcmwgfSA6IHt9LAogICAgLi4uY3JlYXRlZEF0ID8geyBjcmVhdGVkQXQgfSA6IHt9LAogICAgLi4uY29tbWVudD8ucGF0aCA/IHsgcGF0aDogY29tbWVudC5wYXRoIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/LmxpbmUgIT09IHZvaWQgMCA/IHsgbGluZTogY29tbWVudC5saW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/Lm9yaWdpbmFsTGluZSAhPT0gdm9pZCAwID8geyBvcmlnaW5hbExpbmU6IGNvbW1lbnQub3JpZ2luYWxMaW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/LnN0YXJ0TGluZSAhPT0gdm9pZCAwID8geyBzdGFydExpbmU6IGNvbW1lbnQuc3RhcnRMaW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/Lm9yaWdpbmFsU3RhcnRMaW5lICE9PSB2b2lkIDAgPyB7IG9yaWdpbmFsU3RhcnRMaW5lOiBjb21tZW50Lm9yaWdpbmFsU3RhcnRMaW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/LnNpZGUgPyB7IHNpZGU6IGNvbW1lbnQuc2lkZSB9IDoge30sCiAgICAuLi5jb21tZW50Py5zdGFydFNpZGUgPyB7IHN0YXJ0U2lkZTogY29tbWVudC5zdGFydFNpZGUgfSA6IHt9LAogICAgLi4uY29tbWVudD8uZGlmZkh1bmsgPyB7IGRpZmZIdW5rOiB0cnVuY2F0ZVRleHQoY29tbWVudC5kaWZmSHVuaywgOGUzKSB9IDoge30sCiAgICAuLi5jb21tZW50Py5jb21taXRJZCA/IHsgY29tbWl0SWQ6IGNvbW1lbnQuY29tbWl0SWQgfSA6IHt9LAogICAgLi4uY29tbWVudD8ub3JpZ2luYWxDb21taXRJZCA/IHsgb3JpZ2luYWxDb21taXRJZDogY29tbWVudC5vcmlnaW5hbENvbW1pdElkIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/LmluUmVwbHlUb0lkICE9PSB2b2lkIDAgPyB7IGluUmVwbHlUb0lkOiBjb21tZW50LmluUmVwbHlUb0lkIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQ/LnB1bGxSZXF1ZXN0UmV2aWV3SWQgIT09IHZvaWQgMCA/IHsgcHVsbFJlcXVlc3RSZXZpZXdJZDogY29tbWVudC5wdWxsUmVxdWVzdFJldmlld0lkIH0gOiB7fQogIH07Cn0KZnVuY3Rpb24gY29tcGFyZVNvdXJjZWRGaW5kaW5ncyhsZWZ0LCByaWdodCkgewogIGNvbnN0IHNvdXJjZU9yZGVyID0geyByZXZpZXc6IDAsIHJldmlld19jb21tZW50OiAxIH07CiAgcmV0dXJuIHNvdXJjZU9yZGVyW2xlZnQuc291cmNlXSAtIHNvdXJjZU9yZGVyW3JpZ2h0LnNvdXJjZV0gfHwgbGVmdC5pZCAtIHJpZ2h0LmlkOwp9CmZ1bmN0aW9uIGZpbmRpbmdLZXkodmFsdWUpIHsKICBjb25zdCBjb21tZW50SWQgPSAiaWQiIGluIHZhbHVlID8gdmFsdWUuaWQgOiB2YWx1ZS5jb21tZW50SWQ7CiAgcmV0dXJuIGAke3ZhbHVlLnNvdXJjZX06JHtjb21tZW50SWR9YDsKfQpmdW5jdGlvbiBza2lwcGVkMihyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgcmVhc29uKSB7CiAgcmV0dXJuIHsgb2s6IHRydWUsIHNraXBwZWQ6IHRydWUsIHJlYXNvbiwgcmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIgfTsKfQpmdW5jdGlvbiByZXF1aXJlUmV2aWV3Qm90SWRlbnRpdHkoZGVwZW5kZW5jaWVzKSB7CiAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSAmJiAhZGVwZW5kZW5jaWVzLmJvdExvZ2luPy50cmltKCkpIHsKICAgIHRocm93IG5ldyBFcnJvcigiRHJhZnQgUFIgYm90IGxvZ2luIGlzIHJlcXVpcmVkIGluIGFwcGx5IG1vZGUiKTsKICB9Cn0KCi8vIHNyYy9ydW50aW1lL3RhcmdldC1iaW5kaW5nLnRzCmZ1bmN0aW9uIGFzc2VydEJvdW5kVGFyZ2V0KG9wdGlvbnMpIHsKICBjb25zdCBleHBlY3RlZFJlcG9zaXRvcnkgPSBvcHRpb25zLmV4cGVjdGVkUmVwb3NpdG9yeT8udHJpbSgpID8/ICIiOwogIGNvbnN0IGV4cGVjdGVkVGFyZ2V0VGV4dCA9IG9wdGlvbnMuZXhwZWN0ZWRUYXJnZXQ/LnRyaW0oKSA/PyAiIjsKICBpZiAoIWV4cGVjdGVkUmVwb3NpdG9yeSAmJiAhZXhwZWN0ZWRUYXJnZXRUZXh0KSB7CiAgICBpZiAob3B0aW9ucy5hcHBseSkgdGhyb3cgbmV3IEVycm9yKG9wdGlvbnMuZXJyb3JzLm1pc3NpbmcpOwogICAgcmV0dXJuOwogIH0KICBpZiAoIWV4cGVjdGVkUmVwb3NpdG9yeSB8fCAhZXhwZWN0ZWRUYXJnZXRUZXh0KSB7CiAgICB0aHJvdyBuZXcgRXJyb3Iob3B0aW9ucy5lcnJvcnMuaW5jb21wbGV0ZSk7CiAgfQogIGNvbnN0IGV4cGVjdGVkVGFyZ2V0ID0gTnVtYmVyKGV4cGVjdGVkVGFyZ2V0VGV4dCk7CiAgaWYgKCFpc1JlcG9zaXRvcnlTbHVnKGV4cGVjdGVkUmVwb3NpdG9yeSkgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKGV4cGVjdGVkVGFyZ2V0KSB8fCBleHBlY3RlZFRhcmdldCA8PSAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3Iob3B0aW9ucy5lcnJvcnMuaW52YWxpZCk7CiAgfQogIGlmIChvcHRpb25zLnJlcG9zaXRvcnkgIT09IGV4cGVjdGVkUmVwb3NpdG9yeSB8fCBvcHRpb25zLnRhcmdldE51bWJlciAhPT0gZXhwZWN0ZWRUYXJnZXQpIHsKICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgb3B0aW9ucy5lcnJvcnMubWlzbWF0Y2goZXhwZWN0ZWRSZXBvc2l0b3J5LCBleHBlY3RlZFRhcmdldCkKICAgICk7CiAgfQp9CgovLyBzcmMvZHJhZnQtcHIvdGFyZ2V0LnRzCmZ1bmN0aW9uIGFzc2VydEJvdW5kUmV2aWV3VGFyZ2V0KHJlcG9zaXRvcnksIHB1bGxSZXF1ZXN0TnVtYmVyLCBhcHBseSwgZW52aXJvbm1lbnQpIHsKICBhc3NlcnRCb3VuZFRhcmdldCh7CiAgICByZXBvc2l0b3J5LAogICAgdGFyZ2V0TnVtYmVyOiBwdWxsUmVxdWVzdE51bWJlciwKICAgIGFwcGx5LAogICAgZXhwZWN0ZWRSZXBvc2l0b3J5OiBlbnZpcm9ubWVudC5EUkFGVF9QUl9FWFBFQ1RFRF9SRVBPU0lUT1JZLAogICAgZXhwZWN0ZWRUYXJnZXQ6IGVudmlyb25tZW50LkRSQUZUX1BSX0VYUEVDVEVEX1BVTExfUkVRVUVTVCwKICAgIGVycm9yczogewogICAgICBtaXNzaW5nOiAiRHJhZnQgUFIgcmV2aWV3IGFwcGx5IG1vZGUgcmVxdWlyZXMgYSBzY2hlZHVsZXItYm91bmQgUHVsbCBSZXF1ZXN0IHRhcmdldCIsCiAgICAgIGluY29tcGxldGU6ICJpbmNvbXBsZXRlIHNjaGVkdWxlci1ib3VuZCBEcmFmdCBQUiByZXZpZXcgdGFyZ2V0IiwKICAgICAgaW52YWxpZDogImludmFsaWQgc2NoZWR1bGVyLWJvdW5kIERyYWZ0IFBSIHJldmlldyB0YXJnZXQiLAogICAgICBtaXNtYXRjaDogKCkgPT4gYHJlcXVlc3RlZCBQdWxsIFJlcXVlc3QgJHtyZXBvc2l0b3J5fSMke3B1bGxSZXF1ZXN0TnVtYmVyfSBkb2VzIG5vdCBtYXRjaCB0aGUgc2NoZWR1bGVyLWJvdW5kIHJldmlldyB0YXJnZXRgCiAgICB9CiAgfSk7Cn0KZnVuY3Rpb24gYXNzZXJ0Qm91bmREcmFmdFByVGFyZ2V0KHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBhcHBseSwgZW52aXJvbm1lbnQpIHsKICBhc3NlcnRCb3VuZFRhcmdldCh7CiAgICByZXBvc2l0b3J5LAogICAgdGFyZ2V0TnVtYmVyOiBpc3N1ZU51bWJlciwKICAgIGFwcGx5LAogICAgZXhwZWN0ZWRSZXBvc2l0b3J5OiBlbnZpcm9ubWVudC5EUkFGVF9QUl9FWFBFQ1RFRF9SRVBPU0lUT1JZLAogICAgZXhwZWN0ZWRUYXJnZXQ6IGVudmlyb25tZW50LkRSQUZUX1BSX0VYUEVDVEVEX0lTU1VFLAogICAgZXJyb3JzOiB7CiAgICAgIG1pc3Npbmc6ICJEcmFmdCBQUiBhcHBseSBtb2RlIHJlcXVpcmVzIGEgc2NoZWR1bGVyLWJvdW5kIElzc3VlIHRhcmdldCIsCiAgICAgIGluY29tcGxldGU6ICJpbmNvbXBsZXRlIHNjaGVkdWxlci1ib3VuZCBEcmFmdCBQUiB0YXJnZXQiLAogICAgICBpbnZhbGlkOiAiaW52YWxpZCBzY2hlZHVsZXItYm91bmQgRHJhZnQgUFIgdGFyZ2V0IiwKICAgICAgbWlzbWF0Y2g6ICgpID0+IGByZXF1ZXN0ZWQgSXNzdWUgJHtyZXBvc2l0b3J5fSMke2lzc3VlTnVtYmVyfSBkb2VzIG5vdCBtYXRjaCB0aGUgc2NoZWR1bGVyLWJvdW5kIERyYWZ0IFBSIHRhcmdldGAKICAgIH0KICB9KTsKfQoKLy8gc3JjL2lzc3Vlcy9tYW5hZ2VkLWNvbW1lbnRzLnRzCnZhciBJU1NVRV9UUklBR0VfQ09NTUVOVF9QUkVGSVggPSAiPCEtLSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3M6aXNzdWUtdHJpYWdlOnYxIjsKZnVuY3Rpb24gaXNJc3N1ZVRyaWFnZUNvbW1lbnQoYm9keSkgewogIHJldHVybiBib2R5LnN0YXJ0c1dpdGgoSVNTVUVfVFJJQUdFX0NPTU1FTlRfUFJFRklYKTsKfQoKLy8gc3JjL2RyYWZ0LXByL2NvbW1lbnQudHMKdmFyIERSQUZUX1BSX0NPTU1FTlRfUFJFRklYID0gIjwhLS0gZW5naW5lZXJpbmctYWdlbnQtd29ya2Zsb3dzOmRyYWZ0LXByOnYxIjsKZnVuY3Rpb24gZHJhZnRQckNvbW1lbnRNYXJrZXIoaXNzdWVOdW1iZXIpIHsKICByZXR1cm4gYCR7RFJBRlRfUFJfQ09NTUVOVF9QUkVGSVh9IGlzc3VlPSR7aXNzdWVOdW1iZXJ9IC0tPmA7Cn0KZnVuY3Rpb24gZmluZERyYWZ0UHJDb21tZW50KGNvbW1lbnRzLCBib3RMb2dpbikgewogIGNvbnN0IGV4cGVjdGVkID0gYm90TG9naW4udHJpbSgpLnRvTG93ZXJDYXNlKCk7CiAgcmV0dXJuIGNvbW1lbnRzLmZpbmQoCiAgICAoY29tbWVudCkgPT4gY29tbWVudC51c2VyPy5sb2dpbi50cmltKCkudG9Mb3dlckNhc2UoKSA9PT0gZXhwZWN0ZWQgJiYgY29tbWVudC5ib2R5LnN0YXJ0c1dpdGgoRFJBRlRfUFJfQ09NTUVOVF9QUkVGSVgpCiAgKTsKfQpmdW5jdGlvbiBidWlsZERyYWZ0UHJTdGF0dXNDb21tZW50KGlzc3VlTnVtYmVyLCBzdGF0dXMsIGRldGFpbHMgPSB7fSkgewogIGNvbnN0IGxpbmVzID0gW2RyYWZ0UHJDb21tZW50TWFya2VyKGlzc3VlTnVtYmVyKSwgIiMjIERyYWZ0IFBSIGFnZW50IiwgIiJdOwogIGlmIChzdGF0dXMgPT09ICJydW5uaW5nIikgewogICAgbGluZXMucHVzaCgiVGhlIHJlcG9zaXRvcnkgZGV2ZWxvcG1lbnQgQWdlbnQgaGFzIGNsYWltZWQgdGhpcyBJc3N1ZS4iKTsKICB9IGVsc2UgaWYgKHN0YXR1cyA9PT0gIm5lZWRzLWFwcHJvdmFsIikgewogICAgbGluZXMucHVzaCgiSW1wbGVtZW50YXRpb24gcGF1c2VkIGZvciBtYWludGFpbmVyIGFwcHJvdmFsLiIpOwogIH0gZWxzZSBpZiAoc3RhdHVzID09PSAicHItb3BlbiIpIHsKICAgIGxpbmVzLnB1c2goCiAgICAgIGRldGFpbHMucHVsbFJlcXVlc3RVcmwgPyBgRHJhZnQgUHVsbCBSZXF1ZXN0OiAke2RldGFpbHMucHVsbFJlcXVlc3RVcmx9YCA6ICJBIERyYWZ0IFB1bGwgUmVxdWVzdCB3YXMgY3JlYXRlZC4iCiAgICApOwogIH0gZWxzZSBpZiAoc3RhdHVzID09PSAiZHJ5LXJ1biIpIHsKICAgIGxpbmVzLnB1c2goIkRyeSBydW4gY29tcGxldGVkOyBubyBicmFuY2ggb3IgUHVsbCBSZXF1ZXN0IHdhcyBjcmVhdGVkLiIpOwogIH0gZWxzZSB7CiAgICBsaW5lcy5wdXNoKAogICAgICAiVGhlIHJlcG9zaXRvcnkgZGV2ZWxvcG1lbnQgQWdlbnQgY291bGQgbm90IHByZXBhcmUgYSBEcmFmdCBQUi4iCiAgICApOwogIH0KICBjb25zdCByZWFzb25zID0gKGRldGFpbHMucmVhc29ucyA/PyBbXSkubWFwKHNhbml0aXplRmFpbHVyZVJlYXNvbikuZmlsdGVyKEJvb2xlYW4pOwogIGlmIChyZWFzb25zLmxlbmd0aCA+IDApIHsKICAgIGxpbmVzLnB1c2goIiIsICIjIyMgQXR0ZW50aW9uIiwgIiIpOwogICAgZm9yIChjb25zdCByZWFzb24gb2YgcmVhc29ucy5zbGljZSgwLCA4KSkgbGluZXMucHVzaChgLSAke3JlYXNvbn1gKTsKICB9CiAgY29uc3QgbWVzc2FnZSA9IHNhbml0aXplTGluZShkZXRhaWxzLm1lc3NhZ2UgPz8gIiIpOwogIGlmIChtZXNzYWdlKSBsaW5lcy5wdXNoKCIiLCBtZXNzYWdlKTsKICByZXR1cm4gbGluZXMuam9pbigiXG4iKTsKfQpmdW5jdGlvbiBzYW5pdGl6ZUxpbmUodmFsdWUpIHsKICByZXR1cm4gdmFsdWUucmVwbGFjZSgvPCEtLVtcc1xTXSo/LS0+L2csICIiKS5yZXBsYWNlKC9bXHJcbl0rL2csICIgIikucmVwbGFjZSgvXHMrL2csICIgIikudHJpbSgpLnNsaWNlKDAsIDUwMCk7Cn0KZnVuY3Rpb24gc2FuaXRpemVGYWlsdXJlUmVhc29uKHZhbHVlKSB7CiAgcmV0dXJuIHNhbml0aXplTGluZSh2YWx1ZSkucmVwbGFjZSgKICAgIC9cYig/OmdoW3BvdXNyXV9bQS1aYS16MC05XXsyMCx9fGdpdGh1Yl9wYXRfW0EtWmEtejAtOV9dezIwLH0pXGIvZywKICAgICI8cmVkYWN0ZWQtdG9rZW4+IgogICkucmVwbGFjZSgvKEF1dGhvcml6YXRpb25ccyo6XHMqKSg/OkJlYXJlcnx0b2tlbilccytcUysvZ2ksICIkMTxyZWRhY3RlZD4iKS5yZXBsYWNlKC8oaHR0cHM/OlwvXC8pW15ccy9AOl0rOlteXHMvQF0rQC9naSwgIiQxPHJlZGFjdGVkPkAiKS5yZXBsYWNlKC8oWz8mXSg/OmFjY2Vzc190b2tlbnx0b2tlbik9KVteJlxzXSsvZ2ksICIkMTxyZWRhY3RlZD4iKS5zbGljZSgwLCA1MDApOwp9CgovLyBzcmMvZHJhZnQtcHIvdG9vbC50cwphc3luYyBmdW5jdGlvbiBwcmVwYXJlRHJhZnRQcihyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgdHJpZ2dlciwgZGVwZW5kZW5jaWVzKSB7CiAgYXNzZXJ0QWxsb3dlZFJlcG9zaXRvcnkocmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzLmFsbG93ZWRSZXBvc2l0b3J5KTsKICBjb25zdCBpc3N1ZTIgPSBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIuZ2V0SXNzdWUocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIpOwogIGNvbnN0IHJlYXNvbiA9IGluZWxpZ2libGVSZWFzb24zKGlzc3VlMiwgdHJpZ2dlciwgZGVwZW5kZW5jaWVzLnBvbGljeSk7CiAgaWYgKHJlYXNvbikgewogICAgcmV0dXJuIHsKICAgICAgb2s6IHRydWUsCiAgICAgIHNraXBwZWQ6IHRydWUsCiAgICAgIHJlYXNvbiwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIHRyaWdnZXIsCiAgICAgIGFwcHJvdmVkOiB0cmlnZ2VyID09PSAiYXBwcm92ZWQiCiAgICB9OwogIH0KICBjb25zdCBicmFuY2ggPSBgJHtkZXBlbmRlbmNpZXMucG9saWN5LmJyYW5jaFByZWZpeH0ke2lzc3VlTnVtYmVyfWA7CiAgY29uc3QgZXhpc3RpbmdQdWxsUmVxdWVzdHMgPSBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIubGlzdE9wZW5QdWxsUmVxdWVzdHNCeUhlYWQocmVwb3NpdG9yeSwgYnJhbmNoKTsKICBpZiAoZXhpc3RpbmdQdWxsUmVxdWVzdHMubGVuZ3RoID4gMCkgewogICAgcmV0dXJuIHsKICAgICAgb2s6IHRydWUsCiAgICAgIHNraXBwZWQ6IHRydWUsCiAgICAgIHJlYXNvbjogYGFuIG9wZW4gUHVsbCBSZXF1ZXN0IGFscmVhZHkgZXhpc3RzIGZvciAke2JyYW5jaH1gLAogICAgICByZXBvc2l0b3J5LAogICAgICBpc3N1ZU51bWJlciwKICAgICAgdHJpZ2dlciwKICAgICAgYXBwcm92ZWQ6IHRyaWdnZXIgPT09ICJhcHByb3ZlZCIKICAgIH07CiAgfQogIGNvbnN0IFtiYXNlQnJhbmNoLCBjb21tZW50c10gPSBhd2FpdCBQcm9taXNlLmFsbChbCiAgICBkZXBlbmRlbmNpZXMucHJvdmlkZXIuZ2V0UmVwb3NpdG9yeURlZmF1bHRCcmFuY2gocmVwb3NpdG9yeSksCiAgICBkZXBlbmRlbmNpZXMucHJvdmlkZXIubGlzdENvbW1lbnRzKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyKQogIF0pOwogIGNvbnN0IGNvbnRleHRDb21tZW50cyA9IHNlbGVjdENvbnRleHRDb21tZW50cygKICAgIGNvbW1lbnRzLAogICAgZGVwZW5kZW5jaWVzLmJvdExvZ2luCiAgKTsKICBjb25zdCBmaW5nZXJwcmludCA9IGlzc3VlRmluZ2VycHJpbnQoaXNzdWUyLCBjb250ZXh0Q29tbWVudHMpOwogIGxldCBwcmVwYXJlZFdvcmtzcGFjZTsKICB0cnkgewogICAgcHJlcGFyZWRXb3Jrc3BhY2UgPSBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLnByZXBhcmUoewogICAgICByZXBvc2l0b3J5LAogICAgICBpc3N1ZU51bWJlciwKICAgICAgY2xvbmVVcmw6IHJlcG9zaXRvcnlDbG9uZVVybChkZXBlbmRlbmNpZXMuc2VydmVyVXJsLCByZXBvc2l0b3J5KSwKICAgICAgYmFzZUJyYW5jaCwKICAgICAgYnJhbmNoCiAgICB9KTsKICAgIGlmIChkZXBlbmRlbmNpZXMuYXBwbHkpIHsKICAgICAgY29uc3QgYm90TG9naW4gPSByZXF1aXJlZEJvdExvZ2luKGRlcGVuZGVuY2llcy5ib3RMb2dpbik7CiAgICAgIGF3YWl0IGNsYWltSXNzdWUoCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBpc3N1ZU51bWJlciwKICAgICAgICB0cmlnZ2VyLAogICAgICAgIGRlcGVuZGVuY2llcywKICAgICAgICBib3RMb2dpbgogICAgICApOwogICAgfQogIH0gY2F0Y2ggKGVycm9yKSB7CiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBEcmFmdFByV29ya3NwYWNlTG9ja0Vycm9yKSB7CiAgICAgIHJldHVybiB7CiAgICAgICAgb2s6IHRydWUsCiAgICAgICAgc2tpcHBlZDogdHJ1ZSwKICAgICAgICByZWFzb246IGVycm9yLm1lc3NhZ2UsCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBpc3N1ZU51bWJlciwKICAgICAgICB0cmlnZ2VyLAogICAgICAgIGFwcHJvdmVkOiB0cmlnZ2VyID09PSAiYXBwcm92ZWQiCiAgICAgIH07CiAgICB9CiAgICBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmNsZWFudXAocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIpOwogICAgdGhyb3cgZXJyb3I7CiAgfQogIHJldHVybiB7CiAgICBvazogdHJ1ZSwKICAgIHJlcG9zaXRvcnksCiAgICBpc3N1ZU51bWJlciwKICAgIHRyaWdnZXIsCiAgICBhcHByb3ZlZDogdHJpZ2dlciA9PT0gImFwcHJvdmVkIiwKICAgIGlzc3VlRmluZ2VycHJpbnQ6IGZpbmdlcnByaW50LAogICAgaXNzdWU6IGlzc3VlMiwKICAgIGNvbW1lbnRzOiBjb250ZXh0Q29tbWVudHMsCiAgICB3b3Jrc3BhY2VQYXRoOiBwcmVwYXJlZFdvcmtzcGFjZS5wYXRoLAogICAgYnJhbmNoOiBwcmVwYXJlZFdvcmtzcGFjZS5icmFuY2gsCiAgICBiYXNlQnJhbmNoOiBwcmVwYXJlZFdvcmtzcGFjZS5iYXNlQnJhbmNoLAogICAgYmFzZUNvbW1pdDogcHJlcGFyZWRXb3Jrc3BhY2UuYmFzZUNvbW1pdAogIH07Cn0KYXN5bmMgZnVuY3Rpb24gYXBwbHlEcmFmdFByKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBzdWJtaXNzaW9uSW5wdXQsIGRlcGVuZGVuY2llcykgewogIGFzc2VydEFsbG93ZWRSZXBvc2l0b3J5KHJlcG9zaXRvcnksIGRlcGVuZGVuY2llcy5hbGxvd2VkUmVwb3NpdG9yeSk7CiAgY29uc3Qgc3VibWlzc2lvbiA9IGRyYWZ0UHJTdWJtaXNzaW9uU2NoZW1hLnBhcnNlKHN1Ym1pc3Npb25JbnB1dCk7CiAgY29uc3QgW2lzc3VlMiwgY29tbWVudHNdID0gYXdhaXQgUHJvbWlzZS5hbGwoWwogICAgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmdldElzc3VlKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyKSwKICAgIGRlcGVuZGVuY2llcy5wcm92aWRlci5saXN0Q29tbWVudHMocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIpCiAgXSk7CiAgY29uc3QgY29udGV4dENvbW1lbnRzID0gc2VsZWN0Q29udGV4dENvbW1lbnRzKAogICAgY29tbWVudHMsCiAgICBkZXBlbmRlbmNpZXMuYm90TG9naW4KICApOwogIGlmIChpc3N1ZUZpbmdlcnByaW50KGlzc3VlMiwgY29udGV4dENvbW1lbnRzKSAhPT0gc3VibWlzc2lvbi5pc3N1ZUZpbmdlcnByaW50KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIklzc3VlIGNoYW5nZWQgYWZ0ZXIgdGhlIERyYWZ0IFBSIEFnZW50IHN0YXJ0ZWQiKTsKICB9CiAgaWYgKGlzc3VlMi5zdGF0ZS50b0xvd2VyQ2FzZSgpICE9PSAib3BlbiIpIHsKICAgIHRocm93IG5ldyBFcnJvcigiSXNzdWUgaXMgbm8gbG9uZ2VyIG9wZW4iKTsKICB9CiAgY29uc3QgaW5zcGVjdGlvbiA9IGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuaW5zcGVjdCgKICAgIHN1Ym1pc3Npb24ud29ya3NwYWNlUGF0aAogICk7CiAgaWYgKGluc3BlY3Rpb24uaGVhZENvbW1pdCAhPT0gc3VibWlzc2lvbi5iYXNlQ29tbWl0KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJ0aGUgQWdlbnQgY29tbWl0dGVkIG9yIG1vdmVkIEhFQUQgaW5zaWRlIHRoZSBwcmVwYXJlZCB3b3Jrc3BhY2UiCiAgICApOwogIH0KICBjb25zdCBhbmFseXNpcyA9IHN1Ym1pc3Npb24uYW5hbHlzaXM7CiAgaWYgKGFuYWx5c2lzLm91dGNvbWUgIT09ICJpbXBsZW1lbnRlZCIpIHsKICAgIGNvbnN0IHJlYXNvbnMgPSBhbmFseXNpcy5vdXRjb21lID09PSAibmVlZHNfYXBwcm92YWwiID8gb3V0Y29tZVJlYXNvbnMoYW5hbHlzaXMpIDogZmFpbHVyZVJlYXNvbnMoYW5hbHlzaXMpOwogICAgaWYgKGFuYWx5c2lzLm91dGNvbWUgPT09ICJuZWVkc19hcHByb3ZhbCIpIHsKICAgICAgYXdhaXQgdHJhbnNpdGlvbk5lZWRzQXBwcm92YWwoCiAgICAgICAgcmVwb3NpdG9yeSwKICAgICAgICBpc3N1ZU51bWJlciwKICAgICAgICByZWFzb25zLAogICAgICAgIGRlcGVuZGVuY2llcwogICAgICApOwogICAgfSBlbHNlIHsKICAgICAgYXdhaXQgdHJhbnNpdGlvbkZhaWxlZChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgcmVhc29ucywgZGVwZW5kZW5jaWVzKTsKICAgIH0KICAgIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGRlcGVuZGVuY2llcy5hcHBseSwKICAgICAgb3V0Y29tZTogYW5hbHlzaXMub3V0Y29tZSwKICAgICAgYnJhbmNoOiBzdWJtaXNzaW9uLmJyYW5jaCwKICAgICAgaW5zcGVjdGlvbgogICAgfTsKICB9CiAgdmFsaWRhdGVJbXBsZW1lbnRlZEFuYWx5c2lzKGFuYWx5c2lzLCBpbnNwZWN0aW9uKTsKICBjb25zdCBhcHByb3ZhbFJlYXNvbnMgPSByZXF1aXJlc0FwcHJvdmFsKAogICAgYW5hbHlzaXMsCiAgICBpbnNwZWN0aW9uLAogICAgc3VibWlzc2lvbi50cmlnZ2VyID09PSAiYXBwcm92ZWQiLAogICAgZGVwZW5kZW5jaWVzLnBvbGljeQogICk7CiAgaWYgKGFwcHJvdmFsUmVhc29ucy5sZW5ndGggPiAwKSB7CiAgICBhd2FpdCB0cmFuc2l0aW9uTmVlZHNBcHByb3ZhbCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIGFwcHJvdmFsUmVhc29ucywKICAgICAgZGVwZW5kZW5jaWVzCiAgICApOwogICAgYXdhaXQgZGVwZW5kZW5jaWVzLndvcmtzcGFjZS5jbGVhbnVwKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyKTsKICAgIHJldHVybiB7CiAgICAgIG9rOiB0cnVlLAogICAgICByZXBvc2l0b3J5LAogICAgICBpc3N1ZU51bWJlciwKICAgICAgYXBwbGllZDogZGVwZW5kZW5jaWVzLmFwcGx5LAogICAgICBvdXRjb21lOiAibmVlZHNfYXBwcm92YWwiLAogICAgICBicmFuY2g6IHN1Ym1pc3Npb24uYnJhbmNoLAogICAgICBpbnNwZWN0aW9uCiAgICB9OwogIH0KICBjb25zdCB0aXRsZSA9IHNhbml0aXplVGl0bGUoYW5hbHlzaXMucHJUaXRsZSk7CiAgY29uc3QgYm9keSA9IGJ1aWxkUHVsbFJlcXVlc3RCb2R5KGlzc3VlTnVtYmVyLCBhbmFseXNpcyk7CiAgaWYgKCFkZXBlbmRlbmNpZXMuYXBwbHkpIHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGZhbHNlLAogICAgICBvdXRjb21lOiAiaW1wbGVtZW50ZWQiLAogICAgICBicmFuY2g6IHN1Ym1pc3Npb24uYnJhbmNoLAogICAgICBwcm9wb3NlZFRpdGxlOiB0aXRsZSwKICAgICAgcHJvcG9zZWRCb2R5OiBib2R5LAogICAgICBpbnNwZWN0aW9uCiAgICB9OwogIH0KICBjb25zdCBjb21taXQgPSBhd2FpdCBkZXBlbmRlbmNpZXMud29ya3NwYWNlLmNvbW1pdEFuZFB1c2goCiAgICBzdWJtaXNzaW9uLndvcmtzcGFjZVBhdGgsCiAgICBzdWJtaXNzaW9uLmJyYW5jaCwKICAgIHRpdGxlLAogICAgcmVwb3NpdG9yeUNsb25lVXJsKGRlcGVuZGVuY2llcy5zZXJ2ZXJVcmwsIHJlcG9zaXRvcnkpCiAgKTsKICBjb25zdCBwdWxsUmVxdWVzdCA9IGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5jcmVhdGVEcmFmdFB1bGxSZXF1ZXN0KAogICAgcmVwb3NpdG9yeSwKICAgIHsKICAgICAgdGl0bGUsCiAgICAgIGJvZHksCiAgICAgIGhlYWQ6IHN1Ym1pc3Npb24uYnJhbmNoLAogICAgICBiYXNlOiBzdWJtaXNzaW9uLmJhc2VCcmFuY2gKICAgIH0KICApOwogIGF3YWl0IHRyYW5zaXRpb25QdWxsUmVxdWVzdE9wZW4oCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIsCiAgICBwdWxsUmVxdWVzdC51cmwsCiAgICBkZXBlbmRlbmNpZXMKICApOwogIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgYXBwbGllZDogdHJ1ZSwKICAgIG91dGNvbWU6ICJpbXBsZW1lbnRlZCIsCiAgICBicmFuY2g6IHN1Ym1pc3Npb24uYnJhbmNoLAogICAgY29tbWl0LAogICAgcHVsbFJlcXVlc3ROdW1iZXI6IHB1bGxSZXF1ZXN0Lm51bWJlciwKICAgIHB1bGxSZXF1ZXN0VXJsOiBwdWxsUmVxdWVzdC51cmwsCiAgICBpbnNwZWN0aW9uCiAgfTsKfQphc3luYyBmdW5jdGlvbiBmYWlsRHJhZnRQcihyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgbWVzc2FnZSwgZGVwZW5kZW5jaWVzKSB7CiAgYXNzZXJ0QWxsb3dlZFJlcG9zaXRvcnkocmVwb3NpdG9yeSwgZGVwZW5kZW5jaWVzLmFsbG93ZWRSZXBvc2l0b3J5KTsKICB0cnkgewogICAgaWYgKGRlcGVuZGVuY2llcy5hcHBseSkgewogICAgICBhd2FpdCB0cmFuc2l0aW9uRmFpbGVkKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBbbWVzc2FnZV0sIGRlcGVuZGVuY2llcyk7CiAgICB9CiAgfSBmaW5hbGx5IHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy53b3Jrc3BhY2UuY2xlYW51cChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgfQogIHJldHVybiB7CiAgICBvazogdHJ1ZSwKICAgIHJlcG9zaXRvcnksCiAgICBpc3N1ZU51bWJlciwKICAgIGFwcGxpZWQ6IGRlcGVuZGVuY2llcy5hcHBseSwKICAgIG91dGNvbWU6ICJmYWlsZWQiCiAgfTsKfQpmdW5jdGlvbiBpbmVsaWdpYmxlUmVhc29uMyhpc3N1ZTIsIHRyaWdnZXIsIHBvbGljeSkgewogIGlmIChpc3N1ZTIuc3RhdGUudG9Mb3dlckNhc2UoKSAhPT0gIm9wZW4iKSByZXR1cm4gIklzc3VlIGlzIG5vdCBvcGVuIjsKICBpZiAoaGFzQW55TGFiZWwoaXNzdWUyLmxhYmVscywgcG9saWN5LnNraXBMYWJlbHMpKSB7CiAgICByZXR1cm4gIklzc3VlIGhhcyBhIGNvbmZpZ3VyZWQgc2tpcCBsYWJlbCI7CiAgfQogIGlmIChoYXNBbnlMYWJlbChpc3N1ZTIubGFiZWxzLCBwb2xpY3kuYmxvY2tlZExhYmVscykpIHsKICAgIHJldHVybiAiSXNzdWUgaGFzIGEgbGFiZWwgdGhhdCBibG9ja3MgRHJhZnQgUFIgZXhlY3V0aW9uIjsKICB9CiAgY29uc3QgdHJpZ2dlckxhYmVsID0gdHJpZ2dlciA9PT0gImFwcHJvdmVkIiA/IHBvbGljeS5hcHByb3ZlZExhYmVsIDogcG9saWN5LnJlYWR5TGFiZWw7CiAgaWYgKCFoYXNMYWJlbChpc3N1ZTIubGFiZWxzLCB0cmlnZ2VyTGFiZWwpKSB7CiAgICByZXR1cm4gYElzc3VlIGRvZXMgbm90IGhhdmUgJHt0cmlnZ2VyTGFiZWx9YDsKICB9CiAgaWYgKHRyaWdnZXIgPT09ICJhcHByb3ZlZCIgJiYgIWhhc0xhYmVsKGlzc3VlMi5sYWJlbHMsIHBvbGljeS5uZWVkc0FwcHJvdmFsTGFiZWwpKSB7CiAgICByZXR1cm4gYElzc3VlIGRvZXMgbm90IGhhdmUgJHtwb2xpY3kubmVlZHNBcHByb3ZhbExhYmVsfWA7CiAgfQogIHJldHVybiB2b2lkIDA7Cn0KYXN5bmMgZnVuY3Rpb24gY2xhaW1Jc3N1ZShyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgdHJpZ2dlciwgZGVwZW5kZW5jaWVzLCBib3RMb2dpbikgewogIGNvbnN0IHBvbGljeSA9IGRlcGVuZGVuY2llcy5wb2xpY3k7CiAgYXdhaXQgZW5zdXJlV29ya2Zsb3dMYWJlbHMocmVwb3NpdG9yeSwgW3BvbGljeS5ydW5uaW5nTGFiZWxdLCBkZXBlbmRlbmNpZXMpOwogIGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5hZGRMYWJlbHMocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIFsKICAgIHBvbGljeS5ydW5uaW5nTGFiZWwKICBdKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIucmVtb3ZlTGFiZWwoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIsCiAgICB0cmlnZ2VyID09PSAiYXBwcm92ZWQiID8gcG9saWN5LmFwcHJvdmVkTGFiZWwgOiBwb2xpY3kucmVhZHlMYWJlbAogICk7CiAgYXdhaXQgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLnJlbW92ZUxhYmVsKAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgcG9saWN5LmZhaWxlZExhYmVsCiAgKTsKICBpZiAodHJpZ2dlciA9PT0gImFwcHJvdmVkIikgewogICAgYXdhaXQgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLnJlbW92ZUxhYmVsKAogICAgICByZXBvc2l0b3J5LAogICAgICBpc3N1ZU51bWJlciwKICAgICAgcG9saWN5Lm5lZWRzQXBwcm92YWxMYWJlbAogICAgKTsKICB9CiAgYXdhaXQgdXBzZXJ0U3RhdHVzQ29tbWVudCgKICAgIHJlcG9zaXRvcnksCiAgICBpc3N1ZU51bWJlciwKICAgIGJ1aWxkRHJhZnRQclN0YXR1c0NvbW1lbnQoaXNzdWVOdW1iZXIsICJydW5uaW5nIiksCiAgICBkZXBlbmRlbmNpZXMsCiAgICBib3RMb2dpbgogICk7Cn0KYXN5bmMgZnVuY3Rpb24gdHJhbnNpdGlvbk5lZWRzQXBwcm92YWwocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIHJlYXNvbnMsIGRlcGVuZGVuY2llcykgewogIGlmICghZGVwZW5kZW5jaWVzLmFwcGx5KSByZXR1cm47CiAgY29uc3QgYm90TG9naW4gPSByZXF1aXJlZEJvdExvZ2luKGRlcGVuZGVuY2llcy5ib3RMb2dpbik7CiAgY29uc3QgcG9saWN5ID0gZGVwZW5kZW5jaWVzLnBvbGljeTsKICBhd2FpdCBlbnN1cmVXb3JrZmxvd0xhYmVscygKICAgIHJlcG9zaXRvcnksCiAgICBbcG9saWN5Lm5lZWRzQXBwcm92YWxMYWJlbF0sCiAgICBkZXBlbmRlbmNpZXMKICApOwogIGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5hZGRMYWJlbHMocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIFsKICAgIHBvbGljeS5uZWVkc0FwcHJvdmFsTGFiZWwKICBdKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIucmVtb3ZlTGFiZWwoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIsCiAgICBwb2xpY3kucnVubmluZ0xhYmVsCiAgKTsKICBhd2FpdCB1cHNlcnRTdGF0dXNDb21tZW50KAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgYnVpbGREcmFmdFByU3RhdHVzQ29tbWVudChpc3N1ZU51bWJlciwgIm5lZWRzLWFwcHJvdmFsIiwgeyByZWFzb25zIH0pLAogICAgZGVwZW5kZW5jaWVzLAogICAgYm90TG9naW4KICApOwp9CmFzeW5jIGZ1bmN0aW9uIHRyYW5zaXRpb25GYWlsZWQocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIHJlYXNvbnMsIGRlcGVuZGVuY2llcykgewogIGlmICghZGVwZW5kZW5jaWVzLmFwcGx5KSByZXR1cm47CiAgY29uc3QgYm90TG9naW4gPSByZXF1aXJlZEJvdExvZ2luKGRlcGVuZGVuY2llcy5ib3RMb2dpbik7CiAgY29uc3QgcG9saWN5ID0gZGVwZW5kZW5jaWVzLnBvbGljeTsKICBhd2FpdCBlbnN1cmVXb3JrZmxvd0xhYmVscyhyZXBvc2l0b3J5LCBbcG9saWN5LmZhaWxlZExhYmVsXSwgZGVwZW5kZW5jaWVzKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIuYWRkTGFiZWxzKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBbCiAgICBwb2xpY3kuZmFpbGVkTGFiZWwKICBdKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIucmVtb3ZlTGFiZWwoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIsCiAgICBwb2xpY3kucnVubmluZ0xhYmVsCiAgKTsKICBhd2FpdCB1cHNlcnRTdGF0dXNDb21tZW50KAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgYnVpbGREcmFmdFByU3RhdHVzQ29tbWVudChpc3N1ZU51bWJlciwgImZhaWxlZCIsIHsgcmVhc29ucyB9KSwKICAgIGRlcGVuZGVuY2llcywKICAgIGJvdExvZ2luCiAgKTsKfQphc3luYyBmdW5jdGlvbiB0cmFuc2l0aW9uUHVsbFJlcXVlc3RPcGVuKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBwdWxsUmVxdWVzdFVybCwgZGVwZW5kZW5jaWVzKSB7CiAgY29uc3QgYm90TG9naW4gPSByZXF1aXJlZEJvdExvZ2luKGRlcGVuZGVuY2llcy5ib3RMb2dpbik7CiAgY29uc3QgcG9saWN5ID0gZGVwZW5kZW5jaWVzLnBvbGljeTsKICBhd2FpdCBlbnN1cmVXb3JrZmxvd0xhYmVscyhyZXBvc2l0b3J5LCBbcG9saWN5LnByT3BlbkxhYmVsXSwgZGVwZW5kZW5jaWVzKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIuYWRkTGFiZWxzKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBbCiAgICBwb2xpY3kucHJPcGVuTGFiZWwKICBdKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIucmVtb3ZlTGFiZWwoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIsCiAgICBwb2xpY3kucnVubmluZ0xhYmVsCiAgKTsKICBhd2FpdCB1cHNlcnRTdGF0dXNDb21tZW50KAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgYnVpbGREcmFmdFByU3RhdHVzQ29tbWVudChpc3N1ZU51bWJlciwgInByLW9wZW4iLCB7IHB1bGxSZXF1ZXN0VXJsIH0pLAogICAgZGVwZW5kZW5jaWVzLAogICAgYm90TG9naW4KICApOwp9CmFzeW5jIGZ1bmN0aW9uIGVuc3VyZVdvcmtmbG93TGFiZWxzKHJlcG9zaXRvcnksIGxhYmVscywgZGVwZW5kZW5jaWVzKSB7CiAgZm9yIChjb25zdCBsYWJlbCBvZiBsYWJlbHMpIHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy5wcm92aWRlci5lbnN1cmVMYWJlbCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgbGFiZWwsCiAgICAgIGRlcGVuZGVuY2llcy5wb2xpY3kubGFiZWxDb2xvcnNbbGFiZWxdID8/ICJlZGVkZWQiCiAgICApOwogIH0KfQphc3luYyBmdW5jdGlvbiB1cHNlcnRTdGF0dXNDb21tZW50KHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBib2R5LCBkZXBlbmRlbmNpZXMsIGJvdExvZ2luKSB7CiAgY29uc3QgY29tbWVudHMgPSBhd2FpdCBkZXBlbmRlbmNpZXMucHJvdmlkZXIubGlzdENvbW1lbnRzKAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyCiAgKTsKICBjb25zdCBleGlzdGluZyA9IGZpbmREcmFmdFByQ29tbWVudChjb21tZW50cywgYm90TG9naW4pOwogIGlmIChleGlzdGluZykgewogICAgYXdhaXQgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLnVwZGF0ZUNvbW1lbnQoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGlzc3VlTnVtYmVyLAogICAgICBleGlzdGluZy5pZCwKICAgICAgYm9keQogICAgKTsKICB9IGVsc2UgewogICAgYXdhaXQgZGVwZW5kZW5jaWVzLnByb3ZpZGVyLmNyZWF0ZUNvbW1lbnQocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIGJvZHkpOwogIH0KfQpmdW5jdGlvbiBzZWxlY3RDb250ZXh0Q29tbWVudHMoY29tbWVudHMsIGJvdExvZ2luKSB7CiAgY29uc3QgZXhwZWN0ZWRCb3QgPSBib3RMb2dpbj8udHJpbSgpLnRvTG93ZXJDYXNlKCk7CiAgcmV0dXJuIGNvbW1lbnRzLmZpbHRlcigoY29tbWVudCkgPT4gewogICAgY29uc3QgbWFuYWdlZEJvdCA9IGV4cGVjdGVkQm90ICYmIGNvbW1lbnQudXNlcj8ubG9naW4udHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09IGV4cGVjdGVkQm90OwogICAgcmV0dXJuICEobWFuYWdlZEJvdCAmJiAoY29tbWVudC5ib2R5LnN0YXJ0c1dpdGgoRFJBRlRfUFJfQ09NTUVOVF9QUkVGSVgpIHx8IGlzSXNzdWVUcmlhZ2VDb21tZW50KGNvbW1lbnQuYm9keSkpKTsKICB9KS5zb3J0KChsZWZ0LCByaWdodCkgPT4gbGVmdC5pZCAtIHJpZ2h0LmlkKS5zbGljZSgtNTApLm1hcCgoY29tbWVudCkgPT4gKHsKICAgIC4uLmNvbW1lbnQsCiAgICBib2R5OiB0cnVuY2F0ZVRleHQoY29tbWVudC5ib2R5LCA0ZTMpCiAgfSkpOwp9CmZ1bmN0aW9uIHZhbGlkYXRlSW1wbGVtZW50ZWRBbmFseXNpcyhhbmFseXNpcywgaW5zcGVjdGlvbikgewogIGlmICghc2FuaXRpemVUaXRsZShhbmFseXNpcy5wclRpdGxlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJpbXBsZW1lbnRlZCByZXN1bHQgcmVxdWlyZXMgYSBQdWxsIFJlcXVlc3QgdGl0bGUiKTsKICB9CiAgaWYgKGluc3BlY3Rpb24uY2hhbmdlZEZpbGVzLmxlbmd0aCA9PT0gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAiaW1wbGVtZW50ZWQgcmVzdWx0IHJlcXVpcmVzIGEgbm9uLWVtcHR5IHJlcG9zaXRvcnkgY2hhbmdlIgogICAgKTsKICB9CiAgaWYgKCFpbnNwZWN0aW9uLmRpZmZDaGVja1Bhc3NlZCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJnaXQgZGlmZiAtLWNoZWNrIHJlamVjdGVkIHRoZSByZXBvc2l0b3J5IGNoYW5nZSIpOwogIH0KICBpZiAoaW5zcGVjdGlvbi5zZWNyZXRGaW5kaW5nUGF0aHMubGVuZ3RoID4gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICBgcG9zc2libGUgY3JlZGVudGlhbCBtYXRlcmlhbCBkZXRlY3RlZCBpbjogJHtpbnNwZWN0aW9uLnNlY3JldEZpbmRpbmdQYXRocy5qb2luKCIsICIpfWAKICAgICk7CiAgfQogIGlmIChhbmFseXNpcy52YWxpZGF0aW9uT3ZlcnJpZGUgJiYgIWhhc0NvbnNpc3RlbnRWYWxpZGF0aW9uT3ZlcnJpZGUoYW5hbHlzaXMpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJpbXBsZW1lbnRlZCByZXN1bHQgaGFzIGFuIGluY29uc2lzdGVudCB2YWxpZGF0aW9uIG92ZXJyaWRlIgogICAgKTsKICB9CiAgaWYgKGFuYWx5c2lzLnRlc3RzLnNvbWUoKHRlc3QpID0+IHRlc3Quc3RhdHVzID09PSAiZmFpbGVkIikgJiYgIWhhc0NvbnNpc3RlbnRWYWxpZGF0aW9uT3ZlcnJpZGUoYW5hbHlzaXMpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoImltcGxlbWVudGVkIHJlc3VsdCByZXBvcnRzIGEgZmFpbGVkIHZhbGlkYXRpb24gY29tbWFuZCIpOwogIH0KfQpmdW5jdGlvbiBvdXRjb21lUmVhc29ucyhhbmFseXNpcykgewogIHJldHVybiBbCiAgICAuLi5hbmFseXNpcy5yaXNrLnJlYXNvbnMsCiAgICAuLi5hbmFseXNpcy5ub3RlcywKICAgIC4uLmFuYWx5c2lzLnN1bW1hcnkKICBdLnNsaWNlKDAsIDgpOwp9CmZ1bmN0aW9uIGZhaWx1cmVSZWFzb25zKGFuYWx5c2lzKSB7CiAgY29uc3QgdmFsaWRhdGlvbkZhaWx1cmVzID0gYW5hbHlzaXMudGVzdHMuZmlsdGVyKCh0ZXN0KSA9PiB0ZXN0LnN0YXR1cyA9PT0gImZhaWxlZCIgfHwgdGVzdC5zdGF0dXMgPT09ICJub3RfcnVuIikubWFwKCh0ZXN0KSA9PiB7CiAgICBjb25zdCBwcmVmaXggPSB0ZXN0LnN0YXR1cyA9PT0gImZhaWxlZCIgPyAiVmFsaWRhdGlvbiBmYWlsZWQiIDogIlZhbGlkYXRpb24gbm90IHJ1biI7CiAgICByZXR1cm4gYCR7cHJlZml4fTogJHt0ZXN0LmNvbW1hbmR9JHt0ZXN0LmRldGFpbHMgPyBgIFx1MjAxNCAke3Rlc3QuZGV0YWlsc31gIDogIiJ9YDsKICB9KTsKICByZXR1cm4gWwogICAgLi4udmFsaWRhdGlvbkZhaWx1cmVzLAogICAgLi4uYW5hbHlzaXMucmlzay5yZWFzb25zLAogICAgLi4uYW5hbHlzaXMubm90ZXMsCiAgICAuLi5hbmFseXNpcy5zdW1tYXJ5CiAgXS5zbGljZSgwLCA4KTsKfQpmdW5jdGlvbiBidWlsZFB1bGxSZXF1ZXN0Qm9keShpc3N1ZU51bWJlciwgYW5hbHlzaXMpIHsKICBjb25zdCBsaW5lcyA9IFtgQ2xvc2VzICMke2lzc3VlTnVtYmVyfWAsICIiLCAiIyMgU3VtbWFyeSIsICIiXTsKICBmb3IgKGNvbnN0IGl0ZW0gb2YgYW5hbHlzaXMuc3VtbWFyeSkgbGluZXMucHVzaChgLSAke3Nhbml0aXplTGluZTIoaXRlbSl9YCk7CiAgbGluZXMucHVzaCgiIiwgIiMjIFZhbGlkYXRpb24iLCAiIik7CiAgaWYgKGFuYWx5c2lzLnRlc3RzLmxlbmd0aCA9PT0gMCkgewogICAgbGluZXMucHVzaCgiLSBOb3QgcmVwb3J0ZWQuIik7CiAgfSBlbHNlIHsKICAgIGZvciAoY29uc3QgdGVzdCBvZiBhbmFseXNpcy50ZXN0cykgewogICAgICBsaW5lcy5wdXNoKAogICAgICAgIGAtIFxgJHtzYW5pdGl6ZUNvZGUodGVzdC5jb21tYW5kKX1cYCBcdTIwMTQgJHt0ZXN0LnN0YXR1c30ke3Rlc3QuZGV0YWlscyA/IGA6ICR7c2FuaXRpemVMaW5lMih0ZXN0LmRldGFpbHMpfWAgOiAiIn1gCiAgICAgICk7CiAgICB9CiAgfQogIGlmIChhbmFseXNpcy52YWxpZGF0aW9uT3ZlcnJpZGUpIHsKICAgIGxpbmVzLnB1c2goCiAgICAgICIiLAogICAgICAiIyMgVmFsaWRhdGlvbiBvdmVycmlkZSIsCiAgICAgICIiLAogICAgICBgLSBDbGFzc2lmaWNhdGlvbjogXGAke2FuYWx5c2lzLnZhbGlkYXRpb25PdmVycmlkZS5jbGFzc2lmaWNhdGlvbn1cYGAsCiAgICAgIGAtIFNvdXJjZTogXGAke2FuYWx5c2lzLnZhbGlkYXRpb25PdmVycmlkZS5zb3VyY2V9XGBgLAogICAgICBgLSBSZWFzb246ICR7c2FuaXRpemVMaW5lMihhbmFseXNpcy52YWxpZGF0aW9uT3ZlcnJpZGUucmVhc29uKX1gCiAgICApOwogIH0KICBsaW5lcy5wdXNoKCIiLCAiIyMgUmlzayIsICIiLCBgLSBMZXZlbDogXGAke2FuYWx5c2lzLnJpc2subGV2ZWx9XGBgKTsKICBmb3IgKGNvbnN0IHJlYXNvbiBvZiBhbmFseXNpcy5yaXNrLnJlYXNvbnMpIHsKICAgIGxpbmVzLnB1c2goYC0gJHtzYW5pdGl6ZUxpbmUyKHJlYXNvbil9YCk7CiAgfQogIGlmIChhbmFseXNpcy5ub3Rlcy5sZW5ndGggPiAwKSB7CiAgICBsaW5lcy5wdXNoKCIiLCAiIyMgTm90ZXMiLCAiIik7CiAgICBmb3IgKGNvbnN0IG5vdGUgb2YgYW5hbHlzaXMubm90ZXMpIGxpbmVzLnB1c2goYC0gJHtzYW5pdGl6ZUxpbmUyKG5vdGUpfWApOwogIH0KICBsaW5lcy5wdXNoKAogICAgIiIsCiAgICAiX1ByZXBhcmVkIGJ5IHRoZSByZXBvc2l0b3J5IGRldmVsb3BtZW50IEFnZW50IGFuZCBvcGVuZWQgYXMgYSBEcmFmdCBQdWxsIFJlcXVlc3QgZm9yIG1haW50YWluZXIgcmV2aWV3Ll8iCiAgKTsKICByZXR1cm4gbGluZXMuam9pbigiXG4iKTsKfQpmdW5jdGlvbiBzYW5pdGl6ZUxpbmUyKHZhbHVlKSB7CiAgcmV0dXJuIHZhbHVlLnJlcGxhY2UoLzwhLS1bXHNcU10qPy0tPi9nLCAiIikucmVwbGFjZSgvW1xyXG5dKy9nLCAiICIpLnJlcGxhY2UoL1xzKy9nLCAiICIpLnRyaW0oKS5zbGljZSgwLCA1MDApOwp9CmZ1bmN0aW9uIHNhbml0aXplQ29kZSh2YWx1ZSkgewogIHJldHVybiBzYW5pdGl6ZUxpbmUyKHZhbHVlKS5yZXBsYWNlKC9gL2csICInIik7Cn0KZnVuY3Rpb24gcmVxdWlyZWRCb3RMb2dpbih2YWx1ZSkgewogIGNvbnN0IG5vcm1hbGl6ZWQgPSB2YWx1ZT8udHJpbSgpOwogIGlmICghbm9ybWFsaXplZCkKICAgIHRocm93IG5ldyBFcnJvcigiRHJhZnQgUFIgYm90IGxvZ2luIGlzIHJlcXVpcmVkIGluIGFwcGx5IG1vZGUiKTsKICByZXR1cm4gbm9ybWFsaXplZDsKfQoKLy8gc3JjL2RyYWZ0LXByL21haW4udHMKYXN5bmMgZnVuY3Rpb24gbWFpbigpIHsKICBjb25zdCBvcHRpb25zID0gcGFyc2VBcmd1bWVudHMocHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTsKICBjb25zdCBhcHBseSA9IGVudkJvb2xlYW4ocHJvY2Vzcy5lbnYuRFJBRlRfUFJfQVBQTFkpOwogIGNvbnN0IGFsbG93ZWRSZXBvc2l0b3J5ID0gcHJvY2Vzcy5lbnYuRFJBRlRfUFJfQUxMT1dFRF9SRVBPU0lUT1JZPy50cmltKCkgfHwgcHJvY2Vzcy5lbnYuR0lUSFVCX0FMTE9XRURfUkVQT1NJVE9SWT8udHJpbSgpIHx8ICIiOwogIGlmIChbInByZXBhcmUiLCAiaW5zcGVjdC12YWxpZGF0aW9uIiwgImFwcGx5IiwgImZhaWwiXS5pbmNsdWRlcyhvcHRpb25zLmNvbW1hbmQpKSB7CiAgICBhc3NlcnRCb3VuZERyYWZ0UHJUYXJnZXQoCiAgICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgICAgb3B0aW9ucy5pc3N1ZU51bWJlciwKICAgICAgYXBwbHksCiAgICAgIHByb2Nlc3MuZW52CiAgICApOwogIH0gZWxzZSB7CiAgICBhc3NlcnRCb3VuZFJldmlld1RhcmdldCgKICAgICAgb3B0aW9ucy5yZXBvc2l0b3J5LAogICAgICBvcHRpb25zLnB1bGxSZXF1ZXN0TnVtYmVyLAogICAgICBhcHBseSwKICAgICAgcHJvY2Vzcy5lbnYKICAgICk7CiAgfQogIGlmIChvcHRpb25zLmNvbW1hbmQgPT09ICJpbnNwZWN0LXZhbGlkYXRpb24iKSB7CiAgICBhc3NlcnRBbGxvd2VkUmVwb3NpdG9yeShvcHRpb25zLnJlcG9zaXRvcnksIGFsbG93ZWRSZXBvc2l0b3J5KTsKICAgIGNvbnN0IHJlc3VsdDIgPSBhd2FpdCBmaW5nZXJwcmludERyYWZ0UHJXb3Jrc3BhY2UoCiAgICAgIHByb2Nlc3MuZW52LkRSQUZUX1BSX1dPUktTUEFDRV9ST09UPy50cmltKCkgfHwgIi9kcmFmdC1wci13b3Jrc3BhY2VzIiwKICAgICAgb3B0aW9ucy53b3Jrc3BhY2VQYXRoCiAgICApOwogICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkocmVzdWx0MiwgbnVsbCwgMil9CmApOwogICAgcmV0dXJuOwogIH0KICBjb25zdCBwb2xpY3kgPSBhd2FpdCBsb2FkUG9saWN5KCk7CiAgY29uc3QgdG9rZW4gPSBhd2FpdCByZXNvbHZlR2l0SHViVG9rZW4ob3B0aW9ucy5yZXBvc2l0b3J5KTsKICBjb25zdCBwcm92aWRlciA9IG5ldyBHaXRIdWJDbGllbnQoewogICAgLi4udG9rZW4gPyB7IHRva2VuIH0gOiB7fSwKICAgIC4uLnByb2Nlc3MuZW52LkdJVEhVQl9BUElfVVJMID8geyBiYXNlVXJsOiBwcm9jZXNzLmVudi5HSVRIVUJfQVBJX1VSTCB9IDoge30KICB9KTsKICBjb25zdCB3b3Jrc3BhY2UgPSBuZXcgR2l0RHJhZnRQcldvcmtzcGFjZSh7CiAgICByb290OiBwcm9jZXNzLmVudi5EUkFGVF9QUl9XT1JLU1BBQ0VfUk9PVD8udHJpbSgpIHx8ICIvZHJhZnQtcHItd29ya3NwYWNlcyIsCiAgICB0b2tlbiwKICAgIGF1dGhvck5hbWU6IHByb2Nlc3MuZW52LkRSQUZUX1BSX0dJVF9BVVRIT1JfTkFNRT8udHJpbSgpIHx8ICJlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MiLAogICAgYXV0aG9yRW1haWw6IHByb2Nlc3MuZW52LkRSQUZUX1BSX0dJVF9BVVRIT1JfRU1BSUw/LnRyaW0oKSB8fCAiZW5naW5lZXJpbmctYWdlbnQtd29ya2Zsb3dzQHVzZXJzLm5vcmVwbHkuZ2l0aHViLmNvbSIsCiAgICAuLi5wcm9jZXNzLmVudi5EUkFGVF9QUl9HSVRfQ1VSTF9SRVNPTFZFID8geyBnaXRDdXJsUmVzb2x2ZTogcHJvY2Vzcy5lbnYuRFJBRlRfUFJfR0lUX0NVUkxfUkVTT0xWRSB9IDoge30KICB9KTsKICBjb25zdCBkZXBlbmRlbmNpZXMgPSB7CiAgICBwcm92aWRlciwKICAgIHdvcmtzcGFjZSwKICAgIHBvbGljeSwKICAgIGFsbG93ZWRSZXBvc2l0b3J5LAogICAgc2VydmVyVXJsOiBwcm9jZXNzLmVudi5HSVRIVUJfU0VSVkVSX1VSTD8udHJpbSgpIHx8ICJodHRwczovL2dpdGh1Yi5jb20iLAogICAgYXBwbHksCiAgICAuLi5wcm9jZXNzLmVudi5HSVRIVUJfQk9UX0xPR0lOID8geyBib3RMb2dpbjogcHJvY2Vzcy5lbnYuR0lUSFVCX0JPVF9MT0dJTiB9IDoge30KICB9OwogIGNvbnN0IHJlc3VsdCA9IG9wdGlvbnMuY29tbWFuZCA9PT0gInByZXBhcmUiID8gYXdhaXQgcHJlcGFyZURyYWZ0UHIoCiAgICBvcHRpb25zLnJlcG9zaXRvcnksCiAgICBvcHRpb25zLmlzc3VlTnVtYmVyLAogICAgb3B0aW9ucy50cmlnZ2VyLAogICAgZGVwZW5kZW5jaWVzCiAgKSA6IG9wdGlvbnMuY29tbWFuZCA9PT0gImFwcGx5IiA/IGF3YWl0IGFwcGx5RHJhZnRQcigKICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgIG9wdGlvbnMuaXNzdWVOdW1iZXIsCiAgICBKU09OLnBhcnNlKAogICAgICBhd2FpdCByZWFkRmlsZTIob3B0aW9ucy5hbmFseXNpc0ZpbGUsICJ1dGY4IikKICAgICksCiAgICBkZXBlbmRlbmNpZXMKICApIDogb3B0aW9ucy5jb21tYW5kID09PSAiZmFpbCIgPyBhd2FpdCBmYWlsRHJhZnRQcigKICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgIG9wdGlvbnMuaXNzdWVOdW1iZXIsCiAgICBvcHRpb25zLm1lc3NhZ2UgPz8gIkRyYWZ0IFBSIEFnZW50IGV4ZWN1dGlvbiBmYWlsZWQiLAogICAgZGVwZW5kZW5jaWVzCiAgKSA6IG9wdGlvbnMuY29tbWFuZCA9PT0gInByZXBhcmUtcmV2aWV3IiA/IGF3YWl0IHByZXBhcmVSZXZpZXdGaXgoCiAgICBvcHRpb25zLnJlcG9zaXRvcnksCiAgICBvcHRpb25zLnB1bGxSZXF1ZXN0TnVtYmVyLAogICAgb3B0aW9ucy5yZXZpZXdJZCwKICAgIGRlcGVuZGVuY2llcwogICkgOiBvcHRpb25zLmNvbW1hbmQgPT09ICJhcHBseS1yZXZpZXciID8gYXdhaXQgYXBwbHlSZXZpZXdGaXgoCiAgICBvcHRpb25zLnJlcG9zaXRvcnksCiAgICBvcHRpb25zLnB1bGxSZXF1ZXN0TnVtYmVyLAogICAgSlNPTi5wYXJzZSgKICAgICAgYXdhaXQgcmVhZEZpbGUyKG9wdGlvbnMuYW5hbHlzaXNGaWxlLCAidXRmOCIpCiAgICApLAogICAgZGVwZW5kZW5jaWVzCiAgKSA6IG9wdGlvbnMuY29tbWFuZCA9PT0gImZhaWwtcmV2aWV3IiA/IGF3YWl0IGZhaWxSZXZpZXdGaXgoCiAgICBvcHRpb25zLnJlcG9zaXRvcnksCiAgICBvcHRpb25zLnB1bGxSZXF1ZXN0TnVtYmVyLAogICAgb3B0aW9ucy5yZXZpZXdDdXJzb3IgPz8gMCwKICAgIG9wdGlvbnMuaXRlcmF0aW9ucyA/PyAwLAogICAgb3B0aW9ucy5oZWFkU2hhID8/ICIiLAogICAgZGVwZW5kZW5jaWVzCiAgKSA6IG9wdGlvbnMuY29tbWFuZCA9PT0gInByZXBhcmUtY2kiID8gYXdhaXQgcHJlcGFyZUNpRml4KAogICAgb3B0aW9ucy5yZXBvc2l0b3J5LAogICAgb3B0aW9ucy5wdWxsUmVxdWVzdE51bWJlciwKICAgIG9wdGlvbnMuaGVhZFNoYSA/PyAiIiwKICAgIG9wdGlvbnMuY2hlY2tTdWl0ZUlkID8/IDAsCiAgICBkZXBlbmRlbmNpZXMKICApIDogb3B0aW9ucy5jb21tYW5kID09PSAiYXBwbHktY2kiID8gYXdhaXQgYXBwbHlDaUZpeCgKICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgIG9wdGlvbnMucHVsbFJlcXVlc3ROdW1iZXIsCiAgICBKU09OLnBhcnNlKAogICAgICBhd2FpdCByZWFkRmlsZTIob3B0aW9ucy5hbmFseXNpc0ZpbGUsICJ1dGY4IikKICAgICksCiAgICBkZXBlbmRlbmNpZXMKICApIDogYXdhaXQgZmFpbENpRml4KAogICAgb3B0aW9ucy5yZXBvc2l0b3J5LAogICAgb3B0aW9ucy5wdWxsUmVxdWVzdE51bWJlciwKICAgIG9wdGlvbnMuY2hlY2tTdWl0ZUlkID8/IDAsCiAgICBvcHRpb25zLmF0dGVtcHRzID8/IDAsCiAgICBvcHRpb25zLmhlYWRTaGEgPz8gIiIsCiAgICBkZXBlbmRlbmNpZXMKICApOwogIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCwgbnVsbCwgMil9CmApOwp9CmFzeW5jIGZ1bmN0aW9uIGxvYWRQb2xpY3koKSB7CiAgY29uc3QgZW1iZWRkZWQgPSBwcm9jZXNzLmVudi5XT1JLRkxPV19QT0xJQ1lfSlNPTj8udHJpbSgpOwogIGlmIChlbWJlZGRlZCkgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIGRyYWZ0UHJQb2xpY3lTY2hlbWEucGFyc2UoSlNPTi5wYXJzZShlbWJlZGRlZCkpOwogICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAgIGBmYWlsZWQgdG8gbG9hZCBlbWJlZGRlZCBEcmFmdCBQUiBwb2xpY3k6ICR7ZXJyb3JNZXNzYWdlKGVycm9yKX1gCiAgICAgICk7CiAgICB9CiAgfQogIHJldHVybiBsb2FkSnNvbkZyb21DYW5kaWRhdGVzKAogICAgWwogICAgICBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoIi4uL3BvbGljeS5qc29uIiwgaW1wb3J0Lm1ldGEudXJsKSksCiAgICAgIHBhdGgyLnJlc29sdmUoImFnZW50cy9kcmFmdC1wci9wb2xpY3kuanNvbiIpCiAgICBdLAogICAgKHZhbHVlKSA9PiBkcmFmdFByUG9saWN5U2NoZW1hLnBhcnNlKHZhbHVlKSwKICAgICJmYWlsZWQgdG8gbG9hZCBEcmFmdCBQUiBwb2xpY3kiCiAgKTsKfQpmdW5jdGlvbiBwYXJzZUFyZ3VtZW50cyhhcmdzKSB7CiAgY29uc3QgY29tbWFuZCA9IGFyZ3Muc2hpZnQoKTsKICBpZiAoY29tbWFuZCAhPT0gInByZXBhcmUiICYmIGNvbW1hbmQgIT09ICJpbnNwZWN0LXZhbGlkYXRpb24iICYmIGNvbW1hbmQgIT09ICJhcHBseSIgJiYgY29tbWFuZCAhPT0gImZhaWwiICYmIGNvbW1hbmQgIT09ICJwcmVwYXJlLXJldmlldyIgJiYgY29tbWFuZCAhPT0gImFwcGx5LXJldmlldyIgJiYgY29tbWFuZCAhPT0gImZhaWwtcmV2aWV3IiAmJiBjb21tYW5kICE9PSAicHJlcGFyZS1jaSIgJiYgY29tbWFuZCAhPT0gImFwcGx5LWNpIiAmJiBjb21tYW5kICE9PSAiZmFpbC1jaSIpIHsKICAgIHRocm93IG5ldyBFcnJvcigiaW52YWxpZCBEcmFmdCBQUiB0b29sIGNvbW1hbmQiKTsKICB9CiAgbGV0IHJlcG9zaXRvcnkgPSAiIjsKICBsZXQgaXNzdWVOdW1iZXIgPSAwOwogIGxldCBwdWxsUmVxdWVzdE51bWJlciA9IDA7CiAgbGV0IHRyaWdnZXIgPSAiIjsKICBsZXQgYW5hbHlzaXNGaWxlID0gIiI7CiAgbGV0IG1lc3NhZ2UgPSAiIjsKICBsZXQgcmV2aWV3SWQgPSAwOwogIGxldCByZXZpZXdDdXJzb3IgPSAwOwogIGxldCBpdGVyYXRpb25zID0gMDsKICBsZXQgaGVhZFNoYSA9ICIiOwogIGxldCBjaGVja1N1aXRlSWQgPSAwOwogIGxldCBhdHRlbXB0cyA9IDA7CiAgbGV0IHdvcmtzcGFjZVBhdGggPSAiIjsKICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgYXJncy5sZW5ndGg7IGluZGV4ICs9IDEpIHsKICAgIGNvbnN0IGFyZ3VtZW50ID0gYXJnc1tpbmRleF07CiAgICBpZiAoYXJndW1lbnQgPT09ICItLXJlcG9zaXRvcnkiKSB7CiAgICAgIHJlcG9zaXRvcnkgPSByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0taXNzdWUiKSB7CiAgICAgIGlzc3VlTnVtYmVyID0gTnVtYmVyKHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCkpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0tcHVsbC1yZXF1ZXN0IikgewogICAgICBwdWxsUmVxdWVzdE51bWJlciA9IE51bWJlcigKICAgICAgICByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpCiAgICAgICk7CiAgICB9IGVsc2UgaWYgKGFyZ3VtZW50ID09PSAiLS10cmlnZ2VyIikgewogICAgICB0cmlnZ2VyID0gcmVxdWlyZWRBcmd1bWVudFZhbHVlKGFyZ3MsICsraW5kZXgsIGFyZ3VtZW50KTsKICAgIH0gZWxzZSBpZiAoYXJndW1lbnQgPT09ICItLWFuYWx5c2lzIikgewogICAgICBhbmFseXNpc0ZpbGUgPSByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0tbWVzc2FnZSIpIHsKICAgICAgbWVzc2FnZSA9IHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCk7CiAgICB9IGVsc2UgaWYgKGFyZ3VtZW50ID09PSAiLS1yZXZpZXciKSB7CiAgICAgIHJldmlld0lkID0gTnVtYmVyKHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCkpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0tcmV2aWV3LWN1cnNvciIpIHsKICAgICAgcmV2aWV3Q3Vyc29yID0gTnVtYmVyKHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCkpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0taXRlcmF0aW9ucyIpIHsKICAgICAgaXRlcmF0aW9ucyA9IE51bWJlcihyZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpKTsKICAgIH0gZWxzZSBpZiAoYXJndW1lbnQgPT09ICItLWhlYWQiKSB7CiAgICAgIGhlYWRTaGEgPSByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0tY2hlY2stc3VpdGUiKSB7CiAgICAgIGNoZWNrU3VpdGVJZCA9IE51bWJlcihyZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpKTsKICAgIH0gZWxzZSBpZiAoYXJndW1lbnQgPT09ICItLWF0dGVtcHRzIikgewogICAgICBhdHRlbXB0cyA9IE51bWJlcihyZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpKTsKICAgIH0gZWxzZSBpZiAoYXJndW1lbnQgPT09ICItLXdvcmtzcGFjZSIpIHsKICAgICAgd29ya3NwYWNlUGF0aCA9IHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCk7CiAgICB9IGVsc2UgewogICAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gYXJndW1lbnQ6ICR7YXJndW1lbnR9YCk7CiAgICB9CiAgfQogIGlmICghaXNSZXBvc2l0b3J5U2x1ZyhyZXBvc2l0b3J5KSkgewogICAgdGhyb3cgbmV3IEVycm9yKCItLXJlcG9zaXRvcnkgbXVzdCB1c2Ugb3duZXIvcmVwb3NpdG9yeSBmb3JtYXQiKTsKICB9CiAgaWYgKFsicHJlcGFyZSIsICJpbnNwZWN0LXZhbGlkYXRpb24iLCAiYXBwbHkiLCAiZmFpbCJdLmluY2x1ZGVzKGNvbW1hbmQpICYmICghTnVtYmVyLmlzU2FmZUludGVnZXIoaXNzdWVOdW1iZXIpIHx8IGlzc3VlTnVtYmVyIDw9IDApKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIi0taXNzdWUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIiKTsKICB9CiAgaWYgKFsKICAgICJwcmVwYXJlLXJldmlldyIsCiAgICAiYXBwbHktcmV2aWV3IiwKICAgICJmYWlsLXJldmlldyIsCiAgICAicHJlcGFyZS1jaSIsCiAgICAiYXBwbHktY2kiLAogICAgImZhaWwtY2kiCiAgXS5pbmNsdWRlcyhjb21tYW5kKSAmJiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKHB1bGxSZXF1ZXN0TnVtYmVyKSB8fCBwdWxsUmVxdWVzdE51bWJlciA8PSAwKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCItLXB1bGwtcmVxdWVzdCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciIpOwogIH0KICBpZiAoY29tbWFuZCA9PT0gInByZXBhcmUiICYmIHRyaWdnZXIgIT09ICJyZWFkeSIgJiYgdHJpZ2dlciAhPT0gImFwcHJvdmVkIikgewogICAgdGhyb3cgbmV3IEVycm9yKCJwcmVwYXJlIHJlcXVpcmVzIC0tdHJpZ2dlciByZWFkeSBvciBhcHByb3ZlZCIpOwogIH0KICBpZiAoY29tbWFuZCA9PT0gImluc3BlY3QtdmFsaWRhdGlvbiIgJiYgIXdvcmtzcGFjZVBhdGgpIHsKICAgIHRocm93IG5ldyBFcnJvcigiaW5zcGVjdC12YWxpZGF0aW9uIHJlcXVpcmVzIC0td29ya3NwYWNlIik7CiAgfQogIGlmIChjb21tYW5kID09PSAicHJlcGFyZS1yZXZpZXciICYmICghTnVtYmVyLmlzU2FmZUludGVnZXIocmV2aWV3SWQpIHx8IHJldmlld0lkIDw9IDApKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoInByZXBhcmUtcmV2aWV3IHJlcXVpcmVzIC0tcmV2aWV3Iik7CiAgfQogIGlmICgoY29tbWFuZCA9PT0gImFwcGx5IiB8fCBjb21tYW5kID09PSAiYXBwbHktcmV2aWV3IiB8fCBjb21tYW5kID09PSAiYXBwbHktY2kiKSAmJiAhYW5hbHlzaXNGaWxlKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7Y29tbWFuZH0gcmVxdWlyZXMgLS1hbmFseXNpc2ApOwogIH0KICByZXR1cm4gewogICAgY29tbWFuZCwKICAgIHJlcG9zaXRvcnksCiAgICAuLi5pc3N1ZU51bWJlciA/IHsgaXNzdWVOdW1iZXIgfSA6IHt9LAogICAgLi4ucHVsbFJlcXVlc3ROdW1iZXIgPyB7IHB1bGxSZXF1ZXN0TnVtYmVyIH0gOiB7fSwKICAgIC4uLnRyaWdnZXIgPT09ICJyZWFkeSIgfHwgdHJpZ2dlciA9PT0gImFwcHJvdmVkIiA/IHsgdHJpZ2dlciB9IDoge30sCiAgICAuLi5hbmFseXNpc0ZpbGUgPyB7IGFuYWx5c2lzRmlsZSB9IDoge30sCiAgICAuLi5tZXNzYWdlID8geyBtZXNzYWdlIH0gOiB7fSwKICAgIC4uLnJldmlld0lkID8geyByZXZpZXdJZCB9IDoge30sCiAgICAuLi5yZXZpZXdDdXJzb3IgPyB7IHJldmlld0N1cnNvciB9IDoge30sCiAgICAuLi5pdGVyYXRpb25zID8geyBpdGVyYXRpb25zIH0gOiB7fSwKICAgIC4uLmhlYWRTaGEgPyB7IGhlYWRTaGEgfSA6IHt9LAogICAgLi4uTnVtYmVyLmlzU2FmZUludGVnZXIoY2hlY2tTdWl0ZUlkKSAmJiBjaGVja1N1aXRlSWQgPiAwID8geyBjaGVja1N1aXRlSWQgfSA6IHt9LAogICAgLi4uTnVtYmVyLmlzU2FmZUludGVnZXIoYXR0ZW1wdHMpICYmIGF0dGVtcHRzID49IDAgPyB7IGF0dGVtcHRzIH0gOiB7fSwKICAgIC4uLndvcmtzcGFjZVBhdGggPyB7IHdvcmtzcGFjZVBhdGggfSA6IHt9CiAgfTsKfQptYWluKCkuY2F0Y2goKGVycm9yKSA9PiB7CiAgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYGRyYWZ0LXByIGZhaWxlZDogJHtlcnJvck1lc3NhZ2UoZXJyb3IpfQpgKTsKICBwcm9jZXNzLmV4aXRDb2RlID0gMTsKfSk7Cg=="; const WORKFLOW_POLICY_JSON = "{\"version\":1,\"readyLabel\":\"agent:ready\",\"approvedLabel\":\"agent:approved\",\"runningLabel\":\"agent:running\",\"needsApprovalLabel\":\"agent:needs-approval\",\"prOpenLabel\":\"agent:pr-open\",\"failedLabel\":\"agent:failed\",\"skipLabels\":[\"skip-triage\"],\"blockedLabels\":[\"duplicate\",\"agent:pr-open\",\"agent:running\"],\"branchPrefix\":\"codex/issue-\",\"maxChangedFiles\":40,\"maxChangedLines\":1500,\"maxReviewComments\":50,\"maxValidationFixIterations\":2,\"maxFixIterations\":3,\"requiredValidationGates\":[\"task-prepare\",\"task-lint\",\"task-test-unit\"],\"allowedValidationFailureCases\":[\"TestConfigStoreCRUDCoverageWorkflows\",\"TestIntegrationConfigStoreCRUDCoverageWorkflows\",\"TestE2EConfigStoreCRUDCoverageWorkflows\",\"runtime command execution > injects runtime path environment into user commands\"],\"approvalPathPrefixes\":[\".github/workflows/\",\"migrations/\",\"db/migrations/\",\"database/migrations/\",\"pkg/auth/\",\"src/auth/\",\"security/\",\"deploy/\",\"release/\"],\"labelColors\":{\"agent:ready\":\"1d76db\",\"agent:approved\":\"0e8a16\",\"agent:running\":\"fbca04\",\"agent:needs-approval\":\"d93f0b\",\"agent:pr-open\":\"5319e7\",\"agent:failed\":\"b60205\"}}"; -const WORKFLOW_TOOL_CHUNK_SIZE = 60000; +const WORKFLOW_TOOL_PATH = + "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"; const WORKSPACE_VOLUME = { type: "bind", source: "./.draft-pr-workspaces", @@ -14,19 +14,6 @@ const WORKSPACE_VOLUME = { readOnly: false, }; -function workflowToolEnvironment() { - const env = {}; - for ( - let offset = 0, index = 0; - offset < WORKFLOW_TOOL_BASE64.length; - offset += WORKFLOW_TOOL_CHUNK_SIZE, index += 1 - ) { - env[`WORKFLOW_TOOL_CHUNK_${String(index).padStart(4, "0")}`] = - WORKFLOW_TOOL_BASE64.slice(offset, offset + WORKFLOW_TOOL_CHUNK_SIZE); - } - return env; -} - function agentWorkspaceVolume(workspacePath) { const prefix = "/draft-pr-workspaces/repositories/"; if ( @@ -303,17 +290,12 @@ function validateAgentWorkspaceWithRetry(workspacePath) { function runDeterministicTool(script, env, label) { const result = scheduler.shell( - [ - "set -eu", - 'workflow_tool_dir="$(mktemp -d)"', - 'workflow_tool="$workflow_tool_dir/draft-pr.mjs"', - 'node -e \'const fs=require("node:fs"); const source=Object.keys(process.env).filter((key)=>key.startsWith("WORKFLOW_TOOL_CHUNK_")).sort().map((key)=>process.env[key]).join(""); fs.writeFileSync(process.argv[1], Buffer.from(source, "base64"))\' "$workflow_tool"', - 'export DRAFT_PR_TOOL="$workflow_tool"', - script, - ].join("\n"), + ["set -eu", `export DRAFT_PR_TOOL="${WORKFLOW_TOOL_PATH}"`, script].join( + "\n", + ), { sandboxPolicy: "new", - env: { ...env, WORKFLOW_POLICY_JSON, ...workflowToolEnvironment() }, + env: { ...env, WORKFLOW_POLICY_JSON }, volumes: [WORKSPACE_VOLUME], maxOutputBytes: 4 * 1024 * 1024, }, diff --git a/agents/draft-pr/tool/main.mjs b/agents/draft-pr/tool/main.mjs new file mode 100644 index 0000000..00ad31a --- /dev/null +++ b/agents/draft-pr/tool/main.mjs @@ -0,0 +1,7957 @@ +// Generated by scripts/build-tools.ts. Do not edit directly. +var __defProp = Object.defineProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; + +// src/draft-pr/main.ts +import { readFile as readFile2 } from "node:fs/promises"; +import path2 from "node:path"; +import { fileURLToPath } from "node:url"; + +// src/github/app-auth.ts +import { sign } from "node:crypto"; + +// src/github/fetch-retry.ts +var MAX_ATTEMPTS = 3; +var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([502, 503, 504]); +async function fetchWithRetry(options) { + const attempts = options.retryable ? MAX_ATTEMPTS : 1; + let lastError; + for (let attempt = 1; attempt <= attempts; attempt += 1) { + try { + const response = await options.request(options.input, options.init); + if (attempt === attempts || !RETRYABLE_STATUS_CODES.has(response.status)) { + return response; + } + await response.body?.cancel().catch(() => void 0); + } catch (error) { + lastError = error; + if (attempt === attempts) { + throw new Error( + `${options.operation} transport failed after ${attemptLabel(attempts)}`, + { cause: error } + ); + } + } + await (options.sleep ?? sleep)(retryDelayMilliseconds(attempt)); + } + throw new Error(`${options.operation} transport failed`, { + cause: lastError + }); +} +function attemptLabel(attempts) { + return `${attempts} ${attempts === 1 ? "attempt" : "attempts"}`; +} +function retryDelayMilliseconds(attempt) { + const exponential = 250 * 2 ** (attempt - 1); + return exponential + Math.floor(Math.random() * exponential); +} +function sleep(milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} + +// src/github/app-auth.ts +var DEFAULT_GITHUB_API_URL = "https://api.github.com"; +var GITHUB_API_VERSION = "2022-11-28"; +async function resolveGitHubToken(repository, env = process.env, dependencies = {}) { + const configuredToken = env.GITHUB_TOKEN?.trim() ?? ""; + if (configuredToken) return configuredToken; + const clientID = env.GITHUB_APP_CLIENT_ID?.trim() ?? ""; + const appID = env.GITHUB_APP_ID?.trim() ?? ""; + const privateKeyBase64 = env.GITHUB_APP_PRIVATE_KEY_BASE64?.trim() ?? ""; + const configuredInstallationID = env.GITHUB_APP_INSTALLATION_ID?.trim() ?? ""; + const hasAppConfiguration = Boolean( + clientID || appID || privateKeyBase64 || configuredInstallationID + ); + if (!hasAppConfiguration) return ""; + const issuer = clientID || appID; + if (!issuer) { + throw new Error( + "GitHub App authentication requires GITHUB_APP_CLIENT_ID or GITHUB_APP_ID" + ); + } + if (!privateKeyBase64) { + throw new Error( + "GitHub App authentication requires GITHUB_APP_PRIVATE_KEY_BASE64" + ); + } + const privateKey = decodePrivateKey(privateKeyBase64); + const jwt = createAppJWT( + issuer, + privateKey, + dependencies.now?.() ?? Date.now() + ); + const baseUrl = (env.GITHUB_API_URL?.trim() || DEFAULT_GITHUB_API_URL).replace(/\/+$/, ""); + const request = dependencies.fetch ?? fetch; + const installationID = configuredInstallationID ? validateInstallationID(configuredInstallationID) : await findInstallationID( + baseUrl, + repository, + jwt, + request, + dependencies.sleep + ); + const tokenPath = `/app/installations/${installationID}/access_tokens`; + const response = await fetchWithRetry({ + request, + input: `${baseUrl}${tokenPath}`, + init: { + method: "POST", + headers: appHeaders(jwt) + }, + operation: `GitHub App POST ${tokenPath}`, + retryable: true, + ...dependencies.sleep ? { sleep: dependencies.sleep } : {} + }); + if (!response.ok) { + throw githubAppResponseError("installation token request", response); + } + const value = await response.json(); + const token = value.token?.trim() ?? ""; + if (!token) { + throw new Error("GitHub App installation token response has no token"); + } + return token; +} +function createAppJWT(issuer, privateKey, nowMilliseconds) { + const now = Math.floor(nowMilliseconds / 1e3); + const header = encodeJWTPart({ alg: "RS256", typ: "JWT" }); + const payload = encodeJWTPart({ + iat: now - 60, + exp: now + 9 * 60, + iss: issuer + }); + const unsignedToken = `${header}.${payload}`; + let signature; + try { + signature = sign("RSA-SHA256", Buffer.from(unsignedToken), privateKey); + } catch { + throw new Error( + "GITHUB_APP_PRIVATE_KEY_BASE64 is not a valid RSA private key" + ); + } + return `${unsignedToken}.${signature.toString("base64url")}`; +} +async function findInstallationID(baseUrl, repository, jwt, request, sleepDependency) { + const path3 = `/repos/${repositoryPath(repository)}/installation`; + const response = await fetchWithRetry({ + request, + input: `${baseUrl}${path3}`, + init: { + method: "GET", + headers: appHeaders(jwt) + }, + operation: `GitHub App GET ${path3}`, + retryable: true, + ...sleepDependency ? { sleep: sleepDependency } : {} + }); + if (!response.ok) { + throw githubAppResponseError("installation lookup", response); + } + const value = await response.json(); + if (!Number.isSafeInteger(value.id) || (value.id ?? 0) <= 0) { + throw new Error("GitHub App installation response has no valid ID"); + } + return String(value.id); +} +function appHeaders(jwt) { + return { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${jwt}`, + "X-GitHub-Api-Version": GITHUB_API_VERSION, + "User-Agent": "engineering-agent-workflows/github-app-auth" + }; +} +function decodePrivateKey(value) { + let decoded; + try { + decoded = Buffer.from(value, "base64").toString("utf8").trim(); + } catch { + throw new Error("GITHUB_APP_PRIVATE_KEY_BASE64 is not valid base64"); + } + if (!/^-----BEGIN (?:RSA )?PRIVATE KEY-----/.test(decoded)) { + throw new Error( + "GITHUB_APP_PRIVATE_KEY_BASE64 must decode to a PEM private key" + ); + } + return decoded; +} +function validateInstallationID(value) { + if (!/^[1-9][0-9]*$/.test(value)) { + throw new Error("GITHUB_APP_INSTALLATION_ID must be a positive integer"); + } + return value; +} +function repositoryPath(repository) { + const parts = repository.split("/"); + if (parts.length !== 2 || parts.some((part) => !part.trim())) { + throw new Error(`invalid GitHub repository: ${repository}`); + } + return parts.map(encodeURIComponent).join("/"); +} +function encodeJWTPart(value) { + return Buffer.from(JSON.stringify(value)).toString("base64url"); +} +function githubAppResponseError(operation, response) { + const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`; + return new Error(`GitHub App ${operation} failed with ${status}`); +} + +// src/issues/search.ts +function issueSearchText(title) { + return title.replace(/^\[[^\]]+\]\s*:?\s*/, "").replace(/["'`:+(){}[\]\\]/g, " ").replace(/\s+/g, " ").trim().slice(0, 120); +} + +// src/runtime/text.ts +function truncateText(value, max) { + return value.length <= max ? value : value.slice(0, max); +} + +// src/github/client.ts +var GitHubClient = class { + #token; + #baseUrl; + #fetch; + #sleep; + constructor(options = {}) { + this.#token = options.token?.trim() ?? ""; + this.#baseUrl = (options.baseUrl ?? "https://api.github.com").replace( + /\/+$/, + "" + ); + this.#fetch = options.fetch ?? fetch; + this.#sleep = options.sleep; + } + async getIssue(repository, issueNumber) { + const issue2 = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}` + ); + if (issue2.pull_request) { + throw new Error("GitHub pull request payload is not an Issue"); + } + return normalizeIssue(issue2); + } + async searchCandidates(repository, issue2, limit) { + const title = issueSearchText(issue2.title); + if (!title) return []; + const query = new URLSearchParams({ + q: `repo:${repository} is:issue in:title ${title}`, + per_page: String(Math.min(Math.max(limit + 1, 1), 100)) + }); + const response = await this.#request( + "GET", + `/search/issues?${query.toString()}` + ); + return (response.items ?? []).filter( + (candidate) => candidate.number !== issue2.number && !candidate.pull_request + ).slice(0, limit).map((candidate) => ({ + number: candidate.number, + title: candidate.title, + body: truncateText(candidate.body ?? "", 4e3), + state: candidate.state, + labels: labelNames(candidate.labels), + url: candidate.html_url + })); + } + async listComments(repository, issueNumber) { + const comments = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/comments?per_page=100&page=${page}` + ); + comments.push(...batch.map(normalizeComment)); + if (batch.length < 100) return comments; + } + } + async ensureLabel(repository, name, color, description) { + const path3 = `/repos/${repositoryPath2(repository)}/labels/${encodeURIComponent(name)}`; + const response = await this.#rawRequest("GET", path3); + if (response.ok) return; + if (response.status !== 404) { + throw await responseError("GET", path3, response); + } + await this.#request("POST", `/repos/${repositoryPath2(repository)}/labels`, { + name, + color: normalizeColor(color), + description: description?.trim() || "Managed by engineering-agent-workflows" + }); + } + async getRepositoryDefaultBranch(repository) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}` + ); + const branch = value.default_branch?.trim(); + if (!branch) throw new Error("GitHub repository has no default branch"); + return branch; + } + async getPullRequest(repository, pullRequestNumber) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}` + ); + return normalizePullRequest(value); + } + async listOpenPullRequests(repository) { + const values = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls?state=open&per_page=100&page=${page}` + ); + values.push(...batch.map(normalizePullRequest)); + if (batch.length < 100) return values; + } + } + async listReviewComments(repository, pullRequestNumber) { + const comments = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}/comments?per_page=100&page=${page}` + ); + comments.push(...batch.map(normalizeReviewComment)); + if (batch.length < 100) return comments; + } + } + async getPullRequestReview(repository, pullRequestNumber, reviewId) { + const review = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}/reviews/${reviewId}` + ); + return normalizePullRequestReview(review); + } + async listCheckRuns(repository, ref) { + if (!/^[0-9a-f]{40}$/.test(ref)) { + throw new Error("invalid GitHub check run ref"); + } + const runs = []; + for (let page = 1; ; page += 1) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/commits/${ref}/check-runs?per_page=100&page=${page}` + ); + const batch = value.check_runs ?? []; + runs.push(...batch.map(normalizeCheckRun)); + if (batch.length < 100) return runs; + } + } + async listCheckRunAnnotations(repository, checkRunId) { + if (!Number.isSafeInteger(checkRunId) || checkRunId <= 0) { + throw new Error("invalid GitHub check run ID"); + } + const annotations = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/check-runs/${checkRunId}/annotations?per_page=100&page=${page}` + ); + annotations.push(...batch.map(normalizeCheckRunAnnotation)); + if (batch.length < 100) return annotations; + } + } + async listOpenPullRequestsByHead(repository, branch) { + const owner = repository.split("/")[0]; + const query = new URLSearchParams({ + state: "open", + head: `${owner}:${branch}`, + per_page: "100" + }); + const values = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls?${query.toString()}` + ); + return values.map(normalizePullRequest); + } + async createDraftPullRequest(repository, input) { + const value = await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/pulls`, + { ...input, draft: true } + ); + return normalizePullRequest(value); + } + async addLabels(repository, issueNumber, labels) { + if (labels.length === 0) return; + await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/labels`, + { labels } + ); + } + async removeLabel(repository, issueNumber, label) { + const path3 = `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`; + const response = await this.#rawRequest("DELETE", path3); + if (!response.ok && response.status !== 404) { + throw await responseError("DELETE", path3, response); + } + } + async createComment(repository, issueNumber, body) { + const comment = await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/comments`, + { body } + ); + return normalizeComment(comment); + } + async updateComment(repository, _issueNumber, commentID, body) { + const comment = await this.#request( + "PATCH", + `/repos/${repositoryPath2(repository)}/issues/comments/${commentID}`, + { body } + ); + return normalizeComment(comment); + } + async #request(method, path3, body) { + const response = await this.#rawRequest(method, path3, body); + if (!response.ok) throw await responseError(method, path3, response); + return await response.json(); + } + #rawRequest(method, path3, body) { + const headers = { + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "engineering-agent-workflows/issue-triage" + }; + if (this.#token) headers.Authorization = `Bearer ${this.#token}`; + if (body !== void 0) headers["Content-Type"] = "application/json"; + return fetchWithRetry({ + request: this.#fetch, + input: `${this.#baseUrl}${path3}`, + init: { + method, + headers, + ...body === void 0 ? {} : { body: JSON.stringify(body) } + }, + operation: `GitHub API ${method} ${path3}`, + retryable: method === "GET", + ...this.#sleep ? { sleep: this.#sleep } : {} + }); + } +}; +function repositoryPath2(repository) { + const parts = repository.split("/"); + if (parts.length !== 2 || parts.some((part) => !part.trim())) { + throw new Error(`invalid GitHub repository: ${repository}`); + } + return parts.map(encodeURIComponent).join("/"); +} +function normalizeIssue(issue2) { + return { + number: issue2.number, + title: issue2.title, + body: issue2.body, + state: issue2.state, + htmlUrl: issue2.html_url, + updatedAt: issue2.updated_at, + labels: labelNames(issue2.labels), + ...issue2.user ? { user: normalizeUser(issue2.user) } : {} + }; +} +function normalizeComment(comment) { + return { + id: comment.id, + body: comment.body, + ...comment.html_url ? { htmlUrl: comment.html_url } : {}, + ...comment.created_at ? { createdAt: comment.created_at } : {}, + ...comment.user ? { user: normalizeUser(comment.user) } : {} + }; +} +function normalizePullRequest(value) { + return { + number: value.number, + url: value.html_url, + state: value.state, + draft: value.draft ?? false, + head: value.head.ref, + ...value.head.sha ? { headSha: value.head.sha } : {}, + ...value.head.repo?.full_name ? { headRepository: value.head.repo.full_name } : {}, + base: value.base.ref + }; +} +function normalizeReviewComment(comment) { + return { + id: comment.id, + body: comment.body, + path: comment.path, + ...comment.user ? { user: normalizeUser(comment.user) } : {}, + ...comment.html_url ? { htmlUrl: comment.html_url } : {}, + ...comment.created_at ? { createdAt: comment.created_at } : {}, + ...comment.line != null ? { line: comment.line } : {}, + ...comment.original_line != null ? { originalLine: comment.original_line } : {}, + ...comment.start_line != null ? { startLine: comment.start_line } : {}, + ...comment.original_start_line != null ? { originalStartLine: comment.original_start_line } : {}, + ...comment.side ? { side: comment.side } : {}, + ...comment.start_side ? { startSide: comment.start_side } : {}, + ...comment.diff_hunk ? { diffHunk: comment.diff_hunk } : {}, + ...comment.commit_id ? { commitId: comment.commit_id } : {}, + ...comment.original_commit_id ? { originalCommitId: comment.original_commit_id } : {}, + ...comment.in_reply_to_id !== void 0 ? { inReplyToId: comment.in_reply_to_id } : {}, + ...comment.pull_request_review_id !== void 0 ? { pullRequestReviewId: comment.pull_request_review_id } : {} + }; +} +function normalizePullRequestReview(review) { + return { + id: review.id, + body: review.body ?? "", + state: review.state, + commitId: review.commit_id, + authorAssociation: review.author_association, + ...review.user ? { user: normalizeUser(review.user) } : {}, + ...review.html_url ? { htmlUrl: review.html_url } : {}, + ...review.submitted_at ? { submittedAt: review.submitted_at } : {} + }; +} +function normalizeCheckRun(value) { + const checkSuiteId = value.check_suite?.id; + if (!Number.isSafeInteger(checkSuiteId) || checkSuiteId <= 0) { + throw new Error(`GitHub check run ${value.id} has no valid check suite ID`); + } + return { + id: value.id, + checkSuiteId, + name: truncateText(value.name ?? "", 300), + status: value.status, + ...value.conclusion ? { conclusion: value.conclusion } : {}, + ...value.html_url ? { htmlUrl: value.html_url } : {}, + output: { + title: truncateText(value.output?.title ?? "", 1e3), + summary: truncateText(value.output?.summary ?? "", 8e3), + text: truncateText(value.output?.text ?? "", 8e3) + } + }; +} +function normalizeCheckRunAnnotation(value) { + return { + path: truncateText(value.path ?? "", 1e3), + startLine: value.start_line, + endLine: value.end_line, + level: truncateText(value.annotation_level ?? "", 50), + message: truncateText(value.message ?? "", 2e3), + ...value.title ? { title: truncateText(value.title, 500) } : {}, + ...value.raw_details ? { rawDetails: truncateText(value.raw_details, 4e3) } : {} + }; +} +function normalizeUser(user) { + return { + login: user.login, + ...user.id !== void 0 ? { id: user.id } : {}, + ...user.type ? { type: user.type } : {} + }; +} +function labelNames(labels) { + return labels.map((label) => typeof label === "string" ? label : label.name).filter((label) => label.trim() !== ""); +} +function normalizeColor(color) { + const normalized = color.trim().replace(/^#/, ""); + return /^[0-9a-f]{6}$/i.test(normalized) ? normalized : "ededed"; +} +async function responseError(method, path3, response) { + const text = await response.text().catch(() => ""); + return new Error( + `GitHub API ${method} ${path3} failed with HTTP ${response.status}: ${truncateText(text, 1e3)}` + ); +} + +// src/issues/types.ts +function isRepositorySlug(value) { + return /^[^/\s]+\/[^/\s]+$/.test(value); +} + +// src/runtime/cli.ts +function requiredArgumentValue(args, index, name) { + const value = args[index]?.trim(); + if (!value) throw new Error(`${name} requires a value`); + return value; +} +function envBoolean(value) { + return ["1", "true", "yes", "on"].includes(value?.trim().toLowerCase() ?? ""); +} + +// src/runtime/errors.ts +function errorMessage(error) { + return describeError(error, /* @__PURE__ */ new Set(), 0); +} +function describeError(error, seen, depth) { + if (!(error instanceof Error)) return String(error); + seen.add(error); + const code = errorCode(error); + const description = depth === 0 ? error.message : `${error.name}${code ? ` [${code}]` : ""}: ${error.message}`; + if (depth >= 4 || error.cause === void 0 || seen.has(error.cause)) { + return description; + } + return `${description}; cause: ${describeError(error.cause, seen, depth + 1)}`; +} +function errorCode(error) { + if (!("code" in error)) return ""; + const value = error.code; + return typeof value === "string" || typeof value === "number" ? String(value) : ""; +} + +// src/runtime/load-json.ts +import { readFile } from "node:fs/promises"; +async function loadJsonFromCandidates(candidates, parse3, failureMessage) { + let lastError; + for (const candidate of candidates) { + try { + return parse3(JSON.parse(await readFile(candidate, "utf8"))); + } catch (error) { + lastError = error; + } + } + throw new Error(`${failureMessage}: ${errorMessage(lastError)}`); +} + +// src/draft-pr/ci-tool.ts +import crypto3 from "node:crypto"; + +// src/draft-pr/ci-comment.ts +var CI_FIX_COMMENT_PREFIX = "$/ + ); + if (!match) return emptyCiFixState(); + return { + checkSuiteId: Number(match[1]), + attempts: Number(match[2]), + headSha: match[3] === "none" ? "" : match[3], + status: match[4] + }; +} +function buildCiFixComment(state) { + const marker = `${CI_FIX_COMMENT_PREFIX} suite=${state.checkSuiteId} attempts=${state.attempts} head=${state.headSha || "none"} status=${state.status} -->`; + const messages = { + fixing: "The Draft PR Agent is validating the latest failed CI checks.", + fixed: "The Draft PR Agent pushed a validated fix for the failed CI checks.", + "no-change": "The Draft PR Agent inspected the failed CI checks and made no code change.", + "needs-approval": "Automatic CI fixes paused for maintainer review.", + failed: "The Draft PR Agent could not complete the latest CI fix attempt." + }; + return [marker, "## CI follow-up", "", messages[state.status]].join("\n"); +} +function emptyCiFixState() { + return { + checkSuiteId: 0, + attempts: 0, + headSha: "", + status: "fixed" + }; +} + +// node_modules/zod/v4/core/core.js +var _a; +// @__NO_SIDE_EFFECTS__ +function $constructor(name, initializer3, params) { + function init(inst, def) { + if (!inst._zod) { + Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + } + if (inst._zod.traits.has(name)) { + return; + } + inst._zod.traits.add(name); + initializer3(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) { + inst[k] = proto[k].bind(inst); + } + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent { + } + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a3; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a3 = inst._zod).deferred ?? (_a3.deferred = []); + for (const fn of inst._zod.deferred) { + fn(); + } + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { + value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) + return true; + return inst?._zod?.traits?.has(name); + } + }); + Object.defineProperty(_, "name", { value: name }); + return _; +} +var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } +}; +var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } +}; +(_a = globalThis).__zod_globalConfig ?? (_a.__zod_globalConfig = {}); +var globalConfig = globalThis.__zod_globalConfig; +function config(newConfig) { + if (newConfig) + Object.assign(globalConfig, newConfig); + return globalConfig; +} + +// node_modules/zod/v4/core/util.js +var util_exports = {}; +__export(util_exports, { + BIGINT_FORMAT_RANGES: () => BIGINT_FORMAT_RANGES, + Class: () => Class, + NUMBER_FORMAT_RANGES: () => NUMBER_FORMAT_RANGES, + aborted: () => aborted, + allowsEval: () => allowsEval, + assert: () => assert, + assertEqual: () => assertEqual, + assertIs: () => assertIs, + assertNever: () => assertNever, + assertNotEqual: () => assertNotEqual, + assignProp: () => assignProp, + base64ToUint8Array: () => base64ToUint8Array, + base64urlToUint8Array: () => base64urlToUint8Array, + cached: () => cached, + captureStackTrace: () => captureStackTrace, + cleanEnum: () => cleanEnum, + cleanRegex: () => cleanRegex, + clone: () => clone, + cloneDef: () => cloneDef, + createTransparentProxy: () => createTransparentProxy, + defineLazy: () => defineLazy, + esc: () => esc, + escapeRegex: () => escapeRegex, + explicitlyAborted: () => explicitlyAborted, + extend: () => extend, + finalizeIssue: () => finalizeIssue, + floatSafeRemainder: () => floatSafeRemainder, + getElementAtPath: () => getElementAtPath, + getEnumValues: () => getEnumValues, + getLengthableOrigin: () => getLengthableOrigin, + getParsedType: () => getParsedType, + getSizableOrigin: () => getSizableOrigin, + hexToUint8Array: () => hexToUint8Array, + isObject: () => isObject, + isPlainObject: () => isPlainObject, + issue: () => issue, + joinValues: () => joinValues, + jsonStringifyReplacer: () => jsonStringifyReplacer, + merge: () => merge, + mergeDefs: () => mergeDefs, + normalizeParams: () => normalizeParams, + nullish: () => nullish, + numKeys: () => numKeys, + objectClone: () => objectClone, + omit: () => omit, + optionalKeys: () => optionalKeys, + parsedType: () => parsedType, + partial: () => partial, + pick: () => pick, + prefixIssues: () => prefixIssues, + primitiveTypes: () => primitiveTypes, + promiseAllObject: () => promiseAllObject, + propertyKeyTypes: () => propertyKeyTypes, + randomString: () => randomString, + required: () => required, + safeExtend: () => safeExtend, + shallowClone: () => shallowClone, + slugify: () => slugify, + stringifyPrimitive: () => stringifyPrimitive, + uint8ArrayToBase64: () => uint8ArrayToBase64, + uint8ArrayToBase64url: () => uint8ArrayToBase64url, + uint8ArrayToHex: () => uint8ArrayToHex, + unwrapMessage: () => unwrapMessage +}); +function assertEqual(val) { + return val; +} +function assertNotEqual(val) { + return val; +} +function assertIs(_arg) { +} +function assertNever(_x) { + throw new Error("Unexpected value in exhaustive check"); +} +function assert(_) { +} +function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + return values; +} +function joinValues(array2, separator = "|") { + return array2.map((val) => stringifyPrimitive(val)).join(separator); +} +function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") + return value.toString(); + return value; +} +function cached(getter) { + const set = false; + return { + get value() { + if (!set) { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } + }; +} +function nullish(input) { + return input === null || input === void 0; +} +function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); +} +function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) + return 0; + return ratio - roundedRatio; +} +var EVALUATING = /* @__PURE__ */ Symbol("evaluating"); +function defineLazy(object2, key, getter) { + let value = void 0; + Object.defineProperty(object2, key, { + get() { + if (value === EVALUATING) { + return void 0; + } + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object2, key, { + value: v + // configurable: true, + }); + }, + configurable: true + }); +} +function objectClone(obj) { + return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); +} +function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); +} +function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) { + const descriptors = Object.getOwnPropertyDescriptors(def); + Object.assign(mergedDescriptors, descriptors); + } + return Object.defineProperties({}, mergedDescriptors); +} +function cloneDef(schema) { + return mergeDefs(schema._zod.def); +} +function getElementAtPath(obj, path3) { + if (!path3) + return obj; + return path3.reduce((acc, key) => acc?.[key], obj); +} +function promiseAllObject(promisesObj) { + const keys = Object.keys(promisesObj); + const promises = keys.map((key) => promisesObj[key]); + return Promise.all(promises).then((results) => { + const resolvedObj = {}; + for (let i = 0; i < keys.length; i++) { + resolvedObj[keys[i]] = results[i]; + } + return resolvedObj; + }); +} +function randomString(length = 10) { + const chars = "abcdefghijklmnopqrstuvwxyz"; + let str = ""; + for (let i = 0; i < length; i++) { + str += chars[Math.floor(Math.random() * chars.length)]; + } + return str; +} +function esc(str) { + return JSON.stringify(str); +} +function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); +} +var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => { +}; +function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); +} +var allowsEval = /* @__PURE__ */ cached(() => { + if (globalConfig.jitless) { + return false; + } + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) { + return false; + } + try { + const F = Function; + new F(""); + return true; + } catch (_) { + return false; + } +}); +function isPlainObject(o) { + if (isObject(o) === false) + return false; + const ctor = o.constructor; + if (ctor === void 0) + return true; + if (typeof ctor !== "function") + return true; + const prot = ctor.prototype; + if (isObject(prot) === false) + return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) { + return false; + } + return true; +} +function shallowClone(o) { + if (isPlainObject(o)) + return { ...o }; + if (Array.isArray(o)) + return [...o]; + if (o instanceof Map) + return new Map(o); + if (o instanceof Set) + return new Set(o); + return o; +} +function numKeys(data) { + let keyCount = 0; + for (const key in data) { + if (Object.prototype.hasOwnProperty.call(data, key)) { + keyCount++; + } + } + return keyCount; +} +var getParsedType = (data) => { + const t = typeof data; + switch (t) { + case "undefined": + return "undefined"; + case "string": + return "string"; + case "number": + return Number.isNaN(data) ? "nan" : "number"; + case "boolean": + return "boolean"; + case "function": + return "function"; + case "bigint": + return "bigint"; + case "symbol": + return "symbol"; + case "object": + if (Array.isArray(data)) { + return "array"; + } + if (data === null) { + return "null"; + } + if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { + return "promise"; + } + if (typeof Map !== "undefined" && data instanceof Map) { + return "map"; + } + if (typeof Set !== "undefined" && data instanceof Set) { + return "set"; + } + if (typeof Date !== "undefined" && data instanceof Date) { + return "date"; + } + if (typeof File !== "undefined" && data instanceof File) { + return "file"; + } + return "object"; + default: + throw new Error(`Unknown data type: ${t}`); + } +}; +var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]); +var primitiveTypes = /* @__PURE__ */ new Set([ + "string", + "number", + "bigint", + "boolean", + "symbol", + "undefined" +]); +function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} +function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) + cl._zod.parent = inst; + return cl; +} +function normalizeParams(_params) { + const params = _params; + if (!params) + return {}; + if (typeof params === "string") + return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) + throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") + return { ...params, error: () => params.error }; + return params; +} +function createTransparentProxy(getter) { + let target; + return new Proxy({}, { + get(_, prop, receiver) { + target ?? (target = getter()); + return Reflect.get(target, prop, receiver); + }, + set(_, prop, value, receiver) { + target ?? (target = getter()); + return Reflect.set(target, prop, value, receiver); + }, + has(_, prop) { + target ?? (target = getter()); + return Reflect.has(target, prop); + }, + deleteProperty(_, prop) { + target ?? (target = getter()); + return Reflect.deleteProperty(target, prop); + }, + ownKeys(_) { + target ?? (target = getter()); + return Reflect.ownKeys(target); + }, + getOwnPropertyDescriptor(_, prop) { + target ?? (target = getter()); + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + defineProperty(_, prop, descriptor) { + target ?? (target = getter()); + return Reflect.defineProperty(target, prop, descriptor); + } + }); +} +function stringifyPrimitive(value) { + if (typeof value === "bigint") + return value.toString() + "n"; + if (typeof value === "string") + return `"${value}"`; + return `${value}`; +} +function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); +} +var NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] +}; +var BIGINT_FORMAT_RANGES = { + int64: [/* @__PURE__ */ BigInt("-9223372036854775808"), /* @__PURE__ */ BigInt("9223372036854775807")], + uint64: [/* @__PURE__ */ BigInt(0), /* @__PURE__ */ BigInt("18446744073709551615")] +}; +function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".pick() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + }); + return clone(schema, def); +} +function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".omit() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + }); + return clone(schema, def); +} +function extend(schema, shape) { + if (!isPlainObject(shape)) { + throw new Error("Invalid input to extend: expected a plain object"); + } + const checks = schema._zod.def.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + const existingShape = schema._zod.def.shape; + for (const key in shape) { + if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) { + throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + } + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const _shape = { ...schema._zod.def.shape, ...shape }; + assignProp(this, "shape", _shape); + return _shape; + } + }); + return clone(schema, def); +} +function safeExtend(schema, shape) { + if (!isPlainObject(shape)) { + throw new Error("Invalid input to safeExtend: expected a plain object"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const _shape = { ...schema._zod.def.shape, ...shape }; + assignProp(this, "shape", _shape); + return _shape; + } + }); + return clone(schema, def); +} +function merge(a, b) { + if (a._zod.def.checks?.length) { + throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + } + const def = mergeDefs(a._zod.def, { + get shape() { + const _shape = { ...a._zod.def.shape, ...b._zod.def.shape }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + }); + return clone(a, def); +} +function partial(Class2, schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".partial() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in oldShape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + shape[key] = Class2 ? new Class2({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + } else { + for (const key in oldShape) { + shape[key] = Class2 ? new Class2({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + } + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + }); + return clone(schema, def); +} +function required(Class2, schema, mask) { + const def = mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + shape[key] = new Class2({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + } else { + for (const key in oldShape) { + shape[key] = new Class2({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + } + assignProp(this, "shape", shape); + return shape; + } + }); + return clone(schema, def); +} +function aborted(x, startIndex = 0) { + if (x.aborted === true) + return true; + for (let i = startIndex; i < x.issues.length; i++) { + if (x.issues[i]?.continue !== true) { + return true; + } + } + return false; +} +function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) + return true; + for (let i = startIndex; i < x.issues.length; i++) { + if (x.issues[i]?.continue === false) { + return true; + } + } + return false; +} +function prefixIssues(path3, issues) { + return issues.map((iss) => { + var _a3; + (_a3 = iss).path ?? (_a3.path = []); + iss.path.unshift(path3); + return iss; + }); +} +function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; +} +function finalizeIssue(iss, ctx, config2) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config2.customError?.(iss)) ?? unwrapMessage(config2.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) { + rest.input = _input; + } + return rest; +} +function getSizableOrigin(input) { + if (input instanceof Set) + return "set"; + if (input instanceof Map) + return "map"; + if (input instanceof File) + return "file"; + return "unknown"; +} +function getLengthableOrigin(input) { + if (Array.isArray(input)) + return "array"; + if (typeof input === "string") + return "string"; + return "unknown"; +} +function parsedType(data) { + const t = typeof data; + switch (t) { + case "number": { + return Number.isNaN(data) ? "nan" : "number"; + } + case "object": { + if (data === null) { + return "null"; + } + if (Array.isArray(data)) { + return "array"; + } + const obj = data; + if (obj && Object.getPrototypeOf(obj) !== Object.prototype && "constructor" in obj && obj.constructor) { + return obj.constructor.name; + } + } + } + return t; +} +function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") { + return { + message: iss, + code: "custom", + input, + inst + }; + } + return { ...iss }; +} +function cleanEnum(obj) { + return Object.entries(obj).filter(([k, _]) => { + return Number.isNaN(Number.parseInt(k, 10)); + }).map((el) => el[1]); +} +function base64ToUint8Array(base642) { + const binaryString = atob(base642); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; +} +function uint8ArrayToBase64(bytes) { + let binaryString = ""; + for (let i = 0; i < bytes.length; i++) { + binaryString += String.fromCharCode(bytes[i]); + } + return btoa(binaryString); +} +function base64urlToUint8Array(base64url2) { + const base642 = base64url2.replace(/-/g, "+").replace(/_/g, "/"); + const padding = "=".repeat((4 - base642.length % 4) % 4); + return base64ToUint8Array(base642 + padding); +} +function uint8ArrayToBase64url(bytes) { + return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +} +function hexToUint8Array(hex) { + const cleanHex = hex.replace(/^0x/, ""); + if (cleanHex.length % 2 !== 0) { + throw new Error("Invalid hex string length"); + } + const bytes = new Uint8Array(cleanHex.length / 2); + for (let i = 0; i < cleanHex.length; i += 2) { + bytes[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16); + } + return bytes; +} +function uint8ArrayToHex(bytes) { + return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join(""); +} +var Class = class { + constructor(..._args) { + } +}; + +// node_modules/zod/v4/core/errors.js +var initializer = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); +}; +var $ZodError = $constructor("$ZodError", initializer); +var $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error }); +function flattenError(error, mapper = (issue2) => issue2.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) { + if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else { + formErrors.push(mapper(sub)); + } + } + return { formErrors, fieldErrors }; +} +function formatError(error, mapper = (issue2) => issue2.message) { + const fieldErrors = { _errors: [] }; + const processError = (error2, path3 = []) => { + for (const issue2 of error2.issues) { + if (issue2.code === "invalid_union" && issue2.errors.length) { + issue2.errors.map((issues) => processError({ issues }, [...path3, ...issue2.path])); + } else if (issue2.code === "invalid_key") { + processError({ issues: issue2.issues }, [...path3, ...issue2.path]); + } else if (issue2.code === "invalid_element") { + processError({ issues: issue2.issues }, [...path3, ...issue2.path]); + } else { + const fullpath = [...path3, ...issue2.path]; + if (fullpath.length === 0) { + fieldErrors._errors.push(mapper(issue2)); + } else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + const terminal = i === fullpath.length - 1; + if (!terminal) { + curr[el] = curr[el] || { _errors: [] }; + } else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue2)); + } + curr = curr[el]; + i++; + } + } + } + } + }; + processError(error); + return fieldErrors; +} + +// node_modules/zod/v4/core/parse.js +var _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { ..._ctx, async: false } : { async: false }; + const result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) { + throw new $ZodAsyncError(); + } + if (result.issues.length) { + const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; +}; +var _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; + let result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) + result = await result; + if (result.issues.length) { + const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; +}; +var _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, async: false } : { async: false }; + const result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) { + throw new $ZodAsyncError(); + } + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { success: true, data: result.value }; +}; +var safeParse = /* @__PURE__ */ _safeParse($ZodRealError); +var _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; + let result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) + result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { success: true, data: result.value }; +}; +var safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError); +var _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); +}; +var _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); +}; +var _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); +}; +var _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); +}; +var _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); +}; +var _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); +}; +var _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); +}; +var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); +}; + +// node_modules/zod/v4/core/regexes.js +var cuid = /^[cC][0-9a-z]{6,}$/; +var cuid2 = /^[0-9a-z]+$/; +var ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; +var xid = /^[0-9a-vA-V]{20}$/; +var ksuid = /^[A-Za-z0-9]{27}$/; +var nanoid = /^[a-zA-Z0-9_-]{21}$/; +var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; +var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; +var uuid = (version2) => { + if (!version2) + return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); +}; +var email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; +var _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; +function emoji() { + return new RegExp(_emoji, "u"); +} +var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; +var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; +var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; +var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; +var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; +var base64url = /^[A-Za-z0-9_-]*$/; +var httpProtocol = /^https?$/; +var e164 = /^\+[1-9]\d{6,14}$/; +var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; +var date = /* @__PURE__ */ new RegExp(`^${dateSource}$`); +function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + const regex = typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + return regex; +} +function time(args) { + return new RegExp(`^${timeSource(args)}$`); +} +function datetime(args) { + const time3 = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) + opts.push(""); + if (args.offset) + opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time3}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); +} +var string = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); +}; +var integer = /^-?\d+$/; +var number = /^-?\d+(?:\.\d+)?$/; +var lowercase = /^[^A-Z]*$/; +var uppercase = /^[^a-z]*$/; + +// node_modules/zod/v4/core/checks.js +var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => { + var _a3; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a3 = inst._zod).onattach ?? (_a3.onattach = []); +}); +var numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" +}; +var $ZodCheckLessThan = /* @__PURE__ */ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) { + if (def.inclusive) + bag.maximum = def.value; + else + bag.exclusiveMaximum = def.value; + } + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) { + return; + } + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckGreaterThan = /* @__PURE__ */ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) { + if (def.inclusive) + bag.minimum = def.value; + else + bag.exclusiveMinimum = def.value; + } + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) { + return; + } + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckMultipleOf = /* @__PURE__ */ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst2) => { + var _a3; + (_a3 = inst2._zod.bag).multipleOf ?? (_a3.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) + throw new Error("Cannot mix number and bigint in multiple_of check."); + const isMultiple = typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0; + if (isMultiple) + return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) + bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) { + payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + } else { + payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + } + return; + } + } + if (input < minimum) { + payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + } + if (input > maximum) { + payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const curr = inst2._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) + inst2._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length <= def.maximum) + return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const curr = inst2._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) + inst2._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length >= def.minimum) + return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) + return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { code: "too_big", maximum: def.length } : { code: "too_small", minimum: def.length }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckStringFormat = /* @__PURE__ */ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a3, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) + (_a3 = inst._zod).check ?? (_a3.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else + (_b = inst._zod).check ?? (_b.check = () => { + }); +}); +var $ZodCheckRegex = /* @__PURE__ */ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckLowerCase = /* @__PURE__ */ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); +}); +var $ZodCheckUpperCase = /* @__PURE__ */ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); +}); +var $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; +}); + +// node_modules/zod/v4/core/doc.js +var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) + this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const content = arg; + const lines = content.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) { + this.content.push(line); + } + } + compile() { + const F = Function; + const args = this?.args; + const content = this?.content ?? [``]; + const lines = [...content.map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } +}; + +// node_modules/zod/v4/core/versions.js +var version = { + major: 4, + minor: 4, + patch: 3 +}; + +// node_modules/zod/v4/core/schemas.js +var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => { + var _a3; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) { + checks.unshift(inst); + } + for (const ch of checks) { + for (const fn of ch._zod.onattach) { + fn(inst); + } + } + if (checks.length === 0) { + (_a3 = inst._zod).deferred ?? (_a3.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks2, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks2) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) + continue; + const shouldRun = ch._zod.def.when(payload); + if (!shouldRun) + continue; + } else if (isAborted) { + continue; + } + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) { + throw new $ZodAsyncError(); + } + if (asyncResult || _ instanceof Promise) { + asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + const nextLen = payload.issues.length; + if (nextLen === currLen) + return; + if (!isAborted) + isAborted = aborted(payload, currLen); + }); + } else { + const nextLen = payload.issues.length; + if (nextLen === currLen) + continue; + if (!isAborted) + isAborted = aborted(payload, currLen); + } + } + if (asyncResult) { + return asyncResult.then(() => { + return payload; + }); + } + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) + throw new $ZodAsyncError(); + return checkResult.then((checkResult2) => inst._zod.parse(checkResult2, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) { + return inst._zod.parse(payload, ctx); + } + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ value: payload.value, issues: [] }, { ...ctx, skipChecks: true }); + if (canary instanceof Promise) { + return canary.then((canary2) => { + return handleCanaryResult(canary2, payload, ctx); + }); + } + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) + throw new $ZodAsyncError(); + return result.then((result2) => runChecks(result2, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); +}); +var $ZodString = /* @__PURE__ */ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) + try { + payload.value = String(payload.value); + } catch (_2) { + } + if (typeof payload.value === "string") + return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; +}); +var $ZodStringFormat = /* @__PURE__ */ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); +}); +var $ZodGUID = /* @__PURE__ */ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); +}); +var $ZodUUID = /* @__PURE__ */ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const versionMap = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }; + const v = versionMap[def.version]; + if (v === void 0) + throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else + def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); +}); +var $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); +}); +var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + } + if (def.normalize) { + payload.value = url.href; + } else { + payload.value = trimmed; + } + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodEmoji = /* @__PURE__ */ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); +}); +var $ZodNanoID = /* @__PURE__ */ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); +}); +var $ZodCUID = /* @__PURE__ */ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); +}); +var $ZodCUID2 = /* @__PURE__ */ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); +}); +var $ZodULID = /* @__PURE__ */ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); +}); +var $ZodXID = /* @__PURE__ */ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); +}); +var $ZodKSUID = /* @__PURE__ */ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODateTime = /* @__PURE__ */ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime(def)); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODate = /* @__PURE__ */ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date); + $ZodStringFormat.init(inst, def); +}); +var $ZodISOTime = /* @__PURE__ */ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time(def)); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODuration = /* @__PURE__ */ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration); + $ZodStringFormat.init(inst, def); +}); +var $ZodIPv4 = /* @__PURE__ */ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; +}); +var $ZodIPv6 = /* @__PURE__ */ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodCIDRv4 = /* @__PURE__ */ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); +}); +var $ZodCIDRv6 = /* @__PURE__ */ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) + throw new Error(); + const [address, prefix] = parts; + if (!prefix) + throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) + throw new Error(); + if (prefixNum < 0 || prefixNum > 128) + throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +function isValidBase64(data) { + if (data === "") + return true; + if (/\s/.test(data)) + return false; + if (data.length % 4 !== 0) + return false; + try { + atob(data); + return true; + } catch { + return false; + } +} +var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) + return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +function isValidBase64URL(data) { + if (!base64url.test(data)) + return false; + const base642 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + const padded = base642.padEnd(Math.ceil(base642.length / 4) * 4, "="); + return isValidBase64(padded); +} +var $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) + return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodE164 = /* @__PURE__ */ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); +}); +function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) + return false; + const [header] = tokensParts; + if (!header) + return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") + return false; + if (!parsedHeader.alg) + return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) + return false; + return true; + } catch { + return false; + } +} +var $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) + return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) + try { + payload.value = Number(payload.value); + } catch (_) { + } + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) { + return payload; + } + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; +}); +var $ZodNumberFormat = /* @__PURE__ */ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); +}); +var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; +}); +var $ZodNever = /* @__PURE__ */ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; +}); +function handleArrayResult(result, final, index) { + if (result.issues.length) { + final.issues.push(...prefixIssues(index, result.issues)); + } + final.value[index] = result.value; +} +var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => handleArrayResult(result2, payload, i))); + } else { + handleArrayResult(result, payload, i); + } + } + if (proms.length) { + return Promise.all(proms).then(() => payload); + } + return payload; + }; +}); +function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) { + return; + } + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) { + final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + } + return; + } + if (result.value === void 0) { + if (isPresent) { + final.value[key] = void 0; + } + } else { + final.value[key] = result.value; + } +} +function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) { + if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) { + throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + } + } + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; +} +function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") + continue; + if (keySet.has(key)) + continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ value: input[key], issues: [] }, ctx); + if (r instanceof Promise) { + proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut))); + } else { + handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + } + if (unrecognized.length) { + payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + } + if (!proms.length) + return payload; + return Promise.all(proms).then(() => { + return payload; + }); +} +var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + const desc = Object.getOwnPropertyDescriptor(def, "shape"); + if (!desc?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { + get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { + value: newSh + }); + return newSh; + } + }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) + propValues[key].add(v); + } + } + return propValues; + }); + const isObject2 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ value: input[key], issues: [] }, ctx); + if (r instanceof Promise) { + proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut))); + } else { + handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + } + if (!catchall) { + return proms.length ? Promise.all(proms).then(() => payload) : payload; + } + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; +}); +var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc(["shape", "payload", "ctx"]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = /* @__PURE__ */ Object.create(null); + let counter = 0; + for (const key of normalized.keys) { + ids[key] = `key_${counter++}`; + } + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) { + doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } else if (!isOptionalIn) { + doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + } else { + doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject2 = isObject; + const jit = !globalConfig.jitless; + const allowsEval2 = allowsEval; + const fastEnabled = jit && allowsEval2.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) + fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) + return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; +}); +function handleUnionResults(results, final, inst, ctx) { + for (const result of results) { + if (result.issues.length === 0) { + final.value = result.value; + return final; + } + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; +} +var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) { + return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + } + return void 0; + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + return void 0; + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) { + return first(payload, ctx); + } + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) + return result; + results.push(result); + } + } + if (!async) + return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results2) => { + return handleUnionResults(results2, payload, inst, ctx); + }); + }; +}); +var $ZodIntersection = /* @__PURE__ */ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ value: input, issues: [] }, ctx); + const right = def.right._zod.run({ value: input, issues: [] }, ctx); + const async = left instanceof Promise || right instanceof Promise; + if (async) { + return Promise.all([left, right]).then(([left2, right2]) => { + return handleIntersectionResults(payload, left2, right2); + }); + } + return handleIntersectionResults(payload, left, right); + }; +}); +function mergeValues(a, b) { + if (a === b) { + return { valid: true, data: a }; + } + if (a instanceof Date && b instanceof Date && +a === +b) { + return { valid: true, data: a }; + } + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { ...a, ...b }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) { + return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + } + newObj[key] = sharedValue.data; + } + return { valid: true, data: newObj }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) { + return { valid: false, mergeErrorPath: [] }; + } + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) { + return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + } + newArray.push(sharedValue.data); + } + return { valid: true, data: newArray }; + } + return { valid: false, mergeErrorPath: [] }; +} +function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) { + if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) + unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else { + result.issues.push(iss); + } + } + for (const iss of right.issues) { + if (iss.code === "unrecognized_keys") { + for (const k of iss.keys) { + if (!unrecKeys.has(k)) + unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + } else { + result.issues.push(iss); + } + } + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) { + result.issues.push({ ...unrecIssue, keys: bothKeys }); + } + if (aborted(result)) + return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) { + throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + } + result.value = merged.data; + return result; +} +var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) { + if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx); + if (keyResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => { + if (result2.issues.length) { + payload.issues.push(...prefixIssues(key, result2.issues)); + } + payload.value[outKey] = result2.value; + })); + } else { + if (result.issues.length) { + payload.issues.push(...prefixIssues(key, result.issues)); + } + payload.value[outKey] = result.value; + } + } + } + let unrecognized; + for (const key in input) { + if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + } + if (unrecognized && unrecognized.length > 0) { + payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") + continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) + continue; + let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx); + if (keyResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length; + if (checkNumericKey) { + const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx); + if (retryResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + if (retryResult.issues.length === 0) { + keyResult = retryResult; + } + } + if (keyResult.issues.length) { + if (def.mode === "loose") { + payload.value[key] = input[key]; + } else { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + } + continue; + } + const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => { + if (result2.issues.length) { + payload.issues.push(...prefixIssues(key, result2.issues)); + } + payload.value[keyResult.value] = result2.value; + })); + } else { + if (result.issues.length) { + payload.issues.push(...prefixIssues(key, result.issues)); + } + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) { + return Promise.all(proms).then(() => payload); + } + return payload; + }; +}); +var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) { + return payload; + } + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; +}); +var $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + throw new $ZodEncodeError(inst.constructor.name); + } + const _out = def.transform(payload.value, payload); + if (ctx.async) { + const output = _out instanceof Promise ? _out : Promise.resolve(_out); + return output.then((output2) => { + payload.value = output2; + payload.fallback = true; + return payload; + }); + } + if (_out instanceof Promise) { + throw new $ZodAsyncError(); + } + payload.value = _out; + payload.fallback = true; + return payload; + }; +}); +function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) { + return { issues: [], value: void 0 }; + } + return result; +} +var $ZodOptional = /* @__PURE__ */ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) + return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) { + return payload; + } + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodExactOptional = /* @__PURE__ */ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodNullable = /* @__PURE__ */ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) + return payload; + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodDefault = /* @__PURE__ */ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + if (payload.value === void 0) { + payload.value = def.defaultValue; + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => handleDefaultResult(result2, def)); + } + return handleDefaultResult(result, def); + }; +}); +function handleDefaultResult(payload, def) { + if (payload.value === void 0) { + payload.value = def.defaultValue; + } + return payload; +} +var $ZodPrefault = /* @__PURE__ */ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + if (payload.value === void 0) { + payload.value = def.defaultValue; + } + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => handleNonOptionalResult(result2, inst)); + } + return handleNonOptionalResult(result, inst); + }; +}); +function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + } + return payload; +} +var $ZodCatch = /* @__PURE__ */ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => { + payload.value = result2.value; + if (result2.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { + issues: result2.issues.map((iss) => finalizeIssue(iss, ctx, config())) + }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + } + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { + issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) + }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; +}); +var $ZodPipe = /* @__PURE__ */ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) { + return right.then((right2) => handlePipeResult(right2, def.in, ctx)); + } + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) { + return left.then((left2) => handlePipeResult(left2, def.out, ctx)); + } + return handlePipeResult(left, def.out, ctx); + }; +}); +function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ value: left.value, issues: left.issues, fallback: left.fallback }, ctx); +} +var $ZodReadonly = /* @__PURE__ */ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then(handleReadonlyResult); + } + return handleReadonlyResult(result); + }; +}); +function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; +} +var $ZodCustom = /* @__PURE__ */ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) { + return r.then((r2) => handleRefineResult(r2, payload, input, inst)); + } + handleRefineResult(r, payload, input, inst); + return; + }; +}); +function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + // incorporates params.error into issue reporting + path: [...inst._zod.def.path ?? []], + // incorporates params.error into issue reporting + continue: !inst._zod.def.abort + // params: inst._zod.def.params, + }; + if (inst._zod.def.params) + _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } +} + +// node_modules/zod/v4/core/registries.js +var _a2; +var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta2 = _meta[0]; + this._map.set(schema, meta2); + if (meta2 && typeof meta2 === "object" && "id" in meta2) { + this._idmap.set(meta2.id, schema); + } + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta2 = this._map.get(schema); + if (meta2 && typeof meta2 === "object" && "id" in meta2) { + this._idmap.delete(meta2.id); + } + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { ...pm, ...this._map.get(schema) }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } +}; +function registry() { + return new $ZodRegistry(); +} +(_a2 = globalThis).__zod_globalRegistry ?? (_a2.__zod_globalRegistry = registry()); +var globalRegistry = globalThis.__zod_globalRegistry; + +// node_modules/zod/v4/core/api.js +// @__NO_SIDE_EFFECTS__ +function _string(Class2, params) { + return new Class2({ + type: "string", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _email(Class2, params) { + return new Class2({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _guid(Class2, params) { + return new Class2({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuid(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv4(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv6(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv7(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _url(Class2, params) { + return new Class2({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _emoji2(Class2, params) { + return new Class2({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _nanoid(Class2, params) { + return new Class2({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cuid(Class2, params) { + return new Class2({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cuid2(Class2, params) { + return new Class2({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ulid(Class2, params) { + return new Class2({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _xid(Class2, params) { + return new Class2({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ksuid(Class2, params) { + return new Class2({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ipv4(Class2, params) { + return new Class2({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ipv6(Class2, params) { + return new Class2({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cidrv4(Class2, params) { + return new Class2({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cidrv6(Class2, params) { + return new Class2({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _base64(Class2, params) { + return new Class2({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _base64url(Class2, params) { + return new Class2({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _e164(Class2, params) { + return new Class2({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _jwt(Class2, params) { + return new Class2({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDateTime(Class2, params) { + return new Class2({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDate(Class2, params) { + return new Class2({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoTime(Class2, params) { + return new Class2({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDuration(Class2, params) { + return new Class2({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _number(Class2, params) { + return new Class2({ + type: "number", + checks: [], + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _int(Class2, params) { + return new Class2({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _unknown(Class2) { + return new Class2({ + type: "unknown" + }); +} +// @__NO_SIDE_EFFECTS__ +function _never(Class2, params) { + return new Class2({ + type: "never", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); +} +// @__NO_SIDE_EFFECTS__ +function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); +} +// @__NO_SIDE_EFFECTS__ +function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); +} +// @__NO_SIDE_EFFECTS__ +function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); +} +// @__NO_SIDE_EFFECTS__ +function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); +} +// @__NO_SIDE_EFFECTS__ +function _maxLength(maximum, params) { + const ch = new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + return ch; +} +// @__NO_SIDE_EFFECTS__ +function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); +} +// @__NO_SIDE_EFFECTS__ +function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); +} +// @__NO_SIDE_EFFECTS__ +function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); +} +// @__NO_SIDE_EFFECTS__ +function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); +} +// @__NO_SIDE_EFFECTS__ +function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); +} +// @__NO_SIDE_EFFECTS__ +function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); +} +// @__NO_SIDE_EFFECTS__ +function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); +} +// @__NO_SIDE_EFFECTS__ +function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); +} +// @__NO_SIDE_EFFECTS__ +function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); +} +// @__NO_SIDE_EFFECTS__ +function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); +} +// @__NO_SIDE_EFFECTS__ +function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); +} +// @__NO_SIDE_EFFECTS__ +function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); +} +// @__NO_SIDE_EFFECTS__ +function _array(Class2, element, params) { + return new Class2({ + type: "array", + element, + // get element() { + // return element; + // }, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _refine(Class2, fn, _params) { + const schema = new Class2({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + return schema; +} +// @__NO_SIDE_EFFECTS__ +function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue2) => { + if (typeof issue2 === "string") { + payload.issues.push(issue(issue2, payload.value, ch._zod.def)); + } else { + const _issue = issue2; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; +} +// @__NO_SIDE_EFFECTS__ +function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; +} + +// node_modules/zod/v4/core/to-json-schema.js +function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") + target = "draft-04"; + if (target === "draft-7") + target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => { + }), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; +} +function process2(schema, ctx, _params = { path: [], schemaPath: [] }) { + var _a3; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + const isCycle = _params.schemaPath.includes(schema); + if (isCycle) { + seen.cycle = _params.path; + } + return seen.schema; + } + const result = { schema: {}, count: 1, cycle: void 0, path: _params.path }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) { + result.schema = overrideSchema; + } else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) { + schema._zod.processJSONSchema(ctx, result.schema, params); + } else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) { + throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + } + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) + result.ref = parent; + process2(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta2 = ctx.metadataRegistry.get(schema); + if (meta2) + Object.assign(result.schema, meta2); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) + (_a3 = result.schema).default ?? (_a3.default = result.schema._prefault); + delete result.schema._prefault; + const _result = ctx.seen.get(schema); + return _result.schema; +} +function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) + throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) { + throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + } + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id2) => id2); + if (externalId) { + return { ref: uriGenerator(externalId) }; + } + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` }; + } + if (entry[1] === root) { + return { ref: "#" }; + } + const uriPrefix = `#`; + const defUriPrefix = `${uriPrefix}/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { defId, ref: defUriPrefix + defId }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) { + return; + } + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) + seen.defId = defId; + const schema2 = seen.schema; + for (const key in schema2) { + delete schema2[key]; + } + schema2.$ref = ref; + }; + if (ctx.cycles === "throw") { + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) { + throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + } + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } +} +function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) + throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) + return; + const schema2 = seen.def ?? seen.schema; + const _cached = { ...schema2 }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema2.allOf = schema2.allOf ?? []; + schema2.allOf.push(refSchema); + } else { + Object.assign(schema2, refSchema); + } + Object.assign(schema2, _cached); + const isParentRef = zodSchema._zod.parent === ref; + if (isParentRef) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (!(key in _cached)) { + delete schema2[key]; + } + } + } + if (refSchema.$ref && refSeen.def) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (key in refSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(refSeen.def[key])) { + delete schema2[key]; + } + } + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema2.$ref = parentSeen.schema.$ref; + if (parentSeen.def) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (key in parentSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(parentSeen.def[key])) { + delete schema2[key]; + } + } + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema2, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) { + flattenRef(entry[0]); + } + const result = {}; + if (ctx.target === "draft-2020-12") { + result.$schema = "https://json-schema.org/draft/2020-12/schema"; + } else if (ctx.target === "draft-07") { + result.$schema = "http://json-schema.org/draft-07/schema#"; + } else if (ctx.target === "draft-04") { + result.$schema = "http://json-schema.org/draft-04/schema#"; + } else if (ctx.target === "openapi-3.0") { + } else { + } + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) + throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) + delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) + delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) { + } else { + if (Object.keys(defs).length > 0) { + if (ctx.target === "draft-2020-12") { + result.$defs = defs; + } else { + result.definitions = defs; + } + } + } + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } +} +function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) + return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") + return true; + if (def.type === "array") + return isTransforming(def.element, ctx); + if (def.type === "set") + return isTransforming(def.valueType, ctx); + if (def.type === "lazy") + return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") { + return isTransforming(def.innerType, ctx); + } + if (def.type === "intersection") { + return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + } + if (def.type === "record" || def.type === "map") { + return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + } + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) + return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) { + if (isTransforming(def.shape[key], ctx)) + return true; + } + return false; + } + if (def.type === "union") { + for (const option of def.options) { + if (isTransforming(option, ctx)) + return true; + } + return false; + } + if (def.type === "tuple") { + for (const item of def.items) { + if (isTransforming(item, ctx)) + return true; + } + if (def.rest && isTransforming(def.rest, ctx)) + return true; + return false; + } + return false; +} +var createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ ...params, processors }); + process2(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); +}; +var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors }); + process2(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); +}; + +// node_modules/zod/v4/core/json-schema-processors.js +var formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + // do not set +}; +var stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") + json.minLength = minimum; + if (typeof maximum === "number") + json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") + delete json.format; + if (format === "time") { + delete json.format; + } + } + if (contentEncoding) + json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) + json.pattern = regexes[0].source; + else if (regexes.length > 1) { + json.allOf = [ + ...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + })) + ]; + } + } +}; +var numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) + json.type = "integer"; + else + json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) { + if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else { + json.exclusiveMinimum = exclusiveMinimum; + } + } else if (typeof minimum === "number") { + json.minimum = minimum; + } + if (exMax) { + if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else { + json.exclusiveMaximum = exclusiveMaximum; + } + } else if (typeof maximum === "number") { + json.maximum = maximum; + } + if (typeof multipleOf === "number") + json.multipleOf = multipleOf; +}; +var neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; +}; +var unknownProcessor = (_schema, _ctx, _json, _params) => { +}; +var enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) + json.type = "number"; + if (values.every((v) => typeof v === "string")) + json.type = "string"; + json.enum = values; +}; +var customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") { + throw new Error("Custom types cannot be represented in JSON Schema"); + } +}; +var transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") { + throw new Error("Transforms cannot be represented in JSON Schema"); + } +}; +var arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") + json.minItems = minimum; + if (typeof maximum === "number") + json.maxItems = maximum; + json.type = "array"; + json.items = process2(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); +}; +var objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) { + json.properties[key] = process2(shape[key], ctx, { + ...params, + path: [...params.path, "properties", key] + }); + } + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") { + return v.optin === void 0; + } else { + return v.optout === void 0; + } + })); + if (requiredKeys.size > 0) { + json.required = Array.from(requiredKeys); + } + if (def.catchall?._zod.def.type === "never") { + json.additionalProperties = false; + } else if (!def.catchall) { + if (ctx.io === "output") + json.additionalProperties = false; + } else if (def.catchall) { + json.additionalProperties = process2(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } +}; +var unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process2(x, ctx, { + ...params, + path: [...params.path, isExclusive ? "oneOf" : "anyOf", i] + })); + if (isExclusive) { + json.oneOf = options; + } else { + json.anyOf = options; + } +}; +var intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process2(def.left, ctx, { + ...params, + path: [...params.path, "allOf", 0] + }); + const b = process2(def.right, ctx, { + ...params, + path: [...params.path, "allOf", 1] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + const allOf = [ + ...isSimpleIntersection(a) ? a.allOf : [a], + ...isSimpleIntersection(b) ? b.allOf : [b] + ]; + json.allOf = allOf; +}; +var recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const keyBag = keyType._zod.bag; + const patterns = keyBag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process2(def.valueType, ctx, { + ...params, + path: [...params.path, "patternProperties", "*"] + }); + json.patternProperties = {}; + for (const pattern of patterns) { + json.patternProperties[pattern.source] = valueSchema; + } + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") { + json.propertyNames = process2(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + } + json.additionalProperties = process2(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) { + json.required = validKeyValues; + } + } +}; +var nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else { + json.anyOf = [inner, { type: "null" }]; + } +}; +var nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; +}; +var defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); +}; +var prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") + json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); +}; +var catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; +}; +var pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process2(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; +}; +var readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; +}; +var optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; +}; + +// node_modules/zod/v4/classic/iso.js +var ZodISODateTime = /* @__PURE__ */ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function datetime2(params) { + return _isoDateTime(ZodISODateTime, params); +} +var ZodISODate = /* @__PURE__ */ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function date2(params) { + return _isoDate(ZodISODate, params); +} +var ZodISOTime = /* @__PURE__ */ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function time2(params) { + return _isoTime(ZodISOTime, params); +} +var ZodISODuration = /* @__PURE__ */ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function duration2(params) { + return _isoDuration(ZodISODuration, params); +} + +// node_modules/zod/v4/classic/errors.js +var initializer2 = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { + value: (mapper) => formatError(inst, mapper) + // enumerable: false, + }, + flatten: { + value: (mapper) => flattenError(inst, mapper) + // enumerable: false, + }, + addIssue: { + value: (issue2) => { + inst.issues.push(issue2); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } + // enumerable: false, + }, + addIssues: { + value: (issues2) => { + inst.issues.push(...issues2); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } + // enumerable: false, + }, + isEmpty: { + get() { + return inst.issues.length === 0; + } + // enumerable: false, + } + }); +}; +var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, { + Parent: Error +}); + +// node_modules/zod/v4/classic/parse.js +var parse2 = /* @__PURE__ */ _parse(ZodRealError); +var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError); +var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError); +var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError); +var encode = /* @__PURE__ */ _encode(ZodRealError); +var decode = /* @__PURE__ */ _decode(ZodRealError); +var encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); +var decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); +var safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); +var safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); +var safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); +var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + +// node_modules/zod/v4/classic/schemas.js +var _installedGroups = /* @__PURE__ */ new WeakMap(); +function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) + return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } +} +var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { + jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } + }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse2(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def2 = this.def; + return this.clone(util_exports.mergeDefs(def2, { + checks: [ + ...def2.checks ?? [], + ...chks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch) + ] + }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def2, params) { + return clone(this, def2, params); + }, + brand() { + return this; + }, + register(reg, meta2) { + reg.add(this, meta2); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(_overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) + return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; +}); +var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(_regex(...args)); + }, + includes(...args) { + return this.check(_includes(...args)); + }, + startsWith(...args) { + return this.check(_startsWith(...args)); + }, + endsWith(...args) { + return this.check(_endsWith(...args)); + }, + min(...args) { + return this.check(_minLength(...args)); + }, + max(...args) { + return this.check(_maxLength(...args)); + }, + length(...args) { + return this.check(_length(...args)); + }, + nonempty(...args) { + return this.check(_minLength(1, ...args)); + }, + lowercase(params) { + return this.check(_lowercase(params)); + }, + uppercase(params) { + return this.check(_uppercase(params)); + }, + trim() { + return this.check(_trim()); + }, + normalize(...args) { + return this.check(_normalize(...args)); + }, + toLowerCase() { + return this.check(_toLowerCase()); + }, + toUpperCase() { + return this.check(_toUpperCase()); + }, + slugify() { + return this.check(_slugify()); + } + }); +}); +var ZodString = /* @__PURE__ */ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(_email(ZodEmail, params)); + inst.url = (params) => inst.check(_url(ZodURL, params)); + inst.jwt = (params) => inst.check(_jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(_emoji2(ZodEmoji, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(_uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(_uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(_uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(_uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(_nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(_cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(_cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(_ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(_base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(_base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(_xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(_ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(_ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(_ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(_cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(_cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(_e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime2(params)); + inst.date = (params) => inst.check(date2(params)); + inst.time = (params) => inst.check(time2(params)); + inst.duration = (params) => inst.check(duration2(params)); +}); +function string2(params) { + return _string(ZodString, params); +} +var ZodStringFormat = /* @__PURE__ */ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); +}); +var ZodEmail = /* @__PURE__ */ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodGUID = /* @__PURE__ */ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodUUID = /* @__PURE__ */ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodURL = /* @__PURE__ */ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodEmoji = /* @__PURE__ */ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodNanoID = /* @__PURE__ */ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCUID = /* @__PURE__ */ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCUID2 = /* @__PURE__ */ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodULID = /* @__PURE__ */ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodXID = /* @__PURE__ */ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodKSUID = /* @__PURE__ */ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodIPv4 = /* @__PURE__ */ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodIPv6 = /* @__PURE__ */ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCIDRv4 = /* @__PURE__ */ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCIDRv6 = /* @__PURE__ */ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodBase64 = /* @__PURE__ */ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodE164 = /* @__PURE__ */ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(_gt(value, params)); + }, + gte(value, params) { + return this.check(_gte(value, params)); + }, + min(value, params) { + return this.check(_gte(value, params)); + }, + lt(value, params) { + return this.check(_lt(value, params)); + }, + lte(value, params) { + return this.check(_lte(value, params)); + }, + max(value, params) { + return this.check(_lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(_gt(0, params)); + }, + nonnegative(params) { + return this.check(_gte(0, params)); + }, + negative(params) { + return this.check(_lt(0, params)); + }, + nonpositive(params) { + return this.check(_lte(0, params)); + }, + multipleOf(value, params) { + return this.check(_multipleOf(value, params)); + }, + step(value, params) { + return this.check(_multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); + inst.isFinite = true; + inst.format = bag.format ?? null; +}); +function number2(params) { + return _number(ZodNumber, params); +} +var ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); +}); +function int(params) { + return _int(ZodNumberFormat, params); +} +var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unknownProcessor(inst, ctx, json, params); +}); +function unknown() { + return _unknown(ZodUnknown); +} +var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); +}); +function never(params) { + return _never(ZodNever, params); +} +var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(_minLength(n, params)); + }, + nonempty(params) { + return this.check(_minLength(1, params)); + }, + max(n, params) { + return this.check(_maxLength(n, params)); + }, + length(n, params) { + return this.check(_length(n, params)); + }, + unwrap() { + return this.element; + } + }); +}); +function array(element, params) { + return _array(ZodArray, element, params); +} +var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + util_exports.defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ ...this._zod.def, catchall }); + }, + passthrough() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + loose() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + strict() { + return this.clone({ ...this._zod.def, catchall: never() }); + }, + strip() { + return this.clone({ ...this._zod.def, catchall: void 0 }); + }, + extend(incoming) { + return util_exports.extend(this, incoming); + }, + safeExtend(incoming) { + return util_exports.safeExtend(this, incoming); + }, + merge(other) { + return util_exports.merge(this, other); + }, + pick(mask) { + return util_exports.pick(this, mask); + }, + omit(mask) { + return util_exports.omit(this, mask); + }, + partial(...args) { + return util_exports.partial(ZodOptional, this, args[0]); + }, + required(...args) { + return util_exports.required(ZodNonOptional, this, args[0]); + } + }); +}); +function object(shape, params) { + const def = { + type: "object", + shape: shape ?? {}, + ...util_exports.normalizeParams(params) + }; + return new ZodObject(def); +} +var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; +}); +function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...util_exports.normalizeParams(params) + }); +} +var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); +}); +function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); +} +var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; +}); +function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) { + return new ZodRecord({ + type: "record", + keyType: string2(), + valueType: keyType, + ...util_exports.normalizeParams(valueType) + }); + } + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...util_exports.normalizeParams(params) + }); +} +var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) { + if (keys.has(value)) { + newEntries[value] = def.entries[value]; + } else + throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util_exports.normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) { + if (keys.has(value)) { + delete newEntries[value]; + } else + throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util_exports.normalizeParams(params), + entries: newEntries + }); + }; +}); +function _enum(values, params) { + const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values; + return new ZodEnum({ + type: "enum", + entries, + ...util_exports.normalizeParams(params) + }); +} +var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") { + throw new $ZodEncodeError(inst.constructor.name); + } + payload.addIssue = (issue2) => { + if (typeof issue2 === "string") { + payload.issues.push(util_exports.issue(issue2, payload.value, def)); + } else { + const _issue = issue2; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(util_exports.issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) { + return output.then((output2) => { + payload.value = output2; + payload.fallback = true; + return payload; + }); + } + payload.value = output; + payload.fallback = true; + return payload; + }; +}); +function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); +} +var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); +} +var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); +} +var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); +} +var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; +}); +function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : util_exports.shallowClone(defaultValue); + } + }); +} +var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : util_exports.shallowClone(defaultValue); + } + }); +} +var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...util_exports.normalizeParams(params) + }); +} +var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; +}); +function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); +} +var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; +}); +function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + // ...util.normalizeParams(params), + }); +} +var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); +} +var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); +}); +function refine(fn, _params = {}) { + return _refine(ZodCustom, fn, _params); +} +function superRefine(fn, params) { + return _superRefine(fn, params); +} + +// src/issues/fingerprint.ts +import crypto from "node:crypto"; +var ISSUE_FINGERPRINT_PATTERN = /^[0-9a-f]{20}$/; +function issueFingerprint(issue2, comments = []) { + return crypto.createHash("sha256").update( + JSON.stringify({ + title: issue2.title.trim(), + body: issue2.body ?? "", + comments: comments.map((comment) => ({ + id: comment.id, + body: comment.body, + author: comment.user?.login ?? "" + })) + }) + ).digest("hex").slice(0, 20); +} + +// src/draft-pr/schema.ts +var validationOverrideSchema = object({ + classification: _enum(["allowlisted_test_failure"]), + source: _enum(["policy"]), + reason: string2().min(1).max(1e3), + failedCommands: array(string2().min(1).max(300)).min(1).max(20), + allowedFailureCases: array(string2().min(1).max(300)).min(1).max(50) +}); +function hasConsistentValidationOverride(analysis) { + const override = analysis.validationOverride; + if (!override) return false; + const failedCommands = [ + ...new Set( + analysis.tests.filter((test) => test.status === "failed").map((test) => test.command) + ) + ]; + const overrideCommands = [...new Set(override.failedCommands)]; + return failedCommands.length > 0 && failedCommands.length === overrideCommands.length && failedCommands.every((command) => overrideCommands.includes(command)); +} +var draftPrAnalysisSchema = object({ + outcome: _enum(["implemented", "needs_approval", "blocked", "no_change"]), + prTitle: string2().max(120), + summary: array(string2().min(1).max(500)).max(8), + tests: array( + object({ + command: string2().min(1).max(300), + status: _enum(["passed", "failed", "not_run"]), + details: string2().max(1e3) + }) + ).max(20), + risk: object({ + level: _enum(["low", "medium", "high"]), + reasons: array(string2().min(1).max(500)).max(8) + }), + notes: array(string2().min(1).max(500)).max(8), + validationOverride: validationOverrideSchema.optional() +}); +var draftPrSubmissionSchema = object({ + issueFingerprint: string2().regex(ISSUE_FINGERPRINT_PATTERN), + trigger: _enum(["ready", "approved"]), + workspacePath: string2().min(1).max(2e3), + branch: string2().min(1).max(250), + baseBranch: string2().min(1).max(250), + baseCommit: string2().regex(/^[0-9a-f]{40}$/), + analysis: draftPrAnalysisSchema +}); + +// src/draft-pr/ci-schema.ts +var ciCheckReferenceSchema = object({ + checkRunId: number2().int().positive() +}); +var ciFixAnalysisSchema = object({ + outcome: _enum(["fixed", "no_change", "needs_approval", "blocked"]), + commitTitle: string2().max(120), + summary: array(string2().min(1).max(500)).max(8), + failures: array( + object({ + checkRunId: number2().int().positive(), + disposition: _enum(["fixed", "not_reproducible", "needs_approval"]), + reason: string2().min(1).max(1e3) + }) + ).min(1).max(100), + tests: array( + object({ + command: string2().min(1).max(300), + status: _enum(["passed", "failed", "not_run"]), + details: string2().max(1e3) + }) + ).max(20), + risk: object({ + level: _enum(["low", "medium", "high"]), + reasons: array(string2().min(1).max(500)).max(8) + }), + notes: array(string2().min(1).max(500)).max(8), + validationOverride: validationOverrideSchema.optional() +}); +var ciFixSubmissionSchema = object({ + checkSuiteId: number2().int().positive(), + failuresFingerprint: string2().regex(/^[0-9a-f]{20}$/), + checkRefs: array(ciCheckReferenceSchema).min(1).max(100), + workspacePath: string2().min(1).max(2e3), + branch: string2().min(1).max(250), + baseBranch: string2().min(1).max(250), + expectedHeadSha: string2().regex(/^[0-9a-f]{40}$/), + previousAttempts: number2().int().nonnegative(), + analysis: ciFixAnalysisSchema +}); + +// src/draft-pr/policy.ts +var draftPrPolicySchema = object({ + version: number2().int().positive(), + readyLabel: string2().min(1), + approvedLabel: string2().min(1), + runningLabel: string2().min(1), + needsApprovalLabel: string2().min(1), + prOpenLabel: string2().min(1), + failedLabel: string2().min(1), + skipLabels: array(string2().min(1)), + blockedLabels: array(string2().min(1)), + branchPrefix: string2().regex(/^[a-zA-Z0-9._/-]+$/), + maxChangedFiles: number2().int().positive().max(1e3), + maxChangedLines: number2().int().positive().max(1e5), + maxReviewComments: number2().int().positive().max(100), + maxValidationFixIterations: number2().int().positive().max(20), + maxFixIterations: number2().int().positive().max(20), + requiredValidationGates: array( + _enum(["task-prepare", "task-lint", "task-test-unit"]) + ).min(1), + allowedValidationFailureCases: array(string2().min(1).max(300)).max(50), + approvalPathPrefixes: array(string2().min(1)), + labelColors: record(string2(), string2().regex(/^[0-9a-fA-F]{6}$/)) +}); +function requiresApproval(analysis, inspection, approved, policy) { + if (approved) return []; + const reasons = []; + if (analysis.risk.level === "high") { + reasons.push("the implementation reports high risk"); + } + if (inspection.changedFiles.length > policy.maxChangedFiles) { + reasons.push( + `the change touches ${inspection.changedFiles.length} files (limit ${policy.maxChangedFiles})` + ); + } + const changedLines = inspection.additions + inspection.deletions; + if (changedLines > policy.maxChangedLines) { + reasons.push( + `the change modifies ${changedLines} lines (limit ${policy.maxChangedLines})` + ); + } + const sensitivePaths = inspection.changedFiles.filter( + (file) => policy.approvalPathPrefixes.some((prefix) => file.startsWith(prefix)) + ); + if (sensitivePaths.length > 0) { + reasons.push( + `the change touches approval-gated paths: ${sensitivePaths.slice(0, 5).join(", ")}` + ); + } + return reasons; +} +function hasLabel(labels, expected) { + const normalized = expected.trim().toLowerCase(); + return labels.some((label) => label.trim().toLowerCase() === normalized); +} +function hasAnyLabel(labels, expected) { + return expected.some((label) => hasLabel(labels, label)); +} + +// src/draft-pr/repository.ts +function repositoryCloneUrl(serverUrl, repository) { + const base = new URL(serverUrl); + if (base.protocol !== "https:") { + throw new Error("GitHub server URL must use HTTPS"); + } + base.pathname = `${base.pathname.replace(/\/$/, "")}/${repository}.git`; + base.search = ""; + base.hash = ""; + return base.toString(); +} +function sanitizeTitle(value) { + return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 120); +} +function assertAllowedRepository(repository, allowed) { + if (!allowed.trim()) { + throw new Error("Draft PR repository allowlist is required"); + } + if (repository.trim().toLowerCase() !== allowed.trim().toLowerCase()) { + throw new Error("repository is outside the Draft PR allowlist"); + } +} + +// src/draft-pr/workspace.ts +import crypto2 from "node:crypto"; +import { spawn } from "node:child_process"; +import { + chmod, + lstat, + mkdir, + mkdtemp, + rm, + stat, + writeFile +} from "node:fs/promises"; +import { isIP } from "node:net"; +import os from "node:os"; +import path from "node:path"; +var DraftPrWorkspaceLockError = class extends Error { + constructor(target) { + super(`another Draft PR run already holds the ${target} lock`); + this.name = "DraftPrWorkspaceLockError"; + } +}; +var GitDraftPrWorkspace = class { + #root; + #token; + #authorName; + #authorEmail; + #gitCurlResolve; + #lockTtlMs; + constructor(options) { + this.#root = path.resolve(options.root); + this.#token = options.token.trim(); + this.#authorName = options.authorName.trim(); + this.#authorEmail = options.authorEmail.trim(); + this.#gitCurlResolve = options.gitCurlResolve?.trim() ?? ""; + this.#lockTtlMs = options.lockTtlMs ?? 4 * 60 * 60 * 1e3; + if (!this.#token) + throw new Error("GitHub token is required for Git workspace preparation"); + if (!this.#authorName || !this.#authorEmail) { + throw new Error("Git author name and email are required"); + } + gitCurlResolveEnvironment(this.#gitCurlResolve); + } + async prepare(input) { + validateCloneUrl(input.cloneUrl); + validateGitRef(input.baseBranch, "base branch"); + validateGitRef(input.branch, "working branch"); + const paths = this.#paths(input.repository, "issue", input.issueNumber); + await mkdir(path.dirname(paths.lock), { recursive: true }); + await this.#acquireLock(paths.lock); + try { + await rm(paths.workspace, { recursive: true, force: true }); + await mkdir(path.dirname(paths.workspace), { recursive: true }); + const env = await this.#authenticatedGitEnvironment(); + await runGit( + [ + "clone", + "--no-tags", + "--depth=1", + "--branch", + input.baseBranch, + "--", + input.cloneUrl, + paths.workspace + ], + { cwd: this.#root, env } + ); + const existing = await runGit( + ["ls-remote", "--heads", "origin", `refs/heads/${input.branch}`], + { cwd: paths.workspace, env } + ); + if (existing.stdout.trim()) { + throw new Error(`remote branch already exists: ${input.branch}`); + } + await runGit(["checkout", "-b", input.branch], { + cwd: paths.workspace, + env + }); + const baseCommit = (await runGit(["rev-parse", "HEAD"], { cwd: paths.workspace, env })).stdout.trim(); + return { + path: paths.workspace, + branch: input.branch, + baseBranch: input.baseBranch, + baseCommit + }; + } catch (error) { + await this.cleanup(input.repository, input.issueNumber); + throw error; + } + } + async prepareReview(input) { + validateCloneUrl(input.cloneUrl); + validateGitRef(input.baseBranch, "base branch"); + validateGitRef(input.branch, "Pull Request branch"); + if (!/^[0-9a-f]{40}$/.test(input.expectedHeadSha)) { + throw new Error("invalid expected Pull Request head SHA"); + } + const paths = this.#paths(input.repository, "pr", input.pullRequestNumber); + await mkdir(path.dirname(paths.lock), { recursive: true }); + await this.#acquireLock(paths.lock, "Pull Request"); + try { + await rm(paths.workspace, { recursive: true, force: true }); + await mkdir(path.dirname(paths.workspace), { recursive: true }); + const env = await this.#authenticatedGitEnvironment(); + await runGit( + [ + "clone", + "--no-tags", + "--depth=1", + "--branch", + input.branch, + "--", + input.cloneUrl, + paths.workspace + ], + { cwd: this.#root, env } + ); + const headCommit = (await runGit(["rev-parse", "HEAD"], { cwd: paths.workspace, env })).stdout.trim(); + if (headCommit !== input.expectedHeadSha) { + throw new Error( + "Pull Request head changed during workspace preparation" + ); + } + return { + path: paths.workspace, + branch: input.branch, + baseBranch: input.baseBranch, + baseCommit: headCommit + }; + } catch (error) { + await this.cleanupReview(input.repository, input.pullRequestNumber); + throw error; + } + } + async inspect(workspacePath) { + return inspectDraftPrWorkspace(this.#root, workspacePath); + } + async commitAndPush(workspacePath, branch, title, cloneUrl) { + const resolved = this.#assertWorkspacePath(workspacePath); + validateGitRef(branch, "working branch"); + validateCloneUrl(cloneUrl); + await this.#writeTrustedGitConfig(resolved, cloneUrl); + const localEnv = this.#localGitEnvironment(); + await runGit( + [ + "-c", + `user.name=${this.#authorName}`, + "-c", + `user.email=${this.#authorEmail}`, + "-c", + "core.hooksPath=/dev/null", + "commit", + "-m", + title + ], + { cwd: resolved, env: localEnv } + ); + const authenticatedEnv = await this.#authenticatedGitEnvironment(); + await runGit( + [ + "-c", + "core.hooksPath=/dev/null", + "-c", + "credential.helper=", + "push", + "--no-verify", + "--set-upstream", + "origin", + branch + ], + { + cwd: resolved, + env: authenticatedEnv + } + ); + return (await runGit(["rev-parse", "HEAD"], { cwd: resolved, env: localEnv })).stdout.trim(); + } + async cleanup(repository, issueNumber) { + const paths = this.#paths(repository, "issue", issueNumber); + await rm(paths.workspace, { recursive: true, force: true }); + await rm(paths.lock, { recursive: true, force: true }); + } + async cleanupReview(repository, pullRequestNumber) { + const paths = this.#paths(repository, "pr", pullRequestNumber); + await rm(paths.workspace, { recursive: true, force: true }); + await rm(paths.lock, { recursive: true, force: true }); + } + #paths(repository, kind, number3) { + if (!Number.isSafeInteger(number3) || number3 <= 0) { + throw new Error( + `${kind === "issue" ? "Issue" : "Pull Request"} number must be a positive integer` + ); + } + const key = crypto2.createHash("sha256").update(repository.trim().toLowerCase()).digest("hex").slice(0, 16); + return { + workspace: path.join( + this.#root, + "repositories", + key, + `${kind}-${number3}` + ), + lock: path.join(this.#root, ".locks", `${key}-${kind}-${number3}`) + }; + } + #assertWorkspacePath(value) { + const resolved = path.resolve(value); + const expectedPrefix = `${path.join(this.#root, "repositories")}${path.sep}`; + if (!resolved.startsWith(expectedPrefix)) { + throw new Error("workspace path is outside the configured Draft PR root"); + } + return resolved; + } + async #acquireLock(lockPath, target = "Issue") { + try { + await mkdir(lockPath); + return; + } catch (error) { + if (!isAlreadyExists(error)) throw error; + } + const info = await stat(lockPath); + if (Date.now() - info.mtimeMs <= this.#lockTtlMs) { + throw new DraftPrWorkspaceLockError(target); + } + await rm(lockPath, { recursive: true, force: true }); + await mkdir(lockPath); + } + #localGitEnvironment() { + return { + PATH: process.env.PATH, + HOME: process.env.HOME, + LANG: process.env.LANG ?? "C.UTF-8", + GIT_CONFIG_NOSYSTEM: "1", + GIT_CONFIG_GLOBAL: "/dev/null", + GIT_TERMINAL_PROMPT: "0", + ...gitCurlResolveEnvironment(this.#gitCurlResolve) + }; + } + async #authenticatedGitEnvironment() { + await mkdir(this.#root, { recursive: true }); + const askPass = path.join(this.#root, ".git-askpass.sh"); + await writeFile( + askPass, + [ + "#!/bin/sh", + 'case "$1" in', + ' *Username*) printf "%s" "x-access-token" ;;', + ' *) printf "%s" "$DRAFT_PR_GIT_TOKEN" ;;', + "esac", + "" + ].join("\n"), + { mode: 448 } + ); + await chmod(askPass, 448); + return { + ...this.#localGitEnvironment(), + GIT_ASKPASS: askPass, + DRAFT_PR_GIT_TOKEN: this.#token + }; + } + async #writeTrustedGitConfig(workspacePath, cloneUrl) { + const gitDirectory = path.join(workspacePath, ".git"); + const gitDirectoryInfo = await lstat(gitDirectory); + if (!gitDirectoryInfo.isDirectory() || gitDirectoryInfo.isSymbolicLink()) { + throw new Error("prepared workspace .git directory was replaced"); + } + const configPath = path.join(gitDirectory, "config"); + const configInfo = await lstat(configPath); + if (!configInfo.isFile() || configInfo.isSymbolicLink()) { + throw new Error("prepared workspace Git config was replaced"); + } + await writeFile( + configPath, + [ + "[core]", + " repositoryformatversion = 0", + " filemode = true", + " bare = false", + " logallrefupdates = true", + " hooksPath = /dev/null", + '[remote "origin"]', + ` url = ${cloneUrl}`, + " fetch = +refs/heads/*:refs/remotes/origin/*", + "" + ].join("\n"), + { mode: 384 } + ); + } +}; +async function inspectDraftPrWorkspace(root, workspacePath) { + const resolved = assertWorkspacePath(root, workspacePath); + const env = localGitEnvironment(); + await runGit(["add", "-A"], { cwd: resolved, env }); + const [head, tree, names, stats, check, diff] = await Promise.all([ + runGit(["rev-parse", "HEAD"], { cwd: resolved, env }), + runGit(["write-tree"], { cwd: resolved, env }), + runGit(["diff", "--cached", "--name-only", "-z"], { + cwd: resolved, + env + }), + runGit(["diff", "--cached", "--numstat"], { cwd: resolved, env }), + runGit(["diff", "--cached", "--check"], { + cwd: resolved, + env, + allowFailure: true + }), + runGit( + [ + "diff", + "--cached", + "--unified=0", + "--no-color", + "--no-ext-diff", + "--no-textconv" + ], + { + cwd: resolved, + env, + maxOutputBytes: 8 * 1024 * 1024 + } + ) + ]); + const changedFiles = names.stdout.split("\0").filter(Boolean); + let additions = 0; + let deletions = 0; + for (const line of stats.stdout.split("\n")) { + const [added, deleted] = line.split(" "); + if (/^\d+$/.test(added ?? "")) additions += Number(added); + if (/^\d+$/.test(deleted ?? "")) deletions += Number(deleted); + } + return { + headCommit: head.stdout.trim(), + changeFingerprint: tree.stdout.trim(), + changedFiles, + additions, + deletions, + diffCheckPassed: check.exitCode === 0, + secretFindingPaths: scanAddedLinesForSecrets(diff.stdout) + }; +} +async function fingerprintDraftPrWorkspace(root, workspacePath) { + const resolved = assertWorkspacePath(root, workspacePath); + const temporaryDirectory = await mkdtemp( + path.join(os.tmpdir(), "draft-pr-index-") + ); + try { + const env = { + ...localGitEnvironment(), + GIT_INDEX_FILE: path.join(temporaryDirectory, "index") + }; + await runGit(["read-tree", "HEAD"], { cwd: resolved, env }); + await runGit(["add", "-A"], { cwd: resolved, env }); + const [head, tree] = await Promise.all([ + runGit(["rev-parse", "HEAD"], { cwd: resolved, env }), + runGit(["write-tree"], { cwd: resolved, env }) + ]); + return { + headCommit: head.stdout.trim(), + changeFingerprint: tree.stdout.trim() + }; + } finally { + await rm(temporaryDirectory, { recursive: true, force: true }); + } +} +function assertWorkspacePath(root, value) { + const resolvedRoot = path.resolve(root); + const resolved = path.resolve(value); + const expectedPrefix = `${path.join(resolvedRoot, "repositories")}${path.sep}`; + if (!resolved.startsWith(expectedPrefix)) { + throw new Error("workspace path is outside the configured Draft PR root"); + } + return resolved; +} +function localGitEnvironment() { + return { + PATH: process.env.PATH, + HOME: process.env.HOME, + LANG: process.env.LANG ?? "C.UTF-8", + GIT_CONFIG_NOSYSTEM: "1", + GIT_CONFIG_GLOBAL: "/dev/null", + GIT_TERMINAL_PROMPT: "0" + }; +} +function gitCurlResolveEnvironment(value) { + const normalized = value?.trim() ?? ""; + if (!normalized) return {}; + const [host, port, address, ...extra] = normalized.split(":"); + if (host !== "github.com" || port !== "443" || isIP(address ?? "") !== 4 || extra.length > 0) { + throw new Error("Draft PR Git curl resolve must use github.com:443:"); + } + return { + GIT_CONFIG_COUNT: "1", + GIT_CONFIG_KEY_0: "http.curloptResolve", + GIT_CONFIG_VALUE_0: normalized + }; +} +async function runGit(args, options) { + const safeArgs = options.cwd ? ["-c", `safe.directory=${options.cwd}`, ...args] : args; + return new Promise((resolve, reject) => { + const child = spawn("git", safeArgs, { + cwd: options.cwd, + env: options.env, + stdio: ["ignore", "pipe", "pipe"] + }); + const max = options.maxOutputBytes ?? 2 * 1024 * 1024; + let stdout = ""; + let stderr = ""; + let size = 0; + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + child.stdout.on("data", (chunk) => { + size += Buffer.byteLength(chunk); + if (size <= max) stdout += chunk; + }); + child.stderr.on("data", (chunk) => { + size += Buffer.byteLength(chunk); + if (size <= max) stderr += chunk; + }); + child.on("error", reject); + child.on("close", (code) => { + const exitCode = code ?? 1; + if (size > max) { + reject(new Error("git command output exceeded the configured limit")); + } else if (exitCode !== 0 && !options.allowFailure) { + reject( + new Error( + `git ${args[0] ?? "command"} failed: ${stderr.trim().slice(-2e3)}` + ) + ); + } else { + resolve({ stdout, stderr, exitCode }); + } + }); + }); +} +function validateCloneUrl(value) { + const url = new URL(value); + if (url.protocol !== "https:" || url.username || url.password) { + throw new Error("Draft PR clone URL must be credential-free HTTPS"); + } +} +function validateGitRef(value, name) { + if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(value) || value.includes("..") || value.includes("//") || value.endsWith("/") || value.endsWith(".lock")) { + throw new Error(`invalid ${name}: ${value}`); + } +} +function scanAddedLinesForSecrets(diff) { + const findings = /* @__PURE__ */ new Set(); + let currentPath = "unknown"; + const patterns = [ + /-----BEGIN [A-Z ]*PRIVATE KEY-----/, + /\bghp_[A-Za-z0-9]{30,}\b/, + /\bgithub_pat_[A-Za-z0-9_]{30,}\b/, + /\bAKIA[0-9A-Z]{16}\b/, + /Authorization:\s*Bearer\s+[A-Za-z0-9._-]{20,}/i + ]; + for (const line of diff.split("\n")) { + if (line.startsWith("+++ b/")) currentPath = line.slice(6); + if (!line.startsWith("+") || line.startsWith("+++")) continue; + if (patterns.some((pattern) => pattern.test(line))) + findings.add(currentPath); + } + return [...findings].sort(); +} +function isAlreadyExists(error) { + return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST"; +} + +// src/draft-pr/ci-tool.ts +var FAILED_CONCLUSIONS = /* @__PURE__ */ new Set([ + "action_required", + "failure", + "startup_failure", + "timed_out" +]); +var MAX_ANNOTATIONS_PER_CHECK = 50; +async function prepareCiFix(repository, pullRequestNumber, expectedHeadSha, checkSuiteId, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + requireBotIdentity(dependencies); + validateEventTarget(expectedHeadSha, checkSuiteId); + const [pullRequest, comments] = await Promise.all([ + dependencies.provider.getPullRequest(repository, pullRequestNumber), + dependencies.provider.listComments(repository, pullRequestNumber) + ]); + const reason = ineligibleReason(pullRequest, repository, dependencies); + if (reason) { + return skipped(repository, pullRequestNumber, checkSuiteId, reason); + } + if (pullRequest.headSha !== expectedHeadSha) { + return skipped( + repository, + pullRequestNumber, + checkSuiteId, + "CI event is for a stale Pull Request head" + ); + } + const state = ciState(comments, dependencies); + if (state.checkSuiteId === checkSuiteId && ["no-change", "needs-approval"].includes(state.status)) { + return skipped( + repository, + pullRequestNumber, + checkSuiteId, + "CI check suite was already processed" + ); + } + if (state.attempts >= dependencies.policy.maxFixIterations) { + if (dependencies.apply) { + await upsertCiState( + repository, + pullRequestNumber, + { + checkSuiteId, + attempts: state.attempts, + headSha: expectedHeadSha, + status: "needs-approval" + }, + comments, + dependencies + ); + } + return skipped( + repository, + pullRequestNumber, + checkSuiteId, + "automatic CI fix iteration limit reached" + ); + } + const failures = await loadFailures( + repository, + expectedHeadSha, + checkSuiteId, + dependencies + ); + if (failures.length === 0) { + return skipped( + repository, + pullRequestNumber, + checkSuiteId, + "check suite has no supported failed checks" + ); + } + let prepared; + try { + prepared = await dependencies.workspace.prepareReview({ + repository, + pullRequestNumber, + cloneUrl: repositoryCloneUrl(dependencies.serverUrl, repository), + baseBranch: pullRequest.base, + branch: pullRequest.head, + expectedHeadSha + }); + } catch (error) { + if (error instanceof DraftPrWorkspaceLockError) { + return skipped( + repository, + pullRequestNumber, + checkSuiteId, + "another Pull Request fix run holds the workspace lock" + ); + } + throw error; + } + if (dependencies.apply) { + await upsertCiState( + repository, + pullRequestNumber, + { + checkSuiteId, + attempts: state.attempts, + headSha: expectedHeadSha, + status: "fixing" + }, + comments, + dependencies + ); + } + return { + ok: true, + repository, + pullRequestNumber, + checkSuiteId, + workspacePath: prepared.path, + branch: prepared.branch, + baseBranch: prepared.baseBranch, + expectedHeadSha: prepared.baseCommit, + failuresFingerprint: fingerprintFailures(failures), + previousAttempts: state.attempts, + failures + }; +} +async function applyCiFix(repository, pullRequestNumber, submissionInput, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + requireBotIdentity(dependencies); + const submission = ciFixSubmissionSchema.parse(submissionInput); + const [pullRequest, comments, failures] = await Promise.all([ + dependencies.provider.getPullRequest(repository, pullRequestNumber), + dependencies.provider.listComments(repository, pullRequestNumber), + loadFailures( + repository, + submission.expectedHeadSha, + submission.checkSuiteId, + dependencies + ) + ]); + const reason = ineligibleReason(pullRequest, repository, dependencies); + if (reason) throw new Error(reason); + if (pullRequest.headSha !== submission.expectedHeadSha) { + throw new Error("Pull Request head changed after CI fix preparation"); + } + const expectedIds = submission.checkRefs.map((value) => value.checkRunId); + const actualIds = failures.map((value) => value.checkRunId); + if (new Set(expectedIds).size !== expectedIds.length || expectedIds.length !== actualIds.length || expectedIds.some((id, index) => id !== actualIds[index]) || fingerprintFailures(failures) !== submission.failuresFingerprint) { + throw new Error("failed CI checks changed after fix preparation"); + } + validateFailureCoverage(submission.analysis, expectedIds); + const inspection = await dependencies.workspace.inspect( + submission.workspacePath + ); + if (inspection.headCommit !== submission.expectedHeadSha) { + throw new Error("the Agent committed or moved HEAD in the CI workspace"); + } + const nextAttempts = submission.previousAttempts + 1; + if (submission.analysis.outcome !== "fixed") { + if (inspection.changedFiles.length > 0) { + throw new Error( + `${submission.analysis.outcome} CI result contains changes` + ); + } + if (submission.analysis.outcome === "no_change" && submission.analysis.failures.some( + (failure) => failure.disposition !== "not_reproducible" + )) { + throw new Error( + "no_change CI result requires every failure to be not reproducible" + ); + } + const status = submission.analysis.outcome === "needs_approval" ? "needs-approval" : submission.analysis.outcome === "no_change" ? "no-change" : "failed"; + await finishWithoutPush( + repository, + pullRequestNumber, + submission, + nextAttempts, + status, + comments, + dependencies + ); + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: submission.analysis.outcome, + inspection + }; + } + validateFixedAnalysis(submission.analysis, inspection); + const approvalReasons = requiresApproval( + submission.analysis, + inspection, + false, + dependencies.policy + ); + if (approvalReasons.length > 0) { + await finishWithoutPush( + repository, + pullRequestNumber, + submission, + nextAttempts, + "needs-approval", + comments, + dependencies + ); + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: "needs_approval", + inspection + }; + } + if (!dependencies.apply) { + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + return { + ok: true, + repository, + pullRequestNumber, + applied: false, + outcome: "fixed", + inspection + }; + } + const commit = await dependencies.workspace.commitAndPush( + submission.workspacePath, + submission.branch, + sanitizeTitle(submission.analysis.commitTitle), + repositoryCloneUrl(dependencies.serverUrl, repository) + ); + await upsertCiState( + repository, + pullRequestNumber, + { + checkSuiteId: submission.checkSuiteId, + attempts: nextAttempts, + headSha: commit, + status: "fixed" + }, + comments, + dependencies + ); + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + return { + ok: true, + repository, + pullRequestNumber, + applied: true, + outcome: "fixed", + commit, + inspection + }; +} +async function failCiFix(repository, pullRequestNumber, checkSuiteId, attempts, headSha, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + try { + if (dependencies.apply) { + const comments = await dependencies.provider.listComments( + repository, + pullRequestNumber + ); + await upsertCiState( + repository, + pullRequestNumber, + { + checkSuiteId, + attempts, + headSha, + status: "failed" + }, + comments, + dependencies + ); + } + } finally { + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + } + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: "failed" + }; +} +async function loadFailures(repository, headSha, checkSuiteId, dependencies) { + const runs = (await dependencies.provider.listCheckRuns(repository, headSha)).filter( + (run) => run.checkSuiteId === checkSuiteId && run.status === "completed" && FAILED_CONCLUSIONS.has(run.conclusion ?? "") + ).sort((left, right) => left.id - right.id); + if (runs.length > dependencies.policy.maxReviewComments) { + throw new Error( + `CI check suite has ${runs.length} failed checks (limit ${dependencies.policy.maxReviewComments})` + ); + } + return Promise.all( + runs.map(async (run) => ({ + checkRunId: run.id, + name: run.name, + conclusion: run.conclusion, + ...run.htmlUrl ? { htmlUrl: run.htmlUrl } : {}, + output: run.output, + annotations: (await dependencies.provider.listCheckRunAnnotations(repository, run.id)).slice(0, MAX_ANNOTATIONS_PER_CHECK) + })) + ); +} +function fingerprintFailures(failures) { + return crypto3.createHash("sha256").update(JSON.stringify(failures)).digest("hex").slice(0, 20); +} +function validateFailureCoverage(analysis, expectedIds) { + const actual = analysis.failures.map((failure) => failure.checkRunId); + if (new Set(actual).size !== actual.length || actual.length !== expectedIds.length || actual.some((id, index) => id !== expectedIds[index])) { + throw new Error( + "CI fix analysis must address every failed check exactly once" + ); + } + if (analysis.outcome === "fixed" && analysis.failures.some( + (failure) => failure.disposition === "needs_approval" + )) { + throw new Error("fixed CI result cannot contain approval-gated failures"); + } +} +function validateFixedAnalysis(analysis, inspection) { + if (inspection.changedFiles.length === 0) { + throw new Error("fixed CI result contains no repository changes"); + } + if (!inspection.diffCheckPassed) { + throw new Error("CI fix failed git diff --check"); + } + if (inspection.secretFindingPaths.length > 0) { + throw new Error("CI fix contains potential credential material"); + } + if (analysis.validationOverride && !hasConsistentValidationOverride(analysis)) { + throw new Error("fixed CI result has an inconsistent validation override"); + } + if (analysis.tests.some((test) => test.status === "failed") && !hasConsistentValidationOverride(analysis)) { + throw new Error("fixed CI result reports a failed validation command"); + } +} +function ineligibleReason(pullRequest, repository, dependencies) { + if (pullRequest.state.toLowerCase() !== "open") + return "Pull Request is not open"; + if (!pullRequest.head.startsWith(dependencies.policy.branchPrefix)) { + return "Pull Request branch is not managed by the Draft PR Agent"; + } + if (pullRequest.headRepository?.trim().toLowerCase() !== repository.trim().toLowerCase()) { + return "Pull Request head repository is not the allowlisted repository"; + } + if (!pullRequest.headSha || !/^[0-9a-f]{40}$/.test(pullRequest.headSha)) { + return "Pull Request has no valid head SHA"; + } + return void 0; +} +function validateEventTarget(headSha, checkSuiteId) { + if (!/^[0-9a-f]{40}$/.test(headSha)) { + throw new Error("invalid CI event head SHA"); + } + if (!Number.isSafeInteger(checkSuiteId) || checkSuiteId <= 0) { + throw new Error("invalid CI check suite ID"); + } +} +function ciState(comments, dependencies) { + return parseCiFixState( + findCiFixComment(comments, dependencies.botLogin?.trim() ?? "") + ); +} +async function finishWithoutPush(repository, pullRequestNumber, submission, attempts, status, comments, dependencies) { + if (dependencies.apply) { + await upsertCiState( + repository, + pullRequestNumber, + { + checkSuiteId: submission.checkSuiteId, + attempts, + headSha: submission.expectedHeadSha, + status + }, + comments, + dependencies + ); + } + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); +} +async function upsertCiState(repository, pullRequestNumber, state, comments, dependencies) { + const botLogin = dependencies.botLogin?.trim() ?? ""; + if (!botLogin) throw new Error("GitHub bot login is required in apply mode"); + const existing = findCiFixComment(comments, botLogin); + const body = buildCiFixComment(state); + if (existing) { + await dependencies.provider.updateComment( + repository, + pullRequestNumber, + existing.id, + body + ); + } else { + await dependencies.provider.createComment( + repository, + pullRequestNumber, + body + ); + } +} +function requireBotIdentity(dependencies) { + if (dependencies.apply && !dependencies.botLogin?.trim()) { + throw new Error("GitHub bot login is required for CI fixes in apply mode"); + } +} +function skipped(repository, pullRequestNumber, checkSuiteId, reason) { + return { + ok: true, + skipped: true, + reason, + repository, + pullRequestNumber, + checkSuiteId + }; +} + +// src/draft-pr/review-tool.ts +import crypto4 from "node:crypto"; + +// src/draft-pr/review-comment.ts +var REVIEW_FIX_COMMENT_PREFIX = "$/ + ); + if (v3Match) { + return { + reviewCursor: Number(v3Match[1]), + iterations: Number(v3Match[2]), + headSha: v3Match[3] === "none" ? "" : v3Match[3], + status: v3Match[4] + }; + } + const v2Match = marker.match( + /^$/ + ); + if (v2Match) { + return { + // v2 stored Conversation and inline Review Comment IDs, not Review IDs. + // Start the v3 Review cursor at zero so the first formal change request + // after upgrading is never skipped because the ID namespaces differ. + reviewCursor: 0, + iterations: Number(v2Match[3]), + headSha: v2Match[4] === "none" ? "" : v2Match[4], + status: v2Match[5] + }; + } + const v1Match = marker.match( + /^$/ + ); + if (!v1Match) return emptyReviewFixState(); + return { + reviewCursor: 0, + iterations: Number(v1Match[2]), + headSha: v1Match[3] === "none" ? "" : v1Match[3], + status: v1Match[4] + }; +} +function buildReviewFixComment(state) { + const marker = `${REVIEW_FIX_COMMENT_V3_PREFIX} review=${state.reviewCursor} iterations=${state.iterations} head=${state.headSha || "none"} status=${state.status} -->`; + const messages = { + fixing: "The Draft PR Agent is validating a requested change.", + fixed: "The Draft PR Agent pushed a validated fix for the latest requested changes.", + "no-change": "The Draft PR Agent verified the latest requested changes and made no code change.", + "needs-approval": "Automatic Review fixes paused for maintainer approval.", + failed: "The Draft PR Agent could not complete the latest Review fix attempt." + }; + return [marker, "## Review follow-up", "", messages[state.status]].join("\n"); +} +function emptyReviewFixState() { + return { + reviewCursor: 0, + iterations: 0, + headSha: "", + status: "fixed" + }; +} + +// src/draft-pr/review-schema.ts +var reviewFindingSourceSchema = _enum(["review", "review_comment"]); +var reviewFindingReferenceSchema = object({ + source: reviewFindingSourceSchema, + commentId: number2().int().positive() +}); +var reviewTestSchema = object({ + command: string2().min(1).max(300), + status: _enum(["passed", "failed", "not_run"]), + details: string2().max(1e3) +}); +var reviewFixAnalysisSchema = object({ + outcome: _enum(["fixed", "no_change", "needs_approval", "blocked"]), + commitTitle: string2().max(120), + summary: array(string2().min(1).max(500)).max(8), + findings: array( + object({ + source: reviewFindingSourceSchema, + commentId: number2().int().positive(), + disposition: _enum(["fixed", "not_reproducible", "needs_approval"]), + reason: string2().min(1).max(1e3) + }) + ).max(100), + tests: array(reviewTestSchema).max(20), + risk: object({ + level: _enum(["low", "medium", "high"]), + reasons: array(string2().min(1).max(500)).max(8) + }), + notes: array(string2().min(1).max(500)).max(8), + validationOverride: validationOverrideSchema.optional() +}); +var reviewFixSubmissionSchema = object({ + reviewId: number2().int().positive(), + reviewFingerprint: string2().regex(/^[0-9a-f]{20}$/), + findingRefs: array(reviewFindingReferenceSchema).min(1).max(100), + workspacePath: string2().min(1).max(2e3), + branch: string2().min(1).max(250), + baseBranch: string2().min(1).max(250), + expectedHeadSha: string2().regex(/^[0-9a-f]{40}$/), + previousReviewCursor: number2().int().nonnegative(), + previousIterations: number2().int().nonnegative(), + analysis: reviewFixAnalysisSchema +}); + +// src/draft-pr/review-tool.ts +async function prepareReviewFix(repository, pullRequestNumber, reviewId, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + requireReviewBotIdentity(dependencies); + const [pullRequest, review, conversationComments, reviewComments] = await Promise.all([ + dependencies.provider.getPullRequest(repository, pullRequestNumber), + dependencies.provider.getPullRequestReview( + repository, + pullRequestNumber, + reviewId + ), + dependencies.provider.listComments(repository, pullRequestNumber), + dependencies.provider.listReviewComments(repository, pullRequestNumber) + ]); + const reason = ineligibleReason2(pullRequest, repository, dependencies); + if (reason) return skipped2(repository, pullRequestNumber, reason); + const reviewReason = ineligibleReviewReason(review, pullRequest); + if (reviewReason) return skipped2(repository, pullRequestNumber, reviewReason); + const state = reviewState(conversationComments, dependencies); + if (review.id <= state.reviewCursor) { + return skipped2( + repository, + pullRequestNumber, + "Pull Request Review was already processed" + ); + } + const findings = findingsForReview(review, reviewComments); + if (findings.length === 0) { + return skipped2(repository, pullRequestNumber, "Review has no findings"); + } + if (findings.length > dependencies.policy.maxReviewComments) { + if (dependencies.apply) { + await upsertReviewState( + repository, + pullRequestNumber, + { + reviewCursor: state.reviewCursor, + iterations: state.iterations, + headSha: pullRequest.headSha, + status: "needs-approval" + }, + conversationComments, + dependencies + ); + } + return skipped2( + repository, + pullRequestNumber, + `Review has ${findings.length} findings, exceeding the automatic limit of ${dependencies.policy.maxReviewComments}` + ); + } + if (state.iterations >= dependencies.policy.maxFixIterations) { + if (dependencies.apply) { + await upsertReviewState( + repository, + pullRequestNumber, + { + reviewCursor: state.reviewCursor, + iterations: state.iterations, + headSha: pullRequest.headSha, + status: "needs-approval" + }, + conversationComments, + dependencies + ); + } + return skipped2( + repository, + pullRequestNumber, + "automatic Review fix iteration limit reached" + ); + } + let prepared; + try { + prepared = await dependencies.workspace.prepareReview({ + repository, + pullRequestNumber, + cloneUrl: repositoryCloneUrl(dependencies.serverUrl, repository), + baseBranch: pullRequest.base, + branch: pullRequest.head, + expectedHeadSha: pullRequest.headSha + }); + } catch (error) { + if (error instanceof DraftPrWorkspaceLockError) { + return skipped2( + repository, + pullRequestNumber, + "another review fix run holds the Pull Request lock" + ); + } + throw error; + } + if (dependencies.apply) { + await upsertReviewState( + repository, + pullRequestNumber, + { + reviewCursor: state.reviewCursor, + iterations: state.iterations, + headSha: pullRequest.headSha, + status: "fixing" + }, + conversationComments, + dependencies + ); + } + return { + ok: true, + repository, + pullRequestNumber, + workspacePath: prepared.path, + branch: prepared.branch, + baseBranch: prepared.baseBranch, + expectedHeadSha: prepared.baseCommit, + reviewId: review.id, + reviewFingerprint: fingerprintFindings(findings), + previousReviewCursor: state.reviewCursor, + previousIterations: state.iterations, + findings: findings.map((value) => toFinding(value)) + }; +} +async function applyReviewFix(repository, pullRequestNumber, submissionInput, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + requireReviewBotIdentity(dependencies); + const submission = reviewFixSubmissionSchema.parse(submissionInput); + const [pullRequest, review, conversationComments, reviewComments] = await Promise.all([ + dependencies.provider.getPullRequest(repository, pullRequestNumber), + dependencies.provider.getPullRequestReview( + repository, + pullRequestNumber, + submission.reviewId + ), + dependencies.provider.listComments(repository, pullRequestNumber), + dependencies.provider.listReviewComments(repository, pullRequestNumber) + ]); + const reason = ineligibleReason2(pullRequest, repository, dependencies); + if (reason) throw new Error(reason); + const reviewReason = ineligibleReviewReason(review, pullRequest); + if (reviewReason) throw new Error(reviewReason); + if (pullRequest.headSha !== submission.expectedHeadSha) { + throw new Error("Pull Request head changed after review fix preparation"); + } + const expectedKeys = submission.findingRefs.map(findingKey); + const preparedFindings = findingsForReview(review, reviewComments); + if (new Set(expectedKeys).size !== expectedKeys.length || preparedFindings.length !== submission.findingRefs.length || preparedFindings.some( + (value) => !expectedKeys.includes(findingKey(value)) + ) || fingerprintFindings(preparedFindings) !== submission.reviewFingerprint) { + throw new Error("Pull Request Review changed after fix preparation"); + } + const inspection = await dependencies.workspace.inspect( + submission.workspacePath + ); + if (inspection.headCommit !== submission.expectedHeadSha) { + throw new Error( + "the Agent committed or moved HEAD in the review workspace" + ); + } + validateFindingCoverage(submission.analysis, submission.findingRefs); + const nextIterations = submission.previousIterations + 1; + const nextReviewCursor = Math.max( + submission.previousReviewCursor, + submission.reviewId + ); + if (submission.analysis.outcome !== "fixed") { + if (submission.analysis.outcome === "no_change" && inspection.changedFiles.length > 0) { + throw new Error("no_change review result contains repository changes"); + } + const status = submission.analysis.outcome === "needs_approval" ? "needs-approval" : submission.analysis.outcome === "no_change" ? "no-change" : "failed"; + await finishWithoutPush2( + repository, + pullRequestNumber, + nextReviewCursor, + nextIterations, + submission.expectedHeadSha, + status, + conversationComments, + dependencies + ); + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: submission.analysis.outcome, + inspection + }; + } + validateFixedReview(submission.analysis, inspection); + const approvalReasons = requiresApproval( + submission.analysis, + inspection, + false, + dependencies.policy + ); + if (approvalReasons.length > 0) { + await finishWithoutPush2( + repository, + pullRequestNumber, + nextReviewCursor, + nextIterations, + submission.expectedHeadSha, + "needs-approval", + conversationComments, + dependencies + ); + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: "needs_approval", + inspection + }; + } + if (!dependencies.apply) { + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + return { + ok: true, + repository, + pullRequestNumber, + applied: false, + outcome: "fixed", + inspection + }; + } + const commitTitle = sanitizeTitle(submission.analysis.commitTitle); + const commit = await dependencies.workspace.commitAndPush( + submission.workspacePath, + submission.branch, + commitTitle, + repositoryCloneUrl(dependencies.serverUrl, repository) + ); + await upsertReviewState( + repository, + pullRequestNumber, + { + reviewCursor: nextReviewCursor, + iterations: nextIterations, + headSha: commit, + status: "fixed" + }, + conversationComments, + dependencies + ); + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + return { + ok: true, + repository, + pullRequestNumber, + applied: true, + outcome: "fixed", + commit, + inspection + }; +} +async function failReviewFix(repository, pullRequestNumber, reviewCursor, iterations, headSha, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + try { + if (dependencies.apply) { + const comments = await dependencies.provider.listComments( + repository, + pullRequestNumber + ); + await upsertReviewState( + repository, + pullRequestNumber, + { + reviewCursor, + iterations, + headSha, + status: "failed" + }, + comments, + dependencies + ); + } + } finally { + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); + } + return { + ok: true, + repository, + pullRequestNumber, + applied: dependencies.apply, + outcome: "failed" + }; +} +function findingsForReview(review, reviewComments) { + const findings = []; + if (review.body.trim()) { + findings.push({ + source: "review", + id: review.id, + body: review.body, + ...review.htmlUrl ? { htmlUrl: review.htmlUrl } : {}, + ...review.submittedAt ? { createdAt: review.submittedAt } : {}, + review + }); + } + findings.push( + ...reviewComments.filter( + (comment) => comment.pullRequestReviewId === review.id && !comment.inReplyToId && sameUser(comment.user, review.user) + ).map((comment) => ({ + source: "review_comment", + id: comment.id, + body: comment.body, + ...comment.htmlUrl ? { htmlUrl: comment.htmlUrl } : {}, + ...comment.createdAt ? { createdAt: comment.createdAt } : {}, + comment + })) + ); + return findings.sort(compareSourcedFindings); +} +function ineligibleReason2(pullRequest, repository, dependencies) { + if (pullRequest.state.toLowerCase() !== "open") + return "Pull Request is not open"; + if (!pullRequest.draft) return "Pull Request is not a Draft"; + if (!pullRequest.head.startsWith(dependencies.policy.branchPrefix)) { + return "Pull Request branch is not managed by the Draft PR Agent"; + } + if (pullRequest.headRepository?.trim().toLowerCase() !== repository.trim().toLowerCase()) { + return "Pull Request head repository is not the allowlisted repository"; + } + if (!pullRequest.headSha || !/^[0-9a-f]{40}$/.test(pullRequest.headSha)) { + return "Pull Request has no valid head SHA"; + } + return void 0; +} +function ineligibleReviewReason(review, pullRequest) { + if (review.state.trim().toLowerCase() !== "changes_requested") { + return "Pull Request Review is not a change request"; + } + if (!review.user?.login.trim()) return "Pull Request Review has no author"; + if (!trustedReviewerAssociation(review.authorAssociation)) { + return "Pull Request Review author is not a trusted repository member"; + } + if (review.commitId !== pullRequest.headSha) { + return "Pull Request Review targets a stale head"; + } + return void 0; +} +function trustedReviewerAssociation(value) { + return ["owner", "member", "collaborator"].includes( + value.trim().toLowerCase() + ); +} +function sameUser(left, right) { + if (!left || !right) return false; + if (left.id !== void 0 && right.id !== void 0) + return left.id === right.id; + return left.login.trim().toLowerCase() === right.login.trim().toLowerCase(); +} +function validateFindingCoverage(analysis, expectedFindings) { + const actual = analysis.findings.map(findingKey); + const expected = expectedFindings.map(findingKey); + if (new Set(actual).size !== actual.length || actual.length !== expected.length || expected.some((key) => !actual.includes(key))) { + throw new Error("review result must address every prepared finding once"); + } + if (analysis.outcome === "fixed" && analysis.findings.some( + (finding) => finding.disposition === "needs_approval" + )) { + throw new Error( + "fixed review result cannot contain approval-gated findings" + ); + } + if (analysis.outcome === "no_change" && analysis.findings.some( + (finding) => finding.disposition !== "not_reproducible" + )) { + throw new Error( + "no_change review result requires every finding to be not reproducible" + ); + } +} +function validateFixedReview(analysis, inspection) { + if (!sanitizeTitle(analysis.commitTitle)) { + throw new Error("fixed review result requires a commit title"); + } + if (inspection.changedFiles.length === 0) { + throw new Error("fixed review result requires a non-empty change"); + } + if (!inspection.diffCheckPassed) { + throw new Error("git diff --check rejected the review fix"); + } + if (inspection.secretFindingPaths.length > 0) { + throw new Error( + `possible credential material detected in: ${inspection.secretFindingPaths.join(", ")}` + ); + } + if (analysis.validationOverride && !hasConsistentValidationOverride(analysis)) { + throw new Error( + "fixed review result has an inconsistent validation override" + ); + } + if (analysis.tests.some((test) => test.status === "failed") && !hasConsistentValidationOverride(analysis)) { + throw new Error("fixed review result reports a failed validation command"); + } +} +async function finishWithoutPush2(repository, pullRequestNumber, reviewCursor, iterations, headSha, status, comments, dependencies) { + if (dependencies.apply) { + await upsertReviewState( + repository, + pullRequestNumber, + { reviewCursor, iterations, headSha, status }, + comments, + dependencies + ); + } + await dependencies.workspace.cleanupReview(repository, pullRequestNumber); +} +async function upsertReviewState(repository, pullRequestNumber, state, comments, dependencies) { + const botLogin = dependencies.botLogin?.trim(); + if (!botLogin) + throw new Error("Draft PR bot login is required in apply mode"); + const body = buildReviewFixComment(state); + const existing = findReviewFixComment(comments, botLogin); + if (existing) { + await dependencies.provider.updateComment( + repository, + pullRequestNumber, + existing.id, + body + ); + } else { + await dependencies.provider.createComment( + repository, + pullRequestNumber, + body + ); + } +} +function reviewState(comments, dependencies) { + const botLogin = dependencies.botLogin?.trim(); + if (!botLogin) return parseReviewFixState(void 0); + return parseReviewFixState(findReviewFixComment(comments, botLogin)); +} +function fingerprintFindings(findings) { + return crypto4.createHash("sha256").update( + JSON.stringify( + findings.map(({ source, id, body, review, comment }) => ({ + source, + id, + body, + author: (review?.user ?? comment?.user)?.login ?? "", + authorId: (review?.user ?? comment?.user)?.id ?? null, + ...review ? { + state: review.state, + commitId: review.commitId, + authorAssociation: review.authorAssociation + } : {}, + ...comment ? { + path: comment.path, + line: comment.line ?? null, + originalLine: comment.originalLine ?? null, + diffHunk: comment.diffHunk ?? "", + commitId: comment.commitId ?? "" + } : {} + })) + ) + ).digest("hex").slice(0, 20); +} +function toFinding({ + source, + id, + body, + htmlUrl, + createdAt, + comment +}) { + return { + source, + commentId: id, + body: truncateText(body, 4e3), + ...htmlUrl ? { htmlUrl } : {}, + ...createdAt ? { createdAt } : {}, + ...comment?.path ? { path: comment.path } : {}, + ...comment?.line !== void 0 ? { line: comment.line } : {}, + ...comment?.originalLine !== void 0 ? { originalLine: comment.originalLine } : {}, + ...comment?.startLine !== void 0 ? { startLine: comment.startLine } : {}, + ...comment?.originalStartLine !== void 0 ? { originalStartLine: comment.originalStartLine } : {}, + ...comment?.side ? { side: comment.side } : {}, + ...comment?.startSide ? { startSide: comment.startSide } : {}, + ...comment?.diffHunk ? { diffHunk: truncateText(comment.diffHunk, 8e3) } : {}, + ...comment?.commitId ? { commitId: comment.commitId } : {}, + ...comment?.originalCommitId ? { originalCommitId: comment.originalCommitId } : {}, + ...comment?.inReplyToId !== void 0 ? { inReplyToId: comment.inReplyToId } : {}, + ...comment?.pullRequestReviewId !== void 0 ? { pullRequestReviewId: comment.pullRequestReviewId } : {} + }; +} +function compareSourcedFindings(left, right) { + const sourceOrder = { review: 0, review_comment: 1 }; + return sourceOrder[left.source] - sourceOrder[right.source] || left.id - right.id; +} +function findingKey(value) { + const commentId = "id" in value ? value.id : value.commentId; + return `${value.source}:${commentId}`; +} +function skipped2(repository, pullRequestNumber, reason) { + return { ok: true, skipped: true, reason, repository, pullRequestNumber }; +} +function requireReviewBotIdentity(dependencies) { + if (dependencies.apply && !dependencies.botLogin?.trim()) { + throw new Error("Draft PR bot login is required in apply mode"); + } +} + +// src/runtime/target-binding.ts +function assertBoundTarget(options) { + const expectedRepository = options.expectedRepository?.trim() ?? ""; + const expectedTargetText = options.expectedTarget?.trim() ?? ""; + if (!expectedRepository && !expectedTargetText) { + if (options.apply) throw new Error(options.errors.missing); + return; + } + if (!expectedRepository || !expectedTargetText) { + throw new Error(options.errors.incomplete); + } + const expectedTarget = Number(expectedTargetText); + if (!isRepositorySlug(expectedRepository) || !Number.isSafeInteger(expectedTarget) || expectedTarget <= 0) { + throw new Error(options.errors.invalid); + } + if (options.repository !== expectedRepository || options.targetNumber !== expectedTarget) { + throw new Error( + options.errors.mismatch(expectedRepository, expectedTarget) + ); + } +} + +// src/draft-pr/target.ts +function assertBoundReviewTarget(repository, pullRequestNumber, apply, environment) { + assertBoundTarget({ + repository, + targetNumber: pullRequestNumber, + apply, + expectedRepository: environment.DRAFT_PR_EXPECTED_REPOSITORY, + expectedTarget: environment.DRAFT_PR_EXPECTED_PULL_REQUEST, + errors: { + missing: "Draft PR review apply mode requires a scheduler-bound Pull Request target", + incomplete: "incomplete scheduler-bound Draft PR review target", + invalid: "invalid scheduler-bound Draft PR review target", + mismatch: () => `requested Pull Request ${repository}#${pullRequestNumber} does not match the scheduler-bound review target` + } + }); +} +function assertBoundDraftPrTarget(repository, issueNumber, apply, environment) { + assertBoundTarget({ + repository, + targetNumber: issueNumber, + apply, + expectedRepository: environment.DRAFT_PR_EXPECTED_REPOSITORY, + expectedTarget: environment.DRAFT_PR_EXPECTED_ISSUE, + errors: { + missing: "Draft PR apply mode requires a scheduler-bound Issue target", + incomplete: "incomplete scheduler-bound Draft PR target", + invalid: "invalid scheduler-bound Draft PR target", + mismatch: () => `requested Issue ${repository}#${issueNumber} does not match the scheduler-bound Draft PR target` + } + }); +} + +// src/issues/managed-comments.ts +var ISSUE_TRIAGE_COMMENT_PREFIX = "`; +} +function findDraftPrComment(comments, botLogin) { + const expected = botLogin.trim().toLowerCase(); + return comments.find( + (comment) => comment.user?.login.trim().toLowerCase() === expected && comment.body.startsWith(DRAFT_PR_COMMENT_PREFIX) + ); +} +function buildDraftPrStatusComment(issueNumber, status, details = {}) { + const lines = [draftPrCommentMarker(issueNumber), "## Draft PR agent", ""]; + if (status === "running") { + lines.push("The repository development Agent has claimed this Issue."); + } else if (status === "needs-approval") { + lines.push("Implementation paused for maintainer approval."); + } else if (status === "pr-open") { + lines.push( + details.pullRequestUrl ? `Draft Pull Request: ${details.pullRequestUrl}` : "A Draft Pull Request was created." + ); + } else if (status === "dry-run") { + lines.push("Dry run completed; no branch or Pull Request was created."); + } else { + lines.push( + "The repository development Agent could not prepare a Draft PR." + ); + } + const reasons = (details.reasons ?? []).map(sanitizeFailureReason).filter(Boolean); + if (reasons.length > 0) { + lines.push("", "### Attention", ""); + for (const reason of reasons.slice(0, 8)) lines.push(`- ${reason}`); + } + const message = sanitizeLine(details.message ?? ""); + if (message) lines.push("", message); + return lines.join("\n"); +} +function sanitizeLine(value) { + return value.replace(//g, "").replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 500); +} +function sanitizeFailureReason(value) { + return sanitizeLine(value).replace( + /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/g, + "" + ).replace(/(Authorization\s*:\s*)(?:Bearer|token)\s+\S+/gi, "$1").replace(/(https?:\/\/)[^\s/@:]+:[^\s/@]+@/gi, "$1@").replace(/([?&](?:access_token|token)=)[^&\s]+/gi, "$1").slice(0, 500); +} + +// src/draft-pr/tool.ts +async function prepareDraftPr(repository, issueNumber, trigger, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + const issue2 = await dependencies.provider.getIssue(repository, issueNumber); + const reason = ineligibleReason3(issue2, trigger, dependencies.policy); + if (reason) { + return { + ok: true, + skipped: true, + reason, + repository, + issueNumber, + trigger, + approved: trigger === "approved" + }; + } + const branch = `${dependencies.policy.branchPrefix}${issueNumber}`; + const existingPullRequests = await dependencies.provider.listOpenPullRequestsByHead(repository, branch); + if (existingPullRequests.length > 0) { + return { + ok: true, + skipped: true, + reason: `an open Pull Request already exists for ${branch}`, + repository, + issueNumber, + trigger, + approved: trigger === "approved" + }; + } + const [baseBranch, comments] = await Promise.all([ + dependencies.provider.getRepositoryDefaultBranch(repository), + dependencies.provider.listComments(repository, issueNumber) + ]); + const contextComments = selectContextComments( + comments, + dependencies.botLogin + ); + const fingerprint = issueFingerprint(issue2, contextComments); + let preparedWorkspace; + try { + preparedWorkspace = await dependencies.workspace.prepare({ + repository, + issueNumber, + cloneUrl: repositoryCloneUrl(dependencies.serverUrl, repository), + baseBranch, + branch + }); + if (dependencies.apply) { + const botLogin = requiredBotLogin(dependencies.botLogin); + await claimIssue( + repository, + issueNumber, + trigger, + dependencies, + botLogin + ); + } + } catch (error) { + if (error instanceof DraftPrWorkspaceLockError) { + return { + ok: true, + skipped: true, + reason: error.message, + repository, + issueNumber, + trigger, + approved: trigger === "approved" + }; + } + await dependencies.workspace.cleanup(repository, issueNumber); + throw error; + } + return { + ok: true, + repository, + issueNumber, + trigger, + approved: trigger === "approved", + issueFingerprint: fingerprint, + issue: issue2, + comments: contextComments, + workspacePath: preparedWorkspace.path, + branch: preparedWorkspace.branch, + baseBranch: preparedWorkspace.baseBranch, + baseCommit: preparedWorkspace.baseCommit + }; +} +async function applyDraftPr(repository, issueNumber, submissionInput, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + const submission = draftPrSubmissionSchema.parse(submissionInput); + const [issue2, comments] = await Promise.all([ + dependencies.provider.getIssue(repository, issueNumber), + dependencies.provider.listComments(repository, issueNumber) + ]); + const contextComments = selectContextComments( + comments, + dependencies.botLogin + ); + if (issueFingerprint(issue2, contextComments) !== submission.issueFingerprint) { + throw new Error("Issue changed after the Draft PR Agent started"); + } + if (issue2.state.toLowerCase() !== "open") { + throw new Error("Issue is no longer open"); + } + const inspection = await dependencies.workspace.inspect( + submission.workspacePath + ); + if (inspection.headCommit !== submission.baseCommit) { + throw new Error( + "the Agent committed or moved HEAD inside the prepared workspace" + ); + } + const analysis = submission.analysis; + if (analysis.outcome !== "implemented") { + const reasons = analysis.outcome === "needs_approval" ? outcomeReasons(analysis) : failureReasons(analysis); + if (analysis.outcome === "needs_approval") { + await transitionNeedsApproval( + repository, + issueNumber, + reasons, + dependencies + ); + } else { + await transitionFailed(repository, issueNumber, reasons, dependencies); + } + await dependencies.workspace.cleanup(repository, issueNumber); + return { + ok: true, + repository, + issueNumber, + applied: dependencies.apply, + outcome: analysis.outcome, + branch: submission.branch, + inspection + }; + } + validateImplementedAnalysis(analysis, inspection); + const approvalReasons = requiresApproval( + analysis, + inspection, + submission.trigger === "approved", + dependencies.policy + ); + if (approvalReasons.length > 0) { + await transitionNeedsApproval( + repository, + issueNumber, + approvalReasons, + dependencies + ); + await dependencies.workspace.cleanup(repository, issueNumber); + return { + ok: true, + repository, + issueNumber, + applied: dependencies.apply, + outcome: "needs_approval", + branch: submission.branch, + inspection + }; + } + const title = sanitizeTitle(analysis.prTitle); + const body = buildPullRequestBody(issueNumber, analysis); + if (!dependencies.apply) { + await dependencies.workspace.cleanup(repository, issueNumber); + return { + ok: true, + repository, + issueNumber, + applied: false, + outcome: "implemented", + branch: submission.branch, + proposedTitle: title, + proposedBody: body, + inspection + }; + } + const commit = await dependencies.workspace.commitAndPush( + submission.workspacePath, + submission.branch, + title, + repositoryCloneUrl(dependencies.serverUrl, repository) + ); + const pullRequest = await dependencies.provider.createDraftPullRequest( + repository, + { + title, + body, + head: submission.branch, + base: submission.baseBranch + } + ); + await transitionPullRequestOpen( + repository, + issueNumber, + pullRequest.url, + dependencies + ); + await dependencies.workspace.cleanup(repository, issueNumber); + return { + ok: true, + repository, + issueNumber, + applied: true, + outcome: "implemented", + branch: submission.branch, + commit, + pullRequestNumber: pullRequest.number, + pullRequestUrl: pullRequest.url, + inspection + }; +} +async function failDraftPr(repository, issueNumber, message, dependencies) { + assertAllowedRepository(repository, dependencies.allowedRepository); + try { + if (dependencies.apply) { + await transitionFailed(repository, issueNumber, [message], dependencies); + } + } finally { + await dependencies.workspace.cleanup(repository, issueNumber); + } + return { + ok: true, + repository, + issueNumber, + applied: dependencies.apply, + outcome: "failed" + }; +} +function ineligibleReason3(issue2, trigger, policy) { + if (issue2.state.toLowerCase() !== "open") return "Issue is not open"; + if (hasAnyLabel(issue2.labels, policy.skipLabels)) { + return "Issue has a configured skip label"; + } + if (hasAnyLabel(issue2.labels, policy.blockedLabels)) { + return "Issue has a label that blocks Draft PR execution"; + } + const triggerLabel = trigger === "approved" ? policy.approvedLabel : policy.readyLabel; + if (!hasLabel(issue2.labels, triggerLabel)) { + return `Issue does not have ${triggerLabel}`; + } + if (trigger === "approved" && !hasLabel(issue2.labels, policy.needsApprovalLabel)) { + return `Issue does not have ${policy.needsApprovalLabel}`; + } + return void 0; +} +async function claimIssue(repository, issueNumber, trigger, dependencies, botLogin) { + const policy = dependencies.policy; + await ensureWorkflowLabels(repository, [policy.runningLabel], dependencies); + await dependencies.provider.addLabels(repository, issueNumber, [ + policy.runningLabel + ]); + await dependencies.provider.removeLabel( + repository, + issueNumber, + trigger === "approved" ? policy.approvedLabel : policy.readyLabel + ); + await dependencies.provider.removeLabel( + repository, + issueNumber, + policy.failedLabel + ); + if (trigger === "approved") { + await dependencies.provider.removeLabel( + repository, + issueNumber, + policy.needsApprovalLabel + ); + } + await upsertStatusComment( + repository, + issueNumber, + buildDraftPrStatusComment(issueNumber, "running"), + dependencies, + botLogin + ); +} +async function transitionNeedsApproval(repository, issueNumber, reasons, dependencies) { + if (!dependencies.apply) return; + const botLogin = requiredBotLogin(dependencies.botLogin); + const policy = dependencies.policy; + await ensureWorkflowLabels( + repository, + [policy.needsApprovalLabel], + dependencies + ); + await dependencies.provider.addLabels(repository, issueNumber, [ + policy.needsApprovalLabel + ]); + await dependencies.provider.removeLabel( + repository, + issueNumber, + policy.runningLabel + ); + await upsertStatusComment( + repository, + issueNumber, + buildDraftPrStatusComment(issueNumber, "needs-approval", { reasons }), + dependencies, + botLogin + ); +} +async function transitionFailed(repository, issueNumber, reasons, dependencies) { + if (!dependencies.apply) return; + const botLogin = requiredBotLogin(dependencies.botLogin); + const policy = dependencies.policy; + await ensureWorkflowLabels(repository, [policy.failedLabel], dependencies); + await dependencies.provider.addLabels(repository, issueNumber, [ + policy.failedLabel + ]); + await dependencies.provider.removeLabel( + repository, + issueNumber, + policy.runningLabel + ); + await upsertStatusComment( + repository, + issueNumber, + buildDraftPrStatusComment(issueNumber, "failed", { reasons }), + dependencies, + botLogin + ); +} +async function transitionPullRequestOpen(repository, issueNumber, pullRequestUrl, dependencies) { + const botLogin = requiredBotLogin(dependencies.botLogin); + const policy = dependencies.policy; + await ensureWorkflowLabels(repository, [policy.prOpenLabel], dependencies); + await dependencies.provider.addLabels(repository, issueNumber, [ + policy.prOpenLabel + ]); + await dependencies.provider.removeLabel( + repository, + issueNumber, + policy.runningLabel + ); + await upsertStatusComment( + repository, + issueNumber, + buildDraftPrStatusComment(issueNumber, "pr-open", { pullRequestUrl }), + dependencies, + botLogin + ); +} +async function ensureWorkflowLabels(repository, labels, dependencies) { + for (const label of labels) { + await dependencies.provider.ensureLabel( + repository, + label, + dependencies.policy.labelColors[label] ?? "ededed" + ); + } +} +async function upsertStatusComment(repository, issueNumber, body, dependencies, botLogin) { + const comments = await dependencies.provider.listComments( + repository, + issueNumber + ); + const existing = findDraftPrComment(comments, botLogin); + if (existing) { + await dependencies.provider.updateComment( + repository, + issueNumber, + existing.id, + body + ); + } else { + await dependencies.provider.createComment(repository, issueNumber, body); + } +} +function selectContextComments(comments, botLogin) { + const expectedBot = botLogin?.trim().toLowerCase(); + return comments.filter((comment) => { + const managedBot = expectedBot && comment.user?.login.trim().toLowerCase() === expectedBot; + return !(managedBot && (comment.body.startsWith(DRAFT_PR_COMMENT_PREFIX) || isIssueTriageComment(comment.body))); + }).sort((left, right) => left.id - right.id).slice(-50).map((comment) => ({ + ...comment, + body: truncateText(comment.body, 4e3) + })); +} +function validateImplementedAnalysis(analysis, inspection) { + if (!sanitizeTitle(analysis.prTitle)) { + throw new Error("implemented result requires a Pull Request title"); + } + if (inspection.changedFiles.length === 0) { + throw new Error( + "implemented result requires a non-empty repository change" + ); + } + if (!inspection.diffCheckPassed) { + throw new Error("git diff --check rejected the repository change"); + } + if (inspection.secretFindingPaths.length > 0) { + throw new Error( + `possible credential material detected in: ${inspection.secretFindingPaths.join(", ")}` + ); + } + if (analysis.validationOverride && !hasConsistentValidationOverride(analysis)) { + throw new Error( + "implemented result has an inconsistent validation override" + ); + } + if (analysis.tests.some((test) => test.status === "failed") && !hasConsistentValidationOverride(analysis)) { + throw new Error("implemented result reports a failed validation command"); + } +} +function outcomeReasons(analysis) { + return [ + ...analysis.risk.reasons, + ...analysis.notes, + ...analysis.summary + ].slice(0, 8); +} +function failureReasons(analysis) { + const validationFailures = analysis.tests.filter((test) => test.status === "failed" || test.status === "not_run").map((test) => { + const prefix = test.status === "failed" ? "Validation failed" : "Validation not run"; + return `${prefix}: ${test.command}${test.details ? ` \u2014 ${test.details}` : ""}`; + }); + return [ + ...validationFailures, + ...analysis.risk.reasons, + ...analysis.notes, + ...analysis.summary + ].slice(0, 8); +} +function buildPullRequestBody(issueNumber, analysis) { + const lines = [`Closes #${issueNumber}`, "", "## Summary", ""]; + for (const item of analysis.summary) lines.push(`- ${sanitizeLine2(item)}`); + lines.push("", "## Validation", ""); + if (analysis.tests.length === 0) { + lines.push("- Not reported."); + } else { + for (const test of analysis.tests) { + lines.push( + `- \`${sanitizeCode(test.command)}\` \u2014 ${test.status}${test.details ? `: ${sanitizeLine2(test.details)}` : ""}` + ); + } + } + if (analysis.validationOverride) { + lines.push( + "", + "## Validation override", + "", + `- Classification: \`${analysis.validationOverride.classification}\``, + `- Source: \`${analysis.validationOverride.source}\``, + `- Reason: ${sanitizeLine2(analysis.validationOverride.reason)}` + ); + } + lines.push("", "## Risk", "", `- Level: \`${analysis.risk.level}\``); + for (const reason of analysis.risk.reasons) { + lines.push(`- ${sanitizeLine2(reason)}`); + } + if (analysis.notes.length > 0) { + lines.push("", "## Notes", ""); + for (const note of analysis.notes) lines.push(`- ${sanitizeLine2(note)}`); + } + lines.push( + "", + "_Prepared by the repository development Agent and opened as a Draft Pull Request for maintainer review._" + ); + return lines.join("\n"); +} +function sanitizeLine2(value) { + return value.replace(//g, "").replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 500); +} +function sanitizeCode(value) { + return sanitizeLine2(value).replace(/`/g, "'"); +} +function requiredBotLogin(value) { + const normalized = value?.trim(); + if (!normalized) + throw new Error("Draft PR bot login is required in apply mode"); + return normalized; +} + +// src/draft-pr/main.ts +async function main() { + const options = parseArguments(process.argv.slice(2)); + const apply = envBoolean(process.env.DRAFT_PR_APPLY); + const allowedRepository = process.env.DRAFT_PR_ALLOWED_REPOSITORY?.trim() || process.env.GITHUB_ALLOWED_REPOSITORY?.trim() || ""; + if (["prepare", "inspect-validation", "apply", "fail"].includes(options.command)) { + assertBoundDraftPrTarget( + options.repository, + options.issueNumber, + apply, + process.env + ); + } else { + assertBoundReviewTarget( + options.repository, + options.pullRequestNumber, + apply, + process.env + ); + } + if (options.command === "inspect-validation") { + assertAllowedRepository(options.repository, allowedRepository); + const result2 = await fingerprintDraftPrWorkspace( + process.env.DRAFT_PR_WORKSPACE_ROOT?.trim() || "/draft-pr-workspaces", + options.workspacePath + ); + process.stdout.write(`${JSON.stringify(result2, null, 2)} +`); + return; + } + const policy = await loadPolicy(); + const token = await resolveGitHubToken(options.repository); + const provider = new GitHubClient({ + ...token ? { token } : {}, + ...process.env.GITHUB_API_URL ? { baseUrl: process.env.GITHUB_API_URL } : {} + }); + const workspace = new GitDraftPrWorkspace({ + root: process.env.DRAFT_PR_WORKSPACE_ROOT?.trim() || "/draft-pr-workspaces", + token, + authorName: process.env.DRAFT_PR_GIT_AUTHOR_NAME?.trim() || "engineering-agent-workflows", + authorEmail: process.env.DRAFT_PR_GIT_AUTHOR_EMAIL?.trim() || "engineering-agent-workflows@users.noreply.github.com", + ...process.env.DRAFT_PR_GIT_CURL_RESOLVE ? { gitCurlResolve: process.env.DRAFT_PR_GIT_CURL_RESOLVE } : {} + }); + const dependencies = { + provider, + workspace, + policy, + allowedRepository, + serverUrl: process.env.GITHUB_SERVER_URL?.trim() || "https://github.com", + apply, + ...process.env.GITHUB_BOT_LOGIN ? { botLogin: process.env.GITHUB_BOT_LOGIN } : {} + }; + const result = options.command === "prepare" ? await prepareDraftPr( + options.repository, + options.issueNumber, + options.trigger, + dependencies + ) : options.command === "apply" ? await applyDraftPr( + options.repository, + options.issueNumber, + JSON.parse( + await readFile2(options.analysisFile, "utf8") + ), + dependencies + ) : options.command === "fail" ? await failDraftPr( + options.repository, + options.issueNumber, + options.message ?? "Draft PR Agent execution failed", + dependencies + ) : options.command === "prepare-review" ? await prepareReviewFix( + options.repository, + options.pullRequestNumber, + options.reviewId, + dependencies + ) : options.command === "apply-review" ? await applyReviewFix( + options.repository, + options.pullRequestNumber, + JSON.parse( + await readFile2(options.analysisFile, "utf8") + ), + dependencies + ) : options.command === "fail-review" ? await failReviewFix( + options.repository, + options.pullRequestNumber, + options.reviewCursor ?? 0, + options.iterations ?? 0, + options.headSha ?? "", + dependencies + ) : options.command === "prepare-ci" ? await prepareCiFix( + options.repository, + options.pullRequestNumber, + options.headSha ?? "", + options.checkSuiteId ?? 0, + dependencies + ) : options.command === "apply-ci" ? await applyCiFix( + options.repository, + options.pullRequestNumber, + JSON.parse( + await readFile2(options.analysisFile, "utf8") + ), + dependencies + ) : await failCiFix( + options.repository, + options.pullRequestNumber, + options.checkSuiteId ?? 0, + options.attempts ?? 0, + options.headSha ?? "", + dependencies + ); + process.stdout.write(`${JSON.stringify(result, null, 2)} +`); +} +async function loadPolicy() { + const embedded = process.env.WORKFLOW_POLICY_JSON?.trim(); + if (embedded) { + try { + return draftPrPolicySchema.parse(JSON.parse(embedded)); + } catch (error) { + throw new Error( + `failed to load embedded Draft PR policy: ${errorMessage(error)}` + ); + } + } + return loadJsonFromCandidates( + [ + fileURLToPath(new URL("../policy.json", import.meta.url)), + path2.resolve("agents/draft-pr/policy.json") + ], + (value) => draftPrPolicySchema.parse(value), + "failed to load Draft PR policy" + ); +} +function parseArguments(args) { + const command = args.shift(); + if (command !== "prepare" && command !== "inspect-validation" && command !== "apply" && command !== "fail" && command !== "prepare-review" && command !== "apply-review" && command !== "fail-review" && command !== "prepare-ci" && command !== "apply-ci" && command !== "fail-ci") { + throw new Error("invalid Draft PR tool command"); + } + let repository = ""; + let issueNumber = 0; + let pullRequestNumber = 0; + let trigger = ""; + let analysisFile = ""; + let message = ""; + let reviewId = 0; + let reviewCursor = 0; + let iterations = 0; + let headSha = ""; + let checkSuiteId = 0; + let attempts = 0; + let workspacePath = ""; + for (let index = 0; index < args.length; index += 1) { + const argument = args[index]; + if (argument === "--repository") { + repository = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--issue") { + issueNumber = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--pull-request") { + pullRequestNumber = Number( + requiredArgumentValue(args, ++index, argument) + ); + } else if (argument === "--trigger") { + trigger = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--analysis") { + analysisFile = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--message") { + message = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--review") { + reviewId = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--review-cursor") { + reviewCursor = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--iterations") { + iterations = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--head") { + headSha = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--check-suite") { + checkSuiteId = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--attempts") { + attempts = Number(requiredArgumentValue(args, ++index, argument)); + } else if (argument === "--workspace") { + workspacePath = requiredArgumentValue(args, ++index, argument); + } else { + throw new Error(`unknown argument: ${argument}`); + } + } + if (!isRepositorySlug(repository)) { + throw new Error("--repository must use owner/repository format"); + } + if (["prepare", "inspect-validation", "apply", "fail"].includes(command) && (!Number.isSafeInteger(issueNumber) || issueNumber <= 0)) { + throw new Error("--issue must be a positive integer"); + } + if ([ + "prepare-review", + "apply-review", + "fail-review", + "prepare-ci", + "apply-ci", + "fail-ci" + ].includes(command) && (!Number.isSafeInteger(pullRequestNumber) || pullRequestNumber <= 0)) { + throw new Error("--pull-request must be a positive integer"); + } + if (command === "prepare" && trigger !== "ready" && trigger !== "approved") { + throw new Error("prepare requires --trigger ready or approved"); + } + if (command === "inspect-validation" && !workspacePath) { + throw new Error("inspect-validation requires --workspace"); + } + if (command === "prepare-review" && (!Number.isSafeInteger(reviewId) || reviewId <= 0)) { + throw new Error("prepare-review requires --review"); + } + if ((command === "apply" || command === "apply-review" || command === "apply-ci") && !analysisFile) { + throw new Error(`${command} requires --analysis`); + } + return { + command, + repository, + ...issueNumber ? { issueNumber } : {}, + ...pullRequestNumber ? { pullRequestNumber } : {}, + ...trigger === "ready" || trigger === "approved" ? { trigger } : {}, + ...analysisFile ? { analysisFile } : {}, + ...message ? { message } : {}, + ...reviewId ? { reviewId } : {}, + ...reviewCursor ? { reviewCursor } : {}, + ...iterations ? { iterations } : {}, + ...headSha ? { headSha } : {}, + ...Number.isSafeInteger(checkSuiteId) && checkSuiteId > 0 ? { checkSuiteId } : {}, + ...Number.isSafeInteger(attempts) && attempts >= 0 ? { attempts } : {}, + ...workspacePath ? { workspacePath } : {} + }; +} +main().catch((error) => { + process.stderr.write(`draft-pr failed: ${errorMessage(error)} +`); + process.exitCode = 1; +}); diff --git a/agents/issue-triage/scheduler.js b/agents/issue-triage/scheduler.js index acac795..2d432e0 100644 --- a/agents/issue-triage/scheduler.js +++ b/agents/issue-triage/scheduler.js @@ -10,22 +10,9 @@ const GITHUB_ISSUE_ACTIONS = [ ]; const GITHUB_COMMENT_ACTIONS = ["created", "edited", "deleted"]; const GITHUB_TRIAGE_CONTROL_LABEL = "skip-triage"; -const WORKFLOW_TOOL_BASE64 = "dmFyIF9fZGVmUHJvcCA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eTsKdmFyIF9fZXhwb3J0ID0gKHRhcmdldCwgYWxsKSA9PiB7CiAgZm9yICh2YXIgbmFtZSBpbiBhbGwpCiAgICBfX2RlZlByb3AodGFyZ2V0LCBuYW1lLCB7IGdldDogYWxsW25hbWVdLCBlbnVtZXJhYmxlOiB0cnVlIH0pOwp9OwoKLy8gc3JjL2lzc3VlLXRyaWFnZS9tYWluLnRzCmltcG9ydCB7IHJlYWRGaWxlIGFzIHJlYWRGaWxlMiB9IGZyb20gIm5vZGU6ZnMvcHJvbWlzZXMiOwppbXBvcnQgcGF0aCBmcm9tICJub2RlOnBhdGgiOwppbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAibm9kZTp1cmwiOwoKLy8gc3JjL2dpdGh1Yi9hcHAtYXV0aC50cwppbXBvcnQgeyBzaWduIH0gZnJvbSAibm9kZTpjcnlwdG8iOwoKLy8gc3JjL2dpdGh1Yi9mZXRjaC1yZXRyeS50cwp2YXIgTUFYX0FUVEVNUFRTID0gMzsKdmFyIFJFVFJZQUJMRV9TVEFUVVNfQ09ERVMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbNTAyLCA1MDMsIDUwNF0pOwphc3luYyBmdW5jdGlvbiBmZXRjaFdpdGhSZXRyeShvcHRpb25zKSB7CiAgY29uc3QgYXR0ZW1wdHMgPSBvcHRpb25zLnJldHJ5YWJsZSA/IE1BWF9BVFRFTVBUUyA6IDE7CiAgbGV0IGxhc3RFcnJvcjsKICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBhdHRlbXB0czsgYXR0ZW1wdCArPSAxKSB7CiAgICB0cnkgewogICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IG9wdGlvbnMucmVxdWVzdChvcHRpb25zLmlucHV0LCBvcHRpb25zLmluaXQpOwogICAgICBpZiAoYXR0ZW1wdCA9PT0gYXR0ZW1wdHMgfHwgIVJFVFJZQUJMRV9TVEFUVVNfQ09ERVMuaGFzKHJlc3BvbnNlLnN0YXR1cykpIHsKICAgICAgICByZXR1cm4gcmVzcG9uc2U7CiAgICAgIH0KICAgICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCkuY2F0Y2goKCkgPT4gdm9pZCAwKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIGxhc3RFcnJvciA9IGVycm9yOwogICAgICBpZiAoYXR0ZW1wdCA9PT0gYXR0ZW1wdHMpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICAgICBgJHtvcHRpb25zLm9wZXJhdGlvbn0gdHJhbnNwb3J0IGZhaWxlZCBhZnRlciAke2F0dGVtcHRMYWJlbChhdHRlbXB0cyl9YCwKICAgICAgICAgIHsgY2F1c2U6IGVycm9yIH0KICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBhd2FpdCAob3B0aW9ucy5zbGVlcCA/PyBzbGVlcCkocmV0cnlEZWxheU1pbGxpc2Vjb25kcyhhdHRlbXB0KSk7CiAgfQogIHRocm93IG5ldyBFcnJvcihgJHtvcHRpb25zLm9wZXJhdGlvbn0gdHJhbnNwb3J0IGZhaWxlZGAsIHsKICAgIGNhdXNlOiBsYXN0RXJyb3IKICB9KTsKfQpmdW5jdGlvbiBhdHRlbXB0TGFiZWwoYXR0ZW1wdHMpIHsKICByZXR1cm4gYCR7YXR0ZW1wdHN9ICR7YXR0ZW1wdHMgPT09IDEgPyAiYXR0ZW1wdCIgOiAiYXR0ZW1wdHMifWA7Cn0KZnVuY3Rpb24gcmV0cnlEZWxheU1pbGxpc2Vjb25kcyhhdHRlbXB0KSB7CiAgY29uc3QgZXhwb25lbnRpYWwgPSAyNTAgKiAyICoqIChhdHRlbXB0IC0gMSk7CiAgcmV0dXJuIGV4cG9uZW50aWFsICsgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogZXhwb25lbnRpYWwpOwp9CmZ1bmN0aW9uIHNsZWVwKG1pbGxpc2Vjb25kcykgewogIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtaWxsaXNlY29uZHMpKTsKfQoKLy8gc3JjL2dpdGh1Yi9hcHAtYXV0aC50cwp2YXIgREVGQVVMVF9HSVRIVUJfQVBJX1VSTCA9ICJodHRwczovL2FwaS5naXRodWIuY29tIjsKdmFyIEdJVEhVQl9BUElfVkVSU0lPTiA9ICIyMDIyLTExLTI4IjsKYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUdpdEh1YlRva2VuKHJlcG9zaXRvcnksIGVudiA9IHByb2Nlc3MuZW52LCBkZXBlbmRlbmNpZXMgPSB7fSkgewogIGNvbnN0IGNvbmZpZ3VyZWRUb2tlbiA9IGVudi5HSVRIVUJfVE9LRU4/LnRyaW0oKSA/PyAiIjsKICBpZiAoY29uZmlndXJlZFRva2VuKSByZXR1cm4gY29uZmlndXJlZFRva2VuOwogIGNvbnN0IGNsaWVudElEID0gZW52LkdJVEhVQl9BUFBfQ0xJRU5UX0lEPy50cmltKCkgPz8gIiI7CiAgY29uc3QgYXBwSUQgPSBlbnYuR0lUSFVCX0FQUF9JRD8udHJpbSgpID8/ICIiOwogIGNvbnN0IHByaXZhdGVLZXlCYXNlNjQgPSBlbnYuR0lUSFVCX0FQUF9QUklWQVRFX0tFWV9CQVNFNjQ/LnRyaW0oKSA/PyAiIjsKICBjb25zdCBjb25maWd1cmVkSW5zdGFsbGF0aW9uSUQgPSBlbnYuR0lUSFVCX0FQUF9JTlNUQUxMQVRJT05fSUQ/LnRyaW0oKSA/PyAiIjsKICBjb25zdCBoYXNBcHBDb25maWd1cmF0aW9uID0gQm9vbGVhbigKICAgIGNsaWVudElEIHx8IGFwcElEIHx8IHByaXZhdGVLZXlCYXNlNjQgfHwgY29uZmlndXJlZEluc3RhbGxhdGlvbklECiAgKTsKICBpZiAoIWhhc0FwcENvbmZpZ3VyYXRpb24pIHJldHVybiAiIjsKICBjb25zdCBpc3N1ZXIgPSBjbGllbnRJRCB8fCBhcHBJRDsKICBpZiAoIWlzc3VlcikgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAiR2l0SHViIEFwcCBhdXRoZW50aWNhdGlvbiByZXF1aXJlcyBHSVRIVUJfQVBQX0NMSUVOVF9JRCBvciBHSVRIVUJfQVBQX0lEIgogICAgKTsKICB9CiAgaWYgKCFwcml2YXRlS2V5QmFzZTY0KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHaXRIdWIgQXBwIGF1dGhlbnRpY2F0aW9uIHJlcXVpcmVzIEdJVEhVQl9BUFBfUFJJVkFURV9LRVlfQkFTRTY0IgogICAgKTsKICB9CiAgY29uc3QgcHJpdmF0ZUtleSA9IGRlY29kZVByaXZhdGVLZXkocHJpdmF0ZUtleUJhc2U2NCk7CiAgY29uc3Qgand0ID0gY3JlYXRlQXBwSldUKAogICAgaXNzdWVyLAogICAgcHJpdmF0ZUtleSwKICAgIGRlcGVuZGVuY2llcy5ub3c/LigpID8/IERhdGUubm93KCkKICApOwogIGNvbnN0IGJhc2VVcmwgPSAoZW52LkdJVEhVQl9BUElfVVJMPy50cmltKCkgfHwgREVGQVVMVF9HSVRIVUJfQVBJX1VSTCkucmVwbGFjZSgvXC8rJC8sICIiKTsKICBjb25zdCByZXF1ZXN0ID0gZGVwZW5kZW5jaWVzLmZldGNoID8/IGZldGNoOwogIGNvbnN0IGluc3RhbGxhdGlvbklEID0gY29uZmlndXJlZEluc3RhbGxhdGlvbklEID8gdmFsaWRhdGVJbnN0YWxsYXRpb25JRChjb25maWd1cmVkSW5zdGFsbGF0aW9uSUQpIDogYXdhaXQgZmluZEluc3RhbGxhdGlvbklEKAogICAgYmFzZVVybCwKICAgIHJlcG9zaXRvcnksCiAgICBqd3QsCiAgICByZXF1ZXN0LAogICAgZGVwZW5kZW5jaWVzLnNsZWVwCiAgKTsKICBjb25zdCB0b2tlblBhdGggPSBgL2FwcC9pbnN0YWxsYXRpb25zLyR7aW5zdGFsbGF0aW9uSUR9L2FjY2Vzc190b2tlbnNgOwogIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2hXaXRoUmV0cnkoewogICAgcmVxdWVzdCwKICAgIGlucHV0OiBgJHtiYXNlVXJsfSR7dG9rZW5QYXRofWAsCiAgICBpbml0OiB7CiAgICAgIG1ldGhvZDogIlBPU1QiLAogICAgICBoZWFkZXJzOiBhcHBIZWFkZXJzKGp3dCkKICAgIH0sCiAgICBvcGVyYXRpb246IGBHaXRIdWIgQXBwIFBPU1QgJHt0b2tlblBhdGh9YCwKICAgIHJldHJ5YWJsZTogdHJ1ZSwKICAgIC4uLmRlcGVuZGVuY2llcy5zbGVlcCA/IHsgc2xlZXA6IGRlcGVuZGVuY2llcy5zbGVlcCB9IDoge30KICB9KTsKICBpZiAoIXJlc3BvbnNlLm9rKSB7CiAgICB0aHJvdyBnaXRodWJBcHBSZXNwb25zZUVycm9yKCJpbnN0YWxsYXRpb24gdG9rZW4gcmVxdWVzdCIsIHJlc3BvbnNlKTsKICB9CiAgY29uc3QgdmFsdWUgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7CiAgY29uc3QgdG9rZW4gPSB2YWx1ZS50b2tlbj8udHJpbSgpID8/ICIiOwogIGlmICghdG9rZW4pIHsKICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIEFwcCBpbnN0YWxsYXRpb24gdG9rZW4gcmVzcG9uc2UgaGFzIG5vIHRva2VuIik7CiAgfQogIHJldHVybiB0b2tlbjsKfQpmdW5jdGlvbiBjcmVhdGVBcHBKV1QoaXNzdWVyLCBwcml2YXRlS2V5LCBub3dNaWxsaXNlY29uZHMpIHsKICBjb25zdCBub3cgPSBNYXRoLmZsb29yKG5vd01pbGxpc2Vjb25kcyAvIDFlMyk7CiAgY29uc3QgaGVhZGVyID0gZW5jb2RlSldUUGFydCh7IGFsZzogIlJTMjU2IiwgdHlwOiAiSldUIiB9KTsKICBjb25zdCBwYXlsb2FkID0gZW5jb2RlSldUUGFydCh7CiAgICBpYXQ6IG5vdyAtIDYwLAogICAgZXhwOiBub3cgKyA5ICogNjAsCiAgICBpc3M6IGlzc3VlcgogIH0pOwogIGNvbnN0IHVuc2lnbmVkVG9rZW4gPSBgJHtoZWFkZXJ9LiR7cGF5bG9hZH1gOwogIGxldCBzaWduYXR1cmU7CiAgdHJ5IHsKICAgIHNpZ25hdHVyZSA9IHNpZ24oIlJTQS1TSEEyNTYiLCBCdWZmZXIuZnJvbSh1bnNpZ25lZFRva2VuKSwgcHJpdmF0ZUtleSk7CiAgfSBjYXRjaCB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHSVRIVUJfQVBQX1BSSVZBVEVfS0VZX0JBU0U2NCBpcyBub3QgYSB2YWxpZCBSU0EgcHJpdmF0ZSBrZXkiCiAgICApOwogIH0KICByZXR1cm4gYCR7dW5zaWduZWRUb2tlbn0uJHtzaWduYXR1cmUudG9TdHJpbmcoImJhc2U2NHVybCIpfWA7Cn0KYXN5bmMgZnVuY3Rpb24gZmluZEluc3RhbGxhdGlvbklEKGJhc2VVcmwsIHJlcG9zaXRvcnksIGp3dCwgcmVxdWVzdCwgc2xlZXBEZXBlbmRlbmN5KSB7CiAgY29uc3QgcGF0aDIgPSBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgocmVwb3NpdG9yeSl9L2luc3RhbGxhdGlvbmA7CiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaFdpdGhSZXRyeSh7CiAgICByZXF1ZXN0LAogICAgaW5wdXQ6IGAke2Jhc2VVcmx9JHtwYXRoMn1gLAogICAgaW5pdDogewogICAgICBtZXRob2Q6ICJHRVQiLAogICAgICBoZWFkZXJzOiBhcHBIZWFkZXJzKGp3dCkKICAgIH0sCiAgICBvcGVyYXRpb246IGBHaXRIdWIgQXBwIEdFVCAke3BhdGgyfWAsCiAgICByZXRyeWFibGU6IHRydWUsCiAgICAuLi5zbGVlcERlcGVuZGVuY3kgPyB7IHNsZWVwOiBzbGVlcERlcGVuZGVuY3kgfSA6IHt9CiAgfSk7CiAgaWYgKCFyZXNwb25zZS5vaykgewogICAgdGhyb3cgZ2l0aHViQXBwUmVzcG9uc2VFcnJvcigiaW5zdGFsbGF0aW9uIGxvb2t1cCIsIHJlc3BvbnNlKTsKICB9CiAgY29uc3QgdmFsdWUgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7CiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcih2YWx1ZS5pZCkgfHwgKHZhbHVlLmlkID8/IDApIDw9IDApIHsKICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIEFwcCBpbnN0YWxsYXRpb24gcmVzcG9uc2UgaGFzIG5vIHZhbGlkIElEIik7CiAgfQogIHJldHVybiBTdHJpbmcodmFsdWUuaWQpOwp9CmZ1bmN0aW9uIGFwcEhlYWRlcnMoand0KSB7CiAgcmV0dXJuIHsKICAgIEFjY2VwdDogImFwcGxpY2F0aW9uL3ZuZC5naXRodWIranNvbiIsCiAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7and0fWAsCiAgICAiWC1HaXRIdWItQXBpLVZlcnNpb24iOiBHSVRIVUJfQVBJX1ZFUlNJT04sCiAgICAiVXNlci1BZ2VudCI6ICJlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MvZ2l0aHViLWFwcC1hdXRoIgogIH07Cn0KZnVuY3Rpb24gZGVjb2RlUHJpdmF0ZUtleSh2YWx1ZSkgewogIGxldCBkZWNvZGVkOwogIHRyeSB7CiAgICBkZWNvZGVkID0gQnVmZmVyLmZyb20odmFsdWUsICJiYXNlNjQiKS50b1N0cmluZygidXRmOCIpLnRyaW0oKTsKICB9IGNhdGNoIHsKICAgIHRocm93IG5ldyBFcnJvcigiR0lUSFVCX0FQUF9QUklWQVRFX0tFWV9CQVNFNjQgaXMgbm90IHZhbGlkIGJhc2U2NCIpOwogIH0KICBpZiAoIS9eLS0tLS1CRUdJTiAoPzpSU0EgKT9QUklWQVRFIEtFWS0tLS0tLy50ZXN0KGRlY29kZWQpKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJHSVRIVUJfQVBQX1BSSVZBVEVfS0VZX0JBU0U2NCBtdXN0IGRlY29kZSB0byBhIFBFTSBwcml2YXRlIGtleSIKICAgICk7CiAgfQogIHJldHVybiBkZWNvZGVkOwp9CmZ1bmN0aW9uIHZhbGlkYXRlSW5zdGFsbGF0aW9uSUQodmFsdWUpIHsKICBpZiAoIS9eWzEtOV1bMC05XSokLy50ZXN0KHZhbHVlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJHSVRIVUJfQVBQX0lOU1RBTExBVElPTl9JRCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciIpOwogIH0KICByZXR1cm4gdmFsdWU7Cn0KZnVuY3Rpb24gcmVwb3NpdG9yeVBhdGgocmVwb3NpdG9yeSkgewogIGNvbnN0IHBhcnRzID0gcmVwb3NpdG9yeS5zcGxpdCgiLyIpOwogIGlmIChwYXJ0cy5sZW5ndGggIT09IDIgfHwgcGFydHMuc29tZSgocGFydCkgPT4gIXBhcnQudHJpbSgpKSkgewogICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIEdpdEh1YiByZXBvc2l0b3J5OiAke3JlcG9zaXRvcnl9YCk7CiAgfQogIHJldHVybiBwYXJ0cy5tYXAoZW5jb2RlVVJJQ29tcG9uZW50KS5qb2luKCIvIik7Cn0KZnVuY3Rpb24gZW5jb2RlSldUUGFydCh2YWx1ZSkgewogIHJldHVybiBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeSh2YWx1ZSkpLnRvU3RyaW5nKCJiYXNlNjR1cmwiKTsKfQpmdW5jdGlvbiBnaXRodWJBcHBSZXNwb25zZUVycm9yKG9wZXJhdGlvbiwgcmVzcG9uc2UpIHsKICBjb25zdCBzdGF0dXMgPSBgJHtyZXNwb25zZS5zdGF0dXN9JHtyZXNwb25zZS5zdGF0dXNUZXh0ID8gYCAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCA6ICIifWA7CiAgcmV0dXJuIG5ldyBFcnJvcihgR2l0SHViIEFwcCAke29wZXJhdGlvbn0gZmFpbGVkIHdpdGggJHtzdGF0dXN9YCk7Cn0KCi8vIHNyYy9pc3N1ZXMvc2VhcmNoLnRzCmZ1bmN0aW9uIGlzc3VlU2VhcmNoVGV4dCh0aXRsZSkgewogIHJldHVybiB0aXRsZS5yZXBsYWNlKC9eXFtbXlxdXStcXVxzKjo/XHMqLywgIiIpLnJlcGxhY2UoL1siJ2A6Kygpe31bXF1cXF0vZywgIiAiKS5yZXBsYWNlKC9ccysvZywgIiAiKS50cmltKCkuc2xpY2UoMCwgMTIwKTsKfQoKLy8gc3JjL3J1bnRpbWUvdGV4dC50cwpmdW5jdGlvbiB0cnVuY2F0ZVRleHQodmFsdWUsIG1heCkgewogIHJldHVybiB2YWx1ZS5sZW5ndGggPD0gbWF4ID8gdmFsdWUgOiB2YWx1ZS5zbGljZSgwLCBtYXgpOwp9CgovLyBzcmMvZ2l0aHViL2NsaWVudC50cwp2YXIgR2l0SHViQ2xpZW50ID0gY2xhc3MgewogICN0b2tlbjsKICAjYmFzZVVybDsKICAjZmV0Y2g7CiAgI3NsZWVwOwogIGNvbnN0cnVjdG9yKG9wdGlvbnMgPSB7fSkgewogICAgdGhpcy4jdG9rZW4gPSBvcHRpb25zLnRva2VuPy50cmltKCkgPz8gIiI7CiAgICB0aGlzLiNiYXNlVXJsID0gKG9wdGlvbnMuYmFzZVVybCA/PyAiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbSIpLnJlcGxhY2UoCiAgICAgIC9cLyskLywKICAgICAgIiIKICAgICk7CiAgICB0aGlzLiNmZXRjaCA9IG9wdGlvbnMuZmV0Y2ggPz8gZmV0Y2g7CiAgICB0aGlzLiNzbGVlcCA9IG9wdGlvbnMuc2xlZXA7CiAgfQogIGFzeW5jIGdldElzc3VlKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyKSB7CiAgICBjb25zdCBpc3N1ZTIgPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiR0VUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9YAogICAgKTsKICAgIGlmIChpc3N1ZTIucHVsbF9yZXF1ZXN0KSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiR2l0SHViIHB1bGwgcmVxdWVzdCBwYXlsb2FkIGlzIG5vdCBhbiBJc3N1ZSIpOwogICAgfQogICAgcmV0dXJuIG5vcm1hbGl6ZUlzc3VlKGlzc3VlMik7CiAgfQogIGFzeW5jIHNlYXJjaENhbmRpZGF0ZXMocmVwb3NpdG9yeSwgaXNzdWUyLCBsaW1pdCkgewogICAgY29uc3QgdGl0bGUgPSBpc3N1ZVNlYXJjaFRleHQoaXNzdWUyLnRpdGxlKTsKICAgIGlmICghdGl0bGUpIHJldHVybiBbXTsKICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7CiAgICAgIHE6IGByZXBvOiR7cmVwb3NpdG9yeX0gaXM6aXNzdWUgaW46dGl0bGUgJHt0aXRsZX1gLAogICAgICBwZXJfcGFnZTogU3RyaW5nKE1hdGgubWluKE1hdGgubWF4KGxpbWl0ICsgMSwgMSksIDEwMCkpCiAgICB9KTsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvc2VhcmNoL2lzc3Vlcz8ke3F1ZXJ5LnRvU3RyaW5nKCl9YAogICAgKTsKICAgIHJldHVybiAocmVzcG9uc2UuaXRlbXMgPz8gW10pLmZpbHRlcigKICAgICAgKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm51bWJlciAhPT0gaXNzdWUyLm51bWJlciAmJiAhY2FuZGlkYXRlLnB1bGxfcmVxdWVzdAogICAgKS5zbGljZSgwLCBsaW1pdCkubWFwKChjYW5kaWRhdGUpID0+ICh7CiAgICAgIG51bWJlcjogY2FuZGlkYXRlLm51bWJlciwKICAgICAgdGl0bGU6IGNhbmRpZGF0ZS50aXRsZSwKICAgICAgYm9keTogdHJ1bmNhdGVUZXh0KGNhbmRpZGF0ZS5ib2R5ID8/ICIiLCA0ZTMpLAogICAgICBzdGF0ZTogY2FuZGlkYXRlLnN0YXRlLAogICAgICBsYWJlbHM6IGxhYmVsTmFtZXMoY2FuZGlkYXRlLmxhYmVscyksCiAgICAgIHVybDogY2FuZGlkYXRlLmh0bWxfdXJsCiAgICB9KSk7CiAgfQogIGFzeW5jIGxpc3RDb21tZW50cyhyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcikgewogICAgY29uc3QgY29tbWVudHMgPSBbXTsKICAgIGZvciAobGV0IHBhZ2UgPSAxOyA7IHBhZ2UgKz0gMSkgewogICAgICBjb25zdCBiYXRjaCA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICAgIkdFVCIsCiAgICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9L2NvbW1lbnRzP3Blcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIGNvbW1lbnRzLnB1c2goLi4uYmF0Y2gubWFwKG5vcm1hbGl6ZUNvbW1lbnQpKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIGNvbW1lbnRzOwogICAgfQogIH0KICBhc3luYyBlbnN1cmVMYWJlbChyZXBvc2l0b3J5LCBuYW1lLCBjb2xvciwgZGVzY3JpcHRpb24pIHsKICAgIGNvbnN0IHBhdGgyID0gYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vbGFiZWxzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpfWA7CiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuI3Jhd1JlcXVlc3QoIkdFVCIsIHBhdGgyKTsKICAgIGlmIChyZXNwb25zZS5vaykgcmV0dXJuOwogICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gNDA0KSB7CiAgICAgIHRocm93IGF3YWl0IHJlc3BvbnNlRXJyb3IoIkdFVCIsIHBhdGgyLCByZXNwb25zZSk7CiAgICB9CiAgICBhd2FpdCB0aGlzLiNyZXF1ZXN0KCJQT1NUIiwgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vbGFiZWxzYCwgewogICAgICBuYW1lLAogICAgICBjb2xvcjogbm9ybWFsaXplQ29sb3IoY29sb3IpLAogICAgICBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb24/LnRyaW0oKSB8fCAiTWFuYWdlZCBieSBlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MiCiAgICB9KTsKICB9CiAgYXN5bmMgZ2V0UmVwb3NpdG9yeURlZmF1bHRCcmFuY2gocmVwb3NpdG9yeSkgewogICAgY29uc3QgdmFsdWUgPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiR0VUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX1gCiAgICApOwogICAgY29uc3QgYnJhbmNoID0gdmFsdWUuZGVmYXVsdF9icmFuY2g/LnRyaW0oKTsKICAgIGlmICghYnJhbmNoKSB0aHJvdyBuZXcgRXJyb3IoIkdpdEh1YiByZXBvc2l0b3J5IGhhcyBubyBkZWZhdWx0IGJyYW5jaCIpOwogICAgcmV0dXJuIGJyYW5jaDsKICB9CiAgYXN5bmMgZ2V0UHVsbFJlcXVlc3QocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpIHsKICAgIGNvbnN0IHZhbHVlID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzLyR7cHVsbFJlcXVlc3ROdW1iZXJ9YAogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVQdWxsUmVxdWVzdCh2YWx1ZSk7CiAgfQogIGFzeW5jIGxpc3RPcGVuUHVsbFJlcXVlc3RzKHJlcG9zaXRvcnkpIHsKICAgIGNvbnN0IHZhbHVlcyA9IFtdOwogICAgZm9yIChsZXQgcGFnZSA9IDE7IDsgcGFnZSArPSAxKSB7CiAgICAgIGNvbnN0IGJhdGNoID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgICAiR0VUIiwKICAgICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9wdWxscz9zdGF0ZT1vcGVuJnBlcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIHZhbHVlcy5wdXNoKC4uLmJhdGNoLm1hcChub3JtYWxpemVQdWxsUmVxdWVzdCkpOwogICAgICBpZiAoYmF0Y2gubGVuZ3RoIDwgMTAwKSByZXR1cm4gdmFsdWVzOwogICAgfQogIH0KICBhc3luYyBsaXN0UmV2aWV3Q29tbWVudHMocmVwb3NpdG9yeSwgcHVsbFJlcXVlc3ROdW1iZXIpIHsKICAgIGNvbnN0IGNvbW1lbnRzID0gW107CiAgICBmb3IgKGxldCBwYWdlID0gMTsgOyBwYWdlICs9IDEpIHsKICAgICAgY29uc3QgYmF0Y2ggPSBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAgICJHRVQiLAogICAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzLyR7cHVsbFJlcXVlc3ROdW1iZXJ9L2NvbW1lbnRzP3Blcl9wYWdlPTEwMCZwYWdlPSR7cGFnZX1gCiAgICAgICk7CiAgICAgIGNvbW1lbnRzLnB1c2goLi4uYmF0Y2gubWFwKG5vcm1hbGl6ZVJldmlld0NvbW1lbnQpKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIGNvbW1lbnRzOwogICAgfQogIH0KICBhc3luYyBnZXRQdWxsUmVxdWVzdFJldmlldyhyZXBvc2l0b3J5LCBwdWxsUmVxdWVzdE51bWJlciwgcmV2aWV3SWQpIHsKICAgIGNvbnN0IHJldmlldyA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICJHRVQiLAogICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9wdWxscy8ke3B1bGxSZXF1ZXN0TnVtYmVyfS9yZXZpZXdzLyR7cmV2aWV3SWR9YAogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVQdWxsUmVxdWVzdFJldmlldyhyZXZpZXcpOwogIH0KICBhc3luYyBsaXN0Q2hlY2tSdW5zKHJlcG9zaXRvcnksIHJlZikgewogICAgaWYgKCEvXlswLTlhLWZdezQwfSQvLnRlc3QocmVmKSkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoImludmFsaWQgR2l0SHViIGNoZWNrIHJ1biByZWYiKTsKICAgIH0KICAgIGNvbnN0IHJ1bnMgPSBbXTsKICAgIGZvciAobGV0IHBhZ2UgPSAxOyA7IHBhZ2UgKz0gMSkgewogICAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICAgIkdFVCIsCiAgICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vY29tbWl0cy8ke3JlZn0vY2hlY2stcnVucz9wZXJfcGFnZT0xMDAmcGFnZT0ke3BhZ2V9YAogICAgICApOwogICAgICBjb25zdCBiYXRjaCA9IHZhbHVlLmNoZWNrX3J1bnMgPz8gW107CiAgICAgIHJ1bnMucHVzaCguLi5iYXRjaC5tYXAobm9ybWFsaXplQ2hlY2tSdW4pKTsKICAgICAgaWYgKGJhdGNoLmxlbmd0aCA8IDEwMCkgcmV0dXJuIHJ1bnM7CiAgICB9CiAgfQogIGFzeW5jIGxpc3RDaGVja1J1bkFubm90YXRpb25zKHJlcG9zaXRvcnksIGNoZWNrUnVuSWQpIHsKICAgIGlmICghTnVtYmVyLmlzU2FmZUludGVnZXIoY2hlY2tSdW5JZCkgfHwgY2hlY2tSdW5JZCA8PSAwKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiaW52YWxpZCBHaXRIdWIgY2hlY2sgcnVuIElEIik7CiAgICB9CiAgICBjb25zdCBhbm5vdGF0aW9ucyA9IFtdOwogICAgZm9yIChsZXQgcGFnZSA9IDE7IDsgcGFnZSArPSAxKSB7CiAgICAgIGNvbnN0IGJhdGNoID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgICAiR0VUIiwKICAgICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9jaGVjay1ydW5zLyR7Y2hlY2tSdW5JZH0vYW5ub3RhdGlvbnM/cGVyX3BhZ2U9MTAwJnBhZ2U9JHtwYWdlfWAKICAgICAgKTsKICAgICAgYW5ub3RhdGlvbnMucHVzaCguLi5iYXRjaC5tYXAobm9ybWFsaXplQ2hlY2tSdW5Bbm5vdGF0aW9uKSk7CiAgICAgIGlmIChiYXRjaC5sZW5ndGggPCAxMDApIHJldHVybiBhbm5vdGF0aW9uczsKICAgIH0KICB9CiAgYXN5bmMgbGlzdE9wZW5QdWxsUmVxdWVzdHNCeUhlYWQocmVwb3NpdG9yeSwgYnJhbmNoKSB7CiAgICBjb25zdCBvd25lciA9IHJlcG9zaXRvcnkuc3BsaXQoIi8iKVswXTsKICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7CiAgICAgIHN0YXRlOiAib3BlbiIsCiAgICAgIGhlYWQ6IGAke293bmVyfToke2JyYW5jaH1gLAogICAgICBwZXJfcGFnZTogIjEwMCIKICAgIH0pOwogICAgY29uc3QgdmFsdWVzID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIkdFVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L3B1bGxzPyR7cXVlcnkudG9TdHJpbmcoKX1gCiAgICApOwogICAgcmV0dXJuIHZhbHVlcy5tYXAobm9ybWFsaXplUHVsbFJlcXVlc3QpOwogIH0KICBhc3luYyBjcmVhdGVEcmFmdFB1bGxSZXF1ZXN0KHJlcG9zaXRvcnksIGlucHV0KSB7CiAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IHRoaXMuI3JlcXVlc3QoCiAgICAgICJQT1NUIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vcHVsbHNgLAogICAgICB7IC4uLmlucHV0LCBkcmFmdDogdHJ1ZSB9CiAgICApOwogICAgcmV0dXJuIG5vcm1hbGl6ZVB1bGxSZXF1ZXN0KHZhbHVlKTsKICB9CiAgYXN5bmMgYWRkTGFiZWxzKHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBsYWJlbHMpIHsKICAgIGlmIChsYWJlbHMubGVuZ3RoID09PSAwKSByZXR1cm47CiAgICBhd2FpdCB0aGlzLiNyZXF1ZXN0KAogICAgICAiUE9TVCIsCiAgICAgIGAvcmVwb3MvJHtyZXBvc2l0b3J5UGF0aDIocmVwb3NpdG9yeSl9L2lzc3Vlcy8ke2lzc3VlTnVtYmVyfS9sYWJlbHNgLAogICAgICB7IGxhYmVscyB9CiAgICApOwogIH0KICBhc3luYyByZW1vdmVMYWJlbChyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgbGFiZWwpIHsKICAgIGNvbnN0IHBhdGgyID0gYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzLyR7aXNzdWVOdW1iZXJ9L2xhYmVscy8ke2VuY29kZVVSSUNvbXBvbmVudChsYWJlbCl9YDsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmF3UmVxdWVzdCgiREVMRVRFIiwgcGF0aDIpOwogICAgaWYgKCFyZXNwb25zZS5vayAmJiByZXNwb25zZS5zdGF0dXMgIT09IDQwNCkgewogICAgICB0aHJvdyBhd2FpdCByZXNwb25zZUVycm9yKCJERUxFVEUiLCBwYXRoMiwgcmVzcG9uc2UpOwogICAgfQogIH0KICBhc3luYyBjcmVhdGVDb21tZW50KHJlcG9zaXRvcnksIGlzc3VlTnVtYmVyLCBib2R5KSB7CiAgICBjb25zdCBjb21tZW50ID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIlBPU1QiLAogICAgICBgL3JlcG9zLyR7cmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpfS9pc3N1ZXMvJHtpc3N1ZU51bWJlcn0vY29tbWVudHNgLAogICAgICB7IGJvZHkgfQogICAgKTsKICAgIHJldHVybiBub3JtYWxpemVDb21tZW50KGNvbW1lbnQpOwogIH0KICBhc3luYyB1cGRhdGVDb21tZW50KHJlcG9zaXRvcnksIF9pc3N1ZU51bWJlciwgY29tbWVudElELCBib2R5KSB7CiAgICBjb25zdCBjb21tZW50ID0gYXdhaXQgdGhpcy4jcmVxdWVzdCgKICAgICAgIlBBVENIIiwKICAgICAgYC9yZXBvcy8ke3JlcG9zaXRvcnlQYXRoMihyZXBvc2l0b3J5KX0vaXNzdWVzL2NvbW1lbnRzLyR7Y29tbWVudElEfWAsCiAgICAgIHsgYm9keSB9CiAgICApOwogICAgcmV0dXJuIG5vcm1hbGl6ZUNvbW1lbnQoY29tbWVudCk7CiAgfQogIGFzeW5jICNyZXF1ZXN0KG1ldGhvZCwgcGF0aDIsIGJvZHkpIHsKICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy4jcmF3UmVxdWVzdChtZXRob2QsIHBhdGgyLCBib2R5KTsKICAgIGlmICghcmVzcG9uc2Uub2spIHRocm93IGF3YWl0IHJlc3BvbnNlRXJyb3IobWV0aG9kLCBwYXRoMiwgcmVzcG9uc2UpOwogICAgcmV0dXJuIGF3YWl0IHJlc3BvbnNlLmpzb24oKTsKICB9CiAgI3Jhd1JlcXVlc3QobWV0aG9kLCBwYXRoMiwgYm9keSkgewogICAgY29uc3QgaGVhZGVycyA9IHsKICAgICAgQWNjZXB0OiAiYXBwbGljYXRpb24vdm5kLmdpdGh1Yitqc29uIiwKICAgICAgIlgtR2l0SHViLUFwaS1WZXJzaW9uIjogIjIwMjItMTEtMjgiLAogICAgICAiVXNlci1BZ2VudCI6ICJlbmdpbmVlcmluZy1hZ2VudC13b3JrZmxvd3MvaXNzdWUtdHJpYWdlIgogICAgfTsKICAgIGlmICh0aGlzLiN0b2tlbikgaGVhZGVycy5BdXRob3JpemF0aW9uID0gYEJlYXJlciAke3RoaXMuI3Rva2VufWA7CiAgICBpZiAoYm9keSAhPT0gdm9pZCAwKSBoZWFkZXJzWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIjsKICAgIHJldHVybiBmZXRjaFdpdGhSZXRyeSh7CiAgICAgIHJlcXVlc3Q6IHRoaXMuI2ZldGNoLAogICAgICBpbnB1dDogYCR7dGhpcy4jYmFzZVVybH0ke3BhdGgyfWAsCiAgICAgIGluaXQ6IHsKICAgICAgICBtZXRob2QsCiAgICAgICAgaGVhZGVycywKICAgICAgICAuLi5ib2R5ID09PSB2b2lkIDAgPyB7fSA6IHsgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSkgfQogICAgICB9LAogICAgICBvcGVyYXRpb246IGBHaXRIdWIgQVBJICR7bWV0aG9kfSAke3BhdGgyfWAsCiAgICAgIHJldHJ5YWJsZTogbWV0aG9kID09PSAiR0VUIiwKICAgICAgLi4udGhpcy4jc2xlZXAgPyB7IHNsZWVwOiB0aGlzLiNzbGVlcCB9IDoge30KICAgIH0pOwogIH0KfTsKZnVuY3Rpb24gcmVwb3NpdG9yeVBhdGgyKHJlcG9zaXRvcnkpIHsKICBjb25zdCBwYXJ0cyA9IHJlcG9zaXRvcnkuc3BsaXQoIi8iKTsKICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzLnNvbWUoKHBhcnQpID0+ICFwYXJ0LnRyaW0oKSkpIHsKICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBHaXRIdWIgcmVwb3NpdG9yeTogJHtyZXBvc2l0b3J5fWApOwogIH0KICByZXR1cm4gcGFydHMubWFwKGVuY29kZVVSSUNvbXBvbmVudCkuam9pbigiLyIpOwp9CmZ1bmN0aW9uIG5vcm1hbGl6ZUlzc3VlKGlzc3VlMikgewogIHJldHVybiB7CiAgICBudW1iZXI6IGlzc3VlMi5udW1iZXIsCiAgICB0aXRsZTogaXNzdWUyLnRpdGxlLAogICAgYm9keTogaXNzdWUyLmJvZHksCiAgICBzdGF0ZTogaXNzdWUyLnN0YXRlLAogICAgaHRtbFVybDogaXNzdWUyLmh0bWxfdXJsLAogICAgdXBkYXRlZEF0OiBpc3N1ZTIudXBkYXRlZF9hdCwKICAgIGxhYmVsczogbGFiZWxOYW1lcyhpc3N1ZTIubGFiZWxzKSwKICAgIC4uLmlzc3VlMi51c2VyID8geyB1c2VyOiBub3JtYWxpemVVc2VyKGlzc3VlMi51c2VyKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZUNvbW1lbnQoY29tbWVudCkgewogIHJldHVybiB7CiAgICBpZDogY29tbWVudC5pZCwKICAgIGJvZHk6IGNvbW1lbnQuYm9keSwKICAgIC4uLmNvbW1lbnQuaHRtbF91cmwgPyB7IGh0bWxVcmw6IGNvbW1lbnQuaHRtbF91cmwgfSA6IHt9LAogICAgLi4uY29tbWVudC5jcmVhdGVkX2F0ID8geyBjcmVhdGVkQXQ6IGNvbW1lbnQuY3JlYXRlZF9hdCB9IDoge30sCiAgICAuLi5jb21tZW50LnVzZXIgPyB7IHVzZXI6IG5vcm1hbGl6ZVVzZXIoY29tbWVudC51c2VyKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVB1bGxSZXF1ZXN0KHZhbHVlKSB7CiAgcmV0dXJuIHsKICAgIG51bWJlcjogdmFsdWUubnVtYmVyLAogICAgdXJsOiB2YWx1ZS5odG1sX3VybCwKICAgIHN0YXRlOiB2YWx1ZS5zdGF0ZSwKICAgIGRyYWZ0OiB2YWx1ZS5kcmFmdCA/PyBmYWxzZSwKICAgIGhlYWQ6IHZhbHVlLmhlYWQucmVmLAogICAgLi4udmFsdWUuaGVhZC5zaGEgPyB7IGhlYWRTaGE6IHZhbHVlLmhlYWQuc2hhIH0gOiB7fSwKICAgIC4uLnZhbHVlLmhlYWQucmVwbz8uZnVsbF9uYW1lID8geyBoZWFkUmVwb3NpdG9yeTogdmFsdWUuaGVhZC5yZXBvLmZ1bGxfbmFtZSB9IDoge30sCiAgICBiYXNlOiB2YWx1ZS5iYXNlLnJlZgogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplUmV2aWV3Q29tbWVudChjb21tZW50KSB7CiAgcmV0dXJuIHsKICAgIGlkOiBjb21tZW50LmlkLAogICAgYm9keTogY29tbWVudC5ib2R5LAogICAgcGF0aDogY29tbWVudC5wYXRoLAogICAgLi4uY29tbWVudC51c2VyID8geyB1c2VyOiBub3JtYWxpemVVc2VyKGNvbW1lbnQudXNlcikgfSA6IHt9LAogICAgLi4uY29tbWVudC5odG1sX3VybCA/IHsgaHRtbFVybDogY29tbWVudC5odG1sX3VybCB9IDoge30sCiAgICAuLi5jb21tZW50LmNyZWF0ZWRfYXQgPyB7IGNyZWF0ZWRBdDogY29tbWVudC5jcmVhdGVkX2F0IH0gOiB7fSwKICAgIC4uLmNvbW1lbnQubGluZSAhPSBudWxsID8geyBsaW5lOiBjb21tZW50LmxpbmUgfSA6IHt9LAogICAgLi4uY29tbWVudC5vcmlnaW5hbF9saW5lICE9IG51bGwgPyB7IG9yaWdpbmFsTGluZTogY29tbWVudC5vcmlnaW5hbF9saW5lIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQuc3RhcnRfbGluZSAhPSBudWxsID8geyBzdGFydExpbmU6IGNvbW1lbnQuc3RhcnRfbGluZSB9IDoge30sCiAgICAuLi5jb21tZW50Lm9yaWdpbmFsX3N0YXJ0X2xpbmUgIT0gbnVsbCA/IHsgb3JpZ2luYWxTdGFydExpbmU6IGNvbW1lbnQub3JpZ2luYWxfc3RhcnRfbGluZSB9IDoge30sCiAgICAuLi5jb21tZW50LnNpZGUgPyB7IHNpZGU6IGNvbW1lbnQuc2lkZSB9IDoge30sCiAgICAuLi5jb21tZW50LnN0YXJ0X3NpZGUgPyB7IHN0YXJ0U2lkZTogY29tbWVudC5zdGFydF9zaWRlIH0gOiB7fSwKICAgIC4uLmNvbW1lbnQuZGlmZl9odW5rID8geyBkaWZmSHVuazogY29tbWVudC5kaWZmX2h1bmsgfSA6IHt9LAogICAgLi4uY29tbWVudC5jb21taXRfaWQgPyB7IGNvbW1pdElkOiBjb21tZW50LmNvbW1pdF9pZCB9IDoge30sCiAgICAuLi5jb21tZW50Lm9yaWdpbmFsX2NvbW1pdF9pZCA/IHsgb3JpZ2luYWxDb21taXRJZDogY29tbWVudC5vcmlnaW5hbF9jb21taXRfaWQgfSA6IHt9LAogICAgLi4uY29tbWVudC5pbl9yZXBseV90b19pZCAhPT0gdm9pZCAwID8geyBpblJlcGx5VG9JZDogY29tbWVudC5pbl9yZXBseV90b19pZCB9IDoge30sCiAgICAuLi5jb21tZW50LnB1bGxfcmVxdWVzdF9yZXZpZXdfaWQgIT09IHZvaWQgMCA/IHsgcHVsbFJlcXVlc3RSZXZpZXdJZDogY29tbWVudC5wdWxsX3JlcXVlc3RfcmV2aWV3X2lkIH0gOiB7fQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplUHVsbFJlcXVlc3RSZXZpZXcocmV2aWV3KSB7CiAgcmV0dXJuIHsKICAgIGlkOiByZXZpZXcuaWQsCiAgICBib2R5OiByZXZpZXcuYm9keSA/PyAiIiwKICAgIHN0YXRlOiByZXZpZXcuc3RhdGUsCiAgICBjb21taXRJZDogcmV2aWV3LmNvbW1pdF9pZCwKICAgIGF1dGhvckFzc29jaWF0aW9uOiByZXZpZXcuYXV0aG9yX2Fzc29jaWF0aW9uLAogICAgLi4ucmV2aWV3LnVzZXIgPyB7IHVzZXI6IG5vcm1hbGl6ZVVzZXIocmV2aWV3LnVzZXIpIH0gOiB7fSwKICAgIC4uLnJldmlldy5odG1sX3VybCA/IHsgaHRtbFVybDogcmV2aWV3Lmh0bWxfdXJsIH0gOiB7fSwKICAgIC4uLnJldmlldy5zdWJtaXR0ZWRfYXQgPyB7IHN1Ym1pdHRlZEF0OiByZXZpZXcuc3VibWl0dGVkX2F0IH0gOiB7fQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ2hlY2tSdW4odmFsdWUpIHsKICBjb25zdCBjaGVja1N1aXRlSWQgPSB2YWx1ZS5jaGVja19zdWl0ZT8uaWQ7CiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihjaGVja1N1aXRlSWQpIHx8IGNoZWNrU3VpdGVJZCA8PSAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYEdpdEh1YiBjaGVjayBydW4gJHt2YWx1ZS5pZH0gaGFzIG5vIHZhbGlkIGNoZWNrIHN1aXRlIElEYCk7CiAgfQogIHJldHVybiB7CiAgICBpZDogdmFsdWUuaWQsCiAgICBjaGVja1N1aXRlSWQsCiAgICBuYW1lOiB0cnVuY2F0ZVRleHQodmFsdWUubmFtZSA/PyAiIiwgMzAwKSwKICAgIHN0YXR1czogdmFsdWUuc3RhdHVzLAogICAgLi4udmFsdWUuY29uY2x1c2lvbiA/IHsgY29uY2x1c2lvbjogdmFsdWUuY29uY2x1c2lvbiB9IDoge30sCiAgICAuLi52YWx1ZS5odG1sX3VybCA/IHsgaHRtbFVybDogdmFsdWUuaHRtbF91cmwgfSA6IHt9LAogICAgb3V0cHV0OiB7CiAgICAgIHRpdGxlOiB0cnVuY2F0ZVRleHQodmFsdWUub3V0cHV0Py50aXRsZSA/PyAiIiwgMWUzKSwKICAgICAgc3VtbWFyeTogdHJ1bmNhdGVUZXh0KHZhbHVlLm91dHB1dD8uc3VtbWFyeSA/PyAiIiwgOGUzKSwKICAgICAgdGV4dDogdHJ1bmNhdGVUZXh0KHZhbHVlLm91dHB1dD8udGV4dCA/PyAiIiwgOGUzKQogICAgfQogIH07Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ2hlY2tSdW5Bbm5vdGF0aW9uKHZhbHVlKSB7CiAgcmV0dXJuIHsKICAgIHBhdGg6IHRydW5jYXRlVGV4dCh2YWx1ZS5wYXRoID8/ICIiLCAxZTMpLAogICAgc3RhcnRMaW5lOiB2YWx1ZS5zdGFydF9saW5lLAogICAgZW5kTGluZTogdmFsdWUuZW5kX2xpbmUsCiAgICBsZXZlbDogdHJ1bmNhdGVUZXh0KHZhbHVlLmFubm90YXRpb25fbGV2ZWwgPz8gIiIsIDUwKSwKICAgIG1lc3NhZ2U6IHRydW5jYXRlVGV4dCh2YWx1ZS5tZXNzYWdlID8/ICIiLCAyZTMpLAogICAgLi4udmFsdWUudGl0bGUgPyB7IHRpdGxlOiB0cnVuY2F0ZVRleHQodmFsdWUudGl0bGUsIDUwMCkgfSA6IHt9LAogICAgLi4udmFsdWUucmF3X2RldGFpbHMgPyB7IHJhd0RldGFpbHM6IHRydW5jYXRlVGV4dCh2YWx1ZS5yYXdfZGV0YWlscywgNGUzKSB9IDoge30KICB9Owp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVVzZXIodXNlcikgewogIHJldHVybiB7CiAgICBsb2dpbjogdXNlci5sb2dpbiwKICAgIC4uLnVzZXIuaWQgIT09IHZvaWQgMCA/IHsgaWQ6IHVzZXIuaWQgfSA6IHt9LAogICAgLi4udXNlci50eXBlID8geyB0eXBlOiB1c2VyLnR5cGUgfSA6IHt9CiAgfTsKfQpmdW5jdGlvbiBsYWJlbE5hbWVzKGxhYmVscykgewogIHJldHVybiBsYWJlbHMubWFwKChsYWJlbCkgPT4gdHlwZW9mIGxhYmVsID09PSAic3RyaW5nIiA/IGxhYmVsIDogbGFiZWwubmFtZSkuZmlsdGVyKChsYWJlbCkgPT4gbGFiZWwudHJpbSgpICE9PSAiIik7Cn0KZnVuY3Rpb24gbm9ybWFsaXplQ29sb3IoY29sb3IpIHsKICBjb25zdCBub3JtYWxpemVkID0gY29sb3IudHJpbSgpLnJlcGxhY2UoL14jLywgIiIpOwogIHJldHVybiAvXlswLTlhLWZdezZ9JC9pLnRlc3Qobm9ybWFsaXplZCkgPyBub3JtYWxpemVkIDogImVkZWRlZCI7Cn0KYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2VFcnJvcihtZXRob2QsIHBhdGgyLCByZXNwb25zZSkgewogIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gIiIpOwogIHJldHVybiBuZXcgRXJyb3IoCiAgICBgR2l0SHViIEFQSSAke21ldGhvZH0gJHtwYXRoMn0gZmFpbGVkIHdpdGggSFRUUCAke3Jlc3BvbnNlLnN0YXR1c306ICR7dHJ1bmNhdGVUZXh0KHRleHQsIDFlMyl9YAogICk7Cn0KCi8vIHNyYy9pc3N1ZXMvdHlwZXMudHMKZnVuY3Rpb24gaXNSZXBvc2l0b3J5U2x1Zyh2YWx1ZSkgewogIHJldHVybiAvXlteL1xzXStcL1teL1xzXSskLy50ZXN0KHZhbHVlKTsKfQoKLy8gc3JjL3J1bnRpbWUvY2xpLnRzCmZ1bmN0aW9uIHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCBpbmRleCwgbmFtZSkgewogIGNvbnN0IHZhbHVlID0gYXJnc1tpbmRleF0/LnRyaW0oKTsKICBpZiAoIXZhbHVlKSB0aHJvdyBuZXcgRXJyb3IoYCR7bmFtZX0gcmVxdWlyZXMgYSB2YWx1ZWApOwogIHJldHVybiB2YWx1ZTsKfQpmdW5jdGlvbiBlbnZCb29sZWFuKHZhbHVlKSB7CiAgcmV0dXJuIFsiMSIsICJ0cnVlIiwgInllcyIsICJvbiJdLmluY2x1ZGVzKHZhbHVlPy50cmltKCkudG9Mb3dlckNhc2UoKSA/PyAiIik7Cn0KCi8vIHNyYy9ydW50aW1lL2Vycm9ycy50cwpmdW5jdGlvbiBlcnJvck1lc3NhZ2UoZXJyb3IpIHsKICByZXR1cm4gZGVzY3JpYmVFcnJvcihlcnJvciwgLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKSwgMCk7Cn0KZnVuY3Rpb24gZGVzY3JpYmVFcnJvcihlcnJvciwgc2VlbiwgZGVwdGgpIHsKICBpZiAoIShlcnJvciBpbnN0YW5jZW9mIEVycm9yKSkgcmV0dXJuIFN0cmluZyhlcnJvcik7CiAgc2Vlbi5hZGQoZXJyb3IpOwogIGNvbnN0IGNvZGUgPSBlcnJvckNvZGUoZXJyb3IpOwogIGNvbnN0IGRlc2NyaXB0aW9uID0gZGVwdGggPT09IDAgPyBlcnJvci5tZXNzYWdlIDogYCR7ZXJyb3IubmFtZX0ke2NvZGUgPyBgIFske2NvZGV9XWAgOiAiIn06ICR7ZXJyb3IubWVzc2FnZX1gOwogIGlmIChkZXB0aCA+PSA0IHx8IGVycm9yLmNhdXNlID09PSB2b2lkIDAgfHwgc2Vlbi5oYXMoZXJyb3IuY2F1c2UpKSB7CiAgICByZXR1cm4gZGVzY3JpcHRpb247CiAgfQogIHJldHVybiBgJHtkZXNjcmlwdGlvbn07IGNhdXNlOiAke2Rlc2NyaWJlRXJyb3IoZXJyb3IuY2F1c2UsIHNlZW4sIGRlcHRoICsgMSl9YDsKfQpmdW5jdGlvbiBlcnJvckNvZGUoZXJyb3IpIHsKICBpZiAoISgiY29kZSIgaW4gZXJyb3IpKSByZXR1cm4gIiI7CiAgY29uc3QgdmFsdWUgPSBlcnJvci5jb2RlOwogIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciIHx8IHR5cGVvZiB2YWx1ZSA9PT0gIm51bWJlciIgPyBTdHJpbmcodmFsdWUpIDogIiI7Cn0KCi8vIHNyYy9ydW50aW1lL2xvYWQtanNvbi50cwppbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gIm5vZGU6ZnMvcHJvbWlzZXMiOwphc3luYyBmdW5jdGlvbiBsb2FkSnNvbkZyb21DYW5kaWRhdGVzKGNhbmRpZGF0ZXMsIHBhcnNlMywgZmFpbHVyZU1lc3NhZ2UpIHsKICBsZXQgbGFzdEVycm9yOwogIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGNhbmRpZGF0ZXMpIHsKICAgIHRyeSB7CiAgICAgIHJldHVybiBwYXJzZTMoSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShjYW5kaWRhdGUsICJ1dGY4IikpKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIGxhc3RFcnJvciA9IGVycm9yOwogICAgfQogIH0KICB0aHJvdyBuZXcgRXJyb3IoYCR7ZmFpbHVyZU1lc3NhZ2V9OiAke2Vycm9yTWVzc2FnZShsYXN0RXJyb3IpfWApOwp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvY29yZS5qcwp2YXIgX2E7Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uICRjb25zdHJ1Y3RvcihuYW1lLCBpbml0aWFsaXplcjMsIHBhcmFtcykgewogIGZ1bmN0aW9uIGluaXQoaW5zdCwgZGVmKSB7CiAgICBpZiAoIWluc3QuX3pvZCkgewogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgIl96b2QiLCB7CiAgICAgICAgdmFsdWU6IHsKICAgICAgICAgIGRlZiwKICAgICAgICAgIGNvbnN0cjogXywKICAgICAgICAgIHRyYWl0czogLyogQF9fUFVSRV9fICovIG5ldyBTZXQoKQogICAgICAgIH0sCiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UKICAgICAgfSk7CiAgICB9CiAgICBpZiAoaW5zdC5fem9kLnRyYWl0cy5oYXMobmFtZSkpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgaW5zdC5fem9kLnRyYWl0cy5hZGQobmFtZSk7CiAgICBpbml0aWFsaXplcjMoaW5zdCwgZGVmKTsKICAgIGNvbnN0IHByb3RvID0gXy5wcm90b3R5cGU7CiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocHJvdG8pOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7CiAgICAgIGNvbnN0IGsgPSBrZXlzW2ldOwogICAgICBpZiAoIShrIGluIGluc3QpKSB7CiAgICAgICAgaW5zdFtrXSA9IHByb3RvW2tdLmJpbmQoaW5zdCk7CiAgICAgIH0KICAgIH0KICB9CiAgY29uc3QgUGFyZW50ID0gcGFyYW1zPy5QYXJlbnQgPz8gT2JqZWN0OwogIGNsYXNzIERlZmluaXRpb24gZXh0ZW5kcyBQYXJlbnQgewogIH0KICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRGVmaW5pdGlvbiwgIm5hbWUiLCB7IHZhbHVlOiBuYW1lIH0pOwogIGZ1bmN0aW9uIF8oZGVmKSB7CiAgICB2YXIgX2EzOwogICAgY29uc3QgaW5zdCA9IHBhcmFtcz8uUGFyZW50ID8gbmV3IERlZmluaXRpb24oKSA6IHRoaXM7CiAgICBpbml0KGluc3QsIGRlZik7CiAgICAoX2EzID0gaW5zdC5fem9kKS5kZWZlcnJlZCA/PyAoX2EzLmRlZmVycmVkID0gW10pOwogICAgZm9yIChjb25zdCBmbiBvZiBpbnN0Ll96b2QuZGVmZXJyZWQpIHsKICAgICAgZm4oKTsKICAgIH0KICAgIHJldHVybiBpbnN0OwogIH0KICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXywgImluaXQiLCB7IHZhbHVlOiBpbml0IH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShfLCBTeW1ib2wuaGFzSW5zdGFuY2UsIHsKICAgIHZhbHVlOiAoaW5zdCkgPT4gewogICAgICBpZiAocGFyYW1zPy5QYXJlbnQgJiYgaW5zdCBpbnN0YW5jZW9mIHBhcmFtcy5QYXJlbnQpCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIHJldHVybiBpbnN0Py5fem9kPy50cmFpdHM/LmhhcyhuYW1lKTsKICAgIH0KICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXywgIm5hbWUiLCB7IHZhbHVlOiBuYW1lIH0pOwogIHJldHVybiBfOwp9CnZhciAkWm9kQXN5bmNFcnJvciA9IGNsYXNzIGV4dGVuZHMgRXJyb3IgewogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoYEVuY291bnRlcmVkIFByb21pc2UgZHVyaW5nIHN5bmNocm9ub3VzIHBhcnNlLiBVc2UgLnBhcnNlQXN5bmMoKSBpbnN0ZWFkLmApOwogIH0KfTsKdmFyICRab2RFbmNvZGVFcnJvciA9IGNsYXNzIGV4dGVuZHMgRXJyb3IgewogIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgIHN1cGVyKGBFbmNvdW50ZXJlZCB1bmlkaXJlY3Rpb25hbCB0cmFuc2Zvcm0gZHVyaW5nIGVuY29kZTogJHtuYW1lfWApOwogICAgdGhpcy5uYW1lID0gIlpvZEVuY29kZUVycm9yIjsKICB9Cn07CihfYSA9IGdsb2JhbFRoaXMpLl9fem9kX2dsb2JhbENvbmZpZyA/PyAoX2EuX196b2RfZ2xvYmFsQ29uZmlnID0ge30pOwp2YXIgZ2xvYmFsQ29uZmlnID0gZ2xvYmFsVGhpcy5fX3pvZF9nbG9iYWxDb25maWc7CmZ1bmN0aW9uIGNvbmZpZyhuZXdDb25maWcpIHsKICBpZiAobmV3Q29uZmlnKQogICAgT2JqZWN0LmFzc2lnbihnbG9iYWxDb25maWcsIG5ld0NvbmZpZyk7CiAgcmV0dXJuIGdsb2JhbENvbmZpZzsKfQoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL3V0aWwuanMKdmFyIHV0aWxfZXhwb3J0cyA9IHt9OwpfX2V4cG9ydCh1dGlsX2V4cG9ydHMsIHsKICBCSUdJTlRfRk9STUFUX1JBTkdFUzogKCkgPT4gQklHSU5UX0ZPUk1BVF9SQU5HRVMsCiAgQ2xhc3M6ICgpID0+IENsYXNzLAogIE5VTUJFUl9GT1JNQVRfUkFOR0VTOiAoKSA9PiBOVU1CRVJfRk9STUFUX1JBTkdFUywKICBhYm9ydGVkOiAoKSA9PiBhYm9ydGVkLAogIGFsbG93c0V2YWw6ICgpID0+IGFsbG93c0V2YWwsCiAgYXNzZXJ0OiAoKSA9PiBhc3NlcnQsCiAgYXNzZXJ0RXF1YWw6ICgpID0+IGFzc2VydEVxdWFsLAogIGFzc2VydElzOiAoKSA9PiBhc3NlcnRJcywKICBhc3NlcnROZXZlcjogKCkgPT4gYXNzZXJ0TmV2ZXIsCiAgYXNzZXJ0Tm90RXF1YWw6ICgpID0+IGFzc2VydE5vdEVxdWFsLAogIGFzc2lnblByb3A6ICgpID0+IGFzc2lnblByb3AsCiAgYmFzZTY0VG9VaW50OEFycmF5OiAoKSA9PiBiYXNlNjRUb1VpbnQ4QXJyYXksCiAgYmFzZTY0dXJsVG9VaW50OEFycmF5OiAoKSA9PiBiYXNlNjR1cmxUb1VpbnQ4QXJyYXksCiAgY2FjaGVkOiAoKSA9PiBjYWNoZWQsCiAgY2FwdHVyZVN0YWNrVHJhY2U6ICgpID0+IGNhcHR1cmVTdGFja1RyYWNlLAogIGNsZWFuRW51bTogKCkgPT4gY2xlYW5FbnVtLAogIGNsZWFuUmVnZXg6ICgpID0+IGNsZWFuUmVnZXgsCiAgY2xvbmU6ICgpID0+IGNsb25lLAogIGNsb25lRGVmOiAoKSA9PiBjbG9uZURlZiwKICBjcmVhdGVUcmFuc3BhcmVudFByb3h5OiAoKSA9PiBjcmVhdGVUcmFuc3BhcmVudFByb3h5LAogIGRlZmluZUxhenk6ICgpID0+IGRlZmluZUxhenksCiAgZXNjOiAoKSA9PiBlc2MsCiAgZXNjYXBlUmVnZXg6ICgpID0+IGVzY2FwZVJlZ2V4LAogIGV4cGxpY2l0bHlBYm9ydGVkOiAoKSA9PiBleHBsaWNpdGx5QWJvcnRlZCwKICBleHRlbmQ6ICgpID0+IGV4dGVuZCwKICBmaW5hbGl6ZUlzc3VlOiAoKSA9PiBmaW5hbGl6ZUlzc3VlLAogIGZsb2F0U2FmZVJlbWFpbmRlcjogKCkgPT4gZmxvYXRTYWZlUmVtYWluZGVyLAogIGdldEVsZW1lbnRBdFBhdGg6ICgpID0+IGdldEVsZW1lbnRBdFBhdGgsCiAgZ2V0RW51bVZhbHVlczogKCkgPT4gZ2V0RW51bVZhbHVlcywKICBnZXRMZW5ndGhhYmxlT3JpZ2luOiAoKSA9PiBnZXRMZW5ndGhhYmxlT3JpZ2luLAogIGdldFBhcnNlZFR5cGU6ICgpID0+IGdldFBhcnNlZFR5cGUsCiAgZ2V0U2l6YWJsZU9yaWdpbjogKCkgPT4gZ2V0U2l6YWJsZU9yaWdpbiwKICBoZXhUb1VpbnQ4QXJyYXk6ICgpID0+IGhleFRvVWludDhBcnJheSwKICBpc09iamVjdDogKCkgPT4gaXNPYmplY3QsCiAgaXNQbGFpbk9iamVjdDogKCkgPT4gaXNQbGFpbk9iamVjdCwKICBpc3N1ZTogKCkgPT4gaXNzdWUsCiAgam9pblZhbHVlczogKCkgPT4gam9pblZhbHVlcywKICBqc29uU3RyaW5naWZ5UmVwbGFjZXI6ICgpID0+IGpzb25TdHJpbmdpZnlSZXBsYWNlciwKICBtZXJnZTogKCkgPT4gbWVyZ2UsCiAgbWVyZ2VEZWZzOiAoKSA9PiBtZXJnZURlZnMsCiAgbm9ybWFsaXplUGFyYW1zOiAoKSA9PiBub3JtYWxpemVQYXJhbXMsCiAgbnVsbGlzaDogKCkgPT4gbnVsbGlzaCwKICBudW1LZXlzOiAoKSA9PiBudW1LZXlzLAogIG9iamVjdENsb25lOiAoKSA9PiBvYmplY3RDbG9uZSwKICBvbWl0OiAoKSA9PiBvbWl0LAogIG9wdGlvbmFsS2V5czogKCkgPT4gb3B0aW9uYWxLZXlzLAogIHBhcnNlZFR5cGU6ICgpID0+IHBhcnNlZFR5cGUsCiAgcGFydGlhbDogKCkgPT4gcGFydGlhbCwKICBwaWNrOiAoKSA9PiBwaWNrLAogIHByZWZpeElzc3VlczogKCkgPT4gcHJlZml4SXNzdWVzLAogIHByaW1pdGl2ZVR5cGVzOiAoKSA9PiBwcmltaXRpdmVUeXBlcywKICBwcm9taXNlQWxsT2JqZWN0OiAoKSA9PiBwcm9taXNlQWxsT2JqZWN0LAogIHByb3BlcnR5S2V5VHlwZXM6ICgpID0+IHByb3BlcnR5S2V5VHlwZXMsCiAgcmFuZG9tU3RyaW5nOiAoKSA9PiByYW5kb21TdHJpbmcsCiAgcmVxdWlyZWQ6ICgpID0+IHJlcXVpcmVkLAogIHNhZmVFeHRlbmQ6ICgpID0+IHNhZmVFeHRlbmQsCiAgc2hhbGxvd0Nsb25lOiAoKSA9PiBzaGFsbG93Q2xvbmUsCiAgc2x1Z2lmeTogKCkgPT4gc2x1Z2lmeSwKICBzdHJpbmdpZnlQcmltaXRpdmU6ICgpID0+IHN0cmluZ2lmeVByaW1pdGl2ZSwKICB1aW50OEFycmF5VG9CYXNlNjQ6ICgpID0+IHVpbnQ4QXJyYXlUb0Jhc2U2NCwKICB1aW50OEFycmF5VG9CYXNlNjR1cmw6ICgpID0+IHVpbnQ4QXJyYXlUb0Jhc2U2NHVybCwKICB1aW50OEFycmF5VG9IZXg6ICgpID0+IHVpbnQ4QXJyYXlUb0hleCwKICB1bndyYXBNZXNzYWdlOiAoKSA9PiB1bndyYXBNZXNzYWdlCn0pOwpmdW5jdGlvbiBhc3NlcnRFcXVhbCh2YWwpIHsKICByZXR1cm4gdmFsOwp9CmZ1bmN0aW9uIGFzc2VydE5vdEVxdWFsKHZhbCkgewogIHJldHVybiB2YWw7Cn0KZnVuY3Rpb24gYXNzZXJ0SXMoX2FyZykgewp9CmZ1bmN0aW9uIGFzc2VydE5ldmVyKF94KSB7CiAgdGhyb3cgbmV3IEVycm9yKCJVbmV4cGVjdGVkIHZhbHVlIGluIGV4aGF1c3RpdmUgY2hlY2siKTsKfQpmdW5jdGlvbiBhc3NlcnQoXykgewp9CmZ1bmN0aW9uIGdldEVudW1WYWx1ZXMoZW50cmllcykgewogIGNvbnN0IG51bWVyaWNWYWx1ZXMgPSBPYmplY3QudmFsdWVzKGVudHJpZXMpLmZpbHRlcigodikgPT4gdHlwZW9mIHYgPT09ICJudW1iZXIiKTsKICBjb25zdCB2YWx1ZXMgPSBPYmplY3QuZW50cmllcyhlbnRyaWVzKS5maWx0ZXIoKFtrLCBfXSkgPT4gbnVtZXJpY1ZhbHVlcy5pbmRleE9mKCtrKSA9PT0gLTEpLm1hcCgoW18sIHZdKSA9PiB2KTsKICByZXR1cm4gdmFsdWVzOwp9CmZ1bmN0aW9uIGpvaW5WYWx1ZXMoYXJyYXkyLCBzZXBhcmF0b3IgPSAifCIpIHsKICByZXR1cm4gYXJyYXkyLm1hcCgodmFsKSA9PiBzdHJpbmdpZnlQcmltaXRpdmUodmFsKSkuam9pbihzZXBhcmF0b3IpOwp9CmZ1bmN0aW9uIGpzb25TdHJpbmdpZnlSZXBsYWNlcihfLCB2YWx1ZSkgewogIGlmICh0eXBlb2YgdmFsdWUgPT09ICJiaWdpbnQiKQogICAgcmV0dXJuIHZhbHVlLnRvU3RyaW5nKCk7CiAgcmV0dXJuIHZhbHVlOwp9CmZ1bmN0aW9uIGNhY2hlZChnZXR0ZXIpIHsKICBjb25zdCBzZXQgPSBmYWxzZTsKICByZXR1cm4gewogICAgZ2V0IHZhbHVlKCkgewogICAgICBpZiAoIXNldCkgewogICAgICAgIGNvbnN0IHZhbHVlID0gZ2V0dGVyKCk7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICJ2YWx1ZSIsIHsgdmFsdWUgfSk7CiAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICB9CiAgICAgIHRocm93IG5ldyBFcnJvcigiY2FjaGVkIHZhbHVlIGFscmVhZHkgc2V0Iik7CiAgICB9CiAgfTsKfQpmdW5jdGlvbiBudWxsaXNoKGlucHV0KSB7CiAgcmV0dXJuIGlucHV0ID09PSBudWxsIHx8IGlucHV0ID09PSB2b2lkIDA7Cn0KZnVuY3Rpb24gY2xlYW5SZWdleChzb3VyY2UpIHsKICBjb25zdCBzdGFydCA9IHNvdXJjZS5zdGFydHNXaXRoKCJeIikgPyAxIDogMDsKICBjb25zdCBlbmQgPSBzb3VyY2UuZW5kc1dpdGgoIiQiKSA/IHNvdXJjZS5sZW5ndGggLSAxIDogc291cmNlLmxlbmd0aDsKICByZXR1cm4gc291cmNlLnNsaWNlKHN0YXJ0LCBlbmQpOwp9CmZ1bmN0aW9uIGZsb2F0U2FmZVJlbWFpbmRlcih2YWwsIHN0ZXApIHsKICBjb25zdCByYXRpbyA9IHZhbCAvIHN0ZXA7CiAgY29uc3Qgcm91bmRlZFJhdGlvID0gTWF0aC5yb3VuZChyYXRpbyk7CiAgY29uc3QgdG9sZXJhbmNlID0gTnVtYmVyLkVQU0lMT04gKiBNYXRoLm1heChNYXRoLmFicyhyYXRpbyksIDEpOwogIGlmIChNYXRoLmFicyhyYXRpbyAtIHJvdW5kZWRSYXRpbykgPCB0b2xlcmFuY2UpCiAgICByZXR1cm4gMDsKICByZXR1cm4gcmF0aW8gLSByb3VuZGVkUmF0aW87Cn0KdmFyIEVWQUxVQVRJTkcgPSAvKiBAX19QVVJFX18gKi8gU3ltYm9sKCJldmFsdWF0aW5nIik7CmZ1bmN0aW9uIGRlZmluZUxhenkob2JqZWN0Miwga2V5LCBnZXR0ZXIpIHsKICBsZXQgdmFsdWUgPSB2b2lkIDA7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdDIsIGtleSwgewogICAgZ2V0KCkgewogICAgICBpZiAodmFsdWUgPT09IEVWQUxVQVRJTkcpIHsKICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICB9CiAgICAgIGlmICh2YWx1ZSA9PT0gdm9pZCAwKSB7CiAgICAgICAgdmFsdWUgPSBFVkFMVUFUSU5HOwogICAgICAgIHZhbHVlID0gZ2V0dGVyKCk7CiAgICAgIH0KICAgICAgcmV0dXJuIHZhbHVlOwogICAgfSwKICAgIHNldCh2KSB7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmplY3QyLCBrZXksIHsKICAgICAgICB2YWx1ZTogdgogICAgICAgIC8vIGNvbmZpZ3VyYWJsZTogdHJ1ZSwKICAgICAgfSk7CiAgICB9LAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7Cn0KZnVuY3Rpb24gb2JqZWN0Q2xvbmUob2JqKSB7CiAgcmV0dXJuIE9iamVjdC5jcmVhdGUoT2JqZWN0LmdldFByb3RvdHlwZU9mKG9iaiksIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKG9iaikpOwp9CmZ1bmN0aW9uIGFzc2lnblByb3AodGFyZ2V0LCBwcm9wLCB2YWx1ZSkgewogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3AsIHsKICAgIHZhbHVlLAogICAgd3JpdGFibGU6IHRydWUsCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7Cn0KZnVuY3Rpb24gbWVyZ2VEZWZzKC4uLmRlZnMpIHsKICBjb25zdCBtZXJnZWREZXNjcmlwdG9ycyA9IHt9OwogIGZvciAoY29uc3QgZGVmIG9mIGRlZnMpIHsKICAgIGNvbnN0IGRlc2NyaXB0b3JzID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoZGVmKTsKICAgIE9iamVjdC5hc3NpZ24obWVyZ2VkRGVzY3JpcHRvcnMsIGRlc2NyaXB0b3JzKTsKICB9CiAgcmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHt9LCBtZXJnZWREZXNjcmlwdG9ycyk7Cn0KZnVuY3Rpb24gY2xvbmVEZWYoc2NoZW1hKSB7CiAgcmV0dXJuIG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYpOwp9CmZ1bmN0aW9uIGdldEVsZW1lbnRBdFBhdGgob2JqLCBwYXRoMikgewogIGlmICghcGF0aDIpCiAgICByZXR1cm4gb2JqOwogIHJldHVybiBwYXRoMi5yZWR1Y2UoKGFjYywga2V5KSA9PiBhY2M/LltrZXldLCBvYmopOwp9CmZ1bmN0aW9uIHByb21pc2VBbGxPYmplY3QocHJvbWlzZXNPYmopIHsKICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocHJvbWlzZXNPYmopOwogIGNvbnN0IHByb21pc2VzID0ga2V5cy5tYXAoKGtleSkgPT4gcHJvbWlzZXNPYmpba2V5XSk7CiAgcmV0dXJuIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKChyZXN1bHRzKSA9PiB7CiAgICBjb25zdCByZXNvbHZlZE9iaiA9IHt9OwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7CiAgICAgIHJlc29sdmVkT2JqW2tleXNbaV1dID0gcmVzdWx0c1tpXTsKICAgIH0KICAgIHJldHVybiByZXNvbHZlZE9iajsKICB9KTsKfQpmdW5jdGlvbiByYW5kb21TdHJpbmcobGVuZ3RoID0gMTApIHsKICBjb25zdCBjaGFycyA9ICJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiI7CiAgbGV0IHN0ciA9ICIiOwogIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgIHN0ciArPSBjaGFyc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBjaGFycy5sZW5ndGgpXTsKICB9CiAgcmV0dXJuIHN0cjsKfQpmdW5jdGlvbiBlc2Moc3RyKSB7CiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHN0cik7Cn0KZnVuY3Rpb24gc2x1Z2lmeShpbnB1dCkgewogIHJldHVybiBpbnB1dC50b0xvd2VyQ2FzZSgpLnRyaW0oKS5yZXBsYWNlKC9bXlx3XHMtXS9nLCAiIikucmVwbGFjZSgvW1xzXy1dKy9nLCAiLSIpLnJlcGxhY2UoL14tK3wtKyQvZywgIiIpOwp9CnZhciBjYXB0dXJlU3RhY2tUcmFjZSA9ICJjYXB0dXJlU3RhY2tUcmFjZSIgaW4gRXJyb3IgPyBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSA6ICguLi5fYXJncykgPT4gewp9OwpmdW5jdGlvbiBpc09iamVjdChkYXRhKSB7CiAgcmV0dXJuIHR5cGVvZiBkYXRhID09PSAib2JqZWN0IiAmJiBkYXRhICE9PSBudWxsICYmICFBcnJheS5pc0FycmF5KGRhdGEpOwp9CnZhciBhbGxvd3NFdmFsID0gLyogQF9fUFVSRV9fICovIGNhY2hlZCgoKSA9PiB7CiAgaWYgKGdsb2JhbENvbmZpZy5qaXRsZXNzKSB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQogIGlmICh0eXBlb2YgbmF2aWdhdG9yICE9PSAidW5kZWZpbmVkIiAmJiBuYXZpZ2F0b3I/LnVzZXJBZ2VudD8uaW5jbHVkZXMoIkNsb3VkZmxhcmUiKSkgewogICAgcmV0dXJuIGZhbHNlOwogIH0KICB0cnkgewogICAgY29uc3QgRiA9IEZ1bmN0aW9uOwogICAgbmV3IEYoIiIpOwogICAgcmV0dXJuIHRydWU7CiAgfSBjYXRjaCAoXykgewogICAgcmV0dXJuIGZhbHNlOwogIH0KfSk7CmZ1bmN0aW9uIGlzUGxhaW5PYmplY3QobykgewogIGlmIChpc09iamVjdChvKSA9PT0gZmFsc2UpCiAgICByZXR1cm4gZmFsc2U7CiAgY29uc3QgY3RvciA9IG8uY29uc3RydWN0b3I7CiAgaWYgKGN0b3IgPT09IHZvaWQgMCkKICAgIHJldHVybiB0cnVlOwogIGlmICh0eXBlb2YgY3RvciAhPT0gImZ1bmN0aW9uIikKICAgIHJldHVybiB0cnVlOwogIGNvbnN0IHByb3QgPSBjdG9yLnByb3RvdHlwZTsKICBpZiAoaXNPYmplY3QocHJvdCkgPT09IGZhbHNlKQogICAgcmV0dXJuIGZhbHNlOwogIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocHJvdCwgImlzUHJvdG90eXBlT2YiKSA9PT0gZmFsc2UpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHRydWU7Cn0KZnVuY3Rpb24gc2hhbGxvd0Nsb25lKG8pIHsKICBpZiAoaXNQbGFpbk9iamVjdChvKSkKICAgIHJldHVybiB7IC4uLm8gfTsKICBpZiAoQXJyYXkuaXNBcnJheShvKSkKICAgIHJldHVybiBbLi4ub107CiAgaWYgKG8gaW5zdGFuY2VvZiBNYXApCiAgICByZXR1cm4gbmV3IE1hcChvKTsKICBpZiAobyBpbnN0YW5jZW9mIFNldCkKICAgIHJldHVybiBuZXcgU2V0KG8pOwogIHJldHVybiBvOwp9CmZ1bmN0aW9uIG51bUtleXMoZGF0YSkgewogIGxldCBrZXlDb3VudCA9IDA7CiAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkgewogICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChkYXRhLCBrZXkpKSB7CiAgICAgIGtleUNvdW50Kys7CiAgICB9CiAgfQogIHJldHVybiBrZXlDb3VudDsKfQp2YXIgZ2V0UGFyc2VkVHlwZSA9IChkYXRhKSA9PiB7CiAgY29uc3QgdCA9IHR5cGVvZiBkYXRhOwogIHN3aXRjaCAodCkgewogICAgY2FzZSAidW5kZWZpbmVkIjoKICAgICAgcmV0dXJuICJ1bmRlZmluZWQiOwogICAgY2FzZSAic3RyaW5nIjoKICAgICAgcmV0dXJuICJzdHJpbmciOwogICAgY2FzZSAibnVtYmVyIjoKICAgICAgcmV0dXJuIE51bWJlci5pc05hTihkYXRhKSA/ICJuYW4iIDogIm51bWJlciI7CiAgICBjYXNlICJib29sZWFuIjoKICAgICAgcmV0dXJuICJib29sZWFuIjsKICAgIGNhc2UgImZ1bmN0aW9uIjoKICAgICAgcmV0dXJuICJmdW5jdGlvbiI7CiAgICBjYXNlICJiaWdpbnQiOgogICAgICByZXR1cm4gImJpZ2ludCI7CiAgICBjYXNlICJzeW1ib2wiOgogICAgICByZXR1cm4gInN5bWJvbCI7CiAgICBjYXNlICJvYmplY3QiOgogICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkgewogICAgICAgIHJldHVybiAiYXJyYXkiOwogICAgICB9CiAgICAgIGlmIChkYXRhID09PSBudWxsKSB7CiAgICAgICAgcmV0dXJuICJudWxsIjsKICAgICAgfQogICAgICBpZiAoZGF0YS50aGVuICYmIHR5cGVvZiBkYXRhLnRoZW4gPT09ICJmdW5jdGlvbiIgJiYgZGF0YS5jYXRjaCAmJiB0eXBlb2YgZGF0YS5jYXRjaCA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIHJldHVybiAicHJvbWlzZSI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBNYXAgIT09ICJ1bmRlZmluZWQiICYmIGRhdGEgaW5zdGFuY2VvZiBNYXApIHsKICAgICAgICByZXR1cm4gIm1hcCI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBTZXQgIT09ICJ1bmRlZmluZWQiICYmIGRhdGEgaW5zdGFuY2VvZiBTZXQpIHsKICAgICAgICByZXR1cm4gInNldCI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBEYXRlICE9PSAidW5kZWZpbmVkIiAmJiBkYXRhIGluc3RhbmNlb2YgRGF0ZSkgewogICAgICAgIHJldHVybiAiZGF0ZSI7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBGaWxlICE9PSAidW5kZWZpbmVkIiAmJiBkYXRhIGluc3RhbmNlb2YgRmlsZSkgewogICAgICAgIHJldHVybiAiZmlsZSI7CiAgICAgIH0KICAgICAgcmV0dXJuICJvYmplY3QiOwogICAgZGVmYXVsdDoKICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGRhdGEgdHlwZTogJHt0fWApOwogIH0KfTsKdmFyIHByb3BlcnR5S2V5VHlwZXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbInN0cmluZyIsICJudW1iZXIiLCAic3ltYm9sIl0pOwp2YXIgcHJpbWl0aXZlVHlwZXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldChbCiAgInN0cmluZyIsCiAgIm51bWJlciIsCiAgImJpZ2ludCIsCiAgImJvb2xlYW4iLAogICJzeW1ib2wiLAogICJ1bmRlZmluZWQiCl0pOwpmdW5jdGlvbiBlc2NhcGVSZWdleChzdHIpIHsKICByZXR1cm4gc3RyLnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXVxcXS9nLCAiXFwkJiIpOwp9CmZ1bmN0aW9uIGNsb25lKGluc3QsIGRlZiwgcGFyYW1zKSB7CiAgY29uc3QgY2wgPSBuZXcgaW5zdC5fem9kLmNvbnN0cihkZWYgPz8gaW5zdC5fem9kLmRlZik7CiAgaWYgKCFkZWYgfHwgcGFyYW1zPy5wYXJlbnQpCiAgICBjbC5fem9kLnBhcmVudCA9IGluc3Q7CiAgcmV0dXJuIGNsOwp9CmZ1bmN0aW9uIG5vcm1hbGl6ZVBhcmFtcyhfcGFyYW1zKSB7CiAgY29uc3QgcGFyYW1zID0gX3BhcmFtczsKICBpZiAoIXBhcmFtcykKICAgIHJldHVybiB7fTsKICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gInN0cmluZyIpCiAgICByZXR1cm4geyBlcnJvcjogKCkgPT4gcGFyYW1zIH07CiAgaWYgKHBhcmFtcz8ubWVzc2FnZSAhPT0gdm9pZCAwKSB7CiAgICBpZiAocGFyYW1zPy5lcnJvciAhPT0gdm9pZCAwKQogICAgICB0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBzcGVjaWZ5IGJvdGggYG1lc3NhZ2VgIGFuZCBgZXJyb3JgIHBhcmFtcyIpOwogICAgcGFyYW1zLmVycm9yID0gcGFyYW1zLm1lc3NhZ2U7CiAgfQogIGRlbGV0ZSBwYXJhbXMubWVzc2FnZTsKICBpZiAodHlwZW9mIHBhcmFtcy5lcnJvciA9PT0gInN0cmluZyIpCiAgICByZXR1cm4geyAuLi5wYXJhbXMsIGVycm9yOiAoKSA9PiBwYXJhbXMuZXJyb3IgfTsKICByZXR1cm4gcGFyYW1zOwp9CmZ1bmN0aW9uIGNyZWF0ZVRyYW5zcGFyZW50UHJveHkoZ2V0dGVyKSB7CiAgbGV0IHRhcmdldDsKICByZXR1cm4gbmV3IFByb3h5KHt9LCB7CiAgICBnZXQoXywgcHJvcCwgcmVjZWl2ZXIpIHsKICAgICAgdGFyZ2V0ID8/ICh0YXJnZXQgPSBnZXR0ZXIoKSk7CiAgICAgIHJldHVybiBSZWZsZWN0LmdldCh0YXJnZXQsIHByb3AsIHJlY2VpdmVyKTsKICAgIH0sCiAgICBzZXQoXywgcHJvcCwgdmFsdWUsIHJlY2VpdmVyKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5zZXQodGFyZ2V0LCBwcm9wLCB2YWx1ZSwgcmVjZWl2ZXIpOwogICAgfSwKICAgIGhhcyhfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5oYXModGFyZ2V0LCBwcm9wKTsKICAgIH0sCiAgICBkZWxldGVQcm9wZXJ0eShfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5kZWxldGVQcm9wZXJ0eSh0YXJnZXQsIHByb3ApOwogICAgfSwKICAgIG93bktleXMoXykgewogICAgICB0YXJnZXQgPz8gKHRhcmdldCA9IGdldHRlcigpKTsKICAgICAgcmV0dXJuIFJlZmxlY3Qub3duS2V5cyh0YXJnZXQpOwogICAgfSwKICAgIGdldE93blByb3BlcnR5RGVzY3JpcHRvcihfLCBwcm9wKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBwcm9wKTsKICAgIH0sCiAgICBkZWZpbmVQcm9wZXJ0eShfLCBwcm9wLCBkZXNjcmlwdG9yKSB7CiAgICAgIHRhcmdldCA/PyAodGFyZ2V0ID0gZ2V0dGVyKCkpOwogICAgICByZXR1cm4gUmVmbGVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3AsIGRlc2NyaXB0b3IpOwogICAgfQogIH0pOwp9CmZ1bmN0aW9uIHN0cmluZ2lmeVByaW1pdGl2ZSh2YWx1ZSkgewogIGlmICh0eXBlb2YgdmFsdWUgPT09ICJiaWdpbnQiKQogICAgcmV0dXJuIHZhbHVlLnRvU3RyaW5nKCkgKyAibiI7CiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gInN0cmluZyIpCiAgICByZXR1cm4gYCIke3ZhbHVlfSJgOwogIHJldHVybiBgJHt2YWx1ZX1gOwp9CmZ1bmN0aW9uIG9wdGlvbmFsS2V5cyhzaGFwZSkgewogIHJldHVybiBPYmplY3Qua2V5cyhzaGFwZSkuZmlsdGVyKChrKSA9PiB7CiAgICByZXR1cm4gc2hhcGVba10uX3pvZC5vcHRpbiA9PT0gIm9wdGlvbmFsIiAmJiBzaGFwZVtrXS5fem9kLm9wdG91dCA9PT0gIm9wdGlvbmFsIjsKICB9KTsKfQp2YXIgTlVNQkVSX0ZPUk1BVF9SQU5HRVMgPSB7CiAgc2FmZWludDogW051bWJlci5NSU5fU0FGRV9JTlRFR0VSLCBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUl0sCiAgaW50MzI6IFstMjE0NzQ4MzY0OCwgMjE0NzQ4MzY0N10sCiAgdWludDMyOiBbMCwgNDI5NDk2NzI5NV0sCiAgZmxvYXQzMjogWy0zNDAyODIzNDY2Mzg1Mjg4NmUyMiwgMzQwMjgyMzQ2NjM4NTI4ODZlMjJdLAogIGZsb2F0NjQ6IFstTnVtYmVyLk1BWF9WQUxVRSwgTnVtYmVyLk1BWF9WQUxVRV0KfTsKdmFyIEJJR0lOVF9GT1JNQVRfUkFOR0VTID0gewogIGludDY0OiBbLyogQF9fUFVSRV9fICovIEJpZ0ludCgiLTkyMjMzNzIwMzY4NTQ3NzU4MDgiKSwgLyogQF9fUFVSRV9fICovIEJpZ0ludCgiOTIyMzM3MjAzNjg1NDc3NTgwNyIpXSwKICB1aW50NjQ6IFsvKiBAX19QVVJFX18gKi8gQmlnSW50KDApLCAvKiBAX19QVVJFX18gKi8gQmlnSW50KCIxODQ0Njc0NDA3MzcwOTU1MTYxNSIpXQp9OwpmdW5jdGlvbiBwaWNrKHNjaGVtYSwgbWFzaykgewogIGNvbnN0IGN1cnJEZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgY2hlY2tzID0gY3VyckRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIHRocm93IG5ldyBFcnJvcigiLnBpY2soKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzIik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgbmV3U2hhcGUgPSB7fTsKICAgICAgZm9yIChjb25zdCBrZXkgaW4gbWFzaykgewogICAgICAgIGlmICghKGtleSBpbiBjdXJyRGVmLnNoYXBlKSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQga2V5OiAiJHtrZXl9ImApOwogICAgICAgIH0KICAgICAgICBpZiAoIW1hc2tba2V5XSkKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIG5ld1NoYXBlW2tleV0gPSBjdXJyRGVmLnNoYXBlW2tleV07CiAgICAgIH0KICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBuZXdTaGFwZSk7CiAgICAgIHJldHVybiBuZXdTaGFwZTsKICAgIH0sCiAgICBjaGVja3M6IFtdCiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBvbWl0KHNjaGVtYSwgbWFzaykgewogIGNvbnN0IGN1cnJEZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3QgY2hlY2tzID0gY3VyckRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIHRocm93IG5ldyBFcnJvcigiLm9taXQoKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzIik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgbmV3U2hhcGUgPSB7IC4uLnNjaGVtYS5fem9kLmRlZi5zaGFwZSB9OwogICAgICBmb3IgKGNvbnN0IGtleSBpbiBtYXNrKSB7CiAgICAgICAgaWYgKCEoa2V5IGluIGN1cnJEZWYuc2hhcGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBrZXk6ICIke2tleX0iYCk7CiAgICAgICAgfQogICAgICAgIGlmICghbWFza1trZXldKQogICAgICAgICAgY29udGludWU7CiAgICAgICAgZGVsZXRlIG5ld1NoYXBlW2tleV07CiAgICAgIH0KICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBuZXdTaGFwZSk7CiAgICAgIHJldHVybiBuZXdTaGFwZTsKICAgIH0sCiAgICBjaGVja3M6IFtdCiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBleHRlbmQoc2NoZW1hLCBzaGFwZSkgewogIGlmICghaXNQbGFpbk9iamVjdChzaGFwZSkpIHsKICAgIHRocm93IG5ldyBFcnJvcigiSW52YWxpZCBpbnB1dCB0byBleHRlbmQ6IGV4cGVjdGVkIGEgcGxhaW4gb2JqZWN0Iik7CiAgfQogIGNvbnN0IGNoZWNrcyA9IHNjaGVtYS5fem9kLmRlZi5jaGVja3M7CiAgY29uc3QgaGFzQ2hlY2tzID0gY2hlY2tzICYmIGNoZWNrcy5sZW5ndGggPiAwOwogIGlmIChoYXNDaGVja3MpIHsKICAgIGNvbnN0IGV4aXN0aW5nU2hhcGUgPSBzY2hlbWEuX3pvZC5kZWYuc2hhcGU7CiAgICBmb3IgKGNvbnN0IGtleSBpbiBzaGFwZSkgewogICAgICBpZiAoT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihleGlzdGluZ1NoYXBlLCBrZXkpICE9PSB2b2lkIDApIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBvdmVyd3JpdGUga2V5cyBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzLiBVc2UgYC5zYWZlRXh0ZW5kKClgIGluc3RlYWQuIik7CiAgICAgIH0KICAgIH0KICB9CiAgY29uc3QgZGVmID0gbWVyZ2VEZWZzKHNjaGVtYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBfc2hhcGUgPSB7IC4uLnNjaGVtYS5fem9kLmRlZi5zaGFwZSwgLi4uc2hhcGUgfTsKICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBfc2hhcGUpOwogICAgICByZXR1cm4gX3NoYXBlOwogICAgfQogIH0pOwogIHJldHVybiBjbG9uZShzY2hlbWEsIGRlZik7Cn0KZnVuY3Rpb24gc2FmZUV4dGVuZChzY2hlbWEsIHNoYXBlKSB7CiAgaWYgKCFpc1BsYWluT2JqZWN0KHNoYXBlKSkgewogICAgdGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIGlucHV0IHRvIHNhZmVFeHRlbmQ6IGV4cGVjdGVkIGEgcGxhaW4gb2JqZWN0Iik7CiAgfQogIGNvbnN0IGRlZiA9IG1lcmdlRGVmcyhzY2hlbWEuX3pvZC5kZWYsIHsKICAgIGdldCBzaGFwZSgpIHsKICAgICAgY29uc3QgX3NoYXBlID0geyAuLi5zY2hlbWEuX3pvZC5kZWYuc2hhcGUsIC4uLnNoYXBlIH07CiAgICAgIGFzc2lnblByb3AodGhpcywgInNoYXBlIiwgX3NoYXBlKTsKICAgICAgcmV0dXJuIF9zaGFwZTsKICAgIH0KICB9KTsKICByZXR1cm4gY2xvbmUoc2NoZW1hLCBkZWYpOwp9CmZ1bmN0aW9uIG1lcmdlKGEsIGIpIHsKICBpZiAoYS5fem9kLmRlZi5jaGVja3M/Lmxlbmd0aCkgewogICAgdGhyb3cgbmV3IEVycm9yKCIubWVyZ2UoKSBjYW5ub3QgYmUgdXNlZCBvbiBvYmplY3Qgc2NoZW1hcyBjb250YWluaW5nIHJlZmluZW1lbnRzLiBVc2UgLnNhZmVFeHRlbmQoKSBpbnN0ZWFkLiIpOwogIH0KICBjb25zdCBkZWYgPSBtZXJnZURlZnMoYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBfc2hhcGUgPSB7IC4uLmEuX3pvZC5kZWYuc2hhcGUsIC4uLmIuX3pvZC5kZWYuc2hhcGUgfTsKICAgICAgYXNzaWduUHJvcCh0aGlzLCAic2hhcGUiLCBfc2hhcGUpOwogICAgICByZXR1cm4gX3NoYXBlOwogICAgfSwKICAgIGdldCBjYXRjaGFsbCgpIHsKICAgICAgcmV0dXJuIGIuX3pvZC5kZWYuY2F0Y2hhbGw7CiAgICB9LAogICAgY2hlY2tzOiBiLl96b2QuZGVmLmNoZWNrcyA/PyBbXQogIH0pOwogIHJldHVybiBjbG9uZShhLCBkZWYpOwp9CmZ1bmN0aW9uIHBhcnRpYWwoQ2xhc3MyLCBzY2hlbWEsIG1hc2spIHsKICBjb25zdCBjdXJyRGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGNoZWNrcyA9IGN1cnJEZWYuY2hlY2tzOwogIGNvbnN0IGhhc0NoZWNrcyA9IGNoZWNrcyAmJiBjaGVja3MubGVuZ3RoID4gMDsKICBpZiAoaGFzQ2hlY2tzKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIi5wYXJ0aWFsKCkgY2Fubm90IGJlIHVzZWQgb24gb2JqZWN0IHNjaGVtYXMgY29udGFpbmluZyByZWZpbmVtZW50cyIpOwogIH0KICBjb25zdCBkZWYgPSBtZXJnZURlZnMoc2NoZW1hLl96b2QuZGVmLCB7CiAgICBnZXQgc2hhcGUoKSB7CiAgICAgIGNvbnN0IG9sZFNoYXBlID0gc2NoZW1hLl96b2QuZGVmLnNoYXBlOwogICAgICBjb25zdCBzaGFwZSA9IHsgLi4ub2xkU2hhcGUgfTsKICAgICAgaWYgKG1hc2spIHsKICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBtYXNrKSB7CiAgICAgICAgICBpZiAoIShrZXkgaW4gb2xkU2hhcGUpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5yZWNvZ25pemVkIGtleTogIiR7a2V5fSJgKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghbWFza1trZXldKQogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIHNoYXBlW2tleV0gPSBDbGFzczIgPyBuZXcgQ2xhc3MyKHsKICAgICAgICAgICAgdHlwZTogIm9wdGlvbmFsIiwKICAgICAgICAgICAgaW5uZXJUeXBlOiBvbGRTaGFwZVtrZXldCiAgICAgICAgICB9KSA6IG9sZFNoYXBlW2tleV07CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIG9sZFNoYXBlKSB7CiAgICAgICAgICBzaGFwZVtrZXldID0gQ2xhc3MyID8gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJvcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSkgOiBvbGRTaGFwZVtrZXldOwogICAgICAgIH0KICAgICAgfQogICAgICBhc3NpZ25Qcm9wKHRoaXMsICJzaGFwZSIsIHNoYXBlKTsKICAgICAgcmV0dXJuIHNoYXBlOwogICAgfSwKICAgIGNoZWNrczogW10KICB9KTsKICByZXR1cm4gY2xvbmUoc2NoZW1hLCBkZWYpOwp9CmZ1bmN0aW9uIHJlcXVpcmVkKENsYXNzMiwgc2NoZW1hLCBtYXNrKSB7CiAgY29uc3QgZGVmID0gbWVyZ2VEZWZzKHNjaGVtYS5fem9kLmRlZiwgewogICAgZ2V0IHNoYXBlKCkgewogICAgICBjb25zdCBvbGRTaGFwZSA9IHNjaGVtYS5fem9kLmRlZi5zaGFwZTsKICAgICAgY29uc3Qgc2hhcGUgPSB7IC4uLm9sZFNoYXBlIH07CiAgICAgIGlmIChtYXNrKSB7CiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gbWFzaykgewogICAgICAgICAgaWYgKCEoa2V5IGluIHNoYXBlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBrZXk6ICIke2tleX0iYCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIW1hc2tba2V5XSkKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBzaGFwZVtrZXldID0gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJub25vcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIG9sZFNoYXBlKSB7CiAgICAgICAgICBzaGFwZVtrZXldID0gbmV3IENsYXNzMih7CiAgICAgICAgICAgIHR5cGU6ICJub25vcHRpb25hbCIsCiAgICAgICAgICAgIGlubmVyVHlwZTogb2xkU2hhcGVba2V5XQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGFzc2lnblByb3AodGhpcywgInNoYXBlIiwgc2hhcGUpOwogICAgICByZXR1cm4gc2hhcGU7CiAgICB9CiAgfSk7CiAgcmV0dXJuIGNsb25lKHNjaGVtYSwgZGVmKTsKfQpmdW5jdGlvbiBhYm9ydGVkKHgsIHN0YXJ0SW5kZXggPSAwKSB7CiAgaWYgKHguYWJvcnRlZCA9PT0gdHJ1ZSkKICAgIHJldHVybiB0cnVlOwogIGZvciAobGV0IGkgPSBzdGFydEluZGV4OyBpIDwgeC5pc3N1ZXMubGVuZ3RoOyBpKyspIHsKICAgIGlmICh4Lmlzc3Vlc1tpXT8uY29udGludWUgIT09IHRydWUpIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgfQogIHJldHVybiBmYWxzZTsKfQpmdW5jdGlvbiBleHBsaWNpdGx5QWJvcnRlZCh4LCBzdGFydEluZGV4ID0gMCkgewogIGlmICh4LmFib3J0ZWQgPT09IHRydWUpCiAgICByZXR1cm4gdHJ1ZTsKICBmb3IgKGxldCBpID0gc3RhcnRJbmRleDsgaSA8IHguaXNzdWVzLmxlbmd0aDsgaSsrKSB7CiAgICBpZiAoeC5pc3N1ZXNbaV0/LmNvbnRpbnVlID09PSBmYWxzZSkgewogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CiAgcmV0dXJuIGZhbHNlOwp9CmZ1bmN0aW9uIHByZWZpeElzc3VlcyhwYXRoMiwgaXNzdWVzKSB7CiAgcmV0dXJuIGlzc3Vlcy5tYXAoKGlzcykgPT4gewogICAgdmFyIF9hMzsKICAgIChfYTMgPSBpc3MpLnBhdGggPz8gKF9hMy5wYXRoID0gW10pOwogICAgaXNzLnBhdGgudW5zaGlmdChwYXRoMik7CiAgICByZXR1cm4gaXNzOwogIH0pOwp9CmZ1bmN0aW9uIHVud3JhcE1lc3NhZ2UobWVzc2FnZSkgewogIHJldHVybiB0eXBlb2YgbWVzc2FnZSA9PT0gInN0cmluZyIgPyBtZXNzYWdlIDogbWVzc2FnZT8ubWVzc2FnZTsKfQpmdW5jdGlvbiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcyKSB7CiAgY29uc3QgbWVzc2FnZSA9IGlzcy5tZXNzYWdlID8gaXNzLm1lc3NhZ2UgOiB1bndyYXBNZXNzYWdlKGlzcy5pbnN0Py5fem9kLmRlZj8uZXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGN0eD8uZXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGNvbmZpZzIuY3VzdG9tRXJyb3I/Lihpc3MpKSA/PyB1bndyYXBNZXNzYWdlKGNvbmZpZzIubG9jYWxlRXJyb3I/Lihpc3MpKSA/PyAiSW52YWxpZCBpbnB1dCI7CiAgY29uc3QgeyBpbnN0OiBfaW5zdCwgY29udGludWU6IF9jb250aW51ZSwgaW5wdXQ6IF9pbnB1dCwgLi4ucmVzdCB9ID0gaXNzOwogIHJlc3QucGF0aCA/PyAocmVzdC5wYXRoID0gW10pOwogIHJlc3QubWVzc2FnZSA9IG1lc3NhZ2U7CiAgaWYgKGN0eD8ucmVwb3J0SW5wdXQpIHsKICAgIHJlc3QuaW5wdXQgPSBfaW5wdXQ7CiAgfQogIHJldHVybiByZXN0Owp9CmZ1bmN0aW9uIGdldFNpemFibGVPcmlnaW4oaW5wdXQpIHsKICBpZiAoaW5wdXQgaW5zdGFuY2VvZiBTZXQpCiAgICByZXR1cm4gInNldCI7CiAgaWYgKGlucHV0IGluc3RhbmNlb2YgTWFwKQogICAgcmV0dXJuICJtYXAiOwogIGlmIChpbnB1dCBpbnN0YW5jZW9mIEZpbGUpCiAgICByZXR1cm4gImZpbGUiOwogIHJldHVybiAidW5rbm93biI7Cn0KZnVuY3Rpb24gZ2V0TGVuZ3RoYWJsZU9yaWdpbihpbnB1dCkgewogIGlmIChBcnJheS5pc0FycmF5KGlucHV0KSkKICAgIHJldHVybiAiYXJyYXkiOwogIGlmICh0eXBlb2YgaW5wdXQgPT09ICJzdHJpbmciKQogICAgcmV0dXJuICJzdHJpbmciOwogIHJldHVybiAidW5rbm93biI7Cn0KZnVuY3Rpb24gcGFyc2VkVHlwZShkYXRhKSB7CiAgY29uc3QgdCA9IHR5cGVvZiBkYXRhOwogIHN3aXRjaCAodCkgewogICAgY2FzZSAibnVtYmVyIjogewogICAgICByZXR1cm4gTnVtYmVyLmlzTmFOKGRhdGEpID8gIm5hbiIgOiAibnVtYmVyIjsKICAgIH0KICAgIGNhc2UgIm9iamVjdCI6IHsKICAgICAgaWYgKGRhdGEgPT09IG51bGwpIHsKICAgICAgICByZXR1cm4gIm51bGwiOwogICAgICB9CiAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7CiAgICAgICAgcmV0dXJuICJhcnJheSI7CiAgICAgIH0KICAgICAgY29uc3Qgb2JqID0gZGF0YTsKICAgICAgaWYgKG9iaiAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqKSAhPT0gT2JqZWN0LnByb3RvdHlwZSAmJiAiY29uc3RydWN0b3IiIGluIG9iaiAmJiBvYmouY29uc3RydWN0b3IpIHsKICAgICAgICByZXR1cm4gb2JqLmNvbnN0cnVjdG9yLm5hbWU7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIHQ7Cn0KZnVuY3Rpb24gaXNzdWUoLi4uYXJncykgewogIGNvbnN0IFtpc3MsIGlucHV0LCBpbnN0XSA9IGFyZ3M7CiAgaWYgKHR5cGVvZiBpc3MgPT09ICJzdHJpbmciKSB7CiAgICByZXR1cm4gewogICAgICBtZXNzYWdlOiBpc3MsCiAgICAgIGNvZGU6ICJjdXN0b20iLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfTsKICB9CiAgcmV0dXJuIHsgLi4uaXNzIH07Cn0KZnVuY3Rpb24gY2xlYW5FbnVtKG9iaikgewogIHJldHVybiBPYmplY3QuZW50cmllcyhvYmopLmZpbHRlcigoW2ssIF9dKSA9PiB7CiAgICByZXR1cm4gTnVtYmVyLmlzTmFOKE51bWJlci5wYXJzZUludChrLCAxMCkpOwogIH0pLm1hcCgoZWwpID0+IGVsWzFdKTsKfQpmdW5jdGlvbiBiYXNlNjRUb1VpbnQ4QXJyYXkoYmFzZTY0MikgewogIGNvbnN0IGJpbmFyeVN0cmluZyA9IGF0b2IoYmFzZTY0Mik7CiAgY29uc3QgYnl0ZXMgPSBuZXcgVWludDhBcnJheShiaW5hcnlTdHJpbmcubGVuZ3RoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IGJpbmFyeVN0cmluZy5sZW5ndGg7IGkrKykgewogICAgYnl0ZXNbaV0gPSBiaW5hcnlTdHJpbmcuY2hhckNvZGVBdChpKTsKICB9CiAgcmV0dXJuIGJ5dGVzOwp9CmZ1bmN0aW9uIHVpbnQ4QXJyYXlUb0Jhc2U2NChieXRlcykgewogIGxldCBiaW5hcnlTdHJpbmcgPSAiIjsKICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7CiAgICBiaW5hcnlTdHJpbmcgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSk7CiAgfQogIHJldHVybiBidG9hKGJpbmFyeVN0cmluZyk7Cn0KZnVuY3Rpb24gYmFzZTY0dXJsVG9VaW50OEFycmF5KGJhc2U2NHVybDIpIHsKICBjb25zdCBiYXNlNjQyID0gYmFzZTY0dXJsMi5yZXBsYWNlKC8tL2csICIrIikucmVwbGFjZSgvXy9nLCAiLyIpOwogIGNvbnN0IHBhZGRpbmcgPSAiPSIucmVwZWF0KCg0IC0gYmFzZTY0Mi5sZW5ndGggJSA0KSAlIDQpOwogIHJldHVybiBiYXNlNjRUb1VpbnQ4QXJyYXkoYmFzZTY0MiArIHBhZGRpbmcpOwp9CmZ1bmN0aW9uIHVpbnQ4QXJyYXlUb0Jhc2U2NHVybChieXRlcykgewogIHJldHVybiB1aW50OEFycmF5VG9CYXNlNjQoYnl0ZXMpLnJlcGxhY2UoL1wrL2csICItIikucmVwbGFjZSgvXC8vZywgIl8iKS5yZXBsYWNlKC89L2csICIiKTsKfQpmdW5jdGlvbiBoZXhUb1VpbnQ4QXJyYXkoaGV4KSB7CiAgY29uc3QgY2xlYW5IZXggPSBoZXgucmVwbGFjZSgvXjB4LywgIiIpOwogIGlmIChjbGVhbkhleC5sZW5ndGggJSAyICE9PSAwKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgaGV4IHN0cmluZyBsZW5ndGgiKTsKICB9CiAgY29uc3QgYnl0ZXMgPSBuZXcgVWludDhBcnJheShjbGVhbkhleC5sZW5ndGggLyAyKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IGNsZWFuSGV4Lmxlbmd0aDsgaSArPSAyKSB7CiAgICBieXRlc1tpIC8gMl0gPSBOdW1iZXIucGFyc2VJbnQoY2xlYW5IZXguc2xpY2UoaSwgaSArIDIpLCAxNik7CiAgfQogIHJldHVybiBieXRlczsKfQpmdW5jdGlvbiB1aW50OEFycmF5VG9IZXgoYnl0ZXMpIHsKICByZXR1cm4gQXJyYXkuZnJvbShieXRlcykubWFwKChiKSA9PiBiLnRvU3RyaW5nKDE2KS5wYWRTdGFydCgyLCAiMCIpKS5qb2luKCIiKTsKfQp2YXIgQ2xhc3MgPSBjbGFzcyB7CiAgY29uc3RydWN0b3IoLi4uX2FyZ3MpIHsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvZXJyb3JzLmpzCnZhciBpbml0aWFsaXplciA9IChpbnN0LCBkZWYpID0+IHsKICBpbnN0Lm5hbWUgPSAiJFpvZEVycm9yIjsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgIl96b2QiLCB7CiAgICB2YWx1ZTogaW5zdC5fem9kLAogICAgZW51bWVyYWJsZTogZmFsc2UKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgImlzc3VlcyIsIHsKICAgIHZhbHVlOiBkZWYsCiAgICBlbnVtZXJhYmxlOiBmYWxzZQogIH0pOwogIGluc3QubWVzc2FnZSA9IEpTT04uc3RyaW5naWZ5KGRlZiwganNvblN0cmluZ2lmeVJlcGxhY2VyLCAyKTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoaW5zdCwgInRvU3RyaW5nIiwgewogICAgdmFsdWU6ICgpID0+IGluc3QubWVzc2FnZSwKICAgIGVudW1lcmFibGU6IGZhbHNlCiAgfSk7Cn07CnZhciAkWm9kRXJyb3IgPSAkY29uc3RydWN0b3IoIiRab2RFcnJvciIsIGluaXRpYWxpemVyKTsKdmFyICRab2RSZWFsRXJyb3IgPSAkY29uc3RydWN0b3IoIiRab2RFcnJvciIsIGluaXRpYWxpemVyLCB7IFBhcmVudDogRXJyb3IgfSk7CmZ1bmN0aW9uIGZsYXR0ZW5FcnJvcihlcnJvciwgbWFwcGVyID0gKGlzc3VlMikgPT4gaXNzdWUyLm1lc3NhZ2UpIHsKICBjb25zdCBmaWVsZEVycm9ycyA9IHt9OwogIGNvbnN0IGZvcm1FcnJvcnMgPSBbXTsKICBmb3IgKGNvbnN0IHN1YiBvZiBlcnJvci5pc3N1ZXMpIHsKICAgIGlmIChzdWIucGF0aC5sZW5ndGggPiAwKSB7CiAgICAgIGZpZWxkRXJyb3JzW3N1Yi5wYXRoWzBdXSA9IGZpZWxkRXJyb3JzW3N1Yi5wYXRoWzBdXSB8fCBbXTsKICAgICAgZmllbGRFcnJvcnNbc3ViLnBhdGhbMF1dLnB1c2gobWFwcGVyKHN1YikpOwogICAgfSBlbHNlIHsKICAgICAgZm9ybUVycm9ycy5wdXNoKG1hcHBlcihzdWIpKTsKICAgIH0KICB9CiAgcmV0dXJuIHsgZm9ybUVycm9ycywgZmllbGRFcnJvcnMgfTsKfQpmdW5jdGlvbiBmb3JtYXRFcnJvcihlcnJvciwgbWFwcGVyID0gKGlzc3VlMikgPT4gaXNzdWUyLm1lc3NhZ2UpIHsKICBjb25zdCBmaWVsZEVycm9ycyA9IHsgX2Vycm9yczogW10gfTsKICBjb25zdCBwcm9jZXNzRXJyb3IgPSAoZXJyb3IyLCBwYXRoMiA9IFtdKSA9PiB7CiAgICBmb3IgKGNvbnN0IGlzc3VlMiBvZiBlcnJvcjIuaXNzdWVzKSB7CiAgICAgIGlmIChpc3N1ZTIuY29kZSA9PT0gImludmFsaWRfdW5pb24iICYmIGlzc3VlMi5lcnJvcnMubGVuZ3RoKSB7CiAgICAgICAgaXNzdWUyLmVycm9ycy5tYXAoKGlzc3VlcykgPT4gcHJvY2Vzc0Vycm9yKHsgaXNzdWVzIH0sIFsuLi5wYXRoMiwgLi4uaXNzdWUyLnBhdGhdKSk7CiAgICAgIH0gZWxzZSBpZiAoaXNzdWUyLmNvZGUgPT09ICJpbnZhbGlkX2tleSIpIHsKICAgICAgICBwcm9jZXNzRXJyb3IoeyBpc3N1ZXM6IGlzc3VlMi5pc3N1ZXMgfSwgWy4uLnBhdGgyLCAuLi5pc3N1ZTIucGF0aF0pOwogICAgICB9IGVsc2UgaWYgKGlzc3VlMi5jb2RlID09PSAiaW52YWxpZF9lbGVtZW50IikgewogICAgICAgIHByb2Nlc3NFcnJvcih7IGlzc3VlczogaXNzdWUyLmlzc3VlcyB9LCBbLi4ucGF0aDIsIC4uLmlzc3VlMi5wYXRoXSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgZnVsbHBhdGggPSBbLi4ucGF0aDIsIC4uLmlzc3VlMi5wYXRoXTsKICAgICAgICBpZiAoZnVsbHBhdGgubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICBmaWVsZEVycm9ycy5fZXJyb3JzLnB1c2gobWFwcGVyKGlzc3VlMikpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsZXQgY3VyciA9IGZpZWxkRXJyb3JzOwogICAgICAgICAgbGV0IGkgPSAwOwogICAgICAgICAgd2hpbGUgKGkgPCBmdWxscGF0aC5sZW5ndGgpIHsKICAgICAgICAgICAgY29uc3QgZWwgPSBmdWxscGF0aFtpXTsKICAgICAgICAgICAgY29uc3QgdGVybWluYWwgPSBpID09PSBmdWxscGF0aC5sZW5ndGggLSAxOwogICAgICAgICAgICBpZiAoIXRlcm1pbmFsKSB7CiAgICAgICAgICAgICAgY3VycltlbF0gPSBjdXJyW2VsXSB8fCB7IF9lcnJvcnM6IFtdIH07CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgY3VycltlbF0gPSBjdXJyW2VsXSB8fCB7IF9lcnJvcnM6IFtdIH07CiAgICAgICAgICAgICAgY3VycltlbF0uX2Vycm9ycy5wdXNoKG1hcHBlcihpc3N1ZTIpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjdXJyID0gY3VycltlbF07CiAgICAgICAgICAgIGkrKzsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9OwogIHByb2Nlc3NFcnJvcihlcnJvcik7CiAgcmV0dXJuIGZpZWxkRXJyb3JzOwp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvcGFyc2UuanMKdmFyIF9wYXJzZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCwgX3BhcmFtcykgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGFzeW5jOiBmYWxzZSB9IDogeyBhc3luYzogZmFsc2UgfTsKICBjb25zdCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICB9CiAgaWYgKHJlc3VsdC5pc3N1ZXMubGVuZ3RoKSB7CiAgICBjb25zdCBlID0gbmV3IChfcGFyYW1zPy5FcnIgPz8gX0VycikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSk7CiAgICBjYXB0dXJlU3RhY2tUcmFjZShlLCBfcGFyYW1zPy5jYWxsZWUpOwogICAgdGhyb3cgZTsKICB9CiAgcmV0dXJuIHJlc3VsdC52YWx1ZTsKfTsKdmFyIF9wYXJzZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4LCBwYXJhbXMpID0+IHsKICBjb25zdCBjdHggPSBfY3R4ID8geyAuLi5fY3R4LCBhc3luYzogdHJ1ZSB9IDogeyBhc3luYzogdHJ1ZSB9OwogIGxldCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKQogICAgcmVzdWx0ID0gYXdhaXQgcmVzdWx0OwogIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgY29uc3QgZSA9IG5ldyAocGFyYW1zPy5FcnIgPz8gX0VycikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSk7CiAgICBjYXB0dXJlU3RhY2tUcmFjZShlLCBwYXJhbXM/LmNhbGxlZSk7CiAgICB0aHJvdyBlOwogIH0KICByZXR1cm4gcmVzdWx0LnZhbHVlOwp9Owp2YXIgX3NhZmVQYXJzZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGFzeW5jOiBmYWxzZSB9IDogeyBhc3luYzogZmFsc2UgfTsKICBjb25zdCByZXN1bHQgPSBzY2hlbWEuX3pvZC5ydW4oeyB2YWx1ZSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICB9CiAgcmV0dXJuIHJlc3VsdC5pc3N1ZXMubGVuZ3RoID8gewogICAgc3VjY2VzczogZmFsc2UsCiAgICBlcnJvcjogbmV3IChfRXJyID8/ICRab2RFcnJvcikocmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSkKICB9IDogeyBzdWNjZXNzOiB0cnVlLCBkYXRhOiByZXN1bHQudmFsdWUgfTsKfTsKdmFyIHNhZmVQYXJzZSA9IC8qIEBfX1BVUkVfXyAqLyBfc2FmZVBhcnNlKCRab2RSZWFsRXJyb3IpOwp2YXIgX3NhZmVQYXJzZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgY29uc3QgY3R4ID0gX2N0eCA/IHsgLi4uX2N0eCwgYXN5bmM6IHRydWUgfSA6IHsgYXN5bmM6IHRydWUgfTsKICBsZXQgcmVzdWx0ID0gc2NoZW1hLl96b2QucnVuKHsgdmFsdWUsIGlzc3VlczogW10gfSwgY3R4KTsKICBpZiAocmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkKICAgIHJlc3VsdCA9IGF3YWl0IHJlc3VsdDsKICByZXR1cm4gcmVzdWx0Lmlzc3Vlcy5sZW5ndGggPyB7CiAgICBzdWNjZXNzOiBmYWxzZSwKICAgIGVycm9yOiBuZXcgX0VycihyZXN1bHQuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpKQogIH0gOiB7IHN1Y2Nlc3M6IHRydWUsIGRhdGE6IHJlc3VsdC52YWx1ZSB9Owp9Owp2YXIgc2FmZVBhcnNlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVQYXJzZUFzeW5jKCRab2RSZWFsRXJyb3IpOwp2YXIgX2VuY29kZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3BhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfZGVjb2RlID0gKF9FcnIpID0+IChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgcmV0dXJuIF9wYXJzZShfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKdmFyIF9lbmNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3BhcnNlQXN5bmMoX0Vycikoc2NoZW1hLCB2YWx1ZSwgY3R4KTsKfTsKdmFyIF9kZWNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIHJldHVybiBfcGFyc2VBc3luYyhfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKdmFyIF9zYWZlRW5jb2RlID0gKF9FcnIpID0+IChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgY29uc3QgY3R4ID0gX2N0eCA/IHsgLi4uX2N0eCwgZGlyZWN0aW9uOiAiYmFja3dhcmQiIH0gOiB7IGRpcmVjdGlvbjogImJhY2t3YXJkIiB9OwogIHJldHVybiBfc2FmZVBhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfc2FmZURlY29kZSA9IChfRXJyKSA9PiAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIHJldHVybiBfc2FmZVBhcnNlKF9FcnIpKHNjaGVtYSwgdmFsdWUsIF9jdHgpOwp9Owp2YXIgX3NhZmVFbmNvZGVBc3luYyA9IChfRXJyKSA9PiBhc3luYyAoc2NoZW1hLCB2YWx1ZSwgX2N0eCkgPT4gewogIGNvbnN0IGN0eCA9IF9jdHggPyB7IC4uLl9jdHgsIGRpcmVjdGlvbjogImJhY2t3YXJkIiB9IDogeyBkaXJlY3Rpb246ICJiYWNrd2FyZCIgfTsKICByZXR1cm4gX3NhZmVQYXJzZUFzeW5jKF9FcnIpKHNjaGVtYSwgdmFsdWUsIGN0eCk7Cn07CnZhciBfc2FmZURlY29kZUFzeW5jID0gKF9FcnIpID0+IGFzeW5jIChzY2hlbWEsIHZhbHVlLCBfY3R4KSA9PiB7CiAgcmV0dXJuIF9zYWZlUGFyc2VBc3luYyhfRXJyKShzY2hlbWEsIHZhbHVlLCBfY3R4KTsKfTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9yZWdleGVzLmpzCnZhciBjdWlkID0gL15bY0NdWzAtOWEtel17Nix9JC87CnZhciBjdWlkMiA9IC9eWzAtOWEtel0rJC87CnZhciB1bGlkID0gL15bMC05QS1ISktNTlAtVFYtWmEtaGprbW5wLXR2LXpdezI2fSQvOwp2YXIgeGlkID0gL15bMC05YS12QS1WXXsyMH0kLzsKdmFyIGtzdWlkID0gL15bQS1aYS16MC05XXsyN30kLzsKdmFyIG5hbm9pZCA9IC9eW2EtekEtWjAtOV8tXXsyMX0kLzsKdmFyIGR1cmF0aW9uID0gL15QKD86KFxkK1cpfCg/IS4qVykoPz1cZHxUXGQpKFxkK1kpPyhcZCtNKT8oXGQrRCk/KFQoPz1cZCkoXGQrSCk/KFxkK00pPyhcZCsoWy4sXVxkKyk/Uyk/KT8pJC87CnZhciBndWlkID0gL14oWzAtOWEtZkEtRl17OH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17NH0tWzAtOWEtZkEtRl17MTJ9KSQvOwp2YXIgdXVpZCA9ICh2ZXJzaW9uMikgPT4gewogIGlmICghdmVyc2lvbjIpCiAgICByZXR1cm4gL14oWzAtOWEtZkEtRl17OH0tWzAtOWEtZkEtRl17NH0tWzEtOF1bMC05YS1mQS1GXXszfS1bODlhYkFCXVswLTlhLWZBLUZdezN9LVswLTlhLWZBLUZdezEyfXwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8ZmZmZmZmZmYtZmZmZi1mZmZmLWZmZmYtZmZmZmZmZmZmZmZmKSQvOwogIHJldHVybiBuZXcgUmVnRXhwKGBeKFswLTlhLWZBLUZdezh9LVswLTlhLWZBLUZdezR9LSR7dmVyc2lvbjJ9WzAtOWEtZkEtRl17M30tWzg5YWJBQl1bMC05YS1mQS1GXXszfS1bMC05YS1mQS1GXXsxMn0pJGApOwp9Owp2YXIgZW1haWwgPSAvXig/IVwuKSg/IS4qXC5cLikoW0EtWmEtejAtOV8nK1wtXC5dKilbQS1aYS16MC05XystXUAoW0EtWmEtejAtOV1bQS1aYS16MC05XC1dKlwuKStbQS1aYS16XXsyLH0kLzsKdmFyIF9lbW9qaSA9IGBeKFxccHtFeHRlbmRlZF9QaWN0b2dyYXBoaWN9fFxccHtFbW9qaV9Db21wb25lbnR9KSskYDsKZnVuY3Rpb24gZW1vamkoKSB7CiAgcmV0dXJuIG5ldyBSZWdFeHAoX2Vtb2ppLCAidSIpOwp9CnZhciBpcHY0ID0gL14oPzooPzoyNVswLTVdfDJbMC00XVswLTldfDFbMC05XVswLTldfFsxLTldWzAtOV18WzAtOV0pXC4pezN9KD86MjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV1bMC05XXxbMS05XVswLTldfFswLTldKSQvOwp2YXIgaXB2NiA9IC9eKChbMC05YS1mQS1GXXsxLDR9Oil7N31bMC05YS1mQS1GXXsxLDR9fChbMC05YS1mQS1GXXsxLDR9Oil7MSw3fTp8KFswLTlhLWZBLUZdezEsNH06KXsxLDZ9OlswLTlhLWZBLUZdezEsNH18KFswLTlhLWZBLUZdezEsNH06KXsxLDV9KDpbMC05YS1mQS1GXXsxLDR9KXsxLDJ9fChbMC05YS1mQS1GXXsxLDR9Oil7MSw0fSg6WzAtOWEtZkEtRl17MSw0fSl7MSwzfXwoWzAtOWEtZkEtRl17MSw0fTopezEsM30oOlswLTlhLWZBLUZdezEsNH0pezEsNH18KFswLTlhLWZBLUZdezEsNH06KXsxLDJ9KDpbMC05YS1mQS1GXXsxLDR9KXsxLDV9fFswLTlhLWZBLUZdezEsNH06KCg6WzAtOWEtZkEtRl17MSw0fSl7MSw2fSl8OigoOlswLTlhLWZBLUZdezEsNH0pezEsN318OikpJC87CnZhciBjaWRydjQgPSAvXigoMjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV1bMC05XXxbMS05XVswLTldfFswLTldKVwuKXszfSgyNVswLTVdfDJbMC00XVswLTldfDFbMC05XVswLTldfFsxLTldWzAtOV18WzAtOV0pXC8oWzAtOV18WzEtMl1bMC05XXwzWzAtMl0pJC87CnZhciBjaWRydjYgPSAvXigoWzAtOWEtZkEtRl17MSw0fTopezd9WzAtOWEtZkEtRl17MSw0fXw6OnwoWzAtOWEtZkEtRl17MSw0fSk/OjooWzAtOWEtZkEtRl17MSw0fTo/KXswLDZ9KVwvKDEyWzAtOF18MVswMV1bMC05XXxbMS05XT9bMC05XSkkLzsKdmFyIGJhc2U2NCA9IC9eJHxeKD86WzAtOWEtekEtWisvXXs0fSkqKD86KD86WzAtOWEtekEtWisvXXsyfT09KXwoPzpbMC05YS16QS1aKy9dezN9PSkpPyQvOwp2YXIgYmFzZTY0dXJsID0gL15bQS1aYS16MC05Xy1dKiQvOwp2YXIgaHR0cFByb3RvY29sID0gL15odHRwcz8kLzsKdmFyIGUxNjQgPSAvXlwrWzEtOV1cZHs2LDE0fSQvOwp2YXIgZGF0ZVNvdXJjZSA9IGAoPzooPzpcXGRcXGRbMjQ2OF1bMDQ4XXxcXGRcXGRbMTM1NzldWzI2XXxcXGRcXGQwWzQ4XXxbMDI0NjhdWzA0OF0wMHxbMTM1NzldWzI2XTAwKS0wMi0yOXxcXGR7NH0tKD86KD86MFsxMzU3OF18MVswMl0pLSg/OjBbMS05XXxbMTJdXFxkfDNbMDFdKXwoPzowWzQ2OV18MTEpLSg/OjBbMS05XXxbMTJdXFxkfDMwKXwoPzowMiktKD86MFsxLTldfDFcXGR8MlswLThdKSkpYDsKdmFyIGRhdGUgPSAvKiBAX19QVVJFX18gKi8gbmV3IFJlZ0V4cChgXiR7ZGF0ZVNvdXJjZX0kYCk7CmZ1bmN0aW9uIHRpbWVTb3VyY2UoYXJncykgewogIGNvbnN0IGhobW0gPSBgKD86WzAxXVxcZHwyWzAtM10pOlswLTVdXFxkYDsKICBjb25zdCByZWdleCA9IHR5cGVvZiBhcmdzLnByZWNpc2lvbiA9PT0gIm51bWJlciIgPyBhcmdzLnByZWNpc2lvbiA9PT0gLTEgPyBgJHtoaG1tfWAgOiBhcmdzLnByZWNpc2lvbiA9PT0gMCA/IGAke2hobW19OlswLTVdXFxkYCA6IGAke2hobW19OlswLTVdXFxkXFwuXFxkeyR7YXJncy5wcmVjaXNpb259fWAgOiBgJHtoaG1tfSg/OjpbMC01XVxcZCg/OlxcLlxcZCspPyk/YDsKICByZXR1cm4gcmVnZXg7Cn0KZnVuY3Rpb24gdGltZShhcmdzKSB7CiAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke3RpbWVTb3VyY2UoYXJncyl9JGApOwp9CmZ1bmN0aW9uIGRhdGV0aW1lKGFyZ3MpIHsKICBjb25zdCB0aW1lMyA9IHRpbWVTb3VyY2UoeyBwcmVjaXNpb246IGFyZ3MucHJlY2lzaW9uIH0pOwogIGNvbnN0IG9wdHMgPSBbIloiXTsKICBpZiAoYXJncy5sb2NhbCkKICAgIG9wdHMucHVzaCgiIik7CiAgaWYgKGFyZ3Mub2Zmc2V0KQogICAgb3B0cy5wdXNoKGAoWystXSg/OlswMV1cXGR8MlswLTNdKTpbMC01XVxcZClgKTsKICBjb25zdCB0aW1lUmVnZXggPSBgJHt0aW1lM30oPzoke29wdHMuam9pbigifCIpfSlgOwogIHJldHVybiBuZXcgUmVnRXhwKGBeJHtkYXRlU291cmNlfVQoPzoke3RpbWVSZWdleH0pJGApOwp9CnZhciBzdHJpbmcgPSAocGFyYW1zKSA9PiB7CiAgY29uc3QgcmVnZXggPSBwYXJhbXMgPyBgW1xcc1xcU117JHtwYXJhbXM/Lm1pbmltdW0gPz8gMH0sJHtwYXJhbXM/Lm1heGltdW0gPz8gIiJ9fWAgOiBgW1xcc1xcU10qYDsKICByZXR1cm4gbmV3IFJlZ0V4cChgXiR7cmVnZXh9JGApOwp9Owp2YXIgaW50ZWdlciA9IC9eLT9cZCskLzsKdmFyIG51bWJlciA9IC9eLT9cZCsoPzpcLlxkKyk/JC87CnZhciBib29sZWFuID0gL14oPzp0cnVlfGZhbHNlKSQvaTsKdmFyIGxvd2VyY2FzZSA9IC9eW15BLVpdKiQvOwp2YXIgdXBwZXJjYXNlID0gL15bXmEtel0qJC87CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvY2hlY2tzLmpzCnZhciAkWm9kQ2hlY2sgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2siLCAoaW5zdCwgZGVmKSA9PiB7CiAgdmFyIF9hMzsKICBpbnN0Ll96b2QgPz8gKGluc3QuX3pvZCA9IHt9KTsKICBpbnN0Ll96b2QuZGVmID0gZGVmOwogIChfYTMgPSBpbnN0Ll96b2QpLm9uYXR0YWNoID8/IChfYTMub25hdHRhY2ggPSBbXSk7Cn0pOwp2YXIgbnVtZXJpY09yaWdpbk1hcCA9IHsKICBudW1iZXI6ICJudW1iZXIiLAogIGJpZ2ludDogImJpZ2ludCIsCiAgb2JqZWN0OiAiZGF0ZSIKfTsKdmFyICRab2RDaGVja0xlc3NUaGFuID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrTGVzc1RoYW4iLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICBjb25zdCBvcmlnaW4gPSBudW1lcmljT3JpZ2luTWFwW3R5cGVvZiBkZWYudmFsdWVdOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgYmFnID0gaW5zdDIuX3pvZC5iYWc7CiAgICBjb25zdCBjdXJyID0gKGRlZi5pbmNsdXNpdmUgPyBiYWcubWF4aW11bSA6IGJhZy5leGNsdXNpdmVNYXhpbXVtKSA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBpZiAoZGVmLnZhbHVlIDwgY3VycikgewogICAgICBpZiAoZGVmLmluY2x1c2l2ZSkKICAgICAgICBiYWcubWF4aW11bSA9IGRlZi52YWx1ZTsKICAgICAgZWxzZQogICAgICAgIGJhZy5leGNsdXNpdmVNYXhpbXVtID0gZGVmLnZhbHVlOwogICAgfQogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBpZiAoZGVmLmluY2x1c2l2ZSA/IHBheWxvYWQudmFsdWUgPD0gZGVmLnZhbHVlIDogcGF5bG9hZC52YWx1ZSA8IGRlZi52YWx1ZSkgewogICAgICByZXR1cm47CiAgICB9CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luLAogICAgICBjb2RlOiAidG9vX2JpZyIsCiAgICAgIG1heGltdW06IHR5cGVvZiBkZWYudmFsdWUgPT09ICJvYmplY3QiID8gZGVmLnZhbHVlLmdldFRpbWUoKSA6IGRlZi52YWx1ZSwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluY2x1c2l2ZTogZGVmLmluY2x1c2l2ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZENoZWNrR3JlYXRlclRoYW4gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tHcmVhdGVyVGhhbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGNvbnN0IG9yaWdpbiA9IG51bWVyaWNPcmlnaW5NYXBbdHlwZW9mIGRlZi52YWx1ZV07CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICBjb25zdCBiYWcgPSBpbnN0Mi5fem9kLmJhZzsKICAgIGNvbnN0IGN1cnIgPSAoZGVmLmluY2x1c2l2ZSA/IGJhZy5taW5pbXVtIDogYmFnLmV4Y2x1c2l2ZU1pbmltdW0pID8/IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgIGlmIChkZWYudmFsdWUgPiBjdXJyKSB7CiAgICAgIGlmIChkZWYuaW5jbHVzaXZlKQogICAgICAgIGJhZy5taW5pbXVtID0gZGVmLnZhbHVlOwogICAgICBlbHNlCiAgICAgICAgYmFnLmV4Y2x1c2l2ZU1pbmltdW0gPSBkZWYudmFsdWU7CiAgICB9CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChkZWYuaW5jbHVzaXZlID8gcGF5bG9hZC52YWx1ZSA+PSBkZWYudmFsdWUgOiBwYXlsb2FkLnZhbHVlID4gZGVmLnZhbHVlKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW4sCiAgICAgIGNvZGU6ICJ0b29fc21hbGwiLAogICAgICBtaW5pbXVtOiB0eXBlb2YgZGVmLnZhbHVlID09PSAib2JqZWN0IiA/IGRlZi52YWx1ZS5nZXRUaW1lKCkgOiBkZWYudmFsdWUsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBpbmNsdXNpdmU6IGRlZi5pbmNsdXNpdmUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja011bHRpcGxlT2YgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tNdWx0aXBsZU9mIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICB2YXIgX2EzOwogICAgKF9hMyA9IGluc3QyLl96b2QuYmFnKS5tdWx0aXBsZU9mID8/IChfYTMubXVsdGlwbGVPZiA9IGRlZi52YWx1ZSk7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmICh0eXBlb2YgcGF5bG9hZC52YWx1ZSAhPT0gdHlwZW9mIGRlZi52YWx1ZSkKICAgICAgdGhyb3cgbmV3IEVycm9yKCJDYW5ub3QgbWl4IG51bWJlciBhbmQgYmlnaW50IGluIG11bHRpcGxlX29mIGNoZWNrLiIpOwogICAgY29uc3QgaXNNdWx0aXBsZSA9IHR5cGVvZiBwYXlsb2FkLnZhbHVlID09PSAiYmlnaW50IiA/IHBheWxvYWQudmFsdWUgJSBkZWYudmFsdWUgPT09IEJpZ0ludCgwKSA6IGZsb2F0U2FmZVJlbWFpbmRlcihwYXlsb2FkLnZhbHVlLCBkZWYudmFsdWUpID09PSAwOwogICAgaWYgKGlzTXVsdGlwbGUpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW46IHR5cGVvZiBwYXlsb2FkLnZhbHVlLAogICAgICBjb2RlOiAibm90X211bHRpcGxlX29mIiwKICAgICAgZGl2aXNvcjogZGVmLnZhbHVlLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZENoZWNrTnVtYmVyRm9ybWF0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrTnVtYmVyRm9ybWF0IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgZGVmLmZvcm1hdCA9IGRlZi5mb3JtYXQgfHwgImZsb2F0NjQiOwogIGNvbnN0IGlzSW50ID0gZGVmLmZvcm1hdD8uaW5jbHVkZXMoImludCIpOwogIGNvbnN0IG9yaWdpbiA9IGlzSW50ID8gImludCIgOiAibnVtYmVyIjsKICBjb25zdCBbbWluaW11bSwgbWF4aW11bV0gPSBOVU1CRVJfRk9STUFUX1JBTkdFU1tkZWYuZm9ybWF0XTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLmZvcm1hdCA9IGRlZi5mb3JtYXQ7CiAgICBiYWcubWluaW11bSA9IG1pbmltdW07CiAgICBiYWcubWF4aW11bSA9IG1heGltdW07CiAgICBpZiAoaXNJbnQpCiAgICAgIGJhZy5wYXR0ZXJuID0gaW50ZWdlcjsKICB9KTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKGlzSW50KSB7CiAgICAgIGlmICghTnVtYmVyLmlzSW50ZWdlcihpbnB1dCkpIHsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgIGV4cGVjdGVkOiBvcmlnaW4sCiAgICAgICAgICBmb3JtYXQ6IGRlZi5mb3JtYXQsCiAgICAgICAgICBjb2RlOiAiaW52YWxpZF90eXBlIiwKICAgICAgICAgIGNvbnRpbnVlOiBmYWxzZSwKICAgICAgICAgIGlucHV0LAogICAgICAgICAgaW5zdAogICAgICAgIH0pOwogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlucHV0KSkgewogICAgICAgIGlmIChpbnB1dCA+IDApIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgICAgICBpbnB1dCwKICAgICAgICAgICAgY29kZTogInRvb19iaWciLAogICAgICAgICAgICBtYXhpbXVtOiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUiwKICAgICAgICAgICAgbm90ZTogIkludGVnZXJzIG11c3QgYmUgd2l0aGluIHRoZSBzYWZlIGludGVnZXIgcmFuZ2UuIiwKICAgICAgICAgICAgaW5zdCwKICAgICAgICAgICAgb3JpZ2luLAogICAgICAgICAgICBpbmNsdXNpdmU6IHRydWUsCiAgICAgICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgICAgICB9KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgICAgIGlucHV0LAogICAgICAgICAgICBjb2RlOiAidG9vX3NtYWxsIiwKICAgICAgICAgICAgbWluaW11bTogTnVtYmVyLk1JTl9TQUZFX0lOVEVHRVIsCiAgICAgICAgICAgIG5vdGU6ICJJbnRlZ2VycyBtdXN0IGJlIHdpdGhpbiB0aGUgc2FmZSBpbnRlZ2VyIHJhbmdlLiIsCiAgICAgICAgICAgIGluc3QsCiAgICAgICAgICAgIG9yaWdpbiwKICAgICAgICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJldHVybjsKICAgICAgfQogICAgfQogICAgaWYgKGlucHV0IDwgbWluaW11bSkgewogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBvcmlnaW46ICJudW1iZXIiLAogICAgICAgIGlucHV0LAogICAgICAgIGNvZGU6ICJ0b29fc21hbGwiLAogICAgICAgIG1pbmltdW0sCiAgICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICAgIGluc3QsCiAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgfSk7CiAgICB9CiAgICBpZiAoaW5wdXQgPiBtYXhpbXVtKSB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIG9yaWdpbjogIm51bWJlciIsCiAgICAgICAgaW5wdXQsCiAgICAgICAgY29kZTogInRvb19iaWciLAogICAgICAgIG1heGltdW0sCiAgICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICAgIGluc3QsCiAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgfSk7CiAgICB9CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tNYXhMZW5ndGggPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tNYXhMZW5ndGgiLCAoaW5zdCwgZGVmKSA9PiB7CiAgdmFyIF9hMzsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIChfYTMgPSBpbnN0Ll96b2QuZGVmKS53aGVuID8/IChfYTMud2hlbiA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCB2YWwgPSBwYXlsb2FkLnZhbHVlOwogICAgcmV0dXJuICFudWxsaXNoKHZhbCkgJiYgdmFsLmxlbmd0aCAhPT0gdm9pZCAwOwogIH0pOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgY3VyciA9IGluc3QyLl96b2QuYmFnLm1heGltdW0gPz8gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgaWYgKGRlZi5tYXhpbXVtIDwgY3VycikKICAgICAgaW5zdDIuX3pvZC5iYWcubWF4aW11bSA9IGRlZi5tYXhpbXVtOwogIH0pOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7CiAgICBjb25zdCBsZW5ndGggPSBpbnB1dC5sZW5ndGg7CiAgICBpZiAobGVuZ3RoIDw9IGRlZi5tYXhpbXVtKQogICAgICByZXR1cm47CiAgICBjb25zdCBvcmlnaW4gPSBnZXRMZW5ndGhhYmxlT3JpZ2luKGlucHV0KTsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW4sCiAgICAgIGNvZGU6ICJ0b29fYmlnIiwKICAgICAgbWF4aW11bTogZGVmLm1heGltdW0sCiAgICAgIGluY2x1c2l2ZTogdHJ1ZSwKICAgICAgaW5wdXQsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja01pbkxlbmd0aCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja01pbkxlbmd0aCIsIChpbnN0LCBkZWYpID0+IHsKICB2YXIgX2EzOwogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgKF9hMyA9IGluc3QuX3pvZC5kZWYpLndoZW4gPz8gKF9hMy53aGVuID0gKHBheWxvYWQpID0+IHsKICAgIGNvbnN0IHZhbCA9IHBheWxvYWQudmFsdWU7CiAgICByZXR1cm4gIW51bGxpc2godmFsKSAmJiB2YWwubGVuZ3RoICE9PSB2b2lkIDA7CiAgfSk7CiAgaW5zdC5fem9kLm9uYXR0YWNoLnB1c2goKGluc3QyKSA9PiB7CiAgICBjb25zdCBjdXJyID0gaW5zdDIuX3pvZC5iYWcubWluaW11bSA/PyBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBpZiAoZGVmLm1pbmltdW0gPiBjdXJyKQogICAgICBpbnN0Mi5fem9kLmJhZy5taW5pbXVtID0gZGVmLm1pbmltdW07CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGNvbnN0IGxlbmd0aCA9IGlucHV0Lmxlbmd0aDsKICAgIGlmIChsZW5ndGggPj0gZGVmLm1pbmltdW0pCiAgICAgIHJldHVybjsKICAgIGNvbnN0IG9yaWdpbiA9IGdldExlbmd0aGFibGVPcmlnaW4oaW5wdXQpOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbiwKICAgICAgY29kZTogInRvb19zbWFsbCIsCiAgICAgIG1pbmltdW06IGRlZi5taW5pbXVtLAogICAgICBpbmNsdXNpdmU6IHRydWUsCiAgICAgIGlucHV0LAogICAgICBpbnN0LAogICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kQ2hlY2tMZW5ndGhFcXVhbHMgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ2hlY2tMZW5ndGhFcXVhbHMiLCAoaW5zdCwgZGVmKSA9PiB7CiAgdmFyIF9hMzsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIChfYTMgPSBpbnN0Ll96b2QuZGVmKS53aGVuID8/IChfYTMud2hlbiA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCB2YWwgPSBwYXlsb2FkLnZhbHVlOwogICAgcmV0dXJuICFudWxsaXNoKHZhbCkgJiYgdmFsLmxlbmd0aCAhPT0gdm9pZCAwOwogIH0pOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgYmFnID0gaW5zdDIuX3pvZC5iYWc7CiAgICBiYWcubWluaW11bSA9IGRlZi5sZW5ndGg7CiAgICBiYWcubWF4aW11bSA9IGRlZi5sZW5ndGg7CiAgICBiYWcubGVuZ3RoID0gZGVmLmxlbmd0aDsKICB9KTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgY29uc3QgbGVuZ3RoID0gaW5wdXQubGVuZ3RoOwogICAgaWYgKGxlbmd0aCA9PT0gZGVmLmxlbmd0aCkKICAgICAgcmV0dXJuOwogICAgY29uc3Qgb3JpZ2luID0gZ2V0TGVuZ3RoYWJsZU9yaWdpbihpbnB1dCk7CiAgICBjb25zdCB0b29CaWcgPSBsZW5ndGggPiBkZWYubGVuZ3RoOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbiwKICAgICAgLi4udG9vQmlnID8geyBjb2RlOiAidG9vX2JpZyIsIG1heGltdW06IGRlZi5sZW5ndGggfSA6IHsgY29kZTogInRvb19zbWFsbCIsIG1pbmltdW06IGRlZi5sZW5ndGggfSwKICAgICAgaW5jbHVzaXZlOiB0cnVlLAogICAgICBleGFjdDogdHJ1ZSwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja1N0cmluZ0Zvcm1hdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja1N0cmluZ0Zvcm1hdCIsIChpbnN0LCBkZWYpID0+IHsKICB2YXIgX2EzLCBfYjsKICAkWm9kQ2hlY2suaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgYmFnID0gaW5zdDIuX3pvZC5iYWc7CiAgICBiYWcuZm9ybWF0ID0gZGVmLmZvcm1hdDsKICAgIGlmIChkZWYucGF0dGVybikgewogICAgICBiYWcucGF0dGVybnMgPz8gKGJhZy5wYXR0ZXJucyA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KCkpOwogICAgICBiYWcucGF0dGVybnMuYWRkKGRlZi5wYXR0ZXJuKTsKICAgIH0KICB9KTsKICBpZiAoZGVmLnBhdHRlcm4pCiAgICAoX2EzID0gaW5zdC5fem9kKS5jaGVjayA/PyAoX2EzLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgICAgZGVmLnBhdHRlcm4ubGFzdEluZGV4ID0gMDsKICAgICAgaWYgKGRlZi5wYXR0ZXJuLnRlc3QocGF5bG9hZC52YWx1ZSkpCiAgICAgICAgcmV0dXJuOwogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBvcmlnaW46ICJzdHJpbmciLAogICAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgICAgZm9ybWF0OiBkZWYuZm9ybWF0LAogICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICAgIC4uLmRlZi5wYXR0ZXJuID8geyBwYXR0ZXJuOiBkZWYucGF0dGVybi50b1N0cmluZygpIH0gOiB7fSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfSk7CiAgZWxzZQogICAgKF9iID0gaW5zdC5fem9kKS5jaGVjayA/PyAoX2IuY2hlY2sgPSAoKSA9PiB7CiAgICB9KTsKfSk7CnZhciAkWm9kQ2hlY2tSZWdleCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja1JlZ2V4IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVja1N0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGRlZi5wYXR0ZXJuLmxhc3RJbmRleCA9IDA7CiAgICBpZiAoZGVmLnBhdHRlcm4udGVzdChwYXlsb2FkLnZhbHVlKSkKICAgICAgcmV0dXJuOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIG9yaWdpbjogInN0cmluZyIsCiAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgIGZvcm1hdDogInJlZ2V4IiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIHBhdHRlcm46IGRlZi5wYXR0ZXJuLnRvU3RyaW5nKCksCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja0xvd2VyQ2FzZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja0xvd2VyQ2FzZSIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBsb3dlcmNhc2UpOwogICRab2RDaGVja1N0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZENoZWNrVXBwZXJDYXNlID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrVXBwZXJDYXNlIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IHVwcGVyY2FzZSk7CiAgJFpvZENoZWNrU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kQ2hlY2tJbmNsdWRlcyA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja0luY2x1ZGVzIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgZXNjYXBlZFJlZ2V4ID0gZXNjYXBlUmVnZXgoZGVmLmluY2x1ZGVzKTsKICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cCh0eXBlb2YgZGVmLnBvc2l0aW9uID09PSAibnVtYmVyIiA/IGBeLnske2RlZi5wb3NpdGlvbn19JHtlc2NhcGVkUmVnZXh9YCA6IGVzY2FwZWRSZWdleCk7CiAgZGVmLnBhdHRlcm4gPSBwYXR0ZXJuOwogIGluc3QuX3pvZC5vbmF0dGFjaC5wdXNoKChpbnN0MikgPT4gewogICAgY29uc3QgYmFnID0gaW5zdDIuX3pvZC5iYWc7CiAgICBiYWcucGF0dGVybnMgPz8gKGJhZy5wYXR0ZXJucyA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KCkpOwogICAgYmFnLnBhdHRlcm5zLmFkZChwYXR0ZXJuKTsKICB9KTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgaWYgKHBheWxvYWQudmFsdWUuaW5jbHVkZXMoZGVmLmluY2x1ZGVzLCBkZWYucG9zaXRpb24pKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luOiAic3RyaW5nIiwKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAiaW5jbHVkZXMiLAogICAgICBpbmNsdWRlczogZGVmLmluY2x1ZGVzLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZENoZWNrU3RhcnRzV2l0aCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDaGVja1N0YXJ0c1dpdGgiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChgXiR7ZXNjYXBlUmVnZXgoZGVmLnByZWZpeCl9LipgKTsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBwYXR0ZXJuKTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLnBhdHRlcm5zID8/IChiYWcucGF0dGVybnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgIGJhZy5wYXR0ZXJucy5hZGQocGF0dGVybik7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChwYXlsb2FkLnZhbHVlLnN0YXJ0c1dpdGgoZGVmLnByZWZpeCkpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBvcmlnaW46ICJzdHJpbmciLAogICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICBmb3JtYXQ6ICJzdGFydHNfd2l0aCIsCiAgICAgIHByZWZpeDogZGVmLnByZWZpeCwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QsCiAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICB9KTsKICB9Owp9KTsKdmFyICRab2RDaGVja0VuZHNXaXRoID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrRW5kc1dpdGgiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrLmluaXQoaW5zdCwgZGVmKTsKICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChgLioke2VzY2FwZVJlZ2V4KGRlZi5zdWZmaXgpfSRgKTsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBwYXR0ZXJuKTsKICBpbnN0Ll96b2Qub25hdHRhY2gucHVzaCgoaW5zdDIpID0+IHsKICAgIGNvbnN0IGJhZyA9IGluc3QyLl96b2QuYmFnOwogICAgYmFnLnBhdHRlcm5zID8/IChiYWcucGF0dGVybnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgIGJhZy5wYXR0ZXJucy5hZGQocGF0dGVybik7CiAgfSk7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIGlmIChwYXlsb2FkLnZhbHVlLmVuZHNXaXRoKGRlZi5zdWZmaXgpKQogICAgICByZXR1cm47CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgb3JpZ2luOiAic3RyaW5nIiwKICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgZm9ybWF0OiAiZW5kc193aXRoIiwKICAgICAgc3VmZml4OiBkZWYuc3VmZml4LAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZENoZWNrT3ZlcndyaXRlID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENoZWNrT3ZlcndyaXRlIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmNoZWNrID0gKHBheWxvYWQpID0+IHsKICAgIHBheWxvYWQudmFsdWUgPSBkZWYudHgocGF5bG9hZC52YWx1ZSk7CiAgfTsKfSk7CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvZG9jLmpzCnZhciBEb2MgPSBjbGFzcyB7CiAgY29uc3RydWN0b3IoYXJncyA9IFtdKSB7CiAgICB0aGlzLmNvbnRlbnQgPSBbXTsKICAgIHRoaXMuaW5kZW50ID0gMDsKICAgIGlmICh0aGlzKQogICAgICB0aGlzLmFyZ3MgPSBhcmdzOwogIH0KICBpbmRlbnRlZChmbikgewogICAgdGhpcy5pbmRlbnQgKz0gMTsKICAgIGZuKHRoaXMpOwogICAgdGhpcy5pbmRlbnQgLT0gMTsKICB9CiAgd3JpdGUoYXJnKSB7CiAgICBpZiAodHlwZW9mIGFyZyA9PT0gImZ1bmN0aW9uIikgewogICAgICBhcmcodGhpcywgeyBleGVjdXRpb246ICJzeW5jIiB9KTsKICAgICAgYXJnKHRoaXMsIHsgZXhlY3V0aW9uOiAiYXN5bmMiIH0pOwogICAgICByZXR1cm47CiAgICB9CiAgICBjb25zdCBjb250ZW50ID0gYXJnOwogICAgY29uc3QgbGluZXMgPSBjb250ZW50LnNwbGl0KCJcbiIpLmZpbHRlcigoeCkgPT4geCk7CiAgICBjb25zdCBtaW5JbmRlbnQgPSBNYXRoLm1pbiguLi5saW5lcy5tYXAoKHgpID0+IHgubGVuZ3RoIC0geC50cmltU3RhcnQoKS5sZW5ndGgpKTsKICAgIGNvbnN0IGRlZGVudGVkID0gbGluZXMubWFwKCh4KSA9PiB4LnNsaWNlKG1pbkluZGVudCkpLm1hcCgoeCkgPT4gIiAiLnJlcGVhdCh0aGlzLmluZGVudCAqIDIpICsgeCk7CiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgZGVkZW50ZWQpIHsKICAgICAgdGhpcy5jb250ZW50LnB1c2gobGluZSk7CiAgICB9CiAgfQogIGNvbXBpbGUoKSB7CiAgICBjb25zdCBGID0gRnVuY3Rpb247CiAgICBjb25zdCBhcmdzID0gdGhpcz8uYXJnczsKICAgIGNvbnN0IGNvbnRlbnQgPSB0aGlzPy5jb250ZW50ID8/IFtgYF07CiAgICBjb25zdCBsaW5lcyA9IFsuLi5jb250ZW50Lm1hcCgoeCkgPT4gYCAgJHt4fWApXTsKICAgIHJldHVybiBuZXcgRiguLi5hcmdzLCBsaW5lcy5qb2luKCJcbiIpKTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvdmVyc2lvbnMuanMKdmFyIHZlcnNpb24gPSB7CiAgbWFqb3I6IDQsCiAgbWlub3I6IDQsCiAgcGF0Y2g6IDMKfTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9zY2hlbWFzLmpzCnZhciAkWm9kVHlwZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RUeXBlIiwgKGluc3QsIGRlZikgPT4gewogIHZhciBfYTM7CiAgaW5zdCA/PyAoaW5zdCA9IHt9KTsKICBpbnN0Ll96b2QuZGVmID0gZGVmOwogIGluc3QuX3pvZC5iYWcgPSBpbnN0Ll96b2QuYmFnIHx8IHt9OwogIGluc3QuX3pvZC52ZXJzaW9uID0gdmVyc2lvbjsKICBjb25zdCBjaGVja3MgPSBbLi4uaW5zdC5fem9kLmRlZi5jaGVja3MgPz8gW11dOwogIGlmIChpbnN0Ll96b2QudHJhaXRzLmhhcygiJFpvZENoZWNrIikpIHsKICAgIGNoZWNrcy51bnNoaWZ0KGluc3QpOwogIH0KICBmb3IgKGNvbnN0IGNoIG9mIGNoZWNrcykgewogICAgZm9yIChjb25zdCBmbiBvZiBjaC5fem9kLm9uYXR0YWNoKSB7CiAgICAgIGZuKGluc3QpOwogICAgfQogIH0KICBpZiAoY2hlY2tzLmxlbmd0aCA9PT0gMCkgewogICAgKF9hMyA9IGluc3QuX3pvZCkuZGVmZXJyZWQgPz8gKF9hMy5kZWZlcnJlZCA9IFtdKTsKICAgIGluc3QuX3pvZC5kZWZlcnJlZD8ucHVzaCgoKSA9PiB7CiAgICAgIGluc3QuX3pvZC5ydW4gPSBpbnN0Ll96b2QucGFyc2U7CiAgICB9KTsKICB9IGVsc2UgewogICAgY29uc3QgcnVuQ2hlY2tzID0gKHBheWxvYWQsIGNoZWNrczIsIGN0eCkgPT4gewogICAgICBsZXQgaXNBYm9ydGVkID0gYWJvcnRlZChwYXlsb2FkKTsKICAgICAgbGV0IGFzeW5jUmVzdWx0OwogICAgICBmb3IgKGNvbnN0IGNoIG9mIGNoZWNrczIpIHsKICAgICAgICBpZiAoY2guX3pvZC5kZWYud2hlbikgewogICAgICAgICAgaWYgKGV4cGxpY2l0bHlBYm9ydGVkKHBheWxvYWQpKQogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIGNvbnN0IHNob3VsZFJ1biA9IGNoLl96b2QuZGVmLndoZW4ocGF5bG9hZCk7CiAgICAgICAgICBpZiAoIXNob3VsZFJ1bikKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgfSBlbHNlIGlmIChpc0Fib3J0ZWQpIHsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBjb25zdCBjdXJyTGVuID0gcGF5bG9hZC5pc3N1ZXMubGVuZ3RoOwogICAgICAgIGNvbnN0IF8gPSBjaC5fem9kLmNoZWNrKHBheWxvYWQpOwogICAgICAgIGlmIChfIGluc3RhbmNlb2YgUHJvbWlzZSAmJiBjdHg/LmFzeW5jID09PSBmYWxzZSkgewogICAgICAgICAgdGhyb3cgbmV3ICRab2RBc3luY0Vycm9yKCk7CiAgICAgICAgfQogICAgICAgIGlmIChhc3luY1Jlc3VsdCB8fCBfIGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgYXN5bmNSZXN1bHQgPSAoYXN5bmNSZXN1bHQgPz8gUHJvbWlzZS5yZXNvbHZlKCkpLnRoZW4oYXN5bmMgKCkgPT4gewogICAgICAgICAgICBhd2FpdCBfOwogICAgICAgICAgICBjb25zdCBuZXh0TGVuID0gcGF5bG9hZC5pc3N1ZXMubGVuZ3RoOwogICAgICAgICAgICBpZiAobmV4dExlbiA9PT0gY3VyckxlbikKICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIGlmICghaXNBYm9ydGVkKQogICAgICAgICAgICAgIGlzQWJvcnRlZCA9IGFib3J0ZWQocGF5bG9hZCwgY3Vyckxlbik7CiAgICAgICAgICB9KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3QgbmV4dExlbiA9IHBheWxvYWQuaXNzdWVzLmxlbmd0aDsKICAgICAgICAgIGlmIChuZXh0TGVuID09PSBjdXJyTGVuKQogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIGlmICghaXNBYm9ydGVkKQogICAgICAgICAgICBpc0Fib3J0ZWQgPSBhYm9ydGVkKHBheWxvYWQsIGN1cnJMZW4pOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoYXN5bmNSZXN1bHQpIHsKICAgICAgICByZXR1cm4gYXN5bmNSZXN1bHQudGhlbigoKSA9PiB7CiAgICAgICAgICByZXR1cm4gcGF5bG9hZDsKICAgICAgICB9KTsKICAgICAgfQogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH07CiAgICBjb25zdCBoYW5kbGVDYW5hcnlSZXN1bHQgPSAoY2FuYXJ5LCBwYXlsb2FkLCBjdHgpID0+IHsKICAgICAgaWYgKGFib3J0ZWQoY2FuYXJ5KSkgewogICAgICAgIGNhbmFyeS5hYm9ydGVkID0gdHJ1ZTsKICAgICAgICByZXR1cm4gY2FuYXJ5OwogICAgICB9CiAgICAgIGNvbnN0IGNoZWNrUmVzdWx0ID0gcnVuQ2hlY2tzKHBheWxvYWQsIGNoZWNrcywgY3R4KTsKICAgICAgaWYgKGNoZWNrUmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgIGlmIChjdHguYXN5bmMgPT09IGZhbHNlKQogICAgICAgICAgdGhyb3cgbmV3ICRab2RBc3luY0Vycm9yKCk7CiAgICAgICAgcmV0dXJuIGNoZWNrUmVzdWx0LnRoZW4oKGNoZWNrUmVzdWx0MikgPT4gaW5zdC5fem9kLnBhcnNlKGNoZWNrUmVzdWx0MiwgY3R4KSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGluc3QuX3pvZC5wYXJzZShjaGVja1Jlc3VsdCwgY3R4KTsKICAgIH07CiAgICBpbnN0Ll96b2QucnVuID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgICBpZiAoY3R4LnNraXBDaGVja3MpIHsKICAgICAgICByZXR1cm4gaW5zdC5fem9kLnBhcnNlKHBheWxvYWQsIGN0eCk7CiAgICAgIH0KICAgICAgaWYgKGN0eC5kaXJlY3Rpb24gPT09ICJiYWNrd2FyZCIpIHsKICAgICAgICBjb25zdCBjYW5hcnkgPSBpbnN0Ll96b2QucGFyc2UoeyB2YWx1ZTogcGF5bG9hZC52YWx1ZSwgaXNzdWVzOiBbXSB9LCB7IC4uLmN0eCwgc2tpcENoZWNrczogdHJ1ZSB9KTsKICAgICAgICBpZiAoY2FuYXJ5IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgcmV0dXJuIGNhbmFyeS50aGVuKChjYW5hcnkyKSA9PiB7CiAgICAgICAgICAgIHJldHVybiBoYW5kbGVDYW5hcnlSZXN1bHQoY2FuYXJ5MiwgcGF5bG9hZCwgY3R4KTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gaGFuZGxlQ2FuYXJ5UmVzdWx0KGNhbmFyeSwgcGF5bG9hZCwgY3R4KTsKICAgICAgfQogICAgICBjb25zdCByZXN1bHQgPSBpbnN0Ll96b2QucGFyc2UocGF5bG9hZCwgY3R4KTsKICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICBpZiAoY3R4LmFzeW5jID09PSBmYWxzZSkKICAgICAgICAgIHRocm93IG5ldyAkWm9kQXN5bmNFcnJvcigpOwogICAgICAgIHJldHVybiByZXN1bHQudGhlbigocmVzdWx0MikgPT4gcnVuQ2hlY2tzKHJlc3VsdDIsIGNoZWNrcywgY3R4KSk7CiAgICAgIH0KICAgICAgcmV0dXJuIHJ1bkNoZWNrcyhyZXN1bHQsIGNoZWNrcywgY3R4KTsKICAgIH07CiAgfQogIGRlZmluZUxhenkoaW5zdCwgIn5zdGFuZGFyZCIsICgpID0+ICh7CiAgICB2YWxpZGF0ZTogKHZhbHVlKSA9PiB7CiAgICAgIHRyeSB7CiAgICAgICAgY29uc3QgciA9IHNhZmVQYXJzZShpbnN0LCB2YWx1ZSk7CiAgICAgICAgcmV0dXJuIHIuc3VjY2VzcyA/IHsgdmFsdWU6IHIuZGF0YSB9IDogeyBpc3N1ZXM6IHIuZXJyb3I/Lmlzc3VlcyB9OwogICAgICB9IGNhdGNoIChfKSB7CiAgICAgICAgcmV0dXJuIHNhZmVQYXJzZUFzeW5jKGluc3QsIHZhbHVlKS50aGVuKChyKSA9PiByLnN1Y2Nlc3MgPyB7IHZhbHVlOiByLmRhdGEgfSA6IHsgaXNzdWVzOiByLmVycm9yPy5pc3N1ZXMgfSk7CiAgICAgIH0KICAgIH0sCiAgICB2ZW5kb3I6ICJ6b2QiLAogICAgdmVyc2lvbjogMQogIH0pKTsKfSk7CnZhciAkWm9kU3RyaW5nID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFN0cmluZyIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnBhdHRlcm4gPSBbLi4uaW5zdD8uX3pvZC5iYWc/LnBhdHRlcm5zID8/IFtdXS5wb3AoKSA/PyBzdHJpbmcoaW5zdC5fem9kLmJhZyk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIF8pID0+IHsKICAgIGlmIChkZWYuY29lcmNlKQogICAgICB0cnkgewogICAgICAgIHBheWxvYWQudmFsdWUgPSBTdHJpbmcocGF5bG9hZC52YWx1ZSk7CiAgICAgIH0gY2F0Y2ggKF8yKSB7CiAgICAgIH0KICAgIGlmICh0eXBlb2YgcGF5bG9hZC52YWx1ZSA9PT0gInN0cmluZyIpCiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGV4cGVjdGVkOiAic3RyaW5nIiwKICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICBpbnN0CiAgICB9KTsKICAgIHJldHVybiBwYXlsb2FkOwogIH07Cn0pOwp2YXIgJFpvZFN0cmluZ0Zvcm1hdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RTdHJpbmdGb3JtYXQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICAkWm9kU3RyaW5nLmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kR1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RHVUlEIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGd1aWQpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RVVUlEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFVVSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgaWYgKGRlZi52ZXJzaW9uKSB7CiAgICBjb25zdCB2ZXJzaW9uTWFwID0gewogICAgICB2MTogMSwKICAgICAgdjI6IDIsCiAgICAgIHYzOiAzLAogICAgICB2NDogNCwKICAgICAgdjU6IDUsCiAgICAgIHY2OiA2LAogICAgICB2NzogNywKICAgICAgdjg6IDgKICAgIH07CiAgICBjb25zdCB2ID0gdmVyc2lvbk1hcFtkZWYudmVyc2lvbl07CiAgICBpZiAodiA9PT0gdm9pZCAwKQogICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgVVVJRCB2ZXJzaW9uOiAiJHtkZWYudmVyc2lvbn0iYCk7CiAgICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB1dWlkKHYpKTsKICB9IGVsc2UKICAgIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IHV1aWQoKSk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZEVtYWlsID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEVtYWlsIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGVtYWlsKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kVVJMID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFVSTCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgdHJ5IHsKICAgICAgY29uc3QgdHJpbW1lZCA9IHBheWxvYWQudmFsdWUudHJpbSgpOwogICAgICBpZiAoIWRlZi5ub3JtYWxpemUgJiYgZGVmLnByb3RvY29sPy5zb3VyY2UgPT09IGh0dHBQcm90b2NvbC5zb3VyY2UpIHsKICAgICAgICBpZiAoIS9eaHR0cHM/OlwvXC8vaS50ZXN0KHRyaW1tZWQpKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgICAgICAgZm9ybWF0OiAidXJsIiwKICAgICAgICAgICAgbm90ZTogIkludmFsaWQgVVJMIGZvcm1hdCIsCiAgICAgICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICAgICAgICBpbnN0LAogICAgICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICAgICAgfSk7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwodHJpbW1lZCk7CiAgICAgIGlmIChkZWYuaG9zdG5hbWUpIHsKICAgICAgICBkZWYuaG9zdG5hbWUubGFzdEluZGV4ID0gMDsKICAgICAgICBpZiAoIWRlZi5ob3N0bmFtZS50ZXN0KHVybC5ob3N0bmFtZSkpIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICAgICAgICBmb3JtYXQ6ICJ1cmwiLAogICAgICAgICAgICBub3RlOiAiSW52YWxpZCBob3N0bmFtZSIsCiAgICAgICAgICAgIHBhdHRlcm46IGRlZi5ob3N0bmFtZS5zb3VyY2UsCiAgICAgICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICAgICAgICBpbnN0LAogICAgICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmIChkZWYucHJvdG9jb2wpIHsKICAgICAgICBkZWYucHJvdG9jb2wubGFzdEluZGV4ID0gMDsKICAgICAgICBpZiAoIWRlZi5wcm90b2NvbC50ZXN0KHVybC5wcm90b2NvbC5lbmRzV2l0aCgiOiIpID8gdXJsLnByb3RvY29sLnNsaWNlKDAsIC0xKSA6IHVybC5wcm90b2NvbCkpIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICAgICAgICBmb3JtYXQ6ICJ1cmwiLAogICAgICAgICAgICBub3RlOiAiSW52YWxpZCBwcm90b2NvbCIsCiAgICAgICAgICAgIHBhdHRlcm46IGRlZi5wcm90b2NvbC5zb3VyY2UsCiAgICAgICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICAgICAgICBpbnN0LAogICAgICAgICAgICBjb250aW51ZTogIWRlZi5hYm9ydAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmIChkZWYubm9ybWFsaXplKSB7CiAgICAgICAgcGF5bG9hZC52YWx1ZSA9IHVybC5ocmVmOwogICAgICB9IGVsc2UgewogICAgICAgIHBheWxvYWQudmFsdWUgPSB0cmltbWVkOwogICAgICB9CiAgICAgIHJldHVybjsKICAgIH0gY2F0Y2ggKF8pIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgICBmb3JtYXQ6ICJ1cmwiLAogICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlLAogICAgICAgIGluc3QsCiAgICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgICAgfSk7CiAgICB9CiAgfTsKfSk7CnZhciAkWm9kRW1vamkgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kRW1vamkiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gZW1vamkoKSk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZE5hbm9JRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2ROYW5vSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gbmFub2lkKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kQ1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDVUlEIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGN1aWQpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RDVUlEMiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDVUlEMiIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBjdWlkMik7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZFVMSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVUxJRCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB1bGlkKTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kWElEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFhJRCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB4aWQpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RLU1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RLU1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBrc3VpZCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZElTT0RhdGVUaW1lID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZElTT0RhdGVUaW1lIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGRhdGV0aW1lKGRlZikpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RJU09EYXRlID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZElTT0RhdGUiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gZGF0ZSk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZElTT1RpbWUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kSVNPVGltZSIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSB0aW1lKGRlZikpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwp9KTsKdmFyICRab2RJU09EdXJhdGlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RJU09EdXJhdGlvbiIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBkdXJhdGlvbik7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgJFpvZElQdjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kSVB2NCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBpcHY0KTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QuYmFnLmZvcm1hdCA9IGBpcHY0YDsKfSk7CnZhciAkWm9kSVB2NiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RJUHY2IiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGlwdjYpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5iYWcuZm9ybWF0ID0gYGlwdjZgOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICB0cnkgewogICAgICBuZXcgVVJMKGBodHRwOi8vWyR7cGF5bG9hZC52YWx1ZX1dYCk7CiAgICB9IGNhdGNoIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgY29kZTogImludmFsaWRfZm9ybWF0IiwKICAgICAgICBmb3JtYXQ6ICJpcHY2IiwKICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfQogIH07Cn0pOwp2YXIgJFpvZENJRFJ2NCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RDSURSdjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgZGVmLnBhdHRlcm4gPz8gKGRlZi5wYXR0ZXJuID0gY2lkcnY0KTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kQ0lEUnY2ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENJRFJ2NiIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBjaWRydjYpOwogICRab2RTdHJpbmdGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCBwYXJ0cyA9IHBheWxvYWQudmFsdWUuc3BsaXQoIi8iKTsKICAgIHRyeSB7CiAgICAgIGlmIChwYXJ0cy5sZW5ndGggIT09IDIpCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7CiAgICAgIGNvbnN0IFthZGRyZXNzLCBwcmVmaXhdID0gcGFydHM7CiAgICAgIGlmICghcHJlZml4KQogICAgICAgIHRocm93IG5ldyBFcnJvcigpOwogICAgICBjb25zdCBwcmVmaXhOdW0gPSBOdW1iZXIocHJlZml4KTsKICAgICAgaWYgKGAke3ByZWZpeE51bX1gICE9PSBwcmVmaXgpCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7CiAgICAgIGlmIChwcmVmaXhOdW0gPCAwIHx8IHByZWZpeE51bSA+IDEyOCkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTsKICAgICAgbmV3IFVSTChgaHR0cDovL1ske2FkZHJlc3N9XWApOwogICAgfSBjYXRjaCB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIGNvZGU6ICJpbnZhbGlkX2Zvcm1hdCIsCiAgICAgICAgZm9ybWF0OiAiY2lkcnY2IiwKICAgICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgICBpbnN0LAogICAgICAgIGNvbnRpbnVlOiAhZGVmLmFib3J0CiAgICAgIH0pOwogICAgfQogIH07Cn0pOwpmdW5jdGlvbiBpc1ZhbGlkQmFzZTY0KGRhdGEpIHsKICBpZiAoZGF0YSA9PT0gIiIpCiAgICByZXR1cm4gdHJ1ZTsKICBpZiAoL1xzLy50ZXN0KGRhdGEpKQogICAgcmV0dXJuIGZhbHNlOwogIGlmIChkYXRhLmxlbmd0aCAlIDQgIT09IDApCiAgICByZXR1cm4gZmFsc2U7CiAgdHJ5IHsKICAgIGF0b2IoZGF0YSk7CiAgICByZXR1cm4gdHJ1ZTsKICB9IGNhdGNoIHsKICAgIHJldHVybiBmYWxzZTsKICB9Cn0KdmFyICRab2RCYXNlNjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQmFzZTY0IiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGJhc2U2NCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmJhZy5jb250ZW50RW5jb2RpbmcgPSAiYmFzZTY0IjsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgaWYgKGlzVmFsaWRCYXNlNjQocGF5bG9hZC52YWx1ZSkpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICBmb3JtYXQ6ICJiYXNlNjQiLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwpmdW5jdGlvbiBpc1ZhbGlkQmFzZTY0VVJMKGRhdGEpIHsKICBpZiAoIWJhc2U2NHVybC50ZXN0KGRhdGEpKQogICAgcmV0dXJuIGZhbHNlOwogIGNvbnN0IGJhc2U2NDIgPSBkYXRhLnJlcGxhY2UoL1stX10vZywgKGMpID0+IGMgPT09ICItIiA/ICIrIiA6ICIvIik7CiAgY29uc3QgcGFkZGVkID0gYmFzZTY0Mi5wYWRFbmQoTWF0aC5jZWlsKGJhc2U2NDIubGVuZ3RoIC8gNCkgKiA0LCAiPSIpOwogIHJldHVybiBpc1ZhbGlkQmFzZTY0KHBhZGRlZCk7Cn0KdmFyICRab2RCYXNlNjRVUkwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQmFzZTY0VVJMIiwgKGluc3QsIGRlZikgPT4gewogIGRlZi5wYXR0ZXJuID8/IChkZWYucGF0dGVybiA9IGJhc2U2NHVybCk7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLmJhZy5jb250ZW50RW5jb2RpbmcgPSAiYmFzZTY0dXJsIjsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgaWYgKGlzVmFsaWRCYXNlNjRVUkwocGF5bG9hZC52YWx1ZSkpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICBmb3JtYXQ6ICJiYXNlNjR1cmwiLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZEUxNjQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kRTE2NCIsIChpbnN0LCBkZWYpID0+IHsKICBkZWYucGF0dGVybiA/PyAoZGVmLnBhdHRlcm4gPSBlMTY0KTsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIGlzVmFsaWRKV1QodG9rZW4sIGFsZ29yaXRobSA9IG51bGwpIHsKICB0cnkgewogICAgY29uc3QgdG9rZW5zUGFydHMgPSB0b2tlbi5zcGxpdCgiLiIpOwogICAgaWYgKHRva2Vuc1BhcnRzLmxlbmd0aCAhPT0gMykKICAgICAgcmV0dXJuIGZhbHNlOwogICAgY29uc3QgW2hlYWRlcl0gPSB0b2tlbnNQYXJ0czsKICAgIGlmICghaGVhZGVyKQogICAgICByZXR1cm4gZmFsc2U7CiAgICBjb25zdCBwYXJzZWRIZWFkZXIgPSBKU09OLnBhcnNlKGF0b2IoaGVhZGVyKSk7CiAgICBpZiAoInR5cCIgaW4gcGFyc2VkSGVhZGVyICYmIHBhcnNlZEhlYWRlcj8udHlwICE9PSAiSldUIikKICAgICAgcmV0dXJuIGZhbHNlOwogICAgaWYgKCFwYXJzZWRIZWFkZXIuYWxnKQogICAgICByZXR1cm4gZmFsc2U7CiAgICBpZiAoYWxnb3JpdGhtICYmICghKCJhbGciIGluIHBhcnNlZEhlYWRlcikgfHwgcGFyc2VkSGVhZGVyLmFsZyAhPT0gYWxnb3JpdGhtKSkKICAgICAgcmV0dXJuIGZhbHNlOwogICAgcmV0dXJuIHRydWU7CiAgfSBjYXRjaCB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQp9CnZhciAkWm9kSldUID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEpXVCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QuY2hlY2sgPSAocGF5bG9hZCkgPT4gewogICAgaWYgKGlzVmFsaWRKV1QocGF5bG9hZC52YWx1ZSwgZGVmLmFsZykpCiAgICAgIHJldHVybjsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICBjb2RlOiAiaW52YWxpZF9mb3JtYXQiLAogICAgICBmb3JtYXQ6ICJqd3QiLAogICAgICBpbnB1dDogcGF5bG9hZC52YWx1ZSwKICAgICAgaW5zdCwKICAgICAgY29udGludWU6ICFkZWYuYWJvcnQKICAgIH0pOwogIH07Cn0pOwp2YXIgJFpvZE51bWJlciA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2ROdW1iZXIiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXR0ZXJuID0gaW5zdC5fem9kLmJhZy5wYXR0ZXJuID8/IG51bWJlcjsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgaWYgKGRlZi5jb2VyY2UpCiAgICAgIHRyeSB7CiAgICAgICAgcGF5bG9hZC52YWx1ZSA9IE51bWJlcihwYXlsb2FkLnZhbHVlKTsKICAgICAgfSBjYXRjaCAoXykgewogICAgICB9CiAgICBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7CiAgICBpZiAodHlwZW9mIGlucHV0ID09PSAibnVtYmVyIiAmJiAhTnVtYmVyLmlzTmFOKGlucHV0KSAmJiBOdW1iZXIuaXNGaW5pdGUoaW5wdXQpKSB7CiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgfQogICAgY29uc3QgcmVjZWl2ZWQgPSB0eXBlb2YgaW5wdXQgPT09ICJudW1iZXIiID8gTnVtYmVyLmlzTmFOKGlucHV0KSA/ICJOYU4iIDogIU51bWJlci5pc0Zpbml0ZShpbnB1dCkgPyAiSW5maW5pdHkiIDogdm9pZCAwIDogdm9pZCAwOwogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGV4cGVjdGVkOiAibnVtYmVyIiwKICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgIGlucHV0LAogICAgICBpbnN0LAogICAgICAuLi5yZWNlaXZlZCA/IHsgcmVjZWl2ZWQgfSA6IHt9CiAgICB9KTsKICAgIHJldHVybiBwYXlsb2FkOwogIH07Cn0pOwp2YXIgJFpvZE51bWJlckZvcm1hdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2ROdW1iZXJGb3JtYXQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENoZWNrTnVtYmVyRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKICAkWm9kTnVtYmVyLmluaXQoaW5zdCwgZGVmKTsKfSk7CnZhciAkWm9kQm9vbGVhbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RCb29sZWFuIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucGF0dGVybiA9IGJvb2xlYW47CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIF9jdHgpID0+IHsKICAgIGlmIChkZWYuY29lcmNlKQogICAgICB0cnkgewogICAgICAgIHBheWxvYWQudmFsdWUgPSBCb29sZWFuKHBheWxvYWQudmFsdWUpOwogICAgICB9IGNhdGNoIChfKSB7CiAgICAgIH0KICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICJib29sZWFuIikKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgZXhwZWN0ZWQ6ICJib29sZWFuIiwKICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgIGlucHV0LAogICAgICBpbnN0CiAgICB9KTsKICAgIHJldHVybiBwYXlsb2FkOwogIH07Cn0pOwp2YXIgJFpvZFVua25vd24gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVW5rbm93biIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQpID0+IHBheWxvYWQ7Cn0pOwp2YXIgJFpvZE5ldmVyID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZE5ldmVyIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGV4cGVjdGVkOiAibmV2ZXIiLAogICAgICBjb2RlOiAiaW52YWxpZF90eXBlIiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QKICAgIH0pOwogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZUFycmF5UmVzdWx0KHJlc3VsdCwgZmluYWwsIGluZGV4KSB7CiAgaWYgKHJlc3VsdC5pc3N1ZXMubGVuZ3RoKSB7CiAgICBmaW5hbC5pc3N1ZXMucHVzaCguLi5wcmVmaXhJc3N1ZXMoaW5kZXgsIHJlc3VsdC5pc3N1ZXMpKTsKICB9CiAgZmluYWwudmFsdWVbaW5kZXhdID0gcmVzdWx0LnZhbHVlOwp9CnZhciAkWm9kQXJyYXkgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQXJyYXkiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghQXJyYXkuaXNBcnJheShpbnB1dCkpIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgZXhwZWN0ZWQ6ICJhcnJheSIsCiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgaW5wdXQsCiAgICAgICAgaW5zdAogICAgICB9KTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBwYXlsb2FkLnZhbHVlID0gQXJyYXkoaW5wdXQubGVuZ3RoKTsKICAgIGNvbnN0IHByb21zID0gW107CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7CiAgICAgIGNvbnN0IGl0ZW0gPSBpbnB1dFtpXTsKICAgICAgY29uc3QgcmVzdWx0ID0gZGVmLmVsZW1lbnQuX3pvZC5ydW4oewogICAgICAgIHZhbHVlOiBpdGVtLAogICAgICAgIGlzc3VlczogW10KICAgICAgfSwgY3R4KTsKICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICBwcm9tcy5wdXNoKHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiBoYW5kbGVBcnJheVJlc3VsdChyZXN1bHQyLCBwYXlsb2FkLCBpKSkpOwogICAgICB9IGVsc2UgewogICAgICAgIGhhbmRsZUFycmF5UmVzdWx0KHJlc3VsdCwgcGF5bG9hZCwgaSk7CiAgICAgIH0KICAgIH0KICAgIGlmIChwcm9tcy5sZW5ndGgpIHsKICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHByb21zKS50aGVuKCgpID0+IHBheWxvYWQpOwogICAgfQogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZVByb3BlcnR5UmVzdWx0KHJlc3VsdCwgZmluYWwsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkgewogIGNvbnN0IGlzUHJlc2VudCA9IGtleSBpbiBpbnB1dDsKICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgIGlmIChpc09wdGlvbmFsSW4gJiYgaXNPcHRpb25hbE91dCAmJiAhaXNQcmVzZW50KSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGZpbmFsLmlzc3Vlcy5wdXNoKC4uLnByZWZpeElzc3VlcyhrZXksIHJlc3VsdC5pc3N1ZXMpKTsKICB9CiAgaWYgKCFpc1ByZXNlbnQgJiYgIWlzT3B0aW9uYWxJbikgewogICAgaWYgKCFyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICBmaW5hbC5pc3N1ZXMucHVzaCh7CiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgZXhwZWN0ZWQ6ICJub25vcHRpb25hbCIsCiAgICAgICAgaW5wdXQ6IHZvaWQgMCwKICAgICAgICBwYXRoOiBba2V5XQogICAgICB9KTsKICAgIH0KICAgIHJldHVybjsKICB9CiAgaWYgKHJlc3VsdC52YWx1ZSA9PT0gdm9pZCAwKSB7CiAgICBpZiAoaXNQcmVzZW50KSB7CiAgICAgIGZpbmFsLnZhbHVlW2tleV0gPSB2b2lkIDA7CiAgICB9CiAgfSBlbHNlIHsKICAgIGZpbmFsLnZhbHVlW2tleV0gPSByZXN1bHQudmFsdWU7CiAgfQp9CmZ1bmN0aW9uIG5vcm1hbGl6ZURlZihkZWYpIHsKICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoZGVmLnNoYXBlKTsKICBmb3IgKGNvbnN0IGsgb2Yga2V5cykgewogICAgaWYgKCFkZWYuc2hhcGU/LltrXT8uX3pvZD8udHJhaXRzPy5oYXMoIiRab2RUeXBlIikpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGVsZW1lbnQgYXQga2V5ICIke2t9IjogZXhwZWN0ZWQgYSBab2Qgc2NoZW1hYCk7CiAgICB9CiAgfQogIGNvbnN0IG9rZXlzID0gb3B0aW9uYWxLZXlzKGRlZi5zaGFwZSk7CiAgcmV0dXJuIHsKICAgIC4uLmRlZiwKICAgIGtleXMsCiAgICBrZXlTZXQ6IG5ldyBTZXQoa2V5cyksCiAgICBudW1LZXlzOiBrZXlzLmxlbmd0aCwKICAgIG9wdGlvbmFsS2V5czogbmV3IFNldChva2V5cykKICB9Owp9CmZ1bmN0aW9uIGhhbmRsZUNhdGNoYWxsKHByb21zLCBpbnB1dCwgcGF5bG9hZCwgY3R4LCBkZWYsIGluc3QpIHsKICBjb25zdCB1bnJlY29nbml6ZWQgPSBbXTsKICBjb25zdCBrZXlTZXQgPSBkZWYua2V5U2V0OwogIGNvbnN0IF9jYXRjaGFsbCA9IGRlZi5jYXRjaGFsbC5fem9kOwogIGNvbnN0IHQgPSBfY2F0Y2hhbGwuZGVmLnR5cGU7CiAgY29uc3QgaXNPcHRpb25hbEluID0gX2NhdGNoYWxsLm9wdGluID09PSAib3B0aW9uYWwiOwogIGNvbnN0IGlzT3B0aW9uYWxPdXQgPSBfY2F0Y2hhbGwub3B0b3V0ID09PSAib3B0aW9uYWwiOwogIGZvciAoY29uc3Qga2V5IGluIGlucHV0KSB7CiAgICBpZiAoa2V5ID09PSAiX19wcm90b19fIikKICAgICAgY29udGludWU7CiAgICBpZiAoa2V5U2V0LmhhcyhrZXkpKQogICAgICBjb250aW51ZTsKICAgIGlmICh0ID09PSAibmV2ZXIiKSB7CiAgICAgIHVucmVjb2duaXplZC5wdXNoKGtleSk7CiAgICAgIGNvbnRpbnVlOwogICAgfQogICAgY29uc3QgciA9IF9jYXRjaGFsbC5ydW4oeyB2YWx1ZTogaW5wdXRba2V5XSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgaWYgKHIgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgIHByb21zLnB1c2goci50aGVuKChyMikgPT4gaGFuZGxlUHJvcGVydHlSZXN1bHQocjIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkpKTsKICAgIH0gZWxzZSB7CiAgICAgIGhhbmRsZVByb3BlcnR5UmVzdWx0KHIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCk7CiAgICB9CiAgfQogIGlmICh1bnJlY29nbml6ZWQubGVuZ3RoKSB7CiAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgY29kZTogInVucmVjb2duaXplZF9rZXlzIiwKICAgICAga2V5czogdW5yZWNvZ25pemVkLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfSk7CiAgfQogIGlmICghcHJvbXMubGVuZ3RoKQogICAgcmV0dXJuIHBheWxvYWQ7CiAgcmV0dXJuIFByb21pc2UuYWxsKHByb21zKS50aGVuKCgpID0+IHsKICAgIHJldHVybiBwYXlsb2FkOwogIH0pOwp9CnZhciAkWm9kT2JqZWN0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZE9iamVjdCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZGVmLCAic2hhcGUiKTsKICBpZiAoIWRlc2M/LmdldCkgewogICAgY29uc3Qgc2ggPSBkZWYuc2hhcGU7CiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZGVmLCAic2hhcGUiLCB7CiAgICAgIGdldDogKCkgPT4gewogICAgICAgIGNvbnN0IG5ld1NoID0geyAuLi5zaCB9OwogICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShkZWYsICJzaGFwZSIsIHsKICAgICAgICAgIHZhbHVlOiBuZXdTaAogICAgICAgIH0pOwogICAgICAgIHJldHVybiBuZXdTaDsKICAgICAgfQogICAgfSk7CiAgfQogIGNvbnN0IF9ub3JtYWxpemVkID0gY2FjaGVkKCgpID0+IG5vcm1hbGl6ZURlZihkZWYpKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInByb3BWYWx1ZXMiLCAoKSA9PiB7CiAgICBjb25zdCBzaGFwZSA9IGRlZi5zaGFwZTsKICAgIGNvbnN0IHByb3BWYWx1ZXMgPSB7fTsKICAgIGZvciAoY29uc3Qga2V5IGluIHNoYXBlKSB7CiAgICAgIGNvbnN0IGZpZWxkID0gc2hhcGVba2V5XS5fem9kOwogICAgICBpZiAoZmllbGQudmFsdWVzKSB7CiAgICAgICAgcHJvcFZhbHVlc1trZXldID8/IChwcm9wVmFsdWVzW2tleV0gPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgICAgICBmb3IgKGNvbnN0IHYgb2YgZmllbGQudmFsdWVzKQogICAgICAgICAgcHJvcFZhbHVlc1trZXldLmFkZCh2KTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHByb3BWYWx1ZXM7CiAgfSk7CiAgY29uc3QgaXNPYmplY3QyID0gaXNPYmplY3Q7CiAgY29uc3QgY2F0Y2hhbGwgPSBkZWYuY2F0Y2hhbGw7CiAgbGV0IHZhbHVlOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIHZhbHVlID8/ICh2YWx1ZSA9IF9ub3JtYWxpemVkLnZhbHVlKTsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghaXNPYmplY3QyKGlucHV0KSkgewogICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICBleHBlY3RlZDogIm9iamVjdCIsCiAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgaW5wdXQsCiAgICAgICAgaW5zdAogICAgICB9KTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBwYXlsb2FkLnZhbHVlID0ge307CiAgICBjb25zdCBwcm9tcyA9IFtdOwogICAgY29uc3Qgc2hhcGUgPSB2YWx1ZS5zaGFwZTsKICAgIGZvciAoY29uc3Qga2V5IG9mIHZhbHVlLmtleXMpIHsKICAgICAgY29uc3QgZWwgPSBzaGFwZVtrZXldOwogICAgICBjb25zdCBpc09wdGlvbmFsSW4gPSBlbC5fem9kLm9wdGluID09PSAib3B0aW9uYWwiOwogICAgICBjb25zdCBpc09wdGlvbmFsT3V0ID0gZWwuX3pvZC5vcHRvdXQgPT09ICJvcHRpb25hbCI7CiAgICAgIGNvbnN0IHIgPSBlbC5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dFtrZXldLCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgIGlmIChyIGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgIHByb21zLnB1c2goci50aGVuKChyMikgPT4gaGFuZGxlUHJvcGVydHlSZXN1bHQocjIsIHBheWxvYWQsIGtleSwgaW5wdXQsIGlzT3B0aW9uYWxJbiwgaXNPcHRpb25hbE91dCkpKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBoYW5kbGVQcm9wZXJ0eVJlc3VsdChyLCBwYXlsb2FkLCBrZXksIGlucHV0LCBpc09wdGlvbmFsSW4sIGlzT3B0aW9uYWxPdXQpOwogICAgICB9CiAgICB9CiAgICBpZiAoIWNhdGNoYWxsKSB7CiAgICAgIHJldHVybiBwcm9tcy5sZW5ndGggPyBQcm9taXNlLmFsbChwcm9tcykudGhlbigoKSA9PiBwYXlsb2FkKSA6IHBheWxvYWQ7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlQ2F0Y2hhbGwocHJvbXMsIGlucHV0LCBwYXlsb2FkLCBjdHgsIF9ub3JtYWxpemVkLnZhbHVlLCBpbnN0KTsKICB9Owp9KTsKdmFyICRab2RPYmplY3RKSVQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kT2JqZWN0SklUIiwgKGluc3QsIGRlZikgPT4gewogICRab2RPYmplY3QuaW5pdChpbnN0LCBkZWYpOwogIGNvbnN0IHN1cGVyUGFyc2UgPSBpbnN0Ll96b2QucGFyc2U7CiAgY29uc3QgX25vcm1hbGl6ZWQgPSBjYWNoZWQoKCkgPT4gbm9ybWFsaXplRGVmKGRlZikpOwogIGNvbnN0IGdlbmVyYXRlRmFzdHBhc3MgPSAoc2hhcGUpID0+IHsKICAgIGNvbnN0IGRvYyA9IG5ldyBEb2MoWyJzaGFwZSIsICJwYXlsb2FkIiwgImN0eCJdKTsKICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBfbm9ybWFsaXplZC52YWx1ZTsKICAgIGNvbnN0IHBhcnNlU3RyID0gKGtleSkgPT4gewogICAgICBjb25zdCBrID0gZXNjKGtleSk7CiAgICAgIHJldHVybiBgc2hhcGVbJHtrfV0uX3pvZC5ydW4oeyB2YWx1ZTogaW5wdXRbJHtrfV0sIGlzc3VlczogW10gfSwgY3R4KWA7CiAgICB9OwogICAgZG9jLndyaXRlKGBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7YCk7CiAgICBjb25zdCBpZHMgPSAvKiBAX19QVVJFX18gKi8gT2JqZWN0LmNyZWF0ZShudWxsKTsKICAgIGxldCBjb3VudGVyID0gMDsKICAgIGZvciAoY29uc3Qga2V5IG9mIG5vcm1hbGl6ZWQua2V5cykgewogICAgICBpZHNba2V5XSA9IGBrZXlfJHtjb3VudGVyKyt9YDsKICAgIH0KICAgIGRvYy53cml0ZShgY29uc3QgbmV3UmVzdWx0ID0ge307YCk7CiAgICBmb3IgKGNvbnN0IGtleSBvZiBub3JtYWxpemVkLmtleXMpIHsKICAgICAgY29uc3QgaWQgPSBpZHNba2V5XTsKICAgICAgY29uc3QgayA9IGVzYyhrZXkpOwogICAgICBjb25zdCBzY2hlbWEgPSBzaGFwZVtrZXldOwogICAgICBjb25zdCBpc09wdGlvbmFsSW4gPSBzY2hlbWE/Ll96b2Q/Lm9wdGluID09PSAib3B0aW9uYWwiOwogICAgICBjb25zdCBpc09wdGlvbmFsT3V0ID0gc2NoZW1hPy5fem9kPy5vcHRvdXQgPT09ICJvcHRpb25hbCI7CiAgICAgIGRvYy53cml0ZShgY29uc3QgJHtpZH0gPSAke3BhcnNlU3RyKGtleSl9O2ApOwogICAgICBpZiAoaXNPcHRpb25hbEluICYmIGlzT3B0aW9uYWxPdXQpIHsKICAgICAgICBkb2Mud3JpdGUoYAogICAgICAgIGlmICgke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBpZiAoJHtrfSBpbiBpbnB1dCkgewogICAgICAgICAgICBwYXlsb2FkLmlzc3VlcyA9IHBheWxvYWQuaXNzdWVzLmNvbmNhdCgke2lkfS5pc3N1ZXMubWFwKGlzcyA9PiAoewogICAgICAgICAgICAgIC4uLmlzcywKICAgICAgICAgICAgICBwYXRoOiBpc3MucGF0aCA/IFske2t9LCAuLi5pc3MucGF0aF0gOiBbJHtrfV0KICAgICAgICAgICAgfSkpKTsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmICgke2lkfS52YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICBpZiAoJHtrfSBpbiBpbnB1dCkgewogICAgICAgICAgICBuZXdSZXN1bHRbJHtrfV0gPSB1bmRlZmluZWQ7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9ICR7aWR9LnZhbHVlOwogICAgICAgIH0KCiAgICAgIGApOwogICAgICB9IGVsc2UgaWYgKCFpc09wdGlvbmFsSW4pIHsKICAgICAgICBkb2Mud3JpdGUoYAogICAgICAgIGNvbnN0ICR7aWR9X3ByZXNlbnQgPSAke2t9IGluIGlucHV0OwogICAgICAgIGlmICgke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3VlcyA9IHBheWxvYWQuaXNzdWVzLmNvbmNhdCgke2lkfS5pc3N1ZXMubWFwKGlzcyA9PiAoewogICAgICAgICAgICAuLi5pc3MsCiAgICAgICAgICAgIHBhdGg6IGlzcy5wYXRoID8gWyR7a30sIC4uLmlzcy5wYXRoXSA6IFske2t9XQogICAgICAgICAgfSkpKTsKICAgICAgICB9CiAgICAgICAgaWYgKCEke2lkfV9wcmVzZW50ICYmICEke2lkfS5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgY29kZTogImludmFsaWRfdHlwZSIsCiAgICAgICAgICAgIGV4cGVjdGVkOiAibm9ub3B0aW9uYWwiLAogICAgICAgICAgICBpbnB1dDogdW5kZWZpbmVkLAogICAgICAgICAgICBwYXRoOiBbJHtrfV0KICAgICAgICAgIH0pOwogICAgICAgIH0KCiAgICAgICAgaWYgKCR7aWR9X3ByZXNlbnQpIHsKICAgICAgICAgIGlmICgke2lkfS52YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9IHVuZGVmaW5lZDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9ICR7aWR9LnZhbHVlOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgIGApOwogICAgICB9IGVsc2UgewogICAgICAgIGRvYy53cml0ZShgCiAgICAgICAgaWYgKCR7aWR9Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzID0gcGF5bG9hZC5pc3N1ZXMuY29uY2F0KCR7aWR9Lmlzc3Vlcy5tYXAoaXNzID0+ICh7CiAgICAgICAgICAgIC4uLmlzcywKICAgICAgICAgICAgcGF0aDogaXNzLnBhdGggPyBbJHtrfSwgLi4uaXNzLnBhdGhdIDogWyR7a31dCiAgICAgICAgICB9KSkpOwogICAgICAgIH0KCiAgICAgICAgaWYgKCR7aWR9LnZhbHVlID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgIGlmICgke2t9IGluIGlucHV0KSB7CiAgICAgICAgICAgIG5ld1Jlc3VsdFske2t9XSA9IHVuZGVmaW5lZDsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgbmV3UmVzdWx0WyR7a31dID0gJHtpZH0udmFsdWU7CiAgICAgICAgfQoKICAgICAgYCk7CiAgICAgIH0KICAgIH0KICAgIGRvYy53cml0ZShgcGF5bG9hZC52YWx1ZSA9IG5ld1Jlc3VsdDtgKTsKICAgIGRvYy53cml0ZShgcmV0dXJuIHBheWxvYWQ7YCk7CiAgICBjb25zdCBmbiA9IGRvYy5jb21waWxlKCk7CiAgICByZXR1cm4gKHBheWxvYWQsIGN0eCkgPT4gZm4oc2hhcGUsIHBheWxvYWQsIGN0eCk7CiAgfTsKICBsZXQgZmFzdHBhc3M7CiAgY29uc3QgaXNPYmplY3QyID0gaXNPYmplY3Q7CiAgY29uc3Qgaml0ID0gIWdsb2JhbENvbmZpZy5qaXRsZXNzOwogIGNvbnN0IGFsbG93c0V2YWwyID0gYWxsb3dzRXZhbDsKICBjb25zdCBmYXN0RW5hYmxlZCA9IGppdCAmJiBhbGxvd3NFdmFsMi52YWx1ZTsKICBjb25zdCBjYXRjaGFsbCA9IGRlZi5jYXRjaGFsbDsKICBsZXQgdmFsdWU7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgdmFsdWUgPz8gKHZhbHVlID0gX25vcm1hbGl6ZWQudmFsdWUpOwogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKCFpc09iamVjdDIoaW5wdXQpKSB7CiAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goewogICAgICAgIGV4cGVjdGVkOiAib2JqZWN0IiwKICAgICAgICBjb2RlOiAiaW52YWxpZF90eXBlIiwKICAgICAgICBpbnB1dCwKICAgICAgICBpbnN0CiAgICAgIH0pOwogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH0KICAgIGlmIChqaXQgJiYgZmFzdEVuYWJsZWQgJiYgY3R4Py5hc3luYyA9PT0gZmFsc2UgJiYgY3R4LmppdGxlc3MgIT09IHRydWUpIHsKICAgICAgaWYgKCFmYXN0cGFzcykKICAgICAgICBmYXN0cGFzcyA9IGdlbmVyYXRlRmFzdHBhc3MoZGVmLnNoYXBlKTsKICAgICAgcGF5bG9hZCA9IGZhc3RwYXNzKHBheWxvYWQsIGN0eCk7CiAgICAgIGlmICghY2F0Y2hhbGwpCiAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgIHJldHVybiBoYW5kbGVDYXRjaGFsbChbXSwgaW5wdXQsIHBheWxvYWQsIGN0eCwgdmFsdWUsIGluc3QpOwogICAgfQogICAgcmV0dXJuIHN1cGVyUGFyc2UocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlVW5pb25SZXN1bHRzKHJlc3VsdHMsIGZpbmFsLCBpbnN0LCBjdHgpIHsKICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7CiAgICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGggPT09IDApIHsKICAgICAgZmluYWwudmFsdWUgPSByZXN1bHQudmFsdWU7CiAgICAgIHJldHVybiBmaW5hbDsKICAgIH0KICB9CiAgY29uc3Qgbm9uYWJvcnRlZCA9IHJlc3VsdHMuZmlsdGVyKChyKSA9PiAhYWJvcnRlZChyKSk7CiAgaWYgKG5vbmFib3J0ZWQubGVuZ3RoID09PSAxKSB7CiAgICBmaW5hbC52YWx1ZSA9IG5vbmFib3J0ZWRbMF0udmFsdWU7CiAgICByZXR1cm4gbm9uYWJvcnRlZFswXTsKICB9CiAgZmluYWwuaXNzdWVzLnB1c2goewogICAgY29kZTogImludmFsaWRfdW5pb24iLAogICAgaW5wdXQ6IGZpbmFsLnZhbHVlLAogICAgaW5zdCwKICAgIGVycm9yczogcmVzdWx0cy5tYXAoKHJlc3VsdCkgPT4gcmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSkKICB9KTsKICByZXR1cm4gZmluYWw7Cn0KdmFyICRab2RVbmlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RVbmlvbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5vcHRpb25zLnNvbWUoKG8pID0+IG8uX3pvZC5vcHRpbiA9PT0gIm9wdGlvbmFsIikgPyAib3B0aW9uYWwiIDogdm9pZCAwKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdG91dCIsICgpID0+IGRlZi5vcHRpb25zLnNvbWUoKG8pID0+IG8uX3pvZC5vcHRvdXQgPT09ICJvcHRpb25hbCIpID8gIm9wdGlvbmFsIiA6IHZvaWQgMCk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiB7CiAgICBpZiAoZGVmLm9wdGlvbnMuZXZlcnkoKG8pID0+IG8uX3pvZC52YWx1ZXMpKSB7CiAgICAgIHJldHVybiBuZXcgU2V0KGRlZi5vcHRpb25zLmZsYXRNYXAoKG9wdGlvbikgPT4gQXJyYXkuZnJvbShvcHRpb24uX3pvZC52YWx1ZXMpKSk7CiAgICB9CiAgICByZXR1cm4gdm9pZCAwOwogIH0pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicGF0dGVybiIsICgpID0+IHsKICAgIGlmIChkZWYub3B0aW9ucy5ldmVyeSgobykgPT4gby5fem9kLnBhdHRlcm4pKSB7CiAgICAgIGNvbnN0IHBhdHRlcm5zID0gZGVmLm9wdGlvbnMubWFwKChvKSA9PiBvLl96b2QucGF0dGVybik7CiAgICAgIHJldHVybiBuZXcgUmVnRXhwKGBeKCR7cGF0dGVybnMubWFwKChwKSA9PiBjbGVhblJlZ2V4KHAuc291cmNlKSkuam9pbigifCIpfSkkYCk7CiAgICB9CiAgICByZXR1cm4gdm9pZCAwOwogIH0pOwogIGNvbnN0IGZpcnN0ID0gZGVmLm9wdGlvbnMubGVuZ3RoID09PSAxID8gZGVmLm9wdGlvbnNbMF0uX3pvZC5ydW4gOiBudWxsOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChmaXJzdCkgewogICAgICByZXR1cm4gZmlyc3QocGF5bG9hZCwgY3R4KTsKICAgIH0KICAgIGxldCBhc3luYyA9IGZhbHNlOwogICAgY29uc3QgcmVzdWx0cyA9IFtdOwogICAgZm9yIChjb25zdCBvcHRpb24gb2YgZGVmLm9wdGlvbnMpIHsKICAgICAgY29uc3QgcmVzdWx0ID0gb3B0aW9uLl96b2QucnVuKHsKICAgICAgICB2YWx1ZTogcGF5bG9hZC52YWx1ZSwKICAgICAgICBpc3N1ZXM6IFtdCiAgICAgIH0sIGN0eCk7CiAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7CiAgICAgICAgYXN5bmMgPSB0cnVlOwogICAgICB9IGVsc2UgewogICAgICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCA9PT0gMCkKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7CiAgICAgIH0KICAgIH0KICAgIGlmICghYXN5bmMpCiAgICAgIHJldHVybiBoYW5kbGVVbmlvblJlc3VsdHMocmVzdWx0cywgcGF5bG9hZCwgaW5zdCwgY3R4KTsKICAgIHJldHVybiBQcm9taXNlLmFsbChyZXN1bHRzKS50aGVuKChyZXN1bHRzMikgPT4gewogICAgICByZXR1cm4gaGFuZGxlVW5pb25SZXN1bHRzKHJlc3VsdHMyLCBwYXlsb2FkLCBpbnN0LCBjdHgpOwogICAgfSk7CiAgfTsKfSk7CnZhciAkWm9kSW50ZXJzZWN0aW9uID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZEludGVyc2VjdGlvbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgY29uc3QgbGVmdCA9IGRlZi5sZWZ0Ll96b2QucnVuKHsgdmFsdWU6IGlucHV0LCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICBjb25zdCByaWdodCA9IGRlZi5yaWdodC5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dCwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgY29uc3QgYXN5bmMgPSBsZWZ0IGluc3RhbmNlb2YgUHJvbWlzZSB8fCByaWdodCBpbnN0YW5jZW9mIFByb21pc2U7CiAgICBpZiAoYXN5bmMpIHsKICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsZWZ0LCByaWdodF0pLnRoZW4oKFtsZWZ0MiwgcmlnaHQyXSkgPT4gewogICAgICAgIHJldHVybiBoYW5kbGVJbnRlcnNlY3Rpb25SZXN1bHRzKHBheWxvYWQsIGxlZnQyLCByaWdodDIpOwogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBoYW5kbGVJbnRlcnNlY3Rpb25SZXN1bHRzKHBheWxvYWQsIGxlZnQsIHJpZ2h0KTsKICB9Owp9KTsKZnVuY3Rpb24gbWVyZ2VWYWx1ZXMoYSwgYikgewogIGlmIChhID09PSBiKSB7CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogYSB9OwogIH0KICBpZiAoYSBpbnN0YW5jZW9mIERhdGUgJiYgYiBpbnN0YW5jZW9mIERhdGUgJiYgK2EgPT09ICtiKSB7CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogYSB9OwogIH0KICBpZiAoaXNQbGFpbk9iamVjdChhKSAmJiBpc1BsYWluT2JqZWN0KGIpKSB7CiAgICBjb25zdCBiS2V5cyA9IE9iamVjdC5rZXlzKGIpOwogICAgY29uc3Qgc2hhcmVkS2V5cyA9IE9iamVjdC5rZXlzKGEpLmZpbHRlcigoa2V5KSA9PiBiS2V5cy5pbmRleE9mKGtleSkgIT09IC0xKTsKICAgIGNvbnN0IG5ld09iaiA9IHsgLi4uYSwgLi4uYiB9OwogICAgZm9yIChjb25zdCBrZXkgb2Ygc2hhcmVkS2V5cykgewogICAgICBjb25zdCBzaGFyZWRWYWx1ZSA9IG1lcmdlVmFsdWVzKGFba2V5XSwgYltrZXldKTsKICAgICAgaWYgKCFzaGFyZWRWYWx1ZS52YWxpZCkgewogICAgICAgIHJldHVybiB7CiAgICAgICAgICB2YWxpZDogZmFsc2UsCiAgICAgICAgICBtZXJnZUVycm9yUGF0aDogW2tleSwgLi4uc2hhcmVkVmFsdWUubWVyZ2VFcnJvclBhdGhdCiAgICAgICAgfTsKICAgICAgfQogICAgICBuZXdPYmpba2V5XSA9IHNoYXJlZFZhbHVlLmRhdGE7CiAgICB9CiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSwgZGF0YTogbmV3T2JqIH07CiAgfQogIGlmIChBcnJheS5pc0FycmF5KGEpICYmIEFycmF5LmlzQXJyYXkoYikpIHsKICAgIGlmIChhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHsKICAgICAgcmV0dXJuIHsgdmFsaWQ6IGZhbHNlLCBtZXJnZUVycm9yUGF0aDogW10gfTsKICAgIH0KICAgIGNvbnN0IG5ld0FycmF5ID0gW107CiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgYS5sZW5ndGg7IGluZGV4KyspIHsKICAgICAgY29uc3QgaXRlbUEgPSBhW2luZGV4XTsKICAgICAgY29uc3QgaXRlbUIgPSBiW2luZGV4XTsKICAgICAgY29uc3Qgc2hhcmVkVmFsdWUgPSBtZXJnZVZhbHVlcyhpdGVtQSwgaXRlbUIpOwogICAgICBpZiAoIXNoYXJlZFZhbHVlLnZhbGlkKSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIHZhbGlkOiBmYWxzZSwKICAgICAgICAgIG1lcmdlRXJyb3JQYXRoOiBbaW5kZXgsIC4uLnNoYXJlZFZhbHVlLm1lcmdlRXJyb3JQYXRoXQogICAgICAgIH07CiAgICAgIH0KICAgICAgbmV3QXJyYXkucHVzaChzaGFyZWRWYWx1ZS5kYXRhKTsKICAgIH0KICAgIHJldHVybiB7IHZhbGlkOiB0cnVlLCBkYXRhOiBuZXdBcnJheSB9OwogIH0KICByZXR1cm4geyB2YWxpZDogZmFsc2UsIG1lcmdlRXJyb3JQYXRoOiBbXSB9Owp9CmZ1bmN0aW9uIGhhbmRsZUludGVyc2VjdGlvblJlc3VsdHMocmVzdWx0LCBsZWZ0LCByaWdodCkgewogIGNvbnN0IHVucmVjS2V5cyA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgTWFwKCk7CiAgbGV0IHVucmVjSXNzdWU7CiAgZm9yIChjb25zdCBpc3Mgb2YgbGVmdC5pc3N1ZXMpIHsKICAgIGlmIChpc3MuY29kZSA9PT0gInVucmVjb2duaXplZF9rZXlzIikgewogICAgICB1bnJlY0lzc3VlID8/ICh1bnJlY0lzc3VlID0gaXNzKTsKICAgICAgZm9yIChjb25zdCBrIG9mIGlzcy5rZXlzKSB7CiAgICAgICAgaWYgKCF1bnJlY0tleXMuaGFzKGspKQogICAgICAgICAgdW5yZWNLZXlzLnNldChrLCB7fSk7CiAgICAgICAgdW5yZWNLZXlzLmdldChrKS5sID0gdHJ1ZTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcmVzdWx0Lmlzc3Vlcy5wdXNoKGlzcyk7CiAgICB9CiAgfQogIGZvciAoY29uc3QgaXNzIG9mIHJpZ2h0Lmlzc3VlcykgewogICAgaWYgKGlzcy5jb2RlID09PSAidW5yZWNvZ25pemVkX2tleXMiKSB7CiAgICAgIGZvciAoY29uc3QgayBvZiBpc3Mua2V5cykgewogICAgICAgIGlmICghdW5yZWNLZXlzLmhhcyhrKSkKICAgICAgICAgIHVucmVjS2V5cy5zZXQoaywge30pOwogICAgICAgIHVucmVjS2V5cy5nZXQoaykuciA9IHRydWU7CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIHJlc3VsdC5pc3N1ZXMucHVzaChpc3MpOwogICAgfQogIH0KICBjb25zdCBib3RoS2V5cyA9IFsuLi51bnJlY0tleXNdLmZpbHRlcigoWywgZl0pID0+IGYubCAmJiBmLnIpLm1hcCgoW2tdKSA9PiBrKTsKICBpZiAoYm90aEtleXMubGVuZ3RoICYmIHVucmVjSXNzdWUpIHsKICAgIHJlc3VsdC5pc3N1ZXMucHVzaCh7IC4uLnVucmVjSXNzdWUsIGtleXM6IGJvdGhLZXlzIH0pOwogIH0KICBpZiAoYWJvcnRlZChyZXN1bHQpKQogICAgcmV0dXJuIHJlc3VsdDsKICBjb25zdCBtZXJnZWQgPSBtZXJnZVZhbHVlcyhsZWZ0LnZhbHVlLCByaWdodC52YWx1ZSk7CiAgaWYgKCFtZXJnZWQudmFsaWQpIHsKICAgIHRocm93IG5ldyBFcnJvcihgVW5tZXJnYWJsZSBpbnRlcnNlY3Rpb24uIEVycm9yIHBhdGg6ICR7SlNPTi5zdHJpbmdpZnkobWVyZ2VkLm1lcmdlRXJyb3JQYXRoKX1gKTsKICB9CiAgcmVzdWx0LnZhbHVlID0gbWVyZ2VkLmRhdGE7CiAgcmV0dXJuIHJlc3VsdDsKfQp2YXIgJFpvZFJlY29yZCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RSZWNvcmQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGNvbnN0IGlucHV0ID0gcGF5bG9hZC52YWx1ZTsKICAgIGlmICghaXNQbGFpbk9iamVjdChpbnB1dCkpIHsKICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgZXhwZWN0ZWQ6ICJyZWNvcmQiLAogICAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICAgIGlucHV0LAogICAgICAgIGluc3QKICAgICAgfSk7CiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgfQogICAgY29uc3QgcHJvbXMgPSBbXTsKICAgIGNvbnN0IHZhbHVlcyA9IGRlZi5rZXlUeXBlLl96b2QudmFsdWVzOwogICAgaWYgKHZhbHVlcykgewogICAgICBwYXlsb2FkLnZhbHVlID0ge307CiAgICAgIGNvbnN0IHJlY29yZEtleXMgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpOwogICAgICBmb3IgKGNvbnN0IGtleSBvZiB2YWx1ZXMpIHsKICAgICAgICBpZiAodHlwZW9mIGtleSA9PT0gInN0cmluZyIgfHwgdHlwZW9mIGtleSA9PT0gIm51bWJlciIgfHwgdHlwZW9mIGtleSA9PT0gInN5bWJvbCIpIHsKICAgICAgICAgIHJlY29yZEtleXMuYWRkKHR5cGVvZiBrZXkgPT09ICJudW1iZXIiID8ga2V5LnRvU3RyaW5nKCkgOiBrZXkpOwogICAgICAgICAgY29uc3Qga2V5UmVzdWx0ID0gZGVmLmtleVR5cGUuX3pvZC5ydW4oeyB2YWx1ZToga2V5LCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgICAgICBpZiAoa2V5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFzeW5jIHNjaGVtYXMgbm90IHN1cHBvcnRlZCBpbiBvYmplY3Qga2V5cyBjdXJyZW50bHkiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChrZXlSZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgICAgICBjb2RlOiAiaW52YWxpZF9rZXkiLAogICAgICAgICAgICAgIG9yaWdpbjogInJlY29yZCIsCiAgICAgICAgICAgICAgaXNzdWVzOiBrZXlSZXN1bHQuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpLAogICAgICAgICAgICAgIGlucHV0OiBrZXksCiAgICAgICAgICAgICAgcGF0aDogW2tleV0sCiAgICAgICAgICAgICAgaW5zdAogICAgICAgICAgICB9KTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBvdXRLZXkgPSBrZXlSZXN1bHQudmFsdWU7CiAgICAgICAgICBjb25zdCByZXN1bHQgPSBkZWYudmFsdWVUeXBlLl96b2QucnVuKHsgdmFsdWU6IGlucHV0W2tleV0sIGlzc3VlczogW10gfSwgY3R4KTsKICAgICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgICAgIHByb21zLnB1c2gocmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IHsKICAgICAgICAgICAgICBpZiAocmVzdWx0Mi5pc3N1ZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKC4uLnByZWZpeElzc3VlcyhrZXksIHJlc3VsdDIuaXNzdWVzKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHBheWxvYWQudmFsdWVbb3V0S2V5XSA9IHJlc3VsdDIudmFsdWU7CiAgICAgICAgICAgIH0pKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goLi4ucHJlZml4SXNzdWVzKGtleSwgcmVzdWx0Lmlzc3VlcykpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBheWxvYWQudmFsdWVbb3V0S2V5XSA9IHJlc3VsdC52YWx1ZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgbGV0IHVucmVjb2duaXplZDsKICAgICAgZm9yIChjb25zdCBrZXkgaW4gaW5wdXQpIHsKICAgICAgICBpZiAoIXJlY29yZEtleXMuaGFzKGtleSkpIHsKICAgICAgICAgIHVucmVjb2duaXplZCA9IHVucmVjb2duaXplZCA/PyBbXTsKICAgICAgICAgIHVucmVjb2duaXplZC5wdXNoKGtleSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmICh1bnJlY29nbml6ZWQgJiYgdW5yZWNvZ25pemVkLmxlbmd0aCA+IDApIHsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHsKICAgICAgICAgIGNvZGU6ICJ1bnJlY29nbml6ZWRfa2V5cyIsCiAgICAgICAgICBpbnB1dCwKICAgICAgICAgIGluc3QsCiAgICAgICAgICBrZXlzOiB1bnJlY29nbml6ZWQKICAgICAgICB9KTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcGF5bG9hZC52YWx1ZSA9IHt9OwogICAgICBmb3IgKGNvbnN0IGtleSBvZiBSZWZsZWN0Lm93bktleXMoaW5wdXQpKSB7CiAgICAgICAgaWYgKGtleSA9PT0gIl9fcHJvdG9fXyIpCiAgICAgICAgICBjb250aW51ZTsKICAgICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChpbnB1dCwga2V5KSkKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIGxldCBrZXlSZXN1bHQgPSBkZWYua2V5VHlwZS5fem9kLnJ1bih7IHZhbHVlOiBrZXksIGlzc3VlczogW10gfSwgY3R4KTsKICAgICAgICBpZiAoa2V5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJBc3luYyBzY2hlbWFzIG5vdCBzdXBwb3J0ZWQgaW4gb2JqZWN0IGtleXMgY3VycmVudGx5Iik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGNoZWNrTnVtZXJpY0tleSA9IHR5cGVvZiBrZXkgPT09ICJzdHJpbmciICYmIG51bWJlci50ZXN0KGtleSkgJiYga2V5UmVzdWx0Lmlzc3Vlcy5sZW5ndGg7CiAgICAgICAgaWYgKGNoZWNrTnVtZXJpY0tleSkgewogICAgICAgICAgY29uc3QgcmV0cnlSZXN1bHQgPSBkZWYua2V5VHlwZS5fem9kLnJ1bih7IHZhbHVlOiBOdW1iZXIoa2V5KSwgaXNzdWVzOiBbXSB9LCBjdHgpOwogICAgICAgICAgaWYgKHJldHJ5UmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFzeW5jIHNjaGVtYXMgbm90IHN1cHBvcnRlZCBpbiBvYmplY3Qga2V5cyBjdXJyZW50bHkiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZXRyeVJlc3VsdC5pc3N1ZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIGtleVJlc3VsdCA9IHJldHJ5UmVzdWx0OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoa2V5UmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgIGlmIChkZWYubW9kZSA9PT0gImxvb3NlIikgewogICAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleV0gPSBpbnB1dFtrZXldOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgICAgICAgICAgY29kZTogImludmFsaWRfa2V5IiwKICAgICAgICAgICAgICBvcmlnaW46ICJyZWNvcmQiLAogICAgICAgICAgICAgIGlzc3Vlczoga2V5UmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKSwKICAgICAgICAgICAgICBpbnB1dDoga2V5LAogICAgICAgICAgICAgIHBhdGg6IFtrZXldLAogICAgICAgICAgICAgIGluc3QKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcmVzdWx0ID0gZGVmLnZhbHVlVHlwZS5fem9kLnJ1bih7IHZhbHVlOiBpbnB1dFtrZXldLCBpc3N1ZXM6IFtdIH0sIGN0eCk7CiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgICAgIHByb21zLnB1c2gocmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IHsKICAgICAgICAgICAgaWYgKHJlc3VsdDIuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goLi4ucHJlZml4SXNzdWVzKGtleSwgcmVzdWx0Mi5pc3N1ZXMpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleVJlc3VsdC52YWx1ZV0gPSByZXN1bHQyLnZhbHVlOwogICAgICAgICAgfSkpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBpZiAocmVzdWx0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgICAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCguLi5wcmVmaXhJc3N1ZXMoa2V5LCByZXN1bHQuaXNzdWVzKSk7CiAgICAgICAgICB9CiAgICAgICAgICBwYXlsb2FkLnZhbHVlW2tleVJlc3VsdC52YWx1ZV0gPSByZXN1bHQudmFsdWU7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZiAocHJvbXMubGVuZ3RoKSB7CiAgICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9tcykudGhlbigoKSA9PiBwYXlsb2FkKTsKICAgIH0KICAgIHJldHVybiBwYXlsb2FkOwogIH07Cn0pOwp2YXIgJFpvZEVudW0gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kRW51bSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgY29uc3QgdmFsdWVzID0gZ2V0RW51bVZhbHVlcyhkZWYuZW50cmllcyk7CiAgY29uc3QgdmFsdWVzU2V0ID0gbmV3IFNldCh2YWx1ZXMpOwogIGluc3QuX3pvZC52YWx1ZXMgPSB2YWx1ZXNTZXQ7CiAgaW5zdC5fem9kLnBhdHRlcm4gPSBuZXcgUmVnRXhwKGBeKCR7dmFsdWVzLmZpbHRlcigoaykgPT4gcHJvcGVydHlLZXlUeXBlcy5oYXModHlwZW9mIGspKS5tYXAoKG8pID0+IHR5cGVvZiBvID09PSAic3RyaW5nIiA/IGVzY2FwZVJlZ2V4KG8pIDogby50b1N0cmluZygpKS5qb2luKCJ8Iil9KSRgKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgX2N0eCkgPT4gewogICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgaWYgKHZhbHVlc1NldC5oYXMoaW5wdXQpKSB7CiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgfQogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGNvZGU6ICJpbnZhbGlkX3ZhbHVlIiwKICAgICAgdmFsdWVzLAogICAgICBpbnB1dCwKICAgICAgaW5zdAogICAgfSk7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKdmFyICRab2RUcmFuc2Zvcm0gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kVHJhbnNmb3JtIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2Qub3B0aW4gPSAib3B0aW9uYWwiOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChjdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgIHRocm93IG5ldyAkWm9kRW5jb2RlRXJyb3IoaW5zdC5jb25zdHJ1Y3Rvci5uYW1lKTsKICAgIH0KICAgIGNvbnN0IF9vdXQgPSBkZWYudHJhbnNmb3JtKHBheWxvYWQudmFsdWUsIHBheWxvYWQpOwogICAgaWYgKGN0eC5hc3luYykgewogICAgICBjb25zdCBvdXRwdXQgPSBfb3V0IGluc3RhbmNlb2YgUHJvbWlzZSA/IF9vdXQgOiBQcm9taXNlLnJlc29sdmUoX291dCk7CiAgICAgIHJldHVybiBvdXRwdXQudGhlbigob3V0cHV0MikgPT4gewogICAgICAgIHBheWxvYWQudmFsdWUgPSBvdXRwdXQyOwogICAgICAgIHBheWxvYWQuZmFsbGJhY2sgPSB0cnVlOwogICAgICAgIHJldHVybiBwYXlsb2FkOwogICAgICB9KTsKICAgIH0KICAgIGlmIChfb3V0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICB0aHJvdyBuZXcgJFpvZEFzeW5jRXJyb3IoKTsKICAgIH0KICAgIHBheWxvYWQudmFsdWUgPSBfb3V0OwogICAgcGF5bG9hZC5mYWxsYmFjayA9IHRydWU7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlT3B0aW9uYWxSZXN1bHQocmVzdWx0LCBpbnB1dCkgewogIGlmIChpbnB1dCA9PT0gdm9pZCAwICYmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCB8fCByZXN1bHQuZmFsbGJhY2spKSB7CiAgICByZXR1cm4geyBpc3N1ZXM6IFtdLCB2YWx1ZTogdm9pZCAwIH07CiAgfQogIHJldHVybiByZXN1bHQ7Cn0KdmFyICRab2RPcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RPcHRpb25hbCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLm9wdGluID0gIm9wdGlvbmFsIjsKICBpbnN0Ll96b2Qub3B0b3V0ID0gIm9wdGlvbmFsIjsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInZhbHVlcyIsICgpID0+IHsKICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzID8gLyogQF9fUFVSRV9fICovIG5ldyBTZXQoWy4uLmRlZi5pbm5lclR5cGUuX3pvZC52YWx1ZXMsIHZvaWQgMF0pIDogdm9pZCAwOwogIH0pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicGF0dGVybiIsICgpID0+IHsKICAgIGNvbnN0IHBhdHRlcm4gPSBkZWYuaW5uZXJUeXBlLl96b2QucGF0dGVybjsKICAgIHJldHVybiBwYXR0ZXJuID8gbmV3IFJlZ0V4cChgXigke2NsZWFuUmVnZXgocGF0dGVybi5zb3VyY2UpfSk/JGApIDogdm9pZCAwOwogIH0pOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChkZWYuaW5uZXJUeXBlLl96b2Qub3B0aW4gPT09ICJvcHRpb25hbCIpIHsKICAgICAgY29uc3QgaW5wdXQgPSBwYXlsb2FkLnZhbHVlOwogICAgICBjb25zdCByZXN1bHQgPSBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKQogICAgICAgIHJldHVybiByZXN1bHQudGhlbigocikgPT4gaGFuZGxlT3B0aW9uYWxSZXN1bHQociwgaW5wdXQpKTsKICAgICAgcmV0dXJuIGhhbmRsZU9wdGlvbmFsUmVzdWx0KHJlc3VsdCwgaW5wdXQpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICByZXR1cm4gcGF5bG9hZDsKICAgIH0KICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgfTsKfSk7CnZhciAkWm9kRXhhY3RPcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RFeGFjdE9wdGlvbmFsIiwgKGluc3QsIGRlZikgPT4gewogICRab2RPcHRpb25hbC5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInBhdHRlcm4iLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QucGF0dGVybik7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgcmV0dXJuIGRlZi5pbm5lclR5cGUuX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKdmFyICRab2ROdWxsYWJsZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2ROdWxsYWJsZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5pbm5lclR5cGUuX3pvZC5vcHRpbik7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRvdXQiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2Qub3B0b3V0KTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInBhdHRlcm4iLCAoKSA9PiB7CiAgICBjb25zdCBwYXR0ZXJuID0gZGVmLmlubmVyVHlwZS5fem9kLnBhdHRlcm47CiAgICByZXR1cm4gcGF0dGVybiA/IG5ldyBSZWdFeHAoYF4oJHtjbGVhblJlZ2V4KHBhdHRlcm4uc291cmNlKX18bnVsbCkkYCkgOiB2b2lkIDA7CiAgfSk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiB7CiAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnZhbHVlcyA/IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KFsuLi5kZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzLCBudWxsXSkgOiB2b2lkIDA7CiAgfSk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IG51bGwpCiAgICAgIHJldHVybiBwYXlsb2FkOwogICAgcmV0dXJuIGRlZi5pbm5lclR5cGUuX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICB9Owp9KTsKdmFyICRab2REZWZhdWx0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZERlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vcHRpbiA9ICJvcHRpb25hbCI7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmRlZmF1bHRWYWx1ZTsKICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICB9CiAgICBjb25zdCByZXN1bHQgPSBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gcmVzdWx0LnRoZW4oKHJlc3VsdDIpID0+IGhhbmRsZURlZmF1bHRSZXN1bHQocmVzdWx0MiwgZGVmKSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlRGVmYXVsdFJlc3VsdChyZXN1bHQsIGRlZik7CiAgfTsKfSk7CmZ1bmN0aW9uIGhhbmRsZURlZmF1bHRSZXN1bHQocGF5bG9hZCwgZGVmKSB7CiAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgcGF5bG9hZC52YWx1ZSA9IGRlZi5kZWZhdWx0VmFsdWU7CiAgfQogIHJldHVybiBwYXlsb2FkOwp9CnZhciAkWm9kUHJlZmF1bHQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kUHJlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5vcHRpbiA9ICJvcHRpb25hbCI7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgaWYgKHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmRlZmF1bHRWYWx1ZTsKICAgIH0KICAgIHJldHVybiBkZWYuaW5uZXJUeXBlLl96b2QucnVuKHBheWxvYWQsIGN0eCk7CiAgfTsKfSk7CnZhciAkWm9kTm9uT3B0aW9uYWwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kTm9uT3B0aW9uYWwiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAidmFsdWVzIiwgKCkgPT4gewogICAgY29uc3QgdiA9IGRlZi5pbm5lclR5cGUuX3pvZC52YWx1ZXM7CiAgICByZXR1cm4gdiA/IG5ldyBTZXQoWy4uLnZdLmZpbHRlcigoeCkgPT4geCAhPT0gdm9pZCAwKSkgOiB2b2lkIDA7CiAgfSk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIGN0eCkgPT4gewogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiBoYW5kbGVOb25PcHRpb25hbFJlc3VsdChyZXN1bHQyLCBpbnN0KSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlTm9uT3B0aW9uYWxSZXN1bHQocmVzdWx0LCBpbnN0KTsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlTm9uT3B0aW9uYWxSZXN1bHQocGF5bG9hZCwgaW5zdCkgewogIGlmICghcGF5bG9hZC5pc3N1ZXMubGVuZ3RoICYmIHBheWxvYWQudmFsdWUgPT09IHZvaWQgMCkgewogICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh7CiAgICAgIGNvZGU6ICJpbnZhbGlkX3R5cGUiLAogICAgICBleHBlY3RlZDogIm5vbm9wdGlvbmFsIiwKICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUsCiAgICAgIGluc3QKICAgIH0pOwogIH0KICByZXR1cm4gcGF5bG9hZDsKfQp2YXIgJFpvZENhdGNoID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZENhdGNoIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2Qub3B0aW4gPSAib3B0aW9uYWwiOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAib3B0b3V0IiwgKCkgPT4gZGVmLmlubmVyVHlwZS5fem9kLm9wdG91dCk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKChyZXN1bHQyKSA9PiB7CiAgICAgICAgcGF5bG9hZC52YWx1ZSA9IHJlc3VsdDIudmFsdWU7CiAgICAgICAgaWYgKHJlc3VsdDIuaXNzdWVzLmxlbmd0aCkgewogICAgICAgICAgcGF5bG9hZC52YWx1ZSA9IGRlZi5jYXRjaFZhbHVlKHsKICAgICAgICAgICAgLi4ucGF5bG9hZCwKICAgICAgICAgICAgZXJyb3I6IHsKICAgICAgICAgICAgICBpc3N1ZXM6IHJlc3VsdDIuaXNzdWVzLm1hcCgoaXNzKSA9PiBmaW5hbGl6ZUlzc3VlKGlzcywgY3R4LCBjb25maWcoKSkpCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGlucHV0OiBwYXlsb2FkLnZhbHVlCiAgICAgICAgICB9KTsKICAgICAgICAgIHBheWxvYWQuaXNzdWVzID0gW107CiAgICAgICAgICBwYXlsb2FkLmZhbGxiYWNrID0gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgIH0pOwogICAgfQogICAgcGF5bG9hZC52YWx1ZSA9IHJlc3VsdC52YWx1ZTsKICAgIGlmIChyZXN1bHQuaXNzdWVzLmxlbmd0aCkgewogICAgICBwYXlsb2FkLnZhbHVlID0gZGVmLmNhdGNoVmFsdWUoewogICAgICAgIC4uLnBheWxvYWQsCiAgICAgICAgZXJyb3I6IHsKICAgICAgICAgIGlzc3VlczogcmVzdWx0Lmlzc3Vlcy5tYXAoKGlzcykgPT4gZmluYWxpemVJc3N1ZShpc3MsIGN0eCwgY29uZmlnKCkpKQogICAgICAgIH0sCiAgICAgICAgaW5wdXQ6IHBheWxvYWQudmFsdWUKICAgICAgfSk7CiAgICAgIHBheWxvYWQuaXNzdWVzID0gW107CiAgICAgIHBheWxvYWQuZmFsbGJhY2sgPSB0cnVlOwogICAgfQogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CnZhciAkWm9kUGlwZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIiRab2RQaXBlIiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInZhbHVlcyIsICgpID0+IGRlZi5pbi5fem9kLnZhbHVlcyk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJvcHRpbiIsICgpID0+IGRlZi5pbi5fem9kLm9wdGluKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdG91dCIsICgpID0+IGRlZi5vdXQuX3pvZC5vcHRvdXQpOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAicHJvcFZhbHVlcyIsICgpID0+IGRlZi5pbi5fem9kLnByb3BWYWx1ZXMpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBjdHgpID0+IHsKICAgIGlmIChjdHguZGlyZWN0aW9uID09PSAiYmFja3dhcmQiKSB7CiAgICAgIGNvbnN0IHJpZ2h0ID0gZGVmLm91dC5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgICBpZiAocmlnaHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7CiAgICAgICAgcmV0dXJuIHJpZ2h0LnRoZW4oKHJpZ2h0MikgPT4gaGFuZGxlUGlwZVJlc3VsdChyaWdodDIsIGRlZi5pbiwgY3R4KSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGhhbmRsZVBpcGVSZXN1bHQocmlnaHQsIGRlZi5pbiwgY3R4KTsKICAgIH0KICAgIGNvbnN0IGxlZnQgPSBkZWYuaW4uX3pvZC5ydW4ocGF5bG9hZCwgY3R4KTsKICAgIGlmIChsZWZ0IGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gbGVmdC50aGVuKChsZWZ0MikgPT4gaGFuZGxlUGlwZVJlc3VsdChsZWZ0MiwgZGVmLm91dCwgY3R4KSk7CiAgICB9CiAgICByZXR1cm4gaGFuZGxlUGlwZVJlc3VsdChsZWZ0LCBkZWYub3V0LCBjdHgpOwogIH07Cn0pOwpmdW5jdGlvbiBoYW5kbGVQaXBlUmVzdWx0KGxlZnQsIG5leHQsIGN0eCkgewogIGlmIChsZWZ0Lmlzc3Vlcy5sZW5ndGgpIHsKICAgIGxlZnQuYWJvcnRlZCA9IHRydWU7CiAgICByZXR1cm4gbGVmdDsKICB9CiAgcmV0dXJuIG5leHQuX3pvZC5ydW4oeyB2YWx1ZTogbGVmdC52YWx1ZSwgaXNzdWVzOiBsZWZ0Lmlzc3VlcywgZmFsbGJhY2s6IGxlZnQuZmFsbGJhY2sgfSwgY3R4KTsKfQp2YXIgJFpvZFJlYWRvbmx5ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiJFpvZFJlYWRvbmx5IiwgKGluc3QsIGRlZikgPT4gewogICRab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgInByb3BWYWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QucHJvcFZhbHVlcyk7CiAgZGVmaW5lTGF6eShpbnN0Ll96b2QsICJ2YWx1ZXMiLCAoKSA9PiBkZWYuaW5uZXJUeXBlLl96b2QudmFsdWVzKTsKICBkZWZpbmVMYXp5KGluc3QuX3pvZCwgIm9wdGluIiwgKCkgPT4gZGVmLmlubmVyVHlwZT8uX3pvZD8ub3B0aW4pOwogIGRlZmluZUxhenkoaW5zdC5fem9kLCAib3B0b3V0IiwgKCkgPT4gZGVmLmlubmVyVHlwZT8uX3pvZD8ub3B0b3V0KTsKICBpbnN0Ll96b2QucGFyc2UgPSAocGF5bG9hZCwgY3R4KSA9PiB7CiAgICBpZiAoY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICByZXR1cm4gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgfQogICAgY29uc3QgcmVzdWx0ID0gZGVmLmlubmVyVHlwZS5fem9kLnJ1bihwYXlsb2FkLCBjdHgpOwogICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIHJlc3VsdC50aGVuKGhhbmRsZVJlYWRvbmx5UmVzdWx0KTsKICAgIH0KICAgIHJldHVybiBoYW5kbGVSZWFkb25seVJlc3VsdChyZXN1bHQpOwogIH07Cn0pOwpmdW5jdGlvbiBoYW5kbGVSZWFkb25seVJlc3VsdChwYXlsb2FkKSB7CiAgcGF5bG9hZC52YWx1ZSA9IE9iamVjdC5mcmVlemUocGF5bG9hZC52YWx1ZSk7CiAgcmV0dXJuIHBheWxvYWQ7Cn0KdmFyICRab2RDdXN0b20gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCIkWm9kQ3VzdG9tIiwgKGluc3QsIGRlZikgPT4gewogICRab2RDaGVjay5pbml0KGluc3QsIGRlZik7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wYXJzZSA9IChwYXlsb2FkLCBfKSA9PiB7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9OwogIGluc3QuX3pvZC5jaGVjayA9IChwYXlsb2FkKSA9PiB7CiAgICBjb25zdCBpbnB1dCA9IHBheWxvYWQudmFsdWU7CiAgICBjb25zdCByID0gZGVmLmZuKGlucHV0KTsKICAgIGlmIChyIGluc3RhbmNlb2YgUHJvbWlzZSkgewogICAgICByZXR1cm4gci50aGVuKChyMikgPT4gaGFuZGxlUmVmaW5lUmVzdWx0KHIyLCBwYXlsb2FkLCBpbnB1dCwgaW5zdCkpOwogICAgfQogICAgaGFuZGxlUmVmaW5lUmVzdWx0KHIsIHBheWxvYWQsIGlucHV0LCBpbnN0KTsKICAgIHJldHVybjsKICB9Owp9KTsKZnVuY3Rpb24gaGFuZGxlUmVmaW5lUmVzdWx0KHJlc3VsdCwgcGF5bG9hZCwgaW5wdXQsIGluc3QpIHsKICBpZiAoIXJlc3VsdCkgewogICAgY29uc3QgX2lzcyA9IHsKICAgICAgY29kZTogImN1c3RvbSIsCiAgICAgIGlucHV0LAogICAgICBpbnN0LAogICAgICAvLyBpbmNvcnBvcmF0ZXMgcGFyYW1zLmVycm9yIGludG8gaXNzdWUgcmVwb3J0aW5nCiAgICAgIHBhdGg6IFsuLi5pbnN0Ll96b2QuZGVmLnBhdGggPz8gW11dLAogICAgICAvLyBpbmNvcnBvcmF0ZXMgcGFyYW1zLmVycm9yIGludG8gaXNzdWUgcmVwb3J0aW5nCiAgICAgIGNvbnRpbnVlOiAhaW5zdC5fem9kLmRlZi5hYm9ydAogICAgICAvLyBwYXJhbXM6IGluc3QuX3pvZC5kZWYucGFyYW1zLAogICAgfTsKICAgIGlmIChpbnN0Ll96b2QuZGVmLnBhcmFtcykKICAgICAgX2lzcy5wYXJhbXMgPSBpbnN0Ll96b2QuZGVmLnBhcmFtczsKICAgIHBheWxvYWQuaXNzdWVzLnB1c2goaXNzdWUoX2lzcykpOwogIH0KfQoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jb3JlL3JlZ2lzdHJpZXMuanMKdmFyIF9hMjsKdmFyICRab2RSZWdpc3RyeSA9IGNsYXNzIHsKICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMuX21hcCA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgV2Vha01hcCgpOwogICAgdGhpcy5faWRtYXAgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogIH0KICBhZGQoc2NoZW1hLCAuLi5fbWV0YSkgewogICAgY29uc3QgbWV0YTIgPSBfbWV0YVswXTsKICAgIHRoaXMuX21hcC5zZXQoc2NoZW1hLCBtZXRhMik7CiAgICBpZiAobWV0YTIgJiYgdHlwZW9mIG1ldGEyID09PSAib2JqZWN0IiAmJiAiaWQiIGluIG1ldGEyKSB7CiAgICAgIHRoaXMuX2lkbWFwLnNldChtZXRhMi5pZCwgc2NoZW1hKTsKICAgIH0KICAgIHJldHVybiB0aGlzOwogIH0KICBjbGVhcigpIHsKICAgIHRoaXMuX21hcCA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgV2Vha01hcCgpOwogICAgdGhpcy5faWRtYXAgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogICAgcmV0dXJuIHRoaXM7CiAgfQogIHJlbW92ZShzY2hlbWEpIHsKICAgIGNvbnN0IG1ldGEyID0gdGhpcy5fbWFwLmdldChzY2hlbWEpOwogICAgaWYgKG1ldGEyICYmIHR5cGVvZiBtZXRhMiA9PT0gIm9iamVjdCIgJiYgImlkIiBpbiBtZXRhMikgewogICAgICB0aGlzLl9pZG1hcC5kZWxldGUobWV0YTIuaWQpOwogICAgfQogICAgdGhpcy5fbWFwLmRlbGV0ZShzY2hlbWEpOwogICAgcmV0dXJuIHRoaXM7CiAgfQogIGdldChzY2hlbWEpIHsKICAgIGNvbnN0IHAgPSBzY2hlbWEuX3pvZC5wYXJlbnQ7CiAgICBpZiAocCkgewogICAgICBjb25zdCBwbSA9IHsgLi4udGhpcy5nZXQocCkgPz8ge30gfTsKICAgICAgZGVsZXRlIHBtLmlkOwogICAgICBjb25zdCBmID0geyAuLi5wbSwgLi4udGhpcy5fbWFwLmdldChzY2hlbWEpIH07CiAgICAgIHJldHVybiBPYmplY3Qua2V5cyhmKS5sZW5ndGggPyBmIDogdm9pZCAwOwogICAgfQogICAgcmV0dXJuIHRoaXMuX21hcC5nZXQoc2NoZW1hKTsKICB9CiAgaGFzKHNjaGVtYSkgewogICAgcmV0dXJuIHRoaXMuX21hcC5oYXMoc2NoZW1hKTsKICB9Cn07CmZ1bmN0aW9uIHJlZ2lzdHJ5KCkgewogIHJldHVybiBuZXcgJFpvZFJlZ2lzdHJ5KCk7Cn0KKF9hMiA9IGdsb2JhbFRoaXMpLl9fem9kX2dsb2JhbFJlZ2lzdHJ5ID8/IChfYTIuX196b2RfZ2xvYmFsUmVnaXN0cnkgPSByZWdpc3RyeSgpKTsKdmFyIGdsb2JhbFJlZ2lzdHJ5ID0gZ2xvYmFsVGhpcy5fX3pvZF9nbG9iYWxSZWdpc3RyeTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY29yZS9hcGkuanMKLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3N0cmluZyhDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZW1haWwoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImVtYWlsIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9ndWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJndWlkIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ1dWlkIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjYoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NiIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91dWlkdjcoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInV1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIHZlcnNpb246ICJ2NyIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF91cmwoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogInVybCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfZW1vamkyKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJlbW9qaSIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbmFub2lkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJuYW5vaWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2N1aWQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImN1aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2N1aWQyKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJjdWlkMiIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdWxpZChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAidWxpZCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfeGlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ4aWQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2tzdWlkKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJrc3VpZCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfaXB2NChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiaXB2NCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfaXB2NihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiaXB2NiIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfY2lkcnY0KENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJjaWRydjQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2NpZHJ2NihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiY2lkcnY2IiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9iYXNlNjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImJhc2U2NCIsCiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgYWJvcnQ6IGZhbHNlLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfYmFzZTY0dXJsKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJiYXNlNjR1cmwiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2UxNjQoQ2xhc3MyLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IENsYXNzMih7CiAgICB0eXBlOiAic3RyaW5nIiwKICAgIGZvcm1hdDogImUxNjQiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2p3dChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiand0IiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBhYm9ydDogZmFsc2UsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EYXRlVGltZShDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiZGF0ZXRpbWUiLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIG9mZnNldDogZmFsc2UsCiAgICBsb2NhbDogZmFsc2UsCiAgICBwcmVjaXNpb246IG51bGwsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EYXRlKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJkYXRlIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29UaW1lKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInN0cmluZyIsCiAgICBmb3JtYXQ6ICJ0aW1lIiwKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBwcmVjaXNpb246IG51bGwsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9pc29EdXJhdGlvbihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJzdHJpbmciLAogICAgZm9ybWF0OiAiZHVyYXRpb24iLAogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX251bWJlcihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJudW1iZXIiLAogICAgY2hlY2tzOiBbXSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2ludChDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJudW1iZXIiLAogICAgY2hlY2s6ICJudW1iZXJfZm9ybWF0IiwKICAgIGFib3J0OiBmYWxzZSwKICAgIGZvcm1hdDogInNhZmVpbnQiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfYm9vbGVhbihDbGFzczIsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJib29sZWFuIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3Vua25vd24oQ2xhc3MyKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogInVua25vd24iCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX25ldmVyKENsYXNzMiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBDbGFzczIoewogICAgdHlwZTogIm5ldmVyIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2x0KHZhbHVlLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0xlc3NUaGFuKHsKICAgIGNoZWNrOiAibGVzc190aGFuIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgdmFsdWUsCiAgICBpbmNsdXNpdmU6IGZhbHNlCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2x0ZSh2YWx1ZSwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tMZXNzVGhhbih7CiAgICBjaGVjazogImxlc3NfdGhhbiIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIHZhbHVlLAogICAgaW5jbHVzaXZlOiB0cnVlCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2d0KHZhbHVlLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0dyZWF0ZXJUaGFuKHsKICAgIGNoZWNrOiAiZ3JlYXRlcl90aGFuIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgdmFsdWUsCiAgICBpbmNsdXNpdmU6IGZhbHNlCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2d0ZSh2YWx1ZSwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tHcmVhdGVyVGhhbih7CiAgICBjaGVjazogImdyZWF0ZXJfdGhhbiIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIHZhbHVlLAogICAgaW5jbHVzaXZlOiB0cnVlCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX211bHRpcGxlT2YodmFsdWUsIHBhcmFtcykgewogIHJldHVybiBuZXcgJFpvZENoZWNrTXVsdGlwbGVPZih7CiAgICBjaGVjazogIm11bHRpcGxlX29mIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgdmFsdWUKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfbWF4TGVuZ3RoKG1heGltdW0sIHBhcmFtcykgewogIGNvbnN0IGNoID0gbmV3ICRab2RDaGVja01heExlbmd0aCh7CiAgICBjaGVjazogIm1heF9sZW5ndGgiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBtYXhpbXVtCiAgfSk7CiAgcmV0dXJuIGNoOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9taW5MZW5ndGgobWluaW11bSwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tNaW5MZW5ndGgoewogICAgY2hlY2s6ICJtaW5fbGVuZ3RoIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgbWluaW11bQogIH0pOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9sZW5ndGgobGVuZ3RoLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0xlbmd0aEVxdWFscyh7CiAgICBjaGVjazogImxlbmd0aF9lcXVhbHMiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBsZW5ndGgKICB9KTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfcmVnZXgocGF0dGVybiwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tSZWdleCh7CiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgZm9ybWF0OiAicmVnZXgiLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICBwYXR0ZXJuCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2xvd2VyY2FzZShwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0xvd2VyQ2FzZSh7CiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgZm9ybWF0OiAibG93ZXJjYXNlIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3VwcGVyY2FzZShwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja1VwcGVyQ2FzZSh7CiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgZm9ybWF0OiAidXBwZXJjYXNlIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2luY2x1ZGVzKGluY2x1ZGVzLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja0luY2x1ZGVzKHsKICAgIGNoZWNrOiAic3RyaW5nX2Zvcm1hdCIsCiAgICBmb3JtYXQ6ICJpbmNsdWRlcyIsCiAgICAuLi5ub3JtYWxpemVQYXJhbXMocGFyYW1zKSwKICAgIGluY2x1ZGVzCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3N0YXJ0c1dpdGgocHJlZml4LCBwYXJhbXMpIHsKICByZXR1cm4gbmV3ICRab2RDaGVja1N0YXJ0c1dpdGgoewogICAgY2hlY2s6ICJzdHJpbmdfZm9ybWF0IiwKICAgIGZvcm1hdDogInN0YXJ0c193aXRoIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgcHJlZml4CiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2VuZHNXaXRoKHN1ZmZpeCwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyAkWm9kQ2hlY2tFbmRzV2l0aCh7CiAgICBjaGVjazogInN0cmluZ19mb3JtYXQiLAogICAgZm9ybWF0OiAiZW5kc193aXRoIiwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgc3VmZml4CiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX292ZXJ3cml0ZSh0eCkgewogIHJldHVybiBuZXcgJFpvZENoZWNrT3ZlcndyaXRlKHsKICAgIGNoZWNrOiAib3ZlcndyaXRlIiwKICAgIHR4CiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX25vcm1hbGl6ZShmb3JtKSB7CiAgcmV0dXJuIC8qIEBfX1BVUkVfXyAqLyBfb3ZlcndyaXRlKChpbnB1dCkgPT4gaW5wdXQubm9ybWFsaXplKGZvcm0pKTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdHJpbSgpIHsKICByZXR1cm4gLyogQF9fUFVSRV9fICovIF9vdmVyd3JpdGUoKGlucHV0KSA9PiBpbnB1dC50cmltKCkpOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF90b0xvd2VyQ2FzZSgpIHsKICByZXR1cm4gLyogQF9fUFVSRV9fICovIF9vdmVyd3JpdGUoKGlucHV0KSA9PiBpbnB1dC50b0xvd2VyQ2FzZSgpKTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfdG9VcHBlckNhc2UoKSB7CiAgcmV0dXJuIC8qIEBfX1BVUkVfXyAqLyBfb3ZlcndyaXRlKChpbnB1dCkgPT4gaW5wdXQudG9VcHBlckNhc2UoKSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3NsdWdpZnkoKSB7CiAgcmV0dXJuIC8qIEBfX1BVUkVfXyAqLyBfb3ZlcndyaXRlKChpbnB1dCkgPT4gc2x1Z2lmeShpbnB1dCkpOwp9Ci8vIEBfX05PX1NJREVfRUZGRUNUU19fCmZ1bmN0aW9uIF9hcnJheShDbGFzczIsIGVsZW1lbnQsIHBhcmFtcykgewogIHJldHVybiBuZXcgQ2xhc3MyKHsKICAgIHR5cGU6ICJhcnJheSIsCiAgICBlbGVtZW50LAogICAgLy8gZ2V0IGVsZW1lbnQoKSB7CiAgICAvLyAgIHJldHVybiBlbGVtZW50OwogICAgLy8gfSwKICAgIC4uLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX3JlZmluZShDbGFzczIsIGZuLCBfcGFyYW1zKSB7CiAgY29uc3Qgc2NoZW1hID0gbmV3IENsYXNzMih7CiAgICB0eXBlOiAiY3VzdG9tIiwKICAgIGNoZWNrOiAiY3VzdG9tIiwKICAgIGZuLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKF9wYXJhbXMpCiAgfSk7CiAgcmV0dXJuIHNjaGVtYTsKfQovLyBAX19OT19TSURFX0VGRkVDVFNfXwpmdW5jdGlvbiBfc3VwZXJSZWZpbmUoZm4sIHBhcmFtcykgewogIGNvbnN0IGNoID0gLyogQF9fUFVSRV9fICovIF9jaGVjaygocGF5bG9hZCkgPT4gewogICAgcGF5bG9hZC5hZGRJc3N1ZSA9IChpc3N1ZTIpID0+IHsKICAgICAgaWYgKHR5cGVvZiBpc3N1ZTIgPT09ICJzdHJpbmciKSB7CiAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaChpc3N1ZShpc3N1ZTIsIHBheWxvYWQudmFsdWUsIGNoLl96b2QuZGVmKSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgX2lzc3VlID0gaXNzdWUyOwogICAgICAgIGlmIChfaXNzdWUuZmF0YWwpCiAgICAgICAgICBfaXNzdWUuY29udGludWUgPSBmYWxzZTsKICAgICAgICBfaXNzdWUuY29kZSA/PyAoX2lzc3VlLmNvZGUgPSAiY3VzdG9tIik7CiAgICAgICAgX2lzc3VlLmlucHV0ID8/IChfaXNzdWUuaW5wdXQgPSBwYXlsb2FkLnZhbHVlKTsKICAgICAgICBfaXNzdWUuaW5zdCA/PyAoX2lzc3VlLmluc3QgPSBjaCk7CiAgICAgICAgX2lzc3VlLmNvbnRpbnVlID8/IChfaXNzdWUuY29udGludWUgPSAhY2guX3pvZC5kZWYuYWJvcnQpOwogICAgICAgIHBheWxvYWQuaXNzdWVzLnB1c2goaXNzdWUoX2lzc3VlKSk7CiAgICAgIH0KICAgIH07CiAgICByZXR1cm4gZm4ocGF5bG9hZC52YWx1ZSwgcGF5bG9hZCk7CiAgfSwgcGFyYW1zKTsKICByZXR1cm4gY2g7Cn0KLy8gQF9fTk9fU0lERV9FRkZFQ1RTX18KZnVuY3Rpb24gX2NoZWNrKGZuLCBwYXJhbXMpIHsKICBjb25zdCBjaCA9IG5ldyAkWm9kQ2hlY2soewogICAgY2hlY2s6ICJjdXN0b20iLAogICAgLi4ubm9ybWFsaXplUGFyYW1zKHBhcmFtcykKICB9KTsKICBjaC5fem9kLmNoZWNrID0gZm47CiAgcmV0dXJuIGNoOwp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvdG8tanNvbi1zY2hlbWEuanMKZnVuY3Rpb24gaW5pdGlhbGl6ZUNvbnRleHQocGFyYW1zKSB7CiAgbGV0IHRhcmdldCA9IHBhcmFtcz8udGFyZ2V0ID8/ICJkcmFmdC0yMDIwLTEyIjsKICBpZiAodGFyZ2V0ID09PSAiZHJhZnQtNCIpCiAgICB0YXJnZXQgPSAiZHJhZnQtMDQiOwogIGlmICh0YXJnZXQgPT09ICJkcmFmdC03IikKICAgIHRhcmdldCA9ICJkcmFmdC0wNyI7CiAgcmV0dXJuIHsKICAgIHByb2Nlc3NvcnM6IHBhcmFtcy5wcm9jZXNzb3JzID8/IHt9LAogICAgbWV0YWRhdGFSZWdpc3RyeTogcGFyYW1zPy5tZXRhZGF0YSA/PyBnbG9iYWxSZWdpc3RyeSwKICAgIHRhcmdldCwKICAgIHVucmVwcmVzZW50YWJsZTogcGFyYW1zPy51bnJlcHJlc2VudGFibGUgPz8gInRocm93IiwKICAgIG92ZXJyaWRlOiBwYXJhbXM/Lm92ZXJyaWRlID8/ICgoKSA9PiB7CiAgICB9KSwKICAgIGlvOiBwYXJhbXM/LmlvID8/ICJvdXRwdXQiLAogICAgY291bnRlcjogMCwKICAgIHNlZW46IC8qIEBfX1BVUkVfXyAqLyBuZXcgTWFwKCksCiAgICBjeWNsZXM6IHBhcmFtcz8uY3ljbGVzID8/ICJyZWYiLAogICAgcmV1c2VkOiBwYXJhbXM/LnJldXNlZCA/PyAiaW5saW5lIiwKICAgIGV4dGVybmFsOiBwYXJhbXM/LmV4dGVybmFsID8/IHZvaWQgMAogIH07Cn0KZnVuY3Rpb24gcHJvY2VzczIoc2NoZW1hLCBjdHgsIF9wYXJhbXMgPSB7IHBhdGg6IFtdLCBzY2hlbWFQYXRoOiBbXSB9KSB7CiAgdmFyIF9hMzsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgY29uc3Qgc2VlbiA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIGlmIChzZWVuKSB7CiAgICBzZWVuLmNvdW50Kys7CiAgICBjb25zdCBpc0N5Y2xlID0gX3BhcmFtcy5zY2hlbWFQYXRoLmluY2x1ZGVzKHNjaGVtYSk7CiAgICBpZiAoaXNDeWNsZSkgewogICAgICBzZWVuLmN5Y2xlID0gX3BhcmFtcy5wYXRoOwogICAgfQogICAgcmV0dXJuIHNlZW4uc2NoZW1hOwogIH0KICBjb25zdCByZXN1bHQgPSB7IHNjaGVtYToge30sIGNvdW50OiAxLCBjeWNsZTogdm9pZCAwLCBwYXRoOiBfcGFyYW1zLnBhdGggfTsKICBjdHguc2Vlbi5zZXQoc2NoZW1hLCByZXN1bHQpOwogIGNvbnN0IG92ZXJyaWRlU2NoZW1hID0gc2NoZW1hLl96b2QudG9KU09OU2NoZW1hPy4oKTsKICBpZiAob3ZlcnJpZGVTY2hlbWEpIHsKICAgIHJlc3VsdC5zY2hlbWEgPSBvdmVycmlkZVNjaGVtYTsKICB9IGVsc2UgewogICAgY29uc3QgcGFyYW1zID0gewogICAgICAuLi5fcGFyYW1zLAogICAgICBzY2hlbWFQYXRoOiBbLi4uX3BhcmFtcy5zY2hlbWFQYXRoLCBzY2hlbWFdLAogICAgICBwYXRoOiBfcGFyYW1zLnBhdGgKICAgIH07CiAgICBpZiAoc2NoZW1hLl96b2QucHJvY2Vzc0pTT05TY2hlbWEpIHsKICAgICAgc2NoZW1hLl96b2QucHJvY2Vzc0pTT05TY2hlbWEoY3R4LCByZXN1bHQuc2NoZW1hLCBwYXJhbXMpOwogICAgfSBlbHNlIHsKICAgICAgY29uc3QgX2pzb24gPSByZXN1bHQuc2NoZW1hOwogICAgICBjb25zdCBwcm9jZXNzb3IgPSBjdHgucHJvY2Vzc29yc1tkZWYudHlwZV07CiAgICAgIGlmICghcHJvY2Vzc29yKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbdG9KU09OU2NoZW1hXTogTm9uLXJlcHJlc2VudGFibGUgdHlwZSBlbmNvdW50ZXJlZDogJHtkZWYudHlwZX1gKTsKICAgICAgfQogICAgICBwcm9jZXNzb3Ioc2NoZW1hLCBjdHgsIF9qc29uLCBwYXJhbXMpOwogICAgfQogICAgY29uc3QgcGFyZW50ID0gc2NoZW1hLl96b2QucGFyZW50OwogICAgaWYgKHBhcmVudCkgewogICAgICBpZiAoIXJlc3VsdC5yZWYpCiAgICAgICAgcmVzdWx0LnJlZiA9IHBhcmVudDsKICAgICAgcHJvY2VzczIocGFyZW50LCBjdHgsIHBhcmFtcyk7CiAgICAgIGN0eC5zZWVuLmdldChwYXJlbnQpLmlzUGFyZW50ID0gdHJ1ZTsKICAgIH0KICB9CiAgY29uc3QgbWV0YTIgPSBjdHgubWV0YWRhdGFSZWdpc3RyeS5nZXQoc2NoZW1hKTsKICBpZiAobWV0YTIpCiAgICBPYmplY3QuYXNzaWduKHJlc3VsdC5zY2hlbWEsIG1ldGEyKTsKICBpZiAoY3R4LmlvID09PSAiaW5wdXQiICYmIGlzVHJhbnNmb3JtaW5nKHNjaGVtYSkpIHsKICAgIGRlbGV0ZSByZXN1bHQuc2NoZW1hLmV4YW1wbGVzOwogICAgZGVsZXRlIHJlc3VsdC5zY2hlbWEuZGVmYXVsdDsKICB9CiAgaWYgKGN0eC5pbyA9PT0gImlucHV0IiAmJiAiX3ByZWZhdWx0IiBpbiByZXN1bHQuc2NoZW1hKQogICAgKF9hMyA9IHJlc3VsdC5zY2hlbWEpLmRlZmF1bHQgPz8gKF9hMy5kZWZhdWx0ID0gcmVzdWx0LnNjaGVtYS5fcHJlZmF1bHQpOwogIGRlbGV0ZSByZXN1bHQuc2NoZW1hLl9wcmVmYXVsdDsKICBjb25zdCBfcmVzdWx0ID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgcmV0dXJuIF9yZXN1bHQuc2NoZW1hOwp9CmZ1bmN0aW9uIGV4dHJhY3REZWZzKGN0eCwgc2NoZW1hKSB7CiAgY29uc3Qgcm9vdCA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIGlmICghcm9vdCkKICAgIHRocm93IG5ldyBFcnJvcigiVW5wcm9jZXNzZWQgc2NoZW1hLiBUaGlzIGlzIGEgYnVnIGluIFpvZC4iKTsKICBjb25zdCBpZFRvU2NoZW1hID0gLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKTsKICBmb3IgKGNvbnN0IGVudHJ5IG9mIGN0eC5zZWVuLmVudHJpZXMoKSkgewogICAgY29uc3QgaWQgPSBjdHgubWV0YWRhdGFSZWdpc3RyeS5nZXQoZW50cnlbMF0pPy5pZDsKICAgIGlmIChpZCkgewogICAgICBjb25zdCBleGlzdGluZyA9IGlkVG9TY2hlbWEuZ2V0KGlkKTsKICAgICAgaWYgKGV4aXN0aW5nICYmIGV4aXN0aW5nICE9PSBlbnRyeVswXSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgRHVwbGljYXRlIHNjaGVtYSBpZCAiJHtpZH0iIGRldGVjdGVkIGR1cmluZyBKU09OIFNjaGVtYSBjb252ZXJzaW9uLiBUd28gZGlmZmVyZW50IHNjaGVtYXMgY2Fubm90IHNoYXJlIHRoZSBzYW1lIGlkIHdoZW4gY29udmVydGVkIHRvZ2V0aGVyLmApOwogICAgICB9CiAgICAgIGlkVG9TY2hlbWEuc2V0KGlkLCBlbnRyeVswXSk7CiAgICB9CiAgfQogIGNvbnN0IG1ha2VVUkkgPSAoZW50cnkpID0+IHsKICAgIGNvbnN0IGRlZnNTZWdtZW50ID0gY3R4LnRhcmdldCA9PT0gImRyYWZ0LTIwMjAtMTIiID8gIiRkZWZzIiA6ICJkZWZpbml0aW9ucyI7CiAgICBpZiAoY3R4LmV4dGVybmFsKSB7CiAgICAgIGNvbnN0IGV4dGVybmFsSWQgPSBjdHguZXh0ZXJuYWwucmVnaXN0cnkuZ2V0KGVudHJ5WzBdKT8uaWQ7CiAgICAgIGNvbnN0IHVyaUdlbmVyYXRvciA9IGN0eC5leHRlcm5hbC51cmkgPz8gKChpZDIpID0+IGlkMik7CiAgICAgIGlmIChleHRlcm5hbElkKSB7CiAgICAgICAgcmV0dXJuIHsgcmVmOiB1cmlHZW5lcmF0b3IoZXh0ZXJuYWxJZCkgfTsKICAgICAgfQogICAgICBjb25zdCBpZCA9IGVudHJ5WzFdLmRlZklkID8/IGVudHJ5WzFdLnNjaGVtYS5pZCA/PyBgc2NoZW1hJHtjdHguY291bnRlcisrfWA7CiAgICAgIGVudHJ5WzFdLmRlZklkID0gaWQ7CiAgICAgIHJldHVybiB7IGRlZklkOiBpZCwgcmVmOiBgJHt1cmlHZW5lcmF0b3IoIl9fc2hhcmVkIil9Iy8ke2RlZnNTZWdtZW50fS8ke2lkfWAgfTsKICAgIH0KICAgIGlmIChlbnRyeVsxXSA9PT0gcm9vdCkgewogICAgICByZXR1cm4geyByZWY6ICIjIiB9OwogICAgfQogICAgY29uc3QgdXJpUHJlZml4ID0gYCNgOwogICAgY29uc3QgZGVmVXJpUHJlZml4ID0gYCR7dXJpUHJlZml4fS8ke2RlZnNTZWdtZW50fS9gOwogICAgY29uc3QgZGVmSWQgPSBlbnRyeVsxXS5zY2hlbWEuaWQgPz8gYF9fc2NoZW1hJHtjdHguY291bnRlcisrfWA7CiAgICByZXR1cm4geyBkZWZJZCwgcmVmOiBkZWZVcmlQcmVmaXggKyBkZWZJZCB9OwogIH07CiAgY29uc3QgZXh0cmFjdFRvRGVmID0gKGVudHJ5KSA9PiB7CiAgICBpZiAoZW50cnlbMV0uc2NoZW1hLiRyZWYpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3Qgc2VlbiA9IGVudHJ5WzFdOwogICAgY29uc3QgeyByZWYsIGRlZklkIH0gPSBtYWtlVVJJKGVudHJ5KTsKICAgIHNlZW4uZGVmID0geyAuLi5zZWVuLnNjaGVtYSB9OwogICAgaWYgKGRlZklkKQogICAgICBzZWVuLmRlZklkID0gZGVmSWQ7CiAgICBjb25zdCBzY2hlbWEyID0gc2Vlbi5zY2hlbWE7CiAgICBmb3IgKGNvbnN0IGtleSBpbiBzY2hlbWEyKSB7CiAgICAgIGRlbGV0ZSBzY2hlbWEyW2tleV07CiAgICB9CiAgICBzY2hlbWEyLiRyZWYgPSByZWY7CiAgfTsKICBpZiAoY3R4LmN5Y2xlcyA9PT0gInRocm93IikgewogICAgZm9yIChjb25zdCBlbnRyeSBvZiBjdHguc2Vlbi5lbnRyaWVzKCkpIHsKICAgICAgY29uc3Qgc2VlbiA9IGVudHJ5WzFdOwogICAgICBpZiAoc2Vlbi5jeWNsZSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgQ3ljbGUgZGV0ZWN0ZWQ6ICMvJHtzZWVuLmN5Y2xlPy5qb2luKCIvIil9Lzxyb290PgoKU2V0IHRoZSBcYGN5Y2xlc1xgIHBhcmFtZXRlciB0byBcYCJyZWYiXGAgdG8gcmVzb2x2ZSBjeWNsaWNhbCBzY2hlbWFzIHdpdGggZGVmcy5gKTsKICAgICAgfQogICAgfQogIH0KICBmb3IgKGNvbnN0IGVudHJ5IG9mIGN0eC5zZWVuLmVudHJpZXMoKSkgewogICAgY29uc3Qgc2VlbiA9IGVudHJ5WzFdOwogICAgaWYgKHNjaGVtYSA9PT0gZW50cnlbMF0pIHsKICAgICAgZXh0cmFjdFRvRGVmKGVudHJ5KTsKICAgICAgY29udGludWU7CiAgICB9CiAgICBpZiAoY3R4LmV4dGVybmFsKSB7CiAgICAgIGNvbnN0IGV4dCA9IGN0eC5leHRlcm5hbC5yZWdpc3RyeS5nZXQoZW50cnlbMF0pPy5pZDsKICAgICAgaWYgKHNjaGVtYSAhPT0gZW50cnlbMF0gJiYgZXh0KSB7CiAgICAgICAgZXh0cmFjdFRvRGVmKGVudHJ5KTsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgfQogICAgY29uc3QgaWQgPSBjdHgubWV0YWRhdGFSZWdpc3RyeS5nZXQoZW50cnlbMF0pPy5pZDsKICAgIGlmIChpZCkgewogICAgICBleHRyYWN0VG9EZWYoZW50cnkpOwogICAgICBjb250aW51ZTsKICAgIH0KICAgIGlmIChzZWVuLmN5Y2xlKSB7CiAgICAgIGV4dHJhY3RUb0RlZihlbnRyeSk7CiAgICAgIGNvbnRpbnVlOwogICAgfQogICAgaWYgKHNlZW4uY291bnQgPiAxKSB7CiAgICAgIGlmIChjdHgucmV1c2VkID09PSAicmVmIikgewogICAgICAgIGV4dHJhY3RUb0RlZihlbnRyeSk7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgIH0KICB9Cn0KZnVuY3Rpb24gZmluYWxpemUoY3R4LCBzY2hlbWEpIHsKICBjb25zdCByb290ID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgaWYgKCFyb290KQogICAgdGhyb3cgbmV3IEVycm9yKCJVbnByb2Nlc3NlZCBzY2hlbWEuIFRoaXMgaXMgYSBidWcgaW4gWm9kLiIpOwogIGNvbnN0IGZsYXR0ZW5SZWYgPSAoem9kU2NoZW1hKSA9PiB7CiAgICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHpvZFNjaGVtYSk7CiAgICBpZiAoc2Vlbi5yZWYgPT09IG51bGwpCiAgICAgIHJldHVybjsKICAgIGNvbnN0IHNjaGVtYTIgPSBzZWVuLmRlZiA/PyBzZWVuLnNjaGVtYTsKICAgIGNvbnN0IF9jYWNoZWQgPSB7IC4uLnNjaGVtYTIgfTsKICAgIGNvbnN0IHJlZiA9IHNlZW4ucmVmOwogICAgc2Vlbi5yZWYgPSBudWxsOwogICAgaWYgKHJlZikgewogICAgICBmbGF0dGVuUmVmKHJlZik7CiAgICAgIGNvbnN0IHJlZlNlZW4gPSBjdHguc2Vlbi5nZXQocmVmKTsKICAgICAgY29uc3QgcmVmU2NoZW1hID0gcmVmU2Vlbi5zY2hlbWE7CiAgICAgIGlmIChyZWZTY2hlbWEuJHJlZiAmJiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA3IiB8fCBjdHgudGFyZ2V0ID09PSAiZHJhZnQtMDQiIHx8IGN0eC50YXJnZXQgPT09ICJvcGVuYXBpLTMuMCIpKSB7CiAgICAgICAgc2NoZW1hMi5hbGxPZiA9IHNjaGVtYTIuYWxsT2YgPz8gW107CiAgICAgICAgc2NoZW1hMi5hbGxPZi5wdXNoKHJlZlNjaGVtYSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgT2JqZWN0LmFzc2lnbihzY2hlbWEyLCByZWZTY2hlbWEpOwogICAgICB9CiAgICAgIE9iamVjdC5hc3NpZ24oc2NoZW1hMiwgX2NhY2hlZCk7CiAgICAgIGNvbnN0IGlzUGFyZW50UmVmID0gem9kU2NoZW1hLl96b2QucGFyZW50ID09PSByZWY7CiAgICAgIGlmIChpc1BhcmVudFJlZikgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIHNjaGVtYTIpIHsKICAgICAgICAgIGlmIChrZXkgPT09ICIkcmVmIiB8fCBrZXkgPT09ICJhbGxPZiIpCiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgaWYgKCEoa2V5IGluIF9jYWNoZWQpKSB7CiAgICAgICAgICAgIGRlbGV0ZSBzY2hlbWEyW2tleV07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmIChyZWZTY2hlbWEuJHJlZiAmJiByZWZTZWVuLmRlZikgewogICAgICAgIGZvciAoY29uc3Qga2V5IGluIHNjaGVtYTIpIHsKICAgICAgICAgIGlmIChrZXkgPT09ICIkcmVmIiB8fCBrZXkgPT09ICJhbGxPZiIpCiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgaWYgKGtleSBpbiByZWZTZWVuLmRlZiAmJiBKU09OLnN0cmluZ2lmeShzY2hlbWEyW2tleV0pID09PSBKU09OLnN0cmluZ2lmeShyZWZTZWVuLmRlZltrZXldKSkgewogICAgICAgICAgICBkZWxldGUgc2NoZW1hMltrZXldOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgY29uc3QgcGFyZW50ID0gem9kU2NoZW1hLl96b2QucGFyZW50OwogICAgaWYgKHBhcmVudCAmJiBwYXJlbnQgIT09IHJlZikgewogICAgICBmbGF0dGVuUmVmKHBhcmVudCk7CiAgICAgIGNvbnN0IHBhcmVudFNlZW4gPSBjdHguc2Vlbi5nZXQocGFyZW50KTsKICAgICAgaWYgKHBhcmVudFNlZW4/LnNjaGVtYS4kcmVmKSB7CiAgICAgICAgc2NoZW1hMi4kcmVmID0gcGFyZW50U2Vlbi5zY2hlbWEuJHJlZjsKICAgICAgICBpZiAocGFyZW50U2Vlbi5kZWYpIHsKICAgICAgICAgIGZvciAoY29uc3Qga2V5IGluIHNjaGVtYTIpIHsKICAgICAgICAgICAgaWYgKGtleSA9PT0gIiRyZWYiIHx8IGtleSA9PT0gImFsbE9mIikKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgaWYgKGtleSBpbiBwYXJlbnRTZWVuLmRlZiAmJiBKU09OLnN0cmluZ2lmeShzY2hlbWEyW2tleV0pID09PSBKU09OLnN0cmluZ2lmeShwYXJlbnRTZWVuLmRlZltrZXldKSkgewogICAgICAgICAgICAgIGRlbGV0ZSBzY2hlbWEyW2tleV07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGN0eC5vdmVycmlkZSh7CiAgICAgIHpvZFNjaGVtYSwKICAgICAganNvblNjaGVtYTogc2NoZW1hMiwKICAgICAgcGF0aDogc2Vlbi5wYXRoID8/IFtdCiAgICB9KTsKICB9OwogIGZvciAoY29uc3QgZW50cnkgb2YgWy4uLmN0eC5zZWVuLmVudHJpZXMoKV0ucmV2ZXJzZSgpKSB7CiAgICBmbGF0dGVuUmVmKGVudHJ5WzBdKTsKICB9CiAgY29uc3QgcmVzdWx0ID0ge307CiAgaWYgKGN0eC50YXJnZXQgPT09ICJkcmFmdC0yMDIwLTEyIikgewogICAgcmVzdWx0LiRzY2hlbWEgPSAiaHR0cHM6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQvMjAyMC0xMi9zY2hlbWEiOwogIH0gZWxzZSBpZiAoY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA3IikgewogICAgcmVzdWx0LiRzY2hlbWEgPSAiaHR0cDovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC0wNy9zY2hlbWEjIjsKICB9IGVsc2UgaWYgKGN0eC50YXJnZXQgPT09ICJkcmFmdC0wNCIpIHsKICAgIHJlc3VsdC4kc2NoZW1hID0gImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDQvc2NoZW1hIyI7CiAgfSBlbHNlIGlmIChjdHgudGFyZ2V0ID09PSAib3BlbmFwaS0zLjAiKSB7CiAgfSBlbHNlIHsKICB9CiAgaWYgKGN0eC5leHRlcm5hbD8udXJpKSB7CiAgICBjb25zdCBpZCA9IGN0eC5leHRlcm5hbC5yZWdpc3RyeS5nZXQoc2NoZW1hKT8uaWQ7CiAgICBpZiAoIWlkKQogICAgICB0aHJvdyBuZXcgRXJyb3IoIlNjaGVtYSBpcyBtaXNzaW5nIGFuIGBpZGAgcHJvcGVydHkiKTsKICAgIHJlc3VsdC4kaWQgPSBjdHguZXh0ZXJuYWwudXJpKGlkKTsKICB9CiAgT2JqZWN0LmFzc2lnbihyZXN1bHQsIHJvb3QuZGVmID8/IHJvb3Quc2NoZW1hKTsKICBjb25zdCByb290TWV0YUlkID0gY3R4Lm1ldGFkYXRhUmVnaXN0cnkuZ2V0KHNjaGVtYSk/LmlkOwogIGlmIChyb290TWV0YUlkICE9PSB2b2lkIDAgJiYgcmVzdWx0LmlkID09PSByb290TWV0YUlkKQogICAgZGVsZXRlIHJlc3VsdC5pZDsKICBjb25zdCBkZWZzID0gY3R4LmV4dGVybmFsPy5kZWZzID8/IHt9OwogIGZvciAoY29uc3QgZW50cnkgb2YgY3R4LnNlZW4uZW50cmllcygpKSB7CiAgICBjb25zdCBzZWVuID0gZW50cnlbMV07CiAgICBpZiAoc2Vlbi5kZWYgJiYgc2Vlbi5kZWZJZCkgewogICAgICBpZiAoc2Vlbi5kZWYuaWQgPT09IHNlZW4uZGVmSWQpCiAgICAgICAgZGVsZXRlIHNlZW4uZGVmLmlkOwogICAgICBkZWZzW3NlZW4uZGVmSWRdID0gc2Vlbi5kZWY7CiAgICB9CiAgfQogIGlmIChjdHguZXh0ZXJuYWwpIHsKICB9IGVsc2UgewogICAgaWYgKE9iamVjdC5rZXlzKGRlZnMpLmxlbmd0aCA+IDApIHsKICAgICAgaWYgKGN0eC50YXJnZXQgPT09ICJkcmFmdC0yMDIwLTEyIikgewogICAgICAgIHJlc3VsdC4kZGVmcyA9IGRlZnM7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmVzdWx0LmRlZmluaXRpb25zID0gZGVmczsKICAgICAgfQogICAgfQogIH0KICB0cnkgewogICAgY29uc3QgZmluYWxpemVkID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShyZXN1bHQpKTsKICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShmaW5hbGl6ZWQsICJ+c3RhbmRhcmQiLCB7CiAgICAgIHZhbHVlOiB7CiAgICAgICAgLi4uc2NoZW1hWyJ+c3RhbmRhcmQiXSwKICAgICAgICBqc29uU2NoZW1hOiB7CiAgICAgICAgICBpbnB1dDogY3JlYXRlU3RhbmRhcmRKU09OU2NoZW1hTWV0aG9kKHNjaGVtYSwgImlucHV0IiwgY3R4LnByb2Nlc3NvcnMpLAogICAgICAgICAgb3V0cHV0OiBjcmVhdGVTdGFuZGFyZEpTT05TY2hlbWFNZXRob2Qoc2NoZW1hLCAib3V0cHV0IiwgY3R4LnByb2Nlc3NvcnMpCiAgICAgICAgfQogICAgICB9LAogICAgICBlbnVtZXJhYmxlOiBmYWxzZSwKICAgICAgd3JpdGFibGU6IGZhbHNlCiAgICB9KTsKICAgIHJldHVybiBmaW5hbGl6ZWQ7CiAgfSBjYXRjaCAoX2VycikgewogICAgdGhyb3cgbmV3IEVycm9yKCJFcnJvciBjb252ZXJ0aW5nIHNjaGVtYSB0byBKU09OLiIpOwogIH0KfQpmdW5jdGlvbiBpc1RyYW5zZm9ybWluZyhfc2NoZW1hLCBfY3R4KSB7CiAgY29uc3QgY3R4ID0gX2N0eCA/PyB7IHNlZW46IC8qIEBfX1BVUkVfXyAqLyBuZXcgU2V0KCkgfTsKICBpZiAoY3R4LnNlZW4uaGFzKF9zY2hlbWEpKQogICAgcmV0dXJuIGZhbHNlOwogIGN0eC5zZWVuLmFkZChfc2NoZW1hKTsKICBjb25zdCBkZWYgPSBfc2NoZW1hLl96b2QuZGVmOwogIGlmIChkZWYudHlwZSA9PT0gInRyYW5zZm9ybSIpCiAgICByZXR1cm4gdHJ1ZTsKICBpZiAoZGVmLnR5cGUgPT09ICJhcnJheSIpCiAgICByZXR1cm4gaXNUcmFuc2Zvcm1pbmcoZGVmLmVsZW1lbnQsIGN0eCk7CiAgaWYgKGRlZi50eXBlID09PSAic2V0IikKICAgIHJldHVybiBpc1RyYW5zZm9ybWluZyhkZWYudmFsdWVUeXBlLCBjdHgpOwogIGlmIChkZWYudHlwZSA9PT0gImxhenkiKQogICAgcmV0dXJuIGlzVHJhbnNmb3JtaW5nKGRlZi5nZXR0ZXIoKSwgY3R4KTsKICBpZiAoZGVmLnR5cGUgPT09ICJwcm9taXNlIiB8fCBkZWYudHlwZSA9PT0gIm9wdGlvbmFsIiB8fCBkZWYudHlwZSA9PT0gIm5vbm9wdGlvbmFsIiB8fCBkZWYudHlwZSA9PT0gIm51bGxhYmxlIiB8fCBkZWYudHlwZSA9PT0gInJlYWRvbmx5IiB8fCBkZWYudHlwZSA9PT0gImRlZmF1bHQiIHx8IGRlZi50eXBlID09PSAicHJlZmF1bHQiKSB7CiAgICByZXR1cm4gaXNUcmFuc2Zvcm1pbmcoZGVmLmlubmVyVHlwZSwgY3R4KTsKICB9CiAgaWYgKGRlZi50eXBlID09PSAiaW50ZXJzZWN0aW9uIikgewogICAgcmV0dXJuIGlzVHJhbnNmb3JtaW5nKGRlZi5sZWZ0LCBjdHgpIHx8IGlzVHJhbnNmb3JtaW5nKGRlZi5yaWdodCwgY3R4KTsKICB9CiAgaWYgKGRlZi50eXBlID09PSAicmVjb3JkIiB8fCBkZWYudHlwZSA9PT0gIm1hcCIpIHsKICAgIHJldHVybiBpc1RyYW5zZm9ybWluZyhkZWYua2V5VHlwZSwgY3R4KSB8fCBpc1RyYW5zZm9ybWluZyhkZWYudmFsdWVUeXBlLCBjdHgpOwogIH0KICBpZiAoZGVmLnR5cGUgPT09ICJwaXBlIikgewogICAgaWYgKF9zY2hlbWEuX3pvZC50cmFpdHMuaGFzKCIkWm9kQ29kZWMiKSkKICAgICAgcmV0dXJuIHRydWU7CiAgICByZXR1cm4gaXNUcmFuc2Zvcm1pbmcoZGVmLmluLCBjdHgpIHx8IGlzVHJhbnNmb3JtaW5nKGRlZi5vdXQsIGN0eCk7CiAgfQogIGlmIChkZWYudHlwZSA9PT0gIm9iamVjdCIpIHsKICAgIGZvciAoY29uc3Qga2V5IGluIGRlZi5zaGFwZSkgewogICAgICBpZiAoaXNUcmFuc2Zvcm1pbmcoZGVmLnNoYXBlW2tleV0sIGN0eCkpCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICByZXR1cm4gZmFsc2U7CiAgfQogIGlmIChkZWYudHlwZSA9PT0gInVuaW9uIikgewogICAgZm9yIChjb25zdCBvcHRpb24gb2YgZGVmLm9wdGlvbnMpIHsKICAgICAgaWYgKGlzVHJhbnNmb3JtaW5nKG9wdGlvbiwgY3R4KSkKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CiAgaWYgKGRlZi50eXBlID09PSAidHVwbGUiKSB7CiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgZGVmLml0ZW1zKSB7CiAgICAgIGlmIChpc1RyYW5zZm9ybWluZyhpdGVtLCBjdHgpKQogICAgICAgIHJldHVybiB0cnVlOwogICAgfQogICAgaWYgKGRlZi5yZXN0ICYmIGlzVHJhbnNmb3JtaW5nKGRlZi5yZXN0LCBjdHgpKQogICAgICByZXR1cm4gdHJ1ZTsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIGZhbHNlOwp9CnZhciBjcmVhdGVUb0pTT05TY2hlbWFNZXRob2QgPSAoc2NoZW1hLCBwcm9jZXNzb3JzID0ge30pID0+IChwYXJhbXMpID0+IHsKICBjb25zdCBjdHggPSBpbml0aWFsaXplQ29udGV4dCh7IC4uLnBhcmFtcywgcHJvY2Vzc29ycyB9KTsKICBwcm9jZXNzMihzY2hlbWEsIGN0eCk7CiAgZXh0cmFjdERlZnMoY3R4LCBzY2hlbWEpOwogIHJldHVybiBmaW5hbGl6ZShjdHgsIHNjaGVtYSk7Cn07CnZhciBjcmVhdGVTdGFuZGFyZEpTT05TY2hlbWFNZXRob2QgPSAoc2NoZW1hLCBpbywgcHJvY2Vzc29ycyA9IHt9KSA9PiAocGFyYW1zKSA9PiB7CiAgY29uc3QgeyBsaWJyYXJ5T3B0aW9ucywgdGFyZ2V0IH0gPSBwYXJhbXMgPz8ge307CiAgY29uc3QgY3R4ID0gaW5pdGlhbGl6ZUNvbnRleHQoeyAuLi5saWJyYXJ5T3B0aW9ucyA/PyB7fSwgdGFyZ2V0LCBpbywgcHJvY2Vzc29ycyB9KTsKICBwcm9jZXNzMihzY2hlbWEsIGN0eCk7CiAgZXh0cmFjdERlZnMoY3R4LCBzY2hlbWEpOwogIHJldHVybiBmaW5hbGl6ZShjdHgsIHNjaGVtYSk7Cn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NvcmUvanNvbi1zY2hlbWEtcHJvY2Vzc29ycy5qcwp2YXIgZm9ybWF0TWFwID0gewogIGd1aWQ6ICJ1dWlkIiwKICB1cmw6ICJ1cmkiLAogIGRhdGV0aW1lOiAiZGF0ZS10aW1lIiwKICBqc29uX3N0cmluZzogImpzb24tc3RyaW5nIiwKICByZWdleDogIiIKICAvLyBkbyBub3Qgc2V0Cn07CnZhciBzdHJpbmdQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIF9qc29uLCBfcGFyYW1zKSA9PiB7CiAgY29uc3QganNvbiA9IF9qc29uOwogIGpzb24udHlwZSA9ICJzdHJpbmciOwogIGNvbnN0IHsgbWluaW11bSwgbWF4aW11bSwgZm9ybWF0LCBwYXR0ZXJucywgY29udGVudEVuY29kaW5nIH0gPSBzY2hlbWEuX3pvZC5iYWc7CiAgaWYgKHR5cGVvZiBtaW5pbXVtID09PSAibnVtYmVyIikKICAgIGpzb24ubWluTGVuZ3RoID0gbWluaW11bTsKICBpZiAodHlwZW9mIG1heGltdW0gPT09ICJudW1iZXIiKQogICAganNvbi5tYXhMZW5ndGggPSBtYXhpbXVtOwogIGlmIChmb3JtYXQpIHsKICAgIGpzb24uZm9ybWF0ID0gZm9ybWF0TWFwW2Zvcm1hdF0gPz8gZm9ybWF0OwogICAgaWYgKGpzb24uZm9ybWF0ID09PSAiIikKICAgICAgZGVsZXRlIGpzb24uZm9ybWF0OwogICAgaWYgKGZvcm1hdCA9PT0gInRpbWUiKSB7CiAgICAgIGRlbGV0ZSBqc29uLmZvcm1hdDsKICAgIH0KICB9CiAgaWYgKGNvbnRlbnRFbmNvZGluZykKICAgIGpzb24uY29udGVudEVuY29kaW5nID0gY29udGVudEVuY29kaW5nOwogIGlmIChwYXR0ZXJucyAmJiBwYXR0ZXJucy5zaXplID4gMCkgewogICAgY29uc3QgcmVnZXhlcyA9IFsuLi5wYXR0ZXJuc107CiAgICBpZiAocmVnZXhlcy5sZW5ndGggPT09IDEpCiAgICAgIGpzb24ucGF0dGVybiA9IHJlZ2V4ZXNbMF0uc291cmNlOwogICAgZWxzZSBpZiAocmVnZXhlcy5sZW5ndGggPiAxKSB7CiAgICAgIGpzb24uYWxsT2YgPSBbCiAgICAgICAgLi4ucmVnZXhlcy5tYXAoKHJlZ2V4KSA9PiAoewogICAgICAgICAgLi4uY3R4LnRhcmdldCA9PT0gImRyYWZ0LTA3IiB8fCBjdHgudGFyZ2V0ID09PSAiZHJhZnQtMDQiIHx8IGN0eC50YXJnZXQgPT09ICJvcGVuYXBpLTMuMCIgPyB7IHR5cGU6ICJzdHJpbmciIH0gOiB7fSwKICAgICAgICAgIHBhdHRlcm46IHJlZ2V4LnNvdXJjZQogICAgICAgIH0pKQogICAgICBdOwogICAgfQogIH0KfTsKdmFyIG51bWJlclByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwgX2pzb24sIF9wYXJhbXMpID0+IHsKICBjb25zdCBqc29uID0gX2pzb247CiAgY29uc3QgeyBtaW5pbXVtLCBtYXhpbXVtLCBmb3JtYXQsIG11bHRpcGxlT2YsIGV4Y2x1c2l2ZU1heGltdW0sIGV4Y2x1c2l2ZU1pbmltdW0gfSA9IHNjaGVtYS5fem9kLmJhZzsKICBpZiAodHlwZW9mIGZvcm1hdCA9PT0gInN0cmluZyIgJiYgZm9ybWF0LmluY2x1ZGVzKCJpbnQiKSkKICAgIGpzb24udHlwZSA9ICJpbnRlZ2VyIjsKICBlbHNlCiAgICBqc29uLnR5cGUgPSAibnVtYmVyIjsKICBjb25zdCBleE1pbiA9IHR5cGVvZiBleGNsdXNpdmVNaW5pbXVtID09PSAibnVtYmVyIiAmJiBleGNsdXNpdmVNaW5pbXVtID49IChtaW5pbXVtID8/IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSk7CiAgY29uc3QgZXhNYXggPSB0eXBlb2YgZXhjbHVzaXZlTWF4aW11bSA9PT0gIm51bWJlciIgJiYgZXhjbHVzaXZlTWF4aW11bSA8PSAobWF4aW11bSA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpOwogIGNvbnN0IGxlZ2FjeSA9IGN0eC50YXJnZXQgPT09ICJkcmFmdC0wNCIgfHwgY3R4LnRhcmdldCA9PT0gIm9wZW5hcGktMy4wIjsKICBpZiAoZXhNaW4pIHsKICAgIGlmIChsZWdhY3kpIHsKICAgICAganNvbi5taW5pbXVtID0gZXhjbHVzaXZlTWluaW11bTsKICAgICAganNvbi5leGNsdXNpdmVNaW5pbXVtID0gdHJ1ZTsKICAgIH0gZWxzZSB7CiAgICAgIGpzb24uZXhjbHVzaXZlTWluaW11bSA9IGV4Y2x1c2l2ZU1pbmltdW07CiAgICB9CiAgfSBlbHNlIGlmICh0eXBlb2YgbWluaW11bSA9PT0gIm51bWJlciIpIHsKICAgIGpzb24ubWluaW11bSA9IG1pbmltdW07CiAgfQogIGlmIChleE1heCkgewogICAgaWYgKGxlZ2FjeSkgewogICAgICBqc29uLm1heGltdW0gPSBleGNsdXNpdmVNYXhpbXVtOwogICAgICBqc29uLmV4Y2x1c2l2ZU1heGltdW0gPSB0cnVlOwogICAgfSBlbHNlIHsKICAgICAganNvbi5leGNsdXNpdmVNYXhpbXVtID0gZXhjbHVzaXZlTWF4aW11bTsKICAgIH0KICB9IGVsc2UgaWYgKHR5cGVvZiBtYXhpbXVtID09PSAibnVtYmVyIikgewogICAganNvbi5tYXhpbXVtID0gbWF4aW11bTsKICB9CiAgaWYgKHR5cGVvZiBtdWx0aXBsZU9mID09PSAibnVtYmVyIikKICAgIGpzb24ubXVsdGlwbGVPZiA9IG11bHRpcGxlT2Y7Cn07CnZhciBib29sZWFuUHJvY2Vzc29yID0gKF9zY2hlbWEsIF9jdHgsIGpzb24sIF9wYXJhbXMpID0+IHsKICBqc29uLnR5cGUgPSAiYm9vbGVhbiI7Cn07CnZhciBuZXZlclByb2Nlc3NvciA9IChfc2NoZW1hLCBfY3R4LCBqc29uLCBfcGFyYW1zKSA9PiB7CiAganNvbi5ub3QgPSB7fTsKfTsKdmFyIHVua25vd25Qcm9jZXNzb3IgPSAoX3NjaGVtYSwgX2N0eCwgX2pzb24sIF9wYXJhbXMpID0+IHsKfTsKdmFyIGVudW1Qcm9jZXNzb3IgPSAoc2NoZW1hLCBfY3R4LCBqc29uLCBfcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IHZhbHVlcyA9IGdldEVudW1WYWx1ZXMoZGVmLmVudHJpZXMpOwogIGlmICh2YWx1ZXMuZXZlcnkoKHYpID0+IHR5cGVvZiB2ID09PSAibnVtYmVyIikpCiAgICBqc29uLnR5cGUgPSAibnVtYmVyIjsKICBpZiAodmFsdWVzLmV2ZXJ5KCh2KSA9PiB0eXBlb2YgdiA9PT0gInN0cmluZyIpKQogICAganNvbi50eXBlID0gInN0cmluZyI7CiAganNvbi5lbnVtID0gdmFsdWVzOwp9Owp2YXIgY3VzdG9tUHJvY2Vzc29yID0gKF9zY2hlbWEsIGN0eCwgX2pzb24sIF9wYXJhbXMpID0+IHsKICBpZiAoY3R4LnVucmVwcmVzZW50YWJsZSA9PT0gInRocm93IikgewogICAgdGhyb3cgbmV3IEVycm9yKCJDdXN0b20gdHlwZXMgY2Fubm90IGJlIHJlcHJlc2VudGVkIGluIEpTT04gU2NoZW1hIik7CiAgfQp9Owp2YXIgdHJhbnNmb3JtUHJvY2Vzc29yID0gKF9zY2hlbWEsIGN0eCwgX2pzb24sIF9wYXJhbXMpID0+IHsKICBpZiAoY3R4LnVucmVwcmVzZW50YWJsZSA9PT0gInRocm93IikgewogICAgdGhyb3cgbmV3IEVycm9yKCJUcmFuc2Zvcm1zIGNhbm5vdCBiZSByZXByZXNlbnRlZCBpbiBKU09OIFNjaGVtYSIpOwogIH0KfTsKdmFyIGFycmF5UHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QganNvbiA9IF9qc29uOwogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBjb25zdCB7IG1pbmltdW0sIG1heGltdW0gfSA9IHNjaGVtYS5fem9kLmJhZzsKICBpZiAodHlwZW9mIG1pbmltdW0gPT09ICJudW1iZXIiKQogICAganNvbi5taW5JdGVtcyA9IG1pbmltdW07CiAgaWYgKHR5cGVvZiBtYXhpbXVtID09PSAibnVtYmVyIikKICAgIGpzb24ubWF4SXRlbXMgPSBtYXhpbXVtOwogIGpzb24udHlwZSA9ICJhcnJheSI7CiAganNvbi5pdGVtcyA9IHByb2Nlc3MyKGRlZi5lbGVtZW50LCBjdHgsIHsKICAgIC4uLnBhcmFtcywKICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgIml0ZW1zIl0KICB9KTsKfTsKdmFyIG9iamVjdFByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwgX2pzb24sIHBhcmFtcykgPT4gewogIGNvbnN0IGpzb24gPSBfanNvbjsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAganNvbi50eXBlID0gIm9iamVjdCI7CiAganNvbi5wcm9wZXJ0aWVzID0ge307CiAgY29uc3Qgc2hhcGUgPSBkZWYuc2hhcGU7CiAgZm9yIChjb25zdCBrZXkgaW4gc2hhcGUpIHsKICAgIGpzb24ucHJvcGVydGllc1trZXldID0gcHJvY2VzczIoc2hhcGVba2V5XSwgY3R4LCB7CiAgICAgIC4uLnBhcmFtcywKICAgICAgcGF0aDogWy4uLnBhcmFtcy5wYXRoLCAicHJvcGVydGllcyIsIGtleV0KICAgIH0pOwogIH0KICBjb25zdCBhbGxLZXlzID0gbmV3IFNldChPYmplY3Qua2V5cyhzaGFwZSkpOwogIGNvbnN0IHJlcXVpcmVkS2V5cyA9IG5ldyBTZXQoWy4uLmFsbEtleXNdLmZpbHRlcigoa2V5KSA9PiB7CiAgICBjb25zdCB2ID0gZGVmLnNoYXBlW2tleV0uX3pvZDsKICAgIGlmIChjdHguaW8gPT09ICJpbnB1dCIpIHsKICAgICAgcmV0dXJuIHYub3B0aW4gPT09IHZvaWQgMDsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiB2Lm9wdG91dCA9PT0gdm9pZCAwOwogICAgfQogIH0pKTsKICBpZiAocmVxdWlyZWRLZXlzLnNpemUgPiAwKSB7CiAgICBqc29uLnJlcXVpcmVkID0gQXJyYXkuZnJvbShyZXF1aXJlZEtleXMpOwogIH0KICBpZiAoZGVmLmNhdGNoYWxsPy5fem9kLmRlZi50eXBlID09PSAibmV2ZXIiKSB7CiAgICBqc29uLmFkZGl0aW9uYWxQcm9wZXJ0aWVzID0gZmFsc2U7CiAgfSBlbHNlIGlmICghZGVmLmNhdGNoYWxsKSB7CiAgICBpZiAoY3R4LmlvID09PSAib3V0cHV0IikKICAgICAganNvbi5hZGRpdGlvbmFsUHJvcGVydGllcyA9IGZhbHNlOwogIH0gZWxzZSBpZiAoZGVmLmNhdGNoYWxsKSB7CiAgICBqc29uLmFkZGl0aW9uYWxQcm9wZXJ0aWVzID0gcHJvY2VzczIoZGVmLmNhdGNoYWxsLCBjdHgsIHsKICAgICAgLi4ucGFyYW1zLAogICAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsICJhZGRpdGlvbmFsUHJvcGVydGllcyJdCiAgICB9KTsKICB9Cn07CnZhciB1bmlvblByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGlzRXhjbHVzaXZlID0gZGVmLmluY2x1c2l2ZSA9PT0gZmFsc2U7CiAgY29uc3Qgb3B0aW9ucyA9IGRlZi5vcHRpb25zLm1hcCgoeCwgaSkgPT4gcHJvY2VzczIoeCwgY3R4LCB7CiAgICAuLi5wYXJhbXMsCiAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsIGlzRXhjbHVzaXZlID8gIm9uZU9mIiA6ICJhbnlPZiIsIGldCiAgfSkpOwogIGlmIChpc0V4Y2x1c2l2ZSkgewogICAganNvbi5vbmVPZiA9IG9wdGlvbnM7CiAgfSBlbHNlIHsKICAgIGpzb24uYW55T2YgPSBvcHRpb25zOwogIH0KfTsKdmFyIGludGVyc2VjdGlvblByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGEgPSBwcm9jZXNzMihkZWYubGVmdCwgY3R4LCB7CiAgICAuLi5wYXJhbXMsCiAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsICJhbGxPZiIsIDBdCiAgfSk7CiAgY29uc3QgYiA9IHByb2Nlc3MyKGRlZi5yaWdodCwgY3R4LCB7CiAgICAuLi5wYXJhbXMsCiAgICBwYXRoOiBbLi4ucGFyYW1zLnBhdGgsICJhbGxPZiIsIDFdCiAgfSk7CiAgY29uc3QgaXNTaW1wbGVJbnRlcnNlY3Rpb24gPSAodmFsKSA9PiAiYWxsT2YiIGluIHZhbCAmJiBPYmplY3Qua2V5cyh2YWwpLmxlbmd0aCA9PT0gMTsKICBjb25zdCBhbGxPZiA9IFsKICAgIC4uLmlzU2ltcGxlSW50ZXJzZWN0aW9uKGEpID8gYS5hbGxPZiA6IFthXSwKICAgIC4uLmlzU2ltcGxlSW50ZXJzZWN0aW9uKGIpID8gYi5hbGxPZiA6IFtiXQogIF07CiAganNvbi5hbGxPZiA9IGFsbE9mOwp9Owp2YXIgcmVjb3JkUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QganNvbiA9IF9qc29uOwogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBqc29uLnR5cGUgPSAib2JqZWN0IjsKICBjb25zdCBrZXlUeXBlID0gZGVmLmtleVR5cGU7CiAgY29uc3Qga2V5QmFnID0ga2V5VHlwZS5fem9kLmJhZzsKICBjb25zdCBwYXR0ZXJucyA9IGtleUJhZz8ucGF0dGVybnM7CiAgaWYgKGRlZi5tb2RlID09PSAibG9vc2UiICYmIHBhdHRlcm5zICYmIHBhdHRlcm5zLnNpemUgPiAwKSB7CiAgICBjb25zdCB2YWx1ZVNjaGVtYSA9IHByb2Nlc3MyKGRlZi52YWx1ZVR5cGUsIGN0eCwgewogICAgICAuLi5wYXJhbXMsCiAgICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgInBhdHRlcm5Qcm9wZXJ0aWVzIiwgIioiXQogICAgfSk7CiAgICBqc29uLnBhdHRlcm5Qcm9wZXJ0aWVzID0ge307CiAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgcGF0dGVybnMpIHsKICAgICAganNvbi5wYXR0ZXJuUHJvcGVydGllc1twYXR0ZXJuLnNvdXJjZV0gPSB2YWx1ZVNjaGVtYTsKICAgIH0KICB9IGVsc2UgewogICAgaWYgKGN0eC50YXJnZXQgPT09ICJkcmFmdC0wNyIgfHwgY3R4LnRhcmdldCA9PT0gImRyYWZ0LTIwMjAtMTIiKSB7CiAgICAgIGpzb24ucHJvcGVydHlOYW1lcyA9IHByb2Nlc3MyKGRlZi5rZXlUeXBlLCBjdHgsIHsKICAgICAgICAuLi5wYXJhbXMsCiAgICAgICAgcGF0aDogWy4uLnBhcmFtcy5wYXRoLCAicHJvcGVydHlOYW1lcyJdCiAgICAgIH0pOwogICAgfQogICAganNvbi5hZGRpdGlvbmFsUHJvcGVydGllcyA9IHByb2Nlc3MyKGRlZi52YWx1ZVR5cGUsIGN0eCwgewogICAgICAuLi5wYXJhbXMsCiAgICAgIHBhdGg6IFsuLi5wYXJhbXMucGF0aCwgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIl0KICAgIH0pOwogIH0KICBjb25zdCBrZXlWYWx1ZXMgPSBrZXlUeXBlLl96b2QudmFsdWVzOwogIGlmIChrZXlWYWx1ZXMpIHsKICAgIGNvbnN0IHZhbGlkS2V5VmFsdWVzID0gWy4uLmtleVZhbHVlc10uZmlsdGVyKCh2KSA9PiB0eXBlb2YgdiA9PT0gInN0cmluZyIgfHwgdHlwZW9mIHYgPT09ICJudW1iZXIiKTsKICAgIGlmICh2YWxpZEtleVZhbHVlcy5sZW5ndGggPiAwKSB7CiAgICAgIGpzb24ucmVxdWlyZWQgPSB2YWxpZEtleVZhbHVlczsKICAgIH0KICB9Cn07CnZhciBudWxsYWJsZVByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIGNvbnN0IGlubmVyID0gcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBpZiAoY3R4LnRhcmdldCA9PT0gIm9wZW5hcGktMy4wIikgewogICAgc2Vlbi5yZWYgPSBkZWYuaW5uZXJUeXBlOwogICAganNvbi5udWxsYWJsZSA9IHRydWU7CiAgfSBlbHNlIHsKICAgIGpzb24uYW55T2YgPSBbaW5uZXIsIHsgdHlwZTogIm51bGwiIH1dOwogIH0KfTsKdmFyIG5vbm9wdGlvbmFsUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBfanNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIHByb2Nlc3MyKGRlZi5pbm5lclR5cGUsIGN0eCwgcGFyYW1zKTsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgc2Vlbi5yZWYgPSBkZWYuaW5uZXJUeXBlOwp9Owp2YXIgZGVmYXVsdFByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIHByb2Nlc3MyKGRlZi5pbm5lclR5cGUsIGN0eCwgcGFyYW1zKTsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgc2Vlbi5yZWYgPSBkZWYuaW5uZXJUeXBlOwogIGpzb24uZGVmYXVsdCA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZGVmLmRlZmF1bHRWYWx1ZSkpOwp9Owp2YXIgcHJlZmF1bHRQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIGpzb24sIHBhcmFtcykgPT4gewogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBwcm9jZXNzMihkZWYuaW5uZXJUeXBlLCBjdHgsIHBhcmFtcyk7CiAgY29uc3Qgc2VlbiA9IGN0eC5zZWVuLmdldChzY2hlbWEpOwogIHNlZW4ucmVmID0gZGVmLmlubmVyVHlwZTsKICBpZiAoY3R4LmlvID09PSAiaW5wdXQiKQogICAganNvbi5fcHJlZmF1bHQgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGRlZi5kZWZhdWx0VmFsdWUpKTsKfTsKdmFyIGNhdGNoUHJvY2Vzc29yID0gKHNjaGVtYSwgY3R4LCBqc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7CiAgbGV0IGNhdGNoVmFsdWU7CiAgdHJ5IHsKICAgIGNhdGNoVmFsdWUgPSBkZWYuY2F0Y2hWYWx1ZSh2b2lkIDApOwogIH0gY2F0Y2ggewogICAgdGhyb3cgbmV3IEVycm9yKCJEeW5hbWljIGNhdGNoIHZhbHVlcyBhcmUgbm90IHN1cHBvcnRlZCBpbiBKU09OIFNjaGVtYSIpOwogIH0KICBqc29uLmRlZmF1bHQgPSBjYXRjaFZhbHVlOwp9Owp2YXIgcGlwZVByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwgX2pzb24sIHBhcmFtcykgPT4gewogIGNvbnN0IGRlZiA9IHNjaGVtYS5fem9kLmRlZjsKICBjb25zdCBpbklzVHJhbnNmb3JtID0gZGVmLmluLl96b2QudHJhaXRzLmhhcygiJFpvZFRyYW5zZm9ybSIpOwogIGNvbnN0IGlubmVyVHlwZSA9IGN0eC5pbyA9PT0gImlucHV0IiA/IGluSXNUcmFuc2Zvcm0gPyBkZWYub3V0IDogZGVmLmluIDogZGVmLm91dDsKICBwcm9jZXNzMihpbm5lclR5cGUsIGN0eCwgcGFyYW1zKTsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgc2Vlbi5yZWYgPSBpbm5lclR5cGU7Cn07CnZhciByZWFkb25seVByb2Nlc3NvciA9IChzY2hlbWEsIGN0eCwganNvbiwgcGFyYW1zKSA9PiB7CiAgY29uc3QgZGVmID0gc2NoZW1hLl96b2QuZGVmOwogIHByb2Nlc3MyKGRlZi5pbm5lclR5cGUsIGN0eCwgcGFyYW1zKTsKICBjb25zdCBzZWVuID0gY3R4LnNlZW4uZ2V0KHNjaGVtYSk7CiAgc2Vlbi5yZWYgPSBkZWYuaW5uZXJUeXBlOwogIGpzb24ucmVhZE9ubHkgPSB0cnVlOwp9Owp2YXIgb3B0aW9uYWxQcm9jZXNzb3IgPSAoc2NoZW1hLCBjdHgsIF9qc29uLCBwYXJhbXMpID0+IHsKICBjb25zdCBkZWYgPSBzY2hlbWEuX3pvZC5kZWY7CiAgcHJvY2VzczIoZGVmLmlubmVyVHlwZSwgY3R4LCBwYXJhbXMpOwogIGNvbnN0IHNlZW4gPSBjdHguc2Vlbi5nZXQoc2NoZW1hKTsKICBzZWVuLnJlZiA9IGRlZi5pbm5lclR5cGU7Cn07CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NsYXNzaWMvaXNvLmpzCnZhciBab2RJU09EYXRlVGltZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZElTT0RhdGVUaW1lIiwgKGluc3QsIGRlZikgPT4gewogICRab2RJU09EYXRlVGltZS5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIGRhdGV0aW1lMihwYXJhbXMpIHsKICByZXR1cm4gX2lzb0RhdGVUaW1lKFpvZElTT0RhdGVUaW1lLCBwYXJhbXMpOwp9CnZhciBab2RJU09EYXRlID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVNPRGF0ZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kSVNPRGF0ZS5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIGRhdGUyKHBhcmFtcykgewogIHJldHVybiBfaXNvRGF0ZShab2RJU09EYXRlLCBwYXJhbXMpOwp9CnZhciBab2RJU09UaW1lID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSVNPVGltZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kSVNPVGltZS5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIHRpbWUyKHBhcmFtcykgewogIHJldHVybiBfaXNvVGltZShab2RJU09UaW1lLCBwYXJhbXMpOwp9CnZhciBab2RJU09EdXJhdGlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZElTT0R1cmF0aW9uIiwgKGluc3QsIGRlZikgPT4gewogICRab2RJU09EdXJhdGlvbi5pbml0KGluc3QsIGRlZik7CiAgWm9kU3RyaW5nRm9ybWF0LmluaXQoaW5zdCwgZGVmKTsKfSk7CmZ1bmN0aW9uIGR1cmF0aW9uMihwYXJhbXMpIHsKICByZXR1cm4gX2lzb0R1cmF0aW9uKFpvZElTT0R1cmF0aW9uLCBwYXJhbXMpOwp9CgovLyBub2RlX21vZHVsZXMvem9kL3Y0L2NsYXNzaWMvZXJyb3JzLmpzCnZhciBpbml0aWFsaXplcjIgPSAoaW5zdCwgaXNzdWVzKSA9PiB7CiAgJFpvZEVycm9yLmluaXQoaW5zdCwgaXNzdWVzKTsKICBpbnN0Lm5hbWUgPSAiWm9kRXJyb3IiOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGluc3QsIHsKICAgIGZvcm1hdDogewogICAgICB2YWx1ZTogKG1hcHBlcikgPT4gZm9ybWF0RXJyb3IoaW5zdCwgbWFwcGVyKQogICAgICAvLyBlbnVtZXJhYmxlOiBmYWxzZSwKICAgIH0sCiAgICBmbGF0dGVuOiB7CiAgICAgIHZhbHVlOiAobWFwcGVyKSA9PiBmbGF0dGVuRXJyb3IoaW5zdCwgbWFwcGVyKQogICAgICAvLyBlbnVtZXJhYmxlOiBmYWxzZSwKICAgIH0sCiAgICBhZGRJc3N1ZTogewogICAgICB2YWx1ZTogKGlzc3VlMikgPT4gewogICAgICAgIGluc3QuaXNzdWVzLnB1c2goaXNzdWUyKTsKICAgICAgICBpbnN0Lm1lc3NhZ2UgPSBKU09OLnN0cmluZ2lmeShpbnN0Lmlzc3VlcywganNvblN0cmluZ2lmeVJlcGxhY2VyLCAyKTsKICAgICAgfQogICAgICAvLyBlbnVtZXJhYmxlOiBmYWxzZSwKICAgIH0sCiAgICBhZGRJc3N1ZXM6IHsKICAgICAgdmFsdWU6IChpc3N1ZXMyKSA9PiB7CiAgICAgICAgaW5zdC5pc3N1ZXMucHVzaCguLi5pc3N1ZXMyKTsKICAgICAgICBpbnN0Lm1lc3NhZ2UgPSBKU09OLnN0cmluZ2lmeShpbnN0Lmlzc3VlcywganNvblN0cmluZ2lmeVJlcGxhY2VyLCAyKTsKICAgICAgfQogICAgICAvLyBlbnVtZXJhYmxlOiBmYWxzZSwKICAgIH0sCiAgICBpc0VtcHR5OiB7CiAgICAgIGdldCgpIHsKICAgICAgICByZXR1cm4gaW5zdC5pc3N1ZXMubGVuZ3RoID09PSAwOwogICAgICB9CiAgICAgIC8vIGVudW1lcmFibGU6IGZhbHNlLAogICAgfQogIH0pOwp9Owp2YXIgWm9kUmVhbEVycm9yID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kRXJyb3IiLCBpbml0aWFsaXplcjIsIHsKICBQYXJlbnQ6IEVycm9yCn0pOwoKLy8gbm9kZV9tb2R1bGVzL3pvZC92NC9jbGFzc2ljL3BhcnNlLmpzCnZhciBwYXJzZTIgPSAvKiBAX19QVVJFX18gKi8gX3BhcnNlKFpvZFJlYWxFcnJvcik7CnZhciBwYXJzZUFzeW5jMiA9IC8qIEBfX1BVUkVfXyAqLyBfcGFyc2VBc3luYyhab2RSZWFsRXJyb3IpOwp2YXIgc2FmZVBhcnNlMiA9IC8qIEBfX1BVUkVfXyAqLyBfc2FmZVBhcnNlKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlUGFyc2VBc3luYzIgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVQYXJzZUFzeW5jKFpvZFJlYWxFcnJvcik7CnZhciBlbmNvZGUgPSAvKiBAX19QVVJFX18gKi8gX2VuY29kZShab2RSZWFsRXJyb3IpOwp2YXIgZGVjb2RlID0gLyogQF9fUFVSRV9fICovIF9kZWNvZGUoWm9kUmVhbEVycm9yKTsKdmFyIGVuY29kZUFzeW5jID0gLyogQF9fUFVSRV9fICovIF9lbmNvZGVBc3luYyhab2RSZWFsRXJyb3IpOwp2YXIgZGVjb2RlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX2RlY29kZUFzeW5jKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlRW5jb2RlID0gLyogQF9fUFVSRV9fICovIF9zYWZlRW5jb2RlKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlRGVjb2RlID0gLyogQF9fUFVSRV9fICovIF9zYWZlRGVjb2RlKFpvZFJlYWxFcnJvcik7CnZhciBzYWZlRW5jb2RlQXN5bmMgPSAvKiBAX19QVVJFX18gKi8gX3NhZmVFbmNvZGVBc3luYyhab2RSZWFsRXJyb3IpOwp2YXIgc2FmZURlY29kZUFzeW5jID0gLyogQF9fUFVSRV9fICovIF9zYWZlRGVjb2RlQXN5bmMoWm9kUmVhbEVycm9yKTsKCi8vIG5vZGVfbW9kdWxlcy96b2QvdjQvY2xhc3NpYy9zY2hlbWFzLmpzCnZhciBfaW5zdGFsbGVkR3JvdXBzID0gLyogQF9fUFVSRV9fICovIG5ldyBXZWFrTWFwKCk7CmZ1bmN0aW9uIF9pbnN0YWxsTGF6eU1ldGhvZHMoaW5zdCwgZ3JvdXAsIG1ldGhvZHMpIHsKICBjb25zdCBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihpbnN0KTsKICBsZXQgaW5zdGFsbGVkID0gX2luc3RhbGxlZEdyb3Vwcy5nZXQocHJvdG8pOwogIGlmICghaW5zdGFsbGVkKSB7CiAgICBpbnN0YWxsZWQgPSAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpOwogICAgX2luc3RhbGxlZEdyb3Vwcy5zZXQocHJvdG8sIGluc3RhbGxlZCk7CiAgfQogIGlmIChpbnN0YWxsZWQuaGFzKGdyb3VwKSkKICAgIHJldHVybjsKICBpbnN0YWxsZWQuYWRkKGdyb3VwKTsKICBmb3IgKGNvbnN0IGtleSBpbiBtZXRob2RzKSB7CiAgICBjb25zdCBmbiA9IG1ldGhvZHNba2V5XTsKICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShwcm90bywga2V5LCB7CiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSwKICAgICAgZW51bWVyYWJsZTogZmFsc2UsCiAgICAgIGdldCgpIHsKICAgICAgICBjb25zdCBib3VuZCA9IGZuLmJpbmQodGhpcyk7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIGtleSwgewogICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLAogICAgICAgICAgd3JpdGFibGU6IHRydWUsCiAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgICAgICAgdmFsdWU6IGJvdW5kCiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIGJvdW5kOwogICAgICB9LAogICAgICBzZXQodikgewogICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBrZXksIHsKICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSwKICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLAogICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgICAgICAgIHZhbHVlOiB2CiAgICAgICAgfSk7CiAgICAgIH0KICAgIH0pOwogIH0KfQp2YXIgWm9kVHlwZSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFR5cGUiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIE9iamVjdC5hc3NpZ24oaW5zdFsifnN0YW5kYXJkIl0sIHsKICAgIGpzb25TY2hlbWE6IHsKICAgICAgaW5wdXQ6IGNyZWF0ZVN0YW5kYXJkSlNPTlNjaGVtYU1ldGhvZChpbnN0LCAiaW5wdXQiKSwKICAgICAgb3V0cHV0OiBjcmVhdGVTdGFuZGFyZEpTT05TY2hlbWFNZXRob2QoaW5zdCwgIm91dHB1dCIpCiAgICB9CiAgfSk7CiAgaW5zdC50b0pTT05TY2hlbWEgPSBjcmVhdGVUb0pTT05TY2hlbWFNZXRob2QoaW5zdCwge30pOwogIGluc3QuZGVmID0gZGVmOwogIGluc3QudHlwZSA9IGRlZi50eXBlOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpbnN0LCAiX2RlZiIsIHsgdmFsdWU6IGRlZiB9KTsKICBpbnN0LnBhcnNlID0gKGRhdGEsIHBhcmFtcykgPT4gcGFyc2UyKGluc3QsIGRhdGEsIHBhcmFtcywgeyBjYWxsZWU6IGluc3QucGFyc2UgfSk7CiAgaW5zdC5zYWZlUGFyc2UgPSAoZGF0YSwgcGFyYW1zKSA9PiBzYWZlUGFyc2UyKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgaW5zdC5wYXJzZUFzeW5jID0gYXN5bmMgKGRhdGEsIHBhcmFtcykgPT4gcGFyc2VBc3luYzIoaW5zdCwgZGF0YSwgcGFyYW1zLCB7IGNhbGxlZTogaW5zdC5wYXJzZUFzeW5jIH0pOwogIGluc3Quc2FmZVBhcnNlQXN5bmMgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiBzYWZlUGFyc2VBc3luYzIoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LnNwYSA9IGluc3Quc2FmZVBhcnNlQXN5bmM7CiAgaW5zdC5lbmNvZGUgPSAoZGF0YSwgcGFyYW1zKSA9PiBlbmNvZGUoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LmRlY29kZSA9IChkYXRhLCBwYXJhbXMpID0+IGRlY29kZShpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3QuZW5jb2RlQXN5bmMgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiBlbmNvZGVBc3luYyhpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3QuZGVjb2RlQXN5bmMgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiBkZWNvZGVBc3luYyhpbnN0LCBkYXRhLCBwYXJhbXMpOwogIGluc3Quc2FmZUVuY29kZSA9IChkYXRhLCBwYXJhbXMpID0+IHNhZmVFbmNvZGUoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LnNhZmVEZWNvZGUgPSAoZGF0YSwgcGFyYW1zKSA9PiBzYWZlRGVjb2RlKGluc3QsIGRhdGEsIHBhcmFtcyk7CiAgaW5zdC5zYWZlRW5jb2RlQXN5bmMgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiBzYWZlRW5jb2RlQXN5bmMoaW5zdCwgZGF0YSwgcGFyYW1zKTsKICBpbnN0LnNhZmVEZWNvZGVBc3luYyA9IGFzeW5jIChkYXRhLCBwYXJhbXMpID0+IHNhZmVEZWNvZGVBc3luYyhpbnN0LCBkYXRhLCBwYXJhbXMpOwogIF9pbnN0YWxsTGF6eU1ldGhvZHMoaW5zdCwgIlpvZFR5cGUiLCB7CiAgICBjaGVjayguLi5jaGtzKSB7CiAgICAgIGNvbnN0IGRlZjIgPSB0aGlzLmRlZjsKICAgICAgcmV0dXJuIHRoaXMuY2xvbmUodXRpbF9leHBvcnRzLm1lcmdlRGVmcyhkZWYyLCB7CiAgICAgICAgY2hlY2tzOiBbCiAgICAgICAgICAuLi5kZWYyLmNoZWNrcyA/PyBbXSwKICAgICAgICAgIC4uLmNoa3MubWFwKChjaCkgPT4gdHlwZW9mIGNoID09PSAiZnVuY3Rpb24iID8geyBfem9kOiB7IGNoZWNrOiBjaCwgZGVmOiB7IGNoZWNrOiAiY3VzdG9tIiB9LCBvbmF0dGFjaDogW10gfSB9IDogY2gpCiAgICAgICAgXQogICAgICB9KSwgeyBwYXJlbnQ6IHRydWUgfSk7CiAgICB9LAogICAgd2l0aCguLi5jaGtzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKC4uLmNoa3MpOwogICAgfSwKICAgIGNsb25lKGRlZjIsIHBhcmFtcykgewogICAgICByZXR1cm4gY2xvbmUodGhpcywgZGVmMiwgcGFyYW1zKTsKICAgIH0sCiAgICBicmFuZCgpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9LAogICAgcmVnaXN0ZXIocmVnLCBtZXRhMikgewogICAgICByZWcuYWRkKHRoaXMsIG1ldGEyKTsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9LAogICAgcmVmaW5lKGNoZWNrLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2socmVmaW5lKGNoZWNrLCBwYXJhbXMpKTsKICAgIH0sCiAgICBzdXBlclJlZmluZShyZWZpbmVtZW50LCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soc3VwZXJSZWZpbmUocmVmaW5lbWVudCwgcGFyYW1zKSk7CiAgICB9LAogICAgb3ZlcndyaXRlKGZuKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9vdmVyd3JpdGUoZm4pKTsKICAgIH0sCiAgICBvcHRpb25hbCgpIHsKICAgICAgcmV0dXJuIG9wdGlvbmFsKHRoaXMpOwogICAgfSwKICAgIGV4YWN0T3B0aW9uYWwoKSB7CiAgICAgIHJldHVybiBleGFjdE9wdGlvbmFsKHRoaXMpOwogICAgfSwKICAgIG51bGxhYmxlKCkgewogICAgICByZXR1cm4gbnVsbGFibGUodGhpcyk7CiAgICB9LAogICAgbnVsbGlzaCgpIHsKICAgICAgcmV0dXJuIG9wdGlvbmFsKG51bGxhYmxlKHRoaXMpKTsKICAgIH0sCiAgICBub25vcHRpb25hbChwYXJhbXMpIHsKICAgICAgcmV0dXJuIG5vbm9wdGlvbmFsKHRoaXMsIHBhcmFtcyk7CiAgICB9LAogICAgYXJyYXkoKSB7CiAgICAgIHJldHVybiBhcnJheSh0aGlzKTsKICAgIH0sCiAgICBvcihhcmcpIHsKICAgICAgcmV0dXJuIHVuaW9uKFt0aGlzLCBhcmddKTsKICAgIH0sCiAgICBhbmQoYXJnKSB7CiAgICAgIHJldHVybiBpbnRlcnNlY3Rpb24odGhpcywgYXJnKTsKICAgIH0sCiAgICB0cmFuc2Zvcm0odHgpIHsKICAgICAgcmV0dXJuIHBpcGUodGhpcywgdHJhbnNmb3JtKHR4KSk7CiAgICB9LAogICAgZGVmYXVsdChkKSB7CiAgICAgIHJldHVybiBfZGVmYXVsdCh0aGlzLCBkKTsKICAgIH0sCiAgICBwcmVmYXVsdChkKSB7CiAgICAgIHJldHVybiBwcmVmYXVsdCh0aGlzLCBkKTsKICAgIH0sCiAgICBjYXRjaChwYXJhbXMpIHsKICAgICAgcmV0dXJuIF9jYXRjaCh0aGlzLCBwYXJhbXMpOwogICAgfSwKICAgIHBpcGUodGFyZ2V0KSB7CiAgICAgIHJldHVybiBwaXBlKHRoaXMsIHRhcmdldCk7CiAgICB9LAogICAgcmVhZG9ubHkoKSB7CiAgICAgIHJldHVybiByZWFkb25seSh0aGlzKTsKICAgIH0sCiAgICBkZXNjcmliZShkZXNjcmlwdGlvbikgewogICAgICBjb25zdCBjbCA9IHRoaXMuY2xvbmUoKTsKICAgICAgZ2xvYmFsUmVnaXN0cnkuYWRkKGNsLCB7IGRlc2NyaXB0aW9uIH0pOwogICAgICByZXR1cm4gY2w7CiAgICB9LAogICAgbWV0YSguLi5hcmdzKSB7CiAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMCkKICAgICAgICByZXR1cm4gZ2xvYmFsUmVnaXN0cnkuZ2V0KHRoaXMpOwogICAgICBjb25zdCBjbCA9IHRoaXMuY2xvbmUoKTsKICAgICAgZ2xvYmFsUmVnaXN0cnkuYWRkKGNsLCBhcmdzWzBdKTsKICAgICAgcmV0dXJuIGNsOwogICAgfSwKICAgIGlzT3B0aW9uYWwoKSB7CiAgICAgIHJldHVybiB0aGlzLnNhZmVQYXJzZSh2b2lkIDApLnN1Y2Nlc3M7CiAgICB9LAogICAgaXNOdWxsYWJsZSgpIHsKICAgICAgcmV0dXJuIHRoaXMuc2FmZVBhcnNlKG51bGwpLnN1Y2Nlc3M7CiAgICB9LAogICAgYXBwbHkoZm4pIHsKICAgICAgcmV0dXJuIGZuKHRoaXMpOwogICAgfQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpbnN0LCAiZGVzY3JpcHRpb24iLCB7CiAgICBnZXQoKSB7CiAgICAgIHJldHVybiBnbG9iYWxSZWdpc3RyeS5nZXQoaW5zdCk/LmRlc2NyaXB0aW9uOwogICAgfSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIHJldHVybiBpbnN0Owp9KTsKdmFyIF9ab2RTdHJpbmcgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJfWm9kU3RyaW5nIiwgKGluc3QsIGRlZikgPT4gewogICRab2RTdHJpbmcuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gc3RyaW5nUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBjb25zdCBiYWcgPSBpbnN0Ll96b2QuYmFnOwogIGluc3QuZm9ybWF0ID0gYmFnLmZvcm1hdCA/PyBudWxsOwogIGluc3QubWluTGVuZ3RoID0gYmFnLm1pbmltdW0gPz8gbnVsbDsKICBpbnN0Lm1heExlbmd0aCA9IGJhZy5tYXhpbXVtID8/IG51bGw7CiAgX2luc3RhbGxMYXp5TWV0aG9kcyhpbnN0LCAiX1pvZFN0cmluZyIsIHsKICAgIHJlZ2V4KC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX3JlZ2V4KC4uLmFyZ3MpKTsKICAgIH0sCiAgICBpbmNsdWRlcyguLi5hcmdzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9pbmNsdWRlcyguLi5hcmdzKSk7CiAgICB9LAogICAgc3RhcnRzV2l0aCguLi5hcmdzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9zdGFydHNXaXRoKC4uLmFyZ3MpKTsKICAgIH0sCiAgICBlbmRzV2l0aCguLi5hcmdzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9lbmRzV2l0aCguLi5hcmdzKSk7CiAgICB9LAogICAgbWluKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX21pbkxlbmd0aCguLi5hcmdzKSk7CiAgICB9LAogICAgbWF4KC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX21heExlbmd0aCguLi5hcmdzKSk7CiAgICB9LAogICAgbGVuZ3RoKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2xlbmd0aCguLi5hcmdzKSk7CiAgICB9LAogICAgbm9uZW1wdHkoLi4uYXJncykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbWluTGVuZ3RoKDEsIC4uLmFyZ3MpKTsKICAgIH0sCiAgICBsb3dlcmNhc2UocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sb3dlcmNhc2UocGFyYW1zKSk7CiAgICB9LAogICAgdXBwZXJjYXNlKHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfdXBwZXJjYXNlKHBhcmFtcykpOwogICAgfSwKICAgIHRyaW0oKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF90cmltKCkpOwogICAgfSwKICAgIG5vcm1hbGl6ZSguLi5hcmdzKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9ub3JtYWxpemUoLi4uYXJncykpOwogICAgfSwKICAgIHRvTG93ZXJDYXNlKCkgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfdG9Mb3dlckNhc2UoKSk7CiAgICB9LAogICAgdG9VcHBlckNhc2UoKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF90b1VwcGVyQ2FzZSgpKTsKICAgIH0sCiAgICBzbHVnaWZ5KCkgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfc2x1Z2lmeSgpKTsKICAgIH0KICB9KTsKfSk7CnZhciBab2RTdHJpbmcgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RTdHJpbmciLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFN0cmluZy5pbml0KGluc3QsIGRlZik7CiAgX1pvZFN0cmluZy5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5lbWFpbCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2VtYWlsKFpvZEVtYWlsLCBwYXJhbXMpKTsKICBpbnN0LnVybCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX3VybChab2RVUkwsIHBhcmFtcykpOwogIGluc3Quand0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfand0KFpvZEpXVCwgcGFyYW1zKSk7CiAgaW5zdC5lbW9qaSA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2Vtb2ppMihab2RFbW9qaSwgcGFyYW1zKSk7CiAgaW5zdC5ndWlkID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfZ3VpZChab2RHVUlELCBwYXJhbXMpKTsKICBpbnN0LnV1aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF91dWlkKFpvZFVVSUQsIHBhcmFtcykpOwogIGluc3QudXVpZHY0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfdXVpZHY0KFpvZFVVSUQsIHBhcmFtcykpOwogIGluc3QudXVpZHY2ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfdXVpZHY2KFpvZFVVSUQsIHBhcmFtcykpOwogIGluc3QudXVpZHY3ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfdXVpZHY3KFpvZFVVSUQsIHBhcmFtcykpOwogIGluc3QubmFub2lkID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfbmFub2lkKFpvZE5hbm9JRCwgcGFyYW1zKSk7CiAgaW5zdC5ndWlkID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfZ3VpZChab2RHVUlELCBwYXJhbXMpKTsKICBpbnN0LmN1aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9jdWlkKFpvZENVSUQsIHBhcmFtcykpOwogIGluc3QuY3VpZDIgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF9jdWlkMihab2RDVUlEMiwgcGFyYW1zKSk7CiAgaW5zdC51bGlkID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfdWxpZChab2RVTElELCBwYXJhbXMpKTsKICBpbnN0LmJhc2U2NCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2Jhc2U2NChab2RCYXNlNjQsIHBhcmFtcykpOwogIGluc3QuYmFzZTY0dXJsID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfYmFzZTY0dXJsKFpvZEJhc2U2NFVSTCwgcGFyYW1zKSk7CiAgaW5zdC54aWQgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKF94aWQoWm9kWElELCBwYXJhbXMpKTsKICBpbnN0LmtzdWlkID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfa3N1aWQoWm9kS1NVSUQsIHBhcmFtcykpOwogIGluc3QuaXB2NCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2lwdjQoWm9kSVB2NCwgcGFyYW1zKSk7CiAgaW5zdC5pcHY2ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfaXB2Nihab2RJUHY2LCBwYXJhbXMpKTsKICBpbnN0LmNpZHJ2NCA9IChwYXJhbXMpID0+IGluc3QuY2hlY2soX2NpZHJ2NChab2RDSURSdjQsIHBhcmFtcykpOwogIGluc3QuY2lkcnY2ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfY2lkcnY2KFpvZENJRFJ2NiwgcGFyYW1zKSk7CiAgaW5zdC5lMTY0ID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhfZTE2NChab2RFMTY0LCBwYXJhbXMpKTsKICBpbnN0LmRhdGV0aW1lID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhkYXRldGltZTIocGFyYW1zKSk7CiAgaW5zdC5kYXRlID0gKHBhcmFtcykgPT4gaW5zdC5jaGVjayhkYXRlMihwYXJhbXMpKTsKICBpbnN0LnRpbWUgPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKHRpbWUyKHBhcmFtcykpOwogIGluc3QuZHVyYXRpb24gPSAocGFyYW1zKSA9PiBpbnN0LmNoZWNrKGR1cmF0aW9uMihwYXJhbXMpKTsKfSk7CmZ1bmN0aW9uIHN0cmluZzIocGFyYW1zKSB7CiAgcmV0dXJuIF9zdHJpbmcoWm9kU3RyaW5nLCBwYXJhbXMpOwp9CnZhciBab2RTdHJpbmdGb3JtYXQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RTdHJpbmdGb3JtYXQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7CiAgX1pvZFN0cmluZy5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kRW1haWwgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RFbWFpbCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRW1haWwuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kR1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEdVSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEdVSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kVVVJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFVVSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFVVSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kVVJMID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVVJMIiwgKGluc3QsIGRlZikgPT4gewogICRab2RVUkwuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kRW1vamkgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RFbW9qaSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRW1vamkuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kTmFub0lEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kTmFub0lEIiwgKGluc3QsIGRlZikgPT4gewogICRab2ROYW5vSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQ1VJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZENVSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENVSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQ1VJRDIgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RDVUlEMiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQ1VJRDIuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kVUxJRCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFVMSUQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFVMSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kWElEID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kWElEIiwgKGluc3QsIGRlZikgPT4gewogICRab2RYSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kS1NVSUQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RLU1VJRCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kS1NVSUQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kSVB2NCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZElQdjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZElQdjQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kSVB2NiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZElQdjYiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZElQdjYuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQ0lEUnY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQ0lEUnY0IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDSURSdjQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQ0lEUnY2ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQ0lEUnY2IiwgKGluc3QsIGRlZikgPT4gewogICRab2RDSURSdjYuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQmFzZTY0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQmFzZTY0IiwgKGluc3QsIGRlZikgPT4gewogICRab2RCYXNlNjQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kQmFzZTY0VVJMID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQmFzZTY0VVJMIiwgKGluc3QsIGRlZikgPT4gewogICRab2RCYXNlNjRVUkwuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kRTE2NCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEUxNjQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEUxNjQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kSldUID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kSldUIiwgKGluc3QsIGRlZikgPT4gewogICRab2RKV1QuaW5pdChpbnN0LCBkZWYpOwogIFpvZFN0cmluZ0Zvcm1hdC5pbml0KGluc3QsIGRlZik7Cn0pOwp2YXIgWm9kTnVtYmVyID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kTnVtYmVyIiwgKGluc3QsIGRlZikgPT4gewogICRab2ROdW1iZXIuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gbnVtYmVyUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBfaW5zdGFsbExhenlNZXRob2RzKGluc3QsICJab2ROdW1iZXIiLCB7CiAgICBndCh2YWx1ZSwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9ndCh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgZ3RlKHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2d0ZSh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgbWluKHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2d0ZSh2YWx1ZSwgcGFyYW1zKSk7CiAgICB9LAogICAgbHQodmFsdWUsIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbHQodmFsdWUsIHBhcmFtcykpOwogICAgfSwKICAgIGx0ZSh2YWx1ZSwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sdGUodmFsdWUsIHBhcmFtcykpOwogICAgfSwKICAgIG1heCh2YWx1ZSwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sdGUodmFsdWUsIHBhcmFtcykpOwogICAgfSwKICAgIGludChwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soaW50KHBhcmFtcykpOwogICAgfSwKICAgIHNhZmUocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKGludChwYXJhbXMpKTsKICAgIH0sCiAgICBwb3NpdGl2ZShwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2d0KDAsIHBhcmFtcykpOwogICAgfSwKICAgIG5vbm5lZ2F0aXZlKHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfZ3RlKDAsIHBhcmFtcykpOwogICAgfSwKICAgIG5lZ2F0aXZlKHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbHQoMCwgcGFyYW1zKSk7CiAgICB9LAogICAgbm9ucG9zaXRpdmUocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9sdGUoMCwgcGFyYW1zKSk7CiAgICB9LAogICAgbXVsdGlwbGVPZih2YWx1ZSwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9tdWx0aXBsZU9mKHZhbHVlLCBwYXJhbXMpKTsKICAgIH0sCiAgICBzdGVwKHZhbHVlLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX211bHRpcGxlT2YodmFsdWUsIHBhcmFtcykpOwogICAgfSwKICAgIGZpbml0ZSgpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9CiAgfSk7CiAgY29uc3QgYmFnID0gaW5zdC5fem9kLmJhZzsKICBpbnN0Lm1pblZhbHVlID0gTWF0aC5tYXgoYmFnLm1pbmltdW0gPz8gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLCBiYWcuZXhjbHVzaXZlTWluaW11bSA/PyBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFkpID8/IG51bGw7CiAgaW5zdC5tYXhWYWx1ZSA9IE1hdGgubWluKGJhZy5tYXhpbXVtID8/IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwgYmFnLmV4Y2x1c2l2ZU1heGltdW0gPz8gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZKSA/PyBudWxsOwogIGluc3QuaXNJbnQgPSAoYmFnLmZvcm1hdCA/PyAiIikuaW5jbHVkZXMoImludCIpIHx8IE51bWJlci5pc1NhZmVJbnRlZ2VyKGJhZy5tdWx0aXBsZU9mID8/IDAuNSk7CiAgaW5zdC5pc0Zpbml0ZSA9IHRydWU7CiAgaW5zdC5mb3JtYXQgPSBiYWcuZm9ybWF0ID8/IG51bGw7Cn0pOwpmdW5jdGlvbiBudW1iZXIyKHBhcmFtcykgewogIHJldHVybiBfbnVtYmVyKFpvZE51bWJlciwgcGFyYW1zKTsKfQp2YXIgWm9kTnVtYmVyRm9ybWF0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kTnVtYmVyRm9ybWF0IiwgKGluc3QsIGRlZikgPT4gewogICRab2ROdW1iZXJGb3JtYXQuaW5pdChpbnN0LCBkZWYpOwogIFpvZE51bWJlci5pbml0KGluc3QsIGRlZik7Cn0pOwpmdW5jdGlvbiBpbnQocGFyYW1zKSB7CiAgcmV0dXJuIF9pbnQoWm9kTnVtYmVyRm9ybWF0LCBwYXJhbXMpOwp9CnZhciBab2RCb29sZWFuID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQm9vbGVhbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kQm9vbGVhbi5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBib29sZWFuUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKfSk7CmZ1bmN0aW9uIGJvb2xlYW4yKHBhcmFtcykgewogIHJldHVybiBfYm9vbGVhbihab2RCb29sZWFuLCBwYXJhbXMpOwp9CnZhciBab2RVbmtub3duID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kVW5rbm93biIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVW5rbm93bi5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiB1bmtub3duUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKfSk7CmZ1bmN0aW9uIHVua25vd24oKSB7CiAgcmV0dXJuIF91bmtub3duKFpvZFVua25vd24pOwp9CnZhciBab2ROZXZlciA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZE5ldmVyIiwgKGluc3QsIGRlZikgPT4gewogICRab2ROZXZlci5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBuZXZlclByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7Cn0pOwpmdW5jdGlvbiBuZXZlcihwYXJhbXMpIHsKICByZXR1cm4gX25ldmVyKFpvZE5ldmVyLCBwYXJhbXMpOwp9CnZhciBab2RBcnJheSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEFycmF5IiwgKGluc3QsIGRlZikgPT4gewogICRab2RBcnJheS5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBhcnJheVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC5lbGVtZW50ID0gZGVmLmVsZW1lbnQ7CiAgX2luc3RhbGxMYXp5TWV0aG9kcyhpbnN0LCAiWm9kQXJyYXkiLCB7CiAgICBtaW4obiwgcGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9taW5MZW5ndGgobiwgcGFyYW1zKSk7CiAgICB9LAogICAgbm9uZW1wdHkocGFyYW1zKSB7CiAgICAgIHJldHVybiB0aGlzLmNoZWNrKF9taW5MZW5ndGgoMSwgcGFyYW1zKSk7CiAgICB9LAogICAgbWF4KG4sIHBhcmFtcykgewogICAgICByZXR1cm4gdGhpcy5jaGVjayhfbWF4TGVuZ3RoKG4sIHBhcmFtcykpOwogICAgfSwKICAgIGxlbmd0aChuLCBwYXJhbXMpIHsKICAgICAgcmV0dXJuIHRoaXMuY2hlY2soX2xlbmd0aChuLCBwYXJhbXMpKTsKICAgIH0sCiAgICB1bndyYXAoKSB7CiAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQ7CiAgICB9CiAgfSk7Cn0pOwpmdW5jdGlvbiBhcnJheShlbGVtZW50LCBwYXJhbXMpIHsKICByZXR1cm4gX2FycmF5KFpvZEFycmF5LCBlbGVtZW50LCBwYXJhbXMpOwp9CnZhciBab2RPYmplY3QgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RPYmplY3QiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZE9iamVjdEpJVC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBvYmplY3RQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIHV0aWxfZXhwb3J0cy5kZWZpbmVMYXp5KGluc3QsICJzaGFwZSIsICgpID0+IHsKICAgIHJldHVybiBkZWYuc2hhcGU7CiAgfSk7CiAgX2luc3RhbGxMYXp5TWV0aG9kcyhpbnN0LCAiWm9kT2JqZWN0IiwgewogICAga2V5b2YoKSB7CiAgICAgIHJldHVybiBfZW51bShPYmplY3Qua2V5cyh0aGlzLl96b2QuZGVmLnNoYXBlKSk7CiAgICB9LAogICAgY2F0Y2hhbGwoY2F0Y2hhbGwpIHsKICAgICAgcmV0dXJuIHRoaXMuY2xvbmUoeyAuLi50aGlzLl96b2QuZGVmLCBjYXRjaGFsbCB9KTsKICAgIH0sCiAgICBwYXNzdGhyb3VnaCgpIHsKICAgICAgcmV0dXJuIHRoaXMuY2xvbmUoeyAuLi50aGlzLl96b2QuZGVmLCBjYXRjaGFsbDogdW5rbm93bigpIH0pOwogICAgfSwKICAgIGxvb3NlKCkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLnRoaXMuX3pvZC5kZWYsIGNhdGNoYWxsOiB1bmtub3duKCkgfSk7CiAgICB9LAogICAgc3RyaWN0KCkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLnRoaXMuX3pvZC5kZWYsIGNhdGNoYWxsOiBuZXZlcigpIH0pOwogICAgfSwKICAgIHN0cmlwKCkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLnRoaXMuX3pvZC5kZWYsIGNhdGNoYWxsOiB2b2lkIDAgfSk7CiAgICB9LAogICAgZXh0ZW5kKGluY29taW5nKSB7CiAgICAgIHJldHVybiB1dGlsX2V4cG9ydHMuZXh0ZW5kKHRoaXMsIGluY29taW5nKTsKICAgIH0sCiAgICBzYWZlRXh0ZW5kKGluY29taW5nKSB7CiAgICAgIHJldHVybiB1dGlsX2V4cG9ydHMuc2FmZUV4dGVuZCh0aGlzLCBpbmNvbWluZyk7CiAgICB9LAogICAgbWVyZ2Uob3RoZXIpIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5tZXJnZSh0aGlzLCBvdGhlcik7CiAgICB9LAogICAgcGljayhtYXNrKSB7CiAgICAgIHJldHVybiB1dGlsX2V4cG9ydHMucGljayh0aGlzLCBtYXNrKTsKICAgIH0sCiAgICBvbWl0KG1hc2spIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5vbWl0KHRoaXMsIG1hc2spOwogICAgfSwKICAgIHBhcnRpYWwoLi4uYXJncykgewogICAgICByZXR1cm4gdXRpbF9leHBvcnRzLnBhcnRpYWwoWm9kT3B0aW9uYWwsIHRoaXMsIGFyZ3NbMF0pOwogICAgfSwKICAgIHJlcXVpcmVkKC4uLmFyZ3MpIHsKICAgICAgcmV0dXJuIHV0aWxfZXhwb3J0cy5yZXF1aXJlZChab2ROb25PcHRpb25hbCwgdGhpcywgYXJnc1swXSk7CiAgICB9CiAgfSk7Cn0pOwpmdW5jdGlvbiBvYmplY3Qoc2hhcGUsIHBhcmFtcykgewogIGNvbnN0IGRlZiA9IHsKICAgIHR5cGU6ICJvYmplY3QiLAogICAgc2hhcGU6IHNoYXBlID8/IHt9LAogICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfTsKICByZXR1cm4gbmV3IFpvZE9iamVjdChkZWYpOwp9CnZhciBab2RVbmlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFVuaW9uIiwgKGluc3QsIGRlZikgPT4gewogICRab2RVbmlvbi5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiB1bmlvblByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC5vcHRpb25zID0gZGVmLm9wdGlvbnM7Cn0pOwpmdW5jdGlvbiB1bmlvbihvcHRpb25zLCBwYXJhbXMpIHsKICByZXR1cm4gbmV3IFpvZFVuaW9uKHsKICAgIHR5cGU6ICJ1bmlvbiIsCiAgICBvcHRpb25zLAogICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KdmFyIFpvZEludGVyc2VjdGlvbiA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZEludGVyc2VjdGlvbiIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kSW50ZXJzZWN0aW9uLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IGludGVyc2VjdGlvblByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7Cn0pOwpmdW5jdGlvbiBpbnRlcnNlY3Rpb24obGVmdCwgcmlnaHQpIHsKICByZXR1cm4gbmV3IFpvZEludGVyc2VjdGlvbih7CiAgICB0eXBlOiAiaW50ZXJzZWN0aW9uIiwKICAgIGxlZnQsCiAgICByaWdodAogIH0pOwp9CnZhciBab2RSZWNvcmQgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RSZWNvcmQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFJlY29yZC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiByZWNvcmRQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3Qua2V5VHlwZSA9IGRlZi5rZXlUeXBlOwogIGluc3QudmFsdWVUeXBlID0gZGVmLnZhbHVlVHlwZTsKfSk7CmZ1bmN0aW9uIHJlY29yZChrZXlUeXBlLCB2YWx1ZVR5cGUsIHBhcmFtcykgewogIGlmICghdmFsdWVUeXBlIHx8ICF2YWx1ZVR5cGUuX3pvZCkgewogICAgcmV0dXJuIG5ldyBab2RSZWNvcmQoewogICAgICB0eXBlOiAicmVjb3JkIiwKICAgICAga2V5VHlwZTogc3RyaW5nMigpLAogICAgICB2YWx1ZVR5cGU6IGtleVR5cGUsCiAgICAgIC4uLnV0aWxfZXhwb3J0cy5ub3JtYWxpemVQYXJhbXModmFsdWVUeXBlKQogICAgfSk7CiAgfQogIHJldHVybiBuZXcgWm9kUmVjb3JkKHsKICAgIHR5cGU6ICJyZWNvcmQiLAogICAga2V5VHlwZSwKICAgIHZhbHVlVHlwZSwKICAgIC4uLnV0aWxfZXhwb3J0cy5ub3JtYWxpemVQYXJhbXMocGFyYW1zKQogIH0pOwp9CnZhciBab2RFbnVtID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kRW51bSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRW51bS5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBlbnVtUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LmVudW0gPSBkZWYuZW50cmllczsKICBpbnN0Lm9wdGlvbnMgPSBPYmplY3QudmFsdWVzKGRlZi5lbnRyaWVzKTsKICBjb25zdCBrZXlzID0gbmV3IFNldChPYmplY3Qua2V5cyhkZWYuZW50cmllcykpOwogIGluc3QuZXh0cmFjdCA9ICh2YWx1ZXMsIHBhcmFtcykgPT4gewogICAgY29uc3QgbmV3RW50cmllcyA9IHt9OwogICAgZm9yIChjb25zdCB2YWx1ZSBvZiB2YWx1ZXMpIHsKICAgICAgaWYgKGtleXMuaGFzKHZhbHVlKSkgewogICAgICAgIG5ld0VudHJpZXNbdmFsdWVdID0gZGVmLmVudHJpZXNbdmFsdWVdOwogICAgICB9IGVsc2UKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEtleSAke3ZhbHVlfSBub3QgZm91bmQgaW4gZW51bWApOwogICAgfQogICAgcmV0dXJuIG5ldyBab2RFbnVtKHsKICAgICAgLi4uZGVmLAogICAgICBjaGVja3M6IFtdLAogICAgICAuLi51dGlsX2V4cG9ydHMubm9ybWFsaXplUGFyYW1zKHBhcmFtcyksCiAgICAgIGVudHJpZXM6IG5ld0VudHJpZXMKICAgIH0pOwogIH07CiAgaW5zdC5leGNsdWRlID0gKHZhbHVlcywgcGFyYW1zKSA9PiB7CiAgICBjb25zdCBuZXdFbnRyaWVzID0geyAuLi5kZWYuZW50cmllcyB9OwogICAgZm9yIChjb25zdCB2YWx1ZSBvZiB2YWx1ZXMpIHsKICAgICAgaWYgKGtleXMuaGFzKHZhbHVlKSkgewogICAgICAgIGRlbGV0ZSBuZXdFbnRyaWVzW3ZhbHVlXTsKICAgICAgfSBlbHNlCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBLZXkgJHt2YWx1ZX0gbm90IGZvdW5kIGluIGVudW1gKTsKICAgIH0KICAgIHJldHVybiBuZXcgWm9kRW51bSh7CiAgICAgIC4uLmRlZiwKICAgICAgY2hlY2tzOiBbXSwKICAgICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogICAgICBlbnRyaWVzOiBuZXdFbnRyaWVzCiAgICB9KTsKICB9Owp9KTsKZnVuY3Rpb24gX2VudW0odmFsdWVzLCBwYXJhbXMpIHsKICBjb25zdCBlbnRyaWVzID0gQXJyYXkuaXNBcnJheSh2YWx1ZXMpID8gT2JqZWN0LmZyb21FbnRyaWVzKHZhbHVlcy5tYXAoKHYpID0+IFt2LCB2XSkpIDogdmFsdWVzOwogIHJldHVybiBuZXcgWm9kRW51bSh7CiAgICB0eXBlOiAiZW51bSIsCiAgICBlbnRyaWVzLAogICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KdmFyIFpvZFRyYW5zZm9ybSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFRyYW5zZm9ybSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kVHJhbnNmb3JtLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHRyYW5zZm9ybVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC5fem9kLnBhcnNlID0gKHBheWxvYWQsIF9jdHgpID0+IHsKICAgIGlmIChfY3R4LmRpcmVjdGlvbiA9PT0gImJhY2t3YXJkIikgewogICAgICB0aHJvdyBuZXcgJFpvZEVuY29kZUVycm9yKGluc3QuY29uc3RydWN0b3IubmFtZSk7CiAgICB9CiAgICBwYXlsb2FkLmFkZElzc3VlID0gKGlzc3VlMikgPT4gewogICAgICBpZiAodHlwZW9mIGlzc3VlMiA9PT0gInN0cmluZyIpIHsKICAgICAgICBwYXlsb2FkLmlzc3Vlcy5wdXNoKHV0aWxfZXhwb3J0cy5pc3N1ZShpc3N1ZTIsIHBheWxvYWQudmFsdWUsIGRlZikpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IF9pc3N1ZSA9IGlzc3VlMjsKICAgICAgICBpZiAoX2lzc3VlLmZhdGFsKQogICAgICAgICAgX2lzc3VlLmNvbnRpbnVlID0gZmFsc2U7CiAgICAgICAgX2lzc3VlLmNvZGUgPz8gKF9pc3N1ZS5jb2RlID0gImN1c3RvbSIpOwogICAgICAgIF9pc3N1ZS5pbnB1dCA/PyAoX2lzc3VlLmlucHV0ID0gcGF5bG9hZC52YWx1ZSk7CiAgICAgICAgX2lzc3VlLmluc3QgPz8gKF9pc3N1ZS5pbnN0ID0gaW5zdCk7CiAgICAgICAgcGF5bG9hZC5pc3N1ZXMucHVzaCh1dGlsX2V4cG9ydHMuaXNzdWUoX2lzc3VlKSk7CiAgICAgIH0KICAgIH07CiAgICBjb25zdCBvdXRwdXQgPSBkZWYudHJhbnNmb3JtKHBheWxvYWQudmFsdWUsIHBheWxvYWQpOwogICAgaWYgKG91dHB1dCBpbnN0YW5jZW9mIFByb21pc2UpIHsKICAgICAgcmV0dXJuIG91dHB1dC50aGVuKChvdXRwdXQyKSA9PiB7CiAgICAgICAgcGF5bG9hZC52YWx1ZSA9IG91dHB1dDI7CiAgICAgICAgcGF5bG9hZC5mYWxsYmFjayA9IHRydWU7CiAgICAgICAgcmV0dXJuIHBheWxvYWQ7CiAgICAgIH0pOwogICAgfQogICAgcGF5bG9hZC52YWx1ZSA9IG91dHB1dDsKICAgIHBheWxvYWQuZmFsbGJhY2sgPSB0cnVlOwogICAgcmV0dXJuIHBheWxvYWQ7CiAgfTsKfSk7CmZ1bmN0aW9uIHRyYW5zZm9ybShmbikgewogIHJldHVybiBuZXcgWm9kVHJhbnNmb3JtKHsKICAgIHR5cGU6ICJ0cmFuc2Zvcm0iLAogICAgdHJhbnNmb3JtOiBmbgogIH0pOwp9CnZhciBab2RPcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZE9wdGlvbmFsIiwgKGluc3QsIGRlZikgPT4gewogICRab2RPcHRpb25hbC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBvcHRpb25hbFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKfSk7CmZ1bmN0aW9uIG9wdGlvbmFsKGlubmVyVHlwZSkgewogIHJldHVybiBuZXcgWm9kT3B0aW9uYWwoewogICAgdHlwZTogIm9wdGlvbmFsIiwKICAgIGlubmVyVHlwZQogIH0pOwp9CnZhciBab2RFeGFjdE9wdGlvbmFsID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kRXhhY3RPcHRpb25hbCIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kRXhhY3RPcHRpb25hbC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBvcHRpb25hbFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKfSk7CmZ1bmN0aW9uIGV4YWN0T3B0aW9uYWwoaW5uZXJUeXBlKSB7CiAgcmV0dXJuIG5ldyBab2RFeGFjdE9wdGlvbmFsKHsKICAgIHR5cGU6ICJvcHRpb25hbCIsCiAgICBpbm5lclR5cGUKICB9KTsKfQp2YXIgWm9kTnVsbGFibGUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2ROdWxsYWJsZSIsIChpbnN0LCBkZWYpID0+IHsKICAkWm9kTnVsbGFibGUuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gbnVsbGFibGVQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3QudW53cmFwID0gKCkgPT4gaW5zdC5fem9kLmRlZi5pbm5lclR5cGU7Cn0pOwpmdW5jdGlvbiBudWxsYWJsZShpbm5lclR5cGUpIHsKICByZXR1cm4gbmV3IFpvZE51bGxhYmxlKHsKICAgIHR5cGU6ICJudWxsYWJsZSIsCiAgICBpbm5lclR5cGUKICB9KTsKfQp2YXIgWm9kRGVmYXVsdCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZERlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZERlZmF1bHQuaW5pdChpbnN0LCBkZWYpOwogIFpvZFR5cGUuaW5pdChpbnN0LCBkZWYpOwogIGluc3QuX3pvZC5wcm9jZXNzSlNPTlNjaGVtYSA9IChjdHgsIGpzb24sIHBhcmFtcykgPT4gZGVmYXVsdFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKICBpbnN0LnJlbW92ZURlZmF1bHQgPSBpbnN0LnVud3JhcDsKfSk7CmZ1bmN0aW9uIF9kZWZhdWx0KGlubmVyVHlwZSwgZGVmYXVsdFZhbHVlKSB7CiAgcmV0dXJuIG5ldyBab2REZWZhdWx0KHsKICAgIHR5cGU6ICJkZWZhdWx0IiwKICAgIGlubmVyVHlwZSwKICAgIGdldCBkZWZhdWx0VmFsdWUoKSB7CiAgICAgIHJldHVybiB0eXBlb2YgZGVmYXVsdFZhbHVlID09PSAiZnVuY3Rpb24iID8gZGVmYXVsdFZhbHVlKCkgOiB1dGlsX2V4cG9ydHMuc2hhbGxvd0Nsb25lKGRlZmF1bHRWYWx1ZSk7CiAgICB9CiAgfSk7Cn0KdmFyIFpvZFByZWZhdWx0ID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kUHJlZmF1bHQiLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZFByZWZhdWx0LmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHByZWZhdWx0UHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwp9KTsKZnVuY3Rpb24gcHJlZmF1bHQoaW5uZXJUeXBlLCBkZWZhdWx0VmFsdWUpIHsKICByZXR1cm4gbmV3IFpvZFByZWZhdWx0KHsKICAgIHR5cGU6ICJwcmVmYXVsdCIsCiAgICBpbm5lclR5cGUsCiAgICBnZXQgZGVmYXVsdFZhbHVlKCkgewogICAgICByZXR1cm4gdHlwZW9mIGRlZmF1bHRWYWx1ZSA9PT0gImZ1bmN0aW9uIiA/IGRlZmF1bHRWYWx1ZSgpIDogdXRpbF9leHBvcnRzLnNoYWxsb3dDbG9uZShkZWZhdWx0VmFsdWUpOwogICAgfQogIH0pOwp9CnZhciBab2ROb25PcHRpb25hbCA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZE5vbk9wdGlvbmFsIiwgKGluc3QsIGRlZikgPT4gewogICRab2ROb25PcHRpb25hbC5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBub25vcHRpb25hbFByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKfSk7CmZ1bmN0aW9uIG5vbm9wdGlvbmFsKGlubmVyVHlwZSwgcGFyYW1zKSB7CiAgcmV0dXJuIG5ldyBab2ROb25PcHRpb25hbCh7CiAgICB0eXBlOiAibm9ub3B0aW9uYWwiLAogICAgaW5uZXJUeXBlLAogICAgLi4udXRpbF9leHBvcnRzLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpCiAgfSk7Cn0KdmFyIFpvZENhdGNoID0gLyogQF9fUFVSRV9fICovICRjb25zdHJ1Y3RvcigiWm9kQ2F0Y2giLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZENhdGNoLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IGNhdGNoUHJvY2Vzc29yKGluc3QsIGN0eCwganNvbiwgcGFyYW1zKTsKICBpbnN0LnVud3JhcCA9ICgpID0+IGluc3QuX3pvZC5kZWYuaW5uZXJUeXBlOwogIGluc3QucmVtb3ZlQ2F0Y2ggPSBpbnN0LnVud3JhcDsKfSk7CmZ1bmN0aW9uIF9jYXRjaChpbm5lclR5cGUsIGNhdGNoVmFsdWUpIHsKICByZXR1cm4gbmV3IFpvZENhdGNoKHsKICAgIHR5cGU6ICJjYXRjaCIsCiAgICBpbm5lclR5cGUsCiAgICBjYXRjaFZhbHVlOiB0eXBlb2YgY2F0Y2hWYWx1ZSA9PT0gImZ1bmN0aW9uIiA/IGNhdGNoVmFsdWUgOiAoKSA9PiBjYXRjaFZhbHVlCiAgfSk7Cn0KdmFyIFpvZFBpcGUgPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RQaXBlIiwgKGluc3QsIGRlZikgPT4gewogICRab2RQaXBlLmluaXQoaW5zdCwgZGVmKTsKICBab2RUeXBlLmluaXQoaW5zdCwgZGVmKTsKICBpbnN0Ll96b2QucHJvY2Vzc0pTT05TY2hlbWEgPSAoY3R4LCBqc29uLCBwYXJhbXMpID0+IHBpcGVQcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwogIGluc3QuaW4gPSBkZWYuaW47CiAgaW5zdC5vdXQgPSBkZWYub3V0Owp9KTsKZnVuY3Rpb24gcGlwZShpbl8sIG91dCkgewogIHJldHVybiBuZXcgWm9kUGlwZSh7CiAgICB0eXBlOiAicGlwZSIsCiAgICBpbjogaW5fLAogICAgb3V0CiAgICAvLyAuLi51dGlsLm5vcm1hbGl6ZVBhcmFtcyhwYXJhbXMpLAogIH0pOwp9CnZhciBab2RSZWFkb25seSA9IC8qIEBfX1BVUkVfXyAqLyAkY29uc3RydWN0b3IoIlpvZFJlYWRvbmx5IiwgKGluc3QsIGRlZikgPT4gewogICRab2RSZWFkb25seS5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiByZWFkb25seVByb2Nlc3NvcihpbnN0LCBjdHgsIGpzb24sIHBhcmFtcyk7CiAgaW5zdC51bndyYXAgPSAoKSA9PiBpbnN0Ll96b2QuZGVmLmlubmVyVHlwZTsKfSk7CmZ1bmN0aW9uIHJlYWRvbmx5KGlubmVyVHlwZSkgewogIHJldHVybiBuZXcgWm9kUmVhZG9ubHkoewogICAgdHlwZTogInJlYWRvbmx5IiwKICAgIGlubmVyVHlwZQogIH0pOwp9CnZhciBab2RDdXN0b20gPSAvKiBAX19QVVJFX18gKi8gJGNvbnN0cnVjdG9yKCJab2RDdXN0b20iLCAoaW5zdCwgZGVmKSA9PiB7CiAgJFpvZEN1c3RvbS5pbml0KGluc3QsIGRlZik7CiAgWm9kVHlwZS5pbml0KGluc3QsIGRlZik7CiAgaW5zdC5fem9kLnByb2Nlc3NKU09OU2NoZW1hID0gKGN0eCwganNvbiwgcGFyYW1zKSA9PiBjdXN0b21Qcm9jZXNzb3IoaW5zdCwgY3R4LCBqc29uLCBwYXJhbXMpOwp9KTsKZnVuY3Rpb24gcmVmaW5lKGZuLCBfcGFyYW1zID0ge30pIHsKICByZXR1cm4gX3JlZmluZShab2RDdXN0b20sIGZuLCBfcGFyYW1zKTsKfQpmdW5jdGlvbiBzdXBlclJlZmluZShmbiwgcGFyYW1zKSB7CiAgcmV0dXJuIF9zdXBlclJlZmluZShmbiwgcGFyYW1zKTsKfQoKLy8gc3JjL2lzc3VlLXRyaWFnZS9wb2xpY3kudHMKdmFyIHRyaWFnZVBvbGljeVNjaGVtYSA9IG9iamVjdCh7CiAgdmVyc2lvbjogbnVtYmVyMigpLmludCgpLnBvc2l0aXZlKCksCiAgZHVwbGljYXRlQ29uZmlkZW5jZVRocmVzaG9sZDogbnVtYmVyMigpLm1pbigwKS5tYXgoMSksCiAgY2xhc3NpZmljYXRpb25Db25maWRlbmNlVGhyZXNob2xkOiBudW1iZXIyKCkubWluKDApLm1heCgxKSwKICBwcmlvcml0eUNvbmZpZGVuY2VUaHJlc2hvbGQ6IG51bWJlcjIoKS5taW4oMCkubWF4KDEpLAogIG1heENhbmRpZGF0ZXM6IG51bWJlcjIoKS5pbnQoKS5taW4oMCkubWF4KDEwMCksCiAgbWF4UmVsYXRlZElzc3VlczogbnVtYmVyMigpLmludCgpLm1pbigwKS5tYXgoMjApLAogIHNraXBMYWJlbHM6IGFycmF5KHN0cmluZzIoKS5taW4oMSkpLAogIG1hbmFnZWRMYWJlbFByZWZpeGVzOiBhcnJheShzdHJpbmcyKCkubWluKDEpKSwKICBjbGFzc2lmaWNhdGlvbkxhYmVsczogb2JqZWN0KHsKICAgIGJ1Zzogc3RyaW5nMigpLm1pbigxKSwKICAgIGVuaGFuY2VtZW50OiBzdHJpbmcyKCkubWluKDEpLAogICAgZG9jdW1lbnRhdGlvbjogc3RyaW5nMigpLm1pbigxKSwKICAgIHF1ZXN0aW9uOiBzdHJpbmcyKCkubWluKDEpCiAgfSksCiAgbGFiZWxDb2xvcnM6IHJlY29yZChzdHJpbmcyKCksIHN0cmluZzIoKS5yZWdleCgvXlswLTlhLWZBLUZdezZ9JC8pKSwKICBsYWJlbERlc2NyaXB0aW9uczogcmVjb3JkKHN0cmluZzIoKSwgc3RyaW5nMigpLm1pbigxKS5tYXgoMTAwKSkKfSk7CmZ1bmN0aW9uIGNhbGN1bGF0ZVByaW9yaXR5KGFuYWx5c2lzLCBwb2xpY3kpIHsKICBjb25zdCB7IGZhY3RzIH0gPSBhbmFseXNpczsKICBpZiAoZmFjdHMuc2VjdXJpdHlJbXBhY3QgPT09ICJjcml0aWNhbCIgfHwgZmFjdHMuZGF0YUxvc3MgPT09IHRydWUgfHwgZmFjdHMuZW52aXJvbm1lbnQgPT09ICJwcm9kdWN0aW9uIiAmJiBmYWN0cy5wcm9kdWN0aW9uSW1wYWN0ID09PSAib3V0YWdlIikgewogICAgcmV0dXJuICJQMCI7CiAgfQogIGlmIChmYWN0cy5zZWN1cml0eUltcGFjdCA9PT0gImhpZ2giIHx8IGZhY3RzLnJlbGVhc2VCbG9ja2VyID09PSB0cnVlIHx8IGZhY3RzLmVudmlyb25tZW50ID09PSAicHJvZHVjdGlvbiIgJiYgZmFjdHMuY29yZUZsb3dCbG9ja2VkID09PSB0cnVlICYmIGZhY3RzLndvcmthcm91bmQgPT09ICJub25lIikgewogICAgcmV0dXJuICJQMSI7CiAgfQogIGlmIChhbmFseXNpcy5wcmlvcml0eUNvbmZpZGVuY2UgPCBwb2xpY3kucHJpb3JpdHlDb25maWRlbmNlVGhyZXNob2xkKSB7CiAgICByZXR1cm4gInBlbmRpbmciOwogIH0KICBjb25zdCBsYWNrc0ltcGFjdEV2aWRlbmNlID0gZmFjdHMucHJvZHVjdGlvbkltcGFjdCA9PT0gInVua25vd24iICYmIGZhY3RzLmFmZmVjdGVkU2NvcGUgPT09ICJ1bmtub3duIiAmJiBmYWN0cy5zbGFSaXNrID09PSBudWxsICYmIGZhY3RzLnJlbGVhc2VCbG9ja2VyID09PSBudWxsOwogIGlmIChsYWNrc0ltcGFjdEV2aWRlbmNlKSB7CiAgICByZXR1cm4gInBlbmRpbmciOwogIH0KICBpZiAoZmFjdHMucHJvZHVjdGlvbkltcGFjdCA9PT0gImRlZ3JhZGVkIiB8fCBmYWN0cy5hZmZlY3RlZFNjb3BlID09PSAibWFueSIgfHwgZmFjdHMuYWZmZWN0ZWRTY29wZSA9PT0gImFsbCIgfHwgZmFjdHMuc2xhUmlzayA9PT0gdHJ1ZSB8fCBmYWN0cy5jb3JlRmxvd0Jsb2NrZWQgPT09IHRydWUpIHsKICAgIHJldHVybiAiUDIiOwogIH0KICByZXR1cm4gIlAzIjsKfQpmdW5jdGlvbiBtYWtlRGVjaXNpb24oYW5hbHlzaXMsIGNhbmRpZGF0ZXMsIHBvbGljeSwgZXhpc3RpbmdMYWJlbHMgPSBbXSkgewogIGNvbnN0IGNhbmRpZGF0ZU51bWJlcnMgPSBuZXcgU2V0KAogICAgY2FuZGlkYXRlcy5tYXAoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm51bWJlcikKICApOwogIGNvbnN0IGR1cGxpY2F0ZSA9IGFuYWx5c2lzLmR1cGxpY2F0ZTsKICBjb25zdCBkdXBsaWNhdGVJc3N1ZU51bWJlciA9IGR1cGxpY2F0ZS5pc3N1ZU51bWJlciAhPT0gbnVsbCAmJiBkdXBsaWNhdGUuY29uZmlkZW5jZSA+PSBwb2xpY3kuZHVwbGljYXRlQ29uZmlkZW5jZVRocmVzaG9sZCAmJiBjYW5kaWRhdGVOdW1iZXJzLmhhcyhkdXBsaWNhdGUuaXNzdWVOdW1iZXIpID8gZHVwbGljYXRlLmlzc3VlTnVtYmVyIDogbnVsbDsKICBjb25zdCByZWxhdGVkSXNzdWVzID0gYW5hbHlzaXMucmVsYXRlZElzc3Vlcy5maWx0ZXIoCiAgICAocmVsYXRlZCkgPT4gY2FuZGlkYXRlTnVtYmVycy5oYXMocmVsYXRlZC5pc3N1ZU51bWJlcikgJiYgcmVsYXRlZC5pc3N1ZU51bWJlciAhPT0gZHVwbGljYXRlSXNzdWVOdW1iZXIKICApLmZpbHRlcigKICAgIChyZWxhdGVkLCBpbmRleCwgYWxsKSA9PiBhbGwuZmluZEluZGV4KAogICAgICAoY2FuZGlkYXRlKSA9PiBjYW5kaWRhdGUuaXNzdWVOdW1iZXIgPT09IHJlbGF0ZWQuaXNzdWVOdW1iZXIKICAgICkgPT09IGluZGV4CiAgKS5zbGljZSgwLCBwb2xpY3kubWF4UmVsYXRlZElzc3Vlcyk7CiAgY29uc3QgcHJpb3JpdHkgPSBjYWxjdWxhdGVQcmlvcml0eShhbmFseXNpcywgcG9saWN5KTsKICBjb25zdCBjbGFzc2lmaWNhdGlvbiA9IHJlc29sdmVDbGFzc2lmaWNhdGlvbigKICAgIGFuYWx5c2lzLAogICAgZXhpc3RpbmdMYWJlbHMsCiAgICBwb2xpY3kKICApOwogIGNvbnN0IGxhYmVscyA9IFsKICAgIGBwcmlvcml0eToke3ByaW9yaXR5fWAsCiAgICBhbmFseXNpcy5taXNzaW5nSW5mb3JtYXRpb24ubGVuZ3RoID4gMCA/ICJ0cmlhZ2U6bmVlZHMtaW5mbyIgOiAidHJpYWdlOmRvbmUiCiAgXTsKICBpZiAoY2xhc3NpZmljYXRpb24uc291cmNlID09PSAiYW5hbHlzaXMiICYmIGNsYXNzaWZpY2F0aW9uLmxhYmVsKSB7CiAgICBsYWJlbHMucHVzaChjbGFzc2lmaWNhdGlvbi5sYWJlbCk7CiAgfQogIGlmIChkdXBsaWNhdGVJc3N1ZU51bWJlciAhPT0gbnVsbCkgewogICAgbGFiZWxzLnB1c2goImR1cGxpY2F0ZSIpOwogIH0KICByZXR1cm4gewogICAgYW5hbHlzaXMsCiAgICBjbGFzc2lmaWNhdGlvbiwKICAgIHByaW9yaXR5LAogICAgbGFiZWxzOiBbLi4ubmV3IFNldChsYWJlbHMpXSwKICAgIGR1cGxpY2F0ZUlzc3VlTnVtYmVyLAogICAgcmVsYXRlZElzc3VlcwogIH07Cn0KZnVuY3Rpb24gcmVzb2x2ZUNsYXNzaWZpY2F0aW9uKGFuYWx5c2lzLCBleGlzdGluZ0xhYmVscywgcG9saWN5KSB7CiAgY29uc3QgY29uZmlndXJlZExhYmVscyA9IE9iamVjdC52YWx1ZXMocG9saWN5LmNsYXNzaWZpY2F0aW9uTGFiZWxzKTsKICBjb25zdCBub3JtYWxpemVkQ29uZmlndXJlZCA9IG5ldyBNYXAoCiAgICBjb25maWd1cmVkTGFiZWxzLm1hcCgobGFiZWwpID0+IFtsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKSwgbGFiZWxdKQogICk7CiAgY29uc3QgZXhpc3RpbmdDbGFzc2lmaWNhdGlvbkxhYmVscyA9IFsKICAgIC4uLm5ldyBTZXQoCiAgICAgIGV4aXN0aW5nTGFiZWxzLm1hcCgobGFiZWwpID0+IG5vcm1hbGl6ZWRDb25maWd1cmVkLmdldChsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKSkpLmZpbHRlcigobGFiZWwpID0+IEJvb2xlYW4obGFiZWwpKQogICAgKQogIF07CiAgaWYgKGV4aXN0aW5nQ2xhc3NpZmljYXRpb25MYWJlbHMubGVuZ3RoID09PSAxKSB7CiAgICByZXR1cm4geyBsYWJlbDogZXhpc3RpbmdDbGFzc2lmaWNhdGlvbkxhYmVsc1swXSwgc291cmNlOiAiZXhpc3RpbmciIH07CiAgfQogIGlmIChleGlzdGluZ0NsYXNzaWZpY2F0aW9uTGFiZWxzLmxlbmd0aCA+IDEpIHsKICAgIHJldHVybiB7IGxhYmVsOiBudWxsLCBzb3VyY2U6ICJjb25mbGljdCIgfTsKICB9CiAgaWYgKGFuYWx5c2lzLmlzc3VlVHlwZSA9PT0gInVua25vd24iIHx8IGFuYWx5c2lzLmNsYXNzaWZpY2F0aW9uQ29uZmlkZW5jZSA8IHBvbGljeS5jbGFzc2lmaWNhdGlvbkNvbmZpZGVuY2VUaHJlc2hvbGQpIHsKICAgIHJldHVybiB7IGxhYmVsOiBudWxsLCBzb3VyY2U6ICJ1bmtub3duIiB9OwogIH0KICByZXR1cm4gewogICAgbGFiZWw6IHBvbGljeS5jbGFzc2lmaWNhdGlvbkxhYmVsc1thbmFseXNpcy5pc3N1ZVR5cGVdLAogICAgc291cmNlOiAiYW5hbHlzaXMiCiAgfTsKfQpmdW5jdGlvbiBtZXJnZU1hbmFnZWRMYWJlbHMoZXhpc3RpbmcsIGRlc2lyZWQsIG1hbmFnZWRQcmVmaXhlcykgewogIGNvbnN0IHByZXNlcnZlZCA9IGV4aXN0aW5nLmZpbHRlcigKICAgIChsYWJlbCkgPT4gIW1hbmFnZWRQcmVmaXhlcy5zb21lKChwcmVmaXgpID0+IGxhYmVsLnN0YXJ0c1dpdGgocHJlZml4KSkKICApOwogIHJldHVybiBbLi4uLyogQF9fUFVSRV9fICovIG5ldyBTZXQoWy4uLnByZXNlcnZlZCwgLi4uZGVzaXJlZF0pXTsKfQoKLy8gc3JjL3J1bnRpbWUvdGFyZ2V0LWJpbmRpbmcudHMKZnVuY3Rpb24gYXNzZXJ0Qm91bmRUYXJnZXQob3B0aW9ucykgewogIGNvbnN0IGV4cGVjdGVkUmVwb3NpdG9yeSA9IG9wdGlvbnMuZXhwZWN0ZWRSZXBvc2l0b3J5Py50cmltKCkgPz8gIiI7CiAgY29uc3QgZXhwZWN0ZWRUYXJnZXRUZXh0ID0gb3B0aW9ucy5leHBlY3RlZFRhcmdldD8udHJpbSgpID8/ICIiOwogIGlmICghZXhwZWN0ZWRSZXBvc2l0b3J5ICYmICFleHBlY3RlZFRhcmdldFRleHQpIHsKICAgIGlmIChvcHRpb25zLmFwcGx5KSB0aHJvdyBuZXcgRXJyb3Iob3B0aW9ucy5lcnJvcnMubWlzc2luZyk7CiAgICByZXR1cm47CiAgfQogIGlmICghZXhwZWN0ZWRSZXBvc2l0b3J5IHx8ICFleHBlY3RlZFRhcmdldFRleHQpIHsKICAgIHRocm93IG5ldyBFcnJvcihvcHRpb25zLmVycm9ycy5pbmNvbXBsZXRlKTsKICB9CiAgY29uc3QgZXhwZWN0ZWRUYXJnZXQgPSBOdW1iZXIoZXhwZWN0ZWRUYXJnZXRUZXh0KTsKICBpZiAoIWlzUmVwb3NpdG9yeVNsdWcoZXhwZWN0ZWRSZXBvc2l0b3J5KSB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIoZXhwZWN0ZWRUYXJnZXQpIHx8IGV4cGVjdGVkVGFyZ2V0IDw9IDApIHsKICAgIHRocm93IG5ldyBFcnJvcihvcHRpb25zLmVycm9ycy5pbnZhbGlkKTsKICB9CiAgaWYgKG9wdGlvbnMucmVwb3NpdG9yeSAhPT0gZXhwZWN0ZWRSZXBvc2l0b3J5IHx8IG9wdGlvbnMudGFyZ2V0TnVtYmVyICE9PSBleHBlY3RlZFRhcmdldCkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICBvcHRpb25zLmVycm9ycy5taXNtYXRjaChleHBlY3RlZFJlcG9zaXRvcnksIGV4cGVjdGVkVGFyZ2V0KQogICAgKTsKICB9Cn0KCi8vIHNyYy9pc3N1ZS10cmlhZ2UvdGFyZ2V0LnRzCmZ1bmN0aW9uIGFzc2VydEJvdW5kSXNzdWVUYXJnZXQocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIGFwcGx5LCBlbnZpcm9ubWVudCkgewogIGFzc2VydEJvdW5kVGFyZ2V0KHsKICAgIHJlcG9zaXRvcnksCiAgICB0YXJnZXROdW1iZXI6IGlzc3VlTnVtYmVyLAogICAgYXBwbHksCiAgICBleHBlY3RlZFJlcG9zaXRvcnk6IGVudmlyb25tZW50LklTU1VFX1RSSUFHRV9FWFBFQ1RFRF9SRVBPU0lUT1JZLAogICAgZXhwZWN0ZWRUYXJnZXQ6IGVudmlyb25tZW50LklTU1VFX1RSSUFHRV9FWFBFQ1RFRF9JU1NVRSwKICAgIGVycm9yczogewogICAgICBtaXNzaW5nOiAiYXBwbHkgbW9kZSByZXF1aXJlcyBhIHNjaGVkdWxlci1ib3VuZCBJc3N1ZSB0YXJnZXQ7IHNldCBJU1NVRV9UUklBR0VfRVhQRUNURURfUkVQT1NJVE9SWSBhbmQgSVNTVUVfVFJJQUdFX0VYUEVDVEVEX0lTU1VFIiwKICAgICAgaW5jb21wbGV0ZTogImluY29tcGxldGUgc2NoZWR1bGVyLWJvdW5kIElzc3VlIHRhcmdldCIsCiAgICAgIGludmFsaWQ6ICJpbnZhbGlkIHNjaGVkdWxlci1ib3VuZCBJc3N1ZSB0YXJnZXQiLAogICAgICBtaXNtYXRjaDogKGV4cGVjdGVkUmVwb3NpdG9yeSwgZXhwZWN0ZWRJc3N1ZU51bWJlcikgPT4gYHJlcXVlc3RlZCBJc3N1ZSAke3JlcG9zaXRvcnl9IyR7aXNzdWVOdW1iZXJ9IGRvZXMgbm90IG1hdGNoIHNjaGVkdWxlci1ib3VuZCB0YXJnZXQgJHtleHBlY3RlZFJlcG9zaXRvcnl9IyR7ZXhwZWN0ZWRJc3N1ZU51bWJlcn1gCiAgICB9CiAgfSk7Cn0KCi8vIHNyYy9pc3N1ZXMvZmluZ2VycHJpbnQudHMKaW1wb3J0IGNyeXB0byBmcm9tICJub2RlOmNyeXB0byI7CnZhciBJU1NVRV9GSU5HRVJQUklOVF9QQVRURVJOID0gL15bMC05YS1mXXsyMH0kLzsKZnVuY3Rpb24gaXNzdWVGaW5nZXJwcmludChpc3N1ZTIsIGNvbW1lbnRzID0gW10pIHsKICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goInNoYTI1NiIpLnVwZGF0ZSgKICAgIEpTT04uc3RyaW5naWZ5KHsKICAgICAgdGl0bGU6IGlzc3VlMi50aXRsZS50cmltKCksCiAgICAgIGJvZHk6IGlzc3VlMi5ib2R5ID8/ICIiLAogICAgICBjb21tZW50czogY29tbWVudHMubWFwKChjb21tZW50KSA9PiAoewogICAgICAgIGlkOiBjb21tZW50LmlkLAogICAgICAgIGJvZHk6IGNvbW1lbnQuYm9keSwKICAgICAgICBhdXRob3I6IGNvbW1lbnQudXNlcj8ubG9naW4gPz8gIiIKICAgICAgfSkpCiAgICB9KQogICkuZGlnZXN0KCJoZXgiKS5zbGljZSgwLCAyMCk7Cn0KCi8vIHNyYy9pc3N1ZXMvbWFuYWdlZC1jb21tZW50cy50cwp2YXIgSVNTVUVfVFJJQUdFX0NPTU1FTlRfUFJFRklYID0gIjwhLS0gZW5naW5lZXJpbmctYWdlbnQtd29ya2Zsb3dzOmlzc3VlLXRyaWFnZTp2MSI7CmZ1bmN0aW9uIGlzSXNzdWVUcmlhZ2VDb21tZW50KGJvZHkpIHsKICByZXR1cm4gYm9keS5zdGFydHNXaXRoKElTU1VFX1RSSUFHRV9DT01NRU5UX1BSRUZJWCk7Cn0KCi8vIHNyYy9pc3N1ZS10cmlhZ2UvY29tbWVudC50cwp2YXIgQ09NTUVOVF9NQVJLRVJfUFJFRklYID0gSVNTVUVfVFJJQUdFX0NPTU1FTlRfUFJFRklYOwpmdW5jdGlvbiBjb21tZW50TWFya2VyKGlzc3VlTnVtYmVyLCBmaW5nZXJwcmludCkgewogIHJldHVybiBgJHtDT01NRU5UX01BUktFUl9QUkVGSVh9IGlzc3VlPSR7aXNzdWVOdW1iZXJ9IGZpbmdlcnByaW50PSR7ZmluZ2VycHJpbnR9IC0tPmA7Cn0KZnVuY3Rpb24gYnVpbGRUcmlhZ2VDb21tZW50KGlzc3VlTnVtYmVyLCBmaW5nZXJwcmludCwgZGVjaXNpb24pIHsKICBjb25zdCBhbmFseXNpcyA9IGRlY2lzaW9uLmFuYWx5c2lzOwogIGNvbnN0IGxpbmVzID0gWwogICAgY29tbWVudE1hcmtlcihpc3N1ZU51bWJlciwgZmluZ2VycHJpbnQpLAogICAgIiMjIElzc3VlIHRyaWFnZSIsCiAgICAiIiwKICAgICIjIyMgQ2xhc3NpZmljYXRpb24iLAogICAgIiIsCiAgICBgLSBUeXBlOiBcYCR7Y2xhc3NpZmljYXRpb25UZXh0KGRlY2lzaW9uKX1cYGAsCiAgICBgLSBQcmlvcml0eTogXGAke2RlY2lzaW9uLnByaW9yaXR5fVxgYCwKICAgIGAtIFByaW9yaXR5IGJhc2lzOiAke2FuYWx5c2lzLnByaW9yaXR5UmVhc29ufWAKICBdOwogIGlmIChkZWNpc2lvbi5kdXBsaWNhdGVJc3N1ZU51bWJlciAhPT0gbnVsbCkgewogICAgbGluZXMucHVzaCgKICAgICAgIiIsCiAgICAgICIjIyMgUG9zc2libGUgZHVwbGljYXRlIiwKICAgICAgIiIsCiAgICAgIGAtICMke2RlY2lzaW9uLmR1cGxpY2F0ZUlzc3VlTnVtYmVyfTogJHthbmFseXNpcy5kdXBsaWNhdGUucmVhc29ufWAKICAgICk7CiAgfQogIGlmIChkZWNpc2lvbi5yZWxhdGVkSXNzdWVzLmxlbmd0aCA+IDApIHsKICAgIGxpbmVzLnB1c2goIiIsICIjIyMgUmVsYXRlZCBpc3N1ZXMiLCAiIik7CiAgICBmb3IgKGNvbnN0IHJlbGF0ZWQgb2YgZGVjaXNpb24ucmVsYXRlZElzc3VlcykgewogICAgICBsaW5lcy5wdXNoKGAtICMke3JlbGF0ZWQuaXNzdWVOdW1iZXJ9OiAke3JlbGF0ZWQucmVhc29ufWApOwogICAgfQogIH0KICBpZiAoYW5hbHlzaXMubWlzc2luZ0luZm9ybWF0aW9uLmxlbmd0aCA+IDApIHsKICAgIGxpbmVzLnB1c2goIiIsICIjIyMgSW5mb3JtYXRpb24gbmVlZGVkIiwgIiIpOwogICAgZm9yIChjb25zdCBtaXNzaW5nIG9mIGFuYWx5c2lzLm1pc3NpbmdJbmZvcm1hdGlvbikgewogICAgICBsaW5lcy5wdXNoKGAtICR7bWlzc2luZ31gKTsKICAgIH0KICB9CiAgbGluZXMucHVzaCgKICAgICIiLAogICAgIiMjIyBNYWludGFpbmVyIG5leHQgc3RlcCIsCiAgICAiIiwKICAgICItIFdoZW4gdGhpcyBJc3N1ZSBpcyByZWFkeSBmb3IgaW1wbGVtZW50YXRpb24sIGEgbWFpbnRhaW5lciBjYW4gYWRkIHRoZSBgYWdlbnQ6cmVhZHlgIGxhYmVsLiBUaGUgQWdlbnQgd2lsbCBvcGVuIGEgRHJhZnQgUHVsbCBSZXF1ZXN0IGFuZCB3aWxsIG5vdCBtZXJnZSBpdCBhdXRvbWF0aWNhbGx5LiIsCiAgICAiLSBBZGQgYHNraXAtdHJpYWdlYCB0byBvcHQgb3V0IG9mIGF1dG9tYXRlZCB0cmlhZ2UuIiwKICAgICIiLAogICAgIl9UaGlzIGlzIGFuIGF1dG9tYXRlZCBpbml0aWFsIGFzc2Vzc21lbnQgYmFzZWQgb24gdGhlIElzc3VlIHRleHQgYW5kIHJlbGF0ZWQgY2FuZGlkYXRlczsgbm8gcmVwb3NpdG9yeSBjb2RlIHdhcyBpbnNwZWN0ZWQuXyIKICApOwogIHJldHVybiBsaW5lcy5qb2luKCJcbiIpOwp9CmZ1bmN0aW9uIGNsYXNzaWZpY2F0aW9uVGV4dChkZWNpc2lvbikgewogIGlmIChkZWNpc2lvbi5jbGFzc2lmaWNhdGlvbi5sYWJlbCkgcmV0dXJuIGRlY2lzaW9uLmNsYXNzaWZpY2F0aW9uLmxhYmVsOwogIHJldHVybiBkZWNpc2lvbi5jbGFzc2lmaWNhdGlvbi5zb3VyY2UgPT09ICJjb25mbGljdCIgPyAidW5yZXNvbHZlZCAoY29uZmxpY3RpbmcgZXhpc3RpbmcgbGFiZWxzKSIgOiAidW5rbm93biI7Cn0KCi8vIHNyYy9pc3N1ZS10cmlhZ2Uvc2NoZW1hLnRzCnZhciB1bmtub3duQm9vbGVhbiA9IGJvb2xlYW4yKCkubnVsbGFibGUoKTsKdmFyIHRyaWFnZUFuYWx5c2lzU2NoZW1hID0gb2JqZWN0KHsKICBpc3N1ZVR5cGU6IF9lbnVtKFsKICAgICJidWciLAogICAgImVuaGFuY2VtZW50IiwKICAgICJkb2N1bWVudGF0aW9uIiwKICAgICJxdWVzdGlvbiIsCiAgICAidW5rbm93biIKICBdKSwKICBjbGFzc2lmaWNhdGlvbkNvbmZpZGVuY2U6IG51bWJlcjIoKS5taW4oMCkubWF4KDEpLAogIHByaW9yaXR5Q29uZmlkZW5jZTogbnVtYmVyMigpLm1pbigwKS5tYXgoMSksCiAgZmFjdHM6IG9iamVjdCh7CiAgICBlbnZpcm9ubWVudDogX2VudW0oWyJwcm9kdWN0aW9uIiwgIm5vbi1wcm9kdWN0aW9uIiwgInVua25vd24iXSksCiAgICBwcm9kdWN0aW9uSW1wYWN0OiBfZW51bShbIm5vbmUiLCAiZGVncmFkZWQiLCAib3V0YWdlIiwgInVua25vd24iXSksCiAgICBzZWN1cml0eUltcGFjdDogX2VudW0oWyJub25lIiwgImxvdyIsICJoaWdoIiwgImNyaXRpY2FsIiwgInVua25vd24iXSksCiAgICBkYXRhTG9zczogdW5rbm93bkJvb2xlYW4sCiAgICBjb3JlRmxvd0Jsb2NrZWQ6IHVua25vd25Cb29sZWFuLAogICAgd29ya2Fyb3VuZDogX2VudW0oWyJhdmFpbGFibGUiLCAibm9uZSIsICJ1bmtub3duIl0pLAogICAgYWZmZWN0ZWRTY29wZTogX2VudW0oWyJzaW5nbGUiLCAibGltaXRlZCIsICJtYW55IiwgImFsbCIsICJ1bmtub3duIl0pLAogICAgc2xhUmlzazogdW5rbm93bkJvb2xlYW4sCiAgICByZWxlYXNlQmxvY2tlcjogdW5rbm93bkJvb2xlYW4KICB9KSwKICBkdXBsaWNhdGU6IG9iamVjdCh7CiAgICBpc3N1ZU51bWJlcjogbnVtYmVyMigpLmludCgpLnBvc2l0aXZlKCkubnVsbGFibGUoKSwKICAgIGNvbmZpZGVuY2U6IG51bWJlcjIoKS5taW4oMCkubWF4KDEpLAogICAgcmVhc29uOiBzdHJpbmcyKCkubWF4KDJlMykKICB9KSwKICByZWxhdGVkSXNzdWVzOiBhcnJheSgKICAgIG9iamVjdCh7CiAgICAgIGlzc3VlTnVtYmVyOiBudW1iZXIyKCkuaW50KCkucG9zaXRpdmUoKSwKICAgICAgcmVhc29uOiBzdHJpbmcyKCkubWluKDEpLm1heCgxZTMpCiAgICB9KQogICkubWF4KDEwKSwKICBtaXNzaW5nSW5mb3JtYXRpb246IGFycmF5KHN0cmluZzIoKS5taW4oMSkubWF4KDFlMykpLm1heCgxMCksCiAgcHJpb3JpdHlSZWFzb246IHN0cmluZzIoKS5taW4oMSkubWF4KDJlMykKfSk7CnZhciB0cmlhZ2VTdWJtaXNzaW9uU2NoZW1hID0gb2JqZWN0KHsKICBpc3N1ZUZpbmdlcnByaW50OiBzdHJpbmcyKCkucmVnZXgoSVNTVUVfRklOR0VSUFJJTlRfUEFUVEVSTiksCiAgYW5hbHlzaXM6IHRyaWFnZUFuYWx5c2lzU2NoZW1hCn0pOwoKLy8gc3JjL2lzc3VlLXRyaWFnZS90b29sLnRzCmFzeW5jIGZ1bmN0aW9uIHByZXBhcmVJc3N1ZVRyaWFnZShyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgZGVwZW5kZW5jaWVzKSB7CiAgY29uc3QgaXNzdWUyID0gYXdhaXQgZGVwZW5kZW5jaWVzLmlzc3Vlcy5nZXRJc3N1ZShyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgaWYgKGhhc1NraXBMYWJlbChpc3N1ZTIubGFiZWxzLCBkZXBlbmRlbmNpZXMucG9saWN5LnNraXBMYWJlbHMpKSB7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgc2tpcHBlZDogdHJ1ZSwKICAgICAgcmVhc29uOiAiaXNzdWUgaGFzIGEgY29uZmlndXJlZCBza2lwLXRyaWFnZSBsYWJlbCIsCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGlzc3VlTnVtYmVyLAogICAgICBpc3N1ZUZpbmdlcnByaW50OiBpc3N1ZUZpbmdlcnByaW50KGlzc3VlMikKICAgIH07CiAgfQogIGNvbnN0IGNvbW1lbnRzID0gYXdhaXQgZGVwZW5kZW5jaWVzLmlzc3Vlcy5saXN0Q29tbWVudHMoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIKICApOwogIGNvbnN0IGNvbnRleHRDb21tZW50cyA9IHNlbGVjdENvbnRleHRDb21tZW50cygKICAgIGNvbW1lbnRzLAogICAgZGVwZW5kZW5jaWVzLmJvdExvZ2luCiAgKTsKICBjb25zdCBmaW5nZXJwcmludCA9IGlzc3VlRmluZ2VycHJpbnQoaXNzdWUyLCBjb250ZXh0Q29tbWVudHMpOwogIGlmIChoYXNDdXJyZW50VHJpYWdlQ29tbWVudCgKICAgIGNvbW1lbnRzLAogICAgaXNzdWVOdW1iZXIsCiAgICBmaW5nZXJwcmludCwKICAgIGRlcGVuZGVuY2llcy5ib3RMb2dpbgogICkpIHsKICAgIHJldHVybiB7CiAgICAgIG9rOiB0cnVlLAogICAgICBza2lwcGVkOiB0cnVlLAogICAgICByZWFzb246ICJpc3N1ZSBjb250ZW50IGFscmVhZHkgdHJpYWdlZCIsCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGlzc3VlTnVtYmVyLAogICAgICBpc3N1ZUZpbmdlcnByaW50OiBmaW5nZXJwcmludAogICAgfTsKICB9CiAgY29uc3QgeyBjYW5kaWRhdGVzLCB3YXJuaW5ncyB9ID0gYXdhaXQgbG9hZENhbmRpZGF0ZXMoCiAgICBkZXBlbmRlbmNpZXMuaXNzdWVzLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlMiwKICAgIGRlcGVuZGVuY2llcy5wb2xpY3kubWF4Q2FuZGlkYXRlcwogICk7CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgaXNzdWVGaW5nZXJwcmludDogZmluZ2VycHJpbnQsCiAgICBpc3N1ZTogaXNzdWUyLAogICAgY29tbWVudHM6IGNvbnRleHRDb21tZW50cywKICAgIGNhbmRpZGF0ZXMsCiAgICAuLi53YXJuaW5ncy5sZW5ndGggPiAwID8geyB3YXJuaW5ncyB9IDoge30KICB9Owp9CmFzeW5jIGZ1bmN0aW9uIGFwcGx5SXNzdWVUcmlhZ2UocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIHN1Ym1pc3Npb25JbnB1dCwgYXBwbHksIGRlcGVuZGVuY2llcykgewogIGNvbnN0IHN1Ym1pc3Npb24gPSB0cmlhZ2VTdWJtaXNzaW9uU2NoZW1hLnBhcnNlKHN1Ym1pc3Npb25JbnB1dCk7CiAgY29uc3QgaXNzdWUyID0gYXdhaXQgZGVwZW5kZW5jaWVzLmlzc3Vlcy5nZXRJc3N1ZShyZXBvc2l0b3J5LCBpc3N1ZU51bWJlcik7CiAgaWYgKGhhc1NraXBMYWJlbChpc3N1ZTIubGFiZWxzLCBkZXBlbmRlbmNpZXMucG9saWN5LnNraXBMYWJlbHMpKSB7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgc2tpcHBlZDogdHJ1ZSwKICAgICAgcmVhc29uOiAiaXNzdWUgaGFzIGEgY29uZmlndXJlZCBza2lwLXRyaWFnZSBsYWJlbCIsCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGlzc3VlTnVtYmVyLAogICAgICBhcHBsaWVkOiBmYWxzZQogICAgfTsKICB9CiAgY29uc3QgYm90TG9naW4gPSByZXF1aXJlZEJvdExvZ2luKGFwcGx5LCBkZXBlbmRlbmNpZXMuYm90TG9naW4pOwogIGNvbnN0IGNvbW1lbnRzID0gYXdhaXQgZGVwZW5kZW5jaWVzLmlzc3Vlcy5saXN0Q29tbWVudHMoCiAgICByZXBvc2l0b3J5LAogICAgaXNzdWVOdW1iZXIKICApOwogIGNvbnN0IGNvbnRleHRDb21tZW50cyA9IHNlbGVjdENvbnRleHRDb21tZW50cyhjb21tZW50cywgYm90TG9naW4pOwogIGNvbnN0IGN1cnJlbnRGaW5nZXJwcmludCA9IGlzc3VlRmluZ2VycHJpbnQoaXNzdWUyLCBjb250ZXh0Q29tbWVudHMpOwogIGlmIChjdXJyZW50RmluZ2VycHJpbnQgIT09IHN1Ym1pc3Npb24uaXNzdWVGaW5nZXJwcmludCkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAiaXNzdWUgY2hhbmdlZCBhZnRlciBhbmFseXNpczsgcnVuIHRoZSBwcmVwYXJlIGNvbW1hbmQgYWdhaW4gYmVmb3JlIGFwcGx5aW5nIgogICAgKTsKICB9CiAgaWYgKGhhc0N1cnJlbnRUcmlhZ2VDb21tZW50KGNvbW1lbnRzLCBpc3N1ZU51bWJlciwgY3VycmVudEZpbmdlcnByaW50LCBib3RMb2dpbikpIHsKICAgIHJldHVybiB7CiAgICAgIG9rOiB0cnVlLAogICAgICBza2lwcGVkOiB0cnVlLAogICAgICByZWFzb246ICJpc3N1ZSBjb250ZW50IGFscmVhZHkgdHJpYWdlZCIsCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGlzc3VlTnVtYmVyLAogICAgICBhcHBsaWVkOiBmYWxzZQogICAgfTsKICB9CiAgY29uc3QgeyBjYW5kaWRhdGVzLCB3YXJuaW5ncyB9ID0gYXdhaXQgbG9hZENhbmRpZGF0ZXMoCiAgICBkZXBlbmRlbmNpZXMuaXNzdWVzLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlMiwKICAgIGRlcGVuZGVuY2llcy5wb2xpY3kubWF4Q2FuZGlkYXRlcwogICk7CiAgY29uc3QgZGVjaXNpb24gPSBtYWtlRGVjaXNpb24oCiAgICBzdWJtaXNzaW9uLmFuYWx5c2lzLAogICAgY2FuZGlkYXRlcywKICAgIGRlcGVuZGVuY2llcy5wb2xpY3ksCiAgICBpc3N1ZTIubGFiZWxzCiAgKTsKICBjb25zdCBwcm9wb3NlZENvbW1lbnQgPSBidWlsZFRyaWFnZUNvbW1lbnQoCiAgICBpc3N1ZU51bWJlciwKICAgIGN1cnJlbnRGaW5nZXJwcmludCwKICAgIGRlY2lzaW9uCiAgKTsKICBjb25zdCBkZXNpcmVkTGFiZWxzID0gbWVyZ2VNYW5hZ2VkTGFiZWxzKAogICAgaXNzdWUyLmxhYmVscywKICAgIGRlY2lzaW9uLmxhYmVscywKICAgIGRlcGVuZGVuY2llcy5wb2xpY3kubWFuYWdlZExhYmVsUHJlZml4ZXMKICApOwogIGNvbnN0IGV4aXN0aW5nTGFiZWxzID0gaXNzdWUyLmxhYmVsczsKICBjb25zdCBsYWJlbHNUb0FkZCA9IGRlc2lyZWRMYWJlbHMuZmlsdGVyKAogICAgKGxhYmVsKSA9PiAhZXhpc3RpbmdMYWJlbHMuaW5jbHVkZXMobGFiZWwpCiAgKTsKICBjb25zdCBsYWJlbHNUb1JlbW92ZSA9IGV4aXN0aW5nTGFiZWxzLmZpbHRlcigKICAgIChsYWJlbCkgPT4gaXNNYW5hZ2VkTGFiZWwobGFiZWwsIGRlcGVuZGVuY2llcy5wb2xpY3kubWFuYWdlZExhYmVsUHJlZml4ZXMpICYmICFkZXNpcmVkTGFiZWxzLmluY2x1ZGVzKGxhYmVsKQogICk7CiAgY29uc3QgZXhpc3RpbmdDb21tZW50ID0gZmluZFRyaWFnZUNvbW1lbnQoY29tbWVudHMsIGJvdExvZ2luKTsKICBpZiAoIWFwcGx5KSB7CiAgICByZXR1cm4gewogICAgICBvazogdHJ1ZSwKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIGFwcGxpZWQ6IGZhbHNlLAogICAgICBjb21tZW50QWN0aW9uOiAiZHJ5LXJ1biIsCiAgICAgIGRlY2lzaW9uLAogICAgICBwcm9wb3NlZENvbW1lbnQsCiAgICAgIC4uLndhcm5pbmdzLmxlbmd0aCA+IDAgPyB7IHdhcm5pbmdzIH0gOiB7fQogICAgfTsKICB9CiAgYXdhaXQgZW5zdXJlTGFiZWxzKAogICAgZGVwZW5kZW5jaWVzLmlzc3VlcywKICAgIHJlcG9zaXRvcnksCiAgICBkZWNpc2lvbi5sYWJlbHMsCiAgICBkZXBlbmRlbmNpZXMucG9saWN5CiAgKTsKICBhd2FpdCBkZXBlbmRlbmNpZXMuaXNzdWVzLmFkZExhYmVscyhyZXBvc2l0b3J5LCBpc3N1ZU51bWJlciwgbGFiZWxzVG9BZGQpOwogIGZvciAoY29uc3QgbGFiZWwgb2YgbGFiZWxzVG9SZW1vdmUpIHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy5pc3N1ZXMucmVtb3ZlTGFiZWwocmVwb3NpdG9yeSwgaXNzdWVOdW1iZXIsIGxhYmVsKTsKICB9CiAgbGV0IGNvbW1lbnRBY3Rpb24gPSAidW5jaGFuZ2VkIjsKICBpZiAoIWV4aXN0aW5nQ29tbWVudCkgewogICAgYXdhaXQgZGVwZW5kZW5jaWVzLmlzc3Vlcy5jcmVhdGVDb21tZW50KAogICAgICByZXBvc2l0b3J5LAogICAgICBpc3N1ZU51bWJlciwKICAgICAgcHJvcG9zZWRDb21tZW50CiAgICApOwogICAgY29tbWVudEFjdGlvbiA9ICJjcmVhdGVkIjsKICB9IGVsc2UgaWYgKGV4aXN0aW5nQ29tbWVudC5ib2R5ICE9PSBwcm9wb3NlZENvbW1lbnQpIHsKICAgIGF3YWl0IGRlcGVuZGVuY2llcy5pc3N1ZXMudXBkYXRlQ29tbWVudCgKICAgICAgcmVwb3NpdG9yeSwKICAgICAgaXNzdWVOdW1iZXIsCiAgICAgIGV4aXN0aW5nQ29tbWVudC5pZCwKICAgICAgcHJvcG9zZWRDb21tZW50CiAgICApOwogICAgY29tbWVudEFjdGlvbiA9ICJ1cGRhdGVkIjsKICB9CiAgcmV0dXJuIHsKICAgIG9rOiB0cnVlLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgYXBwbGllZDogdHJ1ZSwKICAgIGNvbW1lbnRBY3Rpb24sCiAgICBkZWNpc2lvbiwKICAgIC4uLndhcm5pbmdzLmxlbmd0aCA+IDAgPyB7IHdhcm5pbmdzIH0gOiB7fQogIH07Cn0KYXN5bmMgZnVuY3Rpb24gbG9hZENhbmRpZGF0ZXMoaXNzdWVzLCByZXBvc2l0b3J5LCBpc3N1ZTIsIGxpbWl0KSB7CiAgdHJ5IHsKICAgIHJldHVybiB7CiAgICAgIGNhbmRpZGF0ZXM6IGF3YWl0IGlzc3Vlcy5zZWFyY2hDYW5kaWRhdGVzKHJlcG9zaXRvcnksIGlzc3VlMiwgbGltaXQpLAogICAgICB3YXJuaW5nczogW10KICAgIH07CiAgfSBjYXRjaCAoZXJyb3IpIHsKICAgIHJldHVybiB7CiAgICAgIGNhbmRpZGF0ZXM6IFtdLAogICAgICB3YXJuaW5nczogWwogICAgICAgIGBjYW5kaWRhdGUgc2VhcmNoIGZhaWxlZDsgZHVwbGljYXRlIGNsYWltcyB3aWxsIGJlIHJlamVjdGVkOiAke2Vycm9yTWVzc2FnZShlcnJvcil9YAogICAgICBdCiAgICB9OwogIH0KfQpmdW5jdGlvbiBoYXNDdXJyZW50VHJpYWdlQ29tbWVudChjb21tZW50cywgaXNzdWVOdW1iZXIsIGZpbmdlcnByaW50LCBib3RMb2dpbikgewogIGNvbnN0IG1hcmtlciA9IGNvbW1lbnRNYXJrZXIoaXNzdWVOdW1iZXIsIGZpbmdlcnByaW50KTsKICByZXR1cm4gY29tbWVudHMuc29tZSgKICAgIChjb21tZW50KSA9PiBpc01hbmFnZWRUcmlhZ2VDb21tZW50KGNvbW1lbnQsIGJvdExvZ2luKSAmJiAoY29tbWVudC5ib2R5ID09PSBtYXJrZXIgfHwgY29tbWVudC5ib2R5LnN0YXJ0c1dpdGgoYCR7bWFya2VyfQpgKSkKICApOwp9CmZ1bmN0aW9uIGZpbmRUcmlhZ2VDb21tZW50KGNvbW1lbnRzLCBib3RMb2dpbikgewogIHJldHVybiBjb21tZW50cy5maW5kKAogICAgKGNvbW1lbnQpID0+IGlzTWFuYWdlZFRyaWFnZUNvbW1lbnQoY29tbWVudCwgYm90TG9naW4pICYmIGlzSXNzdWVUcmlhZ2VDb21tZW50KGNvbW1lbnQuYm9keSkKICApOwp9CmZ1bmN0aW9uIGlzTWFuYWdlZFRyaWFnZUNvbW1lbnQoY29tbWVudCwgYm90TG9naW4pIHsKICBjb25zdCBleHBlY3RlZExvZ2luID0gYm90TG9naW4/LnRyaW0oKS50b0xvd2VyQ2FzZSgpOwogIHJldHVybiBCb29sZWFuKAogICAgZXhwZWN0ZWRMb2dpbiAmJiBjb21tZW50LnVzZXI/LmxvZ2luLnRvTG93ZXJDYXNlKCkgPT09IGV4cGVjdGVkTG9naW4KICApOwp9CmZ1bmN0aW9uIHNlbGVjdENvbnRleHRDb21tZW50cyhjb21tZW50cywgYm90TG9naW4pIHsKICByZXR1cm4gY29tbWVudHMuZmlsdGVyKAogICAgKGNvbW1lbnQpID0+ICFpc01hbmFnZWRUcmlhZ2VDb21tZW50KGNvbW1lbnQsIGJvdExvZ2luKSB8fCAhaXNJc3N1ZVRyaWFnZUNvbW1lbnQoY29tbWVudC5ib2R5KQogICkuc29ydCgobGVmdCwgcmlnaHQpID0+IGxlZnQuaWQgLSByaWdodC5pZCkuc2xpY2UoLTUwKS5tYXAoKGNvbW1lbnQpID0+ICh7CiAgICAuLi5jb21tZW50LAogICAgYm9keTogdHJ1bmNhdGVUZXh0KGNvbW1lbnQuYm9keSwgNGUzKQogIH0pKTsKfQpmdW5jdGlvbiByZXF1aXJlZEJvdExvZ2luKGFwcGx5LCBib3RMb2dpbikgewogIGNvbnN0IG5vcm1hbGl6ZWQgPSBib3RMb2dpbj8udHJpbSgpOwogIGlmIChhcHBseSAmJiAhbm9ybWFsaXplZCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJwcm92aWRlciBib3QgdXNlcm5hbWUgaXMgcmVxdWlyZWQgaW4gYXBwbHkgbW9kZSIpOwogIH0KICByZXR1cm4gbm9ybWFsaXplZCB8fCB2b2lkIDA7Cn0KZnVuY3Rpb24gaXNNYW5hZ2VkTGFiZWwobGFiZWwsIG1hbmFnZWRQcmVmaXhlcykgewogIHJldHVybiBtYW5hZ2VkUHJlZml4ZXMuc29tZSgocHJlZml4KSA9PiBsYWJlbC5zdGFydHNXaXRoKHByZWZpeCkpOwp9CmZ1bmN0aW9uIGhhc1NraXBMYWJlbChsYWJlbHMsIHNraXBMYWJlbHMpIHsKICBjb25zdCBub3JtYWxpemVkU2tpcExhYmVscyA9IG5ldyBTZXQoCiAgICBza2lwTGFiZWxzLm1hcCgobGFiZWwpID0+IGxhYmVsLnRyaW0oKS50b0xvd2VyQ2FzZSgpKQogICk7CiAgcmV0dXJuIGxhYmVscy5zb21lKAogICAgKGxhYmVsKSA9PiBub3JtYWxpemVkU2tpcExhYmVscy5oYXMobGFiZWwudHJpbSgpLnRvTG93ZXJDYXNlKCkpCiAgKTsKfQphc3luYyBmdW5jdGlvbiBlbnN1cmVMYWJlbHMoaXNzdWVzLCByZXBvc2l0b3J5LCBsYWJlbHMsIHBvbGljeSkgewogIGZvciAoY29uc3QgbGFiZWwgb2YgbGFiZWxzKSB7CiAgICBhd2FpdCBpc3N1ZXMuZW5zdXJlTGFiZWwoCiAgICAgIHJlcG9zaXRvcnksCiAgICAgIGxhYmVsLAogICAgICBwb2xpY3kubGFiZWxDb2xvcnNbbGFiZWxdID8/ICJlZGVkZWQiLAogICAgICBwb2xpY3kubGFiZWxEZXNjcmlwdGlvbnNbbGFiZWxdCiAgICApOwogIH0KfQoKLy8gc3JjL2lzc3VlLXRyaWFnZS9tYWluLnRzCmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7CiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlQXJndW1lbnRzKHByb2Nlc3MuYXJndi5zbGljZSgyKSk7CiAgY29uc3QgcG9saWN5ID0gYXdhaXQgbG9hZFBvbGljeSgpOwogIGNvbnN0IGFwcGx5ID0gZW52Qm9vbGVhbihwcm9jZXNzLmVudi5JU1NVRV9UUklBR0VfQVBQTFkpOwogIGFzc2VydEJvdW5kSXNzdWVUYXJnZXQoCiAgICBvcHRpb25zLnJlcG9zaXRvcnksCiAgICBvcHRpb25zLmlzc3VlTnVtYmVyLAogICAgYXBwbHksCiAgICBwcm9jZXNzLmVudgogICk7CiAgY29uc3QgdG9rZW4gPSBhd2FpdCByZXNvbHZlR2l0SHViVG9rZW4ob3B0aW9ucy5yZXBvc2l0b3J5KTsKICBjb25zdCBpc3N1ZXMgPSBuZXcgR2l0SHViQ2xpZW50KHsKICAgIC4uLnRva2VuID8geyB0b2tlbiB9IDoge30sCiAgICAuLi5wcm9jZXNzLmVudi5HSVRIVUJfQVBJX1VSTCA/IHsgYmFzZVVybDogcHJvY2Vzcy5lbnYuR0lUSFVCX0FQSV9VUkwgfSA6IHt9CiAgfSk7CiAgY29uc3QgZGVwZW5kZW5jaWVzID0gewogICAgaXNzdWVzLAogICAgcG9saWN5LAogICAgLi4ucHJvY2Vzcy5lbnYuR0lUSFVCX0JPVF9MT0dJTiA/IHsgYm90TG9naW46IHByb2Nlc3MuZW52LkdJVEhVQl9CT1RfTE9HSU4gfSA6IHt9CiAgfTsKICBjb25zdCByZXN1bHQgPSBvcHRpb25zLmNvbW1hbmQgPT09ICJwcmVwYXJlIiA/IGF3YWl0IHByZXBhcmVJc3N1ZVRyaWFnZSgKICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgIG9wdGlvbnMuaXNzdWVOdW1iZXIsCiAgICBkZXBlbmRlbmNpZXMKICApIDogYXdhaXQgYXBwbHlJc3N1ZVRyaWFnZSgKICAgIG9wdGlvbnMucmVwb3NpdG9yeSwKICAgIG9wdGlvbnMuaXNzdWVOdW1iZXIsCiAgICBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlMihvcHRpb25zLmFuYWx5c2lzRmlsZSwgInV0ZjgiKSksCiAgICBhcHBseSwKICAgIGRlcGVuZGVuY2llcwogICk7CiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkocmVzdWx0LCBudWxsLCAyKX0KYCk7Cn0KYXN5bmMgZnVuY3Rpb24gbG9hZFBvbGljeSgpIHsKICBjb25zdCBlbWJlZGRlZCA9IHByb2Nlc3MuZW52LldPUktGTE9XX1BPTElDWV9KU09OPy50cmltKCk7CiAgaWYgKGVtYmVkZGVkKSB7CiAgICB0cnkgewogICAgICByZXR1cm4gdHJpYWdlUG9saWN5U2NoZW1hLnBhcnNlKEpTT04ucGFyc2UoZW1iZWRkZWQpKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigKICAgICAgICBgZmFpbGVkIHRvIGxvYWQgZW1iZWRkZWQgdHJpYWdlIHBvbGljeTogJHtlcnJvck1lc3NhZ2UoZXJyb3IpfWAKICAgICAgKTsKICAgIH0KICB9CiAgcmV0dXJuIGxvYWRKc29uRnJvbUNhbmRpZGF0ZXMoCiAgICBbCiAgICAgIGZpbGVVUkxUb1BhdGgobmV3IFVSTCgiLi4vcG9saWN5Lmpzb24iLCBpbXBvcnQubWV0YS51cmwpKSwKICAgICAgcGF0aC5yZXNvbHZlKCJhZ2VudHMvaXNzdWUtdHJpYWdlL3BvbGljeS5qc29uIikKICAgIF0sCiAgICAodmFsdWUpID0+IHRyaWFnZVBvbGljeVNjaGVtYS5wYXJzZSh2YWx1ZSksCiAgICAiZmFpbGVkIHRvIGxvYWQgaXNzdWUgdHJpYWdlIHBvbGljeSIKICApOwp9CmZ1bmN0aW9uIHBhcnNlQXJndW1lbnRzKGFyZ3MpIHsKICBjb25zdCBjb21tYW5kID0gYXJncy5zaGlmdCgpOwogIGlmIChjb21tYW5kICE9PSAicHJlcGFyZSIgJiYgY29tbWFuZCAhPT0gImFwcGx5IikgewogICAgdGhyb3cgbmV3IEVycm9yKCJmaXJzdCBhcmd1bWVudCBtdXN0IGJlIHByZXBhcmUgb3IgYXBwbHkiKTsKICB9CiAgbGV0IHJlcG9zaXRvcnkgPSAiIjsKICBsZXQgaXNzdWVOdW1iZXIgPSAwOwogIGxldCBhbmFseXNpc0ZpbGUgPSAiIjsKICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgYXJncy5sZW5ndGg7IGluZGV4ICs9IDEpIHsKICAgIGNvbnN0IGFyZ3VtZW50ID0gYXJnc1tpbmRleF07CiAgICBpZiAoYXJndW1lbnQgPT09ICItLXJlcG9zaXRvcnkiKSB7CiAgICAgIHJlcG9zaXRvcnkgPSByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpOwogICAgfSBlbHNlIGlmIChhcmd1bWVudCA9PT0gIi0taXNzdWUiKSB7CiAgICAgIGNvbnN0IHJhdyA9IHJlcXVpcmVkQXJndW1lbnRWYWx1ZShhcmdzLCArK2luZGV4LCBhcmd1bWVudCk7CiAgICAgIGlzc3VlTnVtYmVyID0gTnVtYmVyLnBhcnNlSW50KHJhdywgMTApOwogICAgICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlzc3VlTnVtYmVyKSB8fCBpc3N1ZU51bWJlciA8PSAwKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCItLWlzc3VlIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIik7CiAgICAgIH0KICAgIH0gZWxzZSBpZiAoYXJndW1lbnQgPT09ICItLWFuYWx5c2lzIikgewogICAgICBhbmFseXNpc0ZpbGUgPSByZXF1aXJlZEFyZ3VtZW50VmFsdWUoYXJncywgKytpbmRleCwgYXJndW1lbnQpOwogICAgfSBlbHNlIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKGB1bmtub3duIGFyZ3VtZW50OiAke2FyZ3VtZW50fWApOwogICAgfQogIH0KICBpZiAoIWlzUmVwb3NpdG9yeVNsdWcocmVwb3NpdG9yeSkpIHsKICAgIHRocm93IG5ldyBFcnJvcigiLS1yZXBvc2l0b3J5IG11c3QgdXNlIG93bmVyL3JlcG9zaXRvcnkgZm9ybWF0Iik7CiAgfQogIGlmIChpc3N1ZU51bWJlciA8PSAwKSB0aHJvdyBuZXcgRXJyb3IoIi0taXNzdWUgaXMgcmVxdWlyZWQiKTsKICBpZiAoY29tbWFuZCA9PT0gImFwcGx5IiAmJiAhYW5hbHlzaXNGaWxlKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIi0tYW5hbHlzaXMgaXMgcmVxdWlyZWQgZm9yIGFwcGx5Iik7CiAgfQogIHJldHVybiB7CiAgICBjb21tYW5kLAogICAgcmVwb3NpdG9yeSwKICAgIGlzc3VlTnVtYmVyLAogICAgLi4uYW5hbHlzaXNGaWxlID8geyBhbmFseXNpc0ZpbGUgfSA6IHt9CiAgfTsKfQptYWluKCkuY2F0Y2goKGVycm9yKSA9PiB7CiAgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYGlzc3VlIHRyaWFnZSBmYWlsZWQ6ICR7ZXJyb3JNZXNzYWdlKGVycm9yKX0KYCk7CiAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7Cn0pOwo="; const WORKFLOW_POLICY_JSON = "{\"version\":1,\"duplicateConfidenceThreshold\":0.92,\"classificationConfidenceThreshold\":0.75,\"priorityConfidenceThreshold\":0.8,\"maxCandidates\":20,\"maxRelatedIssues\":5,\"skipLabels\":[\"skip-triage\"],\"managedLabelPrefixes\":[\"priority:\",\"triage:\"],\"classificationLabels\":{\"bug\":\"bug\",\"enhancement\":\"enhancement\",\"documentation\":\"documentation\",\"question\":\"question\"},\"labelColors\":{\"bug\":\"d73a4a\",\"documentation\":\"0075ca\",\"enhancement\":\"a2eeef\",\"question\":\"d876e3\",\"priority:P0\":\"b60205\",\"priority:P1\":\"d93f0b\",\"priority:P2\":\"fbca04\",\"priority:P3\":\"0e8a16\",\"priority:pending\":\"c5def5\",\"triage:done\":\"0e8a16\",\"triage:needs-info\":\"fbca04\",\"duplicate\":\"cfd3d7\"},\"labelDescriptions\":{\"bug\":\"Something isn't working\",\"documentation\":\"Improvements or additions to documentation\",\"enhancement\":\"New feature or request\",\"question\":\"Further information is requested\",\"priority:P0\":\"Automated triage: critical and immediate impact\",\"priority:P1\":\"Automated triage: high-priority impact\",\"priority:P2\":\"Automated triage: significant impact\",\"priority:P3\":\"Automated triage: supported low-impact work\",\"priority:pending\":\"Automated triage: priority needs more evidence\",\"triage:done\":\"Automated initial triage completed\",\"triage:needs-info\":\"Automated triage needs reporter information\",\"duplicate\":\"This issue or pull request already exists\"}}"; -const WORKFLOW_TOOL_CHUNK_SIZE = 60000; - -function workflowToolEnvironment() { - const env = {}; - for ( - let offset = 0, index = 0; - offset < WORKFLOW_TOOL_BASE64.length; - offset += WORKFLOW_TOOL_CHUNK_SIZE, index += 1 - ) { - env[`WORKFLOW_TOOL_CHUNK_${String(index).padStart(4, "0")}`] = - WORKFLOW_TOOL_BASE64.slice(offset, offset + WORKFLOW_TOOL_CHUNK_SIZE); - } - return env; -} +const WORKFLOW_TOOL_PATH = + "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs"; const ANALYSIS_SCHEMA = { type: "object", @@ -119,9 +106,7 @@ function runTool(command, repository, issueNumber, submission, senderLogin) { const result = scheduler.shell( [ "set -eu", - 'workflow_tool_dir="$(mktemp -d)"', - 'workflow_tool="$workflow_tool_dir/issue-triage.mjs"', - 'node -e \'const fs=require("node:fs"); const source=Object.keys(process.env).filter((key)=>key.startsWith("WORKFLOW_TOOL_CHUNK_")).sort().map((key)=>process.env[key]).join(""); fs.writeFileSync(process.argv[1], Buffer.from(source, "base64"))\' "$workflow_tool"', + `workflow_tool="${WORKFLOW_TOOL_PATH}"`, 'sender_login=$(printf "%s" "$TRIAGE_SENDER_LOGIN" | tr "[:upper:]" "[:lower:]")', 'bot_login=$(printf "%s" "${GITHUB_BOT_LOGIN:-}" | tr "[:upper:]" "[:lower:]")', 'allowed_repository="${GITHUB_ALLOWED_REPOSITORY:-}"', @@ -147,7 +132,6 @@ function runTool(command, repository, issueNumber, submission, senderLogin) { TRIAGE_REPOSITORY: repository, TRIAGE_ISSUE: String(issueNumber), WORKFLOW_POLICY_JSON, - ...workflowToolEnvironment(), TRIAGE_SUBMISSION: submission ? JSON.stringify(submission) : "", TRIAGE_SENDER_LOGIN: senderLogin || "", }, diff --git a/agents/issue-triage/tool/main.mjs b/agents/issue-triage/tool/main.mjs new file mode 100644 index 0000000..365be08 --- /dev/null +++ b/agents/issue-triage/tool/main.mjs @@ -0,0 +1,6047 @@ +// Generated by scripts/build-tools.ts. Do not edit directly. +var __defProp = Object.defineProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; + +// src/issue-triage/main.ts +import { readFile as readFile2 } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +// src/github/app-auth.ts +import { sign } from "node:crypto"; + +// src/github/fetch-retry.ts +var MAX_ATTEMPTS = 3; +var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([502, 503, 504]); +async function fetchWithRetry(options) { + const attempts = options.retryable ? MAX_ATTEMPTS : 1; + let lastError; + for (let attempt = 1; attempt <= attempts; attempt += 1) { + try { + const response = await options.request(options.input, options.init); + if (attempt === attempts || !RETRYABLE_STATUS_CODES.has(response.status)) { + return response; + } + await response.body?.cancel().catch(() => void 0); + } catch (error) { + lastError = error; + if (attempt === attempts) { + throw new Error( + `${options.operation} transport failed after ${attemptLabel(attempts)}`, + { cause: error } + ); + } + } + await (options.sleep ?? sleep)(retryDelayMilliseconds(attempt)); + } + throw new Error(`${options.operation} transport failed`, { + cause: lastError + }); +} +function attemptLabel(attempts) { + return `${attempts} ${attempts === 1 ? "attempt" : "attempts"}`; +} +function retryDelayMilliseconds(attempt) { + const exponential = 250 * 2 ** (attempt - 1); + return exponential + Math.floor(Math.random() * exponential); +} +function sleep(milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} + +// src/github/app-auth.ts +var DEFAULT_GITHUB_API_URL = "https://api.github.com"; +var GITHUB_API_VERSION = "2022-11-28"; +async function resolveGitHubToken(repository, env = process.env, dependencies = {}) { + const configuredToken = env.GITHUB_TOKEN?.trim() ?? ""; + if (configuredToken) return configuredToken; + const clientID = env.GITHUB_APP_CLIENT_ID?.trim() ?? ""; + const appID = env.GITHUB_APP_ID?.trim() ?? ""; + const privateKeyBase64 = env.GITHUB_APP_PRIVATE_KEY_BASE64?.trim() ?? ""; + const configuredInstallationID = env.GITHUB_APP_INSTALLATION_ID?.trim() ?? ""; + const hasAppConfiguration = Boolean( + clientID || appID || privateKeyBase64 || configuredInstallationID + ); + if (!hasAppConfiguration) return ""; + const issuer = clientID || appID; + if (!issuer) { + throw new Error( + "GitHub App authentication requires GITHUB_APP_CLIENT_ID or GITHUB_APP_ID" + ); + } + if (!privateKeyBase64) { + throw new Error( + "GitHub App authentication requires GITHUB_APP_PRIVATE_KEY_BASE64" + ); + } + const privateKey = decodePrivateKey(privateKeyBase64); + const jwt = createAppJWT( + issuer, + privateKey, + dependencies.now?.() ?? Date.now() + ); + const baseUrl = (env.GITHUB_API_URL?.trim() || DEFAULT_GITHUB_API_URL).replace(/\/+$/, ""); + const request = dependencies.fetch ?? fetch; + const installationID = configuredInstallationID ? validateInstallationID(configuredInstallationID) : await findInstallationID( + baseUrl, + repository, + jwt, + request, + dependencies.sleep + ); + const tokenPath = `/app/installations/${installationID}/access_tokens`; + const response = await fetchWithRetry({ + request, + input: `${baseUrl}${tokenPath}`, + init: { + method: "POST", + headers: appHeaders(jwt) + }, + operation: `GitHub App POST ${tokenPath}`, + retryable: true, + ...dependencies.sleep ? { sleep: dependencies.sleep } : {} + }); + if (!response.ok) { + throw githubAppResponseError("installation token request", response); + } + const value = await response.json(); + const token = value.token?.trim() ?? ""; + if (!token) { + throw new Error("GitHub App installation token response has no token"); + } + return token; +} +function createAppJWT(issuer, privateKey, nowMilliseconds) { + const now = Math.floor(nowMilliseconds / 1e3); + const header = encodeJWTPart({ alg: "RS256", typ: "JWT" }); + const payload = encodeJWTPart({ + iat: now - 60, + exp: now + 9 * 60, + iss: issuer + }); + const unsignedToken = `${header}.${payload}`; + let signature; + try { + signature = sign("RSA-SHA256", Buffer.from(unsignedToken), privateKey); + } catch { + throw new Error( + "GITHUB_APP_PRIVATE_KEY_BASE64 is not a valid RSA private key" + ); + } + return `${unsignedToken}.${signature.toString("base64url")}`; +} +async function findInstallationID(baseUrl, repository, jwt, request, sleepDependency) { + const path2 = `/repos/${repositoryPath(repository)}/installation`; + const response = await fetchWithRetry({ + request, + input: `${baseUrl}${path2}`, + init: { + method: "GET", + headers: appHeaders(jwt) + }, + operation: `GitHub App GET ${path2}`, + retryable: true, + ...sleepDependency ? { sleep: sleepDependency } : {} + }); + if (!response.ok) { + throw githubAppResponseError("installation lookup", response); + } + const value = await response.json(); + if (!Number.isSafeInteger(value.id) || (value.id ?? 0) <= 0) { + throw new Error("GitHub App installation response has no valid ID"); + } + return String(value.id); +} +function appHeaders(jwt) { + return { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${jwt}`, + "X-GitHub-Api-Version": GITHUB_API_VERSION, + "User-Agent": "engineering-agent-workflows/github-app-auth" + }; +} +function decodePrivateKey(value) { + let decoded; + try { + decoded = Buffer.from(value, "base64").toString("utf8").trim(); + } catch { + throw new Error("GITHUB_APP_PRIVATE_KEY_BASE64 is not valid base64"); + } + if (!/^-----BEGIN (?:RSA )?PRIVATE KEY-----/.test(decoded)) { + throw new Error( + "GITHUB_APP_PRIVATE_KEY_BASE64 must decode to a PEM private key" + ); + } + return decoded; +} +function validateInstallationID(value) { + if (!/^[1-9][0-9]*$/.test(value)) { + throw new Error("GITHUB_APP_INSTALLATION_ID must be a positive integer"); + } + return value; +} +function repositoryPath(repository) { + const parts = repository.split("/"); + if (parts.length !== 2 || parts.some((part) => !part.trim())) { + throw new Error(`invalid GitHub repository: ${repository}`); + } + return parts.map(encodeURIComponent).join("/"); +} +function encodeJWTPart(value) { + return Buffer.from(JSON.stringify(value)).toString("base64url"); +} +function githubAppResponseError(operation, response) { + const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`; + return new Error(`GitHub App ${operation} failed with ${status}`); +} + +// src/issues/search.ts +function issueSearchText(title) { + return title.replace(/^\[[^\]]+\]\s*:?\s*/, "").replace(/["'`:+(){}[\]\\]/g, " ").replace(/\s+/g, " ").trim().slice(0, 120); +} + +// src/runtime/text.ts +function truncateText(value, max) { + return value.length <= max ? value : value.slice(0, max); +} + +// src/github/client.ts +var GitHubClient = class { + #token; + #baseUrl; + #fetch; + #sleep; + constructor(options = {}) { + this.#token = options.token?.trim() ?? ""; + this.#baseUrl = (options.baseUrl ?? "https://api.github.com").replace( + /\/+$/, + "" + ); + this.#fetch = options.fetch ?? fetch; + this.#sleep = options.sleep; + } + async getIssue(repository, issueNumber) { + const issue2 = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}` + ); + if (issue2.pull_request) { + throw new Error("GitHub pull request payload is not an Issue"); + } + return normalizeIssue(issue2); + } + async searchCandidates(repository, issue2, limit) { + const title = issueSearchText(issue2.title); + if (!title) return []; + const query = new URLSearchParams({ + q: `repo:${repository} is:issue in:title ${title}`, + per_page: String(Math.min(Math.max(limit + 1, 1), 100)) + }); + const response = await this.#request( + "GET", + `/search/issues?${query.toString()}` + ); + return (response.items ?? []).filter( + (candidate) => candidate.number !== issue2.number && !candidate.pull_request + ).slice(0, limit).map((candidate) => ({ + number: candidate.number, + title: candidate.title, + body: truncateText(candidate.body ?? "", 4e3), + state: candidate.state, + labels: labelNames(candidate.labels), + url: candidate.html_url + })); + } + async listComments(repository, issueNumber) { + const comments = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/comments?per_page=100&page=${page}` + ); + comments.push(...batch.map(normalizeComment)); + if (batch.length < 100) return comments; + } + } + async ensureLabel(repository, name, color, description) { + const path2 = `/repos/${repositoryPath2(repository)}/labels/${encodeURIComponent(name)}`; + const response = await this.#rawRequest("GET", path2); + if (response.ok) return; + if (response.status !== 404) { + throw await responseError("GET", path2, response); + } + await this.#request("POST", `/repos/${repositoryPath2(repository)}/labels`, { + name, + color: normalizeColor(color), + description: description?.trim() || "Managed by engineering-agent-workflows" + }); + } + async getRepositoryDefaultBranch(repository) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}` + ); + const branch = value.default_branch?.trim(); + if (!branch) throw new Error("GitHub repository has no default branch"); + return branch; + } + async getPullRequest(repository, pullRequestNumber) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}` + ); + return normalizePullRequest(value); + } + async listOpenPullRequests(repository) { + const values = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls?state=open&per_page=100&page=${page}` + ); + values.push(...batch.map(normalizePullRequest)); + if (batch.length < 100) return values; + } + } + async listReviewComments(repository, pullRequestNumber) { + const comments = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}/comments?per_page=100&page=${page}` + ); + comments.push(...batch.map(normalizeReviewComment)); + if (batch.length < 100) return comments; + } + } + async getPullRequestReview(repository, pullRequestNumber, reviewId) { + const review = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls/${pullRequestNumber}/reviews/${reviewId}` + ); + return normalizePullRequestReview(review); + } + async listCheckRuns(repository, ref) { + if (!/^[0-9a-f]{40}$/.test(ref)) { + throw new Error("invalid GitHub check run ref"); + } + const runs = []; + for (let page = 1; ; page += 1) { + const value = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/commits/${ref}/check-runs?per_page=100&page=${page}` + ); + const batch = value.check_runs ?? []; + runs.push(...batch.map(normalizeCheckRun)); + if (batch.length < 100) return runs; + } + } + async listCheckRunAnnotations(repository, checkRunId) { + if (!Number.isSafeInteger(checkRunId) || checkRunId <= 0) { + throw new Error("invalid GitHub check run ID"); + } + const annotations = []; + for (let page = 1; ; page += 1) { + const batch = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/check-runs/${checkRunId}/annotations?per_page=100&page=${page}` + ); + annotations.push(...batch.map(normalizeCheckRunAnnotation)); + if (batch.length < 100) return annotations; + } + } + async listOpenPullRequestsByHead(repository, branch) { + const owner = repository.split("/")[0]; + const query = new URLSearchParams({ + state: "open", + head: `${owner}:${branch}`, + per_page: "100" + }); + const values = await this.#request( + "GET", + `/repos/${repositoryPath2(repository)}/pulls?${query.toString()}` + ); + return values.map(normalizePullRequest); + } + async createDraftPullRequest(repository, input) { + const value = await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/pulls`, + { ...input, draft: true } + ); + return normalizePullRequest(value); + } + async addLabels(repository, issueNumber, labels) { + if (labels.length === 0) return; + await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/labels`, + { labels } + ); + } + async removeLabel(repository, issueNumber, label) { + const path2 = `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`; + const response = await this.#rawRequest("DELETE", path2); + if (!response.ok && response.status !== 404) { + throw await responseError("DELETE", path2, response); + } + } + async createComment(repository, issueNumber, body) { + const comment = await this.#request( + "POST", + `/repos/${repositoryPath2(repository)}/issues/${issueNumber}/comments`, + { body } + ); + return normalizeComment(comment); + } + async updateComment(repository, _issueNumber, commentID, body) { + const comment = await this.#request( + "PATCH", + `/repos/${repositoryPath2(repository)}/issues/comments/${commentID}`, + { body } + ); + return normalizeComment(comment); + } + async #request(method, path2, body) { + const response = await this.#rawRequest(method, path2, body); + if (!response.ok) throw await responseError(method, path2, response); + return await response.json(); + } + #rawRequest(method, path2, body) { + const headers = { + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "engineering-agent-workflows/issue-triage" + }; + if (this.#token) headers.Authorization = `Bearer ${this.#token}`; + if (body !== void 0) headers["Content-Type"] = "application/json"; + return fetchWithRetry({ + request: this.#fetch, + input: `${this.#baseUrl}${path2}`, + init: { + method, + headers, + ...body === void 0 ? {} : { body: JSON.stringify(body) } + }, + operation: `GitHub API ${method} ${path2}`, + retryable: method === "GET", + ...this.#sleep ? { sleep: this.#sleep } : {} + }); + } +}; +function repositoryPath2(repository) { + const parts = repository.split("/"); + if (parts.length !== 2 || parts.some((part) => !part.trim())) { + throw new Error(`invalid GitHub repository: ${repository}`); + } + return parts.map(encodeURIComponent).join("/"); +} +function normalizeIssue(issue2) { + return { + number: issue2.number, + title: issue2.title, + body: issue2.body, + state: issue2.state, + htmlUrl: issue2.html_url, + updatedAt: issue2.updated_at, + labels: labelNames(issue2.labels), + ...issue2.user ? { user: normalizeUser(issue2.user) } : {} + }; +} +function normalizeComment(comment) { + return { + id: comment.id, + body: comment.body, + ...comment.html_url ? { htmlUrl: comment.html_url } : {}, + ...comment.created_at ? { createdAt: comment.created_at } : {}, + ...comment.user ? { user: normalizeUser(comment.user) } : {} + }; +} +function normalizePullRequest(value) { + return { + number: value.number, + url: value.html_url, + state: value.state, + draft: value.draft ?? false, + head: value.head.ref, + ...value.head.sha ? { headSha: value.head.sha } : {}, + ...value.head.repo?.full_name ? { headRepository: value.head.repo.full_name } : {}, + base: value.base.ref + }; +} +function normalizeReviewComment(comment) { + return { + id: comment.id, + body: comment.body, + path: comment.path, + ...comment.user ? { user: normalizeUser(comment.user) } : {}, + ...comment.html_url ? { htmlUrl: comment.html_url } : {}, + ...comment.created_at ? { createdAt: comment.created_at } : {}, + ...comment.line != null ? { line: comment.line } : {}, + ...comment.original_line != null ? { originalLine: comment.original_line } : {}, + ...comment.start_line != null ? { startLine: comment.start_line } : {}, + ...comment.original_start_line != null ? { originalStartLine: comment.original_start_line } : {}, + ...comment.side ? { side: comment.side } : {}, + ...comment.start_side ? { startSide: comment.start_side } : {}, + ...comment.diff_hunk ? { diffHunk: comment.diff_hunk } : {}, + ...comment.commit_id ? { commitId: comment.commit_id } : {}, + ...comment.original_commit_id ? { originalCommitId: comment.original_commit_id } : {}, + ...comment.in_reply_to_id !== void 0 ? { inReplyToId: comment.in_reply_to_id } : {}, + ...comment.pull_request_review_id !== void 0 ? { pullRequestReviewId: comment.pull_request_review_id } : {} + }; +} +function normalizePullRequestReview(review) { + return { + id: review.id, + body: review.body ?? "", + state: review.state, + commitId: review.commit_id, + authorAssociation: review.author_association, + ...review.user ? { user: normalizeUser(review.user) } : {}, + ...review.html_url ? { htmlUrl: review.html_url } : {}, + ...review.submitted_at ? { submittedAt: review.submitted_at } : {} + }; +} +function normalizeCheckRun(value) { + const checkSuiteId = value.check_suite?.id; + if (!Number.isSafeInteger(checkSuiteId) || checkSuiteId <= 0) { + throw new Error(`GitHub check run ${value.id} has no valid check suite ID`); + } + return { + id: value.id, + checkSuiteId, + name: truncateText(value.name ?? "", 300), + status: value.status, + ...value.conclusion ? { conclusion: value.conclusion } : {}, + ...value.html_url ? { htmlUrl: value.html_url } : {}, + output: { + title: truncateText(value.output?.title ?? "", 1e3), + summary: truncateText(value.output?.summary ?? "", 8e3), + text: truncateText(value.output?.text ?? "", 8e3) + } + }; +} +function normalizeCheckRunAnnotation(value) { + return { + path: truncateText(value.path ?? "", 1e3), + startLine: value.start_line, + endLine: value.end_line, + level: truncateText(value.annotation_level ?? "", 50), + message: truncateText(value.message ?? "", 2e3), + ...value.title ? { title: truncateText(value.title, 500) } : {}, + ...value.raw_details ? { rawDetails: truncateText(value.raw_details, 4e3) } : {} + }; +} +function normalizeUser(user) { + return { + login: user.login, + ...user.id !== void 0 ? { id: user.id } : {}, + ...user.type ? { type: user.type } : {} + }; +} +function labelNames(labels) { + return labels.map((label) => typeof label === "string" ? label : label.name).filter((label) => label.trim() !== ""); +} +function normalizeColor(color) { + const normalized = color.trim().replace(/^#/, ""); + return /^[0-9a-f]{6}$/i.test(normalized) ? normalized : "ededed"; +} +async function responseError(method, path2, response) { + const text = await response.text().catch(() => ""); + return new Error( + `GitHub API ${method} ${path2} failed with HTTP ${response.status}: ${truncateText(text, 1e3)}` + ); +} + +// src/issues/types.ts +function isRepositorySlug(value) { + return /^[^/\s]+\/[^/\s]+$/.test(value); +} + +// src/runtime/cli.ts +function requiredArgumentValue(args, index, name) { + const value = args[index]?.trim(); + if (!value) throw new Error(`${name} requires a value`); + return value; +} +function envBoolean(value) { + return ["1", "true", "yes", "on"].includes(value?.trim().toLowerCase() ?? ""); +} + +// src/runtime/errors.ts +function errorMessage(error) { + return describeError(error, /* @__PURE__ */ new Set(), 0); +} +function describeError(error, seen, depth) { + if (!(error instanceof Error)) return String(error); + seen.add(error); + const code = errorCode(error); + const description = depth === 0 ? error.message : `${error.name}${code ? ` [${code}]` : ""}: ${error.message}`; + if (depth >= 4 || error.cause === void 0 || seen.has(error.cause)) { + return description; + } + return `${description}; cause: ${describeError(error.cause, seen, depth + 1)}`; +} +function errorCode(error) { + if (!("code" in error)) return ""; + const value = error.code; + return typeof value === "string" || typeof value === "number" ? String(value) : ""; +} + +// src/runtime/load-json.ts +import { readFile } from "node:fs/promises"; +async function loadJsonFromCandidates(candidates, parse3, failureMessage) { + let lastError; + for (const candidate of candidates) { + try { + return parse3(JSON.parse(await readFile(candidate, "utf8"))); + } catch (error) { + lastError = error; + } + } + throw new Error(`${failureMessage}: ${errorMessage(lastError)}`); +} + +// node_modules/zod/v4/core/core.js +var _a; +// @__NO_SIDE_EFFECTS__ +function $constructor(name, initializer3, params) { + function init(inst, def) { + if (!inst._zod) { + Object.defineProperty(inst, "_zod", { + value: { + def, + constr: _, + traits: /* @__PURE__ */ new Set() + }, + enumerable: false + }); + } + if (inst._zod.traits.has(name)) { + return; + } + inst._zod.traits.add(name); + initializer3(inst, def); + const proto = _.prototype; + const keys = Object.keys(proto); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + if (!(k in inst)) { + inst[k] = proto[k].bind(inst); + } + } + } + const Parent = params?.Parent ?? Object; + class Definition extends Parent { + } + Object.defineProperty(Definition, "name", { value: name }); + function _(def) { + var _a3; + const inst = params?.Parent ? new Definition() : this; + init(inst, def); + (_a3 = inst._zod).deferred ?? (_a3.deferred = []); + for (const fn of inst._zod.deferred) { + fn(); + } + return inst; + } + Object.defineProperty(_, "init", { value: init }); + Object.defineProperty(_, Symbol.hasInstance, { + value: (inst) => { + if (params?.Parent && inst instanceof params.Parent) + return true; + return inst?._zod?.traits?.has(name); + } + }); + Object.defineProperty(_, "name", { value: name }); + return _; +} +var $ZodAsyncError = class extends Error { + constructor() { + super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); + } +}; +var $ZodEncodeError = class extends Error { + constructor(name) { + super(`Encountered unidirectional transform during encode: ${name}`); + this.name = "ZodEncodeError"; + } +}; +(_a = globalThis).__zod_globalConfig ?? (_a.__zod_globalConfig = {}); +var globalConfig = globalThis.__zod_globalConfig; +function config(newConfig) { + if (newConfig) + Object.assign(globalConfig, newConfig); + return globalConfig; +} + +// node_modules/zod/v4/core/util.js +var util_exports = {}; +__export(util_exports, { + BIGINT_FORMAT_RANGES: () => BIGINT_FORMAT_RANGES, + Class: () => Class, + NUMBER_FORMAT_RANGES: () => NUMBER_FORMAT_RANGES, + aborted: () => aborted, + allowsEval: () => allowsEval, + assert: () => assert, + assertEqual: () => assertEqual, + assertIs: () => assertIs, + assertNever: () => assertNever, + assertNotEqual: () => assertNotEqual, + assignProp: () => assignProp, + base64ToUint8Array: () => base64ToUint8Array, + base64urlToUint8Array: () => base64urlToUint8Array, + cached: () => cached, + captureStackTrace: () => captureStackTrace, + cleanEnum: () => cleanEnum, + cleanRegex: () => cleanRegex, + clone: () => clone, + cloneDef: () => cloneDef, + createTransparentProxy: () => createTransparentProxy, + defineLazy: () => defineLazy, + esc: () => esc, + escapeRegex: () => escapeRegex, + explicitlyAborted: () => explicitlyAborted, + extend: () => extend, + finalizeIssue: () => finalizeIssue, + floatSafeRemainder: () => floatSafeRemainder, + getElementAtPath: () => getElementAtPath, + getEnumValues: () => getEnumValues, + getLengthableOrigin: () => getLengthableOrigin, + getParsedType: () => getParsedType, + getSizableOrigin: () => getSizableOrigin, + hexToUint8Array: () => hexToUint8Array, + isObject: () => isObject, + isPlainObject: () => isPlainObject, + issue: () => issue, + joinValues: () => joinValues, + jsonStringifyReplacer: () => jsonStringifyReplacer, + merge: () => merge, + mergeDefs: () => mergeDefs, + normalizeParams: () => normalizeParams, + nullish: () => nullish, + numKeys: () => numKeys, + objectClone: () => objectClone, + omit: () => omit, + optionalKeys: () => optionalKeys, + parsedType: () => parsedType, + partial: () => partial, + pick: () => pick, + prefixIssues: () => prefixIssues, + primitiveTypes: () => primitiveTypes, + promiseAllObject: () => promiseAllObject, + propertyKeyTypes: () => propertyKeyTypes, + randomString: () => randomString, + required: () => required, + safeExtend: () => safeExtend, + shallowClone: () => shallowClone, + slugify: () => slugify, + stringifyPrimitive: () => stringifyPrimitive, + uint8ArrayToBase64: () => uint8ArrayToBase64, + uint8ArrayToBase64url: () => uint8ArrayToBase64url, + uint8ArrayToHex: () => uint8ArrayToHex, + unwrapMessage: () => unwrapMessage +}); +function assertEqual(val) { + return val; +} +function assertNotEqual(val) { + return val; +} +function assertIs(_arg) { +} +function assertNever(_x) { + throw new Error("Unexpected value in exhaustive check"); +} +function assert(_) { +} +function getEnumValues(entries) { + const numericValues = Object.values(entries).filter((v) => typeof v === "number"); + const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v); + return values; +} +function joinValues(array2, separator = "|") { + return array2.map((val) => stringifyPrimitive(val)).join(separator); +} +function jsonStringifyReplacer(_, value) { + if (typeof value === "bigint") + return value.toString(); + return value; +} +function cached(getter) { + const set = false; + return { + get value() { + if (!set) { + const value = getter(); + Object.defineProperty(this, "value", { value }); + return value; + } + throw new Error("cached value already set"); + } + }; +} +function nullish(input) { + return input === null || input === void 0; +} +function cleanRegex(source) { + const start = source.startsWith("^") ? 1 : 0; + const end = source.endsWith("$") ? source.length - 1 : source.length; + return source.slice(start, end); +} +function floatSafeRemainder(val, step) { + const ratio = val / step; + const roundedRatio = Math.round(ratio); + const tolerance = Number.EPSILON * Math.max(Math.abs(ratio), 1); + if (Math.abs(ratio - roundedRatio) < tolerance) + return 0; + return ratio - roundedRatio; +} +var EVALUATING = /* @__PURE__ */ Symbol("evaluating"); +function defineLazy(object2, key, getter) { + let value = void 0; + Object.defineProperty(object2, key, { + get() { + if (value === EVALUATING) { + return void 0; + } + if (value === void 0) { + value = EVALUATING; + value = getter(); + } + return value; + }, + set(v) { + Object.defineProperty(object2, key, { + value: v + // configurable: true, + }); + }, + configurable: true + }); +} +function objectClone(obj) { + return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); +} +function assignProp(target, prop, value) { + Object.defineProperty(target, prop, { + value, + writable: true, + enumerable: true, + configurable: true + }); +} +function mergeDefs(...defs) { + const mergedDescriptors = {}; + for (const def of defs) { + const descriptors = Object.getOwnPropertyDescriptors(def); + Object.assign(mergedDescriptors, descriptors); + } + return Object.defineProperties({}, mergedDescriptors); +} +function cloneDef(schema) { + return mergeDefs(schema._zod.def); +} +function getElementAtPath(obj, path2) { + if (!path2) + return obj; + return path2.reduce((acc, key) => acc?.[key], obj); +} +function promiseAllObject(promisesObj) { + const keys = Object.keys(promisesObj); + const promises = keys.map((key) => promisesObj[key]); + return Promise.all(promises).then((results) => { + const resolvedObj = {}; + for (let i = 0; i < keys.length; i++) { + resolvedObj[keys[i]] = results[i]; + } + return resolvedObj; + }); +} +function randomString(length = 10) { + const chars = "abcdefghijklmnopqrstuvwxyz"; + let str = ""; + for (let i = 0; i < length; i++) { + str += chars[Math.floor(Math.random() * chars.length)]; + } + return str; +} +function esc(str) { + return JSON.stringify(str); +} +function slugify(input) { + return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); +} +var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => { +}; +function isObject(data) { + return typeof data === "object" && data !== null && !Array.isArray(data); +} +var allowsEval = /* @__PURE__ */ cached(() => { + if (globalConfig.jitless) { + return false; + } + if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) { + return false; + } + try { + const F = Function; + new F(""); + return true; + } catch (_) { + return false; + } +}); +function isPlainObject(o) { + if (isObject(o) === false) + return false; + const ctor = o.constructor; + if (ctor === void 0) + return true; + if (typeof ctor !== "function") + return true; + const prot = ctor.prototype; + if (isObject(prot) === false) + return false; + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) { + return false; + } + return true; +} +function shallowClone(o) { + if (isPlainObject(o)) + return { ...o }; + if (Array.isArray(o)) + return [...o]; + if (o instanceof Map) + return new Map(o); + if (o instanceof Set) + return new Set(o); + return o; +} +function numKeys(data) { + let keyCount = 0; + for (const key in data) { + if (Object.prototype.hasOwnProperty.call(data, key)) { + keyCount++; + } + } + return keyCount; +} +var getParsedType = (data) => { + const t = typeof data; + switch (t) { + case "undefined": + return "undefined"; + case "string": + return "string"; + case "number": + return Number.isNaN(data) ? "nan" : "number"; + case "boolean": + return "boolean"; + case "function": + return "function"; + case "bigint": + return "bigint"; + case "symbol": + return "symbol"; + case "object": + if (Array.isArray(data)) { + return "array"; + } + if (data === null) { + return "null"; + } + if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { + return "promise"; + } + if (typeof Map !== "undefined" && data instanceof Map) { + return "map"; + } + if (typeof Set !== "undefined" && data instanceof Set) { + return "set"; + } + if (typeof Date !== "undefined" && data instanceof Date) { + return "date"; + } + if (typeof File !== "undefined" && data instanceof File) { + return "file"; + } + return "object"; + default: + throw new Error(`Unknown data type: ${t}`); + } +}; +var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]); +var primitiveTypes = /* @__PURE__ */ new Set([ + "string", + "number", + "bigint", + "boolean", + "symbol", + "undefined" +]); +function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} +function clone(inst, def, params) { + const cl = new inst._zod.constr(def ?? inst._zod.def); + if (!def || params?.parent) + cl._zod.parent = inst; + return cl; +} +function normalizeParams(_params) { + const params = _params; + if (!params) + return {}; + if (typeof params === "string") + return { error: () => params }; + if (params?.message !== void 0) { + if (params?.error !== void 0) + throw new Error("Cannot specify both `message` and `error` params"); + params.error = params.message; + } + delete params.message; + if (typeof params.error === "string") + return { ...params, error: () => params.error }; + return params; +} +function createTransparentProxy(getter) { + let target; + return new Proxy({}, { + get(_, prop, receiver) { + target ?? (target = getter()); + return Reflect.get(target, prop, receiver); + }, + set(_, prop, value, receiver) { + target ?? (target = getter()); + return Reflect.set(target, prop, value, receiver); + }, + has(_, prop) { + target ?? (target = getter()); + return Reflect.has(target, prop); + }, + deleteProperty(_, prop) { + target ?? (target = getter()); + return Reflect.deleteProperty(target, prop); + }, + ownKeys(_) { + target ?? (target = getter()); + return Reflect.ownKeys(target); + }, + getOwnPropertyDescriptor(_, prop) { + target ?? (target = getter()); + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + defineProperty(_, prop, descriptor) { + target ?? (target = getter()); + return Reflect.defineProperty(target, prop, descriptor); + } + }); +} +function stringifyPrimitive(value) { + if (typeof value === "bigint") + return value.toString() + "n"; + if (typeof value === "string") + return `"${value}"`; + return `${value}`; +} +function optionalKeys(shape) { + return Object.keys(shape).filter((k) => { + return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional"; + }); +} +var NUMBER_FORMAT_RANGES = { + safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], + int32: [-2147483648, 2147483647], + uint32: [0, 4294967295], + float32: [-34028234663852886e22, 34028234663852886e22], + float64: [-Number.MAX_VALUE, Number.MAX_VALUE] +}; +var BIGINT_FORMAT_RANGES = { + int64: [/* @__PURE__ */ BigInt("-9223372036854775808"), /* @__PURE__ */ BigInt("9223372036854775807")], + uint64: [/* @__PURE__ */ BigInt(0), /* @__PURE__ */ BigInt("18446744073709551615")] +}; +function pick(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".pick() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const newShape = {}; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + newShape[key] = currDef.shape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + }); + return clone(schema, def); +} +function omit(schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".omit() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const newShape = { ...schema._zod.def.shape }; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + delete newShape[key]; + } + assignProp(this, "shape", newShape); + return newShape; + }, + checks: [] + }); + return clone(schema, def); +} +function extend(schema, shape) { + if (!isPlainObject(shape)) { + throw new Error("Invalid input to extend: expected a plain object"); + } + const checks = schema._zod.def.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + const existingShape = schema._zod.def.shape; + for (const key in shape) { + if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) { + throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); + } + } + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const _shape = { ...schema._zod.def.shape, ...shape }; + assignProp(this, "shape", _shape); + return _shape; + } + }); + return clone(schema, def); +} +function safeExtend(schema, shape) { + if (!isPlainObject(shape)) { + throw new Error("Invalid input to safeExtend: expected a plain object"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const _shape = { ...schema._zod.def.shape, ...shape }; + assignProp(this, "shape", _shape); + return _shape; + } + }); + return clone(schema, def); +} +function merge(a, b) { + if (a._zod.def.checks?.length) { + throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); + } + const def = mergeDefs(a._zod.def, { + get shape() { + const _shape = { ...a._zod.def.shape, ...b._zod.def.shape }; + assignProp(this, "shape", _shape); + return _shape; + }, + get catchall() { + return b._zod.def.catchall; + }, + checks: b._zod.def.checks ?? [] + }); + return clone(a, def); +} +function partial(Class2, schema, mask) { + const currDef = schema._zod.def; + const checks = currDef.checks; + const hasChecks = checks && checks.length > 0; + if (hasChecks) { + throw new Error(".partial() cannot be used on object schemas containing refinements"); + } + const def = mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in oldShape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + shape[key] = Class2 ? new Class2({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + } else { + for (const key in oldShape) { + shape[key] = Class2 ? new Class2({ + type: "optional", + innerType: oldShape[key] + }) : oldShape[key]; + } + } + assignProp(this, "shape", shape); + return shape; + }, + checks: [] + }); + return clone(schema, def); +} +function required(Class2, schema, mask) { + const def = mergeDefs(schema._zod.def, { + get shape() { + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + shape[key] = new Class2({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + } else { + for (const key in oldShape) { + shape[key] = new Class2({ + type: "nonoptional", + innerType: oldShape[key] + }); + } + } + assignProp(this, "shape", shape); + return shape; + } + }); + return clone(schema, def); +} +function aborted(x, startIndex = 0) { + if (x.aborted === true) + return true; + for (let i = startIndex; i < x.issues.length; i++) { + if (x.issues[i]?.continue !== true) { + return true; + } + } + return false; +} +function explicitlyAborted(x, startIndex = 0) { + if (x.aborted === true) + return true; + for (let i = startIndex; i < x.issues.length; i++) { + if (x.issues[i]?.continue === false) { + return true; + } + } + return false; +} +function prefixIssues(path2, issues) { + return issues.map((iss) => { + var _a3; + (_a3 = iss).path ?? (_a3.path = []); + iss.path.unshift(path2); + return iss; + }); +} +function unwrapMessage(message) { + return typeof message === "string" ? message : message?.message; +} +function finalizeIssue(iss, ctx, config2) { + const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config2.customError?.(iss)) ?? unwrapMessage(config2.localeError?.(iss)) ?? "Invalid input"; + const { inst: _inst, continue: _continue, input: _input, ...rest } = iss; + rest.path ?? (rest.path = []); + rest.message = message; + if (ctx?.reportInput) { + rest.input = _input; + } + return rest; +} +function getSizableOrigin(input) { + if (input instanceof Set) + return "set"; + if (input instanceof Map) + return "map"; + if (input instanceof File) + return "file"; + return "unknown"; +} +function getLengthableOrigin(input) { + if (Array.isArray(input)) + return "array"; + if (typeof input === "string") + return "string"; + return "unknown"; +} +function parsedType(data) { + const t = typeof data; + switch (t) { + case "number": { + return Number.isNaN(data) ? "nan" : "number"; + } + case "object": { + if (data === null) { + return "null"; + } + if (Array.isArray(data)) { + return "array"; + } + const obj = data; + if (obj && Object.getPrototypeOf(obj) !== Object.prototype && "constructor" in obj && obj.constructor) { + return obj.constructor.name; + } + } + } + return t; +} +function issue(...args) { + const [iss, input, inst] = args; + if (typeof iss === "string") { + return { + message: iss, + code: "custom", + input, + inst + }; + } + return { ...iss }; +} +function cleanEnum(obj) { + return Object.entries(obj).filter(([k, _]) => { + return Number.isNaN(Number.parseInt(k, 10)); + }).map((el) => el[1]); +} +function base64ToUint8Array(base642) { + const binaryString = atob(base642); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; +} +function uint8ArrayToBase64(bytes) { + let binaryString = ""; + for (let i = 0; i < bytes.length; i++) { + binaryString += String.fromCharCode(bytes[i]); + } + return btoa(binaryString); +} +function base64urlToUint8Array(base64url2) { + const base642 = base64url2.replace(/-/g, "+").replace(/_/g, "/"); + const padding = "=".repeat((4 - base642.length % 4) % 4); + return base64ToUint8Array(base642 + padding); +} +function uint8ArrayToBase64url(bytes) { + return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +} +function hexToUint8Array(hex) { + const cleanHex = hex.replace(/^0x/, ""); + if (cleanHex.length % 2 !== 0) { + throw new Error("Invalid hex string length"); + } + const bytes = new Uint8Array(cleanHex.length / 2); + for (let i = 0; i < cleanHex.length; i += 2) { + bytes[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16); + } + return bytes; +} +function uint8ArrayToHex(bytes) { + return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join(""); +} +var Class = class { + constructor(..._args) { + } +}; + +// node_modules/zod/v4/core/errors.js +var initializer = (inst, def) => { + inst.name = "$ZodError"; + Object.defineProperty(inst, "_zod", { + value: inst._zod, + enumerable: false + }); + Object.defineProperty(inst, "issues", { + value: def, + enumerable: false + }); + inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "toString", { + value: () => inst.message, + enumerable: false + }); +}; +var $ZodError = $constructor("$ZodError", initializer); +var $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error }); +function flattenError(error, mapper = (issue2) => issue2.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of error.issues) { + if (sub.path.length > 0) { + fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; + fieldErrors[sub.path[0]].push(mapper(sub)); + } else { + formErrors.push(mapper(sub)); + } + } + return { formErrors, fieldErrors }; +} +function formatError(error, mapper = (issue2) => issue2.message) { + const fieldErrors = { _errors: [] }; + const processError = (error2, path2 = []) => { + for (const issue2 of error2.issues) { + if (issue2.code === "invalid_union" && issue2.errors.length) { + issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path])); + } else if (issue2.code === "invalid_key") { + processError({ issues: issue2.issues }, [...path2, ...issue2.path]); + } else if (issue2.code === "invalid_element") { + processError({ issues: issue2.issues }, [...path2, ...issue2.path]); + } else { + const fullpath = [...path2, ...issue2.path]; + if (fullpath.length === 0) { + fieldErrors._errors.push(mapper(issue2)); + } else { + let curr = fieldErrors; + let i = 0; + while (i < fullpath.length) { + const el = fullpath[i]; + const terminal = i === fullpath.length - 1; + if (!terminal) { + curr[el] = curr[el] || { _errors: [] }; + } else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue2)); + } + curr = curr[el]; + i++; + } + } + } + } + }; + processError(error); + return fieldErrors; +} + +// node_modules/zod/v4/core/parse.js +var _parse = (_Err) => (schema, value, _ctx, _params) => { + const ctx = _ctx ? { ..._ctx, async: false } : { async: false }; + const result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) { + throw new $ZodAsyncError(); + } + if (result.issues.length) { + const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, _params?.callee); + throw e; + } + return result.value; +}; +var _parseAsync = (_Err) => async (schema, value, _ctx, params) => { + const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; + let result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) + result = await result; + if (result.issues.length) { + const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))); + captureStackTrace(e, params?.callee); + throw e; + } + return result.value; +}; +var _safeParse = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, async: false } : { async: false }; + const result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) { + throw new $ZodAsyncError(); + } + return result.issues.length ? { + success: false, + error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { success: true, data: result.value }; +}; +var safeParse = /* @__PURE__ */ _safeParse($ZodRealError); +var _safeParseAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; + let result = schema._zod.run({ value, issues: [] }, ctx); + if (result instanceof Promise) + result = await result; + return result.issues.length ? { + success: false, + error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + } : { success: true, data: result.value }; +}; +var safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError); +var _encode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _parse(_Err)(schema, value, ctx); +}; +var _decode = (_Err) => (schema, value, _ctx) => { + return _parse(_Err)(schema, value, _ctx); +}; +var _encodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _parseAsync(_Err)(schema, value, ctx); +}; +var _decodeAsync = (_Err) => async (schema, value, _ctx) => { + return _parseAsync(_Err)(schema, value, _ctx); +}; +var _safeEncode = (_Err) => (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _safeParse(_Err)(schema, value, ctx); +}; +var _safeDecode = (_Err) => (schema, value, _ctx) => { + return _safeParse(_Err)(schema, value, _ctx); +}; +var _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { + const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" }; + return _safeParseAsync(_Err)(schema, value, ctx); +}; +var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { + return _safeParseAsync(_Err)(schema, value, _ctx); +}; + +// node_modules/zod/v4/core/regexes.js +var cuid = /^[cC][0-9a-z]{6,}$/; +var cuid2 = /^[0-9a-z]+$/; +var ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; +var xid = /^[0-9a-vA-V]{20}$/; +var ksuid = /^[A-Za-z0-9]{27}$/; +var nanoid = /^[a-zA-Z0-9_-]{21}$/; +var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/; +var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; +var uuid = (version2) => { + if (!version2) + return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); +}; +var email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; +var _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; +function emoji() { + return new RegExp(_emoji, "u"); +} +var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; +var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; +var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; +var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; +var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; +var base64url = /^[A-Za-z0-9_-]*$/; +var httpProtocol = /^https?$/; +var e164 = /^\+[1-9]\d{6,14}$/; +var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; +var date = /* @__PURE__ */ new RegExp(`^${dateSource}$`); +function timeSource(args) { + const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; + const regex = typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + return regex; +} +function time(args) { + return new RegExp(`^${timeSource(args)}$`); +} +function datetime(args) { + const time3 = timeSource({ precision: args.precision }); + const opts = ["Z"]; + if (args.local) + opts.push(""); + if (args.offset) + opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + const timeRegex = `${time3}(?:${opts.join("|")})`; + return new RegExp(`^${dateSource}T(?:${timeRegex})$`); +} +var string = (params) => { + const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex}$`); +}; +var integer = /^-?\d+$/; +var number = /^-?\d+(?:\.\d+)?$/; +var boolean = /^(?:true|false)$/i; +var lowercase = /^[^A-Z]*$/; +var uppercase = /^[^a-z]*$/; + +// node_modules/zod/v4/core/checks.js +var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => { + var _a3; + inst._zod ?? (inst._zod = {}); + inst._zod.def = def; + (_a3 = inst._zod).onattach ?? (_a3.onattach = []); +}); +var numericOriginMap = { + number: "number", + bigint: "bigint", + object: "date" +}; +var $ZodCheckLessThan = /* @__PURE__ */ $constructor("$ZodCheckLessThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; + if (def.value < curr) { + if (def.inclusive) + bag.maximum = def.value; + else + bag.exclusiveMaximum = def.value; + } + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value <= def.value : payload.value < def.value) { + return; + } + payload.issues.push({ + origin, + code: "too_big", + maximum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckGreaterThan = /* @__PURE__ */ $constructor("$ZodCheckGreaterThan", (inst, def) => { + $ZodCheck.init(inst, def); + const origin = numericOriginMap[typeof def.value]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; + if (def.value > curr) { + if (def.inclusive) + bag.minimum = def.value; + else + bag.exclusiveMinimum = def.value; + } + }); + inst._zod.check = (payload) => { + if (def.inclusive ? payload.value >= def.value : payload.value > def.value) { + return; + } + payload.issues.push({ + origin, + code: "too_small", + minimum: typeof def.value === "object" ? def.value.getTime() : def.value, + input: payload.value, + inclusive: def.inclusive, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckMultipleOf = /* @__PURE__ */ $constructor("$ZodCheckMultipleOf", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst2) => { + var _a3; + (_a3 = inst2._zod.bag).multipleOf ?? (_a3.multipleOf = def.value); + }); + inst._zod.check = (payload) => { + if (typeof payload.value !== typeof def.value) + throw new Error("Cannot mix number and bigint in multiple_of check."); + const isMultiple = typeof payload.value === "bigint" ? payload.value % def.value === BigInt(0) : floatSafeRemainder(payload.value, def.value) === 0; + if (isMultiple) + return; + payload.issues.push({ + origin: typeof payload.value, + code: "not_multiple_of", + divisor: def.value, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat", (inst, def) => { + $ZodCheck.init(inst, def); + def.format = def.format || "float64"; + const isInt = def.format?.includes("int"); + const origin = isInt ? "int" : "number"; + const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.format = def.format; + bag.minimum = minimum; + bag.maximum = maximum; + if (isInt) + bag.pattern = integer; + }); + inst._zod.check = (payload) => { + const input = payload.value; + if (isInt) { + if (!Number.isInteger(input)) { + payload.issues.push({ + expected: origin, + format: def.format, + code: "invalid_type", + continue: false, + input, + inst + }); + return; + } + if (!Number.isSafeInteger(input)) { + if (input > 0) { + payload.issues.push({ + input, + code: "too_big", + maximum: Number.MAX_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + } else { + payload.issues.push({ + input, + code: "too_small", + minimum: Number.MIN_SAFE_INTEGER, + note: "Integers must be within the safe integer range.", + inst, + origin, + inclusive: true, + continue: !def.abort + }); + } + return; + } + } + if (input < minimum) { + payload.issues.push({ + origin: "number", + input, + code: "too_small", + minimum, + inclusive: true, + inst, + continue: !def.abort + }); + } + if (input > maximum) { + payload.issues.push({ + origin: "number", + input, + code: "too_big", + maximum, + inclusive: true, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const curr = inst2._zod.bag.maximum ?? Number.POSITIVE_INFINITY; + if (def.maximum < curr) + inst2._zod.bag.maximum = def.maximum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length <= def.maximum) + return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_big", + maximum: def.maximum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const curr = inst2._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; + if (def.minimum > curr) + inst2._zod.bag.minimum = def.minimum; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length >= def.minimum) + return; + const origin = getLengthableOrigin(input); + payload.issues.push({ + origin, + code: "too_small", + minimum: def.minimum, + inclusive: true, + input, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEquals", (inst, def) => { + var _a3; + $ZodCheck.init(inst, def); + (_a3 = inst._zod.def).when ?? (_a3.when = (payload) => { + const val = payload.value; + return !nullish(val) && val.length !== void 0; + }); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.minimum = def.length; + bag.maximum = def.length; + bag.length = def.length; + }); + inst._zod.check = (payload) => { + const input = payload.value; + const length = input.length; + if (length === def.length) + return; + const origin = getLengthableOrigin(input); + const tooBig = length > def.length; + payload.issues.push({ + origin, + ...tooBig ? { code: "too_big", maximum: def.length } : { code: "too_small", minimum: def.length }, + inclusive: true, + exact: true, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckStringFormat = /* @__PURE__ */ $constructor("$ZodCheckStringFormat", (inst, def) => { + var _a3, _b; + $ZodCheck.init(inst, def); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.format = def.format; + if (def.pattern) { + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(def.pattern); + } + }); + if (def.pattern) + (_a3 = inst._zod).check ?? (_a3.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: def.format, + input: payload.value, + ...def.pattern ? { pattern: def.pattern.toString() } : {}, + inst, + continue: !def.abort + }); + }); + else + (_b = inst._zod).check ?? (_b.check = () => { + }); +}); +var $ZodCheckRegex = /* @__PURE__ */ $constructor("$ZodCheckRegex", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + inst._zod.check = (payload) => { + def.pattern.lastIndex = 0; + if (def.pattern.test(payload.value)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "regex", + input: payload.value, + pattern: def.pattern.toString(), + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckLowerCase = /* @__PURE__ */ $constructor("$ZodCheckLowerCase", (inst, def) => { + def.pattern ?? (def.pattern = lowercase); + $ZodCheckStringFormat.init(inst, def); +}); +var $ZodCheckUpperCase = /* @__PURE__ */ $constructor("$ZodCheckUpperCase", (inst, def) => { + def.pattern ?? (def.pattern = uppercase); + $ZodCheckStringFormat.init(inst, def); +}); +var $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, def) => { + $ZodCheck.init(inst, def); + const escapedRegex = escapeRegex(def.includes); + const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex); + def.pattern = pattern; + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.includes(def.includes, def.position)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "includes", + includes: def.includes, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.startsWith(def.prefix)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "starts_with", + prefix: def.prefix, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, def) => { + $ZodCheck.init(inst, def); + const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); + def.pattern ?? (def.pattern = pattern); + inst._zod.onattach.push((inst2) => { + const bag = inst2._zod.bag; + bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); + bag.patterns.add(pattern); + }); + inst._zod.check = (payload) => { + if (payload.value.endsWith(def.suffix)) + return; + payload.issues.push({ + origin: "string", + code: "invalid_format", + format: "ends_with", + suffix: def.suffix, + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (inst, def) => { + $ZodCheck.init(inst, def); + inst._zod.check = (payload) => { + payload.value = def.tx(payload.value); + }; +}); + +// node_modules/zod/v4/core/doc.js +var Doc = class { + constructor(args = []) { + this.content = []; + this.indent = 0; + if (this) + this.args = args; + } + indented(fn) { + this.indent += 1; + fn(this); + this.indent -= 1; + } + write(arg) { + if (typeof arg === "function") { + arg(this, { execution: "sync" }); + arg(this, { execution: "async" }); + return; + } + const content = arg; + const lines = content.split("\n").filter((x) => x); + const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length)); + const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x); + for (const line of dedented) { + this.content.push(line); + } + } + compile() { + const F = Function; + const args = this?.args; + const content = this?.content ?? [``]; + const lines = [...content.map((x) => ` ${x}`)]; + return new F(...args, lines.join("\n")); + } +}; + +// node_modules/zod/v4/core/versions.js +var version = { + major: 4, + minor: 4, + patch: 3 +}; + +// node_modules/zod/v4/core/schemas.js +var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => { + var _a3; + inst ?? (inst = {}); + inst._zod.def = def; + inst._zod.bag = inst._zod.bag || {}; + inst._zod.version = version; + const checks = [...inst._zod.def.checks ?? []]; + if (inst._zod.traits.has("$ZodCheck")) { + checks.unshift(inst); + } + for (const ch of checks) { + for (const fn of ch._zod.onattach) { + fn(inst); + } + } + if (checks.length === 0) { + (_a3 = inst._zod).deferred ?? (_a3.deferred = []); + inst._zod.deferred?.push(() => { + inst._zod.run = inst._zod.parse; + }); + } else { + const runChecks = (payload, checks2, ctx) => { + let isAborted = aborted(payload); + let asyncResult; + for (const ch of checks2) { + if (ch._zod.def.when) { + if (explicitlyAborted(payload)) + continue; + const shouldRun = ch._zod.def.when(payload); + if (!shouldRun) + continue; + } else if (isAborted) { + continue; + } + const currLen = payload.issues.length; + const _ = ch._zod.check(payload); + if (_ instanceof Promise && ctx?.async === false) { + throw new $ZodAsyncError(); + } + if (asyncResult || _ instanceof Promise) { + asyncResult = (asyncResult ?? Promise.resolve()).then(async () => { + await _; + const nextLen = payload.issues.length; + if (nextLen === currLen) + return; + if (!isAborted) + isAborted = aborted(payload, currLen); + }); + } else { + const nextLen = payload.issues.length; + if (nextLen === currLen) + continue; + if (!isAborted) + isAborted = aborted(payload, currLen); + } + } + if (asyncResult) { + return asyncResult.then(() => { + return payload; + }); + } + return payload; + }; + const handleCanaryResult = (canary, payload, ctx) => { + if (aborted(canary)) { + canary.aborted = true; + return canary; + } + const checkResult = runChecks(payload, checks, ctx); + if (checkResult instanceof Promise) { + if (ctx.async === false) + throw new $ZodAsyncError(); + return checkResult.then((checkResult2) => inst._zod.parse(checkResult2, ctx)); + } + return inst._zod.parse(checkResult, ctx); + }; + inst._zod.run = (payload, ctx) => { + if (ctx.skipChecks) { + return inst._zod.parse(payload, ctx); + } + if (ctx.direction === "backward") { + const canary = inst._zod.parse({ value: payload.value, issues: [] }, { ...ctx, skipChecks: true }); + if (canary instanceof Promise) { + return canary.then((canary2) => { + return handleCanaryResult(canary2, payload, ctx); + }); + } + return handleCanaryResult(canary, payload, ctx); + } + const result = inst._zod.parse(payload, ctx); + if (result instanceof Promise) { + if (ctx.async === false) + throw new $ZodAsyncError(); + return result.then((result2) => runChecks(result2, checks, ctx)); + } + return runChecks(result, checks, ctx); + }; + } + defineLazy(inst, "~standard", () => ({ + validate: (value) => { + try { + const r = safeParse(inst, value); + return r.success ? { value: r.data } : { issues: r.error?.issues }; + } catch (_) { + return safeParseAsync(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues }); + } + }, + vendor: "zod", + version: 1 + })); +}); +var $ZodString = /* @__PURE__ */ $constructor("$ZodString", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string(inst._zod.bag); + inst._zod.parse = (payload, _) => { + if (def.coerce) + try { + payload.value = String(payload.value); + } catch (_2) { + } + if (typeof payload.value === "string") + return payload; + payload.issues.push({ + expected: "string", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; +}); +var $ZodStringFormat = /* @__PURE__ */ $constructor("$ZodStringFormat", (inst, def) => { + $ZodCheckStringFormat.init(inst, def); + $ZodString.init(inst, def); +}); +var $ZodGUID = /* @__PURE__ */ $constructor("$ZodGUID", (inst, def) => { + def.pattern ?? (def.pattern = guid); + $ZodStringFormat.init(inst, def); +}); +var $ZodUUID = /* @__PURE__ */ $constructor("$ZodUUID", (inst, def) => { + if (def.version) { + const versionMap = { + v1: 1, + v2: 2, + v3: 3, + v4: 4, + v5: 5, + v6: 6, + v7: 7, + v8: 8 + }; + const v = versionMap[def.version]; + if (v === void 0) + throw new Error(`Invalid UUID version: "${def.version}"`); + def.pattern ?? (def.pattern = uuid(v)); + } else + def.pattern ?? (def.pattern = uuid()); + $ZodStringFormat.init(inst, def); +}); +var $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => { + def.pattern ?? (def.pattern = email); + $ZodStringFormat.init(inst, def); +}); +var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + try { + const trimmed = payload.value.trim(); + if (!def.normalize && def.protocol?.source === httpProtocol.source) { + if (!/^https?:\/\//i.test(trimmed)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid URL format", + input: payload.value, + inst, + continue: !def.abort + }); + return; + } + } + const url = new URL(trimmed); + if (def.hostname) { + def.hostname.lastIndex = 0; + if (!def.hostname.test(url.hostname)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid hostname", + pattern: def.hostname.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + } + if (def.protocol) { + def.protocol.lastIndex = 0; + if (!def.protocol.test(url.protocol.endsWith(":") ? url.protocol.slice(0, -1) : url.protocol)) { + payload.issues.push({ + code: "invalid_format", + format: "url", + note: "Invalid protocol", + pattern: def.protocol.source, + input: payload.value, + inst, + continue: !def.abort + }); + } + } + if (def.normalize) { + payload.value = url.href; + } else { + payload.value = trimmed; + } + return; + } catch (_) { + payload.issues.push({ + code: "invalid_format", + format: "url", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodEmoji = /* @__PURE__ */ $constructor("$ZodEmoji", (inst, def) => { + def.pattern ?? (def.pattern = emoji()); + $ZodStringFormat.init(inst, def); +}); +var $ZodNanoID = /* @__PURE__ */ $constructor("$ZodNanoID", (inst, def) => { + def.pattern ?? (def.pattern = nanoid); + $ZodStringFormat.init(inst, def); +}); +var $ZodCUID = /* @__PURE__ */ $constructor("$ZodCUID", (inst, def) => { + def.pattern ?? (def.pattern = cuid); + $ZodStringFormat.init(inst, def); +}); +var $ZodCUID2 = /* @__PURE__ */ $constructor("$ZodCUID2", (inst, def) => { + def.pattern ?? (def.pattern = cuid2); + $ZodStringFormat.init(inst, def); +}); +var $ZodULID = /* @__PURE__ */ $constructor("$ZodULID", (inst, def) => { + def.pattern ?? (def.pattern = ulid); + $ZodStringFormat.init(inst, def); +}); +var $ZodXID = /* @__PURE__ */ $constructor("$ZodXID", (inst, def) => { + def.pattern ?? (def.pattern = xid); + $ZodStringFormat.init(inst, def); +}); +var $ZodKSUID = /* @__PURE__ */ $constructor("$ZodKSUID", (inst, def) => { + def.pattern ?? (def.pattern = ksuid); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODateTime = /* @__PURE__ */ $constructor("$ZodISODateTime", (inst, def) => { + def.pattern ?? (def.pattern = datetime(def)); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODate = /* @__PURE__ */ $constructor("$ZodISODate", (inst, def) => { + def.pattern ?? (def.pattern = date); + $ZodStringFormat.init(inst, def); +}); +var $ZodISOTime = /* @__PURE__ */ $constructor("$ZodISOTime", (inst, def) => { + def.pattern ?? (def.pattern = time(def)); + $ZodStringFormat.init(inst, def); +}); +var $ZodISODuration = /* @__PURE__ */ $constructor("$ZodISODuration", (inst, def) => { + def.pattern ?? (def.pattern = duration); + $ZodStringFormat.init(inst, def); +}); +var $ZodIPv4 = /* @__PURE__ */ $constructor("$ZodIPv4", (inst, def) => { + def.pattern ?? (def.pattern = ipv4); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv4`; +}); +var $ZodIPv6 = /* @__PURE__ */ $constructor("$ZodIPv6", (inst, def) => { + def.pattern ?? (def.pattern = ipv6); + $ZodStringFormat.init(inst, def); + inst._zod.bag.format = `ipv6`; + inst._zod.check = (payload) => { + try { + new URL(`http://[${payload.value}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "ipv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +var $ZodCIDRv4 = /* @__PURE__ */ $constructor("$ZodCIDRv4", (inst, def) => { + def.pattern ?? (def.pattern = cidrv4); + $ZodStringFormat.init(inst, def); +}); +var $ZodCIDRv6 = /* @__PURE__ */ $constructor("$ZodCIDRv6", (inst, def) => { + def.pattern ?? (def.pattern = cidrv6); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + const parts = payload.value.split("/"); + try { + if (parts.length !== 2) + throw new Error(); + const [address, prefix] = parts; + if (!prefix) + throw new Error(); + const prefixNum = Number(prefix); + if (`${prefixNum}` !== prefix) + throw new Error(); + if (prefixNum < 0 || prefixNum > 128) + throw new Error(); + new URL(`http://[${address}]`); + } catch { + payload.issues.push({ + code: "invalid_format", + format: "cidrv6", + input: payload.value, + inst, + continue: !def.abort + }); + } + }; +}); +function isValidBase64(data) { + if (data === "") + return true; + if (/\s/.test(data)) + return false; + if (data.length % 4 !== 0) + return false; + try { + atob(data); + return true; + } catch { + return false; + } +} +var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => { + def.pattern ?? (def.pattern = base64); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64"; + inst._zod.check = (payload) => { + if (isValidBase64(payload.value)) + return; + payload.issues.push({ + code: "invalid_format", + format: "base64", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +function isValidBase64URL(data) { + if (!base64url.test(data)) + return false; + const base642 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); + const padded = base642.padEnd(Math.ceil(base642.length / 4) * 4, "="); + return isValidBase64(padded); +} +var $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => { + def.pattern ?? (def.pattern = base64url); + $ZodStringFormat.init(inst, def); + inst._zod.bag.contentEncoding = "base64url"; + inst._zod.check = (payload) => { + if (isValidBase64URL(payload.value)) + return; + payload.issues.push({ + code: "invalid_format", + format: "base64url", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodE164 = /* @__PURE__ */ $constructor("$ZodE164", (inst, def) => { + def.pattern ?? (def.pattern = e164); + $ZodStringFormat.init(inst, def); +}); +function isValidJWT(token, algorithm = null) { + try { + const tokensParts = token.split("."); + if (tokensParts.length !== 3) + return false; + const [header] = tokensParts; + if (!header) + return false; + const parsedHeader = JSON.parse(atob(header)); + if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") + return false; + if (!parsedHeader.alg) + return false; + if (algorithm && (!("alg" in parsedHeader) || parsedHeader.alg !== algorithm)) + return false; + return true; + } catch { + return false; + } +} +var $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => { + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidJWT(payload.value, def.alg)) + return; + payload.issues.push({ + code: "invalid_format", + format: "jwt", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); +var $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = inst._zod.bag.pattern ?? number; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) + try { + payload.value = Number(payload.value); + } catch (_) { + } + const input = payload.value; + if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) { + return payload; + } + const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0; + payload.issues.push({ + expected: "number", + code: "invalid_type", + input, + inst, + ...received ? { received } : {} + }); + return payload; + }; +}); +var $ZodNumberFormat = /* @__PURE__ */ $constructor("$ZodNumberFormat", (inst, def) => { + $ZodCheckNumberFormat.init(inst, def); + $ZodNumber.init(inst, def); +}); +var $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.pattern = boolean; + inst._zod.parse = (payload, _ctx) => { + if (def.coerce) + try { + payload.value = Boolean(payload.value); + } catch (_) { + } + const input = payload.value; + if (typeof input === "boolean") + return payload; + payload.issues.push({ + expected: "boolean", + code: "invalid_type", + input, + inst + }); + return payload; + }; +}); +var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload) => payload; +}); +var $ZodNever = /* @__PURE__ */ $constructor("$ZodNever", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.issues.push({ + expected: "never", + code: "invalid_type", + input: payload.value, + inst + }); + return payload; + }; +}); +function handleArrayResult(result, final, index) { + if (result.issues.length) { + final.issues.push(...prefixIssues(index, result.issues)); + } + final.value[index] = result.value; +} +var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!Array.isArray(input)) { + payload.issues.push({ + expected: "array", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = Array(input.length); + const proms = []; + for (let i = 0; i < input.length; i++) { + const item = input[i]; + const result = def.element._zod.run({ + value: item, + issues: [] + }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => handleArrayResult(result2, payload, i))); + } else { + handleArrayResult(result, payload, i); + } + } + if (proms.length) { + return Promise.all(proms).then(() => payload); + } + return payload; + }; +}); +function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) { + const isPresent = key in input; + if (result.issues.length) { + if (isOptionalIn && isOptionalOut && !isPresent) { + return; + } + final.issues.push(...prefixIssues(key, result.issues)); + } + if (!isPresent && !isOptionalIn) { + if (!result.issues.length) { + final.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: void 0, + path: [key] + }); + } + return; + } + if (result.value === void 0) { + if (isPresent) { + final.value[key] = void 0; + } + } else { + final.value[key] = result.value; + } +} +function normalizeDef(def) { + const keys = Object.keys(def.shape); + for (const k of keys) { + if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) { + throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + } + } + const okeys = optionalKeys(def.shape); + return { + ...def, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys) + }; +} +function handleCatchall(proms, input, payload, ctx, def, inst) { + const unrecognized = []; + const keySet = def.keySet; + const _catchall = def.catchall._zod; + const t = _catchall.def.type; + const isOptionalIn = _catchall.optin === "optional"; + const isOptionalOut = _catchall.optout === "optional"; + for (const key in input) { + if (key === "__proto__") + continue; + if (keySet.has(key)) + continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ value: input[key], issues: [] }, ctx); + if (r instanceof Promise) { + proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut))); + } else { + handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + } + if (unrecognized.length) { + payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst + }); + } + if (!proms.length) + return payload; + return Promise.all(proms).then(() => { + return payload; + }); +} +var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => { + $ZodType.init(inst, def); + const desc = Object.getOwnPropertyDescriptor(def, "shape"); + if (!desc?.get) { + const sh = def.shape; + Object.defineProperty(def, "shape", { + get: () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { + value: newSh + }); + return newSh; + } + }); + } + const _normalized = cached(() => normalizeDef(def)); + defineLazy(inst._zod, "propValues", () => { + const shape = def.shape; + const propValues = {}; + for (const key in shape) { + const field = shape[key]._zod; + if (field.values) { + propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set()); + for (const v of field.values) + propValues[key].add(v); + } + } + return propValues; + }); + const isObject2 = isObject; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + payload.value = {}; + const proms = []; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + const isOptionalIn = el._zod.optin === "optional"; + const isOptionalOut = el._zod.optout === "optional"; + const r = el._zod.run({ value: input[key], issues: [] }, ctx); + if (r instanceof Promise) { + proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut))); + } else { + handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut); + } + } + if (!catchall) { + return proms.length ? Promise.all(proms).then(() => payload) : payload; + } + return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); + }; +}); +var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => { + $ZodObject.init(inst, def); + const superParse = inst._zod.parse; + const _normalized = cached(() => normalizeDef(def)); + const generateFastpass = (shape) => { + const doc = new Doc(["shape", "payload", "ctx"]); + const normalized = _normalized.value; + const parseStr = (key) => { + const k = esc(key); + return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`; + }; + doc.write(`const input = payload.value;`); + const ids = /* @__PURE__ */ Object.create(null); + let counter = 0; + for (const key of normalized.keys) { + ids[key] = `key_${counter++}`; + } + doc.write(`const newResult = {};`); + for (const key of normalized.keys) { + const id = ids[key]; + const k = esc(key); + const schema = shape[key]; + const isOptionalIn = schema?._zod?.optin === "optional"; + const isOptionalOut = schema?._zod?.optout === "optional"; + doc.write(`const ${id} = ${parseStr(key)};`); + if (isOptionalIn && isOptionalOut) { + doc.write(` + if (${id}.issues.length) { + if (${k} in input) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } else if (!isOptionalIn) { + doc.write(` + const ${id}_present = ${k} in input; + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + if (!${id}_present && !${id}.issues.length) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: undefined, + path: [${k}] + }); + } + + if (${id}_present) { + if (${id}.value === undefined) { + newResult[${k}] = undefined; + } else { + newResult[${k}] = ${id}.value; + } + } + + `); + } else { + doc.write(` + if (${id}.issues.length) { + payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}] + }))); + } + + if (${id}.value === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + newResult[${k}] = ${id}.value; + } + + `); + } + } + doc.write(`payload.value = newResult;`); + doc.write(`return payload;`); + const fn = doc.compile(); + return (payload, ctx) => fn(shape, payload, ctx); + }; + let fastpass; + const isObject2 = isObject; + const jit = !globalConfig.jitless; + const allowsEval2 = allowsEval; + const fastEnabled = jit && allowsEval2.value; + const catchall = def.catchall; + let value; + inst._zod.parse = (payload, ctx) => { + value ?? (value = _normalized.value); + const input = payload.value; + if (!isObject2(input)) { + payload.issues.push({ + expected: "object", + code: "invalid_type", + input, + inst + }); + return payload; + } + if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { + if (!fastpass) + fastpass = generateFastpass(def.shape); + payload = fastpass(payload, ctx); + if (!catchall) + return payload; + return handleCatchall([], input, payload, ctx, value, inst); + } + return superParse(payload, ctx); + }; +}); +function handleUnionResults(results, final, inst, ctx) { + for (const result of results) { + if (result.issues.length === 0) { + final.value = result.value; + return final; + } + } + const nonaborted = results.filter((r) => !aborted(r)); + if (nonaborted.length === 1) { + final.value = nonaborted[0].value; + return nonaborted[0]; + } + final.issues.push({ + code: "invalid_union", + input: final.value, + inst, + errors: results.map((result) => result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) + }); + return final; +} +var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.options.some((o) => o._zod.optin === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "optout", () => def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0); + defineLazy(inst._zod, "values", () => { + if (def.options.every((o) => o._zod.values)) { + return new Set(def.options.flatMap((option) => Array.from(option._zod.values))); + } + return void 0; + }); + defineLazy(inst._zod, "pattern", () => { + if (def.options.every((o) => o._zod.pattern)) { + const patterns = def.options.map((o) => o._zod.pattern); + return new RegExp(`^(${patterns.map((p) => cleanRegex(p.source)).join("|")})$`); + } + return void 0; + }); + const first = def.options.length === 1 ? def.options[0]._zod.run : null; + inst._zod.parse = (payload, ctx) => { + if (first) { + return first(payload, ctx); + } + let async = false; + const results = []; + for (const option of def.options) { + const result = option._zod.run({ + value: payload.value, + issues: [] + }, ctx); + if (result instanceof Promise) { + results.push(result); + async = true; + } else { + if (result.issues.length === 0) + return result; + results.push(result); + } + } + if (!async) + return handleUnionResults(results, payload, inst, ctx); + return Promise.all(results).then((results2) => { + return handleUnionResults(results2, payload, inst, ctx); + }); + }; +}); +var $ZodIntersection = /* @__PURE__ */ $constructor("$ZodIntersection", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + const left = def.left._zod.run({ value: input, issues: [] }, ctx); + const right = def.right._zod.run({ value: input, issues: [] }, ctx); + const async = left instanceof Promise || right instanceof Promise; + if (async) { + return Promise.all([left, right]).then(([left2, right2]) => { + return handleIntersectionResults(payload, left2, right2); + }); + } + return handleIntersectionResults(payload, left, right); + }; +}); +function mergeValues(a, b) { + if (a === b) { + return { valid: true, data: a }; + } + if (a instanceof Date && b instanceof Date && +a === +b) { + return { valid: true, data: a }; + } + if (isPlainObject(a) && isPlainObject(b)) { + const bKeys = Object.keys(b); + const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { ...a, ...b }; + for (const key of sharedKeys) { + const sharedValue = mergeValues(a[key], b[key]); + if (!sharedValue.valid) { + return { + valid: false, + mergeErrorPath: [key, ...sharedValue.mergeErrorPath] + }; + } + newObj[key] = sharedValue.data; + } + return { valid: true, data: newObj }; + } + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) { + return { valid: false, mergeErrorPath: [] }; + } + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = mergeValues(itemA, itemB); + if (!sharedValue.valid) { + return { + valid: false, + mergeErrorPath: [index, ...sharedValue.mergeErrorPath] + }; + } + newArray.push(sharedValue.data); + } + return { valid: true, data: newArray }; + } + return { valid: false, mergeErrorPath: [] }; +} +function handleIntersectionResults(result, left, right) { + const unrecKeys = /* @__PURE__ */ new Map(); + let unrecIssue; + for (const iss of left.issues) { + if (iss.code === "unrecognized_keys") { + unrecIssue ?? (unrecIssue = iss); + for (const k of iss.keys) { + if (!unrecKeys.has(k)) + unrecKeys.set(k, {}); + unrecKeys.get(k).l = true; + } + } else { + result.issues.push(iss); + } + } + for (const iss of right.issues) { + if (iss.code === "unrecognized_keys") { + for (const k of iss.keys) { + if (!unrecKeys.has(k)) + unrecKeys.set(k, {}); + unrecKeys.get(k).r = true; + } + } else { + result.issues.push(iss); + } + } + const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k); + if (bothKeys.length && unrecIssue) { + result.issues.push({ ...unrecIssue, keys: bothKeys }); + } + if (aborted(result)) + return result; + const merged = mergeValues(left.value, right.value); + if (!merged.valid) { + throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}`); + } + result.value = merged.data; + return result; +} +var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.parse = (payload, ctx) => { + const input = payload.value; + if (!isPlainObject(input)) { + payload.issues.push({ + expected: "record", + code: "invalid_type", + input, + inst + }); + return payload; + } + const proms = []; + const values = def.keyType._zod.values; + if (values) { + payload.value = {}; + const recordKeys = /* @__PURE__ */ new Set(); + for (const key of values) { + if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { + recordKeys.add(typeof key === "number" ? key.toString() : key); + const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx); + if (keyResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + if (keyResult.issues.length) { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + continue; + } + const outKey = keyResult.value; + const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => { + if (result2.issues.length) { + payload.issues.push(...prefixIssues(key, result2.issues)); + } + payload.value[outKey] = result2.value; + })); + } else { + if (result.issues.length) { + payload.issues.push(...prefixIssues(key, result.issues)); + } + payload.value[outKey] = result.value; + } + } + } + let unrecognized; + for (const key in input) { + if (!recordKeys.has(key)) { + unrecognized = unrecognized ?? []; + unrecognized.push(key); + } + } + if (unrecognized && unrecognized.length > 0) { + payload.issues.push({ + code: "unrecognized_keys", + input, + inst, + keys: unrecognized + }); + } + } else { + payload.value = {}; + for (const key of Reflect.ownKeys(input)) { + if (key === "__proto__") + continue; + if (!Object.prototype.propertyIsEnumerable.call(input, key)) + continue; + let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx); + if (keyResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length; + if (checkNumericKey) { + const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx); + if (retryResult instanceof Promise) { + throw new Error("Async schemas not supported in object keys currently"); + } + if (retryResult.issues.length === 0) { + keyResult = retryResult; + } + } + if (keyResult.issues.length) { + if (def.mode === "loose") { + payload.value[key] = input[key]; + } else { + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + input: key, + path: [key], + inst + }); + } + continue; + } + const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx); + if (result instanceof Promise) { + proms.push(result.then((result2) => { + if (result2.issues.length) { + payload.issues.push(...prefixIssues(key, result2.issues)); + } + payload.value[keyResult.value] = result2.value; + })); + } else { + if (result.issues.length) { + payload.issues.push(...prefixIssues(key, result.issues)); + } + payload.value[keyResult.value] = result.value; + } + } + } + if (proms.length) { + return Promise.all(proms).then(() => payload); + } + return payload; + }; +}); +var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => { + $ZodType.init(inst, def); + const values = getEnumValues(def.entries); + const valuesSet = new Set(values); + inst._zod.values = valuesSet; + inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`); + inst._zod.parse = (payload, _ctx) => { + const input = payload.value; + if (valuesSet.has(input)) { + return payload; + } + payload.issues.push({ + code: "invalid_value", + values, + input, + inst + }); + return payload; + }; +}); +var $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + throw new $ZodEncodeError(inst.constructor.name); + } + const _out = def.transform(payload.value, payload); + if (ctx.async) { + const output = _out instanceof Promise ? _out : Promise.resolve(_out); + return output.then((output2) => { + payload.value = output2; + payload.fallback = true; + return payload; + }); + } + if (_out instanceof Promise) { + throw new $ZodAsyncError(); + } + payload.value = _out; + payload.fallback = true; + return payload; + }; +}); +function handleOptionalResult(result, input) { + if (input === void 0 && (result.issues.length || result.fallback)) { + return { issues: [], value: void 0 }; + } + return result; +} +var $ZodOptional = /* @__PURE__ */ $constructor("$ZodOptional", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + inst._zod.optout = "optional"; + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0; + }); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (def.innerType._zod.optin === "optional") { + const input = payload.value; + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) + return result.then((r) => handleOptionalResult(r, input)); + return handleOptionalResult(result, input); + } + if (payload.value === void 0) { + return payload; + } + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodExactOptional = /* @__PURE__ */ $constructor("$ZodExactOptional", (inst, def) => { + $ZodOptional.init(inst, def); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "pattern", () => def.innerType._zod.pattern); + inst._zod.parse = (payload, ctx) => { + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodNullable = /* @__PURE__ */ $constructor("$ZodNullable", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "pattern", () => { + const pattern = def.innerType._zod.pattern; + return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0; + }); + defineLazy(inst._zod, "values", () => { + return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + if (payload.value === null) + return payload; + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodDefault = /* @__PURE__ */ $constructor("$ZodDefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + if (payload.value === void 0) { + payload.value = def.defaultValue; + return payload; + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => handleDefaultResult(result2, def)); + } + return handleDefaultResult(result, def); + }; +}); +function handleDefaultResult(payload, def) { + if (payload.value === void 0) { + payload.value = def.defaultValue; + } + return payload; +} +var $ZodPrefault = /* @__PURE__ */ $constructor("$ZodPrefault", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + if (payload.value === void 0) { + payload.value = def.defaultValue; + } + return def.innerType._zod.run(payload, ctx); + }; +}); +var $ZodNonOptional = /* @__PURE__ */ $constructor("$ZodNonOptional", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => { + const v = def.innerType._zod.values; + return v ? new Set([...v].filter((x) => x !== void 0)) : void 0; + }); + inst._zod.parse = (payload, ctx) => { + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => handleNonOptionalResult(result2, inst)); + } + return handleNonOptionalResult(result, inst); + }; +}); +function handleNonOptionalResult(payload, inst) { + if (!payload.issues.length && payload.value === void 0) { + payload.issues.push({ + code: "invalid_type", + expected: "nonoptional", + input: payload.value, + inst + }); + } + return payload; +} +var $ZodCatch = /* @__PURE__ */ $constructor("$ZodCatch", (inst, def) => { + $ZodType.init(inst, def); + inst._zod.optin = "optional"; + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then((result2) => { + payload.value = result2.value; + if (result2.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { + issues: result2.issues.map((iss) => finalizeIssue(iss, ctx, config())) + }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }); + } + payload.value = result.value; + if (result.issues.length) { + payload.value = def.catchValue({ + ...payload, + error: { + issues: result.issues.map((iss) => finalizeIssue(iss, ctx, config())) + }, + input: payload.value + }); + payload.issues = []; + payload.fallback = true; + } + return payload; + }; +}); +var $ZodPipe = /* @__PURE__ */ $constructor("$ZodPipe", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "values", () => def.in._zod.values); + defineLazy(inst._zod, "optin", () => def.in._zod.optin); + defineLazy(inst._zod, "optout", () => def.out._zod.optout); + defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + const right = def.out._zod.run(payload, ctx); + if (right instanceof Promise) { + return right.then((right2) => handlePipeResult(right2, def.in, ctx)); + } + return handlePipeResult(right, def.in, ctx); + } + const left = def.in._zod.run(payload, ctx); + if (left instanceof Promise) { + return left.then((left2) => handlePipeResult(left2, def.out, ctx)); + } + return handlePipeResult(left, def.out, ctx); + }; +}); +function handlePipeResult(left, next, ctx) { + if (left.issues.length) { + left.aborted = true; + return left; + } + return next._zod.run({ value: left.value, issues: left.issues, fallback: left.fallback }, ctx); +} +var $ZodReadonly = /* @__PURE__ */ $constructor("$ZodReadonly", (inst, def) => { + $ZodType.init(inst, def); + defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); + defineLazy(inst._zod, "values", () => def.innerType._zod.values); + defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); + defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + inst._zod.parse = (payload, ctx) => { + if (ctx.direction === "backward") { + return def.innerType._zod.run(payload, ctx); + } + const result = def.innerType._zod.run(payload, ctx); + if (result instanceof Promise) { + return result.then(handleReadonlyResult); + } + return handleReadonlyResult(result); + }; +}); +function handleReadonlyResult(payload) { + payload.value = Object.freeze(payload.value); + return payload; +} +var $ZodCustom = /* @__PURE__ */ $constructor("$ZodCustom", (inst, def) => { + $ZodCheck.init(inst, def); + $ZodType.init(inst, def); + inst._zod.parse = (payload, _) => { + return payload; + }; + inst._zod.check = (payload) => { + const input = payload.value; + const r = def.fn(input); + if (r instanceof Promise) { + return r.then((r2) => handleRefineResult(r2, payload, input, inst)); + } + handleRefineResult(r, payload, input, inst); + return; + }; +}); +function handleRefineResult(result, payload, input, inst) { + if (!result) { + const _iss = { + code: "custom", + input, + inst, + // incorporates params.error into issue reporting + path: [...inst._zod.def.path ?? []], + // incorporates params.error into issue reporting + continue: !inst._zod.def.abort + // params: inst._zod.def.params, + }; + if (inst._zod.def.params) + _iss.params = inst._zod.def.params; + payload.issues.push(issue(_iss)); + } +} + +// node_modules/zod/v4/core/registries.js +var _a2; +var $ZodRegistry = class { + constructor() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + } + add(schema, ..._meta) { + const meta2 = _meta[0]; + this._map.set(schema, meta2); + if (meta2 && typeof meta2 === "object" && "id" in meta2) { + this._idmap.set(meta2.id, schema); + } + return this; + } + clear() { + this._map = /* @__PURE__ */ new WeakMap(); + this._idmap = /* @__PURE__ */ new Map(); + return this; + } + remove(schema) { + const meta2 = this._map.get(schema); + if (meta2 && typeof meta2 === "object" && "id" in meta2) { + this._idmap.delete(meta2.id); + } + this._map.delete(schema); + return this; + } + get(schema) { + const p = schema._zod.parent; + if (p) { + const pm = { ...this.get(p) ?? {} }; + delete pm.id; + const f = { ...pm, ...this._map.get(schema) }; + return Object.keys(f).length ? f : void 0; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } +}; +function registry() { + return new $ZodRegistry(); +} +(_a2 = globalThis).__zod_globalRegistry ?? (_a2.__zod_globalRegistry = registry()); +var globalRegistry = globalThis.__zod_globalRegistry; + +// node_modules/zod/v4/core/api.js +// @__NO_SIDE_EFFECTS__ +function _string(Class2, params) { + return new Class2({ + type: "string", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _email(Class2, params) { + return new Class2({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _guid(Class2, params) { + return new Class2({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuid(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv4(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv6(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uuidv7(Class2, params) { + return new Class2({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _url(Class2, params) { + return new Class2({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _emoji2(Class2, params) { + return new Class2({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _nanoid(Class2, params) { + return new Class2({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cuid(Class2, params) { + return new Class2({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cuid2(Class2, params) { + return new Class2({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ulid(Class2, params) { + return new Class2({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _xid(Class2, params) { + return new Class2({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ksuid(Class2, params) { + return new Class2({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ipv4(Class2, params) { + return new Class2({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _ipv6(Class2, params) { + return new Class2({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cidrv4(Class2, params) { + return new Class2({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _cidrv6(Class2, params) { + return new Class2({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _base64(Class2, params) { + return new Class2({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _base64url(Class2, params) { + return new Class2({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _e164(Class2, params) { + return new Class2({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _jwt(Class2, params) { + return new Class2({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDateTime(Class2, params) { + return new Class2({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDate(Class2, params) { + return new Class2({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoTime(Class2, params) { + return new Class2({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _isoDuration(Class2, params) { + return new Class2({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _number(Class2, params) { + return new Class2({ + type: "number", + checks: [], + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _int(Class2, params) { + return new Class2({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _boolean(Class2, params) { + return new Class2({ + type: "boolean", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _unknown(Class2) { + return new Class2({ + type: "unknown" + }); +} +// @__NO_SIDE_EFFECTS__ +function _never(Class2, params) { + return new Class2({ + type: "never", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _lt(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: false + }); +} +// @__NO_SIDE_EFFECTS__ +function _lte(value, params) { + return new $ZodCheckLessThan({ + check: "less_than", + ...normalizeParams(params), + value, + inclusive: true + }); +} +// @__NO_SIDE_EFFECTS__ +function _gt(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: false + }); +} +// @__NO_SIDE_EFFECTS__ +function _gte(value, params) { + return new $ZodCheckGreaterThan({ + check: "greater_than", + ...normalizeParams(params), + value, + inclusive: true + }); +} +// @__NO_SIDE_EFFECTS__ +function _multipleOf(value, params) { + return new $ZodCheckMultipleOf({ + check: "multiple_of", + ...normalizeParams(params), + value + }); +} +// @__NO_SIDE_EFFECTS__ +function _maxLength(maximum, params) { + const ch = new $ZodCheckMaxLength({ + check: "max_length", + ...normalizeParams(params), + maximum + }); + return ch; +} +// @__NO_SIDE_EFFECTS__ +function _minLength(minimum, params) { + return new $ZodCheckMinLength({ + check: "min_length", + ...normalizeParams(params), + minimum + }); +} +// @__NO_SIDE_EFFECTS__ +function _length(length, params) { + return new $ZodCheckLengthEquals({ + check: "length_equals", + ...normalizeParams(params), + length + }); +} +// @__NO_SIDE_EFFECTS__ +function _regex(pattern, params) { + return new $ZodCheckRegex({ + check: "string_format", + format: "regex", + ...normalizeParams(params), + pattern + }); +} +// @__NO_SIDE_EFFECTS__ +function _lowercase(params) { + return new $ZodCheckLowerCase({ + check: "string_format", + format: "lowercase", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _uppercase(params) { + return new $ZodCheckUpperCase({ + check: "string_format", + format: "uppercase", + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _includes(includes, params) { + return new $ZodCheckIncludes({ + check: "string_format", + format: "includes", + ...normalizeParams(params), + includes + }); +} +// @__NO_SIDE_EFFECTS__ +function _startsWith(prefix, params) { + return new $ZodCheckStartsWith({ + check: "string_format", + format: "starts_with", + ...normalizeParams(params), + prefix + }); +} +// @__NO_SIDE_EFFECTS__ +function _endsWith(suffix, params) { + return new $ZodCheckEndsWith({ + check: "string_format", + format: "ends_with", + ...normalizeParams(params), + suffix + }); +} +// @__NO_SIDE_EFFECTS__ +function _overwrite(tx) { + return new $ZodCheckOverwrite({ + check: "overwrite", + tx + }); +} +// @__NO_SIDE_EFFECTS__ +function _normalize(form) { + return /* @__PURE__ */ _overwrite((input) => input.normalize(form)); +} +// @__NO_SIDE_EFFECTS__ +function _trim() { + return /* @__PURE__ */ _overwrite((input) => input.trim()); +} +// @__NO_SIDE_EFFECTS__ +function _toLowerCase() { + return /* @__PURE__ */ _overwrite((input) => input.toLowerCase()); +} +// @__NO_SIDE_EFFECTS__ +function _toUpperCase() { + return /* @__PURE__ */ _overwrite((input) => input.toUpperCase()); +} +// @__NO_SIDE_EFFECTS__ +function _slugify() { + return /* @__PURE__ */ _overwrite((input) => slugify(input)); +} +// @__NO_SIDE_EFFECTS__ +function _array(Class2, element, params) { + return new Class2({ + type: "array", + element, + // get element() { + // return element; + // }, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ +function _refine(Class2, fn, _params) { + const schema = new Class2({ + type: "custom", + check: "custom", + fn, + ...normalizeParams(_params) + }); + return schema; +} +// @__NO_SIDE_EFFECTS__ +function _superRefine(fn, params) { + const ch = /* @__PURE__ */ _check((payload) => { + payload.addIssue = (issue2) => { + if (typeof issue2 === "string") { + payload.issues.push(issue(issue2, payload.value, ch._zod.def)); + } else { + const _issue = issue2; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(issue(_issue)); + } + }; + return fn(payload.value, payload); + }, params); + return ch; +} +// @__NO_SIDE_EFFECTS__ +function _check(fn, params) { + const ch = new $ZodCheck({ + check: "custom", + ...normalizeParams(params) + }); + ch._zod.check = fn; + return ch; +} + +// node_modules/zod/v4/core/to-json-schema.js +function initializeContext(params) { + let target = params?.target ?? "draft-2020-12"; + if (target === "draft-4") + target = "draft-04"; + if (target === "draft-7") + target = "draft-07"; + return { + processors: params.processors ?? {}, + metadataRegistry: params?.metadata ?? globalRegistry, + target, + unrepresentable: params?.unrepresentable ?? "throw", + override: params?.override ?? (() => { + }), + io: params?.io ?? "output", + counter: 0, + seen: /* @__PURE__ */ new Map(), + cycles: params?.cycles ?? "ref", + reused: params?.reused ?? "inline", + external: params?.external ?? void 0 + }; +} +function process2(schema, ctx, _params = { path: [], schemaPath: [] }) { + var _a3; + const def = schema._zod.def; + const seen = ctx.seen.get(schema); + if (seen) { + seen.count++; + const isCycle = _params.schemaPath.includes(schema); + if (isCycle) { + seen.cycle = _params.path; + } + return seen.schema; + } + const result = { schema: {}, count: 1, cycle: void 0, path: _params.path }; + ctx.seen.set(schema, result); + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) { + result.schema = overrideSchema; + } else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path + }; + if (schema._zod.processJSONSchema) { + schema._zod.processJSONSchema(ctx, result.schema, params); + } else { + const _json = result.schema; + const processor = ctx.processors[def.type]; + if (!processor) { + throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`); + } + processor(schema, ctx, _json, params); + } + const parent = schema._zod.parent; + if (parent) { + if (!result.ref) + result.ref = parent; + process2(parent, ctx, params); + ctx.seen.get(parent).isParent = true; + } + } + const meta2 = ctx.metadataRegistry.get(schema); + if (meta2) + Object.assign(result.schema, meta2); + if (ctx.io === "input" && isTransforming(schema)) { + delete result.schema.examples; + delete result.schema.default; + } + if (ctx.io === "input" && "_prefault" in result.schema) + (_a3 = result.schema).default ?? (_a3.default = result.schema._prefault); + delete result.schema._prefault; + const _result = ctx.seen.get(schema); + return _result.schema; +} +function extractDefs(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) + throw new Error("Unprocessed schema. This is a bug in Zod."); + const idToSchema = /* @__PURE__ */ new Map(); + for (const entry of ctx.seen.entries()) { + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + const existing = idToSchema.get(id); + if (existing && existing !== entry[0]) { + throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`); + } + idToSchema.set(id, entry[0]); + } + } + const makeURI = (entry) => { + const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions"; + if (ctx.external) { + const externalId = ctx.external.registry.get(entry[0])?.id; + const uriGenerator = ctx.external.uri ?? ((id2) => id2); + if (externalId) { + return { ref: uriGenerator(externalId) }; + } + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`; + entry[1].defId = id; + return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` }; + } + if (entry[1] === root) { + return { ref: "#" }; + } + const uriPrefix = `#`; + const defUriPrefix = `${uriPrefix}/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`; + return { defId, ref: defUriPrefix + defId }; + }; + const extractToDef = (entry) => { + if (entry[1].schema.$ref) { + return; + } + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + if (defId) + seen.defId = defId; + const schema2 = seen.schema; + for (const key in schema2) { + delete schema2[key]; + } + schema2.$ref = ref; + }; + if (ctx.cycles === "throw") { + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) { + throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/ + +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`); + } + } + } + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (schema === entry[0]) { + extractToDef(entry); + continue; + } + if (ctx.external) { + const ext = ctx.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + const id = ctx.metadataRegistry.get(entry[0])?.id; + if (id) { + extractToDef(entry); + continue; + } + if (seen.cycle) { + extractToDef(entry); + continue; + } + if (seen.count > 1) { + if (ctx.reused === "ref") { + extractToDef(entry); + continue; + } + } + } +} +function finalize(ctx, schema) { + const root = ctx.seen.get(schema); + if (!root) + throw new Error("Unprocessed schema. This is a bug in Zod."); + const flattenRef = (zodSchema) => { + const seen = ctx.seen.get(zodSchema); + if (seen.ref === null) + return; + const schema2 = seen.def ?? seen.schema; + const _cached = { ...schema2 }; + const ref = seen.ref; + seen.ref = null; + if (ref) { + flattenRef(ref); + const refSeen = ctx.seen.get(ref); + const refSchema = refSeen.schema; + if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) { + schema2.allOf = schema2.allOf ?? []; + schema2.allOf.push(refSchema); + } else { + Object.assign(schema2, refSchema); + } + Object.assign(schema2, _cached); + const isParentRef = zodSchema._zod.parent === ref; + if (isParentRef) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (!(key in _cached)) { + delete schema2[key]; + } + } + } + if (refSchema.$ref && refSeen.def) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (key in refSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(refSeen.def[key])) { + delete schema2[key]; + } + } + } + } + const parent = zodSchema._zod.parent; + if (parent && parent !== ref) { + flattenRef(parent); + const parentSeen = ctx.seen.get(parent); + if (parentSeen?.schema.$ref) { + schema2.$ref = parentSeen.schema.$ref; + if (parentSeen.def) { + for (const key in schema2) { + if (key === "$ref" || key === "allOf") + continue; + if (key in parentSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(parentSeen.def[key])) { + delete schema2[key]; + } + } + } + } + } + ctx.override({ + zodSchema, + jsonSchema: schema2, + path: seen.path ?? [] + }); + }; + for (const entry of [...ctx.seen.entries()].reverse()) { + flattenRef(entry[0]); + } + const result = {}; + if (ctx.target === "draft-2020-12") { + result.$schema = "https://json-schema.org/draft/2020-12/schema"; + } else if (ctx.target === "draft-07") { + result.$schema = "http://json-schema.org/draft-07/schema#"; + } else if (ctx.target === "draft-04") { + result.$schema = "http://json-schema.org/draft-04/schema#"; + } else if (ctx.target === "openapi-3.0") { + } else { + } + if (ctx.external?.uri) { + const id = ctx.external.registry.get(schema)?.id; + if (!id) + throw new Error("Schema is missing an `id` property"); + result.$id = ctx.external.uri(id); + } + Object.assign(result, root.def ?? root.schema); + const rootMetaId = ctx.metadataRegistry.get(schema)?.id; + if (rootMetaId !== void 0 && result.id === rootMetaId) + delete result.id; + const defs = ctx.external?.defs ?? {}; + for (const entry of ctx.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + if (seen.def.id === seen.defId) + delete seen.def.id; + defs[seen.defId] = seen.def; + } + } + if (ctx.external) { + } else { + if (Object.keys(defs).length > 0) { + if (ctx.target === "draft-2020-12") { + result.$defs = defs; + } else { + result.definitions = defs; + } + } + } + try { + const finalized = JSON.parse(JSON.stringify(result)); + Object.defineProperty(finalized, "~standard", { + value: { + ...schema["~standard"], + jsonSchema: { + input: createStandardJSONSchemaMethod(schema, "input", ctx.processors), + output: createStandardJSONSchemaMethod(schema, "output", ctx.processors) + } + }, + enumerable: false, + writable: false + }); + return finalized; + } catch (_err) { + throw new Error("Error converting schema to JSON."); + } +} +function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: /* @__PURE__ */ new Set() }; + if (ctx.seen.has(_schema)) + return false; + ctx.seen.add(_schema); + const def = _schema._zod.def; + if (def.type === "transform") + return true; + if (def.type === "array") + return isTransforming(def.element, ctx); + if (def.type === "set") + return isTransforming(def.valueType, ctx); + if (def.type === "lazy") + return isTransforming(def.getter(), ctx); + if (def.type === "promise" || def.type === "optional" || def.type === "nonoptional" || def.type === "nullable" || def.type === "readonly" || def.type === "default" || def.type === "prefault") { + return isTransforming(def.innerType, ctx); + } + if (def.type === "intersection") { + return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + } + if (def.type === "record" || def.type === "map") { + return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + } + if (def.type === "pipe") { + if (_schema._zod.traits.has("$ZodCodec")) + return true; + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + if (def.type === "object") { + for (const key in def.shape) { + if (isTransforming(def.shape[key], ctx)) + return true; + } + return false; + } + if (def.type === "union") { + for (const option of def.options) { + if (isTransforming(option, ctx)) + return true; + } + return false; + } + if (def.type === "tuple") { + for (const item of def.items) { + if (isTransforming(item, ctx)) + return true; + } + if (def.rest && isTransforming(def.rest, ctx)) + return true; + return false; + } + return false; +} +var createToJSONSchemaMethod = (schema, processors = {}) => (params) => { + const ctx = initializeContext({ ...params, processors }); + process2(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); +}; +var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { + const { libraryOptions, target } = params ?? {}; + const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors }); + process2(schema, ctx); + extractDefs(ctx, schema); + return finalize(ctx, schema); +}; + +// node_modules/zod/v4/core/json-schema-processors.js +var formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "" + // do not set +}; +var stringProcessor = (schema, ctx, _json, _params) => { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag; + if (typeof minimum === "number") + json.minLength = minimum; + if (typeof maximum === "number") + json.maxLength = maximum; + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") + delete json.format; + if (format === "time") { + delete json.format; + } + } + if (contentEncoding) + json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) + json.pattern = regexes[0].source; + else if (regexes.length > 1) { + json.allOf = [ + ...regexes.map((regex) => ({ + ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {}, + pattern: regex.source + })) + ]; + } + } +}; +var numberProcessor = (schema, ctx, _json, _params) => { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) + json.type = "integer"; + else + json.type = "number"; + const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); + const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); + const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; + if (exMin) { + if (legacy) { + json.minimum = exclusiveMinimum; + json.exclusiveMinimum = true; + } else { + json.exclusiveMinimum = exclusiveMinimum; + } + } else if (typeof minimum === "number") { + json.minimum = minimum; + } + if (exMax) { + if (legacy) { + json.maximum = exclusiveMaximum; + json.exclusiveMaximum = true; + } else { + json.exclusiveMaximum = exclusiveMaximum; + } + } else if (typeof maximum === "number") { + json.maximum = maximum; + } + if (typeof multipleOf === "number") + json.multipleOf = multipleOf; +}; +var booleanProcessor = (_schema, _ctx, json, _params) => { + json.type = "boolean"; +}; +var neverProcessor = (_schema, _ctx, json, _params) => { + json.not = {}; +}; +var unknownProcessor = (_schema, _ctx, _json, _params) => { +}; +var enumProcessor = (schema, _ctx, json, _params) => { + const def = schema._zod.def; + const values = getEnumValues(def.entries); + if (values.every((v) => typeof v === "number")) + json.type = "number"; + if (values.every((v) => typeof v === "string")) + json.type = "string"; + json.enum = values; +}; +var customProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") { + throw new Error("Custom types cannot be represented in JSON Schema"); + } +}; +var transformProcessor = (_schema, ctx, _json, _params) => { + if (ctx.unrepresentable === "throw") { + throw new Error("Transforms cannot be represented in JSON Schema"); + } +}; +var arrayProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") + json.minItems = minimum; + if (typeof maximum === "number") + json.maxItems = maximum; + json.type = "array"; + json.items = process2(def.element, ctx, { + ...params, + path: [...params.path, "items"] + }); +}; +var objectProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + json.properties = {}; + const shape = def.shape; + for (const key in shape) { + json.properties[key] = process2(shape[key], ctx, { + ...params, + path: [...params.path, "properties", key] + }); + } + const allKeys = new Set(Object.keys(shape)); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (ctx.io === "input") { + return v.optin === void 0; + } else { + return v.optout === void 0; + } + })); + if (requiredKeys.size > 0) { + json.required = Array.from(requiredKeys); + } + if (def.catchall?._zod.def.type === "never") { + json.additionalProperties = false; + } else if (!def.catchall) { + if (ctx.io === "output") + json.additionalProperties = false; + } else if (def.catchall) { + json.additionalProperties = process2(def.catchall, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } +}; +var unionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const isExclusive = def.inclusive === false; + const options = def.options.map((x, i) => process2(x, ctx, { + ...params, + path: [...params.path, isExclusive ? "oneOf" : "anyOf", i] + })); + if (isExclusive) { + json.oneOf = options; + } else { + json.anyOf = options; + } +}; +var intersectionProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const a = process2(def.left, ctx, { + ...params, + path: [...params.path, "allOf", 0] + }); + const b = process2(def.right, ctx, { + ...params, + path: [...params.path, "allOf", 1] + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + const allOf = [ + ...isSimpleIntersection(a) ? a.allOf : [a], + ...isSimpleIntersection(b) ? b.allOf : [b] + ]; + json.allOf = allOf; +}; +var recordProcessor = (schema, ctx, _json, params) => { + const json = _json; + const def = schema._zod.def; + json.type = "object"; + const keyType = def.keyType; + const keyBag = keyType._zod.bag; + const patterns = keyBag?.patterns; + if (def.mode === "loose" && patterns && patterns.size > 0) { + const valueSchema = process2(def.valueType, ctx, { + ...params, + path: [...params.path, "patternProperties", "*"] + }); + json.patternProperties = {}; + for (const pattern of patterns) { + json.patternProperties[pattern.source] = valueSchema; + } + } else { + if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") { + json.propertyNames = process2(def.keyType, ctx, { + ...params, + path: [...params.path, "propertyNames"] + }); + } + json.additionalProperties = process2(def.valueType, ctx, { + ...params, + path: [...params.path, "additionalProperties"] + }); + } + const keyValues = keyType._zod.values; + if (keyValues) { + const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number"); + if (validKeyValues.length > 0) { + json.required = validKeyValues; + } + } +}; +var nullableProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + const inner = process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + if (ctx.target === "openapi-3.0") { + seen.ref = def.innerType; + json.nullable = true; + } else { + json.anyOf = [inner, { type: "null" }]; + } +}; +var nonoptionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; +}; +var defaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.default = JSON.parse(JSON.stringify(def.defaultValue)); +}; +var prefaultProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + if (ctx.io === "input") + json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); +}; +var catchProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(void 0); + } catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + json.default = catchValue; +}; +var pipeProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + const inIsTransform = def.in._zod.traits.has("$ZodTransform"); + const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; + process2(innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = innerType; +}; +var readonlyProcessor = (schema, ctx, json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; + json.readOnly = true; +}; +var optionalProcessor = (schema, ctx, _json, params) => { + const def = schema._zod.def; + process2(def.innerType, ctx, params); + const seen = ctx.seen.get(schema); + seen.ref = def.innerType; +}; + +// node_modules/zod/v4/classic/iso.js +var ZodISODateTime = /* @__PURE__ */ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function datetime2(params) { + return _isoDateTime(ZodISODateTime, params); +} +var ZodISODate = /* @__PURE__ */ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function date2(params) { + return _isoDate(ZodISODate, params); +} +var ZodISOTime = /* @__PURE__ */ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function time2(params) { + return _isoTime(ZodISOTime, params); +} +var ZodISODuration = /* @__PURE__ */ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function duration2(params) { + return _isoDuration(ZodISODuration, params); +} + +// node_modules/zod/v4/classic/errors.js +var initializer2 = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { + value: (mapper) => formatError(inst, mapper) + // enumerable: false, + }, + flatten: { + value: (mapper) => flattenError(inst, mapper) + // enumerable: false, + }, + addIssue: { + value: (issue2) => { + inst.issues.push(issue2); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } + // enumerable: false, + }, + addIssues: { + value: (issues2) => { + inst.issues.push(...issues2); + inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); + } + // enumerable: false, + }, + isEmpty: { + get() { + return inst.issues.length === 0; + } + // enumerable: false, + } + }); +}; +var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, { + Parent: Error +}); + +// node_modules/zod/v4/classic/parse.js +var parse2 = /* @__PURE__ */ _parse(ZodRealError); +var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError); +var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError); +var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError); +var encode = /* @__PURE__ */ _encode(ZodRealError); +var decode = /* @__PURE__ */ _decode(ZodRealError); +var encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); +var decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); +var safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); +var safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); +var safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); +var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); + +// node_modules/zod/v4/classic/schemas.js +var _installedGroups = /* @__PURE__ */ new WeakMap(); +function _installLazyMethods(inst, group, methods) { + const proto = Object.getPrototypeOf(inst); + let installed = _installedGroups.get(proto); + if (!installed) { + installed = /* @__PURE__ */ new Set(); + _installedGroups.set(proto, installed); + } + if (installed.has(group)) + return; + installed.add(group); + for (const key in methods) { + const fn = methods[key]; + Object.defineProperty(proto, key, { + configurable: true, + enumerable: false, + get() { + const bound = fn.bind(this); + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: bound + }); + return bound; + }, + set(v) { + Object.defineProperty(this, key, { + configurable: true, + writable: true, + enumerable: true, + value: v + }); + } + }); + } +} +var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + Object.assign(inst["~standard"], { + jsonSchema: { + input: createStandardJSONSchemaMethod(inst, "input"), + output: createStandardJSONSchemaMethod(inst, "output") + } + }); + inst.toJSONSchema = createToJSONSchemaMethod(inst, {}); + inst.def = def; + inst.type = def.type; + Object.defineProperty(inst, "_def", { value: def }); + inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => safeParse2(inst, data, params); + inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params); + inst.spa = inst.safeParseAsync; + inst.encode = (data, params) => encode(inst, data, params); + inst.decode = (data, params) => decode(inst, data, params); + inst.encodeAsync = async (data, params) => encodeAsync(inst, data, params); + inst.decodeAsync = async (data, params) => decodeAsync(inst, data, params); + inst.safeEncode = (data, params) => safeEncode(inst, data, params); + inst.safeDecode = (data, params) => safeDecode(inst, data, params); + inst.safeEncodeAsync = async (data, params) => safeEncodeAsync(inst, data, params); + inst.safeDecodeAsync = async (data, params) => safeDecodeAsync(inst, data, params); + _installLazyMethods(inst, "ZodType", { + check(...chks) { + const def2 = this.def; + return this.clone(util_exports.mergeDefs(def2, { + checks: [ + ...def2.checks ?? [], + ...chks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch) + ] + }), { parent: true }); + }, + with(...chks) { + return this.check(...chks); + }, + clone(def2, params) { + return clone(this, def2, params); + }, + brand() { + return this; + }, + register(reg, meta2) { + reg.add(this, meta2); + return this; + }, + refine(check, params) { + return this.check(refine(check, params)); + }, + superRefine(refinement, params) { + return this.check(superRefine(refinement, params)); + }, + overwrite(fn) { + return this.check(_overwrite(fn)); + }, + optional() { + return optional(this); + }, + exactOptional() { + return exactOptional(this); + }, + nullable() { + return nullable(this); + }, + nullish() { + return optional(nullable(this)); + }, + nonoptional(params) { + return nonoptional(this, params); + }, + array() { + return array(this); + }, + or(arg) { + return union([this, arg]); + }, + and(arg) { + return intersection(this, arg); + }, + transform(tx) { + return pipe(this, transform(tx)); + }, + default(d) { + return _default(this, d); + }, + prefault(d) { + return prefault(this, d); + }, + catch(params) { + return _catch(this, params); + }, + pipe(target) { + return pipe(this, target); + }, + readonly() { + return readonly(this); + }, + describe(description) { + const cl = this.clone(); + globalRegistry.add(cl, { description }); + return cl; + }, + meta(...args) { + if (args.length === 0) + return globalRegistry.get(this); + const cl = this.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }, + isOptional() { + return this.safeParse(void 0).success; + }, + isNullable() { + return this.safeParse(null).success; + }, + apply(fn) { + return fn(this); + } + }); + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true + }); + return inst; +}); +var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json, params); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + _installLazyMethods(inst, "_ZodString", { + regex(...args) { + return this.check(_regex(...args)); + }, + includes(...args) { + return this.check(_includes(...args)); + }, + startsWith(...args) { + return this.check(_startsWith(...args)); + }, + endsWith(...args) { + return this.check(_endsWith(...args)); + }, + min(...args) { + return this.check(_minLength(...args)); + }, + max(...args) { + return this.check(_maxLength(...args)); + }, + length(...args) { + return this.check(_length(...args)); + }, + nonempty(...args) { + return this.check(_minLength(1, ...args)); + }, + lowercase(params) { + return this.check(_lowercase(params)); + }, + uppercase(params) { + return this.check(_uppercase(params)); + }, + trim() { + return this.check(_trim()); + }, + normalize(...args) { + return this.check(_normalize(...args)); + }, + toLowerCase() { + return this.check(_toLowerCase()); + }, + toUpperCase() { + return this.check(_toUpperCase()); + }, + slugify() { + return this.check(_slugify()); + } + }); +}); +var ZodString = /* @__PURE__ */ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(_email(ZodEmail, params)); + inst.url = (params) => inst.check(_url(ZodURL, params)); + inst.jwt = (params) => inst.check(_jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(_emoji2(ZodEmoji, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(_uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(_uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(_uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(_uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(_nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(_cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(_cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(_ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(_base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(_base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(_xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(_ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(_ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(_ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(_cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(_cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(_e164(ZodE164, params)); + inst.datetime = (params) => inst.check(datetime2(params)); + inst.date = (params) => inst.check(date2(params)); + inst.time = (params) => inst.check(time2(params)); + inst.duration = (params) => inst.check(duration2(params)); +}); +function string2(params) { + return _string(ZodString, params); +} +var ZodStringFormat = /* @__PURE__ */ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); +}); +var ZodEmail = /* @__PURE__ */ $constructor("ZodEmail", (inst, def) => { + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodGUID = /* @__PURE__ */ $constructor("ZodGUID", (inst, def) => { + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodUUID = /* @__PURE__ */ $constructor("ZodUUID", (inst, def) => { + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodURL = /* @__PURE__ */ $constructor("ZodURL", (inst, def) => { + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodEmoji = /* @__PURE__ */ $constructor("ZodEmoji", (inst, def) => { + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodNanoID = /* @__PURE__ */ $constructor("ZodNanoID", (inst, def) => { + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCUID = /* @__PURE__ */ $constructor("ZodCUID", (inst, def) => { + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCUID2 = /* @__PURE__ */ $constructor("ZodCUID2", (inst, def) => { + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodULID = /* @__PURE__ */ $constructor("ZodULID", (inst, def) => { + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodXID = /* @__PURE__ */ $constructor("ZodXID", (inst, def) => { + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodKSUID = /* @__PURE__ */ $constructor("ZodKSUID", (inst, def) => { + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodIPv4 = /* @__PURE__ */ $constructor("ZodIPv4", (inst, def) => { + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodIPv6 = /* @__PURE__ */ $constructor("ZodIPv6", (inst, def) => { + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCIDRv4 = /* @__PURE__ */ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodCIDRv6 = /* @__PURE__ */ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodBase64 = /* @__PURE__ */ $constructor("ZodBase64", (inst, def) => { + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => { + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodE164 = /* @__PURE__ */ $constructor("ZodE164", (inst, def) => { + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => { + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); +}); +var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json, params); + _installLazyMethods(inst, "ZodNumber", { + gt(value, params) { + return this.check(_gt(value, params)); + }, + gte(value, params) { + return this.check(_gte(value, params)); + }, + min(value, params) { + return this.check(_gte(value, params)); + }, + lt(value, params) { + return this.check(_lt(value, params)); + }, + lte(value, params) { + return this.check(_lte(value, params)); + }, + max(value, params) { + return this.check(_lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(_gt(0, params)); + }, + nonnegative(params) { + return this.check(_gte(0, params)); + }, + negative(params) { + return this.check(_lt(0, params)); + }, + nonpositive(params) { + return this.check(_lte(0, params)); + }, + multipleOf(value, params) { + return this.check(_multipleOf(value, params)); + }, + step(value, params) { + return this.check(_multipleOf(value, params)); + }, + finite() { + return this; + } + }); + const bag = inst._zod.bag; + inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); + inst.isFinite = true; + inst.format = bag.format ?? null; +}); +function number2(params) { + return _number(ZodNumber, params); +} +var ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + ZodNumber.init(inst, def); +}); +function int(params) { + return _int(ZodNumberFormat, params); +} +var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params); +}); +function boolean2(params) { + return _boolean(ZodBoolean, params); +} +var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unknownProcessor(inst, ctx, json, params); +}); +function unknown() { + return _unknown(ZodUnknown); +} +var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json, params); +}); +function never(params) { + return _never(ZodNever, params); +} +var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params); + inst.element = def.element; + _installLazyMethods(inst, "ZodArray", { + min(n, params) { + return this.check(_minLength(n, params)); + }, + nonempty(params) { + return this.check(_minLength(1, params)); + }, + max(n, params) { + return this.check(_maxLength(n, params)); + }, + length(n, params) { + return this.check(_length(n, params)); + }, + unwrap() { + return this.element; + } + }); +}); +function array(element, params) { + return _array(ZodArray, element, params); +} +var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => { + $ZodObjectJIT.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params); + util_exports.defineLazy(inst, "shape", () => { + return def.shape; + }); + _installLazyMethods(inst, "ZodObject", { + keyof() { + return _enum(Object.keys(this._zod.def.shape)); + }, + catchall(catchall) { + return this.clone({ ...this._zod.def, catchall }); + }, + passthrough() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + loose() { + return this.clone({ ...this._zod.def, catchall: unknown() }); + }, + strict() { + return this.clone({ ...this._zod.def, catchall: never() }); + }, + strip() { + return this.clone({ ...this._zod.def, catchall: void 0 }); + }, + extend(incoming) { + return util_exports.extend(this, incoming); + }, + safeExtend(incoming) { + return util_exports.safeExtend(this, incoming); + }, + merge(other) { + return util_exports.merge(this, other); + }, + pick(mask) { + return util_exports.pick(this, mask); + }, + omit(mask) { + return util_exports.omit(this, mask); + }, + partial(...args) { + return util_exports.partial(ZodOptional, this, args[0]); + }, + required(...args) { + return util_exports.required(ZodNonOptional, this, args[0]); + } + }); +}); +function object(shape, params) { + const def = { + type: "object", + shape: shape ?? {}, + ...util_exports.normalizeParams(params) + }; + return new ZodObject(def); +} +var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params); + inst.options = def.options; +}); +function union(options, params) { + return new ZodUnion({ + type: "union", + options, + ...util_exports.normalizeParams(params) + }); +} +var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params); +}); +function intersection(left, right) { + return new ZodIntersection({ + type: "intersection", + left, + right + }); +} +var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params); + inst.keyType = def.keyType; + inst.valueType = def.valueType; +}); +function record(keyType, valueType, params) { + if (!valueType || !valueType._zod) { + return new ZodRecord({ + type: "record", + keyType: string2(), + valueType: keyType, + ...util_exports.normalizeParams(valueType) + }); + } + return new ZodRecord({ + type: "record", + keyType, + valueType, + ...util_exports.normalizeParams(params) + }); +} +var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json, params); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) { + if (keys.has(value)) { + newEntries[value] = def.entries[value]; + } else + throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util_exports.normalizeParams(params), + entries: newEntries + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) { + if (keys.has(value)) { + delete newEntries[value]; + } else + throw new Error(`Key ${value} not found in enum`); + } + return new ZodEnum({ + ...def, + checks: [], + ...util_exports.normalizeParams(params), + entries: newEntries + }); + }; +}); +function _enum(values, params) { + const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values; + return new ZodEnum({ + type: "enum", + entries, + ...util_exports.normalizeParams(params) + }); +} +var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx, json, params); + inst._zod.parse = (payload, _ctx) => { + if (_ctx.direction === "backward") { + throw new $ZodEncodeError(inst.constructor.name); + } + payload.addIssue = (issue2) => { + if (typeof issue2 === "string") { + payload.issues.push(util_exports.issue(issue2, payload.value, def)); + } else { + const _issue = issue2; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + payload.issues.push(util_exports.issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) { + return output.then((output2) => { + payload.value = output2; + payload.fallback = true; + return payload; + }); + } + payload.value = output; + payload.fallback = true; + return payload; + }; +}); +function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn + }); +} +var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function optional(innerType) { + return new ZodOptional({ + type: "optional", + innerType + }); +} +var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => { + $ZodExactOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function exactOptional(innerType) { + return new ZodExactOptional({ + type: "optional", + innerType + }); +} +var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nullable(innerType) { + return new ZodNullable({ + type: "nullable", + innerType + }); +} +var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; +}); +function _default(innerType, defaultValue) { + return new ZodDefault({ + type: "default", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : util_exports.shallowClone(defaultValue); + } + }); +} +var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : util_exports.shallowClone(defaultValue); + } + }); +} +var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType, + ...util_exports.normalizeParams(params) + }); +} +var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; +}); +function _catch(innerType, catchValue) { + return new ZodCatch({ + type: "catch", + innerType, + catchValue: typeof catchValue === "function" ? catchValue : () => catchValue + }); +} +var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params); + inst.in = def.in; + inst.out = def.out; +}); +function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out + // ...util.normalizeParams(params), + }); +} +var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params); + inst.unwrap = () => inst._zod.def.innerType; +}); +function readonly(innerType) { + return new ZodReadonly({ + type: "readonly", + innerType + }); +} +var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx, json, params); +}); +function refine(fn, _params = {}) { + return _refine(ZodCustom, fn, _params); +} +function superRefine(fn, params) { + return _superRefine(fn, params); +} + +// src/issue-triage/policy.ts +var triagePolicySchema = object({ + version: number2().int().positive(), + duplicateConfidenceThreshold: number2().min(0).max(1), + classificationConfidenceThreshold: number2().min(0).max(1), + priorityConfidenceThreshold: number2().min(0).max(1), + maxCandidates: number2().int().min(0).max(100), + maxRelatedIssues: number2().int().min(0).max(20), + skipLabels: array(string2().min(1)), + managedLabelPrefixes: array(string2().min(1)), + classificationLabels: object({ + bug: string2().min(1), + enhancement: string2().min(1), + documentation: string2().min(1), + question: string2().min(1) + }), + labelColors: record(string2(), string2().regex(/^[0-9a-fA-F]{6}$/)), + labelDescriptions: record(string2(), string2().min(1).max(100)) +}); +function calculatePriority(analysis, policy) { + const { facts } = analysis; + if (facts.securityImpact === "critical" || facts.dataLoss === true || facts.environment === "production" && facts.productionImpact === "outage") { + return "P0"; + } + if (facts.securityImpact === "high" || facts.releaseBlocker === true || facts.environment === "production" && facts.coreFlowBlocked === true && facts.workaround === "none") { + return "P1"; + } + if (analysis.priorityConfidence < policy.priorityConfidenceThreshold) { + return "pending"; + } + const lacksImpactEvidence = facts.productionImpact === "unknown" && facts.affectedScope === "unknown" && facts.slaRisk === null && facts.releaseBlocker === null; + if (lacksImpactEvidence) { + return "pending"; + } + if (facts.productionImpact === "degraded" || facts.affectedScope === "many" || facts.affectedScope === "all" || facts.slaRisk === true || facts.coreFlowBlocked === true) { + return "P2"; + } + return "P3"; +} +function makeDecision(analysis, candidates, policy, existingLabels = []) { + const candidateNumbers = new Set( + candidates.map((candidate) => candidate.number) + ); + const duplicate = analysis.duplicate; + const duplicateIssueNumber = duplicate.issueNumber !== null && duplicate.confidence >= policy.duplicateConfidenceThreshold && candidateNumbers.has(duplicate.issueNumber) ? duplicate.issueNumber : null; + const relatedIssues = analysis.relatedIssues.filter( + (related) => candidateNumbers.has(related.issueNumber) && related.issueNumber !== duplicateIssueNumber + ).filter( + (related, index, all) => all.findIndex( + (candidate) => candidate.issueNumber === related.issueNumber + ) === index + ).slice(0, policy.maxRelatedIssues); + const priority = calculatePriority(analysis, policy); + const classification = resolveClassification( + analysis, + existingLabels, + policy + ); + const labels = [ + `priority:${priority}`, + analysis.missingInformation.length > 0 ? "triage:needs-info" : "triage:done" + ]; + if (classification.source === "analysis" && classification.label) { + labels.push(classification.label); + } + if (duplicateIssueNumber !== null) { + labels.push("duplicate"); + } + return { + analysis, + classification, + priority, + labels: [...new Set(labels)], + duplicateIssueNumber, + relatedIssues + }; +} +function resolveClassification(analysis, existingLabels, policy) { + const configuredLabels = Object.values(policy.classificationLabels); + const normalizedConfigured = new Map( + configuredLabels.map((label) => [label.trim().toLowerCase(), label]) + ); + const existingClassificationLabels = [ + ...new Set( + existingLabels.map((label) => normalizedConfigured.get(label.trim().toLowerCase())).filter((label) => Boolean(label)) + ) + ]; + if (existingClassificationLabels.length === 1) { + return { label: existingClassificationLabels[0], source: "existing" }; + } + if (existingClassificationLabels.length > 1) { + return { label: null, source: "conflict" }; + } + if (analysis.issueType === "unknown" || analysis.classificationConfidence < policy.classificationConfidenceThreshold) { + return { label: null, source: "unknown" }; + } + return { + label: policy.classificationLabels[analysis.issueType], + source: "analysis" + }; +} +function mergeManagedLabels(existing, desired, managedPrefixes) { + const preserved = existing.filter( + (label) => !managedPrefixes.some((prefix) => label.startsWith(prefix)) + ); + return [.../* @__PURE__ */ new Set([...preserved, ...desired])]; +} + +// src/runtime/target-binding.ts +function assertBoundTarget(options) { + const expectedRepository = options.expectedRepository?.trim() ?? ""; + const expectedTargetText = options.expectedTarget?.trim() ?? ""; + if (!expectedRepository && !expectedTargetText) { + if (options.apply) throw new Error(options.errors.missing); + return; + } + if (!expectedRepository || !expectedTargetText) { + throw new Error(options.errors.incomplete); + } + const expectedTarget = Number(expectedTargetText); + if (!isRepositorySlug(expectedRepository) || !Number.isSafeInteger(expectedTarget) || expectedTarget <= 0) { + throw new Error(options.errors.invalid); + } + if (options.repository !== expectedRepository || options.targetNumber !== expectedTarget) { + throw new Error( + options.errors.mismatch(expectedRepository, expectedTarget) + ); + } +} + +// src/issue-triage/target.ts +function assertBoundIssueTarget(repository, issueNumber, apply, environment) { + assertBoundTarget({ + repository, + targetNumber: issueNumber, + apply, + expectedRepository: environment.ISSUE_TRIAGE_EXPECTED_REPOSITORY, + expectedTarget: environment.ISSUE_TRIAGE_EXPECTED_ISSUE, + errors: { + missing: "apply mode requires a scheduler-bound Issue target; set ISSUE_TRIAGE_EXPECTED_REPOSITORY and ISSUE_TRIAGE_EXPECTED_ISSUE", + incomplete: "incomplete scheduler-bound Issue target", + invalid: "invalid scheduler-bound Issue target", + mismatch: (expectedRepository, expectedIssueNumber) => `requested Issue ${repository}#${issueNumber} does not match scheduler-bound target ${expectedRepository}#${expectedIssueNumber}` + } + }); +} + +// src/issues/fingerprint.ts +import crypto from "node:crypto"; +var ISSUE_FINGERPRINT_PATTERN = /^[0-9a-f]{20}$/; +function issueFingerprint(issue2, comments = []) { + return crypto.createHash("sha256").update( + JSON.stringify({ + title: issue2.title.trim(), + body: issue2.body ?? "", + comments: comments.map((comment) => ({ + id: comment.id, + body: comment.body, + author: comment.user?.login ?? "" + })) + }) + ).digest("hex").slice(0, 20); +} + +// src/issues/managed-comments.ts +var ISSUE_TRIAGE_COMMENT_PREFIX = "`; +} +function buildTriageComment(issueNumber, fingerprint, decision) { + const analysis = decision.analysis; + const lines = [ + commentMarker(issueNumber, fingerprint), + "## Issue triage", + "", + "### Classification", + "", + `- Type: \`${classificationText(decision)}\``, + `- Priority: \`${decision.priority}\``, + `- Priority basis: ${analysis.priorityReason}` + ]; + if (decision.duplicateIssueNumber !== null) { + lines.push( + "", + "### Possible duplicate", + "", + `- #${decision.duplicateIssueNumber}: ${analysis.duplicate.reason}` + ); + } + if (decision.relatedIssues.length > 0) { + lines.push("", "### Related issues", ""); + for (const related of decision.relatedIssues) { + lines.push(`- #${related.issueNumber}: ${related.reason}`); + } + } + if (analysis.missingInformation.length > 0) { + lines.push("", "### Information needed", ""); + for (const missing of analysis.missingInformation) { + lines.push(`- ${missing}`); + } + } + lines.push( + "", + "### Maintainer next step", + "", + "- When this Issue is ready for implementation, a maintainer can add the `agent:ready` label. The Agent will open a Draft Pull Request and will not merge it automatically.", + "- Add `skip-triage` to opt out of automated triage.", + "", + "_This is an automated initial assessment based on the Issue text and related candidates; no repository code was inspected._" + ); + return lines.join("\n"); +} +function classificationText(decision) { + if (decision.classification.label) return decision.classification.label; + return decision.classification.source === "conflict" ? "unresolved (conflicting existing labels)" : "unknown"; +} + +// src/issue-triage/schema.ts +var unknownBoolean = boolean2().nullable(); +var triageAnalysisSchema = object({ + issueType: _enum([ + "bug", + "enhancement", + "documentation", + "question", + "unknown" + ]), + classificationConfidence: number2().min(0).max(1), + priorityConfidence: number2().min(0).max(1), + facts: object({ + environment: _enum(["production", "non-production", "unknown"]), + productionImpact: _enum(["none", "degraded", "outage", "unknown"]), + securityImpact: _enum(["none", "low", "high", "critical", "unknown"]), + dataLoss: unknownBoolean, + coreFlowBlocked: unknownBoolean, + workaround: _enum(["available", "none", "unknown"]), + affectedScope: _enum(["single", "limited", "many", "all", "unknown"]), + slaRisk: unknownBoolean, + releaseBlocker: unknownBoolean + }), + duplicate: object({ + issueNumber: number2().int().positive().nullable(), + confidence: number2().min(0).max(1), + reason: string2().max(2e3) + }), + relatedIssues: array( + object({ + issueNumber: number2().int().positive(), + reason: string2().min(1).max(1e3) + }) + ).max(10), + missingInformation: array(string2().min(1).max(1e3)).max(10), + priorityReason: string2().min(1).max(2e3) +}); +var triageSubmissionSchema = object({ + issueFingerprint: string2().regex(ISSUE_FINGERPRINT_PATTERN), + analysis: triageAnalysisSchema +}); + +// src/issue-triage/tool.ts +async function prepareIssueTriage(repository, issueNumber, dependencies) { + const issue2 = await dependencies.issues.getIssue(repository, issueNumber); + if (hasSkipLabel(issue2.labels, dependencies.policy.skipLabels)) { + return { + ok: true, + skipped: true, + reason: "issue has a configured skip-triage label", + repository, + issueNumber, + issueFingerprint: issueFingerprint(issue2) + }; + } + const comments = await dependencies.issues.listComments( + repository, + issueNumber + ); + const contextComments = selectContextComments( + comments, + dependencies.botLogin + ); + const fingerprint = issueFingerprint(issue2, contextComments); + if (hasCurrentTriageComment( + comments, + issueNumber, + fingerprint, + dependencies.botLogin + )) { + return { + ok: true, + skipped: true, + reason: "issue content already triaged", + repository, + issueNumber, + issueFingerprint: fingerprint + }; + } + const { candidates, warnings } = await loadCandidates( + dependencies.issues, + repository, + issue2, + dependencies.policy.maxCandidates + ); + return { + ok: true, + repository, + issueNumber, + issueFingerprint: fingerprint, + issue: issue2, + comments: contextComments, + candidates, + ...warnings.length > 0 ? { warnings } : {} + }; +} +async function applyIssueTriage(repository, issueNumber, submissionInput, apply, dependencies) { + const submission = triageSubmissionSchema.parse(submissionInput); + const issue2 = await dependencies.issues.getIssue(repository, issueNumber); + if (hasSkipLabel(issue2.labels, dependencies.policy.skipLabels)) { + return { + ok: true, + skipped: true, + reason: "issue has a configured skip-triage label", + repository, + issueNumber, + applied: false + }; + } + const botLogin = requiredBotLogin(apply, dependencies.botLogin); + const comments = await dependencies.issues.listComments( + repository, + issueNumber + ); + const contextComments = selectContextComments(comments, botLogin); + const currentFingerprint = issueFingerprint(issue2, contextComments); + if (currentFingerprint !== submission.issueFingerprint) { + throw new Error( + "issue changed after analysis; run the prepare command again before applying" + ); + } + if (hasCurrentTriageComment(comments, issueNumber, currentFingerprint, botLogin)) { + return { + ok: true, + skipped: true, + reason: "issue content already triaged", + repository, + issueNumber, + applied: false + }; + } + const { candidates, warnings } = await loadCandidates( + dependencies.issues, + repository, + issue2, + dependencies.policy.maxCandidates + ); + const decision = makeDecision( + submission.analysis, + candidates, + dependencies.policy, + issue2.labels + ); + const proposedComment = buildTriageComment( + issueNumber, + currentFingerprint, + decision + ); + const desiredLabels = mergeManagedLabels( + issue2.labels, + decision.labels, + dependencies.policy.managedLabelPrefixes + ); + const existingLabels = issue2.labels; + const labelsToAdd = desiredLabels.filter( + (label) => !existingLabels.includes(label) + ); + const labelsToRemove = existingLabels.filter( + (label) => isManagedLabel(label, dependencies.policy.managedLabelPrefixes) && !desiredLabels.includes(label) + ); + const existingComment = findTriageComment(comments, botLogin); + if (!apply) { + return { + ok: true, + repository, + issueNumber, + applied: false, + commentAction: "dry-run", + decision, + proposedComment, + ...warnings.length > 0 ? { warnings } : {} + }; + } + await ensureLabels( + dependencies.issues, + repository, + decision.labels, + dependencies.policy + ); + await dependencies.issues.addLabels(repository, issueNumber, labelsToAdd); + for (const label of labelsToRemove) { + await dependencies.issues.removeLabel(repository, issueNumber, label); + } + let commentAction = "unchanged"; + if (!existingComment) { + await dependencies.issues.createComment( + repository, + issueNumber, + proposedComment + ); + commentAction = "created"; + } else if (existingComment.body !== proposedComment) { + await dependencies.issues.updateComment( + repository, + issueNumber, + existingComment.id, + proposedComment + ); + commentAction = "updated"; + } + return { + ok: true, + repository, + issueNumber, + applied: true, + commentAction, + decision, + ...warnings.length > 0 ? { warnings } : {} + }; +} +async function loadCandidates(issues, repository, issue2, limit) { + try { + return { + candidates: await issues.searchCandidates(repository, issue2, limit), + warnings: [] + }; + } catch (error) { + return { + candidates: [], + warnings: [ + `candidate search failed; duplicate claims will be rejected: ${errorMessage(error)}` + ] + }; + } +} +function hasCurrentTriageComment(comments, issueNumber, fingerprint, botLogin) { + const marker = commentMarker(issueNumber, fingerprint); + return comments.some( + (comment) => isManagedTriageComment(comment, botLogin) && (comment.body === marker || comment.body.startsWith(`${marker} +`)) + ); +} +function findTriageComment(comments, botLogin) { + return comments.find( + (comment) => isManagedTriageComment(comment, botLogin) && isIssueTriageComment(comment.body) + ); +} +function isManagedTriageComment(comment, botLogin) { + const expectedLogin = botLogin?.trim().toLowerCase(); + return Boolean( + expectedLogin && comment.user?.login.toLowerCase() === expectedLogin + ); +} +function selectContextComments(comments, botLogin) { + return comments.filter( + (comment) => !isManagedTriageComment(comment, botLogin) || !isIssueTriageComment(comment.body) + ).sort((left, right) => left.id - right.id).slice(-50).map((comment) => ({ + ...comment, + body: truncateText(comment.body, 4e3) + })); +} +function requiredBotLogin(apply, botLogin) { + const normalized = botLogin?.trim(); + if (apply && !normalized) { + throw new Error("provider bot username is required in apply mode"); + } + return normalized || void 0; +} +function isManagedLabel(label, managedPrefixes) { + return managedPrefixes.some((prefix) => label.startsWith(prefix)); +} +function hasSkipLabel(labels, skipLabels) { + const normalizedSkipLabels = new Set( + skipLabels.map((label) => label.trim().toLowerCase()) + ); + return labels.some( + (label) => normalizedSkipLabels.has(label.trim().toLowerCase()) + ); +} +async function ensureLabels(issues, repository, labels, policy) { + for (const label of labels) { + await issues.ensureLabel( + repository, + label, + policy.labelColors[label] ?? "ededed", + policy.labelDescriptions[label] + ); + } +} + +// src/issue-triage/main.ts +async function main() { + const options = parseArguments(process.argv.slice(2)); + const policy = await loadPolicy(); + const apply = envBoolean(process.env.ISSUE_TRIAGE_APPLY); + assertBoundIssueTarget( + options.repository, + options.issueNumber, + apply, + process.env + ); + const token = await resolveGitHubToken(options.repository); + const issues = new GitHubClient({ + ...token ? { token } : {}, + ...process.env.GITHUB_API_URL ? { baseUrl: process.env.GITHUB_API_URL } : {} + }); + const dependencies = { + issues, + policy, + ...process.env.GITHUB_BOT_LOGIN ? { botLogin: process.env.GITHUB_BOT_LOGIN } : {} + }; + const result = options.command === "prepare" ? await prepareIssueTriage( + options.repository, + options.issueNumber, + dependencies + ) : await applyIssueTriage( + options.repository, + options.issueNumber, + JSON.parse(await readFile2(options.analysisFile, "utf8")), + apply, + dependencies + ); + process.stdout.write(`${JSON.stringify(result, null, 2)} +`); +} +async function loadPolicy() { + const embedded = process.env.WORKFLOW_POLICY_JSON?.trim(); + if (embedded) { + try { + return triagePolicySchema.parse(JSON.parse(embedded)); + } catch (error) { + throw new Error( + `failed to load embedded triage policy: ${errorMessage(error)}` + ); + } + } + return loadJsonFromCandidates( + [ + fileURLToPath(new URL("../policy.json", import.meta.url)), + path.resolve("agents/issue-triage/policy.json") + ], + (value) => triagePolicySchema.parse(value), + "failed to load issue triage policy" + ); +} +function parseArguments(args) { + const command = args.shift(); + if (command !== "prepare" && command !== "apply") { + throw new Error("first argument must be prepare or apply"); + } + let repository = ""; + let issueNumber = 0; + let analysisFile = ""; + for (let index = 0; index < args.length; index += 1) { + const argument = args[index]; + if (argument === "--repository") { + repository = requiredArgumentValue(args, ++index, argument); + } else if (argument === "--issue") { + const raw = requiredArgumentValue(args, ++index, argument); + issueNumber = Number.parseInt(raw, 10); + if (!Number.isSafeInteger(issueNumber) || issueNumber <= 0) { + throw new Error("--issue must be a positive integer"); + } + } else if (argument === "--analysis") { + analysisFile = requiredArgumentValue(args, ++index, argument); + } else { + throw new Error(`unknown argument: ${argument}`); + } + } + if (!isRepositorySlug(repository)) { + throw new Error("--repository must use owner/repository format"); + } + if (issueNumber <= 0) throw new Error("--issue is required"); + if (command === "apply" && !analysisFile) { + throw new Error("--analysis is required for apply"); + } + return { + command, + repository, + issueNumber, + ...analysisFile ? { analysisFile } : {} + }; +} +main().catch((error) => { + process.stderr.write(`issue triage failed: ${errorMessage(error)} +`); + process.exitCode = 1; +}); diff --git a/package.json b/package.json index 0493017..7e1ed58 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "build:check": "tsx scripts/build-tools.ts --check", "check": "npm run format:check && npm run typecheck && npm test && npm run build:check", "format": "prettier --write .", + "pin-workspace-ref": "tsx scripts/pin-workspace-ref.ts", "format:check": "prettier --check .", "start": "tsx src/issue-triage/main.ts", "start:draft-pr": "tsx src/draft-pr/main.ts", diff --git a/scripts/build-tools.ts b/scripts/build-tools.ts index 0332464..140d7ba 100644 --- a/scripts/build-tools.ts +++ b/scripts/build-tools.ts @@ -1,11 +1,12 @@ -import { readFile, writeFile } from "node:fs/promises"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { build } from "esbuild"; const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); -const workflowToolPlaceholder = "__WORKFLOW_TOOL_BASE64__"; const workflowPolicyPlaceholder = "__WORKFLOW_POLICY_JSON__"; +const generatedFileBanner = + "// Generated by scripts/build-tools.ts. Do not edit directly."; const buildTargets = { "issue-triage": { @@ -13,12 +14,14 @@ const buildTargets = { schedulerSource: "src/schedulers/issue-triage.js", policySource: "agents/issue-triage/policy.json", outfile: "agents/issue-triage/scheduler.js", + toolOutfile: "agents/issue-triage/tool/main.mjs", }, "draft-pr": { entryPoint: "src/draft-pr/main.ts", schedulerSource: "src/schedulers/draft-pr.js", policySource: "agents/draft-pr/policy.json", outfile: "agents/draft-pr/scheduler.js", + toolOutfile: "agents/draft-pr/tool/main.mjs", }, } as const; @@ -35,26 +38,19 @@ export function normalizeGeneratedSource(source: string): string { export function renderSchedulerArtifact( schedulerSource: string, - workflowToolSource: string, workflowPolicySource: string, ): string { - let generated = replaceExactlyOnce( + const generated = replaceExactlyOnce( schedulerSource, - workflowToolPlaceholder, - Buffer.from(normalizeGeneratedSource(workflowToolSource), "utf8").toString( - "base64", - ), - ); - generated = replaceExactlyOnce( - generated, workflowPolicyPlaceholder, JSON.stringify(JSON.parse(workflowPolicySource)), ); + return normalizeGeneratedSource([generatedFileBanner, generated].join("\n")); +} + +export function renderToolArtifact(workflowToolSource: string): string { return normalizeGeneratedSource( - [ - "// Generated by scripts/build-tools.ts. Do not edit directly.", - generated, - ].join("\n"), + [generatedFileBanner, workflowToolSource].join("\n"), ); } @@ -87,6 +83,29 @@ export function parseBuildArguments(args: string[]): BuildOptions { return { check, targets: targets as BuildTargetName[] }; } +async function writeOrCheck( + relativePath: string, + generated: string, + check: boolean, +): Promise { + const outfile = path.join(repositoryRoot, relativePath); + + if (!check) { + await mkdir(path.dirname(outfile), { recursive: true }); + await writeFile(outfile, generated); + process.stdout.write(`built ${relativePath}\n`); + return true; + } + + const current = await readFile(outfile, "utf8").catch(() => ""); + if (current === generated) { + process.stdout.write(`checked ${relativePath}\n`); + return true; + } + process.stderr.write(`stale ${relativePath}\n`); + return false; +} + async function buildTarget( targetName: BuildTargetName, check: boolean, @@ -113,26 +132,17 @@ async function buildTarget( path.join(repositoryRoot, target.policySource), "utf8", ); - const generated = renderSchedulerArtifact( + const generatedScheduler = renderSchedulerArtifact( schedulerSource, - output.text, policySource, ); - const outfile = path.join(repositoryRoot, target.outfile); + const generatedTool = renderToolArtifact(output.text); - if (!check) { - await writeFile(outfile, generated); - process.stdout.write(`built ${target.outfile}\n`); - return true; - } - - const current = await readFile(outfile, "utf8"); - if (current === generated) { - process.stdout.write(`checked ${target.outfile}\n`); - return true; - } - process.stderr.write(`stale ${target.outfile}\n`); - return false; + const [schedulerMatched, toolMatched] = await Promise.all([ + writeOrCheck(target.outfile, generatedScheduler, check), + writeOrCheck(target.toolOutfile, generatedTool, check), + ]); + return schedulerMatched && toolMatched; } export async function runBuild(options: BuildOptions): Promise { diff --git a/scripts/pin-workspace-ref.ts b/scripts/pin-workspace-ref.ts new file mode 100644 index 0000000..95c71d1 --- /dev/null +++ b/scripts/pin-workspace-ref.ts @@ -0,0 +1,62 @@ +import { execFileSync } from "node:child_process"; +import { readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); +const composePath = path.join(repositoryRoot, "agent-compose.yml"); + +// Matches the `ref:` line of an `agents..workspace` block by its fixed +// position immediately before that block's `target: workflow-repo` line. +// Other `ref:` fields in this file (skills, scheduler.script) are followed +// by a `path:` line instead and are intentionally left untouched — see the +// design note in agent-compose.yml history for why only workspace.ref is +// pinned to a commit SHA. +const workspaceRefPattern = + /( {6}ref: )[0-9a-f]{40}(\n {6}target: workflow-repo\n)/g; + +export function pinWorkspaceRefs( + compose: string, + sha: string, +): { updated: string; count: number } { + if (!/^[0-9a-f]{40}$/.test(sha)) { + throw new Error(`expected a 40-character commit SHA, got: ${sha}`); + } + let count = 0; + const updated = compose.replace( + workspaceRefPattern, + (_match, prefix, suffix) => { + count += 1; + return `${prefix}${sha}${suffix}`; + }, + ); + return { updated, count }; +} + +async function main(): Promise { + const sha = execFileSync("git", ["rev-parse", "HEAD"], { + cwd: repositoryRoot, + encoding: "utf8", + }).trim(); + const compose = await readFile(composePath, "utf8"); + const { updated, count } = pinWorkspaceRefs(compose, sha); + if (count === 0) { + throw new Error( + "no agents.*.workspace.ref fields found in agent-compose.yml", + ); + } + await writeFile(composePath, updated); + process.stdout.write(`pinned ${count} workspace.ref field(s) to ${sha}\n`); +} + +if ( + process.argv[1] && + path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url)) +) { + main().catch((error: unknown) => { + process.stderr.write( + `${error instanceof Error ? error.message : String(error)}\n`, + ); + process.exitCode = 1; + }); +} diff --git a/src/schedulers/draft-pr.js b/src/schedulers/draft-pr.js index 97ca0d5..6df4f74 100644 --- a/src/schedulers/draft-pr.js +++ b/src/schedulers/draft-pr.js @@ -3,9 +3,9 @@ const GITHUB_REVIEW_TOPIC = "webhook.github.pull_request_review"; const GITHUB_WORKFLOW_RUN_TOPIC = "webhook.github.workflow_run"; const READY_LABEL = "agent:ready"; const APPROVED_LABEL = "agent:approved"; -const WORKFLOW_TOOL_BASE64 = "__WORKFLOW_TOOL_BASE64__"; const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__"; -const WORKFLOW_TOOL_CHUNK_SIZE = 60000; +const WORKFLOW_TOOL_PATH = + "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"; const WORKSPACE_VOLUME = { type: "bind", source: "./.draft-pr-workspaces", @@ -13,19 +13,6 @@ const WORKSPACE_VOLUME = { readOnly: false, }; -function workflowToolEnvironment() { - const env = {}; - for ( - let offset = 0, index = 0; - offset < WORKFLOW_TOOL_BASE64.length; - offset += WORKFLOW_TOOL_CHUNK_SIZE, index += 1 - ) { - env[`WORKFLOW_TOOL_CHUNK_${String(index).padStart(4, "0")}`] = - WORKFLOW_TOOL_BASE64.slice(offset, offset + WORKFLOW_TOOL_CHUNK_SIZE); - } - return env; -} - function agentWorkspaceVolume(workspacePath) { const prefix = "/draft-pr-workspaces/repositories/"; if ( @@ -302,17 +289,12 @@ function validateAgentWorkspaceWithRetry(workspacePath) { function runDeterministicTool(script, env, label) { const result = scheduler.shell( - [ - "set -eu", - 'workflow_tool_dir="$(mktemp -d)"', - 'workflow_tool="$workflow_tool_dir/draft-pr.mjs"', - 'node -e \'const fs=require("node:fs"); const source=Object.keys(process.env).filter((key)=>key.startsWith("WORKFLOW_TOOL_CHUNK_")).sort().map((key)=>process.env[key]).join(""); fs.writeFileSync(process.argv[1], Buffer.from(source, "base64"))\' "$workflow_tool"', - 'export DRAFT_PR_TOOL="$workflow_tool"', - script, - ].join("\n"), + ["set -eu", `export DRAFT_PR_TOOL="${WORKFLOW_TOOL_PATH}"`, script].join( + "\n", + ), { sandboxPolicy: "new", - env: { ...env, WORKFLOW_POLICY_JSON, ...workflowToolEnvironment() }, + env: { ...env, WORKFLOW_POLICY_JSON }, volumes: [WORKSPACE_VOLUME], maxOutputBytes: 4 * 1024 * 1024, }, diff --git a/src/schedulers/issue-triage.js b/src/schedulers/issue-triage.js index 25cff3c..f96fba9 100644 --- a/src/schedulers/issue-triage.js +++ b/src/schedulers/issue-triage.js @@ -9,22 +9,9 @@ const GITHUB_ISSUE_ACTIONS = [ ]; const GITHUB_COMMENT_ACTIONS = ["created", "edited", "deleted"]; const GITHUB_TRIAGE_CONTROL_LABEL = "skip-triage"; -const WORKFLOW_TOOL_BASE64 = "__WORKFLOW_TOOL_BASE64__"; const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__"; -const WORKFLOW_TOOL_CHUNK_SIZE = 60000; - -function workflowToolEnvironment() { - const env = {}; - for ( - let offset = 0, index = 0; - offset < WORKFLOW_TOOL_BASE64.length; - offset += WORKFLOW_TOOL_CHUNK_SIZE, index += 1 - ) { - env[`WORKFLOW_TOOL_CHUNK_${String(index).padStart(4, "0")}`] = - WORKFLOW_TOOL_BASE64.slice(offset, offset + WORKFLOW_TOOL_CHUNK_SIZE); - } - return env; -} +const WORKFLOW_TOOL_PATH = + "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs"; const ANALYSIS_SCHEMA = { type: "object", @@ -118,9 +105,7 @@ function runTool(command, repository, issueNumber, submission, senderLogin) { const result = scheduler.shell( [ "set -eu", - 'workflow_tool_dir="$(mktemp -d)"', - 'workflow_tool="$workflow_tool_dir/issue-triage.mjs"', - 'node -e \'const fs=require("node:fs"); const source=Object.keys(process.env).filter((key)=>key.startsWith("WORKFLOW_TOOL_CHUNK_")).sort().map((key)=>process.env[key]).join(""); fs.writeFileSync(process.argv[1], Buffer.from(source, "base64"))\' "$workflow_tool"', + `workflow_tool="${WORKFLOW_TOOL_PATH}"`, 'sender_login=$(printf "%s" "$TRIAGE_SENDER_LOGIN" | tr "[:upper:]" "[:lower:]")', 'bot_login=$(printf "%s" "${GITHUB_BOT_LOGIN:-}" | tr "[:upper:]" "[:lower:]")', 'allowed_repository="${GITHUB_ALLOWED_REPOSITORY:-}"', @@ -146,7 +131,6 @@ function runTool(command, repository, issueNumber, submission, senderLogin) { TRIAGE_REPOSITORY: repository, TRIAGE_ISSUE: String(issueNumber), WORKFLOW_POLICY_JSON, - ...workflowToolEnvironment(), TRIAGE_SUBMISSION: submission ? JSON.stringify(submission) : "", TRIAGE_SENDER_LOGIN: senderLogin || "", }, diff --git a/test/build-tools.test.ts b/test/build-tools.test.ts index 3a0e83f..48eb490 100644 --- a/test/build-tools.test.ts +++ b/test/build-tools.test.ts @@ -4,6 +4,7 @@ import { normalizeGeneratedSource, parseBuildArguments, renderSchedulerArtifact, + renderToolArtifact, } from "../scripts/build-tools.js"; describe("generated Scheduler artifact build", () => { @@ -60,32 +61,32 @@ describe("generated Scheduler artifact build", () => { ); }); - it("embeds one deterministic tool bundle in a scheduler artifact", () => { + it("embeds the deterministic tool policy in a scheduler artifact", () => { const artifact = renderSchedulerArtifact( - [ - 'const WORKFLOW_TOOL_BASE64 = "__WORKFLOW_TOOL_BASE64__";', - 'const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__";', - "", - ].join("\n"), - 'process.stdout.write("ready");\n', + ['const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__";', ""].join( + "\n", + ), '{"enabled":true}\n', ); expect(artifact).toContain("Generated by scripts/build-tools.ts"); - expect(artifact).toContain( - `const WORKFLOW_TOOL_BASE64 = ${JSON.stringify(Buffer.from('process.stdout.write("ready");\n').toString("base64"))};`, - ); - expect(artifact).not.toContain("__WORKFLOW_TOOL_BASE64__"); expect(artifact).toContain( 'const WORKFLOW_POLICY_JSON = "{\\\"enabled\\\":true}";', ); expect(artifact).not.toContain("__WORKFLOW_POLICY_JSON__"); - expect(() => - renderSchedulerArtifact("const value = 1;", "tool", "{}"), - ).toThrow("exactly one __WORKFLOW_TOOL_BASE64__ placeholder"); + expect(() => renderSchedulerArtifact("const value = 1;", "{}")).toThrow( + "exactly one __WORKFLOW_POLICY_JSON__ placeholder", + ); + }); + + it("renders a standalone tool artifact with the generated-file banner", () => { + const artifact = renderToolArtifact('process.stdout.write("ready");\n'); + + expect(artifact).toContain("Generated by scripts/build-tools.ts"); + expect(artifact).toContain('process.stdout.write("ready");'); }); - it("keeps the generated bundles free of the Zod locale catalog", async () => { + it("keeps the generated scheduler artifacts free of the tool bundle and Zod locale catalog", async () => { const bundles = await Promise.all([ readFile( new URL("../agents/issue-triage/scheduler.js", import.meta.url), @@ -99,10 +100,28 @@ describe("generated Scheduler artifact build", () => { for (const bundle of bundles) { expect(bundle).toContain("Generated by scripts/build-tools.ts"); - expect(bundle).toContain("WORKFLOW_TOOL_BASE64"); expect(bundle).toContain("WORKFLOW_POLICY_JSON"); - expect(bundle).not.toContain("__WORKFLOW_TOOL_BASE64__"); expect(bundle).not.toContain("__WORKFLOW_POLICY_JSON__"); + expect(bundle).not.toContain("WORKFLOW_TOOL_BASE64"); + expect(bundle).not.toContain("WORKFLOW_TOOL_CHUNK_"); + expect(bundle).not.toContain("node_modules/zod/v4/locales/"); + } + }); + + it("delivers the tool bundle as a standalone committed file, free of the Zod locale catalog", async () => { + const bundles = await Promise.all([ + readFile( + new URL("../agents/issue-triage/tool/main.mjs", import.meta.url), + "utf8", + ), + readFile( + new URL("../agents/draft-pr/tool/main.mjs", import.meta.url), + "utf8", + ), + ]); + + for (const bundle of bundles) { + expect(bundle).toContain("Generated by scripts/build-tools.ts"); expect(bundle).not.toContain("node_modules/zod/v4/locales/"); } }); diff --git a/test/draft-pr-scheduler-script.test.ts b/test/draft-pr-scheduler-script.test.ts index c88d45e..7266cb2 100644 --- a/test/draft-pr-scheduler-script.test.ts +++ b/test/draft-pr-scheduler-script.test.ts @@ -7,7 +7,6 @@ describe("Draft PR Scheduler script", () => { const handlers = new Map unknown>(); const commands: string[] = []; let agentOptions: Record = {}; - let toolChunks: string[] = []; let workflowPolicyJson = ""; const shellCalls: Array<{ script: string; @@ -32,10 +31,6 @@ describe("Draft PR Scheduler script", () => { shellCalls.push({ script, options }); commands.push(schedulerCommand(options.env)); workflowPolicyJson = options.env.WORKFLOW_POLICY_JSON ?? ""; - toolChunks = Object.entries(options.env) - .filter(([name]) => name.startsWith("WORKFLOW_TOOL_CHUNK_")) - .sort(([left], [right]) => left.localeCompare(right)) - .map(([, value]) => value); const result = options.env.DRAFT_PR_COMMAND === "prepare" ? { @@ -178,8 +173,12 @@ describe("Draft PR Scheduler script", () => { }), ); expect(workspaceValidation?.options.volumes).toEqual(agentOptions.volumes); - expect(toolChunks.length).toBeGreaterThan(1); - expect(toolChunks.every((chunk) => chunk.length <= 60000)).toBe(true); + const toolInvocation = shellCalls.find( + ({ options }) => options.env.DRAFT_PR_COMMAND === "prepare", + ); + expect(toolInvocation?.script).toContain( + 'export DRAFT_PR_TOOL="$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"', + ); expect(JSON.parse(workflowPolicyJson)).toEqual( expect.objectContaining({ version: 1, diff --git a/test/scheduler-script.test.ts b/test/scheduler-script.test.ts index a69a1f6..1d31409 100644 --- a/test/scheduler-script.test.ts +++ b/test/scheduler-script.test.ts @@ -7,7 +7,6 @@ describe("GitHub Issue triage scheduler script", () => { const handlers = new Map unknown>(); let shellScript = ""; let senderLogin = ""; - let toolChunks: string[] = []; let workflowPolicyJson = ""; const context = vm.createContext({ scheduler: { @@ -22,10 +21,6 @@ describe("GitHub Issue triage scheduler script", () => { shellScript = script; senderLogin = options.env.TRIAGE_SENDER_LOGIN ?? ""; workflowPolicyJson = options.env.WORKFLOW_POLICY_JSON ?? ""; - toolChunks = Object.entries(options.env) - .filter(([name]) => name.startsWith("WORKFLOW_TOOL_CHUNK_")) - .sort(([left], [right]) => left.localeCompare(right)) - .map(([, value]) => value); return { success: true, stdout: JSON.stringify({ @@ -61,9 +56,9 @@ describe("GitHub Issue triage scheduler script", () => { }); expect(senderLogin).toBe("triage-bot"); expect(shellScript).toContain("GITHUB_BOT_LOGIN"); - expect(shellScript).toContain('Buffer.from(source, "base64")'); - expect(toolChunks.length).toBeGreaterThan(1); - expect(toolChunks.every((chunk) => chunk.length <= 60000)).toBe(true); + expect(shellScript).toContain( + "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs", + ); expect(JSON.parse(workflowPolicyJson)).toEqual( expect.objectContaining({ version: 1 }), ); From ce2f5c2c0cb49d1d20cf71a4fdd251255007774c Mon Sep 17 00:00:00 2001 From: winterfx Date: Thu, 13 Aug 2026 10:41:51 +0800 Subject: [PATCH 2/4] refactor(agent-compose): track workspace.ref on main, drop ref pinning Accept the mid-workflow drift risk instead of pinning workspace.ref to a commit SHA: both agents' workspace now tracks main like skills and scheduler.script already do, removing the pin-workspace-ref manual pre-deploy step and its script. --- agent-compose.yml | 4 +-- package.json | 1 - scripts/pin-workspace-ref.ts | 62 ------------------------------------ 3 files changed, 2 insertions(+), 65 deletions(-) delete mode 100644 scripts/pin-workspace-ref.ts diff --git a/agent-compose.yml b/agent-compose.yml index 95f4d97..3f30dd3 100644 --- a/agent-compose.yml +++ b/agent-compose.yml @@ -39,7 +39,7 @@ agents: workspace: provider: git url: https://github.com/winterfx/engineering-agent-workflows.git - ref: 78db6672cbd38e07d10621f937d55f22c1fcfbab + ref: main target: workflow-repo scheduler: @@ -89,7 +89,7 @@ agents: workspace: provider: git url: https://github.com/winterfx/engineering-agent-workflows.git - ref: 78db6672cbd38e07d10621f937d55f22c1fcfbab + ref: main target: workflow-repo scheduler: diff --git a/package.json b/package.json index 7e1ed58..0493017 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "build:check": "tsx scripts/build-tools.ts --check", "check": "npm run format:check && npm run typecheck && npm test && npm run build:check", "format": "prettier --write .", - "pin-workspace-ref": "tsx scripts/pin-workspace-ref.ts", "format:check": "prettier --check .", "start": "tsx src/issue-triage/main.ts", "start:draft-pr": "tsx src/draft-pr/main.ts", diff --git a/scripts/pin-workspace-ref.ts b/scripts/pin-workspace-ref.ts deleted file mode 100644 index 95c71d1..0000000 --- a/scripts/pin-workspace-ref.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { execFileSync } from "node:child_process"; -import { readFile, writeFile } from "node:fs/promises"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); -const composePath = path.join(repositoryRoot, "agent-compose.yml"); - -// Matches the `ref:` line of an `agents..workspace` block by its fixed -// position immediately before that block's `target: workflow-repo` line. -// Other `ref:` fields in this file (skills, scheduler.script) are followed -// by a `path:` line instead and are intentionally left untouched — see the -// design note in agent-compose.yml history for why only workspace.ref is -// pinned to a commit SHA. -const workspaceRefPattern = - /( {6}ref: )[0-9a-f]{40}(\n {6}target: workflow-repo\n)/g; - -export function pinWorkspaceRefs( - compose: string, - sha: string, -): { updated: string; count: number } { - if (!/^[0-9a-f]{40}$/.test(sha)) { - throw new Error(`expected a 40-character commit SHA, got: ${sha}`); - } - let count = 0; - const updated = compose.replace( - workspaceRefPattern, - (_match, prefix, suffix) => { - count += 1; - return `${prefix}${sha}${suffix}`; - }, - ); - return { updated, count }; -} - -async function main(): Promise { - const sha = execFileSync("git", ["rev-parse", "HEAD"], { - cwd: repositoryRoot, - encoding: "utf8", - }).trim(); - const compose = await readFile(composePath, "utf8"); - const { updated, count } = pinWorkspaceRefs(compose, sha); - if (count === 0) { - throw new Error( - "no agents.*.workspace.ref fields found in agent-compose.yml", - ); - } - await writeFile(composePath, updated); - process.stdout.write(`pinned ${count} workspace.ref field(s) to ${sha}\n`); -} - -if ( - process.argv[1] && - path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url)) -) { - main().catch((error: unknown) => { - process.stderr.write( - `${error instanceof Error ? error.message : String(error)}\n`, - ); - process.exitCode = 1; - }); -} From 25d02247639092e10a901ccbe92917d100ebc45c Mon Sep 17 00:00:00 2001 From: winterfx Date: Thu, 13 Aug 2026 11:02:25 +0800 Subject: [PATCH 3/4] refactor(build-tools): centralize the tool workspace path, tidy build script Address findings from a /simplify pass over the workspace-tool-delivery diff: - Derive the WORKFLOW_TOOL_PATH baked into each scheduler.js from a single workspaceToolTarget constant + placeholder substitution (matching the existing WORKFLOW_POLICY_JSON pattern), instead of hand-typing the same "$WORKSPACE/workflow-repo/agents//tool/ main.mjs" literal separately in build-tools.ts and each scheduler source file. - Extract withGeneratedFileBanner() so renderSchedulerArtifact and renderToolArtifact stop duplicating the banner-wrapping expression. - Parallelize the schedulerSource/policySource reads in buildTarget with Promise.all, matching the existing writeOrCheck parallelism. Not changed: agent-compose.yml's workspace/skills/scheduler.script still declare the same repo URL/ref three times per agent (a review pass flagged this as a duplicate git checkout per sandbox) - fixing that would mean deciding whether `skills` and `workspace` can share one checkout, which needs deeper agent-compose provisioning behavior than the docs settle (skill refs resolve "during an agent run", which may or may not populate the sandbox filesystem the same way workspace does for plain scheduler.shell() calls). Left as a follow-up. --- agents/draft-pr/scheduler.js | 3 +-- agents/issue-triage/scheduler.js | 3 +-- scripts/build-tools.ts | 38 +++++++++++++++++++++----------- src/schedulers/draft-pr.js | 3 +-- src/schedulers/issue-triage.js | 3 +-- test/build-tools.test.ts | 21 +++++++++++++----- 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/agents/draft-pr/scheduler.js b/agents/draft-pr/scheduler.js index 674b99f..8b806dc 100644 --- a/agents/draft-pr/scheduler.js +++ b/agents/draft-pr/scheduler.js @@ -5,8 +5,7 @@ const GITHUB_WORKFLOW_RUN_TOPIC = "webhook.github.workflow_run"; const READY_LABEL = "agent:ready"; const APPROVED_LABEL = "agent:approved"; const WORKFLOW_POLICY_JSON = "{\"version\":1,\"readyLabel\":\"agent:ready\",\"approvedLabel\":\"agent:approved\",\"runningLabel\":\"agent:running\",\"needsApprovalLabel\":\"agent:needs-approval\",\"prOpenLabel\":\"agent:pr-open\",\"failedLabel\":\"agent:failed\",\"skipLabels\":[\"skip-triage\"],\"blockedLabels\":[\"duplicate\",\"agent:pr-open\",\"agent:running\"],\"branchPrefix\":\"codex/issue-\",\"maxChangedFiles\":40,\"maxChangedLines\":1500,\"maxReviewComments\":50,\"maxValidationFixIterations\":2,\"maxFixIterations\":3,\"requiredValidationGates\":[\"task-prepare\",\"task-lint\",\"task-test-unit\"],\"allowedValidationFailureCases\":[\"TestConfigStoreCRUDCoverageWorkflows\",\"TestIntegrationConfigStoreCRUDCoverageWorkflows\",\"TestE2EConfigStoreCRUDCoverageWorkflows\",\"runtime command execution > injects runtime path environment into user commands\"],\"approvalPathPrefixes\":[\".github/workflows/\",\"migrations/\",\"db/migrations/\",\"database/migrations/\",\"pkg/auth/\",\"src/auth/\",\"security/\",\"deploy/\",\"release/\"],\"labelColors\":{\"agent:ready\":\"1d76db\",\"agent:approved\":\"0e8a16\",\"agent:running\":\"fbca04\",\"agent:needs-approval\":\"d93f0b\",\"agent:pr-open\":\"5319e7\",\"agent:failed\":\"b60205\"}}"; -const WORKFLOW_TOOL_PATH = - "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"; +const WORKFLOW_TOOL_PATH = "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"; const WORKSPACE_VOLUME = { type: "bind", source: "./.draft-pr-workspaces", diff --git a/agents/issue-triage/scheduler.js b/agents/issue-triage/scheduler.js index 2d432e0..96edbb6 100644 --- a/agents/issue-triage/scheduler.js +++ b/agents/issue-triage/scheduler.js @@ -11,8 +11,7 @@ const GITHUB_ISSUE_ACTIONS = [ const GITHUB_COMMENT_ACTIONS = ["created", "edited", "deleted"]; const GITHUB_TRIAGE_CONTROL_LABEL = "skip-triage"; const WORKFLOW_POLICY_JSON = "{\"version\":1,\"duplicateConfidenceThreshold\":0.92,\"classificationConfidenceThreshold\":0.75,\"priorityConfidenceThreshold\":0.8,\"maxCandidates\":20,\"maxRelatedIssues\":5,\"skipLabels\":[\"skip-triage\"],\"managedLabelPrefixes\":[\"priority:\",\"triage:\"],\"classificationLabels\":{\"bug\":\"bug\",\"enhancement\":\"enhancement\",\"documentation\":\"documentation\",\"question\":\"question\"},\"labelColors\":{\"bug\":\"d73a4a\",\"documentation\":\"0075ca\",\"enhancement\":\"a2eeef\",\"question\":\"d876e3\",\"priority:P0\":\"b60205\",\"priority:P1\":\"d93f0b\",\"priority:P2\":\"fbca04\",\"priority:P3\":\"0e8a16\",\"priority:pending\":\"c5def5\",\"triage:done\":\"0e8a16\",\"triage:needs-info\":\"fbca04\",\"duplicate\":\"cfd3d7\"},\"labelDescriptions\":{\"bug\":\"Something isn't working\",\"documentation\":\"Improvements or additions to documentation\",\"enhancement\":\"New feature or request\",\"question\":\"Further information is requested\",\"priority:P0\":\"Automated triage: critical and immediate impact\",\"priority:P1\":\"Automated triage: high-priority impact\",\"priority:P2\":\"Automated triage: significant impact\",\"priority:P3\":\"Automated triage: supported low-impact work\",\"priority:pending\":\"Automated triage: priority needs more evidence\",\"triage:done\":\"Automated initial triage completed\",\"triage:needs-info\":\"Automated triage needs reporter information\",\"duplicate\":\"This issue or pull request already exists\"}}"; -const WORKFLOW_TOOL_PATH = - "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs"; +const WORKFLOW_TOOL_PATH = "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs"; const ANALYSIS_SCHEMA = { type: "object", diff --git a/scripts/build-tools.ts b/scripts/build-tools.ts index 140d7ba..fe16fbc 100644 --- a/scripts/build-tools.ts +++ b/scripts/build-tools.ts @@ -5,8 +5,11 @@ import { build } from "esbuild"; const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); const workflowPolicyPlaceholder = "__WORKFLOW_POLICY_JSON__"; +const workflowToolPathPlaceholder = "__WORKFLOW_TOOL_PATH__"; const generatedFileBanner = "// Generated by scripts/build-tools.ts. Do not edit directly."; +// Must match every agents..workspace.target in agent-compose.yml. +const workspaceToolTarget = "workflow-repo"; const buildTargets = { "issue-triage": { @@ -25,6 +28,10 @@ const buildTargets = { }, } as const; +function toolPath(toolOutfile: string): string { + return `$WORKSPACE/${workspaceToolTarget}/${toolOutfile}`; +} + export type BuildTargetName = keyof typeof buildTargets; export interface BuildOptions { @@ -39,19 +46,27 @@ export function normalizeGeneratedSource(source: string): string { export function renderSchedulerArtifact( schedulerSource: string, workflowPolicySource: string, + workflowToolPath: string, ): string { - const generated = replaceExactlyOnce( + let generated = replaceExactlyOnce( schedulerSource, workflowPolicyPlaceholder, JSON.stringify(JSON.parse(workflowPolicySource)), ); - return normalizeGeneratedSource([generatedFileBanner, generated].join("\n")); + generated = replaceExactlyOnce( + generated, + workflowToolPathPlaceholder, + workflowToolPath, + ); + return withGeneratedFileBanner(generated); } export function renderToolArtifact(workflowToolSource: string): string { - return normalizeGeneratedSource( - [generatedFileBanner, workflowToolSource].join("\n"), - ); + return withGeneratedFileBanner(workflowToolSource); +} + +function withGeneratedFileBanner(source: string): string { + return normalizeGeneratedSource([generatedFileBanner, source].join("\n")); } function replaceExactlyOnce( @@ -124,17 +139,14 @@ async function buildTarget( }); const output = result.outputFiles?.[0]; if (!output) throw new Error(`esbuild produced no output for ${targetName}`); - const schedulerSource = await readFile( - path.join(repositoryRoot, target.schedulerSource), - "utf8", - ); - const policySource = await readFile( - path.join(repositoryRoot, target.policySource), - "utf8", - ); + const [schedulerSource, policySource] = await Promise.all([ + readFile(path.join(repositoryRoot, target.schedulerSource), "utf8"), + readFile(path.join(repositoryRoot, target.policySource), "utf8"), + ]); const generatedScheduler = renderSchedulerArtifact( schedulerSource, policySource, + toolPath(target.toolOutfile), ); const generatedTool = renderToolArtifact(output.text); diff --git a/src/schedulers/draft-pr.js b/src/schedulers/draft-pr.js index 6df4f74..cb9db56 100644 --- a/src/schedulers/draft-pr.js +++ b/src/schedulers/draft-pr.js @@ -4,8 +4,7 @@ const GITHUB_WORKFLOW_RUN_TOPIC = "webhook.github.workflow_run"; const READY_LABEL = "agent:ready"; const APPROVED_LABEL = "agent:approved"; const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__"; -const WORKFLOW_TOOL_PATH = - "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs"; +const WORKFLOW_TOOL_PATH = "__WORKFLOW_TOOL_PATH__"; const WORKSPACE_VOLUME = { type: "bind", source: "./.draft-pr-workspaces", diff --git a/src/schedulers/issue-triage.js b/src/schedulers/issue-triage.js index f96fba9..6aec2a8 100644 --- a/src/schedulers/issue-triage.js +++ b/src/schedulers/issue-triage.js @@ -10,8 +10,7 @@ const GITHUB_ISSUE_ACTIONS = [ const GITHUB_COMMENT_ACTIONS = ["created", "edited", "deleted"]; const GITHUB_TRIAGE_CONTROL_LABEL = "skip-triage"; const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__"; -const WORKFLOW_TOOL_PATH = - "$WORKSPACE/workflow-repo/agents/issue-triage/tool/main.mjs"; +const WORKFLOW_TOOL_PATH = "__WORKFLOW_TOOL_PATH__"; const ANALYSIS_SCHEMA = { type: "object", diff --git a/test/build-tools.test.ts b/test/build-tools.test.ts index 48eb490..5377149 100644 --- a/test/build-tools.test.ts +++ b/test/build-tools.test.ts @@ -61,12 +61,15 @@ describe("generated Scheduler artifact build", () => { ); }); - it("embeds the deterministic tool policy in a scheduler artifact", () => { + it("embeds the deterministic tool policy and path in a scheduler artifact", () => { const artifact = renderSchedulerArtifact( - ['const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__";', ""].join( - "\n", - ), + [ + 'const WORKFLOW_POLICY_JSON = "__WORKFLOW_POLICY_JSON__";', + 'const WORKFLOW_TOOL_PATH = "__WORKFLOW_TOOL_PATH__";', + "", + ].join("\n"), '{"enabled":true}\n', + "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs", ); expect(artifact).toContain("Generated by scripts/build-tools.ts"); @@ -74,9 +77,13 @@ describe("generated Scheduler artifact build", () => { 'const WORKFLOW_POLICY_JSON = "{\\\"enabled\\\":true}";', ); expect(artifact).not.toContain("__WORKFLOW_POLICY_JSON__"); - expect(() => renderSchedulerArtifact("const value = 1;", "{}")).toThrow( - "exactly one __WORKFLOW_POLICY_JSON__ placeholder", + expect(artifact).toContain( + 'const WORKFLOW_TOOL_PATH = "$WORKSPACE/workflow-repo/agents/draft-pr/tool/main.mjs";', ); + expect(artifact).not.toContain("__WORKFLOW_TOOL_PATH__"); + expect(() => + renderSchedulerArtifact("const value = 1;", "{}", "tool-path"), + ).toThrow("exactly one __WORKFLOW_POLICY_JSON__ placeholder"); }); it("renders a standalone tool artifact with the generated-file banner", () => { @@ -102,6 +109,8 @@ describe("generated Scheduler artifact build", () => { expect(bundle).toContain("Generated by scripts/build-tools.ts"); expect(bundle).toContain("WORKFLOW_POLICY_JSON"); expect(bundle).not.toContain("__WORKFLOW_POLICY_JSON__"); + expect(bundle).toContain("WORKFLOW_TOOL_PATH"); + expect(bundle).not.toContain("__WORKFLOW_TOOL_PATH__"); expect(bundle).not.toContain("WORKFLOW_TOOL_BASE64"); expect(bundle).not.toContain("WORKFLOW_TOOL_CHUNK_"); expect(bundle).not.toContain("node_modules/zod/v4/locales/"); From a06129f0710280ed43734f89648dbdf356ab3041 Mon Sep 17 00:00:00 2001 From: winterfx Date: Thu, 13 Aug 2026 15:25:24 +0800 Subject: [PATCH 4/4] chore(hooks): auto-rebuild tool bundles on commit Add a pre-commit hook that reruns `npm run build` and re-stages agents/*/tool/main.mjs and agents/*/scheduler.js whenever staged src/ changes would make them stale, so contributors only need to edit the TypeScript sources by hand. CI's `build:check` remains the backstop for --no-verify commits or environments without the hook enabled. Wired up via package.json's "prepare" script so `npm install` sets core.hooksPath automatically. Co-Authored-By: Claude Sonnet 5 --- .githooks/pre-commit | 15 +++++++++++++++ package.json | 1 + 2 files changed, 16 insertions(+) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..f64c14b --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Installed via `core.hooksPath` (see package.json "prepare" script). +# Rebuilds and re-stages the committed agents/*/tool/main.mjs and +# agents/*/scheduler.js bundles whenever staged src/ changes would make +# them stale, so `npm run build` never has to be run by hand. +set -euo pipefail + +if git diff --cached --name-only --diff-filter=ACM | grep -q '^src/'; then + npm run build --silent + git add \ + agents/issue-triage/tool/main.mjs \ + agents/draft-pr/tool/main.mjs \ + agents/issue-triage/scheduler.js \ + agents/draft-pr/scheduler.js +fi diff --git a/package.json b/package.json index 0493017..fffffc5 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "node": ">=20" }, "scripts": { + "prepare": "git config core.hooksPath .githooks", "build": "tsx scripts/build-tools.ts", "build:issue-triage": "tsx scripts/build-tools.ts issue-triage", "build:draft-pr": "tsx scripts/build-tools.ts draft-pr",