Skip to content

fix(issue): auto-mode: artifact verification failures pause with low-actionability diagnostics#6187

Open
jeremymcs wants to merge 7 commits into
mainfrom
issue/5733-auto-mode-artifact-verification-failures-1778892830
Open

fix(issue): auto-mode: artifact verification failures pause with low-actionability diagnostics#6187
jeremymcs wants to merge 7 commits into
mainfrom
issue/5733-auto-mode-artifact-verification-failures-1778892830

Conversation

@jeremymcs
Copy link
Copy Markdown
Collaborator

@jeremymcs jeremymcs commented May 16, 2026

Summary

  • Improved artifact-verification diagnostics and added read-only forensics classification coverage with targeted tests passing.

Bugs Addressed

  • Missing artifact error omits completion-contract guidance
  • Read-only reconnaissance classification misses common tools

Verification

  • Completed in the repository worktree before push.

Related Issue

Repo

  • gsd-build/gsd-2

Branch

  • issue/5733-auto-mode-artifact-verification-failures-1778892830

Summary by CodeRabbit

  • New Features

    • Richer artifact verification errors that include expected-artifact details and contextual hints about task completion when an artifact is missing.
    • Execution-trace classification that detects traces composed solely of read-only reconnaissance actions.
  • Tests

    • Tests validating artifact diagnostic messaging with and without task-completion signals.
    • Tests covering read-only trace classification across multiple tool-call scenarios.

Review Change Stack

jeremymcs added 2 commits May 15, 2026 20:03
missing-artifact failures now include completion-contract guidance and an explicit execute-task completion-tool hint.
added read-only reconnaissance classification coverage for `skill` and read-only `gsd_exec` command patterns.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 582292ab-08be-447b-baf5-791e4e3932a8

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa8fec and 3dfb7a4.

📒 Files selected for processing (1)
  • src/resources/extensions/gsd/commands-prefs-wizard.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/resources/extensions/gsd/commands-prefs-wizard.ts

📝 Walkthrough

Walkthrough

This PR enriches artifact verification failure diagnostics with expected-artifact context and execute-task completion-tool hints, adds trace classification to detect read-only reconnaissance-only tool calls, and fixes a this-binding in the prefs wizard with corresponding tests.

Changes

Artifact Verification and Trace Classification

Layer / File(s) Summary
Artifact verification failure message enrichment
src/resources/extensions/gsd/auto-post-unit.ts, src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
describeArtifactVerificationFailure() now accepts agentEndMessages, computes expected-artifact diagnostics earlier, augments missing-file and contract-failure messages with expected details, adds an execute-task hint when no completion tool call is detected, exports _describeArtifactVerificationFailureForTest, and passes agent end messages at retry sites.
Read-only reconnaissance trace classification
src/resources/extensions/gsd/session-forensics.ts, src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts
Adds constants and regex-based heuristics to identify read-only tool calls (including gsd_exec patterns and explicit tool names), exports classifyTraceProgress() that reports whether a trace is read-only reconnaissance only, and fixes findLast polyfill termination; includes tests covering read-only and mutating cases.

Prefs Wizard this-binding fix

Layer / File(s) Summary
Preserve registry this-binding in configureModels
src/resources/extensions/gsd/commands-prefs-wizard.ts, src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts
configureModels now captures ctx.modelRegistry in a registry variable and calls registry.getAllWithDiscovered() to avoid losing this; corresponding test mock updated to provide instance-style getAllWithDiscovered() so the call runs on the object.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • gsd-build/gsd-2#6189: Both PRs modify src/resources/extensions/gsd/commands-prefs-wizard.ts to call getAllWithDiscovered with the correct this binding and update tests accordingly.
  • gsd-build/gsd-2#6038: Similar fixes to configureModels usage of getAllWithDiscovered() and test adjustments for instance method mocking.
  • gsd-build/gsd-2#5852: Related changes touching artifact-verification diagnostics and retry/terminal reporting in auto-post-unit.ts.

Poem

🐇 I nibble logs and hop through traces, soft and spry,
I mark the missing files and whisper where they lie.
If tasks forget their end-call song, I leave a tiny clue,
I watch the quiet reconnaissance steps and hum a helpful cue.
A carrot for the tests — success hops into view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: improving artifact verification failure diagnostics with more actionable messages for auto-mode, which is the core focus of this PR.
Linked Issues check ✅ Passed The PR fully implements the proposed fixes from issue #5733: always includes expected-artifact diagnostics in missing-artifact messages, adds completion-tool absence hints for execute-task, expands read-only tool classification (adds 'skill'), and includes adversarial regression tests.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objectives: artifact verification messaging, read-only classification, and targeted tests. The minor context-binding fix in commands-prefs-wizard.ts is a necessary supporting fix enabling proper test behavior and falls within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue/5733-auto-mode-artifact-verification-failures-1778892830
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch issue/5733-auto-mode-artifact-verification-failures-1778892830

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 16, 2026

🔴 PR Risk Report — CRITICAL

Files changed 6
Systems affected 1
Overall risk 🔴 CRITICAL

Affected Systems

Risk System
🔴 critical Auto Engine
File Breakdown
Risk File Systems
🔴 src/resources/extensions/gsd/auto-post-unit.ts Auto Engine
src/resources/extensions/gsd/commands-prefs-wizard.ts (unclassified)
src/resources/extensions/gsd/session-forensics.ts (unclassified)
src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts (unclassified)
src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts (unclassified)
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts (unclassified)

⚠️ 🔴 Critical risk — the following systems require verification before merge:

  • 🔴 Auto Engine: validate auto-mode trigger conditions and loop termination

⛔ This PR should not be merged without executing this follow-up prompt.

Ask your coding agent to verify before submitting:

Review this PR for risks in: Auto Engine. Verify:

1. validate auto-mode trigger conditions and loop termination

Before modifying any code, assess the scope of this fix:

- Identify the root cause, not just the reported symptom.
- Search the codebase for other call sites, similar patterns, or duplicated logic that may share the same bug.
- List affected tests, documentation, and any downstream consumers that depend on the current behavior.
- Flag any changes that extend beyond the immediate file or function.

Report findings first. Then propose a fix scoped to the actual root cause, and wait for confirmation before applying changes outside the originally reported location.

💡 Have a Codex subscription? Get an independent second opinion: codex review --adversarial

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts (1)

17-32: ⚡ Quick win

Add adversarial cases for shell chaining/script execution.

Please add regression tests for commands like cat file && echo x > y and script-eval forms (python -c ..., node --print ...) to lock down read-only classification boundaries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`
around lines 17 - 32, Add regression tests in
session-forensics-readonly-classification.test.ts that exercise shell-chaining
and script-eval adversarial cases against classifyTraceProgress: create traces
using traceWithToolCalls invoking gsd_exec with a chained command like "cat file
&& echo x > y" and assert result.isReadOnlyReconnaissanceOnly === false, and
another trace using a script-eval form (e.g., "python -c \"...write...\"" or
"node -e \"require('fs').writeFileSync(...)\"") and assert
isReadOnlyReconnaissanceOnly === false; keep the test patterns consistent with
existing tests (use traceWithToolCalls and classifyTraceProgress) so the new
cases lock down read-only classification boundaries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/resources/extensions/gsd/auto-post-unit.ts`:
- Around line 458-461: The message unconditionally appends a "No completion tool
call detected" hint for unitType === "execute-task" even though this function
doesn't inspect the unit's trace history; update the logic that builds
completionToolHint (the completionToolHint variable and the branch checking
unitType === "execute-task") so it only adds that hint after confirming the
unit's trace/tool-call history actually lacks a gsd_task_complete (and its known
aliases) entry—i.e., accept or access the unit's trace/toolCalls context, scan
for any call named "gsd_task_complete" (or alias) and only set
completionToolHint when none are found; keep the rest of the artifact-not-found
message unchanged.

In `@src/resources/extensions/gsd/session-forensics.ts`:
- Around line 79-87: The current READ_ONLY_EXEC_COMMAND_RE and
isReadOnlyReconnaissanceTool allow commands like "python -c '...; rm -rf /'" by
matching only a safe prefix; tighten the classifier by rejecting any command
that contains shell metacharacters or piping/redirection after the matched
read-only prefix. Update either READ_ONLY_EXEC_COMMAND_RE or add a secondary
check in isReadOnlyReconnaissanceTool (using the local variable command) to
ensure the remainder of the command contains only safe token characters/flags
(e.g., letters, numbers, dashes, dots) and explicitly disallow characters like ;
& | > < $ ` ( ) $() || && `>` and shell control operators, while still allowing
simple version/flag forms; keep READ_ONLY_TOOL_NAMES behavior intact and return
false for any command failing this stricter validation.

---

Nitpick comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 17-32: Add regression tests in
session-forensics-readonly-classification.test.ts that exercise shell-chaining
and script-eval adversarial cases against classifyTraceProgress: create traces
using traceWithToolCalls invoking gsd_exec with a chained command like "cat file
&& echo x > y" and assert result.isReadOnlyReconnaissanceOnly === false, and
another trace using a script-eval form (e.g., "python -c \"...write...\"" or
"node -e \"require('fs').writeFileSync(...)\"") and assert
isReadOnlyReconnaissanceOnly === false; keep the test patterns consistent with
existing tests (use traceWithToolCalls and classifyTraceProgress) so the new
cases lock down read-only classification boundaries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 605882d3-ccb5-4067-ad5f-4b435e6ff540

📥 Commits

Reviewing files that changed from the base of the PR and between db89d64 and b36c97c.

📒 Files selected for processing (4)
  • src/resources/extensions/gsd/auto-post-unit.ts
  • src/resources/extensions/gsd/session-forensics.ts
  • src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
  • src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts

Comment thread src/resources/extensions/gsd/auto-post-unit.ts Outdated
Comment thread src/resources/extensions/gsd/session-forensics.ts Outdated
@jeremymcs
Copy link
Copy Markdown
Collaborator Author

jeremymcs commented May 16, 2026

Accepted — this comment requires code changes. Queuing fix...
🧰 Agent runningcodex is working on the fix...
Agent completed — verifying changes...
🎉 Resolved — addressed in commit 3ee901c.

1 similar comment
@jeremymcs
Copy link
Copy Markdown
Collaborator Author

jeremymcs commented May 16, 2026

Accepted — this comment requires code changes. Queuing fix...
🧰 Agent runningcodex is working on the fix...
Agent completed — verifying changes...
🎉 Resolved — addressed in commit 3ee901c.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

🤖 Dispatched codex with the following prompt:

Agent prompt (click to expand)
You are acting as an autonomous PR babysitter for gsd-build/gsd-2 PR #6187.
PR URL: https://github.com/gsd-build/gsd-2/pull/6187
Base repository: gsd-build/gsd-2
Head repository: gsd-build/gsd-2
Head branch: issue/5733-auto-mode-artifact-verification-failures-1778892830
Head remote: origin
You are running inside an isolated app-owned worktree under ~/.patchdeck.
Make only targeted changes that resolve the approved tasks.
Do not wait for user input, confirmation, or approval at any point.
Do not rewrite unrelated files.
Use the available git tooling for inspection and verification only.
If dependencies are missing, install them using the repository's lockfile/package manager as needed inside this isolated worktree.
Leave file edits uncommitted; the babysitter app will handle Git finalization after your run.
GitHub follow-up replies and review-thread resolution will be handled by the babysitter after your run.
If a task is invalid after inspection, explain it in your final response and include the exact audit token.

Approved review-comment tasks:
1. [general_comment] coderabbitai[bot]
   file=n/a line=n/a
   sourceId=4464911691 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#issuecomment-4464911691
   replyKind=general_comment threadId=n/a threadResolved=n/a
   auditToken=codefactory-feedback:gh-issue-comment-4464911691
   <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough

This PR enriches artifact verification failure diagnostics and improves read-only trace classification. When artifact verification fails, the error message now includes expected contract details and execute-task-specific completion-tool hints. A new trace classification function identifies read-only reconnaissance actions to reduce false negatives in diagnostic output.

## Changes

**Artifact Verification and Trace Classification**

| Layer / File(s) | Summary |
|---|---|
| **Artifact verification failure message enrichment** <br> `src/resources/extensions/gsd/auto-post-unit.ts`, `src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts` | `describeArtifactVerificationFailure()` now computes expected-artifact details upfront and augments both missing-artifact and contract-failure messages with expected context. For `execute-task` units, an additional hint is appended when no completion tool call is detected. The function is exported as `_describeArtifactVerificationFailureForTest` for testing. |
| **Read-only reconnaissance trace classification** <br> `src/resources/extensions/gsd/session-forensics.ts`, `src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts` | New constants and logic identify read-only reconnaissance tool calls via tool-name set and regex-based filtering of `gsd_exec` commands. Exported `classifyTraceProgress()` scans execution traces and reports whether all tool calls are read-only reconnaissance. A polyfill fix ensures `findLast` cleanly returns `undefined` without a match. |

## Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

## Possibly related PRs

- [gsd-build/gsd-2#5852](https://github.com/gsd-build/gsd-2/pull/5852): Modifies artifact-verification diagnostics in `auto-post-unit.ts` to handle additional failure modes and enhance terminal failure reporting.

## Poem

> 🐰 Artifacts speak clearer now, with hints to guide the way,  
> When tasks complete, or tools fall mute, diagnostics save the day.  
> Read-only traces shine so bright, reconnaissance refined,  
> False negatives fade to the past—recovery's easier to find! ✨

</details>

<!-- walkthrough_end -->
<!-- pre_merge_checks_walkthrough_start -->

<details>
<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary>

### ❌ Failed checks (1 warning)

|     Check name     | Status     | Explanation                                                                           | Resolution                                                                         |
| :----------------: | :--------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- |
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |

<details>
<summary>✅ Passed checks (4 passed)</summary>

|         Check name         | Status   | Explanation                                                                                                                                                                                                                                                                                                                                                                                              |
| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|      Description Check     | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                                                                                                                                                                                              |
|         Title check        | ✅ Passed | The title clearly describes the main change: improving artifact verification failure diagnostics in auto-mode with better guidance. It directly reflects the primary intent shown in the PR objectives.                                                                                                                                                                                                  |
|     Linked Issues check    | ✅ Passed | The PR addresses all four main objectives from issue `#5733`: (1) includes completion-contract guidance in missing-artifact messages via enhanced describeArtifactVerificationFailure, (2) adds completion-tool absence hint for execute-task via test coverage, (3) extends read-only detection via classifyTraceProgress to handle 'skill' and gsd_exec patterns, and (4) provides diagnostic framework. |
| Out of Scope Changes check | ✅ Passed | All changes are directly scoped to the PR objectives: artifact diagnostic improvements in auto-post-unit.ts, read-only forensics classification in session-forensics.ts, and corresponding unit tests. No unrelated modifications detected.                                                                                                                                                              |

</details>

<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>

</details>

<!-- pre_merge_checks_walkthrough_end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

<details>
<summary>📝 Generate docstrings</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> Create stacked PR
- [ ] <!-- {"checkboxId": "3e1879ae-f29b-4d0d-8e06-d12b7ba33d98"} --> Commit on current branch

</details>
<details>
<summary>🧪 Generate unit tests (beta)</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with unit tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Commit unit tests in branch `issue/5733-auto-mode-artifact-verification-failures-1778892830`

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> ESLint skipped: no ESLint configuration detected in root package.json. To enable, add `eslint` to devDependencies.
> 
> 
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->
<!-- tips_start -->

---

Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=gsd-build/gsd-2&utm_content=6187)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>


<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>

<!-- tips_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
2. [review_comment] coderabbitai[bot]
   file=src/resources/extensions/gsd/auto-post-unit.ts line=461
   sourceId=3251727627 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#discussion_r3251727627
   replyKind=review_thread threadId=PRRT_kwDORj5hb86Cgq0b threadResolved=false
   auditToken=codefactory-feedback:gh-review-comment-3251727627
   _⚠️ Potential issue_ | _🟠 Major_ | _⚡ Quick win_

**Completion-tool absence is asserted without evidence.**

This message is emitted for every missing `execute-task` artifact, but this function does not inspect trace/tool-call history. It can report a false diagnosis and mislead retries.

 

<details>
<summary>Suggested fix</summary>

```diff
-    const completionToolHint = unitType === "execute-task"
-      ? " No completion tool call detected (`gsd_task_complete`/alias)."
+    const completionToolHint = unitType === "execute-task"
+      ? " Check whether completion tool (`gsd_task_complete`/alias) was called."
       : "";
```

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/resources/extensions/gsd/auto-post-unit.ts` around lines 458 - 461, The
message unconditionally appends a "No completion tool call detected" hint for
unitType === "execute-task" even though this function doesn't inspect the unit's
trace history; update the logic that builds completionToolHint (the
completionToolHint variable and the branch checking unitType === "execute-task")
so it only adds that hint after confirming the unit's trace/tool-call history
actually lacks a gsd_task_complete (and its known aliases) entry—i.e., accept or
access the unit's trace/toolCalls context, scan for any call named
"gsd_task_complete" (or alias) and only set completionToolHint when none are
found; keep the rest of the artifact-not-found message unchanged.
```

</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->
3. [review_comment] coderabbitai[bot]
   file=src/resources/extensions/gsd/session-forensics.ts line=87
   sourceId=3251727629 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#discussion_r3251727629
   replyKind=review_thread threadId=PRRT_kwDORj5hb86Cgq0d threadResolved=false
   auditToken=codefactory-feedback:gh-review-comment-3251727629
   _⚠️ Potential issue_ | _🟠 Major_ | _⚡ Quick win_

**Read-only classifier can mislabel mutating `gsd_exec` commands.**

The allowlist regex matches command prefixes and currently permits executable script forms (e.g., `python -c`, `node --print`) and shell chaining/redirection after a read-only prefix. That can classify write-capable commands as reconnaissance-only.

 

<details>
<summary>Suggested hardening</summary>

```diff
-const READ_ONLY_EXEC_COMMAND_RE = /^\s*(cat|head|tail|ls|find|grep|rg|git\s+(status|log|show|diff|branch|remote|rev-parse|ls-files)|npm\s+(ls|list|info|view|show|outdated|audit|doctor|ping|--version|-v)|node\s+(--print|--version|-v\b)|python[23]?\s+(-c\s+'[^']*'|--version|-V\b)|jq\s|yq\s|env\b|printenv\b)/;
+const UNSAFE_SHELL_TOKENS_RE = /(?:&&|\|\||;|[<>]|`|\$\(|\n)/;
+const READ_ONLY_EXEC_COMMAND_RE = /^\s*(cat|head|tail|ls|find|grep|rg|git\s+(status|log|show|diff|branch|remote|rev-parse|ls-files)|npm\s+(ls|list|info|view|show|outdated|audit|doctor|ping|--version|-v)|node\s+(--version|-v\b)|python[23]?\s+(--version|-V\b)|jq\b|yq\b|env\b|printenv\b)\s*$/;
...
   const command = String(call.input.command || call.input.cmd || "").trim();
   if (!command) return false;
+  if (UNSAFE_SHELL_TOKENS_RE.test(command)) return false;
   return READ_ONLY_EXEC_COMMAND_RE.test(command);
```

</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
const UNSAFE_SHELL_TOKENS_RE = /(?:&&|\|\||;|[<>]|`|\$\(|\n)/;
const READ_ONLY_EXEC_COMMAND_RE = /^\s*(cat|head|tail|ls|find|grep|rg|git\s+(status|log|show|diff|branch|remote|rev-parse|ls-files)|npm\s+(ls|list|info|view|show|outdated|audit|doctor|ping|--version|-v)|node\s+(--version|-v\b)|python[23]?\s+(--version|-V\b)|jq\b|yq\b|env\b|printenv\b)\s*$/;

function isReadOnlyReconnaissanceTool(call: ToolCall): boolean {
  const name = call.name.toLowerCase();
  if (READ_ONLY_TOOL_NAMES.has(name)) return true;
  if (name !== "gsd_exec") return false;
  const command = String(call.input.command || call.input.cmd || "").trim();
  if (!command) return false;
  if (UNSAFE_SHELL_TOKENS_RE.test(command)) return false;
  return READ_ONLY_EXEC_COMMAND_RE.test(command);
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/resources/extensions/gsd/session-forensics.ts` around lines 79 - 87, The
current READ_ONLY_EXEC_COMMAND_RE and isReadOnlyReconnaissanceTool allow
commands like "python -c '...; rm -rf /'" by matching only a safe prefix;
tighten the classifier by rejecting any command that contains shell
metacharacters or piping/redirection after the matched read-only prefix. Update
either READ_ONLY_EXEC_COMMAND_RE or add a secondary check in
isReadOnlyReconnaissanceTool (using the local variable command) to ensure the
remainder of the command contains only safe token characters/flags (e.g.,
letters, numbers, dashes, dots) and explicitly disallow characters like ; & | >
< $ ` ( ) $() || && `>` and shell control operators, while still allowing simple
version/flag forms; keep READ_ONLY_TOOL_NAMES behavior intact and return false
for any command failing this stricter validation.
```

</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->
4. [review] coderabbitai[bot]
   file=n/a line=n/a
   sourceId=4302326702 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#pullrequestreview-4302326702
   replyKind=review threadId=n/a threadResolved=n/a
   auditToken=codefactory-feedback:gh-review-4302326702
   **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts (1)</summary><blockquote>

`17-32`: _⚡ Quick win_

**Add adversarial cases for shell chaining/script execution.**

Please add regression tests for commands like `cat file && echo x > y` and script-eval forms (`python -c ...`, `node --print ...`) to lock down read-only classification boundaries.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`
around lines 17 - 32, Add regression tests in
session-forensics-readonly-classification.test.ts that exercise shell-chaining
and script-eval adversarial cases against classifyTraceProgress: create traces
using traceWithToolCalls invoking gsd_exec with a chained command like "cat file
&& echo x > y" and assert result.isReadOnlyReconnaissanceOnly === false, and
another trace using a script-eval form (e.g., "python -c \"...write...\"" or
"node -e \"require('fs').writeFileSync(...)\"") and assert
isReadOnlyReconnaissanceOnly === false; keep the test patterns consistent with
existing tests (use traceWithToolCalls and classifyTraceProgress) so the new
cases lock down read-only classification boundaries.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/resources/extensions/gsd/auto-post-unit.ts`:
- Around line 458-461: The message unconditionally appends a "No completion tool
call detected" hint for unitType === "execute-task" even though this function
doesn't inspect the unit's trace history; update the logic that builds
completionToolHint (the completionToolHint variable and the branch checking
unitType === "execute-task") so it only adds that hint after confirming the
unit's trace/tool-call history actually lacks a gsd_task_complete (and its known
aliases) entry—i.e., accept or access the unit's trace/toolCalls context, scan
for any call named "gsd_task_complete" (or alias) and only set
completionToolHint when none are found; keep the rest of the artifact-not-found
message unchanged.

In `@src/resources/extensions/gsd/session-forensics.ts`:
- Around line 79-87: The current READ_ONLY_EXEC_COMMAND_RE and
isReadOnlyReconnaissanceTool allow commands like "python -c '...; rm -rf /'" by
matching only a safe prefix; tighten the classifier by rejecting any command
that contains shell metacharacters or piping/redirection after the matched
read-only prefix. Update either READ_ONLY_EXEC_COMMAND_RE or add a secondary
check in isReadOnlyReconnaissanceTool (using the local variable command) to
ensure the remainder of the command contains only safe token characters/flags
(e.g., letters, numbers, dashes, dots) and explicitly disallow characters like ;
& | > < $ ` ( ) $() || && `>` and shell control operators, while still allowing
simple version/flag forms; keep READ_ONLY_TOOL_NAMES behavior intact and return
false for any command failing this stricter validation.

---

Nitpick comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 17-32: Add regression tests in
session-forensics-readonly-classification.test.ts that exercise shell-chaining
and script-eval adversarial cases against classifyTraceProgress: create traces
using traceWithToolCalls invoking gsd_exec with a chained command like "cat file
&& echo x > y" and assert result.isReadOnlyReconnaissanceOnly === false, and
another trace using a script-eval form (e.g., "python -c \"...write...\"" or
"node -e \"require('fs').writeFileSync(...)\"") and assert
isReadOnlyReconnaissanceOnly === false; keep the test patterns consistent with
existing tests (use traceWithToolCalls and classifyTraceProgress) so the new
cases lock down read-only classification boundaries.
```

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro Plus

**Run ID**: `605882d3-ccb5-4067-ad5f-4b435e6ff540`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between db89d645b0ff6d7ae4d57cb1f418353638a0beba and b36c97c54feaf1395a6d27a33d137f68a84ae979.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `src/resources/extensions/gsd/auto-post-unit.ts`
* `src/resources/extensions/gsd/session-forensics.ts`
* `src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts`
* `src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Approved status-check tasks:
None

Approved documentation tasks:
None

When done:
1) Run the relevant verification for your changes.
2) Leave any changed files in the worktree for the babysitter app to finalize.
3) For each feedback item you addressed or were blocked on, emit a summary block in the following format:
   FEEDBACK_SUMMARY_START <auditToken>
   <A concise 1-2 sentence summary of what you did or why you were blocked>
   FEEDBACK_SUMMARY_END
   Include one block per audit token. These summaries will be posted as follow-up comments on the PR.
4) If documentation tasks were assigned, emit exactly one docs summary block in the following format:
   DOCS_SUMMARY_START <changed|no_change>
   <A concise 1-2 sentence summary of the docs you updated, or why no docs changes were necessary after inspection>
   DOCS_SUMMARY_END

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Addressed in commit 3ee901c by the latest babysitter run.

Responding to comment by @coderabbitai[bot]:

Reviewed the general CodeRabbit walkthrough/check output and confirmed the actionable items were the two inline review concerns plus added regression tests; no separate code change was required from the summary-only comment itself.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Addressed in commit 3ee901c by the latest babysitter run.

Responding to comment by @coderabbitai[bot]:
Actionable comments posted: 2

Added adversarial regression coverage for shell chaining (cat file && echo x > y) and script-eval (python -c ...write...) and asserted both are not classified as read-only reconnaissance. Existing positive/negative classification tests continue to pass.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Tip

For best results, initiate chat on the files or code changes.

@jeremymcs: Thanks for the follow-up! The adversarial regression coverage for shell chaining (cat file && echo x > y) and script-eval (python -c ...write...) looks like exactly the right hardening — both are classic bypass vectors that a naive prefix/regex approach would miss. Good to hear the existing classification tests continue to pass as well.

🐇 ✨

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts (1)

26-48: ⚡ Quick win

Consider adding an empty trace edge case test.

The current tests cover various command patterns, but don't verify behavior when toolCalls is empty. An empty trace is a common edge case that should have explicit, tested behavior.

📋 Proposed empty trace test
test("classifyTraceProgress treats empty trace as reconnaissance-only", () => {
  const trace = traceWithToolCalls([]);
  const result = classifyTraceProgress(trace);
  // Adjust expected value based on desired semantics:
  // true if "no mutations" implies read-only, false if "no actions" is distinct
  assert.equal(result.isReadOnlyReconnaissanceOnly, true);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`
around lines 26 - 48, Add an edge-case unit test that passes an empty toolCalls
array to traceWithToolCalls and asserts classifyTraceProgress returns a
reconnaissance-only result; specifically add a test like "classifyTraceProgress
treats empty trace as reconnaissance-only" that constructs const trace =
traceWithToolCalls([]), calls const result = classifyTraceProgress(trace), and
asserts result.isReadOnlyReconnaissanceOnly === true so the classifier’s
behavior for empty traces is explicitly verified.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 17-24: Add two unit tests to
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts
that call classifyTraceProgress with traces created by traceWithToolCalls
containing only the "skill" tool and only the read-only "gsd_exec" command
respectively; for each test assert that result.isReadOnlyReconnaissanceOnly ===
true so we verify that classifyTraceProgress detects "skill" alone and read-only
"gsd_exec" alone as reconnaissance-only rather than requiring both together.

---

Nitpick comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 26-48: Add an edge-case unit test that passes an empty toolCalls
array to traceWithToolCalls and asserts classifyTraceProgress returns a
reconnaissance-only result; specifically add a test like "classifyTraceProgress
treats empty trace as reconnaissance-only" that constructs const trace =
traceWithToolCalls([]), calls const result = classifyTraceProgress(trace), and
asserts result.isReadOnlyReconnaissanceOnly === true so the classifier’s
behavior for empty traces is explicitly verified.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 53ea4df4-a8f1-4861-bc69-6abbcb6e0cd4

📥 Commits

Reviewing files that changed from the base of the PR and between b36c97c and 3ee901c.

📒 Files selected for processing (4)
  • src/resources/extensions/gsd/auto-post-unit.ts
  • src/resources/extensions/gsd/session-forensics.ts
  • src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
  • src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/resources/extensions/gsd/session-forensics.ts
  • src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
  • src/resources/extensions/gsd/auto-post-unit.ts

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

jeremymcs commented May 16, 2026

Accepted — this comment requires code changes. Queuing fix...
🧰 Agent runningcodex is working on the fix...
Agent completed — verifying changes...
🎉 Resolved — addressed in commit 37c92c7.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

🤖 Dispatched codex with the following prompt:

Agent prompt (click to expand)
You are acting as an autonomous PR babysitter for gsd-build/gsd-2 PR #6187.
PR URL: https://github.com/gsd-build/gsd-2/pull/6187
Base repository: gsd-build/gsd-2
Head repository: gsd-build/gsd-2
Head branch: issue/5733-auto-mode-artifact-verification-failures-1778892830
Head remote: origin
You are running inside an isolated app-owned worktree under ~/.patchdeck.
Make only targeted changes that resolve the approved tasks.
Do not wait for user input, confirmation, or approval at any point.
Do not rewrite unrelated files.
Use the available git tooling for inspection and verification only.
If dependencies are missing, install them using the repository's lockfile/package manager as needed inside this isolated worktree.
Leave file edits uncommitted; the babysitter app will handle Git finalization after your run.
GitHub follow-up replies and review-thread resolution will be handled by the babysitter after your run.
If a task is invalid after inspection, explain it in your final response and include the exact audit token.

Approved review-comment tasks:
1. [review_comment] coderabbitai[bot]
   file=src/resources/extensions/gsd/auto-post-unit.ts line=461
   sourceId=3251764934 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#discussion_r3251764934
   replyKind=review_thread threadId=PRRT_kwDORj5hb86Cgq0b threadResolved=true
   auditToken=codefactory-feedback:gh-review-comment-3251764934
   <details>
<summary>🧩 Analysis chain</summary>

🏁 Script executed:
```
#!/bin/bash
# Check ExecutionTrace type and session-forensics.ts structure
rg -n "ExecutionTrace" --type=ts -C2

echo "---"

# Look for gsd_task_complete references in the codebase
rg -n "gsd_task_complete" --type=ts -C2

echo "---"

# Check what tool names are used for completion in execute-task context
rg -n "task_complete\|gsd_task_complete\|completion.*tool\|tool.*completion" --type=ts -l
```

Length of output: 46847

---



</details>

`@jeremymcs`, acknowledged! Here are two concrete options for the fix — one minimal, one accurate:

---

### Option A — Minimal (advisory language, no signature change)

This directly addresses the false assertion with a two-file change:

**`src/resources/extensions/gsd/auto-post-unit.ts`** (Lines 458–460):
```diff
-    const completionToolHint = unitType === "execute-task"
-      ? " No completion tool call detected (`gsd_task_complete`/alias)."
-      : "";
+    const completionToolHint = unitType === "execute-task"
+      ? " Check whether a completion tool call (`gsd_task_complete`/alias) was made."
+      : "";
```

**`src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts`** (Line 16):
```diff
-  assert.match(msg, /No completion tool call detected \(`gsd_task_complete`\/alias\)/);
+  assert.match(msg, /Check whether a completion tool call \(`gsd_task_complete`\/alias\) was made/);
```

---

### Option B — Accurate (scan `toolCalls` before emitting hint)

Pass an optional trace to the helper and only emit the hint when `gsd_task_complete` / `gsd_complete_task` is genuinely absent:

**`src/resources/extensions/gsd/auto-post-unit.ts`**:
```diff
-function describeArtifactVerificationFailure(unitType: string, unitId: string, basePath: string): string {
+import type { ExecutionTrace } from "./session-forensics.js";
+
+const TASK_COMPLETE_TOOL_NAMES = new Set(["gsd_task_complete", "gsd_complete_task"]);
+
+function describeArtifactVerificationFailure(
+  unitType: string,
+  unitId: string,
+  basePath: string,
+  trace?: ExecutionTrace | null,
+): string {
   // ...
   if (!existsSync(artifactPath)) {
-    const completionToolHint = unitType === "execute-task"
-      ? " No completion tool call detected (`gsd_task_complete`/alias)."
-      : "";
+    let completionToolHint = "";
+    if (unitType === "execute-task") {
+      const hasCompletionCall = trace?.toolCalls.some(c => TASK_COMPLETE_TOOL_NAMES.has(c.name));
+      completionToolHint = hasCompletionCall === false
+        ? " No completion tool call detected (`gsd_task_complete`/alias)."
+        : " Check whether a completion tool call (`gsd_task_complete`/alias) was made.";
+    }
     return `Artifact verification failed: ...${completionToolHint}`;
   }
```

Then at the call site, pass the session trace (if available):
```diff
  const failureDetails = describeArtifactVerificationFailure(
    s.currentUnit.type,
    s.currentUnit.id,
    s.basePath,
+   s.currentTrace ?? null,   // thread the live ExecutionTrace if AutoSession carries it
  );
```

And update `_describeArtifactVerificationFailureForTest` and the test to pass a mock trace with no matching tool calls.

---

**Recommendation:** Option A is the safer choice for this PR — Option B requires `AutoSession` to carry a live `ExecutionTrace` reference at the call site, which may not be available yet. Option B could be a clean follow-up once the trace-threading infrastructure is in place.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

- File: src/resources/extensions/gsd/auto-post-unit.ts
  - Enqueue sidecar function (complete snippet)
  ```
  /** Enqueue a sidecar item (hook, triage, or quick-task) for the main loop to
   *  drain via runUnit. Logs the enqueue event and notifies the UI. */
  function enqueueSidecar(
    s: AutoSession,
    ctx: ExtensionContext,
    entry: SidecarItem,
    debugExtra: Record<string, unknown>,
    notification?: string,
  ): "continue" {
    s.sidecarQueue.push(entry);
    debugLog("postUnitPostVerification", {
      phase: "sidecar-enqueue",
      kind: entry.kind,
      unitId: entry.unitId,
      ...debugExtra,
    });
    if (notification) ctx.ui.notify(notification, "info");
    return "continue";
  }
  ```
  - Post-unit hooks queuing (summary description)
    - What it does: If a post-unit hook is applicable, closes out the current unit, persists hook state, and enqueues a sidecar item for a hook to run later via enqueueSidecar. If a hook requests a retry of the trigger unit, it resets the trigger state (DB pending task, deletes the trigger's SUMMARY if needed, deletes any related retry artifact) and invalidates caches. This flow is used to shift hook-driven actions into the main post-unit queue rather than executing inline.
  - Triages and Quick-tasks dispatch (summary description)
    - Triages: When conditions indicate pending captures exist, derives milestone/slice context, loads current plan/roadmap, builds a triage prompt, closes out the current unit if needed, and enqueues a triage sidecar with unitId of the form "<mid>/<sid>/triage".
    - Quick-tasks: When there are pending quick tasks, builds a quick-task prompt, closes out the current unit if needed, marks the capture executed, and enqueues a quick-task sidecar with unitId of the form "<mid>/<capture.id>".

- File: src/resources/extensions/gsd/auto-post-unit.ts
  - Triage dispatch (docstring-style description)
    - Parameters: s (AutoSession), ctx (ExtensionContext)
    - Returns: "continue" when enqueued, else "step-wizard"/"stopped" in step-mode paths
    - Notes: Only dispatched when _shouldDispatchTriageForTest(s) is true and there are pending captures; constructs a triage prompt via triage-captures flow and enqueues a sidecar with kind: "triage", unitType: "triage-captures", unitId: "<mid>/<sid>/triage".
  - Quick-task dispatch (docstring-style description)
    - Parameters: s (AutoSession), ctx (ExtensionContext)
    - Returns: "continue" or "stopped"/"step-wizard" in step-mode
    - Notes: When there are pending quick tasks, creates a quick-task prompt, marks the capture executed, and enqueues a sidecar with kind: "quick-task", unitType: "quick-task", unitId: "<mid>/<capture.id>".

- File: src/resources/extensions/gsd/auto.ts
  - SidecarItem interface (from another module, for reference)
  - Content:
  ```
  export interface SidecarItem {
    kind: "hook" | "triage" | "quick-task";
    unitType: string;
    unitId: string;
    prompt: string;
    /** Model override for hook units (e.g. "anthropic/claude-3-5-sonnet"). */
    model?: string;
    /** Capture ID for quick-task items (already marked executed at enqueue time). */
    captureId?: string;
  }
  ```

- File: src/resources/extensions/gsd/auto/verification-retry-policy.ts
  - verificationRetryKey function
  ```
  export function verificationRetryKey(unitType: string, unitId: string): string {
    return `${unitType}:${unitId}`;
  }
  ```

- File: src/resources/extensions/gsd/auto-post-unit.ts
  - (Optional contextual note)
    - The code paths above are invoked within postUnitPostVerification and are designed to move actions (hooks, triage, quick-tasks) into s.sidecarQueue for the main loop to drain, enabling re-dispatch and avoiding inline side effects during verification.

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
2. [review_comment] coderabbitai[bot]
   file=src/resources/extensions/gsd/session-forensics.ts line=87
   sourceId=3251767287 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#discussion_r3251767287
   replyKind=review_thread threadId=PRRT_kwDORj5hb86Cgq0d threadResolved=true
   auditToken=codefactory-feedback:gh-review-comment-3251767287
   `@jeremymcs`, thanks for accepting! Here's the planned fix:



## Fix: Tighten `gsd_exec` read-only classifier to reject mutating commands

- Add `UNSAFE_SHELL_TOKENS_RE` to reject any command containing shell chaining/redirection/subshell metacharacters (`&&`, `||`, `;`, `<>`, backtick, `$(`, newline)
- Tighten `READ_ONLY_EXEC_COMMAND_RE`: anchor with `\s*$`, remove the `python -c '...'` and `node --print` executable forms, switch `jq\s`/`yq\s` to `jq\b`/`yq\b`
- Add an early-return guard in `isReadOnlyReconnaissanceTool` using the new unsafe-tokens check

<!-- <requirement>
[requirement tighten_readonly_classifier_1/1]
Tighten the `gsd_exec` read-only classifier in `src/resources/extensions/gsd/session-forensics.ts` to:
1. Add a new `UNSAFE_SHELL_TOKENS_RE` constant that matches shell chaining/redirection/subshell metacharacters.
2. Update `READ_ONLY_EXEC_COMMAND_RE` to anchor at end (`\s*$`), remove `python[23]? -c '...'` and `node --print` (both can execute arbitrary code), and change `jq\s`/`yq\s` to `jq\b`/`yq\b`.
3. Add an early-return in `isReadOnlyReconnaissanceTool` to reject commands containing unsafe shell tokens.

File: `src/resources/extensions/gsd/session-forensics.ts`

```diff
-const READ_ONLY_EXEC_COMMAND_RE = /^\s*(cat|head|tail|ls|find|grep|rg|git\s+(status|log|show|diff|branch|remote|rev-parse|ls-files)|npm\s+(ls|list|info|view|show|outdated|audit|doctor|ping|--version|-v)|node\s+(--print|--version|-v\b)|python[23]?\s+(-c\s+'[^']*'|--version|-V\b)|jq\s|yq\s|env\b|printenv\b)/;
+const UNSAFE_SHELL_TOKENS_RE = /(?:&&|\|\||;|[<>]|`|\$\(|\n)/;
+const READ_ONLY_EXEC_COMMAND_RE = /^\s*(cat|head|tail|ls|find|grep|rg|git\s+(status|log|show|diff|branch|remote|rev-parse|ls-files)|npm\s+(ls|list|info|view|show|outdated|audit|doctor|ping|--version|-v)|node\s+(--version|-v\b)|python[23]?\s+(--version|-V\b)|jq\b|yq\b|env\b|printenv\b)\s*$/;
 
 function isReadOnlyReconnaissanceTool(call: ToolCall): boolean {
   const name = call.name.toLowerCase();
   if (READ_ONLY_TOOL_NAMES.has(name)) return true;
   if (name !== "gsd_exec") return false;
   const command = String(call.input.command || call.input.cmd || "").trim();
   if (!command) return false;
+  if (UNSAFE_SHELL_TOKENS_RE.test(command)) return false;
   return READ_ONLY_EXEC_COMMAND_RE.test(command);
 }
```

Key behavioural changes:
- `python -c 'import os; os.remove("x")'` → now **rejected** (unsafe token check catches the semicolon; also no longer matched by the tightened regex)
- `node --print "require('fs').readFileSync('x')"` → now **rejected** (removed from regex)
- `git status && rm -rf /` → now **rejected** (unsafe token `&&`)
- `cat file > /tmp/out` → now **rejected** (unsafe token `>`)
- `git status` → still **accepted** ✓
- `npm ls` → still **accepted** ✓
- `jq .key file.json` → still **accepted** ✓ (word boundary prevents `jqsomething` from matching)
</requirement> -->

---

<!-- agent-chat-trees: W3sicGF0aCI6InNyYy9yZXNvdXJjZXMvZXh0ZW5zaW9ucy9nc2QvYXV0by9waGFzZXMudHMiLCJjb250ZW50IjoiLy8gUHJvamVjdC9BcHA6IEdTRC0yXG4vLyBGaWxlIFB1cnBvc2U6IEF1dG8tbG9vcCBwaXBlbGluZSBwaGFzZXMsIG1lcmdlIGNsb3Nlb3V0LCBhbmQgZmluYWxpemUgaGFuZGxpbmcuXG4vKipcbiAqIGF1dG8vcGhhc2VzLnRzIOKAlCBQaXBlbGluZSBwaGFzZXMgZm9yIHRoZSBhdXRvLWxvb3AuXG4gKlxuICogQ29udGFpbnM6IHJ1blByZURpc3BhdGNoLCBydW5EaXNwYXRjaCwgcnVuR3VhcmRzLCBydW5Vbml0UGhhc2UsIHJ1bkZpbmFsaXplLFxuICogcGx1cyBpbnRlcm5hbCBoZWxwZXJzIGdlbmVyYXRlTWlsZXN0b25lUmVwb3J0IGFuZCBjbG9zZW91dEFuZFN0b3AuXG4gKlxuICogSW1wb3J0cyBmcm9tOiBhdXRvL3R5cGVzLCBhdXRvL2RldGVjdC1zdHVjaywgYXV0by9ydW4tdW5pdCwgYXV0by9sb29wLWRlcHNcbiAqL1xuXG5pbXBvcnQgeyBpbXBvcnRFeHRlbnNpb25Nb2R1bGUsIHR5cGUgRXh0ZW5zaW9uQVBJLCB0eXBlIEV4dGVuc2lvbkNvbnRleHQgfSBmcm9tIFwiQGdzZC9waS1jb2RpbmctYWdlbnRcIjtcblxuaW1wb3J0IHR5cGUgeyBBdXRvU2Vzc2lvbiwgU2lkZWNhckl0ZW0gfSBmcm9tIFwiLi9zZXNzaW9uLmpzXCI7XG5pbXBvcnQgdHlwZSB7IExvb3BEZXBzIH0gZnJvbSBcIi4vbG9vcC1kZXBzLmpzXCI7XG5pbXBvcnQge1xuICBVU0VSX0RSSVZFTl9ERUVQX1VOSVRTLFxuICBpc0F3YWl0aW5nVXNlcklucHV0LFxuICB0eXBlIFBvc3RVbml0Q29udGV4dCxcbiAgdHlwZSBQcmVWZXJpZmljYXRpb25PcHRzLFxufSBmcm9tIFwiLi4vYXV0by1wb3N0LXVuaXQuanNcIjtcbmltcG9ydCB0eXBlIHsgUGhhc2UgfSBmcm9tIFwiLi4vdHlwZXMuanNcIjtcbmltcG9ydCB7XG4gIE1BWF9SRUNPVkVSWV9DSEFSUyxcbiAgQlVER0VUX1RIUkVTSE9MRFMsXG4gIE1BWF9GSU5BTElaRV9USU1FT1VUUyxcbiAgdHlwZSBQaGFzZVJlc3VsdCxcbiAgdHlwZSBJdGVyYXRpb25Db250ZXh0LFxuICB0eXBlIExvb3BTdGF0ZSxcbiAgdHlwZSBQcmVEaXNwYXRjaERhdGEsXG4gIHR5cGUgSXRlcmF0aW9uRGF0YSxcbn0gZnJvbSBcIi4vdHlwZXMuanNcIjtcbmltcG9ydCB7IGRldGVjdFN0dWNrIH0gZnJvbSBcIi4vZGV0ZWN0LXN0dWNrLmpzXCI7XG5pbXBvcnQgeyBydW5Vbml0IH0gZnJvbSBcIi4vcnVuLXVuaXQuanNcIjtcbmltcG9ydCB7IGRlYnVnTG9nIH0gZnJvbSBcIi4uL2RlYnVnLWxvZ2dlci5qc1wiO1xuaW1wb3J0IHsgcmVzb2x2ZVdvcmt0cmVlUHJvamVjdFJvb3QsIG5vcm1hbGl6ZVdvcmt0cmVlUGF0aEZvckNvbXBhcmUgfSBmcm9tIFwiLi4vd29ya3RyZWUtcm9vdC5qc1wiO1xuaW1wb3J0IHsgY2xhc3NpZnlQcm9qZWN0IH0gZnJvbSBcIi4uL2RldGVjdGlvbi5qc1wiO1xuaW1wb3J0IHsgTWVyZ2VDb25mbGljdEVycm9yIH0gZnJvbSBcIi4uL2dpdC1zZXJ2aWNlLmpzXCI7XG5pbXBvcnQgeyBzZXRDdXJyZW50UGhhc2UsIGNsZWFyQ3VycmVudFBoYXNlIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9nc2QtcGhhc2Utc3RhdGUuanNcIjtcbmltcG9ydCB7IHBhdXNlQXV0b0ZvclByb3ZpZGVyRXJyb3IgfSBmcm9tIFwiLi4vcHJvdmlkZXItZXJyb3ItcGF1c2UuanNcIjtcbmltcG9ydCB7IHJlc3VtZUF1dG9BZnRlclByb3ZpZGVyRGVsYXkgfSBmcm9tIFwiLi4vYm9vdHN0cmFwL3Byb3ZpZGVyLWVycm9yLXJlc3VtZS5qc1wiO1xuaW1wb3J0IHsgam9pbiwgYmFzZW5hbWUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBleGlzdHNTeW5jLCBjcFN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHtcbiAgbG9nV2FybmluZyxcbiAgbG9nRXJyb3IsXG4gIF9yZXNldExvZ3MsXG4gIGRyYWluTG9ncyxcbiAgZHJhaW5BbmRTdW1tYXJpemUsXG4gIGZvcm1hdEZvck5vdGlmaWNhdGlvbixcbiAgaGFzQW55SXNzdWVzLFxufSBmcm9tIFwiLi4vd29ya2Zsb3ctbG9nZ2VyLmpzXCI7XG5pbXBvcnQgeyBnc2RSb290IH0gZnJvbSBcIi4uL3BhdGhzLmpzXCI7XG5pbXBvcnQgeyBhdG9taWNXcml0ZVN5bmMgfSBmcm9tIFwiLi4vYXRvbWljLXdyaXRlLmpzXCI7XG5pbXBvcnQgeyB2ZXJpZnlFeHBlY3RlZEFydGlmYWN0LCBkaWFnbm9zZUV4cGVjdGVkQXJ0aWZhY3QsIGJ1aWxkTG9vcFJlbWVkaWF0aW9uU3RlcHMsIHJlZnJlc2hSZWNvdmVyeURiRm9yQXJ0aWZhY3QgfSBmcm9tIFwiLi4vYXV0by1yZWNvdmVyeS5qc1wiO1xuaW1wb3J0IHsgd3JpdGVVbml0UnVudGltZVJlY29yZCB9IGZyb20gXCIuLi91bml0LXJ1bnRpbWUuanNcIjtcbmltcG9ydCB7IHdpdGhUaW1lb3V0LCBGSU5BTElaRV9QUkVfVElNRU9VVF9NUywgRklOQUxJWkVfUE9TVF9USU1FT1VUX01TIH0gZnJvbSBcIi4vZmluYWxpemUtdGltZW91dC5qc1wiO1xuaW1wb3J0IHsgZ2V0RWxpZ2libGVTbGljZXMgfSBmcm9tIFwiLi4vc2xpY2UtcGFyYWxsZWwtZWxpZ2liaWxpdHkuanNcIjtcbmltcG9ydCB7IHN0YXJ0U2xpY2VQYXJhbGxlbCB9IGZyb20gXCIuLi9zbGljZS1wYXJhbGxlbC1vcmNoZXN0cmF0b3IuanNcIjtcbmltcG9ydCB7IGlzRGJBdmFpbGFibGUsIGdldE1pbGVzdG9uZVNsaWNlcyB9IGZyb20gXCIuLi9nc2QtZGIuanNcIjtcbmltcG9ydCB7IHJlY29uY2lsZUJlZm9yZVNwYXduIH0gZnJvbSBcIi4uL3N0YXRlLXJlY29uY2lsaWF0aW9uLmpzXCI7XG5pbXBvcnQgdHlwZSB7IE1pbmltYWxNb2RlbFJlZ2lzdHJ5IH0gZnJvbSBcIi4uL2NvbnRleHQtYnVkZ2V0LmpzXCI7XG5pbXBvcnQgdHlwZSB7IFBvc3RmbGlnaHRSZXN1bHQsIFByZWZsaWdodFJlc3VsdCB9IGZyb20gXCIuLi9jbGVhbi1yb290LXByZWZsaWdodC5qc1wiO1xuaW1wb3J0IHsgZW5zdXJlUGxhblYyR3JhcGgsIGlzRW1wdHlQbGFuVjJHcmFwaFJlc3VsdCwgaXNNaXNzaW5nRmluYWxpemVkQ29udGV4dFJlc3VsdCB9IGZyb20gXCIuLi91b2svcGxhbi12Mi5qc1wiO1xuaW1wb3J0IHsgcmVzb2x2ZVVva0ZsYWdzIH0gZnJvbSBcIi4uL3Vvay9mbGFncy5qc1wiO1xuaW1wb3J0IHsgVW9rR2F0ZVJ1bm5lciB9IGZyb20gXCIuLi91b2svZ2F0ZS1ydW5uZXIuanNcIjtcbmltcG9ydCB7IHJlc2V0RXZpZGVuY2UsIGxvYWRFdmlkZW5jZUZyb21EaXNrIH0gZnJvbSBcIi4uL3NhZmV0eS9ldmlkZW5jZS1jb2xsZWN0b3IuanNcIjtcbmltcG9ydCB7IHBhcnNlVW5pdElkIH0gZnJvbSBcIi4uL3VuaXQtaWQuanNcIjtcbmltcG9ydCB7IGNyZWF0ZUNoZWNrcG9pbnQsIGNsZWFudXBDaGVja3BvaW50LCByb2xsYmFja1RvQ2hlY2twb2ludCB9IGZyb20gXCIuLi9zYWZldHkvZ2l0LWNoZWNrcG9pbnQuanNcIjtcbmltcG9ydCB7IHJlc29sdmVTYWZldHlIYXJuZXNzQ29uZmlnIH0gZnJvbSBcIi4uL3NhZmV0eS9zYWZldHktaGFybmVzcy5qc1wiO1xuaW1wb3J0IHtcbiAgZ2V0V29ya2Zsb3dUcmFuc3BvcnRTdXBwb3J0RXJyb3IsXG4gIGdldFJlcXVpcmVkV29ya2Zsb3dUb29sc0ZvckF1dG9Vbml0LFxuICBzdXBwb3J0c1N0cnVjdHVyZWRRdWVzdGlvbnMsXG59IGZyb20gXCIuLi93b3JrZmxvdy1tY3AuanNcIjtcbmltcG9ydCB7IHJlc29sdmVNYW5pZmVzdCB9IGZyb20gXCIuLi91bml0LWNvbnRleHQtbWFuaWZlc3QuanNcIjtcbmltcG9ydCB7IGNyZWF0ZVdvcmt0cmVlU2FmZXR5TW9kdWxlLCB0eXBlIFdvcmt0cmVlU2FmZXR5UmVzdWx0IH0gZnJvbSBcIi4uL3dvcmt0cmVlLXNhZmV0eS5qc1wiO1xuaW1wb3J0IHsgaXNTdXNwaWNpb3VzR2hvc3RDb21wbGV0aW9uIH0gZnJvbSBcIi4uL2F1dG8tdW5pdC1jbG9zZW91dC5qc1wiO1xuaW1wb3J0IHsgZGVjaWRlVmVyaWZpY2F0aW9uUmV0cnksIHZlcmlmaWNhdGlvblJldHJ5S2V5IH0gZnJvbSBcIi4vdmVyaWZpY2F0aW9uLXJldHJ5LXBvbGljeS5qc1wiO1xuaW1wb3J0IHsgYnVpbGRQaGFzZUhhbmRvZmZPdXRjb21lLCBzZXRBdXRvT3V0Y29tZVdpZGdldCB9IGZyb20gXCIuLi9hdXRvLWRhc2hib2FyZC5qc1wiO1xuaW1wb3J0IHsgZ2V0Q29uc2VjdXRpdmVEaXNwYXRjaEJsb2NrZXIgfSBmcm9tIFwiLi4vZGlzcGF0Y2gtZ3VhcmQuanNcIjtcblxuLy8g4pSA4pSA4pSAIFBhdGggQ29tcGFyaXNvbiBIZWxwZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4vKiogQ29tcGFyZSB0d28gcGF0aHMgZm9yIHBoeXNpY2FsIGlkZW50aXR5LCB0b2xlcmF0aW5nIHRyYWlsaW5nIHNsYXNoZXMgYW5kIHN5bWxpbmtzLiAqL1xuZnVuY3Rpb24gaXNTYW1lUGF0aExvY2FsKGE6IHN0cmluZywgYjogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBub3JtYWxpemVXb3JrdHJlZVBhdGhGb3JDb21wYXJlKGEpID09PSBub3JtYWxpemVXb3JrdHJlZVBhdGhGb3JDb21wYXJlKGIpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBhcHBseVZlcmlmaWNhdGlvblJldHJ5UG9saWN5KFxuICBpYzogSXRlcmF0aW9uQ29udGV4dCxcbiAgdW5pdFR5cGU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgcGhhc2U6IFwiYXJ0aWZhY3QtdmVyaWZpY2F0aW9uLXJldHJ5XCIgfCBcInZlcmlmaWNhdGlvbi1yZXRyeVwiLFxuKTogUHJvbWlzZTxQaGFzZVJlc3VsdCB8IG51bGw+IHtcbiAgY29uc3QgeyBjdHgsIHBpLCBzLCBkZXBzIH0gPSBpYztcbiAgY29uc3QgcmV0cnlJbmZvID0gcy5wZW5kaW5nVmVyaWZpY2F0aW9uUmV0cnk7XG4gIGNvbnN0IGtleSA9IHVuaXRUeXBlICYmIHJldHJ5SW5mb1xuICAgID8gdmVyaWZpY2F0aW9uUmV0cnlLZXkodW5pdFR5cGUsIHJldHJ5SW5mby51bml0SWQpXG4gICAgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGRlY2lzaW9uID0gZGVjaWRlVmVyaWZpY2F0aW9uUmV0cnkoe1xuICAgIHVuaXRUeXBlLFxuICAgIHJldHJ5SW5mbyxcbiAgICBwcmV2aW91c0ZhaWx1cmVIYXNoOiBrZXkgPyBzLnZlcmlmaWNhdGlvblJldHJ5RmFpbHVyZUhhc2hlcy5nZXQoa2V5KSA6IHVuZGVmaW5lZCxcbiAgfSk7XG5cbiAgaWYgKGRlY2lzaW9uLmFjdGlvbiA9PT0gXCJwYXVzZVwiKSB7XG4gICAgcy5wZW5kaW5nVmVyaWZpY2F0aW9uUmV0cnkgPSBudWxsO1xuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgICAgcGhhc2U6IGAke3BoYXNlfS1wYXVzZWRgLFxuICAgICAgcmVhc29uOiBkZWNpc2lvbi5yZWFzb24sXG4gICAgICB1bml0VHlwZSxcbiAgICAgIHVuaXRJZDogcmV0cnlJbmZvPy51bml0SWQsXG4gICAgICBmYWlsdXJlSGFzaDogZGVjaXNpb24uZmFpbHVyZUhhc2gsXG4gICAgfSk7XG4gICAgY29uc3QgcGF1c2VNZXNzYWdlID0gZGVjaXNpb24ucmVhc29uID09PSBcImR1cGxpY2F0ZS1mYWlsdXJlLWNvbnRleHRcIlxuICAgICAgPyBgVmVyaWZpY2F0aW9uIHJldHJ5IGZvciAke3VuaXRUeXBlID8/IFwidW5pdFwifSAke3JldHJ5SW5mbz8udW5pdElkID8/IFwidW5rbm93blwifSBwcm9kdWNlZCB0aGUgc2FtZSBmYWlsdXJlIGNvbnRleHQuIFBhdXNpbmcgYXV0by1tb2RlIGluc3RlYWQgb2YgcmUtZGlzcGF0Y2hpbmcuYFxuICAgICAgOiBcIlZlcmlmaWNhdGlvbiByZXRyeSByZXF1ZXN0ZWQgd2l0aG91dCByZXRyeSBjb250ZXh0LiBQYXVzaW5nIGF1dG8tbW9kZSBpbnN0ZWFkIG9mIHJlLWRpc3BhdGNoaW5nLlwiO1xuICAgIGN0eC51aS5ub3RpZnkocGF1c2VNZXNzYWdlLCBcIndhcm5pbmdcIik7XG4gICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSwgeyBtZXNzYWdlOiBwYXVzZU1lc3NhZ2UsIGNhdGVnb3J5OiBcInVua25vd25cIiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBkZWNpc2lvbi5yZWFzb24gfTtcbiAgfVxuXG5cbiAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgcGhhc2U6IGAke3BoYXNlfS1iYWNrb2ZmYCxcbiAgICBpdGVyYXRpb246IGljLml0ZXJhdGlvbixcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQ6IHJldHJ5SW5mbz8udW5pdElkLFxuICAgIGF0dGVtcHQ6IHJldHJ5SW5mbz8uYXR0ZW1wdCxcbiAgICBkZWxheU1zOiBkZWNpc2lvbi5kZWxheU1zLFxuICAgIGJhc2VEZWxheU1zOiBkZWNpc2lvbi5iYXNlRGVsYXlNcyxcbiAgICBmYWlsdXJlSGFzaDogZGVjaXNpb24uZmFpbHVyZUhhc2gsXG4gIH0pO1xuICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBkZWNpc2lvbi5kZWxheU1zKSk7XG4gIHJldHVybiBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2hvdWxkRGVncmFkZUVtcHR5V29ya3RyZWVUb1Byb2plY3RSb290KFxuICB3b3JrdHJlZUNsYXNzaWZpY2F0aW9uOiBSZXR1cm5UeXBlPHR5cGVvZiBjbGFzc2lmeVByb2plY3Q+LFxuICBwcm9qZWN0Um9vdENsYXNzaWZpY2F0aW9uOiBSZXR1cm5UeXBlPHR5cGVvZiBjbGFzc2lmeVByb2plY3Q+LFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgd29ya3RyZWVDbGFzc2lmaWNhdGlvbi5raW5kID09PSBcImdyZWVuZmllbGRcIiAmJlxuICAgIHByb2plY3RSb290Q2xhc3NpZmljYXRpb24ua2luZCAhPT0gXCJncmVlbmZpZWxkXCIgJiZcbiAgICBwcm9qZWN0Um9vdENsYXNzaWZpY2F0aW9uLmtpbmQgIT09IFwiaW52YWxpZC1yZXBvXCJcbiAgKTtcbn1cblxuZnVuY3Rpb24gdW5pdFdyaXRlc1NvdXJjZSh1bml0VHlwZTogc3RyaW5nKTogYm9vbGVhbiB8IG51bGwge1xuICBjb25zdCBtYW5pZmVzdCA9IHJlc29sdmVNYW5pZmVzdCh1bml0VHlwZSk7XG4gIGlmICghbWFuaWZlc3QpIHJldHVybiBudWxsO1xuICByZXR1cm4gbWFuaWZlc3QudG9vbHMubW9kZSA9PT0gXCJhbGxcIiB8fCBtYW5pZmVzdC50b29scy5tb2RlID09PSBcImRvY3NcIjtcbn1cblxuZnVuY3Rpb24gZm9ybWF0V29ya3RyZWVTYWZldHlGYWlsdXJlKHJlc3VsdDogRXh0cmFjdDxXb3JrdHJlZVNhZmV0eVJlc3VsdCwgeyBvazogZmFsc2UgfT4pOiBzdHJpbmcge1xuICByZXR1cm4gYFdvcmt0cmVlIFNhZmV0eSBmYWlsZWQgKCR7cmVzdWx0LmtpbmR9KTogJHtyZXN1bHQucmVhc29ufSAke3Jlc3VsdC5yZW1lZGlhdGlvbn1gO1xufVxuXG5mdW5jdGlvbiBmb3JtYXRXb3JrdHJlZVNhZmV0eVN0b3BSZWFzb24ocmVzdWx0OiBFeHRyYWN0PFdvcmt0cmVlU2FmZXR5UmVzdWx0LCB7IG9rOiBmYWxzZSB9Pik6IHN0cmluZyB7XG4gIGlmIChyZXN1bHQua2luZCA9PT0gXCJlbXB0eS13b3JrdHJlZS13aXRoLXByb2plY3QtY29udGVudFwiKSB7XG4gICAgcmV0dXJuIGBXb3JrdHJlZSBTYWZldHkgZmFpbGVkICgke3Jlc3VsdC5raW5kfSkuIFJ1biAvZ3NkIGRvY3RvciBmaXgsIHRoZW4gL2dzZCBhdXRvLmA7XG4gIH1cbiAgcmV0dXJuIGBXb3JrdHJlZSBTYWZldHkgZmFpbGVkICgke3Jlc3VsdC5raW5kfSkuYDtcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZUVtcHR5V29ya3RyZWVXaXRoUHJvamVjdENvbnRlbnQoXG4gIHVuaXRSb290OiBzdHJpbmcsXG4gIHByb2plY3RSb290OiBzdHJpbmcsXG4pOiBib29sZWFuIHtcbiAgaWYgKGlzU2FtZVBhdGhMb2NhbCh1bml0Um9vdCwgcHJvamVjdFJvb3QpKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IHdvcmt0cmVlQ2xhc3NpZmljYXRpb24gPSBjbGFzc2lmeVByb2plY3QodW5pdFJvb3QpO1xuICBpZiAod29ya3RyZWVDbGFzc2lmaWNhdGlvbi5raW5kICE9PSBcImdyZWVuZmllbGRcIikgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBwcm9qZWN0Um9vdENsYXNzaWZpY2F0aW9uID0gY2xhc3NpZnlQcm9qZWN0KHByb2plY3RSb290KTtcbiAgcmV0dXJuIHNob3VsZERlZ3JhZGVFbXB0eVdvcmt0cmVlVG9Qcm9qZWN0Um9vdCh3b3JrdHJlZUNsYXNzaWZpY2F0aW9uLCBwcm9qZWN0Um9vdENsYXNzaWZpY2F0aW9uKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmFsaWRhdGVTb3VyY2VXcml0ZVdvcmt0cmVlU2FmZXR5KFxuICBpYzogSXRlcmF0aW9uQ29udGV4dCxcbiAgdW5pdFR5cGU6IHN0cmluZyxcbiAgdW5pdElkOiBzdHJpbmcsXG4gIG1pbGVzdG9uZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHBoYXNlOiBzdHJpbmcsXG4pOiBQcm9taXNlPHsgYWN0aW9uOiBcImJyZWFrXCI7IHJlYXNvbjogc3RyaW5nIH0gfCBudWxsPiB7XG4gIGNvbnN0IHsgY3R4LCBwaSwgcywgZGVwcyB9ID0gaWM7XG4gIGlmICghcy5iYXNlUGF0aCkgcmV0dXJuIG51bGw7XG5cbiAgLy8gQ3VzdG9tIGVuZ2luZSB3b3JrZmxvd3MgKGdyYXBoLWRyaXZlbiwgcmVnaXN0ZXJlZCB2aWEgcnVuIGRpcnMpIGRlZmluZVxuICAvLyB0aGVpciBvd24gc3RlcCBpZHMgdGhhdCBhcmUgbm90IGluIHRoZSBHU0QgVW5pdENvbnRleHRNYW5pZmVzdC4gRG9uJ3RcbiAgLy8gZmFpbCBjbG9zZWQgZm9yIHRob3NlIOKAlCB0aGUgY3VzdG9tIGVuZ2luZSBvd25zIGl0cyBvd24gZGlzcGF0Y2hcbiAgLy8gY29udHJhY3QuIFRoZSBmYWlsLWNsb3NlZCBzYWZldHkgY2hlY2sgYXBwbGllcyBvbmx5IHRvIGJ1aWx0LWluIEdTRFxuICAvLyB1bml0cyB3aG9zZSBUb29sIENvbnRyYWN0IGlzIHJlZ2lzdGVyZWQgaW4gdGhlIG1hbmlmZXN0LiBVc2UgYSB0cnV0aHlcbiAgLy8gY2hlY2sgc28gdW5kZWZpbmVkICh0ZXN0IHNlc3Npb25zIHRoYXQgbmV2ZXIgc2V0IHRoZSBmaWVsZCkgcm91dGVzXG4gIC8vIHRocm91Z2ggdGhlIHNhZmV0eSBjaGVjaywgbWF0Y2hpbmcgdGhlIHJlZ3Jlc3Npb24gdGVzdCBjb250cmFjdC5cbiAgaWYgKHMuYWN0aXZlRW5naW5lSWQpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IHdyaXRlc1NvdXJjZSA9IHVuaXRXcml0ZXNTb3VyY2UodW5pdFR5cGUpO1xuICBpZiAod3JpdGVzU291cmNlID09PSBudWxsKSB7XG4gICAgY29uc3QgbXNnID0gYFdvcmt0cmVlIFNhZmV0eSBmYWlsZWQgKG1pc3NpbmctdG9vbC1jb250cmFjdCk6IG1pc3NpbmcgVG9vbCBDb250cmFjdCBmb3IgJHt1bml0VHlwZX0uIEFkZCBhIFVuaXRDb250ZXh0TWFuaWZlc3QgZW50cnkgYmVmb3JlIGRpc3BhdGNoaW5nIHRoaXMgVW5pdC5gO1xuICAgIGRlYnVnTG9nKFwid29ya3RyZWVTYWZldHlcIiwge1xuICAgICAgcGhhc2UsXG4gICAgICB1bml0VHlwZSxcbiAgICAgIHVuaXRJZCxcbiAgICAgIG1pbGVzdG9uZUlkLFxuICAgICAgcmVzdWx0OiB7IG9rOiBmYWxzZSwga2luZDogXCJtaXNzaW5nLXRvb2wtY29udHJhY3RcIiwgcmVhc29uOiBtc2cgfSxcbiAgICAgIGJhc2VQYXRoOiBzLmJhc2VQYXRoLFxuICAgIH0pO1xuICAgIGN0eC51aS5ub3RpZnkobXNnLCBcImVycm9yXCIpO1xuICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgbXNnKTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcIm1pc3NpbmctdG9vbC1jb250cmFjdFwiIH07XG4gIH1cbiAgaWYgKCF3cml0ZXNTb3VyY2UpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IHByb2plY3RSb290ID0gcy5jYW5vbmljYWxQcm9qZWN0Um9vdCA/PyByZXNvbHZlV29ya3RyZWVQcm9qZWN0Um9vdChzLmJhc2VQYXRoLCBzLm9yaWdpbmFsQmFzZVBhdGgpO1xuICBpZiAoZGVwcy5nZXRJc29sYXRpb25Nb2RlKHByb2plY3RSb290KSAhPT0gXCJ3b3JrdHJlZVwiKSByZXR1cm4gbnVsbDtcblxuICBjb25zdCBzYWZldHkgPSBjcmVhdGVXb3JrdHJlZVNhZmV0eU1vZHVsZSgpO1xuICBjb25zdCByZXN1bHQgPSBzYWZldHkudmFsaWRhdGVVbml0Um9vdCh7XG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICAgIHdyaXRlU2NvcGU6IFwic291cmNlLXdyaXRpbmdcIixcbiAgICBwcm9qZWN0Um9vdCxcbiAgICB1bml0Um9vdDogcy5iYXNlUGF0aCxcbiAgICBtaWxlc3RvbmVJZCxcbiAgICBleHBlY3RlZEJyYW5jaDogbWlsZXN0b25lSWQgPyBkZXBzLmF1dG9Xb3JrdHJlZUJyYW5jaChtaWxlc3RvbmVJZCkgOiBudWxsLFxuICAgIGVtcHR5V29ya3RyZWVXaXRoUHJvamVjdENvbnRlbnQ6IHJlc29sdmVFbXB0eVdvcmt0cmVlV2l0aFByb2plY3RDb250ZW50KHMuYmFzZVBhdGgsIHByb2plY3RSb290KSxcbiAgICBsZWFzZTogcy53b3JrZXJJZFxuICAgICAgPyB7XG4gICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgaGVsZDogcy5jdXJyZW50TWlsZXN0b25lSWQgPT09IG1pbGVzdG9uZUlkICYmIHMubWlsZXN0b25lTGVhc2VUb2tlbiAhPT0gbnVsbCxcbiAgICAgICAgICBvd25lcjogcy53b3JrZXJJZCxcbiAgICAgICAgfVxuICAgICAgOiB1bmRlZmluZWQsXG4gIH0pO1xuXG4gIGlmIChyZXN1bHQub2spIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IG1zZyA9IGZvcm1hdFdvcmt0cmVlU2FmZXR5RmFpbHVyZShyZXN1bHQpO1xuICBkZWJ1Z0xvZyhcIndvcmt0cmVlU2FmZXR5XCIsIHtcbiAgICBwaGFzZSxcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgbWlsZXN0b25lSWQsXG4gICAgcmVzdWx0LFxuICAgIGJhc2VQYXRoOiBzLmJhc2VQYXRoLFxuICAgIHByb2plY3RSb290LFxuICB9KTtcbiAgY3R4LnVpLm5vdGlmeShtc2csIFwiZXJyb3JcIik7XG4gIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgZm9ybWF0V29ya3RyZWVTYWZldHlTdG9wUmVhc29uKHJlc3VsdCkpO1xuICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiByZXN1bHQua2luZCB9O1xufVxuXG4vLyDilIDilIDilIAgU2Vzc2lvbiB0aW1lb3V0IGF1dG8tcmVzdW1lIHN0YXRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5sZXQgY29uc2VjdXRpdmVTZXNzaW9uVGltZW91dHMgPSAwO1xuY29uc3QgTUFYX1NFU1NJT05fVElNRU9VVF9BVVRPX1JFU1VNRVMgPSAzO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRTZXNzaW9uVGltZW91dFN0YXRlKCk6IHZvaWQge1xuICBjb25zZWN1dGl2ZVNlc3Npb25UaW1lb3V0cyA9IDA7XG59XG5cbi8vIOKUgOKUgOKUgCBnZW5lcmF0ZU1pbGVzdG9uZVJlcG9ydCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBiYXNlIHBhdGggZm9yIG1pbGVzdG9uZSByZXBvcnRzLlxuICogUHJlZmVycyBvcmlnaW5hbEJhc2VQYXRoIChwcm9qZWN0IHJvb3QpIG92ZXIgYmFzZVBhdGggKHdoaWNoIG1heSBiZSBhIHdvcmt0cmVlKS5cbiAqIEV4cG9ydGVkIGZvciB0ZXN0aW5nIGFzIF9yZXNvbHZlUmVwb3J0QmFzZVBhdGguXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfcmVzb2x2ZVJlcG9ydEJhc2VQYXRoKHM6IFBpY2s8QXV0b1Nlc3Npb24sIFwib3JpZ2luYWxCYXNlUGF0aFwiIHwgXCJiYXNlUGF0aFwiPik6IHN0cmluZyB7XG4gIHJldHVybiByZXNvbHZlV29ya3RyZWVQcm9qZWN0Um9vdChzLmJhc2VQYXRoLCBzLm9yaWdpbmFsQmFzZVBhdGgpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGF1dGhvcml0YXRpdmUgcHJvamVjdCBiYXNlIGZvciBkaXNwYXRjaCBndWFyZHMuXG4gKiBQcmlvci1taWxlc3RvbmUgY29tcGxldGlvbiBsaXZlcyBhdCB0aGUgcHJvamVjdCByb290LCBldmVuIHdoZW4gdGhlIGFjdGl2ZVxuICogdW5pdCBpcyBydW5uaW5nIGluc2lkZSBhbiBhdXRvIHdvcmt0cmVlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gX3Jlc29sdmVEaXNwYXRjaEd1YXJkQmFzZVBhdGgoXG4gIHM6IFBpY2s8QXV0b1Nlc3Npb24sIFwib3JpZ2luYWxCYXNlUGF0aFwiIHwgXCJiYXNlUGF0aFwiPixcbik6IHN0cmluZyB7XG4gIHJldHVybiByZXNvbHZlV29ya3RyZWVQcm9qZWN0Um9vdChzLmJhc2VQYXRoLCBzLm9yaWdpbmFsQmFzZVBhdGgpO1xufVxuXG5jb25zdCBQTEFOX1YyX0dBVEVfUEhBU0VTOiBSZWFkb25seVNldDxQaGFzZT4gPSBuZXcgU2V0KFtcbiAgXCJleGVjdXRpbmdcIixcbiAgXCJzdW1tYXJpemluZ1wiLFxuICBcInZhbGlkYXRpbmctbWlsZXN0b25lXCIsXG4gIFwiY29tcGxldGluZy1taWxlc3RvbmVcIixcbl0pO1xuXG5leHBvcnQgZnVuY3Rpb24gc2hvdWxkUnVuUGxhblYyR2F0ZShwaGFzZTogUGhhc2UpOiBib29sZWFuIHtcbiAgcmV0dXJuIFBMQU5fVjJfR0FURV9QSEFTRVMuaGFzKHBoYXNlKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIF9zaG91bGRQcm9jZWVkV2l0aEludmFsaWRSZXBvQ2xhc3NpZmljYXRpb25Gb3JUZXN0KFxuICByZWFzb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgaGFzR2l0OiBib29sZWFuLFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiByZWFzb24gPT09IFwibWlzc2luZyAuZ2l0XCIgJiYgaGFzR2l0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gX3Jlc29sdmVDdXJyZW50VW5pdFN0YXJ0ZWRBdEZvclRlc3QoXG4gIGN1cnJlbnRVbml0OiB7IHN0YXJ0ZWRBdDogbnVtYmVyIH0gfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIGN1cnJlbnRVbml0Py5zdGFydGVkQXQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgYW5kIHdyaXRlIGFuIEhUTUwgbWlsZXN0b25lIHJlcG9ydCBzbmFwc2hvdC5cbiAqIEV4dHJhY3RlZCBmcm9tIHRoZSBtaWxlc3RvbmUtdHJhbnNpdGlvbiBibG9jayBpbiBhdXRvTG9vcC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVNaWxlc3RvbmVSZXBvcnQoXG4gIHM6IEF1dG9TZXNzaW9uLFxuICBjdHg6IEV4dGVuc2lvbkNvbnRleHQsXG4gIG1pbGVzdG9uZUlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBsb2FkVmlzdWFsaXplckRhdGEgfSA9IGF3YWl0IGltcG9ydEV4dGVuc2lvbk1vZHVsZTx0eXBlb2YgaW1wb3J0KFwiLi4vdmlzdWFsaXplci1kYXRhLmpzXCIpPihpbXBvcnQubWV0YS51cmwsIFwiLi4vdmlzdWFsaXplci1kYXRhLmpzXCIpO1xuICBjb25zdCB7IGdlbmVyYXRlSHRtbFJlcG9ydCB9ID0gYXdhaXQgaW1wb3J0RXh0ZW5zaW9uTW9kdWxlPHR5cGVvZiBpbXBvcnQoXCIuLi9leHBvcnQtaHRtbC5qc1wiKT4oaW1wb3J0Lm1ldGEudXJsLCBcIi4uL2V4cG9ydC1odG1sLmpzXCIpO1xuICBjb25zdCB7IHdyaXRlUmVwb3J0U25hcHNob3QgfSA9IGF3YWl0IGltcG9ydEV4dGVuc2lvbk1vZHVsZTx0eXBlb2YgaW1wb3J0KFwiLi4vcmVwb3J0cy5qc1wiKT4oaW1wb3J0Lm1ldGEudXJsLCBcIi4uL3JlcG9ydHMuanNcIik7XG4gIGNvbnN0IHsgYmFzZW5hbWUgfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6cGF0aFwiKTtcblxuICBjb25zdCByZXBvcnRCYXNlUGF0aCA9IF9yZXNvbHZlUmVwb3J0QmFzZVBhdGgocyk7XG5cbiAgY29uc3Qgc25hcERhdGEgPSBhd2FpdCBsb2FkVmlzdWFsaXplckRhdGEocmVwb3J0QmFzZVBhdGgpO1xuICBjb25zdCBjb21wbGV0ZWRNcyA9IHNuYXBEYXRhLm1pbGVzdG9uZXMuZmluZChcbiAgICAobTogeyBpZDogc3RyaW5nIH0pID0+IG0uaWQgPT09IG1pbGVzdG9uZUlkLFxuICApO1xuICBjb25zdCBtc1RpdGxlID0gY29tcGxldGVkTXM/LnRpdGxlID8/IG1pbGVzdG9uZUlkO1xuICBjb25zdCBnc2RWZXJzaW9uID0gcHJvY2Vzcy5lbnYuR1NEX1ZFUlNJT04gPz8gXCIwLjAuMFwiO1xuICBjb25zdCBwcm9qTmFtZSA9IGJhc2VuYW1lKHJlcG9ydEJhc2VQYXRoKTtcbiAgY29uc3QgZG9uZVNsaWNlcyA9IHNuYXBEYXRhLm1pbGVzdG9uZXMucmVkdWNlKFxuICAgIChhY2M6IG51bWJlciwgbTogeyBzbGljZXM6IHsgZG9uZTogYm9vbGVhbiB9W10gfSkgPT5cbiAgICAgIGFjYyArIG0uc2xpY2VzLmZpbHRlcigoc2w6IHsgZG9uZTogYm9vbGVhbiB9KSA9PiBzbC5kb25lKS5sZW5ndGgsXG4gICAgMCxcbiAgKTtcbiAgY29uc3QgdG90YWxTbGljZXMgPSBzbmFwRGF0YS5taWxlc3RvbmVzLnJlZHVjZShcbiAgICAoYWNjOiBudW1iZXIsIG06IHsgc2xpY2VzOiB1bmtub3duW10gfSkgPT4gYWNjICsgbS5zbGljZXMubGVuZ3RoLFxuICAgIDAsXG4gICk7XG4gIGNvbnN0IG91dFBhdGggPSB3cml0ZVJlcG9ydFNuYXBzaG90KHtcbiAgICBiYXNlUGF0aDogcmVwb3J0QmFzZVBhdGgsXG4gICAgaHRtbDogZ2VuZXJhdGVIdG1sUmVwb3J0KHNuYXBEYXRhLCB7XG4gICAgICBwcm9qZWN0TmFtZTogcHJvak5hbWUsXG4gICAgICBwcm9qZWN0UGF0aDogcmVwb3J0QmFzZVBhdGgsXG4gICAgICBnc2RWZXJzaW9uLFxuICAgICAgbWlsZXN0b25lSWQsXG4gICAgICBpbmRleFJlbFBhdGg6IFwiaW5kZXguaHRtbFwiLFxuICAgIH0pLFxuICAgIG1pbGVzdG9uZUlkLFxuICAgIG1pbGVzdG9uZVRpdGxlOiBtc1RpdGxlLFxuICAgIGtpbmQ6IFwibWlsZXN0b25lXCIsXG4gICAgcHJvamVjdE5hbWU6IHByb2pOYW1lLFxuICAgIHByb2plY3RQYXRoOiByZXBvcnRCYXNlUGF0aCxcbiAgICBnc2RWZXJzaW9uLFxuICAgIHRvdGFsQ29zdDogc25hcERhdGEudG90YWxzPy5jb3N0ID8/IDAsXG4gICAgdG90YWxUb2tlbnM6IHNuYXBEYXRhLnRvdGFscz8udG9rZW5zLnRvdGFsID8/IDAsXG4gICAgdG90YWxEdXJhdGlvbjogc25hcERhdGEudG90YWxzPy5kdXJhdGlvbiA/PyAwLFxuICAgIGRvbmVTbGljZXMsXG4gICAgdG90YWxTbGljZXMsXG4gICAgZG9uZU1pbGVzdG9uZXM6IHNuYXBEYXRhLm1pbGVzdG9uZXMuZmlsdGVyKFxuICAgICAgKG06IHsgc3RhdHVzOiBzdHJpbmcgfSkgPT4gbS5zdGF0dXMgPT09IFwiY29tcGxldGVcIixcbiAgICApLmxlbmd0aCxcbiAgICB0b3RhbE1pbGVzdG9uZXM6IHNuYXBEYXRhLm1pbGVzdG9uZXMubGVuZ3RoLFxuICAgIHBoYXNlOiBzbmFwRGF0YS5waGFzZSxcbiAgfSk7XG4gIGN0eC51aS5ub3RpZnkoXG4gICAgYFJlcG9ydCBzYXZlZDogLmdzZC9yZXBvcnRzLyR7YmFzZW5hbWUob3V0UGF0aCl9IOKAlCBvcGVuIGluZGV4Lmh0bWwgdG8gYnJvd3NlIHByb2dyZXNzaW9uLmAsXG4gICAgXCJpbmZvXCIsXG4gICk7XG59XG5cbi8vIOKUgOKUgOKUgCBjbG9zZW91dEFuZFN0b3Ag4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogSWYgYSB1bml0IGlzIGluLWZsaWdodCwgY2xvc2UgaXQgb3V0LCB0aGVuIHN0b3AgYXV0by1tb2RlLlxuICogRXh0cmFjdGVkIGZyb20gfjQgaWRlbnRpY2FsIGlmLWNsb3Nlb3V0LXRoZW4tc3RvcCBzZXF1ZW5jZXMgaW4gYXV0b0xvb3AuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNsb3Nlb3V0QW5kU3RvcChcbiAgY3R4OiBFeHRlbnNpb25Db250ZXh0LFxuICBwaTogRXh0ZW5zaW9uQVBJLFxuICBzOiBBdXRvU2Vzc2lvbixcbiAgZGVwczogTG9vcERlcHMsXG4gIHJlYXNvbjogc3RyaW5nLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChzLmN1cnJlbnRVbml0KSB7XG4gICAgYXdhaXQgZGVwcy5jbG9zZW91dFVuaXQoXG4gICAgICBjdHgsXG4gICAgICBzLmJhc2VQYXRoLFxuICAgICAgcy5jdXJyZW50VW5pdC50eXBlLFxuICAgICAgcy5jdXJyZW50VW5pdC5pZCxcbiAgICAgIHMuY3VycmVudFVuaXQuc3RhcnRlZEF0LFxuICAgICAgZGVwcy5idWlsZFNuYXBzaG90T3B0cyhzLmN1cnJlbnRVbml0LnR5cGUsIHMuY3VycmVudFVuaXQuaWQpLFxuICAgICk7XG4gICAgcy5jdXJyZW50VW5pdCA9IG51bGw7XG4gIH1cbiAgYXdhaXQgZGVwcy5zdG9wQXV0byhjdHgsIHBpLCByZWFzb24pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzdG9wT25Qb3N0ZmxpZ2h0UmVjb3ZlcnlOZWVkZWQoXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICByZXN1bHQ6IFBvc3RmbGlnaHRSZXN1bHQsXG4gIG1pbGVzdG9uZUlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPHsgYWN0aW9uOiBcImJyZWFrXCI7IHJlYXNvbjogc3RyaW5nIH0gfCBudWxsPiB7XG4gIGlmICghcmVzdWx0Lm5lZWRzTWFudWFsUmVjb3ZlcnkpIHJldHVybiBudWxsO1xuICBjb25zdCB7IGN0eCwgcGksIGRlcHMgfSA9IGljO1xuICBjb25zdCByZWFzb24gPSBgUG9zdC1tZXJnZSBzdGFzaCByZXN0b3JlIGZhaWxlZCBmb3IgbWlsZXN0b25lICR7bWlsZXN0b25lSWR9YDtcbiAgY3R4LnVpLm5vdGlmeShcbiAgICBgJHtyZWFzb259LiBSZXNvbHZlIHRoZSB3b3JraW5nIHRyZWUgYmVmb3JlIHJlc3VtaW5nIGF1dG8tbW9kZS4gJHtyZXN1bHQubWVzc2FnZX1gLFxuICAgIFwiZXJyb3JcIixcbiAgKTtcbiAgYXdhaXQgZGVwcy5zdG9wQXV0byhjdHgsIHBpLCByZWFzb24pO1xuICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInBvc3RmbGlnaHQtc3Rhc2gtcmVzdG9yZS1mYWlsZWRcIiB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiByZXN0b3JlUHJlZmxpZ2h0U3Rhc2hPclN0b3AoXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICBwcmVmbGlnaHQ6IFByZWZsaWdodFJlc3VsdCxcbiAgbWlsZXN0b25lSWQ6IHN0cmluZyxcbik6IFByb21pc2U8eyBhY3Rpb246IFwiYnJlYWtcIjsgcmVhc29uOiBzdHJpbmcgfSB8IG51bGw+IHtcbiAgaWYgKCFwcmVmbGlnaHQuc3Rhc2hQdXNoZWQpIHJldHVybiBudWxsO1xuICBjb25zdCB7IGN0eCwgcywgZGVwcyB9ID0gaWM7XG4gIGNvbnN0IHJlc3VsdCA9IGRlcHMucG9zdGZsaWdodFBvcFN0YXNoKFxuICAgIHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoLFxuICAgIG1pbGVzdG9uZUlkLFxuICAgIHByZWZsaWdodC5zdGFzaE1hcmtlcixcbiAgICBjdHgudWkubm90aWZ5LmJpbmQoY3R4LnVpKSxcbiAgKTtcbiAgcmV0dXJuIHN0b3BPblBvc3RmbGlnaHRSZWNvdmVyeU5lZWRlZChpYywgcmVzdWx0LCBtaWxlc3RvbmVJZCk7XG59XG5cbi8qKlxuICogUnVuIGEgbWlsZXN0b25lIG1lcmdlIHN1cnJvdW5kZWQgYnkgcHJlZmxpZ2h0IHN0YXNoICsgYWx3YXlzLW9uIHBvc3RmbGlnaHRcbiAqIHBvcC4gVGhlIHByZXZpb3VzIGNvZGUgcG9wcGVkIHRoZSBzdGFzaCBvbmx5IGFmdGVyIGEgc3VjY2Vzc2Z1bCBtZXJnZSwgd2hpY2hcbiAqIGxlYWtlZCBgZ3NkLXByZWZsaWdodC1zdGFzaDpNMDB4OipgIGVudHJpZXMgd2hlbmV2ZXIgYG1lcmdlQW5kRXhpdGAgdGhyZXcg4oCUXG4gKiBsZWF2aW5nIHRoZSB1c2VyJ3MgcHJlLW1lcmdlIHdvcmtpbmcgdHJlZSBzaWxlbnRseSBzdGFzaGVkIGF3YXkgYWZ0ZXIgYVxuICogbWVyZ2UtY29uZmxpY3Qgb3Igb3RoZXIgbWVyZ2UgZXJyb3IuIFRoaXMgaGVscGVyIHJlc3RvcmVzIHRoZSBzdGFzaCBvblxuICogZXZlcnkgZXhpdCBwYXRoLCB0aGVuIHN1cmZhY2VzIHRoZSBtZXJnZSBvciBzdGFzaCBmYWlsdXJlIChpbiBwcmlvcml0eVxuICogb3JkZXIpIGFzIHRoZSBsb29wJ3Mgc3RvcCByZWFzb24uXG4gKlxuICogUmV0dXJucyBhIGBicmVha2AgYWN0aW9uIHdoZW4gYXV0by1tb2RlIG11c3Qgc3RvcCwgb3IgYG51bGxgIHdoZW4gdGhlIG1lcmdlXG4gKiBzdWNjZWVkZWQgYW5kIHRoZSBzdGFzaCAoaWYgYW55KSB3YXMgcmVzdG9yZWQgY2xlYW5seS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIF9ydW5NaWxlc3RvbmVNZXJnZVdpdGhTdGFzaFJlc3RvcmUoXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICBtaWxlc3RvbmVJZDogc3RyaW5nLFxuKTogUHJvbWlzZTx7IGFjdGlvbjogXCJicmVha1wiOyByZWFzb246IHN0cmluZyB9IHwgbnVsbD4ge1xuICBjb25zdCB7IGN0eCwgcGksIHMsIGRlcHMgfSA9IGljO1xuXG4gIGNvbnN0IHByZWZsaWdodCA9IGRlcHMucHJlZmxpZ2h0Q2xlYW5Sb290KFxuICAgIHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoLFxuICAgIG1pbGVzdG9uZUlkLFxuICAgIGN0eC51aS5ub3RpZnkuYmluZChjdHgudWkpLFxuICApO1xuXG4gIGxldCBtZXJnZUVycm9yOiB1bmtub3duID0gbnVsbDtcbiAgY29uc3QgZXhpdFJlc3VsdCA9IGRlcHMubGlmZWN5Y2xlLmV4aXRNaWxlc3RvbmUoXG4gICAgbWlsZXN0b25lSWQsXG4gICAgeyBtZXJnZTogdHJ1ZSB9LFxuICAgIGN0eC51aSxcbiAgKTtcbiAgaWYgKGV4aXRSZXN1bHQub2spIHtcbiAgICBzLm1pbGVzdG9uZU1lcmdlZEluUGhhc2VzID0gdHJ1ZTtcbiAgfSBlbHNlIHtcbiAgICBtZXJnZUVycm9yID0gZXhpdFJlc3VsdC5jYXVzZSA/PyBuZXcgRXJyb3IoYGV4aXQgJHtleGl0UmVzdWx0LnJlYXNvbn1gKTtcbiAgfVxuXG4gIC8vIEFsd2F5cyBhdHRlbXB0IHRvIHJlc3RvcmUgdGhlIHN0YXNoZWQgd29ya2luZyB0cmVlLCBldmVuIG9uIG1lcmdlIGVycm9yLlxuICAvLyBwb3N0ZmxpZ2h0UG9wU3Rhc2ggaXRzZWxmIGRvZXMgbm90IHRocm93OyBmYWlsdXJlcyBzdXJmYWNlIHZpYSB0aGVcbiAgLy8gUG9zdGZsaWdodFJlc3VsdC5uZWVkc01hbnVhbFJlY292ZXJ5IGZsYWcuXG4gIGxldCBzdGFzaFJlc3VsdDogUG9zdGZsaWdodFJlc3VsdCB8IG51bGwgPSBudWxsO1xuICBpZiAocHJlZmxpZ2h0LnN0YXNoUHVzaGVkKSB7XG4gICAgc3Rhc2hSZXN1bHQgPSBkZXBzLnBvc3RmbGlnaHRQb3BTdGFzaChcbiAgICAgIHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoLFxuICAgICAgbWlsZXN0b25lSWQsXG4gICAgICBwcmVmbGlnaHQuc3Rhc2hNYXJrZXIsXG4gICAgICBjdHgudWkubm90aWZ5LmJpbmQoY3R4LnVpKSxcbiAgICApO1xuICB9XG5cbiAgLy8gTWVyZ2UgZmFpbHVyZSB0YWtlcyBwcmlvcml0eSBvdmVyIHN0YXNoIHJlY292ZXJ5IOKAlCB0aGUgbWVyZ2UgaXMgdGhlXG4gIC8vIGF1dGhvcml0YXRpdmUgZ2F0ZS4gSWYgdGhlIHN0YXNoIGFsc28gbmVlZGVkIG1hbnVhbCByZWNvdmVyeSwgdGhlIHVzZXJcbiAgLy8gYWxyZWFkeSBzYXcgdGhlIHBvc3RmbGlnaHRQb3BTdGFzaCBub3RpZnkgYWJvdmUuXG4gIGlmIChtZXJnZUVycm9yKSB7XG4gICAgaWYgKG1lcmdlRXJyb3IgaW5zdGFuY2VvZiBNZXJnZUNvbmZsaWN0RXJyb3IpIHtcbiAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgIGBNZXJnZSBjb25mbGljdDogJHttZXJnZUVycm9yLmNvbmZsaWN0ZWRGaWxlcy5qb2luKFwiLCBcIil9LiBSZXNvbHZlIGNvbmZsaWN0cyBtYW51YWxseSBhbmQgcnVuIC9nc2QgYXV0byB0byByZXN1bWUuYCxcbiAgICAgICAgXCJlcnJvclwiLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgYE1lcmdlIGNvbmZsaWN0IG9uIG1pbGVzdG9uZSAke21pbGVzdG9uZUlkfWApO1xuICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJtZXJnZS1jb25mbGljdFwiIH07XG4gICAgfVxuICAgIGxvZ0Vycm9yKFwiZW5naW5lXCIsIFwiTWlsZXN0b25lIG1lcmdlIGZhaWxlZCB3aXRoIG5vbi1jb25mbGljdCBlcnJvclwiLCB7XG4gICAgICBtaWxlc3RvbmU6IG1pbGVzdG9uZUlkLFxuICAgICAgZXJyb3I6IFN0cmluZyhtZXJnZUVycm9yKSxcbiAgICB9KTtcbiAgICBjdHgudWkubm90aWZ5KFxuICAgICAgYE1lcmdlIGZhaWxlZDogJHttZXJnZUVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBtZXJnZUVycm9yLm1lc3NhZ2UgOiBTdHJpbmcobWVyZ2VFcnJvcil9LiBSZXNvbHZlIGFuZCBydW4gL2dzZCBhdXRvIHRvIHJlc3VtZS5gLFxuICAgICAgXCJlcnJvclwiLFxuICAgICk7XG4gICAgYXdhaXQgZGVwcy5zdG9wQXV0byhcbiAgICAgIGN0eCxcbiAgICAgIHBpLFxuICAgICAgYE1lcmdlIGVycm9yIG9uIG1pbGVzdG9uZSAke21pbGVzdG9uZUlkfTogJHtTdHJpbmcobWVyZ2VFcnJvcil9YCxcbiAgICApO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwibWVyZ2UtZmFpbGVkXCIgfTtcbiAgfVxuXG4gIGlmIChzdGFzaFJlc3VsdCkge1xuICAgIHJldHVybiBzdG9wT25Qb3N0ZmxpZ2h0UmVjb3ZlcnlOZWVkZWQoaWMsIHN0YXNoUmVzdWx0LCBtaWxlc3RvbmVJZCk7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBfcnVuTWlsZXN0b25lTWVyZ2VPbmNlV2l0aFN0YXNoUmVzdG9yZShcbiAgaWM6IEl0ZXJhdGlvbkNvbnRleHQsXG4gIG1pbGVzdG9uZUlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPHsgYWN0aW9uOiBcImJyZWFrXCI7IHJlYXNvbjogc3RyaW5nIH0gfCBudWxsPiB7XG4gIGlmIChpYy5zLm1pbGVzdG9uZU1lcmdlZEluUGhhc2VzKSB7XG4gICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICBwaGFzZTogXCJtaWxlc3RvbmUtbWVyZ2Utc2tpcFwiLFxuICAgICAgcmVhc29uOiBcImFscmVhZHktbWVyZ2VkLWluLXBoYXNlc1wiLFxuICAgICAgbWlsZXN0b25lSWQsXG4gICAgfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgcmV0dXJuIF9ydW5NaWxlc3RvbmVNZXJnZVdpdGhTdGFzaFJlc3RvcmUoaWMsIG1pbGVzdG9uZUlkKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZW1pdENhbmNlbGxlZFVuaXRFbmQoXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICB1bml0VHlwZTogc3RyaW5nLFxuICB1bml0SWQ6IHN0cmluZyxcbiAgdW5pdFN0YXJ0U2VxOiBudW1iZXIsXG4gIGVycm9yQ29udGV4dD86IHsgbWVzc2FnZTogc3RyaW5nOyBjYXRlZ29yeTogc3RyaW5nOyBzdG9wUmVhc29uPzogc3RyaW5nOyBpc1RyYW5zaWVudD86IGJvb2xlYW47IHJldHJ5QWZ0ZXJNcz86IG51bWJlciB9LFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGljLmRlcHMuZW1pdEpvdXJuYWxFdmVudCh7XG4gICAgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICBmbG93SWQ6IGljLmZsb3dJZCxcbiAgICBzZXE6IGljLm5leHRTZXEoKSxcbiAgICBldmVudFR5cGU6IFwidW5pdC1lbmRcIixcbiAgICBkYXRhOiB7XG4gICAgICB1bml0VHlwZSxcbiAgICAgIHVuaXRJZCxcbiAgICAgIHN0YXR1czogXCJjYW5jZWxsZWRcIixcbiAgICAgIGFydGlmYWN0VmVyaWZpZWQ6IGZhbHNlLFxuICAgICAgLi4uKGVycm9yQ29udGV4dCA/IHsgZXJyb3JDb250ZXh0IH0gOiB7fSksXG4gICAgfSxcbiAgICBjYXVzZWRCeTogeyBmbG93SWQ6IGljLmZsb3dJZCwgc2VxOiB1bml0U3RhcnRTZXEgfSxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBfYnVpbGRDYW5jZWxsZWRVbml0U3RvcFJlYXNvbihcbiAgdW5pdFR5cGU6IHN0cmluZyxcbiAgdW5pdElkOiBzdHJpbmcsXG4gIGVycm9yQ29udGV4dD86IHsgbWVzc2FnZTogc3RyaW5nOyBjYXRlZ29yeTogc3RyaW5nIH0sXG4pOiB7XG4gIG5vdGlmeU1lc3NhZ2U6IHN0cmluZztcbiAgc3RvcFJlYXNvbjogc3RyaW5nO1xuICBsb29wUmVhc29uOiBcInNlc3Npb24tZmFpbGVkXCIgfCBcInVuaXQtYWJvcnRlZFwiO1xufSB7XG4gIGNvbnN0IGNhbmNlbGxhdGlvbk1lc3NhZ2UgPSBlcnJvckNvbnRleHQ/Lm1lc3NhZ2UgPz8gXCJ1bmtub3duXCI7XG4gIGNvbnN0IGlzU2Vzc2lvbkNyZWF0aW9uRmFpbHVyZSA9IGVycm9yQ29udGV4dD8uY2F0ZWdvcnkgPT09IFwic2Vzc2lvbi1mYWlsZWRcIjtcblxuICBpZiAoaXNTZXNzaW9uQ3JlYXRpb25GYWlsdXJlKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5vdGlmeU1lc3NhZ2U6IGBTZXNzaW9uIGNyZWF0aW9uIGZhaWxlZCBmb3IgJHt1bml0VHlwZX0gJHt1bml0SWR9OiAke2NhbmNlbGxhdGlvbk1lc3NhZ2V9LiBTdG9wcGluZyBhdXRvLW1vZGUuYCxcbiAgICAgIHN0b3BSZWFzb246IGBTZXNzaW9uIGNyZWF0aW9uIGZhaWxlZDogJHtjYW5jZWxsYXRpb25NZXNzYWdlfWAsXG4gICAgICBsb29wUmVhc29uOiBcInNlc3Npb24tZmFpbGVkXCIsXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbm90aWZ5TWVzc2FnZTogYFVuaXQgJHt1bml0VHlwZX0gJHt1bml0SWR9IGFib3J0ZWQgYWZ0ZXIgZGlzcGF0Y2g6ICR7Y2FuY2VsbGF0aW9uTWVzc2FnZX0uIFN0b3BwaW5nIGF1dG8tbW9kZS5gLFxuICAgIHN0b3BSZWFzb246IGBVbml0IGFib3J0ZWQ6ICR7Y2FuY2VsbGF0aW9uTWVzc2FnZX1gLFxuICAgIGxvb3BSZWFzb246IFwidW5pdC1hYm9ydGVkXCIsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZhaWxDbG9zZWRPbkZpbmFsaXplVGltZW91dChcbiAgaWM6IEl0ZXJhdGlvbkNvbnRleHQsXG4gIGl0ZXJEYXRhOiBJdGVyYXRpb25EYXRhLFxuICBsb29wU3RhdGU6IExvb3BTdGF0ZSxcbiAgc3RhZ2U6IFwicHJlXCIgfCBcInBvc3RcIixcbiAgc3RhcnRlZEF0OiBudW1iZXIsXG4pOiBQcm9taXNlPFBoYXNlUmVzdWx0PiB7XG4gIGNvbnN0IHsgY3R4LCBwaSwgcywgZGVwcyB9ID0gaWM7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGNvbnN0IHVuaXRUeXBlID0gaXRlckRhdGEudW5pdFR5cGU7XG4gIGNvbnN0IHVuaXRJZCA9IGl0ZXJEYXRhLnVuaXRJZDtcbiAgY29uc3QgdGltZW91dE1zID0gc3RhZ2UgPT09IFwicHJlXCIgPyBGSU5BTElaRV9QUkVfVElNRU9VVF9NUyA6IEZJTkFMSVpFX1BPU1RfVElNRU9VVF9NUztcbiAgY29uc3QgcHJvZ3Jlc3NLaW5kID0gc3RhZ2UgPT09IFwicHJlXCIgPyBcImZpbmFsaXplLXByZS10aW1lb3V0XCIgOiBcImZpbmFsaXplLXBvc3QtdGltZW91dFwiO1xuXG4gIHdyaXRlVW5pdFJ1bnRpbWVSZWNvcmQocy5iYXNlUGF0aCwgdW5pdFR5cGUsIHVuaXRJZCwgc3RhcnRlZEF0LCB7XG4gICAgcGhhc2U6IFwiZmluYWxpemUtdGltZW91dFwiLFxuICAgIHRpbWVvdXRBdDogbm93LFxuICAgIGxhc3RQcm9ncmVzc0F0OiBub3csXG4gICAgbGFzdFByb2dyZXNzS2luZDogcHJvZ3Jlc3NLaW5kLFxuICB9KTtcblxuICBkZXBzLmVtaXRKb3VybmFsRXZlbnQoe1xuICAgIHRzOiBuZXcgRGF0ZShub3cpLnRvSVNPU3RyaW5nKCksXG4gICAgZmxvd0lkOiBpYy5mbG93SWQsXG4gICAgc2VxOiBpYy5uZXh0U2VxKCksXG4gICAgZXZlbnRUeXBlOiBcInVuaXQtZW5kXCIsXG4gICAgZGF0YToge1xuICAgICAgdW5pdFR5cGUsXG4gICAgICB1bml0SWQsXG4gICAgICBzdGF0dXM6IFwidGltZWQtb3V0LWZpbmFsaXplXCIsXG4gICAgICBhcnRpZmFjdFZlcmlmaWVkOiBmYWxzZSxcbiAgICAgIGZpbmFsaXplU3RhZ2U6IHN0YWdlLFxuICAgIH0sXG4gIH0pO1xuXG4gIGxvb3BTdGF0ZS5jb25zZWN1dGl2ZUZpbmFsaXplVGltZW91dHMrKztcbiAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgcGhhc2U6IHByb2dyZXNzS2luZCxcbiAgICBpdGVyYXRpb246IGljLml0ZXJhdGlvbixcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgY29uc2VjdXRpdmVUaW1lb3V0czogbG9vcFN0YXRlLmNvbnNlY3V0aXZlRmluYWxpemVUaW1lb3V0cyxcbiAgfSk7XG5cbiAgY3R4LnVpLm5vdGlmeShcbiAgICBgJHtzdGFnZSA9PT0gXCJwcmVcIiA/IFwicG9zdFVuaXRQcmVWZXJpZmljYXRpb25cIiA6IFwicG9zdFVuaXRQb3N0VmVyaWZpY2F0aW9uXCJ9IHRpbWVkIG91dCBhZnRlciAke3RpbWVvdXRNcyAvIDEwMDB9cyBmb3IgJHt1bml0VHlwZX0gJHt1bml0SWR9ICgke2xvb3BTdGF0ZS5jb25zZWN1dGl2ZUZpbmFsaXplVGltZW91dHN9LyR7TUFYX0ZJTkFMSVpFX1RJTUVPVVRTfSkg4oCUIHBhdXNpbmcgYXV0by1tb2RlIGZvciByZWNvdmVyeS5gLFxuICAgIFwid2FybmluZ1wiLFxuICApO1xuXG4gIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICBzLmN1cnJlbnRVbml0ID0gbnVsbDtcbiAgY2xlYXJDdXJyZW50UGhhc2UoKTtcbiAgZHJhaW5Mb2dzKCk7XG4gIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IHByb2dyZXNzS2luZCB9O1xufVxuXG4vLyDilIDilIDilIAgcnVuUHJlRGlzcGF0Y2gg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogUGhhc2UgMTogUHJlLWRpc3BhdGNoIOKAlCByZXNvdXJjZSBndWFyZCwgaGVhbHRoIGdhdGUsIHN0YXRlIGRlcml2YXRpb24sXG4gKiBtaWxlc3RvbmUgdHJhbnNpdGlvbiwgdGVybWluYWwgY29uZGl0aW9ucy5cbiAqIFJldHVybnMgYnJlYWsgdG8gZXhpdCB0aGUgbG9vcCwgb3IgbmV4dCB3aXRoIFByZURpc3BhdGNoRGF0YSBvbiBzdWNjZXNzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuUHJlRGlzcGF0Y2goXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICBsb29wU3RhdGU6IExvb3BTdGF0ZSxcbik6IFByb21pc2U8UGhhc2VSZXN1bHQ8UHJlRGlzcGF0Y2hEYXRhPj4ge1xuICBjb25zdCB7IGN0eCwgcGksIHMsIGRlcHMsIHByZWZzIH0gPSBpYztcbiAgY29uc3QgdW9rRmxhZ3MgPSByZXNvbHZlVW9rRmxhZ3MocHJlZnMpO1xuICBjb25zdCBydW5QcmVEaXNwYXRjaEdhdGUgPSBhc3luYyAoaW5wdXQ6IHtcbiAgICBnYXRlSWQ6IHN0cmluZztcbiAgICBnYXRlVHlwZTogc3RyaW5nO1xuICAgIG91dGNvbWU6IFwicGFzc1wiIHwgXCJmYWlsXCIgfCBcInJldHJ5XCIgfCBcIm1hbnVhbC1hdHRlbnRpb25cIjtcbiAgICBmYWlsdXJlQ2xhc3M6IFwibm9uZVwiIHwgXCJwb2xpY3lcIiB8IFwiaW5wdXRcIiB8IFwiZXhlY3V0aW9uXCIgfCBcImFydGlmYWN0XCIgfCBcInZlcmlmaWNhdGlvblwiIHwgXCJjbG9zZW91dFwiIHwgXCJnaXRcIiB8IFwidGltZW91dFwiIHwgXCJtYW51YWwtYXR0ZW50aW9uXCIgfCBcInVua25vd25cIjtcbiAgICByYXRpb25hbGU6IHN0cmluZztcbiAgICBmaW5kaW5ncz86IHN0cmluZztcbiAgICBtaWxlc3RvbmVJZD86IHN0cmluZztcbiAgfSk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIGlmICghdW9rRmxhZ3MuZ2F0ZXMpIHJldHVybjtcbiAgICBjb25zdCBnYXRlUnVubmVyID0gbmV3IFVva0dhdGVSdW5uZXIoKTtcbiAgICBnYXRlUnVubmVyLnJlZ2lzdGVyKHtcbiAgICAgIGlkOiBpbnB1dC5nYXRlSWQsXG4gICAgICB0eXBlOiBpbnB1dC5nYXRlVHlwZSxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jICgpID0+ICh7XG4gICAgICAgIG91dGNvbWU6IGlucHV0Lm91dGNvbWUsXG4gICAgICAgIGZhaWx1cmVDbGFzczogaW5wdXQuZmFpbHVyZUNsYXNzLFxuICAgICAgICByYXRpb25hbGU6IGlucHV0LnJhdGlvbmFsZSxcbiAgICAgICAgZmluZGluZ3M6IGlucHV0LmZpbmRpbmdzID8/IFwiXCIsXG4gICAgICB9KSxcbiAgICB9KTtcbiAgICBhd2FpdCBnYXRlUnVubmVyLnJ1bihpbnB1dC5nYXRlSWQsIHtcbiAgICAgIGJhc2VQYXRoOiBzLmJhc2VQYXRoLFxuICAgICAgdHJhY2VJZDogYHByZS1kaXNwYXRjaDoke2ljLmZsb3dJZH1gLFxuICAgICAgdHVybklkOiBgaXRlci0ke2ljLml0ZXJhdGlvbn1gLFxuICAgICAgbWlsZXN0b25lSWQ6IGlucHV0Lm1pbGVzdG9uZUlkID8/IHMuY3VycmVudE1pbGVzdG9uZUlkID8/IHVuZGVmaW5lZCxcbiAgICAgIHVuaXRUeXBlOiBcInByZS1kaXNwYXRjaFwiLFxuICAgICAgdW5pdElkOiBgaXRlci0ke2ljLml0ZXJhdGlvbn1gLFxuICAgIH0pO1xuICB9O1xuXG4gIC8vIFJlc291cmNlIHZlcnNpb24gZ3VhcmRcbiAgY29uc3Qgc3RhbGVNc2cgPSBkZXBzLmNoZWNrUmVzb3VyY2VzU3RhbGUocy5yZXNvdXJjZVZlcnNpb25PblN0YXJ0KTtcbiAgaWYgKHN0YWxlTXNnKSB7XG4gICAgYXdhaXQgcnVuUHJlRGlzcGF0Y2hHYXRlKHtcbiAgICAgIGdhdGVJZDogXCJyZXNvdXJjZS12ZXJzaW9uLWd1YXJkXCIsXG4gICAgICBnYXRlVHlwZTogXCJwb2xpY3lcIixcbiAgICAgIG91dGNvbWU6IFwiZmFpbFwiLFxuICAgICAgZmFpbHVyZUNsYXNzOiBcInBvbGljeVwiLFxuICAgICAgcmF0aW9uYWxlOiBcInJlc291cmNlIHZlcnNpb24gZ3VhcmQgYmxvY2tlZCBkaXNwYXRjaFwiLFxuICAgICAgZmluZGluZ3M6IHN0YWxlTXNnLFxuICAgIH0pO1xuICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgc3RhbGVNc2cpO1xuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJleGl0XCIsIHJlYXNvbjogXCJyZXNvdXJjZXMtc3RhbGVcIiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInJlc291cmNlcy1zdGFsZVwiIH07XG4gIH1cbiAgYXdhaXQgcnVuUHJlRGlzcGF0Y2hHYXRlKHtcbiAgICBnYXRlSWQ6IFwicmVzb3VyY2UtdmVyc2lvbi1ndWFyZFwiLFxuICAgIGdhdGVUeXBlOiBcInBvbGljeVwiLFxuICAgIG91dGNvbWU6IFwicGFzc1wiLFxuICAgIGZhaWx1cmVDbGFzczogXCJub25lXCIsXG4gICAgcmF0aW9uYWxlOiBcInJlc291cmNlIHZlcnNpb24gZ3VhcmQgcGFzc2VkXCIsXG4gIH0pO1xuXG4gIGRlcHMuaW52YWxpZGF0ZUFsbENhY2hlcygpO1xuICBzLmxhc3RQcm9tcHRDaGFyQ291bnQgPSB1bmRlZmluZWQ7XG4gIHMubGFzdEJhc2VsaW5lQ2hhckNvdW50ID0gdW5kZWZpbmVkO1xuXG4gIC8vIFByZS1kaXNwYXRjaCBoZWFsdGggZ2F0ZVxuICB0cnkge1xuICAgIGNvbnN0IGhlYWx0aEdhdGUgPSBhd2FpdCBkZXBzLnByZURpc3BhdGNoSGVhbHRoR2F0ZShzLmJhc2VQYXRoKTtcbiAgICBpZiAoaGVhbHRoR2F0ZS5maXhlc0FwcGxpZWQubGVuZ3RoID4gMCkge1xuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYFByZS1kaXNwYXRjaDogJHtoZWFsdGhHYXRlLmZpeGVzQXBwbGllZC5qb2luKFwiLCBcIil9YCxcbiAgICAgICAgXCJpbmZvXCIsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIWhlYWx0aEdhdGUucHJvY2VlZCkge1xuICAgICAgYXdhaXQgcnVuUHJlRGlzcGF0Y2hHYXRlKHtcbiAgICAgICAgZ2F0ZUlkOiBcInByZS1kaXNwYXRjaC1oZWFsdGgtZ2F0ZVwiLFxuICAgICAgICBnYXRlVHlwZTogXCJleGVjdXRpb25cIixcbiAgICAgICAgb3V0Y29tZTogXCJtYW51YWwtYXR0ZW50aW9uXCIsXG4gICAgICAgIGZhaWx1cmVDbGFzczogXCJtYW51YWwtYXR0ZW50aW9uXCIsXG4gICAgICAgIHJhdGlvbmFsZTogXCJwcmUtZGlzcGF0Y2ggaGVhbHRoIGdhdGUgYmxvY2tlZCBkaXNwYXRjaFwiLFxuICAgICAgICBmaW5kaW5nczogaGVhbHRoR2F0ZS5yZWFzb24sXG4gICAgICB9KTtcbiAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgIGhlYWx0aEdhdGUucmVhc29uIHx8IFwiUHJlLWRpc3BhdGNoIGhlYWx0aCBjaGVjayBmYWlsZWQg4oCUIHJ1biAvZ3NkIGRvY3RvciBmb3IgZGV0YWlscy5cIixcbiAgICAgICAgXCJlcnJvclwiLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImV4aXRcIiwgcmVhc29uOiBcImhlYWx0aC1nYXRlLWZhaWxlZFwiIH0pO1xuICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJoZWFsdGgtZ2F0ZS1mYWlsZWRcIiB9O1xuICAgIH1cbiAgICBhd2FpdCBydW5QcmVEaXNwYXRjaEdhdGUoe1xuICAgICAgZ2F0ZUlkOiBcInByZS1kaXNwYXRjaC1oZWFsdGgtZ2F0ZVwiLFxuICAgICAgZ2F0ZVR5cGU6IFwiZXhlY3V0aW9uXCIsXG4gICAgICBvdXRjb21lOiBcInBhc3NcIixcbiAgICAgIGZhaWx1cmVDbGFzczogXCJub25lXCIsXG4gICAgICByYXRpb25hbGU6IFwicHJlLWRpc3BhdGNoIGhlYWx0aCBnYXRlIHBhc3NlZFwiLFxuICAgICAgZmluZGluZ3M6IGhlYWx0aEdhdGUuZml4ZXNBcHBsaWVkLmxlbmd0aCA+IDAgPyBoZWFsdGhHYXRlLmZpeGVzQXBwbGllZC5qb2luKFwiLCBcIikgOiBcIlwiLFxuICAgIH0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgYXdhaXQgcnVuUHJlRGlzcGF0Y2hHYXRlKHtcbiAgICAgIGdhdGVJZDogXCJwcmUtZGlzcGF0Y2gtaGVhbHRoLWdhdGVcIixcbiAgICAgIGdhdGVUeXBlOiBcImV4ZWN1dGlvblwiLFxuICAgICAgb3V0Y29tZTogXCJtYW51YWwtYXR0ZW50aW9uXCIsXG4gICAgICBmYWlsdXJlQ2xhc3M6IFwibWFudWFsLWF0dGVudGlvblwiLFxuICAgICAgcmF0aW9uYWxlOiBcInByZS1kaXNwYXRjaCBoZWFsdGggZ2F0ZSB0aHJldyB1bmV4cGVjdGVkbHlcIixcbiAgICAgIGZpbmRpbmdzOiBTdHJpbmcoZSksXG4gICAgfSk7XG4gICAgbG9nV2FybmluZyhcImVuZ2luZVwiLCBcIlByZS1kaXNwYXRjaCBoZWFsdGggZ2F0ZSB0aHJldyB1bmV4cGVjdGVkbHlcIiwgeyBlcnJvcjogU3RyaW5nKGUpIH0pO1xuICB9XG5cbiAgLy8gU3luYyBwcm9qZWN0IHJvb3QgYXJ0aWZhY3RzIGludG8gd29ya3RyZWVcbiAgaWYgKFxuICAgIHMub3JpZ2luYWxCYXNlUGF0aCAmJlxuICAgICFpc1NhbWVQYXRoTG9jYWwocy5iYXNlUGF0aCwgcy5vcmlnaW5hbEJhc2VQYXRoKSAmJlxuICAgIHMuY3VycmVudE1pbGVzdG9uZUlkICYmXG4gICAgcy5zY29wZVxuICApIHtcbiAgICBkZXBzLndvcmt0cmVlUHJvamVjdGlvbi5wcm9qZWN0Um9vdFRvV29ya3RyZWUocy5zY29wZSk7XG4gIH1cblxuICAvLyBEZXJpdmUgc3RhdGUg4oCUIHVzZSBjYW5vbmljYWwgcHJvamVjdCByb290IHNvIHRoZSBjYWNoZSBrZXkgaXMgc3RhYmxlXG4gIC8vIGFjcm9zcyB3b3JrdHJlZeKGlHByb2plY3Qtcm9vdCBwYXRoLWZvcm0gYWx0ZXJuYXRpb24uIFNlZSBQUiAjNTIzNlxuICAvLyAod29ya3NwYWNlIGhhbmRsZSBpbmZyYXN0cnVjdHVyZSkgYW5kIHRoZSBQaGFzZSBBIHB0IDIgcGxhbi5cbiAgbGV0IHN0YXRlID0gYXdhaXQgZGVwcy5kZXJpdmVTdGF0ZShzLmNhbm9uaWNhbFByb2plY3RSb290KTtcbiAgY29uc3QgeyBnZXREZWVwU3RhZ2VHYXRlIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9hdXRvLWRpc3BhdGNoLmpzXCIpO1xuICBjb25zdCBkZWVwU3RhZ2VHYXRlID0gZ2V0RGVlcFN0YWdlR2F0ZShwcmVmcywgcy5iYXNlUGF0aCk7XG4gIGNvbnN0IGNhblJ1bkRlZXBTZXR1cEdhdGUgPVxuICAgIHN0YXRlLnBoYXNlID09PSBcInByZS1wbGFubmluZ1wiIHx8XG4gICAgc3RhdGUucGhhc2UgPT09IFwibmVlZHMtZGlzY3Vzc2lvblwiIHx8XG4gICAgc3RhdGUucGhhc2UgPT09IFwicGxhbm5pbmdcIjtcbiAgaWYgKFxuICAgIGNhblJ1bkRlZXBTZXR1cEdhdGUgJiZcbiAgICAoZGVlcFN0YWdlR2F0ZS5zdGF0dXMgPT09IFwicGVuZGluZ1wiIHx8IGRlZXBTdGFnZUdhdGUuc3RhdHVzID09PSBcImJsb2NrZWRcIilcbiAgKSB7XG4gICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICBwaGFzZTogXCJkZWVwLXByb2plY3Qtc3RhZ2UtZ2F0ZVwiLFxuICAgICAgc3RhZ2U6IGRlZXBTdGFnZUdhdGUuc3RhZ2UsXG4gICAgICBzdGF0dXM6IGRlZXBTdGFnZUdhdGUuc3RhdHVzLFxuICAgICAgcmVhc29uOiBkZWVwU3RhZ2VHYXRlLnJlYXNvbixcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgYWN0aW9uOiBcIm5leHRcIixcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgc3RhdGU6IHtcbiAgICAgICAgICAuLi5zdGF0ZSxcbiAgICAgICAgICBwaGFzZTogXCJwcmUtcGxhbm5pbmdcIixcbiAgICAgICAgICBhY3RpdmVNaWxlc3RvbmU6IG51bGwsXG4gICAgICAgICAgYWN0aXZlU2xpY2U6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVGFzazogbnVsbCxcbiAgICAgICAgICBuZXh0QWN0aW9uOiBkZWVwU3RhZ2VHYXRlLnJlYXNvbixcbiAgICAgICAgfSxcbiAgICAgICAgbWlkOiBcIlBST0pFQ1RcIixcbiAgICAgICAgbWlkVGl0bGU6IFwiUHJvamVjdCBzZXR1cFwiLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgaWYgKHVva0ZsYWdzLnBsYW5WMiAmJiBzaG91bGRSdW5QbGFuVjJHYXRlKHN0YXRlLnBoYXNlKSkge1xuICAgIGxldCBjb21waWxlZCA9IGVuc3VyZVBsYW5WMkdyYXBoKHMuYmFzZVBhdGgsIHN0YXRlKTtcbiAgICBpZiAoaXNFbXB0eVBsYW5WMkdyYXBoUmVzdWx0KGNvbXBpbGVkKSkge1xuICAgICAgZGVwcy5pbnZhbGlkYXRlQWxsQ2FjaGVzKCk7XG4gICAgICBzdGF0ZSA9IGF3YWl0IGRlcHMuZGVyaXZlU3RhdGUocy5jYW5vbmljYWxQcm9qZWN0Um9vdCk7XG4gICAgICBjb21waWxlZCA9IHNob3VsZFJ1blBsYW5WMkdhdGUoc3RhdGUucGhhc2UpXG4gICAgICAgID8gZW5zdXJlUGxhblYyR3JhcGgocy5iYXNlUGF0aCwgc3RhdGUpXG4gICAgICAgIDoge1xuICAgICAgICAgICAgb2s6IHRydWUsXG4gICAgICAgICAgICByZWFzb246IFwiZW1wdHkgcGxhbi12MiBncmFwaCByZWNvdmVyZWQgYnkgc3RhdGUgcmVkZXJpdmVcIixcbiAgICAgICAgICAgIG5vZGVDb3VudDogMCxcbiAgICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAoIWNvbXBpbGVkLm9rKSB7XG4gICAgICBjb25zdCByZWFzb24gPSBjb21waWxlZC5yZWFzb24gPz8gXCJQbGFuIHYyIGNvbXBpbGF0aW9uIGZhaWxlZFwiO1xuICAgICAgaWYgKGlzTWlzc2luZ0ZpbmFsaXplZENvbnRleHRSZXN1bHQoY29tcGlsZWQpKSB7XG4gICAgICAgIGF3YWl0IHJ1blByZURpc3BhdGNoR2F0ZSh7XG4gICAgICAgICAgZ2F0ZUlkOiBcInBsYW4tdjItZ2F0ZVwiLFxuICAgICAgICAgIGdhdGVUeXBlOiBcInBvbGljeVwiLFxuICAgICAgICAgIG91dGNvbWU6IFwicGFzc1wiLFxuICAgICAgICAgIGZhaWx1cmVDbGFzczogXCJub25lXCIsXG4gICAgICAgICAgcmF0aW9uYWxlOiBcInBsYW4gdjIgbWlzc2luZyBjb250ZXh0IHJlY292ZXJ5IGRlZmVycmVkIHRvIGRpc3BhdGNoXCIsXG4gICAgICAgICAgZmluZGluZ3M6IHJlYXNvbixcbiAgICAgICAgICBtaWxlc3RvbmVJZDogc3RhdGUuYWN0aXZlTWlsZXN0b25lPy5pZCA/PyB1bmRlZmluZWQsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgcnVuUHJlRGlzcGF0Y2hHYXRlKHtcbiAgICAgICAgICBnYXRlSWQ6IFwicGxhbi12Mi1nYXRlXCIsXG4gICAgICAgICAgZ2F0ZVR5cGU6IFwicG9saWN5XCIsXG4gICAgICAgICAgb3V0Y29tZTogXCJtYW51YWwtYXR0ZW50aW9uXCIsXG4gICAgICAgICAgZmFpbHVyZUNsYXNzOiBcIm1hbnVhbC1hdHRlbnRpb25cIixcbiAgICAgICAgICByYXRpb25hbGU6IFwicGxhbiB2MiBjb21waWxlIGdhdGUgZmFpbGVkXCIsXG4gICAgICAgICAgZmluZGluZ3M6IHJlYXNvbixcbiAgICAgICAgICBtaWxlc3RvbmVJZDogc3RhdGUuYWN0aXZlTWlsZXN0b25lPy5pZCA/PyB1bmRlZmluZWQsXG4gICAgICAgIH0pO1xuICAgICAgICBjdHgudWkubm90aWZ5KGBQbGFuIGdhdGUgZmFpbGVkLWNsb3NlZDogJHtyZWFzb259XFxuXFxuSWYgdGhpcyBrZWVwcyBoYXBwZW5pbmcsIHRyeTogL2dzZCBkb2N0b3IgaGVhbGAsIFwiZXJyb3JcIik7XG4gICAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInBsYW4tdjItZ2F0ZS1mYWlsZWRcIiB9O1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY29tcGlsZWQub2spIHtcbiAgICAgIGF3YWl0IHJ1blByZURpc3BhdGNoR2F0ZSh7XG4gICAgICAgIGdhdGVJZDogXCJwbGFuLXYyLWdhdGVcIixcbiAgICAgICAgZ2F0ZVR5cGU6IFwicG9saWN5XCIsXG4gICAgICAgIG91dGNvbWU6IFwicGFzc1wiLFxuICAgICAgICBmYWlsdXJlQ2xhc3M6IFwibm9uZVwiLFxuICAgICAgICByYXRpb25hbGU6IFwicGxhbiB2MiBjb21waWxlIGdhdGUgcGFzc2VkXCIsXG4gICAgICAgIG1pbGVzdG9uZUlkOiBzdGF0ZS5hY3RpdmVNaWxlc3RvbmU/LmlkID8/IHVuZGVmaW5lZCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICBkZXBzLnN5bmNDbXV4U2lkZWJhcihwcmVmcywgc3RhdGUpO1xuICBsZXQgbWlkID0gc3RhdGUuYWN0aXZlTWlsZXN0b25lPy5pZDtcbiAgbGV0IG1pZFRpdGxlID0gc3RhdGUuYWN0aXZlTWlsZXN0b25lPy50aXRsZTtcbiAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgcGhhc2U6IFwic3RhdGUtZGVyaXZlZFwiLFxuICAgIGl0ZXJhdGlvbjogaWMuaXRlcmF0aW9uLFxuICAgIG1pZCxcbiAgICBzdGF0ZVBoYXNlOiBzdGF0ZS5waGFzZSxcbiAgfSk7XG5cbiAgLy8g4pSA4pSAIFNsaWNlLWxldmVsIHBhcmFsbGVsaXNtIGdhdGUgKCMyMzQwKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gV2hlbiBzbGljZV9wYXJhbGxlbCBpcyBlbmFibGVkLCBjaGVjayBpZiBtdWx0aXBsZSBzbGljZXMgYXJlIGVsaWdpYmxlXG4gIC8vIGZvciBwYXJhbGxlbCBleGVjdXRpb24uIElmIHNvLCBkaXNwYXRjaCB0aGVtIGluIHBhcmFsbGVsIGFuZCBzdG9wIHRoZVxuICAvLyBzZXF1ZW50aWFsIGxvb3AuIFdvcmtlcnMgYXJlIHNwYXduZWQgdmlhIHNsaWNlLXBhcmFsbGVsLW9yY2hlc3RyYXRvci50cy5cbiAgaWYgKFxuICAgIHByZWZzPy5zbGljZV9wYXJhbGxlbD8uZW5hYmxlZCAmJlxuICAgIG1pZCAmJlxuICAgICFwcm9jZXNzLmVudi5HU0RfUEFSQUxMRUxfV09SS0VSICYmXG4gICAgaXNEYkF2YWlsYWJsZSgpXG4gICkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBkYlNsaWNlcyA9IGdldE1pbGVzdG9uZVNsaWNlcyhtaWQpO1xuICAgICAgaWYgKGRiU2xpY2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgZG9uZUlkcyA9IG5ldyBTZXQoZGJTbGljZXMuZmlsdGVyKHNsID0+IHNsLnN0YXR1cyA9PT0gXCJjb21wbGV0ZVwiIHx8IHNsLnN0YXR1cyA9PT0gXCJkb25lXCIpLm1hcChzbCA9PiBzbC5pZCkpO1xuICAgICAgICBjb25zdCBzbGljZUlucHV0cyA9IGRiU2xpY2VzLm1hcChzbCA9PiAoe1xuICAgICAgICAgIGlkOiBzbC5pZCxcbiAgICAgICAgICBkb25lOiBkb25lSWRzLmhhcyhzbC5pZCksXG4gICAgICAgICAgZGVwZW5kczogc2wuZGVwZW5kcyA/PyBbXSxcbiAgICAgICAgfSkpO1xuICAgICAgICBjb25zdCBlbGlnaWJsZSA9IGdldEVsaWdpYmxlU2xpY2VzKHNsaWNlSW5wdXRzLCBkb25lSWRzKTtcbiAgICAgICAgaWYgKGVsaWdpYmxlLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHtcbiAgICAgICAgICAgIHBoYXNlOiBcInNsaWNlLXBhcmFsbGVsLWRpc3BhdGNoXCIsXG4gICAgICAgICAgICBpdGVyYXRpb246IGljLml0ZXJhdGlvbixcbiAgICAgICAgICAgIG1pZCxcbiAgICAgICAgICAgIGVsaWdpYmxlU2xpY2VzOiBlbGlnaWJsZS5tYXAoZSA9PiBlLmlkKSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgICAgYFNsaWNlLXBhcmFsbGVsOiBkaXNwYXRjaGluZyAke2VsaWdpYmxlLmxlbmd0aH0gZWxpZ2libGUgc2xpY2VzIGZvciAke21pZH0uYCxcbiAgICAgICAgICAgIFwiaW5mb1wiLFxuICAgICAgICAgICk7XG4gICAgICAgICAgLy8gQURSLTAxNyAjNTcwNzogcmVjb25jaWxlIGJlZm9yZSBzcGF3bmluZyBzbyBlYWNoIHdvcmtlciBkb2Vzbid0XG4gICAgICAgICAgLy8gaW5kZXBlbmRlbnRseSByYWNlIG9uIHRoZSBzYW1lIGRyaWZ0LiBGYWlsdXJlIGFib3J0cyB0aGUgc3Bhd24uXG4gICAgICAgICAgY29uc3Qgc3Bhd25HYXRlID0gYXdhaXQgcmVjb25jaWxlQmVmb3JlU3Bhd24ocy5iYXNlUGF0aCk7XG4gICAgICAgICAgaWYgKCFzcGF3bkdhdGUub2spIHtcbiAgICAgICAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgICAgICAgIGBTbGljZS1wYXJhbGxlbDogYWJvcnRpbmcgc3Bhd24g4oCUICR7c3Bhd25HYXRlLnJlYXNvbn1gLFxuICAgICAgICAgICAgICBcImVycm9yXCIsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogYHNsaWNlLXBhcmFsbGVsLXJlY29uY2lsaWF0aW9uLWZhaWxlZDogJHtzcGF3bkdhdGUucmVhc29ufWAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc3RhcnRTbGljZVBhcmFsbGVsKFxuICAgICAgICAgICAgcy5iYXNlUGF0aCxcbiAgICAgICAgICAgIG1pZCxcbiAgICAgICAgICAgIGVsaWdpYmxlLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtYXhXb3JrZXJzOiBwcmVmcy5zbGljZV9wYXJhbGxlbC5tYXhfd29ya2VycyA/PyAyLFxuICAgICAgICAgICAgICB1c2VFeGVjdXRpb25HcmFwaDogdW9rRmxhZ3MuZXhlY3V0aW9uR3JhcGgsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKHJlc3VsdC5zdGFydGVkLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgICAgICAgIGBTbGljZS1wYXJhbGxlbDogc3RhcnRlZCAke3Jlc3VsdC5zdGFydGVkLmxlbmd0aH0gd29ya2VyKHMpOiAke3Jlc3VsdC5zdGFydGVkLmpvaW4oXCIsIFwiKX0uYCxcbiAgICAgICAgICAgICAgXCJpbmZvXCIsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgZGVwcy5zdG9wQXV0byhjdHgsIHBpLCBgU2xpY2UtcGFyYWxsZWwgZGlzcGF0Y2hlZCBmb3IgJHttaWR9YCk7XG4gICAgICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInNsaWNlLXBhcmFsbGVsLWRpc3BhdGNoZWRcIiB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBGYWxsIHRocm91Z2ggdG8gc2VxdWVudGlhbCBpZiBubyB3b3JrZXJzIHN0YXJ0ZWRcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICAgIHBoYXNlOiBcInNsaWNlLXBhcmFsbGVsLWNoZWNrLWVycm9yXCIsXG4gICAgICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gICAgICB9KTtcbiAgICAgIC8vIE5vbi1mYXRhbCDigJQgZmFsbCB0aHJvdWdoIHRvIHNlcXVlbnRpYWwgZGlzcGF0Y2hcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgTWlsZXN0b25lIHRyYW5zaXRpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGlmIChtaWQgJiYgcy5jdXJyZW50TWlsZXN0b25lSWQgJiYgbWlkICE9PSBzLmN1cnJlbnRNaWxlc3RvbmVJZCkge1xuICAgIGRlcHMuZW1pdEpvdXJuYWxFdmVudCh7IHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksIGZsb3dJZDogaWMuZmxvd0lkLCBzZXE6IGljLm5leHRTZXEoKSwgZXZlbnRUeXBlOiBcIm1pbGVzdG9uZS10cmFuc2l0aW9uXCIsIGRhdGE6IHsgZnJvbTogcy5jdXJyZW50TWlsZXN0b25lSWQsIHRvOiBtaWQgfSB9KTtcbiAgICBjdHgudWkubm90aWZ5KFxuICAgICAgYE1pbGVzdG9uZSAke3MuY3VycmVudE1pbGVzdG9uZUlkfSBjb21wbGV0ZS4gQWR2YW5jaW5nIHRvICR7bWlkfTogJHttaWRUaXRsZX0uYCxcbiAgICAgIFwiaW5mb1wiLFxuICAgICk7XG4gICAgZGVwcy5zZW5kRGVza3RvcE5vdGlmaWNhdGlvbihcbiAgICAgIFwiR1NEXCIsXG4gICAgICBgTWlsZXN0b25lICR7cy5jdXJyZW50TWlsZXN0b25lSWR9IGNvbXBsZXRlIWAsXG4gICAgICBcInN1Y2Nlc3NcIixcbiAgICAgIFwibWlsZXN0b25lXCIsXG4gICAgICBiYXNlbmFtZShzLm9yaWdpbmFsQmFzZVBhdGggfHwgcy5iYXNlUGF0aCksXG4gICAgKTtcbiAgICBkZXBzLmxvZ0NtdXhFdmVudChcbiAgICAgIHByZWZzLFxuICAgICAgYE1pbGVzdG9uZSAke3MuY3VycmVudE1pbGVzdG9uZUlkfSBjb21wbGV0ZS4gQWR2YW5jaW5nIHRvICR7bWlkfS5gLFxuICAgICAgXCJzdWNjZXNzXCIsXG4gICAgKTtcblxuICAgIGNvbnN0IHZpelByZWZzID0gcHJlZnM7XG4gICAgaWYgKHZpelByZWZzPy5hdXRvX3Zpc3VhbGl6ZSkge1xuICAgICAgY3R4LnVpLm5vdGlmeShcIlJ1biAvZ3NkIHZpc3VhbGl6ZSB0byBzZWUgcHJvZ3Jlc3Mgb3ZlcnZpZXcuXCIsIFwiaW5mb1wiKTtcbiAgICB9XG4gICAgaWYgKHZpelByZWZzPy5hdXRvX3JlcG9ydCAhPT0gZmFsc2UpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGdlbmVyYXRlTWlsZXN0b25lUmVwb3J0KHMsIGN0eCwgcy5jdXJyZW50TWlsZXN0b25lSWQhKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgIGBSZXBvcnQgZ2VuZXJhdGlvbiBmYWlsZWQ6ICR7ZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpfWAsXG4gICAgICAgICAgXCJ3YXJuaW5nXCIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgZGlzcGF0Y2ggY291bnRlcnMgZm9yIG5ldyBtaWxlc3RvbmVcbiAgICBzLnVuaXREaXNwYXRjaENvdW50LmNsZWFyKCk7XG4gICAgcy51bml0UmVjb3ZlcnlDb3VudC5jbGVhcigpO1xuICAgIHMudW5pdExpZmV0aW1lRGlzcGF0Y2hlcy5jbGVhcigpO1xuICAgIGxvb3BTdGF0ZS5yZWNlbnRVbml0cy5sZW5ndGggPSAwO1xuICAgIGxvb3BTdGF0ZS5zdHVja1JlY292ZXJ5QXR0ZW1wdHMgPSAwO1xuXG4gICAgLy8gV29ya3RyZWUgbGlmZWN5Y2xlIG9uIG1pbGVzdG9uZSB0cmFuc2l0aW9uIOKAlCBtZXJnZSBjdXJyZW50LCBlbnRlciBuZXh0LlxuICAgIC8vICMyOTA5IC8gIzU1MzgtZm9sbG93dXA6IHByZWZsaWdodCBzdGFzaCArIGFsd2F5cy1vbiBwb3N0ZmxpZ2h0IHBvcC5cbiAgICB7XG4gICAgICBjb25zdCBzdG9wID0gYXdhaXQgX3J1bk1pbGVzdG9uZU1lcmdlT25jZVdpdGhTdGFzaFJlc3RvcmUoaWMsIHMuY3VycmVudE1pbGVzdG9uZUlkISk7XG4gICAgICBpZiAoc3RvcCkgcmV0dXJuIHN0b3A7XG4gICAgfVxuXG4gICAgLy8gUFIgY3JlYXRpb24gKGF1dG9fcHIpIGlzIGhhbmRsZWQgaW5zaWRlIG1lcmdlTWlsZXN0b25lVG9NYWluICgjMjMwMilcblxuICAgIGRlcHMuaW52YWxpZGF0ZUFsbENhY2hlcygpO1xuXG4gICAgc3RhdGUgPSBhd2FpdCBkZXBzLmRlcml2ZVN0YXRlKHMuY2Fub25pY2FsUHJvamVjdFJvb3QpO1xuICAgIG1pZCA9IHN0YXRlLmFjdGl2ZU1pbGVzdG9uZT8uaWQ7XG4gICAgbWlkVGl0bGUgPSBzdGF0ZS5hY3RpdmVNaWxlc3RvbmU/LnRpdGxlO1xuXG4gICAgaWYgKG1pZCkge1xuICAgICAgaWYgKGRlcHMuZ2V0SXNvbGF0aW9uTW9kZShzLmJhc2VQYXRoKSAhPT0gXCJub25lXCIpIHtcbiAgICAgICAgZGVwcy5jYXB0dXJlSW50ZWdyYXRpb25CcmFuY2gocy5iYXNlUGF0aCwgbWlkKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGVudGVyUmVzdWx0ID0gZGVwcy5saWZlY3ljbGUuZW50ZXJNaWxlc3RvbmUobWlkLCBjdHgudWkpO1xuICAgICAgaWYgKCFlbnRlclJlc3VsdC5vaykge1xuICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgIGBNaWxlc3RvbmUgdHJhbnNpdGlvbiBzdG9wcGVkOiBmYWlsZWQgdG8gZW50ZXIgJHttaWR9ICgke2VudGVyUmVzdWx0LnJlYXNvbn0pLmAsXG4gICAgICAgICAgXCJlcnJvclwiLFxuICAgICAgICApO1xuICAgICAgICBpZiAoZW50ZXJSZXN1bHQucmVhc29uID09PSBcImxlYXNlLWNvbmZsaWN0XCIpIHtcbiAgICAgICAgICBhd2FpdCBkZXBzLnBhdXNlQXV0byhjdHgsIHBpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcIm1pbGVzdG9uZS1lbnRlci1mYWlsZWRcIiB9O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBtaWQgaXMgdW5kZWZpbmVkIOKAlCBubyBtaWxlc3RvbmUgdG8gY2FwdHVyZSBpbnRlZ3JhdGlvbiBicmFuY2ggZm9yXG4gICAgfVxuXG4gICAgY29uc3QgcGVuZGluZ0lkcyA9IHN0YXRlLnJlZ2lzdHJ5XG4gICAgICAuZmlsdGVyKFxuICAgICAgICAobTogeyBzdGF0dXM6IHN0cmluZyB9KSA9PlxuICAgICAgICAgIG0uc3RhdHVzICE9PSBcImNvbXBsZXRlXCIgJiYgbS5zdGF0dXMgIT09IFwicGFya2VkXCIsXG4gICAgICApXG4gICAgICAubWFwKChtOiB7IGlkOiBzdHJpbmcgfSkgPT4gbS5pZCk7XG4gICAgZGVwcy5wcnVuZVF1ZXVlT3JkZXIocy5iYXNlUGF0aCwgcGVuZGluZ0lkcyk7XG5cbiAgICAvLyBBcmNoaXZlIHRoZSBvbGQgY29tcGxldGVkLXVuaXRzLmpzb24gaW5zdGVhZCBvZiB3aXBpbmcgaXQgKCMyMzEzKS5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY29tcGxldGVkS2V5c1BhdGggPSBqb2luKGdzZFJvb3Qocy5iYXNlUGF0aCksIFwiY29tcGxldGVkLXVuaXRzLmpzb25cIik7XG4gICAgICBpZiAoZXhpc3RzU3luYyhjb21wbGV0ZWRLZXlzUGF0aCkgJiYgcy5jdXJyZW50TWlsZXN0b25lSWQpIHtcbiAgICAgICAgY29uc3QgYXJjaGl2ZVBhdGggPSBqb2luKFxuICAgICAgICAgIGdzZFJvb3Qocy5iYXNlUGF0aCksXG4gICAgICAgICAgYGNvbXBsZXRlZC11bml0cy0ke3MuY3VycmVudE1pbGVzdG9uZUlkfS5qc29uYCxcbiAgICAgICAgKTtcbiAgICAgICAgY3BTeW5jKGNvbXBsZXRlZEtleXNQYXRoLCBhcmNoaXZlUGF0aCk7XG4gICAgICB9XG4gICAgICBhdG9taWNXcml0ZVN5bmMoY29tcGxldGVkS2V5c1BhdGgsIEpTT04uc3RyaW5naWZ5KFtdLCBudWxsLCAyKSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgbG9nV2FybmluZyhcImVuZ2luZVwiLCBcIkZhaWxlZCB0byBhcmNoaXZlIGNvbXBsZXRlZC11bml0cyBvbiBtaWxlc3RvbmUgdHJhbnNpdGlvblwiLCB7IGVycm9yOiBTdHJpbmcoZSkgfSk7XG4gICAgfVxuXG4gICAgLy8gUmVidWlsZCBTVEFURS5tZCBpbW1lZGlhdGVseSBzbyBpdCByZWZsZWN0cyB0aGUgbmV3IGFjdGl2ZSBtaWxlc3RvbmUuXG4gICAgLy8gVGhpcyBieXBhc3NlcyB0aGUgMzAtc2Vjb25kIHRocm90dGxlIGluIHRoZSBub3JtYWwgcmVidWlsZCBwYXRoIOKAlFxuICAgIC8vIG1pbGVzdG9uZSB0cmFuc2l0aW9ucyBhcmUgcmFyZSBhbmQgaW1wb3J0YW50IGVub3VnaCB0byB3YXJyYW50IGFuXG4gICAgLy8gaW1tZWRpYXRlIHdyaXRlLlxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBkZXBzLnJlYnVpbGRTdGF0ZShzLmJhc2VQYXRoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2dXYXJuaW5nKFwiZW5naW5lXCIsIFwiU1RBVEUubWQgcmVidWlsZCBmYWlsZWQgYWZ0ZXIgbWlsZXN0b25lIHRyYW5zaXRpb25cIiwgeyBlcnJvcjogU3RyaW5nKGUpIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlmIChtaWQpIHtcbiAgICBzLmN1cnJlbnRNaWxlc3RvbmVJZCA9IG1pZDtcbiAgICBkZXBzLnNldEFjdGl2ZU1pbGVzdG9uZUlkKHMuYmFzZVBhdGgsIG1pZCk7XG4gIH1cblxuICAvLyDilIDilIAgVGVybWluYWwgY29uZGl0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBpZiAoIW1pZCkge1xuICAgIGlmIChzLmN1cnJlbnRVbml0KSB7XG4gICAgICBhd2FpdCBkZXBzLmNsb3Nlb3V0VW5pdChcbiAgICAgICAgY3R4LFxuICAgICAgICBzLmJhc2VQYXRoLFxuICAgICAgICBzLmN1cnJlbnRVbml0LnR5cGUsXG4gICAgICAgIHMuY3VycmVudFVuaXQuaWQsXG4gICAgICAgIHMuY3VycmVudFVuaXQuc3RhcnRlZEF0LFxuICAgICAgICBkZXBzLmJ1aWxkU25hcHNob3RPcHRzKHMuY3VycmVudFVuaXQudHlwZSwgcy5jdXJyZW50VW5pdC5pZCksXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGluY29tcGxldGUgPSBzdGF0ZS5yZWdpc3RyeS5maWx0ZXIoXG4gICAgICAobTogeyBzdGF0dXM6IHN0cmluZyB9KSA9PlxuICAgICAgICBtLnN0YXR1cyAhPT0gXCJjb21wbGV0ZVwiICYmIG0uc3RhdHVzICE9PSBcInBhcmtlZFwiLFxuICAgICk7XG4gICAgaWYgKGluY29tcGxldGUubGVuZ3RoID09PSAwICYmIHN0YXRlLnJlZ2lzdHJ5Lmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIEFsbCBtaWxlc3RvbmVzIGNvbXBsZXRlIOKAlCBtZXJnZSBtaWxlc3RvbmUgYnJhbmNoIGJlZm9yZSBzdG9wcGluZy5cbiAgICAgIGlmIChzLmN1cnJlbnRNaWxlc3RvbmVJZCkge1xuICAgICAgICAvLyAjMjkwOSAvICM1NTM4LWZvbGxvd3VwOiBwcmVmbGlnaHQgc3Rhc2ggKyBhbHdheXMtb24gcG9zdGZsaWdodCBwb3AuXG4gICAgICAgIGNvbnN0IHN0b3AgPSBhd2FpdCBfcnVuTWlsZXN0b25lTWVyZ2VPbmNlV2l0aFN0YXNoUmVzdG9yZShpYywgcy5jdXJyZW50TWlsZXN0b25lSWQpO1xuICAgICAgICBpZiAoc3RvcCkgcmV0dXJuIHN0b3A7XG4gICAgICAgIC8vIFBSIGNyZWF0aW9uIChhdXRvX3ByKSBpcyBoYW5kbGVkIGluc2lkZSBtZXJnZU1pbGVzdG9uZVRvTWFpbiAoIzIzMDIpXG4gICAgICB9XG4gICAgICBkZXBzLnNlbmREZXNrdG9wTm90aWZpY2F0aW9uKFxuICAgICAgICBcIkdTRFwiLFxuICAgICAgICBcIkFsbCBtaWxlc3RvbmVzIGNvbXBsZXRlIVwiLFxuICAgICAgICBcInN1Y2Nlc3NcIixcbiAgICAgICAgXCJtaWxlc3RvbmVcIixcbiAgICAgICAgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpLFxuICAgICAgKTtcbiAgICAgIGRlcHMubG9nQ211eEV2ZW50KFxuICAgICAgICBwcmVmcyxcbiAgICAgICAgXCJBbGwgbWlsZXN0b25lcyBjb21wbGV0ZS5cIixcbiAgICAgICAgXCJzdWNjZXNzXCIsXG4gICAgICApO1xuICAgICAgYXdhaXQgZGVwcy5zdG9wQXV0byhjdHgsIHBpLCBcIkFsbCBtaWxlc3RvbmVzIGNvbXBsZXRlXCIsIHtcbiAgICAgICAgY29tcGxldGlvbldpZGdldDoge1xuICAgICAgICAgIG1pbGVzdG9uZUlkOiBzLmN1cnJlbnRNaWxlc3RvbmVJZCxcbiAgICAgICAgICBtaWxlc3RvbmVUaXRsZTogbWlkVGl0bGUsXG4gICAgICAgICAgYWxsTWlsZXN0b25lc0NvbXBsZXRlOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChpbmNvbXBsZXRlLmxlbmd0aCA9PT0gMCAmJiBzdGF0ZS5yZWdpc3RyeS5sZW5ndGggPT09IDApIHtcbiAgICAgIC8vIEVtcHR5IHJlZ2lzdHJ5IOKAlCBubyBtaWxlc3RvbmVzIHZpc2libGUsIGxpa2VseSBhIHBhdGggcmVzb2x1dGlvbiBidWdcbiAgICAgIGNvbnN0IGRpYWcgPSBgYmFzZVBhdGg9JHtzLmJhc2VQYXRofSwgcGhhc2U9JHtzdGF0ZS5waGFzZX1gO1xuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYE5vIG1pbGVzdG9uZXMgdmlzaWJsZSBpbiBjdXJyZW50IHNjb3BlLiBQb3NzaWJsZSBwYXRoIHJlc29sdXRpb24gaXNzdWUuXFxuICAgRGlhZ25vc3RpYzogJHtkaWFnfWAsXG4gICAgICAgIFwiZXJyb3JcIixcbiAgICAgICk7XG4gICAgICBhd2FpdCBkZXBzLnN0b3BBdXRvKFxuICAgICAgICBjdHgsXG4gICAgICAgIHBpLFxuICAgICAgICBgTm8gbWlsZXN0b25lcyBmb3VuZCDigJQgY2hlY2sgYmFzZVBhdGggcmVzb2x1dGlvbmAsXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAoc3RhdGUucGhhc2UgPT09IFwiYmxvY2tlZFwiKSB7XG4gICAgICBjb25zdCBibG9ja2VyTXNnID0gYEJsb2NrZWQ6ICR7c3RhdGUuYmxvY2tlcnMuam9pbihcIiwgXCIpfWA7XG4gICAgICAvLyBQYXVzZSBpbnN0ZWFkIG9mIGhhcmQtc3RvcCBzbyB0aGUgc2Vzc2lvbiBpcyByZXN1bWFibGUgd2l0aCBgL2dzZCBhdXRvYC5cbiAgICAgIC8vIEhhcmQtc3RvcCBoZXJlIHdhcyBjYXVzaW5nIHByZW1hdHVyZSB0ZXJtaW5hdGlvbiB3aGVuIHNsaWNlIGRlcGVuZGVuY2llc1xuICAgICAgLy8gd2VyZSB0ZW1wb3JhcmlseSB1bnJlc29sdmFibGUgKGUuZy4gYWZ0ZXIgcmVhc3Nlc3NtZW50IGFkZGVkIG5ldyBzbGljZXMpLlxuICAgICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSk7XG4gICAgICBjdHgudWkubm90aWZ5KGAke2Jsb2NrZXJNc2d9LiBGaXggYW5kIHJ1biAvZ3NkIGF1dG8gdG8gcmVzdW1lLmAsIFwid2FybmluZ1wiKTtcbiAgICAgIGRlcHMuc2VuZERlc2t0b3BOb3RpZmljYXRpb24oXCJHU0RcIiwgYmxvY2tlck1zZywgXCJ3YXJuaW5nXCIsIFwiYXR0ZW50aW9uXCIsIGJhc2VuYW1lKHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoKSk7XG4gICAgICBkZXBzLmxvZ0NtdXhFdmVudChwcmVmcywgYmxvY2tlck1zZywgXCJ3YXJuaW5nXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBpZHMgPSBpbmNvbXBsZXRlLm1hcCgobTogeyBpZDogc3RyaW5nIH0pID0+IG0uaWQpLmpvaW4oXCIsIFwiKTtcbiAgICAgIGNvbnN0IGRpYWcgPSBgYmFzZVBhdGg9JHtzLmJhc2VQYXRofSwgbWlsZXN0b25lcz1bJHtzdGF0ZS5yZWdpc3RyeS5tYXAoKG06IHsgaWQ6IHN0cmluZzsgc3RhdHVzOiBzdHJpbmcgfSkgPT4gYCR7bS5pZH06JHttLnN0YXR1c31gKS5qb2luKFwiLCBcIil9XSwgcGhhc2U9JHtzdGF0ZS5waGFzZX1gO1xuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYFVuZXhwZWN0ZWQ6ICR7aW5jb21wbGV0ZS5sZW5ndGh9IGluY29tcGxldGUgbWlsZXN0b25lKHMpICgke2lkc30pIGJ1dCBubyBhY3RpdmUgbWlsZXN0b25lLlxcbiAgIERpYWdub3N0aWM6ICR7ZGlhZ31gLFxuICAgICAgICBcImVycm9yXCIsXG4gICAgICApO1xuICAgICAgYXdhaXQgZGVwcy5zdG9wQXV0byhcbiAgICAgICAgY3R4LFxuICAgICAgICBwaSxcbiAgICAgICAgYE5vIGFjdGl2ZSBtaWxlc3RvbmUg4oCUICR7aW5jb21wbGV0ZS5sZW5ndGh9IGluY29tcGxldGUgKCR7aWRzfSksIHNlZSBkaWFnbm9zdGljIGFib3ZlYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJleGl0XCIsIHJlYXNvbjogXCJuby1hY3RpdmUtbWlsZXN0b25lXCIgfSk7XG4gICAgZGVwcy5lbWl0Sm91cm5hbEV2ZW50KHsgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwgZmxvd0lkOiBpYy5mbG93SWQsIHNlcTogaWMubmV4dFNlcSgpLCBldmVudFR5cGU6IFwidGVybWluYWxcIiwgZGF0YTogeyByZWFzb246IFwibm8tYWN0aXZlLW1pbGVzdG9uZVwiIH0gfSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJuby1hY3RpdmUtbWlsZXN0b25lXCIgfTtcbiAgfVxuXG4gIGlmICghbWlkVGl0bGUpIHtcbiAgICBtaWRUaXRsZSA9IG1pZDtcbiAgICBjdHgudWkubm90aWZ5KFxuICAgICAgYE1pbGVzdG9uZSAke21pZH0gaGFzIG5vIHRpdGxlIGluIHJvYWRtYXAg4oCUIHVzaW5nIElEIGFzIGZhbGxiYWNrLmAsXG4gICAgICBcIndhcm5pbmdcIixcbiAgICApO1xuICB9XG5cbiAgLy8gTWlkLW1lcmdlIHNhZmV0eSBjaGVja1xuICBjb25zdCBtZXJnZVJlY29uY2lsZVJlc3VsdCA9IGRlcHMucmVjb25jaWxlTWVyZ2VTdGF0ZShzLmJhc2VQYXRoLCBjdHgpO1xuICBpZiAobWVyZ2VSZWNvbmNpbGVSZXN1bHQgPT09IFwiYmxvY2tlZFwiKSB7XG4gICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSk7XG4gICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImV4aXRcIiwgcmVhc29uOiBcIm1lcmdlLXJlY29uY2lsaWF0aW9uLWJsb2NrZWRcIiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcIm1lcmdlLXJlY29uY2lsaWF0aW9uLWJsb2NrZWRcIiB9O1xuICB9XG4gIGlmIChtZXJnZVJlY29uY2lsZVJlc3VsdCA9PT0gXCJyZWNvbmNpbGVkXCIpIHtcbiAgICBkZXBzLmludmFsaWRhdGVBbGxDYWNoZXMoKTtcbiAgICBzdGF0ZSA9IGF3YWl0IGRlcHMuZGVyaXZlU3RhdGUocy5jYW5vbmljYWxQcm9qZWN0Um9vdCk7XG4gICAgbWlkID0gc3RhdGUuYWN0aXZlTWlsZXN0b25lPy5pZDtcbiAgICBtaWRUaXRsZSA9IHN0YXRlLmFjdGl2ZU1pbGVzdG9uZT8udGl0bGU7XG4gIH1cblxuICBpZiAoIW1pZCB8fCAhbWlkVGl0bGUpIHtcbiAgICBjb25zdCBub01pbGVzdG9uZVJlYXNvbiA9ICFtaWRcbiAgICAgID8gXCJObyBhY3RpdmUgbWlsZXN0b25lIGFmdGVyIG1lcmdlIHJlY29uY2lsaWF0aW9uXCJcbiAgICAgIDogYE1pbGVzdG9uZSAke21pZH0gaGFzIG5vIHRpdGxlIGFmdGVyIHJlY29uY2lsaWF0aW9uYDtcbiAgICBhd2FpdCBjbG9zZW91dEFuZFN0b3AoY3R4LCBwaSwgcywgZGVwcywgbm9NaWxlc3RvbmVSZWFzb24pO1xuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgICAgcGhhc2U6IFwiZXhpdFwiLFxuICAgICAgcmVhc29uOiBcIm5vLW1pbGVzdG9uZS1hZnRlci1yZWNvbmNpbGlhdGlvblwiLFxuICAgIH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwibm8tbWlsZXN0b25lLWFmdGVyLXJlY29uY2lsaWF0aW9uXCIgfTtcbiAgfVxuXG4gIC8vIFRlcm1pbmFsOiBjb21wbGV0ZVxuICBpZiAoc3RhdGUucGhhc2UgPT09IFwiY29tcGxldGVcIikge1xuICAgIC8vIE1pbGVzdG9uZSBtZXJnZSBvbiBjb21wbGV0ZSAoYmVmb3JlIGNsb3Nlb3V0IHNvIGJyYW5jaCBzdGF0ZSBpcyBjbGVhbikuXG4gICAgaWYgKHMuY3VycmVudE1pbGVzdG9uZUlkKSB7XG4gICAgICAvLyAjMjkwOSAvICM1NTM4LWZvbGxvd3VwOiBwcmVmbGlnaHQgc3Rhc2ggKyBhbHdheXMtb24gcG9zdGZsaWdodCBwb3AuXG4gICAgICBjb25zdCBzdG9wID0gYXdhaXQgX3J1bk1pbGVzdG9uZU1lcmdlT25jZVdpdGhTdGFzaFJlc3RvcmUoaWMsIHMuY3VycmVudE1pbGVzdG9uZUlkKTtcbiAgICAgIGlmIChzdG9wKSByZXR1cm4gc3RvcDtcbiAgICAgIC8vIFBSIGNyZWF0aW9uIChhdXRvX3ByKSBpcyBoYW5kbGVkIGluc2lkZSBtZXJnZU1pbGVzdG9uZVRvTWFpbiAoIzIzMDIpXG4gICAgfVxuICAgIGRlcHMuc2VuZERlc2t0b3BOb3RpZmljYXRpb24oXG4gICAgICBcIkdTRFwiLFxuICAgICAgYE1pbGVzdG9uZSAke21pZH0gY29tcGxldGUhYCxcbiAgICAgIFwic3VjY2Vzc1wiLFxuICAgICAgXCJtaWxlc3RvbmVcIixcbiAgICAgIGJhc2VuYW1lKHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoKSxcbiAgICApO1xuICAgIGRlcHMubG9nQ211eEV2ZW50KFxuICAgICAgcHJlZnMsXG4gICAgICBgTWlsZXN0b25lICR7bWlkfSBjb21wbGV0ZS5gLFxuICAgICAgXCJzdWNjZXNzXCIsXG4gICAgKTtcbiAgICBpZiAocy5jdXJyZW50VW5pdCkge1xuICAgICAgYXdhaXQgZGVwcy5jbG9zZW91dFVuaXQoXG4gICAgICAgIGN0eCxcbiAgICAgICAgcy5iYXNlUGF0aCxcbiAgICAgICAgcy5jdXJyZW50VW5pdC50eXBlLFxuICAgICAgICBzLmN1cnJlbnRVbml0LmlkLFxuICAgICAgICBzLmN1cnJlbnRVbml0LnN0YXJ0ZWRBdCxcbiAgICAgICAgZGVwcy5idWlsZFNuYXBzaG90T3B0cyhzLmN1cnJlbnRVbml0LnR5cGUsIHMuY3VycmVudFVuaXQuaWQpLFxuICAgICAgKTtcbiAgICAgIHMuY3VycmVudFVuaXQgPSBudWxsO1xuICAgIH1cbiAgICBhd2FpdCBkZXBzLnN0b3BBdXRvKGN0eCwgcGksIGBNaWxlc3RvbmUgJHttaWR9IGNvbXBsZXRlYCwge1xuICAgICAgY29tcGxldGlvbldpZGdldDoge1xuICAgICAgICBtaWxlc3RvbmVJZDogbWlkLFxuICAgICAgICBtaWxlc3RvbmVUaXRsZTogbWlkVGl0bGUsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJleGl0XCIsIHJlYXNvbjogXCJtaWxlc3RvbmUtY29tcGxldGVcIiB9KTtcbiAgICBkZXBzLmVtaXRKb3VybmFsRXZlbnQoeyB0czogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLCBmbG93SWQ6IGljLmZsb3dJZCwgc2VxOiBpYy5uZXh0U2VxKCksIGV2ZW50VHlwZTogXCJ0ZXJtaW5hbFwiLCBkYXRhOiB7IHJlYXNvbjogXCJtaWxlc3RvbmUtY29tcGxldGVcIiwgbWlsZXN0b25lSWQ6IG1pZCB9IH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwibWlsZXN0b25lLWNvbXBsZXRlXCIgfTtcbiAgfVxuXG4gIC8vIFRlcm1pbmFsOiBibG9ja2VkIOKAlCBwYXVzZSBpbnN0ZWFkIG9mIGhhcmQtc3RvcCBzbyB0aGUgc2Vzc2lvbiBpcyByZXN1bWFibGUuXG4gIGlmIChzdGF0ZS5waGFzZSA9PT0gXCJibG9ja2VkXCIpIHtcbiAgICBjb25zdCBibG9ja2VyTXNnID0gYEJsb2NrZWQ6ICR7c3RhdGUuYmxvY2tlcnMuam9pbihcIiwgXCIpfWA7XG4gICAgaWYgKHMuY3VycmVudFVuaXQpIHtcbiAgICAgIGF3YWl0IGRlcHMuY2xvc2VvdXRVbml0KFxuICAgICAgICBjdHgsXG4gICAgICAgIHMuYmFzZVBhdGgsXG4gICAgICAgIHMuY3VycmVudFVuaXQudHlwZSxcbiAgICAgICAgcy5jdXJyZW50VW5pdC5pZCxcbiAgICAgICAgcy5jdXJyZW50VW5pdC5zdGFydGVkQXQsXG4gICAgICAgIGRlcHMuYnVpbGRTbmFwc2hvdE9wdHMocy5jdXJyZW50VW5pdC50eXBlLCBzLmN1cnJlbnRVbml0LmlkKSxcbiAgICAgICk7XG4gICAgfVxuICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgIGN0eC51aS5ub3RpZnkoYCR7YmxvY2tlck1zZ30uIEZpeCBhbmQgcnVuIC9nc2QgYXV0byB0byByZXN1bWUuYCwgXCJ3YXJuaW5nXCIpO1xuICAgIGRlcHMuc2VuZERlc2t0b3BOb3RpZmljYXRpb24oXCJHU0RcIiwgYmxvY2tlck1zZywgXCJ3YXJuaW5nXCIsIFwiYXR0ZW50aW9uXCIsIGJhc2VuYW1lKHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoKSk7XG4gICAgZGVwcy5sb2dDbXV4RXZlbnQocHJlZnMsIGJsb2NrZXJNc2csIFwid2FybmluZ1wiKTtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwiYmxvY2tlZFwiIH0pO1xuICAgIGRlcHMuZW1pdEpvdXJuYWxFdmVudCh7IHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksIGZsb3dJZDogaWMuZmxvd0lkLCBzZXE6IGljLm5leHRTZXEoKSwgZXZlbnRUeXBlOiBcInRlcm1pbmFsXCIsIGRhdGE6IHsgcmVhc29uOiBcImJsb2NrZWRcIiwgYmxvY2tlcnM6IHN0YXRlLmJsb2NrZXJzIH0gfSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJibG9ja2VkXCIgfTtcbiAgfVxuXG4gIHJldHVybiB7IGFjdGlvbjogXCJuZXh0XCIsIGRhdGE6IHsgc3RhdGUsIG1pZCwgbWlkVGl0bGUgfSB9O1xufVxuXG4vLyDilIDilIDilIAgcnVuRGlzcGF0Y2gg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogUGhhc2UgMzogRGlzcGF0Y2ggcmVzb2x1dGlvbiDigJQgcmVzb2x2ZSBuZXh0IHVuaXQsIHN0dWNrIGRldGVjdGlvbiwgcHJlLWRpc3BhdGNoIGhvb2tzLlxuICogUmV0dXJucyBicmVhay9jb250aW51ZSB0byBjb250cm9sIHRoZSBsb29wLCBvciBuZXh0IHdpdGggSXRlcmF0aW9uRGF0YSBvbiBzdWNjZXNzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuRGlzcGF0Y2goXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICBwcmVEYXRhOiBQcmVEaXNwYXRjaERhdGEsXG4gIGxvb3BTdGF0ZTogTG9vcFN0YXRlLFxuKTogUHJvbWlzZTxQaGFzZVJlc3VsdDxJdGVyYXRpb25EYXRhPj4ge1xuICBjb25zdCB7IGN0eCwgcGksIHMsIGRlcHMsIHByZWZzIH0gPSBpYztcbiAgY29uc3QgeyBzdGF0ZSwgbWlkLCBtaWRUaXRsZSB9ID0gcHJlRGF0YTtcbiAgY29uc3QgU1RVQ0tfV0lORE9XX1NJWkUgPSA2O1xuICBjb25zdCBwcm92aWRlciA9IGN0eC5tb2RlbD8ucHJvdmlkZXI7XG4gIGNvbnN0IGF1dGhNb2RlID0gcHJvdmlkZXIgJiYgdHlwZW9mIGN0eC5tb2RlbFJlZ2lzdHJ5Py5nZXRQcm92aWRlckF1dGhNb2RlID09PSBcImZ1bmN0aW9uXCJcbiAgICA/IGN0eC5tb2RlbFJlZ2lzdHJ5LmdldFByb3ZpZGVyQXV0aE1vZGUocHJvdmlkZXIpXG4gICAgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGFjdGl2ZVRvb2xzID0gdHlwZW9mIHBpLmdldEFjdGl2ZVRvb2xzID09PSBcImZ1bmN0aW9uXCIgPyBwaS5nZXRBY3RpdmVUb29scygpIDogW107XG4gIC8vIERlZXAgcGxhbm5pbmcgaW50ZW50aW9uYWxseSBrZWVwcyBodW1hbiBjaGVja3BvaW50cyBpbiBwbGFpbiBjaGF0LiBJblxuICAvLyBDbGF1ZGUgQ29kZS9sb2NhbCBNQ1AgdHJhbnNwb3J0cywgc3RydWN0dXJlZCBxdWVzdGlvbiByZXF1ZXN0cyBjYW4gYmVcbiAgLy8gY2FuY2VsbGVkIG91dHNpZGUgdGhlIG5vcm1hbCBjaGF0IGZsb3csIHdoaWNoIG1hZGUgYXBwcm92YWwgZ2F0ZXMgZWFzeSB0b1xuICAvLyBza2lwIG9yIGJ1cnkgdW5kZXIgdG9vbCBvdXRwdXQuXG4gIGNvbnN0IHN0cnVjdHVyZWRRdWVzdGlvbnNBdmFpbGFibGUgPSBwcmVmcz8ucGxhbm5pbmdfZGVwdGggPT09IFwiZGVlcFwiXG4gICAgPyBcImZhbHNlXCJcbiAgICA6IHN1cHBvcnRzU3RydWN0dXJlZFF1ZXN0aW9ucyhhY3RpdmVUb29scywge1xuICAgICAgICBhdXRoTW9kZSxcbiAgICAgICAgYmFzZVVybDogY3R4Lm1vZGVsPy5iYXNlVXJsLFxuICAgICAgfSkgPyBcInRydWVcIiA6IFwiZmFsc2VcIjtcblxuICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZGlzcGF0Y2gtcmVzb2x2ZVwiLCBpdGVyYXRpb246IGljLml0ZXJhdGlvbiB9KTtcbiAgY29uc3QgZGlzcGF0Y2hSZXN1bHQgPSBhd2FpdCBkZXBzLnJlc29sdmVEaXNwYXRjaCh7XG4gICAgYmFzZVBhdGg6IHMuYmFzZVBhdGgsXG4gICAgbWlkLFxuICAgIG1pZFRpdGxlLFxuICAgIHN0YXRlLFxuICAgIHByZWZzLFxuICAgIHNlc3Npb246IHMsXG4gICAgc3RydWN0dXJlZFF1ZXN0aW9uc0F2YWlsYWJsZSxcbiAgICBzZXNzaW9uQ29udGV4dFdpbmRvdzogY3R4Lm1vZGVsPy5jb250ZXh0V2luZG93LFxuICAgIHNlc3Npb25Qcm92aWRlcjogY3R4Lm1vZGVsPy5wcm92aWRlcixcbiAgICBtb2RlbFJlZ2lzdHJ5OiBjdHgubW9kZWxSZWdpc3RyeSBhcyBNaW5pbWFsTW9kZWxSZWdpc3RyeSB8IHVuZGVmaW5lZCxcbiAgfSk7XG5cbiAgaWYgKGRpc3BhdGNoUmVzdWx0LmFjdGlvbiA9PT0gXCJzdG9wXCIpIHtcbiAgICBkZXBzLmVtaXRKb3VybmFsRXZlbnQoeyB0czogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLCBmbG93SWQ6IGljLmZsb3dJZCwgc2VxOiBpYy5uZXh0U2VxKCksIGV2ZW50VHlwZTogXCJkaXNwYXRjaC1zdG9wXCIsIHJ1bGU6IGRpc3BhdGNoUmVzdWx0Lm1hdGNoZWRSdWxlLCBkYXRhOiB7IHJlYXNvbjogZGlzcGF0Y2hSZXN1bHQucmVhc29uIH0gfSk7XG4gICAgLy8gV2FybmluZy1sZXZlbCBzdG9wcyBhcmUgcmVjb3ZlcmFibGUgaHVtYW4gY2hlY2twb2ludHMgKGUuZy4gVUFUIHZlcmRpY3RcbiAgICAvLyBnYXRlKSDigJQgcGF1c2UgaW5zdGVhZCBvZiBoYXJkLXN0b3BwaW5nIHNvIHRoZSBzZXNzaW9uIGlzIHJlc3VtYWJsZSB3aXRoXG4gICAgLy8gYC9nc2QgYXV0b2AuIEVycm9yL2luZm8tbGV2ZWwgc3RvcHMgcmVtYWluIGhhcmQgc3RvcHMgZm9yIGluZnJhc3RydWN0dXJlXG4gICAgLy8gZmFpbHVyZXMgYW5kIHRlcm1pbmFsIGNvbmRpdGlvbnMgcmVzcGVjdGl2ZWx5LlxuICAgIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2dzZC1idWlsZC9nc2QtMi9pc3N1ZXMvMjQ3NFxuICAgIGlmIChkaXNwYXRjaFJlc3VsdC5sZXZlbCA9PT0gXCJ3YXJuaW5nXCIpIHtcbiAgICAgIGN0eC51aS5ub3RpZnkoZGlzcGF0Y2hSZXN1bHQucmVhc29uLCBcIndhcm5pbmdcIik7XG4gICAgICBhd2FpdCBkZXBzLnBhdXNlQXV0byhjdHgsIHBpLCB7XG4gICAgICAgIG1lc3NhZ2U6IGRpc3BhdGNoUmVzdWx0LnJlYXNvbixcbiAgICAgICAgY2F0ZWdvcnk6IFwidW5rbm93blwiLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGNsb3Nlb3V0QW5kU3RvcChjdHgsIHBpLCBzLCBkZXBzLCBkaXNwYXRjaFJlc3VsdC5yZWFzb24pO1xuICAgIH1cbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwiZGlzcGF0Y2gtc3RvcFwiIH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwiZGlzcGF0Y2gtc3RvcFwiIH07XG4gIH1cblxuICBpZiAoZGlzcGF0Y2hSZXN1bHQuYWN0aW9uICE9PSBcImRpc3BhdGNoXCIpIHtcbiAgICAvLyBOb24tZGlzcGF0Y2ggYWN0aW9uIChlLmcuIFwic2tpcFwiKSDigJQgcmUtZGVyaXZlIHN0YXRlXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHIpID0+IHNldEltbWVkaWF0ZShyKSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImNvbnRpbnVlXCIgfTtcbiAgfVxuXG4gIGRlcHMuZW1pdEpvdXJuYWxFdmVudCh7IHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksIGZsb3dJZDogaWMuZmxvd0lkLCBzZXE6IGljLm5leHRTZXEoKSwgZXZlbnRUeXBlOiBcImRpc3BhdGNoLW1hdGNoXCIsIHJ1bGU6IGRpc3BhdGNoUmVzdWx0Lm1hdGNoZWRSdWxlLCBkYXRhOiB7IHVuaXRUeXBlOiBkaXNwYXRjaFJlc3VsdC51bml0VHlwZSwgdW5pdElkOiBkaXNwYXRjaFJlc3VsdC51bml0SWQgfSB9KTtcblxuICBsZXQgdW5pdFR5cGUgPSBkaXNwYXRjaFJlc3VsdC51bml0VHlwZTtcbiAgbGV0IHVuaXRJZCA9IGRpc3BhdGNoUmVzdWx0LnVuaXRJZDtcbiAgbGV0IHByb21wdCA9IGRpc3BhdGNoUmVzdWx0LnByb21wdDtcbiAgY29uc3QgcGF1c2VBZnRlclVhdERpc3BhdGNoID0gZGlzcGF0Y2hSZXN1bHQucGF1c2VBZnRlckRpc3BhdGNoID8/IGZhbHNlO1xuXG4gIC8vIFJlc29sdmUgaG9va3MgYW5kIHByaW9yLXNsaWNlIGdhdGluZyBiZWZvcmUgaGVhbHRoL3N0dWNrIGFjY291bnRpbmcgc29cbiAgLy8gdGhvc2UgY2hlY2tzIHJ1biBhZ2FpbnN0IHRoZSBmaW5hbCBkaXNwYXRjaCB1bml0LlxuICBjb25zdCBwcmVEaXNwYXRjaFJlc3VsdCA9IGRlcHMucnVuUHJlRGlzcGF0Y2hIb29rcyhcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgcHJvbXB0LFxuICAgIHMuYmFzZVBhdGgsXG4gICk7XG4gIGlmIChwcmVEaXNwYXRjaFJlc3VsdC5maXJlZEhvb2tzLmxlbmd0aCA+IDApIHtcbiAgICBjdHgudWkubm90aWZ5KFxuICAgICAgYFByZS1kaXNwYXRjaCBob29rJHtwcmVEaXNwYXRjaFJlc3VsdC5maXJlZEhvb2tzLmxlbmd0aCA+IDEgPyBcInNcIiA6IFwiXCJ9OiAke3ByZURpc3BhdGNoUmVzdWx0LmZpcmVkSG9va3Muam9pbihcIiwgXCIpfWAsXG4gICAgICBcImluZm9cIixcbiAgICApO1xuICAgIGRlcHMuZW1pdEpvdXJuYWxFdmVudCh7IHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksIGZsb3dJZDogaWMuZmxvd0lkLCBzZXE6IGljLm5leHRTZXEoKSwgZXZlbnRUeXBlOiBcInByZS1kaXNwYXRjaC1ob29rXCIsIGRhdGE6IHsgZmlyZWRIb29rczogcHJlRGlzcGF0Y2hSZXN1bHQuZmlyZWRIb29rcywgYWN0aW9uOiBwcmVEaXNwYXRjaFJlc3VsdC5hY3Rpb24gfSB9KTtcbiAgfVxuICBpZiAocHJlRGlzcGF0Y2hSZXN1bHQuYWN0aW9uID09PSBcInNraXBcIikge1xuICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICBgU2tpcHBpbmcgJHt1bml0VHlwZX0gJHt1bml0SWR9IChwcmUtZGlzcGF0Y2ggaG9vaykuYCxcbiAgICAgIFwiaW5mb1wiLFxuICAgICk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHIpID0+IHNldEltbWVkaWF0ZShyKSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImNvbnRpbnVlXCIgfTtcbiAgfVxuICBpZiAocHJlRGlzcGF0Y2hSZXN1bHQuYWN0aW9uID09PSBcInJlcGxhY2VcIikge1xuICAgIHByb21wdCA9IHByZURpc3BhdGNoUmVzdWx0LnByb21wdCA/PyBwcm9tcHQ7XG4gICAgaWYgKHByZURpc3BhdGNoUmVzdWx0LnVuaXRUeXBlKSB1bml0VHlwZSA9IHByZURpc3BhdGNoUmVzdWx0LnVuaXRUeXBlO1xuICB9IGVsc2UgaWYgKHByZURpc3BhdGNoUmVzdWx0LnByb21wdCkge1xuICAgIHByb21wdCA9IHByZURpc3BhdGNoUmVzdWx0LnByb21wdDtcbiAgfVxuXG4gIGNvbnN0IGd1YXJkQmFzZVBhdGggPSBfcmVzb2x2ZURpc3BhdGNoR3VhcmRCYXNlUGF0aChzKTtcbiAgbGV0IG1haW5CcmFuY2ggPSBcIm1haW5cIjtcbiAgdHJ5IHtcbiAgICBtYWluQnJhbmNoID0gZGVwcy5nZXRNYWluQnJhbmNoKGd1YXJkQmFzZVBhdGgpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZ2V0TWFpbkJyYW5jaC1mYWlsZWRcIiwgZXJyb3I6IFN0cmluZyhlcnIpIH0pO1xuICB9XG4gIGNvbnN0IHByaW9yU2xpY2VCbG9ja2VyID0gZGVwcy5nZXRQcmlvclNsaWNlQ29tcGxldGlvbkJsb2NrZXIoXG4gICAgZ3VhcmRCYXNlUGF0aCxcbiAgICBtYWluQnJhbmNoLFxuICAgIHVuaXRUeXBlLFxuICAgIHVuaXRJZCxcbiAgKTtcbiAgaWYgKHByaW9yU2xpY2VCbG9ja2VyKSB7XG4gICAgYXdhaXQgZGVwcy5zdG9wQXV0byhjdHgsIHBpLCBwcmlvclNsaWNlQmxvY2tlcik7XG4gICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImV4aXRcIiwgcmVhc29uOiBcInByaW9yLXNsaWNlLWJsb2NrZXJcIiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInByaW9yLXNsaWNlLWJsb2NrZXJcIiB9O1xuICB9XG5cbiAgY29uc3QgY29uc2VjdXRpdmVEaXNwYXRjaEJsb2NrZXIgPSBnZXRDb25zZWN1dGl2ZURpc3BhdGNoQmxvY2tlcihcbiAgICBsb29wU3RhdGUsXG4gICAgc3RhdGUucGhhc2UsXG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICApO1xuICBpZiAoY29uc2VjdXRpdmVEaXNwYXRjaEJsb2NrZXIpIHtcbiAgICBhd2FpdCBkZXBzLnN0b3BBdXRvKGN0eCwgcGksIGNvbnNlY3V0aXZlRGlzcGF0Y2hCbG9ja2VyKTtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwiY29uc2VjdXRpdmUtZGlzcGF0Y2gtYmxvY2tlclwiIH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwiY29uc2VjdXRpdmUtZGlzcGF0Y2gtYmxvY2tlclwiIH07XG4gIH1cblxuICBjb25zdCB3b3JrdHJlZVNhZmV0eUJsb2NrID0gYXdhaXQgdmFsaWRhdGVTb3VyY2VXcml0ZVdvcmt0cmVlU2FmZXR5KFxuICAgIGljLFxuICAgIHVuaXRUeXBlLFxuICAgIHVuaXRJZCxcbiAgICBtaWQsXG4gICAgXCJwcmUtZGlzcGF0Y2hcIixcbiAgKTtcbiAgaWYgKHdvcmt0cmVlU2FmZXR5QmxvY2spIHJldHVybiB3b3JrdHJlZVNhZmV0eUJsb2NrO1xuXG4gIC8vIOKUgOKUgCBTbGlkaW5nLXdpbmRvdyBzdHVjayBkZXRlY3Rpb24gd2l0aCBncmFkdWF0ZWQgcmVjb3Zlcnkg4pSA4pSAXG4gIGNvbnN0IGRlcml2ZWRLZXkgPSBgJHt1bml0VHlwZX0vJHt1bml0SWR9YDtcblxuICAvLyBBbHdheXMgcmVjb3JkIHRoaXMgZGlzcGF0Y2ggaW4gdGhlIHNsaWRpbmcgd2luZG93IGFuZCBydW4gZGV0ZWN0aW9uIHNvXG4gIC8vIFJ1bGVzIDEvMy80IGNhbiBjYXRjaCByZXRyeSBsb29wcyB3aXRoIHJlcGVhdGVkIGZhaWx1cmUgY29udGVudCAoIzU3MTkpLlxuICAvLyBSdWxlcyAyLzJiIHN1cHByZXNzIGxlZ2l0aW1hdGUgcmV0cnkgYmFja29mZiB0aHJvdWdoIHRoZSBkaXNwYXRjaCBsZWRnZXIuXG4gIGxvb3BTdGF0ZS5yZWNlbnRVbml0cy5wdXNoKHsga2V5OiBkZXJpdmVkS2V5IH0pO1xuICBpZiAobG9vcFN0YXRlLnJlY2VudFVuaXRzLmxlbmd0aCA+IFNUVUNLX1dJTkRPV19TSVpFKSBsb29wU3RhdGUucmVjZW50VW5pdHMuc2hpZnQoKTtcblxuICBjb25zdCBzdHVja1NpZ25hbCA9IGRldGVjdFN0dWNrKGxvb3BTdGF0ZS5yZWNlbnRVbml0cyk7XG4gIGlmIChzdHVja1NpZ25hbCkge1xuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICAgIHBoYXNlOiBcInN0dWNrLWNoZWNrXCIsXG4gICAgICAgIHVuaXRUeXBlLFxuICAgICAgICB1bml0SWQsXG4gICAgICAgIHJlYXNvbjogc3R1Y2tTaWduYWwucmVhc29uLFxuICAgICAgICByZWNvdmVyeUF0dGVtcHRzOiBsb29wU3RhdGUuc3R1Y2tSZWNvdmVyeUF0dGVtcHRzLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChsb29wU3RhdGUuc3R1Y2tSZWNvdmVyeUF0dGVtcHRzID09PSAwKSB7XG4gICAgICAgIC8vIExldmVsIDE6IHRyeSB2ZXJpZnlpbmcgdGhlIGFydGlmYWN0LCB0aGVuIGNhY2hlIGludmFsaWRhdGlvbiArIHJldHJ5XG4gICAgICAgIGxvb3BTdGF0ZS5zdHVja1JlY292ZXJ5QXR0ZW1wdHMrKztcbiAgICAgICAgY29uc3QgYXJ0aWZhY3RFeGlzdHMgPSB2ZXJpZnlFeHBlY3RlZEFydGlmYWN0KFxuICAgICAgICAgIHVuaXRUeXBlLFxuICAgICAgICAgIHVuaXRJZCxcbiAgICAgICAgICBzLmJhc2VQYXRoLFxuICAgICAgICApO1xuICAgICAgICBpZiAoYXJ0aWZhY3RFeGlzdHMpIHtcbiAgICAgICAgICBpZiAodW5pdFR5cGUgPT09IFwiY29tcGxldGUtbWlsZXN0b25lXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IHN0dWNrRGlhZyA9IGRpYWdub3NlRXhwZWN0ZWRBcnRpZmFjdCh1bml0VHlwZSwgdW5pdElkLCBzLmJhc2VQYXRoKTtcbiAgICAgICAgICAgIGNvbnN0IHN0dWNrUGFydHMgPSBbXG4gICAgICAgICAgICAgIGBEZXRlY3RlZCAke3VuaXRUeXBlfSAke3VuaXRJZH0gb3V0cHV0IG9uIGRpc2ssIGJ1dCB0aGUgc2FtZSB1bml0IGlzIHN0aWxsIGJlaW5nIGRlcml2ZWQuYCxcbiAgICAgICAgICAgICAgXCJUaGlzIHVzdWFsbHkgbWVhbnMgdGhlIG1pbGVzdG9uZSBzdW1tYXJ5IGV4aXN0cyB3aGlsZSB0aGUgREIgcm93IHN0aWxsIGRvZXMgbm90IG1hcmsgdGhlIG1pbGVzdG9uZSBjb21wbGV0ZS5cIixcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBpZiAoc3R1Y2tEaWFnKSBzdHVja1BhcnRzLnB1c2goYEV4cGVjdGVkOiAke3N0dWNrRGlhZ31gKTtcbiAgICAgICAgICAgIGN0eC51aS5ub3RpZnkoc3R1Y2tQYXJ0cy5qb2luKFwiIFwiKSwgXCJ3YXJuaW5nXCIpO1xuICAgICAgICAgICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSk7XG4gICAgICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcImNvbXBsZXRlLW1pbGVzdG9uZS1hcnRpZmFjdC1kYi1taXNtYXRjaFwiIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgICAgICAgICAgcGhhc2U6IFwic3R1Y2stcmVjb3ZlcnlcIixcbiAgICAgICAgICAgIGxldmVsOiAxLFxuICAgICAgICAgICAgYWN0aW9uOiBcImFydGlmYWN0LWZvdW5kXCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgY29uc3QgcmVjb3ZlcnlEYiA9IHJlZnJlc2hSZWNvdmVyeURiRm9yQXJ0aWZhY3QodW5pdFR5cGUsIHVuaXRJZCk7XG4gICAgICAgICAgaWYgKCFyZWNvdmVyeURiLm9rKSB7XG4gICAgICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgICAgICByZWNvdmVyeURiLmZhdGFsXG4gICAgICAgICAgICAgICAgPyBgJHtyZWNvdmVyeURiLm1lc3NhZ2V9IFBhdXNpbmcgYXV0by1tb2RlIGZvciBtYW51YWwgcmVjb3ZlcnkuYFxuICAgICAgICAgICAgICAgIDogYCR7cmVjb3ZlcnlEYi5tZXNzYWdlfSBLZWVwaW5nIHN0dWNrIHN0YXRlIGZvciByZXRyeS5gLFxuICAgICAgICAgICAgICBcIndhcm5pbmdcIixcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAocmVjb3ZlcnlEYi5mYXRhbCkge1xuICAgICAgICAgICAgICBhd2FpdCBkZXBzLnBhdXNlQXV0byhjdHgsIHBpKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogcmVjb3ZlcnlEYi5yZWFzb24gfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7IGFjdGlvbjogXCJjb250aW51ZVwiIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgICAgICBgU3R1Y2sgcmVjb3Zlcnk6IGFydGlmYWN0IGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH0gZm91bmQgb24gZGlzay4gSW52YWxpZGF0aW5nIGNhY2hlcy5gLFxuICAgICAgICAgICAgXCJpbmZvXCIsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBkZXBzLmludmFsaWRhdGVBbGxDYWNoZXMoKTtcbiAgICAgICAgICBsb29wU3RhdGUucmVjZW50VW5pdHMubGVuZ3RoID0gMDtcbiAgICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiY29udGludWVcIiB9O1xuICAgICAgICB9XG4gICAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgICAgYFN0dWNrIG9uICR7dW5pdFR5cGV9ICR7dW5pdElkfSAoJHtzdHVja1NpZ25hbC5yZWFzb259KS4gSW52YWxpZGF0aW5nIGNhY2hlcyBhbmQgcmV0cnlpbmcuYCxcbiAgICAgICAgICBcIndhcm5pbmdcIixcbiAgICAgICAgKTtcbiAgICAgICAgZGVwcy5pbnZhbGlkYXRlQWxsQ2FjaGVzKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBMZXZlbCAyOiBoYXJkIHN0b3Ag4oCUIGdlbnVpbmVseSBzdHVja1xuICAgICAgICBkZXBzLmludmFsaWRhdGVBbGxDYWNoZXMoKTtcbiAgICAgICAgY29uc3QgYXJ0aWZhY3RFeGlzdHMgPSB2ZXJpZnlFeHBlY3RlZEFydGlmYWN0KFxuICAgICAgICAgIHVuaXRUeXBlLFxuICAgICAgICAgIHVuaXRJZCxcbiAgICAgICAgICBzLmJhc2VQYXRoLFxuICAgICAgICApO1xuICAgICAgICBpZiAoYXJ0aWZhY3RFeGlzdHMgJiYgdW5pdFR5cGUgIT09IFwiY29tcGxldGUtbWlsZXN0b25lXCIpIHtcbiAgICAgICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHtcbiAgICAgICAgICAgIHBoYXNlOiBcInN0dWNrLXJlY292ZXJ5XCIsXG4gICAgICAgICAgICBsZXZlbDogMixcbiAgICAgICAgICAgIGFjdGlvbjogXCJhcnRpZmFjdC1mb3VuZFwiLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnN0IHJlY292ZXJ5RGIgPSByZWZyZXNoUmVjb3ZlcnlEYkZvckFydGlmYWN0KHVuaXRUeXBlLCB1bml0SWQpO1xuICAgICAgICAgIGlmIChyZWNvdmVyeURiLm9rKSB7XG4gICAgICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgICAgICBgU3R1Y2sgcmVjb3Zlcnk6IGFydGlmYWN0IGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH0gZm91bmQgb24gZGlzayBhZnRlciBjYWNoZSBpbnZhbGlkYXRpb24uIENvbnRpbnVpbmcuYCxcbiAgICAgICAgICAgICAgXCJpbmZvXCIsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbG9vcFN0YXRlLnJlY2VudFVuaXRzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICBsb29wU3RhdGUuc3R1Y2tSZWNvdmVyeUF0dGVtcHRzID0gMDtcbiAgICAgICAgICAgIHJldHVybiB7IGFjdGlvbjogXCJjb250aW51ZVwiIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgICAgICByZWNvdmVyeURiLmZhdGFsXG4gICAgICAgICAgICAgID8gYCR7cmVjb3ZlcnlEYi5tZXNzYWdlfSBQYXVzaW5nIGF1dG8tbW9kZSBmb3IgbWFudWFsIHJlY292ZXJ5LmBcbiAgICAgICAgICAgICAgOiBgJHtyZWNvdmVyeURiLm1lc3NhZ2V9IFN0b3BwaW5nIGZvciBtYW51YWwgcmVjb3ZlcnkuYCxcbiAgICAgICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKHJlY292ZXJ5RGIuZmF0YWwpIHtcbiAgICAgICAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogcmVjb3ZlcnlEYi5yZWFzb24gfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICAgICAgcGhhc2U6IFwic3R1Y2stZGV0ZWN0ZWRcIixcbiAgICAgICAgICB1bml0VHlwZSxcbiAgICAgICAgICB1bml0SWQsXG4gICAgICAgICAgcmVhc29uOiBzdHVja1NpZ25hbC5yZWFzb24sXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBzdHVja0RpYWcgPSBkaWFnbm9zZUV4cGVjdGVkQXJ0aWZhY3QodW5pdFR5cGUsIHVuaXRJZCwgcy5iYXNlUGF0aCk7XG4gICAgICAgIGNvbnN0IHN0dWNrUmVtZWRpYXRpb24gPSBidWlsZExvb3BSZW1lZGlhdGlvblN0ZXBzKHVuaXRUeXBlLCB1bml0SWQsIHMuYmFzZVBhdGgpO1xuICAgICAgICBjb25zdCBzdHVja1BhcnRzID0gW2BTdHVjayBvbiAke3VuaXRUeXBlfSAke3VuaXRJZH0g4oCUICR7c3R1Y2tTaWduYWwucmVhc29ufS5gXTtcbiAgICAgICAgaWYgKHN0dWNrRGlhZykgc3R1Y2tQYXJ0cy5wdXNoKGBFeHBlY3RlZDogJHtzdHVja0RpYWd9YCk7XG4gICAgICAgIGlmIChzdHVja1JlbWVkaWF0aW9uKSBzdHVja1BhcnRzLnB1c2goYFRvIHJlY292ZXI6XFxuJHtzdHVja1JlbWVkaWF0aW9ufWApO1xuICAgICAgICBjdHgudWkubm90aWZ5KHN0dWNrUGFydHMuam9pbihcIiBcIiksIFwiZXJyb3JcIik7XG4gICAgICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oXG4gICAgICAgICAgY3R4LFxuICAgICAgICAgIHBpLFxuICAgICAgICAgIGBTdHVjazogJHtzdHVja1NpZ25hbC5yZWFzb259YCxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJzdHVjay1kZXRlY3RlZFwiIH07XG4gICAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gUHJvZ3Jlc3MgZGV0ZWN0ZWQg4oCUIHJlc2V0IHJlY292ZXJ5IGNvdW50ZXJcbiAgICBpZiAobG9vcFN0YXRlLnN0dWNrUmVjb3ZlcnlBdHRlbXB0cyA+IDApIHtcbiAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgICAgICBwaGFzZTogXCJzdHVjay1jb3VudGVyLXJlc2V0XCIsXG4gICAgICAgIGZyb206IGxvb3BTdGF0ZS5yZWNlbnRVbml0c1tsb29wU3RhdGUucmVjZW50VW5pdHMubGVuZ3RoIC0gMl0/LmtleSA/PyBcIlwiLFxuICAgICAgICB0bzogZGVyaXZlZEtleSxcbiAgICAgIH0pO1xuICAgICAgbG9vcFN0YXRlLnN0dWNrUmVjb3ZlcnlBdHRlbXB0cyA9IDA7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBhY3Rpb246IFwibmV4dFwiLFxuICAgIGRhdGE6IHtcbiAgICAgIHVuaXRUeXBlLCB1bml0SWQsIHByb21wdCwgZmluYWxQcm9tcHQ6IHByb21wdCxcbiAgICAgIHBhdXNlQWZ0ZXJVYXREaXNwYXRjaCxcbiAgICAgIHN0YXRlLCBtaWQsIG1pZFRpdGxlLFxuICAgICAgaXNSZXRyeTogZmFsc2UsIHByZXZpb3VzVGllcjogdW5kZWZpbmVkLFxuICAgICAgaG9va01vZGVsT3ZlcnJpZGU6IHByZURpc3BhdGNoUmVzdWx0Lm1vZGVsLFxuICAgIH0sXG4gIH07XG59XG5cbi8vIOKUgOKUgOKUgCBydW5HdWFyZHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogUGhhc2UgMjogR3VhcmRzIOKAlCBzdG9wIGRpcmVjdGl2ZXMsIGJ1ZGdldCBjZWlsaW5nLCBjb250ZXh0IHdpbmRvdywgc2VjcmV0cyByZS1jaGVjay5cbiAqIFJldHVybnMgYnJlYWsgdG8gZXhpdCB0aGUgbG9vcCwgb3IgbmV4dCB0byBwcm9jZWVkIHRvIGRpc3BhdGNoLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuR3VhcmRzKFxuICBpYzogSXRlcmF0aW9uQ29udGV4dCxcbiAgbWlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPFBoYXNlUmVzdWx0PiB7XG4gIGNvbnN0IHsgY3R4LCBwaSwgcywgZGVwcywgcHJlZnMgfSA9IGljO1xuXG4gIC8vIOKUgOKUgCBTdG9wL0JhY2t0cmFjayBkaXJlY3RpdmUgZ3VhcmQgKCMzNDg3KSDilIDilIBcbiAgLy8gQ2hlY2sgZm9yIHVuZXhlY3V0ZWQgc3RvcCBvciBiYWNrdHJhY2sgY2FwdHVyZXMgQkVGT1JFIGRpc3BhdGNoaW5nIGFueSB1bml0LlxuICAvLyBUaGlzIGVuc3VyZXMgdXNlciBcImhhbHRcIiBkaXJlY3RpdmVzIGFyZSBob25vcmVkIGltbWVkaWF0ZWx5LlxuICAvLyBJTVBPUlRBTlQ6IEZhaWwtY2xvc2VkIOKAlCBhbnkgZXhjZXB0aW9uIGR1cmluZyBzdG9wIGhhbmRsaW5nIHN0aWxsIGJyZWFrcyB0aGUgbG9vcFxuICAvLyB0byBlbnN1cmUgdXNlciBoYWx0IGludGVudCBpcyBuZXZlciBzaWxlbnRseSBkcm9wcGVkLlxuICB0cnkge1xuICAgIGNvbnN0IHsgbG9hZFN0b3BDYXB0dXJlcywgbWFya0NhcHR1cmVFeGVjdXRlZCB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vY2FwdHVyZXMuanNcIik7XG4gICAgY29uc3Qgc3RvcENhcHR1cmVzID0gbG9hZFN0b3BDYXB0dXJlcyhzLmJhc2VQYXRoKTtcbiAgICBpZiAoc3RvcENhcHR1cmVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGZpcnN0ID0gc3RvcENhcHR1cmVzWzBdO1xuICAgICAgY29uc3QgaXNCYWNrdHJhY2sgPSBmaXJzdC5jbGFzc2lmaWNhdGlvbiA9PT0gXCJiYWNrdHJhY2tcIjtcbiAgICAgIGNvbnN0IGxhYmVsID0gaXNCYWNrdHJhY2tcbiAgICAgICAgPyBgQmFja3RyYWNrIGRpcmVjdGl2ZTogJHtmaXJzdC50ZXh0fWBcbiAgICAgICAgOiBgU3RvcCBkaXJlY3RpdmU6ICR7Zmlyc3QudGV4dH1gO1xuXG4gICAgICBjdHgudWkubm90aWZ5KGxhYmVsLCBcIndhcm5pbmdcIik7XG4gICAgICBkZXBzLnNlbmREZXNrdG9wTm90aWZpY2F0aW9uKFxuICAgICAgICBcIkdTRFwiLCBsYWJlbCwgXCJ3YXJuaW5nXCIsIFwic3RvcC1kaXJlY3RpdmVcIixcbiAgICAgICAgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpLFxuICAgICAgKTtcblxuICAgICAgLy8gUGF1c2UgZmlyc3Qg4oCUIGVuc3VyZXMgYXV0by1tb2RlIHN0b3BzIGV2ZW4gaWYgbGF0ZXIgc3RlcHMgZmFpbFxuICAgICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSk7XG5cbiAgICAgIC8vIEZvciBiYWNrdHJhY2sgY2FwdHVyZXMsIHdyaXRlIHRoZSBiYWNrdHJhY2sgdHJpZ2dlciBhZnRlciBwYXVzaW5nXG4gICAgICBpZiAoaXNCYWNrdHJhY2spIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB7IGV4ZWN1dGVCYWNrdHJhY2sgfSA9IGF3YWl0IGltcG9ydChcIi4uL3RyaWFnZS1yZXNvbHV0aW9uLmpzXCIpO1xuICAgICAgICAgIGV4ZWN1dGVCYWNrdHJhY2socy5iYXNlUGF0aCwgbWlkLCBmaXJzdCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBkZWJ1Z0xvZyhcImd1YXJkc1wiLCB7IHBoYXNlOiBcImJhY2t0cmFjay1leGVjdXRpb24tZXJyb3JcIiwgZXJyb3I6IFN0cmluZyhlKSB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBNYXJrIGNhcHR1cmVzIGFzIGV4ZWN1dGVkIG9ubHkgYWZ0ZXIgc3VjY2Vzc2Z1bCBwYXVzZS90cmFuc2l0aW9uXG4gICAgICBmb3IgKGNvbnN0IGNhcCBvZiBzdG9wQ2FwdHVyZXMpIHtcbiAgICAgICAgbWFya0NhcHR1cmVFeGVjdXRlZChzLmJhc2VQYXRoLCBjYXAuaWQpO1xuICAgICAgfVxuXG4gICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IGlzQmFja3RyYWNrID8gXCJ1c2VyLWJhY2t0cmFja1wiIDogXCJ1c2VyLXN0b3BcIiB9KTtcbiAgICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IGlzQmFja3RyYWNrID8gXCJ1c2VyLWJhY2t0cmFja1wiIDogXCJ1c2VyLXN0b3BcIiB9O1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIC8vIEZhaWwtY2xvc2VkOiBpZiBhbnl0aGluZyBpbiB0aGUgc3RvcCBndWFyZCB0aHJvd3MsIGJyZWFrIHRoZSBsb29wXG4gICAgLy8gcmF0aGVyIHRoYW4gc2lsZW50bHkgY29udGludWluZyBhbmQgZHJvcHBpbmcgdXNlciBoYWx0IGludGVudFxuICAgIGRlYnVnTG9nKFwiZ3VhcmRzXCIsIHsgcGhhc2U6IFwic3RvcC1ndWFyZC1lcnJvclwiLCBlcnJvcjogU3RyaW5nKGUpIH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwic3RvcC1ndWFyZC1lcnJvclwiIH07XG4gIH1cblxuICAvLyBCdWRnZXQgY2VpbGluZyBndWFyZFxuICBjb25zdCBidWRnZXRDZWlsaW5nID0gcHJlZnM/LmJ1ZGdldF9jZWlsaW5nO1xuICBpZiAoYnVkZ2V0Q2VpbGluZyAhPT0gdW5kZWZpbmVkICYmIGJ1ZGdldENlaWxpbmcgPiAwKSB7XG4gICAgY29uc3QgY3VycmVudExlZGdlciA9IGRlcHMuZ2V0TGVkZ2VyKCkgYXMgeyB1bml0czogdW5rbm93biB9IHwgbnVsbDtcbiAgICAvLyBJbiBwYXJhbGxlbCB3b3JrZXIgbW9kZSwgb25seSBjb3VudCBjb3N0IGZyb20gdGhlIGN1cnJlbnQgYXV0by1tb2RlIHNlc3Npb25cbiAgICAvLyB0byBhdm9pZCBoaXR0aW5nIHRoZSBjZWlsaW5nIGR1ZSB0byBoaXN0b3JpY2FsIHByb2plY3Qtd2lkZSBzcGVuZCAoIzIxODQpLlxuICAgIGxldCBjb3N0VW5pdHMgPSBjdXJyZW50TGVkZ2VyPy51bml0cztcbiAgICBpZiAocHJvY2Vzcy5lbnYuR1NEX1BBUkFMTEVMX1dPUktFUiAmJiBzLmF1dG9TdGFydFRpbWUgJiYgQXJyYXkuaXNBcnJheShjb3N0VW5pdHMpKSB7XG4gICAgICBjb25zdCBzZXNzaW9uU3RhcnRJU08gPSBuZXcgRGF0ZShzLmF1dG9TdGFydFRpbWUpLnRvSVNPU3RyaW5nKCk7XG4gICAgICBjb3N0VW5pdHMgPSBjb3N0VW5pdHMuZmlsdGVyKFxuICAgICAgICAodTogeyBzdGFydGVkQXQ/OiBzdHJpbmcgfSkgPT4gdS5zdGFydGVkQXQgIT0gbnVsbCAmJiB1LnN0YXJ0ZWRBdCA+PSBzZXNzaW9uU3RhcnRJU08sXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCB0b3RhbENvc3QgPSBjb3N0VW5pdHNcbiAgICAgID8gZGVwcy5nZXRQcm9qZWN0VG90YWxzKGNvc3RVbml0cykuY29zdFxuICAgICAgOiAwO1xuICAgIGNvbnN0IGJ1ZGdldFBjdCA9IHRvdGFsQ29zdCAvIGJ1ZGdldENlaWxpbmc7XG4gICAgY29uc3QgYnVkZ2V0QWxlcnRMZXZlbCA9IGRlcHMuZ2V0QnVkZ2V0QWxlcnRMZXZlbChidWRnZXRQY3QpO1xuICAgIGNvbnN0IG5ld0J1ZGdldEFsZXJ0TGV2ZWwgPSBkZXBzLmdldE5ld0J1ZGdldEFsZXJ0TGV2ZWwoXG4gICAgICBzLmxhc3RCdWRnZXRBbGVydExldmVsLFxuICAgICAgYnVkZ2V0UGN0LFxuICAgICk7XG4gICAgY29uc3QgZW5mb3JjZW1lbnQgPSBwcmVmcz8uYnVkZ2V0X2VuZm9yY2VtZW50ID8/IFwicGF1c2VcIjtcbiAgICBjb25zdCBidWRnZXRFbmZvcmNlbWVudEFjdGlvbiA9IGRlcHMuZ2V0QnVkZ2V0RW5mb3JjZW1lbnRBY3Rpb24oXG4gICAgICBlbmZvcmNlbWVudCxcbiAgICAgIGJ1ZGdldFBjdCxcbiAgICApO1xuXG4gICAgLy8gRGF0YS1kcml2ZW4gdGhyZXNob2xkIGNoZWNrIOKAlCBsb29wIGRlc2NlbmRpbmcsIGZpcmUgZmlyc3QgbWF0Y2hcbiAgICBjb25zdCB0aHJlc2hvbGQgPSBCVURHRVRfVEhSRVNIT0xEUy5maW5kKFxuICAgICAgKHQpID0+IG5ld0J1ZGdldEFsZXJ0TGV2ZWwgPj0gdC5wY3QsXG4gICAgKTtcbiAgICBpZiAodGhyZXNob2xkKSB7XG4gICAgICBzLmxhc3RCdWRnZXRBbGVydExldmVsID1cbiAgICAgICAgbmV3QnVkZ2V0QWxlcnRMZXZlbCBhcyBBdXRvU2Vzc2lvbltcImxhc3RCdWRnZXRBbGVydExldmVsXCJdO1xuXG4gICAgICAvLyBFbWl0IExheWVyIDIgYnVkZ2V0X3RocmVzaG9sZCBldmVudCAocG9zdC1wbGFuIGhvb2sgcmVjb21tZW5kYXRpb24pLlxuICAgICAgLy8gRXh0ZW5zaW9ucyAvIExheWVyIDAgc2hlbGwgaG9va3MgbWF5IHJldHVybiBhbiBhY3Rpb24gb3ZlcnJpZGUuXG4gICAgICBsZXQgaG9va0FjdGlvbjogXCJwYXVzZVwiIHwgXCJkb3duZ3JhZGVcIiB8IFwiY29udGludWVcIiB8IHVuZGVmaW5lZDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHsgZW1pdEJ1ZGdldFRocmVzaG9sZCB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vaG9vay1lbWl0dGVyLmpzXCIpO1xuICAgICAgICBjb25zdCBob29rUmVzdWx0ID0gYXdhaXQgZW1pdEJ1ZGdldFRocmVzaG9sZCh7XG4gICAgICAgICAgZnJhY3Rpb246IGJ1ZGdldFBjdCxcbiAgICAgICAgICBzcGVudDogdG90YWxDb3N0LFxuICAgICAgICAgIGxpbWl0OiBidWRnZXRDZWlsaW5nLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGhvb2tSZXN1bHQ/LmFjdGlvbikgaG9va0FjdGlvbiA9IGhvb2tSZXN1bHQuYWN0aW9uO1xuICAgICAgfSBjYXRjaCAoaG9va0Vycikge1xuICAgICAgICBsb2dXYXJuaW5nKFwiZW5naW5lXCIsIGBidWRnZXRfdGhyZXNob2xkIGhvb2sgZW1pc3Npb24gZmFpbGVkOiAkeyhob29rRXJyIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgfVxuXG4gICAgICAvLyBBcHBseSBob29rIG92ZXJyaWRlIHRvIGVuZm9yY2VtZW50IGFjdGlvbi4gXCJjb250aW51ZVwiIOKGkiBcIm5vbmVcIiAobm8gZW5mb3JjZW1lbnQpLFxuICAgICAgLy8gXCJwYXVzZVwiIGFuZCBcImRvd25ncmFkZVwiIG1hcCB0byB0aGUgbWF0Y2hpbmcgZW5mb3JjZW1lbnQgcGF0aCBiZWxvdy5cbiAgICAgIGxldCBlZmZlY3RpdmVBY3Rpb24gPSBidWRnZXRFbmZvcmNlbWVudEFjdGlvbjtcbiAgICAgIGlmIChob29rQWN0aW9uID09PSBcImNvbnRpbnVlXCIpIHtcbiAgICAgICAgZWZmZWN0aXZlQWN0aW9uID0gXCJub25lXCI7XG4gICAgICB9IGVsc2UgaWYgKGhvb2tBY3Rpb24gPT09IFwicGF1c2VcIikge1xuICAgICAgICBlZmZlY3RpdmVBY3Rpb24gPSBcInBhdXNlXCI7XG4gICAgICB9IGVsc2UgaWYgKGhvb2tBY3Rpb24gPT09IFwiZG93bmdyYWRlXCIpIHtcbiAgICAgICAgZWZmZWN0aXZlQWN0aW9uID0gXCJ3YXJuXCI7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aHJlc2hvbGQucGN0ID09PSAxMDAgJiYgZWZmZWN0aXZlQWN0aW9uICE9PSBcIm5vbmVcIikge1xuICAgICAgICAvLyAxMDAlIOKAlCBzcGVjaWFsIGVuZm9yY2VtZW50IGxvZ2ljIChoYWx0L3BhdXNlL3dhcm4pXG4gICAgICAgIGNvbnN0IG1zZyA9IGBCdWRnZXQgY2VpbGluZyAke2RlcHMuZm9ybWF0Q29zdChidWRnZXRDZWlsaW5nKX0gcmVhY2hlZCAoc3BlbnQgJHtkZXBzLmZvcm1hdENvc3QodG90YWxDb3N0KX0pLmA7XG4gICAgICAgIGlmIChlZmZlY3RpdmVBY3Rpb24gPT09IFwiaGFsdFwiKSB7XG4gICAgICAgICAgZGVwcy5zZW5kRGVza3RvcE5vdGlmaWNhdGlvbihcIkdTRFwiLCBtc2csIFwiZXJyb3JcIiwgXCJidWRnZXRcIiwgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpKTtcbiAgICAgICAgICBhd2FpdCBkZXBzLnN0b3BBdXRvKGN0eCwgcGksIFwiQnVkZ2V0IGNlaWxpbmcgcmVhY2hlZFwiKTtcbiAgICAgICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwiYnVkZ2V0LWhhbHRcIiB9KTtcbiAgICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcImJ1ZGdldC1oYWx0XCIgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZWZmZWN0aXZlQWN0aW9uID09PSBcInBhdXNlXCIpIHtcbiAgICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgICAgYCR7bXNnfSBQYXVzaW5nIGF1dG8tbW9kZSDigJQgL2dzZCBhdXRvIHRvIG92ZXJyaWRlIGFuZCBjb250aW51ZS5gLFxuICAgICAgICAgICAgXCJ3YXJuaW5nXCIsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBkZXBzLnNlbmREZXNrdG9wTm90aWZpY2F0aW9uKFwiR1NEXCIsIG1zZywgXCJ3YXJuaW5nXCIsIFwiYnVkZ2V0XCIsIGJhc2VuYW1lKHMub3JpZ2luYWxCYXNlUGF0aCB8fCBzLmJhc2VQYXRoKSk7XG4gICAgICAgICAgZGVwcy5sb2dDbXV4RXZlbnQocHJlZnMsIG1zZywgXCJ3YXJuaW5nXCIpO1xuICAgICAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJleGl0XCIsIHJlYXNvbjogXCJidWRnZXQtcGF1c2VcIiB9KTtcbiAgICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcImJ1ZGdldC1wYXVzZVwiIH07XG4gICAgICAgIH1cbiAgICAgICAgY3R4LnVpLm5vdGlmeShgJHttc2d9IENvbnRpbnVpbmcgKGVuZm9yY2VtZW50OiB3YXJuKS5gLCBcIndhcm5pbmdcIik7XG4gICAgICAgIGRlcHMuc2VuZERlc2t0b3BOb3RpZmljYXRpb24oXCJHU0RcIiwgbXNnLCBcIndhcm5pbmdcIiwgXCJidWRnZXRcIiwgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpKTtcbiAgICAgICAgZGVwcy5sb2dDbXV4RXZlbnQocHJlZnMsIG1zZywgXCJ3YXJuaW5nXCIpO1xuICAgICAgfSBlbHNlIGlmICh0aHJlc2hvbGQucGN0IDwgMTAwKSB7XG4gICAgICAgIC8vIFN1Yi0xMDAlIOKAlCBzaW1wbGUgbm90aWZpY2F0aW9uXG4gICAgICAgIGNvbnN0IG1zZyA9IGAke3RocmVzaG9sZC5sYWJlbH06ICR7ZGVwcy5mb3JtYXRDb3N0KHRvdGFsQ29zdCl9IC8gJHtkZXBzLmZvcm1hdENvc3QoYnVkZ2V0Q2VpbGluZyl9YDtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShtc2csIHRocmVzaG9sZC5ub3RpZnlMZXZlbCk7XG4gICAgICAgIGRlcHMuc2VuZERlc2t0b3BOb3RpZmljYXRpb24oXG4gICAgICAgICAgXCJHU0RcIixcbiAgICAgICAgICBtc2csXG4gICAgICAgICAgdGhyZXNob2xkLm5vdGlmeUxldmVsLFxuICAgICAgICAgIFwiYnVkZ2V0XCIsXG4gICAgICAgICAgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpLFxuICAgICAgICApO1xuICAgICAgICBkZXBzLmxvZ0NtdXhFdmVudChwcmVmcywgbXNnLCB0aHJlc2hvbGQuY211eExldmVsKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGJ1ZGdldEFsZXJ0TGV2ZWwgPT09IDApIHtcbiAgICAgIHMubGFzdEJ1ZGdldEFsZXJ0TGV2ZWwgPSAwO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBzLmxhc3RCdWRnZXRBbGVydExldmVsID0gMDtcbiAgfVxuXG4gIC8vIENvbnRleHQgd2luZG93IGd1YXJkXG4gIGNvbnN0IGNvbnRleHRUaHJlc2hvbGQgPSBwcmVmcz8uY29udGV4dF9wYXVzZV90aHJlc2hvbGQgPz8gMDtcbiAgaWYgKGNvbnRleHRUaHJlc2hvbGQgPiAwICYmIHMuY21kQ3R4KSB7XG4gICAgY29uc3QgY29udGV4dFVzYWdlID0gcy5jbWRDdHguZ2V0Q29udGV4dFVzYWdlKCk7XG4gICAgaWYgKFxuICAgICAgY29udGV4dFVzYWdlICYmXG4gICAgICBjb250ZXh0VXNhZ2UucGVyY2VudCAhPT0gbnVsbCAmJlxuICAgICAgY29udGV4dFVzYWdlLnBlcmNlbnQgPj0gY29udGV4dFRocmVzaG9sZFxuICAgICkge1xuICAgICAgY29uc3QgbXNnID0gYENvbnRleHQgd2luZG93IGF0ICR7Y29udGV4dFVzYWdlLnBlcmNlbnR9JSAodGhyZXNob2xkOiAke2NvbnRleHRUaHJlc2hvbGR9JSkuIFBhdXNpbmcgdG8gcHJldmVudCB0cnVuY2F0ZWQgb3V0cHV0LmA7XG4gICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICBgJHttc2d9IFJ1biAvZ3NkIGF1dG8gdG8gY29udGludWUgKHdpbGwgc3RhcnQgZnJlc2ggc2Vzc2lvbikuYCxcbiAgICAgICAgXCJ3YXJuaW5nXCIsXG4gICAgICApO1xuICAgICAgZGVwcy5zZW5kRGVza3RvcE5vdGlmaWNhdGlvbihcbiAgICAgICAgXCJHU0RcIixcbiAgICAgICAgYENvbnRleHQgJHtjb250ZXh0VXNhZ2UucGVyY2VudH0lIOKAlCBwYXVzZWRgLFxuICAgICAgICBcIndhcm5pbmdcIixcbiAgICAgICAgXCJhdHRlbnRpb25cIixcbiAgICAgICAgYmFzZW5hbWUocy5vcmlnaW5hbEJhc2VQYXRoIHx8IHMuYmFzZVBhdGgpLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImV4aXRcIiwgcmVhc29uOiBcImNvbnRleHQtd2luZG93XCIgfSk7XG4gICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcImNvbnRleHQtd2luZG93XCIgfTtcbiAgICB9XG4gIH1cblxuICAvLyBTZWNyZXRzIHJlLWNoZWNrIGdhdGVcbiAgdHJ5IHtcbiAgICBjb25zdCBtYW5pZmVzdFN0YXR1cyA9IGF3YWl0IGRlcHMuZ2V0TWFuaWZlc3RTdGF0dXMocy5iYXNlUGF0aCwgbWlkLCBzLm9yaWdpbmFsQmFzZVBhdGgpO1xuICAgIGlmIChtYW5pZmVzdFN0YXR1cyAmJiBtYW5pZmVzdFN0YXR1cy5wZW5kaW5nLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGRlcHMuY29sbGVjdFNlY3JldHNGcm9tTWFuaWZlc3QoXG4gICAgICAgIHMuYmFzZVBhdGgsXG4gICAgICAgIG1pZCxcbiAgICAgICAgY3R4LFxuICAgICAgKTtcbiAgICAgIGlmIChcbiAgICAgICAgcmVzdWx0ICYmXG4gICAgICAgIHJlc3VsdC5hcHBsaWVkICYmXG4gICAgICAgIHJlc3VsdC5za2lwcGVkICYmXG4gICAgICAgIHJlc3VsdC5leGlzdGluZ1NraXBwZWRcbiAgICAgICkge1xuICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgIGBTZWNyZXRzIGNvbGxlY3RlZDogJHtyZXN1bHQuYXBwbGllZC5sZW5ndGh9IGFwcGxpZWQsICR7cmVzdWx0LnNraXBwZWQubGVuZ3RofSBza2lwcGVkLCAke3Jlc3VsdC5leGlzdGluZ1NraXBwZWQubGVuZ3RofSBhbHJlYWR5IHNldC5gLFxuICAgICAgICAgIFwiaW5mb1wiLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShcIlNlY3JldHMgY29sbGVjdGlvbiBza2lwcGVkLlwiLCBcImluZm9cIik7XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjdHgudWkubm90aWZ5KFxuICAgICAgYFNlY3JldHMgY29sbGVjdGlvbiBlcnJvcjogJHtlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycil9LiBDb250aW51aW5nIHdpdGggbmV4dCB0YXNrLmAsXG4gICAgICBcIndhcm5pbmdcIixcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIHsgYWN0aW9uOiBcIm5leHRcIiwgZGF0YTogdW5kZWZpbmVkIGFzIHZvaWQgfTtcbn1cblxuLy8g4pSA4pSA4pSAIHJ1blVuaXRQaGFzZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBQaGFzZSA0OiBVbml0IGV4ZWN1dGlvbiDigJQgZGlzcGF0Y2ggcHJvbXB0LCBhd2FpdCBhZ2VudF9lbmQsIGNsb3Nlb3V0LCBhcnRpZmFjdCB2ZXJpZnkuXG4gKiBSZXR1cm5zIGJyZWFrIG9yIG5leHQgd2l0aCB1bml0U3RhcnRlZEF0IGZvciBkb3duc3RyZWFtIHBoYXNlcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1blVuaXRQaGFzZShcbiAgaWM6IEl0ZXJhdGlvbkNvbnRleHQsXG4gIGl0ZXJEYXRhOiBJdGVyYXRpb25EYXRhLFxuICBsb29wU3RhdGU6IExvb3BTdGF0ZSxcbiAgc2lkZWNhckl0ZW0/OiBTaWRlY2FySXRlbSxcbik6IFByb21pc2U8UGhhc2VSZXN1bHQ8eyB1bml0U3RhcnRlZEF0PzogbnVtYmVyOyByZXF1ZXN0RGlzcGF0Y2hlZEF0PzogbnVtYmVyIH0+PiB7XG4gIGNvbnN0IHsgY3R4LCBwaSwgcywgZGVwcywgcHJlZnMgfSA9IGljO1xuICBjb25zdCB7IHVuaXRUeXBlLCB1bml0SWQsIHByb21wdCwgc3RhdGUsIG1pZCB9ID0gaXRlckRhdGE7XG5cbiAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgcGhhc2U6IFwidW5pdC1leGVjdXRpb25cIixcbiAgICBpdGVyYXRpb246IGljLml0ZXJhdGlvbixcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gIH0pO1xuXG4gIGNvbnN0IHdvcmt0cmVlU2FmZXR5QmxvY2sgPSBhd2FpdCB2YWxpZGF0ZVNvdXJjZVdyaXRlV29ya3RyZWVTYWZldHkoXG4gICAgaWMsXG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICAgIG1pZCxcbiAgICBcInVuaXQtZXhlY3V0aW9uXCIsXG4gICk7XG4gIGlmICh3b3JrdHJlZVNhZmV0eUJsb2NrKSByZXR1cm4gd29ya3RyZWVTYWZldHlCbG9jaztcblxuICAvLyDilIDilIAgUHJvamVjdCBjbGFzc2lmaWNhdGlvbiBub3RpY2UgKCMxODMzLCAjMTg0Mykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIFdvcmt0cmVlIFNhZmV0eSBvd25zIHNvdXJjZS13cml0ZSByb290IHZhbGlkaXR5LiBDbGFzc2lmaWNhdGlvbiBub3cgb25seVxuICAvLyBzaGFwZXMgdXNlci9tb2RlbCBndWlkYW5jZSBmb3IgdmFsaWQgcm9vdHMuXG4gIGxldCBwcm9qZWN0Q2xhc3NpZmljYXRpb246IFJldHVyblR5cGU8dHlwZW9mIGNsYXNzaWZ5UHJvamVjdD4gfCBudWxsID0gbnVsbDtcbiAgaWYgKHMuYmFzZVBhdGggJiYgdW5pdFR5cGUgPT09IFwiZXhlY3V0ZS10YXNrXCIpIHtcbiAgICBwcm9qZWN0Q2xhc3NpZmljYXRpb24gPSBjbGFzc2lmeVByb2plY3Qocy5iYXNlUGF0aCk7XG4gICAgaWYgKHByb2plY3RDbGFzc2lmaWNhdGlvbi5raW5kID09PSBcImludmFsaWQtcmVwb1wiKSB7XG4gICAgICBjb25zdCBtc2cgPSBgV29ya3RyZWUgaGVhbHRoIGNoZWNrIGZhaWxlZDogJHtzLmJhc2VQYXRofSBjbGFzc2lmaWVkIGFzIGludmFsaWQtcmVwbyAoJHtwcm9qZWN0Q2xhc3NpZmljYXRpb24ucmVhc29ufSkg4oCUIHJlZnVzaW5nIHRvIGRpc3BhdGNoICR7dW5pdFR5cGV9ICR7dW5pdElkfWA7XG4gICAgICBkZWJ1Z0xvZyhcInJ1blVuaXRQaGFzZVwiLCB7IHBoYXNlOiBcIndvcmt0cmVlLWhlYWx0aC1pbnZhbGlkLXJlcG9cIiwgYmFzZVBhdGg6IHMuYmFzZVBhdGgsIGNsYXNzaWZpY2F0aW9uOiBwcm9qZWN0Q2xhc3NpZmljYXRpb24gfSk7XG4gICAgICBjb25zdCBoYXNHaXQgPSBkZXBzLmV4aXN0c1N5bmMoam9pbihzLmJhc2VQYXRoLCBcIi5naXRcIikpO1xuICAgICAgaWYgKF9zaG91bGRQcm9jZWVkV2l0aEludmFsaWRSZXBvQ2xhc3NpZmljYXRpb25Gb3JUZXN0KHByb2plY3RDbGFzc2lmaWNhdGlvbi5yZWFzb24sIGhhc0dpdCkpIHtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgICBgV2FybmluZzogJHtzLmJhc2VQYXRofSBwcm9qZWN0IGNsYXNzaWZpY2F0aW9uIGNvdWxkIG5vdCBjb25maXJtIC5naXQ7IGFzc3VtaW5nIGl0IGhhcyBubyBwcm9qZWN0IGNvbnRlbnQgeWV0IOKAlCBwcm9jZWVkaW5nIGFzIGdyZWVuZmllbGQgcHJvamVjdCBiZWNhdXNlIHdvcmt0cmVlIGhlYWx0aCByZXBvcnRlZCAuZ2l0IHByZXNlbnRgLFxuICAgICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShtc2csIFwiZXJyb3JcIik7XG4gICAgICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgbXNnKTtcbiAgICAgICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJ3b3JrdHJlZS1pbnZhbGlkXCIgfTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocHJvamVjdENsYXNzaWZpY2F0aW9uLmtpbmQgPT09IFwiZ3JlZW5maWVsZFwiKSB7XG4gICAgICBkZWJ1Z0xvZyhcInJ1blVuaXRQaGFzZVwiLCB7IHBoYXNlOiBcIndvcmt0cmVlLWhlYWx0aC1ncmVlbmZpZWxkXCIsIGJhc2VQYXRoOiBzLmJhc2VQYXRoLCBjbGFzc2lmaWNhdGlvbjogcHJvamVjdENsYXNzaWZpY2F0aW9uIH0pO1xuICAgICAgY3R4LnVpLm5vdGlmeShgV2FybmluZzogJHtzLmJhc2VQYXRofSBoYXMgbm8gcHJvamVjdCBjb250ZW50IHlldCDigJQgcHJvY2VlZGluZyBhcyBncmVlbmZpZWxkIHByb2plY3RgLCBcIndhcm5pbmdcIik7XG4gICAgfSBlbHNlIGlmIChwcm9qZWN0Q2xhc3NpZmljYXRpb24ua2luZCA9PT0gXCJ1bnR5cGVkLWV4aXN0aW5nXCIpIHtcbiAgICAgIGRlYnVnTG9nKFwicnVuVW5pdFBoYXNlXCIsIHsgcGhhc2U6IFwid29ya3RyZWUtaGVhbHRoLXVudHlwZWQtZXhpc3RpbmdcIiwgYmFzZVBhdGg6IHMuYmFzZVBhdGgsIGNsYXNzaWZpY2F0aW9uOiBwcm9qZWN0Q2xhc3NpZmljYXRpb24gfSk7XG4gICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICBgTm90aWNlOiAke3MuYmFzZVBhdGh9IGhhcyBleGlzdGluZyBwcm9qZWN0IGNvbnRlbnQgYnV0IG5vIHJlY29nbml6ZWQgdG9vbGluZyBtYXJrZXJzIOKAlCB1c2luZyBnZW5lcmljIGZpbGUtbGV2ZWwgd29ya2Zsb3cgZ3VpZGFuY2VgLFxuICAgICAgICBcImluZm9cIixcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gRGV0ZWN0IHJldHJ5IGFuZCBjYXB0dXJlIHByZXZpb3VzIHRpZXIgZm9yIGVzY2FsYXRpb25cbiAgY29uc3QgaXNSZXRyeSA9ICEhKFxuICAgIHMuY3VycmVudFVuaXQgJiZcbiAgICBzLmN1cnJlbnRVbml0LnR5cGUgPT09IHVuaXRUeXBlICYmXG4gICAgcy5jdXJyZW50VW5pdC5pZCA9PT0gdW5pdElkXG4gICk7XG4gIGNvbnN0IHByZXZpb3VzVGllciA9IHMuY3VycmVudFVuaXRSb3V0aW5nPy50aWVyO1xuICBjb25zdCBkaXNwYXRjaEtleSA9IGAke3VuaXRUeXBlfS8ke3VuaXRJZH1gO1xuICBjb25zdCBuZXh0RGlzcGF0Y2hDb3VudCA9IChzLnVuaXREaXNwYXRjaENvdW50LmdldChkaXNwYXRjaEtleSkgPz8gMCkgKyAxO1xuXG4gIC8vIFN0YXR1cyBiYXIgKHdpZGdldCArIHByZWNvbmRpdGlvbnMgZGVmZXJyZWQgdW50aWwgYWZ0ZXIgbW9kZWwgc2VsZWN0aW9uIOKAlCBzZWUgIzI4OTkpXG4gIGN0eC51aS5zZXRTdGF0dXMoXCJnc2QtYXV0b1wiLCBcImF1dG9cIik7XG4gIGlmIChtaWQpXG4gICAgZGVwcy51cGRhdGVTbGljZVByb2dyZXNzQ2FjaGUocy5iYXNlUGF0aCwgbWlkLCBzdGF0ZS5hY3RpdmVTbGljZT8uaWQpO1xuXG4gIC8vIOKUgOKUgCBTYWZldHkgaGFybmVzczogcmVzZXQgZXZpZGVuY2UgKyBjcmVhdGUgY2hlY2twb2ludCDilIDilIBcbiAgY29uc3Qgc2FmZXR5Q29uZmlnID0gcmVzb2x2ZVNhZmV0eUhhcm5lc3NDb25maWcoXG4gICAgcHJlZnM/LnNhZmV0eV9oYXJuZXNzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkLFxuICApO1xuICBpZiAoc2FmZXR5Q29uZmlnLmVuYWJsZWQgJiYgc2FmZXR5Q29uZmlnLmV2aWRlbmNlX2NvbGxlY3Rpb24pIHtcbiAgICByZXNldEV2aWRlbmNlKCk7XG4gICAgLy8gUmVzdG9yZSBwZXJzaXN0ZWQgZXZpZGVuY2Ugc28gc2Vzc2lvbi1yZXN0YXJ0IHJlc3VtZXMgZG9uJ3QgcHJvZHVjZVxuICAgIC8vIGZhbHNlLXBvc2l0aXZlIFwibm8gYmFzaCBjYWxsc1wiIHdhcm5pbmdzIChCdWcgIzQzODUpLlxuICAgIGlmIChzLmJhc2VQYXRoICYmIHVuaXRUeXBlID09PSBcImV4ZWN1dGUtdGFza1wiKSB7XG4gICAgICBjb25zdCB7IG1pbGVzdG9uZTogZU1pZCwgc2xpY2U6IGVTaWQsIHRhc2s6IGVUaWQgfSA9IHBhcnNlVW5pdElkKHVuaXRJZCk7XG4gICAgICBpZiAoZU1pZCAmJiBlU2lkICYmIGVUaWQpIHtcbiAgICAgICAgbG9hZEV2aWRlbmNlRnJvbURpc2socy5iYXNlUGF0aCwgZU1pZCwgZVNpZCwgZVRpZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIC8vIE9ubHkgY2hlY2twb2ludCBjb2RlLWV4ZWN1dGluZyB1bml0cyAobm90IGxpZmVjeWNsZS9wbGFubmluZyB1bml0cylcbiAgaWYgKHNhZmV0eUNvbmZpZy5lbmFibGVkICYmIHNhZmV0eUNvbmZpZy5jaGVja3BvaW50cyAmJiB1bml0VHlwZSA9PT0gXCJleGVjdXRlLXRhc2tcIikge1xuICAgIHMuY2hlY2twb2ludFNoYSA9IGNyZWF0ZUNoZWNrcG9pbnQocy5iYXNlUGF0aCwgdW5pdElkKTtcbiAgICBpZiAocy5jaGVja3BvaW50U2hhKSB7XG4gICAgICBkZWJ1Z0xvZyhcInJ1blVuaXRQaGFzZVwiLCB7IHBoYXNlOiBcImNoZWNrcG9pbnQtY3JlYXRlZFwiLCB1bml0SWQsIHNoYTogcy5jaGVja3BvaW50U2hhLnNsaWNlKDAsIDgpIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIFByb21wdCBpbmplY3Rpb25cbiAgbGV0IGZpbmFsUHJvbXB0ID0gcHJvbXB0O1xuXG4gIGlmICh1bml0VHlwZSA9PT0gXCJleGVjdXRlLXRhc2tcIikge1xuICAgIHByb2plY3RDbGFzc2lmaWNhdGlvbiA/Pz0gY2xhc3NpZnlQcm9qZWN0KHMuYmFzZVBhdGgpO1xuICAgIGlmIChwcm9qZWN0Q2xhc3NpZmljYXRpb24ua2luZCA9PT0gXCJ1bnR5cGVkLWV4aXN0aW5nXCIpIHtcbiAgICAgIGNvbnN0IHNhbXBsZXMgPSBwcm9qZWN0Q2xhc3NpZmljYXRpb24uY29udGVudEZpbGVzLnNsaWNlKDAsIDgpLmpvaW4oXCIsIFwiKSB8fCBcInByb2plY3QgZmlsZXNcIjtcbiAgICAgIGZpbmFsUHJvbXB0ICs9XG4gICAgICAgIFwiXFxuXFxuKipQcm9qZWN0IGNsYXNzaWZpY2F0aW9uOioqIEV4aXN0aW5nIHVudHlwZWQgcHJvamVjdC4gTm8gcmVjb2duaXplZCBidWlsZC90b29saW5nIG1hcmtlcnMgd2VyZSBkZXRlY3RlZCwgXCIgK1xuICAgICAgICBcInNvIHVzZSBnZW5lcmljIGZpbGUtbGV2ZWwgd29ya2Zsb3cgZ3VpZGFuY2UuIFRhc2sgcGxhbnMgYW5kIGNvbXBsZXRpb24gc3VtbWFyaWVzIG11c3QgbGlzdCBldmVyeSBjb25jcmV0ZSBcIiArXG4gICAgICAgIGBwcm9qZWN0IGZpbGUgY2hhbmdlZCBpbiBcXGBmaWxlc1xcYCBvciBcXGBleHBlY3RlZF9vdXRwdXRcXGAuIERldGVjdGVkIGNvbnRlbnQgc2FtcGxlOiAke3NhbXBsZXN9LmA7XG4gICAgfVxuICB9XG5cbiAgaWYgKHMucGVuZGluZ1ZlcmlmaWNhdGlvblJldHJ5KSB7XG4gICAgY29uc3QgcmV0cnlDdHggPSBzLnBlbmRpbmdWZXJpZmljYXRpb25SZXRyeTtcbiAgICBzLnBlbmRpbmdWZXJpZmljYXRpb25SZXRyeSA9IG51bGw7XG4gICAgY29uc3QgY2FwcGVkID1cbiAgICAgIHJldHJ5Q3R4LmZhaWx1cmVDb250ZXh0Lmxlbmd0aCA+IE1BWF9SRUNPVkVSWV9DSEFSU1xuICAgICAgICA/IHJldHJ5Q3R4LmZhaWx1cmVDb250ZXh0LnNsaWNlKDAsIE1BWF9SRUNPVkVSWV9DSEFSUykgK1xuICAgICAgICAgIFwiXFxuXFxuWy4uLmZhaWx1cmUgY29udGV4dCB0cnVuY2F0ZWRdXCJcbiAgICAgICAgOiByZXRyeUN0eC5mYWlsdXJlQ29udGV4dDtcbiAgICBmaW5hbFByb21wdCA9IGAqKlZFUklGSUNBVElPTiBGQUlMRUQg4oCUIEFVVE8tRklYIEFUVEVNUFQgJHtyZXRyeUN0eC5hdHRlbXB0fSoqXFxuXFxuVGhlIHZlcmlmaWNhdGlvbiBnYXRlIHJhbiBhZnRlciB5b3VyIHByZXZpb3VzIGF0dGVtcHQgYW5kIGZvdW5kIGZhaWx1cmVzLiBGaXggdGhlc2UgaXNzdWVzIGJlZm9yZSBjb21wbGV0aW5nIHRoZSB0YXNrLlxcblxcbiR7Y2FwcGVkfVxcblxcbi0tLVxcblxcbiR7ZmluYWxQcm9tcHR9YDtcbiAgfVxuXG4gIGlmIChzLnBlbmRpbmdDcmFzaFJlY292ZXJ5KSB7XG4gICAgY29uc3QgY2FwcGVkID1cbiAgICAgIHMucGVuZGluZ0NyYXNoUmVjb3ZlcnkubGVuZ3RoID4gTUFYX1JFQ09WRVJZX0NIQVJTXG4gICAgICAgID8gcy5wZW5kaW5nQ3Jhc2hSZWNvdmVyeS5zbGljZSgwLCBNQVhfUkVDT1ZFUllfQ0hBUlMpICtcbiAgICAgICAgICBcIlxcblxcblsuLi5yZWNvdmVyeSBicmllZmluZyB0cnVuY2F0ZWQgdG8gcHJldmVudCBtZW1vcnkgZXhoYXVzdGlvbl1cIlxuICAgICAgICA6IHMucGVuZGluZ0NyYXNoUmVjb3Zlcnk7XG4gICAgZmluYWxQcm9tcHQgPSBgJHtjYXBwZWR9XFxuXFxuLS0tXFxuXFxuJHtmaW5hbFByb21wdH1gO1xuICAgIHMucGVuZGluZ0NyYXNoUmVjb3ZlcnkgPSBudWxsO1xuICB9IGVsc2UgaWYgKG5leHREaXNwYXRjaENvdW50ID4gMSkge1xuICAgIGNvbnN0IGRpYWdub3N0aWMgPSBkZXBzLmdldERlZXBEaWFnbm9zdGljKHMuYmFzZVBhdGgpO1xuICAgIGlmIChkaWFnbm9zdGljKSB7XG4gICAgICBjb25zdCBjYXBwZWREaWFnID1cbiAgICAgICAgZGlhZ25vc3RpYy5sZW5ndGggPiBNQVhfUkVDT1ZFUllfQ0hBUlNcbiAgICAgICAgICA/IGRpYWdub3N0aWMuc2xpY2UoMCwgTUFYX1JFQ09WRVJZX0NIQVJTKSArXG4gICAgICAgICAgICBcIlxcblxcblsuLi5kaWFnbm9zdGljIHRydW5jYXRlZCB0byBwcmV2ZW50IG1lbW9yeSBleGhhdXN0aW9uXVwiXG4gICAgICAgICAgOiBkaWFnbm9zdGljO1xuICAgICAgZmluYWxQcm9tcHQgPSBgKipSRVRSWSDigJQgeW91ciBwcmV2aW91cyBhdHRlbXB0IGRpZCBub3QgcHJvZHVjZSB0aGUgcmVxdWlyZWQgYXJ0aWZhY3QuKipcXG5cXG5EaWFnbm9zdGljIGZyb20gcHJldmlvdXMgYXR0ZW1wdDpcXG4ke2NhcHBlZERpYWd9XFxuXFxuRml4IHdoYXRldmVyIHdlbnQgd3JvbmcgYW5kIG1ha2Ugc3VyZSB5b3Ugd3JpdGUgdGhlIHJlcXVpcmVkIGZpbGUgdGhpcyB0aW1lLlxcblxcbi0tLVxcblxcbiR7ZmluYWxQcm9tcHR9YDtcbiAgICB9XG4gIH1cblxuICAvLyBQcm9tcHQgY2hhciBtZWFzdXJlbWVudFxuICBzLmxhc3RQcm9tcHRDaGFyQ291bnQgPSBmaW5hbFByb21wdC5sZW5ndGg7XG4gIHMubGFzdEJhc2VsaW5lQ2hhckNvdW50ID0gdW5kZWZpbmVkO1xuICBpZiAoZGVwcy5pc0RiQXZhaWxhYmxlKCkpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBpbmxpbmVHc2RSb290RmlsZSB9ID0gYXdhaXQgaW1wb3J0RXh0ZW5zaW9uTW9kdWxlPHR5cGVvZiBpbXBvcnQoXCIuLi9hdXRvLXByb21wdHMuanNcIik+KGltcG9ydC5tZXRhLnVybCwgXCIuLi9hdXRvLXByb21wdHMuanNcIik7XG4gICAgICBjb25zdCBbZGVjaXNpb25zQ29udGVudCwgcmVxdWlyZW1lbnRzQ29udGVudCwgcHJvamVjdENvbnRlbnRdID1cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIGlubGluZUdzZFJvb3RGaWxlKHMuYmFzZVBhdGgsIFwiZGVjaXNpb25zLm1kXCIsIFwiRGVjaXNpb25zXCIpLFxuICAgICAgICAgIGlubGluZUdzZFJvb3RGaWxlKHMuYmFzZVBhdGgsIFwicmVxdWlyZW1lbnRzLm1kXCIsIFwiUmVxdWlyZW1lbnRzXCIpLFxuICAgICAgICAgIGlubGluZUdzZFJvb3RGaWxlKHMuYmFzZVBhdGgsIFwicHJvamVjdC5tZFwiLCBcIlByb2plY3RcIiksXG4gICAgICAgIF0pO1xuICAgICAgcy5sYXN0QmFzZWxpbmVDaGFyQ291bnQgPVxuICAgICAgICAoZGVjaXNpb25zQ29udGVudD8ubGVuZ3RoID8/IDApICtcbiAgICAgICAgKHJlcXVpcmVtZW50c0NvbnRlbnQ/Lmxlbmd0aCA/PyAwKSArXG4gICAgICAgIChwcm9qZWN0Q29udGVudD8ubGVuZ3RoID8/IDApO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGxvZ1dhcm5pbmcoXCJlbmdpbmVcIiwgXCJCYXNlbGluZSBjaGFyIGNvdW50IG1lYXN1cmVtZW50IGZhaWxlZFwiLCB7IGVycm9yOiBTdHJpbmcoZSkgfSk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2FjaGUtb3B0aW1pemUgcHJvbXB0IHNlY3Rpb24gb3JkZXJpbmdcbiAgdHJ5IHtcbiAgICBmaW5hbFByb21wdCA9IGRlcHMucmVvcmRlckZvckNhY2hpbmcoZmluYWxQcm9tcHQpO1xuICB9IGNhdGNoIChyZW9yZGVyRXJyKSB7XG4gICAgY29uc3QgbXNnID1cbiAgICAgIHJlb3JkZXJFcnIgaW5zdGFuY2VvZiBFcnJvciA/IHJlb3JkZXJFcnIubWVzc2FnZSA6IFN0cmluZyhyZW9yZGVyRXJyKTtcbiAgICBsb2dXYXJuaW5nKFwiZW5naW5lXCIsIFwiUHJvbXB0IHJlb3JkZXIgZmFpbGVkXCIsIHsgZXJyb3I6IG1zZyB9KTtcbiAgfVxuXG4gIC8vIFNlbGVjdCBhbmQgYXBwbHkgbW9kZWwgKHdpdGggdGllciBlc2NhbGF0aW9uIG9uIHJldHJ5IOKAlCBub3JtYWwgdW5pdHMgb25seSlcbiAgY29uc3QgcHJldlVuaXRSb3V0aW5nID0gcy5jdXJyZW50VW5pdFJvdXRpbmc7XG4gIGNvbnN0IHByZXZVbml0TW9kZWwgPSBzLmN1cnJlbnRVbml0TW9kZWw7XG4gIGNvbnN0IHByZXZEaXNwYXRjaGVkTW9kZWxJZCA9IHMuY3VycmVudERpc3BhdGNoZWRNb2RlbElkO1xuICBjb25zdCBwcmV2U2Vzc2lvbk1vZGVsID0gY3R4Lm1vZGVsO1xuICBjb25zdCBwcmV2U2Vzc2lvblRoaW5raW5nTGV2ZWwgPSBwaS5nZXRUaGlua2luZ0xldmVsKCk7XG4gIGNvbnN0IG1vZGVsUmVzdWx0ID0gYXdhaXQgZGVwcy5zZWxlY3RBbmRBcHBseU1vZGVsKFxuICAgIGN0eCxcbiAgICBwaSxcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgcy5iYXNlUGF0aCxcbiAgICBwcmVmcyxcbiAgICBzLnZlcmJvc2UsXG4gICAgcy5hdXRvTW9kZVN0YXJ0TW9kZWwsXG4gICAgc2lkZWNhckl0ZW0gPyB1bmRlZmluZWQgOiB7IGlzUmV0cnksIHByZXZpb3VzVGllciB9LFxuICAgIHVuZGVmaW5lZCxcbiAgICBzLm1hbnVhbFNlc3Npb25Nb2RlbE92ZXJyaWRlLFxuICAgIHMuYXV0b01vZGVTdGFydFRoaW5raW5nTGV2ZWwsXG4gICk7XG4gIHMuY3VycmVudFVuaXRSb3V0aW5nID1cbiAgICBtb2RlbFJlc3VsdC5yb3V0aW5nIGFzIEF1dG9TZXNzaW9uW1wiY3VycmVudFVuaXRSb3V0aW5nXCJdO1xuICBzLmN1cnJlbnRVbml0TW9kZWwgPVxuICAgIG1vZGVsUmVzdWx0LmFwcGxpZWRNb2RlbCBhcyBBdXRvU2Vzc2lvbltcImN1cnJlbnRVbml0TW9kZWxcIl07XG5cbiAgLy8gQXBwbHkgc2lkZWNhci9wcmUtZGlzcGF0Y2ggaG9vayBtb2RlbCBvdmVycmlkZSAodGFrZXMgcHJpb3JpdHkgb3ZlciBzdGFuZGFyZCBtb2RlbCBzZWxlY3Rpb24pXG4gIGNvbnN0IGhvb2tNb2RlbE92ZXJyaWRlID0gc2lkZWNhckl0ZW0/Lm1vZGVsID8/IGl0ZXJEYXRhLmhvb2tNb2RlbE92ZXJyaWRlO1xuICBpZiAoaG9va01vZGVsT3ZlcnJpZGUpIHtcbiAgICBjb25zdCBhdmFpbGFibGVNb2RlbHMgPSBjdHgubW9kZWxSZWdpc3RyeS5nZXRBdmFpbGFibGUoKTtcbiAgICBjb25zdCBtYXRjaCA9IGRlcHMucmVzb2x2ZU1vZGVsSWQoaG9va01vZGVsT3ZlcnJpZGUsIGF2YWlsYWJsZU1vZGVscywgY3R4Lm1vZGVsPy5wcm92aWRlcik7XG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICBjb25zdCBvayA9IGF3YWl0IHBpLnNldE1vZGVsKG1hdGNoLCB7IHBlcnNpc3Q6IGZhbHNlIH0pO1xuICAgICAgaWYgKG9rKSB7XG4gICAgICAgIGlmIChzLmF1dG9Nb2RlU3RhcnRUaGlua2luZ0xldmVsKSB7XG4gICAgICAgICAgcGkuc2V0VGhpbmtpbmdMZXZlbChzLmF1dG9Nb2RlU3RhcnRUaGlua2luZ0xldmVsKTtcbiAgICAgICAgfVxuICAgICAgICBzLmN1cnJlbnRVbml0TW9kZWwgPSBtYXRjaCBhcyBBdXRvU2Vzc2lvbltcImN1cnJlbnRVbml0TW9kZWxcIl07XG4gICAgICAgIGN0eC51aS5ub3RpZnkoYEhvb2sgbW9kZWwgb3ZlcnJpZGU6ICR7bWF0Y2gucHJvdmlkZXJ9LyR7bWF0Y2guaWR9YCwgXCJpbmZvXCIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgICBgSG9vayBtb2RlbCBcIiR7aG9va01vZGVsT3ZlcnJpZGV9XCIgZm91bmQgYnV0IHNldE1vZGVsIGZhaWxlZC4gVXNpbmcgZGVmYXVsdC5gLFxuICAgICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICBgSG9vayBtb2RlbCBcIiR7aG9va01vZGVsT3ZlcnJpZGV9XCIgbm90IGZvdW5kIGluIGF2YWlsYWJsZSBtb2RlbHMuIEZhbGxpbmcgYmFjayB0byBjdXJyZW50IHNlc3Npb24gbW9kZWwuIGAgK1xuICAgICAgICBgRW5zdXJlIHRoZSBtb2RlbCBpcyBkZWZpbmVkIGluIG1vZGVscy5qc29uIGFuZCBoYXMgYXV0aCBjb25maWd1cmVkLmAsXG4gICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBTdG9yZSB0aGUgZmluYWwgZGlzcGF0Y2hlZCBtb2RlbCBJRCBzbyB0aGUgZGFzaGJvYXJkIGNhbiByZWFkIGl0ICgjMjg5OSkuXG4gIC8vIFRoaXMgYWNjb3VudHMgZm9yIGhvb2sgbW9kZWwgb3ZlcnJpZGVzIGFwcGxpZWQgYWZ0ZXIgc2VsZWN0QW5kQXBwbHlNb2RlbC5cbiAgcy5jdXJyZW50RGlzcGF0Y2hlZE1vZGVsSWQgPSBzLmN1cnJlbnRVbml0TW9kZWxcbiAgICA/IGAkeyhzLmN1cnJlbnRVbml0TW9kZWwgYXMgYW55KS5wcm92aWRlciA/PyBcIlwifS8keyhzLmN1cnJlbnRVbml0TW9kZWwgYXMgYW55KS5pZCA/PyBcIlwifWBcbiAgICA6IG51bGw7XG5cbiAgY29uc3QgY29tcGF0aWJpbGl0eUVycm9yID0gZ2V0V29ya2Zsb3dUcmFuc3BvcnRTdXBwb3J0RXJyb3IoXG4gICAgcy5jdXJyZW50VW5pdE1vZGVsPy5wcm92aWRlciA/PyBjdHgubW9kZWw/LnByb3ZpZGVyLFxuICAgIGdldFJlcXVpcmVkV29ya2Zsb3dUb29sc0ZvckF1dG9Vbml0KHVuaXRUeXBlKSxcbiAgICB7XG4gICAgICBwcm9qZWN0Um9vdDogcy5iYXNlUGF0aCxcbiAgICAgIHN1cmZhY2U6IFwiYXV0by1tb2RlXCIsXG4gICAgICB1bml0VHlwZSxcbiAgICAgIGF1dGhNb2RlOiBzLmN1cnJlbnRVbml0TW9kZWw/LnByb3ZpZGVyXG4gICAgICAgID8gY3R4Lm1vZGVsUmVnaXN0cnkuZ2V0UHJvdmlkZXJBdXRoTW9kZShzLmN1cnJlbnRVbml0TW9kZWwucHJvdmlkZXIpXG4gICAgICAgIDogY3R4Lm1vZGVsPy5wcm92aWRlclxuICAgICAgICAgID8gY3R4Lm1vZGVsUmVnaXN0cnkuZ2V0UHJvdmlkZXJBdXRoTW9kZShjdHgubW9kZWwucHJvdmlkZXIpXG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICBiYXNlVXJsOiAocy5jdXJyZW50VW5pdE1vZGVsIGFzIGFueSk/LmJhc2VVcmwgPz8gY3R4Lm1vZGVsPy5iYXNlVXJsLFxuICAgICAgYWN0aXZlVG9vbHM6IHR5cGVvZiBwaS5nZXRBY3RpdmVUb29scyA9PT0gXCJmdW5jdGlvblwiID8gcGkuZ2V0QWN0aXZlVG9vbHMoKSA6IFtdLFxuICAgIH0sXG4gICk7XG4gIGlmIChjb21wYXRpYmlsaXR5RXJyb3IpIHtcbiAgICBzLmN1cnJlbnRVbml0Um91dGluZyA9IHByZXZVbml0Um91dGluZztcbiAgICBzLmN1cnJlbnRVbml0TW9kZWwgPSBwcmV2VW5pdE1vZGVsO1xuICAgIHMuY3VycmVudERpc3BhdGNoZWRNb2RlbElkID0gcHJldkRpc3BhdGNoZWRNb2RlbElkO1xuICAgIGlmIChzLmNoZWNrcG9pbnRTaGEpIHtcbiAgICAgIGNsZWFudXBDaGVja3BvaW50KHMuYmFzZVBhdGgsIHVuaXRJZCk7XG4gICAgICBzLmNoZWNrcG9pbnRTaGEgPSBudWxsO1xuICAgIH1cbiAgICBpZiAocHJldlNlc3Npb25Nb2RlbCkge1xuICAgICAgY29uc3Qgb2sgPSBhd2FpdCBwaS5zZXRNb2RlbChwcmV2U2Vzc2lvbk1vZGVsLCB7IHBlcnNpc3Q6IGZhbHNlIH0pO1xuICAgICAgaWYgKCFvaykge1xuICAgICAgICBjdHgudWkubm90aWZ5KFwiRmFpbGVkIHRvIHJlc3RvcmUgcHJldmlvdXMgc2Vzc2lvbiBtb2RlbCBhZnRlciBjb21wYXRpYmlsaXR5IGNoZWNrIGZhaWx1cmUuXCIsIFwid2FybmluZ1wiKTtcbiAgICAgIH1cbiAgICAgIGlmIChwcmV2U2Vzc2lvblRoaW5raW5nTGV2ZWwpIHtcbiAgICAgICAgcGkuc2V0VGhpbmtpbmdMZXZlbChwcmV2U2Vzc2lvblRoaW5raW5nTGV2ZWwpO1xuICAgICAgfVxuICAgIH1cbiAgICBjdHgudWkubm90aWZ5KGNvbXBhdGliaWxpdHlFcnJvciwgXCJlcnJvclwiKTtcbiAgICBhd2FpdCBkZXBzLnN0b3BBdXRvKGN0eCwgcGksIGNvbXBhdGliaWxpdHlFcnJvcik7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJ3b3JrZmxvdy1jYXBhYmlsaXR5XCIgfTtcbiAgfVxuXG4gIC8vIFNjb3BlIHdvcmtmbG93LWxvZ2dlciBidWZmZXIgdG8gdGhpcyB1bml0IHNvIHBvc3QtZmluYWxpemUgZHJhaW5zIGFyZVxuICAvLyBwZXItdW5pdC4gV2l0aG91dCB0aGlzLCB0aGUgbW9kdWxlLWxldmVsIF9idWZmZXIgYWNjdW11bGF0ZXMgYWNyb3NzIGV2ZXJ5XG4gIC8vIHVuaXQgaW4gdGhlIHNhbWUgTm9kZSBwcm9jZXNzIChzZWUgd29ya2Zsb3ctbG9nZ2VyLnRzIG1vZHVsZSBoZWFkZXIpLlxuICBfcmVzZXRMb2dzKCk7XG4gIGNvbnN0IHVuaXRTdGFydGVkQXQgPSBEYXRlLm5vdygpO1xuICBzLnVuaXREaXNwYXRjaENvdW50LnNldChkaXNwYXRjaEtleSwgbmV4dERpc3BhdGNoQ291bnQpO1xuICBzLmN1cnJlbnRVbml0ID0geyB0eXBlOiB1bml0VHlwZSwgaWQ6IHVuaXRJZCwgc3RhcnRlZEF0OiB1bml0U3RhcnRlZEF0IH07XG4gIHMubGFzdEdpdEFjdGlvbkZhaWx1cmUgPSBudWxsO1xuICBzLmxhc3RHaXRBY3Rpb25TdGF0dXMgPSBudWxsO1xuICBzLmxhc3RVbml0QWdlbnRFbmRNZXNzYWdlcyA9IG51bGw7XG4gIHNldEN1cnJlbnRQaGFzZSh1bml0VHlwZSwge1xuICAgIGJhc2VQYXRoOiBzLmJhc2VQYXRoLFxuICAgIHRyYWNlSWQ6IGljLmZsb3dJZCxcbiAgICB0dXJuSWQ6IGBpdGVyLSR7aWMuaXRlcmF0aW9ufWAsXG4gICAgY2F1c2VkQnk6IFwidW5pdC1zdGFydFwiLFxuICB9KTtcbiAgcy5sYXN0VG9vbEludm9jYXRpb25FcnJvciA9IG51bGw7IC8vICMyODgzOiBjbGVhciBzdGFsZSBlcnJvciBmcm9tIHByZXZpb3VzIHVuaXRcbiAgY29uc3QgdW5pdFN0YXJ0U2VxID0gaWMubmV4dFNlcSgpO1xuICBkZXBzLmVtaXRKb3VybmFsRXZlbnQoeyB0czogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLCBmbG93SWQ6IGljLmZsb3dJZCwgc2VxOiB1bml0U3RhcnRTZXEsIGV2ZW50VHlwZTogXCJ1bml0LXN0YXJ0XCIsIGRhdGE6IHsgdW5pdFR5cGUsIHVuaXRJZCB9IH0pO1xuICBkZXBzLmNhcHR1cmVBdmFpbGFibGVTa2lsbHMoKTtcbiAgd3JpdGVVbml0UnVudGltZVJlY29yZChcbiAgICBzLmJhc2VQYXRoLFxuICAgIHVuaXRUeXBlLFxuICAgIHVuaXRJZCxcbiAgICB1bml0U3RhcnRlZEF0LFxuICAgIHtcbiAgICAgIHBoYXNlOiBcImRpc3BhdGNoZWRcIixcbiAgICAgIHdyYXB1cFdhcm5pbmdTZW50OiBmYWxzZSxcbiAgICAgIHRpbWVvdXRBdDogbnVsbCxcbiAgICAgIGxhc3RQcm9ncmVzc0F0OiB1bml0U3RhcnRlZEF0LFxuICAgICAgcHJvZ3Jlc3NDb3VudDogMCxcbiAgICAgIGxhc3RQcm9ncmVzc0tpbmQ6IFwiZGlzcGF0Y2hcIixcbiAgICAgIHJlY292ZXJ5QXR0ZW1wdHM6IDAsIC8vIFJlc2V0IHNvIHJlLWRpc3BhdGNoZWQgdW5pdHMgZ2V0IGZ1bGwgcmVjb3ZlcnkgYnVkZ2V0ICgjMjMyMilcbiAgICB9LFxuICApO1xuXG4gIC8vIFByb2dyZXNzIHdpZGdldCArIHByZWNvbmRpdGlvbnMg4oCUIGRlZmVycmVkIHRvIGFmdGVyIG1vZGVsIHNlbGVjdGlvbiBzbyB0aGVcbiAgLy8gd2lkZ2V0J3MgZmlyc3QgcmVuZGVyIHRpY2sgc2hvd3MgdGhlIGNvcnJlY3QgbW9kZWwgKCMyODk5KS5cbiAgZGVwcy51cGRhdGVQcm9ncmVzc1dpZGdldChjdHgsIHVuaXRUeXBlLCB1bml0SWQsIHN0YXRlKTtcbiAgZGVwcy5lbnN1cmVQcmVjb25kaXRpb25zKHVuaXRUeXBlLCB1bml0SWQsIHMuYmFzZVBhdGgsIHN0YXRlKTtcblxuICAvLyBTdGFydCB1bml0IHN1cGVydmlzaW9uXG4gIGRlcHMuY2xlYXJVbml0VGltZW91dCgpO1xuICBkZXBzLnN0YXJ0VW5pdFN1cGVydmlzaW9uKHtcbiAgICBzLFxuICAgIGN0eCxcbiAgICBwaSxcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgcHJlZnMsXG4gICAgYnVpbGRTbmFwc2hvdE9wdHM6ICgpID0+IGRlcHMuYnVpbGRTbmFwc2hvdE9wdHModW5pdFR5cGUsIHVuaXRJZCksXG4gICAgYnVpbGRSZWNvdmVyeUNvbnRleHQ6ICgpID0+ICh7XG4gICAgICBiYXNlUGF0aDogcy5iYXNlUGF0aCxcbiAgICAgIHZlcmJvc2U6IHMudmVyYm9zZSxcbiAgICAgIGN1cnJlbnRVbml0U3RhcnRlZEF0OiBzLmN1cnJlbnRVbml0Py5zdGFydGVkQXQgPz8gRGF0ZS5ub3coKSxcbiAgICAgIHVuaXRSZWNvdmVyeUNvdW50OiBzLnVuaXRSZWNvdmVyeUNvdW50LFxuICAgIH0pLFxuICAgIHBhdXNlQXV0bzogZGVwcy5wYXVzZUF1dG8sXG4gIH0pO1xuXG4gIC8vIFdyaXRlIHByZWxpbWluYXJ5IGxvY2sgKG5vIHNlc3Npb24gcGF0aCB5ZXQg4oCUIHJ1blVuaXQgY3JlYXRlcyBhIG5ldyBzZXNzaW9uKS5cbiAgLy8gQ3Jhc2ggcmVjb3ZlcnkgY2FuIHN0aWxsIGlkZW50aWZ5IHRoZSBpbi1mbGlnaHQgdW5pdCBmcm9tIHRoaXMgbG9jay5cbiAgZGVwcy53cml0ZUxvY2soXG4gICAgZGVwcy5sb2NrQmFzZSgpLFxuICAgIHVuaXRUeXBlLFxuICAgIHVuaXRJZCxcbiAgKTtcblxuICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHtcbiAgICBwaGFzZTogXCJydW5Vbml0LXN0YXJ0XCIsXG4gICAgaXRlcmF0aW9uOiBpYy5pdGVyYXRpb24sXG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICB9KTtcbiAgY29uc3QgdW5pdFJlc3VsdCA9IGF3YWl0IHJ1blVuaXQoXG4gICAgY3R4LFxuICAgIHBpLFxuICAgIHMsXG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICAgIGZpbmFsUHJvbXB0LFxuICApO1xuICBzLmxhc3RVbml0QWdlbnRFbmRNZXNzYWdlcyA9IHVuaXRSZXN1bHQuZXZlbnQ/Lm1lc3NhZ2VzID8/IG51bGw7XG4gIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgIHBoYXNlOiBcInJ1blVuaXQtZW5kXCIsXG4gICAgaXRlcmF0aW9uOiBpYy5pdGVyYXRpb24sXG4gICAgdW5pdFR5cGUsXG4gICAgdW5pdElkLFxuICAgIHN0YXR1czogdW5pdFJlc3VsdC5zdGF0dXMsXG4gIH0pO1xuXG4gIGlmIChcbiAgICB1bml0UmVzdWx0LnN0YXR1cyA9PT0gXCJjb21wbGV0ZWRcIiAmJlxuICAgIHMuY3VycmVudFVuaXQgJiZcbiAgICAodW5pdFJlc3VsdC5ldmVudD8ubWVzc2FnZXM/Lmxlbmd0aCA/PyAwKSA9PT0gMCAmJlxuICAgIGlzU3VzcGljaW91c0dob3N0Q29tcGxldGlvbihjdHgsIHVuaXRSZXN1bHQucmVxdWVzdERpc3BhdGNoZWRBdCA/PyBzLmN1cnJlbnRVbml0LnN0YXJ0ZWRBdClcbiAgKSB7XG4gICAgY29uc3QgbWVzc2FnZSA9XG4gICAgICBgJHt1bml0VHlwZX0gJHt1bml0SWR9IGNvbXBsZXRlZCB3aXRob3V0IGFzc2lzdGFudCBvdXRwdXQgb3IgdG9vbCBjYWxsczsgdHJlYXRpbmcgYXMgYSBzdGFsZSBnaG9zdCBjb21wbGV0aW9uLmA7XG4gICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7XG4gICAgICBwaGFzZTogXCJnaG9zdC1jb21wbGV0aW9uXCIsXG4gICAgICBpdGVyYXRpb246IGljLml0ZXJhdGlvbixcbiAgICAgIHVuaXRUeXBlLFxuICAgICAgdW5pdElkLFxuICAgICAgZWxhcHNlZE1zOiBEYXRlLm5vdygpIC0gKHVuaXRSZXN1bHQucmVxdWVzdERpc3BhdGNoZWRBdCA/PyBzLmN1cnJlbnRVbml0LnN0YXJ0ZWRBdCksXG4gICAgfSk7XG4gICAgbG9nV2FybmluZyhcImVuZ2luZVwiLCBtZXNzYWdlKTtcbiAgICBjdHgudWkubm90aWZ5KGAke21lc3NhZ2V9IFBhdXNpbmcgYXV0by1tb2RlIGJlZm9yZSBjbG9zZW91dCBzaWRlIGVmZmVjdHMuYCwgXCJ3YXJuaW5nXCIpO1xuICAgIGF3YWl0IGVtaXRDYW5jZWxsZWRVbml0RW5kKGljLCB1bml0VHlwZSwgdW5pdElkLCB1bml0U3RhcnRTZXEsIHtcbiAgICAgIG1lc3NhZ2UsXG4gICAgICBjYXRlZ29yeTogXCJ1bmtub3duXCIsXG4gICAgICBpc1RyYW5zaWVudDogdHJ1ZSxcbiAgICB9KTtcbiAgICBzLmN1cnJlbnRVbml0ID0gbnVsbDtcbiAgICBhd2FpdCBkZXBzLnBhdXNlQXV0byhjdHgsIHBpKTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcImdob3N0LWNvbXBsZXRpb25cIiB9O1xuICB9XG5cbiAgLy8gTm93IHRoYXQgcnVuVW5pdCBoYXMgY2FsbGVkIG5ld1Nlc3Npb24oKSwgdGhlIHNlc3Npb24gZmlsZSBwYXRoIGlzIGNvcnJlY3QuXG4gIGNvbnN0IHNlc3Npb25GaWxlID0gZGVwcy5nZXRTZXNzaW9uRmlsZShjdHgpO1xuICBkZXBzLnVwZGF0ZVNlc3Npb25Mb2NrKFxuICAgIGRlcHMubG9ja0Jhc2UoKSxcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgc2Vzc2lvbkZpbGUsXG4gICk7XG4gIGRlcHMud3JpdGVMb2NrKFxuICAgIGRlcHMubG9ja0Jhc2UoKSxcbiAgICB1bml0VHlwZSxcbiAgICB1bml0SWQsXG4gICAgc2Vzc2lvbkZpbGUsXG4gICk7XG5cbiAgLy8gVGFnIHRoZSBtb3N0IHJlY2VudCB3aW5kb3cgZW50cnkgd2l0aCBlcnJvciBpbmZvIGZvciBzdHVjayBkZXRlY3Rpb25cbiAgY29uc3QgbGFzdEVudHJ5ID0gbG9vcFN0YXRlLnJlY2VudFVuaXRzW2xvb3BTdGF0ZS5yZWNlbnRVbml0cy5sZW5ndGggLSAxXTtcbiAgaWYgKGxhc3RFbnRyeSkge1xuICAgIGlmICh1bml0UmVzdWx0LmVycm9yQ29udGV4dCkge1xuICAgICAgbGFzdEVudHJ5LmVycm9yID0gYCR7dW5pdFJlc3VsdC5lcnJvckNvbnRleHQuY2F0ZWdvcnl9OiR7dW5pdFJlc3VsdC5lcnJvckNvbnRleHQubWVzc2FnZX1gLnNsaWNlKDAsIDIwMCk7XG4gICAgfSBlbHNlIGlmICh1bml0UmVzdWx0LnN0YXR1cyA9PT0gXCJlcnJvclwiIHx8IHVuaXRSZXN1bHQuc3RhdHVzID09PSBcImNhbmNlbGxlZFwiKSB7XG4gICAgICBsYXN0RW50cnkuZXJyb3IgPSBgJHt1bml0UmVzdWx0LnN0YXR1c306JHt1bml0VHlwZX0vJHt1bml0SWR9YDtcbiAgICB9IGVsc2UgaWYgKHVuaXRSZXN1bHQuZXZlbnQ/Lm1lc3NhZ2VzPy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGxhc3RNc2cgPSB1bml0UmVzdWx0LmV2ZW50Lm1lc3NhZ2VzW3VuaXRSZXN1bHQuZXZlbnQubWVzc2FnZXMubGVuZ3RoIC0gMV07XG4gICAgICBjb25zdCBtc2dTdHIgPSB0eXBlb2YgbGFzdE1zZyA9PT0gXCJzdHJpbmdcIiA/IGxhc3RNc2cgOiBKU09OLnN0cmluZ2lmeShsYXN0TXNnKTtcbiAgICAgIGlmICgvZXJyb3J8ZmFpbHxleGNlcHRpb24vaS50ZXN0KG1zZ1N0cikpIHtcbiAgICAgICAgbGFzdEVudHJ5LmVycm9yID0gbXNnU3RyLnNsaWNlKDAsIDIwMCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaWYgKHVuaXRSZXN1bHQuc3RhdHVzID09PSBcImNhbmNlbGxlZFwiKSB7XG4gICAgY29uc3QgZXJyb3JDYXRlZ29yeSA9IHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0Py5jYXRlZ29yeTtcbiAgICAvLyBQcm92aWRlci1lcnJvciBwYXVzZTogYWdlbnRfZW5kIHJlY292ZXJ5IG5vcm1hbGx5IHBhdXNlcyBiZWZvcmUgdGhpc1xuICAgIC8vIGJyYW5jaC4gUHJvdmlkZXIgcmVhZGluZXNzIGZhaWx1cmVzIGhhcHBlbiBiZWZvcmUgZGlzcGF0Y2gsIHNvIHBhdXNlIGhlcmVcbiAgICAvLyBpZiBub3RoaW5nIHVwc3RyZWFtIGFscmVhZHkgZGlkLlxuICAgIGlmIChlcnJvckNhdGVnb3J5ID09PSBcInByb3ZpZGVyXCIpIHtcbiAgICAgIGlmICghcy5wYXVzZWQpIHtcbiAgICAgICAgY29uc3QgZGV0YWlsID0gdW5pdFJlc3VsdC5lcnJvckNvbnRleHQ/Lm1lc3NhZ2UgPz8gYFByb3ZpZGVyIHVuYXZhaWxhYmxlIGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH1gO1xuICAgICAgICBhd2FpdCBwYXVzZUF1dG9Gb3JQcm92aWRlckVycm9yKFxuICAgICAgICAgIGN0eC51aSxcbiAgICAgICAgICBkZXRhaWwsXG4gICAgICAgICAgKCkgPT4gZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSksXG4gICAgICAgICAge1xuICAgICAgICAgICAgaXNSYXRlTGltaXQ6IGZhbHNlLFxuICAgICAgICAgICAgaXNUcmFuc2llbnQ6IEJvb2xlYW4odW5pdFJlc3VsdC5lcnJvckNvbnRleHQ/LmlzVHJhbnNpZW50KSxcbiAgICAgICAgICAgIHJldHJ5QWZ0ZXJNczogdW5pdFJlc3VsdC5lcnJvckNvbnRleHQ/LnJldHJ5QWZ0ZXJNcyxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgYXdhaXQgZW1pdENhbmNlbGxlZFVuaXRFbmQoaWMsIHVuaXRUeXBlLCB1bml0SWQsIHVuaXRTdGFydFNlcSwgdW5pdFJlc3VsdC5lcnJvckNvbnRleHQpO1xuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImV4aXRcIiwgcmVhc29uOiBcInByb3ZpZGVyLXBhdXNlXCIsIGlzVHJhbnNpZW50OiB1bml0UmVzdWx0LmVycm9yQ29udGV4dD8uaXNUcmFuc2llbnQgfSk7XG4gICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInByb3ZpZGVyLXBhdXNlXCIgfTtcbiAgICB9XG4gICAgLy8gVGltZW91dCBjYXRlZ29yeSBjb3ZlcnMgdHdvIGRpc3RpbmN0IHNjZW5hcmlvczpcbiAgICAvLyAgIDEuIFNlc3Npb24gY3JlYXRpb24gdGltZW91dCAoMTIwcykg4oCUIHRyYW5zaWVudCwgYXV0by1yZXN1bWUgd2l0aCBiYWNrb2ZmXG4gICAgLy8gICAyLiBVbml0IGhhcmQgdGltZW91dCAoMzBtaW4rKSDigJQgc3R1Y2sgYWdlbnQsIHBhdXNlIGZvciBtYW51YWwgcmV2aWV3XG4gICAgLy8gVHJhbnNpZW50IHNlc3Npb24tZmFpbGVkIGNvdmVycyByZWNvdmVyYWJsZSBuZXdTZXNzaW9uIGZhaWx1cmVzIGFuZCBzaG91bGRcbiAgICAvLyBwYXVzZSBpbnN0ZWFkIG9mIGhhcmQtc3RvcHBpbmcuXG4gICAgLy8gU3RydWN0dXJhbCBlcnJvcnMgKFR5cGVFcnJvciwgaXMgbm90IGEgZnVuY3Rpb24pIGFyZSBOT1QgdHJhbnNpZW50XG4gICAgLy8gYW5kIG11c3QgaGFyZC1zdG9wIHRvIGF2b2lkIGluZmluaXRlIHJldHJ5IGxvb3BzLlxuICAgIGlmIChcbiAgICAgIHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0Py5pc1RyYW5zaWVudCAmJlxuICAgICAgZXJyb3JDYXRlZ29yeSA9PT0gXCJ0aW1lb3V0XCJcbiAgICApIHtcbiAgICAgIGNvbnN0IGlzU2Vzc2lvbkNyZWF0aW9uVGltZW91dCA9IHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0Lm1lc3NhZ2U/LmluY2x1ZGVzKFwiU2Vzc2lvbiBjcmVhdGlvbiB0aW1lZCBvdXRcIik7XG5cbiAgICAgIGlmIChpc1Nlc3Npb25DcmVhdGlvblRpbWVvdXQpIHtcbiAgICAgICAgY29uc2VjdXRpdmVTZXNzaW9uVGltZW91dHMgKz0gMTtcbiAgICAgICAgY29uc3QgYmFzZVJldHJ5QWZ0ZXJNcyA9IDMwXzAwMDtcbiAgICAgICAgY29uc3QgcmV0cnlBZnRlck1zID0gYmFzZVJldHJ5QWZ0ZXJNcyAqIDIgKiogTWF0aC5tYXgoMCwgY29uc2VjdXRpdmVTZXNzaW9uVGltZW91dHMgLSAxKTtcbiAgICAgICAgY29uc3QgYWxsb3dBdXRvUmVzdW1lID0gY29uc2VjdXRpdmVTZXNzaW9uVGltZW91dHMgPD0gTUFYX1NFU1NJT05fVElNRU9VVF9BVVRPX1JFU1VNRVM7XG5cbiAgICAgICAgaWYgKCFhbGxvd0F1dG9SZXN1bWUpIHtcbiAgICAgICAgICBjdHgudWkubm90aWZ5KFxuICAgICAgICAgICAgYFNlc3Npb24gY3JlYXRpb24gdGltZWQgb3V0ICR7Y29uc2VjdXRpdmVTZXNzaW9uVGltZW91dHN9IGNvbnNlY3V0aXZlIHRpbWVzIGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH0uIFBhdXNpbmcgZm9yIG1hbnVhbCByZXZpZXcuYCxcbiAgICAgICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHtcbiAgICAgICAgICBwaGFzZTogXCJzZXNzaW9uLXRpbWVvdXQtcGF1c2VcIixcbiAgICAgICAgICB1bml0VHlwZSwgdW5pdElkLFxuICAgICAgICAgIGNvbnNlY3V0aXZlU2Vzc2lvblRpbWVvdXRzLFxuICAgICAgICAgIHJldHJ5QWZ0ZXJNcyxcbiAgICAgICAgICBhbGxvd0F1dG9SZXN1bWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGVycm9yRGV0YWlsID0gYCBmb3IgJHt1bml0VHlwZX0gJHt1bml0SWR9YDtcbiAgICAgICAgYXdhaXQgcGF1c2VBdXRvRm9yUHJvdmlkZXJFcnJvcihcbiAgICAgICAgICBjdHgudWksXG4gICAgICAgICAgZXJyb3JEZXRhaWwsXG4gICAgICAgICAgKCkgPT4gZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSksXG4gICAgICAgICAge1xuICAgICAgICAgICAgaXNSYXRlTGltaXQ6IGZhbHNlLFxuICAgICAgICAgICAgaXNUcmFuc2llbnQ6IGFsbG93QXV0b1Jlc3VtZSxcbiAgICAgICAgICAgIHJldHJ5QWZ0ZXJNcyxcbiAgICAgICAgICAgIHJlc3VtZTogYWxsb3dBdXRvUmVzdW1lXG4gICAgICAgICAgICAgID8gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgdm9pZCByZXN1bWVBdXRvQWZ0ZXJQcm92aWRlckRlbGF5KHBpLCBjdHgpLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbWVzc2FnZSA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgICAgICAgICAgICAgICBgU2Vzc2lvbiB0aW1lb3V0IHJlY292ZXJ5IGZhaWxlZDogJHttZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICAgICAgXCJlcnJvclwiLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuICAgICAgICBhd2FpdCBkZXBzLmF1dG9Db21taXRVbml0Py4ocy5iYXNlUGF0aCwgdW5pdFR5cGUsIHVuaXRJZCwgY3R4KTtcbiAgICAgICAgYXdhaXQgZW1pdENhbmNlbGxlZFVuaXRFbmQoaWMsIHVuaXRUeXBlLCB1bml0SWQsIHVuaXRTdGFydFNlcSwgdW5pdFJlc3VsdC5lcnJvckNvbnRleHQpO1xuICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInNlc3Npb24tdGltZW91dFwiIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFVuaXQgaGFyZCB0aW1lb3V0ICgzMG1pbispOiBwYXVzZSB3aXRob3V0IGF1dG8tcmVzdW1lIOKAlCBzdHVjayBhZ2VudFxuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYFVuaXQgdGltZWQgb3V0IGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH0gKHN1cGVydmlzaW9uIG1heSBoYXZlIGZhaWxlZCkuIFBhdXNpbmcgYXV0by1tb2RlLmAsXG4gICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgKTtcbiAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJ1bml0LWhhcmQtdGltZW91dC1wYXVzZVwiLCB1bml0VHlwZSwgdW5pdElkIH0pO1xuICAgICAgYXdhaXQgZGVwcy5wYXVzZUF1dG8oY3R4LCBwaSk7XG4gICAgICBhd2FpdCBkZXBzLmF1dG9Db21taXRVbml0Py4ocy5iYXNlUGF0aCwgdW5pdFR5cGUsIHVuaXRJZCwgY3R4KTtcbiAgICAgIGF3YWl0IGVtaXRDYW5jZWxsZWRVbml0RW5kKGljLCB1bml0VHlwZSwgdW5pdElkLCB1bml0U3RhcnRTZXEsIHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0KTtcbiAgICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwidW5pdC1oYXJkLXRpbWVvdXRcIiB9O1xuICAgIH1cbiAgICBpZiAoXG4gICAgICB1bml0UmVzdWx0LmVycm9yQ29udGV4dD8uaXNUcmFuc2llbnQgJiZcbiAgICAgIGVycm9yQ2F0ZWdvcnkgPT09IFwic2Vzc2lvbi1mYWlsZWRcIlxuICAgICkge1xuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYFNlc3Npb24gY3JlYXRpb24gZmFpbGVkIHRyYW5zaWVudGx5IGZvciAke3VuaXRUeXBlfSAke3VuaXRJZH06ICR7dW5pdFJlc3VsdC5lcnJvckNvbnRleHQ/Lm1lc3NhZ2UgPz8gXCJ1bmtub3duXCJ9LiBQYXVzaW5nIGF1dG8tbW9kZSAocmVjb3ZlcmFibGUpLmAsXG4gICAgICAgIFwid2FybmluZ1wiLFxuICAgICAgKTtcbiAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJzZXNzaW9uLXN0YXJ0LXRyYW5zaWVudC1wYXVzZVwiLCB1bml0VHlwZSwgdW5pdElkLCBjYXRlZ29yeTogZXJyb3JDYXRlZ29yeSB9KTtcbiAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgYXdhaXQgZGVwcy5hdXRvQ29tbWl0VW5pdD8uKHMuYmFzZVBhdGgsIHVuaXRUeXBlLCB1bml0SWQsIGN0eCk7XG4gICAgICBhd2FpdCBlbWl0Q2FuY2VsbGVkVW5pdEVuZChpYywgdW5pdFR5cGUsIHVuaXRJZCwgdW5pdFN0YXJ0U2VxLCB1bml0UmVzdWx0LmVycm9yQ29udGV4dCk7XG4gICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInNlc3Npb24tdGltZW91dFwiIH07XG4gICAgfVxuICAgIGlmIChcbiAgICAgIHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0Py5pc1RyYW5zaWVudCAmJlxuICAgICAgZXJyb3JDYXRlZ29yeSA9PT0gXCJhYm9ydGVkXCJcbiAgICApIHtcbiAgICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICAgIGBVbml0ICR7dW5pdFR5cGV9ICR7dW5pdElkfSB3YXMgYWJvcnRlZCBieSB0aGUgdXNlci4gUGF1c2luZyBhdXRvLW1vZGUgKHJlY292ZXJhYmxlKS5gLFxuICAgICAgICBcIndhcm5pbmdcIixcbiAgICAgICk7XG4gICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwidW5pdC1hYm9ydGVkLXRyYW5zaWVudC1wYXVzZVwiLCB1bml0VHlwZSwgdW5pdElkLCBjYXRlZ29yeTogZXJyb3JDYXRlZ29yeSB9KTtcbiAgICAgIGF3YWl0IGRlcHMucGF1c2VBdXRvKGN0eCwgcGkpO1xuICAgICAgYXdhaXQgZGVwcy5hdXRvQ29tbWl0VW5pdD8uKHMuYmFzZVBhdGgsIHVuaXRUeXBlLCB1bml0SWQsIGN0eCk7XG4gICAgICBhd2FpdCBlbWl0Q2FuY2VsbGVkVW5pdEVuZChpYywgdW5pdFR5cGUsIHVuaXRJZCwgdW5pdFN0YXJ0U2VxLCB1bml0UmVzdWx0LmVycm9yQ29udGV4dCk7XG4gICAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInVuaXQtYWJvcnRlZC1wYXVzZVwiIH07XG4gICAgfVxuICAgIC8vIEFsbCBvdGhlciBjYW5jZWxsZWQgc3RhdGVzIChzdHJ1Y3R1cmFsIGVycm9ycywgbm9uLXRyYW5zaWVudCBmYWlsdXJlcyk6IGhhcmQgc3RvcFxuICAgIGlmIChzLmN1cnJlbnRVbml0KSB7XG4gICAgICBhd2FpdCBkZXBzLmNsb3Nlb3V0VW5pdChcbiAgICAgICAgY3R4LFxuICAgICAgICBzLmJhc2VQYXRoLFxuICAgICAgICB1bml0VHlwZSxcbiAgICAgICAgdW5pdElkLFxuICAgICAgICBzLmN1cnJlbnRVbml0LnN0YXJ0ZWRBdCxcbiAgICAgICAgZGVwcy5idWlsZFNuYXBzaG90T3B0cyh1bml0VHlwZSwgdW5pdElkKSxcbiAgICAgICk7XG4gICAgfVxuICAgIGF3YWl0IGRlcHMuYXV0b0NvbW1pdFVuaXQ/LihzLmJhc2VQYXRoLCB1bml0VHlwZSwgdW5pdElkLCBjdHgpO1xuICAgIGF3YWl0IGVtaXRDYW5jZWxsZWRVbml0RW5kKGljLCB1bml0VHlwZSwgdW5pdElkLCB1bml0U3RhcnRTZXEsIHVuaXRSZXN1bHQuZXJyb3JDb250ZXh0KTtcblxuICAgIGNvbnN0IGNhbmNlbGxlZFN0b3AgPSBfYnVpbGRDYW5jZWxsZWRVbml0U3RvcFJlYXNvbihcbiAgICAgIHVuaXRUeXBlLFxuICAgICAgdW5pdElkLFxuICAgICAgdW5pdFJlc3VsdC5lcnJvckNvbnRleHQsXG4gICAgKTtcbiAgICBjdHgudWkubm90aWZ5KGNhbmNlbGxlZFN0b3Aubm90aWZ5TWVzc2FnZSwgXCJ3YXJuaW5nXCIpO1xuICAgIGF3YWl0IGRlcHMuc3RvcEF1dG8oY3R4LCBwaSwgY2FuY2VsbGVkU3RvcC5zdG9wUmVhc29uKTtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IGNhbmNlbGxlZFN0b3AubG9vcFJlYXNvbiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBjYW5jZWxsZWRTdG9wLmxvb3BSZWFzb24gfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJbW1lZGlhdGUgdW5pdCBjbG9zZW91dCAobWV0cmljcywgYWN0aXZpdHkgbG9nLCBtZW1vcnkpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBSdW4gcmlnaHQgYWZ0ZXIgcnVuVW5pdCgpIHJldHVybnMgc28gdGVsZW1ldHJ5IGlzIG5ldmVyIGxvc3QgdG8gYVxuICAvLyBjcmFzaCBiZXR3ZWVuIGl0ZXJhdGlvbnMuXG4gIC8vIEd1YXJkOiBzdG9wQXV0bygpIG1heSBoYXZlIG51bGxlZCBzLmN1cnJlbnRVbml0IHZpYSBzLnJlc2V0KCkgd2hpbGVcbiAgLy8gdGhpcyBjb3JvdXRpbmUgd2FzIHN1c3BlbmRlZCBhdCBgYXdhaXQgcnVuVW5pdCguLi4pYCAoIzI5MzkpLlxuICBpZiAocy5jdXJyZW50VW5pdCkge1xuICAgIC8vIFJlc2V0IHNlc3Npb24gdGltZW91dCBjb3VudGVyIOKAlCBhbnkgc3VjY2Vzc2Z1bCB1bml0IGNsZWFycyB0aGUgc2xhdGVcbiAgICBjb25zZWN1dGl2ZVNlc3Npb25UaW1lb3V0cyA9IDA7XG4gICAgYXdhaXQgZGVwcy5jbG9zZW91dFVuaXQoXG4gICAgICBjdHgsXG4gICAgICBzLmJhc2VQYXRoLFxuICAgICAgdW5pdFR5cGUsXG4gICAgICB1bml0SWQsXG4gICAgICBzLmN1cnJlbnRVbml0LnN0YXJ0ZWRBdCxcbiAgICAgIGRlcHMuYnVpbGRTbmFwc2hvdE9wdHModW5pdFR5cGUsIHVuaXRJZCksXG4gICAgKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBaZXJvIHRvb2wtY2FsbCBndWFyZCAoIzE4MzMsICMyNjUzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gQW55IHVuaXQgdGhhdCBjb21wbGV0ZXMgd2l0aCAwIHRvb2wgY2FsbHMgbWFkZSBubyByZWFsIHByb2dyZXNzIOKAlFxuICAvLyBsaWtlbHkgY29udGV4dCBleGhhdXN0aW9uIHdoZXJlIGFsbCB0b29sIGNhbGxzIGVycm9yZWQgb3V0LiBUcmVhdFxuICAvLyBhcyBmYWlsZWQgc28gdGhlIHVuaXQgaXMgcmV0cmllZCBpbiBhIGZyZXNoIGNvbnRleHQgaW5zdGVhZCBvZlxuICAvLyBzaWxlbnRseSBwYXNzaW5nIHRocm91Z2ggdG8gYXJ0aWZhY3QgdmVyaWZpY2F0aW9uICh3aGljaCBsb29wc1xuICAvLyBmb3JldmVyIHdoZW4gdGhlIHVuaXQgbmV2ZXIgcHJvZHVjZWQgaXRzIGFydGlmYWN0KS5cbiAge1xuICAgIGNvbnN0IGN1cnJlbnRMZWRnZXIgPSBkZXBzLmdldExlZGdlcigpIGFzIHsgdW5pdHM6IEFycmF5PHsgdHlwZTogc3RyaW5nOyBpZDogc3RyaW5nOyBzdGFydGVkQXQ6IG51bWJlcjsgdG9vbENhbGxzOiBudW1iZXIgfT4gfSB8IG51bGw7XG4gICAgaWYgKGN1cnJlbnRMZWRnZXI/LnVuaXRzKSB7XG4gICAgICBjb25zdCBsYXN0VW5pdCA9IFsuLi5jdXJyZW50TGVkZ2VyLnVuaXRzXS5yZXZlcnNlKCkuZmluZChcbiAgICAgICAgKHU6IHsgdHlwZTogc3RyaW5nOyBpZDogc3RyaW5nOyBzdGFydGVkQXQ6IG51bWJlcjsgdG9vbENhbGxzOiBudW1iZXIgfSkgPT4gdS50eXBlID09PSB1bml0VHlwZSAmJiB1LmlkID09PSB1bml0SWQgJiYgdS5zdGFydGVkQXQgPT09IF9yZXNvbHZlQ3VycmVudFVuaXRTdGFydGVkQXRGb3JUZXN0KHMuY3VycmVudFVuaXQpLFxuICAgICAgKTtcbiAgICAgIGlmIChsYXN0VW5pdCAmJiBsYXN0VW5pdC50b29sQ2FsbHMgPT09IDApIHtcbiAgICAgICAgaWYgKFVTRVJfRFJJVkVOX0RFRVBfVU5JVFMuaGFzKHVuaXRUeXBlKSAmJiBpc0F3YWl0aW5nVXNlcklucHV0KHMubGFzdFVuaXRBZ2VudEVuZE1lc3NhZ2VzID8/IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgICBkZWJ1Z0xvZyhcInJ1blVuaXRQaGFzZVwiLCB7XG4gICAgICAgICAgICBwaGFzZTogXCJ6ZXJvLXRvb2wtY2FsbHMtYXdhaXRpbmctdXNlci1pbnB1dFwiLFxuICAgICAgICAgICAgdW5pdFR5cGUsXG4gICAgICAgICAgICB1bml0SWQsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGVidWdMb2coXCJydW5Vbml0UGhhc2VcIiwge1xuICAgICAgICAgICAgcGhhc2U6IFwiemVyby10b29sLWNhbGxzXCIsXG4gICAgICAgICAgICB1bml0VHlwZSxcbiAgICAgICAgICAgIHVuaXRJZCxcbiAgICAgICAgICAgIHdhcm5pbmc6IFwiVW5pdCBjb21wbGV0ZWQgd2l0aCAwIHRvb2wgY2FsbHMg4oCUIGxpa2VseSBjb250ZXh0IGV4aGF1c3Rpb24sIG1hcmtpbmcgYXMgZmFpbGVkXCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgICAgIGAke3VuaXRUeXBlfSAke3VuaXRJZH0gY29tcGxldGVkIHdpdGggMCB0b29sIGNhbGxzIOKAlCBjb250ZXh0IGV4aGF1c3Rpb24sIHdpbGwgcmV0cnlgLFxuICAgICAgICAgICAgXCJ3YXJuaW5nXCIsXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBGYWxsIHRocm91Z2ggdG8gbmV4dCBpdGVyYXRpb24gd2hlcmUgZGlzcGF0Y2ggd2lsbCByZS1kZXJpdmVcbiAgICAgICAgICAvLyBhbmQgcmUtZGlzcGF0Y2ggdGhpcyB1bml0LlxuICAgICAgICAgIHJldHVybiB7IGFjdGlvbjogXCJuZXh0XCIsIGRhdGE6IHsgdW5pdFN0YXJ0ZWRBdDogX3Jlc29sdmVDdXJyZW50VW5pdFN0YXJ0ZWRBdEZvclRlc3Qocy5jdXJyZW50VW5pdCksIHJlcXVlc3REaXNwYXRjaGVkQXQ6IHVuaXRSZXN1bHQucmVxdWVzdERpc3BhdGNoZWRBdCB9IH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBza2lwQXJ0aWZhY3RWZXJpZmljYXRpb24gPSB1bml0VHlwZS5zdGFydHNXaXRoKFwiaG9vay9cIikgfHwgdW5pdFR5cGUgPT09IFwiY3VzdG9tLXN0ZXBcIjtcbiAgY29uc3QgYXJ0aWZhY3RWZXJpZmllZCA9XG4gICAgc2tpcEFydGlmYWN0VmVyaWZpY2F0aW9uIHx8XG4gICAgdmVyaWZ5RXhwZWN0ZWRBcnRpZmFjdCh1bml0VHlwZSwgdW5pdElkLCBzLmJhc2VQYXRoKTtcbiAgaWYgKHMuY3VycmVudFVuaXRSb3V0aW5nKSB7XG4gICAgZGVwcy5yZWNvcmRPdXRjb21lKFxuICAgICAgdW5pdFR5cGUsXG4gICAgICBzLmN1cnJlbnRVbml0Um91dGluZy50aWVyIGFzIFwibGlnaHRcIiB8IFwic3RhbmRhcmRcIiB8IFwiaGVhdnlcIixcbiAgICAgIGFydGlmYWN0VmVyaWZpZWQsXG4gICAgKTtcbiAgfVxuICBpZiAoYXJ0aWZhY3RWZXJpZmllZCkge1xuICAgIHMudW5pdERpc3BhdGNoQ291bnQuZGVsZXRlKGRpc3BhdGNoS2V5KTtcbiAgICBzLnVuaXRSZWNvdmVyeUNvdW50LmRlbGV0ZShgJHt1bml0VHlwZX0vJHt1bml0SWR9YCk7XG4gIH1cblxuICAvLyBXcml0ZSBwaGFzZSBoYW5kb2ZmIGFuY2hvciBhZnRlciBzdWNjZXNzZnVsIHJlc2VhcmNoL3BsYW5uaW5nIGNvbXBsZXRpb25cbiAgY29uc3QgYW5jaG9yUGhhc2VzID0gbmV3IFNldChbXCJyZXNlYXJjaC1taWxlc3RvbmVcIiwgXCJyZXNlYXJjaC1zbGljZVwiLCBcInBsYW4tbWlsZXN0b25lXCIsIFwicGxhbi1zbGljZVwiXSk7XG4gIGlmIChhcnRpZmFjdFZlcmlmaWVkICYmIG1pZCAmJiBhbmNob3JQaGFzZXMuaGFzKHVuaXRUeXBlKSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHdyaXRlUGhhc2VBbmNob3IgfSA9IGF3YWl0IGltcG9ydChcIi4uL3BoYXNlLWFuY2hvci5qc1wiKTtcbiAgICAgIHdyaXRlUGhhc2VBbmNob3Iocy5iYXNlUGF0aCwgbWlkLCB7XG4gICAgICAgIHBoYXNlOiB1bml0VHlwZSxcbiAgICAgICAgbWlsZXN0b25lSWQ6IG1pZCxcbiAgICAgICAgZ2VuZXJhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgaW50ZW50OiBgQ29tcGxldGVkICR7dW5pdFR5cGV9IGZvciAke3VuaXRJZH1gLFxuICAgICAgICBkZWNpc2lvbnM6IFtdLFxuICAgICAgICBibG9ja2VyczogW10sXG4gICAgICAgIG5leHRTdGVwczogW10sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHsgLyogbm9uLWZhdGFsIOKAlCBhbmNob3IgaXMgYWR2aXNvcnkgKi9cbiAgICAgIGxvZ1dhcm5pbmcoXCJlbmdpbmVcIiwgYHBoYXNlIGFuY2hvciBmYWlsZWQ6ICR7ZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpfWApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHVuaXRFbmRTdGF0dXMgPVxuICAgICFhcnRpZmFjdFZlcmlmaWVkICYmIHVuaXRSZXN1bHQuc3RhdHVzID09PSBcImNvbXBsZXRlZFwiXG4gICAgICA/IFwibm8tYXJ0aWZhY3RcIlxuICAgICAgOiB1bml0UmVzdWx0LnN0YXR1cztcbiAgZGVwcy5lbWl0Sm91cm5hbEV2ZW50KHsgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwgZmxvd0lkOiBpYy5mbG93SWQsIHNlcTogaWMubmV4dFNlcSgpLCBldmVudFR5cGU6IFwidW5pdC1lbmRcIiwgZGF0YTogeyB1bml0VHlwZSwgdW5pdElkLCBzdGF0dXM6IHVuaXRFbmRTdGF0dXMsIGFydGlmYWN0VmVyaWZpZWQsIC4uLih1bml0UmVzdWx0LmVycm9yQ29udGV4dCA/IHsgZXJyb3JDb250ZXh0OiB1bml0UmVzdWx0LmVycm9yQ29udGV4dCB9IDoge30pIH0sIGNhdXNlZEJ5OiB7IGZsb3dJZDogaWMuZmxvd0lkLCBzZXE6IHVuaXRTdGFydFNlcSB9IH0pO1xuXG4gIC8vIOKUgOKUgCBTYWZldHkgaGFybmVzczogY2hlY2twb2ludCBjbGVhbnVwIG9yIHJvbGxiYWNrIOKUgOKUgFxuICBpZiAocy5jaGVja3BvaW50U2hhKSB7XG4gICAgaWYgKHVuaXRSZXN1bHQuc3RhdHVzID09PSBcImVycm9yXCIgJiYgc2FmZXR5Q29uZmlnLmF1dG9fcm9sbGJhY2spIHtcbiAgICAgIGNvbnN0IHJvbGxlZCA9IHJvbGxiYWNrVG9DaGVja3BvaW50KHMuYmFzZVBhdGgsIHVuaXRJZCwgcy5jaGVja3BvaW50U2hhKTtcbiAgICAgIGlmIChyb2xsZWQpIHtcbiAgICAgICAgY3R4LnVpLm5vdGlmeShgUm9sbGVkIGJhY2sgdG8gcHJlLXVuaXQgY2hlY2twb2ludCBmb3IgJHt1bml0SWR9YCwgXCJpbmZvXCIpO1xuICAgICAgICBkZWJ1Z0xvZyhcInJ1blVuaXRQaGFzZVwiLCB7IHBoYXNlOiBcImNoZWNrcG9pbnQtcm9sbGJhY2tcIiwgdW5pdElkIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodW5pdFJlc3VsdC5zdGF0dXMgPT09IFwiZXJyb3JcIikge1xuICAgICAgY3R4LnVpLm5vdGlmeShcbiAgICAgICAgYFVuaXQgJHt1bml0SWR9IGZhaWxlZC4gUHJlLXVuaXQgY2hlY2twb2ludCBhdmFpbGFibGUgYXQgJHtzLmNoZWNrcG9pbnRTaGEuc2xpY2UoMCwgOCl9YCxcbiAgICAgICAgXCJ3YXJuaW5nXCIsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTdWNjZXNzIOKAlCBjbGVhbiB1cCBjaGVja3BvaW50IHJlZlxuICAgICAgY2xlYW51cENoZWNrcG9pbnQocy5iYXNlUGF0aCwgdW5pdElkKTtcbiAgICAgIGRlYnVnTG9nKFwicnVuVW5pdFBoYXNlXCIsIHsgcGhhc2U6IFwiY2hlY2twb2ludC1jbGVhbmVkXCIsIHVuaXRJZCB9KTtcbiAgICB9XG4gICAgcy5jaGVja3BvaW50U2hhID0gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB7IGFjdGlvbjogXCJuZXh0XCIsIGRhdGE6IHsgdW5pdFN0YXJ0ZWRBdDogX3Jlc29sdmVDdXJyZW50VW5pdFN0YXJ0ZWRBdEZvclRlc3Qocy5jdXJyZW50VW5pdCksIHJlcXVlc3REaXNwYXRjaGVkQXQ6IHVuaXRSZXN1bHQucmVxdWVzdERpc3BhdGNoZWRBdCB9IH07XG59XG5cbi8vIOKUgOKUgOKUgCBydW5GaW5hbGl6ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBQaGFzZSA1OiBQb3N0LXVuaXQgZmluYWxpemUg4oCUIHByZS9wb3N0IHZlcmlmaWNhdGlvbiwgVUFUIHBhdXNlLCBzdGVwLXdpemFyZC5cbiAqIFJldHVybnMgYnJlYWsvY29udGludWUvbmV4dCB0byBjb250cm9sIHRoZSBvdXRlciBsb29wLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuRmluYWxpemUoXG4gIGljOiBJdGVyYXRpb25Db250ZXh0LFxuICBpdGVyRGF0YTogSXRlcmF0aW9uRGF0YSxcbiAgbG9vcFN0YXRlOiBMb29wU3RhdGUsXG4gIHNpZGVjYXJJdGVtPzogU2lkZWNhckl0ZW0sXG4pOiBQcm9taXNlPFBoYXNlUmVzdWx0PiB7XG4gIGNvbnN0IHsgY3R4LCBwaSwgcywgZGVwcyB9ID0gaWM7XG4gIGNvbnN0IHsgcGF1c2VBZnRlclVhdERpc3BhdGNoIH0gPSBpdGVyRGF0YTtcblxuICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZmluYWxpemVcIiwgaXRlcmF0aW9uOiBpYy5pdGVyYXRpb24gfSk7XG5cbiAgLy8gQ2xlYXIgdW5pdCB0aW1lb3V0ICh1bml0IGNvbXBsZXRlZClcbiAgZGVwcy5jbGVhclVuaXRUaW1lb3V0KCk7XG5cbiAgLy8gUG9zdC11bml0IGNvbnRleHQgZm9yIHByZS9wb3N0IHZlcmlmaWNhdGlvblxuICBjb25zdCBwb3N0VW5pdEN0eDogUG9zdFVuaXRDb250ZXh0ID0ge1xuICAgIHMsXG4gICAgY3R4LFxuICAgIHBpLFxuICAgIGJ1aWxkU25hcHNob3RPcHRzOiBkZXBzLmJ1aWxkU25hcHNob3RPcHRzLFxuICAgIGxvY2tCYXNlOiBkZXBzLmxvY2tCYXNlLFxuICAgIHN0b3BBdXRvOiBkZXBzLnN0b3BBdXRvLFxuICAgIHBhdXNlQXV0bzogZGVwcy5wYXVzZUF1dG8sXG4gICAgdXBkYXRlUHJvZ3Jlc3NXaWRnZXQ6IGRlcHMudXBkYXRlUHJvZ3Jlc3NXaWRnZXQsXG4gIH07XG5cbiAgLy8gUHJlLXZlcmlmaWNhdGlvbiBwcm9jZXNzaW5nIChjb21taXQsIGRvY3Rvciwgc3RhdGUgcmVidWlsZCwgZXRjLilcbiAgLy8gVGltZW91dCBndWFyZDogaWYgcG9zdFVuaXRQcmVWZXJpZmljYXRpb24gaGFuZ3MgKGUuZy4sIHNhZmV0eSBoYXJuZXNzXG4gIC8vIGRlYWRsb2NrLCBicm93c2VyIHRlYXJkb3duIGhhbmcsIHdvcmt0cmVlIHN5bmMgc3RhbGwpLCBmb3JjZS1jb250aW51ZVxuICAvLyBhZnRlciB0aW1lb3V0IHNvIHRoZSBhdXRvLWxvb3AgaXMgbm90IHBlcm1hbmVudGx5IGZyb3plbiAoIzM3NTcpLlxuICAvL1xuICAvLyBPbiB0aW1lb3V0LCBudWxsIG91dCBzLmN1cnJlbnRVbml0IHNvIHRoZSB0aW1lZC1vdXQgdGFzaydzIGxhdGUgYXN5bmNcbiAgLy8gbXV0YXRpb25zIGFyZSBoYXJtbGVzcyDigJQgcG9zdFVuaXRQcmVWZXJpZmljYXRpb24gZ3VhcmRzIGFsbCBzaWRlIGVmZmVjdHNcbiAgLy8gYmVoaW5kIGBpZiAocy5jdXJyZW50VW5pdClgLiBUaGUgbmV4dCBpdGVyYXRpb24gc2V0cyBhIGZyZXNoIGN1cnJlbnRVbml0LlxuICAvLyBTaWRlY2FyIGl0ZW1zIHVzZSBsaWdodHdlaWdodCBwcmUtdmVyaWZpY2F0aW9uIG9wdHNcbiAgY29uc3QgcHJlVmVyaWZpY2F0aW9uT3B0czogUHJlVmVyaWZpY2F0aW9uT3B0cyA9IHNpZGVjYXJJdGVtXG4gICAgPyBzaWRlY2FySXRlbS5raW5kID09PSBcImhvb2tcIlxuICAgICAgPyB7IHNraXBTZXR0bGVEZWxheTogdHJ1ZSwgc2tpcFdvcmt0cmVlU3luYzogdHJ1ZSwgYWdlbnRFbmRNZXNzYWdlczogcy5sYXN0VW5pdEFnZW50RW5kTWVzc2FnZXMgPz8gdW5kZWZpbmVkIH1cbiAgICAgIDogeyBza2lwU2V0dGxlRGVsYXk6IHRydWUsIGFnZW50RW5kTWVzc2FnZXM6IHMubGFzdFVuaXRBZ2VudEVuZE1lc3NhZ2VzID8/IHVuZGVmaW5lZCB9XG4gICAgOiB7IGFnZW50RW5kTWVzc2FnZXM6IHMubGFzdFVuaXRBZ2VudEVuZE1lc3NhZ2VzID8/IHVuZGVmaW5lZCB9O1xuICBjb25zdCBwcmVVbml0U25hcHNob3QgPSBzLmN1cnJlbnRVbml0XG4gICAgPyB7IHR5cGU6IHMuY3VycmVudFVuaXQudHlwZSwgaWQ6IHMuY3VycmVudFVuaXQuaWQsIHN0YXJ0ZWRBdDogcy5jdXJyZW50VW5pdC5zdGFydGVkQXQgfVxuICAgIDogbnVsbDtcbiAgcy5jdXJyZW50VW5pdCA9IG51bGw7XG4gIGNsZWFyQ3VycmVudFBoYXNlKCk7XG4gIGNvbnN0IHByZVJlc3VsdEd1YXJkID0gYXdhaXQgd2l0aFRpbWVvdXQoXG4gICAgZGVwcy5wb3N0VW5pdFByZVZlcmlmaWNhdGlvbihwb3N0VW5pdEN0eCwgcHJlVmVyaWZpY2F0aW9uT3B0cyksXG4gICAgRklOQUxJWkVfUFJFX1RJTUVPVVRfTVMsXG4gICAgXCJwb3N0VW5pdFByZVZlcmlmaWNhdGlvblwiLFxuICApO1xuXG4gIGlmIChwcmVSZXN1bHRHdWFyZC50aW1lZE91dCkge1xuICAgIHJldHVybiBmYWlsQ2xvc2VkT25GaW5hbGl6ZVRpbWVvdXQoXG4gICAgICBpYyxcbiAgICAgIGl0ZXJEYXRhLFxuICAgICAgbG9vcFN0YXRlLFxuICAgICAgXCJwcmVcIixcbiAgICAgIHByZVVuaXRTbmFwc2hvdD8uc3RhcnRlZEF0ID8/IERhdGUubm93KCksXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IHByZVJlc3VsdCA9IHByZVJlc3VsdEd1YXJkLnZhbHVlO1xuICBpZiAocHJlUmVzdWx0ID09PSBcImRpc3BhdGNoZWRcIikge1xuICAgIGNvbnN0IGRpc3BhdGNoZWRSZWFzb24gPSBzLmxhc3RHaXRBY3Rpb25GYWlsdXJlXG4gICAgICA/IFwiZ2l0LWNsb3Nlb3V0LWZhaWx1cmVcIlxuICAgICAgOiBcInByZS12ZXJpZmljYXRpb24tZGlzcGF0Y2hlZFwiO1xuICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwge1xuICAgICAgcGhhc2U6IFwiZXhpdFwiLFxuICAgICAgcmVhc29uOiBkaXNwYXRjaGVkUmVhc29uLFxuICAgICAgZ2l0RXJyb3I6IHMubGFzdEdpdEFjdGlvbkZhaWx1cmUgPz8gdW5kZWZpbmVkLFxuICAgIH0pO1xuICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IGRpc3BhdGNoZWRSZWFzb24gfTtcbiAgfVxuICBpZiAocHJlUmVzdWx0ID09PSBcInJldHJ5XCIpIHtcbiAgICBpZiAoc2lkZWNhckl0ZW0pIHtcbiAgICAgIC8vIFNpZGVjYXIgYXJ0aWZhY3QgcmV0cmllcyBhcmUgc2tpcHBlZCDigJQganVzdCBjb250aW51ZVxuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcInNpZGVjYXItYXJ0aWZhY3QtcmV0cnktc2tpcHBlZFwiLCBpdGVyYXRpb246IGljLml0ZXJhdGlvbiB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gcy5wZW5kaW5nVmVyaWZpY2F0aW9uUmV0cnkgd2FzIHNldCBieSBwb3N0VW5pdFByZVZlcmlmaWNhdGlvbi5cbiAgICAgIC8vIEVtaXQgYSBkZWRpY2F0ZWQgam91cm5hbCBldmVudCBzbyBmb3JlbnNpY3MgY2FuIGRpc3Rpbmd1aXNoIGJvdW5kZWRcbiAgICAgIC8vIHZlcmlmaWNhdGlvbiByZXRyaWVzIGZyb20gZ2VudWluZSBzdHVjay1sb29wIGRpc3BhdGNoIHJlcGV0aXRpb25zICgjNDU0MCkuXG4gICAgICBjb25zdCByZXRyeUluZm8gPSBzLnBlbmRpbmdWZXJpZmljYXRpb25SZXRyeTtcbiAgICAgIGRlcHMuZW1pdEpvdXJuYWxFdmVudCh7XG4gICAgICAgIHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIGZsb3dJZDogaWMuZmxvd0lkLFxuICAgICAgICBzZXE6IGljLm5leHRTZXEoKSxcbiAgICAgICAgZXZlbnRUeXBlOiBcImFydGlmYWN0LXZlcmlmaWNhdGlvbi1yZXRyeVwiLFxuICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgdW5pdFR5cGU6IHByZVVuaXRTbmFwc2hvdD8udHlwZSxcbiAgICAgICAgICB1bml0SWQ6IHJldHJ5SW5mbz8udW5pdElkLFxuICAgICAgICAgIGF0dGVtcHQ6IHJldHJ5SW5mbz8uYXR0ZW1wdCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcmV0cnlQb2xpY3lSZXN1bHQgPSBhd2FpdCBhcHBseVZlcmlmaWNhdGlvblJldHJ5UG9saWN5KFxuICAgICAgICBpYyxcbiAgICAgICAgcHJlVW5pdFNuYXBzaG90Py50eXBlLFxuICAgICAgICBcImFydGlmYWN0LXZlcmlmaWNhdGlvbi1yZXRyeVwiLFxuICAgICAgKTtcbiAgICAgIGlmIChyZXRyeVBvbGljeVJlc3VsdCkge1xuICAgICAgICByZXR1cm4gcmV0cnlQb2xpY3lSZXN1bHQ7XG4gICAgICB9XG4gICAgICAvLyBDb250aW51ZSB0aGUgbG9vcCDigJQgbmV4dCBpdGVyYXRpb24gd2lsbCBpbmplY3QgdGhlIHJldHJ5IGNvbnRleHQgaW50byB0aGUgcHJvbXB0LlxuICAgICAgZGVidWdMb2coXCJhdXRvTG9vcFwiLCB7IHBoYXNlOiBcImFydGlmYWN0LXZlcmlmaWNhdGlvbi1yZXRyeVwiLCBpdGVyYXRpb246IGljLml0ZXJhdGlvbiB9KTtcbiAgICAgIHJldHVybiB7IGFjdGlvbjogXCJjb250aW51ZVwiIH07XG4gICAgfVxuICB9XG5cbiAgaWYgKHBhdXNlQWZ0ZXJVYXREaXNwYXRjaCkge1xuICAgIGN0eC51aS5ub3RpZnkoXG4gICAgICBcIlVBVCByZXF1aXJlcyBodW1hbiBleGVjdXRpb24uIEF1dG8tbW9kZSB3aWxsIHBhdXNlIGFmdGVyIHRoaXMgdW5pdCB3cml0ZXMgdGhlIHJlc3VsdCBmaWxlLlwiLFxuICAgICAgXCJpbmZvXCIsXG4gICAgKTtcbiAgICBhd2FpdCBkZXBzLnBhdXNlQXV0byhjdHgsIHBpKTtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwidWF0LXBhdXNlXCIgfSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJ1YXQtcGF1c2VcIiB9O1xuICB9XG5cbiAgLy8gVmVyaWZpY2F0aW9uIGdhdGVcbiAgLy8gSG9vayBzaWRlY2FyIGl0ZW1zIHNraXAgdmVyaWZpY2F0aW9uIGVudGlyZWx5LlxuICAvLyBOb24taG9vayBzaWRlY2FyIGl0ZW1zIHJ1biB2ZXJpZmljYXRpb24gYnV0IHNraXAgcmV0cmllcyAoanVzdCBjb250aW51ZSkuXG4gIGNvbnN0IHNraXBWZXJpZmljYXRpb24gPSBzaWRlY2FySXRlbT8ua2luZCA9PT0gXCJob29rXCI7XG4gIGlmICghc2tpcFZlcmlmaWNhdGlvbikge1xuICAgIGNvbnN0IHZlcmlmaWNhdGlvblJlc3VsdCA9IGF3YWl0IGRlcHMucnVuUG9zdFVuaXRWZXJpZmljYXRpb24oXG4gICAgICB7IHMsIGN0eCwgcGkgfSxcbiAgICAgIGRlcHMucGF1c2VBdXRvLFxuICAgICk7XG5cbiAgICBpZiAodmVyaWZpY2F0aW9uUmVzdWx0ID09PSBcInBhdXNlXCIpIHtcbiAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJleGl0XCIsIHJlYXNvbjogXCJ2ZXJpZmljYXRpb24tcGF1c2VcIiB9KTtcbiAgICAgIHJldHVybiB7IGFjdGlvbjogXCJicmVha1wiLCByZWFzb246IFwidmVyaWZpY2F0aW9uLXBhdXNlXCIgfTtcbiAgICB9XG5cbiAgICBpZiAodmVyaWZpY2F0aW9uUmVzdWx0ID09PSBcInJldHJ5XCIpIHtcbiAgICAgIGlmIChzaWRlY2FySXRlbSkge1xuICAgICAgICAvLyBTaWRlY2FyIHZlcmlmaWNhdGlvbiByZXRyaWVzIGFyZSBza2lwcGVkIOKAlCBqdXN0IGNvbnRpbnVlXG4gICAgICAgIGRlYnVnTG9nKFwiYXV0b0xvb3BcIiwgeyBwaGFzZTogXCJzaWRlY2FyLXZlcmlmaWNhdGlvbi1yZXRyeS1za2lwcGVkXCIsIGl0ZXJhdGlvbjogaWMuaXRlcmF0aW9uIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gcy5wZW5kaW5nVmVyaWZpY2F0aW9uUmV0cnkgd2FzIHNldCBieSBydW5Qb3N0VW5pdFZlcmlmaWNhdGlvbi5cbiAgICAgICAgY29uc3QgcmV0cnlQb2xpY3lSZXN1bHQgPSBhd2FpdCBhcHBseVZlcmlmaWNhdGlvblJldHJ5UG9saWN5KFxuICAgICAgICAgIGljLFxuICAgICAgICAgIGl0ZXJEYXRhLnVuaXRUeXBlLFxuICAgICAgICAgIFwidmVyaWZpY2F0aW9uLXJldHJ5XCIsXG4gICAgICAgICk7XG4gICAgICAgIGlmIChyZXRyeVBvbGljeVJlc3VsdCkge1xuICAgICAgICAgIHJldHVybiByZXRyeVBvbGljeVJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICAvLyBDb250aW51ZSB0aGUgbG9vcCDigJQgbmV4dCBpdGVyYXRpb24gd2lsbCBpbmplY3QgdGhlIHJldHJ5IGNvbnRleHQgaW50byB0aGUgcHJvbXB0LlxuICAgICAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwidmVyaWZpY2F0aW9uLXJldHJ5XCIsIGl0ZXJhdGlvbjogaWMuaXRlcmF0aW9uIH0pO1xuICAgICAgICByZXR1cm4geyBhY3Rpb246IFwiY29udGludWVcIiB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFBvc3QtdmVyaWZpY2F0aW9uIHByb2Nlc3NpbmcgKERCIGR1YWwtd3JpdGUsIGhvb2tzLCB0cmlhZ2UsIHF1aWNrLXRhc2tzKVxuICAvLyBUaW1lb3V0IGd1YXJkOiBpZiBwb3N0VW5pdFBvc3RWZXJpZmljYXRpb24gaGFuZ3MgKGUuZy4sIG1vZHVsZSBpbXBvcnRcbiAgLy8gZGVhZGxvY2ssIFNRTGl0ZSB0cmFuc2FjdGlvbiBoYW5nKSwgZm9yY2UtY29udGludWUgYWZ0ZXIgdGltZW91dCBzbyB0aGVcbiAgLy8gYXV0by1sb29wIGlzIG5vdCBwZXJtYW5lbnRseSBmcm96ZW4gKCMyMzQ0KS5cbiAgY29uc3QgcG9zdFJlc3VsdEd1YXJkID0gYXdhaXQgd2l0aFRpbWVvdXQoXG4gICAgZGVwcy5wb3N0VW5pdFBvc3RWZXJpZmljYXRpb24ocG9zdFVuaXRDdHgpLFxuICAgIEZJTkFMSVpFX1BPU1RfVElNRU9VVF9NUyxcbiAgICBcInBvc3RVbml0UG9zdFZlcmlmaWNhdGlvblwiLFxuICApO1xuXG4gIGlmIChwb3N0UmVzdWx0R3VhcmQudGltZWRPdXQpIHtcbiAgICByZXR1cm4gZmFpbENsb3NlZE9uRmluYWxpemVUaW1lb3V0KFxuICAgICAgaWMsXG4gICAgICBpdGVyRGF0YSxcbiAgICAgIGxvb3BTdGF0ZSxcbiAgICAgIFwicG9zdFwiLFxuICAgICAgcHJlVW5pdFNuYXBzaG90Py5zdGFydGVkQXQgPz8gRGF0ZS5ub3coKSxcbiAgICApO1xuICB9XG5cbiAgY29uc3QgcG9zdFJlc3VsdCA9IHBvc3RSZXN1bHRHdWFyZC52YWx1ZTtcblxuICBpZiAocG9zdFJlc3VsdCA9PT0gXCJzdG9wcGVkXCIpIHtcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHtcbiAgICAgIHBoYXNlOiBcImV4aXRcIixcbiAgICAgIHJlYXNvbjogXCJwb3N0LXZlcmlmaWNhdGlvbi1zdG9wcGVkXCIsXG4gICAgfSk7XG4gICAgcmV0dXJuIHsgYWN0aW9uOiBcImJyZWFrXCIsIHJlYXNvbjogXCJwb3N0LXZlcmlmaWNhdGlvbi1zdG9wcGVkXCIgfTtcbiAgfVxuXG4gIGlmIChwb3N0UmVzdWx0ID09PSBcInN0ZXAtd2l6YXJkXCIpIHtcbiAgICAvLyBTdGVwIG1vZGUg4oCUIGV4aXQgdGhlIGxvb3AgKGNhbGxlciBoYW5kbGVzIHdpemFyZClcbiAgICBkZWJ1Z0xvZyhcImF1dG9Mb29wXCIsIHsgcGhhc2U6IFwiZXhpdFwiLCByZWFzb246IFwic3RlcC13aXphcmRcIiB9KTtcbiAgICByZXR1cm4geyBhY3Rpb246IFwiYnJlYWtcIiwgcmVhc29uOiBcInN0ZXAtd2l6YXJkXCIgfTtcbiAgfVxuXG4gIGlmIChwcmVVbml0U25hcHNob3Q/LnR5cGUgPT09IFwiY29tcGxldGUtbWlsZXN0b25lXCIgJiYgcy5jdXJyZW50TWlsZXN0b25lSWQpIHtcbiAgICBjb25zdCBzdG9wID0gYXdhaXQgX3J1bk1pbGVzdG9uZU1lcmdlT25jZVdpdGhTdGFzaFJlc3RvcmUoaWMsIHMuY3VycmVudE1pbGVzdG9uZUlkKTtcbiAgICBpZiAoc3RvcCkgcmV0dXJuIHN0b3A7XG4gIH1cblxuICAvLyBCb3RoIHByZSBhbmQgcG9zdCB2ZXJpZmljYXRpb24gY29tcGxldGVkIHdpdGhvdXQgdGltZW91dCDigJQgcmVzZXQgY291bnRlclxuICBsb29wU3RhdGUuY29uc2VjdXRpdmVGaW5hbGl6ZVRpbWVvdXRzID0gMDtcbiAgaWYgKHByZVVuaXRTbmFwc2hvdCkge1xuICAgIHdyaXRlVW5pdFJ1bnRpbWVSZWNvcmQocy5iYXNlUGF0aCwgcHJlVW5pdFNuYXBzaG90LnR5cGUsIHByZVVuaXRTbmFwc2hvdC5pZCwgcHJlVW5pdFNuYXBzaG90LnN0YXJ0ZWRBdCwge1xuICAgICAgcGhhc2U6IFwiZmluYWxpemVkXCIsXG4gICAgICBsYXN0UHJvZ3Jlc3NBdDogRGF0ZS5ub3coKSxcbiAgICAgIGxhc3RQcm9ncmVzc0tpbmQ6IFwiZmluYWxpemUtc3VjY2Vzc1wiLFxuICAgIH0pO1xuICAgIGlmIChcbiAgICAgICFwcmVVbml0U25hcHNob3QudHlwZS5zdGFydHNXaXRoKFwiaG9vay9cIikgJiZcbiAgICAgIHByZVVuaXRTbmFwc2hvdC50eXBlICE9PSBcImN1c3RvbS1zdGVwXCIgJiZcbiAgICAgIHByZVVuaXRTbmFwc2hvdC50eXBlICE9PSBcImNvbXBsZXRlLW1pbGVzdG9uZVwiXG4gICAgKSB7XG4gICAgICBzZXRBdXRvT3V0Y29tZVdpZGdldChjdHgsIHtcbiAgICAgICAgLi4uYnVpbGRQaGFzZUhhbmRvZmZPdXRjb21lKHtcbiAgICAgICAgICB1bml0VHlwZTogcHJlVW5pdFNuYXBzaG90LnR5cGUsXG4gICAgICAgICAgdW5pdElkOiBwcmVVbml0U25hcHNob3QuaWQsXG4gICAgICAgICAgYWdlbnRFbmRNZXNzYWdlczogcy5sYXN0VW5pdEFnZW50RW5kTWVzc2FnZXMsXG4gICAgICAgIH0pLFxuICAgICAgICBzdGFydGVkQXQ6IHMuYXV0b1N0YXJ0VGltZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICAvLyBTdXJmYWNlIGFjY3VtdWxhdGVkIHdvcmtmbG93LWxvZ2dlciBpc3N1ZXMgZm9yIHRoaXMgdW5pdCB0byB0aGUgdXNlci5cbiAgLy8gV2FybmluZ3MvZXJyb3JzIGxvZ2dlZCBkdXJpbmcgdGhlIHVuaXQgYXJlIGJ1ZmZlcmVkIGluIHRoZSBsb2dnZXIgYW5kXG4gIC8vIGRyYWluZWQgaGVyZSBzbyB0aGUgdXNlciBzZWVzIGEgc2luZ2xlIGNvbnNvbGlkYXRlZCBwb3N0LXVuaXQgYWxlcnQuXG4gIGlmIChoYXNBbnlJc3N1ZXMoKSkge1xuICAgIGNvbnN0IHsgbG9ncyB9ID0gZHJhaW5BbmRTdW1tYXJpemUoKTtcbiAgICBpZiAobG9ncy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBzZXZlcml0eSA9IGxvZ3Muc29tZSgoZSkgPT4gZS5zZXZlcml0eSA9PT0gXCJlcnJvclwiKSA/IFwiZXJyb3JcIiA6IFwid2FybmluZ1wiO1xuICAgICAgY3R4LnVpLm5vdGlmeShmb3JtYXRGb3JOb3RpZmljYXRpb24obG9ncyksIHNldmVyaXR5KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4geyBhY3Rpb246IFwibmV4dFwiLCBkYXRhOiB1bmRlZmluZWQgYXMgdm9pZCB9O1xufVxuIn1d -->
- [ ] <!-- {"checkboxId": "3cf7720d-6018-47fe-804e-ec1c51a05790"} --> 📌 Commit the changes to this branch



<!-- This is an auto-generated reply by CodeRabbit -->
3. [review_comment] coderabbitai[bot]
   file=src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts line=24
   sourceId=3251769098 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#discussion_r3251769098
   replyKind=review_thread threadId=PRRT_kwDORj5hb86Cgyj6 threadResolved=false
   auditToken=codefactory-feedback:gh-review-comment-3251769098
   _🛠️ Refactor suggestion_ | _🟠 Major_ | _⚡ Quick win_

**Add tests for `skill` alone and read-only `gsd_exec` alone.**

The current test verifies that `skill` + read-only `gsd_exec` together are classified as reconnaissance-only, but doesn't isolate whether each works independently. Per the PR objectives, both "skill" (added to READ_ONLY_TOOL_NAMES) and read-only gsd_exec patterns should be detected on their own.

Consider adding:
1. A test with only `{ name: "skill", ... }` → expects `isReadOnlyReconnaissanceOnly = true`
2. A test with only `{ name: "gsd_exec", input: { command: "rg -n TODO src" }, ... }` → expects `isReadOnlyReconnaissanceOnly = true`

This ensures the implementation correctly classifies each independently and would catch bugs where both are incorrectly required together.




<details>
<summary>✅ Proposed additional test cases</summary>

```typescript
test("classifyTraceProgress treats skill alone as reconnaissance-only", () => {
  const trace = traceWithToolCalls([
    { name: "skill", input: { name: "diagnose" }, isError: false },
  ]);
  const result = classifyTraceProgress(trace);
  assert.equal(result.isReadOnlyReconnaissanceOnly, true);
});

test("classifyTraceProgress treats read-only gsd_exec alone as reconnaissance-only", () => {
  const trace = traceWithToolCalls([
    { name: "gsd_exec", input: { command: "rg -n TODO src" }, isError: false },
  ]);
  const result = classifyTraceProgress(trace);
  assert.equal(result.isReadOnlyReconnaissanceOnly, true);
});
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`
around lines 17 - 24, Add two unit tests to
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts
that call classifyTraceProgress with traces created by traceWithToolCalls
containing only the "skill" tool and only the read-only "gsd_exec" command
respectively; for each test assert that result.isReadOnlyReconnaissanceOnly ===
true so we verify that classifyTraceProgress detects "skill" alone and read-only
"gsd_exec" alone as reconnaissance-only rather than requiring both together.
```

</details>

<!-- fingerprinting:phantom:poseidon:puma -->

<!-- This is an auto-generated comment by CodeRabbit -->
4. [review] coderabbitai[bot]
   file=n/a line=n/a
   sourceId=4302381229 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#pullrequestreview-4302381229
   replyKind=review threadId=n/a threadResolved=n/a
   auditToken=codefactory-feedback:gh-review-4302381229
   **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts (1)</summary><blockquote>

`26-48`: _⚡ Quick win_

**Consider adding an empty trace edge case test.**

The current tests cover various command patterns, but don't verify behavior when `toolCalls` is empty. An empty trace is a common edge case that should have explicit, tested behavior.




<details>
<summary>📋 Proposed empty trace test</summary>

```typescript
test("classifyTraceProgress treats empty trace as reconnaissance-only", () => {
  const trace = traceWithToolCalls([]);
  const result = classifyTraceProgress(trace);
  // Adjust expected value based on desired semantics:
  // true if "no mutations" implies read-only, false if "no actions" is distinct
  assert.equal(result.isReadOnlyReconnaissanceOnly, true);
});
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`
around lines 26 - 48, Add an edge-case unit test that passes an empty toolCalls
array to traceWithToolCalls and asserts classifyTraceProgress returns a
reconnaissance-only result; specifically add a test like "classifyTraceProgress
treats empty trace as reconnaissance-only" that constructs const trace =
traceWithToolCalls([]), calls const result = classifyTraceProgress(trace), and
asserts result.isReadOnlyReconnaissanceOnly === true so the classifier’s
behavior for empty traces is explicitly verified.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 17-24: Add two unit tests to
src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts
that call classifyTraceProgress with traces created by traceWithToolCalls
containing only the "skill" tool and only the read-only "gsd_exec" command
respectively; for each test assert that result.isReadOnlyReconnaissanceOnly ===
true so we verify that classifyTraceProgress detects "skill" alone and read-only
"gsd_exec" alone as reconnaissance-only rather than requiring both together.

---

Nitpick comments:
In
`@src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`:
- Around line 26-48: Add an edge-case unit test that passes an empty toolCalls
array to traceWithToolCalls and asserts classifyTraceProgress returns a
reconnaissance-only result; specifically add a test like "classifyTraceProgress
treats empty trace as reconnaissance-only" that constructs const trace =
traceWithToolCalls([]), calls const result = classifyTraceProgress(trace), and
asserts result.isReadOnlyReconnaissanceOnly === true so the classifier’s
behavior for empty traces is explicitly verified.
```

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro Plus

**Run ID**: `53ea4df4-a8f1-4861-bc69-6abbcb6e0cd4`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b36c97c54feaf1395a6d27a33d137f68a84ae979 and 3ee901cc2f1ee3f9d0447ee7a76b3f3bdafc1583.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `src/resources/extensions/gsd/auto-post-unit.ts`
* `src/resources/extensions/gsd/session-forensics.ts`
* `src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts`
* `src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts`

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* src/resources/extensions/gsd/session-forensics.ts
* src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
* src/resources/extensions/gsd/auto-post-unit.ts

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Approved status-check tasks:
None

Approved documentation tasks:
None

When done:
1) Run the relevant verification for your changes.
2) Leave any changed files in the worktree for the babysitter app to finalize.
3) For each feedback item you addressed or were blocked on, emit a summary block in the following format:
   FEEDBACK_SUMMARY_START <auditToken>
   <A concise 1-2 sentence summary of what you did or why you were blocked>
   FEEDBACK_SUMMARY_END
   Include one block per audit token. These summaries will be posted as follow-up comments on the PR.
4) If documentation tasks were assigned, emit exactly one docs summary block in the following format:
   DOCS_SUMMARY_START <changed|no_change>
   <A concise 1-2 sentence summary of the docs you updated, or why no docs changes were necessary after inspection>
   DOCS_SUMMARY_END

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Addressed in commit 37c92c7 by the latest babysitter run.

Responding to comment by @coderabbitai[bot]:
Actionable comments posted: 1

Added an explicit empty-trace edge-case test and aligned it to current classifier semantics (toolCalls.length === 0 is not reconnaissance-only), ensuring behavior is now documented and guarded by test.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Tip

For best results, initiate chat on the files or code changes.

@jeremymcs: Good call on the toolCalls.length === 0 semantics — treating an empty trace as not reconnaissance-only is the safer default (no evidence of read-only activity ≠ confirmed read-only activity), and pinning that invariant in a test prevents silent regressions if the classifier logic shifts later. Thanks for closing the loop!

🐇 ✨

📝 CodeRabbit Chat: Implement requested code changes
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/resources/extensions/gsd/commands-prefs-wizard.ts (1)

590-593: ⚡ Quick win

Comment inconsistency: internal field name.

The inline comment mentions this.models but the test fixture in prefs-wizard-coverage.test.ts (line 185) shows the real implementation uses this._all. Update the comment for accuracy.

📝 Suggested fix
-  // Call getAllWithDiscovered as a method so `this` stays bound to the
-  // registry — invoking a detached reference loses `this` and the method's
-  // internal `this.models` access throws.
+  // Call getAllWithDiscovered as a method so `this` stays bound to the
+  // registry — invoking a detached reference loses `this` and the method's
+  // internal `this._all` access throws.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/resources/extensions/gsd/commands-prefs-wizard.ts` around lines 590 -
593, Comment mentions internal field `this.models` but real implementation uses
`this._all`; update the inline comment near the registry declaration and any
related explanation to reference `this._all` (and `getAllWithDiscovered` /
`registry`) so the note accurately describes why the method must be called with
the registry bound (i.e., to preserve access to this._all).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/resources/extensions/gsd/commands-prefs-wizard.ts`:
- Around line 590-593: Comment mentions internal field `this.models` but real
implementation uses `this._all`; update the inline comment near the registry
declaration and any related explanation to reference `this._all` (and
`getAllWithDiscovered` / `registry`) so the note accurately describes why the
method must be called with the registry bound (i.e., to preserve access to
this._all).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1ce65604-24c1-4546-9560-34bd84b339d2

📥 Commits

Reviewing files that changed from the base of the PR and between 37c92c7 and 9aa8fec.

📒 Files selected for processing (2)
  • src/resources/extensions/gsd/commands-prefs-wizard.ts
  • src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

jeremymcs commented May 16, 2026

Accepted — this comment requires code changes. Queuing fix...
🧰 Agent runningcodex is working on the fix...
Agent completed — verifying changes...
🎉 Resolved — addressed in commit 3dfb7a4.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

🤖 Dispatched codex with the following prompt:

Agent prompt (click to expand)
You are acting as an autonomous PR babysitter for gsd-build/gsd-2 PR #6187.
PR URL: https://github.com/gsd-build/gsd-2/pull/6187
Base repository: gsd-build/gsd-2
Head repository: gsd-build/gsd-2
Head branch: issue/5733-auto-mode-artifact-verification-failures-1778892830
Head remote: origin
You are running inside an isolated app-owned worktree under ~/.patchdeck.
Make only targeted changes that resolve the approved tasks.
Do not wait for user input, confirmation, or approval at any point.
Do not rewrite unrelated files.
Use the available git tooling for inspection and verification only.
If dependencies are missing, install them using the repository's lockfile/package manager as needed inside this isolated worktree.
Leave file edits uncommitted; the babysitter app will handle Git finalization after your run.
GitHub follow-up replies and review-thread resolution will be handled by the babysitter after your run.
If a task is invalid after inspection, explain it in your final response and include the exact audit token.

Approved review-comment tasks:
1. [review] coderabbitai[bot]
   file=n/a line=n/a
   sourceId=4302585229 sourceUrl=https://github.com/gsd-build/gsd-2/pull/6187#pullrequestreview-4302585229
   replyKind=review threadId=n/a threadResolved=n/a
   auditToken=codefactory-feedback:gh-review-4302585229
   

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/resources/extensions/gsd/commands-prefs-wizard.ts (1)</summary><blockquote>

`590-593`: _⚡ Quick win_

**Comment inconsistency: internal field name.**

The inline comment mentions `this.models` but the test fixture in `prefs-wizard-coverage.test.ts` (line 185) shows the real implementation uses `this._all`. Update the comment for accuracy.


<details>
<summary>📝 Suggested fix</summary>

```diff
-  // Call getAllWithDiscovered as a method so `this` stays bound to the
-  // registry — invoking a detached reference loses `this` and the method's
-  // internal `this.models` access throws.
+  // Call getAllWithDiscovered as a method so `this` stays bound to the
+  // registry — invoking a detached reference loses `this` and the method's
+  // internal `this._all` access throws.
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/resources/extensions/gsd/commands-prefs-wizard.ts` around lines 590 -
593, Comment mentions internal field `this.models` but real implementation uses
`this._all`; update the inline comment near the registry declaration and any
related explanation to reference `this._all` (and `getAllWithDiscovered` /
`registry`) so the note accurately describes why the method must be called with
the registry bound (i.e., to preserve access to this._all).
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/resources/extensions/gsd/commands-prefs-wizard.ts`:
- Around line 590-593: Comment mentions internal field `this.models` but real
implementation uses `this._all`; update the inline comment near the registry
declaration and any related explanation to reference `this._all` (and
`getAllWithDiscovered` / `registry`) so the note accurately describes why the
method must be called with the registry bound (i.e., to preserve access to
this._all).
```

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro Plus

**Run ID**: `1ce65604-24c1-4546-9560-34bd84b339d2`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 37c92c78e5d15ad9ee1a901a1228aed16bf2fbf5 and 9aa8fec7524d135f82c82f3a315b6f1954bd369f.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/resources/extensions/gsd/commands-prefs-wizard.ts`
* `src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Approved status-check tasks:
None

Approved documentation tasks:
None

When done:
1) Run the relevant verification for your changes.
2) Leave any changed files in the worktree for the babysitter app to finalize.
3) For each feedback item you addressed or were blocked on, emit a summary block in the following format:
   FEEDBACK_SUMMARY_START <auditToken>
   <A concise 1-2 sentence summary of what you did or why you were blocked>
   FEEDBACK_SUMMARY_END
   Include one block per audit token. These summaries will be posted as follow-up comments on the PR.
4) If documentation tasks were assigned, emit exactly one docs summary block in the following format:
   DOCS_SUMMARY_START <changed|no_change>
   <A concise 1-2 sentence summary of the docs you updated, or why no docs changes were necessary after inspection>
   DOCS_SUMMARY_END

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Addressed in commit 3dfb7a4 by the latest babysitter run.

Responding to comment by @coderabbitai[bot]:

Verified the finding was still valid and made a minimal one-line comment correction in commands-prefs-wizard.ts, updating this.models to this._all to match the real getAllWithDiscovered internals. Validation was attempted, but the repo currently has pre-existing TypeScript syntax errors in prefs-wizard-coverage.test.ts that block test/typecheck execution.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Tip

For best results, initiate chat on the files or code changes.

@jeremymcs: Good — the this.modelsthis._all correction is the right call; that's the actual backing field iterated by getAllWithDiscovered, so the this-binding fix is now consistent end-to-end.

On the pre-existing TypeScript syntax errors in prefs-wizard-coverage.test.ts blocking typecheck/test execution — that's worth tracking separately so it doesn't quietly persist. Would you like me to open a follow-up issue for it?

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

🤖 Dispatched codex with the following prompt:

Agent prompt (click to expand)
You are acting as an autonomous PR babysitter for gsd-build/gsd-2 PR #6187.
PR URL: https://github.com/gsd-build/gsd-2/pull/6187
Base repository: gsd-build/gsd-2
Head repository: gsd-build/gsd-2
Head branch: issue/5733-auto-mode-artifact-verification-failures-1778892830
Base branch: main
Head remote: origin
You are running inside an isolated app-owned worktree under ~/.patchdeck.

A merge from the base branch into the head branch has been started but has conflicts.
The following files have merge conflicts:
  - src/resources/extensions/gsd/commands-prefs-wizard.ts

Your task:
1) Resolve ALL merge conflicts in the listed files.
2) Preserve the intent of both the base branch and head branch changes.
3) When in doubt, prefer the head branch (PR) changes, since that is the author's work.
4) Leave the resolved files in the worktree. The babysitter app will handle Git finalization.
5) Do not stage files, create commits, or push branches.
6) Summarize what you resolved in your final response.

Do not wait for user input, confirmation, or approval at any point.
Do not rewrite unrelated files.
Use the available git tooling for inspection and verification only.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Code-owner check: validated latest actionable feedback on current HEAD; no additional code changes required.

@jeremymcs
Copy link
Copy Markdown
Collaborator Author

Code-owner follow-up on latest review feedback at commit 3dfb7a4f5bd97761c0485ba01c5bfa0b82835d98:

  1. auto-post-unit.ts completion-tool hint gating: accepted, already fixed at HEAD.
  • Verified completionToolHint is now conditional on unitType === "execute-task" and !hasTaskCompletionToolCall(agentEndMessages).
  • Verified by test: missing execute-task artifact skips completion-tool hint when completion tool call is present.
  1. session-forensics.ts read-only classifier too permissive: accepted, already fixed at HEAD.
  • Verified regex now rejects shell control/meta characters in gsd_exec commands.
  • Verified by tests for mutating, shell-chained, and script-eval command forms.
  1. session-forensics-readonly-classification.test.ts add adversarial tests: accepted, already fixed at HEAD.
  • Verified tests exist for cat file && echo x > y and script-eval command patterns; both assert non-reconnaissance.
  1. session-forensics-readonly-classification.test.ts add skill-alone and read-only-exec-alone tests: accepted, already fixed at HEAD.
  • Verified both tests exist and pass.
  1. session-forensics-readonly-classification.test.ts empty trace should be reconnaissance-only: rejected.
  • Current implementation explicitly treats empty traces as not reconnaissance-only (toolCalls.length > 0 guard), and test coverage now locks this behavior intentionally.
  1. commands-prefs-wizard.ts comment should reference this._all: accepted, already fixed at HEAD.
  • Verified inline comment now references this._all.

Verification run:

  • node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts
  • Result: 9 passed, 0 failed.

Note: I could post this comment, but I could not query thread IDs/resolution state via GraphQL in this environment (error connecting to api.github.com), so I could not resolve individual conversations programmatically from here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auto-mode: artifact verification failures pause with low-actionability diagnostics

1 participant