@dyyz1993/pi-coding-agent 0.74.24 → 0.74.27
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/CHANGELOG.md +9 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/session-manager.d.ts +5 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +8 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/extensions/agent-permissions/index.ts +235 -0
- package/dist/extensions/ask-tools/index.ts +115 -0
- package/dist/extensions/auto-memory/contract.d.ts +51 -0
- package/dist/extensions/auto-memory/contract.d.ts.map +1 -0
- package/dist/extensions/auto-memory/contract.js +2 -0
- package/dist/extensions/auto-memory/contract.js.map +1 -0
- package/dist/extensions/auto-memory/contract.ts +56 -0
- package/dist/extensions/auto-memory/index.ts +969 -0
- package/dist/extensions/auto-memory/prompts.ts +202 -0
- package/dist/extensions/auto-memory/skip-rules.ts +297 -0
- package/dist/extensions/auto-memory/utils.ts +208 -0
- package/dist/extensions/auto-session-title/index.ts +83 -0
- package/dist/extensions/bash-ext/contract.d.ts +79 -0
- package/dist/extensions/bash-ext/contract.d.ts.map +1 -0
- package/dist/extensions/bash-ext/contract.js +2 -0
- package/dist/extensions/bash-ext/contract.js.map +1 -0
- package/dist/extensions/bash-ext/contract.ts +69 -0
- package/dist/extensions/bash-ext/index.ts +858 -0
- package/dist/extensions/claude-hooks-compat/config-loader.ts +49 -0
- package/dist/extensions/claude-hooks-compat/handler-runner.ts +377 -0
- package/dist/extensions/claude-hooks-compat/if-parser.ts +53 -0
- package/dist/extensions/claude-hooks-compat/index.ts +178 -0
- package/dist/extensions/claude-hooks-compat/matcher.ts +17 -0
- package/dist/extensions/claude-hooks-compat/stdin-builder.ts +27 -0
- package/dist/extensions/claude-hooks-compat/types.ts +77 -0
- package/dist/extensions/compaction-manager/config.ts +47 -0
- package/dist/extensions/compaction-manager/context-fold.ts +63 -0
- package/dist/extensions/compaction-manager/index.ts +151 -0
- package/dist/extensions/compaction-manager/microcompact.ts +49 -0
- package/dist/extensions/compaction-manager/reactive.ts +9 -0
- package/dist/extensions/compaction-manager/session-memory.ts +48 -0
- package/dist/extensions/coordinator/INTEGRATION.md +376 -0
- package/dist/extensions/coordinator/handler.test.ts +277 -0
- package/dist/extensions/coordinator/handler.ts +189 -0
- package/dist/extensions/coordinator/index.ts +261 -0
- package/dist/extensions/coordinator/types.d.ts +100 -0
- package/dist/extensions/coordinator/types.d.ts.map +1 -0
- package/dist/extensions/coordinator/types.js +2 -0
- package/dist/extensions/coordinator/types.js.map +1 -0
- package/dist/extensions/coordinator/types.ts +72 -0
- package/dist/extensions/file-snapshot/index.ts +131 -0
- package/dist/extensions/file-time-guard/README.md +133 -0
- package/dist/extensions/file-time-guard/config.ts +13 -0
- package/dist/extensions/file-time-guard/index.ts +171 -0
- package/dist/extensions/hooks-engine/index.ts +117 -0
- package/dist/extensions/lsp/lsp/client/file-tracker.ts +70 -0
- package/dist/extensions/lsp/lsp/client/registry.ts +305 -0
- package/dist/extensions/lsp/lsp/client/runtime.ts +832 -0
- package/dist/extensions/lsp/lsp/config/resolver.ts +573 -0
- package/dist/extensions/lsp/lsp/contract.d.ts +101 -0
- package/dist/extensions/lsp/lsp/contract.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/contract.js +2 -0
- package/dist/extensions/lsp/lsp/contract.js.map +1 -0
- package/dist/extensions/lsp/lsp/contract.ts +103 -0
- package/dist/extensions/lsp/lsp/hooks/agent-end.ts +169 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.d.ts +10 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.js +30 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.js.map +1 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.ts +41 -0
- package/dist/extensions/lsp/lsp/hooks/writethrough.ts +342 -0
- package/dist/extensions/lsp/lsp/index.ts +310 -0
- package/dist/extensions/lsp/lsp/lsp.test.ts +684 -0
- package/dist/extensions/lsp/lsp/monitoring/server-metrics.ts +176 -0
- package/dist/extensions/lsp/lsp/tools/lsp-tool.ts +402 -0
- package/dist/extensions/lsp/lsp/utils/dependency-resolver.ts +147 -0
- package/dist/extensions/lsp/lsp/utils/diagnostics-wait.ts +41 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.d.ts +20 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.js +64 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.js.map +1 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.ts +76 -0
- package/dist/extensions/message-bridge/GUIDE.md +210 -0
- package/dist/extensions/message-bridge/index.ts +222 -0
- package/dist/extensions/output-guard/index.ts +446 -0
- package/dist/extensions/preview/index.ts +278 -0
- package/dist/extensions/rules-engine/MATCH_HISTORY_RECONCILIATION.md +111 -0
- package/dist/extensions/rules-engine/RULES-ENGINE-GUIDE.md +470 -0
- package/dist/extensions/rules-engine/cache.js +232 -0
- package/dist/extensions/rules-engine/cache.ts +38 -0
- package/dist/extensions/rules-engine/config.js +63 -0
- package/dist/extensions/rules-engine/config.ts +70 -0
- package/dist/extensions/rules-engine/index.js +1530 -0
- package/dist/extensions/rules-engine/index.ts +552 -0
- package/dist/extensions/rules-engine/injector.js +68 -0
- package/dist/extensions/rules-engine/injector.ts +74 -0
- package/dist/extensions/rules-engine/loader.js +179 -0
- package/dist/extensions/rules-engine/loader.ts +205 -0
- package/dist/extensions/rules-engine/matcher.js +534 -0
- package/dist/extensions/rules-engine/matcher.ts +52 -0
- package/dist/extensions/rules-engine/types.d.ts +156 -0
- package/dist/extensions/rules-engine/types.d.ts.map +1 -0
- package/dist/extensions/rules-engine/types.js +2 -0
- package/dist/extensions/rules-engine/types.js.map +1 -0
- package/dist/extensions/rules-engine/types.ts +169 -0
- package/dist/extensions/session-supervisor/checker.ts +116 -0
- package/dist/extensions/session-supervisor/config.ts +45 -0
- package/dist/extensions/session-supervisor/index.ts +726 -0
- package/dist/extensions/session-supervisor/prompts.ts +132 -0
- package/dist/extensions/session-supervisor/scheduler.ts +69 -0
- package/dist/extensions/session-supervisor/types.ts +215 -0
- package/dist/extensions/subagent/README.md +172 -0
- package/dist/extensions/subagent/agents/explorer.md +25 -0
- package/dist/extensions/subagent/agents/guide.md +27 -0
- package/dist/extensions/subagent/agents/planner.md +37 -0
- package/dist/extensions/subagent/agents/reviewer.md +35 -0
- package/dist/extensions/subagent/agents/scout.md +50 -0
- package/dist/extensions/subagent/agents/verification.md +35 -0
- package/dist/extensions/subagent/agents/worker.md +24 -0
- package/dist/extensions/subagent/agents.ts +25 -0
- package/dist/extensions/subagent/index.ts +987 -0
- package/dist/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/dist/extensions/subagent/prompts/implement.md +10 -0
- package/dist/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/dist/extensions/subagent-ext/contract.d.ts +2 -0
- package/dist/extensions/subagent-ext/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-ext/contract.js +2 -0
- package/dist/extensions/subagent-ext/contract.js.map +1 -0
- package/dist/extensions/subagent-ext/contract.ts +1 -0
- package/dist/extensions/subagent-ext/index.ts +347 -0
- package/dist/extensions/subagent-shared/contract.d.ts +25 -0
- package/dist/extensions/subagent-shared/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-shared/contract.js +2 -0
- package/dist/extensions/subagent-shared/contract.js.map +1 -0
- package/dist/extensions/subagent-shared/contract.ts +28 -0
- package/dist/extensions/subagent-shared/index.ts +4 -0
- package/dist/extensions/subagent-shared/render.ts +166 -0
- package/dist/extensions/subagent-shared/types.ts +35 -0
- package/dist/extensions/subagent-shared/utils.ts +112 -0
- package/dist/extensions/subagent-v2/contract.d.ts +2 -0
- package/dist/extensions/subagent-v2/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-v2/contract.js +2 -0
- package/dist/extensions/subagent-v2/contract.js.map +1 -0
- package/dist/extensions/subagent-v2/contract.ts +1 -0
- package/dist/extensions/subagent-v2/index.ts +599 -0
- package/dist/extensions/todo-ext/contract.d.ts +27 -0
- package/dist/extensions/todo-ext/contract.d.ts.map +1 -0
- package/dist/extensions/todo-ext/contract.js +2 -0
- package/dist/extensions/todo-ext/contract.js.map +1 -0
- package/dist/extensions/todo-ext/contract.ts +30 -0
- package/dist/extensions/todo-ext/index.ts +419 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,1530 @@
|
|
|
1
|
+
// packages/coding-agent/extensions/rules-engine/index.ts
|
|
2
|
+
import { Type } from "@dyyz1993/pi-ai";
|
|
3
|
+
import { createTypedChannel, defineTool } from "@dyyz1993/pi-coding-agent";
|
|
4
|
+
|
|
5
|
+
// packages/coding-agent/extensions/rules-engine/cache.js
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
import * as path2 from "node:path";
|
|
10
|
+
var DEFAULT_DIRS = {
|
|
11
|
+
managed: ["/etc/claude-code/.claude/rules"],
|
|
12
|
+
user: [path.join(homedir(), ".claude", "rules"), path.join(homedir(), ".config", "opencode", "rules")],
|
|
13
|
+
pi: [".pi/rules"],
|
|
14
|
+
project: [".claude/rules", ".opencode/rules", ".trae/rules"]
|
|
15
|
+
};
|
|
16
|
+
function resolveDirs(projectDir, config) {
|
|
17
|
+
const sources = config.dirs || DEFAULT_DIRS;
|
|
18
|
+
const result = [];
|
|
19
|
+
for (const [scope, paths] of Object.entries(sources)) {
|
|
20
|
+
for (const p of paths) {
|
|
21
|
+
result.push({
|
|
22
|
+
scope,
|
|
23
|
+
dir: p.startsWith("/") || p.startsWith("~") ? p.replace(/^~/, homedir()) : path.resolve(projectDir, p),
|
|
24
|
+
source: p
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function splitComma(val) {
|
|
31
|
+
const result = [];
|
|
32
|
+
let depth = 0;
|
|
33
|
+
let current = "";
|
|
34
|
+
for (const ch of val) {
|
|
35
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
36
|
+
else if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
37
|
+
if (ch === "," && depth === 0) {
|
|
38
|
+
const trimmed2 = current.trim().replace(/^["']|["']$/g, "");
|
|
39
|
+
if (trimmed2) result.push(trimmed2);
|
|
40
|
+
current = "";
|
|
41
|
+
} else {
|
|
42
|
+
current += ch;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const trimmed = current.trim().replace(/^["']|["']$/g, "");
|
|
46
|
+
if (trimmed) result.push(trimmed);
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
function parseFrontmatter(content) {
|
|
50
|
+
const frontmatterRegex = /^---\r?\n([\s\S]*?)\n?---\r?\n([\s\S]*)$/;
|
|
51
|
+
const match = content.match(frontmatterRegex);
|
|
52
|
+
if (!match) {
|
|
53
|
+
return { data: {}, body: content };
|
|
54
|
+
}
|
|
55
|
+
const [, frontmatterStr, body] = match;
|
|
56
|
+
const data = {};
|
|
57
|
+
const lines = frontmatterStr.split("\n");
|
|
58
|
+
let i = 0;
|
|
59
|
+
while (i < lines.length) {
|
|
60
|
+
const line = lines[i];
|
|
61
|
+
const colonIndex = line.indexOf(":");
|
|
62
|
+
if (colonIndex === -1) {
|
|
63
|
+
i++;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const rawKey = line.slice(0, colonIndex).trim();
|
|
67
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
68
|
+
if (value === "" || value === "null" || value === "undefined") {
|
|
69
|
+
const listItems = [];
|
|
70
|
+
let j = i + 1;
|
|
71
|
+
while (j < lines.length) {
|
|
72
|
+
const subLine = lines[j];
|
|
73
|
+
if (subLine.match(/^\s*-\s+/)) {
|
|
74
|
+
listItems.push(
|
|
75
|
+
subLine.replace(/^\s*-\s+/, "").trim().replace(/^["']|["']$/g, "")
|
|
76
|
+
);
|
|
77
|
+
j++;
|
|
78
|
+
} else if (subLine.trim() === "" || subLine.match(/^\s+/)) {
|
|
79
|
+
j++;
|
|
80
|
+
} else {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (listItems.length > 0) {
|
|
85
|
+
const camelKey2 = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
86
|
+
data[camelKey2] = listItems;
|
|
87
|
+
i = j;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
value = null;
|
|
91
|
+
} else if (value.startsWith("[") && value.endsWith("]")) {
|
|
92
|
+
try {
|
|
93
|
+
value = JSON.parse(value.replace(/'/g, '"'));
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.debug("[rules-engine] JSON array parse failed:", err instanceof Error ? err.message : err);
|
|
96
|
+
value = value.slice(1, -1).split(",").map((v) => v.trim().replace(/^["']|["']$/g, ""));
|
|
97
|
+
}
|
|
98
|
+
} else if (value.startsWith('"') && value.endsWith('"')) {
|
|
99
|
+
value = value.slice(1, -1);
|
|
100
|
+
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
101
|
+
value = value.slice(1, -1);
|
|
102
|
+
}
|
|
103
|
+
const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
104
|
+
if ((camelKey === "paths" || camelKey === "globs") && typeof value === "string") {
|
|
105
|
+
data[camelKey] = splitComma(value);
|
|
106
|
+
} else {
|
|
107
|
+
data[camelKey] = value;
|
|
108
|
+
}
|
|
109
|
+
i++;
|
|
110
|
+
}
|
|
111
|
+
return { data, body: body.trim() };
|
|
112
|
+
}
|
|
113
|
+
function extractTitle(body) {
|
|
114
|
+
for (const line of body.split("\n")) {
|
|
115
|
+
const trimmed = line.trim();
|
|
116
|
+
if (trimmed) {
|
|
117
|
+
return trimmed.replace(/^#+\s*/, "").replace(/\*\*/g, "");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return "Untitled Rule";
|
|
121
|
+
}
|
|
122
|
+
function parsePaths(raw) {
|
|
123
|
+
if (!raw) return [];
|
|
124
|
+
if (typeof raw === "string") {
|
|
125
|
+
return raw.split(",").map((g) => g.trim()).filter(Boolean);
|
|
126
|
+
}
|
|
127
|
+
if (Array.isArray(raw)) return raw;
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
function parseRuleFile(filePath, content) {
|
|
131
|
+
const { data, body } = parseFrontmatter(content);
|
|
132
|
+
const rawGlobs = data.globs ?? data.paths;
|
|
133
|
+
const globs = parsePaths(rawGlobs);
|
|
134
|
+
const rawPaths = data.paths;
|
|
135
|
+
const paths = parsePaths(rawPaths);
|
|
136
|
+
const isUnconditional = globs.length === 0 || globs.length === 1 && globs[0] === "**";
|
|
137
|
+
const frontmatter = {};
|
|
138
|
+
if (rawGlobs) {
|
|
139
|
+
frontmatter.globs = globs;
|
|
140
|
+
if (rawPaths) {
|
|
141
|
+
frontmatter.paths = paths;
|
|
142
|
+
} else {
|
|
143
|
+
frontmatter.paths = globs;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (data.description && typeof data.description === "string") frontmatter.description = data.description;
|
|
147
|
+
if (data.severity && typeof data.severity === "string")
|
|
148
|
+
frontmatter.severity = data.severity;
|
|
149
|
+
if (data.allowedTools)
|
|
150
|
+
frontmatter.allowedTools = typeof data.allowedTools === "string" ? [data.allowedTools] : data.allowedTools;
|
|
151
|
+
if (data.whenToUse && typeof data.whenToUse === "string") frontmatter.whenToUse = data.whenToUse;
|
|
152
|
+
if (data.notifyOnMatch !== void 0)
|
|
153
|
+
frontmatter.notifyOnMatch = data.notifyOnMatch === "true" || data.notifyOnMatch === true;
|
|
154
|
+
if (data.skipInPrompt !== void 0)
|
|
155
|
+
frontmatter.skipInPrompt = data.skipInPrompt === "true" || data.skipInPrompt === true;
|
|
156
|
+
return {
|
|
157
|
+
name: path2.basename(filePath, path2.extname(filePath)),
|
|
158
|
+
filePath,
|
|
159
|
+
title: extractTitle(body),
|
|
160
|
+
content: body.trim(),
|
|
161
|
+
scope: "project",
|
|
162
|
+
source: "",
|
|
163
|
+
frontmatter,
|
|
164
|
+
isUnconditional
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function scanDir(dir, files = []) {
|
|
168
|
+
if (!fs.existsSync(dir)) return files;
|
|
169
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
const fullPath = path2.join(dir, entry.name);
|
|
172
|
+
if (entry.isDirectory()) {
|
|
173
|
+
scanDir(fullPath, files);
|
|
174
|
+
} else if (entry.isFile() && (entry.name.endsWith(".md") || entry.name.endsWith(".mdc"))) {
|
|
175
|
+
files.push(fullPath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return files;
|
|
179
|
+
}
|
|
180
|
+
function loadRules(rulesDir) {
|
|
181
|
+
const rules = [];
|
|
182
|
+
const unconditional = [];
|
|
183
|
+
const conditional = [];
|
|
184
|
+
if (!fs.existsSync(rulesDir)) {
|
|
185
|
+
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
186
|
+
}
|
|
187
|
+
const files = scanDir(rulesDir);
|
|
188
|
+
for (const filePath of files) {
|
|
189
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
190
|
+
const rule = parseRuleFile(filePath, content);
|
|
191
|
+
rules.push(rule);
|
|
192
|
+
if (rule.isUnconditional) {
|
|
193
|
+
unconditional.push(rule);
|
|
194
|
+
} else {
|
|
195
|
+
conditional.push(rule);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
199
|
+
}
|
|
200
|
+
var cache = null;
|
|
201
|
+
async function getRules(projectDir, config) {
|
|
202
|
+
if (cache && Date.now() - cache.loadedAt < config.cacheTTL) {
|
|
203
|
+
return cache.rules;
|
|
204
|
+
}
|
|
205
|
+
const rules = await loadAllRules(projectDir, config);
|
|
206
|
+
cache = { rules, loadedAt: Date.now() };
|
|
207
|
+
return rules;
|
|
208
|
+
}
|
|
209
|
+
function invalidateCache() {
|
|
210
|
+
cache = null;
|
|
211
|
+
}
|
|
212
|
+
async function loadAllRules(projectDir, config) {
|
|
213
|
+
const sources = resolveDirs(projectDir, config);
|
|
214
|
+
const result = [];
|
|
215
|
+
const seen = /* @__PURE__ */ new Set();
|
|
216
|
+
for (const { scope, dir, source } of sources) {
|
|
217
|
+
const ruleCache = loadRules(dir);
|
|
218
|
+
for (const rule of ruleCache.rules) {
|
|
219
|
+
if (seen.has(rule.filePath)) continue;
|
|
220
|
+
seen.add(rule.filePath);
|
|
221
|
+
rule.scope = scope;
|
|
222
|
+
rule.source = source;
|
|
223
|
+
result.push(rule);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// packages/coding-agent/extensions/rules-engine/config.js
|
|
230
|
+
import * as fs2 from "node:fs";
|
|
231
|
+
import { homedir as homedir2 } from "node:os";
|
|
232
|
+
import * as path3 from "node:path";
|
|
233
|
+
var DEFAULT_CACHE_TTL = 3e4;
|
|
234
|
+
var DEFAULT_DIRS2 = {
|
|
235
|
+
managed: ["/etc/claude-code/.claude/rules"],
|
|
236
|
+
user: [path3.join(homedir2(), ".claude", "rules"), path3.join(homedir2(), ".config", "opencode", "rules")],
|
|
237
|
+
pi: [".pi/rules"],
|
|
238
|
+
project: [".claude/rules", ".opencode/rules", ".trae/rules"]
|
|
239
|
+
};
|
|
240
|
+
function defaultConfig() {
|
|
241
|
+
return {
|
|
242
|
+
cacheTTL: DEFAULT_CACHE_TTL,
|
|
243
|
+
notifyOnLoad: true,
|
|
244
|
+
notifyOnMatch: true
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
async function loadConfig(projectDir) {
|
|
248
|
+
const configFiles = [
|
|
249
|
+
".rules-config.json",
|
|
250
|
+
".pi/rules-config.json",
|
|
251
|
+
".claude/rules-config.json",
|
|
252
|
+
".opencode/rules-config.json"
|
|
253
|
+
];
|
|
254
|
+
for (const name of configFiles) {
|
|
255
|
+
const fp = path3.resolve(projectDir, name);
|
|
256
|
+
if (!fs2.existsSync(fp)) continue;
|
|
257
|
+
try {
|
|
258
|
+
const raw = fs2.readFileSync(fp, "utf-8");
|
|
259
|
+
const parsed = JSON.parse(raw);
|
|
260
|
+
return {
|
|
261
|
+
...defaultConfig(),
|
|
262
|
+
...parsed,
|
|
263
|
+
cacheTTL: parsed.cacheTTL ?? DEFAULT_CACHE_TTL,
|
|
264
|
+
notifyOnLoad: parsed.notifyOnLoad ?? true,
|
|
265
|
+
notifyOnMatch: parsed.notifyOnMatch ?? true
|
|
266
|
+
};
|
|
267
|
+
} catch (err) {
|
|
268
|
+
console.debug("[rules-engine] config parse failed:", err instanceof Error ? err.message : err);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return defaultConfig();
|
|
272
|
+
}
|
|
273
|
+
function resolveDirs2(projectDir, config) {
|
|
274
|
+
const sources = config.dirs || DEFAULT_DIRS2;
|
|
275
|
+
const result = [];
|
|
276
|
+
for (const [scope, paths] of Object.entries(sources)) {
|
|
277
|
+
for (const p of paths) {
|
|
278
|
+
result.push({
|
|
279
|
+
scope,
|
|
280
|
+
dir: p.startsWith("/") || p.startsWith("~") ? p.replace(/^~/, homedir2()) : path3.resolve(projectDir, p),
|
|
281
|
+
source: p
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// packages/coding-agent/extensions/rules-engine/injector.js
|
|
289
|
+
var SEVERITY_ICONS = {
|
|
290
|
+
critical: "\u{1F534}",
|
|
291
|
+
high: "\u{1F7E0}",
|
|
292
|
+
medium: "\u{1F7E1}",
|
|
293
|
+
low: "\u{1F535}",
|
|
294
|
+
hint: "\u{1F4A1}"
|
|
295
|
+
};
|
|
296
|
+
function buildSystemReminderSection(rules, sources) {
|
|
297
|
+
if (rules.length === 0) return "";
|
|
298
|
+
const lines = [
|
|
299
|
+
"<system-reminder>",
|
|
300
|
+
`Instructions from: ${sources.join(", ")}`,
|
|
301
|
+
"The following rules are always active. Follow them strictly.",
|
|
302
|
+
""
|
|
303
|
+
];
|
|
304
|
+
for (const rule of rules) {
|
|
305
|
+
lines.push(`Rule: ${rule.name} \u2014 ${rule.title}`);
|
|
306
|
+
if (rule.frontmatter.description) {
|
|
307
|
+
lines.push(`> ${rule.frontmatter.description}`);
|
|
308
|
+
}
|
|
309
|
+
lines.push("");
|
|
310
|
+
lines.push(rule.content);
|
|
311
|
+
lines.push("");
|
|
312
|
+
}
|
|
313
|
+
lines.push("</system-reminder>");
|
|
314
|
+
return lines.join("\n");
|
|
315
|
+
}
|
|
316
|
+
function buildToolReminderSection(rules, targetPath) {
|
|
317
|
+
if (rules.length === 0) return "";
|
|
318
|
+
const lines = [
|
|
319
|
+
"<system-reminder>",
|
|
320
|
+
`Conditional rules matched for ${targetPath}:`,
|
|
321
|
+
""
|
|
322
|
+
];
|
|
323
|
+
for (const rule of rules) {
|
|
324
|
+
const severity = rule.frontmatter.severity || "medium";
|
|
325
|
+
const icon = SEVERITY_ICONS[severity] || "\u{1F7E1}";
|
|
326
|
+
lines.push(`Rule: ${icon} ${rule.title} [${severity}]`);
|
|
327
|
+
if (rule.frontmatter.description) {
|
|
328
|
+
lines.push(`> ${rule.frontmatter.description}`);
|
|
329
|
+
}
|
|
330
|
+
lines.push("");
|
|
331
|
+
lines.push(rule.content);
|
|
332
|
+
lines.push("");
|
|
333
|
+
}
|
|
334
|
+
lines.push("</system-reminder>");
|
|
335
|
+
return lines.join("\n");
|
|
336
|
+
}
|
|
337
|
+
var buildSystemPromptSection = buildSystemReminderSection;
|
|
338
|
+
var buildToolContextSection = buildToolReminderSection;
|
|
339
|
+
function buildCompactContext(rules) {
|
|
340
|
+
if (rules.length === 0) return "";
|
|
341
|
+
const lines = ["## Active Rules (persist across compaction)", ""];
|
|
342
|
+
for (const rule of rules) {
|
|
343
|
+
const desc = rule.frontmatter.description || rule.content.split("\n")[0];
|
|
344
|
+
lines.push(`- **${rule.title}** (${rule.name}): ${desc}`);
|
|
345
|
+
}
|
|
346
|
+
return lines.join("\n");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// packages/coding-agent/extensions/rules-engine/matcher.js
|
|
350
|
+
var __create = Object.create;
|
|
351
|
+
var __defProp = Object.defineProperty;
|
|
352
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
353
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
354
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
355
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
356
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
357
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
358
|
+
};
|
|
359
|
+
var __copyProps = (to, from, except, desc) => {
|
|
360
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
361
|
+
for (let key of __getOwnPropNames(from))
|
|
362
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
363
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
364
|
+
}
|
|
365
|
+
return to;
|
|
366
|
+
};
|
|
367
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
368
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
369
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
370
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
371
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
372
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
373
|
+
mod
|
|
374
|
+
));
|
|
375
|
+
var require_ignore = __commonJS({
|
|
376
|
+
"node_modules/ignore/index.js"(exports, module) {
|
|
377
|
+
function makeArray(subject) {
|
|
378
|
+
return Array.isArray(subject) ? subject : [subject];
|
|
379
|
+
}
|
|
380
|
+
var UNDEFINED = void 0;
|
|
381
|
+
var EMPTY = "";
|
|
382
|
+
var SPACE = " ";
|
|
383
|
+
var ESCAPE = "\\";
|
|
384
|
+
var REGEX_TEST_BLANK_LINE = /^\s+$/;
|
|
385
|
+
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
386
|
+
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
387
|
+
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
388
|
+
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
389
|
+
var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
|
|
390
|
+
var REGEX_TEST_TRAILING_SLASH = /\/$/;
|
|
391
|
+
var SLASH = "/";
|
|
392
|
+
var TMP_KEY_IGNORE = "node-ignore";
|
|
393
|
+
if (typeof Symbol !== "undefined") {
|
|
394
|
+
TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
|
|
395
|
+
}
|
|
396
|
+
var KEY_IGNORE = TMP_KEY_IGNORE;
|
|
397
|
+
var define = (object, key, value) => {
|
|
398
|
+
Object.defineProperty(object, key, { value });
|
|
399
|
+
return value;
|
|
400
|
+
};
|
|
401
|
+
var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
|
|
402
|
+
var RETURN_FALSE = () => false;
|
|
403
|
+
var sanitizeRange = (range) => range.replace(
|
|
404
|
+
REGEX_REGEXP_RANGE,
|
|
405
|
+
(match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY
|
|
406
|
+
);
|
|
407
|
+
var cleanRangeBackSlash = (slashes) => {
|
|
408
|
+
const { length } = slashes;
|
|
409
|
+
return slashes.slice(0, length - length % 2);
|
|
410
|
+
};
|
|
411
|
+
var REPLACERS = [
|
|
412
|
+
[
|
|
413
|
+
// Remove BOM
|
|
414
|
+
// TODO:
|
|
415
|
+
// Other similar zero-width characters?
|
|
416
|
+
/^\uFEFF/,
|
|
417
|
+
() => EMPTY
|
|
418
|
+
],
|
|
419
|
+
// > Trailing spaces are ignored unless they are quoted with backslash ("\")
|
|
420
|
+
[
|
|
421
|
+
// (a\ ) -> (a )
|
|
422
|
+
// (a ) -> (a)
|
|
423
|
+
// (a ) -> (a)
|
|
424
|
+
// (a \ ) -> (a )
|
|
425
|
+
/((?:\\\\)*?)(\\?\s+)$/,
|
|
426
|
+
(_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
|
|
427
|
+
],
|
|
428
|
+
// Replace (\ ) with ' '
|
|
429
|
+
// (\ ) -> ' '
|
|
430
|
+
// (\\ ) -> '\\ '
|
|
431
|
+
// (\\\ ) -> '\\ '
|
|
432
|
+
[
|
|
433
|
+
/(\\+?)\s/g,
|
|
434
|
+
(_, m1) => {
|
|
435
|
+
const { length } = m1;
|
|
436
|
+
return m1.slice(0, length - length % 2) + SPACE;
|
|
437
|
+
}
|
|
438
|
+
],
|
|
439
|
+
// Escape metacharacters
|
|
440
|
+
// which is written down by users but means special for regular expressions.
|
|
441
|
+
// > There are 12 characters with special meanings:
|
|
442
|
+
// > - the backslash \,
|
|
443
|
+
// > - the caret ^,
|
|
444
|
+
// > - the dollar sign $,
|
|
445
|
+
// > - the period or dot .,
|
|
446
|
+
// > - the vertical bar or pipe symbol |,
|
|
447
|
+
// > - the question mark ?,
|
|
448
|
+
// > - the asterisk or star *,
|
|
449
|
+
// > - the plus sign +,
|
|
450
|
+
// > - the opening parenthesis (,
|
|
451
|
+
// > - the closing parenthesis ),
|
|
452
|
+
// > - and the opening square bracket [,
|
|
453
|
+
// > - the opening curly brace {,
|
|
454
|
+
// > These special characters are often called "metacharacters".
|
|
455
|
+
[
|
|
456
|
+
/[\\$.|*+(){^]/g,
|
|
457
|
+
(match) => `\\${match}`
|
|
458
|
+
],
|
|
459
|
+
[
|
|
460
|
+
// > a question mark (?) matches a single character
|
|
461
|
+
/(?!\\)\?/g,
|
|
462
|
+
() => "[^/]"
|
|
463
|
+
],
|
|
464
|
+
// leading slash
|
|
465
|
+
[
|
|
466
|
+
// > A leading slash matches the beginning of the pathname.
|
|
467
|
+
// > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
|
|
468
|
+
// A leading slash matches the beginning of the pathname
|
|
469
|
+
/^\//,
|
|
470
|
+
() => "^"
|
|
471
|
+
],
|
|
472
|
+
// replace special metacharacter slash after the leading slash
|
|
473
|
+
[
|
|
474
|
+
/\//g,
|
|
475
|
+
() => "\\/"
|
|
476
|
+
],
|
|
477
|
+
[
|
|
478
|
+
// > A leading "**" followed by a slash means match in all directories.
|
|
479
|
+
// > For example, "**/foo" matches file or directory "foo" anywhere,
|
|
480
|
+
// > the same as pattern "foo".
|
|
481
|
+
// > "**/foo/bar" matches file or directory "bar" anywhere that is directly
|
|
482
|
+
// > under directory "foo".
|
|
483
|
+
// Notice that the '*'s have been replaced as '\\*'
|
|
484
|
+
/^\^*\\\*\\\*\\\//,
|
|
485
|
+
// '**/foo' <-> 'foo'
|
|
486
|
+
() => "^(?:.*\\/)?"
|
|
487
|
+
],
|
|
488
|
+
// starting
|
|
489
|
+
[
|
|
490
|
+
// there will be no leading '/'
|
|
491
|
+
// (which has been replaced by section "leading slash")
|
|
492
|
+
// If starts with '**', adding a '^' to the regular expression also works
|
|
493
|
+
/^(?=[^^])/,
|
|
494
|
+
function startingReplacer() {
|
|
495
|
+
return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
|
|
496
|
+
}
|
|
497
|
+
],
|
|
498
|
+
// two globstars
|
|
499
|
+
[
|
|
500
|
+
// Use lookahead assertions so that we could match more than one `'/**'`
|
|
501
|
+
/\\\/\\\*\\\*(?=\\\/|$)/g,
|
|
502
|
+
// Zero, one or several directories
|
|
503
|
+
// should not use '*', or it will be replaced by the next replacer
|
|
504
|
+
// Check if it is not the last `'/**'`
|
|
505
|
+
(_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
|
|
506
|
+
],
|
|
507
|
+
// normal intermediate wildcards
|
|
508
|
+
[
|
|
509
|
+
// Never replace escaped '*'
|
|
510
|
+
// ignore rule '\*' will match the path '*'
|
|
511
|
+
// 'abc.*/' -> go
|
|
512
|
+
// 'abc.*' -> skip this rule,
|
|
513
|
+
// coz trailing single wildcard will be handed by [trailing wildcard]
|
|
514
|
+
/(^|[^\\]+)(\\\*)+(?=.+)/g,
|
|
515
|
+
// '*.js' matches '.js'
|
|
516
|
+
// '*.js' doesn't match 'abc'
|
|
517
|
+
(_, p1, p2) => {
|
|
518
|
+
const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
|
|
519
|
+
return p1 + unescaped;
|
|
520
|
+
}
|
|
521
|
+
],
|
|
522
|
+
[
|
|
523
|
+
// unescape, revert step 3 except for back slash
|
|
524
|
+
// For example, if a user escape a '\\*',
|
|
525
|
+
// after step 3, the result will be '\\\\\\*'
|
|
526
|
+
/\\\\\\(?=[$.|*+(){^])/g,
|
|
527
|
+
() => ESCAPE
|
|
528
|
+
],
|
|
529
|
+
[
|
|
530
|
+
// '\\\\' -> '\\'
|
|
531
|
+
/\\\\/g,
|
|
532
|
+
() => ESCAPE
|
|
533
|
+
],
|
|
534
|
+
[
|
|
535
|
+
// > The range notation, e.g. [a-zA-Z],
|
|
536
|
+
// > can be used to match one of the characters in a range.
|
|
537
|
+
// `\` is escaped by step 3
|
|
538
|
+
/(\\)?\[([^\]/]*?)(\\*)($|\])/g,
|
|
539
|
+
(match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` : close === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
|
|
540
|
+
],
|
|
541
|
+
// ending
|
|
542
|
+
[
|
|
543
|
+
// 'js' will not match 'js.'
|
|
544
|
+
// 'ab' will not match 'abc'
|
|
545
|
+
/(?:[^*])$/,
|
|
546
|
+
// WTF!
|
|
547
|
+
// https://git-scm.com/docs/gitignore
|
|
548
|
+
// changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
|
|
549
|
+
// which re-fixes #24, #38
|
|
550
|
+
// > If there is a separator at the end of the pattern then the pattern
|
|
551
|
+
// > will only match directories, otherwise the pattern can match both
|
|
552
|
+
// > files and directories.
|
|
553
|
+
// 'js*' will not match 'a.js'
|
|
554
|
+
// 'js/' will not match 'a.js'
|
|
555
|
+
// 'js' will match 'a.js' and 'a.js/'
|
|
556
|
+
(match) => /\/$/.test(match) ? `${match}$` : `${match}(?=$|\\/$)`
|
|
557
|
+
]
|
|
558
|
+
];
|
|
559
|
+
var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
|
|
560
|
+
var MODE_IGNORE = "regex";
|
|
561
|
+
var MODE_CHECK_IGNORE = "checkRegex";
|
|
562
|
+
var UNDERSCORE = "_";
|
|
563
|
+
var TRAILING_WILD_CARD_REPLACERS = {
|
|
564
|
+
[MODE_IGNORE](_, p1) {
|
|
565
|
+
const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
|
|
566
|
+
return `${prefix}(?=$|\\/$)`;
|
|
567
|
+
},
|
|
568
|
+
[MODE_CHECK_IGNORE](_, p1) {
|
|
569
|
+
const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
|
|
570
|
+
return `${prefix}(?=$|\\/$)`;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
var makeRegexPrefix = (pattern) => REPLACERS.reduce(
|
|
574
|
+
(prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)),
|
|
575
|
+
pattern
|
|
576
|
+
);
|
|
577
|
+
var isString = (subject) => typeof subject === "string";
|
|
578
|
+
var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
|
|
579
|
+
var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
|
|
580
|
+
var IgnoreRule = class {
|
|
581
|
+
constructor(pattern, mark, body, ignoreCase, negative, prefix) {
|
|
582
|
+
this.pattern = pattern;
|
|
583
|
+
this.mark = mark;
|
|
584
|
+
this.negative = negative;
|
|
585
|
+
define(this, "body", body);
|
|
586
|
+
define(this, "ignoreCase", ignoreCase);
|
|
587
|
+
define(this, "regexPrefix", prefix);
|
|
588
|
+
}
|
|
589
|
+
get regex() {
|
|
590
|
+
const key = UNDERSCORE + MODE_IGNORE;
|
|
591
|
+
if (this[key]) {
|
|
592
|
+
return this[key];
|
|
593
|
+
}
|
|
594
|
+
return this._make(MODE_IGNORE, key);
|
|
595
|
+
}
|
|
596
|
+
get checkRegex() {
|
|
597
|
+
const key = UNDERSCORE + MODE_CHECK_IGNORE;
|
|
598
|
+
if (this[key]) {
|
|
599
|
+
return this[key];
|
|
600
|
+
}
|
|
601
|
+
return this._make(MODE_CHECK_IGNORE, key);
|
|
602
|
+
}
|
|
603
|
+
_make(mode, key) {
|
|
604
|
+
const str = this.regexPrefix.replace(
|
|
605
|
+
REGEX_REPLACE_TRAILING_WILDCARD,
|
|
606
|
+
// It does not need to bind pattern
|
|
607
|
+
TRAILING_WILD_CARD_REPLACERS[mode]
|
|
608
|
+
);
|
|
609
|
+
const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
|
|
610
|
+
return define(this, key, regex);
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
var createRule = ({
|
|
614
|
+
pattern,
|
|
615
|
+
mark
|
|
616
|
+
}, ignoreCase) => {
|
|
617
|
+
let negative = false;
|
|
618
|
+
let body = pattern;
|
|
619
|
+
if (body.indexOf("!") === 0) {
|
|
620
|
+
negative = true;
|
|
621
|
+
body = body.substr(1);
|
|
622
|
+
}
|
|
623
|
+
body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
|
|
624
|
+
const regexPrefix = makeRegexPrefix(body);
|
|
625
|
+
return new IgnoreRule(
|
|
626
|
+
pattern,
|
|
627
|
+
mark,
|
|
628
|
+
body,
|
|
629
|
+
ignoreCase,
|
|
630
|
+
negative,
|
|
631
|
+
regexPrefix
|
|
632
|
+
);
|
|
633
|
+
};
|
|
634
|
+
var RuleManager = class {
|
|
635
|
+
constructor(ignoreCase) {
|
|
636
|
+
this._ignoreCase = ignoreCase;
|
|
637
|
+
this._rules = [];
|
|
638
|
+
}
|
|
639
|
+
_add(pattern) {
|
|
640
|
+
if (pattern && pattern[KEY_IGNORE]) {
|
|
641
|
+
this._rules = this._rules.concat(pattern._rules._rules);
|
|
642
|
+
this._added = true;
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (isString(pattern)) {
|
|
646
|
+
pattern = {
|
|
647
|
+
pattern
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
if (checkPattern(pattern.pattern)) {
|
|
651
|
+
const rule = createRule(pattern, this._ignoreCase);
|
|
652
|
+
this._added = true;
|
|
653
|
+
this._rules.push(rule);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
// @param {Array<string> | string | Ignore} pattern
|
|
657
|
+
add(pattern) {
|
|
658
|
+
this._added = false;
|
|
659
|
+
makeArray(
|
|
660
|
+
isString(pattern) ? splitPattern(pattern) : pattern
|
|
661
|
+
).forEach(this._add, this);
|
|
662
|
+
return this._added;
|
|
663
|
+
}
|
|
664
|
+
// Test one single path without recursively checking parent directories
|
|
665
|
+
//
|
|
666
|
+
// - checkUnignored `boolean` whether should check if the path is unignored,
|
|
667
|
+
// setting `checkUnignored` to `false` could reduce additional
|
|
668
|
+
// path matching.
|
|
669
|
+
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
670
|
+
// @returns {TestResult} true if a file is ignored
|
|
671
|
+
test(path5, checkUnignored, mode) {
|
|
672
|
+
let ignored = false;
|
|
673
|
+
let unignored = false;
|
|
674
|
+
let matchedRule;
|
|
675
|
+
this._rules.forEach((rule) => {
|
|
676
|
+
const { negative } = rule;
|
|
677
|
+
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const matched = rule[mode].test(path5);
|
|
681
|
+
if (!matched) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
ignored = !negative;
|
|
685
|
+
unignored = negative;
|
|
686
|
+
matchedRule = negative ? UNDEFINED : rule;
|
|
687
|
+
});
|
|
688
|
+
const ret = {
|
|
689
|
+
ignored,
|
|
690
|
+
unignored
|
|
691
|
+
};
|
|
692
|
+
if (matchedRule) {
|
|
693
|
+
ret.rule = matchedRule;
|
|
694
|
+
}
|
|
695
|
+
return ret;
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
var throwError = (message, Ctor) => {
|
|
699
|
+
throw new Ctor(message);
|
|
700
|
+
};
|
|
701
|
+
var checkPath = (path5, originalPath, doThrow) => {
|
|
702
|
+
if (!isString(path5)) {
|
|
703
|
+
return doThrow(
|
|
704
|
+
`path must be a string, but got \`${originalPath}\``,
|
|
705
|
+
TypeError
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
if (!path5) {
|
|
709
|
+
return doThrow(`path must not be empty`, TypeError);
|
|
710
|
+
}
|
|
711
|
+
if (checkPath.isNotRelative(path5)) {
|
|
712
|
+
const r = "`path.relative()`d";
|
|
713
|
+
return doThrow(
|
|
714
|
+
`path should be a ${r} string, but got "${originalPath}"`,
|
|
715
|
+
RangeError
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
return true;
|
|
719
|
+
};
|
|
720
|
+
var isNotRelative = (path5) => REGEX_TEST_INVALID_PATH.test(path5);
|
|
721
|
+
checkPath.isNotRelative = isNotRelative;
|
|
722
|
+
checkPath.convert = (p) => p;
|
|
723
|
+
var Ignore = class {
|
|
724
|
+
constructor({
|
|
725
|
+
ignorecase = true,
|
|
726
|
+
ignoreCase = ignorecase,
|
|
727
|
+
allowRelativePaths = false
|
|
728
|
+
} = {}) {
|
|
729
|
+
define(this, KEY_IGNORE, true);
|
|
730
|
+
this._rules = new RuleManager(ignoreCase);
|
|
731
|
+
this._strictPathCheck = !allowRelativePaths;
|
|
732
|
+
this._initCache();
|
|
733
|
+
}
|
|
734
|
+
_initCache() {
|
|
735
|
+
this._ignoreCache = /* @__PURE__ */ Object.create(null);
|
|
736
|
+
this._testCache = /* @__PURE__ */ Object.create(null);
|
|
737
|
+
}
|
|
738
|
+
add(pattern) {
|
|
739
|
+
if (this._rules.add(pattern)) {
|
|
740
|
+
this._initCache();
|
|
741
|
+
}
|
|
742
|
+
return this;
|
|
743
|
+
}
|
|
744
|
+
// legacy
|
|
745
|
+
addPattern(pattern) {
|
|
746
|
+
return this.add(pattern);
|
|
747
|
+
}
|
|
748
|
+
// @returns {TestResult}
|
|
749
|
+
_test(originalPath, cache2, checkUnignored, slices) {
|
|
750
|
+
const path5 = originalPath && checkPath.convert(originalPath);
|
|
751
|
+
checkPath(
|
|
752
|
+
path5,
|
|
753
|
+
originalPath,
|
|
754
|
+
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
755
|
+
);
|
|
756
|
+
return this._t(path5, cache2, checkUnignored, slices);
|
|
757
|
+
}
|
|
758
|
+
checkIgnore(path5) {
|
|
759
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path5)) {
|
|
760
|
+
return this.test(path5);
|
|
761
|
+
}
|
|
762
|
+
const slices = path5.split(SLASH).filter(Boolean);
|
|
763
|
+
slices.pop();
|
|
764
|
+
if (slices.length) {
|
|
765
|
+
const parent = this._t(
|
|
766
|
+
slices.join(SLASH) + SLASH,
|
|
767
|
+
this._testCache,
|
|
768
|
+
true,
|
|
769
|
+
slices
|
|
770
|
+
);
|
|
771
|
+
if (parent.ignored) {
|
|
772
|
+
return parent;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return this._rules.test(path5, false, MODE_CHECK_IGNORE);
|
|
776
|
+
}
|
|
777
|
+
_t(path5, cache2, checkUnignored, slices) {
|
|
778
|
+
if (path5 in cache2) {
|
|
779
|
+
return cache2[path5];
|
|
780
|
+
}
|
|
781
|
+
if (!slices) {
|
|
782
|
+
slices = path5.split(SLASH).filter(Boolean);
|
|
783
|
+
}
|
|
784
|
+
slices.pop();
|
|
785
|
+
if (!slices.length) {
|
|
786
|
+
return cache2[path5] = this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
787
|
+
}
|
|
788
|
+
const parent = this._t(
|
|
789
|
+
slices.join(SLASH) + SLASH,
|
|
790
|
+
cache2,
|
|
791
|
+
checkUnignored,
|
|
792
|
+
slices
|
|
793
|
+
);
|
|
794
|
+
return cache2[path5] = parent.ignored ? parent : this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
795
|
+
}
|
|
796
|
+
ignores(path5) {
|
|
797
|
+
return this._test(path5, this._ignoreCache, false).ignored;
|
|
798
|
+
}
|
|
799
|
+
createFilter() {
|
|
800
|
+
return (path5) => !this.ignores(path5);
|
|
801
|
+
}
|
|
802
|
+
filter(paths) {
|
|
803
|
+
return makeArray(paths).filter(this.createFilter());
|
|
804
|
+
}
|
|
805
|
+
// @returns {TestResult}
|
|
806
|
+
test(path5) {
|
|
807
|
+
return this._test(path5, this._testCache, true);
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
var factory = (options) => new Ignore(options);
|
|
811
|
+
var isPathValid = (path5) => checkPath(path5 && checkPath.convert(path5), path5, RETURN_FALSE);
|
|
812
|
+
var setupWindows = () => {
|
|
813
|
+
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
814
|
+
checkPath.convert = makePosix;
|
|
815
|
+
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
816
|
+
checkPath.isNotRelative = (path5) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path5) || isNotRelative(path5);
|
|
817
|
+
};
|
|
818
|
+
if (
|
|
819
|
+
// Detect `process` so that it can run in browsers.
|
|
820
|
+
typeof process !== "undefined" && process.platform === "win32"
|
|
821
|
+
) {
|
|
822
|
+
setupWindows();
|
|
823
|
+
}
|
|
824
|
+
module.exports = factory;
|
|
825
|
+
factory.default = factory;
|
|
826
|
+
module.exports.isPathValid = isPathValid;
|
|
827
|
+
define(module.exports, /* @__PURE__ */ Symbol.for("setupWindows"), setupWindows);
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
831
|
+
function expandBraces(pattern) {
|
|
832
|
+
const braceIndex = pattern.indexOf("{");
|
|
833
|
+
if (braceIndex === -1) return [pattern];
|
|
834
|
+
const closeIndex = pattern.indexOf("}", braceIndex);
|
|
835
|
+
if (closeIndex === -1) return [pattern];
|
|
836
|
+
const prefix = pattern.slice(0, braceIndex);
|
|
837
|
+
const suffix = pattern.slice(closeIndex + 1);
|
|
838
|
+
const options = pattern.slice(braceIndex + 1, closeIndex).split(",");
|
|
839
|
+
const results = [];
|
|
840
|
+
for (const opt of options) {
|
|
841
|
+
results.push(...expandBraces(prefix + opt.trim() + suffix));
|
|
842
|
+
}
|
|
843
|
+
return results;
|
|
844
|
+
}
|
|
845
|
+
function expandPatterns(patterns) {
|
|
846
|
+
const expanded = [];
|
|
847
|
+
for (const p of patterns) {
|
|
848
|
+
expanded.push(...expandBraces(p));
|
|
849
|
+
}
|
|
850
|
+
return expanded;
|
|
851
|
+
}
|
|
852
|
+
function toRelative(filePath) {
|
|
853
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
854
|
+
return normalized.startsWith("/") ? normalized.slice(1) : normalized;
|
|
855
|
+
}
|
|
856
|
+
function matchGlob(pattern, target) {
|
|
857
|
+
if (!pattern || !target) return false;
|
|
858
|
+
const expanded = expandBraces(pattern);
|
|
859
|
+
const ig = (0, import_ignore.default)().add(expanded);
|
|
860
|
+
return ig.ignores(toRelative(target));
|
|
861
|
+
}
|
|
862
|
+
function matchesAnyGlob(globs, filePath) {
|
|
863
|
+
if (!filePath || globs.length === 0) return false;
|
|
864
|
+
const expanded = expandPatterns(globs);
|
|
865
|
+
const ig = (0, import_ignore.default)().add(expanded);
|
|
866
|
+
return ig.ignores(toRelative(filePath));
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// packages/coding-agent/extensions/rules-engine/types.js
|
|
870
|
+
var RULES_CHANNEL_NAME = "rules-engine";
|
|
871
|
+
|
|
872
|
+
// packages/coding-agent/extensions/rules-engine/index.ts
|
|
873
|
+
import { createTypedChannel as createTypedChannel2 } from "@dyyz1993/pi-coding-agent";
|
|
874
|
+
|
|
875
|
+
// packages/coding-agent/extensions/rules-engine/loader.js
|
|
876
|
+
import * as fs3 from "node:fs";
|
|
877
|
+
import * as path4 from "node:path";
|
|
878
|
+
function splitComma2(val) {
|
|
879
|
+
const result = [];
|
|
880
|
+
let depth = 0;
|
|
881
|
+
let current = "";
|
|
882
|
+
for (const ch of val) {
|
|
883
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
884
|
+
else if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
885
|
+
if (ch === "," && depth === 0) {
|
|
886
|
+
const trimmed2 = current.trim().replace(/^["']|["']$/g, "");
|
|
887
|
+
if (trimmed2) result.push(trimmed2);
|
|
888
|
+
current = "";
|
|
889
|
+
} else {
|
|
890
|
+
current += ch;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
const trimmed = current.trim().replace(/^["']|["']$/g, "");
|
|
894
|
+
if (trimmed) result.push(trimmed);
|
|
895
|
+
return result;
|
|
896
|
+
}
|
|
897
|
+
function parseFrontmatter2(content) {
|
|
898
|
+
const frontmatterRegex = /^---\r?\n([\s\S]*?)\n?---\r?\n([\s\S]*)$/;
|
|
899
|
+
const match = content.match(frontmatterRegex);
|
|
900
|
+
if (!match) {
|
|
901
|
+
return { data: {}, body: content };
|
|
902
|
+
}
|
|
903
|
+
const [, frontmatterStr, body] = match;
|
|
904
|
+
const data = {};
|
|
905
|
+
const lines = frontmatterStr.split("\n");
|
|
906
|
+
let i = 0;
|
|
907
|
+
while (i < lines.length) {
|
|
908
|
+
const line = lines[i];
|
|
909
|
+
const colonIndex = line.indexOf(":");
|
|
910
|
+
if (colonIndex === -1) {
|
|
911
|
+
i++;
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
const rawKey = line.slice(0, colonIndex).trim();
|
|
915
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
916
|
+
if (value === "" || value === "null" || value === "undefined") {
|
|
917
|
+
const listItems = [];
|
|
918
|
+
let j = i + 1;
|
|
919
|
+
while (j < lines.length) {
|
|
920
|
+
const subLine = lines[j];
|
|
921
|
+
if (subLine.match(/^\s*-\s+/)) {
|
|
922
|
+
listItems.push(
|
|
923
|
+
subLine.replace(/^\s*-\s+/, "").trim().replace(/^["']|["']$/g, "")
|
|
924
|
+
);
|
|
925
|
+
j++;
|
|
926
|
+
} else if (subLine.trim() === "" || subLine.match(/^\s+/)) {
|
|
927
|
+
j++;
|
|
928
|
+
} else {
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
if (listItems.length > 0) {
|
|
933
|
+
const camelKey2 = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
934
|
+
data[camelKey2] = listItems;
|
|
935
|
+
i = j;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
value = null;
|
|
939
|
+
} else if (value.startsWith("[") && value.endsWith("]")) {
|
|
940
|
+
try {
|
|
941
|
+
value = JSON.parse(value.replace(/'/g, '"'));
|
|
942
|
+
} catch (err) {
|
|
943
|
+
console.debug("[rules-engine] JSON array parse failed:", err instanceof Error ? err.message : err);
|
|
944
|
+
value = value.slice(1, -1).split(",").map((v) => v.trim().replace(/^["']|["']$/g, ""));
|
|
945
|
+
}
|
|
946
|
+
} else if (value.startsWith('"') && value.endsWith('"')) {
|
|
947
|
+
value = value.slice(1, -1);
|
|
948
|
+
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
949
|
+
value = value.slice(1, -1);
|
|
950
|
+
}
|
|
951
|
+
const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
952
|
+
if ((camelKey === "paths" || camelKey === "globs") && typeof value === "string") {
|
|
953
|
+
data[camelKey] = splitComma2(value);
|
|
954
|
+
} else {
|
|
955
|
+
data[camelKey] = value;
|
|
956
|
+
}
|
|
957
|
+
i++;
|
|
958
|
+
}
|
|
959
|
+
return { data, body: body.trim() };
|
|
960
|
+
}
|
|
961
|
+
function extractTitle2(body) {
|
|
962
|
+
for (const line of body.split("\n")) {
|
|
963
|
+
const trimmed = line.trim();
|
|
964
|
+
if (trimmed) {
|
|
965
|
+
return trimmed.replace(/^#+\s*/, "").replace(/\*\*/g, "");
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return "Untitled Rule";
|
|
969
|
+
}
|
|
970
|
+
function parsePaths2(raw) {
|
|
971
|
+
if (!raw) return [];
|
|
972
|
+
if (typeof raw === "string") {
|
|
973
|
+
return raw.split(",").map((g) => g.trim()).filter(Boolean);
|
|
974
|
+
}
|
|
975
|
+
if (Array.isArray(raw)) return raw;
|
|
976
|
+
return [];
|
|
977
|
+
}
|
|
978
|
+
function parseRuleFile2(filePath, content) {
|
|
979
|
+
const { data, body } = parseFrontmatter2(content);
|
|
980
|
+
const rawGlobs = data.globs ?? data.paths;
|
|
981
|
+
const globs = parsePaths2(rawGlobs);
|
|
982
|
+
const rawPaths = data.paths;
|
|
983
|
+
const paths = parsePaths2(rawPaths);
|
|
984
|
+
const isUnconditional = globs.length === 0 || globs.length === 1 && globs[0] === "**";
|
|
985
|
+
const frontmatter = {};
|
|
986
|
+
if (rawGlobs) {
|
|
987
|
+
frontmatter.globs = globs;
|
|
988
|
+
if (rawPaths) {
|
|
989
|
+
frontmatter.paths = paths;
|
|
990
|
+
} else {
|
|
991
|
+
frontmatter.paths = globs;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
if (data.description && typeof data.description === "string") frontmatter.description = data.description;
|
|
995
|
+
if (data.severity && typeof data.severity === "string")
|
|
996
|
+
frontmatter.severity = data.severity;
|
|
997
|
+
if (data.allowedTools)
|
|
998
|
+
frontmatter.allowedTools = typeof data.allowedTools === "string" ? [data.allowedTools] : data.allowedTools;
|
|
999
|
+
if (data.whenToUse && typeof data.whenToUse === "string") frontmatter.whenToUse = data.whenToUse;
|
|
1000
|
+
if (data.notifyOnMatch !== void 0)
|
|
1001
|
+
frontmatter.notifyOnMatch = data.notifyOnMatch === "true" || data.notifyOnMatch === true;
|
|
1002
|
+
if (data.skipInPrompt !== void 0)
|
|
1003
|
+
frontmatter.skipInPrompt = data.skipInPrompt === "true" || data.skipInPrompt === true;
|
|
1004
|
+
return {
|
|
1005
|
+
name: path4.basename(filePath, path4.extname(filePath)),
|
|
1006
|
+
filePath,
|
|
1007
|
+
title: extractTitle2(body),
|
|
1008
|
+
content: body.trim(),
|
|
1009
|
+
scope: "project",
|
|
1010
|
+
source: "",
|
|
1011
|
+
frontmatter,
|
|
1012
|
+
isUnconditional
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
function scanDir2(dir, files = []) {
|
|
1016
|
+
if (!fs3.existsSync(dir)) return files;
|
|
1017
|
+
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
1018
|
+
for (const entry of entries) {
|
|
1019
|
+
const fullPath = path4.join(dir, entry.name);
|
|
1020
|
+
if (entry.isDirectory()) {
|
|
1021
|
+
scanDir2(fullPath, files);
|
|
1022
|
+
} else if (entry.isFile() && (entry.name.endsWith(".md") || entry.name.endsWith(".mdc"))) {
|
|
1023
|
+
files.push(fullPath);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
return files;
|
|
1027
|
+
}
|
|
1028
|
+
function loadRules2(rulesDir) {
|
|
1029
|
+
const rules = [];
|
|
1030
|
+
const unconditional = [];
|
|
1031
|
+
const conditional = [];
|
|
1032
|
+
if (!fs3.existsSync(rulesDir)) {
|
|
1033
|
+
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
1034
|
+
}
|
|
1035
|
+
const files = scanDir2(rulesDir);
|
|
1036
|
+
for (const filePath of files) {
|
|
1037
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
1038
|
+
const rule = parseRuleFile2(filePath, content);
|
|
1039
|
+
rules.push(rule);
|
|
1040
|
+
if (rule.isUnconditional) {
|
|
1041
|
+
unconditional.push(rule);
|
|
1042
|
+
} else {
|
|
1043
|
+
conditional.push(rule);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// packages/coding-agent/extensions/rules-engine/index.ts
|
|
1050
|
+
var READ_TOOLS = /* @__PURE__ */ new Set(["read", "grep", "glob"]);
|
|
1051
|
+
function rulesEnginePlugin(pi) {
|
|
1052
|
+
let config = null;
|
|
1053
|
+
let rules = [];
|
|
1054
|
+
let cachedMatchHash = "";
|
|
1055
|
+
let hasSentSnapshot = false;
|
|
1056
|
+
let _lastCwd = "";
|
|
1057
|
+
let lastMessages = [];
|
|
1058
|
+
let injectedRuleFiles = /* @__PURE__ */ new Map();
|
|
1059
|
+
function rebuildMatchHistory(messages) {
|
|
1060
|
+
const history = [];
|
|
1061
|
+
for (const msg of messages) {
|
|
1062
|
+
if (msg.role !== "toolResult") continue;
|
|
1063
|
+
const details = msg.details;
|
|
1064
|
+
if (!details?.rulesMatched) continue;
|
|
1065
|
+
const rulesMatched = details.rulesMatched;
|
|
1066
|
+
history.push({
|
|
1067
|
+
filePath: details.matchedFilePath || "",
|
|
1068
|
+
ruleNames: rulesMatched.map((r) => r.name),
|
|
1069
|
+
toolName: msg.toolName || "",
|
|
1070
|
+
toolCallId: msg.toolCallId || "",
|
|
1071
|
+
severity: rulesMatched.some((r) => r.severity === "critical" || r.severity === "high") ? "warning" : "info",
|
|
1072
|
+
timestamp: msg.timestamp || 0,
|
|
1073
|
+
matchedRuleDetails: rulesMatched
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
return history;
|
|
1077
|
+
}
|
|
1078
|
+
const rawChannel = pi.registerChannel(RULES_CHANNEL_NAME);
|
|
1079
|
+
const channel = createTypedChannel(rawChannel).server;
|
|
1080
|
+
channel.handle("getSnapshot", (params) => {
|
|
1081
|
+
const unconditional = getUnconditionalRules();
|
|
1082
|
+
const conditional = getConditionalRules();
|
|
1083
|
+
const matchHistory = rebuildMatchHistory(lastMessages);
|
|
1084
|
+
return {
|
|
1085
|
+
type: "snapshot",
|
|
1086
|
+
rules: rules.map(toRuleDetail),
|
|
1087
|
+
injectedRuleNames: unconditional.map((r) => r.name),
|
|
1088
|
+
totalRules: rules.length,
|
|
1089
|
+
unconditionalCount: unconditional.length,
|
|
1090
|
+
conditionalCount: conditional.length,
|
|
1091
|
+
matchHistory,
|
|
1092
|
+
lifecycleLog: [],
|
|
1093
|
+
loadedAt: Date.now(),
|
|
1094
|
+
cacheTTL: config?.cacheTTL || 3e4
|
|
1095
|
+
};
|
|
1096
|
+
});
|
|
1097
|
+
function getUnconditionalRules() {
|
|
1098
|
+
return rules.filter((r) => r.isUnconditional);
|
|
1099
|
+
}
|
|
1100
|
+
function getConditionalRules() {
|
|
1101
|
+
return rules.filter((r) => !r.isUnconditional);
|
|
1102
|
+
}
|
|
1103
|
+
function getMatchingRules(targetPath) {
|
|
1104
|
+
return getConditionalRules().filter((rule) => {
|
|
1105
|
+
const globs = rule.frontmatter.globs ?? rule.frontmatter.paths;
|
|
1106
|
+
if (!globs || globs.length === 0) return false;
|
|
1107
|
+
return matchesAnyGlob(globs, targetPath);
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
async function refreshRules(cwd) {
|
|
1111
|
+
config = await loadConfig(cwd);
|
|
1112
|
+
rules = await getRules(cwd, config);
|
|
1113
|
+
}
|
|
1114
|
+
function toRuleDetail(r) {
|
|
1115
|
+
return {
|
|
1116
|
+
name: r.name,
|
|
1117
|
+
title: r.title,
|
|
1118
|
+
filePath: r.filePath,
|
|
1119
|
+
scope: r.scope,
|
|
1120
|
+
source: r.source,
|
|
1121
|
+
severity: r.frontmatter.severity || "medium",
|
|
1122
|
+
isUnconditional: r.isUnconditional,
|
|
1123
|
+
globs: r.frontmatter.globs ?? r.frontmatter.paths ?? [],
|
|
1124
|
+
description: r.frontmatter.description
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function buildSnapshot(matchHistory, lifecycleLog) {
|
|
1128
|
+
const unconditional = getUnconditionalRules();
|
|
1129
|
+
const conditional = getConditionalRules();
|
|
1130
|
+
return {
|
|
1131
|
+
type: "snapshot",
|
|
1132
|
+
rules: rules.map(toRuleDetail),
|
|
1133
|
+
injectedRuleNames: unconditional.map((r) => r.name),
|
|
1134
|
+
totalRules: rules.length,
|
|
1135
|
+
unconditionalCount: unconditional.length,
|
|
1136
|
+
conditionalCount: conditional.length,
|
|
1137
|
+
matchHistory,
|
|
1138
|
+
lifecycleLog,
|
|
1139
|
+
loadedAt: Date.now(),
|
|
1140
|
+
cacheTTL: config?.cacheTTL || 3e4
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
function extractTargetPath(args) {
|
|
1144
|
+
if ("filePath" in args && typeof args.filePath === "string") return args.filePath;
|
|
1145
|
+
if ("path" in args && typeof args.path === "string") return args.path;
|
|
1146
|
+
if ("pattern" in args && typeof args.pattern === "string") return args.pattern;
|
|
1147
|
+
return void 0;
|
|
1148
|
+
}
|
|
1149
|
+
pi.registerTool(
|
|
1150
|
+
defineTool({
|
|
1151
|
+
name: "rules_list",
|
|
1152
|
+
label: "List Rules",
|
|
1153
|
+
description: "List all discovered rules from all configured directories across all scopes",
|
|
1154
|
+
parameters: Type.Object({}),
|
|
1155
|
+
async execute() {
|
|
1156
|
+
const unconditional = getUnconditionalRules();
|
|
1157
|
+
const conditional = getConditionalRules();
|
|
1158
|
+
const byScope = {};
|
|
1159
|
+
for (const r of rules) {
|
|
1160
|
+
byScope[r.scope] = (byScope[r.scope] || 0) + 1;
|
|
1161
|
+
}
|
|
1162
|
+
let output = `# Loaded Rules (${rules.length})
|
|
1163
|
+
|
|
1164
|
+
`;
|
|
1165
|
+
output += `Scopes: ${Object.entries(byScope).map(([k, v]) => `${k}: ${v}`).join(", ")}
|
|
1166
|
+
|
|
1167
|
+
`;
|
|
1168
|
+
output += `**Unconditional** (${unconditional.length}):
|
|
1169
|
+
`;
|
|
1170
|
+
for (const rule of unconditional) {
|
|
1171
|
+
output += `- ${rule.title} (${rule.source})
|
|
1172
|
+
`;
|
|
1173
|
+
}
|
|
1174
|
+
output += `
|
|
1175
|
+
**Conditional** (${conditional.length}):
|
|
1176
|
+
`;
|
|
1177
|
+
for (const rule of conditional) {
|
|
1178
|
+
output += `- ${rule.title} [${(rule.frontmatter.globs ?? rule.frontmatter.paths)?.join(", ")}] (${rule.source})
|
|
1179
|
+
`;
|
|
1180
|
+
}
|
|
1181
|
+
return { content: [{ type: "text", text: output }], details: void 0 };
|
|
1182
|
+
}
|
|
1183
|
+
})
|
|
1184
|
+
);
|
|
1185
|
+
pi.registerTool(
|
|
1186
|
+
defineTool({
|
|
1187
|
+
name: "rules_match",
|
|
1188
|
+
label: "Match Rules",
|
|
1189
|
+
description: "Find conditional rules that match a given file path by glob pattern",
|
|
1190
|
+
parameters: Type.Object({
|
|
1191
|
+
filePath: Type.String({ description: "File path to match" })
|
|
1192
|
+
}),
|
|
1193
|
+
async execute(_id, params) {
|
|
1194
|
+
const matching = getMatchingRules(params.filePath);
|
|
1195
|
+
const unconditional = getUnconditionalRules();
|
|
1196
|
+
let output = `# Rule Match: ${params.filePath}
|
|
1197
|
+
|
|
1198
|
+
`;
|
|
1199
|
+
output += `**Unconditional** (always active, ${unconditional.length}):
|
|
1200
|
+
`;
|
|
1201
|
+
for (const r of unconditional) {
|
|
1202
|
+
output += `- ${r.title}
|
|
1203
|
+
`;
|
|
1204
|
+
}
|
|
1205
|
+
output += `
|
|
1206
|
+
**Conditional matches** (${matching.length}):
|
|
1207
|
+
`;
|
|
1208
|
+
for (const r of matching) {
|
|
1209
|
+
const sev = r.frontmatter.severity || "medium";
|
|
1210
|
+
output += `- [${sev}] ${r.title} (${(r.frontmatter.globs ?? r.frontmatter.paths)?.join(", ")})
|
|
1211
|
+
`;
|
|
1212
|
+
}
|
|
1213
|
+
return { content: [{ type: "text", text: output }], details: void 0 };
|
|
1214
|
+
}
|
|
1215
|
+
})
|
|
1216
|
+
);
|
|
1217
|
+
pi.registerTool(
|
|
1218
|
+
defineTool({
|
|
1219
|
+
name: "rules_reload",
|
|
1220
|
+
label: "Reload Rules",
|
|
1221
|
+
description: "Force reload all rules from disk (clears cache and re-reads config)",
|
|
1222
|
+
parameters: Type.Object({}),
|
|
1223
|
+
async execute(_id, _params, _signal, _onUpdate, ctx) {
|
|
1224
|
+
invalidateCache();
|
|
1225
|
+
await refreshRules(ctx.cwd);
|
|
1226
|
+
return {
|
|
1227
|
+
content: [
|
|
1228
|
+
{
|
|
1229
|
+
type: "text",
|
|
1230
|
+
text: `Rules reloaded: ${rules.length} total (${getUnconditionalRules().length} unconditional, ${getConditionalRules().length} conditional)`
|
|
1231
|
+
}
|
|
1232
|
+
],
|
|
1233
|
+
details: void 0
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
})
|
|
1237
|
+
);
|
|
1238
|
+
pi.registerTool(
|
|
1239
|
+
defineTool({
|
|
1240
|
+
name: "rules_show",
|
|
1241
|
+
label: "Show Rule",
|
|
1242
|
+
description: "Show the full content of a specific rule by name",
|
|
1243
|
+
parameters: Type.Object({
|
|
1244
|
+
name: Type.String({ description: "Rule name (filename without .md)" })
|
|
1245
|
+
}),
|
|
1246
|
+
async execute(_id, params) {
|
|
1247
|
+
const rule = rules.find((r) => r.name === params.name);
|
|
1248
|
+
if (!rule) {
|
|
1249
|
+
return {
|
|
1250
|
+
content: [{ type: "text", text: `Rule '${params.name}' not found` }],
|
|
1251
|
+
isError: true,
|
|
1252
|
+
details: void 0
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
let output = `# ${rule.title}
|
|
1256
|
+
|
|
1257
|
+
`;
|
|
1258
|
+
output += `- **Name**: ${rule.name}
|
|
1259
|
+
`;
|
|
1260
|
+
output += `- **Scope**: ${rule.scope}
|
|
1261
|
+
`;
|
|
1262
|
+
output += `- **Source**: ${rule.source}
|
|
1263
|
+
`;
|
|
1264
|
+
output += `- **File**: ${rule.filePath}
|
|
1265
|
+
`;
|
|
1266
|
+
if ((rule.frontmatter.globs ?? rule.frontmatter.paths)?.length) {
|
|
1267
|
+
output += `- **Globs**: ${(rule.frontmatter.globs ?? rule.frontmatter.paths)?.join(", ")}
|
|
1268
|
+
`;
|
|
1269
|
+
}
|
|
1270
|
+
if (rule.frontmatter.description) {
|
|
1271
|
+
output += `- **Description**: ${rule.frontmatter.description}
|
|
1272
|
+
`;
|
|
1273
|
+
}
|
|
1274
|
+
output += `
|
|
1275
|
+
${rule.content}`;
|
|
1276
|
+
return { content: [{ type: "text", text: output }], details: void 0 };
|
|
1277
|
+
}
|
|
1278
|
+
})
|
|
1279
|
+
);
|
|
1280
|
+
pi.registerCommand("rules", {
|
|
1281
|
+
description: "Rules management (list, reload, check <path>, active)",
|
|
1282
|
+
handler: async (args, ctx) => {
|
|
1283
|
+
const parts = args.trim().split(/\s+/);
|
|
1284
|
+
const sub = parts[0] || "list";
|
|
1285
|
+
if (sub === "list" || sub === "ls") {
|
|
1286
|
+
ctx.ui.notify(
|
|
1287
|
+
`${rules.length} rules loaded (${getUnconditionalRules().length} unconditional, ${getConditionalRules().length} conditional)`,
|
|
1288
|
+
"info"
|
|
1289
|
+
);
|
|
1290
|
+
} else if (sub === "reload") {
|
|
1291
|
+
invalidateCache();
|
|
1292
|
+
await refreshRules(ctx.cwd);
|
|
1293
|
+
ctx.ui.notify(`Rules reloaded: ${rules.length} total`, "info");
|
|
1294
|
+
} else if (sub === "check" && parts[1]) {
|
|
1295
|
+
const target = parts.slice(1).join(" ");
|
|
1296
|
+
const matching = getMatchingRules(target);
|
|
1297
|
+
ctx.ui.notify(
|
|
1298
|
+
matching.length > 0 ? `${matching.length} rules match ${target}: ${matching.map((r) => r.title).join(", ")}` : `No conditional rules match ${target}`,
|
|
1299
|
+
"info"
|
|
1300
|
+
);
|
|
1301
|
+
} else if (sub === "active") {
|
|
1302
|
+
const active = getUnconditionalRules();
|
|
1303
|
+
ctx.ui.notify(
|
|
1304
|
+
`Active: ${active.length} unconditional (in system prompt), ${getConditionalRules().length} conditional (on file match)`,
|
|
1305
|
+
"info"
|
|
1306
|
+
);
|
|
1307
|
+
} else {
|
|
1308
|
+
ctx.ui.notify("Usage: /rules [list|reload|check <path>|active]", "info");
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
1313
|
+
_lastCwd = ctx.cwd;
|
|
1314
|
+
await refreshRules(ctx.cwd);
|
|
1315
|
+
ctx.ui.setStatus("rules-engine", `Rules: ${rules.length}`);
|
|
1316
|
+
const unconditional = getUnconditionalRules();
|
|
1317
|
+
const conditional = getConditionalRules();
|
|
1318
|
+
if (!hasSentSnapshot) {
|
|
1319
|
+
hasSentSnapshot = true;
|
|
1320
|
+
const scopeGroups = /* @__PURE__ */ new Map();
|
|
1321
|
+
for (const r of rules) {
|
|
1322
|
+
const list = scopeGroups.get(r.scope) || [];
|
|
1323
|
+
list.push(r);
|
|
1324
|
+
scopeGroups.set(r.scope, list);
|
|
1325
|
+
}
|
|
1326
|
+
const scannedDirs = [...scopeGroups.entries()].map(([scope, scopeRules]) => ({
|
|
1327
|
+
dir: scopeRules[0]?.source || scope,
|
|
1328
|
+
fileCount: scopeRules.length,
|
|
1329
|
+
ruleNames: scopeRules.map((r) => r.name)
|
|
1330
|
+
}));
|
|
1331
|
+
channel.emit(
|
|
1332
|
+
"snapshot",
|
|
1333
|
+
buildSnapshot(
|
|
1334
|
+
[],
|
|
1335
|
+
[
|
|
1336
|
+
{
|
|
1337
|
+
event: "loaded",
|
|
1338
|
+
message: `Loaded ${rules.length} rules (${unconditional.length} unconditional, ${conditional.length} conditional)`,
|
|
1339
|
+
ruleCount: rules.length,
|
|
1340
|
+
timestamp: Date.now(),
|
|
1341
|
+
details: {
|
|
1342
|
+
scannedDirs,
|
|
1343
|
+
configSource: config ? ".rules-config.json" : "default",
|
|
1344
|
+
cacheHit: false
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
]
|
|
1348
|
+
)
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
pi.on("before_agent_start", async (event) => {
|
|
1353
|
+
const unconditional = getUnconditionalRules();
|
|
1354
|
+
if (unconditional.length === 0) {
|
|
1355
|
+
channel.emit("injected", {
|
|
1356
|
+
type: "injected",
|
|
1357
|
+
ruleNames: [],
|
|
1358
|
+
systemPromptLength: event.systemPrompt.length
|
|
1359
|
+
});
|
|
1360
|
+
return void 0;
|
|
1361
|
+
}
|
|
1362
|
+
const alreadyInjected = lastMessages.some(
|
|
1363
|
+
(msg) => msg.role === "custom" && msg.customType === "rules-engine"
|
|
1364
|
+
);
|
|
1365
|
+
if (alreadyInjected) {
|
|
1366
|
+
channel.emit("injected", {
|
|
1367
|
+
type: "injected",
|
|
1368
|
+
ruleNames: unconditional.map((r) => r.name),
|
|
1369
|
+
systemPromptLength: event.systemPrompt.length,
|
|
1370
|
+
deduplicated: true
|
|
1371
|
+
});
|
|
1372
|
+
return void 0;
|
|
1373
|
+
}
|
|
1374
|
+
const sources = [...new Set(unconditional.map((r) => r.source))];
|
|
1375
|
+
const reminderContent = buildSystemReminderSection(unconditional, sources);
|
|
1376
|
+
channel.emit("injected", {
|
|
1377
|
+
type: "injected",
|
|
1378
|
+
ruleNames: unconditional.map((r) => r.name),
|
|
1379
|
+
systemPromptLength: event.systemPrompt.length
|
|
1380
|
+
});
|
|
1381
|
+
return {
|
|
1382
|
+
message: {
|
|
1383
|
+
customType: "rules-engine",
|
|
1384
|
+
content: reminderContent,
|
|
1385
|
+
display: false
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
});
|
|
1389
|
+
pi.on("tool_result", async (event) => {
|
|
1390
|
+
if (!READ_TOOLS.has(event.toolName)) return void 0;
|
|
1391
|
+
const targetPath = extractTargetPath(event.input);
|
|
1392
|
+
if (!targetPath) return void 0;
|
|
1393
|
+
const matching = getMatchingRules(targetPath);
|
|
1394
|
+
if (matching.length === 0) return void 0;
|
|
1395
|
+
const matchedRuleDetails = matching.map((r) => {
|
|
1396
|
+
const ruleName = r.name;
|
|
1397
|
+
const injectedFiles = injectedRuleFiles.get(ruleName);
|
|
1398
|
+
const wasAlreadyLoaded = injectedFiles !== void 0 && injectedFiles.has(targetPath);
|
|
1399
|
+
return {
|
|
1400
|
+
name: ruleName,
|
|
1401
|
+
title: r.title,
|
|
1402
|
+
severity: r.frontmatter.severity || "medium",
|
|
1403
|
+
matchedGlob: (r.frontmatter.globs ?? r.frontmatter.paths)?.find((p) => matchesAnyGlob([p], targetPath)) || (r.frontmatter.globs ?? r.frontmatter.paths)?.[0] || "",
|
|
1404
|
+
alreadyLoaded: wasAlreadyLoaded || void 0
|
|
1405
|
+
};
|
|
1406
|
+
});
|
|
1407
|
+
const newRules = matching.filter((r) => {
|
|
1408
|
+
const injectedFiles = injectedRuleFiles.get(r.name);
|
|
1409
|
+
return !injectedFiles || !injectedFiles.has(targetPath);
|
|
1410
|
+
});
|
|
1411
|
+
const allAlreadyLoaded = newRules.length === 0;
|
|
1412
|
+
for (const r of matching) {
|
|
1413
|
+
let injectedFiles = injectedRuleFiles.get(r.name);
|
|
1414
|
+
if (!injectedFiles) {
|
|
1415
|
+
injectedFiles = /* @__PURE__ */ new Set();
|
|
1416
|
+
injectedRuleFiles.set(r.name, injectedFiles);
|
|
1417
|
+
}
|
|
1418
|
+
injectedFiles.add(targetPath);
|
|
1419
|
+
}
|
|
1420
|
+
const hasCritical = matching.some((r) => r.frontmatter.severity === "critical");
|
|
1421
|
+
const hasHigh = matching.some((r) => r.frontmatter.severity === "high");
|
|
1422
|
+
channel.emit("matched", {
|
|
1423
|
+
type: "matched",
|
|
1424
|
+
filePath: targetPath,
|
|
1425
|
+
matchedRules: matchedRuleDetails,
|
|
1426
|
+
toolName: event.toolName,
|
|
1427
|
+
toolCallId: event.toolCallId,
|
|
1428
|
+
severity: hasCritical ? "warning" : hasHigh ? "warning" : "info",
|
|
1429
|
+
timestamp: Date.now(),
|
|
1430
|
+
alreadyLoaded: allAlreadyLoaded || void 0
|
|
1431
|
+
});
|
|
1432
|
+
if (allAlreadyLoaded) {
|
|
1433
|
+
return {
|
|
1434
|
+
details: {
|
|
1435
|
+
...event.details || {},
|
|
1436
|
+
rulesMatched: matchedRuleDetails,
|
|
1437
|
+
matchedFilePath: targetPath
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
const contextSection = buildToolReminderSection(newRules, targetPath);
|
|
1442
|
+
return {
|
|
1443
|
+
content: [...event.content, { type: "text", text: `
|
|
1444
|
+
|
|
1445
|
+
${contextSection}` }],
|
|
1446
|
+
details: {
|
|
1447
|
+
...event.details || {},
|
|
1448
|
+
rulesMatched: matchedRuleDetails,
|
|
1449
|
+
matchedFilePath: targetPath
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
});
|
|
1453
|
+
pi.on("context", async (event) => {
|
|
1454
|
+
lastMessages = event.messages;
|
|
1455
|
+
const matchHistory = rebuildMatchHistory(event.messages);
|
|
1456
|
+
const hash = JSON.stringify(matchHistory.map((r) => `${r.toolCallId}:${r.filePath}`));
|
|
1457
|
+
if (hash !== cachedMatchHash) {
|
|
1458
|
+
cachedMatchHash = hash;
|
|
1459
|
+
const unconditional = getUnconditionalRules();
|
|
1460
|
+
const conditional = getConditionalRules();
|
|
1461
|
+
channel.emit("snapshot", {
|
|
1462
|
+
type: "snapshot",
|
|
1463
|
+
rules: rules.map(toRuleDetail),
|
|
1464
|
+
injectedRuleNames: unconditional.map((r) => r.name),
|
|
1465
|
+
totalRules: rules.length,
|
|
1466
|
+
unconditionalCount: unconditional.length,
|
|
1467
|
+
conditionalCount: conditional.length,
|
|
1468
|
+
matchHistory,
|
|
1469
|
+
lifecycleLog: [],
|
|
1470
|
+
loadedAt: Date.now(),
|
|
1471
|
+
cacheTTL: config?.cacheTTL || 3e4
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
return void 0;
|
|
1475
|
+
});
|
|
1476
|
+
pi.on("session_compact", async (_event, ctx) => {
|
|
1477
|
+
cachedMatchHash = "";
|
|
1478
|
+
lastMessages = [];
|
|
1479
|
+
injectedRuleFiles = /* @__PURE__ */ new Map();
|
|
1480
|
+
ctx.ui.setStatus("rules-engine", `Rules: ${rules.length} (re-injected after compact)`);
|
|
1481
|
+
});
|
|
1482
|
+
pi.on("session_tree", async () => {
|
|
1483
|
+
cachedMatchHash = "";
|
|
1484
|
+
lastMessages = [];
|
|
1485
|
+
injectedRuleFiles = /* @__PURE__ */ new Map();
|
|
1486
|
+
});
|
|
1487
|
+
pi.on("turn_end", async () => {
|
|
1488
|
+
if (lastMessages.length === 0 && rules.length > 0) return;
|
|
1489
|
+
const matchHistory = rebuildMatchHistory(lastMessages);
|
|
1490
|
+
const hash = JSON.stringify(matchHistory.map((r) => `${r.toolCallId}:${r.filePath}`));
|
|
1491
|
+
if (hash !== cachedMatchHash) {
|
|
1492
|
+
cachedMatchHash = hash;
|
|
1493
|
+
channel.emit("snapshot", {
|
|
1494
|
+
type: "snapshot",
|
|
1495
|
+
rules: rules.map(toRuleDetail),
|
|
1496
|
+
injectedRuleNames: getUnconditionalRules().map((r) => r.name),
|
|
1497
|
+
totalRules: rules.length,
|
|
1498
|
+
unconditionalCount: getUnconditionalRules().length,
|
|
1499
|
+
conditionalCount: getConditionalRules().length,
|
|
1500
|
+
matchHistory,
|
|
1501
|
+
lifecycleLog: [],
|
|
1502
|
+
loadedAt: Date.now(),
|
|
1503
|
+
cacheTTL: config?.cacheTTL || 3e4
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
});
|
|
1507
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
1508
|
+
channel.emit("unloaded", { type: "unloaded", reason: "session_shutdown" });
|
|
1509
|
+
ctx.ui.setStatus("rules-engine", void 0);
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
export {
|
|
1513
|
+
buildCompactContext,
|
|
1514
|
+
buildSystemPromptSection,
|
|
1515
|
+
buildSystemReminderSection,
|
|
1516
|
+
buildToolContextSection,
|
|
1517
|
+
buildToolReminderSection,
|
|
1518
|
+
createTypedChannel2 as createTypedChannel,
|
|
1519
|
+
rulesEnginePlugin as default,
|
|
1520
|
+
getRules,
|
|
1521
|
+
invalidateCache,
|
|
1522
|
+
loadConfig,
|
|
1523
|
+
loadRules2 as loadRules,
|
|
1524
|
+
matchGlob,
|
|
1525
|
+
matchesAnyGlob,
|
|
1526
|
+
parseFrontmatter2 as parseFrontmatter,
|
|
1527
|
+
parseRuleFile2 as parseRuleFile,
|
|
1528
|
+
resolveDirs2 as resolveDirs
|
|
1529
|
+
};
|
|
1530
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiaW5kZXgudHMiLCAiY29uZmlnLnRzIiwgImxvYWRlci50cyIsICJjYWNoZS50cyIsICJjb25maWcudHMiLCAiaW5qZWN0b3IudHMiLCAiLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL2lnbm9yZS9pbmRleC5qcyIsICJtYXRjaGVyLnRzIiwgInR5cGVzLnRzIiwgImxvYWRlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IHsgVHlwZSB9IGZyb20gXCJAZHl5ejE5OTMvcGktYWlcIjtcbmltcG9ydCB7IGNyZWF0ZVR5cGVkQ2hhbm5lbCwgZGVmaW5lVG9vbCwgdHlwZSBFeHRlbnNpb25BUEkgfSBmcm9tIFwiQGR5eXoxOTkzL3BpLWNvZGluZy1hZ2VudFwiO1xuaW1wb3J0IHsgZ2V0UnVsZXMsIGludmFsaWRhdGVDYWNoZSB9IGZyb20gXCIuL2NhY2hlLmpzXCI7XG5pbXBvcnQgeyBsb2FkQ29uZmlnIH0gZnJvbSBcIi4vY29uZmlnLmpzXCI7XG5pbXBvcnQgeyBidWlsZFN5c3RlbVJlbWluZGVyU2VjdGlvbiwgYnVpbGRUb29sUmVtaW5kZXJTZWN0aW9uIH0gZnJvbSBcIi4vaW5qZWN0b3IuanNcIjtcbmltcG9ydCB7IG1hdGNoZXNBbnlHbG9iIH0gZnJvbSBcIi4vbWF0Y2hlci5qc1wiO1xuaW1wb3J0IHR5cGUge1xuXHRJbmplY3RlZFBheWxvYWQsXG5cdExpZmVjeWNsZUVudHJ5LFxuXHRNYXRjaGVkUnVsZURldGFpbCxcblx0TWF0Y2hSZWNvcmQsXG5cdFBhcnNlZFJ1bGUsXG5cdFJ1bGVEZXRhaWwsXG5cdFJ1bGVTZXZlcml0eSxcblx0UnVsZXNDaGFubmVsQ29udHJhY3QsXG5cdFJ1bGVzQ2hhbm5lbEV2ZW50LFxuXHRSdWxlc0NvbmZpZyxcblx0U2Nhbm5lZERpcixcblx0U25hcHNob3RQYXlsb2FkLFxufSBmcm9tIFwiLi90eXBlcy5qc1wiO1xuaW1wb3J0IHsgUlVMRVNfQ0hBTk5FTF9OQU1FIH0gZnJvbSBcIi4vdHlwZXMuanNcIjtcblxuZXhwb3J0IHsgY3JlYXRlVHlwZWRDaGFubmVsIH0gZnJvbSBcIkBkeXl6MTk5My9waS1jb2RpbmctYWdlbnRcIjtcbmV4cG9ydCB7IGdldFJ1bGVzLCBpbnZhbGlkYXRlQ2FjaGUgfSBmcm9tIFwiLi9jYWNoZS5qc1wiO1xuZXhwb3J0IHsgbG9hZENvbmZpZywgcmVzb2x2ZURpcnMgfSBmcm9tIFwiLi9jb25maWcuanNcIjtcbmV4cG9ydCB7IGJ1aWxkQ29tcGFjdENvbnRleHQsIGJ1aWxkU3lzdGVtUmVtaW5kZXJTZWN0aW9uLCBidWlsZFRvb2xSZW1pbmRlclNlY3Rpb24sIGJ1aWxkU3lzdGVtUHJvbXB0U2VjdGlvbiwgYnVpbGRUb29sQ29udGV4dFNlY3Rpb24gfSBmcm9tIFwiLi9pbmplY3Rvci5qc1wiO1xuZXhwb3J0IHsgbG9hZFJ1bGVzLCBwYXJzZUZyb250bWF0dGVyLCBwYXJzZVJ1bGVGaWxlIH0gZnJvbSBcIi4vbG9hZGVyLmpzXCI7XG5leHBvcnQgeyBtYXRjaGVzQW55R2xvYiwgbWF0Y2hHbG9iIH0gZnJvbSBcIi4vbWF0Y2hlci5qc1wiO1xuZXhwb3J0IHR5cGUge1xuXHRJbmplY3RlZFBheWxvYWQsXG5cdExpZmVjeWNsZUVudHJ5LFxuXHRNYXRjaGVkUGF5bG9hZCxcblx0TWF0Y2hSZWNvcmQsXG5cdFBhcnNlZFJ1bGUsXG5cdFJlbG9hZGVkUGF5bG9hZCxcblx0UnVsZURldGFpbCxcblx0UnVsZUZyb250bWF0dGVyLFxuXHRSdWxlU2NvcGUsXG5cdFJ1bGVTZXZlcml0eSxcblx0UnVsZXNDaGFubmVsQ29udHJhY3QsXG5cdFJ1bGVzQ2hhbm5lbEV2ZW50LFxuXHRSdWxlc0NvbmZpZyxcblx0U2Nhbm5lZERpcixcblx0U25hcHNob3RQYXlsb2FkLFxuXHRVbmxvYWRlZFBheWxvYWQsXG59IGZyb20gXCIuL3R5cGVzLmpzXCI7XG5cbmNvbnN0IFJFQURfVE9PTFMgPSBuZXcgU2V0KFtcInJlYWRcIiwgXCJncmVwXCIsIFwiZ2xvYlwiXSk7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHJ1bGVzRW5naW5lUGx1Z2luKHBpOiBFeHRlbnNpb25BUEkpIHtcblx0bGV0IGNvbmZpZzogUnVsZXNDb25maWcgfCBudWxsID0gbnVsbDtcblx0bGV0IHJ1bGVzOiBQYXJzZWRSdWxlW10gPSBbXTtcblx0bGV0IGNhY2hlZE1hdGNoSGFzaCA9IFwiXCI7XG5cdGxldCBoYXNTZW50U25hcHNob3QgPSBmYWxzZTtcblx0bGV0IF9sYXN0Q3dkID0gXCJcIjtcblx0bGV0IGxhc3RNZXNzYWdlczogdW5rbm93bltdID0gW107XG5cdC8qKiBUcmFjayB3aGljaCBydWxlK2ZpbGUgY29tYm9zIGhhdmUgYmVlbiBpbmplY3RlZCAocnVsZU5hbWUgLT4gU2V0PGZpbGVQYXRoPikgKi9cblx0bGV0IGluamVjdGVkUnVsZUZpbGVzOiBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj4gPSBuZXcgTWFwKCk7XG5cblx0ZnVuY3Rpb24gcmVidWlsZE1hdGNoSGlzdG9yeShtZXNzYWdlczogdW5rbm93bltdKTogTWF0Y2hSZWNvcmRbXSB7XG5cdFx0Y29uc3QgaGlzdG9yeTogTWF0Y2hSZWNvcmRbXSA9IFtdO1xuXHRcdGZvciAoY29uc3QgbXNnIG9mIG1lc3NhZ2VzKSB7XG5cdFx0XHRpZiAoKG1zZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikucm9sZSAhPT0gXCJ0b29sUmVzdWx0XCIpIGNvbnRpbnVlO1xuXHRcdFx0Y29uc3QgZGV0YWlscyA9IChtc2cgYXMgeyBkZXRhaWxzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfSkuZGV0YWlscztcblx0XHRcdGlmICghZGV0YWlscz8ucnVsZXNNYXRjaGVkKSBjb250aW51ZTtcblx0XHRcdGNvbnN0IHJ1bGVzTWF0Y2hlZCA9IGRldGFpbHMucnVsZXNNYXRjaGVkIGFzIE1hdGNoZWRSdWxlRGV0YWlsW107XG5cdFx0XHRoaXN0b3J5LnB1c2goe1xuXHRcdFx0XHRmaWxlUGF0aDogKGRldGFpbHMubWF0Y2hlZEZpbGVQYXRoIGFzIHN0cmluZykgfHwgXCJcIixcblx0XHRcdFx0cnVsZU5hbWVzOiBydWxlc01hdGNoZWQubWFwKChyKSA9PiByLm5hbWUpLFxuXHRcdFx0XHR0b29sTmFtZTogKG1zZyBhcyB7IHRvb2xOYW1lPzogc3RyaW5nIH0pLnRvb2xOYW1lIHx8IFwiXCIsXG5cdFx0XHRcdHRvb2xDYWxsSWQ6IChtc2cgYXMgeyB0b29sQ2FsbElkPzogc3RyaW5nIH0pLnRvb2xDYWxsSWQgfHwgXCJcIixcblx0XHRcdFx0c2V2ZXJpdHk6IHJ1bGVzTWF0Y2hlZC5zb21lKChyKSA9PiByLnNldmVyaXR5ID09PSBcImNyaXRpY2FsXCIgfHwgci5zZXZlcml0eSA9PT0gXCJoaWdoXCIpID8gXCJ3YXJuaW5nXCIgOiBcImluZm9cIixcblx0XHRcdFx0dGltZXN0YW1wOiAobXNnIGFzIHsgdGltZXN0YW1wPzogbnVtYmVyIH0pLnRpbWVzdGFtcCB8fCAwLFxuXHRcdFx0XHRtYXRjaGVkUnVsZURldGFpbHM6IHJ1bGVzTWF0Y2hlZCxcblx0XHRcdH0pO1xuXHRcdH1cblx0XHRyZXR1cm4gaGlzdG9yeTtcblx0fVxuXG5cdGNvbnN0IHJhd0NoYW5uZWwgPSBwaS5yZWdpc3RlckNoYW5uZWwoUlVMRVNfQ0hBTk5FTF9OQU1FKTtcblx0Y29uc3QgY2hhbm5lbCA9IGNyZWF0ZVR5cGVkQ2hhbm5lbDxSdWxlc0NoYW5uZWxDb250cmFjdD4ocmF3Q2hhbm5lbCkuc2VydmVyO1xuXG5cdGNoYW5uZWwuaGFuZGxlKFwiZ2V0U25hcHNob3RcIiwgKHBhcmFtcykgPT4ge1xuXHRcdGNvbnN0IHVuY29uZGl0aW9uYWwgPSBnZXRVbmNvbmRpdGlvbmFsUnVsZXMoKTtcblx0XHRjb25zdCBjb25kaXRpb25hbCA9IGdldENvbmRpdGlvbmFsUnVsZXMoKTtcblx0XHRjb25zdCBtYXRjaEhpc3RvcnkgPSByZWJ1aWxkTWF0Y2hIaXN0b3J5KGxhc3RNZXNzYWdlcyk7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHR5cGU6IFwic25hcHNob3RcIiBhcyBjb25zdCxcblx0XHRcdHJ1bGVzOiBydWxlcy5tYXAodG9SdWxlRGV0YWlsKSxcblx0XHRcdGluamVjdGVkUnVsZU5hbWVzOiB1bmNvbmRpdGlvbmFsLm1hcCgocikgPT4gci5uYW1lKSxcblx0XHRcdHRvdGFsUnVsZXM6IHJ1bGVzLmxlbmd0aCxcblx0XHRcdHVuY29uZGl0aW9uYWxDb3VudDogdW5jb25kaXRpb25hbC5sZW5ndGgsXG5cdFx0XHRjb25kaXRpb25hbENvdW50OiBjb25kaXRpb25hbC5sZW5ndGgsXG5cdFx0XHRtYXRjaEhpc3RvcnksXG5cdFx0XHRsaWZlY3ljbGVMb2c6IFtdIGFzIExpZmVjeWNsZUVudHJ5W10sXG5cdFx0XHRsb2FkZWRBdDogRGF0ZS5ub3coKSxcblx0XHRcdGNhY2hlVFRMOiBjb25maWc/LmNhY2hlVFRMIHx8IDMwMDAwLFxuXHRcdH07XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIGdldFVuY29uZGl0aW9uYWxSdWxlcygpOiBQYXJzZWRSdWxlW10ge1xuXHRcdHJldHVybiBydWxlcy5maWx0ZXIoKHIpID0+IHIuaXNVbmNvbmRpdGlvbmFsKTtcblx0fVxuXG5cdGZ1bmN0aW9uIGdldENvbmRpdGlvbmFsUnVsZXMoKTogUGFyc2VkUnVsZVtdIHtcblx0XHRyZXR1cm4gcnVsZXMuZmlsdGVyKChyKSA9PiAhci5pc1VuY29uZGl0aW9uYWwpO1xuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TWF0Y2hpbmdSdWxlcyh0YXJnZXRQYXRoOiBzdHJpbmcpOiBQYXJzZWRSdWxlW10ge1xuXHRcdHJldHVybiBnZXRDb25kaXRpb25hbFJ1bGVzKCkuZmlsdGVyKChydWxlKSA9PiB7XG5cdFx0XHRjb25zdCBnbG9icyA9IHJ1bGUuZnJvbnRtYXR0ZXIuZ2xvYnMgPz8gcnVsZS5mcm9udG1hdHRlci5wYXRocztcblx0XHRcdGlmICghZ2xvYnMgfHwgZ2xvYnMubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XG5cdFx0XHRyZXR1cm4gbWF0Y2hlc0FueUdsb2IoZ2xvYnMsIHRhcmdldFBhdGgpO1xuXHRcdH0pO1xuXHR9XG5cblx0YXN5bmMgZnVuY3Rpb24gcmVmcmVzaFJ1bGVzKGN3ZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0Y29uZmlnID0gYXdhaXQgbG9hZENvbmZpZyhjd2QpO1xuXHRcdHJ1bGVzID0gYXdhaXQgZ2V0UnVsZXMoY3dkLCBjb25maWcpO1xuXHR9XG5cblx0ZnVuY3Rpb24gdG9SdWxlRGV0YWlsKHI6IFBhcnNlZFJ1bGUpOiBSdWxlRGV0YWlsIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0bmFtZTogci5uYW1lLFxuXHRcdFx0dGl0bGU6IHIudGl0bGUsXG5cdFx0XHRmaWxlUGF0aDogci5maWxlUGF0aCxcblx0XHRcdHNjb3BlOiByLnNjb3BlLFxuXHRcdFx0c291cmNlOiByLnNvdXJjZSxcblx0XHRcdHNldmVyaXR5OiByLmZyb250bWF0dGVyLnNldmVyaXR5IHx8IChcIm1lZGl1bVwiIGFzIFJ1bGVTZXZlcml0eSksXG5cdFx0XHRpc1VuY29uZGl0aW9uYWw6IHIuaXNVbmNvbmRpdGlvbmFsLFxuXHRcdFx0Z2xvYnM6IHIuZnJvbnRtYXR0ZXIuZ2xvYnMgPz8gci5mcm9udG1hdHRlci5wYXRocyA/PyBbXSxcblx0XHRcdGRlc2NyaXB0aW9uOiByLmZyb250bWF0dGVyLmRlc2NyaXB0aW9uLFxuXHRcdH07XG5cdH1cblxuXHRmdW5jdGlvbiBidWlsZFNuYXBzaG90KG1hdGNoSGlzdG9yeTogTWF0Y2hSZWNvcmRbXSwgbGlmZWN5Y2xlTG9nOiBMaWZlY3ljbGVFbnRyeVtdKTogU25hcHNob3RQYXlsb2FkIHtcblx0XHRjb25zdCB1bmNvbmRpdGlvbmFsID0gZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCk7XG5cdFx0Y29uc3QgY29uZGl0aW9uYWwgPSBnZXRDb25kaXRpb25hbFJ1bGVzKCk7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHR5cGU6IFwic25hcHNob3RcIixcblx0XHRcdHJ1bGVzOiBydWxlcy5tYXAodG9SdWxlRGV0YWlsKSxcblx0XHRcdGluamVjdGVkUnVsZU5hbWVzOiB1bmNvbmRpdGlvbmFsLm1hcCgocikgPT4gci5uYW1lKSxcblx0XHRcdHRvdGFsUnVsZXM6IHJ1bGVzLmxlbmd0aCxcblx0XHRcdHVuY29uZGl0aW9uYWxDb3VudDogdW5jb25kaXRpb25hbC5sZW5ndGgsXG5cdFx0XHRjb25kaXRpb25hbENvdW50OiBjb25kaXRpb25hbC5sZW5ndGgsXG5cdFx0XHRtYXRjaEhpc3RvcnksXG5cdFx0XHRsaWZlY3ljbGVMb2csXG5cdFx0XHRsb2FkZWRBdDogRGF0ZS5ub3coKSxcblx0XHRcdGNhY2hlVFRMOiBjb25maWc/LmNhY2hlVFRMIHx8IDMwMDAwLFxuXHRcdH07XG5cdH1cblxuXHRmdW5jdGlvbiBleHRyYWN0VGFyZ2V0UGF0aChhcmdzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cdFx0aWYgKFwiZmlsZVBhdGhcIiBpbiBhcmdzICYmIHR5cGVvZiBhcmdzLmZpbGVQYXRoID09PSBcInN0cmluZ1wiKSByZXR1cm4gYXJncy5maWxlUGF0aDtcblx0XHRpZiAoXCJwYXRoXCIgaW4gYXJncyAmJiB0eXBlb2YgYXJncy5wYXRoID09PSBcInN0cmluZ1wiKSByZXR1cm4gYXJncy5wYXRoO1xuXHRcdGlmIChcInBhdHRlcm5cIiBpbiBhcmdzICYmIHR5cGVvZiBhcmdzLnBhdHRlcm4gPT09IFwic3RyaW5nXCIpIHJldHVybiBhcmdzLnBhdHRlcm47XG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fVxuXG5cdHBpLnJlZ2lzdGVyVG9vbChcblx0XHRkZWZpbmVUb29sKHtcblx0XHRcdG5hbWU6IFwicnVsZXNfbGlzdFwiLFxuXHRcdFx0bGFiZWw6IFwiTGlzdCBSdWxlc1wiLFxuXHRcdFx0ZGVzY3JpcHRpb246IFwiTGlzdCBhbGwgZGlzY292ZXJlZCBydWxlcyBmcm9tIGFsbCBjb25maWd1cmVkIGRpcmVjdG9yaWVzIGFjcm9zcyBhbGwgc2NvcGVzXCIsXG5cdFx0XHRwYXJhbWV0ZXJzOiBUeXBlLk9iamVjdCh7fSksXG5cdFx0XHRhc3luYyBleGVjdXRlKCkge1xuXHRcdFx0XHRjb25zdCB1bmNvbmRpdGlvbmFsID0gZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCk7XG5cdFx0XHRcdGNvbnN0IGNvbmRpdGlvbmFsID0gZ2V0Q29uZGl0aW9uYWxSdWxlcygpO1xuXG5cdFx0XHRcdGNvbnN0IGJ5U2NvcGU6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcblx0XHRcdFx0Zm9yIChjb25zdCByIG9mIHJ1bGVzKSB7XG5cdFx0XHRcdFx0YnlTY29wZVtyLnNjb3BlXSA9IChieVNjb3BlW3Iuc2NvcGVdIHx8IDApICsgMTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGxldCBvdXRwdXQgPSBgIyBMb2FkZWQgUnVsZXMgKCR7cnVsZXMubGVuZ3RofSlcXG5cXG5gO1xuXHRcdFx0XHRvdXRwdXQgKz0gYFNjb3BlczogJHtPYmplY3QuZW50cmllcyhieVNjb3BlKVxuXHRcdFx0XHRcdC5tYXAoKFtrLCB2XSkgPT4gYCR7a306ICR7dn1gKVxuXHRcdFx0XHRcdC5qb2luKFwiLCBcIil9XFxuXFxuYDtcblxuXHRcdFx0XHRvdXRwdXQgKz0gYCoqVW5jb25kaXRpb25hbCoqICgke3VuY29uZGl0aW9uYWwubGVuZ3RofSk6XFxuYDtcblx0XHRcdFx0Zm9yIChjb25zdCBydWxlIG9mIHVuY29uZGl0aW9uYWwpIHtcblx0XHRcdFx0XHRvdXRwdXQgKz0gYC0gJHtydWxlLnRpdGxlfSAoJHtydWxlLnNvdXJjZX0pXFxuYDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdG91dHB1dCArPSBgXFxuKipDb25kaXRpb25hbCoqICgke2NvbmRpdGlvbmFsLmxlbmd0aH0pOlxcbmA7XG5cdFx0XHRcdGZvciAoY29uc3QgcnVsZSBvZiBjb25kaXRpb25hbCkge1xuXHRcdFx0XHRcdG91dHB1dCArPSBgLSAke3J1bGUudGl0bGV9IFskeyhydWxlLmZyb250bWF0dGVyLmdsb2JzID8/IHJ1bGUuZnJvbnRtYXR0ZXIucGF0aHMpPy5qb2luKFwiLCBcIil9XSAoJHtydWxlLnNvdXJjZX0pXFxuYDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB7IGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBvdXRwdXQgfV0sIGRldGFpbHM6IHVuZGVmaW5lZCB9O1xuXHRcdFx0fSxcblx0XHR9KSxcblx0KTtcblxuXHRwaS5yZWdpc3RlclRvb2woXG5cdFx0ZGVmaW5lVG9vbCh7XG5cdFx0XHRuYW1lOiBcInJ1bGVzX21hdGNoXCIsXG5cdFx0XHRsYWJlbDogXCJNYXRjaCBSdWxlc1wiLFxuXHRcdFx0ZGVzY3JpcHRpb246IFwiRmluZCBjb25kaXRpb25hbCBydWxlcyB0aGF0IG1hdGNoIGEgZ2l2ZW4gZmlsZSBwYXRoIGJ5IGdsb2IgcGF0dGVyblwiLFxuXHRcdFx0cGFyYW1ldGVyczogVHlwZS5PYmplY3Qoe1xuXHRcdFx0XHRmaWxlUGF0aDogVHlwZS5TdHJpbmcoeyBkZXNjcmlwdGlvbjogXCJGaWxlIHBhdGggdG8gbWF0Y2hcIiB9KSxcblx0XHRcdH0pLFxuXHRcdFx0YXN5bmMgZXhlY3V0ZShfaWQsIHBhcmFtcykge1xuXHRcdFx0XHRjb25zdCBtYXRjaGluZyA9IGdldE1hdGNoaW5nUnVsZXMocGFyYW1zLmZpbGVQYXRoKTtcblx0XHRcdFx0Y29uc3QgdW5jb25kaXRpb25hbCA9IGdldFVuY29uZGl0aW9uYWxSdWxlcygpO1xuXG5cdFx0XHRcdGxldCBvdXRwdXQgPSBgIyBSdWxlIE1hdGNoOiAke3BhcmFtcy5maWxlUGF0aH1cXG5cXG5gO1xuXHRcdFx0XHRvdXRwdXQgKz0gYCoqVW5jb25kaXRpb25hbCoqIChhbHdheXMgYWN0aXZlLCAke3VuY29uZGl0aW9uYWwubGVuZ3RofSk6XFxuYDtcblx0XHRcdFx0Zm9yIChjb25zdCByIG9mIHVuY29uZGl0aW9uYWwpIHtcblx0XHRcdFx0XHRvdXRwdXQgKz0gYC0gJHtyLnRpdGxlfVxcbmA7XG5cdFx0XHRcdH1cblx0XHRcdFx0b3V0cHV0ICs9IGBcXG4qKkNvbmRpdGlvbmFsIG1hdGNoZXMqKiAoJHttYXRjaGluZy5sZW5ndGh9KTpcXG5gO1xuXHRcdFx0XHRmb3IgKGNvbnN0IHIgb2YgbWF0Y2hpbmcpIHtcblx0XHRcdFx0XHRjb25zdCBzZXYgPSByLmZyb250bWF0dGVyLnNldmVyaXR5IHx8IFwibWVkaXVtXCI7XG5cdFx0XHRcdFx0b3V0cHV0ICs9IGAtIFske3Nldn1dICR7ci50aXRsZX0gKCR7KHIuZnJvbnRtYXR0ZXIuZ2xvYnMgPz8gci5mcm9udG1hdHRlci5wYXRocyk/LmpvaW4oXCIsIFwiKX0pXFxuYDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB7IGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBvdXRwdXQgfV0sIGRldGFpbHM6IHVuZGVmaW5lZCB9O1xuXHRcdFx0fSxcblx0XHR9KSxcblx0KTtcblxuXHRwaS5yZWdpc3RlclRvb2woXG5cdFx0ZGVmaW5lVG9vbCh7XG5cdFx0XHRuYW1lOiBcInJ1bGVzX3JlbG9hZFwiLFxuXHRcdFx0bGFiZWw6IFwiUmVsb2FkIFJ1bGVzXCIsXG5cdFx0XHRkZXNjcmlwdGlvbjogXCJGb3JjZSByZWxvYWQgYWxsIHJ1bGVzIGZyb20gZGlzayAoY2xlYXJzIGNhY2hlIGFuZCByZS1yZWFkcyBjb25maWcpXCIsXG5cdFx0XHRwYXJhbWV0ZXJzOiBUeXBlLk9iamVjdCh7fSksXG5cdFx0XHRhc3luYyBleGVjdXRlKF9pZCwgX3BhcmFtcywgX3NpZ25hbCwgX29uVXBkYXRlLCBjdHgpIHtcblx0XHRcdFx0aW52YWxpZGF0ZUNhY2hlKCk7XG5cdFx0XHRcdGF3YWl0IHJlZnJlc2hSdWxlcyhjdHguY3dkKTtcblx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRjb250ZW50OiBbXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdHR5cGU6IFwidGV4dFwiLFxuXHRcdFx0XHRcdFx0XHR0ZXh0OiBgUnVsZXMgcmVsb2FkZWQ6ICR7cnVsZXMubGVuZ3RofSB0b3RhbCAoJHtnZXRVbmNvbmRpdGlvbmFsUnVsZXMoKS5sZW5ndGh9IHVuY29uZGl0aW9uYWwsICR7Z2V0Q29uZGl0aW9uYWxSdWxlcygpLmxlbmd0aH0gY29uZGl0aW9uYWwpYCxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XSxcblx0XHRcdFx0XHRkZXRhaWxzOiB1bmRlZmluZWQsXG5cdFx0XHRcdH07XG5cdFx0XHR9LFxuXHRcdH0pLFxuXHQpO1xuXG5cdHBpLnJlZ2lzdGVyVG9vbChcblx0XHRkZWZpbmVUb29sKHtcblx0XHRcdG5hbWU6IFwicnVsZXNfc2hvd1wiLFxuXHRcdFx0bGFiZWw6IFwiU2hvdyBSdWxlXCIsXG5cdFx0XHRkZXNjcmlwdGlvbjogXCJTaG93IHRoZSBmdWxsIGNvbnRlbnQgb2YgYSBzcGVjaWZpYyBydWxlIGJ5IG5hbWVcIixcblx0XHRcdHBhcmFtZXRlcnM6IFR5cGUuT2JqZWN0KHtcblx0XHRcdFx0bmFtZTogVHlwZS5TdHJpbmcoeyBkZXNjcmlwdGlvbjogXCJSdWxlIG5hbWUgKGZpbGVuYW1lIHdpdGhvdXQgLm1kKVwiIH0pLFxuXHRcdFx0fSksXG5cdFx0XHRhc3luYyBleGVjdXRlKF9pZCwgcGFyYW1zKSB7XG5cdFx0XHRcdGNvbnN0IHJ1bGUgPSBydWxlcy5maW5kKChyKSA9PiByLm5hbWUgPT09IHBhcmFtcy5uYW1lKTtcblx0XHRcdFx0aWYgKCFydWxlKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdGNvbnRlbnQ6IFt7IHR5cGU6IFwidGV4dFwiLCB0ZXh0OiBgUnVsZSAnJHtwYXJhbXMubmFtZX0nIG5vdCBmb3VuZGAgfV0sXG5cdFx0XHRcdFx0XHRpc0Vycm9yOiB0cnVlLFxuXHRcdFx0XHRcdFx0ZGV0YWlsczogdW5kZWZpbmVkLFxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRsZXQgb3V0cHV0ID0gYCMgJHtydWxlLnRpdGxlfVxcblxcbmA7XG5cdFx0XHRcdG91dHB1dCArPSBgLSAqKk5hbWUqKjogJHtydWxlLm5hbWV9XFxuYDtcblx0XHRcdFx0b3V0cHV0ICs9IGAtICoqU2NvcGUqKjogJHtydWxlLnNjb3BlfVxcbmA7XG5cdFx0XHRcdG91dHB1dCArPSBgLSAqKlNvdXJjZSoqOiAke3J1bGUuc291cmNlfVxcbmA7XG5cdFx0XHRcdG91dHB1dCArPSBgLSAqKkZpbGUqKjogJHtydWxlLmZpbGVQYXRofVxcbmA7XG5cdFx0XHRcdGlmICgocnVsZS5mcm9udG1hdHRlci5nbG9icyA/PyBydWxlLmZyb250bWF0dGVyLnBhdGhzKT8ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0b3V0cHV0ICs9IGAtICoqR2xvYnMqKjogJHsocnVsZS5mcm9udG1hdHRlci5nbG9icyA/PyBydWxlLmZyb250bWF0dGVyLnBhdGhzKT8uam9pbihcIiwgXCIpfVxcbmA7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHJ1bGUuZnJvbnRtYXR0ZXIuZGVzY3JpcHRpb24pIHtcblx0XHRcdFx0XHRvdXRwdXQgKz0gYC0gKipEZXNjcmlwdGlvbioqOiAke3J1bGUuZnJvbnRtYXR0ZXIuZGVzY3JpcHRpb259XFxuYDtcblx0XHRcdFx0fVxuXHRcdFx0XHRvdXRwdXQgKz0gYFxcbiR7cnVsZS5jb250ZW50fWA7XG5cblx0XHRcdFx0cmV0dXJuIHsgY29udGVudDogW3sgdHlwZTogXCJ0ZXh0XCIsIHRleHQ6IG91dHB1dCB9XSwgZGV0YWlsczogdW5kZWZpbmVkIH07XG5cdFx0XHR9LFxuXHRcdH0pLFxuXHQpO1xuXG5cdHBpLnJlZ2lzdGVyQ29tbWFuZChcInJ1bGVzXCIsIHtcblx0XHRkZXNjcmlwdGlvbjogXCJSdWxlcyBtYW5hZ2VtZW50IChsaXN0LCByZWxvYWQsIGNoZWNrIDxwYXRoPiwgYWN0aXZlKVwiLFxuXHRcdGhhbmRsZXI6IGFzeW5jIChhcmdzLCBjdHgpID0+IHtcblx0XHRcdGNvbnN0IHBhcnRzID0gYXJncy50cmltKCkuc3BsaXQoL1xccysvKTtcblx0XHRcdGNvbnN0IHN1YiA9IHBhcnRzWzBdIHx8IFwibGlzdFwiO1xuXG5cdFx0XHRpZiAoc3ViID09PSBcImxpc3RcIiB8fCBzdWIgPT09IFwibHNcIikge1xuXHRcdFx0XHRjdHgudWkubm90aWZ5KFxuXHRcdFx0XHRcdGAke3J1bGVzLmxlbmd0aH0gcnVsZXMgbG9hZGVkICgke2dldFVuY29uZGl0aW9uYWxSdWxlcygpLmxlbmd0aH0gdW5jb25kaXRpb25hbCwgJHtnZXRDb25kaXRpb25hbFJ1bGVzKCkubGVuZ3RofSBjb25kaXRpb25hbClgLFxuXHRcdFx0XHRcdFwiaW5mb1wiLFxuXHRcdFx0XHQpO1xuXHRcdFx0fSBlbHNlIGlmIChzdWIgPT09IFwicmVsb2FkXCIpIHtcblx0XHRcdFx0aW52YWxpZGF0ZUNhY2hlKCk7XG5cdFx0XHRcdGF3YWl0IHJlZnJlc2hSdWxlcyhjdHguY3dkKTtcblx0XHRcdFx0Y3R4LnVpLm5vdGlmeShgUnVsZXMgcmVsb2FkZWQ6ICR7cnVsZXMubGVuZ3RofSB0b3RhbGAsIFwiaW5mb1wiKTtcblx0XHRcdH0gZWxzZSBpZiAoc3ViID09PSBcImNoZWNrXCIgJiYgcGFydHNbMV0pIHtcblx0XHRcdFx0Y29uc3QgdGFyZ2V0ID0gcGFydHMuc2xpY2UoMSkuam9pbihcIiBcIik7XG5cdFx0XHRcdGNvbnN0IG1hdGNoaW5nID0gZ2V0TWF0Y2hpbmdSdWxlcyh0YXJnZXQpO1xuXHRcdFx0XHRjdHgudWkubm90aWZ5KFxuXHRcdFx0XHRcdG1hdGNoaW5nLmxlbmd0aCA+IDBcblx0XHRcdFx0XHRcdD8gYCR7bWF0Y2hpbmcubGVuZ3RofSBydWxlcyBtYXRjaCAke3RhcmdldH06ICR7bWF0Y2hpbmcubWFwKChyKSA9PiByLnRpdGxlKS5qb2luKFwiLCBcIil9YFxuXHRcdFx0XHRcdFx0OiBgTm8gY29uZGl0aW9uYWwgcnVsZXMgbWF0Y2ggJHt0YXJnZXR9YCxcblx0XHRcdFx0XHRcImluZm9cIixcblx0XHRcdFx0KTtcblx0XHRcdH0gZWxzZSBpZiAoc3ViID09PSBcImFjdGl2ZVwiKSB7XG5cdFx0XHRcdGNvbnN0IGFjdGl2ZSA9IGdldFVuY29uZGl0aW9uYWxSdWxlcygpO1xuXHRcdFx0XHRjdHgudWkubm90aWZ5KFxuXHRcdFx0XHRcdGBBY3RpdmU6ICR7YWN0aXZlLmxlbmd0aH0gdW5jb25kaXRpb25hbCAoaW4gc3lzdGVtIHByb21wdCksICR7Z2V0Q29uZGl0aW9uYWxSdWxlcygpLmxlbmd0aH0gY29uZGl0aW9uYWwgKG9uIGZpbGUgbWF0Y2gpYCxcblx0XHRcdFx0XHRcImluZm9cIixcblx0XHRcdFx0KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGN0eC51aS5ub3RpZnkoXCJVc2FnZTogL3J1bGVzIFtsaXN0fHJlbG9hZHxjaGVjayA8cGF0aD58YWN0aXZlXVwiLCBcImluZm9cIik7XG5cdFx0XHR9XG5cdFx0fSxcblx0fSk7XG5cblx0cGkub24oXCJzZXNzaW9uX3N0YXJ0XCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuXHRcdF9sYXN0Q3dkID0gY3R4LmN3ZDtcblx0XHRhd2FpdCByZWZyZXNoUnVsZXMoY3R4LmN3ZCk7XG5cdFx0Y3R4LnVpLnNldFN0YXR1cyhcInJ1bGVzLWVuZ2luZVwiLCBgUnVsZXM6ICR7cnVsZXMubGVuZ3RofWApO1xuXG5cdFx0Y29uc3QgdW5jb25kaXRpb25hbCA9IGdldFVuY29uZGl0aW9uYWxSdWxlcygpO1xuXHRcdGNvbnN0IGNvbmRpdGlvbmFsID0gZ2V0Q29uZGl0aW9uYWxSdWxlcygpO1xuXG5cdFx0aWYgKCFoYXNTZW50U25hcHNob3QpIHtcblx0XHRcdGhhc1NlbnRTbmFwc2hvdCA9IHRydWU7XG5cblx0XHRcdGNvbnN0IHNjb3BlR3JvdXBzID0gbmV3IE1hcDxzdHJpbmcsIFBhcnNlZFJ1bGVbXT4oKTtcblx0XHRcdGZvciAoY29uc3QgciBvZiBydWxlcykge1xuXHRcdFx0XHRjb25zdCBsaXN0ID0gc2NvcGVHcm91cHMuZ2V0KHIuc2NvcGUpIHx8IFtdO1xuXHRcdFx0XHRsaXN0LnB1c2gocik7XG5cdFx0XHRcdHNjb3BlR3JvdXBzLnNldChyLnNjb3BlLCBsaXN0KTtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc2Nhbm5lZERpcnM6IFNjYW5uZWREaXJbXSA9IFsuLi5zY29wZUdyb3Vwcy5lbnRyaWVzKCldLm1hcCgoW3Njb3BlLCBzY29wZVJ1bGVzXSkgPT4gKHtcblx0XHRcdFx0ZGlyOiBzY29wZVJ1bGVzWzBdPy5zb3VyY2UgfHwgc2NvcGUsXG5cdFx0XHRcdGZpbGVDb3VudDogc2NvcGVSdWxlcy5sZW5ndGgsXG5cdFx0XHRcdHJ1bGVOYW1lczogc2NvcGVSdWxlcy5tYXAoKHIpID0+IHIubmFtZSksXG5cdFx0XHR9KSk7XG5cblx0XHRcdGNoYW5uZWwuZW1pdChcblx0XHRcdFx0XCJzbmFwc2hvdFwiLFxuXHRcdFx0XHRidWlsZFNuYXBzaG90KFxuXHRcdFx0XHRcdFtdLFxuXHRcdFx0XHRcdFtcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0ZXZlbnQ6IFwibG9hZGVkXCIsXG5cdFx0XHRcdFx0XHRcdG1lc3NhZ2U6IGBMb2FkZWQgJHtydWxlcy5sZW5ndGh9IHJ1bGVzICgke3VuY29uZGl0aW9uYWwubGVuZ3RofSB1bmNvbmRpdGlvbmFsLCAke2NvbmRpdGlvbmFsLmxlbmd0aH0gY29uZGl0aW9uYWwpYCxcblx0XHRcdFx0XHRcdFx0cnVsZUNvdW50OiBydWxlcy5sZW5ndGgsXG5cdFx0XHRcdFx0XHRcdHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcblx0XHRcdFx0XHRcdFx0ZGV0YWlsczoge1xuXHRcdFx0XHRcdFx0XHRcdHNjYW5uZWREaXJzLFxuXHRcdFx0XHRcdFx0XHRcdGNvbmZpZ1NvdXJjZTogY29uZmlnID8gXCIucnVsZXMtY29uZmlnLmpzb25cIiA6IFwiZGVmYXVsdFwiLFxuXHRcdFx0XHRcdFx0XHRcdGNhY2hlSGl0OiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XSxcblx0XHRcdFx0KSxcblx0XHRcdCk7XG5cdFx0fVxuXHR9KTtcblxuXHRwaS5vbihcImJlZm9yZV9hZ2VudF9zdGFydFwiLCBhc3luYyAoZXZlbnQpID0+IHtcblx0XHRjb25zdCB1bmNvbmRpdGlvbmFsID0gZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCk7XG5cblx0XHRpZiAodW5jb25kaXRpb25hbC5sZW5ndGggPT09IDApIHtcblx0XHRcdGNoYW5uZWwuZW1pdChcImluamVjdGVkXCIsIHtcblx0XHRcdFx0dHlwZTogXCJpbmplY3RlZFwiLFxuXHRcdFx0XHRydWxlTmFtZXM6IFtdLFxuXHRcdFx0XHRzeXN0ZW1Qcm9tcHRMZW5ndGg6IGV2ZW50LnN5c3RlbVByb21wdC5sZW5ndGgsXG5cdFx0XHR9KTtcblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Y29uc3QgYWxyZWFkeUluamVjdGVkID0gbGFzdE1lc3NhZ2VzLnNvbWUoXG5cdFx0XHQobXNnKSA9PlxuXHRcdFx0XHQobXNnIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5yb2xlID09PSBcImN1c3RvbVwiICYmXG5cdFx0XHRcdChtc2cgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLmN1c3RvbVR5cGUgPT09IFwicnVsZXMtZW5naW5lXCIsXG5cdFx0KTtcblx0XHRpZiAoYWxyZWFkeUluamVjdGVkKSB7XG5cdFx0XHRjaGFubmVsLmVtaXQoXCJpbmplY3RlZFwiLCB7XG5cdFx0XHRcdHR5cGU6IFwiaW5qZWN0ZWRcIixcblx0XHRcdFx0cnVsZU5hbWVzOiB1bmNvbmRpdGlvbmFsLm1hcCgocikgPT4gci5uYW1lKSxcblx0XHRcdFx0c3lzdGVtUHJvbXB0TGVuZ3RoOiBldmVudC5zeXN0ZW1Qcm9tcHQubGVuZ3RoLFxuXHRcdFx0XHRkZWR1cGxpY2F0ZWQ6IHRydWUsXG5cdFx0XHR9KTtcblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgc291cmNlcyA9IFsuLi5uZXcgU2V0KHVuY29uZGl0aW9uYWwubWFwKChyKSA9PiByLnNvdXJjZSkpXTtcblx0XHRjb25zdCByZW1pbmRlckNvbnRlbnQgPSBidWlsZFN5c3RlbVJlbWluZGVyU2VjdGlvbih1bmNvbmRpdGlvbmFsLCBzb3VyY2VzKTtcblxuXHRcdGNoYW5uZWwuZW1pdChcImluamVjdGVkXCIsIHtcblx0XHRcdHR5cGU6IFwiaW5qZWN0ZWRcIixcblx0XHRcdHJ1bGVOYW1lczogdW5jb25kaXRpb25hbC5tYXAoKHIpID0+IHIubmFtZSksXG5cdFx0XHRzeXN0ZW1Qcm9tcHRMZW5ndGg6IGV2ZW50LnN5c3RlbVByb21wdC5sZW5ndGgsXG5cdFx0fSk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0bWVzc2FnZToge1xuXHRcdFx0XHRjdXN0b21UeXBlOiBcInJ1bGVzLWVuZ2luZVwiLFxuXHRcdFx0XHRjb250ZW50OiByZW1pbmRlckNvbnRlbnQsXG5cdFx0XHRcdGRpc3BsYXk6IGZhbHNlLFxuXHRcdFx0fSxcblx0XHR9O1xuXHR9KTtcblxuXHRwaS5vbihcInRvb2xfcmVzdWx0XCIsIGFzeW5jIChldmVudCkgPT4ge1xuXHRcdGlmICghUkVBRF9UT09MUy5oYXMoZXZlbnQudG9vbE5hbWUpKSByZXR1cm4gdW5kZWZpbmVkO1xuXG5cdFx0Y29uc3QgdGFyZ2V0UGF0aCA9IGV4dHJhY3RUYXJnZXRQYXRoKGV2ZW50LmlucHV0KTtcblx0XHRpZiAoIXRhcmdldFBhdGgpIHJldHVybiB1bmRlZmluZWQ7XG5cblx0XHRjb25zdCBtYXRjaGluZyA9IGdldE1hdGNoaW5nUnVsZXModGFyZ2V0UGF0aCk7XG5cdFx0aWYgKG1hdGNoaW5nLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuXHRcdGNvbnN0IG1hdGNoZWRSdWxlRGV0YWlsczogTWF0Y2hlZFJ1bGVEZXRhaWxbXSA9IG1hdGNoaW5nLm1hcCgocikgPT4ge1xuXHRcdFx0Y29uc3QgcnVsZU5hbWUgPSByLm5hbWU7XG5cdFx0XHRjb25zdCBpbmplY3RlZEZpbGVzID0gaW5qZWN0ZWRSdWxlRmlsZXMuZ2V0KHJ1bGVOYW1lKTtcblx0XHRcdGNvbnN0IHdhc0FscmVhZHlMb2FkZWQgPSBpbmplY3RlZEZpbGVzICE9PSB1bmRlZmluZWQgJiYgaW5qZWN0ZWRGaWxlcy5oYXModGFyZ2V0UGF0aCk7XG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdG5hbWU6IHJ1bGVOYW1lLFxuXHRcdFx0XHR0aXRsZTogci50aXRsZSxcblx0XHRcdFx0c2V2ZXJpdHk6IHIuZnJvbnRtYXR0ZXIuc2V2ZXJpdHkgfHwgKFwibWVkaXVtXCIgYXMgUnVsZVNldmVyaXR5KSxcblx0XHRcdFx0bWF0Y2hlZEdsb2I6XG5cdFx0XHRcdFx0KHIuZnJvbnRtYXR0ZXIuZ2xvYnMgPz8gci5mcm9udG1hdHRlci5wYXRocyk/LmZpbmQoKHApID0+IG1hdGNoZXNBbnlHbG9iKFtwXSwgdGFyZ2V0UGF0aCkpIHx8XG5cdFx0XHRcdFx0KHIuZnJvbnRtYXR0ZXIuZ2xvYnMgPz8gci5mcm9udG1hdHRlci5wYXRocyk/LlswXSB8fFxuXHRcdFx0XHRcdFwiXCIsXG5cdFx0XHRcdGFscmVhZHlMb2FkZWQ6IHdhc0FscmVhZHlMb2FkZWQgfHwgdW5kZWZpbmVkLFxuXHRcdFx0fTtcblx0XHR9KTtcblxuXHRcdC8vIERldGVybWluZSB3aGljaCBydWxlcyBhcmUgbmV3bHkgaW5qZWN0ZWQgdnMgYWxyZWFkeSBsb2FkZWRcblx0XHRjb25zdCBuZXdSdWxlcyA9IG1hdGNoaW5nLmZpbHRlcigocikgPT4ge1xuXHRcdFx0Y29uc3QgaW5qZWN0ZWRGaWxlcyA9IGluamVjdGVkUnVsZUZpbGVzLmdldChyLm5hbWUpO1xuXHRcdFx0cmV0dXJuICFpbmplY3RlZEZpbGVzIHx8ICFpbmplY3RlZEZpbGVzLmhhcyh0YXJnZXRQYXRoKTtcblx0XHR9KTtcblx0XHRjb25zdCBhbGxBbHJlYWR5TG9hZGVkID0gbmV3UnVsZXMubGVuZ3RoID09PSAwO1xuXG5cdFx0Ly8gUmVjb3JkIHRoYXQgdGhlc2UgcnVsZXMgaGF2ZSBub3cgYmVlbiBpbmplY3RlZCBmb3IgdGhpcyBmaWxlXG5cdFx0Zm9yIChjb25zdCByIG9mIG1hdGNoaW5nKSB7XG5cdFx0XHRsZXQgaW5qZWN0ZWRGaWxlcyA9IGluamVjdGVkUnVsZUZpbGVzLmdldChyLm5hbWUpO1xuXHRcdFx0aWYgKCFpbmplY3RlZEZpbGVzKSB7XG5cdFx0XHRcdGluamVjdGVkRmlsZXMgPSBuZXcgU2V0KCk7XG5cdFx0XHRcdGluamVjdGVkUnVsZUZpbGVzLnNldChyLm5hbWUsIGluamVjdGVkRmlsZXMpO1xuXHRcdFx0fVxuXHRcdFx0aW5qZWN0ZWRGaWxlcy5hZGQodGFyZ2V0UGF0aCk7XG5cdFx0fVxuXG5cdFx0Y29uc3QgaGFzQ3JpdGljYWwgPSBtYXRjaGluZy5zb21lKChyKSA9PiByLmZyb250bWF0dGVyLnNldmVyaXR5ID09PSBcImNyaXRpY2FsXCIpO1xuXHRcdGNvbnN0IGhhc0hpZ2ggPSBtYXRjaGluZy5zb21lKChyKSA9PiByLmZyb250bWF0dGVyLnNldmVyaXR5ID09PSBcImhpZ2hcIik7XG5cblx0XHRjaGFubmVsLmVtaXQoXCJtYXRjaGVkXCIsIHtcblx0XHRcdHR5cGU6IFwibWF0Y2hlZFwiLFxuXHRcdFx0ZmlsZVBhdGg6IHRhcmdldFBhdGgsXG5cdFx0XHRtYXRjaGVkUnVsZXM6IG1hdGNoZWRSdWxlRGV0YWlscyxcblx0XHRcdHRvb2xOYW1lOiBldmVudC50b29sTmFtZSxcblx0XHRcdHRvb2xDYWxsSWQ6IGV2ZW50LnRvb2xDYWxsSWQsXG5cdFx0XHRzZXZlcml0eTogaGFzQ3JpdGljYWwgPyBcIndhcm5pbmdcIiA6IGhhc0hpZ2ggPyBcIndhcm5pbmdcIiA6IFwiaW5mb1wiLFxuXHRcdFx0dGltZXN0YW1wOiBEYXRlLm5vdygpLFxuXHRcdFx0YWxyZWFkeUxvYWRlZDogYWxsQWxyZWFkeUxvYWRlZCB8fCB1bmRlZmluZWQsXG5cdFx0fSk7XG5cblx0XHQvLyBPbmx5IGluamVjdCBjb250ZW50IGZvciBORVcgcnVsZXMgKHNraXAgaWYgYWxsIGFscmVhZHkgbG9hZGVkKVxuXHRcdGlmIChhbGxBbHJlYWR5TG9hZGVkKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRkZXRhaWxzOiB7XG5cdFx0XHRcdFx0Li4uKChldmVudC5kZXRhaWxzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB8fCB7fSksXG5cdFx0XHRcdFx0cnVsZXNNYXRjaGVkOiBtYXRjaGVkUnVsZURldGFpbHMsXG5cdFx0XHRcdFx0bWF0Y2hlZEZpbGVQYXRoOiB0YXJnZXRQYXRoLFxuXHRcdFx0XHR9LFxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHRjb25zdCBjb250ZXh0U2VjdGlvbiA9IGJ1aWxkVG9vbFJlbWluZGVyU2VjdGlvbihuZXdSdWxlcywgdGFyZ2V0UGF0aCk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0Y29udGVudDogWy4uLmV2ZW50LmNvbnRlbnQsIHsgdHlwZTogXCJ0ZXh0XCIgYXMgY29uc3QsIHRleHQ6IGBcXG5cXG4ke2NvbnRleHRTZWN0aW9ufWAgfV0sXG5cdFx0XHRkZXRhaWxzOiB7XG5cdFx0XHRcdC4uLigoZXZlbnQuZGV0YWlscyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikgfHwge30pLFxuXHRcdFx0XHRydWxlc01hdGNoZWQ6IG1hdGNoZWRSdWxlRGV0YWlscyxcblx0XHRcdFx0bWF0Y2hlZEZpbGVQYXRoOiB0YXJnZXRQYXRoLFxuXHRcdFx0fSxcblx0XHR9O1xuXHR9KTtcblxuXHRwaS5vbihcImNvbnRleHRcIiwgYXN5bmMgKGV2ZW50KSA9PiB7XG5cdFx0bGFzdE1lc3NhZ2VzID0gZXZlbnQubWVzc2FnZXM7XG5cdFx0Y29uc3QgbWF0Y2hIaXN0b3J5ID0gcmVidWlsZE1hdGNoSGlzdG9yeShldmVudC5tZXNzYWdlcyk7XG5cblx0XHRjb25zdCBoYXNoID0gSlNPTi5zdHJpbmdpZnkobWF0Y2hIaXN0b3J5Lm1hcCgocikgPT4gYCR7ci50b29sQ2FsbElkfToke3IuZmlsZVBhdGh9YCkpO1xuXHRcdGlmIChoYXNoICE9PSBjYWNoZWRNYXRjaEhhc2gpIHtcblx0XHRcdGNhY2hlZE1hdGNoSGFzaCA9IGhhc2g7XG5cdFx0XHRjb25zdCB1bmNvbmRpdGlvbmFsID0gZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCk7XG5cdFx0XHRjb25zdCBjb25kaXRpb25hbCA9IGdldENvbmRpdGlvbmFsUnVsZXMoKTtcblx0XHRcdGNoYW5uZWwuZW1pdChcInNuYXBzaG90XCIsIHtcblx0XHRcdFx0dHlwZTogXCJzbmFwc2hvdFwiLFxuXHRcdFx0XHRydWxlczogcnVsZXMubWFwKHRvUnVsZURldGFpbCksXG5cdFx0XHRcdGluamVjdGVkUnVsZU5hbWVzOiB1bmNvbmRpdGlvbmFsLm1hcCgocikgPT4gci5uYW1lKSxcblx0XHRcdFx0dG90YWxSdWxlczogcnVsZXMubGVuZ3RoLFxuXHRcdFx0XHR1bmNvbmRpdGlvbmFsQ291bnQ6IHVuY29uZGl0aW9uYWwubGVuZ3RoLFxuXHRcdFx0XHRjb25kaXRpb25hbENvdW50OiBjb25kaXRpb25hbC5sZW5ndGgsXG5cdFx0XHRcdG1hdGNoSGlzdG9yeSxcblx0XHRcdFx0bGlmZWN5Y2xlTG9nOiBbXSxcblx0XHRcdFx0bG9hZGVkQXQ6IERhdGUubm93KCksXG5cdFx0XHRcdGNhY2hlVFRMOiBjb25maWc/LmNhY2hlVFRMIHx8IDMwMDAwLFxuXHRcdFx0fSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fSk7XG5cblx0cGkub24oXCJzZXNzaW9uX2NvbXBhY3RcIiwgYXN5bmMgKF9ldmVudCwgY3R4KSA9PiB7XG5cdFx0Y2FjaGVkTWF0Y2hIYXNoID0gXCJcIjtcblx0XHRsYXN0TWVzc2FnZXMgPSBbXTtcblx0XHRpbmplY3RlZFJ1bGVGaWxlcyA9IG5ldyBNYXAoKTtcblx0XHRjdHgudWkuc2V0U3RhdHVzKFwicnVsZXMtZW5naW5lXCIsIGBSdWxlczogJHtydWxlcy5sZW5ndGh9IChyZS1pbmplY3RlZCBhZnRlciBjb21wYWN0KWApO1xuXHR9KTtcblxuXHRwaS5vbihcInNlc3Npb25fdHJlZVwiLCBhc3luYyAoKSA9PiB7XG5cdFx0Y2FjaGVkTWF0Y2hIYXNoID0gXCJcIjtcblx0XHRsYXN0TWVzc2FnZXMgPSBbXTtcblx0XHRpbmplY3RlZFJ1bGVGaWxlcyA9IG5ldyBNYXAoKTtcblx0fSk7XG5cblx0cGkub24oXCJ0dXJuX2VuZFwiLCBhc3luYyAoKSA9PiB7XG5cdFx0aWYgKGxhc3RNZXNzYWdlcy5sZW5ndGggPT09IDAgJiYgcnVsZXMubGVuZ3RoID4gMCkgcmV0dXJuO1xuXHRcdGNvbnN0IG1hdGNoSGlzdG9yeSA9IHJlYnVpbGRNYXRjaEhpc3RvcnkobGFzdE1lc3NhZ2VzKTtcblx0XHRjb25zdCBoYXNoID0gSlNPTi5zdHJpbmdpZnkobWF0Y2hIaXN0b3J5Lm1hcCgocikgPT4gYCR7ci50b29sQ2FsbElkfToke3IuZmlsZVBhdGh9YCkpO1xuXHRcdGlmIChoYXNoICE9PSBjYWNoZWRNYXRjaEhhc2gpIHtcblx0XHRcdGNhY2hlZE1hdGNoSGFzaCA9IGhhc2g7XG5cdFx0XHRjaGFubmVsLmVtaXQoXCJzbmFwc2hvdFwiLCB7XG5cdFx0XHRcdHR5cGU6IFwic25hcHNob3RcIixcblx0XHRcdFx0cnVsZXM6IHJ1bGVzLm1hcCh0b1J1bGVEZXRhaWwpLFxuXHRcdFx0XHRpbmplY3RlZFJ1bGVOYW1lczogZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCkubWFwKChyKSA9PiByLm5hbWUpLFxuXHRcdFx0XHR0b3RhbFJ1bGVzOiBydWxlcy5sZW5ndGgsXG5cdFx0XHRcdHVuY29uZGl0aW9uYWxDb3VudDogZ2V0VW5jb25kaXRpb25hbFJ1bGVzKCkubGVuZ3RoLFxuXHRcdFx0XHRjb25kaXRpb25hbENvdW50OiBnZXRDb25kaXRpb25hbFJ1bGVzKCkubGVuZ3RoLFxuXHRcdFx0XHRtYXRjaEhpc3RvcnksXG5cdFx0XHRcdGxpZmVjeWNsZUxvZzogW10sXG5cdFx0XHRcdGxvYWRlZEF0OiBEYXRlLm5vdygpLFxuXHRcdFx0XHRjYWNoZVRUTDogY29uZmlnPy5jYWNoZVRUTCB8fCAzMDAwMCxcblx0XHRcdH0pO1xuXHRcdH1cblx0fSk7XG5cblx0cGkub24oXCJzZXNzaW9uX3NodXRkb3duXCIsIGFzeW5jIChfZXZlbnQsIGN0eCkgPT4ge1xuXHRcdGNoYW5uZWwuZW1pdChcInVubG9hZGVkXCIsIHsgdHlwZTogXCJ1bmxvYWRlZFwiLCByZWFzb246IFwic2Vzc2lvbl9zaHV0ZG93blwiIH0pO1xuXHRcdGN0eC51aS5zZXRTdGF0dXMoXCJydWxlcy1lbmdpbmVcIiwgdW5kZWZpbmVkKTtcblx0fSk7XG59XG4iLCAiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgdHlwZSB7IFJ1bGVzQ29uZmlnIH0gZnJvbSBcIi4vdHlwZXMuanNcIjtcblxuY29uc3QgREVGQVVMVF9DQUNIRV9UVEwgPSAzMF8wMDA7XG5cbmNvbnN0IERFRkFVTFRfRElSUyA9IHtcblx0bWFuYWdlZDogW1wiL2V0Yy9jbGF1ZGUtY29kZS8uY2xhdWRlL3J1bGVzXCJdLFxuXHR1c2VyOiBbcGF0aC5qb2luKGhvbWVkaXIoKSwgXCIuY2xhdWRlXCIsIFwicnVsZXNcIiksIHBhdGguam9pbihob21lZGlyKCksIFwiLmNvbmZpZ1wiLCBcIm9wZW5jb2RlXCIsIFwicnVsZXNcIildLFxuXHRwaTogW1wiLnBpL3J1bGVzXCJdLFxuXHRwcm9qZWN0OiBbXCIuY2xhdWRlL3J1bGVzXCIsIFwiLm9wZW5jb2RlL3J1bGVzXCIsIFwiLnRyYWUvcnVsZXNcIl0sXG59O1xuXG5mdW5jdGlvbiBkZWZhdWx0Q29uZmlnKCk6IFJ1bGVzQ29uZmlnIHtcblx0cmV0dXJuIHtcblx0XHRjYWNoZVRUTDogREVGQVVMVF9DQUNIRV9UVEwsXG5cdFx0bm90aWZ5T25Mb2FkOiB0cnVlLFxuXHRcdG5vdGlmeU9uTWF0Y2g6IHRydWUsXG5cdH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkQ29uZmlnKHByb2plY3REaXI6IHN0cmluZyk6IFByb21pc2U8UnVsZXNDb25maWc+IHtcblx0Y29uc3QgY29uZmlnRmlsZXMgPSBbXG5cdFx0XCIucnVsZXMtY29uZmlnLmpzb25cIixcblx0XHRcIi5waS9ydWxlcy1jb25maWcuanNvblwiLFxuXHRcdFwiLmNsYXVkZS9ydWxlcy1jb25maWcuanNvblwiLFxuXHRcdFwiLm9wZW5jb2RlL3J1bGVzLWNvbmZpZy5qc29uXCIsXG5cdF07XG5cblx0Zm9yIChjb25zdCBuYW1lIG9mIGNvbmZpZ0ZpbGVzKSB7XG5cdFx0Y29uc3QgZnAgPSBwYXRoLnJlc29sdmUocHJvamVjdERpciwgbmFtZSk7XG5cdFx0aWYgKCFmcy5leGlzdHNTeW5jKGZwKSkgY29udGludWU7XG5cdFx0dHJ5IHtcblx0XHRcdGNvbnN0IHJhdyA9IGZzLnJlYWRGaWxlU3luYyhmcCwgXCJ1dGYtOFwiKTtcblx0XHRcdGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmF3KTtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdC4uLmRlZmF1bHRDb25maWcoKSxcblx0XHRcdFx0Li4ucGFyc2VkLFxuXHRcdFx0XHRjYWNoZVRUTDogcGFyc2VkLmNhY2hlVFRMID8/IERFRkFVTFRfQ0FDSEVfVFRMLFxuXHRcdFx0XHRub3RpZnlPbkxvYWQ6IHBhcnNlZC5ub3RpZnlPbkxvYWQgPz8gdHJ1ZSxcblx0XHRcdFx0bm90aWZ5T25NYXRjaDogcGFyc2VkLm5vdGlmeU9uTWF0Y2ggPz8gdHJ1ZSxcblx0XHRcdH07XG5cdFx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0XHRjb25zb2xlLmRlYnVnKFwiW3J1bGVzLWVuZ2luZV0gY29uZmlnIHBhcnNlIGZhaWxlZDpcIiwgZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IGVycik7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGRlZmF1bHRDb25maWcoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEaXJzKFxuXHRwcm9qZWN0RGlyOiBzdHJpbmcsXG5cdGNvbmZpZzogUnVsZXNDb25maWcsXG4pOiBBcnJheTx7IHNjb3BlOiBzdHJpbmc7IGRpcjogc3RyaW5nOyBzb3VyY2U6IHN0cmluZyB9PiB7XG5cdGNvbnN0IHNvdXJjZXMgPSBjb25maWcuZGlycyB8fCBERUZBVUxUX0RJUlM7XG5cdGNvbnN0IHJlc3VsdDogQXJyYXk8eyBzY29wZTogc3RyaW5nOyBkaXI6IHN0cmluZzsgc291cmNlOiBzdHJpbmcgfT4gPSBbXTtcblxuXHRmb3IgKGNvbnN0IFtzY29wZSwgcGF0aHNdIG9mIE9iamVjdC5lbnRyaWVzKHNvdXJjZXMpKSB7XG5cdFx0Zm9yIChjb25zdCBwIG9mIHBhdGhzKSB7XG5cdFx0XHRyZXN1bHQucHVzaCh7XG5cdFx0XHRcdHNjb3BlLFxuXHRcdFx0XHRkaXI6IHAuc3RhcnRzV2l0aChcIi9cIikgfHwgcC5zdGFydHNXaXRoKFwiflwiKSA/IHAucmVwbGFjZSgvXn4vLCBob21lZGlyKCkpIDogcGF0aC5yZXNvbHZlKHByb2plY3REaXIsIHApLFxuXHRcdFx0XHRzb3VyY2U6IHAsXG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gcmVzdWx0O1xufVxuIiwgImltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB0eXBlIHsgUGFyc2VkUnVsZSwgUnVsZUNhY2hlLCBSdWxlRnJvbnRtYXR0ZXIgfSBmcm9tIFwiLi90eXBlcy5qc1wiO1xuXG5mdW5jdGlvbiBzcGxpdENvbW1hKHZhbDogc3RyaW5nKTogc3RyaW5nW10ge1xuXHRjb25zdCByZXN1bHQ6IHN0cmluZ1tdID0gW107XG5cdGxldCBkZXB0aCA9IDA7XG5cdGxldCBjdXJyZW50ID0gXCJcIjtcblx0Zm9yIChjb25zdCBjaCBvZiB2YWwpIHtcblx0XHRpZiAoY2ggPT09IFwie1wiIHx8IGNoID09PSBcIihcIiB8fCBjaCA9PT0gXCJbXCIpIGRlcHRoKys7XG5cdFx0ZWxzZSBpZiAoY2ggPT09IFwifVwiIHx8IGNoID09PSBcIilcIiB8fCBjaCA9PT0gXCJdXCIpIGRlcHRoLS07XG5cblx0XHRpZiAoY2ggPT09IFwiLFwiICYmIGRlcHRoID09PSAwKSB7XG5cdFx0XHRjb25zdCB0cmltbWVkID0gY3VycmVudC50cmltKCkucmVwbGFjZSgvXltcIiddfFtcIiddJC9nLCBcIlwiKTtcblx0XHRcdGlmICh0cmltbWVkKSByZXN1bHQucHVzaCh0cmltbWVkKTtcblx0XHRcdGN1cnJlbnQgPSBcIlwiO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdXJyZW50ICs9IGNoO1xuXHRcdH1cblx0fVxuXHRjb25zdCB0cmltbWVkID0gY3VycmVudC50cmltKCkucmVwbGFjZSgvXltcIiddfFtcIiddJC9nLCBcIlwiKTtcblx0aWYgKHRyaW1tZWQpIHJlc3VsdC5wdXNoKHRyaW1tZWQpO1xuXHRyZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VGcm9udG1hdHRlcihjb250ZW50OiBzdHJpbmcpOiB7IGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+OyBib2R5OiBzdHJpbmcgfSB7XG5cdGNvbnN0IGZyb250bWF0dGVyUmVnZXggPSAvXi0tLVxccj9cXG4oW1xcc1xcU10qPylcXG4/LS0tXFxyP1xcbihbXFxzXFxTXSopJC87XG5cdGNvbnN0IG1hdGNoID0gY29udGVudC5tYXRjaChmcm9udG1hdHRlclJlZ2V4KTtcblxuXHRpZiAoIW1hdGNoKSB7XG5cdFx0cmV0dXJuIHsgZGF0YToge30sIGJvZHk6IGNvbnRlbnQgfTtcblx0fVxuXG5cdGNvbnN0IFssIGZyb250bWF0dGVyU3RyLCBib2R5XSA9IG1hdGNoO1xuXHRjb25zdCBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG5cdGNvbnN0IGxpbmVzID0gZnJvbnRtYXR0ZXJTdHIuc3BsaXQoXCJcXG5cIik7XG5cdGxldCBpID0gMDtcblx0d2hpbGUgKGkgPCBsaW5lcy5sZW5ndGgpIHtcblx0XHRjb25zdCBsaW5lID0gbGluZXNbaV07XG5cdFx0Y29uc3QgY29sb25JbmRleCA9IGxpbmUuaW5kZXhPZihcIjpcIik7XG5cdFx0aWYgKGNvbG9uSW5kZXggPT09IC0xKSB7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHRjb25zdCByYXdLZXkgPSBsaW5lLnNsaWNlKDAsIGNvbG9uSW5kZXgpLnRyaW0oKTtcblx0XHRsZXQgdmFsdWU6IHN0cmluZyB8IHN0cmluZ1tdIHwgbnVsbCA9IGxpbmUuc2xpY2UoY29sb25JbmRleCArIDEpLnRyaW0oKTtcblxuXHRcdGlmICh2YWx1ZSA9PT0gXCJcIiB8fCB2YWx1ZSA9PT0gXCJudWxsXCIgfHwgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIpIHtcblx0XHRcdGNvbnN0IGxpc3RJdGVtczogc3RyaW5nW10gPSBbXTtcblx0XHRcdGxldCBqID0gaSArIDE7XG5cdFx0XHR3aGlsZSAoaiA8IGxpbmVzLmxlbmd0aCkge1xuXHRcdFx0XHRjb25zdCBzdWJMaW5lID0gbGluZXNbal07XG5cdFx0XHRcdGlmIChzdWJMaW5lLm1hdGNoKC9eXFxzKi1cXHMrLykpIHtcblx0XHRcdFx0XHRsaXN0SXRlbXMucHVzaChcblx0XHRcdFx0XHRcdHN1YkxpbmVcblx0XHRcdFx0XHRcdFx0LnJlcGxhY2UoL15cXHMqLVxccysvLCBcIlwiKVxuXHRcdFx0XHRcdFx0XHQudHJpbSgpXG5cdFx0XHRcdFx0XHRcdC5yZXBsYWNlKC9eW1wiJ118W1wiJ10kL2csIFwiXCIpLFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0aisrO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHN1YkxpbmUudHJpbSgpID09PSBcIlwiIHx8IHN1YkxpbmUubWF0Y2goL15cXHMrLykpIHtcblx0XHRcdFx0XHRqKys7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmIChsaXN0SXRlbXMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRjb25zdCBjYW1lbEtleSA9IHJhd0tleS5yZXBsYWNlKC8tKFthLXpdKS9nLCAoXywgbGV0dGVyKSA9PiBsZXR0ZXIudG9VcHBlckNhc2UoKSk7XG5cdFx0XHRcdGRhdGFbY2FtZWxLZXldID0gbGlzdEl0ZW1zO1xuXHRcdFx0XHRpID0gajtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cdFx0XHR2YWx1ZSA9IG51bGw7XG5cdFx0fSBlbHNlIGlmICh2YWx1ZS5zdGFydHNXaXRoKFwiW1wiKSAmJiB2YWx1ZS5lbmRzV2l0aChcIl1cIikpIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHZhbHVlID0gSlNPTi5wYXJzZSh2YWx1ZS5yZXBsYWNlKC8nL2csICdcIicpKTtcblx0XHRcdH0gY2F0Y2ggKGVycikge1xuXHRcdFx0XHRjb25zb2xlLmRlYnVnKFwiW3J1bGVzLWVuZ2luZV0gSlNPTiBhcnJheSBwYXJzZSBmYWlsZWQ6XCIsIGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBlcnIpO1xuXHRcdFx0XHR2YWx1ZSA9ICh2YWx1ZSBhcyBzdHJpbmcpXG5cdFx0XHRcdFx0LnNsaWNlKDEsIC0xKVxuXHRcdFx0XHRcdC5zcGxpdChcIixcIilcblx0XHRcdFx0XHQubWFwKCh2OiBzdHJpbmcpID0+IHYudHJpbSgpLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgXCJcIikpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZiAodmFsdWUuc3RhcnRzV2l0aCgnXCInKSAmJiB2YWx1ZS5lbmRzV2l0aCgnXCInKSkge1xuXHRcdFx0dmFsdWUgPSB2YWx1ZS5zbGljZSgxLCAtMSk7XG5cdFx0fSBlbHNlIGlmICh2YWx1ZS5zdGFydHNXaXRoKFwiJ1wiKSAmJiB2YWx1ZS5lbmRzV2l0aChcIidcIikpIHtcblx0XHRcdHZhbHVlID0gdmFsdWUuc2xpY2UoMSwgLTEpO1xuXHRcdH1cblxuXHRcdGNvbnN0IGNhbWVsS2V5ID0gcmF3S2V5LnJlcGxhY2UoLy0oW2Etel0pL2csIChfLCBsZXR0ZXIpID0+IGxldHRlci50b1VwcGVyQ2FzZSgpKTtcblxuXHRcdGlmICgoY2FtZWxLZXkgPT09IFwicGF0aHNcIiB8fCBjYW1lbEtleSA9PT0gXCJnbG9ic1wiKSAmJiB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdGRhdGFbY2FtZWxLZXldID0gc3BsaXRDb21tYSh2YWx1ZSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGRhdGFbY2FtZWxLZXldID0gdmFsdWU7XG5cdFx0fVxuXHRcdGkrKztcblx0fVxuXG5cdHJldHVybiB7IGRhdGEsIGJvZHk6IGJvZHkudHJpbSgpIH07XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RUaXRsZShib2R5OiBzdHJpbmcpOiBzdHJpbmcge1xuXHRmb3IgKGNvbnN0IGxpbmUgb2YgYm9keS5zcGxpdChcIlxcblwiKSkge1xuXHRcdGNvbnN0IHRyaW1tZWQgPSBsaW5lLnRyaW0oKTtcblx0XHRpZiAodHJpbW1lZCkge1xuXHRcdFx0cmV0dXJuIHRyaW1tZWQucmVwbGFjZSgvXiMrXFxzKi8sIFwiXCIpLnJlcGxhY2UoL1xcKlxcKi9nLCBcIlwiKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIFwiVW50aXRsZWQgUnVsZVwiO1xufVxuXG5mdW5jdGlvbiBwYXJzZVBhdGhzKHJhdzogdW5rbm93bik6IHN0cmluZ1tdIHtcblx0aWYgKCFyYXcpIHJldHVybiBbXTtcblx0aWYgKHR5cGVvZiByYXcgPT09IFwic3RyaW5nXCIpIHtcblx0XHRyZXR1cm4gcmF3XG5cdFx0XHQuc3BsaXQoXCIsXCIpXG5cdFx0XHQubWFwKChnKSA9PiBnLnRyaW0oKSlcblx0XHRcdC5maWx0ZXIoQm9vbGVhbik7XG5cdH1cblx0aWYgKEFycmF5LmlzQXJyYXkocmF3KSkgcmV0dXJuIHJhdyBhcyBzdHJpbmdbXTtcblx0cmV0dXJuIFtdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VSdWxlRmlsZShmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50OiBzdHJpbmcpOiBQYXJzZWRSdWxlIHtcblx0Y29uc3QgeyBkYXRhLCBib2R5IH0gPSBwYXJzZUZyb250bWF0dGVyKGNvbnRlbnQpO1xuXHRjb25zdCByYXdHbG9icyA9IGRhdGEuZ2xvYnMgPz8gZGF0YS5wYXRocztcblx0Y29uc3QgZ2xvYnMgPSBwYXJzZVBhdGhzKHJhd0dsb2JzKTtcblx0Y29uc3QgcmF3UGF0aHMgPSBkYXRhLnBhdGhzO1xuXHRjb25zdCBwYXRocyA9IHBhcnNlUGF0aHMocmF3UGF0aHMpO1xuXHRjb25zdCBpc1VuY29uZGl0aW9uYWwgPSBnbG9icy5sZW5ndGggPT09IDAgfHwgKGdsb2JzLmxlbmd0aCA9PT0gMSAmJiBnbG9ic1swXSA9PT0gXCIqKlwiKTtcblxuXHRjb25zdCBmcm9udG1hdHRlcjogUnVsZUZyb250bWF0dGVyID0ge307XG5cdGlmIChyYXdHbG9icykge1xuXHRcdGZyb250bWF0dGVyLmdsb2JzID0gZ2xvYnM7XG5cdFx0aWYgKHJhd1BhdGhzKSB7XG5cdFx0XHRmcm9udG1hdHRlci5wYXRocyA9IHBhdGhzO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmcm9udG1hdHRlci5wYXRocyA9IGdsb2JzO1xuXHRcdH1cblx0fVxuXHRpZiAoZGF0YS5kZXNjcmlwdGlvbiAmJiB0eXBlb2YgZGF0YS5kZXNjcmlwdGlvbiA9PT0gXCJzdHJpbmdcIikgZnJvbnRtYXR0ZXIuZGVzY3JpcHRpb24gPSBkYXRhLmRlc2NyaXB0aW9uO1xuXHRpZiAoZGF0YS5zZXZlcml0eSAmJiB0eXBlb2YgZGF0YS5zZXZlcml0eSA9PT0gXCJzdHJpbmdcIilcblx0XHRmcm9udG1hdHRlci5zZXZlcml0eSA9IGRhdGEuc2V2ZXJpdHkgYXMgUGFyc2VkUnVsZVtcImZyb250bWF0dGVyXCJdW1wic2V2ZXJpdHlcIl07XG5cdGlmIChkYXRhLmFsbG93ZWRUb29scylcblx0XHRmcm9udG1hdHRlci5hbGxvd2VkVG9vbHMgPVxuXHRcdFx0dHlwZW9mIGRhdGEuYWxsb3dlZFRvb2xzID09PSBcInN0cmluZ1wiID8gW2RhdGEuYWxsb3dlZFRvb2xzXSA6IChkYXRhLmFsbG93ZWRUb29scyBhcyBzdHJpbmdbXSk7XG5cdGlmIChkYXRhLndoZW5Ub1VzZSAmJiB0eXBlb2YgZGF0YS53aGVuVG9Vc2UgPT09IFwic3RyaW5nXCIpIGZyb250bWF0dGVyLndoZW5Ub1VzZSA9IGRhdGEud2hlblRvVXNlO1xuXHRpZiAoZGF0YS5ub3RpZnlPbk1hdGNoICE9PSB1bmRlZmluZWQpXG5cdFx0ZnJvbnRtYXR0ZXIubm90aWZ5T25NYXRjaCA9IGRhdGEubm90aWZ5T25NYXRjaCA9PT0gXCJ0cnVlXCIgfHwgZGF0YS5ub3RpZnlPbk1hdGNoID09PSB0cnVlO1xuXHRpZiAoZGF0YS5za2lwSW5Qcm9tcHQgIT09IHVuZGVmaW5lZClcblx0XHRmcm9udG1hdHRlci5za2lwSW5Qcm9tcHQgPSBkYXRhLnNraXBJblByb21wdCA9PT0gXCJ0cnVlXCIgfHwgZGF0YS5za2lwSW5Qcm9tcHQgPT09IHRydWU7XG5cblx0cmV0dXJuIHtcblx0XHRuYW1lOiBwYXRoLmJhc2VuYW1lKGZpbGVQYXRoLCBwYXRoLmV4dG5hbWUoZmlsZVBhdGgpKSxcblx0XHRmaWxlUGF0aCxcblx0XHR0aXRsZTogZXh0cmFjdFRpdGxlKGJvZHkpLFxuXHRcdGNvbnRlbnQ6IGJvZHkudHJpbSgpLFxuXHRcdHNjb3BlOiBcInByb2plY3RcIixcblx0XHRzb3VyY2U6IFwiXCIsXG5cdFx0ZnJvbnRtYXR0ZXIsXG5cdFx0aXNVbmNvbmRpdGlvbmFsLFxuXHR9O1xufVxuXG5mdW5jdGlvbiBzY2FuRGlyKGRpcjogc3RyaW5nLCBmaWxlczogc3RyaW5nW10gPSBbXSk6IHN0cmluZ1tdIHtcblx0aWYgKCFmcy5leGlzdHNTeW5jKGRpcikpIHJldHVybiBmaWxlcztcblx0Y29uc3QgZW50cmllcyA9IGZzLnJlYWRkaXJTeW5jKGRpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuXHRmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcblx0XHRjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbihkaXIsIGVudHJ5Lm5hbWUpO1xuXHRcdGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpKSB7XG5cdFx0XHRzY2FuRGlyKGZ1bGxQYXRoLCBmaWxlcyk7XG5cdFx0fSBlbHNlIGlmIChlbnRyeS5pc0ZpbGUoKSAmJiAoZW50cnkubmFtZS5lbmRzV2l0aChcIi5tZFwiKSB8fCBlbnRyeS5uYW1lLmVuZHNXaXRoKFwiLm1kY1wiKSkpIHtcblx0XHRcdGZpbGVzLnB1c2goZnVsbFBhdGgpO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gZmlsZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2FkUnVsZXMocnVsZXNEaXI6IHN0cmluZyk6IFJ1bGVDYWNoZSB7XG5cdGNvbnN0IHJ1bGVzOiBQYXJzZWRSdWxlW10gPSBbXTtcblx0Y29uc3QgdW5jb25kaXRpb25hbDogUGFyc2VkUnVsZVtdID0gW107XG5cdGNvbnN0IGNvbmRpdGlvbmFsOiBQYXJzZWRSdWxlW10gPSBbXTtcblxuXHRpZiAoIWZzLmV4aXN0c1N5bmMocnVsZXNEaXIpKSB7XG5cdFx0cmV0dXJuIHsgcnVsZXMsIHVuY29uZGl0aW9uYWwsIGNvbmRpdGlvbmFsLCBsb2FkZWRBdDogRGF0ZS5ub3coKSB9O1xuXHR9XG5cblx0Y29uc3QgZmlsZXMgPSBzY2FuRGlyKHJ1bGVzRGlyKTtcblxuXHRmb3IgKGNvbnN0IGZpbGVQYXRoIG9mIGZpbGVzKSB7XG5cdFx0Y29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhmaWxlUGF0aCwgXCJ1dGYtOFwiKTtcblx0XHRjb25zdCBydWxlID0gcGFyc2VSdWxlRmlsZShmaWxlUGF0aCwgY29udGVudCk7XG5cdFx0cnVsZXMucHVzaChydWxlKTtcblx0XHRpZiAocnVsZS5pc1VuY29uZGl0aW9uYWwpIHtcblx0XHRcdHVuY29uZGl0aW9uYWwucHVzaChydWxlKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y29uZGl0aW9uYWwucHVzaChydWxlKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4geyBydWxlcywgdW5jb25kaXRpb25hbCwgY29uZGl0aW9uYWwsIGxvYWRlZEF0OiBEYXRlLm5vdygpIH07XG59XG4iLCAiaW1wb3J0IHsgcmVzb2x2ZURpcnMgfSBmcm9tIFwiLi9jb25maWcuanNcIjtcbmltcG9ydCB7IGxvYWRSdWxlcyB9IGZyb20gXCIuL2xvYWRlci5qc1wiO1xuaW1wb3J0IHR5cGUgeyBQYXJzZWRSdWxlLCBSdWxlc0NvbmZpZyB9IGZyb20gXCIuL3R5cGVzLmpzXCI7XG5cbmxldCBjYWNoZTogeyBydWxlczogUGFyc2VkUnVsZVtdOyBsb2FkZWRBdDogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFJ1bGVzKHByb2plY3REaXI6IHN0cmluZywgY29uZmlnOiBSdWxlc0NvbmZpZyk6IFByb21pc2U8UGFyc2VkUnVsZVtdPiB7XG5cdGlmIChjYWNoZSAmJiBEYXRlLm5vdygpIC0gY2FjaGUubG9hZGVkQXQgPCBjb25maWcuY2FjaGVUVEwpIHtcblx0XHRyZXR1cm4gY2FjaGUucnVsZXM7XG5cdH1cblxuXHRjb25zdCBydWxlcyA9IGF3YWl0IGxvYWRBbGxSdWxlcyhwcm9qZWN0RGlyLCBjb25maWcpO1xuXHRjYWNoZSA9IHsgcnVsZXMsIGxvYWRlZEF0OiBEYXRlLm5vdygpIH07XG5cdHJldHVybiBydWxlcztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGludmFsaWRhdGVDYWNoZSgpOiB2b2lkIHtcblx0Y2FjaGUgPSBudWxsO1xufVxuXG5hc3luYyBmdW5jdGlvbiBsb2FkQWxsUnVsZXMocHJvamVjdERpcjogc3RyaW5nLCBjb25maWc6IFJ1bGVzQ29uZmlnKTogUHJvbWlzZTxQYXJzZWRSdWxlW10+IHtcblx0Y29uc3Qgc291cmNlcyA9IHJlc29sdmVEaXJzKHByb2plY3REaXIsIGNvbmZpZyk7XG5cdGNvbnN0IHJlc3VsdDogUGFyc2VkUnVsZVtdID0gW107XG5cdGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuXHRmb3IgKGNvbnN0IHsgc2NvcGUsIGRpciwgc291cmNlIH0gb2Ygc291cmNlcykge1xuXHRcdGNvbnN0IHJ1bGVDYWNoZSA9IGxvYWRSdWxlcyhkaXIpO1xuXHRcdGZvciAoY29uc3QgcnVsZSBvZiBydWxlQ2FjaGUucnVsZXMpIHtcblx0XHRcdGlmIChzZWVuLmhhcyhydWxlLmZpbGVQYXRoKSkgY29udGludWU7XG5cdFx0XHRzZWVuLmFkZChydWxlLmZpbGVQYXRoKTtcblx0XHRcdHJ1bGUuc2NvcGUgPSBzY29wZSBhcyBQYXJzZWRSdWxlW1wic2NvcGVcIl07XG5cdFx0XHRydWxlLnNvdXJjZSA9IHNvdXJjZTtcblx0XHRcdHJlc3VsdC5wdXNoKHJ1bGUpO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiByZXN1bHQ7XG59XG4iLCAiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgdHlwZSB7IFJ1bGVzQ29uZmlnIH0gZnJvbSBcIi4vdHlwZXMuanNcIjtcblxuY29uc3QgREVGQVVMVF9DQUNIRV9UVEwgPSAzMF8wMDA7XG5cbmNvbnN0IERFRkFVTFRfRElSUyA9IHtcblx0bWFuYWdlZDogW1wiL2V0Yy9jbGF1ZGUtY29kZS8uY2xhdWRlL3J1bGVzXCJdLFxuXHR1c2VyOiBbcGF0aC5qb2luKGhvbWVkaXIoKSwgXCIuY2xhdWRlXCIsIFwicnVsZXNcIiksIHBhdGguam9pbihob21lZGlyKCksIFwiLmNvbmZpZ1wiLCBcIm9wZW5jb2RlXCIsIFwicnVsZXNcIildLFxuXHRwaTogW1wiLnBpL3J1bGVzXCJdLFxuXHRwcm9qZWN0OiBbXCIuY2xhdWRlL3J1bGVzXCIsIFwiLm9wZW5jb2RlL3J1bGVzXCIsIFwiLnRyYWUvcnVsZXNcIl0sXG59O1xuXG5mdW5jdGlvbiBkZWZhdWx0Q29uZmlnKCk6IFJ1bGVzQ29uZmlnIHtcblx0cmV0dXJuIHtcblx0XHRjYWNoZVRUTDogREVGQVVMVF9DQUNIRV9UVEwsXG5cdFx0bm90aWZ5T25Mb2FkOiB0cnVlLFxuXHRcdG5vdGlmeU9uTWF0Y2g6IHRydWUsXG5cdH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkQ29uZmlnKHByb2plY3REaXI6IHN0cmluZyk6IFByb21pc2U8UnVsZXNDb25maWc+IHtcblx0Y29uc3QgY29uZmlnRmlsZXMgPSBbXG5cdFx0XCIucnVsZXMtY29uZmlnLmpzb25cIixcblx0XHRcIi5waS9ydWxlcy1jb25maWcuanNvblwiLFxuXHRcdFwiLmNsYXVkZS9ydWxlcy1jb25maWcuanNvblwiLFxuXHRcdFwiLm9wZW5jb2RlL3J1bGVzLWNvbmZpZy5qc29uXCIsXG5cdF07XG5cblx0Zm9yIChjb25zdCBuYW1lIG9mIGNvbmZpZ0ZpbGVzKSB7XG5cdFx0Y29uc3QgZnAgPSBwYXRoLnJlc29sdmUocHJvamVjdERpciwgbmFtZSk7XG5cdFx0aWYgKCFmcy5leGlzdHNTeW5jKGZwKSkgY29udGludWU7XG5cdFx0dHJ5IHtcblx0XHRcdGNvbnN0IHJhdyA9IGZzLnJlYWRGaWxlU3luYyhmcCwgXCJ1dGYtOFwiKTtcblx0XHRcdGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmF3KTtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdC4uLmRlZmF1bHRDb25maWcoKSxcblx0XHRcdFx0Li4ucGFyc2VkLFxuXHRcdFx0XHRjYWNoZVRUTDogcGFyc2VkLmNhY2hlVFRMID8/IERFRkFVTFRfQ0FDSEVfVFRMLFxuXHRcdFx0XHRub3RpZnlPbkxvYWQ6IHBhcnNlZC5ub3RpZnlPbkxvYWQgPz8gdHJ1ZSxcblx0XHRcdFx0bm90aWZ5T25NYXRjaDogcGFyc2VkLm5vdGlmeU9uTWF0Y2ggPz8gdHJ1ZSxcblx0XHRcdH07XG5cdFx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0XHRjb25zb2xlLmRlYnVnKFwiW3J1bGVzLWVuZ2luZV0gY29uZmlnIHBhcnNlIGZhaWxlZDpcIiwgZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IGVycik7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGRlZmF1bHRDb25maWcoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEaXJzKFxuXHRwcm9qZWN0RGlyOiBzdHJpbmcsXG5cdGNvbmZpZzogUnVsZXNDb25maWcsXG4pOiBBcnJheTx7IHNjb3BlOiBzdHJpbmc7IGRpcjogc3RyaW5nOyBzb3VyY2U6IHN0cmluZyB9PiB7XG5cdGNvbnN0IHNvdXJjZXMgPSBjb25maWcuZGlycyB8fCBERUZBVUxUX0RJUlM7XG5cdGNvbnN0IHJlc3VsdDogQXJyYXk8eyBzY29wZTogc3RyaW5nOyBkaXI6IHN0cmluZzsgc291cmNlOiBzdHJpbmcgfT4gPSBbXTtcblxuXHRmb3IgKGNvbnN0IFtzY29wZSwgcGF0aHNdIG9mIE9iamVjdC5lbnRyaWVzKHNvdXJjZXMpKSB7XG5cdFx0Zm9yIChjb25zdCBwIG9mIHBhdGhzKSB7XG5cdFx0XHRyZXN1bHQucHVzaCh7XG5cdFx0XHRcdHNjb3BlLFxuXHRcdFx0XHRkaXI6IHAuc3RhcnRzV2l0aChcIi9cIikgfHwgcC5zdGFydHNXaXRoKFwiflwiKSA/IHAucmVwbGFjZSgvXn4vLCBob21lZGlyKCkpIDogcGF0aC5yZXNvbHZlKHByb2plY3REaXIsIHApLFxuXHRcdFx0XHRzb3VyY2U6IHAsXG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gcmVzdWx0O1xufVxuIiwgImltcG9ydCB0eXBlIHsgUGFyc2VkUnVsZSB9IGZyb20gXCIuL3R5cGVzLmpzXCI7XG5cbmNvbnN0IFNFVkVSSVRZX0lDT05TOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuXHRjcml0aWNhbDogXCJcdUQ4M0RcdUREMzRcIixcblx0aGlnaDogXCJcdUQ4M0RcdURGRTBcIixcblx0bWVkaXVtOiBcIlx1RDgzRFx1REZFMVwiLFxuXHRsb3c6IFwiXHVEODNEXHVERDM1XCIsXG5cdGhpbnQ6IFwiXHVEODNEXHVEQ0ExXCIsXG59O1xuXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRTeXN0ZW1SZW1pbmRlclNlY3Rpb24ocnVsZXM6IFBhcnNlZFJ1bGVbXSwgc291cmNlczogc3RyaW5nW10pOiBzdHJpbmcge1xuXHRpZiAocnVsZXMubGVuZ3RoID09PSAwKSByZXR1cm4gXCJcIjtcblxuXHRjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXG5cdFx0XCI8c3lzdGVtLXJlbWluZGVyPlwiLFxuXHRcdGBJbnN0cnVjdGlvbnMgZnJvbTogJHtzb3VyY2VzLmpvaW4oXCIsIFwiKX1gLFxuXHRcdFwiVGhlIGZvbGxvd2luZyBydWxlcyBhcmUgYWx3YXlzIGFjdGl2ZS4gRm9sbG93IHRoZW0gc3RyaWN0bHkuXCIsXG5cdFx0XCJcIixcblx0XTtcblxuXHRmb3IgKGNvbnN0IHJ1bGUgb2YgcnVsZXMpIHtcblx0XHRsaW5lcy5wdXNoKGBSdWxlOiAke3J1bGUubmFtZX0gXHUyMDE0ICR7cnVsZS50aXRsZX1gKTtcblx0XHRpZiAocnVsZS5mcm9udG1hdHRlci5kZXNjcmlwdGlvbikge1xuXHRcdFx0bGluZXMucHVzaChgPiAke3J1bGUuZnJvbnRtYXR0ZXIuZGVzY3JpcHRpb259YCk7XG5cdFx0fVxuXHRcdGxpbmVzLnB1c2goXCJcIik7XG5cdFx0bGluZXMucHVzaChydWxlLmNvbnRlbnQpO1xuXHRcdGxpbmVzLnB1c2goXCJcIik7XG5cdH1cblxuXHRsaW5lcy5wdXNoKFwiPC9zeXN0ZW0tcmVtaW5kZXI+XCIpO1xuXHRyZXR1cm4gbGluZXMuam9pbihcIlxcblwiKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkVG9vbFJlbWluZGVyU2VjdGlvbihydWxlczogUGFyc2VkUnVsZVtdLCB0YXJnZXRQYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRpZiAocnVsZXMubGVuZ3RoID09PSAwKSByZXR1cm4gXCJcIjtcblxuXHRjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXG5cdFx0XCI8c3lzdGVtLXJlbWluZGVyPlwiLFxuXHRcdGBDb25kaXRpb25hbCBydWxlcyBtYXRjaGVkIGZvciAke3RhcmdldFBhdGh9OmAsXG5cdFx0XCJcIixcblx0XTtcblxuXHRmb3IgKGNvbnN0IHJ1bGUgb2YgcnVsZXMpIHtcblx0XHRjb25zdCBzZXZlcml0eSA9IHJ1bGUuZnJvbnRtYXR0ZXIuc2V2ZXJpdHkgfHwgXCJtZWRpdW1cIjtcblx0XHRjb25zdCBpY29uID0gU0VWRVJJVFlfSUNPTlNbc2V2ZXJpdHldIHx8IFwiXHVEODNEXHVERkUxXCI7XG5cdFx0bGluZXMucHVzaChgUnVsZTogJHtpY29ufSAke3J1bGUudGl0bGV9IFske3NldmVyaXR5fV1gKTtcblx0XHRpZiAocnVsZS5mcm9udG1hdHRlci5kZXNjcmlwdGlvbikge1xuXHRcdFx0bGluZXMucHVzaChgPiAke3J1bGUuZnJvbnRtYXR0ZXIuZGVzY3JpcHRpb259YCk7XG5cdFx0fVxuXHRcdGxpbmVzLnB1c2goXCJcIik7XG5cdFx0bGluZXMucHVzaChydWxlLmNvbnRlbnQpO1xuXHRcdGxpbmVzLnB1c2goXCJcIik7XG5cdH1cblxuXHRsaW5lcy5wdXNoKFwiPC9zeXN0ZW0tcmVtaW5kZXI+XCIpO1xuXHRyZXR1cm4gbGluZXMuam9pbihcIlxcblwiKTtcbn1cblxuZXhwb3J0IGNvbnN0IGJ1aWxkU3lzdGVtUHJvbXB0U2VjdGlvbiA9IGJ1aWxkU3lzdGVtUmVtaW5kZXJTZWN0aW9uO1xuZXhwb3J0IGNvbnN0IGJ1aWxkVG9vbENvbnRleHRTZWN0aW9uID0gYnVpbGRUb29sUmVtaW5kZXJTZWN0aW9uO1xuXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRDb21wYWN0Q29udGV4dChydWxlczogUGFyc2VkUnVsZVtdKTogc3RyaW5nIHtcblx0aWYgKHJ1bGVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFwiXCI7XG5cblx0Y29uc3QgbGluZXM6IHN0cmluZ1tdID0gW1wiIyMgQWN0aXZlIFJ1bGVzIChwZXJzaXN0IGFjcm9zcyBjb21wYWN0aW9uKVwiLCBcIlwiXTtcblxuXHRmb3IgKGNvbnN0IHJ1bGUgb2YgcnVsZXMpIHtcblx0XHRjb25zdCBkZXNjID0gcnVsZS5mcm9udG1hdHRlci5kZXNjcmlwdGlvbiB8fCBydWxlLmNvbnRlbnQuc3BsaXQoXCJcXG5cIilbMF07XG5cdFx0bGluZXMucHVzaChgLSAqKiR7cnVsZS50aXRsZX0qKiAoJHtydWxlLm5hbWV9KTogJHtkZXNjfWApO1xuXHR9XG5cblx0cmV0dXJuIGxpbmVzLmpvaW4oXCJcXG5cIik7XG59XG4iLCAiLy8gQSBzaW1wbGUgaW1wbGVtZW50YXRpb24gb2YgbWFrZS1hcnJheVxuZnVuY3Rpb24gbWFrZUFycmF5IChzdWJqZWN0KSB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KHN1YmplY3QpXG4gICAgPyBzdWJqZWN0XG4gICAgOiBbc3ViamVjdF1cbn1cblxuY29uc3QgVU5ERUZJTkVEID0gdW5kZWZpbmVkXG5jb25zdCBFTVBUWSA9ICcnXG5jb25zdCBTUEFDRSA9ICcgJ1xuY29uc3QgRVNDQVBFID0gJ1xcXFwnXG5jb25zdCBSRUdFWF9URVNUX0JMQU5LX0xJTkUgPSAvXlxccyskL1xuY29uc3QgUkVHRVhfSU5WQUxJRF9UUkFJTElOR19CQUNLU0xBU0ggPSAvKD86W15cXFxcXXxeKVxcXFwkL1xuY29uc3QgUkVHRVhfUkVQTEFDRV9MRUFESU5HX0VYQ0FQRURfRVhDTEFNQVRJT04gPSAvXlxcXFwhL1xuY29uc3QgUkVHRVhfUkVQTEFDRV9MRUFESU5HX0VYQ0FQRURfSEFTSCA9IC9eXFxcXCMvXG5jb25zdCBSRUdFWF9TUExJVEFMTF9DUkxGID0gL1xccj9cXG4vZ1xuXG4vLyBJbnZhbGlkOlxuLy8gLSAvZm9vLFxuLy8gLSAuL2Zvbyxcbi8vIC0gLi4vZm9vLFxuLy8gLSAuXG4vLyAtIC4uXG4vLyBWYWxpZDpcbi8vIC0gLmZvb1xuY29uc3QgUkVHRVhfVEVTVF9JTlZBTElEX1BBVEggPSAvXlxcLnswLDJ9XFwvfF5cXC57MSwyfSQvXG5cbmNvbnN0IFJFR0VYX1RFU1RfVFJBSUxJTkdfU0xBU0ggPSAvXFwvJC9cblxuY29uc3QgU0xBU0ggPSAnLydcblxuLy8gRG8gbm90IHVzZSB0ZXJuYXJ5IGV4cHJlc3Npb24gaGVyZSwgc2luY2UgXCJpc3RhbmJ1bCBpZ25vcmUgbmV4dFwiIGlzIGJ1Z2d5XG5sZXQgVE1QX0tFWV9JR05PUkUgPSAnbm9kZS1pZ25vcmUnXG4vKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqL1xuaWYgKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnKSB7XG4gIFRNUF9LRVlfSUdOT1JFID0gU3ltYm9sLmZvcignbm9kZS1pZ25vcmUnKVxufVxuY29uc3QgS0VZX0lHTk9SRSA9IFRNUF9LRVlfSUdOT1JFXG5cbmNvbnN0IGRlZmluZSA9IChvYmplY3QsIGtleSwgdmFsdWUpID0+IHtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwga2V5LCB7dmFsdWV9KVxuICByZXR1cm4gdmFsdWVcbn1cblxuY29uc3QgUkVHRVhfUkVHRVhQX1JBTkdFID0gLyhbMC16XSktKFswLXpdKS9nXG5cbmNvbnN0IFJFVFVSTl9GQUxTRSA9ICgpID0+IGZhbHNlXG5cbi8vIFNhbml0aXplIHRoZSByYW5nZSBvZiBhIHJlZ3VsYXIgZXhwcmVzc2lvblxuLy8gVGhlIGNhc2VzIGFyZSBjb21wbGljYXRlZCwgc2VlIHRlc3QgY2FzZXMgZm9yIGRldGFpbHNcbmNvbnN0IHNhbml0aXplUmFuZ2UgPSByYW5nZSA9PiByYW5nZS5yZXBsYWNlKFxuICBSRUdFWF9SRUdFWFBfUkFOR0UsXG4gIChtYXRjaCwgZnJvbSwgdG8pID0+IGZyb20uY2hhckNvZGVBdCgwKSA8PSB0by5jaGFyQ29kZUF0KDApXG4gICAgPyBtYXRjaFxuICAgIC8vIEludmFsaWQgcmFuZ2UgKG91dCBvZiBvcmRlcikgd2hpY2ggaXMgb2sgZm9yIGdpdGlnbm9yZSBydWxlcyBidXRcbiAgICAvLyAgIGZhdGFsIGZvciBKYXZhU2NyaXB0IHJlZ3VsYXIgZXhwcmVzc2lvbiwgc28gZWxpbWluYXRlIGl0LlxuICAgIDogRU1QVFlcbilcblxuLy8gU2VlIGZpeHR1cmVzICM1OVxuY29uc3QgY2xlYW5SYW5nZUJhY2tTbGFzaCA9IHNsYXNoZXMgPT4ge1xuICBjb25zdCB7bGVuZ3RofSA9IHNsYXNoZXNcbiAgcmV0dXJuIHNsYXNoZXMuc2xpY2UoMCwgbGVuZ3RoIC0gbGVuZ3RoICUgMilcbn1cblxuLy8gPiBJZiB0aGUgcGF0dGVybiBlbmRzIHdpdGggYSBzbGFzaCxcbi8vID4gaXQgaXMgcmVtb3ZlZCBmb3IgdGhlIHB1cnBvc2Ugb2YgdGhlIGZvbGxvd2luZyBkZXNjcmlwdGlvbixcbi8vID4gYnV0IGl0IHdvdWxkIG9ubHkgZmluZCBhIG1hdGNoIHdpdGggYSBkaXJlY3RvcnkuXG4vLyA+IEluIG90aGVyIHdvcmRzLCBmb28vIHdpbGwgbWF0Y2ggYSBkaXJlY3RvcnkgZm9vIGFuZCBwYXRocyB1bmRlcm5lYXRoIGl0LFxuLy8gPiBidXQgd2lsbCBub3QgbWF0Y2ggYSByZWd1bGFyIGZpbGUgb3IgYSBzeW1ib2xpYyBsaW5rIGZvb1xuLy8gPiAgKHRoaXMgaXMgY29uc2lzdGVudCB3aXRoIHRoZSB3YXkgaG93IHBhdGhzcGVjIHdvcmtzIGluIGdlbmVyYWwgaW4gR2l0KS5cbi8vICdgZm9vL2AnIHdpbGwgbm90IG1hdGNoIHJlZ3VsYXIgZmlsZSAnYGZvb2AnIG9yIHN5bWJvbGljIGxpbmsgJ2Bmb29gJ1xuLy8gLT4gaWdub3JlLXJ1bGVzIHdpbGwgbm90IGRlYWwgd2l0aCBpdCwgYmVjYXVzZSBpdCBjb3N0cyBleHRyYSBgZnMuc3RhdGAgY2FsbFxuLy8gICAgICB5b3UgY291bGQgdXNlIG9wdGlvbiBgbWFyazogdHJ1ZWAgd2l0aCBgZ2xvYmBcblxuLy8gJ2Bmb28vYCcgc2hvdWxkIG5vdCBjb250aW51ZSB3aXRoIHRoZSAnYC4uYCdcbmNvbnN0IFJFUExBQ0VSUyA9IFtcblxuICBbXG4gICAgLy8gUmVtb3ZlIEJPTVxuICAgIC8vIFRPRE86XG4gICAgLy8gT3RoZXIgc2ltaWxhciB6ZXJvLXdpZHRoIGNoYXJhY3RlcnM/XG4gICAgL15cXHVGRUZGLyxcbiAgICAoKSA9PiBFTVBUWVxuICBdLFxuXG4gIC8vID4gVHJhaWxpbmcgc3BhY2VzIGFyZSBpZ25vcmVkIHVubGVzcyB0aGV5IGFyZSBxdW90ZWQgd2l0aCBiYWNrc2xhc2ggKFwiXFxcIilcbiAgW1xuICAgIC8vIChhXFwgKSAtPiAoYSApXG4gICAgLy8gKGEgICkgLT4gKGEpXG4gICAgLy8gKGEgKSAtPiAoYSlcbiAgICAvLyAoYSBcXCApIC0+IChhICApXG4gICAgLygoPzpcXFxcXFxcXCkqPykoXFxcXD9cXHMrKSQvLFxuICAgIChfLCBtMSwgbTIpID0+IG0xICsgKFxuICAgICAgbTIuaW5kZXhPZignXFxcXCcpID09PSAwXG4gICAgICAgID8gU1BBQ0VcbiAgICAgICAgOiBFTVBUWVxuICAgIClcbiAgXSxcblxuICAvLyBSZXBsYWNlIChcXCApIHdpdGggJyAnXG4gIC8vIChcXCApIC0+ICcgJ1xuICAvLyAoXFxcXCApIC0+ICdcXFxcICdcbiAgLy8gKFxcXFxcXCApIC0+ICdcXFxcICdcbiAgW1xuICAgIC8oXFxcXCs/KVxccy9nLFxuICAgIChfLCBtMSkgPT4ge1xuICAgICAgY29uc3Qge2xlbmd0aH0gPSBtMVxuICAgICAgcmV0dXJuIG0xLnNsaWNlKDAsIGxlbmd0aCAtIGxlbmd0aCAlIDIpICsgU1BBQ0VcbiAgICB9XG4gIF0sXG5cbiAgLy8gRXNjYXBlIG1ldGFjaGFyYWN0ZXJzXG4gIC8vIHdoaWNoIGlzIHdyaXR0ZW4gZG93biBieSB1c2VycyBidXQgbWVhbnMgc3BlY2lhbCBmb3IgcmVndWxhciBleHByZXNzaW9ucy5cblxuICAvLyA+IFRoZXJlIGFyZSAxMiBjaGFyYWN0ZXJzIHdpdGggc3BlY2lhbCBtZWFuaW5nczpcbiAgLy8gPiAtIHRoZSBiYWNrc2xhc2ggXFwsXG4gIC8vID4gLSB0aGUgY2FyZXQgXixcbiAgLy8gPiAtIHRoZSBkb2xsYXIgc2lnbiAkLFxuICAvLyA+IC0gdGhlIHBlcmlvZCBvciBkb3QgLixcbiAgLy8gPiAtIHRoZSB2ZXJ0aWNhbCBiYXIgb3IgcGlwZSBzeW1ib2wgfCxcbiAgLy8gPiAtIHRoZSBxdWVzdGlvbiBtYXJrID8sXG4gIC8vID4gLSB0aGUgYXN0ZXJpc2sgb3Igc3RhciAqLFxuICAvLyA+IC0gdGhlIHBsdXMgc2lnbiArLFxuICAvLyA+IC0gdGhlIG9wZW5pbmcgcGFyZW50aGVzaXMgKCxcbiAgLy8gPiAtIHRoZSBjbG9zaW5nIHBhcmVudGhlc2lzICksXG4gIC8vID4gLSBhbmQgdGhlIG9wZW5pbmcgc3F1YXJlIGJyYWNrZXQgWyxcbiAgLy8gPiAtIHRoZSBvcGVuaW5nIGN1cmx5IGJyYWNlIHssXG4gIC8vID4gVGhlc2Ugc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBvZnRlbiBjYWxsZWQgXCJtZXRhY2hhcmFjdGVyc1wiLlxuICBbXG4gICAgL1tcXFxcJC58KisoKXteXS9nLFxuICAgIG1hdGNoID0+IGBcXFxcJHttYXRjaH1gXG4gIF0sXG5cbiAgW1xuICAgIC8vID4gYSBxdWVzdGlvbiBtYXJrICg/KSBtYXRjaGVzIGEgc2luZ2xlIGNoYXJhY3RlclxuICAgIC8oPyFcXFxcKVxcPy9nLFxuICAgICgpID0+ICdbXi9dJ1xuICBdLFxuXG4gIC8vIGxlYWRpbmcgc2xhc2hcbiAgW1xuXG4gICAgLy8gPiBBIGxlYWRpbmcgc2xhc2ggbWF0Y2hlcyB0aGUgYmVnaW5uaW5nIG9mIHRoZSBwYXRobmFtZS5cbiAgICAvLyA+IEZvciBleGFtcGxlLCBcIi8qLmNcIiBtYXRjaGVzIFwiY2F0LWZpbGUuY1wiIGJ1dCBub3QgXCJtb3ppbGxhLXNoYTEvc2hhMS5jXCIuXG4gICAgLy8gQSBsZWFkaW5nIHNsYXNoIG1hdGNoZXMgdGhlIGJlZ2lubmluZyBvZiB0aGUgcGF0aG5hbWVcbiAgICAvXlxcLy8sXG4gICAgKCkgPT4gJ14nXG4gIF0sXG5cbiAgLy8gcmVwbGFjZSBzcGVjaWFsIG1ldGFjaGFyYWN0ZXIgc2xhc2ggYWZ0ZXIgdGhlIGxlYWRpbmcgc2xhc2hcbiAgW1xuICAgIC9cXC8vZyxcbiAgICAoKSA9PiAnXFxcXC8nXG4gIF0sXG5cbiAgW1xuICAgIC8vID4gQSBsZWFkaW5nIFwiKipcIiBmb2xsb3dlZCBieSBhIHNsYXNoIG1lYW5zIG1hdGNoIGluIGFsbCBkaXJlY3Rvcmllcy5cbiAgICAvLyA+IEZvciBleGFtcGxlLCBcIioqL2Zvb1wiIG1hdGNoZXMgZmlsZSBvciBkaXJlY3RvcnkgXCJmb29cIiBhbnl3aGVyZSxcbiAgICAvLyA+IHRoZSBzYW1lIGFzIHBhdHRlcm4gXCJmb29cIi5cbiAgICAvLyA+IFwiKiovZm9vL2JhclwiIG1hdGNoZXMgZmlsZSBvciBkaXJlY3RvcnkgXCJiYXJcIiBhbnl3aGVyZSB0aGF0IGlzIGRpcmVjdGx5XG4gICAgLy8gPiAgIHVuZGVyIGRpcmVjdG9yeSBcImZvb1wiLlxuICAgIC8vIE5vdGljZSB0aGF0IHRoZSAnKidzIGhhdmUgYmVlbiByZXBsYWNlZCBhcyAnXFxcXConXG4gICAgL15cXF4qXFxcXFxcKlxcXFxcXCpcXFxcXFwvLyxcblxuICAgIC8vICcqKi9mb28nIDwtPiAnZm9vJ1xuICAgICgpID0+ICdeKD86LipcXFxcLyk/J1xuICBdLFxuXG4gIC8vIHN0YXJ0aW5nXG4gIFtcbiAgICAvLyB0aGVyZSB3aWxsIGJlIG5vIGxlYWRpbmcgJy8nXG4gICAgLy8gICAod2hpY2ggaGFzIGJlZW4gcmVwbGFjZWQgYnkgc2VjdGlvbiBcImxlYWRpbmcgc2xhc2hcIilcbiAgICAvLyBJZiBzdGFydHMgd2l0aCAnKionLCBhZGRpbmcgYSAnXicgdG8gdGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBhbHNvIHdvcmtzXG4gICAgL14oPz1bXl5dKS8sXG4gICAgZnVuY3Rpb24gc3RhcnRpbmdSZXBsYWNlciAoKSB7XG4gICAgICAvLyBJZiBoYXMgYSBzbGFzaCBgL2AgYXQgdGhlIGJlZ2lubmluZyBvciBtaWRkbGVcbiAgICAgIHJldHVybiAhL1xcLyg/ISQpLy50ZXN0KHRoaXMpXG4gICAgICAgIC8vID4gUHJpb3IgdG8gMi4yMi4xXG4gICAgICAgIC8vID4gSWYgdGhlIHBhdHRlcm4gZG9lcyBub3QgY29udGFpbiBhIHNsYXNoIC8sXG4gICAgICAgIC8vID4gICBHaXQgdHJlYXRzIGl0IGFzIGEgc2hlbGwgZ2xvYiBwYXR0ZXJuXG4gICAgICAgIC8vIEFjdHVhbGx5LCBpZiB0aGVyZSBpcyBvbmx5IGEgdHJhaWxpbmcgc2xhc2gsXG4gICAgICAgIC8vICAgZ2l0IGFsc28gdHJlYXRzIGl0IGFzIGEgc2hlbGwgZ2xvYiBwYXR0ZXJuXG5cbiAgICAgICAgLy8gQWZ0ZXIgMi4yMi4xIChjb21wYXRpYmxlIGJ1dCBjbGVhcmVyKVxuICAgICAgICAvLyA+IElmIHRoZXJlIGlzIGEgc2VwYXJhdG9yIGF0IHRoZSBiZWdpbm5pbmcgb3IgbWlkZGxlIChvciBib3RoKVxuICAgICAgICAvLyA+IG9mIHRoZSBwYXR0ZXJuLCB0aGVuIHRoZSBwYXR0ZXJuIGlzIHJlbGF0aXZlIHRvIHRoZSBkaXJlY3RvcnlcbiAgICAgICAgLy8gPiBsZXZlbCBvZiB0aGUgcGFydGljdWxhciAuZ2l0aWdub3JlIGZpbGUgaXRzZWxmLlxuICAgICAgICAvLyA+IE90aGVyd2lzZSB0aGUgcGF0dGVybiBtYXkgYWxzbyBtYXRjaCBhdCBhbnkgbGV2ZWwgYmVsb3dcbiAgICAgICAgLy8gPiB0aGUgLmdpdGlnbm9yZSBsZXZlbC5cbiAgICAgICAgPyAnKD86XnxcXFxcLyknXG5cbiAgICAgICAgLy8gPiBPdGhlcndpc2UsIEdpdCB0cmVhdHMgdGhlIHBhdHRlcm4gYXMgYSBzaGVsbCBnbG9iIHN1aXRhYmxlIGZvclxuICAgICAgICAvLyA+ICAgY29uc3VtcHRpb24gYnkgZm5tYXRjaCgzKVxuICAgICAgICA6ICdeJ1xuICAgIH1cbiAgXSxcblxuICAvLyB0d28gZ2xvYnN0YXJzXG4gIFtcbiAgICAvLyBVc2UgbG9va2FoZWFkIGFzc2VydGlvbnMgc28gdGhhdCB3ZSBjb3VsZCBtYXRjaCBtb3JlIHRoYW4gb25lIGAnLyoqJ2BcbiAgICAvXFxcXFxcL1xcXFxcXCpcXFxcXFwqKD89XFxcXFxcL3wkKS9nLFxuXG4gICAgLy8gWmVybywgb25lIG9yIHNldmVyYWwgZGlyZWN0b3JpZXNcbiAgICAvLyBzaG91bGQgbm90IHVzZSAnKicsIG9yIGl0IHdpbGwgYmUgcmVwbGFjZWQgYnkgdGhlIG5leHQgcmVwbGFjZXJcblxuICAgIC8vIENoZWNrIGlmIGl0IGlzIG5vdCB0aGUgbGFzdCBgJy8qKidgXG4gICAgKF8sIGluZGV4LCBzdHIpID0+IGluZGV4ICsgNiA8IHN0ci5sZW5ndGhcblxuICAgICAgLy8gY2FzZTogLyoqL1xuICAgICAgLy8gPiBBIHNsYXNoIGZvbGxvd2VkIGJ5IHR3byBjb25zZWN1dGl2ZSBhc3Rlcmlza3MgdGhlbiBhIHNsYXNoIG1hdGNoZXNcbiAgICAgIC8vID4gICB6ZXJvIG9yIG1vcmUgZGlyZWN0b3JpZXMuXG4gICAgICAvLyA+IEZvciBleGFtcGxlLCBcImEvKiovYlwiIG1hdGNoZXMgXCJhL2JcIiwgXCJhL3gvYlwiLCBcImEveC95L2JcIiBhbmQgc28gb24uXG4gICAgICAvLyAnLyoqLydcbiAgICAgID8gJyg/OlxcXFwvW15cXFxcL10rKSonXG5cbiAgICAgIC8vIGNhc2U6IC8qKlxuICAgICAgLy8gPiBBIHRyYWlsaW5nIGBcIi8qKlwiYCBtYXRjaGVzIGV2ZXJ5dGhpbmcgaW5zaWRlLlxuXG4gICAgICAvLyAjMjE6IGV2ZXJ5dGhpbmcgaW5zaWRlIGJ1dCBpdCBzaG91bGQgbm90IGluY2x1ZGUgdGhlIGN1cnJlbnQgZm9sZGVyXG4gICAgICA6ICdcXFxcLy4rJ1xuICBdLFxuXG4gIC8vIG5vcm1hbCBpbnRlcm1lZGlhdGUgd2lsZGNhcmRzXG4gIFtcbiAgICAvLyBOZXZlciByZXBsYWNlIGVzY2FwZWQgJyonXG4gICAgLy8gaWdub3JlIHJ1bGUgJ1xcKicgd2lsbCBtYXRjaCB0aGUgcGF0aCAnKidcblxuICAgIC8vICdhYmMuKi8nIC0+IGdvXG4gICAgLy8gJ2FiYy4qJyAgLT4gc2tpcCB0aGlzIHJ1bGUsXG4gICAgLy8gICAgY296IHRyYWlsaW5nIHNpbmdsZSB3aWxkY2FyZCB3aWxsIGJlIGhhbmRlZCBieSBbdHJhaWxpbmcgd2lsZGNhcmRdXG4gICAgLyhefFteXFxcXF0rKShcXFxcXFwqKSsoPz0uKykvZyxcblxuICAgIC8vICcqLmpzJyBtYXRjaGVzICcuanMnXG4gICAgLy8gJyouanMnIGRvZXNuJ3QgbWF0Y2ggJ2FiYydcbiAgICAoXywgcDEsIHAyKSA9PiB7XG4gICAgICAvLyAxLlxuICAgICAgLy8gPiBBbiBhc3RlcmlzayBcIipcIiBtYXRjaGVzIGFueXRoaW5nIGV4Y2VwdCBhIHNsYXNoLlxuICAgICAgLy8gMi5cbiAgICAgIC8vID4gT3RoZXIgY29uc2VjdXRpdmUgYXN0ZXJpc2tzIGFyZSBjb25zaWRlcmVkIHJlZ3VsYXIgYXN0ZXJpc2tzXG4gICAgICAvLyA+IGFuZCB3aWxsIG1hdGNoIGFjY29yZGluZyB0byB0aGUgcHJldmlvdXMgcnVsZXMuXG4gICAgICBjb25zdCB1bmVzY2FwZWQgPSBwMi5yZXBsYWNlKC9cXFxcXFwqL2csICdbXlxcXFwvXSonKVxuICAgICAgcmV0dXJuIHAxICsgdW5lc2NhcGVkXG4gICAgfVxuICBdLFxuXG4gIFtcbiAgICAvLyB1bmVzY2FwZSwgcmV2ZXJ0IHN0ZXAgMyBleGNlcHQgZm9yIGJhY2sgc2xhc2hcbiAgICAvLyBGb3IgZXhhbXBsZSwgaWYgYSB1c2VyIGVzY2FwZSBhICdcXFxcKicsXG4gICAgLy8gYWZ0ZXIgc3RlcCAzLCB0aGUgcmVzdWx0IHdpbGwgYmUgJ1xcXFxcXFxcXFxcXConXG4gICAgL1xcXFxcXFxcXFxcXCg/PVskLnwqKygpe15dKS9nLFxuICAgICgpID0+IEVTQ0FQRVxuICBdLFxuXG4gIFtcbiAgICAvLyAnXFxcXFxcXFwnIC0+ICdcXFxcJ1xuICAgIC9cXFxcXFxcXC9nLFxuICAgICgpID0+IEVTQ0FQRVxuICBdLFxuXG4gIFtcbiAgICAvLyA+IFRoZSByYW5nZSBub3RhdGlvbiwgZS5nLiBbYS16QS1aXSxcbiAgICAvLyA+IGNhbiBiZSB1c2VkIHRvIG1hdGNoIG9uZSBvZiB0aGUgY2hhcmFjdGVycyBpbiBhIHJhbmdlLlxuXG4gICAgLy8gYFxcYCBpcyBlc2NhcGVkIGJ5IHN0ZXAgM1xuICAgIC8oXFxcXCk/XFxbKFteXFxdL10qPykoXFxcXCopKCR8XFxdKS9nLFxuICAgIChtYXRjaCwgbGVhZEVzY2FwZSwgcmFuZ2UsIGVuZEVzY2FwZSwgY2xvc2UpID0+IGxlYWRFc2NhcGUgPT09IEVTQ0FQRVxuICAgICAgLy8gJ1xcXFxbYmFyXScgLT4gJ1xcXFxcXFxcW2JhclxcXFxdJ1xuICAgICAgPyBgXFxcXFske3JhbmdlfSR7Y2xlYW5SYW5nZUJhY2tTbGFzaChlbmRFc2NhcGUpfSR7Y2xvc2V9YFxuICAgICAgOiBjbG9zZSA9PT0gJ10nXG4gICAgICAgID8gZW5kRXNjYXBlLmxlbmd0aCAlIDIgPT09IDBcbiAgICAgICAgICAvLyBBIG5vcm1hbCBjYXNlLCBhbmQgaXQgaXMgYSByYW5nZSBub3RhdGlvblxuICAgICAgICAgIC8vICdbYmFyXSdcbiAgICAgICAgICAvLyAnW2JhclxcXFxcXFxcXSdcbiAgICAgICAgICA/IGBbJHtzYW5pdGl6ZVJhbmdlKHJhbmdlKX0ke2VuZEVzY2FwZX1dYFxuICAgICAgICAgIC8vIEludmFsaWQgcmFuZ2Ugbm90YXRvblxuICAgICAgICAgIC8vICdbYmFyXFxcXF0nIC0+ICdbYmFyXFxcXFxcXFxdJ1xuICAgICAgICAgIDogJ1tdJ1xuICAgICAgICA6ICdbXSdcbiAgXSxcblxuICAvLyBlbmRpbmdcbiAgW1xuICAgIC8vICdqcycgd2lsbCBub3QgbWF0Y2ggJ2pzLidcbiAgICAvLyAnYWInIHdpbGwgbm90IG1hdGNoICdhYmMnXG4gICAgLyg/OlteKl0pJC8sXG5cbiAgICAvLyBXVEYhXG4gICAgLy8gaHR0cHM6Ly9naXQtc2NtLmNvbS9kb2NzL2dpdGlnbm9yZVxuICAgIC8vIGNoYW5nZXMgaW4gWzIuMjIuMV0oaHR0cHM6Ly9naXQtc2NtLmNvbS9kb2NzL2dpdGlnbm9yZS8yLjIyLjEpXG4gICAgLy8gd2hpY2ggcmUtZml4ZXMgIzI0LCAjMzhcblxuICAgIC8vID4gSWYgdGhlcmUgaXMgYSBzZXBhcmF0b3IgYXQgdGhlIGVuZCBvZiB0aGUgcGF0dGVybiB0aGVuIHRoZSBwYXR0ZXJuXG4gICAgLy8gPiB3aWxsIG9ubHkgbWF0Y2ggZGlyZWN0b3JpZXMsIG90aGVyd2lzZSB0aGUgcGF0dGVybiBjYW4gbWF0Y2ggYm90aFxuICAgIC8vID4gZmlsZXMgYW5kIGRpcmVjdG9yaWVzLlxuXG4gICAgLy8gJ2pzKicgd2lsbCBub3QgbWF0Y2ggJ2EuanMnXG4gICAgLy8gJ2pzLycgd2lsbCBub3QgbWF0Y2ggJ2EuanMnXG4gICAgLy8gJ2pzJyB3aWxsIG1hdGNoICdhLmpzJyBhbmQgJ2EuanMvJ1xuICAgIG1hdGNoID0+IC9cXC8kLy50ZXN0KG1hdGNoKVxuICAgICAgLy8gZm9vLyB3aWxsIG5vdCBtYXRjaCAnZm9vJ1xuICAgICAgPyBgJHttYXRjaH0kYFxuICAgICAgLy8gZm9vIG1hdGNoZXMgJ2ZvbycgYW5kICdmb28vJ1xuICAgICAgOiBgJHttYXRjaH0oPz0kfFxcXFwvJClgXG4gIF1cbl1cblxuY29uc3QgUkVHRVhfUkVQTEFDRV9UUkFJTElOR19XSUxEQ0FSRCA9IC8oXnxcXFxcXFwvKT9cXFxcXFwqJC9cbmNvbnN0IE1PREVfSUdOT1JFID0gJ3JlZ2V4J1xuY29uc3QgTU9ERV9DSEVDS19JR05PUkUgPSAnY2hlY2tSZWdleCdcbmNvbnN0IFVOREVSU0NPUkUgPSAnXydcblxuY29uc3QgVFJBSUxJTkdfV0lMRF9DQVJEX1JFUExBQ0VSUyA9IHtcbiAgW01PREVfSUdOT1JFXSAoXywgcDEpIHtcbiAgICBjb25zdCBwcmVmaXggPSBwMVxuICAgICAgLy8gJ1xcXic6XG4gICAgICAvLyAnLyonIGRvZXMgbm90IG1hdGNoIEVNUFRZXG4gICAgICAvLyAnLyonIGRvZXMgbm90IG1hdGNoIGV2ZXJ5dGhpbmdcblxuICAgICAgLy8gJ1xcXFxcXC8nOlxuICAgICAgLy8gJ2FiYy8qJyBkb2VzIG5vdCBtYXRjaCAnYWJjLydcbiAgICAgID8gYCR7cDF9W14vXStgXG5cbiAgICAgIC8vICdhKicgbWF0Y2hlcyAnYSdcbiAgICAgIC8vICdhKicgbWF0Y2hlcyAnYWEnXG4gICAgICA6ICdbXi9dKidcblxuICAgIHJldHVybiBgJHtwcmVmaXh9KD89JHxcXFxcLyQpYFxuICB9LFxuXG4gIFtNT0RFX0NIRUNLX0lHTk9SRV0gKF8sIHAxKSB7XG4gICAgLy8gV2hlbiBkb2luZyBgZ2l0IGNoZWNrLWlnbm9yZWBcbiAgICBjb25zdCBwcmVmaXggPSBwMVxuICAgICAgLy8gJ1xcXFxcXC8nOlxuICAgICAgLy8gJ2FiYy8qJyBET0VTIG1hdGNoICdhYmMvJyAhXG4gICAgICA/IGAke3AxfVteL10qYFxuXG4gICAgICAvLyAnYSonIG1hdGNoZXMgJ2EnXG4gICAgICAvLyAnYSonIG1hdGNoZXMgJ2FhJ1xuICAgICAgOiAnW14vXSonXG5cbiAgICByZXR1cm4gYCR7cHJlZml4fSg/PSR8XFxcXC8kKWBcbiAgfVxufVxuXG4vLyBAcGFyYW0ge3BhdHRlcm59XG5jb25zdCBtYWtlUmVnZXhQcmVmaXggPSBwYXR0ZXJuID0+IFJFUExBQ0VSUy5yZWR1Y2UoXG4gIChwcmV2LCBbbWF0Y2hlciwgcmVwbGFjZXJdKSA9PlxuICAgIHByZXYucmVwbGFjZShtYXRjaGVyLCByZXBsYWNlci5iaW5kKHBhdHRlcm4pKSxcbiAgcGF0dGVyblxuKVxuXG5jb25zdCBpc1N0cmluZyA9IHN1YmplY3QgPT4gdHlwZW9mIHN1YmplY3QgPT09ICdzdHJpbmcnXG5cbi8vID4gQSBibGFuayBsaW5lIG1hdGNoZXMgbm8gZmlsZXMsIHNvIGl0IGNhbiBzZXJ2ZSBhcyBhIHNlcGFyYXRvciBmb3IgcmVhZGFiaWxpdHkuXG5jb25zdCBjaGVja1BhdHRlcm4gPSBwYXR0ZXJuID0+IHBhdHRlcm5cbiAgJiYgaXNTdHJpbmcocGF0dGVybilcbiAgJiYgIVJFR0VYX1RFU1RfQkxBTktfTElORS50ZXN0KHBhdHRlcm4pXG4gICYmICFSRUdFWF9JTlZBTElEX1RSQUlMSU5HX0JBQ0tTTEFTSC50ZXN0KHBhdHRlcm4pXG5cbiAgLy8gPiBBIGxpbmUgc3RhcnRpbmcgd2l0aCAjIHNlcnZlcyBhcyBhIGNvbW1lbnQuXG4gICYmIHBhdHRlcm4uaW5kZXhPZignIycpICE9PSAwXG5cbmNvbnN0IHNwbGl0UGF0dGVybiA9IHBhdHRlcm4gPT4gcGF0dGVyblxuLnNwbGl0KFJFR0VYX1NQTElUQUxMX0NSTEYpXG4uZmlsdGVyKEJvb2xlYW4pXG5cbmNsYXNzIElnbm9yZVJ1bGUge1xuICBjb25zdHJ1Y3RvciAoXG4gICAgcGF0dGVybixcbiAgICBtYXJrLFxuICAgIGJvZHksXG4gICAgaWdub3JlQ2FzZSxcbiAgICBuZWdhdGl2ZSxcbiAgICBwcmVmaXhcbiAgKSB7XG4gICAgdGhpcy5wYXR0ZXJuID0gcGF0dGVyblxuICAgIHRoaXMubWFyayA9IG1hcmtcbiAgICB0aGlzLm5lZ2F0aXZlID0gbmVnYXRpdmVcblxuICAgIGRlZmluZSh0aGlzLCAnYm9keScsIGJvZHkpXG4gICAgZGVmaW5lKHRoaXMsICdpZ25vcmVDYXNlJywgaWdub3JlQ2FzZSlcbiAgICBkZWZpbmUodGhpcywgJ3JlZ2V4UHJlZml4JywgcHJlZml4KVxuICB9XG5cbiAgZ2V0IHJlZ2V4ICgpIHtcbiAgICBjb25zdCBrZXkgPSBVTkRFUlNDT1JFICsgTU9ERV9JR05PUkVcblxuICAgIGlmICh0aGlzW2tleV0pIHtcbiAgICAgIHJldHVybiB0aGlzW2tleV1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fbWFrZShNT0RFX0lHTk9SRSwga2V5KVxuICB9XG5cbiAgZ2V0IGNoZWNrUmVnZXggKCkge1xuICAgIGNvbnN0IGtleSA9IFVOREVSU0NPUkUgKyBNT0RFX0NIRUNLX0lHTk9SRVxuXG4gICAgaWYgKHRoaXNba2V5XSkge1xuICAgICAgcmV0dXJuIHRoaXNba2V5XVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl9tYWtlKE1PREVfQ0hFQ0tfSUdOT1JFLCBrZXkpXG4gIH1cblxuICBfbWFrZSAobW9kZSwga2V5KSB7XG4gICAgY29uc3Qgc3RyID0gdGhpcy5yZWdleFByZWZpeC5yZXBsYWNlKFxuICAgICAgUkVHRVhfUkVQTEFDRV9UUkFJTElOR19XSUxEQ0FSRCxcblxuICAgICAgLy8gSXQgZG9lcyBub3QgbmVlZCB0byBiaW5kIHBhdHRlcm5cbiAgICAgIFRSQUlMSU5HX1dJTERfQ0FSRF9SRVBMQUNFUlNbbW9kZV1cbiAgICApXG5cbiAgICBjb25zdCByZWdleCA9IHRoaXMuaWdub3JlQ2FzZVxuICAgICAgPyBuZXcgUmVnRXhwKHN0ciwgJ2knKVxuICAgICAgOiBuZXcgUmVnRXhwKHN0cilcblxuICAgIHJldHVybiBkZWZpbmUodGhpcywga2V5LCByZWdleClcbiAgfVxufVxuXG5jb25zdCBjcmVhdGVSdWxlID0gKHtcbiAgcGF0dGVybixcbiAgbWFya1xufSwgaWdub3JlQ2FzZSkgPT4ge1xuICBsZXQgbmVnYXRpdmUgPSBmYWxzZVxuICBsZXQgYm9keSA9IHBhdHRlcm5cblxuICAvLyA+IEFuIG9wdGlvbmFsIHByZWZpeCBcIiFcIiB3aGljaCBuZWdhdGVzIHRoZSBwYXR0ZXJuO1xuICBpZiAoYm9keS5pbmRleE9mKCchJykgPT09IDApIHtcbiAgICBuZWdhdGl2ZSA9IHRydWVcbiAgICBib2R5ID0gYm9keS5zdWJzdHIoMSlcbiAgfVxuXG4gIGJvZHkgPSBib2R5XG4gIC8vID4gUHV0IGEgYmFja3NsYXNoIChcIlxcXCIpIGluIGZyb250IG9mIHRoZSBmaXJzdCBcIiFcIiBmb3IgcGF0dGVybnMgdGhhdFxuICAvLyA+ICAgYmVnaW4gd2l0aCBhIGxpdGVyYWwgXCIhXCIsIGZvciBleGFtcGxlLCBgXCJcXCFpbXBvcnRhbnQhLnR4dFwiYC5cbiAgLnJlcGxhY2UoUkVHRVhfUkVQTEFDRV9MRUFESU5HX0VYQ0FQRURfRVhDTEFNQVRJT04sICchJylcbiAgLy8gPiBQdXQgYSBiYWNrc2xhc2ggKFwiXFxcIikgaW4gZnJvbnQgb2YgdGhlIGZpcnN0IGhhc2ggZm9yIHBhdHRlcm5zIHRoYXRcbiAgLy8gPiAgIGJlZ2luIHdpdGggYSBoYXNoLlxuICAucmVwbGFjZShSRUdFWF9SRVBMQUNFX0xFQURJTkdfRVhDQVBFRF9IQVNILCAnIycpXG5cbiAgY29uc3QgcmVnZXhQcmVmaXggPSBtYWtlUmVnZXhQcmVmaXgoYm9keSlcblxuICByZXR1cm4gbmV3IElnbm9yZVJ1bGUoXG4gICAgcGF0dGVybixcbiAgICBtYXJrLFxuICAgIGJvZHksXG4gICAgaWdub3JlQ2FzZSxcbiAgICBuZWdhdGl2ZSxcbiAgICByZWdleFByZWZpeFxuICApXG59XG5cbmNsYXNzIFJ1bGVNYW5hZ2VyIHtcbiAgY29uc3RydWN0b3IgKGlnbm9yZUNhc2UpIHtcbiAgICB0aGlzLl9pZ25vcmVDYXNlID0gaWdub3JlQ2FzZVxuICAgIHRoaXMuX3J1bGVzID0gW11cbiAgfVxuXG4gIF9hZGQgKHBhdHRlcm4pIHtcbiAgICAvLyAjMzJcbiAgICBpZiAocGF0dGVybiAmJiBwYXR0ZXJuW0tFWV9JR05PUkVdKSB7XG4gICAgICB0aGlzLl9ydWxlcyA9IHRoaXMuX3J1bGVzLmNvbmNhdChwYXR0ZXJuLl9ydWxlcy5fcnVsZXMpXG4gICAgICB0aGlzLl9hZGRlZCA9IHRydWVcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGlmIChpc1N0cmluZyhwYXR0ZXJuKSkge1xuICAgICAgcGF0dGVybiA9IHtcbiAgICAgICAgcGF0dGVyblxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjaGVja1BhdHRlcm4ocGF0dGVybi5wYXR0ZXJuKSkge1xuICAgICAgY29uc3QgcnVsZSA9IGNyZWF0ZVJ1bGUocGF0dGVybiwgdGhpcy5faWdub3JlQ2FzZSlcbiAgICAgIHRoaXMuX2FkZGVkID0gdHJ1ZVxuICAgICAgdGhpcy5fcnVsZXMucHVzaChydWxlKVxuICAgIH1cbiAgfVxuXG4gIC8vIEBwYXJhbSB7QXJyYXk8c3RyaW5nPiB8IHN0cmluZyB8IElnbm9yZX0gcGF0dGVyblxuICBhZGQgKHBhdHRlcm4pIHtcbiAgICB0aGlzLl9hZGRlZCA9IGZhbHNlXG5cbiAgICBtYWtlQXJyYXkoXG4gICAgICBpc1N0cmluZyhwYXR0ZXJuKVxuICAgICAgICA/IHNwbGl0UGF0dGVybihwYXR0ZXJuKVxuICAgICAgICA6IHBhdHRlcm5cbiAgICApLmZvckVhY2godGhpcy5fYWRkLCB0aGlzKVxuXG4gICAgcmV0dXJuIHRoaXMuX2FkZGVkXG4gIH1cblxuICAvLyBUZXN0IG9uZSBzaW5nbGUgcGF0aCB3aXRob3V0IHJlY3Vyc2l2ZWx5IGNoZWNraW5nIHBhcmVudCBkaXJlY3Rvcmllc1xuICAvL1xuICAvLyAtIGNoZWNrVW5pZ25vcmVkIGBib29sZWFuYCB3aGV0aGVyIHNob3VsZCBjaGVjayBpZiB0aGUgcGF0aCBpcyB1bmlnbm9yZWQsXG4gIC8vICAgc2V0dGluZyBgY2hlY2tVbmlnbm9yZWRgIHRvIGBmYWxzZWAgY291bGQgcmVkdWNlIGFkZGl0aW9uYWxcbiAgLy8gICBwYXRoIG1hdGNoaW5nLlxuICAvLyAtIGNoZWNrIGBzdHJpbmdgIGVpdGhlciBgTU9ERV9JR05PUkVgIG9yIGBNT0RFX0NIRUNLX0lHTk9SRWBcblxuICAvLyBAcmV0dXJucyB7VGVzdFJlc3VsdH0gdHJ1ZSBpZiBhIGZpbGUgaXMgaWdub3JlZFxuICB0ZXN0IChwYXRoLCBjaGVja1VuaWdub3JlZCwgbW9kZSkge1xuICAgIGxldCBpZ25vcmVkID0gZmFsc2VcbiAgICBsZXQgdW5pZ25vcmVkID0gZmFsc2VcbiAgICBsZXQgbWF0Y2hlZFJ1bGVcblxuICAgIHRoaXMuX3J1bGVzLmZvckVhY2gocnVsZSA9PiB7XG4gICAgICBjb25zdCB7bmVnYXRpdmV9ID0gcnVsZVxuXG4gICAgICAvLyAgICAgICAgICB8ICAgICAgICAgICBpZ25vcmVkIDogdW5pZ25vcmVkXG4gICAgICAvLyAtLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgLy8gbmVnYXRpdmUgfCAgIDA6MCAgIHwgICAwOjEgICB8ICAgMTowICAgfCAgIDE6MVxuICAgICAgLy8gLS0tLS0tLS0gfCAtLS0tLS0tIHwgLS0tLS0tLSB8IC0tLS0tLS0gfCAtLS0tLS0tLVxuICAgICAgLy8gICAgIDAgICAgfCAgVEVTVCAgIHwgIFRFU1QgICB8ICBTS0lQICAgfCAgICBYXG4gICAgICAvLyAgICAgMSAgICB8ICBURVNUSUYgfCAgU0tJUCAgIHwgIFRFU1QgICB8ICAgIFhcblxuICAgICAgLy8gLSBTS0lQOiBhbHdheXMgc2tpcFxuICAgICAgLy8gLSBURVNUOiBhbHdheXMgdGVzdFxuICAgICAgLy8gLSBURVNUSUY6IG9ubHkgdGVzdCBpZiBjaGVja1VuaWdub3JlZFxuICAgICAgLy8gLSBYOiB0aGF0IG5ldmVyIGhhcHBlblxuICAgICAgaWYgKFxuICAgICAgICB1bmlnbm9yZWQgPT09IG5lZ2F0aXZlICYmIGlnbm9yZWQgIT09IHVuaWdub3JlZFxuICAgICAgICB8fCBuZWdhdGl2ZSAmJiAhaWdub3JlZCAmJiAhdW5pZ25vcmVkICYmICFjaGVja1VuaWdub3JlZFxuICAgICAgKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCBtYXRjaGVkID0gcnVsZVttb2RlXS50ZXN0KHBhdGgpXG5cbiAgICAgIGlmICghbWF0Y2hlZCkge1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgaWdub3JlZCA9ICFuZWdhdGl2ZVxuICAgICAgdW5pZ25vcmVkID0gbmVnYXRpdmVcblxuICAgICAgbWF0Y2hlZFJ1bGUgPSBuZWdhdGl2ZVxuICAgICAgICA/IFVOREVGSU5FRFxuICAgICAgICA6IHJ1bGVcbiAgICB9KVxuXG4gICAgY29uc3QgcmV0ID0ge1xuICAgICAgaWdub3JlZCxcbiAgICAgIHVuaWdub3JlZFxuICAgIH1cblxuICAgIGlmIChtYXRjaGVkUnVsZSkge1xuICAgICAgcmV0LnJ1bGUgPSBtYXRjaGVkUnVsZVxuICAgIH1cblxuICAgIHJldHVybiByZXRcbiAgfVxufVxuXG5jb25zdCB0aHJvd0Vycm9yID0gKG1lc3NhZ2UsIEN0b3IpID0+IHtcbiAgdGhyb3cgbmV3IEN0b3IobWVzc2FnZSlcbn1cblxuY29uc3QgY2hlY2tQYXRoID0gKHBhdGgsIG9yaWdpbmFsUGF0aCwgZG9UaHJvdykgPT4ge1xuICBpZiAoIWlzU3RyaW5nKHBhdGgpKSB7XG4gICAgcmV0dXJuIGRvVGhyb3coXG4gICAgICBgcGF0aCBtdXN0IGJlIGEgc3RyaW5nLCBidXQgZ290IFxcYCR7b3JpZ2luYWxQYXRofVxcYGAsXG4gICAgICBUeXBlRXJyb3JcbiAgICApXG4gIH1cblxuICAvLyBXZSBkb24ndCBrbm93IGlmIHdlIHNob3VsZCBpZ25vcmUgRU1QVFksIHNvIHRocm93XG4gIGlmICghcGF0aCkge1xuICAgIHJldHVybiBkb1Rocm93KGBwYXRoIG11c3Qgbm90IGJlIGVtcHR5YCwgVHlwZUVycm9yKVxuICB9XG5cbiAgLy8gQ2hlY2sgaWYgaXQgaXMgYSByZWxhdGl2ZSBwYXRoXG4gIGlmIChjaGVja1BhdGguaXNOb3RSZWxhdGl2ZShwYXRoKSkge1xuICAgIGNvbnN0IHIgPSAnYHBhdGgucmVsYXRpdmUoKWBkJ1xuICAgIHJldHVybiBkb1Rocm93KFxuICAgICAgYHBhdGggc2hvdWxkIGJlIGEgJHtyfSBzdHJpbmcsIGJ1dCBnb3QgXCIke29yaWdpbmFsUGF0aH1cImAsXG4gICAgICBSYW5nZUVycm9yXG4gICAgKVxuICB9XG5cbiAgcmV0dXJuIHRydWVcbn1cblxuY29uc3QgaXNOb3RSZWxhdGl2ZSA9IHBhdGggPT4gUkVHRVhfVEVTVF9JTlZBTElEX1BBVEgudGVzdChwYXRoKVxuXG5jaGVja1BhdGguaXNOb3RSZWxhdGl2ZSA9IGlzTm90UmVsYXRpdmVcblxuLy8gT24gd2luZG93cywgdGhlIGZvbGxvd2luZyBmdW5jdGlvbiB3aWxsIGJlIHJlcGxhY2VkXG4vKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuY2hlY2tQYXRoLmNvbnZlcnQgPSBwID0+IHBcblxuXG5jbGFzcyBJZ25vcmUge1xuICBjb25zdHJ1Y3RvciAoe1xuICAgIGlnbm9yZWNhc2UgPSB0cnVlLFxuICAgIGlnbm9yZUNhc2UgPSBpZ25vcmVjYXNlLFxuICAgIGFsbG93UmVsYXRpdmVQYXRocyA9IGZhbHNlXG4gIH0gPSB7fSkge1xuICAgIGRlZmluZSh0aGlzLCBLRVlfSUdOT1JFLCB0cnVlKVxuXG4gICAgdGhpcy5fcnVsZXMgPSBuZXcgUnVsZU1hbmFnZXIoaWdub3JlQ2FzZSlcbiAgICB0aGlzLl9zdHJpY3RQYXRoQ2hlY2sgPSAhYWxsb3dSZWxhdGl2ZVBhdGhzXG4gICAgdGhpcy5faW5pdENhY2hlKClcbiAgfVxuXG4gIF9pbml0Q2FjaGUgKCkge1xuICAgIC8vIEEgY2FjaGUgZm9yIHRoZSByZXN1bHQgb2YgYC5pZ25vcmVzKClgXG4gICAgdGhpcy5faWdub3JlQ2FjaGUgPSBPYmplY3QuY3JlYXRlKG51bGwpXG5cbiAgICAvLyBBIGNhY2hlIGZvciB0aGUgcmVzdWx0IG9mIGAudGVzdCgpYFxuICAgIHRoaXMuX3Rlc3RDYWNoZSA9IE9iamVjdC5jcmVhdGUobnVsbClcbiAgfVxuXG4gIGFkZCAocGF0dGVybikge1xuICAgIGlmICh0aGlzLl9ydWxlcy5hZGQocGF0dGVybikpIHtcbiAgICAgIC8vIFNvbWUgcnVsZXMgaGF2ZSBqdXN0IGFkZGVkIHRvIHRoZSBpZ25vcmUsXG4gICAgICAvLyAgIG1ha2luZyB0aGUgYmVoYXZpb3IgY2hhbmdlZCxcbiAgICAgIC8vICAgc28gd2UgbmVlZCB0byByZS1pbml0aWFsaXplIHRoZSByZXN1bHQgY2FjaGVcbiAgICAgIHRoaXMuX2luaXRDYWNoZSgpXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8vIGxlZ2FjeVxuICBhZGRQYXR0ZXJuIChwYXR0ZXJuKSB7XG4gICAgcmV0dXJuIHRoaXMuYWRkKHBhdHRlcm4pXG4gIH1cblxuICAvLyBAcmV0dXJucyB7VGVzdFJlc3VsdH1cbiAgX3Rlc3QgKG9yaWdpbmFsUGF0aCwgY2FjaGUsIGNoZWNrVW5pZ25vcmVkLCBzbGljZXMpIHtcbiAgICBjb25zdCBwYXRoID0gb3JpZ2luYWxQYXRoXG4gICAgICAvLyBTdXBwb3J0cyBudWxsYWJsZSBwYXRoXG4gICAgICAmJiBjaGVja1BhdGguY29udmVydChvcmlnaW5hbFBhdGgpXG5cbiAgICBjaGVja1BhdGgoXG4gICAgICBwYXRoLFxuICAgICAgb3JpZ2luYWxQYXRoLFxuICAgICAgdGhpcy5fc3RyaWN0UGF0aENoZWNrXG4gICAgICAgID8gdGhyb3dFcnJvclxuICAgICAgICA6IFJFVFVSTl9GQUxTRVxuICAgIClcblxuICAgIHJldHVybiB0aGlzLl90KHBhdGgsIGNhY2hlLCBjaGVja1VuaWdub3JlZCwgc2xpY2VzKVxuICB9XG5cbiAgY2hlY2tJZ25vcmUgKHBhdGgpIHtcbiAgICAvLyBJZiB0aGUgcGF0aCBkb2VzdCBub3QgZW5kIHdpdGggYSBzbGFzaCwgYC5pZ25vcmVzKClgIGlzIG11Y2ggZXF1aXZhbGVudFxuICAgIC8vICAgdG8gYGdpdCBjaGVjay1pZ25vcmVgXG4gICAgaWYgKCFSRUdFWF9URVNUX1RSQUlMSU5HX1NMQVNILnRlc3QocGF0aCkpIHtcbiAgICAgIHJldHVybiB0aGlzLnRlc3QocGF0aClcbiAgICB9XG5cbiAgICBjb25zdCBzbGljZXMgPSBwYXRoLnNwbGl0KFNMQVNIKS5maWx0ZXIoQm9vbGVhbilcbiAgICBzbGljZXMucG9wKClcblxuICAgIGlmIChzbGljZXMubGVuZ3RoKSB7XG4gICAgICBjb25zdCBwYXJlbnQgPSB0aGlzLl90KFxuICAgICAgICBzbGljZXMuam9pbihTTEFTSCkgKyBTTEFTSCxcbiAgICAgICAgdGhpcy5fdGVzdENhY2hlLFxuICAgICAgICB0cnVlLFxuICAgICAgICBzbGljZXNcbiAgICAgIClcblxuICAgICAgaWYgKHBhcmVudC5pZ25vcmVkKSB7XG4gICAgICAgIHJldHVybiBwYXJlbnRcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fcnVsZXMudGVzdChwYXRoLCBmYWxzZSwgTU9ERV9DSEVDS19JR05PUkUpXG4gIH1cblxuICBfdCAoXG4gICAgLy8gVGhlIHBhdGggdG8gYmUgdGVzdGVkXG4gICAgcGF0aCxcblxuICAgIC8vIFRoZSBjYWNoZSBmb3IgdGhlIHJlc3VsdCBvZiBhIGNlcnRhaW4gY2hlY2tpbmdcbiAgICBjYWNoZSxcblxuICAgIC8vIFdoZXRoZXIgc2hvdWxkIGNoZWNrIGlmIHRoZSBwYXRoIGlzIHVuaWdub3JlZFxuICAgIGNoZWNrVW5pZ25vcmVkLFxuXG4gICAgLy8gVGhlIHBhdGggc2xpY2VzXG4gICAgc2xpY2VzXG4gICkge1xuICAgIGlmIChwYXRoIGluIGNhY2hlKSB7XG4gICAgICByZXR1cm4gY2FjaGVbcGF0aF1cbiAgICB9XG5cbiAgICBpZiAoIXNsaWNlcykge1xuICAgICAgLy8gcGF0aC90by9hLmpzXG4gICAgICAvLyBbJ3BhdGgnLCAndG8nLCAnYS5qcyddXG4gICAgICBzbGljZXMgPSBwYXRoLnNwbGl0KFNMQVNIKS5maWx0ZXIoQm9vbGVhbilcbiAgICB9XG5cbiAgICBzbGljZXMucG9wKClcblxuICAgIC8vIElmIHRoZSBwYXRoIGhhcyBubyBwYXJlbnQgZGlyZWN0b3J5LCBqdXN0IHRlc3QgaXRcbiAgICBpZiAoIXNsaWNlcy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBjYWNoZVtwYXRoXSA9IHRoaXMuX3J1bGVzLnRlc3QocGF0aCwgY2hlY2tVbmlnbm9yZWQsIE1PREVfSUdOT1JFKVxuICAgIH1cblxuICAgIGNvbnN0IHBhcmVudCA9IHRoaXMuX3QoXG4gICAgICBzbGljZXMuam9pbihTTEFTSCkgKyBTTEFTSCxcbiAgICAgIGNhY2hlLFxuICAgICAgY2hlY2tVbmlnbm9yZWQsXG4gICAgICBzbGljZXNcbiAgICApXG5cbiAgICAvLyBJZiB0aGUgcGF0aCBjb250YWlucyBhIHBhcmVudCBkaXJlY3RvcnksIGNoZWNrIHRoZSBwYXJlbnQgZmlyc3RcbiAgICByZXR1cm4gY2FjaGVbcGF0aF0gPSBwYXJlbnQuaWdub3JlZFxuICAgICAgLy8gPiBJdCBpcyBub3QgcG9zc2libGUgdG8gcmUtaW5jbHVkZSBhIGZpbGUgaWYgYSBwYXJlbnQgZGlyZWN0b3J5IG9mXG4gICAgICAvLyA+ICAgdGhhdCBmaWxlIGlzIGV4Y2x1ZGVkLlxuICAgICAgPyBwYXJlbnRcbiAgICAgIDogdGhpcy5fcnVsZXMudGVzdChwYXRoLCBjaGVja1VuaWdub3JlZCwgTU9ERV9JR05PUkUpXG4gIH1cblxuICBpZ25vcmVzIChwYXRoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Rlc3QocGF0aCwgdGhpcy5faWdub3JlQ2FjaGUsIGZhbHNlKS5pZ25vcmVkXG4gIH1cblxuICBjcmVhdGVGaWx0ZXIgKCkge1xuICAgIHJldHVybiBwYXRoID0+ICF0aGlzLmlnbm9yZXMocGF0aClcbiAgfVxuXG4gIGZpbHRlciAocGF0aHMpIHtcbiAgICByZXR1cm4gbWFrZUFycmF5KHBhdGhzKS5maWx0ZXIodGhpcy5jcmVhdGVGaWx0ZXIoKSlcbiAgfVxuXG4gIC8vIEByZXR1cm5zIHtUZXN0UmVzdWx0fVxuICB0ZXN0IChwYXRoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Rlc3QocGF0aCwgdGhpcy5fdGVzdENhY2hlLCB0cnVlKVxuICB9XG59XG5cbmNvbnN0IGZhY3RvcnkgPSBvcHRpb25zID0+IG5ldyBJZ25vcmUob3B0aW9ucylcblxuY29uc3QgaXNQYXRoVmFsaWQgPSBwYXRoID0+XG4gIGNoZWNrUGF0aChwYXRoICYmIGNoZWNrUGF0aC5jb252ZXJ0KHBhdGgpLCBwYXRoLCBSRVRVUk5fRkFMU0UpXG5cbi8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG5jb25zdCBzZXR1cFdpbmRvd3MgPSAoKSA9PiB7XG4gIC8qIGVzbGludCBuby1jb250cm9sLXJlZ2V4OiBcIm9mZlwiICovXG4gIGNvbnN0IG1ha2VQb3NpeCA9IHN0ciA9PiAvXlxcXFxcXFxcXFw/XFxcXC8udGVzdChzdHIpXG4gIHx8IC9bXCI8PnxcXHUwMDAwLVxcdTAwMUZdKy91LnRlc3Qoc3RyKVxuICAgID8gc3RyXG4gICAgOiBzdHIucmVwbGFjZSgvXFxcXC9nLCAnLycpXG5cbiAgY2hlY2tQYXRoLmNvbnZlcnQgPSBtYWtlUG9zaXhcblxuICAvLyAnQzpcXFxcZm9vJyAgICAgPC0gJ0M6XFxcXGZvbycgaGFzIGJlZW4gY29udmVydGVkIHRvICdDOi8nXG4gIC8vICdkOlxcXFxmb28nXG4gIGNvbnN0IFJFR0VYX1RFU1RfV0lORE9XU19QQVRIX0FCU09MVVRFID0gL15bYS16XTpcXC8vaVxuICBjaGVja1BhdGguaXNOb3RSZWxhdGl2ZSA9IHBhdGggPT5cbiAgICBSRUdFWF9URVNUX1dJTkRPV1NfUEFUSF9BQlNPTFVURS50ZXN0KHBhdGgpXG4gICAgfHwgaXNOb3RSZWxhdGl2ZShwYXRoKVxufVxuXG5cbi8vIFdpbmRvd3Ncbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuaWYgKFxuICAvLyBEZXRlY3QgYHByb2Nlc3NgIHNvIHRoYXQgaXQgY2FuIHJ1biBpbiBicm93c2Vycy5cbiAgdHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnXG4gICYmIHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMidcbikge1xuICBzZXR1cFdpbmRvd3MoKVxufVxuXG4vLyBDT01NT05KU19FWFBPUlRTIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnlcblxuLy8gQWx0aG91Z2ggaXQgaXMgYW4gYW50aS1wYXR0ZXJuLFxuLy8gICBpdCBpcyBzdGlsbCB3aWRlbHkgbWlzdXNlZCBieSBhIGxvdCBvZiBsaWJyYXJpZXMgaW4gZ2l0aHViXG4vLyBSZWY6IGh0dHBzOi8vZ2l0aHViLmNvbS9zZWFyY2g/cT1pZ25vcmUuZGVmYXVsdCUyOCUyOSZ0eXBlPWNvZGVcbmZhY3RvcnkuZGVmYXVsdCA9IGZhY3RvcnlcblxubW9kdWxlLmV4cG9ydHMuaXNQYXRoVmFsaWQgPSBpc1BhdGhWYWxpZFxuXG4vLyBGb3IgdGVzdGluZyBwdXJwb3Nlc1xuZGVmaW5lKG1vZHVsZS5leHBvcnRzLCBTeW1ib2wuZm9yKCdzZXR1cFdpbmRvd3MnKSwgc2V0dXBXaW5kb3dzKVxuIiwgImltcG9ydCBpZ25vcmUgZnJvbSBcImlnbm9yZVwiO1xuXG5mdW5jdGlvbiBleHBhbmRCcmFjZXMocGF0dGVybjogc3RyaW5nKTogc3RyaW5nW10ge1xuXHRjb25zdCBicmFjZUluZGV4ID0gcGF0dGVybi5pbmRleE9mKFwie1wiKTtcblx0aWYgKGJyYWNlSW5kZXggPT09IC0xKSByZXR1cm4gW3BhdHRlcm5dO1xuXHRjb25zdCBjbG9zZUluZGV4ID0gcGF0dGVybi5pbmRleE9mKFwifVwiLCBicmFjZUluZGV4KTtcblx0aWYgKGNsb3NlSW5kZXggPT09IC0xKSByZXR1cm4gW3BhdHRlcm5dO1xuXG5cdGNvbnN0IHByZWZpeCA9IHBhdHRlcm4uc2xpY2UoMCwgYnJhY2VJbmRleCk7XG5cdGNvbnN0IHN1ZmZpeCA9IHBhdHRlcm4uc2xpY2UoY2xvc2VJbmRleCArIDEpO1xuXHRjb25zdCBvcHRpb25zID0gcGF0dGVybi5zbGljZShicmFjZUluZGV4ICsgMSwgY2xvc2VJbmRleCkuc3BsaXQoXCIsXCIpO1xuXG5cdGNvbnN0IHJlc3VsdHM6IHN0cmluZ1tdID0gW107XG5cdGZvciAoY29uc3Qgb3B0IG9mIG9wdGlvbnMpIHtcblx0XHRyZXN1bHRzLnB1c2goLi4uZXhwYW5kQnJhY2VzKHByZWZpeCArIG9wdC50cmltKCkgKyBzdWZmaXgpKTtcblx0fVxuXHRyZXR1cm4gcmVzdWx0cztcbn1cblxuZnVuY3Rpb24gZXhwYW5kUGF0dGVybnMocGF0dGVybnM6IHN0cmluZ1tdKTogc3RyaW5nW10ge1xuXHRjb25zdCBleHBhbmRlZDogc3RyaW5nW10gPSBbXTtcblx0Zm9yIChjb25zdCBwIG9mIHBhdHRlcm5zKSB7XG5cdFx0ZXhwYW5kZWQucHVzaCguLi5leHBhbmRCcmFjZXMocCkpO1xuXHR9XG5cdHJldHVybiBleHBhbmRlZDtcbn1cblxuZnVuY3Rpb24gdG9SZWxhdGl2ZShmaWxlUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcblx0Y29uc3Qgbm9ybWFsaXplZCA9IGZpbGVQYXRoLnJlcGxhY2UoL1xcXFwvZywgXCIvXCIpO1xuXHRyZXR1cm4gbm9ybWFsaXplZC5zdGFydHNXaXRoKFwiL1wiKSA/IG5vcm1hbGl6ZWQuc2xpY2UoMSkgOiBub3JtYWxpemVkO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbWF0Y2hHbG9iKHBhdHRlcm46IHN0cmluZywgdGFyZ2V0OiBzdHJpbmcpOiBib29sZWFuIHtcblx0aWYgKCFwYXR0ZXJuIHx8ICF0YXJnZXQpIHJldHVybiBmYWxzZTtcblx0Y29uc3QgZXhwYW5kZWQgPSBleHBhbmRCcmFjZXMocGF0dGVybik7XG5cdGNvbnN0IGlnID0gaWdub3JlKCkuYWRkKGV4cGFuZGVkKTtcblx0cmV0dXJuIGlnLmlnbm9yZXModG9SZWxhdGl2ZSh0YXJnZXQpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG1hdGNoZXNBbnlHbG9iKGdsb2JzOiBzdHJpbmdbXSwgZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuXHRpZiAoIWZpbGVQYXRoIHx8IGdsb2JzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuXHRjb25zdCBleHBhbmRlZCA9IGV4cGFuZFBhdHRlcm5zKGdsb2JzKTtcblx0Y29uc3QgaWcgPSBpZ25vcmUoKS5hZGQoZXhwYW5kZWQpO1xuXHRyZXR1cm4gaWcuaWdub3Jlcyh0b1JlbGF0aXZlKGZpbGVQYXRoKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNYXRjaGVyKGdsb2JzOiBzdHJpbmdbXSk6IChmaWxlUGF0aDogc3RyaW5nKSA9PiBib29sZWFuIHtcblx0aWYgKGdsb2JzLmxlbmd0aCA9PT0gMCkgcmV0dXJuICgpID0+IGZhbHNlO1xuXHRjb25zdCBleHBhbmRlZCA9IGV4cGFuZFBhdHRlcm5zKGdsb2JzKTtcblx0Y29uc3QgaWcgPSBpZ25vcmUoKS5hZGQoZXhwYW5kZWQpO1xuXHRyZXR1cm4gKGZpbGVQYXRoOiBzdHJpbmcpID0+IGlnLmlnbm9yZXModG9SZWxhdGl2ZShmaWxlUGF0aCkpO1xufVxuIiwgImV4cG9ydCB0eXBlIFJ1bGVTZXZlcml0eSA9IFwiY3JpdGljYWxcIiB8IFwiaGlnaFwiIHwgXCJtZWRpdW1cIiB8IFwibG93XCIgfCBcImhpbnRcIjtcblxuZXhwb3J0IHR5cGUgUnVsZVNjb3BlID0gXCJ1c2VyXCIgfCBcInBpXCIgfCBcInByb2plY3RcIiB8IFwibWFuYWdlZFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVGcm9udG1hdHRlciB7XG5cdGdsb2JzPzogc3RyaW5nW107XG5cdHBhdGhzPzogc3RyaW5nW107XG5cdGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXHRzZXZlcml0eT86IFJ1bGVTZXZlcml0eTtcblx0YWxsb3dlZFRvb2xzPzogc3RyaW5nW107XG5cdHdoZW5Ub1VzZT86IHN0cmluZztcblx0dmVyc2lvbj86IHN0cmluZztcblx0bW9kZWw/OiBzdHJpbmc7XG5cdHNraWxscz86IHN0cmluZztcblx0ZWZmb3J0Pzogc3RyaW5nO1xuXHR1c2VySW52b2NhYmxlPzogc3RyaW5nO1xuXHRjb250ZXh0PzogXCJpbmxpbmVcIiB8IFwiZm9ya1wiO1xuXHRhZ2VudD86IHN0cmluZztcblx0c2hlbGw/OiBzdHJpbmc7XG5cdG5vdGlmeU9uTWF0Y2g/OiBib29sZWFuO1xuXHRza2lwSW5Qcm9tcHQ/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZFJ1bGUge1xuXHRuYW1lOiBzdHJpbmc7XG5cdGZpbGVQYXRoOiBzdHJpbmc7XG5cdHRpdGxlOiBzdHJpbmc7XG5cdGNvbnRlbnQ6IHN0cmluZztcblx0c2NvcGU6IFJ1bGVTY29wZTtcblx0c291cmNlOiBzdHJpbmc7XG5cdGZyb250bWF0dGVyOiBSdWxlRnJvbnRtYXR0ZXI7XG5cdGlzVW5jb25kaXRpb25hbDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSdWxlQ2FjaGUge1xuXHRydWxlczogUGFyc2VkUnVsZVtdO1xuXHR1bmNvbmRpdGlvbmFsOiBQYXJzZWRSdWxlW107XG5cdGNvbmRpdGlvbmFsOiBQYXJzZWRSdWxlW107XG5cdGxvYWRlZEF0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVkUnVsZXMge1xuXHRydWxlczogUGFyc2VkUnVsZVtdO1xuXHRsb2FkZWRBdDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVzQ29uZmlnIHtcblx0Y2FjaGVUVEw6IG51bWJlcjtcblx0bm90aWZ5T25Mb2FkOiBib29sZWFuO1xuXHRub3RpZnlPbk1hdGNoOiBib29sZWFuO1xuXHRkaXJzPzoge1xuXHRcdHVzZXI/OiBzdHJpbmdbXTtcblx0XHRwaT86IHN0cmluZ1tdO1xuXHRcdHByb2plY3Q/OiBzdHJpbmdbXTtcblx0XHRtYW5hZ2VkPzogc3RyaW5nW107XG5cdH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUnVsZURldGFpbCB7XG5cdG5hbWU6IHN0cmluZztcblx0dGl0bGU6IHN0cmluZztcblx0ZmlsZVBhdGg6IHN0cmluZztcblx0c2NvcGU6IFJ1bGVTY29wZTtcblx0c291cmNlOiBzdHJpbmc7XG5cdHNldmVyaXR5OiBSdWxlU2V2ZXJpdHk7XG5cdGlzVW5jb25kaXRpb25hbDogYm9vbGVhbjtcblx0Z2xvYnM6IHN0cmluZ1tdO1xuXHRkZXNjcmlwdGlvbj86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTY2FubmVkRGlyIHtcblx0ZGlyOiBzdHJpbmc7XG5cdGZpbGVDb3VudDogbnVtYmVyO1xuXHRydWxlTmFtZXM6IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1hdGNoZWRSdWxlRGV0YWlsIHtcblx0bmFtZTogc3RyaW5nO1xuXHR0aXRsZTogc3RyaW5nO1xuXHRzZXZlcml0eTogUnVsZVNldmVyaXR5O1xuXHRtYXRjaGVkR2xvYjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1hdGNoUmVjb3JkIHtcblx0ZmlsZVBhdGg6IHN0cmluZztcblx0cnVsZU5hbWVzOiBzdHJpbmdbXTtcblx0dG9vbE5hbWU6IHN0cmluZztcblx0dG9vbENhbGxJZDogc3RyaW5nO1xuXHRzZXZlcml0eTogXCJpbmZvXCIgfCBcIndhcm5pbmdcIjtcblx0dGltZXN0YW1wOiBudW1iZXI7XG5cdG1hdGNoZWRSdWxlRGV0YWlscz86IE1hdGNoZWRSdWxlRGV0YWlsW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGlmZWN5Y2xlRW50cnkge1xuXHRldmVudDogXCJsb2FkZWRcIiB8IFwicmVzdG9yZWRcIiB8IFwiaW5qZWN0ZWRcIiB8IFwicmVsb2FkZWRcIiB8IFwidW5sb2FkZWRcIiB8IFwiZXhwaXJlZFwiO1xuXHRtZXNzYWdlOiBzdHJpbmc7XG5cdHJ1bGVDb3VudD86IG51bWJlcjtcblx0dGltZXN0YW1wOiBudW1iZXI7XG5cdGRldGFpbHM/OiB7XG5cdFx0c2Nhbm5lZERpcnM/OiBTY2FubmVkRGlyW107XG5cdFx0Y29uZmlnU291cmNlPzogc3RyaW5nO1xuXHRcdGNhY2hlSGl0PzogYm9vbGVhbjtcblx0XHRpbmplY3RlZFJ1bGVzPzogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHByb21wdERlbHRhOiBudW1iZXIgfT47XG5cdH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU25hcHNob3RQYXlsb2FkIHtcblx0dHlwZTogXCJzbmFwc2hvdFwiO1xuXHRydWxlczogUnVsZURldGFpbFtdO1xuXHRpbmplY3RlZFJ1bGVOYW1lczogc3RyaW5nW107XG5cdHRvdGFsUnVsZXM6IG51bWJlcjtcblx0dW5jb25kaXRpb25hbENvdW50OiBudW1iZXI7XG5cdGNvbmRpdGlvbmFsQ291bnQ6IG51bWJlcjtcblx0bWF0Y2hIaXN0b3J5OiBNYXRjaFJlY29yZFtdO1xuXHRsaWZlY3ljbGVMb2c6IExpZmVjeWNsZUVudHJ5W107XG5cdGxvYWRlZEF0OiBudW1iZXI7XG5cdGNhY2hlVFRMOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWF0Y2hlZFBheWxvYWQge1xuXHR0eXBlOiBcIm1hdGNoZWRcIjtcblx0ZmlsZVBhdGg6IHN0cmluZztcblx0bWF0Y2hlZFJ1bGVzOiBNYXRjaGVkUnVsZURldGFpbFtdO1xuXHR0b29sTmFtZTogc3RyaW5nO1xuXHR0b29sQ2FsbElkOiBzdHJpbmc7XG5cdHNldmVyaXR5OiBcImluZm9cIiB8IFwid2FybmluZ1wiO1xuXHR0aW1lc3RhbXA6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmplY3RlZFBheWxvYWQge1xuXHR0eXBlOiBcImluamVjdGVkXCI7XG5cdHJ1bGVOYW1lczogc3RyaW5nW107XG5cdHN5c3RlbVByb21wdExlbmd0aDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlbG9hZGVkUGF5bG9hZCB7XG5cdHR5cGU6IFwicmVsb2FkZWRcIjtcblx0cnVsZXM6IFJ1bGVEZXRhaWxbXTtcblx0bG9hZGVkQXQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBVbmxvYWRlZFBheWxvYWQge1xuXHR0eXBlOiBcInVubG9hZGVkXCI7XG5cdHJlYXNvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBSdWxlc0NoYW5uZWxFdmVudCA9IFNuYXBzaG90UGF5bG9hZCB8IE1hdGNoZWRQYXlsb2FkIHwgSW5qZWN0ZWRQYXlsb2FkIHwgUmVsb2FkZWRQYXlsb2FkIHwgVW5sb2FkZWRQYXlsb2FkO1xuXG5leHBvcnQgY29uc3QgUlVMRVNfQ0hBTk5FTF9OQU1FID0gXCJydWxlcy1lbmdpbmVcIjtcblxuZXhwb3J0IGludGVyZmFjZSBSdWxlc0NoYW5uZWxDb250cmFjdCB7XG5cdG1ldGhvZHM6IHtcblx0XHRnZXRTbmFwc2hvdDoge1xuXHRcdFx0cGFyYW1zOiB7IGN3ZD86IHN0cmluZyB9O1xuXHRcdFx0cmV0dXJuOiBTbmFwc2hvdFBheWxvYWQ7XG5cdFx0fTtcblx0fTtcblx0ZXZlbnRzOiB7XG5cdFx0c25hcHNob3Q6IFNuYXBzaG90UGF5bG9hZDtcblx0XHRtYXRjaGVkOiBNYXRjaGVkUGF5bG9hZDtcblx0XHRpbmplY3RlZDogSW5qZWN0ZWRQYXlsb2FkO1xuXHRcdHJlbG9hZGVkOiBSZWxvYWRlZFBheWxvYWQ7XG5cdFx0dW5sb2FkZWQ6IFVubG9hZGVkUGF5bG9hZDtcblx0fTtcbn1cbiIsICJpbXBvcnQgKiBhcyBmcyBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgdHlwZSB7IFBhcnNlZFJ1bGUsIFJ1bGVDYWNoZSwgUnVsZUZyb250bWF0dGVyIH0gZnJvbSBcIi4vdHlwZXMuanNcIjtcblxuZnVuY3Rpb24gc3BsaXRDb21tYSh2YWw6IHN0cmluZyk6IHN0cmluZ1tdIHtcblx0Y29uc3QgcmVzdWx0OiBzdHJpbmdbXSA9IFtdO1xuXHRsZXQgZGVwdGggPSAwO1xuXHRsZXQgY3VycmVudCA9IFwiXCI7XG5cdGZvciAoY29uc3QgY2ggb2YgdmFsKSB7XG5cdFx0aWYgKGNoID09PSBcIntcIiB8fCBjaCA9PT0gXCIoXCIgfHwgY2ggPT09IFwiW1wiKSBkZXB0aCsrO1xuXHRcdGVsc2UgaWYgKGNoID09PSBcIn1cIiB8fCBjaCA9PT0gXCIpXCIgfHwgY2ggPT09IFwiXVwiKSBkZXB0aC0tO1xuXG5cdFx0aWYgKGNoID09PSBcIixcIiAmJiBkZXB0aCA9PT0gMCkge1xuXHRcdFx0Y29uc3QgdHJpbW1lZCA9IGN1cnJlbnQudHJpbSgpLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgXCJcIik7XG5cdFx0XHRpZiAodHJpbW1lZCkgcmVzdWx0LnB1c2godHJpbW1lZCk7XG5cdFx0XHRjdXJyZW50ID0gXCJcIjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y3VycmVudCArPSBjaDtcblx0XHR9XG5cdH1cblx0Y29uc3QgdHJpbW1lZCA9IGN1cnJlbnQudHJpbSgpLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgXCJcIik7XG5cdGlmICh0cmltbWVkKSByZXN1bHQucHVzaCh0cmltbWVkKTtcblx0cmV0dXJuIHJlc3VsdDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRnJvbnRtYXR0ZXIoY29udGVudDogc3RyaW5nKTogeyBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjsgYm9keTogc3RyaW5nIH0ge1xuXHRjb25zdCBmcm9udG1hdHRlclJlZ2V4ID0gL14tLS1cXHI/XFxuKFtcXHNcXFNdKj8pXFxuPy0tLVxccj9cXG4oW1xcc1xcU10qKSQvO1xuXHRjb25zdCBtYXRjaCA9IGNvbnRlbnQubWF0Y2goZnJvbnRtYXR0ZXJSZWdleCk7XG5cblx0aWYgKCFtYXRjaCkge1xuXHRcdHJldHVybiB7IGRhdGE6IHt9LCBib2R5OiBjb250ZW50IH07XG5cdH1cblxuXHRjb25zdCBbLCBmcm9udG1hdHRlclN0ciwgYm9keV0gPSBtYXRjaDtcblx0Y29uc3QgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcblxuXHRjb25zdCBsaW5lcyA9IGZyb250bWF0dGVyU3RyLnNwbGl0KFwiXFxuXCIpO1xuXHRsZXQgaSA9IDA7XG5cdHdoaWxlIChpIDwgbGluZXMubGVuZ3RoKSB7XG5cdFx0Y29uc3QgbGluZSA9IGxpbmVzW2ldO1xuXHRcdGNvbnN0IGNvbG9uSW5kZXggPSBsaW5lLmluZGV4T2YoXCI6XCIpO1xuXHRcdGlmIChjb2xvbkluZGV4ID09PSAtMSkge1xuXHRcdFx0aSsrO1xuXHRcdFx0Y29udGludWU7XG5cdFx0fVxuXG5cdFx0Y29uc3QgcmF3S2V5ID0gbGluZS5zbGljZSgwLCBjb2xvbkluZGV4KS50cmltKCk7XG5cdFx0bGV0IHZhbHVlOiBzdHJpbmcgfCBzdHJpbmdbXSB8IG51bGwgPSBsaW5lLnNsaWNlKGNvbG9uSW5kZXggKyAxKS50cmltKCk7XG5cblx0XHRpZiAodmFsdWUgPT09IFwiXCIgfHwgdmFsdWUgPT09IFwibnVsbFwiIHx8IHZhbHVlID09PSBcInVuZGVmaW5lZFwiKSB7XG5cdFx0XHRjb25zdCBsaXN0SXRlbXM6IHN0cmluZ1tdID0gW107XG5cdFx0XHRsZXQgaiA9IGkgKyAxO1xuXHRcdFx0d2hpbGUgKGogPCBsaW5lcy5sZW5ndGgpIHtcblx0XHRcdFx0Y29uc3Qgc3ViTGluZSA9IGxpbmVzW2pdO1xuXHRcdFx0XHRpZiAoc3ViTGluZS5tYXRjaCgvXlxccyotXFxzKy8pKSB7XG5cdFx0XHRcdFx0bGlzdEl0ZW1zLnB1c2goXG5cdFx0XHRcdFx0XHRzdWJMaW5lXG5cdFx0XHRcdFx0XHRcdC5yZXBsYWNlKC9eXFxzKi1cXHMrLywgXCJcIilcblx0XHRcdFx0XHRcdFx0LnRyaW0oKVxuXHRcdFx0XHRcdFx0XHQucmVwbGFjZSgvXltcIiddfFtcIiddJC9nLCBcIlwiKSxcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdGorKztcblx0XHRcdFx0fSBlbHNlIGlmIChzdWJMaW5lLnRyaW0oKSA9PT0gXCJcIiB8fCBzdWJMaW5lLm1hdGNoKC9eXFxzKy8pKSB7XG5cdFx0XHRcdFx0aisrO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZiAobGlzdEl0ZW1zLmxlbmd0aCA+IDApIHtcblx0XHRcdFx0Y29uc3QgY2FtZWxLZXkgPSByYXdLZXkucmVwbGFjZSgvLShbYS16XSkvZywgKF8sIGxldHRlcikgPT4gbGV0dGVyLnRvVXBwZXJDYXNlKCkpO1xuXHRcdFx0XHRkYXRhW2NhbWVsS2V5XSA9IGxpc3RJdGVtcztcblx0XHRcdFx0aSA9IGo7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXHRcdFx0dmFsdWUgPSBudWxsO1xuXHRcdH0gZWxzZSBpZiAodmFsdWUuc3RhcnRzV2l0aChcIltcIikgJiYgdmFsdWUuZW5kc1dpdGgoXCJdXCIpKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHR2YWx1ZSA9IEpTT04ucGFyc2UodmFsdWUucmVwbGFjZSgvJy9nLCAnXCInKSk7XG5cdFx0XHR9IGNhdGNoIChlcnIpIHtcblx0XHRcdFx0Y29uc29sZS5kZWJ1ZyhcIltydWxlcy1lbmdpbmVdIEpTT04gYXJyYXkgcGFyc2UgZmFpbGVkOlwiLCBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogZXJyKTtcblx0XHRcdFx0dmFsdWUgPSAodmFsdWUgYXMgc3RyaW5nKVxuXHRcdFx0XHRcdC5zbGljZSgxLCAtMSlcblx0XHRcdFx0XHQuc3BsaXQoXCIsXCIpXG5cdFx0XHRcdFx0Lm1hcCgodjogc3RyaW5nKSA9PiB2LnRyaW0oKS5yZXBsYWNlKC9eW1wiJ118W1wiJ10kL2csIFwiXCIpKTtcblx0XHRcdH1cblx0XHR9IGVsc2UgaWYgKHZhbHVlLnN0YXJ0c1dpdGgoJ1wiJykgJiYgdmFsdWUuZW5kc1dpdGgoJ1wiJykpIHtcblx0XHRcdHZhbHVlID0gdmFsdWUuc2xpY2UoMSwgLTEpO1xuXHRcdH0gZWxzZSBpZiAodmFsdWUuc3RhcnRzV2l0aChcIidcIikgJiYgdmFsdWUuZW5kc1dpdGgoXCInXCIpKSB7XG5cdFx0XHR2YWx1ZSA9IHZhbHVlLnNsaWNlKDEsIC0xKTtcblx0XHR9XG5cblx0XHRjb25zdCBjYW1lbEtleSA9IHJhd0tleS5yZXBsYWNlKC8tKFthLXpdKS9nLCAoXywgbGV0dGVyKSA9PiBsZXR0ZXIudG9VcHBlckNhc2UoKSk7XG5cblx0XHRpZiAoKGNhbWVsS2V5ID09PSBcInBhdGhzXCIgfHwgY2FtZWxLZXkgPT09IFwiZ2xvYnNcIikgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiKSB7XG5cdFx0XHRkYXRhW2NhbWVsS2V5XSA9IHNwbGl0Q29tbWEodmFsdWUpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRkYXRhW2NhbWVsS2V5XSA9IHZhbHVlO1xuXHRcdH1cblx0XHRpKys7XG5cdH1cblxuXHRyZXR1cm4geyBkYXRhLCBib2R5OiBib2R5LnRyaW0oKSB9O1xufVxuXG5mdW5jdGlvbiBleHRyYWN0VGl0bGUoYm9keTogc3RyaW5nKTogc3RyaW5nIHtcblx0Zm9yIChjb25zdCBsaW5lIG9mIGJvZHkuc3BsaXQoXCJcXG5cIikpIHtcblx0XHRjb25zdCB0cmltbWVkID0gbGluZS50cmltKCk7XG5cdFx0aWYgKHRyaW1tZWQpIHtcblx0XHRcdHJldHVybiB0cmltbWVkLnJlcGxhY2UoL14jK1xccyovLCBcIlwiKS5yZXBsYWNlKC9cXCpcXCovZywgXCJcIik7XG5cdFx0fVxuXHR9XG5cdHJldHVybiBcIlVudGl0bGVkIFJ1bGVcIjtcbn1cblxuZnVuY3Rpb24gcGFyc2VQYXRocyhyYXc6IHVua25vd24pOiBzdHJpbmdbXSB7XG5cdGlmICghcmF3KSByZXR1cm4gW107XG5cdGlmICh0eXBlb2YgcmF3ID09PSBcInN0cmluZ1wiKSB7XG5cdFx0cmV0dXJuIHJhd1xuXHRcdFx0LnNwbGl0KFwiLFwiKVxuXHRcdFx0Lm1hcCgoZykgPT4gZy50cmltKCkpXG5cdFx0XHQuZmlsdGVyKEJvb2xlYW4pO1xuXHR9XG5cdGlmIChBcnJheS5pc0FycmF5KHJhdykpIHJldHVybiByYXcgYXMgc3RyaW5nW107XG5cdHJldHVybiBbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUnVsZUZpbGUoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nKTogUGFyc2VkUnVsZSB7XG5cdGNvbnN0IHsgZGF0YSwgYm9keSB9ID0gcGFyc2VGcm9udG1hdHRlcihjb250ZW50KTtcblx0Y29uc3QgcmF3R2xvYnMgPSBkYXRhLmdsb2JzID8/IGRhdGEucGF0aHM7XG5cdGNvbnN0IGdsb2JzID0gcGFyc2VQYXRocyhyYXdHbG9icyk7XG5cdGNvbnN0IHJhd1BhdGhzID0gZGF0YS5wYXRocztcblx0Y29uc3QgcGF0aHMgPSBwYXJzZVBhdGhzKHJhd1BhdGhzKTtcblx0Y29uc3QgaXNVbmNvbmRpdGlvbmFsID0gZ2xvYnMubGVuZ3RoID09PSAwIHx8IChnbG9icy5sZW5ndGggPT09IDEgJiYgZ2xvYnNbMF0gPT09IFwiKipcIik7XG5cblx0Y29uc3QgZnJvbnRtYXR0ZXI6IFJ1bGVGcm9udG1hdHRlciA9IHt9O1xuXHRpZiAocmF3R2xvYnMpIHtcblx0XHRmcm9udG1hdHRlci5nbG9icyA9IGdsb2JzO1xuXHRcdGlmIChyYXdQYXRocykge1xuXHRcdFx0ZnJvbnRtYXR0ZXIucGF0aHMgPSBwYXRocztcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZnJvbnRtYXR0ZXIucGF0aHMgPSBnbG9icztcblx0XHR9XG5cdH1cblx0aWYgKGRhdGEuZGVzY3JpcHRpb24gJiYgdHlwZW9mIGRhdGEuZGVzY3JpcHRpb24gPT09IFwic3RyaW5nXCIpIGZyb250bWF0dGVyLmRlc2NyaXB0aW9uID0gZGF0YS5kZXNjcmlwdGlvbjtcblx0aWYgKGRhdGEuc2V2ZXJpdHkgJiYgdHlwZW9mIGRhdGEuc2V2ZXJpdHkgPT09IFwic3RyaW5nXCIpXG5cdFx0ZnJvbnRtYXR0ZXIuc2V2ZXJpdHkgPSBkYXRhLnNldmVyaXR5IGFzIFBhcnNlZFJ1bGVbXCJmcm9udG1hdHRlclwiXVtcInNldmVyaXR5XCJdO1xuXHRpZiAoZGF0YS5hbGxvd2VkVG9vbHMpXG5cdFx0ZnJvbnRtYXR0ZXIuYWxsb3dlZFRvb2xzID1cblx0XHRcdHR5cGVvZiBkYXRhLmFsbG93ZWRUb29scyA9PT0gXCJzdHJpbmdcIiA/IFtkYXRhLmFsbG93ZWRUb29sc10gOiAoZGF0YS5hbGxvd2VkVG9vbHMgYXMgc3RyaW5nW10pO1xuXHRpZiAoZGF0YS53aGVuVG9Vc2UgJiYgdHlwZW9mIGRhdGEud2hlblRvVXNlID09PSBcInN0cmluZ1wiKSBmcm9udG1hdHRlci53aGVuVG9Vc2UgPSBkYXRhLndoZW5Ub1VzZTtcblx0aWYgKGRhdGEubm90aWZ5T25NYXRjaCAhPT0gdW5kZWZpbmVkKVxuXHRcdGZyb250bWF0dGVyLm5vdGlmeU9uTWF0Y2ggPSBkYXRhLm5vdGlmeU9uTWF0Y2ggPT09IFwidHJ1ZVwiIHx8IGRhdGEubm90aWZ5T25NYXRjaCA9PT0gdHJ1ZTtcblx0aWYgKGRhdGEuc2tpcEluUHJvbXB0ICE9PSB1bmRlZmluZWQpXG5cdFx0ZnJvbnRtYXR0ZXIuc2tpcEluUHJvbXB0ID0gZGF0YS5za2lwSW5Qcm9tcHQgPT09IFwidHJ1ZVwiIHx8IGRhdGEuc2tpcEluUHJvbXB0ID09PSB0cnVlO1xuXG5cdHJldHVybiB7XG5cdFx0bmFtZTogcGF0aC5iYXNlbmFtZShmaWxlUGF0aCwgcGF0aC5leHRuYW1lKGZpbGVQYXRoKSksXG5cdFx0ZmlsZVBhdGgsXG5cdFx0dGl0bGU6IGV4dHJhY3RUaXRsZShib2R5KSxcblx0XHRjb250ZW50OiBib2R5LnRyaW0oKSxcblx0XHRzY29wZTogXCJwcm9qZWN0XCIsXG5cdFx0c291cmNlOiBcIlwiLFxuXHRcdGZyb250bWF0dGVyLFxuXHRcdGlzVW5jb25kaXRpb25hbCxcblx0fTtcbn1cblxuZnVuY3Rpb24gc2NhbkRpcihkaXI6IHN0cmluZywgZmlsZXM6IHN0cmluZ1tdID0gW10pOiBzdHJpbmdbXSB7XG5cdGlmICghZnMuZXhpc3RzU3luYyhkaXIpKSByZXR1cm4gZmlsZXM7XG5cdGNvbnN0IGVudHJpZXMgPSBmcy5yZWFkZGlyU3luYyhkaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcblx0Zm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG5cdFx0Y29uc3QgZnVsbFBhdGggPSBwYXRoLmpvaW4oZGlyLCBlbnRyeS5uYW1lKTtcblx0XHRpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuXHRcdFx0c2NhbkRpcihmdWxsUGF0aCwgZmlsZXMpO1xuXHRcdH0gZWxzZSBpZiAoZW50cnkuaXNGaWxlKCkgJiYgKGVudHJ5Lm5hbWUuZW5kc1dpdGgoXCIubWRcIikgfHwgZW50cnkubmFtZS5lbmRzV2l0aChcIi5tZGNcIikpKSB7XG5cdFx0XHRmaWxlcy5wdXNoKGZ1bGxQYXRoKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIGZpbGVzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbG9hZFJ1bGVzKHJ1bGVzRGlyOiBzdHJpbmcpOiBSdWxlQ2FjaGUge1xuXHRjb25zdCBydWxlczogUGFyc2VkUnVsZVtdID0gW107XG5cdGNvbnN0IHVuY29uZGl0aW9uYWw6IFBhcnNlZFJ1bGVbXSA9IFtdO1xuXHRjb25zdCBjb25kaXRpb25hbDogUGFyc2VkUnVsZVtdID0gW107XG5cblx0aWYgKCFmcy5leGlzdHNTeW5jKHJ1bGVzRGlyKSkge1xuXHRcdHJldHVybiB7IHJ1bGVzLCB1bmNvbmRpdGlvbmFsLCBjb25kaXRpb25hbCwgbG9hZGVkQXQ6IERhdGUubm93KCkgfTtcblx0fVxuXG5cdGNvbnN0IGZpbGVzID0gc2NhbkRpcihydWxlc0Rpcik7XG5cblx0Zm9yIChjb25zdCBmaWxlUGF0aCBvZiBmaWxlcykge1xuXHRcdGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZVBhdGgsIFwidXRmLThcIik7XG5cdFx0Y29uc3QgcnVsZSA9IHBhcnNlUnVsZUZpbGUoZmlsZVBhdGgsIGNvbnRlbnQpO1xuXHRcdHJ1bGVzLnB1c2gocnVsZSk7XG5cdFx0aWYgKHJ1bGUuaXNVbmNvbmRpdGlvbmFsKSB7XG5cdFx0XHR1bmNvbmRpdGlvbmFsLnB1c2gocnVsZSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbmRpdGlvbmFsLnB1c2gocnVsZSk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHsgcnVsZXMsIHVuY29uZGl0aW9uYWwsIGNvbmRpdGlvbmFsLCBsb2FkZWRBdDogRGF0ZS5ub3coKSB9O1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFBLFNBQVMsWUFBWTtBQUNyQixTQUFTLG9CQUFvQixrQkFBcUM7OztBQ0FsRSxTQUFTLGVBQWU7QUFDeEIsWUFBWSxVQUFVO0FDRnRCLFlBQVksUUFBUTtBQUNwQixZQUFZQSxXQUFVO0FETXRCLElBQU0sZUFBZTtFQUNwQixTQUFTLENBQUMsZ0NBQWdDO0VBQzFDLE1BQU0sQ0FBTSxVQUFLLFFBQVEsR0FBRyxXQUFXLE9BQU8sR0FBUSxVQUFLLFFBQVEsR0FBRyxXQUFXLFlBQVksT0FBTyxDQUFDO0VBQ3JHLElBQUksQ0FBQyxXQUFXO0VBQ2hCLFNBQVMsQ0FBQyxpQkFBaUIsbUJBQW1CLGFBQWE7QUFDNUQ7QUF1Q08sU0FBUyxZQUNmLFlBQ0EsUUFDd0Q7QUFDeEQsUUFBTSxVQUFVLE9BQU8sUUFBUTtBQUMvQixRQUFNLFNBQWdFLENBQUM7QUFFdkUsYUFBVyxDQUFDLE9BQU8sS0FBSyxLQUFLLE9BQU8sUUFBUSxPQUFPLEdBQUc7QUFDckQsZUFBVyxLQUFLLE9BQU87QUFDdEIsYUFBTyxLQUFLO1FBQ1g7UUFDQSxLQUFLLEVBQUUsV0FBVyxHQUFHLEtBQUssRUFBRSxXQUFXLEdBQUcsSUFBSSxFQUFFLFFBQVEsTUFBTSxRQUFRLENBQUMsSUFBUyxhQUFRLFlBQVksQ0FBQztRQUNyRyxRQUFRO01BQ1QsQ0FBQztJQUNGO0VB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O0FBQUEsUUFDQSxjQUFjLENBQUM7QUFBQSxRQUNmLFVBQVUsS0FBSyxJQUFJO0FBQUEsUUFDbkIsVUFBVSxRQUFRLFlBQVk7QUFBQSxNQUMvQixDQUFDO0FBQUEsSUFDRjtBQUFBLEVBQ0QsQ0FBQztBQUVELEtBQUcsR0FBRyxvQkFBb0IsT0FBTyxRQUFRLFFBQVE7QUFDaEQsWUFBUSxLQUFLLFlBQVksRUFBRSxNQUFNLFlBQVksUUFBUSxtQkFBbUIsQ0FBQztBQUN6RSxRQUFJLEdBQUcsVUFBVSxnQkFBZ0IsTUFBUztBQUFBLEVBQzNDLENBQUM7QUFDRjsiLAogICJuYW1lcyI6IFsicGF0aCIsICJ0cmltbWVkIiwgImNhbWVsS2V5IiwgImZzIiwgImhvbWVkaXIiLCAicGF0aCIsICJERUZBVUxUX0RJUlMiLCAicmVzb2x2ZURpcnMiLCAicGF0aCIsICJjYWNoZSIsICJpZ25vcmUiLCAiY3JlYXRlVHlwZWRDaGFubmVsIiwgImZzIiwgInBhdGgiLCAic3BsaXRDb21tYSIsICJ0cmltbWVkIiwgInBhcnNlRnJvbnRtYXR0ZXIiLCAiY2FtZWxLZXkiLCAiZXh0cmFjdFRpdGxlIiwgInBhcnNlUGF0aHMiLCAicGFyc2VSdWxlRmlsZSIsICJzY2FuRGlyIiwgImxvYWRSdWxlcyJdCn0K
|